1
use std::{io::stderr, num::NonZeroU32, sync::Arc};
2
3
+use estree::{Binding, BindingId};
4
use swc::Compiler;
5
use swc_core::common::errors::Handler;
6
use swc_core::common::source_map::Pos;
6
-use swc_core::common::{FileName, FilePathMapping, Mark, SourceMap, Span, GLOBALS};
7
+use swc_core::common::{FileName, FilePathMapping, Mark, SourceMap, Span, SyntaxContext, GLOBALS};
8
use swc_core::ecma::ast::{
9
AssignOp, BinaryOp, BlockStmt, Decl, EsVersion, Expr, Ident, Lit, ModuleItem, Pat, PatOrExpr,
10
Program, Stmt, UnaryOp, VarDeclKind, VarDeclOrExpr,
34
Some(&comments),
35
)?;
36
37
+ let context = Context {
38
+ top_level_mark: Mark::new(),
39
+ unresolved_mark: Mark::new(),
40
+ };
41
+
42
let module = c.run_transform(&handler, false, || {
37
- let unresolved_mark = Mark::new();
38
- let top_level_mark = Mark::new();
39
- module.fold_with(&mut resolver(unresolved_mark, top_level_mark, true))
43
+ module.fold_with(&mut resolver(
44
+ context.unresolved_mark,
45
+ context.top_level_mark,
46
+ true,
47
+ ))
48
});
49
42
- Ok(convert_program(&module))
50
+ Ok(convert_program(&context, &module))
51
})
52
}
53
46
-fn convert_program(program: &Program) -> estree::Program {
54
+#[derive(Debug)]
55
+struct Context {
56
+ unresolved_mark: Mark,
57
+ top_level_mark: Mark,
58
+}
59
+
60
+fn convert_program(cx: &Context, program: &Program) -> estree::Program {
61
let mut program_items: Vec<estree::ModuleItem>;
62
match program {
63
Program::Module(program) => {
64
let body = &program.body;
65
program_items = Vec::with_capacity(body.len());
66
for item in body {
53
- program_items.push(convert_module_item(item));
67
+ program_items.push(convert_module_item(cx, item));
68
}
69
}
70
Program::Script(program) => {
72
program_items = Vec::with_capacity(body.len());
73
for item in body {
74
program_items.push(estree::ModuleItem::Statement(Box::new(convert_statement(
61
- item,
75
+ cx, item,
76
))));
77
}
78
}
90
}
91
}
92
79
-fn convert_module_item(item: &ModuleItem) -> estree::ModuleItem {
93
+fn convert_module_item(cx: &Context, item: &ModuleItem) -> estree::ModuleItem {
94
match item {
81
- ModuleItem::Stmt(item) => estree::ModuleItem::Statement(Box::new(convert_statement(item))),
82
- _ => todo!(),
95
+ ModuleItem::Stmt(item) => {
96
+ estree::ModuleItem::Statement(Box::new(convert_statement(cx, item)))
97
+ }
98
+ _ => todo!("Convert {:#?}", item),
99
}
100
}
101
114
}
115
}
116
101
-fn convert_block_statement(stmt: &BlockStmt) -> estree::BlockStatement {
117
+fn convert_block_statement(cx: &Context, stmt: &BlockStmt) -> estree::BlockStatement {
118
let mut body: Vec<estree::Statement> = Vec::with_capacity(stmt.stmts.len());
119
for stmt in &stmt.stmts {
104
- body.push(convert_statement(stmt));
120
+ body.push(convert_statement(cx, stmt));
121
}
122
estree::BlockStatement {
123
body,
126
}
127
}
128
113
-fn convert_statement(stmt: &Stmt) -> estree::Statement {
129
+fn convert_statement(cx: &Context, stmt: &Stmt) -> estree::Statement {
130
match stmt {
131
Stmt::Decl(Decl::Fn(item)) => {
132
let name = item.ident.sym.to_string();
133
estree::Statement::FunctionDeclaration(Box::new(estree::FunctionDeclaration {
134
id: Some(estree::Identifier {
135
name,
136
+ binding: convert_binding(cx, item.ident.span.ctxt),
137
loc: None,
138
range: convert_span(&item.ident.span),
139
}),
141
.function
142
.params
143
.iter()
127
- .map(|param| convert_pattern(¶m.pat))
144
+ .map(|param| convert_pattern(cx, ¶m.pat))
145
.collect(),
146
body: item.function.body.as_ref().map(|body| {
130
- estree::Statement::BlockStatement(Box::new(convert_block_statement(body)))
147
+ estree::Statement::BlockStatement(Box::new(convert_block_statement(cx, body)))
148
}),
149
is_async: item.function.is_async,
150
is_generator: item.function.is_generator,
153
}))
154
}
155
Stmt::Block(item) => {
139
- estree::Statement::BlockStatement(Box::new(convert_block_statement(item)))
156
+ estree::Statement::BlockStatement(Box::new(convert_block_statement(cx, item)))
157
}
158
Stmt::Break(item) => estree::Statement::BreakStatement(Box::new(estree::BreakStatement {
142
- label: item.label.as_ref().map(|label| convert_identifier(label)),
159
+ label: item
160
+ .label
161
+ .as_ref()
162
+ .map(|label| convert_identifier(cx, label)),
163
loc: None,
164
range: convert_span(&item.span),
165
})),
166
Stmt::Continue(item) => {
167
estree::Statement::ContinueStatement(Box::new(estree::ContinueStatement {
148
- label: item.label.as_ref().map(|label| convert_identifier(label)),
168
+ label: item
169
+ .label
170
+ .as_ref()
171
+ .map(|label| convert_identifier(cx, label)),
172
loc: None,
173
range: convert_span(&item.span),
174
}))
181
}
182
Stmt::DoWhile(item) => {
183
estree::Statement::DoWhileStatement(Box::new(estree::DoWhileStatement {
161
- body: convert_statement(&item.body),
162
- test: convert_expression(&item.test),
184
+ body: convert_statement(cx, &item.body),
185
+ test: convert_expression(cx, &item.test),
186
loc: None,
187
range: convert_span(&item.span),
188
}))
192
range: convert_span(&item.span),
193
})),
194
Stmt::Expr(item) => {
172
- let expression = convert_expression(&item.expr);
195
+ let expression = convert_expression(cx, &item.expr);
196
estree::Statement::ExpressionStatement(Box::new(estree::ExpressionStatement {
197
expression,
198
directive: None,
203
Stmt::For(item) => estree::Statement::ForStatement(Box::new(estree::ForStatement {
204
init: item.init.as_ref().map(|init| match init {
205
VarDeclOrExpr::Expr(init) => {
183
- estree::ForInit::Expression(Box::new(convert_expression(init)))
206
+ estree::ForInit::Expression(Box::new(convert_expression(cx, init)))
207
}
208
VarDeclOrExpr::VarDecl(init) => {
209
assert_eq!(init.decls.len(), 1);
211
estree::ForInit::VariableDeclaration(Box::new(estree::VariableDeclaration {
212
kind: convert_decl_kind(&init.kind),
213
declarations: vec![estree::VariableDeclarator {
191
- id: convert_pattern(&decl.name),
192
- init: decl.init.as_ref().map(|init| convert_expression(init)),
214
+ id: convert_pattern(cx, &decl.name),
215
+ init: decl.init.as_ref().map(|init| convert_expression(cx, init)),
216
loc: None,
217
range: convert_span(&decl.span),
218
}],
221
}))
222
}
223
}),
201
- test: item.test.as_ref().map(|test| convert_expression(test)),
224
+ test: item.test.as_ref().map(|test| convert_expression(cx, test)),
225
update: item
226
.update
227
.as_ref()
205
- .map(|update| convert_expression(update)),
206
- body: convert_statement(&item.body),
228
+ .map(|update| convert_expression(cx, update)),
229
+ body: convert_statement(cx, &item.body),
230
loc: None,
231
range: convert_span(&item.span),
232
})),
233
Stmt::Return(item) => {
234
estree::Statement::ReturnStatement(Box::new(estree::ReturnStatement {
212
- argument: item.arg.as_ref().map(|arg| convert_expression(arg)),
235
+ argument: item.arg.as_ref().map(|arg| convert_expression(cx, arg)),
236
loc: None,
237
range: convert_span(&item.span),
238
}))
239
}
240
Stmt::Throw(item) => estree::Statement::ThrowStatement(Box::new(estree::ThrowStatement {
218
- argument: convert_expression(&item.arg),
241
+ argument: convert_expression(cx, &item.arg),
242
loc: None,
243
range: convert_span(&item.span),
244
})),
245
Stmt::If(item) => estree::Statement::IfStatement(Box::new(estree::IfStatement {
223
- test: convert_expression(&item.test),
224
- consequent: convert_statement(&item.cons),
225
- alternate: item.alt.as_ref().map(|alt| convert_statement(alt)),
246
+ test: convert_expression(cx, &item.test),
247
+ consequent: convert_statement(cx, &item.cons),
248
+ alternate: item.alt.as_ref().map(|alt| convert_statement(cx, alt)),
249
loc: None,
250
range: convert_span(&item.span),
251
})),
253
}
254
}
255
233
-fn convert_expression(expr: &Expr) -> estree::ExpressionLike {
256
+fn convert_expression(cx: &Context, expr: &Expr) -> estree::ExpressionLike {
257
match expr {
235
- Expr::Ident(expr) => estree::ExpressionLike::Identifier(Box::new(convert_identifier(expr))),
258
+ Expr::Ident(expr) => {
259
+ estree::ExpressionLike::Identifier(Box::new(convert_identifier(cx, expr)))
260
+ }
261
Expr::Array(expr) => {
262
estree::ExpressionLike::ArrayExpression(Box::new(estree::ArrayExpression {
263
elements: expr
269
match value.spread {
270
Some(spread) => estree::ExpressionLike::SpreadElement(Box::new(
271
estree::SpreadElement {
247
- argument: convert_expression(&value.expr),
272
+ argument: convert_expression(cx, &value.expr),
273
loc: None,
274
range: convert_span(&spread),
275
},
276
)),
252
- None => convert_expression(&value.expr),
277
+ None => convert_expression(cx, &value.expr),
278
}
279
})
280
.collect(),
284
}
285
Expr::Await(expr) => {
286
estree::ExpressionLike::AwaitExpression(Box::new(estree::AwaitExpression {
262
- argument: convert_expression(&expr.arg),
287
+ argument: convert_expression(cx, &expr.arg),
288
loc: None,
289
range: convert_span(&expr.span),
290
}))
293
estree::ExpressionLike::UnaryExpression(Box::new(estree::UnaryExpression {
294
operator: convert_unary_operator(expr.op),
295
is_prefix: false,
271
- argument: convert_expression(&expr.arg),
296
+ argument: convert_expression(cx, &expr.arg),
297
loc: None,
298
range: convert_span(&expr.span),
299
}))
302
Operator::Binary(op) => {
303
estree::ExpressionLike::BinaryExpression(Box::new(estree::BinaryExpression {
304
operator: op,
280
- left: convert_expression(&expr.left),
281
- right: convert_expression(&expr.right),
305
+ left: convert_expression(cx, &expr.left),
306
+ right: convert_expression(cx, &expr.right),
307
loc: None,
308
range: convert_span(&expr.span),
309
}))
311
Operator::Logical(op) => {
312
estree::ExpressionLike::LogicalExpression(Box::new(estree::LogicalExpression {
313
operator: op,
289
- left: convert_expression(&expr.left),
290
- right: convert_expression(&expr.right),
314
+ left: convert_expression(cx, &expr.left),
315
+ right: convert_expression(cx, &expr.right),
316
loc: None,
317
range: convert_span(&expr.span),
318
}))
346
estree::ExpressionLike::AssignmentExpression(Box::new(estree::AssignmentExpression {
347
operator: convert_assignment_operator(expr.op),
348
left: convert_assignment_target(&expr.left),
324
- right: convert_expression(&expr.right),
349
+ right: convert_expression(cx, &expr.right),
350
loc: None,
351
range: convert_span(&expr.span),
352
}))
414
}
415
}
416
392
-fn convert_pattern(pat: &Pat) -> estree::Pattern {
417
+fn convert_pattern(cx: &Context, pat: &Pat) -> estree::Pattern {
418
match pat {
419
Pat::Ident(pat) => estree::Pattern::Identifier(Box::new(estree::Identifier {
420
name: pat.id.sym.to_string(),
421
+ binding: convert_binding(cx, pat.id.span.ctxt),
422
loc: None,
423
range: convert_span(&pat.span),
424
})),
426
}
427
}
428
403
-fn convert_identifier(identifier: &Ident) -> estree::Identifier {
429
+fn convert_binding(context: &Context, binding_cx: SyntaxContext) -> Option<Binding> {
430
+ let id = BindingId::new(NonZeroU32::new(binding_cx.as_u32()).unwrap());
431
+ if binding_cx.as_u32() == context.top_level_mark.as_u32() {
432
+ Some(Binding::Global)
433
+ } else if binding_cx.as_u32() == context.unresolved_mark.as_u32() {
434
+ Some(Binding::Module(id))
435
+ } else {
436
+ Some(Binding::Local(id))
437
+ }
438
+}
439
+
440
+fn convert_identifier(cx: &Context, identifier: &Ident) -> estree::Identifier {
441
let name = identifier.sym.as_ref().to_string();
442
estree::Identifier {
443
name,
444
+ binding: convert_binding(cx, identifier.span.ctxt),
445
loc: None,
446
range: convert_span(&identifier.span),
447
}