next_swc_napi/
parse.rs

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}