@reqlan/language 1.4.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 (371) hide show
  1. package/README.md +24 -0
  2. package/out/file-path-rewrite.d.ts +25 -0
  3. package/out/file-path-rewrite.js +56 -0
  4. package/out/file-path-rewrite.js.map +1 -0
  5. package/out/generated/ast.d.ts +1157 -0
  6. package/out/generated/ast.js +980 -0
  7. package/out/generated/ast.js.map +1 -0
  8. package/out/generated/grammar.d.ts +7 -0
  9. package/out/generated/grammar.js +3071 -0
  10. package/out/generated/grammar.js.map +1 -0
  11. package/out/generated/module.d.ts +20 -0
  12. package/out/generated/module.js +32 -0
  13. package/out/generated/module.js.map +1 -0
  14. package/out/index.d.ts +34 -0
  15. package/out/index.js +35 -0
  16. package/out/index.js.map +1 -0
  17. package/out/reqlan-attribute-catalog.d.ts +19 -0
  18. package/out/reqlan-attribute-catalog.js +87 -0
  19. package/out/reqlan-attribute-catalog.js.map +1 -0
  20. package/out/reqlan-code-action-provider.d.ts +55 -0
  21. package/out/reqlan-code-action-provider.js +269 -0
  22. package/out/reqlan-code-action-provider.js.map +1 -0
  23. package/out/reqlan-code-lens-provider.d.ts +13 -0
  24. package/out/reqlan-code-lens-provider.js +27 -0
  25. package/out/reqlan-code-lens-provider.js.map +1 -0
  26. package/out/reqlan-code-lens-settings.d.ts +34 -0
  27. package/out/reqlan-code-lens-settings.js +12 -0
  28. package/out/reqlan-code-lens-settings.js.map +1 -0
  29. package/out/reqlan-comment-resolver.d.ts +35 -0
  30. package/out/reqlan-comment-resolver.js +308 -0
  31. package/out/reqlan-comment-resolver.js.map +1 -0
  32. package/out/reqlan-completion-context.d.ts +46 -0
  33. package/out/reqlan-completion-context.js +244 -0
  34. package/out/reqlan-completion-context.js.map +1 -0
  35. package/out/reqlan-completion-provider.d.ts +41 -0
  36. package/out/reqlan-completion-provider.js +317 -0
  37. package/out/reqlan-completion-provider.js.map +1 -0
  38. package/out/reqlan-definition-provider.d.ts +31 -0
  39. package/out/reqlan-definition-provider.js +240 -0
  40. package/out/reqlan-definition-provider.js.map +1 -0
  41. package/out/reqlan-document-highlight-provider.d.ts +10 -0
  42. package/out/reqlan-document-highlight-provider.js +11 -0
  43. package/out/reqlan-document-highlight-provider.js.map +1 -0
  44. package/out/reqlan-document-link-provider.d.ts +14 -0
  45. package/out/reqlan-document-link-provider.js +24 -0
  46. package/out/reqlan-document-link-provider.js.map +1 -0
  47. package/out/reqlan-embedded-file-references.d.ts +11 -0
  48. package/out/reqlan-embedded-file-references.js +50 -0
  49. package/out/reqlan-embedded-file-references.js.map +1 -0
  50. package/out/reqlan-file-link-resolver.d.ts +44 -0
  51. package/out/reqlan-file-link-resolver.js +347 -0
  52. package/out/reqlan-file-link-resolver.js.map +1 -0
  53. package/out/reqlan-file-references.d.ts +15 -0
  54. package/out/reqlan-file-references.js +72 -0
  55. package/out/reqlan-file-references.js.map +1 -0
  56. package/out/reqlan-grammar-config.d.ts +5 -0
  57. package/out/reqlan-grammar-config.js +9 -0
  58. package/out/reqlan-grammar-config.js.map +1 -0
  59. package/out/reqlan-idea-reference-site.d.ts +14 -0
  60. package/out/reqlan-idea-reference-site.js +47 -0
  61. package/out/reqlan-idea-reference-site.js.map +1 -0
  62. package/out/reqlan-idea-summary.d.ts +6 -0
  63. package/out/reqlan-idea-summary.js +134 -0
  64. package/out/reqlan-idea-summary.js.map +1 -0
  65. package/out/reqlan-ignore-error.d.ts +10 -0
  66. package/out/reqlan-ignore-error.js +42 -0
  67. package/out/reqlan-ignore-error.js.map +1 -0
  68. package/out/reqlan-import-bindings.d.ts +12 -0
  69. package/out/reqlan-import-bindings.js +65 -0
  70. package/out/reqlan-import-bindings.js.map +1 -0
  71. package/out/reqlan-import-edits.d.ts +17 -0
  72. package/out/reqlan-import-edits.js +96 -0
  73. package/out/reqlan-import-edits.js.map +1 -0
  74. package/out/reqlan-imports.d.ts +22 -0
  75. package/out/reqlan-imports.js +61 -0
  76. package/out/reqlan-imports.js.map +1 -0
  77. package/out/reqlan-inbound-reference-inlay-label.d.ts +27 -0
  78. package/out/reqlan-inbound-reference-inlay-label.js +142 -0
  79. package/out/reqlan-inbound-reference-inlay-label.js.map +1 -0
  80. package/out/reqlan-inlay-hint-provider.d.ts +15 -0
  81. package/out/reqlan-inlay-hint-provider.js +54 -0
  82. package/out/reqlan-inlay-hint-provider.js.map +1 -0
  83. package/out/reqlan-inlay-hint-settings.d.ts +10 -0
  84. package/out/reqlan-inlay-hint-settings.js +10 -0
  85. package/out/reqlan-inlay-hint-settings.js.map +1 -0
  86. package/out/reqlan-linker.d.ts +26 -0
  87. package/out/reqlan-linker.js +83 -0
  88. package/out/reqlan-linker.js.map +1 -0
  89. package/out/reqlan-markdown-links.d.ts +28 -0
  90. package/out/reqlan-markdown-links.js +113 -0
  91. package/out/reqlan-markdown-links.js.map +1 -0
  92. package/out/reqlan-module.d.ts +41 -0
  93. package/out/reqlan-module.js +78 -0
  94. package/out/reqlan-module.js.map +1 -0
  95. package/out/reqlan-name-catalog.d.ts +23 -0
  96. package/out/reqlan-name-catalog.js +63 -0
  97. package/out/reqlan-name-catalog.js.map +1 -0
  98. package/out/reqlan-name-provider.d.ts +10 -0
  99. package/out/reqlan-name-provider.js +38 -0
  100. package/out/reqlan-name-provider.js.map +1 -0
  101. package/out/reqlan-namespace-import-links.d.ts +10 -0
  102. package/out/reqlan-namespace-import-links.js +69 -0
  103. package/out/reqlan-namespace-import-links.js.map +1 -0
  104. package/out/reqlan-path-completion.d.ts +50 -0
  105. package/out/reqlan-path-completion.js +304 -0
  106. package/out/reqlan-path-completion.js.map +1 -0
  107. package/out/reqlan-path-references.d.ts +5 -0
  108. package/out/reqlan-path-references.js +124 -0
  109. package/out/reqlan-path-references.js.map +1 -0
  110. package/out/reqlan-path-resolve.d.ts +81 -0
  111. package/out/reqlan-path-resolve.js +245 -0
  112. package/out/reqlan-path-resolve.js.map +1 -0
  113. package/out/reqlan-quoted-strings.d.ts +9 -0
  114. package/out/reqlan-quoted-strings.js +26 -0
  115. package/out/reqlan-quoted-strings.js.map +1 -0
  116. package/out/reqlan-reference-at-position.d.ts +20 -0
  117. package/out/reqlan-reference-at-position.js +89 -0
  118. package/out/reqlan-reference-at-position.js.map +1 -0
  119. package/out/reqlan-reference-code-lens.d.ts +32 -0
  120. package/out/reqlan-reference-code-lens.js +240 -0
  121. package/out/reqlan-reference-code-lens.js.map +1 -0
  122. package/out/reqlan-reference-search-site.d.ts +34 -0
  123. package/out/reqlan-reference-search-site.js +136 -0
  124. package/out/reqlan-reference-search-site.js.map +1 -0
  125. package/out/reqlan-references.d.ts +16 -0
  126. package/out/reqlan-references.js +51 -0
  127. package/out/reqlan-references.js.map +1 -0
  128. package/out/reqlan-scope.d.ts +25 -0
  129. package/out/reqlan-scope.js +259 -0
  130. package/out/reqlan-scope.js.map +1 -0
  131. package/out/reqlan-semantic-token-provider.d.ts +8 -0
  132. package/out/reqlan-semantic-token-provider.js +91 -0
  133. package/out/reqlan-semantic-token-provider.js.map +1 -0
  134. package/out/reqlan-token-builder.d.ts +12 -0
  135. package/out/reqlan-token-builder.js +459 -0
  136. package/out/reqlan-token-builder.js.map +1 -0
  137. package/out/reqlan-validator.d.ts +25 -0
  138. package/out/reqlan-validator.js +119 -0
  139. package/out/reqlan-validator.js.map +1 -0
  140. package/out/reqlan-workspace-attribute-catalog.d.ts +6 -0
  141. package/out/reqlan-workspace-attribute-catalog.js +54 -0
  142. package/out/reqlan-workspace-attribute-catalog.js.map +1 -0
  143. package/out/src/file-path-rewrite.d.ts +25 -0
  144. package/out/src/file-path-rewrite.js +56 -0
  145. package/out/src/file-path-rewrite.js.map +1 -0
  146. package/out/src/generated/ast.d.ts +1173 -0
  147. package/out/src/generated/ast.js +994 -0
  148. package/out/src/generated/ast.js.map +1 -0
  149. package/out/src/generated/grammar.d.ts +7 -0
  150. package/out/src/generated/grammar.js +3045 -0
  151. package/out/src/generated/grammar.js.map +1 -0
  152. package/out/src/generated/module.d.ts +20 -0
  153. package/out/src/generated/module.js +32 -0
  154. package/out/src/generated/module.js.map +1 -0
  155. package/out/src/index.d.ts +29 -0
  156. package/out/src/index.js +30 -0
  157. package/out/src/index.js.map +1 -0
  158. package/out/src/reqlan-attribute-catalog.d.ts +19 -0
  159. package/out/src/reqlan-attribute-catalog.js +87 -0
  160. package/out/src/reqlan-attribute-catalog.js.map +1 -0
  161. package/out/src/reqlan-code-action-provider.d.ts +34 -0
  162. package/out/src/reqlan-code-action-provider.js +206 -0
  163. package/out/src/reqlan-code-action-provider.js.map +1 -0
  164. package/out/src/reqlan-comment-resolver.d.ts +35 -0
  165. package/out/src/reqlan-comment-resolver.js +308 -0
  166. package/out/src/reqlan-comment-resolver.js.map +1 -0
  167. package/out/src/reqlan-completion-context.d.ts +46 -0
  168. package/out/src/reqlan-completion-context.js +244 -0
  169. package/out/src/reqlan-completion-context.js.map +1 -0
  170. package/out/src/reqlan-completion-provider.d.ts +41 -0
  171. package/out/src/reqlan-completion-provider.js +320 -0
  172. package/out/src/reqlan-completion-provider.js.map +1 -0
  173. package/out/src/reqlan-definition-provider.d.ts +31 -0
  174. package/out/src/reqlan-definition-provider.js +240 -0
  175. package/out/src/reqlan-definition-provider.js.map +1 -0
  176. package/out/src/reqlan-document-highlight-provider.d.ts +10 -0
  177. package/out/src/reqlan-document-highlight-provider.js +11 -0
  178. package/out/src/reqlan-document-highlight-provider.js.map +1 -0
  179. package/out/src/reqlan-document-link-provider.d.ts +14 -0
  180. package/out/src/reqlan-document-link-provider.js +24 -0
  181. package/out/src/reqlan-document-link-provider.js.map +1 -0
  182. package/out/src/reqlan-embedded-file-references.d.ts +11 -0
  183. package/out/src/reqlan-embedded-file-references.js +50 -0
  184. package/out/src/reqlan-embedded-file-references.js.map +1 -0
  185. package/out/src/reqlan-file-link-resolver.d.ts +44 -0
  186. package/out/src/reqlan-file-link-resolver.js +347 -0
  187. package/out/src/reqlan-file-link-resolver.js.map +1 -0
  188. package/out/src/reqlan-file-references.d.ts +15 -0
  189. package/out/src/reqlan-file-references.js +72 -0
  190. package/out/src/reqlan-file-references.js.map +1 -0
  191. package/out/src/reqlan-grammar-config.d.ts +5 -0
  192. package/out/src/reqlan-grammar-config.js +9 -0
  193. package/out/src/reqlan-grammar-config.js.map +1 -0
  194. package/out/src/reqlan-idea-summary.d.ts +6 -0
  195. package/out/src/reqlan-idea-summary.js +78 -0
  196. package/out/src/reqlan-idea-summary.js.map +1 -0
  197. package/out/src/reqlan-ignore-error.d.ts +10 -0
  198. package/out/src/reqlan-ignore-error.js +42 -0
  199. package/out/src/reqlan-ignore-error.js.map +1 -0
  200. package/out/src/reqlan-import-bindings.d.ts +12 -0
  201. package/out/src/reqlan-import-bindings.js +65 -0
  202. package/out/src/reqlan-import-bindings.js.map +1 -0
  203. package/out/src/reqlan-import-edits.d.ts +17 -0
  204. package/out/src/reqlan-import-edits.js +96 -0
  205. package/out/src/reqlan-import-edits.js.map +1 -0
  206. package/out/src/reqlan-imports.d.ts +22 -0
  207. package/out/src/reqlan-imports.js +61 -0
  208. package/out/src/reqlan-imports.js.map +1 -0
  209. package/out/src/reqlan-inbound-reference-inlay-label.d.ts +23 -0
  210. package/out/src/reqlan-inbound-reference-inlay-label.js +128 -0
  211. package/out/src/reqlan-inbound-reference-inlay-label.js.map +1 -0
  212. package/out/src/reqlan-inlay-hint-provider.d.ts +15 -0
  213. package/out/src/reqlan-inlay-hint-provider.js +54 -0
  214. package/out/src/reqlan-inlay-hint-provider.js.map +1 -0
  215. package/out/src/reqlan-inlay-hint-settings.d.ts +10 -0
  216. package/out/src/reqlan-inlay-hint-settings.js +10 -0
  217. package/out/src/reqlan-inlay-hint-settings.js.map +1 -0
  218. package/out/src/reqlan-linker.d.ts +26 -0
  219. package/out/src/reqlan-linker.js +86 -0
  220. package/out/src/reqlan-linker.js.map +1 -0
  221. package/out/src/reqlan-markdown-links.d.ts +28 -0
  222. package/out/src/reqlan-markdown-links.js +113 -0
  223. package/out/src/reqlan-markdown-links.js.map +1 -0
  224. package/out/src/reqlan-module.d.ts +41 -0
  225. package/out/src/reqlan-module.js +76 -0
  226. package/out/src/reqlan-module.js.map +1 -0
  227. package/out/src/reqlan-name-catalog.d.ts +23 -0
  228. package/out/src/reqlan-name-catalog.js +63 -0
  229. package/out/src/reqlan-name-catalog.js.map +1 -0
  230. package/out/src/reqlan-name-provider.d.ts +10 -0
  231. package/out/src/reqlan-name-provider.js +38 -0
  232. package/out/src/reqlan-name-provider.js.map +1 -0
  233. package/out/src/reqlan-namespace-import-links.d.ts +10 -0
  234. package/out/src/reqlan-namespace-import-links.js +81 -0
  235. package/out/src/reqlan-namespace-import-links.js.map +1 -0
  236. package/out/src/reqlan-path-completion.d.ts +50 -0
  237. package/out/src/reqlan-path-completion.js +304 -0
  238. package/out/src/reqlan-path-completion.js.map +1 -0
  239. package/out/src/reqlan-path-references.d.ts +5 -0
  240. package/out/src/reqlan-path-references.js +124 -0
  241. package/out/src/reqlan-path-references.js.map +1 -0
  242. package/out/src/reqlan-path-resolve.d.ts +59 -0
  243. package/out/src/reqlan-path-resolve.js +173 -0
  244. package/out/src/reqlan-path-resolve.js.map +1 -0
  245. package/out/src/reqlan-quoted-strings.d.ts +9 -0
  246. package/out/src/reqlan-quoted-strings.js +26 -0
  247. package/out/src/reqlan-quoted-strings.js.map +1 -0
  248. package/out/src/reqlan-reference-at-position.d.ts +20 -0
  249. package/out/src/reqlan-reference-at-position.js +89 -0
  250. package/out/src/reqlan-reference-at-position.js.map +1 -0
  251. package/out/src/reqlan-references.d.ts +16 -0
  252. package/out/src/reqlan-references.js +51 -0
  253. package/out/src/reqlan-references.js.map +1 -0
  254. package/out/src/reqlan-scope.d.ts +25 -0
  255. package/out/src/reqlan-scope.js +266 -0
  256. package/out/src/reqlan-scope.js.map +1 -0
  257. package/out/src/reqlan-semantic-token-provider.d.ts +8 -0
  258. package/out/src/reqlan-semantic-token-provider.js +97 -0
  259. package/out/src/reqlan-semantic-token-provider.js.map +1 -0
  260. package/out/src/reqlan-token-builder.d.ts +12 -0
  261. package/out/src/reqlan-token-builder.js +459 -0
  262. package/out/src/reqlan-token-builder.js.map +1 -0
  263. package/out/src/reqlan-validator.d.ts +25 -0
  264. package/out/src/reqlan-validator.js +119 -0
  265. package/out/src/reqlan-validator.js.map +1 -0
  266. package/out/src/reqlan-workspace-attribute-catalog.d.ts +6 -0
  267. package/out/src/reqlan-workspace-attribute-catalog.js +54 -0
  268. package/out/src/reqlan-workspace-attribute-catalog.js.map +1 -0
  269. package/out/test/code-actions.test.d.ts +1 -0
  270. package/out/test/code-actions.test.js +126 -0
  271. package/out/test/code-actions.test.js.map +1 -0
  272. package/out/test/comment-in-string.test.d.ts +1 -0
  273. package/out/test/comment-in-string.test.js +100 -0
  274. package/out/test/comment-in-string.test.js.map +1 -0
  275. package/out/test/completion.test.d.ts +1 -0
  276. package/out/test/completion.test.js +467 -0
  277. package/out/test/completion.test.js.map +1 -0
  278. package/out/test/file-path-rewrite.test.d.ts +1 -0
  279. package/out/test/file-path-rewrite.test.js +64 -0
  280. package/out/test/file-path-rewrite.test.js.map +1 -0
  281. package/out/test/ignore-error.test.d.ts +1 -0
  282. package/out/test/ignore-error.test.js +87 -0
  283. package/out/test/ignore-error.test.js.map +1 -0
  284. package/out/test/implicit-import-extension.test.d.ts +1 -0
  285. package/out/test/implicit-import-extension.test.js +203 -0
  286. package/out/test/implicit-import-extension.test.js.map +1 -0
  287. package/out/test/import-edits.test.d.ts +1 -0
  288. package/out/test/import-edits.test.js +20 -0
  289. package/out/test/import-edits.test.js.map +1 -0
  290. package/out/test/inlay-hints.test.d.ts +1 -0
  291. package/out/test/inlay-hints.test.js +238 -0
  292. package/out/test/inlay-hints.test.js.map +1 -0
  293. package/out/test/linking.test.d.ts +1 -0
  294. package/out/test/linking.test.js +754 -0
  295. package/out/test/linking.test.js.map +1 -0
  296. package/out/test/naked-strings.test.d.ts +1 -0
  297. package/out/test/naked-strings.test.js +50 -0
  298. package/out/test/naked-strings.test.js.map +1 -0
  299. package/out/test/parsing.test.d.ts +1 -0
  300. package/out/test/parsing.test.js +773 -0
  301. package/out/test/parsing.test.js.map +1 -0
  302. package/out/test/path-resolve.test.d.ts +1 -0
  303. package/out/test/path-resolve.test.js +88 -0
  304. package/out/test/path-resolve.test.js.map +1 -0
  305. package/out/test/references.test.d.ts +1 -0
  306. package/out/test/references.test.js +168 -0
  307. package/out/test/references.test.js.map +1 -0
  308. package/out/test/rqconfig.test.d.ts +1 -0
  309. package/out/test/rqconfig.test.js +275 -0
  310. package/out/test/rqconfig.test.js.map +1 -0
  311. package/out/test/test-requirement-refs.d.ts +8 -0
  312. package/out/test/test-requirement-refs.js +35 -0
  313. package/out/test/test-requirement-refs.js.map +1 -0
  314. package/out/test/testing.test.d.ts +1 -0
  315. package/out/test/testing.test.js +23 -0
  316. package/out/test/testing.test.js.map +1 -0
  317. package/out/test/validating.test.d.ts +1 -0
  318. package/out/test/validating.test.js +117 -0
  319. package/out/test/validating.test.js.map +1 -0
  320. package/out/tsconfig.tsbuildinfo +1 -0
  321. package/package.json +54 -0
  322. package/src/chevrotain.d.ts +8 -0
  323. package/src/file-path-rewrite.ts +96 -0
  324. package/src/generated/ast.ts +1481 -0
  325. package/src/generated/grammar.ts +3074 -0
  326. package/src/generated/module.ts +38 -0
  327. package/src/index.ts +34 -0
  328. package/src/reqlan-attribute-catalog.ts +100 -0
  329. package/src/reqlan-code-action-provider.ts +385 -0
  330. package/src/reqlan-code-lens-provider.ts +54 -0
  331. package/src/reqlan-code-lens-settings.ts +42 -0
  332. package/src/reqlan-comment-resolver.ts +372 -0
  333. package/src/reqlan-comment.langium +23 -0
  334. package/src/reqlan-completion-context.ts +330 -0
  335. package/src/reqlan-completion-provider.ts +400 -0
  336. package/src/reqlan-definition-provider.ts +319 -0
  337. package/src/reqlan-document-highlight-provider.ts +21 -0
  338. package/src/reqlan-document-link-provider.ts +45 -0
  339. package/src/reqlan-embedded-file-references.ts +72 -0
  340. package/src/reqlan-file-link-resolver.ts +485 -0
  341. package/src/reqlan-file-references.ts +84 -0
  342. package/src/reqlan-grammar-config.ts +14 -0
  343. package/src/reqlan-idea-reference-site.ts +74 -0
  344. package/src/reqlan-idea-summary.ts +162 -0
  345. package/src/reqlan-ignore-error.ts +50 -0
  346. package/src/reqlan-import-bindings.ts +87 -0
  347. package/src/reqlan-import-edits.ts +124 -0
  348. package/src/reqlan-imports.ts +115 -0
  349. package/src/reqlan-inbound-reference-inlay-label.ts +194 -0
  350. package/src/reqlan-inlay-hint-provider.ts +88 -0
  351. package/src/reqlan-inlay-hint-settings.ts +15 -0
  352. package/src/reqlan-linker.ts +108 -0
  353. package/src/reqlan-markdown-links.ts +136 -0
  354. package/src/reqlan-module.ts +104 -0
  355. package/src/reqlan-name-catalog.ts +81 -0
  356. package/src/reqlan-name-provider.ts +56 -0
  357. package/src/reqlan-namespace-import-links.ts +92 -0
  358. package/src/reqlan-path-completion.ts +420 -0
  359. package/src/reqlan-path-references.ts +140 -0
  360. package/src/reqlan-path-resolve.ts +346 -0
  361. package/src/reqlan-quoted-strings.ts +30 -0
  362. package/src/reqlan-reference-at-position.ts +154 -0
  363. package/src/reqlan-reference-code-lens.ts +323 -0
  364. package/src/reqlan-reference-search-site.ts +202 -0
  365. package/src/reqlan-references.ts +76 -0
  366. package/src/reqlan-scope.ts +312 -0
  367. package/src/reqlan-semantic-token-provider.ts +113 -0
  368. package/src/reqlan-token-builder.ts +492 -0
  369. package/src/reqlan-validator.ts +149 -0
  370. package/src/reqlan-workspace-attribute-catalog.ts +62 -0
  371. package/src/reqlan.langium +236 -0
@@ -0,0 +1,140 @@
1
+ /**
2
+ * Collects relative file path strings in .rq imports and embedded references, and rq: paths in comments.
3
+ */
4
+ import type { Range } from 'vscode-languageserver';
5
+ import { findCommentReferencesInText } from './reqlan-comment-resolver.js';
6
+ import { findEmbeddedFileReferencesInText } from './reqlan-embedded-file-references.js';
7
+ import { parseFileReferenceString } from './reqlan-file-references.js';
8
+ import type { PathReference } from './file-path-rewrite.js';
9
+ import { parseReqlanQuotedString, REQLAN_QUOTED_STRING_CAPTURE } from './reqlan-quoted-strings.js';
10
+
11
+ const IMPORT_PATH_PATTERN = new RegExp(`(?:\\bfrom|\\bimport)\\s+(${REQLAN_QUOTED_STRING_CAPTURE})`, 'g');
12
+
13
+ export function findImportPathReferencesInText(text: string, lineOffset = 0): PathReference[] {
14
+ const references: PathReference[] = [];
15
+ const lines = text.split(/\r?\n/);
16
+ for (let lineIndex = 0; lineIndex < lines.length; lineIndex++) {
17
+ const line = lines[lineIndex]!;
18
+ for (const match of line.matchAll(IMPORT_PATH_PATTERN)) {
19
+ const quoted = match[1]!;
20
+ const path = parseReqlanQuotedString(quoted);
21
+ const start = match.index! + match[0].indexOf(quoted);
22
+ references.push({
23
+ path,
24
+ range: {
25
+ start: { line: lineOffset + lineIndex, character: start },
26
+ end: { line: lineOffset + lineIndex, character: start + quoted.length }
27
+ }
28
+ });
29
+ }
30
+ }
31
+ return references;
32
+ }
33
+
34
+ export function findEmbeddedPathReferencesInText(text: string, lineOffset = 0): PathReference[] {
35
+ const references: PathReference[] = [];
36
+ for (const embedded of findEmbeddedFileReferencesInText(text, lineOffset)) {
37
+ const parsed = parseFileReferenceString(embedded.file);
38
+ if (!parsed.filePath) {
39
+ continue;
40
+ }
41
+ const quotedPattern = new RegExp(REQLAN_QUOTED_STRING_CAPTURE);
42
+ const embeddedText = text.slice(
43
+ textOffsetAtPosition(text, embedded.range.start),
44
+ textOffsetAtPosition(text, embedded.range.end)
45
+ );
46
+ const quotedMatch = quotedPattern.exec(embeddedText);
47
+ if (!quotedMatch) {
48
+ continue;
49
+ }
50
+ const quoted = quotedMatch[0];
51
+ const pathIndex = quotedMatch.index ?? embeddedText.indexOf(quoted);
52
+ const absoluteStart = textOffsetAtPosition(text, embedded.range.start) + pathIndex;
53
+ const startPos = offsetToPosition(text, absoluteStart);
54
+ references.push({
55
+ path: parsed.filePath,
56
+ range: {
57
+ start: startPos,
58
+ end: { line: startPos.line, character: startPos.character + quoted.length }
59
+ }
60
+ });
61
+ }
62
+ return references;
63
+ }
64
+
65
+ export function findCommentPathReferencesInText(text: string, lineOffset = 0): PathReference[] {
66
+ const references: PathReference[] = [];
67
+ for (const commentRef of findCommentReferencesInText(text, lineOffset)) {
68
+ if (!commentRef.path) {
69
+ continue;
70
+ }
71
+ const quotedPattern = new RegExp(REQLAN_QUOTED_STRING_CAPTURE);
72
+ const segmentStart = textOffsetAtPosition(text, commentRef.range.start);
73
+ const segmentEnd = textOffsetAtPosition(text, commentRef.range.end);
74
+ const segment = text.slice(segmentStart, segmentEnd);
75
+ const quotedMatch = quotedPattern.exec(segment);
76
+ if (!quotedMatch) {
77
+ continue;
78
+ }
79
+ const quoted = quotedMatch[0];
80
+ const pathIndex = quotedMatch.index ?? segment.indexOf(quoted);
81
+ const absoluteStart = segmentStart + pathIndex;
82
+ const startPos = offsetToPosition(text, absoluteStart);
83
+ references.push({
84
+ path: commentRef.path,
85
+ range: {
86
+ start: startPos,
87
+ end: { line: startPos.line, character: startPos.character + quoted.length }
88
+ }
89
+ });
90
+ }
91
+ return references;
92
+ }
93
+
94
+ export function findPathReferencesInMovedFile(text: string, isRqFile: boolean): PathReference[] {
95
+ const references = isRqFile
96
+ ? [...findImportPathReferencesInText(text), ...findEmbeddedPathReferencesInText(text)]
97
+ : findCommentPathReferencesInText(text);
98
+ return dedupePathReferences(references);
99
+ }
100
+
101
+ function dedupePathReferences(references: PathReference[]): PathReference[] {
102
+ const seen = new Set<string>();
103
+ const unique: PathReference[] = [];
104
+ for (const reference of references) {
105
+ const key = [
106
+ reference.range.start.line,
107
+ reference.range.start.character,
108
+ reference.range.end.line,
109
+ reference.range.end.character
110
+ ].join(':');
111
+ if (seen.has(key)) {
112
+ continue;
113
+ }
114
+ seen.add(key);
115
+ unique.push(reference);
116
+ }
117
+ return unique;
118
+ }
119
+
120
+ function textOffsetAtLine(text: string, lineIndex: number): number {
121
+ const lines = text.split(/\r?\n/);
122
+ let offset = 0;
123
+ for (let index = 0; index < lineIndex; index++) {
124
+ offset += lines[index]!.length + 1;
125
+ }
126
+ return offset;
127
+ }
128
+
129
+ function textOffsetAtPosition(text: string, position: Range['start']): number {
130
+ return textOffsetAtLine(text, position.line) + position.character;
131
+ }
132
+
133
+ function offsetToPosition(text: string, offset: number): Range['start'] {
134
+ const before = text.slice(0, offset);
135
+ const lines = before.split(/\r?\n/);
136
+ return {
137
+ line: lines.length - 1,
138
+ character: lines[lines.length - 1]!.length
139
+ };
140
+ }
@@ -0,0 +1,346 @@
1
+ /**
2
+ * Resolves document-relative and import-root-aliased paths (default `@/`).
3
+ * rq:["../../../reqlan rq/extension/configuration.rq".configuration_location]
4
+ * rq:["../../../reqlan rq/extension/configuration.rq".configuration_import_roots]
5
+ * rq:["../../../reqlan rq/language/imports.rq".configuration_import_root_alias]
6
+ */
7
+ import type { FileSystemProvider, LangiumDocument, URI } from 'langium';
8
+ import { URI as UriCtor, UriUtils } from 'langium';
9
+
10
+ export const DEFAULT_IMPORT_ROOT_ALIAS = '@';
11
+ export const RQCONFIG_FILENAME = '.rqconfig.json';
12
+
13
+ export interface ImportRootMapping {
14
+ alias: string;
15
+ /** Absolute URI of that alias’s import-root directory, when set. */
16
+ rootUri?: URI;
17
+ }
18
+
19
+ export type RqExportScope = 'workspace' | 'currentFile';
20
+ export type RqExportRuntimeMode = 'interactive' | 'document' | 'print';
21
+ export type RqExportClusterStrategy = 'deterministic' | 'hybrid';
22
+
23
+ export interface RqHtmlExportConfig {
24
+ printEntryFileName?: string;
25
+ includeRequirementsPage?: boolean;
26
+ includeGraphPage?: boolean;
27
+ runtimeMode?: RqExportRuntimeMode;
28
+ clusterStrategy?: RqExportClusterStrategy;
29
+ includeIdeaPages?: boolean;
30
+ includeFilePages?: boolean;
31
+ includeCodeFilePages?: boolean;
32
+ includeClusterPages?: boolean;
33
+ includePrintPages?: boolean;
34
+ }
35
+
36
+ export interface RqExportConfig {
37
+ outputFolder?: string;
38
+ templateId?: string;
39
+ scope?: RqExportScope;
40
+ html?: RqHtmlExportConfig;
41
+ }
42
+
43
+ export interface RqConfig {
44
+ importRoots: ImportRootMapping[];
45
+ export?: RqExportConfig;
46
+ }
47
+
48
+ export interface PathResolveContext {
49
+ /** Workspace folders that contain documents (longest match wins). */
50
+ workspaceFolderUris?: readonly URI[];
51
+ /** Explicit workspace folder for tests; preferred over list lookup when set. */
52
+ workspaceFolderUri?: URI;
53
+ fileSystem?: FileSystemProvider;
54
+ /**
55
+ * Preloaded config. `undefined` loads nearest `.rqconfig.json` when fileSystem is set.
56
+ * `null` skips loading and uses defaults only.
57
+ */
58
+ config?: RqConfig | null;
59
+ }
60
+
61
+ export function defaultRqConfig(): RqConfig {
62
+ return { importRoots: [{ alias: DEFAULT_IMPORT_ROOT_ALIAS }] };
63
+ }
64
+
65
+ export function matchImportRootAlias(path: string, alias: string): string | undefined {
66
+ if (!alias || !path.startsWith(alias)) {
67
+ return undefined;
68
+ }
69
+ const afterAlias = path.slice(alias.length);
70
+ if (!afterAlias.startsWith('/')) {
71
+ return undefined;
72
+ }
73
+ return afterAlias.slice(1);
74
+ }
75
+
76
+ /** Longest matching alias wins when several mappings could apply. */
77
+ export function matchImportRootMapping(
78
+ path: string,
79
+ mappings: readonly ImportRootMapping[]
80
+ ): { mapping: ImportRootMapping; remainder: string } | undefined {
81
+ const ordered = [...mappings]
82
+ .filter(mapping => mapping.alias.length > 0)
83
+ .sort((left, right) => right.alias.length - left.alias.length);
84
+ for (const mapping of ordered) {
85
+ const remainder = matchImportRootAlias(path, mapping.alias);
86
+ if (remainder !== undefined) {
87
+ return { mapping, remainder };
88
+ }
89
+ }
90
+ return undefined;
91
+ }
92
+
93
+ export function findWorkspaceFolderUri(
94
+ documentUri: URI,
95
+ folderUris: readonly URI[] | undefined
96
+ ): URI | undefined {
97
+ if (!folderUris || folderUris.length === 0) {
98
+ return undefined;
99
+ }
100
+ const documentPath = documentUri.toString();
101
+ let best: URI | undefined;
102
+ let bestLength = -1;
103
+ for (const folder of folderUris) {
104
+ const folderPath = folder.path.endsWith('/')
105
+ ? folder.toString()
106
+ : `${folder.toString()}/`;
107
+ const folderBase = folder.toString();
108
+ if (documentPath === folderBase || documentPath.startsWith(folderPath)) {
109
+ const length = folderBase.length;
110
+ if (length > bestLength) {
111
+ best = folder;
112
+ bestLength = length;
113
+ }
114
+ }
115
+ }
116
+ return best;
117
+ }
118
+
119
+ export function loadApplyingRqConfig(
120
+ startDirUri: URI,
121
+ fileSystem: FileSystemProvider
122
+ ): RqConfig | undefined {
123
+ let dir = startDirUri;
124
+ for (;;) {
125
+ const configUri = UriUtils.joinPath(dir, RQCONFIG_FILENAME);
126
+ if (fileSystem.existsSync(configUri) && !fileSystem.statSync(configUri).isDirectory) {
127
+ return parseRqConfig(configUri, fileSystem);
128
+ }
129
+ const parent = UriUtils.dirname(dir);
130
+ if (UriUtils.equals(parent, dir)) {
131
+ return undefined;
132
+ }
133
+ dir = parent;
134
+ }
135
+ }
136
+
137
+ function parseRqConfig(configUri: URI, fileSystem: FileSystemProvider): RqConfig | undefined {
138
+ let raw: unknown;
139
+ try {
140
+ raw = JSON.parse(fileSystem.readFileSync(configUri));
141
+ } catch {
142
+ return undefined;
143
+ }
144
+ if (!raw || typeof raw !== 'object' || Array.isArray(raw)) {
145
+ return undefined;
146
+ }
147
+ const record = raw as Record<string, unknown>;
148
+ const importRoots = parseImportRoots(record.importRoots, configUri);
149
+ if (record.importRoots !== undefined && importRoots === undefined) {
150
+ return undefined;
151
+ }
152
+ const parsedExport = parseExportConfig(record.export, UriUtils.dirname(configUri));
153
+ const config: RqConfig = {
154
+ importRoots: importRoots ?? defaultRqConfig().importRoots
155
+ };
156
+ if (parsedExport) {
157
+ config.export = parsedExport;
158
+ }
159
+ return config;
160
+ }
161
+
162
+ function parseImportRootEntry(entry: unknown, configDir: URI): ImportRootMapping | undefined {
163
+ if (!entry || typeof entry !== 'object' || Array.isArray(entry)) {
164
+ return undefined;
165
+ }
166
+ const record = entry as Record<string, unknown>;
167
+ if (typeof record.alias !== 'string' || record.alias.length === 0) {
168
+ return undefined;
169
+ }
170
+ const mapping: ImportRootMapping = { alias: record.alias };
171
+ if (typeof record.root === 'string' && record.root.length > 0) {
172
+ mapping.rootUri = isAbsoluteUriOrPath(record.root)
173
+ ? toDirectoryUri(record.root)
174
+ : UriUtils.resolvePath(configDir, record.root);
175
+ }
176
+ return mapping;
177
+ }
178
+
179
+ function parseImportRoots(raw: unknown, configUri: URI): ImportRootMapping[] | undefined {
180
+ if (raw === undefined) {
181
+ return undefined;
182
+ }
183
+ if (!Array.isArray(raw)) {
184
+ return undefined;
185
+ }
186
+ const configDir = UriUtils.dirname(configUri);
187
+ const importRoots: ImportRootMapping[] = [];
188
+ for (const entry of raw) {
189
+ const mapping = parseImportRootEntry(entry, configDir);
190
+ if (mapping) {
191
+ importRoots.push(mapping);
192
+ }
193
+ }
194
+ return importRoots.length > 0 ? importRoots : defaultRqConfig().importRoots;
195
+ }
196
+
197
+ function parseExportConfig(raw: unknown, configDir: URI): RqExportConfig | undefined {
198
+ if (!raw || typeof raw !== 'object' || Array.isArray(raw)) {
199
+ return undefined;
200
+ }
201
+ const record = raw as Record<string, unknown>;
202
+ const config: RqExportConfig = {};
203
+
204
+ if (typeof record.outputFolder === 'string' && record.outputFolder.trim().length > 0) {
205
+ config.outputFolder = isAbsoluteUriOrPath(record.outputFolder)
206
+ ? toDirectoryUri(record.outputFolder).fsPath
207
+ : UriUtils.resolvePath(configDir, record.outputFolder).fsPath;
208
+ }
209
+ if (typeof record.templateId === 'string' && record.templateId.trim().length > 0) {
210
+ config.templateId = record.templateId.trim();
211
+ }
212
+ if (record.scope === 'workspace' || record.scope === 'currentFile') {
213
+ config.scope = record.scope;
214
+ }
215
+ const html = parseHtmlExportConfig(record.html);
216
+ if (html) {
217
+ config.html = html;
218
+ }
219
+
220
+ return Object.keys(config).length > 0 ? config : undefined;
221
+ }
222
+
223
+ function parseHtmlExportConfig(raw: unknown): RqHtmlExportConfig | undefined {
224
+ if (!raw || typeof raw !== 'object' || Array.isArray(raw)) {
225
+ return undefined;
226
+ }
227
+ const record = raw as Record<string, unknown>;
228
+ const config: RqHtmlExportConfig = {};
229
+ if (typeof record.printEntryFileName === 'string' && record.printEntryFileName.trim().length > 0) {
230
+ config.printEntryFileName = record.printEntryFileName.trim();
231
+ }
232
+ if (typeof record.includeRequirementsPage === 'boolean') {
233
+ config.includeRequirementsPage = record.includeRequirementsPage;
234
+ }
235
+ if (typeof record.includeGraphPage === 'boolean') {
236
+ config.includeGraphPage = record.includeGraphPage;
237
+ }
238
+ if (record.runtimeMode === 'interactive' || record.runtimeMode === 'document' || record.runtimeMode === 'print') {
239
+ config.runtimeMode = record.runtimeMode;
240
+ }
241
+ if (record.clusterStrategy === 'deterministic' || record.clusterStrategy === 'hybrid') {
242
+ config.clusterStrategy = record.clusterStrategy;
243
+ }
244
+ if (typeof record.includeIdeaPages === 'boolean') {
245
+ config.includeIdeaPages = record.includeIdeaPages;
246
+ }
247
+ if (typeof record.includeFilePages === 'boolean') {
248
+ config.includeFilePages = record.includeFilePages;
249
+ }
250
+ if (typeof record.includeCodeFilePages === 'boolean') {
251
+ config.includeCodeFilePages = record.includeCodeFilePages;
252
+ }
253
+ if (typeof record.includeClusterPages === 'boolean') {
254
+ config.includeClusterPages = record.includeClusterPages;
255
+ }
256
+ if (typeof record.includePrintPages === 'boolean') {
257
+ config.includePrintPages = record.includePrintPages;
258
+ }
259
+ return Object.keys(config).length > 0 ? config : undefined;
260
+ }
261
+
262
+ function isAbsoluteUriOrPath(value: string): boolean {
263
+ return /^[a-zA-Z][a-zA-Z0-9+.-]*:/.test(value) || value.startsWith('/');
264
+ }
265
+
266
+ function toDirectoryUri(value: string): URI {
267
+ if (/^[a-zA-Z][a-zA-Z0-9+.-]*:/.test(value)) {
268
+ return UriCtor.parse(value);
269
+ }
270
+ return UriCtor.file(value);
271
+ }
272
+
273
+ export function resolveRqConfig(document: LangiumDocument, context?: PathResolveContext): RqConfig {
274
+ if (context?.config === null) {
275
+ return defaultRqConfig();
276
+ }
277
+ if (context?.config) {
278
+ return context.config;
279
+ }
280
+ if (context?.fileSystem) {
281
+ const loaded = loadApplyingRqConfig(UriUtils.dirname(document.uri), context.fileSystem);
282
+ if (loaded) {
283
+ return loaded;
284
+ }
285
+ }
286
+ return defaultRqConfig();
287
+ }
288
+
289
+ export function resolveImportRootUri(
290
+ document: LangiumDocument,
291
+ context: PathResolveContext | undefined,
292
+ mapping: ImportRootMapping
293
+ ): URI | undefined {
294
+ if (mapping.rootUri) {
295
+ return mapping.rootUri;
296
+ }
297
+ if (context?.workspaceFolderUri) {
298
+ return context.workspaceFolderUri;
299
+ }
300
+ return findWorkspaceFolderUri(document.uri, context?.workspaceFolderUris);
301
+ }
302
+
303
+ /**
304
+ * Resolves a path string against the document directory, or against an import root when aliased.
305
+ */
306
+ export function resolveDocumentPathUri(
307
+ path: string,
308
+ document: LangiumDocument,
309
+ context?: PathResolveContext
310
+ ): URI {
311
+ const config = resolveRqConfig(document, context);
312
+ const matched = matchImportRootMapping(path, config.importRoots);
313
+ if (!matched) {
314
+ return UriUtils.resolvePath(UriUtils.dirname(document.uri), path);
315
+ }
316
+ const importRoot = resolveImportRootUri(document, context, matched.mapping);
317
+ if (!importRoot) {
318
+ return UriUtils.resolvePath(UriUtils.dirname(document.uri), path);
319
+ }
320
+ return UriUtils.resolvePath(importRoot, matched.remainder);
321
+ }
322
+
323
+ export function workspaceFolderUrisFromManager(
324
+ folders: ReadonlyArray<{ uri: string }> | undefined
325
+ ): URI[] {
326
+ if (!folders) {
327
+ return [];
328
+ }
329
+ return folders.map(folder => UriCtor.parse(folder.uri));
330
+ }
331
+
332
+ export function pathResolveContextFromServices(services: {
333
+ shared: {
334
+ workspace: {
335
+ WorkspaceManager: { workspaceFolders?: ReadonlyArray<{ uri: string }> };
336
+ FileSystemProvider: FileSystemProvider;
337
+ };
338
+ };
339
+ }): PathResolveContext {
340
+ return {
341
+ fileSystem: services.shared.workspace.FileSystemProvider,
342
+ workspaceFolderUris: workspaceFolderUrisFromManager(
343
+ services.shared.workspace.WorkspaceManager.workspaceFolders
344
+ )
345
+ };
346
+ }
@@ -0,0 +1,30 @@
1
+ /**
2
+ * Shared helpers for reqlan double- and single-quoted string literals.
3
+ */
4
+
5
+ /** Capturing group for one quoted string (double or single). */
6
+ export const REQLAN_QUOTED_STRING_CAPTURE = '(?:"(?:\\\\.|[^"\\\\])*"|\'(?:\\\\.|[^\'\\\\])*\')';
7
+
8
+ export const REQLAN_QUOTED_STRING_PATTERN = new RegExp(REQLAN_QUOTED_STRING_CAPTURE, 'g');
9
+
10
+ export function reqlanStringDelimiter(text: string): '"' | "'" | undefined {
11
+ if (text.startsWith('"')) {
12
+ return '"';
13
+ }
14
+ if (text.startsWith("'")) {
15
+ return "'";
16
+ }
17
+ return undefined;
18
+ }
19
+
20
+ export function unquoteReqlanString(text: string): string {
21
+ const delimiter = reqlanStringDelimiter(text);
22
+ if (!delimiter || !text.endsWith(delimiter)) {
23
+ return text;
24
+ }
25
+ return text.slice(1, -1).replace(/\\(.)/g, '$1');
26
+ }
27
+
28
+ export function parseReqlanQuotedString(quoted: string): string {
29
+ return unquoteReqlanString(quoted);
30
+ }
@@ -0,0 +1,154 @@
1
+ /**
2
+ * Locates file path references at a cursor position and resolves them to files, folders, or missing paths.
3
+ */
4
+ import type { CstNode, FileSystemProvider, LangiumDocument, LangiumDocuments } from 'langium';
5
+ import { CstUtils, GrammarUtils } from 'langium';
6
+ import type { Position, LocationLink } from 'vscode-languageserver';
7
+ import {
8
+ findCommentReferencePartAt,
9
+ resolveCommentDefinitionLinks,
10
+ resolveFileUri
11
+ } from './reqlan-comment-resolver.js';
12
+ import { findEmbeddedFileReferenceAt } from './reqlan-embedded-file-references.js';
13
+ import {
14
+ classifyReferenceUri,
15
+ listFolderFileNames,
16
+ resolveEmbeddedFileReferenceLink,
17
+ resolveFileReferenceLink,
18
+ type ReferenceResolution,
19
+ type ResolvedFileLink
20
+ } from './reqlan-file-link-resolver.js';
21
+ import {
22
+ isFileReference,
23
+ isFileSymbolReference,
24
+ type FileReference,
25
+ type FileSymbolReference
26
+ } from './generated/ast.js';
27
+ import type { PathResolveContext } from './reqlan-path-resolve.js';
28
+
29
+ export const REQLAN_OPEN_FOLDER_COMMAND = 'reqlan.openFolderReference';
30
+ export const REQLAN_FILE_REFERENCE_AT_REQUEST = 'reqlan/fileReferenceAt';
31
+ export const REQLAN_COMMENT_DEFINITION_REQUEST = 'reqlan/commentDefinition';
32
+
33
+ export function folderReferenceCommandTarget(folderUri: string): string {
34
+ return `command:${REQLAN_OPEN_FOLDER_COMMAND}?${encodeURIComponent(JSON.stringify([folderUri]))}`;
35
+ }
36
+
37
+ export function findFileReferenceAtPosition(
38
+ document: LangiumDocument,
39
+ position: Position,
40
+ documents: LangiumDocuments,
41
+ fileSystem: FileSystemProvider,
42
+ context?: PathResolveContext
43
+ ): ResolvedFileLink | undefined {
44
+ const pathContext = { ...context, fileSystem: context?.fileSystem ?? fileSystem };
45
+ const commentPart = findCommentReferencePartAt(document, position);
46
+ if (commentPart?.property === 'path' && commentPart.reference.path) {
47
+ return resolvePathReference(
48
+ document,
49
+ commentPart.reference.path,
50
+ commentPart.reference.range,
51
+ documents,
52
+ fileSystem,
53
+ pathContext
54
+ );
55
+ }
56
+ const embeddedReference = findEmbeddedFileReferenceAt(document, position);
57
+ if (embeddedReference) {
58
+ return resolveEmbeddedFileReferenceLink(embeddedReference, document, documents, fileSystem, pathContext);
59
+ }
60
+ const fileReference = findFileReferenceNodeAtPosition(document, position);
61
+ if (fileReference) {
62
+ return resolveFileReferenceLink(fileReference.node, documents, fileSystem, pathContext);
63
+ }
64
+ return undefined;
65
+ }
66
+
67
+ function resolvePathReference(
68
+ document: LangiumDocument,
69
+ path: string,
70
+ sourceRange: ResolvedFileLink['sourceRange'],
71
+ documents: LangiumDocuments,
72
+ fileSystem: FileSystemProvider,
73
+ context?: PathResolveContext
74
+ ): ResolvedFileLink | undefined {
75
+ const targetUri = resolveFileUri(path, document, context);
76
+ const resolution = classifyReferenceUri(targetUri, documents, fileSystem);
77
+ if (resolution === 'missing') {
78
+ return undefined;
79
+ }
80
+ if (resolution === 'folder') {
81
+ return {
82
+ sourceRange,
83
+ targetUri: targetUri.toString(),
84
+ resolution,
85
+ folderFiles: listFolderFileNames(fileSystem, targetUri)
86
+ };
87
+ }
88
+ const targetDocument = documents.getDocument(targetUri);
89
+ const target = targetDocument?.parseResult.value.$cstNode;
90
+ if (!targetDocument || !target) {
91
+ return undefined;
92
+ }
93
+ return {
94
+ sourceRange,
95
+ targetUri: targetDocument.textDocument.uri,
96
+ targetRange: target.range,
97
+ resolution: 'file'
98
+ };
99
+ }
100
+
101
+ function findFileReferenceNodeAtPosition(
102
+ document: LangiumDocument,
103
+ position: Position
104
+ ): { node: FileReference | FileSymbolReference; pathNode: CstNode } | undefined {
105
+ const root = document.parseResult.value.$cstNode;
106
+ if (!root) {
107
+ return undefined;
108
+ }
109
+ const offset = document.textDocument.offsetAt(position);
110
+ let current: CstNode | undefined = CstUtils.findLeafNodeAtOffset(root, offset);
111
+ while (current) {
112
+ const assignment = GrammarUtils.findAssignment(current);
113
+ const container = current.astNode;
114
+ if ((isFileReference(container) || isFileSymbolReference(container)) && assignment?.feature === 'file') {
115
+ const pathNode = GrammarUtils.findNodeForProperty(container.$cstNode, 'file');
116
+ if (pathNode) {
117
+ return { node: container, pathNode };
118
+ }
119
+ }
120
+ current = current.container;
121
+ }
122
+ return undefined;
123
+ }
124
+
125
+ export interface FileReferenceAtRequestResult {
126
+ sourceRange: ResolvedFileLink['sourceRange'];
127
+ targetUri: string;
128
+ resolution: ReferenceResolution;
129
+ folderFiles?: string[];
130
+ }
131
+
132
+ export function findCommentDefinitionAtPosition(
133
+ document: LangiumDocument,
134
+ position: Position,
135
+ documents: LangiumDocuments,
136
+ context?: PathResolveContext
137
+ ): LocationLink[] | undefined {
138
+ const commentPart = findCommentReferencePartAt(document, position);
139
+ if (commentPart?.property !== 'idea') {
140
+ return undefined;
141
+ }
142
+ return resolveCommentDefinitionLinks(commentPart.reference, document, documents, context);
143
+ }
144
+
145
+ export function fileReferenceAtRequestResult(
146
+ link: ResolvedFileLink
147
+ ): FileReferenceAtRequestResult {
148
+ return {
149
+ sourceRange: link.sourceRange,
150
+ targetUri: link.targetUri,
151
+ resolution: link.resolution ?? 'file',
152
+ folderFiles: link.folderFiles
153
+ };
154
+ }