From 7818a163712adada628ec3ece35c2a7c18a7b46d Mon Sep 17 00:00:00 2001 From: luckyadam Date: Wed, 11 Oct 2023 11:29:11 +0800 Subject: [PATCH] =?UTF-8?q?fix:=20=E4=BF=AE=E5=A4=8D=20JSX=20=E8=A7=A3?= =?UTF-8?q?=E6=9E=90=E6=8A=A5=E9=94=99=E9=97=AE=E9=A2=98?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- Cargo.lock | 235 +++++++++++++++++++++++++++++++++++ Cargo.toml | 2 + __test__/index.spec.mjs.md | 53 ++++++-- __test__/index.spec.mjs.snap | Bin 1687 -> 1873 bytes src/document.rs | 46 ++++--- src/lib.rs | 15 ++- src/main.rs | 49 ++++++++ src/style_write.rs | 6 +- src/visitor.rs | 14 +-- 9 files changed, 375 insertions(+), 45 deletions(-) create mode 100644 src/main.rs diff --git a/Cargo.lock b/Cargo.lock index d7d746d..baabf17 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -62,6 +62,12 @@ version = "1.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d468802bab17cbc0cc575e9b053f41e72aa36bfa6b7f55e3529ffa43161b97fa" +[[package]] +name = "base64" +version = "0.13.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9e1b586273c5702936fe7b7d6896644d8be71e6314cfe09d3167c95f712589e8" + [[package]] name = "base64-simd" version = "0.7.0" @@ -104,6 +110,15 @@ dependencies = [ "wyz", ] +[[package]] +name = "block-buffer" +version = "0.10.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3078c7629b62d3f0439517fa394996acacc5cbc91c5a20d8c658e77abd503a71" +dependencies = [ + "generic-array", +] + [[package]] name = "bytecheck" version = "0.6.11" @@ -176,6 +191,15 @@ dependencies = [ "unicode-segmentation", ] +[[package]] +name = "cpufeatures" +version = "0.2.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a17b76ff3a4162b0b27f354a0c87015ddad39d35f9c0c36607a3bdd175dde1f1" +dependencies = [ + "libc", +] + [[package]] name = "crossbeam-channel" version = "0.5.8" @@ -219,6 +243,16 @@ dependencies = [ "cfg-if", ] +[[package]] +name = "crypto-common" +version = "0.1.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1bfb12502f3fc46cca1bb51ac28df9d618d813cdc3d2f25b9fe775a34af26bb3" +dependencies = [ + "generic-array", + "typenum", +] + [[package]] name = "cssparser" version = "0.29.6" @@ -318,6 +352,16 @@ dependencies = [ "syn 1.0.109", ] +[[package]] +name = "digest" +version = "0.10.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9ed9a281f7bc9b7576e61468ba615a66a5c8cfdff42420a70aa82701a3b1e292" +dependencies = [ + "block-buffer", + "crypto-common", +] + [[package]] name = "dtoa" version = "1.0.9" @@ -391,6 +435,16 @@ dependencies = [ "byteorder", ] +[[package]] +name = "generic-array" +version = "0.14.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "85649ca51fd72272d7821adaf274ad91c288277713d9c18820d8499a7ff69e9a" +dependencies = [ + "typenum", + "version_check", +] + [[package]] name = "getrandom" version = "0.2.10" @@ -462,6 +516,16 @@ version = "1.0.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "cb56e1aa765b4b4f3aadfab769793b7087bb03a4ea4920644a6d238e2df5b9ed" +[[package]] +name = "indexmap" +version = "1.9.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bd070e393353796e801d209ad339e89596eb4c8d430d18ede6a1cced8fafbd99" +dependencies = [ + "autocfg", + "hashbrown 0.12.3", +] + [[package]] name = "is-macro" version = "0.3.0" @@ -792,7 +856,9 @@ dependencies = [ "swc_ecma_ast", "swc_ecma_codegen", "swc_ecma_parser", + "swc_ecma_transforms_base", "swc_ecma_visit", + "swc_ecmascript", ] [[package]] @@ -1145,6 +1211,12 @@ version = "1.0.15" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1ad4cc8da4ef723ed60bced201181d83791ad433213d8c24efffda1eec85d741" +[[package]] +name = "ryu-js" +version = "0.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6518fc26bced4d53678a22d6e423e9d8716377def84545fe328236e3af070e7f" + [[package]] name = "scoped-tls" version = "1.0.1" @@ -1243,6 +1315,17 @@ dependencies = [ "stable_deref_trait", ] +[[package]] +name = "sha-1" +version = "0.10.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "028f48d513f9678cda28f6e4064755b3fbb2af6acd672f2c209b62323f7aea0f" +dependencies = [ + "cfg-if", + "cpufeatures", + "digest", +] + [[package]] name = "simd-abstraction" version = "0.7.1" @@ -1410,6 +1493,31 @@ dependencies = [ "url", ] +[[package]] +name = "swc_config" +version = "0.1.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9ba1c7a40d38f9dd4e9a046975d3faf95af42937b34b2b963be4d8f01239584b" +dependencies = [ + "indexmap", + "serde", + "serde_json", + "swc_config_macro", +] + +[[package]] +name = "swc_config_macro" +version = "0.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e5b5aaca9a0082be4515f0fbbecc191bf5829cd25b5b9c0a2810f6a2bb0d6829" +dependencies = [ + "pmutil", + "proc-macro2", + "quote", + "swc_macros_common", + "syn 2.0.31", +] + [[package]] name = "swc_ecma_ast" version = "0.110.0" @@ -1478,6 +1586,116 @@ dependencies = [ "typed-arena", ] +[[package]] +name = "swc_ecma_transforms" +version = "0.225.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "579c71cbf89eb244bb1ce890360ef53e472fbd90a3bcd15d7d983c5d596d730d" +dependencies = [ + "swc_atoms", + "swc_common", + "swc_ecma_ast", + "swc_ecma_transforms_base", + "swc_ecma_transforms_typescript", + "swc_ecma_utils", + "swc_ecma_visit", +] + +[[package]] +name = "swc_ecma_transforms_base" +version = "0.134.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "45d22969bd30d953cd5d217dda6d50d0f2fc15e058c373cfdb9971a2f455e457" +dependencies = [ + "better_scoped_tls", + "bitflags 2.4.0", + "indexmap", + "once_cell", + "phf 0.10.1", + "rustc-hash", + "serde", + "smallvec", + "swc_atoms", + "swc_common", + "swc_ecma_ast", + "swc_ecma_parser", + "swc_ecma_utils", + "swc_ecma_visit", + "tracing", +] + +[[package]] +name = "swc_ecma_transforms_macros" +version = "0.5.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8188eab297da773836ef5cf2af03ee5cca7a563e1be4b146f8141452c28cc690" +dependencies = [ + "pmutil", + "proc-macro2", + "quote", + "swc_macros_common", + "syn 2.0.31", +] + +[[package]] +name = "swc_ecma_transforms_react" +version = "0.180.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f64686f3792449f6987859f94c9451fb03be8edc6284119887a419b70686b564" +dependencies = [ + "base64", + "dashmap", + "indexmap", + "once_cell", + "serde", + "sha-1", + "string_enum", + "swc_atoms", + "swc_common", + "swc_config", + "swc_ecma_ast", + "swc_ecma_parser", + "swc_ecma_transforms_base", + "swc_ecma_transforms_macros", + "swc_ecma_utils", + "swc_ecma_visit", +] + +[[package]] +name = "swc_ecma_transforms_typescript" +version = "0.184.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0773e1eb2b46a4157a3279cd850bd643577c50dc0fbae01f4fed8f36085335e6" +dependencies = [ + "ryu-js", + "serde", + "swc_atoms", + "swc_common", + "swc_ecma_ast", + "swc_ecma_transforms_base", + "swc_ecma_transforms_react", + "swc_ecma_utils", + "swc_ecma_visit", +] + +[[package]] +name = "swc_ecma_utils" +version = "0.124.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "83ded5277c882211a7271e285863bfec54715eafd9b2b4fd7421635310c9d3e4" +dependencies = [ + "indexmap", + "num_cpus", + "once_cell", + "rustc-hash", + "swc_atoms", + "swc_common", + "swc_ecma_ast", + "swc_ecma_visit", + "tracing", + "unicode-id", +] + [[package]] name = "swc_ecma_visit" version = "0.96.0" @@ -1492,6 +1710,17 @@ dependencies = [ "tracing", ] +[[package]] +name = "swc_ecmascript" +version = "0.235.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2e0e91dd82505839db27ae3731679aa005d07a493cffffa5650a93433d137eb4" +dependencies = [ + "swc_ecma_ast", + "swc_ecma_parser", + "swc_ecma_transforms", +] + [[package]] name = "swc_eq_ignore_macros" version = "0.1.2" @@ -1651,6 +1880,12 @@ version = "2.0.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "6af6ae20167a9ece4bcb41af5b80f8a1f1df981f6391189ce00fd257af04126a" +[[package]] +name = "typenum" +version = "1.17.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "42ff0bf0c66b8238c6f3b578df37d0b7848e55df8577b3f74f92a69acceeb825" + [[package]] name = "unicode-bidi" version = "0.3.13" diff --git a/Cargo.toml b/Cargo.toml index b4314ef..af9df2b 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -24,6 +24,8 @@ swc_ecma_ast = {version = "0.110.0"} swc_ecma_codegen = "0.146.0" swc_ecma_parser = "0.141.0" swc_ecma_visit = "0.96.0" +swc_ecmascript = {version = "0.235.1", features = ["transforms", "typescript"]} +swc_ecma_transforms_base = "0.134.0" [build-dependencies] napi-build = "2.0.1" diff --git a/__test__/index.spec.mjs.md b/__test__/index.spec.mjs.md index 3078e0c..33e6711 100644 --- a/__test__/index.spec.mjs.md +++ b/__test__/index.spec.mjs.md @@ -11,7 +11,7 @@ Generated by [AVA](https://avajs.dev). `import React from 'react';␊ import './Mod.scss';␊ function Cc() {␊ - return (
␊ + return
␊ ␊ 成员123: 4000+␊ ␊ @@ -25,11 +25,11 @@ Generated by [AVA](https://avajs.dev). ␊
␊ ␊ -
);␊ + ;␊ }␊ export default class Mod extends React.Component {␊ getDom() {␊ - return (
␊ + return
␊ ␊ 成员123: 4000+␊ ␊ @@ -43,10 +43,10 @@ Generated by [AVA](https://avajs.dev). ␊
␊ ␊ -
);␊ + ;␊ }␊ render() {␊ - return (
␊ ␊ -
);␊ + ;␊ }␊ - }␊ + } // function Mod() {␊ + // return (␊ + //
␊ + //
␊ + // ␊ + // 超能芭比 5分钟前查看团购␊ + //
␊ + //
␊ + // ␊ + //
␊ + // 巴拉巴拉小魔仙␊ + // 成员: 4000+␊ + //
␊ + //
␊ + // ␊ + // slslsl-jsj␊ + // 复制␊ + //
␊ + //
␊ + //
␊ + // ␊ + // 团长介绍:售前售后进群售前售后进群售前售后进群售前售后进群VXklsidohh...␊ + // ␊ + // ␊ + //
␊ + //
␊ + // )␊ + // }␊ ` diff --git a/__test__/index.spec.mjs.snap b/__test__/index.spec.mjs.snap index c83d5bfcc5a04a7b96e9fc1cdf65551cfd13e0e2..34cd99dab1d16dedf43e21c585a17604970e4192 100644 GIT binary patch literal 1873 zcmV-X2d?-*RzVW`^?M>{adj z!}KKBBp-_i00000000B+T1}7JL>OK`2x)KpgHbr76*%_zD^9ZAOHsw8Jx~e32|4yS znO(<@Jd^$CY7Z3xwNwiQ6$vO()v6o|9IA3C&_B~`w^H+4-m!FMJp5$3i@V15GJ14CtaVC>-TNjq~>R}g|`;oSqMLG zyuI-5oBs*8*Y^VoK1QZRffM*WPz}QCYHKm+s@BBIzFi|0A*|6EcoxOJ2QFIY&V#K* zz&-(@gTMnzHeLgkYZ7wB?4b))%c?FfMgjmVk-q7rJ6-G{2z_SI* zcm1IGp5r*WBemLoV52|?OdAhK)97!s*0D{yO+{7Mbr<1Imo}lUvm3|vsNk4A>~1!% z`h∋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 diff --git a/src/document.rs b/src/document.rs index b0e4210..46b10b4 100644 --- a/src/document.rs +++ b/src/document.rs @@ -4,11 +4,12 @@ use ego_tree::Tree; use swc_common::{ errors::{ColorConfig, Handler}, sync::Lrc, - SourceMap, + SourceMap, Mark, comments::SingleThreadedComments, Globals, GLOBALS, }; -use swc_ecma_ast::{EsVersion, Module}; +use swc_ecma_ast::{EsVersion, Program}; use swc_ecma_parser::{lexer::Lexer, Parser, StringInput, Syntax, TsConfig}; -use swc_ecma_visit::VisitWith; +use swc_ecma_visit::{VisitWith, FoldWith}; +use swc_ecma_transforms_base::{fixer::fixer, hygiene::hygiene, resolver}; use crate::{ scraper::{ElementRef, Node, Selector}, @@ -17,7 +18,7 @@ use crate::{ pub struct JSXDocument { pub tree: Tree, - pub module: Option, + pub program: Option, pub jsx_record: Option, } @@ -25,20 +26,17 @@ impl JSXDocument { pub fn new() -> Self { JSXDocument { tree: Tree::new(Node::Document), - module: None, + program: None, jsx_record: None, } } - pub fn parse(&mut self, jsx: String) { - // 初始化 swc 的 SourceMap - let cm: Lrc = Default::default(); + pub fn parse(&mut self, jsx: String, cm: Lrc, comments: &SingleThreadedComments) { // 初始化 swc 的错误处理器 let handler = Handler::with_tty_emitter(ColorConfig::Auto, true, false, Some(cm.clone())); // 将 JSX 代码转换为 SourceFile let fm = cm.new_source_file(swc_common::FileName::Anon, jsx); - // 初始化 swc 的词法分析器 let lexer = Lexer::new( Syntax::Typescript(TsConfig { @@ -48,23 +46,31 @@ impl JSXDocument { }), EsVersion::Es2019, StringInput::from(&*fm), - None, + Some(comments), ); // 初始化 swc 的语法分析器 let mut parser = Parser::new_from(lexer); for e in parser.take_errors() { e.into_diagnostic(&handler).emit(); } - - let module = parser - .parse_module() - .map_err(|e| e.into_diagnostic(&handler).emit()) - .expect("解析 JSX 失败"); - let mut jsx_record: JSXRecord = HashMap::new(); - let mut vistor = AstVisitor::new(&module, &mut self.tree, &mut jsx_record); - module.visit_with(&mut vistor); - self.module = Some(module); - self.jsx_record = Some(jsx_record); + let program = parser + .parse_program() + .map_err(|e| e.into_diagnostic(&handler).emit()) + .expect("解析 JSX 失败"); + + let globals = Globals::default(); + GLOBALS.set(&globals, || { + let unresolved_mark = Mark::new(); + let top_level_mark = Mark::new(); + let program = program.fold_with(&mut resolver(unresolved_mark, top_level_mark, true)); + let program = program.fold_with(&mut hygiene()); + let program = program.fold_with(&mut fixer(Some(comments))); + let mut jsx_record: JSXRecord = HashMap::new(); + let mut vistor = AstVisitor::new(&program, &mut self.tree, &mut jsx_record); + program.visit_with(&mut vistor); + self.program = Some(program); + self.jsx_record = Some(jsx_record); + }); } pub fn select<'a>(&self, selector: &'a Selector) -> Vec { diff --git a/src/lib.rs b/src/lib.rs index 418bd9d..3ae8411 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -2,7 +2,7 @@ use std::{cell::RefCell, rc::Rc}; -use swc_common::{comments::SingleThreadedComments, SourceMap}; +use swc_common::{comments::SingleThreadedComments, SourceMap, sync::Lrc}; use swc_ecma_codegen::{text_writer::JsWriter, Emitter}; use crate::{document::JSXDocument, style_parser::StyleParser, style_write::StyleWrite}; @@ -20,8 +20,10 @@ mod visitor; #[napi] pub fn parse(component: String, styles: Vec) -> String { // 解析组件文件 + let cm: Lrc = Default::default(); + let comments = SingleThreadedComments::default(); let mut document = JSXDocument::new(); - document.parse(component); + document.parse(component, cm.clone(), &comments); // 解析样式文件 let css = styles.join("\n"); @@ -29,16 +31,13 @@ pub fn parse(component: String, styles: Vec) -> String { style_parser.parse(&css); let style_record = style_parser.calc(); - let module = Rc::new(RefCell::new(document.module.as_ref().unwrap().clone())); + let program = Rc::new(RefCell::new(document.program.as_ref().unwrap().clone())); let jsx_record = Rc::new(RefCell::new(document.jsx_record.as_ref().unwrap().clone())); let style_record = Rc::new(RefCell::new(style_record)); - let mut style_write = StyleWrite::new(module.clone(), jsx_record.clone(), style_record.clone()); + let mut style_write = StyleWrite::new(program.clone(), jsx_record.clone(), style_record.clone()); style_write.write(); // ast 转代码 - let cm = Rc::new(SourceMap::default()); - let comments = SingleThreadedComments::default(); - let mut buf = Vec::new(); { let writer = Box::new(JsWriter::new(cm.clone(), "\n", &mut buf, None)); @@ -48,7 +47,7 @@ pub fn parse(component: String, styles: Vec) -> String { wr: writer, comments: Some(&comments), }; - emitter.emit_module(&module.borrow()).unwrap(); + emitter.emit_program(&program.borrow()).unwrap(); } let code = String::from_utf8(buf).unwrap().replace("\r\n", "\n"); code diff --git a/src/main.rs b/src/main.rs new file mode 100644 index 0000000..5bcbcea --- /dev/null +++ b/src/main.rs @@ -0,0 +1,49 @@ +use std::{fs, rc::Rc, cell::RefCell}; + +use swc_common::{SourceMap, comments::SingleThreadedComments, sync::Lrc}; +use swc_ecma_codegen::{text_writer::JsWriter, Emitter}; + +use crate::{document::JSXDocument, style_parser::StyleParser, style_write::StyleWrite}; + +mod document; +mod scraper; +mod utils; +mod visitor; +mod style_parser; +mod style_write; + +fn main() { + // 使用 swc 解析 JSX + let jsx = fs::read_to_string("__test__/fixure/mod.jsx").unwrap(); + let css = fs::read_to_string("__test__/fixure/Mod.scss").unwrap(); + let cm: Lrc = Default::default(); + let comments = SingleThreadedComments::default(); + let mut document = JSXDocument::new(); + document.parse(jsx, cm.clone(), &comments); + + println!(); + let mut style_parser = StyleParser::new(&document); + style_parser.parse(&css); + let style_record = style_parser.calc(); + + // println!("{:?}", style_record) + let program = Rc::new(RefCell::new(document.program.as_ref().unwrap().clone())); + let jsx_record = Rc::new(RefCell::new(document.jsx_record.as_ref().unwrap().clone())); + let style_record = Rc::new(RefCell::new(style_record)); + let mut style_write = StyleWrite::new(program.clone(), jsx_record.clone(), style_record.clone()); + style_write.write(); + + // ast 转代码 + let mut buf = vec![]; + { + let mut emitter = Emitter { + cfg: swc_ecma_codegen::Config::default(), + cm: cm.clone(), + comments: Some(&comments), + wr: JsWriter::new(cm.clone(), "\n", &mut buf, None), + }; + emitter.emit_program(&program.borrow()).unwrap(); + } + let code = String::from_utf8(buf).unwrap().replace("\r\n", "\n"); + println!("{}", code); +} diff --git a/src/style_write.rs b/src/style_write.rs index 7ac2655..4a75ab8 100644 --- a/src/style_write.rs +++ b/src/style_write.rs @@ -1,7 +1,7 @@ use std::{cell::RefCell, collections::HashMap, rc::Rc}; use ego_tree::NodeId; -use swc_ecma_ast::Module; +use swc_ecma_ast::Program; use swc_ecma_visit::VisitMutWith; use crate::{ @@ -10,14 +10,14 @@ use crate::{ }; pub struct StyleWrite<'i> { - pub module: Rc>, + pub module: Rc>, pub jsx_record: Rc>, pub style_record: Rc>>>, } impl<'i> StyleWrite<'i> { pub fn new( - module: Rc>, + module: Rc>, jsx_record: Rc>, style_record: Rc>>>, ) -> Self { diff --git a/src/visitor.rs b/src/visitor.rs index a9b0f4c..3aaf152 100644 --- a/src/visitor.rs +++ b/src/visitor.rs @@ -12,7 +12,7 @@ use swc_common::{Span, DUMMY_SP}; use swc_ecma_ast::{ Callee, ClassDecl, ClassMember, DefaultDecl, ExportDefaultDecl, ExportDefaultExpr, Expr, FnDecl, Function, Ident, JSXAttr, JSXAttrName, JSXAttrOrSpread, JSXAttrValue, JSXElement, - JSXElementChild, JSXElementName, JSXExpr, KeyValueProp, Lit, MemberProp, Module, Prop, PropName, + JSXElementChild, JSXElementName, JSXExpr, KeyValueProp, Lit, MemberProp, Program, Prop, PropName, PropOrSpread, Stmt, Str, }; use swc_ecma_visit::{ @@ -52,14 +52,14 @@ fn recursion_sub_tree<'a>(node: &NodeRef, current: &mut NodeMut<'a, Node>) pub struct JSXVisitor<'a> { pub tree: &'a mut Tree, - pub module: &'a Module, + pub module: &'a Program, pub jsx_record: &'a mut JSXRecord, pub root_node: Option, pub current_node: Option, } impl<'a> JSXVisitor<'a> { - pub fn new(tree: &'a mut Tree, module: &'a Module, jsx_record: &'a mut JSXRecord) -> Self { + pub fn new(tree: &'a mut Tree, module: &'a Program, jsx_record: &'a mut JSXRecord) -> Self { JSXVisitor { tree, module, @@ -295,7 +295,7 @@ pub enum SearchType { } pub struct JSXFragmentVisitor<'a> { - pub module: &'a Module, + pub module: &'a Program, pub tree: Tree, pub jsx_record: &'a mut JSXRecord, pub search_fn: &'a str, @@ -304,7 +304,7 @@ pub struct JSXFragmentVisitor<'a> { impl<'a> JSXFragmentVisitor<'a> { pub fn new( - module: &'a Module, + module: &'a Program, jsx_record: &'a mut JSXRecord, search_fn: &'a str, search_type: SearchType, @@ -377,13 +377,13 @@ impl<'a> Visit for JSXFragmentVisitor<'a> { pub struct AstVisitor<'a> { pub export_default_name: Option, - pub module: &'a Module, + pub module: &'a Program, pub tree: &'a mut Tree, pub jsx_record: &'a mut JSXRecord, } impl<'a> AstVisitor<'a> { - pub fn new(module: &'a Module, tree: &'a mut Tree, jsx_record: &'a mut JSXRecord) -> Self { + pub fn new(module: &'a Program, tree: &'a mut Tree, jsx_record: &'a mut JSXRecord) -> Self { AstVisitor { export_default_name: None, module,