fhir-data-utils-ts 0.4.0 → 0.6.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/.codex/skills/govern-fhir-data-utilities/SKILL.md +35 -0
- package/CHANGELOG.md +52 -0
- package/README.md +35 -0
- package/dist/appointment-communication-test-data.d.ts +63 -0
- package/dist/appointment-communication-test-data.js +77 -0
- package/dist/builders/department-service-graph.d.ts +32 -0
- package/dist/builders/department-service-graph.js +102 -0
- package/dist/builders/device-compliance-graph.d.ts +51 -0
- package/dist/builders/device-compliance-graph.js +115 -0
- package/dist/builders/index.d.ts +3 -0
- package/dist/builders/index.js +3 -0
- package/dist/builders/service-schedule-graph.d.ts +58 -0
- package/dist/builders/service-schedule-graph.js +149 -0
- package/dist/claims/appointment-claims.d.ts +6 -0
- package/dist/claims/appointment-claims.js +6 -0
- package/dist/claims/device-metric-claims.d.ts +16 -0
- package/dist/claims/device-metric-claims.js +25 -0
- package/dist/claims/healthcare-service-claims.d.ts +32 -0
- package/dist/claims/healthcare-service-claims.js +54 -0
- package/dist/claims/index.d.ts +4 -0
- package/dist/claims/index.js +4 -0
- package/dist/claims/location-claims.d.ts +3 -0
- package/dist/claims/location-claims.js +6 -0
- package/dist/claims/organization-claims.d.ts +3 -1
- package/dist/claims/organization-claims.js +4 -1
- package/dist/claims/procedure-claims.d.ts +2 -0
- package/dist/claims/procedure-claims.js +4 -0
- package/dist/claims/regulated-authorization-claims.d.ts +17 -0
- package/dist/claims/regulated-authorization-claims.js +27 -0
- package/dist/claims/schedule-slot-claims.d.ts +45 -0
- package/dist/claims/schedule-slot-claims.js +70 -0
- package/dist/constants/fhir-resource-types.d.ts +9 -0
- package/dist/constants/fhir-resource-types.js +3 -0
- package/dist/converters/convert-appointment-communication.d.ts +14 -0
- package/dist/converters/convert-appointment-communication.js +97 -0
- package/dist/converters/convert-appointment.js +16 -7
- package/dist/converters/convert-device-metric.d.ts +3 -0
- package/dist/converters/convert-device-metric.js +37 -0
- package/dist/converters/convert-document-reference.js +5 -0
- package/dist/converters/convert-healthcare-service.d.ts +7 -0
- package/dist/converters/convert-healthcare-service.js +60 -0
- package/dist/converters/convert-location.d.ts +4 -0
- package/dist/converters/convert-location.js +41 -3
- package/dist/converters/convert-organization.d.ts +2 -0
- package/dist/converters/convert-organization.js +20 -3
- package/dist/converters/convert-procedure.d.ts +2 -0
- package/dist/converters/convert-procedure.js +21 -0
- package/dist/converters/convert-regulated-authorization.d.ts +3 -0
- package/dist/converters/convert-regulated-authorization.js +34 -0
- package/dist/converters/convert-schedule-slot.d.ts +9 -0
- package/dist/converters/convert-schedule-slot.js +96 -0
- package/dist/converters/convert-shared.d.ts +10 -0
- package/dist/converters/convert-shared.js +19 -0
- package/dist/converters/index.d.ts +6 -0
- package/dist/converters/index.js +6 -0
- package/dist/converters/materialize-claims-first-resource.d.ts +16 -0
- package/dist/converters/materialize-claims-first-resource.js +61 -0
- package/dist/fhir-bundle.d.ts +21 -0
- package/dist/fhir-bundle.js +74 -0
- package/dist/group-r5.d.ts +12 -0
- package/dist/group-r5.js +20 -0
- package/dist/healthcare-service-specialty-map.d.ts +32 -0
- package/dist/healthcare-service-specialty-map.js +151 -0
- package/dist/index.d.ts +2 -0
- package/dist/index.js +2 -0
- package/docs/CLINICAL_TYPED_ACCESSOR_BOUNDARY.md +44 -0
- package/docs/COMMUNICATION_BUNDLE_CONTRACT.md +61 -0
- package/docs/HEALTHCARE_SERVICE_DEPARTMENT_CATALOG.md +190 -0
- package/docs/UHC_FHIR_UTILS_MIGRATION.md +20 -1
- package/package.json +5 -1
|
@@ -0,0 +1,70 @@
|
|
|
1
|
+
// Copyright 2026 Conéctate Soluciones y Aplicaciones SL under the Apache License, Version 2.0.
|
|
2
|
+
import { defineFlatSearchParameter } from '../search-parameters.js';
|
|
3
|
+
/** Canonical flat claims for the official FHIR R5 Schedule search surface. */
|
|
4
|
+
export const ScheduleClaim = Object.freeze({
|
|
5
|
+
Active: 'Schedule.active',
|
|
6
|
+
Actor: 'Schedule.actor',
|
|
7
|
+
Date: 'Schedule.date',
|
|
8
|
+
Identifier: 'Schedule.identifier',
|
|
9
|
+
Name: 'Schedule.name',
|
|
10
|
+
ServiceCategory: 'Schedule.service-category',
|
|
11
|
+
ServiceType: 'Schedule.service-type',
|
|
12
|
+
ServiceTypeReference: 'Schedule.service-type-reference',
|
|
13
|
+
Specialty: 'Schedule.specialty',
|
|
14
|
+
PlanningHorizonStart: 'Schedule.planning-horizon-start',
|
|
15
|
+
PlanningHorizonEnd: 'Schedule.planning-horizon-end',
|
|
16
|
+
Comment: 'Schedule.comment',
|
|
17
|
+
});
|
|
18
|
+
/** Canonical flat claims for the official FHIR R5 Slot search surface. */
|
|
19
|
+
export const SlotClaim = Object.freeze({
|
|
20
|
+
AppointmentType: 'Slot.appointment-type',
|
|
21
|
+
Identifier: 'Slot.identifier',
|
|
22
|
+
Schedule: 'Slot.schedule',
|
|
23
|
+
ServiceCategory: 'Slot.service-category',
|
|
24
|
+
ServiceType: 'Slot.service-type',
|
|
25
|
+
ServiceTypeReference: 'Slot.service-type-reference',
|
|
26
|
+
Specialty: 'Slot.specialty',
|
|
27
|
+
Start: 'Slot.start',
|
|
28
|
+
Status: 'Slot.status',
|
|
29
|
+
End: 'Slot.end',
|
|
30
|
+
Overbooked: 'Slot.overbooked',
|
|
31
|
+
Comment: 'Slot.comment',
|
|
32
|
+
});
|
|
33
|
+
export const ScheduleR5SearchParameterCatalog = Object.freeze([
|
|
34
|
+
defineFlatSearchParameter({ claim: ScheduleClaim.Active, resourceType: 'Schedule', elementPath: 'Schedule.active', type: 'token' }),
|
|
35
|
+
defineFlatSearchParameter({ claim: ScheduleClaim.Actor, resourceType: 'Schedule', elementPath: 'Schedule.actor', type: 'reference' }),
|
|
36
|
+
defineFlatSearchParameter({ claim: ScheduleClaim.Date, resourceType: 'Schedule', elementPath: 'Schedule.planningHorizon', type: 'date' }),
|
|
37
|
+
defineFlatSearchParameter({ claim: ScheduleClaim.Identifier, resourceType: 'Schedule', elementPath: 'Schedule.identifier', type: 'token' }),
|
|
38
|
+
defineFlatSearchParameter({ claim: ScheduleClaim.Name, resourceType: 'Schedule', elementPath: 'Schedule.name', type: 'string' }),
|
|
39
|
+
defineFlatSearchParameter({ claim: ScheduleClaim.ServiceCategory, resourceType: 'Schedule', elementPath: 'Schedule.serviceCategory', type: 'token' }),
|
|
40
|
+
defineFlatSearchParameter({ claim: ScheduleClaim.ServiceType, resourceType: 'Schedule', elementPath: 'Schedule.serviceType.concept', type: 'token' }),
|
|
41
|
+
defineFlatSearchParameter({ claim: ScheduleClaim.ServiceTypeReference, resourceType: 'Schedule', elementPath: 'Schedule.serviceType.reference', type: 'reference' }),
|
|
42
|
+
defineFlatSearchParameter({ claim: ScheduleClaim.Specialty, resourceType: 'Schedule', elementPath: 'Schedule.specialty', type: 'token' }),
|
|
43
|
+
]);
|
|
44
|
+
export const SlotR5SearchParameterCatalog = Object.freeze([
|
|
45
|
+
defineFlatSearchParameter({ claim: SlotClaim.AppointmentType, resourceType: 'Slot', elementPath: 'Slot.appointmentType', type: 'token' }),
|
|
46
|
+
defineFlatSearchParameter({ claim: SlotClaim.Identifier, resourceType: 'Slot', elementPath: 'Slot.identifier', type: 'token' }),
|
|
47
|
+
defineFlatSearchParameter({ claim: SlotClaim.Schedule, resourceType: 'Slot', elementPath: 'Slot.schedule', type: 'reference' }),
|
|
48
|
+
defineFlatSearchParameter({ claim: SlotClaim.ServiceCategory, resourceType: 'Slot', elementPath: 'Slot.serviceCategory', type: 'token' }),
|
|
49
|
+
defineFlatSearchParameter({ claim: SlotClaim.ServiceType, resourceType: 'Slot', elementPath: 'Slot.serviceType.concept', type: 'token' }),
|
|
50
|
+
defineFlatSearchParameter({ claim: SlotClaim.ServiceTypeReference, resourceType: 'Slot', elementPath: 'Slot.serviceType.reference', type: 'reference' }),
|
|
51
|
+
defineFlatSearchParameter({ claim: SlotClaim.Specialty, resourceType: 'Slot', elementPath: 'Slot.specialty', type: 'token' }),
|
|
52
|
+
defineFlatSearchParameter({ claim: SlotClaim.Start, resourceType: 'Slot', elementPath: 'Slot.start', type: 'date' }),
|
|
53
|
+
defineFlatSearchParameter({ claim: SlotClaim.Status, resourceType: 'Slot', elementPath: 'Slot.status', type: 'token' }),
|
|
54
|
+
]);
|
|
55
|
+
export const ScheduleClaimSpecs = Object.freeze([
|
|
56
|
+
{ key: ScheduleClaim.Identifier, meaning: 'Logical schedule identifier.', example: 'urn:uuid:blood-donation-weekday' },
|
|
57
|
+
{ key: ScheduleClaim.Active, meaning: 'Whether this schedule is in active use.', example: 'true' },
|
|
58
|
+
{ key: ScheduleClaim.Actor, meaning: 'Repeatable independently schedulable actors as CSV references.', example: 'HealthcareService/blood-donation,Location/blood-donation-room' },
|
|
59
|
+
{ key: ScheduleClaim.ServiceType, meaning: 'Repeatable service-type concept tokens as CSV.', example: 'http://terminology.hl7.org/CodeSystem/service-type|117' },
|
|
60
|
+
{ key: ScheduleClaim.ServiceTypeReference, meaning: 'Repeatable HealthcareService references corresponding to service-type concepts.', example: 'HealthcareService/blood-donation' },
|
|
61
|
+
{ key: ScheduleClaim.PlanningHorizonStart, meaning: 'Start of the period covered by this schedule.', example: '2026-10-01' },
|
|
62
|
+
{ key: ScheduleClaim.PlanningHorizonEnd, meaning: 'End of the period covered by this schedule.', example: '2026-10-31' },
|
|
63
|
+
]);
|
|
64
|
+
export const SlotClaimSpecs = Object.freeze([
|
|
65
|
+
{ key: SlotClaim.Identifier, meaning: 'Logical slot identifier.', example: 'urn:uuid:blood-20261001-0900' },
|
|
66
|
+
{ key: SlotClaim.Schedule, meaning: 'The Schedule that owns this independent slot.', example: 'Schedule/blood-donation-weekday' },
|
|
67
|
+
{ key: SlotClaim.Status, meaning: 'FHIR Slot status.', example: 'free' },
|
|
68
|
+
{ key: SlotClaim.Start, meaning: 'Start instant.', example: '2026-10-01T09:00:00Z' },
|
|
69
|
+
{ key: SlotClaim.End, meaning: 'End instant; duration is derived from start and end.', example: '2026-10-01T09:15:00Z' },
|
|
70
|
+
]);
|
|
@@ -25,6 +25,7 @@ export declare const ResourceTypesFhirR4: Readonly<{
|
|
|
25
25
|
readonly Encounter: "Encounter";
|
|
26
26
|
readonly Flag: "Flag";
|
|
27
27
|
readonly Group: "Group";
|
|
28
|
+
readonly HealthcareService: "HealthcareService";
|
|
28
29
|
readonly ImagingStudy: "ImagingStudy";
|
|
29
30
|
readonly Immunization: "Immunization";
|
|
30
31
|
readonly ImmunizationRecommendation: "ImmunizationRecommendation";
|
|
@@ -47,7 +48,9 @@ export declare const ResourceTypesFhirR4: Readonly<{
|
|
|
47
48
|
readonly RelatedPerson: "RelatedPerson";
|
|
48
49
|
readonly ResearchStudy: "ResearchStudy";
|
|
49
50
|
readonly ResearchSubject: "ResearchSubject";
|
|
51
|
+
readonly Schedule: "Schedule";
|
|
50
52
|
readonly Specimen: "Specimen";
|
|
53
|
+
readonly Slot: "Slot";
|
|
51
54
|
readonly ServiceRequest: "ServiceRequest";
|
|
52
55
|
readonly Task: "Task";
|
|
53
56
|
readonly DetectedIssue: "DetectedIssue";
|
|
@@ -81,6 +84,7 @@ export declare const FhirResourceTypes: Readonly<{
|
|
|
81
84
|
readonly Encounter: "Encounter";
|
|
82
85
|
readonly Flag: "Flag";
|
|
83
86
|
readonly Group: "Group";
|
|
87
|
+
readonly HealthcareService: "HealthcareService";
|
|
84
88
|
readonly ImagingStudy: "ImagingStudy";
|
|
85
89
|
readonly Immunization: "Immunization";
|
|
86
90
|
readonly ImmunizationRecommendation: "ImmunizationRecommendation";
|
|
@@ -103,7 +107,9 @@ export declare const FhirResourceTypes: Readonly<{
|
|
|
103
107
|
readonly RelatedPerson: "RelatedPerson";
|
|
104
108
|
readonly ResearchStudy: "ResearchStudy";
|
|
105
109
|
readonly ResearchSubject: "ResearchSubject";
|
|
110
|
+
readonly Schedule: "Schedule";
|
|
106
111
|
readonly Specimen: "Specimen";
|
|
112
|
+
readonly Slot: "Slot";
|
|
107
113
|
readonly ServiceRequest: "ServiceRequest";
|
|
108
114
|
readonly Task: "Task";
|
|
109
115
|
readonly DetectedIssue: "DetectedIssue";
|
|
@@ -133,6 +139,7 @@ export declare const ResourceTypesFhirR5: Readonly<{
|
|
|
133
139
|
readonly Encounter: "Encounter";
|
|
134
140
|
readonly Flag: "Flag";
|
|
135
141
|
readonly Group: "Group";
|
|
142
|
+
readonly HealthcareService: "HealthcareService";
|
|
136
143
|
readonly ImagingStudy: "ImagingStudy";
|
|
137
144
|
readonly Immunization: "Immunization";
|
|
138
145
|
readonly ImmunizationRecommendation: "ImmunizationRecommendation";
|
|
@@ -155,7 +162,9 @@ export declare const ResourceTypesFhirR5: Readonly<{
|
|
|
155
162
|
readonly RelatedPerson: "RelatedPerson";
|
|
156
163
|
readonly ResearchStudy: "ResearchStudy";
|
|
157
164
|
readonly ResearchSubject: "ResearchSubject";
|
|
165
|
+
readonly Schedule: "Schedule";
|
|
158
166
|
readonly Specimen: "Specimen";
|
|
167
|
+
readonly Slot: "Slot";
|
|
159
168
|
readonly ServiceRequest: "ServiceRequest";
|
|
160
169
|
readonly Task: "Task";
|
|
161
170
|
readonly DetectedIssue: "DetectedIssue";
|
|
@@ -25,6 +25,7 @@ export const ResourceTypesFhirR4 = Object.freeze({
|
|
|
25
25
|
Encounter: 'Encounter',
|
|
26
26
|
Flag: 'Flag',
|
|
27
27
|
Group: 'Group',
|
|
28
|
+
HealthcareService: 'HealthcareService',
|
|
28
29
|
ImagingStudy: 'ImagingStudy',
|
|
29
30
|
Immunization: 'Immunization',
|
|
30
31
|
ImmunizationRecommendation: 'ImmunizationRecommendation',
|
|
@@ -47,7 +48,9 @@ export const ResourceTypesFhirR4 = Object.freeze({
|
|
|
47
48
|
RelatedPerson: 'RelatedPerson',
|
|
48
49
|
ResearchStudy: 'ResearchStudy',
|
|
49
50
|
ResearchSubject: 'ResearchSubject',
|
|
51
|
+
Schedule: 'Schedule',
|
|
50
52
|
Specimen: 'Specimen',
|
|
53
|
+
Slot: 'Slot',
|
|
51
54
|
ServiceRequest: 'ServiceRequest',
|
|
52
55
|
Task: 'Task',
|
|
53
56
|
DetectedIssue: 'DetectedIssue',
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
import { type FlatClaimResourceEntry } from '../flat-claim-resource-graph.js';
|
|
2
|
+
export type SupportedAppointmentFhirRelease = 'r4' | 'r5';
|
|
3
|
+
export type AppointmentCommunicationFlatGraph = Readonly<{
|
|
4
|
+
communications: readonly FlatClaimResourceEntry[];
|
|
5
|
+
appointments: readonly FlatClaimResourceEntry[];
|
|
6
|
+
documentReferences: readonly FlatClaimResourceEntry[];
|
|
7
|
+
entries: readonly FlatClaimResourceEntry[];
|
|
8
|
+
}>;
|
|
9
|
+
/**
|
|
10
|
+
* Projects a validated appointment exchange into independently persisted flat
|
|
11
|
+
* claim resources. Transport parsing is delegated to the shared Bundle Reader;
|
|
12
|
+
* native FHIR remains an adapter input and is never persisted beside claims.
|
|
13
|
+
*/
|
|
14
|
+
export declare function projectAppointmentCommunicationBatchToFlatGraph(input: unknown, release: SupportedAppointmentFhirRelease): AppointmentCommunicationFlatGraph;
|
|
@@ -0,0 +1,97 @@
|
|
|
1
|
+
import { AppointmentClaim } from '../claims/appointment-claims.js';
|
|
2
|
+
import { CommunicationClaim } from '../claims/communication-claims.js';
|
|
3
|
+
import { DocumentReferenceClaim } from '../claims/document-reference-claims.js';
|
|
4
|
+
import { readBundleResources, readCommunicationBundlePayloads } from '../fhir-bundle.js';
|
|
5
|
+
import { buildFlatClaimResourceEntry } from '../flat-claim-resource-graph.js';
|
|
6
|
+
import { appointmentFhirR4ToFlat } from './convert-appointment.js';
|
|
7
|
+
import { documentReferenceFhirR4ToFlat } from './convert-document-reference.js';
|
|
8
|
+
/**
|
|
9
|
+
* Projects a validated appointment exchange into independently persisted flat
|
|
10
|
+
* claim resources. Transport parsing is delegated to the shared Bundle Reader;
|
|
11
|
+
* native FHIR remains an adapter input and is never persisted beside claims.
|
|
12
|
+
*/
|
|
13
|
+
export function projectAppointmentCommunicationBatchToFlatGraph(input, release) {
|
|
14
|
+
if (release !== 'r4' && release !== 'r5')
|
|
15
|
+
throw new TypeError('fhir_release_unsupported');
|
|
16
|
+
const communications = [];
|
|
17
|
+
const appointments = [];
|
|
18
|
+
const documentReferences = [];
|
|
19
|
+
for (const { communication, attachment, bundle } of readCommunicationBundlePayloads(input)) {
|
|
20
|
+
const communicationId = resourceId(communication, 'communication_identifier_required');
|
|
21
|
+
communications.push(buildFlatClaimResourceEntry({
|
|
22
|
+
entryId: communicationId,
|
|
23
|
+
resourceType: 'Communication',
|
|
24
|
+
claims: compactClaims({
|
|
25
|
+
[CommunicationClaim.Identifier]: communicationId,
|
|
26
|
+
[CommunicationClaim.Status]: stringValue(communication.status),
|
|
27
|
+
[CommunicationClaim.Subject]: referenceValue(communication.subject),
|
|
28
|
+
[CommunicationClaim.Recipient]: referenceList(communication.recipient),
|
|
29
|
+
[CommunicationClaim.Sender]: referenceValue(communication.sender),
|
|
30
|
+
[CommunicationClaim.Sent]: stringValue(communication.sent),
|
|
31
|
+
[CommunicationClaim.ContentAttachmentType]: attachment.contentType,
|
|
32
|
+
[CommunicationClaim.ContentAttachmentData]: attachment.data,
|
|
33
|
+
[CommunicationClaim.ContentAttachmentTitle]: attachment.title,
|
|
34
|
+
}),
|
|
35
|
+
}));
|
|
36
|
+
for (const child of readBundleResources(bundle)) {
|
|
37
|
+
if (child.resourceType === 'Appointment') {
|
|
38
|
+
const entryId = resourceId(child, 'appointment_identifier_required');
|
|
39
|
+
const structural = appointmentFhirR4ToFlat(child);
|
|
40
|
+
appointments.push(buildFlatClaimResourceEntry({
|
|
41
|
+
entryId,
|
|
42
|
+
resourceType: 'Appointment',
|
|
43
|
+
claims: compactClaims({
|
|
44
|
+
...structural,
|
|
45
|
+
[AppointmentClaim.Identifier]: structural[AppointmentClaim.Identifier] || entryId,
|
|
46
|
+
}),
|
|
47
|
+
}));
|
|
48
|
+
}
|
|
49
|
+
else if (child.resourceType === 'DocumentReference') {
|
|
50
|
+
const entryId = resourceId(child, 'document_reference_identifier_required');
|
|
51
|
+
const structural = documentReferenceFhirR4ToFlat(child);
|
|
52
|
+
documentReferences.push(buildFlatClaimResourceEntry({
|
|
53
|
+
entryId,
|
|
54
|
+
resourceType: 'DocumentReference',
|
|
55
|
+
claims: compactClaims({
|
|
56
|
+
...structural,
|
|
57
|
+
[DocumentReferenceClaim.Identifier]: structural[DocumentReferenceClaim.Identifier] || entryId,
|
|
58
|
+
}),
|
|
59
|
+
}));
|
|
60
|
+
}
|
|
61
|
+
}
|
|
62
|
+
}
|
|
63
|
+
return Object.freeze({
|
|
64
|
+
communications: Object.freeze(communications),
|
|
65
|
+
appointments: Object.freeze(appointments),
|
|
66
|
+
documentReferences: Object.freeze(documentReferences),
|
|
67
|
+
entries: Object.freeze([...communications, ...appointments, ...documentReferences]),
|
|
68
|
+
});
|
|
69
|
+
}
|
|
70
|
+
function resourceId(resource, error) {
|
|
71
|
+
const identifier = Array.isArray(resource.identifier)
|
|
72
|
+
? resource.identifier.find(item => typeof item?.value === 'string')?.value
|
|
73
|
+
: undefined;
|
|
74
|
+
const value = String(resource.id || identifier || '').trim();
|
|
75
|
+
if (!value)
|
|
76
|
+
throw new TypeError(error);
|
|
77
|
+
return value;
|
|
78
|
+
}
|
|
79
|
+
function compactClaims(input) {
|
|
80
|
+
return Object.freeze(Object.fromEntries(Object.entries(input)
|
|
81
|
+
.filter((entry) => entry[1] !== undefined && entry[1] !== null && String(entry[1]).trim() !== '')
|
|
82
|
+
.map(([name, value]) => [name, String(value).trim()])));
|
|
83
|
+
}
|
|
84
|
+
function stringValue(value) {
|
|
85
|
+
return typeof value === 'string' && value.trim() ? value.trim() : undefined;
|
|
86
|
+
}
|
|
87
|
+
function referenceValue(value) {
|
|
88
|
+
if (!value || typeof value !== 'object' || Array.isArray(value))
|
|
89
|
+
return undefined;
|
|
90
|
+
return stringValue(value.reference);
|
|
91
|
+
}
|
|
92
|
+
function referenceList(value) {
|
|
93
|
+
if (!Array.isArray(value))
|
|
94
|
+
return undefined;
|
|
95
|
+
const references = value.map(referenceValue).filter((item) => Boolean(item));
|
|
96
|
+
return references.length ? [...new Set(references)].join(',') : undefined;
|
|
97
|
+
}
|
|
@@ -21,6 +21,8 @@ export function appointmentFlatToFhirR4(claims) {
|
|
|
21
21
|
note: claims[AppointmentClaim.NoteText] ? [{ text: claims[AppointmentClaim.NoteText] }] : undefined,
|
|
22
22
|
patientInstruction: claims[AppointmentClaim.PatientInstruction],
|
|
23
23
|
basedOn: claims[AppointmentClaim.BasedOn] ? claims[AppointmentClaim.BasedOn].split(',').map((reference) => ({ reference: reference.trim() })) : undefined,
|
|
24
|
+
slot: claims[AppointmentClaim.Slot] ? claims[AppointmentClaim.Slot].split(',').map((reference) => ({ reference: reference.trim() })) : undefined,
|
|
25
|
+
supportingInformation: claims[AppointmentClaim.SupportingInfo] ? claims[AppointmentClaim.SupportingInfo].split(',').map((reference) => ({ reference: reference.trim() })) : undefined,
|
|
24
26
|
participant: claims[AppointmentClaim.ParticipantActor]
|
|
25
27
|
? claims[AppointmentClaim.ParticipantActor].split(',').map((reference) => ({
|
|
26
28
|
actor: { reference: reference.trim() },
|
|
@@ -32,11 +34,17 @@ export function appointmentFlatToFhirR4(claims) {
|
|
|
32
34
|
}
|
|
33
35
|
export function appointmentFhirR4ToFlat(resource) {
|
|
34
36
|
const participant = Array.isArray(resource.participant) ? resource.participant[0] : undefined;
|
|
37
|
+
const actorReferences = Array.isArray(resource.participant)
|
|
38
|
+
? resource.participant
|
|
39
|
+
.map((item) => referenceToValue(item?.actor))
|
|
40
|
+
.filter((item) => Boolean(item))
|
|
41
|
+
: [];
|
|
42
|
+
const serviceType = resource.serviceType?.[0];
|
|
35
43
|
return {
|
|
36
44
|
[AppointmentClaim.Identifier]: resource.identifier?.[0]?.value,
|
|
37
45
|
[AppointmentClaim.Status]: resource.status,
|
|
38
46
|
[AppointmentClaim.ServiceCategory]: codingToValue(resource.serviceCategory?.[0]?.coding?.[0]),
|
|
39
|
-
[AppointmentClaim.ServiceType]: codingToValue(
|
|
47
|
+
[AppointmentClaim.ServiceType]: codingToValue(serviceType?.concept?.coding?.[0] ?? serviceType?.coding?.[0]),
|
|
40
48
|
[AppointmentClaim.Specialty]: codingToValue(resource.specialty?.[0]?.coding?.[0]),
|
|
41
49
|
[AppointmentClaim.AppointmentType]: codingToValue(resource.appointmentType?.coding?.[0]),
|
|
42
50
|
[AppointmentClaim.ReasonCode]: codingToValue(resource.reasonCode?.[0]?.coding?.[0]),
|
|
@@ -49,13 +57,14 @@ export function appointmentFhirR4ToFlat(resource) {
|
|
|
49
57
|
[AppointmentClaim.NoteText]: resource.note?.[0]?.text,
|
|
50
58
|
[AppointmentClaim.PatientInstruction]: resource.patientInstruction,
|
|
51
59
|
[AppointmentClaim.BasedOn]: referenceListToCsv(resource.basedOn),
|
|
52
|
-
[AppointmentClaim.ParticipantActor]:
|
|
53
|
-
? resource.participant
|
|
54
|
-
.map((item) => referenceToValue(item?.actor))
|
|
55
|
-
.filter((item) => Boolean(item))
|
|
56
|
-
.join(',')
|
|
57
|
-
: undefined,
|
|
60
|
+
[AppointmentClaim.ParticipantActor]: actorReferences.length ? actorReferences.join(',') : undefined,
|
|
58
61
|
[AppointmentClaim.ParticipantStatus]: participant?.status,
|
|
59
62
|
[AppointmentClaim.ParticipantType]: codingToValue(participant?.type?.[0]?.coding?.[0]),
|
|
63
|
+
[AppointmentClaim.Date]: resource.start,
|
|
64
|
+
[AppointmentClaim.Location]: actorReferences.filter(reference => reference.startsWith('Location/')).join(',') || undefined,
|
|
65
|
+
[AppointmentClaim.Patient]: actorReferences.filter(reference => reference.startsWith('Patient/')).join(',') || undefined,
|
|
66
|
+
[AppointmentClaim.Practitioner]: actorReferences.filter(reference => reference.startsWith('Practitioner/') || reference.startsWith('PractitionerRole/')).join(',') || undefined,
|
|
67
|
+
[AppointmentClaim.Slot]: referenceListToCsv(resource.slot),
|
|
68
|
+
[AppointmentClaim.SupportingInfo]: referenceListToCsv(resource.supportingInformation),
|
|
60
69
|
};
|
|
61
70
|
}
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
import { DeviceMetricClaim } from '../claims/device-metric-claims.js';
|
|
2
|
+
import { codingFromValue, codingToValue, referenceToValue } from './convert-shared.js';
|
|
3
|
+
export function deviceMetricFlatToFhirR5(claims) {
|
|
4
|
+
const calibration = claims[DeviceMetricClaim.CalibrationType]
|
|
5
|
+
|| claims[DeviceMetricClaim.CalibrationState]
|
|
6
|
+
|| claims[DeviceMetricClaim.CalibrationTime]
|
|
7
|
+
? [{
|
|
8
|
+
type: claims[DeviceMetricClaim.CalibrationType],
|
|
9
|
+
state: claims[DeviceMetricClaim.CalibrationState],
|
|
10
|
+
time: claims[DeviceMetricClaim.CalibrationTime],
|
|
11
|
+
}]
|
|
12
|
+
: undefined;
|
|
13
|
+
return {
|
|
14
|
+
resourceType: 'DeviceMetric',
|
|
15
|
+
identifier: claims[DeviceMetricClaim.Identifier] ? [{ value: claims[DeviceMetricClaim.Identifier] }] : undefined,
|
|
16
|
+
type: { coding: codingFromValue(claims[DeviceMetricClaim.Type]) },
|
|
17
|
+
unit: claims[DeviceMetricClaim.Unit] ? { coding: codingFromValue(claims[DeviceMetricClaim.Unit]) } : undefined,
|
|
18
|
+
device: claims[DeviceMetricClaim.Device] ? { reference: claims[DeviceMetricClaim.Device] } : undefined,
|
|
19
|
+
operationalStatus: claims[DeviceMetricClaim.OperationalStatus],
|
|
20
|
+
category: claims[DeviceMetricClaim.Category],
|
|
21
|
+
calibration,
|
|
22
|
+
};
|
|
23
|
+
}
|
|
24
|
+
export function deviceMetricFhirR5ToFlat(resource) {
|
|
25
|
+
const calibration = resource.calibration?.[0];
|
|
26
|
+
return {
|
|
27
|
+
[DeviceMetricClaim.Identifier]: resource.identifier?.[0]?.value,
|
|
28
|
+
[DeviceMetricClaim.Type]: codingToValue(resource.type?.coding?.[0]),
|
|
29
|
+
[DeviceMetricClaim.Unit]: codingToValue(resource.unit?.coding?.[0]),
|
|
30
|
+
[DeviceMetricClaim.Device]: referenceToValue(resource.device),
|
|
31
|
+
[DeviceMetricClaim.OperationalStatus]: resource.operationalStatus,
|
|
32
|
+
[DeviceMetricClaim.Category]: resource.category,
|
|
33
|
+
[DeviceMetricClaim.CalibrationType]: calibration?.type,
|
|
34
|
+
[DeviceMetricClaim.CalibrationState]: calibration?.state,
|
|
35
|
+
[DeviceMetricClaim.CalibrationTime]: calibration?.time,
|
|
36
|
+
};
|
|
37
|
+
}
|
|
@@ -25,6 +25,9 @@ export function documentReferenceFlatToFhirR4(claims) {
|
|
|
25
25
|
}
|
|
26
26
|
: undefined,
|
|
27
27
|
date: claims[DocumentReferenceClaim.Date],
|
|
28
|
+
context: claims[DocumentReferenceClaim.EventReference]
|
|
29
|
+
? { related: claims[DocumentReferenceClaim.EventReference].split(',').map((reference) => ({ reference: reference.trim() })) }
|
|
30
|
+
: undefined,
|
|
28
31
|
content: [{ attachment: {
|
|
29
32
|
contentType: claims[DocumentReferenceClaim.ContentType],
|
|
30
33
|
data: claims[DocumentReferenceClaim.ContentData],
|
|
@@ -45,6 +48,8 @@ export function documentReferenceFhirR4ToFlat(resource) {
|
|
|
45
48
|
[DocumentReferenceClaim.TypeText]: resource.type?.text,
|
|
46
49
|
[DocumentReferenceClaim.TypeDisplay]: resource.type?.coding?.[0]?.display,
|
|
47
50
|
[DocumentReferenceClaim.Date]: resource.date,
|
|
51
|
+
[DocumentReferenceClaim.EventReference]: resource.context
|
|
52
|
+
?.related?.map((related) => related.reference).filter((reference) => Boolean(reference)).join(',') || undefined,
|
|
48
53
|
[DocumentReferenceClaim.ContentType]: attachment?.contentType,
|
|
49
54
|
[DocumentReferenceClaim.ContentData]: attachment?.data,
|
|
50
55
|
[DocumentReferenceClaim.Location]: attachment?.url,
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
import type { FhirResource, FlatClaims } from './convert-shared.js';
|
|
2
|
+
/** Materializes canonical HealthcareService claims as native FHIR R4. */
|
|
3
|
+
export declare function healthcareServiceFlatToFhirR4(claims: FlatClaims): FhirResource;
|
|
4
|
+
/** Extracts only official R4 HealthcareService SearchParameters into flat claims. */
|
|
5
|
+
export declare function healthcareServiceFhirR4ToFlat(resource: FhirResource): FlatClaims;
|
|
6
|
+
/** Materializes canonical HealthcareService claims as native FHIR R5. */
|
|
7
|
+
export declare const healthcareServiceFlatToFhirR5: typeof healthcareServiceFlatToFhirR4;
|
|
@@ -0,0 +1,60 @@
|
|
|
1
|
+
// Copyright 2026 Conéctate Soluciones y Aplicaciones SL under the Apache License, Version 2.0.
|
|
2
|
+
import { HealthcareServiceClaim } from '../claims/healthcare-service-claims.js';
|
|
3
|
+
import { codingListFromCsv, codingListToCsv, identifierFromValue, identifierToValue, referenceListToCsv, referenceToValue, } from './convert-shared.js';
|
|
4
|
+
const conceptsFromCsv = (value) => {
|
|
5
|
+
const coding = codingListFromCsv(value);
|
|
6
|
+
return coding?.map(item => ({ coding: [item] }));
|
|
7
|
+
};
|
|
8
|
+
const conceptsToCsv = (value) => codingListToCsv((Array.isArray(value) ? value : [])
|
|
9
|
+
.flatMap(item => item && typeof item === 'object' && Array.isArray(item.coding)
|
|
10
|
+
? item.coding ?? []
|
|
11
|
+
: []));
|
|
12
|
+
const referencesFromCsv = (value) => {
|
|
13
|
+
const references = String(value || '').split(',').map(item => item.trim()).filter(Boolean);
|
|
14
|
+
return references.length ? references.map(reference => ({ reference })) : undefined;
|
|
15
|
+
};
|
|
16
|
+
/** Materializes canonical HealthcareService claims as native FHIR R4. */
|
|
17
|
+
export function healthcareServiceFlatToFhirR4(claims) {
|
|
18
|
+
return {
|
|
19
|
+
resourceType: 'HealthcareService',
|
|
20
|
+
identifier: claims[HealthcareServiceClaim.Identifier]
|
|
21
|
+
? [identifierFromValue(claims[HealthcareServiceClaim.Identifier])]
|
|
22
|
+
: undefined,
|
|
23
|
+
active: claims[HealthcareServiceClaim.Active] === undefined
|
|
24
|
+
? undefined
|
|
25
|
+
: claims[HealthcareServiceClaim.Active] === 'true',
|
|
26
|
+
providedBy: claims[HealthcareServiceClaim.Organization]
|
|
27
|
+
? { reference: claims[HealthcareServiceClaim.Organization] }
|
|
28
|
+
: undefined,
|
|
29
|
+
category: conceptsFromCsv(claims[HealthcareServiceClaim.ServiceCategory]),
|
|
30
|
+
type: conceptsFromCsv(claims[HealthcareServiceClaim.ServiceType]),
|
|
31
|
+
specialty: conceptsFromCsv(claims[HealthcareServiceClaim.Specialty]),
|
|
32
|
+
location: referencesFromCsv(claims[HealthcareServiceClaim.Location]),
|
|
33
|
+
name: claims[HealthcareServiceClaim.Name],
|
|
34
|
+
comment: claims[HealthcareServiceClaim.Comment],
|
|
35
|
+
coverageArea: referencesFromCsv(claims[HealthcareServiceClaim.CoverageArea]),
|
|
36
|
+
program: conceptsFromCsv(claims[HealthcareServiceClaim.Program]),
|
|
37
|
+
characteristic: conceptsFromCsv(claims[HealthcareServiceClaim.Characteristic]),
|
|
38
|
+
endpoint: referencesFromCsv(claims[HealthcareServiceClaim.Endpoint]),
|
|
39
|
+
};
|
|
40
|
+
}
|
|
41
|
+
/** Extracts only official R4 HealthcareService SearchParameters into flat claims. */
|
|
42
|
+
export function healthcareServiceFhirR4ToFlat(resource) {
|
|
43
|
+
return {
|
|
44
|
+
[HealthcareServiceClaim.Active]: resource.active === undefined ? undefined : String(resource.active),
|
|
45
|
+
[HealthcareServiceClaim.Characteristic]: conceptsToCsv(resource.characteristic),
|
|
46
|
+
[HealthcareServiceClaim.CoverageArea]: referenceListToCsv(resource.coverageArea),
|
|
47
|
+
[HealthcareServiceClaim.Endpoint]: referenceListToCsv(resource.endpoint),
|
|
48
|
+
[HealthcareServiceClaim.Identifier]: identifierToValue(resource.identifier?.[0]),
|
|
49
|
+
[HealthcareServiceClaim.Location]: referenceListToCsv(resource.location),
|
|
50
|
+
[HealthcareServiceClaim.Name]: resource.name,
|
|
51
|
+
[HealthcareServiceClaim.Comment]: resource.comment,
|
|
52
|
+
[HealthcareServiceClaim.Organization]: referenceToValue(resource.providedBy),
|
|
53
|
+
[HealthcareServiceClaim.Program]: conceptsToCsv(resource.program),
|
|
54
|
+
[HealthcareServiceClaim.ServiceCategory]: conceptsToCsv(resource.category),
|
|
55
|
+
[HealthcareServiceClaim.ServiceType]: conceptsToCsv(resource.type),
|
|
56
|
+
[HealthcareServiceClaim.Specialty]: conceptsToCsv(resource.specialty),
|
|
57
|
+
};
|
|
58
|
+
}
|
|
59
|
+
/** Materializes canonical HealthcareService claims as native FHIR R5. */
|
|
60
|
+
export const healthcareServiceFlatToFhirR5 = healthcareServiceFlatToFhirR4;
|
|
@@ -1,3 +1,7 @@
|
|
|
1
1
|
import type { FhirResource, FlatClaims } from './convert-shared.js';
|
|
2
2
|
export declare function locationFlatToFhirR4(claims: FlatClaims): FhirResource;
|
|
3
3
|
export declare function locationFhirR4ToFlat(resource: FhirResource): FlatClaims;
|
|
4
|
+
/** Materializes canonical Location claims as native FHIR R5 (`form`, not the removed R4 `physicalType`). */
|
|
5
|
+
export declare function locationFlatToFhirR5(claims: FlatClaims): FhirResource;
|
|
6
|
+
/** Extracts the version-neutral Location claims from native FHIR R5. */
|
|
7
|
+
export declare function locationFhirR5ToFlat(resource: FhirResource): FlatClaims;
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
// Copyright 2026 Conéctate Soluciones y Aplicaciones SL under the Apache License, Version 2.0.
|
|
2
2
|
// File: src/convert/convert-location.ts
|
|
3
3
|
import { LocationClaim } from '../claims/location-claims.js';
|
|
4
|
-
import { codingFromValue, codingToValue, referenceToValue } from './convert-shared.js';
|
|
4
|
+
import { codingFromValue, codingToValue, identifierFromValue, identifierToValue, referenceToValue } from './convert-shared.js';
|
|
5
5
|
function splitCsv(value) {
|
|
6
6
|
return String(value || '')
|
|
7
7
|
.split(',')
|
|
@@ -11,7 +11,7 @@ function splitCsv(value) {
|
|
|
11
11
|
export function locationFlatToFhirR4(claims) {
|
|
12
12
|
return {
|
|
13
13
|
resourceType: 'Location',
|
|
14
|
-
identifier: claims[LocationClaim.Identifier] ? [
|
|
14
|
+
identifier: claims[LocationClaim.Identifier] ? [identifierFromValue(claims[LocationClaim.Identifier])] : undefined,
|
|
15
15
|
status: claims[LocationClaim.Status],
|
|
16
16
|
name: claims[LocationClaim.Name],
|
|
17
17
|
description: claims[LocationClaim.Description],
|
|
@@ -22,6 +22,15 @@ export function locationFlatToFhirR4(claims) {
|
|
|
22
22
|
physicalType: claims[LocationClaim.PhysicalType] ? { coding: codingFromValue(claims[LocationClaim.PhysicalType]) } : undefined,
|
|
23
23
|
managingOrganization: claims[LocationClaim.ManagingOrganization] ? { reference: claims[LocationClaim.ManagingOrganization] } : undefined,
|
|
24
24
|
partOf: claims[LocationClaim.PartOf] ? { reference: claims[LocationClaim.PartOf] } : undefined,
|
|
25
|
+
position: claims[LocationClaim.PositionLongitude] !== undefined && claims[LocationClaim.PositionLatitude] !== undefined
|
|
26
|
+
? {
|
|
27
|
+
longitude: Number(claims[LocationClaim.PositionLongitude]),
|
|
28
|
+
latitude: Number(claims[LocationClaim.PositionLatitude]),
|
|
29
|
+
...(claims[LocationClaim.PositionAltitude] !== undefined
|
|
30
|
+
? { altitude: Number(claims[LocationClaim.PositionAltitude]) }
|
|
31
|
+
: {}),
|
|
32
|
+
}
|
|
33
|
+
: undefined,
|
|
25
34
|
};
|
|
26
35
|
}
|
|
27
36
|
export function locationFhirR4ToFlat(resource) {
|
|
@@ -29,7 +38,7 @@ export function locationFhirR4ToFlat(resource) {
|
|
|
29
38
|
?.map((item) => item?.value)
|
|
30
39
|
.filter((item) => Boolean(item));
|
|
31
40
|
return {
|
|
32
|
-
[LocationClaim.Identifier]: resource.identifier?.[0]
|
|
41
|
+
[LocationClaim.Identifier]: identifierToValue(resource.identifier?.[0]),
|
|
33
42
|
[LocationClaim.Status]: resource.status,
|
|
34
43
|
[LocationClaim.Name]: resource.name,
|
|
35
44
|
[LocationClaim.Description]: resource.description,
|
|
@@ -40,5 +49,34 @@ export function locationFhirR4ToFlat(resource) {
|
|
|
40
49
|
[LocationClaim.PhysicalType]: codingToValue(resource.physicalType?.coding?.[0]),
|
|
41
50
|
[LocationClaim.ManagingOrganization]: referenceToValue(resource.managingOrganization),
|
|
42
51
|
[LocationClaim.PartOf]: referenceToValue(resource.partOf),
|
|
52
|
+
[LocationClaim.PositionLongitude]: resource.position?.longitude?.toString(),
|
|
53
|
+
[LocationClaim.PositionLatitude]: resource.position?.latitude?.toString(),
|
|
54
|
+
[LocationClaim.PositionAltitude]: resource.position?.altitude?.toString(),
|
|
55
|
+
};
|
|
56
|
+
}
|
|
57
|
+
/** Materializes canonical Location claims as native FHIR R5 (`form`, not the removed R4 `physicalType`). */
|
|
58
|
+
export function locationFlatToFhirR5(claims) {
|
|
59
|
+
const r4 = locationFlatToFhirR4(claims);
|
|
60
|
+
const { physicalType: _physicalType, telecom: _telecom, ...common } = r4;
|
|
61
|
+
const telecom = _telecom;
|
|
62
|
+
return {
|
|
63
|
+
...common,
|
|
64
|
+
contact: telecom?.length ? [{ telecom }] : undefined,
|
|
65
|
+
form: claims[LocationClaim.PhysicalType]
|
|
66
|
+
? { coding: codingFromValue(claims[LocationClaim.PhysicalType]) }
|
|
67
|
+
: undefined,
|
|
68
|
+
};
|
|
69
|
+
}
|
|
70
|
+
/** Extracts the version-neutral Location claims from native FHIR R5. */
|
|
71
|
+
export function locationFhirR5ToFlat(resource) {
|
|
72
|
+
const flat = locationFhirR4ToFlat(resource);
|
|
73
|
+
const telecom = resource.contact
|
|
74
|
+
?.flatMap(contact => contact.telecom ?? [])
|
|
75
|
+
.map(point => point.value)
|
|
76
|
+
.filter((value) => Boolean(value));
|
|
77
|
+
return {
|
|
78
|
+
...flat,
|
|
79
|
+
[LocationClaim.Telecom]: telecom?.length ? telecom.join(',') : undefined,
|
|
80
|
+
[LocationClaim.PhysicalType]: codingToValue(resource.form?.coding?.[0]),
|
|
43
81
|
};
|
|
44
82
|
}
|
|
@@ -1,3 +1,5 @@
|
|
|
1
1
|
import type { FhirResource, FlatClaims } from './convert-shared.js';
|
|
2
2
|
export declare function organizationFlatToFhirR4(claims: FlatClaims): FhirResource;
|
|
3
3
|
export declare function organizationFhirR4ToFlat(resource: FhirResource): FlatClaims;
|
|
4
|
+
/** Materializes canonical Organization claims as native FHIR R5. */
|
|
5
|
+
export declare function organizationFlatToFhirR5(claims: FlatClaims): FhirResource;
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
// Copyright 2026 Conéctate Soluciones y Aplicaciones SL under the Apache License, Version 2.0.
|
|
2
2
|
// File: src/convert/convert-organization.ts
|
|
3
3
|
import { OrganizationClaim } from '../claims/organization-claims.js';
|
|
4
|
-
import { codingFromValue, codingToValue, referenceToValue } from './convert-shared.js';
|
|
4
|
+
import { codingFromValue, codingToValue, identifierFromValue, identifierToValue, referenceToValue } from './convert-shared.js';
|
|
5
5
|
function splitCsv(value) {
|
|
6
6
|
return String(value || '')
|
|
7
7
|
.split(',')
|
|
@@ -11,7 +11,7 @@ function splitCsv(value) {
|
|
|
11
11
|
export function organizationFlatToFhirR4(claims) {
|
|
12
12
|
return {
|
|
13
13
|
resourceType: 'Organization',
|
|
14
|
-
identifier: claims[OrganizationClaim.Identifier] ? [
|
|
14
|
+
identifier: claims[OrganizationClaim.Identifier] ? [identifierFromValue(claims[OrganizationClaim.Identifier])] : undefined,
|
|
15
15
|
active: claims[OrganizationClaim.Active] === undefined ? undefined : claims[OrganizationClaim.Active] === 'true',
|
|
16
16
|
type: claims[OrganizationClaim.Type] ? [{ coding: codingFromValue(claims[OrganizationClaim.Type]) }] : undefined,
|
|
17
17
|
name: claims[OrganizationClaim.Name],
|
|
@@ -27,7 +27,7 @@ export function organizationFhirR4ToFlat(resource) {
|
|
|
27
27
|
?.map((item) => item?.value)
|
|
28
28
|
.filter((item) => Boolean(item));
|
|
29
29
|
return {
|
|
30
|
-
[OrganizationClaim.Identifier]: resource.identifier?.[0]
|
|
30
|
+
[OrganizationClaim.Identifier]: identifierToValue(resource.identifier?.[0]),
|
|
31
31
|
[OrganizationClaim.Active]: resource.active === undefined ? undefined : String(resource.active),
|
|
32
32
|
[OrganizationClaim.Type]: codingToValue(resource.type?.[0]?.coding?.[0]),
|
|
33
33
|
[OrganizationClaim.Name]: resource.name,
|
|
@@ -37,3 +37,20 @@ export function organizationFhirR4ToFlat(resource) {
|
|
|
37
37
|
[OrganizationClaim.Address]: resource.address?.[0]?.text,
|
|
38
38
|
};
|
|
39
39
|
}
|
|
40
|
+
/** Materializes canonical Organization claims as native FHIR R5. */
|
|
41
|
+
export function organizationFlatToFhirR5(claims) {
|
|
42
|
+
const identifier = identifierFromValue(claims[OrganizationClaim.Identifier]);
|
|
43
|
+
const telecom = splitCsv(claims[OrganizationClaim.Telecom]).map((value) => ({ value }));
|
|
44
|
+
const address = claims[OrganizationClaim.Address] ? [{ text: claims[OrganizationClaim.Address] }] : [];
|
|
45
|
+
return {
|
|
46
|
+
resourceType: 'Organization',
|
|
47
|
+
identifier: identifier ? [identifier] : undefined,
|
|
48
|
+
active: claims[OrganizationClaim.Active] === undefined ? undefined : claims[OrganizationClaim.Active] === 'true',
|
|
49
|
+
type: claims[OrganizationClaim.Type] ? [{ coding: codingFromValue(claims[OrganizationClaim.Type]) }] : undefined,
|
|
50
|
+
name: claims[OrganizationClaim.Name],
|
|
51
|
+
alias: splitCsv(claims[OrganizationClaim.Alias]),
|
|
52
|
+
description: claims[OrganizationClaim.Description],
|
|
53
|
+
partOf: claims[OrganizationClaim.PartOf] ? { reference: claims[OrganizationClaim.PartOf] } : undefined,
|
|
54
|
+
contact: telecom.length || address.length ? [{ telecom, address }] : undefined,
|
|
55
|
+
};
|
|
56
|
+
}
|
|
@@ -1,3 +1,5 @@
|
|
|
1
1
|
import type { FhirResource, FlatClaims } from './convert-shared.js';
|
|
2
2
|
export declare function procedureFlatToFhirR4(claims: FlatClaims): FhirResource;
|
|
3
3
|
export declare function procedureFhirR4ToFlat(resource: FhirResource): FlatClaims;
|
|
4
|
+
/** Explicit FHIR R5 projection, including equipment calibration and inspection. */
|
|
5
|
+
export declare function procedureFlatToFhirR5(claims: FlatClaims): FhirResource;
|
|
@@ -62,3 +62,24 @@ export function procedureFhirR4ToFlat(resource) {
|
|
|
62
62
|
[ProcedureClaim.Note]: resource.note?.[0]?.text,
|
|
63
63
|
};
|
|
64
64
|
}
|
|
65
|
+
/** Explicit FHIR R5 projection, including equipment calibration and inspection. */
|
|
66
|
+
export function procedureFlatToFhirR5(claims) {
|
|
67
|
+
const resource = procedureFlatToFhirR4(claims);
|
|
68
|
+
const { performedDateTime, reasonCode, reasonReference, ...common } = resource;
|
|
69
|
+
return {
|
|
70
|
+
...common,
|
|
71
|
+
occurrenceDateTime: performedDateTime,
|
|
72
|
+
reason: reasonCode || reasonReference
|
|
73
|
+
? [
|
|
74
|
+
...(Array.isArray(reasonCode) ? reasonCode.map(concept => ({ concept })) : []),
|
|
75
|
+
...(Array.isArray(reasonReference) ? reasonReference.map(reference => ({ reference })) : []),
|
|
76
|
+
]
|
|
77
|
+
: undefined,
|
|
78
|
+
focalDevice: claims[ProcedureClaim.FocalDevice]
|
|
79
|
+
? claims[ProcedureClaim.FocalDevice].split(',').map(reference => ({ manipulated: { reference: reference.trim() } }))
|
|
80
|
+
: undefined,
|
|
81
|
+
report: claims[ProcedureClaim.Report]
|
|
82
|
+
? claims[ProcedureClaim.Report].split(',').map(reference => ({ reference: reference.trim() }))
|
|
83
|
+
: undefined,
|
|
84
|
+
};
|
|
85
|
+
}
|