From 6a859b500411e50f650576a7d015156c1bc28ffa Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=EA=B0=95=EB=8F=99=EC=9C=A4=20=28Donny=29?= Date: Thu, 19 Sep 2024 15:20:57 +0900 Subject: [PATCH 01/21] Init by copy --- packages/swc-sdk/.npmignore | 2 + packages/swc-sdk/CHANGELOG.md | 139 +++++++++++++++ packages/swc-sdk/Cargo.toml | 25 +++ packages/swc-sdk/README.md | 163 ++++++++++++++++++ packages/swc-sdk/README.tmpl.md | 25 +++ packages/swc-sdk/package.json | 24 +++ packages/swc-sdk/src/lib.rs | 30 ++++ packages/swc-sdk/transform/Cargo.toml | 28 +++ .../swc-sdk/transform/src/import_analyzer.rs | 92 ++++++++++ packages/swc-sdk/transform/src/lib.rs | 110 ++++++++++++ packages/swc-sdk/transform/tests/fixture.rs | 33 ++++ .../tests/fixture/no-name-clash/input.js | 3 + .../tests/fixture/no-name-clash/output.js | 2 + .../transform/tests/fixture/simple/input.js | 3 + .../transform/tests/fixture/simple/output.js | 1 + 15 files changed, 680 insertions(+) create mode 100644 packages/swc-sdk/.npmignore create mode 100644 packages/swc-sdk/CHANGELOG.md create mode 100644 packages/swc-sdk/Cargo.toml create mode 100644 packages/swc-sdk/README.md create mode 100644 packages/swc-sdk/README.tmpl.md create mode 100644 packages/swc-sdk/package.json create mode 100644 packages/swc-sdk/src/lib.rs create mode 100644 packages/swc-sdk/transform/Cargo.toml create mode 100644 packages/swc-sdk/transform/src/import_analyzer.rs create mode 100644 packages/swc-sdk/transform/src/lib.rs create mode 100644 packages/swc-sdk/transform/tests/fixture.rs create mode 100644 packages/swc-sdk/transform/tests/fixture/no-name-clash/input.js create mode 100644 packages/swc-sdk/transform/tests/fixture/no-name-clash/output.js create mode 100644 packages/swc-sdk/transform/tests/fixture/simple/input.js create mode 100644 packages/swc-sdk/transform/tests/fixture/simple/output.js diff --git a/packages/swc-sdk/.npmignore b/packages/swc-sdk/.npmignore new file mode 100644 index 000000000..1ed674f50 --- /dev/null +++ b/packages/swc-sdk/.npmignore @@ -0,0 +1,2 @@ +transform/ +tests/ \ No newline at end of file diff --git a/packages/swc-sdk/CHANGELOG.md b/packages/swc-sdk/CHANGELOG.md new file mode 100644 index 000000000..565f3f02a --- /dev/null +++ b/packages/swc-sdk/CHANGELOG.md @@ -0,0 +1,139 @@ +# @swc/plugin-swc-sdk + +## 3.0.1 + +### Patch Changes + +- 04548e2: Update swc_core to 0.103.x + +## 3.0.0 + +### Major Changes + +- f8e5fd0: Update swc_core to 0.102.x + +## 2.0.10 + +### Patch Changes + +- 7d17e25: Update swc_core to v0.101.x + +## 2.0.9 + +### Patch Changes + +- 7391419: Update swc_core to v0.100.0 + +## 2.0.8 + +### Patch Changes + +- 9c28afb: Update swc_core to 0.99.x (@swc/core 1.7.0) + +## 2.0.7 + +### Patch Changes + +- af25741: Update swc_core to 0.96.0 + +## 2.0.6 + +### Patch Changes + +- 41a8f56: Update swc_core to v0.95.x + +## 2.0.5 + +### Patch Changes + +- fc30490: Update swc_core to v0.93.0 + +## 2.0.4 + +### Patch Changes + +- 0f38844: Publish all chanages + +## 2.0.3 + +### Patch Changes + +- 1cc9eda: Update dependencies + +## 2.0.2 + +### Patch Changes + +- 247cca6: Update rustc to 'nightly-2024-04-16' + +## 2.0.1 + +### Patch Changes + +- 876bbce: Update swc_core to 0.92.x + +## 2.0.0 + +### Major Changes + +- 8e91d39: Update swc_core to 0.91.x + +## 1.5.121 + +### Patch Changes + +- f4df366: Update swc_core + +## 1.5.120 + +### Patch Changes + +- c88b22b: Align package metadata + +## 1.5.119 + +### Patch Changes + +- a3cc4fb: Organize pacakge metadata + +## 1.5.118 + +### Patch Changes + +- e9e78ef: Update swc crates + +## 1.5.117 + +### Patch Changes + +- 6096d6d: Fix plugin version schema issue + +## 1.5.116 + +### Patch Changes + +- 37d3aaf: Depend on the swc download counter package + +## 1.5.115 + +### Patch Changes + +- 8bd92c7: swc_core 0.90.x + +## 1.5.114 + +### Patch Changes + +- 4ef0b7f: Add changelog to the readme + +## 1.5.113 + +### Patch Changes + +- 4e72680: swc_core@0.88.0 + +## 1.5.112 + +### Patch Changes + +- 16bb4d8: swc_core@0.82.x diff --git a/packages/swc-sdk/Cargo.toml b/packages/swc-sdk/Cargo.toml new file mode 100644 index 000000000..3a8dd6cf7 --- /dev/null +++ b/packages/swc-sdk/Cargo.toml @@ -0,0 +1,25 @@ +[package] + +description = "SWC Plugin for @swc/sdk" + + +authors = { workspace = true } +edition = { workspace = true } +homepage = { workspace = true } +license = { workspace = true } +name = "swc_plugin_swc_sdk" +publish = false +repository = { workspace = true } +rust-version = { workspace = true } +version = "0.1.0" + + +[lib] +crate-type = ["cdylib", "rlib"] + +[dependencies] +serde_json = { workspace = true } +swc_core = { workspace = true, features = ["ecma_plugin_transform"] } + + +swc_sdk = { path = "./transform" } diff --git a/packages/swc-sdk/README.md b/packages/swc-sdk/README.md new file mode 100644 index 000000000..e8152e812 --- /dev/null +++ b/packages/swc-sdk/README.md @@ -0,0 +1,163 @@ +# @swc/plugin-swc-sdk + +## Usage + +.swcrc: + +```json +{ + "jsc": { + "experimental": { + "plugins": ["@swc/plugin-swc-sdk"] + } + } +} +``` + +### `markAsPure` + +```js +import { markAsPure } from "@swc/sdk"; + +markAsPure(() => console.log("This will be removed by the SWC minifier")); +``` + +# @swc/plugin-swc-sdk + +## 3.0.1 + +### Patch Changes + +- 04548e2: Update swc_core to 0.103.x + +## 3.0.0 + +### Major Changes + +- f8e5fd0: Update swc_core to 0.102.x + +## 2.0.10 + +### Patch Changes + +- 7d17e25: Update swc_core to v0.101.x + +## 2.0.9 + +### Patch Changes + +- 7391419: Update swc_core to v0.100.0 + +## 2.0.8 + +### Patch Changes + +- 9c28afb: Update swc_core to 0.99.x (@swc/core 1.7.0) + +## 2.0.7 + +### Patch Changes + +- af25741: Update swc_core to 0.96.0 + +## 2.0.6 + +### Patch Changes + +- 41a8f56: Update swc_core to v0.95.x + +## 2.0.5 + +### Patch Changes + +- fc30490: Update swc_core to v0.93.0 + +## 2.0.4 + +### Patch Changes + +- 0f38844: Publish all chanages + +## 2.0.3 + +### Patch Changes + +- 1cc9eda: Update dependencies + +## 2.0.2 + +### Patch Changes + +- 247cca6: Update rustc to 'nightly-2024-04-16' + +## 2.0.1 + +### Patch Changes + +- 876bbce: Update swc_core to 0.92.x + +## 2.0.0 + +### Major Changes + +- 8e91d39: Update swc_core to 0.91.x + +## 1.5.121 + +### Patch Changes + +- f4df366: Update swc_core + +## 1.5.120 + +### Patch Changes + +- c88b22b: Align package metadata + +## 1.5.119 + +### Patch Changes + +- a3cc4fb: Organize pacakge metadata + +## 1.5.118 + +### Patch Changes + +- e9e78ef: Update swc crates + +## 1.5.117 + +### Patch Changes + +- 6096d6d: Fix plugin version schema issue + +## 1.5.116 + +### Patch Changes + +- 37d3aaf: Depend on the swc download counter package + +## 1.5.115 + +### Patch Changes + +- 8bd92c7: swc_core 0.90.x + +## 1.5.114 + +### Patch Changes + +- 4ef0b7f: Add changelog to the readme + +## 1.5.113 + +### Patch Changes + +- 4e72680: swc_core@0.88.0 + +## 1.5.112 + +### Patch Changes + +- 16bb4d8: swc_core@0.82.x diff --git a/packages/swc-sdk/README.tmpl.md b/packages/swc-sdk/README.tmpl.md new file mode 100644 index 000000000..1d6738e70 --- /dev/null +++ b/packages/swc-sdk/README.tmpl.md @@ -0,0 +1,25 @@ +# @swc/plugin-swc-sdk + +## Usage + +.swcrc: + +```json +{ + "jsc": { + "experimental": { + "plugins": ["@swc/plugin-swc-sdk"] + } + } +} +``` + +### `markAsPure` + +```js +import { markAsPure } from "@swc/sdk"; + +markAsPure(() => console.log("This will be removed by the SWC minifier")); +``` + +${CHANGELOG} diff --git a/packages/swc-sdk/package.json b/packages/swc-sdk/package.json new file mode 100644 index 000000000..d35ea6cb7 --- /dev/null +++ b/packages/swc-sdk/package.json @@ -0,0 +1,24 @@ +{ + "name": "@swc/plugin-swc-sdk", + "version": "3.0.1", + "description": "SWC plugin for swc-sdk", + "main": "swc_plugin_swc_sdk.wasm", + "scripts": { + "prepack": "cargo build --release -p swc_plugin_swc_sdk --target wasm32-wasi && cp ../../target/wasm32-wasi/release/swc_plugin_swc_sdk.wasm ." + }, + "homepage": "https://swc.rs", + "repository": { + "type": "git", + "url": "+https://github.com/swc-project/plugins.git" + }, + "bugs": { + "url": "https://github.com/swc-project/plugins/issues" + }, + "author": "강동윤 ", + "keywords": [], + "license": "Apache-2.0", + "preferUnplugged": true, + "dependencies": { + "@swc/counter": "^0.1.3" + } +} diff --git a/packages/swc-sdk/src/lib.rs b/packages/swc-sdk/src/lib.rs new file mode 100644 index 000000000..7b874456e --- /dev/null +++ b/packages/swc-sdk/src/lib.rs @@ -0,0 +1,30 @@ +#![allow(clippy::not_unsafe_ptr_arg_deref)] +#![feature(box_patterns)] + +use swc_core::{ + ecma::{ast::Program, visit::VisitMutWith}, + plugin::{ + plugin_transform, + proxies::{PluginCommentsProxy, TransformPluginProgramMetadata}, + }, +}; + +#[plugin_transform] +fn swc_sdk_plugin(mut program: Program, data: TransformPluginProgramMetadata) -> Program { + let config = serde_json::from_str::( + &data + .get_transform_plugin_config() + .expect("failed to get plugin config for swc-sdk"), + ) + .expect("invalid config for swc-sdk"); + + let unresolved_mark = data.unresolved_mark; + + program.visit_mut_with(&mut swc_sdk::swc_sdk( + unresolved_mark, + config, + PluginCommentsProxy, + )); + + program +} diff --git a/packages/swc-sdk/transform/Cargo.toml b/packages/swc-sdk/transform/Cargo.toml new file mode 100644 index 000000000..a799cf967 --- /dev/null +++ b/packages/swc-sdk/transform/Cargo.toml @@ -0,0 +1,28 @@ +[package] + +description = "AST transforms visitor for swc-sdk" + + +authors = { workspace = true } +edition = { workspace = true } +homepage = { workspace = true } +license = { workspace = true } +name = "swc_sdk" +repository = { workspace = true } +rust-version = { workspace = true } +version = "0.1.0" + + +[dependencies] +serde = { workspace = true, features = ["derive"] } +swc_atoms = { workspace = true } +swc_common = { workspace = true } +swc_ecma_ast = { workspace = true } +swc_ecma_utils = { workspace = true } +swc_ecma_visit = { workspace = true } + +[dev-dependencies] +swc_ecma_parser = { workspace = true } +swc_ecma_transforms_base = { workspace = true } +swc_ecma_transforms_testing = { workspace = true } +testing = { workspace = true } diff --git a/packages/swc-sdk/transform/src/import_analyzer.rs b/packages/swc-sdk/transform/src/import_analyzer.rs new file mode 100644 index 000000000..be4667100 --- /dev/null +++ b/packages/swc-sdk/transform/src/import_analyzer.rs @@ -0,0 +1,92 @@ +use swc_atoms::JsWord; +use swc_common::collections::{AHashMap, AHashSet}; +use swc_ecma_ast::*; +use swc_ecma_visit::{noop_visit_type, Visit, VisitWith}; + +#[derive(Debug, Default)] +pub(crate) struct ImportMap { + /// Map from module name to (module path, exported symbol) + imports: AHashMap, + + namespace_imports: AHashMap, + + imported_modules: AHashSet, +} + +impl ImportMap { + /// Returns true if `e` is an import of `orig_name` from `module`. + pub fn is_import(&self, e: &Expr, module: &str, orig_name: &str) -> bool { + match e { + Expr::Ident(i) => { + if let Some((i_src, i_sym)) = self.imports.get(&i.to_id()) { + i_src == module && i_sym == orig_name + } else { + false + } + } + + Expr::Member(MemberExpr { + obj: box Expr::Ident(obj), + prop: MemberProp::Ident(prop), + .. + }) => { + if let Some(obj_src) = self.namespace_imports.get(&obj.to_id()) { + obj_src == module && prop.sym == *orig_name + } else { + false + } + } + + _ => false, + } + } + + pub fn analyze(m: &Module) -> Self { + let mut data = ImportMap::default(); + + m.visit_with(&mut Analyzer { data: &mut data }); + + data + } +} + +struct Analyzer<'a> { + data: &'a mut ImportMap, +} + +impl Visit for Analyzer<'_> { + noop_visit_type!(); + + fn visit_import_decl(&mut self, import: &ImportDecl) { + self.data.imported_modules.insert(import.src.value.clone()); + + for s in &import.specifiers { + let (local, orig_sym) = match s { + ImportSpecifier::Named(ImportNamedSpecifier { + local, imported, .. + }) => match imported { + Some(imported) => (local.to_id(), orig_name(imported)), + _ => (local.to_id(), local.sym.clone()), + }, + ImportSpecifier::Default(s) => (s.local.to_id(), "default".into()), + ImportSpecifier::Namespace(s) => { + self.data + .namespace_imports + .insert(s.local.to_id(), import.src.value.clone()); + continue; + } + }; + + self.data + .imports + .insert(local, (import.src.value.clone(), orig_sym)); + } + } +} + +fn orig_name(n: &ModuleExportName) -> JsWord { + match n { + ModuleExportName::Ident(v) => v.sym.clone(), + ModuleExportName::Str(v) => v.value.clone(), + } +} diff --git a/packages/swc-sdk/transform/src/lib.rs b/packages/swc-sdk/transform/src/lib.rs new file mode 100644 index 000000000..f74203e04 --- /dev/null +++ b/packages/swc-sdk/transform/src/lib.rs @@ -0,0 +1,110 @@ +#![feature(box_patterns)] + +use import_analyzer::ImportMap; +use serde::Deserialize; +use swc_atoms::Atom; +use swc_common::{ + comments::Comments, errors::HANDLER, util::take::Take, Mark, Span, Spanned, DUMMY_SP, +}; +use swc_ecma_ast::{CallExpr, Callee, EmptyStmt, Expr, Module, ModuleDecl, ModuleItem, Stmt}; +use swc_ecma_visit::{VisitMut, VisitMutWith}; + +mod import_analyzer; + +#[derive(Debug, Clone, Deserialize)] +pub struct Config { + #[serde(default = "default_import_path")] + pub import_path: Atom, +} + +fn default_import_path() -> Atom { + Atom::from("@swc/sdk") +} + +impl Config {} + +pub fn swc_sdk(_unreolved_mark: Mark, config: Config, comments: C) -> impl VisitMut +where + C: Comments, +{ + Magic { + config, + comments, + imports: Default::default(), + } +} + +const MARK_AS_PURE_FN_NAME: &str = "markAsPure"; + +/// Handles functions from `@swc/sdk`. +struct Magic +where + C: Comments, +{ + config: Config, + comments: C, + imports: ImportMap, +} + +impl VisitMut for Magic +where + C: Comments, +{ + fn visit_mut_expr(&mut self, e: &mut Expr) { + e.visit_mut_children_with(self); + + if let Expr::Call(CallExpr { + span, + callee: Callee::Expr(callee), + args, + .. + }) = e + { + if !self + .imports + .is_import(callee, &self.config.import_path, MARK_AS_PURE_FN_NAME) + { + return; + } + + if args.len() != 1 { + HANDLER.with(|handler| { + handler + .struct_span_err(*span, "markAsPure() does not support multiple arguments") + .emit(); + }); + return; + } + + *e = *args[0].expr.take(); + + let mut lo = e.span().lo; + if lo.is_dummy() { + lo = Span::dummy_with_cmt().lo; + } + + self.comments.add_pure_comment(lo); + } + } + + fn visit_mut_module(&mut self, m: &mut Module) { + self.imports = ImportMap::analyze(m); + + m.visit_mut_children_with(self); + + // Remove Stmt::Empty + m.body + .retain(|item| !matches!(item, ModuleItem::Stmt(Stmt::Empty(..)))); + } + + fn visit_mut_module_item(&mut self, m: &mut ModuleItem) { + if let ModuleItem::ModuleDecl(ModuleDecl::Import(import)) = m { + if import.src.value == self.config.import_path { + *m = ModuleItem::Stmt(Stmt::Empty(EmptyStmt { span: DUMMY_SP })); + return; + } + } + + m.visit_mut_children_with(self); + } +} diff --git a/packages/swc-sdk/transform/tests/fixture.rs b/packages/swc-sdk/transform/tests/fixture.rs new file mode 100644 index 000000000..4862c65f1 --- /dev/null +++ b/packages/swc-sdk/transform/tests/fixture.rs @@ -0,0 +1,33 @@ +use std::path::PathBuf; + +use swc_common::{chain, Mark}; +use swc_ecma_parser::Syntax; +use swc_ecma_transforms_base::resolver; +use swc_ecma_transforms_testing::test_fixture; +use swc_ecma_visit::as_folder; + +#[testing::fixture("tests/fixture/**/input.js")] +fn pure(input: PathBuf) { + let output = input.parent().unwrap().join("output.js"); + test_fixture( + Syntax::default(), + &|tr| { + let unresolved_mark = Mark::new(); + let top_level_mark = Mark::new(); + + chain!( + resolver(unresolved_mark, top_level_mark, false), + as_folder(swc_sdk::swc_sdk( + unresolved_mark, + swc_sdk::Config { + import_path: "@swc/sdk".into() + }, + tr.comments.clone() + )) + ) + }, + &input, + &output, + Default::default(), + ); +} diff --git a/packages/swc-sdk/transform/tests/fixture/no-name-clash/input.js b/packages/swc-sdk/transform/tests/fixture/no-name-clash/input.js new file mode 100644 index 000000000..37982ab51 --- /dev/null +++ b/packages/swc-sdk/transform/tests/fixture/no-name-clash/input.js @@ -0,0 +1,3 @@ +import { markAsPure } from "not-swc-sdk"; + +markAsPure(console.log("test!")); diff --git a/packages/swc-sdk/transform/tests/fixture/no-name-clash/output.js b/packages/swc-sdk/transform/tests/fixture/no-name-clash/output.js new file mode 100644 index 000000000..ebe3a4e26 --- /dev/null +++ b/packages/swc-sdk/transform/tests/fixture/no-name-clash/output.js @@ -0,0 +1,2 @@ +import { markAsPure } from "not-swc-sdk"; +markAsPure(console.log("test!")); diff --git a/packages/swc-sdk/transform/tests/fixture/simple/input.js b/packages/swc-sdk/transform/tests/fixture/simple/input.js new file mode 100644 index 000000000..d99137384 --- /dev/null +++ b/packages/swc-sdk/transform/tests/fixture/simple/input.js @@ -0,0 +1,3 @@ +import { markAsPure } from "@swc/sdk"; + +markAsPure(console.log("test!")); diff --git a/packages/swc-sdk/transform/tests/fixture/simple/output.js b/packages/swc-sdk/transform/tests/fixture/simple/output.js new file mode 100644 index 000000000..b5bdc64a8 --- /dev/null +++ b/packages/swc-sdk/transform/tests/fixture/simple/output.js @@ -0,0 +1 @@ +/*#__PURE__*/ console.log("test!"); From 47b15824225fc0498931522120b609e51acf26fb Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=EA=B0=95=EB=8F=99=EC=9C=A4=20=28Donny=29?= Date: Thu, 19 Sep 2024 15:25:25 +0900 Subject: [PATCH 02/21] workspace --- Cargo.toml | 17 +---------------- 1 file changed, 1 insertion(+), 16 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index a4f882e03..707179707 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,20 +1,5 @@ [workspace] -members = [ - "xtask", - "packages/emotion", - "packages/jest", - "packages/loadable-components", - "packages/noop", - "packages/react-remove-properties", - "packages/relay", - "packages/remove-console", - "packages/styled-components", - "packages/styled-jsx", - "packages/swc-confidential", - "packages/swc-magic", - "packages/transform-imports", - "packages/prefresh", -] +members = ["xtask", "packages/*"] resolver = "2" From 8b9171a17dd2e588142160c724a57f7fc8d0d291 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=EA=B0=95=EB=8F=99=EC=9C=A4=20=28Donny=29?= Date: Thu, 19 Sep 2024 15:25:31 +0900 Subject: [PATCH 03/21] cargo lockfile --- Cargo.lock | 25 +++++++++++++++++++++++++ 1 file changed, 25 insertions(+) diff --git a/Cargo.lock b/Cargo.lock index b26a676d1..a9851da11 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -3131,6 +3131,15 @@ dependencies = [ "swc_magic", ] +[[package]] +name = "swc_plugin_swc_sdk" +version = "0.1.0" +dependencies = [ + "serde_json", + "swc_core", + "swc_sdk", +] + [[package]] name = "swc_plugin_transform_imports" version = "0.19.4" @@ -3180,6 +3189,22 @@ dependencies = [ "tracing", ] +[[package]] +name = "swc_sdk" +version = "0.1.0" +dependencies = [ + "serde", + "swc_atoms", + "swc_common", + "swc_ecma_ast", + "swc_ecma_parser", + "swc_ecma_transforms_base", + "swc_ecma_transforms_testing", + "swc_ecma_utils", + "swc_ecma_visit", + "testing", +] + [[package]] name = "swc_timer" version = "0.25.0" From 3305dce2ca7fe73d9aac12677281aef07520ac0d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=EA=B0=95=EB=8F=99=EC=9C=A4=20=28Donny=29?= Date: Thu, 19 Sep 2024 15:25:51 +0900 Subject: [PATCH 04/21] Rename --- packages/swc-sdk/transform/src/lib.rs | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/packages/swc-sdk/transform/src/lib.rs b/packages/swc-sdk/transform/src/lib.rs index f74203e04..1712228dd 100644 --- a/packages/swc-sdk/transform/src/lib.rs +++ b/packages/swc-sdk/transform/src/lib.rs @@ -27,7 +27,7 @@ pub fn swc_sdk(_unreolved_mark: Mark, config: Config, comments: C) -> impl Vi where C: Comments, { - Magic { + SwcSdkTransform { config, comments, imports: Default::default(), @@ -37,7 +37,7 @@ where const MARK_AS_PURE_FN_NAME: &str = "markAsPure"; /// Handles functions from `@swc/sdk`. -struct Magic +struct SwcSdkTransform where C: Comments, { @@ -46,7 +46,7 @@ where imports: ImportMap, } -impl VisitMut for Magic +impl VisitMut for SwcSdkTransform where C: Comments, { From 1e83d8fc3772f550e0d861118c022511c9a4658b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=EA=B0=95=EB=8F=99=EC=9C=A4=20=28Donny=29?= Date: Thu, 19 Sep 2024 15:28:15 +0900 Subject: [PATCH 05/21] env: Env --- packages/swc-sdk/transform/src/lib.rs | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/packages/swc-sdk/transform/src/lib.rs b/packages/swc-sdk/transform/src/lib.rs index 1712228dd..0537da9a8 100644 --- a/packages/swc-sdk/transform/src/lib.rs +++ b/packages/swc-sdk/transform/src/lib.rs @@ -17,17 +17,24 @@ pub struct Config { pub import_path: Atom, } +#[derive(Debug, Clone)] +pub struct Env { + pub unresolved_mark: Mark, + pub top_level_mark: Mark, +} + fn default_import_path() -> Atom { Atom::from("@swc/sdk") } impl Config {} -pub fn swc_sdk(_unreolved_mark: Mark, config: Config, comments: C) -> impl VisitMut +pub fn swc_sdk(env: Env, config: Config, comments: C) -> impl VisitMut where C: Comments, { SwcSdkTransform { + env, config, comments, imports: Default::default(), @@ -41,6 +48,7 @@ struct SwcSdkTransform where C: Comments, { + env: Env, config: Config, comments: C, imports: ImportMap, From 8917bf16878c058efeaf56f7866ec85c56c9622c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=EA=B0=95=EB=8F=99=EC=9C=A4=20=28Donny=29?= Date: Thu, 19 Sep 2024 15:33:43 +0900 Subject: [PATCH 06/21] Dep --- Cargo.toml | 1 + packages/swc-sdk/transform/Cargo.toml | 13 +++++++------ 2 files changed, 8 insertions(+), 6 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index 707179707..adcdddb38 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -22,6 +22,7 @@ cargo_metadata = "0.18.1" cipher = "0.4.4" clap = "4.5.4" convert_case = "0.6.0" +default-from-serde = "0.1" fxhash = "0.2.1" handlebars = "5.1.2" hex = "0.4.3" diff --git a/packages/swc-sdk/transform/Cargo.toml b/packages/swc-sdk/transform/Cargo.toml index a799cf967..67932112b 100644 --- a/packages/swc-sdk/transform/Cargo.toml +++ b/packages/swc-sdk/transform/Cargo.toml @@ -14,12 +14,13 @@ version = "0.1.0" [dependencies] -serde = { workspace = true, features = ["derive"] } -swc_atoms = { workspace = true } -swc_common = { workspace = true } -swc_ecma_ast = { workspace = true } -swc_ecma_utils = { workspace = true } -swc_ecma_visit = { workspace = true } +default-from-serde = { workspace = true } +serde = { workspace = true, features = ["derive"] } +swc_atoms = { workspace = true } +swc_common = { workspace = true } +swc_ecma_ast = { workspace = true } +swc_ecma_utils = { workspace = true } +swc_ecma_visit = { workspace = true } [dev-dependencies] swc_ecma_parser = { workspace = true } From c0e78e50fa129c4255ce93dd7dd17de6a6980566 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=EA=B0=95=EB=8F=99=EC=9C=A4=20=28Donny=29?= Date: Thu, 19 Sep 2024 15:33:49 +0900 Subject: [PATCH 07/21] cargo lockfile --- Cargo.lock | 22 ++++++++++++++++++++++ 1 file changed, 22 insertions(+) diff --git a/Cargo.lock b/Cargo.lock index a9851da11..b19608286 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -642,6 +642,27 @@ dependencies = [ "uuid", ] +[[package]] +name = "default-from-serde" +version = "0.1.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1c5155e51d19a68bb8bc3b1a1ec0d5aff5c24791343dc15fa051424316c267e7" +dependencies = [ + "derive-default-from-serde", + "serde", +] + +[[package]] +name = "derive-default-from-serde" +version = "0.1.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d87f19b90ebc996d8100cabf45b0b177772844c8a911533f55239a430a964f06" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.77", +] + [[package]] name = "derive_builder" version = "0.20.1" @@ -3193,6 +3214,7 @@ dependencies = [ name = "swc_sdk" version = "0.1.0" dependencies = [ + "default-from-serde", "serde", "swc_atoms", "swc_common", From 279a0dda87e1719c00d121b5f01c53b5c61860b5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=EA=B0=95=EB=8F=99=EC=9C=A4=20=28Donny=29?= Date: Thu, 19 Sep 2024 15:38:36 +0900 Subject: [PATCH 08/21] more config work --- packages/swc-sdk/transform/src/config.rs | 36 ++++++++++++++++++++++++ packages/swc-sdk/transform/src/lib.rs | 22 ++------------- 2 files changed, 39 insertions(+), 19 deletions(-) create mode 100644 packages/swc-sdk/transform/src/config.rs diff --git a/packages/swc-sdk/transform/src/config.rs b/packages/swc-sdk/transform/src/config.rs new file mode 100644 index 000000000..1977d6970 --- /dev/null +++ b/packages/swc-sdk/transform/src/config.rs @@ -0,0 +1,36 @@ +use default_from_serde::SerdeDefault; +use serde::Deserialize; +use swc_atoms::Atom; + +#[derive(Debug, Clone, Deserialize, SerdeDefault)] +pub struct Config { + #[serde(default)] + pub flag: FlagConfig, + + /// Drop imports from the following modules. + #[serde(default = "default_remove_imports_from")] + pub remove_imports_from: Vec, +} + +#[derive(Debug, Clone, Deserialize, SerdeDefault)] +pub struct FlagConfig { + #[serde(default = "default_flag_import_source")] + pub import_sources: Vec, +} + +#[derive(Debug, Clone, Deserialize)] +pub struct ImportItem { + pub module: Atom, + pub name: Atom, +} + +fn default_remove_imports_from() -> Vec { + vec![Atom::new("@swc/sdk/annotations")] +} + +fn default_flag_import_source() -> Vec { + vec![ImportItem { + module: Atom::new("@swc/sdk/flag"), + name: Atom::new("flag"), + }] +} diff --git a/packages/swc-sdk/transform/src/lib.rs b/packages/swc-sdk/transform/src/lib.rs index 0537da9a8..d72861b60 100644 --- a/packages/swc-sdk/transform/src/lib.rs +++ b/packages/swc-sdk/transform/src/lib.rs @@ -1,21 +1,15 @@ #![feature(box_patterns)] -use import_analyzer::ImportMap; -use serde::Deserialize; -use swc_atoms::Atom; use swc_common::{ comments::Comments, errors::HANDLER, util::take::Take, Mark, Span, Spanned, DUMMY_SP, }; use swc_ecma_ast::{CallExpr, Callee, EmptyStmt, Expr, Module, ModuleDecl, ModuleItem, Stmt}; use swc_ecma_visit::{VisitMut, VisitMutWith}; -mod import_analyzer; +use crate::{config::Config, import_analyzer::ImportMap}; -#[derive(Debug, Clone, Deserialize)] -pub struct Config { - #[serde(default = "default_import_path")] - pub import_path: Atom, -} +pub mod config; +mod import_analyzer; #[derive(Debug, Clone)] pub struct Env { @@ -23,12 +17,6 @@ pub struct Env { pub top_level_mark: Mark, } -fn default_import_path() -> Atom { - Atom::from("@swc/sdk") -} - -impl Config {} - pub fn swc_sdk(env: Env, config: Config, comments: C) -> impl VisitMut where C: Comments, @@ -99,10 +87,6 @@ where self.imports = ImportMap::analyze(m); m.visit_mut_children_with(self); - - // Remove Stmt::Empty - m.body - .retain(|item| !matches!(item, ModuleItem::Stmt(Stmt::Empty(..)))); } fn visit_mut_module_item(&mut self, m: &mut ModuleItem) { From c365e4046512bc6f34f56c6e375adb83f35ceee3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=EA=B0=95=EB=8F=99=EC=9C=A4=20=28Donny=29?= Date: Thu, 19 Sep 2024 15:41:59 +0900 Subject: [PATCH 09/21] flag.rs --- packages/swc-sdk/transform/src/flag.rs | 11 ++++++ packages/swc-sdk/transform/src/lib.rs | 50 +++++--------------------- 2 files changed, 19 insertions(+), 42 deletions(-) create mode 100644 packages/swc-sdk/transform/src/flag.rs diff --git a/packages/swc-sdk/transform/src/flag.rs b/packages/swc-sdk/transform/src/flag.rs new file mode 100644 index 000000000..e2a6d5f66 --- /dev/null +++ b/packages/swc-sdk/transform/src/flag.rs @@ -0,0 +1,11 @@ +use swc_common::comments::Comments; +use swc_ecma_ast::VarDeclarator; + +use crate::SwcSdkTransform; + +impl SwcSdkTransform +where + C: Comments, +{ + pub(super) fn transform_flag(&mut self, v: &mut VarDeclarator) {} +} diff --git a/packages/swc-sdk/transform/src/lib.rs b/packages/swc-sdk/transform/src/lib.rs index d72861b60..37c3be2d7 100644 --- a/packages/swc-sdk/transform/src/lib.rs +++ b/packages/swc-sdk/transform/src/lib.rs @@ -1,14 +1,13 @@ #![feature(box_patterns)] -use swc_common::{ - comments::Comments, errors::HANDLER, util::take::Take, Mark, Span, Spanned, DUMMY_SP, -}; -use swc_ecma_ast::{CallExpr, Callee, EmptyStmt, Expr, Module, ModuleDecl, ModuleItem, Stmt}; +use swc_common::{comments::Comments, util::take::Take, Mark}; +use swc_ecma_ast::{Module, ModuleDecl, ModuleItem, VarDeclarator}; use swc_ecma_visit::{VisitMut, VisitMutWith}; use crate::{config::Config, import_analyzer::ImportMap}; pub mod config; +mod flag; mod import_analyzer; #[derive(Debug, Clone)] @@ -29,8 +28,6 @@ where } } -const MARK_AS_PURE_FN_NAME: &str = "markAsPure"; - /// Handles functions from `@swc/sdk`. struct SwcSdkTransform where @@ -46,41 +43,10 @@ impl VisitMut for SwcSdkTransform where C: Comments, { - fn visit_mut_expr(&mut self, e: &mut Expr) { - e.visit_mut_children_with(self); - - if let Expr::Call(CallExpr { - span, - callee: Callee::Expr(callee), - args, - .. - }) = e - { - if !self - .imports - .is_import(callee, &self.config.import_path, MARK_AS_PURE_FN_NAME) - { - return; - } + fn visit_mut_var_declarator(&mut self, node: &mut VarDeclarator) { + self.transform_flag(node); - if args.len() != 1 { - HANDLER.with(|handler| { - handler - .struct_span_err(*span, "markAsPure() does not support multiple arguments") - .emit(); - }); - return; - } - - *e = *args[0].expr.take(); - - let mut lo = e.span().lo; - if lo.is_dummy() { - lo = Span::dummy_with_cmt().lo; - } - - self.comments.add_pure_comment(lo); - } + node.visit_mut_children_with(self); } fn visit_mut_module(&mut self, m: &mut Module) { @@ -91,8 +57,8 @@ where fn visit_mut_module_item(&mut self, m: &mut ModuleItem) { if let ModuleItem::ModuleDecl(ModuleDecl::Import(import)) = m { - if import.src.value == self.config.import_path { - *m = ModuleItem::Stmt(Stmt::Empty(EmptyStmt { span: DUMMY_SP })); + if self.config.remove_imports_from.contains(&import.src.value) { + m.take(); return; } } From 0da89068b59b24da2d219ba1d83ae63b2eae32c9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=EA=B0=95=EB=8F=99=EC=9C=A4=20=28Donny=29?= Date: Thu, 19 Sep 2024 15:45:18 +0900 Subject: [PATCH 10/21] is_flag_call --- packages/swc-sdk/transform/src/flag.rs | 11 ++++++++++- packages/swc-sdk/transform/src/import_analyzer.rs | 8 ++++++++ 2 files changed, 18 insertions(+), 1 deletion(-) diff --git a/packages/swc-sdk/transform/src/flag.rs b/packages/swc-sdk/transform/src/flag.rs index e2a6d5f66..b43a45f43 100644 --- a/packages/swc-sdk/transform/src/flag.rs +++ b/packages/swc-sdk/transform/src/flag.rs @@ -7,5 +7,14 @@ impl SwcSdkTransform where C: Comments, { - pub(super) fn transform_flag(&mut self, v: &mut VarDeclarator) {} + pub(super) fn transform_flag(&mut self, v: &mut VarDeclarator) { + let is_flag_call = v.init.as_deref().map_or(false, |e| { + self.imports + .is_in_import_items(e, &self.config.flag.import_sources) + }); + + if !is_flag_call { + return; + } + } } diff --git a/packages/swc-sdk/transform/src/import_analyzer.rs b/packages/swc-sdk/transform/src/import_analyzer.rs index be4667100..5333f92e2 100644 --- a/packages/swc-sdk/transform/src/import_analyzer.rs +++ b/packages/swc-sdk/transform/src/import_analyzer.rs @@ -3,6 +3,8 @@ use swc_common::collections::{AHashMap, AHashSet}; use swc_ecma_ast::*; use swc_ecma_visit::{noop_visit_type, Visit, VisitWith}; +use crate::config::ImportItem; + #[derive(Debug, Default)] pub(crate) struct ImportMap { /// Map from module name to (module path, exported symbol) @@ -41,6 +43,12 @@ impl ImportMap { } } + pub fn is_in_import_items(&self, e: &Expr, import_items: &[ImportItem]) -> bool { + import_items + .iter() + .any(|item| self.is_import(e, &item.module, &item.name)) + } + pub fn analyze(m: &Module) -> Self { let mut data = ImportMap::default(); From a4a6f4082a1645fedf675ad2558d2435c01539fc Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=EA=B0=95=EB=8F=99=EC=9C=A4=20=28Donny=29?= Date: Thu, 19 Sep 2024 15:46:03 +0900 Subject: [PATCH 11/21] Optimize --- packages/swc-sdk/transform/src/import_analyzer.rs | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/packages/swc-sdk/transform/src/import_analyzer.rs b/packages/swc-sdk/transform/src/import_analyzer.rs index 5333f92e2..64b4706e2 100644 --- a/packages/swc-sdk/transform/src/import_analyzer.rs +++ b/packages/swc-sdk/transform/src/import_analyzer.rs @@ -1,4 +1,4 @@ -use swc_atoms::JsWord; +use swc_atoms::Atom; use swc_common::collections::{AHashMap, AHashSet}; use swc_ecma_ast::*; use swc_ecma_visit::{noop_visit_type, Visit, VisitWith}; @@ -8,16 +8,16 @@ use crate::config::ImportItem; #[derive(Debug, Default)] pub(crate) struct ImportMap { /// Map from module name to (module path, exported symbol) - imports: AHashMap, + imports: AHashMap, - namespace_imports: AHashMap, + namespace_imports: AHashMap, - imported_modules: AHashSet, + imported_modules: AHashSet, } impl ImportMap { /// Returns true if `e` is an import of `orig_name` from `module`. - pub fn is_import(&self, e: &Expr, module: &str, orig_name: &str) -> bool { + pub fn is_import(&self, e: &Expr, module: &Atom, orig_name: &Atom) -> bool { match e { Expr::Ident(i) => { if let Some((i_src, i_sym)) = self.imports.get(&i.to_id()) { @@ -92,7 +92,7 @@ impl Visit for Analyzer<'_> { } } -fn orig_name(n: &ModuleExportName) -> JsWord { +fn orig_name(n: &ModuleExportName) -> Atom { match n { ModuleExportName::Ident(v) => v.sym.clone(), ModuleExportName::Str(v) => v.value.clone(), From f00c4c1c8d8957c560cdf3ca3d046d3ff7426ee6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=EA=B0=95=EB=8F=99=EC=9C=A4=20=28Donny=29?= Date: Thu, 19 Sep 2024 15:49:34 +0900 Subject: [PATCH 12/21] doc --- packages/swc-sdk/transform/src/flag.rs | 64 ++++++++++++++++++++++++++ 1 file changed, 64 insertions(+) diff --git a/packages/swc-sdk/transform/src/flag.rs b/packages/swc-sdk/transform/src/flag.rs index b43a45f43..35d483963 100644 --- a/packages/swc-sdk/transform/src/flag.rs +++ b/packages/swc-sdk/transform/src/flag.rs @@ -7,6 +7,70 @@ impl SwcSdkTransform where C: Comments, { + /// + /// ## Cases + /// + /// ### Empty arugments + /// + /// ```js + /// + /// import { flag } from "@swc/sdk/flag"; + /// + /// const foo = flag(); + /// ``` + /// + /// becomes + /// + /// ```js + /// import { flag } from "@swc/sdk/flag"; + /// + /// const foo = flag({ + /// key: "foo", + /// }); + /// ``` + /// + /// ### With arguments + /// + /// ```js + /// import { flag } from "@swc/sdk/flag"; + /// + /// const foo = flag({ + /// decide: () => false, + /// }); + /// ``` + /// + /// becomes + /// + /// ```js + /// import { flag } from "@swc/sdk/flag"; + /// + /// const foo = flag({ + /// key: "foo", + /// decide: () => false, + /// }); + /// ``` + /// + /// ### With custom adapter + /// + /// + /// ```js + /// import { flag } from "@swc/sdk/flag"; + /// + /// const foo = flag(someAdapter({ + /// decide: () => false, + /// }); + /// ``` + /// + /// becomes + /// + /// ```js + /// import { flag } from "@swc/sdk/flag"; + /// + /// const foo = flag(someAdapter({ + /// key: "foo", + /// decide: () => false, + /// })); + /// ``` pub(super) fn transform_flag(&mut self, v: &mut VarDeclarator) { let is_flag_call = v.init.as_deref().map_or(false, |e| { self.imports From a9b5eb1488afb9c157cac26c04bed20bdfa67de9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=EA=B0=95=EB=8F=99=EC=9C=A4=20=28Donny=29?= Date: Thu, 19 Sep 2024 15:53:20 +0900 Subject: [PATCH 13/21] never type --- packages/swc-sdk/transform/src/config.rs | 5 ++++ packages/swc-sdk/transform/src/flag.rs | 31 ++++++++++++++++++------ packages/swc-sdk/transform/src/lib.rs | 1 + 3 files changed, 29 insertions(+), 8 deletions(-) diff --git a/packages/swc-sdk/transform/src/config.rs b/packages/swc-sdk/transform/src/config.rs index 1977d6970..f5e1116b4 100644 --- a/packages/swc-sdk/transform/src/config.rs +++ b/packages/swc-sdk/transform/src/config.rs @@ -14,6 +14,11 @@ pub struct Config { #[derive(Debug, Clone, Deserialize, SerdeDefault)] pub struct FlagConfig { + /// If true, + /// + /// - the variable name must be an identifier. + pub strict: bool, + #[serde(default = "default_flag_import_source")] pub import_sources: Vec, } diff --git a/packages/swc-sdk/transform/src/flag.rs b/packages/swc-sdk/transform/src/flag.rs index 35d483963..fd20d0bed 100644 --- a/packages/swc-sdk/transform/src/flag.rs +++ b/packages/swc-sdk/transform/src/flag.rs @@ -1,5 +1,5 @@ -use swc_common::comments::Comments; -use swc_ecma_ast::VarDeclarator; +use swc_common::{comments::Comments, errors::HANDLER, Spanned}; +use swc_ecma_ast::{Pat, VarDeclarator}; use crate::SwcSdkTransform; @@ -71,14 +71,29 @@ where /// decide: () => false, /// })); /// ``` - pub(super) fn transform_flag(&mut self, v: &mut VarDeclarator) { - let is_flag_call = v.init.as_deref().map_or(false, |e| { - self.imports - .is_in_import_items(e, &self.config.flag.import_sources) - }); + pub(super) fn transform_flag(&mut self, v: &mut VarDeclarator) -> Option { + let init = v.init.as_deref()?; + let is_flag_call = self + .imports + .is_in_import_items(init, &self.config.flag.import_sources); if !is_flag_call { - return; + return None; } + + let name = match &v.name { + Pat::Ident(i) => i.clone(), + _ => { + if self.config.flag.strict { + HANDLER.with(|handler| { + handler.struct_span_err( + v.name.span(), + "The variable name for the `flag()` calls must be an identifier", + ) + }); + } + return None; + } + }; } } diff --git a/packages/swc-sdk/transform/src/lib.rs b/packages/swc-sdk/transform/src/lib.rs index 37c3be2d7..a37cb2cba 100644 --- a/packages/swc-sdk/transform/src/lib.rs +++ b/packages/swc-sdk/transform/src/lib.rs @@ -1,4 +1,5 @@ #![feature(box_patterns)] +#![feature(never_type)] use swc_common::{comments::Comments, util::take::Take, Mark}; use swc_ecma_ast::{Module, ModuleDecl, ModuleItem, VarDeclarator}; From 2b7de89ebc714b828c745ee64dee5e10849f1264 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=EA=B0=95=EB=8F=99=EC=9C=A4=20=28Donny=29?= Date: Thu, 19 Sep 2024 15:53:47 +0900 Subject: [PATCH 14/21] default --- packages/swc-sdk/transform/src/config.rs | 1 + 1 file changed, 1 insertion(+) diff --git a/packages/swc-sdk/transform/src/config.rs b/packages/swc-sdk/transform/src/config.rs index f5e1116b4..cda3d4aad 100644 --- a/packages/swc-sdk/transform/src/config.rs +++ b/packages/swc-sdk/transform/src/config.rs @@ -17,6 +17,7 @@ pub struct FlagConfig { /// If true, /// /// - the variable name must be an identifier. + #[serde(default)] pub strict: bool, #[serde(default = "default_flag_import_source")] From d609ed7d65d28c794a8ee2d29c10080406303eee Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=EA=B0=95=EB=8F=99=EC=9C=A4=20=28Donny=29?= Date: Thu, 19 Sep 2024 16:27:32 +0900 Subject: [PATCH 15/21] transform_flag --- packages/swc-sdk/transform/src/flag.rs | 19 ++++----- .../swc-sdk/transform/src/import_analyzer.rs | 39 ++++++++++++------- 2 files changed, 35 insertions(+), 23 deletions(-) diff --git a/packages/swc-sdk/transform/src/flag.rs b/packages/swc-sdk/transform/src/flag.rs index fd20d0bed..9482764a3 100644 --- a/packages/swc-sdk/transform/src/flag.rs +++ b/packages/swc-sdk/transform/src/flag.rs @@ -75,25 +75,26 @@ where let init = v.init.as_deref()?; let is_flag_call = self .imports - .is_in_import_items(init, &self.config.flag.import_sources); - - if !is_flag_call { - return None; - } + .is_in_import_items(init, &self.config.flag.import_sources)?; let name = match &v.name { Pat::Ident(i) => i.clone(), _ => { if self.config.flag.strict { HANDLER.with(|handler| { - handler.struct_span_err( - v.name.span(), - "The variable name for the `flag()` calls must be an identifier", - ) + handler + .struct_span_err( + v.name.span(), + "The variable name for the `flag()` calls must be an identifier", + ) + .span_note(is_flag_call, "flag() is imported here") + .emit(); }); } return None; } }; + + None } } diff --git a/packages/swc-sdk/transform/src/import_analyzer.rs b/packages/swc-sdk/transform/src/import_analyzer.rs index 64b4706e2..c3d69fc74 100644 --- a/packages/swc-sdk/transform/src/import_analyzer.rs +++ b/packages/swc-sdk/transform/src/import_analyzer.rs @@ -1,5 +1,8 @@ use swc_atoms::Atom; -use swc_common::collections::{AHashMap, AHashSet}; +use swc_common::{ + collections::{AHashMap, AHashSet}, + Span, +}; use swc_ecma_ast::*; use swc_ecma_visit::{noop_visit_type, Visit, VisitWith}; @@ -7,23 +10,27 @@ use crate::config::ImportItem; #[derive(Debug, Default)] pub(crate) struct ImportMap { - /// Map from module name to (module path, exported symbol) - imports: AHashMap, + /// Map from module name to (module path, exported symbol, span) + imports: AHashMap, - namespace_imports: AHashMap, + namespace_imports: AHashMap, imported_modules: AHashSet, } impl ImportMap { /// Returns true if `e` is an import of `orig_name` from `module`. - pub fn is_import(&self, e: &Expr, module: &Atom, orig_name: &Atom) -> bool { + pub fn is_import(&self, e: &Expr, module: &Atom, orig_name: &Atom) -> Option { match e { Expr::Ident(i) => { - if let Some((i_src, i_sym)) = self.imports.get(&i.to_id()) { - i_src == module && i_sym == orig_name + if let Some((i_src, i_sym, i_span)) = self.imports.get(&i.to_id()) { + if i_src == module && i_sym == orig_name { + Some(*i_span) + } else { + None + } } else { - false + None } } @@ -32,21 +39,25 @@ impl ImportMap { prop: MemberProp::Ident(prop), .. }) => { - if let Some(obj_src) = self.namespace_imports.get(&obj.to_id()) { - obj_src == module && prop.sym == *orig_name + if let Some((obj_src, obj_span)) = self.namespace_imports.get(&obj.to_id()) { + if obj_src == module && prop.sym == *orig_name { + Some(*obj_span) + } else { + None + } } else { - false + None } } - _ => false, + _ => None, } } - pub fn is_in_import_items(&self, e: &Expr, import_items: &[ImportItem]) -> bool { + pub fn is_in_import_items(&self, e: &Expr, import_items: &[ImportItem]) -> Option { import_items .iter() - .any(|item| self.is_import(e, &item.module, &item.name)) + .find_map(|item| self.is_import(e, &item.module, &item.name)) } pub fn analyze(m: &Module) -> Self { From 8c269bc7e50006c91019c0f2ff997b1deca22f67 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=EA=B0=95=EB=8F=99=EC=9C=A4=20=28Donny=29?= Date: Thu, 19 Sep 2024 16:37:11 +0900 Subject: [PATCH 16/21] fix --- packages/swc-sdk/transform/src/flag.rs | 54 +++++++++++++++++-- .../swc-sdk/transform/src/import_analyzer.rs | 4 +- 2 files changed, 51 insertions(+), 7 deletions(-) diff --git a/packages/swc-sdk/transform/src/flag.rs b/packages/swc-sdk/transform/src/flag.rs index 9482764a3..862c1c244 100644 --- a/packages/swc-sdk/transform/src/flag.rs +++ b/packages/swc-sdk/transform/src/flag.rs @@ -1,5 +1,8 @@ use swc_common::{comments::Comments, errors::HANDLER, Spanned}; -use swc_ecma_ast::{Pat, VarDeclarator}; +use swc_ecma_ast::{ + Expr, KeyValueProp, ObjectLit, Pat, Prop, PropName, PropOrSpread, VarDeclarator, +}; +use swc_ecma_utils::ExprFactory; use crate::SwcSdkTransform; @@ -72,10 +75,14 @@ where /// })); /// ``` pub(super) fn transform_flag(&mut self, v: &mut VarDeclarator) -> Option { - let init = v.init.as_deref()?; - let is_flag_call = self + let init = v.init.as_deref_mut()?; + let call_expr = init.as_mut_call()?; + + let callee = call_expr.callee.as_mut_expr()?; + + let import_of_flag_callee = self .imports - .is_in_import_items(init, &self.config.flag.import_sources)?; + .is_in_import_items(callee, &self.config.flag.import_sources)?; let name = match &v.name { Pat::Ident(i) => i.clone(), @@ -87,7 +94,7 @@ where v.name.span(), "The variable name for the `flag()` calls must be an identifier", ) - .span_note(is_flag_call, "flag() is imported here") + .span_note(import_of_flag_callee, "flag() is imported here") .emit(); }); } @@ -95,6 +102,43 @@ where } }; + let prop = PropOrSpread::Prop(Box::new(Prop::KeyValue(KeyValueProp { + key: PropName::Str("key".into()), + value: name.sym.clone().into(), + }))); + + if call_expr.args.is_empty() { + call_expr.args.push( + ObjectLit { + props: vec![prop], + ..Default::default() + } + .as_arg(), + ); + } else if let Some(obj) = find_object(&mut call_expr.args[0].expr) { + obj.props.push(prop); + } + None } } + +fn find_object(arg: &mut Expr) -> Option<&mut ObjectLit> { + match arg { + Expr::Object(obj) => Some(obj), + Expr::Call(call) => { + if call.args.is_empty() { + call.args.push( + ObjectLit { + ..Default::default() + } + .as_arg(), + ); + } + + let arg = call.args.get_mut(0)?; + find_object(&mut arg.expr) + } + _ => None, + } +} diff --git a/packages/swc-sdk/transform/src/import_analyzer.rs b/packages/swc-sdk/transform/src/import_analyzer.rs index c3d69fc74..21b3dcdba 100644 --- a/packages/swc-sdk/transform/src/import_analyzer.rs +++ b/packages/swc-sdk/transform/src/import_analyzer.rs @@ -91,14 +91,14 @@ impl Visit for Analyzer<'_> { ImportSpecifier::Namespace(s) => { self.data .namespace_imports - .insert(s.local.to_id(), import.src.value.clone()); + .insert(s.local.to_id(), (import.src.value.clone(), s.local.span)); continue; } }; self.data .imports - .insert(local, (import.src.value.clone(), orig_sym)); + .insert(local, (import.src.value.clone(), orig_sym, import.span)); } } } From 6e5097d37d41ad4bb02de896fad79dcb19415d5e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=EA=B0=95=EB=8F=99=EC=9C=A4=20=28Donny=29?= Date: Thu, 19 Sep 2024 16:39:22 +0900 Subject: [PATCH 17/21] fix --- packages/swc-sdk/src/lib.rs | 4 ++-- packages/swc-sdk/transform/src/lib.rs | 3 ++- packages/swc-sdk/transform/tests/fixture.rs | 6 ++---- 3 files changed, 6 insertions(+), 7 deletions(-) diff --git a/packages/swc-sdk/src/lib.rs b/packages/swc-sdk/src/lib.rs index 7b874456e..91ffe8d89 100644 --- a/packages/swc-sdk/src/lib.rs +++ b/packages/swc-sdk/src/lib.rs @@ -11,7 +11,7 @@ use swc_core::{ #[plugin_transform] fn swc_sdk_plugin(mut program: Program, data: TransformPluginProgramMetadata) -> Program { - let config = serde_json::from_str::( + let config = serde_json::from_str::( &data .get_transform_plugin_config() .expect("failed to get plugin config for swc-sdk"), @@ -21,7 +21,7 @@ fn swc_sdk_plugin(mut program: Program, data: TransformPluginProgramMetadata) -> let unresolved_mark = data.unresolved_mark; program.visit_mut_with(&mut swc_sdk::swc_sdk( - unresolved_mark, + swc_sdk::Env { unresolved_mark }, config, PluginCommentsProxy, )); diff --git a/packages/swc-sdk/transform/src/lib.rs b/packages/swc-sdk/transform/src/lib.rs index a37cb2cba..86fe41725 100644 --- a/packages/swc-sdk/transform/src/lib.rs +++ b/packages/swc-sdk/transform/src/lib.rs @@ -14,7 +14,6 @@ mod import_analyzer; #[derive(Debug, Clone)] pub struct Env { pub unresolved_mark: Mark, - pub top_level_mark: Mark, } pub fn swc_sdk(env: Env, config: Config, comments: C) -> impl VisitMut @@ -34,8 +33,10 @@ struct SwcSdkTransform where C: Comments, { + #[allow(unused)] env: Env, config: Config, + #[allow(unused)] comments: C, imports: ImportMap, } diff --git a/packages/swc-sdk/transform/tests/fixture.rs b/packages/swc-sdk/transform/tests/fixture.rs index 4862c65f1..d89b476b6 100644 --- a/packages/swc-sdk/transform/tests/fixture.rs +++ b/packages/swc-sdk/transform/tests/fixture.rs @@ -18,10 +18,8 @@ fn pure(input: PathBuf) { chain!( resolver(unresolved_mark, top_level_mark, false), as_folder(swc_sdk::swc_sdk( - unresolved_mark, - swc_sdk::Config { - import_path: "@swc/sdk".into() - }, + swc_sdk::Env { unresolved_mark }, + swc_sdk::config::Config::default(), tr.comments.clone() )) ) From bb53e6b91606b90729595ebaa82f46d40761325a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=EA=B0=95=EB=8F=99=EC=9C=A4=20=28Donny=29?= Date: Thu, 19 Sep 2024 16:45:18 +0900 Subject: [PATCH 18/21] Add tests --- .../swc-sdk/transform/tests/fixture/flag/arg-1/input.js | 7 +++++++ .../transform/tests/fixture/flag/custom-adapter/input.js | 7 +++++++ .../swc-sdk/transform/tests/fixture/flag/no-arg/input.js | 7 +++++++ .../swc-sdk/transform/tests/fixture/no-name-clash/input.js | 3 --- .../transform/tests/fixture/no-name-clash/output.js | 2 -- packages/swc-sdk/transform/tests/fixture/simple/input.js | 3 --- packages/swc-sdk/transform/tests/fixture/simple/output.js | 1 - 7 files changed, 21 insertions(+), 9 deletions(-) create mode 100644 packages/swc-sdk/transform/tests/fixture/flag/arg-1/input.js create mode 100644 packages/swc-sdk/transform/tests/fixture/flag/custom-adapter/input.js create mode 100644 packages/swc-sdk/transform/tests/fixture/flag/no-arg/input.js delete mode 100644 packages/swc-sdk/transform/tests/fixture/no-name-clash/input.js delete mode 100644 packages/swc-sdk/transform/tests/fixture/no-name-clash/output.js delete mode 100644 packages/swc-sdk/transform/tests/fixture/simple/input.js delete mode 100644 packages/swc-sdk/transform/tests/fixture/simple/output.js diff --git a/packages/swc-sdk/transform/tests/fixture/flag/arg-1/input.js b/packages/swc-sdk/transform/tests/fixture/flag/arg-1/input.js new file mode 100644 index 000000000..3f8ee128c --- /dev/null +++ b/packages/swc-sdk/transform/tests/fixture/flag/arg-1/input.js @@ -0,0 +1,7 @@ +import { flag } from "@swc/sdk/flag"; + +const foo = flag({ + decide: () => false, +}); + +console.log(foo); \ No newline at end of file diff --git a/packages/swc-sdk/transform/tests/fixture/flag/custom-adapter/input.js b/packages/swc-sdk/transform/tests/fixture/flag/custom-adapter/input.js new file mode 100644 index 000000000..3f8ee128c --- /dev/null +++ b/packages/swc-sdk/transform/tests/fixture/flag/custom-adapter/input.js @@ -0,0 +1,7 @@ +import { flag } from "@swc/sdk/flag"; + +const foo = flag({ + decide: () => false, +}); + +console.log(foo); \ No newline at end of file diff --git a/packages/swc-sdk/transform/tests/fixture/flag/no-arg/input.js b/packages/swc-sdk/transform/tests/fixture/flag/no-arg/input.js new file mode 100644 index 000000000..3f8ee128c --- /dev/null +++ b/packages/swc-sdk/transform/tests/fixture/flag/no-arg/input.js @@ -0,0 +1,7 @@ +import { flag } from "@swc/sdk/flag"; + +const foo = flag({ + decide: () => false, +}); + +console.log(foo); \ No newline at end of file diff --git a/packages/swc-sdk/transform/tests/fixture/no-name-clash/input.js b/packages/swc-sdk/transform/tests/fixture/no-name-clash/input.js deleted file mode 100644 index 37982ab51..000000000 --- a/packages/swc-sdk/transform/tests/fixture/no-name-clash/input.js +++ /dev/null @@ -1,3 +0,0 @@ -import { markAsPure } from "not-swc-sdk"; - -markAsPure(console.log("test!")); diff --git a/packages/swc-sdk/transform/tests/fixture/no-name-clash/output.js b/packages/swc-sdk/transform/tests/fixture/no-name-clash/output.js deleted file mode 100644 index ebe3a4e26..000000000 --- a/packages/swc-sdk/transform/tests/fixture/no-name-clash/output.js +++ /dev/null @@ -1,2 +0,0 @@ -import { markAsPure } from "not-swc-sdk"; -markAsPure(console.log("test!")); diff --git a/packages/swc-sdk/transform/tests/fixture/simple/input.js b/packages/swc-sdk/transform/tests/fixture/simple/input.js deleted file mode 100644 index d99137384..000000000 --- a/packages/swc-sdk/transform/tests/fixture/simple/input.js +++ /dev/null @@ -1,3 +0,0 @@ -import { markAsPure } from "@swc/sdk"; - -markAsPure(console.log("test!")); diff --git a/packages/swc-sdk/transform/tests/fixture/simple/output.js b/packages/swc-sdk/transform/tests/fixture/simple/output.js deleted file mode 100644 index b5bdc64a8..000000000 --- a/packages/swc-sdk/transform/tests/fixture/simple/output.js +++ /dev/null @@ -1 +0,0 @@ -/*#__PURE__*/ console.log("test!"); From 5192a86fa8e73476274b1fa687573d00f56750ab Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=EA=B0=95=EB=8F=99=EC=9C=A4=20=28Donny=29?= Date: Thu, 19 Sep 2024 16:52:41 +0900 Subject: [PATCH 19/21] ident --- packages/swc-sdk/transform/src/flag.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/swc-sdk/transform/src/flag.rs b/packages/swc-sdk/transform/src/flag.rs index 862c1c244..a8e383be8 100644 --- a/packages/swc-sdk/transform/src/flag.rs +++ b/packages/swc-sdk/transform/src/flag.rs @@ -103,7 +103,7 @@ where }; let prop = PropOrSpread::Prop(Box::new(Prop::KeyValue(KeyValueProp { - key: PropName::Str("key".into()), + key: PropName::Ident("key".into()), value: name.sym.clone().into(), }))); From 0092c6fd4cfa620387fb28566a5ba05978d7a9ee Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=EA=B0=95=EB=8F=99=EC=9C=A4=20=28Donny=29?= Date: Thu, 19 Sep 2024 16:54:20 +0900 Subject: [PATCH 20/21] duplicate --- packages/swc-sdk/transform/src/flag.rs | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/packages/swc-sdk/transform/src/flag.rs b/packages/swc-sdk/transform/src/flag.rs index a8e383be8..02309ea82 100644 --- a/packages/swc-sdk/transform/src/flag.rs +++ b/packages/swc-sdk/transform/src/flag.rs @@ -116,6 +116,20 @@ where .as_arg(), ); } else if let Some(obj) = find_object(&mut call_expr.args[0].expr) { + if obj + .props + .iter() + .filter_map(|p| p.as_prop()) + .any(|p| match &**p { + Prop::KeyValue(KeyValueProp { key, .. }) => { + matches!(key, PropName::Ident(i) if i.sym == "key") + } + _ => false, + }) + { + return None; + } + obj.props.push(prop); } From 727b3bc4766c9d9fd6462762360fd386effc661c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=EA=B0=95=EB=8F=99=EC=9C=A4=20=28Donny=29?= Date: Thu, 19 Sep 2024 16:54:49 +0900 Subject: [PATCH 21/21] Update test refs --- .../swc-sdk/transform/tests/fixture/flag/arg-1/output.js | 6 ++++++ .../transform/tests/fixture/flag/custom-adapter/output.js | 6 ++++++ .../transform/tests/fixture/flag/duplicate/input.js | 8 ++++++++ .../transform/tests/fixture/flag/duplicate/output.js | 6 ++++++ .../swc-sdk/transform/tests/fixture/flag/no-arg/output.js | 6 ++++++ 5 files changed, 32 insertions(+) create mode 100644 packages/swc-sdk/transform/tests/fixture/flag/arg-1/output.js create mode 100644 packages/swc-sdk/transform/tests/fixture/flag/custom-adapter/output.js create mode 100644 packages/swc-sdk/transform/tests/fixture/flag/duplicate/input.js create mode 100644 packages/swc-sdk/transform/tests/fixture/flag/duplicate/output.js create mode 100644 packages/swc-sdk/transform/tests/fixture/flag/no-arg/output.js diff --git a/packages/swc-sdk/transform/tests/fixture/flag/arg-1/output.js b/packages/swc-sdk/transform/tests/fixture/flag/arg-1/output.js new file mode 100644 index 000000000..c638dbc70 --- /dev/null +++ b/packages/swc-sdk/transform/tests/fixture/flag/arg-1/output.js @@ -0,0 +1,6 @@ +import { flag } from "@swc/sdk/flag"; +const foo = flag({ + decide: ()=>false, + key: "foo" +}); +console.log(foo); diff --git a/packages/swc-sdk/transform/tests/fixture/flag/custom-adapter/output.js b/packages/swc-sdk/transform/tests/fixture/flag/custom-adapter/output.js new file mode 100644 index 000000000..c638dbc70 --- /dev/null +++ b/packages/swc-sdk/transform/tests/fixture/flag/custom-adapter/output.js @@ -0,0 +1,6 @@ +import { flag } from "@swc/sdk/flag"; +const foo = flag({ + decide: ()=>false, + key: "foo" +}); +console.log(foo); diff --git a/packages/swc-sdk/transform/tests/fixture/flag/duplicate/input.js b/packages/swc-sdk/transform/tests/fixture/flag/duplicate/input.js new file mode 100644 index 000000000..49355de27 --- /dev/null +++ b/packages/swc-sdk/transform/tests/fixture/flag/duplicate/input.js @@ -0,0 +1,8 @@ +import { flag } from "@swc/sdk/flag"; + +const foo = flag({ + decide: () => false, + key: 'custom' +}); + +console.log(foo); \ No newline at end of file diff --git a/packages/swc-sdk/transform/tests/fixture/flag/duplicate/output.js b/packages/swc-sdk/transform/tests/fixture/flag/duplicate/output.js new file mode 100644 index 000000000..588adc579 --- /dev/null +++ b/packages/swc-sdk/transform/tests/fixture/flag/duplicate/output.js @@ -0,0 +1,6 @@ +import { flag } from "@swc/sdk/flag"; +const foo = flag({ + decide: ()=>false, + key: 'custom' +}); +console.log(foo); diff --git a/packages/swc-sdk/transform/tests/fixture/flag/no-arg/output.js b/packages/swc-sdk/transform/tests/fixture/flag/no-arg/output.js new file mode 100644 index 000000000..c638dbc70 --- /dev/null +++ b/packages/swc-sdk/transform/tests/fixture/flag/no-arg/output.js @@ -0,0 +1,6 @@ +import { flag } from "@swc/sdk/flag"; +const foo = flag({ + decide: ()=>false, + key: "foo" +}); +console.log(foo);