xq-lsp 1.4.0 → 1.5.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 (514) hide show
  1. package/CHANGELOG.md +25 -0
  2. package/README.md +54 -8
  3. package/dist/completion-core.d.ts +1 -1
  4. package/dist/completion-core.js +72 -7
  5. package/dist/runtimes.d.ts +14 -1
  6. package/dist/runtimes.js +37 -0
  7. package/dist/server.js +61 -21
  8. package/dist/variable-diagnostics.d.ts +19 -0
  9. package/dist/variable-diagnostics.js +164 -0
  10. package/package.json +4 -4
  11. package/src/completion-core.ts +71 -6
  12. package/src/runtimes/existdb/predeclared-namespaces.json +34 -0
  13. package/src/runtimes/existdb/util.xq +32 -0
  14. package/src/runtimes.ts +43 -1
  15. package/src/server.ts +67 -19
  16. package/src/variable-diagnostics.ts +190 -0
  17. package/firebase.json +0 -12
  18. package/release-please-config.json +0 -16
  19. package/scripts/generate-existdb.ts +0 -890
  20. package/src/analyzer.test.ts +0 -163
  21. package/src/builtins.test.ts +0 -32
  22. package/src/completion.test.ts +0 -152
  23. package/src/context-item-diagnostics.test.ts +0 -182
  24. package/src/features.test.ts +0 -110
  25. package/src/functioncall-diagnostics.test.ts +0 -169
  26. package/src/lsp-config.test.ts +0 -183
  27. package/src/namespace-diagnostics.test.ts +0 -162
  28. package/src/qt4-diagnostic.test.ts +0 -271
  29. package/src/qt4-snaps/app-CatalogCheck.snap +0 -1
  30. package/src/qt4-snaps/app-Demos.snap +0 -18
  31. package/src/qt4-snaps/app-Duplicates.snap +0 -1
  32. package/src/qt4-snaps/app-FunctxFn.snap +0 -162
  33. package/src/qt4-snaps/app-FunctxFunctx.snap +0 -714
  34. package/src/qt4-snaps/app-UseCaseCompoundValues.snap +0 -1
  35. package/src/qt4-snaps/app-UseCaseJSON.snap +0 -1
  36. package/src/qt4-snaps/app-UseCaseNLP.snap +0 -1
  37. package/src/qt4-snaps/app-UseCaseNS.snap +0 -1
  38. package/src/qt4-snaps/app-UseCaseR.snap +0 -1
  39. package/src/qt4-snaps/app-UseCaseR31.snap +0 -1
  40. package/src/qt4-snaps/app-UseCaseSEQ.snap +0 -1
  41. package/src/qt4-snaps/app-UseCaseSGML.snap +0 -1
  42. package/src/qt4-snaps/app-UseCaseSTRING.snap +0 -1
  43. package/src/qt4-snaps/app-UseCaseTREE.snap +0 -1
  44. package/src/qt4-snaps/app-UseCaseXMP.snap +0 -1
  45. package/src/qt4-snaps/app-Walmsley.snap +0 -1
  46. package/src/qt4-snaps/app-XMark.snap +0 -10
  47. package/src/qt4-snaps/array-append.snap +0 -1
  48. package/src/qt4-snaps/array-filter.snap +0 -10
  49. package/src/qt4-snaps/array-flatten.snap +0 -1
  50. package/src/qt4-snaps/array-fold-left.snap +0 -1
  51. package/src/qt4-snaps/array-fold-right.snap +0 -1
  52. package/src/qt4-snaps/array-for-each-pair.snap +0 -1
  53. package/src/qt4-snaps/array-for-each.snap +0 -1
  54. package/src/qt4-snaps/array-get.snap +0 -1
  55. package/src/qt4-snaps/array-head.snap +0 -1
  56. package/src/qt4-snaps/array-insert-before.snap +0 -1
  57. package/src/qt4-snaps/array-join.snap +0 -1
  58. package/src/qt4-snaps/array-put.snap +0 -1
  59. package/src/qt4-snaps/array-remove.snap +0 -1
  60. package/src/qt4-snaps/array-reverse.snap +0 -1
  61. package/src/qt4-snaps/array-size.snap +0 -1
  62. package/src/qt4-snaps/array-sort.snap +0 -1
  63. package/src/qt4-snaps/array-subarray.snap +0 -1
  64. package/src/qt4-snaps/array-tail.snap +0 -1
  65. package/src/qt4-snaps/bin-and.snap +0 -1
  66. package/src/qt4-snaps/bin-bin.snap +0 -1
  67. package/src/qt4-snaps/bin-decode-string.snap +0 -1
  68. package/src/qt4-snaps/bin-encode-string.snap +0 -1
  69. package/src/qt4-snaps/bin-find.snap +0 -1
  70. package/src/qt4-snaps/bin-from-octets.snap +0 -1
  71. package/src/qt4-snaps/bin-hex.snap +0 -1
  72. package/src/qt4-snaps/bin-insert-before.snap +0 -1
  73. package/src/qt4-snaps/bin-join.snap +0 -1
  74. package/src/qt4-snaps/bin-length.snap +0 -1
  75. package/src/qt4-snaps/bin-not.snap +0 -1
  76. package/src/qt4-snaps/bin-octal.snap +0 -1
  77. package/src/qt4-snaps/bin-or.snap +0 -1
  78. package/src/qt4-snaps/bin-pack-double.snap +0 -1
  79. package/src/qt4-snaps/bin-pack-float.snap +0 -1
  80. package/src/qt4-snaps/bin-pack-integer.snap +0 -1
  81. package/src/qt4-snaps/bin-pad-left.snap +0 -1
  82. package/src/qt4-snaps/bin-pad-right.snap +0 -1
  83. package/src/qt4-snaps/bin-part.snap +0 -1
  84. package/src/qt4-snaps/bin-shift.snap +0 -1
  85. package/src/qt4-snaps/bin-to-octets.snap +0 -1
  86. package/src/qt4-snaps/bin-unpack-double.snap +0 -1
  87. package/src/qt4-snaps/bin-unpack-float.snap +0 -1
  88. package/src/qt4-snaps/bin-unpack-integer.snap +0 -1
  89. package/src/qt4-snaps/bin-unpack-unsigned-integer.snap +0 -1
  90. package/src/qt4-snaps/bin-xor.snap +0 -1
  91. package/src/qt4-snaps/file-file.snap +0 -1
  92. package/src/qt4-snaps/fn-QName.snap +0 -1
  93. package/src/qt4-snaps/fn-abs.snap +0 -1
  94. package/src/qt4-snaps/fn-adjust-date-to-timezone.snap +0 -1
  95. package/src/qt4-snaps/fn-adjust-dateTime-to-timezone.snap +0 -1
  96. package/src/qt4-snaps/fn-adjust-time-to-timezone.snap +0 -1
  97. package/src/qt4-snaps/fn-analyze-string.snap +0 -1
  98. package/src/qt4-snaps/fn-apply.snap +0 -1
  99. package/src/qt4-snaps/fn-available-environment-variables.snap +0 -1
  100. package/src/qt4-snaps/fn-avg.snap +0 -1
  101. package/src/qt4-snaps/fn-base-uri.snap +0 -1
  102. package/src/qt4-snaps/fn-boolean.snap +0 -1
  103. package/src/qt4-snaps/fn-ceiling.snap +0 -1
  104. package/src/qt4-snaps/fn-codepoint-equal.snap +0 -1
  105. package/src/qt4-snaps/fn-codepoints-to-string.snap +0 -1
  106. package/src/qt4-snaps/fn-collation-key.snap +0 -1
  107. package/src/qt4-snaps/fn-collection.snap +0 -1
  108. package/src/qt4-snaps/fn-compare.snap +0 -1
  109. package/src/qt4-snaps/fn-concat.snap +0 -1
  110. package/src/qt4-snaps/fn-contains-token.snap +0 -1
  111. package/src/qt4-snaps/fn-contains.snap +0 -1
  112. package/src/qt4-snaps/fn-count.snap +0 -1
  113. package/src/qt4-snaps/fn-current-date.snap +0 -1
  114. package/src/qt4-snaps/fn-current-dateTime.snap +0 -1
  115. package/src/qt4-snaps/fn-current-time.snap +0 -1
  116. package/src/qt4-snaps/fn-data.snap +0 -8
  117. package/src/qt4-snaps/fn-dateTime.snap +0 -1
  118. package/src/qt4-snaps/fn-day-from-date.snap +0 -1
  119. package/src/qt4-snaps/fn-day-from-dateTime.snap +0 -1
  120. package/src/qt4-snaps/fn-days-from-duration.snap +0 -1
  121. package/src/qt4-snaps/fn-deep-equal.snap +0 -1
  122. package/src/qt4-snaps/fn-default-collation.snap +0 -1
  123. package/src/qt4-snaps/fn-default-language.snap +0 -1
  124. package/src/qt4-snaps/fn-distinct-values.snap +0 -1
  125. package/src/qt4-snaps/fn-doc-available.snap +0 -1
  126. package/src/qt4-snaps/fn-doc.snap +0 -1
  127. package/src/qt4-snaps/fn-document-uri.snap +0 -8
  128. package/src/qt4-snaps/fn-element-with-id.snap +0 -1
  129. package/src/qt4-snaps/fn-empty.snap +0 -1
  130. package/src/qt4-snaps/fn-encode-for-uri.snap +0 -1
  131. package/src/qt4-snaps/fn-ends-with.snap +0 -1
  132. package/src/qt4-snaps/fn-environment-variable.snap +0 -1
  133. package/src/qt4-snaps/fn-error.snap +0 -128
  134. package/src/qt4-snaps/fn-escape-html-uri.snap +0 -1
  135. package/src/qt4-snaps/fn-exactly-one.snap +0 -1
  136. package/src/qt4-snaps/fn-exists.snap +0 -1
  137. package/src/qt4-snaps/fn-false.snap +0 -1
  138. package/src/qt4-snaps/fn-filter.snap +0 -10
  139. package/src/qt4-snaps/fn-floor.snap +0 -1
  140. package/src/qt4-snaps/fn-fold-left.snap +0 -1
  141. package/src/qt4-snaps/fn-fold-right.snap +0 -1
  142. package/src/qt4-snaps/fn-for-each-pair.snap +0 -10
  143. package/src/qt4-snaps/fn-for-each.snap +0 -10
  144. package/src/qt4-snaps/fn-format-date.snap +0 -26
  145. package/src/qt4-snaps/fn-format-dateTime.snap +0 -1
  146. package/src/qt4-snaps/fn-format-integer.snap +0 -1
  147. package/src/qt4-snaps/fn-format-number.snap +0 -38
  148. package/src/qt4-snaps/fn-format-time.snap +0 -1
  149. package/src/qt4-snaps/fn-function-arity.snap +0 -1
  150. package/src/qt4-snaps/fn-function-lookup.snap +0 -1
  151. package/src/qt4-snaps/fn-function-name.snap +0 -1
  152. package/src/qt4-snaps/fn-generate-id.snap +0 -18
  153. package/src/qt4-snaps/fn-has-children.snap +0 -26
  154. package/src/qt4-snaps/fn-head.snap +0 -1
  155. package/src/qt4-snaps/fn-hours-from-dateTime.snap +0 -1
  156. package/src/qt4-snaps/fn-hours-from-duration.snap +0 -1
  157. package/src/qt4-snaps/fn-hours-from-time.snap +0 -1
  158. package/src/qt4-snaps/fn-id.snap +0 -10
  159. package/src/qt4-snaps/fn-idref.snap +0 -10
  160. package/src/qt4-snaps/fn-implicit-timezone.snap +0 -1
  161. package/src/qt4-snaps/fn-in-scope-prefixes.snap +0 -26
  162. package/src/qt4-snaps/fn-index-of.snap +0 -1
  163. package/src/qt4-snaps/fn-innermost.snap +0 -58
  164. package/src/qt4-snaps/fn-insert-before.snap +0 -1
  165. package/src/qt4-snaps/fn-iri-to-uri.snap +0 -1
  166. package/src/qt4-snaps/fn-json-doc.snap +0 -1
  167. package/src/qt4-snaps/fn-json-to-xml.snap +0 -1
  168. package/src/qt4-snaps/fn-lang.snap +0 -10
  169. package/src/qt4-snaps/fn-last.snap +0 -1
  170. package/src/qt4-snaps/fn-load-xquery-module.snap +0 -1
  171. package/src/qt4-snaps/fn-local-name-from-QName.snap +0 -1
  172. package/src/qt4-snaps/fn-local-name.snap +0 -10
  173. package/src/qt4-snaps/fn-lower-case.snap +0 -1
  174. package/src/qt4-snaps/fn-matches.re.snap +0 -1
  175. package/src/qt4-snaps/fn-matches.snap +0 -1
  176. package/src/qt4-snaps/fn-max.snap +0 -1
  177. package/src/qt4-snaps/fn-min.snap +0 -1
  178. package/src/qt4-snaps/fn-minutes-from-dateTime.snap +0 -1
  179. package/src/qt4-snaps/fn-minutes-from-duration.snap +0 -1
  180. package/src/qt4-snaps/fn-minutes-from-time.snap +0 -1
  181. package/src/qt4-snaps/fn-month-from-date.snap +0 -1
  182. package/src/qt4-snaps/fn-month-from-dateTime.snap +0 -1
  183. package/src/qt4-snaps/fn-months-from-duration.snap +0 -1
  184. package/src/qt4-snaps/fn-name.snap +0 -10
  185. package/src/qt4-snaps/fn-namespace-uri-for-prefix.snap +0 -1
  186. package/src/qt4-snaps/fn-namespace-uri-from-QName.snap +0 -1
  187. package/src/qt4-snaps/fn-namespace-uri.snap +0 -1
  188. package/src/qt4-snaps/fn-nilled.snap +0 -16
  189. package/src/qt4-snaps/fn-node-name.snap +0 -32
  190. package/src/qt4-snaps/fn-normalize-space.snap +0 -1
  191. package/src/qt4-snaps/fn-normalize-unicode.snap +0 -26
  192. package/src/qt4-snaps/fn-not.snap +0 -1
  193. package/src/qt4-snaps/fn-number.snap +0 -1
  194. package/src/qt4-snaps/fn-one-or-more.snap +0 -1
  195. package/src/qt4-snaps/fn-outermost.snap +0 -58
  196. package/src/qt4-snaps/fn-parse-ietf-date.snap +0 -1
  197. package/src/qt4-snaps/fn-parse-json.snap +0 -1
  198. package/src/qt4-snaps/fn-parse-xml-fragment.snap +0 -1
  199. package/src/qt4-snaps/fn-parse-xml.snap +0 -1
  200. package/src/qt4-snaps/fn-path.snap +0 -26
  201. package/src/qt4-snaps/fn-position.snap +0 -1
  202. package/src/qt4-snaps/fn-prefix-from-QName.snap +0 -1
  203. package/src/qt4-snaps/fn-random-number-generator.snap +0 -1
  204. package/src/qt4-snaps/fn-remove.snap +0 -1
  205. package/src/qt4-snaps/fn-replace.snap +0 -330
  206. package/src/qt4-snaps/fn-resolve-QName.snap +0 -1
  207. package/src/qt4-snaps/fn-resolve-uri.snap +0 -1
  208. package/src/qt4-snaps/fn-reverse.snap +0 -1
  209. package/src/qt4-snaps/fn-root.snap +0 -10
  210. package/src/qt4-snaps/fn-round-half-to-even.snap +0 -1
  211. package/src/qt4-snaps/fn-round.snap +0 -8
  212. package/src/qt4-snaps/fn-seconds-from-dateTime.snap +0 -1
  213. package/src/qt4-snaps/fn-seconds-from-duration.snap +0 -1
  214. package/src/qt4-snaps/fn-seconds-from-time.snap +0 -1
  215. package/src/qt4-snaps/fn-serialize.snap +0 -50
  216. package/src/qt4-snaps/fn-sort.snap +0 -1
  217. package/src/qt4-snaps/fn-starts-with.snap +0 -1
  218. package/src/qt4-snaps/fn-static-base-uri.snap +0 -1
  219. package/src/qt4-snaps/fn-string-join.snap +0 -8
  220. package/src/qt4-snaps/fn-string-length.snap +0 -1
  221. package/src/qt4-snaps/fn-string-to-codepoints.snap +0 -1
  222. package/src/qt4-snaps/fn-string.snap +0 -10
  223. package/src/qt4-snaps/fn-subsequence.snap +0 -1
  224. package/src/qt4-snaps/fn-substring-after.snap +0 -1
  225. package/src/qt4-snaps/fn-substring-before.snap +0 -1
  226. package/src/qt4-snaps/fn-substring.snap +0 -1
  227. package/src/qt4-snaps/fn-sum.snap +0 -1
  228. package/src/qt4-snaps/fn-tail.snap +0 -1
  229. package/src/qt4-snaps/fn-timezone-from-date.snap +0 -1
  230. package/src/qt4-snaps/fn-timezone-from-dateTime.snap +0 -1
  231. package/src/qt4-snaps/fn-timezone-from-time.snap +0 -1
  232. package/src/qt4-snaps/fn-tokenize.snap +0 -16
  233. package/src/qt4-snaps/fn-trace.snap +0 -8
  234. package/src/qt4-snaps/fn-transform.snap +0 -1
  235. package/src/qt4-snaps/fn-translate.snap +0 -1
  236. package/src/qt4-snaps/fn-true.snap +0 -1
  237. package/src/qt4-snaps/fn-unordered.snap +0 -1
  238. package/src/qt4-snaps/fn-unparsed-text-available.snap +0 -1
  239. package/src/qt4-snaps/fn-unparsed-text-lines.snap +0 -1
  240. package/src/qt4-snaps/fn-unparsed-text.snap +0 -1
  241. package/src/qt4-snaps/fn-upper-case.snap +0 -1
  242. package/src/qt4-snaps/fn-uri-collection.snap +0 -1
  243. package/src/qt4-snaps/fn-xml-to-json.snap +0 -1
  244. package/src/qt4-snaps/fn-year-from-date.snap +0 -1
  245. package/src/qt4-snaps/fn-year-from-dateTime.snap +0 -1
  246. package/src/qt4-snaps/fn-years-from-duration.snap +0 -1
  247. package/src/qt4-snaps/fn-zero-or-one.snap +0 -1
  248. package/src/qt4-snaps/map-contains.snap +0 -1
  249. package/src/qt4-snaps/map-entry.snap +0 -1
  250. package/src/qt4-snaps/map-find.snap +0 -1
  251. package/src/qt4-snaps/map-for-each.snap +0 -1
  252. package/src/qt4-snaps/map-get.snap +0 -1
  253. package/src/qt4-snaps/map-keys.snap +0 -1
  254. package/src/qt4-snaps/map-merge.snap +0 -1
  255. package/src/qt4-snaps/map-put.snap +0 -1
  256. package/src/qt4-snaps/map-remove.snap +0 -1
  257. package/src/qt4-snaps/map-size.snap +0 -1
  258. package/src/qt4-snaps/math-math-acos.snap +0 -1
  259. package/src/qt4-snaps/math-math-asin.snap +0 -1
  260. package/src/qt4-snaps/math-math-atan.snap +0 -1
  261. package/src/qt4-snaps/math-math-atan2.snap +0 -1
  262. package/src/qt4-snaps/math-math-cos.snap +0 -1
  263. package/src/qt4-snaps/math-math-exp.snap +0 -1
  264. package/src/qt4-snaps/math-math-exp10.snap +0 -1
  265. package/src/qt4-snaps/math-math-log.snap +0 -1
  266. package/src/qt4-snaps/math-math-log10.snap +0 -1
  267. package/src/qt4-snaps/math-math-pi.snap +0 -1
  268. package/src/qt4-snaps/math-math-pow.snap +0 -1
  269. package/src/qt4-snaps/math-math-sin.snap +0 -1
  270. package/src/qt4-snaps/math-math-sqrt.snap +0 -1
  271. package/src/qt4-snaps/math-math-tan.snap +0 -1
  272. package/src/qt4-snaps/misc-AnnexE.snap +0 -1
  273. package/src/qt4-snaps/misc-AppendixA4.snap +0 -1
  274. package/src/qt4-snaps/misc-CombinedErrorCodes.snap +0 -350
  275. package/src/qt4-snaps/misc-ErrorsAndOptimization.snap +0 -1
  276. package/src/qt4-snaps/misc-HigherOrderFunctions.snap +0 -32
  277. package/src/qt4-snaps/misc-JsonTestSuite.snap +0 -1
  278. package/src/qt4-snaps/misc-StaticContext.snap +0 -8
  279. package/src/qt4-snaps/misc-Surrogates.snap +0 -34
  280. package/src/qt4-snaps/misc-UCACollation.snap +0 -1
  281. package/src/qt4-snaps/misc-XMLEdition.snap +0 -22
  282. package/src/qt4-snaps/op-QName-equal.snap +0 -1
  283. package/src/qt4-snaps/op-add-dayTimeDuration-to-date.snap +0 -1
  284. package/src/qt4-snaps/op-add-dayTimeDuration-to-dateTime.snap +0 -1
  285. package/src/qt4-snaps/op-add-dayTimeDuration-to-time.snap +0 -1
  286. package/src/qt4-snaps/op-add-dayTimeDurations.snap +0 -1
  287. package/src/qt4-snaps/op-add-yearMonthDuration-to-date.snap +0 -1
  288. package/src/qt4-snaps/op-add-yearMonthDuration-to-dateTime.snap +0 -1
  289. package/src/qt4-snaps/op-add-yearMonthDurations.snap +0 -1
  290. package/src/qt4-snaps/op-anyURI-equal.snap +0 -1
  291. package/src/qt4-snaps/op-anyURI-greater-than.snap +0 -1
  292. package/src/qt4-snaps/op-anyURI-less-than.snap +0 -1
  293. package/src/qt4-snaps/op-bang.snap +0 -1
  294. package/src/qt4-snaps/op-base64Binary-equal.snap +0 -1
  295. package/src/qt4-snaps/op-base64Binary-greater-than.snap +0 -1
  296. package/src/qt4-snaps/op-base64Binary-less-than.snap +0 -1
  297. package/src/qt4-snaps/op-boolean-equal.snap +0 -1
  298. package/src/qt4-snaps/op-boolean-greater-than.snap +0 -1
  299. package/src/qt4-snaps/op-boolean-less-than.snap +0 -1
  300. package/src/qt4-snaps/op-concat.snap +0 -1
  301. package/src/qt4-snaps/op-concatenate.snap +0 -1
  302. package/src/qt4-snaps/op-date-equal.snap +0 -1
  303. package/src/qt4-snaps/op-date-greater-than.snap +0 -1
  304. package/src/qt4-snaps/op-date-less-than.snap +0 -1
  305. package/src/qt4-snaps/op-dateTime-equal.snap +0 -1
  306. package/src/qt4-snaps/op-dateTime-greater-than.snap +0 -1
  307. package/src/qt4-snaps/op-dateTime-less-than.snap +0 -1
  308. package/src/qt4-snaps/op-dayTimeDuration-greater-than.snap +0 -1
  309. package/src/qt4-snaps/op-dayTimeDuration-less-than.snap +0 -1
  310. package/src/qt4-snaps/op-divide-dayTimeDuration-by-dayTimeDuration.snap +0 -1
  311. package/src/qt4-snaps/op-divide-dayTimeDuration.snap +0 -1
  312. package/src/qt4-snaps/op-divide-yearMonthDuration-by-yearMonthDuration.snap +0 -1
  313. package/src/qt4-snaps/op-divide-yearMonthDuration.snap +0 -1
  314. package/src/qt4-snaps/op-duration-equal.snap +0 -1
  315. package/src/qt4-snaps/op-except.snap +0 -1
  316. package/src/qt4-snaps/op-gDay-equal.snap +0 -1
  317. package/src/qt4-snaps/op-gMonth-equal.snap +0 -1
  318. package/src/qt4-snaps/op-gMonthDay-equal.snap +0 -1
  319. package/src/qt4-snaps/op-gYear-equal.snap +0 -1
  320. package/src/qt4-snaps/op-gYearMonth-equal.snap +0 -1
  321. package/src/qt4-snaps/op-hexBinary-equal.snap +0 -1
  322. package/src/qt4-snaps/op-hexBinary-greater-than.snap +0 -1
  323. package/src/qt4-snaps/op-hexBinary-less-than.snap +0 -1
  324. package/src/qt4-snaps/op-intersect.snap +0 -1
  325. package/src/qt4-snaps/op-is-same-node.snap +0 -1
  326. package/src/qt4-snaps/op-multiply-dayTimeDuration.snap +0 -1
  327. package/src/qt4-snaps/op-multiply-yearMonthDuration.snap +0 -1
  328. package/src/qt4-snaps/op-node-after.snap +0 -1
  329. package/src/qt4-snaps/op-node-before.snap +0 -1
  330. package/src/qt4-snaps/op-numeric-add.snap +0 -1
  331. package/src/qt4-snaps/op-numeric-divide.snap +0 -1
  332. package/src/qt4-snaps/op-numeric-equal.snap +0 -1
  333. package/src/qt4-snaps/op-numeric-greater-than.snap +0 -1
  334. package/src/qt4-snaps/op-numeric-integer-divide.snap +0 -1
  335. package/src/qt4-snaps/op-numeric-less-than.snap +0 -1
  336. package/src/qt4-snaps/op-numeric-mod.snap +0 -1
  337. package/src/qt4-snaps/op-numeric-multiply.snap +0 -1
  338. package/src/qt4-snaps/op-numeric-subtract.snap +0 -1
  339. package/src/qt4-snaps/op-numeric-unary-minus.snap +0 -1
  340. package/src/qt4-snaps/op-numeric-unary-plus.snap +0 -1
  341. package/src/qt4-snaps/op-same-key.snap +0 -1
  342. package/src/qt4-snaps/op-string-equal.snap +0 -1
  343. package/src/qt4-snaps/op-string-greater-than.snap +0 -1
  344. package/src/qt4-snaps/op-string-less-than.snap +0 -1
  345. package/src/qt4-snaps/op-subtract-dateTimes.snap +0 -1
  346. package/src/qt4-snaps/op-subtract-dates.snap +0 -1
  347. package/src/qt4-snaps/op-subtract-dayTimeDuration-from-date.snap +0 -1
  348. package/src/qt4-snaps/op-subtract-dayTimeDuration-from-dateTime.snap +0 -1
  349. package/src/qt4-snaps/op-subtract-dayTimeDuration-from-time.snap +0 -1
  350. package/src/qt4-snaps/op-subtract-dayTimeDurations.snap +0 -1
  351. package/src/qt4-snaps/op-subtract-times.snap +0 -1
  352. package/src/qt4-snaps/op-subtract-yearMonthDuration-from-date.snap +0 -1
  353. package/src/qt4-snaps/op-subtract-yearMonthDuration-from-dateTime.snap +0 -1
  354. package/src/qt4-snaps/op-subtract-yearMonthDurations.snap +0 -1
  355. package/src/qt4-snaps/op-time-equal.snap +0 -1
  356. package/src/qt4-snaps/op-time-greater-than.snap +0 -1
  357. package/src/qt4-snaps/op-time-less-than.snap +0 -1
  358. package/src/qt4-snaps/op-to.snap +0 -1
  359. package/src/qt4-snaps/op-union.snap +0 -1
  360. package/src/qt4-snaps/op-yearMonthDuration-greater-than.snap +0 -1
  361. package/src/qt4-snaps/op-yearMonthDuration-less-than.snap +0 -1
  362. package/src/qt4-snaps/prod-AllowingEmpty.snap +0 -1
  363. package/src/qt4-snaps/prod-Annotation.snap +0 -146
  364. package/src/qt4-snaps/prod-ArrayType.snap +0 -1
  365. package/src/qt4-snaps/prod-ArrowExpr.snap +0 -1
  366. package/src/qt4-snaps/prod-AxisStep.abbr.snap +0 -1
  367. package/src/qt4-snaps/prod-AxisStep.ancestor-or-self.snap +0 -1
  368. package/src/qt4-snaps/prod-AxisStep.ancestor.snap +0 -1
  369. package/src/qt4-snaps/prod-AxisStep.following-sibling.snap +0 -1
  370. package/src/qt4-snaps/prod-AxisStep.following.snap +0 -1
  371. package/src/qt4-snaps/prod-AxisStep.preceding-sibling.snap +0 -1
  372. package/src/qt4-snaps/prod-AxisStep.preceding.snap +0 -1
  373. package/src/qt4-snaps/prod-AxisStep.snap +0 -114
  374. package/src/qt4-snaps/prod-AxisStep.unabbr.snap +0 -1
  375. package/src/qt4-snaps/prod-BaseURIDecl.snap +0 -20
  376. package/src/qt4-snaps/prod-BoundarySpaceDecl.snap +0 -14
  377. package/src/qt4-snaps/prod-CastExpr.derived.snap +0 -1
  378. package/src/qt4-snaps/prod-CastExpr.snap +0 -218
  379. package/src/qt4-snaps/prod-CastableExpr.snap +0 -56
  380. package/src/qt4-snaps/prod-Comment.snap +0 -1
  381. package/src/qt4-snaps/prod-CompAttrConstructor.snap +0 -14
  382. package/src/qt4-snaps/prod-CompCommentConstructor.snap +0 -8
  383. package/src/qt4-snaps/prod-CompDocConstructor.snap +0 -1
  384. package/src/qt4-snaps/prod-CompElemConstructor.snap +0 -1
  385. package/src/qt4-snaps/prod-CompNamespaceConstructor.snap +0 -1
  386. package/src/qt4-snaps/prod-CompPIConstructor.snap +0 -1
  387. package/src/qt4-snaps/prod-CompTextConstructor.snap +0 -8
  388. package/src/qt4-snaps/prod-ConstructionDecl.snap +0 -14
  389. package/src/qt4-snaps/prod-ContextItemDecl.snap +0 -20
  390. package/src/qt4-snaps/prod-ContextItemExpr.snap +0 -1
  391. package/src/qt4-snaps/prod-CopyNamespacesDecl.snap +0 -14
  392. package/src/qt4-snaps/prod-CountClause.snap +0 -1
  393. package/src/qt4-snaps/prod-CurlyArrayConstructor.snap +0 -1
  394. package/src/qt4-snaps/prod-DecimalFormatDecl.snap +0 -92
  395. package/src/qt4-snaps/prod-DefaultCollationDecl.snap +0 -32
  396. package/src/qt4-snaps/prod-DefaultNamespaceDecl.snap +0 -92
  397. package/src/qt4-snaps/prod-DirAttributeList.snap +0 -58
  398. package/src/qt4-snaps/prod-DirElemConstructor.snap +0 -62
  399. package/src/qt4-snaps/prod-DirElemContent.namespace.snap +0 -176
  400. package/src/qt4-snaps/prod-DirElemContent.snap +0 -14
  401. package/src/qt4-snaps/prod-DirElemContent.whitespace.snap +0 -178
  402. package/src/qt4-snaps/prod-DirectConstructor.snap +0 -56
  403. package/src/qt4-snaps/prod-EQName.snap +0 -48
  404. package/src/qt4-snaps/prod-EmptyOrderDecl.snap +0 -14
  405. package/src/qt4-snaps/prod-ExtensionExpr.snap +0 -50
  406. package/src/qt4-snaps/prod-ForClause.snap +0 -158
  407. package/src/qt4-snaps/prod-FunctionCall.snap +0 -102
  408. package/src/qt4-snaps/prod-FunctionDecl.snap +0 -256
  409. package/src/qt4-snaps/prod-GeneralComp.eq.snap +0 -1
  410. package/src/qt4-snaps/prod-GeneralComp.ge.snap +0 -1
  411. package/src/qt4-snaps/prod-GeneralComp.gt.snap +0 -1
  412. package/src/qt4-snaps/prod-GeneralComp.le.snap +0 -1
  413. package/src/qt4-snaps/prod-GeneralComp.lt.snap +0 -1
  414. package/src/qt4-snaps/prod-GeneralComp.ne.snap +0 -1
  415. package/src/qt4-snaps/prod-GroupByClause.snap +0 -8
  416. package/src/qt4-snaps/prod-IfExpr.snap +0 -1
  417. package/src/qt4-snaps/prod-InlineFunctionExpr.snap +0 -14
  418. package/src/qt4-snaps/prod-InstanceofExpr.snap +0 -38
  419. package/src/qt4-snaps/prod-LetClause.snap +0 -40
  420. package/src/qt4-snaps/prod-Literal.snap +0 -68
  421. package/src/qt4-snaps/prod-Lookup.snap +0 -1
  422. package/src/qt4-snaps/prod-MapConstructor.snap +0 -1
  423. package/src/qt4-snaps/prod-MapType.snap +0 -8
  424. package/src/qt4-snaps/prod-ModuleImport.snap +0 -224
  425. package/src/qt4-snaps/prod-NameTest.snap +0 -164
  426. package/src/qt4-snaps/prod-NamedFunctionRef.snap +0 -1
  427. package/src/qt4-snaps/prod-NamespaceDecl.snap +0 -80
  428. package/src/qt4-snaps/prod-NodeTest.snap +0 -50
  429. package/src/qt4-snaps/prod-OptionDecl.serialization.snap +0 -14
  430. package/src/qt4-snaps/prod-OptionDecl.snap +0 -20
  431. package/src/qt4-snaps/prod-OrExpr.snap +0 -1
  432. package/src/qt4-snaps/prod-OrderByClause.snap +0 -20
  433. package/src/qt4-snaps/prod-OrderingModeDecl.snap +0 -14
  434. package/src/qt4-snaps/prod-ParenthesizedExpr.snap +0 -1
  435. package/src/qt4-snaps/prod-PathExpr.snap +0 -34
  436. package/src/qt4-snaps/prod-PositionalVar.snap +0 -26
  437. package/src/qt4-snaps/prod-Predicate.snap +0 -14
  438. package/src/qt4-snaps/prod-QuantifiedExpr.snap +0 -164
  439. package/src/qt4-snaps/prod-ReturnClause.snap +0 -8
  440. package/src/qt4-snaps/prod-SequenceType.snap +0 -1
  441. package/src/qt4-snaps/prod-SquareArrayConstructor.snap +0 -1
  442. package/src/qt4-snaps/prod-StepExpr.snap +0 -1
  443. package/src/qt4-snaps/prod-StringConstructor.snap +0 -26
  444. package/src/qt4-snaps/prod-SwitchExpr.snap +0 -1
  445. package/src/qt4-snaps/prod-TreatExpr.snap +0 -14
  446. package/src/qt4-snaps/prod-TryCatchExpr.snap +0 -38
  447. package/src/qt4-snaps/prod-TypeswitchExpr.snap +0 -50
  448. package/src/qt4-snaps/prod-UnaryLookup.snap +0 -1
  449. package/src/qt4-snaps/prod-UnorderedExpr.snap +0 -14
  450. package/src/qt4-snaps/prod-ValueComp.snap +0 -1
  451. package/src/qt4-snaps/prod-VarDecl.external.snap +0 -82
  452. package/src/qt4-snaps/prod-VarDecl.snap +0 -146
  453. package/src/qt4-snaps/prod-VarDefaultValue.snap +0 -8
  454. package/src/qt4-snaps/prod-VersionDecl.snap +0 -68
  455. package/src/qt4-snaps/prod-WhereClause.snap +0 -26
  456. package/src/qt4-snaps/prod-WindowClause.snap +0 -98
  457. package/src/qt4-snaps/ser-method-adaptive.snap +0 -1
  458. package/src/qt4-snaps/ser-method-html.snap +0 -1
  459. package/src/qt4-snaps/ser-method-xml.snap +0 -1
  460. package/src/qt4-snaps/upd-AdditionalTyping.snap +0 -1
  461. package/src/qt4-snaps/upd-AddressBookUpdates.snap +0 -1
  462. package/src/qt4-snaps/upd-AttrDataModelErrs.snap +0 -1
  463. package/src/qt4-snaps/upd-CommaExpression.snap +0 -1
  464. package/src/qt4-snaps/upd-Compatibility.snap +0 -1
  465. package/src/qt4-snaps/upd-ConditionalExpression.snap +0 -1
  466. package/src/qt4-snaps/upd-DeleteExpressions.snap +0 -1
  467. package/src/qt4-snaps/upd-FLWORExpression.snap +0 -1
  468. package/src/qt4-snaps/upd-FullAxis.snap +0 -1
  469. package/src/qt4-snaps/upd-FunctionCall.snap +0 -1
  470. package/src/qt4-snaps/upd-FunctionDeclaration.snap +0 -114
  471. package/src/qt4-snaps/upd-InsertExpressions.snap +0 -1
  472. package/src/qt4-snaps/upd-MinOther.snap +0 -1
  473. package/src/qt4-snaps/upd-NSBindingConflictErrs.snap +0 -1
  474. package/src/qt4-snaps/upd-NamespacesUpdates.snap +0 -1
  475. package/src/qt4-snaps/upd-NilUpdates.snap +0 -10
  476. package/src/qt4-snaps/upd-OtherExpressions.snap +0 -1
  477. package/src/qt4-snaps/upd-ParenthesizedExpressions.snap +0 -1
  478. package/src/qt4-snaps/upd-PartsUpdates.snap +0 -1
  479. package/src/qt4-snaps/upd-RelationalDataUpdates.snap +0 -1
  480. package/src/qt4-snaps/upd-RenameExpressions.snap +0 -1
  481. package/src/qt4-snaps/upd-ReplaceNode.snap +0 -1
  482. package/src/qt4-snaps/upd-ReplaceValue.snap +0 -1
  483. package/src/qt4-snaps/upd-RevalidationDeclarationLax.snap +0 -1
  484. package/src/qt4-snaps/upd-RevalidationDeclarationLaxUnsupported.snap +0 -1
  485. package/src/qt4-snaps/upd-RevalidationDeclarationSkip.snap +0 -10
  486. package/src/qt4-snaps/upd-RevalidationDeclarationSkipUnsupported.snap +0 -1
  487. package/src/qt4-snaps/upd-RevalidationDeclarationStrict.snap +0 -1
  488. package/src/qt4-snaps/upd-RevalidationDeclarationStrictUnsupported.snap +0 -1
  489. package/src/qt4-snaps/upd-RevalidationDeclarationStrictandSkip.snap +0 -1
  490. package/src/qt4-snaps/upd-SoapUpdates.snap +0 -1
  491. package/src/qt4-snaps/upd-TransformExpressions.snap +0 -1
  492. package/src/qt4-snaps/upd-TypeswitchExpression.snap +0 -1
  493. package/src/qt4-snaps/upd-VariableDeclaration.snap +0 -1
  494. package/src/qt4-snaps/upd-applyUpdates.snap +0 -1
  495. package/src/qt4-snaps/upd-fnput-document.snap +0 -1
  496. package/src/qt4-snaps/upd-mergeUpdates.snap +0 -1
  497. package/src/qt4-snaps/upd-propagateNamespace.snap +0 -1
  498. package/src/qt4-snaps/upd-setToUntyped.snap +0 -1
  499. package/src/qt4-snaps/xs-anyAtomicType.snap +0 -1
  500. package/src/qt4-snaps/xs-anySimpleType.snap +0 -8
  501. package/src/qt4-snaps/xs-anyURI.snap +0 -34
  502. package/src/qt4-snaps/xs-base64Binary.snap +0 -1
  503. package/src/qt4-snaps/xs-dateTimeStamp.snap +0 -1
  504. package/src/qt4-snaps/xs-double.snap +0 -1
  505. package/src/qt4-snaps/xs-error.snap +0 -10
  506. package/src/qt4-snaps/xs-float.snap +0 -1
  507. package/src/qt4-snaps/xs-hexBinary.snap +0 -1
  508. package/src/qt4-snaps/xs-normalizedString.snap +0 -1
  509. package/src/qt4-snaps/xs-notation.snap +0 -1
  510. package/src/qt4-snaps/xs-numeric.snap +0 -1
  511. package/src/qt4-snaps/xs-token.snap +0 -1
  512. package/src/runtimes.test.ts +0 -152
  513. package/src/typechecker.test.ts +0 -548
  514. package/src/unused-diagnostics.test.ts +0 -174
package/CHANGELOG.md CHANGED
@@ -1,5 +1,30 @@
1
1
  # Changelog
2
2
 
3
+ ## [1.5.0](https://github.com/DrRataplan/xq-lsp/compare/lsp-v1.4.1...lsp-v1.5.0) (2026-06-18)
4
+
5
+
6
+ ### Features
7
+
8
+ * **completion:** add function param completions with proper scope isolation ([dab41a3](https://github.com/DrRataplan/xq-lsp/commit/dab41a349ae1d387f1b32b530e476b1d30da8f07))
9
+ * **diagnostics:** report undeclared variable references as XPST0008 ([6ff1fa9](https://github.com/DrRataplan/xq-lsp/commit/6ff1fa9d5a9ecfb4d440119f3efa9e3f96204e05))
10
+ * eXist-db pre-declared namespaces suppress false XQST0081 diagnostics ([cd94650](https://github.com/DrRataplan/xq-lsp/commit/cd94650db968d727717de62e6a60411481a7fb16))
11
+
12
+
13
+ ### Bug Fixes
14
+
15
+ * inject W3C predeclared namespaces in qt4-worker ([4c93ad6](https://github.com/DrRataplan/xq-lsp/commit/4c93ad677db0eb266e04f080ee1a1ad986dfc03a))
16
+ * **variable-diagnostics:** add explicit type annotation to fix TS build ([5867d7e](https://github.com/DrRataplan/xq-lsp/commit/5867d7ea549026cda98559b8d980f3bdf561f32f))
17
+ * **vscode:** make extension work by shimming import.meta.url ([fca848a](https://github.com/DrRataplan/xq-lsp/commit/fca848af51ee17a0dba8e7b95f4767c4d1ce974f))
18
+
19
+ ## [1.4.1](https://github.com/DrRataplan/xq-lsp/compare/lsp-v1.4.0...lsp-v1.4.1) (2026-06-10)
20
+
21
+
22
+ ### Bug Fixes
23
+
24
+ * change the bin to the dist version ([e77944d](https://github.com/DrRataplan/xq-lsp/commit/e77944de7da857ac6ca9d3148b4a41abec175de4))
25
+ * do not package testing snapshots to npm ([9638734](https://github.com/DrRataplan/xq-lsp/commit/963873401f3e4d74a9338c387bcfc3c3564f4f0d))
26
+ * union multiple imports of modules ([1d77b65](https://github.com/DrRataplan/xq-lsp/commit/1d77b65b48933abfe20c6f0e9abd113c318f16b4))
27
+
3
28
  ## [1.4.0](https://github.com/DrRataplan/xq-lsp/compare/lsp-v1.3.0...lsp-v1.4.0) (2026-05-28)
4
29
 
5
30
 
package/README.md CHANGED
@@ -59,24 +59,70 @@ For files with syntax errors (common while editing), the server falls back to re
59
59
 
60
60
  Use the `lib` key to load built-in definitions for a specific runtime:
61
61
 
62
- | Value | Runtime |
63
- | --------- | ------------------------------------------------------------------- |
64
- | `"fonto"` | [Fonto XML editor](https://www.fontoxml.com/) — `fonto:*` functions |
62
+ | Value | Runtime |
63
+ | ----------- | ------------------------------------------------------------------------- |
64
+ | `"fonto"` | [Fonto XML editor](https://www.fontoxml.com/) — `fonto:*` functions |
65
+ | `"existdb"` | [eXist-db](https://exist-db.org/) — all extension module functions |
65
66
 
66
67
  ```xquery
67
- map {"glob": "src/**/*.xq", "lib": "fonto"}
68
+ map {"glob": "src/**/*.xq", "lib": "existdb"}
68
69
  ```
69
70
 
70
- Then import the namespace in your XQuery files as usual — the server resolves completions, hover, and go-to-definition against the bundled definitions:
71
+ Multiple libs use an XPath sequence:
71
72
 
72
73
  ```xquery
73
- import module namespace fonto="http://www.fontoxml.com/functions";
74
+ map {"glob": "src/**/*.xq", "lib": ("fonto", "other")}
74
75
  ```
75
76
 
76
- Multiple libs use an XPath sequence:
77
+ #### eXist-db runtime
78
+
79
+ The `"existdb"` runtime bundles stub definitions for every eXist-db extension
80
+ module (`util`, `xmldb`, `request`, `sm`, `ft`, `compression`, …).
81
+
82
+ eXist-db automatically pre-declares a large set of namespace prefixes — you can
83
+ call `util:log(…)`, `xmldb:store(…)`, `process:execute(…)`, etc. without any
84
+ `import module namespace` statement. When the `existdb` runtime is active the
85
+ server knows about these pre-declared prefixes and:
86
+
87
+ - **suppresses** false `XQST0081` ("namespace prefix not declared") diagnostics
88
+ for all pre-declared namespaces
89
+ - **provides completions, hover, and go-to-definition** for those modules
90
+ without requiring an explicit `import module namespace` in your source
91
+
92
+ If you do choose to write explicit imports (e.g. for editor portability), the
93
+ server handles those correctly too:
77
94
 
78
95
  ```xquery
79
- map {"glob": "src/**/*.xq", "lib": ("fonto", "other")}
96
+ (: explicit import — also fine :)
97
+ import module namespace util = "http://exist-db.org/xquery/util";
98
+ util:uuid()
99
+ ```
100
+
101
+ Modules that require explicit import even in eXist-db (e.g. `datetime`,
102
+ `httpclient`, `console`, `crypto`, `kwic`) still need a `import module
103
+ namespace` declaration; the server offers quick-fix code actions to insert it.
104
+
105
+ ```xquery
106
+ (: lsp-config.xq in your project root :)
107
+ map {
108
+ "glob": "src/**/*.xq",
109
+ "lib": "existdb",
110
+ "import": map {
111
+ "generateLocationHints": false()
112
+ }
113
+ }
114
+ ```
115
+
116
+ The `generateLocationHints: false()` setting prevents the server from appending
117
+ `at "…"` paths to generated imports, which eXist-db does not need (it resolves
118
+ modules by namespace URI).
119
+
120
+ #### Fonto runtime
121
+
122
+ Then import the namespace in your XQuery files as usual — the server resolves completions, hover, and go-to-definition against the bundled definitions:
123
+
124
+ ```xquery
125
+ import module namespace fonto="http://www.fontoxml.com/functions";
80
126
  ```
81
127
 
82
128
  ### Location hints
@@ -14,4 +14,4 @@ export interface CompletionEntry {
14
14
  isSnippet: boolean;
15
15
  }
16
16
  export declare function functionDoc(fn: FunctionSymbol): string;
17
- export declare function getCompletions(ctx: CompletionContext, currentAnalysis: FileAnalysis, importedAnalyses: Map<string, FileAnalysis>, snippets?: boolean): CompletionEntry[];
17
+ export declare function getCompletions(ctx: CompletionContext, currentAnalysis: FileAnalysis, importedAnalyses: Map<string, FileAnalysis>, snippets?: boolean, lastValidAnalysis?: FileAnalysis): CompletionEntry[];
@@ -1,5 +1,5 @@
1
1
  import { formatQName } from "./types.js";
2
- import { resolvePrefix } from "./analyzer.js";
2
+ import { resolvePrefix, nodeStackAtOffset, findAll } from "./analyzer.js";
3
3
  function parseToken(textBefore) {
4
4
  const match = textBefore.match(/\$([\w:\-]*)$|(?:([\w\-]+):)([\w\-]*)$|([\w\-]+)$/);
5
5
  if (!match)
@@ -41,6 +41,31 @@ function buildVariableEntry(v, filter) {
41
41
  return null;
42
42
  return { label, kind: "variable", insertText: label, isSnippet: false };
43
43
  }
44
+ function buildParamEntry(p, filter) {
45
+ if (filter && !p.name.toLowerCase().startsWith(filter.toLowerCase()))
46
+ return null;
47
+ return {
48
+ label: `$${p.name}`,
49
+ kind: "variable",
50
+ detail: p.type ? `as ${p.type}` : undefined,
51
+ insertText: `$${p.name}`,
52
+ isSnippet: false,
53
+ };
54
+ }
55
+ /** Find the function symbol enclosing the cursor using the AST. */
56
+ function findEnclosingFunction(ast, cursorOffset, functions) {
57
+ const stack = nodeStackAtOffset(ast, cursorOffset);
58
+ const bodyNode = stack.slice().reverse().find((n) => n.type === "FunctionBody");
59
+ if (!bodyNode || bodyNode.start === undefined || bodyNode.end == null)
60
+ return null;
61
+ const annotatedNode = stack.find((n) => n.type === "AnnotatedDecl");
62
+ if (!annotatedNode || annotatedNode.start === undefined)
63
+ return null;
64
+ const fn = functions.find((f) => f.sourceOffset === annotatedNode.start);
65
+ if (!fn)
66
+ return null;
67
+ return { fn, bodyStart: bodyNode.start, bodyEnd: bodyNode.end };
68
+ }
44
69
  function buildFunctionEntry(fn, label, snippets) {
45
70
  return {
46
71
  label,
@@ -51,23 +76,63 @@ function buildFunctionEntry(fn, label, snippets) {
51
76
  isSnippet: snippets && fn.params.length > 0,
52
77
  };
53
78
  }
54
- export function getCompletions(ctx, currentAnalysis, importedAnalyses, snippets = false) {
79
+ export function getCompletions(ctx, currentAnalysis, importedAnalyses, snippets = false, lastValidAnalysis) {
55
80
  const token = parseToken(ctx.textBeforeCursor);
56
81
  const items = [];
57
82
  if (token.kind === "variable") {
58
83
  const filter = token.prefix;
84
+ // Module-level variables are always visible
59
85
  for (const v of currentAnalysis.moduleVariables) {
60
86
  const e = buildVariableEntry(v, filter);
61
87
  if (e)
62
88
  items.push(e);
63
89
  }
64
- for (const v of currentAnalysis.localBindings) {
65
- if (v.offset < ctx.cursorOffset) {
66
- const e = buildVariableEntry(v, filter);
67
- if (e)
68
- items.push(e);
90
+ // Prefer the current AST; fall back to the last successfully-parsed one for scope analysis
91
+ const scopeAst = currentAnalysis.ast ?? lastValidAnalysis?.ast;
92
+ if (scopeAst) {
93
+ const enclosing = findEnclosingFunction(scopeAst, ctx.cursorOffset, currentAnalysis.functions);
94
+ if (enclosing) {
95
+ // Inside a function body: params + local bindings within this body before cursor
96
+ for (const p of enclosing.fn.params) {
97
+ const e = buildParamEntry(p, filter);
98
+ if (e)
99
+ items.push(e);
100
+ }
101
+ for (const v of currentAnalysis.localBindings) {
102
+ if (v.offset > enclosing.bodyStart && v.offset < ctx.cursorOffset && v.offset < enclosing.bodyEnd) {
103
+ const e = buildVariableEntry(v, filter);
104
+ if (e)
105
+ items.push(e);
106
+ }
107
+ }
108
+ }
109
+ else {
110
+ // In query body: exclude local bindings that live inside function bodies
111
+ const functionBodyRanges = findAll(scopeAst, "FunctionBody")
112
+ .filter((b) => b.start !== undefined && b.end != null)
113
+ .map((b) => ({ start: b.start, end: b.end }));
114
+ for (const v of currentAnalysis.localBindings) {
115
+ if (v.offset >= ctx.cursorOffset)
116
+ continue;
117
+ if (functionBodyRanges.some((r) => v.offset >= r.start && v.offset <= r.end))
118
+ continue;
119
+ const e = buildVariableEntry(v, filter);
120
+ if (e)
121
+ items.push(e);
122
+ }
123
+ }
124
+ }
125
+ else {
126
+ // No AST ever available: simple offset-based filter, no function-param completions
127
+ for (const v of currentAnalysis.localBindings) {
128
+ if (v.offset < ctx.cursorOffset) {
129
+ const e = buildVariableEntry(v, filter);
130
+ if (e)
131
+ items.push(e);
132
+ }
69
133
  }
70
134
  }
135
+ // Imported module-level variables are always visible
71
136
  for (const analysis of importedAnalyses.values()) {
72
137
  for (const v of analysis.moduleVariables) {
73
138
  const e = buildVariableEntry(v, filter);
@@ -1,2 +1,15 @@
1
- import type { FileAnalysis } from "./types.ts";
1
+ import type { FileAnalysis, NamespaceDecl } from "./types.ts";
2
+ /**
3
+ * Returns all namespace declarations that are in scope without any explicit
4
+ * `import module namespace` or `declare namespace` statement. Includes the
5
+ * standard XQuery 3.1 predeclared namespaces (math, map, array) and any
6
+ * runtime-specific additions (e.g. eXist-db's util, xmldb, …).
7
+ */
8
+ export declare function getRuntimePredeclaredNamespaces(runtimes: string[]): NamespaceDecl[];
9
+ /**
10
+ * Return a copy of `analysis` with the given predeclared namespace declarations
11
+ * merged into `namespaceDecls`. Prefixes already visible via imports, the
12
+ * module's own prefix, or an existing `declare namespace` are skipped.
13
+ */
14
+ export declare function withPredeclaredNs(analysis: FileAnalysis, predeclaredNs: NamespaceDecl[]): FileAnalysis;
2
15
  export declare function getRuntimeAnalyses(runtimes: string[]): FileAnalysis[];
package/dist/runtimes.js CHANGED
@@ -3,6 +3,14 @@ import * as fs from "fs";
3
3
  import { fileURLToPath } from "url";
4
4
  import { analyze } from "./analyzer.js";
5
5
  const runtimesDir = path.join(path.dirname(fileURLToPath(import.meta.url)), "runtimes");
6
+ function toNamespaceDecls(raw) {
7
+ return Object.entries(raw).map(([prefix, namespaceUri]) => ({ prefix, namespaceUri }));
8
+ }
9
+ // Lazily loaded predeclared namespace list for the existdb runtime.
10
+ let existdbPredeclared = null;
11
+ function loadExistdbPredeclared() {
12
+ return (existdbPredeclared ??= toNamespaceDecls(JSON.parse(fs.readFileSync(path.join(runtimesDir, "existdb", "predeclared-namespaces.json"), "utf-8"))));
13
+ }
6
14
  const RUNTIME_FILES = {
7
15
  fonto: [path.join(runtimesDir, "fonto", "fonto.xq")],
8
16
  existdb: [
@@ -39,6 +47,35 @@ const RUNTIME_FILES = {
39
47
  ],
40
48
  };
41
49
  const runtimeAnalysisCache = new Map();
50
+ /**
51
+ * Returns all namespace declarations that are in scope without any explicit
52
+ * `import module namespace` or `declare namespace` statement. Includes the
53
+ * standard XQuery 3.1 predeclared namespaces (math, map, array) and any
54
+ * runtime-specific additions (e.g. eXist-db's util, xmldb, …).
55
+ */
56
+ export function getRuntimePredeclaredNamespaces(runtimes) {
57
+ if (!runtimes.includes("existdb"))
58
+ return [];
59
+ return loadExistdbPredeclared();
60
+ }
61
+ /**
62
+ * Return a copy of `analysis` with the given predeclared namespace declarations
63
+ * merged into `namespaceDecls`. Prefixes already visible via imports, the
64
+ * module's own prefix, or an existing `declare namespace` are skipped.
65
+ */
66
+ export function withPredeclaredNs(analysis, predeclaredNs) {
67
+ if (predeclaredNs.length === 0)
68
+ return analysis;
69
+ const known = new Set([
70
+ ...analysis.imports.map((i) => i.prefix),
71
+ ...analysis.namespaceDecls.map((nd) => nd.prefix),
72
+ ...(analysis.modulePrefix ? [analysis.modulePrefix] : []),
73
+ ]);
74
+ const toAdd = predeclaredNs.filter((nd) => !known.has(nd.prefix));
75
+ if (toAdd.length === 0)
76
+ return analysis;
77
+ return { ...analysis, namespaceDecls: [...analysis.namespaceDecls, ...toAdd] };
78
+ }
42
79
  export function getRuntimeAnalyses(runtimes) {
43
80
  const results = [];
44
81
  for (const runtime of runtimes) {
package/dist/server.js CHANGED
@@ -14,11 +14,13 @@ import { checkFunctionCalls } from "./functioncall-diagnostics.js";
14
14
  import { findConfig, expandGlobs } from "./config.js";
15
15
  import { findUndeclaredPrefixUsages, findImportInsertPosition, findDeclareNsInsertPosition, } from "./namespace-diagnostics.js";
16
16
  import { checkUnused } from "./unused-diagnostics.js";
17
+ import { checkUndeclaredVariables } from "./variable-diagnostics.js";
17
18
  import { checkContextItemUsage } from "./context-item-diagnostics.js";
18
- import { getRuntimeAnalyses } from "./runtimes.js";
19
+ import { getRuntimeAnalyses, getRuntimePredeclaredNamespaces, withPredeclaredNs } from "./runtimes.js";
19
20
  const connection = createConnection(ProposedFeatures.all);
20
21
  const documents = new TextDocuments(TextDocument);
21
22
  const analysisCache = new Map();
23
+ const lastValidAnalysisCache = new Map(); // last AST-path analysis per URI
22
24
  const typeErrorCache = new Map();
23
25
  // Glob analyses keyed by config directory, then by module namespace URI.
24
26
  // Populated lazily on the first request for a given config root.
@@ -26,11 +28,15 @@ const globAnalysesByConfigDir = new Map();
26
28
  function analyzeDocument(doc) {
27
29
  const { analysis } = analyzeWithAst(doc.getText(), doc.uri);
28
30
  analysisCache.set(doc.uri, analysis);
31
+ if (analysis.usedAstPath)
32
+ lastValidAnalysisCache.set(doc.uri, analysis);
29
33
  return analysis;
30
34
  }
31
35
  function analyzeDocumentFull(doc) {
32
36
  const { analysis, ast, parseError } = analyzeWithAst(doc.getText(), doc.uri);
33
37
  analysisCache.set(doc.uri, analysis);
38
+ if (analysis.usedAstPath)
39
+ lastValidAnalysisCache.set(doc.uri, analysis);
34
40
  return { analysis, parseDiagnostics: buildParseDiagnostics(parseError), hasAst: ast !== null, ast };
35
41
  }
36
42
  function buildParseDiagnostics(parseError) {
@@ -77,6 +83,13 @@ function getImportedAnalysis(importUri) {
77
83
  return null;
78
84
  }
79
85
  }
86
+ function mergeAnalyses(a, b) {
87
+ return {
88
+ ...a,
89
+ functions: [...a.functions, ...b.functions],
90
+ moduleVariables: [...a.moduleVariables, ...b.moduleVariables],
91
+ };
92
+ }
80
93
  function getGlobAnalyses(currentUri) {
81
94
  const found = findConfig(currentUri);
82
95
  if (!found)
@@ -90,23 +103,28 @@ function getGlobAnalyses(currentUri) {
90
103
  for (const filePath of expandGlobs(config.globs, configDir)) {
91
104
  const fileUri = pathToFileURL(filePath).toString();
92
105
  const imported = getImportedAnalysis(fileUri);
93
- if (imported?.moduleNamespaceUri)
94
- byNamespace.set(imported.moduleNamespaceUri, imported);
106
+ if (!imported?.moduleNamespaceUri)
107
+ continue;
108
+ const existing = byNamespace.get(imported.moduleNamespaceUri);
109
+ byNamespace.set(imported.moduleNamespaceUri, existing ? mergeAnalyses(existing, imported) : imported);
95
110
  }
96
111
  globAnalysesByConfigDir.set(configDir, byNamespace);
97
112
  return { byNamespace, lib };
98
113
  }
99
- function resolveImports(currentUri, analysis) {
114
+ function resolveContext(currentUri, rawAnalysis) {
100
115
  const result = new Map();
101
116
  result.set("builtin:fn", getBuiltins());
102
117
  const { byNamespace: globAnalyses, lib } = getGlobAnalyses(currentUri);
118
+ const predeclaredNs = getRuntimePredeclaredNamespaces(lib);
119
+ const analysis = withPredeclaredNs(rawAnalysis, predeclaredNs);
103
120
  const runtimeByNamespace = new Map();
104
121
  for (const runtimeAnalysis of getRuntimeAnalyses(lib)) {
105
122
  if (runtimeAnalysis.moduleNamespaceUri) {
106
- runtimeByNamespace.set(runtimeAnalysis.moduleNamespaceUri, runtimeAnalysis);
123
+ const existing = runtimeByNamespace.get(runtimeAnalysis.moduleNamespaceUri);
124
+ runtimeByNamespace.set(runtimeAnalysis.moduleNamespaceUri, existing ? mergeAnalyses(existing, runtimeAnalysis) : runtimeAnalysis);
107
125
  }
108
126
  }
109
- for (const imp of analysis.imports) {
127
+ for (const imp of rawAnalysis.imports) {
110
128
  if (imp.atPath) {
111
129
  const uri = resolveImportUri(currentUri, imp.atPath);
112
130
  const imported = getImportedAnalysis(uri);
@@ -120,7 +138,15 @@ function resolveImports(currentUri, analysis) {
120
138
  result.set(imp.namespaceUri, imported);
121
139
  }
122
140
  }
123
- return result;
141
+ // Add pre-declared runtime analyses directly — available without explicit import
142
+ for (const nd of predeclaredNs) {
143
+ if (!result.has(nd.namespaceUri)) {
144
+ const runtimeAnalysis = runtimeByNamespace.get(nd.namespaceUri);
145
+ if (runtimeAnalysis)
146
+ result.set(nd.namespaceUri, runtimeAnalysis);
147
+ }
148
+ }
149
+ return { analysis, imported: result };
124
150
  }
125
151
  // ── LSP lifecycle ────────────────────────────────────────────────────────────
126
152
  let snippetSupport = false;
@@ -145,12 +171,12 @@ connection.onInitialize((params) => {
145
171
  });
146
172
  documents.onDidChangeContent((change) => {
147
173
  const doc = change.document;
148
- const { analysis, parseDiagnostics: parseDiags, hasAst, ast } = analyzeDocumentFull(doc);
174
+ const { analysis: rawAnalysis, parseDiagnostics: parseDiags, hasAst, ast } = analyzeDocumentFull(doc);
175
+ const { analysis, imported: resolvedImported } = resolveContext(doc.uri, rawAnalysis);
149
176
  if (hasAst && ast !== null) {
150
- const imported = resolveImports(doc.uri, analysis);
151
177
  typeErrorCache.set(doc.uri, [
152
- ...checkTypes(ast, doc.getText(), analysis, imported),
153
- ...checkFunctionCalls(ast, analysis, imported),
178
+ ...checkTypes(ast, doc.getText(), analysis, resolvedImported),
179
+ ...checkFunctionCalls(ast, analysis, resolvedImported),
154
180
  ]);
155
181
  }
156
182
  const typeDiags = (typeErrorCache.get(doc.uri) ?? []).map((td) => ({
@@ -199,34 +225,48 @@ documents.onDidChangeContent((change) => {
199
225
  code: cd.code,
200
226
  source: "xquery-lsp",
201
227
  }));
228
+ const undeclaredVarDiagRaw = hasAst && ast !== null ? checkUndeclaredVariables(ast, analysis, resolvedImported) : [];
229
+ const undeclaredVarDiags = undeclaredVarDiagRaw.map((d) => ({
230
+ severity: DiagnosticSeverity.Error,
231
+ range: {
232
+ start: doc.positionAt(d.offset),
233
+ end: doc.positionAt(d.offset + d.length),
234
+ },
235
+ message: d.message,
236
+ code: d.code,
237
+ source: "xquery-lsp",
238
+ }));
202
239
  connection.sendDiagnostics({
203
240
  uri: doc.uri,
204
- diagnostics: [...parseDiags, ...typeDiags, ...nsDiags, ...unusedDiags, ...contextItemDiags],
241
+ diagnostics: [
242
+ ...parseDiags, ...typeDiags, ...nsDiags, ...unusedDiags, ...contextItemDiags,
243
+ ...undeclaredVarDiags,
244
+ ],
205
245
  });
206
246
  });
207
247
  connection.onCompletion((params) => {
208
248
  const doc = documents.get(params.textDocument.uri);
209
249
  if (!doc)
210
250
  return [];
211
- const analysis = analysisCache.get(doc.uri) ?? analyzeDocument(doc);
212
- const imported = resolveImports(doc.uri, analysis);
251
+ const rawAnalysis = analysisCache.get(doc.uri) ?? analyzeDocument(doc);
252
+ const { analysis, imported } = resolveContext(doc.uri, rawAnalysis);
213
253
  const offset = doc.offsetAt(params.position);
214
- return getCompletions({ textBeforeCursor: doc.getText().slice(0, offset), cursorOffset: offset }, analysis, imported, snippetSupport);
254
+ return getCompletions({ textBeforeCursor: doc.getText().slice(0, offset), cursorOffset: offset }, analysis, imported, snippetSupport, lastValidAnalysisCache.get(doc.uri));
215
255
  });
216
256
  connection.onHover((params) => {
217
257
  const doc = documents.get(params.textDocument.uri);
218
258
  if (!doc)
219
259
  return null;
220
- const analysis = analysisCache.get(doc.uri) ?? analyzeDocument(doc);
221
- const imported = resolveImports(doc.uri, analysis);
260
+ const rawAnalysis = analysisCache.get(doc.uri) ?? analyzeDocument(doc);
261
+ const { analysis, imported } = resolveContext(doc.uri, rawAnalysis);
222
262
  return getHover(doc, doc.offsetAt(params.position), analysis, imported);
223
263
  });
224
264
  connection.onSignatureHelp((params) => {
225
265
  const doc = documents.get(params.textDocument.uri);
226
266
  if (!doc)
227
267
  return null;
228
- const analysis = analysisCache.get(doc.uri) ?? analyzeDocument(doc);
229
- const imported = resolveImports(doc.uri, analysis);
268
+ const rawAnalysis = analysisCache.get(doc.uri) ?? analyzeDocument(doc);
269
+ const { analysis, imported } = resolveContext(doc.uri, rawAnalysis);
230
270
  return getSignatureHelp(doc, doc.offsetAt(params.position), analysis, imported);
231
271
  });
232
272
  connection.onDocumentSymbol((params) => {
@@ -240,8 +280,8 @@ connection.onDefinition((params) => {
240
280
  const doc = documents.get(params.textDocument.uri);
241
281
  if (!doc)
242
282
  return null;
243
- const analysis = analysisCache.get(doc.uri) ?? analyzeDocument(doc);
244
- const imported = resolveImports(doc.uri, analysis);
283
+ const rawAnalysis = analysisCache.get(doc.uri) ?? analyzeDocument(doc);
284
+ const { analysis, imported } = resolveContext(doc.uri, rawAnalysis);
245
285
  return getDefinition(doc, doc.offsetAt(params.position), analysis, imported, (atPath) => resolveImportUri(doc.uri, atPath));
246
286
  });
247
287
  connection.onCodeAction((params) => {
@@ -0,0 +1,19 @@
1
+ import type { Node } from "xq-parser";
2
+ import type { FileAnalysis } from "./types.ts";
3
+ export interface UndeclaredVariableDiagnostic {
4
+ message: string;
5
+ code: "XPST0008";
6
+ offset: number;
7
+ length: number;
8
+ }
9
+ /**
10
+ * Walk the AST and report every variable reference that cannot be resolved
11
+ * to a declared variable: function parameter, let/for binding, module-level
12
+ * `declare variable`, or an imported module variable.
13
+ *
14
+ * Variables whose namespace prefix is undeclared are skipped — XQST0081
15
+ * already fires for those, and adding XPST0008 on top would be noisy.
16
+ * Variables inside catch clauses are also skipped since the implicit
17
+ * `$err:*` bindings are not represented in the AST.
18
+ */
19
+ export declare function checkUndeclaredVariables(ast: Node, analysis: FileAnalysis, importedAnalyses: Map<string, FileAnalysis>): UndeclaredVariableDiagnostic[];
@@ -0,0 +1,164 @@
1
+ import { qnameKey } from "./types.js";
2
+ import { isTerminal, directChildOf, directChildrenOf } from "./analyzer.js";
3
+ import { asFunctionDecl, asVarRef, asVarName, asBinding } from "./ast-nodes.js";
4
+ // ── Scope stack ───────────────────────────────────────────────────────────────
5
+ class ScopeStack {
6
+ frames = [];
7
+ push() { this.frames.push(new Set()); }
8
+ pop() { this.frames.pop(); }
9
+ add(key) { this.frames[this.frames.length - 1]?.add(key); }
10
+ has(key) { return this.frames.some((f) => f.has(key)); }
11
+ }
12
+ // ── Helpers ───────────────────────────────────────────────────────────────────
13
+ function isKnown(qname, scope, moduleVarKeys) {
14
+ // Variables with an undeclared-prefix URI are already caught by XQST0081; skip here.
15
+ if (qname.namespaceUri.startsWith("urn:xq-lsp:undeclared:"))
16
+ return true;
17
+ return scope.has(qnameKey(qname)) || moduleVarKeys.has(qnameKey(qname));
18
+ }
19
+ function reportVarRef(node, qname, out) {
20
+ const name = qname.prefix ? `${qname.prefix}:${qname.localName}` : qname.localName;
21
+ out.push({
22
+ message: `Variable '$${name}' is not declared`,
23
+ code: "XPST0008",
24
+ offset: node.start ?? 0,
25
+ length: name.length + 1, // +1 for "$"
26
+ });
27
+ }
28
+ function addBinding(bindingNode, scope, analysis, moduleVarKeys, out) {
29
+ const b = asBinding(bindingNode, analysis);
30
+ if (!b)
31
+ return;
32
+ if (b.initExpr)
33
+ walk(b.initExpr, scope, analysis, moduleVarKeys, out);
34
+ scope.add(qnameKey(b.qname));
35
+ if (b.positionalVar)
36
+ scope.add(qnameKey(b.positionalVar.qname));
37
+ }
38
+ // ── Scope-aware AST walker ────────────────────────────────────────────────────
39
+ function walk(node, scope, analysis, moduleVarKeys, out) {
40
+ if (isTerminal(node))
41
+ return;
42
+ const { children } = node;
43
+ switch (node.type) {
44
+ case "AnnotatedDecl": {
45
+ const fnDeclNode = directChildOf(node, "FunctionDecl");
46
+ const fn = fnDeclNode ? asFunctionDecl(fnDeclNode, analysis) : null;
47
+ if (fn) {
48
+ scope.push();
49
+ for (const p of fn.params)
50
+ scope.add(qnameKey(p.qname));
51
+ if (fn.body)
52
+ walk(fn.body, scope, analysis, moduleVarKeys, out);
53
+ scope.pop();
54
+ return;
55
+ }
56
+ // Module variable declaration: walk the initializer expression only
57
+ const varDecl = directChildOf(node, "VarDecl");
58
+ if (varDecl && !isTerminal(varDecl)) {
59
+ for (const child of varDecl.children)
60
+ walk(child, scope, analysis, moduleVarKeys, out);
61
+ }
62
+ return;
63
+ }
64
+ case "FLWORExpr": {
65
+ scope.push();
66
+ for (const child of children) {
67
+ if (isTerminal(child))
68
+ continue;
69
+ // Unwrap InitialClause/IntermediateClause wrappers (may be multiply nested)
70
+ let clause = child;
71
+ while (!isTerminal(clause) && (clause.type === "InitialClause" || clause.type === "IntermediateClause")) {
72
+ const inner = clause.children.find((c) => !isTerminal(c));
73
+ if (!inner)
74
+ break;
75
+ clause = inner;
76
+ }
77
+ switch (clause.type) {
78
+ case "ForClause":
79
+ for (const b of directChildrenOf(clause, "ForBinding"))
80
+ addBinding(b, scope, analysis, moduleVarKeys, out);
81
+ break;
82
+ case "LetClause":
83
+ for (const b of directChildrenOf(clause, "LetBinding"))
84
+ addBinding(b, scope, analysis, moduleVarKeys, out);
85
+ break;
86
+ case "CountClause":
87
+ addBinding(clause, scope, analysis, moduleVarKeys, out);
88
+ break;
89
+ case "GroupByClause": {
90
+ const specList = directChildOf(clause, "GroupingSpecList");
91
+ for (const spec of specList ? directChildrenOf(specList, "GroupingSpec") : [])
92
+ addBinding(spec, scope, analysis, moduleVarKeys, out);
93
+ break;
94
+ }
95
+ case "WindowClause": {
96
+ const inner = directChildOf(clause, "TumblingWindowClause") ??
97
+ directChildOf(clause, "SlidingWindowClause");
98
+ if (inner)
99
+ addBinding(inner, scope, analysis, moduleVarKeys, out);
100
+ for (const c of clause.children)
101
+ if (!isTerminal(c))
102
+ walk(c, scope, analysis, moduleVarKeys, out);
103
+ break;
104
+ }
105
+ default:
106
+ walk(clause, scope, analysis, moduleVarKeys, out);
107
+ }
108
+ }
109
+ scope.pop();
110
+ return;
111
+ }
112
+ case "QuantifiedExpr": {
113
+ scope.push();
114
+ for (const child of children) {
115
+ if (isTerminal(child))
116
+ continue;
117
+ if (child.type === "VarName") {
118
+ const qname = asVarName(child, analysis);
119
+ if (qname)
120
+ scope.add(qnameKey(qname));
121
+ }
122
+ else {
123
+ walk(child, scope, analysis, moduleVarKeys, out);
124
+ }
125
+ }
126
+ scope.pop();
127
+ return;
128
+ }
129
+ case "CatchClause":
130
+ // Skip: implicit $err:* variables inside catch clauses are not tracked in the AST.
131
+ return;
132
+ case "VarRef": {
133
+ const qname = asVarRef(node, analysis);
134
+ if (qname && !isKnown(qname, scope, moduleVarKeys))
135
+ reportVarRef(node, qname, out);
136
+ return;
137
+ }
138
+ default:
139
+ for (const child of children)
140
+ walk(child, scope, analysis, moduleVarKeys, out);
141
+ }
142
+ }
143
+ // ── Public entry point ────────────────────────────────────────────────────────
144
+ /**
145
+ * Walk the AST and report every variable reference that cannot be resolved
146
+ * to a declared variable: function parameter, let/for binding, module-level
147
+ * `declare variable`, or an imported module variable.
148
+ *
149
+ * Variables whose namespace prefix is undeclared are skipped — XQST0081
150
+ * already fires for those, and adding XPST0008 on top would be noisy.
151
+ * Variables inside catch clauses are also skipped since the implicit
152
+ * `$err:*` bindings are not represented in the AST.
153
+ */
154
+ export function checkUndeclaredVariables(ast, analysis, importedAnalyses) {
155
+ const moduleVarKeys = new Set();
156
+ for (const v of analysis.moduleVariables)
157
+ moduleVarKeys.add(qnameKey(v.qname));
158
+ for (const imported of importedAnalyses.values())
159
+ for (const v of imported.moduleVariables)
160
+ moduleVarKeys.add(qnameKey(v.qname));
161
+ const out = [];
162
+ walk(ast, new ScopeStack(), analysis, moduleVarKeys, out);
163
+ return out;
164
+ }