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,308 @@
1
+ import type { CustomFunctionSignature } from '../analyzer/signatures.ts'
2
+ import {
3
+ createContext,
4
+ envCollections,
5
+ type EvaluationContext,
6
+ forkVariables,
7
+ type HostExpressionFunction,
8
+ type HostFunction,
9
+ type HostNativeFunction,
10
+ type HostSingleFunction,
11
+ normalizeEnvKeys,
12
+ type RegexEngine,
13
+ } from '../engine/context.ts'
14
+ import { evaluateNode } from '../engine/evaluator.ts'
15
+ import { FhirPathTypeError } from '../errors.ts'
16
+ import type { ModelProvider } from '../model/provider.ts'
17
+ import type { AstNode } from '../parser/ast.ts'
18
+ import { parse } from '../parser/parser.ts'
19
+ import { printExpression } from '../parser/printer.ts'
20
+ import type { R4TypeOf } from '../r4/generated/type-maps.ts'
21
+ import type { FhirpathInput, FhirpathResult, FhirpathResultIn, FhirTypeName } from '../typed/infer.ts'
22
+ import { toCollection, type TypedValue, unwrap } from '../values/typed-value.ts'
23
+ import { LruCache } from './cache.ts'
24
+
25
+ /**
26
+ * A native or expression-defined FHIRPath function. Native functions receive
27
+ * evaluated JavaScript values. Expression functions take no arguments, keep
28
+ * FHIRPath types, and use the call focus with the caller's `%context` and
29
+ * environment. A signature lets the analyzer check either form. Built-in names
30
+ * cannot be replaced.
31
+ */
32
+ export type SingleCustomFunction =
33
+ | (HostNativeFunction & {
34
+ signature?: CustomFunctionSignature
35
+ expression?: never
36
+ criteria?: never
37
+ /** Only an expression body reads `%name`; a native `fn` gets plain values. */
38
+ env?: never
39
+ })
40
+ | {
41
+ expression: AnyExpression
42
+ signature?: CustomFunctionSignature
43
+ /** Environment values available only while this expression body runs. */
44
+ env?: Record<string, unknown>
45
+ /** Return one criteria Boolean. An empty body result becomes `false`. */
46
+ criteria?: boolean
47
+ fn?: never
48
+ minArity?: never
49
+ maxArity?: never
50
+ }
51
+
52
+ /** Same-name functions selected in order by `signature.input.types`. */
53
+ export interface OverloadedCustomFunction {
54
+ overloads: readonly SingleCustomFunction[]
55
+ fn?: never
56
+ expression?: never
57
+ signature?: never
58
+ criteria?: never
59
+ env?: never
60
+ minArity?: never
61
+ maxArity?: never
62
+ }
63
+
64
+ export type CustomFunction = SingleCustomFunction | OverloadedCustomFunction
65
+
66
+ export interface EvaluateOptions {
67
+ /** Environment variables (`%name`), keyed with or without the leading `%`. */
68
+ env?: Record<string, unknown>
69
+ /**
70
+ * FHIRPath bindings evaluated against the input in declaration order. They
71
+ * keep FHIRPath types and may use `%context`, `env`, and earlier variables.
72
+ * During projection they run once per row. A `TypedValue[]` binds directly.
73
+ */
74
+ vars?: Record<string, AnyExpression | readonly TypedValue[]>
75
+ model?: ModelProvider
76
+ /** Clock for `now()`, `today()`, and `timeOfDay()`. Defaults to the current time. */
77
+ now?: Date
78
+ /**
79
+ * Sink for trace(name, ...) calls. No default logging: traced values may contain
80
+ * patient data, so sending them anywhere is an explicit choice.
81
+ */
82
+ trace?: (name: string, values: TypedValue[]) => void
83
+ /** Host functions by name. Pass the same declarations to `AnalyzeOptions.functions`. */
84
+ functions?: Record<string, CustomFunction>
85
+ /**
86
+ * Regex engine for matches()/matchesFull()/replaceMatches(). The default is
87
+ * the built-in RegExp, which backtracks and cannot be timed out — supply a
88
+ * linear-time engine (e.g. an RE2 binding) when evaluating untrusted
89
+ * expressions (see README, Security).
90
+ */
91
+ regex?: RegexEngine
92
+ }
93
+
94
+ /**
95
+ * A parsed expression, reusable across inputs. Create via `compile()` or the
96
+ * `fhirpath` tag: literal expressions carry inferred result and input types for
97
+ * the supported subset (see src/typed/infer.ts), everything else is unknown[].
98
+ *
99
+ * `TInput`/`TResult` default to the built-in inference but can be overridden,
100
+ * e.g. with `@medplum/fhirtypes` types, for full type-level fidelity with
101
+ * another FHIR type package: `compile<'Patient.name', Patient, HumanName[]>(...)`.
102
+ */
103
+ export class CompiledExpression<
104
+ Expr extends string = string,
105
+ TInput = FhirpathInput<Expr>,
106
+ TResult extends unknown[] = FhirpathResult<Expr>,
107
+ > {
108
+ readonly source: string
109
+ readonly ast: AstNode
110
+
111
+ constructor(source: Expr) {
112
+ this.source = source
113
+ this.ast = parse(source)
114
+ }
115
+
116
+ /** Evaluate and unwrap results to plain JS values. */
117
+ evaluate(input?: TInput, options?: EvaluateOptions): TResult {
118
+ return this.evaluateTyped(input, options).map(unwrap) as TResult
119
+ }
120
+
121
+ /** Evaluate keeping the internal typed representation (types, Decimal, Temporal). */
122
+ evaluateTyped(input?: unknown, options?: EvaluateOptions): TypedValue[] {
123
+ const root = toCollection(input)
124
+ return evaluateNode(this.ast, contextFactory(options)(root), root)
125
+ }
126
+
127
+ /** The canonical form of the expression. */
128
+ toString(): string {
129
+ return printExpression(this.ast)
130
+ }
131
+ }
132
+
133
+ /**
134
+ * Parse an expression once for reuse. Unlike `evaluate()`, does not touch the
135
+ * parse cache. A second argument declares the type the expression runs against,
136
+ * so a relative path infers like a DTO column and the static checkers analyze it
137
+ * against that type — see `fhirpath`, which takes the same declaration.
138
+ */
139
+ export function compile<
140
+ const Expr extends string,
141
+ const Root extends FhirTypeName,
142
+ TResult extends unknown[] = FhirpathResultIn<Expr, Root>,
143
+ >(expression: Expr, inputType: Root): CompiledExpression<Expr, R4TypeOf[Root], TResult>
144
+ export function compile<
145
+ const Expr extends string,
146
+ TInput = FhirpathInput<Expr>,
147
+ TResult extends unknown[] = FhirpathResult<Expr>,
148
+ >(expression: Expr): CompiledExpression<Expr, TInput, TResult>
149
+ export function compile(expression: string): CompiledExpression {
150
+ // A declared input type is a compile-time and check-time declaration (see
151
+ // `fhirpath`), with nothing for the evaluator to do.
152
+ return new CompiledExpression(expression)
153
+ }
154
+
155
+ /** An expression as text or already compiled, with any literal type. */
156
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any -- accepts any literal-typed CompiledExpression
157
+ export type AnyExpression = string | CompiledExpression<any>
158
+
159
+ /** A pre-resolved `vars` value; Array.isArray alone cannot exclude readonly arrays for the checker. */
160
+ function isResolvedCollection<T>(value: T | readonly TypedValue[]): value is readonly TypedValue[] {
161
+ return Array.isArray(value)
162
+ }
163
+
164
+ /** Bind planned vars into a fresh context (see contextFactory for the scoping rules). */
165
+ function bindVars(context: EvaluationContext, vars: readonly PlannedVar[]): void {
166
+ for (const [name, value] of vars) {
167
+ if (context.env.has(name)) {
168
+ throw new FhirPathTypeError(`Cannot override the environment variable %${name} with a var`)
169
+ }
170
+ context.variables.set(
171
+ name,
172
+ isResolvedCollection(value) ? [...value] : evaluateNode(value, forkVariables(context), context.root)
173
+ )
174
+ }
175
+ }
176
+
177
+ /** One `vars` entry taken apart at factory time: a parsed body, or a pre-resolved collection. */
178
+ type PlannedVar = readonly [name: string, value: AstNode | readonly TypedValue[]]
179
+
180
+ /** Take a `vars` record apart once — keys normalize, string bodies parse — keeping declaration order. */
181
+ function planVars(vars: Record<string, AnyExpression | readonly TypedValue[]>): PlannedVar[] {
182
+ return Object.entries(normalizeEnvKeys(vars)).map(([name, value]) => {
183
+ if (typeof value === 'string') {
184
+ return [name, parse(value)] as const
185
+ }
186
+ return [name, isResolvedCollection(value) ? value : value.ast] as const
187
+ })
188
+ }
189
+
190
+ /**
191
+ * Prepares options once, then creates an evaluation context for each root.
192
+ * Variables bind in order. `extraEnv` contains call-specific values, such as
193
+ * projection row numbers, and replaces matching option values.
194
+ */
195
+ export function contextFactory(
196
+ options: EvaluateOptions | undefined
197
+ ): (root: TypedValue[], extraEnv?: Record<string, unknown>) => EvaluationContext {
198
+ const functions = options?.functions === undefined ? undefined : toHostFunctions(options.functions)
199
+ const env = normalizeEnvKeys(options?.env)
200
+ const vars = options?.vars === undefined ? undefined : planVars(options.vars)
201
+ return (root, extraEnv) => {
202
+ const context = createContext({
203
+ root,
204
+ env: extraEnv === undefined ? env : { ...env, ...extraEnv },
205
+ model: options?.model,
206
+ now: options?.now,
207
+ trace: options?.trace,
208
+ functions,
209
+ regex: options?.regex,
210
+ })
211
+ if (vars !== undefined) {
212
+ bindVars(context, vars)
213
+ }
214
+ return context
215
+ }
216
+ }
217
+
218
+ /**
219
+ * Converts CustomFunctions to their runtime form. Expression bodies parse to
220
+ * ASTs, and the declared input types come across for the engine to check. The
221
+ * rest of the signature stays in the API layer, which is the analyzer's half.
222
+ */
223
+ function toHostFunctions(functions: Record<string, CustomFunction>): Record<string, HostFunction> {
224
+ const host: Record<string, HostFunction> = {}
225
+ for (const [name, custom] of Object.entries(functions)) {
226
+ host[name] =
227
+ 'overloads' in custom
228
+ ? { overloads: custom.overloads.map(overload => toHostFunction(name, overload)) }
229
+ : toHostFunction(name, custom)
230
+ }
231
+ return host
232
+ }
233
+
234
+ function toHostFunction(name: string, custom: SingleCustomFunction): HostSingleFunction {
235
+ if ('expression' in custom) {
236
+ if ('fn' in custom) {
237
+ throw new FhirPathTypeError(`Custom function '${name}' declares both 'fn' and 'expression'; use one`)
238
+ }
239
+ return hostExpressionFunction(custom)
240
+ }
241
+ const inputTypes = custom.signature?.input?.types
242
+ // Copy rather than pass through. `custom` is the caller's own object, and the
243
+ // runtime form carries fields the API form does not.
244
+ return inputTypes === undefined ? custom : { ...custom, inputTypes }
245
+ }
246
+
247
+ /** The runtime form of an expression-defined CustomFunction: its body, plus what the engine checks around it. */
248
+ function hostExpressionFunction(
249
+ custom: Extract<SingleCustomFunction, { expression: AnyExpression }>
250
+ ): HostExpressionFunction {
251
+ const { expression, signature } = custom
252
+ const inputTypes = signature?.input?.types
253
+ return {
254
+ ast: typeof expression === 'string' ? parse(expression) : expression.ast,
255
+ ...(inputTypes !== undefined && { inputTypes }),
256
+ ...(custom.env !== undefined && { env: envOverlay(custom.env) }),
257
+ ...(custom.criteria === true && { criteria: true }),
258
+ }
259
+ }
260
+
261
+ /**
262
+ * Overlays already built, by the env record they were built from. A context
263
+ * factory is made per evaluation and resolves every host function, so without
264
+ * this a DTO's tables would be re-wrapped on every `evaluate()` — including
265
+ * evaluations that never call one of its columns. The record is the DTO's
266
+ * cached definition, one object shared by all of its columns, so the entry is
267
+ * reached again on the next evaluation and released with the class.
268
+ */
269
+ const overlays = new WeakMap<object, ReadonlyMap<string, TypedValue[]>>()
270
+
271
+ /** A definition's own env as the collections the context binds, wrapped once per record. */
272
+ function envOverlay(env: Record<string, unknown>): ReadonlyMap<string, TypedValue[]> {
273
+ let overlay = overlays.get(env)
274
+ if (overlay === undefined) {
275
+ overlay = envCollections(env)
276
+ overlays.set(env, overlay)
277
+ }
278
+ return overlay
279
+ }
280
+
281
+ /** Default for `EngineOptions.cacheSize`, matching Firely's FhirPathCompilerCache default. */
282
+ export const DEFAULT_PARSE_CACHE_SIZE = 500
283
+
284
+ /**
285
+ * Parses an expression, reusing an earlier parse of the same text while it is
286
+ * still cached. An already-compiled expression passes through untouched.
287
+ */
288
+ export type Compiler = (expression: AnyExpression) => CompiledExpression<string>
289
+
290
+ /**
291
+ * A compiler over its own LRU of `capacity` distinct expression texts (`0`
292
+ * caches nothing). Each owner holds one — every `FhirPathEngine`, and the free
293
+ * `evaluate()` — so parses are never reused across them.
294
+ */
295
+ export function createCachedCompiler(capacity: number = DEFAULT_PARSE_CACHE_SIZE): Compiler {
296
+ const cache = new LruCache<CompiledExpression>(capacity)
297
+ return expression => {
298
+ if (typeof expression !== 'string') {
299
+ return expression
300
+ }
301
+ let compiled = cache.get(expression)
302
+ if (!compiled) {
303
+ compiled = new CompiledExpression(expression)
304
+ cache.set(expression, compiled)
305
+ }
306
+ return compiled
307
+ }
308
+ }
@@ -0,0 +1,104 @@
1
+ import { FhirPathError } from '../errors.ts'
2
+ import { criteriaBoolean } from '../values/collection.ts'
3
+ import { isBundle, toSubjects } from './bundle.ts'
4
+ import type { Compiler, EvaluateOptions } from './compile.ts'
5
+
6
+ /** An invariant to check, shaped like FHIR's `ElementDefinition.constraint`. */
7
+ export interface FhirConstraint {
8
+ /** Constraint id, e.g. `pat-1`. */
9
+ key: string
10
+ /** `error` (default) fails validation; `warning` is reported but does not. */
11
+ severity?: 'error' | 'warning'
12
+ /** Human-readable description of the rule. */
13
+ human?: string
14
+ /** FHIRPath expression that must evaluate to true. */
15
+ expression: string
16
+ }
17
+
18
+ /** A constraint that did not hold, echoing its definition. */
19
+ export interface ConstraintIssue {
20
+ key: string
21
+ severity: 'error' | 'warning'
22
+ human?: string
23
+ expression: string
24
+ /** Set when the expression itself failed to parse or evaluate, with the engine error. */
25
+ error?: string
26
+ /** For array or Bundle inputs: position of the failing resource (in the array, or in `Bundle.entry`). */
27
+ index?: number
28
+ }
29
+
30
+ /** Minimal OperationOutcome shape; structurally assignable to the full R4 type. */
31
+ export interface OperationOutcome {
32
+ resourceType: 'OperationOutcome'
33
+ issue: {
34
+ severity: 'error' | 'warning' | 'information'
35
+ code: 'invariant' | 'informational'
36
+ details: { text: string }
37
+ diagnostics?: string
38
+ /** For Bundle inputs: FHIRPath to the failing entry resource, e.g. `Bundle.entry[3].resource`. */
39
+ expression?: string[]
40
+ }[]
41
+ }
42
+
43
+ export interface ConstraintCheckResult {
44
+ /** True when no error-severity constraint failed; warnings do not invalidate. */
45
+ valid: boolean
46
+ /** The constraints that failed (both severities), in input order. */
47
+ issues: ConstraintIssue[]
48
+ /** The same issues as a FHIR OperationOutcome (`issue.code = 'invariant'`, validator-style). */
49
+ toOperationOutcome(): OperationOutcome
50
+ }
51
+
52
+ /** Implementation behind `FhirPathEngine.checkConstraints`; options come pre-merged. */
53
+ export function evaluateConstraints(
54
+ input: unknown,
55
+ constraints: readonly FhirConstraint[],
56
+ options: EvaluateOptions,
57
+ compile: Compiler
58
+ ): ConstraintCheckResult {
59
+ const bundle = isBundle(input)
60
+ const issues: ConstraintIssue[] = []
61
+ for (const subject of toSubjects(input)) {
62
+ for (const constraint of constraints) {
63
+ const issue: ConstraintIssue = {
64
+ key: constraint.key,
65
+ severity: constraint.severity ?? 'error',
66
+ expression: constraint.expression,
67
+ ...(constraint.human === undefined ? {} : { human: constraint.human }),
68
+ ...(subject.index === undefined ? {} : { index: subject.index }),
69
+ }
70
+ try {
71
+ if (!criteriaBoolean(compile(constraint.expression).evaluateTyped(subject.value, options))) {
72
+ issues.push(issue)
73
+ }
74
+ } catch (error) {
75
+ issue.error = error instanceof FhirPathError ? error.message : String(error)
76
+ issues.push(issue)
77
+ }
78
+ }
79
+ }
80
+ return {
81
+ valid: issues.every(issue => issue.severity !== 'error'),
82
+ issues,
83
+ toOperationOutcome: () => toOperationOutcome(issues, bundle),
84
+ }
85
+ }
86
+
87
+ function toOperationOutcome(issues: ConstraintIssue[], bundle: boolean): OperationOutcome {
88
+ if (issues.length === 0) {
89
+ return {
90
+ resourceType: 'OperationOutcome',
91
+ issue: [{ severity: 'information', code: 'informational', details: { text: 'All constraints passed' } }],
92
+ }
93
+ }
94
+ return {
95
+ resourceType: 'OperationOutcome',
96
+ issue: issues.map(issue => ({
97
+ severity: issue.severity,
98
+ code: 'invariant',
99
+ details: { text: issue.human ?? `Constraint ${issue.key} failed` },
100
+ diagnostics: issue.error === undefined ? issue.expression : `${issue.expression} (${issue.error})`,
101
+ ...(bundle && issue.index !== undefined ? { expression: [`Bundle.entry[${issue.index}].resource`] } : {}),
102
+ })),
103
+ }
104
+ }