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/main.js
CHANGED
@@ -72,43 +72,77 @@ function $5ab57a471c359130$export$7de3722258b87db9({ config: config, dos: dos, i
|
|
72
72
|
}
|
73
73
|
|
74
74
|
|
75
|
-
//
|
76
|
-
|
77
|
-
|
78
|
-
|
79
|
-
//
|
80
|
-
|
81
|
-
|
82
|
-
|
83
|
-
|
84
|
-
|
85
|
-
|
86
|
-
|
87
|
-
let unit = config.fromFHIRQuantityUnitToString({
|
75
|
+
// Utility function
|
76
|
+
// Quantity unit to string
|
77
|
+
function $9ee880701f47723b$var$transformQuantityUnitToString(i18next, quantity, config) {
|
78
|
+
let quantityValue = quantity.value;
|
79
|
+
// If common units from HL7, do the job
|
80
|
+
if (quantity.system === "http://hl7.org/fhir/ValueSet/duration-units") {
|
81
|
+
let code = quantity.code;
|
82
|
+
return i18next.t(`unitsOfTime:withoutCount.${code}`, {
|
83
|
+
count: quantityValue
|
84
|
+
});
|
85
|
+
} else // otherwise, it is UCUM, ... so let the user do the job
|
86
|
+
return config.fromFHIRQuantityUnitToString({
|
88
87
|
language: config.language,
|
89
|
-
quantity:
|
88
|
+
quantity: quantity
|
90
89
|
});
|
91
|
-
|
92
|
-
|
93
|
-
|
94
|
-
|
95
|
-
|
90
|
+
}
|
91
|
+
function $9ee880701f47723b$export$be17d167ed50d870({ range: range, config: config, i18next: i18next }) {
|
92
|
+
// Extract params
|
93
|
+
const { low: low, high: high } = range;
|
94
|
+
const lowValue = low?.value;
|
95
|
+
const highValue = high?.value;
|
96
|
+
// prepare unit display
|
97
|
+
let quantityUnit = high || low;
|
98
|
+
let hasUnit = quantityUnit?.unit !== undefined || quantityUnit?.code !== undefined;
|
99
|
+
// Four cases
|
100
|
+
// 1. If we have a empty object, return undefined
|
101
|
+
if (lowValue === undefined && highValue === undefined) return undefined;
|
102
|
+
// quantity unit
|
103
|
+
let unit = hasUnit ? $9ee880701f47723b$var$transformQuantityUnitToString(i18next, quantityUnit, config) : "";
|
104
|
+
let technicalKey = hasUnit ? "withUnit" : "withoutUnit";
|
105
|
+
// 2. Both low & high are present
|
106
|
+
if (lowValue !== undefined && highValue !== undefined) return i18next.t(`amount.range.${technicalKey}.lowAndHigh`, {
|
107
|
+
low: lowValue,
|
108
|
+
high: highValue,
|
96
109
|
unit: unit
|
97
110
|
});
|
98
|
-
//
|
99
|
-
if (
|
100
|
-
high:
|
111
|
+
// 3. Only high is present
|
112
|
+
if (highValue !== undefined) return i18next.t(`amount.range.${technicalKey}.onlyHigh`, {
|
113
|
+
high: highValue,
|
101
114
|
unit: unit
|
102
115
|
});
|
103
|
-
//
|
116
|
+
// 4. Only low is present
|
104
117
|
// Warning, this case is kind dangerous and clinically unsafe so minimal effort on this ...
|
105
|
-
return i18next.t(
|
106
|
-
low:
|
118
|
+
return i18next.t(`amount.range.${technicalKey}.onlyLow`, {
|
119
|
+
low: lowValue,
|
107
120
|
unit: unit
|
108
121
|
});
|
109
122
|
}
|
110
123
|
|
111
124
|
|
125
|
+
function $9a073aa5b09aa778$export$4cd16590995531a9({ dos: dos, config: config, i18next: i18next }) {
|
126
|
+
// If empty, return undefined
|
127
|
+
if (dos.doseAndRate === undefined) return undefined;
|
128
|
+
// Find the first entry that match criteria
|
129
|
+
let doseRange = dos.doseAndRate.find((s)=>s.doseRange !== undefined);
|
130
|
+
// If not found, skip
|
131
|
+
if (doseRange === undefined) return undefined;
|
132
|
+
// Turn range into a text
|
133
|
+
const text = (0, $9ee880701f47723b$export$be17d167ed50d870)({
|
134
|
+
range: doseRange.doseRange,
|
135
|
+
config: config,
|
136
|
+
i18next: i18next
|
137
|
+
});
|
138
|
+
// Reject if empty
|
139
|
+
if (text === undefined) return undefined;
|
140
|
+
return i18next.t("fields.doseRange", {
|
141
|
+
rangeText: text
|
142
|
+
});
|
143
|
+
}
|
144
|
+
|
145
|
+
|
112
146
|
// types
|
113
147
|
function $052c79abb28cba29$export$4e24ef8c7997cc56({ dos: dos, config: config, i18next: i18next }) {
|
114
148
|
// If empty, return undefined
|
@@ -131,72 +165,91 @@ function $052c79abb28cba29$export$4e24ef8c7997cc56({ dos: dos, config: config, i
|
|
131
165
|
}
|
132
166
|
|
133
167
|
|
134
|
-
//
|
168
|
+
// Utility function
|
169
|
+
|
135
170
|
function $703b645b55481398$export$d3dd7d3522271dba({ dos: dos, config: config, i18next: i18next }) {
|
136
171
|
// If empty, return undefined
|
137
172
|
if (dos.doseAndRate === undefined) return undefined;
|
138
173
|
// Find the first entry that match criteria
|
139
|
-
let
|
174
|
+
let doseAndRate = dos.doseAndRate.find((s)=>s.rateRange !== undefined);
|
140
175
|
// If not found, skip
|
141
|
-
if (
|
142
|
-
//
|
143
|
-
|
144
|
-
|
145
|
-
|
146
|
-
|
147
|
-
// quantity unit
|
148
|
-
let unit = config.fromFHIRQuantityUnitToString({
|
149
|
-
language: config.language,
|
150
|
-
quantity: high || low
|
176
|
+
if (doseAndRate === undefined) return undefined;
|
177
|
+
// Turn range into a text
|
178
|
+
const rangeText = (0, $9ee880701f47723b$export$be17d167ed50d870)({
|
179
|
+
range: doseAndRate.rateRange,
|
180
|
+
config: config,
|
181
|
+
i18next: i18next
|
151
182
|
});
|
152
|
-
//
|
153
|
-
|
154
|
-
|
155
|
-
|
156
|
-
|
157
|
-
unit: unit
|
158
|
-
});
|
159
|
-
// 2. Only high is present
|
160
|
-
if (quantityHigh !== undefined) return i18next.t("fields.rateRange.onlyHigh", {
|
161
|
-
high: quantityHigh,
|
162
|
-
unit: unit
|
163
|
-
});
|
164
|
-
// 3. Only low is present
|
165
|
-
// Warning, this case is kind dangerous and clinically unsafe so minimal effort on this ...
|
166
|
-
return i18next.t("fields.rateRange.onlyLow", {
|
167
|
-
low: quantityLow,
|
168
|
-
unit: unit
|
183
|
+
// Reject if empty
|
184
|
+
if (rangeText === undefined) return undefined;
|
185
|
+
// return the final string
|
186
|
+
return i18next.t("fields.rateRange", {
|
187
|
+
rangeText: rangeText
|
169
188
|
});
|
170
189
|
}
|
171
190
|
|
172
191
|
|
173
|
-
//
|
174
|
-
function $
|
175
|
-
|
176
|
-
|
177
|
-
|
178
|
-
|
179
|
-
|
180
|
-
if (rateRatio === undefined) return undefined;
|
181
|
-
// num / dem
|
182
|
-
let numerator = rateRatio.rateRatio.numerator;
|
183
|
-
let denominator = rateRatio.rateRatio.denominator;
|
184
|
-
let quantityNum = numerator?.value || 1;
|
185
|
-
let quantityDenom = denominator?.value || 1;
|
192
|
+
// Quantity has an unit ?
|
193
|
+
function $7895e9944cc835ce$var$hasUnit(quantity) {
|
194
|
+
return (quantity?.unit || quantity?.code) !== undefined;
|
195
|
+
}
|
196
|
+
function $7895e9944cc835ce$export$fdc6e9cbd31555fb({ ratio: ratio, config: config, i18next: i18next }) {
|
197
|
+
// Extract params
|
198
|
+
const { denominator: denominator, numerator: numerator } = ratio;
|
186
199
|
// units as text
|
187
|
-
let numeratorUnit = numerator
|
200
|
+
let numeratorUnit = $7895e9944cc835ce$var$hasUnit(numerator) ? config.fromFHIRQuantityUnitToString({
|
188
201
|
language: config.language,
|
189
202
|
quantity: numerator
|
190
|
-
}) :
|
191
|
-
let denominatorUnit = denominator
|
203
|
+
}) : undefined;
|
204
|
+
let denominatorUnit = $7895e9944cc835ce$var$hasUnit(denominator) ? config.fromFHIRQuantityUnitToString({
|
192
205
|
language: config.language,
|
193
206
|
quantity: denominator
|
194
|
-
}) :
|
195
|
-
|
196
|
-
|
197
|
-
|
198
|
-
|
199
|
-
|
207
|
+
}) : undefined;
|
208
|
+
// quantity
|
209
|
+
let quantityNumerator = numerator?.value;
|
210
|
+
let quantityDenominator = denominator?.value;
|
211
|
+
// Collect
|
212
|
+
const parts = [];
|
213
|
+
// Deal with numerator first
|
214
|
+
if (quantityNumerator !== undefined) {
|
215
|
+
let technicalKey = numeratorUnit !== undefined ? "withUnit" : "withoutUnit";
|
216
|
+
const numeratorString = i18next.t(`amount.ratio.${technicalKey}.numerator`, {
|
217
|
+
count: quantityNumerator,
|
218
|
+
numeratorUnit: numeratorUnit
|
219
|
+
});
|
220
|
+
parts.push(numeratorString);
|
221
|
+
}
|
222
|
+
// Deal with denominator
|
223
|
+
if (quantityDenominator !== undefined) {
|
224
|
+
let technicalKey = denominatorUnit !== undefined ? "withUnit" : "withoutUnit";
|
225
|
+
const denominatorString = i18next.t(`amount.ratio.${technicalKey}.denominator`, {
|
226
|
+
count: quantityDenominator,
|
227
|
+
denominatorUnit: denominatorUnit
|
228
|
+
});
|
229
|
+
parts.push(denominatorString);
|
230
|
+
}
|
231
|
+
// Concatenate the result
|
232
|
+
if (parts.length === 0) return undefined;
|
233
|
+
else return parts.join(" ");
|
234
|
+
}
|
235
|
+
|
236
|
+
|
237
|
+
function $301791f33da707fa$export$b71cfd2510242de2({ dos: dos, config: config, i18next: i18next }) {
|
238
|
+
// If empty, return undefined
|
239
|
+
if (dos.doseAndRate === undefined) return undefined;
|
240
|
+
// Find the first entry that match criteria
|
241
|
+
let doseAndRate = dos.doseAndRate.find((s)=>s.rateRatio !== undefined);
|
242
|
+
// If not found, skip
|
243
|
+
if (doseAndRate === undefined) return undefined;
|
244
|
+
// Turn ratio to text
|
245
|
+
const ratioText = (0, $7895e9944cc835ce$export$fdc6e9cbd31555fb)({
|
246
|
+
config: config,
|
247
|
+
i18next: i18next,
|
248
|
+
ratio: doseAndRate.rateRatio
|
249
|
+
});
|
250
|
+
if (ratioText === undefined) return undefined;
|
251
|
+
return i18next.t("fields.rateRatio", {
|
252
|
+
ratioText: ratioText
|
200
253
|
});
|
201
254
|
}
|
202
255
|
|
@@ -496,21 +549,7 @@ function $9d632517596957df$export$b927a06bc51aea32({ dos: dos, config: config, i
|
|
496
549
|
|
497
550
|
|
498
551
|
// types
|
499
|
-
|
500
|
-
function $2da391a8a8345a3d$var$transformQuantityUnitToString(i18next, quantity, config) {
|
501
|
-
let quantityValue = quantity.value;
|
502
|
-
// If common units from HL7, do the job
|
503
|
-
if (quantity.system === "http://hl7.org/fhir/ValueSet/duration-units") {
|
504
|
-
let code = quantity.code;
|
505
|
-
return i18next.t(`unitsOfTime:withoutCount.${code}`, {
|
506
|
-
count: quantityValue
|
507
|
-
});
|
508
|
-
} else // otherwise, it is UCUM, ... so let the user do the job
|
509
|
-
return config.fromFHIRQuantityUnitToString({
|
510
|
-
language: config.language,
|
511
|
-
quantity: quantity
|
512
|
-
});
|
513
|
-
}
|
552
|
+
|
514
553
|
function $2da391a8a8345a3d$export$8c667cbf7bebaa93({ dos: dos, config: config, i18next: i18next }) {
|
515
554
|
// If empty, return undefined
|
516
555
|
if (dos.timing === undefined || dos.timing.repeat === undefined) return undefined;
|
@@ -520,26 +559,17 @@ function $2da391a8a8345a3d$export$8c667cbf7bebaa93({ dos: dos, config: config, i
|
|
520
559
|
// Do nothing if no boundsRange, I am not a wizard
|
521
560
|
if (boundsRange === undefined) return undefined;
|
522
561
|
else {
|
523
|
-
|
524
|
-
|
525
|
-
|
526
|
-
|
527
|
-
|
528
|
-
// 1. Both low & high are present
|
529
|
-
if (high !== undefined && low !== undefined) return i18next.t("fields.boundsRange.lowAndHigh", {
|
530
|
-
low: low.value,
|
531
|
-
high: high.value,
|
532
|
-
unit: unit
|
533
|
-
});
|
534
|
-
// 2. Only high is present
|
535
|
-
if (high !== undefined) return i18next.t("fields.boundsRange.onlyHigh", {
|
536
|
-
high: high.value,
|
537
|
-
unit: unit
|
562
|
+
// Turn range into a text
|
563
|
+
const rangeText = (0, $9ee880701f47723b$export$be17d167ed50d870)({
|
564
|
+
range: boundsRange,
|
565
|
+
config: config,
|
566
|
+
i18next: i18next
|
538
567
|
});
|
539
|
-
//
|
540
|
-
|
541
|
-
|
542
|
-
|
568
|
+
// Reject if empty
|
569
|
+
if (rangeText === undefined) return undefined;
|
570
|
+
// return the final string
|
571
|
+
return i18next.t("fields.boundsRange", {
|
572
|
+
rangeText: rangeText
|
543
573
|
});
|
544
574
|
}
|
545
575
|
}
|
@@ -764,6 +794,7 @@ function $45256d2a188dcbd7$export$75a89431d80a701a({ dos: dos, config: config, i
|
|
764
794
|
|
765
795
|
|
766
796
|
|
797
|
+
|
767
798
|
function $39ffdeadc450f558$export$346b11a8cb220f02({ dos: dos, config: config, i18next: i18next }) {
|
768
799
|
// If empty, return undefined
|
769
800
|
if (dos.maxDosePerPeriod === undefined) return undefined;
|
@@ -778,29 +809,14 @@ function $39ffdeadc450f558$export$346b11a8cb220f02({ dos: dos, config: config, i
|
|
778
809
|
if (values.length === 0) return undefined;
|
779
810
|
// Periods are expressed as ratio (like rateRatio)
|
780
811
|
const valuesAsString = values.map((period)=>{
|
781
|
-
|
782
|
-
|
783
|
-
|
784
|
-
|
785
|
-
let quantityDenom = denominator?.value || 1;
|
786
|
-
// units as text
|
787
|
-
let numeratorUnit = numerator !== undefined ? config.fromFHIRQuantityUnitToString({
|
788
|
-
language: config.language,
|
789
|
-
quantity: numerator
|
790
|
-
}) : "";
|
791
|
-
let denominatorUnit = denominator !== undefined ? config.fromFHIRQuantityUnitToString({
|
792
|
-
language: config.language,
|
793
|
-
quantity: denominator
|
794
|
-
}) : "";
|
795
|
-
return i18next.t("fields.maxDosePerPeriod.maxDosePerPeriod", {
|
796
|
-
count: quantityDenom,
|
797
|
-
quantityNumerator: quantityNum,
|
798
|
-
numeratorUnit: numeratorUnit,
|
799
|
-
denominatorUnit: denominatorUnit
|
812
|
+
return (0, $7895e9944cc835ce$export$fdc6e9cbd31555fb)({
|
813
|
+
config: config,
|
814
|
+
i18next: i18next,
|
815
|
+
ratio: period
|
800
816
|
});
|
801
|
-
});
|
817
|
+
}).filter((s)=>s !== undefined);
|
802
818
|
const maxDosePerPeriodText = (0, $93b58b7d2ead3b95$export$826742c1df3eca39)(i18next, valuesAsString);
|
803
|
-
return i18next.t("fields.maxDosePerPeriod
|
819
|
+
return i18next.t("fields.maxDosePerPeriod", {
|
804
820
|
count: values.length,
|
805
821
|
maxDosePerPeriodText: maxDosePerPeriodText
|
806
822
|
});
|
@@ -1020,9 +1036,8 @@ class $74b0cf9d3dbd5b46$export$1c191bca55f84a03 {
|
|
1020
1036
|
return this.getFields(dos, ...order);
|
1021
1037
|
}
|
1022
1038
|
/**
|
1023
|
-
*
|
1024
|
-
*/
|
1025
|
-
// As we can have concurrent / sequential instructions, we need a generic algorithm to do the job
|
1039
|
+
* Does this array of Dosage objects contains only "sequential" instructions ?
|
1040
|
+
*/ containsOnlySequentialInstructions(dosages) {
|
1026
1041
|
// 1. Collect all sequences number
|
1027
1042
|
let sequencesNumbers = dosages.map((d)=>d.sequence).filter((s)=>s !== undefined);
|
1028
1043
|
// 2. Convert it to a Set
|
@@ -1030,11 +1045,13 @@ class $74b0cf9d3dbd5b46$export$1c191bca55f84a03 {
|
|
1030
1045
|
// 3. We have a "sequential" situation in two cases
|
1031
1046
|
// A) No sequence number were provided
|
1032
1047
|
// B) All sequence numbers are different
|
1033
|
-
|
1034
|
-
|
1035
|
-
|
1036
|
-
|
1037
|
-
|
1048
|
+
return encounteredSequenceNumbers.size === 0 || encounteredSequenceNumbers.size === dosages.length;
|
1049
|
+
}
|
1050
|
+
/**
|
1051
|
+
* Turn this array of Dosage objects into a data structure useful to handle "sequential" and "concurrent" instructions (cf. "sequence" property).
|
1052
|
+
* @returns {Dosage[][]} - A two-dimensional array where each inner array contains Dosage objects belonging to the same sequence numberr.
|
1053
|
+
*/ groupBySequence(dosages) {
|
1054
|
+
// Prepare variables
|
1038
1055
|
let groups = {};
|
1039
1056
|
let sequences = new Set();
|
1040
1057
|
for(let idx = 0; idx < dosages.length; idx++){
|
@@ -1043,23 +1060,39 @@ class $74b0cf9d3dbd5b46$export$1c191bca55f84a03 {
|
|
1043
1060
|
// Get the sequence number (normally, in real world, it should be present in this case)
|
1044
1061
|
// If no sequence number, assume it is idx + 1
|
1045
1062
|
let sequenceNr = dosage.sequence || idx + 1;
|
1046
|
-
// Generate the text version
|
1047
|
-
let dosageAsText = this.fromDosageToText(dosage);
|
1048
1063
|
// Retrieve of create previous entries for this sequence number
|
1049
1064
|
let localGroup = groups[sequenceNr] || [];
|
1050
1065
|
// Add entry
|
1051
|
-
localGroup.push(
|
1066
|
+
localGroup.push(dosage);
|
1052
1067
|
// Pushback result
|
1053
1068
|
groups[sequenceNr] = localGroup;
|
1054
1069
|
// For reminder of the parsed sequence
|
1055
1070
|
sequences.add(sequenceNr);
|
1056
1071
|
}
|
1057
|
-
//
|
1058
|
-
|
1072
|
+
// By using the Set values, we are sure it is returned in the way Dosages were written
|
1073
|
+
return [
|
1059
1074
|
...sequences.values()
|
1060
1075
|
].map((sequence)=>{
|
1061
1076
|
let concurrentInstructions = groups[sequence];
|
1062
|
-
return
|
1077
|
+
return concurrentInstructions;
|
1078
|
+
});
|
1079
|
+
}
|
1080
|
+
/**
|
1081
|
+
* Turn multiple FHIR Dosage objects into text
|
1082
|
+
*/ fromMultipleDosageToText(dosages) {
|
1083
|
+
// As we can have concurrent / sequential instructions, we need a generic algorithm to do the job
|
1084
|
+
const hasOnlySequentialInstructions = this.containsOnlySequentialInstructions(dosages);
|
1085
|
+
// Sequential instructions
|
1086
|
+
if (hasOnlySequentialInstructions) {
|
1087
|
+
const dosagesAsText = dosages.map((d)=>this.fromDosageToText(d));
|
1088
|
+
return (0, $93b58b7d2ead3b95$export$826742c1df3eca39)(this.i18nInstance, dosagesAsText, "then");
|
1089
|
+
}
|
1090
|
+
// We have both "sequential" and "concurrent" instructions - time to see what is the configuration
|
1091
|
+
let sortedDosages = this.groupBySequence(dosages);
|
1092
|
+
// Now that data structures are filled, it is a piece of cake to generate the result
|
1093
|
+
let sequentialInstructions = sortedDosages.map((concurrentInstructions)=>{
|
1094
|
+
let concurrentInstructionsAsString = concurrentInstructions.map((dosage)=>this.fromDosageToText(dosage));
|
1095
|
+
return (0, $93b58b7d2ead3b95$export$826742c1df3eca39)(this.i18nInstance, concurrentInstructionsAsString, "and");
|
1063
1096
|
});
|
1064
1097
|
return (0, $93b58b7d2ead3b95$export$826742c1df3eca39)(this.i18nInstance, sequentialInstructions, "then");
|
1065
1098
|
}
|