@medplum/core 2.0.14 → 2.0.16
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/cjs/index.cjs +1244 -1101
- package/dist/cjs/index.cjs.map +1 -1
- package/dist/cjs/index.min.cjs +1 -1
- package/dist/esm/base64.mjs +33 -0
- package/dist/esm/base64.mjs.map +1 -0
- package/dist/esm/cache.mjs +17 -23
- package/dist/esm/cache.mjs.map +1 -1
- package/dist/esm/client.mjs +500 -413
- package/dist/esm/client.mjs.map +1 -1
- package/dist/esm/eventtarget.mjs +6 -11
- package/dist/esm/eventtarget.mjs.map +1 -1
- package/dist/esm/fhirlexer/parse.mjs +15 -23
- package/dist/esm/fhirlexer/parse.mjs.map +1 -1
- package/dist/esm/fhirlexer/tokenize.mjs +190 -180
- package/dist/esm/fhirlexer/tokenize.mjs.map +1 -1
- package/dist/esm/fhirmapper/parse.mjs +264 -252
- package/dist/esm/fhirmapper/parse.mjs.map +1 -1
- package/dist/esm/fhirmapper/tokenize.mjs +0 -1
- package/dist/esm/fhirmapper/tokenize.mjs.map +1 -1
- package/dist/esm/fhirpath/atoms.mjs +0 -1
- package/dist/esm/fhirpath/atoms.mjs.map +1 -1
- package/dist/esm/fhirpath/parse.mjs +0 -1
- package/dist/esm/fhirpath/parse.mjs.map +1 -1
- package/dist/esm/fhirpath/tokenize.mjs +0 -1
- package/dist/esm/fhirpath/tokenize.mjs.map +1 -1
- package/dist/esm/filter/parse.mjs +0 -2
- package/dist/esm/filter/parse.mjs.map +1 -1
- package/dist/esm/filter/tokenize.mjs +0 -1
- package/dist/esm/filter/tokenize.mjs.map +1 -1
- package/dist/esm/format.mjs +24 -15
- package/dist/esm/format.mjs.map +1 -1
- package/dist/esm/index.min.mjs +1 -1
- package/dist/esm/index.mjs +2 -2
- package/dist/esm/jwt.mjs +2 -9
- package/dist/esm/jwt.mjs.map +1 -1
- package/dist/esm/outcomes.mjs +15 -1
- package/dist/esm/outcomes.mjs.map +1 -1
- package/dist/esm/readablepromise.mjs +18 -23
- package/dist/esm/readablepromise.mjs.map +1 -1
- package/dist/esm/schema.mjs +146 -123
- package/dist/esm/schema.mjs.map +1 -1
- package/dist/esm/search/match.mjs +0 -2
- package/dist/esm/search/match.mjs.map +1 -1
- package/dist/esm/search/search.mjs +15 -9
- package/dist/esm/search/search.mjs.map +1 -1
- package/dist/esm/storage.mjs +13 -19
- package/dist/esm/storage.mjs.map +1 -1
- package/dist/types/base64.d.ts +14 -0
- package/dist/types/cache.d.ts +3 -1
- package/dist/types/client.d.ts +153 -1
- package/dist/types/eventtarget.d.ts +1 -1
- package/dist/types/fhirlexer/parse.d.ts +5 -2
- package/dist/types/fhirlexer/tokenize.d.ts +28 -1
- package/dist/types/format.d.ts +3 -1
- package/dist/types/outcomes.d.ts +1 -0
- package/dist/types/readablepromise.d.ts +4 -1
- package/dist/types/schema.d.ts +33 -1
- package/dist/types/storage.d.ts +2 -2
- package/package.json +1 -1
- package/dist/esm/node_modules/tslib/tslib.es6.mjs +0 -30
- package/dist/esm/node_modules/tslib/tslib.es6.mjs.map +0 -1
package/dist/esm/schema.mjs.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"schema.mjs","sources":["../../src/schema.ts"],"sourcesContent":["import { ElementDefinition, OperationOutcomeIssue, Resource } from '@medplum/fhirtypes';\nimport { getTypedPropertyValue, toTypedValue } from './fhirpath';\nimport { OperationOutcomeError, validationError } from './outcomes';\nimport { globalSchema, PropertyType, TypedValue } from './types';\nimport { capitalize, getExtensionValue, isEmpty, isLowerCase } from './utils';\n\n/*\n * This file provides schema validation utilities for FHIR JSON objects.\n *\n * See: [JSON Representation of Resources](https://hl7.org/fhir/json.html)\n * See: [FHIR Data Types](https://www.hl7.org/fhir/datatypes.html)\n */\n\nconst fhirTypeToJsType: Record<string, string> = {\n base64Binary: 'string',\n boolean: 'boolean',\n canonical: 'string',\n code: 'string',\n date: 'string',\n dateTime: 'string',\n decimal: 'number',\n id: 'string',\n instant: 'string',\n integer: 'number',\n markdown: 'string',\n oid: 'string',\n positiveInt: 'number',\n string: 'string',\n time: 'string',\n unsignedInt: 'number',\n uri: 'string',\n url: 'string',\n uuid: 'string',\n xhtml: 'string',\n 'http://hl7.org/fhirpath/System.String': 'string',\n};\n\nconst baseResourceProperties = new Set<string>([\n // Resource\n 'resourceType',\n 'id',\n 'meta',\n 'implicitRules',\n 'language',\n\n // DomainResource\n 'text',\n 'contained',\n 'extension',\n 'modifierExtension',\n]);\n\n/**\n * Returns true if the given string is a valid FHIR resource type.\n *\n * ```ts\n * isResourceType('Patient'); // true\n * isResourceType('XYZ'); // false\n * ```\n *\n * Note that this depends on globalSchema, which is populated by the StructureDefinition loader.\n *\n * In a server context, you can load all schema definitions:\n *\n * ```ts\n * import { indexStructureDefinitionBundle } from '@medplum/core';\n * import { readJson } from '@medplum/definitions';\n * import { Bundle } from '@medplum/fhirtypes';\n *\n * indexStructureDefinitionBundle(readJson('fhir/r4/profiles-resources.json') as Bundle);\n * ```\n *\n * In a client context, you can load the schema definitions using MedplumClient:\n *\n * ```ts\n * import { MedplumClient } from '@medplum/core';\n *\n * const medplum = new MedplumClient();\n * await medplum.requestSchema('Patient');\n * ```\n *\n * @param resourceType The candidate resource type string.\n * @returns True if the resource type is a valid FHIR resource type.\n */\nexport function isResourceType(resourceType: string): boolean {\n const typeSchema = globalSchema.types[resourceType];\n return (\n typeSchema &&\n typeSchema.structureDefinition.id === resourceType &&\n typeSchema.structureDefinition.kind === 'resource'\n );\n}\n\n/**\n * Validates that the given string is a valid FHIR resource type.\n * On success, silently returns void.\n * On failure, throws an OperationOutcomeError.\n *\n * ```ts\n * validateResourceType('Patient'); // nothing\n * validateResourceType('XYZ'); // throws OperationOutcomeError\n * ```\n *\n * Note that this depends on globalSchema, which is populated by the StructureDefinition loader.\n *\n * In a server context, you can load all schema definitions:\n *\n * ```ts\n * import { indexStructureDefinitionBundle } from '@medplum/core';\n * import { readJson } from '@medplum/definitions';\n * import { Bundle } from '@medplum/fhirtypes';\n *\n * indexStructureDefinitionBundle(readJson('fhir/r4/profiles-resources.json') as Bundle);\n * ```\n *\n * In a client context, you can load the schema definitions using MedplumClient:\n *\n * ```ts\n * import { MedplumClient } from '@medplum/core';\n *\n * const medplum = new MedplumClient();\n * await medplum.requestSchema('Patient');\n * ```\n *\n * @param resourceType The candidate resource type string.\n * @returns True if the resource type is a valid FHIR resource type.\n */\nexport function validateResourceType(resourceType: string): void {\n if (!resourceType) {\n throw new OperationOutcomeError(validationError('Resource type is null'));\n }\n if (!isResourceType(resourceType)) {\n throw new OperationOutcomeError(validationError('Unknown resource type'));\n }\n}\n\n/**\n * Validates a candidate FHIR resource object.\n * On success, silently returns void.\n * On failure, throws an OperationOutcomeError with issues for each violation.\n *\n * ```ts\n * validateResource({ resourceType: 'Patient' }); // nothing\n * validateResource({ resourceType: 'XYZ' }); // throws OperationOutcomeError\n * ```\n *\n * Note that this depends on globalSchema, which is populated by the StructureDefinition loader.\n *\n * In a server context, you can load all schema definitions:\n *\n * ```ts\n * import { indexStructureDefinitionBundle } from '@medplum/core';\n * import { readJson } from '@medplum/definitions';\n * import { Bundle } from '@medplum/fhirtypes';\n *\n * indexStructureDefinitionBundle(readJson('fhir/r4/profiles-resources.json') as Bundle);\n * ```\n *\n * In a client context, you can load the schema definitions using MedplumClient:\n *\n * ```ts\n * import { MedplumClient } from '@medplum/core';\n *\n * const medplum = new MedplumClient();\n * await medplum.requestSchema('Patient');\n * ```\n *\n * @param resourceType The candidate resource type string.\n * @returns True if the resource type is a valid FHIR resource type.\n */\nexport function validateResource<T extends Resource>(resource: T): void {\n new FhirSchemaValidator(resource).validate();\n}\n\nexport class FhirSchemaValidator<T extends Resource> {\n readonly #issues: OperationOutcomeIssue[];\n readonly #root: T;\n\n constructor(root: T) {\n this.#issues = [];\n this.#root = root;\n }\n\n validate(): void {\n const resource = this.#root;\n if (!resource) {\n throw new OperationOutcomeError(validationError('Resource is null'));\n }\n\n const resourceType = resource.resourceType;\n if (!resourceType) {\n throw new OperationOutcomeError(validationError('Missing resource type'));\n }\n\n // Check for \"null\" once for the entire object hierarchy\n checkForNull(resource, '', this.#issues);\n\n this.#validateObject(toTypedValue(resource), resourceType);\n\n if (this.#issues.length > 0) {\n throw new OperationOutcomeError({\n resourceType: 'OperationOutcome',\n issue: this.#issues,\n });\n }\n }\n\n #validateObject(typedValue: TypedValue, path: string): void {\n const definition = globalSchema.types[typedValue.type];\n if (!definition) {\n throw new OperationOutcomeError(validationError('Unknown type: ' + typedValue.type));\n }\n\n const propertyDefinitions = definition.properties;\n this.#checkProperties(path, propertyDefinitions, typedValue);\n this.#checkAdditionalProperties(path, typedValue, propertyDefinitions);\n }\n\n #checkProperties(path: string, propertyDefinitions: Record<string, ElementDefinition>, typedValue: TypedValue): void {\n for (const [key, elementDefinition] of Object.entries(propertyDefinitions)) {\n this.#checkProperty(path + '.' + key, elementDefinition, typedValue);\n }\n }\n\n #checkProperty(path: string, elementDefinition: ElementDefinition, typedValue: TypedValue): void {\n const propertyName = path.split('.').pop() as string;\n const value = getTypedPropertyValue(typedValue, propertyName);\n\n if (isEmpty(value)) {\n if (elementDefinition.min !== undefined && elementDefinition.min > 0) {\n this.#issues.push(createStructureIssue(path, 'Missing required property'));\n }\n return;\n }\n\n if (elementDefinition.max === '*') {\n if (!Array.isArray(value)) {\n this.#issues.push(createStructureIssue(path, 'Expected array for property'));\n return;\n }\n for (const item of value) {\n this.#checkPropertyValue(path, elementDefinition, item);\n }\n } else {\n if (Array.isArray(value)) {\n this.#issues.push(createStructureIssue(path, 'Expected single value for property'));\n return;\n }\n this.#checkPropertyValue(path, elementDefinition, value as TypedValue);\n }\n }\n\n #checkPropertyValue(path: string, elementDefinition: ElementDefinition, typedValue: TypedValue): void {\n if (typedValue.value === null) {\n // Null handled separately\n return;\n }\n\n if (isLowerCase(typedValue.type.charAt(0))) {\n this.#validatePrimitiveType(elementDefinition, typedValue);\n } else {\n this.#validateObject(typedValue, path);\n }\n }\n\n #validatePrimitiveType(elementDefinition: ElementDefinition, typedValue: TypedValue): void {\n const { type, value } = typedValue;\n\n if (value === null) {\n // Null handled separately, so this code should never be reached\n // Leaving this check in place for now, in case we change the null handling\n return;\n }\n\n // First, make sure the value is the correct JS type\n const expectedType = fhirTypeToJsType[typedValue.type];\n if (typeof value !== expectedType) {\n this.#createIssue(elementDefinition, 'Invalid type for ' + type);\n return;\n }\n\n // Then, perform additional checks for specialty types\n if (expectedType === 'string') {\n this.#validateString(elementDefinition, type as PropertyType, value as string);\n } else if (expectedType === 'number') {\n this.#validateNumber(elementDefinition, type as PropertyType, value as number);\n }\n }\n\n #validateString(elementDefinition: ElementDefinition, type: PropertyType, value: string): void {\n if (!value.trim()) {\n this.#createIssue(elementDefinition, 'Invalid empty string');\n return;\n }\n\n // Try to get the regex\n const valueDefinition = globalSchema.types[type]?.properties?.['value'];\n if (valueDefinition?.type) {\n const regex = getExtensionValue(valueDefinition.type[0], 'http://hl7.org/fhir/StructureDefinition/regex');\n if (regex) {\n if (!value.match(new RegExp(regex))) {\n this.#createIssue(elementDefinition, 'Invalid ' + type + ' format');\n }\n }\n }\n }\n\n #validateNumber(elementDefinition: ElementDefinition, type: PropertyType, value: number): void {\n if (isNaN(value) || !isFinite(value)) {\n this.#createIssue(elementDefinition, 'Invalid ' + type + ' value');\n return;\n }\n\n if (isIntegerType(type) && !Number.isInteger(value)) {\n this.#createIssue(elementDefinition, 'Number is not an integer');\n }\n\n if (type === PropertyType.positiveInt && value <= 0) {\n this.#createIssue(elementDefinition, 'Number is less than or equal to zero');\n }\n\n if (type === PropertyType.unsignedInt && value < 0) {\n this.#createIssue(elementDefinition, 'Number is negative');\n }\n }\n\n #checkAdditionalProperties(\n path: string,\n typedValue: TypedValue,\n propertyDefinitions: Record<string, ElementDefinition>\n ): void {\n const object = typedValue.value as Record<string, unknown>;\n for (const key of Object.keys(object)) {\n this.#checkAdditionalProperty(path, key, typedValue, propertyDefinitions);\n }\n }\n\n /**\n * Checks if the given property is allowed on the given object.\n * @param path The path of the current object.\n * @param key The key of a property to check.\n * @param typedValue The current object.\n * @param propertyDefinitions The property definitions of the current object.\n */\n #checkAdditionalProperty(\n path: string,\n key: string,\n typedValue: TypedValue,\n propertyDefinitions: Record<string, ElementDefinition>\n ): void {\n if (\n !baseResourceProperties.has(key) &&\n !(key in propertyDefinitions) &&\n !isChoiceOfType(key, typedValue, propertyDefinitions) &&\n !this.#checkPrimitiveElement(path, key, typedValue)\n ) {\n const expression = `${path}.${key}`;\n this.#issues.push(createStructureIssue(expression, `Invalid additional property \"${expression}\"`));\n }\n }\n\n /**\n * Checks the element for a primitive.\n *\n * FHIR elements with primitive data types are represented in two parts:\n * 1) A JSON property with the name of the element, which has a JSON type of number, boolean, or string\n * 2) a JSON property with _ prepended to the name of the element, which, if present, contains the value's id and/or extensions\n *\n * See: https://hl7.org/fhir/json.html#primitive\n *\n * @param path The path to the property\n * @param key\n * @param typedValue\n */\n #checkPrimitiveElement(path: string, key: string, typedValue: TypedValue): boolean {\n // Primitive element starts with underscore\n if (!key.startsWith('_')) {\n return false;\n }\n\n // Validate the non-underscore property exists\n const primitiveKey = key.slice(1);\n if (!(primitiveKey in typedValue.value)) {\n return false;\n }\n\n // Then validate the element\n this.#validateObject({ type: 'Element', value: typedValue.value[key] }, path);\n return true;\n }\n\n #createIssue(elementDefinition: ElementDefinition, message: string): void {\n this.#issues.push(createStructureIssue(elementDefinition.path as string, message));\n }\n}\n\nfunction isIntegerType(propertyType: PropertyType): boolean {\n return (\n propertyType === PropertyType.integer ||\n propertyType === PropertyType.positiveInt ||\n propertyType === PropertyType.unsignedInt\n );\n}\n\nfunction isChoiceOfType(\n key: string,\n typedValue: TypedValue,\n propertyDefinitions: Record<string, ElementDefinition>\n): boolean {\n for (const propertyName of Object.keys(propertyDefinitions)) {\n if (!propertyName.endsWith('[x]')) {\n continue;\n }\n const basePropertyName = propertyName.replace('[x]', '');\n if (!key.startsWith(basePropertyName)) {\n continue;\n }\n let typedPropertyValue = getTypedPropertyValue(typedValue, propertyName);\n if (!typedPropertyValue) {\n continue;\n }\n if (Array.isArray(typedPropertyValue)) {\n // At present, there are no choice types that are arrays in the FHIR spec\n // Leaving this here to make TypeScript happy, and in case that changes\n typedPropertyValue = typedPropertyValue[0];\n }\n if (typedPropertyValue && key === basePropertyName + capitalize(typedPropertyValue.type)) {\n return true;\n }\n }\n return false;\n}\n\n/**\n * Recursively checks for null values in an object.\n *\n * Note that \"null\" is a special value in JSON that is not allowed in FHIR.\n *\n * @param value Input value of any type.\n * @param path Path string to the value for OperationOutcome.\n * @param issues Output list of issues.\n */\nexport function checkForNull(value: unknown, path: string, issues: OperationOutcomeIssue[]): void {\n if (value === null) {\n issues.push(createStructureIssue(path, 'Invalid null value'));\n } else if (Array.isArray(value)) {\n checkArrayForNull(value, path, issues);\n } else if (typeof value === 'object') {\n checkObjectForNull(value as Record<string, unknown>, path, issues);\n }\n}\n\nfunction checkArrayForNull(array: unknown[], path: string, issues: OperationOutcomeIssue[]): void {\n for (let i = 0; i < array.length; i++) {\n if (array[i] === undefined) {\n issues.push(createStructureIssue(`${path}[${i}]`, 'Invalid undefined value'));\n } else {\n checkForNull(array[i], `${path}[${i}]`, issues);\n }\n }\n}\n\nfunction checkObjectForNull(obj: Record<string, unknown>, path: string, issues: OperationOutcomeIssue[]): void {\n for (const [key, value] of Object.entries(obj)) {\n checkForNull(value, `${path}${path ? '.' : ''}${key}`, issues);\n }\n}\n\nexport function createStructureIssue(expression: string, details: string): OperationOutcomeIssue {\n return {\n severity: 'error',\n code: 'structure',\n details: {\n text: details,\n },\n expression: [expression],\n };\n}\n"],"names":[],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"schema.mjs","sources":["../../src/schema.ts"],"sourcesContent":["import { ElementDefinition, OperationOutcomeIssue, Resource } from '@medplum/fhirtypes';\nimport { getTypedPropertyValue, toTypedValue } from './fhirpath';\nimport { OperationOutcomeError, validationError } from './outcomes';\nimport { globalSchema, PropertyType, TypedValue } from './types';\nimport { capitalize, getExtensionValue, isEmpty, isLowerCase } from './utils';\n\n/*\n * This file provides schema validation utilities for FHIR JSON objects.\n *\n * See: [JSON Representation of Resources](https://hl7.org/fhir/json.html)\n * See: [FHIR Data Types](https://www.hl7.org/fhir/datatypes.html)\n */\n\nconst fhirTypeToJsType: Record<string, string> = {\n base64Binary: 'string',\n boolean: 'boolean',\n canonical: 'string',\n code: 'string',\n date: 'string',\n dateTime: 'string',\n decimal: 'number',\n id: 'string',\n instant: 'string',\n integer: 'number',\n markdown: 'string',\n oid: 'string',\n positiveInt: 'number',\n string: 'string',\n time: 'string',\n unsignedInt: 'number',\n uri: 'string',\n url: 'string',\n uuid: 'string',\n xhtml: 'string',\n 'http://hl7.org/fhirpath/System.String': 'string',\n};\n\nconst baseResourceProperties = new Set<string>([\n // Resource\n 'resourceType',\n 'id',\n 'meta',\n 'implicitRules',\n 'language',\n\n // DomainResource\n 'text',\n 'contained',\n 'extension',\n 'modifierExtension',\n]);\n\n/**\n * Returns true if the given string is a valid FHIR resource type.\n *\n * ```ts\n * isResourceType('Patient'); // true\n * isResourceType('XYZ'); // false\n * ```\n *\n * Note that this depends on globalSchema, which is populated by the StructureDefinition loader.\n *\n * In a server context, you can load all schema definitions:\n *\n * ```ts\n * import { indexStructureDefinitionBundle } from '@medplum/core';\n * import { readJson } from '@medplum/definitions';\n * import { Bundle } from '@medplum/fhirtypes';\n *\n * indexStructureDefinitionBundle(readJson('fhir/r4/profiles-resources.json') as Bundle);\n * ```\n *\n * In a client context, you can load the schema definitions using MedplumClient:\n *\n * ```ts\n * import { MedplumClient } from '@medplum/core';\n *\n * const medplum = new MedplumClient();\n * await medplum.requestSchema('Patient');\n * ```\n *\n * @param resourceType The candidate resource type string.\n * @returns True if the resource type is a valid FHIR resource type.\n */\nexport function isResourceType(resourceType: string): boolean {\n const typeSchema = globalSchema.types[resourceType];\n return (\n typeSchema &&\n typeSchema.structureDefinition.id === resourceType &&\n typeSchema.structureDefinition.kind === 'resource'\n );\n}\n\n/**\n * Validates that the given string is a valid FHIR resource type.\n * On success, silently returns void.\n * On failure, throws an OperationOutcomeError.\n *\n * ```ts\n * validateResourceType('Patient'); // nothing\n * validateResourceType('XYZ'); // throws OperationOutcomeError\n * ```\n *\n * Note that this depends on globalSchema, which is populated by the StructureDefinition loader.\n *\n * In a server context, you can load all schema definitions:\n *\n * ```ts\n * import { indexStructureDefinitionBundle } from '@medplum/core';\n * import { readJson } from '@medplum/definitions';\n * import { Bundle } from '@medplum/fhirtypes';\n *\n * indexStructureDefinitionBundle(readJson('fhir/r4/profiles-resources.json') as Bundle);\n * ```\n *\n * In a client context, you can load the schema definitions using MedplumClient:\n *\n * ```ts\n * import { MedplumClient } from '@medplum/core';\n *\n * const medplum = new MedplumClient();\n * await medplum.requestSchema('Patient');\n * ```\n *\n * @param resourceType The candidate resource type string.\n * @returns True if the resource type is a valid FHIR resource type.\n */\nexport function validateResourceType(resourceType: string): void {\n if (!resourceType) {\n throw new OperationOutcomeError(validationError('Resource type is null'));\n }\n if (!isResourceType(resourceType)) {\n throw new OperationOutcomeError(validationError('Unknown resource type'));\n }\n}\n\n/**\n * Validates a candidate FHIR resource object.\n * On success, silently returns void.\n * On failure, throws an OperationOutcomeError with issues for each violation.\n *\n * ```ts\n * validateResource({ resourceType: 'Patient' }); // nothing\n * validateResource({ resourceType: 'XYZ' }); // throws OperationOutcomeError\n * ```\n *\n * Note that this depends on globalSchema, which is populated by the StructureDefinition loader.\n *\n * In a server context, you can load all schema definitions:\n *\n * ```ts\n * import { indexStructureDefinitionBundle } from '@medplum/core';\n * import { readJson } from '@medplum/definitions';\n * import { Bundle } from '@medplum/fhirtypes';\n *\n * indexStructureDefinitionBundle(readJson('fhir/r4/profiles-resources.json') as Bundle);\n * ```\n *\n * In a client context, you can load the schema definitions using MedplumClient:\n *\n * ```ts\n * import { MedplumClient } from '@medplum/core';\n *\n * const medplum = new MedplumClient();\n * await medplum.requestSchema('Patient');\n * ```\n *\n * @param resourceType The candidate resource type string.\n * @returns True if the resource type is a valid FHIR resource type.\n */\nexport function validateResource<T extends Resource>(resource: T): void {\n new FhirSchemaValidator(resource).validate();\n}\n\nexport class FhirSchemaValidator<T extends Resource> {\n private readonly issues: OperationOutcomeIssue[];\n private readonly root: T;\n\n constructor(root: T) {\n this.issues = [];\n this.root = root;\n }\n\n validate(): void {\n const resource = this.root;\n if (!resource) {\n throw new OperationOutcomeError(validationError('Resource is null'));\n }\n\n const resourceType = resource.resourceType;\n if (!resourceType) {\n throw new OperationOutcomeError(validationError('Missing resource type'));\n }\n\n // Check for \"null\" once for the entire object hierarchy\n checkForNull(resource, '', this.issues);\n\n this.validateObject(toTypedValue(resource), resourceType);\n\n if (this.issues.length > 0) {\n throw new OperationOutcomeError({\n resourceType: 'OperationOutcome',\n issue: this.issues,\n });\n }\n }\n\n private validateObject(typedValue: TypedValue, path: string): void {\n const definition = globalSchema.types[typedValue.type];\n if (!definition) {\n throw new OperationOutcomeError(validationError('Unknown type: ' + typedValue.type));\n }\n\n const propertyDefinitions = definition.properties;\n this.checkProperties(path, propertyDefinitions, typedValue);\n this.checkAdditionalProperties(path, typedValue, propertyDefinitions);\n }\n\n private checkProperties(\n path: string,\n propertyDefinitions: Record<string, ElementDefinition>,\n typedValue: TypedValue\n ): void {\n for (const [key, elementDefinition] of Object.entries(propertyDefinitions)) {\n this.checkProperty(path + '.' + key, elementDefinition, typedValue);\n }\n }\n\n private checkProperty(path: string, elementDefinition: ElementDefinition, typedValue: TypedValue): void {\n const propertyName = path.split('.').pop() as string;\n const value = getTypedPropertyValue(typedValue, propertyName);\n\n if (isEmpty(value)) {\n if (elementDefinition.min !== undefined && elementDefinition.min > 0) {\n this.issues.push(createStructureIssue(path, 'Missing required property'));\n }\n return;\n }\n\n if (elementDefinition.max === '*') {\n if (!Array.isArray(value)) {\n this.issues.push(createStructureIssue(path, 'Expected array for property'));\n return;\n }\n for (const item of value) {\n this.checkPropertyValue(path, elementDefinition, item);\n }\n } else {\n if (Array.isArray(value)) {\n this.issues.push(createStructureIssue(path, 'Expected single value for property'));\n return;\n }\n this.checkPropertyValue(path, elementDefinition, value as TypedValue);\n }\n }\n\n private checkPropertyValue(path: string, elementDefinition: ElementDefinition, typedValue: TypedValue): void {\n if (typedValue.value === null) {\n // Null handled separately\n return;\n }\n\n if (isLowerCase(typedValue.type.charAt(0))) {\n this.validatePrimitiveType(elementDefinition, typedValue);\n } else {\n this.validateObject(typedValue, path);\n }\n }\n\n private validatePrimitiveType(elementDefinition: ElementDefinition, typedValue: TypedValue): void {\n const { type, value } = typedValue;\n\n if (value === null) {\n // Null handled separately, so this code should never be reached\n // Leaving this check in place for now, in case we change the null handling\n return;\n }\n\n // First, make sure the value is the correct JS type\n const expectedType = fhirTypeToJsType[typedValue.type];\n if (typeof value !== expectedType) {\n this.createIssue(elementDefinition, 'Invalid type for ' + type);\n return;\n }\n\n // Then, perform additional checks for specialty types\n if (expectedType === 'string') {\n this.validateString(elementDefinition, type as PropertyType, value as string);\n } else if (expectedType === 'number') {\n this.validateNumber(elementDefinition, type as PropertyType, value as number);\n }\n }\n\n private validateString(elementDefinition: ElementDefinition, type: PropertyType, value: string): void {\n if (!value.trim()) {\n this.createIssue(elementDefinition, 'Invalid empty string');\n return;\n }\n\n // Try to get the regex\n const valueDefinition = globalSchema.types[type]?.properties?.['value'];\n if (valueDefinition?.type) {\n const regex = getExtensionValue(valueDefinition.type[0], 'http://hl7.org/fhir/StructureDefinition/regex');\n if (regex) {\n if (!value.match(new RegExp(regex))) {\n this.createIssue(elementDefinition, 'Invalid ' + type + ' format');\n }\n }\n }\n }\n\n private validateNumber(elementDefinition: ElementDefinition, type: PropertyType, value: number): void {\n if (isNaN(value) || !isFinite(value)) {\n this.createIssue(elementDefinition, 'Invalid ' + type + ' value');\n return;\n }\n\n if (isIntegerType(type) && !Number.isInteger(value)) {\n this.createIssue(elementDefinition, 'Number is not an integer');\n }\n\n if (type === PropertyType.positiveInt && value <= 0) {\n this.createIssue(elementDefinition, 'Number is less than or equal to zero');\n }\n\n if (type === PropertyType.unsignedInt && value < 0) {\n this.createIssue(elementDefinition, 'Number is negative');\n }\n }\n\n private checkAdditionalProperties(\n path: string,\n typedValue: TypedValue,\n propertyDefinitions: Record<string, ElementDefinition>\n ): void {\n const object = typedValue.value as Record<string, unknown>;\n for (const key of Object.keys(object)) {\n this.checkAdditionalProperty(path, key, typedValue, propertyDefinitions);\n }\n }\n\n /**\n * Checks if the given property is allowed on the given object.\n * @param path The path of the current object.\n * @param key The key of a property to check.\n * @param typedValue The current object.\n * @param propertyDefinitions The property definitions of the current object.\n */\n private checkAdditionalProperty(\n path: string,\n key: string,\n typedValue: TypedValue,\n propertyDefinitions: Record<string, ElementDefinition>\n ): void {\n if (\n !baseResourceProperties.has(key) &&\n !(key in propertyDefinitions) &&\n !isChoiceOfType(key, typedValue, propertyDefinitions) &&\n !this.checkPrimitiveElement(path, key, typedValue)\n ) {\n const expression = `${path}.${key}`;\n this.issues.push(createStructureIssue(expression, `Invalid additional property \"${expression}\"`));\n }\n }\n\n /**\n * Checks the element for a primitive.\n *\n * FHIR elements with primitive data types are represented in two parts:\n * 1) A JSON property with the name of the element, which has a JSON type of number, boolean, or string\n * 2) a JSON property with _ prepended to the name of the element, which, if present, contains the value's id and/or extensions\n *\n * See: https://hl7.org/fhir/json.html#primitive\n *\n * @param path The path to the property\n * @param key\n * @param typedValue\n */\n private checkPrimitiveElement(path: string, key: string, typedValue: TypedValue): boolean {\n // Primitive element starts with underscore\n if (!key.startsWith('_')) {\n return false;\n }\n\n // Validate the non-underscore property exists\n const primitiveKey = key.slice(1);\n if (!(primitiveKey in typedValue.value)) {\n return false;\n }\n\n // Then validate the element\n this.validateObject({ type: 'Element', value: typedValue.value[key] }, path);\n return true;\n }\n\n private createIssue(elementDefinition: ElementDefinition, message: string): void {\n this.issues.push(createStructureIssue(elementDefinition.path as string, message));\n }\n}\n\nfunction isIntegerType(propertyType: PropertyType): boolean {\n return (\n propertyType === PropertyType.integer ||\n propertyType === PropertyType.positiveInt ||\n propertyType === PropertyType.unsignedInt\n );\n}\n\nfunction isChoiceOfType(\n key: string,\n typedValue: TypedValue,\n propertyDefinitions: Record<string, ElementDefinition>\n): boolean {\n for (const propertyName of Object.keys(propertyDefinitions)) {\n if (!propertyName.endsWith('[x]')) {\n continue;\n }\n const basePropertyName = propertyName.replace('[x]', '');\n if (!key.startsWith(basePropertyName)) {\n continue;\n }\n let typedPropertyValue = getTypedPropertyValue(typedValue, propertyName);\n if (!typedPropertyValue) {\n continue;\n }\n if (Array.isArray(typedPropertyValue)) {\n // At present, there are no choice types that are arrays in the FHIR spec\n // Leaving this here to make TypeScript happy, and in case that changes\n typedPropertyValue = typedPropertyValue[0];\n }\n if (typedPropertyValue && key === basePropertyName + capitalize(typedPropertyValue.type)) {\n return true;\n }\n }\n return false;\n}\n\n/**\n * Recursively checks for null values in an object.\n *\n * Note that \"null\" is a special value in JSON that is not allowed in FHIR.\n *\n * @param value Input value of any type.\n * @param path Path string to the value for OperationOutcome.\n * @param issues Output list of issues.\n */\nexport function checkForNull(value: unknown, path: string, issues: OperationOutcomeIssue[]): void {\n if (value === null) {\n issues.push(createStructureIssue(path, 'Invalid null value'));\n } else if (Array.isArray(value)) {\n checkArrayForNull(value, path, issues);\n } else if (typeof value === 'object') {\n checkObjectForNull(value as Record<string, unknown>, path, issues);\n }\n}\n\nfunction checkArrayForNull(array: unknown[], path: string, issues: OperationOutcomeIssue[]): void {\n for (let i = 0; i < array.length; i++) {\n if (array[i] === undefined) {\n issues.push(createStructureIssue(`${path}[${i}]`, 'Invalid undefined value'));\n } else {\n checkForNull(array[i], `${path}[${i}]`, issues);\n }\n }\n}\n\nfunction checkObjectForNull(obj: Record<string, unknown>, path: string, issues: OperationOutcomeIssue[]): void {\n for (const [key, value] of Object.entries(obj)) {\n checkForNull(value, `${path}${path ? '.' : ''}${key}`, issues);\n }\n}\n\nexport function createStructureIssue(expression: string, details: string): OperationOutcomeIssue {\n return {\n severity: 'error',\n code: 'structure',\n details: {\n text: details,\n },\n expression: [expression],\n };\n}\n"],"names":[],"mappings":"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"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"match.mjs","sources":["../../../src/search/match.ts"],"sourcesContent":["import { Reference, Resource, SearchParameter } from '@medplum/fhirtypes';\nimport { evalFhirPath } from '../fhirpath';\nimport { globalSchema } from '../types';\nimport { getSearchParameterDetails, SearchParameterType } from './details';\nimport { Filter, Operator, SearchRequest } from './search';\n\n/**\n * Determines if the resource matches the search request.\n * @param resource The resource that was created or updated.\n * @param searchRequest The subscription criteria as a search request.\n * @returns True if the resource satisfies the search request.\n */\nexport function matchesSearchRequest(resource: Resource, searchRequest: SearchRequest): boolean {\n if (searchRequest.resourceType !== resource.resourceType) {\n return false;\n }\n if (searchRequest.filters) {\n for (const filter of searchRequest.filters) {\n if (!matchesSearchFilter(resource, searchRequest, filter)) {\n return false;\n }\n }\n }\n return true;\n}\n\n/**\n * Determines if the resource matches the search filter.\n * @param resource The resource that was created or updated.\n * @param filter One of the filters of a subscription criteria.\n * @returns True if the resource satisfies the search filter.\n */\nfunction matchesSearchFilter(resource: Resource, searchRequest: SearchRequest, filter: Filter): boolean {\n const searchParam = globalSchema.types[searchRequest.resourceType]?.searchParams?.[filter.code];\n switch (searchParam?.type) {\n case 'reference':\n return matchesReferenceFilter(resource, filter, searchParam);\n case 'string':\n case 'uri':\n return matchesStringFilter(resource, filter, searchParam);\n case 'token':\n return matchesTokenFilter(resource, filter, searchParam);\n case 'date':\n return matchesDateFilter(resource, filter, searchParam);\n }\n // Unknown search parameter or search parameter type\n // Default fail the check\n return false;\n}\n\nfunction matchesReferenceFilter(resource: Resource, filter: Filter, searchParam: SearchParameter): boolean {\n const values = evalFhirPath(searchParam.expression as string, resource) as (Reference | string)[];\n const negated = isNegated(filter.operator);\n\n if (filter.value === '' && values.length === 0) {\n // If the filter operator is \"equals\", then the filter matches.\n // If the filter operator is \"not equals\", then the filter does not match.\n return filter.operator === Operator.EQUALS;\n }\n\n // Normalize the values array into reference strings\n const references = values.map((value) => (typeof value === 'string' ? value : value.reference));\n\n for (const filterValue of filter.value.split(',')) {\n let match = references.includes(filterValue);\n if (!match && filter.code === '_compartment') {\n // Backwards compability for compartment search parameter\n // In previous versions, the resource type was not required in compartment values\n // So, \"123\" would match \"Patient/123\"\n // We need to maintain this behavior for backwards compatibility\n match = references.some((reference) => reference?.endsWith('/' + filterValue));\n }\n if (match) {\n return !negated;\n }\n }\n // If \"not equals\" and no matches, then return true\n // If \"equals\" and no matches, then return false\n return negated;\n}\n\nfunction matchesTokenFilter(resource: Resource, filter: Filter, searchParam: SearchParameter): boolean {\n const details = getSearchParameterDetails(resource.resourceType, searchParam);\n if (details.type === SearchParameterType.BOOLEAN) {\n return matchesBooleanFilter(resource, filter, searchParam);\n } else {\n return matchesStringFilter(resource, filter, searchParam, true);\n }\n}\n\nfunction matchesBooleanFilter(resource: Resource, filter: Filter, searchParam: SearchParameter): boolean {\n const values = evalFhirPath(searchParam.expression as string, resource);\n const expected = filter.value === 'true';\n const result = values.includes(expected);\n return isNegated(filter.operator) ? !result : result;\n}\n\nfunction matchesStringFilter(\n resource: Resource,\n filter: Filter,\n searchParam: SearchParameter,\n asToken?: boolean\n): boolean {\n const resourceValues = evalFhirPath(searchParam.expression as string, resource);\n const filterValues = filter.value.split(',');\n const negated = isNegated(filter.operator);\n for (const resourceValue of resourceValues) {\n for (const filterValue of filterValues) {\n const match = matchesStringValue(resourceValue, filter.operator, filterValue, asToken);\n if (match) {\n return !negated;\n }\n }\n }\n // If \"not equals\" and no matches, then return true\n // If \"equals\" and no matches, then return false\n return negated;\n}\n\nfunction matchesStringValue(\n resourceValue: unknown,\n operator: Operator,\n filterValue: string,\n asToken?: boolean\n): boolean {\n if (asToken && filterValue.includes('|')) {\n const [system, code] = filterValue.split('|');\n return (\n matchesStringValue(resourceValue, operator, system, false) &&\n (!code || matchesStringValue(resourceValue, operator, code, false))\n );\n }\n let str = '';\n if (resourceValue) {\n if (typeof resourceValue === 'string') {\n str = resourceValue;\n } else if (typeof resourceValue === 'object') {\n str = JSON.stringify(resourceValue);\n }\n }\n return str.toLowerCase().includes(filterValue.toLowerCase());\n}\n\nfunction matchesDateFilter(resource: Resource, filter: Filter, searchParam: SearchParameter): boolean {\n const resourceValues = evalFhirPath(searchParam.expression as string, resource);\n const filterValues = filter.value.split(',');\n const negated = isNegated(filter.operator);\n for (const resourceValue of resourceValues) {\n for (const filterValue of filterValues) {\n const match = matchesDateValue(resourceValue as string, filter.operator, filterValue);\n if (match) {\n return !negated;\n }\n }\n }\n // If \"not equals\" and no matches, then return true\n // If \"equals\" and no matches, then return false\n return negated;\n}\n\nfunction matchesDateValue(resourceValue: string, operator: Operator, filterValue: string): boolean {\n switch (operator) {\n case Operator.STARTS_AFTER:\n case Operator.GREATER_THAN:\n return resourceValue > filterValue;\n case Operator.GREATER_THAN_OR_EQUALS:\n return resourceValue >= filterValue;\n case Operator.ENDS_BEFORE:\n case Operator.LESS_THAN:\n return resourceValue < filterValue;\n case Operator.LESS_THAN_OR_EQUALS:\n return resourceValue <= filterValue;\n case Operator.EQUALS:\n case Operator.NOT_EQUALS:\n return resourceValue === filterValue;\n }\n return false;\n}\n\nfunction isNegated(operator: Operator): boolean {\n return operator === Operator.NOT_EQUALS || operator === Operator.NOT;\n}\n"],"names":[],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"match.mjs","sources":["../../../src/search/match.ts"],"sourcesContent":["import { Reference, Resource, SearchParameter } from '@medplum/fhirtypes';\nimport { evalFhirPath } from '../fhirpath';\nimport { globalSchema } from '../types';\nimport { getSearchParameterDetails, SearchParameterType } from './details';\nimport { Filter, Operator, SearchRequest } from './search';\n\n/**\n * Determines if the resource matches the search request.\n * @param resource The resource that was created or updated.\n * @param searchRequest The subscription criteria as a search request.\n * @returns True if the resource satisfies the search request.\n */\nexport function matchesSearchRequest(resource: Resource, searchRequest: SearchRequest): boolean {\n if (searchRequest.resourceType !== resource.resourceType) {\n return false;\n }\n if (searchRequest.filters) {\n for (const filter of searchRequest.filters) {\n if (!matchesSearchFilter(resource, searchRequest, filter)) {\n return false;\n }\n }\n }\n return true;\n}\n\n/**\n * Determines if the resource matches the search filter.\n * @param resource The resource that was created or updated.\n * @param filter One of the filters of a subscription criteria.\n * @returns True if the resource satisfies the search filter.\n */\nfunction matchesSearchFilter(resource: Resource, searchRequest: SearchRequest, filter: Filter): boolean {\n const searchParam = globalSchema.types[searchRequest.resourceType]?.searchParams?.[filter.code];\n switch (searchParam?.type) {\n case 'reference':\n return matchesReferenceFilter(resource, filter, searchParam);\n case 'string':\n case 'uri':\n return matchesStringFilter(resource, filter, searchParam);\n case 'token':\n return matchesTokenFilter(resource, filter, searchParam);\n case 'date':\n return matchesDateFilter(resource, filter, searchParam);\n }\n // Unknown search parameter or search parameter type\n // Default fail the check\n return false;\n}\n\nfunction matchesReferenceFilter(resource: Resource, filter: Filter, searchParam: SearchParameter): boolean {\n const values = evalFhirPath(searchParam.expression as string, resource) as (Reference | string)[];\n const negated = isNegated(filter.operator);\n\n if (filter.value === '' && values.length === 0) {\n // If the filter operator is \"equals\", then the filter matches.\n // If the filter operator is \"not equals\", then the filter does not match.\n return filter.operator === Operator.EQUALS;\n }\n\n // Normalize the values array into reference strings\n const references = values.map((value) => (typeof value === 'string' ? value : value.reference));\n\n for (const filterValue of filter.value.split(',')) {\n let match = references.includes(filterValue);\n if (!match && filter.code === '_compartment') {\n // Backwards compability for compartment search parameter\n // In previous versions, the resource type was not required in compartment values\n // So, \"123\" would match \"Patient/123\"\n // We need to maintain this behavior for backwards compatibility\n match = references.some((reference) => reference?.endsWith('/' + filterValue));\n }\n if (match) {\n return !negated;\n }\n }\n // If \"not equals\" and no matches, then return true\n // If \"equals\" and no matches, then return false\n return negated;\n}\n\nfunction matchesTokenFilter(resource: Resource, filter: Filter, searchParam: SearchParameter): boolean {\n const details = getSearchParameterDetails(resource.resourceType, searchParam);\n if (details.type === SearchParameterType.BOOLEAN) {\n return matchesBooleanFilter(resource, filter, searchParam);\n } else {\n return matchesStringFilter(resource, filter, searchParam, true);\n }\n}\n\nfunction matchesBooleanFilter(resource: Resource, filter: Filter, searchParam: SearchParameter): boolean {\n const values = evalFhirPath(searchParam.expression as string, resource);\n const expected = filter.value === 'true';\n const result = values.includes(expected);\n return isNegated(filter.operator) ? !result : result;\n}\n\nfunction matchesStringFilter(\n resource: Resource,\n filter: Filter,\n searchParam: SearchParameter,\n asToken?: boolean\n): boolean {\n const resourceValues = evalFhirPath(searchParam.expression as string, resource);\n const filterValues = filter.value.split(',');\n const negated = isNegated(filter.operator);\n for (const resourceValue of resourceValues) {\n for (const filterValue of filterValues) {\n const match = matchesStringValue(resourceValue, filter.operator, filterValue, asToken);\n if (match) {\n return !negated;\n }\n }\n }\n // If \"not equals\" and no matches, then return true\n // If \"equals\" and no matches, then return false\n return negated;\n}\n\nfunction matchesStringValue(\n resourceValue: unknown,\n operator: Operator,\n filterValue: string,\n asToken?: boolean\n): boolean {\n if (asToken && filterValue.includes('|')) {\n const [system, code] = filterValue.split('|');\n return (\n matchesStringValue(resourceValue, operator, system, false) &&\n (!code || matchesStringValue(resourceValue, operator, code, false))\n );\n }\n let str = '';\n if (resourceValue) {\n if (typeof resourceValue === 'string') {\n str = resourceValue;\n } else if (typeof resourceValue === 'object') {\n str = JSON.stringify(resourceValue);\n }\n }\n return str.toLowerCase().includes(filterValue.toLowerCase());\n}\n\nfunction matchesDateFilter(resource: Resource, filter: Filter, searchParam: SearchParameter): boolean {\n const resourceValues = evalFhirPath(searchParam.expression as string, resource);\n const filterValues = filter.value.split(',');\n const negated = isNegated(filter.operator);\n for (const resourceValue of resourceValues) {\n for (const filterValue of filterValues) {\n const match = matchesDateValue(resourceValue as string, filter.operator, filterValue);\n if (match) {\n return !negated;\n }\n }\n }\n // If \"not equals\" and no matches, then return true\n // If \"equals\" and no matches, then return false\n return negated;\n}\n\nfunction matchesDateValue(resourceValue: string, operator: Operator, filterValue: string): boolean {\n switch (operator) {\n case Operator.STARTS_AFTER:\n case Operator.GREATER_THAN:\n return resourceValue > filterValue;\n case Operator.GREATER_THAN_OR_EQUALS:\n return resourceValue >= filterValue;\n case Operator.ENDS_BEFORE:\n case Operator.LESS_THAN:\n return resourceValue < filterValue;\n case Operator.LESS_THAN_OR_EQUALS:\n return resourceValue <= filterValue;\n case Operator.EQUALS:\n case Operator.NOT_EQUALS:\n return resourceValue === filterValue;\n }\n return false;\n}\n\nfunction isNegated(operator: Operator): boolean {\n return operator === Operator.NOT_EQUALS || operator === Operator.NOT;\n}\n"],"names":[],"mappings":"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"}
|
|
@@ -77,7 +77,18 @@ const PREFIX_OPERATORS = {
|
|
|
77
77
|
* @returns A parsed SearchRequest.
|
|
78
78
|
*/
|
|
79
79
|
function parseSearchRequest(resourceType, query) {
|
|
80
|
-
|
|
80
|
+
const queryArray = [];
|
|
81
|
+
for (const [key, value] of Object.entries(query)) {
|
|
82
|
+
if (Array.isArray(value)) {
|
|
83
|
+
for (let i = 0; i < value.length; i++) {
|
|
84
|
+
queryArray.push([key, value[i]]);
|
|
85
|
+
}
|
|
86
|
+
}
|
|
87
|
+
else {
|
|
88
|
+
queryArray.push([key, value || '']);
|
|
89
|
+
}
|
|
90
|
+
}
|
|
91
|
+
return parseSearchImpl(resourceType, queryArray);
|
|
81
92
|
}
|
|
82
93
|
/**
|
|
83
94
|
* Parses a search URL into a search request.
|
|
@@ -86,7 +97,7 @@ function parseSearchRequest(resourceType, query) {
|
|
|
86
97
|
*/
|
|
87
98
|
function parseSearchUrl(url) {
|
|
88
99
|
const resourceType = url.pathname.split('/').filter(Boolean).pop();
|
|
89
|
-
return parseSearchImpl(resourceType,
|
|
100
|
+
return parseSearchImpl(resourceType, url.searchParams.entries());
|
|
90
101
|
}
|
|
91
102
|
/**
|
|
92
103
|
* Parses a URL string into a SearchRequest.
|
|
@@ -100,13 +111,8 @@ function parseSearchImpl(resourceType, query) {
|
|
|
100
111
|
const searchRequest = {
|
|
101
112
|
resourceType,
|
|
102
113
|
};
|
|
103
|
-
for (const [key, value] of
|
|
104
|
-
|
|
105
|
-
value.forEach((element) => parseKeyValue(searchRequest, key, element));
|
|
106
|
-
}
|
|
107
|
-
else {
|
|
108
|
-
parseKeyValue(searchRequest, key, value ?? '');
|
|
109
|
-
}
|
|
114
|
+
for (const [key, value] of query) {
|
|
115
|
+
parseKeyValue(searchRequest, key, value);
|
|
110
116
|
}
|
|
111
117
|
return searchRequest;
|
|
112
118
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"search.mjs","sources":["../../../src/search/search.ts"],"sourcesContent":["import { Resource, ResourceType, SearchParameter } from '@medplum/fhirtypes';\nimport { globalSchema } from '../types';\n\nexport const DEFAULT_SEARCH_COUNT = 20;\n\nexport interface SearchRequest<T extends Resource = Resource> {\n readonly resourceType: T['resourceType'];\n filters?: Filter[];\n sortRules?: SortRule[];\n offset?: number;\n count?: number;\n fields?: string[];\n name?: string;\n total?: 'none' | 'estimate' | 'accurate';\n include?: string;\n revInclude?: string;\n}\n\nexport interface Filter {\n code: string;\n operator: Operator;\n value: string;\n unitSystem?: string;\n unitCode?: string;\n}\n\nexport interface SortRule {\n code: string;\n descending?: boolean;\n}\n\n/**\n * Search operators.\n * These operators represent \"modifiers\" and \"prefixes\" in FHIR search.\n * See: https://www.hl7.org/fhir/search.html\n */\nexport enum Operator {\n EQUALS = 'eq',\n NOT_EQUALS = 'ne',\n\n // Numbers\n GREATER_THAN = 'gt',\n LESS_THAN = 'lt',\n GREATER_THAN_OR_EQUALS = 'ge',\n LESS_THAN_OR_EQUALS = 'le',\n\n // Dates\n STARTS_AFTER = 'sa',\n ENDS_BEFORE = 'eb',\n APPROXIMATELY = 'ap',\n\n // String\n CONTAINS = 'contains',\n EXACT = 'exact',\n\n // Token\n TEXT = 'text',\n NOT = 'not',\n ABOVE = 'above',\n BELOW = 'below',\n IN = 'in',\n NOT_IN = 'not-in',\n OF_TYPE = 'of-type',\n\n // All\n MISSING = 'missing',\n\n // Reference\n IDENTIFIER = 'identifier',\n}\n\n/**\n * Parameter names may specify a modifier as a suffix.\n * The modifiers are separated from the parameter name by a colon.\n * See: https://www.hl7.org/fhir/search.html#modifiers\n */\nconst MODIFIER_OPERATORS: Record<string, Operator> = {\n contains: Operator.CONTAINS,\n exact: Operator.EXACT,\n above: Operator.ABOVE,\n below: Operator.BELOW,\n text: Operator.TEXT,\n not: Operator.NOT,\n in: Operator.IN,\n 'not-in': Operator.NOT_IN,\n 'of-type': Operator.OF_TYPE,\n missing: Operator.MISSING,\n identifier: Operator.IDENTIFIER,\n};\n\n/**\n * For the ordered parameter types of number, date, and quantity,\n * a prefix to the parameter value may be used to control the nature\n * of the matching.\n * See: https://www.hl7.org/fhir/search.html#prefix\n */\nconst PREFIX_OPERATORS: Record<string, Operator> = {\n eq: Operator.EQUALS,\n ne: Operator.NOT_EQUALS,\n lt: Operator.LESS_THAN,\n le: Operator.LESS_THAN_OR_EQUALS,\n gt: Operator.GREATER_THAN,\n ge: Operator.GREATER_THAN_OR_EQUALS,\n sa: Operator.STARTS_AFTER,\n eb: Operator.ENDS_BEFORE,\n ap: Operator.APPROXIMATELY,\n};\n\n/**\n * Parses a search URL into a search request.\n * @param resourceType The FHIR resource type.\n * @param query The collection of query string parameters.\n * @returns A parsed SearchRequest.\n */\nexport function parseSearchRequest<T extends Resource = Resource>(\n resourceType: T['resourceType'],\n query: Record<string, string[] | string | undefined>\n): SearchRequest<T> {\n return parseSearchImpl(resourceType, query);\n}\n\n/**\n * Parses a search URL into a search request.\n * @param url The search URL.\n * @returns A parsed SearchRequest.\n */\nexport function parseSearchUrl<T extends Resource = Resource>(url: URL): SearchRequest<T> {\n const resourceType = url.pathname.split('/').filter(Boolean).pop() as ResourceType;\n return parseSearchImpl<T>(resourceType, Object.fromEntries(url.searchParams.entries()));\n}\n\n/**\n * Parses a URL string into a SearchRequest.\n * @param url The URL to parse.\n * @returns Parsed search definition.\n */\nexport function parseSearchDefinition<T extends Resource = Resource>(url: string): SearchRequest<T> {\n return parseSearchUrl<T>(new URL(url, 'https://example.com/'));\n}\n\nfunction parseSearchImpl<T extends Resource = Resource>(\n resourceType: T['resourceType'],\n query: Record<string, string[] | string | undefined>\n): SearchRequest<T> {\n const searchRequest: SearchRequest<T> = {\n resourceType,\n };\n\n for (const [key, value] of Object.entries(query)) {\n if (Array.isArray(value)) {\n value.forEach((element) => parseKeyValue(searchRequest, key, element));\n } else {\n parseKeyValue(searchRequest, key, value ?? '');\n }\n }\n\n return searchRequest;\n}\n\nfunction parseKeyValue(searchRequest: SearchRequest, key: string, value: string): void {\n let code;\n let modifier;\n\n const colonIndex = key.indexOf(':');\n if (colonIndex >= 0) {\n code = key.substring(0, colonIndex);\n modifier = key.substring(colonIndex + 1);\n } else {\n code = key;\n modifier = '';\n }\n\n switch (code) {\n case '_sort':\n parseSortRule(searchRequest, value);\n break;\n\n case '_count':\n searchRequest.count = parseInt(value);\n break;\n\n case '_offset':\n searchRequest.offset = parseInt(value);\n break;\n\n case '_total':\n searchRequest.total = value as 'none' | 'estimate' | 'accurate';\n break;\n\n case '_summary':\n searchRequest.total = 'estimate';\n searchRequest.count = 0;\n break;\n\n case '_include':\n searchRequest.include = value;\n break;\n\n case '_revinclude':\n searchRequest.revInclude = value;\n break;\n\n case '_fields':\n searchRequest.fields = value.split(',');\n break;\n\n default: {\n const param = globalSchema.types[searchRequest.resourceType]?.searchParams?.[code];\n if (param) {\n parseParameter(searchRequest, param, modifier, value);\n } else {\n parseUnknownParameter(searchRequest, code, modifier, value);\n }\n }\n }\n}\n\nfunction parseSortRule(searchRequest: SearchRequest, value: string): void {\n for (const field of value.split(',')) {\n let code;\n let descending = false;\n if (field.startsWith('-')) {\n code = field.substring(1);\n descending = true;\n } else {\n code = field;\n }\n if (!searchRequest.sortRules) {\n searchRequest.sortRules = [];\n }\n searchRequest.sortRules.push({ code, descending });\n }\n}\n\nfunction parseParameter(\n searchRequest: SearchRequest,\n searchParam: SearchParameter,\n modifier: string,\n value: string\n): void {\n if (modifier === 'missing') {\n addFilter(searchRequest, {\n code: searchParam.code as string,\n operator: Operator.MISSING,\n value,\n });\n return;\n }\n switch (searchParam.type) {\n case 'number':\n case 'date':\n parsePrefixType(searchRequest, searchParam, value);\n break;\n case 'reference':\n case 'string':\n case 'token':\n case 'uri':\n parseModifierType(searchRequest, searchParam, modifier, value);\n break;\n case 'quantity':\n parseQuantity(searchRequest, searchParam, value);\n break;\n }\n}\n\nfunction parsePrefixType(searchRequest: SearchRequest, param: SearchParameter, input: string): void {\n const { operator, value } = parsePrefix(input);\n addFilter(searchRequest, {\n code: param.code as string,\n operator,\n value,\n });\n}\n\nfunction parseModifierType(\n searchRequest: SearchRequest,\n param: SearchParameter,\n modifier: string,\n value: string\n): void {\n addFilter(searchRequest, {\n code: param.code as string,\n operator: parseModifier(modifier),\n value,\n });\n}\n\nfunction parseQuantity(searchRequest: SearchRequest, param: SearchParameter, input: string): void {\n const [prefixNumber, unitSystem, unitCode] = input.split('|');\n const { operator, value } = parsePrefix(prefixNumber);\n addFilter(searchRequest, {\n code: param.code as string,\n operator,\n value,\n unitSystem,\n unitCode,\n });\n}\n\nfunction parseUnknownParameter(searchRequest: SearchRequest, code: string, modifier: string, value: string): void {\n let operator = Operator.EQUALS;\n if (modifier) {\n operator = modifier as Operator;\n } else if (value.length >= 2) {\n const prefix = value.substring(0, 2);\n if (prefix in PREFIX_OPERATORS) {\n if (value.length === 2 || value.at(2)?.match(/\\d/)) {\n operator = prefix as Operator;\n value = value.substring(prefix.length);\n }\n }\n }\n\n addFilter(searchRequest, {\n code,\n operator,\n value,\n });\n}\n\nfunction parsePrefix(input: string): { operator: Operator; value: string } {\n const prefix = input.substring(0, 2);\n const prefixOperator = PREFIX_OPERATORS[prefix];\n if (prefixOperator) {\n return { operator: prefixOperator, value: input.substring(2) };\n }\n return { operator: Operator.EQUALS, value: input };\n}\n\nfunction parseModifier(modifier: string): Operator {\n return MODIFIER_OPERATORS[modifier] || Operator.EQUALS;\n}\n\nfunction addFilter(searchRequest: SearchRequest, filter: Filter): void {\n if (searchRequest.filters) {\n searchRequest.filters.push(filter);\n } else {\n searchRequest.filters = [filter];\n }\n}\n\n/**\n * Formats a search definition object into a query string.\n * Note: The return value does not include the resource type.\n * @param {!SearchRequest} definition The search definition.\n * @returns Formatted URL.\n */\nexport function formatSearchQuery(definition: SearchRequest): string {\n const params: string[] = [];\n\n if (definition.fields) {\n params.push('_fields=' + definition.fields.join(','));\n }\n\n if (definition.filters) {\n definition.filters.forEach((filter) => params.push(formatFilter(filter)));\n }\n\n if (definition.sortRules && definition.sortRules.length > 0) {\n params.push(formatSortRules(definition.sortRules));\n }\n\n if (definition.offset !== undefined) {\n params.push('_offset=' + definition.offset);\n }\n\n if (definition.count !== undefined) {\n params.push('_count=' + definition.count);\n }\n\n if (definition.total !== undefined) {\n params.push('_total=' + definition.total);\n }\n\n if (params.length === 0) {\n return '';\n }\n\n params.sort();\n return '?' + params.join('&');\n}\n\nfunction formatFilter(filter: Filter): string {\n const modifier = filter.operator in MODIFIER_OPERATORS ? ':' + filter.operator : '';\n const prefix = filter.operator !== Operator.EQUALS && filter.operator in PREFIX_OPERATORS ? filter.operator : '';\n return `${filter.code}${modifier}=${prefix}${encodeURIComponent(filter.value)}`;\n}\n\nfunction formatSortRules(sortRules: SortRule[]): string {\n return '_sort=' + sortRules.map((sr) => (sr.descending ? '-' + sr.code : sr.code)).join(',');\n}\n"],"names":[],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"search.mjs","sources":["../../../src/search/search.ts"],"sourcesContent":["import { Resource, ResourceType, SearchParameter } from '@medplum/fhirtypes';\nimport { globalSchema } from '../types';\n\nexport const DEFAULT_SEARCH_COUNT = 20;\n\nexport interface SearchRequest<T extends Resource = Resource> {\n readonly resourceType: T['resourceType'];\n filters?: Filter[];\n sortRules?: SortRule[];\n offset?: number;\n count?: number;\n fields?: string[];\n name?: string;\n total?: 'none' | 'estimate' | 'accurate';\n include?: string;\n revInclude?: string;\n}\n\nexport interface Filter {\n code: string;\n operator: Operator;\n value: string;\n unitSystem?: string;\n unitCode?: string;\n}\n\nexport interface SortRule {\n code: string;\n descending?: boolean;\n}\n\n/**\n * Search operators.\n * These operators represent \"modifiers\" and \"prefixes\" in FHIR search.\n * See: https://www.hl7.org/fhir/search.html\n */\nexport enum Operator {\n EQUALS = 'eq',\n NOT_EQUALS = 'ne',\n\n // Numbers\n GREATER_THAN = 'gt',\n LESS_THAN = 'lt',\n GREATER_THAN_OR_EQUALS = 'ge',\n LESS_THAN_OR_EQUALS = 'le',\n\n // Dates\n STARTS_AFTER = 'sa',\n ENDS_BEFORE = 'eb',\n APPROXIMATELY = 'ap',\n\n // String\n CONTAINS = 'contains',\n EXACT = 'exact',\n\n // Token\n TEXT = 'text',\n NOT = 'not',\n ABOVE = 'above',\n BELOW = 'below',\n IN = 'in',\n NOT_IN = 'not-in',\n OF_TYPE = 'of-type',\n\n // All\n MISSING = 'missing',\n\n // Reference\n IDENTIFIER = 'identifier',\n}\n\n/**\n * Parameter names may specify a modifier as a suffix.\n * The modifiers are separated from the parameter name by a colon.\n * See: https://www.hl7.org/fhir/search.html#modifiers\n */\nconst MODIFIER_OPERATORS: Record<string, Operator> = {\n contains: Operator.CONTAINS,\n exact: Operator.EXACT,\n above: Operator.ABOVE,\n below: Operator.BELOW,\n text: Operator.TEXT,\n not: Operator.NOT,\n in: Operator.IN,\n 'not-in': Operator.NOT_IN,\n 'of-type': Operator.OF_TYPE,\n missing: Operator.MISSING,\n identifier: Operator.IDENTIFIER,\n};\n\n/**\n * For the ordered parameter types of number, date, and quantity,\n * a prefix to the parameter value may be used to control the nature\n * of the matching.\n * See: https://www.hl7.org/fhir/search.html#prefix\n */\nconst PREFIX_OPERATORS: Record<string, Operator> = {\n eq: Operator.EQUALS,\n ne: Operator.NOT_EQUALS,\n lt: Operator.LESS_THAN,\n le: Operator.LESS_THAN_OR_EQUALS,\n gt: Operator.GREATER_THAN,\n ge: Operator.GREATER_THAN_OR_EQUALS,\n sa: Operator.STARTS_AFTER,\n eb: Operator.ENDS_BEFORE,\n ap: Operator.APPROXIMATELY,\n};\n\n/**\n * Parses a search URL into a search request.\n * @param resourceType The FHIR resource type.\n * @param query The collection of query string parameters.\n * @returns A parsed SearchRequest.\n */\nexport function parseSearchRequest<T extends Resource = Resource>(\n resourceType: T['resourceType'],\n query: Record<string, string[] | string | undefined>\n): SearchRequest<T> {\n const queryArray: [string, string][] = [];\n for (const [key, value] of Object.entries(query)) {\n if (Array.isArray(value)) {\n for (let i = 0; i < value.length; i++) {\n queryArray.push([key, value[i]]);\n }\n } else {\n queryArray.push([key, value || '']);\n }\n }\n return parseSearchImpl(resourceType, queryArray);\n}\n\n/**\n * Parses a search URL into a search request.\n * @param url The search URL.\n * @returns A parsed SearchRequest.\n */\nexport function parseSearchUrl<T extends Resource = Resource>(url: URL): SearchRequest<T> {\n const resourceType = url.pathname.split('/').filter(Boolean).pop() as ResourceType;\n return parseSearchImpl<T>(resourceType, url.searchParams.entries());\n}\n\n/**\n * Parses a URL string into a SearchRequest.\n * @param url The URL to parse.\n * @returns Parsed search definition.\n */\nexport function parseSearchDefinition<T extends Resource = Resource>(url: string): SearchRequest<T> {\n return parseSearchUrl<T>(new URL(url, 'https://example.com/'));\n}\n\nfunction parseSearchImpl<T extends Resource = Resource>(\n resourceType: T['resourceType'],\n query: [string, string][] | IterableIterator<[string, string]>\n): SearchRequest<T> {\n const searchRequest: SearchRequest<T> = {\n resourceType,\n };\n\n for (const [key, value] of query) {\n parseKeyValue(searchRequest, key, value);\n }\n\n return searchRequest;\n}\n\nfunction parseKeyValue(searchRequest: SearchRequest, key: string, value: string): void {\n let code;\n let modifier;\n\n const colonIndex = key.indexOf(':');\n if (colonIndex >= 0) {\n code = key.substring(0, colonIndex);\n modifier = key.substring(colonIndex + 1);\n } else {\n code = key;\n modifier = '';\n }\n\n switch (code) {\n case '_sort':\n parseSortRule(searchRequest, value);\n break;\n\n case '_count':\n searchRequest.count = parseInt(value);\n break;\n\n case '_offset':\n searchRequest.offset = parseInt(value);\n break;\n\n case '_total':\n searchRequest.total = value as 'none' | 'estimate' | 'accurate';\n break;\n\n case '_summary':\n searchRequest.total = 'estimate';\n searchRequest.count = 0;\n break;\n\n case '_include':\n searchRequest.include = value;\n break;\n\n case '_revinclude':\n searchRequest.revInclude = value;\n break;\n\n case '_fields':\n searchRequest.fields = value.split(',');\n break;\n\n default: {\n const param = globalSchema.types[searchRequest.resourceType]?.searchParams?.[code];\n if (param) {\n parseParameter(searchRequest, param, modifier, value);\n } else {\n parseUnknownParameter(searchRequest, code, modifier, value);\n }\n }\n }\n}\n\nfunction parseSortRule(searchRequest: SearchRequest, value: string): void {\n for (const field of value.split(',')) {\n let code;\n let descending = false;\n if (field.startsWith('-')) {\n code = field.substring(1);\n descending = true;\n } else {\n code = field;\n }\n if (!searchRequest.sortRules) {\n searchRequest.sortRules = [];\n }\n searchRequest.sortRules.push({ code, descending });\n }\n}\n\nfunction parseParameter(\n searchRequest: SearchRequest,\n searchParam: SearchParameter,\n modifier: string,\n value: string\n): void {\n if (modifier === 'missing') {\n addFilter(searchRequest, {\n code: searchParam.code as string,\n operator: Operator.MISSING,\n value,\n });\n return;\n }\n switch (searchParam.type) {\n case 'number':\n case 'date':\n parsePrefixType(searchRequest, searchParam, value);\n break;\n case 'reference':\n case 'string':\n case 'token':\n case 'uri':\n parseModifierType(searchRequest, searchParam, modifier, value);\n break;\n case 'quantity':\n parseQuantity(searchRequest, searchParam, value);\n break;\n }\n}\n\nfunction parsePrefixType(searchRequest: SearchRequest, param: SearchParameter, input: string): void {\n const { operator, value } = parsePrefix(input);\n addFilter(searchRequest, {\n code: param.code as string,\n operator,\n value,\n });\n}\n\nfunction parseModifierType(\n searchRequest: SearchRequest,\n param: SearchParameter,\n modifier: string,\n value: string\n): void {\n addFilter(searchRequest, {\n code: param.code as string,\n operator: parseModifier(modifier),\n value,\n });\n}\n\nfunction parseQuantity(searchRequest: SearchRequest, param: SearchParameter, input: string): void {\n const [prefixNumber, unitSystem, unitCode] = input.split('|');\n const { operator, value } = parsePrefix(prefixNumber);\n addFilter(searchRequest, {\n code: param.code as string,\n operator,\n value,\n unitSystem,\n unitCode,\n });\n}\n\nfunction parseUnknownParameter(searchRequest: SearchRequest, code: string, modifier: string, value: string): void {\n let operator = Operator.EQUALS;\n if (modifier) {\n operator = modifier as Operator;\n } else if (value.length >= 2) {\n const prefix = value.substring(0, 2);\n if (prefix in PREFIX_OPERATORS) {\n if (value.length === 2 || value.at(2)?.match(/\\d/)) {\n operator = prefix as Operator;\n value = value.substring(prefix.length);\n }\n }\n }\n\n addFilter(searchRequest, {\n code,\n operator,\n value,\n });\n}\n\nfunction parsePrefix(input: string): { operator: Operator; value: string } {\n const prefix = input.substring(0, 2);\n const prefixOperator = PREFIX_OPERATORS[prefix];\n if (prefixOperator) {\n return { operator: prefixOperator, value: input.substring(2) };\n }\n return { operator: Operator.EQUALS, value: input };\n}\n\nfunction parseModifier(modifier: string): Operator {\n return MODIFIER_OPERATORS[modifier] || Operator.EQUALS;\n}\n\nfunction addFilter(searchRequest: SearchRequest, filter: Filter): void {\n if (searchRequest.filters) {\n searchRequest.filters.push(filter);\n } else {\n searchRequest.filters = [filter];\n }\n}\n\n/**\n * Formats a search definition object into a query string.\n * Note: The return value does not include the resource type.\n * @param {!SearchRequest} definition The search definition.\n * @returns Formatted URL.\n */\nexport function formatSearchQuery(definition: SearchRequest): string {\n const params: string[] = [];\n\n if (definition.fields) {\n params.push('_fields=' + definition.fields.join(','));\n }\n\n if (definition.filters) {\n definition.filters.forEach((filter) => params.push(formatFilter(filter)));\n }\n\n if (definition.sortRules && definition.sortRules.length > 0) {\n params.push(formatSortRules(definition.sortRules));\n }\n\n if (definition.offset !== undefined) {\n params.push('_offset=' + definition.offset);\n }\n\n if (definition.count !== undefined) {\n params.push('_count=' + definition.count);\n }\n\n if (definition.total !== undefined) {\n params.push('_total=' + definition.total);\n }\n\n if (params.length === 0) {\n return '';\n }\n\n params.sort();\n return '?' + params.join('&');\n}\n\nfunction formatFilter(filter: Filter): string {\n const modifier = filter.operator in MODIFIER_OPERATORS ? ':' + filter.operator : '';\n const prefix = filter.operator !== Operator.EQUALS && filter.operator in PREFIX_OPERATORS ? filter.operator : '';\n return `${filter.code}${modifier}=${prefix}${encodeURIComponent(filter.value)}`;\n}\n\nfunction formatSortRules(sortRules: SortRule[]): string {\n return '_sort=' + sortRules.map((sr) => (sr.descending ? '-' + sr.code : sr.code)).join(',');\n}\n"],"names":[],"mappings":"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"}
|
package/dist/esm/storage.mjs
CHANGED
|
@@ -1,7 +1,5 @@
|
|
|
1
|
-
import { __classPrivateFieldSet, __classPrivateFieldGet } from './node_modules/tslib/tslib.es6.mjs';
|
|
2
1
|
import { stringify } from './utils.mjs';
|
|
3
2
|
|
|
4
|
-
var _ClientStorage_storage, _MemoryStorage_data;
|
|
5
3
|
/**
|
|
6
4
|
* The ClientStorage class is a utility class for storing strings and objects.
|
|
7
5
|
*
|
|
@@ -11,21 +9,20 @@ var _ClientStorage_storage, _MemoryStorage_data;
|
|
|
11
9
|
*/
|
|
12
10
|
class ClientStorage {
|
|
13
11
|
constructor() {
|
|
14
|
-
|
|
15
|
-
__classPrivateFieldSet(this, _ClientStorage_storage, typeof localStorage !== 'undefined' ? localStorage : new MemoryStorage(), "f");
|
|
12
|
+
this.storage = typeof localStorage !== 'undefined' ? localStorage : new MemoryStorage();
|
|
16
13
|
}
|
|
17
14
|
clear() {
|
|
18
|
-
|
|
15
|
+
this.storage.clear();
|
|
19
16
|
}
|
|
20
17
|
getString(key) {
|
|
21
|
-
return
|
|
18
|
+
return this.storage.getItem(key) || undefined;
|
|
22
19
|
}
|
|
23
20
|
setString(key, value) {
|
|
24
21
|
if (value) {
|
|
25
|
-
|
|
22
|
+
this.storage.setItem(key, value);
|
|
26
23
|
}
|
|
27
24
|
else {
|
|
28
|
-
|
|
25
|
+
this.storage.removeItem(key);
|
|
29
26
|
}
|
|
30
27
|
}
|
|
31
28
|
getObject(key) {
|
|
@@ -36,58 +33,55 @@ class ClientStorage {
|
|
|
36
33
|
this.setString(key, value ? stringify(value) : undefined);
|
|
37
34
|
}
|
|
38
35
|
}
|
|
39
|
-
_ClientStorage_storage = new WeakMap();
|
|
40
36
|
/**
|
|
41
37
|
* The MemoryStorage class is a minimal in-memory implementation of the Storage interface.
|
|
42
38
|
*/
|
|
43
39
|
class MemoryStorage {
|
|
44
40
|
constructor() {
|
|
45
|
-
|
|
46
|
-
__classPrivateFieldSet(this, _MemoryStorage_data, new Map(), "f");
|
|
41
|
+
this.data = new Map();
|
|
47
42
|
}
|
|
48
43
|
/**
|
|
49
44
|
* Returns the number of key/value pairs.
|
|
50
45
|
*/
|
|
51
46
|
get length() {
|
|
52
|
-
return
|
|
47
|
+
return this.data.size;
|
|
53
48
|
}
|
|
54
49
|
/**
|
|
55
50
|
* Removes all key/value pairs, if there are any.
|
|
56
51
|
*/
|
|
57
52
|
clear() {
|
|
58
|
-
|
|
53
|
+
this.data.clear();
|
|
59
54
|
}
|
|
60
55
|
/**
|
|
61
56
|
* Returns the current value associated with the given key, or null if the given key does not exist.
|
|
62
57
|
*/
|
|
63
58
|
getItem(key) {
|
|
64
|
-
return
|
|
59
|
+
return this.data.get(key) ?? null;
|
|
65
60
|
}
|
|
66
61
|
/**
|
|
67
62
|
* Sets the value of the pair identified by key to value, creating a new key/value pair if none existed for key previously.
|
|
68
63
|
*/
|
|
69
64
|
setItem(key, value) {
|
|
70
65
|
if (value) {
|
|
71
|
-
|
|
66
|
+
this.data.set(key, value);
|
|
72
67
|
}
|
|
73
68
|
else {
|
|
74
|
-
|
|
69
|
+
this.data.delete(key);
|
|
75
70
|
}
|
|
76
71
|
}
|
|
77
72
|
/**
|
|
78
73
|
* Removes the key/value pair with the given key, if a key/value pair with the given key exists.
|
|
79
74
|
*/
|
|
80
75
|
removeItem(key) {
|
|
81
|
-
|
|
76
|
+
this.data.delete(key);
|
|
82
77
|
}
|
|
83
78
|
/**
|
|
84
79
|
* Returns the name of the nth key, or null if n is greater than or equal to the number of key/value pairs.
|
|
85
80
|
*/
|
|
86
81
|
key(index) {
|
|
87
|
-
return Array.from(
|
|
82
|
+
return Array.from(this.data.keys())[index];
|
|
88
83
|
}
|
|
89
84
|
}
|
|
90
|
-
_MemoryStorage_data = new WeakMap();
|
|
91
85
|
|
|
92
86
|
export { ClientStorage, MemoryStorage };
|
|
93
87
|
//# sourceMappingURL=storage.mjs.map
|
package/dist/esm/storage.mjs.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"storage.mjs","sources":["../../src/storage.ts"],"sourcesContent":["import { stringify } from './utils';\n\n/**\n * The ClientStorage class is a utility class for storing strings and objects.\n *\n * When using MedplumClient in the browser, it will be backed by browser localStorage.\n *\n * When Using MedplumClient in the server, it will be backed by the MemoryStorage class.\n */\nexport class ClientStorage {\n readonly
|
|
1
|
+
{"version":3,"file":"storage.mjs","sources":["../../src/storage.ts"],"sourcesContent":["import { stringify } from './utils';\n\n/**\n * The ClientStorage class is a utility class for storing strings and objects.\n *\n * When using MedplumClient in the browser, it will be backed by browser localStorage.\n *\n * When Using MedplumClient in the server, it will be backed by the MemoryStorage class.\n */\nexport class ClientStorage {\n private readonly storage: Storage;\n\n constructor() {\n this.storage = typeof localStorage !== 'undefined' ? localStorage : new MemoryStorage();\n }\n\n clear(): void {\n this.storage.clear();\n }\n\n getString(key: string): string | undefined {\n return this.storage.getItem(key) || undefined;\n }\n\n setString(key: string, value: string | undefined): void {\n if (value) {\n this.storage.setItem(key, value);\n } else {\n this.storage.removeItem(key);\n }\n }\n\n getObject<T>(key: string): T | undefined {\n const str = this.getString(key);\n return str ? (JSON.parse(str) as T) : undefined;\n }\n\n setObject<T>(key: string, value: T): void {\n this.setString(key, value ? stringify(value) : undefined);\n }\n}\n\n/**\n * The MemoryStorage class is a minimal in-memory implementation of the Storage interface.\n */\nexport class MemoryStorage implements Storage {\n private data: Map<string, string>;\n\n constructor() {\n this.data = new Map<string, string>();\n }\n\n /**\n * Returns the number of key/value pairs.\n */\n get length(): number {\n return this.data.size;\n }\n\n /**\n * Removes all key/value pairs, if there are any.\n */\n clear(): void {\n this.data.clear();\n }\n\n /**\n * Returns the current value associated with the given key, or null if the given key does not exist.\n */\n getItem(key: string): string | null {\n return this.data.get(key) ?? null;\n }\n\n /**\n * Sets the value of the pair identified by key to value, creating a new key/value pair if none existed for key previously.\n */\n setItem(key: string, value: string | null): void {\n if (value) {\n this.data.set(key, value);\n } else {\n this.data.delete(key);\n }\n }\n\n /**\n * Removes the key/value pair with the given key, if a key/value pair with the given key exists.\n */\n removeItem(key: string): void {\n this.data.delete(key);\n }\n\n /**\n * Returns the name of the nth key, or null if n is greater than or equal to the number of key/value pairs.\n */\n key(index: number): string | null {\n return Array.from(this.data.keys())[index];\n }\n}\n"],"names":[],"mappings":";;AAEA;;;;;;AAMG;MACU,aAAa,CAAA;AAGxB,IAAA,WAAA,GAAA;AACE,QAAA,IAAI,CAAC,OAAO,GAAG,OAAO,YAAY,KAAK,WAAW,GAAG,YAAY,GAAG,IAAI,aAAa,EAAE,CAAC;KACzF;IAED,KAAK,GAAA;AACH,QAAA,IAAI,CAAC,OAAO,CAAC,KAAK,EAAE,CAAC;KACtB;AAED,IAAA,SAAS,CAAC,GAAW,EAAA;QACnB,OAAO,IAAI,CAAC,OAAO,CAAC,OAAO,CAAC,GAAG,CAAC,IAAI,SAAS,CAAC;KAC/C;IAED,SAAS,CAAC,GAAW,EAAE,KAAyB,EAAA;AAC9C,QAAA,IAAI,KAAK,EAAE;YACT,IAAI,CAAC,OAAO,CAAC,OAAO,CAAC,GAAG,EAAE,KAAK,CAAC,CAAC;AAClC,SAAA;AAAM,aAAA;AACL,YAAA,IAAI,CAAC,OAAO,CAAC,UAAU,CAAC,GAAG,CAAC,CAAC;AAC9B,SAAA;KACF;AAED,IAAA,SAAS,CAAI,GAAW,EAAA;QACtB,MAAM,GAAG,GAAG,IAAI,CAAC,SAAS,CAAC,GAAG,CAAC,CAAC;AAChC,QAAA,OAAO,GAAG,GAAI,IAAI,CAAC,KAAK,CAAC,GAAG,CAAO,GAAG,SAAS,CAAC;KACjD;IAED,SAAS,CAAI,GAAW,EAAE,KAAQ,EAAA;AAChC,QAAA,IAAI,CAAC,SAAS,CAAC,GAAG,EAAE,KAAK,GAAG,SAAS,CAAC,KAAK,CAAC,GAAG,SAAS,CAAC,CAAC;KAC3D;AACF,CAAA;AAED;;AAEG;MACU,aAAa,CAAA;AAGxB,IAAA,WAAA,GAAA;AACE,QAAA,IAAI,CAAC,IAAI,GAAG,IAAI,GAAG,EAAkB,CAAC;KACvC;AAED;;AAEG;AACH,IAAA,IAAI,MAAM,GAAA;AACR,QAAA,OAAO,IAAI,CAAC,IAAI,CAAC,IAAI,CAAC;KACvB;AAED;;AAEG;IACH,KAAK,GAAA;AACH,QAAA,IAAI,CAAC,IAAI,CAAC,KAAK,EAAE,CAAC;KACnB;AAED;;AAEG;AACH,IAAA,OAAO,CAAC,GAAW,EAAA;QACjB,OAAO,IAAI,CAAC,IAAI,CAAC,GAAG,CAAC,GAAG,CAAC,IAAI,IAAI,CAAC;KACnC;AAED;;AAEG;IACH,OAAO,CAAC,GAAW,EAAE,KAAoB,EAAA;AACvC,QAAA,IAAI,KAAK,EAAE;YACT,IAAI,CAAC,IAAI,CAAC,GAAG,CAAC,GAAG,EAAE,KAAK,CAAC,CAAC;AAC3B,SAAA;AAAM,aAAA;AACL,YAAA,IAAI,CAAC,IAAI,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC;AACvB,SAAA;KACF;AAED;;AAEG;AACH,IAAA,UAAU,CAAC,GAAW,EAAA;AACpB,QAAA,IAAI,CAAC,IAAI,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC;KACvB;AAED;;AAEG;AACH,IAAA,GAAG,CAAC,KAAa,EAAA;AACf,QAAA,OAAO,KAAK,CAAC,IAAI,CAAC,IAAI,CAAC,IAAI,CAAC,IAAI,EAAE,CAAC,CAAC,KAAK,CAAC,CAAC;KAC5C;AACF;;;;"}
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Decodes a base64 string.
|
|
3
|
+
* Handles both browser and Node environments.
|
|
4
|
+
* @param data The base-64 encoded input string.
|
|
5
|
+
* @returns The decoded string.
|
|
6
|
+
*/
|
|
7
|
+
export declare function decodeBase64(data: string): string;
|
|
8
|
+
/**
|
|
9
|
+
* Encodes a base64 string.
|
|
10
|
+
* Handles both browser and Node environments.
|
|
11
|
+
* @param data The unencoded input string.
|
|
12
|
+
* @returns The base-64 encoded string.
|
|
13
|
+
*/
|
|
14
|
+
export declare function encodeBase64(data: string): string;
|
package/dist/types/cache.d.ts
CHANGED
|
@@ -3,7 +3,8 @@
|
|
|
3
3
|
* Source: https://stackoverflow.com/a/46432113
|
|
4
4
|
*/
|
|
5
5
|
export declare class LRUCache<T> {
|
|
6
|
-
|
|
6
|
+
private readonly max;
|
|
7
|
+
private readonly cache;
|
|
7
8
|
constructor(max?: number);
|
|
8
9
|
/**
|
|
9
10
|
* Deletes all values from the cache.
|
|
@@ -31,4 +32,5 @@ export declare class LRUCache<T> {
|
|
|
31
32
|
* @returns The array of keys in the cache.
|
|
32
33
|
*/
|
|
33
34
|
keys(): IterableIterator<string>;
|
|
35
|
+
private first;
|
|
34
36
|
}
|