1use std::sync::Arc;
2
3use anyhow::Context as _;
4use napi::bindgen_prelude::*;
5use napi_derive::napi;
6use swc_core::{
7 base::{config::ParseOptions, try_with_handler},
8 common::{
9 FileName, FilePathMapping, GLOBALS, SourceMap, comments::Comments, errors::ColorConfig,
10 },
11};
12
13use crate::util::MapErr;
14
15pub struct ParseTask {
16 pub filename: FileName,
17 pub src: String,
18 pub options: Buffer,
19}
20
21#[napi]
22impl Task for ParseTask {
23 type Output = String;
24 type JsValue = String;
25
26 fn compute(&mut self) -> napi::Result<Self::Output> {
27 GLOBALS.set(&Default::default(), || {
28 let c =
29 swc_core::base::Compiler::new(Arc::new(SourceMap::new(FilePathMapping::empty())));
30
31 let options: ParseOptions = serde_json::from_slice(self.options.as_ref())?;
32 let comments = c.comments().clone();
33 let comments: Option<&dyn Comments> = if options.comments {
34 Some(&comments)
35 } else {
36 None
37 };
38 let fm =
39 c.cm.new_source_file(self.filename.clone().into(), self.src.clone());
40 let program = try_with_handler(
41 c.cm.clone(),
42 swc_core::base::HandlerOpts {
43 color: ColorConfig::Never,
44 skip_filename: false,
45 },
46 |handler| {
47 c.parse_js(
48 fm,
49 handler,
50 options.target,
51 options.syntax,
52 options.is_module,
53 comments,
54 )
55 },
56 )
57 .map_err(|e| e.to_pretty_error())
58 .convert_err()?;
59
60 let ast_json = serde_json::to_string(&program)
61 .context("failed to serialize Program")
62 .convert_err()?;
63
64 Ok(ast_json)
65 })
66 }
67
68 fn resolve(&mut self, _env: Env, result: Self::Output) -> napi::Result<Self::JsValue> {
69 Ok(result)
70 }
71}
72
73#[napi]
74pub fn parse(
75 src: String,
76 options: Buffer,
77 filename: Option<String>,
78 signal: Option<AbortSignal>,
79) -> AsyncTask<ParseTask> {
80 let filename = if let Some(value) = filename {
81 FileName::Real(value.into())
82 } else {
83 FileName::Anon
84 };
85 AsyncTask::with_optional_signal(
86 ParseTask {
87 filename,
88 src,
89 options,
90 },
91 signal,
92 )
93}