Skip to content

Commit 77f1df7

Browse files
authored
fix: Handle module.exports = class Foo when locating classes (#7)
1 parent 65fbb26 commit 77f1df7

File tree

9 files changed

+123
-5
lines changed

9 files changed

+123
-5
lines changed

src/instrumentation.rs

Lines changed: 12 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -7,9 +7,9 @@ use std::path::PathBuf;
77
use swc_core::common::{Span, SyntaxContext};
88
use swc_core::ecma::{
99
ast::{
10-
ArrowExpr, AssignExpr, AssignTarget, BlockStmt, ClassDecl, ClassMethod, Constructor, Expr,
11-
FnDecl, FnExpr, Ident, Lit, MemberProp, MethodProp, Module, ModuleItem, Pat, PropName,
12-
Script, SimpleAssignTarget, Stmt, Str, VarDecl,
10+
ArrowExpr, AssignExpr, AssignTarget, BlockStmt, ClassDecl, ClassExpr, ClassMethod,
11+
Constructor, Expr, FnDecl, FnExpr, Ident, Lit, MemberProp, MethodProp, Module, ModuleItem,
12+
Pat, PropName, Script, SimpleAssignTarget, Stmt, Str, VarDecl,
1313
},
1414
atoms::Atom,
1515
};
@@ -237,6 +237,15 @@ impl Instrumentation {
237237
true
238238
}
239239

240+
pub fn visit_mut_class_expr(&mut self, node: &mut ClassExpr) -> bool {
241+
self.is_correct_class = self.config.function_query.class_name().is_none_or(|class| {
242+
node.ident
243+
.as_ref()
244+
.is_some_and(|ident| ident.sym.as_ref() == class)
245+
});
246+
true
247+
}
248+
240249
pub fn visit_mut_class_method(&mut self, node: &mut ClassMethod) -> bool {
241250
let name = match &node.key {
242251
PropName::Ident(ident) => ident.sym.clone(),

src/lib.rs

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -27,8 +27,8 @@ use swc_core::{
2727
common::{comments::Comments, errors::ColorConfig, FileName, FilePathMapping},
2828
ecma::{
2929
ast::{
30-
AssignExpr, ClassDecl, ClassMethod, Constructor, EsVersion, FnDecl, MethodProp, Module,
31-
Script, Str, VarDecl,
30+
AssignExpr, ClassDecl, ClassExpr, ClassMethod, Constructor, EsVersion, FnDecl,
31+
MethodProp, Module, Script, Str, VarDecl,
3232
},
3333
visit::{VisitMut, VisitMutWith},
3434
},
@@ -227,6 +227,7 @@ impl VisitMut for InstrumentationVisitor {
227227
visit_with_all_fn!(visit_mut_method_prop, MethodProp);
228228
visit_with_all_fn!(visit_mut_assign_expr, AssignExpr);
229229
visit_with_all_fn!(visit_mut_class_decl, ClassDecl);
230+
visit_with_all_fn!(visit_mut_class_expr, ClassExpr);
230231
visit_with_all_fn!(visit_mut_class_method, ClassMethod);
231232
visit_with_all_fn!(visit_mut_constructor, Constructor);
232233
}

tests/class_expression_cjs/mod.js

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
/**
2+
* Unless explicitly stated otherwise all files in this repository are licensed under the Apache-2.0 License.
3+
* This product includes software developed at Datadog (https://www.datadoghq.com/). Copyright 2025 Datadog, Inc.
4+
**/
5+
class UndiciBase {
6+
async fetch (url) {
7+
return 42;
8+
}
9+
}
10+
class Undici extends UndiciBase {
11+
async fetch (url) {
12+
return super.fetch(url);
13+
}
14+
}
15+
16+
module.exports = Undici;
17+

tests/class_expression_cjs/mod.rs

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 class_method_cjs() {
6+
transpile_and_test(
7+
file!(),
8+
false,
9+
Config::new_single(InstrumentationConfig::new(
10+
"Undici:fetch",
11+
test_module_matcher(),
12+
FunctionQuery::class_method("Undici", "fetch", FunctionKind::Async),
13+
)),
14+
);
15+
}

tests/class_expression_cjs/test.js

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
/**
2+
* Unless explicitly stated otherwise all files in this repository are licensed under the Apache-2.0 License.
3+
* This product includes software developed at Datadog (https://www.datadoghq.com/). Copyright 2025 Datadog, Inc.
4+
**/
5+
const Undici = require('./instrumented.js');
6+
const { assert, getContext } = require('../common/preamble.js');
7+
const context = getContext('orchestrion:undici:Undici:fetch');
8+
(async () => {
9+
const undici = new Undici;
10+
const result = await undici.fetch('https://example.com');
11+
assert.strictEqual(result, 42);
12+
assert.deepStrictEqual(context, {
13+
start: true,
14+
end: true,
15+
asyncStart: 42,
16+
asyncEnd: 42
17+
});
18+
})();

tests/instrumentor_test.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@
44
**/
55
mod common;
66

7+
mod class_expression_cjs;
78
mod class_method_cjs;
89
mod constructor_cjs;
910
mod constructor_mjs;

tests/wasm/testdata/expected-cjs.js

Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,40 @@
1+
const { tracingChannel: tr_ch_apm_tracingChannel } = require("diagnostics_channel");
2+
const tr_ch_apm$up_fetch = tr_ch_apm_tracingChannel("orchestrion:one:up:fetch");
3+
const tr_ch_apm$up_constructor = tr_ch_apm_tracingChannel("orchestrion:one:up:constructor");
4+
module.exports = class Up {
5+
constructor(){
6+
const tr_ch_apm_ctx$up_constructor = {
7+
arguments
8+
};
9+
try {
10+
if (tr_ch_apm$up_constructor.hasSubscribers) {
11+
tr_ch_apm$up_constructor.start.publish(tr_ch_apm_ctx$up_constructor);
12+
}
13+
console.log('constructor');
14+
} catch (tr_ch_err) {
15+
if (tr_ch_apm$up_constructor.hasSubscribers) {
16+
tr_ch_apm_ctx$up_constructor.error = tr_ch_err;
17+
try {
18+
tr_ch_apm_ctx$up_constructor.self = this;
19+
} catch (refErr) {}
20+
tr_ch_apm$up_constructor.error.publish(tr_ch_apm_ctx$up_constructor);
21+
}
22+
throw tr_ch_err;
23+
} finally{
24+
if (tr_ch_apm$up_constructor.hasSubscribers) {
25+
tr_ch_apm_ctx$up_constructor.self = this;
26+
tr_ch_apm$up_constructor.end.publish(tr_ch_apm_ctx$up_constructor);
27+
}
28+
}
29+
}
30+
fetch() {
31+
const traced = ()=>{
32+
console.log('fetch');
33+
};
34+
if (!tr_ch_apm$up_fetch.hasSubscribers) return traced();
35+
return tr_ch_apm$up_fetch.traceSync(traced, {
36+
arguments,
37+
self: this
38+
});
39+
}
40+
};

tests/wasm/testdata/original-cjs.js

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
module.exports = class Up {
2+
constructor() {
3+
console.log('constructor')
4+
}
5+
6+
fetch() {
7+
console.log('fetch')
8+
}
9+
}
10+

tests/wasm/tests.mjs

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -33,3 +33,10 @@ const output = matchedTransforms.transform(original.toString('utf8'), true);
3333

3434
const expected = await fs.readFile(path.join(import.meta.dirname, './testdata/expected.mjs'))
3535
assert.strictEqual(output, expected.toString('utf8'));
36+
37+
const originalCjs = await fs.readFile(path.join(import.meta.dirname, './testdata/original-cjs.js'))
38+
const outputCjs = matchedTransforms.transform(originalCjs.toString('utf8'), false);
39+
40+
41+
const expectedCjs = await fs.readFile(path.join(import.meta.dirname, './testdata/expected-cjs.js'))
42+
assert.strictEqual(outputCjs, expectedCjs.toString('utf8'));

0 commit comments

Comments
 (0)