@canyonjs/babel-plugin 1.0.0 → 1.0.2

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.
Files changed (43) hide show
  1. package/dist/helpers/detect-ci-config.d.ts +7 -0
  2. package/dist/helpers/detect-ci-config.d.ts.map +1 -0
  3. package/dist/helpers/detect-ci-config.js +34 -0
  4. package/dist/helpers/detect-ci-config.js.map +1 -0
  5. package/dist/helpers/extract-coverage-data.d.ts +11 -0
  6. package/dist/helpers/extract-coverage-data.d.ts.map +1 -0
  7. package/dist/helpers/extract-coverage-data.js +40 -0
  8. package/dist/helpers/extract-coverage-data.js.map +1 -0
  9. package/dist/helpers/generate-build-hash.d.ts +10 -0
  10. package/dist/helpers/generate-build-hash.d.ts.map +1 -0
  11. package/dist/helpers/generate-build-hash.js +32 -0
  12. package/dist/helpers/generate-build-hash.js.map +1 -0
  13. package/dist/helpers/generate-initial-coverage.d.ts +18 -0
  14. package/dist/helpers/generate-initial-coverage.d.ts.map +1 -0
  15. package/dist/helpers/generate-initial-coverage.js +16 -0
  16. package/dist/helpers/generate-initial-coverage.js.map +1 -0
  17. package/dist/helpers/hash.d.ts +8 -0
  18. package/dist/helpers/hash.d.ts.map +1 -0
  19. package/dist/helpers/hash.js +14 -0
  20. package/dist/helpers/hash.js.map +1 -0
  21. package/dist/helpers/statement-map-hash.d.ts +31 -0
  22. package/dist/helpers/statement-map-hash.d.ts.map +1 -0
  23. package/dist/helpers/statement-map-hash.js +73 -0
  24. package/dist/helpers/statement-map-hash.js.map +1 -0
  25. package/dist/helpers/types.d.ts +13 -0
  26. package/dist/helpers/types.d.ts.map +1 -0
  27. package/dist/helpers/types.js +3 -0
  28. package/dist/helpers/types.js.map +1 -0
  29. package/dist/index.d.ts +15 -0
  30. package/dist/index.d.ts.map +1 -0
  31. package/dist/index.js +60 -0
  32. package/dist/index.js.map +1 -0
  33. package/dist/types.d.ts +18 -0
  34. package/dist/types.d.ts.map +1 -0
  35. package/dist/types.js +3 -0
  36. package/dist/types.js.map +1 -0
  37. package/dist/visitor-program-exit.d.ts +27 -0
  38. package/dist/visitor-program-exit.d.ts.map +1 -0
  39. package/dist/visitor-program-exit.js +187 -0
  40. package/dist/visitor-program-exit.js.map +1 -0
  41. package/package.json +18 -25
  42. package/README.md +0 -0
  43. package/lib/index.js +0 -16
@@ -0,0 +1,7 @@
1
+ import type { CanyonBabelPluginConfig } from '../types';
2
+ /**
3
+ * 从 CI/CD 环境变量中自动检测配置
4
+ * 支持 GitLab CI 和 GitHub Actions
5
+ */
6
+ export declare function detectCIConfig(): Partial<CanyonBabelPluginConfig>;
7
+ //# sourceMappingURL=detect-ci-config.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"detect-ci-config.d.ts","sourceRoot":"","sources":["../../src/helpers/detect-ci-config.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,uBAAuB,EAAE,MAAM,UAAU,CAAC;AAExD;;;GAGG;AACH,wBAAgB,cAAc,IAAI,OAAO,CAAC,uBAAuB,CAAC,CAgCjE"}
@@ -0,0 +1,34 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.detectCIConfig = detectCIConfig;
4
+ /**
5
+ * 从 CI/CD 环境变量中自动检测配置
6
+ * 支持 GitLab CI 和 GitHub Actions
7
+ */
8
+ function detectCIConfig() {
9
+ const ciConfig = {};
10
+ // 检测是否在 CI 环境中
11
+ const isCI = !!(process.env.CI ||
12
+ process.env.GITLAB_CI ||
13
+ process.env.GITHUB_ACTIONS);
14
+ if (!isCI) {
15
+ return ciConfig;
16
+ }
17
+ ciConfig.ci = true;
18
+ // 检测 GitLab CI
19
+ if (process.env.GITLAB_CI || process.env.CI_PROJECT_ID) {
20
+ ciConfig.provider = 'gitlab';
21
+ ciConfig.repoID =
22
+ process.env.CI_PROJECT_ID || process.env.CI_PROJECT_PATH || '';
23
+ ciConfig.sha = process.env.CI_COMMIT_SHA || '';
24
+ }
25
+ // 检测 GitHub Actions
26
+ else if (process.env.GITHUB_ACTIONS || process.env.GITHUB_REPOSITORY) {
27
+ ciConfig.provider = 'github';
28
+ ciConfig.repoID =
29
+ process.env.GITHUB_REPOSITORY_ID || process.env.GITHUB_REPOSITORY || '';
30
+ ciConfig.sha = process.env.GITHUB_SHA || '';
31
+ }
32
+ return ciConfig;
33
+ }
34
+ //# sourceMappingURL=detect-ci-config.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"detect-ci-config.js","sourceRoot":"","sources":["../../src/helpers/detect-ci-config.ts"],"names":[],"mappings":";;;AAEA;;;GAGG;AACH,0BAAmE;IACjE,MAAM,QAAQ,GAAqC,EAAE,CAAC;IAEtD,+BAAe;IACf,MAAM,IAAI,GAAG,CAAC,CAAC,CACb,OAAO,CAAC,GAAG,CAAC,EAAE;QACd,OAAO,CAAC,GAAG,CAAC,SAAS;QACrB,OAAO,CAAC,GAAG,CAAC,cAAc,CAC3B,CAAC;IAEF,IAAI,CAAC,IAAI,EAAE,CAAC;QACV,OAAO,QAAQ,CAAC;IAClB,CAAC;IAED,QAAQ,CAAC,EAAE,GAAG,IAAI,CAAC;IAEnB,mBAAe;IACf,IAAI,OAAO,CAAC,GAAG,CAAC,SAAS,IAAI,OAAO,CAAC,GAAG,CAAC,aAAa,EAAE,CAAC;QACvD,QAAQ,CAAC,QAAQ,GAAG,QAAQ,CAAC;QAC7B,QAAQ,CAAC,MAAM;YACb,OAAO,CAAC,GAAG,CAAC,aAAa,IAAI,OAAO,CAAC,GAAG,CAAC,eAAe,IAAI,EAAE,CAAC;QACjE,QAAQ,CAAC,GAAG,GAAG,OAAO,CAAC,GAAG,CAAC,aAAa,IAAI,EAAE,CAAC;IACjD,CAAC;IACD,wBAAoB;SACf,IAAI,OAAO,CAAC,GAAG,CAAC,cAAc,IAAI,OAAO,CAAC,GAAG,CAAC,iBAAiB,EAAE,CAAC;QACrE,QAAQ,CAAC,QAAQ,GAAG,QAAQ,CAAC;QAC7B,QAAQ,CAAC,MAAM;YACb,OAAO,CAAC,GAAG,CAAC,oBAAoB,IAAI,OAAO,CAAC,GAAG,CAAC,iBAAiB,IAAI,EAAE,CAAC;QAC1E,QAAQ,CAAC,GAAG,GAAG,OAAO,CAAC,GAAG,CAAC,UAAU,IAAI,EAAE,CAAC;IAC9C,CAAC;IAED,OAAO,QAAQ,CAAC;AAAA,CACjB"}
@@ -0,0 +1,11 @@
1
+ /**
2
+ * 从脚本内容中提取覆盖率数据
3
+ * 支持两种格式:
4
+ * 1. var coverageData = {...};
5
+ * 2. var xxx = function() {...}();
6
+ *
7
+ * @param scriptContent - 包含覆盖率数据的脚本内容
8
+ * @returns 提取的覆盖率数据对象,如果提取失败则返回 null
9
+ */
10
+ export declare function extractCoverageData(scriptContent: string): Record<string, unknown> | null;
11
+ //# sourceMappingURL=extract-coverage-data.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"extract-coverage-data.d.ts","sourceRoot":"","sources":["../../src/helpers/extract-coverage-data.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AACH,wBAAgB,mBAAmB,CACjC,aAAa,EAAE,MAAM,GACpB,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,IAAI,CAgChC"}
@@ -0,0 +1,40 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.extractCoverageData = extractCoverageData;
4
+ /**
5
+ * 从脚本内容中提取覆盖率数据
6
+ * 支持两种格式:
7
+ * 1. var coverageData = {...};
8
+ * 2. var xxx = function() {...}();
9
+ *
10
+ * @param scriptContent - 包含覆盖率数据的脚本内容
11
+ * @returns 提取的覆盖率数据对象,如果提取失败则返回 null
12
+ */
13
+ function extractCoverageData(scriptContent) {
14
+ // 匹配格式:var coverageData = {...};
15
+ const coverageDataPattern = /var\s+coverageData\s*=\s*({[\s\S]*?});/;
16
+ // 匹配格式:var xxx = function() {...}();
17
+ const functionPattern = /var\s+(\w+)\s*=\s*function\s*\(\)\s*\{([\s\S]*?)\}\(\);/;
18
+ try {
19
+ // 尝试匹配第一种格式
20
+ const coverageDataMatch = coverageDataPattern.exec(scriptContent);
21
+ if (coverageDataMatch) {
22
+ const objectString = coverageDataMatch[1];
23
+ return new Function(`return ${objectString}`)();
24
+ }
25
+ // 尝试匹配第二种格式
26
+ const functionMatch = functionPattern.exec(scriptContent);
27
+ if (functionMatch) {
28
+ const functionBody = functionMatch[2];
29
+ const func = new Function(`${functionBody}return coverageData;`);
30
+ const result = func();
31
+ return result;
32
+ }
33
+ }
34
+ catch (_error) {
35
+ // 提取失败时返回 null
36
+ return null;
37
+ }
38
+ return null;
39
+ }
40
+ //# sourceMappingURL=extract-coverage-data.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"extract-coverage-data.js","sourceRoot":"","sources":["../../src/helpers/extract-coverage-data.ts"],"names":[],"mappings":";;;AAAA;;;;;;;;GAQG;AACH,6BACE,aAAqB,EACW;IAChC,2CAAiC;IACjC,MAAM,mBAAmB,GAAG,wCAAwC,CAAC;IACrE,+CAAqC;IACrC,MAAM,eAAe,GACnB,yDAAyD,CAAC;IAE5D,IAAI,CAAC;QACH,8BAAY;QACZ,MAAM,iBAAiB,GAAG,mBAAmB,CAAC,IAAI,CAAC,aAAa,CAAC,CAAC;QAClE,IAAI,iBAAiB,EAAE,CAAC;YACtB,MAAM,YAAY,GAAG,iBAAiB,CAAC,CAAC,CAAC,CAAC;YAC1C,OAAO,IAAI,QAAQ,CAAC,UAAU,YAAY,EAAE,CAAC,EAG5C,CAAC;QACJ,CAAC;QAED,8BAAY;QACZ,MAAM,aAAa,GAAG,eAAe,CAAC,IAAI,CAAC,aAAa,CAAC,CAAC;QAC1D,IAAI,aAAa,EAAE,CAAC;YAClB,MAAM,YAAY,GAAG,aAAa,CAAC,CAAC,CAAC,CAAC;YACtC,MAAM,IAAI,GAAG,IAAI,QAAQ,CAAC,GAAG,YAAY,sBAAsB,CAAC,CAAC;YACjE,MAAM,MAAM,GAAG,IAAI,EAAE,CAAC;YACtB,OAAO,MAAiC,CAAC;QAC3C,CAAC;IACH,CAAC;IAAC,OAAO,MAAM,EAAE,CAAC;QAChB,6BAAe;QACf,OAAO,IAAI,CAAC;IACd,CAAC;IAED,OAAO,IAAI,CAAC;AAAA,CACb"}
@@ -0,0 +1,10 @@
1
+ import type { CanyonBabelPluginConfig } from '../types';
2
+ /**
3
+ * 生成 buildHash
4
+ * 基于 provider, repoID, sha, buildTarget 四个字段生成稳定的构建身份标识
5
+ *
6
+ * @param config - 插件配置参数
7
+ * @returns buildHash 字符串
8
+ */
9
+ export declare function generateBuildHash(config: Required<CanyonBabelPluginConfig>): string;
10
+ //# sourceMappingURL=generate-build-hash.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"generate-build-hash.d.ts","sourceRoot":"","sources":["../../src/helpers/generate-build-hash.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,uBAAuB,EAAE,MAAM,UAAU,CAAC;AAExD;;;;;;GAMG;AACH,wBAAgB,iBAAiB,CAC/B,MAAM,EAAE,QAAQ,CAAC,uBAAuB,CAAC,GACxC,MAAM,CAiBR"}
@@ -0,0 +1,32 @@
1
+ "use strict";
2
+ var __importDefault = (this && this.__importDefault) || function (mod) {
3
+ return (mod && mod.__esModule) ? mod : { "default": mod };
4
+ };
5
+ Object.defineProperty(exports, "__esModule", { value: true });
6
+ exports.generateBuildHash = generateBuildHash;
7
+ const node_crypto_1 = require("node:crypto");
8
+ const json_stable_stringify_1 = __importDefault(require("json-stable-stringify"));
9
+ /**
10
+ * 生成 buildHash
11
+ * 基于 provider, repoID, sha, buildTarget 四个字段生成稳定的构建身份标识
12
+ *
13
+ * @param config - 插件配置参数
14
+ * @returns buildHash 字符串
15
+ */
16
+ function generateBuildHash(config) {
17
+ // buildHash 包含这些核心字段:
18
+ // provider + repoID + sha + buildTarget + instrumentCwd
19
+ const buildHashFields = {
20
+ provider: config.provider || '',
21
+ repoID: config.repoID || '',
22
+ sha: config.sha || '',
23
+ buildTarget: config.buildTarget || '',
24
+ instrumentCwd: config.instrumentCwd || '',
25
+ };
26
+ // 使用 json-stable-stringify 确保键顺序稳定,与后端保持一致
27
+ const hash = (0, node_crypto_1.createHash)('sha1')
28
+ .update((0, json_stable_stringify_1.default)(buildHashFields) || '')
29
+ .digest('hex');
30
+ return hash;
31
+ }
32
+ //# sourceMappingURL=generate-build-hash.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"generate-build-hash.js","sourceRoot":"","sources":["../../src/helpers/generate-build-hash.ts"],"names":[],"mappings":";;;;;;AAAA,6CAAyC;AACzC,kFAA8C;AAG9C;;;;;;GAMG;AACH,2BACE,MAAyC,EACjC;IACR,wCAAsB;IACtB,wDAAwD;IACxD,MAAM,eAAe,GAA2B;QAC9C,QAAQ,EAAE,MAAM,CAAC,QAAQ,IAAI,EAAE;QAC/B,MAAM,EAAE,MAAM,CAAC,MAAM,IAAI,EAAE;QAC3B,GAAG,EAAE,MAAM,CAAC,GAAG,IAAI,EAAE;QACrB,WAAW,EAAE,MAAM,CAAC,WAAW,IAAI,EAAE;QACrC,aAAa,EAAE,MAAM,CAAC,aAAa,IAAI,EAAE;KAC1C,CAAC;IAEF,6EAA2C;IAC3C,MAAM,IAAI,GAAG,IAAA,wBAAU,EAAC,MAAM,CAAC;SAC5B,MAAM,CAAC,IAAA,+BAAS,EAAC,eAAe,CAAC,IAAI,EAAE,CAAC;SACxC,MAAM,CAAC,KAAK,CAAC,CAAC;IAEjB,OAAO,IAAI,CAAC;AAAA,CACb"}
@@ -0,0 +1,18 @@
1
+ import type { CanyonBabelPluginConfig } from '../types';
2
+ /**
3
+ * 覆盖率数据接口
4
+ */
5
+ interface CoverageData {
6
+ path?: string;
7
+ [key: string]: unknown;
8
+ }
9
+ /**
10
+ * 生成初始覆盖率数据
11
+ *
12
+ * @param sourceCode - 源代码内容
13
+ * @param _config - 插件配置参数(当前未使用,保留以兼容接口)
14
+ * @returns 提取的覆盖率数据对象,如果提取失败则返回 null
15
+ */
16
+ export declare function generateInitialCoverage(sourceCode: string, _config: Required<CanyonBabelPluginConfig>): CoverageData | null;
17
+ export {};
18
+ //# sourceMappingURL=generate-initial-coverage.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"generate-initial-coverage.d.ts","sourceRoot":"","sources":["../../src/helpers/generate-initial-coverage.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,uBAAuB,EAAE,MAAM,UAAU,CAAC;AAGxD;;GAEG;AACH,UAAU,YAAY;IACpB,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC;CACxB;AAED;;;;;;GAMG;AACH,wBAAgB,uBAAuB,CACrC,UAAU,EAAE,MAAM,EAClB,OAAO,EAAE,QAAQ,CAAC,uBAAuB,CAAC,GACzC,YAAY,GAAG,IAAI,CAGrB"}
@@ -0,0 +1,16 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.generateInitialCoverage = generateInitialCoverage;
4
+ const extract_coverage_data_1 = require("./extract-coverage-data");
5
+ /**
6
+ * 生成初始覆盖率数据
7
+ *
8
+ * @param sourceCode - 源代码内容
9
+ * @param _config - 插件配置参数(当前未使用,保留以兼容接口)
10
+ * @returns 提取的覆盖率数据对象,如果提取失败则返回 null
11
+ */
12
+ function generateInitialCoverage(sourceCode, _config) {
13
+ const coverageData = (0, extract_coverage_data_1.extractCoverageData)(sourceCode);
14
+ return coverageData;
15
+ }
16
+ //# sourceMappingURL=generate-initial-coverage.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"generate-initial-coverage.js","sourceRoot":"","sources":["../../src/helpers/generate-initial-coverage.ts"],"names":[],"mappings":";;;AACA,mEAA8D;AAU9D;;;;;;GAMG;AACH,iCACE,UAAkB,EAClB,OAA0C,EACrB;IACrB,MAAM,YAAY,GAAG,IAAA,2CAAmB,EAAC,UAAU,CAAC,CAAC;IACrD,OAAO,YAAY,CAAC;AAAA,CACrB"}
@@ -0,0 +1,8 @@
1
+ /**
2
+ * 计算字符串的 SHA1 hash
3
+ *
4
+ * @param content - 要计算 hash 的内容
5
+ * @returns SHA1 hash 字符串
6
+ */
7
+ export declare function computeHash(content: string): string;
8
+ //# sourceMappingURL=hash.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"hash.d.ts","sourceRoot":"","sources":["../../src/helpers/hash.ts"],"names":[],"mappings":"AAEA;;;;;GAKG;AACH,wBAAgB,WAAW,CAAC,OAAO,EAAE,MAAM,GAAG,MAAM,CAEnD"}
@@ -0,0 +1,14 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.computeHash = computeHash;
4
+ const node_crypto_1 = require("node:crypto");
5
+ /**
6
+ * 计算字符串的 SHA1 hash
7
+ *
8
+ * @param content - 要计算 hash 的内容
9
+ * @returns SHA1 hash 字符串
10
+ */
11
+ function computeHash(content) {
12
+ return (0, node_crypto_1.createHash)('sha1').update(content).digest('hex');
13
+ }
14
+ //# sourceMappingURL=hash.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"hash.js","sourceRoot":"","sources":["../../src/helpers/hash.ts"],"names":[],"mappings":";;;AAAA,6CAAyC;AAEzC;;;;;GAKG;AACH,qBAA4B,OAAe,EAAU;IACnD,OAAO,IAAA,wBAAU,EAAC,MAAM,CAAC,CAAC,MAAM,CAAC,OAAO,CAAC,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC;AAAA,CACzD"}
@@ -0,0 +1,31 @@
1
+ /**
2
+ * Location 位置信息接口
3
+ */
4
+ interface Location {
5
+ start: {
6
+ line: number;
7
+ column: number;
8
+ };
9
+ end: {
10
+ line: number;
11
+ column: number;
12
+ };
13
+ }
14
+ /**
15
+ * StatementMap 条目接口
16
+ */
17
+ interface StatementMapEntry {
18
+ start: Location['start'];
19
+ end: Location['end'];
20
+ contentHash?: string;
21
+ }
22
+ /**
23
+ * 为 statementMap 中的每个条目添加 contentHash 字段
24
+ * 基于位置信息提取源码片段并计算 hash
25
+ *
26
+ * @param statementMap - StatementMap 对象
27
+ * @param sourceCode - 源代码内容
28
+ */
29
+ export declare function enrichStatementMapWithHash(statementMap: Record<string, StatementMapEntry>, sourceCode: string): void;
30
+ export {};
31
+ //# sourceMappingURL=statement-map-hash.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"statement-map-hash.d.ts","sourceRoot":"","sources":["../../src/helpers/statement-map-hash.ts"],"names":[],"mappings":"AAEA;;GAEG;AACH,UAAU,QAAQ;IAChB,KAAK,EAAE;QACL,IAAI,EAAE,MAAM,CAAC;QACb,MAAM,EAAE,MAAM,CAAC;KAChB,CAAC;IACF,GAAG,EAAE;QACH,IAAI,EAAE,MAAM,CAAC;QACb,MAAM,EAAE,MAAM,CAAC;KAChB,CAAC;CACH;AAED;;GAEG;AACH,UAAU,iBAAiB;IACzB,KAAK,EAAE,QAAQ,CAAC,OAAO,CAAC,CAAC;IACzB,GAAG,EAAE,QAAQ,CAAC,KAAK,CAAC,CAAC;IACrB,WAAW,CAAC,EAAE,MAAM,CAAC;CACtB;AAgDD;;;;;;GAMG;AACH,wBAAgB,0BAA0B,CACxC,YAAY,EAAE,MAAM,CAAC,MAAM,EAAE,iBAAiB,CAAC,EAC/C,UAAU,EAAE,MAAM,GACjB,IAAI,CA+BN"}
@@ -0,0 +1,73 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.enrichStatementMapWithHash = enrichStatementMapWithHash;
4
+ const hash_1 = require("./hash");
5
+ /**
6
+ * 根据位置信息从源码中提取代码片段
7
+ *
8
+ * @param sourceCode - 源代码内容
9
+ * @param start - 起始位置
10
+ * @param end - 结束位置
11
+ * @returns 提取的代码片段
12
+ */
13
+ function extractCodeSnippet(sourceCode, start, end) {
14
+ const lines = sourceCode.split('\n');
15
+ // 行号从 1 开始,数组索引从 0 开始
16
+ const startLineIndex = start.line - 1;
17
+ const endLineIndex = end.line - 1;
18
+ if (startLineIndex < 0 || endLineIndex >= lines.length) {
19
+ return '';
20
+ }
21
+ // 如果是同一行
22
+ if (startLineIndex === endLineIndex) {
23
+ const line = lines[startLineIndex];
24
+ if (!line) {
25
+ return '';
26
+ }
27
+ return line.slice(start.column, end.column);
28
+ }
29
+ // 跨多行的情况
30
+ const startLine = lines[startLineIndex];
31
+ const endLine = lines[endLineIndex];
32
+ if (!startLine || !endLine) {
33
+ return '';
34
+ }
35
+ const firstLinePart = startLine.slice(start.column);
36
+ const middleLines = lines.slice(startLineIndex + 1, endLineIndex);
37
+ const lastLinePart = endLine.slice(0, end.column);
38
+ return [firstLinePart, ...middleLines, lastLinePart].join('\n');
39
+ }
40
+ /**
41
+ * 为 statementMap 中的每个条目添加 contentHash 字段
42
+ * 基于位置信息提取源码片段并计算 hash
43
+ *
44
+ * @param statementMap - StatementMap 对象
45
+ * @param sourceCode - 源代码内容
46
+ */
47
+ function enrichStatementMapWithHash(statementMap, sourceCode) {
48
+ if (!statementMap || typeof statementMap !== 'object') {
49
+ return;
50
+ }
51
+ Object.keys(statementMap).forEach((key) => {
52
+ const entry = statementMap[key];
53
+ if (entry &&
54
+ typeof entry === 'object' &&
55
+ entry.start &&
56
+ entry.end &&
57
+ typeof entry.start.line === 'number' &&
58
+ typeof entry.start.column === 'number' &&
59
+ typeof entry.end.line === 'number' &&
60
+ typeof entry.end.column === 'number') {
61
+ try {
62
+ const codeSnippet = extractCodeSnippet(sourceCode, entry.start, entry.end);
63
+ if (codeSnippet) {
64
+ entry.contentHash = (0, hash_1.computeHash)(codeSnippet);
65
+ }
66
+ }
67
+ catch (_error) {
68
+ // 忽略提取失败,保持现有行为
69
+ }
70
+ }
71
+ });
72
+ }
73
+ //# sourceMappingURL=statement-map-hash.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"statement-map-hash.js","sourceRoot":"","sources":["../../src/helpers/statement-map-hash.ts"],"names":[],"mappings":";;;AAAA,iCAAqC;AAyBrC;;;;;;;GAOG;AACH,SAAS,kBAAkB,CACzB,UAAkB,EAClB,KAAwB,EACxB,GAAoB,EACZ;IACR,MAAM,KAAK,GAAG,UAAU,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC;IAErC,gDAAsB;IACtB,MAAM,cAAc,GAAG,KAAK,CAAC,IAAI,GAAG,CAAC,CAAC;IACtC,MAAM,YAAY,GAAG,GAAG,CAAC,IAAI,GAAG,CAAC,CAAC;IAElC,IAAI,cAAc,GAAG,CAAC,IAAI,YAAY,IAAI,KAAK,CAAC,MAAM,EAAE,CAAC;QACvD,OAAO,EAAE,CAAC;IACZ,CAAC;IAED,qBAAS;IACT,IAAI,cAAc,KAAK,YAAY,EAAE,CAAC;QACpC,MAAM,IAAI,GAAG,KAAK,CAAC,cAAc,CAAC,CAAC;QACnC,IAAI,CAAC,IAAI,EAAE,CAAC;YACV,OAAO,EAAE,CAAC;QACZ,CAAC;QACD,OAAO,IAAI,CAAC,KAAK,CAAC,KAAK,CAAC,MAAM,EAAE,GAAG,CAAC,MAAM,CAAC,CAAC;IAC9C,CAAC;IAED,qBAAS;IACT,MAAM,SAAS,GAAG,KAAK,CAAC,cAAc,CAAC,CAAC;IACxC,MAAM,OAAO,GAAG,KAAK,CAAC,YAAY,CAAC,CAAC;IACpC,IAAI,CAAC,SAAS,IAAI,CAAC,OAAO,EAAE,CAAC;QAC3B,OAAO,EAAE,CAAC;IACZ,CAAC;IAED,MAAM,aAAa,GAAG,SAAS,CAAC,KAAK,CAAC,KAAK,CAAC,MAAM,CAAC,CAAC;IACpD,MAAM,WAAW,GAAG,KAAK,CAAC,KAAK,CAAC,cAAc,GAAG,CAAC,EAAE,YAAY,CAAC,CAAC;IAClE,MAAM,YAAY,GAAG,OAAO,CAAC,KAAK,CAAC,CAAC,EAAE,GAAG,CAAC,MAAM,CAAC,CAAC;IAElD,OAAO,CAAC,aAAa,EAAE,GAAG,WAAW,EAAE,YAAY,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;AAAA,CACjE;AAED;;;;;;GAMG;AACH,oCACE,YAA+C,EAC/C,UAAkB,EACZ;IACN,IAAI,CAAC,YAAY,IAAI,OAAO,YAAY,KAAK,QAAQ,EAAE,CAAC;QACtD,OAAO;IACT,CAAC;IAED,MAAM,CAAC,IAAI,CAAC,YAAY,CAAC,CAAC,OAAO,CAAC,CAAC,GAAG,EAAE,EAAE,CAAC;QACzC,MAAM,KAAK,GAAG,YAAY,CAAC,GAAG,CAAC,CAAC;QAChC,IACE,KAAK;YACL,OAAO,KAAK,KAAK,QAAQ;YACzB,KAAK,CAAC,KAAK;YACX,KAAK,CAAC,GAAG;YACT,OAAO,KAAK,CAAC,KAAK,CAAC,IAAI,KAAK,QAAQ;YACpC,OAAO,KAAK,CAAC,KAAK,CAAC,MAAM,KAAK,QAAQ;YACtC,OAAO,KAAK,CAAC,GAAG,CAAC,IAAI,KAAK,QAAQ;YAClC,OAAO,KAAK,CAAC,GAAG,CAAC,MAAM,KAAK,QAAQ,EACpC,CAAC;YACD,IAAI,CAAC;gBACH,MAAM,WAAW,GAAG,kBAAkB,CACpC,UAAU,EACV,KAAK,CAAC,KAAK,EACX,KAAK,CAAC,GAAG,CACV,CAAC;gBACF,IAAI,WAAW,EAAE,CAAC;oBAChB,KAAK,CAAC,WAAW,GAAG,IAAA,kBAAW,EAAC,WAAW,CAAC,CAAC;gBAC/C,CAAC;YACH,CAAC;YAAC,OAAO,MAAM,EAAE,CAAC;gBAChB,0CAAgB;YAClB,CAAC;QACH,CAAC;IAAA,CACF,CAAC,CAAC;AAAA,CACJ"}
@@ -0,0 +1,13 @@
1
+ /**
2
+ * 覆盖率数据接口
3
+ */
4
+ export interface CoverageData {
5
+ path?: string;
6
+ statementMap?: Record<string, unknown>;
7
+ fnMap?: Record<string, unknown>;
8
+ branchMap?: Record<string, unknown>;
9
+ inputSourceMap?: unknown;
10
+ contentHash?: string;
11
+ [key: string]: unknown;
12
+ }
13
+ //# sourceMappingURL=types.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../src/helpers/types.ts"],"names":[],"mappings":"AAAA;;GAEG;AACH,MAAM,WAAW,YAAY;IAC3B,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,YAAY,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;IACvC,KAAK,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;IAChC,SAAS,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;IACpC,cAAc,CAAC,EAAE,OAAO,CAAC;IACzB,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC;CACxB"}
@@ -0,0 +1,3 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ //# sourceMappingURL=types.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"types.js","sourceRoot":"","sources":["../../src/helpers/types.ts"],"names":[],"mappings":""}
@@ -0,0 +1,15 @@
1
+ import type { NodePath } from '@babel/core';
2
+ import type * as t from '@babel/types';
3
+ /**
4
+ * Babel 插件主入口
5
+ * 用于在代码中注入覆盖率收集逻辑和元数据
6
+ */
7
+ declare const _default: (api: object, options: Record<string, any> | null | undefined, dirname: string) => {
8
+ visitor: {
9
+ Program: {
10
+ exit: (path: NodePath<t.Program>) => void;
11
+ };
12
+ };
13
+ };
14
+ export default _default;
15
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAa,QAAQ,EAAE,MAAM,aAAa,CAAC;AAEvD,OAAO,KAAK,KAAK,CAAC,MAAM,cAAc,CAAC;AA+CvC;;;GAGG;;;;;;;;AACH,wBAoBE"}
package/dist/index.js ADDED
@@ -0,0 +1,60 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ const helper_plugin_utils_1 = require("@babel/helper-plugin-utils");
4
+ const detect_ci_config_1 = require("./helpers/detect-ci-config");
5
+ const visitor_program_exit_1 = require("./visitor-program-exit");
6
+ /**
7
+ * 默认配置对象
8
+ */
9
+ const defaultConfig = {
10
+ repoID: '',
11
+ sha: '',
12
+ provider: '',
13
+ buildTarget: '',
14
+ ci: false,
15
+ instrumentCwd: process.cwd(),
16
+ };
17
+ /**
18
+ * 合并用户配置、CI 自动检测配置和默认配置
19
+ *
20
+ * @param config - 用户提供的配置
21
+ * @returns 合并后的完整配置对象
22
+ */
23
+ function mergeConfig(config) {
24
+ // 首先从 CI 环境变量中自动检测配置
25
+ const ciConfig = (0, detect_ci_config_1.detectCIConfig)();
26
+ // 合并优先级:用户配置 > CI 自动检测 > 默认配置
27
+ return {
28
+ repoID: config?.repoID ?? ciConfig.repoID ?? defaultConfig.repoID,
29
+ sha: config?.sha ?? ciConfig.sha ?? defaultConfig.sha,
30
+ // branch: config?.branch ?? ciConfig.branch ?? defaultConfig.branch,
31
+ provider: config?.provider ?? ciConfig.provider ?? defaultConfig.provider,
32
+ buildTarget: config?.buildTarget ?? ciConfig.buildTarget ?? defaultConfig.buildTarget,
33
+ ci: config?.ci ?? ciConfig.ci ?? defaultConfig.ci,
34
+ instrumentCwd: config?.instrumentCwd ?? defaultConfig.instrumentCwd,
35
+ // buildProvider:
36
+ // config?.buildProvider ??
37
+ // ciConfig.buildProvider ??
38
+ // defaultConfig.buildProvider,
39
+ // buildID: config?.buildID ?? ciConfig.buildID ?? defaultConfig.buildID,
40
+ };
41
+ }
42
+ /**
43
+ * Babel 插件主入口
44
+ * 用于在代码中注入覆盖率收集逻辑和元数据
45
+ */
46
+ exports.default = (0, helper_plugin_utils_1.declare)((api, config) => {
47
+ api.assertVersion(7);
48
+ const userConfig = config;
49
+ const validatedConfig = mergeConfig(userConfig);
50
+ return {
51
+ visitor: {
52
+ Program: {
53
+ exit: (programPath) => {
54
+ (0, visitor_program_exit_1.visitorProgramExit)(api, programPath, validatedConfig);
55
+ },
56
+ },
57
+ },
58
+ };
59
+ });
60
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":";;AAEA,oEAAqD;AAErD,iEAA4D;AAE5D,iEAA4D;AAE5D;;GAEG;AACH,MAAM,aAAa,GAAsC;IACvD,MAAM,EAAE,EAAE;IACV,GAAG,EAAE,EAAE;IACP,QAAQ,EAAE,EAAE;IACZ,WAAW,EAAE,EAAE;IACf,EAAE,EAAE,KAAK;IACT,aAAa,EAAE,OAAO,CAAC,GAAG,EAAE;CAC7B,CAAC;AAEF;;;;;GAKG;AACH,SAAS,WAAW,CAClB,MAA2C,EACR;IACnC,iDAAqB;IACrB,MAAM,QAAQ,GAAG,IAAA,iCAAc,GAAE,CAAC;IAElC,kEAA8B;IAC9B,OAAO;QACL,MAAM,EAAE,MAAM,EAAE,MAAM,IAAI,QAAQ,CAAC,MAAM,IAAI,aAAa,CAAC,MAAM;QACjE,GAAG,EAAE,MAAM,EAAE,GAAG,IAAI,QAAQ,CAAC,GAAG,IAAI,aAAa,CAAC,GAAG;QACrD,qEAAqE;QACrE,QAAQ,EAAE,MAAM,EAAE,QAAQ,IAAI,QAAQ,CAAC,QAAQ,IAAI,aAAa,CAAC,QAAQ;QACzE,WAAW,EACT,MAAM,EAAE,WAAW,IAAI,QAAQ,CAAC,WAAW,IAAI,aAAa,CAAC,WAAW;QAC1E,EAAE,EAAE,MAAM,EAAE,EAAE,IAAI,QAAQ,CAAC,EAAE,IAAI,aAAa,CAAC,EAAE;QACjD,aAAa,EAAE,MAAM,EAAE,aAAa,IAAI,aAAa,CAAC,aAAa;QACnE,iBAAiB;QACjB,6BAA6B;QAC7B,8BAA8B;QAC9B,iCAAiC;QACjC,yEAAyE;KAC1E,CAAC;AAAA,CACH;AAED;;;GAGG;kBACY,IAAA,6BAAO,EACpB,CACE,GAAc,EACd,MAAe,EAGf,EAAE,CAAC;IACH,GAAG,CAAC,aAAa,CAAC,CAAC,CAAC,CAAC;IACrB,MAAM,UAAU,GAAG,MAA6C,CAAC;IACjE,MAAM,eAAe,GAAG,WAAW,CAAC,UAAU,CAAC,CAAC;IAChD,OAAO;QACL,OAAO,EAAE;YACP,OAAO,EAAE;gBACP,IAAI,EAAE,CAAC,WAAgC,EAAE,EAAE,CAAC;oBAC1C,IAAA,yCAAkB,EAAC,GAAG,EAAE,WAAW,EAAE,eAAe,CAAC,CAAC;gBAAA,CACvD;aACF;SACF;KACF,CAAC;AAAA,CACH,CACF"}
@@ -0,0 +1,18 @@
1
+ /**
2
+ * Babel plugin 配置接口
3
+ */
4
+ export interface CanyonBabelPluginConfig {
5
+ /** 仓库 ID */
6
+ repoID?: string;
7
+ /** Git commit SHA */
8
+ sha?: string;
9
+ /** Git 提供商 */
10
+ provider?: string;
11
+ /** 构建目标 */
12
+ buildTarget?: string;
13
+ /** 是否为 CI 环境 */
14
+ ci?: boolean;
15
+ /** 插桩工作目录,默认为当前路径 */
16
+ instrumentCwd?: string;
17
+ }
18
+ //# sourceMappingURL=types.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":"AAAA;;GAEG;AACH,MAAM,WAAW,uBAAuB;IACtC,gBAAY;IACZ,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,qBAAqB;IACrB,GAAG,CAAC,EAAE,MAAM,CAAC;IACb,oBAAc;IACd,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,mBAAW;IACX,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,0BAAgB;IAChB,EAAE,CAAC,EAAE,OAAO,CAAC;IACb,iDAAqB;IACrB,aAAa,CAAC,EAAE,MAAM,CAAC;CACxB"}
package/dist/types.js ADDED
@@ -0,0 +1,3 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ //# sourceMappingURL=types.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"types.js","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":""}
@@ -0,0 +1,27 @@
1
+ import type { types as BabelTypes, ConfigAPI, NodePath } from '@babel/core';
2
+ import type { CanyonBabelPluginConfig } from './types';
3
+ /**
4
+ * 覆盖率数据接口
5
+ */
6
+ interface CoverageData {
7
+ path?: string;
8
+ [key: string]: unknown;
9
+ }
10
+ /**
11
+ * 返回值接口
12
+ */
13
+ interface VisitorProgramExitResult {
14
+ initialCoverageDataForTheCurrentFile: CoverageData | null;
15
+ }
16
+ /**
17
+ * Program 节点退出时的访问器函数
18
+ * 用于处理覆盖率数据,添加元数据并生成初始覆盖率文件
19
+ *
20
+ * @param api - Babel Plugin API 实例
21
+ * @param programPath - Program 节点的路径
22
+ * @param config - 插件配置参数
23
+ * @returns 包含初始覆盖率数据的对象
24
+ */
25
+ export declare function visitorProgramExit(api: ConfigAPI, programPath: NodePath<BabelTypes.Program>, config: Required<CanyonBabelPluginConfig>): VisitorProgramExitResult;
26
+ export {};
27
+ //# sourceMappingURL=visitor-program-exit.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"visitor-program-exit.d.ts","sourceRoot":"","sources":["../src/visitor-program-exit.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAE,KAAK,IAAI,UAAU,EAAE,SAAS,EAAE,QAAQ,EAAE,MAAM,aAAa,CAAC;AAM5E,OAAO,KAAK,EAAE,uBAAuB,EAAE,MAAM,SAAS,CAAC;AAEvD;;GAEG;AACH,UAAU,YAAY;IACpB,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC;CACxB;AAED;;GAEG;AACH,UAAU,wBAAwB;IAChC,oCAAoC,EAAE,YAAY,GAAG,IAAI,CAAC;CAC3D;AAED;;;;;;;;GAQG;AACH,wBAAgB,kBAAkB,CAChC,GAAG,EAAE,SAAS,EACd,WAAW,EAAE,QAAQ,CAAC,UAAU,CAAC,OAAO,CAAC,EACzC,MAAM,EAAE,QAAQ,CAAC,uBAAuB,CAAC,GACxC,wBAAwB,CAsL1B"}
@@ -0,0 +1,187 @@
1
+ "use strict";
2
+ var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
3
+ if (k2 === undefined) k2 = k;
4
+ var desc = Object.getOwnPropertyDescriptor(m, k);
5
+ if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
6
+ desc = { enumerable: true, get: function() { return m[k]; } };
7
+ }
8
+ Object.defineProperty(o, k2, desc);
9
+ }) : (function(o, m, k, k2) {
10
+ if (k2 === undefined) k2 = k;
11
+ o[k2] = m[k];
12
+ }));
13
+ var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
14
+ Object.defineProperty(o, "default", { enumerable: true, value: v });
15
+ }) : function(o, v) {
16
+ o["default"] = v;
17
+ });
18
+ var __importStar = (this && this.__importStar) || (function () {
19
+ var ownKeys = function(o) {
20
+ ownKeys = Object.getOwnPropertyNames || function (o) {
21
+ var ar = [];
22
+ for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
23
+ return ar;
24
+ };
25
+ return ownKeys(o);
26
+ };
27
+ return function (mod) {
28
+ if (mod && mod.__esModule) return mod;
29
+ var result = {};
30
+ if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
31
+ __setModuleDefault(result, mod);
32
+ return result;
33
+ };
34
+ })();
35
+ var __importDefault = (this && this.__importDefault) || function (mod) {
36
+ return (mod && mod.__esModule) ? mod : { "default": mod };
37
+ };
38
+ Object.defineProperty(exports, "__esModule", { value: true });
39
+ exports.visitorProgramExit = visitorProgramExit;
40
+ const node_crypto_1 = require("node:crypto");
41
+ const fs = __importStar(require("node:fs"));
42
+ const path = __importStar(require("node:path"));
43
+ const generator_1 = __importDefault(require("@babel/generator"));
44
+ const generate_build_hash_1 = require("./helpers/generate-build-hash");
45
+ const generate_initial_coverage_1 = require("./helpers/generate-initial-coverage");
46
+ const hash_1 = require("./helpers/hash");
47
+ const statement_map_hash_1 = require("./helpers/statement-map-hash");
48
+ /**
49
+ * Program 节点退出时的访问器函数
50
+ * 用于处理覆盖率数据,添加元数据并生成初始覆盖率文件
51
+ *
52
+ * @param api - Babel Plugin API 实例
53
+ * @param programPath - Program 节点的路径
54
+ * @param config - 插件配置参数
55
+ * @returns 包含初始覆盖率数据的对象
56
+ */
57
+ function visitorProgramExit(api, programPath, config) {
58
+ const sourceCode = (0, generator_1.default)(programPath.node).code;
59
+ const initialCoverageData = (0, generate_initial_coverage_1.generateInitialCoverage)(sourceCode, config);
60
+ // 获取原始源码(用于 hash 计算)
61
+ // 优先使用 hub.file.code,如果没有则使用生成的代码
62
+ const hub = programPath.hub;
63
+ const originalCode = hub?.file?.code ?? sourceCode;
64
+ // 这部分代码未经过大规模测试验证,谨防异常错误
65
+ // 基于 statementMap 的位置信息,提取源码片段并写入 contentHash 字段
66
+ try {
67
+ if (initialCoverageData &&
68
+ initialCoverageData.statementMap &&
69
+ typeof initialCoverageData.statementMap === 'object') {
70
+ (0, statement_map_hash_1.enrichStatementMapWithHash)(initialCoverageData.statementMap, originalCode);
71
+ }
72
+ }
73
+ catch (_error) {
74
+ // 忽略提取失败,保持现有行为
75
+ }
76
+ // 基于文件内容计算 contentHash,并写入内存对象
77
+ try {
78
+ if (initialCoverageData &&
79
+ typeof initialCoverageData === 'object') {
80
+ const contentHash = (0, hash_1.computeHash)(originalCode);
81
+ initialCoverageData.contentHash = contentHash;
82
+ }
83
+ }
84
+ catch (_error) {
85
+ // 忽略
86
+ }
87
+ // 尝试读取 source map 文件(如果 inputSourceMap 不存在)
88
+ if (initialCoverageData && !initialCoverageData.inputSourceMap) {
89
+ try {
90
+ if (initialCoverageData.path) {
91
+ const mapFilePath = path.resolve(initialCoverageData.path + '.map');
92
+ const pathString = fs.readFileSync(mapFilePath, 'utf-8');
93
+ initialCoverageData.inputSourceMap = JSON.parse(pathString);
94
+ }
95
+ }
96
+ catch (_error) {
97
+ // 如果文件不存在或读取失败,忽略错误,继续执行
98
+ }
99
+ }
100
+ // CI 环境下生成覆盖率文件
101
+ if (config.ci) {
102
+ // 这里要注意,就在当下生成,插桩路径可以改,但是工作目录不能改
103
+ const outputDir = './.canyon_output';
104
+ if (!fs.existsSync(outputDir)) {
105
+ fs.mkdirSync(outputDir, { recursive: true });
106
+ }
107
+ // 确保覆盖率数据有效
108
+ if (initialCoverageData?.path) {
109
+ // 使用 crypto.randomBytes 生成更安全的随机后缀(16 字节 = 32 个十六进制字符)
110
+ const randomSuffix = (0, node_crypto_1.randomBytes)(16).toString('hex');
111
+ const outputFilePath = `./.canyon_output/coverage-final-init-${randomSuffix}.json`;
112
+ // 添加 buildHash 和核心四字段到 .canyon_output 的产物中
113
+ // 根据架构设计,不再将 repoID、sha、provider 等业务信息直接插桩到代码产物中
114
+ // 而是生成 buildHash,并将核心字段写入到 .canyon_output 目录的覆盖率文件中
115
+ // 服务端可以通过 buildHash 查询对应的构建信息,也可以直接从文件中获取核心字段
116
+ const buildHash = (0, generate_build_hash_1.generateBuildHash)(config);
117
+ const coverageDataWithMetadata = {
118
+ ...initialCoverageData,
119
+ buildHash,
120
+ provider: config.provider,
121
+ repoID: config.repoID,
122
+ sha: config.sha,
123
+ buildTarget: config.buildTarget,
124
+ instrumentCwd: config.instrumentCwd,
125
+ };
126
+ const coverageDataObject = {
127
+ [initialCoverageData.path]: coverageDataWithMetadata,
128
+ };
129
+ fs.writeFileSync(outputFilePath, JSON.stringify(coverageDataObject, null, 2), 'utf-8');
130
+ }
131
+ }
132
+ // 处理代码中的 coverageData 变量
133
+ if (sourceCode.includes('coverageData')) {
134
+ // 使用 api 的 types,Babel 类型定义可能不完整,使用类型断言
135
+ const types = api.types;
136
+ programPath.traverse({
137
+ VariableDeclarator(variablePath) {
138
+ const { id, init } = variablePath.node;
139
+ // 检查是否是 coverageData 变量且初始化为对象表达式
140
+ if (types.isIdentifier(id, { name: 'coverageData' }) &&
141
+ init &&
142
+ types.isObjectExpression(init)) {
143
+ const objectExpression = init;
144
+ // 过滤掉 SpreadElement,只处理 ObjectProperty 和 ObjectMethod
145
+ const validProperties = objectExpression.properties.filter((property) => types.isObjectProperty(property) ||
146
+ types.isObjectMethod(property));
147
+ const hasInstrumentation = validProperties.some((property) => types.isObjectProperty(property) &&
148
+ types.isIdentifier(property.key, { name: '_coverageSchema' }));
149
+ if (hasInstrumentation) {
150
+ const objectProperties = objectExpression.properties;
151
+ // 注意:keepMap 属性不在配置接口中,这里保留原逻辑但添加注释说明
152
+ const shouldKeepMap = false; // 默认不保留 map
153
+ if (!shouldKeepMap) {
154
+ const keysToRemove = [
155
+ 'statementMap',
156
+ 'fnMap',
157
+ 'branchMap',
158
+ 'inputSourceMap',
159
+ ];
160
+ keysToRemove.forEach((keyToRemove) => {
161
+ const propertyIndex = objectProperties.findIndex((property) => (types.isObjectProperty(property) ||
162
+ types.isObjectMethod(property)) &&
163
+ types.isObjectProperty(property) &&
164
+ types.isIdentifier(property.key, { name: keyToRemove }));
165
+ if (propertyIndex !== -1) {
166
+ objectProperties.splice(propertyIndex, 1);
167
+ }
168
+ });
169
+ // 添加 hasInputSourceMap 属性
170
+ const hasInputSourceMap = !!initialCoverageData?.inputSourceMap;
171
+ const hasInputSourceMapProperty = types.objectProperty(types.identifier('hasInputSourceMap'), types.booleanLiteral(hasInputSourceMap));
172
+ objectProperties.push(hasInputSourceMapProperty);
173
+ }
174
+ // 添加 buildHash 元数据属性
175
+ // 根据架构设计,不再将 repoID、sha、provider 等业务信息直接插桩到产物中
176
+ // 而是生成 buildHash,服务端通过 buildHash 查询对应的构建信息
177
+ const buildHash = (0, generate_build_hash_1.generateBuildHash)(config);
178
+ const buildHashProperty = types.objectProperty(types.identifier('buildHash'), types.stringLiteral(buildHash));
179
+ objectProperties.push(buildHashProperty);
180
+ }
181
+ }
182
+ },
183
+ });
184
+ }
185
+ return { initialCoverageDataForTheCurrentFile: initialCoverageData };
186
+ }
187
+ //# sourceMappingURL=visitor-program-exit.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"visitor-program-exit.js","sourceRoot":"","sources":["../src/visitor-program-exit.ts"],"names":[],"mappings":"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"}
package/package.json CHANGED
@@ -1,40 +1,33 @@
1
1
  {
2
2
  "name": "@canyonjs/babel-plugin",
3
- "version": "1.0.0",
4
- "description": "A Babel plugin for Canyon code coverage instrumentation",
5
- "author": "CanyonJS Team",
6
- "repository": {
7
- "type": "git",
8
- "url": "https://github.com/canyon-project/canyon"
9
- },
10
- "bugs": {
11
- "url": "https://github.com/canyon-project/canyon/issues"
12
- },
13
- "homepage": "https://github.com/canyon-project/canyon#readme",
14
- "main": "lib/index.js",
3
+ "version": "1.0.2",
4
+ "description": "",
5
+ "keywords": [],
6
+ "main": "dist/index.js",
15
7
  "files": [
16
- "lib"
8
+ "dist"
17
9
  ],
18
- "license": "MIT",
10
+ "author": "",
11
+ "license": "ISC",
19
12
  "devDependencies": {
13
+ "@babel/cli": "^7.24.1",
20
14
  "@types/babel__core": "^7.20.5",
21
15
  "@types/babel__generator": "^7.6.8",
22
16
  "@types/babel__helper-plugin-utils": "^7.10.3",
23
- "@babel/cli": "^7.24.1",
24
- "@babel/core": "^7.24.1",
25
- "@babel/plugin-transform-modules-commonjs": "^7.24.1",
26
- "@babel/register": "^7.23.7",
27
- "babel-plugin-istanbul": "6.1.1",
28
- "cross-env": "^7.0.3",
29
- "@types/node": "^22.10.2"
17
+ "@types/node": "^24.10.1",
18
+ "@typescript/native-preview": "^7.0.0-dev.20251215.1",
19
+ "babel-plugin-istanbul": "latest"
30
20
  },
31
21
  "dependencies": {
22
+ "@babel/core": "^7.25.6",
32
23
  "@babel/helper-plugin-utils": "^7.0.0",
33
- "@babel/generator": "^7.25.6"
24
+ "@babel/types": "^7.25.6",
25
+ "json-stable-stringify": "^1.3.0"
34
26
  },
35
27
  "scripts": {
36
- "release": "babel src --extensions \".js\" --out-dir lib",
37
- "pretest": "npm run release",
38
- "test": "babel features --config-file ./test-babel-config.js --out-dir dist"
28
+ "build": "tsgo",
29
+ "release": "tsgo",
30
+ "pretest": "tsgo",
31
+ "test": "babel features --config-file ./test-babel-config.js --out-dir features-dist"
39
32
  }
40
33
  }
package/README.md DELETED
File without changes
package/lib/index.js DELETED
@@ -1,16 +0,0 @@
1
- const {
2
- declare
3
- } = require('@babel/helper-plugin-utils');
4
- module.exports = declare((api, options) => {
5
- api.assertVersion(7);
6
- return {
7
- name: '@canyonjs/babel-plugin',
8
- visitor: {
9
- Program: {
10
- enter(path, state) {
11
- // Plugin logic will be implemented here
12
- }
13
- }
14
- }
15
- };
16
- });