70 %
Chris Biscardi

How to print a JavaScript AST using SWC and Rust

Given a JavaScript file like this, how can we get an AST from it?

foo.js
javascript
import Thing from "a-place";
export const Something = {
some: "object",
};

We can use swc to parse the source file into an AST using parse_js.

rust
use std::{path::Path, sync::Arc};
use swc::config::JscTarget;
use swc_common::{
errors::{ColorConfig, Handler},
SourceMap,
};
use swc_ecma_parser::{EsConfig, Syntax};
fn main() {
let cm = Arc::<SourceMap>::default();
let handler = Arc::new(Handler::with_tty_emitter(
ColorConfig::Auto,
true,
false,
Some(cm.clone()),
));
let c = swc::Compiler::new(cm.clone(), handler.clone());
let fm = cm
.load_file(Path::new("foo.js"))
.expect("failed to load file");
let result = c.parse_js(
fm,
JscTarget::Es2020,
Syntax::Es(EsConfig::default()),
true,
false,
);
dbg!(result);
}

And the resulting AST looks like this, with all of the positional information included.

program-ast.rs
rust
[src/main.rs:28] result = Ok(
Module(
Module {
span: Span {
lo: BytePos(
0,
),
hi: BytePos(
77,
),
ctxt: #0,
},
body: [
ModuleDecl(
Import(
ImportDecl {
span: Span {
lo: BytePos(
0,
),
hi: BytePos(
28,
),
ctxt: #0,
},
specifiers: [
Default(
ImportDefaultSpecifier {
span: Span {
lo: BytePos(
7,
),
hi: BytePos(
12,
),
ctxt: #0,
},
local: Ident {
span: Span {
lo: BytePos(
7,
),
hi: BytePos(
12,
),
ctxt: #0,
},
sym: Atom('Thing' type=inline),
optional: false,
},
},
),
],
src: Str {
span: Span {
lo: BytePos(
18,
),
hi: BytePos(
27,
),
ctxt: #0,
},
value: Atom('a-place' type=inline),
has_escape: false,
kind: Normal {
contains_quote: true,
},
},
type_only: false,
asserts: None,
},
),
),
ModuleDecl(
ExportDecl(
ExportDecl {
span: Span {
lo: BytePos(
30,
),
hi: BytePos(
77,
),
ctxt: #0,
},
decl: Var(
VarDecl {
span: Span {
lo: BytePos(
37,
),
hi: BytePos(
77,
),
ctxt: #0,
},
kind: "const",
declare: false,
decls: [
VarDeclarator {
span: Span {
lo: BytePos(
43,
),
hi: BytePos(
76,
),
ctxt: #0,
},
name: Ident(
BindingIdent {
id: Ident {
span: Span {
lo: BytePos(
43,
),
hi: BytePos(
52,
),
ctxt: #0,
},
sym: Atom('Something' type=dynamic),
optional: false,
},
type_ann: None,
},
),
init: Some(
Object(
ObjectLit {
span: Span {
lo: BytePos(
55,
),
hi: BytePos(
76,
),
ctxt: #0,
},
props: [
Prop(
KeyValue(
KeyValueProp {
key: Ident(
Ident {
span: Span {
lo: BytePos(
59,
),
hi: BytePos(
63,
),
ctxt: #0,
},
sym: Atom('some' type=inline),
optional: false,
},
),
value: Lit(
Str(
Str {
span: Span {
lo: BytePos(
65,
),
hi: BytePos(
73,
),
ctxt: #0,
},
value: Atom('object' type=static),
has_escape: false,
kind: Normal {
contains_quote: true,
},
},
),
),
},
),
),
],
},
),
),
definite: false,
},
],
},
),
},
),
),
],
shebang: None,
},
),
)