@precisa-saude/fhir 0.32.0 → 0.33.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.
Files changed (59) hide show
  1. package/README.md +9 -9
  2. package/dist/biomarkers.cjs +2 -2
  3. package/dist/biomarkers.js +1 -1
  4. package/dist/{chunk-WDDW2WCY.js → chunk-4FKZG5GZ.js} +116 -25
  5. package/dist/chunk-4FKZG5GZ.js.map +1 -0
  6. package/dist/{chunk-AZTZYOAV.cjs → chunk-5RC7C7HJ.cjs} +199 -57
  7. package/dist/chunk-5RC7C7HJ.cjs.map +1 -0
  8. package/dist/{chunk-N3ZCOLG2.js → chunk-E6MXDQXW.js} +19 -1
  9. package/dist/chunk-E6MXDQXW.js.map +1 -0
  10. package/dist/{chunk-OTVCOSCK.cjs → chunk-FGZXQWSR.cjs} +14 -20
  11. package/dist/chunk-FGZXQWSR.cjs.map +1 -0
  12. package/dist/{chunk-MNUQ57JR.js → chunk-KS2YZBAS.js} +15 -21
  13. package/dist/chunk-KS2YZBAS.js.map +1 -0
  14. package/dist/{chunk-555WKD6J.cjs → chunk-LXKFVJF4.cjs} +3 -3
  15. package/dist/{chunk-555WKD6J.cjs.map → chunk-LXKFVJF4.cjs.map} +1 -1
  16. package/dist/{chunk-3ILBFLVQ.cjs → chunk-OAFAERDY.cjs} +20 -2
  17. package/dist/chunk-OAFAERDY.cjs.map +1 -0
  18. package/dist/{chunk-3XIMPALK.js → chunk-Q3H5C6UR.js} +198 -56
  19. package/dist/chunk-Q3H5C6UR.js.map +1 -0
  20. package/dist/{chunk-MKH4Q735.cjs → chunk-T75NZM56.cjs} +116 -25
  21. package/dist/chunk-T75NZM56.cjs.map +1 -0
  22. package/dist/{chunk-PLR54334.js → chunk-WXCX5TJJ.js} +2 -2
  23. package/dist/{chunk-4Y43MQQK.js → chunk-X5WVIJGG.js} +3 -3
  24. package/dist/{chunk-44QMNDOI.cjs → chunk-ZCIZUBMR.cjs} +9 -9
  25. package/dist/{chunk-44QMNDOI.cjs.map → chunk-ZCIZUBMR.cjs.map} +1 -1
  26. package/dist/cli.js +318 -94
  27. package/dist/converter.cjs +4 -4
  28. package/dist/converter.js +3 -3
  29. package/dist/importer.cjs +5 -4
  30. package/dist/importer.cjs.map +1 -1
  31. package/dist/importer.js +4 -3
  32. package/dist/index.cjs +15 -11
  33. package/dist/index.cjs.map +1 -1
  34. package/dist/index.d.cts +1 -1
  35. package/dist/index.d.ts +1 -1
  36. package/dist/index.js +30 -26
  37. package/dist/index.js.map +1 -1
  38. package/dist/reference-ranges.cjs +4 -3
  39. package/dist/reference-ranges.cjs.map +1 -1
  40. package/dist/reference-ranges.js +3 -2
  41. package/dist/units.cjs +7 -2
  42. package/dist/units.cjs.map +1 -1
  43. package/dist/units.d.cts +53 -5
  44. package/dist/units.d.ts +53 -5
  45. package/dist/units.js +6 -1
  46. package/dist/validators.cjs +4 -2
  47. package/dist/validators.cjs.map +1 -1
  48. package/dist/validators.js +3 -1
  49. package/package.json +1 -1
  50. package/dist/chunk-3ILBFLVQ.cjs.map +0 -1
  51. package/dist/chunk-3XIMPALK.js.map +0 -1
  52. package/dist/chunk-AZTZYOAV.cjs.map +0 -1
  53. package/dist/chunk-MKH4Q735.cjs.map +0 -1
  54. package/dist/chunk-MNUQ57JR.js.map +0 -1
  55. package/dist/chunk-N3ZCOLG2.js.map +0 -1
  56. package/dist/chunk-OTVCOSCK.cjs.map +0 -1
  57. package/dist/chunk-WDDW2WCY.js.map +0 -1
  58. /package/dist/{chunk-PLR54334.js.map → chunk-WXCX5TJJ.js.map} +0 -0
  59. /package/dist/{chunk-4Y43MQQK.js.map → chunk-X5WVIJGG.js.map} +0 -0
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
- // Alinha à matriz das entradas irmãs Omega3_EPA (75097-6) e Omega3_DHA
1095
- // (75095-0), ambas em hemácias. Anteriormente 35178-3 (mesmo analito em
1096
- // Ser/Plas), incompatível com o uso clínico do Índice Ômega-3 (Harris &
1097
- // von Schacky 2004), que é definido em membranas de hemácias.
1098
- // Ressalva: LOINC declara moles/volume; o biomarcador armazena %.
1099
- // Não há LOINC vigente para "Omega 3 total em % em RBC" — o `Omega3_Index`
1100
- // (88998-0) cobre apenas EPA+DHA. Mantemos `unit: '%'` por consistência
1101
- // com EPA/DHA (75095-0/75097-6 são [Entitic substance], também não-%).
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
- loinc: "75095-0",
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
- loinc: "48371-9",
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
- loinc: "75097-6",
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
- loinc: "90908-5",
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
- loinc: "35177-5",
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
- loinc: "75110-7",
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
- loinc: "75117-2",
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
- loinc: "8245-3",
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
- loinc: "630-4",
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
- loinc: "5808-1",
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. 56086-2, que parecia o óbvio pela busca, é
2610
- // "Adult Waist Circumference Protocol", um protocolo PhenX e não um
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
- loinc: "53060-0",
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 BIOMARKER_DEFAULT_UNIT = {
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
- Potassium: "mEq/L",
3401
- RDW: "%",
3402
- // Electrolytes
3403
- Sodium: "mEq/L",
3404
- SpecificGravity_Urine: "{specific gravity}",
3405
- T3Free: "pg/mL",
3406
- T4Free: "ng/dL",
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: "mIU/mL",
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: "mIU/mL",
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: "mIU/L",
4344
+ siUcum: "m[iU]/L",
4130
4345
  siUnit: "mIU/L"
4131
4346
  },
4132
4347
  Urea: {
@@ -4181,6 +4396,21 @@ var BIOMARKER_UNITS = {
4181
4396
  function getCanonicalUnit(code) {
4182
4397
  return BIOMARKER_UNITS[code]?.canonicalUnit ?? null;
4183
4398
  }
4399
+ function normalizeUnit(unit, config) {
4400
+ return config.aliases[unit.toLowerCase()] ?? config.aliases[unit] ?? unit;
4401
+ }
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;
4409
+ }
4410
+ const mapped = UNIT_TO_UCUM[unit];
4411
+ if (mapped) return mapped;
4412
+ return isUcumCode(unit) ? unit : void 0;
4413
+ }
4184
4414
 
4185
4415
  // src/converter.ts
4186
4416
  function interpretationCode(flag) {
@@ -4213,13 +4443,7 @@ var SEX_CODING = {
4213
4443
  },
4214
4444
  male: { code: "male", display: "Male", system: "http://hl7.org/fhir/administrative-gender" }
4215
4445
  };
4216
- var buildReferenceRanges = (observation, sourceUnit, ucumUnit) => {
4217
- const quantity = (value) => ({
4218
- code: ucumUnit,
4219
- system: "http://unitsofmeasure.org",
4220
- unit: sourceUnit,
4221
- value
4222
- });
4446
+ var buildReferenceRanges = (observation, quantity) => {
4223
4447
  const toRanges = (low, high, sex) => {
4224
4448
  if (low === void 0 && high === void 0) return [];
4225
4449
  return [
@@ -4238,7 +4462,12 @@ var buildReferenceRanges = (observation, sourceUnit, ucumUnit) => {
4238
4462
  function labObservationToFHIR(observation, patientId, laboratoryName) {
4239
4463
  const loincCode = codeToLoinc(observation.biomarkerCode);
4240
4464
  const sourceUnit = observation.unit || getDefaultUnit(observation.biomarkerCode) || observation.unit;
4241
- const ucumUnit = unitToUCUM(sourceUnit);
4465
+ const ucumUnit = resolveUcum(sourceUnit, observation.biomarkerCode);
4466
+ const quantity = (value) => ({
4467
+ ...ucumUnit ? { code: ucumUnit, system: "http://unitsofmeasure.org" } : {},
4468
+ ...sourceUnit ? { unit: sourceUnit } : {},
4469
+ value
4470
+ });
4242
4471
  const isQualitative = observation.isQualitative || typeof observation.value === "string";
4243
4472
  const fhirObs = {
4244
4473
  category: [
@@ -4297,13 +4526,8 @@ function labObservationToFHIR(observation, patientId, laboratoryName) {
4297
4526
  if (isQualitative) {
4298
4527
  fhirObs.valueString = String(observation.value);
4299
4528
  } 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);
4529
+ fhirObs.valueQuantity = quantity(observation.value);
4530
+ const referenceRange = buildReferenceRanges(observation, quantity);
4307
4531
  if (referenceRange.length > 0) fhirObs.referenceRange = referenceRange;
4308
4532
  }
4309
4533
  return fhirObs;
@@ -7263,7 +7487,7 @@ var COMMANDS = {
7263
7487
  async function main() {
7264
7488
  const { command, help, json, resto, version } = dividirArgv(process.argv.slice(2));
7265
7489
  if (version) {
7266
- process.stdout.write(`${"0.32.0"}
7490
+ process.stdout.write(`${"0.33.0"}
7267
7491
  `);
7268
7492
  return;
7269
7493
  }