ezmedicationinput 0.1.40 → 0.1.42
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/context.d.ts +2 -1
- package/dist/context.js +16 -0
- package/dist/i18n.js +9 -4
- package/dist/maps.js +33 -1
- package/dist/parser.js +255 -26
- package/dist/utils/enum.d.ts +2 -0
- package/dist/utils/enum.js +7 -0
- package/package.json +1 -1
package/dist/context.d.ts
CHANGED
|
@@ -1,3 +1,4 @@
|
|
|
1
|
-
import { MedicationContext } from "./types";
|
|
1
|
+
import { MedicationContext, RouteCode } from "./types";
|
|
2
2
|
export declare function normalizeDosageForm(form: string | undefined): string | undefined;
|
|
3
3
|
export declare function inferUnitFromContext(ctx: MedicationContext | undefined): string | undefined;
|
|
4
|
+
export declare function inferRouteFromContext(ctx: MedicationContext | undefined): RouteCode | undefined;
|
package/dist/context.js
CHANGED
|
@@ -2,6 +2,7 @@
|
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
3
|
exports.normalizeDosageForm = normalizeDosageForm;
|
|
4
4
|
exports.inferUnitFromContext = inferUnitFromContext;
|
|
5
|
+
exports.inferRouteFromContext = inferRouteFromContext;
|
|
5
6
|
const maps_1 = require("./maps");
|
|
6
7
|
function normalizeDosageForm(form) {
|
|
7
8
|
var _a;
|
|
@@ -32,3 +33,18 @@ function inferUnitFromContext(ctx) {
|
|
|
32
33
|
}
|
|
33
34
|
return undefined;
|
|
34
35
|
}
|
|
36
|
+
function inferRouteFromContext(ctx) {
|
|
37
|
+
var _a;
|
|
38
|
+
if (!(ctx === null || ctx === void 0 ? void 0 : ctx.dosageForm)) {
|
|
39
|
+
return undefined;
|
|
40
|
+
}
|
|
41
|
+
const normalized = normalizeDosageForm(ctx.dosageForm);
|
|
42
|
+
if (!normalized) {
|
|
43
|
+
return undefined;
|
|
44
|
+
}
|
|
45
|
+
const snomed = maps_1.KNOWN_TMT_DOSAGE_FORM_TO_SNOMED_ROUTE[normalized];
|
|
46
|
+
if (!snomed) {
|
|
47
|
+
return (_a = maps_1.DEFAULT_ROUTE_SYNONYMS[normalized]) === null || _a === void 0 ? void 0 : _a.code;
|
|
48
|
+
}
|
|
49
|
+
return maps_1.ROUTE_BY_SNOMED[snomed];
|
|
50
|
+
}
|
package/dist/i18n.js
CHANGED
|
@@ -231,7 +231,6 @@ const THAI_ROUTE_GRAMMAR = {
|
|
|
231
231
|
[types_1.RouteCode["Buccal route"]]: { verb: "อมกระพุ้งแก้ม", routePhrase: "ที่กระพุ้งแก้ม" },
|
|
232
232
|
[types_1.RouteCode["Respiratory tract route (qualifier value)"]]: {
|
|
233
233
|
verb: "สูด",
|
|
234
|
-
routePhrase: ({ hasSite }) => (hasSite ? undefined : "โดยการสูดดม"),
|
|
235
234
|
sitePreposition: "ที่"
|
|
236
235
|
},
|
|
237
236
|
[types_1.RouteCode["Nasal route"]]: {
|
|
@@ -291,12 +290,18 @@ const THAI_ROUTE_GRAMMAR = {
|
|
|
291
290
|
}
|
|
292
291
|
};
|
|
293
292
|
function resolveRouteGrammarThai(internal) {
|
|
294
|
-
var _a;
|
|
293
|
+
var _a, _b, _c;
|
|
295
294
|
if (internal.routeCode && THAI_ROUTE_GRAMMAR[internal.routeCode]) {
|
|
296
295
|
return (_a = THAI_ROUTE_GRAMMAR[internal.routeCode]) !== null && _a !== void 0 ? _a : DEFAULT_THAI_ROUTE_GRAMMAR;
|
|
297
296
|
}
|
|
298
297
|
const grammar = grammarFromRouteTextThai(internal.routeText);
|
|
299
|
-
|
|
298
|
+
if (grammar) {
|
|
299
|
+
return grammar;
|
|
300
|
+
}
|
|
301
|
+
if (((_b = internal.unit) === null || _b === void 0 ? void 0 : _b.trim().toLowerCase()) === "puff") {
|
|
302
|
+
return (_c = THAI_ROUTE_GRAMMAR[types_1.RouteCode["Respiratory tract route (qualifier value)"]]) !== null && _c !== void 0 ? _c : DEFAULT_THAI_ROUTE_GRAMMAR;
|
|
303
|
+
}
|
|
304
|
+
return DEFAULT_THAI_ROUTE_GRAMMAR;
|
|
300
305
|
}
|
|
301
306
|
function grammarFromRouteTextThai(text) {
|
|
302
307
|
if (!text)
|
|
@@ -606,7 +611,7 @@ function buildRoutePhraseThai(internal, grammar, hasSite) {
|
|
|
606
611
|
return "ทางจมูก";
|
|
607
612
|
}
|
|
608
613
|
if (normalized.includes("inhal")) {
|
|
609
|
-
return
|
|
614
|
+
return undefined;
|
|
610
615
|
}
|
|
611
616
|
return text;
|
|
612
617
|
}
|
package/dist/maps.js
CHANGED
|
@@ -548,6 +548,13 @@ function addMetricUnitSynonyms(map) {
|
|
|
548
548
|
}
|
|
549
549
|
exports.HOUSEHOLD_VOLUME_UNITS = ["tsp", "tbsp"];
|
|
550
550
|
const STATIC_UNIT_SYNONYMS = {
|
|
551
|
+
u: "U",
|
|
552
|
+
unit: "U",
|
|
553
|
+
units: "U",
|
|
554
|
+
iu: "IU",
|
|
555
|
+
"i.u": "IU",
|
|
556
|
+
"i.u.": "IU",
|
|
557
|
+
ius: "IU",
|
|
551
558
|
tab: "tab",
|
|
552
559
|
tabs: "tab",
|
|
553
560
|
tablet: "tab",
|
|
@@ -745,18 +752,43 @@ exports.DISCOURAGED_TOKENS = {
|
|
|
745
752
|
exports.DAY_OF_WEEK_TOKENS = {
|
|
746
753
|
monday: types_1.FhirDayOfWeek.Monday,
|
|
747
754
|
mon: types_1.FhirDayOfWeek.Monday,
|
|
755
|
+
mond: types_1.FhirDayOfWeek.Monday,
|
|
748
756
|
tuesday: types_1.FhirDayOfWeek.Tuesday,
|
|
749
757
|
tue: types_1.FhirDayOfWeek.Tuesday,
|
|
758
|
+
tues: types_1.FhirDayOfWeek.Tuesday,
|
|
750
759
|
wednesday: types_1.FhirDayOfWeek.Wednesday,
|
|
751
760
|
wed: types_1.FhirDayOfWeek.Wednesday,
|
|
761
|
+
weds: types_1.FhirDayOfWeek.Wednesday,
|
|
752
762
|
thursday: types_1.FhirDayOfWeek.Thursday,
|
|
753
763
|
thu: types_1.FhirDayOfWeek.Thursday,
|
|
764
|
+
thur: types_1.FhirDayOfWeek.Thursday,
|
|
765
|
+
thurs: types_1.FhirDayOfWeek.Thursday,
|
|
754
766
|
friday: types_1.FhirDayOfWeek.Friday,
|
|
755
767
|
fri: types_1.FhirDayOfWeek.Friday,
|
|
756
768
|
saturday: types_1.FhirDayOfWeek.Saturday,
|
|
757
769
|
sat: types_1.FhirDayOfWeek.Saturday,
|
|
758
770
|
sunday: types_1.FhirDayOfWeek.Sunday,
|
|
759
|
-
sun: types_1.FhirDayOfWeek.Sunday
|
|
771
|
+
sun: types_1.FhirDayOfWeek.Sunday,
|
|
772
|
+
จ: types_1.FhirDayOfWeek.Monday,
|
|
773
|
+
จัน: types_1.FhirDayOfWeek.Monday,
|
|
774
|
+
จันทร์: types_1.FhirDayOfWeek.Monday,
|
|
775
|
+
อ: types_1.FhirDayOfWeek.Tuesday,
|
|
776
|
+
อัง: types_1.FhirDayOfWeek.Tuesday,
|
|
777
|
+
อังคาร: types_1.FhirDayOfWeek.Tuesday,
|
|
778
|
+
พ: types_1.FhirDayOfWeek.Wednesday,
|
|
779
|
+
พุธ: types_1.FhirDayOfWeek.Wednesday,
|
|
780
|
+
พฤ: types_1.FhirDayOfWeek.Thursday,
|
|
781
|
+
พฤหัส: types_1.FhirDayOfWeek.Thursday,
|
|
782
|
+
พฤหัสบดี: types_1.FhirDayOfWeek.Thursday,
|
|
783
|
+
ศ: types_1.FhirDayOfWeek.Friday,
|
|
784
|
+
ศุก: types_1.FhirDayOfWeek.Friday,
|
|
785
|
+
ศุกร์: types_1.FhirDayOfWeek.Friday,
|
|
786
|
+
ส: types_1.FhirDayOfWeek.Saturday,
|
|
787
|
+
เสา: types_1.FhirDayOfWeek.Saturday,
|
|
788
|
+
เสาร์: types_1.FhirDayOfWeek.Saturday,
|
|
789
|
+
อา: types_1.FhirDayOfWeek.Sunday,
|
|
790
|
+
อาท: types_1.FhirDayOfWeek.Sunday,
|
|
791
|
+
อาทิตย์: types_1.FhirDayOfWeek.Sunday
|
|
760
792
|
};
|
|
761
793
|
exports.WORD_FREQUENCIES = {
|
|
762
794
|
daily: { frequency: 1, periodUnit: types_1.FhirPeriodUnit.Day },
|
package/dist/parser.js
CHANGED
|
@@ -195,6 +195,11 @@ const COMBO_EVENT_TIMINGS = {
|
|
|
195
195
|
"before sleep": types_1.EventTiming["Before Sleep"],
|
|
196
196
|
"upon waking": types_1.EventTiming.Wake
|
|
197
197
|
};
|
|
198
|
+
const DAY_RANGE_PART_PATTERN = Object.keys(maps_1.DAY_OF_WEEK_TOKENS)
|
|
199
|
+
.sort((a, b) => b.length - a.length)
|
|
200
|
+
.map((token) => token.replace(/[.*+?^${}()|[\]\\]/g, "\\$&"))
|
|
201
|
+
.join("|");
|
|
202
|
+
const DAY_RANGE_SPACED_HYPHEN_REGEX = new RegExp(`(^|\\s)(${DAY_RANGE_PART_PATTERN})\\s*-\\s*(${DAY_RANGE_PART_PATTERN})(?=\\s|$)`, "giu");
|
|
198
203
|
const MEAL_CONTEXT_CONNECTORS = new Set(["and", "or", "&", "+", "plus"]);
|
|
199
204
|
const COUNT_KEYWORDS = new Set([
|
|
200
205
|
"time",
|
|
@@ -331,6 +336,7 @@ const EYE_SITE_TOKENS = {
|
|
|
331
336
|
};
|
|
332
337
|
const OPHTHALMIC_ROUTE_CODES = new Set([
|
|
333
338
|
types_1.RouteCode["Ophthalmic route"],
|
|
339
|
+
types_1.RouteCode["Ocular route (qualifier value)"],
|
|
334
340
|
types_1.RouteCode["Intravitreal route (qualifier value)"]
|
|
335
341
|
]);
|
|
336
342
|
const OPHTHALMIC_CONTEXT_TOKENS = new Set([
|
|
@@ -533,9 +539,13 @@ function shouldTreatEyeTokenAsSite(internal, tokens, index, context) {
|
|
|
533
539
|
const currentToken = tokens[index];
|
|
534
540
|
const normalizedSelf = normalizeTokenLower(currentToken);
|
|
535
541
|
const eyeMeta = EYE_SITE_TOKENS[normalizedSelf];
|
|
542
|
+
const contextRoute = (0, context_1.inferRouteFromContext)(context !== null && context !== void 0 ? context : undefined);
|
|
536
543
|
if (internal.routeCode && !OPHTHALMIC_ROUTE_CODES.has(internal.routeCode)) {
|
|
537
544
|
return false;
|
|
538
545
|
}
|
|
546
|
+
if (contextRoute && !OPHTHALMIC_ROUTE_CODES.has(contextRoute)) {
|
|
547
|
+
return false;
|
|
548
|
+
}
|
|
539
549
|
if (internal.siteText) {
|
|
540
550
|
return false;
|
|
541
551
|
}
|
|
@@ -543,7 +553,9 @@ function shouldTreatEyeTokenAsSite(internal, tokens, index, context) {
|
|
|
543
553
|
return false;
|
|
544
554
|
}
|
|
545
555
|
const dosageForm = (_a = context === null || context === void 0 ? void 0 : context.dosageForm) === null || _a === void 0 ? void 0 : _a.toLowerCase();
|
|
546
|
-
const contextImpliesOphthalmic =
|
|
556
|
+
const contextImpliesOphthalmic = contextRoute
|
|
557
|
+
? OPHTHALMIC_ROUTE_CODES.has(contextRoute)
|
|
558
|
+
: Boolean(dosageForm && /(eye|ophth|ocular|intravit)/i.test(dosageForm));
|
|
547
559
|
const eyeRouteImpliesOphthalmic = (eyeMeta === null || eyeMeta === void 0 ? void 0 : eyeMeta.route) === types_1.RouteCode["Intravitreal route (qualifier value)"];
|
|
548
560
|
const ophthalmicContext = hasOphthalmicContextHint(tokens, index) ||
|
|
549
561
|
(internal.routeCode !== undefined && OPHTHALMIC_ROUTE_CODES.has(internal.routeCode)) ||
|
|
@@ -965,6 +977,7 @@ const SITE_UNIT_ROUTE_HINTS = [
|
|
|
965
977
|
function tokenize(input) {
|
|
966
978
|
const separators = /[(),;]/g;
|
|
967
979
|
let normalized = input.trim().replace(separators, " ");
|
|
980
|
+
normalized = normalized.replace(DAY_RANGE_SPACED_HYPHEN_REGEX, (_match, prefix, start, end) => `${prefix}${start}-${end}`);
|
|
968
981
|
normalized = normalized.replace(/\s-\s/g, " ; ");
|
|
969
982
|
normalized = normalized.replace(/(\d+(?:\.\d+)?)\s*\/\s*(d|day|days|wk|w|week|weeks|mo|month|months|hr|hrs|hour|hours|h|min|mins|minute|minutes)\b/gi, (_match, value, unit) => `${value} per ${unit}`);
|
|
970
983
|
normalized = normalized.replace(/(\d+)\s*\/\s*(\d+)/g, (match, num, den) => {
|
|
@@ -1585,6 +1598,154 @@ function isTimingAnchorOrPrefix(tokens, index, prnReasonStart) {
|
|
|
1585
1598
|
(isAtPrefixToken(lower) || lower === "on" || lower === "with") ||
|
|
1586
1599
|
/^\d/.test(lower));
|
|
1587
1600
|
}
|
|
1601
|
+
const DAY_SEQUENCE = [
|
|
1602
|
+
types_1.FhirDayOfWeek.Monday,
|
|
1603
|
+
types_1.FhirDayOfWeek.Tuesday,
|
|
1604
|
+
types_1.FhirDayOfWeek.Wednesday,
|
|
1605
|
+
types_1.FhirDayOfWeek.Thursday,
|
|
1606
|
+
types_1.FhirDayOfWeek.Friday,
|
|
1607
|
+
types_1.FhirDayOfWeek.Saturday,
|
|
1608
|
+
types_1.FhirDayOfWeek.Sunday
|
|
1609
|
+
];
|
|
1610
|
+
const DAY_GROUP_TOKENS = {
|
|
1611
|
+
weekend: [types_1.FhirDayOfWeek.Saturday, types_1.FhirDayOfWeek.Sunday],
|
|
1612
|
+
weekends: [types_1.FhirDayOfWeek.Saturday, types_1.FhirDayOfWeek.Sunday],
|
|
1613
|
+
wknd: [types_1.FhirDayOfWeek.Saturday, types_1.FhirDayOfWeek.Sunday],
|
|
1614
|
+
weekdays: [
|
|
1615
|
+
types_1.FhirDayOfWeek.Monday,
|
|
1616
|
+
types_1.FhirDayOfWeek.Tuesday,
|
|
1617
|
+
types_1.FhirDayOfWeek.Wednesday,
|
|
1618
|
+
types_1.FhirDayOfWeek.Thursday,
|
|
1619
|
+
types_1.FhirDayOfWeek.Friday
|
|
1620
|
+
],
|
|
1621
|
+
weekday: [
|
|
1622
|
+
types_1.FhirDayOfWeek.Monday,
|
|
1623
|
+
types_1.FhirDayOfWeek.Tuesday,
|
|
1624
|
+
types_1.FhirDayOfWeek.Wednesday,
|
|
1625
|
+
types_1.FhirDayOfWeek.Thursday,
|
|
1626
|
+
types_1.FhirDayOfWeek.Friday
|
|
1627
|
+
],
|
|
1628
|
+
workday: [
|
|
1629
|
+
types_1.FhirDayOfWeek.Monday,
|
|
1630
|
+
types_1.FhirDayOfWeek.Tuesday,
|
|
1631
|
+
types_1.FhirDayOfWeek.Wednesday,
|
|
1632
|
+
types_1.FhirDayOfWeek.Thursday,
|
|
1633
|
+
types_1.FhirDayOfWeek.Friday
|
|
1634
|
+
],
|
|
1635
|
+
workdays: [
|
|
1636
|
+
types_1.FhirDayOfWeek.Monday,
|
|
1637
|
+
types_1.FhirDayOfWeek.Tuesday,
|
|
1638
|
+
types_1.FhirDayOfWeek.Wednesday,
|
|
1639
|
+
types_1.FhirDayOfWeek.Thursday,
|
|
1640
|
+
types_1.FhirDayOfWeek.Friday
|
|
1641
|
+
],
|
|
1642
|
+
วันธรรมดา: [
|
|
1643
|
+
types_1.FhirDayOfWeek.Monday,
|
|
1644
|
+
types_1.FhirDayOfWeek.Tuesday,
|
|
1645
|
+
types_1.FhirDayOfWeek.Wednesday,
|
|
1646
|
+
types_1.FhirDayOfWeek.Thursday,
|
|
1647
|
+
types_1.FhirDayOfWeek.Friday
|
|
1648
|
+
],
|
|
1649
|
+
วันทำงาน: [
|
|
1650
|
+
types_1.FhirDayOfWeek.Monday,
|
|
1651
|
+
types_1.FhirDayOfWeek.Tuesday,
|
|
1652
|
+
types_1.FhirDayOfWeek.Wednesday,
|
|
1653
|
+
types_1.FhirDayOfWeek.Thursday,
|
|
1654
|
+
types_1.FhirDayOfWeek.Friday
|
|
1655
|
+
],
|
|
1656
|
+
วันหยุด: [types_1.FhirDayOfWeek.Saturday, types_1.FhirDayOfWeek.Sunday],
|
|
1657
|
+
สุดสัปดาห์: [types_1.FhirDayOfWeek.Saturday, types_1.FhirDayOfWeek.Sunday],
|
|
1658
|
+
เสาร์อาทิตย์: [types_1.FhirDayOfWeek.Saturday, types_1.FhirDayOfWeek.Sunday],
|
|
1659
|
+
จันทร์ถึงศุกร์: [
|
|
1660
|
+
types_1.FhirDayOfWeek.Monday,
|
|
1661
|
+
types_1.FhirDayOfWeek.Tuesday,
|
|
1662
|
+
types_1.FhirDayOfWeek.Wednesday,
|
|
1663
|
+
types_1.FhirDayOfWeek.Thursday,
|
|
1664
|
+
types_1.FhirDayOfWeek.Friday
|
|
1665
|
+
]
|
|
1666
|
+
};
|
|
1667
|
+
const DAY_RANGE_CONNECTOR_TOKENS = new Set(["-", "to", "through", "thru", "ถึง", "จนถึง"]);
|
|
1668
|
+
function addDayOfWeek(internal, day) {
|
|
1669
|
+
if (!(0, array_1.arrayIncludes)(internal.dayOfWeek, day)) {
|
|
1670
|
+
internal.dayOfWeek.push(day);
|
|
1671
|
+
}
|
|
1672
|
+
}
|
|
1673
|
+
function addDayOfWeekList(internal, days) {
|
|
1674
|
+
for (const day of days) {
|
|
1675
|
+
addDayOfWeek(internal, day);
|
|
1676
|
+
}
|
|
1677
|
+
}
|
|
1678
|
+
function expandDayRange(start, end) {
|
|
1679
|
+
const startIndex = DAY_SEQUENCE.indexOf(start);
|
|
1680
|
+
const endIndex = DAY_SEQUENCE.indexOf(end);
|
|
1681
|
+
if (startIndex < 0 || endIndex < 0) {
|
|
1682
|
+
return [start, end];
|
|
1683
|
+
}
|
|
1684
|
+
if (startIndex <= endIndex) {
|
|
1685
|
+
return DAY_SEQUENCE.slice(startIndex, endIndex + 1);
|
|
1686
|
+
}
|
|
1687
|
+
return [...DAY_SEQUENCE.slice(startIndex), ...DAY_SEQUENCE.slice(0, endIndex + 1)];
|
|
1688
|
+
}
|
|
1689
|
+
function resolveDayTokenDays(tokenLower) {
|
|
1690
|
+
const normalized = tokenLower.replace(/[.,;:]/g, "");
|
|
1691
|
+
const direct = maps_1.DAY_OF_WEEK_TOKENS[normalized];
|
|
1692
|
+
if (direct) {
|
|
1693
|
+
return [direct];
|
|
1694
|
+
}
|
|
1695
|
+
const grouped = DAY_GROUP_TOKENS[normalized];
|
|
1696
|
+
if (grouped) {
|
|
1697
|
+
return grouped.slice();
|
|
1698
|
+
}
|
|
1699
|
+
const rangeMatch = normalized.match(/^([^-–—~]+)[-–—~]([^-–—~]+)$/);
|
|
1700
|
+
if (rangeMatch) {
|
|
1701
|
+
const start = maps_1.DAY_OF_WEEK_TOKENS[rangeMatch[1]];
|
|
1702
|
+
const end = maps_1.DAY_OF_WEEK_TOKENS[rangeMatch[2]];
|
|
1703
|
+
if (start && end) {
|
|
1704
|
+
return expandDayRange(start, end);
|
|
1705
|
+
}
|
|
1706
|
+
}
|
|
1707
|
+
const compactConnectorRange = normalized.match(/^(.+?)(ถึง|จนถึง|to|through|thru)(.+)$/u);
|
|
1708
|
+
if (compactConnectorRange) {
|
|
1709
|
+
const start = maps_1.DAY_OF_WEEK_TOKENS[compactConnectorRange[1]];
|
|
1710
|
+
const end = maps_1.DAY_OF_WEEK_TOKENS[compactConnectorRange[3]];
|
|
1711
|
+
if (start && end) {
|
|
1712
|
+
return expandDayRange(start, end);
|
|
1713
|
+
}
|
|
1714
|
+
}
|
|
1715
|
+
return undefined;
|
|
1716
|
+
}
|
|
1717
|
+
function tryConsumeDayRangeTokens(internal, tokens, index) {
|
|
1718
|
+
const startToken = tokens[index];
|
|
1719
|
+
if (!startToken || internal.consumed.has(startToken.index)) {
|
|
1720
|
+
return 0;
|
|
1721
|
+
}
|
|
1722
|
+
const startDays = resolveDayTokenDays(normalizeTokenLower(startToken));
|
|
1723
|
+
if (!startDays || startDays.length !== 1) {
|
|
1724
|
+
return 0;
|
|
1725
|
+
}
|
|
1726
|
+
const connectorToken = tokens[index + 1];
|
|
1727
|
+
const endToken = tokens[index + 2];
|
|
1728
|
+
if (!connectorToken ||
|
|
1729
|
+
!endToken ||
|
|
1730
|
+
internal.consumed.has(connectorToken.index) ||
|
|
1731
|
+
internal.consumed.has(endToken.index)) {
|
|
1732
|
+
return 0;
|
|
1733
|
+
}
|
|
1734
|
+
const connector = normalizeTokenLower(connectorToken);
|
|
1735
|
+
if (!DAY_RANGE_CONNECTOR_TOKENS.has(connector)) {
|
|
1736
|
+
return 0;
|
|
1737
|
+
}
|
|
1738
|
+
const endDays = resolveDayTokenDays(normalizeTokenLower(endToken));
|
|
1739
|
+
if (!endDays || endDays.length !== 1) {
|
|
1740
|
+
return 0;
|
|
1741
|
+
}
|
|
1742
|
+
const expanded = expandDayRange(startDays[0], endDays[0]);
|
|
1743
|
+
addDayOfWeekList(internal, expanded);
|
|
1744
|
+
mark(internal.consumed, startToken);
|
|
1745
|
+
mark(internal.consumed, connectorToken);
|
|
1746
|
+
mark(internal.consumed, endToken);
|
|
1747
|
+
return 3;
|
|
1748
|
+
}
|
|
1588
1749
|
function parseAnchorSequence(internal, tokens, index, prefixCode) {
|
|
1589
1750
|
var _a;
|
|
1590
1751
|
const token = tokens[index];
|
|
@@ -1594,16 +1755,20 @@ function parseAnchorSequence(internal, tokens, index, prefixCode) {
|
|
|
1594
1755
|
if (internal.consumed.has(nextToken.index)) {
|
|
1595
1756
|
continue;
|
|
1596
1757
|
}
|
|
1597
|
-
const lower = nextToken
|
|
1758
|
+
const lower = normalizeTokenLower(nextToken);
|
|
1598
1759
|
if (MEAL_CONTEXT_CONNECTORS.has(lower) || lower === ",") {
|
|
1599
1760
|
mark(internal.consumed, nextToken);
|
|
1600
1761
|
continue;
|
|
1601
1762
|
}
|
|
1602
|
-
const
|
|
1603
|
-
if (
|
|
1604
|
-
|
|
1605
|
-
|
|
1606
|
-
|
|
1763
|
+
const rangeConsumed = tryConsumeDayRangeTokens(internal, tokens, lookahead);
|
|
1764
|
+
if (rangeConsumed > 0) {
|
|
1765
|
+
converted++;
|
|
1766
|
+
lookahead += rangeConsumed - 1;
|
|
1767
|
+
continue;
|
|
1768
|
+
}
|
|
1769
|
+
const days = resolveDayTokenDays(lower);
|
|
1770
|
+
if (days) {
|
|
1771
|
+
addDayOfWeekList(internal, days);
|
|
1607
1772
|
mark(internal.consumed, nextToken);
|
|
1608
1773
|
converted++;
|
|
1609
1774
|
continue;
|
|
@@ -1748,6 +1913,70 @@ function applyCountLimit(internal, value) {
|
|
|
1748
1913
|
internal.count = rounded;
|
|
1749
1914
|
return true;
|
|
1750
1915
|
}
|
|
1916
|
+
const DOSE_SCALE_MULTIPLIERS = {
|
|
1917
|
+
k: 1000,
|
|
1918
|
+
thousand: 1000,
|
|
1919
|
+
m: 1000000,
|
|
1920
|
+
mn: 1000000,
|
|
1921
|
+
mio: 1000000,
|
|
1922
|
+
million: 1000000,
|
|
1923
|
+
b: 1000000000,
|
|
1924
|
+
bn: 1000000000,
|
|
1925
|
+
billion: 1000000000
|
|
1926
|
+
};
|
|
1927
|
+
function resolveUnitTokenAt(tokens, index, consumed, options) {
|
|
1928
|
+
const token = tokens[index];
|
|
1929
|
+
if (!token || consumed.has(token.index)) {
|
|
1930
|
+
return undefined;
|
|
1931
|
+
}
|
|
1932
|
+
const normalized = normalizeTokenLower(token);
|
|
1933
|
+
const direct = normalizeUnit(normalized, options);
|
|
1934
|
+
if (direct) {
|
|
1935
|
+
return { unit: direct, consumedIndices: [index] };
|
|
1936
|
+
}
|
|
1937
|
+
if (normalized === "international") {
|
|
1938
|
+
const nextToken = tokens[index + 1];
|
|
1939
|
+
if (!nextToken || consumed.has(nextToken.index)) {
|
|
1940
|
+
return undefined;
|
|
1941
|
+
}
|
|
1942
|
+
const nextNormalized = normalizeTokenLower(nextToken);
|
|
1943
|
+
if (nextNormalized === "unit" ||
|
|
1944
|
+
nextNormalized === "units" ||
|
|
1945
|
+
nextNormalized === "u" ||
|
|
1946
|
+
nextNormalized === "iu" ||
|
|
1947
|
+
nextNormalized === "ius") {
|
|
1948
|
+
return { unit: "IU", consumedIndices: [index, index + 1] };
|
|
1949
|
+
}
|
|
1950
|
+
}
|
|
1951
|
+
return undefined;
|
|
1952
|
+
}
|
|
1953
|
+
function resolveNumericDoseUnit(tokens, numberIndex, value, consumed, options) {
|
|
1954
|
+
const directUnit = resolveUnitTokenAt(tokens, numberIndex + 1, consumed, options);
|
|
1955
|
+
if (directUnit) {
|
|
1956
|
+
return {
|
|
1957
|
+
doseValue: value,
|
|
1958
|
+
unit: directUnit.unit,
|
|
1959
|
+
consumedIndices: directUnit.consumedIndices
|
|
1960
|
+
};
|
|
1961
|
+
}
|
|
1962
|
+
const scaleToken = tokens[numberIndex + 1];
|
|
1963
|
+
if (!scaleToken || consumed.has(scaleToken.index)) {
|
|
1964
|
+
return { doseValue: value, consumedIndices: [] };
|
|
1965
|
+
}
|
|
1966
|
+
const multiplier = DOSE_SCALE_MULTIPLIERS[normalizeTokenLower(scaleToken)];
|
|
1967
|
+
if (!multiplier) {
|
|
1968
|
+
return { doseValue: value, consumedIndices: [] };
|
|
1969
|
+
}
|
|
1970
|
+
const scaledUnit = resolveUnitTokenAt(tokens, numberIndex + 2, consumed, options);
|
|
1971
|
+
if (!scaledUnit) {
|
|
1972
|
+
return { doseValue: value, consumedIndices: [] };
|
|
1973
|
+
}
|
|
1974
|
+
return {
|
|
1975
|
+
doseValue: value * multiplier,
|
|
1976
|
+
unit: scaledUnit.unit,
|
|
1977
|
+
consumedIndices: [numberIndex + 1, ...scaledUnit.consumedIndices]
|
|
1978
|
+
};
|
|
1979
|
+
}
|
|
1751
1980
|
function parseInternal(input, options) {
|
|
1752
1981
|
var _a, _b, _c, _d, _e, _f, _g, _h;
|
|
1753
1982
|
const tokens = tokenize(input);
|
|
@@ -2063,11 +2292,13 @@ function parseInternal(input, options) {
|
|
|
2063
2292
|
}
|
|
2064
2293
|
}
|
|
2065
2294
|
// Day of week
|
|
2066
|
-
const
|
|
2067
|
-
if (
|
|
2068
|
-
|
|
2069
|
-
|
|
2070
|
-
|
|
2295
|
+
const rangeConsumed = tryConsumeDayRangeTokens(internal, tokens, i);
|
|
2296
|
+
if (rangeConsumed > 0) {
|
|
2297
|
+
continue;
|
|
2298
|
+
}
|
|
2299
|
+
const days = resolveDayTokenDays(normalizeTokenLower(token));
|
|
2300
|
+
if (days) {
|
|
2301
|
+
addDayOfWeekList(internal, days);
|
|
2071
2302
|
mark(internal.consumed, token);
|
|
2072
2303
|
continue;
|
|
2073
2304
|
}
|
|
@@ -2210,29 +2441,27 @@ function parseInternal(input, options) {
|
|
|
2210
2441
|
internal.doseRange = rangeValue;
|
|
2211
2442
|
}
|
|
2212
2443
|
mark(internal.consumed, token);
|
|
2213
|
-
const
|
|
2214
|
-
if (
|
|
2215
|
-
|
|
2216
|
-
|
|
2217
|
-
internal.
|
|
2218
|
-
mark(internal.consumed, unitToken);
|
|
2444
|
+
const resolvedUnit = resolveUnitTokenAt(tokens, i + 1, internal.consumed, options);
|
|
2445
|
+
if (resolvedUnit) {
|
|
2446
|
+
internal.unit = resolvedUnit.unit;
|
|
2447
|
+
for (const consumedIndex of resolvedUnit.consumedIndices) {
|
|
2448
|
+
mark(internal.consumed, tokens[consumedIndex]);
|
|
2219
2449
|
}
|
|
2220
2450
|
}
|
|
2221
2451
|
continue;
|
|
2222
2452
|
}
|
|
2223
2453
|
if (/^[0-9]+(?:\.[0-9]+)?$/.test(token.lower)) {
|
|
2224
2454
|
const value = parseFloat(token.original);
|
|
2455
|
+
const resolvedDose = resolveNumericDoseUnit(tokens, i, value, internal.consumed, options);
|
|
2225
2456
|
if (internal.dose === undefined) {
|
|
2226
|
-
internal.dose =
|
|
2457
|
+
internal.dose = resolvedDose.doseValue;
|
|
2227
2458
|
}
|
|
2228
2459
|
mark(internal.consumed, token);
|
|
2229
|
-
|
|
2230
|
-
|
|
2231
|
-
|
|
2232
|
-
|
|
2233
|
-
|
|
2234
|
-
mark(internal.consumed, unitToken);
|
|
2235
|
-
}
|
|
2460
|
+
if (resolvedDose.unit) {
|
|
2461
|
+
internal.unit = resolvedDose.unit;
|
|
2462
|
+
}
|
|
2463
|
+
for (const consumedIndex of resolvedDose.consumedIndices) {
|
|
2464
|
+
mark(internal.consumed, tokens[consumedIndex]);
|
|
2236
2465
|
}
|
|
2237
2466
|
continue;
|
|
2238
2467
|
}
|