fhirpath-ts 0.0.0-bootstrap.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (414) hide show
  1. package/LICENSE +201 -0
  2. package/README.md +391 -0
  3. package/THIRD-PARTY-NOTICES.md +296 -0
  4. package/dist/analyzer/analyze-dto.d.ts +45 -0
  5. package/dist/analyzer/analyze-dto.d.ts.map +1 -0
  6. package/dist/analyzer/analyze-dto.js +147 -0
  7. package/dist/analyzer/analyze-dto.js.map +1 -0
  8. package/dist/analyzer/analyze.d.ts +98 -0
  9. package/dist/analyzer/analyze.d.ts.map +1 -0
  10. package/dist/analyzer/analyze.js +925 -0
  11. package/dist/analyzer/analyze.js.map +1 -0
  12. package/dist/analyzer/expression-policy.d.ts +210 -0
  13. package/dist/analyzer/expression-policy.d.ts.map +1 -0
  14. package/dist/analyzer/expression-policy.js +254 -0
  15. package/dist/analyzer/expression-policy.js.map +1 -0
  16. package/dist/analyzer/index.d.ts +3 -0
  17. package/dist/analyzer/index.d.ts.map +1 -0
  18. package/dist/analyzer/index.js +6 -0
  19. package/dist/analyzer/index.js.map +1 -0
  20. package/dist/analyzer/regex-safety.d.ts +10 -0
  21. package/dist/analyzer/regex-safety.d.ts.map +1 -0
  22. package/dist/analyzer/regex-safety.js +84 -0
  23. package/dist/analyzer/regex-safety.js.map +1 -0
  24. package/dist/analyzer/signatures.d.ts +72 -0
  25. package/dist/analyzer/signatures.d.ts.map +1 -0
  26. package/dist/analyzer/signatures.js +195 -0
  27. package/dist/analyzer/signatures.js.map +1 -0
  28. package/dist/api/bundle.d.ts +29 -0
  29. package/dist/api/bundle.d.ts.map +1 -0
  30. package/dist/api/bundle.js +108 -0
  31. package/dist/api/bundle.js.map +1 -0
  32. package/dist/api/cache.d.ts +10 -0
  33. package/dist/api/cache.d.ts.map +1 -0
  34. package/dist/api/cache.js +38 -0
  35. package/dist/api/cache.js.map +1 -0
  36. package/dist/api/column-signature.d.ts +53 -0
  37. package/dist/api/column-signature.d.ts.map +1 -0
  38. package/dist/api/column-signature.js +43 -0
  39. package/dist/api/column-signature.js.map +1 -0
  40. package/dist/api/compile.d.ts +120 -0
  41. package/dist/api/compile.d.ts.map +1 -0
  42. package/dist/api/compile.js +167 -0
  43. package/dist/api/compile.js.map +1 -0
  44. package/dist/api/constraints.d.ts +48 -0
  45. package/dist/api/constraints.d.ts.map +1 -0
  46. package/dist/api/constraints.js +52 -0
  47. package/dist/api/constraints.js.map +1 -0
  48. package/dist/api/dto.d.ts +134 -0
  49. package/dist/api/dto.d.ts.map +1 -0
  50. package/dist/api/dto.js +295 -0
  51. package/dist/api/dto.js.map +1 -0
  52. package/dist/api/engine.d.ts +136 -0
  53. package/dist/api/engine.d.ts.map +1 -0
  54. package/dist/api/engine.js +183 -0
  55. package/dist/api/engine.js.map +1 -0
  56. package/dist/api/evaluate.d.ts +7 -0
  57. package/dist/api/evaluate.d.ts.map +1 -0
  58. package/dist/api/evaluate.js +10 -0
  59. package/dist/api/evaluate.js.map +1 -0
  60. package/dist/api/project.d.ts +89 -0
  61. package/dist/api/project.d.ts.map +1 -0
  62. package/dist/api/project.js +150 -0
  63. package/dist/api/project.js.map +1 -0
  64. package/dist/api/tagged.d.ts +14 -0
  65. package/dist/api/tagged.d.ts.map +1 -0
  66. package/dist/api/tagged.js +13 -0
  67. package/dist/api/tagged.js.map +1 -0
  68. package/dist/cli/dto-check.d.ts +25 -0
  69. package/dist/cli/dto-check.d.ts.map +1 -0
  70. package/dist/cli/dto-check.js +77 -0
  71. package/dist/cli/dto-check.js.map +1 -0
  72. package/dist/cli/fhirpath-check.d.ts +3 -0
  73. package/dist/cli/fhirpath-check.d.ts.map +1 -0
  74. package/dist/cli/fhirpath-check.js +149 -0
  75. package/dist/cli/fhirpath-check.js.map +1 -0
  76. package/dist/cli/ts-loader.d.mts +3 -0
  77. package/dist/cli/ts-loader.d.mts.map +1 -0
  78. package/dist/cli/ts-loader.mjs +48 -0
  79. package/dist/cli/ts-loader.mjs.map +1 -0
  80. package/dist/engine/context.d.ts +173 -0
  81. package/dist/engine/context.d.ts.map +1 -0
  82. package/dist/engine/context.js +118 -0
  83. package/dist/engine/context.js.map +1 -0
  84. package/dist/engine/evaluator.d.ts +7 -0
  85. package/dist/engine/evaluator.d.ts.map +1 -0
  86. package/dist/engine/evaluator.js +196 -0
  87. package/dist/engine/evaluator.js.map +1 -0
  88. package/dist/engine/navigation.d.ts +11 -0
  89. package/dist/engine/navigation.d.ts.map +1 -0
  90. package/dist/engine/navigation.js +102 -0
  91. package/dist/engine/navigation.js.map +1 -0
  92. package/dist/engine/operators/collections.d.ts +12 -0
  93. package/dist/engine/operators/collections.d.ts.map +1 -0
  94. package/dist/engine/operators/collections.js +31 -0
  95. package/dist/engine/operators/collections.js.map +1 -0
  96. package/dist/engine/operators/comparison.d.ts +13 -0
  97. package/dist/engine/operators/comparison.d.ts.map +1 -0
  98. package/dist/engine/operators/comparison.js +77 -0
  99. package/dist/engine/operators/comparison.js.map +1 -0
  100. package/dist/engine/operators/equality.d.ts +19 -0
  101. package/dist/engine/operators/equality.d.ts.map +1 -0
  102. package/dist/engine/operators/equality.js +203 -0
  103. package/dist/engine/operators/equality.js.map +1 -0
  104. package/dist/engine/operators/index.d.ts +18 -0
  105. package/dist/engine/operators/index.d.ts.map +1 -0
  106. package/dist/engine/operators/index.js +30 -0
  107. package/dist/engine/operators/index.js.map +1 -0
  108. package/dist/engine/operators/logic.d.ts +8 -0
  109. package/dist/engine/operators/logic.d.ts.map +1 -0
  110. package/dist/engine/operators/logic.js +38 -0
  111. package/dist/engine/operators/logic.js.map +1 -0
  112. package/dist/engine/operators/math.d.ts +13 -0
  113. package/dist/engine/operators/math.d.ts.map +1 -0
  114. package/dist/engine/operators/math.js +198 -0
  115. package/dist/engine/operators/math.js.map +1 -0
  116. package/dist/engine/operators/strings.d.ts +8 -0
  117. package/dist/engine/operators/strings.d.ts.map +1 -0
  118. package/dist/engine/operators/strings.js +22 -0
  119. package/dist/engine/operators/strings.js.map +1 -0
  120. package/dist/engine/operators/types.d.ts +3 -0
  121. package/dist/engine/operators/types.d.ts.map +1 -0
  122. package/dist/engine/operators/types.js +15 -0
  123. package/dist/engine/operators/types.js.map +1 -0
  124. package/dist/engine/type-matching.d.ts +20 -0
  125. package/dist/engine/type-matching.d.ts.map +1 -0
  126. package/dist/engine/type-matching.js +122 -0
  127. package/dist/engine/type-matching.js.map +1 -0
  128. package/dist/errors.d.ts +25 -0
  129. package/dist/errors.d.ts.map +1 -0
  130. package/dist/errors.js +21 -0
  131. package/dist/errors.js.map +1 -0
  132. package/dist/eslint/index.d.ts +12 -0
  133. package/dist/eslint/index.d.ts.map +1 -0
  134. package/dist/eslint/index.js +316 -0
  135. package/dist/eslint/index.js.map +1 -0
  136. package/dist/fhir/html-checks.d.ts +7 -0
  137. package/dist/fhir/html-checks.d.ts.map +1 -0
  138. package/dist/fhir/html-checks.js +256 -0
  139. package/dist/fhir/html-checks.js.map +1 -0
  140. package/dist/fhir/model-navigation.d.ts +11 -0
  141. package/dist/fhir/model-navigation.d.ts.map +1 -0
  142. package/dist/fhir/model-navigation.js +142 -0
  143. package/dist/fhir/model-navigation.js.map +1 -0
  144. package/dist/functions/aggregate.d.ts +2 -0
  145. package/dist/functions/aggregate.d.ts.map +1 -0
  146. package/dist/functions/aggregate.js +127 -0
  147. package/dist/functions/aggregate.js.map +1 -0
  148. package/dist/functions/boundary.d.ts +2 -0
  149. package/dist/functions/boundary.d.ts.map +1 -0
  150. package/dist/functions/boundary.js +189 -0
  151. package/dist/functions/boundary.js.map +1 -0
  152. package/dist/functions/combining.d.ts +2 -0
  153. package/dist/functions/combining.d.ts.map +1 -0
  154. package/dist/functions/combining.js +13 -0
  155. package/dist/functions/combining.js.map +1 -0
  156. package/dist/functions/control.d.ts +2 -0
  157. package/dist/functions/control.d.ts.map +1 -0
  158. package/dist/functions/control.js +25 -0
  159. package/dist/functions/control.js.map +1 -0
  160. package/dist/functions/conversion.d.ts +3 -0
  161. package/dist/functions/conversion.d.ts.map +1 -0
  162. package/dist/functions/conversion.js +316 -0
  163. package/dist/functions/conversion.js.map +1 -0
  164. package/dist/functions/date-components.d.ts +2 -0
  165. package/dist/functions/date-components.d.ts.map +1 -0
  166. package/dist/functions/date-components.js +81 -0
  167. package/dist/functions/date-components.js.map +1 -0
  168. package/dist/functions/existence.d.ts +4 -0
  169. package/dist/functions/existence.d.ts.map +1 -0
  170. package/dist/functions/existence.js +97 -0
  171. package/dist/functions/existence.js.map +1 -0
  172. package/dist/functions/fhir.d.ts +2 -0
  173. package/dist/functions/fhir.d.ts.map +1 -0
  174. package/dist/functions/fhir.js +222 -0
  175. package/dist/functions/fhir.js.map +1 -0
  176. package/dist/functions/filtering.d.ts +2 -0
  177. package/dist/functions/filtering.d.ts.map +1 -0
  178. package/dist/functions/filtering.js +112 -0
  179. package/dist/functions/filtering.js.map +1 -0
  180. package/dist/functions/install.d.ts +18 -0
  181. package/dist/functions/install.d.ts.map +1 -0
  182. package/dist/functions/install.js +20 -0
  183. package/dist/functions/install.js.map +1 -0
  184. package/dist/functions/iteration.d.ts +7 -0
  185. package/dist/functions/iteration.d.ts.map +1 -0
  186. package/dist/functions/iteration.js +9 -0
  187. package/dist/functions/iteration.js.map +1 -0
  188. package/dist/functions/math.d.ts +2 -0
  189. package/dist/functions/math.d.ts.map +1 -0
  190. package/dist/functions/math.js +152 -0
  191. package/dist/functions/math.js.map +1 -0
  192. package/dist/functions/reflection.d.ts +2 -0
  193. package/dist/functions/reflection.d.ts.map +1 -0
  194. package/dist/functions/reflection.js +23 -0
  195. package/dist/functions/reflection.js.map +1 -0
  196. package/dist/functions/registry.d.ts +28 -0
  197. package/dist/functions/registry.d.ts.map +1 -0
  198. package/dist/functions/registry.js +46 -0
  199. package/dist/functions/registry.js.map +1 -0
  200. package/dist/functions/sort.d.ts +2 -0
  201. package/dist/functions/sort.d.ts.map +1 -0
  202. package/dist/functions/sort.js +48 -0
  203. package/dist/functions/sort.js.map +1 -0
  204. package/dist/functions/string.d.ts +2 -0
  205. package/dist/functions/string.d.ts.map +1 -0
  206. package/dist/functions/string.js +353 -0
  207. package/dist/functions/string.js.map +1 -0
  208. package/dist/functions/subsetting.d.ts +2 -0
  209. package/dist/functions/subsetting.d.ts.map +1 -0
  210. package/dist/functions/subsetting.js +72 -0
  211. package/dist/functions/subsetting.js.map +1 -0
  212. package/dist/functions/tree.d.ts +8 -0
  213. package/dist/functions/tree.d.ts.map +1 -0
  214. package/dist/functions/tree.js +109 -0
  215. package/dist/functions/tree.js.map +1 -0
  216. package/dist/functions/type-specifier.d.ts +8 -0
  217. package/dist/functions/type-specifier.d.ts.map +1 -0
  218. package/dist/functions/type-specifier.js +27 -0
  219. package/dist/functions/type-specifier.js.map +1 -0
  220. package/dist/functions/utility.d.ts +2 -0
  221. package/dist/functions/utility.d.ts.map +1 -0
  222. package/dist/functions/utility.js +76 -0
  223. package/dist/functions/utility.js.map +1 -0
  224. package/dist/functions/variables.d.ts +2 -0
  225. package/dist/functions/variables.d.ts.map +1 -0
  226. package/dist/functions/variables.js +35 -0
  227. package/dist/functions/variables.js.map +1 -0
  228. package/dist/index.d.ts +25 -0
  229. package/dist/index.d.ts.map +1 -0
  230. package/dist/index.js +11 -0
  231. package/dist/index.js.map +1 -0
  232. package/dist/lexer/lexer.d.ts +4 -0
  233. package/dist/lexer/lexer.d.ts.map +1 -0
  234. package/dist/lexer/lexer.js +318 -0
  235. package/dist/lexer/lexer.js.map +1 -0
  236. package/dist/lexer/tokens.d.ts +23 -0
  237. package/dist/lexer/tokens.d.ts.map +1 -0
  238. package/dist/lexer/tokens.js +40 -0
  239. package/dist/lexer/tokens.js.map +1 -0
  240. package/dist/model/provider.d.ts +36 -0
  241. package/dist/model/provider.d.ts.map +1 -0
  242. package/dist/model/provider.js +2 -0
  243. package/dist/model/provider.js.map +1 -0
  244. package/dist/parser/ast.d.ts +104 -0
  245. package/dist/parser/ast.d.ts.map +1 -0
  246. package/dist/parser/ast.js +2 -0
  247. package/dist/parser/ast.js.map +1 -0
  248. package/dist/parser/parser.d.ts +4 -0
  249. package/dist/parser/parser.d.ts.map +1 -0
  250. package/dist/parser/parser.js +299 -0
  251. package/dist/parser/parser.js.map +1 -0
  252. package/dist/parser/precedence.d.ts +24 -0
  253. package/dist/parser/precedence.d.ts.map +1 -0
  254. package/dist/parser/precedence.js +52 -0
  255. package/dist/parser/precedence.js.map +1 -0
  256. package/dist/parser/printer.d.ts +4 -0
  257. package/dist/parser/printer.d.ts.map +1 -0
  258. package/dist/parser/printer.js +112 -0
  259. package/dist/parser/printer.js.map +1 -0
  260. package/dist/r4/generated/resources-data.d.ts +3 -0
  261. package/dist/r4/generated/resources-data.d.ts.map +1 -0
  262. package/dist/r4/generated/resources-data.js +28628 -0
  263. package/dist/r4/generated/resources-data.js.map +1 -0
  264. package/dist/r4/generated/type-maps.d.ts +43153 -0
  265. package/dist/r4/generated/type-maps.d.ts.map +1 -0
  266. package/dist/r4/generated/type-maps.js +4 -0
  267. package/dist/r4/generated/type-maps.js.map +1 -0
  268. package/dist/r4/generated/types-data.d.ts +3 -0
  269. package/dist/r4/generated/types-data.d.ts.map +1 -0
  270. package/dist/r4/generated/types-data.js +2205 -0
  271. package/dist/r4/generated/types-data.js.map +1 -0
  272. package/dist/r4/index.d.ts +9 -0
  273. package/dist/r4/index.d.ts.map +1 -0
  274. package/dist/r4/index.js +94 -0
  275. package/dist/r4/index.js.map +1 -0
  276. package/dist/r4/model-data.d.ts +17 -0
  277. package/dist/r4/model-data.d.ts.map +1 -0
  278. package/dist/r4/model-data.js +2 -0
  279. package/dist/r4/model-data.js.map +1 -0
  280. package/dist/sites/index.d.ts +31 -0
  281. package/dist/sites/index.d.ts.map +1 -0
  282. package/dist/sites/index.js +205 -0
  283. package/dist/sites/index.js.map +1 -0
  284. package/dist/typed/infer.d.ts +234 -0
  285. package/dist/typed/infer.d.ts.map +1 -0
  286. package/dist/typed/infer.js +85 -0
  287. package/dist/typed/infer.js.map +1 -0
  288. package/dist/typed/perf-fixture.types.d.ts +136 -0
  289. package/dist/typed/perf-fixture.types.d.ts.map +1 -0
  290. package/dist/typed/perf-fixture.types.js +2 -0
  291. package/dist/typed/perf-fixture.types.js.map +1 -0
  292. package/dist/values/collection.d.ts +24 -0
  293. package/dist/values/collection.d.ts.map +1 -0
  294. package/dist/values/collection.js +51 -0
  295. package/dist/values/collection.js.map +1 -0
  296. package/dist/values/datetime.d.ts +54 -0
  297. package/dist/values/datetime.d.ts.map +1 -0
  298. package/dist/values/datetime.js +226 -0
  299. package/dist/values/datetime.js.map +1 -0
  300. package/dist/values/decimal.d.ts +48 -0
  301. package/dist/values/decimal.d.ts.map +1 -0
  302. package/dist/values/decimal.js +188 -0
  303. package/dist/values/decimal.js.map +1 -0
  304. package/dist/values/numeric.d.ts +24 -0
  305. package/dist/values/numeric.d.ts.map +1 -0
  306. package/dist/values/numeric.js +53 -0
  307. package/dist/values/numeric.js.map +1 -0
  308. package/dist/values/quantity.d.ts +49 -0
  309. package/dist/values/quantity.d.ts.map +1 -0
  310. package/dist/values/quantity.js +297 -0
  311. package/dist/values/quantity.js.map +1 -0
  312. package/dist/values/temporal-arithmetic.d.ts +17 -0
  313. package/dist/values/temporal-arithmetic.d.ts.map +1 -0
  314. package/dist/values/temporal-arithmetic.js +183 -0
  315. package/dist/values/temporal-arithmetic.js.map +1 -0
  316. package/dist/values/temporal-compare.d.ts +9 -0
  317. package/dist/values/temporal-compare.d.ts.map +1 -0
  318. package/dist/values/temporal-compare.js +59 -0
  319. package/dist/values/temporal-compare.js.map +1 -0
  320. package/dist/values/type-compat.d.ts +47 -0
  321. package/dist/values/type-compat.d.ts.map +1 -0
  322. package/dist/values/type-compat.js +100 -0
  323. package/dist/values/type-compat.js.map +1 -0
  324. package/dist/values/typed-value.d.ts +48 -0
  325. package/dist/values/typed-value.d.ts.map +1 -0
  326. package/dist/values/typed-value.js +117 -0
  327. package/dist/values/typed-value.js.map +1 -0
  328. package/dist/values/ucum.d.ts +14 -0
  329. package/dist/values/ucum.d.ts.map +1 -0
  330. package/dist/values/ucum.js +146 -0
  331. package/dist/values/ucum.js.map +1 -0
  332. package/package.json +137 -0
  333. package/src/analyzer/analyze-dto.ts +195 -0
  334. package/src/analyzer/analyze.ts +1181 -0
  335. package/src/analyzer/expression-policy.ts +434 -0
  336. package/src/analyzer/index.ts +23 -0
  337. package/src/analyzer/regex-safety.ts +85 -0
  338. package/src/analyzer/signatures.ts +260 -0
  339. package/src/api/bundle.ts +132 -0
  340. package/src/api/cache.ts +40 -0
  341. package/src/api/column-signature.ts +71 -0
  342. package/src/api/compile.ts +308 -0
  343. package/src/api/constraints.ts +104 -0
  344. package/src/api/dto.ts +445 -0
  345. package/src/api/engine.ts +328 -0
  346. package/src/api/evaluate.ts +11 -0
  347. package/src/api/project.ts +255 -0
  348. package/src/api/tagged.ts +35 -0
  349. package/src/cli/dto-check.ts +94 -0
  350. package/src/cli/fhirpath-check.ts +168 -0
  351. package/src/cli/ts-loader.mjs +49 -0
  352. package/src/engine/context.ts +282 -0
  353. package/src/engine/evaluator.ts +246 -0
  354. package/src/engine/navigation.ts +106 -0
  355. package/src/engine/operators/collections.ts +34 -0
  356. package/src/engine/operators/comparison.ts +82 -0
  357. package/src/engine/operators/equality.ts +232 -0
  358. package/src/engine/operators/index.ts +65 -0
  359. package/src/engine/operators/logic.ts +53 -0
  360. package/src/engine/operators/math.ts +225 -0
  361. package/src/engine/operators/strings.ts +25 -0
  362. package/src/engine/operators/types.ts +16 -0
  363. package/src/engine/type-matching.ts +148 -0
  364. package/src/errors.ts +33 -0
  365. package/src/eslint/index.ts +388 -0
  366. package/src/fhir/html-checks.ts +266 -0
  367. package/src/fhir/model-navigation.ts +148 -0
  368. package/src/functions/aggregate.ts +136 -0
  369. package/src/functions/boundary.ts +209 -0
  370. package/src/functions/combining.ts +15 -0
  371. package/src/functions/control.ts +25 -0
  372. package/src/functions/conversion.ts +349 -0
  373. package/src/functions/date-components.ts +88 -0
  374. package/src/functions/existence.ts +107 -0
  375. package/src/functions/fhir.ts +247 -0
  376. package/src/functions/filtering.ts +120 -0
  377. package/src/functions/install.ts +19 -0
  378. package/src/functions/iteration.ts +21 -0
  379. package/src/functions/math.ts +167 -0
  380. package/src/functions/reflection.ts +24 -0
  381. package/src/functions/registry.ts +72 -0
  382. package/src/functions/sort.ts +68 -0
  383. package/src/functions/string.ts +413 -0
  384. package/src/functions/subsetting.ts +89 -0
  385. package/src/functions/tree.ts +112 -0
  386. package/src/functions/type-specifier.ts +29 -0
  387. package/src/functions/utility.ts +82 -0
  388. package/src/functions/variables.ts +36 -0
  389. package/src/index.ts +30 -0
  390. package/src/lexer/lexer.ts +341 -0
  391. package/src/lexer/tokens.ts +69 -0
  392. package/src/model/provider.ts +36 -0
  393. package/src/parser/ast.ts +164 -0
  394. package/src/parser/parser.ts +321 -0
  395. package/src/parser/precedence.ts +52 -0
  396. package/src/parser/printer.ts +114 -0
  397. package/src/r4/generated/resources-data.ts +28631 -0
  398. package/src/r4/generated/type-maps.ts +22145 -0
  399. package/src/r4/generated/types-data.ts +2208 -0
  400. package/src/r4/index.ts +107 -0
  401. package/src/r4/model-data.ts +17 -0
  402. package/src/sites/index.ts +285 -0
  403. package/src/typed/infer.ts +433 -0
  404. package/src/typed/perf-fixture.types.ts +143 -0
  405. package/src/values/collection.ts +57 -0
  406. package/src/values/datetime.ts +285 -0
  407. package/src/values/decimal.ts +213 -0
  408. package/src/values/numeric.ts +63 -0
  409. package/src/values/quantity.ts +358 -0
  410. package/src/values/temporal-arithmetic.ts +231 -0
  411. package/src/values/temporal-compare.ts +65 -0
  412. package/src/values/type-compat.ts +133 -0
  413. package/src/values/typed-value.ts +151 -0
  414. package/src/values/ucum.ts +181 -0
@@ -0,0 +1,69 @@
1
+ import type { SourceSpan } from '../errors.ts'
2
+
3
+ export type TokenKind =
4
+ | 'identifier'
5
+ | 'delimitedIdentifier'
6
+ | 'string'
7
+ | 'number'
8
+ | 'date'
9
+ | 'dateTime'
10
+ | 'time'
11
+ | 'specialVariable'
12
+ | 'keyword'
13
+ | 'punct'
14
+ | 'operator'
15
+ | 'end'
16
+
17
+ export interface Token {
18
+ kind: TokenKind
19
+ /** Raw source text of the token. */
20
+ text: string
21
+ /**
22
+ * Decoded value where it differs from the raw text: escape sequences resolved for
23
+ * `string` and `delimitedIdentifier`, quotes/backticks/`@`/`$` stripped where applicable.
24
+ */
25
+ value: string
26
+ span: SourceSpan
27
+ }
28
+
29
+ /**
30
+ * Words the grammar treats as operators or literals. `as`, `contains`, `in`, `is`, `div` and
31
+ * `mod` may still appear as element names (the parser decides by position); calendar duration
32
+ * words (`year`, `months`, ...) lex as plain identifiers.
33
+ */
34
+ export const KEYWORDS: ReadonlySet<string> = new Set([
35
+ 'and',
36
+ 'or',
37
+ 'xor',
38
+ 'implies',
39
+ 'div',
40
+ 'mod',
41
+ 'in',
42
+ 'contains',
43
+ 'is',
44
+ 'as',
45
+ 'true',
46
+ 'false',
47
+ ])
48
+
49
+ export const SPECIAL_VARIABLES: ReadonlySet<string> = new Set(['$this', '$index', '$total'])
50
+
51
+ /** Calendar duration units usable in quantity literals, e.g. `4 days` (spec §4.1.4.7). */
52
+ export const CALENDAR_DURATION_UNITS: ReadonlySet<string> = new Set([
53
+ 'year',
54
+ 'years',
55
+ 'month',
56
+ 'months',
57
+ 'week',
58
+ 'weeks',
59
+ 'day',
60
+ 'days',
61
+ 'hour',
62
+ 'hours',
63
+ 'minute',
64
+ 'minutes',
65
+ 'second',
66
+ 'seconds',
67
+ 'millisecond',
68
+ 'milliseconds',
69
+ ])
@@ -0,0 +1,36 @@
1
+ /** Type and cardinality of one element of a class, from the model's ModelInfo. */
2
+ export interface ElementInfo {
3
+ /** Canonical type name(s); more than one for choice elements like `Observation.value[x]`. */
4
+ types: string[]
5
+ isCollection: boolean
6
+ /** True for `[x]` elements, whose JSON keys carry a type suffix (`valueQuantity`). */
7
+ isChoice: boolean
8
+ /**
9
+ * Resource type names a Reference-typed element may point to, from
10
+ * `Reference.targetProfile` — what resolve() statically yields. Absent when
11
+ * the element is not a reference or the reference is unconstrained.
12
+ */
13
+ referenceTargets?: string[]
14
+ }
15
+
16
+ /**
17
+ * The spec's ModelInfo concept (§10/§12.2): everything the engine and the static
18
+ * analyzer need to know about a data model. The core never assumes FHIR; the R4
19
+ * model package implements this from generated StructureDefinition data.
20
+ */
21
+ export interface ModelProvider {
22
+ /** Namespace prefix for the model's types, e.g. `FHIR`. */
23
+ namespace: string
24
+ /** Resolve an unqualified type name to its canonical name, or undefined if unknown. */
25
+ resolveType(name: string): string | undefined
26
+ /** Look up an element on a type, resolving choice elements by their stem name. */
27
+ getElement(type: string, element: string): ElementInfo | undefined
28
+ /** True when `type` equals or derives from `base` (both canonical). */
29
+ isSubtypeOf(type: string, base: string): boolean
30
+ /**
31
+ * All element names of a type, own and inherited, in declaration order.
32
+ * Undefined when the type is unknown to the model — navigation then falls back
33
+ * to raw JSON reads instead of strict unknown-element errors.
34
+ */
35
+ listElements?(type: string): string[] | undefined
36
+ }
@@ -0,0 +1,164 @@
1
+ import type { SourceSpan } from '../errors.ts'
2
+
3
+ export type BinaryOperator =
4
+ | '*'
5
+ | '/'
6
+ | 'div'
7
+ | 'mod'
8
+ | '+'
9
+ | '-'
10
+ | '&'
11
+ | '|'
12
+ | '<'
13
+ | '>'
14
+ | '<='
15
+ | '>='
16
+ | '='
17
+ | '~'
18
+ | '!='
19
+ | '!~'
20
+ | 'in'
21
+ | 'contains'
22
+ | 'and'
23
+ | 'or'
24
+ | 'xor'
25
+ | 'implies'
26
+
27
+ export type UnaryOperator = '+' | '-'
28
+
29
+ /** A possibly qualified type name, e.g. `Patient`, `FHIR.Patient`, or `System.Boolean`. */
30
+ export interface TypeSpecifier {
31
+ parts: string[]
32
+ span: SourceSpan
33
+ }
34
+
35
+ interface BaseNode {
36
+ span: SourceSpan
37
+ }
38
+
39
+ /** The empty collection literal `{}`. */
40
+ export interface NullLiteralNode extends BaseNode {
41
+ kind: 'null'
42
+ }
43
+
44
+ export interface BooleanLiteralNode extends BaseNode {
45
+ kind: 'boolean'
46
+ value: boolean
47
+ }
48
+
49
+ export interface StringLiteralNode extends BaseNode {
50
+ kind: 'string'
51
+ value: string
52
+ }
53
+
54
+ /** Integer, Long (5L), or Decimal literal; the raw text keeps float precision intact. */
55
+ export interface NumberLiteralNode extends BaseNode {
56
+ kind: 'number'
57
+ text: string
58
+ isDecimal: boolean
59
+ isLong?: boolean
60
+ }
61
+
62
+ export interface DateLiteralNode extends BaseNode {
63
+ kind: 'date'
64
+ /** Literal text without the `@`, e.g. `2014-01`. */
65
+ text: string
66
+ }
67
+
68
+ export interface DateTimeLiteralNode extends BaseNode {
69
+ kind: 'dateTime'
70
+ /** Literal text without the `@`, e.g. `2014-01-25T14:30:00Z` or `2014T`. */
71
+ text: string
72
+ }
73
+
74
+ export interface TimeLiteralNode extends BaseNode {
75
+ kind: 'time'
76
+ /** Literal text without the `@T`, e.g. `14:30`. */
77
+ text: string
78
+ }
79
+
80
+ export interface QuantityLiteralNode extends BaseNode {
81
+ kind: 'quantity'
82
+ value: string
83
+ unit: string
84
+ /** `'mg'` style UCUM strings vs bare calendar words like `days`. */
85
+ unitKind: 'ucum' | 'calendar'
86
+ }
87
+
88
+ /** A path segment or element name, e.g. `Patient` or `name`. */
89
+ export interface IdentifierNode extends BaseNode {
90
+ kind: 'identifier'
91
+ name: string
92
+ }
93
+
94
+ /** `$this`, `$index`, or `$total`. */
95
+ export interface SpecialVariableNode extends BaseNode {
96
+ kind: 'special'
97
+ name: 'this' | 'index' | 'total'
98
+ }
99
+
100
+ /** An environment variable, e.g. `%ucum` or `` %`vs-observation-vitalsignresult` ``. */
101
+ export interface ExternalConstantNode extends BaseNode {
102
+ kind: 'external'
103
+ name: string
104
+ }
105
+
106
+ export interface DotNode extends BaseNode {
107
+ kind: 'dot'
108
+ left: AstNode
109
+ right: AstNode
110
+ }
111
+
112
+ export interface IndexerNode extends BaseNode {
113
+ kind: 'indexer'
114
+ target: AstNode
115
+ index: AstNode
116
+ }
117
+
118
+ export interface FunctionCallNode extends BaseNode {
119
+ kind: 'call'
120
+ name: string
121
+ args: AstNode[]
122
+ }
123
+
124
+ export interface UnaryNode extends BaseNode {
125
+ kind: 'unary'
126
+ operator: UnaryOperator
127
+ operand: AstNode
128
+ }
129
+
130
+ export interface BinaryNode extends BaseNode {
131
+ kind: 'binary'
132
+ operator: BinaryOperator
133
+ left: AstNode
134
+ right: AstNode
135
+ }
136
+
137
+ /** `expr is Type` or `expr as Type`. */
138
+ export interface TypeOpNode extends BaseNode {
139
+ kind: 'typeOp'
140
+ operator: 'is' | 'as'
141
+ operand: AstNode
142
+ type: TypeSpecifier
143
+ }
144
+
145
+ export type AstNode =
146
+ | NullLiteralNode
147
+ | BooleanLiteralNode
148
+ | StringLiteralNode
149
+ | NumberLiteralNode
150
+ | DateLiteralNode
151
+ | DateTimeLiteralNode
152
+ | TimeLiteralNode
153
+ | QuantityLiteralNode
154
+ | IdentifierNode
155
+ | SpecialVariableNode
156
+ | ExternalConstantNode
157
+ | DotNode
158
+ | IndexerNode
159
+ | FunctionCallNode
160
+ | UnaryNode
161
+ | BinaryNode
162
+ | TypeOpNode
163
+
164
+ export type AstNodeKind = AstNode['kind']
@@ -0,0 +1,321 @@
1
+ // The Pratt parsing approach (prefix/infix parselets driven by a precedence table) is adapted
2
+ // from Medplum's FHIRPath parser (Apache-2.0):
3
+ // https://github.com/medplum/medplum/blob/main/packages/core/src/fhirlexer/parse.ts
4
+ import { FhirPathSyntaxError, type SourceSpan } from '../errors.ts'
5
+ import { tokenize } from '../lexer/lexer.ts'
6
+ import { CALENDAR_DURATION_UNITS, type Token } from '../lexer/tokens.ts'
7
+ import type { AstNode, BinaryOperator, TypeSpecifier, UnaryOperator } from './ast.ts'
8
+ import { BindingPower, INFIX_BINDING_POWER } from './precedence.ts'
9
+
10
+ /** Keywords the grammar also accepts as element names, e.g. `'abc'.contains('b')`. */
11
+ const KEYWORDS_USABLE_AS_IDENTIFIERS: ReadonlySet<string> = new Set(['as', 'contains', 'in', 'is'])
12
+
13
+ const TYPE_OPERATORS: ReadonlySet<string> = new Set(['is', 'as'])
14
+
15
+ /**
16
+ * Nesting far beyond anything a real expression uses. Without a cap, adversarial
17
+ * input like ((((…)))) overflows the call stack as a native RangeError instead of
18
+ * the FhirPathSyntaxError callers rely on catching.
19
+ */
20
+ const MAX_DEPTH = 500
21
+
22
+ class Parser {
23
+ private readonly tokens: Token[]
24
+ private pos = 0
25
+ private depth = 0
26
+ /** Parenthesized nodes can no longer take call parentheses: `(a)(b)` is not grammatical. */
27
+ private readonly parenthesized = new WeakSet<AstNode>()
28
+
29
+ constructor(source: string) {
30
+ this.tokens = tokenize(source)
31
+ }
32
+
33
+ parse(): AstNode {
34
+ const expression = this.parseExpression(0)
35
+ const trailing = this.peek()
36
+ if (trailing.kind !== 'end') {
37
+ throw this.error(`Unexpected '${trailing.text}' after expression`, trailing)
38
+ }
39
+ return expression
40
+ }
41
+
42
+ private parseExpression(minBindingPower: number): AstNode {
43
+ if (++this.depth > MAX_DEPTH) {
44
+ throw this.error(`Expression nesting exceeds ${MAX_DEPTH} levels`, this.peek())
45
+ }
46
+ try {
47
+ let left = this.parsePrefix()
48
+ for (;;) {
49
+ const token = this.peek()
50
+ const key = token.kind === 'operator' || token.kind === 'punct' || token.kind === 'keyword' ? token.text : ''
51
+ const bindingPower = INFIX_BINDING_POWER[key]
52
+ if (bindingPower === undefined || bindingPower <= minBindingPower) {
53
+ return left
54
+ }
55
+ this.advance()
56
+ left = this.parseInfix(left, token, bindingPower)
57
+ }
58
+ } finally {
59
+ this.depth--
60
+ }
61
+ }
62
+
63
+ private parsePrefix(): AstNode {
64
+ const token = this.peek()
65
+ switch (token.kind) {
66
+ case 'end':
67
+ throw this.error('Unexpected end of expression', token)
68
+ case 'number':
69
+ return this.parseNumberOrQuantity()
70
+ case 'string':
71
+ this.advance()
72
+ return { kind: 'string', value: token.value, span: token.span }
73
+ case 'date':
74
+ this.advance()
75
+ return { kind: 'date', text: token.value, span: token.span }
76
+ case 'dateTime':
77
+ this.advance()
78
+ return { kind: 'dateTime', text: token.value, span: token.span }
79
+ case 'time':
80
+ this.advance()
81
+ return { kind: 'time', text: token.value, span: token.span }
82
+ case 'specialVariable':
83
+ this.advance()
84
+ return { kind: 'special', name: token.value as 'this' | 'index' | 'total', span: token.span }
85
+ case 'identifier':
86
+ case 'delimitedIdentifier':
87
+ this.advance()
88
+ return { kind: 'identifier', name: token.value, span: token.span }
89
+ case 'keyword':
90
+ return this.parseKeywordPrefix(token)
91
+ case 'operator':
92
+ return this.parseUnary(token)
93
+ case 'punct':
94
+ return this.parsePunctPrefix(token)
95
+ /* v8 ignore start -- exhaustive fallback, every token kind has a case above */
96
+ default:
97
+ throw this.error(`Unexpected '${token.text}'`, token)
98
+ /* v8 ignore stop */
99
+ }
100
+ }
101
+
102
+ private parseKeywordPrefix(token: Token): AstNode {
103
+ if (token.text === 'true' || token.text === 'false') {
104
+ this.advance()
105
+ return { kind: 'boolean', value: token.text === 'true', span: token.span }
106
+ }
107
+ if (KEYWORDS_USABLE_AS_IDENTIFIERS.has(token.text)) {
108
+ this.advance()
109
+ return { kind: 'identifier', name: token.value, span: token.span }
110
+ }
111
+ throw this.error(`Unexpected '${token.text}'`, token)
112
+ }
113
+
114
+ private parseUnary(token: Token): AstNode {
115
+ if (token.text !== '+' && token.text !== '-') {
116
+ throw this.error(`Unexpected '${token.text}'`, token)
117
+ }
118
+ this.advance()
119
+ const operand = this.parseExpression(BindingPower.Unary)
120
+ return {
121
+ kind: 'unary',
122
+ operator: token.text as UnaryOperator,
123
+ operand,
124
+ span: this.spanBetween(token.span, operand.span),
125
+ }
126
+ }
127
+
128
+ private parsePunctPrefix(token: Token): AstNode {
129
+ switch (token.text) {
130
+ case '(': {
131
+ this.advance()
132
+ const inner = this.parseExpression(0)
133
+ this.expect(')')
134
+ this.parenthesized.add(inner)
135
+ return inner
136
+ }
137
+ case '{': {
138
+ this.advance()
139
+ const close = this.expect('}')
140
+ return { kind: 'null', span: this.spanBetween(token.span, close.span) }
141
+ }
142
+ case '%': {
143
+ this.advance()
144
+ const name = this.peek()
145
+ if (name.kind !== 'identifier' && name.kind !== 'delimitedIdentifier' && name.kind !== 'string') {
146
+ throw this.error('Expected a name after %', name)
147
+ }
148
+ this.advance()
149
+ return { kind: 'external', name: name.value, span: this.spanBetween(token.span, name.span) }
150
+ }
151
+ default:
152
+ throw this.error(`Unexpected '${token.text}'`, token)
153
+ }
154
+ }
155
+
156
+ private parseNumberOrQuantity(): AstNode {
157
+ const token = this.peek()
158
+ this.advance()
159
+ if (token.value.endsWith('L')) {
160
+ // Long literals take no quantity unit.
161
+ return { kind: 'number', text: token.value.slice(0, -1), isDecimal: false, isLong: true, span: token.span }
162
+ }
163
+ const next = this.peek()
164
+ if (next.kind === 'string') {
165
+ this.advance()
166
+ return {
167
+ kind: 'quantity',
168
+ value: token.value,
169
+ unit: next.value,
170
+ unitKind: 'ucum',
171
+ span: this.spanBetween(token.span, next.span),
172
+ }
173
+ }
174
+ if (next.kind === 'identifier' && CALENDAR_DURATION_UNITS.has(next.value)) {
175
+ this.advance()
176
+ return {
177
+ kind: 'quantity',
178
+ value: token.value,
179
+ unit: next.value,
180
+ unitKind: 'calendar',
181
+ span: this.spanBetween(token.span, next.span),
182
+ }
183
+ }
184
+ return { kind: 'number', text: token.value, isDecimal: token.value.includes('.'), span: token.span }
185
+ }
186
+
187
+ private parseInfix(left: AstNode, token: Token, bindingPower: number): AstNode {
188
+ switch (token.text) {
189
+ case '.':
190
+ return this.parseDot(left)
191
+ case '[': {
192
+ const index = this.parseExpression(0)
193
+ const close = this.expect(']')
194
+ return { kind: 'indexer', target: left, index, span: this.spanBetween(left.span, close.span) }
195
+ }
196
+ case '(':
197
+ return this.parseCall(left)
198
+ default:
199
+ break
200
+ }
201
+ if (TYPE_OPERATORS.has(token.text)) {
202
+ const type = this.parseTypeSpecifier()
203
+ return {
204
+ kind: 'typeOp',
205
+ operator: token.text as 'is' | 'as',
206
+ operand: left,
207
+ type,
208
+ span: this.spanBetween(left.span, type.span),
209
+ }
210
+ }
211
+ // All FHIRPath binary operators are left-associative, so the right side
212
+ // parses at this operator's own binding power.
213
+ const right = this.parseExpression(bindingPower)
214
+ return {
215
+ kind: 'binary',
216
+ operator: token.text as BinaryOperator,
217
+ left,
218
+ right,
219
+ span: this.spanBetween(left.span, right.span),
220
+ }
221
+ }
222
+
223
+ /**
224
+ * After `.`, only an element name, function call, or special variable may follow.
225
+ * Operator keywords are element names here, so `text.div` and `'abc'.contains('b')` work.
226
+ */
227
+ private parseDot(left: AstNode): AstNode {
228
+ const token = this.peek()
229
+ let right: AstNode
230
+ if (
231
+ token.kind === 'identifier' ||
232
+ token.kind === 'delimitedIdentifier' ||
233
+ (token.kind === 'keyword' && token.text !== 'true' && token.text !== 'false')
234
+ ) {
235
+ this.advance()
236
+ right = { kind: 'identifier', name: token.value, span: token.span }
237
+ if (this.peek().kind === 'punct' && this.peek().text === '(') {
238
+ this.advance()
239
+ right = this.parseCall(right)
240
+ }
241
+ } else if (token.kind === 'specialVariable') {
242
+ this.advance()
243
+ right = { kind: 'special', name: token.value as 'this' | 'index' | 'total', span: token.span }
244
+ } else {
245
+ throw this.error(`Expected an element or function name after '.', got '${token.text}'`, token)
246
+ }
247
+ return { kind: 'dot', left, right, span: this.spanBetween(left.span, right.span) }
248
+ }
249
+
250
+ private parseCall(target: AstNode): AstNode {
251
+ if (target.kind !== 'identifier' || this.parenthesized.has(target)) {
252
+ throw this.error('Unexpected parentheses', this.peek())
253
+ }
254
+ const args: AstNode[] = []
255
+ if (!(this.peek().kind === 'punct' && this.peek().text === ')')) {
256
+ args.push(this.parseExpression(0))
257
+ while (this.peek().kind === 'punct' && this.peek().text === ',') {
258
+ this.advance()
259
+ args.push(this.parseExpression(0))
260
+ }
261
+ }
262
+ const close = this.expect(')')
263
+ return { kind: 'call', name: target.name, args, span: this.spanBetween(target.span, close.span) }
264
+ }
265
+
266
+ private parseTypeSpecifier(): TypeSpecifier {
267
+ const first = this.expectTypeName()
268
+ const parts = [first.value]
269
+ let end = first.span
270
+ while (this.peek().kind === 'punct' && this.peek().text === '.') {
271
+ this.advance()
272
+ const part = this.expectTypeName()
273
+ parts.push(part.value)
274
+ end = part.span
275
+ }
276
+ return { parts, span: this.spanBetween(first.span, end) }
277
+ }
278
+
279
+ private expectTypeName(): Token {
280
+ const token = this.peek()
281
+ if (token.kind !== 'identifier' && token.kind !== 'delimitedIdentifier') {
282
+ throw this.error(`Expected a type name, got '${token.text}'`, token)
283
+ }
284
+ this.advance()
285
+ return token
286
+ }
287
+
288
+ private peek(): Token {
289
+ return this.tokens[this.pos] as Token
290
+ }
291
+
292
+ private advance(): Token {
293
+ const token = this.tokens[this.pos] as Token
294
+ if (token.kind !== 'end') {
295
+ this.pos += 1
296
+ }
297
+ return token
298
+ }
299
+
300
+ private expect(text: string): Token {
301
+ const token = this.peek()
302
+ if (token.text !== text) {
303
+ throw this.error(`Expected '${text}', got '${token.kind === 'end' ? 'end of expression' : token.text}'`, token)
304
+ }
305
+ this.advance()
306
+ return token
307
+ }
308
+
309
+ private error(message: string, token: Token): FhirPathSyntaxError {
310
+ return new FhirPathSyntaxError(message, token.span)
311
+ }
312
+
313
+ private spanBetween(start: SourceSpan, end: SourceSpan): SourceSpan {
314
+ return { start: start.start, end: end.end, line: start.line, column: start.column }
315
+ }
316
+ }
317
+
318
+ /** Parse a FHIRPath expression into its AST. Throws `FhirPathSyntaxError` with a position on bad input. */
319
+ export function parse(source: string): AstNode {
320
+ return new Parser(source).parse()
321
+ }
@@ -0,0 +1,52 @@
1
+ /**
2
+ * Binding powers derived from the spec's 13-level operator precedence table
3
+ * (https://hl7.org/fhirpath/#operator-precedence). Higher binds tighter; the
4
+ * spec numbers levels the other way around (1 = `.`, 13 = `implies`).
5
+ */
6
+ export const BindingPower = {
7
+ Implies: 1,
8
+ OrXor: 2,
9
+ And: 3,
10
+ Membership: 4,
11
+ Equality: 5,
12
+ Comparison: 6,
13
+ Union: 7,
14
+ TypeOps: 8,
15
+ Additive: 9,
16
+ Multiplicative: 10,
17
+ Unary: 11,
18
+ Indexer: 12,
19
+ Dot: 13,
20
+ FunctionCall: 14,
21
+ } as const
22
+
23
+ /** Binding power for every infix (and postfix) construct, keyed by token text. */
24
+ export const INFIX_BINDING_POWER: Readonly<Record<string, number>> = {
25
+ implies: BindingPower.Implies,
26
+ or: BindingPower.OrXor,
27
+ xor: BindingPower.OrXor,
28
+ and: BindingPower.And,
29
+ in: BindingPower.Membership,
30
+ contains: BindingPower.Membership,
31
+ '=': BindingPower.Equality,
32
+ '~': BindingPower.Equality,
33
+ '!=': BindingPower.Equality,
34
+ '!~': BindingPower.Equality,
35
+ '<': BindingPower.Comparison,
36
+ '>': BindingPower.Comparison,
37
+ '<=': BindingPower.Comparison,
38
+ '>=': BindingPower.Comparison,
39
+ '|': BindingPower.Union,
40
+ is: BindingPower.TypeOps,
41
+ as: BindingPower.TypeOps,
42
+ '+': BindingPower.Additive,
43
+ '-': BindingPower.Additive,
44
+ '&': BindingPower.Additive,
45
+ '*': BindingPower.Multiplicative,
46
+ '/': BindingPower.Multiplicative,
47
+ div: BindingPower.Multiplicative,
48
+ mod: BindingPower.Multiplicative,
49
+ '[': BindingPower.Indexer,
50
+ '.': BindingPower.Dot,
51
+ '(': BindingPower.FunctionCall,
52
+ }