fhir-runtime 0.2.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/CHANGELOG.md +211 -0
- package/LICENSE +21 -0
- package/README.md +261 -0
- package/dist/cjs/index.cjs +7368 -0
- package/dist/cjs/index.cjs.map +7 -0
- package/dist/cjs/index.d.ts +4224 -0
- package/dist/cjs/package.json +5 -0
- package/dist/esm/index.d.ts +4224 -0
- package/dist/esm/index.mjs +7250 -0
- package/dist/esm/index.mjs.map +7 -0
- package/dist/esm/package.json +5 -0
- package/dist/index.d.ts +4224 -0
- package/dist/lib/context/bundle-loader.d.ts +124 -0
- package/dist/lib/context/bundle-loader.d.ts.map +1 -0
- package/dist/lib/context/core-definitions/index.d.ts +72 -0
- package/dist/lib/context/core-definitions/index.d.ts.map +1 -0
- package/dist/lib/context/errors.d.ts +114 -0
- package/dist/lib/context/errors.d.ts.map +1 -0
- package/dist/lib/context/fhir-context.d.ts +72 -0
- package/dist/lib/context/fhir-context.d.ts.map +1 -0
- package/dist/lib/context/index.d.ts +21 -0
- package/dist/lib/context/index.d.ts.map +1 -0
- package/dist/lib/context/inheritance-resolver.d.ts +98 -0
- package/dist/lib/context/inheritance-resolver.d.ts.map +1 -0
- package/dist/lib/context/inner-type-extractor.d.ts +80 -0
- package/dist/lib/context/inner-type-extractor.d.ts.map +1 -0
- package/dist/lib/context/loaders/composite-loader.d.ts +47 -0
- package/dist/lib/context/loaders/composite-loader.d.ts.map +1 -0
- package/dist/lib/context/loaders/file-loader.d.ts +47 -0
- package/dist/lib/context/loaders/file-loader.d.ts.map +1 -0
- package/dist/lib/context/loaders/index.d.ts +11 -0
- package/dist/lib/context/loaders/index.d.ts.map +1 -0
- package/dist/lib/context/loaders/memory-loader.d.ts +42 -0
- package/dist/lib/context/loaders/memory-loader.d.ts.map +1 -0
- package/dist/lib/context/registry.d.ts +116 -0
- package/dist/lib/context/registry.d.ts.map +1 -0
- package/dist/lib/context/types.d.ts +266 -0
- package/dist/lib/context/types.d.ts.map +1 -0
- package/dist/lib/fhirpath/atoms.d.ts +228 -0
- package/dist/lib/fhirpath/atoms.d.ts.map +1 -0
- package/dist/lib/fhirpath/cache.d.ts +79 -0
- package/dist/lib/fhirpath/cache.d.ts.map +1 -0
- package/dist/lib/fhirpath/date.d.ts +17 -0
- package/dist/lib/fhirpath/date.d.ts.map +1 -0
- package/dist/lib/fhirpath/functions.d.ts +28 -0
- package/dist/lib/fhirpath/functions.d.ts.map +1 -0
- package/dist/lib/fhirpath/index.d.ts +20 -0
- package/dist/lib/fhirpath/index.d.ts.map +1 -0
- package/dist/lib/fhirpath/lexer/parse.d.ts +100 -0
- package/dist/lib/fhirpath/lexer/parse.d.ts.map +1 -0
- package/dist/lib/fhirpath/lexer/tokenize.d.ts +80 -0
- package/dist/lib/fhirpath/lexer/tokenize.d.ts.map +1 -0
- package/dist/lib/fhirpath/parse.d.ts +101 -0
- package/dist/lib/fhirpath/parse.d.ts.map +1 -0
- package/dist/lib/fhirpath/tokenize.d.ts +20 -0
- package/dist/lib/fhirpath/tokenize.d.ts.map +1 -0
- package/dist/lib/fhirpath/types.d.ts +111 -0
- package/dist/lib/fhirpath/types.d.ts.map +1 -0
- package/dist/lib/fhirpath/utils.d.ts +81 -0
- package/dist/lib/fhirpath/utils.d.ts.map +1 -0
- package/dist/lib/index.d.ts +24 -0
- package/dist/lib/index.d.ts.map +1 -0
- package/dist/lib/model/canonical-profile.d.ts +381 -0
- package/dist/lib/model/canonical-profile.d.ts.map +1 -0
- package/dist/lib/model/element-definition.d.ts +503 -0
- package/dist/lib/model/element-definition.d.ts.map +1 -0
- package/dist/lib/model/index.d.ts +14 -0
- package/dist/lib/model/index.d.ts.map +1 -0
- package/dist/lib/model/primitives.d.ts +464 -0
- package/dist/lib/model/primitives.d.ts.map +1 -0
- package/dist/lib/model/structure-definition.d.ts +263 -0
- package/dist/lib/model/structure-definition.d.ts.map +1 -0
- package/dist/lib/parser/choice-type-parser.d.ts +182 -0
- package/dist/lib/parser/choice-type-parser.d.ts.map +1 -0
- package/dist/lib/parser/index.d.ts +16 -0
- package/dist/lib/parser/index.d.ts.map +1 -0
- package/dist/lib/parser/json-parser.d.ts +171 -0
- package/dist/lib/parser/json-parser.d.ts.map +1 -0
- package/dist/lib/parser/parse-error.d.ts +146 -0
- package/dist/lib/parser/parse-error.d.ts.map +1 -0
- package/dist/lib/parser/primitive-parser.d.ts +136 -0
- package/dist/lib/parser/primitive-parser.d.ts.map +1 -0
- package/dist/lib/parser/serializer.d.ts +64 -0
- package/dist/lib/parser/serializer.d.ts.map +1 -0
- package/dist/lib/parser/structure-definition-parser.d.ts +63 -0
- package/dist/lib/parser/structure-definition-parser.d.ts.map +1 -0
- package/dist/lib/profile/canonical-builder.d.ts +87 -0
- package/dist/lib/profile/canonical-builder.d.ts.map +1 -0
- package/dist/lib/profile/constraint-merger.d.ts +100 -0
- package/dist/lib/profile/constraint-merger.d.ts.map +1 -0
- package/dist/lib/profile/element-merger.d.ts +80 -0
- package/dist/lib/profile/element-merger.d.ts.map +1 -0
- package/dist/lib/profile/element-sorter.d.ts +81 -0
- package/dist/lib/profile/element-sorter.d.ts.map +1 -0
- package/dist/lib/profile/errors.d.ts +150 -0
- package/dist/lib/profile/errors.d.ts.map +1 -0
- package/dist/lib/profile/index.d.ts +27 -0
- package/dist/lib/profile/index.d.ts.map +1 -0
- package/dist/lib/profile/path-utils.d.ts +180 -0
- package/dist/lib/profile/path-utils.d.ts.map +1 -0
- package/dist/lib/profile/slicing-handler.d.ts +121 -0
- package/dist/lib/profile/slicing-handler.d.ts.map +1 -0
- package/dist/lib/profile/snapshot-generator.d.ts +73 -0
- package/dist/lib/profile/snapshot-generator.d.ts.map +1 -0
- package/dist/lib/profile/types.d.ts +220 -0
- package/dist/lib/profile/types.d.ts.map +1 -0
- package/dist/lib/validator/errors.d.ts +83 -0
- package/dist/lib/validator/errors.d.ts.map +1 -0
- package/dist/lib/validator/index.d.ts +23 -0
- package/dist/lib/validator/index.d.ts.map +1 -0
- package/dist/lib/validator/invariant-validator.d.ts +62 -0
- package/dist/lib/validator/invariant-validator.d.ts.map +1 -0
- package/dist/lib/validator/path-extractor.d.ts +123 -0
- package/dist/lib/validator/path-extractor.d.ts.map +1 -0
- package/dist/lib/validator/slicing-validator.d.ts +119 -0
- package/dist/lib/validator/slicing-validator.d.ts.map +1 -0
- package/dist/lib/validator/structure-validator.d.ts +74 -0
- package/dist/lib/validator/structure-validator.d.ts.map +1 -0
- package/dist/lib/validator/types.d.ts +288 -0
- package/dist/lib/validator/types.d.ts.map +1 -0
- package/dist/lib/validator/validation-rules.d.ts +198 -0
- package/dist/lib/validator/validation-rules.d.ts.map +1 -0
- package/dist/tsdoc-metadata.json +11 -0
- package/package.json +76 -0
|
@@ -0,0 +1,80 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* fhir-profile — Element Merger (Core Merge Loop)
|
|
3
|
+
*
|
|
4
|
+
* Implements the base-driven merge loop for snapshot generation,
|
|
5
|
+
* corresponding to HAPI FHIR R4's `ProfileUtilities.processPaths()`.
|
|
6
|
+
*
|
|
7
|
+
* This is the **core engine** of snapshot generation. It walks the base
|
|
8
|
+
* snapshot element-by-element, finds matching differential entries, and
|
|
9
|
+
* produces the merged snapshot output.
|
|
10
|
+
*
|
|
11
|
+
* Four major branches:
|
|
12
|
+
* - **Branch A**: No diff match → inherit base as-is (may recurse for inner diffs)
|
|
13
|
+
* - **Branch B**: Single diff match → merge constraints, recurse into children/datatype
|
|
14
|
+
* - **Branch C**: Type slicing → multiple diffs constrain different types
|
|
15
|
+
* - **Branch D**: Explicit slicing → multiple diffs with sliceNames
|
|
16
|
+
*
|
|
17
|
+
* @module fhir-profile
|
|
18
|
+
*/
|
|
19
|
+
import type { ElementDefinition } from '../model/index.js';
|
|
20
|
+
import type { FhirContext } from '../context/types.js';
|
|
21
|
+
import type { DiffElementTracker, SnapshotIssue } from './types.js';
|
|
22
|
+
/**
|
|
23
|
+
* Shared state passed through all recursive `processPaths` calls.
|
|
24
|
+
*/
|
|
25
|
+
export interface MergeContext {
|
|
26
|
+
/** FhirContext for loading datatype definitions (async). `undefined` for sync-only tests. */
|
|
27
|
+
readonly fhirContext?: FhirContext;
|
|
28
|
+
/** Preloaded datatype snapshots cache (url → snapshot elements). */
|
|
29
|
+
readonly datatypeCache: Map<string, readonly ElementDefinition[]>;
|
|
30
|
+
/** Issue collector. */
|
|
31
|
+
readonly issues: SnapshotIssue[];
|
|
32
|
+
/** URL of the profile being generated. */
|
|
33
|
+
readonly profileUrl: string;
|
|
34
|
+
/** Current recursion depth. */
|
|
35
|
+
depth: number;
|
|
36
|
+
/** Maximum allowed recursion depth. */
|
|
37
|
+
readonly maxDepth: number;
|
|
38
|
+
}
|
|
39
|
+
/**
|
|
40
|
+
* Create a default MergeContext.
|
|
41
|
+
*/
|
|
42
|
+
export declare function createMergeContext(profileUrl: string, options?: {
|
|
43
|
+
fhirContext?: FhirContext;
|
|
44
|
+
maxDepth?: number;
|
|
45
|
+
}): MergeContext;
|
|
46
|
+
/**
|
|
47
|
+
* Base-driven merge loop (corresponds to HAPI `processPaths`).
|
|
48
|
+
*
|
|
49
|
+
* Walks the base snapshot within `baseScope`, finds matching differential
|
|
50
|
+
* entries within `[diffStart, diffEnd]`, and appends merged elements to `result`.
|
|
51
|
+
*
|
|
52
|
+
* @param context - Shared merge state.
|
|
53
|
+
* @param result - Mutable output array to append merged elements to.
|
|
54
|
+
* @param baseElements - The base snapshot element list.
|
|
55
|
+
* @param baseCursor - Start index in baseElements (inclusive).
|
|
56
|
+
* @param baseLimit - End index in baseElements (inclusive).
|
|
57
|
+
* @param diffTrackers - The differential element trackers.
|
|
58
|
+
* @param diffStart - Start index in diffTrackers (inclusive).
|
|
59
|
+
* @param diffEnd - End index in diffTrackers (inclusive).
|
|
60
|
+
* @param contextPathSrc - Source path prefix for rewriting (e.g., datatype name).
|
|
61
|
+
* @param contextPathDst - Destination path prefix for rewriting.
|
|
62
|
+
*/
|
|
63
|
+
export declare function processPaths(context: MergeContext, result: ElementDefinition[], baseElements: readonly ElementDefinition[], baseCursor: number, baseLimit: number, diffTrackers: readonly DiffElementTracker[], diffStart: number, diffEnd: number, contextPathSrc: string, contextPathDst: string): void;
|
|
64
|
+
/**
|
|
65
|
+
* High-level convenience function: merge a base snapshot with a differential
|
|
66
|
+
* to produce a new snapshot element list.
|
|
67
|
+
*
|
|
68
|
+
* This is the primary entry point for testing and for the SnapshotGenerator
|
|
69
|
+
* orchestrator (Task 4.5).
|
|
70
|
+
*
|
|
71
|
+
* @param baseElements - The base profile's snapshot elements.
|
|
72
|
+
* @param diffElements - The differential elements to apply.
|
|
73
|
+
* @param context - Merge context (or auto-created if not provided).
|
|
74
|
+
* @returns The merged snapshot element list.
|
|
75
|
+
*/
|
|
76
|
+
export declare function mergeSnapshot(baseElements: readonly ElementDefinition[], diffElements: readonly ElementDefinition[], context?: MergeContext): {
|
|
77
|
+
elements: ElementDefinition[];
|
|
78
|
+
issues: SnapshotIssue[];
|
|
79
|
+
};
|
|
80
|
+
//# sourceMappingURL=element-merger.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"element-merger.d.ts","sourceRoot":"","sources":["../../../src/profile/element-merger.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;GAiBG;AAEH,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,mBAAmB,CAAC;AAC3D,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,qBAAqB,CAAC;AACvD,OAAO,KAAK,EAAE,kBAAkB,EAAE,aAAa,EAAkB,MAAM,YAAY,CAAC;AAiBpF;;GAEG;AACH,MAAM,WAAW,YAAY;IAC3B,6FAA6F;IAC7F,QAAQ,CAAC,WAAW,CAAC,EAAE,WAAW,CAAC;IACnC,oEAAoE;IACpE,QAAQ,CAAC,aAAa,EAAE,GAAG,CAAC,MAAM,EAAE,SAAS,iBAAiB,EAAE,CAAC,CAAC;IAClE,uBAAuB;IACvB,QAAQ,CAAC,MAAM,EAAE,aAAa,EAAE,CAAC;IACjC,0CAA0C;IAC1C,QAAQ,CAAC,UAAU,EAAE,MAAM,CAAC;IAC5B,+BAA+B;IAC/B,KAAK,EAAE,MAAM,CAAC;IACd,uCAAuC;IACvC,QAAQ,CAAC,QAAQ,EAAE,MAAM,CAAC;CAC3B;AAED;;GAEG;AACH,wBAAgB,kBAAkB,CAChC,UAAU,EAAE,MAAM,EAClB,OAAO,CAAC,EAAE;IACR,WAAW,CAAC,EAAE,WAAW,CAAC;IAC1B,QAAQ,CAAC,EAAE,MAAM,CAAC;CACnB,GACA,YAAY,CASd;AAuBD;;;;;;;;;;;;;;;;GAgBG;AACH,wBAAgB,YAAY,CAC1B,OAAO,EAAE,YAAY,EACrB,MAAM,EAAE,iBAAiB,EAAE,EAC3B,YAAY,EAAE,SAAS,iBAAiB,EAAE,EAC1C,UAAU,EAAE,MAAM,EAClB,SAAS,EAAE,MAAM,EACjB,YAAY,EAAE,SAAS,kBAAkB,EAAE,EAC3C,SAAS,EAAE,MAAM,EACjB,OAAO,EAAE,MAAM,EACf,cAAc,EAAE,MAAM,EACtB,cAAc,EAAE,MAAM,GACrB,IAAI,CAsLN;AAqgBD;;;;;;;;;;;GAWG;AACH,wBAAgB,aAAa,CAC3B,YAAY,EAAE,SAAS,iBAAiB,EAAE,EAC1C,YAAY,EAAE,SAAS,iBAAiB,EAAE,EAC1C,OAAO,CAAC,EAAE,YAAY,GACrB;IAAE,QAAQ,EAAE,iBAAiB,EAAE,CAAC;IAAC,MAAM,EAAE,aAAa,EAAE,CAAA;CAAE,CAiC5D"}
|
|
@@ -0,0 +1,81 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* fhir-profile — Element Sorter
|
|
3
|
+
*
|
|
4
|
+
* Sorting and ordering utilities for snapshot generation.
|
|
5
|
+
* Corresponds to HAPI FHIR R4's `sortDifferential()` + `sortElements()`.
|
|
6
|
+
*
|
|
7
|
+
* Key concepts:
|
|
8
|
+
* - The authoritative order is the **base snapshot element order**, not alphabetical
|
|
9
|
+
* - Differential elements may need pre-sorting before merge
|
|
10
|
+
* - Sorting builds a tree, sorts each level by base index, then flattens
|
|
11
|
+
*
|
|
12
|
+
* Exported functions:
|
|
13
|
+
* - {@link sortDifferential} — sort diff elements by base snapshot order
|
|
14
|
+
* - {@link findBaseIndex} — locate a path in the base snapshot
|
|
15
|
+
* - {@link validateElementOrder} — verify snapshot ordering post-generation
|
|
16
|
+
* - {@link ensureElementIds} — generate element IDs from path + sliceName
|
|
17
|
+
*
|
|
18
|
+
* @module fhir-profile
|
|
19
|
+
*/
|
|
20
|
+
import type { ElementDefinition } from '../model/index.js';
|
|
21
|
+
import type { SnapshotIssue } from './types.js';
|
|
22
|
+
/**
|
|
23
|
+
* Find the index of a path in the base snapshot.
|
|
24
|
+
*
|
|
25
|
+
* Handles:
|
|
26
|
+
* - Exact path match
|
|
27
|
+
* - Choice type match (e.g., `valueString` matches `value[x]`)
|
|
28
|
+
* - Slice paths (strips `:sliceName` from id to match by path)
|
|
29
|
+
*
|
|
30
|
+
* @param baseSnapshot - The base snapshot element list.
|
|
31
|
+
* @param path - The path to find.
|
|
32
|
+
* @param sliceName - Optional slice name for disambiguation.
|
|
33
|
+
* @returns The index in baseSnapshot, or -1 if not found.
|
|
34
|
+
*/
|
|
35
|
+
export declare function findBaseIndex(baseSnapshot: readonly ElementDefinition[], path: string, sliceName?: string): number;
|
|
36
|
+
/**
|
|
37
|
+
* Sort differential elements according to base snapshot order.
|
|
38
|
+
*
|
|
39
|
+
* Corresponds to HAPI's `sortDifferential()`. The algorithm:
|
|
40
|
+
* 1. Build a tree from the differential elements (parent-child by path)
|
|
41
|
+
* 2. Assign each node a base index via {@link findBaseIndex}
|
|
42
|
+
* 3. Sort children at each level by base index
|
|
43
|
+
* 4. Flatten the tree back to a linear list
|
|
44
|
+
*
|
|
45
|
+
* Elements not found in the base are placed at the end of their level
|
|
46
|
+
* and an issue is recorded.
|
|
47
|
+
*
|
|
48
|
+
* @param differential - The differential elements to sort (not mutated).
|
|
49
|
+
* @param baseSnapshot - The base snapshot providing the authoritative order.
|
|
50
|
+
* @param issues - Issue collector for recording problems.
|
|
51
|
+
* @returns A new array of elements in sorted order.
|
|
52
|
+
*/
|
|
53
|
+
export declare function sortDifferential(differential: readonly ElementDefinition[], baseSnapshot: readonly ElementDefinition[], issues: SnapshotIssue[]): ElementDefinition[];
|
|
54
|
+
/**
|
|
55
|
+
* Validate that snapshot elements are in correct order.
|
|
56
|
+
*
|
|
57
|
+
* Rules:
|
|
58
|
+
* - Parent elements must appear before their children
|
|
59
|
+
* - Slice elements must appear after their slicing root
|
|
60
|
+
* - No duplicate paths (unless sliced)
|
|
61
|
+
*
|
|
62
|
+
* @param snapshot - The snapshot elements to validate.
|
|
63
|
+
* @param issues - Issue collector for recording problems.
|
|
64
|
+
* @returns `true` if order is valid, `false` if any violations found.
|
|
65
|
+
*/
|
|
66
|
+
export declare function validateElementOrder(snapshot: readonly ElementDefinition[], issues: SnapshotIssue[]): boolean;
|
|
67
|
+
/**
|
|
68
|
+
* Ensure all elements have an `id` property.
|
|
69
|
+
*
|
|
70
|
+
* If an element lacks an `id`, generates one from its path and sliceName.
|
|
71
|
+
* This follows the FHIR convention:
|
|
72
|
+
* - Unsliced: `id = path` (e.g., `"Patient.name"`)
|
|
73
|
+
* - Sliced: `id = path:sliceName` (e.g., `"Patient.identifier:MRN"`)
|
|
74
|
+
*
|
|
75
|
+
* Corresponds to HAPI's `setIds()`.
|
|
76
|
+
*
|
|
77
|
+
* @param elements - The elements to process (mutated in place).
|
|
78
|
+
* @param resourceType - The resource type name (used for the root element).
|
|
79
|
+
*/
|
|
80
|
+
export declare function ensureElementIds(elements: ElementDefinition[], resourceType?: string): void;
|
|
81
|
+
//# sourceMappingURL=element-sorter.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"element-sorter.d.ts","sourceRoot":"","sources":["../../../src/profile/element-sorter.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;GAkBG;AAEH,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,mBAAmB,CAAC;AAC3D,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,YAAY,CAAC;AA6BhD;;;;;;;;;;;;GAYG;AACH,wBAAgB,aAAa,CAC3B,YAAY,EAAE,SAAS,iBAAiB,EAAE,EAC1C,IAAI,EAAE,MAAM,EACZ,SAAS,CAAC,EAAE,MAAM,GACjB,MAAM,CA2BR;AAMD;;;;;;;;;;;;;;;;GAgBG;AACH,wBAAgB,gBAAgB,CAC9B,YAAY,EAAE,SAAS,iBAAiB,EAAE,EAC1C,YAAY,EAAE,SAAS,iBAAiB,EAAE,EAC1C,MAAM,EAAE,aAAa,EAAE,GACtB,iBAAiB,EAAE,CA+ErB;AAoDD;;;;;;;;;;;GAWG;AACH,wBAAgB,oBAAoB,CAClC,QAAQ,EAAE,SAAS,iBAAiB,EAAE,EACtC,MAAM,EAAE,aAAa,EAAE,GACtB,OAAO,CAmDT;AAMD;;;;;;;;;;;;GAYG;AACH,wBAAgB,gBAAgB,CAC9B,QAAQ,EAAE,iBAAiB,EAAE,EAC7B,YAAY,CAAC,EAAE,MAAM,GACpB,IAAI,CAiBN"}
|
|
@@ -0,0 +1,150 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* fhir-profile — Error Types
|
|
3
|
+
*
|
|
4
|
+
* Structured error hierarchy for the FHIR profile module.
|
|
5
|
+
* All errors extend {@link ProfileError} so consumers can catch
|
|
6
|
+
* profile-related failures with a single `catch` clause.
|
|
7
|
+
*
|
|
8
|
+
* Error hierarchy:
|
|
9
|
+
* ```
|
|
10
|
+
* ProfileError (base)
|
|
11
|
+
* ├── SnapshotCircularDependencyError
|
|
12
|
+
* ├── BaseNotFoundError
|
|
13
|
+
* ├── ConstraintViolationError
|
|
14
|
+
* └── UnconsumedDifferentialError
|
|
15
|
+
* ```
|
|
16
|
+
*
|
|
17
|
+
* @module fhir-profile
|
|
18
|
+
*/
|
|
19
|
+
/**
|
|
20
|
+
* Base error class for all fhir-profile failures.
|
|
21
|
+
*
|
|
22
|
+
* Provides a stable `name` property and preserves the original `cause`
|
|
23
|
+
* when wrapping lower-level errors.
|
|
24
|
+
*
|
|
25
|
+
* @example
|
|
26
|
+
* ```typescript
|
|
27
|
+
* try {
|
|
28
|
+
* await generator.generate(sd);
|
|
29
|
+
* } catch (err) {
|
|
30
|
+
* if (err instanceof ProfileError) {
|
|
31
|
+
* // Handle any profile-related error
|
|
32
|
+
* }
|
|
33
|
+
* }
|
|
34
|
+
* ```
|
|
35
|
+
*/
|
|
36
|
+
export declare class ProfileError extends Error {
|
|
37
|
+
readonly name: string;
|
|
38
|
+
constructor(message: string, options?: ErrorOptions);
|
|
39
|
+
}
|
|
40
|
+
/**
|
|
41
|
+
* Thrown when snapshot generation detects a circular dependency in the
|
|
42
|
+
* profile chain.
|
|
43
|
+
*
|
|
44
|
+
* This occurs when profile A's base chain eventually references A again,
|
|
45
|
+
* which would cause infinite recursion during snapshot generation.
|
|
46
|
+
* HAPI detects this via a `snapshotStack` of URLs currently being generated.
|
|
47
|
+
*
|
|
48
|
+
* @example
|
|
49
|
+
* ```typescript
|
|
50
|
+
* throw new SnapshotCircularDependencyError(
|
|
51
|
+
* 'http://example.org/ProfileA',
|
|
52
|
+
* [
|
|
53
|
+
* 'http://example.org/ProfileA',
|
|
54
|
+
* 'http://example.org/ProfileB',
|
|
55
|
+
* 'http://example.org/ProfileA', // cycle back
|
|
56
|
+
* ]
|
|
57
|
+
* );
|
|
58
|
+
* ```
|
|
59
|
+
*/
|
|
60
|
+
export declare class SnapshotCircularDependencyError extends ProfileError {
|
|
61
|
+
readonly name = "SnapshotCircularDependencyError";
|
|
62
|
+
/** The canonical URL of the profile that triggered the cycle. */
|
|
63
|
+
readonly url: string;
|
|
64
|
+
/** The full chain of URLs forming the cycle. */
|
|
65
|
+
readonly chain: readonly string[];
|
|
66
|
+
constructor(url: string, chain: string[]);
|
|
67
|
+
}
|
|
68
|
+
/**
|
|
69
|
+
* Thrown when the base StructureDefinition required for snapshot generation
|
|
70
|
+
* cannot be loaded from any source.
|
|
71
|
+
*
|
|
72
|
+
* This is a fatal error — snapshot generation cannot proceed without the
|
|
73
|
+
* base profile's snapshot to merge against.
|
|
74
|
+
*
|
|
75
|
+
* @example
|
|
76
|
+
* ```typescript
|
|
77
|
+
* throw new BaseNotFoundError(
|
|
78
|
+
* 'http://hl7.org/fhir/StructureDefinition/Patient',
|
|
79
|
+
* 'http://hl7.org/fhir/StructureDefinition/UnknownBase'
|
|
80
|
+
* );
|
|
81
|
+
* ```
|
|
82
|
+
*/
|
|
83
|
+
export declare class BaseNotFoundError extends ProfileError {
|
|
84
|
+
readonly name = "BaseNotFoundError";
|
|
85
|
+
/** The canonical URL of the derived profile being generated. */
|
|
86
|
+
readonly derivedUrl: string;
|
|
87
|
+
/** The canonical URL of the base that could not be found. */
|
|
88
|
+
readonly baseUrl: string;
|
|
89
|
+
constructor(derivedUrl: string, baseUrl: string, cause?: Error);
|
|
90
|
+
}
|
|
91
|
+
/**
|
|
92
|
+
* Thrown when constraint merging detects an illegal tightening or
|
|
93
|
+
* incompatible constraint.
|
|
94
|
+
*
|
|
95
|
+
* This covers violations such as:
|
|
96
|
+
* - Cardinality loosening (`derived.min < base.min`)
|
|
97
|
+
* - Cardinality widening (`derived.max > base.max`)
|
|
98
|
+
* - Type expansion (derived types not a subset of base types)
|
|
99
|
+
* - Binding relaxation (relaxing a REQUIRED binding)
|
|
100
|
+
*
|
|
101
|
+
* Only thrown when {@link SnapshotGeneratorOptions.throwOnError} is `true`.
|
|
102
|
+
* Otherwise, violations are recorded as issues in the result.
|
|
103
|
+
*
|
|
104
|
+
* @example
|
|
105
|
+
* ```typescript
|
|
106
|
+
* throw new ConstraintViolationError(
|
|
107
|
+
* 'CARDINALITY_VIOLATION',
|
|
108
|
+
* 'Patient.identifier',
|
|
109
|
+
* 'Derived min (0) is less than base min (1)'
|
|
110
|
+
* );
|
|
111
|
+
* ```
|
|
112
|
+
*/
|
|
113
|
+
export declare class ConstraintViolationError extends ProfileError {
|
|
114
|
+
readonly name = "ConstraintViolationError";
|
|
115
|
+
/** The type of constraint violation. */
|
|
116
|
+
readonly violationType: string;
|
|
117
|
+
/** The element path where the violation occurred. */
|
|
118
|
+
readonly path: string;
|
|
119
|
+
constructor(violationType: string, path: string, message: string);
|
|
120
|
+
}
|
|
121
|
+
/**
|
|
122
|
+
* Thrown when differential elements remain unconsumed after snapshot
|
|
123
|
+
* generation completes.
|
|
124
|
+
*
|
|
125
|
+
* This indicates that the algorithm could not find a matching base
|
|
126
|
+
* element for one or more differential entries. Common causes:
|
|
127
|
+
* - Incorrect path in differential
|
|
128
|
+
* - Slicing mismatch
|
|
129
|
+
* - Unsupported constraint pattern
|
|
130
|
+
*
|
|
131
|
+
* HAPI detects this via the `GENERATED_IN_SNAPSHOT` marker pattern.
|
|
132
|
+
*
|
|
133
|
+
* Only thrown when {@link SnapshotGeneratorOptions.throwOnError} is `true`.
|
|
134
|
+
* Otherwise, each unconsumed element is recorded as an issue.
|
|
135
|
+
*
|
|
136
|
+
* @example
|
|
137
|
+
* ```typescript
|
|
138
|
+
* throw new UnconsumedDifferentialError([
|
|
139
|
+
* 'Patient.nonExistentField',
|
|
140
|
+
* 'Patient.identifier:BadSlice',
|
|
141
|
+
* ]);
|
|
142
|
+
* ```
|
|
143
|
+
*/
|
|
144
|
+
export declare class UnconsumedDifferentialError extends ProfileError {
|
|
145
|
+
readonly name = "UnconsumedDifferentialError";
|
|
146
|
+
/** Paths of the unconsumed differential elements. */
|
|
147
|
+
readonly unconsumedPaths: readonly string[];
|
|
148
|
+
constructor(unconsumedPaths: string[]);
|
|
149
|
+
}
|
|
150
|
+
//# sourceMappingURL=errors.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"errors.d.ts","sourceRoot":"","sources":["../../../src/profile/errors.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;GAiBG;AAMH;;;;;;;;;;;;;;;;GAgBG;AACH,qBAAa,YAAa,SAAQ,KAAK;IACrC,SAAkB,IAAI,EAAE,MAAM,CAAkB;gBAEpC,OAAO,EAAE,MAAM,EAAE,OAAO,CAAC,EAAE,YAAY;CAKpD;AAMD;;;;;;;;;;;;;;;;;;;GAmBG;AACH,qBAAa,+BAAgC,SAAQ,YAAY;IAC/D,SAAkB,IAAI,qCAAqC;IAE3D,iEAAiE;IACjE,QAAQ,CAAC,GAAG,EAAE,MAAM,CAAC;IAErB,gDAAgD;IAChD,QAAQ,CAAC,KAAK,EAAE,SAAS,MAAM,EAAE,CAAC;gBAEtB,GAAG,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,EAAE;CAMzC;AAMD;;;;;;;;;;;;;;GAcG;AACH,qBAAa,iBAAkB,SAAQ,YAAY;IACjD,SAAkB,IAAI,uBAAuB;IAE7C,gEAAgE;IAChE,QAAQ,CAAC,UAAU,EAAE,MAAM,CAAC;IAE5B,6DAA6D;IAC7D,QAAQ,CAAC,OAAO,EAAE,MAAM,CAAC;gBAEb,UAAU,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,EAAE,KAAK,CAAC,EAAE,KAAK;CAQ/D;AAMD;;;;;;;;;;;;;;;;;;;;;GAqBG;AACH,qBAAa,wBAAyB,SAAQ,YAAY;IACxD,SAAkB,IAAI,8BAA8B;IAEpD,wCAAwC;IACxC,QAAQ,CAAC,aAAa,EAAE,MAAM,CAAC;IAE/B,qDAAqD;IACrD,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;gBAEV,aAAa,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM;CAKjE;AAMD;;;;;;;;;;;;;;;;;;;;;;GAsBG;AACH,qBAAa,2BAA4B,SAAQ,YAAY;IAC3D,SAAkB,IAAI,iCAAiC;IAEvD,qDAAqD;IACrD,QAAQ,CAAC,eAAe,EAAE,SAAS,MAAM,EAAE,CAAC;gBAEhC,eAAe,EAAE,MAAM,EAAE;CAStC"}
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* fhir-profile — Barrel Exports
|
|
3
|
+
*
|
|
4
|
+
* Re-exports all public types, interfaces, error classes, and helper
|
|
5
|
+
* functions from the FHIR profile module.
|
|
6
|
+
*
|
|
7
|
+
* Public surface:
|
|
8
|
+
* - Types: SnapshotGeneratorOptions, SnapshotResult, SnapshotIssue, etc.
|
|
9
|
+
* - SnapshotGenerator: orchestrator class
|
|
10
|
+
* - CanonicalBuilder: SD → CanonicalProfile conversion
|
|
11
|
+
* - Errors: ProfileError hierarchy
|
|
12
|
+
* - Path Utilities: path matching for advanced consumers
|
|
13
|
+
*
|
|
14
|
+
* @module fhir-profile
|
|
15
|
+
*/
|
|
16
|
+
export type { SnapshotGeneratorOptions, SnapshotResult, SnapshotIssue, SnapshotIssueCode, DiffElementTracker, TraversalScope, } from './types.js';
|
|
17
|
+
export { createSnapshotIssue, createDiffTracker, } from './types.js';
|
|
18
|
+
export { SnapshotGenerator } from './snapshot-generator.js';
|
|
19
|
+
export { buildCanonicalProfile, buildCanonicalElement, buildTypeConstraints, buildBindingConstraint, buildInvariants, buildSlicingDefinition, } from './canonical-builder.js';
|
|
20
|
+
export { ProfileError, SnapshotCircularDependencyError, BaseNotFoundError, ConstraintViolationError, UnconsumedDifferentialError, } from './errors.js';
|
|
21
|
+
export { pathMatches, isDirectChild, isDescendant, pathDepth, parentPath, tailSegment, isChoiceTypePath, matchesChoiceType, extractChoiceTypeName, hasSliceName, extractSliceName, } from './path-utils.js';
|
|
22
|
+
export { findBaseIndex, sortDifferential, validateElementOrder, ensureElementIds, } from './element-sorter.js';
|
|
23
|
+
export { mergeConstraints, setBaseTraceability, mergeCardinality, mergeTypes, mergeBinding, mergeConstraintList, isLargerMax, } from './constraint-merger.js';
|
|
24
|
+
export type { MergeContext } from './element-merger.js';
|
|
25
|
+
export { createMergeContext, processPaths, mergeSnapshot, } from './element-merger.js';
|
|
26
|
+
export { makeExtensionSlicing, getSliceSiblings, validateSlicingCompatibility, diffsConstrainTypes, handleNewSlicing, handleExistingSlicing, } from './slicing-handler.js';
|
|
27
|
+
//# sourceMappingURL=index.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/profile/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;GAcG;AAGH,YAAY,EACV,wBAAwB,EACxB,cAAc,EACd,aAAa,EACb,iBAAiB,EACjB,kBAAkB,EAClB,cAAc,GACf,MAAM,YAAY,CAAC;AAGpB,OAAO,EACL,mBAAmB,EACnB,iBAAiB,GAClB,MAAM,YAAY,CAAC;AAGpB,OAAO,EAAE,iBAAiB,EAAE,MAAM,yBAAyB,CAAC;AAG5D,OAAO,EACL,qBAAqB,EACrB,qBAAqB,EACrB,oBAAoB,EACpB,sBAAsB,EACtB,eAAe,EACf,sBAAsB,GACvB,MAAM,wBAAwB,CAAC;AAGhC,OAAO,EACL,YAAY,EACZ,+BAA+B,EAC/B,iBAAiB,EACjB,wBAAwB,EACxB,2BAA2B,GAC5B,MAAM,aAAa,CAAC;AAGrB,OAAO,EACL,WAAW,EACX,aAAa,EACb,YAAY,EACZ,SAAS,EACT,UAAU,EACV,WAAW,EACX,gBAAgB,EAChB,iBAAiB,EACjB,qBAAqB,EACrB,YAAY,EACZ,gBAAgB,GACjB,MAAM,iBAAiB,CAAC;AAGzB,OAAO,EACL,aAAa,EACb,gBAAgB,EAChB,oBAAoB,EACpB,gBAAgB,GACjB,MAAM,qBAAqB,CAAC;AAG7B,OAAO,EACL,gBAAgB,EAChB,mBAAmB,EACnB,gBAAgB,EAChB,UAAU,EACV,YAAY,EACZ,mBAAmB,EACnB,WAAW,GACZ,MAAM,wBAAwB,CAAC;AAGhC,YAAY,EAAE,YAAY,EAAE,MAAM,qBAAqB,CAAC;AACxD,OAAO,EACL,kBAAkB,EAClB,YAAY,EACZ,aAAa,GACd,MAAM,qBAAqB,CAAC;AAG7B,OAAO,EACL,oBAAoB,EACpB,gBAAgB,EAChB,4BAA4B,EAC5B,mBAAmB,EACnB,gBAAgB,EAChB,qBAAqB,GACtB,MAAM,sBAAsB,CAAC"}
|
|
@@ -0,0 +1,180 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* fhir-profile — Path Utility Functions
|
|
3
|
+
*
|
|
4
|
+
* Path matching and manipulation utilities used by the snapshot generation
|
|
5
|
+
* algorithm. These functions underpin the base-driven traversal in
|
|
6
|
+
* {@link ElementMerger} (the `processPaths` equivalent).
|
|
7
|
+
*
|
|
8
|
+
* Key concepts:
|
|
9
|
+
* - **Element path**: dot-separated segments like `"Patient.name.given"`
|
|
10
|
+
* - **Choice type path**: ends with `[x]`, e.g. `"Observation.value[x]"`
|
|
11
|
+
* - **Concrete choice path**: resolved form, e.g. `"Observation.valueString"`
|
|
12
|
+
* - **Slice name**: stored in element id with `:` separator, e.g. `"Patient.identifier:MRN"`
|
|
13
|
+
*
|
|
14
|
+
* @module fhir-profile
|
|
15
|
+
*/
|
|
16
|
+
import type { ElementDefinition } from '../model/index.js';
|
|
17
|
+
import type { DiffElementTracker, TraversalScope } from './types.js';
|
|
18
|
+
/**
|
|
19
|
+
* Check whether two paths match exactly.
|
|
20
|
+
*
|
|
21
|
+
* @example
|
|
22
|
+
* pathMatches('Patient.name', 'Patient.name') // true
|
|
23
|
+
* pathMatches('Patient.name', 'Patient.identifier') // false
|
|
24
|
+
*/
|
|
25
|
+
export declare function pathMatches(basePath: string, diffPath: string): boolean;
|
|
26
|
+
/**
|
|
27
|
+
* Check whether `childPath` is a direct child of `parentPath`.
|
|
28
|
+
*
|
|
29
|
+
* A direct child has exactly one more segment than the parent.
|
|
30
|
+
*
|
|
31
|
+
* @example
|
|
32
|
+
* isDirectChild('Patient.name', 'Patient.name.given') // true
|
|
33
|
+
* isDirectChild('Patient.name', 'Patient.name.given.value') // false
|
|
34
|
+
* isDirectChild('Patient.name', 'Patient.identifier') // false
|
|
35
|
+
*/
|
|
36
|
+
export declare function isDirectChild(parentPath: string, childPath: string): boolean;
|
|
37
|
+
/**
|
|
38
|
+
* Check whether `descendantPath` is a descendant of `ancestorPath`
|
|
39
|
+
* (at any depth).
|
|
40
|
+
*
|
|
41
|
+
* @example
|
|
42
|
+
* isDescendant('Patient.name', 'Patient.name.given') // true
|
|
43
|
+
* isDescendant('Patient.name', 'Patient.name.given.value') // true
|
|
44
|
+
* isDescendant('Patient.name', 'Patient.name') // false
|
|
45
|
+
* isDescendant('Patient.name', 'Patient.identifier') // false
|
|
46
|
+
*/
|
|
47
|
+
export declare function isDescendant(ancestorPath: string, descendantPath: string): boolean;
|
|
48
|
+
/**
|
|
49
|
+
* Get the depth (number of segments) of a path.
|
|
50
|
+
*
|
|
51
|
+
* @example
|
|
52
|
+
* pathDepth('Patient') // 1
|
|
53
|
+
* pathDepth('Patient.name') // 2
|
|
54
|
+
* pathDepth('Patient.name.given') // 3
|
|
55
|
+
*/
|
|
56
|
+
export declare function pathDepth(path: string): number;
|
|
57
|
+
/**
|
|
58
|
+
* Get the parent path (everything before the last `.`).
|
|
59
|
+
*
|
|
60
|
+
* @example
|
|
61
|
+
* parentPath('Patient.name.given') // 'Patient.name'
|
|
62
|
+
* parentPath('Patient.name') // 'Patient'
|
|
63
|
+
* parentPath('Patient') // undefined
|
|
64
|
+
*/
|
|
65
|
+
export declare function parentPath(path: string): string | undefined;
|
|
66
|
+
/**
|
|
67
|
+
* Get the last segment (tail) of a path.
|
|
68
|
+
*
|
|
69
|
+
* @example
|
|
70
|
+
* tailSegment('Patient.name.given') // 'given'
|
|
71
|
+
* tailSegment('Patient') // 'Patient'
|
|
72
|
+
*/
|
|
73
|
+
export declare function tailSegment(path: string): string;
|
|
74
|
+
/**
|
|
75
|
+
* Check whether a path ends with `[x]` (choice type wildcard).
|
|
76
|
+
*
|
|
77
|
+
* @example
|
|
78
|
+
* isChoiceTypePath('Observation.value[x]') // true
|
|
79
|
+
* isChoiceTypePath('Observation.valueString') // false
|
|
80
|
+
* isChoiceTypePath('Observation.value') // false
|
|
81
|
+
*/
|
|
82
|
+
export declare function isChoiceTypePath(path: string): boolean;
|
|
83
|
+
/**
|
|
84
|
+
* Check whether `concretePath` matches a choice type `choicePath`.
|
|
85
|
+
*
|
|
86
|
+
* The concrete path must share the same prefix (minus `[x]`) and the
|
|
87
|
+
* remaining suffix must start with an uppercase letter (the type name).
|
|
88
|
+
*
|
|
89
|
+
* @example
|
|
90
|
+
* matchesChoiceType('Observation.value[x]', 'Observation.valueString') // true
|
|
91
|
+
* matchesChoiceType('Observation.value[x]', 'Observation.valueQuantity') // true
|
|
92
|
+
* matchesChoiceType('Observation.value[x]', 'Observation.code') // false
|
|
93
|
+
* matchesChoiceType('Observation.value[x]', 'Observation.value') // false
|
|
94
|
+
*/
|
|
95
|
+
export declare function matchesChoiceType(choicePath: string, concretePath: string): boolean;
|
|
96
|
+
/**
|
|
97
|
+
* Extract the type name from a concrete choice path given the choice base.
|
|
98
|
+
*
|
|
99
|
+
* @example
|
|
100
|
+
* extractChoiceTypeName('Observation.value[x]', 'Observation.valueString') // 'String'
|
|
101
|
+
* extractChoiceTypeName('Observation.value[x]', 'Observation.valueQuantity') // 'Quantity'
|
|
102
|
+
* extractChoiceTypeName('Observation.value[x]', 'Observation.code') // undefined
|
|
103
|
+
*/
|
|
104
|
+
export declare function extractChoiceTypeName(choicePath: string, concretePath: string): string | undefined;
|
|
105
|
+
/**
|
|
106
|
+
* Check whether an element id contains a slice name (`:` separator).
|
|
107
|
+
*
|
|
108
|
+
* In FHIR, slice names appear in element ids, not in paths.
|
|
109
|
+
* Format: `"ResourceType.path:sliceName"` or `"ResourceType.path:sliceName.child"`
|
|
110
|
+
*
|
|
111
|
+
* @example
|
|
112
|
+
* hasSliceName('Patient.identifier:MRN') // true
|
|
113
|
+
* hasSliceName('Patient.identifier:MRN.system') // true
|
|
114
|
+
* hasSliceName('Patient.identifier') // false
|
|
115
|
+
*/
|
|
116
|
+
export declare function hasSliceName(elementId: string): boolean;
|
|
117
|
+
/**
|
|
118
|
+
* Extract the first slice name from an element id.
|
|
119
|
+
*
|
|
120
|
+
* @example
|
|
121
|
+
* extractSliceName('Patient.identifier:MRN') // 'MRN'
|
|
122
|
+
* extractSliceName('Patient.identifier:MRN.system') // 'MRN'
|
|
123
|
+
* extractSliceName('Patient.identifier') // undefined
|
|
124
|
+
*/
|
|
125
|
+
export declare function extractSliceName(elementId: string): string | undefined;
|
|
126
|
+
/**
|
|
127
|
+
* Compute the child element scope for a parent element in a list.
|
|
128
|
+
*
|
|
129
|
+
* Returns a {@link TraversalScope} covering all direct and indirect
|
|
130
|
+
* children of the element at `parentIndex`. Both `start` and `end`
|
|
131
|
+
* are inclusive indices.
|
|
132
|
+
*
|
|
133
|
+
* Returns `undefined` if the parent has no children.
|
|
134
|
+
*
|
|
135
|
+
* @example
|
|
136
|
+
* // elements: [Patient, Patient.id, Patient.name, Patient.name.given,
|
|
137
|
+
* // Patient.name.family, Patient.identifier]
|
|
138
|
+
* getChildScope(elements, 2)
|
|
139
|
+
* // → { elements, start: 3, end: 4 } (Patient.name.given, Patient.name.family)
|
|
140
|
+
*/
|
|
141
|
+
export declare function getChildScope(elements: readonly ElementDefinition[], parentIndex: number): TraversalScope | undefined;
|
|
142
|
+
/**
|
|
143
|
+
* Find differential elements matching `basePath` within the given scope.
|
|
144
|
+
*
|
|
145
|
+
* Matching rules (mirrors HAPI `getDiffMatches`):
|
|
146
|
+
* 1. Exact path match
|
|
147
|
+
* 2. Choice type match (base ends with `[x]`, diff has concrete type)
|
|
148
|
+
* 3. Same path with different sliceName (slice match)
|
|
149
|
+
*
|
|
150
|
+
* Only considers unconsumed trackers within `[diffStart, diffEnd]` inclusive.
|
|
151
|
+
*/
|
|
152
|
+
export declare function getDiffMatches(differential: readonly DiffElementTracker[], basePath: string, diffStart: number, diffEnd: number): DiffElementTracker[];
|
|
153
|
+
/**
|
|
154
|
+
* Check whether the differential contains descendant elements of `basePath`
|
|
155
|
+
* within the given scope.
|
|
156
|
+
*
|
|
157
|
+
* This corresponds to HAPI's `hasInnerDiffMatches()` — it detects whether
|
|
158
|
+
* the diff constrains children of an element even when the element itself
|
|
159
|
+
* has no direct diff match.
|
|
160
|
+
*/
|
|
161
|
+
export declare function hasInnerDiffMatches(differential: readonly DiffElementTracker[], basePath: string, diffStart: number, diffEnd: number): boolean;
|
|
162
|
+
/**
|
|
163
|
+
* Rewrite a path from one prefix to another.
|
|
164
|
+
*
|
|
165
|
+
* Used during datatype expansion: when diving into a complex type's
|
|
166
|
+
* snapshot, paths need to be rewritten from the datatype's namespace
|
|
167
|
+
* to the target element's namespace.
|
|
168
|
+
*
|
|
169
|
+
* @example
|
|
170
|
+
* rewritePath('Identifier.system', 'Identifier', 'Patient.identifier')
|
|
171
|
+
* // → 'Patient.identifier.system'
|
|
172
|
+
*
|
|
173
|
+
* rewritePath('Identifier', 'Identifier', 'Patient.identifier')
|
|
174
|
+
* // → 'Patient.identifier'
|
|
175
|
+
*
|
|
176
|
+
* rewritePath('HumanName.given', 'HumanName', 'Patient.name')
|
|
177
|
+
* // → 'Patient.name.given'
|
|
178
|
+
*/
|
|
179
|
+
export declare function rewritePath(sourcePath: string, sourcePrefix: string, targetPrefix: string): string;
|
|
180
|
+
//# sourceMappingURL=path-utils.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"path-utils.d.ts","sourceRoot":"","sources":["../../../src/profile/path-utils.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;GAcG;AAEH,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,mBAAmB,CAAC;AAC3D,OAAO,KAAK,EAAE,kBAAkB,EAAE,cAAc,EAAE,MAAM,YAAY,CAAC;AAMrE;;;;;;GAMG;AACH,wBAAgB,WAAW,CAAC,QAAQ,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,GAAG,OAAO,CAEvE;AAED;;;;;;;;;GASG;AACH,wBAAgB,aAAa,CAAC,UAAU,EAAE,MAAM,EAAE,SAAS,EAAE,MAAM,GAAG,OAAO,CAM5E;AAED;;;;;;;;;GASG;AACH,wBAAgB,YAAY,CAAC,YAAY,EAAE,MAAM,EAAE,cAAc,EAAE,MAAM,GAAG,OAAO,CAElF;AAED;;;;;;;GAOG;AACH,wBAAgB,SAAS,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,CAO9C;AAED;;;;;;;GAOG;AACH,wBAAgB,UAAU,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,GAAG,SAAS,CAG3D;AAED;;;;;;GAMG;AACH,wBAAgB,WAAW,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,CAGhD;AAMD;;;;;;;GAOG;AACH,wBAAgB,gBAAgB,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO,CAEtD;AAED;;;;;;;;;;;GAWG;AACH,wBAAgB,iBAAiB,CAAC,UAAU,EAAE,MAAM,EAAE,YAAY,EAAE,MAAM,GAAG,OAAO,CAOnF;AAED;;;;;;;GAOG;AACH,wBAAgB,qBAAqB,CACnC,UAAU,EAAE,MAAM,EAClB,YAAY,EAAE,MAAM,GACnB,MAAM,GAAG,SAAS,CAIpB;AAMD;;;;;;;;;;GAUG;AACH,wBAAgB,YAAY,CAAC,SAAS,EAAE,MAAM,GAAG,OAAO,CAEvD;AAED;;;;;;;GAOG;AACH,wBAAgB,gBAAgB,CAAC,SAAS,EAAE,MAAM,GAAG,MAAM,GAAG,SAAS,CAOtE;AAMD;;;;;;;;;;;;;;GAcG;AACH,wBAAgB,aAAa,CAC3B,QAAQ,EAAE,SAAS,iBAAiB,EAAE,EACtC,WAAW,EAAE,MAAM,GAClB,cAAc,GAAG,SAAS,CAuB5B;AAED;;;;;;;;;GASG;AACH,wBAAgB,cAAc,CAC5B,YAAY,EAAE,SAAS,kBAAkB,EAAE,EAC3C,QAAQ,EAAE,MAAM,EAChB,SAAS,EAAE,MAAM,EACjB,OAAO,EAAE,MAAM,GACd,kBAAkB,EAAE,CAuBtB;AAED;;;;;;;GAOG;AACH,wBAAgB,mBAAmB,CACjC,YAAY,EAAE,SAAS,kBAAkB,EAAE,EAC3C,QAAQ,EAAE,MAAM,EAChB,SAAS,EAAE,MAAM,EACjB,OAAO,EAAE,MAAM,GACd,OAAO,CA8BT;AAMD;;;;;;;;;;;;;;;;GAgBG;AACH,wBAAgB,WAAW,CACzB,UAAU,EAAE,MAAM,EAClB,YAAY,EAAE,MAAM,EACpB,YAAY,EAAE,MAAM,GACnB,MAAM,CASR"}
|
|
@@ -0,0 +1,121 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* fhir-profile — Slicing Handler
|
|
3
|
+
*
|
|
4
|
+
* Dedicated module for FHIR slicing operations during snapshot generation.
|
|
5
|
+
* Corresponds to the slicing branches in HAPI FHIR R4's `processPaths()`.
|
|
6
|
+
*
|
|
7
|
+
* Slicing is the **second most complex** part of snapshot generation
|
|
8
|
+
* (after `processPaths` itself). This module extracts slicing logic into
|
|
9
|
+
* well-tested, independently callable functions.
|
|
10
|
+
*
|
|
11
|
+
* Two primary scenarios:
|
|
12
|
+
* - **Case A (handleNewSlicing)**: Base is unsliced, differential introduces slicing
|
|
13
|
+
* - **Case B (handleExistingSlicing)**: Base is already sliced, differential modifies/extends
|
|
14
|
+
*
|
|
15
|
+
* Supporting functions:
|
|
16
|
+
* - {@link getSliceSiblings} — collect base slice siblings
|
|
17
|
+
* - {@link validateSlicingCompatibility} — check diff slicing vs base slicing
|
|
18
|
+
* - {@link diffsConstrainTypes} — detect type slicing pattern
|
|
19
|
+
* - {@link makeExtensionSlicing} — synthesize default extension slicing
|
|
20
|
+
*
|
|
21
|
+
* @module fhir-profile
|
|
22
|
+
*/
|
|
23
|
+
import type { ElementDefinition, ElementDefinitionSlicing, ElementDefinitionType } from '../model/index.js';
|
|
24
|
+
import type { DiffElementTracker, SnapshotIssue, TraversalScope } from './types.js';
|
|
25
|
+
import type { MergeContext } from './element-merger.js';
|
|
26
|
+
/**
|
|
27
|
+
* Generate the default slicing definition for extension elements.
|
|
28
|
+
*
|
|
29
|
+
* Corresponds to HAPI's `makeExtensionSlicing()`. Extension elements
|
|
30
|
+
* are always sliced by `url` using the `value` discriminator type.
|
|
31
|
+
*
|
|
32
|
+
* @returns A new {@link ElementDefinitionSlicing} for extensions.
|
|
33
|
+
*/
|
|
34
|
+
export declare function makeExtensionSlicing(): ElementDefinitionSlicing;
|
|
35
|
+
/**
|
|
36
|
+
* Get all sibling slices from a base snapshot starting after the slicing root.
|
|
37
|
+
*
|
|
38
|
+
* Corresponds to HAPI's `getSiblings()`. Collects all elements with the
|
|
39
|
+
* same path as the slicing root that have a `sliceName`, plus their children.
|
|
40
|
+
*
|
|
41
|
+
* @param elements - The base snapshot element list.
|
|
42
|
+
* @param slicingRootIndex - Index of the slicing root element.
|
|
43
|
+
* @returns Array of slice elements (each with sliceName) and their children.
|
|
44
|
+
*/
|
|
45
|
+
export declare function getSliceSiblings(elements: readonly ElementDefinition[], slicingRootIndex: number): ElementDefinition[];
|
|
46
|
+
/**
|
|
47
|
+
* Validate that a differential slicing definition is compatible with
|
|
48
|
+
* the base slicing definition.
|
|
49
|
+
*
|
|
50
|
+
* Rules:
|
|
51
|
+
* - Discriminators must match (same type and path, in same order)
|
|
52
|
+
* - `ordered` cannot change from `true` to `false`
|
|
53
|
+
* - `rules` cannot relax from `closed` to `open`/`openAtEnd`
|
|
54
|
+
*
|
|
55
|
+
* @param baseSlicing - The base element's slicing definition.
|
|
56
|
+
* @param diffSlicing - The differential element's slicing definition.
|
|
57
|
+
* @param issues - Issue collector for recording incompatibilities.
|
|
58
|
+
* @param path - Element path for issue reporting.
|
|
59
|
+
* @returns `true` if compatible, `false` if incompatible.
|
|
60
|
+
*/
|
|
61
|
+
export declare function validateSlicingCompatibility(baseSlicing: ElementDefinitionSlicing, diffSlicing: ElementDefinitionSlicing, issues: SnapshotIssue[], path: string): boolean;
|
|
62
|
+
/**
|
|
63
|
+
* Detect whether diff matches constitute type slicing.
|
|
64
|
+
*
|
|
65
|
+
* Corresponds to HAPI's `diffsConstrainTypes()`. Type slicing is detected when:
|
|
66
|
+
* - Multiple diff matches exist
|
|
67
|
+
* - All diff matches constrain different types, OR
|
|
68
|
+
* - The base is a choice type `[x]` and diffs use concrete type paths
|
|
69
|
+
*
|
|
70
|
+
* @param diffMatches - The differential element trackers that matched a base path.
|
|
71
|
+
* @param basePath - The base element path.
|
|
72
|
+
* @param baseTypes - The base element's type list (optional).
|
|
73
|
+
* @returns `true` if the diffs represent type slicing.
|
|
74
|
+
*/
|
|
75
|
+
export declare function diffsConstrainTypes(diffMatches: readonly DiffElementTracker[], basePath: string, baseTypes: readonly ElementDefinitionType[] | undefined): boolean;
|
|
76
|
+
/**
|
|
77
|
+
* Handle Case A: Base is unsliced, differential introduces slicing.
|
|
78
|
+
*
|
|
79
|
+
* Steps:
|
|
80
|
+
* 1. Create slicing root element (from diff slicing definition or synthesized extension slicing)
|
|
81
|
+
* 2. Add slicing root to result
|
|
82
|
+
* 3. For each diff slice, recursively process against the same base range
|
|
83
|
+
*
|
|
84
|
+
* @param context - Shared merge state.
|
|
85
|
+
* @param result - Mutable output array.
|
|
86
|
+
* @param currentBase - The base element being sliced.
|
|
87
|
+
* @param baseScope - Scope of the base element and its children.
|
|
88
|
+
* @param diffMatches - Diff trackers that matched this base path.
|
|
89
|
+
* @param diffTrackers - All diff trackers (for recursive calls).
|
|
90
|
+
* @param diffStart - Start index in diffTrackers.
|
|
91
|
+
* @param diffEnd - End index in diffTrackers.
|
|
92
|
+
* @param contextPathSrc - Source path prefix for rewriting.
|
|
93
|
+
* @param contextPathDst - Destination path prefix for rewriting.
|
|
94
|
+
* @param cpath - The current (rewritten) path.
|
|
95
|
+
*/
|
|
96
|
+
export declare function handleNewSlicing(context: MergeContext, result: ElementDefinition[], currentBase: ElementDefinition, baseScope: TraversalScope, diffMatches: DiffElementTracker[], diffTrackers: readonly DiffElementTracker[], diffStart: number, diffEnd: number, contextPathSrc: string, contextPathDst: string, cpath: string): void;
|
|
97
|
+
/**
|
|
98
|
+
* Handle Case B: Base is already sliced, differential modifies/extends slices.
|
|
99
|
+
*
|
|
100
|
+
* Steps:
|
|
101
|
+
* 1. Copy base slicing root (merge diff slicing definition if present)
|
|
102
|
+
* 2. Collect base slice siblings
|
|
103
|
+
* 3. Align base slices with diff slices by sliceName
|
|
104
|
+
* 4. Matched slices → merge constraints
|
|
105
|
+
* 5. Unmatched base slices → copy as-is
|
|
106
|
+
* 6. Remaining diff slices → append as new (only if open/openAtEnd)
|
|
107
|
+
*
|
|
108
|
+
* @param context - Shared merge state.
|
|
109
|
+
* @param result - Mutable output array.
|
|
110
|
+
* @param currentBase - The base slicing root element.
|
|
111
|
+
* @param baseScope - Scope of the base element and its children.
|
|
112
|
+
* @param diffMatches - Diff trackers that matched this base path.
|
|
113
|
+
* @param diffTrackers - All diff trackers (for recursive calls).
|
|
114
|
+
* @param diffStart - Start index in diffTrackers.
|
|
115
|
+
* @param diffEnd - End index in diffTrackers.
|
|
116
|
+
* @param contextPathSrc - Source path prefix for rewriting.
|
|
117
|
+
* @param contextPathDst - Destination path prefix for rewriting.
|
|
118
|
+
* @param cpath - The current (rewritten) path.
|
|
119
|
+
*/
|
|
120
|
+
export declare function handleExistingSlicing(context: MergeContext, result: ElementDefinition[], currentBase: ElementDefinition, baseScope: TraversalScope, diffMatches: DiffElementTracker[], diffTrackers: readonly DiffElementTracker[], diffStart: number, diffEnd: number, contextPathSrc: string, contextPathDst: string, cpath: string): void;
|
|
121
|
+
//# sourceMappingURL=slicing-handler.d.ts.map
|