@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 +170 -9
- package/index.d.ts +6 -0
- package/index.js +18 -0
- package/package.json +9 -5
- package/pkg/orchestrion_js.d.ts +48 -1
- package/pkg/orchestrion_js.js +12 -5
- package/pkg/orchestrion_js_bg.wasm +0 -0
package/README.md
CHANGED
|
@@ -1,22 +1,183 @@
|
|
|
1
1
|
# `@apm-js-collab/code-transformer`
|
|
2
2
|
|
|
3
|
-
This is a
|
|
3
|
+
This is a fork of
|
|
4
|
+
[`DataDog/orchestrion-js`](https://github.com/DataDog/orchestrion-js/).
|
|
4
5
|
|
|
5
|
-
This is a library
|
|
6
|
+
This is a library to aid in instrumenting Node.js libraries at build or load
|
|
7
|
+
time.
|
|
6
8
|
|
|
7
|
-
It
|
|
8
|
-
|
|
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
|
-
|
|
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
|
|
15
|
-
|
|
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
|
-
|
|
176
|
+
```ts
|
|
177
|
+
free(): void;
|
|
178
|
+
```
|
|
18
179
|
|
|
19
|
-
|
|
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.
|
|
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": "./
|
|
17
|
-
"types": "./
|
|
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",
|
package/pkg/orchestrion_js.d.ts
CHANGED
|
@@ -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
|
|
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
|
*/
|