ezmedicationinput 0.1.26 → 0.1.28
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/format.js +5 -1
- package/dist/i18n.js +63 -3
- package/dist/maps.js +7 -0
- package/dist/parser.js +69 -24
- package/dist/suggest.js +56 -2
- package/package.json +1 -1
package/dist/format.js
CHANGED
|
@@ -587,6 +587,7 @@ function formatLong(internal) {
|
|
|
587
587
|
const frequencyPart = describeFrequency(internal);
|
|
588
588
|
const eventParts = collectWhenPhrases(internal);
|
|
589
589
|
if ((_b = internal.timeOfDay) === null || _b === void 0 ? void 0 : _b.length) {
|
|
590
|
+
const timeStrings = [];
|
|
590
591
|
for (const time of internal.timeOfDay) {
|
|
591
592
|
const parts = time.split(":");
|
|
592
593
|
const h = parseInt(parts[0], 10);
|
|
@@ -594,7 +595,10 @@ function formatLong(internal) {
|
|
|
594
595
|
const isAm = h < 12;
|
|
595
596
|
const displayH = h % 12 || 12;
|
|
596
597
|
const displayM = m < 10 ? `0${m}` : `${m}`;
|
|
597
|
-
|
|
598
|
+
timeStrings.push(`${displayH}:${displayM}${isAm ? " am" : " pm"}`);
|
|
599
|
+
}
|
|
600
|
+
if (timeStrings.length > 0) {
|
|
601
|
+
eventParts.push(`at ${timeStrings.join(", ")}`);
|
|
598
602
|
}
|
|
599
603
|
}
|
|
600
604
|
const timing = combineFrequencyAndEvents(frequencyPart, eventParts);
|
package/dist/i18n.js
CHANGED
|
@@ -116,6 +116,16 @@ const WHEN_TEXT_THAI = {
|
|
|
116
116
|
[types_1.EventTiming["After Sleep"]]: "หลังจากนอน",
|
|
117
117
|
[types_1.EventTiming.Immediate]: "ทันที"
|
|
118
118
|
};
|
|
119
|
+
const INSTRUCTION_TEXT_THAI = {
|
|
120
|
+
"Take with or after food": "รับประทานพร้อมหรือหลังอาหาร",
|
|
121
|
+
"With or after food": "พร้อมหรือหลังอาหาร",
|
|
122
|
+
"Take before food": "รับประทานก่อนอาหาร",
|
|
123
|
+
"Take on an empty stomach": "รับประทานขณะท้องว่าง",
|
|
124
|
+
"Take with plenty of water": "รับประทานพร้อมน้ำดื่มจำนวนมาก",
|
|
125
|
+
"Dissolve or mix with water before taking": "ละลายหรือผสมน้ำก่อนรับประทาน",
|
|
126
|
+
"Avoid alcoholic drinks": "หลีกเลี่ยงเครื่องดื่มแอลกอฮอล์",
|
|
127
|
+
"May cause drowsiness; do not drive if affected": "อาจทำให้ง่วงซึม; ห้ามขับขี่ยานพาหนะหรือทำงานกับเครื่องจักรหากมีอาการ",
|
|
128
|
+
};
|
|
119
129
|
const DAY_NAMES_THAI = {
|
|
120
130
|
mon: "วันจันทร์",
|
|
121
131
|
tue: "วันอังคาร",
|
|
@@ -634,6 +644,7 @@ function formatAsNeededThai(internal) {
|
|
|
634
644
|
return "ใช้เมื่อจำเป็น";
|
|
635
645
|
}
|
|
636
646
|
function formatShortThai(internal) {
|
|
647
|
+
var _a;
|
|
637
648
|
const parts = [];
|
|
638
649
|
const dose = formatDoseThaiShort(internal);
|
|
639
650
|
if (dose) {
|
|
@@ -671,6 +682,10 @@ function formatShortThai(internal) {
|
|
|
671
682
|
parts.push(events.join(" "));
|
|
672
683
|
}
|
|
673
684
|
}
|
|
685
|
+
if ((_a = internal.timeOfDay) === null || _a === void 0 ? void 0 : _a.length) {
|
|
686
|
+
const times = internal.timeOfDay.map((t) => t.slice(0, 5)).join(",");
|
|
687
|
+
parts.push(times);
|
|
688
|
+
}
|
|
674
689
|
if (internal.dayOfWeek.length) {
|
|
675
690
|
const days = internal.dayOfWeek
|
|
676
691
|
.map((d) => { var _a, _b; return (_b = (_a = DAY_NAMES_THAI[d]) === null || _a === void 0 ? void 0 : _a.replace(/^วัน/, "")) !== null && _b !== void 0 ? _b : d; })
|
|
@@ -687,13 +702,27 @@ function formatShortThai(internal) {
|
|
|
687
702
|
return parts.filter(Boolean).join(" ");
|
|
688
703
|
}
|
|
689
704
|
function formatLongThai(internal) {
|
|
690
|
-
var _a;
|
|
705
|
+
var _a, _b;
|
|
691
706
|
const grammar = resolveRouteGrammarThai(internal);
|
|
692
707
|
const dosePart = (_a = formatDoseThaiLong(internal)) !== null && _a !== void 0 ? _a : "ยา";
|
|
693
708
|
const sitePart = formatSiteThai(internal, grammar);
|
|
694
709
|
const routePart = buildRoutePhraseThai(internal, grammar, Boolean(sitePart));
|
|
695
710
|
const frequencyPart = describeFrequencyThai(internal);
|
|
696
711
|
const eventParts = collectWhenPhrasesThai(internal);
|
|
712
|
+
if ((_b = internal.timeOfDay) === null || _b === void 0 ? void 0 : _b.length) {
|
|
713
|
+
const timeStrings = [];
|
|
714
|
+
for (const time of internal.timeOfDay) {
|
|
715
|
+
const parts = time.split(":");
|
|
716
|
+
const h = parseInt(parts[0], 10);
|
|
717
|
+
const m = parseInt(parts[1], 10);
|
|
718
|
+
const displayM = m < 10 ? `0${m}` : `${m}`;
|
|
719
|
+
const displayH = h < 10 ? `0${h}` : `${h}`;
|
|
720
|
+
timeStrings.push(`${displayH}:${displayM}`);
|
|
721
|
+
}
|
|
722
|
+
if (timeStrings.length > 0) {
|
|
723
|
+
eventParts.push(`เวลา ${timeStrings.join(", ")}`);
|
|
724
|
+
}
|
|
725
|
+
}
|
|
697
726
|
const timing = combineFrequencyAndEventsThai(frequencyPart, eventParts);
|
|
698
727
|
const dayPart = describeDayOfWeekThai(internal);
|
|
699
728
|
const countPart = internal.count !== undefined
|
|
@@ -724,9 +753,40 @@ function formatLongThai(internal) {
|
|
|
724
753
|
}
|
|
725
754
|
const body = segments.filter(Boolean).join(" ").replace(/\s+/g, " ").trim();
|
|
726
755
|
if (!body) {
|
|
727
|
-
|
|
756
|
+
const instructionText = formatAdditionalInstructionsThai(internal);
|
|
757
|
+
if (!instructionText) {
|
|
758
|
+
return `${grammar.verb}.`;
|
|
759
|
+
}
|
|
760
|
+
return `${grammar.verb}. ${instructionText}`.trim();
|
|
761
|
+
}
|
|
762
|
+
const instructionText = formatAdditionalInstructionsThai(internal);
|
|
763
|
+
const baseSentence = `${grammar.verb} ${body}.`;
|
|
764
|
+
return instructionText ? `${baseSentence} ${instructionText}` : baseSentence;
|
|
765
|
+
}
|
|
766
|
+
function formatAdditionalInstructionsThai(internal) {
|
|
767
|
+
var _a;
|
|
768
|
+
if (!((_a = internal.additionalInstructions) === null || _a === void 0 ? void 0 : _a.length)) {
|
|
769
|
+
return undefined;
|
|
770
|
+
}
|
|
771
|
+
const phrases = internal.additionalInstructions
|
|
772
|
+
.map((instruction) => {
|
|
773
|
+
var _a;
|
|
774
|
+
const original = instruction.text || ((_a = instruction.coding) === null || _a === void 0 ? void 0 : _a.display);
|
|
775
|
+
if (!original)
|
|
776
|
+
return undefined;
|
|
777
|
+
const normalized = original.trim();
|
|
778
|
+
return INSTRUCTION_TEXT_THAI[normalized] || normalized;
|
|
779
|
+
})
|
|
780
|
+
.filter((text) => Boolean(text))
|
|
781
|
+
.map((text) => text.trim())
|
|
782
|
+
.filter((text) => text.length > 0);
|
|
783
|
+
if (!phrases.length) {
|
|
784
|
+
return undefined;
|
|
728
785
|
}
|
|
729
|
-
return
|
|
786
|
+
return phrases
|
|
787
|
+
.map((phrase) => (/[.!?]$/.test(phrase) ? phrase : `${phrase}.`))
|
|
788
|
+
.join(" ")
|
|
789
|
+
.trim();
|
|
730
790
|
}
|
|
731
791
|
function stripTrailingZero(value) {
|
|
732
792
|
const text = value.toString();
|
package/dist/maps.js
CHANGED
|
@@ -673,6 +673,9 @@ exports.EVENT_TIMING_TOKENS = {
|
|
|
673
673
|
breakfast: types_1.EventTiming.Breakfast,
|
|
674
674
|
bfast: types_1.EventTiming.Breakfast,
|
|
675
675
|
brkfst: types_1.EventTiming.Breakfast,
|
|
676
|
+
meal: types_1.EventTiming.Meal,
|
|
677
|
+
meals: types_1.EventTiming.Meal,
|
|
678
|
+
food: types_1.EventTiming.Meal,
|
|
676
679
|
brk: types_1.EventTiming.Breakfast,
|
|
677
680
|
cd: types_1.EventTiming.Lunch,
|
|
678
681
|
lunch: types_1.EventTiming.Lunch,
|
|
@@ -717,6 +720,10 @@ registerMealKeywords(["dinner", "dinnertime", "supper", "suppertime"], {
|
|
|
717
720
|
pc: types_1.EventTiming["After Dinner"],
|
|
718
721
|
ac: types_1.EventTiming["Before Dinner"]
|
|
719
722
|
});
|
|
723
|
+
registerMealKeywords(["meal", "meals", "food"], {
|
|
724
|
+
pc: types_1.EventTiming["After Meal"],
|
|
725
|
+
ac: types_1.EventTiming["Before Meal"]
|
|
726
|
+
});
|
|
720
727
|
exports.MEAL_KEYWORDS = (0, object_1.objectFromEntries)(MEAL_KEYWORD_ENTRIES);
|
|
721
728
|
exports.DISCOURAGED_TOKENS = {
|
|
722
729
|
qd: "QD",
|
package/dist/parser.js
CHANGED
|
@@ -781,15 +781,40 @@ function tryParseTimeBasedSchedule(internal, tokens, index) {
|
|
|
781
781
|
const token = tokens[index];
|
|
782
782
|
if (internal.consumed.has(token.index))
|
|
783
783
|
return false;
|
|
784
|
-
|
|
785
|
-
|
|
784
|
+
// Handle connectors like "and at" or just "and" before a time.
|
|
785
|
+
// This prevents rogue "and" from leaking into Additional Instructions
|
|
786
|
+
// when it serves as a connector between schedule parts.
|
|
787
|
+
let isAndPrefix = false;
|
|
788
|
+
let isAtPrefix = token.lower === "@" || token.lower === "at";
|
|
789
|
+
if (token.lower === "and" && !isAtPrefix) {
|
|
790
|
+
const next = tokens[index + 1];
|
|
791
|
+
if (next && !internal.consumed.has(next.index)) {
|
|
792
|
+
const nextLower = next.lower;
|
|
793
|
+
// If "and" is followed by "at", "@", or a number, it's a connector for this time block
|
|
794
|
+
if (nextLower === "@" || nextLower === "at" || /^\d/.test(nextLower)) {
|
|
795
|
+
isAndPrefix = true;
|
|
796
|
+
if (nextLower === "@" || nextLower === "at") {
|
|
797
|
+
isAtPrefix = true;
|
|
798
|
+
}
|
|
799
|
+
}
|
|
800
|
+
}
|
|
801
|
+
}
|
|
802
|
+
if (!isAtPrefix && !isAndPrefix && !/^\d/.test(token.lower))
|
|
786
803
|
return false;
|
|
787
|
-
let nextIndex =
|
|
804
|
+
let nextIndex = index;
|
|
805
|
+
if (isAndPrefix)
|
|
806
|
+
nextIndex++;
|
|
807
|
+
if (isAtPrefix)
|
|
808
|
+
nextIndex++;
|
|
788
809
|
const times = [];
|
|
789
810
|
const consumedIndices = [];
|
|
790
811
|
const timeTokens = [];
|
|
791
|
-
if (
|
|
812
|
+
if (isAndPrefix)
|
|
792
813
|
consumedIndices.push(index);
|
|
814
|
+
if (isAtPrefix) {
|
|
815
|
+
// If we have "and at", at is the second token (index + 1)
|
|
816
|
+
consumedIndices.push(isAndPrefix ? index + 1 : index);
|
|
817
|
+
}
|
|
793
818
|
while (nextIndex < tokens.length) {
|
|
794
819
|
const nextToken = tokens[nextIndex];
|
|
795
820
|
if (!nextToken || internal.consumed.has(nextToken.index))
|
|
@@ -1657,7 +1682,7 @@ function applyCountLimit(internal, value) {
|
|
|
1657
1682
|
return true;
|
|
1658
1683
|
}
|
|
1659
1684
|
function parseInternal(input, options) {
|
|
1660
|
-
var _a, _b, _c, _d, _e, _f, _g;
|
|
1685
|
+
var _a, _b, _c, _d, _e, _f, _g, _h;
|
|
1661
1686
|
const tokens = tokenize(input);
|
|
1662
1687
|
const internal = {
|
|
1663
1688
|
input,
|
|
@@ -1695,15 +1720,20 @@ function parseInternal(input, options) {
|
|
|
1695
1720
|
if (token.lower === "prn") {
|
|
1696
1721
|
internal.asNeeded = true;
|
|
1697
1722
|
mark(internal.consumed, token);
|
|
1698
|
-
|
|
1723
|
+
let reasonIndex = i + 1;
|
|
1724
|
+
if (((_b = tokens[reasonIndex]) === null || _b === void 0 ? void 0 : _b.lower) === "for") {
|
|
1725
|
+
mark(internal.consumed, tokens[reasonIndex]);
|
|
1726
|
+
reasonIndex += 1;
|
|
1727
|
+
}
|
|
1728
|
+
prnReasonStart = reasonIndex;
|
|
1699
1729
|
break;
|
|
1700
1730
|
}
|
|
1701
|
-
if (token.lower === "as" && ((
|
|
1731
|
+
if (token.lower === "as" && ((_c = tokens[i + 1]) === null || _c === void 0 ? void 0 : _c.lower) === "needed") {
|
|
1702
1732
|
internal.asNeeded = true;
|
|
1703
1733
|
mark(internal.consumed, token);
|
|
1704
1734
|
mark(internal.consumed, tokens[i + 1]);
|
|
1705
1735
|
let reasonIndex = i + 2;
|
|
1706
|
-
if (((
|
|
1736
|
+
if (((_d = tokens[reasonIndex]) === null || _d === void 0 ? void 0 : _d.lower) === "for") {
|
|
1707
1737
|
mark(internal.consumed, tokens[reasonIndex]);
|
|
1708
1738
|
reasonIndex += 1;
|
|
1709
1739
|
}
|
|
@@ -1898,7 +1928,7 @@ function parseInternal(input, options) {
|
|
|
1898
1928
|
// Frequency abbreviation map
|
|
1899
1929
|
const freqDescriptor = normalizedLower === "od"
|
|
1900
1930
|
? undefined
|
|
1901
|
-
: (
|
|
1931
|
+
: (_e = maps_1.TIMING_ABBREVIATIONS[token.lower]) !== null && _e !== void 0 ? _e : maps_1.TIMING_ABBREVIATIONS[normalizedLower];
|
|
1902
1932
|
if (freqDescriptor) {
|
|
1903
1933
|
applyFrequencyDescriptor(internal, token, freqDescriptor, options);
|
|
1904
1934
|
continue;
|
|
@@ -1913,34 +1943,32 @@ function parseInternal(input, options) {
|
|
|
1913
1943
|
: types_1.EventTiming["Before Meal"]);
|
|
1914
1944
|
continue;
|
|
1915
1945
|
}
|
|
1916
|
-
if (token.lower === "at" || token.lower === "@" || token.lower === "on") {
|
|
1946
|
+
if (token.lower === "at" || token.lower === "@" || token.lower === "on" || token.lower === "with") {
|
|
1917
1947
|
if (parseAnchorSequence(internal, tokens, i)) {
|
|
1918
1948
|
continue;
|
|
1919
1949
|
}
|
|
1920
1950
|
if (tryParseTimeBasedSchedule(internal, tokens, i)) {
|
|
1921
1951
|
continue;
|
|
1922
1952
|
}
|
|
1923
|
-
|
|
1924
|
-
|
|
1953
|
+
// If none of the above consume it, and it's a known anchor prefix, mark it
|
|
1954
|
+
// but only if it's not "with" which might be part of other phrases later.
|
|
1955
|
+
if (token.lower !== "with") {
|
|
1956
|
+
mark(internal.consumed, token);
|
|
1957
|
+
continue;
|
|
1958
|
+
}
|
|
1925
1959
|
}
|
|
1926
1960
|
const nextToken = tokens[i + 1];
|
|
1927
1961
|
if (nextToken && !internal.consumed.has(nextToken.index)) {
|
|
1928
1962
|
const lowerNext = nextToken.lower;
|
|
1929
1963
|
const combo = `${token.lower} ${lowerNext}`;
|
|
1930
|
-
const comboWhen = (
|
|
1964
|
+
const comboWhen = (_f = COMBO_EVENT_TIMINGS[combo]) !== null && _f !== void 0 ? _f : maps_1.EVENT_TIMING_TOKENS[combo];
|
|
1931
1965
|
if (comboWhen) {
|
|
1932
1966
|
applyWhenToken(internal, token, comboWhen);
|
|
1933
1967
|
mark(internal.consumed, nextToken);
|
|
1934
1968
|
continue;
|
|
1935
1969
|
}
|
|
1936
|
-
// Issue 2: Support "with meal" and "with food" combos explicitly if needed
|
|
1937
|
-
if (token.lower === "with" && (lowerNext === "meal" || lowerNext === "food")) {
|
|
1938
|
-
applyWhenToken(internal, token, types_1.EventTiming.Meal);
|
|
1939
|
-
mark(internal.consumed, nextToken);
|
|
1940
|
-
continue;
|
|
1941
|
-
}
|
|
1942
1970
|
}
|
|
1943
|
-
const customWhen = (
|
|
1971
|
+
const customWhen = (_g = options === null || options === void 0 ? void 0 : options.whenMap) === null || _g === void 0 ? void 0 : _g[token.lower];
|
|
1944
1972
|
if (customWhen) {
|
|
1945
1973
|
applyWhenToken(internal, token, customWhen);
|
|
1946
1974
|
continue;
|
|
@@ -2237,6 +2265,23 @@ function parseInternal(input, options) {
|
|
|
2237
2265
|
// If it is a reclaimable connector, we can pull it back into the reason
|
|
2238
2266
|
// if it helps form a coherent phrase like 'irritation at rectum'.
|
|
2239
2267
|
}
|
|
2268
|
+
// If we haven't started collecting the reason yet, we should skip introductory
|
|
2269
|
+
// connectors to avoid phrases like "as needed for if pain".
|
|
2270
|
+
const PRN_INTRODUCTIONS = new Set(["for", "if", "when", "upon", "due", "to"]);
|
|
2271
|
+
if (reasonTokens.length === 0 && PRN_INTRODUCTIONS.has(token.lower)) {
|
|
2272
|
+
// Special handling for "due to" - if we skipped "due", we should also skip "to"
|
|
2273
|
+
if (token.lower === "due") {
|
|
2274
|
+
const next = tokens[i + 1];
|
|
2275
|
+
if (next && next.lower === "to") {
|
|
2276
|
+
mark(internal.consumed, token);
|
|
2277
|
+
mark(internal.consumed, next);
|
|
2278
|
+
i++; // skip next token in loop
|
|
2279
|
+
continue;
|
|
2280
|
+
}
|
|
2281
|
+
}
|
|
2282
|
+
mark(internal.consumed, token);
|
|
2283
|
+
continue;
|
|
2284
|
+
}
|
|
2240
2285
|
reasonTokens.push(token.original);
|
|
2241
2286
|
reasonIndices.push(token.index);
|
|
2242
2287
|
reasonObjects.push(token);
|
|
@@ -2285,7 +2330,7 @@ function parseInternal(input, options) {
|
|
|
2285
2330
|
let canonicalPrefix;
|
|
2286
2331
|
if (reasonTokens.length > 0) {
|
|
2287
2332
|
const suffixInfo = findTrailingPrnSiteSuffix(reasonObjects, internal, options);
|
|
2288
|
-
if ((
|
|
2333
|
+
if ((_h = suffixInfo === null || suffixInfo === void 0 ? void 0 : suffixInfo.tokens) === null || _h === void 0 ? void 0 : _h.length) {
|
|
2289
2334
|
for (const token of suffixInfo.tokens) {
|
|
2290
2335
|
prnSiteSuffixIndices.add(token.index);
|
|
2291
2336
|
}
|
|
@@ -2791,12 +2836,12 @@ function findAdditionalInstructionDefinition(text, canonical) {
|
|
|
2791
2836
|
if (!entry.canonical) {
|
|
2792
2837
|
continue;
|
|
2793
2838
|
}
|
|
2839
|
+
// Check for exact canonical match first
|
|
2794
2840
|
if (entry.canonical === canonical) {
|
|
2795
2841
|
return entry.definition;
|
|
2796
2842
|
}
|
|
2797
|
-
|
|
2798
|
-
|
|
2799
|
-
}
|
|
2843
|
+
// Avoid broad includes checks (like "with" matching "with meal")
|
|
2844
|
+
// to prevent leakage of common connectors into additional instructions.
|
|
2800
2845
|
for (const term of entry.terms) {
|
|
2801
2846
|
const normalizedTerm = (0, maps_1.normalizeAdditionalInstructionKey)(term);
|
|
2802
2847
|
if (!normalizedTerm) {
|
package/dist/suggest.js
CHANGED
|
@@ -347,6 +347,43 @@ function canonicalizeLowercaseForMatching(value) {
|
|
|
347
347
|
function canonicalizeForMatching(value) {
|
|
348
348
|
return canonicalizeLowercaseForMatching(value.toLowerCase());
|
|
349
349
|
}
|
|
350
|
+
function buildTimeTokens(input) {
|
|
351
|
+
const tokens = new Set();
|
|
352
|
+
// Add common times
|
|
353
|
+
for (let i = 1; i <= 12; i++) {
|
|
354
|
+
tokens.add(`at ${i}:00 am`);
|
|
355
|
+
tokens.add(`at ${i}:00 pm`);
|
|
356
|
+
}
|
|
357
|
+
// Analyze input for specific time requests to provide more granular suggestions
|
|
358
|
+
const match = input.match(/(?:at|@)\s*(\d{1,2})(?::(\d{0,2}))?/i);
|
|
359
|
+
if (match) {
|
|
360
|
+
const h = parseInt(match[1], 10);
|
|
361
|
+
if (h >= 1 && h <= 12) {
|
|
362
|
+
const m = match[2] || "00";
|
|
363
|
+
if (m.length === 1) {
|
|
364
|
+
tokens.add(`at ${h}:${m}0 am`);
|
|
365
|
+
tokens.add(`at ${h}:${m}0 pm`);
|
|
366
|
+
}
|
|
367
|
+
else {
|
|
368
|
+
tokens.add(`at ${h}:${m} am`);
|
|
369
|
+
tokens.add(`at ${h}:${m} pm`);
|
|
370
|
+
}
|
|
371
|
+
}
|
|
372
|
+
else if (h > 12 && h < 24) {
|
|
373
|
+
// Input seems to be 24h, but we format as am/pm usually.
|
|
374
|
+
// Let's add the 24h format as well if that's what they are typing?
|
|
375
|
+
// Or convert to am/pm? Let's add both for robustness.
|
|
376
|
+
const m = match[2] || "00";
|
|
377
|
+
if (m.length === 1) {
|
|
378
|
+
tokens.add(`at ${h}:${m}0`);
|
|
379
|
+
}
|
|
380
|
+
else {
|
|
381
|
+
tokens.add(`at ${h}:${m}`);
|
|
382
|
+
}
|
|
383
|
+
}
|
|
384
|
+
}
|
|
385
|
+
return [...tokens];
|
|
386
|
+
}
|
|
350
387
|
function tokensMatch(prefixTokens, candidateTokens) {
|
|
351
388
|
if (prefixTokens.length === 0) {
|
|
352
389
|
return true;
|
|
@@ -461,7 +498,7 @@ function getCandidateFingerprint(candidateLower) {
|
|
|
461
498
|
}
|
|
462
499
|
return fingerprint;
|
|
463
500
|
}
|
|
464
|
-
function generateCandidateDirections(pairs, doseValues, prnReasons, intervalTokens, whenSequences, limit, matcher) {
|
|
501
|
+
function generateCandidateDirections(pairs, doseValues, prnReasons, intervalTokens, timeTokens, whenSequences, limit, matcher) {
|
|
465
502
|
const suggestions = [];
|
|
466
503
|
const seen = new Set();
|
|
467
504
|
const doseVariantMap = new Map();
|
|
@@ -502,6 +539,7 @@ function generateCandidateDirections(pairs, doseValues, prnReasons, intervalToke
|
|
|
502
539
|
const whenSuffixes = whenSequences === PRECOMPUTED_WHEN_SEQUENCES
|
|
503
540
|
? PRECOMPUTED_WHEN_SEQUENCE_SUFFIXES
|
|
504
541
|
: whenSequences.map((sequence) => ` ${sequence.join(" ")}`);
|
|
542
|
+
const timeSuffixes = timeTokens.map((token) => ` ${token}`);
|
|
505
543
|
for (let pairIndex = 0; pairIndex < pairs.length; pairIndex += 1) {
|
|
506
544
|
const pair = pairs[pairIndex];
|
|
507
545
|
const unitVariants = getUnitVariants(pair.unit);
|
|
@@ -593,6 +631,21 @@ function generateCandidateDirections(pairs, doseValues, prnReasons, intervalToke
|
|
|
593
631
|
return suggestions;
|
|
594
632
|
}
|
|
595
633
|
}
|
|
634
|
+
for (let timeIndex = 0; timeIndex < timeSuffixes.length; timeIndex += 1) {
|
|
635
|
+
const timeSuffix = timeSuffixes[timeIndex];
|
|
636
|
+
for (let unitIndex = 0; unitIndex < unitDoseVariants.length; unitIndex += 1) {
|
|
637
|
+
const doseBases = unitDoseVariants[unitIndex];
|
|
638
|
+
for (let doseIndex = 0; doseIndex < doseBases.length; doseIndex += 1) {
|
|
639
|
+
const base = doseBases[doseIndex];
|
|
640
|
+
if (push(base.value + timeSuffix, base.lower + timeSuffix)) {
|
|
641
|
+
return suggestions;
|
|
642
|
+
}
|
|
643
|
+
}
|
|
644
|
+
}
|
|
645
|
+
if (push(route + timeSuffix, routeLower + timeSuffix)) {
|
|
646
|
+
return suggestions;
|
|
647
|
+
}
|
|
648
|
+
}
|
|
596
649
|
for (let reasonIndex = 0; reasonIndex < prnSuffixes.length; reasonIndex += 1) {
|
|
597
650
|
const reasonSuffix = prnSuffixes[reasonIndex];
|
|
598
651
|
for (let unitIndex = 0; unitIndex < unitDoseVariants.length; unitIndex += 1) {
|
|
@@ -712,7 +765,8 @@ function suggestSig(input, options) {
|
|
|
712
765
|
const doseValues = buildDoseValues(input);
|
|
713
766
|
const prnReasons = buildPrnReasons(options === null || options === void 0 ? void 0 : options.prnReasons);
|
|
714
767
|
const intervalTokens = buildIntervalTokens(input);
|
|
768
|
+
const timeTokens = buildTimeTokens(input);
|
|
715
769
|
const whenSequences = PRECOMPUTED_WHEN_SEQUENCES;
|
|
716
770
|
const matcher = (candidate, candidateLower) => matchesPrefix(candidate, candidateLower, prefixContext);
|
|
717
|
-
return generateCandidateDirections(pairs, doseValues, prnReasons, intervalTokens, whenSequences, limit, matcher);
|
|
771
|
+
return generateCandidateDirections(pairs, doseValues, prnReasons, intervalTokens, timeTokens, whenSequences, limit, matcher);
|
|
718
772
|
}
|