chore(rust): change indentation to tabs
The 4 spaces indentation uses too much screen width in the deep indentation of transforming, and with tabs people can configure their own visible width.
This commit is contained in:
@@ -1,5 +1,5 @@
|
||||
extern crate napi_build;
|
||||
|
||||
fn main() {
|
||||
napi_build::setup();
|
||||
napi_build::setup();
|
||||
}
|
||||
|
||||
@@ -15,27 +15,27 @@ static ALLOC: mimalloc::MiMalloc = mimalloc::MiMalloc;
|
||||
#[allow(clippy::needless_pass_by_value)]
|
||||
#[js_function(1)]
|
||||
fn transform_fs(ctx: CallContext) -> Result<JsUnknown> {
|
||||
let opts = ctx.get::<JsObject>(0)?;
|
||||
let config: qwik_core::TransformFsOptions = ctx.env.from_js_value(opts)?;
|
||||
let opts = ctx.get::<JsObject>(0)?;
|
||||
let config: qwik_core::TransformFsOptions = ctx.env.from_js_value(opts)?;
|
||||
|
||||
let result = qwik_core::transform_fs(config).unwrap();
|
||||
ctx.env.to_js_value(&result)
|
||||
let result = qwik_core::transform_fs(config).unwrap();
|
||||
ctx.env.to_js_value(&result)
|
||||
}
|
||||
|
||||
#[allow(clippy::needless_pass_by_value)]
|
||||
#[js_function(1)]
|
||||
fn transform_modules(ctx: CallContext) -> Result<JsUnknown> {
|
||||
let opts = ctx.get::<JsObject>(0)?;
|
||||
let config: qwik_core::TransformModulesOptions = ctx.env.from_js_value(opts)?;
|
||||
let opts = ctx.get::<JsObject>(0)?;
|
||||
let config: qwik_core::TransformModulesOptions = ctx.env.from_js_value(opts)?;
|
||||
|
||||
let result = qwik_core::transform_modules(config).unwrap();
|
||||
ctx.env.to_js_value(&result)
|
||||
let result = qwik_core::transform_modules(config).unwrap();
|
||||
ctx.env.to_js_value(&result)
|
||||
}
|
||||
|
||||
#[module_exports]
|
||||
fn init(mut exports: JsObject) -> Result<()> {
|
||||
exports.create_named_method("transform_fs", transform_fs)?;
|
||||
exports.create_named_method("transform_modules", transform_modules)?;
|
||||
exports.create_named_method("transform_fs", transform_fs)?;
|
||||
exports.create_named_method("transform_modules", transform_modules)?;
|
||||
|
||||
Ok(())
|
||||
Ok(())
|
||||
}
|
||||
|
||||
@@ -9,24 +9,24 @@ use path_absolutize::Absolutize;
|
||||
use qwik_core::{transform_fs, EmitMode, EntryStrategy, MinifyMode, TransformFsOptions};
|
||||
|
||||
struct OptimizerInput {
|
||||
glob: Option<String>,
|
||||
manifest: Option<String>,
|
||||
core_module: Option<String>,
|
||||
scope: Option<String>,
|
||||
src: PathBuf,
|
||||
dest: PathBuf,
|
||||
mode: EmitMode,
|
||||
strategy: EntryStrategy,
|
||||
transpile_ts: bool,
|
||||
transpile_jsx: bool,
|
||||
preserve_filenames: bool,
|
||||
minify: MinifyMode,
|
||||
sourcemaps: bool,
|
||||
explicit_extensions: bool,
|
||||
glob: Option<String>,
|
||||
manifest: Option<String>,
|
||||
core_module: Option<String>,
|
||||
scope: Option<String>,
|
||||
src: PathBuf,
|
||||
dest: PathBuf,
|
||||
mode: EmitMode,
|
||||
strategy: EntryStrategy,
|
||||
transpile_ts: bool,
|
||||
transpile_jsx: bool,
|
||||
preserve_filenames: bool,
|
||||
minify: MinifyMode,
|
||||
sourcemaps: bool,
|
||||
explicit_extensions: bool,
|
||||
}
|
||||
|
||||
fn main() -> Result<(), Box<dyn std::error::Error>> {
|
||||
let matches = Command::new("qwik")
|
||||
let matches = Command::new("qwik")
|
||||
.version("1.0")
|
||||
.arg_required_else_help(true)
|
||||
.subcommand_required(true)
|
||||
@@ -85,85 +85,85 @@ fn main() -> Result<(), Box<dyn std::error::Error>> {
|
||||
)
|
||||
.get_matches();
|
||||
|
||||
// You can check for the existence of subcommands, and if found use their
|
||||
// matches just as you would the top level app
|
||||
if let Some(matches) = matches.subcommand_matches("optimize") {
|
||||
// "$ myapp test" was run
|
||||
let strategy = match matches.value_of("strategy") {
|
||||
Some("inline") => EntryStrategy::Inline,
|
||||
Some("hook") => EntryStrategy::Hook,
|
||||
Some("single") => EntryStrategy::Single,
|
||||
Some("component") => EntryStrategy::Component,
|
||||
Some("smart") | None => EntryStrategy::Smart,
|
||||
_ => panic!("Invalid strategy option"),
|
||||
};
|
||||
// You can check for the existence of subcommands, and if found use their
|
||||
// matches just as you would the top level app
|
||||
if let Some(matches) = matches.subcommand_matches("optimize") {
|
||||
// "$ myapp test" was run
|
||||
let strategy = match matches.value_of("strategy") {
|
||||
Some("inline") => EntryStrategy::Inline,
|
||||
Some("hook") => EntryStrategy::Hook,
|
||||
Some("single") => EntryStrategy::Single,
|
||||
Some("component") => EntryStrategy::Component,
|
||||
Some("smart") | None => EntryStrategy::Smart,
|
||||
_ => panic!("Invalid strategy option"),
|
||||
};
|
||||
|
||||
let minify = match matches.value_of("minify") {
|
||||
Some("none") => MinifyMode::None,
|
||||
Some("simplify") | None => MinifyMode::Simplify,
|
||||
_ => panic!("Invalid minify option"),
|
||||
};
|
||||
let minify = match matches.value_of("minify") {
|
||||
Some("none") => MinifyMode::None,
|
||||
Some("simplify") | None => MinifyMode::Simplify,
|
||||
_ => panic!("Invalid minify option"),
|
||||
};
|
||||
|
||||
let mode = match matches.value_of("mode") {
|
||||
Some("dev") => EmitMode::Dev,
|
||||
Some("prod") => EmitMode::Prod,
|
||||
Some("lib") | None => EmitMode::Lib,
|
||||
_ => panic!("Invalid mode option"),
|
||||
};
|
||||
optimize(OptimizerInput {
|
||||
src: matches.value_of_t_or_exit("src"),
|
||||
dest: matches.value_of_t_or_exit("dest"),
|
||||
manifest: matches.value_of("manifest").map(|s| s.into()),
|
||||
core_module: matches.value_of("core_module").map(|s| s.into()),
|
||||
scope: matches.value_of("scope").map(|s| s.into()),
|
||||
mode,
|
||||
glob: None,
|
||||
strategy,
|
||||
minify,
|
||||
explicit_extensions: matches.is_present("extensions"),
|
||||
transpile_jsx: !matches.is_present("no-jsx"),
|
||||
transpile_ts: !matches.is_present("no-ts"),
|
||||
preserve_filenames: matches.is_present("preserve-filenames"),
|
||||
sourcemaps: matches.is_present("sourcemaps"),
|
||||
})?;
|
||||
}
|
||||
Ok(())
|
||||
let mode = match matches.value_of("mode") {
|
||||
Some("dev") => EmitMode::Dev,
|
||||
Some("prod") => EmitMode::Prod,
|
||||
Some("lib") | None => EmitMode::Lib,
|
||||
_ => panic!("Invalid mode option"),
|
||||
};
|
||||
optimize(OptimizerInput {
|
||||
src: matches.value_of_t_or_exit("src"),
|
||||
dest: matches.value_of_t_or_exit("dest"),
|
||||
manifest: matches.value_of("manifest").map(|s| s.into()),
|
||||
core_module: matches.value_of("core_module").map(|s| s.into()),
|
||||
scope: matches.value_of("scope").map(|s| s.into()),
|
||||
mode,
|
||||
glob: None,
|
||||
strategy,
|
||||
minify,
|
||||
explicit_extensions: matches.is_present("extensions"),
|
||||
transpile_jsx: !matches.is_present("no-jsx"),
|
||||
transpile_ts: !matches.is_present("no-ts"),
|
||||
preserve_filenames: matches.is_present("preserve-filenames"),
|
||||
sourcemaps: matches.is_present("sourcemaps"),
|
||||
})?;
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn optimize(
|
||||
optimizer_input: OptimizerInput,
|
||||
optimizer_input: OptimizerInput,
|
||||
) -> Result<qwik_core::TransformOutput, Box<dyn std::error::Error>> {
|
||||
let current_dir = std::env::current_dir()?;
|
||||
let src_dir = current_dir.join(optimizer_input.src).canonicalize()?;
|
||||
let current_dir = std::env::current_dir()?;
|
||||
let src_dir = current_dir.join(optimizer_input.src).canonicalize()?;
|
||||
|
||||
let result = transform_fs(TransformFsOptions {
|
||||
src_dir: src_dir.to_string_lossy().to_string(),
|
||||
vendor_roots: vec![],
|
||||
glob: optimizer_input.glob,
|
||||
source_maps: optimizer_input.sourcemaps,
|
||||
minify: optimizer_input.minify,
|
||||
transpile_jsx: optimizer_input.transpile_jsx,
|
||||
transpile_ts: optimizer_input.transpile_ts,
|
||||
preserve_filenames: optimizer_input.preserve_filenames,
|
||||
entry_strategy: optimizer_input.strategy,
|
||||
explicit_extensions: optimizer_input.explicit_extensions,
|
||||
core_module: optimizer_input.core_module,
|
||||
root_dir: None,
|
||||
let result = transform_fs(TransformFsOptions {
|
||||
src_dir: src_dir.to_string_lossy().to_string(),
|
||||
vendor_roots: vec![],
|
||||
glob: optimizer_input.glob,
|
||||
source_maps: optimizer_input.sourcemaps,
|
||||
minify: optimizer_input.minify,
|
||||
transpile_jsx: optimizer_input.transpile_jsx,
|
||||
transpile_ts: optimizer_input.transpile_ts,
|
||||
preserve_filenames: optimizer_input.preserve_filenames,
|
||||
entry_strategy: optimizer_input.strategy,
|
||||
explicit_extensions: optimizer_input.explicit_extensions,
|
||||
core_module: optimizer_input.core_module,
|
||||
root_dir: None,
|
||||
|
||||
mode: optimizer_input.mode,
|
||||
scope: optimizer_input.scope,
|
||||
mode: optimizer_input.mode,
|
||||
scope: optimizer_input.scope,
|
||||
|
||||
manual_chunks: None,
|
||||
strip_exports: None,
|
||||
strip_ctx_name: None,
|
||||
strip_event_handlers: false,
|
||||
reg_ctx_name: None,
|
||||
is_server: None,
|
||||
})?;
|
||||
manual_chunks: None,
|
||||
strip_exports: None,
|
||||
strip_ctx_name: None,
|
||||
strip_event_handlers: false,
|
||||
reg_ctx_name: None,
|
||||
is_server: None,
|
||||
})?;
|
||||
|
||||
result.write_to_fs(
|
||||
¤t_dir.join(optimizer_input.dest).absolutize()?,
|
||||
optimizer_input.manifest,
|
||||
)?;
|
||||
Ok(result)
|
||||
result.write_to_fs(
|
||||
¤t_dir.join(optimizer_input.dest).absolutize()?,
|
||||
optimizer_input.manifest,
|
||||
)?;
|
||||
Ok(result)
|
||||
}
|
||||
|
||||
@@ -7,7 +7,7 @@ use test::Bencher;
|
||||
|
||||
#[bench]
|
||||
fn transform_todo_app(b: &mut Bencher) {
|
||||
b.iter(|| {
|
||||
b.iter(|| {
|
||||
let code = r#"
|
||||
import {
|
||||
Fragment,
|
||||
|
||||
@@ -10,56 +10,56 @@ use swc_ecmascript::ast;
|
||||
use swc_ecmascript::visit::{VisitMut, VisitMutWith};
|
||||
|
||||
pub struct SideEffectVisitor<'a> {
|
||||
global_collector: &'a GlobalCollect,
|
||||
imports: HashSet<JsWord>,
|
||||
path_data: &'a PathData,
|
||||
src_dir: &'a Path,
|
||||
global_collector: &'a GlobalCollect,
|
||||
imports: HashSet<JsWord>,
|
||||
path_data: &'a PathData,
|
||||
src_dir: &'a Path,
|
||||
}
|
||||
|
||||
impl<'a> SideEffectVisitor<'a> {
|
||||
pub fn new(
|
||||
global_collector: &'a GlobalCollect,
|
||||
path_data: &'a PathData,
|
||||
src_dir: &'a Path,
|
||||
) -> Self {
|
||||
Self {
|
||||
global_collector,
|
||||
path_data,
|
||||
src_dir,
|
||||
imports: HashSet::new(),
|
||||
}
|
||||
}
|
||||
pub fn new(
|
||||
global_collector: &'a GlobalCollect,
|
||||
path_data: &'a PathData,
|
||||
src_dir: &'a Path,
|
||||
) -> Self {
|
||||
Self {
|
||||
global_collector,
|
||||
path_data,
|
||||
src_dir,
|
||||
imports: HashSet::new(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a> VisitMut for SideEffectVisitor<'a> {
|
||||
fn visit_mut_import_decl(&mut self, node: &mut ast::ImportDecl) {
|
||||
if node.src.value.starts_with('.') {
|
||||
self.imports.insert(node.src.value.clone());
|
||||
}
|
||||
}
|
||||
fn visit_mut_module(&mut self, node: &mut ast::Module) {
|
||||
node.visit_mut_children_with(self);
|
||||
let mut imports: Vec<_> = self.global_collector.imports.values().collect();
|
||||
imports.sort_by_key(|i| i.source.clone());
|
||||
fn visit_mut_import_decl(&mut self, node: &mut ast::ImportDecl) {
|
||||
if node.src.value.starts_with('.') {
|
||||
self.imports.insert(node.src.value.clone());
|
||||
}
|
||||
}
|
||||
fn visit_mut_module(&mut self, node: &mut ast::Module) {
|
||||
node.visit_mut_children_with(self);
|
||||
let mut imports: Vec<_> = self.global_collector.imports.values().collect();
|
||||
imports.sort_by_key(|i| i.source.clone());
|
||||
|
||||
for import in imports {
|
||||
if import.source.starts_with('.') && !self.imports.contains(&import.source) {
|
||||
let abs_dir = self.path_data.abs_dir.to_slash_lossy();
|
||||
let relative = relative_path::RelativePath::new(&abs_dir);
|
||||
let final_path = relative.join(import.source.as_ref()).normalize();
|
||||
if final_path.starts_with(self.src_dir.to_str().unwrap()) {
|
||||
node.body.insert(
|
||||
0,
|
||||
ast::ModuleItem::ModuleDecl(ast::ModuleDecl::Import(ast::ImportDecl {
|
||||
asserts: None,
|
||||
span: DUMMY_SP,
|
||||
specifiers: vec![],
|
||||
type_only: false,
|
||||
src: Box::new(ast::Str::from(import.source.clone())),
|
||||
})),
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
for import in imports {
|
||||
if import.source.starts_with('.') && !self.imports.contains(&import.source) {
|
||||
let abs_dir = self.path_data.abs_dir.to_slash_lossy();
|
||||
let relative = relative_path::RelativePath::new(&abs_dir);
|
||||
let final_path = relative.join(import.source.as_ref()).normalize();
|
||||
if final_path.starts_with(self.src_dir.to_str().unwrap()) {
|
||||
node.body.insert(
|
||||
0,
|
||||
ast::ModuleItem::ModuleDecl(ast::ModuleDecl::Import(ast::ImportDecl {
|
||||
asserts: None,
|
||||
span: DUMMY_SP,
|
||||
specifiers: vec![],
|
||||
type_only: false,
|
||||
src: Box::new(ast::Str::from(import.source.clone())),
|
||||
})),
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2,58 +2,58 @@ use swc_common::{Mark, Spanned};
|
||||
use swc_ecmascript::ast;
|
||||
use swc_ecmascript::visit::VisitMut;
|
||||
pub struct Treeshaker {
|
||||
pub marker: CleanMarker,
|
||||
pub cleaner: CleanSideEffects,
|
||||
pub marker: CleanMarker,
|
||||
pub cleaner: CleanSideEffects,
|
||||
}
|
||||
|
||||
pub struct CleanSideEffects {
|
||||
pub did_drop: bool,
|
||||
pub mark: Mark,
|
||||
pub did_drop: bool,
|
||||
pub mark: Mark,
|
||||
}
|
||||
|
||||
pub struct CleanMarker {
|
||||
pub mark: Mark,
|
||||
pub mark: Mark,
|
||||
}
|
||||
|
||||
impl Treeshaker {
|
||||
pub fn new() -> Self {
|
||||
let mark = Mark::new();
|
||||
Self {
|
||||
marker: CleanMarker { mark },
|
||||
cleaner: CleanSideEffects {
|
||||
did_drop: false,
|
||||
mark,
|
||||
},
|
||||
}
|
||||
}
|
||||
pub fn new() -> Self {
|
||||
let mark = Mark::new();
|
||||
Self {
|
||||
marker: CleanMarker { mark },
|
||||
cleaner: CleanSideEffects {
|
||||
did_drop: false,
|
||||
mark,
|
||||
},
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl VisitMut for CleanMarker {
|
||||
fn visit_mut_module_item(&mut self, node: &mut ast::ModuleItem) {
|
||||
if let ast::ModuleItem::Stmt(ast::Stmt::Expr(expr)) = node {
|
||||
expr.span = expr.span.apply_mark(self.mark);
|
||||
}
|
||||
}
|
||||
fn visit_mut_module_item(&mut self, node: &mut ast::ModuleItem) {
|
||||
if let ast::ModuleItem::Stmt(ast::Stmt::Expr(expr)) = node {
|
||||
expr.span = expr.span.apply_mark(self.mark);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl VisitMut for CleanSideEffects {
|
||||
fn visit_mut_module(&mut self, node: &mut ast::Module) {
|
||||
let it = node.body.extract_if(|item| {
|
||||
if item.span().has_mark(self.mark) {
|
||||
return false;
|
||||
}
|
||||
match item {
|
||||
ast::ModuleItem::Stmt(ast::Stmt::Expr(expr)) => match *expr.expr {
|
||||
ast::Expr::New(_) | ast::Expr::Call(_) => {
|
||||
self.did_drop = true;
|
||||
true
|
||||
}
|
||||
_ => false,
|
||||
},
|
||||
_ => false,
|
||||
}
|
||||
});
|
||||
// Consume the iterator to force the extraction.
|
||||
for _ in it {}
|
||||
}
|
||||
fn visit_mut_module(&mut self, node: &mut ast::Module) {
|
||||
let it = node.body.extract_if(|item| {
|
||||
if item.span().has_mark(self.mark) {
|
||||
return false;
|
||||
}
|
||||
match item {
|
||||
ast::ModuleItem::Stmt(ast::Stmt::Expr(expr)) => match *expr.expr {
|
||||
ast::Expr::New(_) | ast::Expr::Call(_) => {
|
||||
self.did_drop = true;
|
||||
true
|
||||
}
|
||||
_ => false,
|
||||
},
|
||||
_ => false,
|
||||
}
|
||||
});
|
||||
// Consume the iterator to force the extraction.
|
||||
for _ in it {}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
use crate::collector::{new_ident_from_id, GlobalCollect, Id, ImportKind};
|
||||
use crate::parse::{
|
||||
emit_source_code, might_need_handle_watch, HookAnalysis, PathData, TransformModule,
|
||||
TransformOutput,
|
||||
emit_source_code, might_need_handle_watch, HookAnalysis, PathData, TransformModule,
|
||||
TransformOutput,
|
||||
};
|
||||
use crate::transform::{add_handle_watch, create_synthetic_named_import};
|
||||
use crate::words::*;
|
||||
@@ -18,416 +18,416 @@ use swc_ecmascript::ast;
|
||||
use swc_ecmascript::utils::private_ident;
|
||||
|
||||
macro_rules! id {
|
||||
($ident: expr) => {
|
||||
($ident.sym.clone(), $ident.span.ctxt())
|
||||
};
|
||||
($ident: expr) => {
|
||||
($ident.sym.clone(), $ident.span.ctxt())
|
||||
};
|
||||
}
|
||||
|
||||
pub struct NewModuleCtx<'a> {
|
||||
pub expr: Box<ast::Expr>,
|
||||
pub path: &'a PathData,
|
||||
pub name: &'a str,
|
||||
pub local_idents: &'a [Id],
|
||||
pub scoped_idents: &'a [Id],
|
||||
pub global: &'a GlobalCollect,
|
||||
pub core_module: &'a JsWord,
|
||||
pub is_entry: bool,
|
||||
pub need_handle_watch: bool,
|
||||
pub need_transform: bool,
|
||||
pub explicit_extensions: bool,
|
||||
pub leading_comments: SingleThreadedCommentsMap,
|
||||
pub trailing_comments: SingleThreadedCommentsMap,
|
||||
pub expr: Box<ast::Expr>,
|
||||
pub path: &'a PathData,
|
||||
pub name: &'a str,
|
||||
pub local_idents: &'a [Id],
|
||||
pub scoped_idents: &'a [Id],
|
||||
pub global: &'a GlobalCollect,
|
||||
pub core_module: &'a JsWord,
|
||||
pub is_entry: bool,
|
||||
pub need_handle_watch: bool,
|
||||
pub need_transform: bool,
|
||||
pub explicit_extensions: bool,
|
||||
pub leading_comments: SingleThreadedCommentsMap,
|
||||
pub trailing_comments: SingleThreadedCommentsMap,
|
||||
}
|
||||
|
||||
pub fn new_module(ctx: NewModuleCtx) -> Result<(ast::Module, SingleThreadedComments), Error> {
|
||||
let comments = SingleThreadedComments::from_leading_and_trailing(
|
||||
ctx.leading_comments,
|
||||
ctx.trailing_comments,
|
||||
);
|
||||
let max_cap = ctx.global.imports.len() + ctx.global.exports.len();
|
||||
let mut module = ast::Module {
|
||||
span: DUMMY_SP,
|
||||
body: Vec::with_capacity(max_cap),
|
||||
shebang: None,
|
||||
};
|
||||
let comments = SingleThreadedComments::from_leading_and_trailing(
|
||||
ctx.leading_comments,
|
||||
ctx.trailing_comments,
|
||||
);
|
||||
let max_cap = ctx.global.imports.len() + ctx.global.exports.len();
|
||||
let mut module = ast::Module {
|
||||
span: DUMMY_SP,
|
||||
body: Vec::with_capacity(max_cap),
|
||||
shebang: None,
|
||||
};
|
||||
|
||||
let has_scoped_idents = ctx.need_transform && !ctx.scoped_idents.is_empty();
|
||||
let use_lexical_scope = if has_scoped_idents {
|
||||
let new_local = id!(private_ident!(&USE_LEXICAL_SCOPE.clone()));
|
||||
module
|
||||
.body
|
||||
.push(create_synthetic_named_import(&new_local, ctx.core_module));
|
||||
Some(new_local)
|
||||
} else {
|
||||
None
|
||||
};
|
||||
let has_scoped_idents = ctx.need_transform && !ctx.scoped_idents.is_empty();
|
||||
let use_lexical_scope = if has_scoped_idents {
|
||||
let new_local = id!(private_ident!(&USE_LEXICAL_SCOPE.clone()));
|
||||
module
|
||||
.body
|
||||
.push(create_synthetic_named_import(&new_local, ctx.core_module));
|
||||
Some(new_local)
|
||||
} else {
|
||||
None
|
||||
};
|
||||
|
||||
for id in ctx.local_idents {
|
||||
if let Some(import) = ctx.global.imports.get(id) {
|
||||
let specifier = match import.kind {
|
||||
ImportKind::Named => ast::ImportSpecifier::Named(ast::ImportNamedSpecifier {
|
||||
is_type_only: false,
|
||||
span: DUMMY_SP,
|
||||
imported: if import.specifier == id.0 {
|
||||
None
|
||||
} else {
|
||||
Some(ast::ModuleExportName::Ident(ast::Ident::new(
|
||||
import.specifier.clone(),
|
||||
DUMMY_SP,
|
||||
)))
|
||||
},
|
||||
local: new_ident_from_id(id),
|
||||
}),
|
||||
ImportKind::Default => ast::ImportSpecifier::Default(ast::ImportDefaultSpecifier {
|
||||
span: DUMMY_SP,
|
||||
local: new_ident_from_id(id),
|
||||
}),
|
||||
ImportKind::All => ast::ImportSpecifier::Namespace(ast::ImportStarAsSpecifier {
|
||||
span: DUMMY_SP,
|
||||
local: new_ident_from_id(id),
|
||||
}),
|
||||
};
|
||||
module
|
||||
.body
|
||||
.push(ast::ModuleItem::ModuleDecl(ast::ModuleDecl::Import(
|
||||
ast::ImportDecl {
|
||||
span: DUMMY_SP,
|
||||
type_only: false,
|
||||
asserts: import.asserts.clone(),
|
||||
src: Box::new(ast::Str {
|
||||
span: DUMMY_SP,
|
||||
value: fix_path(
|
||||
&ctx.path.abs_dir,
|
||||
&ctx.path.base_dir,
|
||||
import.source.as_ref(),
|
||||
)?,
|
||||
raw: None,
|
||||
}),
|
||||
specifiers: vec![specifier],
|
||||
},
|
||||
)));
|
||||
} else if let Some(export) = ctx.global.exports.get(id) {
|
||||
let filename = if ctx.explicit_extensions {
|
||||
&ctx.path.file_name
|
||||
} else {
|
||||
&ctx.path.file_stem
|
||||
};
|
||||
let imported = export
|
||||
.as_ref()
|
||||
.map(|e| ast::ModuleExportName::Ident(ast::Ident::new(e.clone(), DUMMY_SP)));
|
||||
module
|
||||
.body
|
||||
.push(ast::ModuleItem::ModuleDecl(ast::ModuleDecl::Import(
|
||||
ast::ImportDecl {
|
||||
span: DUMMY_SP,
|
||||
type_only: false,
|
||||
asserts: None,
|
||||
src: Box::new(ast::Str {
|
||||
span: DUMMY_SP,
|
||||
value: fix_path(
|
||||
&ctx.path.abs_dir,
|
||||
&ctx.path.base_dir,
|
||||
&format!("./{}", filename),
|
||||
)?,
|
||||
raw: None,
|
||||
}),
|
||||
specifiers: vec![ast::ImportSpecifier::Named(ast::ImportNamedSpecifier {
|
||||
is_type_only: false,
|
||||
span: DUMMY_SP,
|
||||
imported,
|
||||
local: new_ident_from_id(id),
|
||||
})],
|
||||
},
|
||||
)));
|
||||
}
|
||||
}
|
||||
for id in ctx.local_idents {
|
||||
if let Some(import) = ctx.global.imports.get(id) {
|
||||
let specifier = match import.kind {
|
||||
ImportKind::Named => ast::ImportSpecifier::Named(ast::ImportNamedSpecifier {
|
||||
is_type_only: false,
|
||||
span: DUMMY_SP,
|
||||
imported: if import.specifier == id.0 {
|
||||
None
|
||||
} else {
|
||||
Some(ast::ModuleExportName::Ident(ast::Ident::new(
|
||||
import.specifier.clone(),
|
||||
DUMMY_SP,
|
||||
)))
|
||||
},
|
||||
local: new_ident_from_id(id),
|
||||
}),
|
||||
ImportKind::Default => ast::ImportSpecifier::Default(ast::ImportDefaultSpecifier {
|
||||
span: DUMMY_SP,
|
||||
local: new_ident_from_id(id),
|
||||
}),
|
||||
ImportKind::All => ast::ImportSpecifier::Namespace(ast::ImportStarAsSpecifier {
|
||||
span: DUMMY_SP,
|
||||
local: new_ident_from_id(id),
|
||||
}),
|
||||
};
|
||||
module
|
||||
.body
|
||||
.push(ast::ModuleItem::ModuleDecl(ast::ModuleDecl::Import(
|
||||
ast::ImportDecl {
|
||||
span: DUMMY_SP,
|
||||
type_only: false,
|
||||
asserts: import.asserts.clone(),
|
||||
src: Box::new(ast::Str {
|
||||
span: DUMMY_SP,
|
||||
value: fix_path(
|
||||
&ctx.path.abs_dir,
|
||||
&ctx.path.base_dir,
|
||||
import.source.as_ref(),
|
||||
)?,
|
||||
raw: None,
|
||||
}),
|
||||
specifiers: vec![specifier],
|
||||
},
|
||||
)));
|
||||
} else if let Some(export) = ctx.global.exports.get(id) {
|
||||
let filename = if ctx.explicit_extensions {
|
||||
&ctx.path.file_name
|
||||
} else {
|
||||
&ctx.path.file_stem
|
||||
};
|
||||
let imported = export
|
||||
.as_ref()
|
||||
.map(|e| ast::ModuleExportName::Ident(ast::Ident::new(e.clone(), DUMMY_SP)));
|
||||
module
|
||||
.body
|
||||
.push(ast::ModuleItem::ModuleDecl(ast::ModuleDecl::Import(
|
||||
ast::ImportDecl {
|
||||
span: DUMMY_SP,
|
||||
type_only: false,
|
||||
asserts: None,
|
||||
src: Box::new(ast::Str {
|
||||
span: DUMMY_SP,
|
||||
value: fix_path(
|
||||
&ctx.path.abs_dir,
|
||||
&ctx.path.base_dir,
|
||||
&format!("./{}", filename),
|
||||
)?,
|
||||
raw: None,
|
||||
}),
|
||||
specifiers: vec![ast::ImportSpecifier::Named(ast::ImportNamedSpecifier {
|
||||
is_type_only: false,
|
||||
span: DUMMY_SP,
|
||||
imported,
|
||||
local: new_ident_from_id(id),
|
||||
})],
|
||||
},
|
||||
)));
|
||||
}
|
||||
}
|
||||
|
||||
let expr = if let Some(use_lexical_scope) = use_lexical_scope {
|
||||
Box::new(transform_function_expr(
|
||||
*ctx.expr,
|
||||
&use_lexical_scope,
|
||||
ctx.scoped_idents,
|
||||
))
|
||||
} else {
|
||||
ctx.expr
|
||||
};
|
||||
let expr = if let Some(use_lexical_scope) = use_lexical_scope {
|
||||
Box::new(transform_function_expr(
|
||||
*ctx.expr,
|
||||
&use_lexical_scope,
|
||||
ctx.scoped_idents,
|
||||
))
|
||||
} else {
|
||||
ctx.expr
|
||||
};
|
||||
|
||||
module.body.push(create_named_export(expr, ctx.name));
|
||||
if ctx.need_handle_watch {
|
||||
// Inject qwik internal import
|
||||
add_handle_watch(&mut module.body, ctx.core_module);
|
||||
}
|
||||
Ok((module, comments))
|
||||
module.body.push(create_named_export(expr, ctx.name));
|
||||
if ctx.need_handle_watch {
|
||||
// Inject qwik internal import
|
||||
add_handle_watch(&mut module.body, ctx.core_module);
|
||||
}
|
||||
Ok((module, comments))
|
||||
}
|
||||
|
||||
pub fn fix_path<S: AsRef<Path>, D: AsRef<Path>>(
|
||||
src: S,
|
||||
dest: D,
|
||||
ident: &str,
|
||||
src: S,
|
||||
dest: D,
|
||||
ident: &str,
|
||||
) -> Result<JsWord, Error> {
|
||||
let src = src.as_ref();
|
||||
let dest = dest.as_ref();
|
||||
if ident.starts_with('.') {
|
||||
let diff = pathdiff::diff_paths(src, dest);
|
||||
let src = src.as_ref();
|
||||
let dest = dest.as_ref();
|
||||
if ident.starts_with('.') {
|
||||
let diff = pathdiff::diff_paths(src, dest);
|
||||
|
||||
if let Some(diff) = diff {
|
||||
let normalize = diff.to_slash_lossy();
|
||||
let relative = relative_path::RelativePath::new(&normalize);
|
||||
let final_path = relative.join(ident).normalize();
|
||||
let final_str = final_path.as_str();
|
||||
return Ok(if final_str.starts_with('.') {
|
||||
JsWord::from(final_str)
|
||||
} else {
|
||||
JsWord::from(format!("./{}", final_str))
|
||||
});
|
||||
}
|
||||
}
|
||||
if let Some(diff) = diff {
|
||||
let normalize = diff.to_slash_lossy();
|
||||
let relative = relative_path::RelativePath::new(&normalize);
|
||||
let final_path = relative.join(ident).normalize();
|
||||
let final_str = final_path.as_str();
|
||||
return Ok(if final_str.starts_with('.') {
|
||||
JsWord::from(final_str)
|
||||
} else {
|
||||
JsWord::from(format!("./{}", final_str))
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
Ok(JsWord::from(ident))
|
||||
Ok(JsWord::from(ident))
|
||||
}
|
||||
|
||||
fn create_named_export(expr: Box<ast::Expr>, name: &str) -> ast::ModuleItem {
|
||||
ast::ModuleItem::ModuleDecl(ast::ModuleDecl::ExportDecl(ast::ExportDecl {
|
||||
span: DUMMY_SP,
|
||||
decl: ast::Decl::Var(Box::new(ast::VarDecl {
|
||||
span: DUMMY_SP,
|
||||
kind: ast::VarDeclKind::Const,
|
||||
declare: false,
|
||||
decls: vec![ast::VarDeclarator {
|
||||
span: DUMMY_SP,
|
||||
definite: false,
|
||||
name: ast::Pat::Ident(ast::BindingIdent::from(ast::Ident::new(
|
||||
JsWord::from(name),
|
||||
DUMMY_SP,
|
||||
))),
|
||||
init: Some(expr),
|
||||
}],
|
||||
})),
|
||||
}))
|
||||
ast::ModuleItem::ModuleDecl(ast::ModuleDecl::ExportDecl(ast::ExportDecl {
|
||||
span: DUMMY_SP,
|
||||
decl: ast::Decl::Var(Box::new(ast::VarDecl {
|
||||
span: DUMMY_SP,
|
||||
kind: ast::VarDeclKind::Const,
|
||||
declare: false,
|
||||
decls: vec![ast::VarDeclarator {
|
||||
span: DUMMY_SP,
|
||||
definite: false,
|
||||
name: ast::Pat::Ident(ast::BindingIdent::from(ast::Ident::new(
|
||||
JsWord::from(name),
|
||||
DUMMY_SP,
|
||||
))),
|
||||
init: Some(expr),
|
||||
}],
|
||||
})),
|
||||
}))
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_fix_path() {
|
||||
assert_eq!(
|
||||
fix_path("src", "", "./state.qwik.mjs").unwrap(),
|
||||
JsWord::from("./src/state.qwik.mjs")
|
||||
);
|
||||
assert_eq!(
|
||||
fix_path("src", "", "./state.qwik.mjs").unwrap(),
|
||||
JsWord::from("./src/state.qwik.mjs")
|
||||
);
|
||||
|
||||
assert_eq!(
|
||||
fix_path("src/path", "", "./state").unwrap(),
|
||||
JsWord::from("./src/path/state")
|
||||
);
|
||||
assert_eq!(
|
||||
fix_path("src/path", "", "./state").unwrap(),
|
||||
JsWord::from("./src/path/state")
|
||||
);
|
||||
|
||||
assert_eq!(
|
||||
fix_path("src", "", "../state").unwrap(),
|
||||
JsWord::from("./state")
|
||||
);
|
||||
assert_eq!(
|
||||
fix_path("a", "a", "./state").unwrap(),
|
||||
JsWord::from("./state")
|
||||
);
|
||||
assert_eq!(
|
||||
fix_path("src", "", "../state").unwrap(),
|
||||
JsWord::from("./state")
|
||||
);
|
||||
assert_eq!(
|
||||
fix_path("a", "a", "./state").unwrap(),
|
||||
JsWord::from("./state")
|
||||
);
|
||||
}
|
||||
|
||||
pub fn generate_entries(
|
||||
mut output: TransformOutput,
|
||||
core_module: &JsWord,
|
||||
explicit_extensions: bool,
|
||||
root_dir: Option<&Path>,
|
||||
mut output: TransformOutput,
|
||||
core_module: &JsWord,
|
||||
explicit_extensions: bool,
|
||||
root_dir: Option<&Path>,
|
||||
) -> Result<TransformOutput, anyhow::Error> {
|
||||
let source_map = Lrc::new(SourceMap::default());
|
||||
let mut entries_map: BTreeMap<&str, Vec<&HookAnalysis>> = BTreeMap::new();
|
||||
let mut new_modules = Vec::with_capacity(output.modules.len());
|
||||
{
|
||||
let hooks: Vec<&HookAnalysis> = output.modules.iter().flat_map(|m| &m.hook).collect();
|
||||
for hook in hooks {
|
||||
if let Some(ref e) = hook.entry {
|
||||
entries_map
|
||||
.entry(e.as_ref())
|
||||
.or_insert_with(Vec::new)
|
||||
.push(hook);
|
||||
}
|
||||
}
|
||||
let source_map = Lrc::new(SourceMap::default());
|
||||
let mut entries_map: BTreeMap<&str, Vec<&HookAnalysis>> = BTreeMap::new();
|
||||
let mut new_modules = Vec::with_capacity(output.modules.len());
|
||||
{
|
||||
let hooks: Vec<&HookAnalysis> = output.modules.iter().flat_map(|m| &m.hook).collect();
|
||||
for hook in hooks {
|
||||
if let Some(ref e) = hook.entry {
|
||||
entries_map
|
||||
.entry(e.as_ref())
|
||||
.or_insert_with(Vec::new)
|
||||
.push(hook);
|
||||
}
|
||||
}
|
||||
|
||||
for (entry, hooks) in &entries_map {
|
||||
let module = new_entry_module(hooks, core_module, explicit_extensions);
|
||||
let (code, map) =
|
||||
emit_source_code(Lrc::clone(&source_map), None, &module, root_dir, false)
|
||||
.context("Emitting source code")?;
|
||||
new_modules.push(TransformModule {
|
||||
path: [entry, ".js"].concat(),
|
||||
code,
|
||||
map,
|
||||
is_entry: true,
|
||||
hook: None,
|
||||
order: 0,
|
||||
});
|
||||
}
|
||||
}
|
||||
output.modules.append(&mut new_modules);
|
||||
for (entry, hooks) in &entries_map {
|
||||
let module = new_entry_module(hooks, core_module, explicit_extensions);
|
||||
let (code, map) =
|
||||
emit_source_code(Lrc::clone(&source_map), None, &module, root_dir, false)
|
||||
.context("Emitting source code")?;
|
||||
new_modules.push(TransformModule {
|
||||
path: [entry, ".js"].concat(),
|
||||
code,
|
||||
map,
|
||||
is_entry: true,
|
||||
hook: None,
|
||||
order: 0,
|
||||
});
|
||||
}
|
||||
}
|
||||
output.modules.append(&mut new_modules);
|
||||
|
||||
Ok(output)
|
||||
Ok(output)
|
||||
}
|
||||
|
||||
fn new_entry_module(
|
||||
hooks: &[&HookAnalysis],
|
||||
core_module: &JsWord,
|
||||
explicit_extensions: bool,
|
||||
hooks: &[&HookAnalysis],
|
||||
core_module: &JsWord,
|
||||
explicit_extensions: bool,
|
||||
) -> ast::Module {
|
||||
let mut module = ast::Module {
|
||||
span: DUMMY_SP,
|
||||
body: Vec::with_capacity(hooks.len()),
|
||||
shebang: None,
|
||||
};
|
||||
let mut need_handle_watch = false;
|
||||
for hook in hooks {
|
||||
let mut src = ["./", &hook.canonical_filename].concat();
|
||||
if explicit_extensions {
|
||||
src = src + "." + hook.extension.as_ref();
|
||||
}
|
||||
if might_need_handle_watch(&hook.ctx_kind, &hook.ctx_name) {
|
||||
need_handle_watch = true;
|
||||
}
|
||||
module
|
||||
.body
|
||||
.push(ast::ModuleItem::ModuleDecl(ast::ModuleDecl::ExportNamed(
|
||||
ast::NamedExport {
|
||||
span: DUMMY_SP,
|
||||
type_only: false,
|
||||
asserts: None,
|
||||
src: Some(Box::new(ast::Str {
|
||||
span: DUMMY_SP,
|
||||
value: JsWord::from(src),
|
||||
raw: None,
|
||||
})),
|
||||
specifiers: vec![ast::ExportSpecifier::Named(ast::ExportNamedSpecifier {
|
||||
is_type_only: false,
|
||||
span: DUMMY_SP,
|
||||
orig: ast::ModuleExportName::Ident(ast::Ident::new(
|
||||
hook.name.clone(),
|
||||
DUMMY_SP,
|
||||
)),
|
||||
exported: None,
|
||||
})],
|
||||
},
|
||||
)));
|
||||
}
|
||||
if need_handle_watch {
|
||||
add_handle_watch(&mut module.body, core_module);
|
||||
}
|
||||
module
|
||||
let mut module = ast::Module {
|
||||
span: DUMMY_SP,
|
||||
body: Vec::with_capacity(hooks.len()),
|
||||
shebang: None,
|
||||
};
|
||||
let mut need_handle_watch = false;
|
||||
for hook in hooks {
|
||||
let mut src = ["./", &hook.canonical_filename].concat();
|
||||
if explicit_extensions {
|
||||
src = src + "." + hook.extension.as_ref();
|
||||
}
|
||||
if might_need_handle_watch(&hook.ctx_kind, &hook.ctx_name) {
|
||||
need_handle_watch = true;
|
||||
}
|
||||
module
|
||||
.body
|
||||
.push(ast::ModuleItem::ModuleDecl(ast::ModuleDecl::ExportNamed(
|
||||
ast::NamedExport {
|
||||
span: DUMMY_SP,
|
||||
type_only: false,
|
||||
asserts: None,
|
||||
src: Some(Box::new(ast::Str {
|
||||
span: DUMMY_SP,
|
||||
value: JsWord::from(src),
|
||||
raw: None,
|
||||
})),
|
||||
specifiers: vec![ast::ExportSpecifier::Named(ast::ExportNamedSpecifier {
|
||||
is_type_only: false,
|
||||
span: DUMMY_SP,
|
||||
orig: ast::ModuleExportName::Ident(ast::Ident::new(
|
||||
hook.name.clone(),
|
||||
DUMMY_SP,
|
||||
)),
|
||||
exported: None,
|
||||
})],
|
||||
},
|
||||
)));
|
||||
}
|
||||
if need_handle_watch {
|
||||
add_handle_watch(&mut module.body, core_module);
|
||||
}
|
||||
module
|
||||
}
|
||||
|
||||
pub fn transform_function_expr(
|
||||
expr: ast::Expr,
|
||||
use_lexical_scope: &Id,
|
||||
scoped_idents: &[Id],
|
||||
expr: ast::Expr,
|
||||
use_lexical_scope: &Id,
|
||||
scoped_idents: &[Id],
|
||||
) -> ast::Expr {
|
||||
match expr {
|
||||
ast::Expr::Arrow(node) => {
|
||||
ast::Expr::Arrow(transform_arrow_fn(node, use_lexical_scope, scoped_idents))
|
||||
}
|
||||
ast::Expr::Fn(node) => ast::Expr::Fn(transform_fn(node, use_lexical_scope, scoped_idents)),
|
||||
_ => expr,
|
||||
}
|
||||
match expr {
|
||||
ast::Expr::Arrow(node) => {
|
||||
ast::Expr::Arrow(transform_arrow_fn(node, use_lexical_scope, scoped_idents))
|
||||
}
|
||||
ast::Expr::Fn(node) => ast::Expr::Fn(transform_fn(node, use_lexical_scope, scoped_idents)),
|
||||
_ => expr,
|
||||
}
|
||||
}
|
||||
|
||||
fn transform_arrow_fn(
|
||||
arrow: ast::ArrowExpr,
|
||||
use_lexical_scope: &Id,
|
||||
scoped_idents: &[Id],
|
||||
arrow: ast::ArrowExpr,
|
||||
use_lexical_scope: &Id,
|
||||
scoped_idents: &[Id],
|
||||
) -> ast::ArrowExpr {
|
||||
match arrow.body {
|
||||
box ast::BlockStmtOrExpr::BlockStmt(mut block) => {
|
||||
let mut stmts = Vec::with_capacity(1 + block.stmts.len());
|
||||
stmts.push(create_use_lexical_scope(use_lexical_scope, scoped_idents));
|
||||
stmts.append(&mut block.stmts);
|
||||
ast::ArrowExpr {
|
||||
body: Box::new(ast::BlockStmtOrExpr::BlockStmt(ast::BlockStmt {
|
||||
span: DUMMY_SP,
|
||||
stmts,
|
||||
})),
|
||||
..arrow
|
||||
}
|
||||
}
|
||||
box ast::BlockStmtOrExpr::Expr(expr) => {
|
||||
let mut stmts = Vec::with_capacity(2);
|
||||
if !scoped_idents.is_empty() {
|
||||
stmts.push(create_use_lexical_scope(use_lexical_scope, scoped_idents));
|
||||
}
|
||||
stmts.push(create_return_stmt(expr));
|
||||
ast::ArrowExpr {
|
||||
body: Box::new(ast::BlockStmtOrExpr::BlockStmt(ast::BlockStmt {
|
||||
span: DUMMY_SP,
|
||||
stmts,
|
||||
})),
|
||||
..arrow
|
||||
}
|
||||
}
|
||||
}
|
||||
match arrow.body {
|
||||
box ast::BlockStmtOrExpr::BlockStmt(mut block) => {
|
||||
let mut stmts = Vec::with_capacity(1 + block.stmts.len());
|
||||
stmts.push(create_use_lexical_scope(use_lexical_scope, scoped_idents));
|
||||
stmts.append(&mut block.stmts);
|
||||
ast::ArrowExpr {
|
||||
body: Box::new(ast::BlockStmtOrExpr::BlockStmt(ast::BlockStmt {
|
||||
span: DUMMY_SP,
|
||||
stmts,
|
||||
})),
|
||||
..arrow
|
||||
}
|
||||
}
|
||||
box ast::BlockStmtOrExpr::Expr(expr) => {
|
||||
let mut stmts = Vec::with_capacity(2);
|
||||
if !scoped_idents.is_empty() {
|
||||
stmts.push(create_use_lexical_scope(use_lexical_scope, scoped_idents));
|
||||
}
|
||||
stmts.push(create_return_stmt(expr));
|
||||
ast::ArrowExpr {
|
||||
body: Box::new(ast::BlockStmtOrExpr::BlockStmt(ast::BlockStmt {
|
||||
span: DUMMY_SP,
|
||||
stmts,
|
||||
})),
|
||||
..arrow
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn transform_fn(node: ast::FnExpr, use_lexical_scope: &Id, scoped_idents: &[Id]) -> ast::FnExpr {
|
||||
let mut stmts = Vec::with_capacity(
|
||||
1 + node
|
||||
.function
|
||||
.body
|
||||
.as_ref()
|
||||
.map_or(0, |body| body.stmts.len()),
|
||||
);
|
||||
if !scoped_idents.is_empty() {
|
||||
stmts.push(create_use_lexical_scope(use_lexical_scope, scoped_idents));
|
||||
}
|
||||
if let Some(mut body) = node.function.body {
|
||||
stmts.append(&mut body.stmts);
|
||||
}
|
||||
ast::FnExpr {
|
||||
function: Box::new(ast::Function {
|
||||
body: Some(ast::BlockStmt {
|
||||
span: DUMMY_SP,
|
||||
stmts,
|
||||
}),
|
||||
..*node.function
|
||||
}),
|
||||
..node
|
||||
}
|
||||
let mut stmts = Vec::with_capacity(
|
||||
1 + node
|
||||
.function
|
||||
.body
|
||||
.as_ref()
|
||||
.map_or(0, |body| body.stmts.len()),
|
||||
);
|
||||
if !scoped_idents.is_empty() {
|
||||
stmts.push(create_use_lexical_scope(use_lexical_scope, scoped_idents));
|
||||
}
|
||||
if let Some(mut body) = node.function.body {
|
||||
stmts.append(&mut body.stmts);
|
||||
}
|
||||
ast::FnExpr {
|
||||
function: Box::new(ast::Function {
|
||||
body: Some(ast::BlockStmt {
|
||||
span: DUMMY_SP,
|
||||
stmts,
|
||||
}),
|
||||
..*node.function
|
||||
}),
|
||||
..node
|
||||
}
|
||||
}
|
||||
|
||||
pub const fn create_return_stmt(expr: Box<ast::Expr>) -> ast::Stmt {
|
||||
ast::Stmt::Return(ast::ReturnStmt {
|
||||
arg: Some(expr),
|
||||
span: DUMMY_SP,
|
||||
})
|
||||
ast::Stmt::Return(ast::ReturnStmt {
|
||||
arg: Some(expr),
|
||||
span: DUMMY_SP,
|
||||
})
|
||||
}
|
||||
|
||||
fn create_use_lexical_scope(use_lexical_scope: &Id, scoped_idents: &[Id]) -> ast::Stmt {
|
||||
ast::Stmt::Decl(ast::Decl::Var(Box::new(ast::VarDecl {
|
||||
span: DUMMY_SP,
|
||||
declare: false,
|
||||
kind: ast::VarDeclKind::Const,
|
||||
decls: vec![ast::VarDeclarator {
|
||||
definite: false,
|
||||
span: DUMMY_SP,
|
||||
init: Some(Box::new(ast::Expr::Call(ast::CallExpr {
|
||||
callee: ast::Callee::Expr(Box::new(ast::Expr::Ident(new_ident_from_id(
|
||||
use_lexical_scope,
|
||||
)))),
|
||||
span: DUMMY_SP,
|
||||
type_args: None,
|
||||
args: vec![],
|
||||
}))),
|
||||
name: ast::Pat::Array(ast::ArrayPat {
|
||||
span: DUMMY_SP,
|
||||
optional: false,
|
||||
type_ann: None,
|
||||
elems: scoped_idents
|
||||
.iter()
|
||||
.map(|id| {
|
||||
Some(ast::Pat::Ident(ast::BindingIdent::from(new_ident_from_id(
|
||||
id,
|
||||
))))
|
||||
})
|
||||
.collect(),
|
||||
}),
|
||||
}],
|
||||
})))
|
||||
ast::Stmt::Decl(ast::Decl::Var(Box::new(ast::VarDecl {
|
||||
span: DUMMY_SP,
|
||||
declare: false,
|
||||
kind: ast::VarDeclKind::Const,
|
||||
decls: vec![ast::VarDeclarator {
|
||||
definite: false,
|
||||
span: DUMMY_SP,
|
||||
init: Some(Box::new(ast::Expr::Call(ast::CallExpr {
|
||||
callee: ast::Callee::Expr(Box::new(ast::Expr::Ident(new_ident_from_id(
|
||||
use_lexical_scope,
|
||||
)))),
|
||||
span: DUMMY_SP,
|
||||
type_args: None,
|
||||
args: vec![],
|
||||
}))),
|
||||
name: ast::Pat::Array(ast::ArrayPat {
|
||||
span: DUMMY_SP,
|
||||
optional: false,
|
||||
type_ann: None,
|
||||
elems: scoped_idents
|
||||
.iter()
|
||||
.map(|id| {
|
||||
Some(ast::Pat::Ident(ast::BindingIdent::from(new_ident_from_id(
|
||||
id,
|
||||
))))
|
||||
})
|
||||
.collect(),
|
||||
}),
|
||||
}],
|
||||
})))
|
||||
}
|
||||
|
||||
@@ -7,429 +7,429 @@ use swc_ecmascript::utils::private_ident;
|
||||
use swc_ecmascript::visit::{noop_visit_type, visit_expr, visit_stmt, Visit, VisitWith};
|
||||
|
||||
macro_rules! id {
|
||||
($ident: expr) => {
|
||||
($ident.sym.clone(), $ident.span.ctxt())
|
||||
};
|
||||
($ident: expr) => {
|
||||
($ident.sym.clone(), $ident.span.ctxt())
|
||||
};
|
||||
}
|
||||
|
||||
pub type Id = (JsWord, SyntaxContext);
|
||||
|
||||
pub fn new_ident_from_id(id: &Id) -> ast::Ident {
|
||||
ast::Ident::new(
|
||||
id.0.clone(),
|
||||
Span {
|
||||
lo: BytePos(0),
|
||||
hi: BytePos(0),
|
||||
ctxt: id.1,
|
||||
},
|
||||
)
|
||||
ast::Ident::new(
|
||||
id.0.clone(),
|
||||
Span {
|
||||
lo: BytePos(0),
|
||||
hi: BytePos(0),
|
||||
ctxt: id.1,
|
||||
},
|
||||
)
|
||||
}
|
||||
|
||||
#[derive(Eq, PartialEq, Clone, Copy)]
|
||||
pub enum ImportKind {
|
||||
Named,
|
||||
All,
|
||||
Default,
|
||||
Named,
|
||||
All,
|
||||
Default,
|
||||
}
|
||||
|
||||
#[derive(Clone)]
|
||||
pub struct Import {
|
||||
pub source: JsWord,
|
||||
pub specifier: JsWord,
|
||||
pub kind: ImportKind,
|
||||
pub synthetic: bool,
|
||||
pub asserts: Option<Box<ast::ObjectLit>>,
|
||||
pub source: JsWord,
|
||||
pub specifier: JsWord,
|
||||
pub kind: ImportKind,
|
||||
pub synthetic: bool,
|
||||
pub asserts: Option<Box<ast::ObjectLit>>,
|
||||
}
|
||||
|
||||
pub struct GlobalCollect {
|
||||
pub synthetic: Vec<(Id, Import)>,
|
||||
pub imports: HashMap<Id, Import>,
|
||||
pub exports: HashMap<Id, Option<JsWord>>,
|
||||
pub root: HashMap<Id, Span>,
|
||||
pub synthetic: Vec<(Id, Import)>,
|
||||
pub imports: HashMap<Id, Import>,
|
||||
pub exports: HashMap<Id, Option<JsWord>>,
|
||||
pub root: HashMap<Id, Span>,
|
||||
|
||||
rev_imports: HashMap<(JsWord, JsWord), Id>,
|
||||
in_export_decl: bool,
|
||||
rev_imports: HashMap<(JsWord, JsWord), Id>,
|
||||
in_export_decl: bool,
|
||||
}
|
||||
|
||||
pub fn global_collect(module: &ast::Module) -> GlobalCollect {
|
||||
let mut collect = GlobalCollect {
|
||||
synthetic: vec![],
|
||||
imports: HashMap::with_capacity(16),
|
||||
exports: HashMap::with_capacity(16),
|
||||
let mut collect = GlobalCollect {
|
||||
synthetic: vec![],
|
||||
imports: HashMap::with_capacity(16),
|
||||
exports: HashMap::with_capacity(16),
|
||||
|
||||
root: HashMap::with_capacity(16),
|
||||
rev_imports: HashMap::with_capacity(16),
|
||||
root: HashMap::with_capacity(16),
|
||||
rev_imports: HashMap::with_capacity(16),
|
||||
|
||||
in_export_decl: false,
|
||||
};
|
||||
module.visit_with(&mut collect);
|
||||
collect
|
||||
in_export_decl: false,
|
||||
};
|
||||
module.visit_with(&mut collect);
|
||||
collect
|
||||
}
|
||||
|
||||
impl GlobalCollect {
|
||||
pub fn get_imported_local(&self, specifier: &JsWord, source: &JsWord) -> Option<Id> {
|
||||
self.imports
|
||||
.iter()
|
||||
.find(|(_, import)| &import.specifier == specifier && &import.source == source)
|
||||
.map(|s| s.0.clone())
|
||||
}
|
||||
pub fn get_imported_local(&self, specifier: &JsWord, source: &JsWord) -> Option<Id> {
|
||||
self.imports
|
||||
.iter()
|
||||
.find(|(_, import)| &import.specifier == specifier && &import.source == source)
|
||||
.map(|s| s.0.clone())
|
||||
}
|
||||
|
||||
pub fn is_global(&self, local: &Id) -> bool {
|
||||
if self.imports.contains_key(local) {
|
||||
return true;
|
||||
}
|
||||
if self.exports.contains_key(local) {
|
||||
return true;
|
||||
}
|
||||
if self.root.contains_key(local) {
|
||||
return true;
|
||||
}
|
||||
false
|
||||
}
|
||||
pub fn is_global(&self, local: &Id) -> bool {
|
||||
if self.imports.contains_key(local) {
|
||||
return true;
|
||||
}
|
||||
if self.exports.contains_key(local) {
|
||||
return true;
|
||||
}
|
||||
if self.root.contains_key(local) {
|
||||
return true;
|
||||
}
|
||||
false
|
||||
}
|
||||
|
||||
pub fn import(&mut self, specifier: &JsWord, source: &JsWord) -> Id {
|
||||
self.rev_imports
|
||||
.get(&(specifier.clone(), source.clone()))
|
||||
.cloned()
|
||||
.map_or_else(
|
||||
|| {
|
||||
let local = id!(private_ident!(specifier));
|
||||
self.add_import(
|
||||
local.clone(),
|
||||
Import {
|
||||
source: source.clone(),
|
||||
specifier: specifier.clone(),
|
||||
kind: ImportKind::Named,
|
||||
synthetic: true,
|
||||
asserts: None,
|
||||
},
|
||||
);
|
||||
local
|
||||
},
|
||||
|local| local,
|
||||
)
|
||||
}
|
||||
pub fn import(&mut self, specifier: &JsWord, source: &JsWord) -> Id {
|
||||
self.rev_imports
|
||||
.get(&(specifier.clone(), source.clone()))
|
||||
.cloned()
|
||||
.map_or_else(
|
||||
|| {
|
||||
let local = id!(private_ident!(specifier));
|
||||
self.add_import(
|
||||
local.clone(),
|
||||
Import {
|
||||
source: source.clone(),
|
||||
specifier: specifier.clone(),
|
||||
kind: ImportKind::Named,
|
||||
synthetic: true,
|
||||
asserts: None,
|
||||
},
|
||||
);
|
||||
local
|
||||
},
|
||||
|local| local,
|
||||
)
|
||||
}
|
||||
|
||||
pub fn add_import(&mut self, local: Id, import: Import) {
|
||||
if import.synthetic {
|
||||
self.synthetic.push((local.clone(), import.clone()));
|
||||
}
|
||||
self.rev_imports.insert(
|
||||
(import.specifier.clone(), import.source.clone()),
|
||||
local.clone(),
|
||||
);
|
||||
self.imports.insert(local, import);
|
||||
}
|
||||
pub fn add_import(&mut self, local: Id, import: Import) {
|
||||
if import.synthetic {
|
||||
self.synthetic.push((local.clone(), import.clone()));
|
||||
}
|
||||
self.rev_imports.insert(
|
||||
(import.specifier.clone(), import.source.clone()),
|
||||
local.clone(),
|
||||
);
|
||||
self.imports.insert(local, import);
|
||||
}
|
||||
|
||||
pub fn add_export(&mut self, local: Id, exported: Option<JsWord>) -> bool {
|
||||
if let std::collections::hash_map::Entry::Vacant(e) = self.exports.entry(local) {
|
||||
e.insert(exported);
|
||||
true
|
||||
} else {
|
||||
false
|
||||
}
|
||||
}
|
||||
pub fn add_export(&mut self, local: Id, exported: Option<JsWord>) -> bool {
|
||||
if let std::collections::hash_map::Entry::Vacant(e) = self.exports.entry(local) {
|
||||
e.insert(exported);
|
||||
true
|
||||
} else {
|
||||
false
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl Visit for GlobalCollect {
|
||||
noop_visit_type!();
|
||||
noop_visit_type!();
|
||||
|
||||
fn visit_module_item(&mut self, node: &ast::ModuleItem) {
|
||||
if let ast::ModuleItem::Stmt(ast::Stmt::Decl(decl)) = node {
|
||||
match decl {
|
||||
ast::Decl::Fn(function) => {
|
||||
self.root.insert(id!(function.ident), function.ident.span);
|
||||
}
|
||||
ast::Decl::Class(class) => {
|
||||
self.root.insert(id!(class.ident), class.ident.span);
|
||||
}
|
||||
ast::Decl::Var(var) => {
|
||||
for decl in &var.decls {
|
||||
let mut identifiers: Vec<(Id, Span)> = vec![];
|
||||
collect_from_pat(&decl.name, &mut identifiers);
|
||||
self.root.extend(identifiers.into_iter());
|
||||
}
|
||||
}
|
||||
ast::Decl::TsEnum(enu) => {
|
||||
self.root.insert(id!(enu.id), enu.id.span);
|
||||
}
|
||||
_ => {}
|
||||
}
|
||||
} else {
|
||||
node.visit_children_with(self);
|
||||
}
|
||||
}
|
||||
fn visit_module_item(&mut self, node: &ast::ModuleItem) {
|
||||
if let ast::ModuleItem::Stmt(ast::Stmt::Decl(decl)) = node {
|
||||
match decl {
|
||||
ast::Decl::Fn(function) => {
|
||||
self.root.insert(id!(function.ident), function.ident.span);
|
||||
}
|
||||
ast::Decl::Class(class) => {
|
||||
self.root.insert(id!(class.ident), class.ident.span);
|
||||
}
|
||||
ast::Decl::Var(var) => {
|
||||
for decl in &var.decls {
|
||||
let mut identifiers: Vec<(Id, Span)> = vec![];
|
||||
collect_from_pat(&decl.name, &mut identifiers);
|
||||
self.root.extend(identifiers.into_iter());
|
||||
}
|
||||
}
|
||||
ast::Decl::TsEnum(enu) => {
|
||||
self.root.insert(id!(enu.id), enu.id.span);
|
||||
}
|
||||
_ => {}
|
||||
}
|
||||
} else {
|
||||
node.visit_children_with(self);
|
||||
}
|
||||
}
|
||||
|
||||
fn visit_import_decl(&mut self, node: &ast::ImportDecl) {
|
||||
for specifier in &node.specifiers {
|
||||
match specifier {
|
||||
ast::ImportSpecifier::Named(named) => {
|
||||
let imported = match &named.imported {
|
||||
Some(ast::ModuleExportName::Ident(ident)) => ident.sym.clone(),
|
||||
_ => named.local.sym.clone(),
|
||||
};
|
||||
self.add_import(
|
||||
id!(named.local),
|
||||
Import {
|
||||
source: node.src.value.clone(),
|
||||
specifier: imported,
|
||||
kind: ImportKind::Named,
|
||||
synthetic: false,
|
||||
asserts: node.asserts.clone(),
|
||||
},
|
||||
);
|
||||
}
|
||||
ast::ImportSpecifier::Default(default) => {
|
||||
self.add_import(
|
||||
id!(default.local),
|
||||
Import {
|
||||
source: node.src.value.clone(),
|
||||
specifier: js_word!("default"),
|
||||
kind: ImportKind::Default,
|
||||
synthetic: false,
|
||||
asserts: node.asserts.clone(),
|
||||
},
|
||||
);
|
||||
}
|
||||
ast::ImportSpecifier::Namespace(namespace) => {
|
||||
self.add_import(
|
||||
id!(namespace.local),
|
||||
Import {
|
||||
source: node.src.value.clone(),
|
||||
specifier: "*".into(),
|
||||
kind: ImportKind::All,
|
||||
synthetic: false,
|
||||
asserts: node.asserts.clone(),
|
||||
},
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
fn visit_import_decl(&mut self, node: &ast::ImportDecl) {
|
||||
for specifier in &node.specifiers {
|
||||
match specifier {
|
||||
ast::ImportSpecifier::Named(named) => {
|
||||
let imported = match &named.imported {
|
||||
Some(ast::ModuleExportName::Ident(ident)) => ident.sym.clone(),
|
||||
_ => named.local.sym.clone(),
|
||||
};
|
||||
self.add_import(
|
||||
id!(named.local),
|
||||
Import {
|
||||
source: node.src.value.clone(),
|
||||
specifier: imported,
|
||||
kind: ImportKind::Named,
|
||||
synthetic: false,
|
||||
asserts: node.asserts.clone(),
|
||||
},
|
||||
);
|
||||
}
|
||||
ast::ImportSpecifier::Default(default) => {
|
||||
self.add_import(
|
||||
id!(default.local),
|
||||
Import {
|
||||
source: node.src.value.clone(),
|
||||
specifier: js_word!("default"),
|
||||
kind: ImportKind::Default,
|
||||
synthetic: false,
|
||||
asserts: node.asserts.clone(),
|
||||
},
|
||||
);
|
||||
}
|
||||
ast::ImportSpecifier::Namespace(namespace) => {
|
||||
self.add_import(
|
||||
id!(namespace.local),
|
||||
Import {
|
||||
source: node.src.value.clone(),
|
||||
specifier: "*".into(),
|
||||
kind: ImportKind::All,
|
||||
synthetic: false,
|
||||
asserts: node.asserts.clone(),
|
||||
},
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn visit_named_export(&mut self, node: &ast::NamedExport) {
|
||||
if node.src.is_some() {
|
||||
return;
|
||||
}
|
||||
fn visit_named_export(&mut self, node: &ast::NamedExport) {
|
||||
if node.src.is_some() {
|
||||
return;
|
||||
}
|
||||
|
||||
for specifier in &node.specifiers {
|
||||
match specifier {
|
||||
ast::ExportSpecifier::Named(named) => {
|
||||
let local = match &named.orig {
|
||||
ast::ModuleExportName::Ident(ident) => Some(id!(ident)),
|
||||
_ => None,
|
||||
};
|
||||
let exported = match &named.exported {
|
||||
Some(ast::ModuleExportName::Ident(exported)) => Some(exported.sym.clone()),
|
||||
_ => None,
|
||||
};
|
||||
if let Some(local) = local {
|
||||
self.add_export(local, exported);
|
||||
}
|
||||
}
|
||||
ast::ExportSpecifier::Default(default) => {
|
||||
self.exports
|
||||
.entry(id!(default.exported))
|
||||
.or_insert(Some(js_word!("default")));
|
||||
}
|
||||
ast::ExportSpecifier::Namespace(namespace) => {
|
||||
if let ast::ModuleExportName::Ident(ident) = &namespace.name {
|
||||
self.exports
|
||||
.entry(id!(ident))
|
||||
.or_insert_with(|| Some("*".into()));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
for specifier in &node.specifiers {
|
||||
match specifier {
|
||||
ast::ExportSpecifier::Named(named) => {
|
||||
let local = match &named.orig {
|
||||
ast::ModuleExportName::Ident(ident) => Some(id!(ident)),
|
||||
_ => None,
|
||||
};
|
||||
let exported = match &named.exported {
|
||||
Some(ast::ModuleExportName::Ident(exported)) => Some(exported.sym.clone()),
|
||||
_ => None,
|
||||
};
|
||||
if let Some(local) = local {
|
||||
self.add_export(local, exported);
|
||||
}
|
||||
}
|
||||
ast::ExportSpecifier::Default(default) => {
|
||||
self.exports
|
||||
.entry(id!(default.exported))
|
||||
.or_insert(Some(js_word!("default")));
|
||||
}
|
||||
ast::ExportSpecifier::Namespace(namespace) => {
|
||||
if let ast::ModuleExportName::Ident(ident) = &namespace.name {
|
||||
self.exports
|
||||
.entry(id!(ident))
|
||||
.or_insert_with(|| Some("*".into()));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn visit_export_decl(&mut self, node: &ast::ExportDecl) {
|
||||
match &node.decl {
|
||||
ast::Decl::TsEnum(enu) => {
|
||||
self.add_export(id!(enu.id), None);
|
||||
}
|
||||
ast::Decl::Class(class) => {
|
||||
self.add_export(id!(class.ident), None);
|
||||
}
|
||||
ast::Decl::Fn(func) => {
|
||||
self.add_export(id!(func.ident), None);
|
||||
}
|
||||
ast::Decl::Var(var) => {
|
||||
for decl in &var.decls {
|
||||
self.in_export_decl = true;
|
||||
decl.name.visit_with(self);
|
||||
self.in_export_decl = false;
|
||||
fn visit_export_decl(&mut self, node: &ast::ExportDecl) {
|
||||
match &node.decl {
|
||||
ast::Decl::TsEnum(enu) => {
|
||||
self.add_export(id!(enu.id), None);
|
||||
}
|
||||
ast::Decl::Class(class) => {
|
||||
self.add_export(id!(class.ident), None);
|
||||
}
|
||||
ast::Decl::Fn(func) => {
|
||||
self.add_export(id!(func.ident), None);
|
||||
}
|
||||
ast::Decl::Var(var) => {
|
||||
for decl in &var.decls {
|
||||
self.in_export_decl = true;
|
||||
decl.name.visit_with(self);
|
||||
self.in_export_decl = false;
|
||||
|
||||
decl.init.visit_with(self);
|
||||
}
|
||||
}
|
||||
_ => {}
|
||||
}
|
||||
}
|
||||
decl.init.visit_with(self);
|
||||
}
|
||||
}
|
||||
_ => {}
|
||||
}
|
||||
}
|
||||
|
||||
fn visit_export_default_decl(&mut self, node: &ast::ExportDefaultDecl) {
|
||||
match &node.decl {
|
||||
ast::DefaultDecl::Class(class) => {
|
||||
if let Some(ident) = &class.ident {
|
||||
self.add_export(id!(ident), Some(js_word!("default")));
|
||||
}
|
||||
}
|
||||
ast::DefaultDecl::Fn(func) => {
|
||||
if let Some(ident) = &func.ident {
|
||||
self.add_export(id!(ident), Some(js_word!("default")));
|
||||
}
|
||||
}
|
||||
_ => {
|
||||
unreachable!("unsupported export default declaration");
|
||||
}
|
||||
};
|
||||
}
|
||||
fn visit_export_default_decl(&mut self, node: &ast::ExportDefaultDecl) {
|
||||
match &node.decl {
|
||||
ast::DefaultDecl::Class(class) => {
|
||||
if let Some(ident) = &class.ident {
|
||||
self.add_export(id!(ident), Some(js_word!("default")));
|
||||
}
|
||||
}
|
||||
ast::DefaultDecl::Fn(func) => {
|
||||
if let Some(ident) = &func.ident {
|
||||
self.add_export(id!(ident), Some(js_word!("default")));
|
||||
}
|
||||
}
|
||||
_ => {
|
||||
unreachable!("unsupported export default declaration");
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
fn visit_binding_ident(&mut self, node: &ast::BindingIdent) {
|
||||
if self.in_export_decl {
|
||||
self.add_export(id!(node.id), None);
|
||||
}
|
||||
}
|
||||
fn visit_binding_ident(&mut self, node: &ast::BindingIdent) {
|
||||
if self.in_export_decl {
|
||||
self.add_export(id!(node.id), None);
|
||||
}
|
||||
}
|
||||
|
||||
fn visit_assign_pat_prop(&mut self, node: &ast::AssignPatProp) {
|
||||
if self.in_export_decl {
|
||||
self.add_export(id!(node.key), None);
|
||||
}
|
||||
}
|
||||
fn visit_assign_pat_prop(&mut self, node: &ast::AssignPatProp) {
|
||||
if self.in_export_decl {
|
||||
self.add_export(id!(node.key), None);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
enum ExprOrSkip {
|
||||
Expr,
|
||||
Skip,
|
||||
Expr,
|
||||
Skip,
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
pub struct IdentCollector {
|
||||
pub local_idents: HashSet<Id>,
|
||||
pub use_h: bool,
|
||||
pub use_fragment: bool,
|
||||
pub local_idents: HashSet<Id>,
|
||||
pub use_h: bool,
|
||||
pub use_fragment: bool,
|
||||
|
||||
expr_ctxt: Vec<ExprOrSkip>,
|
||||
expr_ctxt: Vec<ExprOrSkip>,
|
||||
}
|
||||
|
||||
impl IdentCollector {
|
||||
pub fn new() -> Self {
|
||||
Self {
|
||||
local_idents: HashSet::new(),
|
||||
expr_ctxt: Vec::with_capacity(32),
|
||||
use_h: false,
|
||||
use_fragment: false,
|
||||
}
|
||||
}
|
||||
pub fn new() -> Self {
|
||||
Self {
|
||||
local_idents: HashSet::new(),
|
||||
expr_ctxt: Vec::with_capacity(32),
|
||||
use_h: false,
|
||||
use_fragment: false,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn get_words(self) -> Vec<Id> {
|
||||
let mut local_idents: Vec<Id> = self.local_idents.into_iter().collect();
|
||||
local_idents.sort();
|
||||
local_idents
|
||||
}
|
||||
pub fn get_words(self) -> Vec<Id> {
|
||||
let mut local_idents: Vec<Id> = self.local_idents.into_iter().collect();
|
||||
local_idents.sort();
|
||||
local_idents
|
||||
}
|
||||
}
|
||||
|
||||
impl Visit for IdentCollector {
|
||||
noop_visit_type!();
|
||||
noop_visit_type!();
|
||||
|
||||
fn visit_expr(&mut self, node: &ast::Expr) {
|
||||
self.expr_ctxt.push(ExprOrSkip::Expr);
|
||||
visit_expr(self, node);
|
||||
self.expr_ctxt.pop();
|
||||
}
|
||||
fn visit_expr(&mut self, node: &ast::Expr) {
|
||||
self.expr_ctxt.push(ExprOrSkip::Expr);
|
||||
visit_expr(self, node);
|
||||
self.expr_ctxt.pop();
|
||||
}
|
||||
|
||||
fn visit_stmt(&mut self, node: &ast::Stmt) {
|
||||
self.expr_ctxt.push(ExprOrSkip::Skip);
|
||||
visit_stmt(self, node);
|
||||
self.expr_ctxt.pop();
|
||||
}
|
||||
fn visit_stmt(&mut self, node: &ast::Stmt) {
|
||||
self.expr_ctxt.push(ExprOrSkip::Skip);
|
||||
visit_stmt(self, node);
|
||||
self.expr_ctxt.pop();
|
||||
}
|
||||
|
||||
fn visit_jsx_element(&mut self, node: &ast::JSXElement) {
|
||||
self.use_h = true;
|
||||
node.visit_children_with(self);
|
||||
}
|
||||
fn visit_jsx_element(&mut self, node: &ast::JSXElement) {
|
||||
self.use_h = true;
|
||||
node.visit_children_with(self);
|
||||
}
|
||||
|
||||
fn visit_jsx_fragment(&mut self, node: &ast::JSXFragment) {
|
||||
self.use_h = true;
|
||||
self.use_fragment = true;
|
||||
node.visit_children_with(self);
|
||||
}
|
||||
fn visit_jsx_fragment(&mut self, node: &ast::JSXFragment) {
|
||||
self.use_h = true;
|
||||
self.use_fragment = true;
|
||||
node.visit_children_with(self);
|
||||
}
|
||||
|
||||
fn visit_jsx_element_name(&mut self, node: &ast::JSXElementName) {
|
||||
if let ast::JSXElementName::Ident(ref ident) = node {
|
||||
let ident_name = ident.sym.as_ref().chars().next();
|
||||
if let Some('A'..='Z') = ident_name {
|
||||
} else {
|
||||
return;
|
||||
}
|
||||
}
|
||||
fn visit_jsx_element_name(&mut self, node: &ast::JSXElementName) {
|
||||
if let ast::JSXElementName::Ident(ref ident) = node {
|
||||
let ident_name = ident.sym.as_ref().chars().next();
|
||||
if let Some('A'..='Z') = ident_name {
|
||||
} else {
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
node.visit_children_with(self);
|
||||
}
|
||||
fn visit_jsx_attr(&mut self, node: &ast::JSXAttr) {
|
||||
self.expr_ctxt.push(ExprOrSkip::Skip);
|
||||
node.visit_children_with(self);
|
||||
self.expr_ctxt.pop();
|
||||
}
|
||||
node.visit_children_with(self);
|
||||
}
|
||||
fn visit_jsx_attr(&mut self, node: &ast::JSXAttr) {
|
||||
self.expr_ctxt.push(ExprOrSkip::Skip);
|
||||
node.visit_children_with(self);
|
||||
self.expr_ctxt.pop();
|
||||
}
|
||||
|
||||
fn visit_ident(&mut self, node: &ast::Ident) {
|
||||
if matches!(self.expr_ctxt.last(), Some(ExprOrSkip::Expr))
|
||||
&& node.span.ctxt() != SyntaxContext::empty()
|
||||
{
|
||||
self.local_idents.insert(id!(node));
|
||||
}
|
||||
}
|
||||
fn visit_ident(&mut self, node: &ast::Ident) {
|
||||
if matches!(self.expr_ctxt.last(), Some(ExprOrSkip::Expr))
|
||||
&& node.span.ctxt() != SyntaxContext::empty()
|
||||
{
|
||||
self.local_idents.insert(id!(node));
|
||||
}
|
||||
}
|
||||
|
||||
fn visit_key_value_prop(&mut self, node: &ast::KeyValueProp) {
|
||||
self.expr_ctxt.push(ExprOrSkip::Skip);
|
||||
node.visit_children_with(self);
|
||||
self.expr_ctxt.pop();
|
||||
}
|
||||
fn visit_key_value_prop(&mut self, node: &ast::KeyValueProp) {
|
||||
self.expr_ctxt.push(ExprOrSkip::Skip);
|
||||
node.visit_children_with(self);
|
||||
self.expr_ctxt.pop();
|
||||
}
|
||||
}
|
||||
|
||||
pub fn collect_from_pat(pat: &ast::Pat, identifiers: &mut Vec<(Id, Span)>) -> bool {
|
||||
match pat {
|
||||
ast::Pat::Ident(ident) => {
|
||||
identifiers.push((id!(ident.id), ident.id.span));
|
||||
true
|
||||
}
|
||||
ast::Pat::Array(array) => {
|
||||
for el in array.elems.iter().flatten() {
|
||||
collect_from_pat(el, identifiers);
|
||||
}
|
||||
false
|
||||
}
|
||||
ast::Pat::Rest(rest) => {
|
||||
if let ast::Pat::Ident(ident) = rest.arg.as_ref() {
|
||||
identifiers.push((id!(ident.id), ident.id.span));
|
||||
}
|
||||
false
|
||||
}
|
||||
ast::Pat::Assign(expr) => {
|
||||
if let ast::Pat::Ident(ident) = expr.left.as_ref() {
|
||||
identifiers.push((id!(ident.id), ident.id.span));
|
||||
}
|
||||
false
|
||||
}
|
||||
ast::Pat::Object(obj) => {
|
||||
for prop in &obj.props {
|
||||
match prop {
|
||||
ast::ObjectPatProp::Assign(ref v) => {
|
||||
identifiers.push((id!(v.key), v.key.span));
|
||||
}
|
||||
ast::ObjectPatProp::KeyValue(ref v) => {
|
||||
collect_from_pat(&v.value, identifiers);
|
||||
}
|
||||
ast::ObjectPatProp::Rest(ref v) => {
|
||||
if let ast::Pat::Ident(ident) = v.arg.as_ref() {
|
||||
identifiers.push((id!(ident.id), ident.id.span));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
false
|
||||
}
|
||||
_ => false,
|
||||
}
|
||||
match pat {
|
||||
ast::Pat::Ident(ident) => {
|
||||
identifiers.push((id!(ident.id), ident.id.span));
|
||||
true
|
||||
}
|
||||
ast::Pat::Array(array) => {
|
||||
for el in array.elems.iter().flatten() {
|
||||
collect_from_pat(el, identifiers);
|
||||
}
|
||||
false
|
||||
}
|
||||
ast::Pat::Rest(rest) => {
|
||||
if let ast::Pat::Ident(ident) = rest.arg.as_ref() {
|
||||
identifiers.push((id!(ident.id), ident.id.span));
|
||||
}
|
||||
false
|
||||
}
|
||||
ast::Pat::Assign(expr) => {
|
||||
if let ast::Pat::Ident(ident) = expr.left.as_ref() {
|
||||
identifiers.push((id!(ident.id), ident.id.span));
|
||||
}
|
||||
false
|
||||
}
|
||||
ast::Pat::Object(obj) => {
|
||||
for prop in &obj.props {
|
||||
match prop {
|
||||
ast::ObjectPatProp::Assign(ref v) => {
|
||||
identifiers.push((id!(v.key), v.key.span));
|
||||
}
|
||||
ast::ObjectPatProp::KeyValue(ref v) => {
|
||||
collect_from_pat(&v.value, identifiers);
|
||||
}
|
||||
ast::ObjectPatProp::Rest(ref v) => {
|
||||
if let ast::Pat::Ident(ident) = v.arg.as_ref() {
|
||||
identifiers.push((id!(ident.id), ident.id.span));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
false
|
||||
}
|
||||
_ => false,
|
||||
}
|
||||
}
|
||||
|
||||
@@ -4,80 +4,80 @@ use swc_common::DUMMY_SP;
|
||||
use swc_ecmascript::ast;
|
||||
use swc_ecmascript::visit::{VisitMut, VisitMutWith};
|
||||
pub struct ConstReplacerVisitor {
|
||||
pub is_server: bool,
|
||||
pub is_dev: bool,
|
||||
pub is_server_ident: Option<Id>,
|
||||
pub is_browser_ident: Option<Id>,
|
||||
pub is_dev_ident: Option<Id>,
|
||||
pub is_server: bool,
|
||||
pub is_dev: bool,
|
||||
pub is_server_ident: Option<Id>,
|
||||
pub is_browser_ident: Option<Id>,
|
||||
pub is_dev_ident: Option<Id>,
|
||||
}
|
||||
|
||||
impl ConstReplacerVisitor {
|
||||
pub fn new(is_server: bool, is_dev: bool, global_collector: &GlobalCollect) -> Self {
|
||||
Self {
|
||||
is_server,
|
||||
is_dev,
|
||||
is_server_ident: global_collector
|
||||
.get_imported_local(&IS_SERVER, &BUILDER_IO_QWIK_BUILD),
|
||||
is_browser_ident: global_collector
|
||||
.get_imported_local(&IS_BROWSER, &BUILDER_IO_QWIK_BUILD),
|
||||
is_dev_ident: global_collector.get_imported_local(&IS_DEV, &BUILDER_IO_QWIK_BUILD),
|
||||
}
|
||||
}
|
||||
pub fn new(is_server: bool, is_dev: bool, global_collector: &GlobalCollect) -> Self {
|
||||
Self {
|
||||
is_server,
|
||||
is_dev,
|
||||
is_server_ident: global_collector
|
||||
.get_imported_local(&IS_SERVER, &BUILDER_IO_QWIK_BUILD),
|
||||
is_browser_ident: global_collector
|
||||
.get_imported_local(&IS_BROWSER, &BUILDER_IO_QWIK_BUILD),
|
||||
is_dev_ident: global_collector.get_imported_local(&IS_DEV, &BUILDER_IO_QWIK_BUILD),
|
||||
}
|
||||
}
|
||||
}
|
||||
macro_rules! id_eq {
|
||||
($ident: expr, $cid: expr) => {
|
||||
if let Some(cid) = $cid {
|
||||
cid.0 == $ident.sym && cid.1 == $ident.span.ctxt()
|
||||
} else {
|
||||
false
|
||||
}
|
||||
};
|
||||
($ident: expr, $cid: expr) => {
|
||||
if let Some(cid) = $cid {
|
||||
cid.0 == $ident.sym && cid.1 == $ident.span.ctxt()
|
||||
} else {
|
||||
false
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
enum ConstVariable {
|
||||
IsServer,
|
||||
IsBrowser,
|
||||
IsDev,
|
||||
None,
|
||||
IsServer,
|
||||
IsBrowser,
|
||||
IsDev,
|
||||
None,
|
||||
}
|
||||
impl VisitMut for ConstReplacerVisitor {
|
||||
fn visit_mut_expr(&mut self, node: &mut ast::Expr) {
|
||||
let mode = match node {
|
||||
ast::Expr::Ident(ref ident) => {
|
||||
if id_eq!(ident, &self.is_server_ident) {
|
||||
ConstVariable::IsServer
|
||||
} else if id_eq!(ident, &self.is_browser_ident) {
|
||||
ConstVariable::IsBrowser
|
||||
} else if id_eq!(ident, &self.is_dev_ident) {
|
||||
ConstVariable::IsDev
|
||||
} else {
|
||||
ConstVariable::None
|
||||
}
|
||||
}
|
||||
_ => ConstVariable::None,
|
||||
};
|
||||
match mode {
|
||||
ConstVariable::IsServer => {
|
||||
*node = ast::Expr::Lit(ast::Lit::Bool(ast::Bool {
|
||||
span: DUMMY_SP,
|
||||
value: self.is_server,
|
||||
}))
|
||||
}
|
||||
ConstVariable::IsBrowser => {
|
||||
*node = ast::Expr::Lit(ast::Lit::Bool(ast::Bool {
|
||||
span: DUMMY_SP,
|
||||
value: !self.is_server,
|
||||
}))
|
||||
}
|
||||
ConstVariable::IsDev => {
|
||||
*node = ast::Expr::Lit(ast::Lit::Bool(ast::Bool {
|
||||
span: DUMMY_SP,
|
||||
value: self.is_dev,
|
||||
}))
|
||||
}
|
||||
ConstVariable::None => {
|
||||
node.visit_mut_children_with(self);
|
||||
}
|
||||
}
|
||||
}
|
||||
fn visit_mut_expr(&mut self, node: &mut ast::Expr) {
|
||||
let mode = match node {
|
||||
ast::Expr::Ident(ref ident) => {
|
||||
if id_eq!(ident, &self.is_server_ident) {
|
||||
ConstVariable::IsServer
|
||||
} else if id_eq!(ident, &self.is_browser_ident) {
|
||||
ConstVariable::IsBrowser
|
||||
} else if id_eq!(ident, &self.is_dev_ident) {
|
||||
ConstVariable::IsDev
|
||||
} else {
|
||||
ConstVariable::None
|
||||
}
|
||||
}
|
||||
_ => ConstVariable::None,
|
||||
};
|
||||
match mode {
|
||||
ConstVariable::IsServer => {
|
||||
*node = ast::Expr::Lit(ast::Lit::Bool(ast::Bool {
|
||||
span: DUMMY_SP,
|
||||
value: self.is_server,
|
||||
}))
|
||||
}
|
||||
ConstVariable::IsBrowser => {
|
||||
*node = ast::Expr::Lit(ast::Lit::Bool(ast::Bool {
|
||||
span: DUMMY_SP,
|
||||
value: !self.is_server,
|
||||
}))
|
||||
}
|
||||
ConstVariable::IsDev => {
|
||||
*node = ast::Expr::Lit(ast::Lit::Bool(ast::Bool {
|
||||
span: DUMMY_SP,
|
||||
value: self.is_dev,
|
||||
}))
|
||||
}
|
||||
ConstVariable::None => {
|
||||
node.visit_mut_children_with(self);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -8,185 +8,185 @@ use swc_atoms::JsWord;
|
||||
use lazy_static::lazy_static;
|
||||
|
||||
lazy_static! {
|
||||
static ref ENTRY_HOOKS: JsWord = JsWord::from("entry_hooks");
|
||||
static ref ENTRY_SERVER: JsWord = JsWord::from("entry_server");
|
||||
static ref ENTRY_HOOKS: JsWord = JsWord::from("entry_hooks");
|
||||
static ref ENTRY_SERVER: JsWord = JsWord::from("entry_server");
|
||||
}
|
||||
|
||||
// EntryStrategies
|
||||
#[derive(Debug, Serialize, Copy, Clone, Deserialize)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
pub enum EntryStrategy {
|
||||
Inline,
|
||||
Hoist,
|
||||
Single,
|
||||
Hook,
|
||||
Component,
|
||||
Smart,
|
||||
Inline,
|
||||
Hoist,
|
||||
Single,
|
||||
Hook,
|
||||
Component,
|
||||
Smart,
|
||||
}
|
||||
|
||||
pub trait EntryPolicy: Send + Sync {
|
||||
fn get_entry_for_sym(
|
||||
&self,
|
||||
hash: &str,
|
||||
location: &PathData,
|
||||
context: &[String],
|
||||
hook_data: &HookData,
|
||||
) -> Option<JsWord>;
|
||||
fn get_entry_for_sym(
|
||||
&self,
|
||||
hash: &str,
|
||||
location: &PathData,
|
||||
context: &[String],
|
||||
hook_data: &HookData,
|
||||
) -> Option<JsWord>;
|
||||
}
|
||||
|
||||
#[derive(Default, Clone)]
|
||||
pub struct InlineStrategy;
|
||||
|
||||
impl EntryPolicy for InlineStrategy {
|
||||
fn get_entry_for_sym(
|
||||
&self,
|
||||
_hash: &str,
|
||||
_path: &PathData,
|
||||
_context: &[String],
|
||||
_hook_data: &HookData,
|
||||
) -> Option<JsWord> {
|
||||
Some(ENTRY_HOOKS.clone())
|
||||
}
|
||||
fn get_entry_for_sym(
|
||||
&self,
|
||||
_hash: &str,
|
||||
_path: &PathData,
|
||||
_context: &[String],
|
||||
_hook_data: &HookData,
|
||||
) -> Option<JsWord> {
|
||||
Some(ENTRY_HOOKS.clone())
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Clone)]
|
||||
pub struct SingleStrategy {
|
||||
map: Option<HashMap<String, JsWord>>,
|
||||
map: Option<HashMap<String, JsWord>>,
|
||||
}
|
||||
|
||||
impl SingleStrategy {
|
||||
pub const fn new(map: Option<HashMap<String, JsWord>>) -> Self {
|
||||
Self { map }
|
||||
}
|
||||
pub const fn new(map: Option<HashMap<String, JsWord>>) -> Self {
|
||||
Self { map }
|
||||
}
|
||||
}
|
||||
|
||||
impl EntryPolicy for SingleStrategy {
|
||||
fn get_entry_for_sym(
|
||||
&self,
|
||||
hash: &str,
|
||||
_path: &PathData,
|
||||
_context: &[String],
|
||||
_hook_data: &HookData,
|
||||
) -> Option<JsWord> {
|
||||
if let Some(map) = &self.map {
|
||||
let entry = map.get(hash);
|
||||
if let Some(entry) = entry {
|
||||
return Some(entry.clone());
|
||||
}
|
||||
}
|
||||
Some(ENTRY_HOOKS.clone())
|
||||
}
|
||||
fn get_entry_for_sym(
|
||||
&self,
|
||||
hash: &str,
|
||||
_path: &PathData,
|
||||
_context: &[String],
|
||||
_hook_data: &HookData,
|
||||
) -> Option<JsWord> {
|
||||
if let Some(map) = &self.map {
|
||||
let entry = map.get(hash);
|
||||
if let Some(entry) = entry {
|
||||
return Some(entry.clone());
|
||||
}
|
||||
}
|
||||
Some(ENTRY_HOOKS.clone())
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Clone)]
|
||||
pub struct PerHookStrategy {
|
||||
map: Option<HashMap<String, JsWord>>,
|
||||
map: Option<HashMap<String, JsWord>>,
|
||||
}
|
||||
|
||||
impl PerHookStrategy {
|
||||
pub const fn new(map: Option<HashMap<String, JsWord>>) -> Self {
|
||||
Self { map }
|
||||
}
|
||||
pub const fn new(map: Option<HashMap<String, JsWord>>) -> Self {
|
||||
Self { map }
|
||||
}
|
||||
}
|
||||
|
||||
impl EntryPolicy for PerHookStrategy {
|
||||
fn get_entry_for_sym(
|
||||
&self,
|
||||
hash: &str,
|
||||
_path: &PathData,
|
||||
_context: &[String],
|
||||
_hook_data: &HookData,
|
||||
) -> Option<JsWord> {
|
||||
if let Some(map) = &self.map {
|
||||
let entry = map.get(hash);
|
||||
if let Some(entry) = entry {
|
||||
return Some(entry.clone());
|
||||
}
|
||||
}
|
||||
None
|
||||
}
|
||||
fn get_entry_for_sym(
|
||||
&self,
|
||||
hash: &str,
|
||||
_path: &PathData,
|
||||
_context: &[String],
|
||||
_hook_data: &HookData,
|
||||
) -> Option<JsWord> {
|
||||
if let Some(map) = &self.map {
|
||||
let entry = map.get(hash);
|
||||
if let Some(entry) = entry {
|
||||
return Some(entry.clone());
|
||||
}
|
||||
}
|
||||
None
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Clone)]
|
||||
pub struct PerComponentStrategy {
|
||||
map: Option<HashMap<String, JsWord>>,
|
||||
map: Option<HashMap<String, JsWord>>,
|
||||
}
|
||||
|
||||
impl PerComponentStrategy {
|
||||
pub const fn new(map: Option<HashMap<String, JsWord>>) -> Self {
|
||||
Self { map }
|
||||
}
|
||||
pub const fn new(map: Option<HashMap<String, JsWord>>) -> Self {
|
||||
Self { map }
|
||||
}
|
||||
}
|
||||
|
||||
impl EntryPolicy for PerComponentStrategy {
|
||||
fn get_entry_for_sym(
|
||||
&self,
|
||||
hash: &str,
|
||||
_path: &PathData,
|
||||
context: &[String],
|
||||
_hook_data: &HookData,
|
||||
) -> Option<JsWord> {
|
||||
if let Some(map) = &self.map {
|
||||
let entry = map.get(hash);
|
||||
if let Some(entry) = entry {
|
||||
return Some(entry.clone());
|
||||
}
|
||||
}
|
||||
context.first().map_or_else(
|
||||
|| Some(ENTRY_HOOKS.clone()),
|
||||
|root| Some(JsWord::from(["entry_", root].concat())),
|
||||
)
|
||||
}
|
||||
fn get_entry_for_sym(
|
||||
&self,
|
||||
hash: &str,
|
||||
_path: &PathData,
|
||||
context: &[String],
|
||||
_hook_data: &HookData,
|
||||
) -> Option<JsWord> {
|
||||
if let Some(map) = &self.map {
|
||||
let entry = map.get(hash);
|
||||
if let Some(entry) = entry {
|
||||
return Some(entry.clone());
|
||||
}
|
||||
}
|
||||
context.first().map_or_else(
|
||||
|| Some(ENTRY_HOOKS.clone()),
|
||||
|root| Some(JsWord::from(["entry_", root].concat())),
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Clone)]
|
||||
pub struct SmartStrategy {
|
||||
map: Option<HashMap<String, JsWord>>,
|
||||
map: Option<HashMap<String, JsWord>>,
|
||||
}
|
||||
|
||||
impl SmartStrategy {
|
||||
pub const fn new(map: Option<HashMap<String, JsWord>>) -> Self {
|
||||
Self { map }
|
||||
}
|
||||
pub const fn new(map: Option<HashMap<String, JsWord>>) -> Self {
|
||||
Self { map }
|
||||
}
|
||||
}
|
||||
impl EntryPolicy for SmartStrategy {
|
||||
fn get_entry_for_sym(
|
||||
&self,
|
||||
hash: &str,
|
||||
_path: &PathData,
|
||||
context: &[String],
|
||||
hook_data: &HookData,
|
||||
) -> Option<JsWord> {
|
||||
if hook_data.scoped_idents.is_empty()
|
||||
&& (hook_data.ctx_kind != HookKind::Function || &hook_data.ctx_name == "event$")
|
||||
{
|
||||
return None;
|
||||
}
|
||||
if hook_data.ctx_name == *USE_SERVER_MOUNT {
|
||||
return Some(ENTRY_SERVER.clone());
|
||||
}
|
||||
if let Some(map) = &self.map {
|
||||
let entry = map.get(hash);
|
||||
if let Some(entry) = entry {
|
||||
return Some(entry.clone());
|
||||
}
|
||||
}
|
||||
Some(context.first().map_or_else(
|
||||
|| ENTRY_HOOKS.clone(),
|
||||
|root| JsWord::from(["entry_", root].concat()),
|
||||
))
|
||||
}
|
||||
fn get_entry_for_sym(
|
||||
&self,
|
||||
hash: &str,
|
||||
_path: &PathData,
|
||||
context: &[String],
|
||||
hook_data: &HookData,
|
||||
) -> Option<JsWord> {
|
||||
if hook_data.scoped_idents.is_empty()
|
||||
&& (hook_data.ctx_kind != HookKind::Function || &hook_data.ctx_name == "event$")
|
||||
{
|
||||
return None;
|
||||
}
|
||||
if hook_data.ctx_name == *USE_SERVER_MOUNT {
|
||||
return Some(ENTRY_SERVER.clone());
|
||||
}
|
||||
if let Some(map) = &self.map {
|
||||
let entry = map.get(hash);
|
||||
if let Some(entry) = entry {
|
||||
return Some(entry.clone());
|
||||
}
|
||||
}
|
||||
Some(context.first().map_or_else(
|
||||
|| ENTRY_HOOKS.clone(),
|
||||
|root| JsWord::from(["entry_", root].concat()),
|
||||
))
|
||||
}
|
||||
}
|
||||
|
||||
pub fn parse_entry_strategy(
|
||||
strategy: &EntryStrategy,
|
||||
manual_chunks: Option<HashMap<String, JsWord>>,
|
||||
strategy: &EntryStrategy,
|
||||
manual_chunks: Option<HashMap<String, JsWord>>,
|
||||
) -> Box<dyn EntryPolicy> {
|
||||
match strategy {
|
||||
EntryStrategy::Inline | EntryStrategy::Hoist => Box::<InlineStrategy>::default(),
|
||||
EntryStrategy::Hook => Box::new(PerHookStrategy::new(manual_chunks)),
|
||||
EntryStrategy::Single => Box::new(SingleStrategy::new(manual_chunks)),
|
||||
EntryStrategy::Component => Box::new(PerComponentStrategy::new(manual_chunks)),
|
||||
EntryStrategy::Smart => Box::new(SmartStrategy::new(manual_chunks)),
|
||||
}
|
||||
match strategy {
|
||||
EntryStrategy::Inline | EntryStrategy::Hoist => Box::<InlineStrategy>::default(),
|
||||
EntryStrategy::Hook => Box::new(PerHookStrategy::new(manual_chunks)),
|
||||
EntryStrategy::Single => Box::new(SingleStrategy::new(manual_chunks)),
|
||||
EntryStrategy::Component => Box::new(PerComponentStrategy::new(manual_chunks)),
|
||||
EntryStrategy::Smart => Box::new(SmartStrategy::new(manual_chunks)),
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,13 +1,13 @@
|
||||
use swc_common::errors::DiagnosticId;
|
||||
|
||||
pub enum Error {
|
||||
FunctionReference = 2,
|
||||
CanNotCapture,
|
||||
DynamicImportInsideQhook,
|
||||
MissingQrlImplementation,
|
||||
FunctionReference = 2,
|
||||
CanNotCapture,
|
||||
DynamicImportInsideQhook,
|
||||
MissingQrlImplementation,
|
||||
}
|
||||
|
||||
pub fn get_diagnostic_id(err: Error) -> DiagnosticId {
|
||||
let id = err as u32;
|
||||
DiagnosticId::Error(format!("C{:02}", id))
|
||||
let id = err as u32;
|
||||
DiagnosticId::Error(format!("C{:02}", id))
|
||||
}
|
||||
|
||||
@@ -4,47 +4,47 @@ use swc_ecmascript::ast;
|
||||
use swc_ecmascript::visit::VisitMut;
|
||||
|
||||
pub struct StripExportsVisitor<'a> {
|
||||
pub filter_symbols: &'a [JsWord],
|
||||
pub filter_symbols: &'a [JsWord],
|
||||
}
|
||||
|
||||
impl<'a> StripExportsVisitor<'a> {
|
||||
pub const fn new(filter_symbols: &'a [JsWord]) -> Self {
|
||||
Self { filter_symbols }
|
||||
}
|
||||
pub const fn new(filter_symbols: &'a [JsWord]) -> Self {
|
||||
Self { filter_symbols }
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a> VisitMut for StripExportsVisitor<'a> {
|
||||
fn visit_mut_module(&mut self, node: &mut ast::Module) {
|
||||
for item in &mut node.body {
|
||||
if let ast::ModuleItem::ModuleDecl(ast::ModuleDecl::ExportDecl(decl)) = item {
|
||||
match &decl.decl {
|
||||
ast::Decl::Var(var) => {
|
||||
if var.decls.len() == 1 {
|
||||
if let Some(ast::VarDeclarator {
|
||||
name: ast::Pat::Ident(ident),
|
||||
..
|
||||
}) = var.decls.first()
|
||||
{
|
||||
if self.filter_symbols.contains(&ident.id.sym) {
|
||||
*item = empty_module_item(ident.id.clone());
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
ast::Decl::Fn(fn_decl) => {
|
||||
if self.filter_symbols.contains(&fn_decl.ident.sym) {
|
||||
*item = empty_module_item(fn_decl.ident.clone());
|
||||
}
|
||||
}
|
||||
_ => {}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
fn visit_mut_module(&mut self, node: &mut ast::Module) {
|
||||
for item in &mut node.body {
|
||||
if let ast::ModuleItem::ModuleDecl(ast::ModuleDecl::ExportDecl(decl)) = item {
|
||||
match &decl.decl {
|
||||
ast::Decl::Var(var) => {
|
||||
if var.decls.len() == 1 {
|
||||
if let Some(ast::VarDeclarator {
|
||||
name: ast::Pat::Ident(ident),
|
||||
..
|
||||
}) = var.decls.first()
|
||||
{
|
||||
if self.filter_symbols.contains(&ident.id.sym) {
|
||||
*item = empty_module_item(ident.id.clone());
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
ast::Decl::Fn(fn_decl) => {
|
||||
if self.filter_symbols.contains(&fn_decl.ident.sym) {
|
||||
*item = empty_module_item(fn_decl.ident.clone());
|
||||
}
|
||||
}
|
||||
_ => {}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn empty_module_item(ident: ast::Ident) -> ast::ModuleItem {
|
||||
ast::ModuleItem::ModuleDecl(ast::ModuleDecl::ExportDecl(ast::ExportDecl {
|
||||
ast::ModuleItem::ModuleDecl(ast::ModuleDecl::ExportDecl(ast::ExportDecl {
|
||||
span: DUMMY_SP,
|
||||
decl: ast::Decl::Var(Box::new(ast::VarDecl {
|
||||
span: DUMMY_SP,
|
||||
|
||||
@@ -5,139 +5,139 @@ use swc_ecmascript::ast;
|
||||
use swc_ecmascript::visit::{noop_visit_type, Visit, VisitWith};
|
||||
|
||||
macro_rules! id {
|
||||
($ident: expr) => {
|
||||
($ident.sym.clone(), $ident.span.ctxt())
|
||||
};
|
||||
($ident: expr) => {
|
||||
($ident.sym.clone(), $ident.span.ctxt())
|
||||
};
|
||||
}
|
||||
|
||||
pub fn is_conditional_jsx(
|
||||
expr: &ast::BlockStmtOrExpr,
|
||||
jsx_functions: &HashSet<Id>,
|
||||
immutable_function_cmp: &HashSet<Id>,
|
||||
expr: &ast::BlockStmtOrExpr,
|
||||
jsx_functions: &HashSet<Id>,
|
||||
immutable_function_cmp: &HashSet<Id>,
|
||||
) -> bool {
|
||||
let mut collector = HasBranches::new(jsx_functions, immutable_function_cmp);
|
||||
expr.visit_with(&mut collector);
|
||||
collector.conditional
|
||||
let mut collector = HasBranches::new(jsx_functions, immutable_function_cmp);
|
||||
expr.visit_with(&mut collector);
|
||||
collector.conditional
|
||||
}
|
||||
|
||||
pub fn is_conditional_jsx_block(
|
||||
expr: &ast::BlockStmt,
|
||||
jsx_functions: &HashSet<Id>,
|
||||
immutable_function_cmp: &HashSet<Id>,
|
||||
expr: &ast::BlockStmt,
|
||||
jsx_functions: &HashSet<Id>,
|
||||
immutable_function_cmp: &HashSet<Id>,
|
||||
) -> bool {
|
||||
let mut collector = HasBranches::new(jsx_functions, immutable_function_cmp);
|
||||
expr.visit_with(&mut collector);
|
||||
collector.conditional
|
||||
let mut collector = HasBranches::new(jsx_functions, immutable_function_cmp);
|
||||
expr.visit_with(&mut collector);
|
||||
collector.conditional
|
||||
}
|
||||
|
||||
pub struct HasBranches<'a> {
|
||||
under_conditional: i32,
|
||||
jsx_functions: &'a HashSet<Id>,
|
||||
immutable_function_cmp: &'a HashSet<Id>,
|
||||
conditional: bool,
|
||||
found_return: bool,
|
||||
under_conditional: i32,
|
||||
jsx_functions: &'a HashSet<Id>,
|
||||
immutable_function_cmp: &'a HashSet<Id>,
|
||||
conditional: bool,
|
||||
found_return: bool,
|
||||
}
|
||||
|
||||
impl<'a> HasBranches<'a> {
|
||||
const fn new(jsx_functions: &'a HashSet<Id>, immutable_function_cmp: &'a HashSet<Id>) -> Self {
|
||||
Self {
|
||||
jsx_functions,
|
||||
immutable_function_cmp,
|
||||
under_conditional: 0,
|
||||
conditional: false,
|
||||
found_return: false,
|
||||
}
|
||||
}
|
||||
const fn new(jsx_functions: &'a HashSet<Id>, immutable_function_cmp: &'a HashSet<Id>) -> Self {
|
||||
Self {
|
||||
jsx_functions,
|
||||
immutable_function_cmp,
|
||||
under_conditional: 0,
|
||||
conditional: false,
|
||||
found_return: false,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a> Visit for HasBranches<'a> {
|
||||
noop_visit_type!();
|
||||
noop_visit_type!();
|
||||
|
||||
fn visit_arrow_expr(&mut self, _: &ast::ArrowExpr) {}
|
||||
fn visit_fn_expr(&mut self, _: &ast::FnExpr) {}
|
||||
fn visit_fn_decl(&mut self, _: &ast::FnDecl) {}
|
||||
fn visit_arrow_expr(&mut self, _: &ast::ArrowExpr) {}
|
||||
fn visit_fn_expr(&mut self, _: &ast::FnExpr) {}
|
||||
fn visit_fn_decl(&mut self, _: &ast::FnDecl) {}
|
||||
|
||||
fn visit_return_stmt(&mut self, node: &ast::ReturnStmt) {
|
||||
node.visit_children_with(self);
|
||||
self.found_return = true;
|
||||
}
|
||||
fn visit_return_stmt(&mut self, node: &ast::ReturnStmt) {
|
||||
node.visit_children_with(self);
|
||||
self.found_return = true;
|
||||
}
|
||||
|
||||
fn visit_for_in_stmt(&mut self, node: &ast::ForInStmt) {
|
||||
self.under_conditional += 1;
|
||||
node.visit_children_with(self);
|
||||
self.under_conditional -= 1;
|
||||
}
|
||||
fn visit_for_in_stmt(&mut self, node: &ast::ForInStmt) {
|
||||
self.under_conditional += 1;
|
||||
node.visit_children_with(self);
|
||||
self.under_conditional -= 1;
|
||||
}
|
||||
|
||||
fn visit_for_of_stmt(&mut self, node: &ast::ForOfStmt) {
|
||||
self.under_conditional += 1;
|
||||
node.visit_children_with(self);
|
||||
self.under_conditional -= 1;
|
||||
}
|
||||
fn visit_for_of_stmt(&mut self, node: &ast::ForOfStmt) {
|
||||
self.under_conditional += 1;
|
||||
node.visit_children_with(self);
|
||||
self.under_conditional -= 1;
|
||||
}
|
||||
|
||||
fn visit_for_stmt(&mut self, node: &ast::ForStmt) {
|
||||
self.under_conditional += 1;
|
||||
node.visit_children_with(self);
|
||||
self.under_conditional -= 1;
|
||||
}
|
||||
fn visit_for_stmt(&mut self, node: &ast::ForStmt) {
|
||||
self.under_conditional += 1;
|
||||
node.visit_children_with(self);
|
||||
self.under_conditional -= 1;
|
||||
}
|
||||
|
||||
fn visit_if_stmt(&mut self, node: &ast::IfStmt) {
|
||||
self.under_conditional += 1;
|
||||
node.visit_children_with(self);
|
||||
self.under_conditional -= 1;
|
||||
}
|
||||
fn visit_if_stmt(&mut self, node: &ast::IfStmt) {
|
||||
self.under_conditional += 1;
|
||||
node.visit_children_with(self);
|
||||
self.under_conditional -= 1;
|
||||
}
|
||||
|
||||
fn visit_while_stmt(&mut self, node: &ast::WhileStmt) {
|
||||
self.under_conditional += 1;
|
||||
node.visit_children_with(self);
|
||||
self.under_conditional -= 1;
|
||||
}
|
||||
fn visit_while_stmt(&mut self, node: &ast::WhileStmt) {
|
||||
self.under_conditional += 1;
|
||||
node.visit_children_with(self);
|
||||
self.under_conditional -= 1;
|
||||
}
|
||||
|
||||
fn visit_do_while_stmt(&mut self, node: &ast::DoWhileStmt) {
|
||||
self.under_conditional += 1;
|
||||
node.visit_children_with(self);
|
||||
self.under_conditional -= 1;
|
||||
}
|
||||
fn visit_do_while_stmt(&mut self, node: &ast::DoWhileStmt) {
|
||||
self.under_conditional += 1;
|
||||
node.visit_children_with(self);
|
||||
self.under_conditional -= 1;
|
||||
}
|
||||
|
||||
fn visit_switch_stmt(&mut self, node: &ast::SwitchStmt) {
|
||||
self.under_conditional += 1;
|
||||
node.visit_children_with(self);
|
||||
self.under_conditional -= 1;
|
||||
}
|
||||
fn visit_switch_stmt(&mut self, node: &ast::SwitchStmt) {
|
||||
self.under_conditional += 1;
|
||||
node.visit_children_with(self);
|
||||
self.under_conditional -= 1;
|
||||
}
|
||||
|
||||
fn visit_cond_expr(&mut self, node: &ast::CondExpr) {
|
||||
self.under_conditional += 1;
|
||||
node.visit_children_with(self);
|
||||
self.under_conditional -= 1;
|
||||
}
|
||||
fn visit_cond_expr(&mut self, node: &ast::CondExpr) {
|
||||
self.under_conditional += 1;
|
||||
node.visit_children_with(self);
|
||||
self.under_conditional -= 1;
|
||||
}
|
||||
|
||||
fn visit_bin_expr(&mut self, node: &ast::BinExpr) {
|
||||
if matches!(
|
||||
node.op,
|
||||
ast::BinaryOp::LogicalAnd | ast::BinaryOp::LogicalOr | ast::BinaryOp::NullishCoalescing
|
||||
) {
|
||||
self.under_conditional += 1;
|
||||
node.visit_children_with(self);
|
||||
self.under_conditional -= 1;
|
||||
} else {
|
||||
node.visit_children_with(self);
|
||||
}
|
||||
}
|
||||
fn visit_bin_expr(&mut self, node: &ast::BinExpr) {
|
||||
if matches!(
|
||||
node.op,
|
||||
ast::BinaryOp::LogicalAnd | ast::BinaryOp::LogicalOr | ast::BinaryOp::NullishCoalescing
|
||||
) {
|
||||
self.under_conditional += 1;
|
||||
node.visit_children_with(self);
|
||||
self.under_conditional -= 1;
|
||||
} else {
|
||||
node.visit_children_with(self);
|
||||
}
|
||||
}
|
||||
|
||||
fn visit_call_expr(&mut self, node: &ast::CallExpr) {
|
||||
if self.under_conditional > 0 || self.found_return {
|
||||
if let ast::Callee::Expr(box ast::Expr::Ident(ident)) = &node.callee {
|
||||
if self.jsx_functions.contains(&id!(ident)) {
|
||||
let first_arg = node.args.first();
|
||||
if let Some(name) = first_arg {
|
||||
if let ast::Expr::Ident(jsx_id) = &*name.expr {
|
||||
if !self.immutable_function_cmp.contains(&id!(jsx_id)) {
|
||||
self.conditional = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
node.visit_children_with(self);
|
||||
}
|
||||
fn visit_call_expr(&mut self, node: &ast::CallExpr) {
|
||||
if self.under_conditional > 0 || self.found_return {
|
||||
if let ast::Callee::Expr(box ast::Expr::Ident(ident)) = &node.callee {
|
||||
if self.jsx_functions.contains(&id!(ident)) {
|
||||
let first_arg = node.args.first();
|
||||
if let Some(name) = first_arg {
|
||||
if let ast::Expr::Ident(jsx_id) = &*name.expr {
|
||||
if !self.immutable_function_cmp.contains(&id!(jsx_id)) {
|
||||
self.conditional = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
node.visit_children_with(self);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -9,202 +9,202 @@ use swc_ecmascript::codegen::text_writer::JsWriter;
|
||||
use swc_ecmascript::transforms::fixer;
|
||||
use swc_ecmascript::transforms::hygiene::hygiene_with_config;
|
||||
use swc_ecmascript::{
|
||||
utils::private_ident,
|
||||
visit::{VisitMut, VisitMutWith},
|
||||
utils::private_ident,
|
||||
visit::{VisitMut, VisitMutWith},
|
||||
};
|
||||
|
||||
macro_rules! id {
|
||||
($ident: expr) => {
|
||||
($ident.sym.clone(), $ident.span.ctxt())
|
||||
};
|
||||
($ident: expr) => {
|
||||
($ident.sym.clone(), $ident.span.ctxt())
|
||||
};
|
||||
}
|
||||
|
||||
pub fn convert_inlined_fn(
|
||||
mut expr: ast::Expr,
|
||||
scoped_idents: Vec<Id>,
|
||||
qqhook: &Id,
|
||||
accept_call_expr: bool,
|
||||
serialize_fn: bool,
|
||||
mut expr: ast::Expr,
|
||||
scoped_idents: Vec<Id>,
|
||||
qqhook: &Id,
|
||||
accept_call_expr: bool,
|
||||
serialize_fn: bool,
|
||||
) -> (Option<ast::Expr>, bool) {
|
||||
let mut identifiers = HashMap::new();
|
||||
let params: Vec<ast::Pat> = scoped_idents
|
||||
.iter()
|
||||
.enumerate()
|
||||
.map(|(index, id)| {
|
||||
let new_ident = private_ident!(format!("p{}", index));
|
||||
identifiers.insert(id.clone(), ast::Expr::Ident(new_ident.clone()));
|
||||
ast::Pat::Ident(ast::BindingIdent {
|
||||
id: new_ident,
|
||||
type_ann: None,
|
||||
})
|
||||
})
|
||||
.collect();
|
||||
let mut identifiers = HashMap::new();
|
||||
let params: Vec<ast::Pat> = scoped_idents
|
||||
.iter()
|
||||
.enumerate()
|
||||
.map(|(index, id)| {
|
||||
let new_ident = private_ident!(format!("p{}", index));
|
||||
identifiers.insert(id.clone(), ast::Expr::Ident(new_ident.clone()));
|
||||
ast::Pat::Ident(ast::BindingIdent {
|
||||
id: new_ident,
|
||||
type_ann: None,
|
||||
})
|
||||
})
|
||||
.collect();
|
||||
|
||||
if matches!(expr, ast::Expr::Arrow(_)) {
|
||||
return (None, false);
|
||||
}
|
||||
if matches!(expr, ast::Expr::Arrow(_)) {
|
||||
return (None, false);
|
||||
}
|
||||
|
||||
// Replace identifier
|
||||
let mut replace_identifiers = ReplaceIdentifiers::new(identifiers, accept_call_expr);
|
||||
expr.visit_mut_with(&mut replace_identifiers);
|
||||
// Replace identifier
|
||||
let mut replace_identifiers = ReplaceIdentifiers::new(identifiers, accept_call_expr);
|
||||
expr.visit_mut_with(&mut replace_identifiers);
|
||||
|
||||
if replace_identifiers.abort {
|
||||
return (None, false);
|
||||
}
|
||||
if replace_identifiers.abort {
|
||||
return (None, false);
|
||||
}
|
||||
|
||||
let rendered_expr = render_expr(&expr);
|
||||
if rendered_expr.len() > 150 {
|
||||
return (None, false);
|
||||
}
|
||||
let rendered_expr = render_expr(&expr);
|
||||
if rendered_expr.len() > 150 {
|
||||
return (None, false);
|
||||
}
|
||||
|
||||
if scoped_idents.is_empty() {
|
||||
return (None, true);
|
||||
}
|
||||
if scoped_idents.is_empty() {
|
||||
return (None, true);
|
||||
}
|
||||
|
||||
// Generate stringified version
|
||||
let rendered_str =
|
||||
ast::ExprOrSpread::from(ast::Expr::Lit(ast::Lit::Str(ast::Str::from(rendered_expr))));
|
||||
// Generate stringified version
|
||||
let rendered_str =
|
||||
ast::ExprOrSpread::from(ast::Expr::Lit(ast::Lit::Str(ast::Str::from(rendered_expr))));
|
||||
|
||||
// Wrap around arrow functions
|
||||
let expr = ast::Expr::Arrow(ast::ArrowExpr {
|
||||
body: Box::new(ast::BlockStmtOrExpr::Expr(Box::new(expr))),
|
||||
is_async: false,
|
||||
is_generator: false,
|
||||
params,
|
||||
return_type: None,
|
||||
span: DUMMY_SP,
|
||||
type_params: None,
|
||||
});
|
||||
// Wrap around arrow functions
|
||||
let expr = ast::Expr::Arrow(ast::ArrowExpr {
|
||||
body: Box::new(ast::BlockStmtOrExpr::Expr(Box::new(expr))),
|
||||
is_async: false,
|
||||
is_generator: false,
|
||||
params,
|
||||
return_type: None,
|
||||
span: DUMMY_SP,
|
||||
type_params: None,
|
||||
});
|
||||
|
||||
let mut args = vec![
|
||||
ast::ExprOrSpread::from(expr),
|
||||
ast::ExprOrSpread::from(ast::Expr::Array(ast::ArrayLit {
|
||||
span: DUMMY_SP,
|
||||
elems: scoped_idents
|
||||
.iter()
|
||||
.map(|id| {
|
||||
Some(ast::ExprOrSpread::from(ast::Expr::Ident(
|
||||
new_ident_from_id(id),
|
||||
)))
|
||||
})
|
||||
.collect(),
|
||||
})),
|
||||
];
|
||||
let mut args = vec![
|
||||
ast::ExprOrSpread::from(expr),
|
||||
ast::ExprOrSpread::from(ast::Expr::Array(ast::ArrayLit {
|
||||
span: DUMMY_SP,
|
||||
elems: scoped_idents
|
||||
.iter()
|
||||
.map(|id| {
|
||||
Some(ast::ExprOrSpread::from(ast::Expr::Ident(
|
||||
new_ident_from_id(id),
|
||||
)))
|
||||
})
|
||||
.collect(),
|
||||
})),
|
||||
];
|
||||
|
||||
if serialize_fn {
|
||||
args.push(rendered_str)
|
||||
}
|
||||
if serialize_fn {
|
||||
args.push(rendered_str)
|
||||
}
|
||||
|
||||
(
|
||||
Some(ast::Expr::Call(ast::CallExpr {
|
||||
span: DUMMY_SP,
|
||||
callee: ast::Callee::Expr(Box::new(ast::Expr::Ident(new_ident_from_id(qqhook)))),
|
||||
type_args: None,
|
||||
args,
|
||||
})),
|
||||
true,
|
||||
)
|
||||
(
|
||||
Some(ast::Expr::Call(ast::CallExpr {
|
||||
span: DUMMY_SP,
|
||||
callee: ast::Callee::Expr(Box::new(ast::Expr::Ident(new_ident_from_id(qqhook)))),
|
||||
type_args: None,
|
||||
args,
|
||||
})),
|
||||
true,
|
||||
)
|
||||
}
|
||||
|
||||
struct ReplaceIdentifiers {
|
||||
pub identifiers: HashMap<Id, ast::Expr>,
|
||||
pub accept_call_expr: bool,
|
||||
pub abort: bool,
|
||||
pub identifiers: HashMap<Id, ast::Expr>,
|
||||
pub accept_call_expr: bool,
|
||||
pub abort: bool,
|
||||
}
|
||||
|
||||
impl ReplaceIdentifiers {
|
||||
const fn new(identifiers: HashMap<Id, ast::Expr>, accept_call_expr: bool) -> Self {
|
||||
Self {
|
||||
identifiers,
|
||||
accept_call_expr,
|
||||
abort: false,
|
||||
}
|
||||
}
|
||||
const fn new(identifiers: HashMap<Id, ast::Expr>, accept_call_expr: bool) -> Self {
|
||||
Self {
|
||||
identifiers,
|
||||
accept_call_expr,
|
||||
abort: false,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl VisitMut for ReplaceIdentifiers {
|
||||
fn visit_mut_expr(&mut self, node: &mut ast::Expr) {
|
||||
match node {
|
||||
ast::Expr::Ident(ident) => {
|
||||
if let Some(expr) = self.identifiers.get(&id!(ident)) {
|
||||
*node = expr.clone();
|
||||
}
|
||||
}
|
||||
_ => {
|
||||
node.visit_mut_children_with(self);
|
||||
}
|
||||
}
|
||||
}
|
||||
fn visit_mut_expr(&mut self, node: &mut ast::Expr) {
|
||||
match node {
|
||||
ast::Expr::Ident(ident) => {
|
||||
if let Some(expr) = self.identifiers.get(&id!(ident)) {
|
||||
*node = expr.clone();
|
||||
}
|
||||
}
|
||||
_ => {
|
||||
node.visit_mut_children_with(self);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn visit_mut_prop(&mut self, node: &mut ast::Prop) {
|
||||
if let ast::Prop::Shorthand(short) = node {
|
||||
if let Some(expr) = self.identifiers.get(&id!(short)) {
|
||||
*node = ast::Prop::KeyValue(ast::KeyValueProp {
|
||||
key: ast::PropName::Ident(short.clone()),
|
||||
value: Box::new(expr.clone()),
|
||||
});
|
||||
}
|
||||
}
|
||||
node.visit_mut_children_with(self);
|
||||
}
|
||||
fn visit_mut_prop(&mut self, node: &mut ast::Prop) {
|
||||
if let ast::Prop::Shorthand(short) = node {
|
||||
if let Some(expr) = self.identifiers.get(&id!(short)) {
|
||||
*node = ast::Prop::KeyValue(ast::KeyValueProp {
|
||||
key: ast::PropName::Ident(short.clone()),
|
||||
value: Box::new(expr.clone()),
|
||||
});
|
||||
}
|
||||
}
|
||||
node.visit_mut_children_with(self);
|
||||
}
|
||||
|
||||
fn visit_mut_callee(&mut self, node: &mut ast::Callee) {
|
||||
if !self.accept_call_expr || matches!(node, ast::Callee::Import(_)) {
|
||||
self.abort = true;
|
||||
} else {
|
||||
node.visit_mut_children_with(self);
|
||||
}
|
||||
}
|
||||
fn visit_mut_callee(&mut self, node: &mut ast::Callee) {
|
||||
if !self.accept_call_expr || matches!(node, ast::Callee::Import(_)) {
|
||||
self.abort = true;
|
||||
} else {
|
||||
node.visit_mut_children_with(self);
|
||||
}
|
||||
}
|
||||
|
||||
fn visit_mut_arrow_expr(&mut self, _: &mut ast::ArrowExpr) {
|
||||
self.abort = true;
|
||||
}
|
||||
fn visit_mut_arrow_expr(&mut self, _: &mut ast::ArrowExpr) {
|
||||
self.abort = true;
|
||||
}
|
||||
|
||||
fn visit_mut_function(&mut self, _: &mut ast::Function) {
|
||||
self.abort = true;
|
||||
}
|
||||
fn visit_mut_function(&mut self, _: &mut ast::Function) {
|
||||
self.abort = true;
|
||||
}
|
||||
|
||||
fn visit_mut_class_expr(&mut self, _: &mut ast::ClassExpr) {
|
||||
self.abort = true;
|
||||
}
|
||||
fn visit_mut_class_expr(&mut self, _: &mut ast::ClassExpr) {
|
||||
self.abort = true;
|
||||
}
|
||||
|
||||
fn visit_mut_decorator(&mut self, _: &mut ast::Decorator) {
|
||||
self.abort = true;
|
||||
}
|
||||
fn visit_mut_decorator(&mut self, _: &mut ast::Decorator) {
|
||||
self.abort = true;
|
||||
}
|
||||
|
||||
fn visit_mut_stmt(&mut self, _: &mut ast::Stmt) {
|
||||
self.abort = true;
|
||||
}
|
||||
fn visit_mut_stmt(&mut self, _: &mut ast::Stmt) {
|
||||
self.abort = true;
|
||||
}
|
||||
}
|
||||
|
||||
pub fn render_expr(expr: &ast::Expr) -> String {
|
||||
let mut expr = expr.clone();
|
||||
let mut buf = Vec::new();
|
||||
let source_map = Lrc::new(SourceMap::default());
|
||||
let writer = Box::new(JsWriter::new(Lrc::clone(&source_map), "\n", &mut buf, None));
|
||||
let config = swc_ecmascript::codegen::Config {
|
||||
minify: true,
|
||||
target: ast::EsVersion::latest(),
|
||||
ascii_only: false,
|
||||
omit_last_semi: false,
|
||||
};
|
||||
let mut emitter = swc_ecmascript::codegen::Emitter {
|
||||
cfg: config,
|
||||
comments: None,
|
||||
cm: Lrc::clone(&source_map),
|
||||
wr: writer,
|
||||
};
|
||||
expr.visit_mut_with(&mut hygiene_with_config(Default::default()));
|
||||
expr.visit_mut_with(&mut fixer(None));
|
||||
emitter
|
||||
.emit_module_item(&ast::ModuleItem::Stmt(ast::Stmt::Expr(ast::ExprStmt {
|
||||
span: DUMMY_SP,
|
||||
expr: Box::new(expr),
|
||||
})))
|
||||
.expect("Should emit");
|
||||
let mut expr = expr.clone();
|
||||
let mut buf = Vec::new();
|
||||
let source_map = Lrc::new(SourceMap::default());
|
||||
let writer = Box::new(JsWriter::new(Lrc::clone(&source_map), "\n", &mut buf, None));
|
||||
let config = swc_ecmascript::codegen::Config {
|
||||
minify: true,
|
||||
target: ast::EsVersion::latest(),
|
||||
ascii_only: false,
|
||||
omit_last_semi: false,
|
||||
};
|
||||
let mut emitter = swc_ecmascript::codegen::Emitter {
|
||||
cfg: config,
|
||||
comments: None,
|
||||
cm: Lrc::clone(&source_map),
|
||||
wr: writer,
|
||||
};
|
||||
expr.visit_mut_with(&mut hygiene_with_config(Default::default()));
|
||||
expr.visit_mut_with(&mut fixer(None));
|
||||
emitter
|
||||
.emit_module_item(&ast::ModuleItem::Stmt(ast::Stmt::Expr(ast::ExprStmt {
|
||||
span: DUMMY_SP,
|
||||
expr: Box::new(expr),
|
||||
})))
|
||||
.expect("Should emit");
|
||||
|
||||
str::from_utf8(&buf)
|
||||
.expect("should be utf8")
|
||||
.trim_end_matches(';')
|
||||
.to_string()
|
||||
str::from_utf8(&buf)
|
||||
.expect("should be utf8")
|
||||
.trim_end_matches(';')
|
||||
.to_string()
|
||||
}
|
||||
|
||||
@@ -4,36 +4,36 @@ use swc_ecmascript::ast;
|
||||
use swc_ecmascript::visit::{noop_visit_type, Visit};
|
||||
|
||||
macro_rules! id {
|
||||
($ident: expr) => {
|
||||
($ident.sym.clone(), $ident.span.ctxt())
|
||||
};
|
||||
($ident: expr) => {
|
||||
($ident.sym.clone(), $ident.span.ctxt())
|
||||
};
|
||||
}
|
||||
|
||||
pub fn is_immutable_expr(
|
||||
expr: &ast::Expr,
|
||||
global: &GlobalCollect,
|
||||
current_stack: Option<&Vec<IdPlusType>>,
|
||||
expr: &ast::Expr,
|
||||
global: &GlobalCollect,
|
||||
current_stack: Option<&Vec<IdPlusType>>,
|
||||
) -> bool {
|
||||
let mut collector = ImmutableCollector::new(global, current_stack);
|
||||
collector.visit_expr(expr);
|
||||
collector.is_immutable
|
||||
let mut collector = ImmutableCollector::new(global, current_stack);
|
||||
collector.visit_expr(expr);
|
||||
collector.is_immutable
|
||||
}
|
||||
|
||||
pub struct ImmutableCollector<'a> {
|
||||
global: &'a GlobalCollect,
|
||||
immutable_idents: Option<&'a Vec<IdPlusType>>,
|
||||
global: &'a GlobalCollect,
|
||||
immutable_idents: Option<&'a Vec<IdPlusType>>,
|
||||
|
||||
pub is_immutable: bool,
|
||||
pub is_immutable: bool,
|
||||
}
|
||||
|
||||
impl<'a> ImmutableCollector<'a> {
|
||||
const fn new(global: &'a GlobalCollect, immutable_idents: Option<&'a Vec<IdPlusType>>) -> Self {
|
||||
Self {
|
||||
global,
|
||||
is_immutable: true,
|
||||
immutable_idents,
|
||||
}
|
||||
}
|
||||
const fn new(global: &'a GlobalCollect, immutable_idents: Option<&'a Vec<IdPlusType>>) -> Self {
|
||||
Self {
|
||||
global,
|
||||
is_immutable: true,
|
||||
immutable_idents,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// A prop is considered mutable if it:
|
||||
@@ -41,34 +41,34 @@ impl<'a> ImmutableCollector<'a> {
|
||||
// - accesses a member
|
||||
// - is a variable that is not an import, an export, or in the immutable stack
|
||||
impl<'a> Visit for ImmutableCollector<'a> {
|
||||
noop_visit_type!();
|
||||
noop_visit_type!();
|
||||
|
||||
fn visit_call_expr(&mut self, _: &ast::CallExpr) {
|
||||
self.is_immutable = false;
|
||||
}
|
||||
fn visit_call_expr(&mut self, _: &ast::CallExpr) {
|
||||
self.is_immutable = false;
|
||||
}
|
||||
|
||||
fn visit_member_expr(&mut self, _: &ast::MemberExpr) {
|
||||
self.is_immutable = false;
|
||||
}
|
||||
fn visit_member_expr(&mut self, _: &ast::MemberExpr) {
|
||||
self.is_immutable = false;
|
||||
}
|
||||
|
||||
fn visit_arrow_expr(&mut self, _: &ast::ArrowExpr) {}
|
||||
fn visit_arrow_expr(&mut self, _: &ast::ArrowExpr) {}
|
||||
|
||||
fn visit_ident(&mut self, ident: &ast::Ident) {
|
||||
let id = id!(ident);
|
||||
if self.global.imports.contains_key(&id) {
|
||||
return;
|
||||
}
|
||||
if self.global.exports.contains_key(&id) {
|
||||
return;
|
||||
}
|
||||
if let Some(current_stack) = self.immutable_idents {
|
||||
if current_stack
|
||||
.iter()
|
||||
.any(|item| item.1 == IdentType::Var(true) && item.0 == id)
|
||||
{
|
||||
return;
|
||||
}
|
||||
}
|
||||
self.is_immutable = false;
|
||||
}
|
||||
fn visit_ident(&mut self, ident: &ast::Ident) {
|
||||
let id = id!(ident);
|
||||
if self.global.imports.contains_key(&id) {
|
||||
return;
|
||||
}
|
||||
if self.global.exports.contains_key(&id) {
|
||||
return;
|
||||
}
|
||||
if let Some(current_stack) = self.immutable_idents {
|
||||
if current_stack
|
||||
.iter()
|
||||
.any(|item| item.1 == IdentType::Var(true) && item.0 == id)
|
||||
{
|
||||
return;
|
||||
}
|
||||
}
|
||||
self.is_immutable = false;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -55,195 +55,195 @@ pub use crate::parse::{ErrorBuffer, HookAnalysis, MinifyMode, TransformModule, T
|
||||
#[derive(Serialize, Debug, Deserialize)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
pub struct TransformFsOptions {
|
||||
pub src_dir: String,
|
||||
pub root_dir: Option<String>,
|
||||
pub vendor_roots: Vec<String>,
|
||||
pub glob: Option<String>,
|
||||
pub minify: MinifyMode,
|
||||
pub entry_strategy: EntryStrategy,
|
||||
pub manual_chunks: Option<HashMap<String, JsWord>>,
|
||||
pub source_maps: bool,
|
||||
pub transpile_ts: bool,
|
||||
pub transpile_jsx: bool,
|
||||
pub preserve_filenames: bool,
|
||||
pub explicit_extensions: bool,
|
||||
pub mode: EmitMode,
|
||||
pub scope: Option<String>,
|
||||
pub src_dir: String,
|
||||
pub root_dir: Option<String>,
|
||||
pub vendor_roots: Vec<String>,
|
||||
pub glob: Option<String>,
|
||||
pub minify: MinifyMode,
|
||||
pub entry_strategy: EntryStrategy,
|
||||
pub manual_chunks: Option<HashMap<String, JsWord>>,
|
||||
pub source_maps: bool,
|
||||
pub transpile_ts: bool,
|
||||
pub transpile_jsx: bool,
|
||||
pub preserve_filenames: bool,
|
||||
pub explicit_extensions: bool,
|
||||
pub mode: EmitMode,
|
||||
pub scope: Option<String>,
|
||||
|
||||
pub core_module: Option<String>,
|
||||
pub strip_exports: Option<Vec<JsWord>>,
|
||||
pub strip_ctx_name: Option<Vec<JsWord>>,
|
||||
pub strip_event_handlers: bool,
|
||||
pub reg_ctx_name: Option<Vec<JsWord>>,
|
||||
pub is_server: Option<bool>,
|
||||
pub core_module: Option<String>,
|
||||
pub strip_exports: Option<Vec<JsWord>>,
|
||||
pub strip_ctx_name: Option<Vec<JsWord>>,
|
||||
pub strip_event_handlers: bool,
|
||||
pub reg_ctx_name: Option<Vec<JsWord>>,
|
||||
pub is_server: Option<bool>,
|
||||
}
|
||||
|
||||
#[derive(Serialize, Debug, Deserialize)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
pub struct TransformModuleInput {
|
||||
pub path: String,
|
||||
pub code: String,
|
||||
pub path: String,
|
||||
pub code: String,
|
||||
}
|
||||
|
||||
#[derive(Debug, Serialize, Deserialize)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
pub struct TransformModulesOptions {
|
||||
pub src_dir: String,
|
||||
pub root_dir: Option<String>,
|
||||
pub input: Vec<TransformModuleInput>,
|
||||
pub source_maps: bool,
|
||||
pub minify: MinifyMode,
|
||||
pub transpile_ts: bool,
|
||||
pub transpile_jsx: bool,
|
||||
pub preserve_filenames: bool,
|
||||
pub entry_strategy: EntryStrategy,
|
||||
pub manual_chunks: Option<HashMap<String, JsWord>>,
|
||||
pub explicit_extensions: bool,
|
||||
pub mode: EmitMode,
|
||||
pub scope: Option<String>,
|
||||
pub src_dir: String,
|
||||
pub root_dir: Option<String>,
|
||||
pub input: Vec<TransformModuleInput>,
|
||||
pub source_maps: bool,
|
||||
pub minify: MinifyMode,
|
||||
pub transpile_ts: bool,
|
||||
pub transpile_jsx: bool,
|
||||
pub preserve_filenames: bool,
|
||||
pub entry_strategy: EntryStrategy,
|
||||
pub manual_chunks: Option<HashMap<String, JsWord>>,
|
||||
pub explicit_extensions: bool,
|
||||
pub mode: EmitMode,
|
||||
pub scope: Option<String>,
|
||||
|
||||
pub core_module: Option<String>,
|
||||
pub strip_exports: Option<Vec<JsWord>>,
|
||||
pub strip_ctx_name: Option<Vec<JsWord>>,
|
||||
pub strip_event_handlers: bool,
|
||||
pub reg_ctx_name: Option<Vec<JsWord>>,
|
||||
pub is_server: Option<bool>,
|
||||
pub core_module: Option<String>,
|
||||
pub strip_exports: Option<Vec<JsWord>>,
|
||||
pub strip_ctx_name: Option<Vec<JsWord>>,
|
||||
pub strip_event_handlers: bool,
|
||||
pub reg_ctx_name: Option<Vec<JsWord>>,
|
||||
pub is_server: Option<bool>,
|
||||
}
|
||||
|
||||
#[cfg(feature = "fs")]
|
||||
pub fn transform_fs(config: TransformFsOptions) -> Result<TransformOutput, Error> {
|
||||
let core_module = config
|
||||
.core_module
|
||||
.map_or(BUILDER_IO_QWIK.clone(), |s| s.into());
|
||||
let src_dir = Path::new(&config.src_dir);
|
||||
let root_dir = config.root_dir.as_ref().map(Path::new);
|
||||
let core_module = config
|
||||
.core_module
|
||||
.map_or(BUILDER_IO_QWIK.clone(), |s| s.into());
|
||||
let src_dir = Path::new(&config.src_dir);
|
||||
let root_dir = config.root_dir.as_ref().map(Path::new);
|
||||
|
||||
let mut paths = vec![];
|
||||
let entry_policy = &*parse_entry_strategy(&config.entry_strategy, config.manual_chunks);
|
||||
crate::package_json::find_modules(src_dir, config.vendor_roots, &mut paths)?;
|
||||
let mut paths = vec![];
|
||||
let entry_policy = &*parse_entry_strategy(&config.entry_strategy, config.manual_chunks);
|
||||
crate::package_json::find_modules(src_dir, config.vendor_roots, &mut paths)?;
|
||||
|
||||
#[cfg(feature = "parallel")]
|
||||
let iterator = paths.par_iter();
|
||||
#[cfg(feature = "parallel")]
|
||||
let iterator = paths.par_iter();
|
||||
|
||||
#[cfg(not(feature = "parallel"))]
|
||||
let iterator = paths.iter();
|
||||
let mut final_output = iterator
|
||||
.map(|path| -> Result<TransformOutput, Error> {
|
||||
let code = fs::read_to_string(path)
|
||||
.with_context(|| format!("Opening {}", &path.to_string_lossy()))?;
|
||||
#[cfg(not(feature = "parallel"))]
|
||||
let iterator = paths.iter();
|
||||
let mut final_output = iterator
|
||||
.map(|path| -> Result<TransformOutput, Error> {
|
||||
let code = fs::read_to_string(path)
|
||||
.with_context(|| format!("Opening {}", &path.to_string_lossy()))?;
|
||||
|
||||
let relative_path = pathdiff::diff_paths(path, &config.src_dir).unwrap();
|
||||
transform_code(TransformCodeOptions {
|
||||
src_dir,
|
||||
root_dir,
|
||||
relative_path: relative_path.to_str().unwrap(),
|
||||
minify: config.minify,
|
||||
code: &code,
|
||||
explicit_extensions: config.explicit_extensions,
|
||||
source_maps: config.source_maps,
|
||||
transpile_jsx: config.transpile_jsx,
|
||||
transpile_ts: config.transpile_ts,
|
||||
preserve_filenames: config.preserve_filenames,
|
||||
scope: config.scope.as_ref(),
|
||||
entry_policy,
|
||||
mode: config.mode,
|
||||
core_module: core_module.clone(),
|
||||
entry_strategy: config.entry_strategy,
|
||||
reg_ctx_name: config.reg_ctx_name.as_deref(),
|
||||
strip_exports: config.strip_exports.as_deref(),
|
||||
strip_ctx_name: config.strip_ctx_name.as_deref(),
|
||||
strip_event_handlers: config.strip_event_handlers,
|
||||
is_server: config.is_server,
|
||||
})
|
||||
})
|
||||
.reduce(|| Ok(TransformOutput::new()), |x, y| Ok(x?.append(&mut y?)))?;
|
||||
let relative_path = pathdiff::diff_paths(path, &config.src_dir).unwrap();
|
||||
transform_code(TransformCodeOptions {
|
||||
src_dir,
|
||||
root_dir,
|
||||
relative_path: relative_path.to_str().unwrap(),
|
||||
minify: config.minify,
|
||||
code: &code,
|
||||
explicit_extensions: config.explicit_extensions,
|
||||
source_maps: config.source_maps,
|
||||
transpile_jsx: config.transpile_jsx,
|
||||
transpile_ts: config.transpile_ts,
|
||||
preserve_filenames: config.preserve_filenames,
|
||||
scope: config.scope.as_ref(),
|
||||
entry_policy,
|
||||
mode: config.mode,
|
||||
core_module: core_module.clone(),
|
||||
entry_strategy: config.entry_strategy,
|
||||
reg_ctx_name: config.reg_ctx_name.as_deref(),
|
||||
strip_exports: config.strip_exports.as_deref(),
|
||||
strip_ctx_name: config.strip_ctx_name.as_deref(),
|
||||
strip_event_handlers: config.strip_event_handlers,
|
||||
is_server: config.is_server,
|
||||
})
|
||||
})
|
||||
.reduce(|| Ok(TransformOutput::new()), |x, y| Ok(x?.append(&mut y?)))?;
|
||||
|
||||
final_output.modules.sort_unstable_by_key(|key| key.order);
|
||||
if !matches!(
|
||||
config.entry_strategy,
|
||||
EntryStrategy::Hook | EntryStrategy::Inline | EntryStrategy::Hoist
|
||||
) {
|
||||
final_output = generate_entries(
|
||||
final_output,
|
||||
&core_module,
|
||||
config.explicit_extensions,
|
||||
root_dir,
|
||||
)?;
|
||||
}
|
||||
// final_output = generate_entries(
|
||||
// final_output,
|
||||
// &core_module,
|
||||
// config.explicit_extensions,
|
||||
// root_dir,
|
||||
// )?;
|
||||
Ok(final_output)
|
||||
final_output.modules.sort_unstable_by_key(|key| key.order);
|
||||
if !matches!(
|
||||
config.entry_strategy,
|
||||
EntryStrategy::Hook | EntryStrategy::Inline | EntryStrategy::Hoist
|
||||
) {
|
||||
final_output = generate_entries(
|
||||
final_output,
|
||||
&core_module,
|
||||
config.explicit_extensions,
|
||||
root_dir,
|
||||
)?;
|
||||
}
|
||||
// final_output = generate_entries(
|
||||
// final_output,
|
||||
// &core_module,
|
||||
// config.explicit_extensions,
|
||||
// root_dir,
|
||||
// )?;
|
||||
Ok(final_output)
|
||||
}
|
||||
|
||||
pub fn transform_modules(config: TransformModulesOptions) -> Result<TransformOutput, Error> {
|
||||
let core_module = config
|
||||
.core_module
|
||||
.map_or(BUILDER_IO_QWIK.clone(), |s| s.into());
|
||||
let src_dir = std::path::Path::new(&config.src_dir);
|
||||
let root_dir = config.root_dir.as_ref().map(Path::new);
|
||||
let core_module = config
|
||||
.core_module
|
||||
.map_or(BUILDER_IO_QWIK.clone(), |s| s.into());
|
||||
let src_dir = std::path::Path::new(&config.src_dir);
|
||||
let root_dir = config.root_dir.as_ref().map(Path::new);
|
||||
|
||||
let entry_policy = &*parse_entry_strategy(&config.entry_strategy, config.manual_chunks);
|
||||
#[cfg(feature = "parallel")]
|
||||
let iterator = config.input.par_iter();
|
||||
let entry_policy = &*parse_entry_strategy(&config.entry_strategy, config.manual_chunks);
|
||||
#[cfg(feature = "parallel")]
|
||||
let iterator = config.input.par_iter();
|
||||
|
||||
#[cfg(not(feature = "parallel"))]
|
||||
let iterator = config.input.iter();
|
||||
let iterator = iterator.map(|path| -> Result<TransformOutput, Error> {
|
||||
transform_code(TransformCodeOptions {
|
||||
src_dir,
|
||||
root_dir,
|
||||
relative_path: &path.path,
|
||||
code: &path.code,
|
||||
minify: config.minify,
|
||||
source_maps: config.source_maps,
|
||||
transpile_ts: config.transpile_ts,
|
||||
transpile_jsx: config.transpile_jsx,
|
||||
preserve_filenames: config.preserve_filenames,
|
||||
explicit_extensions: config.explicit_extensions,
|
||||
entry_policy,
|
||||
mode: config.mode,
|
||||
scope: config.scope.as_ref(),
|
||||
core_module: core_module.clone(),
|
||||
entry_strategy: config.entry_strategy,
|
||||
reg_ctx_name: config.reg_ctx_name.as_deref(),
|
||||
strip_exports: config.strip_exports.as_deref(),
|
||||
strip_ctx_name: config.strip_ctx_name.as_deref(),
|
||||
strip_event_handlers: config.strip_event_handlers,
|
||||
is_server: config.is_server,
|
||||
})
|
||||
});
|
||||
#[cfg(not(feature = "parallel"))]
|
||||
let iterator = config.input.iter();
|
||||
let iterator = iterator.map(|path| -> Result<TransformOutput, Error> {
|
||||
transform_code(TransformCodeOptions {
|
||||
src_dir,
|
||||
root_dir,
|
||||
relative_path: &path.path,
|
||||
code: &path.code,
|
||||
minify: config.minify,
|
||||
source_maps: config.source_maps,
|
||||
transpile_ts: config.transpile_ts,
|
||||
transpile_jsx: config.transpile_jsx,
|
||||
preserve_filenames: config.preserve_filenames,
|
||||
explicit_extensions: config.explicit_extensions,
|
||||
entry_policy,
|
||||
mode: config.mode,
|
||||
scope: config.scope.as_ref(),
|
||||
core_module: core_module.clone(),
|
||||
entry_strategy: config.entry_strategy,
|
||||
reg_ctx_name: config.reg_ctx_name.as_deref(),
|
||||
strip_exports: config.strip_exports.as_deref(),
|
||||
strip_ctx_name: config.strip_ctx_name.as_deref(),
|
||||
strip_event_handlers: config.strip_event_handlers,
|
||||
is_server: config.is_server,
|
||||
})
|
||||
});
|
||||
|
||||
#[cfg(feature = "parallel")]
|
||||
let final_output: Result<TransformOutput, Error> =
|
||||
iterator.reduce(|| Ok(TransformOutput::new()), |x, y| Ok(x?.append(&mut y?)));
|
||||
#[cfg(feature = "parallel")]
|
||||
let final_output: Result<TransformOutput, Error> =
|
||||
iterator.reduce(|| Ok(TransformOutput::new()), |x, y| Ok(x?.append(&mut y?)));
|
||||
|
||||
#[cfg(not(feature = "parallel"))]
|
||||
let final_output: Result<TransformOutput, Error> =
|
||||
iterator.fold(Ok(TransformOutput::new()), |x, y| Ok(x?.append(&mut y?)));
|
||||
#[cfg(not(feature = "parallel"))]
|
||||
let final_output: Result<TransformOutput, Error> =
|
||||
iterator.fold(Ok(TransformOutput::new()), |x, y| Ok(x?.append(&mut y?)));
|
||||
|
||||
let mut final_output = final_output?;
|
||||
final_output.modules.sort_unstable_by_key(|key| key.order);
|
||||
if !matches!(
|
||||
config.entry_strategy,
|
||||
EntryStrategy::Hook | EntryStrategy::Inline | EntryStrategy::Hoist
|
||||
) {
|
||||
final_output = generate_entries(
|
||||
final_output,
|
||||
&core_module,
|
||||
config.explicit_extensions,
|
||||
root_dir,
|
||||
)?;
|
||||
}
|
||||
// final_output = generate_entries(
|
||||
// final_output,
|
||||
// &core_module,
|
||||
// config.explicit_extensions,
|
||||
// root_dir,
|
||||
// )?;
|
||||
let mut final_output = final_output?;
|
||||
final_output.modules.sort_unstable_by_key(|key| key.order);
|
||||
if !matches!(
|
||||
config.entry_strategy,
|
||||
EntryStrategy::Hook | EntryStrategy::Inline | EntryStrategy::Hoist
|
||||
) {
|
||||
final_output = generate_entries(
|
||||
final_output,
|
||||
&core_module,
|
||||
config.explicit_extensions,
|
||||
root_dir,
|
||||
)?;
|
||||
}
|
||||
// final_output = generate_entries(
|
||||
// final_output,
|
||||
// &core_module,
|
||||
// config.explicit_extensions,
|
||||
// root_dir,
|
||||
// )?;
|
||||
|
||||
Ok(final_output)
|
||||
Ok(final_output)
|
||||
}
|
||||
|
||||
@@ -3,39 +3,39 @@ pub use crate::parse::{ErrorBuffer, HookAnalysis, MinifyMode, TransformModule, T
|
||||
|
||||
#[cfg(feature = "fs")]
|
||||
pub fn find_modules(
|
||||
src_dir: &std::path::Path,
|
||||
vendor_dirs: Vec<String>,
|
||||
files: &mut Vec<std::path::PathBuf>,
|
||||
src_dir: &std::path::Path,
|
||||
vendor_dirs: Vec<String>,
|
||||
files: &mut Vec<std::path::PathBuf>,
|
||||
) -> std::io::Result<()> {
|
||||
for root in &vendor_dirs {
|
||||
find_files(std::path::Path::new(root), files)?;
|
||||
}
|
||||
find_files(src_dir, files)
|
||||
for root in &vendor_dirs {
|
||||
find_files(std::path::Path::new(root), files)?;
|
||||
}
|
||||
find_files(src_dir, files)
|
||||
}
|
||||
|
||||
#[cfg(feature = "fs")]
|
||||
fn find_files(dir: &std::path::Path, files: &mut Vec<std::path::PathBuf>) -> std::io::Result<()> {
|
||||
if dir.is_dir() {
|
||||
for entry in std::fs::read_dir(dir)? {
|
||||
let entry = entry?;
|
||||
let path = entry.path();
|
||||
if path.is_dir() {
|
||||
find_files(&path, files)?;
|
||||
} else if should_capture_file(&path) {
|
||||
files.push(path);
|
||||
}
|
||||
}
|
||||
} else if should_capture_file(dir) {
|
||||
files.push(dir.to_path_buf());
|
||||
}
|
||||
Ok(())
|
||||
if dir.is_dir() {
|
||||
for entry in std::fs::read_dir(dir)? {
|
||||
let entry = entry?;
|
||||
let path = entry.path();
|
||||
if path.is_dir() {
|
||||
find_files(&path, files)?;
|
||||
} else if should_capture_file(&path) {
|
||||
files.push(path);
|
||||
}
|
||||
}
|
||||
} else if should_capture_file(dir) {
|
||||
files.push(dir.to_path_buf());
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
|
||||
#[cfg(feature = "fs")]
|
||||
fn should_capture_file(path: &std::path::Path) -> bool {
|
||||
let ext = path.extension().and_then(|p| p.to_str());
|
||||
matches!(
|
||||
ext,
|
||||
Some("ts" | "tsx" | "js" | "jsx" | "mjs" | "mts" | "mtsx" | "mjsx")
|
||||
)
|
||||
let ext = path.extension().and_then(|p| p.to_str());
|
||||
matches!(
|
||||
ext,
|
||||
Some("ts" | "tsx" | "js" | "jsx" | "mjs" | "mts" | "mtsx" | "mjsx")
|
||||
)
|
||||
}
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -11,437 +11,437 @@ use swc_ecmascript::utils::private_ident;
|
||||
use swc_ecmascript::visit::{VisitMut, VisitMutWith};
|
||||
|
||||
struct PropsDestructuring<'a> {
|
||||
component_ident: Option<Id>,
|
||||
pub identifiers: HashMap<Id, ast::Expr>,
|
||||
pub global_collect: &'a mut GlobalCollect,
|
||||
pub core_module: &'a JsWord,
|
||||
component_ident: Option<Id>,
|
||||
pub identifiers: HashMap<Id, ast::Expr>,
|
||||
pub global_collect: &'a mut GlobalCollect,
|
||||
pub core_module: &'a JsWord,
|
||||
}
|
||||
|
||||
pub fn transform_props_destructuring(
|
||||
main_module: &mut ast::Module,
|
||||
global_collect: &mut GlobalCollect,
|
||||
core_module: &JsWord,
|
||||
main_module: &mut ast::Module,
|
||||
global_collect: &mut GlobalCollect,
|
||||
core_module: &JsWord,
|
||||
) {
|
||||
main_module.visit_mut_with(&mut PropsDestructuring {
|
||||
component_ident: global_collect.get_imported_local(&COMPONENT, core_module),
|
||||
identifiers: HashMap::new(),
|
||||
global_collect,
|
||||
core_module,
|
||||
});
|
||||
main_module.visit_mut_with(&mut PropsDestructuring {
|
||||
component_ident: global_collect.get_imported_local(&COMPONENT, core_module),
|
||||
identifiers: HashMap::new(),
|
||||
global_collect,
|
||||
core_module,
|
||||
});
|
||||
}
|
||||
|
||||
macro_rules! id {
|
||||
($ident: expr) => {
|
||||
($ident.sym.clone(), $ident.span.ctxt())
|
||||
};
|
||||
($ident: expr) => {
|
||||
($ident.sym.clone(), $ident.span.ctxt())
|
||||
};
|
||||
}
|
||||
|
||||
macro_rules! id_eq {
|
||||
($ident: expr, $cid: expr) => {
|
||||
if let Some(cid) = $cid {
|
||||
cid.0 == $ident.sym && cid.1 == $ident.span.ctxt()
|
||||
} else {
|
||||
false
|
||||
}
|
||||
};
|
||||
($ident: expr, $cid: expr) => {
|
||||
if let Some(cid) = $cid {
|
||||
cid.0 == $ident.sym && cid.1 == $ident.span.ctxt()
|
||||
} else {
|
||||
false
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
enum TransformInit {
|
||||
Keep,
|
||||
Remove,
|
||||
Replace(ast::Expr),
|
||||
Keep,
|
||||
Remove,
|
||||
Replace(ast::Expr),
|
||||
}
|
||||
|
||||
impl<'a> PropsDestructuring<'a> {
|
||||
fn transform_component_props(&mut self, arrow: &mut ast::ArrowExpr) {
|
||||
if let Some(ast::Pat::Object(obj)) = arrow.params.first() {
|
||||
let new_ident = private_ident!("props");
|
||||
if let Some((rest_id, local)) =
|
||||
transform_pat(ast::Expr::Ident(new_ident.clone()), obj, self)
|
||||
{
|
||||
if let Some(rest_id) = rest_id {
|
||||
let omit_fn = self.global_collect.import(&_REST_PROPS, self.core_module);
|
||||
let omit = local.iter().map(|(_, id, _)| id.clone()).collect();
|
||||
transform_rest(
|
||||
arrow,
|
||||
&omit_fn,
|
||||
&rest_id,
|
||||
ast::Expr::Ident(new_ident.clone()),
|
||||
omit,
|
||||
);
|
||||
}
|
||||
for (id, _, expr) in local {
|
||||
self.identifiers.insert(id, expr);
|
||||
}
|
||||
arrow.params[0] = ast::Pat::Ident(ast::BindingIdent::from(new_ident));
|
||||
}
|
||||
}
|
||||
if let ast::BlockStmtOrExpr::BlockStmt(body) = &mut *arrow.body {
|
||||
self.transform_component_body(body);
|
||||
}
|
||||
}
|
||||
fn transform_component_body(&mut self, body: &mut ast::BlockStmt) {
|
||||
let mut inserts = vec![];
|
||||
for (index, stmt) in body.stmts.iter_mut().enumerate() {
|
||||
if let ast::Stmt::Decl(ast::Decl::Var(var_decl)) = stmt {
|
||||
if var_decl.kind == ast::VarDeclKind::Const {
|
||||
for decl in var_decl.decls.iter_mut() {
|
||||
let convert = match &decl.init {
|
||||
Some(box ast::Expr::Lit(lit)) => {
|
||||
let new_ident = private_ident!("_unused");
|
||||
Some((
|
||||
new_ident,
|
||||
ast::Expr::Lit(lit.clone()),
|
||||
TransformInit::Remove,
|
||||
))
|
||||
}
|
||||
Some(box ast::Expr::Member(member_expr)) => match &member_expr.obj {
|
||||
box ast::Expr::Ident(ident) => {
|
||||
let new_ident = private_ident!("_unused");
|
||||
let expr = self
|
||||
.identifiers
|
||||
.get(&id!(ident.clone()))
|
||||
.cloned()
|
||||
.unwrap_or_else(|| ast::Expr::Ident(ident.clone()));
|
||||
fn transform_component_props(&mut self, arrow: &mut ast::ArrowExpr) {
|
||||
if let Some(ast::Pat::Object(obj)) = arrow.params.first() {
|
||||
let new_ident = private_ident!("props");
|
||||
if let Some((rest_id, local)) =
|
||||
transform_pat(ast::Expr::Ident(new_ident.clone()), obj, self)
|
||||
{
|
||||
if let Some(rest_id) = rest_id {
|
||||
let omit_fn = self.global_collect.import(&_REST_PROPS, self.core_module);
|
||||
let omit = local.iter().map(|(_, id, _)| id.clone()).collect();
|
||||
transform_rest(
|
||||
arrow,
|
||||
&omit_fn,
|
||||
&rest_id,
|
||||
ast::Expr::Ident(new_ident.clone()),
|
||||
omit,
|
||||
);
|
||||
}
|
||||
for (id, _, expr) in local {
|
||||
self.identifiers.insert(id, expr);
|
||||
}
|
||||
arrow.params[0] = ast::Pat::Ident(ast::BindingIdent::from(new_ident));
|
||||
}
|
||||
}
|
||||
if let ast::BlockStmtOrExpr::BlockStmt(body) = &mut *arrow.body {
|
||||
self.transform_component_body(body);
|
||||
}
|
||||
}
|
||||
fn transform_component_body(&mut self, body: &mut ast::BlockStmt) {
|
||||
let mut inserts = vec![];
|
||||
for (index, stmt) in body.stmts.iter_mut().enumerate() {
|
||||
if let ast::Stmt::Decl(ast::Decl::Var(var_decl)) = stmt {
|
||||
if var_decl.kind == ast::VarDeclKind::Const {
|
||||
for decl in var_decl.decls.iter_mut() {
|
||||
let convert = match &decl.init {
|
||||
Some(box ast::Expr::Lit(lit)) => {
|
||||
let new_ident = private_ident!("_unused");
|
||||
Some((
|
||||
new_ident,
|
||||
ast::Expr::Lit(lit.clone()),
|
||||
TransformInit::Remove,
|
||||
))
|
||||
}
|
||||
Some(box ast::Expr::Member(member_expr)) => match &member_expr.obj {
|
||||
box ast::Expr::Ident(ident) => {
|
||||
let new_ident = private_ident!("_unused");
|
||||
let expr = self
|
||||
.identifiers
|
||||
.get(&id!(ident.clone()))
|
||||
.cloned()
|
||||
.unwrap_or_else(|| ast::Expr::Ident(ident.clone()));
|
||||
|
||||
let mut cloned_prop = member_expr.prop.clone();
|
||||
cloned_prop.visit_mut_with(self);
|
||||
let new_replace = ast::Expr::Member(ast::MemberExpr {
|
||||
obj: Box::new(expr),
|
||||
prop: cloned_prop,
|
||||
span: member_expr.span,
|
||||
});
|
||||
Some((new_ident, new_replace, TransformInit::Remove))
|
||||
}
|
||||
box ast::Expr::Call(call_expr) => {
|
||||
if let ast::Callee::Expr(box ast::Expr::Ident(ref ident)) =
|
||||
&call_expr.callee
|
||||
{
|
||||
if ident.sym.starts_with("use") {
|
||||
let new_ident =
|
||||
private_ident!(ident.sym[3..].to_lowercase());
|
||||
let mut cloned_prop = member_expr.prop.clone();
|
||||
cloned_prop.visit_mut_with(self);
|
||||
let new_replace = ast::Expr::Member(ast::MemberExpr {
|
||||
obj: Box::new(expr),
|
||||
prop: cloned_prop,
|
||||
span: member_expr.span,
|
||||
});
|
||||
Some((new_ident, new_replace, TransformInit::Remove))
|
||||
}
|
||||
box ast::Expr::Call(call_expr) => {
|
||||
if let ast::Callee::Expr(box ast::Expr::Ident(ref ident)) =
|
||||
&call_expr.callee
|
||||
{
|
||||
if ident.sym.starts_with("use") {
|
||||
let new_ident =
|
||||
private_ident!(ident.sym[3..].to_lowercase());
|
||||
|
||||
let mut cloned_prop = member_expr.prop.clone();
|
||||
cloned_prop.visit_mut_with(self);
|
||||
let mut cloned_prop = member_expr.prop.clone();
|
||||
cloned_prop.visit_mut_with(self);
|
||||
|
||||
let new_replace = ast::Expr::Member(ast::MemberExpr {
|
||||
obj: Box::new(ast::Expr::Ident(new_ident.clone())),
|
||||
prop: cloned_prop,
|
||||
span: DUMMY_SP,
|
||||
});
|
||||
Some((
|
||||
new_ident,
|
||||
new_replace,
|
||||
TransformInit::Replace(ast::Expr::Call(
|
||||
call_expr.clone(),
|
||||
)),
|
||||
))
|
||||
} else {
|
||||
None
|
||||
}
|
||||
} else {
|
||||
None
|
||||
}
|
||||
}
|
||||
_ => None,
|
||||
},
|
||||
Some(box ast::Expr::Ident(ref ident)) => {
|
||||
let new_ident = private_ident!("_unused");
|
||||
let new_replace = self
|
||||
.identifiers
|
||||
.get(&id!(ident.clone()))
|
||||
.cloned()
|
||||
.unwrap_or_else(|| ast::Expr::Ident(ident.clone()));
|
||||
Some((new_ident, new_replace, TransformInit::Remove))
|
||||
}
|
||||
Some(box ast::Expr::Call(call_expr)) => {
|
||||
if let ast::Callee::Expr(box ast::Expr::Ident(ref ident)) =
|
||||
&call_expr.callee
|
||||
{
|
||||
if ident.sym.starts_with("use") {
|
||||
let new_ident =
|
||||
private_ident!(ident.sym[3..].to_lowercase());
|
||||
let new_replace = ast::Expr::Ident(new_ident.clone());
|
||||
Some((new_ident, new_replace, TransformInit::Keep))
|
||||
} else {
|
||||
None
|
||||
}
|
||||
} else {
|
||||
None
|
||||
}
|
||||
}
|
||||
_ => None,
|
||||
};
|
||||
if let Some((replace_pat, new_ref, init)) = convert {
|
||||
let keep_ident = matches!(init, TransformInit::Keep);
|
||||
let mut transform_init = init;
|
||||
match &decl.name {
|
||||
ast::Pat::Ident(ident) => {
|
||||
if !keep_ident {
|
||||
self.identifiers.insert(id!(ident.id.clone()), new_ref);
|
||||
decl.name =
|
||||
ast::Pat::Ident(ast::BindingIdent::from(replace_pat));
|
||||
} else {
|
||||
transform_init = TransformInit::Keep;
|
||||
}
|
||||
}
|
||||
ast::Pat::Object(obj_pat) => {
|
||||
if let Some((rest_id, local)) =
|
||||
transform_pat(new_ref.clone(), obj_pat, self)
|
||||
{
|
||||
if let Some(rest_id) = rest_id {
|
||||
let omit_fn = self
|
||||
.global_collect
|
||||
.import(&_REST_PROPS, self.core_module);
|
||||
let omit =
|
||||
local.iter().map(|(_, id, _)| id.clone()).collect();
|
||||
let new_replace = ast::Expr::Member(ast::MemberExpr {
|
||||
obj: Box::new(ast::Expr::Ident(new_ident.clone())),
|
||||
prop: cloned_prop,
|
||||
span: DUMMY_SP,
|
||||
});
|
||||
Some((
|
||||
new_ident,
|
||||
new_replace,
|
||||
TransformInit::Replace(ast::Expr::Call(
|
||||
call_expr.clone(),
|
||||
)),
|
||||
))
|
||||
} else {
|
||||
None
|
||||
}
|
||||
} else {
|
||||
None
|
||||
}
|
||||
}
|
||||
_ => None,
|
||||
},
|
||||
Some(box ast::Expr::Ident(ref ident)) => {
|
||||
let new_ident = private_ident!("_unused");
|
||||
let new_replace = self
|
||||
.identifiers
|
||||
.get(&id!(ident.clone()))
|
||||
.cloned()
|
||||
.unwrap_or_else(|| ast::Expr::Ident(ident.clone()));
|
||||
Some((new_ident, new_replace, TransformInit::Remove))
|
||||
}
|
||||
Some(box ast::Expr::Call(call_expr)) => {
|
||||
if let ast::Callee::Expr(box ast::Expr::Ident(ref ident)) =
|
||||
&call_expr.callee
|
||||
{
|
||||
if ident.sym.starts_with("use") {
|
||||
let new_ident =
|
||||
private_ident!(ident.sym[3..].to_lowercase());
|
||||
let new_replace = ast::Expr::Ident(new_ident.clone());
|
||||
Some((new_ident, new_replace, TransformInit::Keep))
|
||||
} else {
|
||||
None
|
||||
}
|
||||
} else {
|
||||
None
|
||||
}
|
||||
}
|
||||
_ => None,
|
||||
};
|
||||
if let Some((replace_pat, new_ref, init)) = convert {
|
||||
let keep_ident = matches!(init, TransformInit::Keep);
|
||||
let mut transform_init = init;
|
||||
match &decl.name {
|
||||
ast::Pat::Ident(ident) => {
|
||||
if !keep_ident {
|
||||
self.identifiers.insert(id!(ident.id.clone()), new_ref);
|
||||
decl.name =
|
||||
ast::Pat::Ident(ast::BindingIdent::from(replace_pat));
|
||||
} else {
|
||||
transform_init = TransformInit::Keep;
|
||||
}
|
||||
}
|
||||
ast::Pat::Object(obj_pat) => {
|
||||
if let Some((rest_id, local)) =
|
||||
transform_pat(new_ref.clone(), obj_pat, self)
|
||||
{
|
||||
if let Some(rest_id) = rest_id {
|
||||
let omit_fn = self
|
||||
.global_collect
|
||||
.import(&_REST_PROPS, self.core_module);
|
||||
let omit =
|
||||
local.iter().map(|(_, id, _)| id.clone()).collect();
|
||||
|
||||
let element = create_omit_props(
|
||||
&omit_fn, &rest_id, new_ref, omit,
|
||||
);
|
||||
inserts.push((index + 1 + inserts.len(), element));
|
||||
}
|
||||
for (id, _, expr) in local {
|
||||
self.identifiers.insert(id, expr);
|
||||
}
|
||||
decl.name =
|
||||
ast::Pat::Ident(ast::BindingIdent::from(replace_pat));
|
||||
} else {
|
||||
transform_init = TransformInit::Keep;
|
||||
}
|
||||
}
|
||||
_ => {
|
||||
transform_init = TransformInit::Keep;
|
||||
}
|
||||
}
|
||||
match transform_init {
|
||||
TransformInit::Remove => {
|
||||
decl.init = None;
|
||||
}
|
||||
TransformInit::Replace(expr) => {
|
||||
decl.init = Some(Box::new(expr));
|
||||
}
|
||||
TransformInit::Keep => {}
|
||||
}
|
||||
}
|
||||
}
|
||||
} else {
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
let element = create_omit_props(
|
||||
&omit_fn, &rest_id, new_ref, omit,
|
||||
);
|
||||
inserts.push((index + 1 + inserts.len(), element));
|
||||
}
|
||||
for (id, _, expr) in local {
|
||||
self.identifiers.insert(id, expr);
|
||||
}
|
||||
decl.name =
|
||||
ast::Pat::Ident(ast::BindingIdent::from(replace_pat));
|
||||
} else {
|
||||
transform_init = TransformInit::Keep;
|
||||
}
|
||||
}
|
||||
_ => {
|
||||
transform_init = TransformInit::Keep;
|
||||
}
|
||||
}
|
||||
match transform_init {
|
||||
TransformInit::Remove => {
|
||||
decl.init = None;
|
||||
}
|
||||
TransformInit::Replace(expr) => {
|
||||
decl.init = Some(Box::new(expr));
|
||||
}
|
||||
TransformInit::Keep => {}
|
||||
}
|
||||
}
|
||||
}
|
||||
} else {
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
for (index, stmt) in inserts {
|
||||
body.stmts.insert(index, stmt);
|
||||
}
|
||||
}
|
||||
for (index, stmt) in inserts {
|
||||
body.stmts.insert(index, stmt);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a> VisitMut for PropsDestructuring<'a> {
|
||||
fn visit_mut_call_expr(&mut self, node: &mut ast::CallExpr) {
|
||||
if let ast::Callee::Expr(box ast::Expr::Ident(ref ident)) = &node.callee {
|
||||
if id_eq!(ident, &self.component_ident) {
|
||||
if let Some(first_arg) = node.args.first_mut() {
|
||||
if let ast::Expr::Arrow(arrow) = &mut *first_arg.expr {
|
||||
self.transform_component_props(arrow);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
fn visit_mut_call_expr(&mut self, node: &mut ast::CallExpr) {
|
||||
if let ast::Callee::Expr(box ast::Expr::Ident(ref ident)) = &node.callee {
|
||||
if id_eq!(ident, &self.component_ident) {
|
||||
if let Some(first_arg) = node.args.first_mut() {
|
||||
if let ast::Expr::Arrow(arrow) = &mut *first_arg.expr {
|
||||
self.transform_component_props(arrow);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
node.visit_mut_children_with(self);
|
||||
}
|
||||
node.visit_mut_children_with(self);
|
||||
}
|
||||
|
||||
fn visit_mut_expr(&mut self, node: &mut ast::Expr) {
|
||||
match node {
|
||||
ast::Expr::Ident(ident) => {
|
||||
if let Some(expr) = self.identifiers.get(&id!(ident)) {
|
||||
*node = expr.clone();
|
||||
}
|
||||
}
|
||||
_ => {
|
||||
node.visit_mut_children_with(self);
|
||||
}
|
||||
}
|
||||
}
|
||||
fn visit_mut_expr(&mut self, node: &mut ast::Expr) {
|
||||
match node {
|
||||
ast::Expr::Ident(ident) => {
|
||||
if let Some(expr) = self.identifiers.get(&id!(ident)) {
|
||||
*node = expr.clone();
|
||||
}
|
||||
}
|
||||
_ => {
|
||||
node.visit_mut_children_with(self);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn visit_mut_prop(&mut self, node: &mut ast::Prop) {
|
||||
if let ast::Prop::Shorthand(short) = node {
|
||||
if let Some(expr) = self.identifiers.get(&id!(short)) {
|
||||
*node = ast::Prop::KeyValue(ast::KeyValueProp {
|
||||
key: ast::PropName::Ident(short.clone()),
|
||||
value: Box::new(expr.clone()),
|
||||
});
|
||||
}
|
||||
}
|
||||
node.visit_mut_children_with(self);
|
||||
}
|
||||
fn visit_mut_prop(&mut self, node: &mut ast::Prop) {
|
||||
if let ast::Prop::Shorthand(short) = node {
|
||||
if let Some(expr) = self.identifiers.get(&id!(short)) {
|
||||
*node = ast::Prop::KeyValue(ast::KeyValueProp {
|
||||
key: ast::PropName::Ident(short.clone()),
|
||||
value: Box::new(expr.clone()),
|
||||
});
|
||||
}
|
||||
}
|
||||
node.visit_mut_children_with(self);
|
||||
}
|
||||
}
|
||||
|
||||
type TransformPatReturn = (Option<Id>, Vec<(Id, JsWord, ast::Expr)>);
|
||||
fn transform_pat(
|
||||
new_ident: ast::Expr,
|
||||
obj: &ast::ObjectPat,
|
||||
props_transform: &mut PropsDestructuring,
|
||||
new_ident: ast::Expr,
|
||||
obj: &ast::ObjectPat,
|
||||
props_transform: &mut PropsDestructuring,
|
||||
) -> Option<TransformPatReturn> {
|
||||
let mut local = vec![];
|
||||
let mut skip = false;
|
||||
let mut rest_id = None;
|
||||
for prop in &obj.props {
|
||||
match prop {
|
||||
ast::ObjectPatProp::Assign(ref v) => {
|
||||
let access = ast::Expr::Member(ast::MemberExpr {
|
||||
obj: Box::new(new_ident.clone()),
|
||||
prop: ast::MemberProp::Ident(v.key.clone()),
|
||||
span: DUMMY_SP,
|
||||
});
|
||||
if let Some(value) = &v.value {
|
||||
if is_immutable_expr(value.as_ref(), props_transform.global_collect, None) {
|
||||
local.push((
|
||||
id!(v.key),
|
||||
v.key.sym.clone(),
|
||||
ast::Expr::Bin(ast::BinExpr {
|
||||
span: DUMMY_SP,
|
||||
op: ast::BinaryOp::NullishCoalescing,
|
||||
left: Box::new(access),
|
||||
right: value.clone(),
|
||||
}),
|
||||
));
|
||||
} else {
|
||||
skip = true;
|
||||
}
|
||||
} else {
|
||||
local.push((id!(v.key), v.key.sym.clone(), access));
|
||||
}
|
||||
}
|
||||
ast::ObjectPatProp::KeyValue(ref v) => {
|
||||
if let ast::PropName::Ident(ref key) = v.key {
|
||||
match &v.value {
|
||||
box ast::Pat::Ident(ref ident) => {
|
||||
let access = ast::Expr::Member(ast::MemberExpr {
|
||||
obj: Box::new(new_ident.clone()),
|
||||
prop: ast::MemberProp::Ident(key.clone()),
|
||||
span: DUMMY_SP,
|
||||
});
|
||||
local.push((id!(ident), key.sym.clone(), access));
|
||||
}
|
||||
box ast::Pat::Assign(ast::AssignPat {
|
||||
left: box ast::Pat::Ident(ident),
|
||||
right: value,
|
||||
..
|
||||
}) => {
|
||||
if is_immutable_expr(
|
||||
value.as_ref(),
|
||||
props_transform.global_collect,
|
||||
None,
|
||||
) {
|
||||
let access = ast::Expr::Member(ast::MemberExpr {
|
||||
obj: Box::new(new_ident.clone()),
|
||||
prop: ast::MemberProp::Ident(key.clone()),
|
||||
span: DUMMY_SP,
|
||||
});
|
||||
local.push((
|
||||
id!(ident.id),
|
||||
key.sym.clone(),
|
||||
ast::Expr::Bin(ast::BinExpr {
|
||||
span: DUMMY_SP,
|
||||
op: ast::BinaryOp::NullishCoalescing,
|
||||
left: Box::new(access),
|
||||
right: value.clone(),
|
||||
}),
|
||||
));
|
||||
} else {
|
||||
skip = true;
|
||||
}
|
||||
}
|
||||
_ => {
|
||||
skip = true;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
skip = true;
|
||||
}
|
||||
}
|
||||
ast::ObjectPatProp::Rest(ast::RestPat { box arg, .. }) => {
|
||||
if let ast::Pat::Ident(ref ident) = arg {
|
||||
rest_id = Some(id!(&ident.id));
|
||||
} else {
|
||||
skip = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
if skip || local.is_empty() {
|
||||
return None;
|
||||
}
|
||||
Some((rest_id, local))
|
||||
let mut local = vec![];
|
||||
let mut skip = false;
|
||||
let mut rest_id = None;
|
||||
for prop in &obj.props {
|
||||
match prop {
|
||||
ast::ObjectPatProp::Assign(ref v) => {
|
||||
let access = ast::Expr::Member(ast::MemberExpr {
|
||||
obj: Box::new(new_ident.clone()),
|
||||
prop: ast::MemberProp::Ident(v.key.clone()),
|
||||
span: DUMMY_SP,
|
||||
});
|
||||
if let Some(value) = &v.value {
|
||||
if is_immutable_expr(value.as_ref(), props_transform.global_collect, None) {
|
||||
local.push((
|
||||
id!(v.key),
|
||||
v.key.sym.clone(),
|
||||
ast::Expr::Bin(ast::BinExpr {
|
||||
span: DUMMY_SP,
|
||||
op: ast::BinaryOp::NullishCoalescing,
|
||||
left: Box::new(access),
|
||||
right: value.clone(),
|
||||
}),
|
||||
));
|
||||
} else {
|
||||
skip = true;
|
||||
}
|
||||
} else {
|
||||
local.push((id!(v.key), v.key.sym.clone(), access));
|
||||
}
|
||||
}
|
||||
ast::ObjectPatProp::KeyValue(ref v) => {
|
||||
if let ast::PropName::Ident(ref key) = v.key {
|
||||
match &v.value {
|
||||
box ast::Pat::Ident(ref ident) => {
|
||||
let access = ast::Expr::Member(ast::MemberExpr {
|
||||
obj: Box::new(new_ident.clone()),
|
||||
prop: ast::MemberProp::Ident(key.clone()),
|
||||
span: DUMMY_SP,
|
||||
});
|
||||
local.push((id!(ident), key.sym.clone(), access));
|
||||
}
|
||||
box ast::Pat::Assign(ast::AssignPat {
|
||||
left: box ast::Pat::Ident(ident),
|
||||
right: value,
|
||||
..
|
||||
}) => {
|
||||
if is_immutable_expr(
|
||||
value.as_ref(),
|
||||
props_transform.global_collect,
|
||||
None,
|
||||
) {
|
||||
let access = ast::Expr::Member(ast::MemberExpr {
|
||||
obj: Box::new(new_ident.clone()),
|
||||
prop: ast::MemberProp::Ident(key.clone()),
|
||||
span: DUMMY_SP,
|
||||
});
|
||||
local.push((
|
||||
id!(ident.id),
|
||||
key.sym.clone(),
|
||||
ast::Expr::Bin(ast::BinExpr {
|
||||
span: DUMMY_SP,
|
||||
op: ast::BinaryOp::NullishCoalescing,
|
||||
left: Box::new(access),
|
||||
right: value.clone(),
|
||||
}),
|
||||
));
|
||||
} else {
|
||||
skip = true;
|
||||
}
|
||||
}
|
||||
_ => {
|
||||
skip = true;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
skip = true;
|
||||
}
|
||||
}
|
||||
ast::ObjectPatProp::Rest(ast::RestPat { box arg, .. }) => {
|
||||
if let ast::Pat::Ident(ref ident) = arg {
|
||||
rest_id = Some(id!(&ident.id));
|
||||
} else {
|
||||
skip = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
if skip || local.is_empty() {
|
||||
return None;
|
||||
}
|
||||
Some((rest_id, local))
|
||||
}
|
||||
|
||||
fn transform_rest(
|
||||
arrow: &mut ast::ArrowExpr,
|
||||
omit_fn: &Id,
|
||||
rest_id: &Id,
|
||||
props_expr: ast::Expr,
|
||||
omit: Vec<JsWord>,
|
||||
arrow: &mut ast::ArrowExpr,
|
||||
omit_fn: &Id,
|
||||
rest_id: &Id,
|
||||
props_expr: ast::Expr,
|
||||
omit: Vec<JsWord>,
|
||||
) {
|
||||
let new_stmt = create_omit_props(omit_fn, rest_id, props_expr, omit);
|
||||
match &mut arrow.body {
|
||||
box ast::BlockStmtOrExpr::BlockStmt(block) => {
|
||||
block.stmts.insert(0, new_stmt);
|
||||
}
|
||||
box ast::BlockStmtOrExpr::Expr(ref expr) => {
|
||||
arrow.body = Box::new(ast::BlockStmtOrExpr::BlockStmt(ast::BlockStmt {
|
||||
span: DUMMY_SP,
|
||||
stmts: vec![new_stmt, create_return_stmt(expr.clone())],
|
||||
}));
|
||||
}
|
||||
}
|
||||
let new_stmt = create_omit_props(omit_fn, rest_id, props_expr, omit);
|
||||
match &mut arrow.body {
|
||||
box ast::BlockStmtOrExpr::BlockStmt(block) => {
|
||||
block.stmts.insert(0, new_stmt);
|
||||
}
|
||||
box ast::BlockStmtOrExpr::Expr(ref expr) => {
|
||||
arrow.body = Box::new(ast::BlockStmtOrExpr::BlockStmt(ast::BlockStmt {
|
||||
span: DUMMY_SP,
|
||||
stmts: vec![new_stmt, create_return_stmt(expr.clone())],
|
||||
}));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn create_omit_props(
|
||||
omit_fn: &Id,
|
||||
rest_id: &Id,
|
||||
props_expr: ast::Expr,
|
||||
omit: Vec<JsWord>,
|
||||
omit_fn: &Id,
|
||||
rest_id: &Id,
|
||||
props_expr: ast::Expr,
|
||||
omit: Vec<JsWord>,
|
||||
) -> ast::Stmt {
|
||||
ast::Stmt::Decl(ast::Decl::Var(Box::new(ast::VarDecl {
|
||||
span: DUMMY_SP,
|
||||
declare: false,
|
||||
kind: ast::VarDeclKind::Const,
|
||||
decls: vec![ast::VarDeclarator {
|
||||
definite: false,
|
||||
span: DUMMY_SP,
|
||||
init: Some(Box::new(ast::Expr::Call(ast::CallExpr {
|
||||
callee: ast::Callee::Expr(Box::new(ast::Expr::Ident(new_ident_from_id(omit_fn)))),
|
||||
span: DUMMY_SP,
|
||||
type_args: None,
|
||||
args: vec![
|
||||
ast::ExprOrSpread {
|
||||
spread: None,
|
||||
expr: Box::new(props_expr),
|
||||
},
|
||||
ast::ExprOrSpread {
|
||||
spread: None,
|
||||
expr: Box::new(ast::Expr::Array(ast::ArrayLit {
|
||||
span: DUMMY_SP,
|
||||
elems: omit
|
||||
.into_iter()
|
||||
.map(|v| {
|
||||
Some(ast::ExprOrSpread {
|
||||
spread: None,
|
||||
expr: Box::new(ast::Expr::Lit(ast::Lit::Str(ast::Str {
|
||||
span: DUMMY_SP,
|
||||
value: v,
|
||||
raw: None,
|
||||
}))),
|
||||
})
|
||||
})
|
||||
.collect(),
|
||||
})),
|
||||
},
|
||||
],
|
||||
}))),
|
||||
name: ast::Pat::Ident(ast::BindingIdent::from(new_ident_from_id(rest_id))),
|
||||
}],
|
||||
})))
|
||||
ast::Stmt::Decl(ast::Decl::Var(Box::new(ast::VarDecl {
|
||||
span: DUMMY_SP,
|
||||
declare: false,
|
||||
kind: ast::VarDeclKind::Const,
|
||||
decls: vec![ast::VarDeclarator {
|
||||
definite: false,
|
||||
span: DUMMY_SP,
|
||||
init: Some(Box::new(ast::Expr::Call(ast::CallExpr {
|
||||
callee: ast::Callee::Expr(Box::new(ast::Expr::Ident(new_ident_from_id(omit_fn)))),
|
||||
span: DUMMY_SP,
|
||||
type_args: None,
|
||||
args: vec![
|
||||
ast::ExprOrSpread {
|
||||
spread: None,
|
||||
expr: Box::new(props_expr),
|
||||
},
|
||||
ast::ExprOrSpread {
|
||||
spread: None,
|
||||
expr: Box::new(ast::Expr::Array(ast::ArrayLit {
|
||||
span: DUMMY_SP,
|
||||
elems: omit
|
||||
.into_iter()
|
||||
.map(|v| {
|
||||
Some(ast::ExprOrSpread {
|
||||
spread: None,
|
||||
expr: Box::new(ast::Expr::Lit(ast::Lit::Str(ast::Str {
|
||||
span: DUMMY_SP,
|
||||
value: v,
|
||||
raw: None,
|
||||
}))),
|
||||
})
|
||||
})
|
||||
.collect(),
|
||||
})),
|
||||
},
|
||||
],
|
||||
}))),
|
||||
name: ast::Pat::Ident(ast::BindingIdent::from(new_ident_from_id(rest_id))),
|
||||
}],
|
||||
})))
|
||||
}
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
@@ -5,74 +5,74 @@ use swc_atoms::JsWord;
|
||||
#[derive(Debug, Serialize, Deserialize, Clone, Eq, PartialEq)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
pub struct SourceLocation {
|
||||
lo: usize,
|
||||
hi: usize,
|
||||
start_line: usize,
|
||||
start_col: usize,
|
||||
end_line: usize,
|
||||
end_col: usize,
|
||||
lo: usize,
|
||||
hi: usize,
|
||||
start_line: usize,
|
||||
start_col: usize,
|
||||
end_line: usize,
|
||||
end_col: usize,
|
||||
}
|
||||
|
||||
impl SourceLocation {
|
||||
pub fn from(source_map: &swc_common::SourceMap, span: swc_common::Span) -> Self {
|
||||
let start = source_map.lookup_char_pos(span.lo);
|
||||
let end = source_map.lookup_char_pos(span.hi);
|
||||
// - SWC's columns are exclusive, ours are inclusive (column - 1)
|
||||
// - SWC has 0-based columns, ours are 1-based (column + 1)
|
||||
// = +-0
|
||||
pub fn from(source_map: &swc_common::SourceMap, span: swc_common::Span) -> Self {
|
||||
let start = source_map.lookup_char_pos(span.lo);
|
||||
let end = source_map.lookup_char_pos(span.hi);
|
||||
// - SWC's columns are exclusive, ours are inclusive (column - 1)
|
||||
// - SWC has 0-based columns, ours are 1-based (column + 1)
|
||||
// = +-0
|
||||
|
||||
Self {
|
||||
lo: span.lo.0 as usize,
|
||||
hi: span.hi.0 as usize,
|
||||
start_line: start.line,
|
||||
start_col: start.col_display + 1,
|
||||
end_line: end.line,
|
||||
end_col: end.col_display,
|
||||
}
|
||||
}
|
||||
Self {
|
||||
lo: span.lo.0 as usize,
|
||||
hi: span.hi.0 as usize,
|
||||
start_line: start.line,
|
||||
start_col: start.col_display + 1,
|
||||
end_line: end.line,
|
||||
end_col: end.col_display,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl PartialOrd for SourceLocation {
|
||||
fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
|
||||
match self.start_line.cmp(&other.start_line) {
|
||||
Ordering::Equal => self.start_col.partial_cmp(&other.start_col),
|
||||
o => Some(o),
|
||||
}
|
||||
}
|
||||
fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
|
||||
match self.start_line.cmp(&other.start_line) {
|
||||
Ordering::Equal => self.start_col.partial_cmp(&other.start_col),
|
||||
o => Some(o),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Serialize, Deserialize, Debug)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
pub struct Diagnostic {
|
||||
pub category: DiagnosticCategory,
|
||||
pub code: Option<String>,
|
||||
pub file: JsWord,
|
||||
pub message: String,
|
||||
pub highlights: Option<Vec<SourceLocation>>,
|
||||
pub suggestions: Option<Vec<String>>,
|
||||
pub scope: DiagnosticScope,
|
||||
pub category: DiagnosticCategory,
|
||||
pub code: Option<String>,
|
||||
pub file: JsWord,
|
||||
pub message: String,
|
||||
pub highlights: Option<Vec<SourceLocation>>,
|
||||
pub suggestions: Option<Vec<String>>,
|
||||
pub scope: DiagnosticScope,
|
||||
}
|
||||
|
||||
#[derive(Serialize, Deserialize, Debug, Eq, PartialEq)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
pub enum DiagnosticCategory {
|
||||
/// Fails the build with an error.
|
||||
Error,
|
||||
/// Logs a warning, but the build does not fail.
|
||||
Warning,
|
||||
/// An error if this is source code in the project, or a warning if in node_modules.
|
||||
SourceError,
|
||||
/// Fails the build with an error.
|
||||
Error,
|
||||
/// Logs a warning, but the build does not fail.
|
||||
Warning,
|
||||
/// An error if this is source code in the project, or a warning if in node_modules.
|
||||
SourceError,
|
||||
}
|
||||
|
||||
#[derive(Serialize, Deserialize, Debug, Eq, PartialEq)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
pub enum DiagnosticScope {
|
||||
Optimizer,
|
||||
Optimizer,
|
||||
}
|
||||
|
||||
#[derive(Serialize, Debug, Deserialize, Eq, PartialEq, Clone, Copy)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
pub enum SourceType {
|
||||
Script,
|
||||
Module,
|
||||
Script,
|
||||
Module,
|
||||
}
|
||||
|
||||
@@ -5,44 +5,44 @@ pub const SIGNAL: char = '$';
|
||||
pub const LONG_SUFFIX: &str = "Qrl";
|
||||
|
||||
lazy_static! {
|
||||
pub static ref REF: JsWord = JsWord::from("ref");
|
||||
pub static ref QSLOT: JsWord = JsWord::from("q:slot");
|
||||
pub static ref CHILDREN: JsWord = JsWord::from("children");
|
||||
pub static ref HANDLE_WATCH: JsWord = JsWord::from("_hW");
|
||||
pub static ref _QRL: JsWord = JsWord::from("qrl");
|
||||
pub static ref _QRL_DEV: JsWord = JsWord::from("qrlDEV");
|
||||
pub static ref _INLINED_QRL: JsWord = JsWord::from("inlinedQrl");
|
||||
pub static ref _INLINED_QRL_DEV: JsWord = JsWord::from("inlinedQrlDEV");
|
||||
pub static ref _NOOP_QRL: JsWord = JsWord::from("_noopQrl");
|
||||
pub static ref _REST_PROPS: JsWord = JsWord::from("_restProps");
|
||||
pub static ref QHOOK: JsWord = JsWord::from("$");
|
||||
pub static ref Q_SYNC: JsWord = JsWord::from("sync$");
|
||||
pub static ref QWIK_INTERNAL: JsWord = JsWord::from("qwik");
|
||||
pub static ref BUILDER_IO_QWIK: JsWord = JsWord::from("@builder.io/qwik");
|
||||
pub static ref BUILDER_IO_QWIK_BUILD: JsWord = JsWord::from("@builder.io/qwik/build");
|
||||
pub static ref BUILDER_IO_QWIK_JSX: JsWord = JsWord::from("@builder.io/qwik/jsx-runtime");
|
||||
pub static ref BUILDER_IO_QWIK_JSX_DEV: JsWord =
|
||||
JsWord::from("@builder.io/qwik/jsx-dev-runtime");
|
||||
pub static ref QCOMPONENT: JsWord = JsWord::from("component$");
|
||||
pub static ref USE_LEXICAL_SCOPE: JsWord = JsWord::from("useLexicalScope");
|
||||
pub static ref USE_SERVER_MOUNT: JsWord = JsWord::from("useServerMount$");
|
||||
pub static ref H: JsWord = JsWord::from("h");
|
||||
pub static ref FRAGMENT: JsWord = JsWord::from("Fragment");
|
||||
pub static ref _IMMUTABLE: JsWord = JsWord::from("_IMMUTABLE");
|
||||
pub static ref _INLINED_FN: JsWord = JsWord::from("_fnSignal");
|
||||
pub static ref IS_SERVER: JsWord = JsWord::from("isServer");
|
||||
pub static ref IS_BROWSER: JsWord = JsWord::from("isBrowser");
|
||||
pub static ref IS_DEV: JsWord = JsWord::from("isDev");
|
||||
pub static ref COMPONENT: JsWord = JsWord::from("component$");
|
||||
pub static ref _REG_SYMBOL: JsWord = JsWord::from("_regSymbol");
|
||||
pub static ref _JSX_BRANCH: JsWord = JsWord::from("_jsxBranch");
|
||||
pub static ref _QRL_SYNC: JsWord = JsWord::from("_qrlSync");
|
||||
pub static ref _WRAP_PROP: JsWord = JsWord::from("_wrapProp");
|
||||
pub static ref _WRAP_SIGNAL: JsWord = JsWord::from("_wrapSignal");
|
||||
pub static ref _JSX_Q: JsWord = JsWord::from("_jsxQ");
|
||||
pub static ref _JSX_S: JsWord = JsWord::from("_jsxS");
|
||||
pub static ref _JSX_C: JsWord = JsWord::from("_jsxC");
|
||||
pub static ref JSX: JsWord = JsWord::from("jsx");
|
||||
pub static ref JSXS: JsWord = JsWord::from("jsxs");
|
||||
pub static ref JSX_DEV: JsWord = JsWord::from("jsxDEV");
|
||||
pub static ref REF: JsWord = JsWord::from("ref");
|
||||
pub static ref QSLOT: JsWord = JsWord::from("q:slot");
|
||||
pub static ref CHILDREN: JsWord = JsWord::from("children");
|
||||
pub static ref HANDLE_WATCH: JsWord = JsWord::from("_hW");
|
||||
pub static ref _QRL: JsWord = JsWord::from("qrl");
|
||||
pub static ref _QRL_DEV: JsWord = JsWord::from("qrlDEV");
|
||||
pub static ref _INLINED_QRL: JsWord = JsWord::from("inlinedQrl");
|
||||
pub static ref _INLINED_QRL_DEV: JsWord = JsWord::from("inlinedQrlDEV");
|
||||
pub static ref _NOOP_QRL: JsWord = JsWord::from("_noopQrl");
|
||||
pub static ref _REST_PROPS: JsWord = JsWord::from("_restProps");
|
||||
pub static ref QHOOK: JsWord = JsWord::from("$");
|
||||
pub static ref Q_SYNC: JsWord = JsWord::from("sync$");
|
||||
pub static ref QWIK_INTERNAL: JsWord = JsWord::from("qwik");
|
||||
pub static ref BUILDER_IO_QWIK: JsWord = JsWord::from("@builder.io/qwik");
|
||||
pub static ref BUILDER_IO_QWIK_BUILD: JsWord = JsWord::from("@builder.io/qwik/build");
|
||||
pub static ref BUILDER_IO_QWIK_JSX: JsWord = JsWord::from("@builder.io/qwik/jsx-runtime");
|
||||
pub static ref BUILDER_IO_QWIK_JSX_DEV: JsWord =
|
||||
JsWord::from("@builder.io/qwik/jsx-dev-runtime");
|
||||
pub static ref QCOMPONENT: JsWord = JsWord::from("component$");
|
||||
pub static ref USE_LEXICAL_SCOPE: JsWord = JsWord::from("useLexicalScope");
|
||||
pub static ref USE_SERVER_MOUNT: JsWord = JsWord::from("useServerMount$");
|
||||
pub static ref H: JsWord = JsWord::from("h");
|
||||
pub static ref FRAGMENT: JsWord = JsWord::from("Fragment");
|
||||
pub static ref _IMMUTABLE: JsWord = JsWord::from("_IMMUTABLE");
|
||||
pub static ref _INLINED_FN: JsWord = JsWord::from("_fnSignal");
|
||||
pub static ref IS_SERVER: JsWord = JsWord::from("isServer");
|
||||
pub static ref IS_BROWSER: JsWord = JsWord::from("isBrowser");
|
||||
pub static ref IS_DEV: JsWord = JsWord::from("isDev");
|
||||
pub static ref COMPONENT: JsWord = JsWord::from("component$");
|
||||
pub static ref _REG_SYMBOL: JsWord = JsWord::from("_regSymbol");
|
||||
pub static ref _JSX_BRANCH: JsWord = JsWord::from("_jsxBranch");
|
||||
pub static ref _QRL_SYNC: JsWord = JsWord::from("_qrlSync");
|
||||
pub static ref _WRAP_PROP: JsWord = JsWord::from("_wrapProp");
|
||||
pub static ref _WRAP_SIGNAL: JsWord = JsWord::from("_wrapSignal");
|
||||
pub static ref _JSX_Q: JsWord = JsWord::from("_jsxQ");
|
||||
pub static ref _JSX_S: JsWord = JsWord::from("_jsxS");
|
||||
pub static ref _JSX_C: JsWord = JsWord::from("_jsxC");
|
||||
pub static ref JSX: JsWord = JsWord::from("jsx");
|
||||
pub static ref JSXS: JsWord = JsWord::from("jsxs");
|
||||
pub static ref JSX_DEV: JsWord = JsWord::from("jsxDEV");
|
||||
}
|
||||
|
||||
1
rustfmt.toml
Normal file
1
rustfmt.toml
Normal file
@@ -0,0 +1 @@
|
||||
hard_tabs = true
|
||||
Reference in New Issue
Block a user