@canyonjs/report-component 0.0.1-beta.12 → 0.0.1-beta.16
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 +5 -1
- package/dist/index.js +340 -584
- package/package.json +6 -9
package/dist/index.d.ts
CHANGED
|
@@ -10,12 +10,16 @@ interface FileDataResponse {
|
|
|
10
10
|
fileContent: string;
|
|
11
11
|
fileCodeChange: number[];
|
|
12
12
|
}
|
|
13
|
+
interface DataSourceItem {
|
|
14
|
+
path: string;
|
|
15
|
+
[key: string]: unknown;
|
|
16
|
+
}
|
|
13
17
|
interface CanyonReportProps {
|
|
14
18
|
/** 报告名称 */
|
|
15
19
|
name: string;
|
|
16
20
|
/** 当前选中的文件 */
|
|
17
21
|
value: string;
|
|
18
|
-
dataSource:
|
|
22
|
+
dataSource: DataSourceItem[];
|
|
19
23
|
onSelect: (val: string) => Promise<FileDataResponse>;
|
|
20
24
|
}
|
|
21
25
|
//#endregion
|
package/dist/index.js
CHANGED
|
@@ -2,565 +2,13 @@ import { ConfigProvider, Divider, Input, Progress, Segmented, Space, Spin, Switc
|
|
|
2
2
|
import { Suspense, useEffect, useMemo, useRef, useState } from "react";
|
|
3
3
|
import { Fragment, jsx, jsxs } from "react/jsx-runtime";
|
|
4
4
|
import { genSummaryTreeItem } from "canyon-data";
|
|
5
|
+
import { renderToStaticMarkup } from "react-dom/server";
|
|
5
6
|
import Highlighter from "react-highlight-words";
|
|
6
7
|
import { FileOutlined, FolderFilled } from "@ant-design/icons";
|
|
7
8
|
|
|
8
|
-
//#region rolldown:runtime
|
|
9
|
-
var __commonJSMin = (cb, mod) => () => (mod || cb((mod = { exports: {} }).exports, mod), mod.exports);
|
|
10
|
-
|
|
11
|
-
//#endregion
|
|
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
|
-
});
|
|
34
|
-
});
|
|
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
9
|
//#region src/components/RIf.tsx
|
|
561
|
-
var import_istanbul_lib_coverage = require_istanbul_lib_coverage();
|
|
562
10
|
const RIf = ({ condition, children }) => {
|
|
563
|
-
return /* @__PURE__ */ jsx(Fragment, { children: condition ?
|
|
11
|
+
return /* @__PURE__ */ jsx(Fragment, { children: condition ? children : null });
|
|
564
12
|
};
|
|
565
13
|
var RIf_default = RIf;
|
|
566
14
|
|
|
@@ -598,28 +46,312 @@ const generateCoreDataForEachComponent = ({ dataSource, filenameKeywords, value,
|
|
|
598
46
|
};
|
|
599
47
|
};
|
|
600
48
|
|
|
49
|
+
//#endregion
|
|
50
|
+
//#region src/helpers/annotate.ts
|
|
51
|
+
function annotateStatements(fileCoverage) {
|
|
52
|
+
const annotateStatementsList = [];
|
|
53
|
+
const statementStats = fileCoverage.s;
|
|
54
|
+
const statementMeta = fileCoverage.statementMap;
|
|
55
|
+
Object.entries(statementStats).forEach(([stName, count]) => {
|
|
56
|
+
const meta = statementMeta[stName];
|
|
57
|
+
const type = count > 0 ? "yes" : "no";
|
|
58
|
+
const startCol = meta.start.column;
|
|
59
|
+
const endCol = meta.end.column + 1;
|
|
60
|
+
const startLine = meta.start.line;
|
|
61
|
+
const endLine = meta.end.line;
|
|
62
|
+
if (type === "no") annotateStatementsList.push({
|
|
63
|
+
startLine,
|
|
64
|
+
endLine,
|
|
65
|
+
startCol: startCol + 1,
|
|
66
|
+
endCol: endCol + 1,
|
|
67
|
+
type: "S"
|
|
68
|
+
});
|
|
69
|
+
});
|
|
70
|
+
return annotateStatementsList;
|
|
71
|
+
}
|
|
72
|
+
function annotateFunctions(fileCoverage, structuredText) {
|
|
73
|
+
const fnStats = fileCoverage.f;
|
|
74
|
+
const fnMeta = fileCoverage.fnMap;
|
|
75
|
+
if (!fnStats) return [];
|
|
76
|
+
const list = [];
|
|
77
|
+
Object.entries(fnStats).forEach(([fName, count]) => {
|
|
78
|
+
const meta = fnMeta[fName];
|
|
79
|
+
const type = count > 0 ? "yes" : "no";
|
|
80
|
+
const decl = meta.decl || meta.loc;
|
|
81
|
+
const startCol = decl.start.column;
|
|
82
|
+
let endCol = decl.end.column + 1;
|
|
83
|
+
const startLine = decl.start.line;
|
|
84
|
+
const endLine = decl.end.line;
|
|
85
|
+
if (type === "no") {
|
|
86
|
+
if (endLine !== startLine) endCol = structuredText[startLine - 1].length;
|
|
87
|
+
list.push({
|
|
88
|
+
startLine,
|
|
89
|
+
endLine,
|
|
90
|
+
startCol: startCol + 1,
|
|
91
|
+
endCol: endCol + 1,
|
|
92
|
+
type: "F"
|
|
93
|
+
});
|
|
94
|
+
}
|
|
95
|
+
});
|
|
96
|
+
return list;
|
|
97
|
+
}
|
|
98
|
+
function annotateBranches(fileCoverage, structuredText) {
|
|
99
|
+
const branchStats = fileCoverage.b;
|
|
100
|
+
const branchMeta = fileCoverage.branchMap;
|
|
101
|
+
if (!branchStats) return [];
|
|
102
|
+
const arr = [];
|
|
103
|
+
Object.entries(branchStats).forEach(([branchName, branchArray]) => {
|
|
104
|
+
const sumCount = branchArray.reduce((p, n) => p + n, 0);
|
|
105
|
+
const metaArray = branchMeta[branchName].locations;
|
|
106
|
+
let i;
|
|
107
|
+
let count;
|
|
108
|
+
let meta;
|
|
109
|
+
let startCol;
|
|
110
|
+
let endCol;
|
|
111
|
+
let startLine;
|
|
112
|
+
let endLine;
|
|
113
|
+
if (sumCount > 0 || sumCount === 0 && branchArray.length === 1) {
|
|
114
|
+
if (branchMeta[branchName].type === "if" && branchArray.length === 2 && metaArray.length === 1 && branchArray[1] === 0) metaArray[1] = {
|
|
115
|
+
start: {},
|
|
116
|
+
end: {}
|
|
117
|
+
};
|
|
118
|
+
for (i = 0; i < branchArray.length && i < metaArray.length; i += 1) {
|
|
119
|
+
count = branchArray[i];
|
|
120
|
+
meta = metaArray[i];
|
|
121
|
+
startCol = meta.start.column;
|
|
122
|
+
endCol = meta.end.column + 1;
|
|
123
|
+
startLine = meta.start.line;
|
|
124
|
+
endLine = meta.end.line;
|
|
125
|
+
if (count === 0 && startLine === void 0 && branchMeta[branchName].type === "if") {
|
|
126
|
+
const prevMeta = metaArray[i - 1];
|
|
127
|
+
startCol = prevMeta.start.column;
|
|
128
|
+
endCol = prevMeta.end.column + 1;
|
|
129
|
+
startLine = prevMeta.start.line;
|
|
130
|
+
endLine = prevMeta.end.line;
|
|
131
|
+
}
|
|
132
|
+
if (count === 0 && structuredText[startLine]) {
|
|
133
|
+
if (endLine !== startLine) {}
|
|
134
|
+
structuredText[startLine].text;
|
|
135
|
+
if (branchMeta[branchName].type === "if") arr.push({
|
|
136
|
+
startLine,
|
|
137
|
+
endLine,
|
|
138
|
+
startCol: startCol + 1,
|
|
139
|
+
endCol: endCol + 1,
|
|
140
|
+
type: i === 0 ? "I" : "E",
|
|
141
|
+
skip: meta.skip
|
|
142
|
+
});
|
|
143
|
+
else arr.push({
|
|
144
|
+
startLine,
|
|
145
|
+
endLine,
|
|
146
|
+
startCol: startCol + 1,
|
|
147
|
+
endCol: endCol + 1,
|
|
148
|
+
type: "B",
|
|
149
|
+
skip: meta.skip
|
|
150
|
+
});
|
|
151
|
+
}
|
|
152
|
+
}
|
|
153
|
+
}
|
|
154
|
+
});
|
|
155
|
+
return arr;
|
|
156
|
+
}
|
|
157
|
+
|
|
158
|
+
//#endregion
|
|
159
|
+
//#region src/helpers/coreFn.ts
|
|
160
|
+
function coreFn(fileCoverage, fileDetail) {
|
|
161
|
+
const nullData = {
|
|
162
|
+
times: [],
|
|
163
|
+
rows: [],
|
|
164
|
+
maxWidth: 0,
|
|
165
|
+
lines: []
|
|
166
|
+
};
|
|
167
|
+
if (!fileCoverage.s) return nullData;
|
|
168
|
+
const content = fileDetail;
|
|
169
|
+
const rows = [""];
|
|
170
|
+
let index = 0;
|
|
171
|
+
for (let i = 0; i < content.length; i++) if (content[i] === "\n") {
|
|
172
|
+
index += 1;
|
|
173
|
+
rows.push("");
|
|
174
|
+
} else rows[index] += content[i];
|
|
175
|
+
const maxWidth = JSON.parse(JSON.stringify(rows)).sort((a, b) => -(a.length - b.length))[0].length;
|
|
176
|
+
function getLineCoverage(data) {
|
|
177
|
+
const statementMap = data.statementMap;
|
|
178
|
+
const statements = data.s;
|
|
179
|
+
const lineMap = Object.create(null);
|
|
180
|
+
Object.entries(statements).forEach(([st, count]) => {
|
|
181
|
+
if (!statementMap[st]) return;
|
|
182
|
+
const { line } = statementMap[st].start;
|
|
183
|
+
const prevVal = lineMap[line];
|
|
184
|
+
if (prevVal === void 0 || prevVal < count) lineMap[line] = count;
|
|
185
|
+
});
|
|
186
|
+
return lineMap;
|
|
187
|
+
}
|
|
188
|
+
const lineStats = getLineCoverage(fileCoverage);
|
|
189
|
+
if (!lineStats) return nullData;
|
|
190
|
+
const numberOfRows = [];
|
|
191
|
+
Object.entries(lineStats).forEach(([lineNumber, count]) => {
|
|
192
|
+
numberOfRows.push({
|
|
193
|
+
lineNumber,
|
|
194
|
+
count
|
|
195
|
+
});
|
|
196
|
+
});
|
|
197
|
+
const lines = [];
|
|
198
|
+
for (let i = 0; i < rows.length; i++) if (numberOfRows.find((n) => Number(n.lineNumber) === i + 1)) lines.push({ executionNumber: numberOfRows.find((n) => Number(n.lineNumber) === i + 1).count });
|
|
199
|
+
else lines.push({ executionNumber: -1 });
|
|
200
|
+
return {
|
|
201
|
+
times: numberOfRows,
|
|
202
|
+
rows,
|
|
203
|
+
lines,
|
|
204
|
+
maxWidth
|
|
205
|
+
};
|
|
206
|
+
}
|
|
207
|
+
|
|
208
|
+
//#endregion
|
|
209
|
+
//#region src/widgets/lineNumbers.tsx
|
|
210
|
+
function genBgColor(hit) {
|
|
211
|
+
if (hit > 0) return "rgb(230, 245, 208)";
|
|
212
|
+
else if (hit === 0) return "#f3aeac";
|
|
213
|
+
else return "rgb(234, 234, 234)";
|
|
214
|
+
}
|
|
215
|
+
const LineNumber = ({ lineNumber }) => {
|
|
216
|
+
return /* @__PURE__ */ jsx("span", {
|
|
217
|
+
className: "line-number",
|
|
218
|
+
children: lineNumber
|
|
219
|
+
});
|
|
220
|
+
};
|
|
221
|
+
const LineChange = ({ hasChange }) => {
|
|
222
|
+
return /* @__PURE__ */ jsx("span", {
|
|
223
|
+
className: "line-change",
|
|
224
|
+
children: hasChange ? "+" : ""
|
|
225
|
+
});
|
|
226
|
+
};
|
|
227
|
+
const LineCoverage = ({ hit, width }) => {
|
|
228
|
+
return /* @__PURE__ */ jsx("span", {
|
|
229
|
+
className: "line-coverage",
|
|
230
|
+
style: {
|
|
231
|
+
background: genBgColor(hit),
|
|
232
|
+
width: `${width}px`
|
|
233
|
+
},
|
|
234
|
+
children: hit > 0 ? `${hit}x` : ""
|
|
235
|
+
});
|
|
236
|
+
};
|
|
237
|
+
const LineNumberWrapper = ({ lineNumber, line, maxHitWidth }) => {
|
|
238
|
+
return /* @__PURE__ */ jsxs("div", {
|
|
239
|
+
className: "line-number-wrapper",
|
|
240
|
+
children: [
|
|
241
|
+
/* @__PURE__ */ jsx(LineNumber, { lineNumber }),
|
|
242
|
+
/* @__PURE__ */ jsx(LineChange, { hasChange: line.change }),
|
|
243
|
+
/* @__PURE__ */ jsx(LineCoverage, {
|
|
244
|
+
hit: line.hit,
|
|
245
|
+
width: maxHitWidth
|
|
246
|
+
})
|
|
247
|
+
]
|
|
248
|
+
});
|
|
249
|
+
};
|
|
250
|
+
function lineNumbers(lineNumber, linesState, _addLines) {
|
|
251
|
+
return renderToStaticMarkup(/* @__PURE__ */ jsx(LineNumberWrapper, {
|
|
252
|
+
lineNumber,
|
|
253
|
+
line: linesState.find((line) => line.lineNumber === lineNumber) || {
|
|
254
|
+
change: false,
|
|
255
|
+
hit: 0,
|
|
256
|
+
lineNumber
|
|
257
|
+
},
|
|
258
|
+
maxHitWidth: (Math.max(...linesState.map((line) => line.hit)).toString().length + 2) * 7.2
|
|
259
|
+
}));
|
|
260
|
+
}
|
|
261
|
+
|
|
601
262
|
//#endregion
|
|
602
263
|
//#region src/widgets/CoverageDetail.tsx
|
|
603
|
-
|
|
604
|
-
|
|
264
|
+
const CoverageDetail = ({ source, coverage, diff }) => {
|
|
265
|
+
const { lines } = coreFn(coverage, source);
|
|
266
|
+
const addLines = diff.additions || [];
|
|
267
|
+
const linesState = (() => {
|
|
268
|
+
return lines.map((line, index) => {
|
|
269
|
+
return {
|
|
270
|
+
lineNumber: index + 1,
|
|
271
|
+
change: addLines.includes(index + 1),
|
|
272
|
+
hit: line.executionNumber
|
|
273
|
+
};
|
|
274
|
+
});
|
|
275
|
+
})();
|
|
276
|
+
const lineNumbersMinChars = (() => {
|
|
277
|
+
return Math.max(...linesState.map((line) => line.hit)).toString().length + 8;
|
|
278
|
+
})();
|
|
605
279
|
const ref = useRef(null);
|
|
606
280
|
useEffect(() => {
|
|
607
281
|
if (ref.current) {
|
|
608
282
|
const dom = ref.current;
|
|
609
283
|
const options = {
|
|
610
|
-
value:
|
|
284
|
+
value: source,
|
|
611
285
|
language: "javascript",
|
|
612
|
-
fontFamily: "IBMPlexMono"
|
|
286
|
+
fontFamily: "IBMPlexMono",
|
|
287
|
+
lineHeight: 18,
|
|
288
|
+
lineNumbers: (lineNumber) => {
|
|
289
|
+
return lineNumbers(lineNumber, linesState);
|
|
290
|
+
},
|
|
291
|
+
lineNumbersMinChars,
|
|
292
|
+
readOnly: true,
|
|
293
|
+
folding: false,
|
|
294
|
+
minimap: { enabled: false },
|
|
295
|
+
scrollBeyondLastLine: false,
|
|
296
|
+
showUnused: false,
|
|
297
|
+
fontSize: 12,
|
|
298
|
+
contextmenu: false,
|
|
299
|
+
automaticLayout: true
|
|
613
300
|
};
|
|
614
|
-
if (window.monaco?.editor && dom)
|
|
301
|
+
if (window.monaco?.editor && dom) {
|
|
302
|
+
const editor = window.monaco.editor.create(dom, options);
|
|
303
|
+
const decorations = (() => {
|
|
304
|
+
const all = [];
|
|
305
|
+
const annotateStatementsList = annotateStatements(coverage);
|
|
306
|
+
all.push(...annotateStatementsList);
|
|
307
|
+
const annotateFunctionsList = annotateFunctions(coverage, source);
|
|
308
|
+
all.push(...annotateFunctionsList);
|
|
309
|
+
const annotateBranchesList = annotateBranches(coverage, source);
|
|
310
|
+
all.push(...annotateBranchesList);
|
|
311
|
+
const arr = [];
|
|
312
|
+
for (let i = 0; i < all.length; i++) {
|
|
313
|
+
const { startLine, startCol, endLine, endCol } = all[i];
|
|
314
|
+
if (all[i].type === "S" || all[i].type === "F") arr.push({
|
|
315
|
+
range: new window.monaco.Range(startLine, startCol, endLine, endCol),
|
|
316
|
+
options: {
|
|
317
|
+
isWholeLine: false,
|
|
318
|
+
inlineClassName: "content-class-no-found"
|
|
319
|
+
}
|
|
320
|
+
});
|
|
321
|
+
else if (all[i].type === "B") arr.push({
|
|
322
|
+
range: new window.monaco.Range(startLine, startCol, endLine, endCol),
|
|
323
|
+
options: {
|
|
324
|
+
isWholeLine: false,
|
|
325
|
+
inlineClassName: "content-class-no-found-branch"
|
|
326
|
+
}
|
|
327
|
+
});
|
|
328
|
+
else if (all[i].type === "I") arr.push({
|
|
329
|
+
range: new window.monaco.Range(startLine, startCol, startLine, startCol),
|
|
330
|
+
options: {
|
|
331
|
+
beforeContentClassName: "insert-i-decoration",
|
|
332
|
+
stickiness: window.monaco.editor.TrackedRangeStickiness.NeverGrowsWhenTypingAtEdges
|
|
333
|
+
}
|
|
334
|
+
});
|
|
335
|
+
else if (all[i].type === "E") arr.push({
|
|
336
|
+
range: new window.monaco.Range(startLine, startCol, startLine, startCol),
|
|
337
|
+
options: {
|
|
338
|
+
beforeContentClassName: "insert-e-decoration",
|
|
339
|
+
stickiness: window.monaco.editor.TrackedRangeStickiness.NeverGrowsWhenTypingAtEdges
|
|
340
|
+
}
|
|
341
|
+
});
|
|
342
|
+
}
|
|
343
|
+
return arr;
|
|
344
|
+
})();
|
|
345
|
+
if (editor) editor?.createDecorationsCollection?.(decorations);
|
|
346
|
+
}
|
|
615
347
|
}
|
|
616
|
-
}, []);
|
|
348
|
+
}, [source]);
|
|
617
349
|
return /* @__PURE__ */ jsx("div", { children: /* @__PURE__ */ jsx("div", {
|
|
618
350
|
ref,
|
|
619
351
|
style: { height: "calc(100vh - 150px)" }
|
|
620
352
|
}) });
|
|
621
|
-
}
|
|
622
|
-
var CoverageDetail_default =
|
|
353
|
+
};
|
|
354
|
+
var CoverageDetail_default = CoverageDetail;
|
|
623
355
|
|
|
624
356
|
//#endregion
|
|
625
357
|
//#region src/helpers/color.ts
|
|
@@ -643,24 +375,30 @@ const SummaryNav = ({ value, onClick, reportName }) => {
|
|
|
643
375
|
fontSize: "16px",
|
|
644
376
|
fontWeight: "bold"
|
|
645
377
|
},
|
|
646
|
-
children: `${reportName}/${value}`.split("/").map((item, index) => {
|
|
378
|
+
children: `${reportName}/${value}`.split("/").map((item, index, array) => {
|
|
379
|
+
const pathKey = `${reportName}-${array.slice(0, index + 1).join("/")}`;
|
|
647
380
|
return /* @__PURE__ */ jsxs("div", {
|
|
648
381
|
style: {
|
|
649
382
|
display: "flex",
|
|
650
383
|
gap: "6px"
|
|
651
384
|
},
|
|
652
|
-
children: [/* @__PURE__ */ jsx("
|
|
385
|
+
children: [/* @__PURE__ */ jsx("button", {
|
|
386
|
+
type: "button",
|
|
653
387
|
style: {
|
|
654
388
|
color: token.colorPrimary,
|
|
655
389
|
cursor: "pointer",
|
|
656
|
-
textDecoration: "none"
|
|
390
|
+
textDecoration: "none",
|
|
391
|
+
background: "none",
|
|
392
|
+
border: "none",
|
|
393
|
+
padding: 0,
|
|
394
|
+
font: "inherit"
|
|
657
395
|
},
|
|
658
396
|
onClick: () => {
|
|
659
397
|
onClick(value.split("/").slice(0, index).join("/"));
|
|
660
398
|
},
|
|
661
399
|
children: item
|
|
662
|
-
}
|
|
663
|
-
},
|
|
400
|
+
}), index === value.split("/").length || !value ? null : /* @__PURE__ */ jsx("span", { children: "/" })]
|
|
401
|
+
}, pathKey);
|
|
664
402
|
})
|
|
665
403
|
});
|
|
666
404
|
};
|
|
@@ -767,11 +505,19 @@ const SummaryList = ({ dataSource, onSelect, filenameKeywords, style, onlyChange
|
|
|
767
505
|
key: "path",
|
|
768
506
|
dataIndex: "path",
|
|
769
507
|
render(text) {
|
|
770
|
-
return /* @__PURE__ */ jsx("
|
|
508
|
+
return /* @__PURE__ */ jsx("button", {
|
|
509
|
+
type: "button",
|
|
771
510
|
style: {
|
|
772
511
|
width: "420px",
|
|
773
512
|
display: "block",
|
|
774
|
-
overflowWrap: "break-word"
|
|
513
|
+
overflowWrap: "break-word",
|
|
514
|
+
background: "none",
|
|
515
|
+
border: "none",
|
|
516
|
+
padding: 0,
|
|
517
|
+
textAlign: "left",
|
|
518
|
+
cursor: "pointer",
|
|
519
|
+
color: "inherit",
|
|
520
|
+
font: "inherit"
|
|
775
521
|
},
|
|
776
522
|
onClick: () => {
|
|
777
523
|
onSelect(text);
|
|
@@ -889,10 +635,18 @@ const SummaryTree = ({ dataSource, onSelect, style, onlyChange }) => {
|
|
|
889
635
|
key: "path",
|
|
890
636
|
dataIndex: "path",
|
|
891
637
|
render(text) {
|
|
892
|
-
return /* @__PURE__ */ jsxs("
|
|
638
|
+
return /* @__PURE__ */ jsxs("button", {
|
|
639
|
+
type: "button",
|
|
893
640
|
style: {
|
|
894
641
|
display: "flex",
|
|
895
|
-
gap: "6px"
|
|
642
|
+
gap: "6px",
|
|
643
|
+
background: "none",
|
|
644
|
+
border: "none",
|
|
645
|
+
padding: 0,
|
|
646
|
+
cursor: "pointer",
|
|
647
|
+
color: "inherit",
|
|
648
|
+
font: "inherit",
|
|
649
|
+
alignItems: "center"
|
|
896
650
|
},
|
|
897
651
|
onClick: () => {
|
|
898
652
|
onSelect(text);
|
|
@@ -1085,27 +839,29 @@ const CanyonReport = ({ value, name, dataSource, onSelect }) => {
|
|
|
1085
839
|
const [fileContent, setFileContent] = useState("");
|
|
1086
840
|
const [fileCodeChange, setFileCodeChange] = useState([]);
|
|
1087
841
|
const [onlyChange, setOnlyChange] = useState(Boolean(false));
|
|
1088
|
-
const rootClassName = useMemo(() => `report-scope-${Math.random().toString(36).slice(2, 9)}`, []);
|
|
842
|
+
const rootClassName = useMemo(() => `report-scope-${Math.random().toString(36).slice(2, 9)} canyonjs-report-html`, []);
|
|
1089
843
|
function onChangeOnlyChange(v) {
|
|
1090
844
|
setOnlyChange(v);
|
|
1091
845
|
}
|
|
1092
|
-
|
|
1093
|
-
|
|
1094
|
-
|
|
1095
|
-
|
|
1096
|
-
|
|
1097
|
-
|
|
1098
|
-
|
|
846
|
+
const newOnSelect = useMemo(() => {
|
|
847
|
+
return async (val) => {
|
|
848
|
+
const res = await onSelect(val);
|
|
849
|
+
setFileContent(res.fileContent || "");
|
|
850
|
+
setFileCoverage(res.fileCoverage || {});
|
|
851
|
+
setFileCodeChange(res.fileCodeChange || "");
|
|
852
|
+
return res;
|
|
853
|
+
};
|
|
854
|
+
}, [onSelect]);
|
|
1099
855
|
useEffect(() => {
|
|
1100
856
|
newOnSelect(value);
|
|
1101
|
-
}, []);
|
|
857
|
+
}, [newOnSelect, value]);
|
|
1102
858
|
const isFile = useMemo(() => {
|
|
1103
859
|
return /\.(js|jsx|ts|tsx|vue)$/.test(value);
|
|
1104
860
|
}, [value]);
|
|
1105
861
|
const mode = useMemo(() => {
|
|
1106
862
|
if (isFile) return "file";
|
|
1107
863
|
return showMode;
|
|
1108
|
-
}, [showMode,
|
|
864
|
+
}, [showMode, isFile]);
|
|
1109
865
|
const isFileDataReady = useMemo(() => {
|
|
1110
866
|
const hasCoverage = fileCoverage && Object.keys(fileCoverage).length > 0;
|
|
1111
867
|
const hasContent = fileContent.length > 0;
|
|
@@ -1171,9 +927,9 @@ const CanyonReport = ({ value, name, dataSource, onSelect }) => {
|
|
|
1171
927
|
children: /* @__PURE__ */ jsx(RIf_default, {
|
|
1172
928
|
condition: isFileDataReady,
|
|
1173
929
|
children: /* @__PURE__ */ jsx(CoverageDetail_default, {
|
|
1174
|
-
fileContent,
|
|
1175
|
-
fileCoverage,
|
|
1176
|
-
fileCodeChange
|
|
930
|
+
source: fileContent,
|
|
931
|
+
coverage: fileCoverage,
|
|
932
|
+
diff: fileCodeChange
|
|
1177
933
|
})
|
|
1178
934
|
})
|
|
1179
935
|
})
|
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.16",
|
|
5
5
|
"author": "Travis Zhang<https://github.com/travzhang>",
|
|
6
6
|
"repository": {
|
|
7
7
|
"type": "git",
|
|
@@ -14,7 +14,8 @@
|
|
|
14
14
|
"license": "MIT",
|
|
15
15
|
"exports": {
|
|
16
16
|
".": "./dist/index.js",
|
|
17
|
-
"./package.json": "./package.json"
|
|
17
|
+
"./package.json": "./package.json",
|
|
18
|
+
"./style.css": "./dist/style.css"
|
|
18
19
|
},
|
|
19
20
|
"main": "./dist/index.js",
|
|
20
21
|
"module": "./dist/index.js",
|
|
@@ -22,9 +23,6 @@
|
|
|
22
23
|
"files": [
|
|
23
24
|
"dist"
|
|
24
25
|
],
|
|
25
|
-
"publishConfig": {
|
|
26
|
-
"access": "public"
|
|
27
|
-
},
|
|
28
26
|
"peerDependencies": {
|
|
29
27
|
"react": "^19.2.0",
|
|
30
28
|
"react-dom": "^19.2.0"
|
|
@@ -38,8 +36,8 @@
|
|
|
38
36
|
"@vitejs/plugin-react": "^5.1.1",
|
|
39
37
|
"istanbul-lib-coverage": "^3.2.2",
|
|
40
38
|
"tsdown": "^0.17.0",
|
|
41
|
-
"typescript": "^
|
|
42
|
-
"vite": "
|
|
39
|
+
"@typescript/native-preview": "^7.0.0-dev.20251215.1",
|
|
40
|
+
"vite": "8.0.0-beta.0"
|
|
43
41
|
},
|
|
44
42
|
"dependencies": {
|
|
45
43
|
"@ant-design/icons": "^6.1.0",
|
|
@@ -54,7 +52,6 @@
|
|
|
54
52
|
"build": "tsdown",
|
|
55
53
|
"dev": "tsdown --watch",
|
|
56
54
|
"play": "vite",
|
|
57
|
-
"
|
|
58
|
-
"typecheck": "tsc --noEmit"
|
|
55
|
+
"typecheck": "tsgo --noEmit"
|
|
59
56
|
}
|
|
60
57
|
}
|