next_swc_napi/
react_compiler.rs

1use std::{path::PathBuf, sync::Arc};
2
3use napi::bindgen_prelude::*;
4use next_custom_transforms::react_compiler;
5use swc_core::{
6    common::{GLOBALS, SourceMap},
7    ecma::{
8        ast::EsVersion,
9        parser::{Syntax, TsSyntax, parse_file_as_program},
10    },
11};
12
13pub struct CheckTask {
14    pub filename: PathBuf,
15}
16
17#[napi]
18impl Task for CheckTask {
19    type Output = bool;
20    type JsValue = bool;
21
22    fn compute(&mut self) -> napi::Result<Self::Output> {
23        GLOBALS.set(&Default::default(), || {
24            //
25            let cm = Arc::new(SourceMap::default());
26            let Ok(fm) = cm.load_file(&self.filename.clone()) else {
27                return Ok(false);
28            };
29            let mut errors = vec![];
30            let Ok(program) = parse_file_as_program(
31                &fm,
32                Syntax::Typescript(TsSyntax {
33                    tsx: true,
34                    ..Default::default()
35                }),
36                EsVersion::EsNext,
37                None,
38                &mut errors,
39            ) else {
40                return Ok(false);
41            };
42            if !errors.is_empty() {
43                return Ok(false);
44            }
45
46            Ok(react_compiler::is_required(&program))
47        })
48    }
49
50    fn resolve(&mut self, _env: Env, result: Self::Output) -> napi::Result<Self::JsValue> {
51        Ok(result)
52    }
53}
54
55#[napi]
56pub fn is_react_compiler_required(
57    filename: String,
58    signal: Option<AbortSignal>,
59) -> AsyncTask<CheckTask> {
60    let filename = PathBuf::from(filename);
61    AsyncTask::with_optional_signal(CheckTask { filename }, signal)
62}