@apm-js-collab/code-transformer 0.7.2 → 0.8.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -1,22 +1,183 @@
1
1
  # `@apm-js-collab/code-transformer`
2
2
 
3
- This is a temporary fork of [`DataDog/orchestrion-js`](https://github.com/DataDog/orchestrion-js/). We intend all changes to be upstreamed to the original repository,
3
+ This is a fork of
4
+ [`DataDog/orchestrion-js`](https://github.com/DataDog/orchestrion-js/).
4
5
 
5
- This is a library for instrumenting Node.js libraries at build or load time.
6
+ This is a library to aid in instrumenting Node.js libraries at build or load
7
+ time.
6
8
 
7
- It provides `VisitMut` implementations for SWC's AST nodes, which can be used to insert tracing code into matching functions.
8
- It can be used in SWC plugins, or anything else that mutates JavaScript ASTs using SWC.
9
+ It uses SWC's Rust AST walker to inject code that calls Node.js
10
+ [`TracingChannel`](https://nodejs.org/api/diagnostics_channel.html#class-tracingchannel).
9
11
 
10
- `@apm-js-collab/code-transformer` is built as a JavaScript module, which can be used from Node.js.
12
+ You likely don't want to use this library directly; instead, consider using:
13
+
14
+ - [`@apm-js-collab/tracing-hooks/`](https://github.com/apm-js-collab/tracing-hooks/)
15
+ - ESM and `require` hooks to instrument modules as they are loaded.
16
+ - [`apm-js-collab/code-transformer-bundler-plugins`](https://github.com/apm-js-collab/code-transformer-bundler-plugins)
17
+ - Bundler plugins for webpack, Vite, Rollup and esbuild to instrument modules
18
+ at build time.
19
+
20
+ ## JavaScript
21
+
22
+ `@apm-js-collab/code-transformer` exposes the Rust library as a WebAssembly
23
+ module.
24
+
25
+ ### Building
11
26
 
12
27
  To build the JavaScript module:
28
+
13
29
  - Ensure you have [Rust installed](https://www.rust-lang.org/tools/install)
14
- - Install the wasm toolchain `rustup target add wasm32-unknown-unknown --toolchain stable`
15
- - Install dependencies and build the module `npm install && npm run build`
30
+ - Install the wasm toolchain\
31
+ `rustup target add wasm32-unknown-unknown --toolchain stable`
32
+ - Install dependencies and build the module\
33
+ `npm install && npm run build`
34
+
35
+ ### Usage
36
+
37
+ ```javascript
38
+ import * as codeTransformer from "@apm-js-collab/code-transformer";
39
+
40
+ // The full instrumentation config
41
+ const instrumentation = {
42
+ // The name of the diagnostics channel
43
+ channelName: "my-channel",
44
+ // Define the module you'd like to inject tracing channels into
45
+ module: {
46
+ name: "my-module",
47
+ versionRange: ">=1.0.0",
48
+ filePath: "./dist/index.js",
49
+ },
50
+ // Define the function you'd like to instrument
51
+ // (e.g., match a method named 'foo' that returns a Promise)
52
+ functionQuery: {
53
+ methodName: "fetch",
54
+ kind: "Async",
55
+ },
56
+ };
57
+
58
+ // Create an InstrumentationMatcher with an array of instrumentation configs
59
+ const matcher = codeTransformer.create([instrumentation]);
60
+
61
+ // Get a transformer for a specific module
62
+ const transformer = matcher.getTransformer(
63
+ "my-module",
64
+ "1.2.3",
65
+ "./dist/index.js",
66
+ );
67
+
68
+ if (transformer === undefined) {
69
+ throw new Error("No transformer found for module");
70
+ }
71
+
72
+ // Transform code
73
+ const inputCode = "async function fetch() { return 42; }";
74
+ const result = transformer.transform(inputCode, "unknown");
75
+ console.log(result.code);
76
+
77
+ // Both the matcher and transformer should be freed after use!
78
+ matcher.free();
79
+ transformer.free();
80
+ ```
81
+
82
+ ### API Reference
83
+
84
+ ```ts
85
+ type ModuleType = "esm" | "cjs" | "unknown";
86
+ type FunctionKind = "Sync" | "Async";
87
+ ```
88
+
89
+ #### **`FunctionQuery` Variants**
90
+
91
+ ```ts
92
+ type FunctionQuery =
93
+ | // Match class constructor
94
+ { className: string; index?: number }
95
+ | // Match class method
96
+ {
97
+ className: string;
98
+ methodName: string;
99
+ kind: FunctionKind;
100
+ index?: number;
101
+ }
102
+ | // Match method on objects
103
+ { methodName: string; kind: FunctionKind; index?: number }
104
+ | // Match standalone function
105
+ { functionName: string; kind: FunctionKind; index?: number }
106
+ | // Match arrow function or function expression
107
+ { expressionName: string; kind: FunctionKind; index?: number };
108
+ ```
109
+
110
+ #### **`ModuleMatcher`**
111
+
112
+ ```ts
113
+ type ModuleMatcher = {
114
+ name: string; // Module name
115
+ versionRange: string; // Matching semver range
116
+ filePath: string; // Path to the file from the module root
117
+ };
118
+ ```
119
+
120
+ #### **`InstrumentationConfig`**
121
+
122
+ ```ts
123
+ type InstrumentationConfig = {
124
+ channelName: string; // Name of the diagnostics channel
125
+ module: ModuleMatcher;
126
+ functionQuery: FunctionQuery;
127
+ };
128
+ ```
129
+
130
+ ### Functions
131
+
132
+ ```ts
133
+ create(configs: InstrumentationConfig[], dc_module?: string | null): InstrumentationMatcher;
134
+ ```
135
+
136
+ Create a matcher for one or more instrumentation configurations.
137
+
138
+ - `configs` - Array of instrumentation configurations.
139
+ - `dc_module` - Optional module to import `diagnostics_channel` API from.
140
+
141
+ #### **`InstrumentationMatcher`**
142
+
143
+ ```ts
144
+ getTransformer(module_name: string, version: string, file_path: string): Transformer | undefined;
145
+ ```
146
+
147
+ Gets a transformer for a specific module and file.
148
+
149
+ Returns a `Transformer` for the given module, or `undefined` if there were no
150
+ matching instrumentation configurations.
151
+
152
+ - `module_name` - Name of the module.
153
+ - `version` - Version of the module.
154
+ - `file_path` - Path to the file from the module root.
155
+
156
+ ```ts
157
+ free(): void;
158
+ ```
159
+
160
+ Free the matcher memory when it's no longer needed.
161
+
162
+ #### **`Transformer`**
163
+
164
+ ```ts
165
+ transform(code: string, module_type: ModuleType, sourcemap?: string | undefined): TransformOutput;
166
+ ```
167
+
168
+ Transforms the code, injecting tracing as configured.
169
+
170
+ Returns `{ code, map }`. `map` will be undefined if no sourcemap was supplied.
171
+
172
+ - `code` - The JavaScript/TypeScript code to transform.
173
+ - `module_type` - The type of module being transformed.
174
+ - `sourcemap` - Optional existing source map for the code.
16
175
 
17
- ## Contributing
176
+ ```ts
177
+ free(): void;
178
+ ```
18
179
 
19
- See CONTRIBUTING.md
180
+ Free the transformer memory when it's no longer needed.
20
181
 
21
182
  ## License
22
183
 
package/index.d.ts ADDED
@@ -0,0 +1,6 @@
1
+ import type { InstrumentationConfig, InstrumentationMatcher } from './pkg/orchestrion_js';
2
+ /**
3
+ * Create a new instrumentation matcher from an array of instrumentation configs.
4
+ */
5
+ export declare function create(configs: InstrumentationConfig[], dc_module?: string | null): InstrumentationMatcher;
6
+ export type { FunctionKind, FunctionQuery, InstrumentationConfig, InstrumentationMatcher, ModuleMatcher, ModuleType, TransformOutput, Transformer, } from './pkg/orchestrion_js';
package/index.js ADDED
@@ -0,0 +1,18 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.create = create;
4
+ // ./pkg/orchestrion_js.js has a side effect of loading the wasm binary.
5
+ // We only want that if the library is actually used!
6
+ var cachedCreate;
7
+ /**
8
+ * Create a new instrumentation matcher from an array of instrumentation configs.
9
+ */
10
+ function create(configs, dc_module) {
11
+ if (!cachedCreate) {
12
+ cachedCreate = require('./pkg/orchestrion_js.js').create;
13
+ }
14
+ if (cachedCreate === undefined) {
15
+ throw new Error("Failed to load '@apm-js-collab/code-transformer'");
16
+ }
17
+ return cachedCreate(configs, dc_module);
18
+ }
package/package.json CHANGED
@@ -1,26 +1,30 @@
1
1
  {
2
2
  "name": "@apm-js-collab/code-transformer",
3
- "version": "0.7.2",
3
+ "version": "0.8.0",
4
4
  "license": "Apache-2.0",
5
5
  "repository": {
6
6
  "type": "git",
7
7
  "url": "https://github.com/apm-js-collab/orchestrion-js.git"
8
8
  },
9
9
  "files": [
10
- "./pkg/orchestrion_js_bg.wasm",
11
10
  "./pkg/orchestrion_js.js",
12
11
  "./pkg/orchestrion_js.d.ts",
12
+ "./index.js",
13
+ "./index.d.ts",
13
14
  "LICENSE",
14
15
  "NOTICE"
15
16
  ],
16
- "main": "./pkg/orchestrion_js.js",
17
- "types": "./pkg/orchestrion_js.d.ts",
17
+ "main": "./index.js",
18
+ "types": "./index.d.ts",
18
19
  "scripts": {
19
- "build": "wasm-pack build --target nodejs --release -- --features wasm",
20
+ "build": "wasm-pack build --target nodejs --release -- --features wasm && yarn build:wrapper && yarn build:inline-binary",
21
+ "build:wrapper": "tsc index.ts --declaration --module commonjs",
22
+ "build:inline-binary": "node inline-binary.js",
20
23
  "test": "vitest run",
21
24
  "test:watch": "vitest"
22
25
  },
23
26
  "devDependencies": {
27
+ "@types/node": "^18.0.0",
24
28
  "source-map": "^0.7.6",
25
29
  "typescript": "^5.8.3",
26
30
  "vitest": "^3.2.4",
@@ -1,5 +1,8 @@
1
1
  /* tslint:disable */
2
2
  /* eslint-disable */
3
+ /**
4
+ * Create a new instrumentation matcher from an array of instrumentation configs.
5
+ */
3
6
  export function create(configs: InstrumentationConfig[], dc_module?: string | null): InstrumentationMatcher;
4
7
  /**
5
8
  * Output of a transformation operation
@@ -15,34 +18,78 @@ export interface TransformOutput {
15
18
  map: string | undefined;
16
19
  }
17
20
 
21
+ /**
22
+ * Configuration for injecting instrumentation code
23
+ */
18
24
  export interface InstrumentationConfig {
25
+ /**
26
+ * The name of the diagnostics channel to publish to
27
+ */
19
28
  channelName: string;
29
+ /**
30
+ * The module matcher to identify the module and file to instrument
31
+ */
20
32
  module: ModuleMatcher;
33
+ /**
34
+ * The function query to identify the function to instrument
35
+ */
21
36
  functionQuery: FunctionQuery;
22
37
  }
23
38
 
39
+ /**
40
+ * Describes the module and file path you would like to match
41
+ */
24
42
  export interface ModuleMatcher {
43
+ /**
44
+ * The name of the module you want to match
45
+ */
25
46
  name: string;
47
+ /**
48
+ * The semver range that you want to match
49
+ */
26
50
  versionRange: string;
51
+ /**
52
+ * The path of the file you want to match from the module root
53
+ */
27
54
  filePath: string;
28
55
  }
29
56
 
57
+ /**
58
+ * Describes which function to instrument
59
+ */
30
60
  export type FunctionQuery = { className: string; methodName: string; kind: FunctionKind; index?: number } | { className: string; index?: number } | { methodName: string; kind: FunctionKind; index?: number } | { functionName: string; kind: FunctionKind; index?: number } | { expressionName: string; kind: FunctionKind; index?: number };
31
61
 
62
+ /**
63
+ * The kind of function - Sync or returns a promise
64
+ */
32
65
  export type FunctionKind = "Sync" | "Async";
33
66
 
67
+ /**
68
+ * The type of module being passed - ESM, CJS or unknown
69
+ */
34
70
  export type ModuleType = "esm" | "cjs" | "unknown";
35
71
 
72
+ /**
73
+ * The InstrumentationMatcher is responsible for matching specific modules
74
+ */
36
75
  export class InstrumentationMatcher {
37
76
  private constructor();
38
77
  free(): void;
78
+ /**
79
+ * Get a transformer for the given module name, version and file path.
80
+ * Returns `undefined` if no matching instrumentations are found.
81
+ */
39
82
  getTransformer(module_name: string, version: string, file_path: string): Transformer | undefined;
40
83
  }
84
+ /**
85
+ * The Transformer is responsible for transforming JavaScript code.
86
+ */
41
87
  export class Transformer {
42
88
  private constructor();
43
89
  free(): void;
44
90
  /**
45
- * Transform the given JavaScript code with optional sourcemap support.
91
+ * Transform JavaScript code and optionally sourcemap.
92
+ *
46
93
  * # Errors
47
94
  * Returns an error if the transformation fails to find injection points.
48
95
  */