code-auditor-mcp 3.10.0 → 4.0.1
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 +197 -0
- package/dist/__tests__/fixtures/spec-52/item-04-storage-sql-exec-in-loop.d.ts.map +1 -1
- package/dist/__tests__/fixtures/spec-52/item-05-upsert-forms.d.ts +4 -4
- package/dist/__tests__/fixtures/spec-52/item-05-upsert-forms.d.ts.map +1 -1
- package/dist/analyzers/analyzerUtils.d.ts.map +1 -1
- package/dist/analyzers/analyzerUtils.js +2 -2
- package/dist/analyzers/analyzerUtils.js.map +1 -1
- package/dist/analyzers/applicability.d.ts.map +1 -1
- package/dist/analyzers/applicability.js +1 -0
- package/dist/analyzers/applicability.js.map +1 -1
- package/dist/analyzers/cross-language/APIContractAnalyzer.d.ts.map +1 -1
- package/dist/analyzers/cross-language/DependencyGraphBuilder.d.ts +1 -1
- package/dist/analyzers/cross-language/DependencyGraphBuilder.d.ts.map +1 -1
- package/dist/analyzers/cross-language/DependencyGraphBuilder.js +3 -3
- package/dist/analyzers/cross-language/DependencyGraphBuilder.js.map +1 -1
- package/dist/analyzers/cross-language/SchemaValidator.d.ts.map +1 -1
- package/dist/analyzers/cross-language/SchemaValidator.js.map +1 -1
- package/dist/analyzers/crossDomain/CrossDomainAnalyzer.d.ts +2 -2
- package/dist/analyzers/crossDomain/CrossDomainAnalyzer.d.ts.map +1 -1
- package/dist/analyzers/crossDomain/CrossDomainAnalyzer.js +62 -17
- 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/orm/adapterRegistry.d.ts.map +1 -1
- package/dist/analyzers/orm/drizzleAdapter.d.ts.map +1 -1
- package/dist/analyzers/orm/prismaAdapter.d.ts.map +1 -1
- package/dist/analyzers/provenance.d.ts +10 -1
- package/dist/analyzers/provenance.d.ts.map +1 -1
- package/dist/analyzers/provenance.js +138 -1
- package/dist/analyzers/provenance.js.map +1 -1
- package/dist/analyzers/reactAnalyzer.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 +199 -55
- 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.d.ts.map +1 -1
- 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 +266 -101
- 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.d.ts.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 +19 -7
- package/dist/analyzers/universal/UniversalSchemaAnalyzer.js.map +1 -1
- package/dist/analyzers/universal/UniversalSecretsAnalyzer.d.ts.map +1 -1
- package/dist/analyzers/universal/UniversalStylesAnalyzer.d.ts +2 -2
- package/dist/analyzers/universal/UniversalStylesAnalyzer.d.ts.map +1 -1
- package/dist/analyzers/universal/UniversalStylesAnalyzer.js +93 -46
- package/dist/analyzers/universal/UniversalStylesAnalyzer.js.map +1 -1
- package/dist/analyzers/universal/schema/codeAnalysis.d.ts +58 -34
- package/dist/analyzers/universal/schema/codeAnalysis.d.ts.map +1 -1
- package/dist/analyzers/universal/schema/codeAnalysis.js +239 -97
- package/dist/analyzers/universal/schema/codeAnalysis.js.map +1 -1
- package/dist/analyzers/universal/schema/config.d.ts +6 -6
- package/dist/analyzers/universal/schema/config.d.ts.map +1 -1
- package/dist/analyzers/universal/schema/jsonSchema.js +1 -1
- package/dist/analyzers/universal/schema/jsonSchema.js.map +1 -1
- package/dist/analyzers/universal/schema/types.d.ts +10 -0
- package/dist/analyzers/universal/schema/types.d.ts.map +1 -1
- package/dist/analyzers/universal/schema/violations.d.ts +1 -1
- package/dist/analyzers/universal/schema/violations.d.ts.map +1 -1
- package/dist/auditRouter.js +7 -7
- package/dist/auditRouter.js.map +1 -1
- package/dist/auditRunner.d.ts +1 -1
- package/dist/auditRunner.d.ts.map +1 -1
- package/dist/auditRunner.js +53 -8
- package/dist/auditRunner.js.map +1 -1
- package/dist/churn/churnExtractor.js.map +1 -1
- package/dist/cli.js +52 -24
- 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 +164 -18
- package/dist/codeIndexDB.js.map +1 -1
- package/dist/codeIndexService.d.ts.map +1 -1
- package/dist/codeIndexService.js.map +1 -1
- package/dist/componentScanner.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.d.ts +2 -2
- package/dist/config/defaults.d.ts.map +1 -1
- package/dist/config/defaults.js +10 -3
- package/dist/config/defaults.js.map +1 -1
- package/dist/constants.d.ts +1 -1
- package/dist/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/coverage/lcovParser.js.map +1 -1
- package/dist/daemon/args.js.map +1 -1
- package/dist/daemon/core.d.ts.map +1 -1
- package/dist/daemon/core.js +50 -46
- package/dist/daemon/core.js.map +1 -1
- package/dist/daemon/lspServer.d.ts.map +1 -1
- package/dist/daemon/lspServer.js +1 -1
- package/dist/daemon/lspServer.js.map +1 -1
- package/dist/daemon/main.d.ts.map +1 -1
- package/dist/daemon/main.js +14 -4
- package/dist/daemon/main.js.map +1 -1
- package/dist/daemon/resolve.js.map +1 -1
- package/dist/daemon/socketServer.d.ts.map +1 -1
- package/dist/enforcement/gate.js +2 -2
- package/dist/functionScanner.d.ts.map +1 -1
- package/dist/functionScanner.js +47 -42
- package/dist/functionScanner.js.map +1 -1
- package/dist/generators/AWSQConfigGenerator.d.ts.map +1 -1
- package/dist/generators/AiderConfigGenerator.d.ts.map +1 -1
- package/dist/generators/BaseConfigGenerator.d.ts.map +1 -1
- package/dist/generators/BaseConfigGenerator.js.map +1 -1
- package/dist/generators/ClaudeConfigGenerator.d.ts.map +1 -1
- package/dist/generators/ClineConfigGenerator.d.ts.map +1 -1
- package/dist/generators/CodeiumConfigGenerator.d.ts.map +1 -1
- package/dist/generators/CodexConfigGenerator.d.ts.map +1 -1
- package/dist/generators/ConfigGeneratorFactory.d.ts.map +1 -1
- package/dist/generators/ConfigGeneratorFactory.js.map +1 -1
- package/dist/generators/ContinueConfigGenerator.d.ts.map +1 -1
- package/dist/generators/CopilotConfigGenerator.d.ts.map +1 -1
- package/dist/generators/CursorConfigGenerator.d.ts.map +1 -1
- package/dist/generators/GeminiConfigGenerator.d.ts.map +1 -1
- package/dist/generators/JetBrainsConfigGenerator.d.ts.map +1 -1
- package/dist/generators/VSCodeConfigGenerator.d.ts.map +1 -1
- package/dist/generators/ZCodeConfigGenerator.d.ts.map +1 -1
- package/dist/graph/importClassification.d.ts +114 -0
- package/dist/graph/importClassification.d.ts.map +1 -0
- package/dist/graph/importClassification.js +393 -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/graph/outputFormatter.js.map +1 -1
- package/dist/hooks/codex.d.ts.map +1 -1
- package/dist/hooks/codex.js +1 -1
- package/dist/hooks/codex.js.map +1 -1
- package/dist/hooks/core.d.ts +1 -1
- package/dist/hooks/core.d.ts.map +1 -1
- package/dist/hooks/core.js +4 -4
- package/dist/hooks/core.js.map +1 -1
- package/dist/hooks/cursor.d.ts.map +1 -1
- package/dist/hooks/cursor.js +2 -2
- package/dist/hooks/cursor.js.map +1 -1
- package/dist/index.d.ts +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/ruleEngine.js.map +1 -1
- package/dist/invariants/ruleValidator.js +1 -1
- package/dist/invariants/ruleValidator.js.map +1 -1
- package/dist/invariants/types.d.ts +1 -1
- package/dist/invariants/types.d.ts.map +1 -1
- package/dist/languages/LanguageOrchestrator.d.ts +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/LanguageRegistry.d.ts.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/UniversalAnalyzer.d.ts.map +1 -1
- package/dist/languages/UniversalAnalyzer.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/parser.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 +15 -21
- package/dist/languages/types.d.ts.map +1 -1
- package/dist/languages/typescript/TreeSitterTypeScriptAdapter.d.ts +12 -32
- package/dist/languages/typescript/TreeSitterTypeScriptAdapter.d.ts.map +1 -1
- package/dist/languages/typescript/TreeSitterTypeScriptAdapter.js +103 -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.d.ts +37 -37
- package/dist/mcp-tools/projectTasks.js +2 -2
- package/dist/mcp-tools/projectTasks.js.map +1 -1
- package/dist/mcp-tools/whitelistTools.d.ts +17 -17
- package/dist/mcp-tools/whitelistTools.d.ts.map +1 -1
- package/dist/mcp-tools/workflowGuide.js +3 -3
- package/dist/mcp-tools/workflowGuide.js.map +1 -1
- package/dist/mcp-tools-shared.d.ts.map +1 -1
- package/dist/mcp-tools-shared.js +13 -13
- package/dist/mcp-tools-shared.js.map +1 -1
- package/dist/mcp-ui-simple.js +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/mcpToolErrors.d.ts.map +1 -1
- package/dist/mcpToolErrors.js.map +1 -1
- package/dist/native-bootstrap.js.map +1 -1
- package/dist/nextFile.d.ts +2 -2
- package/dist/nextFile.d.ts.map +1 -1
- package/dist/nextFile.js +19 -5
- package/dist/nextFile.js.map +1 -1
- package/dist/nextFileIncremental.d.ts +10 -2
- package/dist/nextFileIncremental.d.ts.map +1 -1
- package/dist/nextFileIncremental.js +45 -16
- package/dist/nextFileIncremental.js.map +1 -1
- package/dist/pipeline.d.ts +2 -2
- package/dist/pipeline.d.ts.map +1 -1
- package/dist/pipeline.js +35 -0
- package/dist/pipeline.js.map +1 -1
- package/dist/pipelineAdapters.d.ts +17 -0
- package/dist/pipelineAdapters.d.ts.map +1 -1
- package/dist/pipelineAdapters.js +356 -197
- package/dist/pipelineAdapters.js.map +1 -1
- package/dist/reporting/csvReportGenerator.d.ts.map +1 -1
- package/dist/reporting/csvReportGenerator.js +6 -6
- package/dist/reporting/csvReportGenerator.js.map +1 -1
- package/dist/reporting/htmlReportGenerator.d.ts.map +1 -1
- package/dist/reporting/htmlReportGenerator.js +11 -11
- package/dist/reporting/htmlReportGenerator.js.map +1 -1
- package/dist/reporting/jsonReportGenerator.d.ts.map +1 -1
- package/dist/reporting/jsonReportGenerator.js +2 -2
- package/dist/reporting/jsonReportGenerator.js.map +1 -1
- package/dist/reporting/reportGenerator.d.ts.map +1 -1
- package/dist/reporting/sarifReportGenerator.d.ts.map +1 -1
- package/dist/reporting/sarifReportGenerator.js +1 -1
- package/dist/reporting/sarifReportGenerator.js.map +1 -1
- package/dist/scripts/benchmarkWorkers.js +1 -1
- package/dist/scripts/benchmarkWorkers.js.map +1 -1
- package/dist/search/QueryParser.d.ts.map +1 -1
- package/dist/search/QueryParser.js.map +1 -1
- package/dist/services/CodeMapGenerator.d.ts.map +1 -1
- package/dist/services/CodeMapGenerator.js.map +1 -1
- package/dist/services/ProjectTaskRepository.d.ts.map +1 -1
- package/dist/services/ProjectTaskRepository.js.map +1 -1
- package/dist/services/auditJobService.js.map +1 -1
- package/dist/services/fileAccounting.d.ts.map +1 -1
- package/dist/services/projectTaskHelpers.js.map +1 -1
- package/dist/services/whitelistService.d.ts.map +1 -1
- package/dist/sqlite/betterSqlite3.d.ts.map +1 -1
- package/dist/sqlite/betterSqlite3.js.map +1 -1
- package/dist/sqlite/nodeSqlite.d.ts.map +1 -1
- package/dist/sqlite/nodeSqlite.js.map +1 -1
- package/dist/structuralSignature.js.map +1 -1
- package/dist/styles/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/styleExtractor.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/styles/tailwindConfigLoader.js.map +1 -1
- package/dist/styles/tailwindProbe.d.ts.map +1 -1
- package/dist/styles/tailwindUtilityExpander.d.ts.map +1 -1
- package/dist/styles/tailwindUtilityExpander.js.map +1 -1
- package/dist/telemetry.d.ts +1 -1
- package/dist/telemetry.d.ts.map +1 -1
- package/dist/telemetry.js.map +1 -1
- package/dist/tool-registry.d.ts.map +1 -1
- package/dist/types/crossLanguage.d.ts +1 -1
- package/dist/types/crossLanguage.d.ts.map +1 -1
- package/dist/types.d.ts +67 -19
- package/dist/types.d.ts.map +1 -1
- package/dist/types.js +6 -5
- package/dist/types.js.map +1 -1
- package/dist/ui/InteractivePrompts.d.ts.map +1 -1
- package/dist/ui/InteractivePrompts.js.map +1 -1
- package/dist/utils/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/componentPatterns.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/dist/workers/auditWorker.js.map +1 -1
- package/package.json +4 -3
- 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
|
@@ -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');
|
|
@@ -1662,13 +1528,47 @@ class TsSafetyAnalysis extends TsConstantResolution {
|
|
|
1662
1528
|
paramMap: new Map(),
|
|
1663
1529
|
});
|
|
1664
1530
|
}
|
|
1531
|
+
/**
|
|
1532
|
+
* Public entry point (LanguageAdapter.isEscapedInterpolation). True when the
|
|
1533
|
+
* expression applies manual quote-doubling — `.replace(/'/g, "''")`,
|
|
1534
|
+
* `.replace(/"/g, '""')`, `.replaceAll("'", "''")`, or
|
|
1535
|
+
* `.split("'").join("''")` (and the double-quote variants). Such input is
|
|
1536
|
+
* defended but NOT provably safe: single-quote doubling handles only the
|
|
1537
|
+
* single-quote vector, not backslash escapes, unicode quote variants, or
|
|
1538
|
+
* numeric/identifier positions. The caller downgrades these from `critical`
|
|
1539
|
+
* to `advisory` rather than certifying them safe.
|
|
1540
|
+
*/
|
|
1541
|
+
isEscapedInterpolation(node, ast, sourceCode) {
|
|
1542
|
+
// Source slice, not `raw.text` — web-tree-sitter's Node.text is unreliable
|
|
1543
|
+
// without a text provider (the adapter reads text via sourceCode.slice).
|
|
1544
|
+
const text = sourceCode.slice(node.range[0], node.range[1]).trim();
|
|
1545
|
+
if (!text)
|
|
1546
|
+
return false;
|
|
1547
|
+
// Quote-doubling is the *specific* defense: the search argument must be a
|
|
1548
|
+
// bare quote and the replacement that same quote doubled — `.replace(/'/g, "''")`
|
|
1549
|
+
// / `.replaceAll("'", "''")` (single) or `.replace(/"/g, '""')` /
|
|
1550
|
+
// `.replaceAll('"', '""')` (double). A generic `.replace()` whose replacement
|
|
1551
|
+
// merely happens to be a doubled quote — `replace('x', "''")` or
|
|
1552
|
+
// `replace(/x/g, "''")` — is NOT escaping and must not read as one. The
|
|
1553
|
+
// search quote and the replacement quote must match in kind.
|
|
1554
|
+
const singleReplace = /\.(?:replace|replaceAll)\s*\(\s*(?:\/'\/[a-z]*|"'")\s*,\s*"''"\s*\)/;
|
|
1555
|
+
const doubleReplace = /\.(?:replace|replaceAll)\s*\(\s*(?:\/"\/[a-z]*|'"')\s*,\s*'""'\s*\)/;
|
|
1556
|
+
if (singleReplace.test(text) || doubleReplace.test(text))
|
|
1557
|
+
return true;
|
|
1558
|
+
// `.split("'").join("''")` — split on a quote, rejoin on its doubled form.
|
|
1559
|
+
const singleSplit = /\.split\(\s*"'"\s*\)\s*\.join\(\s*"''"\s*\)/;
|
|
1560
|
+
const doubleSplit = /\.split\(\s*'"'\s*\)\s*\.join\(\s*'""'\s*\)/;
|
|
1561
|
+
if (singleSplit.test(text) || doubleSplit.test(text))
|
|
1562
|
+
return true;
|
|
1563
|
+
return false;
|
|
1564
|
+
}
|
|
1665
1565
|
/** Recursive safety check against the traversal context in `ctx`. */
|
|
1666
1566
|
isSafeExpression(node, ctx) {
|
|
1667
1567
|
if (!node)
|
|
1668
1568
|
return false;
|
|
1669
1569
|
if (node === SAFE_STRING_NODE)
|
|
1670
1570
|
return true;
|
|
1671
|
-
const raw = node
|
|
1571
|
+
const raw = getRawNode(node);
|
|
1672
1572
|
// `seen` is path-based (added on entry, removed on exit) and keyed by the
|
|
1673
1573
|
// node's unique `id` — NOT `startIndex`, which collides between an
|
|
1674
1574
|
// expression and its leading operand (a `binary_expression` and its left
|
|
@@ -1719,7 +1619,7 @@ class TsSafetyAnalysis extends TsConstantResolution {
|
|
|
1719
1619
|
evaluateStructuralExpression(node, raw, ctx) {
|
|
1720
1620
|
switch (raw.type) {
|
|
1721
1621
|
case 'parenthesized_expression': {
|
|
1722
|
-
const inner = (node.children ?? []).find((c) => !['(', ')'].includes(c.
|
|
1622
|
+
const inner = (node.children ?? []).find((c) => !['(', ')'].includes((getRawNode(c)).type));
|
|
1723
1623
|
return this.isSafeExpression(inner ?? null, ctx);
|
|
1724
1624
|
}
|
|
1725
1625
|
case 'as_expression':
|
|
@@ -1748,7 +1648,7 @@ class TsSafetyAnalysis extends TsConstantResolution {
|
|
|
1748
1648
|
/** Identifier safety: a bound parameter, compile-time constant, or validated
|
|
1749
1649
|
* parameter at all call sites. */
|
|
1750
1650
|
isSafeIdentifier(node, ctx) {
|
|
1751
|
-
const name = node.
|
|
1651
|
+
const name = (getRawNode(node)).text;
|
|
1752
1652
|
// A parameter bound at the current call site — recurse into its value.
|
|
1753
1653
|
if (ctx.paramMap.has(name)) {
|
|
1754
1654
|
return this.isSafeExpression(ctx.paramMap.get(name) ?? null, ctx);
|
|
@@ -1772,10 +1672,10 @@ class TsSafetyAnalysis extends TsConstantResolution {
|
|
|
1772
1672
|
/** A template string is safe only if every `${…}` substitution is safe. */
|
|
1773
1673
|
isSafeTemplateString(node, ctx) {
|
|
1774
1674
|
for (const child of node.children ?? []) {
|
|
1775
|
-
const ct = child.
|
|
1675
|
+
const ct = (getRawNode(child)).type;
|
|
1776
1676
|
if (ct !== 'template_substitution')
|
|
1777
1677
|
continue;
|
|
1778
|
-
const inner = (child.children ?? []).find((c) => c.
|
|
1678
|
+
const inner = (child.children ?? []).find((c) => (getRawNode(c)).type !== 'template_substitution') ?? child;
|
|
1779
1679
|
if (!this.isSafeExpression(inner, ctx)) {
|
|
1780
1680
|
return false;
|
|
1781
1681
|
}
|
|
@@ -1785,7 +1685,7 @@ class TsSafetyAnalysis extends TsConstantResolution {
|
|
|
1785
1685
|
/** An array literal is safe only if every element is safe. */
|
|
1786
1686
|
isSafeArray(node, ctx) {
|
|
1787
1687
|
for (const child of node.children ?? []) {
|
|
1788
|
-
const ct = child.
|
|
1688
|
+
const ct = (getRawNode(child)).type;
|
|
1789
1689
|
if (ct === ',' || ct === '[' || ct === ']')
|
|
1790
1690
|
continue;
|
|
1791
1691
|
if (!this.isSafeExpression(child, ctx)) {
|
|
@@ -1796,7 +1696,7 @@ class TsSafetyAnalysis extends TsConstantResolution {
|
|
|
1796
1696
|
}
|
|
1797
1697
|
/** Decide whether a call expression is provably safe to embed in SQL. */
|
|
1798
1698
|
isSafeCallExpression(node, ctx) {
|
|
1799
|
-
const raw = node
|
|
1699
|
+
const raw = getRawNode(node);
|
|
1800
1700
|
const fnNode = raw.childForFieldName?.('function');
|
|
1801
1701
|
if (!fnNode)
|
|
1802
1702
|
return false;
|
|
@@ -1815,7 +1715,7 @@ class TsSafetyAnalysis extends TsConstantResolution {
|
|
|
1815
1715
|
/** True when the node is `.join(...)` over `.map(...)` of a static array whose
|
|
1816
1716
|
* callback body is safe for every element. */
|
|
1817
1717
|
isSafeMapJoin(node, ctx) {
|
|
1818
|
-
const raw = node
|
|
1718
|
+
const raw = getRawNode(node);
|
|
1819
1719
|
const fnNode = raw.childForFieldName?.('function');
|
|
1820
1720
|
if (!fnNode || fnNode.type !== 'member_expression')
|
|
1821
1721
|
return false;
|
|
@@ -1851,7 +1751,7 @@ class TsSafetyAnalysis extends TsConstantResolution {
|
|
|
1851
1751
|
/** True when the node is a call to a local (in-file) function whose body is
|
|
1852
1752
|
* safe under the values passed at this call site. */
|
|
1853
1753
|
isLocalFunctionCallSafe(node, ctx) {
|
|
1854
|
-
const raw = node
|
|
1754
|
+
const raw = getRawNode(node);
|
|
1855
1755
|
const fnNode = raw.childForFieldName?.('function');
|
|
1856
1756
|
if (!fnNode || fnNode.type !== 'identifier')
|
|
1857
1757
|
return false;
|
|
@@ -1871,7 +1771,7 @@ class TsSafetyAnalysis extends TsConstantResolution {
|
|
|
1871
1771
|
/** Check a function's body returns only safe values, under the `paramMap`
|
|
1872
1772
|
* already bound in `ctx` to the values passed at the call site. */
|
|
1873
1773
|
isBodySafeUnderParams(fnNode, ctx) {
|
|
1874
|
-
const raw = fnNode
|
|
1774
|
+
const raw = getRawNode(fnNode);
|
|
1875
1775
|
const body = raw.childForFieldName?.('body');
|
|
1876
1776
|
if (!body)
|
|
1877
1777
|
return false;
|
|
@@ -1902,7 +1802,7 @@ class TsSafetyAnalysis extends TsConstantResolution {
|
|
|
1902
1802
|
* in-file call site of that function passes a provably-safe value for that
|
|
1903
1803
|
* parameter position. */
|
|
1904
1804
|
isParamSafeAtAllCallSites(identifierNode, ctx) {
|
|
1905
|
-
const idRaw = identifierNode
|
|
1805
|
+
const idRaw = getRawNode(identifierNode);
|
|
1906
1806
|
const paramName = idRaw.text;
|
|
1907
1807
|
const enclosing = this.findEnclosingScope(identifierNode, ctx.ast);
|
|
1908
1808
|
if (!enclosing || enclosing === ctx.ast.root)
|
|
@@ -1929,7 +1829,7 @@ class TsSafetyAnalysis extends TsConstantResolution {
|
|
|
1929
1829
|
/** True when the identifier names a local variable whose initializer is a
|
|
1930
1830
|
* provably-safe expression and which is never reassigned. */
|
|
1931
1831
|
isDeclarationValueSafe(identifierNode, ctx) {
|
|
1932
|
-
const idRaw = identifierNode
|
|
1832
|
+
const idRaw = getRawNode(identifierNode);
|
|
1933
1833
|
const name = idRaw.text;
|
|
1934
1834
|
const enclosing = this.findEnclosingScope(identifierNode, ctx.ast);
|
|
1935
1835
|
const scopeRoot = enclosing ?? ctx.ast.root;
|
|
@@ -1944,7 +1844,7 @@ class TsSafetyAnalysis extends TsConstantResolution {
|
|
|
1944
1844
|
|| (enclosing && enclosing !== ctx.ast.root ? this.hasReassignment(ctx.ast.root, name, declLine) : false);
|
|
1945
1845
|
if (reassigned)
|
|
1946
1846
|
return false;
|
|
1947
|
-
const declRaw = declNode
|
|
1847
|
+
const declRaw = getRawNode(declNode);
|
|
1948
1848
|
const valueRaw = declRaw.childForFieldName?.('value');
|
|
1949
1849
|
if (!valueRaw)
|
|
1950
1850
|
return false;
|