code-auditor-mcp 3.10.0 → 4.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (261) hide show
  1. package/.claude-plugin/marketplace.json +1 -1
  2. package/CHANGELOG.md +171 -0
  3. package/dist/analyzers/analyzerUtils.js +2 -2
  4. package/dist/analyzers/analyzerUtils.js.map +1 -1
  5. package/dist/analyzers/applicability.d.ts.map +1 -1
  6. package/dist/analyzers/applicability.js +1 -0
  7. package/dist/analyzers/applicability.js.map +1 -1
  8. package/dist/analyzers/cross-language/DependencyGraphBuilder.d.ts +1 -1
  9. package/dist/analyzers/cross-language/DependencyGraphBuilder.d.ts.map +1 -1
  10. package/dist/analyzers/cross-language/DependencyGraphBuilder.js +3 -3
  11. package/dist/analyzers/cross-language/DependencyGraphBuilder.js.map +1 -1
  12. package/dist/analyzers/crossDomain/CrossDomainAnalyzer.d.ts +2 -2
  13. package/dist/analyzers/crossDomain/CrossDomainAnalyzer.d.ts.map +1 -1
  14. package/dist/analyzers/crossDomain/CrossDomainAnalyzer.js +39 -15
  15. package/dist/analyzers/crossDomain/CrossDomainAnalyzer.js.map +1 -1
  16. package/dist/analyzers/documentationAnalyzer.d.ts.map +1 -1
  17. package/dist/analyzers/documentationAnalyzer.js +14 -16
  18. package/dist/analyzers/documentationAnalyzer.js.map +1 -1
  19. package/dist/analyzers/invariantsAnalyzer.d.ts.map +1 -1
  20. package/dist/analyzers/invariantsAnalyzer.js +30 -25
  21. package/dist/analyzers/invariantsAnalyzer.js.map +1 -1
  22. package/dist/analyzers/reactAnalyzer.d.ts +1 -1
  23. package/dist/analyzers/reactAnalyzer.d.ts.map +1 -1
  24. package/dist/analyzers/reactAnalyzer.js +34 -116
  25. package/dist/analyzers/reactAnalyzer.js.map +1 -1
  26. package/dist/analyzers/ruleRegistry.d.ts +5 -3
  27. package/dist/analyzers/ruleRegistry.d.ts.map +1 -1
  28. package/dist/analyzers/ruleRegistry.js +198 -54
  29. package/dist/analyzers/ruleRegistry.js.map +1 -1
  30. package/dist/analyzers/universal/UniversalConventionsAnalyzer.d.ts +2 -2
  31. package/dist/analyzers/universal/UniversalConventionsAnalyzer.d.ts.map +1 -1
  32. package/dist/analyzers/universal/UniversalConventionsAnalyzer.js +10 -17
  33. package/dist/analyzers/universal/UniversalConventionsAnalyzer.js.map +1 -1
  34. package/dist/analyzers/universal/UniversalDRYAnalyzer.d.ts +6 -6
  35. package/dist/analyzers/universal/UniversalDRYAnalyzer.js +13 -13
  36. package/dist/analyzers/universal/UniversalDRYAnalyzer.js.map +1 -1
  37. package/dist/analyzers/universal/UniversalDataAccessAnalyzer.d.ts.map +1 -1
  38. package/dist/analyzers/universal/UniversalDataAccessAnalyzer.js +22 -64
  39. package/dist/analyzers/universal/UniversalDataAccessAnalyzer.js.map +1 -1
  40. package/dist/analyzers/universal/UniversalDocumentationAnalyzer.d.ts +3 -2
  41. package/dist/analyzers/universal/UniversalDocumentationAnalyzer.d.ts.map +1 -1
  42. package/dist/analyzers/universal/UniversalDocumentationAnalyzer.js +14 -13
  43. package/dist/analyzers/universal/UniversalDocumentationAnalyzer.js.map +1 -1
  44. package/dist/analyzers/universal/UniversalSOLIDAnalyzer.js +11 -11
  45. package/dist/analyzers/universal/UniversalSOLIDAnalyzer.js.map +1 -1
  46. package/dist/analyzers/universal/UniversalSchemaAnalyzer.d.ts +1 -1
  47. package/dist/analyzers/universal/UniversalSchemaAnalyzer.d.ts.map +1 -1
  48. package/dist/analyzers/universal/UniversalSchemaAnalyzer.js +18 -7
  49. package/dist/analyzers/universal/UniversalSchemaAnalyzer.js.map +1 -1
  50. package/dist/analyzers/universal/UniversalStylesAnalyzer.d.ts +2 -2
  51. package/dist/analyzers/universal/UniversalStylesAnalyzer.d.ts.map +1 -1
  52. package/dist/analyzers/universal/UniversalStylesAnalyzer.js +38 -26
  53. package/dist/analyzers/universal/UniversalStylesAnalyzer.js.map +1 -1
  54. package/dist/analyzers/universal/schema/codeAnalysis.d.ts +37 -13
  55. package/dist/analyzers/universal/schema/codeAnalysis.d.ts.map +1 -1
  56. package/dist/analyzers/universal/schema/codeAnalysis.js +42 -54
  57. package/dist/analyzers/universal/schema/codeAnalysis.js.map +1 -1
  58. package/dist/analyzers/universal/schema/jsonSchema.js +1 -1
  59. package/dist/analyzers/universal/schema/jsonSchema.js.map +1 -1
  60. package/dist/analyzers/universal/schema/violations.d.ts +1 -1
  61. package/dist/analyzers/universal/schema/violations.d.ts.map +1 -1
  62. package/dist/auditRouter.js +7 -7
  63. package/dist/auditRouter.js.map +1 -1
  64. package/dist/auditRunner.d.ts.map +1 -1
  65. package/dist/auditRunner.js +36 -6
  66. package/dist/auditRunner.js.map +1 -1
  67. package/dist/cli.js +23 -17
  68. package/dist/cli.js.map +1 -1
  69. package/dist/codeIndexDB.d.ts +1 -1
  70. package/dist/codeIndexDB.d.ts.map +1 -1
  71. package/dist/codeIndexDB.js +148 -18
  72. package/dist/codeIndexDB.js.map +1 -1
  73. package/dist/componentScanner.d.ts.map +1 -1
  74. package/dist/componentScanner.js +89 -28
  75. package/dist/componentScanner.js.map +1 -1
  76. package/dist/config/configLoader.js +1 -1
  77. package/dist/config/configLoader.js.map +1 -1
  78. package/dist/config/defaults.js +3 -3
  79. package/dist/config/defaults.js.map +1 -1
  80. package/dist/constants.d.ts +1 -1
  81. package/dist/constants.d.ts.map +1 -1
  82. package/dist/conventions/conventionMiner.d.ts.map +1 -1
  83. package/dist/conventions/conventionMiner.js +3 -10
  84. package/dist/conventions/conventionMiner.js.map +1 -1
  85. package/dist/daemon/core.d.ts.map +1 -1
  86. package/dist/daemon/core.js +33 -38
  87. package/dist/daemon/core.js.map +1 -1
  88. package/dist/daemon/lspServer.js +1 -1
  89. package/dist/daemon/lspServer.js.map +1 -1
  90. package/dist/daemon/main.d.ts.map +1 -1
  91. package/dist/daemon/main.js +14 -4
  92. package/dist/daemon/main.js.map +1 -1
  93. package/dist/enforcement/gate.js +2 -2
  94. package/dist/functionScanner.d.ts.map +1 -1
  95. package/dist/functionScanner.js +47 -42
  96. package/dist/functionScanner.js.map +1 -1
  97. package/dist/graph/importClassification.d.ts +76 -0
  98. package/dist/graph/importClassification.d.ts.map +1 -0
  99. package/dist/graph/importClassification.js +221 -0
  100. package/dist/graph/importClassification.js.map +1 -0
  101. package/dist/graph/importGraph.d.ts +1 -0
  102. package/dist/graph/importGraph.d.ts.map +1 -1
  103. package/dist/graph/importGraph.js +1 -1
  104. package/dist/graph/importGraph.js.map +1 -1
  105. package/dist/hooks/codex.d.ts.map +1 -1
  106. package/dist/hooks/codex.js +1 -1
  107. package/dist/hooks/codex.js.map +1 -1
  108. package/dist/hooks/core.d.ts +1 -1
  109. package/dist/hooks/core.d.ts.map +1 -1
  110. package/dist/hooks/core.js +4 -4
  111. package/dist/hooks/core.js.map +1 -1
  112. package/dist/hooks/cursor.d.ts.map +1 -1
  113. package/dist/hooks/cursor.js +2 -2
  114. package/dist/hooks/cursor.js.map +1 -1
  115. package/dist/index.d.ts +1 -1
  116. package/dist/index.d.ts.map +1 -1
  117. package/dist/index.js.map +1 -1
  118. package/dist/installer.d.ts +13 -7
  119. package/dist/installer.d.ts.map +1 -1
  120. package/dist/installer.js +25 -15
  121. package/dist/installer.js.map +1 -1
  122. package/dist/invariants/invariant-rules.schema.json +1 -1
  123. package/dist/invariants/ruleValidator.js +1 -1
  124. package/dist/invariants/ruleValidator.js.map +1 -1
  125. package/dist/invariants/types.d.ts +1 -1
  126. package/dist/invariants/types.d.ts.map +1 -1
  127. package/dist/languages/LanguageOrchestrator.d.ts +3 -2
  128. package/dist/languages/LanguageOrchestrator.d.ts.map +1 -1
  129. package/dist/languages/LanguageOrchestrator.js +1 -1
  130. package/dist/languages/LanguageOrchestrator.js.map +1 -1
  131. package/dist/languages/RuntimeManager.d.ts +20 -11
  132. package/dist/languages/RuntimeManager.d.ts.map +1 -1
  133. package/dist/languages/RuntimeManager.js +151 -51
  134. package/dist/languages/RuntimeManager.js.map +1 -1
  135. package/dist/languages/adapterBridge.d.ts +10 -0
  136. package/dist/languages/adapterBridge.d.ts.map +1 -1
  137. package/dist/languages/adapterBridge.js +30 -7
  138. package/dist/languages/adapterBridge.js.map +1 -1
  139. package/dist/languages/go/GoAdapter.d.ts +1 -19
  140. package/dist/languages/go/GoAdapter.d.ts.map +1 -1
  141. package/dist/languages/go/GoAdapter.js +33 -116
  142. package/dist/languages/go/GoAdapter.js.map +1 -1
  143. package/dist/languages/go/analyzer +0 -0
  144. package/dist/languages/go/analyzer-src/analyzer.go +8 -8
  145. package/dist/languages/go/analyzer-src/solid.go +5 -5
  146. package/dist/languages/goBinary.d.ts +46 -0
  147. package/dist/languages/goBinary.d.ts.map +1 -0
  148. package/dist/languages/goBinary.js +169 -0
  149. package/dist/languages/goBinary.js.map +1 -0
  150. package/dist/languages/tree-sitter/TreeSitterCssAdapter.d.ts +1 -28
  151. package/dist/languages/tree-sitter/TreeSitterCssAdapter.d.ts.map +1 -1
  152. package/dist/languages/tree-sitter/TreeSitterCssAdapter.js +3 -42
  153. package/dist/languages/tree-sitter/TreeSitterCssAdapter.js.map +1 -1
  154. package/dist/languages/tree-sitter/converter.d.ts.map +1 -1
  155. package/dist/languages/tree-sitter/converter.js +2 -1
  156. package/dist/languages/tree-sitter/converter.js.map +1 -1
  157. package/dist/languages/tree-sitter/rawNode.d.ts +31 -0
  158. package/dist/languages/tree-sitter/rawNode.d.ts.map +1 -0
  159. package/dist/languages/tree-sitter/rawNode.js +38 -0
  160. package/dist/languages/tree-sitter/rawNode.js.map +1 -0
  161. package/dist/languages/types.d.ts +0 -21
  162. package/dist/languages/types.d.ts.map +1 -1
  163. package/dist/languages/typescript/TreeSitterTypeScriptAdapter.d.ts +1 -32
  164. package/dist/languages/typescript/TreeSitterTypeScriptAdapter.d.ts.map +1 -1
  165. package/dist/languages/typescript/TreeSitterTypeScriptAdapter.js +69 -203
  166. package/dist/languages/typescript/TreeSitterTypeScriptAdapter.js.map +1 -1
  167. package/dist/ledger.d.ts +3 -0
  168. package/dist/ledger.d.ts.map +1 -1
  169. package/dist/ledger.js +45 -9
  170. package/dist/ledger.js.map +1 -1
  171. package/dist/mcp-tools/projectTasks.js +2 -2
  172. package/dist/mcp-tools/projectTasks.js.map +1 -1
  173. package/dist/mcp-tools/workflowGuide.js +3 -3
  174. package/dist/mcp-tools/workflowGuide.js.map +1 -1
  175. package/dist/mcp-tools-shared.js +13 -13
  176. package/dist/mcp-tools-shared.js.map +1 -1
  177. package/dist/mcp-ui-simple.js +7 -7
  178. package/dist/mcp-ui-simple.js.map +1 -1
  179. package/dist/mcp.js +14 -14
  180. package/dist/mcp.js.map +1 -1
  181. package/dist/mcpAuditJobs.js +7 -7
  182. package/dist/mcpAuditJobs.js.map +1 -1
  183. package/dist/mcpAutoIndex.js +1 -1
  184. package/dist/mcpAutoIndex.js.map +1 -1
  185. package/dist/nextFile.d.ts +2 -2
  186. package/dist/nextFile.d.ts.map +1 -1
  187. package/dist/nextFile.js +19 -5
  188. package/dist/nextFile.js.map +1 -1
  189. package/dist/nextFileIncremental.d.ts +3 -2
  190. package/dist/nextFileIncremental.d.ts.map +1 -1
  191. package/dist/nextFileIncremental.js +20 -7
  192. package/dist/nextFileIncremental.js.map +1 -1
  193. package/dist/pipelineAdapters.d.ts +17 -0
  194. package/dist/pipelineAdapters.d.ts.map +1 -1
  195. package/dist/pipelineAdapters.js +279 -178
  196. package/dist/pipelineAdapters.js.map +1 -1
  197. package/dist/reporting/csvReportGenerator.js +6 -6
  198. package/dist/reporting/csvReportGenerator.js.map +1 -1
  199. package/dist/reporting/htmlReportGenerator.js +11 -11
  200. package/dist/reporting/htmlReportGenerator.js.map +1 -1
  201. package/dist/reporting/jsonReportGenerator.js +2 -2
  202. package/dist/reporting/jsonReportGenerator.js.map +1 -1
  203. package/dist/reporting/sarifReportGenerator.js +1 -1
  204. package/dist/reporting/sarifReportGenerator.js.map +1 -1
  205. package/dist/scripts/benchmarkWorkers.js +1 -1
  206. package/dist/scripts/benchmarkWorkers.js.map +1 -1
  207. package/dist/styles/cssAstExtractor.d.ts +2 -2
  208. package/dist/styles/cssAstExtractor.d.ts.map +1 -1
  209. package/dist/styles/cssAstExtractor.js +67 -111
  210. package/dist/styles/cssAstExtractor.js.map +1 -1
  211. package/dist/styles/styleIndexer.d.ts.map +1 -1
  212. package/dist/styles/styleIndexer.js +19 -6
  213. package/dist/styles/styleIndexer.js.map +1 -1
  214. package/dist/telemetry.d.ts +1 -1
  215. package/dist/telemetry.d.ts.map +1 -1
  216. package/dist/types/crossLanguage.d.ts +1 -1
  217. package/dist/types/crossLanguage.d.ts.map +1 -1
  218. package/dist/types.d.ts +59 -19
  219. package/dist/types.d.ts.map +1 -1
  220. package/dist/types.js +6 -5
  221. package/dist/types.js.map +1 -1
  222. package/dist/utils/astParser.d.ts +1 -17
  223. package/dist/utils/astParser.d.ts.map +1 -1
  224. package/dist/utils/astParser.js +18 -60
  225. package/dist/utils/astParser.js.map +1 -1
  226. package/dist/utils/astUtils.d.ts +12 -12
  227. package/dist/utils/astUtils.d.ts.map +1 -1
  228. package/dist/utils/astUtils.js +83 -82
  229. package/dist/utils/astUtils.js.map +1 -1
  230. package/dist/utils/componentResponsibility.d.ts +8 -8
  231. package/dist/utils/componentResponsibility.d.ts.map +1 -1
  232. package/dist/utils/componentResponsibility.js +33 -38
  233. package/dist/utils/componentResponsibility.js.map +1 -1
  234. package/dist/utils/dependencyExtractor.d.ts +3 -3
  235. package/dist/utils/dependencyExtractor.d.ts.map +1 -1
  236. package/dist/utils/dependencyExtractor.js +26 -30
  237. package/dist/utils/dependencyExtractor.js.map +1 -1
  238. package/dist/utils/fileDiscovery.d.ts.map +1 -1
  239. package/dist/utils/fileDiscovery.js +65 -0
  240. package/dist/utils/fileDiscovery.js.map +1 -1
  241. package/dist/utils/jsDocParser.d.ts +6 -6
  242. package/dist/utils/jsDocParser.d.ts.map +1 -1
  243. package/dist/utils/jsDocParser.js +18 -21
  244. package/dist/utils/jsDocParser.js.map +1 -1
  245. package/dist/utils/reactDetection.d.ts +7 -7
  246. package/dist/utils/reactDetection.d.ts.map +1 -1
  247. package/dist/utils/reactDetection.js +42 -49
  248. package/dist/utils/reactDetection.js.map +1 -1
  249. package/dist/version.generated.d.ts +1 -1
  250. package/dist/version.generated.d.ts.map +1 -1
  251. package/dist/version.generated.js +1 -1
  252. package/dist/version.generated.js.map +1 -1
  253. package/package.json +1 -1
  254. package/plugin/.claude-plugin/plugin.json +1 -1
  255. package/plugin/README.md +5 -4
  256. package/plugin/hooks/hooks.json +11 -0
  257. package/plugin/scripts/hook-common.sh +85 -31
  258. package/plugin/scripts/hook-warm.sh +44 -0
  259. package/plugin/skills/code-auditor/SKILL-RULE-KINDS.md +28 -21
  260. package/plugin/skills/code-auditor/SKILL.md +10 -10
  261. 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 { getParser, parseWithRecovery } from '../tree-sitter/parser.js';
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.raw;
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.raw;
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.raw;
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.raw;
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.raw;
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.raw;
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.raw;
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.raw;
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.raw.type;
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.raw.type;
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.raw.type === 'method_definition';
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.raw.type;
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.raw.type;
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.raw;
892
+ const syntaxNode = getRawNode(node);
1009
893
  return this.extractDocumentation(syntaxNode);
1010
894
  }
1011
895
  getComplexity(node) {
1012
- const syntaxNode = node.raw;
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.raw;
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.raw.type;
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.raw.type;
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.raw.type;
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.raw.type;
1006
+ const t = (getRawNode(astNode)).type;
1141
1007
  if (t === 'variable_declarator') {
1142
- const raw = astNode.raw;
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.raw.type;
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.raw;
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?.raw?.type === 'import_clause') {
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.raw.type;
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.raw;
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.raw;
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.raw;
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.raw;
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.raw;
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.raw.type;
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.raw.type === 'template_substitution') {
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.raw.type === 'string');
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.raw.text;
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.raw.type === 'arguments') {
1183
+ if ((getRawNode(child)).type === 'arguments') {
1318
1184
  for (const arg of child.children ?? []) {
1319
- const argType = arg.raw.type;
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.raw.type;
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.raw.text;
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.raw.type !== 'arguments')
1224
+ if ((getRawNode(child)).type !== 'arguments')
1359
1225
  continue;
1360
1226
  for (const arg of child.children ?? []) {
1361
- const argType = arg.raw.type;
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.raw.type !== 'arguments')
1241
+ if ((getRawNode(child)).type !== 'arguments')
1376
1242
  continue;
1377
1243
  for (const arg of child.children ?? []) {
1378
- const argType = arg.raw.type;
1244
+ const argType = (getRawNode(arg)).type;
1379
1245
  if (argType === '(' || argType === ')' || argType === ',')
1380
1246
  continue;
1381
- const text = arg.raw.text.trim();
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.raw.type !== 'template_substitution')
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.raw.type !== 'template_substitution') {
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.raw.type;
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.raw;
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.raw;
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.raw;
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.raw;
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.raw;
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.raw;
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.raw;
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.raw;
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.raw;
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.raw.type));
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.raw.text;
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.raw.type;
1641
+ const ct = (getRawNode(child)).type;
1776
1642
  if (ct !== 'template_substitution')
1777
1643
  continue;
1778
- const inner = (child.children ?? []).find((c) => c.raw.type !== 'template_substitution') ?? child;
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.raw.type;
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.raw;
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.raw;
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.raw;
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.raw;
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.raw;
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.raw;
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.raw;
1813
+ const declRaw = getRawNode(declNode);
1948
1814
  const valueRaw = declRaw.childForFieldName?.('value');
1949
1815
  if (!valueRaw)
1950
1816
  return false;