@fuego-systems/core 0.1.7 → 0.1.9
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/constants.d.ts +18 -0
- package/dist/constants.d.ts.map +1 -1
- package/dist/constants.js +21 -2
- package/dist/constants.js.map +1 -1
- package/dist/db/types.d.ts +9 -5
- package/dist/db/types.d.ts.map +1 -1
- package/dist/db/types.js.map +1 -1
- package/dist/plan-definition-group.d.ts +10 -1
- package/dist/plan-definition-group.d.ts.map +1 -1
- package/dist/plan-definition-group.js +23 -3
- package/dist/plan-definition-group.js.map +1 -1
- package/dist/search/alias-builder.d.ts +8 -0
- package/dist/search/alias-builder.d.ts.map +1 -1
- package/dist/search/alias-builder.js +49 -5
- package/dist/search/alias-builder.js.map +1 -1
- package/dist/tsconfig.tsbuildinfo +1 -1
- package/package.json +4 -3
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"alias-builder.js","sourceRoot":"","sources":["../../src/search/alias-builder.ts"],"names":[],"mappings":"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","sourcesContent":["import type { HealthcareService } from '@medplum/fhirtypes'\nimport type { AliasRow } from '../db/types'\nimport { HS_SEARCH_ALIASES_EXTENSION_URL } from '../constants'\nimport { normalize } from './normalizer'\n\n/**\n * FHIR identifier system used by the search index to store and extract service codes.\n *\n * Note: this value may differ from SERVICE_CODES_SYSTEM in constants.ts which is\n * used by the admin UI. Use this constant whenever interacting with the search index.\n */\nexport const SEARCH_SERVICE_CODES_SYSTEM = 'http://fuego.health/fhir/service-codes'\n\n/**\n * Build the list of alias rows to index for a given HealthcareService resource.\n *\n * Each alias carries a `weight` that scales the trigram similarity score\n * during ranking, giving more prominent results for exact name matches\n * vs. code matches vs. abbreviation matches.\n *\n * Weight scale:\n * 1.5 – canonical name (primary display)\n * 1.2 – HS_SEARCH_ALIASES_EXTENSION_URL extension entries (alternative labels)\n * 1.0 – code + name combined phrase (searchable compound)\n * 0.9 – service code identifier alone\n * 0.7 – payer-specific / free-text comment aliases (hs.comment)\n */\n\n/**\n * Extract the service code from the SEARCH_SERVICE_CODES_SYSTEM identifier.\n * @param hs - HealthcareService resource to read.\n * @returns Service code value or an empty string when missing.\n */\nfunction extractCode (hs: HealthcareService): string {\n return hs.identifier?.find((id) => id.system === SEARCH_SERVICE_CODES_SYSTEM)?.value ?? ''\n}\n\n/**\n * Extract custom search aliases from the HS_SEARCH_ALIASES_EXTENSION_URL extension.\n * Returns an empty array when none are present.\n * @param hs - HealthcareService resource to read.\n * @returns Non-empty extension alias strings.\n */\nexport function extractSearchAliases (hs: HealthcareService): string[] {\n return (\n hs.extension\n ?.filter((e) => e.url === HS_SEARCH_ALIASES_EXTENSION_URL)\n ?.map((e) => e.valueString ?? '')\n ?.filter(Boolean) ?? []\n )\n}\n\n/**\n * Deduplicate alias rows by normalizedAlias, keeping the one with the highest\n * weight when multiple rows resolve to the same normalised form.\n * @param rows - Candidate alias rows before deduplication.\n * @returns Rows deduplicated by `normalizedAlias` with highest weight kept.\n */\nfunction dedup (rows: AliasRow[]): AliasRow[] {\n const seen = new Map<string, AliasRow>()\n for (const row of rows) {\n const existing = seen.get(row.normalizedAlias)\n if (!existing || row.weight > existing.weight) {\n seen.set(row.normalizedAlias, row)\n }\n }\n return Array.from(seen.values())\n}\n\n/**\n * Build all alias rows for a single HealthcareService resource.\n * @param hs - Source HealthcareService resource.\n * @returns Alias rows ready to persist in the search index.\n */\nexport function buildAliases (hs: HealthcareService): AliasRow[] {\n const name = hs.name ?? ''\n const code = extractCode(hs)\n const rows: AliasRow[] = []\n\n // 1. Canonical name (highest weight)\n if (name) {\n rows.push({\n alias: name,\n normalizedAlias: normalize(name),\n kind: 'canonical',\n weight: 1.5\n })\n }\n\n // 2. Custom search aliases from HS_SEARCH_ALIASES_EXTENSION_URL extension\n for (const alt of extractSearchAliases(hs)) {\n if (alt !== name) {\n rows.push({\n alias: alt,\n normalizedAlias: normalize(alt),\n kind: 'alias',\n weight: 1.2\n })\n }\n }\n\n // 3. Code + name combined phrase (helps \"RX TORAX\" style searches)\n if (code && name) {\n const combined = `${code} ${name}`\n rows.push({\n alias: combined,\n normalizedAlias: normalize(combined),\n kind: 'code-name',\n weight: 1.0\n })\n }\n\n // 4. Service code alone\n if (code) {\n rows.push({\n alias: code,\n normalizedAlias: normalize(code),\n kind: 'code',\n weight: 0.9\n })\n }\n\n // 5. Comment field – may contain informal / abbreviation labels\n if (hs.comment) {\n rows.push({\n alias: hs.comment,\n normalizedAlias: normalize(hs.comment),\n kind: 'alias',\n weight: 0.7\n })\n }\n\n // Remove empty normalised aliases (e.g. a code that is all punctuation)\n const nonEmpty = rows.filter((r) => r.normalizedAlias.length > 0)\n return dedup(nonEmpty)\n}\n"]}
|
|
1
|
+
{"version":3,"file":"alias-builder.js","sourceRoot":"","sources":["../../src/search/alias-builder.ts"],"names":[],"mappings":"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","sourcesContent":["import type { Extension, HealthcareService } from '@medplum/fhirtypes'\nimport type { AliasRow } from '../db/types'\nimport { HS_SEARCH_ALIASES_EXTENSION_URL, HS_SEARCH_PROTOCOL_ALIASES_EXTENSION_URL } from '../constants'\nimport { normalize } from './normalizer'\nimport { ProtocolSelection } from '../plan-definition-group'\n\n/**\n * FHIR identifier system used by the search index to store and extract service codes.\n *\n * Note: this value may differ from SERVICE_CODES_SYSTEM in constants.ts which is\n * used by the admin UI. Use this constant whenever interacting with the search index.\n */\nexport const SEARCH_SERVICE_CODES_SYSTEM = 'http://fuego.health/fhir/service-codes'\n\n/**\n * Build the list of alias rows to index for a given HealthcareService resource.\n *\n * Each alias carries a `weight` that scales the trigram similarity score\n * during ranking, giving more prominent results for exact name matches\n * vs. code matches vs. abbreviation matches.\n *\n * Weight scale:\n * 1.5 – canonical name (primary display)\n * 1.2 – HS_SEARCH_ALIASES_EXTENSION_URL extension entries (alternative labels)\n * 1.0 – code + name combined phrase (searchable compound)\n * 0.9 – service code identifier alone\n * 0.7 – payer-specific / free-text comment aliases (hs.comment)\n */\n\n/**\n * Extract the service code from the SEARCH_SERVICE_CODES_SYSTEM identifier.\n * @param hs - HealthcareService resource to read.\n * @returns Service code value or an empty string when missing.\n */\nfunction extractCode (hs: HealthcareService): string {\n return hs.identifier?.find((id) => id.system === SEARCH_SERVICE_CODES_SYSTEM)?.value ?? ''\n}\n\n/**\n * Extract custom search aliases from the HS_SEARCH_ALIASES_EXTENSION_URL extension.\n * Returns an empty array when none are present.\n * @param hs - HealthcareService resource to read.\n * @returns Non-empty extension alias strings.\n */\nexport function extractSearchAliases (hs: HealthcareService): string[] {\n return (\n hs.extension\n ?.filter((e) => e.url === HS_SEARCH_ALIASES_EXTENSION_URL)\n ?.map((e) => e.valueString ?? '')\n ?.filter(Boolean) ?? []\n )\n}\n\n/**\n * Extract custom search aliases from the HS_SEARCH_PROTOCOL_ALIASES_EXTENSION_URL extension.\n * Returns an empty array when none are present.\n * @param hs - HealthcareService resource to read.\n * @returns Non-empty extension alias strings.\n */\nexport function extractSearchProtocolAliases (hs: HealthcareService): [string, ProtocolSelection][] {\n return (\n hs.extension\n ?.filter((e) => e.url === HS_SEARCH_PROTOCOL_ALIASES_EXTENSION_URL && e.extension !== undefined)\n ?.map((e) => [\n getExtensionStringValue(e.extension, 'alias'),\n {\n actionId: getExtensionStringValue(e.extension, 'protocol'),\n addonIds: e.extension\n ?.filter((a): a is Extension & { valueString: string } => a.url === 'addon' && a.valueString !== undefined)\n .map((a) => a.valueString) ?? []\n }\n ]) ?? []\n )\n}\n\nfunction getExtensionStringValue (extension: Extension[] | undefined, url: string): string {\n const result = extension?.find((e) => e.url === url)?.valueString\n\n if (result === undefined) {\n throw new Error(`No string value for extension url ${url}`)\n }\n\n return result\n}\n\n/**\n * Deduplicate alias rows by normalizedAlias, keeping the one with the highest\n * weight when multiple rows resolve to the same normalised form.\n * @param rows - Candidate alias rows before deduplication.\n * @returns Rows deduplicated by `normalizedAlias` with highest weight kept.\n */\nfunction dedup (rows: AliasRow[]): AliasRow[] {\n const seen = new Map<string, AliasRow>()\n for (const row of rows) {\n let key = row.normalizedAlias\n if (row.protocolSelection) {\n key += `:${row.protocolSelection.actionId}:${row.protocolSelection.addonIds.slice().sort().join(',')}`\n }\n\n const existing = seen.get(key)\n if (!existing || row.weight > existing.weight) {\n seen.set(key, row)\n }\n }\n return Array.from(seen.values())\n}\n\n/**\n * Build all alias rows for a single HealthcareService resource.\n * @param hs - Source HealthcareService resource.\n * @returns Alias rows ready to persist in the search index.\n */\nexport function buildAliases (hs: HealthcareService): AliasRow[] {\n const name = hs.name ?? ''\n const code = extractCode(hs)\n const rows: AliasRow[] = []\n\n // 1. Canonical name (highest weight)\n if (name) {\n rows.push({\n alias: name,\n normalizedAlias: normalize(name),\n kind: 'canonical',\n weight: 1.5\n })\n }\n\n // 2. Custom search aliases from HS_SEARCH_ALIASES_EXTENSION_URL extension\n for (const alt of extractSearchAliases(hs)) {\n if (alt !== name) {\n rows.push({\n alias: alt,\n normalizedAlias: normalize(alt),\n kind: 'alias',\n weight: 1.2\n })\n }\n }\n\n // 3. Custom search aliases from HS_SEARCH_PROTOCOL_ALIASES_EXTENSION_URL extension\n for (const [alt, protocolSelection] of extractSearchProtocolAliases(hs)) {\n if (alt !== name) {\n rows.push({\n alias: alt,\n protocolSelection,\n normalizedAlias: normalize(alt),\n kind: 'protocol-alias',\n weight: 1.2\n })\n }\n }\n\n // 4. Code + name combined phrase (helps \"RX TORAX\" style searches)\n if (code && name) {\n const combined = `${code} ${name}`\n rows.push({\n alias: combined,\n normalizedAlias: normalize(combined),\n kind: 'code-name',\n weight: 1.0\n })\n }\n\n // 5. Service code alone\n if (code) {\n rows.push({\n alias: code,\n normalizedAlias: normalize(code),\n kind: 'code',\n weight: 0.9\n })\n }\n\n // 6. Comment field – may contain informal / abbreviation labels\n if (hs.comment) {\n rows.push({\n alias: hs.comment,\n normalizedAlias: normalize(hs.comment),\n kind: 'alias',\n weight: 0.7\n })\n }\n\n // Remove empty normalised aliases (e.g. a code that is all punctuation)\n const nonEmpty = rows.filter((r) => r.normalizedAlias.length > 0)\n return dedup(nonEmpty)\n}\n"]}
|