@ngcompass/planner 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.
- package/LICENSE +21 -0
- package/dist/index.cjs +3 -0
- package/dist/index.cjs.map +1 -0
- package/dist/index.d.cts +826 -0
- package/dist/index.d.ts +826 -0
- package/dist/index.js +3 -0
- package/dist/index.js.map +1 -0
- package/package.json +55 -0
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1,826 @@
|
|
|
1
|
+
import { CacheContext, CacheKeyContext, ResultCache } from '@ngcompass/cache';
|
|
2
|
+
import { RuleSeverity, ResolvedRule, ConfigOverride, AnalysisResult, Result } from '@ngcompass/common';
|
|
3
|
+
export { Err, Ok, Result } from '@ngcompass/common';
|
|
4
|
+
|
|
5
|
+
/**
|
|
6
|
+
* Execution Plan Types
|
|
7
|
+
*
|
|
8
|
+
* Maps discovered files + resolved rules → executable tasks with indexes.
|
|
9
|
+
*/
|
|
10
|
+
|
|
11
|
+
/**
|
|
12
|
+
* Complete execution plan output (plan + tasks + indexes)
|
|
13
|
+
*
|
|
14
|
+
* - tasks: Flat array of all tasks (task-centric, content-addressed)
|
|
15
|
+
* - plan: File-grouped view (file-centric, backward compatible)
|
|
16
|
+
* - indexes: Pre-computed indexes for both file and task queries
|
|
17
|
+
*/
|
|
18
|
+
interface ExecutionPlanOutput {
|
|
19
|
+
/** All tasks to execute (primary execution structure) */
|
|
20
|
+
readonly tasks: ReadonlyArray<Task>;
|
|
21
|
+
/** File-grouped view (backward compatible, derived from tasks) */
|
|
22
|
+
readonly plan: ExecutionPlan;
|
|
23
|
+
/** Pre-computed indexes for efficient queries */
|
|
24
|
+
readonly indexes: ExecutionIndexes;
|
|
25
|
+
/** Tasks that were skipped */
|
|
26
|
+
readonly skippedTasks: ReadonlyArray<Task>;
|
|
27
|
+
/** Pre-loaded cached results (taskId → result) */
|
|
28
|
+
readonly cachedResults?: ReadonlyMap<string, unknown>;
|
|
29
|
+
/** Global content hash for the entire plan */
|
|
30
|
+
readonly globalHash?: string;
|
|
31
|
+
/** Pre-computed analysis result (if fully cached) */
|
|
32
|
+
readonly precomputedAnalysis?: AnalysisResult;
|
|
33
|
+
/**
|
|
34
|
+
* Files whose tasks were not found in the result cache and will be
|
|
35
|
+
* re-analysed. Populated when `options.cache` is provided and incremental
|
|
36
|
+
* filtering has run. `undefined` when caching is disabled.
|
|
37
|
+
*/
|
|
38
|
+
readonly changedFiles?: ReadonlyArray<string>;
|
|
39
|
+
/**
|
|
40
|
+
* Files whose tasks were found in the result cache and skipped.
|
|
41
|
+
* Populated when `options.cache` is provided and incremental
|
|
42
|
+
* filtering has run. `undefined` when caching is disabled.
|
|
43
|
+
*/
|
|
44
|
+
readonly cachedFiles?: ReadonlyArray<string>;
|
|
45
|
+
}
|
|
46
|
+
/**
|
|
47
|
+
* Execution plan - one entry per discovered file
|
|
48
|
+
*/
|
|
49
|
+
type ExecutionPlan = Readonly<Record<string, FileAnalysisUnit>>;
|
|
50
|
+
/**
|
|
51
|
+
* A single file that needs to be analyzed
|
|
52
|
+
*/
|
|
53
|
+
interface FileAnalysisUnit {
|
|
54
|
+
/** The primary file being analyzed */
|
|
55
|
+
readonly file: FileInfo;
|
|
56
|
+
/** All the tasks/rules that will run on this file */
|
|
57
|
+
readonly tasks: ReadonlyArray<RuleTask>;
|
|
58
|
+
}
|
|
59
|
+
/**
|
|
60
|
+
* Information about the file being analyzed
|
|
61
|
+
*/
|
|
62
|
+
interface FileInfo {
|
|
63
|
+
/** File path (absolute) */
|
|
64
|
+
readonly path: string;
|
|
65
|
+
/** File type (component, service, etc) */
|
|
66
|
+
readonly type: FileType;
|
|
67
|
+
/** Content hash for cache invalidation */
|
|
68
|
+
readonly hash: string;
|
|
69
|
+
}
|
|
70
|
+
/**
|
|
71
|
+
* File type classification.
|
|
72
|
+
*
|
|
73
|
+
* `'unknown'` is used for files that do not match any recognised Angular or
|
|
74
|
+
* TypeScript pattern (e.g. stray JSON, Markdown, or binary files that
|
|
75
|
+
* somehow enter the file list). Rules are never applied to `'unknown'` files.
|
|
76
|
+
*/
|
|
77
|
+
type FileType = 'component' | 'directive' | 'pipe' | 'service' | 'module' | 'guard' | 'logic' | 'angular-class' | 'spec' | 'template' | 'style' | 'config' | 'unknown';
|
|
78
|
+
/**
|
|
79
|
+
* A single rule execution task
|
|
80
|
+
*/
|
|
81
|
+
interface RuleTask {
|
|
82
|
+
/** Which rule to run */
|
|
83
|
+
readonly ruleName: string;
|
|
84
|
+
/** Rule severity level */
|
|
85
|
+
readonly severity: RuleSeverity;
|
|
86
|
+
/** Rule options (configuration from resolved rules) */
|
|
87
|
+
readonly options: Readonly<Record<string, unknown>>;
|
|
88
|
+
/** Cache key for this specific task */
|
|
89
|
+
readonly cacheKey: string;
|
|
90
|
+
/** What files this task needs to read and analyze */
|
|
91
|
+
readonly inputs: TaskInputs;
|
|
92
|
+
/**
|
|
93
|
+
* Whether this task requires the TypeScript type-checker (expensive!).
|
|
94
|
+
* When true the file is included in `indexes.filesNeedingTypeChecker` so
|
|
95
|
+
* the engine can set up a full TypeScript Program for that file.
|
|
96
|
+
*/
|
|
97
|
+
readonly needsTypeChecker?: boolean;
|
|
98
|
+
/**
|
|
99
|
+
* Whether this task requires a pre-computed `ProjectContext` (CTX-001).
|
|
100
|
+
* Routed to the type-aware execution path alongside `needsTypeChecker`.
|
|
101
|
+
*/
|
|
102
|
+
readonly needsProjectContext?: boolean;
|
|
103
|
+
}
|
|
104
|
+
/**
|
|
105
|
+
* All the files this task needs to read
|
|
106
|
+
*/
|
|
107
|
+
interface TaskInputs {
|
|
108
|
+
/** TypeScript file input (always present) */
|
|
109
|
+
typescript: FileInput;
|
|
110
|
+
/** Template file input (if needed) */
|
|
111
|
+
template?: FileInput;
|
|
112
|
+
/** Style files input (if needed) */
|
|
113
|
+
styles?: ReadonlyArray<FileInput>;
|
|
114
|
+
/** Spec file input (if needed) */
|
|
115
|
+
spec?: FileInput;
|
|
116
|
+
}
|
|
117
|
+
/**
|
|
118
|
+
* A single file input for a task
|
|
119
|
+
*/
|
|
120
|
+
interface FileInput {
|
|
121
|
+
/** Path to the file (absolute) */
|
|
122
|
+
readonly path: string;
|
|
123
|
+
/** Content hash of this file (SHA-256) */
|
|
124
|
+
readonly hash: string;
|
|
125
|
+
/** Does this task need to parse this file into AST? */
|
|
126
|
+
readonly needsAst: boolean;
|
|
127
|
+
}
|
|
128
|
+
/**
|
|
129
|
+
* Resource type enum
|
|
130
|
+
*/
|
|
131
|
+
type ResourceType = 'typescript' | 'template' | 'styles' | 'spec';
|
|
132
|
+
/**
|
|
133
|
+
* A single executable task (task-centric architecture)
|
|
134
|
+
*
|
|
135
|
+
* Task is the fundamental unit of execution with content-based identity.
|
|
136
|
+
* Unlike RuleTask (file-centric), Task uses content-addressable cache keys
|
|
137
|
+
* that survive file renames and enable precise cache invalidation.
|
|
138
|
+
*
|
|
139
|
+
* Key differences from RuleTask:
|
|
140
|
+
* - taskId: Content-based (SHA-256 of all inputs + options)
|
|
141
|
+
* - filePath: Explicit (not embedded in cache key)
|
|
142
|
+
* - inputs: Include content hashes for each file
|
|
143
|
+
*/
|
|
144
|
+
interface Task {
|
|
145
|
+
/**
|
|
146
|
+
* Content-based task identifier (primary cache key)
|
|
147
|
+
*
|
|
148
|
+
* Format: SHA256(ruleName + typescript.hash + template?.hash + styles?.hashes + spec?.hash + options)
|
|
149
|
+
*
|
|
150
|
+
* This enables:
|
|
151
|
+
* - Cache hits even after file renames (content unchanged)
|
|
152
|
+
* - Precise invalidation (only affected tasks)
|
|
153
|
+
* - Cross-project cache sharing (same content = same ID)
|
|
154
|
+
*/
|
|
155
|
+
readonly taskId: string;
|
|
156
|
+
/** Which rule to execute */
|
|
157
|
+
readonly ruleName: string;
|
|
158
|
+
/** Which file is being analyzed */
|
|
159
|
+
readonly filePath: string;
|
|
160
|
+
/** Rule severity level */
|
|
161
|
+
readonly severity: RuleSeverity;
|
|
162
|
+
/** Rule options (configuration) */
|
|
163
|
+
readonly options: Readonly<Record<string, unknown>>;
|
|
164
|
+
/** Input files with content hashes */
|
|
165
|
+
readonly inputs: TaskInputs;
|
|
166
|
+
/**
|
|
167
|
+
* Whether this task requires the TypeScript type-checker (expensive!).
|
|
168
|
+
* Mirrors `RuleTask.needsTypeChecker` on the task-centric view.
|
|
169
|
+
*/
|
|
170
|
+
readonly needsTypeChecker?: boolean;
|
|
171
|
+
/**
|
|
172
|
+
* Whether this task requires a pre-computed `ProjectContext` (CTX-001).
|
|
173
|
+
*
|
|
174
|
+
* When `true` the task is routed to the type-aware execution path on the
|
|
175
|
+
* main thread (same as `needsTypeChecker`) because `ProjectContext` is
|
|
176
|
+
* built from the TypeScript `Program` created there.
|
|
177
|
+
* Rules receive the context via `RuleContext.project`.
|
|
178
|
+
*/
|
|
179
|
+
readonly needsProjectContext?: boolean;
|
|
180
|
+
}
|
|
181
|
+
/**
|
|
182
|
+
* Pre-computed indexes for efficient engine queries
|
|
183
|
+
*
|
|
184
|
+
* - File-level indexes: For parsing optimization (parse once, reuse)
|
|
185
|
+
* - Task-level indexes: For execution strategies (by rule, by severity, etc)
|
|
186
|
+
*/
|
|
187
|
+
interface ExecutionIndexes {
|
|
188
|
+
/** Files that need TypeScript AST parsing */
|
|
189
|
+
readonly filesNeedingTsAst: ReadonlyArray<string>;
|
|
190
|
+
/** Files that need HTML AST parsing */
|
|
191
|
+
readonly filesNeedingHtmlAst: ReadonlyArray<string>;
|
|
192
|
+
/** Files that need CSS AST parsing */
|
|
193
|
+
readonly filesNeedingCssAst: ReadonlyArray<string>;
|
|
194
|
+
/**
|
|
195
|
+
* Files that need the TypeScript type-checker (expensive!).
|
|
196
|
+
* The engine should allocate a full TypeScript Program only for these files.
|
|
197
|
+
*/
|
|
198
|
+
readonly filesNeedingTypeChecker: ReadonlyArray<string>;
|
|
199
|
+
/** Tasks grouped by file path: filePath → tasks */
|
|
200
|
+
readonly tasksByFile: Readonly<Record<string, ReadonlyArray<Task>>>;
|
|
201
|
+
/** Tasks grouped by rule name: ruleName → tasks */
|
|
202
|
+
readonly tasksByRule: Readonly<Record<string, ReadonlyArray<string>>>;
|
|
203
|
+
/** Tasks grouped by severity: severity → tasks */
|
|
204
|
+
readonly tasksBySeverityLevel: Readonly<Record<RuleSeverity, ReadonlyArray<Task>>>;
|
|
205
|
+
/** Files grouped by type: fileType → file paths */
|
|
206
|
+
readonly filesByType: Readonly<Record<FileType, ReadonlyArray<string>>>;
|
|
207
|
+
/** Task count by severity level (backward compatible) */
|
|
208
|
+
readonly tasksBySeverity: Readonly<Record<RuleSeverity, number>>;
|
|
209
|
+
/** Global statistics */
|
|
210
|
+
readonly stats: ExecutionStats;
|
|
211
|
+
}
|
|
212
|
+
/**
|
|
213
|
+
* Global execution statistics
|
|
214
|
+
*/
|
|
215
|
+
interface ExecutionStats {
|
|
216
|
+
/** Total files in the plan */
|
|
217
|
+
readonly totalFiles: number;
|
|
218
|
+
/** Total tasks to execute */
|
|
219
|
+
readonly totalTasks: number;
|
|
220
|
+
/** Average tasks per file */
|
|
221
|
+
readonly avgTasksPerFile: number;
|
|
222
|
+
/** Files with templates */
|
|
223
|
+
readonly filesWithTemplates: number;
|
|
224
|
+
/** Files with styles */
|
|
225
|
+
readonly filesWithStyles: number;
|
|
226
|
+
/** Files with specs */
|
|
227
|
+
readonly filesWithSpecs: number;
|
|
228
|
+
}
|
|
229
|
+
/**
|
|
230
|
+
* Options for building the execution plan
|
|
231
|
+
*/
|
|
232
|
+
interface ExecutionPlanOptions {
|
|
233
|
+
/** Discovered files from Phase 1 */
|
|
234
|
+
readonly files: ReadonlyArray<string>;
|
|
235
|
+
/** Resolved rules from Phase 1.5 */
|
|
236
|
+
readonly rules: ReadonlyMap<string, ResolvedRule>;
|
|
237
|
+
/** Root directory for resolving relative paths */
|
|
238
|
+
readonly rootDir: string;
|
|
239
|
+
/** Optional cache context for persistent optimizations */
|
|
240
|
+
readonly cache?: CacheContext;
|
|
241
|
+
/** Debug mode for detailed timing logging */
|
|
242
|
+
readonly debug?: boolean;
|
|
243
|
+
/** Options for incremental filtering */
|
|
244
|
+
readonly incremental?: IncrementalFilterOptions;
|
|
245
|
+
/**
|
|
246
|
+
* Version context for cache key generation.
|
|
247
|
+
* When provided, toolVersion and ruleRegistryHash are embedded in taskIds
|
|
248
|
+
* and globalHash, ensuring caches are invalidated on tool / rule-set upgrades.
|
|
249
|
+
*
|
|
250
|
+
* Strongly recommended for production use. Omitting risks stale result-cache
|
|
251
|
+
* hits after an upgrade.
|
|
252
|
+
*/
|
|
253
|
+
readonly cacheKeyCtx?: CacheKeyContext;
|
|
254
|
+
/**
|
|
255
|
+
* Number of files at which task-building switches from sequential to
|
|
256
|
+
* parallel (worker threads). Defaults to 10 000.
|
|
257
|
+
*
|
|
258
|
+
* Lower this value to enable parallelism on smaller projects.
|
|
259
|
+
* Set to `Infinity` to always use the sequential path (useful for debugging).
|
|
260
|
+
*/
|
|
261
|
+
readonly parallelThreshold?: number;
|
|
262
|
+
/**
|
|
263
|
+
* Number of worker threads to use when parallel mode is active.
|
|
264
|
+
* Defaults to 4.
|
|
265
|
+
*/
|
|
266
|
+
readonly workerCount?: number;
|
|
267
|
+
/**
|
|
268
|
+
* Per-file rule overrides from config.overrides[].
|
|
269
|
+
*
|
|
270
|
+
* Each override entry's `files` glob patterns are matched against each
|
|
271
|
+
* analysed file path. Matching override rules are merged on top of the
|
|
272
|
+
* global resolved rules before tasks are created for that file.
|
|
273
|
+
* Last matching override wins.
|
|
274
|
+
*
|
|
275
|
+
* - `'off'` → rule is disabled for matching files
|
|
276
|
+
* - `'warn'|'error'` → severity changed, options inherited from global
|
|
277
|
+
* - object form → severity + options merged (override wins on conflicts)
|
|
278
|
+
*/
|
|
279
|
+
readonly overrides?: ReadonlyArray<ConfigOverride>;
|
|
280
|
+
}
|
|
281
|
+
/**
|
|
282
|
+
* Incremental execution plan with cache-based filtering
|
|
283
|
+
*/
|
|
284
|
+
interface IncrementalPlan {
|
|
285
|
+
/** Tasks with results in cache (can be skipped) */
|
|
286
|
+
readonly skippedTasks: ReadonlyArray<Task>;
|
|
287
|
+
/** Tasks without cache entries (must be executed) */
|
|
288
|
+
readonly tasks: ReadonlyArray<Task>;
|
|
289
|
+
/** Pre-loaded cached results (taskId → result) */
|
|
290
|
+
readonly cachedResults: ReadonlyMap<string, unknown>;
|
|
291
|
+
/** Cache statistics */
|
|
292
|
+
readonly stats: CacheFilterStats;
|
|
293
|
+
}
|
|
294
|
+
/**
|
|
295
|
+
* Cache filtering statistics
|
|
296
|
+
*/
|
|
297
|
+
interface CacheFilterStats {
|
|
298
|
+
/** Total tasks in execution plan */
|
|
299
|
+
readonly totalTasks: number;
|
|
300
|
+
/** Tasks found in cache */
|
|
301
|
+
readonly cachedTasks: number;
|
|
302
|
+
/** Tasks not in cache (need execution) */
|
|
303
|
+
readonly pendingTasks: number;
|
|
304
|
+
/** Cache hit rate (0.0 to 1.0) */
|
|
305
|
+
readonly cacheHitRate: number;
|
|
306
|
+
/**
|
|
307
|
+
* Estimated percentage of execution time saved due to caching (0–100).
|
|
308
|
+
*
|
|
309
|
+
* Computed as `cacheHitRate × 100`, which is accurate when tasks have
|
|
310
|
+
* roughly equal cost. Use as a fast approximation for progress UIs and
|
|
311
|
+
* log messages.
|
|
312
|
+
*/
|
|
313
|
+
readonly timeSavedEstimate: number;
|
|
314
|
+
}
|
|
315
|
+
/**
|
|
316
|
+
* Options for incremental filtering
|
|
317
|
+
*/
|
|
318
|
+
interface IncrementalFilterOptions {
|
|
319
|
+
/** Force re-execution even if cached */
|
|
320
|
+
readonly forceRerun?: boolean;
|
|
321
|
+
/** Load cached results into memory */
|
|
322
|
+
readonly loadCachedResults?: boolean;
|
|
323
|
+
/** Maximum age of cached results (ms) */
|
|
324
|
+
readonly maxCacheAge?: number;
|
|
325
|
+
}
|
|
326
|
+
/**
|
|
327
|
+
* Options for cache pruning
|
|
328
|
+
*/
|
|
329
|
+
interface CachePruneOptions {
|
|
330
|
+
/** Maximum age of cache entries (ms) */
|
|
331
|
+
readonly maxAge?: number;
|
|
332
|
+
/** Maximum number of entries to keep */
|
|
333
|
+
readonly maxEntries?: number;
|
|
334
|
+
/** Minimum hit count to keep */
|
|
335
|
+
readonly minHits?: number;
|
|
336
|
+
}
|
|
337
|
+
|
|
338
|
+
/**
|
|
339
|
+
* Execution Plan Builder
|
|
340
|
+
*
|
|
341
|
+
* Builds an execution plan from discovered files and resolved rules.
|
|
342
|
+
* Produces both task-centric and file-centric representations plus indexes.
|
|
343
|
+
*/
|
|
344
|
+
|
|
345
|
+
/**
|
|
346
|
+
* Builds complete execution plan with indexes and optional caching.
|
|
347
|
+
*
|
|
348
|
+
* @param options - Build options (files + rules)
|
|
349
|
+
* @returns ExecutionPlanOutput with tasks[] + plan + indexes
|
|
350
|
+
*/
|
|
351
|
+
declare const buildExecutionPlan: (options: ExecutionPlanOptions) => Promise<Result<ExecutionPlanOutput>>;
|
|
352
|
+
/**
|
|
353
|
+
* Gets execution plan summary (for logging).
|
|
354
|
+
*
|
|
355
|
+
* @param output - Execution plan output
|
|
356
|
+
* @returns Summary string
|
|
357
|
+
*/
|
|
358
|
+
declare const getExecutionPlanSummary: (output: ExecutionPlanOutput) => string;
|
|
359
|
+
|
|
360
|
+
/**
|
|
361
|
+
* File Type Detection
|
|
362
|
+
*
|
|
363
|
+
* Pure functions for detecting Angular file types based on naming conventions.
|
|
364
|
+
* Follows FP principles: pure, deterministic, no side effects.
|
|
365
|
+
*/
|
|
366
|
+
|
|
367
|
+
/**
|
|
368
|
+
* Detects file type based on file path and naming conventions.
|
|
369
|
+
*
|
|
370
|
+
* Convention rules:
|
|
371
|
+
* - *.component.ts → component
|
|
372
|
+
* - *.directive.ts → directive
|
|
373
|
+
* - *.pipe.ts → pipe
|
|
374
|
+
* - *.service.ts → service
|
|
375
|
+
* - *.module.ts → module
|
|
376
|
+
* - *.guard.ts → guard
|
|
377
|
+
* - *.html → template
|
|
378
|
+
* - *.css, *.scss, *.sass, *.less → style
|
|
379
|
+
* - *.config.ts, *.json → config
|
|
380
|
+
* - *.ts (other TypeScript) → logic
|
|
381
|
+
* - Everything else → unknown (rules are never applied to unknown files)
|
|
382
|
+
*
|
|
383
|
+
* @param filePath - Absolute or relative file path
|
|
384
|
+
* @returns FileType classification
|
|
385
|
+
*/
|
|
386
|
+
declare const detectFileType: (filePath: string) => FileType;
|
|
387
|
+
/**
|
|
388
|
+
* Checks if a file is a TypeScript file.
|
|
389
|
+
*
|
|
390
|
+
* @param filePath - File path
|
|
391
|
+
* @returns true if TypeScript file
|
|
392
|
+
*/
|
|
393
|
+
declare const isTypeScriptFile: (filePath: string) => boolean;
|
|
394
|
+
/**
|
|
395
|
+
* Checks if a file is a template file (HTML).
|
|
396
|
+
*
|
|
397
|
+
* @param filePath - File path
|
|
398
|
+
* @returns true if template file
|
|
399
|
+
*/
|
|
400
|
+
declare const isTemplateFile: (filePath: string) => boolean;
|
|
401
|
+
/**
|
|
402
|
+
* Checks if a file is a style file (CSS/SCSS/etc).
|
|
403
|
+
*
|
|
404
|
+
* @param filePath - File path
|
|
405
|
+
* @returns true if style file
|
|
406
|
+
*/
|
|
407
|
+
declare const isStyleFile: (filePath: string) => boolean;
|
|
408
|
+
/**
|
|
409
|
+
* Checks if a file is a spec file (test).
|
|
410
|
+
*
|
|
411
|
+
* @param filePath - File path
|
|
412
|
+
* @returns true if spec file
|
|
413
|
+
*/
|
|
414
|
+
declare const isSpecFile: (filePath: string) => boolean;
|
|
415
|
+
/**
|
|
416
|
+
* Checks if a file is a component file.
|
|
417
|
+
*
|
|
418
|
+
* @param filePath - File path
|
|
419
|
+
* @returns true if component file
|
|
420
|
+
*/
|
|
421
|
+
declare const isComponentFile: (filePath: string) => boolean;
|
|
422
|
+
/**
|
|
423
|
+
* Gets the base name without Angular suffix.
|
|
424
|
+
* Example: "user.component.ts" → "user"
|
|
425
|
+
*
|
|
426
|
+
* @param filePath - File path
|
|
427
|
+
* @returns Base name without suffix
|
|
428
|
+
*/
|
|
429
|
+
declare const getBaseName: (filePath: string) => string;
|
|
430
|
+
|
|
431
|
+
/**
|
|
432
|
+
* Resource Discovery
|
|
433
|
+
*
|
|
434
|
+
* Pure functions for discovering related files (templates, styles, specs)
|
|
435
|
+
* using convention-based detection (no parsing).
|
|
436
|
+
*/
|
|
437
|
+
|
|
438
|
+
/**
|
|
439
|
+
* Discovers all related resources for a TypeScript file.
|
|
440
|
+
*
|
|
441
|
+
* @param tsFilePath - TypeScript file path (absolute)
|
|
442
|
+
* @param needsTsAst - Whether TypeScript input requires AST
|
|
443
|
+
* @param needsHtmlAst - Whether template input requires AST
|
|
444
|
+
* @param needsCssAst - Whether styles inputs require AST
|
|
445
|
+
* @param needsSpecAst - Whether spec input requires AST
|
|
446
|
+
* @param directoryCache - Optional directory listing cache
|
|
447
|
+
* @returns TaskInputs with all discovered resources
|
|
448
|
+
*/
|
|
449
|
+
declare const discoverResources: (tsFilePath: string, needsTsAst: boolean, needsHtmlAst: boolean, needsCssAst: boolean, needsSpecAst: boolean, directoryCache?: Map<string, string[]>) => Promise<TaskInputs>;
|
|
450
|
+
/**
|
|
451
|
+
* Checks if any resource file exists for the given TypeScript file.
|
|
452
|
+
*
|
|
453
|
+
* @param tsFilePath - TypeScript file path
|
|
454
|
+
* @param resourceType - Type of resource to check
|
|
455
|
+
* @param directoryCache - Optional directory listing cache
|
|
456
|
+
* @returns true if resource exists
|
|
457
|
+
*/
|
|
458
|
+
declare const resourceExists: (tsFilePath: string, resourceType: "template" | "style" | "spec", directoryCache?: Map<string, string[]>) => Promise<boolean>;
|
|
459
|
+
/**
|
|
460
|
+
* Gets all style file paths for a component.
|
|
461
|
+
*
|
|
462
|
+
* @param tsFilePath - Component TypeScript file path
|
|
463
|
+
* @param directoryCache - Optional directory listing cache
|
|
464
|
+
* @returns Array of style file paths
|
|
465
|
+
*/
|
|
466
|
+
declare const getStyleFiles: (tsFilePath: string, directoryCache?: Map<string, string[]>) => Promise<ReadonlyArray<string>>;
|
|
467
|
+
/**
|
|
468
|
+
* Gets the template file path for a component.
|
|
469
|
+
*
|
|
470
|
+
* @param tsFilePath - Component TypeScript file path
|
|
471
|
+
* @param directoryCache - Optional directory listing cache
|
|
472
|
+
* @returns Template file path or null if not found
|
|
473
|
+
*/
|
|
474
|
+
declare const getTemplateFile: (tsFilePath: string, directoryCache?: Map<string, string[]>) => Promise<string | null>;
|
|
475
|
+
/**
|
|
476
|
+
* Gets the spec file path.
|
|
477
|
+
*
|
|
478
|
+
* @param tsFilePath - TypeScript file path
|
|
479
|
+
* @param directoryCache - Optional directory listing cache
|
|
480
|
+
* @returns Spec file path or null if not found
|
|
481
|
+
*/
|
|
482
|
+
declare const getSpecFile: (tsFilePath: string, directoryCache?: Map<string, string[]>) => Promise<string | null>;
|
|
483
|
+
|
|
484
|
+
interface ComponentNode {
|
|
485
|
+
tsPath: string;
|
|
486
|
+
templatePath?: string;
|
|
487
|
+
stylePaths: string[];
|
|
488
|
+
specPath?: string;
|
|
489
|
+
type: FileType;
|
|
490
|
+
}
|
|
491
|
+
/**
|
|
492
|
+
* A graph of component dependencies (template, styles, specs).
|
|
493
|
+
* Built in a single pass to avoid repeated directory scans.
|
|
494
|
+
*/
|
|
495
|
+
declare class ComponentDependencyGraph {
|
|
496
|
+
private graph;
|
|
497
|
+
/**
|
|
498
|
+
* Builds the graph from a list of files.
|
|
499
|
+
* O(N) complexity where N is the number of files.
|
|
500
|
+
* Falls back to decorator-based templateUrl/styleUrls extraction when
|
|
501
|
+
* convention-based discovery finds no template or styles.
|
|
502
|
+
*/
|
|
503
|
+
build(files: ReadonlyArray<string>): Promise<void>;
|
|
504
|
+
/**
|
|
505
|
+
* Gets resources for a given component file.
|
|
506
|
+
* O(1) lookup.
|
|
507
|
+
*/
|
|
508
|
+
getResources(tsPath: string): ComponentNode | undefined;
|
|
509
|
+
}
|
|
510
|
+
|
|
511
|
+
/**
|
|
512
|
+
* Task Builder
|
|
513
|
+
*
|
|
514
|
+
* Pure functions for building executable tasks by matching rules to files.
|
|
515
|
+
*/
|
|
516
|
+
|
|
517
|
+
interface GraphStats {
|
|
518
|
+
hits: number;
|
|
519
|
+
misses: number;
|
|
520
|
+
fallbacks: number;
|
|
521
|
+
}
|
|
522
|
+
/**
|
|
523
|
+
* Context for task building to enable memoization and shared caches.
|
|
524
|
+
*/
|
|
525
|
+
interface TaskBuilderContext {
|
|
526
|
+
hashCache?: Map<string, string>;
|
|
527
|
+
resourceCache?: Map<string, TaskInputs>;
|
|
528
|
+
directoryCache?: Map<string, string[]>;
|
|
529
|
+
globalHash?: string;
|
|
530
|
+
componentGraph?: ComponentDependencyGraph;
|
|
531
|
+
graphStats?: GraphStats;
|
|
532
|
+
/**
|
|
533
|
+
* Version context forwarded to calculateTaskId.
|
|
534
|
+
* When provided, toolVersion and ruleRegistryHash are mixed into every
|
|
535
|
+
* taskId so that upgrading the tool or a plugin invalidates per-task
|
|
536
|
+
* result-cache entries automatically.
|
|
537
|
+
*/
|
|
538
|
+
cacheKeyCtx?: CacheKeyContext;
|
|
539
|
+
}
|
|
540
|
+
/**
|
|
541
|
+
* Checks if a rule should be applied to a file type.
|
|
542
|
+
*
|
|
543
|
+
* @param rule - Resolved rule
|
|
544
|
+
* @param fileType - File type
|
|
545
|
+
* @returns true if rule applies to this file type
|
|
546
|
+
*/
|
|
547
|
+
declare const shouldApplyRule: (rule: ResolvedRule, fileType: FileType) => boolean;
|
|
548
|
+
/**
|
|
549
|
+
* Filters rules that require a specific analysis capability.
|
|
550
|
+
*
|
|
551
|
+
* @param rules - All resolved rules
|
|
552
|
+
* @param astType - Capability to filter by
|
|
553
|
+
* @returns Filtered rules
|
|
554
|
+
*/
|
|
555
|
+
declare const filterRulesByAstRequirement: (rules: ReadonlyMap<string, ResolvedRule>, astType: "tsAst" | "htmlAst" | "cssAst" | "typeChecker" | "projectContext") => ReadonlyArray<ResolvedRule>;
|
|
556
|
+
/**
|
|
557
|
+
* Groups rules by dependency type.
|
|
558
|
+
*
|
|
559
|
+
* @param rules - All resolved rules
|
|
560
|
+
* @returns Rules grouped by dependency type
|
|
561
|
+
*/
|
|
562
|
+
declare const groupRulesByDependencyType: (rules: ReadonlyMap<string, ResolvedRule>) => Readonly<Record<string, ReadonlyArray<ResolvedRule>>>;
|
|
563
|
+
/**
|
|
564
|
+
* Builds a single task with content-based taskId.
|
|
565
|
+
*
|
|
566
|
+
* @param filePath - File path
|
|
567
|
+
* @param fileType - File type
|
|
568
|
+
* @param rule - Resolved rule
|
|
569
|
+
* @param context - Optional builder context
|
|
570
|
+
* @returns Task or null if rule does not apply
|
|
571
|
+
*/
|
|
572
|
+
declare const buildTask: (filePath: string, fileType: FileType, rule: ResolvedRule, context?: TaskBuilderContext) => Promise<Task | null>;
|
|
573
|
+
/**
|
|
574
|
+
* Builds all applicable tasks for a file.
|
|
575
|
+
*
|
|
576
|
+
* @param filePath - File path
|
|
577
|
+
* @param fileType - File type
|
|
578
|
+
* @param rules - All resolved rules
|
|
579
|
+
* @param context - Optional context
|
|
580
|
+
* @returns Array of tasks
|
|
581
|
+
*/
|
|
582
|
+
declare const buildTasksForFileTaskCentric: (filePath: string, fileType: FileType, rules: ReadonlyMap<string, ResolvedRule>, context?: TaskBuilderContext) => Promise<ReadonlyArray<Task>>;
|
|
583
|
+
|
|
584
|
+
/**
|
|
585
|
+
* Content Hashing
|
|
586
|
+
*
|
|
587
|
+
* Deterministic hashing utilities for cache invalidation.
|
|
588
|
+
* Hash inputs may include: file content, related resources, and active rules.
|
|
589
|
+
*/
|
|
590
|
+
|
|
591
|
+
/**
|
|
592
|
+
* Reads file content and returns a content hash.
|
|
593
|
+
*
|
|
594
|
+
* @param filePath - File path
|
|
595
|
+
* @param cache - Optional in-memory cache
|
|
596
|
+
* @returns Content hash
|
|
597
|
+
*/
|
|
598
|
+
declare const hashFile: (filePath: string, cache?: Map<string, string>) => Promise<string>;
|
|
599
|
+
/**
|
|
600
|
+
* Calculates a combined hash for multiple files.
|
|
601
|
+
*
|
|
602
|
+
* @param filePaths - Array of file paths
|
|
603
|
+
* @param cache - Optional hash cache
|
|
604
|
+
* @returns Combined hash
|
|
605
|
+
*/
|
|
606
|
+
declare const hashFiles: (filePaths: ReadonlyArray<string>, cache?: Map<string, string>) => Promise<string>;
|
|
607
|
+
/**
|
|
608
|
+
* Calculates hash for rules configuration.
|
|
609
|
+
*
|
|
610
|
+
* @param rules - Rules that apply to this file
|
|
611
|
+
* @returns Rules hash
|
|
612
|
+
*/
|
|
613
|
+
declare const hashRules: (rules: ReadonlyArray<ResolvedRule>) => string;
|
|
614
|
+
/**
|
|
615
|
+
* Calculates combined hash for a file and its resources.
|
|
616
|
+
*
|
|
617
|
+
* @param inputs - Task inputs with hashes
|
|
618
|
+
* @param applicableRules - Rules that apply to this file
|
|
619
|
+
* @returns Combined content hash
|
|
620
|
+
*/
|
|
621
|
+
declare const calculateFileHash: (inputs: TaskInputs, applicableRules: ReadonlyArray<ResolvedRule>) => string;
|
|
622
|
+
/**
|
|
623
|
+
* Calculates hash for task inputs only (no rules).
|
|
624
|
+
*
|
|
625
|
+
* @param inputs - Task inputs
|
|
626
|
+
* @returns Inputs hash
|
|
627
|
+
*/
|
|
628
|
+
declare const hashTaskInputs: (inputs: TaskInputs) => Promise<string>;
|
|
629
|
+
/**
|
|
630
|
+
* Fast hash using only file stats.
|
|
631
|
+
*
|
|
632
|
+
* @param filePath - File path
|
|
633
|
+
* @returns Stats-based hash
|
|
634
|
+
*/
|
|
635
|
+
declare const hashFileStats: (filePath: string) => Promise<string>;
|
|
636
|
+
|
|
637
|
+
/**
|
|
638
|
+
* Index Builder
|
|
639
|
+
*
|
|
640
|
+
* Pure functions for building pre-computed indexes for O(1) queries.
|
|
641
|
+
* Indexes enable efficient incremental execution strategies.
|
|
642
|
+
*/
|
|
643
|
+
|
|
644
|
+
/**
|
|
645
|
+
* Builds all indexes from execution plan and optional task list.
|
|
646
|
+
*
|
|
647
|
+
* @param plan - Execution plan (file-centric view)
|
|
648
|
+
* @param tasks - Task-centric list (optional for backward compatibility)
|
|
649
|
+
* @returns Comprehensive pre-computed indexes
|
|
650
|
+
*/
|
|
651
|
+
declare function buildIndexes(plan: ExecutionPlan): ExecutionIndexes;
|
|
652
|
+
declare function buildIndexes(plan: ExecutionPlan, tasks: ReadonlyArray<Task>): ExecutionIndexes;
|
|
653
|
+
/**
|
|
654
|
+
* Filters index to get files for specific rules.
|
|
655
|
+
*
|
|
656
|
+
* @param index - TasksByRule index
|
|
657
|
+
* @param ruleNames - Rule names to filter by
|
|
658
|
+
* @returns Combined array of file paths
|
|
659
|
+
*/
|
|
660
|
+
declare const getFilesForRules: (index: Readonly<Record<string, ReadonlyArray<string>>>, ruleNames: ReadonlyArray<string>) => ReadonlyArray<string>;
|
|
661
|
+
/**
|
|
662
|
+
* Gets total task count from indexes.
|
|
663
|
+
*
|
|
664
|
+
* @param indexes - Execution indexes
|
|
665
|
+
* @returns Total task count
|
|
666
|
+
*/
|
|
667
|
+
declare const getTotalTasks: (indexes: ExecutionIndexes) => number;
|
|
668
|
+
/**
|
|
669
|
+
* Gets tasks count for a specific severity level.
|
|
670
|
+
*
|
|
671
|
+
* @param indexes - Execution indexes
|
|
672
|
+
* @param severity - Severity level
|
|
673
|
+
* @returns Task count
|
|
674
|
+
*/
|
|
675
|
+
declare const getTasksCountBySeverity: (indexes: ExecutionIndexes, severity: RuleSeverity) => number;
|
|
676
|
+
|
|
677
|
+
/**
|
|
678
|
+
* Incremental Planner (Phase 2.0)
|
|
679
|
+
*
|
|
680
|
+
* Filters execution tasks by cache status.
|
|
681
|
+
* Splits tasks into cached (skip) and pending (execute).
|
|
682
|
+
*/
|
|
683
|
+
|
|
684
|
+
/**
|
|
685
|
+
* Filters tasks by cache status.
|
|
686
|
+
*
|
|
687
|
+
* @param tasks - All tasks from execution plan
|
|
688
|
+
* @param cache - Result cache
|
|
689
|
+
* @param options - Filter options
|
|
690
|
+
* @returns Incremental plan with cache split
|
|
691
|
+
*/
|
|
692
|
+
declare const filterCachedTasks: (tasks: ReadonlyArray<Task>, cache: ResultCache, options?: IncrementalFilterOptions) => Promise<IncrementalPlan>;
|
|
693
|
+
/**
|
|
694
|
+
* Checks if all tasks are cached.
|
|
695
|
+
*
|
|
696
|
+
* @param tasks - Tasks to check
|
|
697
|
+
* @param cache - Result cache
|
|
698
|
+
* @returns true if all tasks are cached
|
|
699
|
+
*/
|
|
700
|
+
declare const areAllTasksCached: (tasks: ReadonlyArray<Task>, cache: ResultCache) => Promise<boolean>;
|
|
701
|
+
/**
|
|
702
|
+
* Gets cache hit rate for a set of tasks.
|
|
703
|
+
*
|
|
704
|
+
* @param tasks - Tasks to check
|
|
705
|
+
* @param cache - Result cache
|
|
706
|
+
* @returns Cache hit rate (0.0 to 1.0)
|
|
707
|
+
*/
|
|
708
|
+
declare const getCacheHitRate: (tasks: ReadonlyArray<Task>, cache: ResultCache) => Promise<number>;
|
|
709
|
+
/**
|
|
710
|
+
* Prunes stale cache entries.
|
|
711
|
+
*
|
|
712
|
+
* @param taskIds - All current task IDs
|
|
713
|
+
* @param cache - Result cache
|
|
714
|
+
* @param options - Prune options
|
|
715
|
+
* @returns Number of entries removed
|
|
716
|
+
*/
|
|
717
|
+
declare const pruneStaleCache: (taskIds: ReadonlyArray<string>, cache: ResultCache, options?: CachePruneOptions) => Promise<number>;
|
|
718
|
+
|
|
719
|
+
/**
|
|
720
|
+
* Groups tasks by file path.
|
|
721
|
+
*
|
|
722
|
+
* @param tasks - Flat list of tasks
|
|
723
|
+
* @returns Map keyed by file path
|
|
724
|
+
*/
|
|
725
|
+
declare const groupTasksByFile: (tasks: ReadonlyArray<Task>) => Map<string, Task[]>;
|
|
726
|
+
|
|
727
|
+
/**
|
|
728
|
+
* Scanner → Planner Bridge Utilities
|
|
729
|
+
*
|
|
730
|
+
* Convenience helpers that convert `@ngcompass/scanner`'s `ScanResult` into
|
|
731
|
+
* the inputs expected by `@ngcompass/planner`'s `buildExecutionPlan`.
|
|
732
|
+
*
|
|
733
|
+
* Using this module eliminates the boilerplate of manually forwarding
|
|
734
|
+
* `ScanResult.files` and keeps the two packages loosely coupled — if either
|
|
735
|
+
* package changes its contract, only this file needs updating.
|
|
736
|
+
*/
|
|
737
|
+
|
|
738
|
+
/**
|
|
739
|
+
* Minimal `ScanResult` shape consumed by the bridge.
|
|
740
|
+
*
|
|
741
|
+
* This matches `@ngcompass/scanner`'s `ScanResult` interface and is kept
|
|
742
|
+
* inline to avoid a circular package dependency (scanner → planner would
|
|
743
|
+
* create a cycle). Only the fields actually used by `scanResultToPlanInput`
|
|
744
|
+
* are listed here.
|
|
745
|
+
*/
|
|
746
|
+
interface ScanResultBridge {
|
|
747
|
+
/** Discovered file paths (absolute). */
|
|
748
|
+
readonly files: ReadonlyArray<string>;
|
|
749
|
+
/** Optional scan timestamp (ms since epoch). */
|
|
750
|
+
readonly timestamp?: number;
|
|
751
|
+
}
|
|
752
|
+
/**
|
|
753
|
+
* Options for converting a scan result into planner inputs.
|
|
754
|
+
*/
|
|
755
|
+
interface ScanToPlanOptions {
|
|
756
|
+
/** Resolved rules produced by the rule resolver (Phase 1.5). */
|
|
757
|
+
readonly rules: ReadonlyMap<string, ResolvedRule>;
|
|
758
|
+
/** Absolute path to the project root. */
|
|
759
|
+
readonly rootDir: string;
|
|
760
|
+
/** Optional cache context for persistent plan and result caching. */
|
|
761
|
+
readonly cache?: CacheContext;
|
|
762
|
+
/** Debug mode: emit detailed timing output to the planner logger. */
|
|
763
|
+
readonly debug?: boolean;
|
|
764
|
+
/** Options for incremental (cache-based) task filtering. */
|
|
765
|
+
readonly incremental?: IncrementalFilterOptions;
|
|
766
|
+
/**
|
|
767
|
+
* Version context for cache key generation. Strongly recommended for
|
|
768
|
+
* production use — omitting risks stale cache hits after a tool upgrade.
|
|
769
|
+
*/
|
|
770
|
+
readonly cacheKeyCtx?: CacheKeyContext;
|
|
771
|
+
/**
|
|
772
|
+
* File count threshold above which task-building switches to parallel
|
|
773
|
+
* worker threads. Forwarded verbatim to `ExecutionPlanOptions`.
|
|
774
|
+
* @default 10000
|
|
775
|
+
*/
|
|
776
|
+
readonly parallelThreshold?: number;
|
|
777
|
+
/**
|
|
778
|
+
* Number of worker threads used in parallel mode.
|
|
779
|
+
* @default 4
|
|
780
|
+
*/
|
|
781
|
+
readonly workerCount?: number;
|
|
782
|
+
}
|
|
783
|
+
/**
|
|
784
|
+
* Converts a `ScanResult` (from `@ngcompass/scanner`) into an
|
|
785
|
+
* `ExecutionPlanOptions` object ready to pass to `buildExecutionPlan`.
|
|
786
|
+
*
|
|
787
|
+
* @example
|
|
788
|
+
* ```typescript
|
|
789
|
+
* import { scan } from '@ngcompass/scanner';
|
|
790
|
+
* import { buildExecutionPlan } from '@ngcompass/planner';
|
|
791
|
+
* import { scanResultToPlanInput } from '@ngcompass/planner/integration';
|
|
792
|
+
*
|
|
793
|
+
* const scanResult = await scan({ rootDir: '.', include: [], exclude: [] });
|
|
794
|
+
* if (!scanResult.ok) throw scanResult.error;
|
|
795
|
+
*
|
|
796
|
+
* const planOptions = scanResultToPlanInput(scanResult.data, {
|
|
797
|
+
* rules,
|
|
798
|
+
* rootDir: '.',
|
|
799
|
+
* cache,
|
|
800
|
+
* });
|
|
801
|
+
*
|
|
802
|
+
* const plan = await buildExecutionPlan(planOptions);
|
|
803
|
+
* ```
|
|
804
|
+
*
|
|
805
|
+
* @param scanResult - Result of a successful `scan()` call.
|
|
806
|
+
* @param opts - Planner configuration (rules, rootDir, cache, …).
|
|
807
|
+
* @returns `ExecutionPlanOptions` ready for `buildExecutionPlan`.
|
|
808
|
+
*/
|
|
809
|
+
declare const scanResultToPlanInput: (scanResult: ScanResultBridge, opts: ScanToPlanOptions) => ExecutionPlanOptions;
|
|
810
|
+
/**
|
|
811
|
+
* Returns `true` if the scan produced at least one file that the planner
|
|
812
|
+
* can operate on (i.e. the file list is non-empty).
|
|
813
|
+
*
|
|
814
|
+
* Useful as a fast guard before calling `buildExecutionPlan`.
|
|
815
|
+
*
|
|
816
|
+
* @param scanResult - Bridge-compatible scan result.
|
|
817
|
+
*/
|
|
818
|
+
declare const hasScanFiles: (scanResult: ScanResultBridge) => boolean;
|
|
819
|
+
/**
|
|
820
|
+
* Returns the discovered file count from a scan result.
|
|
821
|
+
*
|
|
822
|
+
* @param scanResult - Bridge-compatible scan result.
|
|
823
|
+
*/
|
|
824
|
+
declare const getScanFileCount: (scanResult: ScanResultBridge) => number;
|
|
825
|
+
|
|
826
|
+
export { type CacheFilterStats, type CachePruneOptions, type ExecutionIndexes, type ExecutionPlan, type ExecutionPlanOptions, type ExecutionPlanOutput, type ExecutionStats, type FileAnalysisUnit, type FileInfo, type FileInput, type FileType, type IncrementalFilterOptions, type IncrementalPlan, type ResourceType, type RuleTask, type ScanResultBridge, type ScanToPlanOptions, type Task, type TaskInputs, areAllTasksCached, buildExecutionPlan, buildIndexes, buildTask, buildTasksForFileTaskCentric as buildTasksForFile, calculateFileHash, detectFileType, discoverResources, filterCachedTasks, filterRulesByAstRequirement, getBaseName, getCacheHitRate, getExecutionPlanSummary, getFilesForRules, getScanFileCount, getSpecFile, getStyleFiles, getTasksCountBySeverity, getTemplateFile, getTotalTasks, groupRulesByDependencyType, groupTasksByFile, hasScanFiles, hashFile, hashFileStats, hashFiles, hashRules, hashTaskInputs, isComponentFile, isSpecFile, isStyleFile, isTemplateFile, isTypeScriptFile, pruneStaleCache, resourceExists, scanResultToPlanInput, shouldApplyRule };
|