@medplum/core 0.9.30 → 0.9.33

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.js CHANGED
@@ -129,7 +129,7 @@
129
129
  }
130
130
  function formatHumanName(name, options) {
131
131
  const builder = [];
132
- if (name.prefix && ((options === null || options === void 0 ? void 0 : options.all) || (options === null || options === void 0 ? void 0 : options.prefix))) {
132
+ if (name.prefix && (options === null || options === void 0 ? void 0 : options.prefix) !== false) {
133
133
  builder.push(...name.prefix);
134
134
  }
135
135
  if (name.given) {
@@ -138,7 +138,7 @@
138
138
  if (name.family) {
139
139
  builder.push(name.family);
140
140
  }
141
- if (name.suffix && ((options === null || options === void 0 ? void 0 : options.all) || (options === null || options === void 0 ? void 0 : options.suffix))) {
141
+ if (name.suffix && (options === null || options === void 0 ? void 0 : options.suffix) !== false) {
142
142
  builder.push(...name.suffix);
143
143
  }
144
144
  if (name.use && ((options === null || options === void 0 ? void 0 : options.all) || (options === null || options === void 0 ? void 0 : options.use))) {
@@ -692,7 +692,7 @@
692
692
  return word.charAt(0).toUpperCase() + word.substring(1);
693
693
  }
694
694
  function isLowerCase(c) {
695
- return c === c.toLowerCase();
695
+ return c === c.toLowerCase() && c !== c.toUpperCase();
696
696
  }
697
697
  /**
698
698
  * Tries to find a code string for a given system within a given codeable concept.
@@ -6070,19 +6070,13 @@
6070
6070
  function createSchema() {
6071
6071
  return { types: {} };
6072
6072
  }
6073
- function createTypeSchema(typeName, description) {
6073
+ function createTypeSchema(typeName, structureDefinition, elementDefinition) {
6074
6074
  return {
6075
+ structureDefinition,
6076
+ elementDefinition,
6075
6077
  display: typeName,
6076
- description,
6078
+ description: elementDefinition.definition,
6077
6079
  properties: {},
6078
- searchParams: {
6079
- _lastUpdated: {
6080
- base: [typeName],
6081
- code: '_lastUpdated',
6082
- type: 'date',
6083
- expression: typeName + '.meta.lastUpdated',
6084
- },
6085
- },
6086
6080
  };
6087
6081
  }
6088
6082
  /**
@@ -6109,17 +6103,12 @@
6109
6103
  if (!typeName) {
6110
6104
  return;
6111
6105
  }
6112
- if (!(typeName in schema.types)) {
6113
- schema.types[typeName] = createTypeSchema(typeName, structureDefinition.description);
6114
- }
6115
6106
  const elements = (_a = structureDefinition.snapshot) === null || _a === void 0 ? void 0 : _a.element;
6116
6107
  if (elements) {
6117
- // Filter out any elements missing path or type
6118
- const filtered = elements.filter((e) => e.path !== typeName && e.path);
6119
6108
  // First pass, build types
6120
- filtered.forEach((element) => indexType(schema, element));
6109
+ elements.forEach((element) => indexType(schema, structureDefinition, element));
6121
6110
  // Second pass, build properties
6122
- filtered.forEach((element) => indexProperty(schema, element));
6111
+ elements.forEach((element) => indexProperty(schema, element));
6123
6112
  }
6124
6113
  }
6125
6114
  /**
@@ -6129,19 +6118,17 @@
6129
6118
  * @param schema The output IndexedStructureDefinition.
6130
6119
  * @param element The input ElementDefinition.
6131
6120
  */
6132
- function indexType(schema, element) {
6121
+ function indexType(schema, structureDefinition, elementDefinition) {
6133
6122
  var _a, _b;
6134
- const path = element.path;
6135
- const typeCode = (_b = (_a = element.type) === null || _a === void 0 ? void 0 : _a[0]) === null || _b === void 0 ? void 0 : _b.code;
6136
- if (typeCode !== 'Element' && typeCode !== 'BackboneElement') {
6123
+ const path = elementDefinition.path;
6124
+ const typeCode = (_b = (_a = elementDefinition.type) === null || _a === void 0 ? void 0 : _a[0]) === null || _b === void 0 ? void 0 : _b.code;
6125
+ if (typeCode !== undefined && typeCode !== 'Element' && typeCode !== 'BackboneElement') {
6137
6126
  return;
6138
6127
  }
6139
6128
  const parts = path.split('.');
6140
6129
  const typeName = buildTypeName(parts);
6141
- if (!(typeName in schema.types)) {
6142
- schema.types[typeName] = createTypeSchema(typeName, element.definition);
6143
- schema.types[typeName].parentType = buildTypeName(parts.slice(0, parts.length - 1));
6144
- }
6130
+ schema.types[typeName] = createTypeSchema(typeName, structureDefinition, elementDefinition);
6131
+ schema.types[typeName].parentType = buildTypeName(parts.slice(0, parts.length - 1));
6145
6132
  }
6146
6133
  /**
6147
6134
  * Indexes PropertySchema from an ElementDefinition.
@@ -6178,12 +6165,22 @@
6178
6165
  continue;
6179
6166
  }
6180
6167
  if (!typeSchema.searchParams) {
6181
- typeSchema.searchParams = {};
6168
+ typeSchema.searchParams = {
6169
+ _lastUpdated: {
6170
+ base: [resourceType],
6171
+ code: '_lastUpdated',
6172
+ type: 'date',
6173
+ expression: resourceType + '.meta.lastUpdated',
6174
+ },
6175
+ };
6182
6176
  }
6183
6177
  typeSchema.searchParams[searchParam.code] = searchParam;
6184
6178
  }
6185
6179
  }
6186
6180
  function buildTypeName(components) {
6181
+ if (components.length === 1) {
6182
+ return components[0];
6183
+ }
6187
6184
  return components.map(capitalize).join('');
6188
6185
  }
6189
6186
  function getPropertyDisplayName(path) {
@@ -6494,12 +6491,11 @@
6494
6491
  * This requires a partial login from `startNewUser` or `startNewGoogleUser`.
6495
6492
  *
6496
6493
  * @param newProjectRequest Register request including email and password.
6497
- * @param login The partial login to complete. This should come from the `startNewUser` method.
6498
6494
  * @returns Promise to the authentication response.
6499
6495
  */
6500
- startNewProject(newProjectRequest, login) {
6496
+ startNewProject(newProjectRequest) {
6501
6497
  return __awaiter(this, void 0, void 0, function* () {
6502
- return this.post('auth/newproject', Object.assign(Object.assign({}, newProjectRequest), login));
6498
+ return this.post('auth/newproject', newProjectRequest);
6503
6499
  });
6504
6500
  }
6505
6501
  /**
@@ -6508,12 +6504,11 @@
6508
6504
  * This requires a partial login from `startNewUser` or `startNewGoogleUser`.
6509
6505
  *
6510
6506
  * @param newPatientRequest Register request including email and password.
6511
- * @param login The partial login to complete. This should come from the `startNewUser` method.
6512
6507
  * @returns Promise to the authentication response.
6513
6508
  */
6514
- startNewPatient(newPatientRequest, login) {
6509
+ startNewPatient(newPatientRequest) {
6515
6510
  return __awaiter(this, void 0, void 0, function* () {
6516
- return this.post('auth/newpatient', Object.assign(Object.assign({}, newPatientRequest), login));
6511
+ return this.post('auth/newpatient', newPatientRequest);
6517
6512
  });
6518
6513
  }
6519
6514
  /**
@@ -6525,8 +6520,10 @@
6525
6520
  startLogin(loginRequest) {
6526
6521
  var _a, _b;
6527
6522
  return __awaiter(this, void 0, void 0, function* () {
6528
- yield __classPrivateFieldGet(this, _MedplumClient_instances, "m", _MedplumClient_startPkce).call(this);
6529
- return this.post('auth/login', Object.assign(Object.assign({}, loginRequest), { clientId: (_a = loginRequest.clientId) !== null && _a !== void 0 ? _a : __classPrivateFieldGet(this, _MedplumClient_clientId, "f"), scope: (_b = loginRequest.scope) !== null && _b !== void 0 ? _b : DEFAULT_SCOPE, codeChallengeMethod: 'S256', codeChallenge: __classPrivateFieldGet(this, _MedplumClient_storage, "f").getString('codeChallenge') }));
6523
+ if (!loginRequest.codeChallenge || !loginRequest.codeChallengeMethod) {
6524
+ yield __classPrivateFieldGet(this, _MedplumClient_instances, "m", _MedplumClient_startPkce).call(this);
6525
+ }
6526
+ return this.post('auth/login', Object.assign(Object.assign({}, loginRequest), { clientId: (_a = loginRequest.clientId) !== null && _a !== void 0 ? _a : __classPrivateFieldGet(this, _MedplumClient_clientId, "f"), scope: (_b = loginRequest.scope) !== null && _b !== void 0 ? _b : DEFAULT_SCOPE, codeChallengeMethod: loginRequest.codeChallengeMethod || 'S256', codeChallenge: loginRequest.codeChallenge || __classPrivateFieldGet(this, _MedplumClient_storage, "f").getString('codeChallenge') }));
6530
6527
  });
6531
6528
  }
6532
6529
  /**
@@ -6540,8 +6537,10 @@
6540
6537
  startGoogleLogin(loginRequest) {
6541
6538
  var _a, _b;
6542
6539
  return __awaiter(this, void 0, void 0, function* () {
6543
- yield __classPrivateFieldGet(this, _MedplumClient_instances, "m", _MedplumClient_startPkce).call(this);
6544
- return this.post('auth/google', Object.assign(Object.assign({}, loginRequest), { clientId: (_a = loginRequest.clientId) !== null && _a !== void 0 ? _a : __classPrivateFieldGet(this, _MedplumClient_clientId, "f"), scope: (_b = loginRequest.scope) !== null && _b !== void 0 ? _b : DEFAULT_SCOPE }));
6540
+ if (!loginRequest.codeChallenge || !loginRequest.codeChallengeMethod) {
6541
+ yield __classPrivateFieldGet(this, _MedplumClient_instances, "m", _MedplumClient_startPkce).call(this);
6542
+ }
6543
+ return this.post('auth/google', Object.assign(Object.assign({}, loginRequest), { clientId: (_a = loginRequest.clientId) !== null && _a !== void 0 ? _a : __classPrivateFieldGet(this, _MedplumClient_clientId, "f"), scope: (_b = loginRequest.scope) !== null && _b !== void 0 ? _b : DEFAULT_SCOPE, codeChallengeMethod: loginRequest.codeChallengeMethod || 'S256', codeChallenge: loginRequest.codeChallenge || __classPrivateFieldGet(this, _MedplumClient_storage, "f").getString('codeChallenge') }));
6545
6544
  });
6546
6545
  }
6547
6546
  /**
@@ -7663,6 +7662,28 @@
7663
7662
  return url.endsWith('/') ? url : url + '/';
7664
7663
  }
7665
7664
 
7665
+ function parseDateString(str) {
7666
+ if (str.startsWith('T')) {
7667
+ // If a time string,
7668
+ // then normalize to full length.
7669
+ return str + 'T00:00:00.000Z'.substring(str.length);
7670
+ }
7671
+ if (str.length <= 10) {
7672
+ // If a local date (i.e., "2021-01-01"),
7673
+ // then return as-is.
7674
+ return str;
7675
+ }
7676
+ try {
7677
+ // Try to normalize to UTC
7678
+ return new Date(str).toISOString();
7679
+ }
7680
+ catch (e) {
7681
+ // Fallback to original input
7682
+ // This happens on unsupported time formats such as "2021-01-01T12"
7683
+ return str;
7684
+ }
7685
+ }
7686
+
7666
7687
  /**
7667
7688
  * Returns a single element array with a typed boolean value.
7668
7689
  * @param value The primitive boolean value.
@@ -7771,7 +7792,7 @@
7771
7792
  }
7772
7793
  }
7773
7794
  }
7774
- if (resultValue === undefined) {
7795
+ if (isEmpty(resultValue)) {
7775
7796
  return undefined;
7776
7797
  }
7777
7798
  if (resultType === 'BackboneElement') {
@@ -7816,7 +7837,7 @@
7816
7837
  }
7817
7838
  }
7818
7839
  }
7819
- if (result === undefined) {
7840
+ if (isEmpty(result)) {
7820
7841
  return undefined;
7821
7842
  }
7822
7843
  if (Array.isArray(result)) {
@@ -8007,7 +8028,6 @@
8007
8028
  }
8008
8029
  /**
8009
8030
  * Resource equality.
8010
- * Ignores meta.versionId and meta.lastUpdated.
8011
8031
  * See: https://dmitripavlutin.com/how-to-compare-objects-in-javascript/#4-deep-equality
8012
8032
  * @param object1 The first object.
8013
8033
  * @param object2 The second object.
@@ -8035,484 +8055,139 @@
8035
8055
  }
8036
8056
  return true;
8037
8057
  }
8038
- function isObject(object) {
8039
- return object !== null && typeof object === 'object';
8058
+ function isObject(obj) {
8059
+ return obj !== null && typeof obj === 'object';
8040
8060
  }
8041
8061
 
8042
- var _SymbolAtom_instances, _SymbolAtom_evalValue;
8043
- class FhirPathAtom {
8044
- constructor(original, child) {
8045
- this.original = original;
8046
- this.child = child;
8047
- }
8048
- eval(context) {
8049
- try {
8050
- if (context.length > 0) {
8051
- return context.map((e) => this.child.eval([e])).flat();
8052
- }
8053
- else {
8054
- return this.child.eval([]);
8055
- }
8056
- }
8057
- catch (error) {
8058
- throw new Error(`FhirPathError on "${this.original}": ${error}`);
8062
+ /**
8063
+ * Temporary placholder for unimplemented methods.
8064
+ */
8065
+ const stub = () => [];
8066
+ const functions = {
8067
+ /*
8068
+ * 5.1 Existence
8069
+ * See: https://hl7.org/fhirpath/#existence
8070
+ */
8071
+ /**
8072
+ * Returns true if the input collection is empty ({ }) and false otherwise.
8073
+ *
8074
+ * See: https://hl7.org/fhirpath/#empty-boolean
8075
+ *
8076
+ * @param input The input collection.
8077
+ * @returns True if the input collection is empty ({ }) and false otherwise.
8078
+ */
8079
+ empty: (input) => {
8080
+ return booleanToTypedValue(input.length === 0);
8081
+ },
8082
+ /**
8083
+ * Returns true if the collection has unknown elements, and false otherwise.
8084
+ * This is the opposite of empty(), and as such is a shorthand for empty().not().
8085
+ * If the input collection is empty ({ }), the result is false.
8086
+ *
8087
+ * The function can also take an optional criteria to be applied to the collection
8088
+ * prior to the determination of the exists. In this case, the function is shorthand
8089
+ * for where(criteria).exists().
8090
+ *
8091
+ * See: https://hl7.org/fhirpath/#existscriteria-expression-boolean
8092
+ *
8093
+ * @param input
8094
+ * @param criteria
8095
+ * @returns True if the collection has unknown elements, and false otherwise.
8096
+ */
8097
+ exists: (input, criteria) => {
8098
+ if (criteria) {
8099
+ return booleanToTypedValue(input.filter((e) => toJsBoolean(criteria.eval([e]))).length > 0);
8059
8100
  }
8060
- }
8061
- }
8062
- class LiteralAtom {
8063
- constructor(value) {
8064
- this.value = value;
8065
- }
8066
- eval() {
8067
- return [this.value];
8068
- }
8069
- }
8070
- class SymbolAtom {
8071
- constructor(name) {
8072
- this.name = name;
8073
- _SymbolAtom_instances.add(this);
8074
- }
8075
- eval(context) {
8076
- if (this.name === '$this') {
8077
- return context;
8101
+ else {
8102
+ return booleanToTypedValue(input.length > 0);
8078
8103
  }
8079
- return context
8080
- .map((e) => __classPrivateFieldGet(this, _SymbolAtom_instances, "m", _SymbolAtom_evalValue).call(this, e))
8081
- .flat()
8082
- .filter((e) => (e === null || e === void 0 ? void 0 : e.value) !== undefined);
8083
- }
8084
- }
8085
- _SymbolAtom_instances = new WeakSet(), _SymbolAtom_evalValue = function _SymbolAtom_evalValue(typedValue) {
8086
- const input = typedValue.value;
8087
- if (!input || typeof input !== 'object') {
8088
- return undefined;
8089
- }
8090
- if ('resourceType' in input && input.resourceType === this.name) {
8091
- return typedValue;
8092
- }
8093
- return getTypedPropertyValue(typedValue, this.name);
8094
- };
8095
- class EmptySetAtom {
8096
- eval() {
8097
- return [];
8098
- }
8099
- }
8100
- class UnaryOperatorAtom {
8101
- constructor(child, impl) {
8102
- this.child = child;
8103
- this.impl = impl;
8104
- }
8105
- eval(context) {
8106
- return this.impl(this.child.eval(context));
8107
- }
8108
- }
8109
- class AsAtom {
8110
- constructor(left, right) {
8111
- this.left = left;
8112
- this.right = right;
8113
- }
8114
- eval(context) {
8115
- return this.left.eval(context);
8116
- }
8117
- }
8118
- class ArithemticOperatorAtom {
8119
- constructor(left, right, impl) {
8120
- this.left = left;
8121
- this.right = right;
8122
- this.impl = impl;
8123
- }
8124
- eval(context) {
8125
- const leftEvalResult = this.left.eval(context);
8126
- if (leftEvalResult.length !== 1) {
8127
- return [];
8104
+ },
8105
+ /**
8106
+ * Returns true if for every element in the input collection, criteria evaluates to true.
8107
+ * Otherwise, the result is false.
8108
+ *
8109
+ * If the input collection is empty ({ }), the result is true.
8110
+ *
8111
+ * See: https://hl7.org/fhirpath/#allcriteria-expression-boolean
8112
+ *
8113
+ * @param input The input collection.
8114
+ * @param criteria The evaluation criteria.
8115
+ * @returns True if for every element in the input collection, criteria evaluates to true.
8116
+ */
8117
+ all: (input, criteria) => {
8118
+ return booleanToTypedValue(input.every((e) => toJsBoolean(criteria.eval([e]))));
8119
+ },
8120
+ /**
8121
+ * Takes a collection of Boolean values and returns true if all the items are true.
8122
+ * If unknown items are false, the result is false.
8123
+ * If the input is empty ({ }), the result is true.
8124
+ *
8125
+ * See: https://hl7.org/fhirpath/#alltrue-boolean
8126
+ *
8127
+ * @param input The input collection.
8128
+ * @param criteria The evaluation criteria.
8129
+ * @returns True if all the items are true.
8130
+ */
8131
+ allTrue: (input) => {
8132
+ for (const value of input) {
8133
+ if (!value.value) {
8134
+ return booleanToTypedValue(false);
8135
+ }
8128
8136
  }
8129
- const rightEvalResult = this.right.eval(context);
8130
- if (rightEvalResult.length !== 1) {
8131
- return [];
8137
+ return booleanToTypedValue(true);
8138
+ },
8139
+ /**
8140
+ * Takes a collection of Boolean values and returns true if unknown of the items are true.
8141
+ * If all the items are false, or if the input is empty ({ }), the result is false.
8142
+ *
8143
+ * See: https://hl7.org/fhirpath/#anytrue-boolean
8144
+ *
8145
+ * @param input The input collection.
8146
+ * @param criteria The evaluation criteria.
8147
+ * @returns True if unknown of the items are true.
8148
+ */
8149
+ anyTrue: (input) => {
8150
+ for (const value of input) {
8151
+ if (value.value) {
8152
+ return booleanToTypedValue(true);
8153
+ }
8132
8154
  }
8133
- const leftValue = leftEvalResult[0].value;
8134
- const rightValue = rightEvalResult[0].value;
8135
- const leftNumber = isQuantity(leftValue) ? leftValue.value : leftValue;
8136
- const rightNumber = isQuantity(rightValue) ? rightValue.value : rightValue;
8137
- const result = this.impl(leftNumber, rightNumber);
8138
- if (typeof result === 'boolean') {
8139
- return booleanToTypedValue(result);
8155
+ return booleanToTypedValue(false);
8156
+ },
8157
+ /**
8158
+ * Takes a collection of Boolean values and returns true if all the items are false.
8159
+ * If unknown items are true, the result is false.
8160
+ * If the input is empty ({ }), the result is true.
8161
+ *
8162
+ * See: https://hl7.org/fhirpath/#allfalse-boolean
8163
+ *
8164
+ * @param input The input collection.
8165
+ * @param criteria The evaluation criteria.
8166
+ * @returns True if all the items are false.
8167
+ */
8168
+ allFalse: (input) => {
8169
+ for (const value of input) {
8170
+ if (value.value) {
8171
+ return booleanToTypedValue(false);
8172
+ }
8140
8173
  }
8141
- else if (isQuantity(leftValue)) {
8142
- return [{ type: exports.PropertyType.Quantity, value: Object.assign(Object.assign({}, leftValue), { value: result }) }];
8143
- }
8144
- else {
8145
- return [toTypedValue(result)];
8146
- }
8147
- }
8148
- }
8149
- class ConcatAtom {
8150
- constructor(left, right) {
8151
- this.left = left;
8152
- this.right = right;
8153
- }
8154
- eval(context) {
8155
- const leftValue = this.left.eval(context);
8156
- const rightValue = this.right.eval(context);
8157
- const result = [...leftValue, ...rightValue];
8158
- if (result.length > 0 && result.every((e) => typeof e.value === 'string')) {
8159
- return [{ type: exports.PropertyType.string, value: result.map((e) => e.value).join('') }];
8160
- }
8161
- return result;
8162
- }
8163
- }
8164
- class ContainsAtom {
8165
- constructor(left, right) {
8166
- this.left = left;
8167
- this.right = right;
8168
- }
8169
- eval(context) {
8170
- const leftValue = this.left.eval(context);
8171
- const rightValue = this.right.eval(context);
8172
- return booleanToTypedValue(leftValue.some((e) => e.value === rightValue[0].value));
8173
- }
8174
- }
8175
- class InAtom {
8176
- constructor(left, right) {
8177
- this.left = left;
8178
- this.right = right;
8179
- }
8180
- eval(context) {
8181
- const leftValue = this.left.eval(context);
8182
- const rightValue = this.right.eval(context);
8183
- return booleanToTypedValue(rightValue.some((e) => e.value === leftValue[0].value));
8184
- }
8185
- }
8186
- class DotAtom {
8187
- constructor(left, right) {
8188
- this.left = left;
8189
- this.right = right;
8190
- }
8191
- eval(context) {
8192
- return this.right.eval(this.left.eval(context));
8193
- }
8194
- }
8195
- class UnionAtom {
8196
- constructor(left, right) {
8197
- this.left = left;
8198
- this.right = right;
8199
- }
8200
- eval(context) {
8201
- const leftResult = this.left.eval(context);
8202
- const rightResult = this.right.eval(context);
8203
- return removeDuplicates([...leftResult, ...rightResult]);
8204
- }
8205
- }
8206
- class EqualsAtom {
8207
- constructor(left, right) {
8208
- this.left = left;
8209
- this.right = right;
8210
- }
8211
- eval(context) {
8212
- const leftValue = this.left.eval(context);
8213
- const rightValue = this.right.eval(context);
8214
- return fhirPathArrayEquals(leftValue, rightValue);
8215
- }
8216
- }
8217
- class NotEqualsAtom {
8218
- constructor(left, right) {
8219
- this.left = left;
8220
- this.right = right;
8221
- }
8222
- eval(context) {
8223
- const leftValue = this.left.eval(context);
8224
- const rightValue = this.right.eval(context);
8225
- return fhirPathNot(fhirPathArrayEquals(leftValue, rightValue));
8226
- }
8227
- }
8228
- class EquivalentAtom {
8229
- constructor(left, right) {
8230
- this.left = left;
8231
- this.right = right;
8232
- }
8233
- eval(context) {
8234
- const leftValue = this.left.eval(context);
8235
- const rightValue = this.right.eval(context);
8236
- return fhirPathArrayEquivalent(leftValue, rightValue);
8237
- }
8238
- }
8239
- class NotEquivalentAtom {
8240
- constructor(left, right) {
8241
- this.left = left;
8242
- this.right = right;
8243
- }
8244
- eval(context) {
8245
- const leftValue = this.left.eval(context);
8246
- const rightValue = this.right.eval(context);
8247
- return fhirPathNot(fhirPathArrayEquivalent(leftValue, rightValue));
8248
- }
8249
- }
8250
- class IsAtom {
8251
- constructor(left, right) {
8252
- this.left = left;
8253
- this.right = right;
8254
- }
8255
- eval(context) {
8256
- const leftValue = this.left.eval(context);
8257
- if (leftValue.length !== 1) {
8258
- return [];
8259
- }
8260
- const typeName = this.right.name;
8261
- return booleanToTypedValue(fhirPathIs(leftValue[0], typeName));
8262
- }
8263
- }
8264
- /**
8265
- * 6.5.1. and
8266
- * Returns true if both operands evaluate to true,
8267
- * false if either operand evaluates to false,
8268
- * and the empty collection otherwise.
8269
- */
8270
- class AndAtom {
8271
- constructor(left, right) {
8272
- this.left = left;
8273
- this.right = right;
8274
- }
8275
- eval(context) {
8276
- var _a, _b, _c, _d;
8277
- const leftValue = this.left.eval(context);
8278
- const rightValue = this.right.eval(context);
8279
- if (((_a = leftValue[0]) === null || _a === void 0 ? void 0 : _a.value) === true && ((_b = rightValue[0]) === null || _b === void 0 ? void 0 : _b.value) === true) {
8280
- return booleanToTypedValue(true);
8281
- }
8282
- if (((_c = leftValue[0]) === null || _c === void 0 ? void 0 : _c.value) === false || ((_d = rightValue[0]) === null || _d === void 0 ? void 0 : _d.value) === false) {
8283
- return booleanToTypedValue(false);
8284
- }
8285
- return [];
8286
- }
8287
- }
8288
- class OrAtom {
8289
- constructor(left, right) {
8290
- this.left = left;
8291
- this.right = right;
8292
- }
8293
- eval(context) {
8294
- const leftValue = this.left.eval(context);
8295
- if (toJsBoolean(leftValue)) {
8296
- return leftValue;
8297
- }
8298
- const rightValue = this.right.eval(context);
8299
- if (toJsBoolean(rightValue)) {
8300
- return rightValue;
8301
- }
8302
- return [];
8303
- }
8304
- }
8305
- /**
8306
- * 6.5.4. xor
8307
- * Returns true if exactly one of the operands evaluates to true,
8308
- * false if either both operands evaluate to true or both operands evaluate to false,
8309
- * and the empty collection otherwise.
8310
- */
8311
- class XorAtom {
8312
- constructor(left, right) {
8313
- this.left = left;
8314
- this.right = right;
8315
- }
8316
- eval(context) {
8317
- const leftResult = this.left.eval(context);
8318
- const rightResult = this.right.eval(context);
8319
- if (leftResult.length === 0 && rightResult.length === 0) {
8320
- return [];
8321
- }
8322
- const leftValue = leftResult.length === 0 ? null : leftResult[0].value;
8323
- const rightValue = rightResult.length === 0 ? null : rightResult[0].value;
8324
- if ((leftValue === true && rightValue !== true) || (leftValue !== true && rightValue === true)) {
8325
- return booleanToTypedValue(true);
8326
- }
8327
- if ((leftValue === true && rightValue === true) || (leftValue === false && rightValue === false)) {
8328
- return booleanToTypedValue(false);
8329
- }
8330
- return [];
8331
- }
8332
- }
8333
- class FunctionAtom {
8334
- constructor(name, args, impl) {
8335
- this.name = name;
8336
- this.args = args;
8337
- this.impl = impl;
8338
- }
8339
- eval(context) {
8340
- return this.impl(context, ...this.args);
8341
- }
8342
- }
8343
- class IndexerAtom {
8344
- constructor(left, expr) {
8345
- this.left = left;
8346
- this.expr = expr;
8347
- }
8348
- eval(context) {
8349
- const evalResult = this.expr.eval(context);
8350
- if (evalResult.length !== 1) {
8351
- return [];
8352
- }
8353
- const index = evalResult[0].value;
8354
- if (typeof index !== 'number') {
8355
- throw new Error(`Invalid indexer expression: should return integer}`);
8356
- }
8357
- const leftResult = this.left.eval(context);
8358
- if (!(index in leftResult)) {
8359
- return [];
8360
- }
8361
- return [leftResult[index]];
8362
- }
8363
- }
8364
-
8365
- function parseDateString(str) {
8366
- if (str.startsWith('T')) {
8367
- // If a time string,
8368
- // then normalize to full length.
8369
- return str + 'T00:00:00.000Z'.substring(str.length);
8370
- }
8371
- if (str.length <= 10) {
8372
- // If a local date (i.e., "2021-01-01"),
8373
- // then return as-is.
8374
- return str;
8375
- }
8376
- try {
8377
- // Try to normalize to UTC
8378
- return new Date(str).toISOString();
8379
- }
8380
- catch (e) {
8381
- // Fallback to original input
8382
- // This happens on unsupported time formats such as "2021-01-01T12"
8383
- return str;
8384
- }
8385
- }
8386
-
8387
- /**
8388
- * Temporary placholder for unimplemented methods.
8389
- */
8390
- const stub = () => [];
8391
- const functions = {
8392
- /*
8393
- * 5.1 Existence
8394
- * See: https://hl7.org/fhirpath/#existence
8395
- */
8396
- /**
8397
- * Returns true if the input collection is empty ({ }) and false otherwise.
8398
- *
8399
- * See: https://hl7.org/fhirpath/#empty-boolean
8400
- *
8401
- * @param input The input collection.
8402
- * @returns True if the input collection is empty ({ }) and false otherwise.
8403
- */
8404
- empty: (input) => {
8405
- return booleanToTypedValue(input.length === 0);
8406
- },
8407
- /**
8408
- * Returns true if the collection has unknown elements, and false otherwise.
8409
- * This is the opposite of empty(), and as such is a shorthand for empty().not().
8410
- * If the input collection is empty ({ }), the result is false.
8411
- *
8412
- * The function can also take an optional criteria to be applied to the collection
8413
- * prior to the determination of the exists. In this case, the function is shorthand
8414
- * for where(criteria).exists().
8415
- *
8416
- * See: https://hl7.org/fhirpath/#existscriteria-expression-boolean
8417
- *
8418
- * @param input
8419
- * @param criteria
8420
- * @returns True if the collection has unknown elements, and false otherwise.
8421
- */
8422
- exists: (input, criteria) => {
8423
- if (criteria) {
8424
- return booleanToTypedValue(input.filter((e) => toJsBoolean(criteria.eval([e]))).length > 0);
8425
- }
8426
- else {
8427
- return booleanToTypedValue(input.length > 0);
8428
- }
8429
- },
8430
- /**
8431
- * Returns true if for every element in the input collection, criteria evaluates to true.
8432
- * Otherwise, the result is false.
8433
- *
8434
- * If the input collection is empty ({ }), the result is true.
8435
- *
8436
- * See: https://hl7.org/fhirpath/#allcriteria-expression-boolean
8437
- *
8438
- * @param input The input collection.
8439
- * @param criteria The evaluation criteria.
8440
- * @returns True if for every element in the input collection, criteria evaluates to true.
8441
- */
8442
- all: (input, criteria) => {
8443
- return booleanToTypedValue(input.every((e) => toJsBoolean(criteria.eval([e]))));
8444
- },
8445
- /**
8446
- * Takes a collection of Boolean values and returns true if all the items are true.
8447
- * If unknown items are false, the result is false.
8448
- * If the input is empty ({ }), the result is true.
8449
- *
8450
- * See: https://hl7.org/fhirpath/#alltrue-boolean
8451
- *
8452
- * @param input The input collection.
8453
- * @param criteria The evaluation criteria.
8454
- * @returns True if all the items are true.
8455
- */
8456
- allTrue: (input) => {
8457
- for (const value of input) {
8458
- if (!value.value) {
8459
- return booleanToTypedValue(false);
8460
- }
8461
- }
8462
- return booleanToTypedValue(true);
8463
- },
8464
- /**
8465
- * Takes a collection of Boolean values and returns true if unknown of the items are true.
8466
- * If all the items are false, or if the input is empty ({ }), the result is false.
8467
- *
8468
- * See: https://hl7.org/fhirpath/#anytrue-boolean
8469
- *
8470
- * @param input The input collection.
8471
- * @param criteria The evaluation criteria.
8472
- * @returns True if unknown of the items are true.
8473
- */
8474
- anyTrue: (input) => {
8475
- for (const value of input) {
8476
- if (value.value) {
8477
- return booleanToTypedValue(true);
8478
- }
8479
- }
8480
- return booleanToTypedValue(false);
8481
- },
8482
- /**
8483
- * Takes a collection of Boolean values and returns true if all the items are false.
8484
- * If unknown items are true, the result is false.
8485
- * If the input is empty ({ }), the result is true.
8486
- *
8487
- * See: https://hl7.org/fhirpath/#allfalse-boolean
8488
- *
8489
- * @param input The input collection.
8490
- * @param criteria The evaluation criteria.
8491
- * @returns True if all the items are false.
8492
- */
8493
- allFalse: (input) => {
8494
- for (const value of input) {
8495
- if (value.value) {
8496
- return booleanToTypedValue(false);
8497
- }
8498
- }
8499
- return booleanToTypedValue(true);
8500
- },
8501
- /**
8502
- * Takes a collection of Boolean values and returns true if unknown of the items are false.
8503
- * If all the items are true, or if the input is empty ({ }), the result is false.
8504
- *
8505
- * See: https://hl7.org/fhirpath/#anyfalse-boolean
8506
- *
8507
- * @param input The input collection.
8508
- * @param criteria The evaluation criteria.
8509
- * @returns True if for every element in the input collection, criteria evaluates to true.
8510
- */
8511
- anyFalse: (input) => {
8512
- for (const value of input) {
8513
- if (!value.value) {
8514
- return booleanToTypedValue(true);
8515
- }
8174
+ return booleanToTypedValue(true);
8175
+ },
8176
+ /**
8177
+ * Takes a collection of Boolean values and returns true if unknown of the items are false.
8178
+ * If all the items are true, or if the input is empty ({ }), the result is false.
8179
+ *
8180
+ * See: https://hl7.org/fhirpath/#anyfalse-boolean
8181
+ *
8182
+ * @param input The input collection.
8183
+ * @param criteria The evaluation criteria.
8184
+ * @returns True if for every element in the input collection, criteria evaluates to true.
8185
+ */
8186
+ anyFalse: (input) => {
8187
+ for (const value of input) {
8188
+ if (!value.value) {
8189
+ return booleanToTypedValue(true);
8190
+ }
8516
8191
  }
8517
8192
  return booleanToTypedValue(false);
8518
8193
  },
@@ -8643,7 +8318,9 @@
8643
8318
  *
8644
8319
  * See: http://hl7.org/fhirpath/#oftypetype-type-specifier-collection
8645
8320
  */
8646
- ofType: stub,
8321
+ ofType: (input, criteria) => {
8322
+ return input.filter((e) => e.type === criteria.name);
8323
+ },
8647
8324
  /*
8648
8325
  * 5.3 Subsetting
8649
8326
  */
@@ -9688,195 +9365,518 @@
9688
9365
  if (startDate.length === 0) {
9689
9366
  throw new Error('Invalid start date');
9690
9367
  }
9691
- const endDate = functions.toDateTime(endAtom.eval(input));
9692
- if (endDate.length === 0) {
9693
- throw new Error('Invalid end date');
9368
+ const endDate = functions.toDateTime(endAtom.eval(input));
9369
+ if (endDate.length === 0) {
9370
+ throw new Error('Invalid end date');
9371
+ }
9372
+ const unit = (_a = unitsAtom.eval(input)[0]) === null || _a === void 0 ? void 0 : _a.value;
9373
+ if (unit !== 'years' && unit !== 'months' && unit !== 'days') {
9374
+ throw new Error('Invalid units');
9375
+ }
9376
+ const age = calculateAge(startDate[0].value, endDate[0].value);
9377
+ return [{ type: exports.PropertyType.Quantity, value: { value: age[unit], unit } }];
9378
+ },
9379
+ /*
9380
+ * 6.3 Types
9381
+ */
9382
+ /**
9383
+ * The is() function is supported for backwards compatibility with previous
9384
+ * implementations of FHIRPath. Just as with the is keyword, the type argument
9385
+ * is an identifier that must resolve to the name of a type in a model.
9386
+ *
9387
+ * For implementations with compile-time typing, this requires special-case
9388
+ * handling when processing the argument to treat it as a type specifier rather
9389
+ * than an identifier expression:
9390
+ *
9391
+ * @param input
9392
+ * @param typeAtom
9393
+ * @returns
9394
+ */
9395
+ is: (input, typeAtom) => {
9396
+ let typeName = '';
9397
+ if (typeAtom instanceof SymbolAtom) {
9398
+ typeName = typeAtom.name;
9399
+ }
9400
+ else if (typeAtom instanceof DotAtom) {
9401
+ typeName = typeAtom.left.name + '.' + typeAtom.right.name;
9402
+ }
9403
+ if (!typeName) {
9404
+ return [];
9405
+ }
9406
+ return input.map((value) => ({ type: exports.PropertyType.boolean, value: fhirPathIs(value, typeName) }));
9407
+ },
9408
+ /*
9409
+ * 6.5 Boolean logic
9410
+ */
9411
+ /**
9412
+ * 6.5.3. not() : Boolean
9413
+ *
9414
+ * Returns true if the input collection evaluates to false, and false if it evaluates to true. Otherwise, the result is empty ({ }):
9415
+ *
9416
+ * @param input
9417
+ * @returns
9418
+ */
9419
+ not: (input) => {
9420
+ return functions.toBoolean(input).map((value) => ({ type: exports.PropertyType.boolean, value: !value.value }));
9421
+ },
9422
+ /*
9423
+ * Additional functions
9424
+ * See: https://hl7.org/fhir/fhirpath.html#functions
9425
+ */
9426
+ /**
9427
+ * For each item in the collection, if it is a string that is a uri (or canonical or url), locate the target of the reference, and add it to the resulting collection. If the item does not resolve to a resource, the item is ignored and nothing is added to the output collection.
9428
+ * The items in the collection may also represent a Reference, in which case the Reference.reference is resolved.
9429
+ * @param input The input collection.
9430
+ * @returns
9431
+ */
9432
+ resolve: (input) => {
9433
+ return input
9434
+ .map((e) => {
9435
+ const value = e.value;
9436
+ let refStr;
9437
+ if (typeof value === 'string') {
9438
+ refStr = value;
9439
+ }
9440
+ else if (typeof value === 'object') {
9441
+ const ref = value;
9442
+ if (ref.resource) {
9443
+ return toTypedValue(ref.resource);
9444
+ }
9445
+ refStr = ref.reference;
9446
+ }
9447
+ if (!refStr) {
9448
+ return { type: exports.PropertyType.BackboneElement, value: null };
9449
+ }
9450
+ const [resourceType, id] = refStr.split('/');
9451
+ return { type: exports.PropertyType.BackboneElement, value: { resourceType, id } };
9452
+ })
9453
+ .filter((e) => !!e.value);
9454
+ },
9455
+ /**
9456
+ * The as operator can be used to treat a value as a specific type.
9457
+ * @param input The input value.
9458
+ * @returns The value as the specific type.
9459
+ */
9460
+ as: (input) => {
9461
+ return input;
9462
+ },
9463
+ /*
9464
+ * 12. Formal Specifications
9465
+ */
9466
+ /**
9467
+ * Returns the type of the input.
9468
+ *
9469
+ * 12.2. Model Information
9470
+ *
9471
+ * The model information returned by the reflection function type() is specified as an
9472
+ * XML Schema document (xsd) and included in this specification at the following link:
9473
+ * https://hl7.org/fhirpath/modelinfo.xsd
9474
+ *
9475
+ * See: https://hl7.org/fhirpath/#model-information
9476
+ *
9477
+ * @param input The input collection.
9478
+ * @returns
9479
+ */
9480
+ type: (input) => {
9481
+ return input.map(({ value }) => {
9482
+ if (typeof value === 'boolean') {
9483
+ return { type: exports.PropertyType.BackboneElement, value: { namespace: 'System', name: 'Boolean' } };
9484
+ }
9485
+ if (typeof value === 'number') {
9486
+ return { type: exports.PropertyType.BackboneElement, value: { namespace: 'System', name: 'Integer' } };
9487
+ }
9488
+ if (value && typeof value === 'object' && 'resourceType' in value) {
9489
+ return {
9490
+ type: exports.PropertyType.BackboneElement,
9491
+ value: { namespace: 'FHIR', name: value.resourceType },
9492
+ };
9493
+ }
9494
+ return { type: exports.PropertyType.BackboneElement, value: null };
9495
+ });
9496
+ },
9497
+ conformsTo: (input, systemAtom) => {
9498
+ const system = systemAtom.eval(input)[0].value;
9499
+ if (!system.startsWith('http://hl7.org/fhir/StructureDefinition/')) {
9500
+ throw new Error('Expected a StructureDefinition URL');
9501
+ }
9502
+ const expectedResourceType = system.replace('http://hl7.org/fhir/StructureDefinition/', '');
9503
+ return input.map((value) => {
9504
+ var _a;
9505
+ return ({
9506
+ type: exports.PropertyType.boolean,
9507
+ value: ((_a = value.value) === null || _a === void 0 ? void 0 : _a.resourceType) === expectedResourceType,
9508
+ });
9509
+ });
9510
+ },
9511
+ };
9512
+ /*
9513
+ * Helper utilities
9514
+ */
9515
+ function applyStringFunc(func, input, ...argsAtoms) {
9516
+ if (input.length === 0) {
9517
+ return [];
9518
+ }
9519
+ const [{ value }] = validateInput(input, 1);
9520
+ if (typeof value !== 'string') {
9521
+ throw new Error('String function cannot be called with non-string');
9522
+ }
9523
+ const result = func(value, ...argsAtoms.map((atom) => { var _a, _b; return atom && ((_b = (_a = atom.eval(input)) === null || _a === void 0 ? void 0 : _a[0]) === null || _b === void 0 ? void 0 : _b.value); }));
9524
+ if (result === undefined) {
9525
+ return [];
9526
+ }
9527
+ if (Array.isArray(result)) {
9528
+ return result.map(toTypedValue);
9529
+ }
9530
+ return [toTypedValue(result)];
9531
+ }
9532
+ function applyMathFunc(func, input, ...argsAtoms) {
9533
+ if (input.length === 0) {
9534
+ return [];
9535
+ }
9536
+ const [{ value }] = validateInput(input, 1);
9537
+ const quantity = isQuantity(value);
9538
+ const numberInput = quantity ? value.value : value;
9539
+ if (typeof numberInput !== 'number') {
9540
+ throw new Error('Math function cannot be called with non-number');
9541
+ }
9542
+ const result = func(numberInput, ...argsAtoms.map((atom) => { var _a, _b; return (_b = (_a = atom.eval(input)) === null || _a === void 0 ? void 0 : _a[0]) === null || _b === void 0 ? void 0 : _b.value; }));
9543
+ const type = quantity ? exports.PropertyType.Quantity : input[0].type;
9544
+ const returnValue = quantity ? Object.assign(Object.assign({}, value), { value: result }) : result;
9545
+ return [{ type, value: returnValue }];
9546
+ }
9547
+ function validateInput(input, count) {
9548
+ if (input.length !== count) {
9549
+ throw new Error(`Expected ${count} arguments`);
9550
+ }
9551
+ for (const element of input) {
9552
+ if (element === null || element === undefined) {
9553
+ throw new Error('Expected non-null argument');
9554
+ }
9555
+ }
9556
+ return input;
9557
+ }
9558
+
9559
+ var _SymbolAtom_instances, _SymbolAtom_evalValue;
9560
+ class FhirPathAtom {
9561
+ constructor(original, child) {
9562
+ this.original = original;
9563
+ this.child = child;
9564
+ }
9565
+ eval(context) {
9566
+ try {
9567
+ if (context.length > 0) {
9568
+ return context.map((e) => this.child.eval([e])).flat();
9569
+ }
9570
+ else {
9571
+ return this.child.eval([]);
9572
+ }
9694
9573
  }
9695
- const unit = (_a = unitsAtom.eval(input)[0]) === null || _a === void 0 ? void 0 : _a.value;
9696
- if (unit !== 'years' && unit !== 'months' && unit !== 'days') {
9697
- throw new Error('Invalid units');
9574
+ catch (error) {
9575
+ throw new Error(`FhirPathError on "${this.original}": ${error}`);
9576
+ }
9577
+ }
9578
+ }
9579
+ class LiteralAtom {
9580
+ constructor(value) {
9581
+ this.value = value;
9582
+ }
9583
+ eval() {
9584
+ return [this.value];
9585
+ }
9586
+ }
9587
+ class SymbolAtom {
9588
+ constructor(name) {
9589
+ this.name = name;
9590
+ _SymbolAtom_instances.add(this);
9591
+ }
9592
+ eval(context) {
9593
+ if (this.name === '$this') {
9594
+ return context;
9595
+ }
9596
+ return context
9597
+ .map((e) => __classPrivateFieldGet(this, _SymbolAtom_instances, "m", _SymbolAtom_evalValue).call(this, e))
9598
+ .flat()
9599
+ .filter((e) => (e === null || e === void 0 ? void 0 : e.value) !== undefined);
9600
+ }
9601
+ }
9602
+ _SymbolAtom_instances = new WeakSet(), _SymbolAtom_evalValue = function _SymbolAtom_evalValue(typedValue) {
9603
+ const input = typedValue.value;
9604
+ if (!input || typeof input !== 'object') {
9605
+ return undefined;
9606
+ }
9607
+ if ('resourceType' in input && input.resourceType === this.name) {
9608
+ return typedValue;
9609
+ }
9610
+ return getTypedPropertyValue(typedValue, this.name);
9611
+ };
9612
+ class EmptySetAtom {
9613
+ eval() {
9614
+ return [];
9615
+ }
9616
+ }
9617
+ class UnaryOperatorAtom {
9618
+ constructor(child, impl) {
9619
+ this.child = child;
9620
+ this.impl = impl;
9621
+ }
9622
+ eval(context) {
9623
+ return this.impl(this.child.eval(context));
9624
+ }
9625
+ }
9626
+ class AsAtom {
9627
+ constructor(left, right) {
9628
+ this.left = left;
9629
+ this.right = right;
9630
+ }
9631
+ eval(context) {
9632
+ return functions.ofType(this.left.eval(context), this.right);
9633
+ }
9634
+ }
9635
+ class ArithemticOperatorAtom {
9636
+ constructor(left, right, impl) {
9637
+ this.left = left;
9638
+ this.right = right;
9639
+ this.impl = impl;
9640
+ }
9641
+ eval(context) {
9642
+ const leftEvalResult = this.left.eval(context);
9643
+ if (leftEvalResult.length !== 1) {
9644
+ return [];
9645
+ }
9646
+ const rightEvalResult = this.right.eval(context);
9647
+ if (rightEvalResult.length !== 1) {
9648
+ return [];
9649
+ }
9650
+ const leftValue = leftEvalResult[0].value;
9651
+ const rightValue = rightEvalResult[0].value;
9652
+ const leftNumber = isQuantity(leftValue) ? leftValue.value : leftValue;
9653
+ const rightNumber = isQuantity(rightValue) ? rightValue.value : rightValue;
9654
+ const result = this.impl(leftNumber, rightNumber);
9655
+ if (typeof result === 'boolean') {
9656
+ return booleanToTypedValue(result);
9657
+ }
9658
+ else if (isQuantity(leftValue)) {
9659
+ return [{ type: exports.PropertyType.Quantity, value: Object.assign(Object.assign({}, leftValue), { value: result }) }];
9660
+ }
9661
+ else {
9662
+ return [toTypedValue(result)];
9663
+ }
9664
+ }
9665
+ }
9666
+ class ConcatAtom {
9667
+ constructor(left, right) {
9668
+ this.left = left;
9669
+ this.right = right;
9670
+ }
9671
+ eval(context) {
9672
+ const leftValue = this.left.eval(context);
9673
+ const rightValue = this.right.eval(context);
9674
+ const result = [...leftValue, ...rightValue];
9675
+ if (result.length > 0 && result.every((e) => typeof e.value === 'string')) {
9676
+ return [{ type: exports.PropertyType.string, value: result.map((e) => e.value).join('') }];
9677
+ }
9678
+ return result;
9679
+ }
9680
+ }
9681
+ class ContainsAtom {
9682
+ constructor(left, right) {
9683
+ this.left = left;
9684
+ this.right = right;
9685
+ }
9686
+ eval(context) {
9687
+ const leftValue = this.left.eval(context);
9688
+ const rightValue = this.right.eval(context);
9689
+ return booleanToTypedValue(leftValue.some((e) => e.value === rightValue[0].value));
9690
+ }
9691
+ }
9692
+ class InAtom {
9693
+ constructor(left, right) {
9694
+ this.left = left;
9695
+ this.right = right;
9696
+ }
9697
+ eval(context) {
9698
+ const leftValue = this.left.eval(context);
9699
+ const rightValue = this.right.eval(context);
9700
+ return booleanToTypedValue(rightValue.some((e) => e.value === leftValue[0].value));
9701
+ }
9702
+ }
9703
+ class DotAtom {
9704
+ constructor(left, right) {
9705
+ this.left = left;
9706
+ this.right = right;
9707
+ }
9708
+ eval(context) {
9709
+ return this.right.eval(this.left.eval(context));
9710
+ }
9711
+ }
9712
+ class UnionAtom {
9713
+ constructor(left, right) {
9714
+ this.left = left;
9715
+ this.right = right;
9716
+ }
9717
+ eval(context) {
9718
+ const leftResult = this.left.eval(context);
9719
+ const rightResult = this.right.eval(context);
9720
+ return removeDuplicates([...leftResult, ...rightResult]);
9721
+ }
9722
+ }
9723
+ class EqualsAtom {
9724
+ constructor(left, right) {
9725
+ this.left = left;
9726
+ this.right = right;
9727
+ }
9728
+ eval(context) {
9729
+ const leftValue = this.left.eval(context);
9730
+ const rightValue = this.right.eval(context);
9731
+ return fhirPathArrayEquals(leftValue, rightValue);
9732
+ }
9733
+ }
9734
+ class NotEqualsAtom {
9735
+ constructor(left, right) {
9736
+ this.left = left;
9737
+ this.right = right;
9738
+ }
9739
+ eval(context) {
9740
+ const leftValue = this.left.eval(context);
9741
+ const rightValue = this.right.eval(context);
9742
+ return fhirPathNot(fhirPathArrayEquals(leftValue, rightValue));
9743
+ }
9744
+ }
9745
+ class EquivalentAtom {
9746
+ constructor(left, right) {
9747
+ this.left = left;
9748
+ this.right = right;
9749
+ }
9750
+ eval(context) {
9751
+ const leftValue = this.left.eval(context);
9752
+ const rightValue = this.right.eval(context);
9753
+ return fhirPathArrayEquivalent(leftValue, rightValue);
9754
+ }
9755
+ }
9756
+ class NotEquivalentAtom {
9757
+ constructor(left, right) {
9758
+ this.left = left;
9759
+ this.right = right;
9760
+ }
9761
+ eval(context) {
9762
+ const leftValue = this.left.eval(context);
9763
+ const rightValue = this.right.eval(context);
9764
+ return fhirPathNot(fhirPathArrayEquivalent(leftValue, rightValue));
9765
+ }
9766
+ }
9767
+ class IsAtom {
9768
+ constructor(left, right) {
9769
+ this.left = left;
9770
+ this.right = right;
9771
+ }
9772
+ eval(context) {
9773
+ const leftValue = this.left.eval(context);
9774
+ if (leftValue.length !== 1) {
9775
+ return [];
9698
9776
  }
9699
- const age = calculateAge(startDate[0].value, endDate[0].value);
9700
- return [{ type: exports.PropertyType.Quantity, value: { value: age[unit], unit } }];
9701
- },
9702
- /*
9703
- * 6.3 Types
9704
- */
9705
- /**
9706
- * The is() function is supported for backwards compatibility with previous
9707
- * implementations of FHIRPath. Just as with the is keyword, the type argument
9708
- * is an identifier that must resolve to the name of a type in a model.
9709
- *
9710
- * For implementations with compile-time typing, this requires special-case
9711
- * handling when processing the argument to treat it as a type specifier rather
9712
- * than an identifier expression:
9713
- *
9714
- * @param input
9715
- * @param typeAtom
9716
- * @returns
9717
- */
9718
- is: (input, typeAtom) => {
9719
- let typeName = '';
9720
- if (typeAtom instanceof SymbolAtom) {
9721
- typeName = typeAtom.name;
9777
+ const typeName = this.right.name;
9778
+ return booleanToTypedValue(fhirPathIs(leftValue[0], typeName));
9779
+ }
9780
+ }
9781
+ /**
9782
+ * 6.5.1. and
9783
+ * Returns true if both operands evaluate to true,
9784
+ * false if either operand evaluates to false,
9785
+ * and the empty collection otherwise.
9786
+ */
9787
+ class AndAtom {
9788
+ constructor(left, right) {
9789
+ this.left = left;
9790
+ this.right = right;
9791
+ }
9792
+ eval(context) {
9793
+ var _a, _b, _c, _d;
9794
+ const leftValue = this.left.eval(context);
9795
+ const rightValue = this.right.eval(context);
9796
+ if (((_a = leftValue[0]) === null || _a === void 0 ? void 0 : _a.value) === true && ((_b = rightValue[0]) === null || _b === void 0 ? void 0 : _b.value) === true) {
9797
+ return booleanToTypedValue(true);
9722
9798
  }
9723
- else if (typeAtom instanceof DotAtom) {
9724
- typeName = typeAtom.left.name + '.' + typeAtom.right.name;
9799
+ if (((_c = leftValue[0]) === null || _c === void 0 ? void 0 : _c.value) === false || ((_d = rightValue[0]) === null || _d === void 0 ? void 0 : _d.value) === false) {
9800
+ return booleanToTypedValue(false);
9725
9801
  }
9726
- if (!typeName) {
9727
- return [];
9802
+ return [];
9803
+ }
9804
+ }
9805
+ class OrAtom {
9806
+ constructor(left, right) {
9807
+ this.left = left;
9808
+ this.right = right;
9809
+ }
9810
+ eval(context) {
9811
+ const leftValue = this.left.eval(context);
9812
+ if (toJsBoolean(leftValue)) {
9813
+ return leftValue;
9728
9814
  }
9729
- return input.map((value) => ({ type: exports.PropertyType.boolean, value: fhirPathIs(value, typeName) }));
9730
- },
9731
- /*
9732
- * 6.5 Boolean logic
9733
- */
9734
- /**
9735
- * 6.5.3. not() : Boolean
9736
- *
9737
- * Returns true if the input collection evaluates to false, and false if it evaluates to true. Otherwise, the result is empty ({ }):
9738
- *
9739
- * @param input
9740
- * @returns
9741
- */
9742
- not: (input) => {
9743
- return functions.toBoolean(input).map((value) => ({ type: exports.PropertyType.boolean, value: !value.value }));
9744
- },
9745
- /*
9746
- * Additional functions
9747
- * See: https://hl7.org/fhir/fhirpath.html#functions
9748
- */
9749
- /**
9750
- * For each item in the collection, if it is a string that is a uri (or canonical or url), locate the target of the reference, and add it to the resulting collection. If the item does not resolve to a resource, the item is ignored and nothing is added to the output collection.
9751
- * The items in the collection may also represent a Reference, in which case the Reference.reference is resolved.
9752
- * @param input The input collection.
9753
- * @returns
9754
- */
9755
- resolve: (input) => {
9756
- return input
9757
- .map((e) => {
9758
- const value = e.value;
9759
- let refStr;
9760
- if (typeof value === 'string') {
9761
- refStr = value;
9762
- }
9763
- else if (typeof value === 'object') {
9764
- const ref = value;
9765
- if (ref.resource) {
9766
- return toTypedValue(ref.resource);
9767
- }
9768
- refStr = ref.reference;
9769
- }
9770
- if (!refStr) {
9771
- return { type: exports.PropertyType.BackboneElement, value: null };
9772
- }
9773
- const [resourceType, id] = refStr.split('/');
9774
- return { type: exports.PropertyType.BackboneElement, value: { resourceType, id } };
9775
- })
9776
- .filter((e) => !!e.value);
9777
- },
9778
- /**
9779
- * The as operator can be used to treat a value as a specific type.
9780
- * @param input The input value.
9781
- * @returns The value as the specific type.
9782
- */
9783
- as: (input) => {
9784
- return input;
9785
- },
9786
- /*
9787
- * 12. Formal Specifications
9788
- */
9789
- /**
9790
- * Returns the type of the input.
9791
- *
9792
- * 12.2. Model Information
9793
- *
9794
- * The model information returned by the reflection function type() is specified as an
9795
- * XML Schema document (xsd) and included in this specification at the following link:
9796
- * https://hl7.org/fhirpath/modelinfo.xsd
9797
- *
9798
- * See: https://hl7.org/fhirpath/#model-information
9799
- *
9800
- * @param input The input collection.
9801
- * @returns
9802
- */
9803
- type: (input) => {
9804
- return input.map(({ value }) => {
9805
- if (typeof value === 'boolean') {
9806
- return { type: exports.PropertyType.BackboneElement, value: { namespace: 'System', name: 'Boolean' } };
9807
- }
9808
- if (typeof value === 'number') {
9809
- return { type: exports.PropertyType.BackboneElement, value: { namespace: 'System', name: 'Integer' } };
9810
- }
9811
- if (value && typeof value === 'object' && 'resourceType' in value) {
9812
- return {
9813
- type: exports.PropertyType.BackboneElement,
9814
- value: { namespace: 'FHIR', name: value.resourceType },
9815
- };
9816
- }
9817
- return { type: exports.PropertyType.BackboneElement, value: null };
9818
- });
9819
- },
9820
- conformsTo: (input, systemAtom) => {
9821
- const system = systemAtom.eval(input)[0].value;
9822
- if (!system.startsWith('http://hl7.org/fhir/StructureDefinition/')) {
9823
- throw new Error('Expected a StructureDefinition URL');
9815
+ const rightValue = this.right.eval(context);
9816
+ if (toJsBoolean(rightValue)) {
9817
+ return rightValue;
9824
9818
  }
9825
- const expectedResourceType = system.replace('http://hl7.org/fhir/StructureDefinition/', '');
9826
- return input.map((value) => {
9827
- var _a;
9828
- return ({
9829
- type: exports.PropertyType.boolean,
9830
- value: ((_a = value.value) === null || _a === void 0 ? void 0 : _a.resourceType) === expectedResourceType,
9831
- });
9832
- });
9833
- },
9834
- };
9835
- /*
9836
- * Helper utilities
9837
- */
9838
- function applyStringFunc(func, input, ...argsAtoms) {
9839
- if (input.length === 0) {
9840
9819
  return [];
9841
9820
  }
9842
- const [{ value }] = validateInput(input, 1);
9843
- if (typeof value !== 'string') {
9844
- throw new Error('String function cannot be called with non-string');
9821
+ }
9822
+ /**
9823
+ * 6.5.4. xor
9824
+ * Returns true if exactly one of the operands evaluates to true,
9825
+ * false if either both operands evaluate to true or both operands evaluate to false,
9826
+ * and the empty collection otherwise.
9827
+ */
9828
+ class XorAtom {
9829
+ constructor(left, right) {
9830
+ this.left = left;
9831
+ this.right = right;
9845
9832
  }
9846
- const result = func(value, ...argsAtoms.map((atom) => { var _a, _b; return atom && ((_b = (_a = atom.eval(input)) === null || _a === void 0 ? void 0 : _a[0]) === null || _b === void 0 ? void 0 : _b.value); }));
9847
- if (result === undefined) {
9833
+ eval(context) {
9834
+ const leftResult = this.left.eval(context);
9835
+ const rightResult = this.right.eval(context);
9836
+ if (leftResult.length === 0 && rightResult.length === 0) {
9837
+ return [];
9838
+ }
9839
+ const leftValue = leftResult.length === 0 ? null : leftResult[0].value;
9840
+ const rightValue = rightResult.length === 0 ? null : rightResult[0].value;
9841
+ if ((leftValue === true && rightValue !== true) || (leftValue !== true && rightValue === true)) {
9842
+ return booleanToTypedValue(true);
9843
+ }
9844
+ if ((leftValue === true && rightValue === true) || (leftValue === false && rightValue === false)) {
9845
+ return booleanToTypedValue(false);
9846
+ }
9848
9847
  return [];
9849
9848
  }
9850
- if (Array.isArray(result)) {
9851
- return result.map(toTypedValue);
9852
- }
9853
- return [toTypedValue(result)];
9854
9849
  }
9855
- function applyMathFunc(func, input, ...argsAtoms) {
9856
- if (input.length === 0) {
9857
- return [];
9850
+ class FunctionAtom {
9851
+ constructor(name, args, impl) {
9852
+ this.name = name;
9853
+ this.args = args;
9854
+ this.impl = impl;
9858
9855
  }
9859
- const [{ value }] = validateInput(input, 1);
9860
- const quantity = isQuantity(value);
9861
- const numberInput = quantity ? value.value : value;
9862
- if (typeof numberInput !== 'number') {
9863
- throw new Error('Math function cannot be called with non-number');
9856
+ eval(context) {
9857
+ return this.impl(context, ...this.args);
9864
9858
  }
9865
- const result = func(numberInput, ...argsAtoms.map((atom) => { var _a, _b; return (_b = (_a = atom.eval(input)) === null || _a === void 0 ? void 0 : _a[0]) === null || _b === void 0 ? void 0 : _b.value; }));
9866
- const type = quantity ? exports.PropertyType.Quantity : input[0].type;
9867
- const returnValue = quantity ? Object.assign(Object.assign({}, value), { value: result }) : result;
9868
- return [{ type, value: returnValue }];
9869
9859
  }
9870
- function validateInput(input, count) {
9871
- if (input.length !== count) {
9872
- throw new Error(`Expected ${count} arguments`);
9860
+ class IndexerAtom {
9861
+ constructor(left, expr) {
9862
+ this.left = left;
9863
+ this.expr = expr;
9873
9864
  }
9874
- for (const element of input) {
9875
- if (element === null || element === undefined) {
9876
- throw new Error('Expected non-null argument');
9865
+ eval(context) {
9866
+ const evalResult = this.expr.eval(context);
9867
+ if (evalResult.length !== 1) {
9868
+ return [];
9869
+ }
9870
+ const index = evalResult[0].value;
9871
+ if (typeof index !== 'number') {
9872
+ throw new Error(`Invalid indexer expression: should return integer}`);
9873
+ }
9874
+ const leftResult = this.left.eval(context);
9875
+ if (!(index in leftResult)) {
9876
+ return [];
9877
9877
  }
9878
+ return [leftResult[index]];
9878
9879
  }
9879
- return input;
9880
9880
  }
9881
9881
 
9882
9882
  var _Tokenizer_instances, _Tokenizer_str, _Tokenizer_pos, _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;
@@ -11010,7 +11010,6 @@
11010
11010
  exports.capitalize = capitalize;
11011
11011
  exports.createReference = createReference;
11012
11012
  exports.createSchema = createSchema;
11013
- exports.createTypeSchema = createTypeSchema;
11014
11013
  exports.created = created;
11015
11014
  exports.deepClone = deepClone;
11016
11015
  exports.deepEquals = deepEquals$1;
@@ -11053,6 +11052,7 @@
11053
11052
  exports.indexSearchParameter = indexSearchParameter;
11054
11053
  exports.indexStructureDefinition = indexStructureDefinition;
11055
11054
  exports.indexStructureDefinitionBundle = indexStructureDefinitionBundle;
11055
+ exports.isEmpty = isEmpty;
11056
11056
  exports.isGone = isGone;
11057
11057
  exports.isLowerCase = isLowerCase;
11058
11058
  exports.isNotFound = isNotFound;