Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -139,7 +139,7 @@ type FunctionQuery =
type ModuleMatcher = {
name: string; // Module name
versionRange: string; // Matching semver range
filePath: string; // Path to the file from the module root
filePath: string; // Relative Unix-style path to the file from the module root (e.g. "lib/index.js")
};
```

Expand Down Expand Up @@ -177,7 +177,7 @@ matching instrumentation configurations.

- `module_name` - Name of the module.
- `version` - Version of the module.
- `file_path` - Path to the file from the module root.
- `file_path` - Relative Unix-style path to the file from the module root (e.g. `"lib/index.js"`). Windows-style backslash paths are also accepted and will be normalized automatically.

```ts
free(): void;
Expand Down
10 changes: 6 additions & 4 deletions src/config.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@
**/
use crate::function_query::FunctionQuery;
use nodejs_semver::{Range, SemverError, Version};
use std::path::PathBuf;
use std::path::{Path, PathBuf};

#[cfg_attr(feature = "wasm", derive(tsify::Tsify))]
#[cfg_attr(
Expand Down Expand Up @@ -37,7 +37,7 @@ impl ModuleMatcher {
}

#[must_use]
pub fn matches(&self, module_name: &str, version: &str, file_path: &PathBuf) -> bool {
pub fn matches(&self, module_name: &str, version: &str, file_path: &Path) -> bool {
let version: Version = match version.parse() {
Ok(v) => v,
Err(e) => {
Expand All @@ -46,9 +46,11 @@ impl ModuleMatcher {
}
};

// convert windows paths to unix before comparing against `self.file_path`
let normalized_path = PathBuf::from(file_path.to_string_lossy().replace('\\', "/"));
self.name == module_name
&& version.satisfies(&self.version_range)
&& self.file_path == *file_path
&& self.file_path == normalized_path
}
}

Expand Down Expand Up @@ -120,7 +122,7 @@ impl Config {

impl InstrumentationConfig {
#[must_use]
pub fn matches(&self, module_name: &str, version: &str, file_path: &PathBuf) -> bool {
pub fn matches(&self, module_name: &str, version: &str, file_path: &Path) -> bool {
self.module.matches(module_name, version, file_path)
}
}
4 changes: 2 additions & 2 deletions src/instrumentation.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@
**/
use crate::config::InstrumentationConfig;
use std::collections::HashMap;
use std::path::PathBuf;
use std::path::Path;
use swc_core::common::{Span, SyntaxContext};
use swc_core::ecma::{
ast::{
Expand Down Expand Up @@ -244,7 +244,7 @@ impl Instrumentation {
}

#[must_use]
pub fn matches(&self, module_name: &str, version: &str, file_path: &PathBuf) -> bool {
pub fn matches(&self, module_name: &str, version: &str, file_path: &Path) -> bool {
self.config.matches(module_name, version, file_path)
}

Expand Down
4 changes: 2 additions & 2 deletions src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@
* Unless explicitly stated otherwise all files in this repository are licensed under the Apache-2.0 License.
* This product includes software developed at Datadog (<https://www.datadoghq.com>/). Copyright 2025 Datadog, Inc.
**/
use std::{collections::HashMap, error::Error, path::PathBuf, sync::Arc};
use std::{collections::HashMap, error::Error, path::Path, path::PathBuf, sync::Arc};
use swc::{
config::{IsModule, SourceMapsConfig},
sourcemap::SourceMap,
Expand Down Expand Up @@ -134,7 +134,7 @@ impl Instrumentor {
&self,
module_name: &str,
version: &str,
file_path: &PathBuf,
file_path: &Path,
) -> InstrumentationVisitor {
let instrumentations = self
.instrumentations
Expand Down
16 changes: 15 additions & 1 deletion tests/common/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -13,10 +13,18 @@ static TEST_MODULE_NAME: &str = "undici";
static TEST_MODULE_PATH: &str = "index.mjs";

pub fn transpile_and_test(test_file: &str, mjs: bool, config: Config) {
transpile_and_test_with_path(test_file, mjs, config, PathBuf::from(TEST_MODULE_PATH));
}

pub fn transpile_and_test_with_path(
test_file: &str,
mjs: bool,
config: Config,
file_path: PathBuf,
) {
let test_file = PathBuf::from(test_file);
let test_dir = test_file.parent().expect("Couldn't find test directory");

let file_path = PathBuf::from("index.mjs");
let instrumentor = Instrumentor::new(config);
let mut instrumentations =
instrumentor.get_matching_instrumentations(TEST_MODULE_NAME, "0.0.1", &file_path);
Expand Down Expand Up @@ -46,3 +54,9 @@ pub fn transpile_and_test(test_file: &str, mjs: bool, config: Config) {
pub fn test_module_matcher() -> ModuleMatcher {
ModuleMatcher::new(TEST_MODULE_NAME, ">=0.0.1", TEST_MODULE_PATH).unwrap()
}

static WINDOWS_TEST_MODULE_PATH: &str = "lib/index.mjs";

pub fn windows_module_matcher() -> ModuleMatcher {
ModuleMatcher::new(TEST_MODULE_NAME, ">=0.0.1", WINDOWS_TEST_MODULE_PATH).unwrap()
}
1 change: 1 addition & 0 deletions tests/instrumentor_test.rs
Original file line number Diff line number Diff line change
Expand Up @@ -29,3 +29,4 @@ mod polyfill_mjs;
mod private_method_cjs;
mod var_class_export_alias_mjs;
mod var_named_class_export_alias_mjs;
mod windows_path;
29 changes: 29 additions & 0 deletions tests/wasm/__snapshots__/tests.test.mjs.snap
Original file line number Diff line number Diff line change
Expand Up @@ -287,3 +287,32 @@ export class Up {
"map": "{"version":3,"file":"module.js","sources":["module.ts"],"sourceRoot":"","names":[],"mappings":";;;;;;AAEA,MAAM,CAAA,MAAO,EAAE;IACX,aAAA;;;;;;;;;YACI,OAAO,CAAC,GAAG,CAAC,aAAa,CAAC,CAAC;;;;;;;;;;;;;;;;IAC/B,CAAC;IACD,KAAK,IAAS,EAAA;;;mCAAR;gBACF,OAAO,CAAC,GAAG,CAAC,OAAO,CAAC,CAAC;YACzB,CAAC;;;;;;;;;;IACD,KAAK,CAAC,UAAU,GAAA;;;;;;;;;;;;IAAU,CAAC;IAC3B,GAAG,GAAA;;;;;;;;;;;;IAAU,CAAC;IACd,KAAK,EAAC,IAAK;;;;;;;;;;;;IAAU,CAAC;IACtB,KAAK,CAAC,IAAI,GAAA,CAAU,CAAC;CACxB"}",
}
`;

exports[`windows style paths > should transform ESM module correctly 1`] = `
{
"code": "import { tracingChannel as tr_ch_apm_tracingChannel } from "diagnostics_channel";
const tr_ch_apm$up_fetch = tr_ch_apm_tracingChannel("orchestrion:one:up:fetch");
export class Up {
constructor(){
console.log('constructor');
}
fetch() {
const __apm$original_args = arguments;
const __apm$traced = ()=>{
const __apm$wrapped = ()=>{
console.log('fetch');
};
return __apm$wrapped.apply(null, __apm$original_args);
};
if (!tr_ch_apm$up_fetch.hasSubscribers) return __apm$traced();
return tr_ch_apm$up_fetch.traceSync(__apm$traced, {
arguments,
self: this,
moduleVersion: "1.0.0"
});
}
}
",
"map": undefined,
}
`;
39 changes: 39 additions & 0 deletions tests/wasm/tests.test.mjs
Original file line number Diff line number Diff line change
Expand Up @@ -166,3 +166,42 @@ export class Up {
}).toThrow('Failed to find injection points for: ["constructor", "fetch", "asyncFetch", "get", "send"]');
});
});

describe('windows style paths', () => {
const instrumentor = create([
{
channelName: "up:fetch",
module: { name: "one", versionRange: ">=1", filePath: "path/to/file.js" },
functionQuery: {
className: "Up",
methodName: "fetch",
kind: "Sync",
},
},
]);

const matchedTransforms = instrumentor.getTransformer(
"one",
"1.0.0",
"path\\to\\file.js",
);

test('should get transformer for matching module', () => {
expect(matchedTransforms).toBeTruthy();
});

test('should transform ESM module correctly', () => {
const originalEsm = `export class Up {
constructor() {
console.log('constructor')
}

fetch() {
console.log('fetch')
}
}`;

const output = matchedTransforms.transform(originalEsm, 'esm');
expect(output).toMatchSnapshot();
});
})
9 changes: 9 additions & 0 deletions tests/windows_path/mod.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
/**
* Unless explicitly stated otherwise all files in this repository are licensed under the Apache-2.0 License.
* This product includes software developed at Datadog (https://www.datadoghq.com/). Copyright 2025 Datadog, Inc.
**/
async function fetch (url) {
return 42;
}

module.exports = { fetch };
17 changes: 17 additions & 0 deletions tests/windows_path/mod.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
use crate::common::*;
use orchestrion_js::*;
use std::path::PathBuf;

#[test]
fn windows_path() {
transpile_and_test_with_path(
file!(),
false,
Config::new_single(InstrumentationConfig::new(
"fetch_decl",
windows_module_matcher(),
FunctionQuery::function_declaration("fetch", FunctionKind::Async),
)),
PathBuf::from("lib\\index.mjs"),
);
}
17 changes: 17 additions & 0 deletions tests/windows_path/test.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
/**
* Unless explicitly stated otherwise all files in this repository are licensed under the Apache-2.0 License.
* This product includes software developed at Datadog (https://www.datadoghq.com/). Copyright 2025 Datadog, Inc.
**/
const { fetch } = require('./instrumented.js');
const { assert, getContext } = require('../common/preamble.js');
const context = getContext('orchestrion:undici:fetch_decl');
(async () => {
const result = await fetch('https://example.com');
assert.strictEqual(result, 42);
assert.deepStrictEqual(context, {
start: true,
end: true,
asyncStart: 42,
asyncEnd: 42
});
})();