fhir-data-utils-ts 0.6.0 → 0.6.1
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/CHANGELOG.md +9 -0
- package/dist/care-emergency-alert.d.ts +18 -0
- package/dist/care-emergency-alert.js +29 -1
- package/dist/claims/encounter-claims.d.ts +15 -0
- package/dist/claims/encounter-claims.js +19 -0
- package/dist/claims/encounter-history-claims.d.ts +20 -0
- package/dist/claims/encounter-history-claims.js +34 -0
- package/dist/claims/index.d.ts +1 -0
- package/dist/claims/index.js +1 -0
- package/dist/constants/fhir-resource-types.d.ts +1 -0
- package/dist/constants/fhir-resource-types.js +1 -0
- package/dist/converters/convert-encounter-history.d.ts +5 -0
- package/dist/converters/convert-encounter-history.js +83 -0
- package/dist/converters/convert-encounter.d.ts +4 -0
- package/dist/converters/convert-encounter.js +73 -1
- package/dist/converters/index.d.ts +1 -0
- package/dist/converters/index.js +1 -0
- package/dist/converters/materialize-claims-first-resource.d.ts +1 -1
- package/dist/converters/materialize-claims-first-resource.js +4 -0
- package/dist/encounter-transfer-test-data.d.ts +40 -0
- package/dist/encounter-transfer-test-data.js +37 -0
- package/dist/index.d.ts +1 -0
- package/dist/index.js +1 -0
- package/package.json +1 -1
package/CHANGELOG.md
CHANGED
|
@@ -2,6 +2,15 @@
|
|
|
2
2
|
|
|
3
3
|
## Unreleased
|
|
4
4
|
|
|
5
|
+
## 0.6.1 - 2026-09-30
|
|
6
|
+
|
|
7
|
+
- Add canonical flat claims, a claims-first builder and native R5 projection
|
|
8
|
+
for `EncounterHistory`, including explicit Encounter, HealthcareService,
|
|
9
|
+
subject, status, class, period and Location boundaries.
|
|
10
|
+
- Add the R5 Encounter lifecycle and projection without weakening the existing
|
|
11
|
+
R4 adapter; `on-hold`, `discharged` and `completed` are validated only at the
|
|
12
|
+
R5 boundary.
|
|
13
|
+
|
|
5
14
|
## 0.6.0 - 2026-09-29
|
|
6
15
|
|
|
7
16
|
- Add canonical two-level Communication Bundle validation tools recovered from
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { EncounterStatusR5 } from './claims/index.js';
|
|
1
2
|
import { type FlatClaimResourceEntry } from './flat-claim-resource-graph.js';
|
|
2
3
|
export type ClinicalCoding = Readonly<{
|
|
3
4
|
system: string;
|
|
@@ -14,6 +15,23 @@ export type EncounterJourneyNode = Readonly<{
|
|
|
14
15
|
locationReference: string;
|
|
15
16
|
type?: ClinicalCoding;
|
|
16
17
|
}>;
|
|
18
|
+
/** Builds one FHIR R5 EncounterHistory milestone from canonical flat claims. */
|
|
19
|
+
export declare function buildEncounterHistoryR5FlatEntry(input: Readonly<{
|
|
20
|
+
entryId: string;
|
|
21
|
+
identifier: string;
|
|
22
|
+
encounterReference: string;
|
|
23
|
+
status: EncounterStatusR5;
|
|
24
|
+
class: ClinicalCoding;
|
|
25
|
+
serviceReference?: string;
|
|
26
|
+
subjectReference?: string;
|
|
27
|
+
subjectStatus?: ClinicalCoding;
|
|
28
|
+
actualPeriodStart?: string;
|
|
29
|
+
actualPeriodEnd?: string;
|
|
30
|
+
plannedStartDate?: string;
|
|
31
|
+
plannedEndDate?: string;
|
|
32
|
+
locationReference?: string;
|
|
33
|
+
locationForm?: ClinicalCoding;
|
|
34
|
+
}>): FlatClaimResourceEntry;
|
|
17
35
|
/**
|
|
18
36
|
* Builds one actual-care Encounter graph from an originating Appointment.
|
|
19
37
|
* Child service/location encounters inherit subject and provider and reference
|
|
@@ -1,5 +1,33 @@
|
|
|
1
|
-
import { CommunicationRequestClaim, EncounterClaim, ServiceRequestClaim, TaskClaim, } from './claims/index.js';
|
|
1
|
+
import { CommunicationRequestClaim, EncounterClaim, EncounterHistoryClaim, ServiceRequestClaim, TaskClaim, } from './claims/index.js';
|
|
2
2
|
import { buildFlatClaimResourceEntry } from './flat-claim-resource-graph.js';
|
|
3
|
+
/** Builds one FHIR R5 EncounterHistory milestone from canonical flat claims. */
|
|
4
|
+
export function buildEncounterHistoryR5FlatEntry(input) {
|
|
5
|
+
const claims = {
|
|
6
|
+
[EncounterHistoryClaim.Identifier]: required(input.identifier, 'encounter_history_identifier_required'),
|
|
7
|
+
[EncounterHistoryClaim.Encounter]: reference(input.encounterReference, 'encounter_history_encounter_invalid'),
|
|
8
|
+
[EncounterHistoryClaim.Status]: input.status,
|
|
9
|
+
[EncounterHistoryClaim.Class]: coding(input.class, 'encounter_history_class_invalid'),
|
|
10
|
+
};
|
|
11
|
+
if (input.serviceReference)
|
|
12
|
+
claims[EncounterHistoryClaim.ServiceType] = reference(input.serviceReference, 'encounter_history_service_invalid');
|
|
13
|
+
if (input.subjectReference)
|
|
14
|
+
claims[EncounterHistoryClaim.Subject] = reference(input.subjectReference, 'encounter_history_subject_invalid');
|
|
15
|
+
if (input.subjectStatus)
|
|
16
|
+
claims[EncounterHistoryClaim.SubjectStatus] = coding(input.subjectStatus, 'encounter_history_subject_status_invalid');
|
|
17
|
+
if (input.actualPeriodStart)
|
|
18
|
+
claims[EncounterHistoryClaim.ActualPeriodStart] = dateTime(input.actualPeriodStart, 'encounter_history_actual_start_invalid');
|
|
19
|
+
if (input.actualPeriodEnd)
|
|
20
|
+
claims[EncounterHistoryClaim.ActualPeriodEnd] = dateTime(input.actualPeriodEnd, 'encounter_history_actual_end_invalid');
|
|
21
|
+
if (input.plannedStartDate)
|
|
22
|
+
claims[EncounterHistoryClaim.PlannedStartDate] = dateTime(input.plannedStartDate, 'encounter_history_planned_start_invalid');
|
|
23
|
+
if (input.plannedEndDate)
|
|
24
|
+
claims[EncounterHistoryClaim.PlannedEndDate] = dateTime(input.plannedEndDate, 'encounter_history_planned_end_invalid');
|
|
25
|
+
if (input.locationReference)
|
|
26
|
+
claims[EncounterHistoryClaim.Location] = reference(input.locationReference, 'encounter_history_location_invalid');
|
|
27
|
+
if (input.locationForm)
|
|
28
|
+
claims[EncounterHistoryClaim.LocationForm] = coding(input.locationForm, 'encounter_history_location_form_invalid');
|
|
29
|
+
return buildFlatClaimResourceEntry({ entryId: input.entryId, resourceType: 'EncounterHistory', claims });
|
|
30
|
+
}
|
|
3
31
|
/**
|
|
4
32
|
* Builds one actual-care Encounter graph from an originating Appointment.
|
|
5
33
|
* Child service/location encounters inherit subject and provider and reference
|
|
@@ -8,9 +8,12 @@ export declare const EncounterClaim: {
|
|
|
8
8
|
readonly Subject: "Encounter.subject";
|
|
9
9
|
readonly Patient: "Encounter.patient";
|
|
10
10
|
readonly Participant: "Encounter.participant";
|
|
11
|
+
readonly ServiceType: "Encounter.service-type";
|
|
11
12
|
readonly ServiceProvider: "Encounter.service-provider";
|
|
12
13
|
readonly PeriodStart: "Encounter.period-start";
|
|
13
14
|
readonly PeriodEnd: "Encounter.period-end";
|
|
15
|
+
readonly ActualPeriodStart: "Encounter.actual-period-start";
|
|
16
|
+
readonly ActualPeriodEnd: "Encounter.actual-period-end";
|
|
14
17
|
readonly ReasonCode: "Encounter.reason-code";
|
|
15
18
|
readonly Diagnosis: "Encounter.diagnosis";
|
|
16
19
|
readonly Location: "Encounter.location";
|
|
@@ -28,5 +31,17 @@ export declare enum EncounterStatus {
|
|
|
28
31
|
EnteredInError = "entered-in-error",
|
|
29
32
|
Unknown = "unknown"
|
|
30
33
|
}
|
|
34
|
+
/** Canonical FHIR R5 Encounter lifecycle codes. */
|
|
35
|
+
export declare enum EncounterStatusR5 {
|
|
36
|
+
Planned = "planned",
|
|
37
|
+
InProgress = "in-progress",
|
|
38
|
+
OnHold = "on-hold",
|
|
39
|
+
Discharged = "discharged",
|
|
40
|
+
Completed = "completed",
|
|
41
|
+
Cancelled = "cancelled",
|
|
42
|
+
Discontinued = "discontinued",
|
|
43
|
+
EnteredInError = "entered-in-error",
|
|
44
|
+
Unknown = "unknown"
|
|
45
|
+
}
|
|
31
46
|
export type EncounterClaimKey = typeof EncounterClaim[keyof typeof EncounterClaim];
|
|
32
47
|
export declare const EncounterClaimSpecs: ClaimSpec[];
|
|
@@ -9,9 +9,12 @@ export const EncounterClaim = {
|
|
|
9
9
|
Subject: 'Encounter.subject',
|
|
10
10
|
Patient: 'Encounter.patient',
|
|
11
11
|
Participant: 'Encounter.participant',
|
|
12
|
+
ServiceType: 'Encounter.service-type',
|
|
12
13
|
ServiceProvider: 'Encounter.service-provider',
|
|
13
14
|
PeriodStart: 'Encounter.period-start',
|
|
14
15
|
PeriodEnd: 'Encounter.period-end',
|
|
16
|
+
ActualPeriodStart: 'Encounter.actual-period-start',
|
|
17
|
+
ActualPeriodEnd: 'Encounter.actual-period-end',
|
|
15
18
|
ReasonCode: 'Encounter.reason-code',
|
|
16
19
|
Diagnosis: 'Encounter.diagnosis',
|
|
17
20
|
Location: 'Encounter.location',
|
|
@@ -30,6 +33,19 @@ export var EncounterStatus;
|
|
|
30
33
|
EncounterStatus["EnteredInError"] = "entered-in-error";
|
|
31
34
|
EncounterStatus["Unknown"] = "unknown";
|
|
32
35
|
})(EncounterStatus || (EncounterStatus = {}));
|
|
36
|
+
/** Canonical FHIR R5 Encounter lifecycle codes. */
|
|
37
|
+
export var EncounterStatusR5;
|
|
38
|
+
(function (EncounterStatusR5) {
|
|
39
|
+
EncounterStatusR5["Planned"] = "planned";
|
|
40
|
+
EncounterStatusR5["InProgress"] = "in-progress";
|
|
41
|
+
EncounterStatusR5["OnHold"] = "on-hold";
|
|
42
|
+
EncounterStatusR5["Discharged"] = "discharged";
|
|
43
|
+
EncounterStatusR5["Completed"] = "completed";
|
|
44
|
+
EncounterStatusR5["Cancelled"] = "cancelled";
|
|
45
|
+
EncounterStatusR5["Discontinued"] = "discontinued";
|
|
46
|
+
EncounterStatusR5["EnteredInError"] = "entered-in-error";
|
|
47
|
+
EncounterStatusR5["Unknown"] = "unknown";
|
|
48
|
+
})(EncounterStatusR5 || (EncounterStatusR5 = {}));
|
|
33
49
|
export const EncounterClaimSpecs = [
|
|
34
50
|
{ key: EncounterClaim.Identifier, meaning: 'Business identifier.', example: 'enc-001' },
|
|
35
51
|
{ key: EncounterClaim.Appointment, meaning: 'Originating appointment references (CSV).', example: 'Appointment/appointment-1' },
|
|
@@ -39,9 +55,12 @@ export const EncounterClaimSpecs = [
|
|
|
39
55
|
{ key: EncounterClaim.Subject, meaning: 'Canonical subject reference.', example: 'did:web:patient.example.org' },
|
|
40
56
|
{ key: EncounterClaim.Patient, meaning: 'Patient alias reference.', example: 'did:web:patient.example.org' },
|
|
41
57
|
{ key: EncounterClaim.Participant, meaning: 'Participant references (CSV).', example: 'Practitioner/prac-1' },
|
|
58
|
+
{ key: EncounterClaim.ServiceType, meaning: 'HealthcareService references (CSV in R5).', example: 'HealthcareService/emergency-department-1' },
|
|
42
59
|
{ key: EncounterClaim.ServiceProvider, meaning: 'Service provider reference.', example: 'Organization/org-1' },
|
|
43
60
|
{ key: EncounterClaim.PeriodStart, meaning: 'Encounter start.', example: '2026-06-01T10:00:00Z' },
|
|
44
61
|
{ key: EncounterClaim.PeriodEnd, meaning: 'Encounter end.', example: '2026-06-01T10:30:00Z' },
|
|
62
|
+
{ key: EncounterClaim.ActualPeriodStart, meaning: 'R5 actual encounter start.', example: '2026-06-01T10:00:00Z' },
|
|
63
|
+
{ key: EncounterClaim.ActualPeriodEnd, meaning: 'R5 actual encounter end.', example: '2026-06-01T10:30:00Z' },
|
|
45
64
|
{ key: EncounterClaim.ReasonCode, meaning: 'Reason code token.', example: 'http://snomed.info/sct|65363002' },
|
|
46
65
|
{ key: EncounterClaim.Diagnosis, meaning: 'Diagnosis references (CSV).', example: 'Condition/cond-1' },
|
|
47
66
|
{ key: EncounterClaim.Location, meaning: 'Location references (CSV).', example: 'Location/loc-1' },
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
import type { ClaimSpec } from './claim-types.js';
|
|
2
|
+
/** Canonical flat claims for the FHIR R5 EncounterHistory resource. */
|
|
3
|
+
export declare const EncounterHistoryClaim: {
|
|
4
|
+
readonly Identifier: "EncounterHistory.identifier";
|
|
5
|
+
readonly Encounter: "EncounterHistory.encounter";
|
|
6
|
+
readonly Status: "EncounterHistory.status";
|
|
7
|
+
readonly Class: "EncounterHistory.class";
|
|
8
|
+
readonly Type: "EncounterHistory.type";
|
|
9
|
+
readonly ServiceType: "EncounterHistory.service-type";
|
|
10
|
+
readonly Subject: "EncounterHistory.subject";
|
|
11
|
+
readonly SubjectStatus: "EncounterHistory.subject-status";
|
|
12
|
+
readonly ActualPeriodStart: "EncounterHistory.actual-period-start";
|
|
13
|
+
readonly ActualPeriodEnd: "EncounterHistory.actual-period-end";
|
|
14
|
+
readonly PlannedStartDate: "EncounterHistory.planned-start-date";
|
|
15
|
+
readonly PlannedEndDate: "EncounterHistory.planned-end-date";
|
|
16
|
+
readonly Location: "EncounterHistory.location";
|
|
17
|
+
readonly LocationForm: "EncounterHistory.location-form";
|
|
18
|
+
};
|
|
19
|
+
export type EncounterHistoryClaimKey = typeof EncounterHistoryClaim[keyof typeof EncounterHistoryClaim];
|
|
20
|
+
export declare const EncounterHistoryClaimSpecs: ClaimSpec[];
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
// Copyright 2026 Conéctate Soluciones y Aplicaciones SL under the Apache License, Version 2.0.
|
|
2
|
+
/** Canonical flat claims for the FHIR R5 EncounterHistory resource. */
|
|
3
|
+
export const EncounterHistoryClaim = {
|
|
4
|
+
Identifier: 'EncounterHistory.identifier',
|
|
5
|
+
Encounter: 'EncounterHistory.encounter',
|
|
6
|
+
Status: 'EncounterHistory.status',
|
|
7
|
+
Class: 'EncounterHistory.class',
|
|
8
|
+
Type: 'EncounterHistory.type',
|
|
9
|
+
ServiceType: 'EncounterHistory.service-type',
|
|
10
|
+
Subject: 'EncounterHistory.subject',
|
|
11
|
+
SubjectStatus: 'EncounterHistory.subject-status',
|
|
12
|
+
ActualPeriodStart: 'EncounterHistory.actual-period-start',
|
|
13
|
+
ActualPeriodEnd: 'EncounterHistory.actual-period-end',
|
|
14
|
+
PlannedStartDate: 'EncounterHistory.planned-start-date',
|
|
15
|
+
PlannedEndDate: 'EncounterHistory.planned-end-date',
|
|
16
|
+
Location: 'EncounterHistory.location',
|
|
17
|
+
LocationForm: 'EncounterHistory.location-form',
|
|
18
|
+
};
|
|
19
|
+
export const EncounterHistoryClaimSpecs = [
|
|
20
|
+
{ key: EncounterHistoryClaim.Identifier, meaning: 'Business identifier.', example: 'urn:uuid:encounter-history-1' },
|
|
21
|
+
{ key: EncounterHistoryClaim.Encounter, meaning: 'Encounter whose milestone is recorded.', example: 'Encounter/encounter-1' },
|
|
22
|
+
{ key: EncounterHistoryClaim.Status, meaning: 'FHIR R5 Encounter status at this milestone.', example: 'on-hold' },
|
|
23
|
+
{ key: EncounterHistoryClaim.Class, meaning: 'Encounter class token.', example: 'http://terminology.hl7.org/CodeSystem/v3-ActCode|EMER' },
|
|
24
|
+
{ key: EncounterHistoryClaim.Type, meaning: 'Encounter type tokens (CSV).', example: 'http://snomed.info/sct|50849002' },
|
|
25
|
+
{ key: EncounterHistoryClaim.ServiceType, meaning: 'HealthcareService references (CSV).', example: 'HealthcareService/emergency-1' },
|
|
26
|
+
{ key: EncounterHistoryClaim.Subject, meaning: 'Patient or Group reference.', example: 'Patient/patient-1' },
|
|
27
|
+
{ key: EncounterHistoryClaim.SubjectStatus, meaning: 'Subject status token.', example: 'departed' },
|
|
28
|
+
{ key: EncounterHistoryClaim.ActualPeriodStart, meaning: 'Milestone period start.', example: '2026-09-29T08:00:00Z' },
|
|
29
|
+
{ key: EncounterHistoryClaim.ActualPeriodEnd, meaning: 'Milestone period end.', example: '2026-09-29T08:30:00Z' },
|
|
30
|
+
{ key: EncounterHistoryClaim.PlannedStartDate, meaning: 'Planned start.', example: '2026-09-29T08:00:00Z' },
|
|
31
|
+
{ key: EncounterHistoryClaim.PlannedEndDate, meaning: 'Planned end.', example: '2026-09-29T08:30:00Z' },
|
|
32
|
+
{ key: EncounterHistoryClaim.Location, meaning: 'Location references (CSV).', example: 'Location/emergency-box-1' },
|
|
33
|
+
{ key: EncounterHistoryClaim.LocationForm, meaning: 'Location form token.', example: 'http://terminology.hl7.org/CodeSystem/location-physical-type|ro' },
|
|
34
|
+
];
|
package/dist/claims/index.d.ts
CHANGED
|
@@ -16,6 +16,7 @@ export * from './device-use-statement-claims.js';
|
|
|
16
16
|
export * from './diagnostic-report-claims.js';
|
|
17
17
|
export * from './document-reference-claims.js';
|
|
18
18
|
export * from './encounter-claims.js';
|
|
19
|
+
export * from './encounter-history-claims.js';
|
|
19
20
|
export * from './flag-claims.js';
|
|
20
21
|
export * from './immunization-claims.js';
|
|
21
22
|
export * from './immunization-recommendation-claims.js';
|
package/dist/claims/index.js
CHANGED
|
@@ -16,6 +16,7 @@ export * from './device-use-statement-claims.js';
|
|
|
16
16
|
export * from './diagnostic-report-claims.js';
|
|
17
17
|
export * from './document-reference-claims.js';
|
|
18
18
|
export * from './encounter-claims.js';
|
|
19
|
+
export * from './encounter-history-claims.js';
|
|
19
20
|
export * from './flag-claims.js';
|
|
20
21
|
export * from './immunization-claims.js';
|
|
21
22
|
export * from './immunization-recommendation-claims.js';
|
|
@@ -116,6 +116,7 @@ export declare const FhirResourceTypes: Readonly<{
|
|
|
116
116
|
}>;
|
|
117
117
|
/** FHIR R5-only resources currently emitted by shared subscription contracts. */
|
|
118
118
|
export declare const ResourceTypesFhirR5: Readonly<{
|
|
119
|
+
readonly EncounterHistory: "EncounterHistory";
|
|
119
120
|
readonly Subscription: "Subscription";
|
|
120
121
|
readonly SubscriptionTopic: "SubscriptionTopic";
|
|
121
122
|
readonly SubscriptionStatus: "SubscriptionStatus";
|
|
@@ -65,6 +65,7 @@ export const FhirResourceTypes = ResourceTypesFhirR4;
|
|
|
65
65
|
/** FHIR R5-only resources currently emitted by shared subscription contracts. */
|
|
66
66
|
export const ResourceTypesFhirR5 = Object.freeze({
|
|
67
67
|
...ResourceTypesFhirR4,
|
|
68
|
+
EncounterHistory: 'EncounterHistory',
|
|
68
69
|
Subscription: 'Subscription',
|
|
69
70
|
SubscriptionTopic: 'SubscriptionTopic',
|
|
70
71
|
SubscriptionStatus: 'SubscriptionStatus',
|
|
@@ -0,0 +1,5 @@
|
|
|
1
|
+
import type { FhirResource, FlatClaims } from './convert-shared.js';
|
|
2
|
+
/** Materializes canonical EncounterHistory claims as native FHIR R5. */
|
|
3
|
+
export declare function encounterHistoryFlatToFhirR5(claims: FlatClaims): FhirResource;
|
|
4
|
+
/** Extracts supported native FHIR R5 EncounterHistory fields into flat claims. */
|
|
5
|
+
export declare function encounterHistoryFhirR5ToFlat(resource: FhirResource): FlatClaims;
|
|
@@ -0,0 +1,83 @@
|
|
|
1
|
+
// Copyright 2026 Conéctate Soluciones y Aplicaciones SL under the Apache License, Version 2.0.
|
|
2
|
+
import { EncounterHistoryClaim } from '../claims/encounter-history-claims.js';
|
|
3
|
+
import { EncounterStatusR5 } from '../claims/encounter-claims.js';
|
|
4
|
+
import { codingFromValue, codingToValue, referenceToValue } from './convert-shared.js';
|
|
5
|
+
const R5_STATUSES = new Set(Object.values(EncounterStatusR5));
|
|
6
|
+
/** Materializes canonical EncounterHistory claims as native FHIR R5. */
|
|
7
|
+
export function encounterHistoryFlatToFhirR5(claims) {
|
|
8
|
+
const status = claims[EncounterHistoryClaim.Status];
|
|
9
|
+
if (!status || !R5_STATUSES.has(status))
|
|
10
|
+
throw new TypeError('encounter_history_r5_status_invalid');
|
|
11
|
+
const klass = claims[EncounterHistoryClaim.Class];
|
|
12
|
+
if (!klass)
|
|
13
|
+
throw new TypeError('encounter_history_r5_class_required');
|
|
14
|
+
return {
|
|
15
|
+
resourceType: 'EncounterHistory',
|
|
16
|
+
identifier: claims[EncounterHistoryClaim.Identifier] ? [{ value: claims[EncounterHistoryClaim.Identifier] }] : undefined,
|
|
17
|
+
encounter: claims[EncounterHistoryClaim.Encounter] ? { reference: claims[EncounterHistoryClaim.Encounter] } : undefined,
|
|
18
|
+
status,
|
|
19
|
+
class: { coding: codingFromValue(klass) },
|
|
20
|
+
type: concepts(claims[EncounterHistoryClaim.Type]),
|
|
21
|
+
serviceType: codeableReferences(claims[EncounterHistoryClaim.ServiceType]),
|
|
22
|
+
subject: claims[EncounterHistoryClaim.Subject] ? { reference: claims[EncounterHistoryClaim.Subject] } : undefined,
|
|
23
|
+
subjectStatus: claims[EncounterHistoryClaim.SubjectStatus] ? { coding: codingFromValue(claims[EncounterHistoryClaim.SubjectStatus]) } : undefined,
|
|
24
|
+
actualPeriod: period(claims[EncounterHistoryClaim.ActualPeriodStart], claims[EncounterHistoryClaim.ActualPeriodEnd]),
|
|
25
|
+
plannedStartDate: claims[EncounterHistoryClaim.PlannedStartDate],
|
|
26
|
+
plannedEndDate: claims[EncounterHistoryClaim.PlannedEndDate],
|
|
27
|
+
location: locations(claims[EncounterHistoryClaim.Location], claims[EncounterHistoryClaim.LocationForm]),
|
|
28
|
+
};
|
|
29
|
+
}
|
|
30
|
+
/** Extracts supported native FHIR R5 EncounterHistory fields into flat claims. */
|
|
31
|
+
export function encounterHistoryFhirR5ToFlat(resource) {
|
|
32
|
+
const klass = resource.class;
|
|
33
|
+
const actualPeriod = resource.actualPeriod;
|
|
34
|
+
const location = resource.location?.[0];
|
|
35
|
+
return {
|
|
36
|
+
[EncounterHistoryClaim.Identifier]: resource.identifier?.[0]?.value,
|
|
37
|
+
[EncounterHistoryClaim.Encounter]: referenceToValue(resource.encounter),
|
|
38
|
+
[EncounterHistoryClaim.Status]: resource.status,
|
|
39
|
+
[EncounterHistoryClaim.Class]: codingToValue(klass?.coding?.[0]),
|
|
40
|
+
[EncounterHistoryClaim.Type]: conceptsToCsv(resource.type),
|
|
41
|
+
[EncounterHistoryClaim.ServiceType]: codeableReferencesToCsv(resource.serviceType),
|
|
42
|
+
[EncounterHistoryClaim.Subject]: referenceToValue(resource.subject),
|
|
43
|
+
[EncounterHistoryClaim.SubjectStatus]: codingToValue(resource.subjectStatus?.coding?.[0]),
|
|
44
|
+
[EncounterHistoryClaim.ActualPeriodStart]: actualPeriod?.start,
|
|
45
|
+
[EncounterHistoryClaim.ActualPeriodEnd]: actualPeriod?.end,
|
|
46
|
+
[EncounterHistoryClaim.PlannedStartDate]: resource.plannedStartDate,
|
|
47
|
+
[EncounterHistoryClaim.PlannedEndDate]: resource.plannedEndDate,
|
|
48
|
+
[EncounterHistoryClaim.Location]: location?.location?.reference,
|
|
49
|
+
[EncounterHistoryClaim.LocationForm]: codingToValue(location?.form?.coding?.[0]),
|
|
50
|
+
};
|
|
51
|
+
}
|
|
52
|
+
function period(start, end) {
|
|
53
|
+
return start || end ? { start, end } : undefined;
|
|
54
|
+
}
|
|
55
|
+
function concepts(value) {
|
|
56
|
+
const values = value?.split(',').map(item => item.trim()).filter(Boolean) ?? [];
|
|
57
|
+
return values.length ? values.map(item => ({ coding: codingFromValue(item) })) : undefined;
|
|
58
|
+
}
|
|
59
|
+
function conceptsToCsv(value) {
|
|
60
|
+
if (!Array.isArray(value))
|
|
61
|
+
return undefined;
|
|
62
|
+
const values = value.map(item => codingToValue(item?.coding?.[0])).filter(Boolean);
|
|
63
|
+
return values.length ? values.join(',') : undefined;
|
|
64
|
+
}
|
|
65
|
+
function codeableReferences(value) {
|
|
66
|
+
const values = value?.split(',').map(item => item.trim()).filter(Boolean) ?? [];
|
|
67
|
+
return values.length ? values.map(reference => ({ reference: { reference } })) : undefined;
|
|
68
|
+
}
|
|
69
|
+
function codeableReferencesToCsv(value) {
|
|
70
|
+
if (!Array.isArray(value))
|
|
71
|
+
return undefined;
|
|
72
|
+
const values = value.map(item => referenceToValue(item?.reference)).filter(Boolean);
|
|
73
|
+
return values.length ? values.join(',') : undefined;
|
|
74
|
+
}
|
|
75
|
+
function locations(locationValue, formValue) {
|
|
76
|
+
const values = locationValue?.split(',').map(item => item.trim()).filter(Boolean) ?? [];
|
|
77
|
+
if (!values.length)
|
|
78
|
+
return undefined;
|
|
79
|
+
return values.map((reference, index) => ({
|
|
80
|
+
location: { reference },
|
|
81
|
+
form: index === 0 && formValue ? { coding: codingFromValue(formValue) } : undefined,
|
|
82
|
+
}));
|
|
83
|
+
}
|
|
@@ -1,3 +1,7 @@
|
|
|
1
1
|
import type { FhirResource, FlatClaims } from './convert-shared.js';
|
|
2
2
|
export declare function encounterFlatToFhirR4(claims: FlatClaims): FhirResource;
|
|
3
3
|
export declare function encounterFhirR4ToFlat(resource: FhirResource): FlatClaims;
|
|
4
|
+
/** Materializes canonical Encounter claims as native FHIR R5. */
|
|
5
|
+
export declare function encounterFlatToFhirR5(claims: FlatClaims): FhirResource;
|
|
6
|
+
/** Extracts the supported R5 Encounter fields into canonical flat claims. */
|
|
7
|
+
export declare function encounterFhirR5ToFlat(resource: FhirResource): FlatClaims;
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
// Copyright 2026 Conéctate Soluciones y Aplicaciones SL under the Apache License, Version 2.0.
|
|
2
2
|
// File: src/utils/convert-encounter.ts
|
|
3
|
-
import { EncounterClaim } from '../claims/encounter-claims.js';
|
|
3
|
+
import { EncounterClaim, EncounterStatusR5 } from '../claims/encounter-claims.js';
|
|
4
4
|
import { codingFromValue, codingToValue, referenceListToCsv, referenceToValue } from './convert-shared.js';
|
|
5
5
|
export function encounterFlatToFhirR4(claims) {
|
|
6
6
|
const subject = claims[EncounterClaim.Subject] ?? claims[EncounterClaim.Patient];
|
|
@@ -72,3 +72,75 @@ export function encounterFhirR4ToFlat(resource) {
|
|
|
72
72
|
[EncounterClaim.PartOf]: referenceToValue(resource.partOf),
|
|
73
73
|
};
|
|
74
74
|
}
|
|
75
|
+
const R5_STATUSES = new Set(Object.values(EncounterStatusR5));
|
|
76
|
+
/** Materializes canonical Encounter claims as native FHIR R5. */
|
|
77
|
+
export function encounterFlatToFhirR5(claims) {
|
|
78
|
+
const status = claims[EncounterClaim.Status];
|
|
79
|
+
if (status && !R5_STATUSES.has(status))
|
|
80
|
+
throw new TypeError('encounter_r5_status_invalid');
|
|
81
|
+
const subject = claims[EncounterClaim.Subject] ?? claims[EncounterClaim.Patient];
|
|
82
|
+
const actualPeriodStart = claims[EncounterClaim.ActualPeriodStart] ?? claims[EncounterClaim.PeriodStart];
|
|
83
|
+
const actualPeriodEnd = claims[EncounterClaim.ActualPeriodEnd] ?? claims[EncounterClaim.PeriodEnd];
|
|
84
|
+
return {
|
|
85
|
+
resourceType: 'Encounter',
|
|
86
|
+
identifier: claims[EncounterClaim.Identifier] ? [{ value: claims[EncounterClaim.Identifier] }] : undefined,
|
|
87
|
+
appointment: referenceList(claims[EncounterClaim.Appointment]),
|
|
88
|
+
status,
|
|
89
|
+
class: claims[EncounterClaim.Class] ? { coding: codingFromValue(claims[EncounterClaim.Class]) } : undefined,
|
|
90
|
+
type: claims[EncounterClaim.Type] ? [{ coding: codingFromValue(claims[EncounterClaim.Type]) }] : undefined,
|
|
91
|
+
serviceType: codeableReferenceList(claims[EncounterClaim.ServiceType]),
|
|
92
|
+
subject: subject ? { reference: subject } : undefined,
|
|
93
|
+
participant: claims[EncounterClaim.Participant]
|
|
94
|
+
? claims[EncounterClaim.Participant].split(',').map(reference => ({ actor: { reference: reference.trim() } }))
|
|
95
|
+
: undefined,
|
|
96
|
+
serviceProvider: claims[EncounterClaim.ServiceProvider] ? { reference: claims[EncounterClaim.ServiceProvider] } : undefined,
|
|
97
|
+
actualPeriod: (actualPeriodStart || actualPeriodEnd) ? { start: actualPeriodStart, end: actualPeriodEnd } : undefined,
|
|
98
|
+
location: claims[EncounterClaim.Location]
|
|
99
|
+
? claims[EncounterClaim.Location].split(',').map(reference => ({ location: { reference: reference.trim() } }))
|
|
100
|
+
: undefined,
|
|
101
|
+
partOf: claims[EncounterClaim.PartOf] ? { reference: claims[EncounterClaim.PartOf] } : undefined,
|
|
102
|
+
};
|
|
103
|
+
}
|
|
104
|
+
/** Extracts the supported R5 Encounter fields into canonical flat claims. */
|
|
105
|
+
export function encounterFhirR5ToFlat(resource) {
|
|
106
|
+
const klass = resource.class;
|
|
107
|
+
const actualPeriod = resource.actualPeriod;
|
|
108
|
+
return {
|
|
109
|
+
[EncounterClaim.Identifier]: resource.identifier?.[0]?.value,
|
|
110
|
+
[EncounterClaim.Appointment]: referenceListToCsv(resource.appointment),
|
|
111
|
+
[EncounterClaim.Status]: resource.status,
|
|
112
|
+
[EncounterClaim.Class]: codingToValue(klass?.coding?.[0]),
|
|
113
|
+
[EncounterClaim.Type]: codingToValue(resource.type?.[0]?.coding?.[0]),
|
|
114
|
+
[EncounterClaim.ServiceType]: codeableReferencesToCsv(resource.serviceType),
|
|
115
|
+
[EncounterClaim.Subject]: referenceToValue(resource.subject),
|
|
116
|
+
[EncounterClaim.Patient]: referenceToValue(resource.subject),
|
|
117
|
+
[EncounterClaim.Participant]: Array.isArray(resource.participant)
|
|
118
|
+
? resource.participant.map(item => item.actor?.reference).filter(Boolean).join(',') || undefined
|
|
119
|
+
: undefined,
|
|
120
|
+
[EncounterClaim.ServiceProvider]: referenceToValue(resource.serviceProvider),
|
|
121
|
+
[EncounterClaim.ActualPeriodStart]: actualPeriod?.start,
|
|
122
|
+
[EncounterClaim.ActualPeriodEnd]: actualPeriod?.end,
|
|
123
|
+
[EncounterClaim.Location]: Array.isArray(resource.location)
|
|
124
|
+
? resource.location.map(item => item.location?.reference).filter(Boolean).join(',') || undefined
|
|
125
|
+
: undefined,
|
|
126
|
+
[EncounterClaim.PartOf]: referenceToValue(resource.partOf),
|
|
127
|
+
};
|
|
128
|
+
}
|
|
129
|
+
function referenceList(value) {
|
|
130
|
+
const references = value?.split(',').map(reference => reference.trim()).filter(Boolean) ?? [];
|
|
131
|
+
return references.length ? references.map(reference => ({ reference })) : undefined;
|
|
132
|
+
}
|
|
133
|
+
function codeableReferenceList(value) {
|
|
134
|
+
const references = referenceList(value);
|
|
135
|
+
return references?.map(reference => ({ reference }));
|
|
136
|
+
}
|
|
137
|
+
function codeableReferencesToCsv(value) {
|
|
138
|
+
if (!Array.isArray(value))
|
|
139
|
+
return undefined;
|
|
140
|
+
const references = value.map(item => {
|
|
141
|
+
if (!item || typeof item !== 'object')
|
|
142
|
+
return undefined;
|
|
143
|
+
return referenceToValue(item.reference);
|
|
144
|
+
}).filter((item) => Boolean(item));
|
|
145
|
+
return references.length ? references.join(',') : undefined;
|
|
146
|
+
}
|
|
@@ -16,6 +16,7 @@ export * from './convert-device-metric.js';
|
|
|
16
16
|
export * from './convert-diagnostic-report.js';
|
|
17
17
|
export * from './convert-document-reference.js';
|
|
18
18
|
export * from './convert-encounter.js';
|
|
19
|
+
export * from './convert-encounter-history.js';
|
|
19
20
|
export * from './convert-flag.js';
|
|
20
21
|
export * from './convert-immunization.js';
|
|
21
22
|
export * from './convert-imaging-study.js';
|
package/dist/converters/index.js
CHANGED
|
@@ -16,6 +16,7 @@ export * from './convert-device-metric.js';
|
|
|
16
16
|
export * from './convert-diagnostic-report.js';
|
|
17
17
|
export * from './convert-document-reference.js';
|
|
18
18
|
export * from './convert-encounter.js';
|
|
19
|
+
export * from './convert-encounter-history.js';
|
|
19
20
|
export * from './convert-flag.js';
|
|
20
21
|
export * from './convert-immunization.js';
|
|
21
22
|
export * from './convert-imaging-study.js';
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import type { FhirResource } from '../fhir-types.js';
|
|
2
2
|
export type ClaimsFirstFhirResource = Readonly<{
|
|
3
|
-
resourceType: 'Organization' | 'HealthcareService' | 'Location' | 'Schedule' | 'Slot' | 'DeviceMetric' | 'Procedure' | 'RegulatedAuthorization' | 'DocumentReference';
|
|
3
|
+
resourceType: 'Organization' | 'HealthcareService' | 'Location' | 'Schedule' | 'Slot' | 'DeviceMetric' | 'Procedure' | 'RegulatedAuthorization' | 'DocumentReference' | 'Encounter' | 'EncounterHistory';
|
|
4
4
|
id: string;
|
|
5
5
|
meta: Readonly<{
|
|
6
6
|
claims: Readonly<Record<string, unknown>>;
|
|
@@ -6,6 +6,8 @@ import { deviceMetricFlatToFhirR5 } from './convert-device-metric.js';
|
|
|
6
6
|
import { procedureFlatToFhirR5 } from './convert-procedure.js';
|
|
7
7
|
import { regulatedAuthorizationFlatToFhirR5 } from './convert-regulated-authorization.js';
|
|
8
8
|
import { documentReferenceFlatToFhirR4 } from './convert-document-reference.js';
|
|
9
|
+
import { encounterFlatToFhirR5 } from './convert-encounter.js';
|
|
10
|
+
import { encounterHistoryFlatToFhirR5 } from './convert-encounter-history.js';
|
|
9
11
|
const materializers = Object.freeze({
|
|
10
12
|
Organization: organizationFlatToFhirR5,
|
|
11
13
|
HealthcareService: healthcareServiceFlatToFhirR5,
|
|
@@ -16,6 +18,8 @@ const materializers = Object.freeze({
|
|
|
16
18
|
Procedure: procedureFlatToFhirR5,
|
|
17
19
|
RegulatedAuthorization: regulatedAuthorizationFlatToFhirR5,
|
|
18
20
|
DocumentReference: documentReferenceFlatToFhirR4,
|
|
21
|
+
Encounter: encounterFlatToFhirR5,
|
|
22
|
+
EncounterHistory: encounterHistoryFlatToFhirR5,
|
|
19
23
|
});
|
|
20
24
|
/**
|
|
21
25
|
* Materializes native FHIR R5 only at an explicit adapter boundary.
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
import { EncounterStatusR5 } from './claims/encounter-claims.js';
|
|
2
|
+
/** Product-neutral identifiers and references for cross-package Encounter transfer contract tests. */
|
|
3
|
+
export declare const FHIR_ENCOUNTER_TRANSFER_TEST_DATA: Readonly<{
|
|
4
|
+
communicationIdentifier: "urn:uuid:00000000-0000-4000-8000-000000000401";
|
|
5
|
+
subjectReference: "Patient/00000000-0000-4000-8000-000000000402";
|
|
6
|
+
senderReference: "Organization/00000000-0000-4000-8000-000000000403";
|
|
7
|
+
indexRecipientReference: "Organization/00000000-0000-4000-8000-000000000404";
|
|
8
|
+
occurredAt: "2026-09-30T10:10:00Z";
|
|
9
|
+
class: Readonly<{
|
|
10
|
+
system: "http://terminology.hl7.org/CodeSystem/v3-ActCode";
|
|
11
|
+
code: "EMER";
|
|
12
|
+
}>;
|
|
13
|
+
source: Readonly<{
|
|
14
|
+
id: "00000000-0000-4000-8000-000000000405";
|
|
15
|
+
reference: "Encounter/00000000-0000-4000-8000-000000000405";
|
|
16
|
+
identifier: "urn:uuid:00000000-0000-4000-8000-000000000405";
|
|
17
|
+
serviceReference: "HealthcareService/00000000-0000-4000-8000-000000000406";
|
|
18
|
+
locationReference: "Location/00000000-0000-4000-8000-000000000407";
|
|
19
|
+
statusWhenReturning: EncounterStatusR5.OnHold;
|
|
20
|
+
statusWhenNotReturning: EncounterStatusR5.Completed;
|
|
21
|
+
}>;
|
|
22
|
+
destination: Readonly<{
|
|
23
|
+
id: "00000000-0000-4000-8000-000000000408";
|
|
24
|
+
reference: "Encounter/00000000-0000-4000-8000-000000000408";
|
|
25
|
+
identifier: "urn:uuid:00000000-0000-4000-8000-000000000408";
|
|
26
|
+
serviceReference: "HealthcareService/00000000-0000-4000-8000-000000000409";
|
|
27
|
+
locationReference: "Location/00000000-0000-4000-8000-000000000410";
|
|
28
|
+
statusOnArrival: EncounterStatusR5.InProgress;
|
|
29
|
+
}>;
|
|
30
|
+
sourceHistory: Readonly<{
|
|
31
|
+
id: "00000000-0000-4000-8000-000000000411";
|
|
32
|
+
identifier: "urn:uuid:00000000-0000-4000-8000-000000000411";
|
|
33
|
+
encounterReference: "Encounter/00000000-0000-4000-8000-000000000405";
|
|
34
|
+
}>;
|
|
35
|
+
destinationHistory: Readonly<{
|
|
36
|
+
id: "00000000-0000-4000-8000-000000000412";
|
|
37
|
+
identifier: "urn:uuid:00000000-0000-4000-8000-000000000412";
|
|
38
|
+
encounterReference: "Encounter/00000000-0000-4000-8000-000000000408";
|
|
39
|
+
}>;
|
|
40
|
+
}>;
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
import { EncounterStatusR5 } from './claims/encounter-claims.js';
|
|
2
|
+
/** Product-neutral identifiers and references for cross-package Encounter transfer contract tests. */
|
|
3
|
+
export const FHIR_ENCOUNTER_TRANSFER_TEST_DATA = Object.freeze({
|
|
4
|
+
communicationIdentifier: 'urn:uuid:00000000-0000-4000-8000-000000000401',
|
|
5
|
+
subjectReference: 'Patient/00000000-0000-4000-8000-000000000402',
|
|
6
|
+
senderReference: 'Organization/00000000-0000-4000-8000-000000000403',
|
|
7
|
+
indexRecipientReference: 'Organization/00000000-0000-4000-8000-000000000404',
|
|
8
|
+
occurredAt: '2026-09-30T10:10:00Z',
|
|
9
|
+
class: Object.freeze({ system: 'http://terminology.hl7.org/CodeSystem/v3-ActCode', code: 'EMER' }),
|
|
10
|
+
source: Object.freeze({
|
|
11
|
+
id: '00000000-0000-4000-8000-000000000405',
|
|
12
|
+
reference: 'Encounter/00000000-0000-4000-8000-000000000405',
|
|
13
|
+
identifier: 'urn:uuid:00000000-0000-4000-8000-000000000405',
|
|
14
|
+
serviceReference: 'HealthcareService/00000000-0000-4000-8000-000000000406',
|
|
15
|
+
locationReference: 'Location/00000000-0000-4000-8000-000000000407',
|
|
16
|
+
statusWhenReturning: EncounterStatusR5.OnHold,
|
|
17
|
+
statusWhenNotReturning: EncounterStatusR5.Completed,
|
|
18
|
+
}),
|
|
19
|
+
destination: Object.freeze({
|
|
20
|
+
id: '00000000-0000-4000-8000-000000000408',
|
|
21
|
+
reference: 'Encounter/00000000-0000-4000-8000-000000000408',
|
|
22
|
+
identifier: 'urn:uuid:00000000-0000-4000-8000-000000000408',
|
|
23
|
+
serviceReference: 'HealthcareService/00000000-0000-4000-8000-000000000409',
|
|
24
|
+
locationReference: 'Location/00000000-0000-4000-8000-000000000410',
|
|
25
|
+
statusOnArrival: EncounterStatusR5.InProgress,
|
|
26
|
+
}),
|
|
27
|
+
sourceHistory: Object.freeze({
|
|
28
|
+
id: '00000000-0000-4000-8000-000000000411',
|
|
29
|
+
identifier: 'urn:uuid:00000000-0000-4000-8000-000000000411',
|
|
30
|
+
encounterReference: 'Encounter/00000000-0000-4000-8000-000000000405',
|
|
31
|
+
}),
|
|
32
|
+
destinationHistory: Object.freeze({
|
|
33
|
+
id: '00000000-0000-4000-8000-000000000412',
|
|
34
|
+
identifier: 'urn:uuid:00000000-0000-4000-8000-000000000412',
|
|
35
|
+
encounterReference: 'Encounter/00000000-0000-4000-8000-000000000408',
|
|
36
|
+
}),
|
|
37
|
+
});
|
package/dist/index.d.ts
CHANGED
package/dist/index.js
CHANGED