Skip to content

Commit baf7c49

Browse files
committed
Build injected functions using AstBuilder
1 parent a6895ab commit baf7c49

File tree

8 files changed

+367
-71
lines changed

8 files changed

+367
-71
lines changed
Lines changed: 166 additions & 36 deletions
Original file line numberDiff line numberDiff line change
@@ -1,67 +1,197 @@
1-
use super::parse_js_code_to_statements::parse_js_code_to_statements;
2-
use oxc_allocator::{Allocator, Box};
3-
use oxc_ast::ast::FunctionBody;
4-
use oxc_span::SourceType;
5-
6-
pub fn insert_single_statement_into_func<'a>(
7-
allocator: &'a Allocator,
8-
body: &mut Box<'a, FunctionBody<'a>>,
9-
pos: usize,
10-
source_text: &'a str,
11-
) {
12-
body.statements.insert(
13-
pos,
14-
parse_js_code_to_statements(&allocator, &source_text, SourceType::mjs())
15-
.into_iter()
16-
.next()
17-
.unwrap(),
18-
);
19-
}
1+
use oxc_allocator::{Allocator, Box, Vec as OxcVec};
2+
use oxc_ast::{
3+
ast::{
4+
Argument, ArrayExpressionElement, AssignmentOperator, AssignmentTarget, Expression,
5+
FunctionBody,
6+
},
7+
AstBuilder, NONE,
8+
};
9+
use oxc_span::SPAN;
2010

2111
// Add a statement to the beginning of the function: __instrumentInspectArgs('function_identifier', arguments);
2212
pub fn insert_inspect_args<'a>(
2313
allocator: &'a Allocator,
14+
builder: &'a AstBuilder,
2415
identifier: &str,
2516
pkg_version: &'a str,
2617
body: &mut Box<'a, FunctionBody<'a>>,
2718
) {
28-
let source_text: &'a str = allocator.alloc_str(&format!(
29-
"__instrumentInspectArgs('{}', arguments, '{}', this);",
30-
identifier, pkg_version
31-
));
19+
let mut inspect_args: OxcVec<'a, Argument<'a>> = builder.vec_with_capacity(4);
20+
21+
// Add the identifier to the arguments
22+
inspect_args.push(Argument::StringLiteral(builder.alloc_string_literal(
23+
SPAN,
24+
allocator.alloc_str(identifier),
25+
None,
26+
)));
27+
28+
// Add the arguments object as the second argument
29+
inspect_args.push(builder.expression_identifier(SPAN, "arguments").into());
30+
31+
// Add the package version as the third argument
32+
inspect_args.push(Argument::StringLiteral(builder.alloc_string_literal(
33+
SPAN,
34+
allocator.alloc_str(pkg_version),
35+
None,
36+
)));
37+
38+
// Add the `this` context as the fourth argument
39+
inspect_args.push(builder.expression_identifier(SPAN, "this").into());
3240

33-
insert_single_statement_into_func(allocator, body, 0, source_text);
41+
// Build and add a call expression
42+
let call_expr = builder.expression_call(
43+
SPAN,
44+
builder.expression_identifier(SPAN, "__instrumentInspectArgs"),
45+
NONE,
46+
inspect_args,
47+
false,
48+
);
49+
50+
let stmt_expression = builder.statement_expression(SPAN, call_expr);
51+
52+
body.statements.insert(0, stmt_expression);
3453
}
3554

3655
// Modify the arguments by adding a statement to the beginning of the function
3756
// [arg1, arg2, ...] = __instrumentModifyArgs('function_identifier', [arg1, arg2, ...]);
3857
pub fn insert_modify_args<'a>(
3958
allocator: &'a Allocator,
59+
builder: &'a AstBuilder,
4060
identifier: &str,
41-
arg_names_str: &str,
61+
arg_names: &Vec<String>,
4262
body: &mut Box<'a, FunctionBody<'a>>,
4363
modify_arguments_object: bool,
4464
) {
4565
if modify_arguments_object {
4666
// If we are modifying the arguments object, we need to use the arguments object directly
4767
// instead of the individual arguments
48-
let source_text: &'a str = allocator.alloc_str(&format!(
49-
"Object.assign(arguments, __instrumentModifyArgs('{}', Array.from(arguments)));",
50-
identifier
51-
));
52-
insert_single_statement_into_func(allocator, body, 0, source_text);
68+
// Object.assign(arguments, __instrumentModifyArgs('id', Array.from(arguments)));
69+
70+
let mut obj_assign_args: OxcVec<'a, Argument<'a>> = builder.vec_with_capacity(2);
71+
72+
// First argument is the arguments object
73+
obj_assign_args.push(builder.expression_identifier(SPAN, "arguments").into());
74+
75+
// Second argument is the call to __instrumentModifyArgs
76+
77+
let mut instrument_args: OxcVec<'a, Argument<'a>> = builder.vec_with_capacity(2);
78+
// Add the identifier to the arguments
79+
instrument_args.push(Argument::StringLiteral(builder.alloc_string_literal(
80+
SPAN,
81+
allocator.alloc_str(identifier),
82+
None,
83+
)));
84+
85+
let mut array_from_args: OxcVec<'a, Argument<'a>> = builder.vec_with_capacity(1);
86+
// Add the arguments object as the first argument to Array.from
87+
array_from_args.push(builder.expression_identifier(SPAN, "arguments").into());
88+
89+
let array_from_call = builder.expression_call(
90+
SPAN,
91+
Expression::StaticMemberExpression(builder.alloc_static_member_expression(
92+
SPAN,
93+
builder.expression_identifier(SPAN, "Array"),
94+
builder.identifier_name(SPAN, "from"),
95+
false,
96+
)),
97+
NONE,
98+
array_from_args,
99+
false,
100+
);
101+
102+
instrument_args.push(array_from_call.into());
103+
104+
let instrument_modify_args_call = builder.expression_call(
105+
SPAN,
106+
builder.expression_identifier(SPAN, "__instrumentModifyArgs"),
107+
NONE,
108+
instrument_args,
109+
false,
110+
);
111+
112+
obj_assign_args.push(instrument_modify_args_call.into());
113+
114+
let obj_assign_call_expr = builder.expression_call(
115+
SPAN,
116+
Expression::StaticMemberExpression(builder.alloc_static_member_expression(
117+
SPAN,
118+
builder.expression_identifier(SPAN, "Object"),
119+
builder.identifier_name(SPAN, "assign"),
120+
false,
121+
)),
122+
NONE,
123+
obj_assign_args,
124+
false,
125+
);
126+
127+
let stmt_expression = builder.statement_expression(SPAN, obj_assign_call_expr);
128+
129+
body.statements.insert(0, stmt_expression);
130+
53131
return;
54132
}
55133

56-
if arg_names_str.is_empty() {
57-
// If there are no arguments to modify, we can skip this step
134+
if arg_names.is_empty() {
135+
// If there are no arguments to modify, we can skip the modification
58136
return;
59137
}
60138

61-
let source_text: &'a str = allocator.alloc_str(&format!(
62-
"[{}] = __instrumentModifyArgs('{}', [{}]);",
63-
arg_names_str, identifier, arg_names_str
139+
use oxc_ast::ast::AssignmentTargetMaybeDefault;
140+
141+
let mut array_assignment_target_identifiers: OxcVec<
142+
'a,
143+
Option<AssignmentTargetMaybeDefault<'a>>,
144+
> = builder.vec_with_capacity(arg_names.len());
145+
146+
for name in arg_names {
147+
array_assignment_target_identifiers.push(Some(
148+
AssignmentTargetMaybeDefault::AssignmentTargetIdentifier(
149+
builder.alloc_identifier_reference(SPAN, allocator.alloc_str(name)),
150+
),
151+
));
152+
}
153+
154+
let mut instrument_modify_args: OxcVec<'a, Argument<'a>> = builder.vec_with_capacity(2);
155+
// Add the identifier to the arguments
156+
instrument_modify_args.push(Argument::StringLiteral(builder.alloc_string_literal(
157+
SPAN,
158+
allocator.alloc_str(identifier),
159+
None,
160+
)));
161+
162+
let mut instrument_modify_args_array_elements: OxcVec<'a, ArrayExpressionElement<'a>> =
163+
builder.vec_with_capacity(arg_names.len());
164+
165+
for name in arg_names {
166+
instrument_modify_args_array_elements.push(ArrayExpressionElement::Identifier(
167+
builder.alloc_identifier_reference(SPAN, allocator.alloc_str(name)),
168+
));
169+
}
170+
171+
instrument_modify_args.push(Argument::ArrayExpression(
172+
builder.alloc_array_expression(SPAN, instrument_modify_args_array_elements),
64173
));
65174

66-
insert_single_statement_into_func(allocator, body, 0, source_text);
175+
let instrument_modify_args_call = builder.expression_call(
176+
SPAN,
177+
builder.expression_identifier(SPAN, "__instrumentModifyArgs"),
178+
NONE,
179+
instrument_modify_args,
180+
false,
181+
);
182+
183+
let arr_assignment_expr = builder.expression_assignment(
184+
SPAN,
185+
AssignmentOperator::Assign,
186+
AssignmentTarget::ArrayAssignmentTarget(builder.alloc_array_assignment_target(
187+
SPAN,
188+
array_assignment_target_identifiers,
189+
None,
190+
)),
191+
instrument_modify_args_call,
192+
);
193+
194+
let stmt_expression = builder.statement_expression(SPAN, arr_assignment_expr);
195+
196+
body.statements.insert(0, stmt_expression);
67197
}

instrumentation-wasm/src/js_transformer/helpers/insert_import_statement.rs

Lines changed: 15 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
use oxc_allocator::{Allocator, Vec};
1+
use oxc_allocator::{Allocator, Vec as OxcVec};
22
use oxc_ast::{
33
ast::{
44
Argument, BindingPatternKind, BindingProperty, ImportDeclarationSpecifier,
@@ -35,19 +35,19 @@ pub fn insert_import_statement<'a>(
3535
has_module_syntax: bool,
3636
allocator: &'a Allocator,
3737
builder: &'a AstBuilder,
38-
body: &mut Vec<'a, Statement<'a>>,
38+
body: &mut OxcVec<'a, Statement<'a>>,
3939
file_instructions: &FileInstructions,
4040
) {
4141
// Common JS require() statement
4242
if source_type.is_script() || source_type.is_unambiguous() && !has_module_syntax {
43-
let mut require_args: Vec<'a, Argument<'a>> = builder.vec_with_capacity(1);
43+
let mut require_args: OxcVec<'a, Argument<'a>> = builder.vec_with_capacity(1);
4444
require_args.push(Argument::StringLiteral(builder.alloc_string_literal(
4545
SPAN,
4646
allocator.alloc_str(INSTRUMENT_IMPORT_SOURCE),
4747
None,
4848
)));
4949

50-
let mut binding_properties: Vec<'a, BindingProperty<'a>> = builder.vec_with_capacity(3);
50+
let mut binding_properties: OxcVec<'a, BindingProperty<'a>> = builder.vec_with_capacity(3);
5151

5252
for (method_name, predicate) in IMPORT_METHODS.iter() {
5353
// Only import the function if it is used in the file
@@ -66,6 +66,11 @@ pub fn insert_import_statement<'a>(
6666
}
6767
}
6868

69+
if binding_properties.is_empty() {
70+
// If there are no methods to import, we can skip the require statement
71+
return;
72+
}
73+
6974
let mut declarations = builder.vec_with_capacity(1);
7075
declarations.push(builder.variable_declarator(
7176
SPAN,
@@ -102,7 +107,7 @@ pub fn insert_import_statement<'a>(
102107
}
103108
// else: ESM import statement
104109

105-
let mut specifiers: Vec<'a, ImportDeclarationSpecifier<'a>> = builder.vec_with_capacity(3);
110+
let mut specifiers: OxcVec<'a, ImportDeclarationSpecifier<'a>> = builder.vec_with_capacity(3);
106111
for (method_name, predicate) in IMPORT_METHODS.iter() {
107112
if file_instructions.functions.iter().any(|f| predicate(f)) {
108113
specifiers.push(builder.import_declaration_specifier_import_specifier(
@@ -114,6 +119,11 @@ pub fn insert_import_statement<'a>(
114119
}
115120
}
116121

122+
if specifiers.is_empty() {
123+
// If there are no methods to import, we can skip the import statement
124+
return;
125+
}
126+
117127
let import_stmt = Statement::ImportDeclaration(builder.alloc_import_declaration(
118128
SPAN,
119129
Some(specifiers),

instrumentation-wasm/src/js_transformer/helpers/mod.rs

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,5 @@ pub mod get_arg_names;
22
pub mod get_name_str_for_member_expr;
33
pub mod insert_code;
44
pub mod insert_import_statement;
5-
pub mod parse_js_code_to_statements;
65
pub mod select_sourcetype_based_on_enum;
76
pub mod transform_return_statements;

instrumentation-wasm/src/js_transformer/helpers/parse_js_code_to_statements.rs

Lines changed: 0 additions & 20 deletions
This file was deleted.

instrumentation-wasm/src/js_transformer/helpers/transform_return_statements.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
use oxc_allocator::{Allocator, Box, Vec};
1+
use oxc_allocator::{Allocator, Box, Vec as OxcVec};
22
use oxc_ast::{
33
ast::{Argument, FunctionBody, Statement},
44
AstBuilder, NONE,
@@ -15,7 +15,7 @@ pub fn transform_return_statements<'a>(
1515
for statement in &mut body.statements {
1616
match statement {
1717
Statement::ReturnStatement(return_stmt) => {
18-
let mut instrument_args: Vec<'a, Argument<'a>> = builder.vec_with_capacity(2);
18+
let mut instrument_args: OxcVec<'a, Argument<'a>> = builder.vec_with_capacity(2);
1919

2020
// Add the identifier to the arguments
2121
instrument_args.push(Argument::StringLiteral(builder.alloc_string_literal(

instrumentation-wasm/src/js_transformer/transformer_impl.rs

Lines changed: 6 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -57,11 +57,11 @@ impl<'a> Traverse<'a> for Transformer<'a> {
5757
let body = node.value.body.as_mut().unwrap();
5858

5959
if instruction.modify_args && !arg_names.is_empty() {
60-
let arg_names_str = arg_names.join(", ");
6160
insert_modify_args(
6261
self.allocator,
62+
self.ast_builder,
6363
&instruction.identifier,
64-
&arg_names_str,
64+
&arg_names,
6565
body,
6666
instruction.modify_arguments_object,
6767
);
@@ -70,6 +70,7 @@ impl<'a> Traverse<'a> for Transformer<'a> {
7070
if instruction.inspect_args {
7171
insert_inspect_args(
7272
self.allocator,
73+
self.ast_builder,
7374
&instruction.identifier,
7475
self.pkg_version,
7576
body,
@@ -138,11 +139,11 @@ impl<'a> Traverse<'a> for Transformer<'a> {
138139
let body = function_expression.body.as_mut().unwrap();
139140

140141
if instruction.modify_args {
141-
let arg_names_str = arg_names.join(", ");
142142
insert_modify_args(
143143
self.allocator,
144+
self.ast_builder,
144145
&instruction.identifier,
145-
&arg_names_str,
146+
&arg_names,
146147
body,
147148
instruction.modify_arguments_object,
148149
);
@@ -151,6 +152,7 @@ impl<'a> Traverse<'a> for Transformer<'a> {
151152
if instruction.inspect_args {
152153
insert_inspect_args(
153154
self.allocator,
155+
self.ast_builder,
154156
&instruction.identifier,
155157
self.pkg_version,
156158
body,

0 commit comments

Comments
 (0)