@health-samurai/react-components 0.0.0-alpha.2 → 0.0.0-alpha.21

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 (571) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +102 -1
  3. package/dist/bundle.css +2349 -754
  4. package/dist/src/components/button-dropdown.d.ts +10 -0
  5. package/dist/src/components/button-dropdown.d.ts.map +1 -0
  6. package/dist/src/components/button-dropdown.js +70 -0
  7. package/dist/src/components/button-dropdown.js.map +1 -0
  8. package/dist/src/components/button-dropdown.stories.js +48 -0
  9. package/dist/src/components/button-dropdown.stories.js.map +1 -0
  10. package/dist/src/components/code-editor/fhir-autocomplete.d.ts +70 -0
  11. package/dist/src/components/code-editor/fhir-autocomplete.d.ts.map +1 -0
  12. package/dist/src/components/code-editor/fhir-autocomplete.js +1850 -0
  13. package/dist/src/components/code-editor/fhir-autocomplete.js.map +1 -0
  14. package/dist/src/components/code-editor/fhir-autocomplete.test.js +1099 -0
  15. package/dist/src/components/code-editor/fhir-autocomplete.test.js.map +1 -0
  16. package/dist/src/components/code-editor/http/grammar/http.d.ts +3 -0
  17. package/dist/src/components/code-editor/http/grammar/http.d.ts.map +1 -0
  18. package/dist/src/components/code-editor/http/grammar/http.grammar +74 -0
  19. package/dist/src/components/code-editor/http/grammar/http.js +38 -0
  20. package/dist/src/components/code-editor/http/grammar/http.js.map +1 -0
  21. package/dist/src/components/code-editor/http/grammar/http.terms.d.ts +2 -0
  22. package/dist/src/components/code-editor/http/grammar/http.terms.d.ts.map +1 -0
  23. package/dist/src/components/code-editor/http/grammar/http.terms.js +4 -0
  24. package/dist/src/components/code-editor/http/grammar/http.terms.js.map +1 -0
  25. package/dist/src/components/code-editor/http/grammar/http.test.js +80 -0
  26. package/dist/src/components/code-editor/http/grammar/http.test.js.map +1 -0
  27. package/dist/src/components/code-editor/http/index.d.ts +12 -0
  28. package/dist/src/components/code-editor/http/index.d.ts.map +1 -0
  29. package/dist/src/components/code-editor/http/index.js +486 -0
  30. package/dist/src/components/code-editor/http/index.js.map +1 -0
  31. package/dist/src/components/code-editor/index.d.ts +39 -1
  32. package/dist/src/components/code-editor/index.d.ts.map +1 -1
  33. package/dist/src/components/code-editor/index.js +1792 -45
  34. package/dist/src/components/code-editor/index.js.map +1 -1
  35. package/dist/src/components/code-editor/json-ast.d.ts +46 -0
  36. package/dist/src/components/code-editor/json-ast.d.ts.map +1 -0
  37. package/dist/src/components/code-editor/json-ast.js +465 -0
  38. package/dist/src/components/code-editor/json-ast.js.map +1 -0
  39. package/dist/src/components/code-editor/json-ast.test.js +206 -0
  40. package/dist/src/components/code-editor/json-ast.test.js.map +1 -0
  41. package/dist/src/components/code-editor/sql-completion.d.ts +22 -0
  42. package/dist/src/components/code-editor/sql-completion.d.ts.map +1 -0
  43. package/dist/src/components/code-editor/sql-completion.js +897 -0
  44. package/dist/src/components/code-editor/sql-completion.js.map +1 -0
  45. package/dist/src/components/code-editor.stories.js +280 -3
  46. package/dist/src/components/code-editor.stories.js.map +1 -1
  47. package/dist/src/components/copy-icon.d.ts +5 -1
  48. package/dist/src/components/copy-icon.d.ts.map +1 -1
  49. package/dist/src/components/copy-icon.js +41 -3
  50. package/dist/src/components/copy-icon.js.map +1 -1
  51. package/dist/src/components/data-table.d.ts +9 -0
  52. package/dist/src/components/data-table.d.ts.map +1 -0
  53. package/dist/src/components/data-table.js +66 -0
  54. package/dist/src/components/data-table.js.map +1 -0
  55. package/dist/src/components/data-table.stories.js +240 -0
  56. package/dist/src/components/data-table.stories.js.map +1 -0
  57. package/dist/src/components/date-picker-input.d.ts +10 -0
  58. package/dist/src/components/date-picker-input.d.ts.map +1 -0
  59. package/dist/src/components/date-picker-input.js +90 -0
  60. package/dist/src/components/date-picker-input.js.map +1 -0
  61. package/dist/src/components/date-picker-input.stories.js +76 -0
  62. package/dist/src/components/date-picker-input.stories.js.map +1 -0
  63. package/dist/src/components/fhir-structure-view.d.ts +34 -0
  64. package/dist/src/components/fhir-structure-view.d.ts.map +1 -0
  65. package/dist/src/components/fhir-structure-view.js +230 -0
  66. package/dist/src/components/fhir-structure-view.js.map +1 -0
  67. package/dist/src/components/fhir-structure-view.stories.js +447 -0
  68. package/dist/src/components/fhir-structure-view.stories.js.map +1 -0
  69. package/dist/src/components/icon-button.d.ts +12 -0
  70. package/dist/src/components/icon-button.d.ts.map +1 -0
  71. package/dist/src/components/icon-button.js +41 -0
  72. package/dist/src/components/icon-button.js.map +1 -0
  73. package/dist/src/components/icon-button.stories.js +157 -0
  74. package/dist/src/components/icon-button.stories.js.map +1 -0
  75. package/dist/src/components/operation-outcome-view.d.ts +27 -0
  76. package/dist/src/components/operation-outcome-view.d.ts.map +1 -0
  77. package/dist/src/components/operation-outcome-view.js +198 -0
  78. package/dist/src/components/operation-outcome-view.js.map +1 -0
  79. package/dist/src/components/operation-outcome-view.stories.js +207 -0
  80. package/dist/src/components/operation-outcome-view.stories.js.map +1 -0
  81. package/dist/src/components/request-line-editor.d.ts +13 -35
  82. package/dist/src/components/request-line-editor.d.ts.map +1 -1
  83. package/dist/src/components/request-line-editor.js +73 -49
  84. package/dist/src/components/request-line-editor.js.map +1 -1
  85. package/dist/src/components/request-line-editor.stories.js +17 -53
  86. package/dist/src/components/request-line-editor.stories.js.map +1 -1
  87. package/dist/src/components/sandbox.d.ts +13 -0
  88. package/dist/src/components/sandbox.d.ts.map +1 -0
  89. package/dist/src/components/sandbox.js +107 -0
  90. package/dist/src/components/sandbox.js.map +1 -0
  91. package/dist/src/components/sandbox.stories.js +126 -0
  92. package/dist/src/components/sandbox.stories.js.map +1 -0
  93. package/dist/src/components/segment-control.d.ts +13 -0
  94. package/dist/src/components/segment-control.d.ts.map +1 -0
  95. package/dist/src/components/segment-control.js +33 -0
  96. package/dist/src/components/segment-control.js.map +1 -0
  97. package/dist/src/components/segment-control.stories.js +68 -0
  98. package/dist/src/components/segment-control.stories.js.map +1 -0
  99. package/dist/src/components/split-button.d.ts +12 -0
  100. package/dist/src/components/split-button.d.ts.map +1 -0
  101. package/dist/src/components/split-button.js +33 -0
  102. package/dist/src/components/split-button.js.map +1 -0
  103. package/dist/src/components/split-button.stories.js +84 -0
  104. package/dist/src/components/split-button.stories.js.map +1 -0
  105. package/dist/src/components/tag.d.ts +16 -0
  106. package/dist/src/components/tag.d.ts.map +1 -0
  107. package/dist/src/components/tag.js +198 -0
  108. package/dist/src/components/tag.js.map +1 -0
  109. package/dist/src/components/tag.stories.js +459 -0
  110. package/dist/src/components/tag.stories.js.map +1 -0
  111. package/dist/src/components/tile.d.ts +15 -0
  112. package/dist/src/components/tile.d.ts.map +1 -0
  113. package/dist/src/components/tile.js +76 -0
  114. package/dist/src/components/tile.js.map +1 -0
  115. package/dist/src/components/tile.stories.js +167 -0
  116. package/dist/src/components/tile.stories.js.map +1 -0
  117. package/dist/src/components/toolbar.d.ts +18 -0
  118. package/dist/src/components/toolbar.d.ts.map +1 -0
  119. package/dist/src/components/toolbar.js +61 -0
  120. package/dist/src/components/toolbar.js.map +1 -0
  121. package/dist/src/components/toolbar.stories.js +69 -0
  122. package/dist/src/components/toolbar.stories.js.map +1 -0
  123. package/dist/src/components/tree-view.d.ts +47 -0
  124. package/dist/src/components/tree-view.d.ts.map +1 -0
  125. package/dist/src/components/tree-view.js +122 -0
  126. package/dist/src/components/tree-view.js.map +1 -0
  127. package/dist/src/components/tree-view.stories.js +283 -0
  128. package/dist/src/components/tree-view.stories.js.map +1 -0
  129. package/dist/src/icons.d.ts +11 -0
  130. package/dist/src/icons.d.ts.map +1 -0
  131. package/dist/src/icons.js +328 -0
  132. package/dist/src/icons.js.map +1 -0
  133. package/dist/src/index.css +358 -74
  134. package/dist/src/index.d.ts +17 -1
  135. package/dist/src/index.d.ts.map +1 -1
  136. package/dist/src/index.js +17 -1
  137. package/dist/src/index.js.map +1 -1
  138. package/dist/src/shadcn/components/ui/accordion.d.ts +2 -2
  139. package/dist/src/shadcn/components/ui/accordion.d.ts.map +1 -1
  140. package/dist/src/shadcn/components/ui/accordion.js +35 -9
  141. package/dist/src/shadcn/components/ui/accordion.js.map +1 -1
  142. package/dist/src/shadcn/components/ui/alert-dialog.d.ts +12 -4
  143. package/dist/src/shadcn/components/ui/alert-dialog.d.ts.map +1 -1
  144. package/dist/src/shadcn/components/ui/alert-dialog.js +128 -18
  145. package/dist/src/shadcn/components/ui/alert-dialog.js.map +1 -1
  146. package/dist/src/shadcn/components/ui/alert-dialog.stories.js +269 -19
  147. package/dist/src/shadcn/components/ui/alert-dialog.stories.js.map +1 -1
  148. package/dist/src/shadcn/components/ui/alert.d.ts +29 -6
  149. package/dist/src/shadcn/components/ui/alert.d.ts.map +1 -1
  150. package/dist/src/shadcn/components/ui/alert.js +50 -19
  151. package/dist/src/shadcn/components/ui/alert.js.map +1 -1
  152. package/dist/src/shadcn/components/ui/alert.stories.js +140 -36
  153. package/dist/src/shadcn/components/ui/alert.stories.js.map +1 -1
  154. package/dist/src/shadcn/components/ui/aspect-ratio.d.ts.map +1 -1
  155. package/dist/src/shadcn/components/ui/aspect-ratio.js +1 -0
  156. package/dist/src/shadcn/components/ui/aspect-ratio.js.map +1 -1
  157. package/dist/src/shadcn/components/ui/avatar.d.ts.map +1 -1
  158. package/dist/src/shadcn/components/ui/avatar.js +4 -3
  159. package/dist/src/shadcn/components/ui/avatar.js.map +1 -1
  160. package/dist/src/shadcn/components/ui/avatar.stories.js +68 -2
  161. package/dist/src/shadcn/components/ui/avatar.stories.js.map +1 -1
  162. package/dist/src/shadcn/components/ui/badge.d.ts +1 -1
  163. package/dist/src/shadcn/components/ui/badge.d.ts.map +1 -1
  164. package/dist/src/shadcn/components/ui/badge.js +16 -5
  165. package/dist/src/shadcn/components/ui/badge.js.map +1 -1
  166. package/dist/src/shadcn/components/ui/breadcrumb.d.ts +5 -2
  167. package/dist/src/shadcn/components/ui/breadcrumb.d.ts.map +1 -1
  168. package/dist/src/shadcn/components/ui/breadcrumb.js +98 -13
  169. package/dist/src/shadcn/components/ui/breadcrumb.js.map +1 -1
  170. package/dist/src/shadcn/components/ui/breadcrumb.stories.js +205 -45
  171. package/dist/src/shadcn/components/ui/breadcrumb.stories.js.map +1 -1
  172. package/dist/src/shadcn/components/ui/button.d.ts.map +1 -1
  173. package/dist/src/shadcn/components/ui/button.js +65 -11
  174. package/dist/src/shadcn/components/ui/button.js.map +1 -1
  175. package/dist/src/shadcn/components/ui/button.stories.js +99 -17
  176. package/dist/src/shadcn/components/ui/button.stories.js.map +1 -1
  177. package/dist/src/shadcn/components/ui/calendar.d.ts +1 -1
  178. package/dist/src/shadcn/components/ui/calendar.d.ts.map +1 -1
  179. package/dist/src/shadcn/components/ui/calendar.js +1 -0
  180. package/dist/src/shadcn/components/ui/calendar.js.map +1 -1
  181. package/dist/src/shadcn/components/ui/card.d.ts +5 -1
  182. package/dist/src/shadcn/components/ui/card.d.ts.map +1 -1
  183. package/dist/src/shadcn/components/ui/card.js +28 -7
  184. package/dist/src/shadcn/components/ui/card.js.map +1 -1
  185. package/dist/src/shadcn/components/ui/card.stories.js +23 -2
  186. package/dist/src/shadcn/components/ui/card.stories.js.map +1 -1
  187. package/dist/src/shadcn/components/ui/carousel.d.ts +1 -1
  188. package/dist/src/shadcn/components/ui/carousel.d.ts.map +1 -1
  189. package/dist/src/shadcn/components/ui/carousel.js +1 -0
  190. package/dist/src/shadcn/components/ui/carousel.js.map +1 -1
  191. package/dist/src/shadcn/components/ui/chart.d.ts +5 -5
  192. package/dist/src/shadcn/components/ui/chart.d.ts.map +1 -1
  193. package/dist/src/shadcn/components/ui/chart.js +4 -3
  194. package/dist/src/shadcn/components/ui/chart.js.map +1 -1
  195. package/dist/src/shadcn/components/ui/checkbox.d.ts +5 -1
  196. package/dist/src/shadcn/components/ui/checkbox.d.ts.map +1 -1
  197. package/dist/src/shadcn/components/ui/checkbox.js +46 -6
  198. package/dist/src/shadcn/components/ui/checkbox.js.map +1 -1
  199. package/dist/src/shadcn/components/ui/checkbox.stories.js +156 -46
  200. package/dist/src/shadcn/components/ui/checkbox.stories.js.map +1 -1
  201. package/dist/src/shadcn/components/ui/combobox.d.ts +29 -0
  202. package/dist/src/shadcn/components/ui/combobox.d.ts.map +1 -0
  203. package/dist/src/shadcn/components/ui/combobox.js +226 -0
  204. package/dist/src/shadcn/components/ui/combobox.js.map +1 -0
  205. package/dist/src/shadcn/components/ui/combobox.stories.js +167 -0
  206. package/dist/src/shadcn/components/ui/combobox.stories.js.map +1 -0
  207. package/dist/src/shadcn/components/ui/command.d.ts +4 -2
  208. package/dist/src/shadcn/components/ui/command.d.ts.map +1 -1
  209. package/dist/src/shadcn/components/ui/command.js +75 -13
  210. package/dist/src/shadcn/components/ui/command.js.map +1 -1
  211. package/dist/src/shadcn/components/ui/command.stories.js +277 -57
  212. package/dist/src/shadcn/components/ui/command.stories.js.map +1 -1
  213. package/dist/src/shadcn/components/ui/context-menu.d.ts +7 -3
  214. package/dist/src/shadcn/components/ui/context-menu.d.ts.map +1 -1
  215. package/dist/src/shadcn/components/ui/context-menu.js +120 -13
  216. package/dist/src/shadcn/components/ui/context-menu.js.map +1 -1
  217. package/dist/src/shadcn/components/ui/dialog.d.ts.map +1 -1
  218. package/dist/src/shadcn/components/ui/dialog.js +35 -7
  219. package/dist/src/shadcn/components/ui/dialog.js.map +1 -1
  220. package/dist/src/shadcn/components/ui/drawer.d.ts.map +1 -1
  221. package/dist/src/shadcn/components/ui/drawer.js +27 -5
  222. package/dist/src/shadcn/components/ui/drawer.js.map +1 -1
  223. package/dist/src/shadcn/components/ui/dropdown-menu.d.ts +7 -3
  224. package/dist/src/shadcn/components/ui/dropdown-menu.d.ts.map +1 -1
  225. package/dist/src/shadcn/components/ui/dropdown-menu.js +122 -14
  226. package/dist/src/shadcn/components/ui/dropdown-menu.js.map +1 -1
  227. package/dist/src/shadcn/components/ui/dropdown-menu.stories.js +22 -5
  228. package/dist/src/shadcn/components/ui/dropdown-menu.stories.js.map +1 -1
  229. package/dist/src/shadcn/components/ui/form.d.ts +2 -2
  230. package/dist/src/shadcn/components/ui/form.d.ts.map +1 -1
  231. package/dist/src/shadcn/components/ui/form.js +17 -8
  232. package/dist/src/shadcn/components/ui/form.js.map +1 -1
  233. package/dist/src/shadcn/components/ui/hover-card.d.ts.map +1 -1
  234. package/dist/src/shadcn/components/ui/hover-card.js +2 -1
  235. package/dist/src/shadcn/components/ui/hover-card.js.map +1 -1
  236. package/dist/src/shadcn/components/ui/input-otp.d.ts.map +1 -1
  237. package/dist/src/shadcn/components/ui/input-otp.js +1 -0
  238. package/dist/src/shadcn/components/ui/input-otp.js.map +1 -1
  239. package/dist/src/shadcn/components/ui/input.d.ts +3 -1
  240. package/dist/src/shadcn/components/ui/input.d.ts.map +1 -1
  241. package/dist/src/shadcn/components/ui/input.js +126 -17
  242. package/dist/src/shadcn/components/ui/input.js.map +1 -1
  243. package/dist/src/shadcn/components/ui/input.stories.js +218 -29
  244. package/dist/src/shadcn/components/ui/input.stories.js.map +1 -1
  245. package/dist/src/shadcn/components/ui/label.d.ts.map +1 -1
  246. package/dist/src/shadcn/components/ui/label.js +9 -1
  247. package/dist/src/shadcn/components/ui/label.js.map +1 -1
  248. package/dist/src/shadcn/components/ui/menubar.d.ts.map +1 -1
  249. package/dist/src/shadcn/components/ui/menubar.js +35 -13
  250. package/dist/src/shadcn/components/ui/menubar.js.map +1 -1
  251. package/dist/src/shadcn/components/ui/pagination.d.ts +9 -2
  252. package/dist/src/shadcn/components/ui/pagination.d.ts.map +1 -1
  253. package/dist/src/shadcn/components/ui/pagination.js +41 -24
  254. package/dist/src/shadcn/components/ui/pagination.js.map +1 -1
  255. package/dist/src/shadcn/components/ui/pagination.stories.js +44 -37
  256. package/dist/src/shadcn/components/ui/pagination.stories.js.map +1 -1
  257. package/dist/src/shadcn/components/ui/popover.d.ts.map +1 -1
  258. package/dist/src/shadcn/components/ui/popover.js +13 -1
  259. package/dist/src/shadcn/components/ui/popover.js.map +1 -1
  260. package/dist/src/shadcn/components/ui/progress.d.ts.map +1 -1
  261. package/dist/src/shadcn/components/ui/progress.js +6 -2
  262. package/dist/src/shadcn/components/ui/progress.js.map +1 -1
  263. package/dist/src/shadcn/components/ui/radio-button-group.d.ts +21 -0
  264. package/dist/src/shadcn/components/ui/radio-button-group.d.ts.map +1 -0
  265. package/dist/src/shadcn/components/ui/radio-button-group.js +148 -0
  266. package/dist/src/shadcn/components/ui/radio-button-group.js.map +1 -0
  267. package/dist/src/shadcn/components/ui/radio-button-group.stories.js +283 -0
  268. package/dist/src/shadcn/components/ui/radio-button-group.stories.js.map +1 -0
  269. package/dist/src/shadcn/components/ui/radio-group.d.ts +5 -1
  270. package/dist/src/shadcn/components/ui/radio-group.d.ts.map +1 -1
  271. package/dist/src/shadcn/components/ui/radio-group.js +40 -7
  272. package/dist/src/shadcn/components/ui/radio-group.js.map +1 -1
  273. package/dist/src/shadcn/components/ui/radio-group.stories.js +107 -32
  274. package/dist/src/shadcn/components/ui/radio-group.stories.js.map +1 -1
  275. package/dist/src/shadcn/components/ui/resizable.d.ts.map +1 -1
  276. package/dist/src/shadcn/components/ui/resizable.js +2 -1
  277. package/dist/src/shadcn/components/ui/resizable.js.map +1 -1
  278. package/dist/src/shadcn/components/ui/resizable.stories.js +2 -2
  279. package/dist/src/shadcn/components/ui/resizable.stories.js.map +1 -1
  280. package/dist/src/shadcn/components/ui/scroll-area.d.ts.map +1 -1
  281. package/dist/src/shadcn/components/ui/scroll-area.js +10 -3
  282. package/dist/src/shadcn/components/ui/scroll-area.js.map +1 -1
  283. package/dist/src/shadcn/components/ui/select.d.ts +1 -2
  284. package/dist/src/shadcn/components/ui/select.d.ts.map +1 -1
  285. package/dist/src/shadcn/components/ui/select.js +49 -19
  286. package/dist/src/shadcn/components/ui/select.js.map +1 -1
  287. package/dist/src/shadcn/components/ui/select.stories.js +193 -70
  288. package/dist/src/shadcn/components/ui/select.stories.js.map +1 -1
  289. package/dist/src/shadcn/components/ui/separator.d.ts.map +1 -1
  290. package/dist/src/shadcn/components/ui/separator.js +8 -1
  291. package/dist/src/shadcn/components/ui/separator.js.map +1 -1
  292. package/dist/src/shadcn/components/ui/sheet.js +1 -1
  293. package/dist/src/shadcn/components/ui/sheet.js.map +1 -1
  294. package/dist/src/shadcn/components/ui/sidebar.d.ts +4 -4
  295. package/dist/src/shadcn/components/ui/sidebar.d.ts.map +1 -1
  296. package/dist/src/shadcn/components/ui/sidebar.js +21 -6
  297. package/dist/src/shadcn/components/ui/sidebar.js.map +1 -1
  298. package/dist/src/shadcn/components/ui/skeleton.d.ts.map +1 -1
  299. package/dist/src/shadcn/components/ui/skeleton.js +3 -1
  300. package/dist/src/shadcn/components/ui/skeleton.js.map +1 -1
  301. package/dist/src/shadcn/components/ui/slider.d.ts.map +1 -1
  302. package/dist/src/shadcn/components/ui/slider.js +35 -4
  303. package/dist/src/shadcn/components/ui/slider.js.map +1 -1
  304. package/dist/src/shadcn/components/ui/sonner.d.ts +24 -2
  305. package/dist/src/shadcn/components/ui/sonner.d.ts.map +1 -1
  306. package/dist/src/shadcn/components/ui/sonner.js +127 -9
  307. package/dist/src/shadcn/components/ui/sonner.js.map +1 -1
  308. package/dist/src/shadcn/components/ui/sonner.stories.js +251 -12
  309. package/dist/src/shadcn/components/ui/sonner.stories.js.map +1 -1
  310. package/dist/src/shadcn/components/ui/switch.d.ts +7 -1
  311. package/dist/src/shadcn/components/ui/switch.d.ts.map +1 -1
  312. package/dist/src/shadcn/components/ui/switch.js +55 -3
  313. package/dist/src/shadcn/components/ui/switch.js.map +1 -1
  314. package/dist/src/shadcn/components/ui/switch.stories.js +84 -9
  315. package/dist/src/shadcn/components/ui/switch.stories.js.map +1 -1
  316. package/dist/src/shadcn/components/ui/table.d.ts +23 -6
  317. package/dist/src/shadcn/components/ui/table.d.ts.map +1 -1
  318. package/dist/src/shadcn/components/ui/table.js +65 -20
  319. package/dist/src/shadcn/components/ui/table.js.map +1 -1
  320. package/dist/src/shadcn/components/ui/table.stories.js +217 -97
  321. package/dist/src/shadcn/components/ui/table.stories.js.map +1 -1
  322. package/dist/src/shadcn/components/ui/tabs.d.ts +30 -5
  323. package/dist/src/shadcn/components/ui/tabs.d.ts.map +1 -1
  324. package/dist/src/shadcn/components/ui/tabs.js +470 -23
  325. package/dist/src/shadcn/components/ui/tabs.js.map +1 -1
  326. package/dist/src/shadcn/components/ui/tabs.stories.js +405 -181
  327. package/dist/src/shadcn/components/ui/tabs.stories.js.map +1 -1
  328. package/dist/src/shadcn/components/ui/textarea.d.ts +8 -1
  329. package/dist/src/shadcn/components/ui/textarea.d.ts.map +1 -1
  330. package/dist/src/shadcn/components/ui/textarea.js +30 -2
  331. package/dist/src/shadcn/components/ui/textarea.js.map +1 -1
  332. package/dist/src/shadcn/components/ui/textarea.stories.js +85 -4
  333. package/dist/src/shadcn/components/ui/textarea.stories.js.map +1 -1
  334. package/dist/src/shadcn/components/ui/toggle-group.d.ts +3 -3
  335. package/dist/src/shadcn/components/ui/toggle-group.d.ts.map +1 -1
  336. package/dist/src/shadcn/components/ui/toggle-group.js +14 -12
  337. package/dist/src/shadcn/components/ui/toggle-group.js.map +1 -1
  338. package/dist/src/shadcn/components/ui/toggle.d.ts +3 -4
  339. package/dist/src/shadcn/components/ui/toggle.d.ts.map +1 -1
  340. package/dist/src/shadcn/components/ui/toggle.js +44 -16
  341. package/dist/src/shadcn/components/ui/toggle.js.map +1 -1
  342. package/dist/src/shadcn/components/ui/toggle.stories.js +130 -7
  343. package/dist/src/shadcn/components/ui/toggle.stories.js.map +1 -1
  344. package/dist/src/shadcn/components/ui/tooltip.d.ts.map +1 -1
  345. package/dist/src/shadcn/components/ui/tooltip.js +12 -1
  346. package/dist/src/shadcn/components/ui/tooltip.js.map +1 -1
  347. package/dist/src/shadcn/components/ui/tree.d.ts +29 -0
  348. package/dist/src/shadcn/components/ui/tree.d.ts.map +1 -0
  349. package/dist/src/shadcn/components/ui/tree.js +135 -0
  350. package/dist/src/shadcn/components/ui/tree.js.map +1 -0
  351. package/dist/src/shadcn/shadcn.css +4 -4
  352. package/dist/src/tokens.css +50 -20
  353. package/dist/src/typography.css +78 -15
  354. package/package.json +84 -64
  355. package/src/components/button-dropdown.stories.tsx +41 -0
  356. package/src/components/button-dropdown.tsx +97 -0
  357. package/src/components/code-editor/fhir-autocomplete.test.ts +993 -0
  358. package/src/components/code-editor/fhir-autocomplete.ts +2322 -0
  359. package/src/components/code-editor/http/grammar/http.grammar +74 -0
  360. package/src/components/code-editor/http/grammar/http.terms.ts +9 -0
  361. package/src/components/code-editor/http/grammar/http.test.ts +110 -0
  362. package/src/components/code-editor/http/grammar/http.ts +21 -0
  363. package/src/components/code-editor/http/index.ts +424 -0
  364. package/src/components/code-editor/index.tsx +1944 -42
  365. package/src/components/code-editor/json-ast.test.ts +230 -0
  366. package/src/components/code-editor/json-ast.ts +590 -0
  367. package/src/components/code-editor/sql-completion.ts +1112 -0
  368. package/src/components/code-editor.stories.tsx +325 -2
  369. package/src/components/copy-icon.tsx +57 -3
  370. package/src/components/data-table.stories.tsx +91 -0
  371. package/src/components/data-table.tsx +126 -0
  372. package/src/components/date-picker-input.stories.tsx +79 -0
  373. package/src/components/date-picker-input.tsx +104 -0
  374. package/src/components/fhir-structure-view.stories.tsx +439 -0
  375. package/src/components/fhir-structure-view.tsx +233 -0
  376. package/src/components/icon-button.stories.tsx +86 -0
  377. package/src/components/icon-button.tsx +57 -0
  378. package/src/components/operation-outcome-view.stories.tsx +163 -0
  379. package/src/components/operation-outcome-view.tsx +254 -0
  380. package/src/components/request-line-editor.stories.tsx +17 -27
  381. package/src/components/request-line-editor.tsx +103 -61
  382. package/src/components/sandbox.stories.tsx +131 -0
  383. package/src/components/sandbox.tsx +191 -0
  384. package/src/components/segment-control.stories.tsx +61 -0
  385. package/src/components/segment-control.tsx +83 -0
  386. package/src/components/split-button.stories.tsx +68 -0
  387. package/src/components/split-button.tsx +74 -0
  388. package/src/components/tag.stories.tsx +371 -0
  389. package/src/components/tag.tsx +236 -0
  390. package/src/components/tile.stories.tsx +149 -0
  391. package/src/components/tile.tsx +105 -0
  392. package/src/components/toolbar.stories.tsx +64 -0
  393. package/src/components/toolbar.tsx +98 -0
  394. package/src/components/tree-view.stories.tsx +265 -0
  395. package/src/components/tree-view.tsx +246 -0
  396. package/src/icons.tsx +331 -0
  397. package/src/index.css +358 -74
  398. package/src/index.tsx +17 -3
  399. package/src/shadcn/components/ui/accordion.tsx +91 -10
  400. package/src/shadcn/components/ui/alert-dialog.stories.tsx +209 -15
  401. package/src/shadcn/components/ui/alert-dialog.tsx +236 -26
  402. package/src/shadcn/components/ui/alert.stories.tsx +120 -21
  403. package/src/shadcn/components/ui/alert.tsx +125 -28
  404. package/src/shadcn/components/ui/aspect-ratio.tsx +1 -0
  405. package/src/shadcn/components/ui/avatar.stories.tsx +74 -1
  406. package/src/shadcn/components/ui/avatar.tsx +22 -6
  407. package/src/shadcn/components/ui/badge.tsx +67 -18
  408. package/src/shadcn/components/ui/breadcrumb.stories.tsx +161 -41
  409. package/src/shadcn/components/ui/breadcrumb.tsx +172 -23
  410. package/src/shadcn/components/ui/button.stories.tsx +106 -18
  411. package/src/shadcn/components/ui/button.tsx +151 -55
  412. package/src/shadcn/components/ui/calendar.tsx +1 -0
  413. package/src/shadcn/components/ui/card.stories.tsx +17 -3
  414. package/src/shadcn/components/ui/card.tsx +89 -14
  415. package/src/shadcn/components/ui/carousel.tsx +1 -0
  416. package/src/shadcn/components/ui/chart.tsx +9 -5
  417. package/src/shadcn/components/ui/checkbox.stories.tsx +78 -30
  418. package/src/shadcn/components/ui/checkbox.tsx +91 -8
  419. package/src/shadcn/components/ui/combobox.stories.tsx +148 -0
  420. package/src/shadcn/components/ui/combobox.tsx +324 -0
  421. package/src/shadcn/components/ui/command.stories.tsx +184 -39
  422. package/src/shadcn/components/ui/command.tsx +218 -37
  423. package/src/shadcn/components/ui/context-menu.tsx +333 -40
  424. package/src/shadcn/components/ui/dialog.tsx +101 -13
  425. package/src/shadcn/components/ui/drawer.tsx +94 -18
  426. package/src/shadcn/components/ui/dropdown-menu.stories.tsx +18 -2
  427. package/src/shadcn/components/ui/dropdown-menu.tsx +334 -68
  428. package/src/shadcn/components/ui/form.tsx +22 -11
  429. package/src/shadcn/components/ui/hover-card.tsx +2 -1
  430. package/src/shadcn/components/ui/input-otp.tsx +1 -0
  431. package/src/shadcn/components/ui/input.stories.tsx +235 -27
  432. package/src/shadcn/components/ui/input.tsx +400 -29
  433. package/src/shadcn/components/ui/label.tsx +22 -4
  434. package/src/shadcn/components/ui/menubar.tsx +188 -43
  435. package/src/shadcn/components/ui/pagination.stories.tsx +8 -2
  436. package/src/shadcn/components/ui/pagination.tsx +65 -8
  437. package/src/shadcn/components/ui/popover.tsx +36 -4
  438. package/src/shadcn/components/ui/progress.tsx +21 -5
  439. package/src/shadcn/components/ui/radio-button-group.stories.tsx +247 -0
  440. package/src/shadcn/components/ui/radio-button-group.tsx +188 -0
  441. package/src/shadcn/components/ui/radio-group.stories.tsx +70 -14
  442. package/src/shadcn/components/ui/radio-group.tsx +85 -9
  443. package/src/shadcn/components/ui/resizable.stories.tsx +2 -2
  444. package/src/shadcn/components/ui/resizable.tsx +2 -1
  445. package/src/shadcn/components/ui/scroll-area.tsx +34 -5
  446. package/src/shadcn/components/ui/select.stories.tsx +108 -32
  447. package/src/shadcn/components/ui/select.tsx +182 -36
  448. package/src/shadcn/components/ui/separator.tsx +16 -5
  449. package/src/shadcn/components/ui/sheet.tsx +1 -1
  450. package/src/shadcn/components/ui/sidebar.tsx +69 -26
  451. package/src/shadcn/components/ui/skeleton.tsx +4 -1
  452. package/src/shadcn/components/ui/slider.tsx +83 -11
  453. package/src/shadcn/components/ui/sonner.stories.tsx +238 -17
  454. package/src/shadcn/components/ui/sonner.tsx +254 -11
  455. package/src/shadcn/components/ui/switch.stories.tsx +52 -5
  456. package/src/shadcn/components/ui/switch.tsx +92 -7
  457. package/src/shadcn/components/ui/table.stories.tsx +252 -72
  458. package/src/shadcn/components/ui/table.tsx +204 -26
  459. package/src/shadcn/components/ui/tabs.stories.tsx +235 -123
  460. package/src/shadcn/components/ui/tabs.tsx +694 -36
  461. package/src/shadcn/components/ui/textarea.stories.tsx +94 -2
  462. package/src/shadcn/components/ui/textarea.tsx +70 -5
  463. package/src/shadcn/components/ui/toggle-group.tsx +35 -13
  464. package/src/shadcn/components/ui/toggle.stories.tsx +92 -5
  465. package/src/shadcn/components/ui/toggle.tsx +96 -23
  466. package/src/shadcn/components/ui/tooltip.tsx +34 -8
  467. package/src/shadcn/components/ui/tree.tsx +257 -0
  468. package/src/shadcn/shadcn.css +4 -4
  469. package/src/tokens.css +50 -20
  470. package/src/typography.css +78 -15
  471. package/dist/src/components/code-editor.stories.d.ts +0 -7
  472. package/dist/src/components/code-editor.stories.d.ts.map +0 -1
  473. package/dist/src/components/request-line-editor.stories.d.ts +0 -11
  474. package/dist/src/components/request-line-editor.stories.d.ts.map +0 -1
  475. package/dist/src/index.stories.d.ts +0 -14
  476. package/dist/src/index.stories.d.ts.map +0 -1
  477. package/dist/src/index.stories.js +0 -19
  478. package/dist/src/index.stories.js.map +0 -1
  479. package/dist/src/shadcn/components/ui/accordion.stories.d.ts +0 -8
  480. package/dist/src/shadcn/components/ui/accordion.stories.d.ts.map +0 -1
  481. package/dist/src/shadcn/components/ui/alert-dialog.stories.d.ts +0 -8
  482. package/dist/src/shadcn/components/ui/alert-dialog.stories.d.ts.map +0 -1
  483. package/dist/src/shadcn/components/ui/alert.stories.d.ts +0 -8
  484. package/dist/src/shadcn/components/ui/alert.stories.d.ts.map +0 -1
  485. package/dist/src/shadcn/components/ui/aspect-ratio.stories.d.ts +0 -8
  486. package/dist/src/shadcn/components/ui/aspect-ratio.stories.d.ts.map +0 -1
  487. package/dist/src/shadcn/components/ui/avatar.stories.d.ts +0 -8
  488. package/dist/src/shadcn/components/ui/avatar.stories.d.ts.map +0 -1
  489. package/dist/src/shadcn/components/ui/badge.stories.d.ts +0 -8
  490. package/dist/src/shadcn/components/ui/badge.stories.d.ts.map +0 -1
  491. package/dist/src/shadcn/components/ui/breadcrumb.stories.d.ts +0 -8
  492. package/dist/src/shadcn/components/ui/breadcrumb.stories.d.ts.map +0 -1
  493. package/dist/src/shadcn/components/ui/button.stories.d.ts +0 -23
  494. package/dist/src/shadcn/components/ui/button.stories.d.ts.map +0 -1
  495. package/dist/src/shadcn/components/ui/calendar.stories.d.ts +0 -8
  496. package/dist/src/shadcn/components/ui/calendar.stories.d.ts.map +0 -1
  497. package/dist/src/shadcn/components/ui/card.stories.d.ts +0 -8
  498. package/dist/src/shadcn/components/ui/card.stories.d.ts.map +0 -1
  499. package/dist/src/shadcn/components/ui/carousel.stories.d.ts +0 -8
  500. package/dist/src/shadcn/components/ui/carousel.stories.d.ts.map +0 -1
  501. package/dist/src/shadcn/components/ui/chart.stories.d.ts +0 -8
  502. package/dist/src/shadcn/components/ui/chart.stories.d.ts.map +0 -1
  503. package/dist/src/shadcn/components/ui/checkbox.stories.d.ts +0 -8
  504. package/dist/src/shadcn/components/ui/checkbox.stories.d.ts.map +0 -1
  505. package/dist/src/shadcn/components/ui/collapsible.stories.d.ts +0 -8
  506. package/dist/src/shadcn/components/ui/collapsible.stories.d.ts.map +0 -1
  507. package/dist/src/shadcn/components/ui/command.stories.d.ts +0 -8
  508. package/dist/src/shadcn/components/ui/command.stories.d.ts.map +0 -1
  509. package/dist/src/shadcn/components/ui/context-menu.stories.d.ts +0 -8
  510. package/dist/src/shadcn/components/ui/context-menu.stories.d.ts.map +0 -1
  511. package/dist/src/shadcn/components/ui/dialog.stories.d.ts +0 -8
  512. package/dist/src/shadcn/components/ui/dialog.stories.d.ts.map +0 -1
  513. package/dist/src/shadcn/components/ui/drawer.stories.d.ts +0 -8
  514. package/dist/src/shadcn/components/ui/drawer.stories.d.ts.map +0 -1
  515. package/dist/src/shadcn/components/ui/dropdown-menu.stories.d.ts +0 -8
  516. package/dist/src/shadcn/components/ui/dropdown-menu.stories.d.ts.map +0 -1
  517. package/dist/src/shadcn/components/ui/form.stories.d.ts +0 -8
  518. package/dist/src/shadcn/components/ui/form.stories.d.ts.map +0 -1
  519. package/dist/src/shadcn/components/ui/hover-card.stories.d.ts +0 -8
  520. package/dist/src/shadcn/components/ui/hover-card.stories.d.ts.map +0 -1
  521. package/dist/src/shadcn/components/ui/input-otp.stories.d.ts +0 -8
  522. package/dist/src/shadcn/components/ui/input-otp.stories.d.ts.map +0 -1
  523. package/dist/src/shadcn/components/ui/input.stories.d.ts +0 -18
  524. package/dist/src/shadcn/components/ui/input.stories.d.ts.map +0 -1
  525. package/dist/src/shadcn/components/ui/label.stories.d.ts +0 -8
  526. package/dist/src/shadcn/components/ui/label.stories.d.ts.map +0 -1
  527. package/dist/src/shadcn/components/ui/menubar.stories.d.ts +0 -8
  528. package/dist/src/shadcn/components/ui/menubar.stories.d.ts.map +0 -1
  529. package/dist/src/shadcn/components/ui/navigation-menu.stories.d.ts +0 -8
  530. package/dist/src/shadcn/components/ui/navigation-menu.stories.d.ts.map +0 -1
  531. package/dist/src/shadcn/components/ui/pagination.stories.d.ts +0 -8
  532. package/dist/src/shadcn/components/ui/pagination.stories.d.ts.map +0 -1
  533. package/dist/src/shadcn/components/ui/popover.stories.d.ts +0 -8
  534. package/dist/src/shadcn/components/ui/popover.stories.d.ts.map +0 -1
  535. package/dist/src/shadcn/components/ui/progress.stories.d.ts +0 -8
  536. package/dist/src/shadcn/components/ui/progress.stories.d.ts.map +0 -1
  537. package/dist/src/shadcn/components/ui/radio-group.stories.d.ts +0 -8
  538. package/dist/src/shadcn/components/ui/radio-group.stories.d.ts.map +0 -1
  539. package/dist/src/shadcn/components/ui/resizable.stories.d.ts +0 -8
  540. package/dist/src/shadcn/components/ui/resizable.stories.d.ts.map +0 -1
  541. package/dist/src/shadcn/components/ui/scroll-area.stories.d.ts +0 -8
  542. package/dist/src/shadcn/components/ui/scroll-area.stories.d.ts.map +0 -1
  543. package/dist/src/shadcn/components/ui/select.stories.d.ts +0 -11
  544. package/dist/src/shadcn/components/ui/select.stories.d.ts.map +0 -1
  545. package/dist/src/shadcn/components/ui/separator.stories.d.ts +0 -8
  546. package/dist/src/shadcn/components/ui/separator.stories.d.ts.map +0 -1
  547. package/dist/src/shadcn/components/ui/sheet.stories.d.ts +0 -8
  548. package/dist/src/shadcn/components/ui/sheet.stories.d.ts.map +0 -1
  549. package/dist/src/shadcn/components/ui/sidebar.stories.d.ts +0 -11
  550. package/dist/src/shadcn/components/ui/sidebar.stories.d.ts.map +0 -1
  551. package/dist/src/shadcn/components/ui/skeleton.stories.d.ts +0 -8
  552. package/dist/src/shadcn/components/ui/skeleton.stories.d.ts.map +0 -1
  553. package/dist/src/shadcn/components/ui/slider.stories.d.ts +0 -8
  554. package/dist/src/shadcn/components/ui/slider.stories.d.ts.map +0 -1
  555. package/dist/src/shadcn/components/ui/sonner.stories.d.ts +0 -8
  556. package/dist/src/shadcn/components/ui/sonner.stories.d.ts.map +0 -1
  557. package/dist/src/shadcn/components/ui/switch.stories.d.ts +0 -8
  558. package/dist/src/shadcn/components/ui/switch.stories.d.ts.map +0 -1
  559. package/dist/src/shadcn/components/ui/table.stories.d.ts +0 -8
  560. package/dist/src/shadcn/components/ui/table.stories.d.ts.map +0 -1
  561. package/dist/src/shadcn/components/ui/tabs.stories.d.ts +0 -32
  562. package/dist/src/shadcn/components/ui/tabs.stories.d.ts.map +0 -1
  563. package/dist/src/shadcn/components/ui/textarea.stories.d.ts +0 -8
  564. package/dist/src/shadcn/components/ui/textarea.stories.d.ts.map +0 -1
  565. package/dist/src/shadcn/components/ui/toggle-group.stories.d.ts +0 -8
  566. package/dist/src/shadcn/components/ui/toggle-group.stories.d.ts.map +0 -1
  567. package/dist/src/shadcn/components/ui/toggle.stories.d.ts +0 -8
  568. package/dist/src/shadcn/components/ui/toggle.stories.d.ts.map +0 -1
  569. package/dist/src/shadcn/components/ui/tooltip.stories.d.ts +0 -8
  570. package/dist/src/shadcn/components/ui/tooltip.stories.d.ts.map +0 -1
  571. package/src/index.stories.tsx +0 -21
@@ -0,0 +1,1850 @@
1
+ import { completionStatus, startCompletion } from "@codemirror/autocomplete";
2
+ import { jsonLanguage } from "@codemirror/lang-json";
3
+ import { ensureSyntaxTree, syntaxTree } from "@codemirror/language";
4
+ import { RangeSet, StateEffect, StateField } from "@codemirror/state";
5
+ import { Decoration, EditorView, GutterMarker, gutterLineClass, ViewPlugin } from "@codemirror/view";
6
+ import { buildJsonDocumentContext, findRootJsonObject, walkJsonProperties } from "./json-ast.js";
7
+ // ── Constants ──────────────────────────────────────────────────────────
8
+ const PRIMITIVE_TYPES = new Set([
9
+ "boolean",
10
+ "integer",
11
+ "string",
12
+ "decimal",
13
+ "uri",
14
+ "url",
15
+ "canonical",
16
+ "base64Binary",
17
+ "instant",
18
+ "date",
19
+ "dateTime",
20
+ "time",
21
+ "code",
22
+ "oid",
23
+ "id",
24
+ "markdown",
25
+ "unsignedInt",
26
+ "positiveInt",
27
+ "uuid",
28
+ "xhtml"
29
+ ]);
30
+ function isPrimitiveType(typeCode) {
31
+ return PRIMITIVE_TYPES.has(typeCode) || typeCode.startsWith("http://hl7.org/fhirpath/System.");
32
+ }
33
+ const FHIR_STRING_TYPES = new Set([
34
+ "string",
35
+ "code",
36
+ "uri",
37
+ "url",
38
+ "canonical",
39
+ "id",
40
+ "markdown",
41
+ "oid",
42
+ "uuid",
43
+ "base64Binary",
44
+ "xhtml",
45
+ "http://hl7.org/fhirpath/System.String"
46
+ ]);
47
+ const FHIR_NUMBER_TYPES = new Set([
48
+ "boolean",
49
+ "integer",
50
+ "decimal",
51
+ "positiveInt",
52
+ "unsignedInt",
53
+ "http://hl7.org/fhirpath/System.Boolean",
54
+ "http://hl7.org/fhirpath/System.Integer",
55
+ "http://hl7.org/fhirpath/System.Decimal"
56
+ ]);
57
+ // ── Cache ──────────────────────────────────────────────────────────────
58
+ const sdCache = new Map();
59
+ const pendingRequests = new Map();
60
+ const listCache = new Map();
61
+ const pendingListRequests = new Map();
62
+ const SD_ELEMENTS = "differential,type,name,baseDefinition,url,context";
63
+ function cacheKey(params) {
64
+ return JSON.stringify(params);
65
+ }
66
+ async function getCachedSDList(params, getSDs) {
67
+ const key = cacheKey(params);
68
+ if (listCache.has(key)) return listCache.get(key) ?? [];
69
+ let pending = pendingListRequests.get(key);
70
+ if (!pending) {
71
+ pending = getSDs(params).then((list)=>{
72
+ listCache.set(key, list);
73
+ pendingListRequests.delete(key);
74
+ for (const sd of list){
75
+ if (sd.differential?.element) {
76
+ sdCache.set(sd.type, sd);
77
+ }
78
+ }
79
+ return list;
80
+ }).catch(()=>{
81
+ pendingListRequests.delete(key);
82
+ listCache.set(key, []);
83
+ return [];
84
+ });
85
+ pendingListRequests.set(key, pending);
86
+ }
87
+ return pending;
88
+ }
89
+ async function getCachedSD(type, getSDs) {
90
+ if (sdCache.has(type)) return sdCache.get(type) ?? null;
91
+ const key = `single:${type}`;
92
+ let pending = pendingRequests.get(key);
93
+ if (!pending) {
94
+ const isUrl = type.includes("/");
95
+ const searchByType = (params)=>getSDs(params).then((list)=>list[0] ?? null);
96
+ pending = (isUrl ? searchByType({
97
+ url: type,
98
+ _elements: SD_ELEMENTS,
99
+ _count: "1"
100
+ }) : searchByType({
101
+ type,
102
+ derivation: "specialization",
103
+ _elements: SD_ELEMENTS,
104
+ _count: "1"
105
+ }).then((sd)=>sd ?? searchByType({
106
+ type,
107
+ "derivation:missing": "true",
108
+ _elements: SD_ELEMENTS,
109
+ _count: "1"
110
+ }))).then((sd)=>{
111
+ sdCache.set(type, sd);
112
+ pendingRequests.delete(key);
113
+ return sd;
114
+ }).catch(()=>{
115
+ pendingRequests.delete(key);
116
+ return null;
117
+ });
118
+ pendingRequests.set(key, pending);
119
+ }
120
+ return pending;
121
+ }
122
+ // ── Element helpers ────────────────────────────────────────────────────
123
+ function fieldName(element) {
124
+ const parts = element.path.split(".");
125
+ return (parts[parts.length - 1] ?? "").replace("[x]", "");
126
+ }
127
+ function directChildren(elements, parentPath) {
128
+ const prefix = `${parentPath}.`;
129
+ return elements.filter((el)=>{
130
+ if (!el.path.startsWith(prefix)) return false;
131
+ const rest = el.path.slice(prefix.length);
132
+ return !rest.includes(".");
133
+ });
134
+ }
135
+ function findElement(elements, parentPath, key) {
136
+ const direct = elements.find((el)=>{
137
+ if (!el.path.startsWith(`${parentPath}.`)) return false;
138
+ const name = fieldName(el);
139
+ return name === key || name.toLowerCase() === key.toLowerCase();
140
+ });
141
+ if (direct) return direct;
142
+ for (const el of elements){
143
+ if (!el.path.endsWith("[x]")) continue;
144
+ if (!el.path.startsWith(`${parentPath}.`)) continue;
145
+ const baseName = fieldName(el);
146
+ if (!key.toLowerCase().startsWith(baseName.toLowerCase())) continue;
147
+ const typeSuffix = key.slice(baseName.length).toLowerCase();
148
+ const matchedType = el.type?.find((t)=>t.code.toLowerCase() === typeSuffix);
149
+ if (matchedType) {
150
+ return {
151
+ ...el,
152
+ type: [
153
+ matchedType
154
+ ]
155
+ };
156
+ }
157
+ }
158
+ return undefined;
159
+ }
160
+ // ── Resolve completions at path ────────────────────────────────────────
161
+ async function collectAllElements(type, getSDs) {
162
+ const sd = await getCachedSD(type, getSDs);
163
+ if (!sd?.differential?.element) return null;
164
+ const elements = [
165
+ ...sd.differential.element
166
+ ];
167
+ if (sd.baseDefinition) {
168
+ const base = await collectAllElements(sd.baseDefinition, getSDs);
169
+ if (base) {
170
+ for (const baseEl of base.elements){
171
+ const remappedPath = baseEl.path.replace(new RegExp(`^${base.basePath}`), sd.type);
172
+ if (!elements.some((e)=>e.path === remappedPath)) {
173
+ elements.push({
174
+ ...baseEl,
175
+ path: remappedPath
176
+ });
177
+ }
178
+ }
179
+ }
180
+ }
181
+ return {
182
+ elements,
183
+ basePath: sd.type
184
+ };
185
+ }
186
+ async function resolveElements(path, resourceType, getSDs) {
187
+ const result = await collectAllElements(resourceType, getSDs);
188
+ if (!result) return [];
189
+ let currentPath = resourceType;
190
+ let currentElements = result.elements;
191
+ for (const key of path){
192
+ if (key === "resourceType") return [];
193
+ const el = findElement(currentElements, currentPath, key);
194
+ if (!el) return [];
195
+ if (el.contentReference) {
196
+ currentPath = el.contentReference.replace(/^#/, "");
197
+ continue;
198
+ }
199
+ if (!el.type?.[0]) return [];
200
+ const typeCode = el.type[0].code;
201
+ if (typeCode === "BackboneElement") {
202
+ currentPath = el.path;
203
+ continue;
204
+ }
205
+ const typeResult = await collectAllElements(typeCode, getSDs);
206
+ if (!typeResult) return [];
207
+ currentPath = typeResult.basePath;
208
+ currentElements = typeResult.elements;
209
+ }
210
+ const children = directChildren(currentElements, currentPath);
211
+ const expanded = [];
212
+ for (const el of children){
213
+ const isChoiceType = el.path.endsWith("[x]");
214
+ if (isChoiceType && el.type && el.type.length > 0) {
215
+ for (const t of el.type){
216
+ expanded.push({
217
+ ...el,
218
+ path: el.path.replace("[x]", t.code.charAt(0).toUpperCase() + t.code.slice(1)),
219
+ type: [
220
+ t
221
+ ]
222
+ });
223
+ }
224
+ } else {
225
+ expanded.push(el);
226
+ }
227
+ }
228
+ return expanded;
229
+ }
230
+ async function findResourceBoundary(path, resourceType, getSDs) {
231
+ if (path.length === 0) return null;
232
+ const result = await collectAllElements(resourceType, getSDs);
233
+ if (!result) return null;
234
+ let currentPath = resourceType;
235
+ let currentElements = result.elements;
236
+ for(let i = 0; i < path.length; i++){
237
+ const key = path[i];
238
+ if (key === "resourceType") return null;
239
+ const el = findElement(currentElements, currentPath, key);
240
+ if (!el) return null;
241
+ if (el.type?.some((t)=>t.code === "Resource")) {
242
+ return i;
243
+ }
244
+ if (el.contentReference) {
245
+ currentPath = el.contentReference.replace(/^#/, "");
246
+ continue;
247
+ }
248
+ if (!el.type?.[0]) return null;
249
+ const typeCode = el.type[0].code;
250
+ if (typeCode === "BackboneElement") {
251
+ currentPath = el.path;
252
+ continue;
253
+ }
254
+ const typeResult = await collectAllElements(typeCode, getSDs);
255
+ if (!typeResult) return null;
256
+ currentPath = typeResult.basePath;
257
+ currentElements = typeResult.elements;
258
+ }
259
+ return null;
260
+ }
261
+ function snippetKind(element) {
262
+ const isArray = element.max === "*";
263
+ const typeCode = element.type?.[0]?.code;
264
+ if (!typeCode) {
265
+ if (element.contentReference) return isArray ? "array-complex" : "object";
266
+ return "bare";
267
+ }
268
+ if (typeCode === "Extension" && isArray) return "array-extension";
269
+ if (isArray) return isPrimitiveType(typeCode) ? "array-primitive" : "array-complex";
270
+ if (FHIR_NUMBER_TYPES.has(typeCode)) return "number";
271
+ if (isPrimitiveType(typeCode)) return "string";
272
+ return "object";
273
+ }
274
+ function buildSnippet(name, kind, indent) {
275
+ const inner = `${indent} `;
276
+ const innerInner = `${inner} `;
277
+ switch(kind){
278
+ case "array-complex":
279
+ {
280
+ const text = `"${name}": [\n${inner}{\n${innerInner}\n${inner}}\n${indent}]`;
281
+ return {
282
+ text,
283
+ cursorOffset: text.indexOf(innerInner) + innerInner.length
284
+ };
285
+ }
286
+ case "array-extension":
287
+ {
288
+ const text = `"${name}": [\n${inner}{\n${innerInner}"url": ""\n${inner}}\n${indent}]`;
289
+ return {
290
+ text,
291
+ cursorOffset: text.lastIndexOf('""') + 1
292
+ };
293
+ }
294
+ case "array-primitive":
295
+ {
296
+ const text = `"${name}": [\n${inner}\n${indent}]`;
297
+ return {
298
+ text,
299
+ cursorOffset: text.indexOf(`${inner}\n`) + inner.length
300
+ };
301
+ }
302
+ case "object":
303
+ {
304
+ const text = `"${name}": {\n${inner}\n${indent}}`;
305
+ return {
306
+ text,
307
+ cursorOffset: text.indexOf(`${inner}\n`) + inner.length
308
+ };
309
+ }
310
+ case "string":
311
+ {
312
+ const text = `"${name}": ""`;
313
+ return {
314
+ text,
315
+ cursorOffset: text.length - 1
316
+ };
317
+ }
318
+ default:
319
+ {
320
+ const text = `"${name}": `;
321
+ return {
322
+ text,
323
+ cursorOffset: text.length
324
+ };
325
+ }
326
+ }
327
+ }
328
+ function toCompletion(element) {
329
+ const name = fieldName(element);
330
+ const types = element.type?.map((t)=>t.code).join(" | ") ?? "";
331
+ const kind = snippetKind(element);
332
+ const completion = {
333
+ label: name,
334
+ type: "property",
335
+ detail: types,
336
+ boost: element.min && element.min > 0 ? 2 : 0,
337
+ apply: (view, _completion, from, to)=>{
338
+ const doc = view.state.doc.toString();
339
+ let actualFrom = from;
340
+ let actualTo = to;
341
+ if (actualFrom > 0 && doc[actualFrom - 1] === '"') actualFrom--;
342
+ if (actualTo < doc.length && doc[actualTo] === '"') actualTo++;
343
+ const afterName = doc.slice(actualTo).match(/^\s*:/);
344
+ if (afterName) {
345
+ const insert = `"${name}"`;
346
+ view.dispatch({
347
+ changes: {
348
+ from: actualFrom,
349
+ to: actualTo,
350
+ insert
351
+ },
352
+ selection: {
353
+ anchor: actualFrom + insert.length
354
+ }
355
+ });
356
+ return;
357
+ }
358
+ const line = view.state.doc.lineAt(actualFrom);
359
+ const lineText = line.text;
360
+ const indent = lineText.match(/^(\s*)/)?.[1] ?? "";
361
+ const { text, cursorOffset } = buildSnippet(name, kind, indent);
362
+ view.dispatch({
363
+ changes: {
364
+ from: actualFrom,
365
+ to: actualTo,
366
+ insert: text
367
+ },
368
+ selection: {
369
+ anchor: actualFrom + cursorOffset
370
+ }
371
+ });
372
+ if (kind === "string" || kind === "number" || kind === "array-primitive" || kind === "array-extension") {
373
+ setTimeout(()=>startCompletion(view), 0);
374
+ }
375
+ }
376
+ };
377
+ if (element.short) completion.info = element.short;
378
+ return completion;
379
+ }
380
+ function toParameterPropertyCompletion(element) {
381
+ const name = fieldName(element);
382
+ if (name !== "parameter" && name !== "part") return toCompletion(element);
383
+ const types = element.type?.map((t)=>t.code).join(" | ") ?? "";
384
+ const completion = {
385
+ label: name,
386
+ type: "property",
387
+ detail: types,
388
+ boost: element.min && element.min > 0 ? 2 : 0,
389
+ apply: (view, _completion, from, to)=>{
390
+ const doc = view.state.doc.toString();
391
+ let actualFrom = from;
392
+ let actualTo = to;
393
+ if (actualFrom > 0 && doc[actualFrom - 1] === '"') actualFrom--;
394
+ if (actualTo < doc.length && doc[actualTo] === '"') actualTo++;
395
+ const afterName = doc.slice(actualTo).match(/^\s*:/);
396
+ if (afterName) {
397
+ const insert = `"${name}"`;
398
+ view.dispatch({
399
+ changes: {
400
+ from: actualFrom,
401
+ to: actualTo,
402
+ insert
403
+ },
404
+ selection: {
405
+ anchor: actualFrom + insert.length
406
+ }
407
+ });
408
+ return;
409
+ }
410
+ const line = view.state.doc.lineAt(actualFrom);
411
+ const indent = line.text.match(/^(\s*)/)?.[1] ?? "";
412
+ const inner = `${indent} `;
413
+ const innerInner = `${inner} `;
414
+ const text = `"${name}": [\n${inner}{\n${innerInner}"name": ""\n${inner}}\n${indent}]`;
415
+ view.dispatch({
416
+ changes: {
417
+ from: actualFrom,
418
+ to: actualTo,
419
+ insert: text
420
+ },
421
+ selection: {
422
+ anchor: actualFrom + text.lastIndexOf('""') + 1
423
+ }
424
+ });
425
+ setTimeout(()=>startCompletion(view), 0);
426
+ }
427
+ };
428
+ if (element.short) completion.info = element.short;
429
+ return completion;
430
+ }
431
+ function elementsToCompletions(elements, mapFn) {
432
+ const completions = [];
433
+ for (const el of elements){
434
+ completions.push(mapFn(el));
435
+ const name = fieldName(el);
436
+ const firstTypeCode = el.type?.[0]?.code;
437
+ if (el.type?.length === 1 && firstTypeCode && PRIMITIVE_TYPES.has(firstTypeCode)) {
438
+ const ext = {
439
+ label: `_${name}`,
440
+ type: "property",
441
+ detail: "Element",
442
+ boost: -1
443
+ };
444
+ ext.info = "Primitive element extension";
445
+ completions.push(ext);
446
+ }
447
+ }
448
+ return completions;
449
+ }
450
+ function analyzeExtensionSD(sd) {
451
+ if (!sd.differential?.element) return null;
452
+ const elements = sd.differential.element;
453
+ const valueEl = elements.find((e)=>e.path === "Extension.value[x]");
454
+ const isNested = valueEl?.max === "0";
455
+ const valueTypes = isNested ? [] : valueEl?.type?.map((t)=>t.code) ?? [];
456
+ const slices = [];
457
+ for (const el of elements){
458
+ if (el.path === "Extension.extension" && el.sliceName) {
459
+ const sliceName = el.sliceName;
460
+ const urlEl = elements.find((e)=>e.path === "Extension.extension.url" && e.fixedUri && elements.indexOf(e) > elements.indexOf(el));
461
+ const fixedUri = urlEl?.fixedUri ?? sliceName;
462
+ slices.push({
463
+ sliceName,
464
+ fixedUri,
465
+ short: el.short
466
+ });
467
+ }
468
+ }
469
+ return {
470
+ url: sd.url ?? sd.type,
471
+ name: sd.name,
472
+ isNested,
473
+ valueTypes,
474
+ slices
475
+ };
476
+ }
477
+ // ── Parameters slice helpers ────────────────────────────────────────────
478
+ const parametersTypeCache = new Map();
479
+ async function isParametersType(resourceType, getSDs) {
480
+ if (resourceType === "Parameters") return true;
481
+ if (parametersTypeCache.has(resourceType)) return parametersTypeCache.get(resourceType);
482
+ const sd = await getCachedSD(resourceType, getSDs);
483
+ if (!sd?.baseDefinition) {
484
+ parametersTypeCache.set(resourceType, false);
485
+ return false;
486
+ }
487
+ const baseType = sd.baseDefinition.split("/").pop()?.split("|")[0] ?? "";
488
+ const result = await isParametersType(baseType, getSDs);
489
+ parametersTypeCache.set(resourceType, result);
490
+ return result;
491
+ }
492
+ async function getParameterSlices(profileUrls, getSDs) {
493
+ const slices = [];
494
+ for (const profileUrl of profileUrls){
495
+ const sd = await getCachedSD(profileUrl, getSDs);
496
+ if (!sd?.differential?.element) continue;
497
+ const elements = sd.differential.element;
498
+ // Find the parameter path dynamically: "X.parameter" where X is the profile's type
499
+ const paramPath = `${sd.type}.parameter`;
500
+ let current = null;
501
+ const flush = ()=>{
502
+ if (current?.fixedName) {
503
+ const s = {
504
+ sliceName: current.sliceName,
505
+ fixedName: current.fixedName,
506
+ min: current.min,
507
+ max: current.max,
508
+ valueTypes: current.valueTypes
509
+ };
510
+ if (current.short != null) s.short = current.short;
511
+ slices.push(s);
512
+ }
513
+ };
514
+ for (const el of elements){
515
+ if (el.path === paramPath && el.sliceName) {
516
+ flush();
517
+ current = {
518
+ sliceName: el.sliceName,
519
+ min: el.min ?? 0,
520
+ max: el.max ?? "*",
521
+ fixedName: null,
522
+ valueTypes: [],
523
+ short: el.short
524
+ };
525
+ continue;
526
+ }
527
+ if (!current) continue;
528
+ if (el.path === `${paramPath}.name` && el.fixedString) {
529
+ current.fixedName = el.fixedString;
530
+ }
531
+ if (el.path === `${paramPath}.value[x]` && el.type) {
532
+ current.valueTypes = el.type.map((t)=>t.code);
533
+ }
534
+ }
535
+ flush();
536
+ }
537
+ return slices;
538
+ }
539
+ // ── Fixed value helpers ────────────────────────────────────────────────
540
+ async function getFixedValues(effectivePath, valueKey, resourceType, profileUrls, getSDs) {
541
+ for (const profileUrl of profileUrls){
542
+ const sd = await getCachedSD(profileUrl, getSDs);
543
+ if (!sd?.differential?.element) continue;
544
+ const fhirPath = `${resourceType}.${[
545
+ ...effectivePath,
546
+ valueKey
547
+ ].join(".")}`;
548
+ for (const el of sd.differential.element){
549
+ if (el.path !== fhirPath) continue;
550
+ if (el.fixedString != null) return el.fixedString;
551
+ if (el.fixedUri != null) return el.fixedUri;
552
+ if (el.fixedCode != null) return el.fixedCode;
553
+ }
554
+ }
555
+ return null;
556
+ }
557
+ /** @internal — exported for tests only */ export function buildParameterSnippet(name, valueTypes, indent) {
558
+ const inner = `${indent} `;
559
+ if (valueTypes.length === 1 && FHIR_STRING_TYPES.has(valueTypes[0])) {
560
+ const tc = valueTypes[0];
561
+ const vf = `value${tc.charAt(0).toUpperCase()}${tc.slice(1)}`;
562
+ const text = `{\n${inner}"name": "${name}",\n${inner}"${vf}": ""\n${indent}}`;
563
+ return {
564
+ text,
565
+ cursorOffset: text.lastIndexOf('""') + 1
566
+ };
567
+ }
568
+ if (valueTypes.length === 1 && FHIR_NUMBER_TYPES.has(valueTypes[0])) {
569
+ const tc = valueTypes[0];
570
+ const vf = `value${tc.charAt(0).toUpperCase()}${tc.slice(1)}`;
571
+ const text = `{\n${inner}"name": "${name}",\n${inner}"${vf}": \n${indent}}`;
572
+ return {
573
+ text,
574
+ cursorOffset: text.indexOf(`"${vf}": \n`) + `"${vf}": `.length
575
+ };
576
+ }
577
+ if (valueTypes.length === 1) {
578
+ const tc = valueTypes[0];
579
+ const vf = `value${tc.charAt(0).toUpperCase()}${tc.slice(1)}`;
580
+ const innerInner = `${inner} `;
581
+ const text = `{\n${inner}"name": "${name}",\n${inner}"${vf}": {\n${innerInner}\n${inner}}\n${indent}}`;
582
+ return {
583
+ text,
584
+ cursorOffset: text.indexOf(`${innerInner}\n${inner}}`) + innerInner.length
585
+ };
586
+ }
587
+ // Default to valueString when no value type constraint
588
+ const text = `{\n${inner}"name": "${name}",\n${inner}"valueString": ""\n${indent}}`;
589
+ if (name === "") {
590
+ // Generic template: cursor in name
591
+ return {
592
+ text,
593
+ cursorOffset: text.indexOf('""') + 1
594
+ };
595
+ }
596
+ return {
597
+ text,
598
+ cursorOffset: text.lastIndexOf('""') + 1
599
+ };
600
+ }
601
+ // ── Binding & Reference Resolution ─────────────────────────────────────
602
+ function buildFhirElementPath(resourceType, path, valueKey) {
603
+ return `${resourceType}.${[
604
+ ...path,
605
+ valueKey
606
+ ].join(".")}`;
607
+ }
608
+ async function findProfileBinding(profileUrls, resourceType, path, valueKey, getSDs) {
609
+ if (profileUrls.length === 0) return null;
610
+ for (const profileUrl of profileUrls){
611
+ const sd = await getCachedSD(profileUrl, getSDs);
612
+ if (!sd?.differential?.element) continue;
613
+ const directPath = buildFhirElementPath(resourceType, path, valueKey);
614
+ for (const el of sd.differential.element){
615
+ if (el.path === directPath && el.binding?.valueSet) {
616
+ return el.binding.valueSet;
617
+ }
618
+ }
619
+ if (valueKey === "code") {
620
+ for(let i = path.length; i > 0; i--){
621
+ const parentFhirPath = buildFhirElementPath(resourceType, path.slice(0, i - 1), path[i - 1]);
622
+ for (const el of sd.differential.element){
623
+ if (el.path === parentFhirPath && el.binding?.valueSet) {
624
+ return el.binding.valueSet;
625
+ }
626
+ }
627
+ }
628
+ }
629
+ }
630
+ return null;
631
+ }
632
+ async function findExtensionBinding(doc, pos, getSDs) {
633
+ const textBefore = doc.slice(0, pos);
634
+ const urlMatches = [
635
+ ...textBefore.matchAll(/"url"\s*:\s*"([^"]+)"/g)
636
+ ];
637
+ if (urlMatches.length === 0) return null;
638
+ for(let i = urlMatches.length - 1; i >= 0; i--){
639
+ const extUrl = urlMatches[i][1];
640
+ if (!extUrl.includes("StructureDefinition/") && !extUrl.includes("Extension")) {
641
+ const parentUrlMatches = [
642
+ ...textBefore.slice(0, urlMatches[i]?.index).matchAll(/"url"\s*:\s*"([^"]+)"/g)
643
+ ];
644
+ for(let j = parentUrlMatches.length - 1; j >= 0; j--){
645
+ const parentUrl = parentUrlMatches[j][1];
646
+ if (!parentUrl.includes("/")) continue;
647
+ const parentSD = await getCachedSD(parentUrl, getSDs);
648
+ if (!parentSD?.differential?.element) continue;
649
+ let inSlice = false;
650
+ for (const el of parentSD.differential.element){
651
+ if (el.path === "Extension.extension" && el.sliceName) {
652
+ const urlEl = parentSD.differential.element.find((e)=>e.path === "Extension.extension.url" && e.fixedUri && parentSD.differential.element.indexOf(e) > parentSD.differential.element.indexOf(el));
653
+ if ((urlEl?.fixedUri ?? el.sliceName) === extUrl) {
654
+ inSlice = true;
655
+ continue;
656
+ }
657
+ if (inSlice) break;
658
+ }
659
+ if (inSlice && el.path === "Extension.extension.value[x]" && el.binding?.valueSet) {
660
+ return el.binding.valueSet;
661
+ }
662
+ }
663
+ if (inSlice) break;
664
+ }
665
+ continue;
666
+ }
667
+ const sd = await getCachedSD(extUrl, getSDs);
668
+ if (!sd?.differential?.element) continue;
669
+ for (const el of sd.differential.element){
670
+ if (el.path === "Extension.value[x]" && el.binding?.valueSet) {
671
+ return el.binding.valueSet;
672
+ }
673
+ }
674
+ }
675
+ return null;
676
+ }
677
+ async function findBindingForValue(path, valueKey, resourceType, getSDs, profileUrls = [], doc, pos) {
678
+ if (doc != null && pos != null) {
679
+ const inExtension = path.some((p)=>p === "extension" || p === "modifierExtension");
680
+ if (inExtension) {
681
+ const extBinding = await findExtensionBinding(doc, pos, getSDs);
682
+ if (extBinding) return extBinding;
683
+ }
684
+ }
685
+ const profileBinding = await findProfileBinding(profileUrls, resourceType, path, valueKey, getSDs);
686
+ if (profileBinding) return profileBinding;
687
+ const elements = await resolveElements(path, resourceType, getSDs);
688
+ for (const el of elements){
689
+ if (fieldName(el) === valueKey && el.binding?.valueSet) {
690
+ return el.binding.valueSet;
691
+ }
692
+ }
693
+ if (valueKey === "code") {
694
+ for(let i = path.length; i > 0; i--){
695
+ const parentElements = await resolveElements(path.slice(0, i - 1), resourceType, getSDs);
696
+ for (const el of parentElements){
697
+ if (fieldName(el) === path[i - 1] && el.binding?.valueSet) {
698
+ return el.binding.valueSet;
699
+ }
700
+ }
701
+ }
702
+ }
703
+ return null;
704
+ }
705
+ async function findCanonicalTargetType(path, arrayKey, resourceType, getSDs) {
706
+ const elements = await resolveElements(path, resourceType, getSDs);
707
+ for (const el of elements){
708
+ if (fieldName(el) !== arrayKey) continue;
709
+ if (el.max !== "*") continue;
710
+ const t = el.type?.[0];
711
+ if (t?.code !== "canonical" || !t.targetProfile?.length) continue;
712
+ return t.targetProfile[0]?.split("/").pop() ?? null;
713
+ }
714
+ return null;
715
+ }
716
+ async function resolveReferenceTargets(path, resourceType, getSDs) {
717
+ const result = await collectAllElements(resourceType, getSDs);
718
+ if (!result) return null;
719
+ let currentPath = resourceType;
720
+ let currentElements = result.elements;
721
+ for(let i = 0; i < path.length - 1; i++){
722
+ const key = path[i];
723
+ if (key === "resourceType") return null;
724
+ const el = findElement(currentElements, currentPath, key);
725
+ if (!el) return null;
726
+ if (el.contentReference) {
727
+ currentPath = el.contentReference.replace(/^#/, "");
728
+ continue;
729
+ }
730
+ if (!el.type?.[0]) return null;
731
+ const typeCode = el.type[0].code;
732
+ if (typeCode === "BackboneElement") {
733
+ currentPath = el.path;
734
+ continue;
735
+ }
736
+ const typeResult = await collectAllElements(typeCode, getSDs);
737
+ if (!typeResult) return null;
738
+ currentPath = typeResult.basePath;
739
+ currentElements = typeResult.elements;
740
+ }
741
+ const lastKey = path[path.length - 1];
742
+ if (!lastKey) return null;
743
+ const el = findElement(currentElements, currentPath, lastKey);
744
+ if (!el?.type) return null;
745
+ const targets = [];
746
+ for (const t of el.type){
747
+ if (t.code === "Reference" && t.targetProfile) {
748
+ for (const profile of t.targetProfile){
749
+ const rt = profile.split("/").pop();
750
+ if (rt) targets.push(rt);
751
+ }
752
+ }
753
+ }
754
+ return targets.length > 0 ? targets : null;
755
+ }
756
+ // ── Unified completion handler ─────────────────────────────────────────
757
+ async function fhirComplete(ctx, getSDs, resourceTypeHint, expandValueSet, completionContext) {
758
+ const { pos, doc } = ctx;
759
+ // 1. Resolve context: resourceType, effectivePath, profileUrls
760
+ // Search from root (outermost scope) inward to find the root resourceType.
761
+ // If not found in doc, fall back to resourceTypeHint (derived from URL).
762
+ let resourceType;
763
+ let hasExplicitResourceType = false;
764
+ let rtScope = ctx.getScope(0);
765
+ for(let level = ctx.fullPath.length; level >= 0; level--){
766
+ const s = ctx.getScope(level);
767
+ const rt = s.getString("resourceType");
768
+ if (rt) {
769
+ resourceType = rt;
770
+ hasExplicitResourceType = true;
771
+ rtScope = s;
772
+ break;
773
+ }
774
+ }
775
+ // If no resourceType found in any scope, use hint.
776
+ // If found only in an inner scope (not the root), still prefer hint for
777
+ // boundary detection — the inner RT will be picked up via getScope later.
778
+ if (!resourceType) {
779
+ resourceType = resourceTypeHint;
780
+ rtScope = ctx.getScope(ctx.fullPath.length);
781
+ } else if (resourceTypeHint && ctx.fullPath.length > 0) {
782
+ // Check if the found RT is actually from an inner scope, not the root.
783
+ // If the root scope has no RT but hint is available, use hint as the
784
+ // outer RT so that findResourceBoundary can resolve the path correctly.
785
+ const rootRT = ctx.getScope(ctx.fullPath.length).getString("resourceType");
786
+ if (!rootRT) {
787
+ resourceType = resourceTypeHint;
788
+ hasExplicitResourceType = false;
789
+ }
790
+ }
791
+ let effectivePath = ctx.fullPath;
792
+ let profileUrls = [];
793
+ // Detect Resource-typed boundary (e.g. contained, Bundle.entry.resource)
794
+ if (resourceType && effectivePath.length > 0) {
795
+ const boundaryIdx = await findResourceBoundary(effectivePath, resourceType, getSDs);
796
+ if (boundaryIdx !== null) {
797
+ const innerPath = effectivePath.slice(boundaryIdx + 1);
798
+ const innerScope = ctx.getScope(innerPath.length);
799
+ const innerRT = innerScope.getString("resourceType");
800
+ effectivePath = innerPath;
801
+ if (innerRT) {
802
+ resourceType = innerRT;
803
+ hasExplicitResourceType = true;
804
+ } else {
805
+ resourceType = "DomainResource";
806
+ hasExplicitResourceType = false;
807
+ }
808
+ profileUrls = innerScope.getStringArray("meta", "profile");
809
+ } else {
810
+ profileUrls = rtScope.getStringArray("meta", "profile");
811
+ }
812
+ } else {
813
+ profileUrls = rtScope.getStringArray("meta", "profile");
814
+ }
815
+ // 2. Handle cursor position kinds
816
+ const cp = ctx.cursorPosition;
817
+ if (cp.kind === "value") {
818
+ return handleValueCompletion(cp.key, effectivePath, resourceType, hasExplicitResourceType, profileUrls, doc, pos, getSDs, expandValueSet, completionContext, ctx);
819
+ }
820
+ if (cp.kind === "array-item") {
821
+ return handleArrayItemCompletion(cp.parentKey, effectivePath, resourceType, doc, pos, getSDs, completionContext, profileUrls);
822
+ }
823
+ if (cp.kind === "property") {
824
+ // Don't offer property completions inside arrays
825
+ if (ctx.isInsideArray()) return null;
826
+ return handlePropertyCompletion(effectivePath, resourceType, hasExplicitResourceType, doc, pos, getSDs, completionContext, ctx);
827
+ }
828
+ return null;
829
+ }
830
+ // ── Value completion ───────────────────────────────────────────────────
831
+ async function handleValueCompletion(valueKey, effectivePath, resourceType, _hasExplicitResourceType, profileUrls, doc, pos, getSDs, expandValueSet, completionContext, ctx) {
832
+ // resourceType value
833
+ if (valueKey === "resourceType") {
834
+ const sds = await getCachedSDList({
835
+ derivation: "specialization",
836
+ kind: "resource",
837
+ _elements: "type",
838
+ _count: "500"
839
+ }, getSDs);
840
+ const options = sds.map((sd)=>({
841
+ label: sd.type,
842
+ type: "type",
843
+ apply: (view, _c, from, to)=>{
844
+ const d = view.state.doc.toString();
845
+ let actualTo = to;
846
+ if (actualTo < d.length && d[actualTo] === '"') actualTo++;
847
+ view.dispatch({
848
+ changes: {
849
+ from,
850
+ to: actualTo,
851
+ insert: `${sd.type}"`
852
+ },
853
+ selection: {
854
+ anchor: from + sd.type.length + 1
855
+ }
856
+ });
857
+ }
858
+ }));
859
+ if (options.length === 0) return null;
860
+ const word = completionContext.matchBefore(/[\w]*/);
861
+ return {
862
+ from: word?.from ?? pos,
863
+ options,
864
+ validFor: /^\w*$/
865
+ };
866
+ }
867
+ // Parameters.parameter.name → slice names from profile
868
+ if (valueKey === "name" && resourceType && effectivePath.length > 0 && effectivePath[effectivePath.length - 1] === "parameter" && await isParametersType(resourceType, getSDs)) {
869
+ const slices = await getParameterSlices(profileUrls, getSDs);
870
+ if (slices.length > 0) {
871
+ const options = slices.map((slice)=>({
872
+ label: slice.fixedName,
873
+ type: "text",
874
+ detail: slice.min > 0 ? "required" : "optional",
875
+ boost: slice.min > 0 ? 2 : 0,
876
+ ...slice.short ? {
877
+ info: slice.short
878
+ } : {},
879
+ apply: (view, _c, from, to)=>{
880
+ const d = view.state.doc.toString();
881
+ let actualTo = to;
882
+ if (actualTo < d.length && d[actualTo] === '"') actualTo++;
883
+ view.dispatch({
884
+ changes: {
885
+ from,
886
+ to: actualTo,
887
+ insert: `${slice.fixedName}"`
888
+ },
889
+ selection: {
890
+ anchor: from + slice.fixedName.length + 1
891
+ }
892
+ });
893
+ // Auto-insert value[x] field based on slice type
894
+ const vTypes = slice.valueTypes;
895
+ if (vTypes.length === 0) vTypes.push("string");
896
+ if (vTypes.length === 1) {
897
+ setTimeout(()=>{
898
+ const cp = view.state.selection.main.head;
899
+ const cd = view.state.doc.toString();
900
+ const after = cd.slice(cp);
901
+ if (!/^\s*\n\s*\}/.test(after)) return;
902
+ const lineObj = view.state.doc.lineAt(cp);
903
+ const ind = lineObj.text.match(/^(\s*)/)?.[1] ?? "";
904
+ const tc = vTypes[0];
905
+ const vf = `value${tc.charAt(0).toUpperCase()}${tc.slice(1)}`;
906
+ let ins;
907
+ let cOff;
908
+ if (FHIR_STRING_TYPES.has(tc)) {
909
+ ins = `,\n${ind}"${vf}": ""`;
910
+ cOff = ins.length - 1;
911
+ } else if (FHIR_NUMBER_TYPES.has(tc)) {
912
+ ins = `,\n${ind}"${vf}": `;
913
+ cOff = ins.length;
914
+ } else {
915
+ const inner = `${ind} `;
916
+ ins = `,\n${ind}"${vf}": {\n${inner}\n${ind}}`;
917
+ cOff = ins.indexOf(`${inner}\n${ind}}`) + inner.length;
918
+ }
919
+ view.dispatch({
920
+ changes: {
921
+ from: cp,
922
+ insert: ins
923
+ },
924
+ selection: {
925
+ anchor: cp + cOff
926
+ }
927
+ });
928
+ setTimeout(()=>startCompletion(view), 0);
929
+ }, 10);
930
+ }
931
+ }
932
+ }));
933
+ const word = completionContext.matchBefore(/[\w]*/);
934
+ return {
935
+ from: word?.from ?? pos,
936
+ options,
937
+ validFor: /^\w*$/
938
+ };
939
+ }
940
+ }
941
+ // Fixed value from profile (fixedString, fixedUri, fixedCode)
942
+ if (resourceType && profileUrls.length > 0) {
943
+ const fixedVal = await getFixedValues(effectivePath, valueKey, resourceType, profileUrls, getSDs);
944
+ if (fixedVal != null) {
945
+ const option = {
946
+ label: fixedVal,
947
+ type: "text",
948
+ boost: 10,
949
+ apply: (view, _c, from, to)=>{
950
+ const d = view.state.doc.toString();
951
+ let actualTo = to;
952
+ if (actualTo < d.length && d[actualTo] === '"') actualTo++;
953
+ view.dispatch({
954
+ changes: {
955
+ from,
956
+ to: actualTo,
957
+ insert: `${fixedVal}"`
958
+ },
959
+ selection: {
960
+ anchor: from + fixedVal.length + 1
961
+ }
962
+ });
963
+ }
964
+ };
965
+ const word = completionContext.matchBefore(/[\w.:/-]*/);
966
+ return {
967
+ from: word?.from ?? pos,
968
+ options: [
969
+ option
970
+ ],
971
+ validFor: /^[\w.:/-]*$/
972
+ };
973
+ }
974
+ }
975
+ // reference value
976
+ if (valueKey === "reference" && resourceType) {
977
+ const targets = await resolveReferenceTargets(effectivePath, resourceType, getSDs);
978
+ if (targets) {
979
+ const options = targets.map((rt)=>({
980
+ label: `${rt}/`,
981
+ type: "type",
982
+ apply: (view, _c, from, to)=>{
983
+ view.dispatch({
984
+ changes: {
985
+ from,
986
+ to,
987
+ insert: `${rt}/`
988
+ },
989
+ selection: {
990
+ anchor: from + rt.length + 1
991
+ }
992
+ });
993
+ }
994
+ }));
995
+ const word = completionContext.matchBefore(/[\w/]*/);
996
+ return {
997
+ from: word?.from ?? pos,
998
+ options,
999
+ validFor: /^[\w/]*$/
1000
+ };
1001
+ }
1002
+ }
1003
+ // Extension URL value
1004
+ if (valueKey === "url") {
1005
+ const lastSeg = ctx.fullPath[ctx.fullPath.length - 1];
1006
+ if (lastSeg === "extension" || lastSeg === "modifierExtension") {
1007
+ return handleExtensionUrlCompletion(effectivePath, resourceType, profileUrls, doc, pos, getSDs, completionContext, ctx);
1008
+ }
1009
+ }
1010
+ // Boolean value
1011
+ if (resourceType) {
1012
+ const elements = await resolveElements(effectivePath, resourceType, getSDs);
1013
+ const el = elements.find((e)=>fieldName(e) === valueKey);
1014
+ if (el?.type?.length === 1 && el.type[0]?.code === "boolean") {
1015
+ const word = completionContext.matchBefore(/[\w]*/);
1016
+ const options = [
1017
+ "true",
1018
+ "false"
1019
+ ].map((v)=>({
1020
+ label: v,
1021
+ type: "keyword",
1022
+ apply: (view, _c, from, to)=>{
1023
+ const d = view.state.doc.toString();
1024
+ let actualFrom = from;
1025
+ let actualTo = to;
1026
+ // Remove surrounding quotes if present
1027
+ if (actualFrom > 0 && d[actualFrom - 1] === '"') actualFrom--;
1028
+ if (actualTo < d.length && d[actualTo] === '"') actualTo++;
1029
+ view.dispatch({
1030
+ changes: {
1031
+ from: actualFrom,
1032
+ to: actualTo,
1033
+ insert: v
1034
+ },
1035
+ selection: {
1036
+ anchor: actualFrom + v.length
1037
+ }
1038
+ });
1039
+ }
1040
+ }));
1041
+ return {
1042
+ from: word?.from ?? pos,
1043
+ options,
1044
+ validFor: /^\w*$/
1045
+ };
1046
+ }
1047
+ }
1048
+ // Terminology binding
1049
+ if (valueKey !== "resourceType" && valueKey !== "reference" && valueKey !== "url" && expandValueSet && resourceType) {
1050
+ const valueSetUrl = await findBindingForValue(effectivePath, valueKey, resourceType, getSDs, profileUrls, doc, pos);
1051
+ if (valueSetUrl) {
1052
+ const quoteWord = completionContext.matchBefore(/"[\w-]*/);
1053
+ const from = quoteWord?.from ?? pos;
1054
+ const filter = quoteWord ? quoteWord.text.replace(/^"/, "") : "";
1055
+ try {
1056
+ const codes = await expandValueSet(valueSetUrl, filter);
1057
+ if (codes.length > 0) {
1058
+ const options = codes.map((c)=>({
1059
+ label: c.code,
1060
+ ...c.display ? {
1061
+ info: c.display
1062
+ } : {},
1063
+ type: "text",
1064
+ apply: (view, _c, applyFrom, applyTo)=>{
1065
+ const d = view.state.doc.toString();
1066
+ let actualFrom = applyFrom;
1067
+ let actualTo = applyTo;
1068
+ if (d[actualFrom] === '"') actualFrom++;
1069
+ if (actualTo < d.length && d[actualTo] === '"') actualTo++;
1070
+ view.dispatch({
1071
+ changes: {
1072
+ from: actualFrom,
1073
+ to: actualTo,
1074
+ insert: `${c.code}"`
1075
+ },
1076
+ selection: {
1077
+ anchor: actualFrom + c.code.length + 1
1078
+ }
1079
+ });
1080
+ }
1081
+ }));
1082
+ return {
1083
+ from,
1084
+ options,
1085
+ filter: false
1086
+ };
1087
+ }
1088
+ } catch {
1089
+ // expand failed
1090
+ }
1091
+ }
1092
+ }
1093
+ return null;
1094
+ }
1095
+ // ── Extension URL completion ───────────────────────────────────────────
1096
+ async function handleExtensionUrlCompletion(_effectivePath, resourceType, profileUrls, doc, pos, getSDs, completionContext, ctx) {
1097
+ // Check for nested extension (parent has url)
1098
+ const urlKeyPos = doc.lastIndexOf('"url"', pos);
1099
+ let scanEnd = urlKeyPos !== -1 ? urlKeyPos : pos;
1100
+ for(let i = scanEnd - 1; i >= 0; i--){
1101
+ const c = doc[i];
1102
+ if (c === "{") {
1103
+ scanEnd = i;
1104
+ break;
1105
+ }
1106
+ if (c === "}" || c === "]" || c === "[") break;
1107
+ }
1108
+ const textBefore = doc.slice(0, scanEnd);
1109
+ let parentExtUrl = null;
1110
+ let depth = 0;
1111
+ let inStr = false;
1112
+ let esc = false;
1113
+ let foundExtArray = false;
1114
+ for(let i = textBefore.length - 1; i >= 0; i--){
1115
+ const ch = textBefore[i];
1116
+ if (esc) {
1117
+ esc = false;
1118
+ continue;
1119
+ }
1120
+ if (ch === "\\") {
1121
+ esc = true;
1122
+ continue;
1123
+ }
1124
+ if (ch === '"') {
1125
+ inStr = !inStr;
1126
+ continue;
1127
+ }
1128
+ if (inStr) continue;
1129
+ if (ch === "}" || ch === "]") {
1130
+ depth++;
1131
+ } else if (ch === "[") {
1132
+ if (depth === 0) {
1133
+ foundExtArray = true;
1134
+ continue;
1135
+ }
1136
+ depth--;
1137
+ } else if (ch === "{") {
1138
+ if (depth === 0 && foundExtArray) {
1139
+ const objText = textBefore.slice(i);
1140
+ const urlMatch = objText.match(/^\{[\s\S]*?"url"\s*:\s*"([^"]+)"/);
1141
+ if (urlMatch?.[1]?.includes("/")) {
1142
+ parentExtUrl = urlMatch[1];
1143
+ }
1144
+ break;
1145
+ }
1146
+ if (depth === 0) break;
1147
+ depth--;
1148
+ }
1149
+ }
1150
+ if (parentExtUrl) {
1151
+ return handleNestedExtensionSlices(parentExtUrl, pos, getSDs, completionContext);
1152
+ }
1153
+ if (!resourceType) return null;
1154
+ // Top-level extension URL completions
1155
+ const path = ctx.fullPath;
1156
+ const contextTypes = [
1157
+ resourceType,
1158
+ "DomainResource",
1159
+ "Resource",
1160
+ "Element"
1161
+ ];
1162
+ const extIdx = path.lastIndexOf("extension");
1163
+ if (extIdx > 0) {
1164
+ let currentRT = resourceType;
1165
+ for(let i = 0; i < extIdx; i++){
1166
+ const seg = path[i];
1167
+ if (!seg) break;
1168
+ const elements = await resolveElements([], currentRT, getSDs);
1169
+ const el = elements.find((e)=>fieldName(e) === seg);
1170
+ if (el?.type?.[0]?.code && !isPrimitiveType(el.type[0].code)) currentRT = el.type[0].code;
1171
+ else break;
1172
+ }
1173
+ if (currentRT !== resourceType) {
1174
+ contextTypes.length = 0;
1175
+ contextTypes.push(currentRT, "Element", `${resourceType}.${path.slice(0, extIdx).join(".")}`);
1176
+ }
1177
+ }
1178
+ // Profile extensions
1179
+ const profileExtUrls = [];
1180
+ if (contextTypes.includes(resourceType)) {
1181
+ for (const pUrl of profileUrls){
1182
+ const profileSD = await getCachedSD(pUrl, getSDs);
1183
+ if (!profileSD?.differential?.element) continue;
1184
+ for (const el of profileSD.differential.element){
1185
+ for (const t of el.type ?? []){
1186
+ if (t.code === "Extension") {
1187
+ for (const p of t.profile ?? []){
1188
+ const clean = p.includes("|") ? p.slice(0, p.indexOf("|")) : p;
1189
+ if (!profileExtUrls.includes(clean)) profileExtUrls.push(clean);
1190
+ }
1191
+ }
1192
+ }
1193
+ }
1194
+ }
1195
+ }
1196
+ const bareWord = completionContext.matchBefore(/[\w.:/-]*/);
1197
+ const filter = bareWord?.text ?? "";
1198
+ const searchParams = {
1199
+ type: "Extension",
1200
+ derivation: "constraint",
1201
+ _elements: "url,context",
1202
+ _count: "500"
1203
+ };
1204
+ if (filter) searchParams._ilike = filter;
1205
+ const results = await getCachedSDList(searchParams, getSDs);
1206
+ const containerType = contextTypes[0];
1207
+ const fhirPath = contextTypes.find((c)=>c.includes("."));
1208
+ const contextExts = results.filter((sd)=>sd.context?.some((c)=>c.type === "element" && contextTypes.includes(c.expression)));
1209
+ const seen = new Set();
1210
+ const allExts = [];
1211
+ if (contextTypes.includes(resourceType)) {
1212
+ for (const u of profileExtUrls){
1213
+ if (!seen.has(u)) {
1214
+ seen.add(u);
1215
+ allExts.push({
1216
+ url: u,
1217
+ boost: 20
1218
+ });
1219
+ }
1220
+ }
1221
+ }
1222
+ for (const sd of contextExts){
1223
+ const u = sd.url ?? sd.type;
1224
+ if (seen.has(u)) continue;
1225
+ seen.add(u);
1226
+ const ctxExprs = sd.context?.filter((c)=>c.type === "element").map((c)=>c.expression) ?? [];
1227
+ let boost = 0;
1228
+ if (fhirPath && ctxExprs.includes(fhirPath)) boost = 15;
1229
+ else if (containerType && ctxExprs.includes(containerType)) boost = 10;
1230
+ else if (ctxExprs.includes(resourceType)) boost = 5;
1231
+ else if (ctxExprs.some((e)=>e === "DomainResource" || e === "Resource")) boost = 2;
1232
+ else if (ctxExprs.includes("Element")) boost = 1;
1233
+ allExts.push({
1234
+ url: u,
1235
+ boost
1236
+ });
1237
+ }
1238
+ const lf = filter.toLowerCase();
1239
+ const filtered = (lf ? allExts.filter((e)=>e.url.toLowerCase().includes(lf)) : allExts).sort((a, b)=>b.boost - a.boost);
1240
+ if (filtered.length > 0) {
1241
+ const options = filtered.map((ext)=>({
1242
+ label: ext.url,
1243
+ type: "text",
1244
+ boost: ext.boost,
1245
+ apply: (view, _c, applyFrom, applyTo)=>{
1246
+ const d = view.state.doc.toString();
1247
+ let actualTo = applyTo;
1248
+ if (actualTo < d.length && d[actualTo] === '"') actualTo++;
1249
+ view.dispatch({
1250
+ changes: {
1251
+ from: applyFrom,
1252
+ to: actualTo,
1253
+ insert: `${ext.url}"`
1254
+ },
1255
+ selection: {
1256
+ anchor: applyFrom + ext.url.length + 1
1257
+ }
1258
+ });
1259
+ setTimeout(async ()=>{
1260
+ const fullSD = await getCachedSD(ext.url, getSDs);
1261
+ if (!fullSD) return;
1262
+ const extInfo = analyzeExtensionSD(fullSD);
1263
+ if (!extInfo) return;
1264
+ const cursorPos = view.state.selection.main.head;
1265
+ const curDoc = view.state.doc.toString();
1266
+ const after = curDoc.slice(cursorPos);
1267
+ if (!/^\s*\n\s*\}/.test(after)) return;
1268
+ const lineObj = view.state.doc.lineAt(cursorPos);
1269
+ const ind = lineObj.text.match(/^(\s*)/)?.[1] ?? "";
1270
+ let ins;
1271
+ let cOff;
1272
+ if (extInfo.isNested) {
1273
+ const inner = `${ind} `;
1274
+ const innerInner = `${inner} `;
1275
+ ins = `,\n${ind}"extension": [\n${inner}{\n${innerInner}"url": ""\n${inner}}\n${ind}]`;
1276
+ cOff = ins.lastIndexOf('""') + 1;
1277
+ } else if (extInfo.valueTypes.length === 1) {
1278
+ const tc = extInfo.valueTypes[0];
1279
+ const vf = `value${tc.charAt(0).toUpperCase()}${tc.slice(1)}`;
1280
+ if (FHIR_STRING_TYPES.has(tc) || tc === "code") {
1281
+ ins = `,\n${ind}"${vf}": ""`;
1282
+ cOff = ins.length - 1;
1283
+ } else if (FHIR_NUMBER_TYPES.has(tc)) {
1284
+ ins = `,\n${ind}"${vf}": `;
1285
+ cOff = ins.length;
1286
+ } else {
1287
+ const inner = `${ind} `;
1288
+ ins = `,\n${ind}"${vf}": {\n${inner}\n${ind}}`;
1289
+ cOff = ins.indexOf(`${inner}\n${ind}`) + inner.length;
1290
+ }
1291
+ } else {
1292
+ return;
1293
+ }
1294
+ view.dispatch({
1295
+ changes: {
1296
+ from: cursorPos,
1297
+ insert: ins
1298
+ },
1299
+ selection: {
1300
+ anchor: cursorPos + cOff
1301
+ }
1302
+ });
1303
+ setTimeout(()=>startCompletion(view), 0);
1304
+ }, 10);
1305
+ }
1306
+ }));
1307
+ return {
1308
+ from: bareWord?.from ?? pos,
1309
+ options,
1310
+ filter: false
1311
+ };
1312
+ }
1313
+ return null;
1314
+ }
1315
+ async function handleNestedExtensionSlices(parentExtUrl, pos, getSDs, completionContext) {
1316
+ const parentSD = await getCachedSD(parentExtUrl, getSDs);
1317
+ if (!parentSD) return null;
1318
+ const info = analyzeExtensionSD(parentSD);
1319
+ if (!info?.slices.length) return null;
1320
+ const word = completionContext.matchBefore(/[\w.:/-]*/);
1321
+ const filter = word?.text.toLowerCase() ?? "";
1322
+ const matching = filter ? info.slices.filter((s)=>s.fixedUri.toLowerCase().includes(filter) || (s.short?.toLowerCase().includes(filter) ?? false)) : info.slices;
1323
+ const options = matching.map((slice)=>{
1324
+ const sliceElements = parentSD.differential?.element ?? [];
1325
+ let sliceValueTypes = [];
1326
+ let inSl = false;
1327
+ for (const el of sliceElements){
1328
+ if (el.path === "Extension.extension" && el.sliceName === slice.sliceName) {
1329
+ inSl = true;
1330
+ continue;
1331
+ }
1332
+ if (inSl && el.path === "Extension.extension.value[x]") {
1333
+ sliceValueTypes = el.type?.map((t)=>t.code) ?? [];
1334
+ break;
1335
+ }
1336
+ if (inSl && el.path === "Extension.extension" && el.sliceName) break;
1337
+ }
1338
+ return {
1339
+ label: slice.fixedUri,
1340
+ ...slice.short ? {
1341
+ info: slice.short
1342
+ } : {},
1343
+ type: "text",
1344
+ apply: (view, _c, from, to)=>{
1345
+ const d = view.state.doc.toString();
1346
+ let actualTo = to;
1347
+ if (actualTo < d.length && d[actualTo] === '"') actualTo++;
1348
+ view.dispatch({
1349
+ changes: {
1350
+ from,
1351
+ to: actualTo,
1352
+ insert: `${slice.fixedUri}"`
1353
+ },
1354
+ selection: {
1355
+ anchor: from + slice.fixedUri.length + 1
1356
+ }
1357
+ });
1358
+ if (sliceValueTypes.length === 1) {
1359
+ setTimeout(()=>{
1360
+ const cp = view.state.selection.main.head;
1361
+ const cd = view.state.doc.toString();
1362
+ const af = cd.slice(cp);
1363
+ if (!/^\s*\n\s*\}/.test(af)) return;
1364
+ const lo = view.state.doc.lineAt(cp);
1365
+ const ind = lo.text.match(/^(\s*)/)?.[1] ?? "";
1366
+ const tc = sliceValueTypes[0];
1367
+ const vf = `value${tc.charAt(0).toUpperCase()}${tc.slice(1)}`;
1368
+ let ins;
1369
+ let cOff;
1370
+ if (FHIR_STRING_TYPES.has(tc) || tc === "code") {
1371
+ ins = `,\n${ind}"${vf}": ""`;
1372
+ cOff = ins.length - 1;
1373
+ } else if (FHIR_NUMBER_TYPES.has(tc)) {
1374
+ ins = `,\n${ind}"${vf}": `;
1375
+ cOff = ins.length;
1376
+ } else {
1377
+ const inner = `${ind} `;
1378
+ ins = `,\n${ind}"${vf}": {\n${inner}\n${ind}}`;
1379
+ cOff = ins.indexOf(`${inner}\n${ind}`) + inner.length;
1380
+ }
1381
+ view.dispatch({
1382
+ changes: {
1383
+ from: cp,
1384
+ insert: ins
1385
+ },
1386
+ selection: {
1387
+ anchor: cp + cOff
1388
+ }
1389
+ });
1390
+ setTimeout(()=>startCompletion(view), 0);
1391
+ }, 10);
1392
+ }
1393
+ }
1394
+ };
1395
+ });
1396
+ if (options.length > 0) return {
1397
+ from: word?.from ?? pos,
1398
+ options,
1399
+ filter: false
1400
+ };
1401
+ return null;
1402
+ }
1403
+ // ── Array item completion ──────────────────────────────────────────────
1404
+ async function handleArrayItemCompletion(parentKey, effectivePath, resourceType, _doc, pos, getSDs, completionContext, profileUrls) {
1405
+ if (!resourceType) return null;
1406
+ // Parameters.parameter or part → snippet completions from profile slices
1407
+ if ((parentKey === "parameter" || parentKey === "part") && await isParametersType(resourceType, getSDs)) {
1408
+ const slices = parentKey === "parameter" ? await getParameterSlices(profileUrls, getSDs) : [];
1409
+ const options = [];
1410
+ for (const slice of slices){
1411
+ options.push({
1412
+ label: slice.fixedName,
1413
+ type: "text",
1414
+ detail: slice.min > 0 ? `${slice.min}..${slice.max}` : `0..${slice.max}`,
1415
+ boost: slice.min > 0 ? 2 : 0,
1416
+ ...slice.short ? {
1417
+ info: slice.short
1418
+ } : {},
1419
+ apply: (view, _c, from, to)=>{
1420
+ const line = view.state.doc.lineAt(from);
1421
+ const indent = line.text.match(/^(\s*)/)?.[1] ?? "";
1422
+ const { text, cursorOffset } = buildParameterSnippet(slice.fixedName, slice.valueTypes, indent);
1423
+ view.dispatch({
1424
+ changes: {
1425
+ from,
1426
+ to,
1427
+ insert: text
1428
+ },
1429
+ selection: {
1430
+ anchor: from + cursorOffset
1431
+ }
1432
+ });
1433
+ setTimeout(()=>startCompletion(view), 0);
1434
+ }
1435
+ });
1436
+ }
1437
+ // Generic parameter template (always available)
1438
+ options.push({
1439
+ label: "parameter",
1440
+ type: "text",
1441
+ boost: -1,
1442
+ info: "Custom parameter",
1443
+ apply: (view, _c, from, to)=>{
1444
+ const line = view.state.doc.lineAt(from);
1445
+ const indent = line.text.match(/^(\s*)/)?.[1] ?? "";
1446
+ const { text, cursorOffset } = buildParameterSnippet("", [], indent);
1447
+ view.dispatch({
1448
+ changes: {
1449
+ from,
1450
+ to,
1451
+ insert: text
1452
+ },
1453
+ selection: {
1454
+ anchor: from + cursorOffset
1455
+ }
1456
+ });
1457
+ setTimeout(()=>startCompletion(view), 0);
1458
+ }
1459
+ });
1460
+ const word = completionContext.matchBefore(/[\w]*/);
1461
+ return {
1462
+ from: word?.from ?? pos,
1463
+ options
1464
+ };
1465
+ }
1466
+ // Get path excluding the array key itself
1467
+ const parentPath = effectivePath.length > 0 && effectivePath[effectivePath.length - 1] === parentKey ? effectivePath.slice(0, -1) : effectivePath;
1468
+ const targetType = await findCanonicalTargetType(parentPath, parentKey, resourceType, getSDs);
1469
+ if (targetType === "StructureDefinition") {
1470
+ const allSDs = await getCachedSDList({
1471
+ type: `${resourceType},DomainResource,Resource`,
1472
+ derivation: "constraint",
1473
+ _elements: "url,name",
1474
+ _count: "50"
1475
+ }, getSDs);
1476
+ const seen = new Set();
1477
+ const uniqueSDs = allSDs.filter((sd)=>{
1478
+ const u = sd.url ?? sd.type;
1479
+ if (seen.has(u)) return false;
1480
+ seen.add(u);
1481
+ return true;
1482
+ });
1483
+ if (uniqueSDs.length > 0) {
1484
+ const quoteWord = completionContext.matchBefore(/"[^"]*/);
1485
+ const bareWord = completionContext.matchBefore(/[\w.:/-]*/);
1486
+ const from = quoteWord?.from ?? bareWord?.from ?? pos;
1487
+ const filter = quoteWord ? quoteWord.text.replace(/^"/, "").toLowerCase() : bareWord?.text.toLowerCase() ?? "";
1488
+ const filtered = filter ? uniqueSDs.filter((sd)=>sd.name?.toLowerCase().includes(filter) || sd.url?.toLowerCase().includes(filter)) : uniqueSDs;
1489
+ const options = filtered.map((sd)=>{
1490
+ const url = sd.url ?? sd.type;
1491
+ return {
1492
+ label: url,
1493
+ ...sd.name ? {
1494
+ info: sd.name
1495
+ } : {},
1496
+ type: "text",
1497
+ apply: (view, _c, applyFrom, applyTo)=>{
1498
+ const d = view.state.doc.toString();
1499
+ let actualTo = applyTo;
1500
+ if (actualTo < d.length && d[actualTo] === '"') actualTo++;
1501
+ view.dispatch({
1502
+ changes: {
1503
+ from: applyFrom,
1504
+ to: actualTo,
1505
+ insert: `"${url}"`
1506
+ },
1507
+ selection: {
1508
+ anchor: applyFrom + url.length + 2
1509
+ }
1510
+ });
1511
+ }
1512
+ };
1513
+ });
1514
+ if (options.length > 0) {
1515
+ return {
1516
+ from,
1517
+ options,
1518
+ filter: false
1519
+ };
1520
+ }
1521
+ }
1522
+ }
1523
+ if (targetType) return null;
1524
+ return null;
1525
+ }
1526
+ // ── Property completion ────────────────────────────────────────────────
1527
+ async function handlePropertyCompletion(effectivePath, resourceType, hasExplicitResourceType, doc, pos, getSDs, completionContext, ctx) {
1528
+ const line = completionContext.state.doc.lineAt(pos);
1529
+ const beforeCursor = line.text.slice(0, pos - line.from).trimStart();
1530
+ // Only auto-trigger property completions when user has started typing
1531
+ if (!completionContext.explicit && /,\s*"?\s*$/.test(beforeCursor) && !completionContext.matchBefore(/\w+/)) return null;
1532
+ const makeJsonRtCompletion = ()=>{
1533
+ const c = {
1534
+ label: "resourceType",
1535
+ type: "property",
1536
+ detail: "string",
1537
+ boost: 10,
1538
+ apply: (view, _completion, from, to)=>{
1539
+ const d = view.state.doc.toString();
1540
+ let actualFrom = from;
1541
+ let actualTo = to;
1542
+ if (actualFrom > 0 && d[actualFrom - 1] === '"') actualFrom--;
1543
+ if (actualTo < d.length && d[actualTo] === '"') actualTo++;
1544
+ const text = '"resourceType": ""';
1545
+ view.dispatch({
1546
+ changes: {
1547
+ from: actualFrom,
1548
+ to: actualTo,
1549
+ insert: text
1550
+ },
1551
+ selection: {
1552
+ anchor: actualFrom + text.length - 1
1553
+ }
1554
+ });
1555
+ }
1556
+ };
1557
+ c.info = "FHIR resource type";
1558
+ return c;
1559
+ };
1560
+ let completions;
1561
+ if (resourceType) {
1562
+ const elements = await resolveElements(effectivePath, resourceType, getSDs);
1563
+ const isParams = await isParametersType(resourceType, getSDs);
1564
+ const mapFn = isParams ? (el)=>toParameterPropertyCompletion(el) : toCompletion;
1565
+ completions = elementsToCompletions(elements, mapFn);
1566
+ if (!hasExplicitResourceType && effectivePath.length === 0) {
1567
+ completions = [
1568
+ makeJsonRtCompletion(),
1569
+ ...completions
1570
+ ];
1571
+ }
1572
+ } else if (effectivePath.length === 0) {
1573
+ const domainElements = await resolveElements(effectivePath, "DomainResource", getSDs);
1574
+ completions = [
1575
+ makeJsonRtCompletion(),
1576
+ ...elementsToCompletions(domainElements, toCompletion)
1577
+ ];
1578
+ } else {
1579
+ return null;
1580
+ }
1581
+ // Filter out properties already present in current object
1582
+ const existingKeys = new Set(ctx.getScope(0).getKeys());
1583
+ completions = completions.filter((c)=>!existingKeys.has(c.label));
1584
+ if (completions.length === 0) return null;
1585
+ const word = completionContext.matchBefore(/"?\w*/);
1586
+ let from = word?.from ?? pos;
1587
+ if (from < doc.length && doc[from] === '"') from++;
1588
+ return {
1589
+ from,
1590
+ options: completions,
1591
+ validFor: /^\w*$/
1592
+ };
1593
+ }
1594
+ // ── Thin wrapper ───────────────────────────────────────────────────────
1595
+ /** @internal — exported for tests only */ export function jsonCompletionSource(getSDs, resourceTypeHint, expandValueSet) {
1596
+ return async (cc)=>{
1597
+ const ctx = buildJsonDocumentContext(cc.state.doc.toString(), cc.pos);
1598
+ return fhirComplete(ctx, getSDs, resourceTypeHint, expandValueSet, cc);
1599
+ };
1600
+ }
1601
+ async function validateFhirProperties(properties, getSDs) {
1602
+ const groups = new Map();
1603
+ for (const prop of properties){
1604
+ const key = `${prop.resourceType}|${prop.path.join(".")}`;
1605
+ let group = groups.get(key);
1606
+ if (!group) {
1607
+ group = {
1608
+ resourceType: prop.resourceType,
1609
+ path: [
1610
+ ...prop.path
1611
+ ],
1612
+ props: []
1613
+ };
1614
+ groups.set(key, group);
1615
+ }
1616
+ group.props.push(prop);
1617
+ }
1618
+ const diagnostics = [];
1619
+ for (const { resourceType, path, props } of groups.values()){
1620
+ const elements = await resolveElements(path, resourceType, getSDs);
1621
+ if (elements.length === 0) continue;
1622
+ const validNames = new Set();
1623
+ for (const el of elements){
1624
+ const name = fieldName(el);
1625
+ validNames.add(name);
1626
+ const typeCode = el.type?.[0]?.code;
1627
+ if (el.type?.length === 1 && typeCode && isPrimitiveType(typeCode)) {
1628
+ validNames.add(`_${name}`);
1629
+ }
1630
+ }
1631
+ if (path.length === 0) {
1632
+ validNames.add("resourceType");
1633
+ }
1634
+ for (const prop of props){
1635
+ if (!validNames.has(prop.name)) {
1636
+ diagnostics.push({
1637
+ from: prop.from,
1638
+ to: prop.to,
1639
+ message: `Unknown property "${prop.name}"`
1640
+ });
1641
+ }
1642
+ }
1643
+ }
1644
+ return diagnostics;
1645
+ }
1646
+ function buildFhirValidationPlugin(getSDs, resourceTypeHint) {
1647
+ return ViewPlugin.define((view)=>{
1648
+ let timeout = null;
1649
+ let destroyed = false;
1650
+ function hasActiveDiagnostics() {
1651
+ try {
1652
+ return view.state.field(fhirDiagnosticsField).messages.size > 0;
1653
+ } catch {
1654
+ return false;
1655
+ }
1656
+ }
1657
+ function scheduleCheck() {
1658
+ if (timeout) clearTimeout(timeout);
1659
+ const delay = hasActiveDiagnostics() ? 0 : 1500;
1660
+ timeout = setTimeout(()=>check(), delay);
1661
+ }
1662
+ async function check() {
1663
+ if (destroyed) return;
1664
+ const currentDoc = view.state.doc.toString();
1665
+ const tree = ensureSyntaxTree(view.state, view.state.doc.length, 1000) ?? syntaxTree(view.state);
1666
+ const { properties, emptyStrings } = walkJsonProperties(currentDoc, tree, resourceTypeHint ?? null);
1667
+ if (!findRootJsonObject(currentDoc, tree)) {
1668
+ try {
1669
+ view.dispatch({
1670
+ effects: setFhirDiagnosticsEffect.of([])
1671
+ });
1672
+ } catch {
1673
+ /* view destroyed */ }
1674
+ return;
1675
+ }
1676
+ if (properties.length === 0 && emptyStrings.length === 0) {
1677
+ try {
1678
+ view.dispatch({
1679
+ effects: setFhirDiagnosticsEffect.of([])
1680
+ });
1681
+ } catch {
1682
+ /* view destroyed */ }
1683
+ return;
1684
+ }
1685
+ const rawDiags = await validateFhirProperties(properties, getSDs);
1686
+ if (destroyed) return;
1687
+ if (view.state.doc.toString() !== currentDoc) return;
1688
+ // for (const es of emptyStrings) {
1689
+ // rawDiags.push({
1690
+ // from: es.from,
1691
+ // to: es.to,
1692
+ // message: "Value must not be empty",
1693
+ // });
1694
+ // }
1695
+ const diags = rawDiags.map((d)=>({
1696
+ ...d,
1697
+ line: view.state.doc.lineAt(d.from).number
1698
+ }));
1699
+ try {
1700
+ view.dispatch({
1701
+ effects: setFhirDiagnosticsEffect.of(diags)
1702
+ });
1703
+ } catch {
1704
+ /* view destroyed */ }
1705
+ }
1706
+ scheduleCheck();
1707
+ return {
1708
+ update (update) {
1709
+ if (update.docChanged) {
1710
+ scheduleCheck();
1711
+ }
1712
+ },
1713
+ destroy () {
1714
+ destroyed = true;
1715
+ if (timeout) clearTimeout(timeout);
1716
+ }
1717
+ };
1718
+ });
1719
+ }
1720
+ const setFhirDiagnosticsEffect = StateEffect.define();
1721
+ const fhirUnderline = Decoration.mark({
1722
+ class: "cm-fhir-error-underline"
1723
+ });
1724
+ const fhirErrorLineDecoration = Decoration.line({
1725
+ class: "cm-errorLine"
1726
+ });
1727
+ class FhirGutterMarker extends GutterMarker {
1728
+ elementClass = "cm-errorLineGutter";
1729
+ }
1730
+ const fhirGutterMarker = new FhirGutterMarker();
1731
+ export const fhirDiagnosticsField = StateField.define({
1732
+ create () {
1733
+ return {
1734
+ marks: Decoration.none,
1735
+ lineDecos: Decoration.none,
1736
+ gutterMarkers: RangeSet.empty,
1737
+ messages: new Map()
1738
+ };
1739
+ },
1740
+ update (value, tr) {
1741
+ for (const effect of tr.effects){
1742
+ if (effect.is(setFhirDiagnosticsEffect)) {
1743
+ const diags = effect.value;
1744
+ if (diags.length === 0) {
1745
+ return {
1746
+ marks: Decoration.none,
1747
+ lineDecos: Decoration.none,
1748
+ gutterMarkers: RangeSet.empty,
1749
+ messages: new Map()
1750
+ };
1751
+ }
1752
+ const marks = [];
1753
+ const lineDecos = [];
1754
+ const gutter = [];
1755
+ const messages = new Map();
1756
+ for (const d of diags){
1757
+ marks.push(fhirUnderline.range(d.from, d.to));
1758
+ const existing = messages.get(d.line);
1759
+ if (existing) {
1760
+ messages.set(d.line, `${existing}\n${d.message}`);
1761
+ } else {
1762
+ messages.set(d.line, d.message);
1763
+ const line = tr.state.doc.line(d.line);
1764
+ lineDecos.push(fhirErrorLineDecoration.range(line.from));
1765
+ gutter.push(fhirGutterMarker.range(line.from));
1766
+ }
1767
+ }
1768
+ return {
1769
+ marks: Decoration.set(marks, true),
1770
+ lineDecos: Decoration.set(lineDecos, true),
1771
+ gutterMarkers: RangeSet.of(gutter, true),
1772
+ messages
1773
+ };
1774
+ }
1775
+ }
1776
+ if (tr.docChanged) {
1777
+ try {
1778
+ return {
1779
+ marks: value.marks.map(tr.changes),
1780
+ lineDecos: value.lineDecos.map(tr.changes),
1781
+ gutterMarkers: value.gutterMarkers.map(tr.changes),
1782
+ messages: value.messages
1783
+ };
1784
+ } catch {
1785
+ return {
1786
+ marks: Decoration.none,
1787
+ lineDecos: Decoration.none,
1788
+ gutterMarkers: RangeSet.empty,
1789
+ messages: new Map()
1790
+ };
1791
+ }
1792
+ }
1793
+ return value;
1794
+ },
1795
+ provide (field) {
1796
+ return [
1797
+ EditorView.decorations.from(field, (v)=>v.marks),
1798
+ EditorView.decorations.from(field, (v)=>v.lineDecos),
1799
+ gutterLineClass.from(field, (v)=>v.gutterMarkers)
1800
+ ];
1801
+ }
1802
+ });
1803
+ const fhirLinterTheme = EditorView.theme({
1804
+ ".cm-fhir-error-underline": {
1805
+ textDecorationLine: "underline",
1806
+ textDecorationStyle: "wavy",
1807
+ textDecorationColor: "var(--color-text-error-primary)",
1808
+ textUnderlineOffset: "3px"
1809
+ },
1810
+ ".cm-lineNumbers .cm-gutterElement.cm-errorLineGutter": {
1811
+ color: "var(--color-text-error-primary)",
1812
+ backgroundColor: "color-mix(in srgb, var(--color-text-error-primary) 7%, transparent)"
1813
+ }
1814
+ });
1815
+ // ── Public API ─────────────────────────────────────────────────────────
1816
+ export function buildFhirCompletionExtension(getSDs, resourceTypeHint, expandValueSet) {
1817
+ const jsonSource = jsonCompletionSource(getSDs, resourceTypeHint, expandValueSet);
1818
+ const autoTrigger = EditorView.updateListener.of((update)=>{
1819
+ if (!update.docChanged) return;
1820
+ if (completionStatus(update.view.state)) return;
1821
+ const { state } = update.view;
1822
+ const pos = state.selection.main.head;
1823
+ const doc = state.doc.toString();
1824
+ const line = state.doc.lineAt(pos);
1825
+ const beforeCursor = line.text.slice(0, pos - line.from).trimStart();
1826
+ // Trigger on empty lines (including after snippet insertion),
1827
+ // after [ (array open), or after " (string value start)
1828
+ const shouldTrigger = beforeCursor === "" || pos > 0 && doc[pos - 1] === "[" || pos > 0 && doc[pos - 1] === '"' && pos > 1 && doc[pos - 2] !== "\\";
1829
+ if (!shouldTrigger) return;
1830
+ // Skip bulk replacements (e.g. tab switch, currentValue update)
1831
+ // but allow snippets — check only if the ENTIRE doc was replaced
1832
+ let totalInserted = 0;
1833
+ update.changes.iterChanges((_fA, _tA, _fB, _tB, ins)=>{
1834
+ totalInserted += ins.length;
1835
+ });
1836
+ if (totalInserted > doc.length * 0.5) return;
1837
+ setTimeout(()=>startCompletion(update.view), 0);
1838
+ });
1839
+ return [
1840
+ jsonLanguage.data.of({
1841
+ autocomplete: jsonSource
1842
+ }),
1843
+ autoTrigger,
1844
+ fhirDiagnosticsField,
1845
+ fhirLinterTheme,
1846
+ buildFhirValidationPlugin(getSDs, resourceTypeHint)
1847
+ ];
1848
+ }
1849
+
1850
+ //# sourceMappingURL=fhir-autocomplete.js.map