@medplum/core 2.0.5 → 2.0.7

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 (48) hide show
  1. package/dist/cjs/index.cjs +872 -27
  2. package/dist/cjs/index.cjs.map +1 -1
  3. package/dist/cjs/index.min.cjs +1 -1
  4. package/dist/esm/client.mjs +7 -6
  5. package/dist/esm/client.mjs.map +1 -1
  6. package/dist/esm/fhirlexer/tokenize.mjs +13 -4
  7. package/dist/esm/fhirlexer/tokenize.mjs.map +1 -1
  8. package/dist/esm/fhirmapper/parse.mjs +317 -0
  9. package/dist/esm/fhirmapper/parse.mjs.map +1 -0
  10. package/dist/esm/fhirmapper/tokenize.mjs +15 -0
  11. package/dist/esm/fhirmapper/tokenize.mjs.map +1 -0
  12. package/dist/esm/fhirpath/atoms.mjs +2 -2
  13. package/dist/esm/fhirpath/atoms.mjs.map +1 -1
  14. package/dist/esm/fhirpath/functions.mjs +2 -2
  15. package/dist/esm/fhirpath/functions.mjs.map +1 -1
  16. package/dist/esm/fhirpath/utils.mjs +4 -4
  17. package/dist/esm/fhirpath/utils.mjs.map +1 -1
  18. package/dist/esm/filter/parse.mjs +51 -0
  19. package/dist/esm/filter/parse.mjs.map +1 -0
  20. package/dist/esm/filter/tokenize.mjs +18 -0
  21. package/dist/esm/filter/tokenize.mjs.map +1 -0
  22. package/dist/esm/filter/types.mjs +34 -0
  23. package/dist/esm/filter/types.mjs.map +1 -0
  24. package/dist/esm/index.min.mjs +1 -1
  25. package/dist/esm/index.mjs +8 -2
  26. package/dist/esm/index.mjs.map +1 -1
  27. package/dist/esm/node_modules/tslib/tslib.es6.mjs.map +1 -1
  28. package/dist/esm/outcomes.mjs +15 -1
  29. package/dist/esm/outcomes.mjs.map +1 -1
  30. package/dist/esm/schema.mjs +397 -0
  31. package/dist/esm/schema.mjs.map +1 -0
  32. package/dist/esm/search/details.mjs +1 -1
  33. package/dist/esm/search/details.mjs.map +1 -1
  34. package/dist/esm/types.mjs +34 -8
  35. package/dist/esm/types.mjs.map +1 -1
  36. package/dist/types/client.d.ts +20 -8
  37. package/dist/types/fhirlexer/tokenize.d.ts +5 -1
  38. package/dist/types/fhirmapper/index.d.ts +1 -0
  39. package/dist/types/filter/index.d.ts +2 -0
  40. package/dist/types/filter/parse.d.ts +7 -0
  41. package/dist/types/filter/tokenize.d.ts +2 -0
  42. package/dist/types/filter/types.d.ts +31 -0
  43. package/dist/types/index.d.ts +4 -0
  44. package/dist/types/outcomes.d.ts +1 -0
  45. package/dist/types/schema.d.ts +120 -0
  46. package/dist/types/types.d.ts +19 -5
  47. package/package.json +1 -1
  48. package/tsconfig.build.json +0 -9
@@ -1301,6 +1301,20 @@
1301
1301
  ],
1302
1302
  };
1303
1303
  }
1304
+ function validationError(details) {
1305
+ return {
1306
+ resourceType: 'OperationOutcome',
1307
+ issue: [
1308
+ {
1309
+ severity: 'error',
1310
+ code: 'structure',
1311
+ details: {
1312
+ text: details,
1313
+ },
1314
+ },
1315
+ ],
1316
+ };
1317
+ }
1304
1318
  function isOperationOutcome(value) {
1305
1319
  return typeof value === 'object' && value !== null && value.resourceType === 'OperationOutcome';
1306
1320
  }
@@ -6066,7 +6080,7 @@
6066
6080
  // First pass, build types
6067
6081
  elements.forEach((element) => indexType(structureDefinition, element));
6068
6082
  // Second pass, build properties
6069
- elements.forEach((element) => indexProperty(element));
6083
+ elements.forEach((element) => indexProperty(structureDefinition, element));
6070
6084
  }
6071
6085
  }
6072
6086
  /**
@@ -6084,6 +6098,9 @@
6084
6098
  return;
6085
6099
  }
6086
6100
  const parts = path.split('.');
6101
+ // Force the first part to be the type name
6102
+ // This is necessary for "SimpleQuantity" and "MoneyQuantity"
6103
+ parts[0] = structureDefinition.name;
6087
6104
  const typeName = buildTypeName(parts);
6088
6105
  let typeSchema = globalSchema.types[typeName];
6089
6106
  if (!typeSchema) {
@@ -6101,12 +6118,15 @@
6101
6118
  * @param element The input ElementDefinition.
6102
6119
  * @see {@link IndexedStructureDefinition} for more details on indexed StructureDefinitions.
6103
6120
  */
6104
- function indexProperty(element) {
6121
+ function indexProperty(structureDefinition, element) {
6105
6122
  const path = element.path;
6106
6123
  const parts = path.split('.');
6107
6124
  if (parts.length === 1) {
6108
6125
  return;
6109
6126
  }
6127
+ // Force the first part to be the type name
6128
+ // This is necessary for "SimpleQuantity" and "MoneyQuantity"
6129
+ parts[0] = structureDefinition.name;
6110
6130
  const typeName = buildTypeName(parts.slice(0, parts.length - 1));
6111
6131
  const typeSchema = globalSchema.types[typeName];
6112
6132
  if (!typeSchema) {
@@ -6210,12 +6230,16 @@
6210
6230
  return components.map(capitalize).join('');
6211
6231
  }
6212
6232
  /**
6213
- * Returns true if the type schema is a DomainResource.
6233
+ * Returns true if the type schema is a non-abstract FHIR resource.
6214
6234
  * @param typeSchema The type schema to check.
6215
- * @returns True if the type schema is a DomainResource.
6235
+ * @returns True if the type schema is a non-abstract FHIR resource.
6216
6236
  */
6217
- function isResourceType(typeSchema) {
6218
- return typeSchema.structureDefinition?.baseDefinition === 'http://hl7.org/fhir/StructureDefinition/DomainResource';
6237
+ function isResourceTypeSchema(typeSchema) {
6238
+ const structureDefinition = typeSchema.structureDefinition;
6239
+ return (structureDefinition &&
6240
+ structureDefinition.name === typeSchema.elementDefinition?.path &&
6241
+ structureDefinition.kind === 'resource' &&
6242
+ !structureDefinition.abstract);
6219
6243
  }
6220
6244
  /**
6221
6245
  * Returns an array of all resource types.
@@ -6225,7 +6249,7 @@
6225
6249
  function getResourceTypes() {
6226
6250
  const result = [];
6227
6251
  for (const [resourceType, typeSchema] of Object.entries(globalSchema.types)) {
6228
- if (isResourceType(typeSchema)) {
6252
+ if (isResourceTypeSchema(typeSchema)) {
6229
6253
  result.push(resourceType);
6230
6254
  }
6231
6255
  }
@@ -6304,6 +6328,22 @@
6304
6328
  }
6305
6329
  return property;
6306
6330
  }
6331
+ /**
6332
+ * Typeguard to validate that an object is a FHIR resource
6333
+ * @param value The object to check
6334
+ * @returns True if the input is of type 'object' and contains property 'resourceType'
6335
+ */
6336
+ function isResource(value) {
6337
+ return !!(value && typeof value === 'object' && 'resourceType' in value);
6338
+ }
6339
+ /**
6340
+ * Typeguard to validate that an object is a FHIR resource
6341
+ * @param value The object to check
6342
+ * @returns True if the input is of type 'object' and contains property 'reference'
6343
+ */
6344
+ function isReference(value) {
6345
+ return !!(value && typeof value === 'object' && 'reference' in value);
6346
+ }
6307
6347
  /**
6308
6348
  * Global schema singleton.
6309
6349
  */
@@ -6312,7 +6352,7 @@
6312
6352
  // PKCE auth based on:
6313
6353
  // https://aws.amazon.com/blogs/security/how-to-add-authentication-single-page-web-application-with-amazon-cognito-oauth2-implementation/
6314
6354
  var _MedplumClient_instances, _MedplumClient_fetch, _MedplumClient_createPdf, _MedplumClient_storage, _MedplumClient_requestCache, _MedplumClient_cacheTime, _MedplumClient_baseUrl, _MedplumClient_fhirBaseUrl, _MedplumClient_authorizeUrl, _MedplumClient_tokenUrl, _MedplumClient_logoutUrl, _MedplumClient_onUnauthenticated, _MedplumClient_autoBatchTime, _MedplumClient_autoBatchQueue, _MedplumClient_clientId, _MedplumClient_clientSecret, _MedplumClient_autoBatchTimerId, _MedplumClient_accessToken, _MedplumClient_refreshToken, _MedplumClient_refreshPromise, _MedplumClient_profilePromise, _MedplumClient_profile, _MedplumClient_config, _MedplumClient_addLogin, _MedplumClient_refreshProfile, _MedplumClient_getCacheEntry, _MedplumClient_setCacheEntry, _MedplumClient_cacheResource, _MedplumClient_deleteCacheEntry, _MedplumClient_request, _MedplumClient_fetchWithRetry, _MedplumClient_executeAutoBatch, _MedplumClient_addFetchOptionsDefaults, _MedplumClient_setRequestContentType, _MedplumClient_setRequestBody, _MedplumClient_handleUnauthenticated, _MedplumClient_requestAuthorization, _MedplumClient_refresh, _MedplumClient_fetchTokens, _MedplumClient_verifyTokens, _MedplumClient_setupStorageListener;
6315
- const MEDPLUM_VERSION = "2.0.5-886af1d8";
6355
+ const MEDPLUM_VERSION = "2.0.7-c59953c5";
6316
6356
  const DEFAULT_BASE_URL = 'https://api.medplum.com/';
6317
6357
  const DEFAULT_RESOURCE_CACHE_SIZE = 1000;
6318
6358
  const DEFAULT_CACHE_TIME = 60000; // 60 seconds
@@ -6769,13 +6809,14 @@
6769
6809
  * Builds a FHIR search URL from a search query or structured query object.
6770
6810
  * @category HTTP
6771
6811
  * @category Search
6772
- * @param query The FHIR search query or structured query object.
6812
+ * @param resourceType The FHIR resource type.
6813
+ * @param query The FHIR search query or structured query object. Can be any valid input to the URLSearchParams() constructor.
6773
6814
  * @returns The well-formed FHIR URL.
6774
6815
  */
6775
6816
  fhirSearchUrl(resourceType, query) {
6776
6817
  const url = this.fhirUrl(resourceType);
6777
6818
  if (query) {
6778
- url.search = query.toString();
6819
+ url.search = new URLSearchParams(query).toString();
6779
6820
  }
6780
6821
  return url;
6781
6822
  }
@@ -6823,7 +6864,7 @@
6823
6864
  *
6824
6865
  * @category Search
6825
6866
  * @param resourceType The FHIR resource type.
6826
- * @param query The search query as either a string or a structured search object.
6867
+ * @param query Optional FHIR search query or structured query object. Can be any valid input to the URLSearchParams() constructor.
6827
6868
  * @param options Optional fetch options.
6828
6869
  * @returns Promise to the search result bundle.
6829
6870
  */
@@ -6864,7 +6905,7 @@
6864
6905
  *
6865
6906
  * @category Search
6866
6907
  * @param resourceType The FHIR resource type.
6867
- * @param query The search query as either a string or a structured search object.
6908
+ * @param query Optional FHIR search query or structured query object. Can be any valid input to the URLSearchParams() constructor.
6868
6909
  * @param options Optional fetch options.
6869
6910
  * @returns Promise to the search result bundle.
6870
6911
  */
@@ -6899,7 +6940,7 @@
6899
6940
  *
6900
6941
  * @category Search
6901
6942
  * @param resourceType The FHIR resource type.
6902
- * @param query The search query as either a string or a structured search object.
6943
+ * @param query Optional FHIR search query or structured query object. Can be any valid input to the URLSearchParams() constructor.
6903
6944
  * @param options Optional fetch options.
6904
6945
  * @returns Promise to the search result bundle.
6905
6946
  */
@@ -8177,7 +8218,7 @@
8177
8218
  }
8178
8219
  _Parser_tokens = new WeakMap(), _Parser_prefixParselets = new WeakMap(), _Parser_infixParselets = new WeakMap();
8179
8220
 
8180
- var _Tokenizer_instances, _Tokenizer_str, _Tokenizer_keywords, _Tokenizer_operators, _Tokenizer_result, _Tokenizer_pos, _Tokenizer_markStack, _Tokenizer_prevToken, _Tokenizer_peekToken, _Tokenizer_consumeToken, _Tokenizer_consumeWhitespace, _Tokenizer_consumeMultiLineComment, _Tokenizer_consumeSingleLineComment, _Tokenizer_consumeString, _Tokenizer_consumeBacktickSymbol, _Tokenizer_consumeDateTime, _Tokenizer_consumeNumber, _Tokenizer_consumeSymbol, _Tokenizer_consumeOperator, _Tokenizer_consumeWhile, _Tokenizer_curr, _Tokenizer_prev, _Tokenizer_peek, _Tokenizer_mark, _Tokenizer_reset, _Tokenizer_advance, _Tokenizer_buildToken;
8221
+ var _Tokenizer_instances, _Tokenizer_str, _Tokenizer_keywords, _Tokenizer_operators, _Tokenizer_dateTimeLiterals, _Tokenizer_symbolRegex, _Tokenizer_result, _Tokenizer_pos, _Tokenizer_markStack, _Tokenizer_prevToken, _Tokenizer_peekToken, _Tokenizer_consumeToken, _Tokenizer_consumeWhitespace, _Tokenizer_consumeMultiLineComment, _Tokenizer_consumeSingleLineComment, _Tokenizer_consumeString, _Tokenizer_consumeBacktickSymbol, _Tokenizer_consumeDateTime, _Tokenizer_consumeNumber, _Tokenizer_consumeSymbol, _Tokenizer_consumeOperator, _Tokenizer_consumeWhile, _Tokenizer_curr, _Tokenizer_prev, _Tokenizer_peek, _Tokenizer_mark, _Tokenizer_reset, _Tokenizer_advance, _Tokenizer_buildToken;
8181
8222
  const STANDARD_UNITS = [
8182
8223
  'year',
8183
8224
  'years',
@@ -8197,17 +8238,21 @@
8197
8238
  'milliseconds',
8198
8239
  ];
8199
8240
  class Tokenizer {
8200
- constructor(str, keywords, operators) {
8241
+ constructor(str, keywords, operators, options) {
8201
8242
  _Tokenizer_instances.add(this);
8202
8243
  _Tokenizer_str.set(this, void 0);
8203
8244
  _Tokenizer_keywords.set(this, void 0);
8204
8245
  _Tokenizer_operators.set(this, void 0);
8246
+ _Tokenizer_dateTimeLiterals.set(this, void 0);
8247
+ _Tokenizer_symbolRegex.set(this, void 0);
8205
8248
  _Tokenizer_result.set(this, []);
8206
8249
  _Tokenizer_pos.set(this, { index: 0, line: 1, column: 0 });
8207
8250
  _Tokenizer_markStack.set(this, []);
8208
8251
  __classPrivateFieldSet(this, _Tokenizer_str, str, "f");
8209
8252
  __classPrivateFieldSet(this, _Tokenizer_keywords, keywords, "f");
8210
8253
  __classPrivateFieldSet(this, _Tokenizer_operators, operators, "f");
8254
+ __classPrivateFieldSet(this, _Tokenizer_dateTimeLiterals, !!options?.dateTimeLiterals, "f");
8255
+ __classPrivateFieldSet(this, _Tokenizer_symbolRegex, options?.symbolRegex ?? /[$\w]/, "f");
8211
8256
  }
8212
8257
  tokenize() {
8213
8258
  while (__classPrivateFieldGet(this, _Tokenizer_pos, "f").index < __classPrivateFieldGet(this, _Tokenizer_str, "f").length) {
@@ -8219,7 +8264,7 @@
8219
8264
  return __classPrivateFieldGet(this, _Tokenizer_result, "f");
8220
8265
  }
8221
8266
  }
8222
- _Tokenizer_str = new WeakMap(), _Tokenizer_keywords = new WeakMap(), _Tokenizer_operators = new WeakMap(), _Tokenizer_result = new WeakMap(), _Tokenizer_pos = new WeakMap(), _Tokenizer_markStack = new WeakMap(), _Tokenizer_instances = new WeakSet(), _Tokenizer_prevToken = function _Tokenizer_prevToken() {
8267
+ _Tokenizer_str = new WeakMap(), _Tokenizer_keywords = new WeakMap(), _Tokenizer_operators = new WeakMap(), _Tokenizer_dateTimeLiterals = new WeakMap(), _Tokenizer_symbolRegex = new WeakMap(), _Tokenizer_result = new WeakMap(), _Tokenizer_pos = new WeakMap(), _Tokenizer_markStack = new WeakMap(), _Tokenizer_instances = new WeakSet(), _Tokenizer_prevToken = function _Tokenizer_prevToken() {
8223
8268
  return __classPrivateFieldGet(this, _Tokenizer_result, "f").slice(-1)[0];
8224
8269
  }, _Tokenizer_peekToken = function _Tokenizer_peekToken() {
8225
8270
  __classPrivateFieldGet(this, _Tokenizer_instances, "m", _Tokenizer_mark).call(this);
@@ -8307,6 +8352,11 @@
8307
8352
  __classPrivateFieldGet(this, _Tokenizer_instances, "m", _Tokenizer_advance).call(this);
8308
8353
  __classPrivateFieldGet(this, _Tokenizer_instances, "m", _Tokenizer_consumeWhile).call(this, () => __classPrivateFieldGet(this, _Tokenizer_instances, "m", _Tokenizer_curr).call(this).match(/\d/));
8309
8354
  }
8355
+ if (__classPrivateFieldGet(this, _Tokenizer_instances, "m", _Tokenizer_curr).call(this) === '-' && __classPrivateFieldGet(this, _Tokenizer_dateTimeLiterals, "f")) {
8356
+ // Rewind to one character before the start, and then treat as dateTime literal.
8357
+ __classPrivateFieldGet(this, _Tokenizer_pos, "f").index = start - 1;
8358
+ return __classPrivateFieldGet(this, _Tokenizer_instances, "m", _Tokenizer_consumeDateTime).call(this);
8359
+ }
8310
8360
  if (__classPrivateFieldGet(this, _Tokenizer_instances, "m", _Tokenizer_curr).call(this) === ' ') {
8311
8361
  if (isUnitToken(__classPrivateFieldGet(this, _Tokenizer_instances, "m", _Tokenizer_peekToken).call(this))) {
8312
8362
  id = 'Quantity';
@@ -8315,7 +8365,7 @@
8315
8365
  }
8316
8366
  return __classPrivateFieldGet(this, _Tokenizer_instances, "m", _Tokenizer_buildToken).call(this, id, __classPrivateFieldGet(this, _Tokenizer_str, "f").substring(start, __classPrivateFieldGet(this, _Tokenizer_pos, "f").index));
8317
8367
  }, _Tokenizer_consumeSymbol = function _Tokenizer_consumeSymbol() {
8318
- const value = __classPrivateFieldGet(this, _Tokenizer_instances, "m", _Tokenizer_consumeWhile).call(this, () => __classPrivateFieldGet(this, _Tokenizer_instances, "m", _Tokenizer_curr).call(this).match(/[$\w]/));
8368
+ const value = __classPrivateFieldGet(this, _Tokenizer_instances, "m", _Tokenizer_consumeWhile).call(this, () => __classPrivateFieldGet(this, _Tokenizer_instances, "m", _Tokenizer_curr).call(this).match(__classPrivateFieldGet(this, _Tokenizer_symbolRegex, "f")));
8319
8369
  if (__classPrivateFieldGet(this, _Tokenizer_instances, "m", _Tokenizer_prevToken).call(this)?.value !== '.' && __classPrivateFieldGet(this, _Tokenizer_keywords, "f").includes(value)) {
8320
8370
  return __classPrivateFieldGet(this, _Tokenizer_instances, "m", _Tokenizer_buildToken).call(this, value, value);
8321
8371
  }
@@ -8439,7 +8489,7 @@
8439
8489
  else if (isQuantity(value)) {
8440
8490
  return { type: exports.PropertyType.Quantity, value };
8441
8491
  }
8442
- else if (typeof value === 'object' && 'resourceType' in value) {
8492
+ else if (isResource(value)) {
8443
8493
  return { type: value.resourceType, value };
8444
8494
  }
8445
8495
  else {
@@ -8521,7 +8571,7 @@
8521
8571
  }
8522
8572
  }
8523
8573
  function toTypedValueWithType(value, type) {
8524
- if (type === 'Resource' && typeof value === 'object' && 'resourceType' in value) {
8574
+ if (type === 'Resource' && isResource(value)) {
8525
8575
  type = value.resourceType;
8526
8576
  }
8527
8577
  return { type, value };
@@ -8548,7 +8598,7 @@
8548
8598
  // Examples:
8549
8599
  // value + valueString = ok, because "string" is valid
8550
8600
  // value + valueDecimal = ok, because "decimal" is valid
8551
- // id + identifiier = not ok, because "entifier" is not a valid type
8601
+ // id + identifier = not ok, because "entifier" is not a valid type
8552
8602
  // resource + resourceType = not ok, because "type" is not a valid type
8553
8603
  for (const propertyType in exports.PropertyType) {
8554
8604
  const propertyName = path + capitalize(propertyType);
@@ -10203,7 +10253,7 @@
10203
10253
  if (typeof value === 'number') {
10204
10254
  return { type: exports.PropertyType.BackboneElement, value: { namespace: 'System', name: 'Integer' } };
10205
10255
  }
10206
- if (value && typeof value === 'object' && 'resourceType' in value) {
10256
+ if (isResource(value)) {
10207
10257
  return {
10208
10258
  type: exports.PropertyType.BackboneElement,
10209
10259
  value: { namespace: 'FHIR', name: value.resourceType },
@@ -10332,7 +10382,7 @@
10332
10382
  if (!input || typeof input !== 'object') {
10333
10383
  return undefined;
10334
10384
  }
10335
- if ('resourceType' in input && input.resourceType === this.name) {
10385
+ if (isResource(input) && input.resourceType === this.name) {
10336
10386
  return typedValue;
10337
10387
  }
10338
10388
  return getTypedPropertyValue(typedValue, this.name);
@@ -10611,7 +10661,7 @@
10611
10661
 
10612
10662
  const FHIRPATH_KEYWORDS = ['true', 'false'];
10613
10663
  const FHIRPATH_OPERATORS = ['!=', '!~', '<=', '>=', '{}', '->'];
10614
- function tokenize(str) {
10664
+ function tokenize$2(str) {
10615
10665
  return new Tokenizer(str, FHIRPATH_KEYWORDS, FHIRPATH_OPERATORS).tokenize();
10616
10666
  }
10617
10667
 
@@ -10708,7 +10758,7 @@
10708
10758
  .infixLeft('or', 6 /* OperatorPrecedence.Is */, (left, _, right) => new OrAtom(left, right))
10709
10759
  .infixLeft('xor', 6 /* OperatorPrecedence.Is */, (left, _, right) => new XorAtom(left, right));
10710
10760
  }
10711
- const fhirPathParserBuilder = initFhirPathParserBuilder();
10761
+ const fhirPathParserBuilder$2 = initFhirPathParserBuilder();
10712
10762
  /**
10713
10763
  * Parses a FHIRPath expression into an AST.
10714
10764
  * The result can be used to evaluate the expression against a resource or other object.
@@ -10718,7 +10768,7 @@
10718
10768
  * @returns The AST representing the expression.
10719
10769
  */
10720
10770
  function parseFhirPath(input) {
10721
- return new FhirPathAtom(input, fhirPathParserBuilder.construct(tokenize(input)).consumeAndParse());
10771
+ return new FhirPathAtom(input, fhirPathParserBuilder$2.construct(tokenize$2(input)).consumeAndParse());
10722
10772
  }
10723
10773
  /**
10724
10774
  * Evaluates a FHIRPath expression against a resource or other object.
@@ -10748,6 +10798,397 @@
10748
10798
  return parseFhirPath(expression).eval(input);
10749
10799
  }
10750
10800
 
10801
+ const MAPPING_LANGUAGE_OPERATORS$1 = [...FHIRPATH_OPERATORS, '->', '<<', '>>'];
10802
+ function tokenize$1(str) {
10803
+ return new Tokenizer(str, FHIRPATH_KEYWORDS, MAPPING_LANGUAGE_OPERATORS$1).tokenize();
10804
+ }
10805
+
10806
+ var _StructureMapParser_instances, _StructureMapParser_parseUses, _StructureMapParser_parseImport, _StructureMapParser_parseGroup, _StructureMapParser_parseParameters, _StructureMapParser_parseParameter, _StructureMapParser_parseRules, _StructureMapParser_parseRule, _StructureMapParser_parseRuleSources, _StructureMapParser_parseRuleSource, _StructureMapParser_parseRuleTargets, _StructureMapParser_parseRuleTarget, _StructureMapParser_parseRuleTargetTransform, _StructureMapParser_parseRuleTargetSymbol, _StructureMapParser_parseRuleTargetFunction, _StructureMapParser_parseRuleTargetLiteral, _StructureMapParser_parseRuleContext, _StructureMapParser_parseRuleDependents, _StructureMapParser_parseConceptMap;
10807
+ class StructureMapParser {
10808
+ constructor(parser) {
10809
+ this.parser = parser;
10810
+ _StructureMapParser_instances.add(this);
10811
+ this.structureMap = { resourceType: 'StructureMap' };
10812
+ }
10813
+ parse() {
10814
+ // 'map' url '=' identifier
10815
+ // map "http://hl7.org/fhir/StructureMap/tutorial" = tutorial
10816
+ this.parser.consume('Symbol', 'map');
10817
+ this.structureMap.url = this.parser.consume('String').value;
10818
+ this.parser.consume('=');
10819
+ this.structureMap.name = this.parser.consume().value;
10820
+ while (this.parser.hasMore()) {
10821
+ const next = this.parser.peek()?.value;
10822
+ switch (next) {
10823
+ case 'uses':
10824
+ __classPrivateFieldGet(this, _StructureMapParser_instances, "m", _StructureMapParser_parseUses).call(this);
10825
+ break;
10826
+ case 'imports':
10827
+ __classPrivateFieldGet(this, _StructureMapParser_instances, "m", _StructureMapParser_parseImport).call(this);
10828
+ break;
10829
+ case 'group':
10830
+ __classPrivateFieldGet(this, _StructureMapParser_instances, "m", _StructureMapParser_parseGroup).call(this);
10831
+ break;
10832
+ case 'conceptmap':
10833
+ __classPrivateFieldGet(this, _StructureMapParser_instances, "m", _StructureMapParser_parseConceptMap).call(this);
10834
+ break;
10835
+ default:
10836
+ throw new Error(`Unexpected token: ${next}`);
10837
+ }
10838
+ }
10839
+ return this.structureMap;
10840
+ }
10841
+ }
10842
+ _StructureMapParser_instances = new WeakSet(), _StructureMapParser_parseUses = function _StructureMapParser_parseUses() {
10843
+ // 'uses' url structureAlias? 'as' modelMode
10844
+ // uses "http://hl7.org/fhir/StructureDefinition/tutorial-left" as source
10845
+ this.parser.consume('Symbol', 'uses');
10846
+ const result = {};
10847
+ result.url = this.parser.consume('String').value;
10848
+ if (this.parser.peek()?.value === 'alias') {
10849
+ this.parser.consume('Symbol', 'alias');
10850
+ result.alias = this.parser.consume('Symbol').value;
10851
+ }
10852
+ this.parser.consume('Symbol', 'as');
10853
+ result.mode = this.parser.consume().value;
10854
+ if (!this.structureMap.structure) {
10855
+ this.structureMap.structure = [];
10856
+ }
10857
+ this.structureMap.structure.push(result);
10858
+ }, _StructureMapParser_parseImport = function _StructureMapParser_parseImport() {
10859
+ this.parser.consume('Symbol', 'imports');
10860
+ if (!this.structureMap.import) {
10861
+ this.structureMap.import = [];
10862
+ }
10863
+ this.structureMap.import.push(this.parser.consume('String').value);
10864
+ }, _StructureMapParser_parseGroup = function _StructureMapParser_parseGroup() {
10865
+ // 'group' identifier parameters extends? typeMode? rules
10866
+ // group tutorial(source src : TLeft, target tgt : TRight) {
10867
+ const result = {};
10868
+ this.parser.consume('Symbol', 'group');
10869
+ result.name = this.parser.consume('Symbol').value;
10870
+ result.input = __classPrivateFieldGet(this, _StructureMapParser_instances, "m", _StructureMapParser_parseParameters).call(this);
10871
+ if (this.parser.peek()?.value === 'extends') {
10872
+ this.parser.consume('Symbol', 'extends');
10873
+ result.extends = this.parser.consume('Symbol').value;
10874
+ }
10875
+ if (this.parser.peek()?.value === '<<') {
10876
+ this.parser.consume('<<');
10877
+ result.typeMode = this.parser.consume().value;
10878
+ if (this.parser.peek()?.value === '+') {
10879
+ this.parser.consume('+');
10880
+ result.typeMode = 'type-and-types';
10881
+ }
10882
+ this.parser.consume('>>');
10883
+ }
10884
+ else {
10885
+ result.typeMode = 'none';
10886
+ }
10887
+ result.rule = __classPrivateFieldGet(this, _StructureMapParser_instances, "m", _StructureMapParser_parseRules).call(this);
10888
+ if (!this.structureMap.group) {
10889
+ this.structureMap.group = [];
10890
+ }
10891
+ this.structureMap.group.push(result);
10892
+ }, _StructureMapParser_parseParameters = function _StructureMapParser_parseParameters() {
10893
+ const parameters = [];
10894
+ this.parser.consume('(');
10895
+ while (this.parser.hasMore() && this.parser.peek()?.value !== ')') {
10896
+ parameters.push(__classPrivateFieldGet(this, _StructureMapParser_instances, "m", _StructureMapParser_parseParameter).call(this));
10897
+ if (this.parser.peek()?.value === ',') {
10898
+ this.parser.consume(',');
10899
+ }
10900
+ }
10901
+ this.parser.consume(')');
10902
+ return parameters;
10903
+ }, _StructureMapParser_parseParameter = function _StructureMapParser_parseParameter() {
10904
+ // inputMode identifier type?
10905
+ // ':' identifier
10906
+ // source src : TLeft
10907
+ const result = {};
10908
+ result.mode = this.parser.consume().value;
10909
+ result.name = this.parser.consume('Symbol').value;
10910
+ if (this.parser.peek()?.value === ':') {
10911
+ this.parser.consume(':');
10912
+ result.type = this.parser.consume('Symbol').value;
10913
+ }
10914
+ return result;
10915
+ }, _StructureMapParser_parseRules = function _StructureMapParser_parseRules() {
10916
+ const rules = [];
10917
+ this.parser.consume('{');
10918
+ while (this.parser.hasMore() && this.parser.peek()?.value !== '}') {
10919
+ rules.push(__classPrivateFieldGet(this, _StructureMapParser_instances, "m", _StructureMapParser_parseRule).call(this));
10920
+ }
10921
+ this.parser.consume('}');
10922
+ return rules;
10923
+ }, _StructureMapParser_parseRule = function _StructureMapParser_parseRule() {
10924
+ const result = {
10925
+ source: __classPrivateFieldGet(this, _StructureMapParser_instances, "m", _StructureMapParser_parseRuleSources).call(this),
10926
+ };
10927
+ if (this.parser.peek()?.value === '->') {
10928
+ this.parser.consume('->');
10929
+ result.target = __classPrivateFieldGet(this, _StructureMapParser_instances, "m", _StructureMapParser_parseRuleTargets).call(this);
10930
+ }
10931
+ if (this.parser.peek()?.value === 'then') {
10932
+ this.parser.consume('Symbol', 'then');
10933
+ if (this.parser.peek()?.id === '{') {
10934
+ result.rule = __classPrivateFieldGet(this, _StructureMapParser_instances, "m", _StructureMapParser_parseRules).call(this);
10935
+ }
10936
+ else {
10937
+ result.dependent = __classPrivateFieldGet(this, _StructureMapParser_instances, "m", _StructureMapParser_parseRuleDependents).call(this);
10938
+ }
10939
+ }
10940
+ if (this.parser.peek()?.id === 'String') {
10941
+ result.name = this.parser.consume().value;
10942
+ }
10943
+ else {
10944
+ result.name = result.source?.[0]?.element;
10945
+ }
10946
+ this.parser.consume(';');
10947
+ return result;
10948
+ }, _StructureMapParser_parseRuleSources = function _StructureMapParser_parseRuleSources() {
10949
+ const sources = [__classPrivateFieldGet(this, _StructureMapParser_instances, "m", _StructureMapParser_parseRuleSource).call(this)];
10950
+ while (this.parser.hasMore() && this.parser.peek()?.value === ',') {
10951
+ this.parser.consume(',');
10952
+ sources.push(__classPrivateFieldGet(this, _StructureMapParser_instances, "m", _StructureMapParser_parseRuleSource).call(this));
10953
+ }
10954
+ return sources;
10955
+ }, _StructureMapParser_parseRuleSource = function _StructureMapParser_parseRuleSource() {
10956
+ const result = {};
10957
+ const context = __classPrivateFieldGet(this, _StructureMapParser_instances, "m", _StructureMapParser_parseRuleContext).call(this);
10958
+ if (context.includes('.')) {
10959
+ const parts = context.split('.');
10960
+ result.context = parts[0];
10961
+ result.element = parts[1];
10962
+ }
10963
+ else {
10964
+ result.context = context;
10965
+ }
10966
+ if (this.parser.hasMore() && this.parser.peek()?.value === ':') {
10967
+ this.parser.consume(':');
10968
+ result.type = this.parser.consume().value;
10969
+ }
10970
+ if (this.parser.hasMore() && this.parser.peek()?.value === 'default') {
10971
+ this.parser.consume('default');
10972
+ this.parser.consumeAndParse();
10973
+ }
10974
+ if (this.parser.peek()?.value === 'first' ||
10975
+ this.parser.peek()?.value === 'not_first' ||
10976
+ this.parser.peek()?.value === 'last' ||
10977
+ this.parser.peek()?.value === 'not_last' ||
10978
+ this.parser.peek()?.value === 'only_one') {
10979
+ result.listMode = this.parser.consume().value;
10980
+ }
10981
+ if (this.parser.peek()?.value === 'as') {
10982
+ this.parser.consume('Symbol', 'as');
10983
+ result.variable = this.parser.consume().value;
10984
+ }
10985
+ if (this.parser.peek()?.value === 'where') {
10986
+ this.parser.consume('Symbol', 'where');
10987
+ const whereFhirPath = this.parser.consumeAndParse(100 /* OperatorPrecedence.Arrow */);
10988
+ result.condition = whereFhirPath.toString();
10989
+ }
10990
+ if (this.parser.peek()?.value === 'check') {
10991
+ this.parser.consume('Symbol', 'check');
10992
+ const checkFhirPath = this.parser.consumeAndParse(100 /* OperatorPrecedence.Arrow */);
10993
+ result.check = checkFhirPath.toString();
10994
+ }
10995
+ return result;
10996
+ }, _StructureMapParser_parseRuleTargets = function _StructureMapParser_parseRuleTargets() {
10997
+ const targets = [__classPrivateFieldGet(this, _StructureMapParser_instances, "m", _StructureMapParser_parseRuleTarget).call(this)];
10998
+ while (this.parser.hasMore() && this.parser.peek()?.value === ',') {
10999
+ this.parser.consume(',');
11000
+ targets.push(__classPrivateFieldGet(this, _StructureMapParser_instances, "m", _StructureMapParser_parseRuleTarget).call(this));
11001
+ }
11002
+ return targets;
11003
+ }, _StructureMapParser_parseRuleTarget = function _StructureMapParser_parseRuleTarget() {
11004
+ const result = {};
11005
+ const context = __classPrivateFieldGet(this, _StructureMapParser_instances, "m", _StructureMapParser_parseRuleContext).call(this);
11006
+ if (context.includes('.')) {
11007
+ const parts = context.split('.');
11008
+ result.contextType = 'variable';
11009
+ result.context = parts[0];
11010
+ result.element = parts[1];
11011
+ }
11012
+ else {
11013
+ result.context = context;
11014
+ }
11015
+ if (this.parser.peek()?.value === '=') {
11016
+ this.parser.consume('=');
11017
+ __classPrivateFieldGet(this, _StructureMapParser_instances, "m", _StructureMapParser_parseRuleTargetTransform).call(this, result);
11018
+ }
11019
+ if (this.parser.peek()?.value === 'as') {
11020
+ this.parser.consume('Symbol', 'as');
11021
+ result.variable = this.parser.consume().value;
11022
+ }
11023
+ if (this.parser.peek()?.value === 'first' ||
11024
+ this.parser.peek()?.value === 'share' ||
11025
+ this.parser.peek()?.value === 'last' ||
11026
+ this.parser.peek()?.value === 'collate') {
11027
+ result.listMode = [this.parser.consume().value];
11028
+ }
11029
+ return result;
11030
+ }, _StructureMapParser_parseRuleTargetTransform = function _StructureMapParser_parseRuleTargetTransform(result) {
11031
+ result.transform = 'copy';
11032
+ const transformFhirPath = this.parser.consumeAndParse(6 /* OperatorPrecedence.As */);
11033
+ if (transformFhirPath instanceof SymbolAtom) {
11034
+ __classPrivateFieldGet(this, _StructureMapParser_instances, "m", _StructureMapParser_parseRuleTargetSymbol).call(this, result, transformFhirPath);
11035
+ }
11036
+ else if (transformFhirPath instanceof FunctionAtom) {
11037
+ __classPrivateFieldGet(this, _StructureMapParser_instances, "m", _StructureMapParser_parseRuleTargetFunction).call(this, result, transformFhirPath);
11038
+ }
11039
+ else if (transformFhirPath instanceof LiteralAtom) {
11040
+ __classPrivateFieldGet(this, _StructureMapParser_instances, "m", _StructureMapParser_parseRuleTargetLiteral).call(this, result, transformFhirPath);
11041
+ }
11042
+ else {
11043
+ throw new Error(`Unexpected FHIRPath: ${transformFhirPath}`);
11044
+ }
11045
+ }, _StructureMapParser_parseRuleTargetSymbol = function _StructureMapParser_parseRuleTargetSymbol(result, literalAtom) {
11046
+ result.parameter = [{ valueId: literalAtom.name }];
11047
+ }, _StructureMapParser_parseRuleTargetFunction = function _StructureMapParser_parseRuleTargetFunction(result, functionAtom) {
11048
+ const functionName = functionAtom.name;
11049
+ switch (functionName) {
11050
+ case 'create':
11051
+ result.parameter = [
11052
+ {
11053
+ valueString: (functionAtom.args?.[0]).value.value,
11054
+ },
11055
+ ];
11056
+ break;
11057
+ case 'translate':
11058
+ result.parameter = [{}];
11059
+ break;
11060
+ default:
11061
+ throw new Error('Unknown target function: ' + functionName);
11062
+ }
11063
+ }, _StructureMapParser_parseRuleTargetLiteral = function _StructureMapParser_parseRuleTargetLiteral(result, literalAtom) {
11064
+ switch (literalAtom.value.type) {
11065
+ case 'boolean':
11066
+ result.parameter = [{ valueBoolean: literalAtom.value.value }];
11067
+ break;
11068
+ case 'decimal':
11069
+ result.parameter = [{ valueDecimal: literalAtom.value.value }];
11070
+ break;
11071
+ case 'string':
11072
+ result.parameter = [{ valueString: literalAtom.value.value }];
11073
+ break;
11074
+ default:
11075
+ throw new Error('Unknown target literal type: ' + literalAtom.value.type);
11076
+ }
11077
+ }, _StructureMapParser_parseRuleContext = function _StructureMapParser_parseRuleContext() {
11078
+ let identifier = this.parser.consume().value;
11079
+ while (this.parser.peek()?.value === '.') {
11080
+ this.parser.consume('.');
11081
+ identifier += '.' + this.parser.consume().value;
11082
+ }
11083
+ return identifier;
11084
+ }, _StructureMapParser_parseRuleDependents = function _StructureMapParser_parseRuleDependents() {
11085
+ const atom = this.parser.consumeAndParse(100 /* OperatorPrecedence.Arrow */);
11086
+ return [
11087
+ {
11088
+ name: atom.name,
11089
+ variable: atom.args.map((arg) => arg.name),
11090
+ },
11091
+ ];
11092
+ }, _StructureMapParser_parseConceptMap = function _StructureMapParser_parseConceptMap() {
11093
+ while (this.parser.peek()?.value !== '}') {
11094
+ this.parser.consume();
11095
+ }
11096
+ this.parser.consume('}');
11097
+ };
11098
+ const fhirPathParserBuilder$1 = initFhirPathParserBuilder()
11099
+ .registerInfix('->', { precedence: 100 /* OperatorPrecedence.Arrow */ })
11100
+ .registerInfix(';', { precedence: 200 /* OperatorPrecedence.Semicolon */ });
11101
+ /**
11102
+ * Parses a FHIR Mapping Language document into an AST.
11103
+ * @param input The FHIR Mapping Language document to parse.
11104
+ * @returns The AST representing the document.
11105
+ */
11106
+ function parseMappingLanguage(input) {
11107
+ const parser = fhirPathParserBuilder$1.construct(tokenize$1(input));
11108
+ parser.removeComments();
11109
+ return new StructureMapParser(parser).parse();
11110
+ }
11111
+
11112
+ const MAPPING_LANGUAGE_OPERATORS = [...FHIRPATH_OPERATORS, 'eq', 'ne', 'co'];
11113
+ function tokenize(str) {
11114
+ return new Tokenizer(str, FHIRPATH_KEYWORDS, MAPPING_LANGUAGE_OPERATORS, {
11115
+ dateTimeLiterals: true,
11116
+ symbolRegex: /[^\s\])]/,
11117
+ }).tokenize();
11118
+ }
11119
+
11120
+ // See: https://hl7.org/fhir/search_filter.html
11121
+ /**
11122
+ * The FhirFilterComparison class represents a comparison expression.
11123
+ */
11124
+ class FhirFilterComparison {
11125
+ constructor(path, operator, value) {
11126
+ this.path = path;
11127
+ this.operator = operator;
11128
+ this.value = value;
11129
+ }
11130
+ }
11131
+ /**
11132
+ * The FhirFilterNegation class represents a negation expression.
11133
+ * It contains a single child expression.
11134
+ */
11135
+ class FhirFilterNegation {
11136
+ constructor(child) {
11137
+ this.child = child;
11138
+ }
11139
+ }
11140
+ /**
11141
+ * The FhirFilterConnective class represents a connective expression.
11142
+ * It contains a list of child expressions.
11143
+ */
11144
+ class FhirFilterConnective {
11145
+ constructor(keyword, left, right) {
11146
+ this.keyword = keyword;
11147
+ this.left = left;
11148
+ this.right = right;
11149
+ }
11150
+ }
11151
+
11152
+ class FilterParameterParser {
11153
+ constructor(parser) {
11154
+ this.parser = parser;
11155
+ }
11156
+ parse() {
11157
+ let result;
11158
+ if (this.parser.peek()?.value === '(') {
11159
+ this.parser.consume('(');
11160
+ result = this.parse();
11161
+ this.parser.consume(')');
11162
+ }
11163
+ else if (this.parser.peek()?.value === 'not') {
11164
+ this.parser.consume('Symbol', 'not');
11165
+ this.parser.consume('(');
11166
+ result = new FhirFilterNegation(this.parse());
11167
+ this.parser.consume(')');
11168
+ }
11169
+ else {
11170
+ result = new FhirFilterComparison(this.parser.consume('Symbol').value, this.parser.consume('Symbol').value, this.parser.consume().value);
11171
+ }
11172
+ const next = this.parser.peek()?.value;
11173
+ if (next === 'and' || next === 'or') {
11174
+ this.parser.consume('Symbol', next);
11175
+ return new FhirFilterConnective(next, result, this.parse());
11176
+ }
11177
+ return result;
11178
+ }
11179
+ }
11180
+ const fhirPathParserBuilder = initFhirPathParserBuilder();
11181
+ /**
11182
+ * Parses a FHIR _filter parameter expression into an AST.
11183
+ * @param input The FHIR _filter parameter expression.
11184
+ * @returns The AST representing the filters.
11185
+ */
11186
+ function parseFilterParameter(input) {
11187
+ const parser = fhirPathParserBuilder.construct(tokenize(input));
11188
+ parser.removeComments();
11189
+ return new FilterParameterParser(parser).parse();
11190
+ }
11191
+
10751
11192
  /**
10752
11193
  * The Hl7Context class represents the parsing context for an HL7 message.
10753
11194
  *
@@ -10964,6 +11405,391 @@
10964
11405
  }
10965
11406
  }
10966
11407
 
11408
+ 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;
11409
+ /*
11410
+ * This file provides schema validation utilities for FHIR JSON objects.
11411
+ *
11412
+ * See: [JSON Representation of Resources](https://hl7.org/fhir/json.html)
11413
+ * See: [FHIR Data Types](https://www.hl7.org/fhir/datatypes.html)
11414
+ */
11415
+ const fhirTypeToJsType = {
11416
+ base64Binary: 'string',
11417
+ boolean: 'boolean',
11418
+ canonical: 'string',
11419
+ code: 'string',
11420
+ date: 'string',
11421
+ dateTime: 'string',
11422
+ decimal: 'number',
11423
+ id: 'string',
11424
+ instant: 'string',
11425
+ integer: 'number',
11426
+ markdown: 'string',
11427
+ oid: 'string',
11428
+ positiveInt: 'number',
11429
+ string: 'string',
11430
+ time: 'string',
11431
+ unsignedInt: 'number',
11432
+ uri: 'string',
11433
+ url: 'string',
11434
+ uuid: 'string',
11435
+ xhtml: 'string',
11436
+ 'http://hl7.org/fhirpath/System.String': 'string',
11437
+ };
11438
+ const baseResourceProperties = new Set([
11439
+ // Resource
11440
+ 'resourceType',
11441
+ 'id',
11442
+ 'meta',
11443
+ 'implicitRules',
11444
+ 'language',
11445
+ // DomainResource
11446
+ 'text',
11447
+ 'contained',
11448
+ 'extension',
11449
+ 'modifierExtension',
11450
+ ]);
11451
+ /**
11452
+ * Returns true if the given string is a valid FHIR resource type.
11453
+ *
11454
+ * ```ts
11455
+ * isResourceType('Patient'); // true
11456
+ * isResourceType('XYZ'); // false
11457
+ * ```
11458
+ *
11459
+ * Note that this depends on globalSchema, which is populated by the StructureDefinition loader.
11460
+ *
11461
+ * In a server context, you can load all schema definitions:
11462
+ *
11463
+ * ```ts
11464
+ * import { indexStructureDefinitionBundle } from '@medplum/core';
11465
+ * import { readJson } from '@medplum/definitions';
11466
+ * import { Bundle } from '@medplum/fhirtypes';
11467
+ *
11468
+ * indexStructureDefinitionBundle(readJson('fhir/r4/profiles-resources.json') as Bundle);
11469
+ * ```
11470
+ *
11471
+ * In a client context, you can load the schema definitions using MedplumClient:
11472
+ *
11473
+ * ```ts
11474
+ * import { MedplumClient } from '@medplum/core';
11475
+ *
11476
+ * const medplum = new MedplumClient();
11477
+ * await medplum.requestSchema('Patient');
11478
+ * ```
11479
+ *
11480
+ * @param resourceType The candidate resource type string.
11481
+ * @returns True if the resource type is a valid FHIR resource type.
11482
+ */
11483
+ function isResourceType(resourceType) {
11484
+ const typeSchema = globalSchema.types[resourceType];
11485
+ return (typeSchema &&
11486
+ typeSchema.structureDefinition.id === resourceType &&
11487
+ typeSchema.structureDefinition.kind === 'resource');
11488
+ }
11489
+ /**
11490
+ * Validates that the given string is a valid FHIR resource type.
11491
+ * On success, silently returns void.
11492
+ * On failure, throws an OperationOutcomeError.
11493
+ *
11494
+ * ```ts
11495
+ * validateResourceType('Patient'); // nothing
11496
+ * validateResourceType('XYZ'); // throws OperationOutcomeError
11497
+ * ```
11498
+ *
11499
+ * Note that this depends on globalSchema, which is populated by the StructureDefinition loader.
11500
+ *
11501
+ * In a server context, you can load all schema definitions:
11502
+ *
11503
+ * ```ts
11504
+ * import { indexStructureDefinitionBundle } from '@medplum/core';
11505
+ * import { readJson } from '@medplum/definitions';
11506
+ * import { Bundle } from '@medplum/fhirtypes';
11507
+ *
11508
+ * indexStructureDefinitionBundle(readJson('fhir/r4/profiles-resources.json') as Bundle);
11509
+ * ```
11510
+ *
11511
+ * In a client context, you can load the schema definitions using MedplumClient:
11512
+ *
11513
+ * ```ts
11514
+ * import { MedplumClient } from '@medplum/core';
11515
+ *
11516
+ * const medplum = new MedplumClient();
11517
+ * await medplum.requestSchema('Patient');
11518
+ * ```
11519
+ *
11520
+ * @param resourceType The candidate resource type string.
11521
+ * @returns True if the resource type is a valid FHIR resource type.
11522
+ */
11523
+ function validateResourceType(resourceType) {
11524
+ if (!resourceType) {
11525
+ throw new OperationOutcomeError(validationError('Resource type is null'));
11526
+ }
11527
+ if (!isResourceType(resourceType)) {
11528
+ throw new OperationOutcomeError(validationError('Unknown resource type'));
11529
+ }
11530
+ }
11531
+ /**
11532
+ * Validates a candidate FHIR resource object.
11533
+ * On success, silently returns void.
11534
+ * On failure, throws an OperationOutcomeError with issues for each violation.
11535
+ *
11536
+ * ```ts
11537
+ * validateResource({ resourceType: 'Patient' }); // nothing
11538
+ * validateResource({ resourceType: 'XYZ' }); // throws OperationOutcomeError
11539
+ * ```
11540
+ *
11541
+ * Note that this depends on globalSchema, which is populated by the StructureDefinition loader.
11542
+ *
11543
+ * In a server context, you can load all schema definitions:
11544
+ *
11545
+ * ```ts
11546
+ * import { indexStructureDefinitionBundle } from '@medplum/core';
11547
+ * import { readJson } from '@medplum/definitions';
11548
+ * import { Bundle } from '@medplum/fhirtypes';
11549
+ *
11550
+ * indexStructureDefinitionBundle(readJson('fhir/r4/profiles-resources.json') as Bundle);
11551
+ * ```
11552
+ *
11553
+ * In a client context, you can load the schema definitions using MedplumClient:
11554
+ *
11555
+ * ```ts
11556
+ * import { MedplumClient } from '@medplum/core';
11557
+ *
11558
+ * const medplum = new MedplumClient();
11559
+ * await medplum.requestSchema('Patient');
11560
+ * ```
11561
+ *
11562
+ * @param resourceType The candidate resource type string.
11563
+ * @returns True if the resource type is a valid FHIR resource type.
11564
+ */
11565
+ function validateResource(resource) {
11566
+ new FhirSchemaValidator(resource).validate();
11567
+ }
11568
+ class FhirSchemaValidator {
11569
+ constructor(root) {
11570
+ _FhirSchemaValidator_instances.add(this);
11571
+ _FhirSchemaValidator_issues.set(this, void 0);
11572
+ _FhirSchemaValidator_root.set(this, void 0);
11573
+ __classPrivateFieldSet(this, _FhirSchemaValidator_issues, [], "f");
11574
+ __classPrivateFieldSet(this, _FhirSchemaValidator_root, root, "f");
11575
+ }
11576
+ validate() {
11577
+ const resource = __classPrivateFieldGet(this, _FhirSchemaValidator_root, "f");
11578
+ if (!resource) {
11579
+ throw new OperationOutcomeError(validationError('Resource is null'));
11580
+ }
11581
+ const resourceType = resource.resourceType;
11582
+ if (!resourceType) {
11583
+ throw new OperationOutcomeError(validationError('Missing resource type'));
11584
+ }
11585
+ // Check for "null" once for the entire object hierarchy
11586
+ checkForNull(resource, '', __classPrivateFieldGet(this, _FhirSchemaValidator_issues, "f"));
11587
+ __classPrivateFieldGet(this, _FhirSchemaValidator_instances, "m", _FhirSchemaValidator_validateObject).call(this, toTypedValue(resource), resourceType);
11588
+ if (__classPrivateFieldGet(this, _FhirSchemaValidator_issues, "f").length > 0) {
11589
+ throw new OperationOutcomeError({
11590
+ resourceType: 'OperationOutcome',
11591
+ issue: __classPrivateFieldGet(this, _FhirSchemaValidator_issues, "f"),
11592
+ });
11593
+ }
11594
+ }
11595
+ }
11596
+ _FhirSchemaValidator_issues = new WeakMap(), _FhirSchemaValidator_root = new WeakMap(), _FhirSchemaValidator_instances = new WeakSet(), _FhirSchemaValidator_validateObject = function _FhirSchemaValidator_validateObject(typedValue, path) {
11597
+ const definition = globalSchema.types[typedValue.type];
11598
+ if (!definition) {
11599
+ throw new OperationOutcomeError(validationError('Unknown type: ' + typedValue.type));
11600
+ }
11601
+ const propertyDefinitions = definition.properties;
11602
+ __classPrivateFieldGet(this, _FhirSchemaValidator_instances, "m", _FhirSchemaValidator_checkProperties).call(this, path, propertyDefinitions, typedValue);
11603
+ __classPrivateFieldGet(this, _FhirSchemaValidator_instances, "m", _FhirSchemaValidator_checkAdditionalProperties).call(this, path, typedValue, propertyDefinitions);
11604
+ }, _FhirSchemaValidator_checkProperties = function _FhirSchemaValidator_checkProperties(path, propertyDefinitions, typedValue) {
11605
+ for (const [key, elementDefinition] of Object.entries(propertyDefinitions)) {
11606
+ __classPrivateFieldGet(this, _FhirSchemaValidator_instances, "m", _FhirSchemaValidator_checkProperty).call(this, path + '.' + key, elementDefinition, typedValue);
11607
+ }
11608
+ }, _FhirSchemaValidator_checkProperty = function _FhirSchemaValidator_checkProperty(path, elementDefinition, typedValue) {
11609
+ const propertyName = path.split('.').pop();
11610
+ const value = getTypedPropertyValue(typedValue, propertyName);
11611
+ if (isEmpty(value)) {
11612
+ if (elementDefinition.min !== undefined && elementDefinition.min > 0) {
11613
+ __classPrivateFieldGet(this, _FhirSchemaValidator_issues, "f").push(createStructureIssue(path, 'Missing required property'));
11614
+ }
11615
+ return;
11616
+ }
11617
+ if (elementDefinition.max === '*') {
11618
+ if (!Array.isArray(value)) {
11619
+ __classPrivateFieldGet(this, _FhirSchemaValidator_issues, "f").push(createStructureIssue(path, 'Expected array for property'));
11620
+ return;
11621
+ }
11622
+ for (const item of value) {
11623
+ __classPrivateFieldGet(this, _FhirSchemaValidator_instances, "m", _FhirSchemaValidator_checkPropertyValue).call(this, path, elementDefinition, item);
11624
+ }
11625
+ }
11626
+ else {
11627
+ __classPrivateFieldGet(this, _FhirSchemaValidator_instances, "m", _FhirSchemaValidator_checkPropertyValue).call(this, path, elementDefinition, value);
11628
+ }
11629
+ }, _FhirSchemaValidator_checkPropertyValue = function _FhirSchemaValidator_checkPropertyValue(path, elementDefinition, typedValue) {
11630
+ if (typedValue.value === null) {
11631
+ // Null handled separately
11632
+ return;
11633
+ }
11634
+ if (isLowerCase(typedValue.type.charAt(0))) {
11635
+ __classPrivateFieldGet(this, _FhirSchemaValidator_instances, "m", _FhirSchemaValidator_validatePrimitiveType).call(this, elementDefinition, typedValue);
11636
+ }
11637
+ else {
11638
+ __classPrivateFieldGet(this, _FhirSchemaValidator_instances, "m", _FhirSchemaValidator_validateObject).call(this, typedValue, path);
11639
+ }
11640
+ }, _FhirSchemaValidator_validatePrimitiveType = function _FhirSchemaValidator_validatePrimitiveType(elementDefinition, typedValue) {
11641
+ const { type, value } = typedValue;
11642
+ if (value === null) {
11643
+ // Null handled separately, so this code should never be reached
11644
+ // Leaving this check in place for now, in case we change the null handling
11645
+ return;
11646
+ }
11647
+ // First, make sure the value is the correct JS type
11648
+ const expectedType = fhirTypeToJsType[typedValue.type];
11649
+ if (typeof value !== expectedType) {
11650
+ __classPrivateFieldGet(this, _FhirSchemaValidator_instances, "m", _FhirSchemaValidator_createIssue).call(this, elementDefinition, 'Invalid type for ' + type);
11651
+ return;
11652
+ }
11653
+ // Then, perform additional checks for specialty types
11654
+ if (expectedType === 'string') {
11655
+ __classPrivateFieldGet(this, _FhirSchemaValidator_instances, "m", _FhirSchemaValidator_validateString).call(this, elementDefinition, type, value);
11656
+ }
11657
+ else if (expectedType === 'number') {
11658
+ __classPrivateFieldGet(this, _FhirSchemaValidator_instances, "m", _FhirSchemaValidator_validateNumber).call(this, elementDefinition, type, value);
11659
+ }
11660
+ }, _FhirSchemaValidator_validateString = function _FhirSchemaValidator_validateString(elementDefinition, type, value) {
11661
+ if (!value.trim()) {
11662
+ __classPrivateFieldGet(this, _FhirSchemaValidator_instances, "m", _FhirSchemaValidator_createIssue).call(this, elementDefinition, 'Invalid empty string');
11663
+ return;
11664
+ }
11665
+ // Try to get the regex
11666
+ const valueDefinition = globalSchema.types[type]?.properties?.['value'];
11667
+ if (valueDefinition?.type) {
11668
+ const regex = getExtensionValue(valueDefinition.type[0], 'http://hl7.org/fhir/StructureDefinition/regex');
11669
+ if (regex) {
11670
+ if (!value.match(new RegExp(regex))) {
11671
+ __classPrivateFieldGet(this, _FhirSchemaValidator_instances, "m", _FhirSchemaValidator_createIssue).call(this, elementDefinition, 'Invalid ' + type + ' format');
11672
+ }
11673
+ }
11674
+ }
11675
+ }, _FhirSchemaValidator_validateNumber = function _FhirSchemaValidator_validateNumber(elementDefinition, type, value) {
11676
+ if (isNaN(value) || !isFinite(value)) {
11677
+ __classPrivateFieldGet(this, _FhirSchemaValidator_instances, "m", _FhirSchemaValidator_createIssue).call(this, elementDefinition, 'Invalid ' + type + ' value');
11678
+ return;
11679
+ }
11680
+ if (isIntegerType(type) && !Number.isInteger(value)) {
11681
+ __classPrivateFieldGet(this, _FhirSchemaValidator_instances, "m", _FhirSchemaValidator_createIssue).call(this, elementDefinition, 'Number is not an integer');
11682
+ }
11683
+ if (type === exports.PropertyType.positiveInt && value <= 0) {
11684
+ __classPrivateFieldGet(this, _FhirSchemaValidator_instances, "m", _FhirSchemaValidator_createIssue).call(this, elementDefinition, 'Number is less than or equal to zero');
11685
+ }
11686
+ if (type === exports.PropertyType.unsignedInt && value < 0) {
11687
+ __classPrivateFieldGet(this, _FhirSchemaValidator_instances, "m", _FhirSchemaValidator_createIssue).call(this, elementDefinition, 'Number is negative');
11688
+ }
11689
+ }, _FhirSchemaValidator_checkAdditionalProperties = function _FhirSchemaValidator_checkAdditionalProperties(path, typedValue, propertyDefinitions) {
11690
+ const object = typedValue.value;
11691
+ for (const key of Object.keys(object)) {
11692
+ __classPrivateFieldGet(this, _FhirSchemaValidator_instances, "m", _FhirSchemaValidator_checkAdditionalProperty).call(this, path, key, typedValue, propertyDefinitions);
11693
+ }
11694
+ }, _FhirSchemaValidator_checkAdditionalProperty = function _FhirSchemaValidator_checkAdditionalProperty(path, key, typedValue, propertyDefinitions) {
11695
+ if (!baseResourceProperties.has(key) &&
11696
+ !(key in propertyDefinitions) &&
11697
+ !isChoiceOfType(key, typedValue, propertyDefinitions) &&
11698
+ !__classPrivateFieldGet(this, _FhirSchemaValidator_instances, "m", _FhirSchemaValidator_checkPrimitiveElement).call(this, path, key, typedValue)) {
11699
+ const expression = `${path}.${key}`;
11700
+ __classPrivateFieldGet(this, _FhirSchemaValidator_issues, "f").push(createStructureIssue(expression, `Invalid additional property "${expression}"`));
11701
+ }
11702
+ }, _FhirSchemaValidator_checkPrimitiveElement = function _FhirSchemaValidator_checkPrimitiveElement(path, key, typedValue) {
11703
+ // Primitive element starts with underscore
11704
+ if (!key.startsWith('_')) {
11705
+ return false;
11706
+ }
11707
+ // Validate the non-underscore property exists
11708
+ const primitiveKey = key.slice(1);
11709
+ if (!(primitiveKey in typedValue.value)) {
11710
+ return false;
11711
+ }
11712
+ // Then validate the element
11713
+ __classPrivateFieldGet(this, _FhirSchemaValidator_instances, "m", _FhirSchemaValidator_validateObject).call(this, { type: 'Element', value: typedValue.value[key] }, path);
11714
+ return true;
11715
+ }, _FhirSchemaValidator_createIssue = function _FhirSchemaValidator_createIssue(elementDefinition, message) {
11716
+ __classPrivateFieldGet(this, _FhirSchemaValidator_issues, "f").push(createStructureIssue(elementDefinition.path, message));
11717
+ };
11718
+ function isIntegerType(propertyType) {
11719
+ return (propertyType === exports.PropertyType.integer ||
11720
+ propertyType === exports.PropertyType.positiveInt ||
11721
+ propertyType === exports.PropertyType.unsignedInt);
11722
+ }
11723
+ function isChoiceOfType(key, typedValue, propertyDefinitions) {
11724
+ for (const propertyName of Object.keys(propertyDefinitions)) {
11725
+ if (!propertyName.endsWith('[x]')) {
11726
+ continue;
11727
+ }
11728
+ const basePropertyName = propertyName.replace('[x]', '');
11729
+ if (!key.startsWith(basePropertyName)) {
11730
+ continue;
11731
+ }
11732
+ let typedPropertyValue = getTypedPropertyValue(typedValue, propertyName);
11733
+ if (!typedPropertyValue) {
11734
+ continue;
11735
+ }
11736
+ if (Array.isArray(typedPropertyValue)) {
11737
+ // At present, there are no choice types that are arrays in the FHIR spec
11738
+ // Leaving this here to make TypeScript happy, and in case that changes
11739
+ typedPropertyValue = typedPropertyValue[0];
11740
+ }
11741
+ if (typedPropertyValue && key === basePropertyName + capitalize(typedPropertyValue.type)) {
11742
+ return true;
11743
+ }
11744
+ }
11745
+ return false;
11746
+ }
11747
+ /**
11748
+ * Recursively checks for null values in an object.
11749
+ *
11750
+ * Note that "null" is a special value in JSON that is not allowed in FHIR.
11751
+ *
11752
+ * @param value Input value of any type.
11753
+ * @param path Path string to the value for OperationOutcome.
11754
+ * @param issues Output list of issues.
11755
+ */
11756
+ function checkForNull(value, path, issues) {
11757
+ if (value === null) {
11758
+ issues.push(createStructureIssue(path, 'Invalid null value'));
11759
+ }
11760
+ else if (Array.isArray(value)) {
11761
+ checkArrayForNull(value, path, issues);
11762
+ }
11763
+ else if (typeof value === 'object') {
11764
+ checkObjectForNull(value, path, issues);
11765
+ }
11766
+ }
11767
+ function checkArrayForNull(array, path, issues) {
11768
+ for (let i = 0; i < array.length; i++) {
11769
+ if (array[i] === undefined) {
11770
+ issues.push(createStructureIssue(`${path}[${i}]`, 'Invalid undefined value'));
11771
+ }
11772
+ else {
11773
+ checkForNull(array[i], `${path}[${i}]`, issues);
11774
+ }
11775
+ }
11776
+ }
11777
+ function checkObjectForNull(obj, path, issues) {
11778
+ for (const [key, value] of Object.entries(obj)) {
11779
+ checkForNull(value, `${path}${path ? '.' : ''}${key}`, issues);
11780
+ }
11781
+ }
11782
+ function createStructureIssue(expression, details) {
11783
+ return {
11784
+ severity: 'error',
11785
+ code: 'structure',
11786
+ details: {
11787
+ text: details,
11788
+ },
11789
+ expression: [expression],
11790
+ };
11791
+ }
11792
+
10967
11793
  exports.SearchParameterType = void 0;
10968
11794
  (function (SearchParameterType) {
10969
11795
  SearchParameterType["BOOLEAN"] = "BOOLEAN";
@@ -11109,7 +11935,7 @@
11109
11935
  if (result.includes('[0]')) {
11110
11936
  result = result.replaceAll('[0]', '');
11111
11937
  }
11112
- const stopStrings = [' != ', ' as ', '.as(', '.exists(', '.where('];
11938
+ const stopStrings = [' != ', ' as ', '.as(', '.exists(', '.resolve(', '.where('];
11113
11939
  for (const stopString of stopStrings) {
11114
11940
  if (result.includes(stopString)) {
11115
11941
  result = result.substring(0, result.indexOf(stopString));
@@ -11698,7 +12524,11 @@
11698
12524
  exports.EquivalentAtom = EquivalentAtom;
11699
12525
  exports.FHIRPATH_KEYWORDS = FHIRPATH_KEYWORDS;
11700
12526
  exports.FHIRPATH_OPERATORS = FHIRPATH_OPERATORS;
12527
+ exports.FhirFilterComparison = FhirFilterComparison;
12528
+ exports.FhirFilterConnective = FhirFilterConnective;
12529
+ exports.FhirFilterNegation = FhirFilterNegation;
11701
12530
  exports.FhirPathAtom = FhirPathAtom;
12531
+ exports.FhirSchemaValidator = FhirSchemaValidator;
11702
12532
  exports.FunctionAtom = FunctionAtom;
11703
12533
  exports.Hl7Context = Hl7Context;
11704
12534
  exports.Hl7Field = Hl7Field;
@@ -11706,6 +12536,7 @@
11706
12536
  exports.Hl7Segment = Hl7Segment;
11707
12537
  exports.InAtom = InAtom;
11708
12538
  exports.IndexerAtom = IndexerAtom;
12539
+ exports.InfixOperatorAtom = InfixOperatorAtom;
11709
12540
  exports.IsAtom = IsAtom;
11710
12541
  exports.LRUCache = LRUCache;
11711
12542
  exports.LiteralAtom = LiteralAtom;
@@ -11715,8 +12546,12 @@
11715
12546
  exports.NotEquivalentAtom = NotEquivalentAtom;
11716
12547
  exports.OperationOutcomeError = OperationOutcomeError;
11717
12548
  exports.OrAtom = OrAtom;
12549
+ exports.Parser = Parser;
12550
+ exports.ParserBuilder = ParserBuilder;
12551
+ exports.PrefixOperatorAtom = PrefixOperatorAtom;
11718
12552
  exports.ReadablePromise = ReadablePromise;
11719
12553
  exports.SymbolAtom = SymbolAtom;
12554
+ exports.Tokenizer = Tokenizer;
11720
12555
  exports.UnaryOperatorAtom = UnaryOperatorAtom;
11721
12556
  exports.UnionAtom = UnionAtom;
11722
12557
  exports.XorAtom = XorAtom;
@@ -11730,7 +12565,9 @@
11730
12565
  exports.calculateAge = calculateAge;
11731
12566
  exports.calculateAgeString = calculateAgeString;
11732
12567
  exports.capitalize = capitalize;
12568
+ exports.checkForNull = checkForNull;
11733
12569
  exports.createReference = createReference;
12570
+ exports.createStructureIssue = createStructureIssue;
11734
12571
  exports.created = created;
11735
12572
  exports.deepClone = deepClone;
11736
12573
  exports.deepEquals = deepEquals$1;
@@ -11798,7 +12635,10 @@
11798
12635
  exports.isProfileResource = isProfileResource;
11799
12636
  exports.isQuantity = isQuantity;
11800
12637
  exports.isQuantityEquivalent = isQuantityEquivalent;
12638
+ exports.isReference = isReference;
12639
+ exports.isResource = isResource;
11801
12640
  exports.isResourceType = isResourceType;
12641
+ exports.isResourceTypeSchema = isResourceTypeSchema;
11802
12642
  exports.isStringArray = isStringArray;
11803
12643
  exports.isUUID = isUUID;
11804
12644
  exports.isValidDate = isValidDate;
@@ -11809,7 +12649,9 @@
11809
12649
  exports.notFound = notFound;
11810
12650
  exports.notModified = notModified;
11811
12651
  exports.parseFhirPath = parseFhirPath;
12652
+ exports.parseFilterParameter = parseFilterParameter;
11812
12653
  exports.parseJWTPayload = parseJWTPayload;
12654
+ exports.parseMappingLanguage = parseMappingLanguage;
11813
12655
  exports.parseSearchDefinition = parseSearchDefinition;
11814
12656
  exports.parseSearchRequest = parseSearchRequest;
11815
12657
  exports.parseSearchUrl = parseSearchUrl;
@@ -11825,9 +12667,12 @@
11825
12667
  exports.stringify = stringify;
11826
12668
  exports.toJsBoolean = toJsBoolean;
11827
12669
  exports.toTypedValue = toTypedValue;
11828
- exports.tokenize = tokenize;
12670
+ exports.tokenize = tokenize$2;
11829
12671
  exports.tooManyRequests = tooManyRequests;
11830
12672
  exports.unauthorized = unauthorized;
12673
+ exports.validateResource = validateResource;
12674
+ exports.validateResourceType = validateResourceType;
12675
+ exports.validationError = validationError;
11831
12676
 
11832
12677
  }));
11833
12678
  //# sourceMappingURL=index.cjs.map