ezmedicationinput 0.1.20 → 0.1.22
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/README.md +8 -1
- package/dist/parser.js +80 -22
- package/dist/types.d.ts +12 -3
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -293,8 +293,15 @@ You can specify the number of times (total count) the medication is supposed to
|
|
|
293
293
|
- `context`: optional medication context (dosage form, strength, container
|
|
294
294
|
metadata) used to infer default units when a sig omits explicit units. Pass
|
|
295
295
|
`null` to explicitly disable context-based inference.
|
|
296
|
-
- `smartMealExpansion`: when `true`, generic AC/PC/C
|
|
296
|
+
- `smartMealExpansion`: when `true`, generic AC/PC/C meal abbreviations and
|
|
297
|
+
cadence-only instructions expand into concrete with-meal EventTiming
|
|
298
|
+
combinations (e.g. `1x3` → breakfast/lunch/dinner). This also respects
|
|
299
|
+
`context.mealRelation` when provided and only applies to schedules with four
|
|
300
|
+
or fewer daily doses.
|
|
297
301
|
- `twoPerDayPair`: controls whether 2× AC/PC/C doses expand to breakfast+dinner (default) or breakfast+lunch.
|
|
302
|
+
- `assumeSingleDiscreteDose`: when `true`, missing discrete doses (such as
|
|
303
|
+
tablets or capsules) default to a single unit when the parser can infer a
|
|
304
|
+
countable unit from context.
|
|
298
305
|
- `eventClock`: optional map of `EventTiming` codes to HH:mm strings that drives chronological ordering of parsed `when` values.
|
|
299
306
|
- `allowHouseholdVolumeUnits`: defaults to `true`; set to `false` to ignore
|
|
300
307
|
teaspoon/tablespoon units during parsing and suggestions.
|
package/dist/parser.js
CHANGED
|
@@ -134,6 +134,36 @@ const SITE_FILLER_WORDS = new Set([
|
|
|
134
134
|
"my"
|
|
135
135
|
]);
|
|
136
136
|
const HOUSEHOLD_VOLUME_UNIT_SET = new Set(maps_1.HOUSEHOLD_VOLUME_UNITS.map((unit) => unit.toLowerCase()));
|
|
137
|
+
const DISCRETE_UNIT_SET = new Set([
|
|
138
|
+
"tab",
|
|
139
|
+
"tabs",
|
|
140
|
+
"tablet",
|
|
141
|
+
"tablets",
|
|
142
|
+
"cap",
|
|
143
|
+
"caps",
|
|
144
|
+
"capsule",
|
|
145
|
+
"capsules",
|
|
146
|
+
"puff",
|
|
147
|
+
"puffs",
|
|
148
|
+
"spray",
|
|
149
|
+
"sprays",
|
|
150
|
+
"drop",
|
|
151
|
+
"drops",
|
|
152
|
+
"patch",
|
|
153
|
+
"patches",
|
|
154
|
+
"suppository",
|
|
155
|
+
"suppositories",
|
|
156
|
+
"implant",
|
|
157
|
+
"implants",
|
|
158
|
+
"piece",
|
|
159
|
+
"pieces",
|
|
160
|
+
"stick",
|
|
161
|
+
"sticks",
|
|
162
|
+
"pessary",
|
|
163
|
+
"pessaries",
|
|
164
|
+
"lozenge",
|
|
165
|
+
"lozenges"
|
|
166
|
+
]);
|
|
137
167
|
const OCULAR_DIRECTION_WORDS = new Set([
|
|
138
168
|
"left",
|
|
139
169
|
"right",
|
|
@@ -1067,13 +1097,12 @@ function reconcileMealTimingSpecificity(internal) {
|
|
|
1067
1097
|
]);
|
|
1068
1098
|
}
|
|
1069
1099
|
// Optionally replace generic meal tokens with concrete breakfast/lunch/dinner
|
|
1070
|
-
// EventTiming codes when the cadence
|
|
1100
|
+
// EventTiming codes when the cadence or explicit meal abbreviations make the
|
|
1101
|
+
// intent obvious.
|
|
1071
1102
|
function expandMealTimings(internal, options) {
|
|
1072
|
-
var _a;
|
|
1073
|
-
|
|
1074
|
-
|
|
1075
|
-
}
|
|
1076
|
-
if (!internal.when.length) {
|
|
1103
|
+
var _a, _b, _c;
|
|
1104
|
+
const allowSmartExpansion = (options === null || options === void 0 ? void 0 : options.smartMealExpansion) === true;
|
|
1105
|
+
if (!allowSmartExpansion) {
|
|
1077
1106
|
return;
|
|
1078
1107
|
}
|
|
1079
1108
|
if (internal.when.some((code) => SPECIFIC_MEAL_TIMINGS.has(code))) {
|
|
@@ -1083,6 +1112,14 @@ function expandMealTimings(internal, options) {
|
|
|
1083
1112
|
if (!frequency || frequency < 1 || frequency > 4) {
|
|
1084
1113
|
return;
|
|
1085
1114
|
}
|
|
1115
|
+
const needsDefaultExpansion = internal.when.length === 0 && frequency >= 2;
|
|
1116
|
+
const hasBeforeMeal = (0, array_1.arrayIncludes)(internal.when, types_1.EventTiming["Before Meal"]);
|
|
1117
|
+
const hasAfterMeal = (0, array_1.arrayIncludes)(internal.when, types_1.EventTiming["After Meal"]);
|
|
1118
|
+
const hasWithMeal = (0, array_1.arrayIncludes)(internal.when, types_1.EventTiming.Meal);
|
|
1119
|
+
const hasGeneralMealToken = hasBeforeMeal || hasAfterMeal || hasWithMeal;
|
|
1120
|
+
if (!hasGeneralMealToken && !needsDefaultExpansion) {
|
|
1121
|
+
return;
|
|
1122
|
+
}
|
|
1086
1123
|
if (internal.period !== undefined &&
|
|
1087
1124
|
internal.periodUnit !== undefined &&
|
|
1088
1125
|
(internal.periodUnit !== types_1.FhirPeriodUnit.Day || internal.period !== 1)) {
|
|
@@ -1099,28 +1136,36 @@ function expandMealTimings(internal, options) {
|
|
|
1099
1136
|
if (internal.frequencyMax !== undefined || internal.periodMax !== undefined) {
|
|
1100
1137
|
return;
|
|
1101
1138
|
}
|
|
1102
|
-
const pairPreference = (_a = options.twoPerDayPair) !== null && _a !== void 0 ? _a : "breakfast+dinner";
|
|
1139
|
+
const pairPreference = (_a = options === null || options === void 0 ? void 0 : options.twoPerDayPair) !== null && _a !== void 0 ? _a : "breakfast+dinner";
|
|
1103
1140
|
const replacements = [];
|
|
1104
|
-
|
|
1105
|
-
const specifics = computeMealExpansions(
|
|
1141
|
+
const addReplacement = (general, base, removeGeneral) => {
|
|
1142
|
+
const specifics = computeMealExpansions(base, frequency, pairPreference);
|
|
1106
1143
|
if (specifics) {
|
|
1107
|
-
replacements.push({ general
|
|
1144
|
+
replacements.push({ general, specifics, removeGeneral });
|
|
1108
1145
|
}
|
|
1146
|
+
};
|
|
1147
|
+
if (hasBeforeMeal) {
|
|
1148
|
+
addReplacement(types_1.EventTiming["Before Meal"], "before", true);
|
|
1109
1149
|
}
|
|
1110
|
-
if (
|
|
1111
|
-
|
|
1112
|
-
if (specifics) {
|
|
1113
|
-
replacements.push({ general: types_1.EventTiming["After Meal"], specifics });
|
|
1114
|
-
}
|
|
1150
|
+
if (hasAfterMeal) {
|
|
1151
|
+
addReplacement(types_1.EventTiming["After Meal"], "after", true);
|
|
1115
1152
|
}
|
|
1116
|
-
if (
|
|
1117
|
-
|
|
1118
|
-
|
|
1119
|
-
|
|
1120
|
-
|
|
1153
|
+
if (hasWithMeal) {
|
|
1154
|
+
addReplacement(types_1.EventTiming.Meal, "with", true);
|
|
1155
|
+
}
|
|
1156
|
+
if (needsDefaultExpansion) {
|
|
1157
|
+
const relation = (_c = (_b = options === null || options === void 0 ? void 0 : options.context) === null || _b === void 0 ? void 0 : _b.mealRelation) !== null && _c !== void 0 ? _c : types_1.EventTiming.Meal;
|
|
1158
|
+
const base = relation === types_1.EventTiming["Before Meal"]
|
|
1159
|
+
? "before"
|
|
1160
|
+
: relation === types_1.EventTiming["After Meal"]
|
|
1161
|
+
? "after"
|
|
1162
|
+
: "with";
|
|
1163
|
+
addReplacement(relation, base, false);
|
|
1121
1164
|
}
|
|
1122
|
-
for (const { general, specifics } of replacements) {
|
|
1123
|
-
|
|
1165
|
+
for (const { general, specifics, removeGeneral } of replacements) {
|
|
1166
|
+
if (removeGeneral) {
|
|
1167
|
+
removeWhen(internal.when, general);
|
|
1168
|
+
}
|
|
1124
1169
|
for (const specific of specifics) {
|
|
1125
1170
|
addWhen(internal.when, specific);
|
|
1126
1171
|
}
|
|
@@ -1857,6 +1902,13 @@ function parseInternal(input, options) {
|
|
|
1857
1902
|
internal.unit = fallbackUnit;
|
|
1858
1903
|
}
|
|
1859
1904
|
}
|
|
1905
|
+
if ((options === null || options === void 0 ? void 0 : options.assumeSingleDiscreteDose) &&
|
|
1906
|
+
internal.dose === undefined &&
|
|
1907
|
+
internal.doseRange === undefined &&
|
|
1908
|
+
internal.unit !== undefined &&
|
|
1909
|
+
isDiscreteUnit(internal.unit)) {
|
|
1910
|
+
internal.dose = 1;
|
|
1911
|
+
}
|
|
1860
1912
|
// Frequency defaults when timing code implies it
|
|
1861
1913
|
if (internal.frequency === undefined &&
|
|
1862
1914
|
internal.period === undefined &&
|
|
@@ -3264,6 +3316,12 @@ function enforceHouseholdUnitPolicy(unit, options) {
|
|
|
3264
3316
|
}
|
|
3265
3317
|
return unit;
|
|
3266
3318
|
}
|
|
3319
|
+
function isDiscreteUnit(unit) {
|
|
3320
|
+
if (!unit) {
|
|
3321
|
+
return false;
|
|
3322
|
+
}
|
|
3323
|
+
return DISCRETE_UNIT_SET.has(unit.trim().toLowerCase());
|
|
3324
|
+
}
|
|
3267
3325
|
function inferUnitFromRouteHints(internal) {
|
|
3268
3326
|
if (internal.routeCode) {
|
|
3269
3327
|
const unit = maps_1.DEFAULT_UNIT_BY_ROUTE[internal.routeCode];
|
package/dist/types.d.ts
CHANGED
|
@@ -285,6 +285,7 @@ export interface MedicationContext {
|
|
|
285
285
|
containerValue?: number;
|
|
286
286
|
containerUnit?: string;
|
|
287
287
|
defaultUnit?: string;
|
|
288
|
+
mealRelation?: (typeof EventTiming)["Before Meal"] | (typeof EventTiming)["After Meal"] | (typeof EventTiming)["Meal"];
|
|
288
289
|
}
|
|
289
290
|
export interface FormatOptions {
|
|
290
291
|
locale?: "en" | "th" | string;
|
|
@@ -428,9 +429,17 @@ export interface ParseOptions extends FormatOptions {
|
|
|
428
429
|
eventClock?: EventClockMap;
|
|
429
430
|
allowDiscouraged?: boolean;
|
|
430
431
|
/**
|
|
431
|
-
* When enabled the parser will
|
|
432
|
-
*
|
|
433
|
-
*
|
|
432
|
+
* When enabled the parser will assume a single discrete unit (e.g., one
|
|
433
|
+
* tablet/capsule) when no explicit dose is provided and the inferred unit is
|
|
434
|
+
* countable.
|
|
435
|
+
*/
|
|
436
|
+
assumeSingleDiscreteDose?: boolean;
|
|
437
|
+
/**
|
|
438
|
+
* Enables inferring with-meal timings when explicit meal language is present
|
|
439
|
+
* or implied by cadence alone. Generic meal abbreviations (AC/PC/C) and
|
|
440
|
+
* cadence-only instructions expand into specific breakfast/lunch/dinner (and
|
|
441
|
+
* bedtime) EventTiming entries. Works in conjunction with
|
|
442
|
+
* `context.mealRelation` when provided.
|
|
434
443
|
*/
|
|
435
444
|
smartMealExpansion?: boolean;
|
|
436
445
|
/**
|