Skip to content

Commit 052c33b

Browse files
committed
feat: Match more class declarations for export alias check
1 parent f971182 commit 052c33b

File tree

14 files changed

+192
-8
lines changed

14 files changed

+192
-8
lines changed

src/instrumentation.rs

Lines changed: 46 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -272,7 +272,9 @@ impl Instrumentation {
272272
.matches_decl(node, &mut self.count)
273273
&& node.function.body.is_some()
274274
{
275-
if let Some(body) = node.function.body.as_mut() {
275+
if node.function.is_generator {
276+
self.has_injected = true;
277+
} else if let Some(body) = node.function.body.as_mut() {
276278
self.insert_tracing(body, &node.function.params, node.function.is_async);
277279
}
278280
}
@@ -287,6 +289,18 @@ impl Instrumentation {
287289
if let Pat::Ident(name) = &decl.name {
288290
traced = self.trace_expr_or_count(func_expr, &name.id.sym);
289291
}
292+
} else if let Some(class_expr) = init.as_mut_class() {
293+
if let Pat::Ident(name) = &decl.name {
294+
if class_expr.ident.is_none() {
295+
class_expr.ident = Some(name.id.clone());
296+
} else {
297+
self.is_correct_class = self
298+
.config
299+
.function_query
300+
.class_name()
301+
.is_none_or(|class| name.id.sym.as_ref() == class);
302+
}
303+
}
290304
}
291305
}
292306
}
@@ -303,11 +317,15 @@ impl Instrumentation {
303317
}
304318

305319
pub fn visit_mut_class_expr(&mut self, node: &mut ClassExpr) -> bool {
306-
self.is_correct_class = self.config.function_query.class_name().is_none_or(|class| {
307-
node.ident
308-
.as_ref()
309-
.is_some_and(|ident| ident.sym.as_ref() == class)
310-
});
320+
// Don't override is_correct_class if it was already set by
321+
// visit_mut_var_decl for `var X = class Y { ... }` patterns.
322+
if !self.is_correct_class {
323+
self.is_correct_class = self.config.function_query.class_name().is_none_or(|class| {
324+
node.ident
325+
.as_ref()
326+
.is_some_and(|ident| ident.sym.as_ref() == class)
327+
});
328+
}
311329
true
312330
}
313331

@@ -328,7 +346,11 @@ impl Instrumentation {
328346
.matches_method(&mut self.count, name.as_ref())
329347
&& node.function.body.is_some()
330348
{
331-
if let Some(body) = node.function.body.as_mut() {
349+
if node.function.is_generator {
350+
// Skip generators — the tracing wrapper doesn't support yield*.
351+
// Mark as injected so the transform doesn't report a failure.
352+
self.has_injected = true;
353+
} else if let Some(body) = node.function.body.as_mut() {
332354
self.insert_tracing(body, &node.function.params, node.function.is_async);
333355
}
334356
}
@@ -382,7 +404,9 @@ impl Instrumentation {
382404
.matches_method(&mut self.count, name.as_ref())
383405
&& node.function.body.is_some()
384406
{
385-
if let Some(body) = node.function.body.as_mut() {
407+
if node.function.is_generator {
408+
self.has_injected = true;
409+
} else if let Some(body) = node.function.body.as_mut() {
386410
self.insert_tracing(body, &node.function.params, node.function.is_async);
387411
}
388412
}
@@ -416,6 +440,20 @@ impl Instrumentation {
416440
_ => {}
417441
}
418442
}
443+
} else if let Some(class_expr) = node.right.as_mut_class() {
444+
if let AssignTarget::Simple(target) = &node.left {
445+
if let SimpleAssignTarget::Ident(name) = target {
446+
if class_expr.ident.is_none() {
447+
class_expr.ident = Some(name.id.clone());
448+
} else {
449+
self.is_correct_class = self
450+
.config
451+
.function_query
452+
.class_name()
453+
.is_none_or(|class| name.id.sym.as_ref() == class);
454+
}
455+
}
456+
}
419457
}
420458
!traced
421459
}
Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
const J = class {
2+
async fetch(url) {
3+
return 42;
4+
}
5+
};
6+
7+
export { J as Undici };
Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
use crate::common::*;
2+
use orchestrion_js::*;
3+
4+
#[test]
5+
fn const_class_export_alias_mjs() {
6+
transpile_and_test(
7+
file!(),
8+
true,
9+
Config::new_single(InstrumentationConfig::new(
10+
"Undici:fetch",
11+
test_module_matcher(),
12+
FunctionQuery::class_method("Undici", "fetch", FunctionKind::Async).as_export_alias(),
13+
)),
14+
);
15+
}
Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
import { Undici } from './instrumented.mjs';
2+
import { assert, getContext } from '../common/preamble.js';
3+
const context = getContext('orchestrion:undici:Undici:fetch');
4+
const undici = new Undici();
5+
const result = await undici.fetch('https://example.com');
6+
assert.strictEqual(result, 42);
7+
assert.deepStrictEqual(context, {
8+
start: true,
9+
end: true,
10+
asyncStart: 42,
11+
asyncEnd: 42
12+
});

tests/instrumentor_test.rs

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@ mod common;
77
mod arguments_mutation;
88
mod class_expression_cjs;
99
mod class_method_cjs;
10+
mod const_class_export_alias_mjs;
1011
mod constructor_cjs;
1112
mod constructor_mjs;
1213
mod decl_cjs;
@@ -18,10 +19,13 @@ mod expr_cjs;
1819
mod expr_mjs;
1920
mod index_cjs;
2021
mod injection_failure;
22+
mod let_class_export_alias_mjs;
2123
mod multiple_class_method_cjs;
2224
mod multiple_load_cjs;
2325
mod nested_functions;
2426
mod object_method_cjs;
2527
mod polyfill_cjs;
2628
mod polyfill_mjs;
2729
mod private_method_cjs;
30+
mod var_class_export_alias_mjs;
31+
mod var_named_class_export_alias_mjs;
Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
let J = class {
2+
async fetch(url) {
3+
return 42;
4+
}
5+
};
6+
7+
export { J as Undici };
Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
use crate::common::*;
2+
use orchestrion_js::*;
3+
4+
#[test]
5+
fn let_class_export_alias_mjs() {
6+
transpile_and_test(
7+
file!(),
8+
true,
9+
Config::new_single(InstrumentationConfig::new(
10+
"Undici:fetch",
11+
test_module_matcher(),
12+
FunctionQuery::class_method("Undici", "fetch", FunctionKind::Async).as_export_alias(),
13+
)),
14+
);
15+
}
Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
import { Undici } from './instrumented.mjs';
2+
import { assert, getContext } from '../common/preamble.js';
3+
const context = getContext('orchestrion:undici:Undici:fetch');
4+
const undici = new Undici();
5+
const result = await undici.fetch('https://example.com');
6+
assert.strictEqual(result, 42);
7+
assert.deepStrictEqual(context, {
8+
start: true,
9+
end: true,
10+
asyncStart: 42,
11+
asyncEnd: 42
12+
});
Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
var J = class {
2+
async fetch(url) {
3+
return 42;
4+
}
5+
};
6+
7+
export { J as Undici };
Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
use crate::common::*;
2+
use orchestrion_js::*;
3+
4+
#[test]
5+
fn var_class_export_alias_mjs() {
6+
transpile_and_test(
7+
file!(),
8+
true,
9+
Config::new_single(InstrumentationConfig::new(
10+
"Undici:fetch",
11+
test_module_matcher(),
12+
FunctionQuery::class_method("Undici", "fetch", FunctionKind::Async).as_export_alias(),
13+
)),
14+
);
15+
}

0 commit comments

Comments
 (0)