angular-scan 0.2.3 → 1.0.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/fesm2022/angular-scan.mjs +103 -104
- package/fesm2022/angular-scan.mjs.map +1 -1
- package/package.json +1 -1
- package/LICENSE +0 -21
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import * as i0 from '@angular/core';
|
|
2
|
-
import { signal, Injectable, InjectionToken, inject, DOCUMENT as DOCUMENT$1, isDevMode, Injector, runInInjectionContext, afterEveryRender, ChangeDetectionStrategy, Component, makeEnvironmentProviders, provideEnvironmentInitializer, EnvironmentInjector, ApplicationRef, createComponent } from '@angular/core';
|
|
3
|
-
import { DOCUMENT } from '@angular/common';
|
|
2
|
+
import { signal, Injectable, InjectionToken, inject, DOCUMENT as DOCUMENT$1, isDevMode, Injector, runInInjectionContext, afterEveryRender, ChangeDetectionStrategy, Component, makeEnvironmentProviders, provideEnvironmentInitializer, PLATFORM_ID, EnvironmentInjector, ApplicationRef, createComponent } from '@angular/core';
|
|
3
|
+
import { DOCUMENT, isPlatformBrowser } from '@angular/common';
|
|
4
4
|
|
|
5
5
|
class ComponentTracker {
|
|
6
6
|
byInstance = new WeakMap();
|
|
@@ -50,10 +50,10 @@ class ComponentTracker {
|
|
|
50
50
|
this.totalUnnecessary.set(0);
|
|
51
51
|
this.trackedComponents.set([]);
|
|
52
52
|
}
|
|
53
|
-
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.
|
|
54
|
-
static ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "21.2.
|
|
53
|
+
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.5", ngImport: i0, type: ComponentTracker, deps: [], target: i0.ɵɵFactoryTarget.Injectable });
|
|
54
|
+
static ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "21.2.5", ngImport: i0, type: ComponentTracker, providedIn: 'root' });
|
|
55
55
|
}
|
|
56
|
-
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.
|
|
56
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.5", ngImport: i0, type: ComponentTracker, decorators: [{
|
|
57
57
|
type: Injectable,
|
|
58
58
|
args: [{ providedIn: 'root' }]
|
|
59
59
|
}] });
|
|
@@ -80,9 +80,15 @@ function getNgDebugApi() {
|
|
|
80
80
|
return api;
|
|
81
81
|
}
|
|
82
82
|
|
|
83
|
-
const ANGULAR_SCAN_OPTIONS = new InjectionToken('ANGULAR_SCAN_OPTIONS', {
|
|
83
|
+
const ANGULAR_SCAN_OPTIONS = new InjectionToken('ANGULAR_SCAN_OPTIONS', {
|
|
84
|
+
providedIn: 'root',
|
|
85
|
+
factory: () => ({}),
|
|
86
|
+
});
|
|
84
87
|
/** The browser Window object. Resolves to null in SSR. */
|
|
85
|
-
const WINDOW = new InjectionToken('WINDOW', {
|
|
88
|
+
const WINDOW = new InjectionToken('WINDOW', {
|
|
89
|
+
providedIn: 'root',
|
|
90
|
+
factory: () => inject(DOCUMENT).defaultView,
|
|
91
|
+
});
|
|
86
92
|
|
|
87
93
|
class ScanConfigService {
|
|
88
94
|
options = inject(ANGULAR_SCAN_OPTIONS);
|
|
@@ -90,14 +96,67 @@ class ScanConfigService {
|
|
|
90
96
|
showOverlay = signal(true, ...(ngDevMode ? [{ debugName: "showOverlay" }] : /* istanbul ignore next */ []));
|
|
91
97
|
showBadges = signal(this.options.showBadges !== false, ...(ngDevMode ? [{ debugName: "showBadges" }] : /* istanbul ignore next */ []));
|
|
92
98
|
flashDurationMs = signal(this.options.flashDurationMs ?? 500, ...(ngDevMode ? [{ debugName: "flashDurationMs" }] : /* istanbul ignore next */ []));
|
|
93
|
-
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.
|
|
94
|
-
static ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "21.2.
|
|
99
|
+
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.5", ngImport: i0, type: ScanConfigService, deps: [], target: i0.ɵɵFactoryTarget.Injectable });
|
|
100
|
+
static ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "21.2.5", ngImport: i0, type: ScanConfigService, providedIn: 'root' });
|
|
95
101
|
}
|
|
96
|
-
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.
|
|
102
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.5", ngImport: i0, type: ScanConfigService, decorators: [{
|
|
97
103
|
type: Injectable,
|
|
98
104
|
args: [{ providedIn: 'root' }]
|
|
99
105
|
}] });
|
|
100
106
|
|
|
107
|
+
const BADGE_CSS = [
|
|
108
|
+
'position:absolute',
|
|
109
|
+
'top:2px',
|
|
110
|
+
'right:2px',
|
|
111
|
+
'z-index:2147483645',
|
|
112
|
+
'pointer-events:none',
|
|
113
|
+
'font:bold 9px/13px monospace',
|
|
114
|
+
'padding:1px 4px',
|
|
115
|
+
'border-radius:3px',
|
|
116
|
+
'min-width:16px',
|
|
117
|
+
'text-align:center',
|
|
118
|
+
'color:#fff',
|
|
119
|
+
'white-space:nowrap',
|
|
120
|
+
].join(';');
|
|
121
|
+
const BADGE_COLORS = {
|
|
122
|
+
render: '#ff9800',
|
|
123
|
+
unnecessary: '#f44336',
|
|
124
|
+
};
|
|
125
|
+
/**
|
|
126
|
+
* Creates or reuses the render-count badge on a host element.
|
|
127
|
+
* Returns the badge so callers can set extra attributes (e.g. `title`).
|
|
128
|
+
*/
|
|
129
|
+
function createOrUpdateBadge(badges, hostEl, count, kind, doc = document, win) {
|
|
130
|
+
let badge = badges.get(hostEl);
|
|
131
|
+
if (!badge) {
|
|
132
|
+
badge = doc.createElement('div');
|
|
133
|
+
badge.setAttribute('aria-hidden', 'true');
|
|
134
|
+
badge.setAttribute('role', 'presentation');
|
|
135
|
+
badge.style.cssText = BADGE_CSS;
|
|
136
|
+
ensurePositioned(hostEl, win);
|
|
137
|
+
hostEl.appendChild(badge);
|
|
138
|
+
badges.set(hostEl, badge);
|
|
139
|
+
}
|
|
140
|
+
badge.style.background = BADGE_COLORS[kind];
|
|
141
|
+
badge.textContent = String(count);
|
|
142
|
+
return badge;
|
|
143
|
+
}
|
|
144
|
+
function ensurePositioned(el, win) {
|
|
145
|
+
const htmlEl = el;
|
|
146
|
+
const position = win
|
|
147
|
+
? win.getComputedStyle(htmlEl).position
|
|
148
|
+
: getComputedStyle(htmlEl).position;
|
|
149
|
+
if (!position || position === 'static') {
|
|
150
|
+
htmlEl.style.position = 'relative';
|
|
151
|
+
}
|
|
152
|
+
}
|
|
153
|
+
function clearBadges(badges) {
|
|
154
|
+
for (const badge of badges.values()) {
|
|
155
|
+
badge.remove();
|
|
156
|
+
}
|
|
157
|
+
badges.clear();
|
|
158
|
+
}
|
|
159
|
+
|
|
101
160
|
const RENDER_COLOR = '255, 200, 0'; // yellow — normal re-render
|
|
102
161
|
const UNNECESSARY_COLOR = '255, 60, 60'; // red — unnecessary render
|
|
103
162
|
function createCanvas(doc) {
|
|
@@ -138,8 +197,9 @@ function drawRect(ctx, r, now) {
|
|
|
138
197
|
function renderFrame(ctx, canvas, rects, now) {
|
|
139
198
|
ctx.clearRect(0, 0, canvas.width, canvas.height);
|
|
140
199
|
const active = rects.filter((r) => now - r.startTime < r.durationMs);
|
|
141
|
-
for (const r of active)
|
|
200
|
+
for (const r of active) {
|
|
142
201
|
drawRect(ctx, r, now);
|
|
202
|
+
}
|
|
143
203
|
return active;
|
|
144
204
|
}
|
|
145
205
|
/**
|
|
@@ -164,8 +224,9 @@ function createCanvasOverlay(doc, win) {
|
|
|
164
224
|
return {
|
|
165
225
|
flash(element, kind, durationMs) {
|
|
166
226
|
const rect = toFlashRect(element, kind, durationMs, win);
|
|
167
|
-
if (rect)
|
|
227
|
+
if (rect) {
|
|
168
228
|
state = { ...state, rects: [...state.rects, rect] };
|
|
229
|
+
}
|
|
169
230
|
},
|
|
170
231
|
detach() {
|
|
171
232
|
win.cancelAnimationFrame(state.rafId);
|
|
@@ -192,17 +253,15 @@ class OverlayService {
|
|
|
192
253
|
destroy() {
|
|
193
254
|
this.canvas?.detach();
|
|
194
255
|
this.canvas = null;
|
|
195
|
-
|
|
196
|
-
badge.remove();
|
|
197
|
-
}
|
|
198
|
-
this.badges.clear();
|
|
256
|
+
clearBadges(this.badges);
|
|
199
257
|
}
|
|
200
258
|
onComponentChecked(stats) {
|
|
201
259
|
if (this.config.showOverlay()) {
|
|
202
260
|
this.canvas?.flash(stats.hostElement, stats.lastRenderKind, this.config.flashDurationMs());
|
|
203
261
|
}
|
|
204
262
|
if (this.config.showBadges()) {
|
|
205
|
-
this.
|
|
263
|
+
const badge = createOrUpdateBadge(this.badges, stats.hostElement, stats.totalRenders, stats.lastRenderKind, this.document, this.win);
|
|
264
|
+
badge.title = `${stats.componentName}: ${stats.totalRenders} renders, ${stats.unnecessaryRenders} unnecessary`;
|
|
206
265
|
}
|
|
207
266
|
else {
|
|
208
267
|
this.removeBadge(stats.hostElement);
|
|
@@ -212,49 +271,12 @@ class OverlayService {
|
|
|
212
271
|
this.badges.get(el)?.remove();
|
|
213
272
|
this.badges.delete(el);
|
|
214
273
|
}
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
if (!badge) {
|
|
218
|
-
badge = this.document.createElement('div');
|
|
219
|
-
badge.setAttribute('aria-hidden', 'true');
|
|
220
|
-
badge.setAttribute('role', 'presentation');
|
|
221
|
-
badge.style.cssText = [
|
|
222
|
-
'position:absolute',
|
|
223
|
-
'top:2px',
|
|
224
|
-
'right:2px',
|
|
225
|
-
'z-index:2147483645',
|
|
226
|
-
'pointer-events:none',
|
|
227
|
-
'font:bold 9px/13px monospace',
|
|
228
|
-
'padding:1px 4px',
|
|
229
|
-
'border-radius:3px',
|
|
230
|
-
'min-width:16px',
|
|
231
|
-
'text-align:center',
|
|
232
|
-
'color:#fff',
|
|
233
|
-
'white-space:nowrap',
|
|
234
|
-
].join(';');
|
|
235
|
-
this.ensurePositioned(stats.hostElement);
|
|
236
|
-
stats.hostElement.appendChild(badge);
|
|
237
|
-
this.badges.set(stats.hostElement, badge);
|
|
238
|
-
}
|
|
239
|
-
const isUnnecessary = stats.lastRenderKind === 'unnecessary';
|
|
240
|
-
badge.style.background = isUnnecessary ? '#f44336' : '#ff9800';
|
|
241
|
-
badge.textContent = String(stats.totalRenders);
|
|
242
|
-
badge.title = `${stats.componentName}: ${stats.totalRenders} renders, ${stats.unnecessaryRenders} unnecessary`;
|
|
243
|
-
}
|
|
244
|
-
ensurePositioned(el) {
|
|
245
|
-
const htmlEl = el;
|
|
246
|
-
if (this.win?.getComputedStyle(htmlEl).position === 'static') {
|
|
247
|
-
htmlEl.style.position = 'relative';
|
|
248
|
-
}
|
|
249
|
-
}
|
|
250
|
-
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.4", ngImport: i0, type: OverlayService, deps: [], target: i0.ɵɵFactoryTarget.Injectable });
|
|
251
|
-
static ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "21.2.4", ngImport: i0, type: OverlayService, providedIn: 'root' });
|
|
274
|
+
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.5", ngImport: i0, type: OverlayService, deps: [], target: i0.ɵɵFactoryTarget.Injectable });
|
|
275
|
+
static ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "21.2.5", ngImport: i0, type: OverlayService, providedIn: 'root' });
|
|
252
276
|
}
|
|
253
|
-
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.
|
|
277
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.5", ngImport: i0, type: OverlayService, decorators: [{
|
|
254
278
|
type: Injectable,
|
|
255
|
-
args: [{
|
|
256
|
-
providedIn: 'root',
|
|
257
|
-
}]
|
|
279
|
+
args: [{ providedIn: 'root' }]
|
|
258
280
|
}] });
|
|
259
281
|
|
|
260
282
|
/**
|
|
@@ -327,8 +349,9 @@ function createTickProfiler({ ng, body, shouldTrack = () => true, onUpdates, })
|
|
|
327
349
|
const removeProfiler = ng.ɵsetProfiler((event, instance) => {
|
|
328
350
|
switch (event) {
|
|
329
351
|
case PROFILER_EVENTS.ChangeDetectionStart:
|
|
330
|
-
if (inTick)
|
|
352
|
+
if (inTick) {
|
|
331
353
|
break;
|
|
354
|
+
}
|
|
332
355
|
inTick = true;
|
|
333
356
|
mutatedNodes.clear();
|
|
334
357
|
tickInstances.clear();
|
|
@@ -348,8 +371,9 @@ function createTickProfiler({ ng, body, shouldTrack = () => true, onUpdates, })
|
|
|
348
371
|
}
|
|
349
372
|
break;
|
|
350
373
|
case PROFILER_EVENTS.ChangeDetectionEnd: {
|
|
351
|
-
if (!inTick)
|
|
374
|
+
if (!inTick) {
|
|
352
375
|
break;
|
|
376
|
+
}
|
|
353
377
|
inTick = false;
|
|
354
378
|
inSyncPhase = false;
|
|
355
379
|
const pending = observer.takeRecords();
|
|
@@ -384,8 +408,9 @@ class ScannerService {
|
|
|
384
408
|
pendingFlush = [];
|
|
385
409
|
toolbarInstance = null;
|
|
386
410
|
initialize() {
|
|
387
|
-
if (!isDevMode() || !this.win || this.options.enabled === false)
|
|
411
|
+
if (!isDevMode() || !this.win || this.options.enabled === false) {
|
|
388
412
|
return;
|
|
413
|
+
}
|
|
389
414
|
const ng = getNgDebugApi();
|
|
390
415
|
if (!ng) {
|
|
391
416
|
console.warn('[angular-scan] Angular debug APIs (window.ng) not available. ' +
|
|
@@ -421,10 +446,10 @@ class ScannerService {
|
|
|
421
446
|
this.pendingFlush = [];
|
|
422
447
|
this.overlay.destroy();
|
|
423
448
|
}
|
|
424
|
-
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.
|
|
425
|
-
static ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "21.2.
|
|
449
|
+
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.5", ngImport: i0, type: ScannerService, deps: [], target: i0.ɵɵFactoryTarget.Injectable });
|
|
450
|
+
static ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "21.2.5", ngImport: i0, type: ScannerService, providedIn: 'root' });
|
|
426
451
|
}
|
|
427
|
-
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.
|
|
452
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.5", ngImport: i0, type: ScannerService, decorators: [{
|
|
428
453
|
type: Injectable,
|
|
429
454
|
args: [{ providedIn: 'root' }]
|
|
430
455
|
}] });
|
|
@@ -462,10 +487,10 @@ class ToolbarComponent {
|
|
|
462
487
|
const value = Number(event.target.value);
|
|
463
488
|
this.config.flashDurationMs.set(value);
|
|
464
489
|
}
|
|
465
|
-
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.
|
|
466
|
-
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.2.
|
|
490
|
+
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.5", ngImport: i0, type: ToolbarComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
|
|
491
|
+
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.2.5", type: ToolbarComponent, isStandalone: true, selector: "angular-scan-toolbar", host: { properties: { "style.display": "\"block\"" } }, ngImport: i0, template: "<div\n class=\"toolbar\"\n role=\"complementary\"\n aria-label=\"Angular Scan DevTools\"\n>\n <div class=\"toolbar__header\">\n <span class=\"toolbar__logo\" aria-hidden=\"true\">\u25C9</span>\n <span class=\"toolbar__title\">angular-scan</span>\n\n <button\n class=\"toolbar__btn\"\n type=\"button\"\n [attr.aria-pressed]=\"!config.enabled()\"\n [title]=\"config.enabled() ? 'Pause scanning' : 'Resume scanning'\"\n (click)=\"toggleEnabled()\"\n >{{ config.enabled() ? '\u23F8' : '\u25B6' }}</button>\n\n <button\n class=\"toolbar__btn\"\n type=\"button\"\n [attr.aria-pressed]=\"settingsOpen()\"\n title=\"Settings\"\n (click)=\"toggleSettings()\"\n >\u2699</button>\n\n <button\n class=\"toolbar__btn\"\n type=\"button\"\n [attr.aria-pressed]=\"expanded()\"\n [title]=\"expanded() ? 'Collapse inspector' : 'Expand inspector'\"\n (click)=\"toggleExpanded()\"\n >{{ expanded() ? '\u25B2' : '\u25BC' }}</button>\n </div>\n\n <div class=\"toolbar__stats\">\n <span class=\"toolbar__stat\" title=\"Total change detection checks\">\n <span class=\"toolbar__stat-label\">checks</span>\n <strong class=\"toolbar__stat-value\">{{ tracker.totalRenders() }}</strong>\n </span>\n <span\n class=\"toolbar__stat\"\n [class.toolbar__stat--warn]=\"tracker.totalUnnecessary() > 0\"\n title=\"Unnecessary renders: component was checked but DOM did not change\"\n >\n <span class=\"toolbar__stat-label\">wasted</span>\n <strong class=\"toolbar__stat-value\">{{ tracker.totalUnnecessary() }}</strong>\n </span>\n </div>\n\n @if (settingsOpen()) {\n <div class=\"toolbar__settings\" role=\"group\" aria-label=\"Scan settings\">\n\n <label class=\"toolbar__setting\">\n <span class=\"toolbar__setting-label\">Enable scanning</span>\n <button\n class=\"toolbar__toggle\"\n type=\"button\"\n role=\"switch\"\n [attr.aria-checked]=\"config.enabled()\"\n (click)=\"toggleEnabled()\"\n [class.toolbar__toggle--on]=\"config.enabled()\"\n >{{ config.enabled() ? 'ON' : 'OFF' }}</button>\n </label>\n\n <label class=\"toolbar__setting\">\n <span class=\"toolbar__setting-label\">Flash overlay</span>\n <button\n class=\"toolbar__toggle\"\n type=\"button\"\n role=\"switch\"\n [attr.aria-checked]=\"config.showOverlay()\"\n (click)=\"toggleOverlay()\"\n [class.toolbar__toggle--on]=\"config.showOverlay()\"\n >{{ config.showOverlay() ? 'ON' : 'OFF' }}</button>\n </label>\n\n <label class=\"toolbar__setting\">\n <span class=\"toolbar__setting-label\">Render badges</span>\n <button\n class=\"toolbar__toggle\"\n type=\"button\"\n role=\"switch\"\n [attr.aria-checked]=\"config.showBadges()\"\n (click)=\"toggleBadges()\"\n [class.toolbar__toggle--on]=\"config.showBadges()\"\n >{{ config.showBadges() ? 'ON' : 'OFF' }}</button>\n </label>\n\n <label class=\"toolbar__setting toolbar__setting--column\">\n <span class=\"toolbar__setting-label\">\n Flash duration\n <span class=\"toolbar__setting-value\">{{ config.flashDurationMs() }}ms</span>\n </span>\n <input\n class=\"toolbar__slider\"\n type=\"range\"\n min=\"100\"\n max=\"2000\"\n step=\"100\"\n [value]=\"config.flashDurationMs()\"\n (input)=\"onFlashDurationChange($event)\"\n aria-label=\"Flash duration in milliseconds\"\n />\n </label>\n\n <button\n class=\"toolbar__reset\"\n type=\"button\"\n title=\"Clear all render stats\"\n (click)=\"resetStats()\"\n >\u21BA Reset stats</button>\n\n </div>\n }\n\n @if (expanded()) {\n <div\n class=\"toolbar__inspector\"\n role=\"list\"\n aria-label=\"Component render counts\"\n >\n @for (comp of tracker.trackedComponents(); track comp.hostElement) {\n <div\n class=\"toolbar__component\"\n role=\"listitem\"\n [class.toolbar__component--warn]=\"comp.lastRenderKind === 'unnecessary'\"\n [title]=\"comp.componentName + ' \u2014 ' + comp.totalRenders + ' checks, ' + comp.unnecessaryRenders + ' wasted'\"\n >\n <span class=\"toolbar__component-name\">{{ comp.componentName }}</span>\n <span class=\"toolbar__component-count\">{{ comp.totalRenders }}</span>\n @if (comp.unnecessaryRenders > 0) {\n <span class=\"toolbar__component-wasted\" aria-label=\"wasted renders\">\n {{ comp.unnecessaryRenders }}W\n </span>\n }\n </div>\n }\n </div>\n }\n</div>\n", styles: [":host{position:fixed;bottom:0;right:0;z-index:2147483647;font-family:ui-monospace,Cascadia Code,Source Code Pro,Menlo,Consolas,monospace;font-size:11px;line-height:1.4}.toolbar{background:#0f1117;color:#c9d1d9;border:1px solid #30363d;border-bottom:none;border-right:none;border-radius:6px 0 0;min-width:200px;max-width:300px;box-shadow:-2px -2px 12px #00000080}.toolbar__header{display:flex;align-items:center;gap:4px;padding:5px 8px;border-bottom:1px solid #21262d}.toolbar__logo{color:#58a6ff;font-size:12px}.toolbar__title{font-weight:600;color:#58a6ff;flex:1;letter-spacing:.02em}.toolbar__btn{background:transparent;border:1px solid #30363d;color:#8b949e;border-radius:4px;cursor:pointer;padding:2px 6px;font-size:10px;transition:color .15s,border-color .15s}.toolbar__btn:hover{color:#c9d1d9;border-color:#58a6ff}.toolbar__btn:focus-visible{outline:2px solid #58a6ff;outline-offset:2px}.toolbar__stats{display:flex;gap:12px;padding:5px 8px}.toolbar__stat{display:flex;flex-direction:column;gap:1px}.toolbar__stat-label{color:#8b949e;font-size:9px;text-transform:uppercase;letter-spacing:.05em}.toolbar__stat-value{color:#c9d1d9}.toolbar__stat--warn .toolbar__stat-value{color:#f85149}.toolbar__inspector{max-height:220px;overflow-y:auto;border-top:1px solid #21262d}.toolbar__inspector::-webkit-scrollbar{width:4px}.toolbar__inspector::-webkit-scrollbar-track{background:transparent}.toolbar__inspector::-webkit-scrollbar-thumb{background:#30363d;border-radius:2px}.toolbar__component{display:flex;align-items:center;gap:6px;padding:3px 8px;border-bottom:1px solid #161b22;transition:background .1s}.toolbar__component:hover{background:#161b22}.toolbar__component--warn{background:#f851490f}.toolbar__component-name{flex:1;overflow:hidden;text-overflow:ellipsis;white-space:nowrap;color:#8b949e}.toolbar__component-count{font-weight:600;color:#ffa657;min-width:20px;text-align:right}.toolbar__component-wasted{color:#f85149;font-size:9px;font-weight:600}.toolbar__settings{display:flex;flex-direction:column;gap:6px;padding:8px;border-top:1px solid #21262d}.toolbar__setting{display:flex;align-items:center;justify-content:space-between;gap:8px;cursor:default}.toolbar__setting--column{flex-direction:column;align-items:stretch;gap:4px}.toolbar__setting-label{color:#8b949e;font-size:10px;display:flex;align-items:center;justify-content:space-between;gap:4px}.toolbar__setting-value{color:#58a6ff;font-weight:600}.toolbar__toggle{background:#21262d;border:1px solid #30363d;color:#8b949e;border-radius:3px;cursor:pointer;padding:1px 6px;font-size:9px;font-weight:600;font-family:inherit;letter-spacing:.05em;min-width:32px;transition:background .15s,color .15s,border-color .15s}.toolbar__toggle--on{background:#58a6ff26;border-color:#58a6ff;color:#58a6ff}.toolbar__toggle:focus-visible{outline:2px solid #58a6ff;outline-offset:2px}.toolbar__slider{width:100%;accent-color:#58a6ff;cursor:pointer;height:4px}.toolbar__reset{background:transparent;border:1px solid #30363d;color:#8b949e;border-radius:4px;cursor:pointer;padding:3px 8px;font-size:10px;font-family:inherit;margin-top:2px;transition:color .15s,border-color .15s;align-self:flex-start}.toolbar__reset:hover{color:#f85149;border-color:#f85149}.toolbar__reset:focus-visible{outline:2px solid #58a6ff;outline-offset:2px}\n"], changeDetection: i0.ChangeDetectionStrategy.OnPush });
|
|
467
492
|
}
|
|
468
|
-
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.
|
|
493
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.5", ngImport: i0, type: ToolbarComponent, decorators: [{
|
|
469
494
|
type: Component,
|
|
470
495
|
args: [{ selector: 'angular-scan-toolbar', changeDetection: ChangeDetectionStrategy.OnPush, host: { '[style.display]': '"block"' }, template: "<div\n class=\"toolbar\"\n role=\"complementary\"\n aria-label=\"Angular Scan DevTools\"\n>\n <div class=\"toolbar__header\">\n <span class=\"toolbar__logo\" aria-hidden=\"true\">\u25C9</span>\n <span class=\"toolbar__title\">angular-scan</span>\n\n <button\n class=\"toolbar__btn\"\n type=\"button\"\n [attr.aria-pressed]=\"!config.enabled()\"\n [title]=\"config.enabled() ? 'Pause scanning' : 'Resume scanning'\"\n (click)=\"toggleEnabled()\"\n >{{ config.enabled() ? '\u23F8' : '\u25B6' }}</button>\n\n <button\n class=\"toolbar__btn\"\n type=\"button\"\n [attr.aria-pressed]=\"settingsOpen()\"\n title=\"Settings\"\n (click)=\"toggleSettings()\"\n >\u2699</button>\n\n <button\n class=\"toolbar__btn\"\n type=\"button\"\n [attr.aria-pressed]=\"expanded()\"\n [title]=\"expanded() ? 'Collapse inspector' : 'Expand inspector'\"\n (click)=\"toggleExpanded()\"\n >{{ expanded() ? '\u25B2' : '\u25BC' }}</button>\n </div>\n\n <div class=\"toolbar__stats\">\n <span class=\"toolbar__stat\" title=\"Total change detection checks\">\n <span class=\"toolbar__stat-label\">checks</span>\n <strong class=\"toolbar__stat-value\">{{ tracker.totalRenders() }}</strong>\n </span>\n <span\n class=\"toolbar__stat\"\n [class.toolbar__stat--warn]=\"tracker.totalUnnecessary() > 0\"\n title=\"Unnecessary renders: component was checked but DOM did not change\"\n >\n <span class=\"toolbar__stat-label\">wasted</span>\n <strong class=\"toolbar__stat-value\">{{ tracker.totalUnnecessary() }}</strong>\n </span>\n </div>\n\n @if (settingsOpen()) {\n <div class=\"toolbar__settings\" role=\"group\" aria-label=\"Scan settings\">\n\n <label class=\"toolbar__setting\">\n <span class=\"toolbar__setting-label\">Enable scanning</span>\n <button\n class=\"toolbar__toggle\"\n type=\"button\"\n role=\"switch\"\n [attr.aria-checked]=\"config.enabled()\"\n (click)=\"toggleEnabled()\"\n [class.toolbar__toggle--on]=\"config.enabled()\"\n >{{ config.enabled() ? 'ON' : 'OFF' }}</button>\n </label>\n\n <label class=\"toolbar__setting\">\n <span class=\"toolbar__setting-label\">Flash overlay</span>\n <button\n class=\"toolbar__toggle\"\n type=\"button\"\n role=\"switch\"\n [attr.aria-checked]=\"config.showOverlay()\"\n (click)=\"toggleOverlay()\"\n [class.toolbar__toggle--on]=\"config.showOverlay()\"\n >{{ config.showOverlay() ? 'ON' : 'OFF' }}</button>\n </label>\n\n <label class=\"toolbar__setting\">\n <span class=\"toolbar__setting-label\">Render badges</span>\n <button\n class=\"toolbar__toggle\"\n type=\"button\"\n role=\"switch\"\n [attr.aria-checked]=\"config.showBadges()\"\n (click)=\"toggleBadges()\"\n [class.toolbar__toggle--on]=\"config.showBadges()\"\n >{{ config.showBadges() ? 'ON' : 'OFF' }}</button>\n </label>\n\n <label class=\"toolbar__setting toolbar__setting--column\">\n <span class=\"toolbar__setting-label\">\n Flash duration\n <span class=\"toolbar__setting-value\">{{ config.flashDurationMs() }}ms</span>\n </span>\n <input\n class=\"toolbar__slider\"\n type=\"range\"\n min=\"100\"\n max=\"2000\"\n step=\"100\"\n [value]=\"config.flashDurationMs()\"\n (input)=\"onFlashDurationChange($event)\"\n aria-label=\"Flash duration in milliseconds\"\n />\n </label>\n\n <button\n class=\"toolbar__reset\"\n type=\"button\"\n title=\"Clear all render stats\"\n (click)=\"resetStats()\"\n >\u21BA Reset stats</button>\n\n </div>\n }\n\n @if (expanded()) {\n <div\n class=\"toolbar__inspector\"\n role=\"list\"\n aria-label=\"Component render counts\"\n >\n @for (comp of tracker.trackedComponents(); track comp.hostElement) {\n <div\n class=\"toolbar__component\"\n role=\"listitem\"\n [class.toolbar__component--warn]=\"comp.lastRenderKind === 'unnecessary'\"\n [title]=\"comp.componentName + ' \u2014 ' + comp.totalRenders + ' checks, ' + comp.unnecessaryRenders + ' wasted'\"\n >\n <span class=\"toolbar__component-name\">{{ comp.componentName }}</span>\n <span class=\"toolbar__component-count\">{{ comp.totalRenders }}</span>\n @if (comp.unnecessaryRenders > 0) {\n <span class=\"toolbar__component-wasted\" aria-label=\"wasted renders\">\n {{ comp.unnecessaryRenders }}W\n </span>\n }\n </div>\n }\n </div>\n }\n</div>\n", styles: [":host{position:fixed;bottom:0;right:0;z-index:2147483647;font-family:ui-monospace,Cascadia Code,Source Code Pro,Menlo,Consolas,monospace;font-size:11px;line-height:1.4}.toolbar{background:#0f1117;color:#c9d1d9;border:1px solid #30363d;border-bottom:none;border-right:none;border-radius:6px 0 0;min-width:200px;max-width:300px;box-shadow:-2px -2px 12px #00000080}.toolbar__header{display:flex;align-items:center;gap:4px;padding:5px 8px;border-bottom:1px solid #21262d}.toolbar__logo{color:#58a6ff;font-size:12px}.toolbar__title{font-weight:600;color:#58a6ff;flex:1;letter-spacing:.02em}.toolbar__btn{background:transparent;border:1px solid #30363d;color:#8b949e;border-radius:4px;cursor:pointer;padding:2px 6px;font-size:10px;transition:color .15s,border-color .15s}.toolbar__btn:hover{color:#c9d1d9;border-color:#58a6ff}.toolbar__btn:focus-visible{outline:2px solid #58a6ff;outline-offset:2px}.toolbar__stats{display:flex;gap:12px;padding:5px 8px}.toolbar__stat{display:flex;flex-direction:column;gap:1px}.toolbar__stat-label{color:#8b949e;font-size:9px;text-transform:uppercase;letter-spacing:.05em}.toolbar__stat-value{color:#c9d1d9}.toolbar__stat--warn .toolbar__stat-value{color:#f85149}.toolbar__inspector{max-height:220px;overflow-y:auto;border-top:1px solid #21262d}.toolbar__inspector::-webkit-scrollbar{width:4px}.toolbar__inspector::-webkit-scrollbar-track{background:transparent}.toolbar__inspector::-webkit-scrollbar-thumb{background:#30363d;border-radius:2px}.toolbar__component{display:flex;align-items:center;gap:6px;padding:3px 8px;border-bottom:1px solid #161b22;transition:background .1s}.toolbar__component:hover{background:#161b22}.toolbar__component--warn{background:#f851490f}.toolbar__component-name{flex:1;overflow:hidden;text-overflow:ellipsis;white-space:nowrap;color:#8b949e}.toolbar__component-count{font-weight:600;color:#ffa657;min-width:20px;text-align:right}.toolbar__component-wasted{color:#f85149;font-size:9px;font-weight:600}.toolbar__settings{display:flex;flex-direction:column;gap:6px;padding:8px;border-top:1px solid #21262d}.toolbar__setting{display:flex;align-items:center;justify-content:space-between;gap:8px;cursor:default}.toolbar__setting--column{flex-direction:column;align-items:stretch;gap:4px}.toolbar__setting-label{color:#8b949e;font-size:10px;display:flex;align-items:center;justify-content:space-between;gap:4px}.toolbar__setting-value{color:#58a6ff;font-weight:600}.toolbar__toggle{background:#21262d;border:1px solid #30363d;color:#8b949e;border-radius:3px;cursor:pointer;padding:1px 6px;font-size:9px;font-weight:600;font-family:inherit;letter-spacing:.05em;min-width:32px;transition:background .15s,color .15s,border-color .15s}.toolbar__toggle--on{background:#58a6ff26;border-color:#58a6ff;color:#58a6ff}.toolbar__toggle:focus-visible{outline:2px solid #58a6ff;outline-offset:2px}.toolbar__slider{width:100%;accent-color:#58a6ff;cursor:pointer;height:4px}.toolbar__reset{background:transparent;border:1px solid #30363d;color:#8b949e;border-radius:4px;cursor:pointer;padding:3px 8px;font-size:10px;font-family:inherit;margin-top:2px;transition:color .15s,border-color .15s;align-self:flex-start}.toolbar__reset:hover{color:#f85149;border-color:#f85149}.toolbar__reset:focus-visible{outline:2px solid #58a6ff;outline-offset:2px}\n"] }]
|
|
471
496
|
}] });
|
|
@@ -498,6 +523,9 @@ function provideAngularScan(options = {}) {
|
|
|
498
523
|
return makeEnvironmentProviders([
|
|
499
524
|
{ provide: ANGULAR_SCAN_OPTIONS, useValue: resolvedOptions },
|
|
500
525
|
provideEnvironmentInitializer(() => {
|
|
526
|
+
if (!isPlatformBrowser(inject(PLATFORM_ID))) {
|
|
527
|
+
return;
|
|
528
|
+
}
|
|
501
529
|
const overlay = inject(OverlayService);
|
|
502
530
|
const scanner = inject(ScannerService);
|
|
503
531
|
const opts = inject(ANGULAR_SCAN_OPTIONS);
|
|
@@ -539,12 +567,15 @@ function mountToolbar(scanner) {
|
|
|
539
567
|
* @returns A teardown function that stops scanning and removes the overlay.
|
|
540
568
|
*/
|
|
541
569
|
function scan(options = {}) {
|
|
542
|
-
if (!isDevMode())
|
|
570
|
+
if (!isDevMode()) {
|
|
543
571
|
return () => { };
|
|
544
|
-
|
|
572
|
+
}
|
|
573
|
+
if (typeof window === 'undefined') {
|
|
545
574
|
return () => { };
|
|
546
|
-
|
|
575
|
+
}
|
|
576
|
+
if (options.enabled === false) {
|
|
547
577
|
return () => { };
|
|
578
|
+
}
|
|
548
579
|
const ng = getNgDebugApi();
|
|
549
580
|
if (!ng) {
|
|
550
581
|
console.warn('[angular-scan] Angular debug APIs (window.ng) not available. ' +
|
|
@@ -566,7 +597,7 @@ function scan(options = {}) {
|
|
|
566
597
|
renderCounts.set(instance, count);
|
|
567
598
|
overlay.flash(hostElement, kind, durationMs);
|
|
568
599
|
if (showBadges) {
|
|
569
|
-
|
|
600
|
+
createOrUpdateBadge(badges, hostElement, count, kind);
|
|
570
601
|
}
|
|
571
602
|
}
|
|
572
603
|
});
|
|
@@ -575,41 +606,9 @@ function scan(options = {}) {
|
|
|
575
606
|
return () => {
|
|
576
607
|
teardown();
|
|
577
608
|
overlay.detach();
|
|
578
|
-
|
|
579
|
-
b.remove();
|
|
580
|
-
}
|
|
581
|
-
badges.clear();
|
|
609
|
+
clearBadges(badges);
|
|
582
610
|
};
|
|
583
611
|
}
|
|
584
|
-
function updateBadge(badges, hostEl, count, kind) {
|
|
585
|
-
let badge = badges.get(hostEl);
|
|
586
|
-
if (!badge) {
|
|
587
|
-
badge = document.createElement('div');
|
|
588
|
-
badge.setAttribute('aria-hidden', 'true');
|
|
589
|
-
badge.setAttribute('role', 'presentation');
|
|
590
|
-
badge.style.cssText = [
|
|
591
|
-
'position:absolute',
|
|
592
|
-
'top:2px',
|
|
593
|
-
'right:2px',
|
|
594
|
-
'z-index:2147483645',
|
|
595
|
-
'pointer-events:none',
|
|
596
|
-
'font:bold 9px/13px monospace',
|
|
597
|
-
'padding:1px 4px',
|
|
598
|
-
'border-radius:3px',
|
|
599
|
-
'min-width:16px',
|
|
600
|
-
'text-align:center',
|
|
601
|
-
'color:#fff',
|
|
602
|
-
].join(';');
|
|
603
|
-
const htmlEl = hostEl;
|
|
604
|
-
if (getComputedStyle(htmlEl).position === 'static') {
|
|
605
|
-
htmlEl.style.position = 'relative';
|
|
606
|
-
}
|
|
607
|
-
hostEl.appendChild(badge);
|
|
608
|
-
badges.set(hostEl, badge);
|
|
609
|
-
}
|
|
610
|
-
badge.style.background = kind === 'unnecessary' ? '#f44336' : '#ff9800';
|
|
611
|
-
badge.textContent = String(count);
|
|
612
|
-
}
|
|
613
612
|
|
|
614
613
|
/*
|
|
615
614
|
* Public API Surface of angular-scan
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"angular-scan.mjs","sources":["../../../projects/angular-scan/src/lib/component-tracker.ts","../../../projects/angular-scan/src/lib/ng-debug.ts","../../../projects/angular-scan/src/lib/tokens.ts","../../../projects/angular-scan/src/lib/scan-config.service.ts","../../../projects/angular-scan/src/lib/overlay/canvas-overlay.ts","../../../projects/angular-scan/src/lib/overlay/overlay.service.ts","../../../projects/angular-scan/src/lib/models/ProfilerEvents.ts","../../../projects/angular-scan/src/lib/utils/build-mutated-hosts.ts","../../../projects/angular-scan/src/lib/utils/collect-tick-updates.ts","../../../projects/angular-scan/src/lib/utils/create-tick-profiler.ts","../../../projects/angular-scan/src/lib/scanner.service.ts","../../../projects/angular-scan/src/lib/toolbar/toolbar.component.ts","../../../projects/angular-scan/src/lib/toolbar/toolbar.component.html","../../../projects/angular-scan/src/lib/provide-angular-scan.ts","../../../projects/angular-scan/src/lib/scan.ts","../../../projects/angular-scan/src/public-api.ts","../../../projects/angular-scan/src/angular-scan.ts"],"sourcesContent":["import { Injectable, signal } from '@angular/core';\nimport type { ComponentStats } from './models/ComponentStats';\nimport type { RenderKind } from './models/RenderKind';\n\n@Injectable({ providedIn: 'root' })\nexport class ComponentTracker {\n private readonly byInstance = new WeakMap<object, ComponentStats>();\n private readonly byElement = new Map<Element, object>();\n\n readonly totalRenders = signal(0);\n readonly totalUnnecessary = signal(0);\n readonly trackedComponents = signal<readonly ComponentStats[]>([]);\n\n recordRender(instance: object, hostElement: Element, kind: RenderKind): ComponentStats {\n const DEFAULT = {\n componentName: instance.constructor.name,\n hostElement,\n totalRenders: 0,\n unnecessaryRenders: 0,\n lastRenderKind: kind,\n lastRenderTimestamp: 0,\n };\n const prev = this.byInstance.get(instance) ?? DEFAULT;\n\n const isUnnecessary = kind === 'unnecessary';\n const next: ComponentStats = {\n ...prev,\n totalRenders: prev.totalRenders + 1,\n unnecessaryRenders: prev.unnecessaryRenders + (isUnnecessary ? 1 : 0),\n lastRenderKind: kind,\n lastRenderTimestamp: Date.now(),\n };\n\n this.byInstance.set(instance, next);\n this.byElement.set(hostElement, instance);\n\n this.totalRenders.update((n) => n + 1);\n if (isUnnecessary) {\n this.totalUnnecessary.update((n) => n + 1);\n }\n\n return next;\n }\n\n snapshotTrackedComponents(): void {\n const list: ComponentStats[] = [];\n for (const [, instance] of this.byElement) {\n const stats = this.byInstance.get(instance);\n if (stats) {\n list.push(stats);\n }\n }\n this.trackedComponents.set(list);\n }\n\n reset(): void {\n this.byElement.clear();\n this.totalRenders.set(0);\n this.totalUnnecessary.set(0);\n this.trackedComponents.set([]);\n }\n}\n","import type { NgDebugApi } from './models/NgDebugApi';\n\n/**\n * Returns the Angular debug API (window.ng) if available.\n * Returns null in SSR, production builds, or when Angular DevTools APIs are absent.\n *\n * Safe to call before Angular is bootstrapped — the API is attached to window\n * by Angular's dev mode runtime.\n */\nexport function getNgDebugApi(): NgDebugApi | null {\n if (typeof window === 'undefined') return null;\n\n const ng = (window as unknown as Record<string, unknown>)['ng'];\n if (!ng || typeof ng !== 'object') return null;\n\n const api = ng as Partial<NgDebugApi>;\n\n // ɵsetProfiler is the sentinel for dev mode — absent in production builds\n if (typeof api.ɵsetProfiler !== 'function') return null;\n if (typeof api.getHostElement !== 'function') return null;\n\n return api as NgDebugApi;\n}\n","import { InjectionToken, inject } from '@angular/core';\nimport { DOCUMENT } from '@angular/common';\nimport type { AngularScanOptions } from './models/AngularScanOptions';\n\nexport const ANGULAR_SCAN_OPTIONS = new InjectionToken<AngularScanOptions>(\n 'ANGULAR_SCAN_OPTIONS',\n { providedIn: 'root', factory: () => ({}) }\n);\n\n/** The browser Window object. Resolves to null in SSR. */\nexport const WINDOW = new InjectionToken<(Window & typeof globalThis) | null>(\n 'WINDOW',\n { providedIn: 'root', factory: () => inject(DOCUMENT).defaultView }\n);\n","import { Injectable, inject, signal } from '@angular/core';\nimport { ANGULAR_SCAN_OPTIONS } from './tokens';\n\n@Injectable({ providedIn: 'root' })\nexport class ScanConfigService {\n private readonly options = inject(ANGULAR_SCAN_OPTIONS);\n\n readonly enabled = signal(this.options.enabled !== false);\n readonly showOverlay = signal(true);\n readonly showBadges = signal(this.options.showBadges !== false);\n readonly flashDurationMs = signal(this.options.flashDurationMs ?? 500);\n}\n","import type { CanvasOverlay } from '../models/CanvasOverlay';\nimport type { FlashRect } from '../models/FlashRect';\nimport type { OverlayState } from '../models/OverlayState';\nimport type { RenderKind } from '../models/RenderKind';\n\nconst RENDER_COLOR = '255, 200, 0'; // yellow — normal re-render\nconst UNNECESSARY_COLOR = '255, 60, 60'; // red — unnecessary render\n\nfunction createCanvas(doc: Document): HTMLCanvasElement {\n const canvas = doc.createElement('canvas');\n canvas.setAttribute('aria-hidden', 'true');\n canvas.setAttribute('role', 'presentation');\n canvas.style.cssText = [\n 'position:fixed',\n 'top:0',\n 'left:0',\n 'width:100%',\n 'height:100%',\n 'pointer-events:none',\n 'z-index:2147483646',\n ].join(';');\n return canvas;\n}\n\nfunction resizeCanvas(canvas: HTMLCanvasElement, win: Window & typeof globalThis): void {\n canvas.width = win.innerWidth;\n canvas.height = win.innerHeight;\n}\n\nfunction toFlashRect(\n element: Element,\n kind: RenderKind,\n durationMs: number,\n win: Window & typeof globalThis,\n): FlashRect | null {\n const { left, top, width, height } = element.getBoundingClientRect();\n if (width === 0 || height === 0) return null;\n\n return { x: left, y: top, width, height, kind, startTime: win.performance.now(), durationMs };\n}\n\nfunction drawRect(ctx: CanvasRenderingContext2D, r: FlashRect, now: number): void {\n const elapsed = now - r.startTime;\n const alpha = Math.max(0, 1 - elapsed / r.durationMs);\n const color = r.kind === 'render' ? RENDER_COLOR : UNNECESSARY_COLOR;\n\n ctx.fillStyle = `rgba(${color}, ${alpha * 0.1})`;\n ctx.fillRect(r.x, r.y, r.width, r.height);\n\n ctx.strokeStyle = `rgba(${color}, ${alpha * 0.9})`;\n ctx.lineWidth = 2;\n ctx.strokeRect(r.x + 1, r.y + 1, r.width - 2, r.height - 2);\n}\n\nfunction renderFrame(\n ctx: CanvasRenderingContext2D,\n canvas: HTMLCanvasElement,\n rects: readonly FlashRect[],\n now: number,\n): FlashRect[] {\n ctx.clearRect(0, 0, canvas.width, canvas.height);\n const active = rects.filter((r) => now - r.startTime < r.durationMs);\n for (const r of active) drawRect(ctx, r, now);\n return active;\n}\n\n/**\n * Creates a canvas overlay, attaches it to the document, and starts the render loop.\n * Returns a minimal interface: flash to queue an animation, detach to clean up.\n */\nexport function createCanvasOverlay(doc: Document, win: Window & typeof globalThis): CanvasOverlay {\n let state: OverlayState = { rects: [], rafId: 0 };\n\n const canvas = createCanvas(doc);\n doc.body.appendChild(canvas);\n const ctx = canvas.getContext('2d')!;\n\n const onResize = (): void => resizeCanvas(canvas, win);\n const loop = (now: number): void => {\n state = {\n rects: renderFrame(ctx, canvas, state.rects, now),\n rafId: win.requestAnimationFrame(loop),\n };\n };\n\n resizeCanvas(canvas, win);\n win.addEventListener('resize', onResize);\n state = { ...state, rafId: win.requestAnimationFrame(loop) };\n\n return {\n flash(element, kind, durationMs) {\n const rect = toFlashRect(element, kind, durationMs, win);\n if (rect) state = { ...state, rects: [...state.rects, rect] };\n },\n\n detach() {\n win.cancelAnimationFrame(state.rafId);\n win.removeEventListener('resize', onResize);\n canvas.remove();\n state = { rects: [], rafId: 0 };\n },\n };\n}\n","import { DOCUMENT, Injectable, inject, isDevMode } from '@angular/core';\nimport type { CanvasOverlay } from '../models/CanvasOverlay';\nimport type { ComponentStats } from '../models/ComponentStats';\nimport { ScanConfigService } from '../scan-config.service';\nimport { ANGULAR_SCAN_OPTIONS, WINDOW } from '../tokens';\nimport { createCanvasOverlay } from './canvas-overlay';\n\n@Injectable({\n providedIn: 'root',\n})\nexport class OverlayService {\n private readonly document = inject(DOCUMENT);\n private readonly win = inject(WINDOW);\n private readonly options = inject(ANGULAR_SCAN_OPTIONS);\n private readonly config = inject(ScanConfigService);\n\n private canvas: CanvasOverlay | null = null;\n private readonly badges = new Map<Element, HTMLElement>();\n\n initialize(): void {\n if (!isDevMode() || !this.win || this.options.enabled === false) {\n return;\n }\n\n this.canvas = createCanvasOverlay(this.document, this.win);\n }\n\n destroy(): void {\n this.canvas?.detach();\n this.canvas = null;\n for (const badge of this.badges.values()) {\n badge.remove();\n }\n this.badges.clear();\n }\n\n onComponentChecked(stats: ComponentStats): void {\n if (this.config.showOverlay()) {\n this.canvas?.flash(stats.hostElement, stats.lastRenderKind, this.config.flashDurationMs());\n }\n\n if (this.config.showBadges()) {\n this.updateBadge(stats);\n } else {\n this.removeBadge(stats.hostElement);\n }\n }\n\n removeBadge(el: Element): void {\n this.badges.get(el)?.remove();\n this.badges.delete(el);\n }\n\n private updateBadge(stats: ComponentStats): void {\n let badge = this.badges.get(stats.hostElement);\n\n if (!badge) {\n badge = this.document.createElement('div');\n badge.setAttribute('aria-hidden', 'true');\n badge.setAttribute('role', 'presentation');\n badge.style.cssText = [\n 'position:absolute',\n 'top:2px',\n 'right:2px',\n 'z-index:2147483645',\n 'pointer-events:none',\n 'font:bold 9px/13px monospace',\n 'padding:1px 4px',\n 'border-radius:3px',\n 'min-width:16px',\n 'text-align:center',\n 'color:#fff',\n 'white-space:nowrap',\n ].join(';');\n\n this.ensurePositioned(stats.hostElement);\n stats.hostElement.appendChild(badge);\n this.badges.set(stats.hostElement, badge);\n }\n\n const isUnnecessary = stats.lastRenderKind === 'unnecessary';\n badge.style.background = isUnnecessary ? '#f44336' : '#ff9800';\n badge.textContent = String(stats.totalRenders);\n badge.title = `${stats.componentName}: ${stats.totalRenders} renders, ${stats.unnecessaryRenders} unnecessary`;\n }\n\n private ensurePositioned(el: Element): void {\n const htmlEl = el as HTMLElement;\n if (this.win?.getComputedStyle(htmlEl).position === 'static') {\n htmlEl.style.position = 'relative';\n }\n }\n}\n","/**\n * Angular profiler event IDs — stable dev-mode contract, same as Angular DevTools.\n *\n * @see https://github.com/angular/angular/blob/main/packages/core/primitives/devtools/src/profiler_types.ts\n * @see https://github.com/angular/angular/blob/main/devtools/projects/ng-devtools-backend/src/lib/hooks/capture.ts\n */\nexport const PROFILER_EVENTS = {\n TemplateUpdateStart: 2,\n ChangeDetectionStart: 12,\n ChangeDetectionEnd: 13,\n ChangeDetectionSyncStart: 14,\n ChangeDetectionSyncEnd: 15,\n} as const;\n","import type { NgDebugApi } from '../models/NgDebugApi';\n\n/** Walk mutated nodes UP the DOM to find their owning Angular component host. */\nexport function buildMutatedHosts(\n nodes: Set<Node>,\n body: Element,\n ng: NgDebugApi,\n): Set<Element> {\n const hosts = new Set<Element>();\n\n for (const node of nodes) {\n let current: Node | null = node;\n\n while (current && current !== body) {\n if (current instanceof Element) {\n try {\n if (ng.getComponent(current)) {\n hosts.add(current);\n break;\n }\n } catch { /* ignore destroyed nodes */ }\n }\n current = current.parentNode;\n }\n }\n\n return hosts;\n}\n","import type { NgDebugApi } from '../models/NgDebugApi';\nimport type { PendingUpdate } from '../models/PendingUpdate';\nimport type { RenderKind } from '../models/RenderKind';\n\n/** Map checked instances to PendingUpdate records — pure, no side effects. */\nexport function collectTickUpdates(\n instances: Set<object>,\n mutatedHosts: Set<Element>,\n ng: NgDebugApi,\n): PendingUpdate[] {\n const updates: PendingUpdate[] = [];\n\n for (const instance of instances) {\n try {\n const hostElement = ng.getHostElement(instance);\n if (!hostElement) continue;\n const kind: RenderKind = mutatedHosts.has(hostElement) ? 'render' : 'unnecessary';\n updates.push({ instance, hostElement, kind });\n } catch { /* component destroyed */ }\n }\n\n return updates;\n}\n","import type { TickProfilerOptions } from '../models/TickProfilerOptions';\nimport { PROFILER_EVENTS as PE } from '../models/ProfilerEvents';\nimport { buildMutatedHosts } from './build-mutated-hosts';\nimport { collectTickUpdates } from './collect-tick-updates';\n\n/**\n * Wires up the Angular profiler + MutationObserver to track per-tick render updates.\n * Returns a teardown function that removes the profiler and disconnects the observer.\n */\nexport function createTickProfiler({\n ng,\n body,\n shouldTrack = () => true,\n onUpdates,\n}: TickProfilerOptions): () => void {\n let inTick = false;\n let inSyncPhase = false;\n const mutatedNodes = new Set<Node>();\n const tickInstances = new Set<object>();\n\n const observer = new MutationObserver((records) => {\n for (const r of records) {\n mutatedNodes.add(r.target);\n r.addedNodes.forEach((n) => mutatedNodes.add(n));\n r.removedNodes.forEach((n) => mutatedNodes.add(n));\n }\n });\n\n const removeProfiler = ng.ɵsetProfiler((event, instance) => {\n switch (event) {\n case PE.ChangeDetectionStart:\n if (inTick) break;\n inTick = true;\n mutatedNodes.clear();\n tickInstances.clear();\n observer.observe(body, {\n subtree: true, childList: true, attributes: true, characterData: true,\n });\n break;\n\n case PE.ChangeDetectionSyncStart:\n inSyncPhase = true;\n break;\n\n case PE.ChangeDetectionSyncEnd:\n inSyncPhase = false;\n break;\n\n case PE.TemplateUpdateStart:\n if (inSyncPhase && instance && shouldTrack(instance)) {\n tickInstances.add(instance);\n }\n break;\n\n case PE.ChangeDetectionEnd: {\n if (!inTick) break;\n inTick = false;\n inSyncPhase = false;\n\n const pending = observer.takeRecords();\n for (const r of pending) {\n mutatedNodes.add(r.target);\n r.addedNodes.forEach((n) => mutatedNodes.add(n));\n r.removedNodes.forEach((n) => mutatedNodes.add(n));\n }\n observer.disconnect();\n\n const mutatedHosts = buildMutatedHosts(mutatedNodes, body, ng);\n onUpdates(collectTickUpdates(tickInstances, mutatedHosts, ng));\n break;\n }\n }\n });\n\n return () => {\n removeProfiler();\n observer.disconnect();\n };\n}\n","import {\n afterEveryRender,\n AfterRenderRef,\n DOCUMENT,\n inject,\n Injectable,\n Injector,\n isDevMode,\n OnDestroy,\n runInInjectionContext,\n} from '@angular/core';\nimport { ComponentTracker } from './component-tracker';\nimport type { PendingUpdate } from './models/PendingUpdate';\nimport { getNgDebugApi } from './ng-debug';\nimport { OverlayService } from './overlay/overlay.service';\nimport { ScanConfigService } from './scan-config.service';\nimport { ANGULAR_SCAN_OPTIONS, WINDOW } from './tokens';\nimport { createTickProfiler } from './utils/create-tick-profiler';\n\n@Injectable({ providedIn: 'root' })\nexport class ScannerService implements OnDestroy {\n private readonly tracker = inject(ComponentTracker);\n private readonly overlay = inject(OverlayService);\n private readonly options = inject(ANGULAR_SCAN_OPTIONS);\n private readonly win = inject(WINDOW);\n private readonly document = inject(DOCUMENT);\n private readonly injector = inject(Injector);\n private readonly config = inject(ScanConfigService);\n\n private teardownProfiler: (() => void) | null = null;\n private afterRenderRef: AfterRenderRef | null = null;\n private pendingFlush: PendingUpdate[] = [];\n private toolbarInstance: object | null = null;\n\n initialize(): void {\n if (!isDevMode() || !this.win || this.options.enabled === false) return;\n\n const ng = getNgDebugApi();\n if (!ng) {\n console.warn(\n '[angular-scan] Angular debug APIs (window.ng) not available. ' +\n 'Ensure you are running in development mode.',\n );\n return;\n }\n\n this.afterRenderRef = runInInjectionContext(this.injector, () =>\n afterEveryRender({ write: () => this.flushPendingUpdates() }),\n );\n\n this.teardownProfiler = createTickProfiler({\n ng,\n body: this.document.body,\n shouldTrack: (instance) =>\n this.config.enabled() && instance !== this.toolbarInstance,\n onUpdates: (updates) => this.pendingFlush.push(...updates),\n });\n }\n\n setToolbarInstance(instance: object): void {\n this.toolbarInstance = instance;\n }\n\n private flushPendingUpdates(): void {\n const updates = this.pendingFlush.splice(0);\n if (updates.length === 0) return;\n\n for (const { instance, hostElement, kind } of updates) {\n const stats = this.tracker.recordRender(instance, hostElement, kind);\n this.overlay.onComponentChecked(stats);\n }\n this.tracker.snapshotTrackedComponents();\n }\n\n ngOnDestroy(): void {\n this.teardownProfiler?.();\n this.teardownProfiler = null;\n this.afterRenderRef?.destroy();\n this.afterRenderRef = null;\n this.pendingFlush = [];\n this.overlay.destroy();\n }\n}\n","import { ChangeDetectionStrategy, Component, inject, signal } from '@angular/core';\nimport { ComponentTracker } from '../component-tracker';\nimport { ScanConfigService } from '../scan-config.service';\n\n@Component({\n selector: 'angular-scan-toolbar',\n changeDetection: ChangeDetectionStrategy.OnPush,\n templateUrl: './toolbar.component.html',\n styleUrl: './toolbar.component.scss',\n host: { '[style.display]': '\"block\"' },\n})\nexport class ToolbarComponent {\n protected readonly tracker = inject(ComponentTracker);\n protected readonly config = inject(ScanConfigService);\n\n protected readonly expanded = signal(false);\n protected readonly settingsOpen = signal(false);\n\n protected toggleExpanded(): void {\n this.expanded.update((v) => !v);\n if (this.expanded()) {\n this.settingsOpen.set(false);\n }\n }\n\n protected toggleSettings(): void {\n this.settingsOpen.update((v) => !v);\n if (this.settingsOpen()) {\n this.expanded.set(false);\n }\n }\n\n protected toggleEnabled(): void {\n this.config.enabled.update((v) => !v);\n }\n\n protected toggleOverlay(): void {\n this.config.showOverlay.update((v) => !v);\n }\n\n protected toggleBadges(): void {\n this.config.showBadges.update((v) => !v);\n }\n\n protected resetStats(): void {\n this.tracker.reset();\n }\n\n protected onFlashDurationChange(event: Event): void {\n const value = Number((event.target as HTMLInputElement).value);\n this.config.flashDurationMs.set(value);\n }\n}\n","<div\n class=\"toolbar\"\n role=\"complementary\"\n aria-label=\"Angular Scan DevTools\"\n>\n <div class=\"toolbar__header\">\n <span class=\"toolbar__logo\" aria-hidden=\"true\">◉</span>\n <span class=\"toolbar__title\">angular-scan</span>\n\n <button\n class=\"toolbar__btn\"\n type=\"button\"\n [attr.aria-pressed]=\"!config.enabled()\"\n [title]=\"config.enabled() ? 'Pause scanning' : 'Resume scanning'\"\n (click)=\"toggleEnabled()\"\n >{{ config.enabled() ? '⏸' : '▶' }}</button>\n\n <button\n class=\"toolbar__btn\"\n type=\"button\"\n [attr.aria-pressed]=\"settingsOpen()\"\n title=\"Settings\"\n (click)=\"toggleSettings()\"\n >⚙</button>\n\n <button\n class=\"toolbar__btn\"\n type=\"button\"\n [attr.aria-pressed]=\"expanded()\"\n [title]=\"expanded() ? 'Collapse inspector' : 'Expand inspector'\"\n (click)=\"toggleExpanded()\"\n >{{ expanded() ? '▲' : '▼' }}</button>\n </div>\n\n <div class=\"toolbar__stats\">\n <span class=\"toolbar__stat\" title=\"Total change detection checks\">\n <span class=\"toolbar__stat-label\">checks</span>\n <strong class=\"toolbar__stat-value\">{{ tracker.totalRenders() }}</strong>\n </span>\n <span\n class=\"toolbar__stat\"\n [class.toolbar__stat--warn]=\"tracker.totalUnnecessary() > 0\"\n title=\"Unnecessary renders: component was checked but DOM did not change\"\n >\n <span class=\"toolbar__stat-label\">wasted</span>\n <strong class=\"toolbar__stat-value\">{{ tracker.totalUnnecessary() }}</strong>\n </span>\n </div>\n\n @if (settingsOpen()) {\n <div class=\"toolbar__settings\" role=\"group\" aria-label=\"Scan settings\">\n\n <label class=\"toolbar__setting\">\n <span class=\"toolbar__setting-label\">Enable scanning</span>\n <button\n class=\"toolbar__toggle\"\n type=\"button\"\n role=\"switch\"\n [attr.aria-checked]=\"config.enabled()\"\n (click)=\"toggleEnabled()\"\n [class.toolbar__toggle--on]=\"config.enabled()\"\n >{{ config.enabled() ? 'ON' : 'OFF' }}</button>\n </label>\n\n <label class=\"toolbar__setting\">\n <span class=\"toolbar__setting-label\">Flash overlay</span>\n <button\n class=\"toolbar__toggle\"\n type=\"button\"\n role=\"switch\"\n [attr.aria-checked]=\"config.showOverlay()\"\n (click)=\"toggleOverlay()\"\n [class.toolbar__toggle--on]=\"config.showOverlay()\"\n >{{ config.showOverlay() ? 'ON' : 'OFF' }}</button>\n </label>\n\n <label class=\"toolbar__setting\">\n <span class=\"toolbar__setting-label\">Render badges</span>\n <button\n class=\"toolbar__toggle\"\n type=\"button\"\n role=\"switch\"\n [attr.aria-checked]=\"config.showBadges()\"\n (click)=\"toggleBadges()\"\n [class.toolbar__toggle--on]=\"config.showBadges()\"\n >{{ config.showBadges() ? 'ON' : 'OFF' }}</button>\n </label>\n\n <label class=\"toolbar__setting toolbar__setting--column\">\n <span class=\"toolbar__setting-label\">\n Flash duration\n <span class=\"toolbar__setting-value\">{{ config.flashDurationMs() }}ms</span>\n </span>\n <input\n class=\"toolbar__slider\"\n type=\"range\"\n min=\"100\"\n max=\"2000\"\n step=\"100\"\n [value]=\"config.flashDurationMs()\"\n (input)=\"onFlashDurationChange($event)\"\n aria-label=\"Flash duration in milliseconds\"\n />\n </label>\n\n <button\n class=\"toolbar__reset\"\n type=\"button\"\n title=\"Clear all render stats\"\n (click)=\"resetStats()\"\n >↺ Reset stats</button>\n\n </div>\n }\n\n @if (expanded()) {\n <div\n class=\"toolbar__inspector\"\n role=\"list\"\n aria-label=\"Component render counts\"\n >\n @for (comp of tracker.trackedComponents(); track comp.hostElement) {\n <div\n class=\"toolbar__component\"\n role=\"listitem\"\n [class.toolbar__component--warn]=\"comp.lastRenderKind === 'unnecessary'\"\n [title]=\"comp.componentName + ' — ' + comp.totalRenders + ' checks, ' + comp.unnecessaryRenders + ' wasted'\"\n >\n <span class=\"toolbar__component-name\">{{ comp.componentName }}</span>\n <span class=\"toolbar__component-count\">{{ comp.totalRenders }}</span>\n @if (comp.unnecessaryRenders > 0) {\n <span class=\"toolbar__component-wasted\" aria-label=\"wasted renders\">\n {{ comp.unnecessaryRenders }}W\n </span>\n }\n </div>\n }\n </div>\n }\n</div>\n","import {\n EnvironmentProviders,\n makeEnvironmentProviders,\n isDevMode,\n provideEnvironmentInitializer,\n inject,\n ApplicationRef,\n createComponent,\n EnvironmentInjector,\n} from '@angular/core';\nimport { DOCUMENT } from '@angular/common';\nimport { ScannerService } from './scanner.service';\nimport { OverlayService } from './overlay/overlay.service';\nimport { ToolbarComponent } from './toolbar/toolbar.component';\nimport { ANGULAR_SCAN_OPTIONS } from './tokens';\nimport type { AngularScanOptions } from './models/AngularScanOptions';\n\n/**\n * Provides angular-scan for development-time render tracking.\n *\n * Add to your application providers:\n * ```ts\n * bootstrapApplication(AppComponent, {\n * providers: [provideAngularScan()]\n * });\n * ```\n *\n * This is a complete no-op in production builds (`isDevMode() === false`),\n * so it can safely be left in your app config.\n */\nexport function provideAngularScan(options: AngularScanOptions = {}): EnvironmentProviders {\n // Return empty providers in production — entire library is tree-shaken\n if (!isDevMode()) {\n return makeEnvironmentProviders([]);\n }\n\n const resolvedOptions: AngularScanOptions = {\n enabled: true,\n flashDurationMs: 500,\n showBadges: true,\n showToolbar: true,\n ...options,\n };\n\n return makeEnvironmentProviders([\n { provide: ANGULAR_SCAN_OPTIONS, useValue: resolvedOptions },\n provideEnvironmentInitializer(() => {\n const overlay = inject(OverlayService);\n const scanner = inject(ScannerService);\n const opts = inject(ANGULAR_SCAN_OPTIONS);\n\n overlay.initialize();\n scanner.initialize();\n\n if (opts.showToolbar !== false) {\n mountToolbar(scanner);\n }\n }),\n ]);\n}\n\n/** Create the toolbar outside Angular's component tree and attach it to the DOM. */\nfunction mountToolbar(scanner: ScannerService): void {\n const injector = inject(EnvironmentInjector);\n const doc = inject(DOCUMENT);\n const appRef = inject(ApplicationRef);\n\n // Creating outside the component tree means it won't appear in CD tracking.\n // Attaching to ApplicationRef ensures signals and change detection work.\n const toolbarRef = createComponent(ToolbarComponent, { environmentInjector: injector });\n\n doc.body.appendChild(toolbarRef.location.nativeElement);\n appRef.attachView(toolbarRef.hostView);\n\n // Tell the scanner to exclude the toolbar's own renders\n scanner.setToolbarInstance(toolbarRef.instance);\n}\n","import { isDevMode } from '@angular/core';\nimport type { AngularScanOptions } from './models/AngularScanOptions';\nimport type { RenderKind } from './models/RenderKind';\nimport { getNgDebugApi } from './ng-debug';\nimport { createCanvasOverlay } from './overlay/canvas-overlay';\nimport { createTickProfiler } from './utils/create-tick-profiler';\n\n/**\n * Imperative API for angular-scan.\n *\n * Use this when you cannot modify application providers (e.g. micro-frontends,\n * third-party apps). Call before `bootstrapApplication()`.\n *\n * ```ts\n * // main.ts\n * import { scan } from 'angular-scan';\n * scan();\n * bootstrapApplication(AppComponent, appConfig);\n * ```\n *\n * @returns A teardown function that stops scanning and removes the overlay.\n */\nexport function scan(options: AngularScanOptions = {}): () => void {\n if (!isDevMode()) return () => {};\n if (typeof window === 'undefined') return () => {};\n if (options.enabled === false) return () => {};\n\n const ng = getNgDebugApi();\n if (!ng) {\n console.warn(\n '[angular-scan] Angular debug APIs (window.ng) not available. ' +\n 'Ensure you are running in development mode.',\n );\n return () => {};\n }\n\n const durationMs = options.flashDurationMs ?? 500;\n const showBadges = options.showBadges !== false;\n const overlay = createCanvasOverlay(document, window);\n const renderCounts = new WeakMap<object, number>();\n const badges = new Map<Element, HTMLElement>();\n\n const teardown = createTickProfiler({\n ng,\n body: document.body,\n onUpdates: (updates) => {\n queueMicrotask(() => {\n for (const { instance, hostElement, kind } of updates) {\n const count = (renderCounts.get(instance) ?? 0) + 1;\n renderCounts.set(instance, count);\n overlay.flash(hostElement, kind, durationMs);\n if (showBadges) {\n updateBadge(badges, hostElement, count, kind);\n }\n }\n });\n },\n });\n\n return () => {\n teardown();\n overlay.detach();\n for (const b of badges.values()) {\n b.remove();\n }\n badges.clear();\n };\n}\n\nfunction updateBadge(\n badges: Map<Element, HTMLElement>,\n hostEl: Element,\n count: number,\n kind: RenderKind,\n): void {\n let badge = badges.get(hostEl);\n\n if (!badge) {\n badge = document.createElement('div');\n badge.setAttribute('aria-hidden', 'true');\n badge.setAttribute('role', 'presentation');\n badge.style.cssText = [\n 'position:absolute',\n 'top:2px',\n 'right:2px',\n 'z-index:2147483645',\n 'pointer-events:none',\n 'font:bold 9px/13px monospace',\n 'padding:1px 4px',\n 'border-radius:3px',\n 'min-width:16px',\n 'text-align:center',\n 'color:#fff',\n ].join(';');\n\n const htmlEl = hostEl as HTMLElement;\n if (getComputedStyle(htmlEl).position === 'static') {\n htmlEl.style.position = 'relative';\n }\n\n hostEl.appendChild(badge);\n badges.set(hostEl, badge);\n }\n\n badge.style.background = kind === 'unnecessary' ? '#f44336' : '#ff9800';\n badge.textContent = String(count);\n}\n\n","/*\n * Public API Surface of angular-scan\n */\n\nexport { provideAngularScan } from './lib/provide-angular-scan';\nexport { scan } from './lib/scan';\nexport type { AngularScanOptions } from './lib/models/AngularScanOptions';\nexport type { ComponentStats } from './lib/models/ComponentStats';\nexport type { RenderKind } from './lib/models/RenderKind';\n","/**\n * Generated bundle index. Do not edit.\n */\n\nexport * from './public-api';\n"],"names":["DOCUMENT","PE"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"angular-scan.mjs","sources":["../../../projects/angular-scan/src/lib/services/component-tracker/component-tracker.ts","../../../projects/angular-scan/src/lib/utils/ng-debug/ng-debug.ts","../../../projects/angular-scan/src/lib/tokens.ts","../../../projects/angular-scan/src/lib/services/scan-config/scan-config.service.ts","../../../projects/angular-scan/src/lib/overlay/badge.ts","../../../projects/angular-scan/src/lib/overlay/canvas-overlay.ts","../../../projects/angular-scan/src/lib/overlay/overlay.service.ts","../../../projects/angular-scan/src/lib/models/ProfilerEvents.ts","../../../projects/angular-scan/src/lib/utils/build-mutated-hosts/build-mutated-hosts.ts","../../../projects/angular-scan/src/lib/utils/collect-tick-updates/collect-tick-updates.ts","../../../projects/angular-scan/src/lib/utils/create-tick-profiler/create-tick-profiler.ts","../../../projects/angular-scan/src/lib/services/scanner/scanner.service.ts","../../../projects/angular-scan/src/lib/toolbar/toolbar.component.ts","../../../projects/angular-scan/src/lib/toolbar/toolbar.component.html","../../../projects/angular-scan/src/lib/provide-angular-scan.ts","../../../projects/angular-scan/src/lib/scan.ts","../../../projects/angular-scan/src/public-api.ts","../../../projects/angular-scan/src/angular-scan.ts"],"sourcesContent":["import { Injectable, signal } from '@angular/core';\nimport type { ComponentStats } from '../../models/ComponentStats';\nimport type { RenderKind } from '../../models/RenderKind';\n\n@Injectable({ providedIn: 'root' })\nexport class ComponentTracker {\n private readonly byInstance = new WeakMap<object, ComponentStats>();\n private readonly byElement = new Map<Element, object>();\n\n readonly totalRenders = signal(0);\n readonly totalUnnecessary = signal(0);\n readonly trackedComponents = signal<readonly ComponentStats[]>([]);\n\n recordRender(instance: object, hostElement: Element, kind: RenderKind): ComponentStats {\n const DEFAULT = {\n componentName: instance.constructor.name,\n hostElement,\n totalRenders: 0,\n unnecessaryRenders: 0,\n lastRenderKind: kind,\n lastRenderTimestamp: 0,\n };\n const prev = this.byInstance.get(instance) ?? DEFAULT;\n\n const isUnnecessary = kind === 'unnecessary';\n const next: ComponentStats = {\n ...prev,\n totalRenders: prev.totalRenders + 1,\n unnecessaryRenders: prev.unnecessaryRenders + (isUnnecessary ? 1 : 0),\n lastRenderKind: kind,\n lastRenderTimestamp: Date.now(),\n };\n\n this.byInstance.set(instance, next);\n this.byElement.set(hostElement, instance);\n\n this.totalRenders.update((n) => n + 1);\n if (isUnnecessary) {\n this.totalUnnecessary.update((n) => n + 1);\n }\n\n return next;\n }\n\n snapshotTrackedComponents(): void {\n const list: ComponentStats[] = [];\n for (const [, instance] of this.byElement) {\n const stats = this.byInstance.get(instance);\n if (stats) {\n list.push(stats);\n }\n }\n this.trackedComponents.set(list);\n }\n\n reset(): void {\n this.byElement.clear();\n this.totalRenders.set(0);\n this.totalUnnecessary.set(0);\n this.trackedComponents.set([]);\n }\n}\n","import type { NgDebugApi } from '../../models/NgDebugApi';\n\n/**\n * Returns the Angular debug API (window.ng) if available.\n * Returns null in SSR, production builds, or when Angular DevTools APIs are absent.\n *\n * Safe to call before Angular is bootstrapped — the API is attached to window\n * by Angular's dev mode runtime.\n */\nexport function getNgDebugApi(): NgDebugApi | null {\n if (typeof window === 'undefined') return null;\n\n const ng = (window as unknown as Record<string, unknown>)['ng'];\n if (!ng || typeof ng !== 'object') return null;\n\n const api = ng as Partial<NgDebugApi>;\n\n // ɵsetProfiler is the sentinel for dev mode — absent in production builds\n if (typeof api.ɵsetProfiler !== 'function') return null;\n if (typeof api.getHostElement !== 'function') return null;\n\n return api as NgDebugApi;\n}\n","import { DOCUMENT } from '@angular/common';\nimport { InjectionToken, inject } from '@angular/core';\nimport type { AngularScanOptions } from './models/AngularScanOptions';\nimport type { BrowserWindow } from './models/BrowserWindow';\n\nexport const ANGULAR_SCAN_OPTIONS = new InjectionToken<AngularScanOptions>('ANGULAR_SCAN_OPTIONS', {\n providedIn: 'root',\n factory: () => ({}),\n});\n\n/** The browser Window object. Resolves to null in SSR. */\nexport const WINDOW = new InjectionToken<BrowserWindow | null>('WINDOW', {\n providedIn: 'root',\n factory: () => inject(DOCUMENT).defaultView,\n});\n","import { Injectable, inject, signal } from '@angular/core';\nimport { ANGULAR_SCAN_OPTIONS } from '../../tokens';\n\n@Injectable({ providedIn: 'root' })\nexport class ScanConfigService {\n private readonly options = inject(ANGULAR_SCAN_OPTIONS);\n\n readonly enabled = signal(this.options.enabled !== false);\n readonly showOverlay = signal(true);\n readonly showBadges = signal(this.options.showBadges !== false);\n readonly flashDurationMs = signal(this.options.flashDurationMs ?? 500);\n}\n","import type { BrowserWindow } from '../models/BrowserWindow';\nimport type { RenderKind } from '../models/RenderKind';\n\nconst BADGE_CSS = [\n 'position:absolute',\n 'top:2px',\n 'right:2px',\n 'z-index:2147483645',\n 'pointer-events:none',\n 'font:bold 9px/13px monospace',\n 'padding:1px 4px',\n 'border-radius:3px',\n 'min-width:16px',\n 'text-align:center',\n 'color:#fff',\n 'white-space:nowrap',\n].join(';');\n\nexport const BADGE_COLORS = {\n render: '#ff9800',\n unnecessary: '#f44336',\n} as const satisfies Record<RenderKind, string>;\n\n/**\n * Creates or reuses the render-count badge on a host element.\n * Returns the badge so callers can set extra attributes (e.g. `title`).\n */\nexport function createOrUpdateBadge(\n badges: Map<Element, HTMLElement>,\n hostEl: Element,\n count: number,\n kind: RenderKind,\n doc: Document = document,\n win?: (BrowserWindow) | null,\n): HTMLElement {\n let badge = badges.get(hostEl);\n\n if (!badge) {\n badge = doc.createElement('div');\n badge.setAttribute('aria-hidden', 'true');\n badge.setAttribute('role', 'presentation');\n badge.style.cssText = BADGE_CSS;\n ensurePositioned(hostEl, win);\n hostEl.appendChild(badge);\n badges.set(hostEl, badge);\n }\n\n badge.style.background = BADGE_COLORS[kind];\n badge.textContent = String(count);\n return badge;\n}\n\nexport function ensurePositioned(\n el: Element,\n win?: (BrowserWindow) | null,\n): void {\n const htmlEl = el as HTMLElement;\n const position = win\n ? win.getComputedStyle(htmlEl).position\n : getComputedStyle(htmlEl).position;\n if (!position || position === 'static') {\n htmlEl.style.position = 'relative';\n }\n}\n\nexport function clearBadges(badges: Map<Element, HTMLElement>): void {\n for (const badge of badges.values()) {\n badge.remove();\n }\n badges.clear();\n}\n","import type { BrowserWindow } from '../models/BrowserWindow';\nimport type { CanvasOverlay } from '../models/CanvasOverlay';\nimport type { FlashRect } from '../models/FlashRect';\nimport type { OverlayState } from '../models/OverlayState';\nimport type { RenderKind } from '../models/RenderKind';\n\nconst RENDER_COLOR = '255, 200, 0'; // yellow — normal re-render\nconst UNNECESSARY_COLOR = '255, 60, 60'; // red — unnecessary render\n\nfunction createCanvas(doc: Document): HTMLCanvasElement {\n const canvas = doc.createElement('canvas');\n canvas.setAttribute('aria-hidden', 'true');\n canvas.setAttribute('role', 'presentation');\n canvas.style.cssText = [\n 'position:fixed',\n 'top:0',\n 'left:0',\n 'width:100%',\n 'height:100%',\n 'pointer-events:none',\n 'z-index:2147483646',\n ].join(';');\n return canvas;\n}\n\nfunction resizeCanvas(canvas: HTMLCanvasElement, win: BrowserWindow): void {\n canvas.width = win.innerWidth;\n canvas.height = win.innerHeight;\n}\n\nfunction toFlashRect(\n element: Element,\n kind: RenderKind,\n durationMs: number,\n win: BrowserWindow,\n): FlashRect | null {\n const { left, top, width, height } = element.getBoundingClientRect();\n if (width === 0 || height === 0) return null;\n\n return { x: left, y: top, width, height, kind, startTime: win.performance.now(), durationMs };\n}\n\nfunction drawRect(ctx: CanvasRenderingContext2D, r: FlashRect, now: number): void {\n const elapsed = now - r.startTime;\n const alpha = Math.max(0, 1 - elapsed / r.durationMs);\n const color = r.kind === 'render' ? RENDER_COLOR : UNNECESSARY_COLOR;\n\n ctx.fillStyle = `rgba(${color}, ${alpha * 0.1})`;\n ctx.fillRect(r.x, r.y, r.width, r.height);\n\n ctx.strokeStyle = `rgba(${color}, ${alpha * 0.9})`;\n ctx.lineWidth = 2;\n ctx.strokeRect(r.x + 1, r.y + 1, r.width - 2, r.height - 2);\n}\n\nfunction renderFrame(\n ctx: CanvasRenderingContext2D,\n canvas: HTMLCanvasElement,\n rects: readonly FlashRect[],\n now: number,\n): FlashRect[] {\n ctx.clearRect(0, 0, canvas.width, canvas.height);\n const active = rects.filter((r) => now - r.startTime < r.durationMs);\n for (const r of active) {\n drawRect(ctx, r, now);\n }\n return active;\n}\n\n/**\n * Creates a canvas overlay, attaches it to the document, and starts the render loop.\n * Returns a minimal interface: flash to queue an animation, detach to clean up.\n */\nexport function createCanvasOverlay(doc: Document, win: BrowserWindow): CanvasOverlay {\n let state: OverlayState = { rects: [], rafId: 0 };\n\n const canvas = createCanvas(doc);\n doc.body.appendChild(canvas);\n const ctx = canvas.getContext('2d')!;\n\n const onResize = (): void => resizeCanvas(canvas, win);\n const loop = (now: number): void => {\n state = {\n rects: renderFrame(ctx, canvas, state.rects, now),\n rafId: win.requestAnimationFrame(loop),\n };\n };\n\n resizeCanvas(canvas, win);\n win.addEventListener('resize', onResize);\n state = { ...state, rafId: win.requestAnimationFrame(loop) };\n\n return {\n flash(element, kind, durationMs) {\n const rect = toFlashRect(element, kind, durationMs, win);\n if (rect) {\n state = { ...state, rects: [...state.rects, rect] };\n }\n },\n\n detach() {\n win.cancelAnimationFrame(state.rafId);\n win.removeEventListener('resize', onResize);\n canvas.remove();\n state = { rects: [], rafId: 0 };\n },\n };\n}\n","import { DOCUMENT, Injectable, inject, isDevMode } from '@angular/core';\nimport type { CanvasOverlay } from '../models/CanvasOverlay';\nimport type { ComponentStats } from '../models/ComponentStats';\nimport { ScanConfigService } from '../services/scan-config/scan-config.service';\nimport { ANGULAR_SCAN_OPTIONS, WINDOW } from '../tokens';\nimport { clearBadges, createOrUpdateBadge } from './badge';\nimport { createCanvasOverlay } from './canvas-overlay';\n\n@Injectable({ providedIn: 'root' })\nexport class OverlayService {\n private readonly document = inject(DOCUMENT);\n private readonly win = inject(WINDOW);\n private readonly options = inject(ANGULAR_SCAN_OPTIONS);\n private readonly config = inject(ScanConfigService);\n\n private canvas: CanvasOverlay | null = null;\n private readonly badges = new Map<Element, HTMLElement>();\n\n initialize(): void {\n if (!isDevMode() || !this.win || this.options.enabled === false) {\n return;\n }\n this.canvas = createCanvasOverlay(this.document, this.win);\n }\n\n destroy(): void {\n this.canvas?.detach();\n this.canvas = null;\n clearBadges(this.badges);\n }\n\n onComponentChecked(stats: ComponentStats): void {\n if (this.config.showOverlay()) {\n this.canvas?.flash(stats.hostElement, stats.lastRenderKind, this.config.flashDurationMs());\n }\n\n if (this.config.showBadges()) {\n const badge = createOrUpdateBadge(\n this.badges,\n stats.hostElement,\n stats.totalRenders,\n stats.lastRenderKind,\n this.document,\n this.win,\n );\n badge.title = `${stats.componentName}: ${stats.totalRenders} renders, ${stats.unnecessaryRenders} unnecessary`;\n } else {\n this.removeBadge(stats.hostElement);\n }\n }\n\n removeBadge(el: Element): void {\n this.badges.get(el)?.remove();\n this.badges.delete(el);\n }\n}\n","/**\n * Angular profiler event IDs — stable dev-mode contract, same as Angular DevTools.\n *\n * @see https://github.com/angular/angular/blob/main/packages/core/primitives/devtools/src/profiler_types.ts\n * @see https://github.com/angular/angular/blob/main/devtools/projects/ng-devtools-backend/src/lib/hooks/capture.ts\n */\nexport const PROFILER_EVENTS = {\n TemplateUpdateStart: 2,\n ChangeDetectionStart: 12,\n ChangeDetectionEnd: 13,\n ChangeDetectionSyncStart: 14,\n ChangeDetectionSyncEnd: 15,\n} as const;\n","import type { NgDebugApi } from '../../models/NgDebugApi';\n\n/** Walk mutated nodes UP the DOM to find their owning Angular component host. */\nexport function buildMutatedHosts(\n nodes: Set<Node>,\n body: Element,\n ng: NgDebugApi,\n): Set<Element> {\n const hosts = new Set<Element>();\n\n for (const node of nodes) {\n let current: Node | null = node;\n\n while (current && current !== body) {\n if (current instanceof Element) {\n try {\n if (ng.getComponent(current)) {\n hosts.add(current);\n break;\n }\n } catch { /* ignore destroyed nodes */ }\n }\n current = current.parentNode;\n }\n }\n\n return hosts;\n}\n","import type { NgDebugApi } from '../../models/NgDebugApi';\nimport type { PendingUpdate } from '../../models/PendingUpdate';\nimport type { RenderKind } from '../../models/RenderKind';\n\n/** Map checked instances to PendingUpdate records — pure, no side effects. */\nexport function collectTickUpdates(\n instances: Set<object>,\n mutatedHosts: Set<Element>,\n ng: NgDebugApi,\n): PendingUpdate[] {\n const updates: PendingUpdate[] = [];\n\n for (const instance of instances) {\n try {\n const hostElement = ng.getHostElement(instance);\n if (!hostElement) continue;\n const kind: RenderKind = mutatedHosts.has(hostElement) ? 'render' : 'unnecessary';\n updates.push({ instance, hostElement, kind });\n } catch { /* component destroyed */ }\n }\n\n return updates;\n}\n","import type { TickProfilerOptions } from '../../models/TickProfilerOptions';\nimport { PROFILER_EVENTS as PE } from '../../models/ProfilerEvents';\nimport { buildMutatedHosts } from '../build-mutated-hosts/build-mutated-hosts';\nimport { collectTickUpdates } from '../collect-tick-updates/collect-tick-updates';\n\n/**\n * Wires up the Angular profiler + MutationObserver to track per-tick render updates.\n * Returns a teardown function that removes the profiler and disconnects the observer.\n */\nexport function createTickProfiler({\n ng,\n body,\n shouldTrack = () => true,\n onUpdates,\n}: TickProfilerOptions): () => void {\n let inTick = false;\n let inSyncPhase = false;\n const mutatedNodes = new Set<Node>();\n const tickInstances = new Set<object>();\n\n const observer = new MutationObserver((records) => {\n for (const r of records) {\n mutatedNodes.add(r.target);\n r.addedNodes.forEach((n) => mutatedNodes.add(n));\n r.removedNodes.forEach((n) => mutatedNodes.add(n));\n }\n });\n\n const removeProfiler = ng.ɵsetProfiler((event, instance) => {\n switch (event) {\n case PE.ChangeDetectionStart:\n if (inTick) {\n break;\n }\n inTick = true;\n mutatedNodes.clear();\n tickInstances.clear();\n observer.observe(body, {\n subtree: true, childList: true, attributes: true, characterData: true,\n });\n break;\n\n case PE.ChangeDetectionSyncStart:\n inSyncPhase = true;\n break;\n\n case PE.ChangeDetectionSyncEnd:\n inSyncPhase = false;\n break;\n\n case PE.TemplateUpdateStart:\n if (inSyncPhase && instance && shouldTrack(instance)) {\n tickInstances.add(instance);\n }\n break;\n\n case PE.ChangeDetectionEnd: {\n if (!inTick) {\n break;\n }\n inTick = false;\n inSyncPhase = false;\n\n const pending = observer.takeRecords();\n for (const r of pending) {\n mutatedNodes.add(r.target);\n r.addedNodes.forEach((n) => mutatedNodes.add(n));\n r.removedNodes.forEach((n) => mutatedNodes.add(n));\n }\n observer.disconnect();\n\n const mutatedHosts = buildMutatedHosts(mutatedNodes, body, ng);\n onUpdates(collectTickUpdates(tickInstances, mutatedHosts, ng));\n break;\n }\n }\n });\n\n return () => {\n removeProfiler();\n observer.disconnect();\n };\n}\n","import {\n afterEveryRender,\n AfterRenderRef,\n DOCUMENT,\n inject,\n Injectable,\n Injector,\n isDevMode,\n OnDestroy,\n runInInjectionContext,\n} from '@angular/core';\nimport { ComponentTracker } from '../component-tracker/component-tracker';\nimport type { PendingUpdate } from '../../models/PendingUpdate';\nimport { getNgDebugApi } from '../../utils/ng-debug/ng-debug';\nimport { OverlayService } from '../../overlay/overlay.service';\nimport { ScanConfigService } from '../scan-config/scan-config.service';\nimport { ANGULAR_SCAN_OPTIONS, WINDOW } from '../../tokens';\nimport { createTickProfiler } from '../../utils/create-tick-profiler/create-tick-profiler';\n\n@Injectable({ providedIn: 'root' })\nexport class ScannerService implements OnDestroy {\n private readonly tracker = inject(ComponentTracker);\n private readonly overlay = inject(OverlayService);\n private readonly options = inject(ANGULAR_SCAN_OPTIONS);\n private readonly win = inject(WINDOW);\n private readonly document = inject(DOCUMENT);\n private readonly injector = inject(Injector);\n private readonly config = inject(ScanConfigService);\n\n private teardownProfiler: (() => void) | null = null;\n private afterRenderRef: AfterRenderRef | null = null;\n private pendingFlush: PendingUpdate[] = [];\n private toolbarInstance: object | null = null;\n\n initialize(): void {\n if (!isDevMode() || !this.win || this.options.enabled === false) {\n return;\n }\n\n const ng = getNgDebugApi();\n if (!ng) {\n console.warn(\n '[angular-scan] Angular debug APIs (window.ng) not available. ' +\n 'Ensure you are running in development mode.',\n );\n return;\n }\n\n this.afterRenderRef = runInInjectionContext(this.injector, () =>\n afterEveryRender({ write: () => this.flushPendingUpdates() }),\n );\n\n this.teardownProfiler = createTickProfiler({\n ng,\n body: this.document.body,\n shouldTrack: (instance) =>\n this.config.enabled() && instance !== this.toolbarInstance,\n onUpdates: (updates) => this.pendingFlush.push(...updates),\n });\n }\n\n setToolbarInstance(instance: object): void {\n this.toolbarInstance = instance;\n }\n\n private flushPendingUpdates(): void {\n const updates = this.pendingFlush.splice(0);\n if (updates.length === 0) return;\n\n for (const { instance, hostElement, kind } of updates) {\n const stats = this.tracker.recordRender(instance, hostElement, kind);\n this.overlay.onComponentChecked(stats);\n }\n this.tracker.snapshotTrackedComponents();\n }\n\n ngOnDestroy(): void {\n this.teardownProfiler?.();\n this.teardownProfiler = null;\n this.afterRenderRef?.destroy();\n this.afterRenderRef = null;\n this.pendingFlush = [];\n this.overlay.destroy();\n }\n}\n","import { ChangeDetectionStrategy, Component, inject, signal } from '@angular/core';\nimport { ComponentTracker } from '../services/component-tracker/component-tracker';\nimport { ScanConfigService } from '../services/scan-config/scan-config.service';\n\n@Component({\n selector: 'angular-scan-toolbar',\n changeDetection: ChangeDetectionStrategy.OnPush,\n templateUrl: './toolbar.component.html',\n styleUrl: './toolbar.component.scss',\n host: { '[style.display]': '\"block\"' },\n})\nexport class ToolbarComponent {\n protected readonly tracker = inject(ComponentTracker);\n protected readonly config = inject(ScanConfigService);\n\n protected readonly expanded = signal(false);\n protected readonly settingsOpen = signal(false);\n\n protected toggleExpanded(): void {\n this.expanded.update((v) => !v);\n if (this.expanded()) {\n this.settingsOpen.set(false);\n }\n }\n\n protected toggleSettings(): void {\n this.settingsOpen.update((v) => !v);\n if (this.settingsOpen()) {\n this.expanded.set(false);\n }\n }\n\n protected toggleEnabled(): void {\n this.config.enabled.update((v) => !v);\n }\n\n protected toggleOverlay(): void {\n this.config.showOverlay.update((v) => !v);\n }\n\n protected toggleBadges(): void {\n this.config.showBadges.update((v) => !v);\n }\n\n protected resetStats(): void {\n this.tracker.reset();\n }\n\n protected onFlashDurationChange(event: Event): void {\n const value = Number((event.target as HTMLInputElement).value);\n this.config.flashDurationMs.set(value);\n }\n}\n","<div\n class=\"toolbar\"\n role=\"complementary\"\n aria-label=\"Angular Scan DevTools\"\n>\n <div class=\"toolbar__header\">\n <span class=\"toolbar__logo\" aria-hidden=\"true\">◉</span>\n <span class=\"toolbar__title\">angular-scan</span>\n\n <button\n class=\"toolbar__btn\"\n type=\"button\"\n [attr.aria-pressed]=\"!config.enabled()\"\n [title]=\"config.enabled() ? 'Pause scanning' : 'Resume scanning'\"\n (click)=\"toggleEnabled()\"\n >{{ config.enabled() ? '⏸' : '▶' }}</button>\n\n <button\n class=\"toolbar__btn\"\n type=\"button\"\n [attr.aria-pressed]=\"settingsOpen()\"\n title=\"Settings\"\n (click)=\"toggleSettings()\"\n >⚙</button>\n\n <button\n class=\"toolbar__btn\"\n type=\"button\"\n [attr.aria-pressed]=\"expanded()\"\n [title]=\"expanded() ? 'Collapse inspector' : 'Expand inspector'\"\n (click)=\"toggleExpanded()\"\n >{{ expanded() ? '▲' : '▼' }}</button>\n </div>\n\n <div class=\"toolbar__stats\">\n <span class=\"toolbar__stat\" title=\"Total change detection checks\">\n <span class=\"toolbar__stat-label\">checks</span>\n <strong class=\"toolbar__stat-value\">{{ tracker.totalRenders() }}</strong>\n </span>\n <span\n class=\"toolbar__stat\"\n [class.toolbar__stat--warn]=\"tracker.totalUnnecessary() > 0\"\n title=\"Unnecessary renders: component was checked but DOM did not change\"\n >\n <span class=\"toolbar__stat-label\">wasted</span>\n <strong class=\"toolbar__stat-value\">{{ tracker.totalUnnecessary() }}</strong>\n </span>\n </div>\n\n @if (settingsOpen()) {\n <div class=\"toolbar__settings\" role=\"group\" aria-label=\"Scan settings\">\n\n <label class=\"toolbar__setting\">\n <span class=\"toolbar__setting-label\">Enable scanning</span>\n <button\n class=\"toolbar__toggle\"\n type=\"button\"\n role=\"switch\"\n [attr.aria-checked]=\"config.enabled()\"\n (click)=\"toggleEnabled()\"\n [class.toolbar__toggle--on]=\"config.enabled()\"\n >{{ config.enabled() ? 'ON' : 'OFF' }}</button>\n </label>\n\n <label class=\"toolbar__setting\">\n <span class=\"toolbar__setting-label\">Flash overlay</span>\n <button\n class=\"toolbar__toggle\"\n type=\"button\"\n role=\"switch\"\n [attr.aria-checked]=\"config.showOverlay()\"\n (click)=\"toggleOverlay()\"\n [class.toolbar__toggle--on]=\"config.showOverlay()\"\n >{{ config.showOverlay() ? 'ON' : 'OFF' }}</button>\n </label>\n\n <label class=\"toolbar__setting\">\n <span class=\"toolbar__setting-label\">Render badges</span>\n <button\n class=\"toolbar__toggle\"\n type=\"button\"\n role=\"switch\"\n [attr.aria-checked]=\"config.showBadges()\"\n (click)=\"toggleBadges()\"\n [class.toolbar__toggle--on]=\"config.showBadges()\"\n >{{ config.showBadges() ? 'ON' : 'OFF' }}</button>\n </label>\n\n <label class=\"toolbar__setting toolbar__setting--column\">\n <span class=\"toolbar__setting-label\">\n Flash duration\n <span class=\"toolbar__setting-value\">{{ config.flashDurationMs() }}ms</span>\n </span>\n <input\n class=\"toolbar__slider\"\n type=\"range\"\n min=\"100\"\n max=\"2000\"\n step=\"100\"\n [value]=\"config.flashDurationMs()\"\n (input)=\"onFlashDurationChange($event)\"\n aria-label=\"Flash duration in milliseconds\"\n />\n </label>\n\n <button\n class=\"toolbar__reset\"\n type=\"button\"\n title=\"Clear all render stats\"\n (click)=\"resetStats()\"\n >↺ Reset stats</button>\n\n </div>\n }\n\n @if (expanded()) {\n <div\n class=\"toolbar__inspector\"\n role=\"list\"\n aria-label=\"Component render counts\"\n >\n @for (comp of tracker.trackedComponents(); track comp.hostElement) {\n <div\n class=\"toolbar__component\"\n role=\"listitem\"\n [class.toolbar__component--warn]=\"comp.lastRenderKind === 'unnecessary'\"\n [title]=\"comp.componentName + ' — ' + comp.totalRenders + ' checks, ' + comp.unnecessaryRenders + ' wasted'\"\n >\n <span class=\"toolbar__component-name\">{{ comp.componentName }}</span>\n <span class=\"toolbar__component-count\">{{ comp.totalRenders }}</span>\n @if (comp.unnecessaryRenders > 0) {\n <span class=\"toolbar__component-wasted\" aria-label=\"wasted renders\">\n {{ comp.unnecessaryRenders }}W\n </span>\n }\n </div>\n }\n </div>\n }\n</div>\n","import {\n EnvironmentProviders,\n makeEnvironmentProviders,\n isDevMode,\n provideEnvironmentInitializer,\n inject,\n ApplicationRef,\n createComponent,\n EnvironmentInjector,\n PLATFORM_ID,\n} from '@angular/core';\nimport { DOCUMENT, isPlatformBrowser } from '@angular/common';\nimport { ScannerService } from './services/scanner/scanner.service';\nimport { OverlayService } from './overlay/overlay.service';\nimport { ToolbarComponent } from './toolbar/toolbar.component';\nimport { ANGULAR_SCAN_OPTIONS } from './tokens';\nimport type { AngularScanOptions } from './models/AngularScanOptions';\n\n/**\n * Provides angular-scan for development-time render tracking.\n *\n * Add to your application providers:\n * ```ts\n * bootstrapApplication(AppComponent, {\n * providers: [provideAngularScan()]\n * });\n * ```\n *\n * This is a complete no-op in production builds (`isDevMode() === false`),\n * so it can safely be left in your app config.\n */\nexport function provideAngularScan(options: AngularScanOptions = {}): EnvironmentProviders {\n // Return empty providers in production — entire library is tree-shaken\n if (!isDevMode()) {\n return makeEnvironmentProviders([]);\n }\n\n const resolvedOptions: AngularScanOptions = {\n enabled: true,\n flashDurationMs: 500,\n showBadges: true,\n showToolbar: true,\n ...options,\n };\n\n return makeEnvironmentProviders([\n { provide: ANGULAR_SCAN_OPTIONS, useValue: resolvedOptions },\n provideEnvironmentInitializer(() => {\n if (!isPlatformBrowser(inject(PLATFORM_ID))) {\n return;\n }\n\n const overlay = inject(OverlayService);\n const scanner = inject(ScannerService);\n const opts = inject(ANGULAR_SCAN_OPTIONS);\n\n overlay.initialize();\n scanner.initialize();\n\n if (opts.showToolbar !== false) {\n mountToolbar(scanner);\n }\n }),\n ]);\n}\n\n/** Create the toolbar outside Angular's component tree and attach it to the DOM. */\nfunction mountToolbar(scanner: ScannerService): void {\n const injector = inject(EnvironmentInjector);\n const doc = inject(DOCUMENT);\n const appRef = inject(ApplicationRef);\n\n // Creating outside the component tree means it won't appear in CD tracking.\n // Attaching to ApplicationRef ensures signals and change detection work.\n const toolbarRef = createComponent(ToolbarComponent, { environmentInjector: injector });\n\n doc.body.appendChild(toolbarRef.location.nativeElement);\n appRef.attachView(toolbarRef.hostView);\n\n // Tell the scanner to exclude the toolbar's own renders\n scanner.setToolbarInstance(toolbarRef.instance);\n}\n","import { isDevMode } from '@angular/core';\nimport type { AngularScanOptions } from './models/AngularScanOptions';\nimport { clearBadges, createOrUpdateBadge } from './overlay/badge';\nimport { createCanvasOverlay } from './overlay/canvas-overlay';\nimport { createTickProfiler } from './utils/create-tick-profiler/create-tick-profiler';\nimport { getNgDebugApi } from './utils/ng-debug/ng-debug';\n\n/**\n * Imperative API for angular-scan.\n *\n * Use this when you cannot modify application providers (e.g. micro-frontends,\n * third-party apps). Call before `bootstrapApplication()`.\n *\n * ```ts\n * // main.ts\n * import { scan } from 'angular-scan';\n * scan();\n * bootstrapApplication(AppComponent, appConfig);\n * ```\n *\n * @returns A teardown function that stops scanning and removes the overlay.\n */\nexport function scan(options: AngularScanOptions = {}): () => void {\n if (!isDevMode()) {\n return () => {};\n }\n if (typeof window === 'undefined') {\n return () => {};\n }\n if (options.enabled === false) {\n return () => {};\n }\n\n const ng = getNgDebugApi();\n if (!ng) {\n console.warn(\n '[angular-scan] Angular debug APIs (window.ng) not available. ' +\n 'Ensure you are running in development mode.',\n );\n return () => {};\n }\n\n const durationMs = options.flashDurationMs ?? 500;\n const showBadges = options.showBadges !== false;\n const overlay = createCanvasOverlay(document, window);\n const renderCounts = new WeakMap<object, number>();\n const badges = new Map<Element, HTMLElement>();\n\n const teardown = createTickProfiler({\n ng,\n body: document.body,\n onUpdates: (updates) => {\n queueMicrotask(() => {\n for (const { instance, hostElement, kind } of updates) {\n const count = (renderCounts.get(instance) ?? 0) + 1;\n renderCounts.set(instance, count);\n overlay.flash(hostElement, kind, durationMs);\n if (showBadges) {\n createOrUpdateBadge(badges, hostElement, count, kind);\n }\n }\n });\n },\n });\n\n return () => {\n teardown();\n overlay.detach();\n clearBadges(badges);\n };\n}\n","/*\n * Public API Surface of angular-scan\n */\n\nexport { provideAngularScan } from './lib/provide-angular-scan';\nexport { scan } from './lib/scan';\nexport type { AngularScanOptions } from './lib/models/AngularScanOptions';\nexport type { ComponentStats } from './lib/models/ComponentStats';\nexport type { RenderKind } from './lib/models/RenderKind';\n","/**\n * Generated bundle index. Do not edit.\n */\n\nexport * from './public-api';\n"],"names":["DOCUMENT","PE"],"mappings":"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"}
|
package/package.json
CHANGED
package/LICENSE
DELETED
|
@@ -1,21 +0,0 @@
|
|
|
1
|
-
MIT License
|
|
2
|
-
|
|
3
|
-
Copyright (c) 2026 Hussein AbdElaziz
|
|
4
|
-
|
|
5
|
-
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
-
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
-
in the Software without restriction, including without limitation the rights
|
|
8
|
-
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
-
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
-
furnished to do so, subject to the following conditions:
|
|
11
|
-
|
|
12
|
-
The above copyright notice and this permission notice shall be included in all
|
|
13
|
-
copies or substantial portions of the Software.
|
|
14
|
-
|
|
15
|
-
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
-
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
-
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
-
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
-
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
-
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
-
SOFTWARE.
|