next_swc_napi/
parse.rs

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}