next_swc_napi/
react_compiler.rs

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