fhir-dosage-utils 1.1.0 → 1.2.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/LICENSE +661 -0
- package/README.md +1 -1
- package/dist/locales/de/common.json +32 -24
- package/dist/locales/en/common.json +32 -24
- package/dist/locales/fr/common.json +32 -24
- package/dist/locales/nl/common.json +32 -24
- package/dist/main.js +178 -145
- package/dist/main.js.map +1 -1
- package/dist/module.js +178 -145
- package/dist/module.js.map +1 -1
- package/dist/types.d.ts +10 -1
- package/dist/types.d.ts.map +1 -1
- package/package.json +1 -1
package/dist/module.js
CHANGED
@@ -56,43 +56,77 @@ function $7cf24331c38efaf1$export$7de3722258b87db9({ config: config, dos: dos, i
|
|
56
56
|
}
|
57
57
|
|
58
58
|
|
59
|
-
//
|
60
|
-
|
61
|
-
|
62
|
-
|
63
|
-
//
|
64
|
-
|
65
|
-
|
66
|
-
|
67
|
-
|
68
|
-
|
69
|
-
|
70
|
-
|
71
|
-
let unit = config.fromFHIRQuantityUnitToString({
|
59
|
+
// Utility function
|
60
|
+
// Quantity unit to string
|
61
|
+
function $73073500f7f08f16$var$transformQuantityUnitToString(i18next, quantity, config) {
|
62
|
+
let quantityValue = quantity.value;
|
63
|
+
// If common units from HL7, do the job
|
64
|
+
if (quantity.system === "http://hl7.org/fhir/ValueSet/duration-units") {
|
65
|
+
let code = quantity.code;
|
66
|
+
return i18next.t(`unitsOfTime:withoutCount.${code}`, {
|
67
|
+
count: quantityValue
|
68
|
+
});
|
69
|
+
} else // otherwise, it is UCUM, ... so let the user do the job
|
70
|
+
return config.fromFHIRQuantityUnitToString({
|
72
71
|
language: config.language,
|
73
|
-
quantity:
|
72
|
+
quantity: quantity
|
74
73
|
});
|
75
|
-
|
76
|
-
|
77
|
-
|
78
|
-
|
79
|
-
|
74
|
+
}
|
75
|
+
function $73073500f7f08f16$export$be17d167ed50d870({ range: range, config: config, i18next: i18next }) {
|
76
|
+
// Extract params
|
77
|
+
const { low: low, high: high } = range;
|
78
|
+
const lowValue = low?.value;
|
79
|
+
const highValue = high?.value;
|
80
|
+
// prepare unit display
|
81
|
+
let quantityUnit = high || low;
|
82
|
+
let hasUnit = quantityUnit?.unit !== undefined || quantityUnit?.code !== undefined;
|
83
|
+
// Four cases
|
84
|
+
// 1. If we have a empty object, return undefined
|
85
|
+
if (lowValue === undefined && highValue === undefined) return undefined;
|
86
|
+
// quantity unit
|
87
|
+
let unit = hasUnit ? $73073500f7f08f16$var$transformQuantityUnitToString(i18next, quantityUnit, config) : "";
|
88
|
+
let technicalKey = hasUnit ? "withUnit" : "withoutUnit";
|
89
|
+
// 2. Both low & high are present
|
90
|
+
if (lowValue !== undefined && highValue !== undefined) return i18next.t(`amount.range.${technicalKey}.lowAndHigh`, {
|
91
|
+
low: lowValue,
|
92
|
+
high: highValue,
|
80
93
|
unit: unit
|
81
94
|
});
|
82
|
-
//
|
83
|
-
if (
|
84
|
-
high:
|
95
|
+
// 3. Only high is present
|
96
|
+
if (highValue !== undefined) return i18next.t(`amount.range.${technicalKey}.onlyHigh`, {
|
97
|
+
high: highValue,
|
85
98
|
unit: unit
|
86
99
|
});
|
87
|
-
//
|
100
|
+
// 4. Only low is present
|
88
101
|
// Warning, this case is kind dangerous and clinically unsafe so minimal effort on this ...
|
89
|
-
return i18next.t(
|
90
|
-
low:
|
102
|
+
return i18next.t(`amount.range.${technicalKey}.onlyLow`, {
|
103
|
+
low: lowValue,
|
91
104
|
unit: unit
|
92
105
|
});
|
93
106
|
}
|
94
107
|
|
95
108
|
|
109
|
+
function $465e6e43e1df9717$export$4cd16590995531a9({ dos: dos, config: config, i18next: i18next }) {
|
110
|
+
// If empty, return undefined
|
111
|
+
if (dos.doseAndRate === undefined) return undefined;
|
112
|
+
// Find the first entry that match criteria
|
113
|
+
let doseRange = dos.doseAndRate.find((s)=>s.doseRange !== undefined);
|
114
|
+
// If not found, skip
|
115
|
+
if (doseRange === undefined) return undefined;
|
116
|
+
// Turn range into a text
|
117
|
+
const text = (0, $73073500f7f08f16$export$be17d167ed50d870)({
|
118
|
+
range: doseRange.doseRange,
|
119
|
+
config: config,
|
120
|
+
i18next: i18next
|
121
|
+
});
|
122
|
+
// Reject if empty
|
123
|
+
if (text === undefined) return undefined;
|
124
|
+
return i18next.t("fields.doseRange", {
|
125
|
+
rangeText: text
|
126
|
+
});
|
127
|
+
}
|
128
|
+
|
129
|
+
|
96
130
|
// types
|
97
131
|
function $bbbd1877a73b7a2b$export$4e24ef8c7997cc56({ dos: dos, config: config, i18next: i18next }) {
|
98
132
|
// If empty, return undefined
|
@@ -115,72 +149,91 @@ function $bbbd1877a73b7a2b$export$4e24ef8c7997cc56({ dos: dos, config: config, i
|
|
115
149
|
}
|
116
150
|
|
117
151
|
|
118
|
-
//
|
152
|
+
// Utility function
|
153
|
+
|
119
154
|
function $09db039855b6d015$export$d3dd7d3522271dba({ dos: dos, config: config, i18next: i18next }) {
|
120
155
|
// If empty, return undefined
|
121
156
|
if (dos.doseAndRate === undefined) return undefined;
|
122
157
|
// Find the first entry that match criteria
|
123
|
-
let
|
158
|
+
let doseAndRate = dos.doseAndRate.find((s)=>s.rateRange !== undefined);
|
124
159
|
// If not found, skip
|
125
|
-
if (
|
126
|
-
//
|
127
|
-
|
128
|
-
|
129
|
-
|
130
|
-
|
131
|
-
// quantity unit
|
132
|
-
let unit = config.fromFHIRQuantityUnitToString({
|
133
|
-
language: config.language,
|
134
|
-
quantity: high || low
|
160
|
+
if (doseAndRate === undefined) return undefined;
|
161
|
+
// Turn range into a text
|
162
|
+
const rangeText = (0, $73073500f7f08f16$export$be17d167ed50d870)({
|
163
|
+
range: doseAndRate.rateRange,
|
164
|
+
config: config,
|
165
|
+
i18next: i18next
|
135
166
|
});
|
136
|
-
//
|
137
|
-
|
138
|
-
|
139
|
-
|
140
|
-
|
141
|
-
unit: unit
|
142
|
-
});
|
143
|
-
// 2. Only high is present
|
144
|
-
if (quantityHigh !== undefined) return i18next.t("fields.rateRange.onlyHigh", {
|
145
|
-
high: quantityHigh,
|
146
|
-
unit: unit
|
147
|
-
});
|
148
|
-
// 3. Only low is present
|
149
|
-
// Warning, this case is kind dangerous and clinically unsafe so minimal effort on this ...
|
150
|
-
return i18next.t("fields.rateRange.onlyLow", {
|
151
|
-
low: quantityLow,
|
152
|
-
unit: unit
|
167
|
+
// Reject if empty
|
168
|
+
if (rangeText === undefined) return undefined;
|
169
|
+
// return the final string
|
170
|
+
return i18next.t("fields.rateRange", {
|
171
|
+
rangeText: rangeText
|
153
172
|
});
|
154
173
|
}
|
155
174
|
|
156
175
|
|
157
|
-
//
|
158
|
-
function $
|
159
|
-
|
160
|
-
|
161
|
-
|
162
|
-
|
163
|
-
|
164
|
-
if (rateRatio === undefined) return undefined;
|
165
|
-
// num / dem
|
166
|
-
let numerator = rateRatio.rateRatio.numerator;
|
167
|
-
let denominator = rateRatio.rateRatio.denominator;
|
168
|
-
let quantityNum = numerator?.value || 1;
|
169
|
-
let quantityDenom = denominator?.value || 1;
|
176
|
+
// Quantity has an unit ?
|
177
|
+
function $eb371feb739abc89$var$hasUnit(quantity) {
|
178
|
+
return (quantity?.unit || quantity?.code) !== undefined;
|
179
|
+
}
|
180
|
+
function $eb371feb739abc89$export$fdc6e9cbd31555fb({ ratio: ratio, config: config, i18next: i18next }) {
|
181
|
+
// Extract params
|
182
|
+
const { denominator: denominator, numerator: numerator } = ratio;
|
170
183
|
// units as text
|
171
|
-
let numeratorUnit = numerator
|
184
|
+
let numeratorUnit = $eb371feb739abc89$var$hasUnit(numerator) ? config.fromFHIRQuantityUnitToString({
|
172
185
|
language: config.language,
|
173
186
|
quantity: numerator
|
174
|
-
}) :
|
175
|
-
let denominatorUnit = denominator
|
187
|
+
}) : undefined;
|
188
|
+
let denominatorUnit = $eb371feb739abc89$var$hasUnit(denominator) ? config.fromFHIRQuantityUnitToString({
|
176
189
|
language: config.language,
|
177
190
|
quantity: denominator
|
178
|
-
}) :
|
179
|
-
|
180
|
-
|
181
|
-
|
182
|
-
|
183
|
-
|
191
|
+
}) : undefined;
|
192
|
+
// quantity
|
193
|
+
let quantityNumerator = numerator?.value;
|
194
|
+
let quantityDenominator = denominator?.value;
|
195
|
+
// Collect
|
196
|
+
const parts = [];
|
197
|
+
// Deal with numerator first
|
198
|
+
if (quantityNumerator !== undefined) {
|
199
|
+
let technicalKey = numeratorUnit !== undefined ? "withUnit" : "withoutUnit";
|
200
|
+
const numeratorString = i18next.t(`amount.ratio.${technicalKey}.numerator`, {
|
201
|
+
count: quantityNumerator,
|
202
|
+
numeratorUnit: numeratorUnit
|
203
|
+
});
|
204
|
+
parts.push(numeratorString);
|
205
|
+
}
|
206
|
+
// Deal with denominator
|
207
|
+
if (quantityDenominator !== undefined) {
|
208
|
+
let technicalKey = denominatorUnit !== undefined ? "withUnit" : "withoutUnit";
|
209
|
+
const denominatorString = i18next.t(`amount.ratio.${technicalKey}.denominator`, {
|
210
|
+
count: quantityDenominator,
|
211
|
+
denominatorUnit: denominatorUnit
|
212
|
+
});
|
213
|
+
parts.push(denominatorString);
|
214
|
+
}
|
215
|
+
// Concatenate the result
|
216
|
+
if (parts.length === 0) return undefined;
|
217
|
+
else return parts.join(" ");
|
218
|
+
}
|
219
|
+
|
220
|
+
|
221
|
+
function $520e93a43a731e9b$export$b71cfd2510242de2({ dos: dos, config: config, i18next: i18next }) {
|
222
|
+
// If empty, return undefined
|
223
|
+
if (dos.doseAndRate === undefined) return undefined;
|
224
|
+
// Find the first entry that match criteria
|
225
|
+
let doseAndRate = dos.doseAndRate.find((s)=>s.rateRatio !== undefined);
|
226
|
+
// If not found, skip
|
227
|
+
if (doseAndRate === undefined) return undefined;
|
228
|
+
// Turn ratio to text
|
229
|
+
const ratioText = (0, $eb371feb739abc89$export$fdc6e9cbd31555fb)({
|
230
|
+
config: config,
|
231
|
+
i18next: i18next,
|
232
|
+
ratio: doseAndRate.rateRatio
|
233
|
+
});
|
234
|
+
if (ratioText === undefined) return undefined;
|
235
|
+
return i18next.t("fields.rateRatio", {
|
236
|
+
ratioText: ratioText
|
184
237
|
});
|
185
238
|
}
|
186
239
|
|
@@ -480,21 +533,7 @@ function $ac69a26e361175ba$export$b927a06bc51aea32({ dos: dos, config: config, i
|
|
480
533
|
|
481
534
|
|
482
535
|
// types
|
483
|
-
|
484
|
-
function $6b27b297c2af1001$var$transformQuantityUnitToString(i18next, quantity, config) {
|
485
|
-
let quantityValue = quantity.value;
|
486
|
-
// If common units from HL7, do the job
|
487
|
-
if (quantity.system === "http://hl7.org/fhir/ValueSet/duration-units") {
|
488
|
-
let code = quantity.code;
|
489
|
-
return i18next.t(`unitsOfTime:withoutCount.${code}`, {
|
490
|
-
count: quantityValue
|
491
|
-
});
|
492
|
-
} else // otherwise, it is UCUM, ... so let the user do the job
|
493
|
-
return config.fromFHIRQuantityUnitToString({
|
494
|
-
language: config.language,
|
495
|
-
quantity: quantity
|
496
|
-
});
|
497
|
-
}
|
536
|
+
|
498
537
|
function $6b27b297c2af1001$export$8c667cbf7bebaa93({ dos: dos, config: config, i18next: i18next }) {
|
499
538
|
// If empty, return undefined
|
500
539
|
if (dos.timing === undefined || dos.timing.repeat === undefined) return undefined;
|
@@ -504,26 +543,17 @@ function $6b27b297c2af1001$export$8c667cbf7bebaa93({ dos: dos, config: config, i
|
|
504
543
|
// Do nothing if no boundsRange, I am not a wizard
|
505
544
|
if (boundsRange === undefined) return undefined;
|
506
545
|
else {
|
507
|
-
|
508
|
-
|
509
|
-
|
510
|
-
|
511
|
-
|
512
|
-
// 1. Both low & high are present
|
513
|
-
if (high !== undefined && low !== undefined) return i18next.t("fields.boundsRange.lowAndHigh", {
|
514
|
-
low: low.value,
|
515
|
-
high: high.value,
|
516
|
-
unit: unit
|
517
|
-
});
|
518
|
-
// 2. Only high is present
|
519
|
-
if (high !== undefined) return i18next.t("fields.boundsRange.onlyHigh", {
|
520
|
-
high: high.value,
|
521
|
-
unit: unit
|
546
|
+
// Turn range into a text
|
547
|
+
const rangeText = (0, $73073500f7f08f16$export$be17d167ed50d870)({
|
548
|
+
range: boundsRange,
|
549
|
+
config: config,
|
550
|
+
i18next: i18next
|
522
551
|
});
|
523
|
-
//
|
524
|
-
|
525
|
-
|
526
|
-
|
552
|
+
// Reject if empty
|
553
|
+
if (rangeText === undefined) return undefined;
|
554
|
+
// return the final string
|
555
|
+
return i18next.t("fields.boundsRange", {
|
556
|
+
rangeText: rangeText
|
527
557
|
});
|
528
558
|
}
|
529
559
|
}
|
@@ -748,6 +778,7 @@ function $f28938e27e1e9773$export$75a89431d80a701a({ dos: dos, config: config, i
|
|
748
778
|
|
749
779
|
|
750
780
|
|
781
|
+
|
751
782
|
function $252769c9f296cd6d$export$346b11a8cb220f02({ dos: dos, config: config, i18next: i18next }) {
|
752
783
|
// If empty, return undefined
|
753
784
|
if (dos.maxDosePerPeriod === undefined) return undefined;
|
@@ -762,29 +793,14 @@ function $252769c9f296cd6d$export$346b11a8cb220f02({ dos: dos, config: config, i
|
|
762
793
|
if (values.length === 0) return undefined;
|
763
794
|
// Periods are expressed as ratio (like rateRatio)
|
764
795
|
const valuesAsString = values.map((period)=>{
|
765
|
-
|
766
|
-
|
767
|
-
|
768
|
-
|
769
|
-
let quantityDenom = denominator?.value || 1;
|
770
|
-
// units as text
|
771
|
-
let numeratorUnit = numerator !== undefined ? config.fromFHIRQuantityUnitToString({
|
772
|
-
language: config.language,
|
773
|
-
quantity: numerator
|
774
|
-
}) : "";
|
775
|
-
let denominatorUnit = denominator !== undefined ? config.fromFHIRQuantityUnitToString({
|
776
|
-
language: config.language,
|
777
|
-
quantity: denominator
|
778
|
-
}) : "";
|
779
|
-
return i18next.t("fields.maxDosePerPeriod.maxDosePerPeriod", {
|
780
|
-
count: quantityDenom,
|
781
|
-
quantityNumerator: quantityNum,
|
782
|
-
numeratorUnit: numeratorUnit,
|
783
|
-
denominatorUnit: denominatorUnit
|
796
|
+
return (0, $eb371feb739abc89$export$fdc6e9cbd31555fb)({
|
797
|
+
config: config,
|
798
|
+
i18next: i18next,
|
799
|
+
ratio: period
|
784
800
|
});
|
785
|
-
});
|
801
|
+
}).filter((s)=>s !== undefined);
|
786
802
|
const maxDosePerPeriodText = (0, $f475af73bad0ba43$export$826742c1df3eca39)(i18next, valuesAsString);
|
787
|
-
return i18next.t("fields.maxDosePerPeriod
|
803
|
+
return i18next.t("fields.maxDosePerPeriod", {
|
788
804
|
count: values.length,
|
789
805
|
maxDosePerPeriodText: maxDosePerPeriodText
|
790
806
|
});
|
@@ -1004,9 +1020,8 @@ class $8435b8d847fb3eb7$export$1c191bca55f84a03 {
|
|
1004
1020
|
return this.getFields(dos, ...order);
|
1005
1021
|
}
|
1006
1022
|
/**
|
1007
|
-
*
|
1008
|
-
*/
|
1009
|
-
// As we can have concurrent / sequential instructions, we need a generic algorithm to do the job
|
1023
|
+
* Does this array of Dosage objects contains only "sequential" instructions ?
|
1024
|
+
*/ containsOnlySequentialInstructions(dosages) {
|
1010
1025
|
// 1. Collect all sequences number
|
1011
1026
|
let sequencesNumbers = dosages.map((d)=>d.sequence).filter((s)=>s !== undefined);
|
1012
1027
|
// 2. Convert it to a Set
|
@@ -1014,11 +1029,13 @@ class $8435b8d847fb3eb7$export$1c191bca55f84a03 {
|
|
1014
1029
|
// 3. We have a "sequential" situation in two cases
|
1015
1030
|
// A) No sequence number were provided
|
1016
1031
|
// B) All sequence numbers are different
|
1017
|
-
|
1018
|
-
|
1019
|
-
|
1020
|
-
|
1021
|
-
|
1032
|
+
return encounteredSequenceNumbers.size === 0 || encounteredSequenceNumbers.size === dosages.length;
|
1033
|
+
}
|
1034
|
+
/**
|
1035
|
+
* Turn this array of Dosage objects into a data structure useful to handle "sequential" and "concurrent" instructions (cf. "sequence" property).
|
1036
|
+
* @returns {Dosage[][]} - A two-dimensional array where each inner array contains Dosage objects belonging to the same sequence numberr.
|
1037
|
+
*/ groupBySequence(dosages) {
|
1038
|
+
// Prepare variables
|
1022
1039
|
let groups = {};
|
1023
1040
|
let sequences = new Set();
|
1024
1041
|
for(let idx = 0; idx < dosages.length; idx++){
|
@@ -1027,23 +1044,39 @@ class $8435b8d847fb3eb7$export$1c191bca55f84a03 {
|
|
1027
1044
|
// Get the sequence number (normally, in real world, it should be present in this case)
|
1028
1045
|
// If no sequence number, assume it is idx + 1
|
1029
1046
|
let sequenceNr = dosage.sequence || idx + 1;
|
1030
|
-
// Generate the text version
|
1031
|
-
let dosageAsText = this.fromDosageToText(dosage);
|
1032
1047
|
// Retrieve of create previous entries for this sequence number
|
1033
1048
|
let localGroup = groups[sequenceNr] || [];
|
1034
1049
|
// Add entry
|
1035
|
-
localGroup.push(
|
1050
|
+
localGroup.push(dosage);
|
1036
1051
|
// Pushback result
|
1037
1052
|
groups[sequenceNr] = localGroup;
|
1038
1053
|
// For reminder of the parsed sequence
|
1039
1054
|
sequences.add(sequenceNr);
|
1040
1055
|
}
|
1041
|
-
//
|
1042
|
-
|
1056
|
+
// By using the Set values, we are sure it is returned in the way Dosages were written
|
1057
|
+
return [
|
1043
1058
|
...sequences.values()
|
1044
1059
|
].map((sequence)=>{
|
1045
1060
|
let concurrentInstructions = groups[sequence];
|
1046
|
-
return
|
1061
|
+
return concurrentInstructions;
|
1062
|
+
});
|
1063
|
+
}
|
1064
|
+
/**
|
1065
|
+
* Turn multiple FHIR Dosage objects into text
|
1066
|
+
*/ fromMultipleDosageToText(dosages) {
|
1067
|
+
// As we can have concurrent / sequential instructions, we need a generic algorithm to do the job
|
1068
|
+
const hasOnlySequentialInstructions = this.containsOnlySequentialInstructions(dosages);
|
1069
|
+
// Sequential instructions
|
1070
|
+
if (hasOnlySequentialInstructions) {
|
1071
|
+
const dosagesAsText = dosages.map((d)=>this.fromDosageToText(d));
|
1072
|
+
return (0, $f475af73bad0ba43$export$826742c1df3eca39)(this.i18nInstance, dosagesAsText, "then");
|
1073
|
+
}
|
1074
|
+
// We have both "sequential" and "concurrent" instructions - time to see what is the configuration
|
1075
|
+
let sortedDosages = this.groupBySequence(dosages);
|
1076
|
+
// Now that data structures are filled, it is a piece of cake to generate the result
|
1077
|
+
let sequentialInstructions = sortedDosages.map((concurrentInstructions)=>{
|
1078
|
+
let concurrentInstructionsAsString = concurrentInstructions.map((dosage)=>this.fromDosageToText(dosage));
|
1079
|
+
return (0, $f475af73bad0ba43$export$826742c1df3eca39)(this.i18nInstance, concurrentInstructionsAsString, "and");
|
1047
1080
|
});
|
1048
1081
|
return (0, $f475af73bad0ba43$export$826742c1df3eca39)(this.i18nInstance, sequentialInstructions, "then");
|
1049
1082
|
}
|