swc_ast_explorer/
main.rs

1use std::{
2    io::{Read, stdin},
3    sync::Arc,
4};
5
6use anyhow::Result;
7use clap::Parser;
8use owo_colors::OwoColorize;
9use regex::{NoExpand, Regex};
10use swc_core::{
11    base::{Compiler, HandlerOpts, config::IsModule, try_with_handler},
12    common::{GLOBALS, Globals, SourceMap, errors::ColorConfig, source_map::FileName},
13    ecma::{
14        ast::EsVersion,
15        parser::{Syntax, TsSyntax},
16    },
17};
18
19#[derive(Parser, Debug)]
20#[clap(author, version, about, long_about = None)]
21struct Args {
22    /// Whether to keep Span (location) markers
23    #[clap(long, value_parser, default_value_t = false)]
24    spans: bool,
25}
26
27fn main() -> Result<()> {
28    let args = Args::parse();
29
30    let mut contents = String::new();
31    stdin().read_to_string(&mut contents)?;
32
33    let sm = Arc::new(SourceMap::default());
34    let file = sm.new_source_file(FileName::Anon.into(), contents);
35    let target = EsVersion::latest();
36    let syntax = Syntax::Typescript(TsSyntax {
37        tsx: true,
38        decorators: false,
39        dts: false,
40        no_early_errors: true,
41        disallow_ambiguous_jsx_like: false,
42    });
43
44    let compiler = Compiler::new(sm.clone());
45    let res = GLOBALS
46        .set(&Globals::new(), || {
47            try_with_handler(
48                sm,
49                HandlerOpts {
50                    color: ColorConfig::Always,
51                    skip_filename: false,
52                },
53                |handler| compiler.parse_js(file, handler, target, syntax, IsModule::Unknown, None),
54            )
55        })
56        .map_err(|e| e.to_pretty_error());
57
58    let print = format!("{:#?}", res?);
59
60    let stripped = if args.spans {
61        print
62    } else {
63        let span = Regex::new(r"(?m)^\s+\w+: Span \{[^}]*\},\n").unwrap();
64        span.replace_all(&print, NoExpand("")).to_string()
65    };
66
67    let alternate_ws = Regex::new(r" {8}").unwrap();
68    let alternating = alternate_ws.replace_all(
69        &stripped,
70        NoExpand(&format!(
71            "{}{}",
72            "    ".on_default_color(),
73            "    ".on_black()
74        )),
75    );
76    let ws = Regex::new(r" {4}").unwrap();
77    println!("{}", ws.replace_all(&alternating, NoExpand("  ")));
78
79    Ok(())
80}