mirror of
https://github.com/danbulant/oxc
synced 2026-05-19 12:19:15 +00:00
feat(napi/transform): add inject plugin (#6250)
This commit is contained in:
parent
d085c2cd25
commit
f98e12c13a
6 changed files with 112 additions and 20 deletions
1
Cargo.lock
generated
1
Cargo.lock
generated
|
|
@ -1986,6 +1986,7 @@ dependencies = [
|
|||
"oxc_sourcemap",
|
||||
"oxc_span",
|
||||
"oxc_transformer",
|
||||
"rustc-hash",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
|
|
|
|||
|
|
@ -32,6 +32,8 @@ oxc_sourcemap = { workspace = true }
|
|||
oxc_span = { workspace = true }
|
||||
oxc_transformer = { workspace = true }
|
||||
|
||||
rustc-hash = { workspace = true }
|
||||
|
||||
napi = { workspace = true }
|
||||
napi-derive = { workspace = true }
|
||||
|
||||
|
|
|
|||
2
napi/transform/index.d.ts
vendored
2
napi/transform/index.d.ts
vendored
|
|
@ -205,6 +205,8 @@ export interface TransformOptions {
|
|||
es2015?: ES2015BindingOptions
|
||||
/** Define Plugin */
|
||||
define?: Record<string, string>
|
||||
/** Inject Plugin */
|
||||
inject?: Record<string, string | [string, string]>
|
||||
}
|
||||
|
||||
export interface TransformResult {
|
||||
|
|
|
|||
|
|
@ -1,11 +1,11 @@
|
|||
#![allow(rustdoc::bare_urls)]
|
||||
#![allow(clippy::disallowed_types)] // allow HashMap
|
||||
|
||||
use std::collections::HashMap;
|
||||
use std::path::PathBuf;
|
||||
|
||||
use napi::Either;
|
||||
use napi_derive::napi;
|
||||
use rustc_hash::FxHashMap;
|
||||
|
||||
use oxc_transformer::{ArrowFunctionsOptions, ES2015Options, JsxRuntime, RewriteExtensionsMode};
|
||||
|
||||
use crate::IsolatedDeclarationsOptions;
|
||||
|
|
@ -42,7 +42,12 @@ pub struct TransformOptions {
|
|||
pub es2015: Option<ES2015BindingOptions>,
|
||||
|
||||
/// Define Plugin
|
||||
pub define: Option<HashMap<String, String>>,
|
||||
#[napi(ts_type = "Record<string, string>")]
|
||||
pub define: Option<FxHashMap<String, String>>,
|
||||
|
||||
/// Inject Plugin
|
||||
#[napi(ts_type = "Record<string, string | [string, string]>")]
|
||||
pub inject: Option<FxHashMap<String, Either<String, Vec<String>>>>,
|
||||
}
|
||||
|
||||
impl From<TransformOptions> for oxc_transformer::TransformOptions {
|
||||
|
|
|
|||
|
|
@ -1,9 +1,15 @@
|
|||
use napi::Either;
|
||||
use napi_derive::napi;
|
||||
use rustc_hash::FxHashMap;
|
||||
|
||||
use oxc_allocator::Allocator;
|
||||
use oxc_codegen::CodegenReturn;
|
||||
use oxc_semantic::SemanticBuilder;
|
||||
use oxc_semantic::{ScopeTree, SemanticBuilder, SymbolTable};
|
||||
use oxc_span::SourceType;
|
||||
use oxc_transformer::{ReplaceGlobalDefines, ReplaceGlobalDefinesConfig, Transformer};
|
||||
use oxc_transformer::{
|
||||
InjectGlobalVariables, InjectGlobalVariablesConfig, InjectImport, ReplaceGlobalDefines,
|
||||
ReplaceGlobalDefinesConfig, Transformer,
|
||||
};
|
||||
|
||||
use crate::{context::TransformContext, isolated_declaration, SourceMap, TransformOptions};
|
||||
|
||||
|
|
@ -107,6 +113,7 @@ fn transpile(ctx: &TransformContext<'_>, options: Option<TransformOptions>) -> C
|
|||
|
||||
let mut options = options;
|
||||
let define = options.as_mut().and_then(|options| options.define.take());
|
||||
let inject = options.as_mut().and_then(|options| options.inject.take());
|
||||
|
||||
let options = options.map(oxc_transformer::TransformOptions::from).unwrap_or_default();
|
||||
|
||||
|
|
@ -126,22 +133,72 @@ fn transpile(ctx: &TransformContext<'_>, options: Option<TransformOptions>) -> C
|
|||
scopes = ret.scopes;
|
||||
|
||||
if let Some(define) = define {
|
||||
let define = define.into_iter().collect::<Vec<_>>();
|
||||
match ReplaceGlobalDefinesConfig::new(&define) {
|
||||
Ok(config) => {
|
||||
let _ret = ReplaceGlobalDefines::new(ctx.allocator, config).build(
|
||||
symbols,
|
||||
scopes,
|
||||
&mut ctx.program_mut(),
|
||||
);
|
||||
// symbols = ret.symbols;
|
||||
// scopes = ret.scopes;
|
||||
}
|
||||
Err(errors) => {
|
||||
ctx.add_diagnostics(errors);
|
||||
}
|
||||
}
|
||||
(symbols, scopes) = define_plugin(ctx, define, symbols, scopes);
|
||||
}
|
||||
|
||||
if let Some(inject) = inject {
|
||||
_ = inject_plugin(ctx, inject, symbols, scopes);
|
||||
}
|
||||
|
||||
ctx.codegen().build(&ctx.program())
|
||||
}
|
||||
|
||||
fn define_plugin(
|
||||
ctx: &TransformContext<'_>,
|
||||
define: FxHashMap<String, String>,
|
||||
symbols: SymbolTable,
|
||||
scopes: ScopeTree,
|
||||
) -> (SymbolTable, ScopeTree) {
|
||||
let define = define.into_iter().collect::<Vec<_>>();
|
||||
match ReplaceGlobalDefinesConfig::new(&define) {
|
||||
Ok(config) => {
|
||||
let ret = ReplaceGlobalDefines::new(ctx.allocator, config).build(
|
||||
symbols,
|
||||
scopes,
|
||||
&mut ctx.program_mut(),
|
||||
);
|
||||
(ret.symbols, ret.scopes)
|
||||
}
|
||||
Err(errors) => {
|
||||
ctx.add_diagnostics(errors);
|
||||
(symbols, scopes)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn inject_plugin(
|
||||
ctx: &TransformContext<'_>,
|
||||
inject: FxHashMap<String, Either<String, Vec<String>>>,
|
||||
symbols: SymbolTable,
|
||||
scopes: ScopeTree,
|
||||
) -> (SymbolTable, ScopeTree) {
|
||||
let Ok(injects) = inject
|
||||
.into_iter()
|
||||
.map(|(local, value)| match value {
|
||||
Either::A(source) => Ok(InjectImport::default_specifier(&source, &local)),
|
||||
Either::B(v) => {
|
||||
if v.len() != 2 {
|
||||
return Err(());
|
||||
}
|
||||
let source = v[0].to_string();
|
||||
Ok(if v[1] == "*" {
|
||||
InjectImport::namespace_specifier(&source, &local)
|
||||
} else {
|
||||
InjectImport::named_specifier(&source, Some(&v[1]), &local)
|
||||
})
|
||||
}
|
||||
})
|
||||
.collect::<Result<Vec<_>, ()>>()
|
||||
else {
|
||||
return (symbols, scopes);
|
||||
};
|
||||
|
||||
let config = InjectGlobalVariablesConfig::new(injects);
|
||||
let ret = InjectGlobalVariables::new(ctx.allocator, config).build(
|
||||
symbols,
|
||||
scopes,
|
||||
&mut ctx.program_mut(),
|
||||
);
|
||||
|
||||
(ret.symbols, ret.scopes)
|
||||
}
|
||||
|
|
|
|||
|
|
@ -83,4 +83,29 @@ test(
|
|||
},
|
||||
);
|
||||
|
||||
// Test define plugin
|
||||
// TODO: should be constant folded
|
||||
test(
|
||||
oxc.transform('test.ts', 'if (process.env.NODE_ENV === "production") { foo; }', {
|
||||
define: {
|
||||
'process.env.NODE_ENV': 'false',
|
||||
},
|
||||
}),
|
||||
{
|
||||
code: 'if (false === "production") {\n\tfoo;\n}\n',
|
||||
},
|
||||
);
|
||||
|
||||
// Test inject plugin
|
||||
test(
|
||||
oxc.transform('test.ts', 'let _ = Object.assign', {
|
||||
inject: {
|
||||
'Object.assign': 'foo',
|
||||
},
|
||||
}),
|
||||
{
|
||||
code: 'import $inject_Object_assign from "foo";\nlet _ = $inject_Object_assign;\n',
|
||||
},
|
||||
);
|
||||
|
||||
console.log('Success.');
|
||||
|
|
|
|||
Loading…
Reference in a new issue