@ng-prism/plugin-coverage 21.4.5 → 21.5.0

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.
@@ -1,17 +1,15 @@
1
- import type { CoverageData, MetricDetail } from './coverage.types.js';
1
+ import type { CoverageData, FileCoverageDetail } from './coverage.types.js';
2
2
  import * as i0 from "@angular/core";
3
- interface MetricRow {
4
- label: string;
5
- detail: MetricDetail;
6
- level: 'good' | 'warn' | 'bad';
7
- }
8
3
  export declare class CoveragePanelComponent {
9
4
  readonly activeComponent: import("@angular/core").InputSignal<unknown>;
10
5
  protected readonly coverage: import("@angular/core").Signal<CoverageData | null>;
11
- protected readonly scoreLevel: import("@angular/core").Signal<"good" | "warn" | "bad">;
12
- protected readonly metricRows: import("@angular/core").Signal<MetricRow[]>;
6
+ protected readonly summaryStats: import("@angular/core").Signal<{
7
+ label: string;
8
+ pct: number;
9
+ }[]>;
10
+ protected readonly files: import("@angular/core").Signal<FileCoverageDetail[]>;
11
+ protected fileName(path: string): string;
13
12
  static ɵfac: i0.ɵɵFactoryDeclaration<CoveragePanelComponent, never>;
14
13
  static ɵcmp: i0.ɵɵComponentDeclaration<CoveragePanelComponent, "prism-coverage-panel", never, { "activeComponent": { "alias": "activeComponent"; "required": false; "isSignal": true; }; }, {}, never, never, true, never>;
15
14
  }
16
- export {};
17
15
  //# sourceMappingURL=coverage-panel.component.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"coverage-panel.component.d.ts","sourceRoot":"","sources":["../src/coverage-panel.component.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,YAAY,EAAE,YAAY,EAAE,MAAM,qBAAqB,CAAC;;AAEtE,UAAU,SAAS;IACjB,KAAK,EAAE,MAAM,CAAC;IACd,MAAM,EAAE,YAAY,CAAC;IACrB,KAAK,EAAE,MAAM,GAAG,MAAM,GAAG,KAAK,CAAC;CAChC;AAED,qBAyIa,sBAAsB;IACjC,QAAQ,CAAC,eAAe,+CAAwB;IAEhD,SAAS,CAAC,QAAQ,CAAC,QAAQ,sDAGxB;IAEH,SAAS,CAAC,QAAQ,CAAC,UAAU,0DAK1B;IAEH,SAAS,CAAC,QAAQ,CAAC,UAAU,8CAgB1B;yCA/BQ,sBAAsB;2CAAtB,sBAAsB;CAgClC"}
1
+ {"version":3,"file":"coverage-panel.component.d.ts","sourceRoot":"","sources":["../src/coverage-panel.component.ts"],"names":[],"mappings":"AAMA,OAAO,KAAK,EAAE,YAAY,EAAE,kBAAkB,EAAE,MAAM,qBAAqB,CAAC;;AAE5E,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,IAAI,EAAE,MAAM,GAAG,MAAM;yCAzB7B,sBAAsB;2CAAtB,sBAAsB;CA6BlC"}
@@ -1,137 +1,190 @@
1
- import { ChangeDetectionStrategy, Component, computed, input } from '@angular/core';
1
+ import { ChangeDetectionStrategy, Component, computed, input, } from '@angular/core';
2
2
  import * as i0 from "@angular/core";
3
3
  const _forTrack0 = ($index, $item) => $item.label;
4
- function CoveragePanelComponent_Conditional_0_For_8_Template(rf, ctx) { if (rf & 1) {
5
- i0.ɵɵdomElementStart(0, "div", 6)(1, "span", 7);
4
+ const _forTrack1 = ($index, $item) => $item.path;
5
+ function CoveragePanelComponent_Conditional_0_For_3_Template(rf, ctx) { if (rf & 1) {
6
+ i0.ɵɵdomElementStart(0, "div", 3)(1, "div", 5);
6
7
  i0.ɵɵtext(2);
7
8
  i0.ɵɵdomElementEnd();
8
- i0.ɵɵdomElementStart(3, "div", 8);
9
- i0.ɵɵdomElement(4, "div", 9);
9
+ i0.ɵɵdomElementStart(3, "div", 6);
10
+ i0.ɵɵtext(4);
11
+ i0.ɵɵdomElementStart(5, "small");
12
+ i0.ɵɵtext(6, "%");
13
+ i0.ɵɵdomElementEnd()();
14
+ i0.ɵɵdomElementStart(7, "div", 7);
15
+ i0.ɵɵdomElement(8, "div", 8);
16
+ i0.ɵɵdomElementEnd()();
17
+ } if (rf & 2) {
18
+ const stat_r1 = ctx.$implicit;
19
+ i0.ɵɵadvance(2);
20
+ i0.ɵɵtextInterpolate(stat_r1.label);
21
+ i0.ɵɵadvance(2);
22
+ i0.ɵɵtextInterpolate(stat_r1.pct);
23
+ i0.ɵɵadvance(4);
24
+ i0.ɵɵstyleProp("width", stat_r1.pct, "%");
25
+ } }
26
+ function CoveragePanelComponent_Conditional_0_Conditional_4_For_13_Template(rf, ctx) { if (rf & 1) {
27
+ i0.ɵɵdomElementStart(0, "div", 10)(1, "span", 11);
28
+ i0.ɵɵtext(2);
10
29
  i0.ɵɵdomElementEnd();
11
- i0.ɵɵdomElementStart(5, "span", 10);
30
+ i0.ɵɵdomElementStart(3, "span", 12);
31
+ i0.ɵɵtext(4);
32
+ i0.ɵɵdomElementEnd();
33
+ i0.ɵɵdomElementStart(5, "span", 12);
12
34
  i0.ɵɵtext(6);
13
35
  i0.ɵɵdomElementEnd();
14
- i0.ɵɵdomElementStart(7, "span", 11);
36
+ i0.ɵɵdomElementStart(7, "span", 12);
15
37
  i0.ɵɵtext(8);
38
+ i0.ɵɵdomElementEnd();
39
+ i0.ɵɵdomElementStart(9, "span", 12);
40
+ i0.ɵɵtext(10);
16
41
  i0.ɵɵdomElementEnd()();
17
42
  } if (rf & 2) {
18
- const row_r1 = ctx.$implicit;
43
+ const file_r2 = ctx.$implicit;
44
+ const ctx_r2 = i0.ɵɵnextContext(3);
19
45
  i0.ɵɵadvance(2);
20
- i0.ɵɵtextInterpolate(row_r1.label);
21
- i0.ɵɵadvance(2);
22
- i0.ɵɵstyleProp("width", row_r1.detail.pct, "%");
23
- i0.ɵɵattribute("data-level", row_r1.level);
46
+ i0.ɵɵtextInterpolate(ctx_r2.fileName(file_r2.path));
24
47
  i0.ɵɵadvance();
25
- i0.ɵɵattribute("data-level", row_r1.level);
48
+ i0.ɵɵclassProp("bad", file_r2.lines.pct < 80);
26
49
  i0.ɵɵadvance();
27
- i0.ɵɵtextInterpolate1("", row_r1.detail.pct, "%");
28
- i0.ɵɵadvance(2);
29
- i0.ɵɵtextInterpolate2("", row_r1.detail.covered, "/", row_r1.detail.total);
50
+ i0.ɵɵtextInterpolate1("", file_r2.lines.pct, "%");
51
+ i0.ɵɵadvance();
52
+ i0.ɵɵclassProp("bad", file_r2.branches.pct < 80);
53
+ i0.ɵɵadvance();
54
+ i0.ɵɵtextInterpolate1("", file_r2.branches.pct, "%");
55
+ i0.ɵɵadvance();
56
+ i0.ɵɵclassProp("bad", file_r2.functions.pct < 80);
57
+ i0.ɵɵadvance();
58
+ i0.ɵɵtextInterpolate1("", file_r2.functions.pct, "%");
59
+ i0.ɵɵadvance();
60
+ i0.ɵɵclassProp("bad", file_r2.statements.pct < 80);
61
+ i0.ɵɵadvance();
62
+ i0.ɵɵtextInterpolate1("", file_r2.statements.pct, "%");
30
63
  } }
31
- function CoveragePanelComponent_Conditional_0_Template(rf, ctx) { if (rf & 1) {
32
- i0.ɵɵdomElementStart(0, "div", 0)(1, "div", 2)(2, "span", 3);
33
- i0.ɵɵtext(3, "Test Coverage");
64
+ function CoveragePanelComponent_Conditional_0_Conditional_4_Template(rf, ctx) { if (rf & 1) {
65
+ i0.ɵɵdomElementStart(0, "div", 4)(1, "div", 9)(2, "span");
66
+ i0.ɵɵtext(3, "File");
34
67
  i0.ɵɵdomElementEnd();
35
- i0.ɵɵdomElementStart(4, "span", 4);
36
- i0.ɵɵtext(5);
37
- i0.ɵɵdomElementEnd()();
38
- i0.ɵɵdomElementStart(6, "div", 5);
39
- i0.ɵɵrepeaterCreate(7, CoveragePanelComponent_Conditional_0_For_8_Template, 9, 8, "div", 6, _forTrack0);
68
+ i0.ɵɵdomElementStart(4, "span");
69
+ i0.ɵɵtext(5, "Lines");
70
+ i0.ɵɵdomElementEnd();
71
+ i0.ɵɵdomElementStart(6, "span");
72
+ i0.ɵɵtext(7, "Branch");
73
+ i0.ɵɵdomElementEnd();
74
+ i0.ɵɵdomElementStart(8, "span");
75
+ i0.ɵɵtext(9, "Func");
76
+ i0.ɵɵdomElementEnd();
77
+ i0.ɵɵdomElementStart(10, "span");
78
+ i0.ɵɵtext(11, "Stmt");
40
79
  i0.ɵɵdomElementEnd()();
80
+ i0.ɵɵrepeaterCreate(12, CoveragePanelComponent_Conditional_0_Conditional_4_For_13_Template, 11, 13, "div", 10, _forTrack1);
81
+ i0.ɵɵdomElementEnd();
41
82
  } if (rf & 2) {
42
- const ctx_r1 = i0.ɵɵnextContext();
43
- i0.ɵɵadvance(4);
44
- i0.ɵɵattribute("data-level", ctx_r1.scoreLevel());
45
- i0.ɵɵadvance();
46
- i0.ɵɵtextInterpolate1("", ctx_r1.coverage().score, "%");
83
+ const ctx_r2 = i0.ɵɵnextContext(2);
84
+ i0.ɵɵadvance(12);
85
+ i0.ɵɵrepeater(ctx_r2.files());
86
+ } }
87
+ function CoveragePanelComponent_Conditional_0_Template(rf, ctx) { if (rf & 1) {
88
+ i0.ɵɵdomElementStart(0, "div", 0)(1, "div", 2);
89
+ i0.ɵɵrepeaterCreate(2, CoveragePanelComponent_Conditional_0_For_3_Template, 9, 4, "div", 3, _forTrack0);
90
+ i0.ɵɵdomElementEnd();
91
+ i0.ɵɵconditionalCreate(4, CoveragePanelComponent_Conditional_0_Conditional_4_Template, 14, 0, "div", 4);
92
+ i0.ɵɵdomElementEnd();
93
+ } if (rf & 2) {
94
+ const ctx_r2 = i0.ɵɵnextContext();
47
95
  i0.ɵɵadvance(2);
48
- i0.ɵɵrepeater(ctx_r1.metricRows());
96
+ i0.ɵɵrepeater(ctx_r2.summaryStats());
97
+ i0.ɵɵadvance(2);
98
+ i0.ɵɵconditional(ctx_r2.files().length ? 4 : -1);
49
99
  } }
50
100
  function CoveragePanelComponent_Conditional_1_Template(rf, ctx) { if (rf & 1) {
51
- i0.ɵɵdomElementStart(0, "div", 1)(1, "p", 12);
52
- i0.ɵɵtext(2, " Keine Coverage-Daten gefunden.");
53
- i0.ɵɵdomElement(3, "br");
54
- i0.ɵɵtext(4, " Fuehre ");
55
- i0.ɵɵdomElementStart(5, "code");
56
- i0.ɵɵtext(6, "nx test <project> --coverage");
57
- i0.ɵɵdomElementEnd();
58
- i0.ɵɵtext(7, " aus und rebuilde den Styleguide. ");
101
+ i0.ɵɵdomElementStart(0, "div", 1)(1, "p");
102
+ i0.ɵɵtext(2, "No coverage data. Run tests with coverage enabled.");
59
103
  i0.ɵɵdomElementEnd()();
60
104
  } }
61
105
  export class CoveragePanelComponent {
62
106
  activeComponent = input(null, ...(ngDevMode ? [{ debugName: "activeComponent" }] : []));
63
107
  coverage = computed(() => {
64
108
  const comp = this.activeComponent();
65
- return comp?.meta?.showcaseConfig?.meta?.['coverage'] ?? null;
109
+ return (comp?.meta?.showcaseConfig?.meta?.['coverage'] ?? null);
66
110
  }, ...(ngDevMode ? [{ debugName: "coverage" }] : []));
67
- scoreLevel = computed(() => {
68
- const s = this.coverage()?.score ?? 0;
69
- if (s >= 80)
70
- return 'good';
71
- if (s >= 50)
72
- return 'warn';
73
- return 'bad';
74
- }, ...(ngDevMode ? [{ debugName: "scoreLevel" }] : []));
75
- metricRows = computed(() => {
111
+ summaryStats = computed(() => {
76
112
  const c = this.coverage();
77
113
  if (!c?.found)
78
114
  return [];
79
- const toLevel = (pct) => {
80
- if (pct >= 80)
81
- return 'good';
82
- if (pct >= 50)
83
- return 'warn';
84
- return 'bad';
85
- };
86
115
  return [
87
- { label: 'Statements', detail: c.statements, level: toLevel(c.statements.pct) },
88
- { label: 'Branches', detail: c.branches, level: toLevel(c.branches.pct) },
89
- { label: 'Functions', detail: c.functions, level: toLevel(c.functions.pct) },
90
- { label: 'Lines', detail: c.lines, level: toLevel(c.lines.pct) },
116
+ { label: 'Lines', pct: c.lines.pct },
117
+ { label: 'Branches', pct: c.branches.pct },
118
+ { label: 'Functions', pct: c.functions.pct },
119
+ { label: 'Statements', pct: c.statements.pct },
91
120
  ];
92
- }, ...(ngDevMode ? [{ debugName: "metricRows" }] : []));
121
+ }, ...(ngDevMode ? [{ debugName: "summaryStats" }] : []));
122
+ files = computed(() => {
123
+ return this.coverage()?.files ?? [];
124
+ }, ...(ngDevMode ? [{ debugName: "files" }] : []));
125
+ fileName(path) {
126
+ const parts = path.split('/');
127
+ return parts[parts.length - 1];
128
+ }
93
129
  static ɵfac = function CoveragePanelComponent_Factory(__ngFactoryType__) { return new (__ngFactoryType__ || CoveragePanelComponent)(); };
94
- static ɵcmp = /*@__PURE__*/ i0.ɵɵdefineComponent({ type: CoveragePanelComponent, selectors: [["prism-coverage-panel"]], inputs: { activeComponent: [1, "activeComponent"] }, decls: 2, vars: 1, consts: [[1, "prism-coverage"], [1, "prism-coverage", "prism-coverage--empty"], [1, "prism-coverage__header"], [1, "prism-coverage__title"], [1, "prism-coverage__score"], [1, "prism-coverage__metrics"], [1, "prism-coverage__row"], [1, "prism-coverage__label"], [1, "prism-coverage__bar-track"], [1, "prism-coverage__bar-fill"], [1, "prism-coverage__pct"], [1, "prism-coverage__ratio"], [1, "prism-coverage__hint"]], template: function CoveragePanelComponent_Template(rf, ctx) { if (rf & 1) {
95
- i0.ɵɵconditionalCreate(0, CoveragePanelComponent_Conditional_0_Template, 9, 2, "div", 0)(1, CoveragePanelComponent_Conditional_1_Template, 8, 0, "div", 1);
130
+ static ɵcmp = /*@__PURE__*/ i0.ɵɵdefineComponent({ type: CoveragePanelComponent, selectors: [["prism-coverage-panel"]], inputs: { activeComponent: [1, "activeComponent"] }, decls: 2, vars: 1, consts: [[1, "cov-body"], [1, "cov-empty"], [1, "cov-summary"], [1, "cov-stat"], [1, "cov-files"], [1, "cov-stat-k"], [1, "cov-stat-v"], [1, "cov-bar"], [1, "cov-bar-fill"], [1, "cov-file", "cov-file--header"], [1, "cov-file"], [1, "cov-file-name"], [1, "cov-file-val"]], template: function CoveragePanelComponent_Template(rf, ctx) { if (rf & 1) {
131
+ i0.ɵɵconditionalCreate(0, CoveragePanelComponent_Conditional_0_Template, 5, 1, "div", 0)(1, CoveragePanelComponent_Conditional_1_Template, 3, 0, "div", 1);
96
132
  } if (rf & 2) {
97
133
  let tmp_0_0;
98
134
  i0.ɵɵconditional(((tmp_0_0 = ctx.coverage()) == null ? null : tmp_0_0.found) ? 0 : 1);
99
- } }, styles: [".prism-coverage[_ngcontent-%COMP%] {\n padding: 16px;\n font-family: var(--prism-font-sans, system-ui, sans-serif);\n font-size: 13px;\n color: var(--prism-text, #e2e4e9);\n }\n\n .prism-coverage--empty[_ngcontent-%COMP%] {\n display: flex;\n align-items: center;\n justify-content: center;\n min-height: 120px;\n }\n\n .prism-coverage__hint[_ngcontent-%COMP%] {\n color: var(--prism-text-muted, #8b8fa3);\n text-align: center;\n line-height: 1.6;\n }\n\n .prism-coverage__hint[_ngcontent-%COMP%] code[_ngcontent-%COMP%] {\n background: rgba(255, 255, 255, 0.06);\n padding: 2px 6px;\n border-radius: 4px;\n font-size: 12px;\n }\n\n .prism-coverage__header[_ngcontent-%COMP%] {\n display: flex;\n align-items: center;\n justify-content: space-between;\n margin-bottom: 16px;\n }\n\n .prism-coverage__title[_ngcontent-%COMP%] {\n font-weight: 600;\n font-size: 14px;\n }\n\n .prism-coverage__score[_ngcontent-%COMP%] {\n font-weight: 700;\n font-size: 16px;\n }\n\n .prism-coverage__score[data-level=\"good\"][_ngcontent-%COMP%], \n .prism-coverage__pct[data-level=\"good\"][_ngcontent-%COMP%] { color: #4ade80; }\n .prism-coverage__score[data-level=\"warn\"][_ngcontent-%COMP%], \n .prism-coverage__pct[data-level=\"warn\"][_ngcontent-%COMP%] { color: #fbbf24; }\n .prism-coverage__score[data-level=\"bad\"][_ngcontent-%COMP%], \n .prism-coverage__pct[data-level=\"bad\"][_ngcontent-%COMP%] { color: #f87171; }\n\n .prism-coverage__metrics[_ngcontent-%COMP%] {\n display: flex;\n flex-direction: column;\n gap: 10px;\n }\n\n .prism-coverage__row[_ngcontent-%COMP%] {\n display: grid;\n grid-template-columns: 90px 1fr 50px 70px;\n align-items: center;\n gap: 10px;\n }\n\n .prism-coverage__label[_ngcontent-%COMP%] {\n color: var(--prism-text-muted, #8b8fa3);\n font-size: 12px;\n }\n\n .prism-coverage__bar-track[_ngcontent-%COMP%] {\n height: 6px;\n border-radius: 3px;\n background: rgba(255, 255, 255, 0.06);\n overflow: hidden;\n }\n\n .prism-coverage__bar-fill[_ngcontent-%COMP%] {\n height: 100%;\n border-radius: 3px;\n transition: width 0.3s ease;\n }\n\n .prism-coverage__bar-fill[data-level=\"good\"][_ngcontent-%COMP%] { background: #4ade80; }\n .prism-coverage__bar-fill[data-level=\"warn\"][_ngcontent-%COMP%] { background: #fbbf24; }\n .prism-coverage__bar-fill[data-level=\"bad\"][_ngcontent-%COMP%] { background: #f87171; }\n\n .prism-coverage__pct[_ngcontent-%COMP%] {\n text-align: right;\n font-weight: 600;\n font-size: 12px;\n }\n\n .prism-coverage__ratio[_ngcontent-%COMP%] {\n text-align: right;\n font-size: 11px;\n color: var(--prism-text-muted, #8b8fa3);\n }"], changeDetection: 0 });
135
+ } }, styles: ["[_nghost-%COMP%] { display: block; height: 100%; overflow: auto; }\n\n .cov-body[_ngcontent-%COMP%] { padding: 20px 24px; }\n\n .cov-summary[_ngcontent-%COMP%] {\n display: grid;\n grid-template-columns: repeat(4, 1fr);\n gap: 12px;\n margin-bottom: 18px;\n }\n\n .cov-stat[_ngcontent-%COMP%] {\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[_ngcontent-%COMP%] {\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[_ngcontent-%COMP%] {\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[_ngcontent-%COMP%] small[_ngcontent-%COMP%] {\n font-size: 13px;\n color: var(--prism-text-muted);\n font-weight: 500;\n }\n .cov-bar[_ngcontent-%COMP%] {\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[_ngcontent-%COMP%] {\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[_ngcontent-%COMP%] {\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[_ngcontent-%COMP%] {\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[_ngcontent-%COMP%]:last-child { border-bottom: 0; }\n\n .cov-file--header[_ngcontent-%COMP%] {\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[_ngcontent-%COMP%] { color: var(--prism-text-2); }\n .cov-file-val[_ngcontent-%COMP%] {\n color: var(--prism-text);\n min-width: 54px;\n text-align: right;\n }\n .cov-file-val.bad[_ngcontent-%COMP%] { color: var(--prism-warn); }\n\n .cov-empty[_ngcontent-%COMP%] {\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 }"], changeDetection: 0 });
100
136
  }
101
137
  (() => { (typeof ngDevMode === "undefined" || ngDevMode) && i0.ɵsetClassMetadata(CoveragePanelComponent, [{
102
138
  type: Component,
103
139
  args: [{ selector: 'prism-coverage-panel', standalone: true, changeDetection: ChangeDetectionStrategy.OnPush, template: `
104
140
  @if (coverage()?.found) {
105
- <div class="prism-coverage">
106
- <div class="prism-coverage__header">
107
- <span class="prism-coverage__title">Test Coverage</span>
108
- <span class="prism-coverage__score" [attr.data-level]="scoreLevel()">{{ coverage()!.score }}%</span>
141
+ <div class="cov-body">
142
+ <div class="cov-summary">
143
+ @for (stat of summaryStats(); track stat.label) {
144
+ <div class="cov-stat">
145
+ <div class="cov-stat-k">{{ stat.label }}</div>
146
+ <div class="cov-stat-v">{{ stat.pct }}<small>%</small></div>
147
+ <div class="cov-bar">
148
+ <div class="cov-bar-fill" [style.width.%]="stat.pct"></div>
149
+ </div>
150
+ </div>
151
+ }
152
+ </div>
153
+
154
+ @if (files().length) {
155
+ <div class="cov-files">
156
+ <div class="cov-file cov-file--header">
157
+ <span>File</span>
158
+ <span>Lines</span>
159
+ <span>Branch</span>
160
+ <span>Func</span>
161
+ <span>Stmt</span>
109
162
  </div>
110
- <div class="prism-coverage__metrics">
111
- @for (row of metricRows(); track row.label) {
112
- <div class="prism-coverage__row">
113
- <span class="prism-coverage__label">{{ row.label }}</span>
114
- <div class="prism-coverage__bar-track">
115
- <div
116
- class="prism-coverage__bar-fill"
117
- [attr.data-level]="row.level"
118
- [style.width.%]="row.detail.pct"
119
- ></div>
120
- </div>
121
- <span class="prism-coverage__pct" [attr.data-level]="row.level">{{ row.detail.pct }}%</span>
122
- <span class="prism-coverage__ratio">{{ row.detail.covered }}/{{ row.detail.total }}</span>
123
- </div>
124
- }
163
+ @for (file of files(); track file.path) {
164
+ <div class="cov-file">
165
+ <span class="cov-file-name">{{ fileName(file.path) }}</span>
166
+ <span class="cov-file-val" [class.bad]="file.lines.pct < 80"
167
+ >{{ file.lines.pct }}%</span
168
+ >
169
+ <span class="cov-file-val" [class.bad]="file.branches.pct < 80"
170
+ >{{ file.branches.pct }}%</span
171
+ >
172
+ <span class="cov-file-val" [class.bad]="file.functions.pct < 80"
173
+ >{{ file.functions.pct }}%</span
174
+ >
175
+ <span class="cov-file-val" [class.bad]="file.statements.pct < 80"
176
+ >{{ file.statements.pct }}%</span
177
+ >
125
178
  </div>
179
+ }
126
180
  </div>
181
+ }
182
+ </div>
127
183
  } @else {
128
- <div class="prism-coverage prism-coverage--empty">
129
- <p class="prism-coverage__hint">
130
- Keine Coverage-Daten gefunden.<br />
131
- Fuehre <code>nx test &lt;project&gt; --coverage</code> aus und rebuilde den Styleguide.
132
- </p>
133
- </div>
184
+ <div class="cov-empty">
185
+ <p>No coverage data. Run tests with coverage enabled.</p>
186
+ </div>
134
187
  }
135
- `, styles: ["\n .prism-coverage {\n padding: 16px;\n font-family: var(--prism-font-sans, system-ui, sans-serif);\n font-size: 13px;\n color: var(--prism-text, #e2e4e9);\n }\n\n .prism-coverage--empty {\n display: flex;\n align-items: center;\n justify-content: center;\n min-height: 120px;\n }\n\n .prism-coverage__hint {\n color: var(--prism-text-muted, #8b8fa3);\n text-align: center;\n line-height: 1.6;\n }\n\n .prism-coverage__hint code {\n background: rgba(255, 255, 255, 0.06);\n padding: 2px 6px;\n border-radius: 4px;\n font-size: 12px;\n }\n\n .prism-coverage__header {\n display: flex;\n align-items: center;\n justify-content: space-between;\n margin-bottom: 16px;\n }\n\n .prism-coverage__title {\n font-weight: 600;\n font-size: 14px;\n }\n\n .prism-coverage__score {\n font-weight: 700;\n font-size: 16px;\n }\n\n .prism-coverage__score[data-level=\"good\"],\n .prism-coverage__pct[data-level=\"good\"] { color: #4ade80; }\n .prism-coverage__score[data-level=\"warn\"],\n .prism-coverage__pct[data-level=\"warn\"] { color: #fbbf24; }\n .prism-coverage__score[data-level=\"bad\"],\n .prism-coverage__pct[data-level=\"bad\"] { color: #f87171; }\n\n .prism-coverage__metrics {\n display: flex;\n flex-direction: column;\n gap: 10px;\n }\n\n .prism-coverage__row {\n display: grid;\n grid-template-columns: 90px 1fr 50px 70px;\n align-items: center;\n gap: 10px;\n }\n\n .prism-coverage__label {\n color: var(--prism-text-muted, #8b8fa3);\n font-size: 12px;\n }\n\n .prism-coverage__bar-track {\n height: 6px;\n border-radius: 3px;\n background: rgba(255, 255, 255, 0.06);\n overflow: hidden;\n }\n\n .prism-coverage__bar-fill {\n height: 100%;\n border-radius: 3px;\n transition: width 0.3s ease;\n }\n\n .prism-coverage__bar-fill[data-level=\"good\"] { background: #4ade80; }\n .prism-coverage__bar-fill[data-level=\"warn\"] { background: #fbbf24; }\n .prism-coverage__bar-fill[data-level=\"bad\"] { background: #f87171; }\n\n .prism-coverage__pct {\n text-align: right;\n font-weight: 600;\n font-size: 12px;\n }\n\n .prism-coverage__ratio {\n text-align: right;\n font-size: 11px;\n color: var(--prism-text-muted, #8b8fa3);\n }\n "] }]
188
+ `, 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 "] }]
136
189
  }], null, { activeComponent: [{ type: i0.Input, args: [{ isSignal: true, alias: "activeComponent", required: false }] }] }); })();
137
- (() => { (typeof ngDevMode === "undefined" || ngDevMode) && i0.ɵsetClassDebugInfo(CoveragePanelComponent, { className: "CoveragePanelComponent", filePath: "coverage-panel.component.ts", lineNumber: 147 }); })();
190
+ (() => { (typeof ngDevMode === "undefined" || ngDevMode) && i0.ɵsetClassDebugInfo(CoveragePanelComponent, { className: "CoveragePanelComponent", filePath: "coverage-panel.component.ts", lineNumber: 163 }); })();
@@ -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,CAAC,QAAQ,CAAC,EAAE,qBAAqB,GAAG,aAAa,CAa9E"}
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,CAgBf"}
@@ -5,6 +5,7 @@ export function coveragePlugin(_options) {
5
5
  {
6
6
  id: 'coverage',
7
7
  label: 'Coverage',
8
+ icon: 'shield-check',
8
9
  loadComponent: () => import('./coverage-panel.component.js').then((m) => m.CoveragePanelComponent),
9
10
  position: 'bottom',
10
11
  },
@@ -4,6 +4,13 @@ export interface MetricDetail {
4
4
  skipped: number;
5
5
  pct: number;
6
6
  }
7
+ export interface FileCoverageDetail {
8
+ path: string;
9
+ statements: MetricDetail;
10
+ branches: MetricDetail;
11
+ functions: MetricDetail;
12
+ lines: MetricDetail;
13
+ }
7
14
  export interface CoverageData {
8
15
  score: number;
9
16
  statements: MetricDetail;
@@ -11,6 +18,7 @@ export interface CoverageData {
11
18
  functions: MetricDetail;
12
19
  lines: MetricDetail;
13
20
  found: boolean;
21
+ files?: FileCoverageDetail[];
14
22
  }
15
23
  export interface CoveragePluginOptions {
16
24
  coveragePath?: string;
@@ -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,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;CAChB;AAED,MAAM,WAAW,qBAAqB;IACpC,YAAY,CAAC,EAAE,MAAM,CAAC;CACvB;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"}
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;CAC9B;AAED,MAAM,WAAW,qBAAqB;IACpC,YAAY,CAAC,EAAE,MAAM,CAAC;CACvB;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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@ng-prism/plugin-coverage",
3
- "version": "21.4.5",
3
+ "version": "21.5.0",
4
4
  "description": "Test coverage panel for ng-prism.",
5
5
  "keywords": [
6
6
  "@ng-prism/core",