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,266 @@
1
+ /**
2
+ * FHIR narrative validation for htmlChecks(): the xhtml must be well formed, use
3
+ * only the elements and attributes the FHIR spec allows in Narrative.div, and
4
+ * carry no active content. (https://hl7.org/fhir/narrative.html)
5
+ */
6
+
7
+ const ALLOWED_ELEMENTS = new Set([
8
+ 'div',
9
+ 'p',
10
+ 'b',
11
+ 'i',
12
+ 'em',
13
+ 'strong',
14
+ 'u',
15
+ 's',
16
+ 'strike',
17
+ 'small',
18
+ 'big',
19
+ 'tt',
20
+ 'sub',
21
+ 'sup',
22
+ 'span',
23
+ 'br',
24
+ 'hr',
25
+ 'ul',
26
+ 'ol',
27
+ 'li',
28
+ 'dl',
29
+ 'dt',
30
+ 'dd',
31
+ 'table',
32
+ 'caption',
33
+ 'col',
34
+ 'colgroup',
35
+ 'thead',
36
+ 'tbody',
37
+ 'tfoot',
38
+ 'tr',
39
+ 'td',
40
+ 'th',
41
+ 'pre',
42
+ 'blockquote',
43
+ 'q',
44
+ 'a',
45
+ 'img',
46
+ 'code',
47
+ 'samp',
48
+ 'kbd',
49
+ 'var',
50
+ 'abbr',
51
+ 'acronym',
52
+ 'cite',
53
+ 'dfn',
54
+ 'address',
55
+ 'bdo',
56
+ 'h1',
57
+ 'h2',
58
+ 'h3',
59
+ 'h4',
60
+ 'h5',
61
+ 'h6',
62
+ ])
63
+
64
+ const VOID_ELEMENTS = new Set(['br', 'hr', 'img', 'col'])
65
+
66
+ const ALLOWED_ATTRIBUTES = new Set([
67
+ 'abbr',
68
+ 'accesskey',
69
+ 'align',
70
+ 'alt',
71
+ 'axis',
72
+ 'bgcolor',
73
+ 'border',
74
+ 'cellhalign',
75
+ 'cellpadding',
76
+ 'cellspacing',
77
+ 'cellvalign',
78
+ 'char',
79
+ 'charoff',
80
+ 'charset',
81
+ 'cite',
82
+ 'class',
83
+ 'colspan',
84
+ 'compact',
85
+ 'coords',
86
+ 'dir',
87
+ 'frame',
88
+ 'headers',
89
+ 'height',
90
+ 'href',
91
+ 'hreflang',
92
+ 'hspace',
93
+ 'id',
94
+ 'lang',
95
+ 'longdesc',
96
+ 'name',
97
+ 'nowrap',
98
+ 'rel',
99
+ 'rev',
100
+ 'rowspan',
101
+ 'rules',
102
+ 'scope',
103
+ 'shape',
104
+ 'span',
105
+ 'src',
106
+ 'start',
107
+ 'style',
108
+ 'summary',
109
+ 'tabindex',
110
+ 'title',
111
+ 'type',
112
+ 'valign',
113
+ 'value',
114
+ 'vspace',
115
+ 'width',
116
+ 'xmlns',
117
+ 'xml:id',
118
+ 'xml:lang',
119
+ 'xml:space',
120
+ ])
121
+
122
+ const TAG_PATTERN = /<!--[\s\S]*?-->|<!\[CDATA\[[\s\S]*?\]\]>|<[^>]*>|[^<]+/g
123
+ const OPEN_TAG = /^<([a-zA-Z][a-zA-Z0-9]*)((?:\s+[^\s=>/]+(?:\s*=\s*(?:"[^"]*"|'[^']*'))?)*)\s*(\/?)>$/
124
+ const CLOSE_TAG = /^<\/([a-zA-Z][a-zA-Z0-9]*)\s*>$/
125
+ const ATTRIBUTE = /([^\s=>/]+)(?:\s*=\s*("[^"]*"|'[^']*'))?/g
126
+
127
+ export function validateNarrative(xhtml: string): boolean {
128
+ const stack: string[] = []
129
+ let sawRoot = false
130
+ let position = 0
131
+ for (const match of xhtml.matchAll(TAG_PATTERN)) {
132
+ if (match.index !== position) {
133
+ return false
134
+ }
135
+ position = match.index + match[0].length
136
+ const token = match[0]
137
+ if (!token.startsWith('<')) {
138
+ // Text content: a stray '>' is fine, but only whitespace may sit outside the root.
139
+ if (stack.length === 0 && token.trim() !== '') {
140
+ return false
141
+ }
142
+ // Well-formed XHTML only uses the five XML entities and numeric references;
143
+ // an unknown entity (e.g. &Tab;) means the document is not well-formed.
144
+ if (decodeEntities(token) === undefined) {
145
+ return false
146
+ }
147
+ continue
148
+ }
149
+ if (token.startsWith('<!--') || token.startsWith('<![CDATA[')) {
150
+ continue
151
+ }
152
+ const close = CLOSE_TAG.exec(token)
153
+ if (close) {
154
+ const name = (close[1] as string).toLowerCase()
155
+ if (stack.pop() !== name) {
156
+ return false
157
+ }
158
+ continue
159
+ }
160
+ const open = OPEN_TAG.exec(token)
161
+ if (!open) {
162
+ return false
163
+ }
164
+ const name = (open[1] as string).toLowerCase()
165
+ if (!ALLOWED_ELEMENTS.has(name)) {
166
+ return false
167
+ }
168
+ if (stack.length === 0) {
169
+ if (sawRoot || name !== 'div') {
170
+ return false
171
+ }
172
+ sawRoot = true
173
+ if (!/xmlns\s*=\s*["']http:\/\/www\.w3\.org\/1999\/xhtml["']/.test(token)) {
174
+ return false
175
+ }
176
+ }
177
+ if (!validAttributes(open[2] as string)) {
178
+ return false
179
+ }
180
+ const selfClosing = open[3] === '/' || VOID_ELEMENTS.has(name)
181
+ if (!selfClosing) {
182
+ stack.push(name)
183
+ }
184
+ }
185
+ return sawRoot && stack.length === 0 && position === xhtml.length
186
+ }
187
+
188
+ function validAttributes(attributesText: string): boolean {
189
+ for (const match of attributesText.matchAll(ATTRIBUTE)) {
190
+ const name = (match[1] as string).toLowerCase()
191
+ if (name.startsWith('on') || !ALLOWED_ATTRIBUTES.has(name)) {
192
+ return false
193
+ }
194
+ const value = match[2]?.slice(1, -1) ?? ''
195
+ if ((name === 'href' || name === 'src') && !safeUrl(value, name)) {
196
+ return false
197
+ }
198
+ }
199
+ return true
200
+ }
201
+
202
+ const SAFE_SCHEMES = new Set(['http', 'https', 'mailto', 'tel', 'ftp', 'urn', 'cid'])
203
+
204
+ /**
205
+ * Allow only inert URL schemes. Browsers entity-decode attribute values and skip
206
+ * control characters before resolving the scheme, so the check must see the value
207
+ * the way a browser does — `java&#115;cript:` is still `javascript:`.
208
+ */
209
+ function safeUrl(rawValue: string, attributeName: string): boolean {
210
+ const decoded = decodeEntities(rawValue)
211
+ if (decoded === undefined) {
212
+ // An unknown entity in the URL (e.g. javascript&colon;) is malformed; reject.
213
+ return false
214
+ }
215
+ // eslint-disable-next-line no-control-regex -- stripping control characters is the point
216
+ const value = decoded.replace(/[\u0000-\u0020]/gu, '')
217
+ const scheme = /^([a-zA-Z][a-zA-Z0-9+.-]*):/.exec(value)
218
+ if (!scheme) {
219
+ // Relative URL or fragment: no scheme to smuggle code through.
220
+ return true
221
+ }
222
+ const name = (scheme[1] as string).toLowerCase()
223
+ if (attributeName === 'src' && name === 'data') {
224
+ // Inline images are common in narratives; data: must never reach href.
225
+ return /^data:image\//i.test(value)
226
+ }
227
+ return SAFE_SCHEMES.has(name)
228
+ }
229
+
230
+ const NAMED_ENTITIES: Readonly<Record<string, string>> = {
231
+ lt: '<',
232
+ gt: '>',
233
+ amp: '&',
234
+ quot: '"',
235
+ apos: "'",
236
+ }
237
+
238
+ /**
239
+ * Resolve XML entity and numeric character references. Returns undefined when the
240
+ * text contains an entity XHTML does not define — those five names plus numeric
241
+ * references are the only well-formed forms, so anything else fails validation
242
+ * instead of passing through unresolved (which is how &Tab;/&colon; smuggled a
243
+ * javascript: URL past the scheme check).
244
+ */
245
+ function decodeEntities(text: string): string | undefined {
246
+ let malformed = false
247
+ const decoded = text.replace(/&(?:#x([0-9a-fA-F]+)|#(\d+)|([a-zA-Z0-9]+));/g, (whole, hex, dec, named) => {
248
+ if (hex !== undefined) {
249
+ return fromCodePoint(Number.parseInt(hex, 16))
250
+ }
251
+ if (dec !== undefined) {
252
+ return fromCodePoint(Number.parseInt(dec, 10))
253
+ }
254
+ const resolved = NAMED_ENTITIES[named as string]
255
+ if (resolved === undefined) {
256
+ malformed = true
257
+ return whole
258
+ }
259
+ return resolved
260
+ })
261
+ return malformed ? undefined : decoded
262
+ }
263
+
264
+ function fromCodePoint(codePoint: number): string {
265
+ return codePoint >= 0 && codePoint <= 0x10ffff ? String.fromCodePoint(codePoint) : '\uFFFD'
266
+ }
@@ -0,0 +1,148 @@
1
+ import type { ModelProvider } from '../model/provider.ts'
2
+ import { Temporal } from '../values/datetime.ts'
3
+ import { Decimal } from '../values/decimal.ts'
4
+ import { FHIR_PRIMITIVE_TO_SYSTEM, toTypedValue, type TypedValue } from '../values/typed-value.ts'
5
+
6
+ export function isFhirPrimitiveType(typeName: string): boolean {
7
+ return FHIR_PRIMITIVE_TO_SYSTEM[typeName] !== undefined
8
+ }
9
+
10
+ /**
11
+ * Read one element with model knowledge: choice elements resolve their suffixed
12
+ * JSON key, primitives parse into System values (dates become Temporal, decimals
13
+ * become Decimal) and carry their `_field` sibling for extension/id access.
14
+ * Undefined when the model does not know the element.
15
+ */
16
+ export function readModelProperty(model: ModelProvider, item: TypedValue, name: string): TypedValue[] | undefined {
17
+ const metadata = readPrimitiveMetadata(item, name)
18
+ if (metadata !== undefined) {
19
+ return metadata
20
+ }
21
+ const info = model.getElement(item.type, name)
22
+ if (!info) {
23
+ return undefined
24
+ }
25
+ const container = item.value
26
+ if (typeof container !== 'object' || container === null || Array.isArray(container)) {
27
+ return []
28
+ }
29
+ const record = container as Record<string, unknown>
30
+ if (info.isChoice) {
31
+ for (const typeName of info.types) {
32
+ const key = name + typeName.charAt(0).toUpperCase() + typeName.slice(1)
33
+ if (record[key] !== undefined && record[key] !== null) {
34
+ return convertValues(record[key], record[`_${key}`], typeName)
35
+ }
36
+ // A choice primitive may be present through its `_field` sibling alone,
37
+ // e.g. { _valueString: { extension: [...] } } with no valueString.
38
+ const sibling = record[`_${key}`]
39
+ if (sibling !== undefined && sibling !== null && isFhirPrimitiveType(typeName)) {
40
+ return convertValues(undefined, sibling, typeName)
41
+ }
42
+ }
43
+ return []
44
+ }
45
+ const raw = record[name]
46
+ if (raw === undefined || raw === null) {
47
+ // A primitive may be present through its `_field` sibling alone.
48
+ const sibling = record[`_${name}`]
49
+ if (sibling !== undefined && sibling !== null && isFhirPrimitiveType(info.types[0] as string)) {
50
+ return convertValues(undefined, sibling, info.types[0] as string)
51
+ }
52
+ return []
53
+ }
54
+ return convertValues(raw, record[`_${name}`], info.types[0] as string)
55
+ }
56
+
57
+ /** `id` and `extension` on an already-navigated primitive come from its `_field` sibling. */
58
+ function readPrimitiveMetadata(item: TypedValue, name: string): TypedValue[] | undefined {
59
+ if (item.primitiveElement === undefined || (name !== 'id' && name !== 'extension')) {
60
+ return undefined
61
+ }
62
+ const metadata = item.primitiveElement as Record<string, unknown>
63
+ const value = metadata[name]
64
+ if (value === undefined || value === null) {
65
+ return []
66
+ }
67
+ if (name === 'id') {
68
+ return [{ type: 'System.String', value }]
69
+ }
70
+ return (Array.isArray(value) ? value : [value]).map(extension => ({
71
+ type: 'FHIR.Extension',
72
+ value: extension,
73
+ }))
74
+ }
75
+
76
+ function convertValues(raw: unknown, sibling: unknown, typeName: string): TypedValue[] {
77
+ if (Array.isArray(raw) || Array.isArray(sibling)) {
78
+ // The value and _name arrays align by index and either may be the longer one:
79
+ // a tail entry present only in _name is still an element (with extensions).
80
+ const values = Array.isArray(raw) ? raw : []
81
+ const siblings = Array.isArray(sibling) ? sibling : []
82
+ const result: TypedValue[] = []
83
+ for (let index = 0; index < Math.max(values.length, siblings.length); index++) {
84
+ const converted = convertSingle(values[index], siblings[index], typeName)
85
+ if (converted) {
86
+ result.push(converted)
87
+ }
88
+ }
89
+ return result
90
+ }
91
+ const converted = convertSingle(raw, sibling, typeName)
92
+ return converted ? [converted] : []
93
+ }
94
+
95
+ function convertSingle(raw: unknown, sibling: unknown, typeName: string): TypedValue | undefined {
96
+ if ((raw === undefined || raw === null) && (sibling === undefined || sibling === null)) {
97
+ return undefined
98
+ }
99
+ // Element ids and primitive value elements carry System types directly.
100
+ if (typeName.startsWith('System.')) {
101
+ return raw === undefined || raw === null ? undefined : { type: typeName, value: raw }
102
+ }
103
+ const systemType = FHIR_PRIMITIVE_TO_SYSTEM[typeName]
104
+ if (systemType === undefined) {
105
+ // Complex, backbone, or resource element.
106
+ if (raw === undefined || raw === null) {
107
+ return undefined
108
+ }
109
+ if (typeName === 'Resource' || typeName === 'DomainResource') {
110
+ return toTypedValue(raw)
111
+ }
112
+ return { type: `FHIR.${typeName}`, value: raw }
113
+ }
114
+ // FHIR primitives keep their FHIR type (the official type() and is() tests rely
115
+ // on it) while the value itself parses into the System representation.
116
+ const typed: TypedValue = { type: `FHIR.${typeName}`, value: parsePrimitive(raw, systemType) }
117
+ if (sibling !== undefined && sibling !== null) {
118
+ typed.primitiveElement = sibling
119
+ }
120
+ return typed
121
+ }
122
+
123
+ function parsePrimitive(raw: unknown, systemType: string): unknown {
124
+ if (raw === undefined || raw === null) {
125
+ return undefined
126
+ }
127
+ switch (systemType) {
128
+ case 'System.Date': {
129
+ return typeof raw === 'string' ? (Temporal.parseDate(raw) ?? raw) : raw
130
+ }
131
+ case 'System.DateTime': {
132
+ return typeof raw === 'string' ? (Temporal.parseDateTime(raw) ?? raw) : raw
133
+ }
134
+ case 'System.Time': {
135
+ return typeof raw === 'string' ? (Temporal.parseTime(raw) ?? raw) : raw
136
+ }
137
+ case 'System.Decimal': {
138
+ const parsed = typeof raw === 'number' ? Decimal.fromNumber(raw) : Decimal.fromString(String(raw))
139
+ return parsed ?? raw
140
+ }
141
+ /* v8 ignore next 3 -- R4 has no integer64 elements; kept for R5 model reuse */
142
+ case 'System.Long': {
143
+ return typeof raw === 'number' ? BigInt(raw) : raw
144
+ }
145
+ default:
146
+ return raw
147
+ }
148
+ }
@@ -0,0 +1,136 @@
1
+ import { withFrame } from '../engine/context.ts'
2
+ import { FhirPathTypeError } from '../errors.ts'
3
+ import { Decimal } from '../values/decimal.ts'
4
+ import { asNumeric, type NumericKind, widerKind, wrapNumeric } from '../values/numeric.ts'
5
+ import { alignQuantities, coerceQuantity } from '../values/quantity.ts'
6
+ import { type QuantityValue, SYSTEM_DECIMAL, SYSTEM_QUANTITY, type TypedValue } from '../values/typed-value.ts'
7
+ import { argAt, registerFunction } from './registry.ts'
8
+
9
+ registerFunction('aggregate', {
10
+ minArity: 1,
11
+ maxArity: 2,
12
+ evaluate: (context, input, args, evaluateNode) => {
13
+ let total: TypedValue[] = args.length === 2 ? evaluateNode(argAt(args, 1), context, input) : []
14
+ input.forEach((item, index) => {
15
+ total = withFrame(context, { thisValue: [item], index, total }, frameContext =>
16
+ evaluateNode(argAt(args, 0), frameContext, [item])
17
+ )
18
+ })
19
+ return total
20
+ },
21
+ })
22
+
23
+ /** Shared by sum/min/max/avg: all items must be numeric, of a comparable kind. */
24
+ function numericItems(name: string, input: TypedValue[]): { values: Decimal[]; kind: NumericKind } {
25
+ let kind: NumericKind = 'Integer'
26
+ const values = input.map(item => {
27
+ const numeric = asNumeric(item)
28
+ if (!numeric) {
29
+ throw new FhirPathTypeError(`${name}() expects numeric values, found ${item.type}`)
30
+ }
31
+ kind = widerKind(kind, numeric.kind)
32
+ return numeric.value
33
+ })
34
+ return { values, kind }
35
+ }
36
+
37
+ /**
38
+ * Quantity collections aggregate by pairwise-aligning units, exactly like
39
+ * repeated `+`: (1 'cm' | 3 'cm' | 1 'm').sum() = 104 'cm'. Empty when any
40
+ * pair of units cannot align.
41
+ */
42
+ function foldQuantities(quantities: QuantityValue[], fold: (acc: Decimal, next: Decimal) => Decimal): TypedValue[] {
43
+ let acc = quantities[0] as QuantityValue
44
+ for (const quantity of quantities.slice(1)) {
45
+ const pair = alignQuantities(acc, quantity)
46
+ if (!pair) {
47
+ return []
48
+ }
49
+ acc = { value: fold(pair.left, pair.right), unit: pair.unit, calendar: pair.calendar }
50
+ }
51
+ return [{ type: SYSTEM_QUANTITY, value: acc }]
52
+ }
53
+
54
+ function allQuantities(input: TypedValue[]): QuantityValue[] | undefined {
55
+ const quantities: QuantityValue[] = []
56
+ for (const item of input) {
57
+ const quantity = coerceQuantity(item)
58
+ if (quantity === undefined) {
59
+ return undefined
60
+ }
61
+ quantities.push(quantity)
62
+ }
63
+ return quantities
64
+ }
65
+
66
+ // Convenience aggregates (ballot STU). All four are empty for empty input.
67
+ registerFunction('sum', {
68
+ minArity: 0,
69
+ maxArity: 0,
70
+ evaluate: (_context, input) => {
71
+ if (input.length === 0) {
72
+ return []
73
+ }
74
+ const quantities = allQuantities(input)
75
+ if (quantities) {
76
+ return foldQuantities(quantities, (acc, next) => acc.add(next))
77
+ }
78
+ const { values, kind } = numericItems('sum', input)
79
+ const total = values.reduce((acc, value) => acc.add(value), Decimal.zero())
80
+ return [wrapNumeric(total, kind)]
81
+ },
82
+ })
83
+
84
+ function extremum(name: string, keep: (comparison: number) => boolean): void {
85
+ registerFunction(name, {
86
+ minArity: 0,
87
+ maxArity: 0,
88
+ evaluate: (_context, input) => {
89
+ if (input.length === 0) {
90
+ return []
91
+ }
92
+ const quantities = allQuantities(input)
93
+ if (quantities) {
94
+ return foldQuantities(quantities, (acc, next) => (keep(next.compare(acc)) ? next : acc))
95
+ }
96
+ const { values, kind } = numericItems(name, input)
97
+ let best = values[0] as Decimal
98
+ for (const value of values.slice(1)) {
99
+ if (keep(value.compare(best))) {
100
+ best = value
101
+ }
102
+ }
103
+ return [wrapNumeric(best, kind)]
104
+ },
105
+ })
106
+ }
107
+
108
+ extremum('min', comparison => comparison < 0)
109
+ extremum('max', comparison => comparison > 0)
110
+
111
+ registerFunction('avg', {
112
+ minArity: 0,
113
+ maxArity: 0,
114
+ evaluate: (_context, input) => {
115
+ if (input.length === 0) {
116
+ return []
117
+ }
118
+ const count = Decimal.fromString(String(input.length)) as Decimal
119
+ const quantities = allQuantities(input)
120
+ if (quantities) {
121
+ const total = foldQuantities(quantities, (acc, next) => acc.add(next))
122
+ if (total.length === 0) {
123
+ return []
124
+ }
125
+ const sum = (total[0] as TypedValue).value as QuantityValue
126
+ const average = sum.value.divide(count)
127
+ /* v8 ignore next -- the divisor is the non-zero item count */
128
+ return average === undefined ? [] : [{ type: SYSTEM_QUANTITY, value: { ...sum, value: average } }]
129
+ }
130
+ const { values } = numericItems('avg', input)
131
+ const total = values.reduce((acc, value) => acc.add(value), Decimal.zero())
132
+ const average = total.divide(count)
133
+ /* v8 ignore next -- the divisor is the non-zero item count */
134
+ return average === undefined ? [] : [{ type: SYSTEM_DECIMAL, value: average }]
135
+ },
136
+ })