Skip to content

Commit

Permalink
feat(oxc,napi/transform): napi/transform use oxc compiler pipeline (#…
Browse files Browse the repository at this point in the history
…6298)

part of #6156
  • Loading branch information
Boshen committed Oct 5, 2024
1 parent 0cea6e9 commit 8729755
Show file tree
Hide file tree
Showing 9 changed files with 305 additions and 229 deletions.
1 change: 0 additions & 1 deletion Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

108 changes: 93 additions & 15 deletions crates/oxc/src/compiler.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,14 +2,18 @@ use std::{mem, ops::ControlFlow, path::Path};

use oxc_allocator::Allocator;
use oxc_ast::{ast::Program, Trivias};
use oxc_codegen::{CodeGenerator, CodegenOptions, CommentOptions};
use oxc_codegen::{CodeGenerator, CodegenOptions, CodegenReturn, CommentOptions};
use oxc_diagnostics::OxcDiagnostic;
use oxc_isolated_declarations::{IsolatedDeclarations, IsolatedDeclarationsOptions};
use oxc_mangler::{MangleOptions, Mangler};
use oxc_minifier::{CompressOptions, Compressor};
use oxc_parser::{ParseOptions, Parser, ParserReturn};
use oxc_semantic::{ScopeTree, SemanticBuilder, SemanticBuilderReturn, SymbolTable};
use oxc_span::SourceType;
use oxc_transformer::{TransformOptions, Transformer, TransformerReturn};
use oxc_transformer::{
InjectGlobalVariables, InjectGlobalVariablesConfig, ReplaceGlobalDefines,
ReplaceGlobalDefinesConfig, TransformOptions, Transformer, TransformerReturn,
};

#[derive(Default)]
pub struct Compiler {
Expand All @@ -22,8 +26,8 @@ impl CompilerInterface for Compiler {
self.errors.extend(errors);
}

fn after_codegen(&mut self, printed: String) {
self.printed = printed;
fn after_codegen(&mut self, ret: CodegenReturn) {
self.printed = ret.source_text;
}
}

Expand All @@ -49,14 +53,30 @@ impl Compiler {
pub trait CompilerInterface {
fn handle_errors(&mut self, _errors: Vec<OxcDiagnostic>) {}

fn enable_sourcemap(&self) -> bool {
false
}

fn parse_options(&self) -> ParseOptions {
ParseOptions::default()
}

fn isolated_declaration_options(&self) -> Option<IsolatedDeclarationsOptions> {
None
}

fn transform_options(&self) -> Option<TransformOptions> {
Some(TransformOptions::default())
}

fn define_options(&self) -> Option<ReplaceGlobalDefinesConfig> {
None
}

fn inject_options(&self) -> Option<InjectGlobalVariablesConfig> {
None
}

fn compress_options(&self) -> Option<CompressOptions> {
None
}
Expand Down Expand Up @@ -89,6 +109,8 @@ pub trait CompilerInterface {
ControlFlow::Continue(())
}

fn after_isolated_declarations(&mut self, _ret: CodegenReturn) {}

fn after_transform(
&mut self,
_program: &mut Program<'_>,
Expand All @@ -97,7 +119,7 @@ pub trait CompilerInterface {
ControlFlow::Continue(())
}

fn after_codegen(&mut self, _printed: String) {}
fn after_codegen(&mut self, _ret: CodegenReturn) {}

fn compile(&mut self, source_text: &str, source_type: SourceType, source_path: &Path) {
let allocator = Allocator::default();
Expand All @@ -112,11 +134,23 @@ pub trait CompilerInterface {
self.handle_errors(parser_return.errors);
}

/* Semantic */

let mut program = parser_return.program;
let trivias = parser_return.trivias;

/* Isolated Declarations */
if let Some(options) = self.isolated_declaration_options() {
self.isolated_declaration(
options,
&allocator,
&program,
source_text,
source_path,
&trivias,
);
}

/* Semantic */

let mut semantic_return = self.semantic(&program, source_text, source_path);
if !semantic_return.errors.is_empty() {
self.handle_errors(semantic_return.errors);
Expand All @@ -126,7 +160,7 @@ pub trait CompilerInterface {
return;
}

let (symbols, scopes) = semantic_return.semantic.into_symbol_table_and_scope_tree();
let (mut symbols, mut scopes) = semantic_return.semantic.into_symbol_table_and_scope_tree();

/* Transform */

Expand All @@ -150,6 +184,23 @@ pub trait CompilerInterface {
if self.after_transform(&mut program, &mut transformer_return).is_break() {
return;
}

symbols = transformer_return.symbols;
scopes = transformer_return.scopes;
}

if let Some(config) = self.define_options() {
let ret =
ReplaceGlobalDefines::new(&allocator, config).build(symbols, scopes, &mut program);
symbols = ret.symbols;
scopes = ret.scopes;
}

if let Some(config) = self.inject_options() {
let _ret =
InjectGlobalVariables::new(&allocator, config).build(symbols, scopes, &mut program);
// symbols = ret.symbols;
// scopes = ret.scopes;
}

/* Compress */
Expand All @@ -165,8 +216,8 @@ pub trait CompilerInterface {
/* Codegen */

if let Some(options) = self.codegen_options() {
let printed = self.codegen(&program, source_text, &trivias, mangler, options);
self.after_codegen(printed);
let ret = self.codegen(&program, source_text, source_path, &trivias, mangler, options);
self.after_codegen(ret);
}
}

Expand Down Expand Up @@ -199,6 +250,29 @@ pub trait CompilerInterface {
.build(program)
}

fn isolated_declaration<'a>(
&mut self,
options: IsolatedDeclarationsOptions,
allocator: &'a Allocator,
program: &Program<'a>,
source_text: &'a str,
source_path: &Path,
trivias: &Trivias,
) {
let ret =
IsolatedDeclarations::new(allocator, source_text, trivias, options).build(program);
self.handle_errors(ret.errors);
let ret = self.codegen(
&ret.program,
source_text,
source_path,
trivias,
None,
self.codegen_options().unwrap_or_default(),
);
self.after_isolated_declarations(ret);
}

#[allow(clippy::too_many_arguments)]
fn transform<'a>(
&self,
Expand Down Expand Up @@ -232,16 +306,20 @@ pub trait CompilerInterface {
&self,
program: &Program<'a>,
source_text: &'a str,
source_path: &Path,
trivias: &Trivias,
mangler: Option<Mangler>,
options: CodegenOptions,
) -> String {
) -> CodegenReturn {
let comment_options = CommentOptions { preserve_annotate_comments: true };
CodeGenerator::new()
let mut codegen = CodeGenerator::new()
.with_options(options)
.with_mangler(mangler)
.enable_comment(source_text, trivias.clone(), comment_options)
.build(program)
.source_text
.enable_comment(source_text, trivias.clone(), comment_options);
if self.enable_sourcemap() {
codegen =
codegen.enable_source_map(source_path.to_string_lossy().as_ref(), source_text);
}
codegen.build(program)
}
}
40 changes: 39 additions & 1 deletion crates/oxc/src/napi/transform.rs
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
// NOTE: Types must be aligned with [@types/babel__core](https://github.com/DefinitelyTyped/DefinitelyTyped/blob/master/types/babel__core/index.d.ts).

#![allow(rustdoc::bare_urls)]

use std::path::PathBuf;
Expand All @@ -8,7 +10,43 @@ use rustc_hash::FxHashMap;

use oxc_transformer::{JsxRuntime, RewriteExtensionsMode};

use super::isolated_declarations::IsolatedDeclarationsOptions;
use super::{isolated_declarations::IsolatedDeclarationsOptions, source_map::SourceMap};

#[derive(Default)]
#[napi(object)]
pub struct TransformResult {
/// The transformed code.
///
/// If parsing failed, this will be an empty string.
pub code: String,

/// The source map for the transformed code.
///
/// This will be set if {@link TransformOptions#sourcemap} is `true`.
pub map: Option<SourceMap>,

/// The `.d.ts` declaration file for the transformed code. Declarations are
/// only generated if `declaration` is set to `true` and a TypeScript file
/// is provided.
///
/// If parsing failed and `declaration` is set, this will be an empty string.
///
/// @see {@link TypeScriptOptions#declaration}
/// @see [declaration tsconfig option](https://www.typescriptlang.org/tsconfig/#declaration)
pub declaration: Option<String>,

/// Declaration source map. Only generated if both
/// {@link TypeScriptOptions#declaration declaration} and
/// {@link TransformOptions#sourcemap sourcemap} are set to `true`.
pub declaration_map: Option<SourceMap>,

/// Parse and transformation errors.
///
/// Oxc's parser recovers from common syntax errors, meaning that
/// transformed code may still be available even if there are errors in this
/// list.
pub errors: Vec<String>,
}

/// Options for transforming a JavaScript or TypeScript file.
///
Expand Down
4 changes: 1 addition & 3 deletions napi/transform/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -21,9 +21,7 @@ test = false
doctest = false

[dependencies]
oxc = { workspace = true, features = ["napi", "isolated_declarations", "transformer", "sourcemap", "codegen", "semantic"] }

rustc-hash = { workspace = true }
oxc = { workspace = true, features = ["full", "napi"] }

napi = { workspace = true }
napi-derive = { workspace = true }
Expand Down
33 changes: 3 additions & 30 deletions napi/transform/src/context.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,5 @@
use std::{
cell::{Ref, RefCell, RefMut},
path::Path,
cell::{Ref, RefCell},
sync::Arc,
};

Expand All @@ -9,7 +8,6 @@ use oxc::{
ast::{ast::Program, Trivias},
codegen::Codegen,
diagnostics::{Error, NamedSource, OxcDiagnostic},
napi::{isolated_declarations::IsolatedDeclarationsOptions, transform::TransformOptions},
parser::{Parser, ParserReturn},
span::SourceType,
};
Expand All @@ -23,9 +21,6 @@ pub(crate) struct TransformContext<'a> {
/// Generate source maps?
source_map: bool,

/// Generate `.d.ts` files?
declarations: Option<IsolatedDeclarationsOptions>,

/// Path to the file being transformed.
filename: &'a str,

Expand All @@ -43,24 +38,17 @@ impl<'a> TransformContext<'a> {
filename: &'a str,
source_text: &'a str,
source_type: SourceType,
options: Option<&TransformOptions>,
source_map: Option<bool>,
) -> Self {
let ParserReturn { errors, program, trivias, .. } =
Parser::new(allocator, source_text, source_type).parse();

// Options that are added by this napi crates and don't exist in
// oxc_transformer.
let source_map = options.as_ref().and_then(|o| o.sourcemap).unwrap_or_default();
let declarations =
options.as_ref().and_then(|o| o.typescript.as_ref()).and_then(|t| t.declaration);

let source_map = source_map.unwrap_or_default();
Self {
allocator,
program: RefCell::new(program),
trivias,

source_map,
declarations,

filename,
source_text,
Expand All @@ -74,31 +62,16 @@ impl<'a> TransformContext<'a> {
self.filename
}

#[inline]
pub fn file_path(&self) -> &'a Path {
Path::new(self.filename)
}

#[inline]
pub fn source_text(&self) -> &'a str {
self.source_text
}

#[inline]
pub(crate) fn declarations(&self) -> Option<&IsolatedDeclarationsOptions> {
self.declarations.as_ref()
}

#[inline]
pub fn program(&self) -> Ref<'_, Program<'a>> {
self.program.borrow()
}

#[inline]
pub fn program_mut(&self) -> RefMut<'_, Program<'a>> {
self.program.borrow_mut()
}

pub fn codegen(&self) -> Codegen<'a> {
let codegen = Codegen::new();
if self.source_map {
Expand Down
14 changes: 3 additions & 11 deletions napi/transform/src/isolated_declaration.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,10 +3,7 @@ use oxc::{
allocator::Allocator,
codegen::{CodegenReturn, CommentOptions},
isolated_declarations::IsolatedDeclarations,
napi::{
isolated_declarations::{IsolatedDeclarationsOptions, IsolatedDeclarationsResult},
transform::TransformOptions,
},
napi::isolated_declarations::{IsolatedDeclarationsOptions, IsolatedDeclarationsResult},
span::SourceType,
};

Expand All @@ -23,13 +20,8 @@ pub fn isolated_declaration(
let source_type = SourceType::from_path(&filename).unwrap_or_default().with_typescript(true);
let allocator = Allocator::default();
let options = options.unwrap_or_default();
let ctx = TransformContext::new(
&allocator,
&filename,
&source_text,
source_type,
Some(&TransformOptions { sourcemap: options.sourcemap, ..Default::default() }),
);
let ctx =
TransformContext::new(&allocator, &filename, &source_text, source_type, options.sourcemap);
let transformed_ret = build_declarations(&ctx, options);

IsolatedDeclarationsResult {
Expand Down
Loading

0 comments on commit 8729755

Please sign in to comment.