@ngcompass/common 0.1.1-beta

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,975 @@
1
+ import * as typescript from 'typescript';
2
+ import typescript__default from 'typescript';
3
+ import { Program } from 'oxc-parser';
4
+
5
+ /**
6
+ * Constants used across packages
7
+ */
8
+ declare const TOOL_NAME = "ngcompass";
9
+ declare const PACKAGE_VERSION = "v.0.1.1-beta";
10
+ declare const CACHE_VERSION = "1.0.0";
11
+ declare const CONFIG_FILE_NAMES: readonly [".ngcompassrc.json", ".ngcompassrc.js", ".ngcompass.config.js", "ngcompass.config.json"];
12
+ declare const DEFAULT_CACHE_DIR = "node_modules/.cache/ngcompass";
13
+ declare const DEFAULT_INCLUDE_PATTERNS: readonly ["**/*.ts", "**/*.html"];
14
+ declare const DEFAULT_EXCLUDE_PATTERNS: readonly ["**/node_modules/**", "**/dist/**", "**/build/**", "**/*.spec.ts", "**/*.test.ts"];
15
+ declare const SUPPORTED_ANGULAR_VERSIONS: {
16
+ readonly min: 12;
17
+ readonly max: 21;
18
+ };
19
+
20
+ /**
21
+ * Helper to map string offsets to line/column numbers.
22
+ */
23
+ declare class Locator {
24
+ private readonly lines;
25
+ constructor(content: string);
26
+ location(offset: number): {
27
+ line: number;
28
+ column: number;
29
+ };
30
+ }
31
+
32
+ /**
33
+ * Custom error types
34
+ */
35
+ declare class AnalyzerError extends Error {
36
+ readonly code?: string | undefined;
37
+ constructor(message: string, code?: string | undefined);
38
+ }
39
+ declare class ConfigurationError extends AnalyzerError {
40
+ constructor(message: string);
41
+ }
42
+ declare class ParseError extends AnalyzerError {
43
+ readonly filePath: string;
44
+ constructor(message: string, filePath: string);
45
+ }
46
+ declare class RuleError extends AnalyzerError {
47
+ readonly ruleId: string;
48
+ constructor(message: string, ruleId: string);
49
+ }
50
+ /**
51
+ * Thrown when a rule handler crashes during execution.
52
+ *
53
+ * Unlike ParseError (which is collected and surfaced as a warning),
54
+ * RuleExecutionError indicates a bug in the rule itself and is re-thrown
55
+ * so the caller can decide whether to fail loudly or skip the rule.
56
+ */
57
+ declare class RuleExecutionError extends AnalyzerError {
58
+ readonly ruleName: string;
59
+ readonly filePath: string;
60
+ constructor(ruleName: string, filePath: string, cause: unknown);
61
+ }
62
+ /**
63
+ * Categories of infrastructure failures that can occur during analysis.
64
+ *
65
+ * ParseError — AST parsing failed for a source file
66
+ * IOError — File read / write failed
67
+ * WorkerCrash — A worker thread exited with a non-zero code
68
+ * CacheCorruption — A cached entry could not be deserialized
69
+ * SerializationError — stableSerialize() threw (indicates a rule authoring bug)
70
+ */
71
+ type InfrastructureErrorType = 'ParseError' | 'IOError' | 'WorkerCrash' | 'CacheCorruption' | 'SerializationError' | 'RuleExecutionError';
72
+ /**
73
+ * Structured record of an infrastructure failure.
74
+ *
75
+ * recoverable: true → the pipeline can continue (file is skipped / cold rebuild)
76
+ * recoverable: false → the pipeline cannot produce correct results and should abort
77
+ * and should abort the current run.
78
+ */
79
+ interface InfrastructureError {
80
+ readonly type: InfrastructureErrorType;
81
+ readonly filePath?: string;
82
+ readonly cause: string;
83
+ readonly timestamp: number;
84
+ readonly recoverable: boolean;
85
+ readonly phase: 'config' | 'planner' | 'engine';
86
+ readonly details?: Readonly<Record<string, unknown>>;
87
+ }
88
+ /**
89
+ * Factory that stamps a timestamp and freezes the error object.
90
+ */
91
+ declare function createInfrastructureError(type: InfrastructureErrorType, fields: Omit<InfrastructureError, 'type' | 'timestamp'>): InfrastructureError;
92
+ /**
93
+ * Per-run accumulator of infrastructure errors.
94
+ *
95
+ * Passed through the pipeline so callers can inspect failures at the end
96
+ * after execution completes.
97
+ */
98
+ declare class InfrastructureErrorCollector {
99
+ private readonly _errors;
100
+ record(error: InfrastructureError): void;
101
+ get errors(): ReadonlyArray<InfrastructureError>;
102
+ get hasFatalErrors(): boolean;
103
+ get hasAnyErrors(): boolean;
104
+ /** Returns only errors in a specific phase. */
105
+ forPhase(phase: InfrastructureError['phase']): ReadonlyArray<InfrastructureError>;
106
+ }
107
+
108
+ /**
109
+ * Violation severity levels:
110
+ *
111
+ * error — hard-constraint violations that should block CI / fail the run.
112
+ * warn — advisory violations surfaced as warnings.
113
+ */
114
+ type Severity = 'warn' | 'error';
115
+ /**
116
+ * Rule categories for organization
117
+ */
118
+ declare enum RuleCategory {
119
+ Architecture = "architecture",
120
+ Performance = "performance",
121
+ SSR = "ssr",
122
+ Security = "security",
123
+ Accessibility = "accessibility",
124
+ Testing = "testing",
125
+ CodeSmell = "code-smell",
126
+ Reactivity = "reactivity",
127
+ BestPractice = "best-practice"
128
+ }
129
+ /**
130
+ * Result type for functional error handling
131
+ */
132
+ type Result<T, E = Error> = {
133
+ readonly ok: true;
134
+ readonly data: T;
135
+ } | {
136
+ readonly ok: false;
137
+ readonly error: E;
138
+ };
139
+ /**
140
+ * Creates a successful result
141
+ */
142
+ declare const Ok: <T>(data: T) => Result<T, never>;
143
+ /**
144
+ * Creates a failed result
145
+ */
146
+ declare const Err: <E>(error: E) => Result<never, E>;
147
+ /**
148
+ * Rule severity levels
149
+ */
150
+ type RuleSeverity = Severity | 'off';
151
+ /**
152
+ * Short-hand rule configuration (just severity)
153
+ */
154
+ type RuleConfigShorthand = RuleSeverity;
155
+ /**
156
+ * Full rule configuration (severity + options)
157
+ */
158
+ interface RuleConfigFull {
159
+ readonly severity: RuleSeverity;
160
+ readonly options?: Readonly<Record<string, unknown>>;
161
+ }
162
+ /**
163
+ * Rule configuration (either shorthand or full)
164
+ */
165
+ type RuleConfig = RuleConfigShorthand | RuleConfigFull;
166
+ /**
167
+ * Rules object (ruleName → config)
168
+ */
169
+ type RulesConfig = Readonly<Record<string, RuleConfig>>;
170
+ /**
171
+ * Dependency types for rules
172
+ */
173
+ type RuleDependencyType = 'standalone' | 'component' | 'styles' | 'imports' | 'spec';
174
+ /**
175
+ * AST requirements for a rule
176
+ */
177
+ interface RuleAstRequirements {
178
+ readonly tsAst?: boolean;
179
+ readonly htmlAst?: boolean;
180
+ readonly cssAst?: boolean;
181
+ readonly specAst?: boolean;
182
+ readonly typeChecker?: boolean;
183
+ /**
184
+ * Set to `true` when the rule needs the project-wide import graph,
185
+ * component → template mapping, or other cross-file metadata provided
186
+ * by `ProjectContext`.
187
+ *
188
+ * Rules declaring this are routed to the type-aware execution path (main
189
+ * thread) so they always receive a populated `context.project`.
190
+ * Implies `typeChecker` for routing purposes (the TypeScript Program is
191
+ * required to build the import graph).
192
+ */
193
+ readonly projectContext?: boolean;
194
+ }
195
+ /**
196
+ * File type patterns a rule applies to
197
+ */
198
+ interface RuleFilePatterns {
199
+ readonly include?: ReadonlyArray<string>;
200
+ readonly exclude?: ReadonlyArray<string>;
201
+ }
202
+ /**
203
+ * Rule metadata (describes rule behavior)
204
+ */
205
+ interface RuleMetadata {
206
+ readonly name: string;
207
+ readonly description: string;
208
+ readonly category: string;
209
+ readonly dependencyType: RuleDependencyType;
210
+ readonly requires: RuleAstRequirements;
211
+ readonly filePatterns?: RuleFilePatterns;
212
+ }
213
+ /**
214
+ * Resolved rule (config + metadata)
215
+ */
216
+ interface ResolvedRule {
217
+ readonly name: string;
218
+ readonly severity: RuleSeverity;
219
+ readonly options: Readonly<Record<string, unknown>>;
220
+ readonly metadata: RuleMetadata;
221
+ }
222
+ /**
223
+ * Map of resolved rules
224
+ */
225
+ type ResolvedRulesMap = ReadonlyMap<string, ResolvedRule>;
226
+ /**
227
+ * Preset configuration file structure
228
+ */
229
+ interface PresetConfig {
230
+ readonly name: string;
231
+ readonly description?: string;
232
+ readonly extends?: string | ReadonlyArray<string>;
233
+ readonly rules: RulesConfig;
234
+ }
235
+ /**
236
+ * Built-in preset names
237
+ */
238
+ type BuiltinPreset = 'recommended' | 'strict' | 'performance' | 'reactivity' | 'security' | 'ssr' | 'all';
239
+ /**
240
+ * Preset reference (builtin or file path)
241
+ */
242
+ type PresetReference = string;
243
+ /**
244
+ * Rule resolution result
245
+ */
246
+ interface RuleResolutionResult {
247
+ readonly rules: ResolvedRulesMap;
248
+ readonly metadata: {
249
+ readonly totalRules: number;
250
+ readonly enabledRules: number;
251
+ readonly disabledRules: number;
252
+ readonly presetsLoaded: ReadonlyArray<string>;
253
+ readonly resolutionTime: number;
254
+ };
255
+ }
256
+ /**
257
+ * Rule registry entry (for looking up metadata)
258
+ */
259
+ interface RuleRegistryEntry {
260
+ readonly name: string;
261
+ readonly metadata: RuleMetadata;
262
+ readonly defaultConfig: RuleConfigFull;
263
+ }
264
+ /**
265
+ * Rule registry (ruleName → entry)
266
+ */
267
+ type RuleRegistryMap = ReadonlyMap<string, RuleRegistryEntry>;
268
+ interface RegisterOptions {
269
+ allowOverride?: boolean;
270
+ }
271
+ interface RulePlugin {
272
+ readonly name: string;
273
+ /**
274
+ * The rule handler. Typed as `unknown` here because `@ngcompass/common`
275
+ * cannot import `RuleHandler` from `@ngcompass/engine` (would create a
276
+ * circular dependency). Call sites in `@ngcompass/rules` narrow this to
277
+ * `RuleHandler<unknown>` when registering.
278
+ */
279
+ readonly handler: unknown;
280
+ readonly meta?: Partial<RuleMetadata>;
281
+ readonly manifest?: PluginManifest;
282
+ }
283
+ interface RuleRegistry {
284
+ register(plugin: RulePlugin, opts?: RegisterOptions): void;
285
+ get(name: string): unknown;
286
+ has(name: string): boolean;
287
+ getRuleNames(): ReadonlyArray<string>;
288
+ getAll(): ReadonlyMap<string, unknown>;
289
+ getMeta(name: string): Partial<RuleMetadata> | undefined;
290
+ getMetadata(name: string): RuleMetadata | undefined;
291
+ getRegistryEntry(name: string): RuleRegistryEntry | undefined;
292
+ toReadonlyMap(): ReadonlyMap<string, RuleRegistryEntry>;
293
+ readonly size: number;
294
+ }
295
+ /**
296
+ * A single entry in the rules list output.
297
+ * Consumed by the RulesReporter to render a grouped, filterable rule catalog.
298
+ */
299
+ interface RuleListEntry {
300
+ readonly name: string;
301
+ readonly description: string;
302
+ readonly domain: string;
303
+ readonly severity: string;
304
+ readonly presets: readonly string[];
305
+ }
306
+ interface RuleFailure {
307
+ readonly filePath: string;
308
+ readonly message: string;
309
+ readonly line: number;
310
+ readonly column: number;
311
+ readonly severity: RuleSeverity;
312
+ readonly ruleName: string;
313
+ /**
314
+ * Optional actionable fix recommendation shown in reporter output.
315
+ * Plain English description of how to resolve the violation.
316
+ * Example: "Add standalone: true to @Component({ ... })"
317
+ */
318
+ readonly fix?: string;
319
+ /**
320
+ * Optional multi-line code snippet illustrating the correct pattern.
321
+ * Displayed below the fix recommendation when no auto-fix is available.
322
+ * Use plain TypeScript — no ANSI codes.
323
+ */
324
+ readonly codeExample?: string;
325
+ }
326
+ interface RuleResult {
327
+ readonly ruleName: string;
328
+ readonly failures: ReadonlyArray<RuleFailure>;
329
+ readonly taskId?: string;
330
+ }
331
+ /**
332
+ * Minimal parsed template AST handed to rules via `RuleContext.template`.
333
+ * Mirrors `@ngcompass/ast`'s `HtmlParserResult` without importing it.
334
+ *
335
+ * Rule authors: access `rootNodes` to traverse the Angular HTML tree.
336
+ * Each node is typed `unknown` here; use `@ngcompass/ast`'s node interfaces
337
+ * (e.g. `Element`, `Text`, `BoundAttribute`) for narrowing.
338
+ */
339
+ interface TemplateAst {
340
+ /** Root-level parsed nodes from the Angular HTML parser. */
341
+ readonly rootNodes: ReadonlyArray<unknown>;
342
+ /** Parse errors emitted by the HTML parser (does not throw). */
343
+ readonly errors: ReadonlyArray<unknown>;
344
+ /**
345
+ * Byte offset of the first template character inside the source file.
346
+ * - External `.html` files: always `0`.
347
+ * - Inline templates inside `.ts` files: position after the opening quote.
348
+ * Add this value to node `sourceSpan.start` before calling
349
+ * `context.locator.location()` to obtain correct line/column numbers.
350
+ */
351
+ readonly templateStartOffset: number;
352
+ }
353
+ /**
354
+ * Minimal parsed style AST handed to rules via `RuleContext.style`.
355
+ * Mirrors `@ngcompass/ast`'s `CssResult` without importing it.
356
+ */
357
+ interface StyleAst {
358
+ /** Whether parsing succeeded. */
359
+ readonly ok: boolean;
360
+ /** Transformed CSS bytes — present when `ok` is `true`. */
361
+ readonly code?: Buffer | Uint8Array;
362
+ /** Parse/transform error — present when `ok` is `false`. */
363
+ readonly error?: unknown;
364
+ }
365
+ /**
366
+ * Component file cluster: the TypeScript class file and its associated
367
+ * template, styles, and spec (mirrors ComponentNode in @ngcompass/planner
368
+ * without creating a cross-package dependency).
369
+ */
370
+ interface ComponentFiles {
371
+ /** Absolute path to the `.component.ts` file. */
372
+ readonly tsPath: string;
373
+ /** Absolute path to the external template file, if any. */
374
+ readonly templatePath?: string;
375
+ /** Absolute paths to associated style files. */
376
+ readonly stylePaths: ReadonlyArray<string>;
377
+ /** Absolute path to the spec file, if any. */
378
+ readonly specPath?: string;
379
+ }
380
+ /**
381
+ * Angular module metadata extracted from `@NgModule` or standalone
382
+ * `@Component` decorators. Populated by CTX-004; initially empty.
383
+ */
384
+ interface NgModuleInfo {
385
+ /** Absolute path to the module/component file. */
386
+ readonly filePath: string;
387
+ /** Class names declared in this module (or standalone imports array). */
388
+ readonly declarations: ReadonlySet<string>;
389
+ /** Class names imported by this module/standalone component. */
390
+ readonly imports: ReadonlySet<string>;
391
+ /** Class names exported from this module. */
392
+ readonly exports: ReadonlySet<string>;
393
+ /** Provider class names registered in this module/component. */
394
+ readonly providers: ReadonlySet<string>;
395
+ /** `true` for standalone components; `false` for NgModule-based. */
396
+ readonly isStandalone: boolean;
397
+ }
398
+ /**
399
+ * Project-wide, read-only context shared across all rules in a single run.
400
+ *
401
+ * Computed once by `buildProjectContext()` (@ngcompass/engine) before task
402
+ * dispatch and injected into every `RuleContext` for rules that opt-in via
403
+ * `requires.projectContext: true`.
404
+ *
405
+ * All file paths are absolute and normalised with `path.resolve()`.
406
+ */
407
+ interface ProjectContext {
408
+ /**
409
+ * Forward import graph: absolute file path → set of absolute paths it
410
+ * directly imports (intra-project only; external packages excluded).
411
+ */
412
+ readonly importGraph: ReadonlyMap<string, ReadonlySet<string>>;
413
+ /**
414
+ * Reverse import graph: absolute file path → set of absolute paths that
415
+ * directly import it. Enables "who uses this file?" queries in O(1).
416
+ */
417
+ readonly reverseImportGraph: ReadonlyMap<string, ReadonlySet<string>>;
418
+ /**
419
+ * Angular module / standalone component map. (CTX-004)
420
+ *
421
+ * Key: absolute path to the `@NgModule` or standalone `@Component` file.
422
+ * Value: `NgModuleInfo` with declarations, imports, exports, providers.
423
+ *
424
+ * Populated by scanning all `@NgModule` and `@Component({ standalone: true })`
425
+ * decorators in the project. Empty for files that are neither.
426
+ */
427
+ readonly ngModuleMap: ReadonlyMap<string, NgModuleInfo>;
428
+ /**
429
+ * Set of absolute file paths for all standalone Angular entities. (CTX-004)
430
+ *
431
+ * Includes files that contain `@Component({ standalone: true })`,
432
+ * `@Directive({ standalone: true })`, or `@Pipe({ standalone: true })`.
433
+ *
434
+ * Rules can use this to detect module-based components subject to a
435
+ * standalone-first migration policy, or to validate that standalone
436
+ * components only reference dependencies in their own `imports` array.
437
+ */
438
+ readonly standaloneComponents: ReadonlySet<string>;
439
+ /**
440
+ * Class name → absolute file path resolver. (CTX-004)
441
+ *
442
+ * Maps the name of every exported class in the project to the absolute
443
+ * path of the file that declares it. Enables NgModule rules to resolve
444
+ * the class names stored in `NgModuleInfo.declarations` / `imports` /
445
+ * `exports` / `providers` to concrete file paths without a linear scan.
446
+ *
447
+ * Only directly-exported class declarations are indexed (`export class Foo`);
448
+ * re-exports through barrel files are not followed.
449
+ *
450
+ * Example:
451
+ * `project.classToFile.get('FooComponent')` → `'/src/app/foo/foo.component.ts'`
452
+ */
453
+ readonly classToFile: ReadonlyMap<string, string>;
454
+ /**
455
+ * Component file cluster map.
456
+ * Key: absolute path to the `.component.ts` file.
457
+ * Value: associated template, styles, and spec paths.
458
+ */
459
+ readonly componentGraph: ReadonlyMap<string, ComponentFiles>;
460
+ /**
461
+ * Full set of absolute file paths discovered by the scanner for this run.
462
+ */
463
+ readonly projectFiles: ReadonlySet<string>;
464
+ /** Root directory of the project (absolute, normalised). */
465
+ readonly rootDir: string;
466
+ /**
467
+ * Set of barrel file absolute paths.
468
+ *
469
+ * A barrel file is one whose every top-level statement is an
470
+ * `export … from '…'` re-export declaration (no regular imports,
471
+ * no class/function/variable declarations). The canonical example is
472
+ * an `index.ts` or `public-api.ts` that re-exports sibling modules.
473
+ *
474
+ * Rules can use this to skip barrel files (no logic to lint) or to
475
+ * follow re-export chains when tracing where a symbol is consumed.
476
+ */
477
+ readonly barrelFiles: ReadonlySet<string>;
478
+ /**
479
+ * External dependency map (CTX-002).
480
+ *
481
+ * Key: absolute path of the project source file.
482
+ * Value: set of npm package names (scope-aware bare specifiers, e.g.
483
+ * `'@angular/core'`, `'rxjs'`) imported by that file.
484
+ *
485
+ * Sub-path specifiers are normalised to the package name:
486
+ * `'rxjs/operators'` → `'rxjs'`
487
+ * `'@angular/core/rxjs-interop'` → `'@angular/core'`
488
+ *
489
+ * Relative imports and absolute paths are excluded.
490
+ * Entries are only present for files that have at least one external dep —
491
+ * files with no external deps simply have no entry in the map.
492
+ */
493
+ readonly externalDeps: ReadonlyMap<string, ReadonlySet<string>>;
494
+ /**
495
+ * Reverse map: absolute template file path → absolute component `.ts` path.
496
+ *
497
+ * Enables template rules to answer "which component owns this template?"
498
+ * in O(1) without scanning the whole `componentGraph`.
499
+ *
500
+ * Built automatically from `componentGraph` by `buildProjectContext()`.
501
+ * Only files that have an explicit external template appear here; inline
502
+ * templates are associated via `componentGraph` keyed on the `.ts` path.
503
+ */
504
+ readonly templateToComponent: ReadonlyMap<string, string>;
505
+ }
506
+ /**
507
+ * Cross-reference between an Angular component and its associated files.
508
+ *
509
+ * Attached to `RuleContext.crossRef` for rules running on:
510
+ * - `.component.ts` files — gives access to `templatePath`, `stylePaths`,
511
+ * `specPath`, and `templateReferences` (members used in the template).
512
+ * - `.component.html` template files — gives access to `componentPath`
513
+ * and `publicMembers` (members declared on the component class).
514
+ *
515
+ * `undefined` for all other file types and when `project` is unavailable.
516
+ */
517
+ interface ComponentCrossRef {
518
+ /** Absolute path to the `.component.ts` class file. */
519
+ readonly componentPath: string;
520
+ /**
521
+ * Absolute path to the external template `.html` file.
522
+ * `undefined` when the component uses an inline `template: '…'` string.
523
+ */
524
+ readonly templatePath?: string;
525
+ /** Absolute paths to associated style files (`.scss`, `.css`, …). */
526
+ readonly stylePaths: ReadonlyArray<string>;
527
+ /** Absolute path to the spec file, if any. */
528
+ readonly specPath?: string;
529
+ /**
530
+ * Names of public members (properties and methods) declared directly in
531
+ * the component class, extracted from the TypeScript `SourceFile`.
532
+ *
533
+ * Available in **template rules** to verify that every bound property /
534
+ * called method actually exists in the component class.
535
+ *
536
+ * Populated only when the type-aware execution path is active
537
+ * (`ts.Program` exists). Private, protected, and `#private` members are
538
+ * excluded.
539
+ */
540
+ readonly publicMembers?: ReadonlySet<string>;
541
+ /**
542
+ * Public class fields that are known Angular signal-like values.
543
+ *
544
+ * These are safe to invoke from templates as `name()` because the call reads
545
+ * signal state rather than executing arbitrary component work.
546
+ */
547
+ readonly signalMembers?: ReadonlySet<string>;
548
+ /**
549
+ * Identifiers from the template that reference the component — property
550
+ * reads, method calls, and event-handler expressions whose implicit
551
+ * receiver is the component instance (`this`).
552
+ *
553
+ * Available in **component rules** to detect unused public members (a
554
+ * member not in this set is likely unreferenced in the template).
555
+ *
556
+ * Populated when the template AST is already loaded for the current
557
+ * analysis batch (i.e. the rule or a peer rule declared `htmlAst: true`).
558
+ */
559
+ readonly templateReferences?: ReadonlySet<string>;
560
+ }
561
+ interface RuleContext {
562
+ /**
563
+ * Lazily-created TypeScript `SourceFile` for this file.
564
+ *
565
+ * Populated on first access by `rule-utils.ts`:`getTsSymbolAtNode()` when a rule
566
+ * requests TypeChecker-based symbol resolution. Creating a `SourceFile` is O(n)
567
+ * in source length; caching it here ensures the cost is paid at most once per
568
+ * file, regardless of how many rules request type information.
569
+ *
570
+ * Rule authors: **do not read or write this field directly.** Use
571
+ * `getTsSymbolAtNode(node, context)` from `rule-utils` instead.
572
+ */
573
+ readonly sourceFile?: typescript.SourceFile;
574
+ readonly filePath: string;
575
+ readonly fileContent: string;
576
+ readonly locator: Locator;
577
+ readonly program?: Program;
578
+ readonly typeChecker?: typescript.TypeChecker;
579
+ /**
580
+ * Parsed template AST — use `rootNodes` to traverse the Angular HTML tree.
581
+ * Typed as `TemplateAst` (defined above) to avoid a circular dep on `@ngcompass/ast`.
582
+ */
583
+ readonly template?: TemplateAst;
584
+ /**
585
+ * External template file details used while dispatching template rules.
586
+ *
587
+ * Present only when a component rule batch loaded a separate `.html`
588
+ * template. Template rule execution may use these values so findings point
589
+ * at the HTML file instead of the owning `.component.ts` file.
590
+ */
591
+ readonly templateFilePath?: string;
592
+ readonly templateFileContent?: string;
593
+ readonly templateLocator?: Locator;
594
+ /**
595
+ * Parsed style AST — check `ok` before accessing `code`.
596
+ * Typed as `StyleAst` (defined above) to avoid a circular dep on `@ngcompass/ast`.
597
+ */
598
+ readonly style?: StyleAst;
599
+ readonly options?: Readonly<Record<string, unknown>>;
600
+ /**
601
+ * Project-wide cross-file metadata (import graph, component clusters, …).
602
+ *
603
+ * Populated only for rules that declare `requires.projectContext: true`.
604
+ * `undefined` for all other rules — access is always guarded by an opt-in
605
+ * flag so there is zero overhead on rules that don't need it.
606
+ */
607
+ readonly project?: ProjectContext;
608
+ /**
609
+ * Component ↔ template cross-reference (CTX-003).
610
+ *
611
+ * Non-`undefined` when `project` is available **and** the file under
612
+ * analysis is either a `.component.ts` file or its associated template.
613
+ * Provides structural links (paths) and optional semantic sets
614
+ * (`publicMembers`, `templateReferences`) at zero extra parse cost for
615
+ * files that don't match either category.
616
+ */
617
+ readonly crossRef?: ComponentCrossRef;
618
+ }
619
+ /**
620
+ * Analysis aggregate output.
621
+ */
622
+ interface AnalysisResult {
623
+ readonly results: ReadonlyArray<RuleResult>;
624
+ /**
625
+ * Parse errors encountered during analysis (collected, not thrown).
626
+ * Allows analysis to continue for other files while surfacing tool errors
627
+ * separately from rule violations in the reporter output.
628
+ */
629
+ readonly parseErrors: ReadonlyArray<ParseError>;
630
+ readonly stats: {
631
+ readonly totalFiles: number;
632
+ readonly totalErrors: number;
633
+ readonly totalWarnings: number;
634
+ readonly duration: number;
635
+ /**
636
+ * Fraction of tasks whose results were served from cache (0–1).
637
+ * `undefined` when no cache is in use (e.g. first cold run or worker path).
638
+ * Consumers can display this as a percentage: `(cacheHitRate * 100).toFixed(1)%`.
639
+ */
640
+ readonly cacheHitRate?: number;
641
+ };
642
+ }
643
+ /** Describes a task that failed inside a worker thread. */
644
+ interface WorkerTaskError {
645
+ readonly task: {
646
+ readonly taskId: string;
647
+ };
648
+ readonly error: string;
649
+ }
650
+ /** File-level progress event emitted by a worker thread. */
651
+ interface WorkerFileProgress {
652
+ readonly kind: 'file-progress';
653
+ readonly filePath: string;
654
+ readonly taskCount: number;
655
+ readonly issueCount: number;
656
+ readonly errorCount: number;
657
+ readonly warningCount: number;
658
+ readonly duration: number;
659
+ }
660
+ /** Message posted back from a worker thread to the orchestrator. */
661
+ interface WorkerMessageResult {
662
+ readonly results: RuleResult[];
663
+ readonly errors: WorkerTaskError[];
664
+ }
665
+
666
+ /**
667
+ * Optional manifest that a plugin can export alongside its rules.
668
+ *
669
+ * When present the engine validates:
670
+ * - That the current tool version satisfies engineVersionRange
671
+ * - That required capabilities (typeInfo, templateAST) are available
672
+ *
673
+ * Plugins without a manifest are loaded with a deprecation warning.
674
+ * Enforcement (hard error on missing manifest) is reserved for the next major.
675
+ */
676
+ interface PluginManifest {
677
+ /** Package name (must match the plugin's npm package name) */
678
+ readonly name: string;
679
+ /** Plugin semver version (e.g. "2.1.0") */
680
+ readonly version: string;
681
+ /** Engine API semver version this plugin was built against */
682
+ readonly apiVersion: string;
683
+ /**
684
+ * Semver range of ngcompass versions this plugin is compatible with.
685
+ * Examples: ">=1.0.0 <2.0.0", "^1.2.0", "*"
686
+ */
687
+ readonly engineVersionRange: string;
688
+ /** Optional capability declarations */
689
+ readonly capabilities?: {
690
+ /** Plugin uses the TypeScript type-checker (expensive) */
691
+ readonly requiresTypeInfo?: boolean;
692
+ /** Plugin needs the full HTML template AST */
693
+ readonly requiresTemplateAST?: boolean;
694
+ /** Plugin needs the CSS/SCSS AST */
695
+ readonly requiresCssAST?: boolean;
696
+ };
697
+ }
698
+ /** Minimal telemetry event shape used in config (avoids circular dep with core) */
699
+ interface TelemetryEventBase {
700
+ readonly phase: 'config' | 'planner' | 'engine';
701
+ readonly operation: string;
702
+ readonly durationMs: number;
703
+ readonly cacheHit?: boolean;
704
+ readonly workerId?: number;
705
+ readonly metadata?: Readonly<Record<string, string | number | boolean>>;
706
+ }
707
+ interface TelemetryConfig {
708
+ /** Whether telemetry collection is active (default: false) */
709
+ enabled?: boolean;
710
+ /**
711
+ * Called synchronously for every emitted event.
712
+ * Use this to pipe events to a file, stdout, or an external collector.
713
+ */
714
+ onEvent?: (event: TelemetryEventBase) => void;
715
+ }
716
+ /**
717
+ * Reporting output formats
718
+ */
719
+ type OutputFormat = 'json' | 'text' | 'sarif' | 'html';
720
+ /**
721
+ * Severity level that triggers failure in CI/build
722
+ */
723
+ type FailSeverity = Severity;
724
+ /**
725
+ * TypeScript parser options
726
+ */
727
+ interface ParserOptions {
728
+ project?: string;
729
+ tsconfigRootDir?: string;
730
+ sourceType?: 'module' | 'commonjs';
731
+ ecmaVersion?: number;
732
+ }
733
+ /**
734
+ * Cache configuration options
735
+ */
736
+ interface CacheOptions {
737
+ enabled?: boolean;
738
+ location?: string;
739
+ strategy?: 'memory' | 'local';
740
+ ttl?: number;
741
+ }
742
+ /**
743
+ * Configuration override for specific files
744
+ * Rules in overrides are merged with global rules
745
+ */
746
+ interface ConfigOverride {
747
+ files: string | string[];
748
+ rules?: Record<string, RuleConfig | Severity | 'off'>;
749
+ }
750
+ /**
751
+ * Profile-specific configuration (dev/ci)
752
+ * Profiles can override most settings except nested profiles
753
+ */
754
+ type ProfileConfig = Partial<Omit<AnalyzerConfig, 'profiles'>>;
755
+ /**
756
+ * Main analyzer configuration interface
757
+ * Supports extends, rules, overrides, profiles, and more
758
+ */
759
+ interface AnalyzerConfig {
760
+ /**
761
+ * Extend from other configuration presets
762
+ */
763
+ extends?: string | string[];
764
+ /**
765
+ * Files to include in analysis
766
+ */
767
+ include?: string[];
768
+ /**
769
+ * Files to exclude from analysis
770
+ */
771
+ exclude?: string[];
772
+ /**
773
+ * Maximum number of worker threads for parallel analysis
774
+ */
775
+ maxWorkers?: number;
776
+ /**
777
+ * Cache configuration
778
+ */
779
+ cache?: boolean | CacheOptions;
780
+ /**
781
+ * Output format for reports
782
+ */
783
+ outputFormat?: OutputFormat;
784
+ /**
785
+ * Output file path for report
786
+ */
787
+ outputPath?: string;
788
+ /**
789
+ * Severity level that causes non-zero exit code
790
+ */
791
+ failOnSeverity?: FailSeverity;
792
+ /**
793
+ * Maximum number of violations allowed before failing
794
+ */
795
+ maxWarnings?: number;
796
+ /**
797
+ * Additional patterns to ignore
798
+ */
799
+ ignorePatterns?: string[];
800
+ /**
801
+ * External rule plugins to load.
802
+ * Each entry is a package name or file path that exports a RulePlugin or RulePlugin[].
803
+ * Example: ['@my-org/ngcompass-rules', './tools/local-rules']
804
+ */
805
+ plugins?: string[];
806
+ /**
807
+ * Rule configuration
808
+ */
809
+ rules?: Record<string, RuleConfig | Severity | 'off'>;
810
+ /**
811
+ * Per-file rule overrides
812
+ */
813
+ overrides?: ConfigOverride[];
814
+ /**
815
+ * TypeScript parser configuration
816
+ */
817
+ parserOptions?: ParserOptions;
818
+ /**
819
+ * Environment-specific profiles
820
+ */
821
+ profiles?: Record<string, ProfileConfig>;
822
+ /**
823
+ * Structured telemetry collection.
824
+ * Disabled by default — enabling it adds a small per-event overhead.
825
+ */
826
+ telemetry?: TelemetryConfig;
827
+ /**
828
+ * Engine execution thresholds.
829
+ * Override the built-in defaults for parallelism decisions.
830
+ */
831
+ engine?: {
832
+ /**
833
+ * Number of tasks above which the worker pool is used instead of
834
+ * local pLimit execution. Default: 150.
835
+ */
836
+ parallelThreshold?: number;
837
+ };
838
+ }
839
+ /**
840
+ * Structured configuration issue
841
+ */
842
+ interface ConfigIssue {
843
+ readonly code: string;
844
+ readonly message: string;
845
+ readonly path?: ReadonlyArray<string | number>;
846
+ readonly severity: 'error' | 'warning';
847
+ readonly file?: string;
848
+ readonly line?: number;
849
+ readonly column?: number;
850
+ readonly suggestion?: string;
851
+ }
852
+ /**
853
+ * Health report for configuration validation
854
+ */
855
+ interface HealthReport {
856
+ valid: boolean;
857
+ issues: ConfigIssue[];
858
+ config?: unknown;
859
+ }
860
+ /**
861
+ * Configuration Report (alias for HealthReport)
862
+ */
863
+ type ConfigReport = HealthReport;
864
+ /**
865
+ * Result of the configuration initialization
866
+ */
867
+ interface InitResult {
868
+ success: boolean;
869
+ filePath: string;
870
+ alreadyExists?: boolean;
871
+ }
872
+ interface NormalizedAnalyzerConfig extends Omit<AnalyzerConfig, 'cache' | 'maxWorkers' | 'outputFormat' | 'failOnSeverity' | 'maxWarnings' | 'rules'> {
873
+ /**
874
+ * Cache configuration.
875
+ * Guaranteed to be a full object, never boolean.
876
+ */
877
+ cache: Required<CacheOptions>;
878
+ /**
879
+ * Maximum number of worker threads.
880
+ * Defaults to (CPUs - 1) or 1.
881
+ */
882
+ maxWorkers: number;
883
+ /**
884
+ * Reporting format.
885
+ */
886
+ outputFormat: OutputFormat;
887
+ /**
888
+ * Severity level for non-zero exit code.
889
+ */
890
+ failOnSeverity: FailSeverity;
891
+ /**
892
+ * Max allowed warnings.
893
+ */
894
+ maxWarnings: number;
895
+ /**
896
+ * Resolved rule configuration.
897
+ */
898
+ rules: Record<string, RuleConfig | Severity | 'off'>;
899
+ }
900
+ interface ConfigValidationResult {
901
+ config?: NormalizedAnalyzerConfig;
902
+ report: HealthReport;
903
+ }
904
+
905
+ interface Location {
906
+ line: number;
907
+ column: number;
908
+ }
909
+ type LocationMap = Record<string, Location>;
910
+ declare class ASTUtils {
911
+ /**
912
+ * Parses content into a TypeScript SourceFile.
913
+ */
914
+ static parse(content: string, fileName?: string): typescript__default.SourceFile;
915
+ /**
916
+ * Generates a map of all property locations in the object.
917
+ * Keys are dot-notation paths (e.g. "rules.my-rule").
918
+ */
919
+ static generateLocationMap(sourceFile: typescript__default.SourceFile): LocationMap;
920
+ private static getPropertyName;
921
+ }
922
+
923
+ /**
924
+ * Global Logger Module
925
+ *
926
+ * Provides debug and performance logging capabilities with namespace filtering.
927
+ * Follows industry standards (ESLint, TypeScript debug patterns).
928
+ */
929
+ type LogLevel = 'debug' | 'info' | 'warn' | 'error';
930
+ type Namespace = 'discovery' | 'loader' | 'validator' | 'cache' | 'scanner' | 'parser' | 'rules' | 'workers' | 'reporter' | 'init' | 'config' | 'planner' | 'incremental' | 'dry-run' | 'engine' | 'plugin-loader' | 'env-fingerprint';
931
+ declare const debug: (namespace: Namespace, message: string, ...args: unknown[]) => void;
932
+ declare const info: (namespace: Namespace, message: string, ...args: unknown[]) => void;
933
+ declare const warn: (namespace: Namespace, message: string, ...args: unknown[]) => void;
934
+ declare const error: (namespace: Namespace, message: string, ...args: unknown[]) => void;
935
+ declare const time: (label: string) => void;
936
+ declare const timeEnd: (label: string) => number;
937
+ declare const timeLog: (label: string, namespace: Namespace, message?: string) => number;
938
+ declare const enableDebug: (level?: LogLevel, namespaces?: Namespace[] | "all") => void;
939
+ declare const disableDebug: () => void;
940
+ declare const isDebugEnabled: () => boolean;
941
+
942
+ /**
943
+ * Stable Serialization Utility
944
+ *
945
+ * Produces a deterministic JSON string suitable for use in cache keys and hashes.
946
+ *
947
+ * Guarantees:
948
+ * - Objects: keys sorted alphabetically at every depth level
949
+ * - Arrays: elements preserved in insertion order (NOT sorted)
950
+ * - undefined values in objects: omitted (same as JSON.stringify)
951
+ * - Date: serialized as ISO 8601 string
952
+ * - RegExp: serialized as its string representation (e.g. "/abc/gi")
953
+ * - Circular references: throws SerializationError (never silently sanitizes)
954
+ * - Functions: throws SerializationError
955
+ * - NaN / Infinity: throws SerializationError
956
+ *
957
+ * This replaces bare JSON.stringify() wherever the insertion order of object
958
+ * keys must not affect the resulting string (e.g. batch keys, cache keys).
959
+ */
960
+ declare class SerializationError extends Error {
961
+ readonly path: string[];
962
+ constructor(message: string, path: string[]);
963
+ }
964
+ /**
965
+ * Produces a deterministic JSON string by sorting object keys recursively.
966
+ *
967
+ * @param value - The value to serialize
968
+ * @param _path - Internal: tracks key path for error messages
969
+ * @param _seen - Internal: tracks visited objects for circular detection
970
+ * @returns A stable, deterministic JSON string
971
+ * @throws {SerializationError} on circular references, functions, or non-finite numbers
972
+ */
973
+ declare function stableSerialize(value: unknown, _path?: string[], _seen?: WeakSet<object>): string;
974
+
975
+ export { ASTUtils, type AnalysisResult, type AnalyzerConfig, AnalyzerError, type BuiltinPreset, CACHE_VERSION, CONFIG_FILE_NAMES, type CacheOptions, type ComponentCrossRef, type ComponentFiles, type ConfigIssue, type ConfigOverride, type ConfigReport, type ConfigValidationResult, ConfigurationError, DEFAULT_CACHE_DIR, DEFAULT_EXCLUDE_PATTERNS, DEFAULT_INCLUDE_PATTERNS, Err, type FailSeverity, type HealthReport, type InfrastructureError, InfrastructureErrorCollector, type InfrastructureErrorType, type InitResult, type Location, type LocationMap, Locator, type LogLevel, type Namespace, type NgModuleInfo, type NormalizedAnalyzerConfig, Ok, type OutputFormat, PACKAGE_VERSION, ParseError, type ParserOptions, type PluginManifest, type PresetConfig, type PresetReference, type ProjectContext, type RegisterOptions, type ResolvedRule, type ResolvedRulesMap, type Result, type RuleAstRequirements, RuleCategory, type RuleConfig, type RuleConfigFull, type RuleConfigShorthand, type RuleContext, type RuleDependencyType, RuleError, RuleExecutionError, type RuleFailure, type RuleFilePatterns, type RuleListEntry, type RuleMetadata, type RulePlugin, type RuleRegistry, type RuleRegistryEntry, type RuleRegistryMap, type RuleResolutionResult, type RuleResult, type RuleSeverity, type RulesConfig, SUPPORTED_ANGULAR_VERSIONS, SerializationError, type Severity, type StyleAst, TOOL_NAME, type TelemetryConfig, type TelemetryEventBase, type TemplateAst, type WorkerFileProgress, type WorkerMessageResult, type WorkerTaskError, createInfrastructureError, debug, disableDebug, enableDebug, error, info, isDebugEnabled, stableSerialize, time, timeEnd, timeLog, warn };