@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,323 @@
1
+ /**
2
+ * Classification labels and summary stats for reference CodeLens buttons.
3
+ * Click opens a reference card; navigation stays on document links / go-to-definition.
4
+ */
5
+ import { AstUtils, GrammarUtils, URI, type AstNode } from 'langium';
6
+ import { Command, type CodeLens, type Range } from 'vscode-languageserver';
7
+ import { statSync } from 'node:fs';
8
+ import {
9
+ isBracketReference,
10
+ isFileReference,
11
+ isFileSymbolReference,
12
+ isIdea,
13
+ isIdeaSet,
14
+ isLocalReference,
15
+ isOneLinerIdea,
16
+ isQualifiedReference,
17
+ isWikiLink,
18
+ type IdeaDeclaration,
19
+ type IdeaSet
20
+ } from './generated/ast.js';
21
+ import {
22
+ collectInboundReferencers,
23
+ type ReferencedDeclaration
24
+ } from './reqlan-inbound-reference-inlay-label.js';
25
+ import {
26
+ listFolderFileNames,
27
+ resolveFileReferenceLink,
28
+ type ResolvedFileLink
29
+ } from './reqlan-file-link-resolver.js';
30
+ import {
31
+ isNamespaceImportOnlyReference,
32
+ resolveNamespaceImportReferenceLink
33
+ } from './reqlan-namespace-import-links.js';
34
+ import { pathResolveContextFromServices } from './reqlan-path-resolve.js';
35
+ import { referenceIdea } from './reqlan-references.js';
36
+ import { summarizeIdeaDeclaration, truncateSummary } from './reqlan-idea-summary.js';
37
+ import {
38
+ REQLAN_OPEN_REFERENCE_CODE_LENS_COMMAND,
39
+ type ReferenceCodeLensPayload
40
+ } from './reqlan-code-lens-settings.js';
41
+ import type { ReqlanServices } from './reqlan-module.js';
42
+
43
+ export type ReferenceCodeLensClassification =
44
+ | { kind: 'idea'; declaration: ReferencedDeclaration }
45
+ | { kind: 'reqlan-file'; link: ResolvedFileLink }
46
+ | { kind: 'file'; link: ResolvedFileLink; extension: string }
47
+ | { kind: 'folder'; link: ResolvedFileLink };
48
+
49
+ export function classifyReferenceForCodeLens(
50
+ services: ReqlanServices,
51
+ node: AstNode
52
+ ): ReferenceCodeLensClassification | undefined {
53
+ if (!isBracketReference(node) && !isWikiLink(node)) {
54
+ return undefined;
55
+ }
56
+ const target = node.target;
57
+ if (isLocalReference(target) || isQualifiedReference(target)) {
58
+ if (isNamespaceImportOnlyReference(target)) {
59
+ const link = resolveNamespaceImportReferenceLink(
60
+ target,
61
+ services.shared.workspace.LangiumDocuments,
62
+ services.shared.workspace.FileSystemProvider,
63
+ pathResolveContextFromServices(services)
64
+ );
65
+ return classifyResolvedFileLink(link);
66
+ }
67
+ const ideaRef = referenceIdea(target);
68
+ if (ideaRef?.ref) {
69
+ return { kind: 'idea', declaration: ideaRef.ref };
70
+ }
71
+ if (isQualifiedReference(target) && target.ideaset?.ref) {
72
+ return { kind: 'idea', declaration: target.ideaset.ref };
73
+ }
74
+ return undefined;
75
+ }
76
+ if (isFileReference(target) || isFileSymbolReference(target)) {
77
+ const link = resolveFileReferenceLink(
78
+ target,
79
+ services.shared.workspace.LangiumDocuments,
80
+ services.shared.workspace.FileSystemProvider,
81
+ pathResolveContextFromServices(services)
82
+ );
83
+ if (isFileSymbolReference(target) && target.symbols.length > 0) {
84
+ const idea = resolveFileSymbolIdea(services, link, target.symbols[0]!);
85
+ if (idea) {
86
+ return { kind: 'idea', declaration: idea };
87
+ }
88
+ }
89
+ return classifyResolvedFileLink(link);
90
+ }
91
+ return undefined;
92
+ }
93
+
94
+ function classifyResolvedFileLink(link: ResolvedFileLink | undefined): ReferenceCodeLensClassification | undefined {
95
+ if (!link || link.resolution === 'missing') {
96
+ return undefined;
97
+ }
98
+ if (link.resolution === 'folder') {
99
+ return { kind: 'folder', link };
100
+ }
101
+ const extension = fileExtension(link.targetUri);
102
+ if (!extension || extension === 'rq') {
103
+ return { kind: 'reqlan-file', link };
104
+ }
105
+ return { kind: 'file', link, extension };
106
+ }
107
+
108
+ function resolveFileSymbolIdea(
109
+ services: ReqlanServices,
110
+ link: ResolvedFileLink | undefined,
111
+ symbolName: string
112
+ ): IdeaDeclaration | IdeaSet | undefined {
113
+ if (!link || link.resolution !== 'file') {
114
+ return undefined;
115
+ }
116
+ const targetDocument = services.shared.workspace.LangiumDocuments.getDocument(URI.parse(link.targetUri));
117
+ if (!targetDocument) {
118
+ return undefined;
119
+ }
120
+ for (const candidate of AstUtils.streamAst(targetDocument.parseResult.value)) {
121
+ if ((isIdea(candidate) || isOneLinerIdea(candidate) || isIdeaSet(candidate)) && candidate.name === symbolName) {
122
+ return candidate;
123
+ }
124
+ }
125
+ return undefined;
126
+ }
127
+
128
+ export function referenceCodeLensTitle(classification: ReferenceCodeLensClassification): string {
129
+ switch (classification.kind) {
130
+ case 'idea':
131
+ return 'open idea';
132
+ case 'reqlan-file':
133
+ return 'open reqlan file';
134
+ case 'file':
135
+ return `open ${classification.extension} file`;
136
+ case 'folder':
137
+ return 'open folder';
138
+ }
139
+ }
140
+
141
+ export function buildReferenceCodeLens(
142
+ services: ReqlanServices,
143
+ node: AstNode,
144
+ classification: ReferenceCodeLensClassification
145
+ ): CodeLens | undefined {
146
+ const range = codeLensRange(node);
147
+ if (!range) {
148
+ return undefined;
149
+ }
150
+ const payload = payloadForClassification(services, classification);
151
+ if (!payload) {
152
+ return undefined;
153
+ }
154
+ const title = payload.classification;
155
+ const tooltip = payload.stats.length > 0
156
+ ? `${payload.displayName} · ${payload.stats.join(' · ')}`
157
+ : payload.displayName;
158
+ const command = Command.create(title, REQLAN_OPEN_REFERENCE_CODE_LENS_COMMAND, payload);
159
+ command.tooltip = tooltip;
160
+ return { range, command };
161
+ }
162
+
163
+ export function buildReferenceCodeLensStats(
164
+ services: ReqlanServices,
165
+ classification: ReferenceCodeLensClassification
166
+ ): string[] {
167
+ const parts: string[] = [];
168
+ if (classification.kind === 'idea') {
169
+ const referencers = collectInboundReferencers(services, classification.declaration).length;
170
+ const references = countOutboundReferences(classification.declaration);
171
+ parts.push(`${referencers} referencer${referencers === 1 ? '' : 's'}`);
172
+ parts.push(`${references} reference${references === 1 ? '' : 's'}`);
173
+ const edited = fileLastEditedLabel(AstUtils.getDocument(classification.declaration).uri.toString());
174
+ if (edited) {
175
+ parts.push(`last edited ${edited}`);
176
+ }
177
+ return parts;
178
+ }
179
+ if (classification.kind === 'folder') {
180
+ const files = classification.link.folderFiles
181
+ ?? listFolderFileNames(
182
+ services.shared.workspace.FileSystemProvider,
183
+ URI.parse(classification.link.targetUri)
184
+ );
185
+ parts.push(`${files.length} file${files.length === 1 ? '' : 's'}`);
186
+ return parts;
187
+ }
188
+ const edited = fileLastEditedLabel(classification.link.targetUri);
189
+ if (edited) {
190
+ parts.push(`last edited ${edited}`);
191
+ }
192
+ if (classification.kind === 'reqlan-file') {
193
+ const targetDocument = services.shared.workspace.LangiumDocuments.getDocument(
194
+ URI.parse(classification.link.targetUri)
195
+ );
196
+ if (targetDocument) {
197
+ let ideaCount = 0;
198
+ for (const candidate of AstUtils.streamAst(targetDocument.parseResult.value)) {
199
+ if (isIdea(candidate) || isOneLinerIdea(candidate) || isIdeaSet(candidate)) {
200
+ ideaCount++;
201
+ }
202
+ }
203
+ parts.push(`${ideaCount} idea${ideaCount === 1 ? '' : 's'}`);
204
+ }
205
+ }
206
+ return parts;
207
+ }
208
+
209
+ /** @deprecated Prefer {@link buildReferenceCodeLensStats} — kept for existing tests. */
210
+ export function buildReferenceCodeLensTooltip(
211
+ services: ReqlanServices,
212
+ classification: ReferenceCodeLensClassification
213
+ ): string | undefined {
214
+ const parts = buildReferenceCodeLensStats(services, classification);
215
+ return parts.length > 0 ? parts.join(' · ') : undefined;
216
+ }
217
+
218
+ export function countOutboundReferences(declaration: ReferencedDeclaration): number {
219
+ let count = 0;
220
+ for (const node of AstUtils.streamAst(declaration)) {
221
+ if (isBracketReference(node) || isWikiLink(node)) {
222
+ count++;
223
+ }
224
+ }
225
+ return count;
226
+ }
227
+
228
+ export function fileExtension(targetUri: string): string | undefined {
229
+ const path = URI.parse(targetUri).path;
230
+ const slash = Math.max(path.lastIndexOf('/'), path.lastIndexOf('\\'));
231
+ const base = slash >= 0 ? path.slice(slash + 1) : path;
232
+ const dot = base.lastIndexOf('.');
233
+ if (dot <= 0 || dot === base.length - 1) {
234
+ return undefined;
235
+ }
236
+ return base.slice(dot + 1).toLowerCase();
237
+ }
238
+
239
+ export function fileLastEditedLabel(targetUri: string): string | undefined {
240
+ try {
241
+ const uri = URI.parse(targetUri);
242
+ if (uri.scheme !== 'file') {
243
+ return undefined;
244
+ }
245
+ const mtime = statSync(uri.fsPath).mtime;
246
+ return mtime.toISOString().slice(0, 10);
247
+ } catch {
248
+ return undefined;
249
+ }
250
+ }
251
+
252
+ function displayNameForUri(targetUri: string): string {
253
+ const path = URI.parse(targetUri).path;
254
+ const slash = Math.max(path.lastIndexOf('/'), path.lastIndexOf('\\'));
255
+ return slash >= 0 ? path.slice(slash + 1) : path;
256
+ }
257
+
258
+ function payloadForClassification(
259
+ services: ReqlanServices,
260
+ classification: ReferenceCodeLensClassification
261
+ ): ReferenceCodeLensPayload | undefined {
262
+ const classificationLabel = referenceCodeLensTitle(classification);
263
+ const stats = buildReferenceCodeLensStats(services, classification);
264
+
265
+ if (classification.kind === 'idea') {
266
+ const declaration = classification.declaration;
267
+ const nameNode = GrammarUtils.findNodeForProperty(declaration.$cstNode, 'name');
268
+ const document = AstUtils.getDocument(declaration);
269
+ const summary = isIdea(declaration) || isOneLinerIdea(declaration)
270
+ ? truncateSummary(summarizeIdeaDeclaration(declaration), 240)
271
+ : undefined;
272
+ return {
273
+ kind: 'idea',
274
+ classification: classificationLabel,
275
+ displayName: declaration.name,
276
+ targetUri: document.uri.toString(),
277
+ line: nameNode?.range.start.line ?? 0,
278
+ character: nameNode?.range.start.character ?? 0,
279
+ summary: summary || undefined,
280
+ stats
281
+ };
282
+ }
283
+
284
+ const link = classification.link;
285
+ const displayName = displayNameForUri(link.targetUri);
286
+ if (classification.kind === 'folder') {
287
+ const folderFiles = link.folderFiles
288
+ ?? listFolderFileNames(
289
+ services.shared.workspace.FileSystemProvider,
290
+ URI.parse(link.targetUri)
291
+ );
292
+ return {
293
+ kind: 'folder',
294
+ classification: classificationLabel,
295
+ displayName,
296
+ targetUri: link.targetUri,
297
+ folderFiles,
298
+ summary: folderFiles.slice(0, 8).join(', ') + (folderFiles.length > 8 ? '…' : ''),
299
+ stats
300
+ };
301
+ }
302
+ return {
303
+ kind: classification.kind === 'reqlan-file' ? 'reqlan-file' : 'file',
304
+ classification: classificationLabel,
305
+ displayName,
306
+ targetUri: link.targetUri,
307
+ line: link.targetRange?.start.line ?? 0,
308
+ character: link.targetRange?.start.character ?? 0,
309
+ extension: classification.kind === 'file' ? classification.extension : undefined,
310
+ stats
311
+ };
312
+ }
313
+
314
+ function codeLensRange(node: AstNode): Range | undefined {
315
+ const cst = node.$cstNode;
316
+ if (!cst) {
317
+ return undefined;
318
+ }
319
+ return {
320
+ start: { line: cst.range.start.line, character: 0 },
321
+ end: cst.range.end
322
+ };
323
+ }
@@ -0,0 +1,202 @@
1
+ /**
2
+ * Locate places where a selection or word can become a [reference],
3
+ * and extract surrounding idea text for the search modal preview.
4
+ * rq:["../../../reqlan rq/extension/features-commands.rq".search_code_actions]
5
+ */
6
+ import type { LangiumDocument } from 'langium';
7
+ import type { Position, Range } from 'vscode-languageserver';
8
+ import {
9
+ findContainingIdea,
10
+ isInMainDescriptionProse
11
+ } from './reqlan-completion-context.js';
12
+ import {
13
+ findIdeaReferenceAtPosition,
14
+ type IdeaReferenceSite
15
+ } from './reqlan-idea-reference-site.js';
16
+ import { isIdea, isOneLinerIdea, type IdeaDeclaration } from './generated/ast.js';
17
+
18
+ export type ReferenceSearchMode = 'replace' | 'wrap';
19
+
20
+ export interface ReferenceSearchContext {
21
+ ideaName: string;
22
+ /** Text before the target within the idea source. */
23
+ before: string;
24
+ /** Selected / reference text that will become (or already is) the reference. */
25
+ target: string;
26
+ /** Text after the target within the idea source. */
27
+ after: string;
28
+ }
29
+
30
+ export interface ReferenceSearchSite {
31
+ refText: string;
32
+ range: Range;
33
+ mode: ReferenceSearchMode;
34
+ kind: 'bracket' | 'wikilink' | 'prose';
35
+ context?: ReferenceSearchContext;
36
+ }
37
+
38
+ /**
39
+ * Prefer an existing [reference]/[[wikilink]] under the cursor; otherwise a
40
+ * selection or word in idea-body prose that can be wrapped as `[name]`.
41
+ */
42
+ export function findReferenceSearchSite(
43
+ document: LangiumDocument,
44
+ range: Range
45
+ ): ReferenceSearchSite | undefined {
46
+ const existing = findIdeaReferenceAtPosition(document, range.start);
47
+ if (existing) {
48
+ return siteFromExistingReference(document, existing);
49
+ }
50
+ return findWrapSite(document, range);
51
+ }
52
+
53
+ function siteFromExistingReference(
54
+ document: LangiumDocument,
55
+ existing: IdeaReferenceSite
56
+ ): ReferenceSearchSite {
57
+ return {
58
+ refText: existing.refText,
59
+ range: existing.range,
60
+ mode: 'replace',
61
+ kind: existing.kind,
62
+ context: buildContextForRange(document, existing.range)
63
+ };
64
+ }
65
+
66
+ function findWrapSite(document: LangiumDocument, range: Range): ReferenceSearchSite | undefined {
67
+ const rawRange = isEmptyRange(range)
68
+ ? expandToWordAtPosition(document, range.start)
69
+ : normalizeForwardRange(range);
70
+ const wrapRange = rawRange ? trimRangeWhitespace(document, rawRange) : undefined;
71
+ if (!wrapRange || isEmptyRange(wrapRange)) {
72
+ return undefined;
73
+ }
74
+
75
+ // Both ends must sit in idea-body prose (not imports, attribute keys, refs, etc.)
76
+ const endProbe = document.textDocument.positionAt(
77
+ Math.max(
78
+ document.textDocument.offsetAt(wrapRange.start),
79
+ document.textDocument.offsetAt(wrapRange.end) - 1
80
+ )
81
+ );
82
+ if (!isAppropriateWrapLocation(document, wrapRange.start)
83
+ || !isAppropriateWrapLocation(document, endProbe)) {
84
+ return undefined;
85
+ }
86
+
87
+ // Keep wrap inside a single idea
88
+ const idea = findContainingIdea(document, wrapRange.start);
89
+ if (!idea || findContainingIdea(document, wrapRange.end) !== idea) {
90
+ return undefined;
91
+ }
92
+
93
+ const refText = document.textDocument.getText(wrapRange).trim();
94
+ if (!refText || /\n/.test(refText)) {
95
+ return undefined;
96
+ }
97
+ // Avoid wrapping text that is already bracket-wrapped
98
+ if (/^\[.*\]$/.test(refText) || /^\[\[.*\]\]$/.test(refText)) {
99
+ return undefined;
100
+ }
101
+
102
+ return {
103
+ refText,
104
+ range: wrapRange,
105
+ mode: 'wrap',
106
+ kind: 'prose',
107
+ context: buildContextForRange(document, wrapRange, idea)
108
+ };
109
+ }
110
+
111
+ export function isAppropriateWrapLocation(document: LangiumDocument, position: Position): boolean {
112
+ return isInMainDescriptionProse(document, position);
113
+ }
114
+
115
+ export function buildContextForRange(
116
+ document: LangiumDocument,
117
+ range: Range,
118
+ idea?: IdeaDeclaration
119
+ ): ReferenceSearchContext | undefined {
120
+ const containing = idea ?? findContainingIdea(document, range.start);
121
+ if (!containing?.$cstNode) {
122
+ return undefined;
123
+ }
124
+ const ideaRange = containing.$cstNode.range;
125
+ const ideaText = document.textDocument.getText(ideaRange);
126
+ const ideaStart = document.textDocument.offsetAt(ideaRange.start);
127
+ const targetStart = document.textDocument.offsetAt(range.start) - ideaStart;
128
+ const targetEnd = document.textDocument.offsetAt(range.end) - ideaStart;
129
+ if (targetStart < 0 || targetEnd > ideaText.length || targetStart > targetEnd) {
130
+ return undefined;
131
+ }
132
+ return {
133
+ ideaName: containing.name,
134
+ before: ideaText.slice(0, targetStart),
135
+ target: ideaText.slice(targetStart, targetEnd),
136
+ after: ideaText.slice(targetEnd)
137
+ };
138
+ }
139
+
140
+ export function expandToWordAtPosition(
141
+ document: LangiumDocument,
142
+ position: Position
143
+ ): Range | undefined {
144
+ const line = document.textDocument.getText({
145
+ start: { line: position.line, character: 0 },
146
+ end: { line: position.line + 1, character: 0 }
147
+ });
148
+ // Strip trailing newline for indexing
149
+ const lineText = line.replace(/\r?\n$/, '');
150
+ if (position.character > lineText.length) {
151
+ return undefined;
152
+ }
153
+ const isWord = (ch: string | undefined) => !!ch && /[A-Za-z0-9_]/.test(ch);
154
+ let start = position.character;
155
+ let end = position.character;
156
+ while (start > 0 && isWord(lineText[start - 1])) {
157
+ start -= 1;
158
+ }
159
+ while (end < lineText.length && isWord(lineText[end])) {
160
+ end += 1;
161
+ }
162
+ if (start === end) {
163
+ return undefined;
164
+ }
165
+ return {
166
+ start: { line: position.line, character: start },
167
+ end: { line: position.line, character: end }
168
+ };
169
+ }
170
+
171
+ function trimRangeWhitespace(document: LangiumDocument, range: Range): Range | undefined {
172
+ const text = document.textDocument.getText(range);
173
+ const lead = /^\s*/.exec(text)?.[0].length ?? 0;
174
+ const trail = /\s*$/.exec(text)?.[0].length ?? 0;
175
+ if (lead + trail >= text.length) {
176
+ return undefined;
177
+ }
178
+ const startOffset = document.textDocument.offsetAt(range.start) + lead;
179
+ const endOffset = document.textDocument.offsetAt(range.end) - trail;
180
+ return {
181
+ start: document.textDocument.positionAt(startOffset),
182
+ end: document.textDocument.positionAt(endOffset)
183
+ };
184
+ }
185
+
186
+ function isEmptyRange(range: Range): boolean {
187
+ return range.start.line === range.end.line && range.start.character === range.end.character;
188
+ }
189
+
190
+ function normalizeForwardRange(range: Range): Range {
191
+ if (
192
+ range.start.line > range.end.line
193
+ || (range.start.line === range.end.line && range.start.character > range.end.character)
194
+ ) {
195
+ return { start: range.end, end: range.start };
196
+ }
197
+ return range;
198
+ }
199
+
200
+ export function isBlockOrOneLinerIdea(node: unknown): node is IdeaDeclaration {
201
+ return isIdea(node) || isOneLinerIdea(node);
202
+ }
@@ -0,0 +1,76 @@
1
+ /**
2
+ * Shared helpers for the reference target union types.
3
+ */
4
+ import type { Reference } from 'langium';
5
+ import {
6
+ isFileReference,
7
+ isFileSymbolReference,
8
+ isLocalReference,
9
+ isQualifiedReference,
10
+ type IdeaDeclaration,
11
+ type Import,
12
+ type QualifiedReference,
13
+ type ReferenceTarget
14
+ } from './generated/ast.js';
15
+ import { unquoteReqlanString } from './reqlan-quoted-strings.js';
16
+
17
+ export function referenceImport(target: ReferenceTarget): Reference<Import> | undefined {
18
+ if (isQualifiedReference(target)) {
19
+ return target.path?.ref || target.qualifier?.ref ? (target.path ?? target.qualifier) : undefined;
20
+ }
21
+ return undefined;
22
+ }
23
+
24
+ export function referenceIdea(target: ReferenceTarget): Reference<IdeaDeclaration> | undefined {
25
+ if (isQualifiedReference(target) || isLocalReference(target)) {
26
+ return target.idea;
27
+ }
28
+ return undefined;
29
+ }
30
+
31
+ export function referenceFilePath(target: ReferenceTarget): string | undefined {
32
+ if (isFileReference(target) || isFileSymbolReference(target)) {
33
+ return target.file;
34
+ }
35
+ if (isQualifiedReference(target)) {
36
+ return qualifiedReferenceImportPath(target);
37
+ }
38
+ return undefined;
39
+ }
40
+
41
+ export function qualifiedReferenceImportPath(reference: QualifiedReference): string | undefined {
42
+ if (reference.qualifier?.ref) {
43
+ return reference.qualifier.ref.path;
44
+ }
45
+ if (reference.path?.ref) {
46
+ return reference.path.ref.path;
47
+ }
48
+ if (reference.path?.$refText) {
49
+ return unquoteReqlanString(reference.path.$refText);
50
+ }
51
+ return undefined;
52
+ }
53
+
54
+ export function isAnonymousQualifiedReference(reference: QualifiedReference): boolean {
55
+ return reference.path !== undefined && reference.path.ref === undefined && reference.qualifier === undefined;
56
+ }
57
+
58
+ export { unquoteReqlanString } from './reqlan-quoted-strings.js';
59
+
60
+ export interface ParsedMarkdownLink {
61
+ label: string;
62
+ target: string;
63
+ }
64
+
65
+ const MARKDOWN_LINK_PATTERN = /^\[([^\]]+)\]\(([^)]+)\)$/;
66
+
67
+ export function parseMarkdownLink(raw: string): ParsedMarkdownLink | undefined {
68
+ const match = MARKDOWN_LINK_PATTERN.exec(raw);
69
+ if (!match) {
70
+ return undefined;
71
+ }
72
+ return {
73
+ label: match[1]!,
74
+ target: match[2]!
75
+ };
76
+ }