@archora/core 1.1.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.
- package/LICENSE +201 -0
- package/README.md +62 -0
- package/package.json +36 -0
- package/src/README.md +4 -0
- package/src/analyzer/__tests__/__snapshots__/referenceSnapshot.test.ts.snap +145 -0
- package/src/analyzer/__tests__/_paths.ts +8 -0
- package/src/analyzer/__tests__/analyze.test.ts +522 -0
- package/src/analyzer/__tests__/archDebt.test.ts +111 -0
- package/src/analyzer/__tests__/asyncLifecycleRisk.test.ts +122 -0
- package/src/analyzer/__tests__/browserFsAccessFileSource.test.ts +97 -0
- package/src/analyzer/__tests__/bundle.test.ts +191 -0
- package/src/analyzer/__tests__/classify.test.ts +99 -0
- package/src/analyzer/__tests__/contracts.test.ts +372 -0
- package/src/analyzer/__tests__/crossSourceConsistency.test.ts +317 -0
- package/src/analyzer/__tests__/cyclePatterns.test.ts +132 -0
- package/src/analyzer/__tests__/cycles.test.ts +74 -0
- package/src/analyzer/__tests__/detect.test.ts +62 -0
- package/src/analyzer/__tests__/discover.test.ts +68 -0
- package/src/analyzer/__tests__/displayId.test.ts +30 -0
- package/src/analyzer/__tests__/feedbackArcSet.test.ts +168 -0
- package/src/analyzer/__tests__/inMemoryFileSource.test.ts +34 -0
- package/src/analyzer/__tests__/incremental.test.ts +154 -0
- package/src/analyzer/__tests__/layers.test.ts +87 -0
- package/src/analyzer/__tests__/layersOverrides.test.ts +120 -0
- package/src/analyzer/__tests__/memoryRisk.test.ts +132 -0
- package/src/analyzer/__tests__/metrics.test.ts +59 -0
- package/src/analyzer/__tests__/parserRegistry.test.ts +54 -0
- package/src/analyzer/__tests__/parsers.test.ts +187 -0
- package/src/analyzer/__tests__/reactParser.test.ts +93 -0
- package/src/analyzer/__tests__/recommendations.test.ts +171 -0
- package/src/analyzer/__tests__/referenceSnapshot.test.ts +63 -0
- package/src/analyzer/__tests__/resolve.test.ts +294 -0
- package/src/analyzer/__tests__/rsc.test.ts +130 -0
- package/src/analyzer/__tests__/signals.test.ts +316 -0
- package/src/analyzer/__tests__/suggestContracts.test.ts +108 -0
- package/src/analyzer/__tests__/svelteParser.test.ts +108 -0
- package/src/analyzer/__tests__/typeOnlyCandidates.test.ts +163 -0
- package/src/analyzer/__tests__/vueAutoImport.test.ts +177 -0
- package/src/analyzer/archDebt.ts +68 -0
- package/src/analyzer/asyncLifecycleRisk.ts +234 -0
- package/src/analyzer/buildGraph.ts +683 -0
- package/src/analyzer/bundle/analyzeBundle.ts +147 -0
- package/src/analyzer/bundle/index.ts +12 -0
- package/src/analyzer/bundle/parseStats.ts +152 -0
- package/src/analyzer/bundle/types.ts +85 -0
- package/src/analyzer/classify.ts +54 -0
- package/src/analyzer/contracts.ts +265 -0
- package/src/analyzer/cyclePatterns.ts +138 -0
- package/src/analyzer/cycles.ts +98 -0
- package/src/analyzer/detect.ts +34 -0
- package/src/analyzer/discover.ts +131 -0
- package/src/analyzer/displayId.ts +21 -0
- package/src/analyzer/entryPoints.ts +136 -0
- package/src/analyzer/feedbackArcSet.ts +332 -0
- package/src/analyzer/fileSource.ts +8 -0
- package/src/analyzer/hotZones.ts +17 -0
- package/src/analyzer/incremental.ts +455 -0
- package/src/analyzer/index.ts +444 -0
- package/src/analyzer/layers.ts +183 -0
- package/src/analyzer/loadAliases.ts +288 -0
- package/src/analyzer/memoryRisk.ts +345 -0
- package/src/analyzer/metrics.ts +156 -0
- package/src/analyzer/parsers/index.ts +62 -0
- package/src/analyzer/parsers/reactParser.ts +24 -0
- package/src/analyzer/parsers/svelteParser.ts +46 -0
- package/src/analyzer/parsers/tsParser.ts +364 -0
- package/src/analyzer/parsers/vueParser.ts +109 -0
- package/src/analyzer/recommendations.ts +432 -0
- package/src/analyzer/resolve.ts +315 -0
- package/src/analyzer/rsc.ts +120 -0
- package/src/analyzer/signals.ts +684 -0
- package/src/analyzer/sources/browserFsAccessFileSource.ts +132 -0
- package/src/analyzer/sources/inMemoryFileSource.ts +24 -0
- package/src/analyzer/sources/nodeFsFileSource.ts +93 -0
- package/src/analyzer/sources/tauriFileSource.ts +68 -0
- package/src/analyzer/suggestContracts.ts +214 -0
- package/src/analyzer/typeOnlyCandidates.ts +233 -0
- package/src/analyzer/types.ts +537 -0
- package/src/cache/__tests__/cache.test.ts +316 -0
- package/src/cache/index.ts +432 -0
- package/src/codegen/__tests__/applyTypeOnlyFix.integration.test.ts +62 -0
- package/src/codegen/__tests__/applyTypeOnlyFix.test.ts +176 -0
- package/src/codegen/__tests__/configSnippets.test.ts +230 -0
- package/src/codegen/applyTypeOnlyFix.ts +344 -0
- package/src/codegen/configSnippets.ts +172 -0
- package/src/codegen/initConfig.ts +223 -0
- package/src/config/__tests__/frontScopeConfig.test.ts +187 -0
- package/src/config/frontScopeConfig.ts +830 -0
- package/src/diff/__tests__/diffScans.test.ts +103 -0
- package/src/diff/diffScans.ts +61 -0
- package/src/diff/index.ts +2 -0
- package/src/diff/types.ts +39 -0
- package/src/git/__tests__/computeChurn.test.ts +113 -0
- package/src/git/__tests__/computeTemporalCoupling.test.ts +125 -0
- package/src/git/__tests__/parseGitLog.test.ts +120 -0
- package/src/git/computeChurn.ts +111 -0
- package/src/git/computeTemporalCoupling.ts +114 -0
- package/src/git/index.ts +24 -0
- package/src/git/parseGitLog.ts +124 -0
- package/src/git/readGitHistory.ts +130 -0
- package/src/git/types.ts +119 -0
- package/src/index.ts +137 -0
- package/src/report/__tests__/buildFixPlan.test.ts +357 -0
- package/src/report/__tests__/buildJsonReport.test.ts +34 -0
- package/src/report/buildFixPlan.ts +481 -0
- package/src/report/buildJsonReport.ts +27 -0
- package/src/search/__tests__/parseQuery.test.ts +67 -0
- package/src/search/__tests__/search.test.ts +172 -0
- package/src/search/index.ts +281 -0
- package/src/search/parseQuery.ts +75 -0
- package/src/views/__tests__/analyzerViews.test.ts +558 -0
- package/src/views/analyzerViews.ts +1294 -0
|
@@ -0,0 +1,537 @@
|
|
|
1
|
+
export type ModuleId = string;
|
|
2
|
+
|
|
3
|
+
export type ModuleKind =
|
|
4
|
+
| 'api'
|
|
5
|
+
| 'component'
|
|
6
|
+
| 'composable'
|
|
7
|
+
| 'config'
|
|
8
|
+
| 'store'
|
|
9
|
+
| 'route'
|
|
10
|
+
| 'model'
|
|
11
|
+
| 'module'
|
|
12
|
+
| 'schema'
|
|
13
|
+
| 'service'
|
|
14
|
+
| 'style'
|
|
15
|
+
| 'test'
|
|
16
|
+
| 'util'
|
|
17
|
+
| 'entry'
|
|
18
|
+
| 'integration'
|
|
19
|
+
/** @deprecated kept for old scan JSON compatibility; new scans use `module`. */
|
|
20
|
+
| 'unknown';
|
|
21
|
+
|
|
22
|
+
export type ModuleLanguage = 'ts' | 'js' | 'vue' | 'svelte';
|
|
23
|
+
|
|
24
|
+
export type EdgeKind = 'static' | 'dynamic' | 'type-only' | 'side-effect' | 'auto-import';
|
|
25
|
+
export type FactConfidence = 'high' | 'medium' | 'low';
|
|
26
|
+
export type ImportResolutionKind =
|
|
27
|
+
| 'literal'
|
|
28
|
+
| 'dynamic-literal'
|
|
29
|
+
| 'glob'
|
|
30
|
+
| 'prefix'
|
|
31
|
+
| 'framework-auto'
|
|
32
|
+
| 'asset'
|
|
33
|
+
| 'external';
|
|
34
|
+
|
|
35
|
+
export type DetectedFramework =
|
|
36
|
+
| 'vue'
|
|
37
|
+
| 'react'
|
|
38
|
+
| 'svelte'
|
|
39
|
+
| 'nuxt'
|
|
40
|
+
| 'next'
|
|
41
|
+
| 'generic'
|
|
42
|
+
/** @deprecated kept for old scan JSON compatibility; new scans use `generic`. */
|
|
43
|
+
| 'unknown';
|
|
44
|
+
|
|
45
|
+
export interface ProjectRef {
|
|
46
|
+
id: string;
|
|
47
|
+
name: string;
|
|
48
|
+
rootPath: string;
|
|
49
|
+
detectedFramework: DetectedFramework;
|
|
50
|
+
tsconfigPath?: string;
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
export interface ModuleNode {
|
|
54
|
+
id: ModuleId;
|
|
55
|
+
absPath: string;
|
|
56
|
+
kind: ModuleKind;
|
|
57
|
+
language: ModuleLanguage;
|
|
58
|
+
loc: number;
|
|
59
|
+
exports: string[];
|
|
60
|
+
isInfra: boolean;
|
|
61
|
+
/**
|
|
62
|
+
* Server/client/shared classification (RSC).
|
|
63
|
+
* Inferred from `'use server'` / `'use client'` directives plus framework
|
|
64
|
+
* conventions (Next app/, Nuxt server/, SvelteKit `+server.ts`/`*.server.ts`).
|
|
65
|
+
* Defaults to `'shared'` when nothing pins it down.
|
|
66
|
+
*/
|
|
67
|
+
runtime?: ModuleRuntime;
|
|
68
|
+
isGenerated?: boolean;
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
export type ModuleRuntime = 'server' | 'client' | 'shared';
|
|
72
|
+
|
|
73
|
+
export interface DependencyEdge {
|
|
74
|
+
from: ModuleId;
|
|
75
|
+
to: ModuleId;
|
|
76
|
+
kind: EdgeKind;
|
|
77
|
+
specifier: string;
|
|
78
|
+
resolved: boolean;
|
|
79
|
+
confidence?: FactConfidence;
|
|
80
|
+
resolutionKind?: ImportResolutionKind;
|
|
81
|
+
approximate?: boolean;
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
export interface CycleBreakpoint {
|
|
85
|
+
from: ModuleId;
|
|
86
|
+
to: ModuleId;
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
export interface Cycle {
|
|
90
|
+
// `cycle:<hex8>` content-addressed over the sorted member list. Stable
|
|
91
|
+
// across module insertion order; safe as a dictionary key and baseline
|
|
92
|
+
// marker.
|
|
93
|
+
id: string;
|
|
94
|
+
modules: ModuleId[];
|
|
95
|
+
length: number;
|
|
96
|
+
severity: 'direct' | 'indirect';
|
|
97
|
+
// Edge picked from the feedback arc set as the cheapest break point.
|
|
98
|
+
// Absent for SCCs with no recoverable internal edges.
|
|
99
|
+
suggestedBreakpoint?: CycleBreakpoint;
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
export interface ModuleMetrics {
|
|
103
|
+
fanIn: number;
|
|
104
|
+
fanOut: number;
|
|
105
|
+
instability: number;
|
|
106
|
+
depth: number;
|
|
107
|
+
inCycle: boolean;
|
|
108
|
+
couplingScore: number;
|
|
109
|
+
hotnessScore: number;
|
|
110
|
+
}
|
|
111
|
+
|
|
112
|
+
export interface AnalyzerWarning {
|
|
113
|
+
code:
|
|
114
|
+
| 'parse-failed'
|
|
115
|
+
| 'resolve-failed'
|
|
116
|
+
| 'self-import'
|
|
117
|
+
| 'tsconfig-missing'
|
|
118
|
+
| 'unsupported-extension';
|
|
119
|
+
message: string;
|
|
120
|
+
file?: string;
|
|
121
|
+
detail?: string;
|
|
122
|
+
}
|
|
123
|
+
|
|
124
|
+
// Forward import-as-type so `ScanResult` below can use `ContractViolation`.
|
|
125
|
+
// We re-export at the bottom so consumers can `import type { ContractViolation } from '@archora/core'`.
|
|
126
|
+
import type { ContractViolation as _ContractViolation } from './contracts';
|
|
127
|
+
import type { BundleReport as _BundleReport } from './bundle/types';
|
|
128
|
+
import type { ConfigDiagnostic as _ConfigDiagnostic } from '../config/frontScopeConfig';
|
|
129
|
+
import type {
|
|
130
|
+
ChurnByModule as _ChurnByModule,
|
|
131
|
+
GitHistory as _GitHistory,
|
|
132
|
+
TemporalCoupling as _TemporalCoupling,
|
|
133
|
+
} from '../git/types';
|
|
134
|
+
|
|
135
|
+
export interface ScanResult {
|
|
136
|
+
project: ProjectRef;
|
|
137
|
+
modules: ModuleNode[];
|
|
138
|
+
edges: DependencyEdge[];
|
|
139
|
+
cycles: Cycle[];
|
|
140
|
+
metrics: Record<ModuleId, ModuleMetrics>;
|
|
141
|
+
hotZones: ModuleId[];
|
|
142
|
+
layerViolations: LayerViolation[];
|
|
143
|
+
archDebt: ArchDebt;
|
|
144
|
+
recommendations: Recommendation[];
|
|
145
|
+
/**
|
|
146
|
+
* Trust layer. Signals are evidence-backed compatibility output
|
|
147
|
+
* derived from analyzer facts and legacy recommendations. The legacy
|
|
148
|
+
* `recommendations` array remains the UI/CLI compatibility projection.
|
|
149
|
+
*/
|
|
150
|
+
signals?: ArchitectureSignal[];
|
|
151
|
+
insights?: ArchitectureInsight[];
|
|
152
|
+
/**
|
|
153
|
+
* Parser fact summaries. This is an additive compatibility layer:
|
|
154
|
+
* legacy ParsedFile/RawImport still drive graph construction, while these
|
|
155
|
+
* facts expose confidence/limitations for future signals.
|
|
156
|
+
*/
|
|
157
|
+
parserFacts?: ParsedFileSummary[];
|
|
158
|
+
/**
|
|
159
|
+
* Violations of user-declared architectural contracts (boundaries / budgets
|
|
160
|
+
* / api-stability). Empty when no `contracts` block is defined in
|
|
161
|
+
* `.archora.json`.
|
|
162
|
+
*/
|
|
163
|
+
contractViolations: _ContractViolation[];
|
|
164
|
+
/**
|
|
165
|
+
* First-class `.archora.json` setup diagnostics. Invalid config is still
|
|
166
|
+
* soft-failed into defaults, but callers can show the dropped fields and
|
|
167
|
+
* parse errors as fixable setup issues.
|
|
168
|
+
*/
|
|
169
|
+
configDiagnostics?: _ConfigDiagnostic[];
|
|
170
|
+
/**
|
|
171
|
+
* Human-facing rules config state. `not-configured` is not an error: it means
|
|
172
|
+
* the scan used built-in defaults and no project rules file was found.
|
|
173
|
+
*/
|
|
174
|
+
configStatus?: {
|
|
175
|
+
state: 'not-configured' | 'loaded' | 'invalid';
|
|
176
|
+
file: string | null;
|
|
177
|
+
};
|
|
178
|
+
/**
|
|
179
|
+
* Bundle-aware analysis. Populated only when the caller supplied
|
|
180
|
+
* a parsed bundler stats payload via `AnalyzeOptions.bundleStats`.
|
|
181
|
+
*/
|
|
182
|
+
bundle?: _BundleReport;
|
|
183
|
+
/**
|
|
184
|
+
* Per-module churn. Populated only when the caller supplied
|
|
185
|
+
* `AnalyzeOptions.gitHistory`. Modules with zero touches in the history
|
|
186
|
+
* window are absent from the map.
|
|
187
|
+
*/
|
|
188
|
+
churn?: _ChurnByModule;
|
|
189
|
+
/**
|
|
190
|
+
* The git history that was used to compute `churn`. Echoed back so
|
|
191
|
+
* consumers (UI, reports) can show window/commit-count metadata without
|
|
192
|
+
* re-running git.
|
|
193
|
+
*/
|
|
194
|
+
gitHistory?: _GitHistory;
|
|
195
|
+
/**
|
|
196
|
+
* Top temporally coupled module pairs. Sorted: hidden
|
|
197
|
+
* couplings first, then by score desc. Capped at `maxPairs` (default 100).
|
|
198
|
+
*/
|
|
199
|
+
temporalCoupling?: _TemporalCoupling[];
|
|
200
|
+
/**
|
|
201
|
+
* Static browser memory-risk heuristics. These findings identify cleanup
|
|
202
|
+
* patterns worth reviewing; they are not runtime leak proof.
|
|
203
|
+
*/
|
|
204
|
+
memoryRisks?: MemoryRiskFinding[];
|
|
205
|
+
/**
|
|
206
|
+
* Static async lifecycle heuristics. These findings identify async work
|
|
207
|
+
* that can outlive component lifecycle without an abort or stale guard.
|
|
208
|
+
*/
|
|
209
|
+
asyncLifecycleRisks?: AsyncLifecycleRiskFinding[];
|
|
210
|
+
scannedAt: string;
|
|
211
|
+
durationMs: number;
|
|
212
|
+
warnings: AnalyzerWarning[];
|
|
213
|
+
}
|
|
214
|
+
|
|
215
|
+
/**
|
|
216
|
+
* Re-exported here (rather than imported from `analyzer/contracts.ts`) so
|
|
217
|
+
* downstream packages don't need a sub-path import - keeps `ScanResult`
|
|
218
|
+
* self-contained.
|
|
219
|
+
*/
|
|
220
|
+
export type { ContractViolation } from './contracts';
|
|
221
|
+
export type { ConfigDiagnostic, ConfigDiagnosticSeverity } from '../config/frontScopeConfig';
|
|
222
|
+
export type {
|
|
223
|
+
ChurnAuthor,
|
|
224
|
+
ChurnByModule,
|
|
225
|
+
ChurnMetric,
|
|
226
|
+
GitCommit,
|
|
227
|
+
GitFileChange,
|
|
228
|
+
GitHistory,
|
|
229
|
+
TemporalCoupling,
|
|
230
|
+
TemporalCouplingThresholds,
|
|
231
|
+
} from '../git/types';
|
|
232
|
+
export type {
|
|
233
|
+
BundleBloat,
|
|
234
|
+
BundleBloatKind,
|
|
235
|
+
BundleChunk,
|
|
236
|
+
BundleChunkModule,
|
|
237
|
+
BundleReport,
|
|
238
|
+
BundleThresholds,
|
|
239
|
+
ParsedBundleStats,
|
|
240
|
+
} from './bundle/types';
|
|
241
|
+
|
|
242
|
+
export interface LayerViolation {
|
|
243
|
+
edgeId: string;
|
|
244
|
+
from: ModuleId;
|
|
245
|
+
to: ModuleId;
|
|
246
|
+
fromLayer: string;
|
|
247
|
+
toLayer: string;
|
|
248
|
+
severity: 'error' | 'warning';
|
|
249
|
+
}
|
|
250
|
+
|
|
251
|
+
export interface Recommendation {
|
|
252
|
+
id: string;
|
|
253
|
+
kind:
|
|
254
|
+
| 'split-god-module'
|
|
255
|
+
| 'unused-utility'
|
|
256
|
+
/** @deprecated use `cycle-break-cluster`. Kept for snapshot compatibility. */
|
|
257
|
+
| 'cycle-break-candidate'
|
|
258
|
+
| 'cycle-break-cluster'
|
|
259
|
+
| 'type-only-candidate'
|
|
260
|
+
| 'misplaced-by-layer'
|
|
261
|
+
| 'isolated-cluster'
|
|
262
|
+
| 'contract-violation'
|
|
263
|
+
| 'bundle-bloat'
|
|
264
|
+
| 'temporal-coupling';
|
|
265
|
+
modules: ModuleId[];
|
|
266
|
+
/**
|
|
267
|
+
* Per-kind structured payload. Primitive values flow into the i18n template
|
|
268
|
+
* picked by `kind`; complex values (e.g. the feedback-edge list for
|
|
269
|
+
* `cycle-break-cluster`) are rendered explicitly by the UI. Storing
|
|
270
|
+
* structured data here keeps the recommendation localization-agnostic.
|
|
271
|
+
*/
|
|
272
|
+
params: Record<string, string | number | readonly CycleFeedbackEdge[]>;
|
|
273
|
+
weight: number;
|
|
274
|
+
}
|
|
275
|
+
|
|
276
|
+
export interface CycleFeedbackEdge {
|
|
277
|
+
from: ModuleId;
|
|
278
|
+
to: ModuleId;
|
|
279
|
+
/** Number of elementary cycles broken by removing this edge. */
|
|
280
|
+
broken: number;
|
|
281
|
+
/** True when the count is an estimate (large SCC, cap reached). */
|
|
282
|
+
partial: boolean;
|
|
283
|
+
}
|
|
284
|
+
|
|
285
|
+
export interface ArchDebt {
|
|
286
|
+
/** 0..100, higher = worse. Composite of cycles, layer violations, hot-zone density and avg coupling. */
|
|
287
|
+
score: number;
|
|
288
|
+
grade: 'A' | 'B' | 'C' | 'D' | 'F';
|
|
289
|
+
breakdown: {
|
|
290
|
+
cycles: number;
|
|
291
|
+
layerViolations: number;
|
|
292
|
+
hotZones: number;
|
|
293
|
+
coupling: number;
|
|
294
|
+
};
|
|
295
|
+
}
|
|
296
|
+
|
|
297
|
+
export interface RawImport {
|
|
298
|
+
specifier: string;
|
|
299
|
+
kind: EdgeKind;
|
|
300
|
+
confidence?: FactConfidence;
|
|
301
|
+
resolutionKind?: ImportResolutionKind;
|
|
302
|
+
approximate?: boolean;
|
|
303
|
+
/**
|
|
304
|
+
* Match strategy for the specifier when the graph builder resolves it.
|
|
305
|
+
*
|
|
306
|
+
* - `literal` (default): exact specifier, resolves to a single module.
|
|
307
|
+
* - `prefix`: the specifier is the static prefix of a dynamic path (e.g. the
|
|
308
|
+
* head of a template literal `` `./mfes/${name}/index` `` is `./mfes/`).
|
|
309
|
+
* The graph builder treats it as a directory and creates one edge per
|
|
310
|
+
* matching file inside. Used to recover MFE-style dynamic loaders that
|
|
311
|
+
* would otherwise produce false-positive isolated-cluster insights.
|
|
312
|
+
* - `glob`: the specifier is a Vite-style `import.meta.glob(...)` pattern,
|
|
313
|
+
* resolved against the project's file list to one edge per match.
|
|
314
|
+
* Multiple patterns are emitted as multiple `RawImport` entries.
|
|
315
|
+
*/
|
|
316
|
+
pattern?: 'literal' | 'prefix' | 'glob';
|
|
317
|
+
globEager?: boolean;
|
|
318
|
+
globImport?: string;
|
|
319
|
+
}
|
|
320
|
+
|
|
321
|
+
export interface ImportFact {
|
|
322
|
+
specifier: string;
|
|
323
|
+
kind: EdgeKind;
|
|
324
|
+
resolutionKind: ImportResolutionKind;
|
|
325
|
+
confidence: FactConfidence;
|
|
326
|
+
approximate: boolean;
|
|
327
|
+
isAsset?: boolean;
|
|
328
|
+
globEager?: boolean;
|
|
329
|
+
globImport?: string;
|
|
330
|
+
negative?: boolean;
|
|
331
|
+
}
|
|
332
|
+
|
|
333
|
+
export interface ExportFact {
|
|
334
|
+
name: string;
|
|
335
|
+
kind: 'value' | 'type' | 'default' | 'namespace' | 'named' | 'unknown';
|
|
336
|
+
source?: string;
|
|
337
|
+
confidence: FactConfidence;
|
|
338
|
+
}
|
|
339
|
+
|
|
340
|
+
export interface RuntimeFact {
|
|
341
|
+
runtime: ModuleRuntime;
|
|
342
|
+
source: 'directive' | 'framework-convention' | 'default';
|
|
343
|
+
confidence: FactConfidence;
|
|
344
|
+
}
|
|
345
|
+
|
|
346
|
+
export interface FrameworkFact {
|
|
347
|
+
kind:
|
|
348
|
+
| 'vue-template-ref'
|
|
349
|
+
| 'react-lazy'
|
|
350
|
+
| 'next-dynamic'
|
|
351
|
+
| 'nuxt-auto-component'
|
|
352
|
+
| 'nuxt-auto-composable'
|
|
353
|
+
| 'sveltekit-route'
|
|
354
|
+
| 'unknown';
|
|
355
|
+
value: string;
|
|
356
|
+
confidence: FactConfidence;
|
|
357
|
+
}
|
|
358
|
+
|
|
359
|
+
export interface RouteFact {
|
|
360
|
+
routeKind: 'page' | 'layout' | 'api' | 'middleware' | 'server-route';
|
|
361
|
+
confidence: FactConfidence;
|
|
362
|
+
}
|
|
363
|
+
|
|
364
|
+
export interface StateFact {
|
|
365
|
+
kind: 'pinia-store' | 'unknown';
|
|
366
|
+
confidence: FactConfidence;
|
|
367
|
+
}
|
|
368
|
+
|
|
369
|
+
export interface AssetFact {
|
|
370
|
+
specifier: string;
|
|
371
|
+
assetKind: 'style' | 'json' | 'image' | 'font' | 'other';
|
|
372
|
+
confidence: FactConfidence;
|
|
373
|
+
}
|
|
374
|
+
|
|
375
|
+
export interface ParsedFileSummary {
|
|
376
|
+
relPath: string;
|
|
377
|
+
language: ModuleLanguage;
|
|
378
|
+
loc: number;
|
|
379
|
+
imports: ImportFact[];
|
|
380
|
+
exports: ExportFact[];
|
|
381
|
+
runtimeFacts: RuntimeFact[];
|
|
382
|
+
frameworkFacts: FrameworkFact[];
|
|
383
|
+
routeFacts: RouteFact[];
|
|
384
|
+
stateFacts: StateFact[];
|
|
385
|
+
assetFacts: AssetFact[];
|
|
386
|
+
limitations: string[];
|
|
387
|
+
}
|
|
388
|
+
|
|
389
|
+
export interface ParsedFile {
|
|
390
|
+
relPath: string;
|
|
391
|
+
language: ModuleLanguage;
|
|
392
|
+
loc: number;
|
|
393
|
+
exports: string[];
|
|
394
|
+
imports: RawImport[];
|
|
395
|
+
summary?: ParsedFileSummary;
|
|
396
|
+
hasDefineStore: boolean;
|
|
397
|
+
/**
|
|
398
|
+
* Top-of-file directive prologue (`'use server'` / `'use client'`).
|
|
399
|
+
* Empty when none. Order-preserving for first-wins resolution.
|
|
400
|
+
*/
|
|
401
|
+
directives?: ('use server' | 'use client')[];
|
|
402
|
+
/** PascalCase component tags from <template>, resolved against the component registry in buildGraph. */
|
|
403
|
+
templateRefs?: string[];
|
|
404
|
+
}
|
|
405
|
+
|
|
406
|
+
export type SignalSeverity = 'info' | 'low' | 'medium' | 'high' | 'critical';
|
|
407
|
+
export type SignalConfidence = FactConfidence;
|
|
408
|
+
export type SignalActionability = 'none' | 'manual' | 'guided' | 'safe-fix';
|
|
409
|
+
export type SignalStatus = 'new' | 'existing' | 'regressed' | 'resolved';
|
|
410
|
+
export type SignalMaturity = 'experimental' | 'beta' | 'stable';
|
|
411
|
+
|
|
412
|
+
export interface SignalEvidence {
|
|
413
|
+
kind:
|
|
414
|
+
| 'cycle'
|
|
415
|
+
| 'contract'
|
|
416
|
+
| 'bundle'
|
|
417
|
+
| 'temporal'
|
|
418
|
+
| 'memory'
|
|
419
|
+
| 'async-lifecycle'
|
|
420
|
+
| 'metric'
|
|
421
|
+
| 'layer'
|
|
422
|
+
| 'parser-fact'
|
|
423
|
+
| 'heuristic';
|
|
424
|
+
message: string;
|
|
425
|
+
modules?: ModuleId[];
|
|
426
|
+
confidence: SignalConfidence;
|
|
427
|
+
source?: string;
|
|
428
|
+
}
|
|
429
|
+
|
|
430
|
+
export type MemoryRiskKind =
|
|
431
|
+
| 'event-listener-cleanup'
|
|
432
|
+
| 'timer-cleanup'
|
|
433
|
+
| 'observer-cleanup'
|
|
434
|
+
| 'object-url-cleanup'
|
|
435
|
+
| 'subscription-cleanup';
|
|
436
|
+
|
|
437
|
+
export interface MemoryRiskEvidence {
|
|
438
|
+
message: string;
|
|
439
|
+
line?: number;
|
|
440
|
+
acquire: string;
|
|
441
|
+
expectedCleanup: string;
|
|
442
|
+
}
|
|
443
|
+
|
|
444
|
+
export interface MemoryRiskFinding {
|
|
445
|
+
id: string;
|
|
446
|
+
kind: MemoryRiskKind;
|
|
447
|
+
moduleId: ModuleId;
|
|
448
|
+
framework?: DetectedFramework;
|
|
449
|
+
severity: 'low' | 'medium';
|
|
450
|
+
confidence: FactConfidence;
|
|
451
|
+
evidence: MemoryRiskEvidence[];
|
|
452
|
+
remediation: string;
|
|
453
|
+
}
|
|
454
|
+
|
|
455
|
+
export type AsyncLifecycleRiskKind = 'async-effect-cleanup';
|
|
456
|
+
|
|
457
|
+
export interface AsyncLifecycleRiskEvidence {
|
|
458
|
+
message: string;
|
|
459
|
+
line?: number;
|
|
460
|
+
asyncSource: string;
|
|
461
|
+
expectedGuard: string;
|
|
462
|
+
}
|
|
463
|
+
|
|
464
|
+
export interface AsyncLifecycleRiskFinding {
|
|
465
|
+
id: string;
|
|
466
|
+
kind: AsyncLifecycleRiskKind;
|
|
467
|
+
moduleId: ModuleId;
|
|
468
|
+
framework?: DetectedFramework;
|
|
469
|
+
severity: 'low' | 'medium';
|
|
470
|
+
confidence: FactConfidence;
|
|
471
|
+
evidence: AsyncLifecycleRiskEvidence[];
|
|
472
|
+
remediation: string;
|
|
473
|
+
}
|
|
474
|
+
|
|
475
|
+
export interface SignalLifecycle {
|
|
476
|
+
status: SignalStatus;
|
|
477
|
+
firstSeenAt?: string;
|
|
478
|
+
lastSeenAt?: string;
|
|
479
|
+
baselineKey?: string;
|
|
480
|
+
}
|
|
481
|
+
|
|
482
|
+
export interface Suppression {
|
|
483
|
+
stableKey: string;
|
|
484
|
+
reason: string;
|
|
485
|
+
scope?: 'project' | 'module' | 'rule';
|
|
486
|
+
moduleId?: ModuleId;
|
|
487
|
+
createdAt?: string;
|
|
488
|
+
expiresAt?: string;
|
|
489
|
+
status?: 'active' | 'expired' | 'stale';
|
|
490
|
+
}
|
|
491
|
+
|
|
492
|
+
export interface SignalRanking {
|
|
493
|
+
score: number;
|
|
494
|
+
reasons: string[];
|
|
495
|
+
noisePenalty: number;
|
|
496
|
+
noveltyBoost: number;
|
|
497
|
+
}
|
|
498
|
+
|
|
499
|
+
export interface ArchitectureSignal {
|
|
500
|
+
id: string;
|
|
501
|
+
stableKey: string;
|
|
502
|
+
kind: string;
|
|
503
|
+
title: string;
|
|
504
|
+
severity: SignalSeverity;
|
|
505
|
+
confidence: SignalConfidence;
|
|
506
|
+
actionability: SignalActionability;
|
|
507
|
+
status: SignalStatus;
|
|
508
|
+
maturity: SignalMaturity;
|
|
509
|
+
modules: ModuleId[];
|
|
510
|
+
evidence: SignalEvidence[];
|
|
511
|
+
limitations: string[];
|
|
512
|
+
ranking: SignalRanking;
|
|
513
|
+
legacyRecommendationId?: string;
|
|
514
|
+
suppressed?: boolean;
|
|
515
|
+
suppressionReason?: string;
|
|
516
|
+
}
|
|
517
|
+
|
|
518
|
+
export interface ArchitectureInsight {
|
|
519
|
+
id: string;
|
|
520
|
+
title: string;
|
|
521
|
+
severity: SignalSeverity;
|
|
522
|
+
confidence: SignalConfidence;
|
|
523
|
+
signals: string[];
|
|
524
|
+
modules: ModuleId[];
|
|
525
|
+
rankingScore: number;
|
|
526
|
+
summary: string;
|
|
527
|
+
}
|
|
528
|
+
|
|
529
|
+
export type ScanPhase = 'discover' | 'parse' | 'graph' | 'cycles' | 'metrics' | 'done';
|
|
530
|
+
|
|
531
|
+
export interface ScanProgressEvent {
|
|
532
|
+
phase: ScanPhase;
|
|
533
|
+
current?: number;
|
|
534
|
+
total?: number;
|
|
535
|
+
}
|
|
536
|
+
|
|
537
|
+
export type ScanProgressCallback = (event: ScanProgressEvent) => void;
|