@@ -7,6 +7,7 @@ use std::{
7
7
use options:: OxcCodegenOptions ;
8
8
use rustc_hash:: FxHashMap ;
9
9
10
+ use napi:: Either ;
10
11
use napi_derive:: napi;
11
12
use serde:: Serialize ;
12
13
@@ -35,8 +36,15 @@ use oxc_linter::{
35
36
ModuleRecord , Oxlintrc ,
36
37
} ;
37
38
use oxc_napi:: { Comment , OxcError , convert_utf8_to_utf16} ;
39
+ use oxc_transformer_plugins:: {
40
+ InjectGlobalVariables , InjectGlobalVariablesConfig , InjectImport , ReplaceGlobalDefines ,
41
+ ReplaceGlobalDefinesConfig ,
42
+ } ;
38
43
39
- use crate :: options:: { OxcLinterOptions , OxcOptions , OxcRunOptions } ;
44
+ use crate :: options:: {
45
+ OxcControlFlowOptions , OxcDefineOptions , OxcInjectOptions , OxcIsolatedDeclarationsOptions ,
46
+ OxcLinterOptions , OxcOptions , OxcParserOptions , OxcRunOptions , OxcTransformerOptions ,
47
+ } ;
40
48
41
49
mod options;
42
50
@@ -97,12 +105,16 @@ impl Oxc {
97
105
control_flow : ref control_flow_options,
98
106
isolated_declarations : ref isolated_declarations_options,
99
107
codegen : ref codegen_options,
108
+ inject : ref inject_options,
109
+ define : ref define_options,
100
110
..
101
111
} = options;
102
112
let linter_options = linter_options. clone ( ) . unwrap_or_default ( ) ;
103
113
let transform_options = transform_options. clone ( ) . unwrap_or_default ( ) ;
104
114
let control_flow_options = control_flow_options. clone ( ) . unwrap_or_default ( ) ;
105
115
let codegen_options = codegen_options. clone ( ) . unwrap_or_default ( ) ;
116
+ let inject_options = inject_options. clone ( ) ;
117
+ let define_options = define_options. clone ( ) ;
106
118
107
119
let allocator = Allocator :: default ( ) ;
108
120
@@ -139,7 +151,7 @@ impl Oxc {
139
151
} ;
140
152
self . run_formatter ( run_options, parse_options, & source_text, source_type) ;
141
153
142
- let scoping = semantic. into_scoping ( ) ;
154
+ let mut scoping = semantic. into_scoping ( ) ;
143
155
144
156
// Extract scope and symbol information if needed
145
157
if !source_type. is_typescript_definition ( ) {
@@ -164,9 +176,17 @@ impl Oxc {
164
176
return Ok ( ( ) ) ;
165
177
}
166
178
179
+ // Phase 5.5: Apply ReplaceGlobalDefines (before transformations)
180
+ if let Some ( define_opts) = define_options {
181
+ let define_config = Self :: build_define_config ( & define_opts) ?;
182
+ let ret =
183
+ ReplaceGlobalDefines :: new ( & allocator, define_config) . build ( scoping, & mut program) ;
184
+ scoping = ret. scoping ;
185
+ }
186
+
167
187
// Phase 6: Apply transformations
168
188
if run_options. transform {
169
- self . apply_transformations (
189
+ scoping = self . apply_transformations (
170
190
& allocator,
171
191
& path,
172
192
& mut program,
@@ -175,6 +195,13 @@ impl Oxc {
175
195
) ;
176
196
}
177
197
198
+ // Phase 6.5: Apply InjectGlobalVariables (after transformations)
199
+ if let Some ( inject_opts) = inject_options {
200
+ let inject_config = Self :: build_inject_config ( & inject_opts) ?;
201
+ let _ =
202
+ InjectGlobalVariables :: new ( & allocator, inject_config) . build ( scoping, & mut program) ;
203
+ }
204
+
178
205
// Phase 7: Apply minification
179
206
let scoping = Self :: apply_minification ( & allocator, & mut program, & options) ;
180
207
@@ -192,7 +219,7 @@ impl Oxc {
192
219
allocator : & ' a Allocator ,
193
220
source_text : & ' a str ,
194
221
source_type : SourceType ,
195
- parser_options : & crate :: options :: OxcParserOptions ,
222
+ parser_options : & OxcParserOptions ,
196
223
) -> ( Program < ' a > , oxc:: syntax:: module_record:: ModuleRecord < ' a > ) {
197
224
let parser_options = ParseOptions {
198
225
parse_regular_expression : true ,
@@ -210,7 +237,7 @@ impl Oxc {
210
237
& mut self ,
211
238
program : & ' a Program < ' a > ,
212
239
run_options : & OxcRunOptions ,
213
- control_flow_options : & crate :: options :: OxcControlFlowOptions ,
240
+ control_flow_options : & OxcControlFlowOptions ,
214
241
) -> oxc:: semantic:: Semantic < ' a > {
215
242
let mut semantic_builder = SemanticBuilder :: new ( ) ;
216
243
if run_options. transform {
@@ -238,7 +265,7 @@ impl Oxc {
238
265
program : & Program < ' a > ,
239
266
run_options : & OxcRunOptions ,
240
267
codegen_options : & OxcCodegenOptions ,
241
- isolated_declarations_options : Option < crate :: options :: OxcIsolatedDeclarationsOptions > ,
268
+ isolated_declarations_options : Option < OxcIsolatedDeclarationsOptions > ,
242
269
) {
243
270
let id_options = isolated_declarations_options
244
271
. map ( |o| IsolatedDeclarationsOptions { strip_internal : o. strip_internal } )
@@ -259,7 +286,7 @@ impl Oxc {
259
286
path : & Path ,
260
287
program : & mut Program < ' a > ,
261
288
scoping : Scoping ,
262
- transform_options : & crate :: options :: OxcTransformerOptions ,
289
+ transform_options : & OxcTransformerOptions ,
263
290
) -> Scoping {
264
291
let mut options = transform_options
265
292
. target
@@ -493,6 +520,49 @@ impl Oxc {
493
520
writer. scope_text
494
521
}
495
522
523
+ fn build_inject_config (
524
+ inject_opts : & OxcInjectOptions ,
525
+ ) -> napi:: Result < InjectGlobalVariablesConfig > {
526
+ let mut imports = Vec :: new ( ) ;
527
+
528
+ for ( local, value) in & inject_opts. inject {
529
+ let import = match value {
530
+ Either :: A ( source) => InjectImport :: default_specifier ( source, local) ,
531
+ Either :: B ( v) => {
532
+ if v. len ( ) != 2 {
533
+ return Err ( napi:: Error :: from_reason (
534
+ "Inject plugin did not receive a tuple [string, string]." ,
535
+ ) ) ;
536
+ }
537
+ let source = & v[ 0 ] ;
538
+ if v[ 1 ] == "*" {
539
+ InjectImport :: namespace_specifier ( source, local)
540
+ } else {
541
+ InjectImport :: named_specifier ( source, Some ( & v[ 1 ] ) , local)
542
+ }
543
+ }
544
+ } ;
545
+ imports. push ( import) ;
546
+ }
547
+
548
+ Ok ( InjectGlobalVariablesConfig :: new ( imports) )
549
+ }
550
+
551
+ fn build_define_config (
552
+ define_opts : & OxcDefineOptions ,
553
+ ) -> napi:: Result < ReplaceGlobalDefinesConfig > {
554
+ let define_pairs: Vec < ( String , String ) > =
555
+ define_opts. define . iter ( ) . map ( |( k, v) | ( k. clone ( ) , v. clone ( ) ) ) . collect ( ) ;
556
+
557
+ ReplaceGlobalDefinesConfig :: new ( & define_pairs) . map_err ( |errors| {
558
+ let error_messages: Vec < String > = errors. iter ( ) . map ( ToString :: to_string) . collect ( ) ;
559
+ napi:: Error :: from_reason ( format ! (
560
+ "Invalid define config: {}" ,
561
+ error_messages. join( ", " )
562
+ ) )
563
+ } )
564
+ }
565
+
496
566
fn get_symbols_text ( scoping : & Scoping ) -> napi:: Result < String > {
497
567
#[ derive( Serialize ) ]
498
568
struct Data {
0 commit comments