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