refactor(isolated-declarations): decouple codegen (#3715)

This commit is contained in:
Boshen 2024-06-17 11:45:29 +00:00
parent 87c3282deb
commit 815260ed2f
6 changed files with 37 additions and 42 deletions

View file

@ -19,7 +19,7 @@ pub fn get_leading_annotate_comment<const MINIFY: bool>(
CommentKind::SingleLine => comment.end, CommentKind::SingleLine => comment.end,
CommentKind::MultiLine => comment.end + 2, CommentKind::MultiLine => comment.end + 2,
}; };
let source_code = codegen.source_code; let source_code = codegen.source_text;
let content_between = &source_code[real_end as usize..node_start as usize]; let content_between = &source_code[real_end as usize..node_start as usize];
// Used for VariableDeclaration (Rollup only respects "const" and only for the first one) // Used for VariableDeclaration (Rollup only respects "const" and only for the first one)
if content_between.chars().all(|ch| ch.is_ascii_whitespace()) { if content_between.chars().all(|ch| ch.is_ascii_whitespace()) {

View file

@ -72,7 +72,7 @@ impl<'a, const MINIFY: bool> From<Codegen<'a, MINIFY>> for Cow<'a, str> {
pub struct Codegen<'a, const MINIFY: bool> { pub struct Codegen<'a, const MINIFY: bool> {
options: CodegenOptions, options: CodegenOptions,
source_code: &'a str, source_text: &'a str,
trivias: Trivias, trivias: Trivias,
@ -116,24 +116,24 @@ pub enum Separator {
impl<'a, const MINIFY: bool> Codegen<'a, MINIFY> { impl<'a, const MINIFY: bool> Codegen<'a, MINIFY> {
pub fn new( pub fn new(
source_name: &str, source_name: &str,
source_code: &'a str, source_text: &'a str,
trivias: Trivias, trivias: Trivias,
options: CodegenOptions, options: CodegenOptions,
) -> Self { ) -> Self {
// Initialize the output code buffer to reduce memory reallocation. // Initialize the output code buffer to reduce memory reallocation.
// Minification will reduce by at least half of the original size. // Minification will reduce by at least half of the original size.
let source_len = source_code.len(); let source_len = source_text.len();
let capacity = if MINIFY { source_len / 2 } else { source_len }; let capacity = if MINIFY { source_len / 2 } else { source_len };
let sourcemap_builder = options.enable_source_map.then(|| { let sourcemap_builder = options.enable_source_map.then(|| {
let mut sourcemap_builder = SourcemapBuilder::default(); let mut sourcemap_builder = SourcemapBuilder::default();
sourcemap_builder.with_name_and_source(source_name, source_code); sourcemap_builder.with_name_and_source(source_name, source_text);
sourcemap_builder sourcemap_builder
}); });
Self { Self {
options, options,
source_code, source_text,
trivias, trivias,
// mangler: None, // mangler: None,
code: Vec::with_capacity(capacity), code: Vec::with_capacity(capacity),
@ -192,7 +192,7 @@ impl<'a, const MINIFY: bool> Codegen<'a, MINIFY> {
/// Since if you want to print a range of source code, you need to borrow the source code /// Since if you want to print a range of source code, you need to borrow the source code
/// immutable first, and call the [Self::print_str] which is a mutable borrow. /// immutable first, and call the [Self::print_str] which is a mutable borrow.
pub fn print_range_of_source_code(&mut self, range: Range<usize>) { pub fn print_range_of_source_code(&mut self, range: Range<usize>) {
self.code.extend_from_slice(self.source_code[range].as_bytes()); self.code.extend_from_slice(self.source_text[range].as_bytes());
} }
/// In some scenario, we want to move the comment that should be codegened to another position. /// In some scenario, we want to move the comment that should be codegened to another position.

View file

@ -20,7 +20,6 @@ workspace = true
doctest = false doctest = false
[dependencies] [dependencies]
oxc_codegen = { workspace = true }
oxc_ast = { workspace = true } oxc_ast = { workspace = true }
oxc_span = { workspace = true } oxc_span = { workspace = true }
oxc_allocator = { workspace = true } oxc_allocator = { workspace = true }
@ -30,7 +29,5 @@ oxc_syntax = { workspace = true, features = ["to_js_string"] }
rustc-hash = { workspace = true } rustc-hash = { workspace = true }
[dev-dependencies] [dev-dependencies]
oxc_parser = { workspace = true } oxc_parser = { workspace = true }
oxc_codegen = { workspace = true }
[features]
default = []

View file

@ -2,6 +2,8 @@
use std::{env, path::Path}; use std::{env, path::Path};
use oxc_allocator::Allocator; use oxc_allocator::Allocator;
use oxc_ast::Trivias;
use oxc_codegen::{Codegen, CodegenOptions};
use oxc_isolated_declarations::TransformerDts; use oxc_isolated_declarations::TransformerDts;
use oxc_parser::Parser; use oxc_parser::Parser;
use oxc_span::SourceType; use oxc_span::SourceType;
@ -31,11 +33,14 @@ fn main() {
println!("Original:\n"); println!("Original:\n");
println!("{source_text}\n"); println!("{source_text}\n");
let program = ret.program; let ret = TransformerDts::new(&allocator).build(&ret.program);
let ret = TransformerDts::new(&allocator, path, &source_text, ret.trivias).build(&program); let printed =
Codegen::<false>::new("", &source_text, Trivias::default(), CodegenOptions::default())
.build(&ret.program)
.source_text;
println!("Transformed dts:\n"); println!("Dts Emit:\n");
println!("{}\n", ret.source_text); println!("{printed}\n");
if !ret.errors.is_empty() { if !ret.errors.is_empty() {
println!("Transformed dts failed:\n"); println!("Transformed dts failed:\n");

View file

@ -17,20 +17,18 @@ mod return_type;
mod scope; mod scope;
mod types; mod types;
use std::{collections::VecDeque, path::Path, rc::Rc}; use std::{collections::VecDeque, rc::Rc};
use context::{Ctx, TransformDtsCtx}; use context::{Ctx, TransformDtsCtx};
use oxc_allocator::Allocator; use oxc_allocator::Allocator;
use oxc_ast::Trivias;
#[allow(clippy::wildcard_imports)] #[allow(clippy::wildcard_imports)]
use oxc_ast::{ast::*, Visit}; use oxc_ast::{ast::*, Visit};
use oxc_codegen::{Codegen, CodegenOptions};
use oxc_diagnostics::OxcDiagnostic; use oxc_diagnostics::OxcDiagnostic;
use oxc_span::{SourceType, SPAN}; use oxc_span::{SourceType, SPAN};
use scope::ScopeTree; use scope::ScopeTree;
pub struct TransformerDtsReturn { pub struct TransformerDtsReturn<'a> {
pub source_text: String, pub program: Program<'a>,
pub errors: Vec<OxcDiagnostic>, pub errors: Vec<OxcDiagnostic>,
} }
@ -40,13 +38,7 @@ pub struct TransformerDts<'a> {
} }
impl<'a> TransformerDts<'a> { impl<'a> TransformerDts<'a> {
#[allow(clippy::needless_pass_by_value)] pub fn new(allocator: &'a Allocator) -> Self {
pub fn new(
allocator: &'a Allocator,
_source_path: &Path,
_source_text: &'a str,
_trivias: Trivias,
) -> Self {
let ctx = Rc::new(TransformDtsCtx::new(allocator)); let ctx = Rc::new(TransformDtsCtx::new(allocator));
Self { ctx, scope: ScopeTree::new(allocator) } Self { ctx, scope: ScopeTree::new(allocator) }
} }
@ -54,17 +46,12 @@ impl<'a> TransformerDts<'a> {
/// # Errors /// # Errors
/// ///
/// Returns `Vec<Error>` if any errors were collected during the transformation. /// Returns `Vec<Error>` if any errors were collected during the transformation.
pub fn build(mut self, program: &Program<'a>) -> TransformerDtsReturn { pub fn build(mut self, program: &Program<'a>) -> TransformerDtsReturn<'a> {
let source_type = SourceType::default().with_module(true).with_typescript_definition(true); let source_type = SourceType::default().with_module(true).with_typescript_definition(true);
let directives = self.ctx.ast.new_vec(); let directives = self.ctx.ast.new_vec();
let stmts = self.transform_program(program); let stmts = self.transform_program(program);
let program = self.ctx.ast.program(SPAN, source_type, directives, None, stmts); let program = self.ctx.ast.program(SPAN, source_type, directives, None, stmts);
let source_text = TransformerDtsReturn { program, errors: self.ctx.take_errors() }
Codegen::<false>::new("", "", Trivias::default(), CodegenOptions::default())
.build(&program)
.source_text;
TransformerDtsReturn { source_text, errors: self.ctx.take_errors() }
} }
} }

View file

@ -3,7 +3,10 @@
use std::path::{Path, PathBuf}; use std::path::{Path, PathBuf};
use oxc_allocator::Allocator; use oxc_allocator::Allocator;
use oxc_isolated_declarations::{TransformerDts, TransformerDtsReturn}; use oxc_ast::Trivias;
use oxc_codegen::{Codegen, CodegenOptions};
use oxc_diagnostics::OxcDiagnostic;
use oxc_isolated_declarations::TransformerDts;
use oxc_parser::Parser; use oxc_parser::Parser;
use oxc_span::SourceType; use oxc_span::SourceType;
@ -137,13 +140,12 @@ impl TypeScriptTranspileCase {
} }
for unit in &self.units { for unit in &self.units {
let ret = transpile(&self.path, &unit.content); let (source_text, errors) = transpile(&self.path, &unit.content);
let baseline = Baseline { let baseline = Baseline {
name: change_extension(&unit.name), name: change_extension(&unit.name),
original: unit.content.clone(), original: unit.content.clone(),
oxc_printed: ret.source_text, oxc_printed: source_text,
diagnostic: ret diagnostic: errors
.errors
.into_iter() .into_iter()
.map(|e| e.message.clone()) .map(|e| e.message.clone())
.collect::<Vec<_>>() .collect::<Vec<_>>()
@ -160,9 +162,13 @@ fn change_extension(name: &str) -> String {
Path::new(name).with_extension("").with_extension("d.ts").to_str().unwrap().to_string() Path::new(name).with_extension("").with_extension("d.ts").to_str().unwrap().to_string()
} }
fn transpile(path: &Path, source_text: &str) -> TransformerDtsReturn { fn transpile(path: &Path, source_text: &str) -> (String, Vec<OxcDiagnostic>) {
let allocator = Allocator::default(); let allocator = Allocator::default();
let source_type = SourceType::from_path(path).unwrap(); let source_type = SourceType::from_path(path).unwrap();
let ret = Parser::new(&allocator, source_text, source_type).parse(); let ret = Parser::new(&allocator, source_text, source_type).parse();
TransformerDts::new(&allocator, path, source_text, ret.trivias).build(&ret.program) let ret = TransformerDts::new(&allocator).build(&ret.program);
let printed = Codegen::<false>::new("", "", Trivias::default(), CodegenOptions::default())
.build(&ret.program)
.source_text;
(printed, ret.errors)
} }