@haste-health/fhir-validation 0.14.3

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (59) hide show
  1. package/README.md +4 -0
  2. package/lib/elements/conformance.d.ts +9 -0
  3. package/lib/elements/conformance.js +40 -0
  4. package/lib/elements/conformance.js.map +1 -0
  5. package/lib/elements/primitive.d.ts +5 -0
  6. package/lib/elements/primitive.js +102 -0
  7. package/lib/elements/primitive.js.map +1 -0
  8. package/lib/elements/validators/cardinality.d.ts +3 -0
  9. package/lib/elements/validators/cardinality.js +57 -0
  10. package/lib/elements/validators/cardinality.js.map +1 -0
  11. package/lib/elements/validators/fixedValue.d.ts +4 -0
  12. package/lib/elements/validators/fixedValue.js +20 -0
  13. package/lib/elements/validators/fixedValue.js.map +1 -0
  14. package/lib/elements/validators/pattern.d.ts +11 -0
  15. package/lib/elements/validators/pattern.js +53 -0
  16. package/lib/elements/validators/pattern.js.map +1 -0
  17. package/lib/elements/validators/value.d.ts +10 -0
  18. package/lib/elements/validators/value.js +18 -0
  19. package/lib/elements/validators/value.js.map +1 -0
  20. package/lib/elements/validators.d.ts +8 -0
  21. package/lib/elements/validators.js +37 -0
  22. package/lib/elements/validators.js.map +1 -0
  23. package/lib/index.d.ts +4 -0
  24. package/lib/index.js +13 -0
  25. package/lib/index.js.map +1 -0
  26. package/lib/profile/element.d.ts +40 -0
  27. package/lib/profile/element.js +180 -0
  28. package/lib/profile/element.js.map +1 -0
  29. package/lib/profile/index.d.ts +20 -0
  30. package/lib/profile/index.js +45 -0
  31. package/lib/profile/index.js.map +1 -0
  32. package/lib/profile/slicing/index.d.ts +24 -0
  33. package/lib/profile/slicing/index.js +247 -0
  34. package/lib/profile/slicing/index.js.map +1 -0
  35. package/lib/profile/slicing.d.ts +47 -0
  36. package/lib/profile/slicing.js +195 -0
  37. package/lib/profile/slicing.js.map +1 -0
  38. package/lib/profile/utilities.d.ts +14 -0
  39. package/lib/profile/utilities.js +32 -0
  40. package/lib/profile/utilities.js.map +1 -0
  41. package/lib/profile/validators.d.ts +8 -0
  42. package/lib/profile/validators.js +37 -0
  43. package/lib/profile/validators.js.map +1 -0
  44. package/lib/slicing/index.d.ts +47 -0
  45. package/lib/slicing/index.js +197 -0
  46. package/lib/slicing/index.js.map +1 -0
  47. package/lib/structural/index.d.ts +4 -0
  48. package/lib/structural/index.js +296 -0
  49. package/lib/structural/index.js.map +1 -0
  50. package/lib/structural/validate-primitive.d.ts +11 -0
  51. package/lib/structural/validate-primitive.js +102 -0
  52. package/lib/structural/validate-primitive.js.map +1 -0
  53. package/lib/types.d.ts +10 -0
  54. package/lib/types.js +2 -0
  55. package/lib/types.js.map +1 -0
  56. package/lib/utilities.d.ts +34 -0
  57. package/lib/utilities.js +114 -0
  58. package/lib/utilities.js.map +1 -0
  59. package/package.json +50 -0
@@ -0,0 +1,296 @@
1
+ /* eslint-disable @typescript-eslint/no-explicit-any */
2
+ import { descend, get, pointer, toJSONPointer, } from "@haste-health/fhir-pointer";
3
+ import { getMeta, getStartingMeta, resolveMeta, } from "@haste-health/meta-value/meta";
4
+ import { isObject } from "@haste-health/meta-value/utilities";
5
+ import { OperationError, issueError, outcomeFatal, } from "@haste-health/operation-outcomes";
6
+ import { validatePrimitive } from "../elements/primitive.js";
7
+ import { validateCardinality } from "../elements/validators/cardinality.js";
8
+ import { validateFixedValue } from "../elements/validators/fixedValue.js";
9
+ import { validatePattern } from "../elements/validators/pattern.js";
10
+ import { isElementRequired, isResourceType } from "../utilities.js";
11
+ function isReferenceConformantToStructureDefinition(sd, value) {
12
+ switch (true) {
13
+ case sd?.type === "Resource" || sd?.type === "DomainResource": {
14
+ return true;
15
+ }
16
+ case value.reference !== undefined: {
17
+ const resourceType = value.reference.split("/")[0];
18
+ switch (true) {
19
+ // Could be ref in bundle so skip for now.
20
+ case !isResourceType(resourceType): {
21
+ return true;
22
+ }
23
+ case resourceType === sd?.type: {
24
+ // If Reference also has type need to validate that as well
25
+ if (value.type)
26
+ return resourceType === value.type;
27
+ return true;
28
+ }
29
+ default: {
30
+ return false;
31
+ }
32
+ }
33
+ }
34
+ case value.type && value === sd?.type: {
35
+ return true;
36
+ }
37
+ case value.type === undefined && value.reference === undefined: {
38
+ return true;
39
+ }
40
+ default: {
41
+ return false;
42
+ }
43
+ }
44
+ }
45
+ /**
46
+ * Validate the Reference is conformant to the profile (only confirms the type)
47
+ * @param ctx ValidationCTX
48
+ * @param element ElementDefinition to confirm Reference types
49
+ * @param root
50
+ * @param path
51
+ * @returns
52
+ */
53
+ async function validateReferenceTypeConstraint(ctx, element, root, path) {
54
+ // [Note] because element should already be validated as reference this can be considered safe?
55
+ const value = get(path, root);
56
+ if (!value)
57
+ return [];
58
+ const referenceProfiles = element.type?.find((t) => t.code === "Reference")?.targetProfile;
59
+ if (referenceProfiles === undefined || referenceProfiles?.length === 0)
60
+ return [];
61
+ for (const profileURI of referenceProfiles ?? []) {
62
+ const sd = await ctx.resolveCanonical(ctx.fhirVersion, "StructureDefinition", profileURI);
63
+ if (!sd) {
64
+ throw new OperationError(outcomeFatal("not-found", `Could not find profile: '${profileURI}' to validate reference`));
65
+ }
66
+ if (isReferenceConformantToStructureDefinition(sd, value)) {
67
+ return [];
68
+ }
69
+ }
70
+ return [
71
+ issueError("structure", `Expected reference to be constrained by one of the following profiles '${referenceProfiles?.join(", ")}' at path '${toJSONPointer(path)}' found reference of type '${value.type ? value.type : value.reference?.split("/")[0]}' instead.`, [toJSONPointer(path)]),
72
+ ];
73
+ }
74
+ function checkResourceType(type, root, path) {
75
+ const resource = root;
76
+ // Verify the resourceType aligns.
77
+ if (get(descend(path, "resourceType"), resource) !== type) {
78
+ return [
79
+ issueError("invalid", `ResourceType '${get(descend(path, "resourceType"), resource)}' does not match expected type '${type}'`, [toJSONPointer(path)]),
80
+ ];
81
+ }
82
+ return [];
83
+ }
84
+ function findFields(ctx, meta, value, field) {
85
+ switch (meta._type_) {
86
+ case "fp-primitive":
87
+ case "resource":
88
+ case "complex-type": {
89
+ if (!("definition" in meta))
90
+ throw new Error("Definition not found in meta");
91
+ if (field in value) {
92
+ return [{ field, meta }];
93
+ }
94
+ return [];
95
+ }
96
+ case "type": {
97
+ return findFields(ctx, {
98
+ ...getStartingMeta(ctx.fhirVersion, meta.type),
99
+ definition: meta.definition,
100
+ }, value, field);
101
+ }
102
+ case "primitive-type": {
103
+ const foundFields = [];
104
+ if (field in value) {
105
+ foundFields.push({ field, meta });
106
+ }
107
+ // Because Primitives have Element data under seperate key we must check multiple fields.
108
+ if (`_${field}` in value) {
109
+ const elementMeta = getStartingMeta(ctx.fhirVersion, "Element");
110
+ foundFields.push({
111
+ field: `_${field}`,
112
+ meta: {
113
+ ...elementMeta,
114
+ // Reet the min max cardinaltiy to the field definition.
115
+ definition: {
116
+ ...elementMeta.definition,
117
+ // Set both path and max,min,base to field definition to avoid issues with cardinality validation.
118
+ path: meta.definition.path,
119
+ max: meta.definition.max,
120
+ min: meta.definition.min,
121
+ base: meta.definition.base,
122
+ },
123
+ },
124
+ });
125
+ }
126
+ return foundFields;
127
+ }
128
+ case "typechoice": {
129
+ for (const fieldToType of Object.keys(meta.fieldsToType)) {
130
+ const foundFields = findFields(ctx, {
131
+ ...getStartingMeta(ctx.fhirVersion, meta.fieldsToType[fieldToType]),
132
+ definition: meta.definition,
133
+ }, value, fieldToType);
134
+ if (foundFields.length > 0)
135
+ return foundFields;
136
+ }
137
+ return [];
138
+ }
139
+ case "content-reference": {
140
+ const nextMeta = resolveMeta(ctx.fhirVersion, meta, value, field);
141
+ if (!nextMeta)
142
+ throw new OperationError(outcomeFatal("not-found", `Could not derive meta from content-reference '${meta.definition.path}'`));
143
+ return findFields(ctx, {
144
+ ...nextMeta.meta,
145
+ cardinality: meta.cardinality,
146
+ definition: {
147
+ ...nextMeta.meta.definition,
148
+ min: meta.definition.min,
149
+ max: meta.definition.max,
150
+ },
151
+ }, value, field);
152
+ }
153
+ default: {
154
+ // @ts-ignore
155
+ throw new Error(`Unknown meta type: ${meta._type_}`);
156
+ }
157
+ }
158
+ }
159
+ /**
160
+ * Validates singular complex item.
161
+ * @param ctx
162
+ * @param meta
163
+ * @param root
164
+ * @param path
165
+ */
166
+ async function validateComplex(ctx, meta, root, path) {
167
+ const value = get(path, root);
168
+ if (!isObject(value)) {
169
+ return [
170
+ issueError("structure", `Value must be an object when validating '${meta.type}'. Instead found type of '${typeof value}'`, [toJSONPointer(path)]),
171
+ ];
172
+ }
173
+ switch (meta._type_) {
174
+ case "resource":
175
+ case "complex-type": {
176
+ const foundFields = meta._type_ === "resource" ? new Set(["resourceType"]) : new Set([]);
177
+ const issues = (await Promise.all(Object.keys(meta.properties).map(async (property) => {
178
+ const childMeta = getMeta(ctx.fhirVersion, meta, property);
179
+ if (!childMeta) {
180
+ throw new OperationError(outcomeFatal("not-found", `Could not find meta for property '${property}' on type '${meta.type}'`));
181
+ }
182
+ // Because Primitives can be extended under seperate key we must check multiple fields.
183
+ const fields = findFields(ctx, childMeta, value, property);
184
+ fields.forEach((f) => foundFields.add(f.field));
185
+ if (isElementRequired(childMeta.definition) &&
186
+ fields.length === 0) {
187
+ return [
188
+ issueError("structure", `Missing required field at path '${toJSONPointer(descend(path, property))}'`, [toJSONPointer(path)]),
189
+ ];
190
+ }
191
+ return (await Promise.all(fields.map((child) => validateElement(ctx, child.meta, root, descend(path, child.field))))).flat();
192
+ }))).flat();
193
+ // Check for additional fields
194
+ const additionalFields = new Set(Object.keys(value)).difference(foundFields);
195
+ if (additionalFields.size > 0) {
196
+ issues.push(issueError("structure", `Additional fields found at path '${toJSONPointer(path)}': '${Array.from(additionalFields).join(", ")}'`, [toJSONPointer(path)]));
197
+ }
198
+ return issues;
199
+ }
200
+ default: {
201
+ throw new OperationError(outcomeFatal("invalid", "Invalid Meta type."));
202
+ }
203
+ }
204
+ }
205
+ /**
206
+ * Validate cardinality for the element.
207
+ * @param ctx Validation context.
208
+ * @param meta Meta of the element to be validated.
209
+ * @param root
210
+ * @param path
211
+ * @returns
212
+ */
213
+ async function validateElement(ctx, meta, root, path) {
214
+ const value = get(path, root);
215
+ const issues = validateCardinality(meta.definition, root, path);
216
+ if (issues.length > 0)
217
+ return issues;
218
+ switch (true) {
219
+ // If min is zero than allow undefined.
220
+ case value === undefined: {
221
+ return [];
222
+ }
223
+ case Array.isArray(value): {
224
+ return (await Promise.all((value || []).map((_v, i) => {
225
+ return validateElementSingular(ctx, meta, root, descend(path, i));
226
+ }))).flat();
227
+ }
228
+ // Means single item.
229
+ default: {
230
+ return validateElementSingular(ctx, meta, root, path);
231
+ }
232
+ }
233
+ }
234
+ /**
235
+ * Validates a singular item.
236
+ * @param ctx Validation ctx which includes the version.
237
+ * @param meta
238
+ * @param root
239
+ * @param path_
240
+ * @returns
241
+ */
242
+ async function validateElementSingular(ctx, meta, root, path) {
243
+ const patternIssues = await validatePattern(meta.definition, root, path);
244
+ if (patternIssues.length > 0) {
245
+ return patternIssues;
246
+ }
247
+ const fixedValueIssues = await validateFixedValue(meta.definition, root, path);
248
+ if (fixedValueIssues.length > 0) {
249
+ return fixedValueIssues;
250
+ }
251
+ switch (meta._type_) {
252
+ case "resource": {
253
+ let type = meta.type;
254
+ if (!isObject(root))
255
+ return [
256
+ issueError("structure", `Value must be an object when validating '${meta.type}'. Instead found type of '${typeof root}'`, [toJSONPointer(path)]),
257
+ ];
258
+ if (meta.type === "Resource" || meta.type === "DomainResource") {
259
+ type = get(descend(path, "resourceType"), root);
260
+ }
261
+ const typeIssues = checkResourceType(type, root, path);
262
+ if (typeIssues.length > 0)
263
+ return typeIssues;
264
+ const resourceMeta = getStartingMeta(ctx.fhirVersion, type);
265
+ if (!resourceMeta || resourceMeta._type_ !== "resource")
266
+ throw new OperationError(outcomeFatal("not-found", `Could not find meta for type '${type}'`));
267
+ return validateComplex(ctx, resourceMeta, root, path);
268
+ }
269
+ case "complex-type": {
270
+ if (!isObject(root))
271
+ return [
272
+ issueError("structure", `Value must be an object when validating '${meta.type}'. Instead found type of '${typeof root}'`, [toJSONPointer(path)]),
273
+ ];
274
+ if (meta.type === "Reference") {
275
+ const issuesReferenceConstraint = await validateReferenceTypeConstraint(ctx, meta.definition, root, path);
276
+ if (issuesReferenceConstraint.length > 0)
277
+ return issuesReferenceConstraint;
278
+ }
279
+ return validateComplex(ctx, meta, root, path);
280
+ }
281
+ case "fp-primitive":
282
+ case "primitive-type": {
283
+ return validatePrimitive(ctx, meta.definition, root, path, meta.type);
284
+ }
285
+ }
286
+ }
287
+ export default async function validate(ctx, type, root, path_) {
288
+ const path = path_ ?? pointer(ctx.fhirVersion, type, "id");
289
+ const meta = getStartingMeta(ctx.fhirVersion, type);
290
+ if (!meta)
291
+ throw new OperationError(outcomeFatal("not-found", `Could not find meta for type '${type}'`));
292
+ if (meta._type_ === "fp-primitive")
293
+ throw new Error();
294
+ return validateElementSingular(ctx, meta, root, path) ?? [];
295
+ }
296
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/structural/index.ts"],"names":[],"mappings":"AAAA,uDAAuD;AAQvD,OAAO,EAEL,OAAO,EACP,GAAG,EACH,OAAO,EACP,aAAa,GACd,MAAM,4BAA4B,CAAC;AAepC,OAAO,EAEL,OAAO,EACP,eAAe,EACf,WAAW,GACZ,MAAM,+BAA+B,CAAC;AACvC,OAAO,EAAE,QAAQ,EAAE,MAAM,oCAAoC,CAAC;AAC9D,OAAO,EACL,cAAc,EACd,UAAU,EACV,YAAY,GACb,MAAM,kCAAkC,CAAC;AAE1C,OAAO,EAAE,iBAAiB,EAAE,MAAM,0BAA0B,CAAC;AAC7D,OAAO,EAAE,mBAAmB,EAAE,MAAM,uCAAuC,CAAC;AAC5E,OAAO,EAAE,kBAAkB,EAAE,MAAM,sCAAsC,CAAC;AAC1E,OAAO,EAAE,eAAe,EAAE,MAAM,mCAAmC,CAAC;AAEpE,OAAO,EAAE,iBAAiB,EAAE,cAAc,EAAE,MAAM,iBAAiB,CAAC;AAEpE,SAAS,0CAA0C,CACjD,EAAiD,EACjD,KAAgB;IAEhB,QAAQ,IAAI,EAAE,CAAC;QACb,KAAK,EAAE,EAAE,IAAI,KAAK,UAAU,IAAI,EAAE,EAAE,IAAI,KAAK,gBAAgB,CAAC,CAAC,CAAC;YAC9D,OAAO,IAAI,CAAC;QACd,CAAC;QACD,KAAK,KAAK,CAAC,SAAS,KAAK,SAAS,CAAC,CAAC,CAAC;YACnC,MAAM,YAAY,GAAG,KAAK,CAAC,SAAS,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,CAAC;YAEnD,QAAQ,IAAI,EAAE,CAAC;gBACb,0CAA0C;gBAC1C,KAAK,CAAC,cAAc,CAAC,YAAY,CAAC,CAAC,CAAC,CAAC;oBACnC,OAAO,IAAI,CAAC;gBACd,CAAC;gBACD,KAAK,YAAY,KAAK,EAAE,EAAE,IAAI,CAAC,CAAC,CAAC;oBAC/B,2DAA2D;oBAC3D,IAAI,KAAK,CAAC,IAAI;wBAAE,OAAO,YAAY,KAAK,KAAK,CAAC,IAAI,CAAC;oBACnD,OAAO,IAAI,CAAC;gBACd,CAAC;gBACD,OAAO,CAAC,CAAC,CAAC;oBACR,OAAO,KAAK,CAAC;gBACf,CAAC;YACH,CAAC;QACH,CAAC;QACD,KAAK,KAAK,CAAC,IAAI,IAAI,KAAK,KAAK,EAAE,EAAE,IAAI,CAAC,CAAC,CAAC;YACtC,OAAO,IAAI,CAAC;QACd,CAAC;QACD,KAAK,KAAK,CAAC,IAAI,KAAK,SAAS,IAAI,KAAK,CAAC,SAAS,KAAK,SAAS,CAAC,CAAC,CAAC;YAC/D,OAAO,IAAI,CAAC;QACd,CAAC;QACD,OAAO,CAAC,CAAC,CAAC;YACR,OAAO,KAAK,CAAC;QACf,CAAC;IACH,CAAC;AACH,CAAC;AAED;;;;;;;GAOG;AACH,KAAK,UAAU,+BAA+B,CAC5C,GAAkB,EAClB,OAA0B,EAC1B,IAAY,EACZ,IAA2B;IAE3B,+FAA+F;IAC/F,MAAM,KAAK,GAAG,GAAG,CAAC,IAAI,EAAE,IAAI,CAA0B,CAAC;IACvD,IAAI,CAAC,KAAK;QAAE,OAAO,EAAE,CAAC;IAEtB,MAAM,iBAAiB,GAAG,OAAO,CAAC,IAAI,EAAE,IAAI,CAC1C,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,IAAI,KAAK,WAAW,CAC9B,EAAE,aAAa,CAAC;IACjB,IAAI,iBAAiB,KAAK,SAAS,IAAI,iBAAiB,EAAE,MAAM,KAAK,CAAC;QACpE,OAAO,EAAE,CAAC;IACZ,KAAK,MAAM,UAAU,IAAI,iBAAiB,IAAI,EAAE,EAAE,CAAC;QACjD,MAAM,EAAE,GAAG,MAAM,GAAG,CAAC,gBAAgB,CACnC,GAAG,CAAC,WAAW,EACf,qBAAqB,EACrB,UAAU,CACX,CAAC;QACF,IAAI,CAAC,EAAE,EAAE,CAAC;YACR,MAAM,IAAI,cAAc,CACtB,YAAY,CACV,WAAW,EACX,4BAA4B,UAAU,yBAAyB,CAChE,CACF,CAAC;QACJ,CAAC;QACD,IAAI,0CAA0C,CAAC,EAAE,EAAE,KAAK,CAAC,EAAE,CAAC;YAC1D,OAAO,EAAE,CAAC;QACZ,CAAC;IACH,CAAC;IAED,OAAO;QACL,UAAU,CACR,WAAW,EACX,0EAA0E,iBAAiB,EAAE,IAAI,CAC/F,IAAI,CACL,cAAc,aAAa,CAAC,IAAI,CAAC,8BAChC,KAAK,CAAC,IAAI,CAAC,CAAC,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC,CAAC,KAAK,CAAC,SAAS,EAAE,KAAK,CAAC,GAAG,CAAC,CAAC,CAAC,CACzD,YAAY,EACZ,CAAC,aAAa,CAAC,IAAI,CAAC,CAAC,CACtB;KACF,CAAC;AACJ,CAAC;AAED,SAAS,iBAAiB,CACxB,IAAS,EACT,IAA6B,EAC7B,IAAwB;IAExB,MAAM,QAAQ,GAAG,IAA2D,CAAC;IAC7E,kCAAkC;IAClC,IAAI,GAAG,CAAC,OAAO,CAAC,IAAI,EAAE,cAAc,CAAC,EAAE,QAAQ,CAAC,KAAK,IAAI,EAAE,CAAC;QAC1D,OAAO;YACL,UAAU,CACR,SAAS,EACT,iBAAiB,GAAG,CAClB,OAAO,CAAC,IAAI,EAAE,cAAc,CAAC,EAC7B,QAAQ,CACT,mCAAmC,IAAI,GAAG,EAC3C,CAAC,aAAa,CAAC,IAAI,CAAC,CAAC,CACtB;SACF,CAAC;IACJ,CAAC;IACD,OAAO,EAAE,CAAC;AACZ,CAAC;AAOD,SAAS,UAAU,CACjB,GAAkB,EAClB,IAKwB,EACxB,KAAa,EACb,KAAa;IAEb,QAAQ,IAAI,CAAC,MAAM,EAAE,CAAC;QACpB,KAAK,cAAc,CAAC;QACpB,KAAK,UAAU,CAAC;QAChB,KAAK,cAAc,CAAC,CAAC,CAAC;YACpB,IAAI,CAAC,CAAC,YAAY,IAAI,IAAI,CAAC;gBACzB,MAAM,IAAI,KAAK,CAAC,8BAA8B,CAAC,CAAC;YAElD,IAAI,KAAK,IAAI,KAAK,EAAE,CAAC;gBACnB,OAAO,CAAC,EAAE,KAAK,EAAE,IAAI,EAAE,CAAC,CAAC;YAC3B,CAAC;YAED,OAAO,EAAE,CAAC;QACZ,CAAC;QACD,KAAK,MAAM,CAAC,CAAC,CAAC;YACZ,OAAO,UAAU,CACf,GAAG,EACH;gBACE,GAAG,eAAe,CAAC,GAAG,CAAC,WAAW,EAAE,IAAI,CAAC,IAAI,CAAC;gBAC9C,UAAU,EAAE,IAAI,CAAC,UAAU;aACb,EAChB,KAAK,EACL,KAAK,CACN,CAAC;QACJ,CAAC;QACD,KAAK,gBAAgB,CAAC,CAAC,CAAC;YACtB,MAAM,WAAW,GAAgB,EAAE,CAAC;YACpC,IAAI,KAAK,IAAI,KAAK,EAAE,CAAC;gBACnB,WAAW,CAAC,IAAI,CAAC,EAAE,KAAK,EAAE,IAAI,EAAE,CAAC,CAAC;YACpC,CAAC;YACD,yFAAyF;YACzF,IAAI,IAAI,KAAK,EAAE,IAAI,KAAK,EAAE,CAAC;gBACzB,MAAM,WAAW,GAAG,eAAe,CACjC,GAAG,CAAC,WAAW,EACf,SAAgB,CACF,CAAC;gBACjB,WAAW,CAAC,IAAI,CAAC;oBACf,KAAK,EAAE,IAAI,KAAK,EAAE;oBAClB,IAAI,EAAE;wBACJ,GAAG,WAAW;wBACd,wDAAwD;wBACxD,UAAU,EAAE;4BACV,GAAG,WAAW,CAAC,UAAU;4BACzB,kGAAkG;4BAClG,IAAI,EAAE,IAAI,CAAC,UAAU,CAAC,IAAI;4BAC1B,GAAG,EAAE,IAAI,CAAC,UAAU,CAAC,GAAG;4BACxB,GAAG,EAAE,IAAI,CAAC,UAAU,CAAC,GAAG;4BACxB,IAAI,EAAE,IAAI,CAAC,UAAU,CAAC,IAAI;yBAC3B;qBACF;iBACF,CAAC,CAAC;YACL,CAAC;YAED,OAAO,WAAW,CAAC;QACrB,CAAC;QAED,KAAK,YAAY,CAAC,CAAC,CAAC;YAClB,KAAK,MAAM,WAAW,IAAI,MAAM,CAAC,IAAI,CAAC,IAAI,CAAC,YAAY,CAAC,EAAE,CAAC;gBACzD,MAAM,WAAW,GAAG,UAAU,CAC5B,GAAG,EACH;oBACE,GAAG,eAAe,CAAC,GAAG,CAAC,WAAW,EAAE,IAAI,CAAC,YAAY,CAAC,WAAW,CAAC,CAAC;oBACnE,UAAU,EAAE,IAAI,CAAC,UAAU;iBACb,EAChB,KAAK,EACL,WAAW,CACZ,CAAC;gBACF,IAAI,WAAW,CAAC,MAAM,GAAG,CAAC;oBAAE,OAAO,WAAW,CAAC;YACjD,CAAC;YACD,OAAO,EAAE,CAAC;QACZ,CAAC;QAED,KAAK,mBAAmB,CAAC,CAAC,CAAC;YACzB,MAAM,QAAQ,GAAG,WAAW,CAAC,GAAG,CAAC,WAAW,EAAE,IAAI,EAAE,KAAK,EAAE,KAAK,CAAC,CAAC;YAClE,IAAI,CAAC,QAAQ;gBACX,MAAM,IAAI,cAAc,CACtB,YAAY,CACV,WAAW,EACX,iDAAiD,IAAI,CAAC,UAAU,CAAC,IAAI,GAAG,CACzE,CACF,CAAC;YAEJ,OAAO,UAAU,CACf,GAAG,EACH;gBACE,GAAG,QAAQ,CAAC,IAAI;gBAChB,WAAW,EAAE,IAAI,CAAC,WAAW;gBAC7B,UAAU,EAAE;oBACV,GAAG,QAAQ,CAAC,IAAI,CAAC,UAAU;oBAC3B,GAAG,EAAE,IAAI,CAAC,UAAU,CAAC,GAAG;oBACxB,GAAG,EAAE,IAAI,CAAC,UAAU,CAAC,GAAG;iBACzB;aACF,EACD,KAAK,EACL,KAAK,CACN,CAAC;QACJ,CAAC;QAED,OAAO,CAAC,CAAC,CAAC;YACR,aAAa;YACb,MAAM,IAAI,KAAK,CAAC,sBAAsB,IAAI,CAAC,MAAM,EAAE,CAAC,CAAC;QACvD,CAAC;IACH,CAAC;AACH,CAAC;AAED;;;;;;GAMG;AACH,KAAK,UAAU,eAAe,CAC5B,GAAkB,EAClB,IAAiB,EACjB,IAAY,EACZ,IAAwB;IAExB,MAAM,KAAK,GAAG,GAAG,CAAC,IAAI,EAAE,IAAI,CAAC,CAAC;IAC9B,IAAI,CAAC,QAAQ,CAAC,KAAK,CAAC,EAAE,CAAC;QACrB,OAAO;YACL,UAAU,CACR,WAAW,EACX,4CACE,IAAI,CAAC,IACP,6BAA6B,OAAO,KAAK,GAAG,EAC5C,CAAC,aAAa,CAAC,IAAI,CAAC,CAAC,CACtB;SACF,CAAC;IACJ,CAAC;IACD,QAAQ,IAAI,CAAC,MAAM,EAAE,CAAC;QACpB,KAAK,UAAU,CAAC;QAChB,KAAK,cAAc,CAAC,CAAC,CAAC;YACpB,MAAM,WAAW,GACf,IAAI,CAAC,MAAM,KAAK,UAAU,CAAC,CAAC,CAAC,IAAI,GAAG,CAAC,CAAC,cAAc,CAAC,CAAC,CAAC,CAAC,CAAC,IAAI,GAAG,CAAC,EAAE,CAAC,CAAC;YAEvE,MAAM,MAAM,GAAG,CACb,MAAM,OAAO,CAAC,GAAG,CACf,MAAM,CAAC,IAAI,CAAC,IAAI,CAAC,UAAU,CAAC,CAAC,GAAG,CAAC,KAAK,EAAE,QAAQ,EAAE,EAAE;gBAClD,MAAM,SAAS,GAAG,OAAO,CAAC,GAAG,CAAC,WAAW,EAAE,IAAI,EAAE,QAAQ,CAAC,CAAC;gBAC3D,IAAI,CAAC,SAAS,EAAE,CAAC;oBACf,MAAM,IAAI,cAAc,CACtB,YAAY,CACV,WAAW,EACX,qCAAqC,QAAQ,cAAc,IAAI,CAAC,IAAI,GAAG,CACxE,CACF,CAAC;gBACJ,CAAC;gBAED,uFAAuF;gBACvF,MAAM,MAAM,GAAG,UAAU,CAAC,GAAG,EAAE,SAAS,EAAE,KAAK,EAAE,QAAQ,CAAC,CAAC;gBAC3D,MAAM,CAAC,OAAO,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,WAAW,CAAC,GAAG,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC;gBAEhD,IACE,iBAAiB,CAAC,SAAS,CAAC,UAAU,CAAC;oBACvC,MAAM,CAAC,MAAM,KAAK,CAAC,EACnB,CAAC;oBACD,OAAO;wBACL,UAAU,CACR,WAAW,EACX,mCAAmC,aAAa,CAC9C,OAAO,CAAC,IAAI,EAAE,QAAQ,CAAC,CACxB,GAAG,EACJ,CAAC,aAAa,CAAC,IAAI,CAAC,CAAC,CACtB;qBACF,CAAC;gBACJ,CAAC;gBAED,OAAO,CACL,MAAM,OAAO,CAAC,GAAG,CACf,MAAM,CAAC,GAAG,CAAC,CAAC,KAAK,EAAE,EAAE,CACnB,eAAe,CACb,GAAG,EACH,KAAK,CAAC,IAAI,EACV,IAAI,EACJ,OAAO,CAAC,IAAI,EAAE,KAAK,CAAC,KAAK,CAAC,CAC3B,CACF,CACF,CACF,CAAC,IAAI,EAAE,CAAC;YACX,CAAC,CAAC,CACH,CACF,CAAC,IAAI,EAAE,CAAC;YAET,8BAA8B;YAC9B,MAAM,gBAAgB,GAAG,IAAI,GAAG,CAAC,MAAM,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC,CAAC,UAAU,CAC7D,WAAW,CACZ,CAAC;YAEF,IAAI,gBAAgB,CAAC,IAAI,GAAG,CAAC,EAAE,CAAC;gBAC9B,MAAM,CAAC,IAAI,CACT,UAAU,CACR,WAAW,EACX,oCAAoC,aAAa,CAC/C,IAAI,CACL,OAAO,KAAK,CAAC,IAAI,CAAC,gBAAgB,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,GAAG,EAClD,CAAC,aAAa,CAAC,IAAI,CAAC,CAAC,CACtB,CACF,CAAC;YACJ,CAAC;YAED,OAAO,MAAM,CAAC;QAChB,CAAC;QACD,OAAO,CAAC,CAAC,CAAC;YACR,MAAM,IAAI,cAAc,CAAC,YAAY,CAAC,SAAS,EAAE,oBAAoB,CAAC,CAAC,CAAC;QAC1E,CAAC;IACH,CAAC;AACH,CAAC;AAED;;;;;;;GAOG;AACH,KAAK,UAAU,eAAe,CAC5B,GAAkB,EAClB,IAAyE,EACzE,IAAY,EACZ,IAAwB;IAExB,MAAM,KAAK,GAAG,GAAG,CAAC,IAAI,EAAE,IAAI,CAAC,CAAC;IAC9B,MAAM,MAAM,GAAG,mBAAmB,CAAC,IAAI,CAAC,UAAU,EAAE,IAAI,EAAE,IAAI,CAAC,CAAC;IAChE,IAAI,MAAM,CAAC,MAAM,GAAG,CAAC;QAAE,OAAO,MAAM,CAAC;IAErC,QAAQ,IAAI,EAAE,CAAC;QACb,uCAAuC;QACvC,KAAK,KAAK,KAAK,SAAS,CAAC,CAAC,CAAC;YACzB,OAAO,EAAE,CAAC;QACZ,CAAC;QACD,KAAK,KAAK,CAAC,OAAO,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC;YAC1B,OAAO,CACL,MAAM,OAAO,CAAC,GAAG,CACf,CAAC,KAAK,IAAI,EAAE,CAAC,CAAC,GAAG,CAAC,CAAC,EAAO,EAAE,CAAS,EAAE,EAAE;gBACvC,OAAO,uBAAuB,CAAC,GAAG,EAAE,IAAI,EAAE,IAAI,EAAE,OAAO,CAAC,IAAI,EAAE,CAAC,CAAC,CAAC,CAAC;YACpE,CAAC,CAAC,CACH,CACF,CAAC,IAAI,EAAE,CAAC;QACX,CAAC;QACD,qBAAqB;QACrB,OAAO,CAAC,CAAC,CAAC;YACR,OAAO,uBAAuB,CAAC,GAAG,EAAE,IAAI,EAAE,IAAI,EAAE,IAAI,CAAC,CAAC;QACxD,CAAC;IACH,CAAC;AACH,CAAC;AAED;;;;;;;GAOG;AACH,KAAK,UAAU,uBAAuB,CACpC,GAAkB,EAClB,IAAyE,EACzE,IAAa,EACb,IAAwB;IAExB,MAAM,aAAa,GAAG,MAAM,eAAe,CAAC,IAAI,CAAC,UAAU,EAAE,IAAI,EAAE,IAAI,CAAC,CAAC;IACzE,IAAI,aAAa,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;QAC7B,OAAO,aAAa,CAAC;IACvB,CAAC;IAED,MAAM,gBAAgB,GAAG,MAAM,kBAAkB,CAC/C,IAAI,CAAC,UAAU,EACf,IAAI,EACJ,IAAI,CACL,CAAC;IACF,IAAI,gBAAgB,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;QAChC,OAAO,gBAAgB,CAAC;IAC1B,CAAC;IAED,QAAQ,IAAI,CAAC,MAAM,EAAE,CAAC;QACpB,KAAK,UAAU,CAAC,CAAC,CAAC;YAChB,IAAI,IAAI,GAAG,IAAI,CAAC,IAAI,CAAC;YACrB,IAAI,CAAC,QAAQ,CAAC,IAAI,CAAC;gBACjB,OAAO;oBACL,UAAU,CACR,WAAW,EACX,4CACE,IAAI,CAAC,IACP,6BAA6B,OAAO,IAAI,GAAG,EAC3C,CAAC,aAAa,CAAC,IAAI,CAAC,CAAC,CACtB;iBACF,CAAC;YAEJ,IAAI,IAAI,CAAC,IAAI,KAAK,UAAU,IAAI,IAAI,CAAC,IAAI,KAAK,gBAAgB,EAAE,CAAC;gBAC/D,IAAI,GAAG,GAAG,CAAC,OAAO,CAAC,IAAI,EAAE,cAAc,CAAC,EAAE,IAAI,CAAC,CAAC;YAClD,CAAC;YAED,MAAM,UAAU,GAAG,iBAAiB,CAAC,IAAI,EAAE,IAAI,EAAE,IAAI,CAAC,CAAC;YACvD,IAAI,UAAU,CAAC,MAAM,GAAG,CAAC;gBAAE,OAAO,UAAU,CAAC;YAE7C,MAAM,YAAY,GAAG,eAAe,CAAC,GAAG,CAAC,WAAW,EAAE,IAAI,CAAC,CAAC;YAC5D,IAAI,CAAC,YAAY,IAAI,YAAY,CAAC,MAAM,KAAK,UAAU;gBACrD,MAAM,IAAI,cAAc,CACtB,YAAY,CAAC,WAAW,EAAE,iCAAiC,IAAI,GAAG,CAAC,CACpE,CAAC;YAEJ,OAAO,eAAe,CAAC,GAAG,EAAE,YAAY,EAAE,IAAI,EAAE,IAAI,CAAC,CAAC;QACxD,CAAC;QACD,KAAK,cAAc,CAAC,CAAC,CAAC;YACpB,IAAI,CAAC,QAAQ,CAAC,IAAI,CAAC;gBACjB,OAAO;oBACL,UAAU,CACR,WAAW,EACX,4CACE,IAAI,CAAC,IACP,6BAA6B,OAAO,IAAI,GAAG,EAC3C,CAAC,aAAa,CAAC,IAAI,CAAC,CAAC,CACtB;iBACF,CAAC;YAEJ,IAAI,IAAI,CAAC,IAAI,KAAK,WAAW,EAAE,CAAC;gBAC9B,MAAM,yBAAyB,GAAG,MAAM,+BAA+B,CACrE,GAAG,EACH,IAAI,CAAC,UAAU,EACf,IAAI,EACJ,IAAI,CACL,CAAC;gBACF,IAAI,yBAAyB,CAAC,MAAM,GAAG,CAAC;oBACtC,OAAO,yBAAyB,CAAC;YACrC,CAAC;YAED,OAAO,eAAe,CAAC,GAAG,EAAE,IAAI,EAAE,IAAI,EAAE,IAAI,CAAC,CAAC;QAChD,CAAC;QACD,KAAK,cAAc,CAAC;QACpB,KAAK,gBAAgB,CAAC,CAAC,CAAC;YACtB,OAAO,iBAAiB,CACtB,GAAG,EACH,IAAI,CAAC,UAAU,EACf,IAAI,EACJ,IAA0B,EAC1B,IAAI,CAAC,IAAI,CACV,CAAC;QACJ,CAAC;IACH,CAAC;AACH,CAAC;AAED,MAAM,CAAC,OAAO,CAAC,KAAK,UAAU,QAAQ,CACpC,GAAkB,EAClB,IAAS,EACT,IAAa,EACb,KAA0B;IAE1B,MAAM,IAAI,GACR,KAAK,IAAI,OAAO,CAAC,GAAG,CAAC,WAAW,EAAE,IAAoB,EAAE,IAAU,CAAC,CAAC;IAEtE,MAAM,IAAI,GAAG,eAAe,CAAC,GAAG,CAAC,WAAW,EAAE,IAAI,CAAC,CAAC;IACpD,IAAI,CAAC,IAAI;QACP,MAAM,IAAI,cAAc,CACtB,YAAY,CAAC,WAAW,EAAE,iCAAiC,IAAI,GAAG,CAAC,CACpE,CAAC;IAEJ,IAAI,IAAI,CAAC,MAAM,KAAK,cAAc;QAAE,MAAM,IAAI,KAAK,EAAE,CAAC;IAEtD,OAAO,uBAAuB,CAAC,GAAG,EAAE,IAAI,EAAE,IAAI,EAAE,IAAI,CAAC,IAAI,EAAE,CAAC;AAC9D,CAAC"}
@@ -0,0 +1,11 @@
1
+ import * as fpointer from "@oxidized-health/fhir-pointer";
2
+ import { ElementDefinition } from "@oxidized-health/fhir-types/r4/types";
3
+ import { FHIR_VERSION, Resource } from "@oxidized-health/fhir-types/versions";
4
+ import { ValidationCTX } from "../types.js";
5
+ export declare function validatePrimitive(
6
+ ctx: ValidationCTX,
7
+ element: ElementDefinition | undefined,
8
+ rootValue: unknown,
9
+ path: fpointer.Loc<object, any, any>,
10
+ type: string
11
+ ): Promise<Resource<FHIR_VERSION, "OperationOutcome">["issue"]>;
@@ -0,0 +1,102 @@
1
+ /* eslint-disable @typescript-eslint/no-explicit-any */
2
+ import * as fpointer from "@iguhealth/fhir-pointer";
3
+ import { OperationError, issueError, outcomeError, } from "@iguhealth/operation-outcomes";
4
+ import { isObject } from "@iguhealth/meta-value/utilities";
5
+ const REGEX = {
6
+ // base64Binary: /^(\s*([0-9a-zA-Z+=]){4}\s*)+$/,
7
+ uuid: /^[0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{12}$/,
8
+ time: /^([01][0-9]|2[0-3]):[0-5][0-9]:([0-5][0-9]|60)(\.[0-9]+)?$/,
9
+ oid: /^urn:oid:[0-2](\.(0|[1-9][0-9]*))+$/,
10
+ unsignedInt: /^([0]|([1-9][0-9]*))$/,
11
+ positiveInt: /^(\+?[1-9][0-9]*)$/,
12
+ instant: /^([0-9]([0-9]([0-9][1-9]|[1-9]0)|[1-9]00)|[1-9]000)-(0[1-9]|1[0-2])-(0[1-9]|[1-2][0-9]|3[0-1])T([01][0-9]|2[0-3]):[0-5][0-9]:([0-5][0-9]|60)(\.[0-9]+)?(Z|(\+|-)((0[0-9]|1[0-3]):[0-5][0-9]|14:00))$/,
13
+ id: /^[A-Za-z0-9\-.]{1,64}$/,
14
+ date: /^([0-9]([0-9]([0-9][1-9]|[1-9]0)|[1-9]00)|[1-9]000)(-(0[1-9]|1[0-2])(-(0[1-9]|[1-2][0-9]|3[0-1]))?)?$/,
15
+ dateTime: /^([0-9]([0-9]([0-9][1-9]|[1-9]0)|[1-9]00)|[1-9]000)(-(0[1-9]|1[0-2])(-(0[1-9]|[1-2][0-9]|3[0-1])(T([01][0-9]|2[0-3]):[0-5][0-9]:([0-5][0-9]|60)(\.[0-9]+)?(Z|(\+|-)((0[0-9]|1[0-3]):[0-5][0-9]|14:00)))?)?)?$/,
16
+ };
17
+ export async function validatePrimitive(ctx, element, rootValue, path, type) {
18
+ let value;
19
+ if (isObject(rootValue))
20
+ value = fpointer.get(path, rootValue);
21
+ else if (path === fpointer.root(path))
22
+ value = rootValue;
23
+ else {
24
+ return [
25
+ issueError("structure", `Expected primitive type '${type}' at path '${fpointer.toJSONPointer(path)}'`, [fpointer.toJSONPointer(path)]),
26
+ ];
27
+ }
28
+ switch (type) {
29
+ case "http://hl7.org/fhirpath/System.String":
30
+ case "date":
31
+ case "dateTime":
32
+ case "time":
33
+ case "instant":
34
+ case "id":
35
+ case "string":
36
+ case "xhtml":
37
+ case "markdown":
38
+ case "base64Binary":
39
+ case "uri":
40
+ case "uuid":
41
+ case "canonical":
42
+ case "oid":
43
+ case "url": {
44
+ if (typeof value !== "string") {
45
+ return [
46
+ issueError("structure", `Expected primitive type '${type}' at path '${fpointer.toJSONPointer(path)}'`, [fpointer.toJSONPointer(path)]),
47
+ ];
48
+ }
49
+ if (REGEX[type] && !REGEX[type].test(value)) {
50
+ return [
51
+ issueError("value", `Invalid value '${value}' at path '${fpointer.toJSONPointer(path)}'. Value must conform to regex '${REGEX[type]}'`, [fpointer.toJSONPointer(path)]),
52
+ ];
53
+ }
54
+ return [];
55
+ }
56
+ case "boolean": {
57
+ if (typeof value !== "boolean") {
58
+ return [
59
+ issueError("structure", `Expected primitive type '${type}' at path '${fpointer.toJSONPointer(path)}'`, [fpointer.toJSONPointer(path)]),
60
+ ];
61
+ }
62
+ return [];
63
+ }
64
+ case "code": {
65
+ const strength = element?.binding?.strength;
66
+ const valueSet = element?.binding?.valueSet;
67
+ if (typeof value !== "string") {
68
+ return [
69
+ issueError("structure", `Expected primitive type '${type}' at path '${fpointer.toJSONPointer(path)}'`, [fpointer.toJSONPointer(path)]),
70
+ ];
71
+ }
72
+ if (strength === "required" && valueSet && ctx.validateCode) {
73
+ const isValid = await ctx.validateCode(valueSet, value);
74
+ if (!isValid) {
75
+ return [
76
+ issueError("structure", `Code '${value}' is not in value set '${valueSet}' at path '${fpointer.toJSONPointer(path)}'`, [fpointer.toJSONPointer(path)]),
77
+ ];
78
+ }
79
+ }
80
+ return [];
81
+ }
82
+ case "integer":
83
+ case "positiveInt":
84
+ case "unsignedInt":
85
+ case "decimal": {
86
+ if (typeof value !== "number") {
87
+ return [
88
+ issueError("structure", `Expected primitive type '${type}' at path '${fpointer.toJSONPointer(path)}'`, [fpointer.toJSONPointer(path)]),
89
+ ];
90
+ }
91
+ if (REGEX[type] && !REGEX[type].test(value.toString())) {
92
+ return [
93
+ issueError("value", `Invalid value '${value}' at path '${fpointer.toJSONPointer(path)}'. Value must conform to regex '${REGEX[type]}'`, [fpointer.toJSONPointer(path)]),
94
+ ];
95
+ }
96
+ return [];
97
+ }
98
+ default:
99
+ throw new OperationError(outcomeError("structure", `Unknown primitive type '${type}' at path '${fpointer.toJSONPointer(path)}'`, [fpointer.toJSONPointer(path)]));
100
+ }
101
+ }
102
+ //# sourceMappingURL=validate-primitive.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"validate-primitive.js","sourceRoot":"","sources":["../../src/structural/validate-primitive.ts"],"names":[],"mappings":"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"}
package/lib/types.d.ts ADDED
@@ -0,0 +1,10 @@
1
+ import { Loc } from "@haste-health/fhir-pointer";
2
+ import { ElementDefinition, StructureDefinition, canonical } from "@haste-health/fhir-types/r4/types";
3
+ import * as r4b from "@haste-health/fhir-types/r4b/types";
4
+ import { FHIR_VERSION, Resource, ResourceType } from "@haste-health/fhir-types/versions";
5
+ export type ElementLoc = Loc<StructureDefinition | r4b.StructureDefinition, ElementDefinition | r4b.ElementDefinition | undefined, Loc<StructureDefinition | r4b.StructureDefinition, r4b.ElementDefinition[] | ElementDefinition[]>>;
6
+ export interface ValidationCTX {
7
+ fhirVersion: FHIR_VERSION;
8
+ resolveCanonical: <FHIRVersion extends FHIR_VERSION, Type extends ResourceType<FHIRVersion>>(fhirVersion: FHIRVersion, type: Type, url: canonical) => Promise<Resource<FHIRVersion, Type> | undefined>;
9
+ validateCode?(system: string, code: string): Promise<boolean>;
10
+ }
package/lib/types.js ADDED
@@ -0,0 +1,2 @@
1
+ export {};
2
+ //# sourceMappingURL=types.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"types.js","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":""}
@@ -0,0 +1,34 @@
1
+ import { Loc } from "@haste-health/fhir-pointer";
2
+ import { ElementDefinition, StructureDefinition, uri } from "@haste-health/fhir-types/r4/types";
3
+ import { FHIR_VERSION, Resource } from "@haste-health/fhir-types/versions";
4
+ import { ElementLoc, ValidationCTX } from "./types.js";
5
+ export declare function notNullable<T, Z extends T | undefined>(value: Z): value is NonNullable<Z>;
6
+ /**
7
+ * Per spec the ID can be used to determine if typechoice
8
+ * See https://hl7.org/fhir/R4/elementdefinition.html#id
9
+ * For type choice elements, the id reflects the type slice. e.g. For path = Patient.deceasedBoolean, the id is Patient.deceased[x]:deceasedBoolean
10
+ * @param element
11
+ * @returns
12
+ */
13
+ export declare function isTypeChoice(element: ElementDefinition): boolean | undefined;
14
+ export declare function isResourceType(type: string): boolean;
15
+ export declare function fieldName(elementDefinition: ElementDefinition, type?: string): string;
16
+ export declare function resolveTypeToStructureDefinition(ctx: ValidationCTX, type: uri): Promise<Resource<FHIR_VERSION, "StructureDefinition">>;
17
+ export declare function ascendElementLoc(loc: ElementLoc): {
18
+ parent: Loc<StructureDefinition, ElementDefinition[]>;
19
+ field: NonNullable<keyof ElementDefinition[]>;
20
+ };
21
+ export type PropertyAndType = {
22
+ field: string;
23
+ type: uri;
24
+ };
25
+ export declare function isElementRequired(element: ElementDefinition): boolean;
26
+ /**
27
+ * Returns fields associated to an element. Because it could be a primitive it may result in multiple fields.
28
+ * IE _field for Element values for field primitive value.
29
+ *
30
+ * @param element The ElementDefinition to find fields for
31
+ * @param value Value to check for fields.
32
+ * @returns
33
+ */
34
+ export declare function getFoundFieldsForElement(ctx: ValidationCTX, element: ElementDefinition, value: unknown): PropertyAndType[];
@@ -0,0 +1,114 @@
1
+ /* eslint-disable @typescript-eslint/no-explicit-any */
2
+ import { ascend } from "@haste-health/fhir-pointer";
3
+ import { resourceTypes } from "@haste-health/fhir-types/r4/sets";
4
+ import { resolveTypeToCanonical } from "@haste-health/meta-value";
5
+ import { isObject, isPrimitiveType } from "@haste-health/meta-value/utilities";
6
+ import { OperationError, outcomeFatal } from "@haste-health/operation-outcomes";
7
+ function capitalize(str) {
8
+ return str.charAt(0).toUpperCase() + str.slice(1);
9
+ }
10
+ export function notNullable(value) {
11
+ if (value === undefined || value === null)
12
+ return false;
13
+ return true;
14
+ }
15
+ /**
16
+ * Per spec the ID can be used to determine if typechoice
17
+ * See https://hl7.org/fhir/R4/elementdefinition.html#id
18
+ * For type choice elements, the id reflects the type slice. e.g. For path = Patient.deceasedBoolean, the id is Patient.deceased[x]:deceasedBoolean
19
+ * @param element
20
+ * @returns
21
+ */
22
+ export function isTypeChoice(element) {
23
+ return element.id?.endsWith("[x]");
24
+ }
25
+ export function isResourceType(type) {
26
+ return resourceTypes.has(type);
27
+ }
28
+ export function fieldName(elementDefinition, type) {
29
+ const field = elementDefinition.path.split(".").pop();
30
+ if (isTypeChoice(elementDefinition)) {
31
+ if (!type)
32
+ throw new Error("deriving field from typechoice requires a type");
33
+ return field.replace("[x]", capitalize(type));
34
+ }
35
+ return field;
36
+ }
37
+ export async function resolveTypeToStructureDefinition(ctx, type) {
38
+ const canonical = resolveTypeToCanonical(ctx.fhirVersion, type);
39
+ if (!canonical) {
40
+ throw new OperationError(outcomeFatal("structure", `Unable to resolve canonical for type '${type}'`, []));
41
+ }
42
+ const sd = await ctx.resolveCanonical(ctx.fhirVersion, "StructureDefinition", canonical);
43
+ if (!sd)
44
+ throw new OperationError(outcomeFatal("structure", `Unable to resolve canonical for type '${type}'`));
45
+ return sd;
46
+ }
47
+ export function ascendElementLoc(loc) {
48
+ const parent = ascend(loc);
49
+ if (!parent) {
50
+ throw new OperationError(outcomeFatal("invalid", `Invalid element path ${loc}`));
51
+ }
52
+ return parent;
53
+ }
54
+ function _findBaseFieldAndType(element, value) {
55
+ if (element.contentReference) {
56
+ const baseField = fieldName(element);
57
+ if (baseField in value) {
58
+ return {
59
+ field: fieldName(element),
60
+ type: (element.type?.[0].code ?? ""),
61
+ };
62
+ }
63
+ }
64
+ for (const type of element.type?.map((t) => t.code) ?? []) {
65
+ const field = fieldName(element, type);
66
+ if (field in value) {
67
+ return { field, type };
68
+ }
69
+ }
70
+ }
71
+ export function isElementRequired(element) {
72
+ return (element.min ?? 0) > 0;
73
+ }
74
+ /**
75
+ * Returns fields associated to an element. Because it could be a primitive it may result in multiple fields.
76
+ * IE _field for Element values for field primitive value.
77
+ *
78
+ * @param element The ElementDefinition to find fields for
79
+ * @param value Value to check for fields.
80
+ * @returns
81
+ */
82
+ export function getFoundFieldsForElement(ctx, element, value) {
83
+ if (!isObject(value))
84
+ return [];
85
+ const properties = [];
86
+ const base = _findBaseFieldAndType(element, value);
87
+ if (base) {
88
+ properties.push(base);
89
+ const { field, type } = base;
90
+ if (isPrimitiveType(ctx.fhirVersion, type)) {
91
+ const primitiveElementField = {
92
+ field: `_${field}`,
93
+ type: "Element",
94
+ };
95
+ if (`_${field}` in value)
96
+ properties.push(primitiveElementField);
97
+ }
98
+ }
99
+ else {
100
+ // Check for primitive extensions when non existent values
101
+ const primitives = element.type?.filter((type) => isPrimitiveType(ctx.fhirVersion, type.code)) ?? [];
102
+ for (const primType of primitives) {
103
+ if (`_${fieldName(element, primType.code)}` in value) {
104
+ const primitiveElementField = {
105
+ field: `_${fieldName(element, primType.code)}`,
106
+ type: "Element",
107
+ };
108
+ properties.push(primitiveElementField);
109
+ }
110
+ }
111
+ }
112
+ return properties;
113
+ }
114
+ //# sourceMappingURL=utilities.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"utilities.js","sourceRoot":"","sources":["../src/utilities.ts"],"names":[],"mappings":"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"}