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
package/src/r4/index.ts
ADDED
|
@@ -0,0 +1,107 @@
|
|
|
1
|
+
import { FhirPathEngine } from '../api/engine.ts'
|
|
2
|
+
import type { ElementInfo, ModelProvider } from '../model/provider.ts'
|
|
3
|
+
import { R4_RESOURCES } from './generated/resources-data.ts'
|
|
4
|
+
import { R4_DATA_TYPES } from './generated/types-data.ts'
|
|
5
|
+
import type { GeneratedElement, GeneratedType } from './model-data.ts'
|
|
6
|
+
|
|
7
|
+
// One canonical FHIR-primitive → System map lives in values/typed-value.ts;
|
|
8
|
+
// re-exported here because the model subpath is where consumers look for it.
|
|
9
|
+
export { FHIR_PRIMITIVE_TO_SYSTEM as PRIMITIVE_TO_SYSTEM } from '../values/typed-value.ts'
|
|
10
|
+
export type { GeneratedElement, GeneratedType } from './model-data.ts'
|
|
11
|
+
|
|
12
|
+
const NAMESPACE = 'FHIR'
|
|
13
|
+
const PREFIX = `${NAMESPACE}.`
|
|
14
|
+
|
|
15
|
+
function lookupType(name: string): GeneratedType | undefined {
|
|
16
|
+
return R4_RESOURCES[name] ?? R4_DATA_TYPES[name]
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
function localName(canonical: string): string {
|
|
20
|
+
return canonical.startsWith(PREFIX) ? canonical.slice(PREFIX.length) : canonical
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
/**
|
|
24
|
+
* Walk a type and its ancestors for an element. Backbone elements are typed by
|
|
25
|
+
* their path (`Patient.contact`), which is itself a key in the generated tables.
|
|
26
|
+
*/
|
|
27
|
+
function findElement(typeName: string, element: string): GeneratedElement | undefined {
|
|
28
|
+
let current: string | undefined = typeName
|
|
29
|
+
const visited = new Set<string>()
|
|
30
|
+
while (current !== undefined && !visited.has(current)) {
|
|
31
|
+
visited.add(current)
|
|
32
|
+
const definition = lookupType(current)
|
|
33
|
+
if (!definition) {
|
|
34
|
+
return undefined
|
|
35
|
+
}
|
|
36
|
+
const found: GeneratedElement | undefined = definition.e[element]
|
|
37
|
+
if (found) {
|
|
38
|
+
return found
|
|
39
|
+
}
|
|
40
|
+
current = definition.b
|
|
41
|
+
}
|
|
42
|
+
return undefined
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
/** The generated R4 model: type resolution, element lookup, and the type hierarchy. */
|
|
46
|
+
export const r4Model: ModelProvider = {
|
|
47
|
+
namespace: NAMESPACE,
|
|
48
|
+
|
|
49
|
+
resolveType(name: string): string | undefined {
|
|
50
|
+
return lookupType(name) ? `${PREFIX}${name}` : undefined
|
|
51
|
+
},
|
|
52
|
+
|
|
53
|
+
getElement(type: string, element: string): ElementInfo | undefined {
|
|
54
|
+
const found = findElement(localName(type), element)
|
|
55
|
+
if (!found) {
|
|
56
|
+
return undefined
|
|
57
|
+
}
|
|
58
|
+
return {
|
|
59
|
+
types: found.t,
|
|
60
|
+
isCollection: found.a === 1,
|
|
61
|
+
isChoice: found.c === 1,
|
|
62
|
+
...(found.r !== undefined && { referenceTargets: found.r }),
|
|
63
|
+
}
|
|
64
|
+
},
|
|
65
|
+
|
|
66
|
+
listElements(type: string): string[] | undefined {
|
|
67
|
+
let current: string | undefined = localName(type)
|
|
68
|
+
if (!lookupType(current)) {
|
|
69
|
+
return undefined
|
|
70
|
+
}
|
|
71
|
+
const names: string[] = []
|
|
72
|
+
const seen = new Set<string>()
|
|
73
|
+
const visited = new Set<string>()
|
|
74
|
+
while (current !== undefined && !visited.has(current)) {
|
|
75
|
+
visited.add(current)
|
|
76
|
+
const definition = lookupType(current)
|
|
77
|
+
if (!definition) {
|
|
78
|
+
break
|
|
79
|
+
}
|
|
80
|
+
for (const name of Object.keys(definition.e)) {
|
|
81
|
+
if (!seen.has(name)) {
|
|
82
|
+
seen.add(name)
|
|
83
|
+
names.push(name)
|
|
84
|
+
}
|
|
85
|
+
}
|
|
86
|
+
current = definition.b
|
|
87
|
+
}
|
|
88
|
+
return names
|
|
89
|
+
},
|
|
90
|
+
|
|
91
|
+
isSubtypeOf(type: string, base: string): boolean {
|
|
92
|
+
const target = localName(base)
|
|
93
|
+
let current: string | undefined = localName(type)
|
|
94
|
+
const visited = new Set<string>()
|
|
95
|
+
while (current !== undefined && !visited.has(current)) {
|
|
96
|
+
if (current === target) {
|
|
97
|
+
return true
|
|
98
|
+
}
|
|
99
|
+
visited.add(current)
|
|
100
|
+
current = lookupType(current)?.b
|
|
101
|
+
}
|
|
102
|
+
return false
|
|
103
|
+
},
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
/** A ready-made engine with the R4 model bound: `r4.evaluate('Patient.name.given', patient)`. */
|
|
107
|
+
export const r4 = new FhirPathEngine({ model: r4Model })
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
/** Shapes of the generated R4 model data (see scripts/generate-r4-model.ts). */
|
|
2
|
+
export interface GeneratedElement {
|
|
3
|
+
/** Element types; several entries for choice elements (`value[x]`). */
|
|
4
|
+
t: string[]
|
|
5
|
+
/** Present (1) when max cardinality is above 1. */
|
|
6
|
+
a?: 1
|
|
7
|
+
/** Present (1) for choice elements: JSON keys carry a type suffix (valueQuantity). */
|
|
8
|
+
c?: 1
|
|
9
|
+
/** Resource names a Reference element may point to (targetProfile); absent when unconstrained. */
|
|
10
|
+
r?: string[]
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
export interface GeneratedType {
|
|
14
|
+
/** Base type local name, absent for the roots (Base, Element). */
|
|
15
|
+
b?: string
|
|
16
|
+
e: Record<string, GeneratedElement>
|
|
17
|
+
}
|
|
@@ -0,0 +1,285 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Finds FHIRPath expressions in a TypeScript AST. The caller supplies TypeScript,
|
|
3
|
+
* which keeps this entry point free of runtime dependencies. The ESLint rule has
|
|
4
|
+
* a separate ESTree walker that uses the same expression policy.
|
|
5
|
+
*/
|
|
6
|
+
// A default import, not `* as TS`. Under Node's ESM resolution a namespace
|
|
7
|
+
// import of `typescript` (a CommonJS `export =` module) carries a synthetic
|
|
8
|
+
// `default` property that a caller's own `import ts from 'typescript'` does not,
|
|
9
|
+
// so `typeof TS` would reject the very value callers pass. The default form
|
|
10
|
+
// names the same namespace — `TS.Node` still resolves — and accepts both.
|
|
11
|
+
import type TS from 'typescript'
|
|
12
|
+
|
|
13
|
+
import {
|
|
14
|
+
CALL_SITES,
|
|
15
|
+
type ClassHeritage,
|
|
16
|
+
columnFunctionDeclaration,
|
|
17
|
+
constructsEngine,
|
|
18
|
+
declaredColumnOverloads,
|
|
19
|
+
DTO_BASE_NAME,
|
|
20
|
+
dtoRootsOf,
|
|
21
|
+
type ExpressionAst,
|
|
22
|
+
expressionEntries,
|
|
23
|
+
type FileColumnFunction,
|
|
24
|
+
isCheckedCall,
|
|
25
|
+
isCheckedTag,
|
|
26
|
+
isForeignModule,
|
|
27
|
+
type LocalModuleOptions,
|
|
28
|
+
rootOf,
|
|
29
|
+
type SiteContext,
|
|
30
|
+
siteContext,
|
|
31
|
+
type SourceBindings,
|
|
32
|
+
TAG_NAME,
|
|
33
|
+
} from '../analyzer/expression-policy.ts'
|
|
34
|
+
|
|
35
|
+
/** The TypeScript namespace accepted by `createSiteFinder`. */
|
|
36
|
+
export type TypeScriptApi = typeof TS
|
|
37
|
+
|
|
38
|
+
export interface ExpressionSite {
|
|
39
|
+
expression: string
|
|
40
|
+
/** 0-based offset of the expression text inside the file. */
|
|
41
|
+
start: number
|
|
42
|
+
line: number
|
|
43
|
+
column: number
|
|
44
|
+
/** The DTO fhirType the expression is analyzed against, when the site fixes one. */
|
|
45
|
+
inputType?: string
|
|
46
|
+
/** A DTO member site, which `analyzeSite` checks with source-only limits. */
|
|
47
|
+
dto?: true
|
|
48
|
+
/** Callable DTO columns declared in the same file. */
|
|
49
|
+
functions?: Readonly<Record<string, FileColumnFunction>>
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
/** Finds every static FHIRPath expression in one source file. */
|
|
53
|
+
export type SiteFinder = (sourceText: string, fileName: string, options?: LocalModuleOptions) => ExpressionSite[]
|
|
54
|
+
|
|
55
|
+
/**
|
|
56
|
+
* Creates a finder for the calls and tags in `CALL_SITES`. DTO fields include a
|
|
57
|
+
* root type when the class declares one, and each column is exposed as a local
|
|
58
|
+
* function declaration. Dynamic expressions are skipped.
|
|
59
|
+
*/
|
|
60
|
+
export function createSiteFinder(ts: TypeScriptApi): SiteFinder {
|
|
61
|
+
/** How the shared shape extractor reads TypeScript AST nodes. */
|
|
62
|
+
const tsAst: ExpressionAst<TS.Node> = {
|
|
63
|
+
string: node => (ts.isStringLiteralLike(node) ? { node, expression: node.text } : undefined),
|
|
64
|
+
boolean: node =>
|
|
65
|
+
node.kind === ts.SyntaxKind.TrueKeyword ? true : node.kind === ts.SyntaxKind.FalseKeyword ? false : undefined,
|
|
66
|
+
properties: node =>
|
|
67
|
+
ts.isObjectLiteralExpression(node)
|
|
68
|
+
? node.properties
|
|
69
|
+
.filter(ts.isPropertyAssignment)
|
|
70
|
+
.map(property => ({ name: propertyKeyName(property.name), value: property.initializer }))
|
|
71
|
+
: undefined,
|
|
72
|
+
elements: node => (ts.isArrayLiteralExpression(node) ? [...node.elements] : undefined),
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
/** Statically-known property key (`path` in `{ path: ... }` or `{ 'path': ... }`), undefined when computed. */
|
|
76
|
+
function propertyKeyName(name: TS.PropertyName): string | undefined {
|
|
77
|
+
return ts.isIdentifier(name) || ts.isStringLiteral(name) ? name.text : undefined
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
/** The name of the field a `@column(...)` decorator belongs to. */
|
|
81
|
+
function decoratedFieldName(call: TS.CallExpression): string | undefined {
|
|
82
|
+
const decorator = call.parent
|
|
83
|
+
const member = decorator?.parent
|
|
84
|
+
if (
|
|
85
|
+
decorator === undefined ||
|
|
86
|
+
!ts.isDecorator(decorator) ||
|
|
87
|
+
member === undefined ||
|
|
88
|
+
!ts.isPropertyDeclaration(member) ||
|
|
89
|
+
!(ts.isIdentifier(member.name) || ts.isStringLiteral(member.name))
|
|
90
|
+
) {
|
|
91
|
+
return undefined
|
|
92
|
+
}
|
|
93
|
+
return member.name.text
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
/** A class's heritage, as `dtoRootsOf` reads it: its own DTO root, or the name of the class it extends. */
|
|
97
|
+
function heritageOf(node: TS.ClassLikeDeclaration): ClassHeritage {
|
|
98
|
+
const heritage: ClassHeritage = { name: node.name?.text, ownRoot: undefined, baseName: undefined }
|
|
99
|
+
for (const clause of node.heritageClauses ?? []) {
|
|
100
|
+
if (clause.token !== ts.SyntaxKind.ExtendsKeyword) {
|
|
101
|
+
continue
|
|
102
|
+
}
|
|
103
|
+
for (const type of clause.types) {
|
|
104
|
+
const base = type.expression
|
|
105
|
+
if (ts.isCallExpression(base)) {
|
|
106
|
+
if (nameOf(base.expression) === DTO_BASE_NAME) {
|
|
107
|
+
const root = base.arguments[0]
|
|
108
|
+
heritage.ownRoot = root === undefined ? undefined : tsAst.string(root)?.expression
|
|
109
|
+
}
|
|
110
|
+
} else if (ts.isIdentifier(base)) {
|
|
111
|
+
heritage.baseName = base.text
|
|
112
|
+
}
|
|
113
|
+
}
|
|
114
|
+
}
|
|
115
|
+
return heritage
|
|
116
|
+
}
|
|
117
|
+
|
|
118
|
+
/** Collects imports, engine locals, rebound names, and DTO class roots before extracting sites. */
|
|
119
|
+
function collectFile(
|
|
120
|
+
source: TS.SourceFile,
|
|
121
|
+
options: LocalModuleOptions
|
|
122
|
+
): {
|
|
123
|
+
bindings: SourceBindings
|
|
124
|
+
dtoRoots: ReadonlyMap<string, string>
|
|
125
|
+
heritage: ReadonlyMap<TS.Node, ClassHeritage>
|
|
126
|
+
} {
|
|
127
|
+
const foreign = new Set<string>()
|
|
128
|
+
const trusted = new Set<string>()
|
|
129
|
+
const rebound = new Set<string>()
|
|
130
|
+
for (const statement of source.statements) {
|
|
131
|
+
if (!(ts.isImportDeclaration(statement) && ts.isStringLiteral(statement.moduleSpecifier))) {
|
|
132
|
+
continue
|
|
133
|
+
}
|
|
134
|
+
const names = isForeignModule(statement.moduleSpecifier.text, options) ? foreign : trusted
|
|
135
|
+
const clause = statement.importClause
|
|
136
|
+
if (!clause) {
|
|
137
|
+
continue
|
|
138
|
+
}
|
|
139
|
+
if (clause.name) {
|
|
140
|
+
names.add(clause.name.text)
|
|
141
|
+
}
|
|
142
|
+
if (clause.namedBindings) {
|
|
143
|
+
if (ts.isNamedImports(clause.namedBindings)) {
|
|
144
|
+
for (const element of clause.namedBindings.elements) {
|
|
145
|
+
names.add(element.name.text)
|
|
146
|
+
}
|
|
147
|
+
} else {
|
|
148
|
+
names.add(clause.namedBindings.name.text)
|
|
149
|
+
}
|
|
150
|
+
}
|
|
151
|
+
}
|
|
152
|
+
const bindings = { foreign, trusted, rebound }
|
|
153
|
+
const heritage = new Map<TS.Node, ClassHeritage>()
|
|
154
|
+
const collectLocals = (node: TS.Node): void => {
|
|
155
|
+
if (ts.isClassLike(node)) {
|
|
156
|
+
heritage.set(node, heritageOf(node))
|
|
157
|
+
}
|
|
158
|
+
if (ts.isVariableDeclaration(node)) {
|
|
159
|
+
if (
|
|
160
|
+
ts.isIdentifier(node.name) &&
|
|
161
|
+
node.initializer !== undefined &&
|
|
162
|
+
ts.isNewExpression(node.initializer) &&
|
|
163
|
+
ts.isIdentifier(node.initializer.expression)
|
|
164
|
+
) {
|
|
165
|
+
const set = constructsEngine(node.initializer.expression.text, bindings) ? trusted : rebound
|
|
166
|
+
set.add(node.name.text)
|
|
167
|
+
} else {
|
|
168
|
+
// Catch clauses reach here too: `catch (r4)` is a VariableDeclaration.
|
|
169
|
+
addBindingNames(node.name, rebound)
|
|
170
|
+
}
|
|
171
|
+
} else if (ts.isParameter(node)) {
|
|
172
|
+
addBindingNames(node.name, rebound)
|
|
173
|
+
} else if (
|
|
174
|
+
(ts.isFunctionDeclaration(node) ||
|
|
175
|
+
ts.isFunctionExpression(node) ||
|
|
176
|
+
ts.isClassDeclaration(node) ||
|
|
177
|
+
ts.isClassExpression(node)) &&
|
|
178
|
+
node.name !== undefined
|
|
179
|
+
) {
|
|
180
|
+
rebound.add(node.name.text)
|
|
181
|
+
}
|
|
182
|
+
ts.forEachChild(node, collectLocals)
|
|
183
|
+
}
|
|
184
|
+
collectLocals(source)
|
|
185
|
+
return { bindings, dtoRoots: dtoRootsOf([...heritage.values()]), heritage }
|
|
186
|
+
}
|
|
187
|
+
|
|
188
|
+
/** Add every identifier a binding name declares (`x`, `{ r4 }`, `[a, ...rest]`). */
|
|
189
|
+
function addBindingNames(name: TS.BindingName, into: Set<string>): void {
|
|
190
|
+
if (ts.isIdentifier(name)) {
|
|
191
|
+
into.add(name.text)
|
|
192
|
+
return
|
|
193
|
+
}
|
|
194
|
+
for (const element of name.elements) {
|
|
195
|
+
if (ts.isBindingElement(element)) {
|
|
196
|
+
addBindingNames(element.name, into)
|
|
197
|
+
}
|
|
198
|
+
}
|
|
199
|
+
}
|
|
200
|
+
|
|
201
|
+
function nameOf(node: TS.Expression): string | undefined {
|
|
202
|
+
if (ts.isIdentifier(node)) {
|
|
203
|
+
return node.text
|
|
204
|
+
}
|
|
205
|
+
if (ts.isPropertyAccessExpression(node)) {
|
|
206
|
+
return node.name.text
|
|
207
|
+
}
|
|
208
|
+
return undefined
|
|
209
|
+
}
|
|
210
|
+
|
|
211
|
+
/** Leftmost identifier of a member-access callee (`Handlebars` in `Handlebars.compile`). */
|
|
212
|
+
function receiverRoot(callee: TS.Expression): string | undefined {
|
|
213
|
+
if (!ts.isPropertyAccessExpression(callee)) {
|
|
214
|
+
return undefined
|
|
215
|
+
}
|
|
216
|
+
let current: TS.Expression = callee.expression
|
|
217
|
+
while (ts.isPropertyAccessExpression(current) || ts.isElementAccessExpression(current)) {
|
|
218
|
+
current = current.expression
|
|
219
|
+
}
|
|
220
|
+
return ts.isIdentifier(current) ? current.text : undefined
|
|
221
|
+
}
|
|
222
|
+
|
|
223
|
+
return function findExpressionSites(
|
|
224
|
+
sourceText: string,
|
|
225
|
+
fileName: string,
|
|
226
|
+
options: LocalModuleOptions = {}
|
|
227
|
+
): ExpressionSite[] {
|
|
228
|
+
const source = ts.createSourceFile(fileName, sourceText, ts.ScriptTarget.Latest, true)
|
|
229
|
+
const { bindings, dtoRoots, heritage } = collectFile(source, options)
|
|
230
|
+
const sites: ExpressionSite[] = []
|
|
231
|
+
const functions: Record<string, FileColumnFunction> = {}
|
|
232
|
+
// A site points at the first character inside the quote/backtick (node start
|
|
233
|
+
// + 1), so fhirpath-check can add a diagnostic's span offsets directly. The
|
|
234
|
+
// ESLint rule reports on the literal node itself, one column earlier.
|
|
235
|
+
const record = (text: string, literalNode: TS.Node, context: SiteContext = {}): void => {
|
|
236
|
+
const literalStart = literalNode.getStart(source) + 1
|
|
237
|
+
const { line, character } = source.getLineAndCharacterOfPosition(literalStart)
|
|
238
|
+
sites.push({
|
|
239
|
+
expression: text,
|
|
240
|
+
start: literalStart,
|
|
241
|
+
line: line + 1,
|
|
242
|
+
column: character + 1,
|
|
243
|
+
...context,
|
|
244
|
+
})
|
|
245
|
+
}
|
|
246
|
+
const visit = (node: TS.Node, classRoot: string | undefined): void => {
|
|
247
|
+
if (
|
|
248
|
+
ts.isTaggedTemplateExpression(node) &&
|
|
249
|
+
nameOf(node.tag) === TAG_NAME &&
|
|
250
|
+
isCheckedTag(receiverRoot(node.tag), bindings)
|
|
251
|
+
) {
|
|
252
|
+
if (ts.isNoSubstitutionTemplateLiteral(node.template)) {
|
|
253
|
+
record(node.template.text, node.template)
|
|
254
|
+
}
|
|
255
|
+
} else if (ts.isCallExpression(node)) {
|
|
256
|
+
const callee = nameOf(node.expression)
|
|
257
|
+
const policy = callee === undefined ? undefined : CALL_SITES.get(callee)
|
|
258
|
+
const argument = policy && (node.arguments[policy.argIndex] as TS.Expression | undefined)
|
|
259
|
+
if (
|
|
260
|
+
callee !== undefined &&
|
|
261
|
+
policy !== undefined &&
|
|
262
|
+
argument !== undefined &&
|
|
263
|
+
isCheckedCall(policy, callee, receiverRoot(node.expression), bindings)
|
|
264
|
+
) {
|
|
265
|
+
const declares = policy.declaresField
|
|
266
|
+
const field = declares === undefined ? undefined : decoratedFieldName(node)
|
|
267
|
+
if (declares !== undefined && field !== undefined) {
|
|
268
|
+
functions[field] = declaredColumnOverloads(
|
|
269
|
+
functions[field],
|
|
270
|
+
columnFunctionDeclaration<TS.Node>(declares, node.arguments[1], tsAst, classRoot)
|
|
271
|
+
)
|
|
272
|
+
}
|
|
273
|
+
const context = siteContext<TS.Node>(policy, index => node.arguments[index], classRoot, tsAst)
|
|
274
|
+
for (const entry of expressionEntries<TS.Node>(argument, policy.shape, tsAst)) {
|
|
275
|
+
record(entry.expression, entry.node, context)
|
|
276
|
+
}
|
|
277
|
+
}
|
|
278
|
+
}
|
|
279
|
+
const nested = ts.isClassLike(node) ? rootOf(heritage.get(node), dtoRoots) : classRoot
|
|
280
|
+
ts.forEachChild(node, child => visit(child, nested))
|
|
281
|
+
}
|
|
282
|
+
visit(source, undefined)
|
|
283
|
+
return Object.keys(functions).length === 0 ? sites : sites.map(site => ({ ...site, functions }))
|
|
284
|
+
}
|
|
285
|
+
}
|