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,148 @@
1
+ import { FhirPathTypeError } from '../errors.ts'
2
+ import { resolveByInput, type UnsatisfiedInput, unsatisfiedInput } from '../values/type-compat.ts'
3
+ import { OBJECT_TYPE, type TypedValue, typeLocalName } from '../values/typed-value.ts'
4
+ import type { EvaluationContext, HostFunction, HostSingleFunction } from './context.ts'
5
+
6
+ const SYSTEM_LOCAL_NAMES = new Set([
7
+ 'Any',
8
+ 'Boolean',
9
+ 'String',
10
+ 'Integer',
11
+ 'Long',
12
+ 'Decimal',
13
+ 'Date',
14
+ 'DateTime',
15
+ 'Time',
16
+ 'Quantity',
17
+ ])
18
+
19
+ const SYSTEM_LOCAL_NAMES_LOWER = new Set([...SYSTEM_LOCAL_NAMES].map(name => name.toLowerCase()))
20
+
21
+ /** True when an unqualified name may mean a System primitive and requires exact `as`/`ofType` matching. */
22
+ function isSystemAmbiguousName(name: string): boolean {
23
+ return SYSTEM_LOCAL_NAMES_LOWER.has(name.toLowerCase())
24
+ }
25
+
26
+ /**
27
+ * Does an item satisfy a type specifier? Shared by `is`/`as`/`ofType()` and the
28
+ * static analyzer. Resolution order per spec §10.1: the context model's types
29
+ * first, then the System namespace. `is` always walks subtypes; `as`/`ofType`
30
+ * do too, except when the requested name aliases a System primitive, where the
31
+ * official inheritance tests pin an exact match instead (see isSystemAmbiguousName).
32
+ */
33
+ export function itemMatchesType(
34
+ context: EvaluationContext,
35
+ item: TypedValue,
36
+ parts: string[],
37
+ options?: { exact?: boolean }
38
+ ): boolean {
39
+ const exact = options?.exact === true
40
+ if (parts.length === 2 && parts[0] === 'System') {
41
+ // FHIR-typed values do not answer System-qualified questions (testType14).
42
+ // System type names are case-sensitive, so `System.STRING` is not `System.String`
43
+ // (the lowercase fallback in matchesSystemType is only for unqualified names).
44
+ const systemName = parts[1] as string
45
+ return systemName === 'Any' ? item.type.startsWith('System.') : item.type === `System.${systemName}`
46
+ }
47
+ const model = context.model
48
+ if (parts.length === 2) {
49
+ if (model && parts[0] === model.namespace) {
50
+ const typeName = parts[1] as string
51
+ const canonical = model.resolveType(typeName)
52
+ if (canonical === undefined) {
53
+ return false
54
+ }
55
+ return exact && isSystemAmbiguousName(typeName)
56
+ ? item.type === canonical
57
+ : model.isSubtypeOf(item.type, canonical)
58
+ }
59
+ return item.type === parts.join('.')
60
+ }
61
+ const name = parts[0] as string
62
+ // System-typed values answer from the System namespace.
63
+ if (item.type.startsWith('System.')) {
64
+ return matchesSystemType(item, name)
65
+ }
66
+ if (model) {
67
+ const canonical = model.resolveType(name)
68
+ if (canonical !== undefined) {
69
+ return exact && isSystemAmbiguousName(name) ? item.type === canonical : model.isSubtypeOf(item.type, canonical)
70
+ }
71
+ }
72
+ // Dynamic fallback: resource and complex types match on their local name. The
73
+ // internal Object marker never answers a type question — `ofType(Object)` is not
74
+ // a way to select untyped values.
75
+ return item.type !== OBJECT_TYPE && typeLocalName(item.type) === name
76
+ }
77
+
78
+ /**
79
+ * Selects a host function by focus type. Same-name overloads use registration
80
+ * order. If none accepts the focus, one error lists all accepted input types.
81
+ */
82
+ export function resolveHostCall(
83
+ name: string,
84
+ host: HostFunction,
85
+ context: EvaluationContext,
86
+ input: TypedValue[]
87
+ ): HostSingleFunction {
88
+ if (!('overloads' in host)) {
89
+ // `unsatisfiedInput` handles an undeclared input too. Returning first is
90
+ // what stops the many host functions that declare no types from walking the
91
+ // focus at all.
92
+ if (host.inputTypes === undefined) {
93
+ return host
94
+ }
95
+ const unsatisfied = unsatisfiedInput(context.model, host.inputTypes, focusTypes(input))
96
+ if (unsatisfied === undefined) {
97
+ return host
98
+ }
99
+ throw wrongFocus(name, unsatisfied)
100
+ }
101
+ const resolution = resolveByInput(
102
+ context.model,
103
+ host.overloads,
104
+ overload => overload.inputTypes,
105
+ input.map(item => item.type)
106
+ )
107
+ if ('resolved' in resolution) {
108
+ return resolution.resolved
109
+ }
110
+ throw wrongFocus(name, resolution.unsatisfied)
111
+ }
112
+
113
+ function wrongFocus(name: string, { wanted, found }: UnsatisfiedInput): FhirPathTypeError {
114
+ return new FhirPathTypeError(
115
+ `Function '${name}' expects ${wanted.join(' | ')} as input, but the focus is ${found.join(' | ')}`
116
+ )
117
+ }
118
+
119
+ /** The focus's type names, read one at a time. A valid call stops at the first item that fits. */
120
+ function* focusTypes(input: TypedValue[]): Iterable<string> {
121
+ for (const item of input) {
122
+ yield item.type
123
+ }
124
+ }
125
+
126
+ /** True when a single-part type name resolves in the model or the System namespace. */
127
+ export function isKnownTypeName(context: EvaluationContext, parts: string[]): boolean {
128
+ if (parts.length === 2) {
129
+ return parts[0] === 'System' ? SYSTEM_LOCAL_NAMES.has(parts[1] as string) : parts[0] === context.model?.namespace
130
+ }
131
+ const name = parts[0] as string
132
+ if (context.model?.resolveType(name) !== undefined) {
133
+ return true
134
+ }
135
+ return SYSTEM_LOCAL_NAMES.has(name)
136
+ }
137
+
138
+ function matchesSystemType(item: TypedValue, name: string): boolean {
139
+ if (name === 'Any') {
140
+ return true
141
+ }
142
+ const local = typeLocalName(item.type)
143
+ if (local === name) {
144
+ return true
145
+ }
146
+ // Lowercase FHIR spellings (`boolean`, `dateTime`) reach the System twin.
147
+ return local.toLowerCase() === name.toLowerCase()
148
+ }
package/src/errors.ts ADDED
@@ -0,0 +1,33 @@
1
+ export interface SourceSpan {
2
+ /** 0-based offset of the first character. */
3
+ start: number
4
+ /** 0-based offset one past the last character. */
5
+ end: number
6
+ /** 1-based line of the first character. */
7
+ line: number
8
+ /** 1-based column of the first character. */
9
+ column: number
10
+ }
11
+
12
+ export class FhirPathError extends Error {
13
+ constructor(message: string) {
14
+ super(message)
15
+ this.name = new.target.name
16
+ }
17
+ }
18
+
19
+ /** The expression does not match the FHIRPath grammar. Maps to `invalid="syntax"` in the official test suite. */
20
+ export class FhirPathSyntaxError extends FhirPathError {
21
+ readonly span: SourceSpan
22
+
23
+ constructor(message: string, span: SourceSpan) {
24
+ super(`${message} (line ${span.line}, column ${span.column})`)
25
+ this.span = span
26
+ }
27
+ }
28
+
29
+ /** The expression is grammatical but breaks a typing rule, e.g. a singleton rule or an undefined `%var`. Maps to `invalid="semantic"`. */
30
+ export class FhirPathTypeError extends FhirPathError {}
31
+
32
+ /** Evaluation failed on the given input, e.g. `single()` over many items. Maps to `invalid="execution"`. */
33
+ export class FhirPathRuntimeError extends FhirPathError {}
@@ -0,0 +1,388 @@
1
+ import { readFileSync } from 'node:fs'
2
+
3
+ import type { Rule } from 'eslint'
4
+ import type * as ESTree from 'estree'
5
+
6
+ import { analyzeSite, type DeclaredFunction, type DeclaredVariable } from '../analyzer/analyze.ts'
7
+ import {
8
+ CALL_SITES,
9
+ type CallSitePolicy,
10
+ type ClassHeritage,
11
+ columnFunctionDeclaration,
12
+ constructsEngine,
13
+ declaredColumnOverloads,
14
+ DTO_BASE_NAME,
15
+ dtoRootsOf,
16
+ type ExpressionAst,
17
+ expressionEntries,
18
+ type FileColumnFunction,
19
+ isCheckedCall,
20
+ isCheckedTag,
21
+ isForeignModule,
22
+ type LocalModuleOptions,
23
+ rootOf,
24
+ type SiteContext,
25
+ siteContext,
26
+ type SourceBindings,
27
+ TAG_NAME,
28
+ } from '../analyzer/expression-policy.ts'
29
+ import { r4Model } from '../r4/index.ts'
30
+
31
+ function isStringLiteral(node: ESTree.Node): node is ESTree.SimpleLiteral & { value: string } {
32
+ return node.type === 'Literal' && typeof node.value === 'string'
33
+ }
34
+
35
+ /** Statically-known property key (`path` in `{ path: ... }` or `{ 'path': ... }`), undefined when computed. */
36
+ function propertyKeyName(property: ESTree.Property): string | undefined {
37
+ if (property.computed) {
38
+ return undefined
39
+ }
40
+ if (property.key.type === 'Identifier') {
41
+ return property.key.name
42
+ }
43
+ return isStringLiteral(property.key) ? property.key.value : undefined
44
+ }
45
+
46
+ /** How the shared shape extractor reads ESTree nodes. */
47
+ const estreeAst: ExpressionAst<ESTree.Node> = {
48
+ string: node => (isStringLiteral(node) ? { node, expression: node.value } : undefined),
49
+ boolean: node => (node.type === 'Literal' && typeof node.value === 'boolean' ? node.value : undefined),
50
+ properties: node =>
51
+ node.type === 'ObjectExpression'
52
+ ? node.properties.flatMap(property =>
53
+ property.type === 'Property' ? [{ name: propertyKeyName(property), value: property.value }] : []
54
+ )
55
+ : undefined,
56
+ elements: node => (node.type === 'ArrayExpression' ? node.elements.filter(element => element !== null) : undefined),
57
+ }
58
+
59
+ /** Add every identifier a binding pattern declares (`x`, `{ r4 }`, `[a, ...rest]`, `x = 1`). */
60
+ function addPatternNames(pattern: ESTree.Pattern, into: Set<string>): void {
61
+ switch (pattern.type) {
62
+ case 'Identifier':
63
+ into.add(pattern.name)
64
+ return
65
+ case 'ObjectPattern':
66
+ for (const property of pattern.properties) {
67
+ addPatternNames(property.type === 'RestElement' ? property.argument : property.value, into)
68
+ }
69
+ return
70
+ case 'ArrayPattern':
71
+ for (const element of pattern.elements) {
72
+ if (element) {
73
+ addPatternNames(element, into)
74
+ }
75
+ }
76
+ return
77
+ case 'AssignmentPattern':
78
+ addPatternNames(pattern.left, into)
79
+ return
80
+ case 'RestElement':
81
+ addPatternNames(pattern.argument, into)
82
+ return
83
+ default:
84
+ // A MemberExpression target does not declare a new name.
85
+ return
86
+ }
87
+ }
88
+
89
+ /** Leftmost identifier of a member-expression callee (`Handlebars` in `Handlebars.compile`). */
90
+ function receiverRoot(callee: ESTree.Expression | ESTree.Super): string | undefined {
91
+ if (callee.type !== 'MemberExpression') {
92
+ return undefined
93
+ }
94
+ let current: ESTree.Expression | ESTree.Super = callee.object
95
+ while (current.type === 'MemberExpression') {
96
+ current = current.object
97
+ }
98
+ return current.type === 'Identifier' ? current.name : undefined
99
+ }
100
+
101
+ /** Returns an identifier name or the property name of a non-computed member access. */
102
+ function nameOf(node: ESTree.Node): string | undefined {
103
+ if (node.type === 'Identifier') {
104
+ return node.name
105
+ }
106
+ return node.type === 'MemberExpression' && !node.computed && node.property.type === 'Identifier'
107
+ ? node.property.name
108
+ : undefined
109
+ }
110
+
111
+ /** The name of the field a `@column(...)` decorator belongs to, from the call's ancestors. */
112
+ function decoratedFieldName(ancestors: readonly ESTree.Node[]): string | undefined {
113
+ const member = ancestors.at(-2) as (ESTree.Node & { key?: ESTree.Node }) | undefined
114
+ if (member?.type !== 'PropertyDefinition') {
115
+ return undefined
116
+ }
117
+ const key = member.key
118
+ if (key?.type === 'Identifier') {
119
+ return key.name
120
+ }
121
+ return key !== undefined && isStringLiteral(key) ? key.value : undefined
122
+ }
123
+
124
+ /** A class's heritage, as `dtoRootsOf` reads it: its own DTO root, or the name of the class it extends. */
125
+ function heritageOf(node: ESTree.ClassDeclaration | ESTree.ClassExpression): ClassHeritage {
126
+ const base = node.superClass
127
+ const rootArgument =
128
+ base?.type === 'CallExpression' && nameOf(base.callee) === DTO_BASE_NAME ? base.arguments[0] : undefined
129
+ return {
130
+ name: node.id?.name,
131
+ ownRoot: rootArgument === undefined ? undefined : estreeAst.string(rootArgument)?.expression,
132
+ baseName: base?.type === 'Identifier' ? base.name : undefined,
133
+ }
134
+ }
135
+
136
+ /**
137
+ * The heritage of the nearest enclosing class — what a `@column` field's
138
+ * expressions analyze against, once `dtoRootsOf` has resolved it against the rest
139
+ * of the file. Undefined when the field is not inside a class at all.
140
+ */
141
+ function enclosingClass(ancestors: readonly ESTree.Node[]): ClassHeritage | undefined {
142
+ for (let index = ancestors.length - 1; index >= 0; index--) {
143
+ const node = ancestors[index]
144
+ if (node?.type === 'ClassDeclaration' || node?.type === 'ClassExpression') {
145
+ return heritageOf(node)
146
+ }
147
+ }
148
+ return undefined
149
+ }
150
+
151
+ /**
152
+ * ESLint rule for literal FHIRPath expressions. The shared source policy decides
153
+ * which calls and tags count. `packages` adds trusted import prefixes, and
154
+ * `localImports` trusts relative imports.
155
+ */
156
+ const noInvalidExpressions: Rule.RuleModule = {
157
+ meta: {
158
+ type: 'problem',
159
+ docs: {
160
+ description: 'check FHIRPath expression literals with the static analyzer',
161
+ },
162
+ schema: [
163
+ {
164
+ type: 'object',
165
+ properties: {
166
+ packages: { type: 'array', items: { type: 'string' } },
167
+ localImports: { type: 'boolean' },
168
+ // Host-supplied environment variables and functions the checked code
169
+ // passes at runtime — AnalyzeOptions.variables / AnalyzeOptions.functions.
170
+ variables: { type: 'object' },
171
+ functions: { type: 'object' },
172
+ },
173
+ additionalProperties: false,
174
+ },
175
+ ],
176
+ },
177
+ create(context) {
178
+ const options = (context.options[0] ?? {}) as LocalModuleOptions & {
179
+ variables?: Record<string, DeclaredVariable>
180
+ functions?: Record<string, DeclaredFunction>
181
+ }
182
+ // Decide candidate sites at Program:exit because imports and engine
183
+ // declarations may appear after calls that depend on them.
184
+ const foreign = new Set<string>()
185
+ const trusted = new Set<string>()
186
+ const rebound = new Set<string>()
187
+ const engineLocals: { localName: string; className: string }[] = []
188
+ const reboundFunction = (node: { id?: ESTree.Identifier | null | undefined; params: ESTree.Pattern[] }): void => {
189
+ if (node.id) {
190
+ rebound.add(node.id.name)
191
+ }
192
+ for (const param of node.params) {
193
+ addPatternNames(param, rebound)
194
+ }
195
+ }
196
+ const tags: { literal: ESTree.TemplateLiteral; expression: string; receiverRoot: string | undefined }[] = []
197
+ const calls: {
198
+ policy: CallSitePolicy
199
+ name: string
200
+ receiverRoot: string | undefined
201
+ argument: ESTree.Node
202
+ /** The call itself, for the argument that may name the type it runs against. */
203
+ node: ESTree.CallExpression
204
+ /** The class the call sits in, resolved to a root once the whole file is known. */
205
+ enclosing: ClassHeritage | undefined
206
+ }[] = []
207
+ /** Every class in the file, so a DTO root can be followed through a base class. */
208
+ const classes: ClassHeritage[] = []
209
+ /**
210
+ * One entry per `@column` field in the file. Any expression can call a
211
+ * registered DTO column, so this is what lets calls between a file's own
212
+ * columns resolve. It is filled in `Program:exit` because a declaration
213
+ * carries the `fhirType` of the class it sits in, and a base class may be
214
+ * declared further down the file. The call sites themselves are decided
215
+ * there for the same reason.
216
+ */
217
+ const columnDeclarations: {
218
+ kind: 'column' | 'criteria'
219
+ field: string
220
+ options: ESTree.Node | undefined
221
+ enclosing: ClassHeritage | undefined
222
+ }[] = []
223
+ const columnFunctions: Record<string, FileColumnFunction> = {}
224
+ const checkAt = (node: ESTree.Node, expression: string, site: SiteContext = {}): void => {
225
+ // ESLint severity comes from the rule's configuration, not per report, so
226
+ // only error-severity diagnostics are reported; analyzer warnings (style
227
+ // and possible-mistake findings) don't fail a lint run.
228
+ const diagnostics = analyzeSite(
229
+ {
230
+ expression,
231
+ ...site,
232
+ // The file's whole column vocabulary, shared by every site in it.
233
+ ...(Object.keys(columnFunctions).length > 0 && { functions: columnFunctions }),
234
+ },
235
+ {
236
+ model: r4Model,
237
+ ...(options.variables !== undefined && { variables: options.variables }),
238
+ ...(options.functions !== undefined && { functions: options.functions }),
239
+ }
240
+ )
241
+ for (const diagnostic of diagnostics) {
242
+ if (diagnostic.severity === 'error') {
243
+ context.report({ node, message: `[${diagnostic.code}] ${diagnostic.message}` })
244
+ }
245
+ }
246
+ }
247
+ return {
248
+ ImportDeclaration(node) {
249
+ if (typeof node.source.value !== 'string') {
250
+ return
251
+ }
252
+ const names = isForeignModule(node.source.value, options) ? foreign : trusted
253
+ for (const specifier of node.specifiers) {
254
+ names.add(specifier.local.name)
255
+ }
256
+ },
257
+ VariableDeclarator(node) {
258
+ if (
259
+ node.id.type === 'Identifier' &&
260
+ node.init?.type === 'NewExpression' &&
261
+ node.init.callee.type === 'Identifier'
262
+ ) {
263
+ engineLocals.push({ localName: node.id.name, className: node.init.callee.name })
264
+ } else {
265
+ addPatternNames(node.id, rebound)
266
+ }
267
+ },
268
+ FunctionDeclaration: reboundFunction,
269
+ FunctionExpression: reboundFunction,
270
+ ArrowFunctionExpression: reboundFunction,
271
+ ClassDeclaration(node) {
272
+ classes.push(heritageOf(node))
273
+ if (node.id) {
274
+ rebound.add(node.id.name)
275
+ }
276
+ },
277
+ ClassExpression(node) {
278
+ classes.push(heritageOf(node))
279
+ if (node.id) {
280
+ rebound.add(node.id.name)
281
+ }
282
+ },
283
+ CatchClause(node) {
284
+ if (node.param) {
285
+ addPatternNames(node.param, rebound)
286
+ }
287
+ },
288
+ TaggedTemplateExpression(node) {
289
+ if (nameOf(node.tag) === TAG_NAME && node.quasi.expressions.length === 0 && node.quasi.quasis[0]) {
290
+ // Report on the template literal, like the call shapes report on their literals.
291
+ tags.push({
292
+ literal: node.quasi,
293
+ expression: node.quasi.quasis[0].value.cooked ?? '',
294
+ receiverRoot: receiverRoot(node.tag),
295
+ })
296
+ }
297
+ },
298
+ CallExpression(node) {
299
+ const callee = node.callee
300
+ const name = nameOf(callee)
301
+ const policy = name === undefined ? undefined : CALL_SITES.get(name)
302
+ const argument = policy && node.arguments[policy.argIndex]
303
+ if (name === undefined || policy === undefined || argument === undefined) {
304
+ return
305
+ }
306
+ // Only the DTO decorators need to look up: the class they sit in, and the
307
+ // field they decorate.
308
+ const ancestors =
309
+ policy.rootFromClass === true || policy.declaresField !== undefined
310
+ ? context.sourceCode.getAncestors(node)
311
+ : []
312
+ const declares = policy.declaresField
313
+ if (declares !== undefined) {
314
+ const field = decoratedFieldName(ancestors)
315
+ if (field !== undefined) {
316
+ columnDeclarations.push({
317
+ kind: declares,
318
+ field,
319
+ options: node.arguments[1],
320
+ enclosing: enclosingClass(ancestors),
321
+ })
322
+ }
323
+ }
324
+ calls.push({
325
+ policy,
326
+ name,
327
+ receiverRoot: receiverRoot(callee),
328
+ argument,
329
+ node,
330
+ enclosing: policy.rootFromClass === true ? enclosingClass(ancestors) : undefined,
331
+ })
332
+ },
333
+ 'Program:exit'() {
334
+ const bindings: SourceBindings = { foreign, trusted, rebound }
335
+ // All imports are known now; resolve engine locals in source order, like
336
+ // the CLI walker. A `new` local of some other class is a re-binding.
337
+ for (const { localName, className } of engineLocals) {
338
+ if (constructsEngine(className, bindings)) {
339
+ trusted.add(localName)
340
+ } else {
341
+ rebound.add(localName)
342
+ }
343
+ }
344
+ const dtoRoots = dtoRootsOf(classes)
345
+ // Build the column names first. `checkAt` reads them, and every site in
346
+ // the file shares them, including the tags.
347
+ for (const { kind, field, options: columnOptions, enclosing } of columnDeclarations) {
348
+ columnFunctions[field] = declaredColumnOverloads(
349
+ columnFunctions[field],
350
+ columnFunctionDeclaration<ESTree.Node>(kind, columnOptions, estreeAst, rootOf(enclosing, dtoRoots))
351
+ )
352
+ }
353
+ for (const tag of tags) {
354
+ if (isCheckedTag(tag.receiverRoot, bindings)) {
355
+ checkAt(tag.literal, tag.expression)
356
+ }
357
+ }
358
+ for (const call of calls) {
359
+ if (!isCheckedCall(call.policy, call.name, call.receiverRoot, bindings)) {
360
+ continue
361
+ }
362
+ const site = siteContext<ESTree.Node>(
363
+ call.policy,
364
+ index => call.node.arguments[index],
365
+ rootOf(call.enclosing, dtoRoots),
366
+ estreeAst
367
+ )
368
+ for (const entry of expressionEntries(call.argument, call.policy.shape, estreeAst)) {
369
+ checkAt(entry.node, entry.expression, site)
370
+ }
371
+ }
372
+ },
373
+ }
374
+ },
375
+ }
376
+
377
+ const { name: packageName, version: packageVersion }: { name: string; version: string } = JSON.parse(
378
+ readFileSync(new URL('../../package.json', import.meta.url), 'utf8')
379
+ )
380
+
381
+ const plugin = {
382
+ meta: { name: packageName, version: packageVersion },
383
+ rules: {
384
+ 'no-invalid-expressions': noInvalidExpressions,
385
+ },
386
+ }
387
+
388
+ export default plugin