rspack_plugin_javascript 0.102.2

rspack javascript plugin
Documentation
use rspack_core::{
  BoxDependency, ContextMode, ContextOptions, DependencyCategory, get_context,
  try_convert_str_to_context_mode,
};
use rspack_error::Error;
use rspack_regex::RspackRegex;
use rspack_util::SpanExt;
use swc_experimental_ecma_ast::{CallExpr, GetSpan};

use super::JavascriptParserPlugin;
use crate::{
  dependency::RequireContextDependency,
  visitors::{
    JavascriptParser, clean_regexp_in_context_module, create_traceable_error,
    default_context_reg_exp,
  },
};

pub struct RequireContextDependencyParserPlugin;

#[rspack_macros::implemented_javascript_parser_hooks]
impl<'p, 'a> JavascriptParserPlugin<'p, 'a> for RequireContextDependencyParserPlugin {
  fn call(
    &self,
    parser: &mut JavascriptParser<'p>,
    expr: &CallExpr,
    for_name: &str,
  ) -> Option<bool> {
    if for_name != "require.context" {
      return None;
    }

    let arg = expr.args.first()?;
    let request_expr = parser.evaluate_expression(&arg.expr);
    if !request_expr.is_string() {
      return None;
    }

    let mode = if expr.args.len() == 4 {
      let mode_expr = parser.evaluate_expression(&expr.args[3].expr);
      if !mode_expr.is_string() {
        // FIXME: return `None` in webpack
        ContextMode::Sync
      } else if let Some(mode_expr) = try_convert_str_to_context_mode(mode_expr.string()) {
        mode_expr
      } else {
        // Align with webpack, which throws an `Unsupported mode` error during
        // code generation when an unknown context mode is used.
        let mut error: Error = create_traceable_error(
          "Unsupported mode".into(),
          format!(
            r#"`mode` expected "sync", "eager", "weak", "async-weak", "lazy" or "lazy-once", but received: "{}"."#,
            mode_expr.string()
          ),
          parser.source.to_string(),
          expr.args[3].expr.span().into(),
        );
        error.hide_stack = Some(true);
        parser.add_error(error.into());
        ContextMode::Sync
      }
    } else {
      ContextMode::Sync
    };

    let (reg_exp, reg_exp_span) = if expr.args.len() >= 3 {
      let reg_exp_expr = parser.evaluate_expression(&expr.args[2].expr);
      let reg_exp = if !reg_exp_expr.is_regexp() {
        // FIXME: return `None` in webpack
        default_context_reg_exp()
      } else {
        let (expr, flags) = reg_exp_expr.regexp();
        RspackRegex::with_flags(expr.as_str(), flags.as_str()).expect("reg should success")
      };
      (reg_exp, Some(expr.args[2].expr.span().into()))
    } else {
      (default_context_reg_exp(), None)
    };

    let recursive = if expr.args.len() >= 2 {
      let recursive_expr = parser.evaluate_expression(&expr.args[1].expr);
      if !recursive_expr.is_bool() {
        // FIXME: return `None` in webpack
        true
      } else {
        recursive_expr.bool()
      }
    } else {
      true
    };

    let reg_exp = clean_regexp_in_context_module(reg_exp, reg_exp_span, parser);
    parser.add_dependency(BoxDependency::new(RequireContextDependency::new(
      ContextOptions {
        mode,
        recursive,
        pattern: reg_exp.into(),
        category: DependencyCategory::CommonJS,
        request: request_expr.string().clone(),
        context: get_context(parser.resource_data).to_string(),
        compiler_context: parser.compiler_options.context.clone(),
        start: expr.span().real_lo(),
        end: expr.span().real_hi(),
        ..Default::default()
      },
      expr.span.into(),
      parser.in_try,
    )));
    Some(true)
  }
}