@ng-prism/plugin-perf 21.0.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.
Files changed (43) hide show
  1. package/dist/bundle/bundle-scanner.d.ts +3 -0
  2. package/dist/bundle/bundle-scanner.d.ts.map +1 -0
  3. package/dist/bundle/bundle-scanner.js +85 -0
  4. package/dist/bundle/bundle-section.component.d.ts +23 -0
  5. package/dist/bundle/bundle-section.component.d.ts.map +1 -0
  6. package/dist/bundle/bundle-section.component.js +321 -0
  7. package/dist/index.browser.d.ts +5 -0
  8. package/dist/index.browser.d.ts.map +1 -0
  9. package/dist/index.browser.js +3 -0
  10. package/dist/index.d.ts +5 -0
  11. package/dist/index.d.ts.map +1 -0
  12. package/dist/index.js +3 -0
  13. package/dist/memory/memory-section.component.d.ts +14 -0
  14. package/dist/memory/memory-section.component.d.ts.map +1 -0
  15. package/dist/memory/memory-section.component.js +323 -0
  16. package/dist/memory/perf-memory.service.d.ts +26 -0
  17. package/dist/memory/perf-memory.service.d.ts.map +1 -0
  18. package/dist/memory/perf-memory.service.js +62 -0
  19. package/dist/perf-config.token.d.ts +4 -0
  20. package/dist/perf-config.token.d.ts.map +1 -0
  21. package/dist/perf-config.token.js +2 -0
  22. package/dist/perf-panel.component.d.ts +18 -0
  23. package/dist/perf-panel.component.d.ts.map +1 -0
  24. package/dist/perf-panel.component.js +247 -0
  25. package/dist/perf-plugin.browser.d.ts +4 -0
  26. package/dist/perf-plugin.browser.d.ts.map +1 -0
  27. package/dist/perf-plugin.browser.js +14 -0
  28. package/dist/perf-plugin.d.ts +4 -0
  29. package/dist/perf-plugin.d.ts.map +1 -0
  30. package/dist/perf-plugin.js +27 -0
  31. package/dist/perf.types.d.ts +31 -0
  32. package/dist/perf.types.d.ts.map +1 -0
  33. package/dist/perf.types.js +8 -0
  34. package/dist/render/perf-render.service.d.ts +19 -0
  35. package/dist/render/perf-render.service.d.ts.map +1 -0
  36. package/dist/render/perf-render.service.js +73 -0
  37. package/dist/render/render-section.component.d.ts +13 -0
  38. package/dist/render/render-section.component.d.ts.map +1 -0
  39. package/dist/render/render-section.component.js +205 -0
  40. package/dist/render/sparkline.component.d.ts +23 -0
  41. package/dist/render/sparkline.component.d.ts.map +1 -0
  42. package/dist/render/sparkline.component.js +165 -0
  43. package/package.json +49 -0
@@ -0,0 +1,323 @@
1
+ import { ChangeDetectionStrategy, Component, computed, input } from '@angular/core';
2
+ import * as i0 from "@angular/core";
3
+ function MemorySectionComponent_Conditional_0_Conditional_0_Template(rf, ctx) { if (rf & 1) {
4
+ i0.ɵɵdomElementStart(0, "div", 0)(1, "div", 1);
5
+ i0.ɵɵtext(2, "\uD83E\uDDE0");
6
+ i0.ɵɵdomElementEnd();
7
+ i0.ɵɵdomElementStart(3, "div", 2);
8
+ i0.ɵɵtext(4, "Memory API not available");
9
+ i0.ɵɵdomElementEnd();
10
+ i0.ɵɵdomElementStart(5, "div", 3);
11
+ i0.ɵɵtext(6, "performance.memory is Chrome-only (non-standard)");
12
+ i0.ɵɵdomElementEnd()();
13
+ } }
14
+ function MemorySectionComponent_Conditional_0_Conditional_1_Conditional_28_Conditional_18_Template(rf, ctx) { if (rf & 1) {
15
+ i0.ɵɵdomElementStart(0, "div", 16)(1, "span", 17);
16
+ i0.ɵɵtext(2, "after destroy");
17
+ i0.ɵɵdomElementEnd();
18
+ i0.ɵɵdomElementStart(3, "div", 18);
19
+ i0.ɵɵdomElement(4, "div", 23);
20
+ i0.ɵɵdomElementEnd();
21
+ i0.ɵɵdomElementStart(5, "span", 24);
22
+ i0.ɵɵtext(6);
23
+ i0.ɵɵdomElementEnd()();
24
+ } if (rf & 2) {
25
+ let tmp_5_0;
26
+ let tmp_6_0;
27
+ const svc_r1 = i0.ɵɵnextContext(3);
28
+ const ctx_r1 = i0.ɵɵnextContext();
29
+ i0.ɵɵadvance(4);
30
+ i0.ɵɵstyleProp("width", ctx_r1.barPercent((tmp_5_0 = svc_r1.afterDestroy()) == null ? null : tmp_5_0.bytes), "%");
31
+ i0.ɵɵadvance(2);
32
+ i0.ɵɵtextInterpolate1("", ctx_r1.formatMb((tmp_6_0 = svc_r1.afterDestroy()) == null ? null : tmp_6_0.bytes), " MB");
33
+ } }
34
+ function MemorySectionComponent_Conditional_0_Conditional_1_Conditional_28_Template(rf, ctx) { if (rf & 1) {
35
+ i0.ɵɵdomElementStart(0, "div", 10)(1, "div", 6);
36
+ i0.ɵɵtext(2, "Heap Comparison");
37
+ i0.ɵɵdomElementEnd();
38
+ i0.ɵɵdomElementStart(3, "div", 15)(4, "div", 16)(5, "span", 17);
39
+ i0.ɵɵtext(6, "before");
40
+ i0.ɵɵdomElementEnd();
41
+ i0.ɵɵdomElementStart(7, "div", 18);
42
+ i0.ɵɵdomElement(8, "div", 19);
43
+ i0.ɵɵdomElementEnd();
44
+ i0.ɵɵdomElementStart(9, "span", 20);
45
+ i0.ɵɵtext(10);
46
+ i0.ɵɵdomElementEnd()();
47
+ i0.ɵɵdomElementStart(11, "div", 16)(12, "span", 17);
48
+ i0.ɵɵtext(13, "after create");
49
+ i0.ɵɵdomElementEnd();
50
+ i0.ɵɵdomElementStart(14, "div", 18);
51
+ i0.ɵɵdomElement(15, "div", 21);
52
+ i0.ɵɵdomElementEnd();
53
+ i0.ɵɵdomElementStart(16, "span", 22);
54
+ i0.ɵɵtext(17);
55
+ i0.ɵɵdomElementEnd()();
56
+ i0.ɵɵconditionalCreate(18, MemorySectionComponent_Conditional_0_Conditional_1_Conditional_28_Conditional_18_Template, 7, 3, "div", 16);
57
+ i0.ɵɵdomElementEnd()();
58
+ } if (rf & 2) {
59
+ let tmp_4_0;
60
+ let tmp_5_0;
61
+ let tmp_6_0;
62
+ let tmp_7_0;
63
+ const svc_r1 = i0.ɵɵnextContext(2);
64
+ const ctx_r1 = i0.ɵɵnextContext();
65
+ i0.ɵɵadvance(8);
66
+ i0.ɵɵstyleProp("width", ctx_r1.barPercent((tmp_4_0 = svc_r1.beforeCreate()) == null ? null : tmp_4_0.bytes), "%");
67
+ i0.ɵɵadvance(2);
68
+ i0.ɵɵtextInterpolate1("", ctx_r1.formatMb((tmp_5_0 = svc_r1.beforeCreate()) == null ? null : tmp_5_0.bytes), " MB");
69
+ i0.ɵɵadvance(5);
70
+ i0.ɵɵstyleProp("width", ctx_r1.barPercent((tmp_6_0 = svc_r1.afterCreate()) == null ? null : tmp_6_0.bytes), "%");
71
+ i0.ɵɵadvance(2);
72
+ i0.ɵɵtextInterpolate1("", ctx_r1.formatMb((tmp_7_0 = svc_r1.afterCreate()) == null ? null : tmp_7_0.bytes), " MB");
73
+ i0.ɵɵadvance();
74
+ i0.ɵɵconditional(svc_r1.afterDestroy() ? 18 : -1);
75
+ } }
76
+ function MemorySectionComponent_Conditional_0_Conditional_1_Conditional_32_Template(rf, ctx) { if (rf & 1) {
77
+ i0.ɵɵdomElementStart(0, "div", 12);
78
+ i0.ɵɵdomElement(1, "div", 25);
79
+ i0.ɵɵtext(2);
80
+ i0.ɵɵdomElementEnd();
81
+ } if (rf & 2) {
82
+ let tmp_4_0;
83
+ const svc_r1 = i0.ɵɵnextContext(2);
84
+ const ctx_r1 = i0.ɵɵnextContext();
85
+ i0.ɵɵadvance(2);
86
+ i0.ɵɵtextInterpolate1(" No significant leak detected \u2014 residual ", ctx_r1.formatMb(svc_r1.residual() + (((tmp_4_0 = svc_r1.beforeCreate()) == null ? null : tmp_4_0.bytes) ?? 0)), " MB within threshold ");
87
+ } }
88
+ function MemorySectionComponent_Conditional_0_Conditional_1_Conditional_33_Template(rf, ctx) { if (rf & 1) {
89
+ i0.ɵɵdomElementStart(0, "div", 13);
90
+ i0.ɵɵdomElement(1, "div", 25);
91
+ i0.ɵɵtext(2);
92
+ i0.ɵɵdomElementEnd();
93
+ } if (rf & 2) {
94
+ const svc_r1 = i0.ɵɵnextContext(2);
95
+ const ctx_r1 = i0.ɵɵnextContext();
96
+ i0.ɵɵadvance(2);
97
+ i0.ɵɵtextInterpolate1(" Possible leak \u2014 +", ctx_r1.formatMb(svc_r1.residual()), " MB not reclaimed after destroy ");
98
+ } }
99
+ function MemorySectionComponent_Conditional_0_Conditional_1_Template(rf, ctx) { if (rf & 1) {
100
+ i0.ɵɵdomElementStart(0, "div", 4)(1, "div", 5)(2, "div", 6);
101
+ i0.ɵɵtext(3, "Before Create");
102
+ i0.ɵɵdomElementEnd();
103
+ i0.ɵɵdomElementStart(4, "div", 7);
104
+ i0.ɵɵtext(5);
105
+ i0.ɵɵdomElementStart(6, "span", 8);
106
+ i0.ɵɵtext(7, " MB");
107
+ i0.ɵɵdomElementEnd()();
108
+ i0.ɵɵdomElementStart(8, "div", 9);
109
+ i0.ɵɵtext(9, "baseline heap");
110
+ i0.ɵɵdomElementEnd()();
111
+ i0.ɵɵdomElementStart(10, "div", 5)(11, "div", 6);
112
+ i0.ɵɵtext(12, "After Create");
113
+ i0.ɵɵdomElementEnd();
114
+ i0.ɵɵdomElementStart(13, "div", 7);
115
+ i0.ɵɵtext(14);
116
+ i0.ɵɵdomElementStart(15, "span", 8);
117
+ i0.ɵɵtext(16, " MB");
118
+ i0.ɵɵdomElementEnd()();
119
+ i0.ɵɵdomElementStart(17, "div", 9);
120
+ i0.ɵɵtext(18);
121
+ i0.ɵɵdomElementEnd()();
122
+ i0.ɵɵdomElementStart(19, "div", 5)(20, "div", 6);
123
+ i0.ɵɵtext(21, "After Destroy");
124
+ i0.ɵɵdomElementEnd();
125
+ i0.ɵɵdomElementStart(22, "div", 7);
126
+ i0.ɵɵtext(23);
127
+ i0.ɵɵdomElementStart(24, "span", 8);
128
+ i0.ɵɵtext(25, " MB");
129
+ i0.ɵɵdomElementEnd()();
130
+ i0.ɵɵdomElementStart(26, "div", 9);
131
+ i0.ɵɵtext(27);
132
+ i0.ɵɵdomElementEnd()()();
133
+ i0.ɵɵconditionalCreate(28, MemorySectionComponent_Conditional_0_Conditional_1_Conditional_28_Template, 19, 7, "div", 10);
134
+ i0.ɵɵdomElementStart(29, "div", 11)(30, "div", 6);
135
+ i0.ɵɵtext(31, "Leak Analysis");
136
+ i0.ɵɵdomElementEnd();
137
+ i0.ɵɵconditionalCreate(32, MemorySectionComponent_Conditional_0_Conditional_1_Conditional_32_Template, 3, 1, "div", 12)(33, MemorySectionComponent_Conditional_0_Conditional_1_Conditional_33_Template, 3, 1, "div", 13);
138
+ i0.ɵɵdomElementStart(34, "div", 14);
139
+ i0.ɵɵtext(35, " performance.memory is Chrome-only (non-standard). Not available in other browsers. ");
140
+ i0.ɵɵdomElementEnd()();
141
+ } if (rf & 2) {
142
+ let tmp_3_0;
143
+ let tmp_5_0;
144
+ let tmp_8_0;
145
+ const svc_r1 = i0.ɵɵnextContext();
146
+ const ctx_r1 = i0.ɵɵnextContext();
147
+ i0.ɵɵadvance(5);
148
+ i0.ɵɵtextInterpolate(ctx_r1.formatMb((tmp_3_0 = svc_r1.beforeCreate()) == null ? null : tmp_3_0.bytes));
149
+ i0.ɵɵadvance(8);
150
+ i0.ɵɵclassProp("delta-pos", svc_r1.delta() !== null && svc_r1.delta() > 0);
151
+ i0.ɵɵadvance();
152
+ i0.ɵɵtextInterpolate1(" ", ctx_r1.formatMb((tmp_5_0 = svc_r1.afterCreate()) == null ? null : tmp_5_0.bytes));
153
+ i0.ɵɵadvance(4);
154
+ i0.ɵɵtextInterpolate(ctx_r1.deltaText());
155
+ i0.ɵɵadvance(4);
156
+ i0.ɵɵclassMap(ctx_r1.destroyClass());
157
+ i0.ɵɵadvance();
158
+ i0.ɵɵtextInterpolate1(" ", ctx_r1.formatMb((tmp_8_0 = svc_r1.afterDestroy()) == null ? null : tmp_8_0.bytes));
159
+ i0.ɵɵadvance(4);
160
+ i0.ɵɵtextInterpolate(ctx_r1.residualText());
161
+ i0.ɵɵadvance();
162
+ i0.ɵɵconditional(svc_r1.beforeCreate() && svc_r1.afterCreate() ? 28 : -1);
163
+ i0.ɵɵadvance(4);
164
+ i0.ɵɵconditional(svc_r1.leakStatus() === "ok" ? 32 : svc_r1.leakStatus() === "warn" ? 33 : -1);
165
+ } }
166
+ function MemorySectionComponent_Conditional_0_Conditional_2_Template(rf, ctx) { if (rf & 1) {
167
+ i0.ɵɵdomElementStart(0, "div", 0)(1, "div", 1);
168
+ i0.ɵɵtext(2, "\uD83E\uDDE0");
169
+ i0.ɵɵdomElementEnd();
170
+ i0.ɵɵdomElementStart(3, "div", 2);
171
+ i0.ɵɵtext(4, "No memory snapshots yet");
172
+ i0.ɵɵdomElementEnd();
173
+ i0.ɵɵdomElementStart(5, "div", 3);
174
+ i0.ɵɵtext(6, "Click Snapshot to capture heap data");
175
+ i0.ɵɵdomElementEnd()();
176
+ } }
177
+ function MemorySectionComponent_Conditional_0_Template(rf, ctx) { if (rf & 1) {
178
+ i0.ɵɵconditionalCreate(0, MemorySectionComponent_Conditional_0_Conditional_0_Template, 7, 0, "div", 0)(1, MemorySectionComponent_Conditional_0_Conditional_1_Template, 36, 11)(2, MemorySectionComponent_Conditional_0_Conditional_2_Template, 7, 0, "div", 0);
179
+ } if (rf & 2) {
180
+ const svc_r1 = ctx;
181
+ i0.ɵɵconditional(!svc_r1.available() ? 0 : svc_r1.snapshots().length > 0 ? 1 : 2);
182
+ } }
183
+ export class MemorySectionComponent {
184
+ memoryService = input.required(...(ngDevMode ? [{ debugName: "memoryService" }] : []));
185
+ maxBytes = computed(() => {
186
+ const svc = this.memoryService();
187
+ const vals = [
188
+ svc.beforeCreate()?.bytes ?? 0,
189
+ svc.afterCreate()?.bytes ?? 0,
190
+ svc.afterDestroy()?.bytes ?? 0,
191
+ ];
192
+ return Math.max(...vals);
193
+ }, ...(ngDevMode ? [{ debugName: "maxBytes" }] : []));
194
+ deltaText = computed(() => {
195
+ const d = this.memoryService().delta();
196
+ if (d === null)
197
+ return '';
198
+ return `+${this.formatMb(d)} MB delta`;
199
+ }, ...(ngDevMode ? [{ debugName: "deltaText" }] : []));
200
+ residualText = computed(() => {
201
+ const r = this.memoryService().residual();
202
+ if (r === null)
203
+ return '';
204
+ return `+${this.formatMb(r)} MB residual`;
205
+ }, ...(ngDevMode ? [{ debugName: "residualText" }] : []));
206
+ destroyClass = computed(() => {
207
+ const status = this.memoryService().leakStatus();
208
+ if (status === 'ok')
209
+ return 'delta-ok';
210
+ if (status === 'warn')
211
+ return 'delta-neg';
212
+ return '';
213
+ }, ...(ngDevMode ? [{ debugName: "destroyClass" }] : []));
214
+ barPercent(bytes) {
215
+ if (!bytes || this.maxBytes() === 0)
216
+ return 0;
217
+ return (bytes / this.maxBytes()) * 100;
218
+ }
219
+ formatMb(bytes) {
220
+ if (bytes === null || bytes === undefined)
221
+ return '—';
222
+ return (bytes / (1024 * 1024)).toFixed(1);
223
+ }
224
+ static ɵfac = function MemorySectionComponent_Factory(__ngFactoryType__) { return new (__ngFactoryType__ || MemorySectionComponent)(); };
225
+ static ɵcmp = /*@__PURE__*/ i0.ɵɵdefineComponent({ type: MemorySectionComponent, selectors: [["perf-memory-section"]], inputs: { memoryService: [1, "memoryService"] }, decls: 1, vars: 1, consts: [[1, "prism-perf-empty"], [1, "prism-perf-empty-icon"], [1, "prism-perf-empty-text"], [1, "prism-perf-empty-hint"], [1, "prism-perf-memory-hero"], [1, "prism-perf-memory-metric"], [1, "prism-perf-label"], [1, "prism-perf-memory-value"], [1, "prism-perf-memory-unit"], [1, "prism-perf-sub"], [1, "prism-perf-memory-bar-section"], [1, "prism-perf-memory-leak-section"], [1, "prism-perf-leak-badge", "ok"], [1, "prism-perf-leak-badge", "warn"], [1, "prism-perf-memory-disclaimer"], [1, "prism-perf-memory-bars"], [1, "prism-perf-memory-bar-row"], [1, "prism-perf-memory-bar-label"], [1, "prism-perf-memory-bar-track"], [1, "prism-perf-memory-bar-fill", 2, "background", "rgba(167,139,250,0.4)"], [1, "prism-perf-memory-bar-val"], [1, "prism-perf-memory-bar-fill", 2, "background", "linear-gradient(90deg,rgba(167,139,250,0.4),rgba(251,191,36,0.6))"], [1, "prism-perf-memory-bar-val", 2, "color", "var(--perf-warn, #fbbf24)"], [1, "prism-perf-memory-bar-fill", 2, "background", "rgba(74,222,128,0.4)"], [1, "prism-perf-memory-bar-val", 2, "color", "var(--perf-ok, #4ade80)"], [1, "prism-perf-leak-dot"]], template: function MemorySectionComponent_Template(rf, ctx) { if (rf & 1) {
226
+ i0.ɵɵconditionalCreate(0, MemorySectionComponent_Conditional_0_Template, 3, 1);
227
+ } if (rf & 2) {
228
+ let tmp_0_0;
229
+ i0.ɵɵconditional((tmp_0_0 = ctx.memoryService()) ? 0 : -1, tmp_0_0);
230
+ } }, styles: [".prism-perf-memory-hero[_ngcontent-%COMP%] {\n display: grid;\n grid-template-columns: 1fr 1fr 1fr;\n border-bottom: 1px solid var(--prism-border, rgba(255,255,255,0.08));\n }\n .prism-perf-memory-metric[_ngcontent-%COMP%] {\n padding: 14px 16px;\n border-right: 1px solid var(--prism-border, rgba(255,255,255,0.08));\n display: flex;\n flex-direction: column;\n gap: 3px;\n }\n .prism-perf-memory-metric[_ngcontent-%COMP%]:last-child { border-right: none; }\n .prism-perf-memory-value[_ngcontent-%COMP%] {\n font-size: 20px;\n font-family: var(--prism-font-mono, monospace);\n font-weight: 600;\n color: var(--prism-text, #ede9f8);\n line-height: 1.1;\n }\n .prism-perf-memory-value.delta-pos[_ngcontent-%COMP%] { color: var(--perf-warn, #fbbf24); }\n .prism-perf-memory-value.delta-ok[_ngcontent-%COMP%] { color: var(--perf-ok, #4ade80); }\n .prism-perf-memory-value.delta-neg[_ngcontent-%COMP%] { color: var(--perf-crit, #f87171); }\n .prism-perf-memory-unit[_ngcontent-%COMP%] { font-size: 11px; font-weight: 400; color: var(--prism-text-muted, #8476a2); }\n .prism-perf-label[_ngcontent-%COMP%] {\n font-size: 9px;\n font-weight: 600;\n letter-spacing: 0.1em;\n text-transform: uppercase;\n color: var(--prism-text-ghost, #6a5d87);\n }\n .prism-perf-sub[_ngcontent-%COMP%] {\n font-size: 10px;\n color: var(--prism-text-ghost, #6a5d87);\n font-family: var(--prism-font-mono, monospace);\n }\n .prism-perf-memory-bar-section[_ngcontent-%COMP%] {\n padding: 14px 16px;\n border-bottom: 1px solid var(--prism-border, rgba(255,255,255,0.08));\n }\n .prism-perf-memory-bars[_ngcontent-%COMP%] {\n display: flex;\n flex-direction: column;\n gap: 8px;\n margin-top: 12px;\n }\n .prism-perf-memory-bar-row[_ngcontent-%COMP%] {\n display: flex;\n align-items: center;\n gap: 10px;\n }\n .prism-perf-memory-bar-label[_ngcontent-%COMP%] {\n font-size: 10px;\n color: var(--prism-text-muted, #8476a2);\n width: 80px;\n flex-shrink: 0;\n font-family: var(--prism-font-mono, monospace);\n }\n .prism-perf-memory-bar-track[_ngcontent-%COMP%] {\n flex: 1;\n height: 8px;\n background: rgba(255,255,255,0.04);\n border-radius: 4px;\n overflow: hidden;\n }\n .prism-perf-memory-bar-fill[_ngcontent-%COMP%] {\n height: 100%;\n border-radius: 4px;\n }\n .prism-perf-memory-bar-val[_ngcontent-%COMP%] {\n font-size: 11px;\n font-family: var(--prism-font-mono, monospace);\n color: var(--prism-text-2, #b0a6c8);\n width: 60px;\n text-align: right;\n flex-shrink: 0;\n }\n .prism-perf-memory-leak-section[_ngcontent-%COMP%] {\n padding: 14px 16px;\n }\n .prism-perf-leak-badge[_ngcontent-%COMP%] {\n display: inline-flex;\n align-items: center;\n gap: 8px;\n padding: 8px 14px;\n border-radius: 5px;\n font-size: 12px;\n font-weight: 500;\n margin-top: 8px;\n }\n .prism-perf-leak-badge.ok[_ngcontent-%COMP%] {\n background: color-mix(in srgb, var(--perf-ok, #4ade80) 10%, transparent);\n border: 1px solid color-mix(in srgb, var(--perf-ok, #4ade80) 25%, transparent);\n color: var(--perf-ok, #4ade80);\n }\n .prism-perf-leak-badge.warn[_ngcontent-%COMP%] {\n background: color-mix(in srgb, var(--perf-warn, #fbbf24) 10%, transparent);\n border: 1px solid color-mix(in srgb, var(--perf-warn, #fbbf24) 25%, transparent);\n color: var(--perf-warn, #fbbf24);\n }\n .prism-perf-leak-dot[_ngcontent-%COMP%] {\n width: 6px;\n height: 6px;\n border-radius: 50%;\n }\n .ok[_ngcontent-%COMP%] .prism-perf-leak-dot[_ngcontent-%COMP%] { background: var(--perf-ok, #4ade80); }\n .warn[_ngcontent-%COMP%] .prism-perf-leak-dot[_ngcontent-%COMP%] { background: var(--perf-warn, #fbbf24); box-shadow: 0 0 6px var(--perf-warn, #fbbf24); }\n .prism-perf-memory-disclaimer[_ngcontent-%COMP%] {\n margin-top: 10px;\n font-size: 10px;\n color: var(--prism-text-ghost, #6a5d87);\n font-family: var(--prism-font-mono, monospace);\n }\n .prism-perf-empty[_ngcontent-%COMP%] {\n display: flex;\n flex-direction: column;\n align-items: center;\n justify-content: center;\n gap: 8px;\n height: 100%;\n min-height: 180px;\n }\n .prism-perf-empty-icon[_ngcontent-%COMP%] { font-size: 28px; opacity: 0.2; }\n .prism-perf-empty-text[_ngcontent-%COMP%] { font-size: 12px; color: var(--prism-text-ghost, #6a5d87); }\n .prism-perf-empty-hint[_ngcontent-%COMP%] { font-size: 11px; color: var(--prism-text-ghost, #6a5d87); opacity: 0.6; }"], changeDetection: 0 });
231
+ }
232
+ (() => { (typeof ngDevMode === "undefined" || ngDevMode) && i0.ɵsetClassMetadata(MemorySectionComponent, [{
233
+ type: Component,
234
+ args: [{ selector: 'perf-memory-section', standalone: true, changeDetection: ChangeDetectionStrategy.OnPush, template: `
235
+ @if (memoryService(); as svc) {
236
+ @if (!svc.available()) {
237
+ <div class="prism-perf-empty">
238
+ <div class="prism-perf-empty-icon">&#129504;</div>
239
+ <div class="prism-perf-empty-text">Memory API not available</div>
240
+ <div class="prism-perf-empty-hint">performance.memory is Chrome-only (non-standard)</div>
241
+ </div>
242
+ } @else if (svc.snapshots().length > 0) {
243
+ <div class="prism-perf-memory-hero">
244
+ <div class="prism-perf-memory-metric">
245
+ <div class="prism-perf-label">Before Create</div>
246
+ <div class="prism-perf-memory-value">{{ formatMb(svc.beforeCreate()?.bytes) }}<span class="prism-perf-memory-unit"> MB</span></div>
247
+ <div class="prism-perf-sub">baseline heap</div>
248
+ </div>
249
+ <div class="prism-perf-memory-metric">
250
+ <div class="prism-perf-label">After Create</div>
251
+ <div class="prism-perf-memory-value" [class.delta-pos]="svc.delta() !== null && svc.delta()! > 0">
252
+ {{ formatMb(svc.afterCreate()?.bytes) }}<span class="prism-perf-memory-unit"> MB</span>
253
+ </div>
254
+ <div class="prism-perf-sub">{{ deltaText() }}</div>
255
+ </div>
256
+ <div class="prism-perf-memory-metric">
257
+ <div class="prism-perf-label">After Destroy</div>
258
+ <div class="prism-perf-memory-value" [class]="destroyClass()">
259
+ {{ formatMb(svc.afterDestroy()?.bytes) }}<span class="prism-perf-memory-unit"> MB</span>
260
+ </div>
261
+ <div class="prism-perf-sub">{{ residualText() }}</div>
262
+ </div>
263
+ </div>
264
+
265
+ @if (svc.beforeCreate() && svc.afterCreate()) {
266
+ <div class="prism-perf-memory-bar-section">
267
+ <div class="prism-perf-label">Heap Comparison</div>
268
+ <div class="prism-perf-memory-bars">
269
+ <div class="prism-perf-memory-bar-row">
270
+ <span class="prism-perf-memory-bar-label">before</span>
271
+ <div class="prism-perf-memory-bar-track">
272
+ <div class="prism-perf-memory-bar-fill" [style.width.%]="barPercent(svc.beforeCreate()?.bytes)" style="background:rgba(167,139,250,0.4)"></div>
273
+ </div>
274
+ <span class="prism-perf-memory-bar-val">{{ formatMb(svc.beforeCreate()?.bytes) }} MB</span>
275
+ </div>
276
+ <div class="prism-perf-memory-bar-row">
277
+ <span class="prism-perf-memory-bar-label">after create</span>
278
+ <div class="prism-perf-memory-bar-track">
279
+ <div class="prism-perf-memory-bar-fill" [style.width.%]="barPercent(svc.afterCreate()?.bytes)" style="background:linear-gradient(90deg,rgba(167,139,250,0.4),rgba(251,191,36,0.6))"></div>
280
+ </div>
281
+ <span class="prism-perf-memory-bar-val" style="color:var(--perf-warn, #fbbf24)">{{ formatMb(svc.afterCreate()?.bytes) }} MB</span>
282
+ </div>
283
+ @if (svc.afterDestroy()) {
284
+ <div class="prism-perf-memory-bar-row">
285
+ <span class="prism-perf-memory-bar-label">after destroy</span>
286
+ <div class="prism-perf-memory-bar-track">
287
+ <div class="prism-perf-memory-bar-fill" [style.width.%]="barPercent(svc.afterDestroy()?.bytes)" style="background:rgba(74,222,128,0.4)"></div>
288
+ </div>
289
+ <span class="prism-perf-memory-bar-val" style="color:var(--perf-ok, #4ade80)">{{ formatMb(svc.afterDestroy()?.bytes) }} MB</span>
290
+ </div>
291
+ }
292
+ </div>
293
+ </div>
294
+ }
295
+
296
+ <div class="prism-perf-memory-leak-section">
297
+ <div class="prism-perf-label">Leak Analysis</div>
298
+ @if (svc.leakStatus() === 'ok') {
299
+ <div class="prism-perf-leak-badge ok">
300
+ <div class="prism-perf-leak-dot"></div>
301
+ No significant leak detected — residual {{ formatMb(svc.residual()! + (svc.beforeCreate()?.bytes ?? 0)) }} MB within threshold
302
+ </div>
303
+ } @else if (svc.leakStatus() === 'warn') {
304
+ <div class="prism-perf-leak-badge warn">
305
+ <div class="prism-perf-leak-dot"></div>
306
+ Possible leak — +{{ formatMb(svc.residual()!) }} MB not reclaimed after destroy
307
+ </div>
308
+ }
309
+ <div class="prism-perf-memory-disclaimer">
310
+ performance.memory is Chrome-only (non-standard). Not available in other browsers.
311
+ </div>
312
+ </div>
313
+ } @else {
314
+ <div class="prism-perf-empty">
315
+ <div class="prism-perf-empty-icon">&#129504;</div>
316
+ <div class="prism-perf-empty-text">No memory snapshots yet</div>
317
+ <div class="prism-perf-empty-hint">Click Snapshot to capture heap data</div>
318
+ </div>
319
+ }
320
+ }
321
+ `, styles: ["\n .prism-perf-memory-hero {\n display: grid;\n grid-template-columns: 1fr 1fr 1fr;\n border-bottom: 1px solid var(--prism-border, rgba(255,255,255,0.08));\n }\n .prism-perf-memory-metric {\n padding: 14px 16px;\n border-right: 1px solid var(--prism-border, rgba(255,255,255,0.08));\n display: flex;\n flex-direction: column;\n gap: 3px;\n }\n .prism-perf-memory-metric:last-child { border-right: none; }\n .prism-perf-memory-value {\n font-size: 20px;\n font-family: var(--prism-font-mono, monospace);\n font-weight: 600;\n color: var(--prism-text, #ede9f8);\n line-height: 1.1;\n }\n .prism-perf-memory-value.delta-pos { color: var(--perf-warn, #fbbf24); }\n .prism-perf-memory-value.delta-ok { color: var(--perf-ok, #4ade80); }\n .prism-perf-memory-value.delta-neg { color: var(--perf-crit, #f87171); }\n .prism-perf-memory-unit { font-size: 11px; font-weight: 400; color: var(--prism-text-muted, #8476a2); }\n .prism-perf-label {\n font-size: 9px;\n font-weight: 600;\n letter-spacing: 0.1em;\n text-transform: uppercase;\n color: var(--prism-text-ghost, #6a5d87);\n }\n .prism-perf-sub {\n font-size: 10px;\n color: var(--prism-text-ghost, #6a5d87);\n font-family: var(--prism-font-mono, monospace);\n }\n .prism-perf-memory-bar-section {\n padding: 14px 16px;\n border-bottom: 1px solid var(--prism-border, rgba(255,255,255,0.08));\n }\n .prism-perf-memory-bars {\n display: flex;\n flex-direction: column;\n gap: 8px;\n margin-top: 12px;\n }\n .prism-perf-memory-bar-row {\n display: flex;\n align-items: center;\n gap: 10px;\n }\n .prism-perf-memory-bar-label {\n font-size: 10px;\n color: var(--prism-text-muted, #8476a2);\n width: 80px;\n flex-shrink: 0;\n font-family: var(--prism-font-mono, monospace);\n }\n .prism-perf-memory-bar-track {\n flex: 1;\n height: 8px;\n background: rgba(255,255,255,0.04);\n border-radius: 4px;\n overflow: hidden;\n }\n .prism-perf-memory-bar-fill {\n height: 100%;\n border-radius: 4px;\n }\n .prism-perf-memory-bar-val {\n font-size: 11px;\n font-family: var(--prism-font-mono, monospace);\n color: var(--prism-text-2, #b0a6c8);\n width: 60px;\n text-align: right;\n flex-shrink: 0;\n }\n .prism-perf-memory-leak-section {\n padding: 14px 16px;\n }\n .prism-perf-leak-badge {\n display: inline-flex;\n align-items: center;\n gap: 8px;\n padding: 8px 14px;\n border-radius: 5px;\n font-size: 12px;\n font-weight: 500;\n margin-top: 8px;\n }\n .prism-perf-leak-badge.ok {\n background: color-mix(in srgb, var(--perf-ok, #4ade80) 10%, transparent);\n border: 1px solid color-mix(in srgb, var(--perf-ok, #4ade80) 25%, transparent);\n color: var(--perf-ok, #4ade80);\n }\n .prism-perf-leak-badge.warn {\n background: color-mix(in srgb, var(--perf-warn, #fbbf24) 10%, transparent);\n border: 1px solid color-mix(in srgb, var(--perf-warn, #fbbf24) 25%, transparent);\n color: var(--perf-warn, #fbbf24);\n }\n .prism-perf-leak-dot {\n width: 6px;\n height: 6px;\n border-radius: 50%;\n }\n .ok .prism-perf-leak-dot { background: var(--perf-ok, #4ade80); }\n .warn .prism-perf-leak-dot { background: var(--perf-warn, #fbbf24); box-shadow: 0 0 6px var(--perf-warn, #fbbf24); }\n .prism-perf-memory-disclaimer {\n margin-top: 10px;\n font-size: 10px;\n color: var(--prism-text-ghost, #6a5d87);\n font-family: var(--prism-font-mono, monospace);\n }\n .prism-perf-empty {\n display: flex;\n flex-direction: column;\n align-items: center;\n justify-content: center;\n gap: 8px;\n height: 100%;\n min-height: 180px;\n }\n .prism-perf-empty-icon { font-size: 28px; opacity: 0.2; }\n .prism-perf-empty-text { font-size: 12px; color: var(--prism-text-ghost, #6a5d87); }\n .prism-perf-empty-hint { font-size: 11px; color: var(--prism-text-ghost, #6a5d87); opacity: 0.6; }\n "] }]
322
+ }], null, { memoryService: [{ type: i0.Input, args: [{ isSignal: true, alias: "memoryService", required: true }] }] }); })();
323
+ (() => { (typeof ngDevMode === "undefined" || ngDevMode) && i0.ɵsetClassDebugInfo(MemorySectionComponent, { className: "MemorySectionComponent", filePath: "memory/memory-section.component.ts", lineNumber: 224 }); })();
@@ -0,0 +1,26 @@
1
+ import type { PrismRendererHooks } from '@ng-prism/core/plugin';
2
+ export interface HeapSnapshot {
3
+ label: string;
4
+ bytes: number;
5
+ timestamp: number;
6
+ }
7
+ export declare class PerfMemoryService implements PrismRendererHooks {
8
+ static getInstance(): PerfMemoryService;
9
+ readonly snapshots: import("@angular/core").WritableSignal<HeapSnapshot[]>;
10
+ readonly available: import("@angular/core").Signal<boolean>;
11
+ private gcDelay;
12
+ readonly beforeCreate: import("@angular/core").Signal<HeapSnapshot | null>;
13
+ readonly afterCreate: import("@angular/core").Signal<HeapSnapshot | null>;
14
+ readonly afterDestroy: import("@angular/core").Signal<HeapSnapshot | null>;
15
+ readonly delta: import("@angular/core").Signal<number | null>;
16
+ readonly residual: import("@angular/core").Signal<number | null>;
17
+ readonly leakStatus: import("@angular/core").Signal<"ok" | "warn" | "unknown">;
18
+ configure(gcDelayMs: number): void;
19
+ onBeforeCreate(_selector: string): void;
20
+ onAfterCreate(_selector: string): void;
21
+ onAfterDestroy(_selector: string): void;
22
+ takeSnapshot(label: string): void;
23
+ clear(): void;
24
+ private findSnapshot;
25
+ }
26
+ //# sourceMappingURL=perf-memory.service.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"perf-memory.service.d.ts","sourceRoot":"","sources":["../../src/memory/perf-memory.service.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,kBAAkB,EAAE,MAAM,uBAAuB,CAAC;AAEhE,MAAM,WAAW,YAAY;IAC3B,KAAK,EAAE,MAAM,CAAC;IACd,KAAK,EAAE,MAAM,CAAC;IACd,SAAS,EAAE,MAAM,CAAC;CACnB;AAID,qBAAa,iBAAkB,YAAW,kBAAkB;IAC1D,MAAM,CAAC,WAAW,IAAI,iBAAiB;IAKvC,QAAQ,CAAC,SAAS,yDAA8B;IAChD,QAAQ,CAAC,SAAS,0CAAiF;IAEnG,OAAO,CAAC,OAAO,CAAO;IAEtB,QAAQ,CAAC,YAAY,sDAAsD;IAC3E,QAAQ,CAAC,WAAW,sDAAqD;IACzE,QAAQ,CAAC,YAAY,sDAAsD;IAE3E,QAAQ,CAAC,KAAK,gDAKX;IAEH,QAAQ,CAAC,QAAQ,gDAKd;IAEH,QAAQ,CAAC,UAAU,4DAIhB;IAEH,SAAS,CAAC,SAAS,EAAE,MAAM,GAAG,IAAI;IAIlC,cAAc,CAAC,SAAS,EAAE,MAAM,GAAG,IAAI;IAIvC,aAAa,CAAC,SAAS,EAAE,MAAM,GAAG,IAAI;IAItC,cAAc,CAAC,SAAS,EAAE,MAAM,GAAG,IAAI;IAIvC,YAAY,CAAC,KAAK,EAAE,MAAM,GAAG,IAAI;IASjC,KAAK,IAAI,IAAI;IAIb,OAAO,CAAC,YAAY;CAGrB"}
@@ -0,0 +1,62 @@
1
+ import { signal, computed } from '@angular/core';
2
+ let instance = null;
3
+ export class PerfMemoryService {
4
+ static getInstance() {
5
+ if (!instance)
6
+ instance = new PerfMemoryService();
7
+ return instance;
8
+ }
9
+ snapshots = signal([], ...(ngDevMode ? [{ debugName: "snapshots" }] : []));
10
+ available = computed(() => typeof performance !== 'undefined' && 'memory' in performance, ...(ngDevMode ? [{ debugName: "available" }] : []));
11
+ gcDelay = 100;
12
+ beforeCreate = computed(() => this.findSnapshot('before-create'), ...(ngDevMode ? [{ debugName: "beforeCreate" }] : []));
13
+ afterCreate = computed(() => this.findSnapshot('after-create'), ...(ngDevMode ? [{ debugName: "afterCreate" }] : []));
14
+ afterDestroy = computed(() => this.findSnapshot('after-destroy'), ...(ngDevMode ? [{ debugName: "afterDestroy" }] : []));
15
+ delta = computed(() => {
16
+ const before = this.beforeCreate();
17
+ const after = this.afterCreate();
18
+ if (!before || !after)
19
+ return null;
20
+ return after.bytes - before.bytes;
21
+ }, ...(ngDevMode ? [{ debugName: "delta" }] : []));
22
+ residual = computed(() => {
23
+ const before = this.beforeCreate();
24
+ const destroy = this.afterDestroy();
25
+ if (!before || !destroy)
26
+ return null;
27
+ return destroy.bytes - before.bytes;
28
+ }, ...(ngDevMode ? [{ debugName: "residual" }] : []));
29
+ leakStatus = computed(() => {
30
+ const residualMb = this.residual();
31
+ if (residualMb === null)
32
+ return 'unknown';
33
+ return residualMb / (1024 * 1024) >= 0.5 ? 'warn' : 'ok';
34
+ }, ...(ngDevMode ? [{ debugName: "leakStatus" }] : []));
35
+ configure(gcDelayMs) {
36
+ this.gcDelay = gcDelayMs;
37
+ }
38
+ onBeforeCreate(_selector) {
39
+ this.takeSnapshot('before-create');
40
+ }
41
+ onAfterCreate(_selector) {
42
+ setTimeout(() => this.takeSnapshot('after-create'), 50);
43
+ }
44
+ onAfterDestroy(_selector) {
45
+ setTimeout(() => this.takeSnapshot('after-destroy'), this.gcDelay);
46
+ }
47
+ takeSnapshot(label) {
48
+ if (!this.available())
49
+ return;
50
+ const mem = performance.memory;
51
+ this.snapshots.update((arr) => [
52
+ ...arr.filter((s) => s.label !== label),
53
+ { label, bytes: mem.usedJSHeapSize, timestamp: Date.now() },
54
+ ]);
55
+ }
56
+ clear() {
57
+ this.snapshots.set([]);
58
+ }
59
+ findSnapshot(label) {
60
+ return this.snapshots().find((s) => s.label === label) ?? null;
61
+ }
62
+ }
@@ -0,0 +1,4 @@
1
+ import { InjectionToken } from '@angular/core';
2
+ import type { PerfPluginOptions } from './perf.types.js';
3
+ export declare const PERF_PLUGIN_CONFIG: InjectionToken<PerfPluginOptions>;
4
+ //# sourceMappingURL=perf-config.token.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"perf-config.token.d.ts","sourceRoot":"","sources":["../src/perf-config.token.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,cAAc,EAAE,MAAM,eAAe,CAAC;AAC/C,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,iBAAiB,CAAC;AAEzD,eAAO,MAAM,kBAAkB,mCAA8D,CAAC"}
@@ -0,0 +1,2 @@
1
+ import { InjectionToken } from '@angular/core';
2
+ export const PERF_PLUGIN_CONFIG = new InjectionToken('PERF_PLUGIN_CONFIG');
@@ -0,0 +1,18 @@
1
+ import type { BundleMetrics, PerfThresholds } from './perf.types.js';
2
+ import { PerfRenderService } from './render/perf-render.service.js';
3
+ import { PerfMemoryService } from './memory/perf-memory.service.js';
4
+ import * as i0 from "@angular/core";
5
+ type SubTab = 'bundle' | 'render' | 'memory';
6
+ export declare class PerfPanelComponent {
7
+ readonly activeComponent: import("@angular/core").InputSignal<unknown>;
8
+ readonly activeTab: import("@angular/core").WritableSignal<SubTab>;
9
+ readonly renderService: PerfRenderService;
10
+ readonly memoryService: PerfMemoryService;
11
+ readonly thresholds: PerfThresholds;
12
+ captureMemorySnapshots(): void;
13
+ readonly bundleMetrics: import("@angular/core").Signal<BundleMetrics | null>;
14
+ static ɵfac: i0.ɵɵFactoryDeclaration<PerfPanelComponent, never>;
15
+ static ɵcmp: i0.ɵɵComponentDeclaration<PerfPanelComponent, "prism-perf-panel", never, { "activeComponent": { "alias": "activeComponent"; "required": false; "isSignal": true; }; }, {}, never, never, true, never>;
16
+ }
17
+ export {};
18
+ //# sourceMappingURL=perf-panel.component.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"perf-panel.component.d.ts","sourceRoot":"","sources":["../src/perf-panel.component.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,aAAa,EAAE,cAAc,EAAE,MAAM,iBAAiB,CAAC;AAErE,OAAO,EAAE,iBAAiB,EAAE,MAAM,iCAAiC,CAAC;AACpE,OAAO,EAAE,iBAAiB,EAAE,MAAM,iCAAiC,CAAC;;AAKpE,KAAK,MAAM,GAAG,QAAQ,GAAG,QAAQ,GAAG,QAAQ,CAAC;AAE7C,qBA2Ma,kBAAkB;IAC7B,QAAQ,CAAC,eAAe,+CAAwB;IAEhD,QAAQ,CAAC,SAAS,iDAA4B;IAC9C,QAAQ,CAAC,aAAa,oBAAmC;IACzD,QAAQ,CAAC,aAAa,oBAAmC;IAEzD,QAAQ,CAAC,UAAU,EAAE,cAAc,CAAsB;IAEzD,sBAAsB,IAAI,IAAI;IAK9B,QAAQ,CAAC,aAAa,uDAGnB;yCAjBQ,kBAAkB;2CAAlB,kBAAkB;CAkB9B"}