rspack_core 0.102.0-beta.1

rspack core
Documentation
use std::{any::Any, borrow::Cow, ops::Deref};

use derive_more::with_trait::Debug;
use rspack_cacheable::{
  cacheable, cacheable_dyn,
  with::{AsMap, AsPreset, AsVec},
};
use rspack_error::{Result, TWithDiagnosticArray};
use rspack_hash::RspackHashDigest;
use rspack_loader_runner::{AdditionalData, ParseMeta, ResourceData};
use rspack_sources::{BoxSource, ReplaceSource};
use rspack_util::{ext::AsAny, source_map::SourceMapKind};
use rustc_hash::{FxHashMap, FxHashSet};
use swc_core::atoms::Atom;

use crate::{
  AsyncDependenciesBlock, BoxDependency, BoxDependencyTemplate, BoxLoader, BoxModuleDependency,
  BuildInfo, BuildMeta, ChunkGraph, CodeGenerationData, Compilation, CompilerOptions,
  ConcatenationScope, Context, DependencyLocation, DependencyRange, EvaluatedInlinableValue,
  FactoryMeta, GeneratorOptions, Module, ModuleCodeTemplate, ModuleGraph, ModuleIdentifier,
  ModuleLayer, ModuleType, NormalModule, ParserOptions, RuntimeGlobals, RuntimeSpec, SourceType,
};

#[derive(Debug)]
pub struct ParseContext<'a> {
  pub source: BoxSource,
  pub module_context: &'a Context,
  pub module_identifier: ModuleIdentifier,
  pub module_type: &'a ModuleType,
  pub module_layer: Option<&'a ModuleLayer>,
  pub module_user_request: &'a str,
  pub module_parser_options: Option<&'a ParserOptions>,
  pub module_generator_options: Option<&'a GeneratorOptions>,
  pub module_source_map_kind: SourceMapKind,
  pub module_match_resource: Option<&'a ResourceData>,
  #[debug(skip)]
  pub loaders: &'a [BoxLoader],
  pub resource_data: &'a ResourceData,
  pub compiler_options: &'a CompilerOptions,
  pub additional_data: Option<AdditionalData>,
  pub factory_meta: Option<&'a FactoryMeta>,
  pub parse_meta: ParseMeta,
  pub build_info: &'a mut BuildInfo,
  pub build_meta: &'a mut BuildMeta,
  pub runtime_template: &'a ModuleCodeTemplate,
}

#[cacheable]
#[derive(Debug, Default, Clone)]
pub struct CollectedTypeScriptInfo {
  #[cacheable(with=AsVec<AsPreset>)]
  pub type_exports: FxHashSet<Atom>,
  #[cacheable(with=AsMap<AsPreset>)]
  pub exported_enums: FxHashMap<Atom, TSEnumValue>,
}

pub const COLLECTED_TYPESCRIPT_INFO_PARSE_META_KEY: &str = "rspack-collected-ts-info";

#[cacheable]
#[derive(Debug, Default, Clone)]
pub struct TSEnumValue(
  #[cacheable(with=AsMap<AsPreset>)] FxHashMap<Atom, Option<EvaluatedInlinableValue>>,
);

impl TSEnumValue {
  pub fn new(value: FxHashMap<Atom, Option<EvaluatedInlinableValue>>) -> Self {
    Self(value)
  }
}

impl Deref for TSEnumValue {
  type Target = FxHashMap<Atom, Option<EvaluatedInlinableValue>>;

  fn deref(&self) -> &Self::Target {
    &self.0
  }
}

#[derive(Debug)]
pub struct SideEffectsBailoutItem {
  pub msg: String,
  /// The type of AstNode
  pub ty: String,
}

impl SideEffectsBailoutItem {}

#[derive(Debug)]
pub struct SideEffectsBailoutItemWithSpan {
  pub range: DependencyRange,
  pub loc: Option<DependencyLocation>,
  /// The type of AstNode
  pub ty: String,
}

impl SideEffectsBailoutItemWithSpan {
  pub fn new(range: DependencyRange, loc: Option<DependencyLocation>, ty: String) -> Self {
    Self { range, loc, ty }
  }
}

#[derive(Debug)]
pub struct ParseResult {
  pub dependencies: Vec<BoxDependency>,
  pub blocks: Vec<Box<AsyncDependenciesBlock>>,
  pub presentational_dependencies: Vec<BoxDependencyTemplate>,
  pub code_generation_dependencies: Vec<BoxModuleDependency>,
  pub source: BoxSource,
  pub side_effects_bailout: Option<SideEffectsBailoutItem>,
}

#[derive(Debug)]
pub struct GenerateContext<'a> {
  pub compilation: &'a Compilation,
  pub runtime_template: &'a mut ModuleCodeTemplate,
  pub data: &'a mut CodeGenerationData,
  pub requested_source_type: SourceType,
  pub module_parser_options: Option<&'a ParserOptions>,
  pub module_generator_options: Option<&'a GeneratorOptions>,
  pub runtime: Option<&'a RuntimeSpec>,
  pub concatenation_scope: Option<&'a mut ConcatenationScope>,
  pub(crate) analyzed_concatenation_source: Option<ReplaceSource>,
}

impl GenerateContext<'_> {
  /// Takes the editable source initialized from the make-time module source.
  ///
  /// This is only available to generators using `AnalyzeAtMake` during faster
  /// module concatenation.
  pub fn take_analyzed_concatenation_source(&mut self) -> Option<ReplaceSource> {
    self.analyzed_concatenation_source.take()
  }

  /// Renders a runtime global and records the identifiers referenced by the
  /// rendered expression for generated concatenation sources.
  pub fn render_runtime_globals(&mut self, runtime_globals: &RuntimeGlobals) -> String {
    let rendered = self
      .runtime_template
      .render_runtime_globals(runtime_globals);
    if let Some(scope) = self.concatenation_scope.as_deref_mut() {
      scope.register_used_names_from_generated_code(&rendered);
    }
    rendered
  }
}

#[derive(Debug, Clone)]
pub enum ConcatenationCodeGenerationSource {
  /// Dependency-template edits are based on the make-time module source.
  Analyzed(ReplaceSource),
  /// The complete JavaScript source was produced during code generation.
  Generated(ReplaceSource),
}

impl ConcatenationCodeGenerationSource {
  pub fn into_source(self) -> ReplaceSource {
    match self {
      Self::Analyzed(source) | Self::Generated(source) => source,
    }
  }
}

#[derive(Debug)]
pub enum GeneratedSource {
  Source(BoxSource),
  Concatenation(Box<ConcatenationCodeGenerationSource>),
}

impl GeneratedSource {
  pub fn analyzed_concatenation(source: ReplaceSource) -> Self {
    Self::Concatenation(Box::new(ConcatenationCodeGenerationSource::Analyzed(
      source,
    )))
  }

  pub fn generated_concatenation(source: ReplaceSource) -> Self {
    Self::Concatenation(Box::new(ConcatenationCodeGenerationSource::Generated(
      source,
    )))
  }
}

impl From<BoxSource> for GeneratedSource {
  fn from(source: BoxSource) -> Self {
    Self::Source(source)
  }
}

#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum ConcatenationScopeInfoMode {
  /// Scope information is collected from the original JavaScript program
  /// during make.
  AnalyzeAtMake,
  /// The module has no original JavaScript scope. Its generator must register
  /// every generated binding and referenced identifier through
  /// `ConcatenationScope`.
  GenerateAtCodegen,
  /// The parser and generator cannot participate in module concatenation.
  Unsupported,
}

#[cacheable_dyn]
#[async_trait::async_trait]
pub trait ParserAndGenerator: Send + Sync + Debug + AsAny {
  /// The source types that the generator can generate (the source types you can make requests for)
  fn source_types(&self, module: &dyn Module, module_graph: &ModuleGraph) -> &[SourceType];
  /// Parse the source and return the dependencies and the ast or source
  async fn parse<'a>(
    &mut self,
    parse_context: ParseContext<'a>,
  ) -> Result<TWithDiagnosticArray<ParseResult>>;
  /// Size of the original source
  fn size(&self, module: &dyn Module, source_type: Option<&SourceType>) -> f64;
  /// Generate source or AST based on the built source or AST
  async fn generate(
    &self,
    source: &BoxSource,
    module: &dyn Module,
    generate_context: &mut GenerateContext,
  ) -> Result<GeneratedSource>;

  fn concatenation_scope_info_mode(&self) -> ConcatenationScopeInfoMode;

  fn get_concatenation_bailout_reason(
    &self,
    _module: &dyn Module,
    _mg: &ModuleGraph,
    _cg: &ChunkGraph,
  ) -> Option<Cow<'static, str>>;

  async fn get_runtime_hash(
    &self,
    _module: &NormalModule,
    compilation: &Compilation,
    _runtime: Option<&RuntimeSpec>,
  ) -> Result<RspackHashDigest> {
    Ok(RspackHashDigest::new(
      &[],
      &compilation.options.output.hash_digest,
    ))
  }

  fn has_runtime_hash(&self) -> bool {
    false
  }
}

impl dyn ParserAndGenerator + '_ {
  pub fn downcast_ref<D: Any>(&self) -> Option<&D> {
    self.as_any().downcast_ref::<D>()
  }

  pub fn downcast_mut<D: Any>(&mut self) -> Option<&mut D> {
    self.as_any_mut().downcast_mut::<D>()
  }

  pub fn is<D: Any>(&self) -> bool {
    self.downcast_ref::<D>().is_some()
  }
}