ezmedicationinput 0.1.35 → 0.1.36

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/schedule.js CHANGED
@@ -433,6 +433,25 @@ function mergeFrequencyDefaults(base, override) {
433
433
  }
434
434
  return merged;
435
435
  }
436
+ function inferDailyFrequencyClocks(frequency) {
437
+ if (!Number.isFinite(frequency) || frequency <= 0) {
438
+ return [];
439
+ }
440
+ if (frequency === 1) {
441
+ return ["09:00:00"];
442
+ }
443
+ const startMinutes = 8 * 60;
444
+ const endMinutes = 20 * 60;
445
+ const spanMinutes = endMinutes - startMinutes;
446
+ const clocks = new Set();
447
+ for (let index = 0; index < frequency; index += 1) {
448
+ const minutes = startMinutes + Math.round((spanMinutes * index) / (frequency - 1));
449
+ const hour = Math.floor(minutes / SECONDS_PER_MINUTE);
450
+ const minute = minutes % SECONDS_PER_MINUTE;
451
+ clocks.add(`${pad(hour)}:${pad(minute)}:00`);
452
+ }
453
+ return Array.from(clocks).sort();
454
+ }
436
455
  /** Resolves fallback clock arrays for frequency-only schedules. */
437
456
  function resolveFrequencyClocks(timing, config) {
438
457
  var _a, _b, _c, _d, _e, _f, _g, _h, _j, _k;
@@ -462,6 +481,11 @@ function resolveFrequencyClocks(timing, config) {
462
481
  collected.add(normalizeClock(clock));
463
482
  }
464
483
  }
484
+ if (collected.size === 0 && repeat.period === 1 && repeat.periodUnit === "d") {
485
+ for (const clock of inferDailyFrequencyClocks(repeat.frequency)) {
486
+ collected.add(clock);
487
+ }
488
+ }
465
489
  }
466
490
  return Array.from(collected).sort();
467
491
  }
@@ -561,46 +585,53 @@ function nextDueDoses(dosage, options) {
561
585
  if (results.length >= effectiveLimit) {
562
586
  return results.slice(0, effectiveLimit);
563
587
  }
564
- if (expanded.length === 0) {
565
- return results.slice(0, effectiveLimit);
566
- }
567
- let currentDay = startOfLocalDay(from, timeZone);
568
- let iterations = 0;
569
- const maxIterations = effectiveLimit * 31;
570
- while (results.length < effectiveLimit && iterations < maxIterations) {
571
- const weekday = getLocalWeekday(currentDay, timeZone);
572
- if (!enforceDayFilter || dayFilter.has(weekday)) {
573
- for (const entry of expanded) {
574
- const targetDay = entry.dayShift === 0
575
- ? currentDay
576
- : addLocalDays(currentDay, entry.dayShift, timeZone);
577
- const zoned = makeZonedDateFromDay(targetDay, timeZone, entry.time);
578
- if (!zoned) {
579
- continue;
580
- }
581
- if (zoned < from) {
582
- continue;
583
- }
584
- if (orderedAt && zoned < orderedAt) {
585
- continue;
586
- }
587
- const iso = formatZonedIso(zoned, timeZone);
588
- if (!seen.has(iso)) {
589
- seen.add(iso);
590
- results.push(iso);
591
- if (results.length === effectiveLimit) {
592
- break;
588
+ const canFallbackToFrequency = expanded.length === 0 &&
589
+ timeOfDayEntries.length === 0 &&
590
+ !!repeat.frequency &&
591
+ !!repeat.period &&
592
+ !!repeat.periodUnit;
593
+ if (!canFallbackToFrequency) {
594
+ if (expanded.length === 0) {
595
+ return results.slice(0, effectiveLimit);
596
+ }
597
+ let currentDay = startOfLocalDay(from, timeZone);
598
+ let iterations = 0;
599
+ const maxIterations = effectiveLimit * 31;
600
+ while (results.length < effectiveLimit && iterations < maxIterations) {
601
+ const weekday = getLocalWeekday(currentDay, timeZone);
602
+ if (!enforceDayFilter || dayFilter.has(weekday)) {
603
+ for (const entry of expanded) {
604
+ const targetDay = entry.dayShift === 0
605
+ ? currentDay
606
+ : addLocalDays(currentDay, entry.dayShift, timeZone);
607
+ const zoned = makeZonedDateFromDay(targetDay, timeZone, entry.time);
608
+ if (!zoned) {
609
+ continue;
610
+ }
611
+ if (zoned < from) {
612
+ continue;
613
+ }
614
+ if (orderedAt && zoned < orderedAt) {
615
+ continue;
616
+ }
617
+ const iso = formatZonedIso(zoned, timeZone);
618
+ if (!seen.has(iso)) {
619
+ seen.add(iso);
620
+ results.push(iso);
621
+ if (results.length === effectiveLimit) {
622
+ break;
623
+ }
593
624
  }
594
625
  }
595
626
  }
627
+ if (results.length >= effectiveLimit) {
628
+ break;
629
+ }
630
+ currentDay = addLocalDays(currentDay, 1, timeZone);
631
+ iterations += 1;
596
632
  }
597
- if (results.length >= effectiveLimit) {
598
- break;
599
- }
600
- currentDay = addLocalDays(currentDay, 1, timeZone);
601
- iterations += 1;
633
+ return results.slice(0, effectiveLimit);
602
634
  }
603
- return results.slice(0, effectiveLimit);
604
635
  }
605
636
  const treatAsInterval = !!repeat.period &&
606
637
  !!repeat.periodUnit &&
@@ -705,35 +736,42 @@ function derivePriorCountFromHistory(timing, repeat, config, orderedAt, from, ti
705
736
  return count;
706
737
  }
707
738
  }
708
- if (expanded.length === 0) {
709
- return count;
710
- }
711
- let currentDay = startOfLocalDay(orderedAt, timeZone);
712
- let iterations = 0;
713
- const maxIterations = normalizedCount !== undefined ? normalizedCount * 31 : 31 * 365;
714
- while (currentDay < from && iterations < maxIterations) {
715
- const weekday = getLocalWeekday(currentDay, timeZone);
716
- if (!enforceDayFilter || dayFilter.has(weekday)) {
717
- for (const entry of expanded) {
718
- const targetDay = entry.dayShift === 0
719
- ? currentDay
720
- : addLocalDays(currentDay, entry.dayShift, timeZone);
721
- const zoned = makeZonedDateFromDay(targetDay, timeZone, entry.time);
722
- if (!zoned) {
723
- continue;
724
- }
725
- if (zoned < orderedAt || zoned >= from) {
726
- continue;
727
- }
728
- if (recordCandidate(zoned) && normalizedCount !== undefined && seen.size >= normalizedCount) {
729
- return count;
739
+ const canFallbackToFrequency = expanded.length === 0 &&
740
+ timeOfDayEntries.length === 0 &&
741
+ !!repeat.frequency &&
742
+ !!repeat.period &&
743
+ !!repeat.periodUnit;
744
+ if (!canFallbackToFrequency) {
745
+ if (expanded.length === 0) {
746
+ return count;
747
+ }
748
+ let currentDay = startOfLocalDay(orderedAt, timeZone);
749
+ let iterations = 0;
750
+ const maxIterations = normalizedCount !== undefined ? normalizedCount * 31 : 31 * 365;
751
+ while (currentDay < from && iterations < maxIterations) {
752
+ const weekday = getLocalWeekday(currentDay, timeZone);
753
+ if (!enforceDayFilter || dayFilter.has(weekday)) {
754
+ for (const entry of expanded) {
755
+ const targetDay = entry.dayShift === 0
756
+ ? currentDay
757
+ : addLocalDays(currentDay, entry.dayShift, timeZone);
758
+ const zoned = makeZonedDateFromDay(targetDay, timeZone, entry.time);
759
+ if (!zoned) {
760
+ continue;
761
+ }
762
+ if (zoned < orderedAt || zoned >= from) {
763
+ continue;
764
+ }
765
+ if (recordCandidate(zoned) && normalizedCount !== undefined && seen.size >= normalizedCount) {
766
+ return count;
767
+ }
730
768
  }
731
769
  }
770
+ currentDay = addLocalDays(currentDay, 1, timeZone);
771
+ iterations += 1;
732
772
  }
733
- currentDay = addLocalDays(currentDay, 1, timeZone);
734
- iterations += 1;
773
+ return count;
735
774
  }
736
- return count;
737
775
  }
738
776
  const treatAsInterval = !!repeat.period &&
739
777
  !!repeat.periodUnit &&
@@ -949,27 +987,34 @@ function countScheduleEvents(dosage, from, to, config, baseTime, orderedAt, limi
949
987
  recordCandidate(immediateSource);
950
988
  }
951
989
  }
952
- if (expanded.length === 0)
953
- return count;
954
- let currentDay = startOfLocalDay(from, timeZone);
955
- let iterations = 0;
956
- const maxIterations = limit !== undefined ? limit * 31 : 365 * 31;
957
- while (count < (limit !== null && limit !== void 0 ? limit : Infinity) && currentDay < to && iterations < maxIterations) {
958
- const weekday = getLocalWeekday(currentDay, timeZone);
959
- if (!enforceDayFilter || dayFilter.has(weekday)) {
960
- for (const entry of expanded) {
961
- const targetDay = entry.dayShift === 0
962
- ? currentDay
963
- : addLocalDays(currentDay, entry.dayShift, timeZone);
964
- const zoned = makeZonedDateFromDay(targetDay, timeZone, entry.time);
965
- if (zoned)
966
- recordCandidate(zoned);
990
+ const canFallbackToFrequency = expanded.length === 0 &&
991
+ timeOfDayEntries.length === 0 &&
992
+ !!repeat.frequency &&
993
+ !!repeat.period &&
994
+ !!repeat.periodUnit;
995
+ if (!canFallbackToFrequency) {
996
+ if (expanded.length === 0)
997
+ return count;
998
+ let currentDay = startOfLocalDay(from, timeZone);
999
+ let iterations = 0;
1000
+ const maxIterations = limit !== undefined ? limit * 31 : 365 * 31;
1001
+ while (count < (limit !== null && limit !== void 0 ? limit : Infinity) && currentDay < to && iterations < maxIterations) {
1002
+ const weekday = getLocalWeekday(currentDay, timeZone);
1003
+ if (!enforceDayFilter || dayFilter.has(weekday)) {
1004
+ for (const entry of expanded) {
1005
+ const targetDay = entry.dayShift === 0
1006
+ ? currentDay
1007
+ : addLocalDays(currentDay, entry.dayShift, timeZone);
1008
+ const zoned = makeZonedDateFromDay(targetDay, timeZone, entry.time);
1009
+ if (zoned)
1010
+ recordCandidate(zoned);
1011
+ }
967
1012
  }
1013
+ currentDay = addLocalDays(currentDay, 1, timeZone);
1014
+ iterations += 1;
968
1015
  }
969
- currentDay = addLocalDays(currentDay, 1, timeZone);
970
- iterations += 1;
1016
+ return count;
971
1017
  }
972
- return count;
973
1018
  }
974
1019
  const treatAsInterval = !!repeat.period &&
975
1020
  !!repeat.periodUnit &&
@@ -1047,7 +1092,7 @@ function countScheduleEvents(dosage, from, to, config, baseTime, orderedAt, limi
1047
1092
  }
1048
1093
  return count;
1049
1094
  }
1050
- function calculateTotalUnits(options) {
1095
+ function calculateTotalUnitsSingle(options) {
1051
1096
  var _a, _b, _c, _d, _e, _f, _g, _h, _j, _k, _l, _m;
1052
1097
  const { dosage, durationValue, durationUnit, roundToMultiple, context } = options;
1053
1098
  const from = coerceDate(options.from, "from");
@@ -1102,3 +1147,24 @@ function calculateTotalUnits(options) {
1102
1147
  }
1103
1148
  return result;
1104
1149
  }
1150
+ function calculateTotalUnits(options) {
1151
+ if (Array.isArray(options.dosage)) {
1152
+ const hasAnyDosage = options.dosage.length > 0;
1153
+ if (!hasAnyDosage) {
1154
+ return { totalUnits: 0 };
1155
+ }
1156
+ let totalUnits = 0;
1157
+ let totalContainers = 0;
1158
+ let sawContainers = false;
1159
+ for (const dosage of options.dosage) {
1160
+ const result = calculateTotalUnitsSingle(Object.assign(Object.assign({}, options), { dosage }));
1161
+ totalUnits += result.totalUnits;
1162
+ if (result.totalContainers !== undefined) {
1163
+ totalContainers += result.totalContainers;
1164
+ sawContainers = true;
1165
+ }
1166
+ }
1167
+ return sawContainers ? { totalUnits, totalContainers } : { totalUnits };
1168
+ }
1169
+ return calculateTotalUnitsSingle(options);
1170
+ }
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;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "ezmedicationinput",
3
- "version": "0.1.35",
3
+ "version": "0.1.36",
4
4
  "description": "Parse concise medication sigs into FHIR R5 Dosage JSON",
5
5
  "type": "module",
6
6
  "main": "dist/index.js",