code-auditor-mcp 3.10.0 → 4.0.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/.claude-plugin/marketplace.json +1 -1
- package/CHANGELOG.md +171 -0
- package/dist/analyzers/analyzerUtils.js +2 -2
- package/dist/analyzers/analyzerUtils.js.map +1 -1
- package/dist/analyzers/applicability.d.ts.map +1 -1
- package/dist/analyzers/applicability.js +1 -0
- package/dist/analyzers/applicability.js.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/crossDomain/CrossDomainAnalyzer.d.ts +2 -2
- package/dist/analyzers/crossDomain/CrossDomainAnalyzer.d.ts.map +1 -1
- package/dist/analyzers/crossDomain/CrossDomainAnalyzer.js +39 -15
- package/dist/analyzers/crossDomain/CrossDomainAnalyzer.js.map +1 -1
- package/dist/analyzers/documentationAnalyzer.d.ts.map +1 -1
- package/dist/analyzers/documentationAnalyzer.js +14 -16
- package/dist/analyzers/documentationAnalyzer.js.map +1 -1
- package/dist/analyzers/invariantsAnalyzer.d.ts.map +1 -1
- package/dist/analyzers/invariantsAnalyzer.js +30 -25
- package/dist/analyzers/invariantsAnalyzer.js.map +1 -1
- package/dist/analyzers/reactAnalyzer.d.ts +1 -1
- package/dist/analyzers/reactAnalyzer.d.ts.map +1 -1
- package/dist/analyzers/reactAnalyzer.js +34 -116
- package/dist/analyzers/reactAnalyzer.js.map +1 -1
- package/dist/analyzers/ruleRegistry.d.ts +5 -3
- package/dist/analyzers/ruleRegistry.d.ts.map +1 -1
- package/dist/analyzers/ruleRegistry.js +198 -54
- 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 +10 -17
- package/dist/analyzers/universal/UniversalConventionsAnalyzer.js.map +1 -1
- package/dist/analyzers/universal/UniversalDRYAnalyzer.d.ts +6 -6
- package/dist/analyzers/universal/UniversalDRYAnalyzer.js +13 -13
- 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 +22 -64
- package/dist/analyzers/universal/UniversalDataAccessAnalyzer.js.map +1 -1
- package/dist/analyzers/universal/UniversalDocumentationAnalyzer.d.ts +3 -2
- package/dist/analyzers/universal/UniversalDocumentationAnalyzer.d.ts.map +1 -1
- package/dist/analyzers/universal/UniversalDocumentationAnalyzer.js +14 -13
- package/dist/analyzers/universal/UniversalDocumentationAnalyzer.js.map +1 -1
- package/dist/analyzers/universal/UniversalSOLIDAnalyzer.js +11 -11
- package/dist/analyzers/universal/UniversalSOLIDAnalyzer.js.map +1 -1
- package/dist/analyzers/universal/UniversalSchemaAnalyzer.d.ts +1 -1
- package/dist/analyzers/universal/UniversalSchemaAnalyzer.d.ts.map +1 -1
- package/dist/analyzers/universal/UniversalSchemaAnalyzer.js +18 -7
- package/dist/analyzers/universal/UniversalSchemaAnalyzer.js.map +1 -1
- package/dist/analyzers/universal/UniversalStylesAnalyzer.d.ts +2 -2
- package/dist/analyzers/universal/UniversalStylesAnalyzer.d.ts.map +1 -1
- package/dist/analyzers/universal/UniversalStylesAnalyzer.js +38 -26
- package/dist/analyzers/universal/UniversalStylesAnalyzer.js.map +1 -1
- package/dist/analyzers/universal/schema/codeAnalysis.d.ts +37 -13
- package/dist/analyzers/universal/schema/codeAnalysis.d.ts.map +1 -1
- package/dist/analyzers/universal/schema/codeAnalysis.js +42 -54
- package/dist/analyzers/universal/schema/codeAnalysis.js.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/violations.d.ts +1 -1
- package/dist/analyzers/universal/schema/violations.d.ts.map +1 -1
- package/dist/auditRouter.js +7 -7
- package/dist/auditRouter.js.map +1 -1
- package/dist/auditRunner.d.ts.map +1 -1
- package/dist/auditRunner.js +36 -6
- package/dist/auditRunner.js.map +1 -1
- package/dist/cli.js +23 -17
- package/dist/cli.js.map +1 -1
- package/dist/codeIndexDB.d.ts +1 -1
- package/dist/codeIndexDB.d.ts.map +1 -1
- package/dist/codeIndexDB.js +148 -18
- package/dist/codeIndexDB.js.map +1 -1
- package/dist/componentScanner.d.ts.map +1 -1
- package/dist/componentScanner.js +89 -28
- 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.js +3 -3
- package/dist/config/defaults.js.map +1 -1
- package/dist/constants.d.ts +1 -1
- package/dist/constants.d.ts.map +1 -1
- package/dist/conventions/conventionMiner.d.ts.map +1 -1
- package/dist/conventions/conventionMiner.js +3 -10
- package/dist/conventions/conventionMiner.js.map +1 -1
- package/dist/daemon/core.d.ts.map +1 -1
- package/dist/daemon/core.js +33 -38
- package/dist/daemon/core.js.map +1 -1
- package/dist/daemon/lspServer.js +1 -1
- package/dist/daemon/lspServer.js.map +1 -1
- package/dist/daemon/main.d.ts.map +1 -1
- package/dist/daemon/main.js +14 -4
- package/dist/daemon/main.js.map +1 -1
- package/dist/enforcement/gate.js +2 -2
- package/dist/functionScanner.d.ts.map +1 -1
- package/dist/functionScanner.js +47 -42
- package/dist/functionScanner.js.map +1 -1
- package/dist/graph/importClassification.d.ts +76 -0
- package/dist/graph/importClassification.d.ts.map +1 -0
- package/dist/graph/importClassification.js +221 -0
- package/dist/graph/importClassification.js.map +1 -0
- package/dist/graph/importGraph.d.ts +1 -0
- package/dist/graph/importGraph.d.ts.map +1 -1
- package/dist/graph/importGraph.js +1 -1
- package/dist/graph/importGraph.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 +1 -1
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js.map +1 -1
- package/dist/installer.d.ts +13 -7
- package/dist/installer.d.ts.map +1 -1
- package/dist/installer.js +25 -15
- package/dist/installer.js.map +1 -1
- package/dist/invariants/invariant-rules.schema.json +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 +3 -2
- package/dist/languages/LanguageOrchestrator.d.ts.map +1 -1
- package/dist/languages/LanguageOrchestrator.js +1 -1
- package/dist/languages/LanguageOrchestrator.js.map +1 -1
- package/dist/languages/RuntimeManager.d.ts +20 -11
- package/dist/languages/RuntimeManager.d.ts.map +1 -1
- package/dist/languages/RuntimeManager.js +151 -51
- package/dist/languages/RuntimeManager.js.map +1 -1
- package/dist/languages/adapterBridge.d.ts +10 -0
- package/dist/languages/adapterBridge.d.ts.map +1 -1
- package/dist/languages/adapterBridge.js +30 -7
- package/dist/languages/adapterBridge.js.map +1 -1
- package/dist/languages/go/GoAdapter.d.ts +1 -19
- package/dist/languages/go/GoAdapter.d.ts.map +1 -1
- package/dist/languages/go/GoAdapter.js +33 -116
- package/dist/languages/go/GoAdapter.js.map +1 -1
- package/dist/languages/go/analyzer +0 -0
- package/dist/languages/go/analyzer-src/analyzer.go +8 -8
- package/dist/languages/go/analyzer-src/solid.go +5 -5
- package/dist/languages/goBinary.d.ts +46 -0
- package/dist/languages/goBinary.d.ts.map +1 -0
- package/dist/languages/goBinary.js +169 -0
- package/dist/languages/goBinary.js.map +1 -0
- package/dist/languages/tree-sitter/TreeSitterCssAdapter.d.ts +1 -28
- package/dist/languages/tree-sitter/TreeSitterCssAdapter.d.ts.map +1 -1
- package/dist/languages/tree-sitter/TreeSitterCssAdapter.js +3 -42
- package/dist/languages/tree-sitter/TreeSitterCssAdapter.js.map +1 -1
- package/dist/languages/tree-sitter/converter.d.ts.map +1 -1
- package/dist/languages/tree-sitter/converter.js +2 -1
- package/dist/languages/tree-sitter/converter.js.map +1 -1
- package/dist/languages/tree-sitter/rawNode.d.ts +31 -0
- package/dist/languages/tree-sitter/rawNode.d.ts.map +1 -0
- package/dist/languages/tree-sitter/rawNode.js +38 -0
- package/dist/languages/tree-sitter/rawNode.js.map +1 -0
- package/dist/languages/types.d.ts +0 -21
- package/dist/languages/types.d.ts.map +1 -1
- package/dist/languages/typescript/TreeSitterTypeScriptAdapter.d.ts +1 -32
- package/dist/languages/typescript/TreeSitterTypeScriptAdapter.d.ts.map +1 -1
- package/dist/languages/typescript/TreeSitterTypeScriptAdapter.js +69 -203
- package/dist/languages/typescript/TreeSitterTypeScriptAdapter.js.map +1 -1
- package/dist/ledger.d.ts +3 -0
- package/dist/ledger.d.ts.map +1 -1
- package/dist/ledger.js +45 -9
- package/dist/ledger.js.map +1 -1
- package/dist/mcp-tools/projectTasks.js +2 -2
- package/dist/mcp-tools/projectTasks.js.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.js +13 -13
- package/dist/mcp-tools-shared.js.map +1 -1
- package/dist/mcp-ui-simple.js +7 -7
- 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/nextFile.d.ts +2 -2
- package/dist/nextFile.d.ts.map +1 -1
- package/dist/nextFile.js +19 -5
- package/dist/nextFile.js.map +1 -1
- package/dist/nextFileIncremental.d.ts +3 -2
- package/dist/nextFileIncremental.d.ts.map +1 -1
- package/dist/nextFileIncremental.js +20 -7
- package/dist/nextFileIncremental.js.map +1 -1
- package/dist/pipelineAdapters.d.ts +17 -0
- package/dist/pipelineAdapters.d.ts.map +1 -1
- package/dist/pipelineAdapters.js +279 -178
- package/dist/pipelineAdapters.js.map +1 -1
- package/dist/reporting/csvReportGenerator.js +6 -6
- package/dist/reporting/csvReportGenerator.js.map +1 -1
- package/dist/reporting/htmlReportGenerator.js +11 -11
- package/dist/reporting/htmlReportGenerator.js.map +1 -1
- package/dist/reporting/jsonReportGenerator.js +2 -2
- package/dist/reporting/jsonReportGenerator.js.map +1 -1
- package/dist/reporting/sarifReportGenerator.js +1 -1
- package/dist/reporting/sarifReportGenerator.js.map +1 -1
- package/dist/scripts/benchmarkWorkers.js +1 -1
- package/dist/scripts/benchmarkWorkers.js.map +1 -1
- package/dist/styles/cssAstExtractor.d.ts +2 -2
- package/dist/styles/cssAstExtractor.d.ts.map +1 -1
- package/dist/styles/cssAstExtractor.js +67 -111
- package/dist/styles/cssAstExtractor.js.map +1 -1
- package/dist/styles/styleIndexer.d.ts.map +1 -1
- package/dist/styles/styleIndexer.js +19 -6
- package/dist/styles/styleIndexer.js.map +1 -1
- package/dist/telemetry.d.ts +1 -1
- package/dist/telemetry.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 +59 -19
- package/dist/types.d.ts.map +1 -1
- package/dist/types.js +6 -5
- package/dist/types.js.map +1 -1
- package/dist/utils/astParser.d.ts +1 -17
- package/dist/utils/astParser.d.ts.map +1 -1
- package/dist/utils/astParser.js +18 -60
- package/dist/utils/astParser.js.map +1 -1
- package/dist/utils/astUtils.d.ts +12 -12
- package/dist/utils/astUtils.d.ts.map +1 -1
- package/dist/utils/astUtils.js +83 -82
- package/dist/utils/astUtils.js.map +1 -1
- package/dist/utils/componentResponsibility.d.ts +8 -8
- package/dist/utils/componentResponsibility.d.ts.map +1 -1
- package/dist/utils/componentResponsibility.js +33 -38
- package/dist/utils/componentResponsibility.js.map +1 -1
- package/dist/utils/dependencyExtractor.d.ts +3 -3
- package/dist/utils/dependencyExtractor.d.ts.map +1 -1
- package/dist/utils/dependencyExtractor.js +26 -30
- package/dist/utils/dependencyExtractor.js.map +1 -1
- package/dist/utils/fileDiscovery.d.ts.map +1 -1
- package/dist/utils/fileDiscovery.js +65 -0
- package/dist/utils/fileDiscovery.js.map +1 -1
- package/dist/utils/jsDocParser.d.ts +6 -6
- package/dist/utils/jsDocParser.d.ts.map +1 -1
- package/dist/utils/jsDocParser.js +18 -21
- package/dist/utils/jsDocParser.js.map +1 -1
- package/dist/utils/reactDetection.d.ts +7 -7
- package/dist/utils/reactDetection.d.ts.map +1 -1
- package/dist/utils/reactDetection.js +42 -49
- package/dist/utils/reactDetection.js.map +1 -1
- package/dist/version.generated.d.ts +1 -1
- package/dist/version.generated.d.ts.map +1 -1
- package/dist/version.generated.js +1 -1
- package/dist/version.generated.js.map +1 -1
- package/package.json +1 -1
- package/plugin/.claude-plugin/plugin.json +1 -1
- package/plugin/README.md +5 -4
- package/plugin/hooks/hooks.json +11 -0
- package/plugin/scripts/hook-common.sh +85 -31
- package/plugin/scripts/hook-warm.sh +44 -0
- package/plugin/skills/code-auditor/SKILL-RULE-KINDS.md +28 -21
- package/plugin/skills/code-auditor/SKILL.md +10 -10
- package/server.json +2 -2
package/dist/utils/astUtils.js
CHANGED
|
@@ -8,14 +8,10 @@
|
|
|
8
8
|
* The `ts.SourceFile` parameter has been replaced with `ASTNode` (root node).
|
|
9
9
|
* For source-code-dependent operations, `sourceCode: string` is passed separately.
|
|
10
10
|
*/
|
|
11
|
-
import { walkAST, findNodes, getNodeText
|
|
11
|
+
import { walkAST, findNodes, getNodeText, getLineAndColumn as bridgeGetLineAndColumn, isExported as bridgeIsExported, calculateComplexity as bridgeCalculateComplexity, hasModifier, } from '../languages/adapterBridge.js';
|
|
12
12
|
// ---------------------------------------------------------------------------
|
|
13
13
|
// Helpers
|
|
14
14
|
// ---------------------------------------------------------------------------
|
|
15
|
-
/** Get raw text from a tree-sitter node (stored on ASTNode.raw). */
|
|
16
|
-
function rawText(node) {
|
|
17
|
-
return node.raw?.text ?? '';
|
|
18
|
-
}
|
|
19
15
|
/** Find the first child of a given type. */
|
|
20
16
|
function findChildOfType(node, type) {
|
|
21
17
|
return node.children?.find(c => c.type === type);
|
|
@@ -37,7 +33,7 @@ export function findNodesByType(root, predicate) {
|
|
|
37
33
|
* Get the text content of a node.
|
|
38
34
|
* Uses sourceCode if provided; falls back to raw tree-sitter text.
|
|
39
35
|
*/
|
|
40
|
-
export {
|
|
36
|
+
export { getNodeText };
|
|
41
37
|
// ---------------------------------------------------------------------------
|
|
42
38
|
// Position helpers (re-exports from adapterBridge)
|
|
43
39
|
// ---------------------------------------------------------------------------
|
|
@@ -61,7 +57,7 @@ export { bridgeCalculateComplexity as calculateComplexity };
|
|
|
61
57
|
* Uses tree-sitter import_statement structure:
|
|
62
58
|
* import_statement → import_clause? → (identifier | named_imports) → string
|
|
63
59
|
*/
|
|
64
|
-
export function getImports(root) {
|
|
60
|
+
export function getImports(root, sourceCode) {
|
|
65
61
|
const imports = [];
|
|
66
62
|
const importNodes = findNodes(root, n => n.type === 'import_statement');
|
|
67
63
|
for (const node of importNodes) {
|
|
@@ -69,18 +65,18 @@ export function getImports(root) {
|
|
|
69
65
|
const moduleNode = findChildOfType(node, 'string');
|
|
70
66
|
if (!moduleNode)
|
|
71
67
|
continue;
|
|
72
|
-
const
|
|
73
|
-
const
|
|
68
|
+
const source = getNodeText(moduleNode, sourceCode).replace(/^["']|["']$/g, '');
|
|
69
|
+
const specifiers = [];
|
|
74
70
|
const importClause = findChildOfType(node, 'import_clause');
|
|
75
|
-
let isTypeOnly = false;
|
|
76
71
|
if (importClause) {
|
|
77
|
-
//
|
|
78
|
-
const raw = importClause.raw;
|
|
79
|
-
isTypeOnly = raw?.children?.some(c => !c.isNamed && c.type === 'type') ?? false;
|
|
80
|
-
// Default import (identifier child of import_clause that's not 'type' modifier)
|
|
72
|
+
// Default import (identifier child of import_clause that's not the `type` keyword)
|
|
81
73
|
const defaultId = importClause.children?.find(c => c.type === 'identifier');
|
|
82
74
|
if (defaultId) {
|
|
83
|
-
|
|
75
|
+
specifiers.push({
|
|
76
|
+
name: getNodeText(defaultId, sourceCode),
|
|
77
|
+
isDefault: true,
|
|
78
|
+
isNamespace: false,
|
|
79
|
+
});
|
|
84
80
|
}
|
|
85
81
|
// Named imports
|
|
86
82
|
const namedImports = findChildOfType(importClause, 'named_imports');
|
|
@@ -88,10 +84,17 @@ export function getImports(root) {
|
|
|
88
84
|
for (const child of namedImports.children ?? []) {
|
|
89
85
|
if (child.type !== 'import_specifier')
|
|
90
86
|
continue;
|
|
91
|
-
//
|
|
87
|
+
// import { name } / { name as alias } / { default as name }
|
|
92
88
|
const ids = child.children?.filter(c => c.type === 'identifier') ?? [];
|
|
93
89
|
if (ids.length > 0) {
|
|
94
|
-
|
|
90
|
+
const imported = getNodeText(ids[0], sourceCode);
|
|
91
|
+
const local = getNodeText(ids[ids.length - 1], sourceCode);
|
|
92
|
+
specifiers.push({
|
|
93
|
+
name: local,
|
|
94
|
+
alias: imported !== local ? imported : undefined,
|
|
95
|
+
isDefault: imported === 'default',
|
|
96
|
+
isNamespace: false,
|
|
97
|
+
});
|
|
95
98
|
}
|
|
96
99
|
}
|
|
97
100
|
}
|
|
@@ -100,12 +103,15 @@ export function getImports(root) {
|
|
|
100
103
|
if (namespaceImport) {
|
|
101
104
|
const nsId = findChildOfType(namespaceImport, 'identifier');
|
|
102
105
|
if (nsId) {
|
|
103
|
-
|
|
106
|
+
specifiers.push({
|
|
107
|
+
name: getNodeText(nsId, sourceCode),
|
|
108
|
+
isDefault: false,
|
|
109
|
+
isNamespace: true,
|
|
110
|
+
});
|
|
104
111
|
}
|
|
105
112
|
}
|
|
106
113
|
}
|
|
107
|
-
|
|
108
|
-
imports.push({ moduleSpecifier, importedNames, isTypeOnly, line });
|
|
114
|
+
imports.push({ source, specifiers, location: node.location });
|
|
109
115
|
}
|
|
110
116
|
return imports;
|
|
111
117
|
}
|
|
@@ -116,15 +122,14 @@ export function getImports(root) {
|
|
|
116
122
|
* Extract export statements from an AST root node.
|
|
117
123
|
* Uses tree-sitter export_statement structure.
|
|
118
124
|
*/
|
|
119
|
-
export function getExports(root) {
|
|
125
|
+
export function getExports(root, sourceCode) {
|
|
120
126
|
const exports = [];
|
|
121
127
|
// export declarations: export { name1, name2 }
|
|
122
128
|
const exportNodes = findNodes(root, n => n.type === 'export_statement' || n.type === 'export_declaration');
|
|
123
129
|
for (const node of exportNodes) {
|
|
124
130
|
const { line } = bridgeGetLineAndColumn(node);
|
|
125
131
|
// Check for type-only exports
|
|
126
|
-
const
|
|
127
|
-
const isTypeOnly = raw?.children?.some(c => !c.isNamed && c.type === 'type') ?? false;
|
|
132
|
+
const isTypeOnly = hasModifier(node, 'type');
|
|
128
133
|
// export clause with named exports
|
|
129
134
|
const exportClause = findChildOfType(node, 'export_clause');
|
|
130
135
|
if (exportClause) {
|
|
@@ -136,7 +141,7 @@ export function getExports(root) {
|
|
|
136
141
|
const ids = child.children?.filter(c => c.type === 'identifier') ?? [];
|
|
137
142
|
if (ids.length > 0) {
|
|
138
143
|
exports.push({
|
|
139
|
-
name:
|
|
144
|
+
name: getNodeText(ids[ids.length - 1], sourceCode),
|
|
140
145
|
isDefault: false,
|
|
141
146
|
isTypeOnly,
|
|
142
147
|
line
|
|
@@ -146,14 +151,14 @@ export function getExports(root) {
|
|
|
146
151
|
}
|
|
147
152
|
}
|
|
148
153
|
// Check for `default` keyword — export default X
|
|
149
|
-
const isDefault =
|
|
154
|
+
const isDefault = hasModifier(node, 'default');
|
|
150
155
|
if (isDefault) {
|
|
151
156
|
const exported = node.children?.find(c => c.type === 'identifier' || c.type === 'function_declaration' ||
|
|
152
157
|
c.type === 'class_declaration' || c.type === 'call_expression');
|
|
153
158
|
if (exported) {
|
|
154
159
|
const nameNode = findChildOfType(exported, 'identifier');
|
|
155
160
|
exports.push({
|
|
156
|
-
name: nameNode ?
|
|
161
|
+
name: nameNode ? getNodeText(nameNode, sourceCode) : 'default',
|
|
157
162
|
isDefault: true,
|
|
158
163
|
isTypeOnly,
|
|
159
164
|
line
|
|
@@ -187,11 +192,11 @@ export function findClasses(root) {
|
|
|
187
192
|
/**
|
|
188
193
|
* Get AST node for inspection/debugging.
|
|
189
194
|
*/
|
|
190
|
-
export function getASTNode(node) {
|
|
195
|
+
export function getASTNode(node, sourceCode) {
|
|
191
196
|
return {
|
|
192
197
|
type: node.type,
|
|
193
|
-
text:
|
|
194
|
-
children: (node.children ?? []).map(child => getASTNode(child))
|
|
198
|
+
text: getNodeText(node, sourceCode),
|
|
199
|
+
children: (node.children ?? []).map(child => getASTNode(child, sourceCode))
|
|
195
200
|
};
|
|
196
201
|
}
|
|
197
202
|
// ---------------------------------------------------------------------------
|
|
@@ -201,20 +206,20 @@ export function getASTNode(node) {
|
|
|
201
206
|
* Check if a node has a specific decorator.
|
|
202
207
|
* Tree-sitter parses decorators as `decorator` nodes.
|
|
203
208
|
*/
|
|
204
|
-
export function hasDecorator(node, decoratorName) {
|
|
209
|
+
export function hasDecorator(node, decoratorName, sourceCode) {
|
|
205
210
|
const decorators = findNodes(node, n => n.type === 'decorator');
|
|
206
211
|
return decorators.some(decorator => {
|
|
207
212
|
// decorator → call_expression → identifier (e.g., @Component())
|
|
208
213
|
const callExpr = findChildOfType(decorator, 'call_expression');
|
|
209
214
|
if (callExpr) {
|
|
210
215
|
const callee = callExpr.children?.[0];
|
|
211
|
-
if (callee?.type === 'identifier' &&
|
|
216
|
+
if (callee?.type === 'identifier' && getNodeText(callee, sourceCode) === decoratorName) {
|
|
212
217
|
return true;
|
|
213
218
|
}
|
|
214
219
|
}
|
|
215
220
|
// decorator → identifier (e.g., @deprecated)
|
|
216
221
|
const id = findChildOfType(decorator, 'identifier');
|
|
217
|
-
if (id &&
|
|
222
|
+
if (id && getNodeText(id, sourceCode) === decoratorName) {
|
|
218
223
|
return true;
|
|
219
224
|
}
|
|
220
225
|
return false;
|
|
@@ -227,7 +232,7 @@ export function hasDecorator(node, decoratorName) {
|
|
|
227
232
|
* Get method names from a class declaration node.
|
|
228
233
|
* Tree-sitter: class_declaration → class_body → method_definition / public_field_definition
|
|
229
234
|
*/
|
|
230
|
-
export function getClassMethods(classNode) {
|
|
235
|
+
export function getClassMethods(classNode, sourceCode) {
|
|
231
236
|
const methods = [];
|
|
232
237
|
const classBody = findChildOfType(classNode, 'class_body');
|
|
233
238
|
if (!classBody)
|
|
@@ -236,7 +241,7 @@ export function getClassMethods(classNode) {
|
|
|
236
241
|
if (member.type === 'method_definition' || member.type === 'public_field_definition') {
|
|
237
242
|
const nameNode = member.children?.find(c => c.type === 'identifier' || c.type === 'property_identifier');
|
|
238
243
|
if (nameNode) {
|
|
239
|
-
methods.push(
|
|
244
|
+
methods.push(getNodeText(nameNode, sourceCode));
|
|
240
245
|
}
|
|
241
246
|
}
|
|
242
247
|
}
|
|
@@ -334,7 +339,7 @@ export async function parseTypeScriptFile(filePath) {
|
|
|
334
339
|
const ast = parseFile(filePath, content);
|
|
335
340
|
if (!ast) {
|
|
336
341
|
const failLocation = { start: { line: 0, column: 0 }, end: { line: 0, column: 0 } };
|
|
337
|
-
const failAst = { root: { type: 'source_file', range: [0, 0], location: failLocation
|
|
342
|
+
const failAst = { root: { type: 'source_file', range: [0, 0], location: failLocation }, language: 'unknown', filePath, errors: [{ message: 'Failed to parse file', location: failLocation, severity: 'error' }] };
|
|
338
343
|
return { ast: failAst, errors: [{ message: 'Failed to parse file', line: 0, column: 0 }] };
|
|
339
344
|
}
|
|
340
345
|
return { ast, errors: ast.errors ?? [] };
|
|
@@ -346,14 +351,14 @@ export async function parseTypeScriptFile(filePath) {
|
|
|
346
351
|
* Enhanced version of getImports that returns detailed ImportMapping[].
|
|
347
352
|
* Uses tree-sitter import_statement traversal.
|
|
348
353
|
*/
|
|
349
|
-
export function getImportsDetailed(root) {
|
|
354
|
+
export function getImportsDetailed(root, sourceCode) {
|
|
350
355
|
const imports = [];
|
|
351
356
|
const importNodes = findNodes(root, n => n.type === 'import_statement');
|
|
352
357
|
for (const node of importNodes) {
|
|
353
358
|
const moduleNode = findChildOfType(node, 'string');
|
|
354
359
|
if (!moduleNode)
|
|
355
360
|
continue;
|
|
356
|
-
const moduleSpecifier =
|
|
361
|
+
const moduleSpecifier = getNodeText(moduleNode, sourceCode).replace(/^["']|["']$/g, '');
|
|
357
362
|
const importClause = findChildOfType(node, 'import_clause');
|
|
358
363
|
if (!importClause) {
|
|
359
364
|
// Side-effect import (no import clause)
|
|
@@ -366,13 +371,12 @@ export function getImportsDetailed(root) {
|
|
|
366
371
|
});
|
|
367
372
|
continue;
|
|
368
373
|
}
|
|
369
|
-
const
|
|
370
|
-
const isTypeOnly = raw?.children?.some(c => !c.isNamed && c.type === 'type') ?? false;
|
|
374
|
+
const isTypeOnly = hasModifier(importClause, 'type');
|
|
371
375
|
// Default import
|
|
372
376
|
const defaultId = importClause.children?.find(c => c.type === 'identifier');
|
|
373
377
|
if (defaultId) {
|
|
374
378
|
imports.push({
|
|
375
|
-
localName:
|
|
379
|
+
localName: getNodeText(defaultId, sourceCode),
|
|
376
380
|
importedName: 'default',
|
|
377
381
|
modulePath: moduleSpecifier,
|
|
378
382
|
importType: 'default',
|
|
@@ -388,8 +392,8 @@ export function getImportsDetailed(root) {
|
|
|
388
392
|
const identifiers = child.children?.filter(c => c.type === 'identifier') ?? [];
|
|
389
393
|
if (identifiers.length === 0)
|
|
390
394
|
continue;
|
|
391
|
-
const localName =
|
|
392
|
-
const importedName = identifiers.length > 1 ?
|
|
395
|
+
const localName = getNodeText(identifiers[identifiers.length - 1], sourceCode);
|
|
396
|
+
const importedName = identifiers.length > 1 ? getNodeText(identifiers[0], sourceCode) : localName;
|
|
393
397
|
imports.push({
|
|
394
398
|
localName,
|
|
395
399
|
importedName,
|
|
@@ -405,7 +409,7 @@ export function getImportsDetailed(root) {
|
|
|
405
409
|
const nsId = findChildOfType(nsImport, 'identifier');
|
|
406
410
|
if (nsId) {
|
|
407
411
|
imports.push({
|
|
408
|
-
localName:
|
|
412
|
+
localName: getNodeText(nsId, sourceCode),
|
|
409
413
|
importedName: '*',
|
|
410
414
|
modulePath: moduleSpecifier,
|
|
411
415
|
importType: 'namespace',
|
|
@@ -423,7 +427,7 @@ export function getImportsDetailed(root) {
|
|
|
423
427
|
* Get re-exports from a source file.
|
|
424
428
|
* Tree-sitter: export_statement → string (module specifier).
|
|
425
429
|
*/
|
|
426
|
-
export function getReExports(root) {
|
|
430
|
+
export function getReExports(root, sourceCode) {
|
|
427
431
|
const reExports = [];
|
|
428
432
|
const exportNodes = findNodes(root, n => n.type === 'export_statement' || n.type === 'export_declaration');
|
|
429
433
|
for (const node of exportNodes) {
|
|
@@ -431,7 +435,7 @@ export function getReExports(root) {
|
|
|
431
435
|
const moduleNode = findChildOfType(node, 'string');
|
|
432
436
|
if (!moduleNode)
|
|
433
437
|
continue;
|
|
434
|
-
const moduleSpecifier =
|
|
438
|
+
const moduleSpecifier = getNodeText(moduleNode, sourceCode).replace(/^["']|["']$/g, '');
|
|
435
439
|
const exportClause = findChildOfType(node, 'export_clause');
|
|
436
440
|
if (exportClause) {
|
|
437
441
|
const namedExports = findChildOfType(exportClause, 'named_exports');
|
|
@@ -442,8 +446,8 @@ export function getReExports(root) {
|
|
|
442
446
|
const identifiers = child.children?.filter(c => c.type === 'identifier') ?? [];
|
|
443
447
|
if (identifiers.length > 0) {
|
|
444
448
|
const name = identifiers.length > 1
|
|
445
|
-
?
|
|
446
|
-
:
|
|
449
|
+
? getNodeText(identifiers[0], sourceCode)
|
|
450
|
+
: getNodeText(identifiers[identifiers.length - 1], sourceCode);
|
|
447
451
|
reExports.push({ name, module: moduleSpecifier });
|
|
448
452
|
}
|
|
449
453
|
}
|
|
@@ -601,8 +605,7 @@ function isTypeOnlyUsage(identifier) {
|
|
|
601
605
|
if (parent.type === 'generic_type' && parent.children?.[0] === identifier) {
|
|
602
606
|
const heritageClause = parent.parent;
|
|
603
607
|
if (heritageClause?.type === 'heritage_clause') {
|
|
604
|
-
const
|
|
605
|
-
const isExtends = raw?.children?.some(c => !c.isNamed && c.type === 'extends');
|
|
608
|
+
const isExtends = hasModifier(heritageClause, 'extends');
|
|
606
609
|
if (isExtends) {
|
|
607
610
|
const interfaceNode = heritageClause.parent;
|
|
608
611
|
if (interfaceNode?.type === 'interface_declaration') {
|
|
@@ -617,8 +620,7 @@ function isTypeOnlyUsage(identifier) {
|
|
|
617
620
|
if (grandParent?.type === 'generic_type') {
|
|
618
621
|
const heritageClause = grandParent.parent;
|
|
619
622
|
if (heritageClause?.type === 'heritage_clause') {
|
|
620
|
-
const
|
|
621
|
-
const isExtends = raw?.children?.some(c => !c.isNamed && c.type === 'extends');
|
|
623
|
+
const isExtends = hasModifier(heritageClause, 'extends');
|
|
622
624
|
if (isExtends) {
|
|
623
625
|
const interfaceNode = heritageClause.parent;
|
|
624
626
|
if (interfaceNode?.type === 'interface_declaration') {
|
|
@@ -640,8 +642,7 @@ function isTypeOnlyUsage(identifier) {
|
|
|
640
642
|
for (const child of parent.children ?? []) {
|
|
641
643
|
if (child.type !== 'heritage_clause')
|
|
642
644
|
continue;
|
|
643
|
-
const
|
|
644
|
-
const isImplements = raw?.children?.some(c => !c.isNamed && c.type === 'implements');
|
|
645
|
+
const isImplements = hasModifier(child, 'implements');
|
|
645
646
|
if (!isImplements)
|
|
646
647
|
continue;
|
|
647
648
|
for (const typeNode of child.children ?? []) {
|
|
@@ -799,7 +800,7 @@ export function extractIdentifierUsage(root, sourceCode, importNames) {
|
|
|
799
800
|
walkAST(root, (node) => {
|
|
800
801
|
// --- identifiers ---
|
|
801
802
|
if (node.type === 'identifier') {
|
|
802
|
-
const name =
|
|
803
|
+
const name = getNodeText(node, sourceCode);
|
|
803
804
|
if (importNames.has(name)) {
|
|
804
805
|
let shouldCount = true;
|
|
805
806
|
// Skip if part of an import declaration
|
|
@@ -842,16 +843,16 @@ export function extractIdentifierUsage(root, sourceCode, importNames) {
|
|
|
842
843
|
// --- spread elements ---
|
|
843
844
|
else if (SPREAD_TYPES.has(node.type)) {
|
|
844
845
|
const expr = node.children?.find(c => c.type !== '...');
|
|
845
|
-
if (expr?.type === 'identifier' && importNames.has(
|
|
846
|
+
if (expr?.type === 'identifier' && importNames.has(getNodeText(expr, sourceCode))) {
|
|
846
847
|
const { line } = bridgeGetLineAndColumn(expr);
|
|
847
|
-
const existing = usageMap.get(
|
|
848
|
+
const existing = usageMap.get(getNodeText(expr, sourceCode)) || {
|
|
848
849
|
usageType: 'direct',
|
|
849
850
|
usageCount: 0,
|
|
850
851
|
lineNumbers: [],
|
|
851
852
|
};
|
|
852
853
|
existing.usageCount++;
|
|
853
854
|
existing.lineNumbers.push(line);
|
|
854
|
-
usageMap.set(
|
|
855
|
+
usageMap.set(getNodeText(expr, sourceCode), existing);
|
|
855
856
|
}
|
|
856
857
|
}
|
|
857
858
|
// --- JSX elements: <Button /> or <Button.Primary /> ---
|
|
@@ -867,29 +868,29 @@ export function extractIdentifierUsage(root, sourceCode, importNames) {
|
|
|
867
868
|
tagNameNode = node.children?.find(c => c.type === 'identifier' || c.type === 'member_expression');
|
|
868
869
|
}
|
|
869
870
|
if (tagNameNode) {
|
|
870
|
-
if (tagNameNode.type === 'identifier' && importNames.has(
|
|
871
|
+
if (tagNameNode.type === 'identifier' && importNames.has(getNodeText(tagNameNode, sourceCode))) {
|
|
871
872
|
const { line } = bridgeGetLineAndColumn(tagNameNode);
|
|
872
|
-
const existing = usageMap.get(
|
|
873
|
+
const existing = usageMap.get(getNodeText(tagNameNode, sourceCode)) || {
|
|
873
874
|
usageType: 'direct',
|
|
874
875
|
usageCount: 0,
|
|
875
876
|
lineNumbers: [],
|
|
876
877
|
};
|
|
877
878
|
existing.usageCount++;
|
|
878
879
|
existing.lineNumbers.push(line);
|
|
879
|
-
usageMap.set(
|
|
880
|
+
usageMap.set(getNodeText(tagNameNode, sourceCode), existing);
|
|
880
881
|
}
|
|
881
882
|
else if (tagNameNode.type === 'member_expression') {
|
|
882
883
|
const leftmost = tagNameNode.children?.[0];
|
|
883
|
-
if (leftmost?.type === 'identifier' && importNames.has(
|
|
884
|
+
if (leftmost?.type === 'identifier' && importNames.has(getNodeText(leftmost, sourceCode))) {
|
|
884
885
|
const { line } = bridgeGetLineAndColumn(leftmost);
|
|
885
|
-
const existing = usageMap.get(
|
|
886
|
+
const existing = usageMap.get(getNodeText(leftmost, sourceCode)) || {
|
|
886
887
|
usageType: 'direct',
|
|
887
888
|
usageCount: 0,
|
|
888
889
|
lineNumbers: [],
|
|
889
890
|
};
|
|
890
891
|
existing.usageCount++;
|
|
891
892
|
existing.lineNumbers.push(line);
|
|
892
|
-
usageMap.set(
|
|
893
|
+
usageMap.set(getNodeText(leftmost, sourceCode), existing);
|
|
893
894
|
}
|
|
894
895
|
}
|
|
895
896
|
}
|
|
@@ -898,31 +899,31 @@ export function extractIdentifierUsage(root, sourceCode, importNames) {
|
|
|
898
899
|
else if (node.type === 'decorator') {
|
|
899
900
|
// decorator → identifier (e.g., @deprecated)
|
|
900
901
|
const id = findChildOfType(node, 'identifier');
|
|
901
|
-
if (id && importNames.has(
|
|
902
|
+
if (id && importNames.has(getNodeText(id, sourceCode))) {
|
|
902
903
|
const { line } = bridgeGetLineAndColumn(id);
|
|
903
|
-
const existing = usageMap.get(
|
|
904
|
+
const existing = usageMap.get(getNodeText(id, sourceCode)) || {
|
|
904
905
|
usageType: 'direct',
|
|
905
906
|
usageCount: 0,
|
|
906
907
|
lineNumbers: [],
|
|
907
908
|
};
|
|
908
909
|
existing.usageCount++;
|
|
909
910
|
existing.lineNumbers.push(line);
|
|
910
|
-
usageMap.set(
|
|
911
|
+
usageMap.set(getNodeText(id, sourceCode), existing);
|
|
911
912
|
}
|
|
912
913
|
// decorator → call_expression → identifier (e.g., @Component())
|
|
913
914
|
const callExpr = findChildOfType(node, 'call_expression');
|
|
914
915
|
if (callExpr) {
|
|
915
916
|
const callee = callExpr.children?.[0];
|
|
916
|
-
if (callee?.type === 'identifier' && importNames.has(
|
|
917
|
+
if (callee?.type === 'identifier' && importNames.has(getNodeText(callee, sourceCode))) {
|
|
917
918
|
const { line } = bridgeGetLineAndColumn(callee);
|
|
918
|
-
const existing = usageMap.get(
|
|
919
|
+
const existing = usageMap.get(getNodeText(callee, sourceCode)) || {
|
|
919
920
|
usageType: 'direct',
|
|
920
921
|
usageCount: 0,
|
|
921
922
|
lineNumbers: [],
|
|
922
923
|
};
|
|
923
924
|
existing.usageCount++;
|
|
924
925
|
existing.lineNumbers.push(line);
|
|
925
|
-
usageMap.set(
|
|
926
|
+
usageMap.set(getNodeText(callee, sourceCode), existing);
|
|
926
927
|
}
|
|
927
928
|
}
|
|
928
929
|
}
|
|
@@ -930,44 +931,44 @@ export function extractIdentifierUsage(root, sourceCode, importNames) {
|
|
|
930
931
|
else if (node.type === 'pair') {
|
|
931
932
|
const key = node.children?.find(c => c.type === 'property_identifier');
|
|
932
933
|
const value = node.children?.find(c => c.type === 'identifier' && c !== key);
|
|
933
|
-
if (value && importNames.has(
|
|
934
|
+
if (value && importNames.has(getNodeText(value, sourceCode))) {
|
|
934
935
|
const { line } = bridgeGetLineAndColumn(value);
|
|
935
|
-
const existing = usageMap.get(
|
|
936
|
+
const existing = usageMap.get(getNodeText(value, sourceCode)) || {
|
|
936
937
|
usageType: 'direct',
|
|
937
938
|
usageCount: 0,
|
|
938
939
|
lineNumbers: [],
|
|
939
940
|
};
|
|
940
941
|
existing.usageCount++;
|
|
941
942
|
existing.lineNumbers.push(line);
|
|
942
|
-
usageMap.set(
|
|
943
|
+
usageMap.set(getNodeText(value, sourceCode), existing);
|
|
943
944
|
}
|
|
944
945
|
}
|
|
945
946
|
// --- Shorthand property assignments: { ComponentA, ComponentB } ---
|
|
946
947
|
else if (node.type === 'shorthand_property_identifier') {
|
|
947
948
|
// The value node is a reference to an imported name
|
|
948
949
|
const ref = node.children?.find(c => c.type === 'identifier');
|
|
949
|
-
if (ref && importNames.has(
|
|
950
|
+
if (ref && importNames.has(getNodeText(ref, sourceCode))) {
|
|
950
951
|
const { line } = bridgeGetLineAndColumn(ref);
|
|
951
|
-
const existing = usageMap.get(
|
|
952
|
+
const existing = usageMap.get(getNodeText(ref, sourceCode)) || {
|
|
952
953
|
usageType: 'direct',
|
|
953
954
|
usageCount: 0,
|
|
954
955
|
lineNumbers: [],
|
|
955
956
|
};
|
|
956
957
|
existing.usageCount++;
|
|
957
958
|
existing.lineNumbers.push(line);
|
|
958
|
-
usageMap.set(
|
|
959
|
+
usageMap.set(getNodeText(ref, sourceCode), existing);
|
|
959
960
|
}
|
|
960
|
-
else if (ref && importNames.has(
|
|
961
|
+
else if (ref && importNames.has(getNodeText(ref, sourceCode))) {
|
|
961
962
|
// shorthand_property_identifier might itself be just text
|
|
962
963
|
const { line } = bridgeGetLineAndColumn(node);
|
|
963
|
-
const existing = usageMap.get(
|
|
964
|
+
const existing = usageMap.get(getNodeText(node, sourceCode)) || {
|
|
964
965
|
usageType: 'direct',
|
|
965
966
|
usageCount: 0,
|
|
966
967
|
lineNumbers: [],
|
|
967
968
|
};
|
|
968
969
|
existing.usageCount++;
|
|
969
970
|
existing.lineNumbers.push(line);
|
|
970
|
-
usageMap.set(
|
|
971
|
+
usageMap.set(getNodeText(node, sourceCode), existing);
|
|
971
972
|
}
|
|
972
973
|
}
|
|
973
974
|
});
|
|
@@ -980,7 +981,7 @@ export function extractIdentifierUsage(root, sourceCode, importNames) {
|
|
|
980
981
|
* Check if a function name is defined locally in the file.
|
|
981
982
|
* Uses tree-sitter instead of TS API.
|
|
982
983
|
*/
|
|
983
|
-
export function isLocalFunction(name, root) {
|
|
984
|
+
export function isLocalFunction(name, root, sourceCode) {
|
|
984
985
|
let found = false;
|
|
985
986
|
walkAST(root, (node) => {
|
|
986
987
|
if (found)
|
|
@@ -988,7 +989,7 @@ export function isLocalFunction(name, root) {
|
|
|
988
989
|
// function declarations
|
|
989
990
|
if (node.type === 'function_declaration') {
|
|
990
991
|
const nameNode = findChildOfType(node, 'identifier');
|
|
991
|
-
if (nameNode &&
|
|
992
|
+
if (nameNode && getNodeText(nameNode, sourceCode) === name) {
|
|
992
993
|
found = true;
|
|
993
994
|
}
|
|
994
995
|
}
|
|
@@ -996,14 +997,14 @@ export function isLocalFunction(name, root) {
|
|
|
996
997
|
if (node.type === 'variable_declarator') {
|
|
997
998
|
const nameNode = findChildOfType(node, 'identifier');
|
|
998
999
|
const initializer = node.children?.find(c => c.type === 'arrow_function' || c.type === 'function_expression');
|
|
999
|
-
if (nameNode && initializer &&
|
|
1000
|
+
if (nameNode && initializer && getNodeText(nameNode, sourceCode) === name) {
|
|
1000
1001
|
found = true;
|
|
1001
1002
|
}
|
|
1002
1003
|
}
|
|
1003
1004
|
// class declarations
|
|
1004
1005
|
if (node.type === 'class_declaration') {
|
|
1005
1006
|
const nameNode = findChildOfType(node, 'identifier');
|
|
1006
|
-
if (nameNode &&
|
|
1007
|
+
if (nameNode && getNodeText(nameNode, sourceCode) === name) {
|
|
1007
1008
|
found = true;
|
|
1008
1009
|
}
|
|
1009
1010
|
}
|