code-auditor-mcp 4.0.0 → 4.0.2
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/.claude-plugin/marketplace.json +1 -1
- package/CHANGELOG.md +80 -0
- package/dist/__tests__/fixtures/spec-52/item-04-storage-sql-exec-in-loop.d.ts.map +1 -1
- package/dist/__tests__/fixtures/spec-52/item-05-upsert-forms.d.ts +4 -4
- package/dist/__tests__/fixtures/spec-52/item-05-upsert-forms.d.ts.map +1 -1
- package/dist/analyzers/analyzerUtils.d.ts.map +1 -1
- package/dist/analyzers/analyzerUtils.js +2 -2
- package/dist/analyzers/analyzerUtils.js.map +1 -1
- package/dist/analyzers/applicability.d.ts +13 -0
- package/dist/analyzers/applicability.d.ts.map +1 -1
- package/dist/analyzers/applicability.js +1 -1
- package/dist/analyzers/applicability.js.map +1 -1
- package/dist/analyzers/cross-language/APIContractAnalyzer.d.ts.map +1 -1
- package/dist/analyzers/cross-language/DependencyGraphBuilder.d.ts +1 -1
- package/dist/analyzers/cross-language/DependencyGraphBuilder.d.ts.map +1 -1
- package/dist/analyzers/cross-language/DependencyGraphBuilder.js +3 -3
- package/dist/analyzers/cross-language/DependencyGraphBuilder.js.map +1 -1
- package/dist/analyzers/cross-language/SchemaValidator.d.ts.map +1 -1
- package/dist/analyzers/cross-language/SchemaValidator.js.map +1 -1
- package/dist/analyzers/crossDomain/CrossDomainAnalyzer.d.ts +1 -1
- package/dist/analyzers/crossDomain/CrossDomainAnalyzer.d.ts.map +1 -1
- package/dist/analyzers/crossDomain/CrossDomainAnalyzer.js +28 -7
- package/dist/analyzers/crossDomain/CrossDomainAnalyzer.js.map +1 -1
- package/dist/analyzers/documentationAnalyzer.js +5 -5
- package/dist/analyzers/documentationAnalyzer.js.map +1 -1
- package/dist/analyzers/orm/adapterRegistry.d.ts.map +1 -1
- package/dist/analyzers/orm/drizzleAdapter.d.ts.map +1 -1
- package/dist/analyzers/orm/prismaAdapter.d.ts.map +1 -1
- package/dist/analyzers/provenance.d.ts +10 -1
- package/dist/analyzers/provenance.d.ts.map +1 -1
- package/dist/analyzers/provenance.js +138 -1
- package/dist/analyzers/provenance.js.map +1 -1
- package/dist/analyzers/reactAnalyzer.js +8 -8
- package/dist/analyzers/reactAnalyzer.js.map +1 -1
- package/dist/analyzers/ruleRegistry.js +2 -2
- package/dist/analyzers/ruleRegistry.js.map +1 -1
- package/dist/analyzers/universal/UniversalConventionsAnalyzer.d.ts +2 -2
- package/dist/analyzers/universal/UniversalConventionsAnalyzer.d.ts.map +1 -1
- package/dist/analyzers/universal/UniversalConventionsAnalyzer.js +7 -7
- package/dist/analyzers/universal/UniversalConventionsAnalyzer.js.map +1 -1
- package/dist/analyzers/universal/UniversalDRYAnalyzer.d.ts +4 -4
- package/dist/analyzers/universal/UniversalDRYAnalyzer.d.ts.map +1 -1
- package/dist/analyzers/universal/UniversalDRYAnalyzer.js +10 -10
- package/dist/analyzers/universal/UniversalDRYAnalyzer.js.map +1 -1
- package/dist/analyzers/universal/UniversalDataAccessAnalyzer.d.ts.map +1 -1
- package/dist/analyzers/universal/UniversalDataAccessAnalyzer.js +283 -39
- package/dist/analyzers/universal/UniversalDataAccessAnalyzer.js.map +1 -1
- package/dist/analyzers/universal/UniversalDocumentationAnalyzer.d.ts +1 -1
- package/dist/analyzers/universal/UniversalDocumentationAnalyzer.d.ts.map +1 -1
- package/dist/analyzers/universal/UniversalDocumentationAnalyzer.js +7 -7
- package/dist/analyzers/universal/UniversalDocumentationAnalyzer.js.map +1 -1
- package/dist/analyzers/universal/UniversalSOLIDAnalyzer.d.ts +18 -0
- package/dist/analyzers/universal/UniversalSOLIDAnalyzer.d.ts.map +1 -1
- package/dist/analyzers/universal/UniversalSOLIDAnalyzer.js +57 -11
- package/dist/analyzers/universal/UniversalSOLIDAnalyzer.js.map +1 -1
- package/dist/analyzers/universal/UniversalSchemaAnalyzer.d.ts.map +1 -1
- package/dist/analyzers/universal/UniversalSchemaAnalyzer.js +1 -0
- package/dist/analyzers/universal/UniversalSchemaAnalyzer.js.map +1 -1
- package/dist/analyzers/universal/UniversalSecretsAnalyzer.d.ts.map +1 -1
- package/dist/analyzers/universal/UniversalStylesAnalyzer.d.ts +1 -1
- package/dist/analyzers/universal/UniversalStylesAnalyzer.d.ts.map +1 -1
- package/dist/analyzers/universal/UniversalStylesAnalyzer.js +66 -31
- package/dist/analyzers/universal/UniversalStylesAnalyzer.js.map +1 -1
- package/dist/analyzers/universal/schema/codeAnalysis.d.ts +21 -21
- package/dist/analyzers/universal/schema/codeAnalysis.d.ts.map +1 -1
- package/dist/analyzers/universal/schema/codeAnalysis.js +199 -45
- package/dist/analyzers/universal/schema/codeAnalysis.js.map +1 -1
- package/dist/analyzers/universal/schema/config.d.ts +6 -6
- package/dist/analyzers/universal/schema/config.d.ts.map +1 -1
- package/dist/analyzers/universal/schema/jsonSchema.js +1 -1
- package/dist/analyzers/universal/schema/jsonSchema.js.map +1 -1
- package/dist/analyzers/universal/schema/types.d.ts +10 -0
- package/dist/analyzers/universal/schema/types.d.ts.map +1 -1
- package/dist/analyzers/universal/schema/violations.d.ts +1 -1
- package/dist/analyzers/universal/schema/violations.d.ts.map +1 -1
- package/dist/auditRouter.js +2 -2
- package/dist/auditRouter.js.map +1 -1
- package/dist/auditRunner.d.ts +1 -1
- package/dist/auditRunner.d.ts.map +1 -1
- package/dist/auditRunner.js +46 -13
- package/dist/auditRunner.js.map +1 -1
- package/dist/churn/churnExtractor.js.map +1 -1
- package/dist/cli.js +93 -28
- package/dist/cli.js.map +1 -1
- package/dist/codeIndexDB.d.ts.map +1 -1
- package/dist/codeIndexDB.js +19 -3
- package/dist/codeIndexDB.js.map +1 -1
- package/dist/codeIndexService.d.ts.map +1 -1
- package/dist/codeIndexService.js.map +1 -1
- package/dist/componentScanner.js.map +1 -1
- package/dist/config/configLoader.js +1 -1
- package/dist/config/configLoader.js.map +1 -1
- package/dist/config/defaults.d.ts +2 -2
- package/dist/config/defaults.d.ts.map +1 -1
- package/dist/config/defaults.js +10 -3
- package/dist/config/defaults.js.map +1 -1
- package/dist/constants.d.ts +1 -1
- package/dist/conventions/conventionMiner.js.map +1 -1
- package/dist/coverage/lcovParser.js.map +1 -1
- package/dist/daemon/args.js.map +1 -1
- package/dist/daemon/core.d.ts.map +1 -1
- package/dist/daemon/core.js +18 -9
- package/dist/daemon/core.js.map +1 -1
- package/dist/daemon/lspServer.d.ts.map +1 -1
- package/dist/daemon/lspServer.js +1 -1
- package/dist/daemon/lspServer.js.map +1 -1
- package/dist/daemon/main.js.map +1 -1
- package/dist/daemon/resolve.js.map +1 -1
- package/dist/daemon/socketServer.d.ts.map +1 -1
- package/dist/enforcement/gate.js +2 -2
- package/dist/functionScanner.d.ts.map +1 -1
- package/dist/generators/AWSQConfigGenerator.d.ts.map +1 -1
- package/dist/generators/AiderConfigGenerator.d.ts.map +1 -1
- package/dist/generators/BaseConfigGenerator.d.ts.map +1 -1
- package/dist/generators/BaseConfigGenerator.js.map +1 -1
- package/dist/generators/ClaudeConfigGenerator.d.ts.map +1 -1
- package/dist/generators/ClineConfigGenerator.d.ts.map +1 -1
- package/dist/generators/CodeiumConfigGenerator.d.ts.map +1 -1
- package/dist/generators/CodexConfigGenerator.d.ts.map +1 -1
- package/dist/generators/ConfigGeneratorFactory.d.ts.map +1 -1
- package/dist/generators/ConfigGeneratorFactory.js.map +1 -1
- package/dist/generators/ContinueConfigGenerator.d.ts.map +1 -1
- package/dist/generators/CopilotConfigGenerator.d.ts.map +1 -1
- package/dist/generators/CursorConfigGenerator.d.ts.map +1 -1
- package/dist/generators/GeminiConfigGenerator.d.ts.map +1 -1
- package/dist/generators/JetBrainsConfigGenerator.d.ts.map +1 -1
- package/dist/generators/VSCodeConfigGenerator.d.ts.map +1 -1
- package/dist/generators/ZCodeConfigGenerator.d.ts.map +1 -1
- package/dist/graph/importClassification.d.ts +46 -8
- package/dist/graph/importClassification.d.ts.map +1 -1
- package/dist/graph/importClassification.js +207 -35
- package/dist/graph/importClassification.js.map +1 -1
- package/dist/graph/outputFormatter.js.map +1 -1
- package/dist/hooks/codex.d.ts.map +1 -1
- package/dist/hooks/codex.js +1 -1
- package/dist/hooks/codex.js.map +1 -1
- package/dist/hooks/core.d.ts +1 -1
- package/dist/hooks/core.d.ts.map +1 -1
- package/dist/hooks/core.js +4 -4
- package/dist/hooks/core.js.map +1 -1
- package/dist/hooks/cursor.d.ts.map +1 -1
- package/dist/hooks/cursor.js +2 -2
- package/dist/hooks/cursor.js.map +1 -1
- package/dist/index.d.ts.map +1 -1
- package/dist/installer.js.map +1 -1
- package/dist/invariants/invariant-rules.schema.json +1 -1
- package/dist/invariants/ruleEngine.js.map +1 -1
- package/dist/invariants/ruleValidator.js +1 -1
- package/dist/invariants/ruleValidator.js.map +1 -1
- package/dist/invariants/types.d.ts +1 -1
- package/dist/invariants/types.d.ts.map +1 -1
- package/dist/languages/LanguageOrchestrator.d.ts +2 -2
- package/dist/languages/LanguageOrchestrator.d.ts.map +1 -1
- package/dist/languages/LanguageOrchestrator.js.map +1 -1
- package/dist/languages/LanguageRegistry.d.ts.map +1 -1
- package/dist/languages/RuntimeManager.d.ts.map +1 -1
- package/dist/languages/RuntimeManager.js +2 -2
- package/dist/languages/RuntimeManager.js.map +1 -1
- package/dist/languages/UniversalAnalyzer.d.ts.map +1 -1
- package/dist/languages/UniversalAnalyzer.js.map +1 -1
- package/dist/languages/adapterBridge.js.map +1 -1
- package/dist/languages/go/GoAdapter.d.ts.map +1 -1
- package/dist/languages/go/GoAdapter.js.map +1 -1
- package/dist/languages/go/analyzer +0 -0
- package/dist/languages/go/analyzer-src/analyzer.go +3 -3
- package/dist/languages/go/analyzer-src/solid.go +5 -5
- package/dist/languages/goBinary.js.map +1 -1
- package/dist/languages/tree-sitter/TreeSitterCssAdapter.d.ts.map +1 -1
- package/dist/languages/tree-sitter/TreeSitterCssAdapter.js.map +1 -1
- package/dist/languages/tree-sitter/converter.js.map +1 -1
- package/dist/languages/tree-sitter/parser.js.map +1 -1
- package/dist/languages/types.d.ts +15 -0
- package/dist/languages/types.d.ts.map +1 -1
- package/dist/languages/typescript/TreeSitterTypeScriptAdapter.d.ts +11 -0
- package/dist/languages/typescript/TreeSitterTypeScriptAdapter.d.ts.map +1 -1
- package/dist/languages/typescript/TreeSitterTypeScriptAdapter.js +34 -0
- package/dist/languages/typescript/TreeSitterTypeScriptAdapter.js.map +1 -1
- package/dist/ledger.js +1 -1
- package/dist/ledger.js.map +1 -1
- package/dist/mcp-tools/projectTasks.d.ts +37 -37
- package/dist/mcp-tools/projectTasks.js +2 -2
- package/dist/mcp-tools/projectTasks.js.map +1 -1
- package/dist/mcp-tools/whitelistTools.d.ts +17 -17
- package/dist/mcp-tools/whitelistTools.d.ts.map +1 -1
- package/dist/mcp-tools/workflowGuide.js +3 -3
- package/dist/mcp-tools/workflowGuide.js.map +1 -1
- package/dist/mcp-tools-shared.d.ts.map +1 -1
- package/dist/mcp-tools-shared.js +13 -13
- package/dist/mcp-tools-shared.js.map +1 -1
- package/dist/mcp-ui-simple.js +6 -6
- package/dist/mcp-ui-simple.js.map +1 -1
- package/dist/mcp.js +14 -14
- package/dist/mcp.js.map +1 -1
- package/dist/mcpAuditJobs.js +7 -7
- package/dist/mcpAuditJobs.js.map +1 -1
- package/dist/mcpAutoIndex.js +1 -1
- package/dist/mcpAutoIndex.js.map +1 -1
- package/dist/mcpToolErrors.d.ts.map +1 -1
- package/dist/mcpToolErrors.js.map +1 -1
- package/dist/native-bootstrap.js.map +1 -1
- package/dist/nextFile.d.ts +2 -2
- package/dist/nextFile.d.ts.map +1 -1
- package/dist/nextFile.js +3 -3
- package/dist/nextFile.js.map +1 -1
- package/dist/nextFileIncremental.d.ts +9 -2
- package/dist/nextFileIncremental.d.ts.map +1 -1
- package/dist/nextFileIncremental.js +41 -23
- package/dist/nextFileIncremental.js.map +1 -1
- package/dist/pipeline.d.ts +2 -2
- package/dist/pipeline.d.ts.map +1 -1
- package/dist/pipeline.js +45 -0
- package/dist/pipeline.js.map +1 -1
- package/dist/pipelineAdapters.d.ts +39 -2
- package/dist/pipelineAdapters.d.ts.map +1 -1
- package/dist/pipelineAdapters.js +230 -29
- package/dist/pipelineAdapters.js.map +1 -1
- package/dist/reporting/csvReportGenerator.d.ts.map +1 -1
- package/dist/reporting/csvReportGenerator.js +6 -6
- package/dist/reporting/csvReportGenerator.js.map +1 -1
- package/dist/reporting/htmlReportGenerator.d.ts.map +1 -1
- package/dist/reporting/htmlReportGenerator.js +11 -11
- package/dist/reporting/htmlReportGenerator.js.map +1 -1
- package/dist/reporting/jsonReportGenerator.d.ts.map +1 -1
- package/dist/reporting/jsonReportGenerator.js +1 -1
- package/dist/reporting/jsonReportGenerator.js.map +1 -1
- package/dist/reporting/reportGenerator.d.ts.map +1 -1
- package/dist/reporting/sarifReportGenerator.d.ts.map +1 -1
- package/dist/reporting/sarifReportGenerator.js +1 -1
- package/dist/reporting/sarifReportGenerator.js.map +1 -1
- package/dist/reporting/sizeDistribution.d.ts +17 -0
- package/dist/reporting/sizeDistribution.d.ts.map +1 -0
- package/dist/reporting/sizeDistribution.js +93 -0
- package/dist/reporting/sizeDistribution.js.map +1 -0
- package/dist/scripts/benchmarkWorkers.js +1 -1
- package/dist/scripts/benchmarkWorkers.js.map +1 -1
- package/dist/search/QueryParser.d.ts.map +1 -1
- package/dist/search/QueryParser.js.map +1 -1
- package/dist/services/CodeMapGenerator.d.ts.map +1 -1
- package/dist/services/CodeMapGenerator.js.map +1 -1
- package/dist/services/ProjectTaskRepository.d.ts.map +1 -1
- package/dist/services/ProjectTaskRepository.js.map +1 -1
- package/dist/services/auditJobService.js.map +1 -1
- package/dist/services/fileAccounting.d.ts.map +1 -1
- package/dist/services/projectTaskHelpers.js.map +1 -1
- package/dist/services/whitelistService.d.ts.map +1 -1
- package/dist/sqlite/betterSqlite3.d.ts.map +1 -1
- package/dist/sqlite/betterSqlite3.js.map +1 -1
- package/dist/sqlite/nodeSqlite.d.ts.map +1 -1
- package/dist/sqlite/nodeSqlite.js.map +1 -1
- package/dist/structuralSignature.js.map +1 -1
- package/dist/styles/styleExtractor.js.map +1 -1
- package/dist/styles/styleIndexer.js.map +1 -1
- package/dist/styles/tailwindConfigLoader.js.map +1 -1
- package/dist/styles/tailwindProbe.d.ts.map +1 -1
- package/dist/styles/tailwindUtilityExpander.d.ts.map +1 -1
- package/dist/styles/tailwindUtilityExpander.js.map +1 -1
- package/dist/telemetry.d.ts +1 -1
- package/dist/telemetry.d.ts.map +1 -1
- package/dist/telemetry.js.map +1 -1
- package/dist/tool-registry.d.ts.map +1 -1
- package/dist/types/crossLanguage.d.ts +1 -1
- package/dist/types/crossLanguage.d.ts.map +1 -1
- package/dist/types.d.ts +99 -5
- package/dist/types.d.ts.map +1 -1
- package/dist/types.js +3 -3
- package/dist/types.js.map +1 -1
- package/dist/ui/InteractivePrompts.d.ts.map +1 -1
- package/dist/ui/InteractivePrompts.js.map +1 -1
- package/dist/utils/componentPatterns.js.map +1 -1
- package/dist/utils/fileDiscovery.js.map +1 -1
- package/dist/utils/jsDocParser.js.map +1 -1
- package/dist/version.generated.d.ts +1 -1
- package/dist/version.generated.js +1 -1
- package/dist/workers/auditWorker.js.map +1 -1
- package/package.json +4 -3
- package/plugin/.claude-plugin/plugin.json +1 -1
- package/plugin/skills/code-auditor/SKILL-RULE-KINDS.md +7 -7
- package/plugin/skills/code-auditor/SKILL.md +9 -9
- package/server.json +2 -2
|
@@ -15,8 +15,14 @@
|
|
|
15
15
|
* analyzer.analyze([]) with rawDb injected through config
|
|
16
16
|
* - Invariants: Stage 3 reducer — receives full file list, runs rule engine
|
|
17
17
|
*/
|
|
18
|
-
import type { Stage2Visitor, Stage3Reducer, Stage4Reducer, Violation } from './types.js';
|
|
19
|
-
|
|
18
|
+
import type { Stage2Visitor, Stage3Reducer, Stage4Reducer, Violation, TestCoverageReport, DeadCluster } from './types.js';
|
|
19
|
+
import type { SizeSample } from './analyzers/universal/UniversalSOLIDAnalyzer.js';
|
|
20
|
+
export interface SolidVisitorBundle {
|
|
21
|
+
visitor: Stage2Visitor;
|
|
22
|
+
/** Spec 60 R2 — extract the raw size readings accumulated by the SOLID analyzer. */
|
|
23
|
+
getSizeSamples: () => Promise<SizeSample[]>;
|
|
24
|
+
}
|
|
25
|
+
export declare function createSolidVisitor(): SolidVisitorBundle;
|
|
20
26
|
export interface DryVisitorBundle {
|
|
21
27
|
visitor: Stage2Visitor;
|
|
22
28
|
/** Extract accumulated dryPairs after the pipeline finishes stage 2. */
|
|
@@ -105,7 +111,37 @@ export declare function createConventionsReducer(): Stage3Reducer;
|
|
|
105
111
|
* Uses analyzer.analyze([]) with rawDb injected.
|
|
106
112
|
*/
|
|
107
113
|
export declare function createCrossDomainReducer(): Stage4Reducer;
|
|
114
|
+
interface ClFileInfo {
|
|
115
|
+
imports: string[];
|
|
116
|
+
hasExports: boolean;
|
|
117
|
+
/** Dynamic `import()`/`require()` calls whose specifier is computed (not a
|
|
118
|
+
* static string) and therefore cannot be resolved into an import edge. */
|
|
119
|
+
unresolvedDynamicImports: Array<{
|
|
120
|
+
line: number;
|
|
121
|
+
expression: string;
|
|
122
|
+
}>;
|
|
123
|
+
}
|
|
108
124
|
export declare function createCrossLanguageEntityVisitor(): Stage2Visitor;
|
|
125
|
+
/**
|
|
126
|
+
* Spec 60 R1 — classify every non-test source module as `tested`,
|
|
127
|
+
* `untested-live`, or `untested-dead` off the file-level import edges
|
|
128
|
+
* (`importersOf`), not `function_dependencies`.
|
|
129
|
+
*
|
|
130
|
+
* A module is `tested` when a test file imports it *directly* (the edge set is
|
|
131
|
+
* alias-aware — built by `clResolveImport` through `classifyImportSpecifier`).
|
|
132
|
+
* `untested-dead` is the *post*-exception dead bucket: a file imported by
|
|
133
|
+
* nothing *and* not a framework entry point. `deadPreException` is the
|
|
134
|
+
* empty-importers count before the entry-point exception, so the drop
|
|
135
|
+
* (`deadPreException - untestedDead`) attributes the entry points exempted.
|
|
136
|
+
*/
|
|
137
|
+
export declare function classifyTestCoverage(fileFacts: Map<string, ClFileInfo>, importersOf: Map<string, Set<string>>, packageEntrySet: ReadonlySet<string>): TestCoverageReport;
|
|
138
|
+
/**
|
|
139
|
+
* Spec 60 R3 — group unreferenced modules by basename, surfacing the pattern of
|
|
140
|
+
* the same file name appearing in several sibling directories (e.g. two
|
|
141
|
+
* `ErrorState.tsx`, three `services.ts` under separate `reports` folders). Only
|
|
142
|
+
* basenames with ≥2 files become clusters; a singleton dead file is not a duplicate.
|
|
143
|
+
*/
|
|
144
|
+
export declare function clusterDeadModules(deadFiles: string[]): DeadCluster[];
|
|
109
145
|
export declare function createSchemaValidatorReducer(): Stage4Reducer;
|
|
110
146
|
export declare function createAPIContractReducer(): Stage4Reducer;
|
|
111
147
|
export declare function createDependencyGraphReducer(): Stage4Reducer;
|
|
@@ -141,4 +177,5 @@ export declare function createSchemaJsonVisitor(): Stage2Visitor;
|
|
|
141
177
|
* Builds the complete known-tables catalog and checks all table references against it.
|
|
142
178
|
*/
|
|
143
179
|
export declare function createSchemaReducer(): Stage3Reducer;
|
|
180
|
+
export {};
|
|
144
181
|
//# sourceMappingURL=pipelineAdapters.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"pipelineAdapters.d.ts","sourceRoot":"","sources":["../src/pipelineAdapters.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;GAgBG;AAKH,OAAO,KAAK,EAGV,aAAa,EACb,aAAa,EACb,aAAa,EACb,SAAS,
|
|
1
|
+
{"version":3,"file":"pipelineAdapters.d.ts","sourceRoot":"","sources":["../src/pipelineAdapters.ts"],"names":[],"mappings":"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"}
|
package/dist/pipelineAdapters.js
CHANGED
|
@@ -21,7 +21,6 @@ import { RULE_REGISTRY } from './analyzers/ruleRegistry.js';
|
|
|
21
21
|
import { TYPESCRIPT_EXTENSIONS, JAVASCRIPT_EXTENSIONS, getLanguageFromPath } from './utils/fileDiscovery.js';
|
|
22
22
|
import { walkAST, isExported, getNodeText, getFieldNode, getLineAndColumn, calculateComplexity, getFunctionBody, } from './languages/adapterBridge.js';
|
|
23
23
|
import { buildImportMap, extractFunctionCalls, } from './utils/dependencyExtractor.js';
|
|
24
|
-
import { resolveDependency, basenameNoExt } from './graph/importGraph.js';
|
|
25
24
|
import { classifyImportSpecifier, DEFAULT_VIRTUAL_MODULES } from './graph/importClassification.js';
|
|
26
25
|
import { isReactComponent, detectComponentType, getComponentName, } from './utils/reactDetection.js';
|
|
27
26
|
import { findTableReferences, checkNamingConventions, checkQueryPatterns, checkSQLInjection, checkUnresolvedQueries, getNearestTableSuggestions, } from './analyzers/universal/schema/codeAnalysis.js';
|
|
@@ -50,10 +49,9 @@ function lazySingleton(loader) {
|
|
|
50
49
|
return promise;
|
|
51
50
|
};
|
|
52
51
|
}
|
|
53
|
-
// ── SOLID visitor ────────────────────────────────────────────────────────────
|
|
54
52
|
export function createSolidVisitor() {
|
|
55
53
|
const getAnalyzer = lazySingleton(() => import('./analyzers/universal/UniversalSOLIDAnalyzer.js').then((m) => new m.UniversalSOLIDAnalyzer()));
|
|
56
|
-
|
|
54
|
+
const visitor = {
|
|
57
55
|
name: 'solid',
|
|
58
56
|
stage: 'visitor',
|
|
59
57
|
getRuleIds: () => getRuleIdsFor('solid'),
|
|
@@ -69,6 +67,18 @@ export function createSolidVisitor() {
|
|
|
69
67
|
description: 'Detects violations of SOLID principles',
|
|
70
68
|
category: 'architecture',
|
|
71
69
|
};
|
|
70
|
+
return {
|
|
71
|
+
visitor,
|
|
72
|
+
getSizeSamples: async () => {
|
|
73
|
+
try {
|
|
74
|
+
const a = await getAnalyzer();
|
|
75
|
+
return a.sizeSamples ?? [];
|
|
76
|
+
}
|
|
77
|
+
catch {
|
|
78
|
+
return [];
|
|
79
|
+
}
|
|
80
|
+
},
|
|
81
|
+
};
|
|
72
82
|
}
|
|
73
83
|
export function createDryVisitor(fullFunctionIndex) {
|
|
74
84
|
const getAnalyzer = lazySingleton(() => import('./analyzers/universal/UniversalDRYAnalyzer.js').then((m) => new m.UniversalDRYAnalyzer()));
|
|
@@ -408,6 +418,9 @@ export function createFunctionIndexVisitor() {
|
|
|
408
418
|
const { classification, resolvedPath } = classifyImportSpecifier(imp.source, filePath, corpusFiles, {
|
|
409
419
|
virtualModules,
|
|
410
420
|
aliasPatterns: tsconfigAliases?.pathPatterns ?? [],
|
|
421
|
+
pathMappings: tsconfigAliases?.paths ?? {},
|
|
422
|
+
baseUrl: tsconfigAliases?.baseUrl,
|
|
423
|
+
projectRoot: context.projectRoot,
|
|
411
424
|
});
|
|
412
425
|
indexFacts.push({
|
|
413
426
|
table: 'import_specifiers',
|
|
@@ -542,7 +555,7 @@ export function createReactVisitor() {
|
|
|
542
555
|
}
|
|
543
556
|
}
|
|
544
557
|
catch {
|
|
545
|
-
// Cross-component checks are
|
|
558
|
+
// Cross-component checks are high
|
|
546
559
|
}
|
|
547
560
|
return violations;
|
|
548
561
|
},
|
|
@@ -856,7 +869,12 @@ export function createStylesReducer() {
|
|
|
856
869
|
const factsConsumed = context.indexHandle.count('style_declarations')
|
|
857
870
|
+ context.indexHandle.count('style_tokens')
|
|
858
871
|
+ context.indexHandle.count('style_class_usage');
|
|
859
|
-
return {
|
|
872
|
+
return {
|
|
873
|
+
violations: result.violations ?? [],
|
|
874
|
+
facts: {},
|
|
875
|
+
factsConsumed,
|
|
876
|
+
...((result.diagnostics?.length ?? 0) > 0 && { diagnostics: result.diagnostics }),
|
|
877
|
+
};
|
|
860
878
|
}
|
|
861
879
|
catch {
|
|
862
880
|
return { violations: [], facts: {} };
|
|
@@ -1507,27 +1525,35 @@ function clIsEntryPointFile(fp) {
|
|
|
1507
1525
|
return true;
|
|
1508
1526
|
return false;
|
|
1509
1527
|
}
|
|
1528
|
+
/** Resolve one import specifier to zero or one internal file via the classifier. */
|
|
1529
|
+
function clResolveImport(dep, sourceFile, options) {
|
|
1530
|
+
const { classification, resolvedPath } = classifyImportSpecifier(dep, sourceFile, options.corpusFiles, {
|
|
1531
|
+
virtualModules: options.virtualModules,
|
|
1532
|
+
aliasPatterns: options.tsconfigAliases?.pathPatterns ?? [],
|
|
1533
|
+
pathMappings: options.tsconfigAliases?.paths ?? {},
|
|
1534
|
+
baseUrl: options.tsconfigAliases?.baseUrl,
|
|
1535
|
+
projectRoot: options.projectRoot,
|
|
1536
|
+
});
|
|
1537
|
+
if (classification === 'internal-resolved' && resolvedPath)
|
|
1538
|
+
return [resolvedPath];
|
|
1539
|
+
return [];
|
|
1540
|
+
}
|
|
1510
1541
|
/**
|
|
1511
1542
|
* Compute file-level reachability from per-file imports.
|
|
1512
1543
|
*
|
|
1513
1544
|
* A file is a framework entry point (live → 1.0), imported by another file
|
|
1514
|
-
* (live → 0.5), or referenced by nothing (dead → 0.0).
|
|
1515
|
-
*
|
|
1516
|
-
*
|
|
1545
|
+
* (live → 0.5), or referenced by nothing (dead → 0.0). Resolution goes through
|
|
1546
|
+
* `classifyImportSpecifier` (relative paths and tsconfig `paths` aliases like
|
|
1547
|
+
* `@/`) instead of the legacy basename/fuzzy matcher, so an alias import creates
|
|
1548
|
+
* a real edge and a bare package import never fabricates a local one.
|
|
1517
1549
|
*/
|
|
1518
|
-
function clComputeReachability(fileFacts) {
|
|
1550
|
+
function clComputeReachability(fileFacts, options) {
|
|
1519
1551
|
const filePaths = new Set(fileFacts.keys());
|
|
1520
|
-
const
|
|
1521
|
-
for (const fp of filePaths) {
|
|
1522
|
-
const bn = basenameNoExt(fp);
|
|
1523
|
-
if (!moduleToFile.has(bn))
|
|
1524
|
-
moduleToFile.set(bn, new Set());
|
|
1525
|
-
moduleToFile.get(bn).add(fp);
|
|
1526
|
-
}
|
|
1552
|
+
const packageEntries = options.packageEntryPoints ?? new Set();
|
|
1527
1553
|
const importersOf = new Map();
|
|
1528
1554
|
for (const [fp, info] of fileFacts) {
|
|
1529
1555
|
for (const dep of info.imports) {
|
|
1530
|
-
const targets =
|
|
1556
|
+
const targets = clResolveImport(dep, fp, options);
|
|
1531
1557
|
for (const t of targets) {
|
|
1532
1558
|
if (t === fp)
|
|
1533
1559
|
continue;
|
|
@@ -1539,12 +1565,106 @@ function clComputeReachability(fileFacts) {
|
|
|
1539
1565
|
}
|
|
1540
1566
|
const reachability = new Map();
|
|
1541
1567
|
for (const fp of filePaths) {
|
|
1542
|
-
const entry = clIsEntryPointFile(fp);
|
|
1568
|
+
const entry = clIsEntryPointFile(fp) || packageEntries.has(fp);
|
|
1543
1569
|
const imported = (importersOf.get(fp)?.size ?? 0) > 0;
|
|
1544
1570
|
reachability.set(fp, entry ? 1 : imported ? 0.5 : 0);
|
|
1545
1571
|
}
|
|
1546
1572
|
return { reachability, importersOf };
|
|
1547
1573
|
}
|
|
1574
|
+
/**
|
|
1575
|
+
* Spec 60 R1 — classify every non-test source module as `tested`,
|
|
1576
|
+
* `untested-live`, or `untested-dead` off the file-level import edges
|
|
1577
|
+
* (`importersOf`), not `function_dependencies`.
|
|
1578
|
+
*
|
|
1579
|
+
* A module is `tested` when a test file imports it *directly* (the edge set is
|
|
1580
|
+
* alias-aware — built by `clResolveImport` through `classifyImportSpecifier`).
|
|
1581
|
+
* `untested-dead` is the *post*-exception dead bucket: a file imported by
|
|
1582
|
+
* nothing *and* not a framework entry point. `deadPreException` is the
|
|
1583
|
+
* empty-importers count before the entry-point exception, so the drop
|
|
1584
|
+
* (`deadPreException - untestedDead`) attributes the entry points exempted.
|
|
1585
|
+
*/
|
|
1586
|
+
export function classifyTestCoverage(fileFacts, importersOf, packageEntrySet) {
|
|
1587
|
+
const result = {
|
|
1588
|
+
tested: 0,
|
|
1589
|
+
untestedLive: 0,
|
|
1590
|
+
untestedDead: 0,
|
|
1591
|
+
total: 0,
|
|
1592
|
+
deadPreException: 0,
|
|
1593
|
+
deadPostException: 0,
|
|
1594
|
+
deadDrop: 0,
|
|
1595
|
+
entryPointExemptions: [],
|
|
1596
|
+
testedFiles: [],
|
|
1597
|
+
untestedLiveFiles: [],
|
|
1598
|
+
untestedDeadFiles: [],
|
|
1599
|
+
};
|
|
1600
|
+
for (const fp of fileFacts.keys()) {
|
|
1601
|
+
if (clIsTestFile(fp))
|
|
1602
|
+
continue;
|
|
1603
|
+
result.total++;
|
|
1604
|
+
const importers = importersOf.get(fp);
|
|
1605
|
+
if (!importers || importers.size === 0) {
|
|
1606
|
+
// Imported by nothing — dead *unless* it is a framework entry point.
|
|
1607
|
+
result.deadPreException++;
|
|
1608
|
+
const isPackageEntry = packageEntrySet.has(fp);
|
|
1609
|
+
const isEntry = isPackageEntry || clIsEntryPointFile(fp);
|
|
1610
|
+
if (isEntry) {
|
|
1611
|
+
result.untestedLive++;
|
|
1612
|
+
result.untestedLiveFiles.push(fp);
|
|
1613
|
+
result.entryPointExemptions.push({
|
|
1614
|
+
file: fp,
|
|
1615
|
+
kind: isPackageEntry ? 'package-entry' : 'entry-point',
|
|
1616
|
+
});
|
|
1617
|
+
}
|
|
1618
|
+
else {
|
|
1619
|
+
result.untestedDead++;
|
|
1620
|
+
result.untestedDeadFiles.push(fp);
|
|
1621
|
+
}
|
|
1622
|
+
continue;
|
|
1623
|
+
}
|
|
1624
|
+
let hasTestImporter = false;
|
|
1625
|
+
for (const importer of importers) {
|
|
1626
|
+
if (clIsTestFile(importer)) {
|
|
1627
|
+
hasTestImporter = true;
|
|
1628
|
+
break;
|
|
1629
|
+
}
|
|
1630
|
+
}
|
|
1631
|
+
if (hasTestImporter) {
|
|
1632
|
+
result.tested++;
|
|
1633
|
+
result.testedFiles.push(fp);
|
|
1634
|
+
}
|
|
1635
|
+
else {
|
|
1636
|
+
result.untestedLive++;
|
|
1637
|
+
result.untestedLiveFiles.push(fp);
|
|
1638
|
+
}
|
|
1639
|
+
}
|
|
1640
|
+
result.deadPostException = result.untestedDead;
|
|
1641
|
+
result.deadDrop = result.deadPreException - result.untestedDead;
|
|
1642
|
+
return result;
|
|
1643
|
+
}
|
|
1644
|
+
/**
|
|
1645
|
+
* Spec 60 R3 — group unreferenced modules by basename, surfacing the pattern of
|
|
1646
|
+
* the same file name appearing in several sibling directories (e.g. two
|
|
1647
|
+
* `ErrorState.tsx`, three `services.ts` under separate `reports` folders). Only
|
|
1648
|
+
* basenames with ≥2 files become clusters; a singleton dead file is not a duplicate.
|
|
1649
|
+
*/
|
|
1650
|
+
export function clusterDeadModules(deadFiles) {
|
|
1651
|
+
const byBasename = new Map();
|
|
1652
|
+
for (const fp of deadFiles) {
|
|
1653
|
+
const segments = fp.replace(/\\/g, '/').split('/').filter(Boolean);
|
|
1654
|
+
const basename = segments[segments.length - 1] ?? fp;
|
|
1655
|
+
const list = byBasename.get(basename) ?? [];
|
|
1656
|
+
list.push(fp);
|
|
1657
|
+
byBasename.set(basename, list);
|
|
1658
|
+
}
|
|
1659
|
+
const clusters = [];
|
|
1660
|
+
for (const [basename, files] of byBasename) {
|
|
1661
|
+
if (files.length >= 2) {
|
|
1662
|
+
clusters.push({ basename, count: files.length, files });
|
|
1663
|
+
}
|
|
1664
|
+
}
|
|
1665
|
+
clusters.sort((a, b) => b.count - a.count || a.basename.localeCompare(b.basename));
|
|
1666
|
+
return clusters;
|
|
1667
|
+
}
|
|
1548
1668
|
/**
|
|
1549
1669
|
* Build `calls` cross-references by resolving each entity's extracted callee
|
|
1550
1670
|
* names against the corpus entity name index. Library calls (fetch, map, …)
|
|
@@ -1759,8 +1879,21 @@ export function createDependencyGraphReducer() {
|
|
|
1759
1879
|
}
|
|
1760
1880
|
// ── File-level reachability: unreferenced modules + ranking axis ──
|
|
1761
1881
|
const fileFacts = clFileFacts(allFacts);
|
|
1882
|
+
let testCoverage;
|
|
1883
|
+
let deadClusters = [];
|
|
1762
1884
|
if (fileFacts.size > 0) {
|
|
1763
|
-
|
|
1885
|
+
// `context.config` is the reducer's merged config (namespace + `_infra`);
|
|
1886
|
+
// a bare reducer context in a unit test omits it, so fall back to the
|
|
1887
|
+
// file facts themselves as the corpus and a no-alias classification.
|
|
1888
|
+
const infraConfig = (context.config ?? {});
|
|
1889
|
+
const packageEntrySet = new Set(infraConfig.packageEntryPoints ?? []);
|
|
1890
|
+
const { reachability, importersOf } = clComputeReachability(fileFacts, {
|
|
1891
|
+
corpusFiles: new Set(infraConfig.corpusFiles ?? [...fileFacts.keys()]),
|
|
1892
|
+
virtualModules: infraConfig.importVirtualModules ?? DEFAULT_VIRTUAL_MODULES,
|
|
1893
|
+
tsconfigAliases: infraConfig.tsconfigAliases,
|
|
1894
|
+
packageEntryPoints: packageEntrySet,
|
|
1895
|
+
projectRoot: context.projectRoot ?? '',
|
|
1896
|
+
});
|
|
1764
1897
|
// Persist reachability to graph_cache so the post-pipeline reorder
|
|
1765
1898
|
// (auditRunner hotspot block) can rank every finding by live/dead.
|
|
1766
1899
|
if (context.indexHandle?.rawDb) {
|
|
@@ -1781,19 +1914,44 @@ export function createDependencyGraphReducer() {
|
|
|
1781
1914
|
// neutral default without it.
|
|
1782
1915
|
}
|
|
1783
1916
|
}
|
|
1917
|
+
// Spec 60 R1 — persist the file-level import edges (reverse adjacency:
|
|
1918
|
+
// module → its direct importers) so "what tests exercise this module"
|
|
1919
|
+
// is answerable downstream from `importersOf`, not the symbol-level
|
|
1920
|
+
// `function_dependencies` table.
|
|
1921
|
+
if (context.indexHandle?.rawDb) {
|
|
1922
|
+
try {
|
|
1923
|
+
const db = context.indexHandle.rawDb;
|
|
1924
|
+
const del = db.prepare("DELETE FROM graph_cache WHERE graph_type = 'importers'");
|
|
1925
|
+
const ins = db.prepare("INSERT OR REPLACE INTO graph_cache (graph_type, node_key, neighbor_key, weight) VALUES ('importers', ?, ?, 1)");
|
|
1926
|
+
const tx = db.transaction(() => {
|
|
1927
|
+
del.run();
|
|
1928
|
+
for (const [fp, importers] of importersOf) {
|
|
1929
|
+
for (const importer of importers) {
|
|
1930
|
+
ins.run(fp, importer);
|
|
1931
|
+
}
|
|
1932
|
+
}
|
|
1933
|
+
});
|
|
1934
|
+
tx();
|
|
1935
|
+
}
|
|
1936
|
+
catch {
|
|
1937
|
+
// Importer-edge persistence is advisory, like reachability.
|
|
1938
|
+
}
|
|
1939
|
+
}
|
|
1784
1940
|
// Flag files that export symbols yet are imported by nothing and are
|
|
1785
1941
|
// not framework entry points — a dead module. This is the signal the
|
|
1786
1942
|
// orphaned-nodes check missed: a whole unreferenced file whose every
|
|
1787
1943
|
// internal symbol still forms a connected component.
|
|
1944
|
+
const deadModuleFiles = [];
|
|
1788
1945
|
for (const [fp, info] of fileFacts) {
|
|
1789
1946
|
if (!info.hasExports)
|
|
1790
1947
|
continue;
|
|
1791
1948
|
if (clIsTestFile(fp))
|
|
1792
1949
|
continue;
|
|
1793
|
-
if (clIsEntryPointFile(fp))
|
|
1950
|
+
if (clIsEntryPointFile(fp) || packageEntrySet.has(fp))
|
|
1794
1951
|
continue;
|
|
1795
1952
|
if ((importersOf.get(fp)?.size ?? 0) > 0)
|
|
1796
1953
|
continue;
|
|
1954
|
+
deadModuleFiles.push(fp);
|
|
1797
1955
|
violations.push({
|
|
1798
1956
|
file: fp,
|
|
1799
1957
|
line: 1,
|
|
@@ -1808,6 +1966,12 @@ export function createDependencyGraphReducer() {
|
|
|
1808
1966
|
details: { imports: info.imports },
|
|
1809
1967
|
});
|
|
1810
1968
|
}
|
|
1969
|
+
// Spec 60 R1 — classify each non-test module off the import edge set.
|
|
1970
|
+
testCoverage = classifyTestCoverage(fileFacts, importersOf, packageEntrySet);
|
|
1971
|
+
// Spec 60 R3 — cluster the unreferenced modules by basename so the
|
|
1972
|
+
// "dead-and-duplicated" pattern (same file name in sibling dirs) is
|
|
1973
|
+
// visible as a cluster rather than scattered one-per-file findings.
|
|
1974
|
+
deadClusters = clusterDeadModules(deadModuleFiles);
|
|
1811
1975
|
// Spec 58 R2 — computed-specifier dynamic imports. `import(someVar)`
|
|
1812
1976
|
// cannot be resolved into an edge, so any module in this corpus could
|
|
1813
1977
|
// be its target and `unreferenced-module` is therefore not exhaustive.
|
|
@@ -1828,15 +1992,15 @@ export function createDependencyGraphReducer() {
|
|
|
1828
1992
|
}
|
|
1829
1993
|
const HEALTH_SEVERITY = {
|
|
1830
1994
|
'break-cycles': 'severe',
|
|
1831
|
-
'reduce-coupling': '
|
|
1832
|
-
'split-responsibilities': '
|
|
1995
|
+
'reduce-coupling': 'high',
|
|
1996
|
+
'split-responsibilities': 'high',
|
|
1833
1997
|
'review-orphans': 'severe',
|
|
1834
1998
|
};
|
|
1835
1999
|
for (const s of health.suggestions) {
|
|
1836
2000
|
violations.push({
|
|
1837
2001
|
file: '(multiple)',
|
|
1838
2002
|
line: 0,
|
|
1839
|
-
severity: HEALTH_SEVERITY[s.type] ?? '
|
|
2003
|
+
severity: HEALTH_SEVERITY[s.type] ?? 'high',
|
|
1840
2004
|
message: s.description,
|
|
1841
2005
|
rule: s.type,
|
|
1842
2006
|
type: s.type,
|
|
@@ -1845,7 +2009,12 @@ export function createDependencyGraphReducer() {
|
|
|
1845
2009
|
details: s.affectedNodes ? { affectedNodes: s.affectedNodes } : undefined,
|
|
1846
2010
|
});
|
|
1847
2011
|
}
|
|
1848
|
-
|
|
2012
|
+
const facts = {};
|
|
2013
|
+
if (testCoverage)
|
|
2014
|
+
facts.testCoverage = testCoverage;
|
|
2015
|
+
if (deadClusters.length > 0)
|
|
2016
|
+
facts.deadClusters = deadClusters;
|
|
2017
|
+
return { violations, facts, factsConsumed: entities.length, ...(diagnostics.length > 0 && { diagnostics }) };
|
|
1849
2018
|
}
|
|
1850
2019
|
catch (e) {
|
|
1851
2020
|
console.error('[dependency-graph reducer] error:', e.message);
|
|
@@ -2093,6 +2262,7 @@ export function createSchemaCodeVisitor() {
|
|
|
2093
2262
|
line: usage.line,
|
|
2094
2263
|
column: usage.column,
|
|
2095
2264
|
raw_query: usage.rawQuery,
|
|
2265
|
+
origin: usage.origin ?? null,
|
|
2096
2266
|
},
|
|
2097
2267
|
});
|
|
2098
2268
|
}
|
|
@@ -2111,9 +2281,14 @@ export function createSchemaCodeVisitor() {
|
|
|
2111
2281
|
}
|
|
2112
2282
|
// Check SQL injection
|
|
2113
2283
|
violations.push(...checkSQLInjection(ast, adapter, sourceCode));
|
|
2114
|
-
// Emit facts for the Stage 3 reducer
|
|
2284
|
+
// Emit facts for the Stage 3 reducer. Fluent-builder references
|
|
2285
|
+
// (`origin: 'query-builder'`) are excluded from the unknown-table check:
|
|
2286
|
+
// a scratch/test table name carried by `db('t').select(...)` is not a
|
|
2287
|
+
// schema catalog miss, and feeding it in flips the 10:1 fail-open ratio.
|
|
2115
2288
|
const fileFacts = {
|
|
2116
|
-
tableRefs: tableRefs
|
|
2289
|
+
tableRefs: tableRefs
|
|
2290
|
+
.filter((r) => r.origin !== 'query-builder')
|
|
2291
|
+
.map((r) => ({
|
|
2117
2292
|
table: r.table,
|
|
2118
2293
|
type: r.type,
|
|
2119
2294
|
line: r.location.line,
|
|
@@ -2283,12 +2458,18 @@ export function createSchemaReducer() {
|
|
|
2283
2458
|
// Genuinely-new tables introduced by this migration (excludes rename/rebuild
|
|
2284
2459
|
// churn like `ALTER … RENAME TO x_old` + re-CREATE of the same name).
|
|
2285
2460
|
const createdHere = [];
|
|
2461
|
+
const createdTables = new Set();
|
|
2462
|
+
const droppedTables = new Set();
|
|
2286
2463
|
for (const op of sqlFile.ops) {
|
|
2464
|
+
const t = stripIdentifier(op.table);
|
|
2287
2465
|
if (op.op === 'CREATE') {
|
|
2288
|
-
|
|
2466
|
+
createdTables.add(t);
|
|
2289
2467
|
if (!before.has(t))
|
|
2290
2468
|
createdHere.push(t);
|
|
2291
2469
|
}
|
|
2470
|
+
else if (op.op === 'DROP') {
|
|
2471
|
+
droppedTables.add(t);
|
|
2472
|
+
}
|
|
2292
2473
|
}
|
|
2293
2474
|
for (const op of sqlFile.ops) {
|
|
2294
2475
|
const t = stripIdentifier(op.table);
|
|
@@ -2299,6 +2480,21 @@ export function createSchemaReducer() {
|
|
|
2299
2480
|
dropProvenance.delete(t);
|
|
2300
2481
|
}
|
|
2301
2482
|
}
|
|
2483
|
+
// A table created and dropped within this same file is a self-contained
|
|
2484
|
+
// fixture — a scratch table a test or script creates, uses, then tears
|
|
2485
|
+
// down. Its DROP is teardown, not a migration, so it must neither surface
|
|
2486
|
+
// as a stale-table-reference nor leave the name unknown: keep it known and
|
|
2487
|
+
// clear the drop provenance this file recorded for it. (A genuine dropped
|
|
2488
|
+
// table stays stale because its DROP lives in a migration that never also
|
|
2489
|
+
// CREATEs it — e.g. recall's `generation_queue`, dropped in 0198.)
|
|
2490
|
+
for (const t of createdTables) {
|
|
2491
|
+
if (droppedTables.has(t)) {
|
|
2492
|
+
knownTables.add(t);
|
|
2493
|
+
if (dropProvenance.get(t)?.migrationFile === sqlFile.filePath) {
|
|
2494
|
+
dropProvenance.delete(t);
|
|
2495
|
+
}
|
|
2496
|
+
}
|
|
2497
|
+
}
|
|
2302
2498
|
}
|
|
2303
2499
|
// 1b. ORM tables from code files — with provenance from the table-source registry
|
|
2304
2500
|
for (const [filePath, fact] of perFile()) {
|
|
@@ -2403,9 +2599,14 @@ export function createSchemaReducer() {
|
|
|
2403
2599
|
symbol: ref.table,
|
|
2404
2600
|
resolution: {
|
|
2405
2601
|
action: 'update-stale-reference',
|
|
2602
|
+
// The tables `created` are evidence the migration replaced the
|
|
2603
|
+
// dropped table, not proof of a drop-in successor — schemas can
|
|
2604
|
+
// be split or changed incompatibly, in which case the file must
|
|
2605
|
+
// be removed rather than updated. The summary names them as
|
|
2606
|
+
// context and leaves update-vs-remove to the reviewer.
|
|
2406
2607
|
summary: created.length > 0
|
|
2407
|
-
? `The table '${ref.table}' was dropped in ${migrationName}. That migration
|
|
2408
|
-
: `The table '${ref.table}' was dropped in ${migrationName} and not recreated — update or remove this reference.`,
|
|
2608
|
+
? `The table '${ref.table}' was dropped in ${migrationName}. That migration introduces ${joinEnglish(created)} — review this reference and update or remove it.`
|
|
2609
|
+
: `The table '${ref.table}' was dropped in ${migrationName} and was not recreated — update or remove this reference.`,
|
|
2409
2610
|
symbols: created.length > 0 ? created : [ref.table],
|
|
2410
2611
|
files: [ref.file],
|
|
2411
2612
|
lines: [ref.line],
|