@precisa-saude/fhir 0.33.0 → 0.35.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 +2 -0
- package/dist/biomarkers.cjs +4 -2
- package/dist/biomarkers.cjs.map +1 -1
- package/dist/biomarkers.d.cts +34 -1
- package/dist/biomarkers.d.ts +34 -1
- package/dist/biomarkers.js +3 -1
- package/dist/{chunk-X5WVIJGG.js → chunk-6QUGBBV2.js} +12 -3
- package/dist/chunk-6QUGBBV2.js.map +1 -0
- package/dist/{chunk-ZCIZUBMR.cjs → chunk-77LDD6OP.cjs} +20 -11
- package/dist/chunk-77LDD6OP.cjs.map +1 -0
- package/dist/{chunk-LXKFVJF4.cjs → chunk-HZSW5T7E.cjs} +447 -63
- package/dist/chunk-HZSW5T7E.cjs.map +1 -0
- package/dist/{chunk-4FKZG5GZ.js → chunk-KQ4CX67G.js} +35 -1
- package/dist/chunk-KQ4CX67G.js.map +1 -0
- package/dist/{chunk-5RC7C7HJ.cjs → chunk-LNL5QSHP.cjs} +3 -3
- package/dist/{chunk-5RC7C7HJ.cjs.map → chunk-LNL5QSHP.cjs.map} +1 -1
- package/dist/{chunk-WXCX5TJJ.js → chunk-O3FXUPW3.js} +445 -61
- package/dist/chunk-O3FXUPW3.js.map +1 -0
- package/dist/{chunk-KS2YZBAS.js → chunk-TLF3IVSN.js} +14 -6
- package/dist/chunk-TLF3IVSN.js.map +1 -0
- package/dist/{chunk-Q3H5C6UR.js → chunk-U2XW6DY4.js} +2 -2
- package/dist/{chunk-OAFAERDY.cjs → chunk-VMYB7KOE.cjs} +3 -3
- package/dist/{chunk-OAFAERDY.cjs.map → chunk-VMYB7KOE.cjs.map} +1 -1
- package/dist/{chunk-FGZXQWSR.cjs → chunk-XAIIZLZ7.cjs} +16 -8
- package/dist/chunk-XAIIZLZ7.cjs.map +1 -0
- package/dist/{chunk-E6MXDQXW.js → chunk-XT635TWP.js} +2 -2
- package/dist/{chunk-T75NZM56.cjs → chunk-YL65SZ6S.cjs} +38 -4
- package/dist/chunk-YL65SZ6S.cjs.map +1 -0
- package/dist/cli.js +1276 -851
- package/dist/{converter-DZH9x52r.d.cts → converter-CTj83kPz.d.ts} +15 -1
- package/dist/{converter-D1Q84Oc9.d.ts → converter-Dlwb6OfB.d.cts} +15 -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 -5
- package/dist/importer.d.cts +5 -1
- package/dist/importer.d.ts +5 -1
- package/dist/importer.js +4 -4
- package/dist/index.cjs +16 -10
- 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 +13 -7
- package/dist/index.js.map +1 -1
- package/dist/reference-ranges.cjs +8 -4
- 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 -5
- package/dist/units.cjs +3 -3
- package/dist/units.js +2 -2
- package/dist/validators.cjs +4 -4
- package/dist/validators.d.cts +1 -1
- package/dist/validators.d.ts +1 -1
- package/dist/validators.js +3 -3
- package/package.json +1 -1
- package/dist/chunk-4FKZG5GZ.js.map +0 -1
- package/dist/chunk-FGZXQWSR.cjs.map +0 -1
- package/dist/chunk-KS2YZBAS.js.map +0 -1
- package/dist/chunk-LXKFVJF4.cjs.map +0 -1
- package/dist/chunk-T75NZM56.cjs.map +0 -1
- package/dist/chunk-WXCX5TJJ.js.map +0 -1
- package/dist/chunk-X5WVIJGG.js.map +0 -1
- package/dist/chunk-ZCIZUBMR.cjs.map +0 -1
- /package/dist/{chunk-Q3H5C6UR.js.map → chunk-U2XW6DY4.js.map} +0 -0
- /package/dist/{chunk-E6MXDQXW.js.map → chunk-XT635TWP.js.map} +0 -0
package/dist/cli.js
CHANGED
|
@@ -115,6 +115,32 @@ var BIOMARKER_DEFINITIONS = [
|
|
|
115
115
|
category: "coracao",
|
|
116
116
|
code: "LDL",
|
|
117
117
|
loinc: "2089-1",
|
|
118
|
+
// Os três irmãos de 2089-1 no eixo Method, conferidos ativos em out/2026.
|
|
119
|
+
// Medido em três dezenas de laudos reais, a única pista escrita foi a
|
|
120
|
+
// nota de rodapé de um laboratório norte-americano que declara o cálculo de
|
|
121
|
+
// Martin-Hopkins. Nenhum laudo brasileiro do corpus imprimiu "calculado",
|
|
122
|
+
// "direto" ou "Método:" perto do LDL, e por isso as outras duas variantes
|
|
123
|
+
// ficam sem pista até aparecer laudo que as afirme.
|
|
124
|
+
methodVariants: [
|
|
125
|
+
{
|
|
126
|
+
cues: { en: ["calculated using the Martin-Hopkins"], pt: [] },
|
|
127
|
+
loinc: "96259-7",
|
|
128
|
+
method: "Calculated.Martin-Hopkins",
|
|
129
|
+
note: 'Rodap\xE9 "LDL-C is now calculated using the Martin-Hopkins calculation", que menciona Friedewald s\xF3 para comparar. Por isso a pista \xE9 a frase afirmativa, e n\xE3o o nome do m\xE9todo.'
|
|
130
|
+
},
|
|
131
|
+
{
|
|
132
|
+
cues: { en: [], pt: [] },
|
|
133
|
+
loinc: "13457-7",
|
|
134
|
+
method: "Calculated",
|
|
135
|
+
note: "Friedewald. Sem pista: nenhum laudo do corpus afirmou o c\xE1lculo por escrito."
|
|
136
|
+
},
|
|
137
|
+
{
|
|
138
|
+
cues: { en: [], pt: [] },
|
|
139
|
+
loinc: "18262-6",
|
|
140
|
+
method: "Direct assay",
|
|
141
|
+
note: "Dosagem direta. Sem pista: nenhum laudo do corpus afirmou o m\xE9todo por escrito."
|
|
142
|
+
}
|
|
143
|
+
],
|
|
118
144
|
names: {
|
|
119
145
|
en: ["LDL Cholesterol", "LDL", "Low-Density Lipoprotein"],
|
|
120
146
|
pt: ["Colesterol LDL", "LDL", "LDL-Colesterol"]
|
|
@@ -3313,6 +3339,10 @@ for (const def of BIOMARKER_DEFINITIONS) {
|
|
|
3313
3339
|
validLoincSet.add(alias);
|
|
3314
3340
|
}
|
|
3315
3341
|
}
|
|
3342
|
+
for (const variant of def.methodVariants ?? []) {
|
|
3343
|
+
loincToCodeMap.set(variant.loinc, def.code);
|
|
3344
|
+
validLoincSet.add(variant.loinc);
|
|
3345
|
+
}
|
|
3316
3346
|
if (def.codeAliases) {
|
|
3317
3347
|
for (const alias of def.codeAliases) {
|
|
3318
3348
|
codeAliasToCanonicalMap.set(alias, def.code);
|
|
@@ -3324,6 +3354,9 @@ for (const def of BIOMARKER_DEFINITIONS) {
|
|
|
3324
3354
|
function loincToCode(loinc) {
|
|
3325
3355
|
return loincToCodeMap.get(loinc);
|
|
3326
3356
|
}
|
|
3357
|
+
function methodVariantOf(code, loinc) {
|
|
3358
|
+
return codeToDefinitionMap.get(code)?.methodVariants?.find((v) => v.loinc === loinc);
|
|
3359
|
+
}
|
|
3327
3360
|
function codeToLoinc(code) {
|
|
3328
3361
|
return codeToLoincMap.get(code);
|
|
3329
3362
|
}
|
|
@@ -4412,628 +4445,89 @@ function resolveUcum(unit, biomarkerCode) {
|
|
|
4412
4445
|
return isUcumCode(unit) ? unit : void 0;
|
|
4413
4446
|
}
|
|
4414
4447
|
|
|
4415
|
-
// src/
|
|
4416
|
-
|
|
4417
|
-
|
|
4418
|
-
|
|
4419
|
-
|
|
4420
|
-
|
|
4421
|
-
case "L":
|
|
4422
|
-
return "L";
|
|
4423
|
-
// Low
|
|
4424
|
-
default:
|
|
4425
|
-
return "N";
|
|
4426
|
-
}
|
|
4427
|
-
}
|
|
4428
|
-
function interpretationDisplay(flag) {
|
|
4429
|
-
switch (flag) {
|
|
4430
|
-
case "H":
|
|
4431
|
-
return "High";
|
|
4432
|
-
case "L":
|
|
4433
|
-
return "Low";
|
|
4434
|
-
default:
|
|
4435
|
-
return "Normal";
|
|
4436
|
-
}
|
|
4437
|
-
}
|
|
4438
|
-
var SEX_CODING = {
|
|
4439
|
-
female: {
|
|
4440
|
-
code: "female",
|
|
4441
|
-
display: "Female",
|
|
4442
|
-
system: "http://hl7.org/fhir/administrative-gender"
|
|
4448
|
+
// src/reference-ranges.ts
|
|
4449
|
+
var biomarkerRangeDefinitions = {
|
|
4450
|
+
Albumin_Creatinine_Ratio: {
|
|
4451
|
+
default: { max: 30, min: 0, optimalMax: 20, optimalMin: 0, unit: "mg/g" },
|
|
4452
|
+
kind: "decision-threshold",
|
|
4453
|
+
source: "tietz-7ed-2015"
|
|
4443
4454
|
},
|
|
4444
|
-
|
|
4445
|
-
}
|
|
4446
|
-
|
|
4447
|
-
|
|
4448
|
-
|
|
4449
|
-
|
|
4455
|
+
Adiponectin: {
|
|
4456
|
+
default: { max: 26, min: 4, optimalMax: 20, optimalMin: 8, unit: "mcg/mL" },
|
|
4457
|
+
kind: "reference-interval",
|
|
4458
|
+
source: "tietz-7ed-2015"
|
|
4459
|
+
},
|
|
4460
|
+
ADMA: {
|
|
4461
|
+
default: { max: 0.7, min: 0.3, optimalMax: 0.55, optimalMin: 0.3, unit: "umol/L" },
|
|
4462
|
+
kind: "reference-interval",
|
|
4463
|
+
source: "nemeth-adma-2017"
|
|
4464
|
+
},
|
|
4465
|
+
AFP: {
|
|
4466
|
+
default: { max: 10, min: 0, optimalMax: 8, optimalMin: 0, unit: "ng/mL" },
|
|
4467
|
+
kind: "reference-interval",
|
|
4468
|
+
source: "sturgeon-nacb-2008"
|
|
4469
|
+
},
|
|
4470
|
+
Albumin_Globulin_Ratio: {
|
|
4471
|
+
default: { max: 2.5, min: 1, optimalMax: 2.2, optimalMin: 1.2, unit: "" },
|
|
4472
|
+
kind: "reference-interval",
|
|
4473
|
+
source: "tietz-7ed-2015"
|
|
4474
|
+
},
|
|
4475
|
+
Albumin: {
|
|
4476
|
+
default: { max: 5, min: 3.5, optimalMax: 4.8, optimalMin: 4, unit: "g/dL" },
|
|
4477
|
+
kind: "reference-interval",
|
|
4478
|
+
source: "pns-bioquimica-2019"
|
|
4479
|
+
},
|
|
4480
|
+
AlkalinePhosphatase: {
|
|
4481
|
+
default: { max: 147, min: 44, optimalMax: 120, optimalMin: 50, unit: "U/L" },
|
|
4482
|
+
kind: "reference-interval",
|
|
4483
|
+
source: "tietz-7ed-2015",
|
|
4484
|
+
variants: [
|
|
4450
4485
|
{
|
|
4451
|
-
|
|
4452
|
-
|
|
4453
|
-
|
|
4454
|
-
}
|
|
4455
|
-
];
|
|
4456
|
-
};
|
|
4457
|
-
if (observation.referenceRanges && observation.referenceRanges.length > 0) {
|
|
4458
|
-
return observation.referenceRanges.flatMap((r) => toRanges(r.low, r.high, r.appliesTo));
|
|
4459
|
-
}
|
|
4460
|
-
return toRanges(observation.referenceMin, observation.referenceMax);
|
|
4461
|
-
};
|
|
4462
|
-
function labObservationToFHIR(observation, patientId, laboratoryName) {
|
|
4463
|
-
const loincCode = codeToLoinc(observation.biomarkerCode);
|
|
4464
|
-
const sourceUnit = observation.unit || getDefaultUnit(observation.biomarkerCode) || observation.unit;
|
|
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
|
-
});
|
|
4471
|
-
const isQualitative = observation.isQualitative || typeof observation.value === "string";
|
|
4472
|
-
const fhirObs = {
|
|
4473
|
-
category: [
|
|
4486
|
+
ageMin: 18,
|
|
4487
|
+
range: { max: 147, min: 44, optimalMax: 120, optimalMin: 50, unit: "U/L" },
|
|
4488
|
+
sex: "M"
|
|
4489
|
+
},
|
|
4474
4490
|
{
|
|
4475
|
-
|
|
4476
|
-
|
|
4477
|
-
|
|
4478
|
-
display: "Laboratory",
|
|
4479
|
-
system: "http://terminology.hl7.org/CodeSystem/observation-category"
|
|
4480
|
-
}
|
|
4481
|
-
]
|
|
4491
|
+
ageMin: 18,
|
|
4492
|
+
range: { max: 104, min: 35, optimalMax: 90, optimalMin: 40, unit: "U/L" },
|
|
4493
|
+
sex: "F"
|
|
4482
4494
|
}
|
|
4483
|
-
]
|
|
4484
|
-
|
|
4485
|
-
|
|
4486
|
-
|
|
4487
|
-
|
|
4488
|
-
|
|
4489
|
-
|
|
4490
|
-
coding: [
|
|
4491
|
-
...loincCode ? [
|
|
4492
|
-
{
|
|
4493
|
-
code: loincCode,
|
|
4494
|
-
display: observation.biomarkerName,
|
|
4495
|
-
system: LOINC_SYSTEM
|
|
4496
|
-
}
|
|
4497
|
-
] : [],
|
|
4498
|
-
{
|
|
4499
|
-
code: observation.biomarkerCode,
|
|
4500
|
-
display: observation.biomarkerName,
|
|
4501
|
-
system: BIOMARKER_CODE_SYSTEM
|
|
4502
|
-
}
|
|
4503
|
-
],
|
|
4504
|
-
text: observation.biomarkerName
|
|
4505
|
-
},
|
|
4506
|
-
effectiveDateTime: observation.collectionDate,
|
|
4507
|
-
id: `${observation.reportId}-${observation.biomarkerCode}`,
|
|
4508
|
-
interpretation: [
|
|
4495
|
+
]
|
|
4496
|
+
},
|
|
4497
|
+
ALT: {
|
|
4498
|
+
default: { max: 35, min: 0, optimalMax: 25, optimalMin: 0, unit: "U/L" },
|
|
4499
|
+
kind: "reference-interval",
|
|
4500
|
+
source: "tietz-7ed-2015",
|
|
4501
|
+
variants: [
|
|
4509
4502
|
{
|
|
4510
|
-
|
|
4511
|
-
|
|
4512
|
-
|
|
4513
|
-
|
|
4514
|
-
system: "http://terminology.hl7.org/CodeSystem/v3-ObservationInterpretation"
|
|
4515
|
-
}
|
|
4516
|
-
]
|
|
4517
|
-
}
|
|
4518
|
-
],
|
|
4519
|
-
performer: laboratoryName ? [{ display: laboratoryName }] : void 0,
|
|
4520
|
-
resourceType: "Observation",
|
|
4521
|
-
status: "final",
|
|
4522
|
-
subject: {
|
|
4523
|
-
reference: `Patient/${patientId}`
|
|
4524
|
-
}
|
|
4525
|
-
};
|
|
4526
|
-
if (isQualitative) {
|
|
4527
|
-
fhirObs.valueString = String(observation.value);
|
|
4528
|
-
} else {
|
|
4529
|
-
fhirObs.valueQuantity = quantity(observation.value);
|
|
4530
|
-
const referenceRange = buildReferenceRanges(observation, quantity);
|
|
4531
|
-
if (referenceRange.length > 0) fhirObs.referenceRange = referenceRange;
|
|
4532
|
-
}
|
|
4533
|
-
return fhirObs;
|
|
4534
|
-
}
|
|
4535
|
-
function labReportToFHIR(report, patientId, observationIds) {
|
|
4536
|
-
let status;
|
|
4537
|
-
switch (report.processingStatus) {
|
|
4538
|
-
case "complete":
|
|
4539
|
-
status = "final";
|
|
4540
|
-
break;
|
|
4541
|
-
case "partial":
|
|
4542
|
-
status = "partial";
|
|
4543
|
-
break;
|
|
4544
|
-
case "pending_review":
|
|
4545
|
-
status = "preliminary";
|
|
4546
|
-
break;
|
|
4547
|
-
default:
|
|
4548
|
-
status = "final";
|
|
4549
|
-
}
|
|
4550
|
-
return {
|
|
4551
|
-
category: [
|
|
4503
|
+
ageMin: 18,
|
|
4504
|
+
range: { max: 56, min: 7, optimalMax: 35, optimalMin: 10, unit: "U/L" },
|
|
4505
|
+
sex: "M"
|
|
4506
|
+
},
|
|
4552
4507
|
{
|
|
4553
|
-
|
|
4554
|
-
|
|
4555
|
-
|
|
4556
|
-
display: "Laboratory",
|
|
4557
|
-
system: "http://terminology.hl7.org/CodeSystem/v2-0074"
|
|
4558
|
-
}
|
|
4559
|
-
]
|
|
4508
|
+
ageMin: 18,
|
|
4509
|
+
range: { max: 45, min: 7, optimalMax: 30, optimalMin: 10, unit: "U/L" },
|
|
4510
|
+
sex: "F"
|
|
4560
4511
|
}
|
|
4561
|
-
]
|
|
4562
|
-
|
|
4563
|
-
|
|
4564
|
-
|
|
4565
|
-
|
|
4566
|
-
|
|
4567
|
-
|
|
4568
|
-
|
|
4569
|
-
|
|
4570
|
-
|
|
4571
|
-
|
|
4572
|
-
|
|
4573
|
-
|
|
4574
|
-
conclusionCode: report.overallStatus === "ANORMAL" ? [
|
|
4512
|
+
]
|
|
4513
|
+
},
|
|
4514
|
+
// AMH — fortemente dependente de idade e sexo. As variantes femininas por
|
|
4515
|
+
// faixa etária são a referência clínica; o `default` foi ajustado para
|
|
4516
|
+
// refletir uma faixa adulta conservadora (~18-40 anos, mulheres em idade
|
|
4517
|
+
// reprodutiva geral). optimalMax anterior (6.9 ng/mL) sobrepunha-se a
|
|
4518
|
+
// valores sugestivos de SOP ou risco de OHSS; clinicamente, valores acima
|
|
4519
|
+
// de ~4 ng/mL já merecem investigação.
|
|
4520
|
+
AMH: {
|
|
4521
|
+
default: { max: 6, min: 1, optimalMax: 4, optimalMin: 1.5, unit: "ng/mL" },
|
|
4522
|
+
kind: "reference-interval",
|
|
4523
|
+
source: "tietz-7ed-2015",
|
|
4524
|
+
variants: [
|
|
4575
4525
|
{
|
|
4576
|
-
|
|
4577
|
-
|
|
4578
|
-
|
|
4579
|
-
|
|
4580
|
-
|
|
4581
|
-
}
|
|
4582
|
-
]
|
|
4583
|
-
}
|
|
4584
|
-
] : void 0,
|
|
4585
|
-
effectiveDateTime: report.collectionDate,
|
|
4586
|
-
id: report.reportId,
|
|
4587
|
-
issued: report.createdAt,
|
|
4588
|
-
performer: report.laboratoryName ? [{ display: report.laboratoryName }] : void 0,
|
|
4589
|
-
resourceType: "DiagnosticReport",
|
|
4590
|
-
result: observationIds.map((id) => ({ reference: `Observation/${id}` })),
|
|
4591
|
-
status,
|
|
4592
|
-
subject: {
|
|
4593
|
-
reference: `Patient/${patientId}`
|
|
4594
|
-
}
|
|
4595
|
-
};
|
|
4596
|
-
}
|
|
4597
|
-
function userProfileToFHIR(profile) {
|
|
4598
|
-
const nameParts = profile.name.split(" ");
|
|
4599
|
-
const given = nameParts.slice(0, -1);
|
|
4600
|
-
const family = nameParts[nameParts.length - 1] || "";
|
|
4601
|
-
return {
|
|
4602
|
-
address: profile.address ? [
|
|
4603
|
-
{
|
|
4604
|
-
city: profile.address.city,
|
|
4605
|
-
country: profile.address.country || "BR",
|
|
4606
|
-
line: [
|
|
4607
|
-
profile.address.street && profile.address.number ? `${profile.address.street}, ${profile.address.number}` : profile.address.street,
|
|
4608
|
-
profile.address.complement
|
|
4609
|
-
].filter(Boolean),
|
|
4610
|
-
postalCode: profile.address.postalCode,
|
|
4611
|
-
state: profile.address.state
|
|
4612
|
-
}
|
|
4613
|
-
] : void 0,
|
|
4614
|
-
birthDate: profile.birthDate,
|
|
4615
|
-
gender: profile.gender,
|
|
4616
|
-
id: profile.userId,
|
|
4617
|
-
name: [
|
|
4618
|
-
{
|
|
4619
|
-
family,
|
|
4620
|
-
given: given.length > 0 ? given : void 0,
|
|
4621
|
-
text: profile.name
|
|
4622
|
-
}
|
|
4623
|
-
],
|
|
4624
|
-
resourceType: "Patient",
|
|
4625
|
-
telecom: [
|
|
4626
|
-
...profile.email ? [{ system: "email", value: profile.email }] : [],
|
|
4627
|
-
...profile.phone ? [{ system: "phone", value: profile.phone }] : []
|
|
4628
|
-
].length > 0 ? [
|
|
4629
|
-
...profile.email ? [{ system: "email", value: profile.email }] : [],
|
|
4630
|
-
...profile.phone ? [{ system: "phone", value: profile.phone }] : []
|
|
4631
|
-
] : void 0
|
|
4632
|
-
};
|
|
4633
|
-
}
|
|
4634
|
-
function labResultToFHIRBundle(report, observations, userProfile) {
|
|
4635
|
-
const patientId = userProfile.userId;
|
|
4636
|
-
const fhirObservations = observations.map((obs) => {
|
|
4637
|
-
const resource = labObservationToFHIR(
|
|
4638
|
-
{ ...obs, collectionDate: report.collectionDate },
|
|
4639
|
-
patientId,
|
|
4640
|
-
report.laboratoryName
|
|
4641
|
-
);
|
|
4642
|
-
return { fullUrl: entryFullUrl(resource), resource };
|
|
4643
|
-
});
|
|
4644
|
-
const observationIds = fhirObservations.map((entry) => entry.resource.id);
|
|
4645
|
-
const diagnosticReport = labReportToFHIR(report, patientId, observationIds);
|
|
4646
|
-
const fhirPatient = userProfileToFHIR(userProfile);
|
|
4647
|
-
return {
|
|
4648
|
-
entry: [
|
|
4649
|
-
{ fullUrl: entryFullUrl(fhirPatient), resource: fhirPatient },
|
|
4650
|
-
{ fullUrl: entryFullUrl(diagnosticReport), resource: diagnosticReport },
|
|
4651
|
-
...fhirObservations
|
|
4652
|
-
],
|
|
4653
|
-
resourceType: "Bundle",
|
|
4654
|
-
type: "collection"
|
|
4655
|
-
};
|
|
4656
|
-
}
|
|
4657
|
-
|
|
4658
|
-
// src/cli/commands/convert.ts
|
|
4659
|
-
async function convert(args, json) {
|
|
4660
|
-
const raw = await getInput(args[0]);
|
|
4661
|
-
const data = parseJson(
|
|
4662
|
-
raw,
|
|
4663
|
-
"JSON inv\xE1lido. Forne\xE7a um objeto com { report, observations, profile }."
|
|
4664
|
-
);
|
|
4665
|
-
if (!data.report || !data.observations || !data.profile) {
|
|
4666
|
-
exitWithError(
|
|
4667
|
-
'Formato esperado: { "report": LabReportData, "observations": LabObservationData[], "profile": UserProfileData }'
|
|
4668
|
-
);
|
|
4669
|
-
}
|
|
4670
|
-
const bundle = labResultToFHIRBundle(data.report, data.observations, data.profile);
|
|
4671
|
-
if (json) {
|
|
4672
|
-
outputJson(bundle);
|
|
4673
|
-
} else {
|
|
4674
|
-
outputText(JSON.stringify(bundle, null, 2));
|
|
4675
|
-
}
|
|
4676
|
-
}
|
|
4677
|
-
|
|
4678
|
-
// src/validators.ts
|
|
4679
|
-
function validateFHIRImportBundle(data) {
|
|
4680
|
-
const errors = [];
|
|
4681
|
-
if (!data || typeof data !== "object") {
|
|
4682
|
-
errors.push({ details: "Input must be a JSON object", field: "root" });
|
|
4683
|
-
return errors;
|
|
4684
|
-
}
|
|
4685
|
-
const bundle = data;
|
|
4686
|
-
if (bundle.resourceType !== "Bundle") {
|
|
4687
|
-
errors.push({
|
|
4688
|
-
details: `Expected resourceType "Bundle", got "${String(bundle.resourceType)}"`,
|
|
4689
|
-
field: "resourceType"
|
|
4690
|
-
});
|
|
4691
|
-
}
|
|
4692
|
-
if (!Array.isArray(bundle.entry)) {
|
|
4693
|
-
errors.push({ details: 'Bundle must contain an "entry" array', field: "entry" });
|
|
4694
|
-
} else if (bundle.entry.length === 0) {
|
|
4695
|
-
errors.push({ details: "Bundle entry array is empty", field: "entry" });
|
|
4696
|
-
}
|
|
4697
|
-
return errors;
|
|
4698
|
-
}
|
|
4699
|
-
|
|
4700
|
-
// src/importer.ts
|
|
4701
|
-
var MAX_OBSERVATIONS = 5e3;
|
|
4702
|
-
var MAX_FILE_SIZE = 15 * 1024 * 1024;
|
|
4703
|
-
function resolveBiomarkerCode(observation) {
|
|
4704
|
-
const coding = observation.code?.coding ?? [];
|
|
4705
|
-
const loincCode = coding.find((c) => c.system === LOINC_SYSTEM)?.code;
|
|
4706
|
-
const declaredCode = coding.find((c) => c.system === BIOMARKER_CODE_SYSTEM)?.code;
|
|
4707
|
-
const seenCodes = [
|
|
4708
|
-
...loincCode ? [`LOINC ${loincCode}`] : [],
|
|
4709
|
-
...declaredCode ? [`biomarker code ${declaredCode}`] : []
|
|
4710
|
-
];
|
|
4711
|
-
let reason;
|
|
4712
|
-
if (seenCodes.length > 0) {
|
|
4713
|
-
reason = `Unknown code: ${seenCodes.join(", ")}`;
|
|
4714
|
-
} else if (coding.length > 0) {
|
|
4715
|
-
const systems = [...new Set(coding.map((c) => c.system ?? "(sem system)"))];
|
|
4716
|
-
reason = `No code in a supported system (found: ${systems.join(", ")})`;
|
|
4717
|
-
} else {
|
|
4718
|
-
reason = "No code found in observation coding";
|
|
4719
|
-
}
|
|
4720
|
-
const fromLoinc = loincCode ? loincToCode(loincCode) : void 0;
|
|
4721
|
-
if (fromLoinc) return { internalCode: fromLoinc, loincCode, reason };
|
|
4722
|
-
if (declaredCode && isValidCode(declaredCode)) {
|
|
4723
|
-
const canonical = normalizeCode(declaredCode);
|
|
4724
|
-
return { internalCode: canonical, loincCode: codeToLoinc(canonical), reason };
|
|
4725
|
-
}
|
|
4726
|
-
return { loincCode, reason };
|
|
4727
|
-
}
|
|
4728
|
-
function extractFlag(observation) {
|
|
4729
|
-
const code = observation.interpretation?.[0]?.coding?.[0]?.code;
|
|
4730
|
-
if (code === "H" || code === "HH") return "H";
|
|
4731
|
-
if (code === "L" || code === "LL") return "L";
|
|
4732
|
-
return "";
|
|
4733
|
-
}
|
|
4734
|
-
function extractObservationsFromBundle(bundle) {
|
|
4735
|
-
const observations = [];
|
|
4736
|
-
const skipped = [];
|
|
4737
|
-
for (let i = 0; i < bundle.entry.length; i++) {
|
|
4738
|
-
const entry = bundle.entry[i];
|
|
4739
|
-
if (!entry.resource) {
|
|
4740
|
-
skipped.push({ index: i, reason: "Entry has no resource" });
|
|
4741
|
-
continue;
|
|
4742
|
-
}
|
|
4743
|
-
if (entry.resource.resourceType !== "Observation") {
|
|
4744
|
-
continue;
|
|
4745
|
-
}
|
|
4746
|
-
if (observations.length >= MAX_OBSERVATIONS) {
|
|
4747
|
-
skipped.push({ index: i, reason: `Maximum of ${MAX_OBSERVATIONS} observations exceeded` });
|
|
4748
|
-
continue;
|
|
4749
|
-
}
|
|
4750
|
-
observations.push(entry.resource);
|
|
4751
|
-
}
|
|
4752
|
-
return { observations, skipped };
|
|
4753
|
-
}
|
|
4754
|
-
function mapFHIRObservationToInternal(observation, index) {
|
|
4755
|
-
const { internalCode, loincCode, reason } = resolveBiomarkerCode(observation);
|
|
4756
|
-
if (!internalCode) {
|
|
4757
|
-
return {
|
|
4758
|
-
skipped: { index, loincCode, reason, resourceType: "Observation" }
|
|
4759
|
-
};
|
|
4760
|
-
}
|
|
4761
|
-
const definition = getDefinitionByCode(internalCode);
|
|
4762
|
-
let value;
|
|
4763
|
-
let unit = "";
|
|
4764
|
-
let isQualitative = false;
|
|
4765
|
-
if (observation.valueQuantity?.value !== void 0) {
|
|
4766
|
-
value = observation.valueQuantity.value;
|
|
4767
|
-
unit = observation.valueQuantity.unit || observation.valueQuantity.code || "";
|
|
4768
|
-
} else if (observation.valueString) {
|
|
4769
|
-
value = observation.valueString;
|
|
4770
|
-
isQualitative = true;
|
|
4771
|
-
} else {
|
|
4772
|
-
return {
|
|
4773
|
-
skipped: {
|
|
4774
|
-
index,
|
|
4775
|
-
loincCode,
|
|
4776
|
-
reason: "Observation has no value (valueQuantity or valueString)",
|
|
4777
|
-
resourceType: "Observation"
|
|
4778
|
-
}
|
|
4779
|
-
};
|
|
4780
|
-
}
|
|
4781
|
-
const collectionDate = observation.effectiveDateTime || observation.effectivePeriod?.start || "";
|
|
4782
|
-
if (!collectionDate) {
|
|
4783
|
-
return {
|
|
4784
|
-
skipped: {
|
|
4785
|
-
index,
|
|
4786
|
-
loincCode,
|
|
4787
|
-
reason: "Observation has no effectiveDateTime or effectivePeriod.start",
|
|
4788
|
-
resourceType: "Observation"
|
|
4789
|
-
}
|
|
4790
|
-
};
|
|
4791
|
-
}
|
|
4792
|
-
let referenceMin;
|
|
4793
|
-
let referenceMax;
|
|
4794
|
-
if (observation.referenceRange?.[0]) {
|
|
4795
|
-
referenceMin = observation.referenceRange[0].low?.value;
|
|
4796
|
-
referenceMax = observation.referenceRange[0].high?.value;
|
|
4797
|
-
}
|
|
4798
|
-
const imported = {
|
|
4799
|
-
biomarkerCode: internalCode,
|
|
4800
|
-
biomarkerName: definition?.names.pt[0] || definition?.names.en[0] || observation.code.text || internalCode,
|
|
4801
|
-
collectionDate,
|
|
4802
|
-
flag: extractFlag(observation),
|
|
4803
|
-
isQualitative,
|
|
4804
|
-
loincCode,
|
|
4805
|
-
referenceMax,
|
|
4806
|
-
referenceMin,
|
|
4807
|
-
unit: unit || definition?.unit || "",
|
|
4808
|
-
value
|
|
4809
|
-
};
|
|
4810
|
-
return { observation: imported };
|
|
4811
|
-
}
|
|
4812
|
-
function processImportBundle(data) {
|
|
4813
|
-
const validationErrors = validateFHIRImportBundle(data);
|
|
4814
|
-
if (validationErrors.length > 0) {
|
|
4815
|
-
return {
|
|
4816
|
-
errors: validationErrors,
|
|
4817
|
-
imported: [],
|
|
4818
|
-
skipped: [],
|
|
4819
|
-
totalProcessed: 0
|
|
4820
|
-
};
|
|
4821
|
-
}
|
|
4822
|
-
const bundle = data;
|
|
4823
|
-
const { observations, skipped } = extractObservationsFromBundle(bundle);
|
|
4824
|
-
const imported = [];
|
|
4825
|
-
const allSkipped = [...skipped];
|
|
4826
|
-
for (let i = 0; i < observations.length; i++) {
|
|
4827
|
-
const result = mapFHIRObservationToInternal(observations[i], i);
|
|
4828
|
-
if ("observation" in result) {
|
|
4829
|
-
imported.push(result.observation);
|
|
4830
|
-
} else {
|
|
4831
|
-
allSkipped.push(result.skipped);
|
|
4832
|
-
}
|
|
4833
|
-
}
|
|
4834
|
-
return {
|
|
4835
|
-
errors: [],
|
|
4836
|
-
imported,
|
|
4837
|
-
skipped: allSkipped,
|
|
4838
|
-
totalProcessed: observations.length
|
|
4839
|
-
};
|
|
4840
|
-
}
|
|
4841
|
-
|
|
4842
|
-
// src/cli/commands/import.ts
|
|
4843
|
-
async function importBundle(args, json) {
|
|
4844
|
-
const raw = await getInput(args[0]);
|
|
4845
|
-
const bundle = parseJson(raw, "JSON inv\xE1lido.");
|
|
4846
|
-
const result = processImportBundle(bundle);
|
|
4847
|
-
if (json) {
|
|
4848
|
-
outputJson(result);
|
|
4849
|
-
return;
|
|
4850
|
-
}
|
|
4851
|
-
outputText(`Processados: ${result.totalProcessed}`);
|
|
4852
|
-
outputText(`Importados: ${result.imported.length}`);
|
|
4853
|
-
outputText(`Ignorados: ${result.skipped.length}`);
|
|
4854
|
-
outputText(`Erros: ${result.errors.length}`);
|
|
4855
|
-
if (result.imported.length > 0) {
|
|
4856
|
-
outputText("\nObserva\xE7\xF5es importadas:");
|
|
4857
|
-
for (const obs of result.imported) {
|
|
4858
|
-
outputText(` ${obs.biomarkerCode} (${obs.loincCode}): ${obs.value} ${obs.unit}`);
|
|
4859
|
-
}
|
|
4860
|
-
}
|
|
4861
|
-
if (result.errors.length > 0) {
|
|
4862
|
-
outputText("\nErros:");
|
|
4863
|
-
for (const err of result.errors) {
|
|
4864
|
-
outputText(` ${err.field}: ${err.details}`);
|
|
4865
|
-
}
|
|
4866
|
-
}
|
|
4867
|
-
}
|
|
4868
|
-
|
|
4869
|
-
// src/cli/commands/list.ts
|
|
4870
|
-
import { parseArgs } from "util";
|
|
4871
|
-
async function list(args, json) {
|
|
4872
|
-
const { values } = parseArgs({
|
|
4873
|
-
args,
|
|
4874
|
-
options: {
|
|
4875
|
-
category: { type: "string" },
|
|
4876
|
-
visible: { default: false, type: "boolean" }
|
|
4877
|
-
},
|
|
4878
|
-
strict: false
|
|
4879
|
-
});
|
|
4880
|
-
let defs;
|
|
4881
|
-
if (values.category) {
|
|
4882
|
-
defs = getBiomarkersByCategory(values.category);
|
|
4883
|
-
if (defs.length === 0) {
|
|
4884
|
-
exitWithError(`Categoria n\xE3o encontrada ou vazia: ${values.category}`);
|
|
4885
|
-
}
|
|
4886
|
-
} else if (values.visible) {
|
|
4887
|
-
defs = getVisibleDefinitions();
|
|
4888
|
-
} else {
|
|
4889
|
-
defs = getAllDefinitions();
|
|
4890
|
-
}
|
|
4891
|
-
if (json) {
|
|
4892
|
-
outputJson(defs);
|
|
4893
|
-
return;
|
|
4894
|
-
}
|
|
4895
|
-
const rows = defs.map((d) => [
|
|
4896
|
-
d.code,
|
|
4897
|
-
d.loinc ?? "\u2014",
|
|
4898
|
-
d.names.pt[0] ?? "",
|
|
4899
|
-
d.unit ?? "\u2014",
|
|
4900
|
-
Array.isArray(d.category) ? d.category.join(", ") : d.category
|
|
4901
|
-
]);
|
|
4902
|
-
outputText(formatTable(["C\xF3digo", "LOINC", "Nome (pt)", "Unidade", "Categoria"], rows));
|
|
4903
|
-
outputText(`
|
|
4904
|
-
Total: ${defs.length} biomarcadores`);
|
|
4905
|
-
}
|
|
4906
|
-
|
|
4907
|
-
// src/cli/commands/loinc-map.ts
|
|
4908
|
-
async function loincMap(_args, json) {
|
|
4909
|
-
const defs = getAllDefinitions().filter((d) => d.loinc);
|
|
4910
|
-
if (json) {
|
|
4911
|
-
const map = Object.fromEntries(defs.map((d) => [d.loinc, d.code]));
|
|
4912
|
-
outputJson(map);
|
|
4913
|
-
return;
|
|
4914
|
-
}
|
|
4915
|
-
const rows = defs.map((d) => [d.loinc, d.code, d.names.pt[0] ?? d.names.en[0] ?? ""]);
|
|
4916
|
-
outputText(formatTable(["LOINC", "C\xF3digo", "Nome (pt)"], rows));
|
|
4917
|
-
outputText(`
|
|
4918
|
-
Total: ${rows.length} mapeamentos`);
|
|
4919
|
-
}
|
|
4920
|
-
|
|
4921
|
-
// src/cli/commands/lookup.ts
|
|
4922
|
-
function displayDefinition(def) {
|
|
4923
|
-
const cat = Array.isArray(def.category) ? def.category.join(", ") : def.category;
|
|
4924
|
-
outputText(
|
|
4925
|
-
[
|
|
4926
|
-
`Biomarcador: ${def.code}`,
|
|
4927
|
-
` LOINC: ${def.loinc ?? "\u2014"}`,
|
|
4928
|
-
` Nomes (pt): ${def.names.pt.join(", ")}`,
|
|
4929
|
-
` Nomes (en): ${def.names.en.join(", ")}`,
|
|
4930
|
-
` Categoria: ${cat}`,
|
|
4931
|
-
` Unidade: ${def.unit ?? "\u2014"}`,
|
|
4932
|
-
` Sexo: ${def.sex ?? "ambos"}`,
|
|
4933
|
-
` Vis\xEDvel: ${def.hidden ? "n\xE3o" : "sim"}`
|
|
4934
|
-
].join("\n")
|
|
4935
|
-
);
|
|
4936
|
-
}
|
|
4937
|
-
async function lookup(args, json) {
|
|
4938
|
-
const code = args[0];
|
|
4939
|
-
if (!code) exitWithError("Uso: fhir-bio lookup <c\xF3digo>");
|
|
4940
|
-
const def = getDefinitionByCode(code);
|
|
4941
|
-
if (!def) exitWithError(`Biomarcador n\xE3o encontrado: ${code}`);
|
|
4942
|
-
if (json) {
|
|
4943
|
-
outputJson(def);
|
|
4944
|
-
} else {
|
|
4945
|
-
displayDefinition(def);
|
|
4946
|
-
}
|
|
4947
|
-
}
|
|
4948
|
-
async function lookupLoinc(args, json) {
|
|
4949
|
-
const loinc = args[0];
|
|
4950
|
-
if (!loinc) exitWithError("Uso: fhir-bio lookup-loinc <loinc>");
|
|
4951
|
-
const def = getDefinitionByLoinc(loinc);
|
|
4952
|
-
if (!def) exitWithError(`Biomarcador n\xE3o encontrado para LOINC: ${loinc}`);
|
|
4953
|
-
if (json) {
|
|
4954
|
-
outputJson(def);
|
|
4955
|
-
} else {
|
|
4956
|
-
displayDefinition(def);
|
|
4957
|
-
}
|
|
4958
|
-
}
|
|
4959
|
-
|
|
4960
|
-
// src/cli/commands/range.ts
|
|
4961
|
-
import { parseArgs as parseArgs2 } from "util";
|
|
4962
|
-
|
|
4963
|
-
// src/reference-ranges.ts
|
|
4964
|
-
var biomarkerRangeDefinitions = {
|
|
4965
|
-
Albumin_Creatinine_Ratio: {
|
|
4966
|
-
default: { max: 30, min: 0, optimalMax: 20, optimalMin: 0, unit: "mg/g" },
|
|
4967
|
-
source: "tietz-7ed-2015"
|
|
4968
|
-
},
|
|
4969
|
-
Adiponectin: {
|
|
4970
|
-
default: { max: 26, min: 4, optimalMax: 20, optimalMin: 8, unit: "mcg/mL" },
|
|
4971
|
-
source: "tietz-7ed-2015"
|
|
4972
|
-
},
|
|
4973
|
-
ADMA: {
|
|
4974
|
-
default: { max: 0.7, min: 0.3, optimalMax: 0.55, optimalMin: 0.3, unit: "umol/L" },
|
|
4975
|
-
source: "nemeth-adma-2017"
|
|
4976
|
-
},
|
|
4977
|
-
AFP: {
|
|
4978
|
-
default: { max: 10, min: 0, optimalMax: 8, optimalMin: 0, unit: "ng/mL" },
|
|
4979
|
-
source: "sturgeon-nacb-2008"
|
|
4980
|
-
},
|
|
4981
|
-
Albumin_Globulin_Ratio: {
|
|
4982
|
-
default: { max: 2.5, min: 1, optimalMax: 2.2, optimalMin: 1.2, unit: "" },
|
|
4983
|
-
source: "tietz-7ed-2015"
|
|
4984
|
-
},
|
|
4985
|
-
Albumin: {
|
|
4986
|
-
default: { max: 5, min: 3.5, optimalMax: 4.8, optimalMin: 4, unit: "g/dL" },
|
|
4987
|
-
source: "pns-bioquimica-2019"
|
|
4988
|
-
},
|
|
4989
|
-
AlkalinePhosphatase: {
|
|
4990
|
-
default: { max: 147, min: 44, optimalMax: 120, optimalMin: 50, unit: "U/L" },
|
|
4991
|
-
source: "tietz-7ed-2015",
|
|
4992
|
-
variants: [
|
|
4993
|
-
{
|
|
4994
|
-
ageMin: 18,
|
|
4995
|
-
range: { max: 147, min: 44, optimalMax: 120, optimalMin: 50, unit: "U/L" },
|
|
4996
|
-
sex: "M"
|
|
4997
|
-
},
|
|
4998
|
-
{
|
|
4999
|
-
ageMin: 18,
|
|
5000
|
-
range: { max: 104, min: 35, optimalMax: 90, optimalMin: 40, unit: "U/L" },
|
|
5001
|
-
sex: "F"
|
|
5002
|
-
}
|
|
5003
|
-
]
|
|
5004
|
-
},
|
|
5005
|
-
ALT: {
|
|
5006
|
-
default: { max: 35, min: 0, optimalMax: 25, optimalMin: 0, unit: "U/L" },
|
|
5007
|
-
source: "tietz-7ed-2015",
|
|
5008
|
-
variants: [
|
|
5009
|
-
{
|
|
5010
|
-
ageMin: 18,
|
|
5011
|
-
range: { max: 56, min: 7, optimalMax: 35, optimalMin: 10, unit: "U/L" },
|
|
5012
|
-
sex: "M"
|
|
5013
|
-
},
|
|
5014
|
-
{
|
|
5015
|
-
ageMin: 18,
|
|
5016
|
-
range: { max: 45, min: 7, optimalMax: 30, optimalMin: 10, unit: "U/L" },
|
|
5017
|
-
sex: "F"
|
|
5018
|
-
}
|
|
5019
|
-
]
|
|
5020
|
-
},
|
|
5021
|
-
// AMH — fortemente dependente de idade e sexo. As variantes femininas por
|
|
5022
|
-
// faixa etária são a referência clínica; o `default` foi ajustado para
|
|
5023
|
-
// refletir uma faixa adulta conservadora (~18-40 anos, mulheres em idade
|
|
5024
|
-
// reprodutiva geral). optimalMax anterior (6.9 ng/mL) sobrepunha-se a
|
|
5025
|
-
// valores sugestivos de SOP ou risco de OHSS; clinicamente, valores acima
|
|
5026
|
-
// de ~4 ng/mL já merecem investigação.
|
|
5027
|
-
AMH: {
|
|
5028
|
-
default: { max: 6, min: 1, optimalMax: 4, optimalMin: 1.5, unit: "ng/mL" },
|
|
5029
|
-
source: "tietz-7ed-2015",
|
|
5030
|
-
variants: [
|
|
5031
|
-
{
|
|
5032
|
-
ageMax: 24,
|
|
5033
|
-
ageMin: 18,
|
|
5034
|
-
range: { max: 13, min: 1.5, optimalMax: 10, optimalMin: 3, unit: "ng/mL" },
|
|
5035
|
-
sex: "F"
|
|
5036
|
-
},
|
|
4526
|
+
ageMax: 24,
|
|
4527
|
+
ageMin: 18,
|
|
4528
|
+
range: { max: 13, min: 1.5, optimalMax: 10, optimalMin: 3, unit: "ng/mL" },
|
|
4529
|
+
sex: "F"
|
|
4530
|
+
},
|
|
5037
4531
|
{
|
|
5038
4532
|
ageMax: 30,
|
|
5039
4533
|
ageMin: 25,
|
|
@@ -5061,14 +4555,17 @@ var biomarkerRangeDefinitions = {
|
|
|
5061
4555
|
},
|
|
5062
4556
|
Ammonia: {
|
|
5063
4557
|
default: { max: 45, min: 15, optimalMax: 40, optimalMin: 20, unit: "umol/L" },
|
|
4558
|
+
kind: "reference-interval",
|
|
5064
4559
|
source: "tietz-7ed-2015"
|
|
5065
4560
|
},
|
|
5066
4561
|
AntiThyroglobulin: {
|
|
5067
4562
|
default: { max: 115, min: 0, optimalMax: 40, optimalMin: 0, unit: "IU/mL" },
|
|
4563
|
+
kind: "reference-interval",
|
|
5068
4564
|
source: "tietz-7ed-2015"
|
|
5069
4565
|
},
|
|
5070
4566
|
AntiTPO: {
|
|
5071
4567
|
default: { max: 34, min: 0, optimalMax: 9, optimalMin: 0, unit: "IU/mL" },
|
|
4568
|
+
kind: "reference-interval",
|
|
5072
4569
|
source: "tietz-7ed-2015"
|
|
5073
4570
|
},
|
|
5074
4571
|
// Aortic valve calcium — no standardized clinical threshold; use mild cutoff
|
|
@@ -5076,23 +4573,28 @@ var biomarkerRangeDefinitions = {
|
|
|
5076
4573
|
AorticValveCalcium: {
|
|
5077
4574
|
default: { max: 99, min: 0, optimalMax: 0, optimalMin: 0, unit: "AU" },
|
|
5078
4575
|
direction: "lower-better",
|
|
4576
|
+
kind: "decision-threshold",
|
|
5079
4577
|
source: "rumberger-cac-1999"
|
|
5080
4578
|
},
|
|
5081
4579
|
ApoA1: {
|
|
5082
4580
|
default: { max: 200, min: 100, optimalMax: 180, optimalMin: 120, unit: "mg/dL" },
|
|
4581
|
+
kind: "reference-interval",
|
|
5083
4582
|
source: "contois-apoa1-1996"
|
|
5084
4583
|
},
|
|
5085
4584
|
ApoB: {
|
|
5086
4585
|
default: { max: 90, min: 0, optimalMax: 70, optimalMin: 0, unit: "mg/dL" },
|
|
5087
4586
|
direction: "lower-better",
|
|
4587
|
+
kind: "decision-threshold",
|
|
5088
4588
|
source: "sbc-lipids-2025"
|
|
5089
4589
|
},
|
|
5090
4590
|
ApoCIII: {
|
|
5091
4591
|
default: { max: 10, min: 0, optimalMax: 7, optimalMin: 0, unit: "mg/dL" },
|
|
4592
|
+
kind: "decision-threshold",
|
|
5092
4593
|
source: "khetarpal-apociii-2016"
|
|
5093
4594
|
},
|
|
5094
4595
|
Omega6_AA: {
|
|
5095
4596
|
default: { max: 15, min: 5, optimalMax: 12, optimalMin: 7, unit: "%" },
|
|
4597
|
+
kind: "decision-threshold",
|
|
5096
4598
|
source: "simopoulos-omega-ratio-2002"
|
|
5097
4599
|
},
|
|
5098
4600
|
// Razão Ácido Araquidônico/EPA (sangue total) — `lower-better`: razão menor =
|
|
@@ -5105,16 +4607,19 @@ var biomarkerRangeDefinitions = {
|
|
|
5105
4607
|
// dentro do intervalo. Sem `optimal*`: não há corte ótimo de AA/EPA com fonte.
|
|
5106
4608
|
// Em telas de relatório único, prefira o intervalo impresso pelo laboratório.
|
|
5107
4609
|
AA_EPA_Ratio: {
|
|
5108
|
-
default: { max: 40.7, min: 3.7, unit: "" },
|
|
4610
|
+
default: { max: 40.7, min: 3.7, minKind: "display", unit: "" },
|
|
5109
4611
|
direction: "lower-better",
|
|
4612
|
+
kind: "population",
|
|
5110
4613
|
source: "torrissen-omega3-dbs-2025"
|
|
5111
4614
|
},
|
|
5112
4615
|
Arsenic: {
|
|
5113
4616
|
default: { max: 35, min: 0, optimalMax: 20, optimalMin: 0, unit: "mcg/L" },
|
|
4617
|
+
kind: "decision-threshold",
|
|
5114
4618
|
source: "nr7-pcmso-2020"
|
|
5115
4619
|
},
|
|
5116
4620
|
AST: {
|
|
5117
4621
|
default: { max: 35, min: 0, optimalMax: 25, optimalMin: 0, unit: "U/L" },
|
|
4622
|
+
kind: "reference-interval",
|
|
5118
4623
|
source: "tietz-7ed-2015",
|
|
5119
4624
|
variants: [
|
|
5120
4625
|
{
|
|
@@ -5133,6 +4638,7 @@ var biomarkerRangeDefinitions = {
|
|
|
5133
4638
|
// Tabela 2 da PNS 2019. Ver o comentário em `Neutrophils_Abs`.
|
|
5134
4639
|
Basophils_Abs: {
|
|
5135
4640
|
default: { max: 0.072, min: 0, unit: "K/uL" },
|
|
4641
|
+
kind: "reference-interval",
|
|
5136
4642
|
source: "pns-hemograma-2019",
|
|
5137
4643
|
variants: [
|
|
5138
4644
|
{ ageMin: 18, range: { max: 0.062, min: 0, unit: "K/uL" }, sex: "M" },
|
|
@@ -5141,6 +4647,7 @@ var biomarkerRangeDefinitions = {
|
|
|
5141
4647
|
},
|
|
5142
4648
|
Bicarbonate: {
|
|
5143
4649
|
default: { max: 29, min: 23, optimalMax: 28, optimalMin: 24, unit: "mEq/L" },
|
|
4650
|
+
kind: "reference-interval",
|
|
5144
4651
|
source: "tietz-7ed-2015"
|
|
5145
4652
|
},
|
|
5146
4653
|
// β-Hidroxibutirato (BHB) sérico — corpos cetônicos. Faixa derivada de
|
|
@@ -5150,23 +4657,28 @@ var biomarkerRangeDefinitions = {
|
|
|
5150
4657
|
// superior aqui reflete estado pós-prandial habitual, não jejum.
|
|
5151
4658
|
BetaHydroxybutyrate: {
|
|
5152
4659
|
default: { max: 0.28, min: 0.02, optimalMax: 0.28, optimalMin: 0.02, unit: "mmol/L" },
|
|
4660
|
+
kind: "reference-interval",
|
|
5153
4661
|
source: "klee-bhb-2020"
|
|
5154
4662
|
},
|
|
5155
4663
|
BilirubinDirect: {
|
|
5156
4664
|
default: { max: 0.3, min: 0, optimalMax: 0.2, optimalMin: 0, unit: "mg/dL" },
|
|
4665
|
+
kind: "reference-interval",
|
|
5157
4666
|
source: "tietz-7ed-2015"
|
|
5158
4667
|
},
|
|
5159
4668
|
BilirubinIndirect: {
|
|
5160
4669
|
default: { max: 0.8, min: 0, optimalMax: 0.6, optimalMin: 0, unit: "mg/dL" },
|
|
4670
|
+
kind: "reference-interval",
|
|
5161
4671
|
source: "tietz-7ed-2015"
|
|
5162
4672
|
},
|
|
5163
4673
|
BilirubinTotal: {
|
|
5164
4674
|
default: { max: 1.2, min: 0.1, optimalMax: 0.9, optimalMin: 0.2, unit: "mg/dL" },
|
|
4675
|
+
kind: "reference-interval",
|
|
5165
4676
|
source: "tietz-7ed-2015"
|
|
5166
4677
|
},
|
|
5167
4678
|
// BNP: 35 pg/mL = corte não-agudo para triagem de IC (SBC IC 2018)
|
|
5168
4679
|
BNP: {
|
|
5169
4680
|
default: { max: 35, min: 0, optimalMax: 20, optimalMin: 0, unit: "pg/mL" },
|
|
4681
|
+
kind: "decision-threshold",
|
|
5170
4682
|
source: "sbc-ic-2018"
|
|
5171
4683
|
},
|
|
5172
4684
|
// Razão BUN/Creatinina — faixa 10-20 aplica-se ao Nitrogênio Ureico (BUN).
|
|
@@ -5177,14 +4689,17 @@ var biomarkerRangeDefinitions = {
|
|
|
5177
4689
|
// distinta. Ver issue #41 para alinhamento de nomenclatura/LOINC.
|
|
5178
4690
|
BUN_Creatinine_Ratio: {
|
|
5179
4691
|
default: { max: 20, min: 10, optimalMax: 18, optimalMin: 12, unit: "" },
|
|
4692
|
+
kind: "reference-interval",
|
|
5180
4693
|
source: "tietz-7ed-2015"
|
|
5181
4694
|
},
|
|
5182
4695
|
CA125: {
|
|
5183
4696
|
default: { max: 35, min: 0, optimalMax: 25, optimalMin: 0, unit: "U/mL" },
|
|
4697
|
+
kind: "reference-interval",
|
|
5184
4698
|
source: "sturgeon-nacb-2008"
|
|
5185
4699
|
},
|
|
5186
4700
|
CA199: {
|
|
5187
4701
|
default: { max: 37, min: 0, optimalMax: 30, optimalMin: 0, unit: "U/mL" },
|
|
4702
|
+
kind: "reference-interval",
|
|
5188
4703
|
source: "sturgeon-nacb-2008"
|
|
5189
4704
|
},
|
|
5190
4705
|
// CAC: Agatston classification — 0=none, 1-99=mild, 100-399=moderate, 400+=severe
|
|
@@ -5192,44 +4707,53 @@ var biomarkerRangeDefinitions = {
|
|
|
5192
4707
|
CAC: {
|
|
5193
4708
|
default: { max: 99, min: 0, optimalMax: 0, optimalMin: 0, unit: "AU" },
|
|
5194
4709
|
direction: "lower-better",
|
|
4710
|
+
kind: "decision-threshold",
|
|
5195
4711
|
source: "rumberger-cac-1999"
|
|
5196
4712
|
},
|
|
5197
4713
|
// Per-vessel scores — same Agatston classification applied per vessel
|
|
5198
4714
|
CAC_LAD: {
|
|
5199
4715
|
default: { max: 99, min: 0, optimalMax: 0, optimalMin: 0, unit: "AU" },
|
|
5200
4716
|
direction: "lower-better",
|
|
4717
|
+
kind: "decision-threshold",
|
|
5201
4718
|
source: "rumberger-cac-1999"
|
|
5202
4719
|
},
|
|
5203
4720
|
CAC_LCX: {
|
|
5204
4721
|
default: { max: 99, min: 0, optimalMax: 0, optimalMin: 0, unit: "AU" },
|
|
5205
4722
|
direction: "lower-better",
|
|
4723
|
+
kind: "decision-threshold",
|
|
5206
4724
|
source: "rumberger-cac-1999"
|
|
5207
4725
|
},
|
|
5208
4726
|
CAC_LMA: {
|
|
5209
4727
|
default: { max: 99, min: 0, optimalMax: 0, optimalMin: 0, unit: "AU" },
|
|
5210
4728
|
direction: "lower-better",
|
|
4729
|
+
kind: "decision-threshold",
|
|
5211
4730
|
source: "rumberger-cac-1999"
|
|
5212
4731
|
},
|
|
5213
4732
|
CAC_Percentile: {
|
|
5214
4733
|
default: { max: 50, min: 0, optimalMax: 25, optimalMin: 0, unit: "%", warningMax: 75 },
|
|
5215
4734
|
direction: "lower-better",
|
|
4735
|
+
kind: "decision-threshold",
|
|
5216
4736
|
source: "rumberger-cac-1999"
|
|
5217
4737
|
},
|
|
5218
4738
|
CAC_RCA: {
|
|
5219
4739
|
default: { max: 99, min: 0, optimalMax: 0, optimalMin: 0, unit: "AU" },
|
|
5220
4740
|
direction: "lower-better",
|
|
4741
|
+
kind: "decision-threshold",
|
|
5221
4742
|
source: "rumberger-cac-1999"
|
|
5222
4743
|
},
|
|
5223
4744
|
Cadmium: {
|
|
5224
4745
|
default: { max: 1.2, min: 0, optimalMax: 0.5, optimalMin: 0, unit: "mcg/L" },
|
|
4746
|
+
kind: "decision-threshold",
|
|
5225
4747
|
source: "nr7-pcmso-2020"
|
|
5226
4748
|
},
|
|
5227
4749
|
Calcium: {
|
|
5228
4750
|
default: { max: 10.5, min: 8.5, optimalMax: 10, optimalMin: 9, unit: "mg/dL" },
|
|
4751
|
+
kind: "reference-interval",
|
|
5229
4752
|
source: "tietz-7ed-2015"
|
|
5230
4753
|
},
|
|
5231
4754
|
CEA: {
|
|
5232
4755
|
default: { max: 3, min: 0, optimalMax: 2.5, optimalMin: 0, unit: "ng/mL" },
|
|
4756
|
+
kind: "reference-interval",
|
|
5233
4757
|
source: "sturgeon-nacb-2008"
|
|
5234
4758
|
},
|
|
5235
4759
|
// CK: valores conservadores baseados em faixas laboratoriais típicas
|
|
@@ -5254,6 +4778,7 @@ var biomarkerRangeDefinitions = {
|
|
|
5254
4778
|
// autodeclaração de raça/Cor". Ver a issue #3 para a decisão registrada.
|
|
5255
4779
|
CK: {
|
|
5256
4780
|
default: { max: 314, min: 30, optimalMax: 170, optimalMin: 40, unit: "U/L" },
|
|
4781
|
+
kind: "reference-interval",
|
|
5257
4782
|
source: "kalaria-ck-ri-2026",
|
|
5258
4783
|
variants: [
|
|
5259
4784
|
{ sex: "F", range: { max: 170, min: 30, optimalMax: 150, optimalMin: 40, unit: "U/L" } }
|
|
@@ -5261,6 +4786,7 @@ var biomarkerRangeDefinitions = {
|
|
|
5261
4786
|
},
|
|
5262
4787
|
Chloride: {
|
|
5263
4788
|
default: { max: 106, min: 98, optimalMax: 105, optimalMin: 100, unit: "mEq/L" },
|
|
4789
|
+
kind: "reference-interval",
|
|
5264
4790
|
source: "tietz-7ed-2015"
|
|
5265
4791
|
},
|
|
5266
4792
|
// Colesterol total — SBC 2017/2025: valor desejável < 190 mg/dL para adultos,
|
|
@@ -5268,6 +4794,7 @@ var biomarkerRangeDefinitions = {
|
|
|
5268
4794
|
// (NCEP, 2002), superada pelas atualizações brasileiras.
|
|
5269
4795
|
Cholesterol: {
|
|
5270
4796
|
default: { max: 190, min: 0, optimalMax: 170, optimalMin: 0, unit: "mg/dL" },
|
|
4797
|
+
kind: "decision-threshold",
|
|
5271
4798
|
source: "sbc-lipids-2025"
|
|
5272
4799
|
},
|
|
5273
4800
|
// Índice de Castelli I (CT/HDL-c)
|
|
@@ -5275,6 +4802,7 @@ var biomarkerRangeDefinitions = {
|
|
|
5275
4802
|
// Índice de Castelli I — SBC 2017: M <4.9, F <4.3
|
|
5276
4803
|
default: { max: 4.9, min: 0, optimalMax: 3.5, optimalMin: 0, unit: "" },
|
|
5277
4804
|
direction: "lower-better",
|
|
4805
|
+
kind: "decision-threshold",
|
|
5278
4806
|
source: "castelli-ratio-1992",
|
|
5279
4807
|
variants: [
|
|
5280
4808
|
{
|
|
@@ -5291,22 +4819,27 @@ var biomarkerRangeDefinitions = {
|
|
|
5291
4819
|
},
|
|
5292
4820
|
CO2: {
|
|
5293
4821
|
default: { max: 29, min: 23, optimalMax: 28, optimalMin: 24, unit: "mEq/L" },
|
|
4822
|
+
kind: "reference-interval",
|
|
5294
4823
|
source: "tietz-7ed-2015"
|
|
5295
4824
|
},
|
|
5296
4825
|
Copper: {
|
|
5297
4826
|
default: { max: 175, min: 70, optimalMax: 150, optimalMin: 85, unit: "mcg/dL" },
|
|
4827
|
+
kind: "reference-interval",
|
|
5298
4828
|
source: "tietz-7ed-2015"
|
|
5299
4829
|
},
|
|
5300
4830
|
CoQ10: {
|
|
5301
4831
|
default: { max: 1.5, min: 0.5, optimalMax: 1.3, optimalMin: 0.7, unit: "mg/L" },
|
|
4832
|
+
kind: "reference-interval",
|
|
5302
4833
|
source: "tietz-7ed-2015"
|
|
5303
4834
|
},
|
|
5304
4835
|
Cortisol: {
|
|
5305
4836
|
default: { max: 25, min: 5, optimalMax: 20, optimalMin: 10, unit: "mcg/dL" },
|
|
4837
|
+
kind: "reference-interval",
|
|
5306
4838
|
source: "tietz-7ed-2015"
|
|
5307
4839
|
},
|
|
5308
4840
|
CortisolFree: {
|
|
5309
4841
|
default: { max: 2.5, min: 0.5, optimalMax: 2, optimalMin: 0.8, unit: "mcg/dL" },
|
|
4842
|
+
kind: "reference-interval",
|
|
5310
4843
|
source: "tietz-7ed-2015"
|
|
5311
4844
|
},
|
|
5312
4845
|
CPeptide: {
|
|
@@ -5318,10 +4851,12 @@ var biomarkerRangeDefinitions = {
|
|
|
5318
4851
|
optimalMin: 1,
|
|
5319
4852
|
unit: "ng/mL"
|
|
5320
4853
|
},
|
|
4854
|
+
kind: "reference-interval",
|
|
5321
4855
|
source: "tietz-7ed-2015"
|
|
5322
4856
|
},
|
|
5323
4857
|
Creatinine: {
|
|
5324
4858
|
default: { max: 1.2, min: 0.6, optimalMax: 1, optimalMin: 0.7, unit: "mg/dL" },
|
|
4859
|
+
kind: "reference-interval",
|
|
5325
4860
|
source: "pns-bioquimica-2019",
|
|
5326
4861
|
variants: [
|
|
5327
4862
|
// Gestação: hiperfiltração glomerular (↑ 40–50% GFR) reduz a creatinina
|
|
@@ -5347,10 +4882,12 @@ var biomarkerRangeDefinitions = {
|
|
|
5347
4882
|
CRP: {
|
|
5348
4883
|
default: { max: 3, min: 0, optimalMax: 1, optimalMin: 0, unit: "mg/L" },
|
|
5349
4884
|
direction: "lower-better",
|
|
4885
|
+
kind: "decision-threshold",
|
|
5350
4886
|
source: "tietz-7ed-2015"
|
|
5351
4887
|
},
|
|
5352
4888
|
CystatinC: {
|
|
5353
4889
|
default: { max: 1, min: 0.5, optimalMax: 0.9, optimalMin: 0.6, unit: "mg/L" },
|
|
4890
|
+
kind: "reference-interval",
|
|
5354
4891
|
source: "tietz-7ed-2015"
|
|
5355
4892
|
},
|
|
5356
4893
|
// D-Dímero — exame de exclusão de TEV (tromboembolismo venoso) com
|
|
@@ -5364,6 +4901,7 @@ var biomarkerRangeDefinitions = {
|
|
|
5364
4901
|
DDimer: {
|
|
5365
4902
|
default: { max: 500, min: 0, unit: "ng/mL" },
|
|
5366
4903
|
direction: "lower-better",
|
|
4904
|
+
kind: "decision-threshold",
|
|
5367
4905
|
source: "wells-ddimer-2003",
|
|
5368
4906
|
variants: [
|
|
5369
4907
|
// Corte ajustado por idade — ESC 2019 (Konstantinides et al.) e
|
|
@@ -5377,10 +4915,12 @@ var biomarkerRangeDefinitions = {
|
|
|
5377
4915
|
},
|
|
5378
4916
|
Omega3_DHA: {
|
|
5379
4917
|
default: { max: 8, min: 2, optimalMax: 6.5, optimalMin: 3.5, unit: "%" },
|
|
4918
|
+
kind: "decision-threshold",
|
|
5380
4919
|
source: "harris-omega3-2004"
|
|
5381
4920
|
},
|
|
5382
4921
|
DHEAS: {
|
|
5383
4922
|
default: { max: 500, min: 100, optimalMax: 400, optimalMin: 150, unit: "mcg/dL" },
|
|
4923
|
+
kind: "reference-interval",
|
|
5384
4924
|
source: "tietz-7ed-2015",
|
|
5385
4925
|
variants: [
|
|
5386
4926
|
{
|
|
@@ -5421,20 +4961,30 @@ var biomarkerRangeDefinitions = {
|
|
|
5421
4961
|
},
|
|
5422
4962
|
Omega3_DPA: {
|
|
5423
4963
|
default: { max: 2, min: 0.3, optimalMax: 1.5, optimalMin: 0.5, unit: "%" },
|
|
4964
|
+
kind: "decision-threshold",
|
|
5424
4965
|
source: "harris-omega3-2004"
|
|
5425
4966
|
},
|
|
5426
4967
|
eGFR: {
|
|
5427
|
-
default: {
|
|
4968
|
+
default: {
|
|
4969
|
+
max: 120,
|
|
4970
|
+
maxKind: "display",
|
|
4971
|
+
min: 60,
|
|
4972
|
+
optimalMax: 120,
|
|
4973
|
+
optimalMin: 90,
|
|
4974
|
+
unit: "mL/min/1.73m\xB2"
|
|
4975
|
+
},
|
|
5428
4976
|
// KDIGO 2024: TFG 60-89 (G2) sem marcador de lesão renal não é DRC, em
|
|
5429
4977
|
// nenhuma faixa etária. A variante por idade que existia aqui rebaixava o
|
|
5430
4978
|
// piso só para 60+ e ainda limitava o teto a 90, o que sinalizava como
|
|
5431
4979
|
// alterado qualquer idoso com função preservada.
|
|
4980
|
+
kind: "decision-threshold",
|
|
5432
4981
|
source: "kdigo-ckd-2024"
|
|
5433
4982
|
},
|
|
5434
4983
|
// `Eosinophils` (%) fica sem faixa de propósito e `Eosinophils_Abs` usa os limites da
|
|
5435
4984
|
// Tabela 2 da PNS 2019. Ver o comentário em `Neutrophils_Abs`.
|
|
5436
4985
|
Eosinophils_Abs: {
|
|
5437
4986
|
default: { max: 0.66, min: 0, unit: "K/uL" },
|
|
4987
|
+
kind: "reference-interval",
|
|
5438
4988
|
source: "pns-hemograma-2019",
|
|
5439
4989
|
variants: [
|
|
5440
4990
|
{ ageMin: 18, range: { max: 0.66, min: 0, unit: "K/uL" }, sex: "M" },
|
|
@@ -5443,18 +4993,22 @@ var biomarkerRangeDefinitions = {
|
|
|
5443
4993
|
},
|
|
5444
4994
|
Omega3_EPA: {
|
|
5445
4995
|
default: { max: 3.5, min: 0.5, optimalMax: 2.5, optimalMin: 1, unit: "%" },
|
|
4996
|
+
kind: "decision-threshold",
|
|
5446
4997
|
source: "harris-omega3-2004"
|
|
5447
4998
|
},
|
|
5448
4999
|
EPADPADHA: {
|
|
5449
5000
|
default: { max: 10, min: 3, optimalMax: 9, optimalMin: 5, unit: "%" },
|
|
5001
|
+
kind: "decision-threshold",
|
|
5450
5002
|
source: "harris-omega3-2004"
|
|
5451
5003
|
},
|
|
5452
5004
|
ESR: {
|
|
5453
5005
|
default: { max: 20, min: 0, optimalMax: 10, optimalMin: 0, unit: "mm/hr" },
|
|
5006
|
+
kind: "reference-interval",
|
|
5454
5007
|
source: "tietz-7ed-2015"
|
|
5455
5008
|
},
|
|
5456
5009
|
Estradiol: {
|
|
5457
5010
|
default: { max: 40, min: 10, optimalMax: 35, optimalMin: 15, unit: "pg/mL" },
|
|
5011
|
+
kind: "reference-interval",
|
|
5458
5012
|
source: "tietz-7ed-2015",
|
|
5459
5013
|
variants: [
|
|
5460
5014
|
{
|
|
@@ -5477,6 +5031,7 @@ var biomarkerRangeDefinitions = {
|
|
|
5477
5031
|
},
|
|
5478
5032
|
F2Isoprostanes: {
|
|
5479
5033
|
default: { max: 86, min: 0, optimalMax: 60, optimalMin: 0, unit: "pg/mL" },
|
|
5034
|
+
kind: "reference-interval",
|
|
5480
5035
|
source: "tietz-7ed-2015"
|
|
5481
5036
|
},
|
|
5482
5037
|
// Ferritina — WHO 2020 é o documento de referência específico para avaliação
|
|
@@ -5486,6 +5041,7 @@ var biomarkerRangeDefinitions = {
|
|
|
5486
5041
|
// tipo de faixa, mas documentado aqui para consumidores).
|
|
5487
5042
|
Ferritin: {
|
|
5488
5043
|
default: { max: 150, min: 12, optimalMax: 120, optimalMin: 30, unit: "ng/mL" },
|
|
5044
|
+
kind: "decision-threshold",
|
|
5489
5045
|
source: "who-iron-2020",
|
|
5490
5046
|
variants: [
|
|
5491
5047
|
// Gestação: ferritina cai fisiologicamente no 2º/3º trimestre pela expansão
|
|
@@ -5518,14 +5074,17 @@ var biomarkerRangeDefinitions = {
|
|
|
5518
5074
|
// Fibrinogênio: 200-400 mg/dL — faixa de referência padrão (método de Clauss)
|
|
5519
5075
|
Fibrinogen: {
|
|
5520
5076
|
default: { max: 400, min: 200, optimalMax: 350, optimalMin: 250, unit: "mg/dL" },
|
|
5077
|
+
kind: "reference-interval",
|
|
5521
5078
|
source: "tietz-7ed-2015"
|
|
5522
5079
|
},
|
|
5523
5080
|
FolicAcid: {
|
|
5524
5081
|
default: { max: 20, min: 3, optimalMax: 15, optimalMin: 5, unit: "ng/mL" },
|
|
5082
|
+
kind: "reference-interval",
|
|
5525
5083
|
source: "tietz-7ed-2015"
|
|
5526
5084
|
},
|
|
5527
5085
|
FSH: {
|
|
5528
5086
|
default: { max: 12.4, min: 1.5, optimalMax: 10, optimalMin: 3, unit: "mIU/mL" },
|
|
5087
|
+
kind: "reference-interval",
|
|
5529
5088
|
source: "tietz-7ed-2015",
|
|
5530
5089
|
variants: [
|
|
5531
5090
|
{
|
|
@@ -5549,26 +5108,29 @@ var biomarkerRangeDefinitions = {
|
|
|
5549
5108
|
GGT: {
|
|
5550
5109
|
default: { max: 55, min: 0, optimalMax: 30, optimalMin: 0, unit: "U/L" },
|
|
5551
5110
|
direction: "lower-better",
|
|
5111
|
+
kind: "reference-interval",
|
|
5552
5112
|
source: "tietz-7ed-2015",
|
|
5553
5113
|
variants: [
|
|
5554
5114
|
{
|
|
5555
5115
|
ageMin: 18,
|
|
5556
|
-
range: { max: 61, min: 8, optimalMax: 40, optimalMin: 10, unit: "U/L" },
|
|
5116
|
+
range: { max: 61, min: 8, minKind: "display", optimalMax: 40, optimalMin: 10, unit: "U/L" },
|
|
5557
5117
|
sex: "M"
|
|
5558
5118
|
},
|
|
5559
5119
|
{
|
|
5560
5120
|
ageMin: 18,
|
|
5561
|
-
range: { max: 36, min: 5, optimalMax: 25, optimalMin: 8, unit: "U/L" },
|
|
5121
|
+
range: { max: 36, min: 5, minKind: "display", optimalMax: 25, optimalMin: 8, unit: "U/L" },
|
|
5562
5122
|
sex: "F"
|
|
5563
5123
|
}
|
|
5564
5124
|
]
|
|
5565
5125
|
},
|
|
5566
5126
|
Ghrelin: {
|
|
5567
5127
|
default: { max: 1e3, min: 300, optimalMax: 800, optimalMin: 400, unit: "pg/mL" },
|
|
5128
|
+
kind: "reference-interval",
|
|
5568
5129
|
source: "tietz-7ed-2015"
|
|
5569
5130
|
},
|
|
5570
5131
|
Globulin: {
|
|
5571
5132
|
default: { max: 3.5, min: 2, optimalMax: 3.2, optimalMin: 2.3, unit: "g/dL" },
|
|
5133
|
+
kind: "reference-interval",
|
|
5572
5134
|
source: "tietz-7ed-2015"
|
|
5573
5135
|
},
|
|
5574
5136
|
// A faixa é de jejum, então mora na definição que afirma jejum. Glicose
|
|
@@ -5591,6 +5153,7 @@ var biomarkerRangeDefinitions = {
|
|
|
5591
5153
|
optimalMin: 70,
|
|
5592
5154
|
unit: "mg/dL"
|
|
5593
5155
|
},
|
|
5156
|
+
kind: "decision-threshold",
|
|
5594
5157
|
source: "sbd-diabetes-2024",
|
|
5595
5158
|
variants: [
|
|
5596
5159
|
// Gestação: DMG (IADPSG/SBD 2024) usa cortes mais restritivos na glicemia
|
|
@@ -5612,10 +5175,12 @@ var biomarkerRangeDefinitions = {
|
|
|
5612
5175
|
},
|
|
5613
5176
|
GlycoMark: {
|
|
5614
5177
|
default: { max: 40, min: 10, optimalMax: 35, optimalMin: 15, unit: "mcg/mL" },
|
|
5178
|
+
kind: "reference-interval",
|
|
5615
5179
|
source: "tietz-7ed-2015"
|
|
5616
5180
|
},
|
|
5617
5181
|
GrowthHormone: {
|
|
5618
5182
|
default: { max: 5, min: 0, optimalMax: 3, optimalMin: 0, unit: "ng/mL" },
|
|
5183
|
+
kind: "reference-interval",
|
|
5619
5184
|
source: "tietz-7ed-2015"
|
|
5620
5185
|
},
|
|
5621
5186
|
// HbA1c — SBD 2024 não estabelece piso de referência clinicamente acionável.
|
|
@@ -5625,11 +5190,13 @@ var biomarkerRangeDefinitions = {
|
|
|
5625
5190
|
// criar flag clínico em valores fisiologicamente baixos. optimalMin preserva
|
|
5626
5191
|
// o alvo fisiológico da fração glicada.
|
|
5627
5192
|
HbA1c: {
|
|
5628
|
-
default: { max: 5.7, min: 2, optimalMax: 5.3, optimalMin: 4.5, unit: "%" },
|
|
5193
|
+
default: { max: 5.7, min: 2, minKind: "display", optimalMax: 5.3, optimalMin: 4.5, unit: "%" },
|
|
5194
|
+
kind: "decision-threshold",
|
|
5629
5195
|
source: "sbd-diabetes-2024"
|
|
5630
5196
|
},
|
|
5631
5197
|
Hct: {
|
|
5632
5198
|
default: { max: 50, min: 36, optimalMax: 48, optimalMin: 40, unit: "%" },
|
|
5199
|
+
kind: "reference-interval",
|
|
5633
5200
|
source: "pns-hemograma-2019",
|
|
5634
5201
|
variants: [
|
|
5635
5202
|
{
|
|
@@ -5651,18 +5218,40 @@ var biomarkerRangeDefinitions = {
|
|
|
5651
5218
|
// não como ponto de corte clínico; consumidores devem tratar `direction:
|
|
5652
5219
|
// higher-better` como sinal autoritativo.
|
|
5653
5220
|
HDL: {
|
|
5654
|
-
default: {
|
|
5221
|
+
default: {
|
|
5222
|
+
max: 100,
|
|
5223
|
+
maxKind: "display",
|
|
5224
|
+
min: 40,
|
|
5225
|
+
optimalMax: 100,
|
|
5226
|
+
optimalMin: 50,
|
|
5227
|
+
unit: "mg/dL"
|
|
5228
|
+
},
|
|
5655
5229
|
direction: "higher-better",
|
|
5230
|
+
kind: "decision-threshold",
|
|
5656
5231
|
source: "sbc-lipids-2025",
|
|
5657
5232
|
variants: [
|
|
5658
5233
|
{
|
|
5659
5234
|
ageMin: 18,
|
|
5660
|
-
range: {
|
|
5235
|
+
range: {
|
|
5236
|
+
max: 100,
|
|
5237
|
+
maxKind: "display",
|
|
5238
|
+
min: 40,
|
|
5239
|
+
optimalMax: 100,
|
|
5240
|
+
optimalMin: 45,
|
|
5241
|
+
unit: "mg/dL"
|
|
5242
|
+
},
|
|
5661
5243
|
sex: "M"
|
|
5662
5244
|
},
|
|
5663
5245
|
{
|
|
5664
5246
|
ageMin: 18,
|
|
5665
|
-
range: {
|
|
5247
|
+
range: {
|
|
5248
|
+
max: 100,
|
|
5249
|
+
maxKind: "display",
|
|
5250
|
+
min: 50,
|
|
5251
|
+
optimalMax: 100,
|
|
5252
|
+
optimalMin: 55,
|
|
5253
|
+
unit: "mg/dL"
|
|
5254
|
+
},
|
|
5666
5255
|
sex: "F"
|
|
5667
5256
|
}
|
|
5668
5257
|
]
|
|
@@ -5670,12 +5259,21 @@ var biomarkerRangeDefinitions = {
|
|
|
5670
5259
|
HDL_Large: {
|
|
5671
5260
|
// HDL Large: higher is better
|
|
5672
5261
|
// Quest Ion Mobility reference: Male 4334-10815, Female 5038-17886 nmol/L, optimal >6729
|
|
5673
|
-
default: {
|
|
5262
|
+
default: {
|
|
5263
|
+
max: 17886,
|
|
5264
|
+
maxKind: "display",
|
|
5265
|
+
min: 4334,
|
|
5266
|
+
optimalMax: 17886,
|
|
5267
|
+
optimalMin: 6729,
|
|
5268
|
+
unit: "nmol/L"
|
|
5269
|
+
},
|
|
5674
5270
|
direction: "higher-better",
|
|
5271
|
+
kind: "reference-interval",
|
|
5675
5272
|
source: "caulfield-ionmobility-2008"
|
|
5676
5273
|
},
|
|
5677
5274
|
Hgb: {
|
|
5678
5275
|
default: { max: 17.5, min: 12, optimalMax: 16, optimalMin: 13.5, unit: "g/dL" },
|
|
5276
|
+
kind: "reference-interval",
|
|
5679
5277
|
source: "pns-hemograma-2019",
|
|
5680
5278
|
variants: [
|
|
5681
5279
|
// Gestação: hemodiluição fisiológica reduz o piso aceitável.
|
|
@@ -5731,19 +5329,23 @@ var biomarkerRangeDefinitions = {
|
|
|
5731
5329
|
warningMax: 2.71
|
|
5732
5330
|
},
|
|
5733
5331
|
direction: "lower-better",
|
|
5332
|
+
kind: "decision-threshold",
|
|
5734
5333
|
source: "geloneze-brams-2009"
|
|
5735
5334
|
},
|
|
5736
5335
|
Homocysteine: {
|
|
5737
|
-
default: { max: 15, min: 4, optimalMax: 10, optimalMin: 5, unit: "umol/L" },
|
|
5336
|
+
default: { max: 15, min: 4, minKind: "display", optimalMax: 10, optimalMin: 5, unit: "umol/L" },
|
|
5738
5337
|
direction: "lower-better",
|
|
5338
|
+
kind: "reference-interval",
|
|
5739
5339
|
source: "selhub-homocysteine-1999"
|
|
5740
5340
|
},
|
|
5741
5341
|
IGF1: {
|
|
5742
5342
|
default: { max: 350, min: 100, optimalMax: 300, optimalMin: 150, unit: "ng/mL" },
|
|
5343
|
+
kind: "reference-interval",
|
|
5743
5344
|
source: "tietz-7ed-2015"
|
|
5744
5345
|
},
|
|
5745
5346
|
ImmatureGranulocytes: {
|
|
5746
5347
|
default: { max: 1, min: 0, optimalMax: 0.5, optimalMin: 0, unit: "%" },
|
|
5348
|
+
kind: "reference-interval",
|
|
5747
5349
|
source: "tietz-7ed-2015"
|
|
5748
5350
|
},
|
|
5749
5351
|
Insulin: {
|
|
@@ -5755,10 +5357,12 @@ var biomarkerRangeDefinitions = {
|
|
|
5755
5357
|
optimalMin: 3,
|
|
5756
5358
|
unit: "uIU/mL"
|
|
5757
5359
|
},
|
|
5360
|
+
kind: "reference-interval",
|
|
5758
5361
|
source: "tietz-7ed-2015"
|
|
5759
5362
|
},
|
|
5760
5363
|
Iron: {
|
|
5761
5364
|
default: { max: 170, min: 60, optimalMax: 140, optimalMin: 80, unit: "mcg/dL" },
|
|
5365
|
+
kind: "reference-interval",
|
|
5762
5366
|
source: "sbpc-ml-2021",
|
|
5763
5367
|
variants: [
|
|
5764
5368
|
{
|
|
@@ -5775,6 +5379,7 @@ var biomarkerRangeDefinitions = {
|
|
|
5775
5379
|
},
|
|
5776
5380
|
Lactate: {
|
|
5777
5381
|
default: { max: 2.2, min: 0.5, optimalMax: 1.8, optimalMin: 0.7, unit: "mmol/L" },
|
|
5382
|
+
kind: "reference-interval",
|
|
5778
5383
|
source: "tietz-7ed-2015"
|
|
5779
5384
|
},
|
|
5780
5385
|
// DHL/LDH — método IFCC a 37 °C (padrão atual na maioria dos laboratórios
|
|
@@ -5786,6 +5391,7 @@ var biomarkerRangeDefinitions = {
|
|
|
5786
5391
|
LDH: {
|
|
5787
5392
|
default: { max: 248, min: 0, optimalMax: 248, optimalMin: 0, unit: "U/L" },
|
|
5788
5393
|
direction: "lower-better",
|
|
5394
|
+
kind: "reference-interval",
|
|
5789
5395
|
source: "schumann-ifcc-ldh-2002",
|
|
5790
5396
|
variants: [
|
|
5791
5397
|
{
|
|
@@ -5803,59 +5409,109 @@ var biomarkerRangeDefinitions = {
|
|
|
5803
5409
|
LDL: {
|
|
5804
5410
|
default: { max: 100, min: 0, optimalMax: 70, optimalMin: 0, unit: "mg/dL" },
|
|
5805
5411
|
direction: "lower-better",
|
|
5412
|
+
kind: "decision-threshold",
|
|
5806
5413
|
source: "sbc-lipids-2025"
|
|
5807
5414
|
},
|
|
5808
5415
|
LDL_Medium: {
|
|
5809
5416
|
// LDL Medium (LDL Média): lower is better
|
|
5810
5417
|
// Quest Ion Mobility reference: Male 167-485, Female 121-397 nmol/L, optimal <215
|
|
5811
|
-
default: {
|
|
5418
|
+
default: {
|
|
5419
|
+
max: 485,
|
|
5420
|
+
min: 121,
|
|
5421
|
+
minKind: "display",
|
|
5422
|
+
optimalMax: 215,
|
|
5423
|
+
optimalMin: 121,
|
|
5424
|
+
unit: "nmol/L"
|
|
5425
|
+
},
|
|
5812
5426
|
direction: "lower-better",
|
|
5427
|
+
kind: "reference-interval",
|
|
5813
5428
|
source: "caulfield-ionmobility-2008"
|
|
5814
5429
|
},
|
|
5815
5430
|
LDL_ParticleNumber: {
|
|
5816
5431
|
// LDL Particle Number: lower is better
|
|
5817
5432
|
// Quest Ion Mobility reference: 1016-2185 nmol/L, optimal <1138
|
|
5818
|
-
default: {
|
|
5433
|
+
default: {
|
|
5434
|
+
max: 2185,
|
|
5435
|
+
min: 1016,
|
|
5436
|
+
minKind: "display",
|
|
5437
|
+
optimalMax: 1138,
|
|
5438
|
+
optimalMin: 1016,
|
|
5439
|
+
unit: "nmol/L"
|
|
5440
|
+
},
|
|
5819
5441
|
direction: "lower-better",
|
|
5442
|
+
kind: "reference-interval",
|
|
5820
5443
|
source: "caulfield-ionmobility-2008"
|
|
5821
5444
|
},
|
|
5822
5445
|
LDL_Peak_Size: {
|
|
5823
5446
|
// LDL Peak Size: higher is better (larger particles less atherogenic)
|
|
5824
5447
|
// Quest Ion Mobility reference: optimal >222.9 Å (22.29 nm)
|
|
5825
|
-
default: {
|
|
5448
|
+
default: {
|
|
5449
|
+
max: 250,
|
|
5450
|
+
maxKind: "display",
|
|
5451
|
+
min: 217.4,
|
|
5452
|
+
optimalMax: 250,
|
|
5453
|
+
optimalMin: 222.9,
|
|
5454
|
+
unit: "Angstrom"
|
|
5455
|
+
},
|
|
5826
5456
|
direction: "higher-better",
|
|
5457
|
+
kind: "reference-interval",
|
|
5827
5458
|
source: "caulfield-ionmobility-2008"
|
|
5828
5459
|
},
|
|
5829
5460
|
LDL_Small: {
|
|
5830
5461
|
// LDL Small (LDL Pequena): lower is better (small dense LDL is most atherogenic)
|
|
5831
5462
|
// Quest Ion Mobility reference: Male 123-441, Female 126-382 nmol/L, optimal <142
|
|
5832
|
-
default: {
|
|
5463
|
+
default: {
|
|
5464
|
+
max: 441,
|
|
5465
|
+
min: 123,
|
|
5466
|
+
minKind: "display",
|
|
5467
|
+
optimalMax: 142,
|
|
5468
|
+
optimalMin: 123,
|
|
5469
|
+
unit: "nmol/L"
|
|
5470
|
+
},
|
|
5833
5471
|
direction: "lower-better",
|
|
5472
|
+
kind: "reference-interval",
|
|
5834
5473
|
source: "caulfield-ionmobility-2008"
|
|
5835
5474
|
},
|
|
5836
5475
|
Lead: {
|
|
5837
5476
|
default: { max: 5, min: 0, optimalMax: 2, optimalMin: 0, unit: "mcg/dL" },
|
|
5477
|
+
kind: "decision-threshold",
|
|
5838
5478
|
source: "nr7-pcmso-2020"
|
|
5839
5479
|
},
|
|
5840
5480
|
Leptin: {
|
|
5841
|
-
default: { max: 15, min: 2, optimalMax: 12, optimalMin: 3, unit: "ng/mL" },
|
|
5481
|
+
default: { max: 15, min: 2, minKind: "clinical", optimalMax: 12, optimalMin: 3, unit: "ng/mL" },
|
|
5842
5482
|
direction: "lower-better",
|
|
5483
|
+
kind: "reference-interval",
|
|
5843
5484
|
source: "tietz-7ed-2015",
|
|
5844
5485
|
variants: [
|
|
5845
5486
|
{
|
|
5846
5487
|
ageMin: 18,
|
|
5847
|
-
range: {
|
|
5488
|
+
range: {
|
|
5489
|
+
max: 10,
|
|
5490
|
+
min: 1,
|
|
5491
|
+
minKind: "clinical",
|
|
5492
|
+
optimalMax: 8,
|
|
5493
|
+
optimalMin: 2,
|
|
5494
|
+
unit: "ng/mL"
|
|
5495
|
+
},
|
|
5848
5496
|
sex: "M"
|
|
5849
5497
|
},
|
|
5850
5498
|
{
|
|
5851
5499
|
ageMin: 18,
|
|
5852
|
-
range: {
|
|
5500
|
+
range: {
|
|
5501
|
+
max: 25,
|
|
5502
|
+
min: 4,
|
|
5503
|
+
minKind: "clinical",
|
|
5504
|
+
optimalMax: 18,
|
|
5505
|
+
optimalMin: 5,
|
|
5506
|
+
unit: "ng/mL"
|
|
5507
|
+
},
|
|
5853
5508
|
sex: "F"
|
|
5854
5509
|
}
|
|
5855
5510
|
]
|
|
5856
5511
|
},
|
|
5857
5512
|
LH: {
|
|
5858
5513
|
default: { max: 8.6, min: 1.7, optimalMax: 8, optimalMin: 2, unit: "mIU/mL" },
|
|
5514
|
+
kind: "reference-interval",
|
|
5859
5515
|
source: "tietz-7ed-2015",
|
|
5860
5516
|
variants: [
|
|
5861
5517
|
{
|
|
@@ -5878,6 +5534,7 @@ var biomarkerRangeDefinitions = {
|
|
|
5878
5534
|
},
|
|
5879
5535
|
Omega6_LA: {
|
|
5880
5536
|
default: { max: 35, min: 15, optimalMax: 28, optimalMin: 18, unit: "%" },
|
|
5537
|
+
kind: "decision-threshold",
|
|
5881
5538
|
source: "simopoulos-omega-ratio-2002"
|
|
5882
5539
|
},
|
|
5883
5540
|
// Lp(a) — SBC 2025 (seção 3.1.1.2.7): níveis ≥ 50 mg/dL ou ≥ 125 nmol/L são
|
|
@@ -5889,12 +5546,14 @@ var biomarkerRangeDefinitions = {
|
|
|
5889
5546
|
Lipoprotein_a: {
|
|
5890
5547
|
default: { max: 125, min: 0, optimalMax: 75, optimalMin: 0, unit: "nmol/L" },
|
|
5891
5548
|
direction: "lower-better",
|
|
5549
|
+
kind: "decision-threshold",
|
|
5892
5550
|
source: "sbc-lipids-2025"
|
|
5893
5551
|
},
|
|
5894
5552
|
// `Lymphocytes` (%) fica sem faixa de propósito e `Lymphocytes_Abs` usa os limites da
|
|
5895
5553
|
// Tabela 2 da PNS 2019. Ver o comentário em `Neutrophils_Abs`.
|
|
5896
5554
|
Lymphocytes_Abs: {
|
|
5897
5555
|
default: { max: 3.414, min: 0.72, unit: "K/uL" },
|
|
5556
|
+
kind: "reference-interval",
|
|
5898
5557
|
source: "pns-hemograma-2019",
|
|
5899
5558
|
variants: [
|
|
5900
5559
|
{ ageMin: 18, range: { max: 3.37, min: 0.72, unit: "K/uL" }, sex: "M" },
|
|
@@ -5903,40 +5562,49 @@ var biomarkerRangeDefinitions = {
|
|
|
5903
5562
|
},
|
|
5904
5563
|
Magnesium: {
|
|
5905
5564
|
default: { max: 2.2, min: 1.7, optimalMax: 2.1, optimalMin: 1.9, unit: "mg/dL" },
|
|
5565
|
+
kind: "reference-interval",
|
|
5906
5566
|
source: "tietz-7ed-2015"
|
|
5907
5567
|
},
|
|
5908
5568
|
Magnesium_RBC: {
|
|
5909
5569
|
default: { max: 6.8, min: 4, optimalMax: 6, optimalMin: 4.5, unit: "mg/dL" },
|
|
5570
|
+
kind: "reference-interval",
|
|
5910
5571
|
source: "tietz-7ed-2015"
|
|
5911
5572
|
},
|
|
5912
5573
|
MCH: {
|
|
5913
5574
|
default: { max: 33, min: 27, optimalMax: 32, optimalMin: 28, unit: "pg" },
|
|
5575
|
+
kind: "reference-interval",
|
|
5914
5576
|
source: "pns-hemograma-2019"
|
|
5915
5577
|
},
|
|
5916
5578
|
MCHC: {
|
|
5917
5579
|
default: { max: 36, min: 32, optimalMax: 35, optimalMin: 33, unit: "g/dL" },
|
|
5580
|
+
kind: "reference-interval",
|
|
5918
5581
|
source: "pns-hemograma-2019"
|
|
5919
5582
|
},
|
|
5920
5583
|
MCV: {
|
|
5921
5584
|
default: { max: 100, min: 80, optimalMax: 98, optimalMin: 82, unit: "fL" },
|
|
5585
|
+
kind: "reference-interval",
|
|
5922
5586
|
source: "pns-hemograma-2019"
|
|
5923
5587
|
},
|
|
5924
5588
|
Mercury: {
|
|
5925
5589
|
default: { max: 10, min: 0, optimalMax: 5, optimalMin: 0, unit: "mcg/L" },
|
|
5590
|
+
kind: "decision-threshold",
|
|
5926
5591
|
source: "nr7-pcmso-2020"
|
|
5927
5592
|
},
|
|
5928
5593
|
Microalbumin: {
|
|
5929
5594
|
default: { max: 30, min: 0, optimalMax: 20, optimalMin: 0, unit: "mg/L" },
|
|
5595
|
+
kind: "decision-threshold",
|
|
5930
5596
|
source: "kdigo-ckd-2024"
|
|
5931
5597
|
},
|
|
5932
5598
|
MMA: {
|
|
5933
5599
|
default: { max: 378, min: 0, optimalMax: 270, optimalMin: 0, unit: "nmol/L" },
|
|
5600
|
+
kind: "reference-interval",
|
|
5934
5601
|
source: "tietz-7ed-2015"
|
|
5935
5602
|
},
|
|
5936
5603
|
// `Monocytes` (%) fica sem faixa de propósito e `Monocytes_Abs` usa os limites da
|
|
5937
5604
|
// Tabela 2 da PNS 2019. Ver o comentário em `Neutrophils_Abs`.
|
|
5938
5605
|
Monocytes_Abs: {
|
|
5939
5606
|
default: { max: 0.812, min: 0.011, unit: "K/uL" },
|
|
5607
|
+
kind: "reference-interval",
|
|
5940
5608
|
source: "pns-hemograma-2019",
|
|
5941
5609
|
variants: [
|
|
5942
5610
|
{ ageMin: 18, range: { max: 0.812, min: 0.011, unit: "K/uL" }, sex: "M" },
|
|
@@ -5945,11 +5613,13 @@ var biomarkerRangeDefinitions = {
|
|
|
5945
5613
|
},
|
|
5946
5614
|
MPV: {
|
|
5947
5615
|
default: { max: 11.5, min: 7.5, optimalMax: 10.5, optimalMin: 8, unit: "fL" },
|
|
5616
|
+
kind: "reference-interval",
|
|
5948
5617
|
source: "pns-hemograma-2019"
|
|
5949
5618
|
},
|
|
5950
5619
|
// MPO: Meuwese 2007 (EPIC-Norfolk) — risco CV elevado >322 pmol/L
|
|
5951
5620
|
Myeloperoxidase: {
|
|
5952
5621
|
default: { max: 470, min: 0, optimalMax: 322, optimalMin: 0, unit: "pmol/L" },
|
|
5622
|
+
kind: "decision-threshold",
|
|
5953
5623
|
source: "meuwese-mpo-2007"
|
|
5954
5624
|
},
|
|
5955
5625
|
// Leucograma diferencial em percentual (`Neutrophils`, `Lymphocytes`,
|
|
@@ -5973,6 +5643,7 @@ var biomarkerRangeDefinitions = {
|
|
|
5973
5643
|
// (menor mínimo e maior máximo entre homens e mulheres).
|
|
5974
5644
|
Neutrophils_Abs: {
|
|
5975
5645
|
default: { max: 6.474, min: 0.576, unit: "K/uL" },
|
|
5646
|
+
kind: "reference-interval",
|
|
5976
5647
|
source: "pns-hemograma-2019",
|
|
5977
5648
|
variants: [
|
|
5978
5649
|
{ ageMin: 18, range: { max: 5.971, min: 0.576, unit: "K/uL" }, sex: "M" },
|
|
@@ -5982,22 +5653,27 @@ var biomarkerRangeDefinitions = {
|
|
|
5982
5653
|
NonHDL_Cholesterol: {
|
|
5983
5654
|
default: { max: 130, min: 0, optimalMax: 100, optimalMin: 0, unit: "mg/dL" },
|
|
5984
5655
|
direction: "lower-better",
|
|
5656
|
+
kind: "decision-threshold",
|
|
5985
5657
|
source: "sbc-lipids-2025"
|
|
5986
5658
|
},
|
|
5987
5659
|
NRBC: {
|
|
5988
5660
|
default: { max: 0, min: 0, optimalMax: 0, optimalMin: 0, unit: "/100WBC" },
|
|
5661
|
+
kind: "reference-interval",
|
|
5989
5662
|
source: "tietz-7ed-2015"
|
|
5990
5663
|
},
|
|
5991
5664
|
NTproBNP: {
|
|
5992
5665
|
default: { max: 125, min: 0, optimalMax: 75, optimalMin: 0, unit: "pg/mL" },
|
|
5666
|
+
kind: "decision-threshold",
|
|
5993
5667
|
source: "sbc-ic-2018"
|
|
5994
5668
|
},
|
|
5995
5669
|
Oleic_Acid: {
|
|
5996
5670
|
default: { max: 25, min: 15, optimalMax: 22, optimalMin: 18, unit: "%" },
|
|
5671
|
+
kind: "reference-interval",
|
|
5997
5672
|
source: "tietz-7ed-2015"
|
|
5998
5673
|
},
|
|
5999
5674
|
Omega3_Index: {
|
|
6000
5675
|
default: { max: 8, min: 4, optimalMax: 8, optimalMin: 5.5, unit: "%" },
|
|
5676
|
+
kind: "decision-threshold",
|
|
6001
5677
|
source: "harris-omega3-2004"
|
|
6002
5678
|
},
|
|
6003
5679
|
// Ômega-3 Total (% de ácidos graxos eritrocitários) — Harris & von Schacky
|
|
@@ -6007,39 +5683,55 @@ var biomarkerRangeDefinitions = {
|
|
|
6007
5683
|
// a literatura e o próprio texto educacional do `platform`.
|
|
6008
5684
|
Omega3_Total: {
|
|
6009
5685
|
default: { max: 12, min: 3, optimalMax: 10, optimalMin: 8, unit: "%" },
|
|
5686
|
+
kind: "decision-threshold",
|
|
6010
5687
|
source: "harris-omega3-2004"
|
|
6011
5688
|
},
|
|
6012
5689
|
Omega6_Total: {
|
|
6013
5690
|
default: { max: 40, min: 20, optimalMax: 35, optimalMin: 25, unit: "%" },
|
|
5691
|
+
kind: "decision-threshold",
|
|
6014
5692
|
source: "simopoulos-omega-ratio-2002"
|
|
6015
5693
|
},
|
|
6016
5694
|
Omega6_Omega3_Ratio: {
|
|
6017
|
-
default: {
|
|
5695
|
+
default: {
|
|
5696
|
+
max: 10,
|
|
5697
|
+
min: 1,
|
|
5698
|
+
minKind: "display",
|
|
5699
|
+
optimalMax: 4,
|
|
5700
|
+
optimalMin: 1,
|
|
5701
|
+
unit: ""
|
|
5702
|
+
},
|
|
6018
5703
|
direction: "lower-better",
|
|
5704
|
+
kind: "decision-threshold",
|
|
6019
5705
|
source: "simopoulos-omega-ratio-2002"
|
|
6020
5706
|
},
|
|
6021
5707
|
OmegaCheck: {
|
|
6022
5708
|
default: { max: 8, min: 4, optimalMax: 8, optimalMin: 5.5, unit: "%" },
|
|
5709
|
+
kind: "decision-threshold",
|
|
6023
5710
|
source: "harris-omega3-2004"
|
|
6024
5711
|
},
|
|
6025
5712
|
Palmitic_Acid: {
|
|
6026
5713
|
default: { max: 30, min: 20, optimalMax: 27, optimalMin: 22, unit: "%" },
|
|
5714
|
+
kind: "reference-interval",
|
|
6027
5715
|
source: "tietz-7ed-2015"
|
|
6028
5716
|
},
|
|
6029
5717
|
Phosphorus: {
|
|
6030
5718
|
default: { max: 4.5, min: 2.5, optimalMax: 4, optimalMin: 3, unit: "mg/dL" },
|
|
5719
|
+
kind: "reference-interval",
|
|
6031
5720
|
source: "tietz-7ed-2015"
|
|
6032
5721
|
},
|
|
6033
5722
|
Platelets: {
|
|
6034
5723
|
default: { max: 400, min: 150, optimalMax: 350, optimalMin: 180, unit: "K/uL" },
|
|
5724
|
+
kind: "reference-interval",
|
|
6035
5725
|
source: "pns-hemograma-2019"
|
|
6036
5726
|
},
|
|
6037
5727
|
Potassium: {
|
|
6038
5728
|
default: { max: 5, min: 3.5, optimalMax: 4.6, optimalMin: 3.8, unit: "mEq/L" },
|
|
5729
|
+
kind: "reference-interval",
|
|
6039
5730
|
source: "tietz-7ed-2015"
|
|
6040
5731
|
},
|
|
6041
5732
|
Prealbumin: {
|
|
6042
5733
|
default: { max: 38, min: 18, optimalMax: 35, optimalMin: 20, unit: "mg/dL" },
|
|
5734
|
+
kind: "reference-interval",
|
|
6043
5735
|
source: "tietz-7ed-2015"
|
|
6044
5736
|
},
|
|
6045
5737
|
// Progesterona — varia drasticamente com a fase do ciclo menstrual.
|
|
@@ -6050,6 +5742,7 @@ var biomarkerRangeDefinitions = {
|
|
|
6050
5742
|
// ciclo, indisponível neste contexto.
|
|
6051
5743
|
Progesterone: {
|
|
6052
5744
|
default: { max: 0.9, min: 0.1, optimalMax: 0.7, optimalMin: 0.2, unit: "ng/mL" },
|
|
5745
|
+
kind: "reference-interval",
|
|
6053
5746
|
source: "tietz-7ed-2015",
|
|
6054
5747
|
variants: [
|
|
6055
5748
|
{
|
|
@@ -6076,6 +5769,7 @@ var biomarkerRangeDefinitions = {
|
|
|
6076
5769
|
},
|
|
6077
5770
|
Prolactin: {
|
|
6078
5771
|
default: { max: 18, min: 2, optimalMax: 15, optimalMin: 4, unit: "ng/mL" },
|
|
5772
|
+
kind: "reference-interval",
|
|
6079
5773
|
source: "tietz-7ed-2015",
|
|
6080
5774
|
variants: [
|
|
6081
5775
|
{
|
|
@@ -6092,6 +5786,7 @@ var biomarkerRangeDefinitions = {
|
|
|
6092
5786
|
},
|
|
6093
5787
|
PSA: {
|
|
6094
5788
|
default: { max: 4, min: 0, optimalMax: 2.5, optimalMin: 0, unit: "ng/mL" },
|
|
5789
|
+
kind: "reference-interval",
|
|
6095
5790
|
source: "sturgeon-nacb-2008",
|
|
6096
5791
|
variants: [
|
|
6097
5792
|
{
|
|
@@ -6121,6 +5816,7 @@ var biomarkerRangeDefinitions = {
|
|
|
6121
5816
|
},
|
|
6122
5817
|
RBC: {
|
|
6123
5818
|
default: { max: 5.5, min: 4, optimalMax: 5.2, optimalMin: 4.3, unit: "M/uL" },
|
|
5819
|
+
kind: "reference-interval",
|
|
6124
5820
|
source: "pns-hemograma-2019",
|
|
6125
5821
|
variants: [
|
|
6126
5822
|
{
|
|
@@ -6137,22 +5833,27 @@ var biomarkerRangeDefinitions = {
|
|
|
6137
5833
|
},
|
|
6138
5834
|
RDW: {
|
|
6139
5835
|
default: { max: 14.5, min: 11.5, optimalMax: 14, optimalMin: 12, unit: "%" },
|
|
5836
|
+
kind: "reference-interval",
|
|
6140
5837
|
source: "pns-hemograma-2019"
|
|
6141
5838
|
},
|
|
6142
5839
|
Reticulocytes: {
|
|
6143
5840
|
default: { max: 2.5, min: 0.5, optimalMax: 2, optimalMin: 0.8, unit: "%" },
|
|
5841
|
+
kind: "reference-interval",
|
|
6144
5842
|
source: "pns-hemograma-2019"
|
|
6145
5843
|
},
|
|
6146
5844
|
SDMA: {
|
|
6147
5845
|
default: { max: 0.6, min: 0.3, optimalMax: 0.5, optimalMin: 0.3, unit: "umol/L" },
|
|
5846
|
+
kind: "reference-interval",
|
|
6148
5847
|
source: "schwedhelm-sdma-2011"
|
|
6149
5848
|
},
|
|
6150
5849
|
Selenium: {
|
|
6151
5850
|
default: { max: 150, min: 70, optimalMax: 125, optimalMin: 85, unit: "\xB5g/L" },
|
|
5851
|
+
kind: "reference-interval",
|
|
6152
5852
|
source: "tietz-7ed-2015"
|
|
6153
5853
|
},
|
|
6154
5854
|
SHBG: {
|
|
6155
5855
|
default: { max: 54, min: 18, optimalMax: 50, optimalMin: 20, unit: "nmol/L" },
|
|
5856
|
+
kind: "reference-interval",
|
|
6156
5857
|
source: "tietz-7ed-2015",
|
|
6157
5858
|
variants: [
|
|
6158
5859
|
{
|
|
@@ -6169,34 +5870,42 @@ var biomarkerRangeDefinitions = {
|
|
|
6169
5870
|
},
|
|
6170
5871
|
Sodium: {
|
|
6171
5872
|
default: { max: 145, min: 136, optimalMax: 143, optimalMin: 138, unit: "mEq/L" },
|
|
5873
|
+
kind: "reference-interval",
|
|
6172
5874
|
source: "tietz-7ed-2015"
|
|
6173
5875
|
},
|
|
6174
5876
|
SpecificGravity_Urine: {
|
|
6175
5877
|
default: { max: 1.03, min: 1.005, optimalMax: 1.025, optimalMin: 1.01, unit: "SG" },
|
|
5878
|
+
kind: "reference-interval",
|
|
6176
5879
|
source: "tietz-7ed-2015"
|
|
6177
5880
|
},
|
|
6178
5881
|
Stearic_Acid: {
|
|
6179
5882
|
default: { max: 14, min: 8, optimalMax: 12, optimalMin: 10, unit: "%" },
|
|
5883
|
+
kind: "reference-interval",
|
|
6180
5884
|
source: "tietz-7ed-2015"
|
|
6181
5885
|
},
|
|
6182
5886
|
T3Free: {
|
|
6183
5887
|
default: { max: 4.2, min: 2.3, optimalMax: 3.8, optimalMin: 2.8, unit: "pg/mL" },
|
|
5888
|
+
kind: "reference-interval",
|
|
6184
5889
|
source: "tietz-7ed-2015"
|
|
6185
5890
|
},
|
|
6186
5891
|
T3Reverse: {
|
|
6187
5892
|
default: { max: 24, min: 10, optimalMax: 20, optimalMin: 12, unit: "ng/dL" },
|
|
5893
|
+
kind: "reference-interval",
|
|
6188
5894
|
source: "tietz-7ed-2015"
|
|
6189
5895
|
},
|
|
6190
5896
|
T4Free: {
|
|
6191
5897
|
default: { max: 1.8, min: 0.8, optimalMax: 1.5, optimalMin: 1, unit: "ng/dL" },
|
|
5898
|
+
kind: "reference-interval",
|
|
6192
5899
|
source: "tietz-7ed-2015"
|
|
6193
5900
|
},
|
|
6194
5901
|
T4Total: {
|
|
6195
5902
|
default: { max: 12, min: 4.5, optimalMax: 10, optimalMin: 6, unit: "ug/dL" },
|
|
5903
|
+
kind: "reference-interval",
|
|
6196
5904
|
source: "tietz-7ed-2015"
|
|
6197
5905
|
},
|
|
6198
5906
|
Testosterone: {
|
|
6199
5907
|
default: { max: 1e3, min: 300, optimalMax: 800, optimalMin: 500, unit: "ng/dL" },
|
|
5908
|
+
kind: "reference-interval",
|
|
6200
5909
|
source: "tietz-7ed-2015",
|
|
6201
5910
|
variants: [
|
|
6202
5911
|
{
|
|
@@ -6219,12 +5928,14 @@ var biomarkerRangeDefinitions = {
|
|
|
6219
5928
|
},
|
|
6220
5929
|
TestosteroneBioavailable: {
|
|
6221
5930
|
default: { max: 200, min: 50, optimalMax: 150, optimalMin: 80, unit: "ng/dL" },
|
|
5931
|
+
kind: "reference-interval",
|
|
6222
5932
|
source: "tietz-7ed-2015"
|
|
6223
5933
|
},
|
|
6224
5934
|
// TestosteroneFree - using direct immunoassay ranges (Quest/LabCorp standard)
|
|
6225
5935
|
// Previous values (9.3-26.5 pg/mL) were based on equilibrium dialysis method
|
|
6226
5936
|
TestosteroneFree: {
|
|
6227
5937
|
default: { max: 155, min: 35, optimalMax: 120, optimalMin: 50, unit: "pg/mL" },
|
|
5938
|
+
kind: "reference-interval",
|
|
6228
5939
|
source: "tietz-7ed-2015",
|
|
6229
5940
|
variants: [
|
|
6230
5941
|
{
|
|
@@ -6247,22 +5958,27 @@ var biomarkerRangeDefinitions = {
|
|
|
6247
5958
|
},
|
|
6248
5959
|
TIBC: {
|
|
6249
5960
|
default: { max: 370, min: 250, optimalMax: 350, optimalMin: 280, unit: "mcg/dL" },
|
|
5961
|
+
kind: "reference-interval",
|
|
6250
5962
|
source: "tietz-7ed-2015"
|
|
6251
5963
|
},
|
|
6252
5964
|
TotalProtein: {
|
|
6253
5965
|
default: { max: 8.3, min: 6, optimalMax: 7.8, optimalMin: 6.5, unit: "g/dL" },
|
|
5966
|
+
kind: "reference-interval",
|
|
6254
5967
|
source: "tietz-7ed-2015"
|
|
6255
5968
|
},
|
|
6256
5969
|
Trans_Fat_Index: {
|
|
6257
5970
|
default: { max: 1, min: 0, optimalMax: 0.5, optimalMin: 0, unit: "%" },
|
|
5971
|
+
kind: "reference-interval",
|
|
6258
5972
|
source: "tietz-7ed-2015"
|
|
6259
5973
|
},
|
|
6260
5974
|
Transferrin: {
|
|
6261
5975
|
default: { max: 360, min: 200, optimalMax: 340, optimalMin: 220, unit: "mg/dL" },
|
|
5976
|
+
kind: "reference-interval",
|
|
6262
5977
|
source: "tietz-7ed-2015"
|
|
6263
5978
|
},
|
|
6264
5979
|
TransferrinSaturation: {
|
|
6265
5980
|
default: { max: 50, min: 20, optimalMax: 45, optimalMin: 25, unit: "%" },
|
|
5981
|
+
kind: "reference-interval",
|
|
6266
5982
|
source: "tietz-7ed-2015",
|
|
6267
5983
|
variants: [
|
|
6268
5984
|
{
|
|
@@ -6290,16 +6006,19 @@ var biomarkerRangeDefinitions = {
|
|
|
6290
6006
|
unit: "mg/dL"
|
|
6291
6007
|
},
|
|
6292
6008
|
direction: "lower-better",
|
|
6009
|
+
kind: "decision-threshold",
|
|
6293
6010
|
source: "sbc-lipids-2025"
|
|
6294
6011
|
},
|
|
6295
6012
|
// TroponinI: 0.04 ng/mL = percentil 99 (ensaio Siemens TnI-Ultra)
|
|
6296
6013
|
TroponinI: {
|
|
6297
6014
|
default: { max: 0.04, min: 0, optimalMax: 0.02, optimalMin: 0, unit: "ng/mL" },
|
|
6015
|
+
kind: "reference-interval",
|
|
6298
6016
|
source: "keller-tni-2013"
|
|
6299
6017
|
},
|
|
6300
6018
|
// TroponinT: 14 ng/L = percentil 99 hs-cTnT (ensaio Roche Elecsys 5ª geração)
|
|
6301
6019
|
TroponinT: {
|
|
6302
6020
|
default: { max: 14, min: 0, optimalMax: 10, optimalMin: 0, unit: "ng/L" },
|
|
6021
|
+
kind: "reference-interval",
|
|
6303
6022
|
source: "giannitsis-hstnt-2010"
|
|
6304
6023
|
},
|
|
6305
6024
|
// TSH — 0.4–4.0 é a faixa de referência adulta geral. O alvo 2.5 µIU/mL é
|
|
@@ -6309,6 +6028,7 @@ var biomarkerRangeDefinitions = {
|
|
|
6309
6028
|
// expandido (tolerância fisiológica do eixo em idosos, SBEM 2013).
|
|
6310
6029
|
TSH: {
|
|
6311
6030
|
default: { max: 4, min: 0.4, optimalMax: 3, optimalMin: 1, unit: "uIU/mL" },
|
|
6031
|
+
kind: "reference-interval",
|
|
6312
6032
|
source: "sbem-thyroid-2013",
|
|
6313
6033
|
variants: [
|
|
6314
6034
|
// Variantes gestacionais (ATA 2017 / SBEM): supressão fisiológica por hCG
|
|
@@ -6357,10 +6077,12 @@ var biomarkerRangeDefinitions = {
|
|
|
6357
6077
|
// deve ser revisto em biomarkers.ts — ver issue #41.
|
|
6358
6078
|
Urea: {
|
|
6359
6079
|
default: { max: 50, min: 15, optimalMax: 40, optimalMin: 20, unit: "mg/dL" },
|
|
6080
|
+
kind: "reference-interval",
|
|
6360
6081
|
source: "tietz-7ed-2015"
|
|
6361
6082
|
},
|
|
6362
6083
|
UricAcid: {
|
|
6363
6084
|
default: { max: 7, min: 2.5, optimalMax: 5.5, optimalMin: 3, unit: "mg/dL" },
|
|
6085
|
+
kind: "reference-interval",
|
|
6364
6086
|
source: "tietz-7ed-2015",
|
|
6365
6087
|
variants: [
|
|
6366
6088
|
{
|
|
@@ -6377,50 +6099,62 @@ var biomarkerRangeDefinitions = {
|
|
|
6377
6099
|
},
|
|
6378
6100
|
Urobilinogen_Urine: {
|
|
6379
6101
|
default: { max: 1, min: 0.1, optimalMax: 1, optimalMin: 0.1, unit: "mg/dL" },
|
|
6102
|
+
kind: "reference-interval",
|
|
6380
6103
|
source: "tietz-7ed-2015"
|
|
6381
6104
|
},
|
|
6382
6105
|
pH_Urine: {
|
|
6383
6106
|
default: { max: 8, min: 4.5, optimalMax: 7, optimalMin: 5.5, unit: "pH" },
|
|
6107
|
+
kind: "reference-interval",
|
|
6384
6108
|
source: "tietz-7ed-2015"
|
|
6385
6109
|
},
|
|
6386
6110
|
HyalineCasts_Urine: {
|
|
6387
6111
|
default: { max: 2, min: 0, optimalMax: 1, optimalMin: 0, unit: "/LPF" },
|
|
6112
|
+
kind: "reference-interval",
|
|
6388
6113
|
source: "tietz-7ed-2015"
|
|
6389
6114
|
},
|
|
6390
6115
|
RBC_Urine: {
|
|
6391
6116
|
default: { max: 3, min: 0, optimalMax: 1, optimalMin: 0, unit: "/HPF" },
|
|
6117
|
+
kind: "reference-interval",
|
|
6392
6118
|
source: "tietz-7ed-2015"
|
|
6393
6119
|
},
|
|
6394
6120
|
SquamousEpithelial_Urine: {
|
|
6395
6121
|
default: { max: 15, min: 0, optimalMax: 5, optimalMin: 0, unit: "/HPF" },
|
|
6122
|
+
kind: "reference-interval",
|
|
6396
6123
|
source: "tietz-7ed-2015"
|
|
6397
6124
|
},
|
|
6398
6125
|
Leukocytes_Urine: {
|
|
6399
6126
|
default: { max: 5, min: 0, optimalMax: 2, optimalMin: 0, unit: "/HPF" },
|
|
6127
|
+
kind: "reference-interval",
|
|
6400
6128
|
source: "tietz-7ed-2015"
|
|
6401
6129
|
},
|
|
6402
6130
|
Folate: {
|
|
6403
6131
|
default: { max: 20, min: 3.9, optimalMax: 17, optimalMin: 5, unit: "ng/mL" },
|
|
6132
|
+
kind: "reference-interval",
|
|
6404
6133
|
source: "tietz-7ed-2015"
|
|
6405
6134
|
},
|
|
6406
6135
|
VitaminA: {
|
|
6407
6136
|
default: { max: 100, min: 20, optimalMax: 80, optimalMin: 30, unit: "mcg/dL" },
|
|
6137
|
+
kind: "reference-interval",
|
|
6408
6138
|
source: "tietz-7ed-2015"
|
|
6409
6139
|
},
|
|
6410
6140
|
VitaminB1: {
|
|
6411
6141
|
default: { max: 180, min: 70, optimalMax: 150, optimalMin: 80, unit: "nmol/L" },
|
|
6142
|
+
kind: "reference-interval",
|
|
6412
6143
|
source: "tietz-7ed-2015"
|
|
6413
6144
|
},
|
|
6414
6145
|
VitaminB12: {
|
|
6415
6146
|
default: { max: 900, min: 200, optimalMax: 800, optimalMin: 400, unit: "pg/mL" },
|
|
6147
|
+
kind: "reference-interval",
|
|
6416
6148
|
source: "tietz-7ed-2015"
|
|
6417
6149
|
},
|
|
6418
6150
|
VitaminB6: {
|
|
6419
6151
|
default: { max: 50, min: 5, optimalMax: 40, optimalMin: 10, unit: "ng/mL" },
|
|
6152
|
+
kind: "reference-interval",
|
|
6420
6153
|
source: "tietz-7ed-2015"
|
|
6421
6154
|
},
|
|
6422
6155
|
VitaminC: {
|
|
6423
6156
|
default: { max: 2, min: 0.4, optimalMax: 1.5, optimalMin: 0.6, unit: "mg/dL" },
|
|
6157
|
+
kind: "reference-interval",
|
|
6424
6158
|
source: "tietz-7ed-2015"
|
|
6425
6159
|
},
|
|
6426
6160
|
// Vitamina D — posicionamento conjunto SBEM/SBPC-ML 2017:
|
|
@@ -6437,6 +6171,7 @@ var biomarkerRangeDefinitions = {
|
|
|
6437
6171
|
// quando a modelagem de comorbidades chegar ao schema.
|
|
6438
6172
|
VitaminD: {
|
|
6439
6173
|
default: { max: 100, min: 20, optimalMax: 70, optimalMin: 40, unit: "ng/mL" },
|
|
6174
|
+
kind: "decision-threshold",
|
|
6440
6175
|
source: "ferreira-vitd-2017",
|
|
6441
6176
|
variants: [
|
|
6442
6177
|
{
|
|
@@ -6448,10 +6183,12 @@ var biomarkerRangeDefinitions = {
|
|
|
6448
6183
|
},
|
|
6449
6184
|
VitaminD_1_25: {
|
|
6450
6185
|
default: { max: 72, min: 18, optimalMax: 60, optimalMin: 25, unit: "pg/mL" },
|
|
6186
|
+
kind: "reference-interval",
|
|
6451
6187
|
source: "tietz-7ed-2015"
|
|
6452
6188
|
},
|
|
6453
6189
|
VitaminE: {
|
|
6454
6190
|
default: { max: 17, min: 5.5, optimalMax: 14, optimalMin: 7, unit: "mg/L" },
|
|
6191
|
+
kind: "reference-interval",
|
|
6455
6192
|
source: "tietz-7ed-2015"
|
|
6456
6193
|
},
|
|
6457
6194
|
// VLDL — estimado clinicamente via TG/5 (método Friedewald). O corte de
|
|
@@ -6460,30 +6197,34 @@ var biomarkerRangeDefinitions = {
|
|
|
6460
6197
|
// método de cálculo, mas a faixa de referência tem respaldo na diretriz
|
|
6461
6198
|
// SBC 2025.
|
|
6462
6199
|
VLDL: {
|
|
6463
|
-
default: { max: 30, min: 2, optimalMax: 20, optimalMin: 5, unit: "mg/dL" },
|
|
6200
|
+
default: { max: 30, min: 2, minKind: "display", optimalMax: 20, optimalMin: 5, unit: "mg/dL" },
|
|
6201
|
+
kind: "decision-threshold",
|
|
6464
6202
|
source: "sbc-lipids-2025"
|
|
6465
6203
|
},
|
|
6466
6204
|
WBC: {
|
|
6467
6205
|
default: { max: 11, min: 4, optimalMax: 8, optimalMin: 5, unit: "K/uL" },
|
|
6206
|
+
kind: "reference-interval",
|
|
6468
6207
|
source: "pns-hemograma-2019"
|
|
6469
6208
|
},
|
|
6470
6209
|
Zinc: {
|
|
6471
6210
|
default: { max: 120, min: 60, optimalMax: 100, optimalMin: 70, unit: "mcg/dL" },
|
|
6211
|
+
kind: "reference-interval",
|
|
6472
6212
|
source: "tietz-7ed-2015"
|
|
6473
6213
|
},
|
|
6474
6214
|
AndroidFatPct: {
|
|
6475
|
-
default: { max: 35, min: 10, optimalMax: 25, optimalMin: 15, unit: "%" },
|
|
6215
|
+
default: { max: 35, min: 10, minKind: "display", optimalMax: 25, optimalMin: 15, unit: "%" },
|
|
6476
6216
|
direction: "lower-better",
|
|
6217
|
+
kind: "population",
|
|
6477
6218
|
source: "kelly-dxa-2009",
|
|
6478
6219
|
variants: [
|
|
6479
6220
|
{
|
|
6480
6221
|
ageMin: 18,
|
|
6481
|
-
range: { max: 30, min: 10, optimalMax: 22, optimalMin: 12, unit: "%" },
|
|
6222
|
+
range: { max: 30, min: 10, minKind: "display", optimalMax: 22, optimalMin: 12, unit: "%" },
|
|
6482
6223
|
sex: "M"
|
|
6483
6224
|
},
|
|
6484
6225
|
{
|
|
6485
6226
|
ageMin: 18,
|
|
6486
|
-
range: { max: 42, min: 15, optimalMax: 32, optimalMin: 20, unit: "%" },
|
|
6227
|
+
range: { max: 42, min: 15, minKind: "display", optimalMax: 32, optimalMin: 20, unit: "%" },
|
|
6487
6228
|
sex: "F"
|
|
6488
6229
|
}
|
|
6489
6230
|
]
|
|
@@ -6534,6 +6275,7 @@ var biomarkerRangeDefinitions = {
|
|
|
6534
6275
|
CalfCircumference: {
|
|
6535
6276
|
default: { unit: "cm" },
|
|
6536
6277
|
direction: "higher-better",
|
|
6278
|
+
kind: "decision-threshold",
|
|
6537
6279
|
source: "ewgsop2-2019",
|
|
6538
6280
|
// O corte não é específico por sexo na fonte; as duas variantes existem
|
|
6539
6281
|
// porque `RangeVariant` exige o campo, e carregam o mesmo número.
|
|
@@ -6545,38 +6287,76 @@ var biomarkerRangeDefinitions = {
|
|
|
6545
6287
|
WaistToHeightRatio: {
|
|
6546
6288
|
default: { max: 0.5, unit: "" },
|
|
6547
6289
|
direction: "lower-better",
|
|
6290
|
+
kind: "decision-threshold",
|
|
6548
6291
|
source: "browning-ashwell-2010"
|
|
6549
6292
|
},
|
|
6550
6293
|
AndroidGynoidRatio: {
|
|
6551
|
-
default: { max: 1.2, min: 0.5, optimalMax: 1, optimalMin: 0.6, unit: "" },
|
|
6294
|
+
default: { max: 1.2, min: 0.5, minKind: "display", optimalMax: 1, optimalMin: 0.6, unit: "" },
|
|
6552
6295
|
direction: "lower-better",
|
|
6296
|
+
kind: "population",
|
|
6553
6297
|
source: "kelly-dxa-2009",
|
|
6554
6298
|
variants: [
|
|
6555
6299
|
{
|
|
6556
6300
|
ageMin: 18,
|
|
6557
|
-
range: {
|
|
6301
|
+
range: {
|
|
6302
|
+
max: 1.2,
|
|
6303
|
+
min: 0.6,
|
|
6304
|
+
minKind: "display",
|
|
6305
|
+
optimalMax: 1,
|
|
6306
|
+
optimalMin: 0.7,
|
|
6307
|
+
unit: ""
|
|
6308
|
+
},
|
|
6558
6309
|
sex: "M"
|
|
6559
6310
|
},
|
|
6560
6311
|
{
|
|
6561
6312
|
ageMin: 18,
|
|
6562
|
-
range: {
|
|
6313
|
+
range: {
|
|
6314
|
+
max: 1,
|
|
6315
|
+
min: 0.4,
|
|
6316
|
+
minKind: "display",
|
|
6317
|
+
optimalMax: 0.8,
|
|
6318
|
+
optimalMin: 0.5,
|
|
6319
|
+
unit: ""
|
|
6320
|
+
},
|
|
6563
6321
|
sex: "F"
|
|
6564
6322
|
}
|
|
6565
6323
|
]
|
|
6566
6324
|
},
|
|
6567
6325
|
BMC: {
|
|
6568
|
-
default: {
|
|
6326
|
+
default: {
|
|
6327
|
+
max: 3.5,
|
|
6328
|
+
maxKind: "display",
|
|
6329
|
+
min: 2,
|
|
6330
|
+
optimalMax: 3.2,
|
|
6331
|
+
optimalMin: 2.3,
|
|
6332
|
+
unit: "kg"
|
|
6333
|
+
},
|
|
6569
6334
|
direction: "higher-better",
|
|
6335
|
+
kind: "population",
|
|
6570
6336
|
source: "kelly-dxa-2009",
|
|
6571
6337
|
variants: [
|
|
6572
6338
|
{
|
|
6573
6339
|
ageMin: 18,
|
|
6574
|
-
range: {
|
|
6340
|
+
range: {
|
|
6341
|
+
max: 4,
|
|
6342
|
+
maxKind: "display",
|
|
6343
|
+
min: 2.5,
|
|
6344
|
+
optimalMax: 3.5,
|
|
6345
|
+
optimalMin: 2.8,
|
|
6346
|
+
unit: "kg"
|
|
6347
|
+
},
|
|
6575
6348
|
sex: "M"
|
|
6576
6349
|
},
|
|
6577
6350
|
{
|
|
6578
6351
|
ageMin: 18,
|
|
6579
|
-
range: {
|
|
6352
|
+
range: {
|
|
6353
|
+
max: 3,
|
|
6354
|
+
maxKind: "display",
|
|
6355
|
+
min: 1.8,
|
|
6356
|
+
optimalMax: 2.7,
|
|
6357
|
+
optimalMin: 2,
|
|
6358
|
+
unit: "kg"
|
|
6359
|
+
},
|
|
6580
6360
|
sex: "F"
|
|
6581
6361
|
}
|
|
6582
6362
|
]
|
|
@@ -6584,142 +6364,148 @@ var biomarkerRangeDefinitions = {
|
|
|
6584
6364
|
// BodyFatPct — Age-bracketed ranges from Gallagher et al. Am J Clin Nutr 2000;72:694-701
|
|
6585
6365
|
// (PMID: 10966886) and ACSM Guidelines for Exercise Testing, 11th Ed (2021)
|
|
6586
6366
|
BodyFatPct: {
|
|
6587
|
-
default: { max: 30, min: 10, optimalMax: 25, optimalMin: 15, unit: "%" },
|
|
6367
|
+
default: { max: 30, min: 10, minKind: "clinical", optimalMax: 25, optimalMin: 15, unit: "%" },
|
|
6588
6368
|
direction: "lower-better",
|
|
6369
|
+
kind: "decision-threshold",
|
|
6589
6370
|
source: "gallagher-bodyfat-2000",
|
|
6590
6371
|
variants: [
|
|
6591
6372
|
// Men — age brackets
|
|
6592
6373
|
{
|
|
6593
6374
|
ageMax: 25,
|
|
6594
6375
|
ageMin: 18,
|
|
6595
|
-
range: { max: 25, min: 5, optimalMax: 20, optimalMin: 10, unit: "%" },
|
|
6376
|
+
range: { max: 25, min: 5, minKind: "clinical", optimalMax: 20, optimalMin: 10, unit: "%" },
|
|
6596
6377
|
sex: "M"
|
|
6597
6378
|
},
|
|
6598
6379
|
{
|
|
6599
6380
|
ageMax: 35,
|
|
6600
6381
|
ageMin: 26,
|
|
6601
|
-
range: { max: 26, min: 5, optimalMax: 21, optimalMin: 11, unit: "%" },
|
|
6382
|
+
range: { max: 26, min: 5, minKind: "clinical", optimalMax: 21, optimalMin: 11, unit: "%" },
|
|
6602
6383
|
sex: "M"
|
|
6603
6384
|
},
|
|
6604
6385
|
{
|
|
6605
6386
|
ageMax: 45,
|
|
6606
6387
|
ageMin: 36,
|
|
6607
|
-
range: { max: 27, min: 5, optimalMax: 22, optimalMin: 12, unit: "%" },
|
|
6388
|
+
range: { max: 27, min: 5, minKind: "clinical", optimalMax: 22, optimalMin: 12, unit: "%" },
|
|
6608
6389
|
sex: "M"
|
|
6609
6390
|
},
|
|
6610
6391
|
{
|
|
6611
6392
|
ageMax: 55,
|
|
6612
6393
|
ageMin: 46,
|
|
6613
|
-
range: { max: 28, min: 5, optimalMax: 23, optimalMin: 13, unit: "%" },
|
|
6394
|
+
range: { max: 28, min: 5, minKind: "clinical", optimalMax: 23, optimalMin: 13, unit: "%" },
|
|
6614
6395
|
sex: "M"
|
|
6615
6396
|
},
|
|
6616
6397
|
{
|
|
6617
6398
|
ageMin: 56,
|
|
6618
|
-
range: { max: 29, min: 5, optimalMax: 24, optimalMin: 14, unit: "%" },
|
|
6399
|
+
range: { max: 29, min: 5, minKind: "clinical", optimalMax: 24, optimalMin: 14, unit: "%" },
|
|
6619
6400
|
sex: "M"
|
|
6620
6401
|
},
|
|
6621
6402
|
// Women — age brackets
|
|
6622
6403
|
{
|
|
6623
6404
|
ageMax: 25,
|
|
6624
6405
|
ageMin: 18,
|
|
6625
|
-
range: { max: 32, min: 13, optimalMax: 28, optimalMin: 18, unit: "%" },
|
|
6406
|
+
range: { max: 32, min: 13, minKind: "clinical", optimalMax: 28, optimalMin: 18, unit: "%" },
|
|
6626
6407
|
sex: "F"
|
|
6627
6408
|
},
|
|
6628
6409
|
{
|
|
6629
6410
|
ageMax: 35,
|
|
6630
6411
|
ageMin: 26,
|
|
6631
|
-
range: { max: 33, min: 13, optimalMax: 29, optimalMin: 18, unit: "%" },
|
|
6412
|
+
range: { max: 33, min: 13, minKind: "clinical", optimalMax: 29, optimalMin: 18, unit: "%" },
|
|
6632
6413
|
sex: "F"
|
|
6633
6414
|
},
|
|
6634
6415
|
{
|
|
6635
6416
|
ageMax: 45,
|
|
6636
6417
|
ageMin: 36,
|
|
6637
|
-
range: { max: 34, min: 13, optimalMax: 30, optimalMin: 19, unit: "%" },
|
|
6418
|
+
range: { max: 34, min: 13, minKind: "clinical", optimalMax: 30, optimalMin: 19, unit: "%" },
|
|
6638
6419
|
sex: "F"
|
|
6639
6420
|
},
|
|
6640
6421
|
{
|
|
6641
6422
|
ageMax: 55,
|
|
6642
6423
|
ageMin: 46,
|
|
6643
|
-
range: { max: 35, min: 13, optimalMax: 31, optimalMin: 20, unit: "%" },
|
|
6424
|
+
range: { max: 35, min: 13, minKind: "clinical", optimalMax: 31, optimalMin: 20, unit: "%" },
|
|
6644
6425
|
sex: "F"
|
|
6645
6426
|
},
|
|
6646
6427
|
{
|
|
6647
6428
|
ageMin: 56,
|
|
6648
|
-
range: { max: 36, min: 13, optimalMax: 32, optimalMin: 20, unit: "%" },
|
|
6429
|
+
range: { max: 36, min: 13, minKind: "clinical", optimalMax: 32, optimalMin: 20, unit: "%" },
|
|
6649
6430
|
sex: "F"
|
|
6650
6431
|
}
|
|
6651
6432
|
]
|
|
6652
6433
|
},
|
|
6653
6434
|
FatFreeMass: {
|
|
6654
|
-
default: { max: 80, min: 40, optimalMax: 70, optimalMin: 45, unit: "kg" },
|
|
6435
|
+
default: { max: 80, maxKind: "display", min: 40, optimalMax: 70, optimalMin: 45, unit: "kg" },
|
|
6655
6436
|
direction: "higher-better",
|
|
6437
|
+
kind: "population",
|
|
6656
6438
|
source: "kelly-dxa-2009",
|
|
6657
6439
|
variants: [
|
|
6658
6440
|
{
|
|
6659
6441
|
ageMin: 18,
|
|
6660
|
-
range: { max: 90, min: 50, optimalMax: 80, optimalMin: 55, unit: "kg" },
|
|
6442
|
+
range: { max: 90, maxKind: "display", min: 50, optimalMax: 80, optimalMin: 55, unit: "kg" },
|
|
6661
6443
|
sex: "M"
|
|
6662
6444
|
},
|
|
6663
6445
|
{
|
|
6664
6446
|
ageMin: 18,
|
|
6665
|
-
range: { max: 60, min: 35, optimalMax: 52, optimalMin: 38, unit: "kg" },
|
|
6447
|
+
range: { max: 60, maxKind: "display", min: 35, optimalMax: 52, optimalMin: 38, unit: "kg" },
|
|
6666
6448
|
sex: "F"
|
|
6667
6449
|
}
|
|
6668
6450
|
]
|
|
6669
6451
|
},
|
|
6670
6452
|
FatMass: {
|
|
6671
|
-
default: { max: 30, min: 5, optimalMax: 20, optimalMin: 8, unit: "kg" },
|
|
6453
|
+
default: { max: 30, min: 5, minKind: "clinical", optimalMax: 20, optimalMin: 8, unit: "kg" },
|
|
6672
6454
|
direction: "lower-better",
|
|
6455
|
+
kind: "population",
|
|
6673
6456
|
source: "kelly-dxa-2009",
|
|
6674
6457
|
variants: [
|
|
6675
6458
|
{
|
|
6676
6459
|
ageMin: 18,
|
|
6677
|
-
range: { max: 25, min: 5, optimalMax: 18, optimalMin: 7, unit: "kg" },
|
|
6460
|
+
range: { max: 25, min: 5, minKind: "clinical", optimalMax: 18, optimalMin: 7, unit: "kg" },
|
|
6678
6461
|
sex: "M"
|
|
6679
6462
|
},
|
|
6680
6463
|
{
|
|
6681
6464
|
ageMin: 18,
|
|
6682
|
-
range: { max: 30, min: 8, optimalMax: 22, optimalMin: 10, unit: "kg" },
|
|
6465
|
+
range: { max: 30, min: 8, minKind: "clinical", optimalMax: 22, optimalMin: 10, unit: "kg" },
|
|
6683
6466
|
sex: "F"
|
|
6684
6467
|
}
|
|
6685
6468
|
]
|
|
6686
6469
|
},
|
|
6687
6470
|
GynoidFatPct: {
|
|
6688
|
-
default: { max: 45, min: 15, optimalMax: 35, optimalMin: 20, unit: "%" },
|
|
6471
|
+
default: { max: 45, min: 15, minKind: "display", optimalMax: 35, optimalMin: 20, unit: "%" },
|
|
6689
6472
|
direction: "lower-better",
|
|
6473
|
+
kind: "population",
|
|
6690
6474
|
source: "kelly-dxa-2009",
|
|
6691
6475
|
variants: [
|
|
6692
6476
|
{
|
|
6693
6477
|
ageMin: 18,
|
|
6694
|
-
range: { max: 35, min: 12, optimalMax: 28, optimalMin: 15, unit: "%" },
|
|
6478
|
+
range: { max: 35, min: 12, minKind: "display", optimalMax: 28, optimalMin: 15, unit: "%" },
|
|
6695
6479
|
sex: "M"
|
|
6696
6480
|
},
|
|
6697
6481
|
{
|
|
6698
6482
|
ageMin: 18,
|
|
6699
|
-
range: { max: 50, min: 20, optimalMax: 40, optimalMin: 25, unit: "%" },
|
|
6483
|
+
range: { max: 50, min: 20, minKind: "display", optimalMax: 40, optimalMin: 25, unit: "%" },
|
|
6700
6484
|
sex: "F"
|
|
6701
6485
|
}
|
|
6702
6486
|
]
|
|
6703
6487
|
},
|
|
6704
6488
|
LeanMass: {
|
|
6705
|
-
default: { max: 75, min: 35, optimalMax: 65, optimalMin: 40, unit: "kg" },
|
|
6489
|
+
default: { max: 75, maxKind: "display", min: 35, optimalMax: 65, optimalMin: 40, unit: "kg" },
|
|
6706
6490
|
direction: "higher-better",
|
|
6491
|
+
kind: "population",
|
|
6707
6492
|
source: "kelly-dxa-2009",
|
|
6708
6493
|
variants: [
|
|
6709
6494
|
{
|
|
6710
6495
|
ageMin: 18,
|
|
6711
|
-
range: { max: 85, min: 45, optimalMax: 75, optimalMin: 50, unit: "kg" },
|
|
6496
|
+
range: { max: 85, maxKind: "display", min: 45, optimalMax: 75, optimalMin: 50, unit: "kg" },
|
|
6712
6497
|
sex: "M"
|
|
6713
6498
|
},
|
|
6714
6499
|
{
|
|
6715
6500
|
ageMin: 18,
|
|
6716
|
-
range: { max: 55, min: 30, optimalMax: 48, optimalMin: 35, unit: "kg" },
|
|
6501
|
+
range: { max: 55, maxKind: "display", min: 30, optimalMax: 48, optimalMin: 35, unit: "kg" },
|
|
6717
6502
|
sex: "F"
|
|
6718
6503
|
}
|
|
6719
6504
|
]
|
|
6720
6505
|
},
|
|
6721
6506
|
TotalMass: {
|
|
6722
6507
|
default: { max: 100, min: 50, optimalMax: 85, optimalMin: 55, unit: "kg" },
|
|
6508
|
+
kind: "population",
|
|
6723
6509
|
source: "kelly-dxa-2009",
|
|
6724
6510
|
variants: [
|
|
6725
6511
|
{
|
|
@@ -6734,226 +6520,858 @@ var biomarkerRangeDefinitions = {
|
|
|
6734
6520
|
}
|
|
6735
6521
|
]
|
|
6736
6522
|
},
|
|
6737
|
-
VATMass: {
|
|
6738
|
-
default: { max: 1.5, min: 0, optimalMax: 0.8, optimalMin: 0, unit: "kg" },
|
|
6739
|
-
direction: "lower-better",
|
|
6740
|
-
|
|
6523
|
+
VATMass: {
|
|
6524
|
+
default: { max: 1.5, min: 0, optimalMax: 0.8, optimalMin: 0, unit: "kg" },
|
|
6525
|
+
direction: "lower-better",
|
|
6526
|
+
kind: "population",
|
|
6527
|
+
source: "ofenheimer-vat-2020",
|
|
6528
|
+
variants: [
|
|
6529
|
+
{
|
|
6530
|
+
ageMin: 18,
|
|
6531
|
+
range: { max: 1.5, min: 0, optimalMax: 1, optimalMin: 0, unit: "kg" },
|
|
6532
|
+
sex: "M"
|
|
6533
|
+
},
|
|
6534
|
+
{
|
|
6535
|
+
ageMin: 18,
|
|
6536
|
+
range: { max: 1, min: 0, optimalMax: 0.5, optimalMin: 0, unit: "kg" },
|
|
6537
|
+
sex: "F"
|
|
6538
|
+
}
|
|
6539
|
+
]
|
|
6540
|
+
},
|
|
6541
|
+
VATVolume: {
|
|
6542
|
+
default: {
|
|
6543
|
+
max: 852,
|
|
6544
|
+
min: 0,
|
|
6545
|
+
optimalMax: 600,
|
|
6546
|
+
optimalMin: 0,
|
|
6547
|
+
unit: "cm\xB3",
|
|
6548
|
+
warningMax: 1837
|
|
6549
|
+
},
|
|
6550
|
+
direction: "lower-better",
|
|
6551
|
+
kind: "decision-threshold",
|
|
6552
|
+
source: "ge-corescan"
|
|
6553
|
+
},
|
|
6554
|
+
BMD_Total: {
|
|
6555
|
+
default: {
|
|
6556
|
+
max: 1.4,
|
|
6557
|
+
maxKind: "display",
|
|
6558
|
+
min: 0.9,
|
|
6559
|
+
optimalMax: 1.3,
|
|
6560
|
+
optimalMin: 1,
|
|
6561
|
+
unit: "g/cm\xB2"
|
|
6562
|
+
},
|
|
6563
|
+
direction: "higher-better",
|
|
6564
|
+
kind: "decision-threshold",
|
|
6565
|
+
source: "who-osteoporosis-1994"
|
|
6566
|
+
},
|
|
6567
|
+
TScore_Total: {
|
|
6568
|
+
default: {
|
|
6569
|
+
max: 4,
|
|
6570
|
+
maxKind: "display",
|
|
6571
|
+
min: -1,
|
|
6572
|
+
optimalMax: 2,
|
|
6573
|
+
optimalMin: -0.5,
|
|
6574
|
+
unit: ""
|
|
6575
|
+
},
|
|
6576
|
+
direction: "higher-better",
|
|
6577
|
+
kind: "decision-threshold",
|
|
6578
|
+
source: "who-osteoporosis-1994"
|
|
6579
|
+
},
|
|
6580
|
+
ZScore_Total: {
|
|
6581
|
+
default: {
|
|
6582
|
+
max: 2,
|
|
6583
|
+
maxKind: "display",
|
|
6584
|
+
min: -2,
|
|
6585
|
+
optimalMax: 1,
|
|
6586
|
+
optimalMin: -1,
|
|
6587
|
+
unit: ""
|
|
6588
|
+
},
|
|
6589
|
+
direction: "higher-better",
|
|
6590
|
+
kind: "decision-threshold",
|
|
6591
|
+
source: "who-osteoporosis-1994"
|
|
6592
|
+
},
|
|
6593
|
+
Amylase: {
|
|
6594
|
+
default: { max: 100, min: 28, optimalMax: 90, optimalMin: 35, unit: "U/L" },
|
|
6595
|
+
kind: "reference-interval",
|
|
6596
|
+
source: "tietz-7ed-2015"
|
|
6597
|
+
},
|
|
6598
|
+
Creatinine_Urine: {
|
|
6599
|
+
default: { max: 300, min: 20, optimalMax: 250, optimalMin: 40, unit: "mg/dL" },
|
|
6600
|
+
kind: "reference-interval",
|
|
6601
|
+
source: "tietz-7ed-2015",
|
|
6602
|
+
variants: [
|
|
6603
|
+
{
|
|
6604
|
+
ageMin: 18,
|
|
6605
|
+
range: { max: 300, min: 40, optimalMax: 260, optimalMin: 60, unit: "mg/dL" },
|
|
6606
|
+
sex: "M"
|
|
6607
|
+
},
|
|
6608
|
+
{
|
|
6609
|
+
ageMin: 18,
|
|
6610
|
+
range: { max: 220, min: 20, optimalMax: 180, optimalMin: 40, unit: "mg/dL" },
|
|
6611
|
+
sex: "F"
|
|
6612
|
+
}
|
|
6613
|
+
]
|
|
6614
|
+
},
|
|
6615
|
+
IgA: {
|
|
6616
|
+
default: { max: 400, min: 70, optimalMax: 350, optimalMin: 100, unit: "mg/dL" },
|
|
6617
|
+
kind: "reference-interval",
|
|
6618
|
+
source: "tietz-7ed-2015"
|
|
6619
|
+
},
|
|
6620
|
+
Lipase: {
|
|
6621
|
+
default: { max: 60, min: 0, optimalMax: 50, optimalMin: 10, unit: "U/L" },
|
|
6622
|
+
kind: "reference-interval",
|
|
6623
|
+
source: "tietz-7ed-2015"
|
|
6624
|
+
},
|
|
6625
|
+
Microalbumin_Urine: {
|
|
6626
|
+
default: { max: 30, min: 0, optimalMax: 20, optimalMin: 0, unit: "mg/L" },
|
|
6627
|
+
kind: "decision-threshold",
|
|
6628
|
+
source: "kdigo-ckd-2024"
|
|
6629
|
+
},
|
|
6630
|
+
PSA_Free: {
|
|
6631
|
+
default: { max: 1.5, min: 0, optimalMax: 1, optimalMin: 0, unit: "ng/mL" },
|
|
6632
|
+
kind: "reference-interval",
|
|
6633
|
+
source: "sturgeon-nacb-2008"
|
|
6634
|
+
},
|
|
6635
|
+
// Relação PSA livre/total — `higher-better`: razão maior = menor risco de
|
|
6636
|
+
// câncer de próstata, logo não há limite superior "ruim" (acima do normal é
|
|
6637
|
+
// verde). Faixas alinhadas à tabela clínica: ≥25% baixo risco (verde),
|
|
6638
|
+
// 10–25% atenção — intermediário/moderado (âmbar), <10% alto risco >50%
|
|
6639
|
+
// (vermelho). Limites: `min` (25) é o piso do verde e `warningMin` (10) o
|
|
6640
|
+
// piso do âmbar — o vermelho é estritamente abaixo de 10% (< 10%); 10%
|
|
6641
|
+
// pertence ao âmbar, conforme a faixa "10–15% moderado" da tabela.
|
|
6642
|
+
PSA_FreeRatio: {
|
|
6643
|
+
default: {
|
|
6644
|
+
max: 100,
|
|
6645
|
+
maxKind: "display",
|
|
6646
|
+
min: 25,
|
|
6647
|
+
optimalMax: 100,
|
|
6648
|
+
optimalMin: 30,
|
|
6649
|
+
unit: "%",
|
|
6650
|
+
warningMin: 10
|
|
6651
|
+
},
|
|
6652
|
+
direction: "higher-better",
|
|
6653
|
+
kind: "decision-threshold",
|
|
6654
|
+
source: "sturgeon-nacb-2008"
|
|
6655
|
+
},
|
|
6656
|
+
// BMI - WHO classification: 18.5–24.9 normal, 25–29.9 overweight, ≥30 obese
|
|
6657
|
+
BMI: {
|
|
6658
|
+
default: { max: 30, min: 18.5, optimalMax: 24.9, optimalMin: 18.5, unit: "kg/m2" },
|
|
6659
|
+
kind: "decision-threshold",
|
|
6660
|
+
source: "who-obesity-2000"
|
|
6661
|
+
},
|
|
6662
|
+
// eAG — Estimated Average Glucose, derivada da HbA1c pela fórmula ADAG:
|
|
6663
|
+
// eAG (mg/dL) = 28,7 × HbA1c(%) − 46,7 (NATHAN, D. M. et al. Translating the
|
|
6664
|
+
// A1C assay into estimated average glucose values. Diabetes Care, v. 31, n. 8,
|
|
6665
|
+
// p. 1473-1478, 2008. DOI: 10.2337/dc08-0545).
|
|
6666
|
+
//
|
|
6667
|
+
// As faixas espelham os cortes diagnósticos de HbA1c da SBD (ver entrada
|
|
6668
|
+
// `HbA1c`) convertidos por essa fórmula, mantendo a eAG coerente com o
|
|
6669
|
+
// marcador de origem:
|
|
6670
|
+
// optimalMax 105 ← HbA1c 5,3 % (teto do controle ótimo)
|
|
6671
|
+
// max 117 ← HbA1c 5,7 % (teto do não diabético → início do pré-diabetes)
|
|
6672
|
+
// warningMax 137 ← HbA1c 6,4 % (teto do pré-diabetes → acima disso, diabetes)
|
|
6673
|
+
// optimalMin 82 ← HbA1c 4,5 % (piso do alvo fisiológico da entrada HbA1c)
|
|
6674
|
+
// min 11 ← HbA1c 2,0 % (mesmo piso de sanidade da entrada HbA1c)
|
|
6675
|
+
//
|
|
6676
|
+
// O piso era 70 nos dois campos, e não vinha desta conversão: 70 é o limite
|
|
6677
|
+
// inferior clássico da glicemia **de jejum**, transplantado para uma média
|
|
6678
|
+
// estimada de ~3 meses. Pela fórmula, 70 equivale a HbA1c 4,07 % — ou seja,
|
|
6679
|
+
// marcava como alterado exatamente quem a entrada `HbA1c` documenta que não
|
|
6680
|
+
// deve ser sinalizado, já que HbA1c baixa reflete hemólise, perda sanguínea
|
|
6681
|
+
// ou hemoglobinopatia, e não doença do metabolismo glicêmico. Espelhar o piso
|
|
6682
|
+
// do HbA1c mantém as duas entradas coerentes, que é o que o comentário sempre
|
|
6683
|
+
// afirmou fazer.
|
|
6684
|
+
//
|
|
6685
|
+
// Substitui a faixa anterior (optimalMax 126 = corte de glicemia de jejum;
|
|
6686
|
+
// max 154 = meta terapêutica do diabético, HbA1c 7 %), que classificava como
|
|
6687
|
+
// "Normal" valores já pré-diabéticos e diabéticos.
|
|
6688
|
+
eAG: {
|
|
6689
|
+
default: {
|
|
6690
|
+
max: 117,
|
|
6691
|
+
min: 11,
|
|
6692
|
+
minKind: "display",
|
|
6693
|
+
optimalMax: 105,
|
|
6694
|
+
optimalMin: 82,
|
|
6695
|
+
unit: "mg/dL",
|
|
6696
|
+
warningMax: 137
|
|
6697
|
+
},
|
|
6698
|
+
kind: "decision-threshold",
|
|
6699
|
+
source: "sbd-diabetes-2024"
|
|
6700
|
+
},
|
|
6701
|
+
// INR - International Normalized Ratio (non-anticoagulated patients)
|
|
6702
|
+
INR: {
|
|
6703
|
+
default: { max: 1.2, min: 0.8, optimalMax: 1.1, optimalMin: 0.9, unit: "ratio" },
|
|
6704
|
+
kind: "reference-interval",
|
|
6705
|
+
source: "tietz-7ed-2015"
|
|
6706
|
+
},
|
|
6707
|
+
// Prothrombin Time
|
|
6708
|
+
ProthrombinTime: {
|
|
6709
|
+
default: { max: 13.5, min: 11, optimalMax: 13, optimalMin: 11, unit: "seconds" },
|
|
6710
|
+
kind: "reference-interval",
|
|
6711
|
+
source: "tietz-7ed-2015"
|
|
6712
|
+
},
|
|
6713
|
+
// DHT - Dihydrotestosterone (adult male reference; female values are much lower)
|
|
6714
|
+
DHT: {
|
|
6715
|
+
default: { max: 85, min: 30, optimalMax: 85, optimalMin: 30, unit: "ng/dL" },
|
|
6716
|
+
kind: "reference-interval",
|
|
6717
|
+
source: "tietz-7ed-2015",
|
|
6741
6718
|
variants: [
|
|
6742
6719
|
{
|
|
6743
6720
|
ageMin: 18,
|
|
6744
|
-
range: { max:
|
|
6721
|
+
range: { max: 85, min: 30, optimalMax: 85, optimalMin: 30, unit: "ng/dL" },
|
|
6745
6722
|
sex: "M"
|
|
6746
6723
|
},
|
|
6747
6724
|
{
|
|
6748
6725
|
ageMin: 18,
|
|
6749
|
-
range: { max:
|
|
6726
|
+
range: { max: 22, min: 4, optimalMax: 22, optimalMin: 4, unit: "ng/dL" },
|
|
6750
6727
|
sex: "F"
|
|
6751
6728
|
}
|
|
6752
6729
|
]
|
|
6753
6730
|
},
|
|
6754
|
-
|
|
6755
|
-
|
|
6756
|
-
|
|
6757
|
-
min: 0,
|
|
6758
|
-
optimalMax: 600,
|
|
6759
|
-
optimalMin: 0,
|
|
6760
|
-
unit: "cm\xB3",
|
|
6761
|
-
warningMax: 1837
|
|
6762
|
-
},
|
|
6731
|
+
// Total IgE - higher values suggest atopy/allergic sensitization
|
|
6732
|
+
IgE_Total: {
|
|
6733
|
+
default: { max: 100, min: 0, optimalMax: 100, optimalMin: 0, unit: "IU/mL" },
|
|
6763
6734
|
direction: "lower-better",
|
|
6764
|
-
|
|
6765
|
-
|
|
6766
|
-
BMD_Total: {
|
|
6767
|
-
default: { max: 1.4, min: 0.9, optimalMax: 1.3, optimalMin: 1, unit: "g/cm\xB2" },
|
|
6768
|
-
direction: "higher-better",
|
|
6769
|
-
source: "who-osteoporosis-1994"
|
|
6735
|
+
kind: "reference-interval",
|
|
6736
|
+
source: "tietz-7ed-2015"
|
|
6770
6737
|
},
|
|
6771
|
-
|
|
6772
|
-
|
|
6773
|
-
|
|
6774
|
-
|
|
6738
|
+
// IgG - Immunoglobulin G
|
|
6739
|
+
IgG: {
|
|
6740
|
+
default: { max: 1600, min: 700, optimalMax: 1600, optimalMin: 700, unit: "mg/dL" },
|
|
6741
|
+
kind: "reference-interval",
|
|
6742
|
+
source: "tietz-7ed-2015"
|
|
6775
6743
|
},
|
|
6776
|
-
|
|
6777
|
-
|
|
6778
|
-
|
|
6779
|
-
|
|
6744
|
+
// IgE E1 Cat Dander - Class 0 (≤0.35 kU/L) = negative
|
|
6745
|
+
IgE_E1_CatDander: {
|
|
6746
|
+
default: { max: 0.35, min: 0, optimalMax: 0.35, optimalMin: 0, unit: "kU/L" },
|
|
6747
|
+
direction: "lower-better",
|
|
6748
|
+
kind: "decision-threshold",
|
|
6749
|
+
source: "tietz-7ed-2015"
|
|
6780
6750
|
},
|
|
6781
|
-
|
|
6782
|
-
|
|
6751
|
+
// IgE GX1 Grasses - Class 0 (≤0.35 kU/L) = negative
|
|
6752
|
+
IgE_GX1_Grasses: {
|
|
6753
|
+
default: { max: 0.35, min: 0, optimalMax: 0.35, optimalMin: 0, unit: "kU/L" },
|
|
6754
|
+
direction: "lower-better",
|
|
6755
|
+
kind: "decision-threshold",
|
|
6783
6756
|
source: "tietz-7ed-2015"
|
|
6757
|
+
}
|
|
6758
|
+
};
|
|
6759
|
+
var defaultReferenceRanges = Object.fromEntries(
|
|
6760
|
+
Object.entries(biomarkerRangeDefinitions).map(([code, def]) => [
|
|
6761
|
+
code,
|
|
6762
|
+
{
|
|
6763
|
+
...def.default,
|
|
6764
|
+
...def.kind && { kind: def.kind },
|
|
6765
|
+
...def.source && { source: def.source }
|
|
6766
|
+
}
|
|
6767
|
+
])
|
|
6768
|
+
);
|
|
6769
|
+
function getReferenceRange(testCode, context) {
|
|
6770
|
+
const definition = biomarkerRangeDefinitions[testCode];
|
|
6771
|
+
if (!definition) return void 0;
|
|
6772
|
+
const withSource = (range2, kind = definition.kind) => ({
|
|
6773
|
+
...range2,
|
|
6774
|
+
...kind && { kind },
|
|
6775
|
+
...definition.source && { source: definition.source }
|
|
6776
|
+
});
|
|
6777
|
+
if (!context || !definition.variants || definition.variants.length === 0) {
|
|
6778
|
+
return withSource(definition.default);
|
|
6779
|
+
}
|
|
6780
|
+
const { age, biologicalSex, pregnancyTrimester, pregnant } = context;
|
|
6781
|
+
const hasPregnancyVariant = definition.variants.some((v) => v.pregnant === true);
|
|
6782
|
+
for (const variant of definition.variants) {
|
|
6783
|
+
if (variant.pregnant === true) {
|
|
6784
|
+
if (!pregnant) continue;
|
|
6785
|
+
if (variant.pregnancyTrimester !== void 0 && variant.pregnancyTrimester !== pregnancyTrimester) {
|
|
6786
|
+
continue;
|
|
6787
|
+
}
|
|
6788
|
+
} else if (pregnant && hasPregnancyVariant) {
|
|
6789
|
+
continue;
|
|
6790
|
+
}
|
|
6791
|
+
if (variant.sex !== "all" && variant.sex !== biologicalSex) {
|
|
6792
|
+
continue;
|
|
6793
|
+
}
|
|
6794
|
+
if (variant.ageMin !== void 0 && (age === void 0 || age < variant.ageMin)) {
|
|
6795
|
+
continue;
|
|
6796
|
+
}
|
|
6797
|
+
if (variant.ageMax !== void 0 && (age === void 0 || age > variant.ageMax)) {
|
|
6798
|
+
continue;
|
|
6799
|
+
}
|
|
6800
|
+
return withSource(variant.range, variant.kind ?? definition.kind);
|
|
6801
|
+
}
|
|
6802
|
+
return withSource(definition.default);
|
|
6803
|
+
}
|
|
6804
|
+
function getRangeDirection(testCode) {
|
|
6805
|
+
return biomarkerRangeDefinitions[testCode]?.direction ?? "range";
|
|
6806
|
+
}
|
|
6807
|
+
function referenceRangeMeaning(kind) {
|
|
6808
|
+
const system = "http://terminology.hl7.org/CodeSystem/referencerange-meaning";
|
|
6809
|
+
if (kind === "reference-interval") return { code: "normal", display: "Normal Range", system };
|
|
6810
|
+
if (kind === "decision-threshold") {
|
|
6811
|
+
return { code: "recommended", display: "Recommended Range", system };
|
|
6812
|
+
}
|
|
6813
|
+
return void 0;
|
|
6814
|
+
}
|
|
6815
|
+
|
|
6816
|
+
// src/converter.ts
|
|
6817
|
+
function interpretationCode(flag) {
|
|
6818
|
+
switch (flag) {
|
|
6819
|
+
case "H":
|
|
6820
|
+
return "H";
|
|
6821
|
+
// High
|
|
6822
|
+
case "L":
|
|
6823
|
+
return "L";
|
|
6824
|
+
// Low
|
|
6825
|
+
default:
|
|
6826
|
+
return "N";
|
|
6827
|
+
}
|
|
6828
|
+
}
|
|
6829
|
+
function interpretationDisplay(flag) {
|
|
6830
|
+
switch (flag) {
|
|
6831
|
+
case "H":
|
|
6832
|
+
return "High";
|
|
6833
|
+
case "L":
|
|
6834
|
+
return "Low";
|
|
6835
|
+
default:
|
|
6836
|
+
return "Normal";
|
|
6837
|
+
}
|
|
6838
|
+
}
|
|
6839
|
+
var SEX_CODING = {
|
|
6840
|
+
female: {
|
|
6841
|
+
code: "female",
|
|
6842
|
+
display: "Female",
|
|
6843
|
+
system: "http://hl7.org/fhir/administrative-gender"
|
|
6784
6844
|
},
|
|
6785
|
-
|
|
6786
|
-
|
|
6787
|
-
|
|
6788
|
-
|
|
6845
|
+
male: { code: "male", display: "Male", system: "http://hl7.org/fhir/administrative-gender" }
|
|
6846
|
+
};
|
|
6847
|
+
var buildReferenceRanges = (observation, quantity) => {
|
|
6848
|
+
const toRanges = (low, high, sex) => {
|
|
6849
|
+
if (low === void 0 && high === void 0) return [];
|
|
6850
|
+
return [
|
|
6789
6851
|
{
|
|
6790
|
-
|
|
6791
|
-
|
|
6792
|
-
|
|
6793
|
-
}
|
|
6852
|
+
...sex === void 0 ? {} : { appliesTo: [{ coding: [SEX_CODING[sex]] }] },
|
|
6853
|
+
...high === void 0 ? {} : { high: quantity(high) },
|
|
6854
|
+
...low === void 0 ? {} : { low: quantity(low) }
|
|
6855
|
+
}
|
|
6856
|
+
];
|
|
6857
|
+
};
|
|
6858
|
+
if (observation.referenceRanges && observation.referenceRanges.length > 0) {
|
|
6859
|
+
return observation.referenceRanges.flatMap((r) => toRanges(r.low, r.high, r.appliesTo));
|
|
6860
|
+
}
|
|
6861
|
+
const meaning = observation.referenceKind && referenceRangeMeaning(observation.referenceKind);
|
|
6862
|
+
return toRanges(observation.referenceMin, observation.referenceMax).map(
|
|
6863
|
+
(range2) => meaning ? { ...range2, type: { coding: [meaning] } } : range2
|
|
6864
|
+
);
|
|
6865
|
+
};
|
|
6866
|
+
function labObservationToFHIR(observation, patientId, laboratoryName) {
|
|
6867
|
+
const methodLoinc = observation.methodLoinc && methodVariantOf(observation.biomarkerCode, observation.methodLoinc) ? observation.methodLoinc : void 0;
|
|
6868
|
+
const loincCode = methodLoinc ?? codeToLoinc(observation.biomarkerCode);
|
|
6869
|
+
const sourceUnit = observation.unit || getDefaultUnit(observation.biomarkerCode) || observation.unit;
|
|
6870
|
+
const ucumUnit = resolveUcum(sourceUnit, observation.biomarkerCode);
|
|
6871
|
+
const quantity = (value) => ({
|
|
6872
|
+
...ucumUnit ? { code: ucumUnit, system: "http://unitsofmeasure.org" } : {},
|
|
6873
|
+
...sourceUnit ? { unit: sourceUnit } : {},
|
|
6874
|
+
value
|
|
6875
|
+
});
|
|
6876
|
+
const isQualitative = observation.isQualitative || typeof observation.value === "string";
|
|
6877
|
+
const fhirObs = {
|
|
6878
|
+
category: [
|
|
6879
|
+
{
|
|
6880
|
+
coding: [
|
|
6881
|
+
{
|
|
6882
|
+
code: "laboratory",
|
|
6883
|
+
display: "Laboratory",
|
|
6884
|
+
system: "http://terminology.hl7.org/CodeSystem/observation-category"
|
|
6885
|
+
}
|
|
6886
|
+
]
|
|
6887
|
+
}
|
|
6888
|
+
],
|
|
6889
|
+
code: {
|
|
6890
|
+
// Sem LOINC, o coding LOINC simplesmente não sai. Antes ia `99999-9`,
|
|
6891
|
+
// que não é código LOINC nenhum: publicava sob `http://loinc.org` uma
|
|
6892
|
+
// afirmação falsa, e quem consumisse o bundle confiando no system
|
|
6893
|
+
// trataria aquilo como código de verdade. Composição corporal, densidade
|
|
6894
|
+
// óssea e escore de cálcio não têm LOINC, e o certo é a lacuna explícita.
|
|
6895
|
+
coding: [
|
|
6896
|
+
...loincCode ? [
|
|
6897
|
+
{
|
|
6898
|
+
code: loincCode,
|
|
6899
|
+
display: observation.biomarkerName,
|
|
6900
|
+
system: LOINC_SYSTEM
|
|
6901
|
+
}
|
|
6902
|
+
] : [],
|
|
6903
|
+
{
|
|
6904
|
+
code: observation.biomarkerCode,
|
|
6905
|
+
display: observation.biomarkerName,
|
|
6906
|
+
system: BIOMARKER_CODE_SYSTEM
|
|
6907
|
+
}
|
|
6908
|
+
],
|
|
6909
|
+
text: observation.biomarkerName
|
|
6910
|
+
},
|
|
6911
|
+
effectiveDateTime: observation.collectionDate,
|
|
6912
|
+
id: `${observation.reportId}-${observation.biomarkerCode}`,
|
|
6913
|
+
interpretation: [
|
|
6914
|
+
{
|
|
6915
|
+
coding: [
|
|
6916
|
+
{
|
|
6917
|
+
code: interpretationCode(observation.flag),
|
|
6918
|
+
display: interpretationDisplay(observation.flag),
|
|
6919
|
+
system: "http://terminology.hl7.org/CodeSystem/v3-ObservationInterpretation"
|
|
6920
|
+
}
|
|
6921
|
+
]
|
|
6922
|
+
}
|
|
6923
|
+
],
|
|
6924
|
+
performer: laboratoryName ? [{ display: laboratoryName }] : void 0,
|
|
6925
|
+
resourceType: "Observation",
|
|
6926
|
+
status: "final",
|
|
6927
|
+
subject: {
|
|
6928
|
+
reference: `Patient/${patientId}`
|
|
6929
|
+
}
|
|
6930
|
+
};
|
|
6931
|
+
if (isQualitative) {
|
|
6932
|
+
fhirObs.valueString = String(observation.value);
|
|
6933
|
+
} else {
|
|
6934
|
+
fhirObs.valueQuantity = quantity(observation.value);
|
|
6935
|
+
const referenceRange = buildReferenceRanges(observation, quantity);
|
|
6936
|
+
if (referenceRange.length > 0) fhirObs.referenceRange = referenceRange;
|
|
6937
|
+
}
|
|
6938
|
+
return fhirObs;
|
|
6939
|
+
}
|
|
6940
|
+
function labReportToFHIR(report, patientId, observationIds) {
|
|
6941
|
+
let status;
|
|
6942
|
+
switch (report.processingStatus) {
|
|
6943
|
+
case "complete":
|
|
6944
|
+
status = "final";
|
|
6945
|
+
break;
|
|
6946
|
+
case "partial":
|
|
6947
|
+
status = "partial";
|
|
6948
|
+
break;
|
|
6949
|
+
case "pending_review":
|
|
6950
|
+
status = "preliminary";
|
|
6951
|
+
break;
|
|
6952
|
+
default:
|
|
6953
|
+
status = "final";
|
|
6954
|
+
}
|
|
6955
|
+
return {
|
|
6956
|
+
category: [
|
|
6957
|
+
{
|
|
6958
|
+
coding: [
|
|
6959
|
+
{
|
|
6960
|
+
code: "LAB",
|
|
6961
|
+
display: "Laboratory",
|
|
6962
|
+
system: "http://terminology.hl7.org/CodeSystem/v2-0074"
|
|
6963
|
+
}
|
|
6964
|
+
]
|
|
6965
|
+
}
|
|
6966
|
+
],
|
|
6967
|
+
code: {
|
|
6968
|
+
coding: [
|
|
6969
|
+
{
|
|
6970
|
+
code: "11502-2",
|
|
6971
|
+
// Laboratory report
|
|
6972
|
+
display: "Laboratory report",
|
|
6973
|
+
system: "http://loinc.org"
|
|
6974
|
+
}
|
|
6975
|
+
],
|
|
6976
|
+
text: "Laboratory Results"
|
|
6977
|
+
},
|
|
6978
|
+
conclusion: report.overallStatus === "NORMAL" ? "All results within normal limits" : "One or more abnormal results detected",
|
|
6979
|
+
conclusionCode: report.overallStatus === "ANORMAL" ? [
|
|
6794
6980
|
{
|
|
6795
|
-
|
|
6796
|
-
|
|
6797
|
-
|
|
6981
|
+
coding: [
|
|
6982
|
+
{
|
|
6983
|
+
code: "A",
|
|
6984
|
+
display: "Abnormal",
|
|
6985
|
+
system: "http://terminology.hl7.org/CodeSystem/v3-ObservationInterpretation"
|
|
6986
|
+
}
|
|
6987
|
+
]
|
|
6798
6988
|
}
|
|
6799
|
-
]
|
|
6800
|
-
|
|
6801
|
-
|
|
6802
|
-
|
|
6803
|
-
|
|
6804
|
-
|
|
6805
|
-
|
|
6806
|
-
|
|
6807
|
-
|
|
6808
|
-
|
|
6809
|
-
|
|
6810
|
-
|
|
6811
|
-
|
|
6812
|
-
|
|
6813
|
-
|
|
6814
|
-
|
|
6815
|
-
|
|
6816
|
-
|
|
6817
|
-
|
|
6818
|
-
// câncer de próstata, logo não há limite superior "ruim" (acima do normal é
|
|
6819
|
-
// verde). Faixas alinhadas à tabela clínica: ≥25% baixo risco (verde),
|
|
6820
|
-
// 10–25% atenção — intermediário/moderado (âmbar), <10% alto risco >50%
|
|
6821
|
-
// (vermelho). Limites: `min` (25) é o piso do verde e `warningMin` (10) o
|
|
6822
|
-
// piso do âmbar — o vermelho é estritamente abaixo de 10% (< 10%); 10%
|
|
6823
|
-
// pertence ao âmbar, conforme a faixa "10–15% moderado" da tabela.
|
|
6824
|
-
PSA_FreeRatio: {
|
|
6825
|
-
default: { max: 100, min: 25, optimalMax: 100, optimalMin: 30, unit: "%", warningMin: 10 },
|
|
6826
|
-
direction: "higher-better",
|
|
6827
|
-
source: "sturgeon-nacb-2008"
|
|
6828
|
-
},
|
|
6829
|
-
// BMI - WHO classification: 18.5–24.9 normal, 25–29.9 overweight, ≥30 obese
|
|
6830
|
-
BMI: {
|
|
6831
|
-
default: { max: 30, min: 18.5, optimalMax: 24.9, optimalMin: 18.5, unit: "kg/m2" },
|
|
6832
|
-
source: "who-obesity-2000"
|
|
6833
|
-
},
|
|
6834
|
-
// eAG — Estimated Average Glucose, derivada da HbA1c pela fórmula ADAG:
|
|
6835
|
-
// eAG (mg/dL) = 28,7 × HbA1c(%) − 46,7 (NATHAN, D. M. et al. Translating the
|
|
6836
|
-
// A1C assay into estimated average glucose values. Diabetes Care, v. 31, n. 8,
|
|
6837
|
-
// p. 1473-1478, 2008. DOI: 10.2337/dc08-0545).
|
|
6838
|
-
//
|
|
6839
|
-
// As faixas espelham os cortes diagnósticos de HbA1c da SBD (ver entrada
|
|
6840
|
-
// `HbA1c`) convertidos por essa fórmula, mantendo a eAG coerente com o
|
|
6841
|
-
// marcador de origem:
|
|
6842
|
-
// optimalMax 105 ← HbA1c 5,3 % (teto do controle ótimo)
|
|
6843
|
-
// max 117 ← HbA1c 5,7 % (teto do não diabético → início do pré-diabetes)
|
|
6844
|
-
// warningMax 137 ← HbA1c 6,4 % (teto do pré-diabetes → acima disso, diabetes)
|
|
6845
|
-
// optimalMin 82 ← HbA1c 4,5 % (piso do alvo fisiológico da entrada HbA1c)
|
|
6846
|
-
// min 11 ← HbA1c 2,0 % (mesmo piso de sanidade da entrada HbA1c)
|
|
6847
|
-
//
|
|
6848
|
-
// O piso era 70 nos dois campos, e não vinha desta conversão: 70 é o limite
|
|
6849
|
-
// inferior clássico da glicemia **de jejum**, transplantado para uma média
|
|
6850
|
-
// estimada de ~3 meses. Pela fórmula, 70 equivale a HbA1c 4,07 % — ou seja,
|
|
6851
|
-
// marcava como alterado exatamente quem a entrada `HbA1c` documenta que não
|
|
6852
|
-
// deve ser sinalizado, já que HbA1c baixa reflete hemólise, perda sanguínea
|
|
6853
|
-
// ou hemoglobinopatia, e não doença do metabolismo glicêmico. Espelhar o piso
|
|
6854
|
-
// do HbA1c mantém as duas entradas coerentes, que é o que o comentário sempre
|
|
6855
|
-
// afirmou fazer.
|
|
6856
|
-
//
|
|
6857
|
-
// Substitui a faixa anterior (optimalMax 126 = corte de glicemia de jejum;
|
|
6858
|
-
// max 154 = meta terapêutica do diabético, HbA1c 7 %), que classificava como
|
|
6859
|
-
// "Normal" valores já pré-diabéticos e diabéticos.
|
|
6860
|
-
eAG: {
|
|
6861
|
-
default: { max: 117, min: 11, optimalMax: 105, optimalMin: 82, unit: "mg/dL", warningMax: 137 },
|
|
6862
|
-
source: "sbd-diabetes-2024"
|
|
6863
|
-
},
|
|
6864
|
-
// INR - International Normalized Ratio (non-anticoagulated patients)
|
|
6865
|
-
INR: {
|
|
6866
|
-
default: { max: 1.2, min: 0.8, optimalMax: 1.1, optimalMin: 0.9, unit: "ratio" },
|
|
6867
|
-
source: "tietz-7ed-2015"
|
|
6868
|
-
},
|
|
6869
|
-
// Prothrombin Time
|
|
6870
|
-
ProthrombinTime: {
|
|
6871
|
-
default: { max: 13.5, min: 11, optimalMax: 13, optimalMin: 11, unit: "seconds" },
|
|
6872
|
-
source: "tietz-7ed-2015"
|
|
6873
|
-
},
|
|
6874
|
-
// DHT - Dihydrotestosterone (adult male reference; female values are much lower)
|
|
6875
|
-
DHT: {
|
|
6876
|
-
default: { max: 85, min: 30, optimalMax: 85, optimalMin: 30, unit: "ng/dL" },
|
|
6877
|
-
source: "tietz-7ed-2015",
|
|
6878
|
-
variants: [
|
|
6989
|
+
] : void 0,
|
|
6990
|
+
effectiveDateTime: report.collectionDate,
|
|
6991
|
+
id: report.reportId,
|
|
6992
|
+
issued: report.createdAt,
|
|
6993
|
+
performer: report.laboratoryName ? [{ display: report.laboratoryName }] : void 0,
|
|
6994
|
+
resourceType: "DiagnosticReport",
|
|
6995
|
+
result: observationIds.map((id) => ({ reference: `Observation/${id}` })),
|
|
6996
|
+
status,
|
|
6997
|
+
subject: {
|
|
6998
|
+
reference: `Patient/${patientId}`
|
|
6999
|
+
}
|
|
7000
|
+
};
|
|
7001
|
+
}
|
|
7002
|
+
function userProfileToFHIR(profile) {
|
|
7003
|
+
const nameParts = profile.name.split(" ");
|
|
7004
|
+
const given = nameParts.slice(0, -1);
|
|
7005
|
+
const family = nameParts[nameParts.length - 1] || "";
|
|
7006
|
+
return {
|
|
7007
|
+
address: profile.address ? [
|
|
6879
7008
|
{
|
|
6880
|
-
|
|
6881
|
-
|
|
6882
|
-
|
|
6883
|
-
|
|
7009
|
+
city: profile.address.city,
|
|
7010
|
+
country: profile.address.country || "BR",
|
|
7011
|
+
line: [
|
|
7012
|
+
profile.address.street && profile.address.number ? `${profile.address.street}, ${profile.address.number}` : profile.address.street,
|
|
7013
|
+
profile.address.complement
|
|
7014
|
+
].filter(Boolean),
|
|
7015
|
+
postalCode: profile.address.postalCode,
|
|
7016
|
+
state: profile.address.state
|
|
7017
|
+
}
|
|
7018
|
+
] : void 0,
|
|
7019
|
+
birthDate: profile.birthDate,
|
|
7020
|
+
gender: profile.gender,
|
|
7021
|
+
id: profile.userId,
|
|
7022
|
+
name: [
|
|
6884
7023
|
{
|
|
6885
|
-
|
|
6886
|
-
|
|
6887
|
-
|
|
7024
|
+
family,
|
|
7025
|
+
given: given.length > 0 ? given : void 0,
|
|
7026
|
+
text: profile.name
|
|
6888
7027
|
}
|
|
6889
|
-
]
|
|
6890
|
-
|
|
6891
|
-
|
|
6892
|
-
|
|
6893
|
-
|
|
6894
|
-
|
|
6895
|
-
|
|
6896
|
-
|
|
6897
|
-
|
|
6898
|
-
|
|
6899
|
-
|
|
6900
|
-
|
|
6901
|
-
|
|
6902
|
-
|
|
6903
|
-
|
|
6904
|
-
|
|
6905
|
-
|
|
6906
|
-
|
|
6907
|
-
|
|
6908
|
-
|
|
6909
|
-
|
|
6910
|
-
|
|
6911
|
-
|
|
6912
|
-
|
|
7028
|
+
],
|
|
7029
|
+
resourceType: "Patient",
|
|
7030
|
+
telecom: [
|
|
7031
|
+
...profile.email ? [{ system: "email", value: profile.email }] : [],
|
|
7032
|
+
...profile.phone ? [{ system: "phone", value: profile.phone }] : []
|
|
7033
|
+
].length > 0 ? [
|
|
7034
|
+
...profile.email ? [{ system: "email", value: profile.email }] : [],
|
|
7035
|
+
...profile.phone ? [{ system: "phone", value: profile.phone }] : []
|
|
7036
|
+
] : void 0
|
|
7037
|
+
};
|
|
7038
|
+
}
|
|
7039
|
+
function labResultToFHIRBundle(report, observations, userProfile) {
|
|
7040
|
+
const patientId = userProfile.userId;
|
|
7041
|
+
const fhirObservations = observations.map((obs) => {
|
|
7042
|
+
const resource = labObservationToFHIR(
|
|
7043
|
+
{ ...obs, collectionDate: report.collectionDate },
|
|
7044
|
+
patientId,
|
|
7045
|
+
report.laboratoryName
|
|
7046
|
+
);
|
|
7047
|
+
return { fullUrl: entryFullUrl(resource), resource };
|
|
7048
|
+
});
|
|
7049
|
+
const observationIds = fhirObservations.map((entry) => entry.resource.id);
|
|
7050
|
+
const diagnosticReport = labReportToFHIR(report, patientId, observationIds);
|
|
7051
|
+
const fhirPatient = userProfileToFHIR(userProfile);
|
|
7052
|
+
return {
|
|
7053
|
+
entry: [
|
|
7054
|
+
{ fullUrl: entryFullUrl(fhirPatient), resource: fhirPatient },
|
|
7055
|
+
{ fullUrl: entryFullUrl(diagnosticReport), resource: diagnosticReport },
|
|
7056
|
+
...fhirObservations
|
|
7057
|
+
],
|
|
7058
|
+
resourceType: "Bundle",
|
|
7059
|
+
type: "collection"
|
|
7060
|
+
};
|
|
7061
|
+
}
|
|
7062
|
+
|
|
7063
|
+
// src/cli/commands/convert.ts
|
|
7064
|
+
async function convert(args, json) {
|
|
7065
|
+
const raw = await getInput(args[0]);
|
|
7066
|
+
const data = parseJson(
|
|
7067
|
+
raw,
|
|
7068
|
+
"JSON inv\xE1lido. Forne\xE7a um objeto com { report, observations, profile }."
|
|
7069
|
+
);
|
|
7070
|
+
if (!data.report || !data.observations || !data.profile) {
|
|
7071
|
+
exitWithError(
|
|
7072
|
+
'Formato esperado: { "report": LabReportData, "observations": LabObservationData[], "profile": UserProfileData }'
|
|
7073
|
+
);
|
|
6913
7074
|
}
|
|
6914
|
-
|
|
6915
|
-
|
|
6916
|
-
|
|
6917
|
-
|
|
6918
|
-
|
|
6919
|
-
|
|
6920
|
-
|
|
6921
|
-
|
|
6922
|
-
|
|
6923
|
-
|
|
6924
|
-
const
|
|
6925
|
-
if (!
|
|
6926
|
-
|
|
7075
|
+
const bundle = labResultToFHIRBundle(data.report, data.observations, data.profile);
|
|
7076
|
+
if (json) {
|
|
7077
|
+
outputJson(bundle);
|
|
7078
|
+
} else {
|
|
7079
|
+
outputText(JSON.stringify(bundle, null, 2));
|
|
7080
|
+
}
|
|
7081
|
+
}
|
|
7082
|
+
|
|
7083
|
+
// src/validators.ts
|
|
7084
|
+
function validateFHIRImportBundle(data) {
|
|
7085
|
+
const errors = [];
|
|
7086
|
+
if (!data || typeof data !== "object") {
|
|
7087
|
+
errors.push({ details: "Input must be a JSON object", field: "root" });
|
|
7088
|
+
return errors;
|
|
7089
|
+
}
|
|
7090
|
+
const bundle = data;
|
|
7091
|
+
if (bundle.resourceType !== "Bundle") {
|
|
7092
|
+
errors.push({
|
|
7093
|
+
details: `Expected resourceType "Bundle", got "${String(bundle.resourceType)}"`,
|
|
7094
|
+
field: "resourceType"
|
|
7095
|
+
});
|
|
7096
|
+
}
|
|
7097
|
+
if (!Array.isArray(bundle.entry)) {
|
|
7098
|
+
errors.push({ details: 'Bundle must contain an "entry" array', field: "entry" });
|
|
7099
|
+
} else if (bundle.entry.length === 0) {
|
|
7100
|
+
errors.push({ details: "Bundle entry array is empty", field: "entry" });
|
|
7101
|
+
}
|
|
7102
|
+
return errors;
|
|
7103
|
+
}
|
|
7104
|
+
|
|
7105
|
+
// src/importer.ts
|
|
7106
|
+
var MAX_OBSERVATIONS = 5e3;
|
|
7107
|
+
var MAX_FILE_SIZE = 15 * 1024 * 1024;
|
|
7108
|
+
function resolveBiomarkerCode(observation) {
|
|
7109
|
+
const coding = observation.code?.coding ?? [];
|
|
7110
|
+
const loincCode = coding.find((c) => c.system === LOINC_SYSTEM)?.code;
|
|
7111
|
+
const declaredCode = coding.find((c) => c.system === BIOMARKER_CODE_SYSTEM)?.code;
|
|
7112
|
+
const seenCodes = [
|
|
7113
|
+
...loincCode ? [`LOINC ${loincCode}`] : [],
|
|
7114
|
+
...declaredCode ? [`biomarker code ${declaredCode}`] : []
|
|
7115
|
+
];
|
|
7116
|
+
let reason;
|
|
7117
|
+
if (seenCodes.length > 0) {
|
|
7118
|
+
reason = `Unknown code: ${seenCodes.join(", ")}`;
|
|
7119
|
+
} else if (coding.length > 0) {
|
|
7120
|
+
const systems = [...new Set(coding.map((c) => c.system ?? "(sem system)"))];
|
|
7121
|
+
reason = `No code in a supported system (found: ${systems.join(", ")})`;
|
|
7122
|
+
} else {
|
|
7123
|
+
reason = "No code found in observation coding";
|
|
6927
7124
|
}
|
|
6928
|
-
const
|
|
6929
|
-
|
|
6930
|
-
|
|
6931
|
-
|
|
6932
|
-
|
|
6933
|
-
|
|
6934
|
-
|
|
6935
|
-
|
|
6936
|
-
|
|
7125
|
+
const fromLoinc = loincCode ? loincToCode(loincCode) : void 0;
|
|
7126
|
+
if (fromLoinc) return { internalCode: fromLoinc, loincCode, reason };
|
|
7127
|
+
if (declaredCode && isValidCode(declaredCode)) {
|
|
7128
|
+
const canonical = normalizeCode(declaredCode);
|
|
7129
|
+
return { internalCode: canonical, loincCode: codeToLoinc(canonical), reason };
|
|
7130
|
+
}
|
|
7131
|
+
return { loincCode, reason };
|
|
7132
|
+
}
|
|
7133
|
+
function extractFlag(observation) {
|
|
7134
|
+
const code = observation.interpretation?.[0]?.coding?.[0]?.code;
|
|
7135
|
+
if (code === "H" || code === "HH") return "H";
|
|
7136
|
+
if (code === "L" || code === "LL") return "L";
|
|
7137
|
+
return "";
|
|
7138
|
+
}
|
|
7139
|
+
function extractObservationsFromBundle(bundle) {
|
|
7140
|
+
const observations = [];
|
|
7141
|
+
const skipped = [];
|
|
7142
|
+
for (let i = 0; i < bundle.entry.length; i++) {
|
|
7143
|
+
const entry = bundle.entry[i];
|
|
7144
|
+
if (!entry.resource) {
|
|
7145
|
+
skipped.push({ index: i, reason: "Entry has no resource" });
|
|
6937
7146
|
continue;
|
|
6938
7147
|
}
|
|
6939
|
-
if (
|
|
7148
|
+
if (entry.resource.resourceType !== "Observation") {
|
|
6940
7149
|
continue;
|
|
6941
7150
|
}
|
|
6942
|
-
if (
|
|
7151
|
+
if (observations.length >= MAX_OBSERVATIONS) {
|
|
7152
|
+
skipped.push({ index: i, reason: `Maximum of ${MAX_OBSERVATIONS} observations exceeded` });
|
|
6943
7153
|
continue;
|
|
6944
7154
|
}
|
|
6945
|
-
|
|
6946
|
-
|
|
7155
|
+
observations.push(entry.resource);
|
|
7156
|
+
}
|
|
7157
|
+
return { observations, skipped };
|
|
7158
|
+
}
|
|
7159
|
+
function mapFHIRObservationToInternal(observation, index) {
|
|
7160
|
+
const { internalCode, loincCode, reason } = resolveBiomarkerCode(observation);
|
|
7161
|
+
if (!internalCode) {
|
|
7162
|
+
return {
|
|
7163
|
+
skipped: { index, loincCode, reason, resourceType: "Observation" }
|
|
7164
|
+
};
|
|
7165
|
+
}
|
|
7166
|
+
const definition = getDefinitionByCode(internalCode);
|
|
7167
|
+
let value;
|
|
7168
|
+
let unit = "";
|
|
7169
|
+
let isQualitative = false;
|
|
7170
|
+
if (observation.valueQuantity?.value !== void 0) {
|
|
7171
|
+
value = observation.valueQuantity.value;
|
|
7172
|
+
unit = observation.valueQuantity.unit || observation.valueQuantity.code || "";
|
|
7173
|
+
} else if (observation.valueString) {
|
|
7174
|
+
value = observation.valueString;
|
|
7175
|
+
isQualitative = true;
|
|
7176
|
+
} else {
|
|
7177
|
+
return {
|
|
7178
|
+
skipped: {
|
|
7179
|
+
index,
|
|
7180
|
+
loincCode,
|
|
7181
|
+
reason: "Observation has no value (valueQuantity or valueString)",
|
|
7182
|
+
resourceType: "Observation"
|
|
7183
|
+
}
|
|
7184
|
+
};
|
|
7185
|
+
}
|
|
7186
|
+
const collectionDate = observation.effectiveDateTime || observation.effectivePeriod?.start || "";
|
|
7187
|
+
if (!collectionDate) {
|
|
7188
|
+
return {
|
|
7189
|
+
skipped: {
|
|
7190
|
+
index,
|
|
7191
|
+
loincCode,
|
|
7192
|
+
reason: "Observation has no effectiveDateTime or effectivePeriod.start",
|
|
7193
|
+
resourceType: "Observation"
|
|
7194
|
+
}
|
|
7195
|
+
};
|
|
7196
|
+
}
|
|
7197
|
+
let referenceMin;
|
|
7198
|
+
let referenceMax;
|
|
7199
|
+
let referenceKind;
|
|
7200
|
+
if (observation.referenceRange?.[0]) {
|
|
7201
|
+
referenceMin = observation.referenceRange[0].low?.value;
|
|
7202
|
+
referenceMax = observation.referenceRange[0].high?.value;
|
|
7203
|
+
const meaning = observation.referenceRange[0].type?.coding?.find(
|
|
7204
|
+
(c) => c.system === "http://terminology.hl7.org/CodeSystem/referencerange-meaning"
|
|
7205
|
+
)?.code;
|
|
7206
|
+
if (meaning === "normal") referenceKind = "reference-interval";
|
|
7207
|
+
else if (meaning === "recommended") referenceKind = "decision-threshold";
|
|
7208
|
+
}
|
|
7209
|
+
const imported = {
|
|
7210
|
+
biomarkerCode: internalCode,
|
|
7211
|
+
biomarkerName: definition?.names.pt[0] || definition?.names.en[0] || observation.code.text || internalCode,
|
|
7212
|
+
collectionDate,
|
|
7213
|
+
flag: extractFlag(observation),
|
|
7214
|
+
isQualitative,
|
|
7215
|
+
loincCode,
|
|
7216
|
+
...loincCode && methodVariantOf(internalCode, loincCode) && { methodLoinc: loincCode },
|
|
7217
|
+
...referenceKind && { referenceKind },
|
|
7218
|
+
referenceMax,
|
|
7219
|
+
referenceMin,
|
|
7220
|
+
unit: unit || definition?.unit || "",
|
|
7221
|
+
value
|
|
7222
|
+
};
|
|
7223
|
+
return { observation: imported };
|
|
7224
|
+
}
|
|
7225
|
+
function processImportBundle(data) {
|
|
7226
|
+
const validationErrors = validateFHIRImportBundle(data);
|
|
7227
|
+
if (validationErrors.length > 0) {
|
|
7228
|
+
return {
|
|
7229
|
+
errors: validationErrors,
|
|
7230
|
+
imported: [],
|
|
7231
|
+
skipped: [],
|
|
7232
|
+
totalProcessed: 0
|
|
7233
|
+
};
|
|
7234
|
+
}
|
|
7235
|
+
const bundle = data;
|
|
7236
|
+
const { observations, skipped } = extractObservationsFromBundle(bundle);
|
|
7237
|
+
const imported = [];
|
|
7238
|
+
const allSkipped = [...skipped];
|
|
7239
|
+
for (let i = 0; i < observations.length; i++) {
|
|
7240
|
+
const result = mapFHIRObservationToInternal(observations[i], i);
|
|
7241
|
+
if ("observation" in result) {
|
|
7242
|
+
imported.push(result.observation);
|
|
7243
|
+
} else {
|
|
7244
|
+
allSkipped.push(result.skipped);
|
|
6947
7245
|
}
|
|
6948
|
-
return withSource(variant.range);
|
|
6949
7246
|
}
|
|
6950
|
-
return
|
|
7247
|
+
return {
|
|
7248
|
+
errors: [],
|
|
7249
|
+
imported,
|
|
7250
|
+
skipped: allSkipped,
|
|
7251
|
+
totalProcessed: observations.length
|
|
7252
|
+
};
|
|
6951
7253
|
}
|
|
6952
|
-
|
|
6953
|
-
|
|
7254
|
+
|
|
7255
|
+
// src/cli/commands/import.ts
|
|
7256
|
+
async function importBundle(args, json) {
|
|
7257
|
+
const raw = await getInput(args[0]);
|
|
7258
|
+
const bundle = parseJson(raw, "JSON inv\xE1lido.");
|
|
7259
|
+
const result = processImportBundle(bundle);
|
|
7260
|
+
if (json) {
|
|
7261
|
+
outputJson(result);
|
|
7262
|
+
return;
|
|
7263
|
+
}
|
|
7264
|
+
outputText(`Processados: ${result.totalProcessed}`);
|
|
7265
|
+
outputText(`Importados: ${result.imported.length}`);
|
|
7266
|
+
outputText(`Ignorados: ${result.skipped.length}`);
|
|
7267
|
+
outputText(`Erros: ${result.errors.length}`);
|
|
7268
|
+
if (result.imported.length > 0) {
|
|
7269
|
+
outputText("\nObserva\xE7\xF5es importadas:");
|
|
7270
|
+
for (const obs of result.imported) {
|
|
7271
|
+
outputText(` ${obs.biomarkerCode} (${obs.loincCode}): ${obs.value} ${obs.unit}`);
|
|
7272
|
+
}
|
|
7273
|
+
}
|
|
7274
|
+
if (result.errors.length > 0) {
|
|
7275
|
+
outputText("\nErros:");
|
|
7276
|
+
for (const err of result.errors) {
|
|
7277
|
+
outputText(` ${err.field}: ${err.details}`);
|
|
7278
|
+
}
|
|
7279
|
+
}
|
|
7280
|
+
}
|
|
7281
|
+
|
|
7282
|
+
// src/cli/commands/list.ts
|
|
7283
|
+
import { parseArgs } from "util";
|
|
7284
|
+
async function list(args, json) {
|
|
7285
|
+
const { values } = parseArgs({
|
|
7286
|
+
args,
|
|
7287
|
+
options: {
|
|
7288
|
+
category: { type: "string" },
|
|
7289
|
+
visible: { default: false, type: "boolean" }
|
|
7290
|
+
},
|
|
7291
|
+
strict: false
|
|
7292
|
+
});
|
|
7293
|
+
let defs;
|
|
7294
|
+
if (values.category) {
|
|
7295
|
+
defs = getBiomarkersByCategory(values.category);
|
|
7296
|
+
if (defs.length === 0) {
|
|
7297
|
+
exitWithError(`Categoria n\xE3o encontrada ou vazia: ${values.category}`);
|
|
7298
|
+
}
|
|
7299
|
+
} else if (values.visible) {
|
|
7300
|
+
defs = getVisibleDefinitions();
|
|
7301
|
+
} else {
|
|
7302
|
+
defs = getAllDefinitions();
|
|
7303
|
+
}
|
|
7304
|
+
if (json) {
|
|
7305
|
+
outputJson(defs);
|
|
7306
|
+
return;
|
|
7307
|
+
}
|
|
7308
|
+
const rows = defs.map((d) => [
|
|
7309
|
+
d.code,
|
|
7310
|
+
d.loinc ?? "\u2014",
|
|
7311
|
+
d.names.pt[0] ?? "",
|
|
7312
|
+
d.unit ?? "\u2014",
|
|
7313
|
+
Array.isArray(d.category) ? d.category.join(", ") : d.category
|
|
7314
|
+
]);
|
|
7315
|
+
outputText(formatTable(["C\xF3digo", "LOINC", "Nome (pt)", "Unidade", "Categoria"], rows));
|
|
7316
|
+
outputText(`
|
|
7317
|
+
Total: ${defs.length} biomarcadores`);
|
|
7318
|
+
}
|
|
7319
|
+
|
|
7320
|
+
// src/cli/commands/loinc-map.ts
|
|
7321
|
+
async function loincMap(_args, json) {
|
|
7322
|
+
const defs = getAllDefinitions().filter((d) => d.loinc);
|
|
7323
|
+
if (json) {
|
|
7324
|
+
const map = Object.fromEntries(defs.map((d) => [d.loinc, d.code]));
|
|
7325
|
+
outputJson(map);
|
|
7326
|
+
return;
|
|
7327
|
+
}
|
|
7328
|
+
const rows = defs.map((d) => [d.loinc, d.code, d.names.pt[0] ?? d.names.en[0] ?? ""]);
|
|
7329
|
+
outputText(formatTable(["LOINC", "C\xF3digo", "Nome (pt)"], rows));
|
|
7330
|
+
outputText(`
|
|
7331
|
+
Total: ${rows.length} mapeamentos`);
|
|
7332
|
+
}
|
|
7333
|
+
|
|
7334
|
+
// src/cli/commands/lookup.ts
|
|
7335
|
+
function displayDefinition(def) {
|
|
7336
|
+
const cat = Array.isArray(def.category) ? def.category.join(", ") : def.category;
|
|
7337
|
+
outputText(
|
|
7338
|
+
[
|
|
7339
|
+
`Biomarcador: ${def.code}`,
|
|
7340
|
+
` LOINC: ${def.loinc ?? "\u2014"}`,
|
|
7341
|
+
` Nomes (pt): ${def.names.pt.join(", ")}`,
|
|
7342
|
+
` Nomes (en): ${def.names.en.join(", ")}`,
|
|
7343
|
+
` Categoria: ${cat}`,
|
|
7344
|
+
` Unidade: ${def.unit ?? "\u2014"}`,
|
|
7345
|
+
` Sexo: ${def.sex ?? "ambos"}`,
|
|
7346
|
+
` Vis\xEDvel: ${def.hidden ? "n\xE3o" : "sim"}`
|
|
7347
|
+
].join("\n")
|
|
7348
|
+
);
|
|
7349
|
+
}
|
|
7350
|
+
async function lookup(args, json) {
|
|
7351
|
+
const code = args[0];
|
|
7352
|
+
if (!code) exitWithError("Uso: fhir-bio lookup <c\xF3digo>");
|
|
7353
|
+
const def = getDefinitionByCode(code);
|
|
7354
|
+
if (!def) exitWithError(`Biomarcador n\xE3o encontrado: ${code}`);
|
|
7355
|
+
if (json) {
|
|
7356
|
+
outputJson(def);
|
|
7357
|
+
} else {
|
|
7358
|
+
displayDefinition(def);
|
|
7359
|
+
}
|
|
7360
|
+
}
|
|
7361
|
+
async function lookupLoinc(args, json) {
|
|
7362
|
+
const loinc = args[0];
|
|
7363
|
+
if (!loinc) exitWithError("Uso: fhir-bio lookup-loinc <loinc>");
|
|
7364
|
+
const def = getDefinitionByLoinc(loinc);
|
|
7365
|
+
if (!def) exitWithError(`Biomarcador n\xE3o encontrado para LOINC: ${loinc}`);
|
|
7366
|
+
if (json) {
|
|
7367
|
+
outputJson(def);
|
|
7368
|
+
} else {
|
|
7369
|
+
displayDefinition(def);
|
|
7370
|
+
}
|
|
6954
7371
|
}
|
|
6955
7372
|
|
|
6956
7373
|
// src/cli/commands/range.ts
|
|
7374
|
+
import { parseArgs as parseArgs2 } from "util";
|
|
6957
7375
|
async function range(args, json) {
|
|
6958
7376
|
const { positionals, values } = parseArgs2({
|
|
6959
7377
|
allowPositionals: true,
|
|
@@ -6990,11 +7408,18 @@ async function range(args, json) {
|
|
|
6990
7408
|
const sexLabel = ctx.biologicalSex === "M" ? "Homem" : ctx.biologicalSex === "F" ? "Mulher" : "Geral";
|
|
6991
7409
|
const ageLabel = ctx.age !== void 0 ? `, ${ctx.age} anos` : "";
|
|
6992
7410
|
const fmt = (v) => v !== void 0 ? String(v) : "\u2014";
|
|
7411
|
+
const desenho = (kind) => kind === "display" ? " (desenho, n\xE3o \xE9 corte)" : "";
|
|
7412
|
+
const tipos = {
|
|
7413
|
+
"decision-threshold": "limiar de decis\xE3o",
|
|
7414
|
+
population: "distribui\xE7\xE3o populacional",
|
|
7415
|
+
"reference-interval": "intervalo de refer\xEAncia"
|
|
7416
|
+
};
|
|
6993
7417
|
outputText(
|
|
6994
7418
|
[
|
|
6995
7419
|
`Faixa de Refer\xEAncia: ${code} (${sexLabel}${ageLabel})`,
|
|
6996
|
-
`
|
|
6997
|
-
` M\
|
|
7420
|
+
` Tipo: ${ref.kind ? tipos[ref.kind] : "\u2014"}`,
|
|
7421
|
+
` M\xEDnimo: ${fmt(ref.min)} ${ref.unit}${desenho(ref.minKind)}`,
|
|
7422
|
+
` M\xE1ximo: ${fmt(ref.max)} ${ref.unit}${desenho(ref.maxKind)}`,
|
|
6998
7423
|
` \xD3timo (m\xEDn): ${fmt(ref.optimalMin)} ${ref.unit}`,
|
|
6999
7424
|
` \xD3timo (m\xE1x): ${fmt(ref.optimalMax)} ${ref.unit}`,
|
|
7000
7425
|
` Alerta (m\xE1x): ${fmt(ref.warningMax)} ${ref.unit}`,
|
|
@@ -7487,7 +7912,7 @@ var COMMANDS = {
|
|
|
7487
7912
|
async function main() {
|
|
7488
7913
|
const { command, help, json, resto, version } = dividirArgv(process.argv.slice(2));
|
|
7489
7914
|
if (version) {
|
|
7490
|
-
process.stdout.write(`${"0.
|
|
7915
|
+
process.stdout.write(`${"0.35.0"}
|
|
7491
7916
|
`);
|
|
7492
7917
|
return;
|
|
7493
7918
|
}
|