@precisa-saude/fhir 0.17.4 → 0.18.0

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.
@@ -7,8 +7,8 @@ var _chunkONRVND6Ucjs = require('./chunk-ONRVND6U.cjs');
7
7
  var _chunk3ILBFLVQcjs = require('./chunk-3ILBFLVQ.cjs');
8
8
 
9
9
  // src/importer.ts
10
- var MAX_OBSERVATIONS = 1e3;
11
- var MAX_FILE_SIZE = 5 * 1024 * 1024;
10
+ var MAX_OBSERVATIONS = 5e3;
11
+ var MAX_FILE_SIZE = 15 * 1024 * 1024;
12
12
  function extractLoincCode(observation) {
13
13
  if (!_optionalChain([observation, 'access', _ => _.code, 'optionalAccess', _2 => _2.coding])) return void 0;
14
14
  const loincCoding = observation.code.coding.find((c) => c.system === "http://loinc.org");
@@ -150,4 +150,4 @@ function processImportBundle(data) {
150
150
 
151
151
 
152
152
  exports.MAX_OBSERVATIONS = MAX_OBSERVATIONS; exports.MAX_FILE_SIZE = MAX_FILE_SIZE; exports.extractObservationsFromBundle = extractObservationsFromBundle; exports.mapFHIRObservationToInternal = mapFHIRObservationToInternal; exports.processImportBundle = processImportBundle;
153
- //# sourceMappingURL=chunk-R6FI2RNB.cjs.map
153
+ //# sourceMappingURL=chunk-HGEQS7P7.cjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["/home/runner/work/fhir-brasil/fhir-brasil/packages/core/dist/chunk-HGEQS7P7.cjs","../src/importer.ts"],"names":[],"mappings":"AAAA;AACE;AACA;AACF,wDAA6B;AAC7B;AACE;AACF,wDAA6B;AAC7B;AACA;AC+CA,IAAM,iBAAA,EAAmB,GAAA;AACzB,IAAM,cAAA,EAAgB,GAAA,EAAK,KAAA,EAAO,IAAA;AAKlC,SAAS,gBAAA,CAAiB,WAAA,EAAkD;AAC1E,EAAA,GAAA,CAAI,iBAAC,WAAA,mBAAY,IAAA,6BAAM,QAAA,EAAQ,OAAO,KAAA,CAAA;AACtC,EAAA,MAAM,YAAA,EAAc,WAAA,CAAY,IAAA,CAAK,MAAA,CAAO,IAAA,CAAK,CAAC,CAAA,EAAA,GAAM,CAAA,CAAE,OAAA,IAAW,kBAAkB,CAAA;AACvF,EAAA,uBAAO,WAAA,6BAAa,MAAA;AACtB;AAKA,SAAS,WAAA,CAAY,WAAA,EAA8C;AACjE,EAAA,MAAM,KAAA,kBAAO,WAAA,qBAAY,cAAA,4BAAA,CAAiB,CAAC,CAAA,6BAAG,MAAA,4BAAA,CAAS,CAAC,CAAA,6BAAG,MAAA;AAC3D,EAAA,GAAA,CAAI,KAAA,IAAS,IAAA,GAAO,KAAA,IAAS,IAAA,EAAM,OAAO,GAAA;AAC1C,EAAA,GAAA,CAAI,KAAA,IAAS,IAAA,GAAO,KAAA,IAAS,IAAA,EAAM,OAAO,GAAA;AAC1C,EAAA,OAAO,EAAA;AACT;AAKO,SAAS,6BAAA,CAA8B,MAAA,EAG5C;AACA,EAAA,MAAM,aAAA,EAAkC,CAAC,CAAA;AACzC,EAAA,MAAM,QAAA,EAA0B,CAAC,CAAA;AAEjC,EAAA,IAAA,CAAA,IAAS,EAAA,EAAI,CAAA,EAAG,EAAA,EAAI,MAAA,CAAO,KAAA,CAAM,MAAA,EAAQ,CAAA,EAAA,EAAK;AAC5C,IAAA,MAAM,MAAA,EAAQ,MAAA,CAAO,KAAA,CAAM,CAAC,CAAA;AAC5B,IAAA,GAAA,CAAI,CAAC,KAAA,CAAM,QAAA,EAAU;AACnB,MAAA,OAAA,CAAQ,IAAA,CAAK,EAAE,KAAA,EAAO,CAAA,EAAG,MAAA,EAAQ,wBAAwB,CAAC,CAAA;AAC1D,MAAA,QAAA;AAAA,IACF;AAEA,IAAA,GAAA,CAAI,KAAA,CAAM,QAAA,CAAS,aAAA,IAAiB,aAAA,EAAe;AAEjD,MAAA,QAAA;AAAA,IACF;AAEA,IAAA,GAAA,CAAI,YAAA,CAAa,OAAA,GAAU,gBAAA,EAAkB;AAC3C,MAAA,OAAA,CAAQ,IAAA,CAAK,EAAE,KAAA,EAAO,CAAA,EAAG,MAAA,EAAQ,CAAA,WAAA,EAAc,gBAAgB,CAAA,sBAAA,EAAyB,CAAC,CAAA;AACzF,MAAA,QAAA;AAAA,IACF;AAEA,IAAA,YAAA,CAAa,IAAA,CAAK,KAAA,CAAM,QAA2B,CAAA;AAAA,EACrD;AAEA,EAAA,OAAO,EAAE,YAAA,EAAc,QAAQ,CAAA;AACjC;AAKO,SAAS,4BAAA,CACd,WAAA,EACA,KAAA,EACkE;AAClE,EAAA,MAAM,UAAA,EAAY,gBAAA,CAAiB,WAAW,CAAA;AAE9C,EAAA,GAAA,CAAI,CAAC,SAAA,EAAW;AACd,IAAA,OAAO;AAAA,MACL,OAAA,EAAS;AAAA,QACP,KAAA;AAAA,QACA,MAAA,EAAQ,2CAAA;AAAA,QACR,YAAA,EAAc;AAAA,MAChB;AAAA,IACF,CAAA;AAAA,EACF;AAEA,EAAA,MAAM,aAAA,EAAe,2CAAA,SAAqB,CAAA;AAC1C,EAAA,GAAA,CAAI,CAAC,YAAA,EAAc;AACjB,IAAA,OAAO;AAAA,MACL,OAAA,EAAS;AAAA,QACP,KAAA;AAAA,QACA,SAAA;AAAA,QACA,MAAA,EAAQ,CAAA,oBAAA,EAAuB,SAAS,CAAA,CAAA;AAC1B,QAAA;AAChB,MAAA;AACF,IAAA;AACF,EAAA;AAEwC,EAAA;AAGpC,EAAA;AACO,EAAA;AACS,EAAA;AAEqB,EAAA;AACL,IAAA;AACO,IAAA;AACP,EAAA;AACd,IAAA;AACJ,IAAA;AACX,EAAA;AACE,IAAA;AACI,MAAA;AACP,QAAA;AACA,QAAA;AACQ,QAAA;AACM,QAAA;AAChB,MAAA;AACF,IAAA;AACF,EAAA;AAGmC,EAAA;AACd,EAAA;AACZ,IAAA;AACI,MAAA;AACP,QAAA;AACA,QAAA;AACQ,QAAA;AACM,QAAA;AAChB,MAAA;AACF,IAAA;AACF,EAAA;AAGI,EAAA;AACA,EAAA;AACiC,EAAA;AACU,IAAA;AACA,IAAA;AAC/C,EAAA;AAEsC,EAAA;AACrB,IAAA;AAEc,IAAA;AAC7B,IAAA;AAC6B,IAAA;AAC7B,IAAA;AACA,IAAA;AACA,IAAA;AACA,IAAA;AACkC,IAAA;AAClC,IAAA;AACF,EAAA;AAE+B,EAAA;AACjC;AAKqE;AAE1C,EAAA;AACQ,EAAA;AACxB,IAAA;AACG,MAAA;AACG,MAAA;AACD,MAAA;AACM,MAAA;AAClB,IAAA;AACF,EAAA;AAEe,EAAA;AAGmB,EAAA;AAGO,EAAA;AACK,EAAA;AAEA,EAAA;AACA,IAAA;AAEf,IAAA;AACK,MAAA;AAC3B,IAAA;AACyB,MAAA;AAChC,IAAA;AACF,EAAA;AAEO,EAAA;AACI,IAAA;AACT,IAAA;AACS,IAAA;AACoB,IAAA;AAC/B,EAAA;AACF;ADnGiD;AACA;AACA;AACA;AACA;AACA;AACA;AACA","file":"/home/runner/work/fhir-brasil/fhir-brasil/packages/core/dist/chunk-HGEQS7P7.cjs","sourcesContent":[null,"/**\n * FHIR Importer\n *\n * Parses FHIR R4 Bundles and extracts Observation resources with known LOINC codes,\n * mapping them to internal biomarker codes for storage as lab results.\n */\n\nimport { getDefinitionByLoinc, loincToCode } from './biomarkers';\nimport type { FHIRBundle, FHIRObservation } from './fhir-types';\nimport { validateFHIRImportBundle } from './validators';\n\nexport interface ImportedObservation {\n biomarkerCode: string;\n biomarkerName: string;\n collectionDate: string;\n flag: 'H' | 'L' | '';\n isQualitative: boolean;\n loincCode: string;\n referenceMax?: number;\n referenceMin?: number;\n unit: string;\n value: number | string;\n}\n\nexport interface SkippedEntry {\n index: number;\n loincCode?: string;\n reason: string;\n resourceType?: string;\n}\n\nexport interface ImportError {\n details: string;\n field: string;\n}\n\nexport interface FHIRImportResult {\n errors: ImportError[];\n imported: ImportedObservation[];\n skipped: SkippedEntry[];\n totalProcessed: number;\n}\n\n/**\n * Limites de importação.\n *\n * Uma Observation exportada ocupa cerca de 1,25KB em JSON compacto e 2,75KB\n * quando o arquivo vem indentado, medido sobre um histórico real de 998\n * Observations em 61 laudos. Nesse tamanho, 5000 Observations dão 6,0MB\n * compactos ou 13,1MB indentados, e por isso o teto de arquivo é 15MB: cobre\n * as duas formas com folga.\n *\n * Na densidade desse mesmo histórico (16 Observations por laudo), 5000\n * equivalem a cerca de 300 laudos.\n */\nconst MAX_OBSERVATIONS = 5000;\nconst MAX_FILE_SIZE = 15 * 1024 * 1024; // 15MB\n\n/**\n * Extract LOINC code from an Observation's code.coding array\n */\nfunction extractLoincCode(observation: FHIRObservation): string | undefined {\n if (!observation.code?.coding) return undefined;\n const loincCoding = observation.code.coding.find((c) => c.system === 'http://loinc.org');\n return loincCoding?.code;\n}\n\n/**\n * Extract interpretation flag from Observation\n */\nfunction extractFlag(observation: FHIRObservation): 'H' | 'L' | '' {\n const code = observation.interpretation?.[0]?.coding?.[0]?.code;\n if (code === 'H' || code === 'HH') return 'H';\n if (code === 'L' || code === 'LL') return 'L';\n return '';\n}\n\n/**\n * Extract Observation resources from a FHIR Bundle\n */\nexport function extractObservationsFromBundle(bundle: FHIRBundle): {\n observations: FHIRObservation[];\n skipped: SkippedEntry[];\n} {\n const observations: FHIRObservation[] = [];\n const skipped: SkippedEntry[] = [];\n\n for (let i = 0; i < bundle.entry.length; i++) {\n const entry = bundle.entry[i]!;\n if (!entry.resource) {\n skipped.push({ index: i, reason: 'Entry has no resource' });\n continue;\n }\n\n if (entry.resource.resourceType !== 'Observation') {\n // Non-observation resources are silently skipped (Patient, DiagnosticReport, etc.)\n continue;\n }\n\n if (observations.length >= MAX_OBSERVATIONS) {\n skipped.push({ index: i, reason: `Maximum of ${MAX_OBSERVATIONS} observations exceeded` });\n continue;\n }\n\n observations.push(entry.resource as FHIRObservation);\n }\n\n return { observations, skipped };\n}\n\n/**\n * Map a FHIR Observation to internal format using LOINC→biomarker code lookup\n */\nexport function mapFHIRObservationToInternal(\n observation: FHIRObservation,\n index: number,\n): { observation: ImportedObservation } | { skipped: SkippedEntry } {\n const loincCode = extractLoincCode(observation);\n\n if (!loincCode) {\n return {\n skipped: {\n index,\n reason: 'No LOINC code found in observation coding',\n resourceType: 'Observation',\n },\n };\n }\n\n const internalCode = loincToCode(loincCode);\n if (!internalCode) {\n return {\n skipped: {\n index,\n loincCode,\n reason: `Unknown LOINC code: ${loincCode}`,\n resourceType: 'Observation',\n },\n };\n }\n\n const definition = getDefinitionByLoinc(loincCode);\n\n // Extract value\n let value: number | string;\n let unit = '';\n let isQualitative = false;\n\n if (observation.valueQuantity?.value !== undefined) {\n value = observation.valueQuantity.value;\n unit = observation.valueQuantity.unit || observation.valueQuantity.code || '';\n } else if (observation.valueString) {\n value = observation.valueString;\n isQualitative = true;\n } else {\n return {\n skipped: {\n index,\n loincCode,\n reason: 'Observation has no value (valueQuantity or valueString)',\n resourceType: 'Observation',\n },\n };\n }\n\n // Extract collection date (effectiveDateTime or effectivePeriod.start)\n const collectionDate = observation.effectiveDateTime || observation.effectivePeriod?.start || '';\n if (!collectionDate) {\n return {\n skipped: {\n index,\n loincCode,\n reason: 'Observation has no effectiveDateTime or effectivePeriod.start',\n resourceType: 'Observation',\n },\n };\n }\n\n // Extract reference ranges\n let referenceMin: number | undefined;\n let referenceMax: number | undefined;\n if (observation.referenceRange?.[0]) {\n referenceMin = observation.referenceRange[0].low?.value;\n referenceMax = observation.referenceRange[0].high?.value;\n }\n\n const imported: ImportedObservation = {\n biomarkerCode: internalCode,\n biomarkerName:\n definition?.names.pt[0] || definition?.names.en[0] || observation.code.text || internalCode,\n collectionDate,\n flag: extractFlag(observation),\n isQualitative,\n loincCode,\n referenceMax,\n referenceMin,\n unit: unit || definition?.unit || '',\n value,\n };\n\n return { observation: imported };\n}\n\n/**\n * Process a complete FHIR Bundle for import\n */\nexport function processImportBundle(data: unknown): FHIRImportResult {\n // Structural validation\n const validationErrors = validateFHIRImportBundle(data);\n if (validationErrors.length > 0) {\n return {\n errors: validationErrors,\n imported: [],\n skipped: [],\n totalProcessed: 0,\n };\n }\n\n const bundle = data as FHIRBundle;\n\n // Extract observations\n const { observations, skipped } = extractObservationsFromBundle(bundle);\n\n // Map each observation to internal format\n const imported: ImportedObservation[] = [];\n const allSkipped: SkippedEntry[] = [...skipped];\n\n for (let i = 0; i < observations.length; i++) {\n const result = mapFHIRObservationToInternal(observations[i]!, i);\n\n if ('observation' in result) {\n imported.push(result.observation);\n } else {\n allSkipped.push(result.skipped);\n }\n }\n\n return {\n errors: [],\n imported,\n skipped: allSkipped,\n totalProcessed: observations.length,\n };\n}\n\nexport { MAX_FILE_SIZE, MAX_OBSERVATIONS };\n"]}
@@ -7,8 +7,8 @@ import {
7
7
  } from "./chunk-N3ZCOLG2.js";
8
8
 
9
9
  // src/importer.ts
10
- var MAX_OBSERVATIONS = 1e3;
11
- var MAX_FILE_SIZE = 5 * 1024 * 1024;
10
+ var MAX_OBSERVATIONS = 5e3;
11
+ var MAX_FILE_SIZE = 15 * 1024 * 1024;
12
12
  function extractLoincCode(observation) {
13
13
  if (!observation.code?.coding) return void 0;
14
14
  const loincCoding = observation.code.coding.find((c) => c.system === "http://loinc.org");
@@ -150,4 +150,4 @@ export {
150
150
  mapFHIRObservationToInternal,
151
151
  processImportBundle
152
152
  };
153
- //# sourceMappingURL=chunk-NAUVJPLC.js.map
153
+ //# sourceMappingURL=chunk-HP3OETAJ.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/importer.ts"],"sourcesContent":["/**\n * FHIR Importer\n *\n * Parses FHIR R4 Bundles and extracts Observation resources with known LOINC codes,\n * mapping them to internal biomarker codes for storage as lab results.\n */\n\nimport { getDefinitionByLoinc, loincToCode } from './biomarkers';\nimport type { FHIRBundle, FHIRObservation } from './fhir-types';\nimport { validateFHIRImportBundle } from './validators';\n\nexport interface ImportedObservation {\n biomarkerCode: string;\n biomarkerName: string;\n collectionDate: string;\n flag: 'H' | 'L' | '';\n isQualitative: boolean;\n loincCode: string;\n referenceMax?: number;\n referenceMin?: number;\n unit: string;\n value: number | string;\n}\n\nexport interface SkippedEntry {\n index: number;\n loincCode?: string;\n reason: string;\n resourceType?: string;\n}\n\nexport interface ImportError {\n details: string;\n field: string;\n}\n\nexport interface FHIRImportResult {\n errors: ImportError[];\n imported: ImportedObservation[];\n skipped: SkippedEntry[];\n totalProcessed: number;\n}\n\n/**\n * Limites de importação.\n *\n * Uma Observation exportada ocupa cerca de 1,25KB em JSON compacto e 2,75KB\n * quando o arquivo vem indentado, medido sobre um histórico real de 998\n * Observations em 61 laudos. Nesse tamanho, 5000 Observations dão 6,0MB\n * compactos ou 13,1MB indentados, e por isso o teto de arquivo é 15MB: cobre\n * as duas formas com folga.\n *\n * Na densidade desse mesmo histórico (16 Observations por laudo), 5000\n * equivalem a cerca de 300 laudos.\n */\nconst MAX_OBSERVATIONS = 5000;\nconst MAX_FILE_SIZE = 15 * 1024 * 1024; // 15MB\n\n/**\n * Extract LOINC code from an Observation's code.coding array\n */\nfunction extractLoincCode(observation: FHIRObservation): string | undefined {\n if (!observation.code?.coding) return undefined;\n const loincCoding = observation.code.coding.find((c) => c.system === 'http://loinc.org');\n return loincCoding?.code;\n}\n\n/**\n * Extract interpretation flag from Observation\n */\nfunction extractFlag(observation: FHIRObservation): 'H' | 'L' | '' {\n const code = observation.interpretation?.[0]?.coding?.[0]?.code;\n if (code === 'H' || code === 'HH') return 'H';\n if (code === 'L' || code === 'LL') return 'L';\n return '';\n}\n\n/**\n * Extract Observation resources from a FHIR Bundle\n */\nexport function extractObservationsFromBundle(bundle: FHIRBundle): {\n observations: FHIRObservation[];\n skipped: SkippedEntry[];\n} {\n const observations: FHIRObservation[] = [];\n const skipped: SkippedEntry[] = [];\n\n for (let i = 0; i < bundle.entry.length; i++) {\n const entry = bundle.entry[i]!;\n if (!entry.resource) {\n skipped.push({ index: i, reason: 'Entry has no resource' });\n continue;\n }\n\n if (entry.resource.resourceType !== 'Observation') {\n // Non-observation resources are silently skipped (Patient, DiagnosticReport, etc.)\n continue;\n }\n\n if (observations.length >= MAX_OBSERVATIONS) {\n skipped.push({ index: i, reason: `Maximum of ${MAX_OBSERVATIONS} observations exceeded` });\n continue;\n }\n\n observations.push(entry.resource as FHIRObservation);\n }\n\n return { observations, skipped };\n}\n\n/**\n * Map a FHIR Observation to internal format using LOINC→biomarker code lookup\n */\nexport function mapFHIRObservationToInternal(\n observation: FHIRObservation,\n index: number,\n): { observation: ImportedObservation } | { skipped: SkippedEntry } {\n const loincCode = extractLoincCode(observation);\n\n if (!loincCode) {\n return {\n skipped: {\n index,\n reason: 'No LOINC code found in observation coding',\n resourceType: 'Observation',\n },\n };\n }\n\n const internalCode = loincToCode(loincCode);\n if (!internalCode) {\n return {\n skipped: {\n index,\n loincCode,\n reason: `Unknown LOINC code: ${loincCode}`,\n resourceType: 'Observation',\n },\n };\n }\n\n const definition = getDefinitionByLoinc(loincCode);\n\n // Extract value\n let value: number | string;\n let unit = '';\n let isQualitative = false;\n\n if (observation.valueQuantity?.value !== undefined) {\n value = observation.valueQuantity.value;\n unit = observation.valueQuantity.unit || observation.valueQuantity.code || '';\n } else if (observation.valueString) {\n value = observation.valueString;\n isQualitative = true;\n } else {\n return {\n skipped: {\n index,\n loincCode,\n reason: 'Observation has no value (valueQuantity or valueString)',\n resourceType: 'Observation',\n },\n };\n }\n\n // Extract collection date (effectiveDateTime or effectivePeriod.start)\n const collectionDate = observation.effectiveDateTime || observation.effectivePeriod?.start || '';\n if (!collectionDate) {\n return {\n skipped: {\n index,\n loincCode,\n reason: 'Observation has no effectiveDateTime or effectivePeriod.start',\n resourceType: 'Observation',\n },\n };\n }\n\n // Extract reference ranges\n let referenceMin: number | undefined;\n let referenceMax: number | undefined;\n if (observation.referenceRange?.[0]) {\n referenceMin = observation.referenceRange[0].low?.value;\n referenceMax = observation.referenceRange[0].high?.value;\n }\n\n const imported: ImportedObservation = {\n biomarkerCode: internalCode,\n biomarkerName:\n definition?.names.pt[0] || definition?.names.en[0] || observation.code.text || internalCode,\n collectionDate,\n flag: extractFlag(observation),\n isQualitative,\n loincCode,\n referenceMax,\n referenceMin,\n unit: unit || definition?.unit || '',\n value,\n };\n\n return { observation: imported };\n}\n\n/**\n * Process a complete FHIR Bundle for import\n */\nexport function processImportBundle(data: unknown): FHIRImportResult {\n // Structural validation\n const validationErrors = validateFHIRImportBundle(data);\n if (validationErrors.length > 0) {\n return {\n errors: validationErrors,\n imported: [],\n skipped: [],\n totalProcessed: 0,\n };\n }\n\n const bundle = data as FHIRBundle;\n\n // Extract observations\n const { observations, skipped } = extractObservationsFromBundle(bundle);\n\n // Map each observation to internal format\n const imported: ImportedObservation[] = [];\n const allSkipped: SkippedEntry[] = [...skipped];\n\n for (let i = 0; i < observations.length; i++) {\n const result = mapFHIRObservationToInternal(observations[i]!, i);\n\n if ('observation' in result) {\n imported.push(result.observation);\n } else {\n allSkipped.push(result.skipped);\n }\n }\n\n return {\n errors: [],\n imported,\n skipped: allSkipped,\n totalProcessed: observations.length,\n };\n}\n\nexport { MAX_FILE_SIZE, MAX_OBSERVATIONS };\n"],"mappings":";;;;;;;;;AAuDA,IAAM,mBAAmB;AACzB,IAAM,gBAAgB,KAAK,OAAO;AAKlC,SAAS,iBAAiB,aAAkD;AAC1E,MAAI,CAAC,YAAY,MAAM,OAAQ,QAAO;AACtC,QAAM,cAAc,YAAY,KAAK,OAAO,KAAK,CAAC,MAAM,EAAE,WAAW,kBAAkB;AACvF,SAAO,aAAa;AACtB;AAKA,SAAS,YAAY,aAA8C;AACjE,QAAM,OAAO,YAAY,iBAAiB,CAAC,GAAG,SAAS,CAAC,GAAG;AAC3D,MAAI,SAAS,OAAO,SAAS,KAAM,QAAO;AAC1C,MAAI,SAAS,OAAO,SAAS,KAAM,QAAO;AAC1C,SAAO;AACT;AAKO,SAAS,8BAA8B,QAG5C;AACA,QAAM,eAAkC,CAAC;AACzC,QAAM,UAA0B,CAAC;AAEjC,WAAS,IAAI,GAAG,IAAI,OAAO,MAAM,QAAQ,KAAK;AAC5C,UAAM,QAAQ,OAAO,MAAM,CAAC;AAC5B,QAAI,CAAC,MAAM,UAAU;AACnB,cAAQ,KAAK,EAAE,OAAO,GAAG,QAAQ,wBAAwB,CAAC;AAC1D;AAAA,IACF;AAEA,QAAI,MAAM,SAAS,iBAAiB,eAAe;AAEjD;AAAA,IACF;AAEA,QAAI,aAAa,UAAU,kBAAkB;AAC3C,cAAQ,KAAK,EAAE,OAAO,GAAG,QAAQ,cAAc,gBAAgB,yBAAyB,CAAC;AACzF;AAAA,IACF;AAEA,iBAAa,KAAK,MAAM,QAA2B;AAAA,EACrD;AAEA,SAAO,EAAE,cAAc,QAAQ;AACjC;AAKO,SAAS,6BACd,aACA,OACkE;AAClE,QAAM,YAAY,iBAAiB,WAAW;AAE9C,MAAI,CAAC,WAAW;AACd,WAAO;AAAA,MACL,SAAS;AAAA,QACP;AAAA,QACA,QAAQ;AAAA,QACR,cAAc;AAAA,MAChB;AAAA,IACF;AAAA,EACF;AAEA,QAAM,eAAe,YAAY,SAAS;AAC1C,MAAI,CAAC,cAAc;AACjB,WAAO;AAAA,MACL,SAAS;AAAA,QACP;AAAA,QACA;AAAA,QACA,QAAQ,uBAAuB,SAAS;AAAA,QACxC,cAAc;AAAA,MAChB;AAAA,IACF;AAAA,EACF;AAEA,QAAM,aAAa,qBAAqB,SAAS;AAGjD,MAAI;AACJ,MAAI,OAAO;AACX,MAAI,gBAAgB;AAEpB,MAAI,YAAY,eAAe,UAAU,QAAW;AAClD,YAAQ,YAAY,cAAc;AAClC,WAAO,YAAY,cAAc,QAAQ,YAAY,cAAc,QAAQ;AAAA,EAC7E,WAAW,YAAY,aAAa;AAClC,YAAQ,YAAY;AACpB,oBAAgB;AAAA,EAClB,OAAO;AACL,WAAO;AAAA,MACL,SAAS;AAAA,QACP;AAAA,QACA;AAAA,QACA,QAAQ;AAAA,QACR,cAAc;AAAA,MAChB;AAAA,IACF;AAAA,EACF;AAGA,QAAM,iBAAiB,YAAY,qBAAqB,YAAY,iBAAiB,SAAS;AAC9F,MAAI,CAAC,gBAAgB;AACnB,WAAO;AAAA,MACL,SAAS;AAAA,QACP;AAAA,QACA;AAAA,QACA,QAAQ;AAAA,QACR,cAAc;AAAA,MAChB;AAAA,IACF;AAAA,EACF;AAGA,MAAI;AACJ,MAAI;AACJ,MAAI,YAAY,iBAAiB,CAAC,GAAG;AACnC,mBAAe,YAAY,eAAe,CAAC,EAAE,KAAK;AAClD,mBAAe,YAAY,eAAe,CAAC,EAAE,MAAM;AAAA,EACrD;AAEA,QAAM,WAAgC;AAAA,IACpC,eAAe;AAAA,IACf,eACE,YAAY,MAAM,GAAG,CAAC,KAAK,YAAY,MAAM,GAAG,CAAC,KAAK,YAAY,KAAK,QAAQ;AAAA,IACjF;AAAA,IACA,MAAM,YAAY,WAAW;AAAA,IAC7B;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA,MAAM,QAAQ,YAAY,QAAQ;AAAA,IAClC;AAAA,EACF;AAEA,SAAO,EAAE,aAAa,SAAS;AACjC;AAKO,SAAS,oBAAoB,MAAiC;AAEnE,QAAM,mBAAmB,yBAAyB,IAAI;AACtD,MAAI,iBAAiB,SAAS,GAAG;AAC/B,WAAO;AAAA,MACL,QAAQ;AAAA,MACR,UAAU,CAAC;AAAA,MACX,SAAS,CAAC;AAAA,MACV,gBAAgB;AAAA,IAClB;AAAA,EACF;AAEA,QAAM,SAAS;AAGf,QAAM,EAAE,cAAc,QAAQ,IAAI,8BAA8B,MAAM;AAGtE,QAAM,WAAkC,CAAC;AACzC,QAAM,aAA6B,CAAC,GAAG,OAAO;AAE9C,WAAS,IAAI,GAAG,IAAI,aAAa,QAAQ,KAAK;AAC5C,UAAM,SAAS,6BAA6B,aAAa,CAAC,GAAI,CAAC;AAE/D,QAAI,iBAAiB,QAAQ;AAC3B,eAAS,KAAK,OAAO,WAAW;AAAA,IAClC,OAAO;AACL,iBAAW,KAAK,OAAO,OAAO;AAAA,IAChC;AAAA,EACF;AAEA,SAAO;AAAA,IACL,QAAQ,CAAC;AAAA,IACT;AAAA,IACA,SAAS;AAAA,IACT,gBAAgB,aAAa;AAAA,EAC/B;AACF;","names":[]}
package/dist/cli.js CHANGED
@@ -3888,8 +3888,8 @@ function validateFHIRImportBundle(data) {
3888
3888
  }
3889
3889
 
3890
3890
  // src/importer.ts
3891
- var MAX_OBSERVATIONS = 1e3;
3892
- var MAX_FILE_SIZE = 5 * 1024 * 1024;
3891
+ var MAX_OBSERVATIONS = 5e3;
3892
+ var MAX_FILE_SIZE = 15 * 1024 * 1024;
3893
3893
  function extractLoincCode(observation) {
3894
3894
  if (!observation.code?.coding) return void 0;
3895
3895
  const loincCoding = observation.code.coding.find((c) => c.system === "http://loinc.org");
@@ -6192,7 +6192,7 @@ async function main() {
6192
6192
  strict: false
6193
6193
  });
6194
6194
  if (values.version) {
6195
- process.stdout.write(`${"0.17.4"}
6195
+ process.stdout.write(`${"0.18.0"}
6196
6196
  `);
6197
6197
  return;
6198
6198
  }
package/dist/importer.cjs CHANGED
@@ -4,7 +4,7 @@
4
4
 
5
5
 
6
6
 
7
- var _chunkR6FI2RNBcjs = require('./chunk-R6FI2RNB.cjs');
7
+ var _chunkHGEQS7P7cjs = require('./chunk-HGEQS7P7.cjs');
8
8
  require('./chunk-ONRVND6U.cjs');
9
9
  require('./chunk-3ILBFLVQ.cjs');
10
10
 
@@ -13,5 +13,5 @@ require('./chunk-3ILBFLVQ.cjs');
13
13
 
14
14
 
15
15
 
16
- exports.MAX_FILE_SIZE = _chunkR6FI2RNBcjs.MAX_FILE_SIZE; exports.MAX_OBSERVATIONS = _chunkR6FI2RNBcjs.MAX_OBSERVATIONS; exports.extractObservationsFromBundle = _chunkR6FI2RNBcjs.extractObservationsFromBundle; exports.mapFHIRObservationToInternal = _chunkR6FI2RNBcjs.mapFHIRObservationToInternal; exports.processImportBundle = _chunkR6FI2RNBcjs.processImportBundle;
16
+ exports.MAX_FILE_SIZE = _chunkHGEQS7P7cjs.MAX_FILE_SIZE; exports.MAX_OBSERVATIONS = _chunkHGEQS7P7cjs.MAX_OBSERVATIONS; exports.extractObservationsFromBundle = _chunkHGEQS7P7cjs.extractObservationsFromBundle; exports.mapFHIRObservationToInternal = _chunkHGEQS7P7cjs.mapFHIRObservationToInternal; exports.processImportBundle = _chunkHGEQS7P7cjs.processImportBundle;
17
17
  //# sourceMappingURL=importer.cjs.map
@@ -35,7 +35,19 @@ interface FHIRImportResult {
35
35
  skipped: SkippedEntry[];
36
36
  totalProcessed: number;
37
37
  }
38
- declare const MAX_OBSERVATIONS = 1000;
38
+ /**
39
+ * Limites de importação.
40
+ *
41
+ * Uma Observation exportada ocupa cerca de 1,25KB em JSON compacto e 2,75KB
42
+ * quando o arquivo vem indentado, medido sobre um histórico real de 998
43
+ * Observations em 61 laudos. Nesse tamanho, 5000 Observations dão 6,0MB
44
+ * compactos ou 13,1MB indentados, e por isso o teto de arquivo é 15MB: cobre
45
+ * as duas formas com folga.
46
+ *
47
+ * Na densidade desse mesmo histórico (16 Observations por laudo), 5000
48
+ * equivalem a cerca de 300 laudos.
49
+ */
50
+ declare const MAX_OBSERVATIONS = 5000;
39
51
  declare const MAX_FILE_SIZE: number;
40
52
  /**
41
53
  * Extract Observation resources from a FHIR Bundle
@@ -35,7 +35,19 @@ interface FHIRImportResult {
35
35
  skipped: SkippedEntry[];
36
36
  totalProcessed: number;
37
37
  }
38
- declare const MAX_OBSERVATIONS = 1000;
38
+ /**
39
+ * Limites de importação.
40
+ *
41
+ * Uma Observation exportada ocupa cerca de 1,25KB em JSON compacto e 2,75KB
42
+ * quando o arquivo vem indentado, medido sobre um histórico real de 998
43
+ * Observations em 61 laudos. Nesse tamanho, 5000 Observations dão 6,0MB
44
+ * compactos ou 13,1MB indentados, e por isso o teto de arquivo é 15MB: cobre
45
+ * as duas formas com folga.
46
+ *
47
+ * Na densidade desse mesmo histórico (16 Observations por laudo), 5000
48
+ * equivalem a cerca de 300 laudos.
49
+ */
50
+ declare const MAX_OBSERVATIONS = 5000;
39
51
  declare const MAX_FILE_SIZE: number;
40
52
  /**
41
53
  * Extract Observation resources from a FHIR Bundle
package/dist/importer.js CHANGED
@@ -4,7 +4,7 @@ import {
4
4
  extractObservationsFromBundle,
5
5
  mapFHIRObservationToInternal,
6
6
  processImportBundle
7
- } from "./chunk-NAUVJPLC.js";
7
+ } from "./chunk-HP3OETAJ.js";
8
8
  import "./chunk-7O6VUA2B.js";
9
9
  import "./chunk-N3ZCOLG2.js";
10
10
  export {
package/dist/index.cjs CHANGED
@@ -10,7 +10,7 @@ var _chunkNP4YZFUIcjs = require('./chunk-NP4YZFUI.cjs');
10
10
 
11
11
 
12
12
 
13
- var _chunkR6FI2RNBcjs = require('./chunk-R6FI2RNB.cjs');
13
+ var _chunkHGEQS7P7cjs = require('./chunk-HGEQS7P7.cjs');
14
14
 
15
15
 
16
16
 
@@ -691,5 +691,5 @@ function cnsToFHIRIdentifier(cns) {
691
691
 
692
692
 
693
693
 
694
- exports.AGE_BRACKETS = AGE_BRACKETS; exports.BIOMARKER_DEFAULT_UNIT = _chunkMJ254F5Kcjs.BIOMARKER_DEFAULT_UNIT; exports.BIOMARKER_DEFINITIONS = _chunkONRVND6Ucjs.BIOMARKER_DEFINITIONS; exports.BIOMARKER_UNITS = _chunkMJ254F5Kcjs.BIOMARKER_UNITS; exports.BODY_FAT_ZONES = BODY_FAT_ZONES; exports.CAC_INDICATOR_CODES = _chunkONRVND6Ucjs.CAC_INDICATOR_CODES; exports.CATEGORY_GROUPS = CATEGORY_GROUPS; exports.CATEGORY_SCREENING_INTERVALS = CATEGORY_SCREENING_INTERVALS; exports.DEXA_CATEGORIES = _chunkONRVND6Ucjs.DEXA_CATEGORIES; exports.DEXA_INDICATOR_CODES = _chunkONRVND6Ucjs.DEXA_INDICATOR_CODES; exports.MAX_FILE_SIZE = _chunkR6FI2RNBcjs.MAX_FILE_SIZE; exports.MAX_OBSERVATIONS = _chunkR6FI2RNBcjs.MAX_OBSERVATIONS; exports.T_SCORE_ZONES = T_SCORE_ZONES; exports.UNIT_TO_UCUM = _chunkMJ254F5Kcjs.UNIT_TO_UCUM; exports.ZONE_DEFS = ZONE_DEFS; exports.applyFallbackReferenceRanges = _chunkCBGEU6SGcjs.applyFallbackReferenceRanges; exports.biomarkerRangeDefinitions = _chunkCBGEU6SGcjs.biomarkerRangeDefinitions; exports.calculateNextScreeningDate = calculateNextScreeningDate; exports.cnsToFHIRIdentifier = cnsToFHIRIdentifier; exports.codeToLoinc = _chunkONRVND6Ucjs.codeToLoinc; exports.convertUnit = _chunkMJ254F5Kcjs.convertUnit; exports.cpfToFHIRIdentifier = cpfToFHIRIdentifier; exports.defaultReferenceRanges = _chunkCBGEU6SGcjs.defaultReferenceRanges; exports.extractObservationsFromBundle = _chunkR6FI2RNBcjs.extractObservationsFromBundle; exports.filterVisibleBiomarkers = _chunkONRVND6Ucjs.filterVisibleBiomarkers; exports.findCodeByName = _chunkONRVND6Ucjs.findCodeByName; exports.formatCNS = formatCNS; exports.formatCPF = formatCPF; exports.generateCacFullReference = _chunkONRVND6Ucjs.generateCacFullReference; exports.generateDexaFullReference = _chunkONRVND6Ucjs.generateDexaFullReference; exports.generateFilteredLLMReference = _chunkONRVND6Ucjs.generateFilteredLLMReference; exports.generateLLMReference = _chunkONRVND6Ucjs.generateLLMReference; exports.getAllCodes = _chunkONRVND6Ucjs.getAllCodes; exports.getAllDefinitions = _chunkONRVND6Ucjs.getAllDefinitions; exports.getAllLoincCodes = _chunkONRVND6Ucjs.getAllLoincCodes; exports.getAllSearchPatterns = _chunkONRVND6Ucjs.getAllSearchPatterns; exports.getBiomarkersByCategory = _chunkONRVND6Ucjs.getBiomarkersByCategory; exports.getBiomarkersForCategories = _chunkONRVND6Ucjs.getBiomarkersForCategories; exports.getCanonicalUnit = _chunkMJ254F5Kcjs.getCanonicalUnit; exports.getCategoriesByInterval = getCategoriesByInterval; exports.getCategoryGroup = getCategoryGroup; exports.getDaysUntilScreening = getDaysUntilScreening; exports.getDefaultUnit = _chunkMJ254F5Kcjs.getDefaultUnit; exports.getDefinitionByCode = _chunkONRVND6Ucjs.getDefinitionByCode; exports.getDefinitionByLoinc = _chunkONRVND6Ucjs.getDefinitionByLoinc; exports.getDefinitionsBySex = _chunkONRVND6Ucjs.getDefinitionsBySex; exports.getDueCategories = getDueCategories; exports.getFallbackReferenceRange = _chunkCBGEU6SGcjs.getFallbackReferenceRange; exports.getRangeDirection = _chunkCBGEU6SGcjs.getRangeDirection; exports.getReferenceRange = _chunkCBGEU6SGcjs.getReferenceRange; exports.getSIUnit = _chunkMJ254F5Kcjs.getSIUnit; exports.getScreeningInterval = getScreeningInterval; exports.getSexForCode = _chunkONRVND6Ucjs.getSexForCode; exports.getVisibleDefinitions = _chunkONRVND6Ucjs.getVisibleDefinitions; exports.interventionToFHIRMedicationStatement = interventionToFHIRMedicationStatement; exports.interventionToFHIRObservation = interventionToFHIRObservation; exports.interventionsToFHIRBundle = interventionsToFHIRBundle; exports.isBiomarkerVisible = _chunkONRVND6Ucjs.isBiomarkerVisible; exports.isCacDocument = _chunkONRVND6Ucjs.isCacDocument; exports.isDexaDocument = _chunkONRVND6Ucjs.isDexaDocument; exports.isScreeningDue = isScreeningDue; exports.isValidCode = _chunkONRVND6Ucjs.isValidCode; exports.isValidLoinc = _chunkONRVND6Ucjs.isValidLoinc; exports.labObservationToFHIR = _chunkNP4YZFUIcjs.labObservationToFHIR; exports.labReportToFHIR = _chunkNP4YZFUIcjs.labReportToFHIR; exports.labResultToFHIRBundle = _chunkNP4YZFUIcjs.labResultToFHIRBundle; exports.listMappedSubcategories = listMappedSubcategories; exports.loincToCode = _chunkONRVND6Ucjs.loincToCode; exports.mapFHIRObservationToInternal = _chunkR6FI2RNBcjs.mapFHIRObservationToInternal; exports.normalizeCode = _chunkONRVND6Ucjs.normalizeCode; exports.plural = plural; exports.pluralCount = pluralCount; exports.pluralPhrase = pluralPhrase; exports.pluralPhraseCount = pluralPhraseCount; exports.processImportBundle = _chunkR6FI2RNBcjs.processImportBundle; exports.toBiomarkerTests = _chunkONRVND6Ucjs.toBiomarkerTests; exports.unitToUCUM = _chunkMJ254F5Kcjs.unitToUCUM; exports.userProfileToFHIR = _chunkNP4YZFUIcjs.userProfileToFHIR; exports.validateCNS = validateCNS; exports.validateCPF = validateCPF; exports.validateFHIRDiagnosticReport = _chunk3ILBFLVQcjs.validateFHIRDiagnosticReport; exports.validateFHIRImportBundle = _chunk3ILBFLVQcjs.validateFHIRImportBundle; exports.validateFHIRObservation = _chunk3ILBFLVQcjs.validateFHIRObservation; exports.validateLoincNameMatch = _chunkONRVND6Ucjs.validateLoincNameMatch;
694
+ exports.AGE_BRACKETS = AGE_BRACKETS; exports.BIOMARKER_DEFAULT_UNIT = _chunkMJ254F5Kcjs.BIOMARKER_DEFAULT_UNIT; exports.BIOMARKER_DEFINITIONS = _chunkONRVND6Ucjs.BIOMARKER_DEFINITIONS; exports.BIOMARKER_UNITS = _chunkMJ254F5Kcjs.BIOMARKER_UNITS; exports.BODY_FAT_ZONES = BODY_FAT_ZONES; exports.CAC_INDICATOR_CODES = _chunkONRVND6Ucjs.CAC_INDICATOR_CODES; exports.CATEGORY_GROUPS = CATEGORY_GROUPS; exports.CATEGORY_SCREENING_INTERVALS = CATEGORY_SCREENING_INTERVALS; exports.DEXA_CATEGORIES = _chunkONRVND6Ucjs.DEXA_CATEGORIES; exports.DEXA_INDICATOR_CODES = _chunkONRVND6Ucjs.DEXA_INDICATOR_CODES; exports.MAX_FILE_SIZE = _chunkHGEQS7P7cjs.MAX_FILE_SIZE; exports.MAX_OBSERVATIONS = _chunkHGEQS7P7cjs.MAX_OBSERVATIONS; exports.T_SCORE_ZONES = T_SCORE_ZONES; exports.UNIT_TO_UCUM = _chunkMJ254F5Kcjs.UNIT_TO_UCUM; exports.ZONE_DEFS = ZONE_DEFS; exports.applyFallbackReferenceRanges = _chunkCBGEU6SGcjs.applyFallbackReferenceRanges; exports.biomarkerRangeDefinitions = _chunkCBGEU6SGcjs.biomarkerRangeDefinitions; exports.calculateNextScreeningDate = calculateNextScreeningDate; exports.cnsToFHIRIdentifier = cnsToFHIRIdentifier; exports.codeToLoinc = _chunkONRVND6Ucjs.codeToLoinc; exports.convertUnit = _chunkMJ254F5Kcjs.convertUnit; exports.cpfToFHIRIdentifier = cpfToFHIRIdentifier; exports.defaultReferenceRanges = _chunkCBGEU6SGcjs.defaultReferenceRanges; exports.extractObservationsFromBundle = _chunkHGEQS7P7cjs.extractObservationsFromBundle; exports.filterVisibleBiomarkers = _chunkONRVND6Ucjs.filterVisibleBiomarkers; exports.findCodeByName = _chunkONRVND6Ucjs.findCodeByName; exports.formatCNS = formatCNS; exports.formatCPF = formatCPF; exports.generateCacFullReference = _chunkONRVND6Ucjs.generateCacFullReference; exports.generateDexaFullReference = _chunkONRVND6Ucjs.generateDexaFullReference; exports.generateFilteredLLMReference = _chunkONRVND6Ucjs.generateFilteredLLMReference; exports.generateLLMReference = _chunkONRVND6Ucjs.generateLLMReference; exports.getAllCodes = _chunkONRVND6Ucjs.getAllCodes; exports.getAllDefinitions = _chunkONRVND6Ucjs.getAllDefinitions; exports.getAllLoincCodes = _chunkONRVND6Ucjs.getAllLoincCodes; exports.getAllSearchPatterns = _chunkONRVND6Ucjs.getAllSearchPatterns; exports.getBiomarkersByCategory = _chunkONRVND6Ucjs.getBiomarkersByCategory; exports.getBiomarkersForCategories = _chunkONRVND6Ucjs.getBiomarkersForCategories; exports.getCanonicalUnit = _chunkMJ254F5Kcjs.getCanonicalUnit; exports.getCategoriesByInterval = getCategoriesByInterval; exports.getCategoryGroup = getCategoryGroup; exports.getDaysUntilScreening = getDaysUntilScreening; exports.getDefaultUnit = _chunkMJ254F5Kcjs.getDefaultUnit; exports.getDefinitionByCode = _chunkONRVND6Ucjs.getDefinitionByCode; exports.getDefinitionByLoinc = _chunkONRVND6Ucjs.getDefinitionByLoinc; exports.getDefinitionsBySex = _chunkONRVND6Ucjs.getDefinitionsBySex; exports.getDueCategories = getDueCategories; exports.getFallbackReferenceRange = _chunkCBGEU6SGcjs.getFallbackReferenceRange; exports.getRangeDirection = _chunkCBGEU6SGcjs.getRangeDirection; exports.getReferenceRange = _chunkCBGEU6SGcjs.getReferenceRange; exports.getSIUnit = _chunkMJ254F5Kcjs.getSIUnit; exports.getScreeningInterval = getScreeningInterval; exports.getSexForCode = _chunkONRVND6Ucjs.getSexForCode; exports.getVisibleDefinitions = _chunkONRVND6Ucjs.getVisibleDefinitions; exports.interventionToFHIRMedicationStatement = interventionToFHIRMedicationStatement; exports.interventionToFHIRObservation = interventionToFHIRObservation; exports.interventionsToFHIRBundle = interventionsToFHIRBundle; exports.isBiomarkerVisible = _chunkONRVND6Ucjs.isBiomarkerVisible; exports.isCacDocument = _chunkONRVND6Ucjs.isCacDocument; exports.isDexaDocument = _chunkONRVND6Ucjs.isDexaDocument; exports.isScreeningDue = isScreeningDue; exports.isValidCode = _chunkONRVND6Ucjs.isValidCode; exports.isValidLoinc = _chunkONRVND6Ucjs.isValidLoinc; exports.labObservationToFHIR = _chunkNP4YZFUIcjs.labObservationToFHIR; exports.labReportToFHIR = _chunkNP4YZFUIcjs.labReportToFHIR; exports.labResultToFHIRBundle = _chunkNP4YZFUIcjs.labResultToFHIRBundle; exports.listMappedSubcategories = listMappedSubcategories; exports.loincToCode = _chunkONRVND6Ucjs.loincToCode; exports.mapFHIRObservationToInternal = _chunkHGEQS7P7cjs.mapFHIRObservationToInternal; exports.normalizeCode = _chunkONRVND6Ucjs.normalizeCode; exports.plural = plural; exports.pluralCount = pluralCount; exports.pluralPhrase = pluralPhrase; exports.pluralPhraseCount = pluralPhraseCount; exports.processImportBundle = _chunkHGEQS7P7cjs.processImportBundle; exports.toBiomarkerTests = _chunkONRVND6Ucjs.toBiomarkerTests; exports.unitToUCUM = _chunkMJ254F5Kcjs.unitToUCUM; exports.userProfileToFHIR = _chunkNP4YZFUIcjs.userProfileToFHIR; exports.validateCNS = validateCNS; exports.validateCPF = validateCPF; exports.validateFHIRDiagnosticReport = _chunk3ILBFLVQcjs.validateFHIRDiagnosticReport; exports.validateFHIRImportBundle = _chunk3ILBFLVQcjs.validateFHIRImportBundle; exports.validateFHIRObservation = _chunk3ILBFLVQcjs.validateFHIRObservation; exports.validateLoincNameMatch = _chunkONRVND6Ucjs.validateLoincNameMatch;
695
695
  //# sourceMappingURL=index.cjs.map
package/dist/index.js CHANGED
@@ -10,7 +10,7 @@ import {
10
10
  extractObservationsFromBundle,
11
11
  mapFHIRObservationToInternal,
12
12
  processImportBundle
13
- } from "./chunk-NAUVJPLC.js";
13
+ } from "./chunk-HP3OETAJ.js";
14
14
  import {
15
15
  BIOMARKER_DEFINITIONS,
16
16
  CAC_INDICATOR_CODES,
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@precisa-saude/fhir",
3
- "version": "0.17.4",
3
+ "version": "0.18.0",
4
4
  "description": "Tipos FHIR R4, definições de biomarcadores, faixas de referência e conversores para o ecossistema de saúde brasileiro",
5
5
  "keywords": [
6
6
  "fhir",
@@ -1 +0,0 @@
1
- {"version":3,"sources":["../src/importer.ts"],"sourcesContent":["/**\n * FHIR Importer\n *\n * Parses FHIR R4 Bundles and extracts Observation resources with known LOINC codes,\n * mapping them to internal biomarker codes for storage as lab results.\n */\n\nimport { getDefinitionByLoinc, loincToCode } from './biomarkers';\nimport type { FHIRBundle, FHIRObservation } from './fhir-types';\nimport { validateFHIRImportBundle } from './validators';\n\nexport interface ImportedObservation {\n biomarkerCode: string;\n biomarkerName: string;\n collectionDate: string;\n flag: 'H' | 'L' | '';\n isQualitative: boolean;\n loincCode: string;\n referenceMax?: number;\n referenceMin?: number;\n unit: string;\n value: number | string;\n}\n\nexport interface SkippedEntry {\n index: number;\n loincCode?: string;\n reason: string;\n resourceType?: string;\n}\n\nexport interface ImportError {\n details: string;\n field: string;\n}\n\nexport interface FHIRImportResult {\n errors: ImportError[];\n imported: ImportedObservation[];\n skipped: SkippedEntry[];\n totalProcessed: number;\n}\n\nconst MAX_OBSERVATIONS = 1000;\nconst MAX_FILE_SIZE = 5 * 1024 * 1024; // 5MB\n\n/**\n * Extract LOINC code from an Observation's code.coding array\n */\nfunction extractLoincCode(observation: FHIRObservation): string | undefined {\n if (!observation.code?.coding) return undefined;\n const loincCoding = observation.code.coding.find((c) => c.system === 'http://loinc.org');\n return loincCoding?.code;\n}\n\n/**\n * Extract interpretation flag from Observation\n */\nfunction extractFlag(observation: FHIRObservation): 'H' | 'L' | '' {\n const code = observation.interpretation?.[0]?.coding?.[0]?.code;\n if (code === 'H' || code === 'HH') return 'H';\n if (code === 'L' || code === 'LL') return 'L';\n return '';\n}\n\n/**\n * Extract Observation resources from a FHIR Bundle\n */\nexport function extractObservationsFromBundle(bundle: FHIRBundle): {\n observations: FHIRObservation[];\n skipped: SkippedEntry[];\n} {\n const observations: FHIRObservation[] = [];\n const skipped: SkippedEntry[] = [];\n\n for (let i = 0; i < bundle.entry.length; i++) {\n const entry = bundle.entry[i]!;\n if (!entry.resource) {\n skipped.push({ index: i, reason: 'Entry has no resource' });\n continue;\n }\n\n if (entry.resource.resourceType !== 'Observation') {\n // Non-observation resources are silently skipped (Patient, DiagnosticReport, etc.)\n continue;\n }\n\n if (observations.length >= MAX_OBSERVATIONS) {\n skipped.push({ index: i, reason: `Maximum of ${MAX_OBSERVATIONS} observations exceeded` });\n continue;\n }\n\n observations.push(entry.resource as FHIRObservation);\n }\n\n return { observations, skipped };\n}\n\n/**\n * Map a FHIR Observation to internal format using LOINC→biomarker code lookup\n */\nexport function mapFHIRObservationToInternal(\n observation: FHIRObservation,\n index: number,\n): { observation: ImportedObservation } | { skipped: SkippedEntry } {\n const loincCode = extractLoincCode(observation);\n\n if (!loincCode) {\n return {\n skipped: {\n index,\n reason: 'No LOINC code found in observation coding',\n resourceType: 'Observation',\n },\n };\n }\n\n const internalCode = loincToCode(loincCode);\n if (!internalCode) {\n return {\n skipped: {\n index,\n loincCode,\n reason: `Unknown LOINC code: ${loincCode}`,\n resourceType: 'Observation',\n },\n };\n }\n\n const definition = getDefinitionByLoinc(loincCode);\n\n // Extract value\n let value: number | string;\n let unit = '';\n let isQualitative = false;\n\n if (observation.valueQuantity?.value !== undefined) {\n value = observation.valueQuantity.value;\n unit = observation.valueQuantity.unit || observation.valueQuantity.code || '';\n } else if (observation.valueString) {\n value = observation.valueString;\n isQualitative = true;\n } else {\n return {\n skipped: {\n index,\n loincCode,\n reason: 'Observation has no value (valueQuantity or valueString)',\n resourceType: 'Observation',\n },\n };\n }\n\n // Extract collection date (effectiveDateTime or effectivePeriod.start)\n const collectionDate = observation.effectiveDateTime || observation.effectivePeriod?.start || '';\n if (!collectionDate) {\n return {\n skipped: {\n index,\n loincCode,\n reason: 'Observation has no effectiveDateTime or effectivePeriod.start',\n resourceType: 'Observation',\n },\n };\n }\n\n // Extract reference ranges\n let referenceMin: number | undefined;\n let referenceMax: number | undefined;\n if (observation.referenceRange?.[0]) {\n referenceMin = observation.referenceRange[0].low?.value;\n referenceMax = observation.referenceRange[0].high?.value;\n }\n\n const imported: ImportedObservation = {\n biomarkerCode: internalCode,\n biomarkerName:\n definition?.names.pt[0] || definition?.names.en[0] || observation.code.text || internalCode,\n collectionDate,\n flag: extractFlag(observation),\n isQualitative,\n loincCode,\n referenceMax,\n referenceMin,\n unit: unit || definition?.unit || '',\n value,\n };\n\n return { observation: imported };\n}\n\n/**\n * Process a complete FHIR Bundle for import\n */\nexport function processImportBundle(data: unknown): FHIRImportResult {\n // Structural validation\n const validationErrors = validateFHIRImportBundle(data);\n if (validationErrors.length > 0) {\n return {\n errors: validationErrors,\n imported: [],\n skipped: [],\n totalProcessed: 0,\n };\n }\n\n const bundle = data as FHIRBundle;\n\n // Extract observations\n const { observations, skipped } = extractObservationsFromBundle(bundle);\n\n // Map each observation to internal format\n const imported: ImportedObservation[] = [];\n const allSkipped: SkippedEntry[] = [...skipped];\n\n for (let i = 0; i < observations.length; i++) {\n const result = mapFHIRObservationToInternal(observations[i]!, i);\n\n if ('observation' in result) {\n imported.push(result.observation);\n } else {\n allSkipped.push(result.skipped);\n }\n }\n\n return {\n errors: [],\n imported,\n skipped: allSkipped,\n totalProcessed: observations.length,\n };\n}\n\nexport { MAX_FILE_SIZE, MAX_OBSERVATIONS };\n"],"mappings":"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","names":[]}
@@ -1 +0,0 @@
1
- {"version":3,"sources":["/home/runner/work/fhir-brasil/fhir-brasil/packages/core/dist/chunk-R6FI2RNB.cjs","../src/importer.ts"],"names":[],"mappings":"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","file":"/home/runner/work/fhir-brasil/fhir-brasil/packages/core/dist/chunk-R6FI2RNB.cjs","sourcesContent":[null,"/**\n * FHIR Importer\n *\n * Parses FHIR R4 Bundles and extracts Observation resources with known LOINC codes,\n * mapping them to internal biomarker codes for storage as lab results.\n */\n\nimport { getDefinitionByLoinc, loincToCode } from './biomarkers';\nimport type { FHIRBundle, FHIRObservation } from './fhir-types';\nimport { validateFHIRImportBundle } from './validators';\n\nexport interface ImportedObservation {\n biomarkerCode: string;\n biomarkerName: string;\n collectionDate: string;\n flag: 'H' | 'L' | '';\n isQualitative: boolean;\n loincCode: string;\n referenceMax?: number;\n referenceMin?: number;\n unit: string;\n value: number | string;\n}\n\nexport interface SkippedEntry {\n index: number;\n loincCode?: string;\n reason: string;\n resourceType?: string;\n}\n\nexport interface ImportError {\n details: string;\n field: string;\n}\n\nexport interface FHIRImportResult {\n errors: ImportError[];\n imported: ImportedObservation[];\n skipped: SkippedEntry[];\n totalProcessed: number;\n}\n\nconst MAX_OBSERVATIONS = 1000;\nconst MAX_FILE_SIZE = 5 * 1024 * 1024; // 5MB\n\n/**\n * Extract LOINC code from an Observation's code.coding array\n */\nfunction extractLoincCode(observation: FHIRObservation): string | undefined {\n if (!observation.code?.coding) return undefined;\n const loincCoding = observation.code.coding.find((c) => c.system === 'http://loinc.org');\n return loincCoding?.code;\n}\n\n/**\n * Extract interpretation flag from Observation\n */\nfunction extractFlag(observation: FHIRObservation): 'H' | 'L' | '' {\n const code = observation.interpretation?.[0]?.coding?.[0]?.code;\n if (code === 'H' || code === 'HH') return 'H';\n if (code === 'L' || code === 'LL') return 'L';\n return '';\n}\n\n/**\n * Extract Observation resources from a FHIR Bundle\n */\nexport function extractObservationsFromBundle(bundle: FHIRBundle): {\n observations: FHIRObservation[];\n skipped: SkippedEntry[];\n} {\n const observations: FHIRObservation[] = [];\n const skipped: SkippedEntry[] = [];\n\n for (let i = 0; i < bundle.entry.length; i++) {\n const entry = bundle.entry[i]!;\n if (!entry.resource) {\n skipped.push({ index: i, reason: 'Entry has no resource' });\n continue;\n }\n\n if (entry.resource.resourceType !== 'Observation') {\n // Non-observation resources are silently skipped (Patient, DiagnosticReport, etc.)\n continue;\n }\n\n if (observations.length >= MAX_OBSERVATIONS) {\n skipped.push({ index: i, reason: `Maximum of ${MAX_OBSERVATIONS} observations exceeded` });\n continue;\n }\n\n observations.push(entry.resource as FHIRObservation);\n }\n\n return { observations, skipped };\n}\n\n/**\n * Map a FHIR Observation to internal format using LOINC→biomarker code lookup\n */\nexport function mapFHIRObservationToInternal(\n observation: FHIRObservation,\n index: number,\n): { observation: ImportedObservation } | { skipped: SkippedEntry } {\n const loincCode = extractLoincCode(observation);\n\n if (!loincCode) {\n return {\n skipped: {\n index,\n reason: 'No LOINC code found in observation coding',\n resourceType: 'Observation',\n },\n };\n }\n\n const internalCode = loincToCode(loincCode);\n if (!internalCode) {\n return {\n skipped: {\n index,\n loincCode,\n reason: `Unknown LOINC code: ${loincCode}`,\n resourceType: 'Observation',\n },\n };\n }\n\n const definition = getDefinitionByLoinc(loincCode);\n\n // Extract value\n let value: number | string;\n let unit = '';\n let isQualitative = false;\n\n if (observation.valueQuantity?.value !== undefined) {\n value = observation.valueQuantity.value;\n unit = observation.valueQuantity.unit || observation.valueQuantity.code || '';\n } else if (observation.valueString) {\n value = observation.valueString;\n isQualitative = true;\n } else {\n return {\n skipped: {\n index,\n loincCode,\n reason: 'Observation has no value (valueQuantity or valueString)',\n resourceType: 'Observation',\n },\n };\n }\n\n // Extract collection date (effectiveDateTime or effectivePeriod.start)\n const collectionDate = observation.effectiveDateTime || observation.effectivePeriod?.start || '';\n if (!collectionDate) {\n return {\n skipped: {\n index,\n loincCode,\n reason: 'Observation has no effectiveDateTime or effectivePeriod.start',\n resourceType: 'Observation',\n },\n };\n }\n\n // Extract reference ranges\n let referenceMin: number | undefined;\n let referenceMax: number | undefined;\n if (observation.referenceRange?.[0]) {\n referenceMin = observation.referenceRange[0].low?.value;\n referenceMax = observation.referenceRange[0].high?.value;\n }\n\n const imported: ImportedObservation = {\n biomarkerCode: internalCode,\n biomarkerName:\n definition?.names.pt[0] || definition?.names.en[0] || observation.code.text || internalCode,\n collectionDate,\n flag: extractFlag(observation),\n isQualitative,\n loincCode,\n referenceMax,\n referenceMin,\n unit: unit || definition?.unit || '',\n value,\n };\n\n return { observation: imported };\n}\n\n/**\n * Process a complete FHIR Bundle for import\n */\nexport function processImportBundle(data: unknown): FHIRImportResult {\n // Structural validation\n const validationErrors = validateFHIRImportBundle(data);\n if (validationErrors.length > 0) {\n return {\n errors: validationErrors,\n imported: [],\n skipped: [],\n totalProcessed: 0,\n };\n }\n\n const bundle = data as FHIRBundle;\n\n // Extract observations\n const { observations, skipped } = extractObservationsFromBundle(bundle);\n\n // Map each observation to internal format\n const imported: ImportedObservation[] = [];\n const allSkipped: SkippedEntry[] = [...skipped];\n\n for (let i = 0; i < observations.length; i++) {\n const result = mapFHIRObservationToInternal(observations[i]!, i);\n\n if ('observation' in result) {\n imported.push(result.observation);\n } else {\n allSkipped.push(result.skipped);\n }\n }\n\n return {\n errors: [],\n imported,\n skipped: allSkipped,\n totalProcessed: observations.length,\n };\n}\n\nexport { MAX_FILE_SIZE, MAX_OBSERVATIONS };\n"]}