rspack_plugin_rslib 0.101.0

Rslib native plugin
Documentation
use rspack_core::ConstDependency;
use rspack_plugin_javascript::{JavascriptParserPlugin, visitors::JavascriptParser};
use swc_experimental_ecma_ast::{Lit, ModuleItem, Program, Span, Stmt};

pub struct ReactDirectivesParserPlugin;

impl ReactDirectivesParserPlugin {
  fn process_statements<'a, I>(stmts: I, directives: &mut Vec<(String, Span)>)
  where
    I: Iterator<Item = &'a Stmt<'a>>,
  {
    for stmt in stmts {
      let Stmt::Expr(expr_stmt) = stmt else { break };
      let Some(Lit::Str(str_lit)) = expr_stmt.expr.as_lit() else {
        break;
      };

      let value = str_lit.value.to_string_lossy().to_string();
      if !value.starts_with("use ") {
        break;
      }

      let directive = format!("\"{value}\"");
      directives.push((directive, expr_stmt.span));
    }
  }
}

#[rspack_plugin_javascript::implemented_javascript_parser_hooks]
impl<'p, 'a> JavascriptParserPlugin<'p, 'a> for ReactDirectivesParserPlugin {
  fn program(&self, parser: &mut JavascriptParser<'p>, ast: &Program) -> Option<bool> {
    let mut directives = Vec::new();

    match ast {
      Program::Module(module) => {
        let stmts = module.body.iter().filter_map(|item| {
          if let ModuleItem::Stmt(stmt) = item {
            Some(&**stmt)
          } else {
            None
          }
        });
        Self::process_statements(stmts, &mut directives);
      }
      Program::Script(script) => {
        Self::process_statements(script.body.iter(), &mut directives);
      }
    }

    if directives.is_empty() {
      return None;
    }

    parser.build_info.extras.insert(
      "react_directives".to_string(),
      serde_json::json!(directives.iter().map(|(d, _)| d).collect::<Vec<_>>()),
    );

    for (_, span) in directives {
      parser.add_presentational_dependency(Box::new(ConstDependency::new(span.into(), "".into())));
    }

    None
  }
}