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,133 @@
1
+ /** Shared, conservative type compatibility for runtime dispatch and static checks. */
2
+ import type { ModelProvider } from '../model/provider.ts'
3
+ import { FHIR_PRIMITIVE_TO_SYSTEM, typeLocalName } from './typed-value.ts'
4
+
5
+ /** Behavior families used by the static checks. */
6
+ export type ValueKind = 'Boolean' | 'String' | 'Numeric' | 'Temporal' | 'Quantity' | 'Complex'
7
+
8
+ export function valueKindOfTypeName(canonical: string): ValueKind {
9
+ const system = canonical.startsWith('System.') ? canonical : FHIR_PRIMITIVE_TO_SYSTEM[typeLocalName(canonical)]
10
+ switch (system) {
11
+ case 'System.Boolean':
12
+ return 'Boolean'
13
+ case 'System.String':
14
+ return 'String'
15
+ case 'System.Integer':
16
+ case 'System.Long':
17
+ case 'System.Decimal':
18
+ return 'Numeric'
19
+ case 'System.Date':
20
+ case 'System.DateTime':
21
+ case 'System.Time':
22
+ return 'Temporal'
23
+ case 'System.Quantity':
24
+ return 'Quantity'
25
+ default:
26
+ return canonical === 'FHIR.Quantity' || typeLocalName(canonical) === 'Quantity' ? 'Quantity' : 'Complex'
27
+ }
28
+ }
29
+
30
+ /**
31
+ * Resolves a focus type through its full name, then its local name. Unknown names
32
+ * return undefined so callers can skip claims the model cannot support.
33
+ */
34
+ export function canonicalFocusType(model: ModelProvider, raw: string): string | undefined {
35
+ if (raw.startsWith('System.')) {
36
+ return raw
37
+ }
38
+ return model.resolveType(raw) ?? model.resolveType(typeLocalName(raw))
39
+ }
40
+
41
+ /** True when every `type` value is a `base` value, including FHIR-primitive → System subtyping. */
42
+ function typeSatisfies(model: ModelProvider, type: string, base: string): boolean {
43
+ if (type === base || model.isSubtypeOf(type, base)) {
44
+ return true
45
+ }
46
+ return base.startsWith('System.') && FHIR_PRIMITIVE_TO_SYSTEM[typeLocalName(type)] === base
47
+ }
48
+
49
+ /**
50
+ * Returns whether one value may have both types. Compatible value kinds and
51
+ * either direction of the model hierarchy count. The model check must still run
52
+ * when kinds differ because `SimpleQuantity` and `Quantity` use different kinds.
53
+ */
54
+ export function typesOverlap(model: ModelProvider, a: string, b: string): boolean {
55
+ const kind = valueKindOfTypeName(a)
56
+ if (kind !== 'Complex' && kind === valueKindOfTypeName(b)) {
57
+ return true
58
+ }
59
+ return typeSatisfies(model, a, b) || typeSatisfies(model, b, a)
60
+ }
61
+
62
+ /**
63
+ * The proof that a call is on the wrong focus: `wanted` lists the declared
64
+ * types and `found` lists the focus types, both as canonical names with
65
+ * duplicates removed. Callers report those two lists and add nothing of their
66
+ * own.
67
+ */
68
+ export interface UnsatisfiedInput {
69
+ wanted: string[]
70
+ found: string[]
71
+ }
72
+
73
+ /**
74
+ * Returns proof only when every known focus type is incompatible with every
75
+ * declared input type. Missing models, unknown types, empty focus, and any
76
+ * matching type remain allowed. Runtime dispatch and the analyzer share this
77
+ * decision and report it in their own way.
78
+ */
79
+ export function unsatisfiedInput(
80
+ model: ModelProvider | undefined,
81
+ declared: readonly string[] | undefined,
82
+ focus: Iterable<string>
83
+ ): UnsatisfiedInput | undefined {
84
+ if (model === undefined || declared === undefined) {
85
+ return undefined
86
+ }
87
+ const wanted = declared
88
+ .map(type => canonicalFocusType(model, type))
89
+ .filter((type): type is string => type !== undefined)
90
+ if (wanted.length === 0) {
91
+ return undefined
92
+ }
93
+ const found = new Set<string>()
94
+ for (const type of focus) {
95
+ const canonical = canonicalFocusType(model, type)
96
+ if (canonical === undefined || wanted.some(want => typesOverlap(model, canonical, want))) {
97
+ return undefined
98
+ }
99
+ found.add(canonical)
100
+ }
101
+ return found.size === 0 ? undefined : { wanted, found: [...found] }
102
+ }
103
+
104
+ /** Either the declaration a call resolves to, or the proof that none of them fits. */
105
+ export type InputResolution<T> = { resolved: T } | { unsatisfied: UnsatisfiedInput }
106
+
107
+ /**
108
+ * Selects the first same-name declaration accepted by the focus. If none fits,
109
+ * the result combines their expected and found types into one error. Unknown or
110
+ * empty focus selects the first declaration; registration prevents ambiguous
111
+ * known focus types.
112
+ */
113
+ export function resolveByInput<T>(
114
+ model: ModelProvider | undefined,
115
+ candidates: readonly T[],
116
+ declaredTypesOf: (candidate: T) => readonly string[] | undefined,
117
+ focus: readonly string[]
118
+ ): InputResolution<T> {
119
+ const misses: UnsatisfiedInput[] = []
120
+ for (const candidate of candidates) {
121
+ const miss = unsatisfiedInput(model, declaredTypesOf(candidate), focus)
122
+ if (miss === undefined) {
123
+ return { resolved: candidate }
124
+ }
125
+ misses.push(miss)
126
+ }
127
+ return {
128
+ unsatisfied: {
129
+ wanted: [...new Set(misses.flatMap(miss => miss.wanted))],
130
+ found: [...new Set(misses.flatMap(miss => miss.found))],
131
+ },
132
+ }
133
+ }
@@ -0,0 +1,151 @@
1
+ import type { Temporal } from './datetime.ts'
2
+ import { Decimal } from './decimal.ts'
3
+
4
+ export const SYSTEM_BOOLEAN = 'System.Boolean'
5
+ export const SYSTEM_STRING = 'System.String'
6
+ export const SYSTEM_INTEGER = 'System.Integer'
7
+ export const SYSTEM_LONG = 'System.Long'
8
+ export const SYSTEM_DECIMAL = 'System.Decimal'
9
+ export const SYSTEM_DATE = 'System.Date'
10
+ export const SYSTEM_DATETIME = 'System.DateTime'
11
+ export const SYSTEM_TIME = 'System.Time'
12
+ export const SYSTEM_QUANTITY = 'System.Quantity'
13
+
14
+ /** Placeholder type for plain objects when no model knows better. */
15
+ export const OBJECT_TYPE = 'Object'
16
+
17
+ /** A minimal Quantity value; unit algebra and UCUM conversion land in the quantity phase. */
18
+ export interface QuantityValue {
19
+ value: Decimal
20
+ unit: string
21
+ /** True for calendar duration units (`4 days`), false for UCUM strings (`4 'd'`). */
22
+ calendar: boolean
23
+ }
24
+
25
+ /**
26
+ * A value paired with its type name, e.g. `System.Integer` or `FHIR.Patient`.
27
+ * Runtime representations: Boolean → boolean, String → string, Integer → number,
28
+ * Long → bigint, Decimal → Decimal, Date/DateTime/Time → Temporal,
29
+ * Quantity → QuantityValue, complex types → raw JSON.
30
+ */
31
+ export interface TypedValue {
32
+ type: string
33
+ value: unknown
34
+ /** For FHIR primitives navigated with a model: the `_field` sibling (id/extension). */
35
+ primitiveElement?: unknown
36
+ }
37
+
38
+ /** FHIR primitive type names to their System twins (FHIR spec "types" page). */
39
+ export const FHIR_PRIMITIVE_TO_SYSTEM: Readonly<Record<string, string>> = {
40
+ boolean: 'System.Boolean',
41
+ integer: 'System.Integer',
42
+ positiveInt: 'System.Integer',
43
+ unsignedInt: 'System.Integer',
44
+ integer64: 'System.Long',
45
+ decimal: 'System.Decimal',
46
+ date: 'System.Date',
47
+ dateTime: 'System.DateTime',
48
+ instant: 'System.DateTime',
49
+ time: 'System.Time',
50
+ string: 'System.String',
51
+ code: 'System.String',
52
+ id: 'System.String',
53
+ markdown: 'System.String',
54
+ uri: 'System.String',
55
+ url: 'System.String',
56
+ canonical: 'System.String',
57
+ oid: 'System.String',
58
+ uuid: 'System.String',
59
+ base64Binary: 'System.String',
60
+ xhtml: 'System.String',
61
+ }
62
+
63
+ /**
64
+ * The System type a value behaves as: System types answer themselves, FHIR
65
+ * primitives answer their twin (`FHIR.code` → `System.String`), everything else
66
+ * undefined. Operators dispatch on this so FHIR-typed primitives keep working.
67
+ */
68
+ export function systemTypeOf(item: TypedValue): string | undefined {
69
+ if (item.type.startsWith('System.')) {
70
+ return item.type
71
+ }
72
+ return FHIR_PRIMITIVE_TO_SYSTEM[typeLocalName(item.type)]
73
+ }
74
+
75
+ /** The local part of a qualified type name: `System.Boolean` → `Boolean`. */
76
+ export function typeLocalName(type: string): string {
77
+ const separator = type.lastIndexOf('.')
78
+ return separator === -1 ? type : type.slice(separator + 1)
79
+ }
80
+
81
+ /** Wrap a raw JSON value, inferring System types where possible. */
82
+ export function toTypedValue(value: unknown): TypedValue {
83
+ if (typeof value === 'boolean') {
84
+ return { type: SYSTEM_BOOLEAN, value }
85
+ }
86
+ if (typeof value === 'string') {
87
+ return { type: SYSTEM_STRING, value }
88
+ }
89
+ if (typeof value === 'bigint') {
90
+ return { type: SYSTEM_LONG, value }
91
+ }
92
+ if (typeof value === 'number') {
93
+ if (Number.isSafeInteger(value)) {
94
+ return { type: SYSTEM_INTEGER, value }
95
+ }
96
+ const decimal = Decimal.fromNumber(value)
97
+ // NaN/Infinity have no FHIRPath representation; keep them opaque so operations
98
+ // against them fail with a clean type error instead of a raw TypeError.
99
+ return decimal === undefined ? { type: OBJECT_TYPE, value } : { type: SYSTEM_DECIMAL, value: decimal }
100
+ }
101
+ if (value instanceof Decimal) {
102
+ return { type: SYSTEM_DECIMAL, value }
103
+ }
104
+ if (isResource(value)) {
105
+ return { type: `FHIR.${value.resourceType}`, value }
106
+ }
107
+ return { type: OBJECT_TYPE, value }
108
+ }
109
+
110
+ function isResource(value: unknown): value is { resourceType: string } {
111
+ return (
112
+ typeof value === 'object' &&
113
+ value !== null &&
114
+ typeof (value as { resourceType?: unknown }).resourceType === 'string'
115
+ )
116
+ }
117
+
118
+ /** Wrap an input (single value, array, or undefined) as a collection. */
119
+ export function toCollection(value: unknown): TypedValue[] {
120
+ if (value === undefined || value === null) {
121
+ return []
122
+ }
123
+ if (Array.isArray(value)) {
124
+ return value.flatMap(item => toCollection(item))
125
+ }
126
+ return [toTypedValue(value)]
127
+ }
128
+
129
+ /** Unwrap for the public API: internal value objects become plain JS values. */
130
+ export function unwrap(typed: TypedValue): unknown {
131
+ const value = typed.value
132
+ if (value instanceof Decimal) {
133
+ return value.toNumber()
134
+ }
135
+ if (isTemporal(value)) {
136
+ return value.toString()
137
+ }
138
+ if (isQuantity(typed)) {
139
+ const quantity = value as QuantityValue
140
+ return { value: quantity.value.toNumber(), unit: quantity.unit }
141
+ }
142
+ return value
143
+ }
144
+
145
+ function isTemporal(value: unknown): value is Temporal {
146
+ return typeof value === 'object' && value !== null && 'kind' in value && 'toLiteralString' in value
147
+ }
148
+
149
+ function isQuantity(typed: TypedValue): boolean {
150
+ return typed.type === SYSTEM_QUANTITY
151
+ }
@@ -0,0 +1,181 @@
1
+ import { Decimal } from './decimal.ts'
2
+
3
+ /**
4
+ * Minimal UCUM support: enough units for quantity comparison, conversion, and the
5
+ * official test suites. Factors are exact Decimals, so `1 'm' = 100 'cm'` holds
6
+ * without float drift. Anything outside this table still works as an opaque unit
7
+ * that only compares with itself. Full UCUM (@lhncbc/ucum-lhc) is the documented
8
+ * upgrade path if conformance ever needs it.
9
+ */
10
+
11
+ /** Base dimensions; every known unit reduces to a product of these. */
12
+ type Dimension = 'g' | 'm' | 's' | 'mol' | '1'
13
+
14
+ interface UnitAtom {
15
+ dimension: Dimension
16
+ /** Factor to the base unit of the dimension, as an exact decimal string. */
17
+ factor: string
18
+ /** Prefixable per UCUM metadata; bracketed and derived units are not. */
19
+ prefixable: boolean
20
+ }
21
+
22
+ const ATOMS: Readonly<Record<string, UnitAtom>> = {
23
+ m: { dimension: 'm', factor: '1', prefixable: true },
24
+ g: { dimension: 'g', factor: '1', prefixable: true },
25
+ s: { dimension: 's', factor: '1', prefixable: true },
26
+ mol: { dimension: 'mol', factor: '1', prefixable: true },
27
+ L: { dimension: 'm', factor: '0.001', prefixable: true }, // handled as m^3 via exponent bump below
28
+ l: { dimension: 'm', factor: '0.001', prefixable: true },
29
+ min: { dimension: 's', factor: '60', prefixable: false },
30
+ h: { dimension: 's', factor: '3600', prefixable: false },
31
+ d: { dimension: 's', factor: '86400', prefixable: false },
32
+ wk: { dimension: 's', factor: '604800', prefixable: false },
33
+ // UCUM's annum is the Julian year; the Julian month is a twelfth of it.
34
+ a: { dimension: 's', factor: '31557600', prefixable: false },
35
+ mo: { dimension: 's', factor: '2629800', prefixable: false },
36
+ '[lb_av]': { dimension: 'g', factor: '453.59237', prefixable: false },
37
+ '[oz_av]': { dimension: 'g', factor: '28.349523125', prefixable: false },
38
+ '[in_i]': { dimension: 'm', factor: '0.0254', prefixable: false },
39
+ '[ft_i]': { dimension: 'm', factor: '0.3048', prefixable: false },
40
+ '1': { dimension: '1', factor: '1', prefixable: false },
41
+ '%': { dimension: '1', factor: '0.01', prefixable: false },
42
+ }
43
+
44
+ /** Units that are volumes even though their atom row reduces through meters. */
45
+ const VOLUME_ATOMS = new Set(['L', 'l'])
46
+
47
+ const PREFIXES: Readonly<Record<string, string>> = {
48
+ T: '1000000000000',
49
+ G: '1000000000',
50
+ M: '1000000',
51
+ k: '1000',
52
+ h: '100',
53
+ da: '10',
54
+ d: '0.1',
55
+ c: '0.01',
56
+ m: '0.001',
57
+ u: '0.000001',
58
+ n: '0.000000001',
59
+ p: '0.000000000001',
60
+ }
61
+
62
+ export interface CanonicalUnit {
63
+ /** Multiplier to base units, exact. */
64
+ factor: Decimal
65
+ /** Dimension exponents, e.g. `g/m` → { g: 1, m: -1 }. Dimensionless entries are dropped. */
66
+ dimensions: Readonly<Record<string, number>>
67
+ }
68
+
69
+ /**
70
+ * Real UCUM exponents are single-digit (m2, cm3, s2). Larger ones would make
71
+ * powDecimal multiply huge exact BigInts — a tiny expression could hang the
72
+ * process — so anything past this stays an opaque unit.
73
+ */
74
+ const MAX_EXPONENT_MAGNITUDE = 9
75
+
76
+ /** One `atom` optionally followed by an integer exponent, e.g. `m2` or `cm3`. */
77
+ function parseComponent(text: string): { factor: Decimal; dimension: Dimension; exponent: number } | undefined {
78
+ // Whole-text atoms first, so '1' is the unity unit rather than an empty atom with exponent 1.
79
+ const whole = resolveAtom(text)
80
+ if (whole) {
81
+ const volumeBump = VOLUME_ATOMS.has(whole.atomKey) ? 3 : 1
82
+ return { factor: whole.factor, dimension: whole.atom.dimension, exponent: volumeBump }
83
+ }
84
+ const match = /^(.*?)(-?\d+)?$/.exec(text)
85
+ /* v8 ignore next 3 -- the regex cannot fail on any string */
86
+ if (!match) {
87
+ return undefined
88
+ }
89
+ const [, atomText = '', exponentText] = match
90
+ const exponent = exponentText === undefined ? 1 : Number.parseInt(exponentText, 10)
91
+ if (Math.abs(exponent) > MAX_EXPONENT_MAGNITUDE) {
92
+ return undefined
93
+ }
94
+ const resolved = resolveAtom(atomText)
95
+ if (!resolved) {
96
+ return undefined
97
+ }
98
+ const volumeBump = VOLUME_ATOMS.has(resolved.atomKey) ? 3 : 1
99
+ const factor = powDecimal(resolved.factor, exponent)
100
+ return { factor, dimension: resolved.atom.dimension, exponent: exponent * volumeBump }
101
+ }
102
+
103
+ function resolveAtom(text: string): { atom: UnitAtom; atomKey: string; factor: Decimal } | undefined {
104
+ const direct = ATOMS[text]
105
+ if (direct) {
106
+ return { atom: direct, atomKey: text, factor: Decimal.fromString(direct.factor) as Decimal }
107
+ }
108
+ for (const [prefix, prefixFactor] of Object.entries(PREFIXES)) {
109
+ if (text.startsWith(prefix)) {
110
+ const rest = text.slice(prefix.length)
111
+ const atom = ATOMS[rest]
112
+ if (atom?.prefixable) {
113
+ const factor = (Decimal.fromString(atom.factor) as Decimal).multiply(
114
+ Decimal.fromString(prefixFactor) as Decimal
115
+ )
116
+ return { atom, atomKey: rest, factor }
117
+ }
118
+ }
119
+ }
120
+ return undefined
121
+ }
122
+
123
+ function powDecimal(base: Decimal, exponent: number): Decimal {
124
+ if (exponent === 0) {
125
+ return new Decimal(1n, 0)
126
+ }
127
+ let result = new Decimal(1n, 0)
128
+ for (let i = 0; i < Math.abs(exponent); i++) {
129
+ result = result.multiply(base)
130
+ }
131
+ if (exponent < 0) {
132
+ // Factors are exact positive decimals, so the inverse always exists.
133
+ return new Decimal(1n, 0).divide(result) as Decimal
134
+ }
135
+ return result
136
+ }
137
+
138
+ /**
139
+ * Reduce a UCUM expression (`mg`, `m2`, `g/m`, `kg.m/s2`) to base dimensions.
140
+ * Undefined for units outside the table — they stay opaque.
141
+ */
142
+ export function canonicalizeUnit(unit: string): CanonicalUnit | undefined {
143
+ const [numerator, ...denominators] = unit.split('/')
144
+ let factor = new Decimal(1n, 0)
145
+ const dimensions: Record<string, number> = {}
146
+ const apply = (componentText: string, sign: 1 | -1): boolean => {
147
+ const component = parseComponent(componentText)
148
+ if (!component) {
149
+ return false
150
+ }
151
+ factor = sign === 1 ? factor.multiply(component.factor) : (factor.divide(component.factor) as Decimal)
152
+ if (component.dimension !== '1') {
153
+ const next = (dimensions[component.dimension] ?? 0) + sign * component.exponent
154
+ if (next === 0) {
155
+ delete dimensions[component.dimension]
156
+ } else {
157
+ dimensions[component.dimension] = next
158
+ }
159
+ }
160
+ return true
161
+ }
162
+ for (const part of (numerator ?? '').split('.')) {
163
+ if (!apply(part, 1)) {
164
+ return undefined
165
+ }
166
+ }
167
+ for (const denominator of denominators) {
168
+ for (const part of denominator.split('.')) {
169
+ if (!apply(part, -1)) {
170
+ return undefined
171
+ }
172
+ }
173
+ }
174
+ return { factor, dimensions }
175
+ }
176
+
177
+ export function sameDimensions(a: CanonicalUnit, b: CanonicalUnit): boolean {
178
+ const keysA = Object.keys(a.dimensions)
179
+ const keysB = Object.keys(b.dimensions)
180
+ return keysA.length === keysB.length && keysA.every(key => a.dimensions[key] === b.dimensions[key])
181
+ }