ezmedicationinput 0.1.35 → 0.1.37
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/dist/i18n.js +17 -0
- package/dist/schedule.js +223 -79
- package/dist/types.d.ts +1 -1
- package/package.json +1 -1
package/dist/i18n.js
CHANGED
|
@@ -551,8 +551,25 @@ function combineFrequencyAndEventsThai(frequency, events) {
|
|
|
551
551
|
}
|
|
552
552
|
return { frequency, event: joinWithAndThai(events) };
|
|
553
553
|
}
|
|
554
|
+
function isOralRouteThai(internal) {
|
|
555
|
+
var _a;
|
|
556
|
+
if (internal.routeCode === types_1.RouteCode["Oral route"]) {
|
|
557
|
+
return true;
|
|
558
|
+
}
|
|
559
|
+
const text = (_a = internal.routeText) === null || _a === void 0 ? void 0 : _a.trim().toLowerCase();
|
|
560
|
+
if (!text) {
|
|
561
|
+
return false;
|
|
562
|
+
}
|
|
563
|
+
return (text === "po" ||
|
|
564
|
+
text === "oral" ||
|
|
565
|
+
text.includes("mouth") ||
|
|
566
|
+
text.includes("per os"));
|
|
567
|
+
}
|
|
554
568
|
function buildRoutePhraseThai(internal, grammar, hasSite) {
|
|
555
569
|
var _a;
|
|
570
|
+
if (grammar.verb === "รับประทาน" && isOralRouteThai(internal)) {
|
|
571
|
+
return undefined;
|
|
572
|
+
}
|
|
556
573
|
if (typeof grammar.routePhrase === "function") {
|
|
557
574
|
return grammar.routePhrase({ hasSite, internal });
|
|
558
575
|
}
|
package/dist/schedule.js
CHANGED
|
@@ -419,6 +419,69 @@ function expandWhenCodes(whenCodes, config, repeat) {
|
|
|
419
419
|
return a.time.localeCompare(b.time);
|
|
420
420
|
});
|
|
421
421
|
}
|
|
422
|
+
const DEFAULT_WHEN_FALLBACK_CLOCKS = {
|
|
423
|
+
[types_1.EventTiming.Wake]: ["06:00:00"],
|
|
424
|
+
[types_1.EventTiming["Early Morning"]]: ["06:00:00"],
|
|
425
|
+
[types_1.EventTiming.Morning]: ["08:00:00"],
|
|
426
|
+
[types_1.EventTiming["Late Morning"]]: ["10:00:00"],
|
|
427
|
+
[types_1.EventTiming.Breakfast]: ["08:00:00"],
|
|
428
|
+
[types_1.EventTiming["Before Breakfast"]]: ["07:30:00"],
|
|
429
|
+
[types_1.EventTiming["After Breakfast"]]: ["08:30:00"],
|
|
430
|
+
[types_1.EventTiming.Noon]: ["12:00:00"],
|
|
431
|
+
[types_1.EventTiming.Lunch]: ["12:30:00"],
|
|
432
|
+
[types_1.EventTiming["Before Lunch"]]: ["12:00:00"],
|
|
433
|
+
[types_1.EventTiming["After Lunch"]]: ["13:00:00"],
|
|
434
|
+
[types_1.EventTiming["Early Afternoon"]]: ["14:00:00"],
|
|
435
|
+
[types_1.EventTiming.Afternoon]: ["15:00:00"],
|
|
436
|
+
[types_1.EventTiming["Late Afternoon"]]: ["16:00:00"],
|
|
437
|
+
[types_1.EventTiming["Early Evening"]]: ["18:00:00"],
|
|
438
|
+
[types_1.EventTiming.Evening]: ["19:00:00"],
|
|
439
|
+
[types_1.EventTiming["Late Evening"]]: ["20:00:00"],
|
|
440
|
+
[types_1.EventTiming.Dinner]: ["18:30:00"],
|
|
441
|
+
[types_1.EventTiming["Before Dinner"]]: ["18:00:00"],
|
|
442
|
+
[types_1.EventTiming["After Dinner"]]: ["19:00:00"],
|
|
443
|
+
[types_1.EventTiming.Night]: ["21:00:00"],
|
|
444
|
+
[types_1.EventTiming["Before Sleep"]]: ["22:00:00"],
|
|
445
|
+
[types_1.EventTiming["After Sleep"]]: ["06:30:00"],
|
|
446
|
+
[types_1.EventTiming.Meal]: ["08:00:00", "12:30:00", "18:30:00"],
|
|
447
|
+
[types_1.EventTiming["Before Meal"]]: ["07:30:00", "12:00:00", "18:00:00"],
|
|
448
|
+
[types_1.EventTiming["After Meal"]]: ["08:30:00", "13:00:00", "19:00:00"]
|
|
449
|
+
};
|
|
450
|
+
function inferWhenFallbackEntries(whenCodes, repeat) {
|
|
451
|
+
const entries = [];
|
|
452
|
+
const seen = new Set();
|
|
453
|
+
const addClock = (clock) => {
|
|
454
|
+
var _a;
|
|
455
|
+
const normalized = normalizeClock(clock);
|
|
456
|
+
const adjusted = repeat.offset
|
|
457
|
+
? applyOffset(normalized, (_a = repeat.offset) !== null && _a !== void 0 ? _a : 0)
|
|
458
|
+
: { time: normalized, dayShift: 0 };
|
|
459
|
+
const key = `${adjusted.dayShift}|${adjusted.time}`;
|
|
460
|
+
if (seen.has(key)) {
|
|
461
|
+
return;
|
|
462
|
+
}
|
|
463
|
+
seen.add(key);
|
|
464
|
+
entries.push(adjusted);
|
|
465
|
+
};
|
|
466
|
+
for (const code of whenCodes) {
|
|
467
|
+
if (code === types_1.EventTiming.Immediate) {
|
|
468
|
+
continue;
|
|
469
|
+
}
|
|
470
|
+
const fallbackClocks = DEFAULT_WHEN_FALLBACK_CLOCKS[code];
|
|
471
|
+
if (!fallbackClocks) {
|
|
472
|
+
continue;
|
|
473
|
+
}
|
|
474
|
+
for (const clock of fallbackClocks) {
|
|
475
|
+
addClock(clock);
|
|
476
|
+
}
|
|
477
|
+
}
|
|
478
|
+
return entries.sort((a, b) => {
|
|
479
|
+
if (a.dayShift !== b.dayShift) {
|
|
480
|
+
return a.dayShift - b.dayShift;
|
|
481
|
+
}
|
|
482
|
+
return a.time.localeCompare(b.time);
|
|
483
|
+
});
|
|
484
|
+
}
|
|
422
485
|
function mergeFrequencyDefaults(base, override) {
|
|
423
486
|
var _a, _b, _c, _d;
|
|
424
487
|
if (!base && !override) {
|
|
@@ -433,6 +496,25 @@ function mergeFrequencyDefaults(base, override) {
|
|
|
433
496
|
}
|
|
434
497
|
return merged;
|
|
435
498
|
}
|
|
499
|
+
function inferDailyFrequencyClocks(frequency) {
|
|
500
|
+
if (!Number.isFinite(frequency) || frequency <= 0) {
|
|
501
|
+
return [];
|
|
502
|
+
}
|
|
503
|
+
if (frequency === 1) {
|
|
504
|
+
return ["09:00:00"];
|
|
505
|
+
}
|
|
506
|
+
const startMinutes = 8 * 60;
|
|
507
|
+
const endMinutes = 20 * 60;
|
|
508
|
+
const spanMinutes = endMinutes - startMinutes;
|
|
509
|
+
const clocks = new Set();
|
|
510
|
+
for (let index = 0; index < frequency; index += 1) {
|
|
511
|
+
const minutes = startMinutes + Math.round((spanMinutes * index) / (frequency - 1));
|
|
512
|
+
const hour = Math.floor(minutes / SECONDS_PER_MINUTE);
|
|
513
|
+
const minute = minutes % SECONDS_PER_MINUTE;
|
|
514
|
+
clocks.add(`${pad(hour)}:${pad(minute)}:00`);
|
|
515
|
+
}
|
|
516
|
+
return Array.from(clocks).sort();
|
|
517
|
+
}
|
|
436
518
|
/** Resolves fallback clock arrays for frequency-only schedules. */
|
|
437
519
|
function resolveFrequencyClocks(timing, config) {
|
|
438
520
|
var _a, _b, _c, _d, _e, _f, _g, _h, _j, _k;
|
|
@@ -462,6 +544,11 @@ function resolveFrequencyClocks(timing, config) {
|
|
|
462
544
|
collected.add(normalizeClock(clock));
|
|
463
545
|
}
|
|
464
546
|
}
|
|
547
|
+
if (collected.size === 0 && repeat.period === 1 && repeat.periodUnit === "d") {
|
|
548
|
+
for (const clock of inferDailyFrequencyClocks(repeat.frequency)) {
|
|
549
|
+
collected.add(clock);
|
|
550
|
+
}
|
|
551
|
+
}
|
|
465
552
|
}
|
|
466
553
|
return Array.from(collected).sort();
|
|
467
554
|
}
|
|
@@ -547,6 +634,11 @@ function nextDueDoses(dosage, options) {
|
|
|
547
634
|
return a.time.localeCompare(b.time);
|
|
548
635
|
});
|
|
549
636
|
}
|
|
637
|
+
if (expanded.length === 0 &&
|
|
638
|
+
timeOfDayEntries.length === 0 &&
|
|
639
|
+
(!repeat.frequency || !repeat.period || !repeat.periodUnit)) {
|
|
640
|
+
expanded.push(...inferWhenFallbackEntries(whenCodes, repeat));
|
|
641
|
+
}
|
|
550
642
|
const includesImmediate = (0, array_1.arrayIncludes)(whenCodes, types_1.EventTiming.Immediate);
|
|
551
643
|
if (includesImmediate) {
|
|
552
644
|
const immediateSource = orderedAt !== null && orderedAt !== void 0 ? orderedAt : from;
|
|
@@ -561,46 +653,53 @@ function nextDueDoses(dosage, options) {
|
|
|
561
653
|
if (results.length >= effectiveLimit) {
|
|
562
654
|
return results.slice(0, effectiveLimit);
|
|
563
655
|
}
|
|
564
|
-
|
|
565
|
-
|
|
566
|
-
|
|
567
|
-
|
|
568
|
-
|
|
569
|
-
|
|
570
|
-
|
|
571
|
-
|
|
572
|
-
|
|
573
|
-
|
|
574
|
-
|
|
575
|
-
|
|
576
|
-
|
|
577
|
-
|
|
578
|
-
|
|
579
|
-
|
|
580
|
-
|
|
581
|
-
|
|
582
|
-
|
|
583
|
-
|
|
584
|
-
|
|
585
|
-
|
|
586
|
-
|
|
587
|
-
|
|
588
|
-
|
|
589
|
-
|
|
590
|
-
|
|
591
|
-
|
|
592
|
-
|
|
656
|
+
const canFallbackToFrequency = expanded.length === 0 &&
|
|
657
|
+
timeOfDayEntries.length === 0 &&
|
|
658
|
+
!!repeat.frequency &&
|
|
659
|
+
!!repeat.period &&
|
|
660
|
+
!!repeat.periodUnit;
|
|
661
|
+
if (!canFallbackToFrequency) {
|
|
662
|
+
if (expanded.length === 0) {
|
|
663
|
+
return results.slice(0, effectiveLimit);
|
|
664
|
+
}
|
|
665
|
+
let currentDay = startOfLocalDay(from, timeZone);
|
|
666
|
+
let iterations = 0;
|
|
667
|
+
const maxIterations = effectiveLimit * 31;
|
|
668
|
+
while (results.length < effectiveLimit && iterations < maxIterations) {
|
|
669
|
+
const weekday = getLocalWeekday(currentDay, timeZone);
|
|
670
|
+
if (!enforceDayFilter || dayFilter.has(weekday)) {
|
|
671
|
+
for (const entry of expanded) {
|
|
672
|
+
const targetDay = entry.dayShift === 0
|
|
673
|
+
? currentDay
|
|
674
|
+
: addLocalDays(currentDay, entry.dayShift, timeZone);
|
|
675
|
+
const zoned = makeZonedDateFromDay(targetDay, timeZone, entry.time);
|
|
676
|
+
if (!zoned) {
|
|
677
|
+
continue;
|
|
678
|
+
}
|
|
679
|
+
if (zoned < from) {
|
|
680
|
+
continue;
|
|
681
|
+
}
|
|
682
|
+
if (orderedAt && zoned < orderedAt) {
|
|
683
|
+
continue;
|
|
684
|
+
}
|
|
685
|
+
const iso = formatZonedIso(zoned, timeZone);
|
|
686
|
+
if (!seen.has(iso)) {
|
|
687
|
+
seen.add(iso);
|
|
688
|
+
results.push(iso);
|
|
689
|
+
if (results.length === effectiveLimit) {
|
|
690
|
+
break;
|
|
691
|
+
}
|
|
593
692
|
}
|
|
594
693
|
}
|
|
595
694
|
}
|
|
695
|
+
if (results.length >= effectiveLimit) {
|
|
696
|
+
break;
|
|
697
|
+
}
|
|
698
|
+
currentDay = addLocalDays(currentDay, 1, timeZone);
|
|
699
|
+
iterations += 1;
|
|
596
700
|
}
|
|
597
|
-
|
|
598
|
-
break;
|
|
599
|
-
}
|
|
600
|
-
currentDay = addLocalDays(currentDay, 1, timeZone);
|
|
601
|
-
iterations += 1;
|
|
701
|
+
return results.slice(0, effectiveLimit);
|
|
602
702
|
}
|
|
603
|
-
return results.slice(0, effectiveLimit);
|
|
604
703
|
}
|
|
605
704
|
const treatAsInterval = !!repeat.period &&
|
|
606
705
|
!!repeat.periodUnit &&
|
|
@@ -700,40 +799,52 @@ function derivePriorCountFromHistory(timing, repeat, config, orderedAt, from, ti
|
|
|
700
799
|
return a.time.localeCompare(b.time);
|
|
701
800
|
});
|
|
702
801
|
}
|
|
802
|
+
if (expanded.length === 0 &&
|
|
803
|
+
timeOfDayEntries.length === 0 &&
|
|
804
|
+
(!repeat.frequency || !repeat.period || !repeat.periodUnit)) {
|
|
805
|
+
expanded.push(...inferWhenFallbackEntries(whenCodes, repeat));
|
|
806
|
+
}
|
|
703
807
|
if ((0, array_1.arrayIncludes)(whenCodes, types_1.EventTiming.Immediate)) {
|
|
704
808
|
if (recordCandidate(orderedAt) && normalizedCount !== undefined && seen.size >= normalizedCount) {
|
|
705
809
|
return count;
|
|
706
810
|
}
|
|
707
811
|
}
|
|
708
|
-
|
|
709
|
-
|
|
710
|
-
|
|
711
|
-
|
|
712
|
-
|
|
713
|
-
|
|
714
|
-
|
|
715
|
-
|
|
716
|
-
|
|
717
|
-
|
|
718
|
-
|
|
719
|
-
|
|
720
|
-
|
|
721
|
-
|
|
722
|
-
|
|
723
|
-
|
|
724
|
-
|
|
725
|
-
|
|
726
|
-
|
|
727
|
-
|
|
728
|
-
|
|
729
|
-
|
|
812
|
+
const canFallbackToFrequency = expanded.length === 0 &&
|
|
813
|
+
timeOfDayEntries.length === 0 &&
|
|
814
|
+
!!repeat.frequency &&
|
|
815
|
+
!!repeat.period &&
|
|
816
|
+
!!repeat.periodUnit;
|
|
817
|
+
if (!canFallbackToFrequency) {
|
|
818
|
+
if (expanded.length === 0) {
|
|
819
|
+
return count;
|
|
820
|
+
}
|
|
821
|
+
let currentDay = startOfLocalDay(orderedAt, timeZone);
|
|
822
|
+
let iterations = 0;
|
|
823
|
+
const maxIterations = normalizedCount !== undefined ? normalizedCount * 31 : 31 * 365;
|
|
824
|
+
while (currentDay < from && iterations < maxIterations) {
|
|
825
|
+
const weekday = getLocalWeekday(currentDay, timeZone);
|
|
826
|
+
if (!enforceDayFilter || dayFilter.has(weekday)) {
|
|
827
|
+
for (const entry of expanded) {
|
|
828
|
+
const targetDay = entry.dayShift === 0
|
|
829
|
+
? currentDay
|
|
830
|
+
: addLocalDays(currentDay, entry.dayShift, timeZone);
|
|
831
|
+
const zoned = makeZonedDateFromDay(targetDay, timeZone, entry.time);
|
|
832
|
+
if (!zoned) {
|
|
833
|
+
continue;
|
|
834
|
+
}
|
|
835
|
+
if (zoned < orderedAt || zoned >= from) {
|
|
836
|
+
continue;
|
|
837
|
+
}
|
|
838
|
+
if (recordCandidate(zoned) && normalizedCount !== undefined && seen.size >= normalizedCount) {
|
|
839
|
+
return count;
|
|
840
|
+
}
|
|
730
841
|
}
|
|
731
842
|
}
|
|
843
|
+
currentDay = addLocalDays(currentDay, 1, timeZone);
|
|
844
|
+
iterations += 1;
|
|
732
845
|
}
|
|
733
|
-
|
|
734
|
-
iterations += 1;
|
|
846
|
+
return count;
|
|
735
847
|
}
|
|
736
|
-
return count;
|
|
737
848
|
}
|
|
738
849
|
const treatAsInterval = !!repeat.period &&
|
|
739
850
|
!!repeat.periodUnit &&
|
|
@@ -943,33 +1054,45 @@ function countScheduleEvents(dosage, from, to, config, baseTime, orderedAt, limi
|
|
|
943
1054
|
return a.time.localeCompare(b.time);
|
|
944
1055
|
});
|
|
945
1056
|
}
|
|
1057
|
+
if (expanded.length === 0 &&
|
|
1058
|
+
timeOfDayEntries.length === 0 &&
|
|
1059
|
+
(!repeat.frequency || !repeat.period || !repeat.periodUnit)) {
|
|
1060
|
+
expanded.push(...inferWhenFallbackEntries(whenCodes, repeat));
|
|
1061
|
+
}
|
|
946
1062
|
if ((0, array_1.arrayIncludes)(whenCodes, types_1.EventTiming.Immediate)) {
|
|
947
1063
|
const immediateSource = orderedAt !== null && orderedAt !== void 0 ? orderedAt : from;
|
|
948
1064
|
if (!orderedAt || orderedAt >= from) {
|
|
949
1065
|
recordCandidate(immediateSource);
|
|
950
1066
|
}
|
|
951
1067
|
}
|
|
952
|
-
|
|
953
|
-
|
|
954
|
-
|
|
955
|
-
|
|
956
|
-
|
|
957
|
-
|
|
958
|
-
|
|
959
|
-
|
|
960
|
-
|
|
961
|
-
|
|
962
|
-
|
|
963
|
-
|
|
964
|
-
|
|
965
|
-
|
|
966
|
-
|
|
1068
|
+
const canFallbackToFrequency = expanded.length === 0 &&
|
|
1069
|
+
timeOfDayEntries.length === 0 &&
|
|
1070
|
+
!!repeat.frequency &&
|
|
1071
|
+
!!repeat.period &&
|
|
1072
|
+
!!repeat.periodUnit;
|
|
1073
|
+
if (!canFallbackToFrequency) {
|
|
1074
|
+
if (expanded.length === 0)
|
|
1075
|
+
return count;
|
|
1076
|
+
let currentDay = startOfLocalDay(from, timeZone);
|
|
1077
|
+
let iterations = 0;
|
|
1078
|
+
const maxIterations = limit !== undefined ? limit * 31 : 365 * 31;
|
|
1079
|
+
while (count < (limit !== null && limit !== void 0 ? limit : Infinity) && currentDay < to && iterations < maxIterations) {
|
|
1080
|
+
const weekday = getLocalWeekday(currentDay, timeZone);
|
|
1081
|
+
if (!enforceDayFilter || dayFilter.has(weekday)) {
|
|
1082
|
+
for (const entry of expanded) {
|
|
1083
|
+
const targetDay = entry.dayShift === 0
|
|
1084
|
+
? currentDay
|
|
1085
|
+
: addLocalDays(currentDay, entry.dayShift, timeZone);
|
|
1086
|
+
const zoned = makeZonedDateFromDay(targetDay, timeZone, entry.time);
|
|
1087
|
+
if (zoned)
|
|
1088
|
+
recordCandidate(zoned);
|
|
1089
|
+
}
|
|
967
1090
|
}
|
|
1091
|
+
currentDay = addLocalDays(currentDay, 1, timeZone);
|
|
1092
|
+
iterations += 1;
|
|
968
1093
|
}
|
|
969
|
-
|
|
970
|
-
iterations += 1;
|
|
1094
|
+
return count;
|
|
971
1095
|
}
|
|
972
|
-
return count;
|
|
973
1096
|
}
|
|
974
1097
|
const treatAsInterval = !!repeat.period &&
|
|
975
1098
|
!!repeat.periodUnit &&
|
|
@@ -1047,7 +1170,7 @@ function countScheduleEvents(dosage, from, to, config, baseTime, orderedAt, limi
|
|
|
1047
1170
|
}
|
|
1048
1171
|
return count;
|
|
1049
1172
|
}
|
|
1050
|
-
function
|
|
1173
|
+
function calculateTotalUnitsSingle(options) {
|
|
1051
1174
|
var _a, _b, _c, _d, _e, _f, _g, _h, _j, _k, _l, _m;
|
|
1052
1175
|
const { dosage, durationValue, durationUnit, roundToMultiple, context } = options;
|
|
1053
1176
|
const from = coerceDate(options.from, "from");
|
|
@@ -1102,3 +1225,24 @@ function calculateTotalUnits(options) {
|
|
|
1102
1225
|
}
|
|
1103
1226
|
return result;
|
|
1104
1227
|
}
|
|
1228
|
+
function calculateTotalUnits(options) {
|
|
1229
|
+
if (Array.isArray(options.dosage)) {
|
|
1230
|
+
const hasAnyDosage = options.dosage.length > 0;
|
|
1231
|
+
if (!hasAnyDosage) {
|
|
1232
|
+
return { totalUnits: 0 };
|
|
1233
|
+
}
|
|
1234
|
+
let totalUnits = 0;
|
|
1235
|
+
let totalContainers = 0;
|
|
1236
|
+
let sawContainers = false;
|
|
1237
|
+
for (const dosage of options.dosage) {
|
|
1238
|
+
const result = calculateTotalUnitsSingle(Object.assign(Object.assign({}, options), { dosage }));
|
|
1239
|
+
totalUnits += result.totalUnits;
|
|
1240
|
+
if (result.totalContainers !== undefined) {
|
|
1241
|
+
totalContainers += result.totalContainers;
|
|
1242
|
+
sawContainers = true;
|
|
1243
|
+
}
|
|
1244
|
+
}
|
|
1245
|
+
return sawContainers ? { totalUnits, totalContainers } : { totalUnits };
|
|
1246
|
+
}
|
|
1247
|
+
return calculateTotalUnitsSingle(options);
|
|
1248
|
+
}
|
package/dist/types.d.ts
CHANGED
|
@@ -673,7 +673,7 @@ export interface TotalUnitsResult {
|
|
|
673
673
|
totalContainers?: number;
|
|
674
674
|
}
|
|
675
675
|
export interface TotalUnitsOptions extends NextDueDoseOptions {
|
|
676
|
-
dosage: FhirDosage;
|
|
676
|
+
dosage: FhirDosage | FhirDosage[];
|
|
677
677
|
durationValue: number;
|
|
678
678
|
durationUnit: FhirPeriodUnit;
|
|
679
679
|
roundToMultiple?: number;
|