angular-scan 0.2.3 → 1.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.
@@ -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();
@@ -80,9 +80,15 @@ function getNgDebugApi() {
80
80
  return api;
81
81
  }
82
82
 
83
- const ANGULAR_SCAN_OPTIONS = new InjectionToken('ANGULAR_SCAN_OPTIONS', { providedIn: 'root', factory: () => ({}) });
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', { providedIn: 'root', factory: () => inject(DOCUMENT).defaultView });
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);
@@ -98,6 +104,59 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.4", ngImpor
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
- for (const badge of this.badges.values()) {
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.updateBadge(stats);
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
- updateBadge(stats) {
216
- let badge = this.badges.get(stats.hostElement);
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
274
  static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.4", ngImport: i0, type: OverlayService, deps: [], target: i0.ɵɵFactoryTarget.Injectable });
251
275
  static ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "21.2.4", ngImport: i0, type: OverlayService, providedIn: 'root' });
252
276
  }
253
277
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.4", 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. ' +
@@ -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
- if (typeof window === 'undefined')
572
+ }
573
+ if (typeof window === 'undefined') {
545
574
  return () => { };
546
- if (options.enabled === false)
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
- updateBadge(badges, hostElement, count, kind);
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
- for (const b of badges.values()) {
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
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "angular-scan",
3
- "version": "0.2.3",
3
+ "version": "1.0.0",
4
4
  "description": "Automatically detects and highlights Angular components that are re-rendering — the Angular equivalent of react-scan.",
5
5
  "author": "Hussein AbdElAziz",
6
6
  "license": "MIT",
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.