@ng-prism/plugin-coverage 21.11.0 → 21.12.0-beta.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +11 -0
- package/dist/coverage-header-badge.component.d.ts +14 -0
- package/dist/coverage-header-badge.component.d.ts.map +1 -0
- package/dist/coverage-header-badge.component.js +72 -0
- package/dist/coverage-panel.component.d.ts +2 -1
- package/dist/coverage-panel.component.d.ts.map +1 -1
- package/dist/coverage-panel.component.js +18 -9
- package/dist/coverage-plugin.browser.d.ts.map +1 -1
- package/dist/coverage-plugin.browser.js +8 -0
- package/dist/coverage-plugin.d.ts +3 -1
- package/dist/coverage-plugin.d.ts.map +1 -1
- package/dist/coverage-plugin.js +38 -1
- package/dist/coverage-reader.d.ts +3 -1
- package/dist/coverage-reader.d.ts.map +1 -1
- package/dist/coverage-reader.js +20 -0
- package/dist/coverage.types.d.ts +13 -0
- package/dist/coverage.types.d.ts.map +1 -1
- package/dist/index.browser.d.ts +2 -1
- package/dist/index.browser.d.ts.map +1 -1
- package/dist/index.browser.js +1 -0
- package/dist/index.d.ts +2 -1
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +1 -0
- package/package.json +2 -2
package/README.md
CHANGED
|
@@ -46,6 +46,17 @@ export default defineConfig({
|
|
|
46
46
|
| Option | Default | Description |
|
|
47
47
|
|---|---|---|
|
|
48
48
|
| `coveragePath` | `'coverage/coverage-summary.json'` | Path to the Istanbul coverage summary file (relative to workspace root) |
|
|
49
|
+
| `thresholds` | `80` for all metrics | Minimum acceptable percentage per metric. Files below the threshold are highlighted in red in the per-file table. Number → applied to all metrics; partial object → keys you omit fall back to `80`. |
|
|
50
|
+
|
|
51
|
+
```typescript
|
|
52
|
+
// Single value — applied to lines, branches, functions, statements
|
|
53
|
+
coveragePlugin({ thresholds: 90 });
|
|
54
|
+
|
|
55
|
+
// Per-metric — others fall back to 80
|
|
56
|
+
coveragePlugin({
|
|
57
|
+
thresholds: { lines: 95, branches: 70 },
|
|
58
|
+
});
|
|
59
|
+
```
|
|
49
60
|
|
|
50
61
|
## Example
|
|
51
62
|
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
import * as i0 from "@angular/core";
|
|
2
|
+
type Variant = 'ok' | 'warn' | 'danger';
|
|
3
|
+
export declare class CoverageHeaderBadgeComponent {
|
|
4
|
+
private readonly manifest;
|
|
5
|
+
protected readonly data: import("@angular/core").Signal<{
|
|
6
|
+
score: number;
|
|
7
|
+
variant: Variant;
|
|
8
|
+
title: string;
|
|
9
|
+
} | null>;
|
|
10
|
+
static ɵfac: i0.ɵɵFactoryDeclaration<CoverageHeaderBadgeComponent, never>;
|
|
11
|
+
static ɵcmp: i0.ɵɵComponentDeclaration<CoverageHeaderBadgeComponent, "prism-coverage-header-badge", never, {}, {}, never, never, true, never>;
|
|
12
|
+
}
|
|
13
|
+
export {};
|
|
14
|
+
//# sourceMappingURL=coverage-header-badge.component.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"coverage-header-badge.component.d.ts","sourceRoot":"","sources":["../src/coverage-header-badge.component.ts"],"names":[],"mappings":";AAUA,KAAK,OAAO,GAAG,IAAI,GAAG,MAAM,GAAG,QAAQ,CAAC;AAExC,qBAqFa,4BAA4B;IACvC,OAAO,CAAC,QAAQ,CAAC,QAAQ,CAA2C;IAEpE,SAAS,CAAC,QAAQ,CAAC,IAAI;;;;cA6BpB;yCAhCQ,4BAA4B;2CAA5B,4BAA4B;CAiCxC"}
|
|
@@ -0,0 +1,72 @@
|
|
|
1
|
+
import { ChangeDetectionStrategy, Component, computed, inject, } from '@angular/core';
|
|
2
|
+
import { PRISM_MANIFEST } from '@ng-prism/core/plugin';
|
|
3
|
+
import * as i0 from "@angular/core";
|
|
4
|
+
function CoverageHeaderBadgeComponent_Conditional_0_Template(rf, ctx) { if (rf & 1) {
|
|
5
|
+
i0.ɵɵdomElementStart(0, "span", 1);
|
|
6
|
+
i0.ɵɵdomElement(1, "span", 2);
|
|
7
|
+
i0.ɵɵdomElementStart(2, "span", 3);
|
|
8
|
+
i0.ɵɵtext(3, "Coverage");
|
|
9
|
+
i0.ɵɵdomElementEnd();
|
|
10
|
+
i0.ɵɵdomElementStart(4, "span", 4);
|
|
11
|
+
i0.ɵɵtext(5);
|
|
12
|
+
i0.ɵɵdomElementStart(6, "small");
|
|
13
|
+
i0.ɵɵtext(7, "%");
|
|
14
|
+
i0.ɵɵdomElementEnd()()();
|
|
15
|
+
} if (rf & 2) {
|
|
16
|
+
const d_r1 = ctx;
|
|
17
|
+
i0.ɵɵclassProp("cov-pill--ok", d_r1.variant === "ok")("cov-pill--warn", d_r1.variant === "warn")("cov-pill--danger", d_r1.variant === "danger");
|
|
18
|
+
i0.ɵɵdomProperty("title", d_r1.title);
|
|
19
|
+
i0.ɵɵadvance(5);
|
|
20
|
+
i0.ɵɵtextInterpolate(d_r1.score);
|
|
21
|
+
} }
|
|
22
|
+
export class CoverageHeaderBadgeComponent {
|
|
23
|
+
manifest = inject(PRISM_MANIFEST);
|
|
24
|
+
data = computed(() => {
|
|
25
|
+
const meta = this.manifest.meta?.['coverage'];
|
|
26
|
+
if (!meta?.total?.found)
|
|
27
|
+
return null;
|
|
28
|
+
const score = meta.total.score;
|
|
29
|
+
const t = meta.thresholds;
|
|
30
|
+
const avgThreshold = Math.round((t.lines + t.branches + t.functions + t.statements) / 4);
|
|
31
|
+
const variant = score >= avgThreshold
|
|
32
|
+
? 'ok'
|
|
33
|
+
: score >= avgThreshold * 0.75
|
|
34
|
+
? 'warn'
|
|
35
|
+
: 'danger';
|
|
36
|
+
return {
|
|
37
|
+
score,
|
|
38
|
+
variant,
|
|
39
|
+
title: `Library coverage: ${score}% (target ${avgThreshold}%)\n` +
|
|
40
|
+
`Lines ${meta.total.lines.pct}% · ` +
|
|
41
|
+
`Branches ${meta.total.branches.pct}% · ` +
|
|
42
|
+
`Functions ${meta.total.functions.pct}% · ` +
|
|
43
|
+
`Statements ${meta.total.statements.pct}%`,
|
|
44
|
+
};
|
|
45
|
+
}, ...(ngDevMode ? [{ debugName: "data" }] : []));
|
|
46
|
+
static ɵfac = function CoverageHeaderBadgeComponent_Factory(__ngFactoryType__) { return new (__ngFactoryType__ || CoverageHeaderBadgeComponent)(); };
|
|
47
|
+
static ɵcmp = /*@__PURE__*/ i0.ɵɵdefineComponent({ type: CoverageHeaderBadgeComponent, selectors: [["prism-coverage-header-badge"]], decls: 1, vars: 1, consts: [[1, "cov-pill", 3, "cov-pill--ok", "cov-pill--warn", "cov-pill--danger", "title"], [1, "cov-pill", 3, "title"], [1, "cov-pill__dot"], [1, "cov-pill__label"], [1, "cov-pill__value"]], template: function CoverageHeaderBadgeComponent_Template(rf, ctx) { if (rf & 1) {
|
|
48
|
+
i0.ɵɵconditionalCreate(0, CoverageHeaderBadgeComponent_Conditional_0_Template, 8, 8, "span", 0);
|
|
49
|
+
} if (rf & 2) {
|
|
50
|
+
let tmp_0_0;
|
|
51
|
+
i0.ɵɵconditional((tmp_0_0 = ctx.data()) ? 0 : -1, tmp_0_0);
|
|
52
|
+
} }, styles: ["[_nghost-%COMP%] { display: inline-flex; align-items: center; }\n\n .cov-pill[_ngcontent-%COMP%] {\n display: inline-flex;\n align-items: center;\n gap: 6px;\n font-family: var(--font-mono);\n font-size: var(--fs-xs);\n padding: 2px 10px;\n border-radius: 9999px;\n line-height: 1.4;\n border: 1px solid var(--prism-border);\n background: var(--prism-input-bg);\n color: var(--prism-text-muted);\n white-space: nowrap;\n }\n\n .cov-pill__dot[_ngcontent-%COMP%] {\n width: 6px;\n height: 6px;\n border-radius: 50%;\n background: currentColor;\n }\n\n .cov-pill__label[_ngcontent-%COMP%] {\n color: var(--prism-text-ghost);\n letter-spacing: 0.02em;\n }\n\n .cov-pill__value[_ngcontent-%COMP%] {\n color: var(--prism-text);\n font-weight: 600;\n }\n .cov-pill__value[_ngcontent-%COMP%] small[_ngcontent-%COMP%] {\n font-size: 9px;\n margin-left: 1px;\n color: var(--prism-text-muted);\n font-weight: 500;\n }\n\n .cov-pill--ok[_ngcontent-%COMP%] {\n color: var(--prism-success);\n border-color: color-mix(in srgb, var(--prism-success) 35%, transparent);\n background: color-mix(in srgb, var(--prism-success) 12%, transparent);\n }\n .cov-pill--ok[_ngcontent-%COMP%] .cov-pill__label[_ngcontent-%COMP%], \n .cov-pill--ok[_ngcontent-%COMP%] .cov-pill__value[_ngcontent-%COMP%] { color: var(--prism-success); }\n\n .cov-pill--warn[_ngcontent-%COMP%] {\n color: var(--prism-warn);\n border-color: color-mix(in srgb, var(--prism-warn) 35%, transparent);\n background: color-mix(in srgb, var(--prism-warn) 12%, transparent);\n }\n .cov-pill--warn[_ngcontent-%COMP%] .cov-pill__label[_ngcontent-%COMP%], \n .cov-pill--warn[_ngcontent-%COMP%] .cov-pill__value[_ngcontent-%COMP%] { color: var(--prism-warn); }\n\n .cov-pill--danger[_ngcontent-%COMP%] {\n color: var(--prism-danger);\n border-color: color-mix(in srgb, var(--prism-danger) 35%, transparent);\n background: color-mix(in srgb, var(--prism-danger) 12%, transparent);\n }\n .cov-pill--danger[_ngcontent-%COMP%] .cov-pill__label[_ngcontent-%COMP%], \n .cov-pill--danger[_ngcontent-%COMP%] .cov-pill__value[_ngcontent-%COMP%] { color: var(--prism-danger); }"], changeDetection: 0 });
|
|
53
|
+
}
|
|
54
|
+
(() => { (typeof ngDevMode === "undefined" || ngDevMode) && i0.ɵsetClassMetadata(CoverageHeaderBadgeComponent, [{
|
|
55
|
+
type: Component,
|
|
56
|
+
args: [{ selector: 'prism-coverage-header-badge', standalone: true, changeDetection: ChangeDetectionStrategy.OnPush, template: `
|
|
57
|
+
@if (data(); as d) {
|
|
58
|
+
<span
|
|
59
|
+
class="cov-pill"
|
|
60
|
+
[class.cov-pill--ok]="d.variant === 'ok'"
|
|
61
|
+
[class.cov-pill--warn]="d.variant === 'warn'"
|
|
62
|
+
[class.cov-pill--danger]="d.variant === 'danger'"
|
|
63
|
+
[title]="d.title"
|
|
64
|
+
>
|
|
65
|
+
<span class="cov-pill__dot"></span>
|
|
66
|
+
<span class="cov-pill__label">Coverage</span>
|
|
67
|
+
<span class="cov-pill__value">{{ d.score }}<small>%</small></span>
|
|
68
|
+
</span>
|
|
69
|
+
}
|
|
70
|
+
`, styles: ["\n :host { display: inline-flex; align-items: center; }\n\n .cov-pill {\n display: inline-flex;\n align-items: center;\n gap: 6px;\n font-family: var(--font-mono);\n font-size: var(--fs-xs);\n padding: 2px 10px;\n border-radius: 9999px;\n line-height: 1.4;\n border: 1px solid var(--prism-border);\n background: var(--prism-input-bg);\n color: var(--prism-text-muted);\n white-space: nowrap;\n }\n\n .cov-pill__dot {\n width: 6px;\n height: 6px;\n border-radius: 50%;\n background: currentColor;\n }\n\n .cov-pill__label {\n color: var(--prism-text-ghost);\n letter-spacing: 0.02em;\n }\n\n .cov-pill__value {\n color: var(--prism-text);\n font-weight: 600;\n }\n .cov-pill__value small {\n font-size: 9px;\n margin-left: 1px;\n color: var(--prism-text-muted);\n font-weight: 500;\n }\n\n .cov-pill--ok {\n color: var(--prism-success);\n border-color: color-mix(in srgb, var(--prism-success) 35%, transparent);\n background: color-mix(in srgb, var(--prism-success) 12%, transparent);\n }\n .cov-pill--ok .cov-pill__label,\n .cov-pill--ok .cov-pill__value { color: var(--prism-success); }\n\n .cov-pill--warn {\n color: var(--prism-warn);\n border-color: color-mix(in srgb, var(--prism-warn) 35%, transparent);\n background: color-mix(in srgb, var(--prism-warn) 12%, transparent);\n }\n .cov-pill--warn .cov-pill__label,\n .cov-pill--warn .cov-pill__value { color: var(--prism-warn); }\n\n .cov-pill--danger {\n color: var(--prism-danger);\n border-color: color-mix(in srgb, var(--prism-danger) 35%, transparent);\n background: color-mix(in srgb, var(--prism-danger) 12%, transparent);\n }\n .cov-pill--danger .cov-pill__label,\n .cov-pill--danger .cov-pill__value { color: var(--prism-danger); }\n "] }]
|
|
71
|
+
}], null, null); })();
|
|
72
|
+
(() => { (typeof ngDevMode === "undefined" || ngDevMode) && i0.ɵsetClassDebugInfo(CoverageHeaderBadgeComponent, { className: "CoverageHeaderBadgeComponent", filePath: "coverage-header-badge.component.ts", lineNumber: 98 }); })();
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import type { CoverageData, FileCoverageDetail } from './coverage.types.js';
|
|
1
|
+
import type { CoverageData, CoverageThresholds, FileCoverageDetail } from './coverage.types.js';
|
|
2
2
|
import * as i0 from "@angular/core";
|
|
3
3
|
export declare class CoveragePanelComponent {
|
|
4
4
|
readonly activeComponent: import("@angular/core").InputSignal<unknown>;
|
|
@@ -8,6 +8,7 @@ export declare class CoveragePanelComponent {
|
|
|
8
8
|
pct: number;
|
|
9
9
|
}[]>;
|
|
10
10
|
protected readonly files: import("@angular/core").Signal<FileCoverageDetail[]>;
|
|
11
|
+
protected readonly thresholds: import("@angular/core").Signal<CoverageThresholds>;
|
|
11
12
|
protected fileName(path: string): string;
|
|
12
13
|
static ɵfac: i0.ɵɵFactoryDeclaration<CoveragePanelComponent, never>;
|
|
13
14
|
static ɵcmp: i0.ɵɵComponentDeclaration<CoveragePanelComponent, "prism-coverage-panel", never, { "activeComponent": { "alias": "activeComponent"; "required": false; "isSignal": true; }; }, {}, never, never, true, never>;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"coverage-panel.component.d.ts","sourceRoot":"","sources":["../src/coverage-panel.component.ts"],"names":[],"mappings":"AAMA,OAAO,KAAK,
|
|
1
|
+
{"version":3,"file":"coverage-panel.component.d.ts","sourceRoot":"","sources":["../src/coverage-panel.component.ts"],"names":[],"mappings":"AAMA,OAAO,KAAK,EACV,YAAY,EACZ,kBAAkB,EAClB,kBAAkB,EACnB,MAAM,qBAAqB,CAAC;;AAS7B,qBA0Ja,sBAAsB;IACjC,QAAQ,CAAC,eAAe,+CAAwB;IAEhD,SAAS,CAAC,QAAQ,CAAC,QAAQ,sDAKxB;IAEH,SAAS,CAAC,QAAQ,CAAC,YAAY;;;SAS5B;IAEH,SAAS,CAAC,QAAQ,CAAC,KAAK,uDAErB;IAEH,SAAS,CAAC,QAAQ,CAAC,UAAU,qDAE1B;IAEH,SAAS,CAAC,QAAQ,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM;yCA7B7B,sBAAsB;2CAAtB,sBAAsB;CAiClC"}
|
|
@@ -45,19 +45,19 @@ function CoveragePanelComponent_Conditional_0_Conditional_4_For_13_Template(rf,
|
|
|
45
45
|
i0.ɵɵadvance(2);
|
|
46
46
|
i0.ɵɵtextInterpolate(ctx_r2.fileName(file_r2.path));
|
|
47
47
|
i0.ɵɵadvance();
|
|
48
|
-
i0.ɵɵclassProp("bad", file_r2.lines.pct <
|
|
48
|
+
i0.ɵɵclassProp("bad", file_r2.lines.pct < ctx_r2.thresholds().lines);
|
|
49
49
|
i0.ɵɵadvance();
|
|
50
50
|
i0.ɵɵtextInterpolate1("", file_r2.lines.pct, "%");
|
|
51
51
|
i0.ɵɵadvance();
|
|
52
|
-
i0.ɵɵclassProp("bad", file_r2.branches.pct <
|
|
52
|
+
i0.ɵɵclassProp("bad", file_r2.branches.pct < ctx_r2.thresholds().branches);
|
|
53
53
|
i0.ɵɵadvance();
|
|
54
54
|
i0.ɵɵtextInterpolate1("", file_r2.branches.pct, "%");
|
|
55
55
|
i0.ɵɵadvance();
|
|
56
|
-
i0.ɵɵclassProp("bad", file_r2.functions.pct <
|
|
56
|
+
i0.ɵɵclassProp("bad", file_r2.functions.pct < ctx_r2.thresholds().functions);
|
|
57
57
|
i0.ɵɵadvance();
|
|
58
58
|
i0.ɵɵtextInterpolate1("", file_r2.functions.pct, "%");
|
|
59
59
|
i0.ɵɵadvance();
|
|
60
|
-
i0.ɵɵclassProp("bad", file_r2.statements.pct <
|
|
60
|
+
i0.ɵɵclassProp("bad", file_r2.statements.pct < ctx_r2.thresholds().statements);
|
|
61
61
|
i0.ɵɵadvance();
|
|
62
62
|
i0.ɵɵtextInterpolate1("", file_r2.statements.pct, "%");
|
|
63
63
|
} }
|
|
@@ -102,6 +102,12 @@ function CoveragePanelComponent_Conditional_1_Template(rf, ctx) { if (rf & 1) {
|
|
|
102
102
|
i0.ɵɵtext(2, "No coverage data. Run tests with coverage enabled.");
|
|
103
103
|
i0.ɵɵdomElementEnd()();
|
|
104
104
|
} }
|
|
105
|
+
const FALLBACK_THRESHOLDS = {
|
|
106
|
+
lines: 80,
|
|
107
|
+
branches: 80,
|
|
108
|
+
functions: 80,
|
|
109
|
+
statements: 80,
|
|
110
|
+
};
|
|
105
111
|
export class CoveragePanelComponent {
|
|
106
112
|
activeComponent = input(null, ...(ngDevMode ? [{ debugName: "activeComponent" }] : []));
|
|
107
113
|
coverage = computed(() => {
|
|
@@ -122,6 +128,9 @@ export class CoveragePanelComponent {
|
|
|
122
128
|
files = computed(() => {
|
|
123
129
|
return this.coverage()?.files ?? [];
|
|
124
130
|
}, ...(ngDevMode ? [{ debugName: "files" }] : []));
|
|
131
|
+
thresholds = computed(() => {
|
|
132
|
+
return this.coverage()?.thresholds ?? FALLBACK_THRESHOLDS;
|
|
133
|
+
}, ...(ngDevMode ? [{ debugName: "thresholds" }] : []));
|
|
125
134
|
fileName(path) {
|
|
126
135
|
const parts = path.split('/');
|
|
127
136
|
return parts[parts.length - 1];
|
|
@@ -163,16 +172,16 @@ export class CoveragePanelComponent {
|
|
|
163
172
|
@for (file of files(); track file.path) {
|
|
164
173
|
<div class="cov-file">
|
|
165
174
|
<span class="cov-file-name">{{ fileName(file.path) }}</span>
|
|
166
|
-
<span class="cov-file-val" [class.bad]="file.lines.pct <
|
|
175
|
+
<span class="cov-file-val" [class.bad]="file.lines.pct < thresholds().lines"
|
|
167
176
|
>{{ file.lines.pct }}%</span
|
|
168
177
|
>
|
|
169
|
-
<span class="cov-file-val" [class.bad]="file.branches.pct <
|
|
178
|
+
<span class="cov-file-val" [class.bad]="file.branches.pct < thresholds().branches"
|
|
170
179
|
>{{ file.branches.pct }}%</span
|
|
171
180
|
>
|
|
172
|
-
<span class="cov-file-val" [class.bad]="file.functions.pct <
|
|
181
|
+
<span class="cov-file-val" [class.bad]="file.functions.pct < thresholds().functions"
|
|
173
182
|
>{{ file.functions.pct }}%</span
|
|
174
183
|
>
|
|
175
|
-
<span class="cov-file-val" [class.bad]="file.statements.pct <
|
|
184
|
+
<span class="cov-file-val" [class.bad]="file.statements.pct < thresholds().statements"
|
|
176
185
|
>{{ file.statements.pct }}%</span
|
|
177
186
|
>
|
|
178
187
|
</div>
|
|
@@ -187,4 +196,4 @@ export class CoveragePanelComponent {
|
|
|
187
196
|
}
|
|
188
197
|
`, styles: ["\n :host { display: block; height: 100%; overflow: auto; }\n\n .cov-body { padding: 20px 24px; }\n\n .cov-summary {\n display: grid;\n grid-template-columns: repeat(4, 1fr);\n gap: 12px;\n margin-bottom: 18px;\n }\n\n .cov-stat {\n padding: 12px 14px;\n background: var(--prism-bg-surface);\n border: 1px solid var(--prism-border);\n border-radius: 8px;\n }\n .cov-stat-k {\n font-size: 10.5px;\n text-transform: uppercase;\n letter-spacing: 0.08em;\n color: var(--prism-text-ghost);\n font-weight: 700;\n margin-bottom: 6px;\n }\n .cov-stat-v {\n font-family: var(--font-mono);\n font-size: 22px;\n font-weight: 700;\n color: var(--prism-text);\n letter-spacing: -0.02em;\n }\n .cov-stat-v small {\n font-size: 13px;\n color: var(--prism-text-muted);\n font-weight: 500;\n }\n .cov-bar {\n margin-top: 8px;\n height: 4px;\n background: var(--prism-input-bg);\n border-radius: 2px;\n overflow: hidden;\n }\n .cov-bar-fill {\n height: 100%;\n background: linear-gradient(90deg, var(--prism-primary-from), var(--prism-primary-to));\n border-radius: 2px;\n transition: width 0.6s;\n }\n\n .cov-files {\n padding: 12px;\n background: var(--prism-bg-surface);\n border: 1px solid var(--prism-border);\n border-radius: 8px;\n }\n\n .cov-file {\n display: grid;\n grid-template-columns: 1fr auto auto auto auto;\n align-items: center;\n gap: 16px;\n padding: 7px 4px;\n font-family: var(--font-mono);\n font-size: 12px;\n border-bottom: 1px solid var(--prism-border);\n }\n .cov-file:last-child { border-bottom: 0; }\n\n .cov-file--header {\n border-bottom: 1px solid var(--prism-border-strong);\n padding-bottom: 8px;\n color: var(--prism-text-ghost);\n font-size: 10.5px;\n text-transform: uppercase;\n letter-spacing: 0.06em;\n font-weight: 700;\n }\n\n .cov-file-name { color: var(--prism-text-2); }\n .cov-file-val {\n color: var(--prism-text);\n min-width: 54px;\n text-align: right;\n }\n .cov-file-val.bad { color: var(--prism-warn); }\n\n .cov-empty {\n display: flex;\n align-items: center;\n justify-content: center;\n min-height: 120px;\n color: var(--prism-text-muted);\n font-size: 13px;\n text-align: center;\n }\n "] }]
|
|
189
198
|
}], null, { activeComponent: [{ type: i0.Input, args: [{ isSignal: true, alias: "activeComponent", required: false }] }] }); })();
|
|
190
|
-
(() => { (typeof ngDevMode === "undefined" || ngDevMode) && i0.ɵsetClassDebugInfo(CoveragePanelComponent, { className: "CoveragePanelComponent", filePath: "coverage-panel.component.ts", lineNumber:
|
|
199
|
+
(() => { (typeof ngDevMode === "undefined" || ngDevMode) && i0.ɵsetClassDebugInfo(CoveragePanelComponent, { className: "CoveragePanelComponent", filePath: "coverage-panel.component.ts", lineNumber: 174 }); })();
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"coverage-plugin.browser.d.ts","sourceRoot":"","sources":["../src/coverage-plugin.browser.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,uBAAuB,CAAC;AAC3D,OAAO,KAAK,EAAE,qBAAqB,EAAE,MAAM,qBAAqB,CAAC;AAEjE,wBAAgB,cAAc,CAC5B,QAAQ,CAAC,EAAE,qBAAqB,GAC/B,aAAa,
|
|
1
|
+
{"version":3,"file":"coverage-plugin.browser.d.ts","sourceRoot":"","sources":["../src/coverage-plugin.browser.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,uBAAuB,CAAC;AAC3D,OAAO,KAAK,EAAE,qBAAqB,EAAE,MAAM,qBAAqB,CAAC;AAEjE,wBAAgB,cAAc,CAC5B,QAAQ,CAAC,EAAE,qBAAqB,GAC/B,aAAa,CA2Bf"}
|
|
@@ -10,5 +10,13 @@ export function coveragePlugin(_options) {
|
|
|
10
10
|
position: 'bottom',
|
|
11
11
|
},
|
|
12
12
|
],
|
|
13
|
+
headerWidgets: [
|
|
14
|
+
{
|
|
15
|
+
id: 'coverage-total',
|
|
16
|
+
placement: 'end',
|
|
17
|
+
order: -10,
|
|
18
|
+
loadComponent: () => import('./coverage-header-badge.component.js').then((m) => m.CoverageHeaderBadgeComponent),
|
|
19
|
+
},
|
|
20
|
+
],
|
|
13
21
|
};
|
|
14
22
|
}
|
|
@@ -1,4 +1,6 @@
|
|
|
1
1
|
import type { NgPrismPlugin } from '@ng-prism/core/plugin';
|
|
2
|
-
import type { CoveragePluginOptions } from './coverage.types.js';
|
|
2
|
+
import type { CoveragePluginOptions, CoverageThresholds } from './coverage.types.js';
|
|
3
|
+
export declare const DEFAULT_COVERAGE_THRESHOLDS: CoverageThresholds;
|
|
4
|
+
export declare function resolveCoverageThresholds(input?: number | Partial<CoverageThresholds>): CoverageThresholds;
|
|
3
5
|
export declare function coveragePlugin(options?: CoveragePluginOptions): NgPrismPlugin;
|
|
4
6
|
//# sourceMappingURL=coverage-plugin.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"coverage-plugin.d.ts","sourceRoot":"","sources":["../src/coverage-plugin.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,uBAAuB,CAAC;AAC3D,OAAO,KAAK,EAAE,qBAAqB,EAAE,MAAM,qBAAqB,CAAC;
|
|
1
|
+
{"version":3,"file":"coverage-plugin.d.ts","sourceRoot":"","sources":["../src/coverage-plugin.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,uBAAuB,CAAC;AAC3D,OAAO,KAAK,EAAE,qBAAqB,EAAE,kBAAkB,EAAE,MAAM,qBAAqB,CAAC;AAIrF,eAAO,MAAM,2BAA2B,EAAE,kBAKzC,CAAC;AAEF,wBAAgB,yBAAyB,CACvC,KAAK,CAAC,EAAE,MAAM,GAAG,OAAO,CAAC,kBAAkB,CAAC,GAC3C,kBAAkB,CAMpB;AAED,wBAAgB,cAAc,CAAC,OAAO,CAAC,EAAE,qBAAqB,GAAG,aAAa,CAoD7E"}
|
package/dist/coverage-plugin.js
CHANGED
|
@@ -1,6 +1,21 @@
|
|
|
1
1
|
const DEFAULT_COVERAGE_PATH = 'coverage/coverage-summary.json';
|
|
2
|
+
export const DEFAULT_COVERAGE_THRESHOLDS = {
|
|
3
|
+
lines: 80,
|
|
4
|
+
branches: 80,
|
|
5
|
+
functions: 80,
|
|
6
|
+
statements: 80,
|
|
7
|
+
};
|
|
8
|
+
export function resolveCoverageThresholds(input) {
|
|
9
|
+
if (input === undefined)
|
|
10
|
+
return { ...DEFAULT_COVERAGE_THRESHOLDS };
|
|
11
|
+
if (typeof input === 'number') {
|
|
12
|
+
return { lines: input, branches: input, functions: input, statements: input };
|
|
13
|
+
}
|
|
14
|
+
return { ...DEFAULT_COVERAGE_THRESHOLDS, ...input };
|
|
15
|
+
}
|
|
2
16
|
export function coveragePlugin(options) {
|
|
3
17
|
const coveragePath = options?.coveragePath ?? DEFAULT_COVERAGE_PATH;
|
|
18
|
+
const thresholds = resolveCoverageThresholds(options?.thresholds);
|
|
4
19
|
return {
|
|
5
20
|
name: '@ng-prism/plugin-coverage',
|
|
6
21
|
async onComponentScanned(component) {
|
|
@@ -10,7 +25,21 @@ export function coveragePlugin(options) {
|
|
|
10
25
|
...component,
|
|
11
26
|
showcaseConfig: {
|
|
12
27
|
...component.showcaseConfig,
|
|
13
|
-
meta: {
|
|
28
|
+
meta: {
|
|
29
|
+
...component.showcaseConfig.meta,
|
|
30
|
+
coverage: { ...coverage, thresholds },
|
|
31
|
+
},
|
|
32
|
+
},
|
|
33
|
+
};
|
|
34
|
+
},
|
|
35
|
+
async onManifestReady(manifest) {
|
|
36
|
+
const { readTotalCoverage } = await import('./coverage-reader.js');
|
|
37
|
+
const total = readTotalCoverage(coveragePath);
|
|
38
|
+
return {
|
|
39
|
+
...manifest,
|
|
40
|
+
meta: {
|
|
41
|
+
...manifest.meta,
|
|
42
|
+
coverage: { total, thresholds },
|
|
14
43
|
},
|
|
15
44
|
};
|
|
16
45
|
},
|
|
@@ -22,5 +51,13 @@ export function coveragePlugin(options) {
|
|
|
22
51
|
position: 'bottom',
|
|
23
52
|
},
|
|
24
53
|
],
|
|
54
|
+
headerWidgets: [
|
|
55
|
+
{
|
|
56
|
+
id: 'coverage-total',
|
|
57
|
+
placement: 'end',
|
|
58
|
+
order: -10,
|
|
59
|
+
loadComponent: () => import('./coverage-header-badge.component.js').then((m) => m.CoverageHeaderBadgeComponent),
|
|
60
|
+
},
|
|
61
|
+
],
|
|
25
62
|
};
|
|
26
63
|
}
|
|
@@ -1,4 +1,6 @@
|
|
|
1
|
-
import type { CoverageData } from './coverage.types.js';
|
|
1
|
+
import type { CoverageData, CoverageThresholds } from './coverage.types.js';
|
|
2
2
|
export declare function readCoverageForFile(coveragePath: string, componentFilePath: string): CoverageData;
|
|
3
|
+
export declare function readTotalCoverage(coveragePath: string): CoverageData;
|
|
4
|
+
export declare function averageThreshold(thresholds: CoverageThresholds): number;
|
|
3
5
|
export declare function clearCoverageCache(): void;
|
|
4
6
|
//# sourceMappingURL=coverage-reader.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"coverage-reader.d.ts","sourceRoot":"","sources":["../src/coverage-reader.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,
|
|
1
|
+
{"version":3,"file":"coverage-reader.d.ts","sourceRoot":"","sources":["../src/coverage-reader.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EACV,YAAY,EACZ,kBAAkB,EAEnB,MAAM,qBAAqB,CAAC;AA6D7B,wBAAgB,mBAAmB,CAAC,YAAY,EAAE,MAAM,EAAE,iBAAiB,EAAE,MAAM,GAAG,YAAY,CAoBjG;AAED,wBAAgB,iBAAiB,CAAC,YAAY,EAAE,MAAM,GAAG,YAAY,CAmBpE;AAED,wBAAgB,gBAAgB,CAAC,UAAU,EAAE,kBAAkB,GAAG,MAAM,CAIvE;AAED,wBAAgB,kBAAkB,IAAI,IAAI,CAEzC"}
|
package/dist/coverage-reader.js
CHANGED
|
@@ -67,6 +67,26 @@ export function readCoverageForFile(coveragePath, componentFilePath) {
|
|
|
67
67
|
found: true,
|
|
68
68
|
};
|
|
69
69
|
}
|
|
70
|
+
export function readTotalCoverage(coveragePath) {
|
|
71
|
+
const summary = loadSummary(coveragePath);
|
|
72
|
+
if (!summary)
|
|
73
|
+
return { ...EMPTY_COVERAGE };
|
|
74
|
+
const total = summary['total'];
|
|
75
|
+
if (!total)
|
|
76
|
+
return { ...EMPTY_COVERAGE };
|
|
77
|
+
const score = Math.round((total.statements.pct + total.branches.pct + total.functions.pct + total.lines.pct) / 4);
|
|
78
|
+
return {
|
|
79
|
+
score,
|
|
80
|
+
statements: { ...total.statements },
|
|
81
|
+
branches: { ...total.branches },
|
|
82
|
+
functions: { ...total.functions },
|
|
83
|
+
lines: { ...total.lines },
|
|
84
|
+
found: true,
|
|
85
|
+
};
|
|
86
|
+
}
|
|
87
|
+
export function averageThreshold(thresholds) {
|
|
88
|
+
return Math.round((thresholds.lines + thresholds.branches + thresholds.functions + thresholds.statements) / 4);
|
|
89
|
+
}
|
|
70
90
|
export function clearCoverageCache() {
|
|
71
91
|
cache.clear();
|
|
72
92
|
}
|
package/dist/coverage.types.d.ts
CHANGED
|
@@ -11,6 +11,12 @@ export interface FileCoverageDetail {
|
|
|
11
11
|
functions: MetricDetail;
|
|
12
12
|
lines: MetricDetail;
|
|
13
13
|
}
|
|
14
|
+
export interface CoverageThresholds {
|
|
15
|
+
lines: number;
|
|
16
|
+
branches: number;
|
|
17
|
+
functions: number;
|
|
18
|
+
statements: number;
|
|
19
|
+
}
|
|
14
20
|
export interface CoverageData {
|
|
15
21
|
score: number;
|
|
16
22
|
statements: MetricDetail;
|
|
@@ -19,9 +25,16 @@ export interface CoverageData {
|
|
|
19
25
|
lines: MetricDetail;
|
|
20
26
|
found: boolean;
|
|
21
27
|
files?: FileCoverageDetail[];
|
|
28
|
+
thresholds?: CoverageThresholds;
|
|
22
29
|
}
|
|
23
30
|
export interface CoveragePluginOptions {
|
|
24
31
|
coveragePath?: string;
|
|
32
|
+
thresholds?: number | Partial<CoverageThresholds>;
|
|
33
|
+
}
|
|
34
|
+
/** Shape stored under `manifest.meta.coverage`. */
|
|
35
|
+
export interface CoverageManifestMeta {
|
|
36
|
+
total: CoverageData;
|
|
37
|
+
thresholds: CoverageThresholds;
|
|
25
38
|
}
|
|
26
39
|
export interface IstanbulFileCoverage {
|
|
27
40
|
statements: MetricDetail;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"coverage.types.d.ts","sourceRoot":"","sources":["../src/coverage.types.ts"],"names":[],"mappings":"AAAA,MAAM,WAAW,YAAY;IAC3B,KAAK,EAAE,MAAM,CAAC;IACd,OAAO,EAAE,MAAM,CAAC;IAChB,OAAO,EAAE,MAAM,CAAC;IAChB,GAAG,EAAE,MAAM,CAAC;CACb;AAED,MAAM,WAAW,kBAAkB;IACjC,IAAI,EAAE,MAAM,CAAC;IACb,UAAU,EAAE,YAAY,CAAC;IACzB,QAAQ,EAAE,YAAY,CAAC;IACvB,SAAS,EAAE,YAAY,CAAC;IACxB,KAAK,EAAE,YAAY,CAAC;CACrB;AAED,MAAM,WAAW,YAAY;IAC3B,KAAK,EAAE,MAAM,CAAC;IACd,UAAU,EAAE,YAAY,CAAC;IACzB,QAAQ,EAAE,YAAY,CAAC;IACvB,SAAS,EAAE,YAAY,CAAC;IACxB,KAAK,EAAE,YAAY,CAAC;IACpB,KAAK,EAAE,OAAO,CAAC;IACf,KAAK,CAAC,EAAE,kBAAkB,EAAE,CAAC;
|
|
1
|
+
{"version":3,"file":"coverage.types.d.ts","sourceRoot":"","sources":["../src/coverage.types.ts"],"names":[],"mappings":"AAAA,MAAM,WAAW,YAAY;IAC3B,KAAK,EAAE,MAAM,CAAC;IACd,OAAO,EAAE,MAAM,CAAC;IAChB,OAAO,EAAE,MAAM,CAAC;IAChB,GAAG,EAAE,MAAM,CAAC;CACb;AAED,MAAM,WAAW,kBAAkB;IACjC,IAAI,EAAE,MAAM,CAAC;IACb,UAAU,EAAE,YAAY,CAAC;IACzB,QAAQ,EAAE,YAAY,CAAC;IACvB,SAAS,EAAE,YAAY,CAAC;IACxB,KAAK,EAAE,YAAY,CAAC;CACrB;AAED,MAAM,WAAW,kBAAkB;IACjC,KAAK,EAAE,MAAM,CAAC;IACd,QAAQ,EAAE,MAAM,CAAC;IACjB,SAAS,EAAE,MAAM,CAAC;IAClB,UAAU,EAAE,MAAM,CAAC;CACpB;AAED,MAAM,WAAW,YAAY;IAC3B,KAAK,EAAE,MAAM,CAAC;IACd,UAAU,EAAE,YAAY,CAAC;IACzB,QAAQ,EAAE,YAAY,CAAC;IACvB,SAAS,EAAE,YAAY,CAAC;IACxB,KAAK,EAAE,YAAY,CAAC;IACpB,KAAK,EAAE,OAAO,CAAC;IACf,KAAK,CAAC,EAAE,kBAAkB,EAAE,CAAC;IAC7B,UAAU,CAAC,EAAE,kBAAkB,CAAC;CACjC;AAED,MAAM,WAAW,qBAAqB;IACpC,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,UAAU,CAAC,EAAE,MAAM,GAAG,OAAO,CAAC,kBAAkB,CAAC,CAAC;CACnD;AAED,mDAAmD;AACnD,MAAM,WAAW,oBAAoB;IACnC,KAAK,EAAE,YAAY,CAAC;IACpB,UAAU,EAAE,kBAAkB,CAAC;CAChC;AAED,MAAM,WAAW,oBAAoB;IACnC,UAAU,EAAE,YAAY,CAAC;IACzB,QAAQ,EAAE,YAAY,CAAC;IACvB,SAAS,EAAE,YAAY,CAAC;IACxB,KAAK,EAAE,YAAY,CAAC;CACrB;AAED,MAAM,WAAW,eAAe;IAC9B,CAAC,QAAQ,EAAE,MAAM,GAAG,oBAAoB,CAAC;CAC1C"}
|
package/dist/index.browser.d.ts
CHANGED
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
export { coveragePlugin } from './coverage-plugin.browser.js';
|
|
2
2
|
export { CoveragePanelComponent } from './coverage-panel.component.js';
|
|
3
|
-
export
|
|
3
|
+
export { CoverageHeaderBadgeComponent } from './coverage-header-badge.component.js';
|
|
4
|
+
export type { CoverageData, CoverageManifestMeta, CoveragePluginOptions, CoverageThresholds, MetricDetail, } from './coverage.types.js';
|
|
4
5
|
//# sourceMappingURL=index.browser.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.browser.d.ts","sourceRoot":"","sources":["../src/index.browser.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,cAAc,EAAE,MAAM,8BAA8B,CAAC;AAC9D,OAAO,EAAE,sBAAsB,EAAE,MAAM,+BAA+B,CAAC;AACvE,
|
|
1
|
+
{"version":3,"file":"index.browser.d.ts","sourceRoot":"","sources":["../src/index.browser.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,cAAc,EAAE,MAAM,8BAA8B,CAAC;AAC9D,OAAO,EAAE,sBAAsB,EAAE,MAAM,+BAA+B,CAAC;AACvE,OAAO,EAAE,4BAA4B,EAAE,MAAM,sCAAsC,CAAC;AACpF,YAAY,EACV,YAAY,EACZ,oBAAoB,EACpB,qBAAqB,EACrB,kBAAkB,EAClB,YAAY,GACb,MAAM,qBAAqB,CAAC"}
|
package/dist/index.browser.js
CHANGED
package/dist/index.d.ts
CHANGED
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
export { coveragePlugin } from './coverage-plugin.js';
|
|
2
2
|
export { CoveragePanelComponent } from './coverage-panel.component.js';
|
|
3
|
-
export
|
|
3
|
+
export { CoverageHeaderBadgeComponent } from './coverage-header-badge.component.js';
|
|
4
|
+
export type { CoverageData, CoverageManifestMeta, CoveragePluginOptions, CoverageThresholds, MetricDetail, } from './coverage.types.js';
|
|
4
5
|
//# sourceMappingURL=index.d.ts.map
|
package/dist/index.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,cAAc,EAAE,MAAM,sBAAsB,CAAC;AACtD,OAAO,EAAE,sBAAsB,EAAE,MAAM,+BAA+B,CAAC;AACvE,
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,cAAc,EAAE,MAAM,sBAAsB,CAAC;AACtD,OAAO,EAAE,sBAAsB,EAAE,MAAM,+BAA+B,CAAC;AACvE,OAAO,EAAE,4BAA4B,EAAE,MAAM,sCAAsC,CAAC;AACpF,YAAY,EACV,YAAY,EACZ,oBAAoB,EACpB,qBAAqB,EACrB,kBAAkB,EAClB,YAAY,GACb,MAAM,qBAAqB,CAAC"}
|
package/dist/index.js
CHANGED
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@ng-prism/plugin-coverage",
|
|
3
|
-
"version": "21.
|
|
3
|
+
"version": "21.12.0-beta.1",
|
|
4
4
|
"description": "Test coverage panel for ng-prism.",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"@ng-prism/core",
|
|
@@ -30,7 +30,7 @@
|
|
|
30
30
|
],
|
|
31
31
|
"peerDependencies": {
|
|
32
32
|
"@angular/core": ">=21.0.0",
|
|
33
|
-
"@ng-prism/core": ">=21.0.0"
|
|
33
|
+
"@ng-prism/core": ">=21.0.0-0"
|
|
34
34
|
},
|
|
35
35
|
"devDependencies": {
|
|
36
36
|
"@ng-prism/core": "*"
|