@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/dist/cli.js
CHANGED
|
@@ -124,6 +124,10 @@ var BIOMARKER_DEFINITIONS = [
|
|
|
124
124
|
{
|
|
125
125
|
category: "coracao",
|
|
126
126
|
code: "LDL_Medium",
|
|
127
|
+
// 96735-6 é "in Serum" só, enquanto as vizinhas LDL_Small (43727-7),
|
|
128
|
+
// LDL_ParticleNumber (54434-6) e HDL_Large (43729-3) são Ser/Plas. É o
|
|
129
|
+
// único código para a subfração média, e o perfil por RMN roda em soro.
|
|
130
|
+
// Material registrado de propósito.
|
|
127
131
|
loinc: "96735-6",
|
|
128
132
|
names: {
|
|
129
133
|
en: ["LDL Medium", "Medium LDL Particles"],
|
|
@@ -1091,14 +1095,16 @@ var BIOMARKER_DEFINITIONS = [
|
|
|
1091
1095
|
},
|
|
1092
1096
|
{
|
|
1093
1097
|
// LOINC 99620-7 = "Omega 3 fatty acids (w3) [Moles/volume] in RBC.lysate".
|
|
1094
|
-
//
|
|
1095
|
-
//
|
|
1096
|
-
//
|
|
1097
|
-
//
|
|
1098
|
-
//
|
|
1099
|
-
//
|
|
1100
|
-
//
|
|
1101
|
-
//
|
|
1098
|
+
// Anteriormente 35178-3 (mesmo analito em Ser/Plas), incompatível com o
|
|
1099
|
+
// uso clínico do Índice Ômega-3 (Harris & von Schacky 2004), que é
|
|
1100
|
+
// definido em membranas de hemácias.
|
|
1101
|
+
//
|
|
1102
|
+
// Compromisso declarado, e não erro: o LOINC 2.82 não tem código de fração
|
|
1103
|
+
// ("ômega-3 total / ácidos graxos totais") para o total, só para os ácidos
|
|
1104
|
+
// individuais e para EPA+DPA+DHA (90911-9). O componente confere; a
|
|
1105
|
+
// propriedade é moles/volume enquanto o laudo imprime %. O teste de eixos
|
|
1106
|
+
// (`loinc-axes.test.ts`) lista esta entrada como exceção com este motivo.
|
|
1107
|
+
// Mesmo compromisso em `Omega6_Total` (99621-5).
|
|
1102
1108
|
category: "nutrientes",
|
|
1103
1109
|
code: "Omega3_Total",
|
|
1104
1110
|
loinc: "99620-7",
|
|
@@ -1112,7 +1118,18 @@ var BIOMARKER_DEFINITIONS = [
|
|
|
1112
1118
|
category: "nutrientes",
|
|
1113
1119
|
code: "Omega3_DHA",
|
|
1114
1120
|
codeAliases: ["DHA"],
|
|
1115
|
-
|
|
1121
|
+
// Ácidos graxos individuais: fração do total (% dos ácidos graxos C14-C22),
|
|
1122
|
+
// que é o que o perfil de ácidos graxos e o Índice Ômega-3 imprimem. Os
|
|
1123
|
+
// códigos vêm do painel 90918-4 ("Fatty acid omega-3 and omega-6 panel -
|
|
1124
|
+
// Blood"), o mesmo de onde já saem as razões AA/EPA (90909-3) e ω6/ω3
|
|
1125
|
+
// (90910-1). Até out/2026 apontavam para os códigos [Entitic substance]
|
|
1126
|
+
// em hemácias (75095-0, 75097-6, 75110-7, 75117-2), que são quantidade por
|
|
1127
|
+
// célula, e para 48371-9, que é moles/volume em soro: componente certo,
|
|
1128
|
+
// propriedade errada nos cinco, desde mar/2026. Ficam como alias porque o
|
|
1129
|
+
// analito é o mesmo. Material: o painel em soro/plasma (88884-2, C14-C24)
|
|
1130
|
+
// existe, e é a troca a fazer se um laboratório imprimir o perfil em soro.
|
|
1131
|
+
loinc: "90914-3",
|
|
1132
|
+
loincAliases: ["75095-0"],
|
|
1116
1133
|
names: {
|
|
1117
1134
|
en: ["Omega-3 DHA", "DHA", "Docosahexaenoic Acid"],
|
|
1118
1135
|
pt: ["\xD4mega-3: DHA", "DHA", "\xC1cido Docosahexaenoico"]
|
|
@@ -1123,7 +1140,9 @@ var BIOMARKER_DEFINITIONS = [
|
|
|
1123
1140
|
category: "nutrientes",
|
|
1124
1141
|
code: "Omega3_DPA",
|
|
1125
1142
|
codeAliases: ["DPA"],
|
|
1126
|
-
|
|
1143
|
+
// Fração em sangue, painel 90918-4. Ver `Omega3_DHA`.
|
|
1144
|
+
loinc: "90913-5",
|
|
1145
|
+
loincAliases: ["48371-9"],
|
|
1127
1146
|
names: {
|
|
1128
1147
|
en: ["Omega-3 DPA", "DPA", "Docosapentaenoic Acid"],
|
|
1129
1148
|
pt: ["\xD4mega-3: DPA", "DPA", "\xC1cido Docosapentaenoico"]
|
|
@@ -1134,7 +1153,9 @@ var BIOMARKER_DEFINITIONS = [
|
|
|
1134
1153
|
category: "nutrientes",
|
|
1135
1154
|
code: "Omega3_EPA",
|
|
1136
1155
|
codeAliases: ["EPA"],
|
|
1137
|
-
|
|
1156
|
+
// Fração em sangue, painel 90918-4. Ver `Omega3_DHA`.
|
|
1157
|
+
loinc: "90912-7",
|
|
1158
|
+
loincAliases: ["75097-6"],
|
|
1138
1159
|
names: {
|
|
1139
1160
|
en: ["Omega-3 EPA", "EPA", "Eicosapentaenoic Acid"],
|
|
1140
1161
|
pt: ["\xD4mega-3: EPA", "EPA", "\xC1cido Eicosapentaenoico"]
|
|
@@ -1144,7 +1165,12 @@ var BIOMARKER_DEFINITIONS = [
|
|
|
1144
1165
|
{
|
|
1145
1166
|
category: "nutrientes",
|
|
1146
1167
|
code: "EPADPADHA",
|
|
1147
|
-
|
|
1168
|
+
// 90911-9 é a fração EPA+DPA+DHA / ácidos graxos C14-C22 em sangue, o
|
|
1169
|
+
// valor em %. Até out/2026 apontava para 90908-5, que é a *interpretação*
|
|
1170
|
+
// desse mesmo valor (ordinal: risco alto, moderado, baixo), e não o
|
|
1171
|
+
// número. Sem alias: código ordinal carregando valor numérico é o erro
|
|
1172
|
+
// que se quer parar de aceitar.
|
|
1173
|
+
loinc: "90911-9",
|
|
1148
1174
|
names: {
|
|
1149
1175
|
en: ["Omega-3 EPA+DPA+DHA", "EPA+DPA+DHA"],
|
|
1150
1176
|
pt: ["\xD4mega-3: EPA+DPA+DHA"]
|
|
@@ -1165,7 +1191,12 @@ var BIOMARKER_DEFINITIONS = [
|
|
|
1165
1191
|
{
|
|
1166
1192
|
category: "nutrientes",
|
|
1167
1193
|
code: "Omega6_Total",
|
|
1168
|
-
|
|
1194
|
+
// 99621-5 é "Omega 6 fatty acids (w6) [Moles/volume] in RBC.lysate", o
|
|
1195
|
+
// par exato do 99620-7 de `Omega3_Total`, com o mesmo compromisso de
|
|
1196
|
+
// propriedade documentado lá. Até out/2026 apontava para 35177-5, que é
|
|
1197
|
+
// ácidos graxos poli-insaturados totais em soro: ômega-3 e ômega-6
|
|
1198
|
+
// somados, outro componente. Sem alias.
|
|
1199
|
+
loinc: "99621-5",
|
|
1169
1200
|
names: {
|
|
1170
1201
|
en: ["Omega-6 Total", "Total Omega-6"],
|
|
1171
1202
|
pt: ["\xD4mega-6 Total"]
|
|
@@ -1176,7 +1207,9 @@ var BIOMARKER_DEFINITIONS = [
|
|
|
1176
1207
|
category: "nutrientes",
|
|
1177
1208
|
code: "Omega6_AA",
|
|
1178
1209
|
codeAliases: ["Arachidonic_Acid"],
|
|
1179
|
-
|
|
1210
|
+
// Fração em sangue, painel 90918-4. Ver `Omega3_DHA`.
|
|
1211
|
+
loinc: "90916-8",
|
|
1212
|
+
loincAliases: ["75110-7"],
|
|
1180
1213
|
names: {
|
|
1181
1214
|
en: ["Omega-6 Arachidonic Acid", "Arachidonic Acid", "AA"],
|
|
1182
1215
|
pt: ["\xD4mega-6: \xC1cido Araquid\xF4nico", "\xC1cido Araquid\xF4nico", "AA"]
|
|
@@ -1187,7 +1220,9 @@ var BIOMARKER_DEFINITIONS = [
|
|
|
1187
1220
|
category: "nutrientes",
|
|
1188
1221
|
code: "Omega6_LA",
|
|
1189
1222
|
codeAliases: ["Linoleic_Acid"],
|
|
1190
|
-
|
|
1223
|
+
// Fração em sangue, painel 90918-4. Ver `Omega3_DHA`.
|
|
1224
|
+
loinc: "90917-6",
|
|
1225
|
+
loincAliases: ["75117-2"],
|
|
1191
1226
|
names: {
|
|
1192
1227
|
en: ["Omega-6 Linoleic Acid", "Linoleic Acid", "LA"],
|
|
1193
1228
|
pt: ["\xD4mega-6: \xC1cido Linoleico", "\xC1cido Linoleico", "LA"]
|
|
@@ -1268,7 +1303,11 @@ var BIOMARKER_DEFINITIONS = [
|
|
|
1268
1303
|
{
|
|
1269
1304
|
category: "nutrientes",
|
|
1270
1305
|
code: "Zinc",
|
|
1271
|
-
|
|
1306
|
+
// 5763-8 é "Zinc [Mass/volume] in Serum or Plasma", o zinco sérico da
|
|
1307
|
+
// rotina brasileira (o nome em inglês já dizia "Serum Zinc"). Até out/2026
|
|
1308
|
+
// apontava para 8245-3, o mesmo analito em sangue total, que tem faixa de
|
|
1309
|
+
// referência própria. Sem alias: sangue total é outro material.
|
|
1310
|
+
loinc: "5763-8",
|
|
1272
1311
|
names: {
|
|
1273
1312
|
en: ["Zinc", "Serum Zinc"],
|
|
1274
1313
|
pt: ["Zinco"]
|
|
@@ -1369,6 +1408,9 @@ var BIOMARKER_DEFINITIONS = [
|
|
|
1369
1408
|
{
|
|
1370
1409
|
category: "figado",
|
|
1371
1410
|
code: "Globulin",
|
|
1411
|
+
// 2336-6 é "Globulin [Mass/volume] in Serum", soro só: o LOINC 2.82 não
|
|
1412
|
+
// tem a versão Ser/Plas da globulina total (as frações alfa, beta e gama
|
|
1413
|
+
// têm). Material registrado de propósito.
|
|
1372
1414
|
loinc: "2336-6",
|
|
1373
1415
|
names: {
|
|
1374
1416
|
en: ["Globulin", "Serum Globulin"],
|
|
@@ -1648,6 +1690,13 @@ var BIOMARKER_DEFINITIONS = [
|
|
|
1648
1690
|
{
|
|
1649
1691
|
category: "rins",
|
|
1650
1692
|
code: "BUN_Creatinine_Ratio",
|
|
1693
|
+
// 3097-3 é "Urea nitrogen/Creatinine [Mass Ratio]", a razão BUN/creatinina,
|
|
1694
|
+
// e a faixa de referência (10-20, Tietz) é a dessa convenção. O laudo
|
|
1695
|
+
// brasileiro imprime "Relação Ureia/Creatinina", cuja faixa é outra (cerca
|
|
1696
|
+
// de 21-43) e cujo código é 56997-0 ("Urea/Creatinine [Mass Ratio] in
|
|
1697
|
+
// Serum or Plasma"). Trocar só o código deixaria a faixa errada do outro
|
|
1698
|
+
// lado; a separação em duas grandezas, como em `Glucose_Fasting`, é
|
|
1699
|
+
// decisão à parte, registrada em `reference-ranges.ts`.
|
|
1651
1700
|
loinc: "3097-3",
|
|
1652
1701
|
names: {
|
|
1653
1702
|
en: ["BUN/Creatinine Ratio", "Urea/Creatinine Ratio"],
|
|
@@ -1815,7 +1864,12 @@ var BIOMARKER_DEFINITIONS = [
|
|
|
1815
1864
|
category: "urina",
|
|
1816
1865
|
code: "Bacteria_Urine",
|
|
1817
1866
|
codeAliases: ["UrineBacteria"],
|
|
1818
|
-
|
|
1867
|
+
// 5769-5 é "Bacteria [#/area] in Urine sediment by Microscopy high power
|
|
1868
|
+
// field", a contagem do sedimento que a unidade /HPF declara. Até out/2026
|
|
1869
|
+
// apontava para 630-4, "Bacteria identified in Urine by Culture": outro
|
|
1870
|
+
// exame, nominal, que identifica a espécie em cultura. Sem alias:
|
|
1871
|
+
// urocultura não é sedimento.
|
|
1872
|
+
loinc: "5769-5",
|
|
1819
1873
|
names: {
|
|
1820
1874
|
en: ["Urine Bacteria", "Bacteria Urine", "Bacteria, Urine", "Bacteria"],
|
|
1821
1875
|
pt: ["Bact\xE9rias na Urina", "Bact\xE9rias"]
|
|
@@ -1934,7 +1988,14 @@ var BIOMARKER_DEFINITIONS = [
|
|
|
1934
1988
|
{
|
|
1935
1989
|
category: "urina",
|
|
1936
1990
|
code: "RBC_Urine",
|
|
1937
|
-
|
|
1991
|
+
// 13945-1 é "Erythrocytes [#/area] in Urine sediment by Microscopy high
|
|
1992
|
+
// power field", o /HPF que o laudo imprime e que `Leukocytes_Urine` já usa
|
|
1993
|
+
// em 5821-4. Até out/2026 apontava para 5808-1, o mesmo exame em #/volume
|
|
1994
|
+
// (por mL): analito e material certos, propriedade errada. Fica como alias
|
|
1995
|
+
// porque o analito é o mesmo, e laudo de analisador automático que conte
|
|
1996
|
+
// por mL continua resolvendo em RBC_Urine.
|
|
1997
|
+
loinc: "13945-1",
|
|
1998
|
+
loincAliases: ["5808-1"],
|
|
1938
1999
|
names: {
|
|
1939
2000
|
en: ["Urine RBC", "Red Blood Cells in Urine", "RBC Urine", "RBC, Urine"],
|
|
1940
2001
|
pt: ["Hem\xE1cias na Urina"]
|
|
@@ -2029,6 +2090,10 @@ var BIOMARKER_DEFINITIONS = [
|
|
|
2029
2090
|
{
|
|
2030
2091
|
category: "autoimunidade",
|
|
2031
2092
|
code: "Gliadin_Deamidated_IgA",
|
|
2093
|
+
// 63453-5 e 63459-2 (IgG) afirmam método, "by Immunoassay", e material,
|
|
2094
|
+
// "Serum". É o que os kits de DGP usam. A propriedade é unidades
|
|
2095
|
+
// arbitrárias por volume, e o laudo imprime U/mL; até out/2026 a unidade
|
|
2096
|
+
// declarada era "U", sem o volume.
|
|
2032
2097
|
loinc: "63453-5",
|
|
2033
2098
|
names: {
|
|
2034
2099
|
en: [
|
|
@@ -2042,7 +2107,7 @@ var BIOMARKER_DEFINITIONS = [
|
|
|
2042
2107
|
],
|
|
2043
2108
|
pt: ["Anticorpos Anti-Gliadina Deamidada IgA", "DGP IgA"]
|
|
2044
2109
|
},
|
|
2045
|
-
unit: "U"
|
|
2110
|
+
unit: "U/mL"
|
|
2046
2111
|
},
|
|
2047
2112
|
{
|
|
2048
2113
|
category: "autoimunidade",
|
|
@@ -2060,7 +2125,7 @@ var BIOMARKER_DEFINITIONS = [
|
|
|
2060
2125
|
],
|
|
2061
2126
|
pt: ["Anticorpos Anti-Gliadina Deamidada IgG", "DGP IgG"]
|
|
2062
2127
|
},
|
|
2063
|
-
unit: "U"
|
|
2128
|
+
unit: "U/mL"
|
|
2064
2129
|
},
|
|
2065
2130
|
{
|
|
2066
2131
|
category: "autoimunidade",
|
|
@@ -2451,6 +2516,10 @@ var BIOMARKER_DEFINITIONS = [
|
|
|
2451
2516
|
{
|
|
2452
2517
|
category: "composicao-corporal",
|
|
2453
2518
|
code: "TotalBodyWater",
|
|
2519
|
+
// 101683-1 é "Body water mass", em kg; o aparelho de bioimpedância imprime
|
|
2520
|
+
// litros. É o único código de água corporal total no LOINC 2.82 (o outro,
|
|
2521
|
+
// 101684-9, é o percentual), e para água 1 L pesa 1 kg, então o número não
|
|
2522
|
+
// muda. O teste de eixos lista a entrada como exceção com este motivo.
|
|
2454
2523
|
loinc: "101683-1",
|
|
2455
2524
|
names: {
|
|
2456
2525
|
en: ["Total Body Water", "Body Water", "TBW", "Total Water"],
|
|
@@ -2516,6 +2585,10 @@ var BIOMARKER_DEFINITIONS = [
|
|
|
2516
2585
|
{
|
|
2517
2586
|
category: "composicao-corporal",
|
|
2518
2587
|
code: "PhaseAngle",
|
|
2588
|
+
// 107160-4 é "Phase angle Xc/R [Ratio] Bioelectrical impedance analysis",
|
|
2589
|
+
// único código de ângulo de fase. O aparelho imprime graus (arctan Xc/R)
|
|
2590
|
+
// e o LOINC declara razão com unidade-exemplo %. Fica em graus, que é o
|
|
2591
|
+
// que o laudo traz, e o teste de eixos lista a entrada como exceção.
|
|
2519
2592
|
loinc: "107160-4",
|
|
2520
2593
|
names: {
|
|
2521
2594
|
en: ["Phase Angle", "Whole Body Phase Angle", "PhA", "AnglePhase"],
|
|
@@ -2606,9 +2679,9 @@ var BIOMARKER_DEFINITIONS = [
|
|
|
2606
2679
|
{
|
|
2607
2680
|
category: "composicao-corporal",
|
|
2608
2681
|
code: "WaistCircumference",
|
|
2609
|
-
// 8280-0 é a medida em si
|
|
2610
|
-
// "
|
|
2611
|
-
// resultado.
|
|
2682
|
+
// 8280-0 é a medida em si, e afirma sítio e método: "at umbilicus by Tape
|
|
2683
|
+
// measure". 56086-2, que parecia o óbvio pela busca, é "Adult Waist
|
|
2684
|
+
// Circumference Protocol", um protocolo PhenX e não um resultado.
|
|
2612
2685
|
loinc: "8280-0",
|
|
2613
2686
|
names: {
|
|
2614
2687
|
en: ["Waist Circumference", "Abdominal Circumference", "Waist"],
|
|
@@ -3018,6 +3091,10 @@ var BIOMARKER_DEFINITIONS = [
|
|
|
3018
3091
|
{
|
|
3019
3092
|
category: "coracao",
|
|
3020
3093
|
code: "TroponinI",
|
|
3094
|
+
// 49563-0 afirma método: limite de detecção ≤ 0,01 ng/mL, o ensaio de alta
|
|
3095
|
+
// sensibilidade. Um resultado de troponina I convencional pede o código
|
|
3096
|
+
// sem método, 10839-9. Assimétrico com `TroponinT`, que fica no 6598-7 sem
|
|
3097
|
+
// método de propósito: a hs-cTnT em ng/L é a convenção dos laudos.
|
|
3021
3098
|
loinc: "49563-0",
|
|
3022
3099
|
names: {
|
|
3023
3100
|
en: ["Troponin I", "cTnI", "Cardiac Troponin I", "hs-TnI", "High-Sensitivity Troponin I"],
|
|
@@ -3028,6 +3105,9 @@ var BIOMARKER_DEFINITIONS = [
|
|
|
3028
3105
|
{
|
|
3029
3106
|
category: "coracao",
|
|
3030
3107
|
code: "TroponinT",
|
|
3108
|
+
// 6598-7 não afirma método. A unidade ng/L é a convenção do ensaio de alta
|
|
3109
|
+
// sensibilidade (hs-cTnT), e o ensaio convencional em ng/mL converte por
|
|
3110
|
+
// fator exato (ver `units.ts`). Ver `TroponinI` para a assimetria.
|
|
3031
3111
|
loinc: "6598-7",
|
|
3032
3112
|
names: {
|
|
3033
3113
|
en: ["Troponin T", "cTnT", "Cardiac Troponin T", "hs-TnT", "High-Sensitivity Troponin T"],
|
|
@@ -3064,6 +3144,11 @@ var BIOMARKER_DEFINITIONS = [
|
|
|
3064
3144
|
{
|
|
3065
3145
|
category: "figado",
|
|
3066
3146
|
code: "LDH",
|
|
3147
|
+
// 14804-9 afirma método: reação lactato → piruvato (L→P). O código sem
|
|
3148
|
+
// método, 2532-0, está DISCOURAGED, então um método tem que ser escolhido,
|
|
3149
|
+
// e L→P é o do procedimento de referência IFCC que os laboratórios
|
|
3150
|
+
// brasileiros usam, ainda que o laudo raramente imprima a direção. Se um
|
|
3151
|
+
// laudo declarar P→L, o código é outro (14805-6).
|
|
3067
3152
|
loinc: "14804-9",
|
|
3068
3153
|
// 2532-0 é o código genérico anterior, que o LOINC marca como DISCOURAGED.
|
|
3069
3154
|
// Fica como alias para que laudo antigo e dado já armazenado continuem
|
|
@@ -3194,7 +3279,13 @@ var BIOMARKER_DEFINITIONS = [
|
|
|
3194
3279
|
{
|
|
3195
3280
|
category: "pancreas",
|
|
3196
3281
|
code: "BetaHydroxybutyrate",
|
|
3197
|
-
|
|
3282
|
+
// 6873-4 é "Beta hydroxybutyrate [Moles/volume] in Serum or Plasma", o
|
|
3283
|
+
// que o laudo dosa em mmol/L. Até out/2026 apontava para 53060-0, que é
|
|
3284
|
+
// butirilcarnitina (C4) em líquido amniótico: analito e material errados
|
|
3285
|
+
// desde abr/2026, e nenhum check pegou porque o código existe e está
|
|
3286
|
+
// ACTIVE. Sem alias para o código antigo: ele nunca significou BHB, e
|
|
3287
|
+
// aceitá-lo na importação faria um laudo de carnitina virar cetona.
|
|
3288
|
+
loinc: "6873-4",
|
|
3198
3289
|
names: {
|
|
3199
3290
|
en: ["Beta-Hydroxybutyrate", "\u03B2-Hydroxybutyrate", "BHB", "Ketone Bodies"],
|
|
3200
3291
|
pt: ["Beta-Hidroxibutirato", "\u03B2-Hidroxibutirato", "BHB", "Corpos Cet\xF4nicos"]
|
|
@@ -3325,97 +3416,99 @@ var BIOMARKER_CODE_SYSTEM = "http://fhir-brasil.dev/biomarker-codes";
|
|
|
3325
3416
|
var UNIT_TO_UCUM = {
|
|
3326
3417
|
// Dimensionless / special measurements
|
|
3327
3418
|
"[pH]": "[pH]",
|
|
3419
|
+
"{index}": "{index}",
|
|
3328
3420
|
"{ratio}": "{ratio}",
|
|
3421
|
+
"{score}": "{score}",
|
|
3329
3422
|
"{specific gravity}": "{specific gravity}",
|
|
3423
|
+
"/HPF": "/[HPF]",
|
|
3424
|
+
"/LPF": "/[LPF]",
|
|
3330
3425
|
"/\xB5L": "/uL",
|
|
3331
3426
|
// Percentage
|
|
3332
3427
|
"%": "%",
|
|
3333
3428
|
// Count units
|
|
3334
3429
|
"10\xB3/\xB5L": "10*3/uL",
|
|
3335
3430
|
"10\u2076/\xB5L": "10*6/uL",
|
|
3431
|
+
Angstrom: "Ao",
|
|
3432
|
+
AU: "{score}",
|
|
3433
|
+
cm: "cm",
|
|
3434
|
+
"cm\xB3": "cm3",
|
|
3435
|
+
deg: "deg",
|
|
3336
3436
|
// Volume
|
|
3337
3437
|
fL: "fL",
|
|
3338
3438
|
g: "g",
|
|
3439
|
+
"g/cm\xB2": "g/cm2",
|
|
3339
3440
|
// Mass concentration
|
|
3340
3441
|
"g/dL": "g/dL",
|
|
3442
|
+
"g/L": "g/L",
|
|
3443
|
+
"IU/L": "[IU]/L",
|
|
3444
|
+
"IU/mL": "[IU]/mL",
|
|
3445
|
+
"K/uL": "10*3/uL",
|
|
3446
|
+
"kcal/d": "kcal/d",
|
|
3447
|
+
kg: "kg",
|
|
3448
|
+
"kg/m2": "kg/m2",
|
|
3449
|
+
"kg/m\xB2": "kg/m2",
|
|
3450
|
+
"kU/L": "k[IU]/L",
|
|
3341
3451
|
L: "L",
|
|
3452
|
+
"M/uL": "10*6/uL",
|
|
3453
|
+
"mcg/dL": "ug/dL",
|
|
3454
|
+
"mcg/L": "ug/L",
|
|
3455
|
+
"mcg/mL": "ug/mL",
|
|
3342
3456
|
// Molar concentration
|
|
3343
3457
|
"mEq/L": "meq/L",
|
|
3344
3458
|
mg: "mg",
|
|
3345
3459
|
"mg/dL": "mg/dL",
|
|
3460
|
+
"mg/g": "mg/g",
|
|
3461
|
+
"mg/L": "mg/L",
|
|
3462
|
+
"mIU/L": "m[IU]/L",
|
|
3463
|
+
"mIU/mL": "m[IU]/mL",
|
|
3346
3464
|
mL: "mL",
|
|
3465
|
+
"mL/min/1.73m\xB2": "mL/min/{1.73_m2}",
|
|
3466
|
+
mm: "mm",
|
|
3467
|
+
"mm/h": "mm/h",
|
|
3468
|
+
"mm/hr": "mm/h",
|
|
3347
3469
|
"mmol/L": "mmol/L",
|
|
3470
|
+
"mUI/L": "m[IU]/L",
|
|
3348
3471
|
"mUI/mL": "m[IU]/mL",
|
|
3349
3472
|
ng: "ng",
|
|
3350
3473
|
"ng/dL": "ng/dL",
|
|
3474
|
+
"ng/L": "ng/L",
|
|
3351
3475
|
"ng/mL": "ng/mL",
|
|
3352
3476
|
"nmol/L": "nmol/L",
|
|
3353
3477
|
// Mass
|
|
3354
3478
|
pg: "pg",
|
|
3355
3479
|
"pg/mL": "pg/mL",
|
|
3356
3480
|
pH: "[pH]",
|
|
3481
|
+
"pmol/L": "pmol/L",
|
|
3482
|
+
raz\u00E3o: "{ratio}",
|
|
3483
|
+
score: "{score}",
|
|
3484
|
+
segundos: "s",
|
|
3357
3485
|
// Enzyme activity
|
|
3486
|
+
U: "U",
|
|
3358
3487
|
"U/L": "U/L",
|
|
3359
3488
|
// Special units
|
|
3360
3489
|
"U/mL": "U/mL",
|
|
3490
|
+
"ug/dL": "ug/dL",
|
|
3491
|
+
"ug/L": "ug/L",
|
|
3361
3492
|
"UI/L": "[IU]/L",
|
|
3362
3493
|
"UI/mL": "[IU]/mL",
|
|
3494
|
+
"uIU/mL": "u[IU]/mL",
|
|
3495
|
+
"umol/L": "umol/L",
|
|
3363
3496
|
\u00B5g: "ug",
|
|
3364
3497
|
"\xB5g/dL": "ug/dL",
|
|
3498
|
+
"\xB5g/L": "ug/L",
|
|
3365
3499
|
"\xB5mol/L": "umol/L",
|
|
3366
|
-
"\xB5UI/mL": "u[IU]/mL"
|
|
3500
|
+
"\xB5UI/mL": "u[IU]/mL",
|
|
3501
|
+
\u00EDndice: "{index}"
|
|
3367
3502
|
};
|
|
3368
|
-
var
|
|
3369
|
-
// Proteins
|
|
3370
|
-
Albumin: "g/dL",
|
|
3371
|
-
AlkalinePhosphatase: "U/L",
|
|
3372
|
-
// Liver
|
|
3373
|
-
ALT: "U/L",
|
|
3374
|
-
AST: "U/L",
|
|
3375
|
-
Calcium: "mg/dL",
|
|
3376
|
-
Chloride: "mEq/L",
|
|
3377
|
-
// Lipids
|
|
3378
|
-
Cholesterol: "mg/dL",
|
|
3379
|
-
// Kidney
|
|
3380
|
-
Creatinine: "mg/dL",
|
|
3381
|
-
eAG: "mg/dL",
|
|
3382
|
-
Ferritin: "ng/mL",
|
|
3383
|
-
FolicAcid: "ng/mL",
|
|
3384
|
-
GGT: "U/L",
|
|
3385
|
-
// Glucose/Diabetes
|
|
3386
|
-
Glucose: "mg/dL",
|
|
3387
|
-
HbA1c: "%",
|
|
3388
|
-
Hct: "%",
|
|
3389
|
-
HDL: "mg/dL",
|
|
3390
|
-
// Hematology
|
|
3391
|
-
Hgb: "g/dL",
|
|
3392
|
-
Insulin: "\xB5UI/mL",
|
|
3393
|
-
// Iron studies
|
|
3394
|
-
Iron: "\xB5g/dL",
|
|
3395
|
-
LDL: "mg/dL",
|
|
3396
|
-
Magnesium: "mg/dL",
|
|
3397
|
-
NonHDL_Cholesterol: "mg/dL",
|
|
3398
|
-
// Urinalysis - dimensionless
|
|
3503
|
+
var DIMENSIONLESS_DEFAULTS = {
|
|
3399
3504
|
pH_Urine: "[pH]",
|
|
3400
|
-
|
|
3401
|
-
|
|
3402
|
-
|
|
3403
|
-
|
|
3404
|
-
|
|
3405
|
-
|
|
3406
|
-
|
|
3407
|
-
TIBC: "\xB5g/dL",
|
|
3408
|
-
TotalProtein: "g/dL",
|
|
3409
|
-
TransferrinSaturation: "%",
|
|
3410
|
-
Triglycerides: "mg/dL",
|
|
3411
|
-
// Thyroid
|
|
3412
|
-
TSH: "\xB5UI/mL",
|
|
3413
|
-
Urea: "mg/dL",
|
|
3414
|
-
UricAcid: "mg/dL",
|
|
3415
|
-
// Vitamins
|
|
3416
|
-
VitaminB12: "pg/mL",
|
|
3417
|
-
VitaminD: "ng/mL",
|
|
3418
|
-
VLDL: "mg/dL"
|
|
3505
|
+
SpecificGravity_Urine: "{specific gravity}"
|
|
3506
|
+
};
|
|
3507
|
+
var BIOMARKER_DEFAULT_UNIT = {
|
|
3508
|
+
...Object.fromEntries(
|
|
3509
|
+
BIOMARKER_DEFINITIONS.filter((b) => b.unit).map((b) => [b.code, b.unit])
|
|
3510
|
+
),
|
|
3511
|
+
...DIMENSIONLESS_DEFAULTS
|
|
3419
3512
|
};
|
|
3420
3513
|
function unitToUCUM(unit) {
|
|
3421
3514
|
return UNIT_TO_UCUM[unit] || unit;
|
|
@@ -3423,6 +3516,128 @@ function unitToUCUM(unit) {
|
|
|
3423
3516
|
function getDefaultUnit(biomarkerCode) {
|
|
3424
3517
|
return BIOMARKER_DEFAULT_UNIT[biomarkerCode] || "";
|
|
3425
3518
|
}
|
|
3519
|
+
var UCUM_ATOMS = /* @__PURE__ */ new Set([
|
|
3520
|
+
"m",
|
|
3521
|
+
"g",
|
|
3522
|
+
"s",
|
|
3523
|
+
"L",
|
|
3524
|
+
"l",
|
|
3525
|
+
"mol",
|
|
3526
|
+
"eq",
|
|
3527
|
+
"U",
|
|
3528
|
+
"cal",
|
|
3529
|
+
"h",
|
|
3530
|
+
"d",
|
|
3531
|
+
"min",
|
|
3532
|
+
"wk",
|
|
3533
|
+
"mo",
|
|
3534
|
+
"a",
|
|
3535
|
+
"Ao",
|
|
3536
|
+
"deg",
|
|
3537
|
+
"K",
|
|
3538
|
+
"A",
|
|
3539
|
+
"N",
|
|
3540
|
+
"Pa",
|
|
3541
|
+
"J",
|
|
3542
|
+
"W",
|
|
3543
|
+
"Hz",
|
|
3544
|
+
"V",
|
|
3545
|
+
"C",
|
|
3546
|
+
"osm",
|
|
3547
|
+
"t",
|
|
3548
|
+
"u",
|
|
3549
|
+
"bar",
|
|
3550
|
+
"atm",
|
|
3551
|
+
"rad",
|
|
3552
|
+
"sr",
|
|
3553
|
+
"cd",
|
|
3554
|
+
"Bq",
|
|
3555
|
+
"Gy",
|
|
3556
|
+
"Sv",
|
|
3557
|
+
"lm",
|
|
3558
|
+
"lx",
|
|
3559
|
+
"Cel",
|
|
3560
|
+
"B",
|
|
3561
|
+
"Np"
|
|
3562
|
+
]);
|
|
3563
|
+
var UCUM_PREFIXES = /* @__PURE__ */ new Set([
|
|
3564
|
+
"Y",
|
|
3565
|
+
"Z",
|
|
3566
|
+
"E",
|
|
3567
|
+
"P",
|
|
3568
|
+
"T",
|
|
3569
|
+
"G",
|
|
3570
|
+
"M",
|
|
3571
|
+
"k",
|
|
3572
|
+
"h",
|
|
3573
|
+
"da",
|
|
3574
|
+
"d",
|
|
3575
|
+
"c",
|
|
3576
|
+
"m",
|
|
3577
|
+
"u",
|
|
3578
|
+
"n",
|
|
3579
|
+
"p",
|
|
3580
|
+
"f",
|
|
3581
|
+
"a",
|
|
3582
|
+
"z",
|
|
3583
|
+
"y"
|
|
3584
|
+
]);
|
|
3585
|
+
function isUcumAtom(token) {
|
|
3586
|
+
if (token === "%" || /^10\*-?\d+$/.test(token) || /^\d+$/.test(token)) return true;
|
|
3587
|
+
const bracket = /^([A-Za-z]{0,2})\[[^[\]{}\s]+\]$/.exec(token);
|
|
3588
|
+
if (bracket) return bracket[1] === "" || UCUM_PREFIXES.has(bracket[1]);
|
|
3589
|
+
if (UCUM_ATOMS.has(token)) return true;
|
|
3590
|
+
for (const prefix of UCUM_PREFIXES) {
|
|
3591
|
+
if (token.startsWith(prefix) && UCUM_ATOMS.has(token.slice(prefix.length))) return true;
|
|
3592
|
+
}
|
|
3593
|
+
return false;
|
|
3594
|
+
}
|
|
3595
|
+
function isUcumComponent(token) {
|
|
3596
|
+
const m = /^(.*?)(\{[^{}]*\})?$/.exec(token);
|
|
3597
|
+
if (!m) return false;
|
|
3598
|
+
const [, body, annotation] = m;
|
|
3599
|
+
if (!body) return annotation !== void 0;
|
|
3600
|
+
const exp = /^(.+?)([+-]?\d+)?$/.exec(body);
|
|
3601
|
+
if (!exp) return false;
|
|
3602
|
+
const [, atom, exponent] = exp;
|
|
3603
|
+
if (isUcumAtom(body)) return true;
|
|
3604
|
+
if (exponent === void 0) return false;
|
|
3605
|
+
return isUcumAtom(atom);
|
|
3606
|
+
}
|
|
3607
|
+
function isUcumCode(code) {
|
|
3608
|
+
if (!code || /[^\x21-\x7E ]/.test(code)) return false;
|
|
3609
|
+
const terms = [];
|
|
3610
|
+
let current = "";
|
|
3611
|
+
let braces = 0;
|
|
3612
|
+
let inBracket = false;
|
|
3613
|
+
for (const ch of code) {
|
|
3614
|
+
if (ch === "{") braces++;
|
|
3615
|
+
else if (ch === "}") {
|
|
3616
|
+
if (braces === 0) return false;
|
|
3617
|
+
braces--;
|
|
3618
|
+
} else if (ch === "[") inBracket = true;
|
|
3619
|
+
else if (ch === "]") inBracket = false;
|
|
3620
|
+
if ((ch === "." || ch === "/") && braces === 0 && !inBracket) {
|
|
3621
|
+
terms.push(current, ch);
|
|
3622
|
+
current = "";
|
|
3623
|
+
continue;
|
|
3624
|
+
}
|
|
3625
|
+
current += ch;
|
|
3626
|
+
}
|
|
3627
|
+
if (braces !== 0 || inBracket) return false;
|
|
3628
|
+
terms.push(current);
|
|
3629
|
+
if (terms[0] === "" && terms[1] === "/") terms[0] = "1";
|
|
3630
|
+
let expectOperand = true;
|
|
3631
|
+
for (const t of terms) {
|
|
3632
|
+
if (expectOperand) {
|
|
3633
|
+
if (!isUcumComponent(t)) return false;
|
|
3634
|
+
} else if (t !== "." && t !== "/") {
|
|
3635
|
+
return false;
|
|
3636
|
+
}
|
|
3637
|
+
expectOperand = !expectOperand;
|
|
3638
|
+
}
|
|
3639
|
+
return !expectOperand;
|
|
3640
|
+
}
|
|
3426
3641
|
var CBC_DIFF_ALIASES = {
|
|
3427
3642
|
"/ul": "/uL",
|
|
3428
3643
|
"/\xB5l": "/uL",
|
|
@@ -3724,7 +3939,7 @@ var BIOMARKER_UNITS = {
|
|
|
3724
3939
|
"miu/ml": "mIU/mL",
|
|
3725
3940
|
"ui/l": "mIU/mL"
|
|
3726
3941
|
},
|
|
3727
|
-
canonicalUcum: "
|
|
3942
|
+
canonicalUcum: "m[iU]/mL",
|
|
3728
3943
|
canonicalUnit: "mIU/mL",
|
|
3729
3944
|
siUcum: "[iU]/L",
|
|
3730
3945
|
siUnit: "IU/L"
|
|
@@ -3859,7 +4074,7 @@ var BIOMARKER_UNITS = {
|
|
|
3859
4074
|
"miu/ml": "mIU/mL",
|
|
3860
4075
|
"ui/l": "mIU/mL"
|
|
3861
4076
|
},
|
|
3862
|
-
canonicalUcum: "
|
|
4077
|
+
canonicalUcum: "m[iU]/mL",
|
|
3863
4078
|
canonicalUnit: "mIU/mL",
|
|
3864
4079
|
siUcum: "[iU]/L",
|
|
3865
4080
|
siUnit: "IU/L"
|
|
@@ -4126,7 +4341,7 @@ var BIOMARKER_UNITS = {
|
|
|
4126
4341
|
},
|
|
4127
4342
|
canonicalUcum: "u[iU]/mL",
|
|
4128
4343
|
canonicalUnit: "uIU/mL",
|
|
4129
|
-
siUcum: "
|
|
4344
|
+
siUcum: "m[iU]/L",
|
|
4130
4345
|
siUnit: "mIU/L"
|
|
4131
4346
|
},
|
|
4132
4347
|
Urea: {
|
|
@@ -4181,635 +4396,105 @@ var BIOMARKER_UNITS = {
|
|
|
4181
4396
|
function getCanonicalUnit(code) {
|
|
4182
4397
|
return BIOMARKER_UNITS[code]?.canonicalUnit ?? null;
|
|
4183
4398
|
}
|
|
4184
|
-
|
|
4185
|
-
|
|
4186
|
-
function interpretationCode(flag) {
|
|
4187
|
-
switch (flag) {
|
|
4188
|
-
case "H":
|
|
4189
|
-
return "H";
|
|
4190
|
-
// High
|
|
4191
|
-
case "L":
|
|
4192
|
-
return "L";
|
|
4193
|
-
// Low
|
|
4194
|
-
default:
|
|
4195
|
-
return "N";
|
|
4196
|
-
}
|
|
4399
|
+
function normalizeUnit(unit, config) {
|
|
4400
|
+
return config.aliases[unit.toLowerCase()] ?? config.aliases[unit] ?? unit;
|
|
4197
4401
|
}
|
|
4198
|
-
function
|
|
4199
|
-
|
|
4200
|
-
|
|
4201
|
-
|
|
4202
|
-
|
|
4203
|
-
|
|
4204
|
-
|
|
4205
|
-
return "Normal";
|
|
4402
|
+
function resolveUcum(unit, biomarkerCode) {
|
|
4403
|
+
if (!unit) return void 0;
|
|
4404
|
+
const config = biomarkerCode ? BIOMARKER_UNITS[biomarkerCode] : void 0;
|
|
4405
|
+
if (config) {
|
|
4406
|
+
const normalized = normalizeUnit(unit, config);
|
|
4407
|
+
if (normalized === config.canonicalUnit) return config.canonicalUcum;
|
|
4408
|
+
if (normalized === config.siUnit) return config.siUcum;
|
|
4206
4409
|
}
|
|
4410
|
+
const mapped = UNIT_TO_UCUM[unit];
|
|
4411
|
+
if (mapped) return mapped;
|
|
4412
|
+
return isUcumCode(unit) ? unit : void 0;
|
|
4207
4413
|
}
|
|
4208
|
-
|
|
4209
|
-
|
|
4210
|
-
|
|
4211
|
-
|
|
4212
|
-
|
|
4414
|
+
|
|
4415
|
+
// src/reference-ranges.ts
|
|
4416
|
+
var biomarkerRangeDefinitions = {
|
|
4417
|
+
Albumin_Creatinine_Ratio: {
|
|
4418
|
+
default: { max: 30, min: 0, optimalMax: 20, optimalMin: 0, unit: "mg/g" },
|
|
4419
|
+
kind: "decision-threshold",
|
|
4420
|
+
source: "tietz-7ed-2015"
|
|
4213
4421
|
},
|
|
4214
|
-
|
|
4215
|
-
}
|
|
4216
|
-
|
|
4217
|
-
|
|
4218
|
-
|
|
4219
|
-
|
|
4220
|
-
unit:
|
|
4221
|
-
|
|
4222
|
-
|
|
4223
|
-
|
|
4224
|
-
|
|
4225
|
-
|
|
4422
|
+
Adiponectin: {
|
|
4423
|
+
default: { max: 26, min: 4, optimalMax: 20, optimalMin: 8, unit: "mcg/mL" },
|
|
4424
|
+
kind: "reference-interval",
|
|
4425
|
+
source: "tietz-7ed-2015"
|
|
4426
|
+
},
|
|
4427
|
+
ADMA: {
|
|
4428
|
+
default: { max: 0.7, min: 0.3, optimalMax: 0.55, optimalMin: 0.3, unit: "umol/L" },
|
|
4429
|
+
kind: "reference-interval",
|
|
4430
|
+
source: "nemeth-adma-2017"
|
|
4431
|
+
},
|
|
4432
|
+
AFP: {
|
|
4433
|
+
default: { max: 10, min: 0, optimalMax: 8, optimalMin: 0, unit: "ng/mL" },
|
|
4434
|
+
kind: "reference-interval",
|
|
4435
|
+
source: "sturgeon-nacb-2008"
|
|
4436
|
+
},
|
|
4437
|
+
Albumin_Globulin_Ratio: {
|
|
4438
|
+
default: { max: 2.5, min: 1, optimalMax: 2.2, optimalMin: 1.2, unit: "" },
|
|
4439
|
+
kind: "reference-interval",
|
|
4440
|
+
source: "tietz-7ed-2015"
|
|
4441
|
+
},
|
|
4442
|
+
Albumin: {
|
|
4443
|
+
default: { max: 5, min: 3.5, optimalMax: 4.8, optimalMin: 4, unit: "g/dL" },
|
|
4444
|
+
kind: "reference-interval",
|
|
4445
|
+
source: "pns-bioquimica-2019"
|
|
4446
|
+
},
|
|
4447
|
+
AlkalinePhosphatase: {
|
|
4448
|
+
default: { max: 147, min: 44, optimalMax: 120, optimalMin: 50, unit: "U/L" },
|
|
4449
|
+
kind: "reference-interval",
|
|
4450
|
+
source: "tietz-7ed-2015",
|
|
4451
|
+
variants: [
|
|
4226
4452
|
{
|
|
4227
|
-
|
|
4228
|
-
|
|
4229
|
-
|
|
4230
|
-
}
|
|
4231
|
-
];
|
|
4232
|
-
};
|
|
4233
|
-
if (observation.referenceRanges && observation.referenceRanges.length > 0) {
|
|
4234
|
-
return observation.referenceRanges.flatMap((r) => toRanges(r.low, r.high, r.appliesTo));
|
|
4235
|
-
}
|
|
4236
|
-
return toRanges(observation.referenceMin, observation.referenceMax);
|
|
4237
|
-
};
|
|
4238
|
-
function labObservationToFHIR(observation, patientId, laboratoryName) {
|
|
4239
|
-
const loincCode = codeToLoinc(observation.biomarkerCode);
|
|
4240
|
-
const sourceUnit = observation.unit || getDefaultUnit(observation.biomarkerCode) || observation.unit;
|
|
4241
|
-
const ucumUnit = unitToUCUM(sourceUnit);
|
|
4242
|
-
const isQualitative = observation.isQualitative || typeof observation.value === "string";
|
|
4243
|
-
const fhirObs = {
|
|
4244
|
-
category: [
|
|
4453
|
+
ageMin: 18,
|
|
4454
|
+
range: { max: 147, min: 44, optimalMax: 120, optimalMin: 50, unit: "U/L" },
|
|
4455
|
+
sex: "M"
|
|
4456
|
+
},
|
|
4245
4457
|
{
|
|
4246
|
-
|
|
4247
|
-
|
|
4248
|
-
|
|
4249
|
-
display: "Laboratory",
|
|
4250
|
-
system: "http://terminology.hl7.org/CodeSystem/observation-category"
|
|
4251
|
-
}
|
|
4252
|
-
]
|
|
4458
|
+
ageMin: 18,
|
|
4459
|
+
range: { max: 104, min: 35, optimalMax: 90, optimalMin: 40, unit: "U/L" },
|
|
4460
|
+
sex: "F"
|
|
4253
4461
|
}
|
|
4254
|
-
]
|
|
4255
|
-
|
|
4256
|
-
|
|
4257
|
-
|
|
4258
|
-
|
|
4259
|
-
|
|
4260
|
-
|
|
4261
|
-
coding: [
|
|
4262
|
-
...loincCode ? [
|
|
4263
|
-
{
|
|
4264
|
-
code: loincCode,
|
|
4265
|
-
display: observation.biomarkerName,
|
|
4266
|
-
system: LOINC_SYSTEM
|
|
4267
|
-
}
|
|
4268
|
-
] : [],
|
|
4269
|
-
{
|
|
4270
|
-
code: observation.biomarkerCode,
|
|
4271
|
-
display: observation.biomarkerName,
|
|
4272
|
-
system: BIOMARKER_CODE_SYSTEM
|
|
4273
|
-
}
|
|
4274
|
-
],
|
|
4275
|
-
text: observation.biomarkerName
|
|
4276
|
-
},
|
|
4277
|
-
effectiveDateTime: observation.collectionDate,
|
|
4278
|
-
id: `${observation.reportId}-${observation.biomarkerCode}`,
|
|
4279
|
-
interpretation: [
|
|
4462
|
+
]
|
|
4463
|
+
},
|
|
4464
|
+
ALT: {
|
|
4465
|
+
default: { max: 35, min: 0, optimalMax: 25, optimalMin: 0, unit: "U/L" },
|
|
4466
|
+
kind: "reference-interval",
|
|
4467
|
+
source: "tietz-7ed-2015",
|
|
4468
|
+
variants: [
|
|
4280
4469
|
{
|
|
4281
|
-
|
|
4282
|
-
|
|
4283
|
-
|
|
4284
|
-
|
|
4285
|
-
system: "http://terminology.hl7.org/CodeSystem/v3-ObservationInterpretation"
|
|
4286
|
-
}
|
|
4287
|
-
]
|
|
4288
|
-
}
|
|
4289
|
-
],
|
|
4290
|
-
performer: laboratoryName ? [{ display: laboratoryName }] : void 0,
|
|
4291
|
-
resourceType: "Observation",
|
|
4292
|
-
status: "final",
|
|
4293
|
-
subject: {
|
|
4294
|
-
reference: `Patient/${patientId}`
|
|
4295
|
-
}
|
|
4296
|
-
};
|
|
4297
|
-
if (isQualitative) {
|
|
4298
|
-
fhirObs.valueString = String(observation.value);
|
|
4299
|
-
} else {
|
|
4300
|
-
fhirObs.valueQuantity = {
|
|
4301
|
-
code: ucumUnit,
|
|
4302
|
-
system: "http://unitsofmeasure.org",
|
|
4303
|
-
unit: sourceUnit,
|
|
4304
|
-
value: observation.value
|
|
4305
|
-
};
|
|
4306
|
-
const referenceRange = buildReferenceRanges(observation, sourceUnit, ucumUnit);
|
|
4307
|
-
if (referenceRange.length > 0) fhirObs.referenceRange = referenceRange;
|
|
4308
|
-
}
|
|
4309
|
-
return fhirObs;
|
|
4310
|
-
}
|
|
4311
|
-
function labReportToFHIR(report, patientId, observationIds) {
|
|
4312
|
-
let status;
|
|
4313
|
-
switch (report.processingStatus) {
|
|
4314
|
-
case "complete":
|
|
4315
|
-
status = "final";
|
|
4316
|
-
break;
|
|
4317
|
-
case "partial":
|
|
4318
|
-
status = "partial";
|
|
4319
|
-
break;
|
|
4320
|
-
case "pending_review":
|
|
4321
|
-
status = "preliminary";
|
|
4322
|
-
break;
|
|
4323
|
-
default:
|
|
4324
|
-
status = "final";
|
|
4325
|
-
}
|
|
4326
|
-
return {
|
|
4327
|
-
category: [
|
|
4470
|
+
ageMin: 18,
|
|
4471
|
+
range: { max: 56, min: 7, optimalMax: 35, optimalMin: 10, unit: "U/L" },
|
|
4472
|
+
sex: "M"
|
|
4473
|
+
},
|
|
4328
4474
|
{
|
|
4329
|
-
|
|
4330
|
-
|
|
4331
|
-
|
|
4332
|
-
display: "Laboratory",
|
|
4333
|
-
system: "http://terminology.hl7.org/CodeSystem/v2-0074"
|
|
4334
|
-
}
|
|
4335
|
-
]
|
|
4475
|
+
ageMin: 18,
|
|
4476
|
+
range: { max: 45, min: 7, optimalMax: 30, optimalMin: 10, unit: "U/L" },
|
|
4477
|
+
sex: "F"
|
|
4336
4478
|
}
|
|
4337
|
-
]
|
|
4338
|
-
|
|
4339
|
-
|
|
4340
|
-
|
|
4341
|
-
|
|
4342
|
-
|
|
4343
|
-
|
|
4344
|
-
|
|
4345
|
-
|
|
4346
|
-
|
|
4347
|
-
|
|
4348
|
-
|
|
4349
|
-
|
|
4350
|
-
conclusionCode: report.overallStatus === "ANORMAL" ? [
|
|
4479
|
+
]
|
|
4480
|
+
},
|
|
4481
|
+
// AMH — fortemente dependente de idade e sexo. As variantes femininas por
|
|
4482
|
+
// faixa etária são a referência clínica; o `default` foi ajustado para
|
|
4483
|
+
// refletir uma faixa adulta conservadora (~18-40 anos, mulheres em idade
|
|
4484
|
+
// reprodutiva geral). optimalMax anterior (6.9 ng/mL) sobrepunha-se a
|
|
4485
|
+
// valores sugestivos de SOP ou risco de OHSS; clinicamente, valores acima
|
|
4486
|
+
// de ~4 ng/mL já merecem investigação.
|
|
4487
|
+
AMH: {
|
|
4488
|
+
default: { max: 6, min: 1, optimalMax: 4, optimalMin: 1.5, unit: "ng/mL" },
|
|
4489
|
+
kind: "reference-interval",
|
|
4490
|
+
source: "tietz-7ed-2015",
|
|
4491
|
+
variants: [
|
|
4351
4492
|
{
|
|
4352
|
-
|
|
4353
|
-
|
|
4354
|
-
|
|
4355
|
-
|
|
4356
|
-
|
|
4357
|
-
}
|
|
4358
|
-
]
|
|
4359
|
-
}
|
|
4360
|
-
] : void 0,
|
|
4361
|
-
effectiveDateTime: report.collectionDate,
|
|
4362
|
-
id: report.reportId,
|
|
4363
|
-
issued: report.createdAt,
|
|
4364
|
-
performer: report.laboratoryName ? [{ display: report.laboratoryName }] : void 0,
|
|
4365
|
-
resourceType: "DiagnosticReport",
|
|
4366
|
-
result: observationIds.map((id) => ({ reference: `Observation/${id}` })),
|
|
4367
|
-
status,
|
|
4368
|
-
subject: {
|
|
4369
|
-
reference: `Patient/${patientId}`
|
|
4370
|
-
}
|
|
4371
|
-
};
|
|
4372
|
-
}
|
|
4373
|
-
function userProfileToFHIR(profile) {
|
|
4374
|
-
const nameParts = profile.name.split(" ");
|
|
4375
|
-
const given = nameParts.slice(0, -1);
|
|
4376
|
-
const family = nameParts[nameParts.length - 1] || "";
|
|
4377
|
-
return {
|
|
4378
|
-
address: profile.address ? [
|
|
4379
|
-
{
|
|
4380
|
-
city: profile.address.city,
|
|
4381
|
-
country: profile.address.country || "BR",
|
|
4382
|
-
line: [
|
|
4383
|
-
profile.address.street && profile.address.number ? `${profile.address.street}, ${profile.address.number}` : profile.address.street,
|
|
4384
|
-
profile.address.complement
|
|
4385
|
-
].filter(Boolean),
|
|
4386
|
-
postalCode: profile.address.postalCode,
|
|
4387
|
-
state: profile.address.state
|
|
4388
|
-
}
|
|
4389
|
-
] : void 0,
|
|
4390
|
-
birthDate: profile.birthDate,
|
|
4391
|
-
gender: profile.gender,
|
|
4392
|
-
id: profile.userId,
|
|
4393
|
-
name: [
|
|
4394
|
-
{
|
|
4395
|
-
family,
|
|
4396
|
-
given: given.length > 0 ? given : void 0,
|
|
4397
|
-
text: profile.name
|
|
4398
|
-
}
|
|
4399
|
-
],
|
|
4400
|
-
resourceType: "Patient",
|
|
4401
|
-
telecom: [
|
|
4402
|
-
...profile.email ? [{ system: "email", value: profile.email }] : [],
|
|
4403
|
-
...profile.phone ? [{ system: "phone", value: profile.phone }] : []
|
|
4404
|
-
].length > 0 ? [
|
|
4405
|
-
...profile.email ? [{ system: "email", value: profile.email }] : [],
|
|
4406
|
-
...profile.phone ? [{ system: "phone", value: profile.phone }] : []
|
|
4407
|
-
] : void 0
|
|
4408
|
-
};
|
|
4409
|
-
}
|
|
4410
|
-
function labResultToFHIRBundle(report, observations, userProfile) {
|
|
4411
|
-
const patientId = userProfile.userId;
|
|
4412
|
-
const fhirObservations = observations.map((obs) => {
|
|
4413
|
-
const resource = labObservationToFHIR(
|
|
4414
|
-
{ ...obs, collectionDate: report.collectionDate },
|
|
4415
|
-
patientId,
|
|
4416
|
-
report.laboratoryName
|
|
4417
|
-
);
|
|
4418
|
-
return { fullUrl: entryFullUrl(resource), resource };
|
|
4419
|
-
});
|
|
4420
|
-
const observationIds = fhirObservations.map((entry) => entry.resource.id);
|
|
4421
|
-
const diagnosticReport = labReportToFHIR(report, patientId, observationIds);
|
|
4422
|
-
const fhirPatient = userProfileToFHIR(userProfile);
|
|
4423
|
-
return {
|
|
4424
|
-
entry: [
|
|
4425
|
-
{ fullUrl: entryFullUrl(fhirPatient), resource: fhirPatient },
|
|
4426
|
-
{ fullUrl: entryFullUrl(diagnosticReport), resource: diagnosticReport },
|
|
4427
|
-
...fhirObservations
|
|
4428
|
-
],
|
|
4429
|
-
resourceType: "Bundle",
|
|
4430
|
-
type: "collection"
|
|
4431
|
-
};
|
|
4432
|
-
}
|
|
4433
|
-
|
|
4434
|
-
// src/cli/commands/convert.ts
|
|
4435
|
-
async function convert(args, json) {
|
|
4436
|
-
const raw = await getInput(args[0]);
|
|
4437
|
-
const data = parseJson(
|
|
4438
|
-
raw,
|
|
4439
|
-
"JSON inv\xE1lido. Forne\xE7a um objeto com { report, observations, profile }."
|
|
4440
|
-
);
|
|
4441
|
-
if (!data.report || !data.observations || !data.profile) {
|
|
4442
|
-
exitWithError(
|
|
4443
|
-
'Formato esperado: { "report": LabReportData, "observations": LabObservationData[], "profile": UserProfileData }'
|
|
4444
|
-
);
|
|
4445
|
-
}
|
|
4446
|
-
const bundle = labResultToFHIRBundle(data.report, data.observations, data.profile);
|
|
4447
|
-
if (json) {
|
|
4448
|
-
outputJson(bundle);
|
|
4449
|
-
} else {
|
|
4450
|
-
outputText(JSON.stringify(bundle, null, 2));
|
|
4451
|
-
}
|
|
4452
|
-
}
|
|
4453
|
-
|
|
4454
|
-
// src/validators.ts
|
|
4455
|
-
function validateFHIRImportBundle(data) {
|
|
4456
|
-
const errors = [];
|
|
4457
|
-
if (!data || typeof data !== "object") {
|
|
4458
|
-
errors.push({ details: "Input must be a JSON object", field: "root" });
|
|
4459
|
-
return errors;
|
|
4460
|
-
}
|
|
4461
|
-
const bundle = data;
|
|
4462
|
-
if (bundle.resourceType !== "Bundle") {
|
|
4463
|
-
errors.push({
|
|
4464
|
-
details: `Expected resourceType "Bundle", got "${String(bundle.resourceType)}"`,
|
|
4465
|
-
field: "resourceType"
|
|
4466
|
-
});
|
|
4467
|
-
}
|
|
4468
|
-
if (!Array.isArray(bundle.entry)) {
|
|
4469
|
-
errors.push({ details: 'Bundle must contain an "entry" array', field: "entry" });
|
|
4470
|
-
} else if (bundle.entry.length === 0) {
|
|
4471
|
-
errors.push({ details: "Bundle entry array is empty", field: "entry" });
|
|
4472
|
-
}
|
|
4473
|
-
return errors;
|
|
4474
|
-
}
|
|
4475
|
-
|
|
4476
|
-
// src/importer.ts
|
|
4477
|
-
var MAX_OBSERVATIONS = 5e3;
|
|
4478
|
-
var MAX_FILE_SIZE = 15 * 1024 * 1024;
|
|
4479
|
-
function resolveBiomarkerCode(observation) {
|
|
4480
|
-
const coding = observation.code?.coding ?? [];
|
|
4481
|
-
const loincCode = coding.find((c) => c.system === LOINC_SYSTEM)?.code;
|
|
4482
|
-
const declaredCode = coding.find((c) => c.system === BIOMARKER_CODE_SYSTEM)?.code;
|
|
4483
|
-
const seenCodes = [
|
|
4484
|
-
...loincCode ? [`LOINC ${loincCode}`] : [],
|
|
4485
|
-
...declaredCode ? [`biomarker code ${declaredCode}`] : []
|
|
4486
|
-
];
|
|
4487
|
-
let reason;
|
|
4488
|
-
if (seenCodes.length > 0) {
|
|
4489
|
-
reason = `Unknown code: ${seenCodes.join(", ")}`;
|
|
4490
|
-
} else if (coding.length > 0) {
|
|
4491
|
-
const systems = [...new Set(coding.map((c) => c.system ?? "(sem system)"))];
|
|
4492
|
-
reason = `No code in a supported system (found: ${systems.join(", ")})`;
|
|
4493
|
-
} else {
|
|
4494
|
-
reason = "No code found in observation coding";
|
|
4495
|
-
}
|
|
4496
|
-
const fromLoinc = loincCode ? loincToCode(loincCode) : void 0;
|
|
4497
|
-
if (fromLoinc) return { internalCode: fromLoinc, loincCode, reason };
|
|
4498
|
-
if (declaredCode && isValidCode(declaredCode)) {
|
|
4499
|
-
const canonical = normalizeCode(declaredCode);
|
|
4500
|
-
return { internalCode: canonical, loincCode: codeToLoinc(canonical), reason };
|
|
4501
|
-
}
|
|
4502
|
-
return { loincCode, reason };
|
|
4503
|
-
}
|
|
4504
|
-
function extractFlag(observation) {
|
|
4505
|
-
const code = observation.interpretation?.[0]?.coding?.[0]?.code;
|
|
4506
|
-
if (code === "H" || code === "HH") return "H";
|
|
4507
|
-
if (code === "L" || code === "LL") return "L";
|
|
4508
|
-
return "";
|
|
4509
|
-
}
|
|
4510
|
-
function extractObservationsFromBundle(bundle) {
|
|
4511
|
-
const observations = [];
|
|
4512
|
-
const skipped = [];
|
|
4513
|
-
for (let i = 0; i < bundle.entry.length; i++) {
|
|
4514
|
-
const entry = bundle.entry[i];
|
|
4515
|
-
if (!entry.resource) {
|
|
4516
|
-
skipped.push({ index: i, reason: "Entry has no resource" });
|
|
4517
|
-
continue;
|
|
4518
|
-
}
|
|
4519
|
-
if (entry.resource.resourceType !== "Observation") {
|
|
4520
|
-
continue;
|
|
4521
|
-
}
|
|
4522
|
-
if (observations.length >= MAX_OBSERVATIONS) {
|
|
4523
|
-
skipped.push({ index: i, reason: `Maximum of ${MAX_OBSERVATIONS} observations exceeded` });
|
|
4524
|
-
continue;
|
|
4525
|
-
}
|
|
4526
|
-
observations.push(entry.resource);
|
|
4527
|
-
}
|
|
4528
|
-
return { observations, skipped };
|
|
4529
|
-
}
|
|
4530
|
-
function mapFHIRObservationToInternal(observation, index) {
|
|
4531
|
-
const { internalCode, loincCode, reason } = resolveBiomarkerCode(observation);
|
|
4532
|
-
if (!internalCode) {
|
|
4533
|
-
return {
|
|
4534
|
-
skipped: { index, loincCode, reason, resourceType: "Observation" }
|
|
4535
|
-
};
|
|
4536
|
-
}
|
|
4537
|
-
const definition = getDefinitionByCode(internalCode);
|
|
4538
|
-
let value;
|
|
4539
|
-
let unit = "";
|
|
4540
|
-
let isQualitative = false;
|
|
4541
|
-
if (observation.valueQuantity?.value !== void 0) {
|
|
4542
|
-
value = observation.valueQuantity.value;
|
|
4543
|
-
unit = observation.valueQuantity.unit || observation.valueQuantity.code || "";
|
|
4544
|
-
} else if (observation.valueString) {
|
|
4545
|
-
value = observation.valueString;
|
|
4546
|
-
isQualitative = true;
|
|
4547
|
-
} else {
|
|
4548
|
-
return {
|
|
4549
|
-
skipped: {
|
|
4550
|
-
index,
|
|
4551
|
-
loincCode,
|
|
4552
|
-
reason: "Observation has no value (valueQuantity or valueString)",
|
|
4553
|
-
resourceType: "Observation"
|
|
4554
|
-
}
|
|
4555
|
-
};
|
|
4556
|
-
}
|
|
4557
|
-
const collectionDate = observation.effectiveDateTime || observation.effectivePeriod?.start || "";
|
|
4558
|
-
if (!collectionDate) {
|
|
4559
|
-
return {
|
|
4560
|
-
skipped: {
|
|
4561
|
-
index,
|
|
4562
|
-
loincCode,
|
|
4563
|
-
reason: "Observation has no effectiveDateTime or effectivePeriod.start",
|
|
4564
|
-
resourceType: "Observation"
|
|
4565
|
-
}
|
|
4566
|
-
};
|
|
4567
|
-
}
|
|
4568
|
-
let referenceMin;
|
|
4569
|
-
let referenceMax;
|
|
4570
|
-
if (observation.referenceRange?.[0]) {
|
|
4571
|
-
referenceMin = observation.referenceRange[0].low?.value;
|
|
4572
|
-
referenceMax = observation.referenceRange[0].high?.value;
|
|
4573
|
-
}
|
|
4574
|
-
const imported = {
|
|
4575
|
-
biomarkerCode: internalCode,
|
|
4576
|
-
biomarkerName: definition?.names.pt[0] || definition?.names.en[0] || observation.code.text || internalCode,
|
|
4577
|
-
collectionDate,
|
|
4578
|
-
flag: extractFlag(observation),
|
|
4579
|
-
isQualitative,
|
|
4580
|
-
loincCode,
|
|
4581
|
-
referenceMax,
|
|
4582
|
-
referenceMin,
|
|
4583
|
-
unit: unit || definition?.unit || "",
|
|
4584
|
-
value
|
|
4585
|
-
};
|
|
4586
|
-
return { observation: imported };
|
|
4587
|
-
}
|
|
4588
|
-
function processImportBundle(data) {
|
|
4589
|
-
const validationErrors = validateFHIRImportBundle(data);
|
|
4590
|
-
if (validationErrors.length > 0) {
|
|
4591
|
-
return {
|
|
4592
|
-
errors: validationErrors,
|
|
4593
|
-
imported: [],
|
|
4594
|
-
skipped: [],
|
|
4595
|
-
totalProcessed: 0
|
|
4596
|
-
};
|
|
4597
|
-
}
|
|
4598
|
-
const bundle = data;
|
|
4599
|
-
const { observations, skipped } = extractObservationsFromBundle(bundle);
|
|
4600
|
-
const imported = [];
|
|
4601
|
-
const allSkipped = [...skipped];
|
|
4602
|
-
for (let i = 0; i < observations.length; i++) {
|
|
4603
|
-
const result = mapFHIRObservationToInternal(observations[i], i);
|
|
4604
|
-
if ("observation" in result) {
|
|
4605
|
-
imported.push(result.observation);
|
|
4606
|
-
} else {
|
|
4607
|
-
allSkipped.push(result.skipped);
|
|
4608
|
-
}
|
|
4609
|
-
}
|
|
4610
|
-
return {
|
|
4611
|
-
errors: [],
|
|
4612
|
-
imported,
|
|
4613
|
-
skipped: allSkipped,
|
|
4614
|
-
totalProcessed: observations.length
|
|
4615
|
-
};
|
|
4616
|
-
}
|
|
4617
|
-
|
|
4618
|
-
// src/cli/commands/import.ts
|
|
4619
|
-
async function importBundle(args, json) {
|
|
4620
|
-
const raw = await getInput(args[0]);
|
|
4621
|
-
const bundle = parseJson(raw, "JSON inv\xE1lido.");
|
|
4622
|
-
const result = processImportBundle(bundle);
|
|
4623
|
-
if (json) {
|
|
4624
|
-
outputJson(result);
|
|
4625
|
-
return;
|
|
4626
|
-
}
|
|
4627
|
-
outputText(`Processados: ${result.totalProcessed}`);
|
|
4628
|
-
outputText(`Importados: ${result.imported.length}`);
|
|
4629
|
-
outputText(`Ignorados: ${result.skipped.length}`);
|
|
4630
|
-
outputText(`Erros: ${result.errors.length}`);
|
|
4631
|
-
if (result.imported.length > 0) {
|
|
4632
|
-
outputText("\nObserva\xE7\xF5es importadas:");
|
|
4633
|
-
for (const obs of result.imported) {
|
|
4634
|
-
outputText(` ${obs.biomarkerCode} (${obs.loincCode}): ${obs.value} ${obs.unit}`);
|
|
4635
|
-
}
|
|
4636
|
-
}
|
|
4637
|
-
if (result.errors.length > 0) {
|
|
4638
|
-
outputText("\nErros:");
|
|
4639
|
-
for (const err of result.errors) {
|
|
4640
|
-
outputText(` ${err.field}: ${err.details}`);
|
|
4641
|
-
}
|
|
4642
|
-
}
|
|
4643
|
-
}
|
|
4644
|
-
|
|
4645
|
-
// src/cli/commands/list.ts
|
|
4646
|
-
import { parseArgs } from "util";
|
|
4647
|
-
async function list(args, json) {
|
|
4648
|
-
const { values } = parseArgs({
|
|
4649
|
-
args,
|
|
4650
|
-
options: {
|
|
4651
|
-
category: { type: "string" },
|
|
4652
|
-
visible: { default: false, type: "boolean" }
|
|
4653
|
-
},
|
|
4654
|
-
strict: false
|
|
4655
|
-
});
|
|
4656
|
-
let defs;
|
|
4657
|
-
if (values.category) {
|
|
4658
|
-
defs = getBiomarkersByCategory(values.category);
|
|
4659
|
-
if (defs.length === 0) {
|
|
4660
|
-
exitWithError(`Categoria n\xE3o encontrada ou vazia: ${values.category}`);
|
|
4661
|
-
}
|
|
4662
|
-
} else if (values.visible) {
|
|
4663
|
-
defs = getVisibleDefinitions();
|
|
4664
|
-
} else {
|
|
4665
|
-
defs = getAllDefinitions();
|
|
4666
|
-
}
|
|
4667
|
-
if (json) {
|
|
4668
|
-
outputJson(defs);
|
|
4669
|
-
return;
|
|
4670
|
-
}
|
|
4671
|
-
const rows = defs.map((d) => [
|
|
4672
|
-
d.code,
|
|
4673
|
-
d.loinc ?? "\u2014",
|
|
4674
|
-
d.names.pt[0] ?? "",
|
|
4675
|
-
d.unit ?? "\u2014",
|
|
4676
|
-
Array.isArray(d.category) ? d.category.join(", ") : d.category
|
|
4677
|
-
]);
|
|
4678
|
-
outputText(formatTable(["C\xF3digo", "LOINC", "Nome (pt)", "Unidade", "Categoria"], rows));
|
|
4679
|
-
outputText(`
|
|
4680
|
-
Total: ${defs.length} biomarcadores`);
|
|
4681
|
-
}
|
|
4682
|
-
|
|
4683
|
-
// src/cli/commands/loinc-map.ts
|
|
4684
|
-
async function loincMap(_args, json) {
|
|
4685
|
-
const defs = getAllDefinitions().filter((d) => d.loinc);
|
|
4686
|
-
if (json) {
|
|
4687
|
-
const map = Object.fromEntries(defs.map((d) => [d.loinc, d.code]));
|
|
4688
|
-
outputJson(map);
|
|
4689
|
-
return;
|
|
4690
|
-
}
|
|
4691
|
-
const rows = defs.map((d) => [d.loinc, d.code, d.names.pt[0] ?? d.names.en[0] ?? ""]);
|
|
4692
|
-
outputText(formatTable(["LOINC", "C\xF3digo", "Nome (pt)"], rows));
|
|
4693
|
-
outputText(`
|
|
4694
|
-
Total: ${rows.length} mapeamentos`);
|
|
4695
|
-
}
|
|
4696
|
-
|
|
4697
|
-
// src/cli/commands/lookup.ts
|
|
4698
|
-
function displayDefinition(def) {
|
|
4699
|
-
const cat = Array.isArray(def.category) ? def.category.join(", ") : def.category;
|
|
4700
|
-
outputText(
|
|
4701
|
-
[
|
|
4702
|
-
`Biomarcador: ${def.code}`,
|
|
4703
|
-
` LOINC: ${def.loinc ?? "\u2014"}`,
|
|
4704
|
-
` Nomes (pt): ${def.names.pt.join(", ")}`,
|
|
4705
|
-
` Nomes (en): ${def.names.en.join(", ")}`,
|
|
4706
|
-
` Categoria: ${cat}`,
|
|
4707
|
-
` Unidade: ${def.unit ?? "\u2014"}`,
|
|
4708
|
-
` Sexo: ${def.sex ?? "ambos"}`,
|
|
4709
|
-
` Vis\xEDvel: ${def.hidden ? "n\xE3o" : "sim"}`
|
|
4710
|
-
].join("\n")
|
|
4711
|
-
);
|
|
4712
|
-
}
|
|
4713
|
-
async function lookup(args, json) {
|
|
4714
|
-
const code = args[0];
|
|
4715
|
-
if (!code) exitWithError("Uso: fhir-bio lookup <c\xF3digo>");
|
|
4716
|
-
const def = getDefinitionByCode(code);
|
|
4717
|
-
if (!def) exitWithError(`Biomarcador n\xE3o encontrado: ${code}`);
|
|
4718
|
-
if (json) {
|
|
4719
|
-
outputJson(def);
|
|
4720
|
-
} else {
|
|
4721
|
-
displayDefinition(def);
|
|
4722
|
-
}
|
|
4723
|
-
}
|
|
4724
|
-
async function lookupLoinc(args, json) {
|
|
4725
|
-
const loinc = args[0];
|
|
4726
|
-
if (!loinc) exitWithError("Uso: fhir-bio lookup-loinc <loinc>");
|
|
4727
|
-
const def = getDefinitionByLoinc(loinc);
|
|
4728
|
-
if (!def) exitWithError(`Biomarcador n\xE3o encontrado para LOINC: ${loinc}`);
|
|
4729
|
-
if (json) {
|
|
4730
|
-
outputJson(def);
|
|
4731
|
-
} else {
|
|
4732
|
-
displayDefinition(def);
|
|
4733
|
-
}
|
|
4734
|
-
}
|
|
4735
|
-
|
|
4736
|
-
// src/cli/commands/range.ts
|
|
4737
|
-
import { parseArgs as parseArgs2 } from "util";
|
|
4738
|
-
|
|
4739
|
-
// src/reference-ranges.ts
|
|
4740
|
-
var biomarkerRangeDefinitions = {
|
|
4741
|
-
Albumin_Creatinine_Ratio: {
|
|
4742
|
-
default: { max: 30, min: 0, optimalMax: 20, optimalMin: 0, unit: "mg/g" },
|
|
4743
|
-
source: "tietz-7ed-2015"
|
|
4744
|
-
},
|
|
4745
|
-
Adiponectin: {
|
|
4746
|
-
default: { max: 26, min: 4, optimalMax: 20, optimalMin: 8, unit: "mcg/mL" },
|
|
4747
|
-
source: "tietz-7ed-2015"
|
|
4748
|
-
},
|
|
4749
|
-
ADMA: {
|
|
4750
|
-
default: { max: 0.7, min: 0.3, optimalMax: 0.55, optimalMin: 0.3, unit: "umol/L" },
|
|
4751
|
-
source: "nemeth-adma-2017"
|
|
4752
|
-
},
|
|
4753
|
-
AFP: {
|
|
4754
|
-
default: { max: 10, min: 0, optimalMax: 8, optimalMin: 0, unit: "ng/mL" },
|
|
4755
|
-
source: "sturgeon-nacb-2008"
|
|
4756
|
-
},
|
|
4757
|
-
Albumin_Globulin_Ratio: {
|
|
4758
|
-
default: { max: 2.5, min: 1, optimalMax: 2.2, optimalMin: 1.2, unit: "" },
|
|
4759
|
-
source: "tietz-7ed-2015"
|
|
4760
|
-
},
|
|
4761
|
-
Albumin: {
|
|
4762
|
-
default: { max: 5, min: 3.5, optimalMax: 4.8, optimalMin: 4, unit: "g/dL" },
|
|
4763
|
-
source: "pns-bioquimica-2019"
|
|
4764
|
-
},
|
|
4765
|
-
AlkalinePhosphatase: {
|
|
4766
|
-
default: { max: 147, min: 44, optimalMax: 120, optimalMin: 50, unit: "U/L" },
|
|
4767
|
-
source: "tietz-7ed-2015",
|
|
4768
|
-
variants: [
|
|
4769
|
-
{
|
|
4770
|
-
ageMin: 18,
|
|
4771
|
-
range: { max: 147, min: 44, optimalMax: 120, optimalMin: 50, unit: "U/L" },
|
|
4772
|
-
sex: "M"
|
|
4773
|
-
},
|
|
4774
|
-
{
|
|
4775
|
-
ageMin: 18,
|
|
4776
|
-
range: { max: 104, min: 35, optimalMax: 90, optimalMin: 40, unit: "U/L" },
|
|
4777
|
-
sex: "F"
|
|
4778
|
-
}
|
|
4779
|
-
]
|
|
4780
|
-
},
|
|
4781
|
-
ALT: {
|
|
4782
|
-
default: { max: 35, min: 0, optimalMax: 25, optimalMin: 0, unit: "U/L" },
|
|
4783
|
-
source: "tietz-7ed-2015",
|
|
4784
|
-
variants: [
|
|
4785
|
-
{
|
|
4786
|
-
ageMin: 18,
|
|
4787
|
-
range: { max: 56, min: 7, optimalMax: 35, optimalMin: 10, unit: "U/L" },
|
|
4788
|
-
sex: "M"
|
|
4789
|
-
},
|
|
4790
|
-
{
|
|
4791
|
-
ageMin: 18,
|
|
4792
|
-
range: { max: 45, min: 7, optimalMax: 30, optimalMin: 10, unit: "U/L" },
|
|
4793
|
-
sex: "F"
|
|
4794
|
-
}
|
|
4795
|
-
]
|
|
4796
|
-
},
|
|
4797
|
-
// AMH — fortemente dependente de idade e sexo. As variantes femininas por
|
|
4798
|
-
// faixa etária são a referência clínica; o `default` foi ajustado para
|
|
4799
|
-
// refletir uma faixa adulta conservadora (~18-40 anos, mulheres em idade
|
|
4800
|
-
// reprodutiva geral). optimalMax anterior (6.9 ng/mL) sobrepunha-se a
|
|
4801
|
-
// valores sugestivos de SOP ou risco de OHSS; clinicamente, valores acima
|
|
4802
|
-
// de ~4 ng/mL já merecem investigação.
|
|
4803
|
-
AMH: {
|
|
4804
|
-
default: { max: 6, min: 1, optimalMax: 4, optimalMin: 1.5, unit: "ng/mL" },
|
|
4805
|
-
source: "tietz-7ed-2015",
|
|
4806
|
-
variants: [
|
|
4807
|
-
{
|
|
4808
|
-
ageMax: 24,
|
|
4809
|
-
ageMin: 18,
|
|
4810
|
-
range: { max: 13, min: 1.5, optimalMax: 10, optimalMin: 3, unit: "ng/mL" },
|
|
4811
|
-
sex: "F"
|
|
4812
|
-
},
|
|
4493
|
+
ageMax: 24,
|
|
4494
|
+
ageMin: 18,
|
|
4495
|
+
range: { max: 13, min: 1.5, optimalMax: 10, optimalMin: 3, unit: "ng/mL" },
|
|
4496
|
+
sex: "F"
|
|
4497
|
+
},
|
|
4813
4498
|
{
|
|
4814
4499
|
ageMax: 30,
|
|
4815
4500
|
ageMin: 25,
|
|
@@ -4837,14 +4522,17 @@ var biomarkerRangeDefinitions = {
|
|
|
4837
4522
|
},
|
|
4838
4523
|
Ammonia: {
|
|
4839
4524
|
default: { max: 45, min: 15, optimalMax: 40, optimalMin: 20, unit: "umol/L" },
|
|
4525
|
+
kind: "reference-interval",
|
|
4840
4526
|
source: "tietz-7ed-2015"
|
|
4841
4527
|
},
|
|
4842
4528
|
AntiThyroglobulin: {
|
|
4843
4529
|
default: { max: 115, min: 0, optimalMax: 40, optimalMin: 0, unit: "IU/mL" },
|
|
4530
|
+
kind: "reference-interval",
|
|
4844
4531
|
source: "tietz-7ed-2015"
|
|
4845
4532
|
},
|
|
4846
4533
|
AntiTPO: {
|
|
4847
4534
|
default: { max: 34, min: 0, optimalMax: 9, optimalMin: 0, unit: "IU/mL" },
|
|
4535
|
+
kind: "reference-interval",
|
|
4848
4536
|
source: "tietz-7ed-2015"
|
|
4849
4537
|
},
|
|
4850
4538
|
// Aortic valve calcium — no standardized clinical threshold; use mild cutoff
|
|
@@ -4852,23 +4540,28 @@ var biomarkerRangeDefinitions = {
|
|
|
4852
4540
|
AorticValveCalcium: {
|
|
4853
4541
|
default: { max: 99, min: 0, optimalMax: 0, optimalMin: 0, unit: "AU" },
|
|
4854
4542
|
direction: "lower-better",
|
|
4543
|
+
kind: "decision-threshold",
|
|
4855
4544
|
source: "rumberger-cac-1999"
|
|
4856
4545
|
},
|
|
4857
4546
|
ApoA1: {
|
|
4858
4547
|
default: { max: 200, min: 100, optimalMax: 180, optimalMin: 120, unit: "mg/dL" },
|
|
4548
|
+
kind: "reference-interval",
|
|
4859
4549
|
source: "contois-apoa1-1996"
|
|
4860
4550
|
},
|
|
4861
4551
|
ApoB: {
|
|
4862
4552
|
default: { max: 90, min: 0, optimalMax: 70, optimalMin: 0, unit: "mg/dL" },
|
|
4863
4553
|
direction: "lower-better",
|
|
4554
|
+
kind: "decision-threshold",
|
|
4864
4555
|
source: "sbc-lipids-2025"
|
|
4865
4556
|
},
|
|
4866
4557
|
ApoCIII: {
|
|
4867
4558
|
default: { max: 10, min: 0, optimalMax: 7, optimalMin: 0, unit: "mg/dL" },
|
|
4559
|
+
kind: "decision-threshold",
|
|
4868
4560
|
source: "khetarpal-apociii-2016"
|
|
4869
4561
|
},
|
|
4870
4562
|
Omega6_AA: {
|
|
4871
4563
|
default: { max: 15, min: 5, optimalMax: 12, optimalMin: 7, unit: "%" },
|
|
4564
|
+
kind: "decision-threshold",
|
|
4872
4565
|
source: "simopoulos-omega-ratio-2002"
|
|
4873
4566
|
},
|
|
4874
4567
|
// Razão Ácido Araquidônico/EPA (sangue total) — `lower-better`: razão menor =
|
|
@@ -4881,16 +4574,19 @@ var biomarkerRangeDefinitions = {
|
|
|
4881
4574
|
// dentro do intervalo. Sem `optimal*`: não há corte ótimo de AA/EPA com fonte.
|
|
4882
4575
|
// Em telas de relatório único, prefira o intervalo impresso pelo laboratório.
|
|
4883
4576
|
AA_EPA_Ratio: {
|
|
4884
|
-
default: { max: 40.7, min: 3.7, unit: "" },
|
|
4577
|
+
default: { max: 40.7, min: 3.7, minKind: "display", unit: "" },
|
|
4885
4578
|
direction: "lower-better",
|
|
4579
|
+
kind: "population",
|
|
4886
4580
|
source: "torrissen-omega3-dbs-2025"
|
|
4887
4581
|
},
|
|
4888
4582
|
Arsenic: {
|
|
4889
4583
|
default: { max: 35, min: 0, optimalMax: 20, optimalMin: 0, unit: "mcg/L" },
|
|
4584
|
+
kind: "decision-threshold",
|
|
4890
4585
|
source: "nr7-pcmso-2020"
|
|
4891
4586
|
},
|
|
4892
4587
|
AST: {
|
|
4893
4588
|
default: { max: 35, min: 0, optimalMax: 25, optimalMin: 0, unit: "U/L" },
|
|
4589
|
+
kind: "reference-interval",
|
|
4894
4590
|
source: "tietz-7ed-2015",
|
|
4895
4591
|
variants: [
|
|
4896
4592
|
{
|
|
@@ -4909,6 +4605,7 @@ var biomarkerRangeDefinitions = {
|
|
|
4909
4605
|
// Tabela 2 da PNS 2019. Ver o comentário em `Neutrophils_Abs`.
|
|
4910
4606
|
Basophils_Abs: {
|
|
4911
4607
|
default: { max: 0.072, min: 0, unit: "K/uL" },
|
|
4608
|
+
kind: "reference-interval",
|
|
4912
4609
|
source: "pns-hemograma-2019",
|
|
4913
4610
|
variants: [
|
|
4914
4611
|
{ ageMin: 18, range: { max: 0.062, min: 0, unit: "K/uL" }, sex: "M" },
|
|
@@ -4917,6 +4614,7 @@ var biomarkerRangeDefinitions = {
|
|
|
4917
4614
|
},
|
|
4918
4615
|
Bicarbonate: {
|
|
4919
4616
|
default: { max: 29, min: 23, optimalMax: 28, optimalMin: 24, unit: "mEq/L" },
|
|
4617
|
+
kind: "reference-interval",
|
|
4920
4618
|
source: "tietz-7ed-2015"
|
|
4921
4619
|
},
|
|
4922
4620
|
// β-Hidroxibutirato (BHB) sérico — corpos cetônicos. Faixa derivada de
|
|
@@ -4926,23 +4624,28 @@ var biomarkerRangeDefinitions = {
|
|
|
4926
4624
|
// superior aqui reflete estado pós-prandial habitual, não jejum.
|
|
4927
4625
|
BetaHydroxybutyrate: {
|
|
4928
4626
|
default: { max: 0.28, min: 0.02, optimalMax: 0.28, optimalMin: 0.02, unit: "mmol/L" },
|
|
4627
|
+
kind: "reference-interval",
|
|
4929
4628
|
source: "klee-bhb-2020"
|
|
4930
4629
|
},
|
|
4931
4630
|
BilirubinDirect: {
|
|
4932
4631
|
default: { max: 0.3, min: 0, optimalMax: 0.2, optimalMin: 0, unit: "mg/dL" },
|
|
4632
|
+
kind: "reference-interval",
|
|
4933
4633
|
source: "tietz-7ed-2015"
|
|
4934
4634
|
},
|
|
4935
4635
|
BilirubinIndirect: {
|
|
4936
4636
|
default: { max: 0.8, min: 0, optimalMax: 0.6, optimalMin: 0, unit: "mg/dL" },
|
|
4637
|
+
kind: "reference-interval",
|
|
4937
4638
|
source: "tietz-7ed-2015"
|
|
4938
4639
|
},
|
|
4939
4640
|
BilirubinTotal: {
|
|
4940
4641
|
default: { max: 1.2, min: 0.1, optimalMax: 0.9, optimalMin: 0.2, unit: "mg/dL" },
|
|
4642
|
+
kind: "reference-interval",
|
|
4941
4643
|
source: "tietz-7ed-2015"
|
|
4942
4644
|
},
|
|
4943
4645
|
// BNP: 35 pg/mL = corte não-agudo para triagem de IC (SBC IC 2018)
|
|
4944
4646
|
BNP: {
|
|
4945
4647
|
default: { max: 35, min: 0, optimalMax: 20, optimalMin: 0, unit: "pg/mL" },
|
|
4648
|
+
kind: "decision-threshold",
|
|
4946
4649
|
source: "sbc-ic-2018"
|
|
4947
4650
|
},
|
|
4948
4651
|
// Razão BUN/Creatinina — faixa 10-20 aplica-se ao Nitrogênio Ureico (BUN).
|
|
@@ -4953,14 +4656,17 @@ var biomarkerRangeDefinitions = {
|
|
|
4953
4656
|
// distinta. Ver issue #41 para alinhamento de nomenclatura/LOINC.
|
|
4954
4657
|
BUN_Creatinine_Ratio: {
|
|
4955
4658
|
default: { max: 20, min: 10, optimalMax: 18, optimalMin: 12, unit: "" },
|
|
4659
|
+
kind: "reference-interval",
|
|
4956
4660
|
source: "tietz-7ed-2015"
|
|
4957
4661
|
},
|
|
4958
4662
|
CA125: {
|
|
4959
4663
|
default: { max: 35, min: 0, optimalMax: 25, optimalMin: 0, unit: "U/mL" },
|
|
4664
|
+
kind: "reference-interval",
|
|
4960
4665
|
source: "sturgeon-nacb-2008"
|
|
4961
4666
|
},
|
|
4962
4667
|
CA199: {
|
|
4963
4668
|
default: { max: 37, min: 0, optimalMax: 30, optimalMin: 0, unit: "U/mL" },
|
|
4669
|
+
kind: "reference-interval",
|
|
4964
4670
|
source: "sturgeon-nacb-2008"
|
|
4965
4671
|
},
|
|
4966
4672
|
// CAC: Agatston classification — 0=none, 1-99=mild, 100-399=moderate, 400+=severe
|
|
@@ -4968,44 +4674,53 @@ var biomarkerRangeDefinitions = {
|
|
|
4968
4674
|
CAC: {
|
|
4969
4675
|
default: { max: 99, min: 0, optimalMax: 0, optimalMin: 0, unit: "AU" },
|
|
4970
4676
|
direction: "lower-better",
|
|
4677
|
+
kind: "decision-threshold",
|
|
4971
4678
|
source: "rumberger-cac-1999"
|
|
4972
4679
|
},
|
|
4973
4680
|
// Per-vessel scores — same Agatston classification applied per vessel
|
|
4974
4681
|
CAC_LAD: {
|
|
4975
4682
|
default: { max: 99, min: 0, optimalMax: 0, optimalMin: 0, unit: "AU" },
|
|
4976
4683
|
direction: "lower-better",
|
|
4684
|
+
kind: "decision-threshold",
|
|
4977
4685
|
source: "rumberger-cac-1999"
|
|
4978
4686
|
},
|
|
4979
4687
|
CAC_LCX: {
|
|
4980
4688
|
default: { max: 99, min: 0, optimalMax: 0, optimalMin: 0, unit: "AU" },
|
|
4981
4689
|
direction: "lower-better",
|
|
4690
|
+
kind: "decision-threshold",
|
|
4982
4691
|
source: "rumberger-cac-1999"
|
|
4983
4692
|
},
|
|
4984
4693
|
CAC_LMA: {
|
|
4985
4694
|
default: { max: 99, min: 0, optimalMax: 0, optimalMin: 0, unit: "AU" },
|
|
4986
4695
|
direction: "lower-better",
|
|
4696
|
+
kind: "decision-threshold",
|
|
4987
4697
|
source: "rumberger-cac-1999"
|
|
4988
4698
|
},
|
|
4989
4699
|
CAC_Percentile: {
|
|
4990
4700
|
default: { max: 50, min: 0, optimalMax: 25, optimalMin: 0, unit: "%", warningMax: 75 },
|
|
4991
4701
|
direction: "lower-better",
|
|
4702
|
+
kind: "decision-threshold",
|
|
4992
4703
|
source: "rumberger-cac-1999"
|
|
4993
4704
|
},
|
|
4994
4705
|
CAC_RCA: {
|
|
4995
4706
|
default: { max: 99, min: 0, optimalMax: 0, optimalMin: 0, unit: "AU" },
|
|
4996
4707
|
direction: "lower-better",
|
|
4708
|
+
kind: "decision-threshold",
|
|
4997
4709
|
source: "rumberger-cac-1999"
|
|
4998
4710
|
},
|
|
4999
4711
|
Cadmium: {
|
|
5000
4712
|
default: { max: 1.2, min: 0, optimalMax: 0.5, optimalMin: 0, unit: "mcg/L" },
|
|
4713
|
+
kind: "decision-threshold",
|
|
5001
4714
|
source: "nr7-pcmso-2020"
|
|
5002
4715
|
},
|
|
5003
4716
|
Calcium: {
|
|
5004
4717
|
default: { max: 10.5, min: 8.5, optimalMax: 10, optimalMin: 9, unit: "mg/dL" },
|
|
4718
|
+
kind: "reference-interval",
|
|
5005
4719
|
source: "tietz-7ed-2015"
|
|
5006
4720
|
},
|
|
5007
4721
|
CEA: {
|
|
5008
4722
|
default: { max: 3, min: 0, optimalMax: 2.5, optimalMin: 0, unit: "ng/mL" },
|
|
4723
|
+
kind: "reference-interval",
|
|
5009
4724
|
source: "sturgeon-nacb-2008"
|
|
5010
4725
|
},
|
|
5011
4726
|
// CK: valores conservadores baseados em faixas laboratoriais típicas
|
|
@@ -5030,6 +4745,7 @@ var biomarkerRangeDefinitions = {
|
|
|
5030
4745
|
// autodeclaração de raça/Cor". Ver a issue #3 para a decisão registrada.
|
|
5031
4746
|
CK: {
|
|
5032
4747
|
default: { max: 314, min: 30, optimalMax: 170, optimalMin: 40, unit: "U/L" },
|
|
4748
|
+
kind: "reference-interval",
|
|
5033
4749
|
source: "kalaria-ck-ri-2026",
|
|
5034
4750
|
variants: [
|
|
5035
4751
|
{ sex: "F", range: { max: 170, min: 30, optimalMax: 150, optimalMin: 40, unit: "U/L" } }
|
|
@@ -5037,6 +4753,7 @@ var biomarkerRangeDefinitions = {
|
|
|
5037
4753
|
},
|
|
5038
4754
|
Chloride: {
|
|
5039
4755
|
default: { max: 106, min: 98, optimalMax: 105, optimalMin: 100, unit: "mEq/L" },
|
|
4756
|
+
kind: "reference-interval",
|
|
5040
4757
|
source: "tietz-7ed-2015"
|
|
5041
4758
|
},
|
|
5042
4759
|
// Colesterol total — SBC 2017/2025: valor desejável < 190 mg/dL para adultos,
|
|
@@ -5044,6 +4761,7 @@ var biomarkerRangeDefinitions = {
|
|
|
5044
4761
|
// (NCEP, 2002), superada pelas atualizações brasileiras.
|
|
5045
4762
|
Cholesterol: {
|
|
5046
4763
|
default: { max: 190, min: 0, optimalMax: 170, optimalMin: 0, unit: "mg/dL" },
|
|
4764
|
+
kind: "decision-threshold",
|
|
5047
4765
|
source: "sbc-lipids-2025"
|
|
5048
4766
|
},
|
|
5049
4767
|
// Índice de Castelli I (CT/HDL-c)
|
|
@@ -5051,6 +4769,7 @@ var biomarkerRangeDefinitions = {
|
|
|
5051
4769
|
// Índice de Castelli I — SBC 2017: M <4.9, F <4.3
|
|
5052
4770
|
default: { max: 4.9, min: 0, optimalMax: 3.5, optimalMin: 0, unit: "" },
|
|
5053
4771
|
direction: "lower-better",
|
|
4772
|
+
kind: "decision-threshold",
|
|
5054
4773
|
source: "castelli-ratio-1992",
|
|
5055
4774
|
variants: [
|
|
5056
4775
|
{
|
|
@@ -5067,22 +4786,27 @@ var biomarkerRangeDefinitions = {
|
|
|
5067
4786
|
},
|
|
5068
4787
|
CO2: {
|
|
5069
4788
|
default: { max: 29, min: 23, optimalMax: 28, optimalMin: 24, unit: "mEq/L" },
|
|
4789
|
+
kind: "reference-interval",
|
|
5070
4790
|
source: "tietz-7ed-2015"
|
|
5071
4791
|
},
|
|
5072
4792
|
Copper: {
|
|
5073
4793
|
default: { max: 175, min: 70, optimalMax: 150, optimalMin: 85, unit: "mcg/dL" },
|
|
4794
|
+
kind: "reference-interval",
|
|
5074
4795
|
source: "tietz-7ed-2015"
|
|
5075
4796
|
},
|
|
5076
4797
|
CoQ10: {
|
|
5077
4798
|
default: { max: 1.5, min: 0.5, optimalMax: 1.3, optimalMin: 0.7, unit: "mg/L" },
|
|
4799
|
+
kind: "reference-interval",
|
|
5078
4800
|
source: "tietz-7ed-2015"
|
|
5079
4801
|
},
|
|
5080
4802
|
Cortisol: {
|
|
5081
4803
|
default: { max: 25, min: 5, optimalMax: 20, optimalMin: 10, unit: "mcg/dL" },
|
|
4804
|
+
kind: "reference-interval",
|
|
5082
4805
|
source: "tietz-7ed-2015"
|
|
5083
4806
|
},
|
|
5084
4807
|
CortisolFree: {
|
|
5085
4808
|
default: { max: 2.5, min: 0.5, optimalMax: 2, optimalMin: 0.8, unit: "mcg/dL" },
|
|
4809
|
+
kind: "reference-interval",
|
|
5086
4810
|
source: "tietz-7ed-2015"
|
|
5087
4811
|
},
|
|
5088
4812
|
CPeptide: {
|
|
@@ -5094,10 +4818,12 @@ var biomarkerRangeDefinitions = {
|
|
|
5094
4818
|
optimalMin: 1,
|
|
5095
4819
|
unit: "ng/mL"
|
|
5096
4820
|
},
|
|
4821
|
+
kind: "reference-interval",
|
|
5097
4822
|
source: "tietz-7ed-2015"
|
|
5098
4823
|
},
|
|
5099
4824
|
Creatinine: {
|
|
5100
4825
|
default: { max: 1.2, min: 0.6, optimalMax: 1, optimalMin: 0.7, unit: "mg/dL" },
|
|
4826
|
+
kind: "reference-interval",
|
|
5101
4827
|
source: "pns-bioquimica-2019",
|
|
5102
4828
|
variants: [
|
|
5103
4829
|
// Gestação: hiperfiltração glomerular (↑ 40–50% GFR) reduz a creatinina
|
|
@@ -5123,10 +4849,12 @@ var biomarkerRangeDefinitions = {
|
|
|
5123
4849
|
CRP: {
|
|
5124
4850
|
default: { max: 3, min: 0, optimalMax: 1, optimalMin: 0, unit: "mg/L" },
|
|
5125
4851
|
direction: "lower-better",
|
|
4852
|
+
kind: "decision-threshold",
|
|
5126
4853
|
source: "tietz-7ed-2015"
|
|
5127
4854
|
},
|
|
5128
4855
|
CystatinC: {
|
|
5129
4856
|
default: { max: 1, min: 0.5, optimalMax: 0.9, optimalMin: 0.6, unit: "mg/L" },
|
|
4857
|
+
kind: "reference-interval",
|
|
5130
4858
|
source: "tietz-7ed-2015"
|
|
5131
4859
|
},
|
|
5132
4860
|
// D-Dímero — exame de exclusão de TEV (tromboembolismo venoso) com
|
|
@@ -5140,6 +4868,7 @@ var biomarkerRangeDefinitions = {
|
|
|
5140
4868
|
DDimer: {
|
|
5141
4869
|
default: { max: 500, min: 0, unit: "ng/mL" },
|
|
5142
4870
|
direction: "lower-better",
|
|
4871
|
+
kind: "decision-threshold",
|
|
5143
4872
|
source: "wells-ddimer-2003",
|
|
5144
4873
|
variants: [
|
|
5145
4874
|
// Corte ajustado por idade — ESC 2019 (Konstantinides et al.) e
|
|
@@ -5153,10 +4882,12 @@ var biomarkerRangeDefinitions = {
|
|
|
5153
4882
|
},
|
|
5154
4883
|
Omega3_DHA: {
|
|
5155
4884
|
default: { max: 8, min: 2, optimalMax: 6.5, optimalMin: 3.5, unit: "%" },
|
|
4885
|
+
kind: "decision-threshold",
|
|
5156
4886
|
source: "harris-omega3-2004"
|
|
5157
4887
|
},
|
|
5158
4888
|
DHEAS: {
|
|
5159
4889
|
default: { max: 500, min: 100, optimalMax: 400, optimalMin: 150, unit: "mcg/dL" },
|
|
4890
|
+
kind: "reference-interval",
|
|
5160
4891
|
source: "tietz-7ed-2015",
|
|
5161
4892
|
variants: [
|
|
5162
4893
|
{
|
|
@@ -5197,20 +4928,30 @@ var biomarkerRangeDefinitions = {
|
|
|
5197
4928
|
},
|
|
5198
4929
|
Omega3_DPA: {
|
|
5199
4930
|
default: { max: 2, min: 0.3, optimalMax: 1.5, optimalMin: 0.5, unit: "%" },
|
|
4931
|
+
kind: "decision-threshold",
|
|
5200
4932
|
source: "harris-omega3-2004"
|
|
5201
4933
|
},
|
|
5202
4934
|
eGFR: {
|
|
5203
|
-
default: {
|
|
4935
|
+
default: {
|
|
4936
|
+
max: 120,
|
|
4937
|
+
maxKind: "display",
|
|
4938
|
+
min: 60,
|
|
4939
|
+
optimalMax: 120,
|
|
4940
|
+
optimalMin: 90,
|
|
4941
|
+
unit: "mL/min/1.73m\xB2"
|
|
4942
|
+
},
|
|
5204
4943
|
// KDIGO 2024: TFG 60-89 (G2) sem marcador de lesão renal não é DRC, em
|
|
5205
4944
|
// nenhuma faixa etária. A variante por idade que existia aqui rebaixava o
|
|
5206
4945
|
// piso só para 60+ e ainda limitava o teto a 90, o que sinalizava como
|
|
5207
4946
|
// alterado qualquer idoso com função preservada.
|
|
4947
|
+
kind: "decision-threshold",
|
|
5208
4948
|
source: "kdigo-ckd-2024"
|
|
5209
4949
|
},
|
|
5210
4950
|
// `Eosinophils` (%) fica sem faixa de propósito e `Eosinophils_Abs` usa os limites da
|
|
5211
4951
|
// Tabela 2 da PNS 2019. Ver o comentário em `Neutrophils_Abs`.
|
|
5212
4952
|
Eosinophils_Abs: {
|
|
5213
4953
|
default: { max: 0.66, min: 0, unit: "K/uL" },
|
|
4954
|
+
kind: "reference-interval",
|
|
5214
4955
|
source: "pns-hemograma-2019",
|
|
5215
4956
|
variants: [
|
|
5216
4957
|
{ ageMin: 18, range: { max: 0.66, min: 0, unit: "K/uL" }, sex: "M" },
|
|
@@ -5219,18 +4960,22 @@ var biomarkerRangeDefinitions = {
|
|
|
5219
4960
|
},
|
|
5220
4961
|
Omega3_EPA: {
|
|
5221
4962
|
default: { max: 3.5, min: 0.5, optimalMax: 2.5, optimalMin: 1, unit: "%" },
|
|
4963
|
+
kind: "decision-threshold",
|
|
5222
4964
|
source: "harris-omega3-2004"
|
|
5223
4965
|
},
|
|
5224
4966
|
EPADPADHA: {
|
|
5225
4967
|
default: { max: 10, min: 3, optimalMax: 9, optimalMin: 5, unit: "%" },
|
|
4968
|
+
kind: "decision-threshold",
|
|
5226
4969
|
source: "harris-omega3-2004"
|
|
5227
4970
|
},
|
|
5228
4971
|
ESR: {
|
|
5229
4972
|
default: { max: 20, min: 0, optimalMax: 10, optimalMin: 0, unit: "mm/hr" },
|
|
4973
|
+
kind: "reference-interval",
|
|
5230
4974
|
source: "tietz-7ed-2015"
|
|
5231
4975
|
},
|
|
5232
4976
|
Estradiol: {
|
|
5233
4977
|
default: { max: 40, min: 10, optimalMax: 35, optimalMin: 15, unit: "pg/mL" },
|
|
4978
|
+
kind: "reference-interval",
|
|
5234
4979
|
source: "tietz-7ed-2015",
|
|
5235
4980
|
variants: [
|
|
5236
4981
|
{
|
|
@@ -5253,6 +4998,7 @@ var biomarkerRangeDefinitions = {
|
|
|
5253
4998
|
},
|
|
5254
4999
|
F2Isoprostanes: {
|
|
5255
5000
|
default: { max: 86, min: 0, optimalMax: 60, optimalMin: 0, unit: "pg/mL" },
|
|
5001
|
+
kind: "reference-interval",
|
|
5256
5002
|
source: "tietz-7ed-2015"
|
|
5257
5003
|
},
|
|
5258
5004
|
// Ferritina — WHO 2020 é o documento de referência específico para avaliação
|
|
@@ -5262,6 +5008,7 @@ var biomarkerRangeDefinitions = {
|
|
|
5262
5008
|
// tipo de faixa, mas documentado aqui para consumidores).
|
|
5263
5009
|
Ferritin: {
|
|
5264
5010
|
default: { max: 150, min: 12, optimalMax: 120, optimalMin: 30, unit: "ng/mL" },
|
|
5011
|
+
kind: "decision-threshold",
|
|
5265
5012
|
source: "who-iron-2020",
|
|
5266
5013
|
variants: [
|
|
5267
5014
|
// Gestação: ferritina cai fisiologicamente no 2º/3º trimestre pela expansão
|
|
@@ -5294,14 +5041,17 @@ var biomarkerRangeDefinitions = {
|
|
|
5294
5041
|
// Fibrinogênio: 200-400 mg/dL — faixa de referência padrão (método de Clauss)
|
|
5295
5042
|
Fibrinogen: {
|
|
5296
5043
|
default: { max: 400, min: 200, optimalMax: 350, optimalMin: 250, unit: "mg/dL" },
|
|
5044
|
+
kind: "reference-interval",
|
|
5297
5045
|
source: "tietz-7ed-2015"
|
|
5298
5046
|
},
|
|
5299
5047
|
FolicAcid: {
|
|
5300
5048
|
default: { max: 20, min: 3, optimalMax: 15, optimalMin: 5, unit: "ng/mL" },
|
|
5049
|
+
kind: "reference-interval",
|
|
5301
5050
|
source: "tietz-7ed-2015"
|
|
5302
5051
|
},
|
|
5303
5052
|
FSH: {
|
|
5304
5053
|
default: { max: 12.4, min: 1.5, optimalMax: 10, optimalMin: 3, unit: "mIU/mL" },
|
|
5054
|
+
kind: "reference-interval",
|
|
5305
5055
|
source: "tietz-7ed-2015",
|
|
5306
5056
|
variants: [
|
|
5307
5057
|
{
|
|
@@ -5325,26 +5075,29 @@ var biomarkerRangeDefinitions = {
|
|
|
5325
5075
|
GGT: {
|
|
5326
5076
|
default: { max: 55, min: 0, optimalMax: 30, optimalMin: 0, unit: "U/L" },
|
|
5327
5077
|
direction: "lower-better",
|
|
5078
|
+
kind: "reference-interval",
|
|
5328
5079
|
source: "tietz-7ed-2015",
|
|
5329
5080
|
variants: [
|
|
5330
5081
|
{
|
|
5331
5082
|
ageMin: 18,
|
|
5332
|
-
range: { max: 61, min: 8, optimalMax: 40, optimalMin: 10, unit: "U/L" },
|
|
5083
|
+
range: { max: 61, min: 8, minKind: "display", optimalMax: 40, optimalMin: 10, unit: "U/L" },
|
|
5333
5084
|
sex: "M"
|
|
5334
5085
|
},
|
|
5335
5086
|
{
|
|
5336
5087
|
ageMin: 18,
|
|
5337
|
-
range: { max: 36, min: 5, optimalMax: 25, optimalMin: 8, unit: "U/L" },
|
|
5088
|
+
range: { max: 36, min: 5, minKind: "display", optimalMax: 25, optimalMin: 8, unit: "U/L" },
|
|
5338
5089
|
sex: "F"
|
|
5339
5090
|
}
|
|
5340
5091
|
]
|
|
5341
5092
|
},
|
|
5342
5093
|
Ghrelin: {
|
|
5343
5094
|
default: { max: 1e3, min: 300, optimalMax: 800, optimalMin: 400, unit: "pg/mL" },
|
|
5095
|
+
kind: "reference-interval",
|
|
5344
5096
|
source: "tietz-7ed-2015"
|
|
5345
5097
|
},
|
|
5346
5098
|
Globulin: {
|
|
5347
5099
|
default: { max: 3.5, min: 2, optimalMax: 3.2, optimalMin: 2.3, unit: "g/dL" },
|
|
5100
|
+
kind: "reference-interval",
|
|
5348
5101
|
source: "tietz-7ed-2015"
|
|
5349
5102
|
},
|
|
5350
5103
|
// A faixa é de jejum, então mora na definição que afirma jejum. Glicose
|
|
@@ -5367,6 +5120,7 @@ var biomarkerRangeDefinitions = {
|
|
|
5367
5120
|
optimalMin: 70,
|
|
5368
5121
|
unit: "mg/dL"
|
|
5369
5122
|
},
|
|
5123
|
+
kind: "decision-threshold",
|
|
5370
5124
|
source: "sbd-diabetes-2024",
|
|
5371
5125
|
variants: [
|
|
5372
5126
|
// Gestação: DMG (IADPSG/SBD 2024) usa cortes mais restritivos na glicemia
|
|
@@ -5388,10 +5142,12 @@ var biomarkerRangeDefinitions = {
|
|
|
5388
5142
|
},
|
|
5389
5143
|
GlycoMark: {
|
|
5390
5144
|
default: { max: 40, min: 10, optimalMax: 35, optimalMin: 15, unit: "mcg/mL" },
|
|
5145
|
+
kind: "reference-interval",
|
|
5391
5146
|
source: "tietz-7ed-2015"
|
|
5392
5147
|
},
|
|
5393
5148
|
GrowthHormone: {
|
|
5394
5149
|
default: { max: 5, min: 0, optimalMax: 3, optimalMin: 0, unit: "ng/mL" },
|
|
5150
|
+
kind: "reference-interval",
|
|
5395
5151
|
source: "tietz-7ed-2015"
|
|
5396
5152
|
},
|
|
5397
5153
|
// HbA1c — SBD 2024 não estabelece piso de referência clinicamente acionável.
|
|
@@ -5401,11 +5157,13 @@ var biomarkerRangeDefinitions = {
|
|
|
5401
5157
|
// criar flag clínico em valores fisiologicamente baixos. optimalMin preserva
|
|
5402
5158
|
// o alvo fisiológico da fração glicada.
|
|
5403
5159
|
HbA1c: {
|
|
5404
|
-
default: { max: 5.7, min: 2, optimalMax: 5.3, optimalMin: 4.5, unit: "%" },
|
|
5160
|
+
default: { max: 5.7, min: 2, minKind: "display", optimalMax: 5.3, optimalMin: 4.5, unit: "%" },
|
|
5161
|
+
kind: "decision-threshold",
|
|
5405
5162
|
source: "sbd-diabetes-2024"
|
|
5406
5163
|
},
|
|
5407
5164
|
Hct: {
|
|
5408
5165
|
default: { max: 50, min: 36, optimalMax: 48, optimalMin: 40, unit: "%" },
|
|
5166
|
+
kind: "reference-interval",
|
|
5409
5167
|
source: "pns-hemograma-2019",
|
|
5410
5168
|
variants: [
|
|
5411
5169
|
{
|
|
@@ -5427,18 +5185,40 @@ var biomarkerRangeDefinitions = {
|
|
|
5427
5185
|
// não como ponto de corte clínico; consumidores devem tratar `direction:
|
|
5428
5186
|
// higher-better` como sinal autoritativo.
|
|
5429
5187
|
HDL: {
|
|
5430
|
-
default: {
|
|
5188
|
+
default: {
|
|
5189
|
+
max: 100,
|
|
5190
|
+
maxKind: "display",
|
|
5191
|
+
min: 40,
|
|
5192
|
+
optimalMax: 100,
|
|
5193
|
+
optimalMin: 50,
|
|
5194
|
+
unit: "mg/dL"
|
|
5195
|
+
},
|
|
5431
5196
|
direction: "higher-better",
|
|
5197
|
+
kind: "decision-threshold",
|
|
5432
5198
|
source: "sbc-lipids-2025",
|
|
5433
5199
|
variants: [
|
|
5434
5200
|
{
|
|
5435
5201
|
ageMin: 18,
|
|
5436
|
-
range: {
|
|
5202
|
+
range: {
|
|
5203
|
+
max: 100,
|
|
5204
|
+
maxKind: "display",
|
|
5205
|
+
min: 40,
|
|
5206
|
+
optimalMax: 100,
|
|
5207
|
+
optimalMin: 45,
|
|
5208
|
+
unit: "mg/dL"
|
|
5209
|
+
},
|
|
5437
5210
|
sex: "M"
|
|
5438
5211
|
},
|
|
5439
5212
|
{
|
|
5440
5213
|
ageMin: 18,
|
|
5441
|
-
range: {
|
|
5214
|
+
range: {
|
|
5215
|
+
max: 100,
|
|
5216
|
+
maxKind: "display",
|
|
5217
|
+
min: 50,
|
|
5218
|
+
optimalMax: 100,
|
|
5219
|
+
optimalMin: 55,
|
|
5220
|
+
unit: "mg/dL"
|
|
5221
|
+
},
|
|
5442
5222
|
sex: "F"
|
|
5443
5223
|
}
|
|
5444
5224
|
]
|
|
@@ -5446,12 +5226,21 @@ var biomarkerRangeDefinitions = {
|
|
|
5446
5226
|
HDL_Large: {
|
|
5447
5227
|
// HDL Large: higher is better
|
|
5448
5228
|
// Quest Ion Mobility reference: Male 4334-10815, Female 5038-17886 nmol/L, optimal >6729
|
|
5449
|
-
default: {
|
|
5229
|
+
default: {
|
|
5230
|
+
max: 17886,
|
|
5231
|
+
maxKind: "display",
|
|
5232
|
+
min: 4334,
|
|
5233
|
+
optimalMax: 17886,
|
|
5234
|
+
optimalMin: 6729,
|
|
5235
|
+
unit: "nmol/L"
|
|
5236
|
+
},
|
|
5450
5237
|
direction: "higher-better",
|
|
5238
|
+
kind: "reference-interval",
|
|
5451
5239
|
source: "caulfield-ionmobility-2008"
|
|
5452
5240
|
},
|
|
5453
5241
|
Hgb: {
|
|
5454
5242
|
default: { max: 17.5, min: 12, optimalMax: 16, optimalMin: 13.5, unit: "g/dL" },
|
|
5243
|
+
kind: "reference-interval",
|
|
5455
5244
|
source: "pns-hemograma-2019",
|
|
5456
5245
|
variants: [
|
|
5457
5246
|
// Gestação: hemodiluição fisiológica reduz o piso aceitável.
|
|
@@ -5507,19 +5296,23 @@ var biomarkerRangeDefinitions = {
|
|
|
5507
5296
|
warningMax: 2.71
|
|
5508
5297
|
},
|
|
5509
5298
|
direction: "lower-better",
|
|
5299
|
+
kind: "decision-threshold",
|
|
5510
5300
|
source: "geloneze-brams-2009"
|
|
5511
5301
|
},
|
|
5512
5302
|
Homocysteine: {
|
|
5513
|
-
default: { max: 15, min: 4, optimalMax: 10, optimalMin: 5, unit: "umol/L" },
|
|
5303
|
+
default: { max: 15, min: 4, minKind: "display", optimalMax: 10, optimalMin: 5, unit: "umol/L" },
|
|
5514
5304
|
direction: "lower-better",
|
|
5305
|
+
kind: "reference-interval",
|
|
5515
5306
|
source: "selhub-homocysteine-1999"
|
|
5516
5307
|
},
|
|
5517
5308
|
IGF1: {
|
|
5518
5309
|
default: { max: 350, min: 100, optimalMax: 300, optimalMin: 150, unit: "ng/mL" },
|
|
5310
|
+
kind: "reference-interval",
|
|
5519
5311
|
source: "tietz-7ed-2015"
|
|
5520
5312
|
},
|
|
5521
5313
|
ImmatureGranulocytes: {
|
|
5522
5314
|
default: { max: 1, min: 0, optimalMax: 0.5, optimalMin: 0, unit: "%" },
|
|
5315
|
+
kind: "reference-interval",
|
|
5523
5316
|
source: "tietz-7ed-2015"
|
|
5524
5317
|
},
|
|
5525
5318
|
Insulin: {
|
|
@@ -5531,10 +5324,12 @@ var biomarkerRangeDefinitions = {
|
|
|
5531
5324
|
optimalMin: 3,
|
|
5532
5325
|
unit: "uIU/mL"
|
|
5533
5326
|
},
|
|
5327
|
+
kind: "reference-interval",
|
|
5534
5328
|
source: "tietz-7ed-2015"
|
|
5535
5329
|
},
|
|
5536
5330
|
Iron: {
|
|
5537
5331
|
default: { max: 170, min: 60, optimalMax: 140, optimalMin: 80, unit: "mcg/dL" },
|
|
5332
|
+
kind: "reference-interval",
|
|
5538
5333
|
source: "sbpc-ml-2021",
|
|
5539
5334
|
variants: [
|
|
5540
5335
|
{
|
|
@@ -5551,6 +5346,7 @@ var biomarkerRangeDefinitions = {
|
|
|
5551
5346
|
},
|
|
5552
5347
|
Lactate: {
|
|
5553
5348
|
default: { max: 2.2, min: 0.5, optimalMax: 1.8, optimalMin: 0.7, unit: "mmol/L" },
|
|
5349
|
+
kind: "reference-interval",
|
|
5554
5350
|
source: "tietz-7ed-2015"
|
|
5555
5351
|
},
|
|
5556
5352
|
// DHL/LDH — método IFCC a 37 °C (padrão atual na maioria dos laboratórios
|
|
@@ -5562,6 +5358,7 @@ var biomarkerRangeDefinitions = {
|
|
|
5562
5358
|
LDH: {
|
|
5563
5359
|
default: { max: 248, min: 0, optimalMax: 248, optimalMin: 0, unit: "U/L" },
|
|
5564
5360
|
direction: "lower-better",
|
|
5361
|
+
kind: "reference-interval",
|
|
5565
5362
|
source: "schumann-ifcc-ldh-2002",
|
|
5566
5363
|
variants: [
|
|
5567
5364
|
{
|
|
@@ -5579,59 +5376,109 @@ var biomarkerRangeDefinitions = {
|
|
|
5579
5376
|
LDL: {
|
|
5580
5377
|
default: { max: 100, min: 0, optimalMax: 70, optimalMin: 0, unit: "mg/dL" },
|
|
5581
5378
|
direction: "lower-better",
|
|
5379
|
+
kind: "decision-threshold",
|
|
5582
5380
|
source: "sbc-lipids-2025"
|
|
5583
5381
|
},
|
|
5584
5382
|
LDL_Medium: {
|
|
5585
5383
|
// LDL Medium (LDL Média): lower is better
|
|
5586
5384
|
// Quest Ion Mobility reference: Male 167-485, Female 121-397 nmol/L, optimal <215
|
|
5587
|
-
default: {
|
|
5385
|
+
default: {
|
|
5386
|
+
max: 485,
|
|
5387
|
+
min: 121,
|
|
5388
|
+
minKind: "display",
|
|
5389
|
+
optimalMax: 215,
|
|
5390
|
+
optimalMin: 121,
|
|
5391
|
+
unit: "nmol/L"
|
|
5392
|
+
},
|
|
5588
5393
|
direction: "lower-better",
|
|
5394
|
+
kind: "reference-interval",
|
|
5589
5395
|
source: "caulfield-ionmobility-2008"
|
|
5590
5396
|
},
|
|
5591
5397
|
LDL_ParticleNumber: {
|
|
5592
5398
|
// LDL Particle Number: lower is better
|
|
5593
5399
|
// Quest Ion Mobility reference: 1016-2185 nmol/L, optimal <1138
|
|
5594
|
-
default: {
|
|
5400
|
+
default: {
|
|
5401
|
+
max: 2185,
|
|
5402
|
+
min: 1016,
|
|
5403
|
+
minKind: "display",
|
|
5404
|
+
optimalMax: 1138,
|
|
5405
|
+
optimalMin: 1016,
|
|
5406
|
+
unit: "nmol/L"
|
|
5407
|
+
},
|
|
5595
5408
|
direction: "lower-better",
|
|
5409
|
+
kind: "reference-interval",
|
|
5596
5410
|
source: "caulfield-ionmobility-2008"
|
|
5597
5411
|
},
|
|
5598
5412
|
LDL_Peak_Size: {
|
|
5599
5413
|
// LDL Peak Size: higher is better (larger particles less atherogenic)
|
|
5600
5414
|
// Quest Ion Mobility reference: optimal >222.9 Å (22.29 nm)
|
|
5601
|
-
default: {
|
|
5415
|
+
default: {
|
|
5416
|
+
max: 250,
|
|
5417
|
+
maxKind: "display",
|
|
5418
|
+
min: 217.4,
|
|
5419
|
+
optimalMax: 250,
|
|
5420
|
+
optimalMin: 222.9,
|
|
5421
|
+
unit: "Angstrom"
|
|
5422
|
+
},
|
|
5602
5423
|
direction: "higher-better",
|
|
5424
|
+
kind: "reference-interval",
|
|
5603
5425
|
source: "caulfield-ionmobility-2008"
|
|
5604
5426
|
},
|
|
5605
5427
|
LDL_Small: {
|
|
5606
5428
|
// LDL Small (LDL Pequena): lower is better (small dense LDL is most atherogenic)
|
|
5607
5429
|
// Quest Ion Mobility reference: Male 123-441, Female 126-382 nmol/L, optimal <142
|
|
5608
|
-
default: {
|
|
5430
|
+
default: {
|
|
5431
|
+
max: 441,
|
|
5432
|
+
min: 123,
|
|
5433
|
+
minKind: "display",
|
|
5434
|
+
optimalMax: 142,
|
|
5435
|
+
optimalMin: 123,
|
|
5436
|
+
unit: "nmol/L"
|
|
5437
|
+
},
|
|
5609
5438
|
direction: "lower-better",
|
|
5439
|
+
kind: "reference-interval",
|
|
5610
5440
|
source: "caulfield-ionmobility-2008"
|
|
5611
5441
|
},
|
|
5612
5442
|
Lead: {
|
|
5613
5443
|
default: { max: 5, min: 0, optimalMax: 2, optimalMin: 0, unit: "mcg/dL" },
|
|
5444
|
+
kind: "decision-threshold",
|
|
5614
5445
|
source: "nr7-pcmso-2020"
|
|
5615
5446
|
},
|
|
5616
5447
|
Leptin: {
|
|
5617
|
-
default: { max: 15, min: 2, optimalMax: 12, optimalMin: 3, unit: "ng/mL" },
|
|
5448
|
+
default: { max: 15, min: 2, minKind: "clinical", optimalMax: 12, optimalMin: 3, unit: "ng/mL" },
|
|
5618
5449
|
direction: "lower-better",
|
|
5450
|
+
kind: "reference-interval",
|
|
5619
5451
|
source: "tietz-7ed-2015",
|
|
5620
5452
|
variants: [
|
|
5621
5453
|
{
|
|
5622
5454
|
ageMin: 18,
|
|
5623
|
-
range: {
|
|
5455
|
+
range: {
|
|
5456
|
+
max: 10,
|
|
5457
|
+
min: 1,
|
|
5458
|
+
minKind: "clinical",
|
|
5459
|
+
optimalMax: 8,
|
|
5460
|
+
optimalMin: 2,
|
|
5461
|
+
unit: "ng/mL"
|
|
5462
|
+
},
|
|
5624
5463
|
sex: "M"
|
|
5625
5464
|
},
|
|
5626
5465
|
{
|
|
5627
5466
|
ageMin: 18,
|
|
5628
|
-
range: {
|
|
5467
|
+
range: {
|
|
5468
|
+
max: 25,
|
|
5469
|
+
min: 4,
|
|
5470
|
+
minKind: "clinical",
|
|
5471
|
+
optimalMax: 18,
|
|
5472
|
+
optimalMin: 5,
|
|
5473
|
+
unit: "ng/mL"
|
|
5474
|
+
},
|
|
5629
5475
|
sex: "F"
|
|
5630
5476
|
}
|
|
5631
5477
|
]
|
|
5632
5478
|
},
|
|
5633
5479
|
LH: {
|
|
5634
5480
|
default: { max: 8.6, min: 1.7, optimalMax: 8, optimalMin: 2, unit: "mIU/mL" },
|
|
5481
|
+
kind: "reference-interval",
|
|
5635
5482
|
source: "tietz-7ed-2015",
|
|
5636
5483
|
variants: [
|
|
5637
5484
|
{
|
|
@@ -5654,6 +5501,7 @@ var biomarkerRangeDefinitions = {
|
|
|
5654
5501
|
},
|
|
5655
5502
|
Omega6_LA: {
|
|
5656
5503
|
default: { max: 35, min: 15, optimalMax: 28, optimalMin: 18, unit: "%" },
|
|
5504
|
+
kind: "decision-threshold",
|
|
5657
5505
|
source: "simopoulos-omega-ratio-2002"
|
|
5658
5506
|
},
|
|
5659
5507
|
// Lp(a) — SBC 2025 (seção 3.1.1.2.7): níveis ≥ 50 mg/dL ou ≥ 125 nmol/L são
|
|
@@ -5665,12 +5513,14 @@ var biomarkerRangeDefinitions = {
|
|
|
5665
5513
|
Lipoprotein_a: {
|
|
5666
5514
|
default: { max: 125, min: 0, optimalMax: 75, optimalMin: 0, unit: "nmol/L" },
|
|
5667
5515
|
direction: "lower-better",
|
|
5516
|
+
kind: "decision-threshold",
|
|
5668
5517
|
source: "sbc-lipids-2025"
|
|
5669
5518
|
},
|
|
5670
5519
|
// `Lymphocytes` (%) fica sem faixa de propósito e `Lymphocytes_Abs` usa os limites da
|
|
5671
5520
|
// Tabela 2 da PNS 2019. Ver o comentário em `Neutrophils_Abs`.
|
|
5672
5521
|
Lymphocytes_Abs: {
|
|
5673
5522
|
default: { max: 3.414, min: 0.72, unit: "K/uL" },
|
|
5523
|
+
kind: "reference-interval",
|
|
5674
5524
|
source: "pns-hemograma-2019",
|
|
5675
5525
|
variants: [
|
|
5676
5526
|
{ ageMin: 18, range: { max: 3.37, min: 0.72, unit: "K/uL" }, sex: "M" },
|
|
@@ -5679,40 +5529,49 @@ var biomarkerRangeDefinitions = {
|
|
|
5679
5529
|
},
|
|
5680
5530
|
Magnesium: {
|
|
5681
5531
|
default: { max: 2.2, min: 1.7, optimalMax: 2.1, optimalMin: 1.9, unit: "mg/dL" },
|
|
5532
|
+
kind: "reference-interval",
|
|
5682
5533
|
source: "tietz-7ed-2015"
|
|
5683
5534
|
},
|
|
5684
5535
|
Magnesium_RBC: {
|
|
5685
5536
|
default: { max: 6.8, min: 4, optimalMax: 6, optimalMin: 4.5, unit: "mg/dL" },
|
|
5537
|
+
kind: "reference-interval",
|
|
5686
5538
|
source: "tietz-7ed-2015"
|
|
5687
5539
|
},
|
|
5688
5540
|
MCH: {
|
|
5689
5541
|
default: { max: 33, min: 27, optimalMax: 32, optimalMin: 28, unit: "pg" },
|
|
5542
|
+
kind: "reference-interval",
|
|
5690
5543
|
source: "pns-hemograma-2019"
|
|
5691
5544
|
},
|
|
5692
5545
|
MCHC: {
|
|
5693
5546
|
default: { max: 36, min: 32, optimalMax: 35, optimalMin: 33, unit: "g/dL" },
|
|
5547
|
+
kind: "reference-interval",
|
|
5694
5548
|
source: "pns-hemograma-2019"
|
|
5695
5549
|
},
|
|
5696
5550
|
MCV: {
|
|
5697
5551
|
default: { max: 100, min: 80, optimalMax: 98, optimalMin: 82, unit: "fL" },
|
|
5552
|
+
kind: "reference-interval",
|
|
5698
5553
|
source: "pns-hemograma-2019"
|
|
5699
5554
|
},
|
|
5700
5555
|
Mercury: {
|
|
5701
5556
|
default: { max: 10, min: 0, optimalMax: 5, optimalMin: 0, unit: "mcg/L" },
|
|
5557
|
+
kind: "decision-threshold",
|
|
5702
5558
|
source: "nr7-pcmso-2020"
|
|
5703
5559
|
},
|
|
5704
5560
|
Microalbumin: {
|
|
5705
5561
|
default: { max: 30, min: 0, optimalMax: 20, optimalMin: 0, unit: "mg/L" },
|
|
5562
|
+
kind: "decision-threshold",
|
|
5706
5563
|
source: "kdigo-ckd-2024"
|
|
5707
5564
|
},
|
|
5708
5565
|
MMA: {
|
|
5709
5566
|
default: { max: 378, min: 0, optimalMax: 270, optimalMin: 0, unit: "nmol/L" },
|
|
5567
|
+
kind: "reference-interval",
|
|
5710
5568
|
source: "tietz-7ed-2015"
|
|
5711
5569
|
},
|
|
5712
5570
|
// `Monocytes` (%) fica sem faixa de propósito e `Monocytes_Abs` usa os limites da
|
|
5713
5571
|
// Tabela 2 da PNS 2019. Ver o comentário em `Neutrophils_Abs`.
|
|
5714
5572
|
Monocytes_Abs: {
|
|
5715
5573
|
default: { max: 0.812, min: 0.011, unit: "K/uL" },
|
|
5574
|
+
kind: "reference-interval",
|
|
5716
5575
|
source: "pns-hemograma-2019",
|
|
5717
5576
|
variants: [
|
|
5718
5577
|
{ ageMin: 18, range: { max: 0.812, min: 0.011, unit: "K/uL" }, sex: "M" },
|
|
@@ -5721,11 +5580,13 @@ var biomarkerRangeDefinitions = {
|
|
|
5721
5580
|
},
|
|
5722
5581
|
MPV: {
|
|
5723
5582
|
default: { max: 11.5, min: 7.5, optimalMax: 10.5, optimalMin: 8, unit: "fL" },
|
|
5583
|
+
kind: "reference-interval",
|
|
5724
5584
|
source: "pns-hemograma-2019"
|
|
5725
5585
|
},
|
|
5726
5586
|
// MPO: Meuwese 2007 (EPIC-Norfolk) — risco CV elevado >322 pmol/L
|
|
5727
5587
|
Myeloperoxidase: {
|
|
5728
5588
|
default: { max: 470, min: 0, optimalMax: 322, optimalMin: 0, unit: "pmol/L" },
|
|
5589
|
+
kind: "decision-threshold",
|
|
5729
5590
|
source: "meuwese-mpo-2007"
|
|
5730
5591
|
},
|
|
5731
5592
|
// Leucograma diferencial em percentual (`Neutrophils`, `Lymphocytes`,
|
|
@@ -5749,6 +5610,7 @@ var biomarkerRangeDefinitions = {
|
|
|
5749
5610
|
// (menor mínimo e maior máximo entre homens e mulheres).
|
|
5750
5611
|
Neutrophils_Abs: {
|
|
5751
5612
|
default: { max: 6.474, min: 0.576, unit: "K/uL" },
|
|
5613
|
+
kind: "reference-interval",
|
|
5752
5614
|
source: "pns-hemograma-2019",
|
|
5753
5615
|
variants: [
|
|
5754
5616
|
{ ageMin: 18, range: { max: 5.971, min: 0.576, unit: "K/uL" }, sex: "M" },
|
|
@@ -5758,22 +5620,27 @@ var biomarkerRangeDefinitions = {
|
|
|
5758
5620
|
NonHDL_Cholesterol: {
|
|
5759
5621
|
default: { max: 130, min: 0, optimalMax: 100, optimalMin: 0, unit: "mg/dL" },
|
|
5760
5622
|
direction: "lower-better",
|
|
5623
|
+
kind: "decision-threshold",
|
|
5761
5624
|
source: "sbc-lipids-2025"
|
|
5762
5625
|
},
|
|
5763
5626
|
NRBC: {
|
|
5764
5627
|
default: { max: 0, min: 0, optimalMax: 0, optimalMin: 0, unit: "/100WBC" },
|
|
5628
|
+
kind: "reference-interval",
|
|
5765
5629
|
source: "tietz-7ed-2015"
|
|
5766
5630
|
},
|
|
5767
5631
|
NTproBNP: {
|
|
5768
5632
|
default: { max: 125, min: 0, optimalMax: 75, optimalMin: 0, unit: "pg/mL" },
|
|
5633
|
+
kind: "decision-threshold",
|
|
5769
5634
|
source: "sbc-ic-2018"
|
|
5770
5635
|
},
|
|
5771
5636
|
Oleic_Acid: {
|
|
5772
5637
|
default: { max: 25, min: 15, optimalMax: 22, optimalMin: 18, unit: "%" },
|
|
5638
|
+
kind: "reference-interval",
|
|
5773
5639
|
source: "tietz-7ed-2015"
|
|
5774
5640
|
},
|
|
5775
5641
|
Omega3_Index: {
|
|
5776
5642
|
default: { max: 8, min: 4, optimalMax: 8, optimalMin: 5.5, unit: "%" },
|
|
5643
|
+
kind: "decision-threshold",
|
|
5777
5644
|
source: "harris-omega3-2004"
|
|
5778
5645
|
},
|
|
5779
5646
|
// Ômega-3 Total (% de ácidos graxos eritrocitários) — Harris & von Schacky
|
|
@@ -5783,39 +5650,55 @@ var biomarkerRangeDefinitions = {
|
|
|
5783
5650
|
// a literatura e o próprio texto educacional do `platform`.
|
|
5784
5651
|
Omega3_Total: {
|
|
5785
5652
|
default: { max: 12, min: 3, optimalMax: 10, optimalMin: 8, unit: "%" },
|
|
5653
|
+
kind: "decision-threshold",
|
|
5786
5654
|
source: "harris-omega3-2004"
|
|
5787
5655
|
},
|
|
5788
5656
|
Omega6_Total: {
|
|
5789
5657
|
default: { max: 40, min: 20, optimalMax: 35, optimalMin: 25, unit: "%" },
|
|
5658
|
+
kind: "decision-threshold",
|
|
5790
5659
|
source: "simopoulos-omega-ratio-2002"
|
|
5791
5660
|
},
|
|
5792
5661
|
Omega6_Omega3_Ratio: {
|
|
5793
|
-
default: {
|
|
5662
|
+
default: {
|
|
5663
|
+
max: 10,
|
|
5664
|
+
min: 1,
|
|
5665
|
+
minKind: "display",
|
|
5666
|
+
optimalMax: 4,
|
|
5667
|
+
optimalMin: 1,
|
|
5668
|
+
unit: ""
|
|
5669
|
+
},
|
|
5794
5670
|
direction: "lower-better",
|
|
5671
|
+
kind: "decision-threshold",
|
|
5795
5672
|
source: "simopoulos-omega-ratio-2002"
|
|
5796
5673
|
},
|
|
5797
5674
|
OmegaCheck: {
|
|
5798
5675
|
default: { max: 8, min: 4, optimalMax: 8, optimalMin: 5.5, unit: "%" },
|
|
5676
|
+
kind: "decision-threshold",
|
|
5799
5677
|
source: "harris-omega3-2004"
|
|
5800
5678
|
},
|
|
5801
5679
|
Palmitic_Acid: {
|
|
5802
5680
|
default: { max: 30, min: 20, optimalMax: 27, optimalMin: 22, unit: "%" },
|
|
5681
|
+
kind: "reference-interval",
|
|
5803
5682
|
source: "tietz-7ed-2015"
|
|
5804
5683
|
},
|
|
5805
5684
|
Phosphorus: {
|
|
5806
5685
|
default: { max: 4.5, min: 2.5, optimalMax: 4, optimalMin: 3, unit: "mg/dL" },
|
|
5686
|
+
kind: "reference-interval",
|
|
5807
5687
|
source: "tietz-7ed-2015"
|
|
5808
5688
|
},
|
|
5809
5689
|
Platelets: {
|
|
5810
5690
|
default: { max: 400, min: 150, optimalMax: 350, optimalMin: 180, unit: "K/uL" },
|
|
5691
|
+
kind: "reference-interval",
|
|
5811
5692
|
source: "pns-hemograma-2019"
|
|
5812
5693
|
},
|
|
5813
5694
|
Potassium: {
|
|
5814
5695
|
default: { max: 5, min: 3.5, optimalMax: 4.6, optimalMin: 3.8, unit: "mEq/L" },
|
|
5696
|
+
kind: "reference-interval",
|
|
5815
5697
|
source: "tietz-7ed-2015"
|
|
5816
5698
|
},
|
|
5817
5699
|
Prealbumin: {
|
|
5818
5700
|
default: { max: 38, min: 18, optimalMax: 35, optimalMin: 20, unit: "mg/dL" },
|
|
5701
|
+
kind: "reference-interval",
|
|
5819
5702
|
source: "tietz-7ed-2015"
|
|
5820
5703
|
},
|
|
5821
5704
|
// Progesterona — varia drasticamente com a fase do ciclo menstrual.
|
|
@@ -5826,6 +5709,7 @@ var biomarkerRangeDefinitions = {
|
|
|
5826
5709
|
// ciclo, indisponível neste contexto.
|
|
5827
5710
|
Progesterone: {
|
|
5828
5711
|
default: { max: 0.9, min: 0.1, optimalMax: 0.7, optimalMin: 0.2, unit: "ng/mL" },
|
|
5712
|
+
kind: "reference-interval",
|
|
5829
5713
|
source: "tietz-7ed-2015",
|
|
5830
5714
|
variants: [
|
|
5831
5715
|
{
|
|
@@ -5852,6 +5736,7 @@ var biomarkerRangeDefinitions = {
|
|
|
5852
5736
|
},
|
|
5853
5737
|
Prolactin: {
|
|
5854
5738
|
default: { max: 18, min: 2, optimalMax: 15, optimalMin: 4, unit: "ng/mL" },
|
|
5739
|
+
kind: "reference-interval",
|
|
5855
5740
|
source: "tietz-7ed-2015",
|
|
5856
5741
|
variants: [
|
|
5857
5742
|
{
|
|
@@ -5868,6 +5753,7 @@ var biomarkerRangeDefinitions = {
|
|
|
5868
5753
|
},
|
|
5869
5754
|
PSA: {
|
|
5870
5755
|
default: { max: 4, min: 0, optimalMax: 2.5, optimalMin: 0, unit: "ng/mL" },
|
|
5756
|
+
kind: "reference-interval",
|
|
5871
5757
|
source: "sturgeon-nacb-2008",
|
|
5872
5758
|
variants: [
|
|
5873
5759
|
{
|
|
@@ -5897,6 +5783,7 @@ var biomarkerRangeDefinitions = {
|
|
|
5897
5783
|
},
|
|
5898
5784
|
RBC: {
|
|
5899
5785
|
default: { max: 5.5, min: 4, optimalMax: 5.2, optimalMin: 4.3, unit: "M/uL" },
|
|
5786
|
+
kind: "reference-interval",
|
|
5900
5787
|
source: "pns-hemograma-2019",
|
|
5901
5788
|
variants: [
|
|
5902
5789
|
{
|
|
@@ -5913,22 +5800,27 @@ var biomarkerRangeDefinitions = {
|
|
|
5913
5800
|
},
|
|
5914
5801
|
RDW: {
|
|
5915
5802
|
default: { max: 14.5, min: 11.5, optimalMax: 14, optimalMin: 12, unit: "%" },
|
|
5803
|
+
kind: "reference-interval",
|
|
5916
5804
|
source: "pns-hemograma-2019"
|
|
5917
5805
|
},
|
|
5918
5806
|
Reticulocytes: {
|
|
5919
5807
|
default: { max: 2.5, min: 0.5, optimalMax: 2, optimalMin: 0.8, unit: "%" },
|
|
5808
|
+
kind: "reference-interval",
|
|
5920
5809
|
source: "pns-hemograma-2019"
|
|
5921
5810
|
},
|
|
5922
5811
|
SDMA: {
|
|
5923
5812
|
default: { max: 0.6, min: 0.3, optimalMax: 0.5, optimalMin: 0.3, unit: "umol/L" },
|
|
5813
|
+
kind: "reference-interval",
|
|
5924
5814
|
source: "schwedhelm-sdma-2011"
|
|
5925
5815
|
},
|
|
5926
5816
|
Selenium: {
|
|
5927
5817
|
default: { max: 150, min: 70, optimalMax: 125, optimalMin: 85, unit: "\xB5g/L" },
|
|
5818
|
+
kind: "reference-interval",
|
|
5928
5819
|
source: "tietz-7ed-2015"
|
|
5929
5820
|
},
|
|
5930
5821
|
SHBG: {
|
|
5931
5822
|
default: { max: 54, min: 18, optimalMax: 50, optimalMin: 20, unit: "nmol/L" },
|
|
5823
|
+
kind: "reference-interval",
|
|
5932
5824
|
source: "tietz-7ed-2015",
|
|
5933
5825
|
variants: [
|
|
5934
5826
|
{
|
|
@@ -5945,34 +5837,42 @@ var biomarkerRangeDefinitions = {
|
|
|
5945
5837
|
},
|
|
5946
5838
|
Sodium: {
|
|
5947
5839
|
default: { max: 145, min: 136, optimalMax: 143, optimalMin: 138, unit: "mEq/L" },
|
|
5840
|
+
kind: "reference-interval",
|
|
5948
5841
|
source: "tietz-7ed-2015"
|
|
5949
5842
|
},
|
|
5950
5843
|
SpecificGravity_Urine: {
|
|
5951
5844
|
default: { max: 1.03, min: 1.005, optimalMax: 1.025, optimalMin: 1.01, unit: "SG" },
|
|
5845
|
+
kind: "reference-interval",
|
|
5952
5846
|
source: "tietz-7ed-2015"
|
|
5953
5847
|
},
|
|
5954
5848
|
Stearic_Acid: {
|
|
5955
5849
|
default: { max: 14, min: 8, optimalMax: 12, optimalMin: 10, unit: "%" },
|
|
5850
|
+
kind: "reference-interval",
|
|
5956
5851
|
source: "tietz-7ed-2015"
|
|
5957
5852
|
},
|
|
5958
5853
|
T3Free: {
|
|
5959
5854
|
default: { max: 4.2, min: 2.3, optimalMax: 3.8, optimalMin: 2.8, unit: "pg/mL" },
|
|
5855
|
+
kind: "reference-interval",
|
|
5960
5856
|
source: "tietz-7ed-2015"
|
|
5961
5857
|
},
|
|
5962
5858
|
T3Reverse: {
|
|
5963
5859
|
default: { max: 24, min: 10, optimalMax: 20, optimalMin: 12, unit: "ng/dL" },
|
|
5860
|
+
kind: "reference-interval",
|
|
5964
5861
|
source: "tietz-7ed-2015"
|
|
5965
5862
|
},
|
|
5966
5863
|
T4Free: {
|
|
5967
5864
|
default: { max: 1.8, min: 0.8, optimalMax: 1.5, optimalMin: 1, unit: "ng/dL" },
|
|
5865
|
+
kind: "reference-interval",
|
|
5968
5866
|
source: "tietz-7ed-2015"
|
|
5969
5867
|
},
|
|
5970
5868
|
T4Total: {
|
|
5971
5869
|
default: { max: 12, min: 4.5, optimalMax: 10, optimalMin: 6, unit: "ug/dL" },
|
|
5870
|
+
kind: "reference-interval",
|
|
5972
5871
|
source: "tietz-7ed-2015"
|
|
5973
5872
|
},
|
|
5974
5873
|
Testosterone: {
|
|
5975
5874
|
default: { max: 1e3, min: 300, optimalMax: 800, optimalMin: 500, unit: "ng/dL" },
|
|
5875
|
+
kind: "reference-interval",
|
|
5976
5876
|
source: "tietz-7ed-2015",
|
|
5977
5877
|
variants: [
|
|
5978
5878
|
{
|
|
@@ -5995,12 +5895,14 @@ var biomarkerRangeDefinitions = {
|
|
|
5995
5895
|
},
|
|
5996
5896
|
TestosteroneBioavailable: {
|
|
5997
5897
|
default: { max: 200, min: 50, optimalMax: 150, optimalMin: 80, unit: "ng/dL" },
|
|
5898
|
+
kind: "reference-interval",
|
|
5998
5899
|
source: "tietz-7ed-2015"
|
|
5999
5900
|
},
|
|
6000
5901
|
// TestosteroneFree - using direct immunoassay ranges (Quest/LabCorp standard)
|
|
6001
5902
|
// Previous values (9.3-26.5 pg/mL) were based on equilibrium dialysis method
|
|
6002
5903
|
TestosteroneFree: {
|
|
6003
5904
|
default: { max: 155, min: 35, optimalMax: 120, optimalMin: 50, unit: "pg/mL" },
|
|
5905
|
+
kind: "reference-interval",
|
|
6004
5906
|
source: "tietz-7ed-2015",
|
|
6005
5907
|
variants: [
|
|
6006
5908
|
{
|
|
@@ -6023,22 +5925,27 @@ var biomarkerRangeDefinitions = {
|
|
|
6023
5925
|
},
|
|
6024
5926
|
TIBC: {
|
|
6025
5927
|
default: { max: 370, min: 250, optimalMax: 350, optimalMin: 280, unit: "mcg/dL" },
|
|
5928
|
+
kind: "reference-interval",
|
|
6026
5929
|
source: "tietz-7ed-2015"
|
|
6027
5930
|
},
|
|
6028
5931
|
TotalProtein: {
|
|
6029
5932
|
default: { max: 8.3, min: 6, optimalMax: 7.8, optimalMin: 6.5, unit: "g/dL" },
|
|
5933
|
+
kind: "reference-interval",
|
|
6030
5934
|
source: "tietz-7ed-2015"
|
|
6031
5935
|
},
|
|
6032
5936
|
Trans_Fat_Index: {
|
|
6033
5937
|
default: { max: 1, min: 0, optimalMax: 0.5, optimalMin: 0, unit: "%" },
|
|
5938
|
+
kind: "reference-interval",
|
|
6034
5939
|
source: "tietz-7ed-2015"
|
|
6035
5940
|
},
|
|
6036
5941
|
Transferrin: {
|
|
6037
5942
|
default: { max: 360, min: 200, optimalMax: 340, optimalMin: 220, unit: "mg/dL" },
|
|
5943
|
+
kind: "reference-interval",
|
|
6038
5944
|
source: "tietz-7ed-2015"
|
|
6039
5945
|
},
|
|
6040
5946
|
TransferrinSaturation: {
|
|
6041
5947
|
default: { max: 50, min: 20, optimalMax: 45, optimalMin: 25, unit: "%" },
|
|
5948
|
+
kind: "reference-interval",
|
|
6042
5949
|
source: "tietz-7ed-2015",
|
|
6043
5950
|
variants: [
|
|
6044
5951
|
{
|
|
@@ -6066,16 +5973,19 @@ var biomarkerRangeDefinitions = {
|
|
|
6066
5973
|
unit: "mg/dL"
|
|
6067
5974
|
},
|
|
6068
5975
|
direction: "lower-better",
|
|
5976
|
+
kind: "decision-threshold",
|
|
6069
5977
|
source: "sbc-lipids-2025"
|
|
6070
5978
|
},
|
|
6071
5979
|
// TroponinI: 0.04 ng/mL = percentil 99 (ensaio Siemens TnI-Ultra)
|
|
6072
5980
|
TroponinI: {
|
|
6073
5981
|
default: { max: 0.04, min: 0, optimalMax: 0.02, optimalMin: 0, unit: "ng/mL" },
|
|
5982
|
+
kind: "reference-interval",
|
|
6074
5983
|
source: "keller-tni-2013"
|
|
6075
5984
|
},
|
|
6076
5985
|
// TroponinT: 14 ng/L = percentil 99 hs-cTnT (ensaio Roche Elecsys 5ª geração)
|
|
6077
5986
|
TroponinT: {
|
|
6078
5987
|
default: { max: 14, min: 0, optimalMax: 10, optimalMin: 0, unit: "ng/L" },
|
|
5988
|
+
kind: "reference-interval",
|
|
6079
5989
|
source: "giannitsis-hstnt-2010"
|
|
6080
5990
|
},
|
|
6081
5991
|
// TSH — 0.4–4.0 é a faixa de referência adulta geral. O alvo 2.5 µIU/mL é
|
|
@@ -6085,6 +5995,7 @@ var biomarkerRangeDefinitions = {
|
|
|
6085
5995
|
// expandido (tolerância fisiológica do eixo em idosos, SBEM 2013).
|
|
6086
5996
|
TSH: {
|
|
6087
5997
|
default: { max: 4, min: 0.4, optimalMax: 3, optimalMin: 1, unit: "uIU/mL" },
|
|
5998
|
+
kind: "reference-interval",
|
|
6088
5999
|
source: "sbem-thyroid-2013",
|
|
6089
6000
|
variants: [
|
|
6090
6001
|
// Variantes gestacionais (ATA 2017 / SBEM): supressão fisiológica por hCG
|
|
@@ -6133,10 +6044,12 @@ var biomarkerRangeDefinitions = {
|
|
|
6133
6044
|
// deve ser revisto em biomarkers.ts — ver issue #41.
|
|
6134
6045
|
Urea: {
|
|
6135
6046
|
default: { max: 50, min: 15, optimalMax: 40, optimalMin: 20, unit: "mg/dL" },
|
|
6047
|
+
kind: "reference-interval",
|
|
6136
6048
|
source: "tietz-7ed-2015"
|
|
6137
6049
|
},
|
|
6138
6050
|
UricAcid: {
|
|
6139
6051
|
default: { max: 7, min: 2.5, optimalMax: 5.5, optimalMin: 3, unit: "mg/dL" },
|
|
6052
|
+
kind: "reference-interval",
|
|
6140
6053
|
source: "tietz-7ed-2015",
|
|
6141
6054
|
variants: [
|
|
6142
6055
|
{
|
|
@@ -6153,50 +6066,62 @@ var biomarkerRangeDefinitions = {
|
|
|
6153
6066
|
},
|
|
6154
6067
|
Urobilinogen_Urine: {
|
|
6155
6068
|
default: { max: 1, min: 0.1, optimalMax: 1, optimalMin: 0.1, unit: "mg/dL" },
|
|
6069
|
+
kind: "reference-interval",
|
|
6156
6070
|
source: "tietz-7ed-2015"
|
|
6157
6071
|
},
|
|
6158
6072
|
pH_Urine: {
|
|
6159
6073
|
default: { max: 8, min: 4.5, optimalMax: 7, optimalMin: 5.5, unit: "pH" },
|
|
6074
|
+
kind: "reference-interval",
|
|
6160
6075
|
source: "tietz-7ed-2015"
|
|
6161
6076
|
},
|
|
6162
6077
|
HyalineCasts_Urine: {
|
|
6163
6078
|
default: { max: 2, min: 0, optimalMax: 1, optimalMin: 0, unit: "/LPF" },
|
|
6079
|
+
kind: "reference-interval",
|
|
6164
6080
|
source: "tietz-7ed-2015"
|
|
6165
6081
|
},
|
|
6166
6082
|
RBC_Urine: {
|
|
6167
6083
|
default: { max: 3, min: 0, optimalMax: 1, optimalMin: 0, unit: "/HPF" },
|
|
6084
|
+
kind: "reference-interval",
|
|
6168
6085
|
source: "tietz-7ed-2015"
|
|
6169
6086
|
},
|
|
6170
6087
|
SquamousEpithelial_Urine: {
|
|
6171
6088
|
default: { max: 15, min: 0, optimalMax: 5, optimalMin: 0, unit: "/HPF" },
|
|
6089
|
+
kind: "reference-interval",
|
|
6172
6090
|
source: "tietz-7ed-2015"
|
|
6173
6091
|
},
|
|
6174
6092
|
Leukocytes_Urine: {
|
|
6175
6093
|
default: { max: 5, min: 0, optimalMax: 2, optimalMin: 0, unit: "/HPF" },
|
|
6094
|
+
kind: "reference-interval",
|
|
6176
6095
|
source: "tietz-7ed-2015"
|
|
6177
6096
|
},
|
|
6178
6097
|
Folate: {
|
|
6179
6098
|
default: { max: 20, min: 3.9, optimalMax: 17, optimalMin: 5, unit: "ng/mL" },
|
|
6099
|
+
kind: "reference-interval",
|
|
6180
6100
|
source: "tietz-7ed-2015"
|
|
6181
6101
|
},
|
|
6182
6102
|
VitaminA: {
|
|
6183
6103
|
default: { max: 100, min: 20, optimalMax: 80, optimalMin: 30, unit: "mcg/dL" },
|
|
6104
|
+
kind: "reference-interval",
|
|
6184
6105
|
source: "tietz-7ed-2015"
|
|
6185
6106
|
},
|
|
6186
6107
|
VitaminB1: {
|
|
6187
6108
|
default: { max: 180, min: 70, optimalMax: 150, optimalMin: 80, unit: "nmol/L" },
|
|
6109
|
+
kind: "reference-interval",
|
|
6188
6110
|
source: "tietz-7ed-2015"
|
|
6189
6111
|
},
|
|
6190
6112
|
VitaminB12: {
|
|
6191
6113
|
default: { max: 900, min: 200, optimalMax: 800, optimalMin: 400, unit: "pg/mL" },
|
|
6114
|
+
kind: "reference-interval",
|
|
6192
6115
|
source: "tietz-7ed-2015"
|
|
6193
6116
|
},
|
|
6194
6117
|
VitaminB6: {
|
|
6195
6118
|
default: { max: 50, min: 5, optimalMax: 40, optimalMin: 10, unit: "ng/mL" },
|
|
6119
|
+
kind: "reference-interval",
|
|
6196
6120
|
source: "tietz-7ed-2015"
|
|
6197
6121
|
},
|
|
6198
6122
|
VitaminC: {
|
|
6199
6123
|
default: { max: 2, min: 0.4, optimalMax: 1.5, optimalMin: 0.6, unit: "mg/dL" },
|
|
6124
|
+
kind: "reference-interval",
|
|
6200
6125
|
source: "tietz-7ed-2015"
|
|
6201
6126
|
},
|
|
6202
6127
|
// Vitamina D — posicionamento conjunto SBEM/SBPC-ML 2017:
|
|
@@ -6213,6 +6138,7 @@ var biomarkerRangeDefinitions = {
|
|
|
6213
6138
|
// quando a modelagem de comorbidades chegar ao schema.
|
|
6214
6139
|
VitaminD: {
|
|
6215
6140
|
default: { max: 100, min: 20, optimalMax: 70, optimalMin: 40, unit: "ng/mL" },
|
|
6141
|
+
kind: "decision-threshold",
|
|
6216
6142
|
source: "ferreira-vitd-2017",
|
|
6217
6143
|
variants: [
|
|
6218
6144
|
{
|
|
@@ -6224,10 +6150,12 @@ var biomarkerRangeDefinitions = {
|
|
|
6224
6150
|
},
|
|
6225
6151
|
VitaminD_1_25: {
|
|
6226
6152
|
default: { max: 72, min: 18, optimalMax: 60, optimalMin: 25, unit: "pg/mL" },
|
|
6153
|
+
kind: "reference-interval",
|
|
6227
6154
|
source: "tietz-7ed-2015"
|
|
6228
6155
|
},
|
|
6229
6156
|
VitaminE: {
|
|
6230
6157
|
default: { max: 17, min: 5.5, optimalMax: 14, optimalMin: 7, unit: "mg/L" },
|
|
6158
|
+
kind: "reference-interval",
|
|
6231
6159
|
source: "tietz-7ed-2015"
|
|
6232
6160
|
},
|
|
6233
6161
|
// VLDL — estimado clinicamente via TG/5 (método Friedewald). O corte de
|
|
@@ -6236,30 +6164,34 @@ var biomarkerRangeDefinitions = {
|
|
|
6236
6164
|
// método de cálculo, mas a faixa de referência tem respaldo na diretriz
|
|
6237
6165
|
// SBC 2025.
|
|
6238
6166
|
VLDL: {
|
|
6239
|
-
default: { max: 30, min: 2, optimalMax: 20, optimalMin: 5, unit: "mg/dL" },
|
|
6167
|
+
default: { max: 30, min: 2, minKind: "display", optimalMax: 20, optimalMin: 5, unit: "mg/dL" },
|
|
6168
|
+
kind: "decision-threshold",
|
|
6240
6169
|
source: "sbc-lipids-2025"
|
|
6241
6170
|
},
|
|
6242
6171
|
WBC: {
|
|
6243
6172
|
default: { max: 11, min: 4, optimalMax: 8, optimalMin: 5, unit: "K/uL" },
|
|
6173
|
+
kind: "reference-interval",
|
|
6244
6174
|
source: "pns-hemograma-2019"
|
|
6245
6175
|
},
|
|
6246
6176
|
Zinc: {
|
|
6247
6177
|
default: { max: 120, min: 60, optimalMax: 100, optimalMin: 70, unit: "mcg/dL" },
|
|
6178
|
+
kind: "reference-interval",
|
|
6248
6179
|
source: "tietz-7ed-2015"
|
|
6249
6180
|
},
|
|
6250
6181
|
AndroidFatPct: {
|
|
6251
|
-
default: { max: 35, min: 10, optimalMax: 25, optimalMin: 15, unit: "%" },
|
|
6182
|
+
default: { max: 35, min: 10, minKind: "display", optimalMax: 25, optimalMin: 15, unit: "%" },
|
|
6252
6183
|
direction: "lower-better",
|
|
6184
|
+
kind: "population",
|
|
6253
6185
|
source: "kelly-dxa-2009",
|
|
6254
6186
|
variants: [
|
|
6255
6187
|
{
|
|
6256
6188
|
ageMin: 18,
|
|
6257
|
-
range: { max: 30, min: 10, optimalMax: 22, optimalMin: 12, unit: "%" },
|
|
6189
|
+
range: { max: 30, min: 10, minKind: "display", optimalMax: 22, optimalMin: 12, unit: "%" },
|
|
6258
6190
|
sex: "M"
|
|
6259
6191
|
},
|
|
6260
6192
|
{
|
|
6261
6193
|
ageMin: 18,
|
|
6262
|
-
range: { max: 42, min: 15, optimalMax: 32, optimalMin: 20, unit: "%" },
|
|
6194
|
+
range: { max: 42, min: 15, minKind: "display", optimalMax: 32, optimalMin: 20, unit: "%" },
|
|
6263
6195
|
sex: "F"
|
|
6264
6196
|
}
|
|
6265
6197
|
]
|
|
@@ -6310,6 +6242,7 @@ var biomarkerRangeDefinitions = {
|
|
|
6310
6242
|
CalfCircumference: {
|
|
6311
6243
|
default: { unit: "cm" },
|
|
6312
6244
|
direction: "higher-better",
|
|
6245
|
+
kind: "decision-threshold",
|
|
6313
6246
|
source: "ewgsop2-2019",
|
|
6314
6247
|
// O corte não é específico por sexo na fonte; as duas variantes existem
|
|
6315
6248
|
// porque `RangeVariant` exige o campo, e carregam o mesmo número.
|
|
@@ -6321,38 +6254,76 @@ var biomarkerRangeDefinitions = {
|
|
|
6321
6254
|
WaistToHeightRatio: {
|
|
6322
6255
|
default: { max: 0.5, unit: "" },
|
|
6323
6256
|
direction: "lower-better",
|
|
6257
|
+
kind: "decision-threshold",
|
|
6324
6258
|
source: "browning-ashwell-2010"
|
|
6325
6259
|
},
|
|
6326
6260
|
AndroidGynoidRatio: {
|
|
6327
|
-
default: { max: 1.2, min: 0.5, optimalMax: 1, optimalMin: 0.6, unit: "" },
|
|
6261
|
+
default: { max: 1.2, min: 0.5, minKind: "display", optimalMax: 1, optimalMin: 0.6, unit: "" },
|
|
6328
6262
|
direction: "lower-better",
|
|
6263
|
+
kind: "population",
|
|
6329
6264
|
source: "kelly-dxa-2009",
|
|
6330
6265
|
variants: [
|
|
6331
6266
|
{
|
|
6332
6267
|
ageMin: 18,
|
|
6333
|
-
range: {
|
|
6268
|
+
range: {
|
|
6269
|
+
max: 1.2,
|
|
6270
|
+
min: 0.6,
|
|
6271
|
+
minKind: "display",
|
|
6272
|
+
optimalMax: 1,
|
|
6273
|
+
optimalMin: 0.7,
|
|
6274
|
+
unit: ""
|
|
6275
|
+
},
|
|
6334
6276
|
sex: "M"
|
|
6335
6277
|
},
|
|
6336
6278
|
{
|
|
6337
6279
|
ageMin: 18,
|
|
6338
|
-
range: {
|
|
6280
|
+
range: {
|
|
6281
|
+
max: 1,
|
|
6282
|
+
min: 0.4,
|
|
6283
|
+
minKind: "display",
|
|
6284
|
+
optimalMax: 0.8,
|
|
6285
|
+
optimalMin: 0.5,
|
|
6286
|
+
unit: ""
|
|
6287
|
+
},
|
|
6339
6288
|
sex: "F"
|
|
6340
6289
|
}
|
|
6341
6290
|
]
|
|
6342
6291
|
},
|
|
6343
6292
|
BMC: {
|
|
6344
|
-
default: {
|
|
6293
|
+
default: {
|
|
6294
|
+
max: 3.5,
|
|
6295
|
+
maxKind: "display",
|
|
6296
|
+
min: 2,
|
|
6297
|
+
optimalMax: 3.2,
|
|
6298
|
+
optimalMin: 2.3,
|
|
6299
|
+
unit: "kg"
|
|
6300
|
+
},
|
|
6345
6301
|
direction: "higher-better",
|
|
6302
|
+
kind: "population",
|
|
6346
6303
|
source: "kelly-dxa-2009",
|
|
6347
6304
|
variants: [
|
|
6348
6305
|
{
|
|
6349
6306
|
ageMin: 18,
|
|
6350
|
-
range: {
|
|
6307
|
+
range: {
|
|
6308
|
+
max: 4,
|
|
6309
|
+
maxKind: "display",
|
|
6310
|
+
min: 2.5,
|
|
6311
|
+
optimalMax: 3.5,
|
|
6312
|
+
optimalMin: 2.8,
|
|
6313
|
+
unit: "kg"
|
|
6314
|
+
},
|
|
6351
6315
|
sex: "M"
|
|
6352
6316
|
},
|
|
6353
6317
|
{
|
|
6354
6318
|
ageMin: 18,
|
|
6355
|
-
range: {
|
|
6319
|
+
range: {
|
|
6320
|
+
max: 3,
|
|
6321
|
+
maxKind: "display",
|
|
6322
|
+
min: 1.8,
|
|
6323
|
+
optimalMax: 2.7,
|
|
6324
|
+
optimalMin: 2,
|
|
6325
|
+
unit: "kg"
|
|
6326
|
+
},
|
|
6356
6327
|
sex: "F"
|
|
6357
6328
|
}
|
|
6358
6329
|
]
|
|
@@ -6360,142 +6331,148 @@ var biomarkerRangeDefinitions = {
|
|
|
6360
6331
|
// BodyFatPct — Age-bracketed ranges from Gallagher et al. Am J Clin Nutr 2000;72:694-701
|
|
6361
6332
|
// (PMID: 10966886) and ACSM Guidelines for Exercise Testing, 11th Ed (2021)
|
|
6362
6333
|
BodyFatPct: {
|
|
6363
|
-
default: { max: 30, min: 10, optimalMax: 25, optimalMin: 15, unit: "%" },
|
|
6334
|
+
default: { max: 30, min: 10, minKind: "clinical", optimalMax: 25, optimalMin: 15, unit: "%" },
|
|
6364
6335
|
direction: "lower-better",
|
|
6336
|
+
kind: "decision-threshold",
|
|
6365
6337
|
source: "gallagher-bodyfat-2000",
|
|
6366
6338
|
variants: [
|
|
6367
6339
|
// Men — age brackets
|
|
6368
6340
|
{
|
|
6369
6341
|
ageMax: 25,
|
|
6370
6342
|
ageMin: 18,
|
|
6371
|
-
range: { max: 25, min: 5, optimalMax: 20, optimalMin: 10, unit: "%" },
|
|
6343
|
+
range: { max: 25, min: 5, minKind: "clinical", optimalMax: 20, optimalMin: 10, unit: "%" },
|
|
6372
6344
|
sex: "M"
|
|
6373
6345
|
},
|
|
6374
6346
|
{
|
|
6375
6347
|
ageMax: 35,
|
|
6376
6348
|
ageMin: 26,
|
|
6377
|
-
range: { max: 26, min: 5, optimalMax: 21, optimalMin: 11, unit: "%" },
|
|
6349
|
+
range: { max: 26, min: 5, minKind: "clinical", optimalMax: 21, optimalMin: 11, unit: "%" },
|
|
6378
6350
|
sex: "M"
|
|
6379
6351
|
},
|
|
6380
6352
|
{
|
|
6381
6353
|
ageMax: 45,
|
|
6382
6354
|
ageMin: 36,
|
|
6383
|
-
range: { max: 27, min: 5, optimalMax: 22, optimalMin: 12, unit: "%" },
|
|
6355
|
+
range: { max: 27, min: 5, minKind: "clinical", optimalMax: 22, optimalMin: 12, unit: "%" },
|
|
6384
6356
|
sex: "M"
|
|
6385
6357
|
},
|
|
6386
6358
|
{
|
|
6387
6359
|
ageMax: 55,
|
|
6388
6360
|
ageMin: 46,
|
|
6389
|
-
range: { max: 28, min: 5, optimalMax: 23, optimalMin: 13, unit: "%" },
|
|
6361
|
+
range: { max: 28, min: 5, minKind: "clinical", optimalMax: 23, optimalMin: 13, unit: "%" },
|
|
6390
6362
|
sex: "M"
|
|
6391
6363
|
},
|
|
6392
6364
|
{
|
|
6393
6365
|
ageMin: 56,
|
|
6394
|
-
range: { max: 29, min: 5, optimalMax: 24, optimalMin: 14, unit: "%" },
|
|
6366
|
+
range: { max: 29, min: 5, minKind: "clinical", optimalMax: 24, optimalMin: 14, unit: "%" },
|
|
6395
6367
|
sex: "M"
|
|
6396
6368
|
},
|
|
6397
6369
|
// Women — age brackets
|
|
6398
6370
|
{
|
|
6399
6371
|
ageMax: 25,
|
|
6400
6372
|
ageMin: 18,
|
|
6401
|
-
range: { max: 32, min: 13, optimalMax: 28, optimalMin: 18, unit: "%" },
|
|
6373
|
+
range: { max: 32, min: 13, minKind: "clinical", optimalMax: 28, optimalMin: 18, unit: "%" },
|
|
6402
6374
|
sex: "F"
|
|
6403
6375
|
},
|
|
6404
6376
|
{
|
|
6405
6377
|
ageMax: 35,
|
|
6406
6378
|
ageMin: 26,
|
|
6407
|
-
range: { max: 33, min: 13, optimalMax: 29, optimalMin: 18, unit: "%" },
|
|
6379
|
+
range: { max: 33, min: 13, minKind: "clinical", optimalMax: 29, optimalMin: 18, unit: "%" },
|
|
6408
6380
|
sex: "F"
|
|
6409
6381
|
},
|
|
6410
6382
|
{
|
|
6411
6383
|
ageMax: 45,
|
|
6412
6384
|
ageMin: 36,
|
|
6413
|
-
range: { max: 34, min: 13, optimalMax: 30, optimalMin: 19, unit: "%" },
|
|
6385
|
+
range: { max: 34, min: 13, minKind: "clinical", optimalMax: 30, optimalMin: 19, unit: "%" },
|
|
6414
6386
|
sex: "F"
|
|
6415
6387
|
},
|
|
6416
6388
|
{
|
|
6417
6389
|
ageMax: 55,
|
|
6418
6390
|
ageMin: 46,
|
|
6419
|
-
range: { max: 35, min: 13, optimalMax: 31, optimalMin: 20, unit: "%" },
|
|
6391
|
+
range: { max: 35, min: 13, minKind: "clinical", optimalMax: 31, optimalMin: 20, unit: "%" },
|
|
6420
6392
|
sex: "F"
|
|
6421
6393
|
},
|
|
6422
6394
|
{
|
|
6423
6395
|
ageMin: 56,
|
|
6424
|
-
range: { max: 36, min: 13, optimalMax: 32, optimalMin: 20, unit: "%" },
|
|
6396
|
+
range: { max: 36, min: 13, minKind: "clinical", optimalMax: 32, optimalMin: 20, unit: "%" },
|
|
6425
6397
|
sex: "F"
|
|
6426
6398
|
}
|
|
6427
6399
|
]
|
|
6428
6400
|
},
|
|
6429
6401
|
FatFreeMass: {
|
|
6430
|
-
default: { max: 80, min: 40, optimalMax: 70, optimalMin: 45, unit: "kg" },
|
|
6402
|
+
default: { max: 80, maxKind: "display", min: 40, optimalMax: 70, optimalMin: 45, unit: "kg" },
|
|
6431
6403
|
direction: "higher-better",
|
|
6404
|
+
kind: "population",
|
|
6432
6405
|
source: "kelly-dxa-2009",
|
|
6433
6406
|
variants: [
|
|
6434
6407
|
{
|
|
6435
6408
|
ageMin: 18,
|
|
6436
|
-
range: { max: 90, min: 50, optimalMax: 80, optimalMin: 55, unit: "kg" },
|
|
6409
|
+
range: { max: 90, maxKind: "display", min: 50, optimalMax: 80, optimalMin: 55, unit: "kg" },
|
|
6437
6410
|
sex: "M"
|
|
6438
6411
|
},
|
|
6439
6412
|
{
|
|
6440
6413
|
ageMin: 18,
|
|
6441
|
-
range: { max: 60, min: 35, optimalMax: 52, optimalMin: 38, unit: "kg" },
|
|
6414
|
+
range: { max: 60, maxKind: "display", min: 35, optimalMax: 52, optimalMin: 38, unit: "kg" },
|
|
6442
6415
|
sex: "F"
|
|
6443
6416
|
}
|
|
6444
6417
|
]
|
|
6445
6418
|
},
|
|
6446
6419
|
FatMass: {
|
|
6447
|
-
default: { max: 30, min: 5, optimalMax: 20, optimalMin: 8, unit: "kg" },
|
|
6420
|
+
default: { max: 30, min: 5, minKind: "clinical", optimalMax: 20, optimalMin: 8, unit: "kg" },
|
|
6448
6421
|
direction: "lower-better",
|
|
6422
|
+
kind: "population",
|
|
6449
6423
|
source: "kelly-dxa-2009",
|
|
6450
6424
|
variants: [
|
|
6451
6425
|
{
|
|
6452
6426
|
ageMin: 18,
|
|
6453
|
-
range: { max: 25, min: 5, optimalMax: 18, optimalMin: 7, unit: "kg" },
|
|
6427
|
+
range: { max: 25, min: 5, minKind: "clinical", optimalMax: 18, optimalMin: 7, unit: "kg" },
|
|
6454
6428
|
sex: "M"
|
|
6455
6429
|
},
|
|
6456
6430
|
{
|
|
6457
6431
|
ageMin: 18,
|
|
6458
|
-
range: { max: 30, min: 8, optimalMax: 22, optimalMin: 10, unit: "kg" },
|
|
6432
|
+
range: { max: 30, min: 8, minKind: "clinical", optimalMax: 22, optimalMin: 10, unit: "kg" },
|
|
6459
6433
|
sex: "F"
|
|
6460
6434
|
}
|
|
6461
6435
|
]
|
|
6462
6436
|
},
|
|
6463
6437
|
GynoidFatPct: {
|
|
6464
|
-
default: { max: 45, min: 15, optimalMax: 35, optimalMin: 20, unit: "%" },
|
|
6438
|
+
default: { max: 45, min: 15, minKind: "display", optimalMax: 35, optimalMin: 20, unit: "%" },
|
|
6465
6439
|
direction: "lower-better",
|
|
6440
|
+
kind: "population",
|
|
6466
6441
|
source: "kelly-dxa-2009",
|
|
6467
6442
|
variants: [
|
|
6468
6443
|
{
|
|
6469
6444
|
ageMin: 18,
|
|
6470
|
-
range: { max: 35, min: 12, optimalMax: 28, optimalMin: 15, unit: "%" },
|
|
6445
|
+
range: { max: 35, min: 12, minKind: "display", optimalMax: 28, optimalMin: 15, unit: "%" },
|
|
6471
6446
|
sex: "M"
|
|
6472
6447
|
},
|
|
6473
6448
|
{
|
|
6474
6449
|
ageMin: 18,
|
|
6475
|
-
range: { max: 50, min: 20, optimalMax: 40, optimalMin: 25, unit: "%" },
|
|
6450
|
+
range: { max: 50, min: 20, minKind: "display", optimalMax: 40, optimalMin: 25, unit: "%" },
|
|
6476
6451
|
sex: "F"
|
|
6477
6452
|
}
|
|
6478
6453
|
]
|
|
6479
6454
|
},
|
|
6480
6455
|
LeanMass: {
|
|
6481
|
-
default: { max: 75, min: 35, optimalMax: 65, optimalMin: 40, unit: "kg" },
|
|
6456
|
+
default: { max: 75, maxKind: "display", min: 35, optimalMax: 65, optimalMin: 40, unit: "kg" },
|
|
6482
6457
|
direction: "higher-better",
|
|
6458
|
+
kind: "population",
|
|
6483
6459
|
source: "kelly-dxa-2009",
|
|
6484
6460
|
variants: [
|
|
6485
6461
|
{
|
|
6486
6462
|
ageMin: 18,
|
|
6487
|
-
range: { max: 85, min: 45, optimalMax: 75, optimalMin: 50, unit: "kg" },
|
|
6463
|
+
range: { max: 85, maxKind: "display", min: 45, optimalMax: 75, optimalMin: 50, unit: "kg" },
|
|
6488
6464
|
sex: "M"
|
|
6489
6465
|
},
|
|
6490
6466
|
{
|
|
6491
6467
|
ageMin: 18,
|
|
6492
|
-
range: { max: 55, min: 30, optimalMax: 48, optimalMin: 35, unit: "kg" },
|
|
6468
|
+
range: { max: 55, maxKind: "display", min: 30, optimalMax: 48, optimalMin: 35, unit: "kg" },
|
|
6493
6469
|
sex: "F"
|
|
6494
6470
|
}
|
|
6495
6471
|
]
|
|
6496
6472
|
},
|
|
6497
6473
|
TotalMass: {
|
|
6498
6474
|
default: { max: 100, min: 50, optimalMax: 85, optimalMin: 55, unit: "kg" },
|
|
6475
|
+
kind: "population",
|
|
6499
6476
|
source: "kelly-dxa-2009",
|
|
6500
6477
|
variants: [
|
|
6501
6478
|
{
|
|
@@ -6510,226 +6487,856 @@ var biomarkerRangeDefinitions = {
|
|
|
6510
6487
|
}
|
|
6511
6488
|
]
|
|
6512
6489
|
},
|
|
6513
|
-
VATMass: {
|
|
6514
|
-
default: { max: 1.5, min: 0, optimalMax: 0.8, optimalMin: 0, unit: "kg" },
|
|
6515
|
-
direction: "lower-better",
|
|
6516
|
-
|
|
6490
|
+
VATMass: {
|
|
6491
|
+
default: { max: 1.5, min: 0, optimalMax: 0.8, optimalMin: 0, unit: "kg" },
|
|
6492
|
+
direction: "lower-better",
|
|
6493
|
+
kind: "population",
|
|
6494
|
+
source: "ofenheimer-vat-2020",
|
|
6495
|
+
variants: [
|
|
6496
|
+
{
|
|
6497
|
+
ageMin: 18,
|
|
6498
|
+
range: { max: 1.5, min: 0, optimalMax: 1, optimalMin: 0, unit: "kg" },
|
|
6499
|
+
sex: "M"
|
|
6500
|
+
},
|
|
6501
|
+
{
|
|
6502
|
+
ageMin: 18,
|
|
6503
|
+
range: { max: 1, min: 0, optimalMax: 0.5, optimalMin: 0, unit: "kg" },
|
|
6504
|
+
sex: "F"
|
|
6505
|
+
}
|
|
6506
|
+
]
|
|
6507
|
+
},
|
|
6508
|
+
VATVolume: {
|
|
6509
|
+
default: {
|
|
6510
|
+
max: 852,
|
|
6511
|
+
min: 0,
|
|
6512
|
+
optimalMax: 600,
|
|
6513
|
+
optimalMin: 0,
|
|
6514
|
+
unit: "cm\xB3",
|
|
6515
|
+
warningMax: 1837
|
|
6516
|
+
},
|
|
6517
|
+
direction: "lower-better",
|
|
6518
|
+
kind: "decision-threshold",
|
|
6519
|
+
source: "ge-corescan"
|
|
6520
|
+
},
|
|
6521
|
+
BMD_Total: {
|
|
6522
|
+
default: {
|
|
6523
|
+
max: 1.4,
|
|
6524
|
+
maxKind: "display",
|
|
6525
|
+
min: 0.9,
|
|
6526
|
+
optimalMax: 1.3,
|
|
6527
|
+
optimalMin: 1,
|
|
6528
|
+
unit: "g/cm\xB2"
|
|
6529
|
+
},
|
|
6530
|
+
direction: "higher-better",
|
|
6531
|
+
kind: "decision-threshold",
|
|
6532
|
+
source: "who-osteoporosis-1994"
|
|
6533
|
+
},
|
|
6534
|
+
TScore_Total: {
|
|
6535
|
+
default: {
|
|
6536
|
+
max: 4,
|
|
6537
|
+
maxKind: "display",
|
|
6538
|
+
min: -1,
|
|
6539
|
+
optimalMax: 2,
|
|
6540
|
+
optimalMin: -0.5,
|
|
6541
|
+
unit: ""
|
|
6542
|
+
},
|
|
6543
|
+
direction: "higher-better",
|
|
6544
|
+
kind: "decision-threshold",
|
|
6545
|
+
source: "who-osteoporosis-1994"
|
|
6546
|
+
},
|
|
6547
|
+
ZScore_Total: {
|
|
6548
|
+
default: {
|
|
6549
|
+
max: 2,
|
|
6550
|
+
maxKind: "display",
|
|
6551
|
+
min: -2,
|
|
6552
|
+
optimalMax: 1,
|
|
6553
|
+
optimalMin: -1,
|
|
6554
|
+
unit: ""
|
|
6555
|
+
},
|
|
6556
|
+
direction: "higher-better",
|
|
6557
|
+
kind: "decision-threshold",
|
|
6558
|
+
source: "who-osteoporosis-1994"
|
|
6559
|
+
},
|
|
6560
|
+
Amylase: {
|
|
6561
|
+
default: { max: 100, min: 28, optimalMax: 90, optimalMin: 35, unit: "U/L" },
|
|
6562
|
+
kind: "reference-interval",
|
|
6563
|
+
source: "tietz-7ed-2015"
|
|
6564
|
+
},
|
|
6565
|
+
Creatinine_Urine: {
|
|
6566
|
+
default: { max: 300, min: 20, optimalMax: 250, optimalMin: 40, unit: "mg/dL" },
|
|
6567
|
+
kind: "reference-interval",
|
|
6568
|
+
source: "tietz-7ed-2015",
|
|
6569
|
+
variants: [
|
|
6570
|
+
{
|
|
6571
|
+
ageMin: 18,
|
|
6572
|
+
range: { max: 300, min: 40, optimalMax: 260, optimalMin: 60, unit: "mg/dL" },
|
|
6573
|
+
sex: "M"
|
|
6574
|
+
},
|
|
6575
|
+
{
|
|
6576
|
+
ageMin: 18,
|
|
6577
|
+
range: { max: 220, min: 20, optimalMax: 180, optimalMin: 40, unit: "mg/dL" },
|
|
6578
|
+
sex: "F"
|
|
6579
|
+
}
|
|
6580
|
+
]
|
|
6581
|
+
},
|
|
6582
|
+
IgA: {
|
|
6583
|
+
default: { max: 400, min: 70, optimalMax: 350, optimalMin: 100, unit: "mg/dL" },
|
|
6584
|
+
kind: "reference-interval",
|
|
6585
|
+
source: "tietz-7ed-2015"
|
|
6586
|
+
},
|
|
6587
|
+
Lipase: {
|
|
6588
|
+
default: { max: 60, min: 0, optimalMax: 50, optimalMin: 10, unit: "U/L" },
|
|
6589
|
+
kind: "reference-interval",
|
|
6590
|
+
source: "tietz-7ed-2015"
|
|
6591
|
+
},
|
|
6592
|
+
Microalbumin_Urine: {
|
|
6593
|
+
default: { max: 30, min: 0, optimalMax: 20, optimalMin: 0, unit: "mg/L" },
|
|
6594
|
+
kind: "decision-threshold",
|
|
6595
|
+
source: "kdigo-ckd-2024"
|
|
6596
|
+
},
|
|
6597
|
+
PSA_Free: {
|
|
6598
|
+
default: { max: 1.5, min: 0, optimalMax: 1, optimalMin: 0, unit: "ng/mL" },
|
|
6599
|
+
kind: "reference-interval",
|
|
6600
|
+
source: "sturgeon-nacb-2008"
|
|
6601
|
+
},
|
|
6602
|
+
// Relação PSA livre/total — `higher-better`: razão maior = menor risco de
|
|
6603
|
+
// câncer de próstata, logo não há limite superior "ruim" (acima do normal é
|
|
6604
|
+
// verde). Faixas alinhadas à tabela clínica: ≥25% baixo risco (verde),
|
|
6605
|
+
// 10–25% atenção — intermediário/moderado (âmbar), <10% alto risco >50%
|
|
6606
|
+
// (vermelho). Limites: `min` (25) é o piso do verde e `warningMin` (10) o
|
|
6607
|
+
// piso do âmbar — o vermelho é estritamente abaixo de 10% (< 10%); 10%
|
|
6608
|
+
// pertence ao âmbar, conforme a faixa "10–15% moderado" da tabela.
|
|
6609
|
+
PSA_FreeRatio: {
|
|
6610
|
+
default: {
|
|
6611
|
+
max: 100,
|
|
6612
|
+
maxKind: "display",
|
|
6613
|
+
min: 25,
|
|
6614
|
+
optimalMax: 100,
|
|
6615
|
+
optimalMin: 30,
|
|
6616
|
+
unit: "%",
|
|
6617
|
+
warningMin: 10
|
|
6618
|
+
},
|
|
6619
|
+
direction: "higher-better",
|
|
6620
|
+
kind: "decision-threshold",
|
|
6621
|
+
source: "sturgeon-nacb-2008"
|
|
6622
|
+
},
|
|
6623
|
+
// BMI - WHO classification: 18.5–24.9 normal, 25–29.9 overweight, ≥30 obese
|
|
6624
|
+
BMI: {
|
|
6625
|
+
default: { max: 30, min: 18.5, optimalMax: 24.9, optimalMin: 18.5, unit: "kg/m2" },
|
|
6626
|
+
kind: "decision-threshold",
|
|
6627
|
+
source: "who-obesity-2000"
|
|
6628
|
+
},
|
|
6629
|
+
// eAG — Estimated Average Glucose, derivada da HbA1c pela fórmula ADAG:
|
|
6630
|
+
// eAG (mg/dL) = 28,7 × HbA1c(%) − 46,7 (NATHAN, D. M. et al. Translating the
|
|
6631
|
+
// A1C assay into estimated average glucose values. Diabetes Care, v. 31, n. 8,
|
|
6632
|
+
// p. 1473-1478, 2008. DOI: 10.2337/dc08-0545).
|
|
6633
|
+
//
|
|
6634
|
+
// As faixas espelham os cortes diagnósticos de HbA1c da SBD (ver entrada
|
|
6635
|
+
// `HbA1c`) convertidos por essa fórmula, mantendo a eAG coerente com o
|
|
6636
|
+
// marcador de origem:
|
|
6637
|
+
// optimalMax 105 ← HbA1c 5,3 % (teto do controle ótimo)
|
|
6638
|
+
// max 117 ← HbA1c 5,7 % (teto do não diabético → início do pré-diabetes)
|
|
6639
|
+
// warningMax 137 ← HbA1c 6,4 % (teto do pré-diabetes → acima disso, diabetes)
|
|
6640
|
+
// optimalMin 82 ← HbA1c 4,5 % (piso do alvo fisiológico da entrada HbA1c)
|
|
6641
|
+
// min 11 ← HbA1c 2,0 % (mesmo piso de sanidade da entrada HbA1c)
|
|
6642
|
+
//
|
|
6643
|
+
// O piso era 70 nos dois campos, e não vinha desta conversão: 70 é o limite
|
|
6644
|
+
// inferior clássico da glicemia **de jejum**, transplantado para uma média
|
|
6645
|
+
// estimada de ~3 meses. Pela fórmula, 70 equivale a HbA1c 4,07 % — ou seja,
|
|
6646
|
+
// marcava como alterado exatamente quem a entrada `HbA1c` documenta que não
|
|
6647
|
+
// deve ser sinalizado, já que HbA1c baixa reflete hemólise, perda sanguínea
|
|
6648
|
+
// ou hemoglobinopatia, e não doença do metabolismo glicêmico. Espelhar o piso
|
|
6649
|
+
// do HbA1c mantém as duas entradas coerentes, que é o que o comentário sempre
|
|
6650
|
+
// afirmou fazer.
|
|
6651
|
+
//
|
|
6652
|
+
// Substitui a faixa anterior (optimalMax 126 = corte de glicemia de jejum;
|
|
6653
|
+
// max 154 = meta terapêutica do diabético, HbA1c 7 %), que classificava como
|
|
6654
|
+
// "Normal" valores já pré-diabéticos e diabéticos.
|
|
6655
|
+
eAG: {
|
|
6656
|
+
default: {
|
|
6657
|
+
max: 117,
|
|
6658
|
+
min: 11,
|
|
6659
|
+
minKind: "display",
|
|
6660
|
+
optimalMax: 105,
|
|
6661
|
+
optimalMin: 82,
|
|
6662
|
+
unit: "mg/dL",
|
|
6663
|
+
warningMax: 137
|
|
6664
|
+
},
|
|
6665
|
+
kind: "decision-threshold",
|
|
6666
|
+
source: "sbd-diabetes-2024"
|
|
6667
|
+
},
|
|
6668
|
+
// INR - International Normalized Ratio (non-anticoagulated patients)
|
|
6669
|
+
INR: {
|
|
6670
|
+
default: { max: 1.2, min: 0.8, optimalMax: 1.1, optimalMin: 0.9, unit: "ratio" },
|
|
6671
|
+
kind: "reference-interval",
|
|
6672
|
+
source: "tietz-7ed-2015"
|
|
6673
|
+
},
|
|
6674
|
+
// Prothrombin Time
|
|
6675
|
+
ProthrombinTime: {
|
|
6676
|
+
default: { max: 13.5, min: 11, optimalMax: 13, optimalMin: 11, unit: "seconds" },
|
|
6677
|
+
kind: "reference-interval",
|
|
6678
|
+
source: "tietz-7ed-2015"
|
|
6679
|
+
},
|
|
6680
|
+
// DHT - Dihydrotestosterone (adult male reference; female values are much lower)
|
|
6681
|
+
DHT: {
|
|
6682
|
+
default: { max: 85, min: 30, optimalMax: 85, optimalMin: 30, unit: "ng/dL" },
|
|
6683
|
+
kind: "reference-interval",
|
|
6684
|
+
source: "tietz-7ed-2015",
|
|
6517
6685
|
variants: [
|
|
6518
6686
|
{
|
|
6519
6687
|
ageMin: 18,
|
|
6520
|
-
range: { max:
|
|
6688
|
+
range: { max: 85, min: 30, optimalMax: 85, optimalMin: 30, unit: "ng/dL" },
|
|
6521
6689
|
sex: "M"
|
|
6522
6690
|
},
|
|
6523
6691
|
{
|
|
6524
6692
|
ageMin: 18,
|
|
6525
|
-
range: { max:
|
|
6693
|
+
range: { max: 22, min: 4, optimalMax: 22, optimalMin: 4, unit: "ng/dL" },
|
|
6526
6694
|
sex: "F"
|
|
6527
6695
|
}
|
|
6528
6696
|
]
|
|
6529
6697
|
},
|
|
6530
|
-
|
|
6531
|
-
|
|
6532
|
-
|
|
6533
|
-
min: 0,
|
|
6534
|
-
optimalMax: 600,
|
|
6535
|
-
optimalMin: 0,
|
|
6536
|
-
unit: "cm\xB3",
|
|
6537
|
-
warningMax: 1837
|
|
6538
|
-
},
|
|
6698
|
+
// Total IgE - higher values suggest atopy/allergic sensitization
|
|
6699
|
+
IgE_Total: {
|
|
6700
|
+
default: { max: 100, min: 0, optimalMax: 100, optimalMin: 0, unit: "IU/mL" },
|
|
6539
6701
|
direction: "lower-better",
|
|
6540
|
-
|
|
6541
|
-
|
|
6542
|
-
BMD_Total: {
|
|
6543
|
-
default: { max: 1.4, min: 0.9, optimalMax: 1.3, optimalMin: 1, unit: "g/cm\xB2" },
|
|
6544
|
-
direction: "higher-better",
|
|
6545
|
-
source: "who-osteoporosis-1994"
|
|
6702
|
+
kind: "reference-interval",
|
|
6703
|
+
source: "tietz-7ed-2015"
|
|
6546
6704
|
},
|
|
6547
|
-
|
|
6548
|
-
|
|
6549
|
-
|
|
6550
|
-
|
|
6705
|
+
// IgG - Immunoglobulin G
|
|
6706
|
+
IgG: {
|
|
6707
|
+
default: { max: 1600, min: 700, optimalMax: 1600, optimalMin: 700, unit: "mg/dL" },
|
|
6708
|
+
kind: "reference-interval",
|
|
6709
|
+
source: "tietz-7ed-2015"
|
|
6551
6710
|
},
|
|
6552
|
-
|
|
6553
|
-
|
|
6554
|
-
|
|
6555
|
-
|
|
6711
|
+
// IgE E1 Cat Dander - Class 0 (≤0.35 kU/L) = negative
|
|
6712
|
+
IgE_E1_CatDander: {
|
|
6713
|
+
default: { max: 0.35, min: 0, optimalMax: 0.35, optimalMin: 0, unit: "kU/L" },
|
|
6714
|
+
direction: "lower-better",
|
|
6715
|
+
kind: "decision-threshold",
|
|
6716
|
+
source: "tietz-7ed-2015"
|
|
6556
6717
|
},
|
|
6557
|
-
|
|
6558
|
-
|
|
6718
|
+
// IgE GX1 Grasses - Class 0 (≤0.35 kU/L) = negative
|
|
6719
|
+
IgE_GX1_Grasses: {
|
|
6720
|
+
default: { max: 0.35, min: 0, optimalMax: 0.35, optimalMin: 0, unit: "kU/L" },
|
|
6721
|
+
direction: "lower-better",
|
|
6722
|
+
kind: "decision-threshold",
|
|
6559
6723
|
source: "tietz-7ed-2015"
|
|
6724
|
+
}
|
|
6725
|
+
};
|
|
6726
|
+
var defaultReferenceRanges = Object.fromEntries(
|
|
6727
|
+
Object.entries(biomarkerRangeDefinitions).map(([code, def]) => [
|
|
6728
|
+
code,
|
|
6729
|
+
{
|
|
6730
|
+
...def.default,
|
|
6731
|
+
...def.kind && { kind: def.kind },
|
|
6732
|
+
...def.source && { source: def.source }
|
|
6733
|
+
}
|
|
6734
|
+
])
|
|
6735
|
+
);
|
|
6736
|
+
function getReferenceRange(testCode, context) {
|
|
6737
|
+
const definition = biomarkerRangeDefinitions[testCode];
|
|
6738
|
+
if (!definition) return void 0;
|
|
6739
|
+
const withSource = (range2, kind = definition.kind) => ({
|
|
6740
|
+
...range2,
|
|
6741
|
+
...kind && { kind },
|
|
6742
|
+
...definition.source && { source: definition.source }
|
|
6743
|
+
});
|
|
6744
|
+
if (!context || !definition.variants || definition.variants.length === 0) {
|
|
6745
|
+
return withSource(definition.default);
|
|
6746
|
+
}
|
|
6747
|
+
const { age, biologicalSex, pregnancyTrimester, pregnant } = context;
|
|
6748
|
+
const hasPregnancyVariant = definition.variants.some((v) => v.pregnant === true);
|
|
6749
|
+
for (const variant of definition.variants) {
|
|
6750
|
+
if (variant.pregnant === true) {
|
|
6751
|
+
if (!pregnant) continue;
|
|
6752
|
+
if (variant.pregnancyTrimester !== void 0 && variant.pregnancyTrimester !== pregnancyTrimester) {
|
|
6753
|
+
continue;
|
|
6754
|
+
}
|
|
6755
|
+
} else if (pregnant && hasPregnancyVariant) {
|
|
6756
|
+
continue;
|
|
6757
|
+
}
|
|
6758
|
+
if (variant.sex !== "all" && variant.sex !== biologicalSex) {
|
|
6759
|
+
continue;
|
|
6760
|
+
}
|
|
6761
|
+
if (variant.ageMin !== void 0 && (age === void 0 || age < variant.ageMin)) {
|
|
6762
|
+
continue;
|
|
6763
|
+
}
|
|
6764
|
+
if (variant.ageMax !== void 0 && (age === void 0 || age > variant.ageMax)) {
|
|
6765
|
+
continue;
|
|
6766
|
+
}
|
|
6767
|
+
return withSource(variant.range, variant.kind ?? definition.kind);
|
|
6768
|
+
}
|
|
6769
|
+
return withSource(definition.default);
|
|
6770
|
+
}
|
|
6771
|
+
function getRangeDirection(testCode) {
|
|
6772
|
+
return biomarkerRangeDefinitions[testCode]?.direction ?? "range";
|
|
6773
|
+
}
|
|
6774
|
+
function referenceRangeMeaning(kind) {
|
|
6775
|
+
const system = "http://terminology.hl7.org/CodeSystem/referencerange-meaning";
|
|
6776
|
+
if (kind === "reference-interval") return { code: "normal", display: "Normal Range", system };
|
|
6777
|
+
if (kind === "decision-threshold") {
|
|
6778
|
+
return { code: "recommended", display: "Recommended Range", system };
|
|
6779
|
+
}
|
|
6780
|
+
return void 0;
|
|
6781
|
+
}
|
|
6782
|
+
|
|
6783
|
+
// src/converter.ts
|
|
6784
|
+
function interpretationCode(flag) {
|
|
6785
|
+
switch (flag) {
|
|
6786
|
+
case "H":
|
|
6787
|
+
return "H";
|
|
6788
|
+
// High
|
|
6789
|
+
case "L":
|
|
6790
|
+
return "L";
|
|
6791
|
+
// Low
|
|
6792
|
+
default:
|
|
6793
|
+
return "N";
|
|
6794
|
+
}
|
|
6795
|
+
}
|
|
6796
|
+
function interpretationDisplay(flag) {
|
|
6797
|
+
switch (flag) {
|
|
6798
|
+
case "H":
|
|
6799
|
+
return "High";
|
|
6800
|
+
case "L":
|
|
6801
|
+
return "Low";
|
|
6802
|
+
default:
|
|
6803
|
+
return "Normal";
|
|
6804
|
+
}
|
|
6805
|
+
}
|
|
6806
|
+
var SEX_CODING = {
|
|
6807
|
+
female: {
|
|
6808
|
+
code: "female",
|
|
6809
|
+
display: "Female",
|
|
6810
|
+
system: "http://hl7.org/fhir/administrative-gender"
|
|
6560
6811
|
},
|
|
6561
|
-
|
|
6562
|
-
|
|
6563
|
-
|
|
6564
|
-
|
|
6812
|
+
male: { code: "male", display: "Male", system: "http://hl7.org/fhir/administrative-gender" }
|
|
6813
|
+
};
|
|
6814
|
+
var buildReferenceRanges = (observation, quantity) => {
|
|
6815
|
+
const toRanges = (low, high, sex) => {
|
|
6816
|
+
if (low === void 0 && high === void 0) return [];
|
|
6817
|
+
return [
|
|
6565
6818
|
{
|
|
6566
|
-
|
|
6567
|
-
|
|
6568
|
-
|
|
6569
|
-
}
|
|
6819
|
+
...sex === void 0 ? {} : { appliesTo: [{ coding: [SEX_CODING[sex]] }] },
|
|
6820
|
+
...high === void 0 ? {} : { high: quantity(high) },
|
|
6821
|
+
...low === void 0 ? {} : { low: quantity(low) }
|
|
6822
|
+
}
|
|
6823
|
+
];
|
|
6824
|
+
};
|
|
6825
|
+
if (observation.referenceRanges && observation.referenceRanges.length > 0) {
|
|
6826
|
+
return observation.referenceRanges.flatMap((r) => toRanges(r.low, r.high, r.appliesTo));
|
|
6827
|
+
}
|
|
6828
|
+
const meaning = observation.referenceKind && referenceRangeMeaning(observation.referenceKind);
|
|
6829
|
+
return toRanges(observation.referenceMin, observation.referenceMax).map(
|
|
6830
|
+
(range2) => meaning ? { ...range2, type: { coding: [meaning] } } : range2
|
|
6831
|
+
);
|
|
6832
|
+
};
|
|
6833
|
+
function labObservationToFHIR(observation, patientId, laboratoryName) {
|
|
6834
|
+
const loincCode = codeToLoinc(observation.biomarkerCode);
|
|
6835
|
+
const sourceUnit = observation.unit || getDefaultUnit(observation.biomarkerCode) || observation.unit;
|
|
6836
|
+
const ucumUnit = resolveUcum(sourceUnit, observation.biomarkerCode);
|
|
6837
|
+
const quantity = (value) => ({
|
|
6838
|
+
...ucumUnit ? { code: ucumUnit, system: "http://unitsofmeasure.org" } : {},
|
|
6839
|
+
...sourceUnit ? { unit: sourceUnit } : {},
|
|
6840
|
+
value
|
|
6841
|
+
});
|
|
6842
|
+
const isQualitative = observation.isQualitative || typeof observation.value === "string";
|
|
6843
|
+
const fhirObs = {
|
|
6844
|
+
category: [
|
|
6845
|
+
{
|
|
6846
|
+
coding: [
|
|
6847
|
+
{
|
|
6848
|
+
code: "laboratory",
|
|
6849
|
+
display: "Laboratory",
|
|
6850
|
+
system: "http://terminology.hl7.org/CodeSystem/observation-category"
|
|
6851
|
+
}
|
|
6852
|
+
]
|
|
6853
|
+
}
|
|
6854
|
+
],
|
|
6855
|
+
code: {
|
|
6856
|
+
// Sem LOINC, o coding LOINC simplesmente não sai. Antes ia `99999-9`,
|
|
6857
|
+
// que não é código LOINC nenhum: publicava sob `http://loinc.org` uma
|
|
6858
|
+
// afirmação falsa, e quem consumisse o bundle confiando no system
|
|
6859
|
+
// trataria aquilo como código de verdade. Composição corporal, densidade
|
|
6860
|
+
// óssea e escore de cálcio não têm LOINC, e o certo é a lacuna explícita.
|
|
6861
|
+
coding: [
|
|
6862
|
+
...loincCode ? [
|
|
6863
|
+
{
|
|
6864
|
+
code: loincCode,
|
|
6865
|
+
display: observation.biomarkerName,
|
|
6866
|
+
system: LOINC_SYSTEM
|
|
6867
|
+
}
|
|
6868
|
+
] : [],
|
|
6869
|
+
{
|
|
6870
|
+
code: observation.biomarkerCode,
|
|
6871
|
+
display: observation.biomarkerName,
|
|
6872
|
+
system: BIOMARKER_CODE_SYSTEM
|
|
6873
|
+
}
|
|
6874
|
+
],
|
|
6875
|
+
text: observation.biomarkerName
|
|
6876
|
+
},
|
|
6877
|
+
effectiveDateTime: observation.collectionDate,
|
|
6878
|
+
id: `${observation.reportId}-${observation.biomarkerCode}`,
|
|
6879
|
+
interpretation: [
|
|
6880
|
+
{
|
|
6881
|
+
coding: [
|
|
6882
|
+
{
|
|
6883
|
+
code: interpretationCode(observation.flag),
|
|
6884
|
+
display: interpretationDisplay(observation.flag),
|
|
6885
|
+
system: "http://terminology.hl7.org/CodeSystem/v3-ObservationInterpretation"
|
|
6886
|
+
}
|
|
6887
|
+
]
|
|
6888
|
+
}
|
|
6889
|
+
],
|
|
6890
|
+
performer: laboratoryName ? [{ display: laboratoryName }] : void 0,
|
|
6891
|
+
resourceType: "Observation",
|
|
6892
|
+
status: "final",
|
|
6893
|
+
subject: {
|
|
6894
|
+
reference: `Patient/${patientId}`
|
|
6895
|
+
}
|
|
6896
|
+
};
|
|
6897
|
+
if (isQualitative) {
|
|
6898
|
+
fhirObs.valueString = String(observation.value);
|
|
6899
|
+
} else {
|
|
6900
|
+
fhirObs.valueQuantity = quantity(observation.value);
|
|
6901
|
+
const referenceRange = buildReferenceRanges(observation, quantity);
|
|
6902
|
+
if (referenceRange.length > 0) fhirObs.referenceRange = referenceRange;
|
|
6903
|
+
}
|
|
6904
|
+
return fhirObs;
|
|
6905
|
+
}
|
|
6906
|
+
function labReportToFHIR(report, patientId, observationIds) {
|
|
6907
|
+
let status;
|
|
6908
|
+
switch (report.processingStatus) {
|
|
6909
|
+
case "complete":
|
|
6910
|
+
status = "final";
|
|
6911
|
+
break;
|
|
6912
|
+
case "partial":
|
|
6913
|
+
status = "partial";
|
|
6914
|
+
break;
|
|
6915
|
+
case "pending_review":
|
|
6916
|
+
status = "preliminary";
|
|
6917
|
+
break;
|
|
6918
|
+
default:
|
|
6919
|
+
status = "final";
|
|
6920
|
+
}
|
|
6921
|
+
return {
|
|
6922
|
+
category: [
|
|
6923
|
+
{
|
|
6924
|
+
coding: [
|
|
6925
|
+
{
|
|
6926
|
+
code: "LAB",
|
|
6927
|
+
display: "Laboratory",
|
|
6928
|
+
system: "http://terminology.hl7.org/CodeSystem/v2-0074"
|
|
6929
|
+
}
|
|
6930
|
+
]
|
|
6931
|
+
}
|
|
6932
|
+
],
|
|
6933
|
+
code: {
|
|
6934
|
+
coding: [
|
|
6935
|
+
{
|
|
6936
|
+
code: "11502-2",
|
|
6937
|
+
// Laboratory report
|
|
6938
|
+
display: "Laboratory report",
|
|
6939
|
+
system: "http://loinc.org"
|
|
6940
|
+
}
|
|
6941
|
+
],
|
|
6942
|
+
text: "Laboratory Results"
|
|
6943
|
+
},
|
|
6944
|
+
conclusion: report.overallStatus === "NORMAL" ? "All results within normal limits" : "One or more abnormal results detected",
|
|
6945
|
+
conclusionCode: report.overallStatus === "ANORMAL" ? [
|
|
6570
6946
|
{
|
|
6571
|
-
|
|
6572
|
-
|
|
6573
|
-
|
|
6947
|
+
coding: [
|
|
6948
|
+
{
|
|
6949
|
+
code: "A",
|
|
6950
|
+
display: "Abnormal",
|
|
6951
|
+
system: "http://terminology.hl7.org/CodeSystem/v3-ObservationInterpretation"
|
|
6952
|
+
}
|
|
6953
|
+
]
|
|
6574
6954
|
}
|
|
6575
|
-
]
|
|
6576
|
-
|
|
6577
|
-
|
|
6578
|
-
|
|
6579
|
-
|
|
6580
|
-
|
|
6581
|
-
|
|
6582
|
-
|
|
6583
|
-
|
|
6584
|
-
|
|
6585
|
-
|
|
6586
|
-
|
|
6587
|
-
|
|
6588
|
-
|
|
6589
|
-
|
|
6590
|
-
|
|
6591
|
-
|
|
6592
|
-
|
|
6593
|
-
|
|
6594
|
-
// câncer de próstata, logo não há limite superior "ruim" (acima do normal é
|
|
6595
|
-
// verde). Faixas alinhadas à tabela clínica: ≥25% baixo risco (verde),
|
|
6596
|
-
// 10–25% atenção — intermediário/moderado (âmbar), <10% alto risco >50%
|
|
6597
|
-
// (vermelho). Limites: `min` (25) é o piso do verde e `warningMin` (10) o
|
|
6598
|
-
// piso do âmbar — o vermelho é estritamente abaixo de 10% (< 10%); 10%
|
|
6599
|
-
// pertence ao âmbar, conforme a faixa "10–15% moderado" da tabela.
|
|
6600
|
-
PSA_FreeRatio: {
|
|
6601
|
-
default: { max: 100, min: 25, optimalMax: 100, optimalMin: 30, unit: "%", warningMin: 10 },
|
|
6602
|
-
direction: "higher-better",
|
|
6603
|
-
source: "sturgeon-nacb-2008"
|
|
6604
|
-
},
|
|
6605
|
-
// BMI - WHO classification: 18.5–24.9 normal, 25–29.9 overweight, ≥30 obese
|
|
6606
|
-
BMI: {
|
|
6607
|
-
default: { max: 30, min: 18.5, optimalMax: 24.9, optimalMin: 18.5, unit: "kg/m2" },
|
|
6608
|
-
source: "who-obesity-2000"
|
|
6609
|
-
},
|
|
6610
|
-
// eAG — Estimated Average Glucose, derivada da HbA1c pela fórmula ADAG:
|
|
6611
|
-
// eAG (mg/dL) = 28,7 × HbA1c(%) − 46,7 (NATHAN, D. M. et al. Translating the
|
|
6612
|
-
// A1C assay into estimated average glucose values. Diabetes Care, v. 31, n. 8,
|
|
6613
|
-
// p. 1473-1478, 2008. DOI: 10.2337/dc08-0545).
|
|
6614
|
-
//
|
|
6615
|
-
// As faixas espelham os cortes diagnósticos de HbA1c da SBD (ver entrada
|
|
6616
|
-
// `HbA1c`) convertidos por essa fórmula, mantendo a eAG coerente com o
|
|
6617
|
-
// marcador de origem:
|
|
6618
|
-
// optimalMax 105 ← HbA1c 5,3 % (teto do controle ótimo)
|
|
6619
|
-
// max 117 ← HbA1c 5,7 % (teto do não diabético → início do pré-diabetes)
|
|
6620
|
-
// warningMax 137 ← HbA1c 6,4 % (teto do pré-diabetes → acima disso, diabetes)
|
|
6621
|
-
// optimalMin 82 ← HbA1c 4,5 % (piso do alvo fisiológico da entrada HbA1c)
|
|
6622
|
-
// min 11 ← HbA1c 2,0 % (mesmo piso de sanidade da entrada HbA1c)
|
|
6623
|
-
//
|
|
6624
|
-
// O piso era 70 nos dois campos, e não vinha desta conversão: 70 é o limite
|
|
6625
|
-
// inferior clássico da glicemia **de jejum**, transplantado para uma média
|
|
6626
|
-
// estimada de ~3 meses. Pela fórmula, 70 equivale a HbA1c 4,07 % — ou seja,
|
|
6627
|
-
// marcava como alterado exatamente quem a entrada `HbA1c` documenta que não
|
|
6628
|
-
// deve ser sinalizado, já que HbA1c baixa reflete hemólise, perda sanguínea
|
|
6629
|
-
// ou hemoglobinopatia, e não doença do metabolismo glicêmico. Espelhar o piso
|
|
6630
|
-
// do HbA1c mantém as duas entradas coerentes, que é o que o comentário sempre
|
|
6631
|
-
// afirmou fazer.
|
|
6632
|
-
//
|
|
6633
|
-
// Substitui a faixa anterior (optimalMax 126 = corte de glicemia de jejum;
|
|
6634
|
-
// max 154 = meta terapêutica do diabético, HbA1c 7 %), que classificava como
|
|
6635
|
-
// "Normal" valores já pré-diabéticos e diabéticos.
|
|
6636
|
-
eAG: {
|
|
6637
|
-
default: { max: 117, min: 11, optimalMax: 105, optimalMin: 82, unit: "mg/dL", warningMax: 137 },
|
|
6638
|
-
source: "sbd-diabetes-2024"
|
|
6639
|
-
},
|
|
6640
|
-
// INR - International Normalized Ratio (non-anticoagulated patients)
|
|
6641
|
-
INR: {
|
|
6642
|
-
default: { max: 1.2, min: 0.8, optimalMax: 1.1, optimalMin: 0.9, unit: "ratio" },
|
|
6643
|
-
source: "tietz-7ed-2015"
|
|
6644
|
-
},
|
|
6645
|
-
// Prothrombin Time
|
|
6646
|
-
ProthrombinTime: {
|
|
6647
|
-
default: { max: 13.5, min: 11, optimalMax: 13, optimalMin: 11, unit: "seconds" },
|
|
6648
|
-
source: "tietz-7ed-2015"
|
|
6649
|
-
},
|
|
6650
|
-
// DHT - Dihydrotestosterone (adult male reference; female values are much lower)
|
|
6651
|
-
DHT: {
|
|
6652
|
-
default: { max: 85, min: 30, optimalMax: 85, optimalMin: 30, unit: "ng/dL" },
|
|
6653
|
-
source: "tietz-7ed-2015",
|
|
6654
|
-
variants: [
|
|
6955
|
+
] : void 0,
|
|
6956
|
+
effectiveDateTime: report.collectionDate,
|
|
6957
|
+
id: report.reportId,
|
|
6958
|
+
issued: report.createdAt,
|
|
6959
|
+
performer: report.laboratoryName ? [{ display: report.laboratoryName }] : void 0,
|
|
6960
|
+
resourceType: "DiagnosticReport",
|
|
6961
|
+
result: observationIds.map((id) => ({ reference: `Observation/${id}` })),
|
|
6962
|
+
status,
|
|
6963
|
+
subject: {
|
|
6964
|
+
reference: `Patient/${patientId}`
|
|
6965
|
+
}
|
|
6966
|
+
};
|
|
6967
|
+
}
|
|
6968
|
+
function userProfileToFHIR(profile) {
|
|
6969
|
+
const nameParts = profile.name.split(" ");
|
|
6970
|
+
const given = nameParts.slice(0, -1);
|
|
6971
|
+
const family = nameParts[nameParts.length - 1] || "";
|
|
6972
|
+
return {
|
|
6973
|
+
address: profile.address ? [
|
|
6655
6974
|
{
|
|
6656
|
-
|
|
6657
|
-
|
|
6658
|
-
|
|
6659
|
-
|
|
6975
|
+
city: profile.address.city,
|
|
6976
|
+
country: profile.address.country || "BR",
|
|
6977
|
+
line: [
|
|
6978
|
+
profile.address.street && profile.address.number ? `${profile.address.street}, ${profile.address.number}` : profile.address.street,
|
|
6979
|
+
profile.address.complement
|
|
6980
|
+
].filter(Boolean),
|
|
6981
|
+
postalCode: profile.address.postalCode,
|
|
6982
|
+
state: profile.address.state
|
|
6983
|
+
}
|
|
6984
|
+
] : void 0,
|
|
6985
|
+
birthDate: profile.birthDate,
|
|
6986
|
+
gender: profile.gender,
|
|
6987
|
+
id: profile.userId,
|
|
6988
|
+
name: [
|
|
6660
6989
|
{
|
|
6661
|
-
|
|
6662
|
-
|
|
6663
|
-
|
|
6990
|
+
family,
|
|
6991
|
+
given: given.length > 0 ? given : void 0,
|
|
6992
|
+
text: profile.name
|
|
6664
6993
|
}
|
|
6665
|
-
]
|
|
6666
|
-
|
|
6667
|
-
|
|
6668
|
-
|
|
6669
|
-
|
|
6670
|
-
|
|
6671
|
-
|
|
6672
|
-
|
|
6673
|
-
|
|
6674
|
-
|
|
6675
|
-
|
|
6676
|
-
|
|
6677
|
-
|
|
6678
|
-
|
|
6679
|
-
|
|
6680
|
-
|
|
6681
|
-
|
|
6682
|
-
|
|
6683
|
-
|
|
6684
|
-
|
|
6685
|
-
|
|
6686
|
-
|
|
6687
|
-
|
|
6688
|
-
|
|
6994
|
+
],
|
|
6995
|
+
resourceType: "Patient",
|
|
6996
|
+
telecom: [
|
|
6997
|
+
...profile.email ? [{ system: "email", value: profile.email }] : [],
|
|
6998
|
+
...profile.phone ? [{ system: "phone", value: profile.phone }] : []
|
|
6999
|
+
].length > 0 ? [
|
|
7000
|
+
...profile.email ? [{ system: "email", value: profile.email }] : [],
|
|
7001
|
+
...profile.phone ? [{ system: "phone", value: profile.phone }] : []
|
|
7002
|
+
] : void 0
|
|
7003
|
+
};
|
|
7004
|
+
}
|
|
7005
|
+
function labResultToFHIRBundle(report, observations, userProfile) {
|
|
7006
|
+
const patientId = userProfile.userId;
|
|
7007
|
+
const fhirObservations = observations.map((obs) => {
|
|
7008
|
+
const resource = labObservationToFHIR(
|
|
7009
|
+
{ ...obs, collectionDate: report.collectionDate },
|
|
7010
|
+
patientId,
|
|
7011
|
+
report.laboratoryName
|
|
7012
|
+
);
|
|
7013
|
+
return { fullUrl: entryFullUrl(resource), resource };
|
|
7014
|
+
});
|
|
7015
|
+
const observationIds = fhirObservations.map((entry) => entry.resource.id);
|
|
7016
|
+
const diagnosticReport = labReportToFHIR(report, patientId, observationIds);
|
|
7017
|
+
const fhirPatient = userProfileToFHIR(userProfile);
|
|
7018
|
+
return {
|
|
7019
|
+
entry: [
|
|
7020
|
+
{ fullUrl: entryFullUrl(fhirPatient), resource: fhirPatient },
|
|
7021
|
+
{ fullUrl: entryFullUrl(diagnosticReport), resource: diagnosticReport },
|
|
7022
|
+
...fhirObservations
|
|
7023
|
+
],
|
|
7024
|
+
resourceType: "Bundle",
|
|
7025
|
+
type: "collection"
|
|
7026
|
+
};
|
|
7027
|
+
}
|
|
7028
|
+
|
|
7029
|
+
// src/cli/commands/convert.ts
|
|
7030
|
+
async function convert(args, json) {
|
|
7031
|
+
const raw = await getInput(args[0]);
|
|
7032
|
+
const data = parseJson(
|
|
7033
|
+
raw,
|
|
7034
|
+
"JSON inv\xE1lido. Forne\xE7a um objeto com { report, observations, profile }."
|
|
7035
|
+
);
|
|
7036
|
+
if (!data.report || !data.observations || !data.profile) {
|
|
7037
|
+
exitWithError(
|
|
7038
|
+
'Formato esperado: { "report": LabReportData, "observations": LabObservationData[], "profile": UserProfileData }'
|
|
7039
|
+
);
|
|
6689
7040
|
}
|
|
6690
|
-
|
|
6691
|
-
|
|
6692
|
-
|
|
6693
|
-
|
|
6694
|
-
|
|
6695
|
-
|
|
6696
|
-
|
|
6697
|
-
|
|
6698
|
-
|
|
6699
|
-
|
|
6700
|
-
const
|
|
6701
|
-
if (!
|
|
6702
|
-
|
|
7041
|
+
const bundle = labResultToFHIRBundle(data.report, data.observations, data.profile);
|
|
7042
|
+
if (json) {
|
|
7043
|
+
outputJson(bundle);
|
|
7044
|
+
} else {
|
|
7045
|
+
outputText(JSON.stringify(bundle, null, 2));
|
|
7046
|
+
}
|
|
7047
|
+
}
|
|
7048
|
+
|
|
7049
|
+
// src/validators.ts
|
|
7050
|
+
function validateFHIRImportBundle(data) {
|
|
7051
|
+
const errors = [];
|
|
7052
|
+
if (!data || typeof data !== "object") {
|
|
7053
|
+
errors.push({ details: "Input must be a JSON object", field: "root" });
|
|
7054
|
+
return errors;
|
|
7055
|
+
}
|
|
7056
|
+
const bundle = data;
|
|
7057
|
+
if (bundle.resourceType !== "Bundle") {
|
|
7058
|
+
errors.push({
|
|
7059
|
+
details: `Expected resourceType "Bundle", got "${String(bundle.resourceType)}"`,
|
|
7060
|
+
field: "resourceType"
|
|
7061
|
+
});
|
|
7062
|
+
}
|
|
7063
|
+
if (!Array.isArray(bundle.entry)) {
|
|
7064
|
+
errors.push({ details: 'Bundle must contain an "entry" array', field: "entry" });
|
|
7065
|
+
} else if (bundle.entry.length === 0) {
|
|
7066
|
+
errors.push({ details: "Bundle entry array is empty", field: "entry" });
|
|
7067
|
+
}
|
|
7068
|
+
return errors;
|
|
7069
|
+
}
|
|
7070
|
+
|
|
7071
|
+
// src/importer.ts
|
|
7072
|
+
var MAX_OBSERVATIONS = 5e3;
|
|
7073
|
+
var MAX_FILE_SIZE = 15 * 1024 * 1024;
|
|
7074
|
+
function resolveBiomarkerCode(observation) {
|
|
7075
|
+
const coding = observation.code?.coding ?? [];
|
|
7076
|
+
const loincCode = coding.find((c) => c.system === LOINC_SYSTEM)?.code;
|
|
7077
|
+
const declaredCode = coding.find((c) => c.system === BIOMARKER_CODE_SYSTEM)?.code;
|
|
7078
|
+
const seenCodes = [
|
|
7079
|
+
...loincCode ? [`LOINC ${loincCode}`] : [],
|
|
7080
|
+
...declaredCode ? [`biomarker code ${declaredCode}`] : []
|
|
7081
|
+
];
|
|
7082
|
+
let reason;
|
|
7083
|
+
if (seenCodes.length > 0) {
|
|
7084
|
+
reason = `Unknown code: ${seenCodes.join(", ")}`;
|
|
7085
|
+
} else if (coding.length > 0) {
|
|
7086
|
+
const systems = [...new Set(coding.map((c) => c.system ?? "(sem system)"))];
|
|
7087
|
+
reason = `No code in a supported system (found: ${systems.join(", ")})`;
|
|
7088
|
+
} else {
|
|
7089
|
+
reason = "No code found in observation coding";
|
|
6703
7090
|
}
|
|
6704
|
-
const
|
|
6705
|
-
|
|
6706
|
-
|
|
6707
|
-
|
|
6708
|
-
|
|
6709
|
-
|
|
6710
|
-
|
|
6711
|
-
|
|
6712
|
-
|
|
7091
|
+
const fromLoinc = loincCode ? loincToCode(loincCode) : void 0;
|
|
7092
|
+
if (fromLoinc) return { internalCode: fromLoinc, loincCode, reason };
|
|
7093
|
+
if (declaredCode && isValidCode(declaredCode)) {
|
|
7094
|
+
const canonical = normalizeCode(declaredCode);
|
|
7095
|
+
return { internalCode: canonical, loincCode: codeToLoinc(canonical), reason };
|
|
7096
|
+
}
|
|
7097
|
+
return { loincCode, reason };
|
|
7098
|
+
}
|
|
7099
|
+
function extractFlag(observation) {
|
|
7100
|
+
const code = observation.interpretation?.[0]?.coding?.[0]?.code;
|
|
7101
|
+
if (code === "H" || code === "HH") return "H";
|
|
7102
|
+
if (code === "L" || code === "LL") return "L";
|
|
7103
|
+
return "";
|
|
7104
|
+
}
|
|
7105
|
+
function extractObservationsFromBundle(bundle) {
|
|
7106
|
+
const observations = [];
|
|
7107
|
+
const skipped = [];
|
|
7108
|
+
for (let i = 0; i < bundle.entry.length; i++) {
|
|
7109
|
+
const entry = bundle.entry[i];
|
|
7110
|
+
if (!entry.resource) {
|
|
7111
|
+
skipped.push({ index: i, reason: "Entry has no resource" });
|
|
6713
7112
|
continue;
|
|
6714
7113
|
}
|
|
6715
|
-
if (
|
|
7114
|
+
if (entry.resource.resourceType !== "Observation") {
|
|
6716
7115
|
continue;
|
|
6717
7116
|
}
|
|
6718
|
-
if (
|
|
7117
|
+
if (observations.length >= MAX_OBSERVATIONS) {
|
|
7118
|
+
skipped.push({ index: i, reason: `Maximum of ${MAX_OBSERVATIONS} observations exceeded` });
|
|
6719
7119
|
continue;
|
|
6720
7120
|
}
|
|
6721
|
-
|
|
6722
|
-
|
|
7121
|
+
observations.push(entry.resource);
|
|
7122
|
+
}
|
|
7123
|
+
return { observations, skipped };
|
|
7124
|
+
}
|
|
7125
|
+
function mapFHIRObservationToInternal(observation, index) {
|
|
7126
|
+
const { internalCode, loincCode, reason } = resolveBiomarkerCode(observation);
|
|
7127
|
+
if (!internalCode) {
|
|
7128
|
+
return {
|
|
7129
|
+
skipped: { index, loincCode, reason, resourceType: "Observation" }
|
|
7130
|
+
};
|
|
7131
|
+
}
|
|
7132
|
+
const definition = getDefinitionByCode(internalCode);
|
|
7133
|
+
let value;
|
|
7134
|
+
let unit = "";
|
|
7135
|
+
let isQualitative = false;
|
|
7136
|
+
if (observation.valueQuantity?.value !== void 0) {
|
|
7137
|
+
value = observation.valueQuantity.value;
|
|
7138
|
+
unit = observation.valueQuantity.unit || observation.valueQuantity.code || "";
|
|
7139
|
+
} else if (observation.valueString) {
|
|
7140
|
+
value = observation.valueString;
|
|
7141
|
+
isQualitative = true;
|
|
7142
|
+
} else {
|
|
7143
|
+
return {
|
|
7144
|
+
skipped: {
|
|
7145
|
+
index,
|
|
7146
|
+
loincCode,
|
|
7147
|
+
reason: "Observation has no value (valueQuantity or valueString)",
|
|
7148
|
+
resourceType: "Observation"
|
|
7149
|
+
}
|
|
7150
|
+
};
|
|
7151
|
+
}
|
|
7152
|
+
const collectionDate = observation.effectiveDateTime || observation.effectivePeriod?.start || "";
|
|
7153
|
+
if (!collectionDate) {
|
|
7154
|
+
return {
|
|
7155
|
+
skipped: {
|
|
7156
|
+
index,
|
|
7157
|
+
loincCode,
|
|
7158
|
+
reason: "Observation has no effectiveDateTime or effectivePeriod.start",
|
|
7159
|
+
resourceType: "Observation"
|
|
7160
|
+
}
|
|
7161
|
+
};
|
|
7162
|
+
}
|
|
7163
|
+
let referenceMin;
|
|
7164
|
+
let referenceMax;
|
|
7165
|
+
let referenceKind;
|
|
7166
|
+
if (observation.referenceRange?.[0]) {
|
|
7167
|
+
referenceMin = observation.referenceRange[0].low?.value;
|
|
7168
|
+
referenceMax = observation.referenceRange[0].high?.value;
|
|
7169
|
+
const meaning = observation.referenceRange[0].type?.coding?.find(
|
|
7170
|
+
(c) => c.system === "http://terminology.hl7.org/CodeSystem/referencerange-meaning"
|
|
7171
|
+
)?.code;
|
|
7172
|
+
if (meaning === "normal") referenceKind = "reference-interval";
|
|
7173
|
+
else if (meaning === "recommended") referenceKind = "decision-threshold";
|
|
7174
|
+
}
|
|
7175
|
+
const imported = {
|
|
7176
|
+
biomarkerCode: internalCode,
|
|
7177
|
+
biomarkerName: definition?.names.pt[0] || definition?.names.en[0] || observation.code.text || internalCode,
|
|
7178
|
+
collectionDate,
|
|
7179
|
+
flag: extractFlag(observation),
|
|
7180
|
+
isQualitative,
|
|
7181
|
+
loincCode,
|
|
7182
|
+
...referenceKind && { referenceKind },
|
|
7183
|
+
referenceMax,
|
|
7184
|
+
referenceMin,
|
|
7185
|
+
unit: unit || definition?.unit || "",
|
|
7186
|
+
value
|
|
7187
|
+
};
|
|
7188
|
+
return { observation: imported };
|
|
7189
|
+
}
|
|
7190
|
+
function processImportBundle(data) {
|
|
7191
|
+
const validationErrors = validateFHIRImportBundle(data);
|
|
7192
|
+
if (validationErrors.length > 0) {
|
|
7193
|
+
return {
|
|
7194
|
+
errors: validationErrors,
|
|
7195
|
+
imported: [],
|
|
7196
|
+
skipped: [],
|
|
7197
|
+
totalProcessed: 0
|
|
7198
|
+
};
|
|
7199
|
+
}
|
|
7200
|
+
const bundle = data;
|
|
7201
|
+
const { observations, skipped } = extractObservationsFromBundle(bundle);
|
|
7202
|
+
const imported = [];
|
|
7203
|
+
const allSkipped = [...skipped];
|
|
7204
|
+
for (let i = 0; i < observations.length; i++) {
|
|
7205
|
+
const result = mapFHIRObservationToInternal(observations[i], i);
|
|
7206
|
+
if ("observation" in result) {
|
|
7207
|
+
imported.push(result.observation);
|
|
7208
|
+
} else {
|
|
7209
|
+
allSkipped.push(result.skipped);
|
|
6723
7210
|
}
|
|
6724
|
-
return withSource(variant.range);
|
|
6725
7211
|
}
|
|
6726
|
-
return
|
|
7212
|
+
return {
|
|
7213
|
+
errors: [],
|
|
7214
|
+
imported,
|
|
7215
|
+
skipped: allSkipped,
|
|
7216
|
+
totalProcessed: observations.length
|
|
7217
|
+
};
|
|
6727
7218
|
}
|
|
6728
|
-
|
|
6729
|
-
|
|
7219
|
+
|
|
7220
|
+
// src/cli/commands/import.ts
|
|
7221
|
+
async function importBundle(args, json) {
|
|
7222
|
+
const raw = await getInput(args[0]);
|
|
7223
|
+
const bundle = parseJson(raw, "JSON inv\xE1lido.");
|
|
7224
|
+
const result = processImportBundle(bundle);
|
|
7225
|
+
if (json) {
|
|
7226
|
+
outputJson(result);
|
|
7227
|
+
return;
|
|
7228
|
+
}
|
|
7229
|
+
outputText(`Processados: ${result.totalProcessed}`);
|
|
7230
|
+
outputText(`Importados: ${result.imported.length}`);
|
|
7231
|
+
outputText(`Ignorados: ${result.skipped.length}`);
|
|
7232
|
+
outputText(`Erros: ${result.errors.length}`);
|
|
7233
|
+
if (result.imported.length > 0) {
|
|
7234
|
+
outputText("\nObserva\xE7\xF5es importadas:");
|
|
7235
|
+
for (const obs of result.imported) {
|
|
7236
|
+
outputText(` ${obs.biomarkerCode} (${obs.loincCode}): ${obs.value} ${obs.unit}`);
|
|
7237
|
+
}
|
|
7238
|
+
}
|
|
7239
|
+
if (result.errors.length > 0) {
|
|
7240
|
+
outputText("\nErros:");
|
|
7241
|
+
for (const err of result.errors) {
|
|
7242
|
+
outputText(` ${err.field}: ${err.details}`);
|
|
7243
|
+
}
|
|
7244
|
+
}
|
|
7245
|
+
}
|
|
7246
|
+
|
|
7247
|
+
// src/cli/commands/list.ts
|
|
7248
|
+
import { parseArgs } from "util";
|
|
7249
|
+
async function list(args, json) {
|
|
7250
|
+
const { values } = parseArgs({
|
|
7251
|
+
args,
|
|
7252
|
+
options: {
|
|
7253
|
+
category: { type: "string" },
|
|
7254
|
+
visible: { default: false, type: "boolean" }
|
|
7255
|
+
},
|
|
7256
|
+
strict: false
|
|
7257
|
+
});
|
|
7258
|
+
let defs;
|
|
7259
|
+
if (values.category) {
|
|
7260
|
+
defs = getBiomarkersByCategory(values.category);
|
|
7261
|
+
if (defs.length === 0) {
|
|
7262
|
+
exitWithError(`Categoria n\xE3o encontrada ou vazia: ${values.category}`);
|
|
7263
|
+
}
|
|
7264
|
+
} else if (values.visible) {
|
|
7265
|
+
defs = getVisibleDefinitions();
|
|
7266
|
+
} else {
|
|
7267
|
+
defs = getAllDefinitions();
|
|
7268
|
+
}
|
|
7269
|
+
if (json) {
|
|
7270
|
+
outputJson(defs);
|
|
7271
|
+
return;
|
|
7272
|
+
}
|
|
7273
|
+
const rows = defs.map((d) => [
|
|
7274
|
+
d.code,
|
|
7275
|
+
d.loinc ?? "\u2014",
|
|
7276
|
+
d.names.pt[0] ?? "",
|
|
7277
|
+
d.unit ?? "\u2014",
|
|
7278
|
+
Array.isArray(d.category) ? d.category.join(", ") : d.category
|
|
7279
|
+
]);
|
|
7280
|
+
outputText(formatTable(["C\xF3digo", "LOINC", "Nome (pt)", "Unidade", "Categoria"], rows));
|
|
7281
|
+
outputText(`
|
|
7282
|
+
Total: ${defs.length} biomarcadores`);
|
|
7283
|
+
}
|
|
7284
|
+
|
|
7285
|
+
// src/cli/commands/loinc-map.ts
|
|
7286
|
+
async function loincMap(_args, json) {
|
|
7287
|
+
const defs = getAllDefinitions().filter((d) => d.loinc);
|
|
7288
|
+
if (json) {
|
|
7289
|
+
const map = Object.fromEntries(defs.map((d) => [d.loinc, d.code]));
|
|
7290
|
+
outputJson(map);
|
|
7291
|
+
return;
|
|
7292
|
+
}
|
|
7293
|
+
const rows = defs.map((d) => [d.loinc, d.code, d.names.pt[0] ?? d.names.en[0] ?? ""]);
|
|
7294
|
+
outputText(formatTable(["LOINC", "C\xF3digo", "Nome (pt)"], rows));
|
|
7295
|
+
outputText(`
|
|
7296
|
+
Total: ${rows.length} mapeamentos`);
|
|
7297
|
+
}
|
|
7298
|
+
|
|
7299
|
+
// src/cli/commands/lookup.ts
|
|
7300
|
+
function displayDefinition(def) {
|
|
7301
|
+
const cat = Array.isArray(def.category) ? def.category.join(", ") : def.category;
|
|
7302
|
+
outputText(
|
|
7303
|
+
[
|
|
7304
|
+
`Biomarcador: ${def.code}`,
|
|
7305
|
+
` LOINC: ${def.loinc ?? "\u2014"}`,
|
|
7306
|
+
` Nomes (pt): ${def.names.pt.join(", ")}`,
|
|
7307
|
+
` Nomes (en): ${def.names.en.join(", ")}`,
|
|
7308
|
+
` Categoria: ${cat}`,
|
|
7309
|
+
` Unidade: ${def.unit ?? "\u2014"}`,
|
|
7310
|
+
` Sexo: ${def.sex ?? "ambos"}`,
|
|
7311
|
+
` Vis\xEDvel: ${def.hidden ? "n\xE3o" : "sim"}`
|
|
7312
|
+
].join("\n")
|
|
7313
|
+
);
|
|
7314
|
+
}
|
|
7315
|
+
async function lookup(args, json) {
|
|
7316
|
+
const code = args[0];
|
|
7317
|
+
if (!code) exitWithError("Uso: fhir-bio lookup <c\xF3digo>");
|
|
7318
|
+
const def = getDefinitionByCode(code);
|
|
7319
|
+
if (!def) exitWithError(`Biomarcador n\xE3o encontrado: ${code}`);
|
|
7320
|
+
if (json) {
|
|
7321
|
+
outputJson(def);
|
|
7322
|
+
} else {
|
|
7323
|
+
displayDefinition(def);
|
|
7324
|
+
}
|
|
7325
|
+
}
|
|
7326
|
+
async function lookupLoinc(args, json) {
|
|
7327
|
+
const loinc = args[0];
|
|
7328
|
+
if (!loinc) exitWithError("Uso: fhir-bio lookup-loinc <loinc>");
|
|
7329
|
+
const def = getDefinitionByLoinc(loinc);
|
|
7330
|
+
if (!def) exitWithError(`Biomarcador n\xE3o encontrado para LOINC: ${loinc}`);
|
|
7331
|
+
if (json) {
|
|
7332
|
+
outputJson(def);
|
|
7333
|
+
} else {
|
|
7334
|
+
displayDefinition(def);
|
|
7335
|
+
}
|
|
6730
7336
|
}
|
|
6731
7337
|
|
|
6732
7338
|
// src/cli/commands/range.ts
|
|
7339
|
+
import { parseArgs as parseArgs2 } from "util";
|
|
6733
7340
|
async function range(args, json) {
|
|
6734
7341
|
const { positionals, values } = parseArgs2({
|
|
6735
7342
|
allowPositionals: true,
|
|
@@ -6766,11 +7373,18 @@ async function range(args, json) {
|
|
|
6766
7373
|
const sexLabel = ctx.biologicalSex === "M" ? "Homem" : ctx.biologicalSex === "F" ? "Mulher" : "Geral";
|
|
6767
7374
|
const ageLabel = ctx.age !== void 0 ? `, ${ctx.age} anos` : "";
|
|
6768
7375
|
const fmt = (v) => v !== void 0 ? String(v) : "\u2014";
|
|
7376
|
+
const desenho = (kind) => kind === "display" ? " (desenho, n\xE3o \xE9 corte)" : "";
|
|
7377
|
+
const tipos = {
|
|
7378
|
+
"decision-threshold": "limiar de decis\xE3o",
|
|
7379
|
+
population: "distribui\xE7\xE3o populacional",
|
|
7380
|
+
"reference-interval": "intervalo de refer\xEAncia"
|
|
7381
|
+
};
|
|
6769
7382
|
outputText(
|
|
6770
7383
|
[
|
|
6771
7384
|
`Faixa de Refer\xEAncia: ${code} (${sexLabel}${ageLabel})`,
|
|
6772
|
-
`
|
|
6773
|
-
` M\
|
|
7385
|
+
` Tipo: ${ref.kind ? tipos[ref.kind] : "\u2014"}`,
|
|
7386
|
+
` M\xEDnimo: ${fmt(ref.min)} ${ref.unit}${desenho(ref.minKind)}`,
|
|
7387
|
+
` M\xE1ximo: ${fmt(ref.max)} ${ref.unit}${desenho(ref.maxKind)}`,
|
|
6774
7388
|
` \xD3timo (m\xEDn): ${fmt(ref.optimalMin)} ${ref.unit}`,
|
|
6775
7389
|
` \xD3timo (m\xE1x): ${fmt(ref.optimalMax)} ${ref.unit}`,
|
|
6776
7390
|
` Alerta (m\xE1x): ${fmt(ref.warningMax)} ${ref.unit}`,
|
|
@@ -7263,7 +7877,7 @@ var COMMANDS = {
|
|
|
7263
7877
|
async function main() {
|
|
7264
7878
|
const { command, help, json, resto, version } = dividirArgv(process.argv.slice(2));
|
|
7265
7879
|
if (version) {
|
|
7266
|
-
process.stdout.write(`${"0.
|
|
7880
|
+
process.stdout.write(`${"0.34.0"}
|
|
7267
7881
|
`);
|
|
7268
7882
|
return;
|
|
7269
7883
|
}
|