@ng-prism/plugin-coverage 22.2.0-beta.4 → 22.2.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.
@@ -0,0 +1,13 @@
1
+ import type { NavigationDecorationDefinition, PanelBadge, RuntimeComponent } from '@ng-prism/core/plugin';
2
+ /**
3
+ * The score on the panel's own tab.
4
+ *
5
+ * Declared by the plugin rather than left to the core's built-in badge chain,
6
+ * which graded every score on a fixed 90/70 scale and so could paint the tab
7
+ * red for a component the navigation marker — reading this plugin's configured
8
+ * thresholds — called amber. The `summary` written at build time wins when it
9
+ * is there; deriving from `thresholds` covers the run where it is not.
10
+ */
11
+ export declare function coverageBadge(component: RuntimeComponent): PanelBadge | null;
12
+ export declare const COVERAGE_NAVIGATION_DECORATION: NavigationDecorationDefinition;
13
+ //# sourceMappingURL=coverage-contributions.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"coverage-contributions.d.ts","sourceRoot":"","sources":["../src/coverage-contributions.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EACV,8BAA8B,EAC9B,UAAU,EACV,gBAAgB,EACjB,MAAM,uBAAuB,CAAC;AAiB/B;;;;;;;;GAQG;AACH,wBAAgB,aAAa,CAAC,SAAS,EAAE,gBAAgB,GAAG,UAAU,GAAG,IAAI,CAW5E;AAED,eAAO,MAAM,8BAA8B,EAAE,8BAU5C,CAAC"}
@@ -0,0 +1,41 @@
1
+ import { deriveCoverageSummary } from './coverage-summary.js';
2
+ /**
3
+ * The runtime contributions both entry points declare. `coverage-plugin.ts`
4
+ * carries the build-time hook and must never be reachable from a browser
5
+ * bundle, so the browser entry cannot import through it.
6
+ */
7
+ function componentMeta(component) {
8
+ return (component.meta?.showcaseConfig?.meta?.['coverage'] ?? null);
9
+ }
10
+ /**
11
+ * The score on the panel's own tab.
12
+ *
13
+ * Declared by the plugin rather than left to the core's built-in badge chain,
14
+ * which graded every score on a fixed 90/70 scale and so could paint the tab
15
+ * red for a component the navigation marker — reading this plugin's configured
16
+ * thresholds — called amber. The `summary` written at build time wins when it
17
+ * is there; deriving from `thresholds` covers the run where it is not.
18
+ */
19
+ export function coverageBadge(component) {
20
+ const meta = componentMeta(component);
21
+ if (!meta?.found)
22
+ return null;
23
+ const variant = meta.summary?.variant ??
24
+ (meta.thresholds
25
+ ? deriveCoverageSummary(meta.score, meta.thresholds).variant
26
+ : 'default');
27
+ return { text: String(meta.score), variant };
28
+ }
29
+ export const COVERAGE_NAVIGATION_DECORATION = {
30
+ id: 'coverage',
31
+ icon: 'shield-check',
32
+ order: 30,
33
+ badge: (component) => {
34
+ const meta = componentMeta(component);
35
+ if (!meta?.found || !meta.summary)
36
+ return null;
37
+ if (meta.summary.variant === 'ok')
38
+ return null;
39
+ return { variant: meta.summary.variant, label: meta.summary.label };
40
+ },
41
+ };
@@ -1,14 +1,12 @@
1
1
  import * as i0 from "@angular/core";
2
- type Variant = 'ok' | 'warn' | 'danger';
3
2
  export declare class CoverageHeaderBadgeComponent {
4
3
  private readonly manifest;
5
4
  protected readonly data: import("@angular/core").Signal<{
6
5
  score: number;
7
- variant: Variant;
6
+ variant: "ok" | "warn" | "danger";
8
7
  title: string;
9
8
  } | null>;
10
9
  static ɵfac: i0.ɵɵFactoryDeclaration<CoverageHeaderBadgeComponent, never>;
11
10
  static ɵcmp: i0.ɵɵComponentDeclaration<CoverageHeaderBadgeComponent, "prism-coverage-header-badge", never, {}, {}, never, never, true, never>;
12
11
  }
13
- export {};
14
12
  //# sourceMappingURL=coverage-header-badge.component.d.ts.map
@@ -1 +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"}
1
+ {"version":3,"file":"coverage-header-badge.component.d.ts","sourceRoot":"","sources":["../src/coverage-header-badge.component.ts"],"names":[],"mappings":";AAYA,qBAiBa,4BAA4B;IACvC,OAAO,CAAC,QAAQ,CAAC,QAAQ,CAA2C;IAEpE,SAAS,CAAC,QAAQ,CAAC,IAAI;;;;cAqBpB;yCAxBQ,4BAA4B;2CAA5B,4BAA4B;CAyBxC"}
@@ -1,23 +1,13 @@
1
1
  import { ChangeDetectionStrategy, Component, computed, inject, } from '@angular/core';
2
2
  import { PRISM_MANIFEST } from '@ng-prism/core/plugin';
3
+ import { PrismMetricBadgeComponent } from '@ng-prism/core';
4
+ import { deriveCoverageSummary } from './coverage-summary.js';
3
5
  import * as i0 from "@angular/core";
4
6
  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()()();
7
+ i0.ɵɵelement(0, "prism-metric-badge", 0);
15
8
  } if (rf & 2) {
16
9
  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);
10
+ i0.ɵɵproperty("value", d_r1.score + "%")("variant", d_r1.variant)("title", d_r1.title);
21
11
  } }
22
12
  export class CoverageHeaderBadgeComponent {
23
13
  manifest = inject(PRISM_MANIFEST);
@@ -26,17 +16,13 @@ export class CoverageHeaderBadgeComponent {
26
16
  if (!meta?.total?.found)
27
17
  return null;
28
18
  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';
19
+ // Both halves come from the one derivation, so the pill's first line and
20
+ // the navigation marker's tooltip cannot name different targets.
21
+ const { variant, label } = deriveCoverageSummary(score, meta.thresholds);
36
22
  return {
37
23
  score,
38
24
  variant,
39
- title: `Library coverage: ${score}% (target ${avgThreshold}%)\n` +
25
+ title: `Library ${label}\n` +
40
26
  `Lines ${meta.total.lines.pct}% · ` +
41
27
  `Branches ${meta.total.branches.pct}% · ` +
42
28
  `Functions ${meta.total.functions.pct}% · ` +
@@ -45,29 +31,31 @@ export class CoverageHeaderBadgeComponent {
45
31
  }, /* @ts-ignore */
46
32
  ...(ngDevMode ? [{ debugName: "data" }] : /* istanbul ignore next */ []));
47
33
  static ɵfac = function CoverageHeaderBadgeComponent_Factory(__ngFactoryType__) { return new (__ngFactoryType__ || CoverageHeaderBadgeComponent)(); };
48
- 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) {
49
- i0.ɵɵconditionalCreate(0, CoverageHeaderBadgeComponent_Conditional_0_Template, 8, 8, "span", 0);
34
+ static ɵcmp = /*@__PURE__*/ i0.ɵɵdefineComponent({ type: CoverageHeaderBadgeComponent, selectors: [["prism-coverage-header-badge"]], decls: 1, vars: 1, consts: [["icon", "shield-check", "label", "Library coverage", 3, "value", "variant", "title"]], template: function CoverageHeaderBadgeComponent_Template(rf, ctx) { if (rf & 1) {
35
+ i0.ɵɵconditionalCreate(0, CoverageHeaderBadgeComponent_Conditional_0_Template, 1, 3, "prism-metric-badge", 0);
50
36
  } if (rf & 2) {
51
37
  let tmp_0_0;
52
38
  i0.ɵɵconditional((tmp_0_0 = ctx.data()) ? 0 : -1, tmp_0_0);
53
- } }, 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); }"] });
39
+ } }, dependencies: [PrismMetricBadgeComponent], encapsulation: 2 });
54
40
  }
55
41
  (() => { (typeof ngDevMode === "undefined" || ngDevMode) && i0.ɵsetClassMetadata(CoverageHeaderBadgeComponent, [{
56
42
  type: Component,
57
- args: [{ selector: 'prism-coverage-header-badge', standalone: true, changeDetection: ChangeDetectionStrategy.OnPush, template: `
43
+ args: [{
44
+ selector: 'prism-coverage-header-badge',
45
+ standalone: true,
46
+ changeDetection: ChangeDetectionStrategy.OnPush,
47
+ imports: [PrismMetricBadgeComponent],
48
+ template: `
58
49
  @if (data(); as d) {
59
- <span
60
- class="cov-pill"
61
- [class.cov-pill--ok]="d.variant === 'ok'"
62
- [class.cov-pill--warn]="d.variant === 'warn'"
63
- [class.cov-pill--danger]="d.variant === 'danger'"
50
+ <prism-metric-badge
51
+ icon="shield-check"
52
+ label="Library coverage"
53
+ [value]="d.score + '%'"
54
+ [variant]="d.variant"
64
55
  [title]="d.title"
65
- >
66
- <span class="cov-pill__dot"></span>
67
- <span class="cov-pill__label">Coverage</span>
68
- <span class="cov-pill__value">{{ d.score }}<small>%</small></span>
69
- </span>
56
+ />
70
57
  }
71
- `, 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 "] }]
58
+ `,
59
+ }]
72
60
  }], null, null); })();
73
- (() => { (typeof ngDevMode === "undefined" || ngDevMode) && i0.ɵsetClassDebugInfo(CoverageHeaderBadgeComponent, { className: "CoverageHeaderBadgeComponent", filePath: "coverage-header-badge.component.ts", lineNumber: 98 }); })();
61
+ (() => { (typeof ngDevMode === "undefined" || ngDevMode) && i0.ɵsetClassDebugInfo(CoverageHeaderBadgeComponent, { className: "CoverageHeaderBadgeComponent", filePath: "coverage-header-badge.component.ts", lineNumber: 30 }); })();
@@ -145,7 +145,7 @@ export class CoveragePanelComponent {
145
145
  i0.ɵɵconditionalCreate(0, CoveragePanelComponent_Conditional_0_Template, 5, 1, "div", 0)(1, CoveragePanelComponent_Conditional_1_Template, 3, 0, "div", 1);
146
146
  } if (rf & 2) {
147
147
  i0.ɵɵconditional(ctx.coverage()?.found ? 0 : 1);
148
- } }, 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 }"] });
148
+ } }, 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(--%NS%prism-bg-surface);\n border: 1px solid var(--%NS%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(--%NS%prism-text-ghost);\n font-weight: 700;\n margin-bottom: 6px;\n }\n .cov-stat-v[_ngcontent-%COMP%] {\n font-family: var(--%NS%font-mono);\n font-size: 22px;\n font-weight: 700;\n color: var(--%NS%prism-text);\n letter-spacing: -0.02em;\n }\n .cov-stat-v[_ngcontent-%COMP%] small[_ngcontent-%COMP%] {\n font-size: 13px;\n color: var(--%NS%prism-text-muted);\n font-weight: 500;\n }\n .cov-bar[_ngcontent-%COMP%] {\n margin-top: 8px;\n height: 4px;\n background: var(--%NS%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(--%NS%prism-primary-from), var(--%NS%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(--%NS%prism-bg-surface);\n border: 1px solid var(--%NS%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(--%NS%font-mono);\n font-size: 12px;\n border-bottom: 1px solid var(--%NS%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(--%NS%prism-border-strong);\n padding-bottom: 8px;\n color: var(--%NS%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(--%NS%prism-text-2); }\n .cov-file-val[_ngcontent-%COMP%] {\n color: var(--%NS%prism-text);\n min-width: 54px;\n text-align: right;\n }\n .cov-file-val.bad[_ngcontent-%COMP%] { color: var(--%NS%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(--%NS%prism-text-muted);\n font-size: 13px;\n text-align: center;\n }"] });
149
149
  }
150
150
  (() => { (typeof ngDevMode === "undefined" || ngDevMode) && i0.ɵsetClassMetadata(CoveragePanelComponent, [{
151
151
  type: Component,
@@ -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,CA2Bf"}
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;AAMjE,wBAAgB,cAAc,CAC5B,QAAQ,CAAC,EAAE,qBAAqB,GAC/B,aAAa,CA8Bf"}
@@ -1,3 +1,4 @@
1
+ import { coverageBadge, COVERAGE_NAVIGATION_DECORATION, } from './coverage-contributions.js';
1
2
  export function coveragePlugin(_options) {
2
3
  return {
3
4
  name: '@ng-prism/plugin-coverage',
@@ -5,6 +6,7 @@ export function coveragePlugin(_options) {
5
6
  {
6
7
  id: 'coverage',
7
8
  label: 'Coverage',
9
+ badge: coverageBadge,
8
10
  icon: 'shield-check',
9
11
  loadComponent: () => import('./coverage-panel.component.js').then((m) => m.CoveragePanelComponent),
10
12
  position: 'bottom',
@@ -18,5 +20,6 @@ export function coveragePlugin(_options) {
18
20
  loadComponent: () => import('./coverage-header-badge.component.js').then((m) => m.CoverageHeaderBadgeComponent),
19
21
  },
20
22
  ],
23
+ navigationDecorations: [COVERAGE_NAVIGATION_DECORATION],
21
24
  };
22
25
  }
@@ -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,EACV,qBAAqB,EACrB,kBAAkB,EACnB,MAAM,qBAAqB,CAAC;AAI7B,eAAO,MAAM,2BAA2B,EAAE,kBAKzC,CAAC;AAEF,wBAAgB,yBAAyB,CACvC,KAAK,CAAC,EAAE,MAAM,GAAG,OAAO,CAAC,kBAAkB,CAAC,GAC3C,kBAAkB,CAWpB;AAED,wBAAgB,cAAc,CAAC,OAAO,CAAC,EAAE,qBAAqB,GAAG,aAAa,CAsD7E"}
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,EACV,qBAAqB,EACrB,kBAAkB,EACnB,MAAM,qBAAqB,CAAC;AAQ7B,eAAO,MAAM,2BAA2B,EAAE,kBAKzC,CAAC;AAEF,wBAAgB,yBAAyB,CACvC,KAAK,CAAC,EAAE,MAAM,GAAG,OAAO,CAAC,kBAAkB,CAAC,GAC3C,kBAAkB,CAWpB;AAED,wBAAgB,cAAc,CAAC,OAAO,CAAC,EAAE,qBAAqB,GAAG,aAAa,CAgE7E"}
@@ -1,3 +1,4 @@
1
+ import { coverageBadge, COVERAGE_NAVIGATION_DECORATION, } from './coverage-contributions.js';
1
2
  const DEFAULT_COVERAGE_PATH = 'coverage/coverage-summary.json';
2
3
  export const DEFAULT_COVERAGE_THRESHOLDS = {
3
4
  lines: 80,
@@ -25,6 +26,7 @@ export function coveragePlugin(options) {
25
26
  name: '@ng-prism/plugin-coverage',
26
27
  async onComponentScanned(component) {
27
28
  const { readCoverageForFile } = await import('./coverage-reader.js');
29
+ const { deriveCoverageSummary } = await import('./coverage-summary.js');
28
30
  const coverage = readCoverageForFile(coveragePath, component.filePath);
29
31
  return {
30
32
  ...component,
@@ -32,7 +34,13 @@ export function coveragePlugin(options) {
32
34
  ...component.showcaseConfig,
33
35
  meta: {
34
36
  ...component.showcaseConfig.meta,
35
- coverage: { ...coverage, thresholds },
37
+ coverage: {
38
+ ...coverage,
39
+ thresholds,
40
+ ...(coverage.found
41
+ ? { summary: deriveCoverageSummary(coverage.score, thresholds) }
42
+ : {}),
43
+ },
36
44
  },
37
45
  },
38
46
  };
@@ -52,6 +60,7 @@ export function coveragePlugin(options) {
52
60
  {
53
61
  id: 'coverage',
54
62
  label: 'Coverage',
63
+ badge: coverageBadge,
55
64
  loadComponent: () => import('./coverage-panel.component.js').then((m) => m.CoveragePanelComponent),
56
65
  position: 'bottom',
57
66
  },
@@ -64,5 +73,6 @@ export function coveragePlugin(options) {
64
73
  loadComponent: () => import('./coverage-header-badge.component.js').then((m) => m.CoverageHeaderBadgeComponent),
65
74
  },
66
75
  ],
76
+ navigationDecorations: [COVERAGE_NAVIGATION_DECORATION],
67
77
  };
68
78
  }
@@ -0,0 +1,13 @@
1
+ import type { CoverageSummary, CoverageThresholds } from './coverage.types.js';
2
+ /**
3
+ * Threshold derivation lives in its own module so both sides can reach it:
4
+ * `coverage-plugin.ts` carries the build-time hook that reads the istanbul
5
+ * summary from disk and must never be reachable from a browser bundle, while
6
+ * the header badge and the navigation marker run in the browser.
7
+ *
8
+ * Same motive as `thresholds.ts` in `plugin-visual-regression`.
9
+ */
10
+ /** The single number the badge compares against — the mean of the four metrics. */
11
+ export declare function avgThreshold(thresholds: CoverageThresholds): number;
12
+ export declare function deriveCoverageSummary(score: number, thresholds: CoverageThresholds): CoverageSummary;
13
+ //# sourceMappingURL=coverage-summary.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"coverage-summary.d.ts","sourceRoot":"","sources":["../src/coverage-summary.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,eAAe,EAAE,kBAAkB,EAAE,MAAM,qBAAqB,CAAC;AAE/E;;;;;;;GAOG;AACH,mFAAmF;AACnF,wBAAgB,YAAY,CAAC,UAAU,EAAE,kBAAkB,GAAG,MAAM,CAQnE;AAED,wBAAgB,qBAAqB,CACnC,KAAK,EAAE,MAAM,EACb,UAAU,EAAE,kBAAkB,GAC7B,eAAe,CAMjB"}
@@ -0,0 +1,21 @@
1
+ /**
2
+ * Threshold derivation lives in its own module so both sides can reach it:
3
+ * `coverage-plugin.ts` carries the build-time hook that reads the istanbul
4
+ * summary from disk and must never be reachable from a browser bundle, while
5
+ * the header badge and the navigation marker run in the browser.
6
+ *
7
+ * Same motive as `thresholds.ts` in `plugin-visual-regression`.
8
+ */
9
+ /** The single number the badge compares against — the mean of the four metrics. */
10
+ export function avgThreshold(thresholds) {
11
+ return Math.round((thresholds.lines +
12
+ thresholds.branches +
13
+ thresholds.functions +
14
+ thresholds.statements) /
15
+ 4);
16
+ }
17
+ export function deriveCoverageSummary(score, thresholds) {
18
+ const avg = avgThreshold(thresholds);
19
+ const variant = score >= avg ? 'ok' : score >= avg * 0.75 ? 'warn' : 'danger';
20
+ return { variant, label: `Coverage: ${score}% (target ${avg}%)` };
21
+ }
@@ -17,6 +17,10 @@ export interface CoverageThresholds {
17
17
  functions: number;
18
18
  statements: number;
19
19
  }
20
+ export interface CoverageSummary {
21
+ variant: 'ok' | 'warn' | 'danger';
22
+ label: string;
23
+ }
20
24
  export interface CoverageData {
21
25
  score: number;
22
26
  statements: MetricDetail;
@@ -26,6 +30,11 @@ export interface CoverageData {
26
30
  found: boolean;
27
31
  files?: FileCoverageDetail[];
28
32
  thresholds?: CoverageThresholds;
33
+ /**
34
+ * Pre-derived headline, written by the build-time hook. Optional because a
35
+ * browser-only plugin setup runs no build-time hooks and then has none.
36
+ */
37
+ summary?: CoverageSummary;
29
38
  }
30
39
  export interface CoveragePluginOptions {
31
40
  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,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"}
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,eAAe;IAC9B,OAAO,EAAE,IAAI,GAAG,MAAM,GAAG,QAAQ,CAAC;IAClC,KAAK,EAAE,MAAM,CAAC;CACf;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;IAChC;;;OAGG;IACH,OAAO,CAAC,EAAE,eAAe,CAAC;CAC3B;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"}
@@ -1,5 +1,5 @@
1
1
  export { coveragePlugin } from './coverage-plugin.browser.js';
2
2
  export { CoveragePanelComponent } from './coverage-panel.component.js';
3
3
  export { CoverageHeaderBadgeComponent } from './coverage-header-badge.component.js';
4
- export type { CoverageData, CoverageManifestMeta, CoveragePluginOptions, CoverageThresholds, MetricDetail, } from './coverage.types.js';
4
+ export type { CoverageData, CoverageManifestMeta, CoveragePluginOptions, CoverageSummary, CoverageThresholds, MetricDetail, } from './coverage.types.js';
5
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,OAAO,EAAE,4BAA4B,EAAE,MAAM,sCAAsC,CAAC;AACpF,YAAY,EACV,YAAY,EACZ,oBAAoB,EACpB,qBAAqB,EACrB,kBAAkB,EAClB,YAAY,GACb,MAAM,qBAAqB,CAAC"}
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,eAAe,EACf,kBAAkB,EAClB,YAAY,GACb,MAAM,qBAAqB,CAAC"}
package/dist/index.d.ts CHANGED
@@ -1,5 +1,5 @@
1
1
  export { coveragePlugin } from './coverage-plugin.js';
2
2
  export { CoveragePanelComponent } from './coverage-panel.component.js';
3
3
  export { CoverageHeaderBadgeComponent } from './coverage-header-badge.component.js';
4
- export type { CoverageData, CoverageManifestMeta, CoveragePluginOptions, CoverageThresholds, MetricDetail, } from './coverage.types.js';
4
+ export type { CoverageData, CoverageManifestMeta, CoveragePluginOptions, CoverageSummary, CoverageThresholds, MetricDetail, } from './coverage.types.js';
5
5
  //# sourceMappingURL=index.d.ts.map
@@ -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,OAAO,EAAE,4BAA4B,EAAE,MAAM,sCAAsC,CAAC;AACpF,YAAY,EACV,YAAY,EACZ,oBAAoB,EACpB,qBAAqB,EACrB,kBAAkB,EAClB,YAAY,GACb,MAAM,qBAAqB,CAAC"}
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,eAAe,EACf,kBAAkB,EAClB,YAAY,GACb,MAAM,qBAAqB,CAAC"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@ng-prism/plugin-coverage",
3
- "version": "22.2.0-beta.4",
3
+ "version": "22.2.0",
4
4
  "description": "Test coverage panel for ng-prism.",
5
5
  "ng-add": {
6
6
  "save": "devDependencies"