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.
- package/LICENSE +201 -0
- package/README.md +391 -0
- package/THIRD-PARTY-NOTICES.md +296 -0
- package/dist/analyzer/analyze-dto.d.ts +45 -0
- package/dist/analyzer/analyze-dto.d.ts.map +1 -0
- package/dist/analyzer/analyze-dto.js +147 -0
- package/dist/analyzer/analyze-dto.js.map +1 -0
- package/dist/analyzer/analyze.d.ts +98 -0
- package/dist/analyzer/analyze.d.ts.map +1 -0
- package/dist/analyzer/analyze.js +925 -0
- package/dist/analyzer/analyze.js.map +1 -0
- package/dist/analyzer/expression-policy.d.ts +210 -0
- package/dist/analyzer/expression-policy.d.ts.map +1 -0
- package/dist/analyzer/expression-policy.js +254 -0
- package/dist/analyzer/expression-policy.js.map +1 -0
- package/dist/analyzer/index.d.ts +3 -0
- package/dist/analyzer/index.d.ts.map +1 -0
- package/dist/analyzer/index.js +6 -0
- package/dist/analyzer/index.js.map +1 -0
- package/dist/analyzer/regex-safety.d.ts +10 -0
- package/dist/analyzer/regex-safety.d.ts.map +1 -0
- package/dist/analyzer/regex-safety.js +84 -0
- package/dist/analyzer/regex-safety.js.map +1 -0
- package/dist/analyzer/signatures.d.ts +72 -0
- package/dist/analyzer/signatures.d.ts.map +1 -0
- package/dist/analyzer/signatures.js +195 -0
- package/dist/analyzer/signatures.js.map +1 -0
- package/dist/api/bundle.d.ts +29 -0
- package/dist/api/bundle.d.ts.map +1 -0
- package/dist/api/bundle.js +108 -0
- package/dist/api/bundle.js.map +1 -0
- package/dist/api/cache.d.ts +10 -0
- package/dist/api/cache.d.ts.map +1 -0
- package/dist/api/cache.js +38 -0
- package/dist/api/cache.js.map +1 -0
- package/dist/api/column-signature.d.ts +53 -0
- package/dist/api/column-signature.d.ts.map +1 -0
- package/dist/api/column-signature.js +43 -0
- package/dist/api/column-signature.js.map +1 -0
- package/dist/api/compile.d.ts +120 -0
- package/dist/api/compile.d.ts.map +1 -0
- package/dist/api/compile.js +167 -0
- package/dist/api/compile.js.map +1 -0
- package/dist/api/constraints.d.ts +48 -0
- package/dist/api/constraints.d.ts.map +1 -0
- package/dist/api/constraints.js +52 -0
- package/dist/api/constraints.js.map +1 -0
- package/dist/api/dto.d.ts +134 -0
- package/dist/api/dto.d.ts.map +1 -0
- package/dist/api/dto.js +295 -0
- package/dist/api/dto.js.map +1 -0
- package/dist/api/engine.d.ts +136 -0
- package/dist/api/engine.d.ts.map +1 -0
- package/dist/api/engine.js +183 -0
- package/dist/api/engine.js.map +1 -0
- package/dist/api/evaluate.d.ts +7 -0
- package/dist/api/evaluate.d.ts.map +1 -0
- package/dist/api/evaluate.js +10 -0
- package/dist/api/evaluate.js.map +1 -0
- package/dist/api/project.d.ts +89 -0
- package/dist/api/project.d.ts.map +1 -0
- package/dist/api/project.js +150 -0
- package/dist/api/project.js.map +1 -0
- package/dist/api/tagged.d.ts +14 -0
- package/dist/api/tagged.d.ts.map +1 -0
- package/dist/api/tagged.js +13 -0
- package/dist/api/tagged.js.map +1 -0
- package/dist/cli/dto-check.d.ts +25 -0
- package/dist/cli/dto-check.d.ts.map +1 -0
- package/dist/cli/dto-check.js +77 -0
- package/dist/cli/dto-check.js.map +1 -0
- package/dist/cli/fhirpath-check.d.ts +3 -0
- package/dist/cli/fhirpath-check.d.ts.map +1 -0
- package/dist/cli/fhirpath-check.js +149 -0
- package/dist/cli/fhirpath-check.js.map +1 -0
- package/dist/cli/ts-loader.d.mts +3 -0
- package/dist/cli/ts-loader.d.mts.map +1 -0
- package/dist/cli/ts-loader.mjs +48 -0
- package/dist/cli/ts-loader.mjs.map +1 -0
- package/dist/engine/context.d.ts +173 -0
- package/dist/engine/context.d.ts.map +1 -0
- package/dist/engine/context.js +118 -0
- package/dist/engine/context.js.map +1 -0
- package/dist/engine/evaluator.d.ts +7 -0
- package/dist/engine/evaluator.d.ts.map +1 -0
- package/dist/engine/evaluator.js +196 -0
- package/dist/engine/evaluator.js.map +1 -0
- package/dist/engine/navigation.d.ts +11 -0
- package/dist/engine/navigation.d.ts.map +1 -0
- package/dist/engine/navigation.js +102 -0
- package/dist/engine/navigation.js.map +1 -0
- package/dist/engine/operators/collections.d.ts +12 -0
- package/dist/engine/operators/collections.d.ts.map +1 -0
- package/dist/engine/operators/collections.js +31 -0
- package/dist/engine/operators/collections.js.map +1 -0
- package/dist/engine/operators/comparison.d.ts +13 -0
- package/dist/engine/operators/comparison.d.ts.map +1 -0
- package/dist/engine/operators/comparison.js +77 -0
- package/dist/engine/operators/comparison.js.map +1 -0
- package/dist/engine/operators/equality.d.ts +19 -0
- package/dist/engine/operators/equality.d.ts.map +1 -0
- package/dist/engine/operators/equality.js +203 -0
- package/dist/engine/operators/equality.js.map +1 -0
- package/dist/engine/operators/index.d.ts +18 -0
- package/dist/engine/operators/index.d.ts.map +1 -0
- package/dist/engine/operators/index.js +30 -0
- package/dist/engine/operators/index.js.map +1 -0
- package/dist/engine/operators/logic.d.ts +8 -0
- package/dist/engine/operators/logic.d.ts.map +1 -0
- package/dist/engine/operators/logic.js +38 -0
- package/dist/engine/operators/logic.js.map +1 -0
- package/dist/engine/operators/math.d.ts +13 -0
- package/dist/engine/operators/math.d.ts.map +1 -0
- package/dist/engine/operators/math.js +198 -0
- package/dist/engine/operators/math.js.map +1 -0
- package/dist/engine/operators/strings.d.ts +8 -0
- package/dist/engine/operators/strings.d.ts.map +1 -0
- package/dist/engine/operators/strings.js +22 -0
- package/dist/engine/operators/strings.js.map +1 -0
- package/dist/engine/operators/types.d.ts +3 -0
- package/dist/engine/operators/types.d.ts.map +1 -0
- package/dist/engine/operators/types.js +15 -0
- package/dist/engine/operators/types.js.map +1 -0
- package/dist/engine/type-matching.d.ts +20 -0
- package/dist/engine/type-matching.d.ts.map +1 -0
- package/dist/engine/type-matching.js +122 -0
- package/dist/engine/type-matching.js.map +1 -0
- package/dist/errors.d.ts +25 -0
- package/dist/errors.d.ts.map +1 -0
- package/dist/errors.js +21 -0
- package/dist/errors.js.map +1 -0
- package/dist/eslint/index.d.ts +12 -0
- package/dist/eslint/index.d.ts.map +1 -0
- package/dist/eslint/index.js +316 -0
- package/dist/eslint/index.js.map +1 -0
- package/dist/fhir/html-checks.d.ts +7 -0
- package/dist/fhir/html-checks.d.ts.map +1 -0
- package/dist/fhir/html-checks.js +256 -0
- package/dist/fhir/html-checks.js.map +1 -0
- package/dist/fhir/model-navigation.d.ts +11 -0
- package/dist/fhir/model-navigation.d.ts.map +1 -0
- package/dist/fhir/model-navigation.js +142 -0
- package/dist/fhir/model-navigation.js.map +1 -0
- package/dist/functions/aggregate.d.ts +2 -0
- package/dist/functions/aggregate.d.ts.map +1 -0
- package/dist/functions/aggregate.js +127 -0
- package/dist/functions/aggregate.js.map +1 -0
- package/dist/functions/boundary.d.ts +2 -0
- package/dist/functions/boundary.d.ts.map +1 -0
- package/dist/functions/boundary.js +189 -0
- package/dist/functions/boundary.js.map +1 -0
- package/dist/functions/combining.d.ts +2 -0
- package/dist/functions/combining.d.ts.map +1 -0
- package/dist/functions/combining.js +13 -0
- package/dist/functions/combining.js.map +1 -0
- package/dist/functions/control.d.ts +2 -0
- package/dist/functions/control.d.ts.map +1 -0
- package/dist/functions/control.js +25 -0
- package/dist/functions/control.js.map +1 -0
- package/dist/functions/conversion.d.ts +3 -0
- package/dist/functions/conversion.d.ts.map +1 -0
- package/dist/functions/conversion.js +316 -0
- package/dist/functions/conversion.js.map +1 -0
- package/dist/functions/date-components.d.ts +2 -0
- package/dist/functions/date-components.d.ts.map +1 -0
- package/dist/functions/date-components.js +81 -0
- package/dist/functions/date-components.js.map +1 -0
- package/dist/functions/existence.d.ts +4 -0
- package/dist/functions/existence.d.ts.map +1 -0
- package/dist/functions/existence.js +97 -0
- package/dist/functions/existence.js.map +1 -0
- package/dist/functions/fhir.d.ts +2 -0
- package/dist/functions/fhir.d.ts.map +1 -0
- package/dist/functions/fhir.js +222 -0
- package/dist/functions/fhir.js.map +1 -0
- package/dist/functions/filtering.d.ts +2 -0
- package/dist/functions/filtering.d.ts.map +1 -0
- package/dist/functions/filtering.js +112 -0
- package/dist/functions/filtering.js.map +1 -0
- package/dist/functions/install.d.ts +18 -0
- package/dist/functions/install.d.ts.map +1 -0
- package/dist/functions/install.js +20 -0
- package/dist/functions/install.js.map +1 -0
- package/dist/functions/iteration.d.ts +7 -0
- package/dist/functions/iteration.d.ts.map +1 -0
- package/dist/functions/iteration.js +9 -0
- package/dist/functions/iteration.js.map +1 -0
- package/dist/functions/math.d.ts +2 -0
- package/dist/functions/math.d.ts.map +1 -0
- package/dist/functions/math.js +152 -0
- package/dist/functions/math.js.map +1 -0
- package/dist/functions/reflection.d.ts +2 -0
- package/dist/functions/reflection.d.ts.map +1 -0
- package/dist/functions/reflection.js +23 -0
- package/dist/functions/reflection.js.map +1 -0
- package/dist/functions/registry.d.ts +28 -0
- package/dist/functions/registry.d.ts.map +1 -0
- package/dist/functions/registry.js +46 -0
- package/dist/functions/registry.js.map +1 -0
- package/dist/functions/sort.d.ts +2 -0
- package/dist/functions/sort.d.ts.map +1 -0
- package/dist/functions/sort.js +48 -0
- package/dist/functions/sort.js.map +1 -0
- package/dist/functions/string.d.ts +2 -0
- package/dist/functions/string.d.ts.map +1 -0
- package/dist/functions/string.js +353 -0
- package/dist/functions/string.js.map +1 -0
- package/dist/functions/subsetting.d.ts +2 -0
- package/dist/functions/subsetting.d.ts.map +1 -0
- package/dist/functions/subsetting.js +72 -0
- package/dist/functions/subsetting.js.map +1 -0
- package/dist/functions/tree.d.ts +8 -0
- package/dist/functions/tree.d.ts.map +1 -0
- package/dist/functions/tree.js +109 -0
- package/dist/functions/tree.js.map +1 -0
- package/dist/functions/type-specifier.d.ts +8 -0
- package/dist/functions/type-specifier.d.ts.map +1 -0
- package/dist/functions/type-specifier.js +27 -0
- package/dist/functions/type-specifier.js.map +1 -0
- package/dist/functions/utility.d.ts +2 -0
- package/dist/functions/utility.d.ts.map +1 -0
- package/dist/functions/utility.js +76 -0
- package/dist/functions/utility.js.map +1 -0
- package/dist/functions/variables.d.ts +2 -0
- package/dist/functions/variables.d.ts.map +1 -0
- package/dist/functions/variables.js +35 -0
- package/dist/functions/variables.js.map +1 -0
- package/dist/index.d.ts +25 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +11 -0
- package/dist/index.js.map +1 -0
- package/dist/lexer/lexer.d.ts +4 -0
- package/dist/lexer/lexer.d.ts.map +1 -0
- package/dist/lexer/lexer.js +318 -0
- package/dist/lexer/lexer.js.map +1 -0
- package/dist/lexer/tokens.d.ts +23 -0
- package/dist/lexer/tokens.d.ts.map +1 -0
- package/dist/lexer/tokens.js +40 -0
- package/dist/lexer/tokens.js.map +1 -0
- package/dist/model/provider.d.ts +36 -0
- package/dist/model/provider.d.ts.map +1 -0
- package/dist/model/provider.js +2 -0
- package/dist/model/provider.js.map +1 -0
- package/dist/parser/ast.d.ts +104 -0
- package/dist/parser/ast.d.ts.map +1 -0
- package/dist/parser/ast.js +2 -0
- package/dist/parser/ast.js.map +1 -0
- package/dist/parser/parser.d.ts +4 -0
- package/dist/parser/parser.d.ts.map +1 -0
- package/dist/parser/parser.js +299 -0
- package/dist/parser/parser.js.map +1 -0
- package/dist/parser/precedence.d.ts +24 -0
- package/dist/parser/precedence.d.ts.map +1 -0
- package/dist/parser/precedence.js +52 -0
- package/dist/parser/precedence.js.map +1 -0
- package/dist/parser/printer.d.ts +4 -0
- package/dist/parser/printer.d.ts.map +1 -0
- package/dist/parser/printer.js +112 -0
- package/dist/parser/printer.js.map +1 -0
- package/dist/r4/generated/resources-data.d.ts +3 -0
- package/dist/r4/generated/resources-data.d.ts.map +1 -0
- package/dist/r4/generated/resources-data.js +28628 -0
- package/dist/r4/generated/resources-data.js.map +1 -0
- package/dist/r4/generated/type-maps.d.ts +43153 -0
- package/dist/r4/generated/type-maps.d.ts.map +1 -0
- package/dist/r4/generated/type-maps.js +4 -0
- package/dist/r4/generated/type-maps.js.map +1 -0
- package/dist/r4/generated/types-data.d.ts +3 -0
- package/dist/r4/generated/types-data.d.ts.map +1 -0
- package/dist/r4/generated/types-data.js +2205 -0
- package/dist/r4/generated/types-data.js.map +1 -0
- package/dist/r4/index.d.ts +9 -0
- package/dist/r4/index.d.ts.map +1 -0
- package/dist/r4/index.js +94 -0
- package/dist/r4/index.js.map +1 -0
- package/dist/r4/model-data.d.ts +17 -0
- package/dist/r4/model-data.d.ts.map +1 -0
- package/dist/r4/model-data.js +2 -0
- package/dist/r4/model-data.js.map +1 -0
- package/dist/sites/index.d.ts +31 -0
- package/dist/sites/index.d.ts.map +1 -0
- package/dist/sites/index.js +205 -0
- package/dist/sites/index.js.map +1 -0
- package/dist/typed/infer.d.ts +234 -0
- package/dist/typed/infer.d.ts.map +1 -0
- package/dist/typed/infer.js +85 -0
- package/dist/typed/infer.js.map +1 -0
- package/dist/typed/perf-fixture.types.d.ts +136 -0
- package/dist/typed/perf-fixture.types.d.ts.map +1 -0
- package/dist/typed/perf-fixture.types.js +2 -0
- package/dist/typed/perf-fixture.types.js.map +1 -0
- package/dist/values/collection.d.ts +24 -0
- package/dist/values/collection.d.ts.map +1 -0
- package/dist/values/collection.js +51 -0
- package/dist/values/collection.js.map +1 -0
- package/dist/values/datetime.d.ts +54 -0
- package/dist/values/datetime.d.ts.map +1 -0
- package/dist/values/datetime.js +226 -0
- package/dist/values/datetime.js.map +1 -0
- package/dist/values/decimal.d.ts +48 -0
- package/dist/values/decimal.d.ts.map +1 -0
- package/dist/values/decimal.js +188 -0
- package/dist/values/decimal.js.map +1 -0
- package/dist/values/numeric.d.ts +24 -0
- package/dist/values/numeric.d.ts.map +1 -0
- package/dist/values/numeric.js +53 -0
- package/dist/values/numeric.js.map +1 -0
- package/dist/values/quantity.d.ts +49 -0
- package/dist/values/quantity.d.ts.map +1 -0
- package/dist/values/quantity.js +297 -0
- package/dist/values/quantity.js.map +1 -0
- package/dist/values/temporal-arithmetic.d.ts +17 -0
- package/dist/values/temporal-arithmetic.d.ts.map +1 -0
- package/dist/values/temporal-arithmetic.js +183 -0
- package/dist/values/temporal-arithmetic.js.map +1 -0
- package/dist/values/temporal-compare.d.ts +9 -0
- package/dist/values/temporal-compare.d.ts.map +1 -0
- package/dist/values/temporal-compare.js +59 -0
- package/dist/values/temporal-compare.js.map +1 -0
- package/dist/values/type-compat.d.ts +47 -0
- package/dist/values/type-compat.d.ts.map +1 -0
- package/dist/values/type-compat.js +100 -0
- package/dist/values/type-compat.js.map +1 -0
- package/dist/values/typed-value.d.ts +48 -0
- package/dist/values/typed-value.d.ts.map +1 -0
- package/dist/values/typed-value.js +117 -0
- package/dist/values/typed-value.js.map +1 -0
- package/dist/values/ucum.d.ts +14 -0
- package/dist/values/ucum.d.ts.map +1 -0
- package/dist/values/ucum.js +146 -0
- package/dist/values/ucum.js.map +1 -0
- package/package.json +137 -0
- package/src/analyzer/analyze-dto.ts +195 -0
- package/src/analyzer/analyze.ts +1181 -0
- package/src/analyzer/expression-policy.ts +434 -0
- package/src/analyzer/index.ts +23 -0
- package/src/analyzer/regex-safety.ts +85 -0
- package/src/analyzer/signatures.ts +260 -0
- package/src/api/bundle.ts +132 -0
- package/src/api/cache.ts +40 -0
- package/src/api/column-signature.ts +71 -0
- package/src/api/compile.ts +308 -0
- package/src/api/constraints.ts +104 -0
- package/src/api/dto.ts +445 -0
- package/src/api/engine.ts +328 -0
- package/src/api/evaluate.ts +11 -0
- package/src/api/project.ts +255 -0
- package/src/api/tagged.ts +35 -0
- package/src/cli/dto-check.ts +94 -0
- package/src/cli/fhirpath-check.ts +168 -0
- package/src/cli/ts-loader.mjs +49 -0
- package/src/engine/context.ts +282 -0
- package/src/engine/evaluator.ts +246 -0
- package/src/engine/navigation.ts +106 -0
- package/src/engine/operators/collections.ts +34 -0
- package/src/engine/operators/comparison.ts +82 -0
- package/src/engine/operators/equality.ts +232 -0
- package/src/engine/operators/index.ts +65 -0
- package/src/engine/operators/logic.ts +53 -0
- package/src/engine/operators/math.ts +225 -0
- package/src/engine/operators/strings.ts +25 -0
- package/src/engine/operators/types.ts +16 -0
- package/src/engine/type-matching.ts +148 -0
- package/src/errors.ts +33 -0
- package/src/eslint/index.ts +388 -0
- package/src/fhir/html-checks.ts +266 -0
- package/src/fhir/model-navigation.ts +148 -0
- package/src/functions/aggregate.ts +136 -0
- package/src/functions/boundary.ts +209 -0
- package/src/functions/combining.ts +15 -0
- package/src/functions/control.ts +25 -0
- package/src/functions/conversion.ts +349 -0
- package/src/functions/date-components.ts +88 -0
- package/src/functions/existence.ts +107 -0
- package/src/functions/fhir.ts +247 -0
- package/src/functions/filtering.ts +120 -0
- package/src/functions/install.ts +19 -0
- package/src/functions/iteration.ts +21 -0
- package/src/functions/math.ts +167 -0
- package/src/functions/reflection.ts +24 -0
- package/src/functions/registry.ts +72 -0
- package/src/functions/sort.ts +68 -0
- package/src/functions/string.ts +413 -0
- package/src/functions/subsetting.ts +89 -0
- package/src/functions/tree.ts +112 -0
- package/src/functions/type-specifier.ts +29 -0
- package/src/functions/utility.ts +82 -0
- package/src/functions/variables.ts +36 -0
- package/src/index.ts +30 -0
- package/src/lexer/lexer.ts +341 -0
- package/src/lexer/tokens.ts +69 -0
- package/src/model/provider.ts +36 -0
- package/src/parser/ast.ts +164 -0
- package/src/parser/parser.ts +321 -0
- package/src/parser/precedence.ts +52 -0
- package/src/parser/printer.ts +114 -0
- package/src/r4/generated/resources-data.ts +28631 -0
- package/src/r4/generated/type-maps.ts +22145 -0
- package/src/r4/generated/types-data.ts +2208 -0
- package/src/r4/index.ts +107 -0
- package/src/r4/model-data.ts +17 -0
- package/src/sites/index.ts +285 -0
- package/src/typed/infer.ts +433 -0
- package/src/typed/perf-fixture.types.ts +143 -0
- package/src/values/collection.ts +57 -0
- package/src/values/datetime.ts +285 -0
- package/src/values/decimal.ts +213 -0
- package/src/values/numeric.ts +63 -0
- package/src/values/quantity.ts +358 -0
- package/src/values/temporal-arithmetic.ts +231 -0
- package/src/values/temporal-compare.ts +65 -0
- package/src/values/type-compat.ts +133 -0
- package/src/values/typed-value.ts +151 -0
- 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. 	) 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 — `javascript:` 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:) 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 	/: 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
|
+
})
|