monocart-coverage-reports 3.2.0 → 3.2.1
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 +8 -6
- package/README.zh-Hans.md +8 -6
- package/lib/converter/ast-visitor.js +27 -1
- package/lib/converter/ast.js +20 -1
- package/lib/packages/monocart-coverage-assets.js +1 -1
- package/lib/packages/monocart-coverage-vendor.js +2 -2
- package/lib/packages/monocart-coverage-vendor.js.LICENSE +6 -6
- package/package.json +16 -16
package/README.md
CHANGED
|
@@ -14,6 +14,7 @@
|
|
|
14
14
|
|
|
15
15
|
* [Usage](#usage)
|
|
16
16
|
* [Best Practices](#best-practices)
|
|
17
|
+
* [AI Agent Skill](#ai-agent-skill)
|
|
17
18
|
* [Options](#options)
|
|
18
19
|
* [Available Reports](#available-reports)
|
|
19
20
|
* [Compare Reports](#compare-reports)
|
|
@@ -118,20 +119,21 @@ For detailed setup instructions and examples, see the [best-practices guide](ski
|
|
|
118
119
|
|
|
119
120
|
## AI Agent Skill
|
|
120
121
|
|
|
121
|
-
|
|
122
|
+
**Reliable AI-assisted development starts with automated testing.** Test results validate behavior; coverage highlights testing gaps. With **`mcr test`**, AI coding agents can run Node.js tests, collect native V8 coverage, and generate reports without instrumentation. This feedback supports iterative development and CI/CD quality gates, whether an agent assists a developer or works autonomously.
|
|
122
123
|
|
|
123
|
-
The
|
|
124
|
+
The [Monocart Coverage Reports skill](skills/monocart-coverage-reports/SKILL.md) guides agents through coverage collection, CLI configuration, sourcemap troubleshooting, report merging, and CI thresholds. It targets MCR 3.x and loads task-specific references on demand.
|
|
124
125
|
|
|
125
|
-
The npm package
|
|
126
|
+
The skill ships in the npm package. Copy the **entire `skills/monocart-coverage-reports/` directory**, including `references/`, into your agent's skills directory, or have the agent read `SKILL.md` directly. Installation does not automatically register the skill. The instructions are in English; you can use any language with your agent.
|
|
126
127
|
|
|
127
|
-
|
|
128
|
+
Locate the installed skill from your project root:
|
|
128
129
|
|
|
129
130
|
```sh
|
|
130
131
|
node -p "require.resolve('monocart-coverage-reports/skills/monocart-coverage-reports/SKILL.md')"
|
|
131
|
-
node -p "require.resolve('monocart-coverage-reports/package.json')"
|
|
132
132
|
```
|
|
133
133
|
|
|
134
|
-
|
|
134
|
+
Follow the skill's reference links and the installed package's version and runtime requirements. Older releases may not include the skill.
|
|
135
|
+
|
|
136
|
+
For development of MCR itself, see [AGENTS.md](https://github.com/cenfun/monocart-coverage-reports/blob/main/AGENTS.md).
|
|
135
137
|
|
|
136
138
|
## Options
|
|
137
139
|
- Default options: [lib/default/options.js](./lib/default/options.js)
|
package/README.zh-Hans.md
CHANGED
|
@@ -14,6 +14,7 @@
|
|
|
14
14
|
|
|
15
15
|
* [用法](#usage)
|
|
16
16
|
* [最佳实践](#best-practices)
|
|
17
|
+
* [AI Agent Skill](#ai-agent-skill)
|
|
17
18
|
* [选项配置](#options)
|
|
18
19
|
* [所有支持的报告类型](#available-reports)
|
|
19
20
|
* [比较两种报告](#compare-reports)
|
|
@@ -118,20 +119,21 @@ mcr node my-app.js -r v8,console-details
|
|
|
118
119
|
|
|
119
120
|
## AI Agent Skill
|
|
120
121
|
|
|
121
|
-
|
|
122
|
+
**可靠的 AI 辅助开发离不开自动化测试。** 测试结果验证代码行为,覆盖率帮助识别测试缺口。通过 **`mcr test`**,AI 编程助手可直接运行 Node.js 测试、采集原生 V8 覆盖率并生成报告,无需插桩。测试与覆盖率反馈支持持续迭代,并可结合 CI/CD 质量门禁,用于 AI 辅助或自主开发。
|
|
122
123
|
|
|
123
|
-
|
|
124
|
+
[Monocart Coverage Reports 技能](skills/monocart-coverage-reports/SKILL.md) 指导 AI 配置覆盖率采集和 CLI、排查 sourcemap 问题、合并报告及设置 CI 阈值,适用于 MCR 3.x,专题参考文档按需加载。
|
|
124
125
|
|
|
125
|
-
npm
|
|
126
|
+
技能随 npm 包发布。将**整个 `skills/monocart-coverage-reports/` 目录**(含 `references/`)复制到 AI 工具的技能目录,或让 AI 直接读取 `SKILL.md`。安装 MCR 不会自动注册技能。技能说明使用英文,与 AI 交流可使用任意语言。
|
|
126
127
|
|
|
127
|
-
|
|
128
|
+
在项目根目录定位已安装的技能:
|
|
128
129
|
|
|
129
130
|
```sh
|
|
130
131
|
node -p "require.resolve('monocart-coverage-reports/skills/monocart-coverage-reports/SKILL.md')"
|
|
131
|
-
node -p "require.resolve('monocart-coverage-reports/package.json')"
|
|
132
132
|
```
|
|
133
133
|
|
|
134
|
-
|
|
134
|
+
按技能中的链接查阅参考文档,并以已安装包的版本和运行环境要求为准。旧版本可能不包含该技能。
|
|
135
|
+
|
|
136
|
+
开发 MCR 本身时,请参阅 [AGENTS.md](https://github.com/cenfun/monocart-coverage-reports/blob/main/AGENTS.md)。
|
|
135
137
|
|
|
136
138
|
## Options
|
|
137
139
|
- 默认选项: [lib/default/options.js](./lib/default/options.js)
|
|
@@ -489,6 +489,7 @@ const viteImportDefaultHandler = (node, group) => {
|
|
|
489
489
|
|
|
490
490
|
const collectNodes = (ast) => {
|
|
491
491
|
const functionNodes = [];
|
|
492
|
+
const initializerNodes = [];
|
|
492
493
|
const statementNodes = [];
|
|
493
494
|
const blockNodes = [];
|
|
494
495
|
const branchMap = new Map();
|
|
@@ -514,6 +515,12 @@ const collectNodes = (ast) => {
|
|
|
514
515
|
});
|
|
515
516
|
},
|
|
516
517
|
|
|
518
|
+
PropertyDefinition: (node) => {
|
|
519
|
+
if (node.value) {
|
|
520
|
+
initializerNodes.push(node);
|
|
521
|
+
}
|
|
522
|
+
},
|
|
523
|
+
|
|
517
524
|
// https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Classes/static
|
|
518
525
|
// as a function "functionName": "<static_initializer>",
|
|
519
526
|
StaticBlock: (node, parents) => {
|
|
@@ -646,6 +653,7 @@ const collectNodes = (ast) => {
|
|
|
646
653
|
|
|
647
654
|
return {
|
|
648
655
|
functionNodes,
|
|
656
|
+
initializerNodes,
|
|
649
657
|
statementNodes,
|
|
650
658
|
blockNodes,
|
|
651
659
|
branchMap
|
|
@@ -735,12 +743,30 @@ const findFunctionRange = (item, coverageInfo) => {
|
|
|
735
743
|
const collectAstInfo = (ast, coverageInfo) => {
|
|
736
744
|
|
|
737
745
|
const {
|
|
738
|
-
functionNodes, statementNodes, blockNodes, branchMap
|
|
746
|
+
functionNodes, initializerNodes, statementNodes, blockNodes, branchMap
|
|
739
747
|
} = collectNodes(ast);
|
|
740
748
|
|
|
741
749
|
// root function state
|
|
742
750
|
const rootState = getRootFunctionState(ast, coverageInfo);
|
|
743
751
|
|
|
752
|
+
// V8 groups field values into implicit functions. Use their counts and
|
|
753
|
+
// block ranges without adding synthetic functions to the report. Keys
|
|
754
|
+
// execute at class definition time, so only the value gets this state.
|
|
755
|
+
initializerNodes.forEach((node) => {
|
|
756
|
+
const ranges = node.static ? coverageInfo.functionStaticRanges : coverageInfo.functionInstanceRanges;
|
|
757
|
+
const { value } = node;
|
|
758
|
+
const range = Util.findInRanges(value.start, value.end, ranges, 'startOffset', 'endOffset');
|
|
759
|
+
if (range) {
|
|
760
|
+
value._state = {
|
|
761
|
+
isFunction: true,
|
|
762
|
+
count: range.count,
|
|
763
|
+
range
|
|
764
|
+
};
|
|
765
|
+
}
|
|
766
|
+
});
|
|
767
|
+
|
|
768
|
+
// Explicit functions (including arrow-valued fields) keep their own
|
|
769
|
+
// execution state, overriding any initializer state on the value node.
|
|
744
770
|
const functions = [];
|
|
745
771
|
functionNodes.forEach((item) => {
|
|
746
772
|
const { node } = item;
|
package/lib/converter/ast.js
CHANGED
|
@@ -9,6 +9,7 @@ const getCoverageInfo = (coverageList) => {
|
|
|
9
9
|
const functionMap = new Map();
|
|
10
10
|
const functionNameMap = new Map();
|
|
11
11
|
const functionStaticRanges = [];
|
|
12
|
+
const functionInstanceRanges = [];
|
|
12
13
|
const functionUncoveredRanges = [];
|
|
13
14
|
|
|
14
15
|
let rootRange;
|
|
@@ -66,6 +67,9 @@ const getCoverageInfo = (coverageList) => {
|
|
|
66
67
|
if (functionName === '<static_initializer>') {
|
|
67
68
|
functionStaticRanges.push(functionRange);
|
|
68
69
|
}
|
|
70
|
+
if (functionName === '<instance_members_initializer>') {
|
|
71
|
+
functionInstanceRanges.push(functionRange);
|
|
72
|
+
}
|
|
69
73
|
|
|
70
74
|
// cache uncovered
|
|
71
75
|
if (functionRange.count === 0) {
|
|
@@ -76,11 +80,14 @@ const getCoverageInfo = (coverageList) => {
|
|
|
76
80
|
|
|
77
81
|
// sort ranges
|
|
78
82
|
Util.sortOffsetRanges(functionUncoveredRanges);
|
|
83
|
+
Util.sortOffsetRanges(functionStaticRanges);
|
|
84
|
+
Util.sortOffsetRanges(functionInstanceRanges);
|
|
79
85
|
|
|
80
86
|
return {
|
|
81
87
|
functionMap,
|
|
82
88
|
functionNameMap,
|
|
83
89
|
functionStaticRanges,
|
|
90
|
+
functionInstanceRanges,
|
|
84
91
|
functionUncoveredRanges,
|
|
85
92
|
rootRange
|
|
86
93
|
};
|
|
@@ -220,7 +227,19 @@ const addRule = (item, coverageList, coveredRanges, count = 0) => {
|
|
|
220
227
|
const endOffset = end.offset;
|
|
221
228
|
|
|
222
229
|
if (!count) {
|
|
223
|
-
|
|
230
|
+
let matchEnd = endOffset;
|
|
231
|
+
if (item.type === 'rule') {
|
|
232
|
+
const child = item.nodes?.find((node) => node.type === 'rule' || node.type === 'atrule');
|
|
233
|
+
if (child) {
|
|
234
|
+
// Chromium 158 may stop the used parent range before a nested
|
|
235
|
+
// rule. Keep legacy whole-rule accounting, matching only the
|
|
236
|
+
// parent's prefix rather than requiring its entire subtree.
|
|
237
|
+
// TODO: Track native nested rules and trailing declarations
|
|
238
|
+
// separately, including their sparse sourcemap boundaries.
|
|
239
|
+
matchEnd = startOffset + source.input.css.slice(startOffset, child.source.start.offset).trimEnd().length;
|
|
240
|
+
}
|
|
241
|
+
}
|
|
242
|
+
const coveredRange = Util.findInRanges(startOffset, matchEnd, coveredRanges, 'startOffset', 'endOffset');
|
|
224
243
|
if (coveredRange) {
|
|
225
244
|
count = 1;
|
|
226
245
|
}
|