lsp-intelligence 0.2.1 → 0.3.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 +18 -0
- package/.claude-plugin/plugin.json +11 -0
- package/CLAUDE.md +75 -0
- package/README.md +15 -38
- package/dist/adapters/express/index.d.ts +9 -0
- package/dist/adapters/express/index.js +46 -0
- package/dist/adapters/express/index.js.map +1 -0
- package/dist/adapters/next/index.d.ts +10 -0
- package/dist/adapters/next/index.js +67 -0
- package/dist/adapters/next/index.js.map +1 -0
- package/dist/adapters/react/index.d.ts +11 -0
- package/dist/adapters/react/index.js +133 -0
- package/dist/adapters/react/index.js.map +1 -0
- package/dist/adapters/registry.d.ts +22 -0
- package/dist/adapters/registry.js +101 -0
- package/dist/adapters/registry.js.map +1 -0
- package/dist/adapters/types.d.ts +97 -0
- package/dist/adapters/types.js +2 -0
- package/dist/adapters/types.js.map +1 -0
- package/dist/analysis/ts/applyVirtualEdit.d.ts +27 -0
- package/dist/analysis/ts/applyVirtualEdit.js +235 -0
- package/dist/analysis/ts/applyVirtualEdit.js.map +1 -0
- package/dist/analysis/ts/changeRecipes.d.ts +52 -0
- package/dist/analysis/ts/changeRecipes.js +14 -0
- package/dist/analysis/ts/changeRecipes.js.map +1 -0
- package/dist/analysis/ts/compatibility.d.ts +54 -0
- package/dist/analysis/ts/compatibility.js +113 -0
- package/dist/analysis/ts/compatibility.js.map +1 -0
- package/dist/analysis/ts/diffDeclarationShape.d.ts +26 -0
- package/dist/analysis/ts/diffDeclarationShape.js +114 -0
- package/dist/analysis/ts/diffDeclarationShape.js.map +1 -0
- package/dist/analysis/ts/exhaustiveness.d.ts +49 -0
- package/dist/analysis/ts/exhaustiveness.js +158 -0
- package/dist/analysis/ts/exhaustiveness.js.map +1 -0
- package/dist/analysis/ts/extractDeclarationShape.d.ts +30 -0
- package/dist/analysis/ts/extractDeclarationShape.js +127 -0
- package/dist/analysis/ts/extractDeclarationShape.js.map +1 -0
- package/dist/analysis/ts/extractExports.d.ts +19 -0
- package/dist/analysis/ts/extractExports.js +178 -0
- package/dist/analysis/ts/extractExports.js.map +1 -0
- package/dist/analysis/ts/extractRoutes.d.ts +12 -0
- package/dist/analysis/ts/extractRoutes.js +165 -0
- package/dist/analysis/ts/extractRoutes.js.map +1 -0
- package/dist/analysis/ts/parseSourceFile.d.ts +5 -1
- package/dist/analysis/ts/parseSourceFile.js +6 -2
- package/dist/analysis/ts/parseSourceFile.js.map +1 -1
- package/dist/analysis/ts/program/CheckerQueries.d.ts +56 -0
- package/dist/analysis/ts/program/CheckerQueries.js +187 -0
- package/dist/analysis/ts/program/CheckerQueries.js.map +1 -0
- package/dist/analysis/ts/program/ProgramManager.d.ts +27 -0
- package/dist/analysis/ts/program/ProgramManager.js +147 -0
- package/dist/analysis/ts/program/ProgramManager.js.map +1 -0
- package/dist/analysis/ts/program/TypeFacts.d.ts +58 -0
- package/dist/analysis/ts/program/TypeFacts.js +68 -0
- package/dist/analysis/ts/program/TypeFacts.js.map +1 -0
- package/dist/analysis/ts/typeState.d.ts +46 -0
- package/dist/analysis/ts/typeState.js +108 -0
- package/dist/analysis/ts/typeState.js.map +1 -0
- package/dist/ast/diffDeclarationShapes.js +25 -11
- package/dist/ast/diffDeclarationShapes.js.map +1 -1
- package/dist/ast/extractExportDeclarations.js +8 -3
- package/dist/ast/extractExportDeclarations.js.map +1 -1
- package/dist/cache/CacheSchema.d.ts +30 -0
- package/dist/cache/CacheSchema.js +9 -0
- package/dist/cache/CacheSchema.js.map +1 -0
- package/dist/cache/CacheStore.d.ts +22 -0
- package/dist/cache/CacheStore.js +111 -0
- package/dist/cache/CacheStore.js.map +1 -0
- package/dist/cache/SemanticCache.d.ts +38 -0
- package/dist/cache/SemanticCache.js +87 -0
- package/dist/cache/SemanticCache.js.map +1 -0
- package/dist/cache/SnapshotFingerprint.d.ts +17 -0
- package/dist/cache/SnapshotFingerprint.js +14 -0
- package/dist/cache/SnapshotFingerprint.js.map +1 -0
- package/dist/engine/DocumentManager.d.ts +16 -0
- package/dist/engine/DocumentManager.js +32 -0
- package/dist/engine/DocumentManager.js.map +1 -1
- package/dist/index.js +6 -0
- package/dist/index.js.map +1 -1
- package/dist/search/adapters/http.d.ts +9 -3
- package/dist/search/adapters/http.js +7 -52
- package/dist/search/adapters/http.js.map +1 -1
- package/dist/search/adapters/react.d.ts +8 -8
- package/dist/search/adapters/react.js +3 -88
- package/dist/search/adapters/react.js.map +1 -1
- package/dist/search/adapters/registry.d.ts +7 -4
- package/dist/search/adapters/registry.js +7 -17
- package/dist/search/adapters/registry.js.map +1 -1
- package/dist/search/expand/graphExpansion.js +47 -14
- package/dist/search/expand/graphExpansion.js.map +1 -1
- package/dist/search/index/declarationIndex.d.ts +3 -1
- package/dist/search/index/declarationIndex.js +4 -2
- package/dist/search/index/declarationIndex.js.map +1 -1
- package/dist/search/index/routeIndex.d.ts +6 -0
- package/dist/search/index/routeIndex.js +19 -0
- package/dist/search/index/routeIndex.js.map +1 -0
- package/dist/search/index/usageIndex.d.ts +3 -1
- package/dist/search/index/usageIndex.js +4 -2
- package/dist/search/index/usageIndex.js.map +1 -1
- package/dist/search/index/workspaceIndex.d.ts +7 -1
- package/dist/search/index/workspaceIndex.js +54 -14
- package/dist/search/index/workspaceIndex.js.map +1 -1
- package/dist/search/query/compileEffectiveSearchSpec.js +9 -0
- package/dist/search/query/compileEffectiveSearchSpec.js.map +1 -1
- package/dist/search/query/parseQuery.js +5 -1
- package/dist/search/query/parseQuery.js.map +1 -1
- package/dist/search/query/planQuery.js +14 -4
- package/dist/search/query/planQuery.js.map +1 -1
- package/dist/search/ranking/mergeCandidates.d.ts +1 -0
- package/dist/search/ranking/mergeCandidates.js +16 -0
- package/dist/search/ranking/mergeCandidates.js.map +1 -1
- package/dist/search/retrievers/routeRetriever.d.ts +7 -0
- package/dist/search/retrievers/routeRetriever.js +64 -0
- package/dist/search/retrievers/routeRetriever.js.map +1 -0
- package/dist/search/types.d.ts +16 -4
- package/dist/session/OverlayStore.d.ts +15 -0
- package/dist/session/OverlayStore.js +46 -0
- package/dist/session/OverlayStore.js.map +1 -0
- package/dist/session/SnapshotResolver.d.ts +31 -0
- package/dist/session/SnapshotResolver.js +50 -0
- package/dist/session/SnapshotResolver.js.map +1 -0
- package/dist/session/WorkspaceSnapshot.d.ts +21 -0
- package/dist/session/WorkspaceSnapshot.js +2 -0
- package/dist/session/WorkspaceSnapshot.js.map +1 -0
- package/dist/tools/composites/apiGuard.d.ts +4 -0
- package/dist/tools/composites/apiGuard.js +158 -24
- package/dist/tools/composites/apiGuard.js.map +1 -1
- package/dist/tools/composites/findCode.js +12 -2
- package/dist/tools/composites/findCode.js.map +1 -1
- package/dist/tools/composites/rootCauseTrace.js +89 -13
- package/dist/tools/composites/rootCauseTrace.js.map +1 -1
- package/dist/workflows/simulateChange.d.ts +44 -0
- package/dist/workflows/simulateChange.js +194 -0
- package/dist/workflows/simulateChange.js.map +1 -0
- package/dist/workflows/verifyChangeSet.d.ts +58 -0
- package/dist/workflows/verifyChangeSet.js +300 -0
- package/dist/workflows/verifyChangeSet.js.map +1 -0
- package/hooks/hooks.json +25 -0
- package/hooks/post-edit-check.sh +23 -0
- package/package.json +20 -4
- package/scripts/launch.mjs +29 -0
- package/skills/api-check/SKILL.md +34 -0
- package/skills/check/SKILL.md +25 -0
- package/skills/context/SKILL.md +24 -0
- package/skills/diff/SKILL.md +27 -0
- package/skills/find/SKILL.md +63 -0
- package/skills/impact/SKILL.md +21 -0
- package/skills/verify/SKILL.md +54 -0
- package/skills/why/SKILL.md +31 -0
|
@@ -0,0 +1,114 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Diff two declaration shapes and return a list of changes.
|
|
3
|
+
*/
|
|
4
|
+
export function diffDeclarationShapes(base, current) {
|
|
5
|
+
const diffs = [];
|
|
6
|
+
// Name changed
|
|
7
|
+
if (base.name !== current.name) {
|
|
8
|
+
diffs.push({ kind: 'renamed', risk: 'breaking', reason: `Renamed from "${base.name}" to "${current.name}"`, details: [`base: ${base.name}`, `current: ${current.name}`] });
|
|
9
|
+
}
|
|
10
|
+
// Params changed (functions)
|
|
11
|
+
if (base.params && current.params) {
|
|
12
|
+
// New params (required or optional)
|
|
13
|
+
for (const cp of current.params) {
|
|
14
|
+
const bp = base.params.find((p) => p.name === cp.name);
|
|
15
|
+
if (!bp && !cp.optional) {
|
|
16
|
+
diffs.push({ kind: 'param_required', risk: 'breaking', reason: `New required parameter "${cp.name}"`, details: [`param: ${cp.name}`, `type: ${cp.typeText ?? 'unknown'}`] });
|
|
17
|
+
}
|
|
18
|
+
else if (!bp && cp.optional) {
|
|
19
|
+
diffs.push({ kind: 'param_added', risk: 'safe', reason: `New optional parameter "${cp.name}"`, details: [`param: ${cp.name}`, `type: ${cp.typeText ?? 'unknown'}`] });
|
|
20
|
+
}
|
|
21
|
+
}
|
|
22
|
+
// Removed params
|
|
23
|
+
for (const bp of base.params) {
|
|
24
|
+
if (!current.params.find((p) => p.name === bp.name)) {
|
|
25
|
+
diffs.push({ kind: 'param_removed', risk: 'breaking', reason: `Parameter "${bp.name}" removed`, details: [`param: ${bp.name}`] });
|
|
26
|
+
}
|
|
27
|
+
}
|
|
28
|
+
// Optional → required
|
|
29
|
+
for (const cp of current.params) {
|
|
30
|
+
const bp = base.params.find((p) => p.name === cp.name);
|
|
31
|
+
if (bp && bp.optional && !cp.optional) {
|
|
32
|
+
diffs.push({ kind: 'param_required', risk: 'breaking', reason: `Parameter "${cp.name}" became required (was optional)`, details: [`param: ${cp.name}`] });
|
|
33
|
+
}
|
|
34
|
+
}
|
|
35
|
+
}
|
|
36
|
+
// Return type changed
|
|
37
|
+
if (base.returnTypeText && current.returnTypeText && base.returnTypeText !== current.returnTypeText) {
|
|
38
|
+
diffs.push({ kind: 'return_type_changed', risk: 'risky', reason: `Return type changed from "${base.returnTypeText}" to "${current.returnTypeText}"`, details: [`base: ${base.returnTypeText}`, `current: ${current.returnTypeText}`] });
|
|
39
|
+
}
|
|
40
|
+
// Interface members changed
|
|
41
|
+
if (base.members && current.members) {
|
|
42
|
+
const baseByName = new Map(base.members.map((m) => [m.name, m]));
|
|
43
|
+
const currentByName = new Map(current.members.map((m) => [m.name, m]));
|
|
44
|
+
for (const [name, cm] of currentByName) {
|
|
45
|
+
const bm = baseByName.get(name);
|
|
46
|
+
if (!bm) {
|
|
47
|
+
if (!cm.optional) {
|
|
48
|
+
diffs.push({ kind: 'interface_shape_changed', risk: 'breaking', reason: `Required interface property "${name}" added — breaking for existing implementations`, details: [`property: ${name}`, `type: ${cm.typeText ?? 'unknown'}`] });
|
|
49
|
+
}
|
|
50
|
+
else {
|
|
51
|
+
diffs.push({ kind: 'interface_shape_changed', risk: 'risky', reason: `Optional interface property "${name}" added`, details: [`property: ${name}`] });
|
|
52
|
+
}
|
|
53
|
+
}
|
|
54
|
+
else if (bm.optional && !cm.optional) {
|
|
55
|
+
diffs.push({ kind: 'interface_shape_changed', risk: 'breaking', reason: `Interface property "${name}" became required (was optional)`, details: [`property: ${name}`] });
|
|
56
|
+
}
|
|
57
|
+
}
|
|
58
|
+
for (const [name] of baseByName) {
|
|
59
|
+
if (!currentByName.has(name)) {
|
|
60
|
+
diffs.push({ kind: 'interface_shape_changed', risk: 'breaking', reason: `Interface property "${name}" removed`, details: [`property: ${name}`] });
|
|
61
|
+
}
|
|
62
|
+
}
|
|
63
|
+
}
|
|
64
|
+
// Enum members changed
|
|
65
|
+
if (base.enumMembers && current.enumMembers) {
|
|
66
|
+
const added = current.enumMembers.filter((m) => !base.enumMembers.includes(m));
|
|
67
|
+
const removed = base.enumMembers.filter((m) => !current.enumMembers.includes(m));
|
|
68
|
+
for (const m of added) {
|
|
69
|
+
diffs.push({ kind: 'enum_member_added', risk: 'risky', reason: `Enum member "${m}" added — exhaustive handling may be incomplete`, details: [m] });
|
|
70
|
+
}
|
|
71
|
+
for (const m of removed) {
|
|
72
|
+
diffs.push({ kind: 'enum_member_removed', risk: 'breaking', reason: `Enum member "${m}" removed`, details: [m] });
|
|
73
|
+
}
|
|
74
|
+
}
|
|
75
|
+
// Signature text changed (catch-all)
|
|
76
|
+
if (diffs.length === 0 && base.signatureText !== current.signatureText) {
|
|
77
|
+
diffs.push({ kind: 'signature_changed', risk: 'risky', reason: 'Declaration signature changed', details: [`base: ${base.signatureText}`, `current: ${current.signatureText}`] });
|
|
78
|
+
}
|
|
79
|
+
return diffs;
|
|
80
|
+
}
|
|
81
|
+
const RISK_ORDER = { breaking: 2, risky: 1, safe: 0 };
|
|
82
|
+
function worstRisk(diffs) {
|
|
83
|
+
return diffs.reduce((worst, d) => RISK_ORDER[d.risk] > RISK_ORDER[worst] ? d.risk : worst, 'safe');
|
|
84
|
+
}
|
|
85
|
+
/**
|
|
86
|
+
* Diff two sets of exports: find added, removed, and changed declarations.
|
|
87
|
+
* Each result includes risk, the originating shapes, and per-change diffs.
|
|
88
|
+
*/
|
|
89
|
+
export function diffExportSets(baseShapes, currentShapes) {
|
|
90
|
+
const results = [];
|
|
91
|
+
const baseByName = new Map(baseShapes.map((s) => [s.name, s]));
|
|
92
|
+
const currentByName = new Map(currentShapes.map((s) => [s.name, s]));
|
|
93
|
+
for (const [name, baseShape] of baseByName) {
|
|
94
|
+
if (!currentByName.has(name)) {
|
|
95
|
+
results.push({ name, status: 'removed', risk: 'breaking', diffs: [{ kind: 'removed', risk: 'breaking', reason: `Export "${name}" (${baseShape.kind}) was removed`, details: [] }], baseShape });
|
|
96
|
+
}
|
|
97
|
+
}
|
|
98
|
+
for (const [name, currentShape] of currentByName) {
|
|
99
|
+
if (!baseByName.has(name)) {
|
|
100
|
+
results.push({ name, status: 'added', risk: 'safe', diffs: [{ kind: 'added', risk: 'safe', reason: `New export "${name}" (${currentShape.kind})`, details: [] }], currentShape });
|
|
101
|
+
}
|
|
102
|
+
}
|
|
103
|
+
for (const [name, currentShape] of currentByName) {
|
|
104
|
+
const baseShape = baseByName.get(name);
|
|
105
|
+
if (baseShape) {
|
|
106
|
+
const diffs = diffDeclarationShapes(baseShape, currentShape);
|
|
107
|
+
if (diffs.length > 0) {
|
|
108
|
+
results.push({ name, status: 'changed', risk: worstRisk(diffs), diffs, baseShape, currentShape });
|
|
109
|
+
}
|
|
110
|
+
}
|
|
111
|
+
}
|
|
112
|
+
return results;
|
|
113
|
+
}
|
|
114
|
+
//# sourceMappingURL=diffDeclarationShape.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"diffDeclarationShape.js","sourceRoot":"","sources":["../../../src/analysis/ts/diffDeclarationShape.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
import ts from 'typescript';
|
|
2
|
+
/**
|
|
3
|
+
* Phase 2D — Switch exhaustiveness intelligence.
|
|
4
|
+
*
|
|
5
|
+
* Answers questions that a graph product cannot answer from structure alone:
|
|
6
|
+
* - "Which switches break if I add/remove this enum member?"
|
|
7
|
+
* - "Is this switch exhaustive over its enum?"
|
|
8
|
+
*
|
|
9
|
+
* Builds on the TypeScript checker (Phase 2C) for accurate type information.
|
|
10
|
+
*/
|
|
11
|
+
export interface SwitchExhaustivenessResult {
|
|
12
|
+
filePath: string;
|
|
13
|
+
/** 1-indexed line number of the switch keyword */
|
|
14
|
+
line: number;
|
|
15
|
+
/** Enum members that are explicitly handled in this switch */
|
|
16
|
+
handledMembers: string[];
|
|
17
|
+
/** Enum members NOT handled (and no default case covers them) */
|
|
18
|
+
missingMembers: string[];
|
|
19
|
+
/** True if there is a default case (covers missing members at runtime) */
|
|
20
|
+
hasDefaultCase: boolean;
|
|
21
|
+
/** Whether the switch is exhaustive — all members covered OR has default */
|
|
22
|
+
isExhaustive: boolean;
|
|
23
|
+
}
|
|
24
|
+
/**
|
|
25
|
+
* Find all non-exhaustive switch statements for a given enum across the program.
|
|
26
|
+
* "Non-exhaustive" means: missing at least one enum member AND no default case.
|
|
27
|
+
*
|
|
28
|
+
* This is the core "smarter than a graph" query: the TypeScript checker knows
|
|
29
|
+
* which type is being switched on, and we can verify coverage precisely.
|
|
30
|
+
*/
|
|
31
|
+
export declare function findNonExhaustiveSwitches(program: ts.Program, enumFilePath: string, enumName: string): SwitchExhaustivenessResult[];
|
|
32
|
+
/**
|
|
33
|
+
* Predict the exhaustiveness impact of adding a new enum member.
|
|
34
|
+
* Returns which switches would become non-exhaustive — i.e., they currently
|
|
35
|
+
* handle all members but would miss the new one.
|
|
36
|
+
*/
|
|
37
|
+
export declare function predictAddedMemberImpact(program: ts.Program, enumFilePath: string, enumName: string, newMemberName: string): {
|
|
38
|
+
affectedSwitches: Array<{
|
|
39
|
+
filePath: string;
|
|
40
|
+
line: number;
|
|
41
|
+
missingMember: string;
|
|
42
|
+
}>;
|
|
43
|
+
safeCount: number;
|
|
44
|
+
};
|
|
45
|
+
/**
|
|
46
|
+
* Get all switch exhaustiveness results for an enum, including exhaustive ones.
|
|
47
|
+
* Useful for a full picture: which files use this enum in a switch.
|
|
48
|
+
*/
|
|
49
|
+
export declare function getAllSwitchResults(program: ts.Program, enumFilePath: string, enumName: string): SwitchExhaustivenessResult[];
|
|
@@ -0,0 +1,158 @@
|
|
|
1
|
+
import ts from 'typescript';
|
|
2
|
+
/**
|
|
3
|
+
* Find all non-exhaustive switch statements for a given enum across the program.
|
|
4
|
+
* "Non-exhaustive" means: missing at least one enum member AND no default case.
|
|
5
|
+
*
|
|
6
|
+
* This is the core "smarter than a graph" query: the TypeScript checker knows
|
|
7
|
+
* which type is being switched on, and we can verify coverage precisely.
|
|
8
|
+
*/
|
|
9
|
+
export function findNonExhaustiveSwitches(program, enumFilePath, enumName) {
|
|
10
|
+
const checker = program.getTypeChecker();
|
|
11
|
+
const allMembers = getEnumMembers(program, enumFilePath, enumName);
|
|
12
|
+
if (!allMembers)
|
|
13
|
+
return [];
|
|
14
|
+
const results = [];
|
|
15
|
+
for (const sf of program.getSourceFiles()) {
|
|
16
|
+
if (sf.fileName.includes('node_modules') || sf.fileName.endsWith('.d.ts'))
|
|
17
|
+
continue;
|
|
18
|
+
ts.forEachChild(sf, function visitNode(node) {
|
|
19
|
+
if (ts.isSwitchStatement(node)) {
|
|
20
|
+
const result = analyzeSwitchForEnum(node, sf, checker, enumName, allMembers);
|
|
21
|
+
if (result)
|
|
22
|
+
results.push({ filePath: sf.fileName, ...result });
|
|
23
|
+
}
|
|
24
|
+
ts.forEachChild(node, visitNode);
|
|
25
|
+
});
|
|
26
|
+
}
|
|
27
|
+
return results.filter((r) => !r.isExhaustive);
|
|
28
|
+
}
|
|
29
|
+
/**
|
|
30
|
+
* Predict the exhaustiveness impact of adding a new enum member.
|
|
31
|
+
* Returns which switches would become non-exhaustive — i.e., they currently
|
|
32
|
+
* handle all members but would miss the new one.
|
|
33
|
+
*/
|
|
34
|
+
export function predictAddedMemberImpact(program, enumFilePath, enumName, newMemberName) {
|
|
35
|
+
const checker = program.getTypeChecker();
|
|
36
|
+
const currentMembers = getEnumMembers(program, enumFilePath, enumName);
|
|
37
|
+
if (!currentMembers)
|
|
38
|
+
return { affectedSwitches: [], safeCount: 0 };
|
|
39
|
+
const affectedSwitches = [];
|
|
40
|
+
let safeCount = 0;
|
|
41
|
+
for (const sf of program.getSourceFiles()) {
|
|
42
|
+
if (sf.fileName.includes('node_modules') || sf.fileName.endsWith('.d.ts'))
|
|
43
|
+
continue;
|
|
44
|
+
ts.forEachChild(sf, function visitNode(node) {
|
|
45
|
+
if (ts.isSwitchStatement(node)) {
|
|
46
|
+
const result = analyzeSwitchForEnum(node, sf, checker, enumName, currentMembers);
|
|
47
|
+
if (result && result.handledMembers.length > 0) {
|
|
48
|
+
// This switch uses the enum
|
|
49
|
+
if (!result.hasDefaultCase) {
|
|
50
|
+
// No default — adding a new member would make it non-exhaustive
|
|
51
|
+
affectedSwitches.push({ filePath: sf.fileName, line: result.line, missingMember: newMemberName });
|
|
52
|
+
}
|
|
53
|
+
else {
|
|
54
|
+
safeCount++;
|
|
55
|
+
}
|
|
56
|
+
}
|
|
57
|
+
}
|
|
58
|
+
ts.forEachChild(node, visitNode);
|
|
59
|
+
});
|
|
60
|
+
}
|
|
61
|
+
return { affectedSwitches, safeCount };
|
|
62
|
+
}
|
|
63
|
+
/**
|
|
64
|
+
* Get all switch exhaustiveness results for an enum, including exhaustive ones.
|
|
65
|
+
* Useful for a full picture: which files use this enum in a switch.
|
|
66
|
+
*/
|
|
67
|
+
export function getAllSwitchResults(program, enumFilePath, enumName) {
|
|
68
|
+
const checker = program.getTypeChecker();
|
|
69
|
+
const allMembers = getEnumMembers(program, enumFilePath, enumName);
|
|
70
|
+
if (!allMembers)
|
|
71
|
+
return [];
|
|
72
|
+
const results = [];
|
|
73
|
+
for (const sf of program.getSourceFiles()) {
|
|
74
|
+
if (sf.fileName.includes('node_modules') || sf.fileName.endsWith('.d.ts'))
|
|
75
|
+
continue;
|
|
76
|
+
ts.forEachChild(sf, function visitNode(node) {
|
|
77
|
+
if (ts.isSwitchStatement(node)) {
|
|
78
|
+
const result = analyzeSwitchForEnum(node, sf, checker, enumName, allMembers);
|
|
79
|
+
if (result)
|
|
80
|
+
results.push({ filePath: sf.fileName, ...result });
|
|
81
|
+
}
|
|
82
|
+
ts.forEachChild(node, visitNode);
|
|
83
|
+
});
|
|
84
|
+
}
|
|
85
|
+
return results;
|
|
86
|
+
}
|
|
87
|
+
// ---------------------------------------------------------------------------
|
|
88
|
+
// Internal helpers
|
|
89
|
+
// ---------------------------------------------------------------------------
|
|
90
|
+
function getEnumMembers(program, filePath, enumName) {
|
|
91
|
+
const sf = program.getSourceFile(filePath);
|
|
92
|
+
if (!sf)
|
|
93
|
+
return null;
|
|
94
|
+
let members = null;
|
|
95
|
+
ts.forEachChild(sf, (node) => {
|
|
96
|
+
if (ts.isEnumDeclaration(node) && node.name.text === enumName) {
|
|
97
|
+
members = node.members.map((m) => (ts.isIdentifier(m.name) ? m.name.text : m.name.getText(sf)));
|
|
98
|
+
}
|
|
99
|
+
});
|
|
100
|
+
return members;
|
|
101
|
+
}
|
|
102
|
+
function analyzeSwitchForEnum(node, sf, checker, enumName, allMembers) {
|
|
103
|
+
// Check if the switch expression uses the enum type
|
|
104
|
+
const switchType = checker.getTypeAtLocation(node.expression);
|
|
105
|
+
const typeSym = switchType.getSymbol() ?? switchType.aliasSymbol;
|
|
106
|
+
const typeStr = checker.typeToString(switchType);
|
|
107
|
+
const usesEnum = typeSym?.name === enumName || typeStr === enumName;
|
|
108
|
+
if (!usesEnum) {
|
|
109
|
+
// Also check if any case clause uses EnumName.Member pattern
|
|
110
|
+
const hasMemberAccess = hasCaseWithEnumAccess(node, enumName, allMembers, sf);
|
|
111
|
+
if (!hasMemberAccess)
|
|
112
|
+
return null;
|
|
113
|
+
}
|
|
114
|
+
const handled = new Set();
|
|
115
|
+
let hasDefaultCase = false;
|
|
116
|
+
for (const clause of node.caseBlock.clauses) {
|
|
117
|
+
if (ts.isDefaultClause(clause)) {
|
|
118
|
+
hasDefaultCase = true;
|
|
119
|
+
}
|
|
120
|
+
else if (ts.isCaseClause(clause)) {
|
|
121
|
+
const memberName = extractEnumMemberFromExpr(clause.expression, enumName, sf);
|
|
122
|
+
if (memberName && allMembers.includes(memberName)) {
|
|
123
|
+
handled.add(memberName);
|
|
124
|
+
}
|
|
125
|
+
}
|
|
126
|
+
}
|
|
127
|
+
if (handled.size === 0 && !hasDefaultCase)
|
|
128
|
+
return null; // Not actually using this enum
|
|
129
|
+
const missingMembers = allMembers.filter((m) => !handled.has(m));
|
|
130
|
+
const line = sf.getLineAndCharacterOfPosition(node.getStart(sf)).line + 1;
|
|
131
|
+
return {
|
|
132
|
+
line,
|
|
133
|
+
handledMembers: [...handled],
|
|
134
|
+
missingMembers,
|
|
135
|
+
hasDefaultCase,
|
|
136
|
+
isExhaustive: missingMembers.length === 0 || hasDefaultCase,
|
|
137
|
+
};
|
|
138
|
+
}
|
|
139
|
+
function extractEnumMemberFromExpr(expr, enumName, sf) {
|
|
140
|
+
if (ts.isPropertyAccessExpression(expr)) {
|
|
141
|
+
const obj = expr.expression;
|
|
142
|
+
if (ts.isIdentifier(obj) && obj.text === enumName) {
|
|
143
|
+
return expr.name.text;
|
|
144
|
+
}
|
|
145
|
+
}
|
|
146
|
+
return null;
|
|
147
|
+
}
|
|
148
|
+
function hasCaseWithEnumAccess(node, enumName, members, sf) {
|
|
149
|
+
for (const clause of node.caseBlock.clauses) {
|
|
150
|
+
if (ts.isCaseClause(clause)) {
|
|
151
|
+
const m = extractEnumMemberFromExpr(clause.expression, enumName, sf);
|
|
152
|
+
if (m && members.includes(m))
|
|
153
|
+
return true;
|
|
154
|
+
}
|
|
155
|
+
}
|
|
156
|
+
return false;
|
|
157
|
+
}
|
|
158
|
+
//# sourceMappingURL=exhaustiveness.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"exhaustiveness.js","sourceRoot":"","sources":["../../../src/analysis/ts/exhaustiveness.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
import ts from 'typescript';
|
|
2
|
+
import type { ExportedDeclaration } from './extractExports.js';
|
|
3
|
+
export interface ParamShape {
|
|
4
|
+
name: string;
|
|
5
|
+
optional: boolean;
|
|
6
|
+
rest: boolean;
|
|
7
|
+
typeText?: string;
|
|
8
|
+
}
|
|
9
|
+
export interface MemberShape {
|
|
10
|
+
name: string;
|
|
11
|
+
optional?: boolean;
|
|
12
|
+
typeText?: string;
|
|
13
|
+
}
|
|
14
|
+
export interface DeclarationShape {
|
|
15
|
+
name: string;
|
|
16
|
+
kind: ExportedDeclaration['kind'];
|
|
17
|
+
line: number;
|
|
18
|
+
signatureText: string;
|
|
19
|
+
params?: ParamShape[];
|
|
20
|
+
returnTypeText?: string;
|
|
21
|
+
members?: MemberShape[];
|
|
22
|
+
enumMembers?: string[];
|
|
23
|
+
exportedAs?: string[];
|
|
24
|
+
moduleSpecifier?: string;
|
|
25
|
+
}
|
|
26
|
+
/**
|
|
27
|
+
* Extract the shape of an exported declaration for diffing.
|
|
28
|
+
* Works on the TS AST node near the export's line.
|
|
29
|
+
*/
|
|
30
|
+
export declare function extractDeclarationShape(sf: ts.SourceFile, exp: ExportedDeclaration): DeclarationShape;
|
|
@@ -0,0 +1,127 @@
|
|
|
1
|
+
import ts from 'typescript';
|
|
2
|
+
/**
|
|
3
|
+
* Extract the shape of an exported declaration for diffing.
|
|
4
|
+
* Works on the TS AST node near the export's line.
|
|
5
|
+
*/
|
|
6
|
+
export function extractDeclarationShape(sf, exp) {
|
|
7
|
+
const base = {
|
|
8
|
+
name: exp.name,
|
|
9
|
+
kind: exp.kind,
|
|
10
|
+
line: exp.line,
|
|
11
|
+
signatureText: '',
|
|
12
|
+
exportedAs: exp.exportedAs,
|
|
13
|
+
moduleSpecifier: exp.moduleSpecifier,
|
|
14
|
+
};
|
|
15
|
+
// Find the node at the export's line
|
|
16
|
+
const node = findNodeAtLine(sf, exp.line - 1);
|
|
17
|
+
if (!node)
|
|
18
|
+
return { ...base, signatureText: `${exp.kind} ${exp.name}` };
|
|
19
|
+
// Function
|
|
20
|
+
if (ts.isFunctionDeclaration(node) || ts.isFunctionExpression(node) || ts.isArrowFunction(node)) {
|
|
21
|
+
base.params = extractParams(node);
|
|
22
|
+
base.returnTypeText = node.type ? node.type.getText(sf) : undefined;
|
|
23
|
+
base.signatureText = `function ${exp.name}(${formatParams(base.params)}): ${base.returnTypeText ?? 'unknown'}`;
|
|
24
|
+
return base;
|
|
25
|
+
}
|
|
26
|
+
// Method (inside class)
|
|
27
|
+
if (ts.isMethodDeclaration(node)) {
|
|
28
|
+
base.params = extractParams(node);
|
|
29
|
+
base.returnTypeText = node.type ? node.type.getText(sf) : undefined;
|
|
30
|
+
base.signatureText = `method ${exp.name}(${formatParams(base.params)})`;
|
|
31
|
+
return base;
|
|
32
|
+
}
|
|
33
|
+
// Interface
|
|
34
|
+
if (ts.isInterfaceDeclaration(node)) {
|
|
35
|
+
base.members = extractMembers(node, sf);
|
|
36
|
+
base.signatureText = `interface ${exp.name} { ${base.members.map((m) => m.name).join(', ')} }`;
|
|
37
|
+
return base;
|
|
38
|
+
}
|
|
39
|
+
// Type alias
|
|
40
|
+
if (ts.isTypeAliasDeclaration(node)) {
|
|
41
|
+
base.signatureText = `type ${exp.name} = ${node.type.getText(sf).substring(0, 100)}`;
|
|
42
|
+
return base;
|
|
43
|
+
}
|
|
44
|
+
// Enum
|
|
45
|
+
if (ts.isEnumDeclaration(node)) {
|
|
46
|
+
base.enumMembers = node.members.map((m) => ts.isIdentifier(m.name) ? m.name.text : m.name.getText(sf));
|
|
47
|
+
base.signatureText = `enum ${exp.name} { ${base.enumMembers.join(', ')} }`;
|
|
48
|
+
return base;
|
|
49
|
+
}
|
|
50
|
+
// Variable
|
|
51
|
+
if (ts.isVariableStatement(node)) {
|
|
52
|
+
for (const decl of node.declarationList.declarations) {
|
|
53
|
+
if (ts.isIdentifier(decl.name) && decl.name.text === exp.name) {
|
|
54
|
+
if (decl.initializer && (ts.isArrowFunction(decl.initializer) || ts.isFunctionExpression(decl.initializer))) {
|
|
55
|
+
base.params = extractParams(decl.initializer);
|
|
56
|
+
base.returnTypeText = decl.initializer.type ? decl.initializer.type.getText(sf) : undefined;
|
|
57
|
+
base.signatureText = `const ${exp.name} = (${formatParams(base.params)}) => ${base.returnTypeText ?? '...'}`;
|
|
58
|
+
}
|
|
59
|
+
else {
|
|
60
|
+
base.signatureText = `const ${exp.name}: ${decl.type?.getText(sf) ?? 'unknown'}`;
|
|
61
|
+
}
|
|
62
|
+
return base;
|
|
63
|
+
}
|
|
64
|
+
}
|
|
65
|
+
}
|
|
66
|
+
// Class
|
|
67
|
+
if (ts.isClassDeclaration(node)) {
|
|
68
|
+
base.members = [];
|
|
69
|
+
for (const member of node.members) {
|
|
70
|
+
if (ts.isMethodDeclaration(member) && ts.isIdentifier(member.name)) {
|
|
71
|
+
base.members.push({ name: member.name.text });
|
|
72
|
+
}
|
|
73
|
+
else if (ts.isPropertyDeclaration(member) && ts.isIdentifier(member.name)) {
|
|
74
|
+
base.members.push({
|
|
75
|
+
name: member.name.text,
|
|
76
|
+
optional: !!member.questionToken,
|
|
77
|
+
typeText: member.type?.getText(sf),
|
|
78
|
+
});
|
|
79
|
+
}
|
|
80
|
+
}
|
|
81
|
+
base.signatureText = `class ${exp.name} { ${base.members.map((m) => m.name).join(', ')} }`;
|
|
82
|
+
return base;
|
|
83
|
+
}
|
|
84
|
+
base.signatureText = `${exp.kind} ${exp.name}`;
|
|
85
|
+
return base;
|
|
86
|
+
}
|
|
87
|
+
function extractParams(node) {
|
|
88
|
+
return node.parameters.map((p) => ({
|
|
89
|
+
name: ts.isIdentifier(p.name) ? p.name.text : p.name.getText(),
|
|
90
|
+
optional: !!p.questionToken || !!p.initializer,
|
|
91
|
+
rest: !!p.dotDotDotToken,
|
|
92
|
+
typeText: p.type?.getText() ?? undefined,
|
|
93
|
+
}));
|
|
94
|
+
}
|
|
95
|
+
function extractMembers(node, sf) {
|
|
96
|
+
return node.members
|
|
97
|
+
.filter((m) => ts.isPropertySignature(m))
|
|
98
|
+
.map((m) => ({
|
|
99
|
+
name: ts.isIdentifier(m.name) ? m.name.text : m.name.getText(sf),
|
|
100
|
+
optional: !!m.questionToken,
|
|
101
|
+
typeText: m.type?.getText(sf),
|
|
102
|
+
}));
|
|
103
|
+
}
|
|
104
|
+
function formatParams(params) {
|
|
105
|
+
return params.map((p) => `${p.rest ? '...' : ''}${p.name}${p.optional ? '?' : ''}`).join(', ');
|
|
106
|
+
}
|
|
107
|
+
function findNodeAtLine(sf, line0) {
|
|
108
|
+
let found;
|
|
109
|
+
function visit(node) {
|
|
110
|
+
if (found)
|
|
111
|
+
return;
|
|
112
|
+
const nodeLine = sf.getLineAndCharacterOfPosition(node.getStart(sf)).line;
|
|
113
|
+
if (nodeLine === line0 || nodeLine === line0 + 1 || nodeLine === line0 - 1) {
|
|
114
|
+
// Prefer specific declaration types
|
|
115
|
+
if (ts.isFunctionDeclaration(node) || ts.isClassDeclaration(node) ||
|
|
116
|
+
ts.isInterfaceDeclaration(node) || ts.isTypeAliasDeclaration(node) ||
|
|
117
|
+
ts.isEnumDeclaration(node) || ts.isVariableStatement(node)) {
|
|
118
|
+
found = node;
|
|
119
|
+
return;
|
|
120
|
+
}
|
|
121
|
+
}
|
|
122
|
+
ts.forEachChild(node, visit);
|
|
123
|
+
}
|
|
124
|
+
visit(sf);
|
|
125
|
+
return found;
|
|
126
|
+
}
|
|
127
|
+
//# sourceMappingURL=extractDeclarationShape.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"extractDeclarationShape.js","sourceRoot":"","sources":["../../../src/analysis/ts/extractDeclarationShape.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
import ts from 'typescript';
|
|
2
|
+
/**
|
|
3
|
+
* Exported declaration — the shared type used by api_guard and root_cause_trace.
|
|
4
|
+
*/
|
|
5
|
+
export interface ExportedDeclaration {
|
|
6
|
+
name: string;
|
|
7
|
+
exportedAs: string[];
|
|
8
|
+
kind: 'function' | 'class' | 'interface' | 'type' | 'enum' | 'const' | 'var' | 'default' | 'reexport' | 'cjs' | 'unknown';
|
|
9
|
+
filePath: string;
|
|
10
|
+
line: number;
|
|
11
|
+
isTypeOnly?: boolean;
|
|
12
|
+
moduleSpecifier?: string;
|
|
13
|
+
}
|
|
14
|
+
/**
|
|
15
|
+
* Extract all exports from a TypeScript/JavaScript source file using the TS AST.
|
|
16
|
+
* Supports ESM (export function, export const, export { }, export * from, export default)
|
|
17
|
+
* and basic CJS (module.exports, exports.foo).
|
|
18
|
+
*/
|
|
19
|
+
export declare function extractExports(sf: ts.SourceFile): ExportedDeclaration[];
|