@swc-contrib/mut-cjs-exports 10.7.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +21 -0
- package/README.md +120 -0
- package/package.json +42 -0
- package/src/lib.rs +325 -0
- package/src/local_export_strip.rs +362 -0
- package/src/utils.rs +143 -0
- package/swc_mut_cjs_exports.wasm +0 -0
package/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) magic-akari
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
package/README.md
ADDED
|
@@ -0,0 +1,120 @@
|
|
|
1
|
+
# [SWC plugin] mutable CJS exports
|
|
2
|
+
|
|
3
|
+
Migrated from https://github.com/magic-akari/swc_mut_cjs_exports
|
|
4
|
+
|
|
5
|
+
This is a SWC plugin to emit mutable CJS exports.
|
|
6
|
+
|
|
7
|
+
This SWC plugin has only been tested for compatibility with jest. It should be used with `@swc/jest`.
|
|
8
|
+
|
|
9
|
+
This project was previously called jest_workaround
|
|
10
|
+
|
|
11
|
+
## plugin version
|
|
12
|
+
|
|
13
|
+
https://swc.rs/docs/plugin/selecting-swc-core
|
|
14
|
+
|
|
15
|
+
## usage
|
|
16
|
+
|
|
17
|
+
install
|
|
18
|
+
|
|
19
|
+
```bash
|
|
20
|
+
npm i -D jest @swc/core @swc/jest @swc-contrib/mut-cjs-exports
|
|
21
|
+
```
|
|
22
|
+
|
|
23
|
+
```js
|
|
24
|
+
// jest.config.js
|
|
25
|
+
const fs = require("node:fs");
|
|
26
|
+
|
|
27
|
+
const swcrc = JSON.parse(fs.readFileSync(".swcrc", "utf8"));
|
|
28
|
+
|
|
29
|
+
// If you have other plugins, change this line.
|
|
30
|
+
((swcrc.jsc ??= {}).experimental ??= {}).plugins = [
|
|
31
|
+
["@swc-contrib/mut-cjs-exports", {}],
|
|
32
|
+
];
|
|
33
|
+
|
|
34
|
+
module.exports = {
|
|
35
|
+
transform: {
|
|
36
|
+
"^.+\\.(t|j)sx?$": ["@swc/jest", swcrc],
|
|
37
|
+
},
|
|
38
|
+
};
|
|
39
|
+
```
|
|
40
|
+
|
|
41
|
+
Alternative implementation without .swcrc file
|
|
42
|
+
|
|
43
|
+
```JavaScript
|
|
44
|
+
// jest.config.js
|
|
45
|
+
|
|
46
|
+
module.exports = {
|
|
47
|
+
transform: {
|
|
48
|
+
"^.+\\.(t|j)sx?$": [
|
|
49
|
+
"@swc/jest",
|
|
50
|
+
{
|
|
51
|
+
jsc: {
|
|
52
|
+
experimental: {
|
|
53
|
+
plugins: [["@swc-contrib/mut-cjs-exports", {}]],
|
|
54
|
+
},
|
|
55
|
+
},
|
|
56
|
+
},
|
|
57
|
+
],
|
|
58
|
+
},
|
|
59
|
+
};
|
|
60
|
+
```
|
|
61
|
+
|
|
62
|
+
Make sure that `module.type` is `commonjs` in your `.swcrc` since this plugin
|
|
63
|
+
does not touch non-workaround parts, such as import statements.
|
|
64
|
+
|
|
65
|
+
## FAQ
|
|
66
|
+
|
|
67
|
+
#### 1. When do I need this?
|
|
68
|
+
|
|
69
|
+
If you're using the swc compiler to transform your code to comply with the ESM
|
|
70
|
+
specification, but you're also using Jest to test it in a CJS environment, you
|
|
71
|
+
may encounter issues due to the immutable issue of `exports`.
|
|
72
|
+
|
|
73
|
+
This plugin can help by transforming the `export` statements into mutable
|
|
74
|
+
`exports`.
|
|
75
|
+
|
|
76
|
+
#### 2. Do I have a better choice?
|
|
77
|
+
|
|
78
|
+
You may have other options depending on your specific needs:
|
|
79
|
+
|
|
80
|
+
- If you're able to run Jest in an ESM environment, you can use swc to transpile
|
|
81
|
+
TypeScript/JSX syntax or downgrade JavaScript syntax without module
|
|
82
|
+
conversion. Simply set the value of `module.type` to `es6` to achieve this.
|
|
83
|
+
|
|
84
|
+
- It's possible that some issues related to running Jest in an ESM environment
|
|
85
|
+
will be resolved over time. Keep an eye on
|
|
86
|
+
[facebook/jest#9430](https://github.com/facebook/jest/issues/9430) for
|
|
87
|
+
updates.
|
|
88
|
+
|
|
89
|
+
- If you don't need the behavior of ESM specifically, you can stick with the CJS
|
|
90
|
+
syntax to get the CJS behavior of `exports`.
|
|
91
|
+
|
|
92
|
+
These options may be worth considering before using this plugin.
|
|
93
|
+
|
|
94
|
+
CJS syntax
|
|
95
|
+
|
|
96
|
+
```JavaScript
|
|
97
|
+
exports.foo = function foo() {
|
|
98
|
+
return 42;
|
|
99
|
+
};
|
|
100
|
+
```
|
|
101
|
+
|
|
102
|
+
CTS(CJS in TypeScript) syntax
|
|
103
|
+
|
|
104
|
+
```TypeScript
|
|
105
|
+
export = {
|
|
106
|
+
foo: function foo() {
|
|
107
|
+
return 42;
|
|
108
|
+
},
|
|
109
|
+
};
|
|
110
|
+
```
|
|
111
|
+
|
|
112
|
+
Notes:
|
|
113
|
+
|
|
114
|
+
- ESM style export means immutable exports when transformed into CJS
|
|
115
|
+
- ESM style import means hoisted require when transformed into CJS
|
|
116
|
+
|
|
117
|
+
#### 3. After upgrading the plugin version, the changes have not taken effect.
|
|
118
|
+
|
|
119
|
+
This is a known issue. You could remove the Jest cache by running
|
|
120
|
+
[`jest --clearCache`](https://jestjs.io/docs/cli#--clearcache) as a workaround.
|
package/package.json
ADDED
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@swc-contrib/mut-cjs-exports",
|
|
3
|
+
"version": "10.7.0",
|
|
4
|
+
"description": "[SWC plugin] mutable CJS exports",
|
|
5
|
+
"author": "magic-akari <akari.ccino@gmail.com>",
|
|
6
|
+
"license": "MIT",
|
|
7
|
+
"keywords": [
|
|
8
|
+
"swc-plugin",
|
|
9
|
+
"swc",
|
|
10
|
+
"jest",
|
|
11
|
+
"cjs",
|
|
12
|
+
"commonjs"
|
|
13
|
+
],
|
|
14
|
+
"main": "swc_mut_cjs_exports.wasm",
|
|
15
|
+
"files": [
|
|
16
|
+
"src",
|
|
17
|
+
"swc_mut_cjs_exports.wasm"
|
|
18
|
+
],
|
|
19
|
+
"homepage": "https://github.com/magic-akari/swc_mut_cjs_exports#readme",
|
|
20
|
+
"repository": {
|
|
21
|
+
"type": "git",
|
|
22
|
+
"url": "git+https://github.com/magic-akari/swc_mut_cjs_exports.git"
|
|
23
|
+
},
|
|
24
|
+
"bugs": {
|
|
25
|
+
"url": "https://github.com/magic-akari/swc_mut_cjs_exports/issues"
|
|
26
|
+
},
|
|
27
|
+
"devDependencies": {
|
|
28
|
+
"@swc/core": "^1.10.0",
|
|
29
|
+
"@swc/jest": "^0.2.37",
|
|
30
|
+
"@types/jest": "^29.5.11",
|
|
31
|
+
"jest": "^29.7.0"
|
|
32
|
+
},
|
|
33
|
+
"peerDependencies": {
|
|
34
|
+
"@swc/core": "^1.10.0",
|
|
35
|
+
"@swc/jest": "^0.2.37"
|
|
36
|
+
},
|
|
37
|
+
"scripts": {
|
|
38
|
+
"build": "cargo build --release --target wasm32-unknown-unknown && cp ../../target/wasm32-unknown-unknown/release/swc_mut_cjs_exports.wasm .",
|
|
39
|
+
"build:debug": "cargo build --target wasm32-unknown-unknown && cp ../../target/wasm32-unknown-unknown/debug/swc_mut_cjs_exports.wasm ./swc_mut_cjs_exports_debug.wasm",
|
|
40
|
+
"test": "pnpm run build:debug && jest"
|
|
41
|
+
}
|
|
42
|
+
}
|
package/src/lib.rs
ADDED
|
@@ -0,0 +1,325 @@
|
|
|
1
|
+
mod local_export_strip;
|
|
2
|
+
mod utils;
|
|
3
|
+
|
|
4
|
+
use local_export_strip::LocalExportStrip;
|
|
5
|
+
use rustc_hash::FxHashSet;
|
|
6
|
+
use swc_core::{
|
|
7
|
+
common::{util::take::Take, Mark, SyntaxContext, DUMMY_SP},
|
|
8
|
+
ecma::{
|
|
9
|
+
ast::*,
|
|
10
|
+
utils::{
|
|
11
|
+
for_each_binding_ident, member_expr, private_ident, quote_ident, quote_str,
|
|
12
|
+
ExprFactory, IntoIndirectCall,
|
|
13
|
+
},
|
|
14
|
+
visit::{noop_visit_mut_type, VisitMut, VisitMutWith},
|
|
15
|
+
},
|
|
16
|
+
plugin::{plugin_transform, proxies::TransformPluginProgramMetadata},
|
|
17
|
+
};
|
|
18
|
+
use utils::{emit_export_stmts, object_define_property};
|
|
19
|
+
|
|
20
|
+
#[derive(Debug)]
|
|
21
|
+
pub struct TransformVisitor {
|
|
22
|
+
unresolved_mark: Mark,
|
|
23
|
+
|
|
24
|
+
export_decl_id: FxHashSet<Id>,
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
impl VisitMut for TransformVisitor {
|
|
28
|
+
noop_visit_mut_type!();
|
|
29
|
+
|
|
30
|
+
fn visit_mut_script(&mut self, _: &mut Script) {
|
|
31
|
+
// skip
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
fn visit_mut_module(&mut self, n: &mut Module) {
|
|
35
|
+
let mut strip = LocalExportStrip::default();
|
|
36
|
+
n.visit_mut_with(&mut strip);
|
|
37
|
+
|
|
38
|
+
let LocalExportStrip {
|
|
39
|
+
has_export_assign,
|
|
40
|
+
export,
|
|
41
|
+
export_all,
|
|
42
|
+
export_decl_id,
|
|
43
|
+
..
|
|
44
|
+
} = strip;
|
|
45
|
+
|
|
46
|
+
self.export_decl_id = export_decl_id;
|
|
47
|
+
|
|
48
|
+
let mut stmts: Vec<ModuleItem> = Vec::with_capacity(n.body.len() + 1);
|
|
49
|
+
|
|
50
|
+
if !has_export_assign && !export.is_empty() {
|
|
51
|
+
// keep module env
|
|
52
|
+
stmts.push(ModuleItem::ModuleDecl(ModuleDecl::ExportNamed(
|
|
53
|
+
NamedExport::dummy(),
|
|
54
|
+
)));
|
|
55
|
+
|
|
56
|
+
let exports = self.exports();
|
|
57
|
+
|
|
58
|
+
stmts.extend(
|
|
59
|
+
emit_export_stmts(exports, export)
|
|
60
|
+
.into_iter()
|
|
61
|
+
.map(Into::into),
|
|
62
|
+
);
|
|
63
|
+
|
|
64
|
+
if !self.export_decl_id.is_empty() {
|
|
65
|
+
n.visit_mut_children_with(self);
|
|
66
|
+
}
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
stmts.extend(export_all.into_iter().map(|id| self.export_all(id)));
|
|
70
|
+
|
|
71
|
+
stmts.extend(n.body.take());
|
|
72
|
+
|
|
73
|
+
n.body = stmts;
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
fn visit_mut_function(&mut self, node: &mut Function) {
|
|
77
|
+
let export_decl_id = self.export_decl_id.clone();
|
|
78
|
+
|
|
79
|
+
for_each_binding_ident(&node.params, |ident| {
|
|
80
|
+
self.export_decl_id.remove(&ident.id.to_id());
|
|
81
|
+
});
|
|
82
|
+
|
|
83
|
+
node.visit_mut_children_with(self);
|
|
84
|
+
self.export_decl_id = export_decl_id;
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
fn visit_mut_prop(&mut self, n: &mut Prop) {
|
|
88
|
+
match n {
|
|
89
|
+
Prop::Shorthand(ref_ident) => {
|
|
90
|
+
if self.export_decl_id.contains(&ref_ident.to_id()) {
|
|
91
|
+
*n = KeyValueProp {
|
|
92
|
+
key: ref_ident.clone().into(),
|
|
93
|
+
value: Box::new(self.exports().make_member(ref_ident.take().into()).into()),
|
|
94
|
+
}
|
|
95
|
+
.into()
|
|
96
|
+
}
|
|
97
|
+
}
|
|
98
|
+
_ => n.visit_mut_children_with(self),
|
|
99
|
+
}
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
fn visit_mut_expr(&mut self, n: &mut Expr) {
|
|
103
|
+
match n {
|
|
104
|
+
Expr::Ident(ref_ident) => {
|
|
105
|
+
if self.export_decl_id.contains(&ref_ident.to_id()) {
|
|
106
|
+
*n = self.exports().make_member(ref_ident.take().into()).into();
|
|
107
|
+
}
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
_ => n.visit_mut_children_with(self),
|
|
111
|
+
};
|
|
112
|
+
}
|
|
113
|
+
|
|
114
|
+
fn visit_mut_tagged_tpl(&mut self, n: &mut TaggedTpl) {
|
|
115
|
+
let is_indirect = n
|
|
116
|
+
.tag
|
|
117
|
+
.as_ident()
|
|
118
|
+
.map(|ident| self.export_decl_id.contains(&ident.to_id()))
|
|
119
|
+
.unwrap_or_default();
|
|
120
|
+
|
|
121
|
+
n.visit_mut_children_with(self);
|
|
122
|
+
|
|
123
|
+
if is_indirect {
|
|
124
|
+
*n = n.take().into_indirect()
|
|
125
|
+
}
|
|
126
|
+
}
|
|
127
|
+
|
|
128
|
+
fn visit_mut_callee(&mut self, n: &mut Callee) {
|
|
129
|
+
match n {
|
|
130
|
+
Callee::Expr(e) if e.is_ident() => {
|
|
131
|
+
let is_indirect_callee = e
|
|
132
|
+
.as_ident()
|
|
133
|
+
.map(|ident| self.export_decl_id.contains(&ident.to_id()))
|
|
134
|
+
.unwrap_or_default();
|
|
135
|
+
|
|
136
|
+
e.visit_mut_with(self);
|
|
137
|
+
|
|
138
|
+
if is_indirect_callee {
|
|
139
|
+
*n = n.take().into_indirect()
|
|
140
|
+
}
|
|
141
|
+
}
|
|
142
|
+
|
|
143
|
+
_ => n.visit_mut_children_with(self),
|
|
144
|
+
}
|
|
145
|
+
}
|
|
146
|
+
|
|
147
|
+
fn visit_mut_jsx_element_name(&mut self, n: &mut JSXElementName) {
|
|
148
|
+
match n {
|
|
149
|
+
JSXElementName::Ident(ref_ident) => {
|
|
150
|
+
if self.export_decl_id.contains(&ref_ident.to_id()) {
|
|
151
|
+
*n = JSXElementName::JSXMemberExpr(
|
|
152
|
+
JSXMemberExpr {
|
|
153
|
+
span: DUMMY_SP,
|
|
154
|
+
obj: self.exports().into(),
|
|
155
|
+
prop: ref_ident.clone().into(),
|
|
156
|
+
}
|
|
157
|
+
.into(),
|
|
158
|
+
);
|
|
159
|
+
}
|
|
160
|
+
}
|
|
161
|
+
_ => n.visit_mut_children_with(self),
|
|
162
|
+
};
|
|
163
|
+
}
|
|
164
|
+
}
|
|
165
|
+
|
|
166
|
+
impl TransformVisitor {
|
|
167
|
+
pub fn new(unresolved_mark: Mark) -> Self {
|
|
168
|
+
Self {
|
|
169
|
+
unresolved_mark,
|
|
170
|
+
export_decl_id: Default::default(),
|
|
171
|
+
}
|
|
172
|
+
}
|
|
173
|
+
|
|
174
|
+
fn exports(&self) -> Ident {
|
|
175
|
+
quote_ident!(
|
|
176
|
+
SyntaxContext::empty().apply_mark(self.unresolved_mark),
|
|
177
|
+
"exports"
|
|
178
|
+
)
|
|
179
|
+
}
|
|
180
|
+
|
|
181
|
+
/// ```JavaScript
|
|
182
|
+
/// Object.keys(_mod).forEach(function (key) {
|
|
183
|
+
/// if (key === "default" || key === "__esModule") return;
|
|
184
|
+
/// if (Object.prototype.hasOwnProperty.call(exports, key)) return;
|
|
185
|
+
/// Object.defineProperty(exports, key, {
|
|
186
|
+
/// enumerable: true,
|
|
187
|
+
/// get: function () {
|
|
188
|
+
/// return mod[key];
|
|
189
|
+
/// },
|
|
190
|
+
/// configurable: true
|
|
191
|
+
/// });
|
|
192
|
+
/// ```
|
|
193
|
+
fn export_all(&self, id: Id) -> ModuleItem {
|
|
194
|
+
let mod_name = Ident::from(id);
|
|
195
|
+
let key = private_ident!("key");
|
|
196
|
+
|
|
197
|
+
member_expr!(Default::default(), DUMMY_SP, Object.keys)
|
|
198
|
+
.as_call(DUMMY_SP, vec![mod_name.clone().as_arg()])
|
|
199
|
+
.make_member(quote_ident!("forEach"))
|
|
200
|
+
.as_call(
|
|
201
|
+
DUMMY_SP,
|
|
202
|
+
vec![Function {
|
|
203
|
+
params: vec![key.clone().into()],
|
|
204
|
+
span: DUMMY_SP,
|
|
205
|
+
body: Some(BlockStmt {
|
|
206
|
+
stmts: vec![
|
|
207
|
+
// if (key === "default" || key === "__esModule") return;
|
|
208
|
+
IfStmt {
|
|
209
|
+
span: DUMMY_SP,
|
|
210
|
+
test: BinExpr {
|
|
211
|
+
span: DUMMY_SP,
|
|
212
|
+
op: op!("||"),
|
|
213
|
+
left: BinExpr {
|
|
214
|
+
span: DUMMY_SP,
|
|
215
|
+
op: op!("==="),
|
|
216
|
+
left: key.clone().into(),
|
|
217
|
+
right: quote_str!("default").into(),
|
|
218
|
+
}
|
|
219
|
+
.into(),
|
|
220
|
+
right: BinExpr {
|
|
221
|
+
span: DUMMY_SP,
|
|
222
|
+
op: op!("==="),
|
|
223
|
+
left: key.clone().into(),
|
|
224
|
+
right: quote_str!("__esModule").into(),
|
|
225
|
+
}
|
|
226
|
+
.into(),
|
|
227
|
+
}
|
|
228
|
+
.into(),
|
|
229
|
+
cons: Box::new(
|
|
230
|
+
ReturnStmt {
|
|
231
|
+
span: DUMMY_SP,
|
|
232
|
+
arg: None,
|
|
233
|
+
}
|
|
234
|
+
.into(),
|
|
235
|
+
),
|
|
236
|
+
alt: None,
|
|
237
|
+
}
|
|
238
|
+
.into(),
|
|
239
|
+
// if (Object.prototype.hasOwnProperty.call(exports, key)) return;
|
|
240
|
+
IfStmt {
|
|
241
|
+
span: DUMMY_SP,
|
|
242
|
+
test: Box::new(
|
|
243
|
+
member_expr!(
|
|
244
|
+
Default::default(),
|
|
245
|
+
DUMMY_SP,
|
|
246
|
+
Object.prototype.hasOwnProperty.call
|
|
247
|
+
)
|
|
248
|
+
.as_call(
|
|
249
|
+
DUMMY_SP,
|
|
250
|
+
vec![self.exports().as_arg(), key.clone().as_arg()],
|
|
251
|
+
),
|
|
252
|
+
),
|
|
253
|
+
cons: Box::new(
|
|
254
|
+
ReturnStmt {
|
|
255
|
+
span: DUMMY_SP,
|
|
256
|
+
arg: None,
|
|
257
|
+
}
|
|
258
|
+
.into(),
|
|
259
|
+
),
|
|
260
|
+
alt: None,
|
|
261
|
+
}
|
|
262
|
+
.into(),
|
|
263
|
+
// Object.defineProperty(exports, key, {
|
|
264
|
+
// enumerable: true,
|
|
265
|
+
// get: function () {
|
|
266
|
+
// return mod[key];
|
|
267
|
+
// },
|
|
268
|
+
// configurable: true
|
|
269
|
+
// });
|
|
270
|
+
object_define_property(
|
|
271
|
+
self.exports().as_arg(),
|
|
272
|
+
key.clone().as_arg(),
|
|
273
|
+
ObjectLit {
|
|
274
|
+
span: DUMMY_SP,
|
|
275
|
+
props: vec![
|
|
276
|
+
PropOrSpread::Prop(Box::new(
|
|
277
|
+
KeyValueProp {
|
|
278
|
+
key: quote_ident!("enumerable").into(),
|
|
279
|
+
value: true.into(),
|
|
280
|
+
}
|
|
281
|
+
.into(),
|
|
282
|
+
)),
|
|
283
|
+
PropOrSpread::Prop(Box::new(
|
|
284
|
+
KeyValueProp {
|
|
285
|
+
key: quote_ident!("get").into(),
|
|
286
|
+
value: mod_name
|
|
287
|
+
.clone()
|
|
288
|
+
.computed_member(key.clone())
|
|
289
|
+
.into_lazy_fn(vec![])
|
|
290
|
+
.into(),
|
|
291
|
+
}
|
|
292
|
+
.into(),
|
|
293
|
+
)),
|
|
294
|
+
PropOrSpread::Prop(Box::new(
|
|
295
|
+
KeyValueProp {
|
|
296
|
+
key: quote_ident!("configurable").into(),
|
|
297
|
+
value: true.into(),
|
|
298
|
+
}
|
|
299
|
+
.into(),
|
|
300
|
+
)),
|
|
301
|
+
],
|
|
302
|
+
}
|
|
303
|
+
.as_arg(),
|
|
304
|
+
)
|
|
305
|
+
.into_stmt(),
|
|
306
|
+
],
|
|
307
|
+
..Default::default()
|
|
308
|
+
}),
|
|
309
|
+
..Default::default()
|
|
310
|
+
}
|
|
311
|
+
.as_arg()],
|
|
312
|
+
)
|
|
313
|
+
.into_stmt()
|
|
314
|
+
.into()
|
|
315
|
+
}
|
|
316
|
+
}
|
|
317
|
+
|
|
318
|
+
#[plugin_transform]
|
|
319
|
+
pub fn process_transform(
|
|
320
|
+
mut program: Program,
|
|
321
|
+
metadata: TransformPluginProgramMetadata,
|
|
322
|
+
) -> Program {
|
|
323
|
+
program.visit_mut_with(&mut TransformVisitor::new(metadata.unresolved_mark));
|
|
324
|
+
program
|
|
325
|
+
}
|
|
@@ -0,0 +1,362 @@
|
|
|
1
|
+
use std::collections::BTreeMap;
|
|
2
|
+
|
|
3
|
+
use rustc_hash::FxHashSet;
|
|
4
|
+
use swc_core::{
|
|
5
|
+
atoms::Atom,
|
|
6
|
+
common::{util::take::Take, Span, DUMMY_SP},
|
|
7
|
+
ecma::{
|
|
8
|
+
ast::*,
|
|
9
|
+
utils::{find_pat_ids, private_ident, ExprFactory},
|
|
10
|
+
visit::{noop_visit_mut_type, VisitMut, VisitMutWith},
|
|
11
|
+
},
|
|
12
|
+
};
|
|
13
|
+
|
|
14
|
+
use crate::utils::{key_from_export_name, local_ident_from_export_name};
|
|
15
|
+
|
|
16
|
+
pub type Export = BTreeMap<Atom, ExportItem>;
|
|
17
|
+
|
|
18
|
+
#[derive(Debug)]
|
|
19
|
+
pub struct ExportItem(Span, Ident);
|
|
20
|
+
|
|
21
|
+
impl ExportItem {
|
|
22
|
+
pub fn new(export_name_span: Span, local_ident: Ident) -> Self {
|
|
23
|
+
Self(export_name_span, local_ident)
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
pub fn export_name_span(&self) -> Span {
|
|
27
|
+
self.0
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
pub fn into_local_ident(self) -> Ident {
|
|
31
|
+
self.1
|
|
32
|
+
}
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
#[derive(Debug, Default)]
|
|
36
|
+
pub(crate) struct LocalExportStrip {
|
|
37
|
+
pub(crate) has_export_assign: bool,
|
|
38
|
+
pub(crate) export: Export,
|
|
39
|
+
pub(crate) export_all: FxHashSet<Id>,
|
|
40
|
+
pub(crate) export_decl_id: FxHashSet<Id>,
|
|
41
|
+
export_default: Option<Stmt>,
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
impl VisitMut for LocalExportStrip {
|
|
45
|
+
noop_visit_mut_type!();
|
|
46
|
+
|
|
47
|
+
fn visit_mut_script(&mut self, _: &mut Script) {
|
|
48
|
+
// skip
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
fn visit_mut_module(&mut self, n: &mut Module) {
|
|
52
|
+
let mut list = Vec::with_capacity(n.body.len());
|
|
53
|
+
|
|
54
|
+
for item in n.body.drain(..) {
|
|
55
|
+
match item {
|
|
56
|
+
ModuleItem::Stmt(stmt) => list.push(stmt.into()),
|
|
57
|
+
|
|
58
|
+
ModuleItem::ModuleDecl(mut module_decl) => {
|
|
59
|
+
// collect link meta
|
|
60
|
+
module_decl.visit_mut_with(self);
|
|
61
|
+
|
|
62
|
+
// emit stmt
|
|
63
|
+
match module_decl {
|
|
64
|
+
ModuleDecl::ExportDecl(ExportDecl { decl, .. }) => {
|
|
65
|
+
list.push(Stmt::Decl(decl).into());
|
|
66
|
+
}
|
|
67
|
+
ModuleDecl::ExportNamed(NamedExport { src: None, .. }) => continue,
|
|
68
|
+
ModuleDecl::ExportNamed(
|
|
69
|
+
item @ NamedExport {
|
|
70
|
+
src: Some(..),
|
|
71
|
+
type_only: false,
|
|
72
|
+
..
|
|
73
|
+
},
|
|
74
|
+
) => {
|
|
75
|
+
let decl: ModuleDecl = self.convert_export_decl(item).into();
|
|
76
|
+
list.push(decl.into());
|
|
77
|
+
}
|
|
78
|
+
ModuleDecl::ExportAll(
|
|
79
|
+
e @ ExportAll {
|
|
80
|
+
type_only: false, ..
|
|
81
|
+
},
|
|
82
|
+
) => {
|
|
83
|
+
let decl: ModuleDecl = self.convert_export_all(e).into();
|
|
84
|
+
list.push(decl.into());
|
|
85
|
+
}
|
|
86
|
+
ModuleDecl::ExportDefaultDecl(ExportDefaultDecl {
|
|
87
|
+
decl:
|
|
88
|
+
decl @ (DefaultDecl::Class(ClassExpr {
|
|
89
|
+
ident: Some(..), ..
|
|
90
|
+
})
|
|
91
|
+
| DefaultDecl::Fn(FnExpr {
|
|
92
|
+
ident: Some(..), ..
|
|
93
|
+
})),
|
|
94
|
+
..
|
|
95
|
+
}) => match decl {
|
|
96
|
+
DefaultDecl::Class(class_expr) => list.extend(
|
|
97
|
+
class_expr
|
|
98
|
+
.as_class_decl()
|
|
99
|
+
.map(|decl| Stmt::Decl(Decl::Class(decl)))
|
|
100
|
+
.map(Into::into),
|
|
101
|
+
),
|
|
102
|
+
DefaultDecl::Fn(fn_expr) => list.extend(
|
|
103
|
+
fn_expr
|
|
104
|
+
.as_fn_decl()
|
|
105
|
+
.map(|decl| Stmt::Decl(Decl::Fn(decl)))
|
|
106
|
+
.map(Into::into),
|
|
107
|
+
),
|
|
108
|
+
_ => unreachable!(),
|
|
109
|
+
},
|
|
110
|
+
ModuleDecl::ExportDefaultExpr(..) => {
|
|
111
|
+
list.extend(self.export_default.take().map(From::from))
|
|
112
|
+
}
|
|
113
|
+
ModuleDecl::TsExportAssignment(..) => {
|
|
114
|
+
self.has_export_assign = true;
|
|
115
|
+
list.push(module_decl.into());
|
|
116
|
+
}
|
|
117
|
+
_ => list.push(module_decl.into()),
|
|
118
|
+
};
|
|
119
|
+
}
|
|
120
|
+
};
|
|
121
|
+
}
|
|
122
|
+
|
|
123
|
+
n.body = list;
|
|
124
|
+
}
|
|
125
|
+
|
|
126
|
+
/// ```javascript
|
|
127
|
+
/// export const foo = 1, bar = 2, { baz } = { baz: 3 };
|
|
128
|
+
/// export let a = 1, [b] = [2];
|
|
129
|
+
/// export function x() {}
|
|
130
|
+
/// export class y {}
|
|
131
|
+
/// ```
|
|
132
|
+
/// ->
|
|
133
|
+
/// ```javascript
|
|
134
|
+
/// const foo = 1, bar = 2, { baz } = { baz: 3 };
|
|
135
|
+
/// let a = 1, [b] = [2];
|
|
136
|
+
/// function x() {}
|
|
137
|
+
/// class y {}
|
|
138
|
+
/// ```
|
|
139
|
+
fn visit_mut_export_decl(&mut self, n: &mut ExportDecl) {
|
|
140
|
+
match &n.decl {
|
|
141
|
+
Decl::Class(ClassDecl { ident, .. }) | Decl::Fn(FnDecl { ident, .. }) => {
|
|
142
|
+
self.export.insert(
|
|
143
|
+
ident.sym.clone(),
|
|
144
|
+
ExportItem::new(ident.span, ident.clone()),
|
|
145
|
+
);
|
|
146
|
+
}
|
|
147
|
+
|
|
148
|
+
Decl::Var(v) => {
|
|
149
|
+
let ids = find_pat_ids::<_, Ident>(&v.decls);
|
|
150
|
+
|
|
151
|
+
self.export_decl_id.extend(ids.iter().map(Ident::to_id));
|
|
152
|
+
|
|
153
|
+
self.export.extend(
|
|
154
|
+
find_pat_ids::<_, Ident>(&v.decls)
|
|
155
|
+
.into_iter()
|
|
156
|
+
.map(|id| (id.sym.clone(), ExportItem::new(id.span, id))),
|
|
157
|
+
);
|
|
158
|
+
}
|
|
159
|
+
_ => {}
|
|
160
|
+
};
|
|
161
|
+
}
|
|
162
|
+
|
|
163
|
+
/// ```javascript
|
|
164
|
+
/// export { foo, foo as bar, foo as "baz" };
|
|
165
|
+
/// export { "foo", foo as bar, "foo" as "baz" } from "mod";
|
|
166
|
+
/// export * as foo from "mod";
|
|
167
|
+
/// export * as "bar" from "mod";
|
|
168
|
+
/// ```
|
|
169
|
+
fn visit_mut_named_export(&mut self, n: &mut NamedExport) {
|
|
170
|
+
if n.type_only || n.src.is_some() {
|
|
171
|
+
return;
|
|
172
|
+
}
|
|
173
|
+
|
|
174
|
+
let NamedExport { specifiers, .. } = n.take();
|
|
175
|
+
|
|
176
|
+
self.export.extend(specifiers.into_iter().map(|e| match e {
|
|
177
|
+
ExportSpecifier::Namespace(..) => {
|
|
178
|
+
unreachable!("`export *` without src is invalid")
|
|
179
|
+
}
|
|
180
|
+
ExportSpecifier::Default(..) => {
|
|
181
|
+
unreachable!("`export foo` without src is invalid")
|
|
182
|
+
}
|
|
183
|
+
ExportSpecifier::Named(ExportNamedSpecifier { orig, exported, .. }) => {
|
|
184
|
+
let orig = match orig {
|
|
185
|
+
ModuleExportName::Ident(id) => id,
|
|
186
|
+
ModuleExportName::Str(_) => {
|
|
187
|
+
unreachable!(r#"`export {{ "foo" }}` without src is invalid"#)
|
|
188
|
+
}
|
|
189
|
+
};
|
|
190
|
+
|
|
191
|
+
if let Some(exported) = exported {
|
|
192
|
+
let (export_name, export_name_span) = match exported {
|
|
193
|
+
ModuleExportName::Ident(Ident { span, sym, .. }) => (sym, span),
|
|
194
|
+
ModuleExportName::Str(Str { span, value, .. }) => (value, span),
|
|
195
|
+
};
|
|
196
|
+
|
|
197
|
+
(export_name, ExportItem::new(export_name_span, orig))
|
|
198
|
+
} else {
|
|
199
|
+
(orig.sym.clone(), ExportItem::new(orig.span, orig))
|
|
200
|
+
}
|
|
201
|
+
}
|
|
202
|
+
}))
|
|
203
|
+
}
|
|
204
|
+
|
|
205
|
+
/// ```javascript
|
|
206
|
+
/// export default class foo {};
|
|
207
|
+
/// export default class {};
|
|
208
|
+
/// export default function bar () {};
|
|
209
|
+
/// export default function () {};
|
|
210
|
+
/// ```
|
|
211
|
+
/// ->
|
|
212
|
+
/// ```javascript
|
|
213
|
+
/// class foo {};
|
|
214
|
+
/// class _default {};
|
|
215
|
+
/// function bar () {};
|
|
216
|
+
/// function _default () {};
|
|
217
|
+
/// ```
|
|
218
|
+
fn visit_mut_export_default_decl(&mut self, n: &mut ExportDefaultDecl) {
|
|
219
|
+
match &mut n.decl {
|
|
220
|
+
DefaultDecl::Class(class_expr) => {
|
|
221
|
+
if let Some(ident) = class_expr.ident.clone() {
|
|
222
|
+
self.export
|
|
223
|
+
.insert("default".into(), ExportItem::new(n.span, ident));
|
|
224
|
+
}
|
|
225
|
+
}
|
|
226
|
+
DefaultDecl::Fn(fn_expr) => {
|
|
227
|
+
if let Some(ident) = fn_expr.ident.clone() {
|
|
228
|
+
self.export
|
|
229
|
+
.insert("default".into(), ExportItem::new(n.span, ident));
|
|
230
|
+
}
|
|
231
|
+
}
|
|
232
|
+
DefaultDecl::TsInterfaceDecl(_) => {}
|
|
233
|
+
}
|
|
234
|
+
}
|
|
235
|
+
|
|
236
|
+
/// ```javascript
|
|
237
|
+
/// export default foo;
|
|
238
|
+
/// export default 1
|
|
239
|
+
/// ```
|
|
240
|
+
/// ->
|
|
241
|
+
/// ```javascript
|
|
242
|
+
/// var _default = foo;
|
|
243
|
+
/// var _default = 1;
|
|
244
|
+
/// ```
|
|
245
|
+
fn visit_mut_export_default_expr(&mut self, n: &mut ExportDefaultExpr) {
|
|
246
|
+
let ident = private_ident!(n.span, "_default");
|
|
247
|
+
|
|
248
|
+
self.export
|
|
249
|
+
.insert("default".into(), ExportItem::new(n.span, ident.clone()));
|
|
250
|
+
|
|
251
|
+
self.export_default = Some(Stmt::Decl(
|
|
252
|
+
n.expr
|
|
253
|
+
.take()
|
|
254
|
+
.into_var_decl(VarDeclKind::Const, ident.into())
|
|
255
|
+
.into(),
|
|
256
|
+
));
|
|
257
|
+
}
|
|
258
|
+
}
|
|
259
|
+
|
|
260
|
+
impl LocalExportStrip {
|
|
261
|
+
fn convert_export_decl(&mut self, n: NamedExport) -> ImportDecl {
|
|
262
|
+
let NamedExport {
|
|
263
|
+
span,
|
|
264
|
+
specifiers,
|
|
265
|
+
src,
|
|
266
|
+
type_only,
|
|
267
|
+
with,
|
|
268
|
+
} = n;
|
|
269
|
+
|
|
270
|
+
let src = src.unwrap();
|
|
271
|
+
|
|
272
|
+
let specifiers = specifiers
|
|
273
|
+
.into_iter()
|
|
274
|
+
.flat_map(|s| self.convert_export_specifier(s))
|
|
275
|
+
.collect();
|
|
276
|
+
|
|
277
|
+
ImportDecl {
|
|
278
|
+
span,
|
|
279
|
+
specifiers,
|
|
280
|
+
src,
|
|
281
|
+
type_only,
|
|
282
|
+
with,
|
|
283
|
+
phase: Default::default(),
|
|
284
|
+
}
|
|
285
|
+
}
|
|
286
|
+
|
|
287
|
+
fn convert_export_specifier(&mut self, s: ExportSpecifier) -> Option<ImportSpecifier> {
|
|
288
|
+
match s {
|
|
289
|
+
ExportSpecifier::Namespace(ExportNamespaceSpecifier { span, name }) => {
|
|
290
|
+
let (export_name, export_span) = key_from_export_name(&name);
|
|
291
|
+
let local = local_ident_from_export_name(name);
|
|
292
|
+
self.export
|
|
293
|
+
.insert(export_name, ExportItem::new(export_span, local.clone()));
|
|
294
|
+
|
|
295
|
+
Some(ImportSpecifier::Namespace(ImportStarAsSpecifier {
|
|
296
|
+
span,
|
|
297
|
+
local,
|
|
298
|
+
}))
|
|
299
|
+
}
|
|
300
|
+
ExportSpecifier::Default(ExportDefaultSpecifier { exported }) => {
|
|
301
|
+
let (export_name, export_span) = (exported.sym.clone(), exported.span);
|
|
302
|
+
let local = exported.into_private();
|
|
303
|
+
self.export
|
|
304
|
+
.insert(export_name, ExportItem::new(export_span, local.clone()));
|
|
305
|
+
|
|
306
|
+
Some(ImportSpecifier::Default(ImportDefaultSpecifier {
|
|
307
|
+
local,
|
|
308
|
+
span: DUMMY_SP,
|
|
309
|
+
}))
|
|
310
|
+
}
|
|
311
|
+
ExportSpecifier::Named(ExportNamedSpecifier {
|
|
312
|
+
span,
|
|
313
|
+
orig,
|
|
314
|
+
exported,
|
|
315
|
+
is_type_only: false,
|
|
316
|
+
}) => {
|
|
317
|
+
// export { "x-1" as "y-1" } from "foo"
|
|
318
|
+
// ->
|
|
319
|
+
// import { "x-1" as x1 } from "foo"
|
|
320
|
+
// export { x1 as "y-1" }
|
|
321
|
+
let name = exported.as_ref().unwrap_or(&orig);
|
|
322
|
+
|
|
323
|
+
let (export_name, export_span) = key_from_export_name(name);
|
|
324
|
+
let local = local_ident_from_export_name(orig.clone());
|
|
325
|
+
self.export
|
|
326
|
+
.insert(export_name, ExportItem::new(export_span, local.clone()));
|
|
327
|
+
|
|
328
|
+
Some(ImportSpecifier::Named(ImportNamedSpecifier {
|
|
329
|
+
span,
|
|
330
|
+
local,
|
|
331
|
+
imported: Some(orig),
|
|
332
|
+
is_type_only: false,
|
|
333
|
+
}))
|
|
334
|
+
}
|
|
335
|
+
_ => None,
|
|
336
|
+
}
|
|
337
|
+
}
|
|
338
|
+
|
|
339
|
+
fn convert_export_all(&mut self, e: ExportAll) -> ImportDecl {
|
|
340
|
+
let ExportAll {
|
|
341
|
+
span, src, with, ..
|
|
342
|
+
} = e;
|
|
343
|
+
|
|
344
|
+
let mod_name = private_ident!("mod");
|
|
345
|
+
|
|
346
|
+
self.export_all.insert(mod_name.to_id());
|
|
347
|
+
|
|
348
|
+
let star = ImportStarAsSpecifier {
|
|
349
|
+
span,
|
|
350
|
+
local: mod_name.clone(),
|
|
351
|
+
};
|
|
352
|
+
|
|
353
|
+
ImportDecl {
|
|
354
|
+
span,
|
|
355
|
+
specifiers: vec![star.into()],
|
|
356
|
+
src,
|
|
357
|
+
type_only: false,
|
|
358
|
+
with,
|
|
359
|
+
phase: Default::default(),
|
|
360
|
+
}
|
|
361
|
+
}
|
|
362
|
+
}
|
package/src/utils.rs
ADDED
|
@@ -0,0 +1,143 @@
|
|
|
1
|
+
use swc_core::{
|
|
2
|
+
atoms::Atom,
|
|
3
|
+
common::{Span, DUMMY_SP},
|
|
4
|
+
ecma::{
|
|
5
|
+
ast::*,
|
|
6
|
+
utils::{member_expr, private_ident, quote_ident, quote_str, ExprFactory},
|
|
7
|
+
},
|
|
8
|
+
};
|
|
9
|
+
|
|
10
|
+
use crate::local_export_strip::Export;
|
|
11
|
+
|
|
12
|
+
/// ```javascript
|
|
13
|
+
/// {
|
|
14
|
+
/// get() { return ident; }
|
|
15
|
+
/// }
|
|
16
|
+
/// ```
|
|
17
|
+
pub(crate) fn prop_method_getter(ident: Ident) -> Prop {
|
|
18
|
+
let key = quote_ident!("get").into();
|
|
19
|
+
|
|
20
|
+
MethodProp {
|
|
21
|
+
key,
|
|
22
|
+
function: ident.into_lazy_fn(Default::default()).into(),
|
|
23
|
+
}
|
|
24
|
+
.into()
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
/// ```javascript
|
|
28
|
+
/// {
|
|
29
|
+
/// set(v) { ident = v; }
|
|
30
|
+
/// }
|
|
31
|
+
/// ```
|
|
32
|
+
pub(crate) fn prop_method_setter(ident: Ident) -> Prop {
|
|
33
|
+
let key = quote_ident!("set").into();
|
|
34
|
+
|
|
35
|
+
let setter_param = private_ident!("v");
|
|
36
|
+
let params = vec![setter_param.clone().into()];
|
|
37
|
+
|
|
38
|
+
let body = BlockStmt {
|
|
39
|
+
stmts: vec![setter_param
|
|
40
|
+
.make_assign_to(op!("="), ident.clone().into())
|
|
41
|
+
.into_stmt()],
|
|
42
|
+
..Default::default()
|
|
43
|
+
};
|
|
44
|
+
|
|
45
|
+
MethodProp {
|
|
46
|
+
key,
|
|
47
|
+
function: Function {
|
|
48
|
+
params,
|
|
49
|
+
body: Some(body),
|
|
50
|
+
..Default::default()
|
|
51
|
+
}
|
|
52
|
+
.into(),
|
|
53
|
+
}
|
|
54
|
+
.into()
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
/// Creates
|
|
58
|
+
///
|
|
59
|
+
///```js
|
|
60
|
+
///
|
|
61
|
+
/// Object.defineProperty(target, prop_name, {
|
|
62
|
+
/// ...props
|
|
63
|
+
/// });
|
|
64
|
+
/// ```
|
|
65
|
+
pub(super) fn object_define_property(
|
|
66
|
+
target: ExprOrSpread,
|
|
67
|
+
prop_name: ExprOrSpread,
|
|
68
|
+
descriptor: ExprOrSpread,
|
|
69
|
+
) -> Expr {
|
|
70
|
+
member_expr!(Default::default(), DUMMY_SP, Object.defineProperty)
|
|
71
|
+
.as_call(DUMMY_SP, vec![target, prop_name, descriptor])
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
pub(crate) fn object_define_enumerable_configurable(
|
|
75
|
+
target: ExprOrSpread,
|
|
76
|
+
prop_name: ExprOrSpread,
|
|
77
|
+
getter: PropOrSpread,
|
|
78
|
+
setter: PropOrSpread,
|
|
79
|
+
) -> Expr {
|
|
80
|
+
object_define_property(
|
|
81
|
+
target,
|
|
82
|
+
prop_name,
|
|
83
|
+
ObjectLit {
|
|
84
|
+
span: DUMMY_SP,
|
|
85
|
+
props: vec![
|
|
86
|
+
PropOrSpread::Prop(Box::new(
|
|
87
|
+
KeyValueProp {
|
|
88
|
+
key: quote_ident!("enumerable").into(),
|
|
89
|
+
value: Box::new(true.into()),
|
|
90
|
+
}
|
|
91
|
+
.into(),
|
|
92
|
+
)),
|
|
93
|
+
getter,
|
|
94
|
+
setter,
|
|
95
|
+
PropOrSpread::Prop(Box::new(
|
|
96
|
+
KeyValueProp {
|
|
97
|
+
key: quote_ident!("configurable").into(),
|
|
98
|
+
value: Box::new(true.into()),
|
|
99
|
+
}
|
|
100
|
+
.into(),
|
|
101
|
+
)),
|
|
102
|
+
],
|
|
103
|
+
}
|
|
104
|
+
.as_arg(),
|
|
105
|
+
)
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
pub(crate) fn emit_export_stmts(exports: Ident, export: Export) -> Vec<Stmt> {
|
|
109
|
+
export
|
|
110
|
+
.into_iter()
|
|
111
|
+
.map(|(export_name, export_item)| {
|
|
112
|
+
let prop_name = quote_str!(export_item.export_name_span(), export_name);
|
|
113
|
+
let local_ident = export_item.into_local_ident();
|
|
114
|
+
|
|
115
|
+
object_define_enumerable_configurable(
|
|
116
|
+
exports.clone().as_arg(),
|
|
117
|
+
prop_name.as_arg(),
|
|
118
|
+
prop_method_getter(local_ident.clone()).into(),
|
|
119
|
+
prop_method_setter(local_ident).into(),
|
|
120
|
+
)
|
|
121
|
+
.into_stmt()
|
|
122
|
+
})
|
|
123
|
+
.collect()
|
|
124
|
+
}
|
|
125
|
+
|
|
126
|
+
pub(crate) fn key_from_export_name(n: &ModuleExportName) -> (Atom, Span) {
|
|
127
|
+
match n {
|
|
128
|
+
ModuleExportName::Ident(ident) => (ident.sym.clone(), ident.span),
|
|
129
|
+
ModuleExportName::Str(str) => (str.value.clone(), str.span),
|
|
130
|
+
}
|
|
131
|
+
}
|
|
132
|
+
|
|
133
|
+
pub(crate) fn local_ident_from_export_name(n: ModuleExportName) -> Ident {
|
|
134
|
+
let name = match n {
|
|
135
|
+
ModuleExportName::Ident(ident) => ident.sym,
|
|
136
|
+
ModuleExportName::Str(str) => str.value,
|
|
137
|
+
};
|
|
138
|
+
|
|
139
|
+
match Ident::verify_symbol(&name) {
|
|
140
|
+
Ok(_) => private_ident!(name),
|
|
141
|
+
Err(s) => private_ident!(s),
|
|
142
|
+
}
|
|
143
|
+
}
|
|
Binary file
|