@precisa-saude/fhir 0.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (72) hide show
  1. package/README.md +85 -0
  2. package/dist/biomarkers.cjs +67 -0
  3. package/dist/biomarkers.cjs.map +1 -0
  4. package/dist/biomarkers.d.cts +226 -0
  5. package/dist/biomarkers.d.ts +226 -0
  6. package/dist/biomarkers.js +67 -0
  7. package/dist/biomarkers.js.map +1 -0
  8. package/dist/chunk-2EVQ2ESB.cjs +2692 -0
  9. package/dist/chunk-2EVQ2ESB.cjs.map +1 -0
  10. package/dist/chunk-2X6MT5KE.cjs +1464 -0
  11. package/dist/chunk-2X6MT5KE.cjs.map +1 -0
  12. package/dist/chunk-3ILBFLVQ.cjs +63 -0
  13. package/dist/chunk-3ILBFLVQ.cjs.map +1 -0
  14. package/dist/chunk-FDOBUUGY.js +1464 -0
  15. package/dist/chunk-FDOBUUGY.js.map +1 -0
  16. package/dist/chunk-GFXKYXHW.cjs +436 -0
  17. package/dist/chunk-GFXKYXHW.cjs.map +1 -0
  18. package/dist/chunk-I6H35QXI.js +2692 -0
  19. package/dist/chunk-I6H35QXI.js.map +1 -0
  20. package/dist/chunk-N3ZCOLG2.js +63 -0
  21. package/dist/chunk-N3ZCOLG2.js.map +1 -0
  22. package/dist/chunk-O25F6G3K.cjs +153 -0
  23. package/dist/chunk-O25F6G3K.cjs.map +1 -0
  24. package/dist/chunk-S6VJHXJF.js +153 -0
  25. package/dist/chunk-S6VJHXJF.js.map +1 -0
  26. package/dist/chunk-UIDSSWBJ.js +251 -0
  27. package/dist/chunk-UIDSSWBJ.js.map +1 -0
  28. package/dist/chunk-VPMT4MRS.js +436 -0
  29. package/dist/chunk-VPMT4MRS.js.map +1 -0
  30. package/dist/chunk-Z6YE6FJ4.cjs +251 -0
  31. package/dist/chunk-Z6YE6FJ4.cjs.map +1 -0
  32. package/dist/converter-C-QpCcTL.d.ts +99 -0
  33. package/dist/converter-Dee-qjBV.d.cts +99 -0
  34. package/dist/converter.cjs +15 -0
  35. package/dist/converter.cjs.map +1 -0
  36. package/dist/converter.d.cts +2 -0
  37. package/dist/converter.d.ts +2 -0
  38. package/dist/converter.js +15 -0
  39. package/dist/converter.js.map +1 -0
  40. package/dist/fhir-types-D9hUzGrc.d.cts +129 -0
  41. package/dist/fhir-types-D9hUzGrc.d.ts +129 -0
  42. package/dist/importer.cjs +17 -0
  43. package/dist/importer.cjs.map +1 -0
  44. package/dist/importer.d.cts +60 -0
  45. package/dist/importer.d.ts +60 -0
  46. package/dist/importer.js +17 -0
  47. package/dist/importer.js.map +1 -0
  48. package/dist/index.cjs +540 -0
  49. package/dist/index.cjs.map +1 -0
  50. package/dist/index.d.cts +163 -0
  51. package/dist/index.d.ts +163 -0
  52. package/dist/index.js +540 -0
  53. package/dist/index.js.map +1 -0
  54. package/dist/reference-ranges.cjs +18 -0
  55. package/dist/reference-ranges.cjs.map +1 -0
  56. package/dist/reference-ranges.d.cts +106 -0
  57. package/dist/reference-ranges.d.ts +106 -0
  58. package/dist/reference-ranges.js +18 -0
  59. package/dist/reference-ranges.js.map +1 -0
  60. package/dist/units.cjs +19 -0
  61. package/dist/units.cjs.map +1 -0
  62. package/dist/units.d.cts +46 -0
  63. package/dist/units.d.ts +46 -0
  64. package/dist/units.js +19 -0
  65. package/dist/units.js.map +1 -0
  66. package/dist/validators.cjs +11 -0
  67. package/dist/validators.cjs.map +1 -0
  68. package/dist/validators.d.cts +23 -0
  69. package/dist/validators.d.ts +23 -0
  70. package/dist/validators.js +11 -0
  71. package/dist/validators.js.map +1 -0
  72. package/package.json +105 -0
@@ -0,0 +1,153 @@
1
+ import {
2
+ getDefinitionByLoinc,
3
+ loincToCode
4
+ } from "./chunk-I6H35QXI.js";
5
+ import {
6
+ validateFHIRImportBundle
7
+ } from "./chunk-N3ZCOLG2.js";
8
+
9
+ // src/importer.ts
10
+ var MAX_OBSERVATIONS = 1e3;
11
+ var MAX_FILE_SIZE = 5 * 1024 * 1024;
12
+ function extractLoincCode(observation) {
13
+ if (!observation.code?.coding) return void 0;
14
+ const loincCoding = observation.code.coding.find((c) => c.system === "http://loinc.org");
15
+ return loincCoding?.code;
16
+ }
17
+ function extractFlag(observation) {
18
+ const code = observation.interpretation?.[0]?.coding?.[0]?.code;
19
+ if (code === "H" || code === "HH") return "H";
20
+ if (code === "L" || code === "LL") return "L";
21
+ return "";
22
+ }
23
+ function extractObservationsFromBundle(bundle) {
24
+ const observations = [];
25
+ const skipped = [];
26
+ for (let i = 0; i < bundle.entry.length; i++) {
27
+ const entry = bundle.entry[i];
28
+ if (!entry.resource) {
29
+ skipped.push({ index: i, reason: "Entry has no resource" });
30
+ continue;
31
+ }
32
+ if (entry.resource.resourceType !== "Observation") {
33
+ continue;
34
+ }
35
+ if (observations.length >= MAX_OBSERVATIONS) {
36
+ skipped.push({ index: i, reason: `Maximum of ${MAX_OBSERVATIONS} observations exceeded` });
37
+ continue;
38
+ }
39
+ observations.push(entry.resource);
40
+ }
41
+ return { observations, skipped };
42
+ }
43
+ function mapFHIRObservationToInternal(observation, index) {
44
+ const loincCode = extractLoincCode(observation);
45
+ if (!loincCode) {
46
+ return {
47
+ skipped: {
48
+ index,
49
+ reason: "No LOINC code found in observation coding",
50
+ resourceType: "Observation"
51
+ }
52
+ };
53
+ }
54
+ const internalCode = loincToCode(loincCode);
55
+ if (!internalCode) {
56
+ return {
57
+ skipped: {
58
+ index,
59
+ loincCode,
60
+ reason: `Unknown LOINC code: ${loincCode}`,
61
+ resourceType: "Observation"
62
+ }
63
+ };
64
+ }
65
+ const definition = getDefinitionByLoinc(loincCode);
66
+ let value;
67
+ let unit = "";
68
+ let isQualitative = false;
69
+ if (observation.valueQuantity?.value !== void 0) {
70
+ value = observation.valueQuantity.value;
71
+ unit = observation.valueQuantity.unit || observation.valueQuantity.code || "";
72
+ } else if (observation.valueString) {
73
+ value = observation.valueString;
74
+ isQualitative = true;
75
+ } else {
76
+ return {
77
+ skipped: {
78
+ index,
79
+ loincCode,
80
+ reason: "Observation has no value (valueQuantity or valueString)",
81
+ resourceType: "Observation"
82
+ }
83
+ };
84
+ }
85
+ const collectionDate = observation.effectiveDateTime || observation.effectivePeriod?.start || "";
86
+ if (!collectionDate) {
87
+ return {
88
+ skipped: {
89
+ index,
90
+ loincCode,
91
+ reason: "Observation has no effectiveDateTime or effectivePeriod.start",
92
+ resourceType: "Observation"
93
+ }
94
+ };
95
+ }
96
+ let referenceMin;
97
+ let referenceMax;
98
+ if (observation.referenceRange?.[0]) {
99
+ referenceMin = observation.referenceRange[0].low?.value;
100
+ referenceMax = observation.referenceRange[0].high?.value;
101
+ }
102
+ const imported = {
103
+ biomarkerCode: internalCode,
104
+ biomarkerName: definition?.names.pt[0] || definition?.names.en[0] || observation.code.text || internalCode,
105
+ collectionDate,
106
+ flag: extractFlag(observation),
107
+ isQualitative,
108
+ loincCode,
109
+ referenceMax,
110
+ referenceMin,
111
+ unit: unit || definition?.unit || "",
112
+ value
113
+ };
114
+ return { observation: imported };
115
+ }
116
+ function processImportBundle(data) {
117
+ const validationErrors = validateFHIRImportBundle(data);
118
+ if (validationErrors.length > 0) {
119
+ return {
120
+ errors: validationErrors,
121
+ imported: [],
122
+ skipped: [],
123
+ totalProcessed: 0
124
+ };
125
+ }
126
+ const bundle = data;
127
+ const { observations, skipped } = extractObservationsFromBundle(bundle);
128
+ const imported = [];
129
+ const allSkipped = [...skipped];
130
+ for (let i = 0; i < observations.length; i++) {
131
+ const result = mapFHIRObservationToInternal(observations[i], i);
132
+ if ("observation" in result) {
133
+ imported.push(result.observation);
134
+ } else {
135
+ allSkipped.push(result.skipped);
136
+ }
137
+ }
138
+ return {
139
+ errors: [],
140
+ imported,
141
+ skipped: allSkipped,
142
+ totalProcessed: observations.length
143
+ };
144
+ }
145
+
146
+ export {
147
+ MAX_OBSERVATIONS,
148
+ MAX_FILE_SIZE,
149
+ extractObservationsFromBundle,
150
+ mapFHIRObservationToInternal,
151
+ processImportBundle
152
+ };
153
+ //# sourceMappingURL=chunk-S6VJHXJF.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/importer.ts"],"sourcesContent":["/**\n * FHIR Importer\n *\n * Parses FHIR R4 Bundles and extracts Observation resources with known LOINC codes,\n * mapping them to internal biomarker codes for storage as lab results.\n */\n\nimport { getDefinitionByLoinc, loincToCode } from './biomarkers';\nimport type { FHIRBundle, FHIRObservation } from './fhir-types';\nimport { validateFHIRImportBundle } from './validators';\n\nexport interface ImportedObservation {\n biomarkerCode: string;\n biomarkerName: string;\n collectionDate: string;\n flag: 'H' | 'L' | '';\n isQualitative: boolean;\n loincCode: string;\n referenceMax?: number;\n referenceMin?: number;\n unit: string;\n value: number | string;\n}\n\nexport interface SkippedEntry {\n index: number;\n loincCode?: string;\n reason: string;\n resourceType?: string;\n}\n\nexport interface ImportError {\n details: string;\n field: string;\n}\n\nexport interface FHIRImportResult {\n errors: ImportError[];\n imported: ImportedObservation[];\n skipped: SkippedEntry[];\n totalProcessed: number;\n}\n\nconst MAX_OBSERVATIONS = 1000;\nconst MAX_FILE_SIZE = 5 * 1024 * 1024; // 5MB\n\n/**\n * Extract LOINC code from an Observation's code.coding array\n */\nfunction extractLoincCode(observation: FHIRObservation): string | undefined {\n if (!observation.code?.coding) return undefined;\n const loincCoding = observation.code.coding.find((c) => c.system === 'http://loinc.org');\n return loincCoding?.code;\n}\n\n/**\n * Extract interpretation flag from Observation\n */\nfunction extractFlag(observation: FHIRObservation): 'H' | 'L' | '' {\n const code = observation.interpretation?.[0]?.coding?.[0]?.code;\n if (code === 'H' || code === 'HH') return 'H';\n if (code === 'L' || code === 'LL') return 'L';\n return '';\n}\n\n/**\n * Extract Observation resources from a FHIR Bundle\n */\nexport function extractObservationsFromBundle(bundle: FHIRBundle): {\n observations: FHIRObservation[];\n skipped: SkippedEntry[];\n} {\n const observations: FHIRObservation[] = [];\n const skipped: SkippedEntry[] = [];\n\n for (let i = 0; i < bundle.entry.length; i++) {\n const entry = bundle.entry[i]!;\n if (!entry.resource) {\n skipped.push({ index: i, reason: 'Entry has no resource' });\n continue;\n }\n\n if (entry.resource.resourceType !== 'Observation') {\n // Non-observation resources are silently skipped (Patient, DiagnosticReport, etc.)\n continue;\n }\n\n if (observations.length >= MAX_OBSERVATIONS) {\n skipped.push({ index: i, reason: `Maximum of ${MAX_OBSERVATIONS} observations exceeded` });\n continue;\n }\n\n observations.push(entry.resource as FHIRObservation);\n }\n\n return { observations, skipped };\n}\n\n/**\n * Map a FHIR Observation to internal format using LOINC→biomarker code lookup\n */\nexport function mapFHIRObservationToInternal(\n observation: FHIRObservation,\n index: number,\n): { observation: ImportedObservation } | { skipped: SkippedEntry } {\n const loincCode = extractLoincCode(observation);\n\n if (!loincCode) {\n return {\n skipped: {\n index,\n reason: 'No LOINC code found in observation coding',\n resourceType: 'Observation',\n },\n };\n }\n\n const internalCode = loincToCode(loincCode);\n if (!internalCode) {\n return {\n skipped: {\n index,\n loincCode,\n reason: `Unknown LOINC code: ${loincCode}`,\n resourceType: 'Observation',\n },\n };\n }\n\n const definition = getDefinitionByLoinc(loincCode);\n\n // Extract value\n let value: number | string;\n let unit = '';\n let isQualitative = false;\n\n if (observation.valueQuantity?.value !== undefined) {\n value = observation.valueQuantity.value;\n unit = observation.valueQuantity.unit || observation.valueQuantity.code || '';\n } else if (observation.valueString) {\n value = observation.valueString;\n isQualitative = true;\n } else {\n return {\n skipped: {\n index,\n loincCode,\n reason: 'Observation has no value (valueQuantity or valueString)',\n resourceType: 'Observation',\n },\n };\n }\n\n // Extract collection date (effectiveDateTime or effectivePeriod.start)\n const collectionDate = observation.effectiveDateTime || observation.effectivePeriod?.start || '';\n if (!collectionDate) {\n return {\n skipped: {\n index,\n loincCode,\n reason: 'Observation has no effectiveDateTime or effectivePeriod.start',\n resourceType: 'Observation',\n },\n };\n }\n\n // Extract reference ranges\n let referenceMin: number | undefined;\n let referenceMax: number | undefined;\n if (observation.referenceRange?.[0]) {\n referenceMin = observation.referenceRange[0].low?.value;\n referenceMax = observation.referenceRange[0].high?.value;\n }\n\n const imported: ImportedObservation = {\n biomarkerCode: internalCode,\n biomarkerName:\n definition?.names.pt[0] || definition?.names.en[0] || observation.code.text || internalCode,\n collectionDate,\n flag: extractFlag(observation),\n isQualitative,\n loincCode,\n referenceMax,\n referenceMin,\n unit: unit || definition?.unit || '',\n value,\n };\n\n return { observation: imported };\n}\n\n/**\n * Process a complete FHIR Bundle for import\n */\nexport function processImportBundle(data: unknown): FHIRImportResult {\n // Structural validation\n const validationErrors = validateFHIRImportBundle(data);\n if (validationErrors.length > 0) {\n return {\n errors: validationErrors,\n imported: [],\n skipped: [],\n totalProcessed: 0,\n };\n }\n\n const bundle = data as FHIRBundle;\n\n // Extract observations\n const { observations, skipped } = extractObservationsFromBundle(bundle);\n\n // Map each observation to internal format\n const imported: ImportedObservation[] = [];\n const allSkipped: SkippedEntry[] = [...skipped];\n\n for (let i = 0; i < observations.length; i++) {\n const result = mapFHIRObservationToInternal(observations[i]!, i);\n\n if ('observation' in result) {\n imported.push(result.observation);\n } else {\n allSkipped.push(result.skipped);\n }\n }\n\n return {\n errors: [],\n imported,\n skipped: allSkipped,\n totalProcessed: observations.length,\n };\n}\n\nexport { MAX_FILE_SIZE, MAX_OBSERVATIONS };\n"],"mappings":"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","names":[]}
@@ -0,0 +1,251 @@
1
+ import {
2
+ codeToLoinc
3
+ } from "./chunk-I6H35QXI.js";
4
+ import {
5
+ getDefaultUnit,
6
+ unitToUCUM
7
+ } from "./chunk-VPMT4MRS.js";
8
+
9
+ // src/converter.ts
10
+ function interpretationCode(flag) {
11
+ switch (flag) {
12
+ case "H":
13
+ return "H";
14
+ // High
15
+ case "L":
16
+ return "L";
17
+ // Low
18
+ default:
19
+ return "N";
20
+ }
21
+ }
22
+ function interpretationDisplay(flag) {
23
+ switch (flag) {
24
+ case "H":
25
+ return "High";
26
+ case "L":
27
+ return "Low";
28
+ default:
29
+ return "Normal";
30
+ }
31
+ }
32
+ function labObservationToFHIR(observation, patientId, laboratoryName) {
33
+ const loincCode = codeToLoinc(observation.biomarkerCode) || "99999-9";
34
+ const sourceUnit = observation.unit || getDefaultUnit(observation.biomarkerCode) || observation.unit;
35
+ const ucumUnit = unitToUCUM(sourceUnit);
36
+ const isQualitative = observation.isQualitative || typeof observation.value === "string";
37
+ const fhirObs = {
38
+ category: [
39
+ {
40
+ coding: [
41
+ {
42
+ code: "laboratory",
43
+ display: "Laboratory",
44
+ system: "http://terminology.hl7.org/CodeSystem/observation-category"
45
+ }
46
+ ]
47
+ }
48
+ ],
49
+ code: {
50
+ coding: [
51
+ {
52
+ code: loincCode,
53
+ display: observation.biomarkerName,
54
+ system: "http://loinc.org"
55
+ },
56
+ {
57
+ code: observation.biomarkerCode,
58
+ display: observation.biomarkerName,
59
+ system: "http://fhir-brasil.dev/biomarker-codes"
60
+ }
61
+ ],
62
+ text: observation.biomarkerName
63
+ },
64
+ effectiveDateTime: observation.collectionDate,
65
+ id: `${observation.reportId}-${observation.biomarkerCode}`,
66
+ interpretation: [
67
+ {
68
+ coding: [
69
+ {
70
+ code: interpretationCode(observation.flag),
71
+ display: interpretationDisplay(observation.flag),
72
+ system: "http://terminology.hl7.org/CodeSystem/v3-ObservationInterpretation"
73
+ }
74
+ ]
75
+ }
76
+ ],
77
+ performer: laboratoryName ? [{ display: laboratoryName }] : void 0,
78
+ resourceType: "Observation",
79
+ status: "final",
80
+ subject: {
81
+ reference: `Patient/${patientId}`
82
+ }
83
+ };
84
+ if (isQualitative) {
85
+ fhirObs.valueString = String(observation.value);
86
+ } else {
87
+ fhirObs.valueQuantity = {
88
+ code: ucumUnit,
89
+ system: "http://unitsofmeasure.org",
90
+ unit: sourceUnit,
91
+ value: observation.value
92
+ };
93
+ if (observation.referenceMin !== void 0 && observation.referenceMax !== void 0) {
94
+ fhirObs.referenceRange = [
95
+ {
96
+ high: {
97
+ code: ucumUnit,
98
+ system: "http://unitsofmeasure.org",
99
+ unit: sourceUnit,
100
+ value: observation.referenceMax
101
+ },
102
+ low: {
103
+ code: ucumUnit,
104
+ system: "http://unitsofmeasure.org",
105
+ unit: sourceUnit,
106
+ value: observation.referenceMin
107
+ }
108
+ }
109
+ ];
110
+ }
111
+ }
112
+ return fhirObs;
113
+ }
114
+ function labReportToFHIR(report, patientId, observationIds) {
115
+ let status;
116
+ switch (report.processingStatus) {
117
+ case "complete":
118
+ status = "final";
119
+ break;
120
+ case "partial":
121
+ status = "partial";
122
+ break;
123
+ case "pending_review":
124
+ status = "preliminary";
125
+ break;
126
+ default:
127
+ status = "final";
128
+ }
129
+ return {
130
+ category: [
131
+ {
132
+ coding: [
133
+ {
134
+ code: "LAB",
135
+ display: "Laboratory",
136
+ system: "http://terminology.hl7.org/CodeSystem/v2-0074"
137
+ }
138
+ ]
139
+ }
140
+ ],
141
+ code: {
142
+ coding: [
143
+ {
144
+ code: "11502-2",
145
+ // Laboratory report
146
+ display: "Laboratory report",
147
+ system: "http://loinc.org"
148
+ }
149
+ ],
150
+ text: "Laboratory Results"
151
+ },
152
+ conclusion: report.overallStatus === "NORMAL" ? "All results within normal limits" : "One or more abnormal results detected",
153
+ conclusionCode: report.overallStatus === "ANORMAL" ? [
154
+ {
155
+ coding: [
156
+ {
157
+ code: "A",
158
+ display: "Abnormal",
159
+ system: "http://terminology.hl7.org/CodeSystem/v3-ObservationInterpretation"
160
+ }
161
+ ]
162
+ }
163
+ ] : void 0,
164
+ effectiveDateTime: report.collectionDate,
165
+ id: report.reportId,
166
+ issued: report.createdAt,
167
+ performer: report.laboratoryName ? [{ display: report.laboratoryName }] : void 0,
168
+ resourceType: "DiagnosticReport",
169
+ result: observationIds.map((id) => ({ reference: `Observation/${id}` })),
170
+ status,
171
+ subject: {
172
+ reference: `Patient/${patientId}`
173
+ }
174
+ };
175
+ }
176
+ function userProfileToFHIR(profile) {
177
+ const nameParts = profile.name.split(" ");
178
+ const given = nameParts.slice(0, -1);
179
+ const family = nameParts[nameParts.length - 1] || "";
180
+ return {
181
+ address: profile.address ? [
182
+ {
183
+ city: profile.address.city,
184
+ country: profile.address.country || "BR",
185
+ line: [
186
+ profile.address.street && profile.address.number ? `${profile.address.street}, ${profile.address.number}` : profile.address.street,
187
+ profile.address.complement
188
+ ].filter(Boolean),
189
+ postalCode: profile.address.postalCode,
190
+ state: profile.address.state
191
+ }
192
+ ] : void 0,
193
+ birthDate: profile.birthDate,
194
+ gender: profile.gender,
195
+ id: profile.userId,
196
+ name: [
197
+ {
198
+ family,
199
+ given: given.length > 0 ? given : void 0,
200
+ text: profile.name
201
+ }
202
+ ],
203
+ resourceType: "Patient",
204
+ telecom: [
205
+ ...profile.email ? [{ system: "email", value: profile.email }] : [],
206
+ ...profile.phone ? [{ system: "phone", value: profile.phone }] : []
207
+ ].length > 0 ? [
208
+ ...profile.email ? [{ system: "email", value: profile.email }] : [],
209
+ ...profile.phone ? [{ system: "phone", value: profile.phone }] : []
210
+ ] : void 0
211
+ };
212
+ }
213
+ function labResultToFHIRBundle(report, observations, userProfile) {
214
+ const patientId = userProfile.userId;
215
+ const fhirObservations = observations.map((obs) => ({
216
+ fullUrl: `urn:uuid:observation-${obs.reportId}-${obs.biomarkerCode}`,
217
+ resource: labObservationToFHIR(
218
+ { ...obs, collectionDate: report.collectionDate },
219
+ patientId,
220
+ report.laboratoryName
221
+ )
222
+ }));
223
+ const observationIds = observations.map(
224
+ (obs) => `observation-${obs.reportId}-${obs.biomarkerCode}`
225
+ );
226
+ const diagnosticReport = labReportToFHIR(report, patientId, observationIds);
227
+ const fhirPatient = userProfileToFHIR(userProfile);
228
+ return {
229
+ entry: [
230
+ {
231
+ fullUrl: `urn:uuid:${patientId}`,
232
+ resource: fhirPatient
233
+ },
234
+ {
235
+ fullUrl: `urn:uuid:diagnostic-report-${report.reportId}`,
236
+ resource: diagnosticReport
237
+ },
238
+ ...fhirObservations
239
+ ],
240
+ resourceType: "Bundle",
241
+ type: "collection"
242
+ };
243
+ }
244
+
245
+ export {
246
+ labObservationToFHIR,
247
+ labReportToFHIR,
248
+ userProfileToFHIR,
249
+ labResultToFHIRBundle
250
+ };
251
+ //# sourceMappingURL=chunk-UIDSSWBJ.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/converter.ts"],"sourcesContent":["/**\n * FHIR Converter\n *\n * Converts lab results to FHIR R4 DiagnosticReport and Observation resources.\n * See: https://hl7.org/fhir/diagnosticreport.html\n */\n\nimport { codeToLoinc } from './biomarkers';\nimport type { FHIRBundle, FHIRDiagnosticReport, FHIRObservation, FHIRPatient } from './fhir-types';\nimport { getDefaultUnit, unitToUCUM } from './units';\nimport type { Flag, LabObservationData, LabReportData, UserProfileData } from './types';\n\n// Re-export all types and functions\nexport * from './fhir-types';\n\n/**\n * Convert Flag to FHIR interpretation code\n */\nfunction interpretationCode(flag: Flag): string {\n switch (flag) {\n case 'H':\n return 'H'; // High\n case 'L':\n return 'L'; // Low\n default:\n return 'N'; // Normal\n }\n}\n\n/**\n * Convert Flag to FHIR interpretation display\n */\nfunction interpretationDisplay(flag: Flag): string {\n switch (flag) {\n case 'H':\n return 'High';\n case 'L':\n return 'Low';\n default:\n return 'Normal';\n }\n}\n\n/**\n * Convert generic lab observation to FHIR Observation\n */\nexport function labObservationToFHIR(\n observation: LabObservationData,\n patientId: string,\n laboratoryName?: string,\n): FHIRObservation {\n const loincCode = codeToLoinc(observation.biomarkerCode) || '99999-9';\n // Use default unit if source unit is empty\n const sourceUnit =\n observation.unit || getDefaultUnit(observation.biomarkerCode) || observation.unit;\n const ucumUnit = unitToUCUM(sourceUnit);\n const isQualitative = observation.isQualitative || typeof observation.value === 'string';\n\n // Base observation structure\n const fhirObs: FHIRObservation = {\n category: [\n {\n coding: [\n {\n code: 'laboratory',\n display: 'Laboratory',\n system: 'http://terminology.hl7.org/CodeSystem/observation-category',\n },\n ],\n },\n ],\n code: {\n coding: [\n {\n code: loincCode,\n display: observation.biomarkerName,\n system: 'http://loinc.org',\n },\n {\n code: observation.biomarkerCode,\n display: observation.biomarkerName,\n system: 'http://fhir-brasil.dev/biomarker-codes',\n },\n ],\n text: observation.biomarkerName,\n },\n effectiveDateTime: observation.collectionDate,\n id: `${observation.reportId}-${observation.biomarkerCode}`,\n interpretation: [\n {\n coding: [\n {\n code: interpretationCode(observation.flag),\n display: interpretationDisplay(observation.flag),\n system: 'http://terminology.hl7.org/CodeSystem/v3-ObservationInterpretation',\n },\n ],\n },\n ],\n performer: laboratoryName ? [{ display: laboratoryName }] : undefined,\n resourceType: 'Observation',\n status: 'final',\n subject: {\n reference: `Patient/${patientId}`,\n },\n };\n\n // Add value based on type (qualitative = string, quantitative = number)\n if (isQualitative) {\n fhirObs.valueString = String(observation.value);\n } else {\n fhirObs.valueQuantity = {\n code: ucumUnit,\n system: 'http://unitsofmeasure.org',\n unit: sourceUnit,\n value: observation.value as number,\n };\n\n // Reference range only applies to quantitative values\n if (observation.referenceMin !== undefined && observation.referenceMax !== undefined) {\n fhirObs.referenceRange = [\n {\n high: {\n code: ucumUnit,\n system: 'http://unitsofmeasure.org',\n unit: sourceUnit,\n value: observation.referenceMax,\n },\n low: {\n code: ucumUnit,\n system: 'http://unitsofmeasure.org',\n unit: sourceUnit,\n value: observation.referenceMin,\n },\n },\n ];\n }\n }\n\n return fhirObs;\n}\n\n/**\n * Convert generic lab report to FHIR DiagnosticReport\n */\nexport function labReportToFHIR(\n report: LabReportData,\n patientId: string,\n observationIds: string[],\n): FHIRDiagnosticReport {\n // Map processing status to FHIR status\n let status: FHIRDiagnosticReport['status'];\n switch (report.processingStatus) {\n case 'complete':\n status = 'final';\n break;\n case 'partial':\n status = 'partial';\n break;\n case 'pending_review':\n status = 'preliminary';\n break;\n default:\n status = 'final';\n }\n\n return {\n category: [\n {\n coding: [\n {\n code: 'LAB',\n display: 'Laboratory',\n system: 'http://terminology.hl7.org/CodeSystem/v2-0074',\n },\n ],\n },\n ],\n code: {\n coding: [\n {\n code: '11502-2', // Laboratory report\n display: 'Laboratory report',\n system: 'http://loinc.org',\n },\n ],\n text: 'Laboratory Results',\n },\n conclusion:\n report.overallStatus === 'NORMAL'\n ? 'All results within normal limits'\n : 'One or more abnormal results detected',\n conclusionCode:\n report.overallStatus === 'ANORMAL'\n ? [\n {\n coding: [\n {\n code: 'A',\n display: 'Abnormal',\n system: 'http://terminology.hl7.org/CodeSystem/v3-ObservationInterpretation',\n },\n ],\n },\n ]\n : undefined,\n effectiveDateTime: report.collectionDate,\n id: report.reportId,\n issued: report.createdAt,\n performer: report.laboratoryName ? [{ display: report.laboratoryName }] : undefined,\n resourceType: 'DiagnosticReport',\n result: observationIds.map((id) => ({ reference: `Observation/${id}` })),\n status,\n subject: {\n reference: `Patient/${patientId}`,\n },\n };\n}\n\n/**\n * Convert user profile to FHIR Patient\n * NOTE: CPF is intentionally excluded for privacy (LGPD compliance)\n */\nexport function userProfileToFHIR(profile: UserProfileData): FHIRPatient {\n const nameParts = profile.name.split(' ');\n const given = nameParts.slice(0, -1);\n const family = nameParts[nameParts.length - 1] || '';\n\n return {\n address: profile.address\n ? [\n {\n city: profile.address.city,\n country: profile.address.country || 'BR',\n line: [\n profile.address.street && profile.address.number\n ? `${profile.address.street}, ${profile.address.number}`\n : profile.address.street,\n profile.address.complement,\n ].filter(Boolean) as string[],\n postalCode: profile.address.postalCode,\n state: profile.address.state,\n },\n ]\n : undefined,\n birthDate: profile.birthDate,\n gender: profile.gender,\n id: profile.userId,\n name: [\n {\n family,\n given: given.length > 0 ? given : undefined,\n text: profile.name,\n },\n ],\n resourceType: 'Patient',\n telecom:\n [\n ...(profile.email ? [{ system: 'email' as const, value: profile.email }] : []),\n ...(profile.phone ? [{ system: 'phone' as const, value: profile.phone }] : []),\n ].length > 0\n ? [\n ...(profile.email ? [{ system: 'email' as const, value: profile.email }] : []),\n ...(profile.phone ? [{ system: 'phone' as const, value: profile.phone }] : []),\n ]\n : undefined,\n };\n}\n\n/**\n * Convert complete lab result to FHIR Bundle\n * This is the main function for exporting lab results to FHIR R4 format\n */\nexport function labResultToFHIRBundle(\n report: LabReportData,\n observations: LabObservationData[],\n userProfile: UserProfileData,\n): FHIRBundle {\n const patientId = userProfile.userId;\n\n // Convert observations\n const fhirObservations = observations.map((obs) => ({\n fullUrl: `urn:uuid:observation-${obs.reportId}-${obs.biomarkerCode}`,\n resource: labObservationToFHIR(\n { ...obs, collectionDate: report.collectionDate },\n patientId,\n report.laboratoryName,\n ),\n }));\n\n const observationIds = observations.map(\n (obs) => `observation-${obs.reportId}-${obs.biomarkerCode}`,\n );\n\n // Convert report\n const diagnosticReport = labReportToFHIR(report, patientId, observationIds);\n\n // Convert patient\n const fhirPatient = userProfileToFHIR(userProfile);\n\n return {\n entry: [\n {\n fullUrl: `urn:uuid:${patientId}`,\n resource: fhirPatient,\n },\n {\n fullUrl: `urn:uuid:diagnostic-report-${report.reportId}`,\n resource: diagnosticReport,\n },\n ...fhirObservations,\n ],\n resourceType: 'Bundle',\n type: 'collection',\n };\n}\n"],"mappings":"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","names":[]}