@precisa-saude/fhir 0.32.0 → 0.34.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.
- package/README.md +11 -9
- package/dist/biomarkers.cjs +2 -2
- package/dist/biomarkers.js +1 -1
- package/dist/{chunk-44QMNDOI.cjs → chunk-376KM7IL.cjs} +18 -11
- package/dist/chunk-376KM7IL.cjs.map +1 -0
- package/dist/{chunk-WDDW2WCY.js → chunk-4FKZG5GZ.js} +116 -25
- package/dist/chunk-4FKZG5GZ.js.map +1 -0
- package/dist/{chunk-AZTZYOAV.cjs → chunk-5RC7C7HJ.cjs} +199 -57
- package/dist/chunk-5RC7C7HJ.cjs.map +1 -0
- package/dist/{chunk-N3ZCOLG2.js → chunk-E6MXDQXW.js} +19 -1
- package/dist/chunk-E6MXDQXW.js.map +1 -0
- package/dist/{chunk-MNUQ57JR.js → chunk-K3VZ3F5Z.js} +21 -21
- package/dist/chunk-K3VZ3F5Z.js.map +1 -0
- package/dist/{chunk-4Y43MQQK.js → chunk-NJM45WAH.js} +10 -3
- package/dist/chunk-NJM45WAH.js.map +1 -0
- package/dist/{chunk-OTVCOSCK.cjs → chunk-NKDUVSDK.cjs} +21 -21
- package/dist/chunk-NKDUVSDK.cjs.map +1 -0
- package/dist/{chunk-3ILBFLVQ.cjs → chunk-OAFAERDY.cjs} +20 -2
- package/dist/chunk-OAFAERDY.cjs.map +1 -0
- package/dist/{chunk-PLR54334.js → chunk-P4G534AQ.js} +445 -61
- package/dist/chunk-P4G534AQ.js.map +1 -0
- package/dist/{chunk-3XIMPALK.js → chunk-Q3H5C6UR.js} +198 -56
- package/dist/chunk-Q3H5C6UR.js.map +1 -0
- package/dist/{chunk-MKH4Q735.cjs → chunk-T75NZM56.cjs} +116 -25
- package/dist/chunk-T75NZM56.cjs.map +1 -0
- package/dist/{chunk-555WKD6J.cjs → chunk-VKLWTTUO.cjs} +447 -63
- package/dist/chunk-VKLWTTUO.cjs.map +1 -0
- package/dist/cli.js +1547 -933
- package/dist/{converter-D1Q84Oc9.d.ts → converter-DP8VkkO3.d.cts} +9 -1
- package/dist/{converter-DZH9x52r.d.cts → converter-UygMzWlL.d.ts} +9 -1
- package/dist/converter.cjs +5 -4
- package/dist/converter.cjs.map +1 -1
- package/dist/converter.d.cts +3 -2
- package/dist/converter.d.ts +3 -2
- package/dist/converter.js +4 -3
- package/dist/{fhir-types-B1KQmlRb.d.ts → fhir-types-Cn5WFbOI.d.cts} +5 -0
- package/dist/{fhir-types-B1KQmlRb.d.cts → fhir-types-Cn5WFbOI.d.ts} +5 -0
- package/dist/importer.cjs +5 -4
- package/dist/importer.cjs.map +1 -1
- package/dist/importer.d.cts +3 -1
- package/dist/importer.d.ts +3 -1
- package/dist/importer.js +4 -3
- package/dist/index.cjs +19 -11
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +6 -6
- package/dist/index.d.ts +6 -6
- package/dist/index.js +34 -26
- package/dist/index.js.map +1 -1
- package/dist/reference-ranges.cjs +8 -3
- package/dist/reference-ranges.cjs.map +1 -1
- package/dist/reference-ranges.d.cts +83 -1
- package/dist/reference-ranges.d.ts +83 -1
- package/dist/reference-ranges.js +9 -4
- package/dist/units.cjs +7 -2
- package/dist/units.cjs.map +1 -1
- package/dist/units.d.cts +53 -5
- package/dist/units.d.ts +53 -5
- package/dist/units.js +6 -1
- package/dist/validators.cjs +4 -2
- package/dist/validators.cjs.map +1 -1
- package/dist/validators.d.cts +1 -1
- package/dist/validators.d.ts +1 -1
- package/dist/validators.js +3 -1
- package/package.json +1 -1
- package/dist/chunk-3ILBFLVQ.cjs.map +0 -1
- package/dist/chunk-3XIMPALK.js.map +0 -1
- package/dist/chunk-44QMNDOI.cjs.map +0 -1
- package/dist/chunk-4Y43MQQK.js.map +0 -1
- package/dist/chunk-555WKD6J.cjs.map +0 -1
- package/dist/chunk-AZTZYOAV.cjs.map +0 -1
- package/dist/chunk-MKH4Q735.cjs.map +0 -1
- package/dist/chunk-MNUQ57JR.js.map +0 -1
- package/dist/chunk-N3ZCOLG2.js.map +0 -1
- package/dist/chunk-OTVCOSCK.cjs.map +0 -1
- package/dist/chunk-PLR54334.js.map +0 -1
- package/dist/chunk-WDDW2WCY.js.map +0 -1
package/README.md
CHANGED
|
@@ -82,15 +82,15 @@ import { validateFHIRObservation } from '@precisa-saude/fhir/validators';
|
|
|
82
82
|
|
|
83
83
|
## Módulos
|
|
84
84
|
|
|
85
|
-
| Sub-path | Descrição
|
|
86
|
-
| ------------------- |
|
|
87
|
-
| `/biomarkers` | Definições com códigos LOINC, nomes pt/en, sub-categorias
|
|
88
|
-
| `/category-groups` | Agrupamento de 10 categorias clínicas top-level sobre 20 subcategorias
|
|
89
|
-
| `/reference-ranges` | Faixas de referência por sexo/idade/gestação (SBPC/ML, SBC, SBD, OMS)
|
|
90
|
-
| `/converter` | Converte dados laboratoriais para FHIR R4 Bundle
|
|
91
|
-
| `/importer` | Importa FHIR Bundle de volta para estruturas internas
|
|
92
|
-
| `/units` | Mapeamento de unidades, conversão para UCUM
|
|
93
|
-
| `/validators` | Validação de recursos FHIR (DiagnosticReport, Observation, Bundle)
|
|
85
|
+
| Sub-path | Descrição |
|
|
86
|
+
| ------------------- | ------------------------------------------------------------------------- |
|
|
87
|
+
| `/biomarkers` | Definições com códigos LOINC, nomes pt/en, sub-categorias |
|
|
88
|
+
| `/category-groups` | Agrupamento de 10 categorias clínicas top-level sobre 20 subcategorias |
|
|
89
|
+
| `/reference-ranges` | Faixas de referência por sexo/idade/gestação (SBPC/ML, SBC, SBD, OMS) |
|
|
90
|
+
| `/converter` | Converte dados laboratoriais para FHIR R4 Bundle |
|
|
91
|
+
| `/importer` | Importa FHIR Bundle de volta para estruturas internas |
|
|
92
|
+
| `/units` | Mapeamento de unidades, conversão para UCUM (`resolveUcum`, `isUcumCode`) |
|
|
93
|
+
| `/validators` | Validação de recursos FHIR (DiagnosticReport, Observation, Bundle) |
|
|
94
94
|
|
|
95
95
|
## Escopo das faixas de referência
|
|
96
96
|
|
|
@@ -107,6 +107,8 @@ const range = getReferenceRange('TSH', {
|
|
|
107
107
|
// → { max: 2.5, min: 0.1, ... } (alvo ATA 2017 para 1º trimestre)
|
|
108
108
|
```
|
|
109
109
|
|
|
110
|
+
Cada faixa diz que tipo de afirmação ela é (`kind`: intervalo de referência do ensaio, limiar de decisão de diretriz ou distribuição populacional) e, por limite, se ele é corte clínico ou só desenho (`minKind`/`maxKind`). Para sinalizar um valor contra a faixa do catálogo, use `flagAgainstCatalogRange`, que ignora os limites de desenho; o `direction` diz para que lado o marcador melhora e não decide flag. Detalhes em [docs/biomarcadores.md](../../docs/biomarcadores.md#tipo-da-faixa).
|
|
111
|
+
|
|
110
112
|
O metadado opcional `fastingRequired` em `BiomarkerReferenceRange` indica se a amostra exige jejum estrito (ex.: `Glucose`, `Insulin`, `HOMA_IR`) ou se o jejum é preferido mas não obrigatório (ex.: `Triglycerides`, que aceita dosagem não-jejum por SBC 2017/2025).
|
|
111
113
|
|
|
112
114
|
## Aviso médico
|
package/dist/biomarkers.cjs
CHANGED
|
@@ -30,7 +30,7 @@
|
|
|
30
30
|
|
|
31
31
|
|
|
32
32
|
|
|
33
|
-
var
|
|
33
|
+
var _chunkT75NZM56cjs = require('./chunk-T75NZM56.cjs');
|
|
34
34
|
|
|
35
35
|
|
|
36
36
|
|
|
@@ -63,5 +63,5 @@ var _chunkMKH4Q735cjs = require('./chunk-MKH4Q735.cjs');
|
|
|
63
63
|
|
|
64
64
|
|
|
65
65
|
|
|
66
|
-
exports.BIOMARKER_DEFINITIONS =
|
|
66
|
+
exports.BIOMARKER_DEFINITIONS = _chunkT75NZM56cjs.BIOMARKER_DEFINITIONS; exports.CAC_INDICATOR_CODES = _chunkT75NZM56cjs.CAC_INDICATOR_CODES; exports.DEXA_CATEGORIES = _chunkT75NZM56cjs.DEXA_CATEGORIES; exports.DEXA_INDICATOR_CODES = _chunkT75NZM56cjs.DEXA_INDICATOR_CODES; exports.codeToLoinc = _chunkT75NZM56cjs.codeToLoinc; exports.filterVisibleBiomarkers = _chunkT75NZM56cjs.filterVisibleBiomarkers; exports.findCodeByName = _chunkT75NZM56cjs.findCodeByName; exports.generateCacFullReference = _chunkT75NZM56cjs.generateCacFullReference; exports.generateDexaFullReference = _chunkT75NZM56cjs.generateDexaFullReference; exports.generateFilteredLLMReference = _chunkT75NZM56cjs.generateFilteredLLMReference; exports.generateLLMReference = _chunkT75NZM56cjs.generateLLMReference; exports.getAllCodes = _chunkT75NZM56cjs.getAllCodes; exports.getAllDefinitions = _chunkT75NZM56cjs.getAllDefinitions; exports.getAllLoincCodes = _chunkT75NZM56cjs.getAllLoincCodes; exports.getAllSearchPatterns = _chunkT75NZM56cjs.getAllSearchPatterns; exports.getBiomarkersByCategory = _chunkT75NZM56cjs.getBiomarkersByCategory; exports.getBiomarkersForCategories = _chunkT75NZM56cjs.getBiomarkersForCategories; exports.getDefinitionByCode = _chunkT75NZM56cjs.getDefinitionByCode; exports.getDefinitionByLoinc = _chunkT75NZM56cjs.getDefinitionByLoinc; exports.getDefinitionsBySex = _chunkT75NZM56cjs.getDefinitionsBySex; exports.getSexForCode = _chunkT75NZM56cjs.getSexForCode; exports.getVisibleDefinitions = _chunkT75NZM56cjs.getVisibleDefinitions; exports.isBiomarkerVisible = _chunkT75NZM56cjs.isBiomarkerVisible; exports.isCacDocument = _chunkT75NZM56cjs.isCacDocument; exports.isDexaDocument = _chunkT75NZM56cjs.isDexaDocument; exports.isValidCode = _chunkT75NZM56cjs.isValidCode; exports.isValidLoinc = _chunkT75NZM56cjs.isValidLoinc; exports.loincToCode = _chunkT75NZM56cjs.loincToCode; exports.normalizeCode = _chunkT75NZM56cjs.normalizeCode; exports.toBiomarkerTests = _chunkT75NZM56cjs.toBiomarkerTests; exports.validateLoincNameMatch = _chunkT75NZM56cjs.validateLoincNameMatch;
|
|
67
67
|
//# sourceMappingURL=biomarkers.cjs.map
|
package/dist/biomarkers.js
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
"use strict";Object.defineProperty(exports, "__esModule", {value: true}); function _nullishCoalesce(lhs, rhsFn) { if (lhs != null) { return lhs; } else { return rhsFn(); } } function _optionalChain(ops) { let lastAccessLHS = undefined; let value = ops[0]; let i = 1; while (i < ops.length) { const op = ops[i]; const fn = ops[i + 1]; i += 2; if ((op === 'optionalAccess' || op === 'optionalCall') && value == null) { return undefined; } if (op === 'access' || op === 'optionalAccess') { lastAccessLHS = value; value = fn(value); } else if (op === 'call' || op === 'optionalCall') { value = fn((...args) => value.call(lastAccessLHS, ...args)); lastAccessLHS = undefined; } } return value; }
|
|
2
2
|
|
|
3
|
-
var
|
|
3
|
+
var _chunkOAFAERDYcjs = require('./chunk-OAFAERDY.cjs');
|
|
4
4
|
|
|
5
5
|
|
|
6
6
|
|
|
@@ -11,7 +11,7 @@ var _chunkOR67NJDZcjs = require('./chunk-OR67NJDZ.cjs');
|
|
|
11
11
|
|
|
12
12
|
|
|
13
13
|
|
|
14
|
-
var
|
|
14
|
+
var _chunkT75NZM56cjs = require('./chunk-T75NZM56.cjs');
|
|
15
15
|
|
|
16
16
|
// src/importer.ts
|
|
17
17
|
var MAX_OBSERVATIONS = 5e3;
|
|
@@ -33,11 +33,11 @@ function resolveBiomarkerCode(observation) {
|
|
|
33
33
|
} else {
|
|
34
34
|
reason = "No code found in observation coding";
|
|
35
35
|
}
|
|
36
|
-
const fromLoinc = loincCode ?
|
|
36
|
+
const fromLoinc = loincCode ? _chunkT75NZM56cjs.loincToCode.call(void 0, loincCode) : void 0;
|
|
37
37
|
if (fromLoinc) return { internalCode: fromLoinc, loincCode, reason };
|
|
38
|
-
if (declaredCode &&
|
|
39
|
-
const canonical =
|
|
40
|
-
return { internalCode: canonical, loincCode:
|
|
38
|
+
if (declaredCode && _chunkT75NZM56cjs.isValidCode.call(void 0, declaredCode)) {
|
|
39
|
+
const canonical = _chunkT75NZM56cjs.normalizeCode.call(void 0, declaredCode);
|
|
40
|
+
return { internalCode: canonical, loincCode: _chunkT75NZM56cjs.codeToLoinc.call(void 0, canonical), reason };
|
|
41
41
|
}
|
|
42
42
|
return { loincCode, reason };
|
|
43
43
|
}
|
|
@@ -74,7 +74,7 @@ function mapFHIRObservationToInternal(observation, index) {
|
|
|
74
74
|
skipped: { index, loincCode, reason, resourceType: "Observation" }
|
|
75
75
|
};
|
|
76
76
|
}
|
|
77
|
-
const definition =
|
|
77
|
+
const definition = _chunkT75NZM56cjs.getDefinitionByCode.call(void 0, internalCode);
|
|
78
78
|
let value;
|
|
79
79
|
let unit = "";
|
|
80
80
|
let isQualitative = false;
|
|
@@ -107,26 +107,33 @@ function mapFHIRObservationToInternal(observation, index) {
|
|
|
107
107
|
}
|
|
108
108
|
let referenceMin;
|
|
109
109
|
let referenceMax;
|
|
110
|
+
let referenceKind;
|
|
110
111
|
if (_optionalChain([observation, 'access', _18 => _18.referenceRange, 'optionalAccess', _19 => _19[0]])) {
|
|
111
112
|
referenceMin = _optionalChain([observation, 'access', _20 => _20.referenceRange, 'access', _21 => _21[0], 'access', _22 => _22.low, 'optionalAccess', _23 => _23.value]);
|
|
112
113
|
referenceMax = _optionalChain([observation, 'access', _24 => _24.referenceRange, 'access', _25 => _25[0], 'access', _26 => _26.high, 'optionalAccess', _27 => _27.value]);
|
|
114
|
+
const meaning = _optionalChain([observation, 'access', _28 => _28.referenceRange, 'access', _29 => _29[0], 'access', _30 => _30.type, 'optionalAccess', _31 => _31.coding, 'optionalAccess', _32 => _32.find, 'call', _33 => _33(
|
|
115
|
+
(c) => c.system === "http://terminology.hl7.org/CodeSystem/referencerange-meaning"
|
|
116
|
+
), 'optionalAccess', _34 => _34.code]);
|
|
117
|
+
if (meaning === "normal") referenceKind = "reference-interval";
|
|
118
|
+
else if (meaning === "recommended") referenceKind = "decision-threshold";
|
|
113
119
|
}
|
|
114
120
|
const imported = {
|
|
115
121
|
biomarkerCode: internalCode,
|
|
116
|
-
biomarkerName: _optionalChain([definition, 'optionalAccess',
|
|
122
|
+
biomarkerName: _optionalChain([definition, 'optionalAccess', _35 => _35.names, 'access', _36 => _36.pt, 'access', _37 => _37[0]]) || _optionalChain([definition, 'optionalAccess', _38 => _38.names, 'access', _39 => _39.en, 'access', _40 => _40[0]]) || observation.code.text || internalCode,
|
|
117
123
|
collectionDate,
|
|
118
124
|
flag: extractFlag(observation),
|
|
119
125
|
isQualitative,
|
|
120
126
|
loincCode,
|
|
127
|
+
...referenceKind && { referenceKind },
|
|
121
128
|
referenceMax,
|
|
122
129
|
referenceMin,
|
|
123
|
-
unit: unit || _optionalChain([definition, 'optionalAccess',
|
|
130
|
+
unit: unit || _optionalChain([definition, 'optionalAccess', _41 => _41.unit]) || "",
|
|
124
131
|
value
|
|
125
132
|
};
|
|
126
133
|
return { observation: imported };
|
|
127
134
|
}
|
|
128
135
|
function processImportBundle(data) {
|
|
129
|
-
const validationErrors =
|
|
136
|
+
const validationErrors = _chunkOAFAERDYcjs.validateFHIRImportBundle.call(void 0, data);
|
|
130
137
|
if (validationErrors.length > 0) {
|
|
131
138
|
return {
|
|
132
139
|
errors: validationErrors,
|
|
@@ -162,4 +169,4 @@ function processImportBundle(data) {
|
|
|
162
169
|
|
|
163
170
|
|
|
164
171
|
exports.MAX_OBSERVATIONS = MAX_OBSERVATIONS; exports.MAX_FILE_SIZE = MAX_FILE_SIZE; exports.extractObservationsFromBundle = extractObservationsFromBundle; exports.mapFHIRObservationToInternal = mapFHIRObservationToInternal; exports.processImportBundle = processImportBundle;
|
|
165
|
-
//# sourceMappingURL=chunk-
|
|
172
|
+
//# sourceMappingURL=chunk-376KM7IL.cjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["/home/runner/work/fhir-brasil/fhir-brasil/packages/core/dist/chunk-376KM7IL.cjs","../src/importer.ts"],"names":[],"mappings":"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","file":"/home/runner/work/fhir-brasil/fhir-brasil/packages/core/dist/chunk-376KM7IL.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 {\n codeToLoinc,\n getDefinitionByCode,\n isValidCode,\n loincToCode,\n normalizeCode,\n} from './biomarkers';\nimport { BIOMARKER_CODE_SYSTEM, LOINC_SYSTEM } from './code-systems';\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 /** Ausente nos biomarcadores sem LOINC publicado, como composição corporal. */\n loincCode?: string;\n /** Lido do `referenceRange.type`, quando o Bundle o traz. */\n referenceKind?: 'decision-threshold' | 'reference-interval';\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 * Resolve o código interno do biomarcador a partir do `code.coding`.\n *\n * LOINC primeiro, que é o vocabulário que arquivos de terceiros usam. Quando\n * não resolve, cai para o coding de códigos internos, presente nos arquivos\n * exportados pela própria plataforma.\n *\n * O fallback cobre dois casos: biomarcadores sem LOINC publicado (composição\n * corporal, densidade óssea, escore de cálcio) e arquivos antigos, exportados\n * quando esses biomarcadores saíam com o placeholder `99999-9`, que não\n * resolve para nada.\n */\nfunction resolveBiomarkerCode(observation: FHIRObservation): {\n internalCode?: string;\n loincCode?: string;\n reason: string;\n} {\n const coding = observation.code?.coding ?? [];\n const loincCode = coding.find((c) => c.system === LOINC_SYSTEM)?.code;\n const declaredCode = coding.find((c) => c.system === BIOMARKER_CODE_SYSTEM)?.code;\n\n const seenCodes = [\n ...(loincCode ? [`LOINC ${loincCode}`] : []),\n ...(declaredCode ? [`biomarker code ${declaredCode}`] : []),\n ];\n\n // Três motivos distintos de descarte, que antes se confundiam num só. Sem\n // essa separação, um arquivo em SNOMED relatava \"nenhum código encontrado\",\n // sugerindo `coding` vazio quando na verdade o código existia e estava num\n // system que não tratamos. Para importação de terceiros, é a diferença entre\n // um diagnóstico acionável e um enigma.\n let reason: string;\n if (seenCodes.length > 0) {\n reason = `Unknown code: ${seenCodes.join(', ')}`;\n } else if (coding.length > 0) {\n const systems = [...new Set(coding.map((c) => c.system ?? '(sem system)'))];\n reason = `No code in a supported system (found: ${systems.join(', ')})`;\n } else {\n reason = 'No code found in observation coding';\n }\n\n const fromLoinc = loincCode ? loincToCode(loincCode) : undefined;\n if (fromLoinc) return { internalCode: fromLoinc, loincCode, reason };\n\n if (declaredCode && isValidCode(declaredCode)) {\n // `isValidCode` aceita alias, mas alias não serve como código armazenado:\n // 49 definições têm um, e tanto `codeToLoinc` quanto as faixas de\n // referência são indexadas só pelo canônico. Sem normalizar, `VLDL_Cholesterol`\n // entraria no lugar de `VLDL` e perderia o LOINC 13458-5 que ele tem.\n // Importar um Bundle é fronteira de dados, que é onde `normalizeCode` deve\n // ser aplicado.\n const canonical = normalizeCode(declaredCode);\n\n // `codeToLoinc` devolve undefined para quem não tem LOINC, que é o caso\n // esperado aqui. O campo fica de fora em vez de receber um valor inventado.\n return { internalCode: canonical, loincCode: codeToLoinc(canonical), reason };\n }\n\n return { loincCode, reason };\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 { internalCode, loincCode, reason } = resolveBiomarkerCode(observation);\n\n if (!internalCode) {\n return {\n skipped: { index, loincCode, reason, resourceType: 'Observation' },\n };\n }\n\n const definition = getDefinitionByCode(internalCode);\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 let referenceKind: ImportedObservation['referenceKind'];\n if (observation.referenceRange?.[0]) {\n referenceMin = observation.referenceRange[0].low?.value;\n referenceMax = observation.referenceRange[0].high?.value;\n const meaning = observation.referenceRange[0].type?.coding?.find(\n (c) => c.system === 'http://terminology.hl7.org/CodeSystem/referencerange-meaning',\n )?.code;\n if (meaning === 'normal') referenceKind = 'reference-interval';\n else if (meaning === 'recommended') referenceKind = 'decision-threshold';\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 ...(referenceKind && { referenceKind }),\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"]}
|
|
@@ -56,6 +56,10 @@ var BIOMARKER_DEFINITIONS = [
|
|
|
56
56
|
{
|
|
57
57
|
category: "coracao",
|
|
58
58
|
code: "LDL_Medium",
|
|
59
|
+
// 96735-6 é "in Serum" só, enquanto as vizinhas LDL_Small (43727-7),
|
|
60
|
+
// LDL_ParticleNumber (54434-6) e HDL_Large (43729-3) são Ser/Plas. É o
|
|
61
|
+
// único código para a subfração média, e o perfil por RMN roda em soro.
|
|
62
|
+
// Material registrado de propósito.
|
|
59
63
|
loinc: "96735-6",
|
|
60
64
|
names: {
|
|
61
65
|
en: ["LDL Medium", "Medium LDL Particles"],
|
|
@@ -1023,14 +1027,16 @@ var BIOMARKER_DEFINITIONS = [
|
|
|
1023
1027
|
},
|
|
1024
1028
|
{
|
|
1025
1029
|
// LOINC 99620-7 = "Omega 3 fatty acids (w3) [Moles/volume] in RBC.lysate".
|
|
1026
|
-
//
|
|
1027
|
-
//
|
|
1028
|
-
//
|
|
1029
|
-
//
|
|
1030
|
-
//
|
|
1031
|
-
//
|
|
1032
|
-
//
|
|
1033
|
-
//
|
|
1030
|
+
// Anteriormente 35178-3 (mesmo analito em Ser/Plas), incompatível com o
|
|
1031
|
+
// uso clínico do Índice Ômega-3 (Harris & von Schacky 2004), que é
|
|
1032
|
+
// definido em membranas de hemácias.
|
|
1033
|
+
//
|
|
1034
|
+
// Compromisso declarado, e não erro: o LOINC 2.82 não tem código de fração
|
|
1035
|
+
// ("ômega-3 total / ácidos graxos totais") para o total, só para os ácidos
|
|
1036
|
+
// individuais e para EPA+DPA+DHA (90911-9). O componente confere; a
|
|
1037
|
+
// propriedade é moles/volume enquanto o laudo imprime %. O teste de eixos
|
|
1038
|
+
// (`loinc-axes.test.ts`) lista esta entrada como exceção com este motivo.
|
|
1039
|
+
// Mesmo compromisso em `Omega6_Total` (99621-5).
|
|
1034
1040
|
category: "nutrientes",
|
|
1035
1041
|
code: "Omega3_Total",
|
|
1036
1042
|
loinc: "99620-7",
|
|
@@ -1044,7 +1050,18 @@ var BIOMARKER_DEFINITIONS = [
|
|
|
1044
1050
|
category: "nutrientes",
|
|
1045
1051
|
code: "Omega3_DHA",
|
|
1046
1052
|
codeAliases: ["DHA"],
|
|
1047
|
-
|
|
1053
|
+
// Ácidos graxos individuais: fração do total (% dos ácidos graxos C14-C22),
|
|
1054
|
+
// que é o que o perfil de ácidos graxos e o Índice Ômega-3 imprimem. Os
|
|
1055
|
+
// códigos vêm do painel 90918-4 ("Fatty acid omega-3 and omega-6 panel -
|
|
1056
|
+
// Blood"), o mesmo de onde já saem as razões AA/EPA (90909-3) e ω6/ω3
|
|
1057
|
+
// (90910-1). Até out/2026 apontavam para os códigos [Entitic substance]
|
|
1058
|
+
// em hemácias (75095-0, 75097-6, 75110-7, 75117-2), que são quantidade por
|
|
1059
|
+
// célula, e para 48371-9, que é moles/volume em soro: componente certo,
|
|
1060
|
+
// propriedade errada nos cinco, desde mar/2026. Ficam como alias porque o
|
|
1061
|
+
// analito é o mesmo. Material: o painel em soro/plasma (88884-2, C14-C24)
|
|
1062
|
+
// existe, e é a troca a fazer se um laboratório imprimir o perfil em soro.
|
|
1063
|
+
loinc: "90914-3",
|
|
1064
|
+
loincAliases: ["75095-0"],
|
|
1048
1065
|
names: {
|
|
1049
1066
|
en: ["Omega-3 DHA", "DHA", "Docosahexaenoic Acid"],
|
|
1050
1067
|
pt: ["\xD4mega-3: DHA", "DHA", "\xC1cido Docosahexaenoico"]
|
|
@@ -1055,7 +1072,9 @@ var BIOMARKER_DEFINITIONS = [
|
|
|
1055
1072
|
category: "nutrientes",
|
|
1056
1073
|
code: "Omega3_DPA",
|
|
1057
1074
|
codeAliases: ["DPA"],
|
|
1058
|
-
|
|
1075
|
+
// Fração em sangue, painel 90918-4. Ver `Omega3_DHA`.
|
|
1076
|
+
loinc: "90913-5",
|
|
1077
|
+
loincAliases: ["48371-9"],
|
|
1059
1078
|
names: {
|
|
1060
1079
|
en: ["Omega-3 DPA", "DPA", "Docosapentaenoic Acid"],
|
|
1061
1080
|
pt: ["\xD4mega-3: DPA", "DPA", "\xC1cido Docosapentaenoico"]
|
|
@@ -1066,7 +1085,9 @@ var BIOMARKER_DEFINITIONS = [
|
|
|
1066
1085
|
category: "nutrientes",
|
|
1067
1086
|
code: "Omega3_EPA",
|
|
1068
1087
|
codeAliases: ["EPA"],
|
|
1069
|
-
|
|
1088
|
+
// Fração em sangue, painel 90918-4. Ver `Omega3_DHA`.
|
|
1089
|
+
loinc: "90912-7",
|
|
1090
|
+
loincAliases: ["75097-6"],
|
|
1070
1091
|
names: {
|
|
1071
1092
|
en: ["Omega-3 EPA", "EPA", "Eicosapentaenoic Acid"],
|
|
1072
1093
|
pt: ["\xD4mega-3: EPA", "EPA", "\xC1cido Eicosapentaenoico"]
|
|
@@ -1076,7 +1097,12 @@ var BIOMARKER_DEFINITIONS = [
|
|
|
1076
1097
|
{
|
|
1077
1098
|
category: "nutrientes",
|
|
1078
1099
|
code: "EPADPADHA",
|
|
1079
|
-
|
|
1100
|
+
// 90911-9 é a fração EPA+DPA+DHA / ácidos graxos C14-C22 em sangue, o
|
|
1101
|
+
// valor em %. Até out/2026 apontava para 90908-5, que é a *interpretação*
|
|
1102
|
+
// desse mesmo valor (ordinal: risco alto, moderado, baixo), e não o
|
|
1103
|
+
// número. Sem alias: código ordinal carregando valor numérico é o erro
|
|
1104
|
+
// que se quer parar de aceitar.
|
|
1105
|
+
loinc: "90911-9",
|
|
1080
1106
|
names: {
|
|
1081
1107
|
en: ["Omega-3 EPA+DPA+DHA", "EPA+DPA+DHA"],
|
|
1082
1108
|
pt: ["\xD4mega-3: EPA+DPA+DHA"]
|
|
@@ -1097,7 +1123,12 @@ var BIOMARKER_DEFINITIONS = [
|
|
|
1097
1123
|
{
|
|
1098
1124
|
category: "nutrientes",
|
|
1099
1125
|
code: "Omega6_Total",
|
|
1100
|
-
|
|
1126
|
+
// 99621-5 é "Omega 6 fatty acids (w6) [Moles/volume] in RBC.lysate", o
|
|
1127
|
+
// par exato do 99620-7 de `Omega3_Total`, com o mesmo compromisso de
|
|
1128
|
+
// propriedade documentado lá. Até out/2026 apontava para 35177-5, que é
|
|
1129
|
+
// ácidos graxos poli-insaturados totais em soro: ômega-3 e ômega-6
|
|
1130
|
+
// somados, outro componente. Sem alias.
|
|
1131
|
+
loinc: "99621-5",
|
|
1101
1132
|
names: {
|
|
1102
1133
|
en: ["Omega-6 Total", "Total Omega-6"],
|
|
1103
1134
|
pt: ["\xD4mega-6 Total"]
|
|
@@ -1108,7 +1139,9 @@ var BIOMARKER_DEFINITIONS = [
|
|
|
1108
1139
|
category: "nutrientes",
|
|
1109
1140
|
code: "Omega6_AA",
|
|
1110
1141
|
codeAliases: ["Arachidonic_Acid"],
|
|
1111
|
-
|
|
1142
|
+
// Fração em sangue, painel 90918-4. Ver `Omega3_DHA`.
|
|
1143
|
+
loinc: "90916-8",
|
|
1144
|
+
loincAliases: ["75110-7"],
|
|
1112
1145
|
names: {
|
|
1113
1146
|
en: ["Omega-6 Arachidonic Acid", "Arachidonic Acid", "AA"],
|
|
1114
1147
|
pt: ["\xD4mega-6: \xC1cido Araquid\xF4nico", "\xC1cido Araquid\xF4nico", "AA"]
|
|
@@ -1119,7 +1152,9 @@ var BIOMARKER_DEFINITIONS = [
|
|
|
1119
1152
|
category: "nutrientes",
|
|
1120
1153
|
code: "Omega6_LA",
|
|
1121
1154
|
codeAliases: ["Linoleic_Acid"],
|
|
1122
|
-
|
|
1155
|
+
// Fração em sangue, painel 90918-4. Ver `Omega3_DHA`.
|
|
1156
|
+
loinc: "90917-6",
|
|
1157
|
+
loincAliases: ["75117-2"],
|
|
1123
1158
|
names: {
|
|
1124
1159
|
en: ["Omega-6 Linoleic Acid", "Linoleic Acid", "LA"],
|
|
1125
1160
|
pt: ["\xD4mega-6: \xC1cido Linoleico", "\xC1cido Linoleico", "LA"]
|
|
@@ -1200,7 +1235,11 @@ var BIOMARKER_DEFINITIONS = [
|
|
|
1200
1235
|
{
|
|
1201
1236
|
category: "nutrientes",
|
|
1202
1237
|
code: "Zinc",
|
|
1203
|
-
|
|
1238
|
+
// 5763-8 é "Zinc [Mass/volume] in Serum or Plasma", o zinco sérico da
|
|
1239
|
+
// rotina brasileira (o nome em inglês já dizia "Serum Zinc"). Até out/2026
|
|
1240
|
+
// apontava para 8245-3, o mesmo analito em sangue total, que tem faixa de
|
|
1241
|
+
// referência própria. Sem alias: sangue total é outro material.
|
|
1242
|
+
loinc: "5763-8",
|
|
1204
1243
|
names: {
|
|
1205
1244
|
en: ["Zinc", "Serum Zinc"],
|
|
1206
1245
|
pt: ["Zinco"]
|
|
@@ -1301,6 +1340,9 @@ var BIOMARKER_DEFINITIONS = [
|
|
|
1301
1340
|
{
|
|
1302
1341
|
category: "figado",
|
|
1303
1342
|
code: "Globulin",
|
|
1343
|
+
// 2336-6 é "Globulin [Mass/volume] in Serum", soro só: o LOINC 2.82 não
|
|
1344
|
+
// tem a versão Ser/Plas da globulina total (as frações alfa, beta e gama
|
|
1345
|
+
// têm). Material registrado de propósito.
|
|
1304
1346
|
loinc: "2336-6",
|
|
1305
1347
|
names: {
|
|
1306
1348
|
en: ["Globulin", "Serum Globulin"],
|
|
@@ -1580,6 +1622,13 @@ var BIOMARKER_DEFINITIONS = [
|
|
|
1580
1622
|
{
|
|
1581
1623
|
category: "rins",
|
|
1582
1624
|
code: "BUN_Creatinine_Ratio",
|
|
1625
|
+
// 3097-3 é "Urea nitrogen/Creatinine [Mass Ratio]", a razão BUN/creatinina,
|
|
1626
|
+
// e a faixa de referência (10-20, Tietz) é a dessa convenção. O laudo
|
|
1627
|
+
// brasileiro imprime "Relação Ureia/Creatinina", cuja faixa é outra (cerca
|
|
1628
|
+
// de 21-43) e cujo código é 56997-0 ("Urea/Creatinine [Mass Ratio] in
|
|
1629
|
+
// Serum or Plasma"). Trocar só o código deixaria a faixa errada do outro
|
|
1630
|
+
// lado; a separação em duas grandezas, como em `Glucose_Fasting`, é
|
|
1631
|
+
// decisão à parte, registrada em `reference-ranges.ts`.
|
|
1583
1632
|
loinc: "3097-3",
|
|
1584
1633
|
names: {
|
|
1585
1634
|
en: ["BUN/Creatinine Ratio", "Urea/Creatinine Ratio"],
|
|
@@ -1747,7 +1796,12 @@ var BIOMARKER_DEFINITIONS = [
|
|
|
1747
1796
|
category: "urina",
|
|
1748
1797
|
code: "Bacteria_Urine",
|
|
1749
1798
|
codeAliases: ["UrineBacteria"],
|
|
1750
|
-
|
|
1799
|
+
// 5769-5 é "Bacteria [#/area] in Urine sediment by Microscopy high power
|
|
1800
|
+
// field", a contagem do sedimento que a unidade /HPF declara. Até out/2026
|
|
1801
|
+
// apontava para 630-4, "Bacteria identified in Urine by Culture": outro
|
|
1802
|
+
// exame, nominal, que identifica a espécie em cultura. Sem alias:
|
|
1803
|
+
// urocultura não é sedimento.
|
|
1804
|
+
loinc: "5769-5",
|
|
1751
1805
|
names: {
|
|
1752
1806
|
en: ["Urine Bacteria", "Bacteria Urine", "Bacteria, Urine", "Bacteria"],
|
|
1753
1807
|
pt: ["Bact\xE9rias na Urina", "Bact\xE9rias"]
|
|
@@ -1866,7 +1920,14 @@ var BIOMARKER_DEFINITIONS = [
|
|
|
1866
1920
|
{
|
|
1867
1921
|
category: "urina",
|
|
1868
1922
|
code: "RBC_Urine",
|
|
1869
|
-
|
|
1923
|
+
// 13945-1 é "Erythrocytes [#/area] in Urine sediment by Microscopy high
|
|
1924
|
+
// power field", o /HPF que o laudo imprime e que `Leukocytes_Urine` já usa
|
|
1925
|
+
// em 5821-4. Até out/2026 apontava para 5808-1, o mesmo exame em #/volume
|
|
1926
|
+
// (por mL): analito e material certos, propriedade errada. Fica como alias
|
|
1927
|
+
// porque o analito é o mesmo, e laudo de analisador automático que conte
|
|
1928
|
+
// por mL continua resolvendo em RBC_Urine.
|
|
1929
|
+
loinc: "13945-1",
|
|
1930
|
+
loincAliases: ["5808-1"],
|
|
1870
1931
|
names: {
|
|
1871
1932
|
en: ["Urine RBC", "Red Blood Cells in Urine", "RBC Urine", "RBC, Urine"],
|
|
1872
1933
|
pt: ["Hem\xE1cias na Urina"]
|
|
@@ -1961,6 +2022,10 @@ var BIOMARKER_DEFINITIONS = [
|
|
|
1961
2022
|
{
|
|
1962
2023
|
category: "autoimunidade",
|
|
1963
2024
|
code: "Gliadin_Deamidated_IgA",
|
|
2025
|
+
// 63453-5 e 63459-2 (IgG) afirmam método, "by Immunoassay", e material,
|
|
2026
|
+
// "Serum". É o que os kits de DGP usam. A propriedade é unidades
|
|
2027
|
+
// arbitrárias por volume, e o laudo imprime U/mL; até out/2026 a unidade
|
|
2028
|
+
// declarada era "U", sem o volume.
|
|
1964
2029
|
loinc: "63453-5",
|
|
1965
2030
|
names: {
|
|
1966
2031
|
en: [
|
|
@@ -1974,7 +2039,7 @@ var BIOMARKER_DEFINITIONS = [
|
|
|
1974
2039
|
],
|
|
1975
2040
|
pt: ["Anticorpos Anti-Gliadina Deamidada IgA", "DGP IgA"]
|
|
1976
2041
|
},
|
|
1977
|
-
unit: "U"
|
|
2042
|
+
unit: "U/mL"
|
|
1978
2043
|
},
|
|
1979
2044
|
{
|
|
1980
2045
|
category: "autoimunidade",
|
|
@@ -1992,7 +2057,7 @@ var BIOMARKER_DEFINITIONS = [
|
|
|
1992
2057
|
],
|
|
1993
2058
|
pt: ["Anticorpos Anti-Gliadina Deamidada IgG", "DGP IgG"]
|
|
1994
2059
|
},
|
|
1995
|
-
unit: "U"
|
|
2060
|
+
unit: "U/mL"
|
|
1996
2061
|
},
|
|
1997
2062
|
{
|
|
1998
2063
|
category: "autoimunidade",
|
|
@@ -2383,6 +2448,10 @@ var BIOMARKER_DEFINITIONS = [
|
|
|
2383
2448
|
{
|
|
2384
2449
|
category: "composicao-corporal",
|
|
2385
2450
|
code: "TotalBodyWater",
|
|
2451
|
+
// 101683-1 é "Body water mass", em kg; o aparelho de bioimpedância imprime
|
|
2452
|
+
// litros. É o único código de água corporal total no LOINC 2.82 (o outro,
|
|
2453
|
+
// 101684-9, é o percentual), e para água 1 L pesa 1 kg, então o número não
|
|
2454
|
+
// muda. O teste de eixos lista a entrada como exceção com este motivo.
|
|
2386
2455
|
loinc: "101683-1",
|
|
2387
2456
|
names: {
|
|
2388
2457
|
en: ["Total Body Water", "Body Water", "TBW", "Total Water"],
|
|
@@ -2448,6 +2517,10 @@ var BIOMARKER_DEFINITIONS = [
|
|
|
2448
2517
|
{
|
|
2449
2518
|
category: "composicao-corporal",
|
|
2450
2519
|
code: "PhaseAngle",
|
|
2520
|
+
// 107160-4 é "Phase angle Xc/R [Ratio] Bioelectrical impedance analysis",
|
|
2521
|
+
// único código de ângulo de fase. O aparelho imprime graus (arctan Xc/R)
|
|
2522
|
+
// e o LOINC declara razão com unidade-exemplo %. Fica em graus, que é o
|
|
2523
|
+
// que o laudo traz, e o teste de eixos lista a entrada como exceção.
|
|
2451
2524
|
loinc: "107160-4",
|
|
2452
2525
|
names: {
|
|
2453
2526
|
en: ["Phase Angle", "Whole Body Phase Angle", "PhA", "AnglePhase"],
|
|
@@ -2538,9 +2611,9 @@ var BIOMARKER_DEFINITIONS = [
|
|
|
2538
2611
|
{
|
|
2539
2612
|
category: "composicao-corporal",
|
|
2540
2613
|
code: "WaistCircumference",
|
|
2541
|
-
// 8280-0 é a medida em si
|
|
2542
|
-
// "
|
|
2543
|
-
// resultado.
|
|
2614
|
+
// 8280-0 é a medida em si, e afirma sítio e método: "at umbilicus by Tape
|
|
2615
|
+
// measure". 56086-2, que parecia o óbvio pela busca, é "Adult Waist
|
|
2616
|
+
// Circumference Protocol", um protocolo PhenX e não um resultado.
|
|
2544
2617
|
loinc: "8280-0",
|
|
2545
2618
|
names: {
|
|
2546
2619
|
en: ["Waist Circumference", "Abdominal Circumference", "Waist"],
|
|
@@ -2950,6 +3023,10 @@ var BIOMARKER_DEFINITIONS = [
|
|
|
2950
3023
|
{
|
|
2951
3024
|
category: "coracao",
|
|
2952
3025
|
code: "TroponinI",
|
|
3026
|
+
// 49563-0 afirma método: limite de detecção ≤ 0,01 ng/mL, o ensaio de alta
|
|
3027
|
+
// sensibilidade. Um resultado de troponina I convencional pede o código
|
|
3028
|
+
// sem método, 10839-9. Assimétrico com `TroponinT`, que fica no 6598-7 sem
|
|
3029
|
+
// método de propósito: a hs-cTnT em ng/L é a convenção dos laudos.
|
|
2953
3030
|
loinc: "49563-0",
|
|
2954
3031
|
names: {
|
|
2955
3032
|
en: ["Troponin I", "cTnI", "Cardiac Troponin I", "hs-TnI", "High-Sensitivity Troponin I"],
|
|
@@ -2960,6 +3037,9 @@ var BIOMARKER_DEFINITIONS = [
|
|
|
2960
3037
|
{
|
|
2961
3038
|
category: "coracao",
|
|
2962
3039
|
code: "TroponinT",
|
|
3040
|
+
// 6598-7 não afirma método. A unidade ng/L é a convenção do ensaio de alta
|
|
3041
|
+
// sensibilidade (hs-cTnT), e o ensaio convencional em ng/mL converte por
|
|
3042
|
+
// fator exato (ver `units.ts`). Ver `TroponinI` para a assimetria.
|
|
2963
3043
|
loinc: "6598-7",
|
|
2964
3044
|
names: {
|
|
2965
3045
|
en: ["Troponin T", "cTnT", "Cardiac Troponin T", "hs-TnT", "High-Sensitivity Troponin T"],
|
|
@@ -2996,6 +3076,11 @@ var BIOMARKER_DEFINITIONS = [
|
|
|
2996
3076
|
{
|
|
2997
3077
|
category: "figado",
|
|
2998
3078
|
code: "LDH",
|
|
3079
|
+
// 14804-9 afirma método: reação lactato → piruvato (L→P). O código sem
|
|
3080
|
+
// método, 2532-0, está DISCOURAGED, então um método tem que ser escolhido,
|
|
3081
|
+
// e L→P é o do procedimento de referência IFCC que os laboratórios
|
|
3082
|
+
// brasileiros usam, ainda que o laudo raramente imprima a direção. Se um
|
|
3083
|
+
// laudo declarar P→L, o código é outro (14805-6).
|
|
2999
3084
|
loinc: "14804-9",
|
|
3000
3085
|
// 2532-0 é o código genérico anterior, que o LOINC marca como DISCOURAGED.
|
|
3001
3086
|
// Fica como alias para que laudo antigo e dado já armazenado continuem
|
|
@@ -3126,7 +3211,13 @@ var BIOMARKER_DEFINITIONS = [
|
|
|
3126
3211
|
{
|
|
3127
3212
|
category: "pancreas",
|
|
3128
3213
|
code: "BetaHydroxybutyrate",
|
|
3129
|
-
|
|
3214
|
+
// 6873-4 é "Beta hydroxybutyrate [Moles/volume] in Serum or Plasma", o
|
|
3215
|
+
// que o laudo dosa em mmol/L. Até out/2026 apontava para 53060-0, que é
|
|
3216
|
+
// butirilcarnitina (C4) em líquido amniótico: analito e material errados
|
|
3217
|
+
// desde abr/2026, e nenhum check pegou porque o código existe e está
|
|
3218
|
+
// ACTIVE. Sem alias para o código antigo: ele nunca significou BHB, e
|
|
3219
|
+
// aceitá-lo na importação faria um laudo de carnitina virar cetona.
|
|
3220
|
+
loinc: "6873-4",
|
|
3130
3221
|
names: {
|
|
3131
3222
|
en: ["Beta-Hydroxybutyrate", "\u03B2-Hydroxybutyrate", "BHB", "Ketone Bodies"],
|
|
3132
3223
|
pt: ["Beta-Hidroxibutirato", "\u03B2-Hidroxibutirato", "BHB", "Corpos Cet\xF4nicos"]
|
|
@@ -3465,4 +3556,4 @@ export {
|
|
|
3465
3556
|
getBiomarkersByCategory,
|
|
3466
3557
|
getBiomarkersForCategories
|
|
3467
3558
|
};
|
|
3468
|
-
//# sourceMappingURL=chunk-
|
|
3559
|
+
//# sourceMappingURL=chunk-4FKZG5GZ.js.map
|