@apm-js-collab/code-transformer

中文文档
0.19.0发布于 2026/10/22Apache-2.0TypeScriptCommonJS构建来源已验证近 30 天下载 4573万

这是一个在构建或加载时间帮助给Node.js 库配置仪器的图书馆.

中文使用文档
文档目录12 节
  1. Java 脚本
  2. 使用量
  3. 导出异名
  4. 更改返回值
  5. AST 查询
  6. 自定义变形
  7. API 参考
  8. 职能
  9. CLI 工具
  10. CLI 使用量
  11. CLI 示例
  12. 许可证

管弦乐-JS/ @apm-js-collab/code-transformer

这是一个用于帮助在构建或加载时对 Node.js 库进行设备化的图书馆 时间.

它使用一个AST行走器来注入代码,该代码称为Node.js TracingChannel。 。 。 .

您可能不想直接使用此库, 而是考虑使用 :

Java 脚本

@apm-js-collab/code-transformer 揭发图书馆.

使用量

import * as codeTransformer from "@apm-js-collab/code-transformer";

// The full instrumentation config
const instrumentation = {
    // The name of the diagnostics channel
    channelName: "my-channel",
    // Define the module you'd like to inject tracing channels into
    module: {
        name: "my-module",
        versionRange: ">=1.0.0",
        filePath: "./dist/index.js",
    },
    // Define the function you'd like to instrument
    // (e.g., match a method named 'foo' that returns a Promise)
    functionQuery: {
        methodName: "fetch",
        kind: "Async",
    },
};

// Create an InstrumentationMatcher with an array of instrumentation configs
const matcher = codeTransformer.create([instrumentation]);

// Get a transformer for a specific module
const transformer = matcher.getTransformer(
    "my-module",
    "1.2.3",
    "./dist/index.js",
);

if (transformer === undefined) {
    throw new Error("No transformer found for module");
}

// Transform code
const inputCode = "async function fetch() { return 42; }";
const result = transformer.transform(inputCode, "unknown");
console.log(result.code);

导出异名

当模块使用不同的名称再导出函数或类时 export { local as exported },你可以瞄准 导出 名称中 FunctionQuery 设置 isExportAlias: true。变压器将解决 在匹配前将别名移至本地声明.

例如:

function f(url) { return fetch(url); }
export { f as fetchAliased };

你可以瞄准目标 fetchAliased 在配置中 :

const instrumentation = {
    channelName: "my-channel",
    module: { name: "my-module", versionRange: ">=1.0.0", filePath: "./index.mjs" },
    functionQuery: { functionName: "fetchAliased", kind: "Async", isExportAlias: true },
};

这也有利于阶级出口(例如:, export { MyClass as PublicClass }) (中文(简体) ).

更改返回值

用户既可以观察函数的返回值,也可以变异函数的返回值 通过 message.result重新调配 message.result 当 函数返回您需要的另一个函数(或对象) 包装,像工厂 返回每个要求处理器.

对于 同步 函数,重新指定 message.result 输入 end 处理器 :

const instrumentation = {
    channelName: "create-handler",
    module: { name: "my-framework", versionRange: ">=1.0.0", filePath: "lib/router.js" },
    functionQuery: { methodName: "create", kind: "Sync" },
};
const { tracingChannel } = require("node:diagnostics_channel");

tracingChannel("orchestrion:my-framework:create-handler").subscribe({
    end(message) {
        const original = message.result;
        // Replace the returned handler with a wrapped version.
        message.result = function wrapped(...args) {
            // ...start a span, etc.
            return original.apply(this, args);
        };
    },
});

对于 一个同步 函数,重新指定 message.result 输入 asyncEnd 操作者替换返回的许诺值 决心——例如,将承诺决定的功能包起来 改为:

const instrumentation = {
    channelName: "load-handler",
    module: { name: "my-framework", versionRange: ">=1.0.0", filePath: "lib/router.js" },
    functionQuery: { methodName: "load", kind: "Async" },
};
tracingChannel("orchestrion:my-framework:load-handler").subscribe({
    asyncEnd(message) {
        const original = message.result;
        message.result = function wrapped(...args) {
            // ...start a span, etc.
            return original.apply(this, args);
        };
    },
});

[!INFO]

更改一个合成函数的解析值, 仅工作 当它返回本地时 Promise (单位:千美元)value instanceof Promise) (中文(简体) ). 承诺子类和其他可使用土地是 侧链并返回到呼叫者 不变,以便他们 子类特定方法(例如:. APIPromise.withResponse()(中文(简体) ) 仍可使用;因此,其确定的价值 无法 为: 变异,和再分配 message.result 他们没有 效应.

在抛出路径上,原始错误仍然传播 替换返回值仅适用于函数返回时(或 通常情况下。 如果没有订阅者重新指定 message.result,则 原始返回值保持不变.

AST 查询

名称 FunctionQuery 涵盖常见情况的变式 (命名函数,类/对象方法,表达式). 当你 需要瞄准一个无法表达的节点,例如 匿名 由工厂返回的函数 (装饰厂,a) 每个请求处理器,您可以设置 astQuery 改为生 风情 选择器代替.

现在, astQuery 选择乐器的节点 优先于 functionQuery匹配字段; functionQuery 然后只提供行为(kind, (中文(简体) ), index, (中文(简体) ), callbackIndex)并可能被省略(默认为 kind: "Sync") (中文(简体) ).

例如,工厂归还的装饰器的仪器:

function Injectable(options) {
    return (target) => { /* applied to the decorated class */ };
}
const instrumentation = {
    channelName: "injectable-apply",
    module: { name: "@nestjs/common", versionRange: ">=8.0.0", filePath: "decorators/core/injectable.decorator.js" },
    // Match the arrow returned from `Injectable`. There is no name to target!
    astQuery: 'FunctionDeclaration[id.name="Injectable"] ReturnStatement > ArrowFunctionExpression',
    functionQuery: { kind: "Sync" },
};

每次安装时,通道会起火 可用的装饰目标为 message.arguments[0],哪个a 订阅者可以变异,例如用来包装原型方法.

一个 astQuery 用于逐字记录,因此可以匹配任何节点, 包括那些基于名称的变体不暴露的,例如 匿名或深度嵌入功能。 (两个名称均基于 astQuery 匹配同步和同步函数的工作 类似。 )

如果一个 astQuery 匹配节点, “找不到注入” 点"出错包括选择器,因此可以调试.

自定义变形

内置运算符( E)traceSync, (中文(简体) ), tracePromise, (中文(简体) ), traceCallback, (中文(简体) ), traceAuto选择 functionQuery.kind(中文(简体) ) 包括诊断渠道追踪。 当你需要重写一个 匹配不同的节点,将自定义操作员注册到 matcher.addTransform(name, fn) 并参考从一个配置 transform 字段。 何时 transform 设定为优先 结束 functionQuery.kind。 。 。 .

自定义变换收到相同的参数 横向产量,加上合并的仪器状态,以及 变异匹配的节点 :

type CustomTransform = (state, node, parent, ancestry) => void;
  • state - 配置与运行时域合并 (单位:千美元)moduleVersion, (中文(简体) ), moduleType, (中文(简体) ), operator,解决 functionQuery(中文(简体) ).
  • node - 匹配的 AST 节点(选定的函数/表达式) 以 functionQuery 或者说 astQuery) (中文(简体) ).
  • parent, (中文(简体) ), ancestry - 父节点和完整的祖先链 (最后根数); ancestry[ancestry.length - 1] 这是 Program。 。 。 .

一个自定义的变换是完全自主的 node 重写。 没有 需要插入一个追踪通道.

const matcher = codeTransformer.create([
    {
        channelName: "fetch",
        module: { name: "my-module", versionRange: ">=1.0.0", filePath: "index.js" },
        functionQuery: { functionName: "fetch", kind: "Sync" },
        transform: "myCustomTransform",
    },
]);

matcher.addTransform("myCustomTransform", (state, node) => {
    // Mutate the matched node's AST however you need.
    node.body.body.unshift(/* an ESTree statement */);
});

注册匹配内置变换的名称( N)traceSync, (中文(简体) ), tracePromise, (中文(简体) ), traceCallback, (中文(简体) ), traceAuto, (中文(简体) ), tracingChannelImport, (中文(简体) ), tracingChannelDeclaration() 超过它 在它派遣的任何地方—— 包括当有人内在援引 另一个内部(例如,追踪操作员呼叫 tracingChannelDeclaration,这反过来又要求 tracingChannelImport) (中文(简体) ). state.transforms 持有合并的地图 用于此发送的(已安装内置外加已注册的覆盖); 至 代表给原内置的,从一个覆盖,称它通过 页:1 @apm-js-collab/code-transformer/lib/transforms 模块 直接说.

(CLI通过 customTransforms 区域。 见: CLI 工具. ) (中文(简体) )

API 参考

type ModuleType = "esm" | "cjs" | "unknown";
type FunctionKind = "Sync" | "Async" | "Callback" | "Auto";

FunctionQuery 备选案文

type FunctionQuery =
    | // Match class constructor
    { className: string; index?: number | null; isExportAlias?: boolean }
    | // Match class method
    {
        className: string;
        methodName: string;
        kind: FunctionKind;
        index?: number | null;
        callbackIndex?: number;
        isExportAlias?: boolean;
    }
    | // Match method on objects
    { methodName: string; kind: FunctionKind; index?: number | null; callbackIndex?: number }
    | // Match standalone function
    { functionName: string; kind: FunctionKind; index?: number | null; callbackIndex?: number; isExportAlias?: boolean }
    | // Match arrow function or function expression
    { expressionName: string; kind: FunctionKind; index?: number | null; callbackIndex?: number; isExportAlias?: boolean };
    | // Match private class methods
    { className: string; privateMethodName: string; kind: FunctionKind; index?: number | null; callbackIndex?: number };

ModuleMatcher

type ModuleMatcher = {
    /** Module name */
    name: string; 
    /** Matching semver range */
    versionRange: string;
    /** 
     * Relative Unix-style path to the file from the module root (e.g. "lib/index.js") 
     * Or a regular expression to test against the Unix-style path.
     */
    filePath: string | RegExp;
};

InstrumentationConfig

// Behaviour-only fields, used when `astQuery` does the matching.
type FunctionBehavior = {
    kind?: FunctionKind;
    index?: number | null;
    callbackIndex?: number;
};

type InstrumentationConfig =
    | {
        channelName: string; // Name of the diagnostics channel
        module: ModuleMatcher;
        functionQuery: FunctionQuery; // Name-based matching
        astQuery?: string; // Raw esquery selector; takes precedence over functionQuery matching
        transform?: string; // Name of a custom transform registered via addTransform
    }
    | {
        channelName: string;
        module: ModuleMatcher;
        astQuery: string; // Raw esquery selector chooses the node(s)
        functionQuery?: FunctionBehavior; // Behaviour only; matching fields ignored
        transform?: string;
    };

职能

create(configs: InstrumentationConfig[], dcModule?: string | null): InstrumentationMatcher;

为一个或多个仪器配置创建匹配器.

  • configs - 仪器配置阵列.
  • dcModule - 要导入的可选模块 diagnostics_channel API从.

InstrumentationMatcher

getTransformer(moduleName: string, version: string, filePath: string): Transformer | undefined;

获取特定模块和文件的变压器.

回返a Transformer 用于给定模块,或 undefined 如果没有 匹配仪器配置.

  • moduleName - 舱名.
  • version - 模块的版本.
  • filePath - 从模块根(如:. "lib/index.js") (中文(简体) ). Windows风格的回斜道也被接受,并将自动正常化.
addTransform(name: string, fn: CustomTransform): void;

注册自定义变换操作员 name编号 从配置 transform 字段。 见 自定义 变换。 。 。 .

  • name - 运算符名称(也用作配置) transform 数值).
  • fn - 说吧 (state, node, parent, ancestry) => void; 变异 匹配节点.

Transformer

transform(code: string | Buffer, moduleType: ModuleType, sourcemap?: string | undefined): TransformOutput;

转换代码,按配置进行注射跟踪.

回返 { code, map }。 。 。 . map 如果没有提供源图,则将取消定义.

  • code - JavaScript代码要转换.
  • moduleType - 正在改造的模块类型.
  • sourcemap - 代码的可选现有源地图.

CLI 工具

软件包包括一个用于应用转换到源文件的 CLI 工具 :

npx @apm-js-collab/code-transformer transformer.js source-file.js

CLI 使用量

CLI 工具需要两个参数:

  1. transformer.js - 一个导出仪器配置的文件
  2. source-file.js - 要转换的源文件(可以是任何路径,包括节点 模块)

已转换的代码被写入 stdout, 您可以将它重定向到文件或管道到其他命令中 .

CLI 示例

创建变压器配置文件 :

// my-transformer.js
module.exports = [{
  channelName: 'my-fetch-channel',
  module: {
    name: 'my-module',
    versionRange: '>=1.0.0',
    filePath: 'index.js'
  },
  functionQuery: {
    functionName: 'fetch',
    kind: 'Async'
  }
}]

应用转换 :

npx @apm-js-collab/code-transformer my-transformer.js lib/index.js > instrumented.js

变压器配置文件还可以导出一个带有额外选项的对象:

module.exports = {
  configs: [/* array of configs */],
  dcModule: './custom-diagnostics-channel.js', // optional custom dc module
  customTransforms: {  // optional custom transform functions
    myCustomTransform: (state, node) => {
      // custom AST transformation logic
    }
  }
}

许可证

见LICENSE

版本与发布记录

@apm-js-collab/code-transformer 共发布 25 个版本,首次发布于 2025/06/02;过去 12 个月发布了 11 个版本。最新版本附带 npm provenance 构建来源证明,可追溯到公开的 CI 构建记录。

版本发布日期距今
0.19.0latest2026/10/2216 天前
0.18.12026/07/233 个月前
0.18.02026/07/103 个月前
0.16.02026/07/014 个月前
0.15.02026/06/184 个月前
0.14.02026/05/285 个月前

关于 @apm-js-collab/code-transformer 的常见问题

@apm-js-collab/code-transformer 是什么?

这是一个在构建或加载时间帮助给Node.js 库配置仪器的图书馆.

如何安装 @apm-js-collab/code-transformer?

在项目目录运行 npm install @apm-js-collab/code-transformer,或使用 pnpm add / yarn add / bun add。它还提供命令行工具 code-transformer,可以用 npx code-transformer 直接运行。

@apm-js-collab/code-transformer 支持 TypeScript 吗?

支持。包内自带 TypeScript 类型声明(package.json 声明了 types 入口),安装后即可获得类型提示,无需再安装 @types 包。

@apm-js-collab/code-transformer 支持 ESM 还是 CommonJS?

以 CommonJS 形式发布,可以直接 require();在 ES Module 项目中也可以用 import 引入(Node.js 会把 module.exports 作为默认导出)。

@apm-js-collab/code-transformer 可以商用吗?

@apm-js-collab/code-transformer 使用 Apache-2.0 许可。宽松许可:允许商业使用、修改和再分发,并附带明确的专利授权;分发时需保留许可与 NOTICE 文件,修改过的文件要注明改动。以上为概括,不构成法律意见,请以许可原文为准。

@apm-js-collab/code-transformer 的下载量有多少?

根据 npm 官方下载统计,@apm-js-collab/code-transformer 在 2026/10/07 – 2026/11/05 这 30 天内被下载 45,730,135 次,日均约 1,524,338 次。下载量会把 CI 构建、镜像同步和作为其他包依赖的安装一并计入,适合横向比较热度,不能直接等同于使用人数。

@apm-js-collab/code-transformer 还在维护吗?

最新版本 0.19.0 发布于 2026/10/22(16 天前);至今共发布 25 个版本,其中过去 12 个月发布了 11 个;首次发布于 2025/06/02。发布频率只是参考信号:功能稳定的工具可能很少需要更新,建议结合源码仓库的 issue 和提交记录判断。