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 #[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 ..Default::default()
39 });
40
41 let compiler = Compiler::new(sm.clone());
42 let res = GLOBALS
43 .set(&Globals::new(), || {
44 try_with_handler(
45 sm,
46 HandlerOpts {
47 color: ColorConfig::Always,
48 skip_filename: false,
49 },
50 |handler| compiler.parse_js(file, handler, target, syntax, IsModule::Unknown, None),
51 )
52 })
53 .map_err(|e| e.to_pretty_error());
54
55 let print = format!("{:#?}", res?);
56
57 let stripped = if args.spans {
58 print
59 } else {
60 let span = Regex::new(r"(?m)^\s+\w+: Span \{[^}]*\},\n").unwrap();
61 span.replace_all(&print, NoExpand("")).to_string()
62 };
63
64 let alternate_ws = Regex::new(r" {8}").unwrap();
65 let alternating = alternate_ws.replace_all(
66 &stripped,
67 NoExpand(&format!(
68 "{}{}",
69 " ".on_default_color(),
70 " ".on_black()
71 )),
72 );
73 let ws = Regex::new(r" {4}").unwrap();
74 println!("{}", ws.replace_all(&alternating, NoExpand(" ")));
75
76 Ok(())
77}