code-auditor-mcp 3.9.11 → 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 +200 -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 +20 -0
- package/dist/installer.d.ts.map +1 -1
- package/dist/installer.js +58 -0
- 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 +129 -26
- 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
|
@@ -13,8 +13,9 @@
|
|
|
13
13
|
* co-located in TsSafetyAnalysis (TypeScript forbids a base class calling a
|
|
14
14
|
* subclass method, so those must live in one class).
|
|
15
15
|
*/
|
|
16
|
-
import {
|
|
16
|
+
import { parseWithRecovery } from '../tree-sitter/parser.js';
|
|
17
17
|
import { toASTNode, toSourceLocation } from '../tree-sitter/converter.js';
|
|
18
|
+
import { getRawNode } from '../tree-sitter/rawNode.js';
|
|
18
19
|
// ---------------------------------------------------------------------------
|
|
19
20
|
// Source code storage
|
|
20
21
|
// ---------------------------------------------------------------------------
|
|
@@ -34,12 +35,6 @@ const SAFE_STRING_NODE = {
|
|
|
34
35
|
type: 'string',
|
|
35
36
|
range: [-1, -1],
|
|
36
37
|
location: { start: { line: 0, column: 0 }, end: { line: 0, column: 0 } },
|
|
37
|
-
raw: {
|
|
38
|
-
type: 'string',
|
|
39
|
-
text: "''",
|
|
40
|
-
startIndex: -1,
|
|
41
|
-
endIndex: -1,
|
|
42
|
-
},
|
|
43
38
|
};
|
|
44
39
|
// ---------------------------------------------------------------------------
|
|
45
40
|
// Traversal + primitive helpers
|
|
@@ -74,14 +69,6 @@ class TsTraversalHelpers {
|
|
|
74
69
|
this.collectErrors(child, errors);
|
|
75
70
|
}
|
|
76
71
|
}
|
|
77
|
-
/** Find first child of node matching one of the given types. */
|
|
78
|
-
getChildByType(node, type) {
|
|
79
|
-
for (const child of node.children) {
|
|
80
|
-
if (child.type === type)
|
|
81
|
-
return child;
|
|
82
|
-
}
|
|
83
|
-
return null;
|
|
84
|
-
}
|
|
85
72
|
/** Find the first named child matching one of the given types. */
|
|
86
73
|
findFirstNamedChild(node, types) {
|
|
87
74
|
const typeSet = Array.isArray(types) ? new Set(types) : new Set([types]);
|
|
@@ -171,7 +158,7 @@ class TsTraversalHelpers {
|
|
|
171
158
|
}
|
|
172
159
|
/** Extract ordered parameter names from a function node. */
|
|
173
160
|
getParamNames(fnNode) {
|
|
174
|
-
const raw = fnNode
|
|
161
|
+
const raw = getRawNode(fnNode);
|
|
175
162
|
const paramsNode = raw.childForFieldName?.('parameters');
|
|
176
163
|
if (!paramsNode)
|
|
177
164
|
return [];
|
|
@@ -203,7 +190,7 @@ class TsTraversalHelpers {
|
|
|
203
190
|
}
|
|
204
191
|
/** Return the ASTNodes for a call expression's arguments. */
|
|
205
192
|
getCallArgASTNodes(callNode) {
|
|
206
|
-
const raw = callNode
|
|
193
|
+
const raw = getRawNode(callNode);
|
|
207
194
|
const argsNode = raw.childForFieldName?.('arguments');
|
|
208
195
|
if (!argsNode)
|
|
209
196
|
return [];
|
|
@@ -422,7 +409,7 @@ class TsNameDocumentation extends TsTraversalHelpers {
|
|
|
422
409
|
}
|
|
423
410
|
/** Match an ASTNode against a NodePattern. */
|
|
424
411
|
matchesPattern(node, pattern) {
|
|
425
|
-
const syntaxNode = node
|
|
412
|
+
const syntaxNode = getRawNode(node);
|
|
426
413
|
// type matching
|
|
427
414
|
if (pattern.type !== undefined) {
|
|
428
415
|
const types = Array.isArray(pattern.type) ? pattern.type : [pattern.type];
|
|
@@ -756,81 +743,6 @@ class TsExtraction extends TsNameDocumentation {
|
|
|
756
743
|
}
|
|
757
744
|
return undefined;
|
|
758
745
|
}
|
|
759
|
-
/** Collect static imports, dynamic `import()`, and `require()` calls. */
|
|
760
|
-
collectRawImport(node, results) {
|
|
761
|
-
if (node.type === 'import_statement') {
|
|
762
|
-
const source = this.getChildByType(node, 'string');
|
|
763
|
-
if (source) {
|
|
764
|
-
results.push({
|
|
765
|
-
moduleSpecifier: source.text.slice(1, -1), // strip quotes
|
|
766
|
-
isStatic: true,
|
|
767
|
-
isDynamic: false,
|
|
768
|
-
isRequire: false,
|
|
769
|
-
line: source.startPosition.row,
|
|
770
|
-
});
|
|
771
|
-
}
|
|
772
|
-
}
|
|
773
|
-
if (node.type === 'call_expression') {
|
|
774
|
-
const fn = node.firstChild;
|
|
775
|
-
if (fn?.type === 'import') {
|
|
776
|
-
this.pushCallImport(node, results, /* isRequire */ false);
|
|
777
|
-
}
|
|
778
|
-
else if (fn?.type === 'identifier' && fn.text === 'require') {
|
|
779
|
-
this.pushCallImport(node, results, /* isRequire */ true);
|
|
780
|
-
}
|
|
781
|
-
}
|
|
782
|
-
}
|
|
783
|
-
/** Push a `import('...')` or `require('...')` record for a call expression. */
|
|
784
|
-
pushCallImport(node, results, isRequire) {
|
|
785
|
-
const args = this.getChildByType(node, 'arguments');
|
|
786
|
-
const strNode = args ? this.findFirstNamedChild(args, 'string') : null;
|
|
787
|
-
if (!strNode)
|
|
788
|
-
return;
|
|
789
|
-
results.push({
|
|
790
|
-
moduleSpecifier: strNode.text.slice(1, -1),
|
|
791
|
-
isStatic: false,
|
|
792
|
-
isDynamic: !isRequire,
|
|
793
|
-
isRequire,
|
|
794
|
-
line: strNode.startPosition.row,
|
|
795
|
-
});
|
|
796
|
-
}
|
|
797
|
-
/** Collect the exported symbol(s) declared by a single `export_statement`. */
|
|
798
|
-
collectExportedSymbol(node, symbols) {
|
|
799
|
-
// export function foo / export class Foo / export const x
|
|
800
|
-
const declaration = this.findFirstNamedChild(node, [
|
|
801
|
-
'function_declaration',
|
|
802
|
-
'class_declaration',
|
|
803
|
-
'abstract_class_declaration',
|
|
804
|
-
'lexical_declaration',
|
|
805
|
-
'variable_declaration',
|
|
806
|
-
'interface_declaration',
|
|
807
|
-
'type_alias_declaration',
|
|
808
|
-
'enum_declaration',
|
|
809
|
-
]);
|
|
810
|
-
if (declaration) {
|
|
811
|
-
const name = this.extractName(declaration);
|
|
812
|
-
if (name) {
|
|
813
|
-
symbols.push({ name, line: declaration.startPosition.row });
|
|
814
|
-
return;
|
|
815
|
-
}
|
|
816
|
-
}
|
|
817
|
-
// export { foo, bar } or export { default }
|
|
818
|
-
const clause = this.getChildByType(node, 'export_clause');
|
|
819
|
-
if (clause) {
|
|
820
|
-
for (const child of clause.namedChildren) {
|
|
821
|
-
if (child.type === 'export_specifier') {
|
|
822
|
-
const nameNode = this.getChildByType(child, 'identifier');
|
|
823
|
-
if (nameNode) {
|
|
824
|
-
symbols.push({ name: nameNode.text, line: nameNode.startPosition.row });
|
|
825
|
-
}
|
|
826
|
-
}
|
|
827
|
-
}
|
|
828
|
-
}
|
|
829
|
-
// export default <expression>
|
|
830
|
-
if (node.childForFieldName?.('value')) {
|
|
831
|
-
symbols.push({ name: 'default', line: node.startPosition.row });
|
|
832
|
-
}
|
|
833
|
-
}
|
|
834
746
|
}
|
|
835
747
|
// ---------------------------------------------------------------------------
|
|
836
748
|
// Public LanguageAdapter surface: parsing, navigation, extraction
|
|
@@ -876,11 +788,6 @@ class TsPublicApi extends TsExtraction {
|
|
|
876
788
|
getChildren(node) {
|
|
877
789
|
return node.children ?? [];
|
|
878
790
|
}
|
|
879
|
-
getSiblings(node) {
|
|
880
|
-
if (!node.parent?.children)
|
|
881
|
-
return [];
|
|
882
|
-
return node.parent.children.filter((c) => c !== node);
|
|
883
|
-
}
|
|
884
791
|
getNodeType(node) {
|
|
885
792
|
return node.type;
|
|
886
793
|
}
|
|
@@ -888,17 +795,14 @@ class TsPublicApi extends TsExtraction {
|
|
|
888
795
|
return sourceCode.slice(node.range[0], node.range[1]);
|
|
889
796
|
}
|
|
890
797
|
getNodeName(node) {
|
|
891
|
-
const syntaxNode = node
|
|
798
|
+
const syntaxNode = getRawNode(node);
|
|
892
799
|
return this.extractName(syntaxNode);
|
|
893
800
|
}
|
|
894
|
-
getNodeLocation(node) {
|
|
895
|
-
return node.location;
|
|
896
|
-
}
|
|
897
801
|
extractFunctions(ast) {
|
|
898
802
|
const sourceCode = sourceCodeMap.get(ast) ?? '';
|
|
899
803
|
const functions = [];
|
|
900
804
|
this.walk(ast.root, (node) => {
|
|
901
|
-
const syntaxNode = node
|
|
805
|
+
const syntaxNode = getRawNode(node);
|
|
902
806
|
const type = syntaxNode.type;
|
|
903
807
|
if (type === 'function_declaration' ||
|
|
904
808
|
type === 'generator_function_declaration' ||
|
|
@@ -916,7 +820,7 @@ class TsPublicApi extends TsExtraction {
|
|
|
916
820
|
const sourceCode = sourceCodeMap.get(ast) ?? '';
|
|
917
821
|
const classes = [];
|
|
918
822
|
this.walk(ast.root, (node) => {
|
|
919
|
-
const syntaxNode = node
|
|
823
|
+
const syntaxNode = getRawNode(node);
|
|
920
824
|
if (syntaxNode.type === 'class_declaration' || syntaxNode.type === 'abstract_class_declaration') {
|
|
921
825
|
const cls = this.buildClassInfo(syntaxNode, sourceCode);
|
|
922
826
|
if (cls)
|
|
@@ -929,7 +833,7 @@ class TsPublicApi extends TsExtraction {
|
|
|
929
833
|
const sourceCode = sourceCodeMap.get(ast) ?? '';
|
|
930
834
|
const imports = [];
|
|
931
835
|
this.walk(ast.root, (node) => {
|
|
932
|
-
const syntaxNode = node
|
|
836
|
+
const syntaxNode = getRawNode(node);
|
|
933
837
|
if (syntaxNode.type === 'import_statement') {
|
|
934
838
|
const imp = this.buildImportInfo(syntaxNode, sourceCode);
|
|
935
839
|
if (imp)
|
|
@@ -942,7 +846,7 @@ class TsPublicApi extends TsExtraction {
|
|
|
942
846
|
const sourceCode = sourceCodeMap.get(ast) ?? '';
|
|
943
847
|
const exports = [];
|
|
944
848
|
this.walk(ast.root, (node) => {
|
|
945
|
-
const syntaxNode = node
|
|
849
|
+
const syntaxNode = getRawNode(node);
|
|
946
850
|
if (syntaxNode.type === 'export_statement') {
|
|
947
851
|
const ex = this.buildExportInfo(syntaxNode, sourceCode);
|
|
948
852
|
if (ex)
|
|
@@ -957,11 +861,11 @@ class TsPublicApi extends TsExtraction {
|
|
|
957
861
|
// ---------------------------------------------------------------------------
|
|
958
862
|
class TsPredicatesOptional extends TsPublicApi {
|
|
959
863
|
isClass(node) {
|
|
960
|
-
const type = node.
|
|
864
|
+
const type = (getRawNode(node)).type;
|
|
961
865
|
return type === 'class_declaration' || type === 'abstract_class_declaration' || type === 'class_expression';
|
|
962
866
|
}
|
|
963
867
|
isFunction(node) {
|
|
964
|
-
const type = node.
|
|
868
|
+
const type = (getRawNode(node)).type;
|
|
965
869
|
return (type === 'function_declaration' ||
|
|
966
870
|
type === 'function_expression' ||
|
|
967
871
|
type === 'arrow_function' ||
|
|
@@ -969,54 +873,34 @@ class TsPredicatesOptional extends TsPublicApi {
|
|
|
969
873
|
type === 'generator_function_expression');
|
|
970
874
|
}
|
|
971
875
|
isMethod(node) {
|
|
972
|
-
return node.
|
|
973
|
-
}
|
|
974
|
-
isInterface(node) {
|
|
975
|
-
return node.raw.type === 'interface_declaration';
|
|
976
|
-
}
|
|
977
|
-
isImport(node) {
|
|
978
|
-
return node.raw.type === 'import_statement';
|
|
979
|
-
}
|
|
980
|
-
isExport(node) {
|
|
981
|
-
return node.raw.type === 'export_statement';
|
|
876
|
+
return (getRawNode(node)).type === 'method_definition';
|
|
982
877
|
}
|
|
983
878
|
isLoop(node) {
|
|
984
|
-
const type = node.
|
|
879
|
+
const type = (getRawNode(node)).type;
|
|
985
880
|
return (type === 'for_statement' ||
|
|
986
881
|
type === 'for_in_statement' ||
|
|
987
882
|
type === 'while_statement' ||
|
|
988
883
|
type === 'do_statement');
|
|
989
884
|
}
|
|
990
|
-
isConditional(node) {
|
|
991
|
-
const type = node.raw.type;
|
|
992
|
-
return (type === 'if_statement' ||
|
|
993
|
-
type === 'switch_statement' ||
|
|
994
|
-
type === 'ternary_expression' ||
|
|
995
|
-
type === 'switch_case');
|
|
996
|
-
}
|
|
997
885
|
isVariableDeclaration(node) {
|
|
998
|
-
const type = node.
|
|
886
|
+
const type = (getRawNode(node)).type;
|
|
999
887
|
return (type === 'variable_declaration' ||
|
|
1000
888
|
type === 'lexical_declaration' ||
|
|
1001
889
|
type === 'variable_declarator');
|
|
1002
890
|
}
|
|
1003
|
-
getTypeInfo(node) {
|
|
1004
|
-
const syntaxNode = node.raw;
|
|
1005
|
-
return this.extractTypeAnnotation(syntaxNode);
|
|
1006
|
-
}
|
|
1007
891
|
getDocumentation(node) {
|
|
1008
|
-
const syntaxNode = node
|
|
892
|
+
const syntaxNode = getRawNode(node);
|
|
1009
893
|
return this.extractDocumentation(syntaxNode);
|
|
1010
894
|
}
|
|
1011
895
|
getComplexity(node) {
|
|
1012
|
-
const syntaxNode = node
|
|
896
|
+
const syntaxNode = getRawNode(node);
|
|
1013
897
|
return this.calculateCyclomaticComplexity(syntaxNode);
|
|
1014
898
|
}
|
|
1015
899
|
extractInterfaces(ast) {
|
|
1016
900
|
const sourceCode = sourceCodeMap.get(ast) ?? '';
|
|
1017
901
|
const interfaces = [];
|
|
1018
902
|
this.walk(ast.root, (node) => {
|
|
1019
|
-
const syntaxNode = node
|
|
903
|
+
const syntaxNode = getRawNode(node);
|
|
1020
904
|
if (syntaxNode.type === 'interface_declaration') {
|
|
1021
905
|
const iface = this.buildInterfaceInfo(syntaxNode, sourceCode);
|
|
1022
906
|
if (iface)
|
|
@@ -1025,24 +909,6 @@ class TsPredicatesOptional extends TsPublicApi {
|
|
|
1025
909
|
});
|
|
1026
910
|
return interfaces;
|
|
1027
911
|
}
|
|
1028
|
-
extractRawImports(_filePath, content) {
|
|
1029
|
-
const results = [];
|
|
1030
|
-
const parser = getParser('typescript');
|
|
1031
|
-
const tree = parser.parse(content);
|
|
1032
|
-
if (!tree)
|
|
1033
|
-
return results;
|
|
1034
|
-
this.walkRaw(tree.rootNode, (node) => this.collectRawImport(node, results));
|
|
1035
|
-
return results;
|
|
1036
|
-
}
|
|
1037
|
-
extractExportedSymbols(ast) {
|
|
1038
|
-
const symbols = [];
|
|
1039
|
-
this.walk(ast.root, (astNode) => {
|
|
1040
|
-
const node = astNode.raw;
|
|
1041
|
-
if (node.type === 'export_statement')
|
|
1042
|
-
this.collectExportedSymbol(node, symbols);
|
|
1043
|
-
});
|
|
1044
|
-
return symbols;
|
|
1045
|
-
}
|
|
1046
912
|
}
|
|
1047
913
|
// ---------------------------------------------------------------------------
|
|
1048
914
|
// Scope + static-value resolution
|
|
@@ -1099,7 +965,7 @@ class TsScopeStatic extends TsPredicatesOptional {
|
|
|
1099
965
|
findEnclosingScope(node, ast) {
|
|
1100
966
|
let current = node;
|
|
1101
967
|
while (current) {
|
|
1102
|
-
const type = current.
|
|
968
|
+
const type = (getRawNode(current)).type;
|
|
1103
969
|
if (type === 'function_declaration' ||
|
|
1104
970
|
type === 'arrow_function' ||
|
|
1105
971
|
type === 'function_expression' ||
|
|
@@ -1119,14 +985,14 @@ class TsScopeStatic extends TsPredicatesOptional {
|
|
|
1119
985
|
const parent = declNode.parent;
|
|
1120
986
|
if (!parent)
|
|
1121
987
|
return null;
|
|
1122
|
-
const pType = parent.
|
|
988
|
+
const pType = (getRawNode(parent)).type;
|
|
1123
989
|
// The declarator's parent is lexical_declaration; the for-statement
|
|
1124
990
|
// is the parent of that.
|
|
1125
991
|
if (pType === 'lexical_declaration' || pType === 'variable_declaration') {
|
|
1126
992
|
const grandparent = parent.parent;
|
|
1127
993
|
if (!grandparent)
|
|
1128
994
|
return null;
|
|
1129
|
-
const gpType = grandparent.
|
|
995
|
+
const gpType = (getRawNode(grandparent)).type;
|
|
1130
996
|
if (gpType === 'for_of_statement' || gpType === 'for_in_statement') {
|
|
1131
997
|
return grandparent;
|
|
1132
998
|
}
|
|
@@ -1137,14 +1003,14 @@ class TsScopeStatic extends TsPredicatesOptional {
|
|
|
1137
1003
|
findDeclarationInScope(scopeRoot, targetName) {
|
|
1138
1004
|
const results = [];
|
|
1139
1005
|
this.walk(scopeRoot, (astNode) => {
|
|
1140
|
-
const t = astNode.
|
|
1006
|
+
const t = (getRawNode(astNode)).type;
|
|
1141
1007
|
if (t === 'variable_declarator') {
|
|
1142
|
-
const raw = astNode
|
|
1008
|
+
const raw = getRawNode(astNode);
|
|
1143
1009
|
const nameNode = raw.childForFieldName?.('name') ?? null;
|
|
1144
1010
|
const name = nameNode ? nameNode.text : '?';
|
|
1145
1011
|
const parent = astNode.parent;
|
|
1146
1012
|
if (parent) {
|
|
1147
|
-
const pType = parent.
|
|
1013
|
+
const pType = (getRawNode(parent)).type;
|
|
1148
1014
|
if (pType === 'lexical_declaration' || pType === 'variable_declaration') {
|
|
1149
1015
|
if (name === targetName) {
|
|
1150
1016
|
results.push(astNode);
|
|
@@ -1166,7 +1032,7 @@ class TsScopeStatic extends TsPredicatesOptional {
|
|
|
1166
1032
|
// Early exit — first match wins.
|
|
1167
1033
|
if (results.length > 0)
|
|
1168
1034
|
return;
|
|
1169
|
-
const raw = astNode
|
|
1035
|
+
const raw = getRawNode(astNode);
|
|
1170
1036
|
const type = raw.type;
|
|
1171
1037
|
if (type === 'import_specifier') {
|
|
1172
1038
|
// named import: import { X } from … or import { X as Y } from …
|
|
@@ -1177,7 +1043,7 @@ class TsScopeStatic extends TsPredicatesOptional {
|
|
|
1177
1043
|
results.push({ isStatic: true, declLine: astNode.location.start.line });
|
|
1178
1044
|
}
|
|
1179
1045
|
}
|
|
1180
|
-
else if (type === 'import' && astNode.parent?.
|
|
1046
|
+
else if (type === 'import' && astNode.parent?.type === 'import_clause') {
|
|
1181
1047
|
// default import: import X from … — the 'import' node is a child of
|
|
1182
1048
|
// 'import_clause', and its text is the local binding name.
|
|
1183
1049
|
if (raw.text === name) {
|
|
@@ -1204,11 +1070,11 @@ class TsScopeStatic extends TsPredicatesOptional {
|
|
|
1204
1070
|
this.walk(scopeRoot, (astNode) => {
|
|
1205
1071
|
if (found)
|
|
1206
1072
|
return;
|
|
1207
|
-
const t = astNode.
|
|
1073
|
+
const t = (getRawNode(astNode)).type;
|
|
1208
1074
|
if (t === 'assignment_expression' || t === 'augmented_assignment_expression') {
|
|
1209
1075
|
if (astNode.location.start.line < declLine)
|
|
1210
1076
|
return;
|
|
1211
|
-
const raw = astNode
|
|
1077
|
+
const raw = getRawNode(astNode);
|
|
1212
1078
|
const left = raw.childForFieldName?.('left');
|
|
1213
1079
|
if (left && left.type === 'identifier' && left.text === targetName) {
|
|
1214
1080
|
found = true;
|
|
@@ -1223,7 +1089,7 @@ class TsScopeStatic extends TsPredicatesOptional {
|
|
|
1223
1089
|
this.walk(ast.root, (node) => {
|
|
1224
1090
|
if (result)
|
|
1225
1091
|
return;
|
|
1226
|
-
const raw = node
|
|
1092
|
+
const raw = getRawNode(node);
|
|
1227
1093
|
const t = raw.type;
|
|
1228
1094
|
if (t === 'function_declaration' || t === 'generator_function_declaration') {
|
|
1229
1095
|
const nameNode = raw.childForFieldName?.('name');
|
|
@@ -1243,7 +1109,7 @@ class TsScopeStatic extends TsPredicatesOptional {
|
|
|
1243
1109
|
}
|
|
1244
1110
|
/** Extract a function's name (named functions and arrow-function assignments). */
|
|
1245
1111
|
getFunctionName(node) {
|
|
1246
|
-
const raw = node
|
|
1112
|
+
const raw = getRawNode(node);
|
|
1247
1113
|
const t = raw.type;
|
|
1248
1114
|
if (t === 'function_declaration' || t === 'generator_function_declaration'
|
|
1249
1115
|
|| t === 'function_expression' || t === 'method_definition') {
|
|
@@ -1254,7 +1120,7 @@ class TsScopeStatic extends TsPredicatesOptional {
|
|
|
1254
1120
|
if (t === 'arrow_function') {
|
|
1255
1121
|
const parent = node.parent;
|
|
1256
1122
|
if (parent) {
|
|
1257
|
-
const pRaw = parent
|
|
1123
|
+
const pRaw = getRawNode(parent);
|
|
1258
1124
|
if (pRaw.type === 'variable_declarator') {
|
|
1259
1125
|
const nameNode = pRaw.childForFieldName?.('name');
|
|
1260
1126
|
if (nameNode && nameNode.type === 'identifier')
|
|
@@ -1268,7 +1134,7 @@ class TsScopeStatic extends TsPredicatesOptional {
|
|
|
1268
1134
|
findCallSites(fnName, ast) {
|
|
1269
1135
|
const sites = [];
|
|
1270
1136
|
this.walk(ast.root, (node) => {
|
|
1271
|
-
const raw = node
|
|
1137
|
+
const raw = getRawNode(node);
|
|
1272
1138
|
if (raw.type !== 'call_expression')
|
|
1273
1139
|
return;
|
|
1274
1140
|
const fn = raw.childForFieldName?.('function');
|
|
@@ -1290,11 +1156,11 @@ class TsDynamicStringConstruction extends TsScopeStatic {
|
|
|
1290
1156
|
* String-like identifiers and plain string literals are never dynamic.
|
|
1291
1157
|
*/
|
|
1292
1158
|
isDynamicStringConstruction(node) {
|
|
1293
|
-
const type = node.
|
|
1159
|
+
const type = (getRawNode(node)).type;
|
|
1294
1160
|
if (type === 'template_string') {
|
|
1295
1161
|
// template_string is dynamic only if it has template_substitution children
|
|
1296
1162
|
for (const child of node.children ?? []) {
|
|
1297
|
-
if (child.
|
|
1163
|
+
if ((getRawNode(child)).type === 'template_substitution') {
|
|
1298
1164
|
return true;
|
|
1299
1165
|
}
|
|
1300
1166
|
}
|
|
@@ -1303,20 +1169,20 @@ class TsDynamicStringConstruction extends TsScopeStatic {
|
|
|
1303
1169
|
if (type === 'binary_expression') {
|
|
1304
1170
|
// Check for string concatenation: operands include a string literal
|
|
1305
1171
|
const children = node.children ?? [];
|
|
1306
|
-
const hasStringLiteral = children.some(c => c.
|
|
1172
|
+
const hasStringLiteral = children.some(c => (getRawNode(c)).type === 'string');
|
|
1307
1173
|
return hasStringLiteral;
|
|
1308
1174
|
}
|
|
1309
1175
|
if (type === 'call_expression') {
|
|
1310
1176
|
// Check for .concat() calls
|
|
1311
|
-
const text = node.
|
|
1177
|
+
const text = (getRawNode(node)).text;
|
|
1312
1178
|
if (text.includes('.concat(') || text.includes('?.concat('))
|
|
1313
1179
|
return true;
|
|
1314
1180
|
// Recurse into arguments: query(binaryExpression) where the argument
|
|
1315
1181
|
// itself is a dynamic string construction.
|
|
1316
1182
|
for (const child of node.children ?? []) {
|
|
1317
|
-
if (child.
|
|
1183
|
+
if ((getRawNode(child)).type === 'arguments') {
|
|
1318
1184
|
for (const arg of child.children ?? []) {
|
|
1319
|
-
const argType = arg.
|
|
1185
|
+
const argType = (getRawNode(arg)).type;
|
|
1320
1186
|
if (argType === '(' || argType === ')' || argType === ',')
|
|
1321
1187
|
continue;
|
|
1322
1188
|
if (this.isDynamicStringConstruction(arg))
|
|
@@ -1335,7 +1201,7 @@ class TsDynamicStringConstruction extends TsScopeStatic {
|
|
|
1335
1201
|
* and non-literal arguments for concat calls.
|
|
1336
1202
|
*/
|
|
1337
1203
|
getDynamicParts(node, sourceCode) {
|
|
1338
|
-
const type = node.
|
|
1204
|
+
const type = (getRawNode(node)).type;
|
|
1339
1205
|
if (type === 'call_expression') {
|
|
1340
1206
|
const nested = this.getNestedDynamicCallParts(node, sourceCode);
|
|
1341
1207
|
if (nested)
|
|
@@ -1351,14 +1217,14 @@ class TsDynamicStringConstruction extends TsScopeStatic {
|
|
|
1351
1217
|
/** For a non-`.concat()` call, recurse into the first argument that is itself
|
|
1352
1218
|
* a dynamic string construction; null when there is none (or it's .concat). */
|
|
1353
1219
|
getNestedDynamicCallParts(node, sourceCode) {
|
|
1354
|
-
const text = node.
|
|
1220
|
+
const text = (getRawNode(node)).text;
|
|
1355
1221
|
if (text.includes('.concat(') || text.includes('?.concat('))
|
|
1356
1222
|
return null;
|
|
1357
1223
|
for (const child of node.children ?? []) {
|
|
1358
|
-
if (child.
|
|
1224
|
+
if ((getRawNode(child)).type !== 'arguments')
|
|
1359
1225
|
continue;
|
|
1360
1226
|
for (const arg of child.children ?? []) {
|
|
1361
|
-
const argType = arg.
|
|
1227
|
+
const argType = (getRawNode(arg)).type;
|
|
1362
1228
|
if (argType === '(' || argType === ')' || argType === ',')
|
|
1363
1229
|
continue;
|
|
1364
1230
|
if (this.isDynamicStringConstruction(arg)) {
|
|
@@ -1372,13 +1238,13 @@ class TsDynamicStringConstruction extends TsScopeStatic {
|
|
|
1372
1238
|
getCallArgParts(node) {
|
|
1373
1239
|
const parts = [];
|
|
1374
1240
|
for (const child of node.children ?? []) {
|
|
1375
|
-
if (child.
|
|
1241
|
+
if ((getRawNode(child)).type !== 'arguments')
|
|
1376
1242
|
continue;
|
|
1377
1243
|
for (const arg of child.children ?? []) {
|
|
1378
|
-
const argType = arg.
|
|
1244
|
+
const argType = (getRawNode(arg)).type;
|
|
1379
1245
|
if (argType === '(' || argType === ')' || argType === ',')
|
|
1380
1246
|
continue;
|
|
1381
|
-
const text = arg.
|
|
1247
|
+
const text = (getRawNode(arg)).text.trim();
|
|
1382
1248
|
const isId = /^[$\p{L}_][\p{L}\p{N}_$]*$/u.test(text);
|
|
1383
1249
|
parts.push({ text, isIdentifier: isId, node: arg });
|
|
1384
1250
|
}
|
|
@@ -1389,7 +1255,7 @@ class TsDynamicStringConstruction extends TsScopeStatic {
|
|
|
1389
1255
|
getTemplateStringParts(node, sourceCode) {
|
|
1390
1256
|
const parts = [];
|
|
1391
1257
|
for (const child of node.children ?? []) {
|
|
1392
|
-
if (child.
|
|
1258
|
+
if ((getRawNode(child)).type !== 'template_substitution')
|
|
1393
1259
|
continue;
|
|
1394
1260
|
const text = sourceCode.slice(child.range[0], child.range[1]);
|
|
1395
1261
|
// Strip the ${ } wrapper to get the inner identifier/expression.
|
|
@@ -1399,7 +1265,7 @@ class TsDynamicStringConstruction extends TsScopeStatic {
|
|
|
1399
1265
|
// isSafeInterpolation() cross-function safety checks.
|
|
1400
1266
|
let exprNode;
|
|
1401
1267
|
for (const subChild of child.children ?? []) {
|
|
1402
|
-
if (subChild.
|
|
1268
|
+
if ((getRawNode(subChild)).type !== 'template_substitution') {
|
|
1403
1269
|
exprNode = subChild;
|
|
1404
1270
|
break;
|
|
1405
1271
|
}
|
|
@@ -1412,7 +1278,7 @@ class TsDynamicStringConstruction extends TsScopeStatic {
|
|
|
1412
1278
|
getBinaryExpressionParts(node, sourceCode) {
|
|
1413
1279
|
const parts = [];
|
|
1414
1280
|
for (const child of node.children ?? []) {
|
|
1415
|
-
const childType = child.
|
|
1281
|
+
const childType = (getRawNode(child)).type;
|
|
1416
1282
|
if (childType === 'string' || childType === '+' || childType === 'template_string')
|
|
1417
1283
|
continue;
|
|
1418
1284
|
const text = sourceCode.slice(child.range[0], child.range[1]);
|
|
@@ -1457,7 +1323,7 @@ class TsConstantResolution extends TsDynamicStringConstruction {
|
|
|
1457
1323
|
* declarations survive (`.` doesn't match `\n`). */
|
|
1458
1324
|
resolveFromDeclaration(declNode, idName, sourceCode, scope) {
|
|
1459
1325
|
const { scopeRoot, enclosing, ast } = scope;
|
|
1460
|
-
const raw = declNode
|
|
1326
|
+
const raw = getRawNode(declNode);
|
|
1461
1327
|
const valueNode = raw.childForFieldName?.('value');
|
|
1462
1328
|
const declLine = declNode.location.start.line;
|
|
1463
1329
|
const reassigned = this.hasReassignment(scopeRoot, idName, declLine);
|
|
@@ -1524,7 +1390,7 @@ class TsConstantResolution extends TsDynamicStringConstruction {
|
|
|
1524
1390
|
*/
|
|
1525
1391
|
traceForInLoopVariable(identifierNode, idName, sourceCode, scope) {
|
|
1526
1392
|
const { scopeRoot, enclosing, ast } = scope;
|
|
1527
|
-
const idRaw = identifierNode
|
|
1393
|
+
const idRaw = getRawNode(identifierNode);
|
|
1528
1394
|
let tsCurrent = idRaw.parent;
|
|
1529
1395
|
while (tsCurrent) {
|
|
1530
1396
|
if (tsCurrent.type === 'for_in_statement') {
|
|
@@ -1535,7 +1401,7 @@ class TsConstantResolution extends TsDynamicStringConstruction {
|
|
|
1535
1401
|
const iterName = right.text;
|
|
1536
1402
|
let iterDecl = this.resolveDeclaration(scopeRoot, enclosing, ast, iterName);
|
|
1537
1403
|
if (iterDecl) {
|
|
1538
|
-
const iterRaw = iterDecl
|
|
1404
|
+
const iterRaw = getRawNode(iterDecl);
|
|
1539
1405
|
const iterValue = iterRaw.childForFieldName?.('value');
|
|
1540
1406
|
const iterLine = iterDecl.location.start.line;
|
|
1541
1407
|
const iterReassigned = this.hasReassignment(scopeRoot, iterName, iterLine)
|
|
@@ -1560,7 +1426,7 @@ class TsConstantResolution extends TsDynamicStringConstruction {
|
|
|
1560
1426
|
const forParent = this.findEnclosingForStatement(declNode);
|
|
1561
1427
|
if (!forParent)
|
|
1562
1428
|
return false;
|
|
1563
|
-
const forRaw = forParent
|
|
1429
|
+
const forRaw = getRawNode(forParent);
|
|
1564
1430
|
const iterable = forRaw.childForFieldName?.('right');
|
|
1565
1431
|
if (!iterable || iterable.type !== 'identifier')
|
|
1566
1432
|
return false;
|
|
@@ -1568,7 +1434,7 @@ class TsConstantResolution extends TsDynamicStringConstruction {
|
|
|
1568
1434
|
let iterDecl = this.resolveDeclaration(scopeRoot, enclosing, ast, iterName);
|
|
1569
1435
|
if (!iterDecl)
|
|
1570
1436
|
return false;
|
|
1571
|
-
const iterRaw = iterDecl
|
|
1437
|
+
const iterRaw = getRawNode(iterDecl);
|
|
1572
1438
|
const iterValue = iterRaw.childForFieldName?.('value');
|
|
1573
1439
|
const iterLine = iterDecl.location.start.line;
|
|
1574
1440
|
const iterReassigned = this.hasReassignment(scopeRoot, iterName, iterLine)
|
|
@@ -1589,7 +1455,7 @@ class TsConstantResolution extends TsDynamicStringConstruction {
|
|
|
1589
1455
|
}
|
|
1590
1456
|
if (!linkedDecl)
|
|
1591
1457
|
return false;
|
|
1592
|
-
const linkedRaw = linkedDecl
|
|
1458
|
+
const linkedRaw = getRawNode(linkedDecl);
|
|
1593
1459
|
const linkedValue = linkedRaw.childForFieldName?.('value');
|
|
1594
1460
|
const linkedLine = linkedDecl.location.start.line;
|
|
1595
1461
|
const linkedReassigned = this.hasReassignment(scopeRoot, linkedName, linkedLine)
|
|
@@ -1614,7 +1480,7 @@ class TsConstantResolution extends TsDynamicStringConstruction {
|
|
|
1614
1480
|
* before its use. Guards throw on invalid input, so a parameter that has
|
|
1615
1481
|
* passed one cannot carry unvalidated attacker data past the check. */
|
|
1616
1482
|
isGuardValidatedParameter(identifierNode, ast) {
|
|
1617
|
-
const idRaw = identifierNode
|
|
1483
|
+
const idRaw = getRawNode(identifierNode);
|
|
1618
1484
|
const paramName = idRaw.text;
|
|
1619
1485
|
const enclosing = this.findEnclosingScope(identifierNode, ast);
|
|
1620
1486
|
if (!enclosing || enclosing === ast.root)
|
|
@@ -1625,7 +1491,7 @@ class TsConstantResolution extends TsDynamicStringConstruction {
|
|
|
1625
1491
|
this.walk(enclosing, (node) => {
|
|
1626
1492
|
if (guarded)
|
|
1627
1493
|
return;
|
|
1628
|
-
const raw = node
|
|
1494
|
+
const raw = getRawNode(node);
|
|
1629
1495
|
if (raw.type !== 'call_expression')
|
|
1630
1496
|
return;
|
|
1631
1497
|
const fn = raw.childForFieldName?.('function');
|
|
@@ -1668,7 +1534,7 @@ class TsSafetyAnalysis extends TsConstantResolution {
|
|
|
1668
1534
|
return false;
|
|
1669
1535
|
if (node === SAFE_STRING_NODE)
|
|
1670
1536
|
return true;
|
|
1671
|
-
const raw = node
|
|
1537
|
+
const raw = getRawNode(node);
|
|
1672
1538
|
// `seen` is path-based (added on entry, removed on exit) and keyed by the
|
|
1673
1539
|
// node's unique `id` — NOT `startIndex`, which collides between an
|
|
1674
1540
|
// expression and its leading operand (a `binary_expression` and its left
|
|
@@ -1719,7 +1585,7 @@ class TsSafetyAnalysis extends TsConstantResolution {
|
|
|
1719
1585
|
evaluateStructuralExpression(node, raw, ctx) {
|
|
1720
1586
|
switch (raw.type) {
|
|
1721
1587
|
case 'parenthesized_expression': {
|
|
1722
|
-
const inner = (node.children ?? []).find((c) => !['(', ')'].includes(c.
|
|
1588
|
+
const inner = (node.children ?? []).find((c) => !['(', ')'].includes((getRawNode(c)).type));
|
|
1723
1589
|
return this.isSafeExpression(inner ?? null, ctx);
|
|
1724
1590
|
}
|
|
1725
1591
|
case 'as_expression':
|
|
@@ -1748,7 +1614,7 @@ class TsSafetyAnalysis extends TsConstantResolution {
|
|
|
1748
1614
|
/** Identifier safety: a bound parameter, compile-time constant, or validated
|
|
1749
1615
|
* parameter at all call sites. */
|
|
1750
1616
|
isSafeIdentifier(node, ctx) {
|
|
1751
|
-
const name = node.
|
|
1617
|
+
const name = (getRawNode(node)).text;
|
|
1752
1618
|
// A parameter bound at the current call site — recurse into its value.
|
|
1753
1619
|
if (ctx.paramMap.has(name)) {
|
|
1754
1620
|
return this.isSafeExpression(ctx.paramMap.get(name) ?? null, ctx);
|
|
@@ -1772,10 +1638,10 @@ class TsSafetyAnalysis extends TsConstantResolution {
|
|
|
1772
1638
|
/** A template string is safe only if every `${…}` substitution is safe. */
|
|
1773
1639
|
isSafeTemplateString(node, ctx) {
|
|
1774
1640
|
for (const child of node.children ?? []) {
|
|
1775
|
-
const ct = child.
|
|
1641
|
+
const ct = (getRawNode(child)).type;
|
|
1776
1642
|
if (ct !== 'template_substitution')
|
|
1777
1643
|
continue;
|
|
1778
|
-
const inner = (child.children ?? []).find((c) => c.
|
|
1644
|
+
const inner = (child.children ?? []).find((c) => (getRawNode(c)).type !== 'template_substitution') ?? child;
|
|
1779
1645
|
if (!this.isSafeExpression(inner, ctx)) {
|
|
1780
1646
|
return false;
|
|
1781
1647
|
}
|
|
@@ -1785,7 +1651,7 @@ class TsSafetyAnalysis extends TsConstantResolution {
|
|
|
1785
1651
|
/** An array literal is safe only if every element is safe. */
|
|
1786
1652
|
isSafeArray(node, ctx) {
|
|
1787
1653
|
for (const child of node.children ?? []) {
|
|
1788
|
-
const ct = child.
|
|
1654
|
+
const ct = (getRawNode(child)).type;
|
|
1789
1655
|
if (ct === ',' || ct === '[' || ct === ']')
|
|
1790
1656
|
continue;
|
|
1791
1657
|
if (!this.isSafeExpression(child, ctx)) {
|
|
@@ -1796,7 +1662,7 @@ class TsSafetyAnalysis extends TsConstantResolution {
|
|
|
1796
1662
|
}
|
|
1797
1663
|
/** Decide whether a call expression is provably safe to embed in SQL. */
|
|
1798
1664
|
isSafeCallExpression(node, ctx) {
|
|
1799
|
-
const raw = node
|
|
1665
|
+
const raw = getRawNode(node);
|
|
1800
1666
|
const fnNode = raw.childForFieldName?.('function');
|
|
1801
1667
|
if (!fnNode)
|
|
1802
1668
|
return false;
|
|
@@ -1815,7 +1681,7 @@ class TsSafetyAnalysis extends TsConstantResolution {
|
|
|
1815
1681
|
/** True when the node is `.join(...)` over `.map(...)` of a static array whose
|
|
1816
1682
|
* callback body is safe for every element. */
|
|
1817
1683
|
isSafeMapJoin(node, ctx) {
|
|
1818
|
-
const raw = node
|
|
1684
|
+
const raw = getRawNode(node);
|
|
1819
1685
|
const fnNode = raw.childForFieldName?.('function');
|
|
1820
1686
|
if (!fnNode || fnNode.type !== 'member_expression')
|
|
1821
1687
|
return false;
|
|
@@ -1851,7 +1717,7 @@ class TsSafetyAnalysis extends TsConstantResolution {
|
|
|
1851
1717
|
/** True when the node is a call to a local (in-file) function whose body is
|
|
1852
1718
|
* safe under the values passed at this call site. */
|
|
1853
1719
|
isLocalFunctionCallSafe(node, ctx) {
|
|
1854
|
-
const raw = node
|
|
1720
|
+
const raw = getRawNode(node);
|
|
1855
1721
|
const fnNode = raw.childForFieldName?.('function');
|
|
1856
1722
|
if (!fnNode || fnNode.type !== 'identifier')
|
|
1857
1723
|
return false;
|
|
@@ -1871,7 +1737,7 @@ class TsSafetyAnalysis extends TsConstantResolution {
|
|
|
1871
1737
|
/** Check a function's body returns only safe values, under the `paramMap`
|
|
1872
1738
|
* already bound in `ctx` to the values passed at the call site. */
|
|
1873
1739
|
isBodySafeUnderParams(fnNode, ctx) {
|
|
1874
|
-
const raw = fnNode
|
|
1740
|
+
const raw = getRawNode(fnNode);
|
|
1875
1741
|
const body = raw.childForFieldName?.('body');
|
|
1876
1742
|
if (!body)
|
|
1877
1743
|
return false;
|
|
@@ -1902,7 +1768,7 @@ class TsSafetyAnalysis extends TsConstantResolution {
|
|
|
1902
1768
|
* in-file call site of that function passes a provably-safe value for that
|
|
1903
1769
|
* parameter position. */
|
|
1904
1770
|
isParamSafeAtAllCallSites(identifierNode, ctx) {
|
|
1905
|
-
const idRaw = identifierNode
|
|
1771
|
+
const idRaw = getRawNode(identifierNode);
|
|
1906
1772
|
const paramName = idRaw.text;
|
|
1907
1773
|
const enclosing = this.findEnclosingScope(identifierNode, ctx.ast);
|
|
1908
1774
|
if (!enclosing || enclosing === ctx.ast.root)
|
|
@@ -1929,7 +1795,7 @@ class TsSafetyAnalysis extends TsConstantResolution {
|
|
|
1929
1795
|
/** True when the identifier names a local variable whose initializer is a
|
|
1930
1796
|
* provably-safe expression and which is never reassigned. */
|
|
1931
1797
|
isDeclarationValueSafe(identifierNode, ctx) {
|
|
1932
|
-
const idRaw = identifierNode
|
|
1798
|
+
const idRaw = getRawNode(identifierNode);
|
|
1933
1799
|
const name = idRaw.text;
|
|
1934
1800
|
const enclosing = this.findEnclosingScope(identifierNode, ctx.ast);
|
|
1935
1801
|
const scopeRoot = enclosing ?? ctx.ast.root;
|
|
@@ -1944,7 +1810,7 @@ class TsSafetyAnalysis extends TsConstantResolution {
|
|
|
1944
1810
|
|| (enclosing && enclosing !== ctx.ast.root ? this.hasReassignment(ctx.ast.root, name, declLine) : false);
|
|
1945
1811
|
if (reassigned)
|
|
1946
1812
|
return false;
|
|
1947
|
-
const declRaw = declNode
|
|
1813
|
+
const declRaw = getRawNode(declNode);
|
|
1948
1814
|
const valueRaw = declRaw.childForFieldName?.('value');
|
|
1949
1815
|
if (!valueRaw)
|
|
1950
1816
|
return false;
|