@canyonjs/report-component 0.0.1-beta.5 → 0.0.1-beta.7
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/dist/index.d.ts +10 -1
- package/dist/index.js +1185 -36
- package/package.json +8 -2
package/dist/index.d.ts
CHANGED
|
@@ -1,13 +1,22 @@
|
|
|
1
1
|
import { FC } from "react";
|
|
2
|
+
import { FileCoverageData } from "istanbul-lib-coverage";
|
|
2
3
|
|
|
3
4
|
//#region src/types.d.ts
|
|
4
|
-
|
|
5
|
+
/**
|
|
6
|
+
* 文件数据响应接口
|
|
7
|
+
*/
|
|
8
|
+
interface FileDataResponse {
|
|
9
|
+
fileCoverage: FileCoverageData;
|
|
10
|
+
fileContent: string;
|
|
11
|
+
fileCodeChange: number[];
|
|
12
|
+
}
|
|
5
13
|
interface CanyonReportProps {
|
|
6
14
|
/** 报告名称 */
|
|
7
15
|
name: string;
|
|
8
16
|
/** 当前选中的文件 */
|
|
9
17
|
value: string;
|
|
10
18
|
dataSource: any[];
|
|
19
|
+
onSelect: (val: string) => Promise<FileDataResponse>;
|
|
11
20
|
}
|
|
12
21
|
//#endregion
|
|
13
22
|
//#region src/CanyonReport.d.ts
|
package/dist/index.js
CHANGED
|
@@ -1,53 +1,1202 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import {
|
|
1
|
+
import { ConfigProvider, Divider, Input, Progress, Segmented, Space, Spin, Switch, Table, Tag, Typography, theme } from "antd";
|
|
2
|
+
import { Suspense, useEffect, useMemo, useRef, useState } from "react";
|
|
3
|
+
import { Fragment, jsx, jsxs } from "react/jsx-runtime";
|
|
4
|
+
import Highlighter from "react-highlight-words";
|
|
5
|
+
import { genSummaryTreeItem } from "canyon-data";
|
|
6
|
+
import { FileOutlined, FolderFilled } from "@ant-design/icons";
|
|
3
7
|
|
|
4
|
-
//#region
|
|
5
|
-
|
|
6
|
-
console.log(dom, options, window.monaco, window.monaco.editor);
|
|
7
|
-
if (window.monaco && window.monaco.editor && dom) window.monaco.editor.create(dom, options);
|
|
8
|
-
}
|
|
8
|
+
//#region rolldown:runtime
|
|
9
|
+
var __commonJSMin = (cb, mod) => () => (mod || cb((mod = { exports: {} }).exports, mod), mod.exports);
|
|
9
10
|
|
|
10
11
|
//#endregion
|
|
11
|
-
//#region
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
if (
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
12
|
+
//#region ../../node_modules/.pnpm/istanbul-lib-coverage@3.2.2/node_modules/istanbul-lib-coverage/lib/percent.js
|
|
13
|
+
var require_percent = /* @__PURE__ */ __commonJSMin(((exports, module) => {
|
|
14
|
+
module.exports = function percent$2(covered, total) {
|
|
15
|
+
let tmp;
|
|
16
|
+
if (total > 0) {
|
|
17
|
+
tmp = 1e3 * 100 * covered / total;
|
|
18
|
+
return Math.floor(tmp / 10) / 100;
|
|
19
|
+
} else return 100;
|
|
20
|
+
};
|
|
21
|
+
}));
|
|
22
|
+
|
|
23
|
+
//#endregion
|
|
24
|
+
//#region ../../node_modules/.pnpm/istanbul-lib-coverage@3.2.2/node_modules/istanbul-lib-coverage/lib/data-properties.js
|
|
25
|
+
var require_data_properties = /* @__PURE__ */ __commonJSMin(((exports, module) => {
|
|
26
|
+
module.exports = function dataProperties$2(klass, properties) {
|
|
27
|
+
properties.forEach((p) => {
|
|
28
|
+
Object.defineProperty(klass.prototype, p, {
|
|
29
|
+
enumerable: true,
|
|
30
|
+
get() {
|
|
31
|
+
return this.data[p];
|
|
32
|
+
}
|
|
33
|
+
});
|
|
19
34
|
});
|
|
20
|
-
}
|
|
35
|
+
};
|
|
36
|
+
}));
|
|
37
|
+
|
|
38
|
+
//#endregion
|
|
39
|
+
//#region ../../node_modules/.pnpm/istanbul-lib-coverage@3.2.2/node_modules/istanbul-lib-coverage/lib/coverage-summary.js
|
|
40
|
+
var require_coverage_summary = /* @__PURE__ */ __commonJSMin(((exports, module) => {
|
|
41
|
+
const percent$1 = require_percent();
|
|
42
|
+
const dataProperties$1 = require_data_properties();
|
|
43
|
+
function blankSummary() {
|
|
44
|
+
const empty = () => ({
|
|
45
|
+
total: 0,
|
|
46
|
+
covered: 0,
|
|
47
|
+
skipped: 0,
|
|
48
|
+
pct: "Unknown"
|
|
49
|
+
});
|
|
50
|
+
return {
|
|
51
|
+
lines: empty(),
|
|
52
|
+
statements: empty(),
|
|
53
|
+
functions: empty(),
|
|
54
|
+
branches: empty(),
|
|
55
|
+
branchesTrue: empty()
|
|
56
|
+
};
|
|
57
|
+
}
|
|
58
|
+
function assertValidSummary(obj) {
|
|
59
|
+
if (!(obj && obj.lines && obj.statements && obj.functions && obj.branches)) throw new Error("Invalid summary coverage object, missing keys, found:" + Object.keys(obj).join(","));
|
|
60
|
+
}
|
|
61
|
+
/**
|
|
62
|
+
* CoverageSummary provides a summary of code coverage . It exposes 4 properties,
|
|
63
|
+
* `lines`, `statements`, `branches`, and `functions`. Each of these properties
|
|
64
|
+
* is an object that has 4 keys `total`, `covered`, `skipped` and `pct`.
|
|
65
|
+
* `pct` is a percentage number (0-100).
|
|
66
|
+
*/
|
|
67
|
+
var CoverageSummary$3 = class CoverageSummary$3 {
|
|
68
|
+
/**
|
|
69
|
+
* @constructor
|
|
70
|
+
* @param {Object|CoverageSummary} [obj=undefined] an optional data object or
|
|
71
|
+
* another coverage summary to initialize this object with.
|
|
72
|
+
*/
|
|
73
|
+
constructor(obj) {
|
|
74
|
+
if (!obj) this.data = blankSummary();
|
|
75
|
+
else if (obj instanceof CoverageSummary$3) this.data = obj.data;
|
|
76
|
+
else this.data = obj;
|
|
77
|
+
assertValidSummary(this.data);
|
|
78
|
+
}
|
|
79
|
+
/**
|
|
80
|
+
* merges a second summary coverage object into this one
|
|
81
|
+
* @param {CoverageSummary} obj - another coverage summary object
|
|
82
|
+
*/
|
|
83
|
+
merge(obj) {
|
|
84
|
+
[
|
|
85
|
+
"lines",
|
|
86
|
+
"statements",
|
|
87
|
+
"branches",
|
|
88
|
+
"functions",
|
|
89
|
+
"branchesTrue"
|
|
90
|
+
].forEach((key) => {
|
|
91
|
+
if (obj[key]) {
|
|
92
|
+
this[key].total += obj[key].total;
|
|
93
|
+
this[key].covered += obj[key].covered;
|
|
94
|
+
this[key].skipped += obj[key].skipped;
|
|
95
|
+
this[key].pct = percent$1(this[key].covered, this[key].total);
|
|
96
|
+
}
|
|
97
|
+
});
|
|
98
|
+
return this;
|
|
99
|
+
}
|
|
100
|
+
/**
|
|
101
|
+
* returns a POJO that is JSON serializable. May be used to get the raw
|
|
102
|
+
* summary object.
|
|
103
|
+
*/
|
|
104
|
+
toJSON() {
|
|
105
|
+
return this.data;
|
|
106
|
+
}
|
|
107
|
+
/**
|
|
108
|
+
* return true if summary has no lines of code
|
|
109
|
+
*/
|
|
110
|
+
isEmpty() {
|
|
111
|
+
return this.lines.total === 0;
|
|
112
|
+
}
|
|
113
|
+
};
|
|
114
|
+
dataProperties$1(CoverageSummary$3, [
|
|
115
|
+
"lines",
|
|
116
|
+
"statements",
|
|
117
|
+
"functions",
|
|
118
|
+
"branches",
|
|
119
|
+
"branchesTrue"
|
|
120
|
+
]);
|
|
121
|
+
module.exports = { CoverageSummary: CoverageSummary$3 };
|
|
122
|
+
}));
|
|
123
|
+
|
|
124
|
+
//#endregion
|
|
125
|
+
//#region ../../node_modules/.pnpm/istanbul-lib-coverage@3.2.2/node_modules/istanbul-lib-coverage/lib/file-coverage.js
|
|
126
|
+
var require_file_coverage = /* @__PURE__ */ __commonJSMin(((exports, module) => {
|
|
127
|
+
const percent = require_percent();
|
|
128
|
+
const dataProperties = require_data_properties();
|
|
129
|
+
const { CoverageSummary: CoverageSummary$2 } = require_coverage_summary();
|
|
130
|
+
function emptyCoverage(filePath, reportLogic) {
|
|
131
|
+
const cov = {
|
|
132
|
+
path: filePath,
|
|
133
|
+
statementMap: {},
|
|
134
|
+
fnMap: {},
|
|
135
|
+
branchMap: {},
|
|
136
|
+
s: {},
|
|
137
|
+
f: {},
|
|
138
|
+
b: {}
|
|
139
|
+
};
|
|
140
|
+
if (reportLogic) cov.bT = {};
|
|
141
|
+
return cov;
|
|
142
|
+
}
|
|
143
|
+
function assertValidObject(obj) {
|
|
144
|
+
if (!(obj && obj.path && obj.statementMap && obj.fnMap && obj.branchMap && obj.s && obj.f && obj.b)) throw new Error("Invalid file coverage object, missing keys, found:" + Object.keys(obj).join(","));
|
|
145
|
+
}
|
|
146
|
+
const keyFromLoc = ({ start, end }) => `${start.line}|${start.column}|${end.line}|${end.column}`;
|
|
147
|
+
const isObj = (o) => !!o && typeof o === "object";
|
|
148
|
+
const isLineCol = (o) => isObj(o) && typeof o.line === "number" && typeof o.column === "number";
|
|
149
|
+
const isLoc = (o) => isObj(o) && isLineCol(o.start) && isLineCol(o.end);
|
|
150
|
+
const getLoc = (o) => isLoc(o) ? o : isLoc(o.loc) ? o.loc : null;
|
|
151
|
+
const findNearestContainer = (item, map) => {
|
|
152
|
+
const itemLoc = getLoc(item);
|
|
153
|
+
if (!itemLoc) return null;
|
|
154
|
+
let nearestContainingItem = null;
|
|
155
|
+
let containerDistance = null;
|
|
156
|
+
let containerKey = null;
|
|
157
|
+
for (const [i, mapItem] of Object.entries(map)) {
|
|
158
|
+
const mapLoc = getLoc(mapItem);
|
|
159
|
+
if (!mapLoc) continue;
|
|
160
|
+
const distance = [
|
|
161
|
+
itemLoc.start.line - mapLoc.start.line,
|
|
162
|
+
itemLoc.start.column - mapLoc.start.column,
|
|
163
|
+
mapLoc.end.line - itemLoc.end.line,
|
|
164
|
+
mapLoc.end.column - itemLoc.end.column
|
|
165
|
+
];
|
|
166
|
+
if (distance[0] < 0 || distance[2] < 0 || distance[0] === 0 && distance[1] < 0 || distance[2] === 0 && distance[3] < 0) continue;
|
|
167
|
+
if (nearestContainingItem === null) {
|
|
168
|
+
containerDistance = distance;
|
|
169
|
+
nearestContainingItem = mapItem;
|
|
170
|
+
containerKey = i;
|
|
171
|
+
continue;
|
|
172
|
+
}
|
|
173
|
+
const closerBefore = distance[0] < containerDistance[0] || distance[0] === 0 && distance[1] < containerDistance[1];
|
|
174
|
+
const closerAfter = distance[2] < containerDistance[2] || distance[2] === 0 && distance[3] < containerDistance[3];
|
|
175
|
+
if (closerBefore || closerAfter) {
|
|
176
|
+
containerDistance = distance;
|
|
177
|
+
nearestContainingItem = mapItem;
|
|
178
|
+
containerKey = i;
|
|
179
|
+
}
|
|
180
|
+
}
|
|
181
|
+
return containerKey;
|
|
182
|
+
};
|
|
183
|
+
const addHits = (aHits, bHits) => {
|
|
184
|
+
if (typeof aHits === "number" && typeof bHits === "number") return aHits + bHits;
|
|
185
|
+
else if (Array.isArray(aHits) && Array.isArray(bHits)) return aHits.map((a, i) => (a || 0) + (bHits[i] || 0));
|
|
186
|
+
return null;
|
|
187
|
+
};
|
|
188
|
+
const addNearestContainerHits = (item, itemHits, map, mapHits) => {
|
|
189
|
+
const container = findNearestContainer(item, map);
|
|
190
|
+
if (container) return addHits(itemHits, mapHits[container]);
|
|
191
|
+
else return itemHits;
|
|
192
|
+
};
|
|
193
|
+
const mergeProp = (aHits, aMap, bHits, bMap, itemKey = keyFromLoc) => {
|
|
194
|
+
const aItems = {};
|
|
195
|
+
for (const [key, itemHits] of Object.entries(aHits)) {
|
|
196
|
+
const item = aMap[key];
|
|
197
|
+
aItems[itemKey(item)] = [itemHits, item];
|
|
198
|
+
}
|
|
199
|
+
const bItems = {};
|
|
200
|
+
for (const [key, itemHits] of Object.entries(bHits)) {
|
|
201
|
+
const item = bMap[key];
|
|
202
|
+
bItems[itemKey(item)] = [itemHits, item];
|
|
203
|
+
}
|
|
204
|
+
const mergedItems = {};
|
|
205
|
+
for (const [key, aValue] of Object.entries(aItems)) {
|
|
206
|
+
let aItemHits = aValue[0];
|
|
207
|
+
const aItem = aValue[1];
|
|
208
|
+
const bValue = bItems[key];
|
|
209
|
+
if (!bValue) aItemHits = addNearestContainerHits(aItem, aItemHits, bMap, bHits);
|
|
210
|
+
else aItemHits = addHits(aItemHits, bValue[0]);
|
|
211
|
+
mergedItems[key] = [aItemHits, aItem];
|
|
212
|
+
}
|
|
213
|
+
for (const [key, bValue] of Object.entries(bItems)) {
|
|
214
|
+
let bItemHits = bValue[0];
|
|
215
|
+
const bItem = bValue[1];
|
|
216
|
+
if (mergedItems[key]) continue;
|
|
217
|
+
bItemHits = addNearestContainerHits(bItem, bItemHits, aMap, aHits);
|
|
218
|
+
mergedItems[key] = [bItemHits, bItem];
|
|
219
|
+
}
|
|
220
|
+
const hits = {};
|
|
221
|
+
const map = {};
|
|
222
|
+
Object.values(mergedItems).forEach(([itemHits, item], i) => {
|
|
223
|
+
hits[i] = itemHits;
|
|
224
|
+
map[i] = item;
|
|
225
|
+
});
|
|
226
|
+
return [hits, map];
|
|
227
|
+
};
|
|
228
|
+
/**
|
|
229
|
+
* provides a read-only view of coverage for a single file.
|
|
230
|
+
* The deep structure of this object is documented elsewhere. It has the following
|
|
231
|
+
* properties:
|
|
232
|
+
*
|
|
233
|
+
* * `path` - the file path for which coverage is being tracked
|
|
234
|
+
* * `statementMap` - map of statement locations keyed by statement index
|
|
235
|
+
* * `fnMap` - map of function metadata keyed by function index
|
|
236
|
+
* * `branchMap` - map of branch metadata keyed by branch index
|
|
237
|
+
* * `s` - hit counts for statements
|
|
238
|
+
* * `f` - hit count for functions
|
|
239
|
+
* * `b` - hit count for branches
|
|
240
|
+
*/
|
|
241
|
+
var FileCoverage$2 = class FileCoverage$2 {
|
|
242
|
+
/**
|
|
243
|
+
* @constructor
|
|
244
|
+
* @param {Object|FileCoverage|String} pathOrObj is a string that initializes
|
|
245
|
+
* and empty coverage object with the specified file path or a data object that
|
|
246
|
+
* has all the required properties for a file coverage object.
|
|
247
|
+
*/
|
|
248
|
+
constructor(pathOrObj, reportLogic = false) {
|
|
249
|
+
if (!pathOrObj) throw new Error("Coverage must be initialized with a path or an object");
|
|
250
|
+
if (typeof pathOrObj === "string") this.data = emptyCoverage(pathOrObj, reportLogic);
|
|
251
|
+
else if (pathOrObj instanceof FileCoverage$2) this.data = pathOrObj.data;
|
|
252
|
+
else if (typeof pathOrObj === "object") this.data = pathOrObj;
|
|
253
|
+
else throw new Error("Invalid argument to coverage constructor");
|
|
254
|
+
assertValidObject(this.data);
|
|
255
|
+
}
|
|
256
|
+
/**
|
|
257
|
+
* returns computed line coverage from statement coverage.
|
|
258
|
+
* This is a map of hits keyed by line number in the source.
|
|
259
|
+
*/
|
|
260
|
+
getLineCoverage() {
|
|
261
|
+
const statementMap = this.data.statementMap;
|
|
262
|
+
const statements = this.data.s;
|
|
263
|
+
const lineMap = Object.create(null);
|
|
264
|
+
Object.entries(statements).forEach(([st, count]) => {
|
|
265
|
+
/* istanbul ignore if: is this even possible? */
|
|
266
|
+
if (!statementMap[st]) return;
|
|
267
|
+
const { line } = statementMap[st].start;
|
|
268
|
+
const prevVal = lineMap[line];
|
|
269
|
+
if (prevVal === void 0 || prevVal < count) lineMap[line] = count;
|
|
270
|
+
});
|
|
271
|
+
return lineMap;
|
|
272
|
+
}
|
|
273
|
+
/**
|
|
274
|
+
* returns an array of uncovered line numbers.
|
|
275
|
+
* @returns {Array} an array of line numbers for which no hits have been
|
|
276
|
+
* collected.
|
|
277
|
+
*/
|
|
278
|
+
getUncoveredLines() {
|
|
279
|
+
const lc = this.getLineCoverage();
|
|
280
|
+
const ret = [];
|
|
281
|
+
Object.entries(lc).forEach(([l, hits]) => {
|
|
282
|
+
if (hits === 0) ret.push(l);
|
|
283
|
+
});
|
|
284
|
+
return ret;
|
|
285
|
+
}
|
|
286
|
+
/**
|
|
287
|
+
* returns a map of branch coverage by source line number.
|
|
288
|
+
* @returns {Object} an object keyed by line number. Each object
|
|
289
|
+
* has a `covered`, `total` and `coverage` (percentage) property.
|
|
290
|
+
*/
|
|
291
|
+
getBranchCoverageByLine() {
|
|
292
|
+
const branchMap = this.branchMap;
|
|
293
|
+
const branches = this.b;
|
|
294
|
+
const ret = {};
|
|
295
|
+
Object.entries(branchMap).forEach(([k, map]) => {
|
|
296
|
+
const line = map.line || map.loc.start.line;
|
|
297
|
+
const branchData = branches[k];
|
|
298
|
+
ret[line] = ret[line] || [];
|
|
299
|
+
ret[line].push(...branchData);
|
|
300
|
+
});
|
|
301
|
+
Object.entries(ret).forEach(([k, dataArray]) => {
|
|
302
|
+
const covered = dataArray.filter((item) => item > 0);
|
|
303
|
+
const coverage = covered.length / dataArray.length * 100;
|
|
304
|
+
ret[k] = {
|
|
305
|
+
covered: covered.length,
|
|
306
|
+
total: dataArray.length,
|
|
307
|
+
coverage
|
|
308
|
+
};
|
|
309
|
+
});
|
|
310
|
+
return ret;
|
|
311
|
+
}
|
|
312
|
+
/**
|
|
313
|
+
* return a JSON-serializable POJO for this file coverage object
|
|
314
|
+
*/
|
|
315
|
+
toJSON() {
|
|
316
|
+
return this.data;
|
|
317
|
+
}
|
|
318
|
+
/**
|
|
319
|
+
* merges a second coverage object into this one, updating hit counts
|
|
320
|
+
* @param {FileCoverage} other - the coverage object to be merged into this one.
|
|
321
|
+
* Note that the other object should have the same structure as this one (same file).
|
|
322
|
+
*/
|
|
323
|
+
merge(other) {
|
|
324
|
+
if (other.all === true) return;
|
|
325
|
+
if (this.all === true) {
|
|
326
|
+
this.data = other.data;
|
|
327
|
+
return;
|
|
328
|
+
}
|
|
329
|
+
let [hits, map] = mergeProp(this.s, this.statementMap, other.s, other.statementMap);
|
|
330
|
+
this.data.s = hits;
|
|
331
|
+
this.data.statementMap = map;
|
|
332
|
+
const keyFromLocProp = (x) => keyFromLoc(x.loc);
|
|
333
|
+
const keyFromLocationsProp = (x) => keyFromLoc(x.locations[0]);
|
|
334
|
+
[hits, map] = mergeProp(this.f, this.fnMap, other.f, other.fnMap, keyFromLocProp);
|
|
335
|
+
this.data.f = hits;
|
|
336
|
+
this.data.fnMap = map;
|
|
337
|
+
[hits, map] = mergeProp(this.b, this.branchMap, other.b, other.branchMap, keyFromLocationsProp);
|
|
338
|
+
this.data.b = hits;
|
|
339
|
+
this.data.branchMap = map;
|
|
340
|
+
if (this.bT && other.bT) {
|
|
341
|
+
[hits, map] = mergeProp(this.bT, this.branchMap, other.bT, other.branchMap, keyFromLocationsProp);
|
|
342
|
+
this.data.bT = hits;
|
|
343
|
+
}
|
|
344
|
+
}
|
|
345
|
+
computeSimpleTotals(property) {
|
|
346
|
+
let stats = this[property];
|
|
347
|
+
if (typeof stats === "function") stats = stats.call(this);
|
|
348
|
+
const ret = {
|
|
349
|
+
total: Object.keys(stats).length,
|
|
350
|
+
covered: Object.values(stats).filter((v) => !!v).length,
|
|
351
|
+
skipped: 0
|
|
352
|
+
};
|
|
353
|
+
ret.pct = percent(ret.covered, ret.total);
|
|
354
|
+
return ret;
|
|
355
|
+
}
|
|
356
|
+
computeBranchTotals(property) {
|
|
357
|
+
const stats = this[property];
|
|
358
|
+
const ret = {
|
|
359
|
+
total: 0,
|
|
360
|
+
covered: 0,
|
|
361
|
+
skipped: 0
|
|
362
|
+
};
|
|
363
|
+
Object.values(stats).forEach((branches) => {
|
|
364
|
+
ret.covered += branches.filter((hits) => hits > 0).length;
|
|
365
|
+
ret.total += branches.length;
|
|
366
|
+
});
|
|
367
|
+
ret.pct = percent(ret.covered, ret.total);
|
|
368
|
+
return ret;
|
|
369
|
+
}
|
|
370
|
+
/**
|
|
371
|
+
* resets hit counts for all statements, functions and branches
|
|
372
|
+
* in this coverage object resulting in zero coverage.
|
|
373
|
+
*/
|
|
374
|
+
resetHits() {
|
|
375
|
+
const statements = this.s;
|
|
376
|
+
const functions = this.f;
|
|
377
|
+
const branches = this.b;
|
|
378
|
+
const branchesTrue = this.bT;
|
|
379
|
+
Object.keys(statements).forEach((s) => {
|
|
380
|
+
statements[s] = 0;
|
|
381
|
+
});
|
|
382
|
+
Object.keys(functions).forEach((f) => {
|
|
383
|
+
functions[f] = 0;
|
|
384
|
+
});
|
|
385
|
+
Object.keys(branches).forEach((b) => {
|
|
386
|
+
branches[b].fill(0);
|
|
387
|
+
});
|
|
388
|
+
if (branchesTrue) Object.keys(branchesTrue).forEach((bT) => {
|
|
389
|
+
branchesTrue[bT].fill(0);
|
|
390
|
+
});
|
|
391
|
+
}
|
|
392
|
+
/**
|
|
393
|
+
* returns a CoverageSummary for this file coverage object
|
|
394
|
+
* @returns {CoverageSummary}
|
|
395
|
+
*/
|
|
396
|
+
toSummary() {
|
|
397
|
+
const ret = {};
|
|
398
|
+
ret.lines = this.computeSimpleTotals("getLineCoverage");
|
|
399
|
+
ret.functions = this.computeSimpleTotals("f", "fnMap");
|
|
400
|
+
ret.statements = this.computeSimpleTotals("s", "statementMap");
|
|
401
|
+
ret.branches = this.computeBranchTotals("b");
|
|
402
|
+
if (this.bT) ret.branchesTrue = this.computeBranchTotals("bT");
|
|
403
|
+
return new CoverageSummary$2(ret);
|
|
404
|
+
}
|
|
405
|
+
};
|
|
406
|
+
dataProperties(FileCoverage$2, [
|
|
407
|
+
"path",
|
|
408
|
+
"statementMap",
|
|
409
|
+
"fnMap",
|
|
410
|
+
"branchMap",
|
|
411
|
+
"s",
|
|
412
|
+
"f",
|
|
413
|
+
"b",
|
|
414
|
+
"bT",
|
|
415
|
+
"all"
|
|
416
|
+
]);
|
|
417
|
+
module.exports = {
|
|
418
|
+
FileCoverage: FileCoverage$2,
|
|
419
|
+
findNearestContainer,
|
|
420
|
+
addHits,
|
|
421
|
+
addNearestContainerHits
|
|
422
|
+
};
|
|
423
|
+
}));
|
|
424
|
+
|
|
425
|
+
//#endregion
|
|
426
|
+
//#region ../../node_modules/.pnpm/istanbul-lib-coverage@3.2.2/node_modules/istanbul-lib-coverage/lib/coverage-map.js
|
|
427
|
+
var require_coverage_map = /* @__PURE__ */ __commonJSMin(((exports, module) => {
|
|
428
|
+
const { FileCoverage: FileCoverage$1 } = require_file_coverage();
|
|
429
|
+
const { CoverageSummary: CoverageSummary$1 } = require_coverage_summary();
|
|
430
|
+
function maybeConstruct(obj, klass) {
|
|
431
|
+
if (obj instanceof klass) return obj;
|
|
432
|
+
return new klass(obj);
|
|
433
|
+
}
|
|
434
|
+
function loadMap(source) {
|
|
435
|
+
const data = Object.create(null);
|
|
436
|
+
if (!source) return data;
|
|
437
|
+
Object.entries(source).forEach(([k, cov]) => {
|
|
438
|
+
data[k] = maybeConstruct(cov, FileCoverage$1);
|
|
439
|
+
});
|
|
440
|
+
return data;
|
|
441
|
+
}
|
|
442
|
+
/** CoverageMap is a map of `FileCoverage` objects keyed by file paths. */
|
|
443
|
+
var CoverageMap$1 = class CoverageMap$1 {
|
|
444
|
+
/**
|
|
445
|
+
* @constructor
|
|
446
|
+
* @param {Object} [obj=undefined] obj A coverage map from which to initialize this
|
|
447
|
+
* map's contents. This can be the raw global coverage object.
|
|
448
|
+
*/
|
|
449
|
+
constructor(obj) {
|
|
450
|
+
if (obj instanceof CoverageMap$1) this.data = obj.data;
|
|
451
|
+
else this.data = loadMap(obj);
|
|
452
|
+
}
|
|
453
|
+
/**
|
|
454
|
+
* merges a second coverage map into this one
|
|
455
|
+
* @param {CoverageMap} obj - a CoverageMap or its raw data. Coverage is merged
|
|
456
|
+
* correctly for the same files and additional file coverage keys are created
|
|
457
|
+
* as needed.
|
|
458
|
+
*/
|
|
459
|
+
merge(obj) {
|
|
460
|
+
const other = maybeConstruct(obj, CoverageMap$1);
|
|
461
|
+
Object.values(other.data).forEach((fc) => {
|
|
462
|
+
this.addFileCoverage(fc);
|
|
463
|
+
});
|
|
464
|
+
}
|
|
465
|
+
/**
|
|
466
|
+
* filter the coveragemap based on the callback provided
|
|
467
|
+
* @param {Function (filename)} callback - Returns true if the path
|
|
468
|
+
* should be included in the coveragemap. False if it should be
|
|
469
|
+
* removed.
|
|
470
|
+
*/
|
|
471
|
+
filter(callback) {
|
|
472
|
+
Object.keys(this.data).forEach((k) => {
|
|
473
|
+
if (!callback(k)) delete this.data[k];
|
|
474
|
+
});
|
|
475
|
+
}
|
|
476
|
+
/**
|
|
477
|
+
* returns a JSON-serializable POJO for this coverage map
|
|
478
|
+
* @returns {Object}
|
|
479
|
+
*/
|
|
480
|
+
toJSON() {
|
|
481
|
+
return this.data;
|
|
482
|
+
}
|
|
483
|
+
/**
|
|
484
|
+
* returns an array for file paths for which this map has coverage
|
|
485
|
+
* @returns {Array{string}} - array of files
|
|
486
|
+
*/
|
|
487
|
+
files() {
|
|
488
|
+
return Object.keys(this.data);
|
|
489
|
+
}
|
|
490
|
+
/**
|
|
491
|
+
* returns the file coverage for the specified file.
|
|
492
|
+
* @param {String} file
|
|
493
|
+
* @returns {FileCoverage}
|
|
494
|
+
*/
|
|
495
|
+
fileCoverageFor(file) {
|
|
496
|
+
const fc = this.data[file];
|
|
497
|
+
if (!fc) throw new Error(`No file coverage available for: ${file}`);
|
|
498
|
+
return fc;
|
|
499
|
+
}
|
|
500
|
+
/**
|
|
501
|
+
* adds a file coverage object to this map. If the path for the object,
|
|
502
|
+
* already exists in the map, it is merged with the existing coverage
|
|
503
|
+
* otherwise a new key is added to the map.
|
|
504
|
+
* @param {FileCoverage} fc the file coverage to add
|
|
505
|
+
*/
|
|
506
|
+
addFileCoverage(fc) {
|
|
507
|
+
const cov = new FileCoverage$1(fc);
|
|
508
|
+
const { path } = cov;
|
|
509
|
+
if (this.data[path]) this.data[path].merge(cov);
|
|
510
|
+
else this.data[path] = cov;
|
|
511
|
+
}
|
|
512
|
+
/**
|
|
513
|
+
* returns the coverage summary for all the file coverage objects in this map.
|
|
514
|
+
* @returns {CoverageSummary}
|
|
515
|
+
*/
|
|
516
|
+
getCoverageSummary() {
|
|
517
|
+
const ret = new CoverageSummary$1();
|
|
518
|
+
Object.values(this.data).forEach((fc) => {
|
|
519
|
+
ret.merge(fc.toSummary());
|
|
520
|
+
});
|
|
521
|
+
return ret;
|
|
522
|
+
}
|
|
523
|
+
};
|
|
524
|
+
module.exports = { CoverageMap: CoverageMap$1 };
|
|
525
|
+
}));
|
|
526
|
+
|
|
527
|
+
//#endregion
|
|
528
|
+
//#region ../../node_modules/.pnpm/istanbul-lib-coverage@3.2.2/node_modules/istanbul-lib-coverage/index.js
|
|
529
|
+
var require_istanbul_lib_coverage = /* @__PURE__ */ __commonJSMin(((exports, module) => {
|
|
530
|
+
/**
|
|
531
|
+
* istanbul-lib-coverage exports an API that allows you to create and manipulate
|
|
532
|
+
* file coverage, coverage maps (a set of file coverage objects) and summary
|
|
533
|
+
* coverage objects. File coverage for the same file can be merged as can
|
|
534
|
+
* entire coverage maps.
|
|
535
|
+
*
|
|
536
|
+
* @module Exports
|
|
537
|
+
*/
|
|
538
|
+
const { FileCoverage } = require_file_coverage();
|
|
539
|
+
const { CoverageMap } = require_coverage_map();
|
|
540
|
+
const { CoverageSummary } = require_coverage_summary();
|
|
541
|
+
module.exports = {
|
|
542
|
+
createCoverageSummary(obj) {
|
|
543
|
+
if (obj && obj instanceof CoverageSummary) return obj;
|
|
544
|
+
return new CoverageSummary(obj);
|
|
545
|
+
},
|
|
546
|
+
createCoverageMap(obj) {
|
|
547
|
+
if (obj && obj instanceof CoverageMap) return obj;
|
|
548
|
+
return new CoverageMap(obj);
|
|
549
|
+
},
|
|
550
|
+
createFileCoverage(obj) {
|
|
551
|
+
if (obj && obj instanceof FileCoverage) return obj;
|
|
552
|
+
return new FileCoverage(obj);
|
|
553
|
+
}
|
|
554
|
+
};
|
|
555
|
+
/** classes exported for reuse */
|
|
556
|
+
module.exports.classes = { FileCoverage };
|
|
557
|
+
}));
|
|
558
|
+
|
|
559
|
+
//#endregion
|
|
560
|
+
//#region src/helpers/color.ts
|
|
561
|
+
var import_istanbul_lib_coverage = require_istanbul_lib_coverage();
|
|
562
|
+
const getColor = (pct) => {
|
|
563
|
+
if (pct >= 80) return "rgb(33,181,119)";
|
|
564
|
+
if (pct >= 50) return "rgb(244,176,27)";
|
|
565
|
+
return "rgb(245,32,32)";
|
|
566
|
+
};
|
|
567
|
+
|
|
568
|
+
//#endregion
|
|
569
|
+
//#region src/widgets/SummaryHeader.tsx
|
|
570
|
+
const { Text } = Typography;
|
|
571
|
+
const { useToken } = theme;
|
|
572
|
+
const SummaryNav = ({ value, onClick, reportName }) => {
|
|
573
|
+
const { token } = useToken();
|
|
574
|
+
return /* @__PURE__ */ jsx("div", {
|
|
575
|
+
style: {
|
|
576
|
+
display: "flex",
|
|
577
|
+
gap: "6px",
|
|
578
|
+
marginBottom: "6px",
|
|
579
|
+
fontSize: "16px",
|
|
580
|
+
fontWeight: "bold"
|
|
581
|
+
},
|
|
582
|
+
children: `${reportName}/${value}`.split("/").map((item, index) => {
|
|
583
|
+
return /* @__PURE__ */ jsxs("div", {
|
|
584
|
+
style: {
|
|
585
|
+
display: "flex",
|
|
586
|
+
gap: "6px"
|
|
587
|
+
},
|
|
588
|
+
children: [/* @__PURE__ */ jsx("a", {
|
|
589
|
+
style: {
|
|
590
|
+
color: token.colorPrimary,
|
|
591
|
+
cursor: "pointer",
|
|
592
|
+
textDecoration: "none"
|
|
593
|
+
},
|
|
594
|
+
onClick: () => {
|
|
595
|
+
onClick(value.split("/").slice(0, index).join("/"));
|
|
596
|
+
},
|
|
597
|
+
children: item
|
|
598
|
+
}, index), index === value.split("/").length || !value ? null : /* @__PURE__ */ jsx("span", { children: "/" })]
|
|
599
|
+
}, index);
|
|
600
|
+
})
|
|
601
|
+
});
|
|
602
|
+
};
|
|
603
|
+
const SummaryMetric = ({ data, onlyChange }) => {
|
|
604
|
+
const t$1 = (v) => v;
|
|
605
|
+
const summaryTreeItem = { summary: data };
|
|
21
606
|
return /* @__PURE__ */ jsx("div", { children: /* @__PURE__ */ jsx("div", {
|
|
22
|
-
ref,
|
|
23
607
|
style: {
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
608
|
+
display: "flex",
|
|
609
|
+
gap: "6px",
|
|
610
|
+
marginBottom: "6px",
|
|
611
|
+
maxWidth: "1000px",
|
|
612
|
+
flexWrap: "wrap"
|
|
613
|
+
},
|
|
614
|
+
children: Object.entries(summaryTreeItem.summary).sort(([key1], [key2]) => {
|
|
615
|
+
const order = [
|
|
616
|
+
"statements",
|
|
617
|
+
"branches",
|
|
618
|
+
"functions",
|
|
619
|
+
"lines",
|
|
620
|
+
"changestatements"
|
|
621
|
+
];
|
|
622
|
+
return order.indexOf(key1) - order.indexOf(key2);
|
|
623
|
+
}).filter(([key]) => (onlyChange ? ["statements", "changestatements"] : [
|
|
624
|
+
"statements",
|
|
625
|
+
"branches",
|
|
626
|
+
"functions",
|
|
627
|
+
"lines",
|
|
628
|
+
"changestatements"
|
|
629
|
+
]).includes(key)).map(([key, value]) => {
|
|
630
|
+
return /* @__PURE__ */ jsxs("div", {
|
|
631
|
+
style: {
|
|
632
|
+
display: "flex",
|
|
633
|
+
gap: "3px",
|
|
634
|
+
alignItems: "center"
|
|
635
|
+
},
|
|
636
|
+
children: [
|
|
637
|
+
/* @__PURE__ */ jsxs("span", {
|
|
638
|
+
style: {
|
|
639
|
+
fontWeight: "600",
|
|
640
|
+
fontSize: "14px"
|
|
641
|
+
},
|
|
642
|
+
children: [value.pct, "%"]
|
|
643
|
+
}),
|
|
644
|
+
/* @__PURE__ */ jsxs(Text, {
|
|
645
|
+
style: { fontSize: "14px" },
|
|
646
|
+
type: "secondary",
|
|
647
|
+
children: [t$1(`${key}`), ":"]
|
|
648
|
+
}),
|
|
649
|
+
/* @__PURE__ */ jsxs(Tag, {
|
|
650
|
+
bordered: false,
|
|
651
|
+
children: [
|
|
652
|
+
value.covered,
|
|
653
|
+
"/",
|
|
654
|
+
value.total
|
|
655
|
+
]
|
|
656
|
+
})
|
|
657
|
+
]
|
|
658
|
+
}, key);
|
|
659
|
+
})
|
|
27
660
|
}) });
|
|
661
|
+
};
|
|
662
|
+
const SummaryBar = ({ pct }) => {
|
|
663
|
+
return /* @__PURE__ */ jsx("div", { style: {
|
|
664
|
+
height: "8px",
|
|
665
|
+
width: "100%",
|
|
666
|
+
marginBottom: "6px",
|
|
667
|
+
backgroundColor: getColor(pct)
|
|
668
|
+
} });
|
|
669
|
+
};
|
|
670
|
+
const SummaryHeader = ({ value, onSelect, data, reportName, onlyChange }) => {
|
|
671
|
+
return /* @__PURE__ */ jsxs("div", { children: [
|
|
672
|
+
/* @__PURE__ */ jsx(SummaryNav, {
|
|
673
|
+
reportName,
|
|
674
|
+
value,
|
|
675
|
+
onClick: onSelect
|
|
676
|
+
}),
|
|
677
|
+
/* @__PURE__ */ jsx(SummaryMetric, {
|
|
678
|
+
data,
|
|
679
|
+
onlyChange
|
|
680
|
+
}),
|
|
681
|
+
/* @__PURE__ */ jsx(SummaryBar, { pct: data.statements.pct })
|
|
682
|
+
] });
|
|
683
|
+
};
|
|
684
|
+
var SummaryHeader_default = SummaryHeader;
|
|
685
|
+
|
|
686
|
+
//#endregion
|
|
687
|
+
//#region src/widgets/SummaryList.tsx
|
|
688
|
+
const t = (msg) => msg;
|
|
689
|
+
const SummaryList = ({ dataSource, onSelect, filenameKeywords, style, onlyChange }) => {
|
|
690
|
+
return /* @__PURE__ */ jsx("div", {
|
|
691
|
+
style,
|
|
692
|
+
children: /* @__PURE__ */ jsx(ConfigProvider, {
|
|
693
|
+
theme: { token: { borderRadius: 0 } },
|
|
694
|
+
children: /* @__PURE__ */ jsx(Table, {
|
|
695
|
+
bordered: true,
|
|
696
|
+
pagination: { defaultPageSize: 15 },
|
|
697
|
+
size: "small",
|
|
698
|
+
dataSource,
|
|
699
|
+
rowKey: "path",
|
|
700
|
+
columns: [
|
|
701
|
+
{
|
|
702
|
+
title: t("Files"),
|
|
703
|
+
key: "path",
|
|
704
|
+
dataIndex: "path",
|
|
705
|
+
render(text) {
|
|
706
|
+
return /* @__PURE__ */ jsx("a", {
|
|
707
|
+
style: {
|
|
708
|
+
width: "420px",
|
|
709
|
+
display: "block",
|
|
710
|
+
overflowWrap: "break-word"
|
|
711
|
+
},
|
|
712
|
+
onClick: () => {
|
|
713
|
+
onSelect(text);
|
|
714
|
+
},
|
|
715
|
+
children: /* @__PURE__ */ jsx(Highlighter, {
|
|
716
|
+
highlightClassName: "YourHighlightClass",
|
|
717
|
+
searchWords: [filenameKeywords],
|
|
718
|
+
autoEscape: true,
|
|
719
|
+
textToHighlight: text
|
|
720
|
+
})
|
|
721
|
+
});
|
|
722
|
+
}
|
|
723
|
+
},
|
|
724
|
+
{
|
|
725
|
+
title: t("Total"),
|
|
726
|
+
key: "total",
|
|
727
|
+
dataIndex: ["statements", "total"],
|
|
728
|
+
sorter(a, b) {
|
|
729
|
+
return a.statements.total - b.statements.total;
|
|
730
|
+
}
|
|
731
|
+
},
|
|
732
|
+
{
|
|
733
|
+
title: t("Covered"),
|
|
734
|
+
key: "covered",
|
|
735
|
+
dataIndex: ["statements", "covered"],
|
|
736
|
+
sorter(a, b) {
|
|
737
|
+
return a.statements.covered - b.statements.covered;
|
|
738
|
+
}
|
|
739
|
+
},
|
|
740
|
+
{
|
|
741
|
+
title: t("Change Statements"),
|
|
742
|
+
key: "changestatements",
|
|
743
|
+
dataIndex: ["changestatements"],
|
|
744
|
+
width: "220px",
|
|
745
|
+
render(_) {
|
|
746
|
+
_ = _ || {
|
|
747
|
+
pct: 100,
|
|
748
|
+
total: 0,
|
|
749
|
+
covered: 0
|
|
750
|
+
};
|
|
751
|
+
return /* @__PURE__ */ jsxs("div", {
|
|
752
|
+
style: {
|
|
753
|
+
display: "flex",
|
|
754
|
+
alignItems: "center"
|
|
755
|
+
},
|
|
756
|
+
children: [/* @__PURE__ */ jsx(Progress, {
|
|
757
|
+
percent: _.pct,
|
|
758
|
+
strokeLinecap: "butt",
|
|
759
|
+
size: "small",
|
|
760
|
+
strokeColor: getColor(_.pct),
|
|
761
|
+
style: {
|
|
762
|
+
width: "100px",
|
|
763
|
+
paddingRight: "5px",
|
|
764
|
+
fontSize: "10px"
|
|
765
|
+
},
|
|
766
|
+
status: "normal"
|
|
767
|
+
}), /* @__PURE__ */ jsxs("span", {
|
|
768
|
+
style: { fontSize: "10px" },
|
|
769
|
+
children: [
|
|
770
|
+
"(",
|
|
771
|
+
`${_.covered}/${_.total}`,
|
|
772
|
+
")"
|
|
773
|
+
]
|
|
774
|
+
})]
|
|
775
|
+
});
|
|
776
|
+
}
|
|
777
|
+
},
|
|
778
|
+
{
|
|
779
|
+
title: `${t("Coverage")} %`,
|
|
780
|
+
width: "240px",
|
|
781
|
+
key: "c",
|
|
782
|
+
sorter: (a, b) => {
|
|
783
|
+
return a.statements.pct - b.statements.pct;
|
|
784
|
+
},
|
|
785
|
+
dataIndex: ["statements", "pct"],
|
|
786
|
+
render(text) {
|
|
787
|
+
return /* @__PURE__ */ jsx(Progress, {
|
|
788
|
+
percent: text,
|
|
789
|
+
strokeLinecap: "butt",
|
|
790
|
+
size: "small",
|
|
791
|
+
strokeColor: getColor(text),
|
|
792
|
+
style: { paddingRight: "5px" },
|
|
793
|
+
status: "normal"
|
|
794
|
+
});
|
|
795
|
+
}
|
|
796
|
+
}
|
|
797
|
+
].filter((c) => c.key !== "changestatements" || c.key === "changestatements" && onlyChange)
|
|
798
|
+
})
|
|
799
|
+
})
|
|
800
|
+
});
|
|
801
|
+
};
|
|
802
|
+
var SummaryList_default = SummaryList;
|
|
803
|
+
|
|
804
|
+
//#endregion
|
|
805
|
+
//#region src/widgets/TopControl.tsx
|
|
806
|
+
const TopControl = ({ total, showMode, onChangeShowMode, onChangeKeywords, filenameKeywords, onChangeOnlyChange, onlyChange }) => {
|
|
807
|
+
return /* @__PURE__ */ jsxs("div", { children: [/* @__PURE__ */ jsxs("div", {
|
|
808
|
+
style: {
|
|
809
|
+
display: "flex",
|
|
810
|
+
marginBottom: "6px",
|
|
811
|
+
justifyContent: "space-between",
|
|
812
|
+
alignItems: "center"
|
|
813
|
+
},
|
|
814
|
+
children: [/* @__PURE__ */ jsx("div", {
|
|
815
|
+
style: {
|
|
816
|
+
display: "flex",
|
|
817
|
+
gap: "6px",
|
|
818
|
+
flexDirection: "column"
|
|
819
|
+
},
|
|
820
|
+
children: /* @__PURE__ */ jsxs(Space, { children: [/* @__PURE__ */ jsx(Segmented, {
|
|
821
|
+
size: "small",
|
|
822
|
+
value: showMode,
|
|
823
|
+
defaultValue: showMode,
|
|
824
|
+
onChange: (v) => {
|
|
825
|
+
onChangeShowMode(v);
|
|
826
|
+
},
|
|
827
|
+
options: [{
|
|
828
|
+
label: "Code Tree",
|
|
829
|
+
value: "tree"
|
|
830
|
+
}, {
|
|
831
|
+
label: "File List",
|
|
832
|
+
value: "list"
|
|
833
|
+
}]
|
|
834
|
+
}), /* @__PURE__ */ jsx("span", {
|
|
835
|
+
style: { fontSize: "14px" },
|
|
836
|
+
children: /* @__PURE__ */ jsxs("span", {
|
|
837
|
+
style: { marginBottom: "6px" },
|
|
838
|
+
children: [
|
|
839
|
+
total,
|
|
840
|
+
" ",
|
|
841
|
+
"Total Files"
|
|
842
|
+
]
|
|
843
|
+
})
|
|
844
|
+
})] })
|
|
845
|
+
}), /* @__PURE__ */ jsxs("div", {
|
|
846
|
+
style: {
|
|
847
|
+
display: "flex",
|
|
848
|
+
alignItems: "center"
|
|
849
|
+
},
|
|
850
|
+
children: [
|
|
851
|
+
/* @__PURE__ */ jsxs("div", {
|
|
852
|
+
style: {
|
|
853
|
+
display: "flex",
|
|
854
|
+
alignItems: "center",
|
|
855
|
+
gap: "6px"
|
|
856
|
+
},
|
|
857
|
+
children: [/* @__PURE__ */ jsxs(Typography.Text, {
|
|
858
|
+
type: "secondary",
|
|
859
|
+
style: { fontSize: "12px" },
|
|
860
|
+
children: [
|
|
861
|
+
"Only Changed",
|
|
862
|
+
":",
|
|
863
|
+
" "
|
|
864
|
+
]
|
|
865
|
+
}), /* @__PURE__ */ jsx(Switch, {
|
|
866
|
+
checked: onlyChange,
|
|
867
|
+
size: "small",
|
|
868
|
+
onChange: onChangeOnlyChange
|
|
869
|
+
})]
|
|
870
|
+
}),
|
|
871
|
+
/* @__PURE__ */ jsx(Divider, { type: "vertical" }),
|
|
872
|
+
/* @__PURE__ */ jsx(Input, {
|
|
873
|
+
placeholder: "Enter the file path to search",
|
|
874
|
+
value: filenameKeywords,
|
|
875
|
+
style: { width: "240px" },
|
|
876
|
+
size: "small",
|
|
877
|
+
onChange: (val) => {
|
|
878
|
+
onChangeKeywords(val.target.value);
|
|
879
|
+
}
|
|
880
|
+
})
|
|
881
|
+
]
|
|
882
|
+
})]
|
|
883
|
+
}), /* @__PURE__ */ jsx(Divider, { style: {
|
|
884
|
+
margin: "0",
|
|
885
|
+
marginBottom: "6px"
|
|
886
|
+
} })] });
|
|
887
|
+
};
|
|
888
|
+
var TopControl_default = TopControl;
|
|
889
|
+
|
|
890
|
+
//#endregion
|
|
891
|
+
//#region src/helpers/generateCoreDataForEachComponent.ts
|
|
892
|
+
function checkSummaryOnlyChange(item, onlyChange) {
|
|
893
|
+
if (onlyChange === false) return true;
|
|
894
|
+
if (onlyChange && item.change) return true;
|
|
895
|
+
return false;
|
|
28
896
|
}
|
|
29
|
-
|
|
897
|
+
function checkSummaryKeywords(item, keywords) {
|
|
898
|
+
return item.path.toLowerCase().includes(keywords.toLowerCase());
|
|
899
|
+
}
|
|
900
|
+
function checkStartValue(item, startValue) {
|
|
901
|
+
return item.path.toLowerCase().includes(startValue.toLowerCase());
|
|
902
|
+
}
|
|
903
|
+
const generateCoreDataForEachComponent = ({ dataSource, filenameKeywords, value, onlyChange }) => {
|
|
904
|
+
const listDataSource = Object.values(dataSource).filter((item) => checkStartValue(item, value) && checkSummaryOnlyChange(item, onlyChange) && checkSummaryKeywords(item, filenameKeywords));
|
|
905
|
+
const aaaa = genSummaryTreeItem(value, listDataSource.reduce((acc, cur) => {
|
|
906
|
+
acc[cur.path] = cur;
|
|
907
|
+
return acc;
|
|
908
|
+
}, {}));
|
|
909
|
+
return {
|
|
910
|
+
treeDataSource: aaaa.children.map((item) => {
|
|
911
|
+
return {
|
|
912
|
+
path: item.path,
|
|
913
|
+
...item.summary
|
|
914
|
+
};
|
|
915
|
+
}),
|
|
916
|
+
rootDataSource: {
|
|
917
|
+
path: aaaa.path,
|
|
918
|
+
...aaaa.summary
|
|
919
|
+
},
|
|
920
|
+
listDataSource
|
|
921
|
+
};
|
|
922
|
+
};
|
|
30
923
|
|
|
31
924
|
//#endregion
|
|
32
|
-
//#region src/
|
|
33
|
-
function
|
|
34
|
-
|
|
925
|
+
//#region src/widgets/SummaryTree.tsx
|
|
926
|
+
function checkSuffix(str) {
|
|
927
|
+
console.log(str);
|
|
928
|
+
return true;
|
|
35
929
|
}
|
|
930
|
+
const SummaryTree = ({ dataSource, onSelect, style, onlyChange }) => {
|
|
931
|
+
const t$1 = (res) => res;
|
|
932
|
+
return /* @__PURE__ */ jsx("div", {
|
|
933
|
+
style,
|
|
934
|
+
children: /* @__PURE__ */ jsx(ConfigProvider, {
|
|
935
|
+
theme: { token: { borderRadius: 0 } },
|
|
936
|
+
children: /* @__PURE__ */ jsx(Table, {
|
|
937
|
+
rowKey: "path",
|
|
938
|
+
bordered: true,
|
|
939
|
+
pagination: false,
|
|
940
|
+
size: "small",
|
|
941
|
+
dataSource,
|
|
942
|
+
columns: [
|
|
943
|
+
{
|
|
944
|
+
title: t$1("Files"),
|
|
945
|
+
key: "path",
|
|
946
|
+
dataIndex: "path",
|
|
947
|
+
render(text) {
|
|
948
|
+
return /* @__PURE__ */ jsxs("a", {
|
|
949
|
+
style: {
|
|
950
|
+
display: "flex",
|
|
951
|
+
gap: "6px"
|
|
952
|
+
},
|
|
953
|
+
onClick: () => {
|
|
954
|
+
onSelect(text);
|
|
955
|
+
},
|
|
956
|
+
children: [/\.(js|jsx|ts|tsx|vue)$/.test(text) && checkSuffix(text) ? /* @__PURE__ */ jsx(FileOutlined, { style: { fontSize: "16px" } }) : /* @__PURE__ */ jsx(FolderFilled, { style: { fontSize: "16px" } }), text.split("/").at(-1)]
|
|
957
|
+
});
|
|
958
|
+
}
|
|
959
|
+
},
|
|
960
|
+
{
|
|
961
|
+
title: t$1("Total"),
|
|
962
|
+
key: "total",
|
|
963
|
+
dataIndex: ["statements", "total"],
|
|
964
|
+
sorter(a, b) {
|
|
965
|
+
return a.statements.total - b.statements.total;
|
|
966
|
+
}
|
|
967
|
+
},
|
|
968
|
+
{
|
|
969
|
+
title: t$1("Covered"),
|
|
970
|
+
key: "covered",
|
|
971
|
+
dataIndex: ["statements", "covered"],
|
|
972
|
+
sorter(a, b) {
|
|
973
|
+
return a.statements.covered - b.statements.covered;
|
|
974
|
+
}
|
|
975
|
+
},
|
|
976
|
+
{
|
|
977
|
+
title: t$1("Change Statements"),
|
|
978
|
+
key: "changestatements",
|
|
979
|
+
dataIndex: ["changestatements"],
|
|
980
|
+
width: "220px",
|
|
981
|
+
render(_) {
|
|
982
|
+
_ = _ || {
|
|
983
|
+
pct: 100,
|
|
984
|
+
total: 0,
|
|
985
|
+
covered: 0
|
|
986
|
+
};
|
|
987
|
+
return /* @__PURE__ */ jsxs("div", {
|
|
988
|
+
style: {
|
|
989
|
+
display: "flex",
|
|
990
|
+
alignItems: "center"
|
|
991
|
+
},
|
|
992
|
+
children: [/* @__PURE__ */ jsx(Progress, {
|
|
993
|
+
percent: _.pct,
|
|
994
|
+
strokeLinecap: "butt",
|
|
995
|
+
size: "small",
|
|
996
|
+
strokeColor: getColor(_.pct),
|
|
997
|
+
style: {
|
|
998
|
+
width: "100px",
|
|
999
|
+
paddingRight: "5px",
|
|
1000
|
+
fontSize: "10px"
|
|
1001
|
+
},
|
|
1002
|
+
status: "normal"
|
|
1003
|
+
}), /* @__PURE__ */ jsxs("span", {
|
|
1004
|
+
style: { fontSize: "10px" },
|
|
1005
|
+
children: [
|
|
1006
|
+
"(",
|
|
1007
|
+
`${_.covered}/${_.total}`,
|
|
1008
|
+
")"
|
|
1009
|
+
]
|
|
1010
|
+
})]
|
|
1011
|
+
});
|
|
1012
|
+
}
|
|
1013
|
+
},
|
|
1014
|
+
{
|
|
1015
|
+
title: `${t$1("Coverage")} %`,
|
|
1016
|
+
width: "240px",
|
|
1017
|
+
key: "c",
|
|
1018
|
+
dataIndex: ["statements", "pct"],
|
|
1019
|
+
sorter(a, b) {
|
|
1020
|
+
return a.statements.pct - b.statements.pct;
|
|
1021
|
+
},
|
|
1022
|
+
render(text) {
|
|
1023
|
+
return /* @__PURE__ */ jsx(Progress, {
|
|
1024
|
+
percent: text,
|
|
1025
|
+
strokeLinecap: "butt",
|
|
1026
|
+
size: "small",
|
|
1027
|
+
strokeColor: getColor(text),
|
|
1028
|
+
style: { paddingRight: "5px" },
|
|
1029
|
+
status: "normal"
|
|
1030
|
+
});
|
|
1031
|
+
}
|
|
1032
|
+
}
|
|
1033
|
+
].filter((c) => c.key !== "changestatements" || c.key === "changestatements" && onlyChange)
|
|
1034
|
+
})
|
|
1035
|
+
})
|
|
1036
|
+
});
|
|
1037
|
+
};
|
|
1038
|
+
var SummaryTree_default = SummaryTree;
|
|
1039
|
+
|
|
1040
|
+
//#endregion
|
|
1041
|
+
//#region src/components/RIf.tsx
|
|
1042
|
+
const RIf = ({ condition, children }) => {
|
|
1043
|
+
return /* @__PURE__ */ jsx(Fragment, { children: condition ? /* @__PURE__ */ jsx(Fragment, { children }) : null });
|
|
1044
|
+
};
|
|
1045
|
+
var RIf_default = RIf;
|
|
1046
|
+
|
|
1047
|
+
//#endregion
|
|
1048
|
+
//#region src/widgets/CoverageDetail.tsx
|
|
1049
|
+
function CanyonReport$1({ fileContent, fileCoverage, fileCodeChange }) {
|
|
1050
|
+
const ref = useRef(null);
|
|
1051
|
+
useEffect(() => {
|
|
1052
|
+
if (ref.current) {
|
|
1053
|
+
const dom = ref.current;
|
|
1054
|
+
const options = {
|
|
1055
|
+
value: fileContent,
|
|
1056
|
+
language: "javascript"
|
|
1057
|
+
};
|
|
1058
|
+
if (window.monaco?.editor && dom) window.monaco.editor.create(dom, options);
|
|
1059
|
+
}
|
|
1060
|
+
}, []);
|
|
1061
|
+
return /* @__PURE__ */ jsxs("div", { children: [JSON.stringify(fileCodeChange || []), /* @__PURE__ */ jsx("div", {
|
|
1062
|
+
ref,
|
|
1063
|
+
style: { height: "calc(100vh - 150px)" }
|
|
1064
|
+
})] });
|
|
1065
|
+
}
|
|
1066
|
+
var CoverageDetail_default = CanyonReport$1;
|
|
36
1067
|
|
|
37
1068
|
//#endregion
|
|
38
1069
|
//#region src/CanyonReport.tsx
|
|
39
|
-
const CanyonReport = ({ value, name, dataSource }) => {
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
1070
|
+
const CanyonReport = ({ value, name, dataSource, onSelect }) => {
|
|
1071
|
+
const [_isLoading, _setIsLoading] = useState(false);
|
|
1072
|
+
const [filenameKeywords, setFilenameKeywords] = useState("");
|
|
1073
|
+
const [showMode, setShowMode] = useState("tree");
|
|
1074
|
+
const [fileCoverage, setFileCoverage] = useState({
|
|
1075
|
+
path: "",
|
|
1076
|
+
statementMap: {},
|
|
1077
|
+
fnMap: {},
|
|
1078
|
+
branchMap: {},
|
|
1079
|
+
s: {},
|
|
1080
|
+
f: {},
|
|
1081
|
+
b: {}
|
|
1082
|
+
});
|
|
1083
|
+
const [fileContent, setFileContent] = useState("");
|
|
1084
|
+
const [fileCodeChange, setFileCodeChange] = useState([]);
|
|
1085
|
+
const [onlyChange, setOnlyChange] = useState(Boolean(false));
|
|
1086
|
+
const rootClassName = useMemo(() => `report-scope-${Math.random().toString(36).slice(2, 9)}`, []);
|
|
1087
|
+
function onChangeOnlyChange(v) {
|
|
1088
|
+
setOnlyChange(v);
|
|
1089
|
+
}
|
|
1090
|
+
async function newOnSelect(val) {
|
|
1091
|
+
const res = await onSelect(val);
|
|
1092
|
+
setFileContent(res.fileContent || "");
|
|
1093
|
+
setFileCoverage(res.fileCoverage || {});
|
|
1094
|
+
setFileCodeChange(res.fileCodeChange || "");
|
|
1095
|
+
return res;
|
|
1096
|
+
}
|
|
1097
|
+
useEffect(() => {
|
|
1098
|
+
newOnSelect(value);
|
|
1099
|
+
}, []);
|
|
1100
|
+
const isFile = useMemo(() => {
|
|
1101
|
+
return /\.(js|jsx|ts|tsx|vue)$/.test(value);
|
|
1102
|
+
}, [value]);
|
|
1103
|
+
const mode = useMemo(() => {
|
|
1104
|
+
if (isFile) return "file";
|
|
1105
|
+
return showMode;
|
|
1106
|
+
}, [showMode, value]);
|
|
1107
|
+
const isFileDataReady = useMemo(() => {
|
|
1108
|
+
const hasCoverage = fileCoverage && Object.keys(fileCoverage).length > 0;
|
|
1109
|
+
const hasContent = fileContent.length > 0;
|
|
1110
|
+
return hasCoverage && hasContent;
|
|
1111
|
+
}, [fileCoverage, fileContent]);
|
|
1112
|
+
const { treeDataSource, rootDataSource, listDataSource } = useMemo(() => {
|
|
1113
|
+
console.log(dataSource, "dataSource", "filenameKeywords", filenameKeywords, value);
|
|
1114
|
+
return generateCoreDataForEachComponent({
|
|
1115
|
+
dataSource,
|
|
1116
|
+
filenameKeywords,
|
|
1117
|
+
value,
|
|
1118
|
+
onlyChange
|
|
1119
|
+
});
|
|
1120
|
+
}, [
|
|
1121
|
+
dataSource,
|
|
1122
|
+
value,
|
|
1123
|
+
filenameKeywords,
|
|
1124
|
+
onlyChange
|
|
1125
|
+
]);
|
|
1126
|
+
return /* @__PURE__ */ jsx("div", {
|
|
1127
|
+
className: rootClassName,
|
|
1128
|
+
children: /* @__PURE__ */ jsxs(ConfigProvider, {
|
|
1129
|
+
theme: { token: {
|
|
1130
|
+
colorPrimary: "#0071c2",
|
|
1131
|
+
borderRadius: 2
|
|
1132
|
+
} },
|
|
1133
|
+
children: [
|
|
1134
|
+
/* @__PURE__ */ jsx("style", { children: `
|
|
1135
|
+
.${rootClassName} .canyon-coverage-detail-spin-wrapper { height: 100%; }
|
|
1136
|
+
.${rootClassName} .canyon-coverage-detail-spin-wrapper > .ant-spin-container { height: 100%; }
|
|
1137
|
+
` }),
|
|
1138
|
+
/* @__PURE__ */ jsx(TopControl_default, {
|
|
1139
|
+
onlyChange,
|
|
1140
|
+
filenameKeywords,
|
|
1141
|
+
showMode,
|
|
1142
|
+
onChangeShowMode: (val) => {
|
|
1143
|
+
setShowMode(val);
|
|
1144
|
+
},
|
|
1145
|
+
onChangeOnlyChange,
|
|
1146
|
+
total: listDataSource.length,
|
|
1147
|
+
onChangeKeywords: (val) => {
|
|
1148
|
+
setFilenameKeywords(val);
|
|
1149
|
+
}
|
|
1150
|
+
}),
|
|
1151
|
+
/* @__PURE__ */ jsx(SummaryHeader_default, {
|
|
1152
|
+
reportName: name,
|
|
1153
|
+
data: rootDataSource,
|
|
1154
|
+
value,
|
|
1155
|
+
onSelect: newOnSelect,
|
|
1156
|
+
onlyChange
|
|
1157
|
+
}),
|
|
1158
|
+
/* @__PURE__ */ jsx(RIf_default, {
|
|
1159
|
+
condition: mode === "file",
|
|
1160
|
+
children: /* @__PURE__ */ jsx("div", {
|
|
1161
|
+
style: {
|
|
1162
|
+
flex: 1,
|
|
1163
|
+
minHeight: 0,
|
|
1164
|
+
overflow: "auto",
|
|
1165
|
+
height: "100%"
|
|
1166
|
+
},
|
|
1167
|
+
children: /* @__PURE__ */ jsx(Spin, {
|
|
1168
|
+
spinning: !isFileDataReady,
|
|
1169
|
+
wrapperClassName: "canyon-coverage-detail-spin-wrapper",
|
|
1170
|
+
children: /* @__PURE__ */ jsx(RIf_default, {
|
|
1171
|
+
condition: isFileDataReady,
|
|
1172
|
+
children: /* @__PURE__ */ jsx(CoverageDetail_default, {
|
|
1173
|
+
fileContent,
|
|
1174
|
+
fileCoverage,
|
|
1175
|
+
fileCodeChange
|
|
1176
|
+
})
|
|
1177
|
+
})
|
|
1178
|
+
})
|
|
1179
|
+
})
|
|
1180
|
+
}),
|
|
1181
|
+
/* @__PURE__ */ jsxs(Suspense, {
|
|
1182
|
+
fallback: /* @__PURE__ */ jsx("div", {
|
|
1183
|
+
className: "p-8 text-center",
|
|
1184
|
+
children: "Loading..."
|
|
1185
|
+
}),
|
|
1186
|
+
children: [mode === "tree" && /* @__PURE__ */ jsx(SummaryTree_default, {
|
|
1187
|
+
dataSource: treeDataSource,
|
|
1188
|
+
onSelect: newOnSelect,
|
|
1189
|
+
onlyChange
|
|
1190
|
+
}), mode === "list" && /* @__PURE__ */ jsx(SummaryList_default, {
|
|
1191
|
+
dataSource: listDataSource,
|
|
1192
|
+
onSelect: newOnSelect,
|
|
1193
|
+
filenameKeywords,
|
|
1194
|
+
onlyChange
|
|
1195
|
+
})]
|
|
1196
|
+
})
|
|
1197
|
+
]
|
|
1198
|
+
})
|
|
1199
|
+
});
|
|
51
1200
|
};
|
|
52
1201
|
var CanyonReport_default = CanyonReport;
|
|
53
1202
|
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@canyonjs/report-component",
|
|
3
3
|
"type": "module",
|
|
4
|
-
"version": "0.0.1-beta.
|
|
4
|
+
"version": "0.0.1-beta.7",
|
|
5
5
|
"description": "A starter for creating a React component library.",
|
|
6
6
|
"author": "Author Name <author.name@mail.com>",
|
|
7
7
|
"license": "MIT",
|
|
@@ -32,6 +32,7 @@
|
|
|
32
32
|
},
|
|
33
33
|
"devDependencies": {
|
|
34
34
|
"@tsconfig/strictest": "^2.0.8",
|
|
35
|
+
"@types/istanbul-lib-coverage": "^2.0.6",
|
|
35
36
|
"@types/node": "^24.10.1",
|
|
36
37
|
"@types/react": "^19.2.7",
|
|
37
38
|
"@types/react-dom": "^19.2.3",
|
|
@@ -42,7 +43,12 @@
|
|
|
42
43
|
"vite": "^7.2.6"
|
|
43
44
|
},
|
|
44
45
|
"dependencies": {
|
|
45
|
-
"
|
|
46
|
+
"@ant-design/icons": "^6.1.0",
|
|
47
|
+
"@monaco-editor/react": "^4.7.0",
|
|
48
|
+
"antd": "^6.1.0",
|
|
49
|
+
"canyon-data": "2.0.0-beta.36",
|
|
50
|
+
"monaco-editor": "^0.55.1",
|
|
51
|
+
"react-highlight-words": "^0.21.0"
|
|
46
52
|
},
|
|
47
53
|
"scripts": {
|
|
48
54
|
"build": "tsdown",
|