@medplum/core 2.0.14 → 2.0.15
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/dist/cjs/index.cjs +1155 -1060
- package/dist/cjs/index.cjs.map +1 -1
- package/dist/cjs/index.min.cjs +1 -1
- package/dist/esm/base64.mjs +33 -0
- package/dist/esm/base64.mjs.map +1 -0
- package/dist/esm/cache.mjs +17 -23
- package/dist/esm/cache.mjs.map +1 -1
- package/dist/esm/client.mjs +464 -395
- package/dist/esm/client.mjs.map +1 -1
- package/dist/esm/eventtarget.mjs +6 -11
- package/dist/esm/eventtarget.mjs.map +1 -1
- package/dist/esm/fhirlexer/parse.mjs +15 -23
- package/dist/esm/fhirlexer/parse.mjs.map +1 -1
- package/dist/esm/fhirlexer/tokenize.mjs +190 -180
- package/dist/esm/fhirlexer/tokenize.mjs.map +1 -1
- package/dist/esm/fhirmapper/parse.mjs +264 -252
- package/dist/esm/fhirmapper/parse.mjs.map +1 -1
- package/dist/esm/fhirmapper/tokenize.mjs +0 -1
- package/dist/esm/fhirmapper/tokenize.mjs.map +1 -1
- package/dist/esm/fhirpath/atoms.mjs +0 -1
- package/dist/esm/fhirpath/atoms.mjs.map +1 -1
- package/dist/esm/fhirpath/parse.mjs +0 -1
- package/dist/esm/fhirpath/parse.mjs.map +1 -1
- package/dist/esm/fhirpath/tokenize.mjs +0 -1
- package/dist/esm/fhirpath/tokenize.mjs.map +1 -1
- package/dist/esm/filter/parse.mjs +0 -2
- package/dist/esm/filter/parse.mjs.map +1 -1
- package/dist/esm/filter/tokenize.mjs +0 -1
- package/dist/esm/filter/tokenize.mjs.map +1 -1
- package/dist/esm/index.min.mjs +1 -1
- package/dist/esm/jwt.mjs +2 -9
- package/dist/esm/jwt.mjs.map +1 -1
- package/dist/esm/readablepromise.mjs +18 -23
- package/dist/esm/readablepromise.mjs.map +1 -1
- package/dist/esm/schema.mjs +146 -123
- package/dist/esm/schema.mjs.map +1 -1
- package/dist/esm/search/match.mjs +0 -2
- package/dist/esm/search/match.mjs.map +1 -1
- package/dist/esm/storage.mjs +13 -19
- package/dist/esm/storage.mjs.map +1 -1
- package/dist/types/base64.d.ts +14 -0
- package/dist/types/cache.d.ts +3 -1
- package/dist/types/client.d.ts +127 -1
- package/dist/types/eventtarget.d.ts +1 -1
- package/dist/types/fhirlexer/parse.d.ts +5 -2
- package/dist/types/fhirlexer/tokenize.d.ts +28 -1
- package/dist/types/readablepromise.d.ts +4 -1
- package/dist/types/schema.d.ts +33 -1
- package/dist/types/storage.d.ts +2 -2
- package/package.json +1 -1
- package/dist/esm/node_modules/tslib/tslib.es6.mjs +0 -30
- package/dist/esm/node_modules/tslib/tslib.es6.mjs.map +0 -1
package/dist/esm/jwt.mjs
CHANGED
|
@@ -1,3 +1,5 @@
|
|
|
1
|
+
import { decodeBase64 } from './base64.mjs';
|
|
2
|
+
|
|
1
3
|
/**
|
|
2
4
|
* Decodes a section of a JWT.
|
|
3
5
|
* See: https://tools.ietf.org/html/rfc7519
|
|
@@ -13,15 +15,6 @@ function decodePayload(payload) {
|
|
|
13
15
|
const jsonPayload = decodeURIComponent(uriEncodedPayload);
|
|
14
16
|
return JSON.parse(jsonPayload);
|
|
15
17
|
}
|
|
16
|
-
function decodeBase64(data) {
|
|
17
|
-
if (typeof window !== 'undefined') {
|
|
18
|
-
return window.atob(data);
|
|
19
|
-
}
|
|
20
|
-
if (typeof Buffer !== 'undefined') {
|
|
21
|
-
return Buffer.from(data, 'base64').toString('binary');
|
|
22
|
-
}
|
|
23
|
-
throw new Error('Unable to decode base64');
|
|
24
|
-
}
|
|
25
18
|
/**
|
|
26
19
|
* Parses the JWT payload.
|
|
27
20
|
* @param token JWT token
|
package/dist/esm/jwt.mjs.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"jwt.mjs","sources":["../../src/jwt.ts"],"sourcesContent":["/**\n * Decodes a section of a JWT.\n * See: https://tools.ietf.org/html/rfc7519\n * @param payload\n */\nfunction decodePayload(payload: string): Record<string, number | string> {\n const cleanedPayload = payload.replace(/-/g, '+').replace(/_/g, '/');\n const decodedPayload = decodeBase64(cleanedPayload);\n const uriEncodedPayload = Array.from(decodedPayload).reduce((acc, char) => {\n const uriEncodedChar = ('00' + char.charCodeAt(0).toString(16)).slice(-2);\n return `${acc}%${uriEncodedChar}`;\n }, '');\n const jsonPayload = decodeURIComponent(uriEncodedPayload);\n return JSON.parse(jsonPayload);\n}\n\
|
|
1
|
+
{"version":3,"file":"jwt.mjs","sources":["../../src/jwt.ts"],"sourcesContent":["import { decodeBase64 } from './base64';\n\n/**\n * Decodes a section of a JWT.\n * See: https://tools.ietf.org/html/rfc7519\n * @param payload\n */\nfunction decodePayload(payload: string): Record<string, number | string> {\n const cleanedPayload = payload.replace(/-/g, '+').replace(/_/g, '/');\n const decodedPayload = decodeBase64(cleanedPayload);\n const uriEncodedPayload = Array.from(decodedPayload).reduce((acc, char) => {\n const uriEncodedChar = ('00' + char.charCodeAt(0).toString(16)).slice(-2);\n return `${acc}%${uriEncodedChar}`;\n }, '');\n const jsonPayload = decodeURIComponent(uriEncodedPayload);\n return JSON.parse(jsonPayload);\n}\n\n/**\n * Parses the JWT payload.\n * @param token JWT token\n */\nexport function parseJWTPayload(token: string): Record<string, number | string> {\n const [_header, payload, _signature] = token.split('.');\n return decodePayload(payload);\n}\n"],"names":[],"mappings":";;AAEA;;;;AAIG;AACH,SAAS,aAAa,CAAC,OAAe,EAAA;AACpC,IAAA,MAAM,cAAc,GAAG,OAAO,CAAC,OAAO,CAAC,IAAI,EAAE,GAAG,CAAC,CAAC,OAAO,CAAC,IAAI,EAAE,GAAG,CAAC,CAAC;AACrE,IAAA,MAAM,cAAc,GAAG,YAAY,CAAC,cAAc,CAAC,CAAC;AACpD,IAAA,MAAM,iBAAiB,GAAG,KAAK,CAAC,IAAI,CAAC,cAAc,CAAC,CAAC,MAAM,CAAC,CAAC,GAAG,EAAE,IAAI,KAAI;QACxE,MAAM,cAAc,GAAG,CAAC,IAAI,GAAG,IAAI,CAAC,UAAU,CAAC,CAAC,CAAC,CAAC,QAAQ,CAAC,EAAE,CAAC,EAAE,KAAK,CAAC,CAAC,CAAC,CAAC,CAAC;AAC1E,QAAA,OAAO,CAAG,EAAA,GAAG,CAAI,CAAA,EAAA,cAAc,EAAE,CAAC;KACnC,EAAE,EAAE,CAAC,CAAC;AACP,IAAA,MAAM,WAAW,GAAG,kBAAkB,CAAC,iBAAiB,CAAC,CAAC;AAC1D,IAAA,OAAO,IAAI,CAAC,KAAK,CAAC,WAAW,CAAC,CAAC;AACjC,CAAC;AAED;;;AAGG;AACG,SAAU,eAAe,CAAC,KAAa,EAAA;AAC3C,IAAA,MAAM,CAAC,OAAO,EAAE,OAAO,EAAE,UAAU,CAAC,GAAG,KAAK,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC;AACxD,IAAA,OAAO,aAAa,CAAC,OAAO,CAAC,CAAC;AAChC;;;;"}
|
|
@@ -1,6 +1,4 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
var _ReadablePromise_suspender, _ReadablePromise_status, _ReadablePromise_response, _ReadablePromise_error, _a;
|
|
1
|
+
var _a;
|
|
4
2
|
/**
|
|
5
3
|
* The ReadablePromise class wraps a request promise suitable for React Suspense.
|
|
6
4
|
* See: https://blog.logrocket.com/react-suspense-data-fetching/#wrappromise-js
|
|
@@ -9,33 +7,30 @@ var _ReadablePromise_suspender, _ReadablePromise_status, _ReadablePromise_respon
|
|
|
9
7
|
class ReadablePromise {
|
|
10
8
|
constructor(requestPromise) {
|
|
11
9
|
this[_a] = 'ReadablePromise';
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
__classPrivateFieldSet(this, _ReadablePromise_suspender, requestPromise.then((res) => {
|
|
17
|
-
__classPrivateFieldSet(this, _ReadablePromise_status, 'success', "f");
|
|
18
|
-
__classPrivateFieldSet(this, _ReadablePromise_response, res, "f");
|
|
10
|
+
this.status = 'pending';
|
|
11
|
+
this.suspender = requestPromise.then((res) => {
|
|
12
|
+
this.status = 'success';
|
|
13
|
+
this.response = res;
|
|
19
14
|
return res;
|
|
20
15
|
}, (err) => {
|
|
21
|
-
|
|
22
|
-
|
|
16
|
+
this.status = 'error';
|
|
17
|
+
this.error = err;
|
|
23
18
|
throw err;
|
|
24
|
-
})
|
|
19
|
+
});
|
|
25
20
|
}
|
|
26
21
|
/**
|
|
27
22
|
* Returns true if the promise is pending.
|
|
28
23
|
* @returns True if the Promise is pending.
|
|
29
24
|
*/
|
|
30
25
|
isPending() {
|
|
31
|
-
return
|
|
26
|
+
return this.status === 'pending';
|
|
32
27
|
}
|
|
33
28
|
/**
|
|
34
29
|
* Returns true if the promise resolved successfully.
|
|
35
30
|
* @returns True if the Promise resolved successfully.
|
|
36
31
|
*/
|
|
37
32
|
isOk() {
|
|
38
|
-
return
|
|
33
|
+
return this.status === 'success';
|
|
39
34
|
}
|
|
40
35
|
/**
|
|
41
36
|
* Attempts to read the value of the promise.
|
|
@@ -45,13 +40,13 @@ class ReadablePromise {
|
|
|
45
40
|
* @returns The resolved value of the Promise.
|
|
46
41
|
*/
|
|
47
42
|
read() {
|
|
48
|
-
switch (
|
|
43
|
+
switch (this.status) {
|
|
49
44
|
case 'pending':
|
|
50
|
-
throw
|
|
45
|
+
throw this.suspender;
|
|
51
46
|
case 'error':
|
|
52
|
-
throw
|
|
47
|
+
throw this.error;
|
|
53
48
|
default:
|
|
54
|
-
return
|
|
49
|
+
return this.response;
|
|
55
50
|
}
|
|
56
51
|
}
|
|
57
52
|
/**
|
|
@@ -61,7 +56,7 @@ class ReadablePromise {
|
|
|
61
56
|
* @returns A Promise for the completion of which ever callback is executed.
|
|
62
57
|
*/
|
|
63
58
|
then(onfulfilled, onrejected) {
|
|
64
|
-
return
|
|
59
|
+
return this.suspender.then(onfulfilled, onrejected);
|
|
65
60
|
}
|
|
66
61
|
/**
|
|
67
62
|
* Attaches a callback for only the rejection of the Promise.
|
|
@@ -69,7 +64,7 @@ class ReadablePromise {
|
|
|
69
64
|
* @returns A Promise for the completion of the callback.
|
|
70
65
|
*/
|
|
71
66
|
catch(onrejected) {
|
|
72
|
-
return
|
|
67
|
+
return this.suspender.catch(onrejected);
|
|
73
68
|
}
|
|
74
69
|
/**
|
|
75
70
|
* Attaches a callback that is invoked when the Promise is settled (fulfilled or rejected). The
|
|
@@ -78,10 +73,10 @@ class ReadablePromise {
|
|
|
78
73
|
* @returns A Promise for the completion of the callback.
|
|
79
74
|
*/
|
|
80
75
|
finally(onfinally) {
|
|
81
|
-
return
|
|
76
|
+
return this.suspender.finally(onfinally);
|
|
82
77
|
}
|
|
83
78
|
}
|
|
84
|
-
|
|
79
|
+
_a = Symbol.toStringTag;
|
|
85
80
|
|
|
86
81
|
export { ReadablePromise };
|
|
87
82
|
//# sourceMappingURL=readablepromise.mjs.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"readablepromise.mjs","sources":["../../src/readablepromise.ts"],"sourcesContent":["/**\n * The ReadablePromise class wraps a request promise suitable for React Suspense.\n * See: https://blog.logrocket.com/react-suspense-data-fetching/#wrappromise-js\n * See: https://github.com/ovieokeh/suspense-data-fetching/blob/master/lib/api/wrapPromise.js\n */\nexport class ReadablePromise<T> implements Promise<T> {\n readonly [Symbol.toStringTag]: string = 'ReadablePromise';\n
|
|
1
|
+
{"version":3,"file":"readablepromise.mjs","sources":["../../src/readablepromise.ts"],"sourcesContent":["/**\n * The ReadablePromise class wraps a request promise suitable for React Suspense.\n * See: https://blog.logrocket.com/react-suspense-data-fetching/#wrappromise-js\n * See: https://github.com/ovieokeh/suspense-data-fetching/blob/master/lib/api/wrapPromise.js\n */\nexport class ReadablePromise<T> implements Promise<T> {\n readonly [Symbol.toStringTag]: string = 'ReadablePromise';\n private suspender: Promise<T>;\n private status: 'pending' | 'error' | 'success' = 'pending';\n private response: T | undefined;\n private error: Error | undefined;\n\n constructor(requestPromise: Promise<T>) {\n this.suspender = requestPromise.then(\n (res: T) => {\n this.status = 'success';\n this.response = res;\n return res;\n },\n (err: any) => {\n this.status = 'error';\n this.error = err;\n throw err;\n }\n );\n }\n\n /**\n * Returns true if the promise is pending.\n * @returns True if the Promise is pending.\n */\n isPending(): boolean {\n return this.status === 'pending';\n }\n\n /**\n * Returns true if the promise resolved successfully.\n * @returns True if the Promise resolved successfully.\n */\n isOk(): boolean {\n return this.status === 'success';\n }\n\n /**\n * Attempts to read the value of the promise.\n * If the promise is pending, this method will throw a promise.\n * If the promise rejected, this method will throw the rejection reason.\n * If the promise resolved, this method will return the resolved value.\n * @returns The resolved value of the Promise.\n */\n read(): T {\n switch (this.status) {\n case 'pending':\n throw this.suspender;\n case 'error':\n throw this.error;\n default:\n return this.response as T;\n }\n }\n\n /**\n * Attaches callbacks for the resolution and/or rejection of the Promise.\n * @param onfulfilled The callback to execute when the Promise is resolved.\n * @param onrejected The callback to execute when the Promise is rejected.\n * @returns A Promise for the completion of which ever callback is executed.\n */\n then<TResult1 = T, TResult2 = never>(\n onfulfilled?: ((value: T) => TResult1 | PromiseLike<TResult1>) | undefined | null,\n onrejected?: ((reason: any) => TResult2 | PromiseLike<TResult2>) | undefined | null\n ): Promise<TResult1 | TResult2> {\n return this.suspender.then(onfulfilled, onrejected);\n }\n\n /**\n * Attaches a callback for only the rejection of the Promise.\n * @param onrejected The callback to execute when the Promise is rejected.\n * @returns A Promise for the completion of the callback.\n */\n catch<TResult = never>(\n onrejected?: ((reason: any) => TResult | PromiseLike<TResult>) | undefined | null\n ): Promise<T | TResult> {\n return this.suspender.catch(onrejected);\n }\n\n /**\n * Attaches a callback that is invoked when the Promise is settled (fulfilled or rejected). The\n * resolved value cannot be modified from the callback.\n * @param onfinally The callback to execute when the Promise is settled (fulfilled or rejected).\n * @returns A Promise for the completion of the callback.\n */\n finally(onfinally?: (() => void) | undefined | null): Promise<T> {\n return this.suspender.finally(onfinally);\n }\n}\n"],"names":[],"mappings":";AAAA;;;;AAIG;MACU,eAAe,CAAA;AAO1B,IAAA,WAAA,CAAY,cAA0B,EAAA;QAN7B,IAAoB,CAAA,EAAA,CAAA,GAAW,iBAAiB,CAAC;QAElD,IAAM,CAAA,MAAA,GAAoC,SAAS,CAAC;QAK1D,IAAI,CAAC,SAAS,GAAG,cAAc,CAAC,IAAI,CAClC,CAAC,GAAM,KAAI;AACT,YAAA,IAAI,CAAC,MAAM,GAAG,SAAS,CAAC;AACxB,YAAA,IAAI,CAAC,QAAQ,GAAG,GAAG,CAAC;AACpB,YAAA,OAAO,GAAG,CAAC;AACb,SAAC,EACD,CAAC,GAAQ,KAAI;AACX,YAAA,IAAI,CAAC,MAAM,GAAG,OAAO,CAAC;AACtB,YAAA,IAAI,CAAC,KAAK,GAAG,GAAG,CAAC;AACjB,YAAA,MAAM,GAAG,CAAC;AACZ,SAAC,CACF,CAAC;KACH;AAED;;;AAGG;IACH,SAAS,GAAA;AACP,QAAA,OAAO,IAAI,CAAC,MAAM,KAAK,SAAS,CAAC;KAClC;AAED;;;AAGG;IACH,IAAI,GAAA;AACF,QAAA,OAAO,IAAI,CAAC,MAAM,KAAK,SAAS,CAAC;KAClC;AAED;;;;;;AAMG;IACH,IAAI,GAAA;QACF,QAAQ,IAAI,CAAC,MAAM;AACjB,YAAA,KAAK,SAAS;gBACZ,MAAM,IAAI,CAAC,SAAS,CAAC;AACvB,YAAA,KAAK,OAAO;gBACV,MAAM,IAAI,CAAC,KAAK,CAAC;AACnB,YAAA;gBACE,OAAO,IAAI,CAAC,QAAa,CAAC;AAC7B,SAAA;KACF;AAED;;;;;AAKG;IACH,IAAI,CACF,WAAiF,EACjF,UAAmF,EAAA;QAEnF,OAAO,IAAI,CAAC,SAAS,CAAC,IAAI,CAAC,WAAW,EAAE,UAAU,CAAC,CAAC;KACrD;AAED;;;;AAIG;AACH,IAAA,KAAK,CACH,UAAiF,EAAA;QAEjF,OAAO,IAAI,CAAC,SAAS,CAAC,KAAK,CAAC,UAAU,CAAC,CAAC;KACzC;AAED;;;;;AAKG;AACH,IAAA,OAAO,CAAC,SAA2C,EAAA;QACjD,OAAO,IAAI,CAAC,SAAS,CAAC,OAAO,CAAC,SAAS,CAAC,CAAC;KAC1C;AACF,CAAA;AAxFW,EAAA,GAAA,MAAM,CAAC,WAAW;;;;"}
|
package/dist/esm/schema.mjs
CHANGED
|
@@ -1,13 +1,9 @@
|
|
|
1
|
-
import { __classPrivateFieldSet, __classPrivateFieldGet } from './node_modules/tslib/tslib.es6.mjs';
|
|
2
|
-
import './fhirlexer/parse.mjs';
|
|
3
|
-
import './fhirlexer/tokenize.mjs';
|
|
4
1
|
import { globalSchema, PropertyType } from './types.mjs';
|
|
5
2
|
import { isEmpty, isLowerCase, getExtensionValue, capitalize } from './utils.mjs';
|
|
6
3
|
import { toTypedValue, getTypedPropertyValue } from './fhirpath/utils.mjs';
|
|
7
4
|
import './fhirpath/parse.mjs';
|
|
8
5
|
import { OperationOutcomeError, validationError } from './outcomes.mjs';
|
|
9
6
|
|
|
10
|
-
var _FhirSchemaValidator_instances, _FhirSchemaValidator_issues, _FhirSchemaValidator_root, _FhirSchemaValidator_validateObject, _FhirSchemaValidator_checkProperties, _FhirSchemaValidator_checkProperty, _FhirSchemaValidator_checkPropertyValue, _FhirSchemaValidator_validatePrimitiveType, _FhirSchemaValidator_validateString, _FhirSchemaValidator_validateNumber, _FhirSchemaValidator_checkAdditionalProperties, _FhirSchemaValidator_checkAdditionalProperty, _FhirSchemaValidator_checkPrimitiveElement, _FhirSchemaValidator_createIssue;
|
|
11
7
|
/*
|
|
12
8
|
* This file provides schema validation utilities for FHIR JSON objects.
|
|
13
9
|
*
|
|
@@ -169,14 +165,11 @@ function validateResource(resource) {
|
|
|
169
165
|
}
|
|
170
166
|
class FhirSchemaValidator {
|
|
171
167
|
constructor(root) {
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
_FhirSchemaValidator_root.set(this, void 0);
|
|
175
|
-
__classPrivateFieldSet(this, _FhirSchemaValidator_issues, [], "f");
|
|
176
|
-
__classPrivateFieldSet(this, _FhirSchemaValidator_root, root, "f");
|
|
168
|
+
this.issues = [];
|
|
169
|
+
this.root = root;
|
|
177
170
|
}
|
|
178
171
|
validate() {
|
|
179
|
-
const resource =
|
|
172
|
+
const resource = this.root;
|
|
180
173
|
if (!resource) {
|
|
181
174
|
throw new OperationOutcomeError(validationError('Resource is null'));
|
|
182
175
|
}
|
|
@@ -185,142 +178,172 @@ class FhirSchemaValidator {
|
|
|
185
178
|
throw new OperationOutcomeError(validationError('Missing resource type'));
|
|
186
179
|
}
|
|
187
180
|
// Check for "null" once for the entire object hierarchy
|
|
188
|
-
checkForNull(resource, '',
|
|
189
|
-
|
|
190
|
-
if (
|
|
181
|
+
checkForNull(resource, '', this.issues);
|
|
182
|
+
this.validateObject(toTypedValue(resource), resourceType);
|
|
183
|
+
if (this.issues.length > 0) {
|
|
191
184
|
throw new OperationOutcomeError({
|
|
192
185
|
resourceType: 'OperationOutcome',
|
|
193
|
-
issue:
|
|
186
|
+
issue: this.issues,
|
|
194
187
|
});
|
|
195
188
|
}
|
|
196
189
|
}
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
__classPrivateFieldGet(this, _FhirSchemaValidator_instances, "m", _FhirSchemaValidator_checkAdditionalProperties).call(this, path, typedValue, propertyDefinitions);
|
|
206
|
-
}, _FhirSchemaValidator_checkProperties = function _FhirSchemaValidator_checkProperties(path, propertyDefinitions, typedValue) {
|
|
207
|
-
for (const [key, elementDefinition] of Object.entries(propertyDefinitions)) {
|
|
208
|
-
__classPrivateFieldGet(this, _FhirSchemaValidator_instances, "m", _FhirSchemaValidator_checkProperty).call(this, path + '.' + key, elementDefinition, typedValue);
|
|
190
|
+
validateObject(typedValue, path) {
|
|
191
|
+
const definition = globalSchema.types[typedValue.type];
|
|
192
|
+
if (!definition) {
|
|
193
|
+
throw new OperationOutcomeError(validationError('Unknown type: ' + typedValue.type));
|
|
194
|
+
}
|
|
195
|
+
const propertyDefinitions = definition.properties;
|
|
196
|
+
this.checkProperties(path, propertyDefinitions, typedValue);
|
|
197
|
+
this.checkAdditionalProperties(path, typedValue, propertyDefinitions);
|
|
209
198
|
}
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
if (elementDefinition.min !== undefined && elementDefinition.min > 0) {
|
|
215
|
-
__classPrivateFieldGet(this, _FhirSchemaValidator_issues, "f").push(createStructureIssue(path, 'Missing required property'));
|
|
216
|
-
}
|
|
217
|
-
return;
|
|
199
|
+
checkProperties(path, propertyDefinitions, typedValue) {
|
|
200
|
+
for (const [key, elementDefinition] of Object.entries(propertyDefinitions)) {
|
|
201
|
+
this.checkProperty(path + '.' + key, elementDefinition, typedValue);
|
|
202
|
+
}
|
|
218
203
|
}
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
204
|
+
checkProperty(path, elementDefinition, typedValue) {
|
|
205
|
+
const propertyName = path.split('.').pop();
|
|
206
|
+
const value = getTypedPropertyValue(typedValue, propertyName);
|
|
207
|
+
if (isEmpty(value)) {
|
|
208
|
+
if (elementDefinition.min !== undefined && elementDefinition.min > 0) {
|
|
209
|
+
this.issues.push(createStructureIssue(path, 'Missing required property'));
|
|
210
|
+
}
|
|
222
211
|
return;
|
|
223
212
|
}
|
|
224
|
-
|
|
225
|
-
|
|
213
|
+
if (elementDefinition.max === '*') {
|
|
214
|
+
if (!Array.isArray(value)) {
|
|
215
|
+
this.issues.push(createStructureIssue(path, 'Expected array for property'));
|
|
216
|
+
return;
|
|
217
|
+
}
|
|
218
|
+
for (const item of value) {
|
|
219
|
+
this.checkPropertyValue(path, elementDefinition, item);
|
|
220
|
+
}
|
|
221
|
+
}
|
|
222
|
+
else {
|
|
223
|
+
if (Array.isArray(value)) {
|
|
224
|
+
this.issues.push(createStructureIssue(path, 'Expected single value for property'));
|
|
225
|
+
return;
|
|
226
|
+
}
|
|
227
|
+
this.checkPropertyValue(path, elementDefinition, value);
|
|
226
228
|
}
|
|
227
229
|
}
|
|
228
|
-
|
|
229
|
-
if (
|
|
230
|
-
|
|
230
|
+
checkPropertyValue(path, elementDefinition, typedValue) {
|
|
231
|
+
if (typedValue.value === null) {
|
|
232
|
+
// Null handled separately
|
|
231
233
|
return;
|
|
232
234
|
}
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
}
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
}
|
|
240
|
-
if (isLowerCase(typedValue.type.charAt(0))) {
|
|
241
|
-
__classPrivateFieldGet(this, _FhirSchemaValidator_instances, "m", _FhirSchemaValidator_validatePrimitiveType).call(this, elementDefinition, typedValue);
|
|
242
|
-
}
|
|
243
|
-
else {
|
|
244
|
-
__classPrivateFieldGet(this, _FhirSchemaValidator_instances, "m", _FhirSchemaValidator_validateObject).call(this, typedValue, path);
|
|
245
|
-
}
|
|
246
|
-
}, _FhirSchemaValidator_validatePrimitiveType = function _FhirSchemaValidator_validatePrimitiveType(elementDefinition, typedValue) {
|
|
247
|
-
const { type, value } = typedValue;
|
|
248
|
-
if (value === null) {
|
|
249
|
-
// Null handled separately, so this code should never be reached
|
|
250
|
-
// Leaving this check in place for now, in case we change the null handling
|
|
251
|
-
return;
|
|
252
|
-
}
|
|
253
|
-
// First, make sure the value is the correct JS type
|
|
254
|
-
const expectedType = fhirTypeToJsType[typedValue.type];
|
|
255
|
-
if (typeof value !== expectedType) {
|
|
256
|
-
__classPrivateFieldGet(this, _FhirSchemaValidator_instances, "m", _FhirSchemaValidator_createIssue).call(this, elementDefinition, 'Invalid type for ' + type);
|
|
257
|
-
return;
|
|
258
|
-
}
|
|
259
|
-
// Then, perform additional checks for specialty types
|
|
260
|
-
if (expectedType === 'string') {
|
|
261
|
-
__classPrivateFieldGet(this, _FhirSchemaValidator_instances, "m", _FhirSchemaValidator_validateString).call(this, elementDefinition, type, value);
|
|
262
|
-
}
|
|
263
|
-
else if (expectedType === 'number') {
|
|
264
|
-
__classPrivateFieldGet(this, _FhirSchemaValidator_instances, "m", _FhirSchemaValidator_validateNumber).call(this, elementDefinition, type, value);
|
|
235
|
+
if (isLowerCase(typedValue.type.charAt(0))) {
|
|
236
|
+
this.validatePrimitiveType(elementDefinition, typedValue);
|
|
237
|
+
}
|
|
238
|
+
else {
|
|
239
|
+
this.validateObject(typedValue, path);
|
|
240
|
+
}
|
|
265
241
|
}
|
|
266
|
-
|
|
267
|
-
|
|
268
|
-
|
|
269
|
-
|
|
242
|
+
validatePrimitiveType(elementDefinition, typedValue) {
|
|
243
|
+
const { type, value } = typedValue;
|
|
244
|
+
if (value === null) {
|
|
245
|
+
// Null handled separately, so this code should never be reached
|
|
246
|
+
// Leaving this check in place for now, in case we change the null handling
|
|
247
|
+
return;
|
|
248
|
+
}
|
|
249
|
+
// First, make sure the value is the correct JS type
|
|
250
|
+
const expectedType = fhirTypeToJsType[typedValue.type];
|
|
251
|
+
if (typeof value !== expectedType) {
|
|
252
|
+
this.createIssue(elementDefinition, 'Invalid type for ' + type);
|
|
253
|
+
return;
|
|
254
|
+
}
|
|
255
|
+
// Then, perform additional checks for specialty types
|
|
256
|
+
if (expectedType === 'string') {
|
|
257
|
+
this.validateString(elementDefinition, type, value);
|
|
258
|
+
}
|
|
259
|
+
else if (expectedType === 'number') {
|
|
260
|
+
this.validateNumber(elementDefinition, type, value);
|
|
261
|
+
}
|
|
270
262
|
}
|
|
271
|
-
|
|
272
|
-
|
|
273
|
-
|
|
274
|
-
|
|
275
|
-
|
|
276
|
-
|
|
277
|
-
|
|
263
|
+
validateString(elementDefinition, type, value) {
|
|
264
|
+
if (!value.trim()) {
|
|
265
|
+
this.createIssue(elementDefinition, 'Invalid empty string');
|
|
266
|
+
return;
|
|
267
|
+
}
|
|
268
|
+
// Try to get the regex
|
|
269
|
+
const valueDefinition = globalSchema.types[type]?.properties?.['value'];
|
|
270
|
+
if (valueDefinition?.type) {
|
|
271
|
+
const regex = getExtensionValue(valueDefinition.type[0], 'http://hl7.org/fhir/StructureDefinition/regex');
|
|
272
|
+
if (regex) {
|
|
273
|
+
if (!value.match(new RegExp(regex))) {
|
|
274
|
+
this.createIssue(elementDefinition, 'Invalid ' + type + ' format');
|
|
275
|
+
}
|
|
278
276
|
}
|
|
279
277
|
}
|
|
280
278
|
}
|
|
281
|
-
|
|
282
|
-
|
|
283
|
-
|
|
284
|
-
|
|
285
|
-
|
|
286
|
-
|
|
287
|
-
|
|
288
|
-
|
|
289
|
-
|
|
290
|
-
|
|
291
|
-
|
|
292
|
-
|
|
293
|
-
|
|
279
|
+
validateNumber(elementDefinition, type, value) {
|
|
280
|
+
if (isNaN(value) || !isFinite(value)) {
|
|
281
|
+
this.createIssue(elementDefinition, 'Invalid ' + type + ' value');
|
|
282
|
+
return;
|
|
283
|
+
}
|
|
284
|
+
if (isIntegerType(type) && !Number.isInteger(value)) {
|
|
285
|
+
this.createIssue(elementDefinition, 'Number is not an integer');
|
|
286
|
+
}
|
|
287
|
+
if (type === PropertyType.positiveInt && value <= 0) {
|
|
288
|
+
this.createIssue(elementDefinition, 'Number is less than or equal to zero');
|
|
289
|
+
}
|
|
290
|
+
if (type === PropertyType.unsignedInt && value < 0) {
|
|
291
|
+
this.createIssue(elementDefinition, 'Number is negative');
|
|
292
|
+
}
|
|
294
293
|
}
|
|
295
|
-
|
|
296
|
-
|
|
297
|
-
|
|
298
|
-
|
|
294
|
+
checkAdditionalProperties(path, typedValue, propertyDefinitions) {
|
|
295
|
+
const object = typedValue.value;
|
|
296
|
+
for (const key of Object.keys(object)) {
|
|
297
|
+
this.checkAdditionalProperty(path, key, typedValue, propertyDefinitions);
|
|
298
|
+
}
|
|
299
299
|
}
|
|
300
|
-
|
|
301
|
-
|
|
302
|
-
|
|
303
|
-
|
|
304
|
-
|
|
305
|
-
|
|
306
|
-
|
|
300
|
+
/**
|
|
301
|
+
* Checks if the given property is allowed on the given object.
|
|
302
|
+
* @param path The path of the current object.
|
|
303
|
+
* @param key The key of a property to check.
|
|
304
|
+
* @param typedValue The current object.
|
|
305
|
+
* @param propertyDefinitions The property definitions of the current object.
|
|
306
|
+
*/
|
|
307
|
+
checkAdditionalProperty(path, key, typedValue, propertyDefinitions) {
|
|
308
|
+
if (!baseResourceProperties.has(key) &&
|
|
309
|
+
!(key in propertyDefinitions) &&
|
|
310
|
+
!isChoiceOfType(key, typedValue, propertyDefinitions) &&
|
|
311
|
+
!this.checkPrimitiveElement(path, key, typedValue)) {
|
|
312
|
+
const expression = `${path}.${key}`;
|
|
313
|
+
this.issues.push(createStructureIssue(expression, `Invalid additional property "${expression}"`));
|
|
314
|
+
}
|
|
307
315
|
}
|
|
308
|
-
|
|
309
|
-
|
|
310
|
-
|
|
311
|
-
|
|
316
|
+
/**
|
|
317
|
+
* Checks the element for a primitive.
|
|
318
|
+
*
|
|
319
|
+
* FHIR elements with primitive data types are represented in two parts:
|
|
320
|
+
* 1) A JSON property with the name of the element, which has a JSON type of number, boolean, or string
|
|
321
|
+
* 2) a JSON property with _ prepended to the name of the element, which, if present, contains the value's id and/or extensions
|
|
322
|
+
*
|
|
323
|
+
* See: https://hl7.org/fhir/json.html#primitive
|
|
324
|
+
*
|
|
325
|
+
* @param path The path to the property
|
|
326
|
+
* @param key
|
|
327
|
+
* @param typedValue
|
|
328
|
+
*/
|
|
329
|
+
checkPrimitiveElement(path, key, typedValue) {
|
|
330
|
+
// Primitive element starts with underscore
|
|
331
|
+
if (!key.startsWith('_')) {
|
|
332
|
+
return false;
|
|
333
|
+
}
|
|
334
|
+
// Validate the non-underscore property exists
|
|
335
|
+
const primitiveKey = key.slice(1);
|
|
336
|
+
if (!(primitiveKey in typedValue.value)) {
|
|
337
|
+
return false;
|
|
338
|
+
}
|
|
339
|
+
// Then validate the element
|
|
340
|
+
this.validateObject({ type: 'Element', value: typedValue.value[key] }, path);
|
|
341
|
+
return true;
|
|
312
342
|
}
|
|
313
|
-
|
|
314
|
-
|
|
315
|
-
if (!(primitiveKey in typedValue.value)) {
|
|
316
|
-
return false;
|
|
343
|
+
createIssue(elementDefinition, message) {
|
|
344
|
+
this.issues.push(createStructureIssue(elementDefinition.path, message));
|
|
317
345
|
}
|
|
318
|
-
|
|
319
|
-
__classPrivateFieldGet(this, _FhirSchemaValidator_instances, "m", _FhirSchemaValidator_validateObject).call(this, { type: 'Element', value: typedValue.value[key] }, path);
|
|
320
|
-
return true;
|
|
321
|
-
}, _FhirSchemaValidator_createIssue = function _FhirSchemaValidator_createIssue(elementDefinition, message) {
|
|
322
|
-
__classPrivateFieldGet(this, _FhirSchemaValidator_issues, "f").push(createStructureIssue(elementDefinition.path, message));
|
|
323
|
-
};
|
|
346
|
+
}
|
|
324
347
|
function isIntegerType(propertyType) {
|
|
325
348
|
return (propertyType === PropertyType.integer ||
|
|
326
349
|
propertyType === PropertyType.positiveInt ||
|
package/dist/esm/schema.mjs.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"schema.mjs","sources":["../../src/schema.ts"],"sourcesContent":["import { ElementDefinition, OperationOutcomeIssue, Resource } from '@medplum/fhirtypes';\nimport { getTypedPropertyValue, toTypedValue } from './fhirpath';\nimport { OperationOutcomeError, validationError } from './outcomes';\nimport { globalSchema, PropertyType, TypedValue } from './types';\nimport { capitalize, getExtensionValue, isEmpty, isLowerCase } from './utils';\n\n/*\n * This file provides schema validation utilities for FHIR JSON objects.\n *\n * See: [JSON Representation of Resources](https://hl7.org/fhir/json.html)\n * See: [FHIR Data Types](https://www.hl7.org/fhir/datatypes.html)\n */\n\nconst fhirTypeToJsType: Record<string, string> = {\n base64Binary: 'string',\n boolean: 'boolean',\n canonical: 'string',\n code: 'string',\n date: 'string',\n dateTime: 'string',\n decimal: 'number',\n id: 'string',\n instant: 'string',\n integer: 'number',\n markdown: 'string',\n oid: 'string',\n positiveInt: 'number',\n string: 'string',\n time: 'string',\n unsignedInt: 'number',\n uri: 'string',\n url: 'string',\n uuid: 'string',\n xhtml: 'string',\n 'http://hl7.org/fhirpath/System.String': 'string',\n};\n\nconst baseResourceProperties = new Set<string>([\n // Resource\n 'resourceType',\n 'id',\n 'meta',\n 'implicitRules',\n 'language',\n\n // DomainResource\n 'text',\n 'contained',\n 'extension',\n 'modifierExtension',\n]);\n\n/**\n * Returns true if the given string is a valid FHIR resource type.\n *\n * ```ts\n * isResourceType('Patient'); // true\n * isResourceType('XYZ'); // false\n * ```\n *\n * Note that this depends on globalSchema, which is populated by the StructureDefinition loader.\n *\n * In a server context, you can load all schema definitions:\n *\n * ```ts\n * import { indexStructureDefinitionBundle } from '@medplum/core';\n * import { readJson } from '@medplum/definitions';\n * import { Bundle } from '@medplum/fhirtypes';\n *\n * indexStructureDefinitionBundle(readJson('fhir/r4/profiles-resources.json') as Bundle);\n * ```\n *\n * In a client context, you can load the schema definitions using MedplumClient:\n *\n * ```ts\n * import { MedplumClient } from '@medplum/core';\n *\n * const medplum = new MedplumClient();\n * await medplum.requestSchema('Patient');\n * ```\n *\n * @param resourceType The candidate resource type string.\n * @returns True if the resource type is a valid FHIR resource type.\n */\nexport function isResourceType(resourceType: string): boolean {\n const typeSchema = globalSchema.types[resourceType];\n return (\n typeSchema &&\n typeSchema.structureDefinition.id === resourceType &&\n typeSchema.structureDefinition.kind === 'resource'\n );\n}\n\n/**\n * Validates that the given string is a valid FHIR resource type.\n * On success, silently returns void.\n * On failure, throws an OperationOutcomeError.\n *\n * ```ts\n * validateResourceType('Patient'); // nothing\n * validateResourceType('XYZ'); // throws OperationOutcomeError\n * ```\n *\n * Note that this depends on globalSchema, which is populated by the StructureDefinition loader.\n *\n * In a server context, you can load all schema definitions:\n *\n * ```ts\n * import { indexStructureDefinitionBundle } from '@medplum/core';\n * import { readJson } from '@medplum/definitions';\n * import { Bundle } from '@medplum/fhirtypes';\n *\n * indexStructureDefinitionBundle(readJson('fhir/r4/profiles-resources.json') as Bundle);\n * ```\n *\n * In a client context, you can load the schema definitions using MedplumClient:\n *\n * ```ts\n * import { MedplumClient } from '@medplum/core';\n *\n * const medplum = new MedplumClient();\n * await medplum.requestSchema('Patient');\n * ```\n *\n * @param resourceType The candidate resource type string.\n * @returns True if the resource type is a valid FHIR resource type.\n */\nexport function validateResourceType(resourceType: string): void {\n if (!resourceType) {\n throw new OperationOutcomeError(validationError('Resource type is null'));\n }\n if (!isResourceType(resourceType)) {\n throw new OperationOutcomeError(validationError('Unknown resource type'));\n }\n}\n\n/**\n * Validates a candidate FHIR resource object.\n * On success, silently returns void.\n * On failure, throws an OperationOutcomeError with issues for each violation.\n *\n * ```ts\n * validateResource({ resourceType: 'Patient' }); // nothing\n * validateResource({ resourceType: 'XYZ' }); // throws OperationOutcomeError\n * ```\n *\n * Note that this depends on globalSchema, which is populated by the StructureDefinition loader.\n *\n * In a server context, you can load all schema definitions:\n *\n * ```ts\n * import { indexStructureDefinitionBundle } from '@medplum/core';\n * import { readJson } from '@medplum/definitions';\n * import { Bundle } from '@medplum/fhirtypes';\n *\n * indexStructureDefinitionBundle(readJson('fhir/r4/profiles-resources.json') as Bundle);\n * ```\n *\n * In a client context, you can load the schema definitions using MedplumClient:\n *\n * ```ts\n * import { MedplumClient } from '@medplum/core';\n *\n * const medplum = new MedplumClient();\n * await medplum.requestSchema('Patient');\n * ```\n *\n * @param resourceType The candidate resource type string.\n * @returns True if the resource type is a valid FHIR resource type.\n */\nexport function validateResource<T extends Resource>(resource: T): void {\n new FhirSchemaValidator(resource).validate();\n}\n\nexport class FhirSchemaValidator<T extends Resource> {\n readonly #issues: OperationOutcomeIssue[];\n readonly #root: T;\n\n constructor(root: T) {\n this.#issues = [];\n this.#root = root;\n }\n\n validate(): void {\n const resource = this.#root;\n if (!resource) {\n throw new OperationOutcomeError(validationError('Resource is null'));\n }\n\n const resourceType = resource.resourceType;\n if (!resourceType) {\n throw new OperationOutcomeError(validationError('Missing resource type'));\n }\n\n // Check for \"null\" once for the entire object hierarchy\n checkForNull(resource, '', this.#issues);\n\n this.#validateObject(toTypedValue(resource), resourceType);\n\n if (this.#issues.length > 0) {\n throw new OperationOutcomeError({\n resourceType: 'OperationOutcome',\n issue: this.#issues,\n });\n }\n }\n\n #validateObject(typedValue: TypedValue, path: string): void {\n const definition = globalSchema.types[typedValue.type];\n if (!definition) {\n throw new OperationOutcomeError(validationError('Unknown type: ' + typedValue.type));\n }\n\n const propertyDefinitions = definition.properties;\n this.#checkProperties(path, propertyDefinitions, typedValue);\n this.#checkAdditionalProperties(path, typedValue, propertyDefinitions);\n }\n\n #checkProperties(path: string, propertyDefinitions: Record<string, ElementDefinition>, typedValue: TypedValue): void {\n for (const [key, elementDefinition] of Object.entries(propertyDefinitions)) {\n this.#checkProperty(path + '.' + key, elementDefinition, typedValue);\n }\n }\n\n #checkProperty(path: string, elementDefinition: ElementDefinition, typedValue: TypedValue): void {\n const propertyName = path.split('.').pop() as string;\n const value = getTypedPropertyValue(typedValue, propertyName);\n\n if (isEmpty(value)) {\n if (elementDefinition.min !== undefined && elementDefinition.min > 0) {\n this.#issues.push(createStructureIssue(path, 'Missing required property'));\n }\n return;\n }\n\n if (elementDefinition.max === '*') {\n if (!Array.isArray(value)) {\n this.#issues.push(createStructureIssue(path, 'Expected array for property'));\n return;\n }\n for (const item of value) {\n this.#checkPropertyValue(path, elementDefinition, item);\n }\n } else {\n if (Array.isArray(value)) {\n this.#issues.push(createStructureIssue(path, 'Expected single value for property'));\n return;\n }\n this.#checkPropertyValue(path, elementDefinition, value as TypedValue);\n }\n }\n\n #checkPropertyValue(path: string, elementDefinition: ElementDefinition, typedValue: TypedValue): void {\n if (typedValue.value === null) {\n // Null handled separately\n return;\n }\n\n if (isLowerCase(typedValue.type.charAt(0))) {\n this.#validatePrimitiveType(elementDefinition, typedValue);\n } else {\n this.#validateObject(typedValue, path);\n }\n }\n\n #validatePrimitiveType(elementDefinition: ElementDefinition, typedValue: TypedValue): void {\n const { type, value } = typedValue;\n\n if (value === null) {\n // Null handled separately, so this code should never be reached\n // Leaving this check in place for now, in case we change the null handling\n return;\n }\n\n // First, make sure the value is the correct JS type\n const expectedType = fhirTypeToJsType[typedValue.type];\n if (typeof value !== expectedType) {\n this.#createIssue(elementDefinition, 'Invalid type for ' + type);\n return;\n }\n\n // Then, perform additional checks for specialty types\n if (expectedType === 'string') {\n this.#validateString(elementDefinition, type as PropertyType, value as string);\n } else if (expectedType === 'number') {\n this.#validateNumber(elementDefinition, type as PropertyType, value as number);\n }\n }\n\n #validateString(elementDefinition: ElementDefinition, type: PropertyType, value: string): void {\n if (!value.trim()) {\n this.#createIssue(elementDefinition, 'Invalid empty string');\n return;\n }\n\n // Try to get the regex\n const valueDefinition = globalSchema.types[type]?.properties?.['value'];\n if (valueDefinition?.type) {\n const regex = getExtensionValue(valueDefinition.type[0], 'http://hl7.org/fhir/StructureDefinition/regex');\n if (regex) {\n if (!value.match(new RegExp(regex))) {\n this.#createIssue(elementDefinition, 'Invalid ' + type + ' format');\n }\n }\n }\n }\n\n #validateNumber(elementDefinition: ElementDefinition, type: PropertyType, value: number): void {\n if (isNaN(value) || !isFinite(value)) {\n this.#createIssue(elementDefinition, 'Invalid ' + type + ' value');\n return;\n }\n\n if (isIntegerType(type) && !Number.isInteger(value)) {\n this.#createIssue(elementDefinition, 'Number is not an integer');\n }\n\n if (type === PropertyType.positiveInt && value <= 0) {\n this.#createIssue(elementDefinition, 'Number is less than or equal to zero');\n }\n\n if (type === PropertyType.unsignedInt && value < 0) {\n this.#createIssue(elementDefinition, 'Number is negative');\n }\n }\n\n #checkAdditionalProperties(\n path: string,\n typedValue: TypedValue,\n propertyDefinitions: Record<string, ElementDefinition>\n ): void {\n const object = typedValue.value as Record<string, unknown>;\n for (const key of Object.keys(object)) {\n this.#checkAdditionalProperty(path, key, typedValue, propertyDefinitions);\n }\n }\n\n /**\n * Checks if the given property is allowed on the given object.\n * @param path The path of the current object.\n * @param key The key of a property to check.\n * @param typedValue The current object.\n * @param propertyDefinitions The property definitions of the current object.\n */\n #checkAdditionalProperty(\n path: string,\n key: string,\n typedValue: TypedValue,\n propertyDefinitions: Record<string, ElementDefinition>\n ): void {\n if (\n !baseResourceProperties.has(key) &&\n !(key in propertyDefinitions) &&\n !isChoiceOfType(key, typedValue, propertyDefinitions) &&\n !this.#checkPrimitiveElement(path, key, typedValue)\n ) {\n const expression = `${path}.${key}`;\n this.#issues.push(createStructureIssue(expression, `Invalid additional property \"${expression}\"`));\n }\n }\n\n /**\n * Checks the element for a primitive.\n *\n * FHIR elements with primitive data types are represented in two parts:\n * 1) A JSON property with the name of the element, which has a JSON type of number, boolean, or string\n * 2) a JSON property with _ prepended to the name of the element, which, if present, contains the value's id and/or extensions\n *\n * See: https://hl7.org/fhir/json.html#primitive\n *\n * @param path The path to the property\n * @param key\n * @param typedValue\n */\n #checkPrimitiveElement(path: string, key: string, typedValue: TypedValue): boolean {\n // Primitive element starts with underscore\n if (!key.startsWith('_')) {\n return false;\n }\n\n // Validate the non-underscore property exists\n const primitiveKey = key.slice(1);\n if (!(primitiveKey in typedValue.value)) {\n return false;\n }\n\n // Then validate the element\n this.#validateObject({ type: 'Element', value: typedValue.value[key] }, path);\n return true;\n }\n\n #createIssue(elementDefinition: ElementDefinition, message: string): void {\n this.#issues.push(createStructureIssue(elementDefinition.path as string, message));\n }\n}\n\nfunction isIntegerType(propertyType: PropertyType): boolean {\n return (\n propertyType === PropertyType.integer ||\n propertyType === PropertyType.positiveInt ||\n propertyType === PropertyType.unsignedInt\n );\n}\n\nfunction isChoiceOfType(\n key: string,\n typedValue: TypedValue,\n propertyDefinitions: Record<string, ElementDefinition>\n): boolean {\n for (const propertyName of Object.keys(propertyDefinitions)) {\n if (!propertyName.endsWith('[x]')) {\n continue;\n }\n const basePropertyName = propertyName.replace('[x]', '');\n if (!key.startsWith(basePropertyName)) {\n continue;\n }\n let typedPropertyValue = getTypedPropertyValue(typedValue, propertyName);\n if (!typedPropertyValue) {\n continue;\n }\n if (Array.isArray(typedPropertyValue)) {\n // At present, there are no choice types that are arrays in the FHIR spec\n // Leaving this here to make TypeScript happy, and in case that changes\n typedPropertyValue = typedPropertyValue[0];\n }\n if (typedPropertyValue && key === basePropertyName + capitalize(typedPropertyValue.type)) {\n return true;\n }\n }\n return false;\n}\n\n/**\n * Recursively checks for null values in an object.\n *\n * Note that \"null\" is a special value in JSON that is not allowed in FHIR.\n *\n * @param value Input value of any type.\n * @param path Path string to the value for OperationOutcome.\n * @param issues Output list of issues.\n */\nexport function checkForNull(value: unknown, path: string, issues: OperationOutcomeIssue[]): void {\n if (value === null) {\n issues.push(createStructureIssue(path, 'Invalid null value'));\n } else if (Array.isArray(value)) {\n checkArrayForNull(value, path, issues);\n } else if (typeof value === 'object') {\n checkObjectForNull(value as Record<string, unknown>, path, issues);\n }\n}\n\nfunction checkArrayForNull(array: unknown[], path: string, issues: OperationOutcomeIssue[]): void {\n for (let i = 0; i < array.length; i++) {\n if (array[i] === undefined) {\n issues.push(createStructureIssue(`${path}[${i}]`, 'Invalid undefined value'));\n } else {\n checkForNull(array[i], `${path}[${i}]`, issues);\n }\n }\n}\n\nfunction checkObjectForNull(obj: Record<string, unknown>, path: string, issues: OperationOutcomeIssue[]): void {\n for (const [key, value] of Object.entries(obj)) {\n checkForNull(value, `${path}${path ? '.' : ''}${key}`, issues);\n }\n}\n\nexport function createStructureIssue(expression: string, details: string): OperationOutcomeIssue {\n return {\n severity: 'error',\n code: 'structure',\n details: {\n text: details,\n },\n expression: [expression],\n };\n}\n"],"names":[],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"schema.mjs","sources":["../../src/schema.ts"],"sourcesContent":["import { ElementDefinition, OperationOutcomeIssue, Resource } from '@medplum/fhirtypes';\nimport { getTypedPropertyValue, toTypedValue } from './fhirpath';\nimport { OperationOutcomeError, validationError } from './outcomes';\nimport { globalSchema, PropertyType, TypedValue } from './types';\nimport { capitalize, getExtensionValue, isEmpty, isLowerCase } from './utils';\n\n/*\n * This file provides schema validation utilities for FHIR JSON objects.\n *\n * See: [JSON Representation of Resources](https://hl7.org/fhir/json.html)\n * See: [FHIR Data Types](https://www.hl7.org/fhir/datatypes.html)\n */\n\nconst fhirTypeToJsType: Record<string, string> = {\n base64Binary: 'string',\n boolean: 'boolean',\n canonical: 'string',\n code: 'string',\n date: 'string',\n dateTime: 'string',\n decimal: 'number',\n id: 'string',\n instant: 'string',\n integer: 'number',\n markdown: 'string',\n oid: 'string',\n positiveInt: 'number',\n string: 'string',\n time: 'string',\n unsignedInt: 'number',\n uri: 'string',\n url: 'string',\n uuid: 'string',\n xhtml: 'string',\n 'http://hl7.org/fhirpath/System.String': 'string',\n};\n\nconst baseResourceProperties = new Set<string>([\n // Resource\n 'resourceType',\n 'id',\n 'meta',\n 'implicitRules',\n 'language',\n\n // DomainResource\n 'text',\n 'contained',\n 'extension',\n 'modifierExtension',\n]);\n\n/**\n * Returns true if the given string is a valid FHIR resource type.\n *\n * ```ts\n * isResourceType('Patient'); // true\n * isResourceType('XYZ'); // false\n * ```\n *\n * Note that this depends on globalSchema, which is populated by the StructureDefinition loader.\n *\n * In a server context, you can load all schema definitions:\n *\n * ```ts\n * import { indexStructureDefinitionBundle } from '@medplum/core';\n * import { readJson } from '@medplum/definitions';\n * import { Bundle } from '@medplum/fhirtypes';\n *\n * indexStructureDefinitionBundle(readJson('fhir/r4/profiles-resources.json') as Bundle);\n * ```\n *\n * In a client context, you can load the schema definitions using MedplumClient:\n *\n * ```ts\n * import { MedplumClient } from '@medplum/core';\n *\n * const medplum = new MedplumClient();\n * await medplum.requestSchema('Patient');\n * ```\n *\n * @param resourceType The candidate resource type string.\n * @returns True if the resource type is a valid FHIR resource type.\n */\nexport function isResourceType(resourceType: string): boolean {\n const typeSchema = globalSchema.types[resourceType];\n return (\n typeSchema &&\n typeSchema.structureDefinition.id === resourceType &&\n typeSchema.structureDefinition.kind === 'resource'\n );\n}\n\n/**\n * Validates that the given string is a valid FHIR resource type.\n * On success, silently returns void.\n * On failure, throws an OperationOutcomeError.\n *\n * ```ts\n * validateResourceType('Patient'); // nothing\n * validateResourceType('XYZ'); // throws OperationOutcomeError\n * ```\n *\n * Note that this depends on globalSchema, which is populated by the StructureDefinition loader.\n *\n * In a server context, you can load all schema definitions:\n *\n * ```ts\n * import { indexStructureDefinitionBundle } from '@medplum/core';\n * import { readJson } from '@medplum/definitions';\n * import { Bundle } from '@medplum/fhirtypes';\n *\n * indexStructureDefinitionBundle(readJson('fhir/r4/profiles-resources.json') as Bundle);\n * ```\n *\n * In a client context, you can load the schema definitions using MedplumClient:\n *\n * ```ts\n * import { MedplumClient } from '@medplum/core';\n *\n * const medplum = new MedplumClient();\n * await medplum.requestSchema('Patient');\n * ```\n *\n * @param resourceType The candidate resource type string.\n * @returns True if the resource type is a valid FHIR resource type.\n */\nexport function validateResourceType(resourceType: string): void {\n if (!resourceType) {\n throw new OperationOutcomeError(validationError('Resource type is null'));\n }\n if (!isResourceType(resourceType)) {\n throw new OperationOutcomeError(validationError('Unknown resource type'));\n }\n}\n\n/**\n * Validates a candidate FHIR resource object.\n * On success, silently returns void.\n * On failure, throws an OperationOutcomeError with issues for each violation.\n *\n * ```ts\n * validateResource({ resourceType: 'Patient' }); // nothing\n * validateResource({ resourceType: 'XYZ' }); // throws OperationOutcomeError\n * ```\n *\n * Note that this depends on globalSchema, which is populated by the StructureDefinition loader.\n *\n * In a server context, you can load all schema definitions:\n *\n * ```ts\n * import { indexStructureDefinitionBundle } from '@medplum/core';\n * import { readJson } from '@medplum/definitions';\n * import { Bundle } from '@medplum/fhirtypes';\n *\n * indexStructureDefinitionBundle(readJson('fhir/r4/profiles-resources.json') as Bundle);\n * ```\n *\n * In a client context, you can load the schema definitions using MedplumClient:\n *\n * ```ts\n * import { MedplumClient } from '@medplum/core';\n *\n * const medplum = new MedplumClient();\n * await medplum.requestSchema('Patient');\n * ```\n *\n * @param resourceType The candidate resource type string.\n * @returns True if the resource type is a valid FHIR resource type.\n */\nexport function validateResource<T extends Resource>(resource: T): void {\n new FhirSchemaValidator(resource).validate();\n}\n\nexport class FhirSchemaValidator<T extends Resource> {\n private readonly issues: OperationOutcomeIssue[];\n private readonly root: T;\n\n constructor(root: T) {\n this.issues = [];\n this.root = root;\n }\n\n validate(): void {\n const resource = this.root;\n if (!resource) {\n throw new OperationOutcomeError(validationError('Resource is null'));\n }\n\n const resourceType = resource.resourceType;\n if (!resourceType) {\n throw new OperationOutcomeError(validationError('Missing resource type'));\n }\n\n // Check for \"null\" once for the entire object hierarchy\n checkForNull(resource, '', this.issues);\n\n this.validateObject(toTypedValue(resource), resourceType);\n\n if (this.issues.length > 0) {\n throw new OperationOutcomeError({\n resourceType: 'OperationOutcome',\n issue: this.issues,\n });\n }\n }\n\n private validateObject(typedValue: TypedValue, path: string): void {\n const definition = globalSchema.types[typedValue.type];\n if (!definition) {\n throw new OperationOutcomeError(validationError('Unknown type: ' + typedValue.type));\n }\n\n const propertyDefinitions = definition.properties;\n this.checkProperties(path, propertyDefinitions, typedValue);\n this.checkAdditionalProperties(path, typedValue, propertyDefinitions);\n }\n\n private checkProperties(\n path: string,\n propertyDefinitions: Record<string, ElementDefinition>,\n typedValue: TypedValue\n ): void {\n for (const [key, elementDefinition] of Object.entries(propertyDefinitions)) {\n this.checkProperty(path + '.' + key, elementDefinition, typedValue);\n }\n }\n\n private checkProperty(path: string, elementDefinition: ElementDefinition, typedValue: TypedValue): void {\n const propertyName = path.split('.').pop() as string;\n const value = getTypedPropertyValue(typedValue, propertyName);\n\n if (isEmpty(value)) {\n if (elementDefinition.min !== undefined && elementDefinition.min > 0) {\n this.issues.push(createStructureIssue(path, 'Missing required property'));\n }\n return;\n }\n\n if (elementDefinition.max === '*') {\n if (!Array.isArray(value)) {\n this.issues.push(createStructureIssue(path, 'Expected array for property'));\n return;\n }\n for (const item of value) {\n this.checkPropertyValue(path, elementDefinition, item);\n }\n } else {\n if (Array.isArray(value)) {\n this.issues.push(createStructureIssue(path, 'Expected single value for property'));\n return;\n }\n this.checkPropertyValue(path, elementDefinition, value as TypedValue);\n }\n }\n\n private checkPropertyValue(path: string, elementDefinition: ElementDefinition, typedValue: TypedValue): void {\n if (typedValue.value === null) {\n // Null handled separately\n return;\n }\n\n if (isLowerCase(typedValue.type.charAt(0))) {\n this.validatePrimitiveType(elementDefinition, typedValue);\n } else {\n this.validateObject(typedValue, path);\n }\n }\n\n private validatePrimitiveType(elementDefinition: ElementDefinition, typedValue: TypedValue): void {\n const { type, value } = typedValue;\n\n if (value === null) {\n // Null handled separately, so this code should never be reached\n // Leaving this check in place for now, in case we change the null handling\n return;\n }\n\n // First, make sure the value is the correct JS type\n const expectedType = fhirTypeToJsType[typedValue.type];\n if (typeof value !== expectedType) {\n this.createIssue(elementDefinition, 'Invalid type for ' + type);\n return;\n }\n\n // Then, perform additional checks for specialty types\n if (expectedType === 'string') {\n this.validateString(elementDefinition, type as PropertyType, value as string);\n } else if (expectedType === 'number') {\n this.validateNumber(elementDefinition, type as PropertyType, value as number);\n }\n }\n\n private validateString(elementDefinition: ElementDefinition, type: PropertyType, value: string): void {\n if (!value.trim()) {\n this.createIssue(elementDefinition, 'Invalid empty string');\n return;\n }\n\n // Try to get the regex\n const valueDefinition = globalSchema.types[type]?.properties?.['value'];\n if (valueDefinition?.type) {\n const regex = getExtensionValue(valueDefinition.type[0], 'http://hl7.org/fhir/StructureDefinition/regex');\n if (regex) {\n if (!value.match(new RegExp(regex))) {\n this.createIssue(elementDefinition, 'Invalid ' + type + ' format');\n }\n }\n }\n }\n\n private validateNumber(elementDefinition: ElementDefinition, type: PropertyType, value: number): void {\n if (isNaN(value) || !isFinite(value)) {\n this.createIssue(elementDefinition, 'Invalid ' + type + ' value');\n return;\n }\n\n if (isIntegerType(type) && !Number.isInteger(value)) {\n this.createIssue(elementDefinition, 'Number is not an integer');\n }\n\n if (type === PropertyType.positiveInt && value <= 0) {\n this.createIssue(elementDefinition, 'Number is less than or equal to zero');\n }\n\n if (type === PropertyType.unsignedInt && value < 0) {\n this.createIssue(elementDefinition, 'Number is negative');\n }\n }\n\n private checkAdditionalProperties(\n path: string,\n typedValue: TypedValue,\n propertyDefinitions: Record<string, ElementDefinition>\n ): void {\n const object = typedValue.value as Record<string, unknown>;\n for (const key of Object.keys(object)) {\n this.checkAdditionalProperty(path, key, typedValue, propertyDefinitions);\n }\n }\n\n /**\n * Checks if the given property is allowed on the given object.\n * @param path The path of the current object.\n * @param key The key of a property to check.\n * @param typedValue The current object.\n * @param propertyDefinitions The property definitions of the current object.\n */\n private checkAdditionalProperty(\n path: string,\n key: string,\n typedValue: TypedValue,\n propertyDefinitions: Record<string, ElementDefinition>\n ): void {\n if (\n !baseResourceProperties.has(key) &&\n !(key in propertyDefinitions) &&\n !isChoiceOfType(key, typedValue, propertyDefinitions) &&\n !this.checkPrimitiveElement(path, key, typedValue)\n ) {\n const expression = `${path}.${key}`;\n this.issues.push(createStructureIssue(expression, `Invalid additional property \"${expression}\"`));\n }\n }\n\n /**\n * Checks the element for a primitive.\n *\n * FHIR elements with primitive data types are represented in two parts:\n * 1) A JSON property with the name of the element, which has a JSON type of number, boolean, or string\n * 2) a JSON property with _ prepended to the name of the element, which, if present, contains the value's id and/or extensions\n *\n * See: https://hl7.org/fhir/json.html#primitive\n *\n * @param path The path to the property\n * @param key\n * @param typedValue\n */\n private checkPrimitiveElement(path: string, key: string, typedValue: TypedValue): boolean {\n // Primitive element starts with underscore\n if (!key.startsWith('_')) {\n return false;\n }\n\n // Validate the non-underscore property exists\n const primitiveKey = key.slice(1);\n if (!(primitiveKey in typedValue.value)) {\n return false;\n }\n\n // Then validate the element\n this.validateObject({ type: 'Element', value: typedValue.value[key] }, path);\n return true;\n }\n\n private createIssue(elementDefinition: ElementDefinition, message: string): void {\n this.issues.push(createStructureIssue(elementDefinition.path as string, message));\n }\n}\n\nfunction isIntegerType(propertyType: PropertyType): boolean {\n return (\n propertyType === PropertyType.integer ||\n propertyType === PropertyType.positiveInt ||\n propertyType === PropertyType.unsignedInt\n );\n}\n\nfunction isChoiceOfType(\n key: string,\n typedValue: TypedValue,\n propertyDefinitions: Record<string, ElementDefinition>\n): boolean {\n for (const propertyName of Object.keys(propertyDefinitions)) {\n if (!propertyName.endsWith('[x]')) {\n continue;\n }\n const basePropertyName = propertyName.replace('[x]', '');\n if (!key.startsWith(basePropertyName)) {\n continue;\n }\n let typedPropertyValue = getTypedPropertyValue(typedValue, propertyName);\n if (!typedPropertyValue) {\n continue;\n }\n if (Array.isArray(typedPropertyValue)) {\n // At present, there are no choice types that are arrays in the FHIR spec\n // Leaving this here to make TypeScript happy, and in case that changes\n typedPropertyValue = typedPropertyValue[0];\n }\n if (typedPropertyValue && key === basePropertyName + capitalize(typedPropertyValue.type)) {\n return true;\n }\n }\n return false;\n}\n\n/**\n * Recursively checks for null values in an object.\n *\n * Note that \"null\" is a special value in JSON that is not allowed in FHIR.\n *\n * @param value Input value of any type.\n * @param path Path string to the value for OperationOutcome.\n * @param issues Output list of issues.\n */\nexport function checkForNull(value: unknown, path: string, issues: OperationOutcomeIssue[]): void {\n if (value === null) {\n issues.push(createStructureIssue(path, 'Invalid null value'));\n } else if (Array.isArray(value)) {\n checkArrayForNull(value, path, issues);\n } else if (typeof value === 'object') {\n checkObjectForNull(value as Record<string, unknown>, path, issues);\n }\n}\n\nfunction checkArrayForNull(array: unknown[], path: string, issues: OperationOutcomeIssue[]): void {\n for (let i = 0; i < array.length; i++) {\n if (array[i] === undefined) {\n issues.push(createStructureIssue(`${path}[${i}]`, 'Invalid undefined value'));\n } else {\n checkForNull(array[i], `${path}[${i}]`, issues);\n }\n }\n}\n\nfunction checkObjectForNull(obj: Record<string, unknown>, path: string, issues: OperationOutcomeIssue[]): void {\n for (const [key, value] of Object.entries(obj)) {\n checkForNull(value, `${path}${path ? '.' : ''}${key}`, issues);\n }\n}\n\nexport function createStructureIssue(expression: string, details: string): OperationOutcomeIssue {\n return {\n severity: 'error',\n code: 'structure',\n details: {\n text: details,\n },\n expression: [expression],\n };\n}\n"],"names":[],"mappings":"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"}
|