ezmedicationinput 0.1.39 → 0.1.41
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/index.js +194 -2
- package/dist/maps.js +33 -1
- package/dist/parser.js +247 -25
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -58,6 +58,15 @@ Object.defineProperty(exports, "DEFAULT_BODY_SITE_SNOMED_SOURCE", { enumerable:
|
|
|
58
58
|
Object.defineProperty(exports, "DEFAULT_ROUTE_SYNONYMS", { enumerable: true, get: function () { return maps_1.DEFAULT_ROUTE_SYNONYMS; } });
|
|
59
59
|
Object.defineProperty(exports, "DEFAULT_UNIT_BY_ROUTE", { enumerable: true, get: function () { return maps_1.DEFAULT_UNIT_BY_ROUTE; } });
|
|
60
60
|
Object.defineProperty(exports, "KNOWN_DOSAGE_FORMS_TO_DOSE", { enumerable: true, get: function () { return maps_1.KNOWN_DOSAGE_FORMS_TO_DOSE; } });
|
|
61
|
+
const REPEAT_NON_ANCHOR_KEYS = [
|
|
62
|
+
"count",
|
|
63
|
+
"frequency",
|
|
64
|
+
"frequencyMax",
|
|
65
|
+
"period",
|
|
66
|
+
"periodMax",
|
|
67
|
+
"periodUnit",
|
|
68
|
+
"offset"
|
|
69
|
+
];
|
|
61
70
|
function parseMealDashValues(token) {
|
|
62
71
|
if (!/^[0-9]+(?:\.[0-9]+)?(?:-[0-9]+(?:\.[0-9]+)?){2,3}$/.test(token)) {
|
|
63
72
|
return undefined;
|
|
@@ -155,6 +164,189 @@ function toSegmentMeta(segments) {
|
|
|
155
164
|
range: { start: segment.start, end: segment.end }
|
|
156
165
|
}));
|
|
157
166
|
}
|
|
167
|
+
/**
|
|
168
|
+
* Deep equality helper for plain JSON-like parser output objects.
|
|
169
|
+
*
|
|
170
|
+
* @param left Left-side value.
|
|
171
|
+
* @param right Right-side value.
|
|
172
|
+
* @returns `true` when both values are structurally equal.
|
|
173
|
+
*/
|
|
174
|
+
function deepEqual(left, right) {
|
|
175
|
+
if (left === right) {
|
|
176
|
+
return true;
|
|
177
|
+
}
|
|
178
|
+
if (left === null || right === null) {
|
|
179
|
+
return left === right;
|
|
180
|
+
}
|
|
181
|
+
if (Array.isArray(left) || Array.isArray(right)) {
|
|
182
|
+
if (!Array.isArray(left) || !Array.isArray(right)) {
|
|
183
|
+
return false;
|
|
184
|
+
}
|
|
185
|
+
if (left.length !== right.length) {
|
|
186
|
+
return false;
|
|
187
|
+
}
|
|
188
|
+
for (let i = 0; i < left.length; i += 1) {
|
|
189
|
+
if (!deepEqual(left[i], right[i])) {
|
|
190
|
+
return false;
|
|
191
|
+
}
|
|
192
|
+
}
|
|
193
|
+
return true;
|
|
194
|
+
}
|
|
195
|
+
if (typeof left !== "object" || typeof right !== "object") {
|
|
196
|
+
return false;
|
|
197
|
+
}
|
|
198
|
+
const leftRecord = left;
|
|
199
|
+
const rightRecord = right;
|
|
200
|
+
const leftKeys = Object.keys(leftRecord).filter((key) => leftRecord[key] !== undefined);
|
|
201
|
+
const rightKeys = Object.keys(rightRecord).filter((key) => rightRecord[key] !== undefined);
|
|
202
|
+
if (leftKeys.length !== rightKeys.length) {
|
|
203
|
+
return false;
|
|
204
|
+
}
|
|
205
|
+
for (const key of leftKeys) {
|
|
206
|
+
if (!Object.prototype.hasOwnProperty.call(rightRecord, key)) {
|
|
207
|
+
return false;
|
|
208
|
+
}
|
|
209
|
+
if (!deepEqual(leftRecord[key], rightRecord[key])) {
|
|
210
|
+
return false;
|
|
211
|
+
}
|
|
212
|
+
}
|
|
213
|
+
return true;
|
|
214
|
+
}
|
|
215
|
+
/**
|
|
216
|
+
* Compares two string arrays as sets.
|
|
217
|
+
*
|
|
218
|
+
* @param left Left array.
|
|
219
|
+
* @param right Right array.
|
|
220
|
+
* @returns `true` when both arrays contain the same unique values.
|
|
221
|
+
*/
|
|
222
|
+
function sameStringSet(left, right) {
|
|
223
|
+
const a = left !== null && left !== void 0 ? left : [];
|
|
224
|
+
const b = right !== null && right !== void 0 ? right : [];
|
|
225
|
+
if (a.length !== b.length) {
|
|
226
|
+
return false;
|
|
227
|
+
}
|
|
228
|
+
const set = new Set(a);
|
|
229
|
+
if (set.size !== b.length) {
|
|
230
|
+
return false;
|
|
231
|
+
}
|
|
232
|
+
for (const value of b) {
|
|
233
|
+
if (!set.has(value)) {
|
|
234
|
+
return false;
|
|
235
|
+
}
|
|
236
|
+
}
|
|
237
|
+
return true;
|
|
238
|
+
}
|
|
239
|
+
/**
|
|
240
|
+
* Determines whether a repeat block only uses merge-safe anchor fields.
|
|
241
|
+
*
|
|
242
|
+
* @param repeat FHIR timing repeat payload.
|
|
243
|
+
* @returns `true` when repeat contains only `when`/`timeOfDay`/`dayOfWeek`.
|
|
244
|
+
*/
|
|
245
|
+
function isMergeableAnchorRepeat(repeat) {
|
|
246
|
+
if (!repeat) {
|
|
247
|
+
return true;
|
|
248
|
+
}
|
|
249
|
+
for (const key of REPEAT_NON_ANCHOR_KEYS) {
|
|
250
|
+
if (repeat[key] !== undefined) {
|
|
251
|
+
return false;
|
|
252
|
+
}
|
|
253
|
+
}
|
|
254
|
+
return true;
|
|
255
|
+
}
|
|
256
|
+
/**
|
|
257
|
+
* Checks whether two parsed items can be merged without changing semantics.
|
|
258
|
+
*
|
|
259
|
+
* @param base Existing merged item candidate.
|
|
260
|
+
* @param next Incoming parsed item.
|
|
261
|
+
* @returns `true` when both items differ only by merge-safe timing anchors.
|
|
262
|
+
*/
|
|
263
|
+
function canMergeTimingOnly(base, next) {
|
|
264
|
+
const baseTiming = base.fhir.timing;
|
|
265
|
+
const nextTiming = next.fhir.timing;
|
|
266
|
+
const baseRepeat = baseTiming === null || baseTiming === void 0 ? void 0 : baseTiming.repeat;
|
|
267
|
+
const nextRepeat = nextTiming === null || nextTiming === void 0 ? void 0 : nextTiming.repeat;
|
|
268
|
+
if (!baseRepeat || !nextRepeat) {
|
|
269
|
+
return false;
|
|
270
|
+
}
|
|
271
|
+
if (!isMergeableAnchorRepeat(baseRepeat) || !isMergeableAnchorRepeat(nextRepeat)) {
|
|
272
|
+
return false;
|
|
273
|
+
}
|
|
274
|
+
if (!sameStringSet(baseRepeat.dayOfWeek, nextRepeat.dayOfWeek)) {
|
|
275
|
+
return false;
|
|
276
|
+
}
|
|
277
|
+
if (!deepEqual(baseTiming === null || baseTiming === void 0 ? void 0 : baseTiming.code, nextTiming === null || nextTiming === void 0 ? void 0 : nextTiming.code)) {
|
|
278
|
+
return false;
|
|
279
|
+
}
|
|
280
|
+
if (!deepEqual(baseTiming === null || baseTiming === void 0 ? void 0 : baseTiming.event, nextTiming === null || nextTiming === void 0 ? void 0 : nextTiming.event)) {
|
|
281
|
+
return false;
|
|
282
|
+
}
|
|
283
|
+
return (deepEqual(base.fhir.doseAndRate, next.fhir.doseAndRate) &&
|
|
284
|
+
deepEqual(base.fhir.route, next.fhir.route) &&
|
|
285
|
+
deepEqual(base.fhir.site, next.fhir.site) &&
|
|
286
|
+
deepEqual(base.fhir.additionalInstruction, next.fhir.additionalInstruction) &&
|
|
287
|
+
deepEqual(base.fhir.asNeededBoolean, next.fhir.asNeededBoolean) &&
|
|
288
|
+
deepEqual(base.fhir.asNeededFor, next.fhir.asNeededFor));
|
|
289
|
+
}
|
|
290
|
+
/**
|
|
291
|
+
* Returns a stable unique list preserving first-seen order.
|
|
292
|
+
*
|
|
293
|
+
* @param values Input values.
|
|
294
|
+
* @returns Deduplicated values in insertion order.
|
|
295
|
+
*/
|
|
296
|
+
function uniqueStrings(values) {
|
|
297
|
+
const seen = new Set();
|
|
298
|
+
const output = [];
|
|
299
|
+
for (const value of values) {
|
|
300
|
+
if (!seen.has(value)) {
|
|
301
|
+
seen.add(value);
|
|
302
|
+
output.push(value);
|
|
303
|
+
}
|
|
304
|
+
}
|
|
305
|
+
return output;
|
|
306
|
+
}
|
|
307
|
+
/**
|
|
308
|
+
* Merges two parse results that are known to be timing-compatible.
|
|
309
|
+
*
|
|
310
|
+
* @param base Existing merged result.
|
|
311
|
+
* @param next Next result to fold into `base`.
|
|
312
|
+
* @param options Parse options used to render localized text.
|
|
313
|
+
* @returns New merged parse result.
|
|
314
|
+
*/
|
|
315
|
+
function mergeParseResults(base, next, options) {
|
|
316
|
+
var _a, _b, _c, _d, _e, _f, _g, _h, _j, _k, _l, _m, _o, _p, _q, _r, _s;
|
|
317
|
+
const baseRepeat = (_b = (_a = base.fhir.timing) === null || _a === void 0 ? void 0 : _a.repeat) !== null && _b !== void 0 ? _b : {};
|
|
318
|
+
const nextRepeat = (_d = (_c = next.fhir.timing) === null || _c === void 0 ? void 0 : _c.repeat) !== null && _d !== void 0 ? _d : {};
|
|
319
|
+
const mergedWhen = uniqueStrings([...((_e = baseRepeat.when) !== null && _e !== void 0 ? _e : []), ...((_f = nextRepeat.when) !== null && _f !== void 0 ? _f : [])]);
|
|
320
|
+
const mergedTimeOfDay = uniqueStrings([...((_g = baseRepeat.timeOfDay) !== null && _g !== void 0 ? _g : []), ...((_h = nextRepeat.timeOfDay) !== null && _h !== void 0 ? _h : [])]).sort();
|
|
321
|
+
const mergedRepeat = Object.assign(Object.assign(Object.assign(Object.assign({}, baseRepeat), (nextRepeat.dayOfWeek ? { dayOfWeek: nextRepeat.dayOfWeek } : {})), (mergedWhen.length ? { when: mergedWhen } : {})), (mergedTimeOfDay.length ? { timeOfDay: mergedTimeOfDay } : {}));
|
|
322
|
+
const mergedFhir = Object.assign(Object.assign({}, base.fhir), { timing: Object.assign(Object.assign({}, ((_j = base.fhir.timing) !== null && _j !== void 0 ? _j : {})), { repeat: mergedRepeat }) });
|
|
323
|
+
const shortText = formatSig(mergedFhir, "short", options);
|
|
324
|
+
const longText = formatSig(mergedFhir, "long", options);
|
|
325
|
+
mergedFhir.text = longText;
|
|
326
|
+
return {
|
|
327
|
+
fhir: mergedFhir,
|
|
328
|
+
shortText,
|
|
329
|
+
longText,
|
|
330
|
+
warnings: uniqueStrings([...((_k = base.warnings) !== null && _k !== void 0 ? _k : []), ...((_l = next.warnings) !== null && _l !== void 0 ? _l : [])]),
|
|
331
|
+
meta: Object.assign(Object.assign({}, base.meta), { consumedTokens: uniqueStrings([...((_m = base.meta.consumedTokens) !== null && _m !== void 0 ? _m : []), ...((_o = next.meta.consumedTokens) !== null && _o !== void 0 ? _o : [])]), leftoverText: uniqueStrings([base.meta.leftoverText, next.meta.leftoverText].filter((value) => !!value)).join(" ").trim() || undefined, siteLookups: [...((_p = base.meta.siteLookups) !== null && _p !== void 0 ? _p : []), ...((_q = next.meta.siteLookups) !== null && _q !== void 0 ? _q : [])], prnReasonLookups: [...((_r = base.meta.prnReasonLookups) !== null && _r !== void 0 ? _r : []), ...((_s = next.meta.prnReasonLookups) !== null && _s !== void 0 ? _s : [])] })
|
|
332
|
+
};
|
|
333
|
+
}
|
|
334
|
+
/**
|
|
335
|
+
* Appends a parsed segment result to the batch, reusing the current item when
|
|
336
|
+
* timing-only expansion can be represented as a single dosage element.
|
|
337
|
+
*
|
|
338
|
+
* @param items Accumulated batch items.
|
|
339
|
+
* @param next Newly parsed segment result.
|
|
340
|
+
* @param options Parse options used to format merged text.
|
|
341
|
+
*/
|
|
342
|
+
function appendParseResult(items, next, options) {
|
|
343
|
+
const previous = items[items.length - 1];
|
|
344
|
+
if (previous && canMergeTimingOnly(previous, next)) {
|
|
345
|
+
items[items.length - 1] = mergeParseResults(previous, next, options);
|
|
346
|
+
return;
|
|
347
|
+
}
|
|
348
|
+
items.push(next);
|
|
349
|
+
}
|
|
158
350
|
function parseSig(input, options) {
|
|
159
351
|
const segments = expandMealDashSegments((0, segment_1.splitSigSegments)(input), options);
|
|
160
352
|
const carry = {};
|
|
@@ -166,7 +358,7 @@ function parseSig(input, options) {
|
|
|
166
358
|
(0, parser_1.applySiteCoding)(internal, options);
|
|
167
359
|
const result = buildParseResult(internal, options);
|
|
168
360
|
rebaseParseResult(result, input, segment.start);
|
|
169
|
-
results
|
|
361
|
+
appendParseResult(results, result, options);
|
|
170
362
|
updateCarryForward(carry, internal);
|
|
171
363
|
}
|
|
172
364
|
const legacy = resolveLegacyParseResult(results, input, options);
|
|
@@ -232,7 +424,7 @@ function parseSigAsync(input, options) {
|
|
|
232
424
|
yield (0, parser_1.applySiteCodingAsync)(internal, options);
|
|
233
425
|
const result = buildParseResult(internal, options);
|
|
234
426
|
rebaseParseResult(result, input, segment.start);
|
|
235
|
-
results
|
|
427
|
+
appendParseResult(results, result, options);
|
|
236
428
|
updateCarryForward(carry, internal);
|
|
237
429
|
}
|
|
238
430
|
const legacy = resolveLegacyParseResult(results, input, options);
|
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",
|
|
@@ -965,6 +970,7 @@ const SITE_UNIT_ROUTE_HINTS = [
|
|
|
965
970
|
function tokenize(input) {
|
|
966
971
|
const separators = /[(),;]/g;
|
|
967
972
|
let normalized = input.trim().replace(separators, " ");
|
|
973
|
+
normalized = normalized.replace(DAY_RANGE_SPACED_HYPHEN_REGEX, (_match, prefix, start, end) => `${prefix}${start}-${end}`);
|
|
968
974
|
normalized = normalized.replace(/\s-\s/g, " ; ");
|
|
969
975
|
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
976
|
normalized = normalized.replace(/(\d+)\s*\/\s*(\d+)/g, (match, num, den) => {
|
|
@@ -1585,6 +1591,154 @@ function isTimingAnchorOrPrefix(tokens, index, prnReasonStart) {
|
|
|
1585
1591
|
(isAtPrefixToken(lower) || lower === "on" || lower === "with") ||
|
|
1586
1592
|
/^\d/.test(lower));
|
|
1587
1593
|
}
|
|
1594
|
+
const DAY_SEQUENCE = [
|
|
1595
|
+
types_1.FhirDayOfWeek.Monday,
|
|
1596
|
+
types_1.FhirDayOfWeek.Tuesday,
|
|
1597
|
+
types_1.FhirDayOfWeek.Wednesday,
|
|
1598
|
+
types_1.FhirDayOfWeek.Thursday,
|
|
1599
|
+
types_1.FhirDayOfWeek.Friday,
|
|
1600
|
+
types_1.FhirDayOfWeek.Saturday,
|
|
1601
|
+
types_1.FhirDayOfWeek.Sunday
|
|
1602
|
+
];
|
|
1603
|
+
const DAY_GROUP_TOKENS = {
|
|
1604
|
+
weekend: [types_1.FhirDayOfWeek.Saturday, types_1.FhirDayOfWeek.Sunday],
|
|
1605
|
+
weekends: [types_1.FhirDayOfWeek.Saturday, types_1.FhirDayOfWeek.Sunday],
|
|
1606
|
+
wknd: [types_1.FhirDayOfWeek.Saturday, types_1.FhirDayOfWeek.Sunday],
|
|
1607
|
+
weekdays: [
|
|
1608
|
+
types_1.FhirDayOfWeek.Monday,
|
|
1609
|
+
types_1.FhirDayOfWeek.Tuesday,
|
|
1610
|
+
types_1.FhirDayOfWeek.Wednesday,
|
|
1611
|
+
types_1.FhirDayOfWeek.Thursday,
|
|
1612
|
+
types_1.FhirDayOfWeek.Friday
|
|
1613
|
+
],
|
|
1614
|
+
weekday: [
|
|
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
|
+
workday: [
|
|
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
|
+
workdays: [
|
|
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
|
+
วันธรรมดา: [
|
|
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
|
+
วันหยุด: [types_1.FhirDayOfWeek.Saturday, types_1.FhirDayOfWeek.Sunday],
|
|
1650
|
+
สุดสัปดาห์: [types_1.FhirDayOfWeek.Saturday, types_1.FhirDayOfWeek.Sunday],
|
|
1651
|
+
เสาร์อาทิตย์: [types_1.FhirDayOfWeek.Saturday, types_1.FhirDayOfWeek.Sunday],
|
|
1652
|
+
จันทร์ถึงศุกร์: [
|
|
1653
|
+
types_1.FhirDayOfWeek.Monday,
|
|
1654
|
+
types_1.FhirDayOfWeek.Tuesday,
|
|
1655
|
+
types_1.FhirDayOfWeek.Wednesday,
|
|
1656
|
+
types_1.FhirDayOfWeek.Thursday,
|
|
1657
|
+
types_1.FhirDayOfWeek.Friday
|
|
1658
|
+
]
|
|
1659
|
+
};
|
|
1660
|
+
const DAY_RANGE_CONNECTOR_TOKENS = new Set(["-", "to", "through", "thru", "ถึง", "จนถึง"]);
|
|
1661
|
+
function addDayOfWeek(internal, day) {
|
|
1662
|
+
if (!(0, array_1.arrayIncludes)(internal.dayOfWeek, day)) {
|
|
1663
|
+
internal.dayOfWeek.push(day);
|
|
1664
|
+
}
|
|
1665
|
+
}
|
|
1666
|
+
function addDayOfWeekList(internal, days) {
|
|
1667
|
+
for (const day of days) {
|
|
1668
|
+
addDayOfWeek(internal, day);
|
|
1669
|
+
}
|
|
1670
|
+
}
|
|
1671
|
+
function expandDayRange(start, end) {
|
|
1672
|
+
const startIndex = DAY_SEQUENCE.indexOf(start);
|
|
1673
|
+
const endIndex = DAY_SEQUENCE.indexOf(end);
|
|
1674
|
+
if (startIndex < 0 || endIndex < 0) {
|
|
1675
|
+
return [start, end];
|
|
1676
|
+
}
|
|
1677
|
+
if (startIndex <= endIndex) {
|
|
1678
|
+
return DAY_SEQUENCE.slice(startIndex, endIndex + 1);
|
|
1679
|
+
}
|
|
1680
|
+
return [...DAY_SEQUENCE.slice(startIndex), ...DAY_SEQUENCE.slice(0, endIndex + 1)];
|
|
1681
|
+
}
|
|
1682
|
+
function resolveDayTokenDays(tokenLower) {
|
|
1683
|
+
const normalized = tokenLower.replace(/[.,;:]/g, "");
|
|
1684
|
+
const direct = maps_1.DAY_OF_WEEK_TOKENS[normalized];
|
|
1685
|
+
if (direct) {
|
|
1686
|
+
return [direct];
|
|
1687
|
+
}
|
|
1688
|
+
const grouped = DAY_GROUP_TOKENS[normalized];
|
|
1689
|
+
if (grouped) {
|
|
1690
|
+
return grouped.slice();
|
|
1691
|
+
}
|
|
1692
|
+
const rangeMatch = normalized.match(/^([^-–—~]+)[-–—~]([^-–—~]+)$/);
|
|
1693
|
+
if (rangeMatch) {
|
|
1694
|
+
const start = maps_1.DAY_OF_WEEK_TOKENS[rangeMatch[1]];
|
|
1695
|
+
const end = maps_1.DAY_OF_WEEK_TOKENS[rangeMatch[2]];
|
|
1696
|
+
if (start && end) {
|
|
1697
|
+
return expandDayRange(start, end);
|
|
1698
|
+
}
|
|
1699
|
+
}
|
|
1700
|
+
const compactConnectorRange = normalized.match(/^(.+?)(ถึง|จนถึง|to|through|thru)(.+)$/u);
|
|
1701
|
+
if (compactConnectorRange) {
|
|
1702
|
+
const start = maps_1.DAY_OF_WEEK_TOKENS[compactConnectorRange[1]];
|
|
1703
|
+
const end = maps_1.DAY_OF_WEEK_TOKENS[compactConnectorRange[3]];
|
|
1704
|
+
if (start && end) {
|
|
1705
|
+
return expandDayRange(start, end);
|
|
1706
|
+
}
|
|
1707
|
+
}
|
|
1708
|
+
return undefined;
|
|
1709
|
+
}
|
|
1710
|
+
function tryConsumeDayRangeTokens(internal, tokens, index) {
|
|
1711
|
+
const startToken = tokens[index];
|
|
1712
|
+
if (!startToken || internal.consumed.has(startToken.index)) {
|
|
1713
|
+
return 0;
|
|
1714
|
+
}
|
|
1715
|
+
const startDays = resolveDayTokenDays(normalizeTokenLower(startToken));
|
|
1716
|
+
if (!startDays || startDays.length !== 1) {
|
|
1717
|
+
return 0;
|
|
1718
|
+
}
|
|
1719
|
+
const connectorToken = tokens[index + 1];
|
|
1720
|
+
const endToken = tokens[index + 2];
|
|
1721
|
+
if (!connectorToken ||
|
|
1722
|
+
!endToken ||
|
|
1723
|
+
internal.consumed.has(connectorToken.index) ||
|
|
1724
|
+
internal.consumed.has(endToken.index)) {
|
|
1725
|
+
return 0;
|
|
1726
|
+
}
|
|
1727
|
+
const connector = normalizeTokenLower(connectorToken);
|
|
1728
|
+
if (!DAY_RANGE_CONNECTOR_TOKENS.has(connector)) {
|
|
1729
|
+
return 0;
|
|
1730
|
+
}
|
|
1731
|
+
const endDays = resolveDayTokenDays(normalizeTokenLower(endToken));
|
|
1732
|
+
if (!endDays || endDays.length !== 1) {
|
|
1733
|
+
return 0;
|
|
1734
|
+
}
|
|
1735
|
+
const expanded = expandDayRange(startDays[0], endDays[0]);
|
|
1736
|
+
addDayOfWeekList(internal, expanded);
|
|
1737
|
+
mark(internal.consumed, startToken);
|
|
1738
|
+
mark(internal.consumed, connectorToken);
|
|
1739
|
+
mark(internal.consumed, endToken);
|
|
1740
|
+
return 3;
|
|
1741
|
+
}
|
|
1588
1742
|
function parseAnchorSequence(internal, tokens, index, prefixCode) {
|
|
1589
1743
|
var _a;
|
|
1590
1744
|
const token = tokens[index];
|
|
@@ -1594,16 +1748,20 @@ function parseAnchorSequence(internal, tokens, index, prefixCode) {
|
|
|
1594
1748
|
if (internal.consumed.has(nextToken.index)) {
|
|
1595
1749
|
continue;
|
|
1596
1750
|
}
|
|
1597
|
-
const lower = nextToken
|
|
1751
|
+
const lower = normalizeTokenLower(nextToken);
|
|
1598
1752
|
if (MEAL_CONTEXT_CONNECTORS.has(lower) || lower === ",") {
|
|
1599
1753
|
mark(internal.consumed, nextToken);
|
|
1600
1754
|
continue;
|
|
1601
1755
|
}
|
|
1602
|
-
const
|
|
1603
|
-
if (
|
|
1604
|
-
|
|
1605
|
-
|
|
1606
|
-
|
|
1756
|
+
const rangeConsumed = tryConsumeDayRangeTokens(internal, tokens, lookahead);
|
|
1757
|
+
if (rangeConsumed > 0) {
|
|
1758
|
+
converted++;
|
|
1759
|
+
lookahead += rangeConsumed - 1;
|
|
1760
|
+
continue;
|
|
1761
|
+
}
|
|
1762
|
+
const days = resolveDayTokenDays(lower);
|
|
1763
|
+
if (days) {
|
|
1764
|
+
addDayOfWeekList(internal, days);
|
|
1607
1765
|
mark(internal.consumed, nextToken);
|
|
1608
1766
|
converted++;
|
|
1609
1767
|
continue;
|
|
@@ -1748,6 +1906,70 @@ function applyCountLimit(internal, value) {
|
|
|
1748
1906
|
internal.count = rounded;
|
|
1749
1907
|
return true;
|
|
1750
1908
|
}
|
|
1909
|
+
const DOSE_SCALE_MULTIPLIERS = {
|
|
1910
|
+
k: 1000,
|
|
1911
|
+
thousand: 1000,
|
|
1912
|
+
m: 1000000,
|
|
1913
|
+
mn: 1000000,
|
|
1914
|
+
mio: 1000000,
|
|
1915
|
+
million: 1000000,
|
|
1916
|
+
b: 1000000000,
|
|
1917
|
+
bn: 1000000000,
|
|
1918
|
+
billion: 1000000000
|
|
1919
|
+
};
|
|
1920
|
+
function resolveUnitTokenAt(tokens, index, consumed, options) {
|
|
1921
|
+
const token = tokens[index];
|
|
1922
|
+
if (!token || consumed.has(token.index)) {
|
|
1923
|
+
return undefined;
|
|
1924
|
+
}
|
|
1925
|
+
const normalized = normalizeTokenLower(token);
|
|
1926
|
+
const direct = normalizeUnit(normalized, options);
|
|
1927
|
+
if (direct) {
|
|
1928
|
+
return { unit: direct, consumedIndices: [index] };
|
|
1929
|
+
}
|
|
1930
|
+
if (normalized === "international") {
|
|
1931
|
+
const nextToken = tokens[index + 1];
|
|
1932
|
+
if (!nextToken || consumed.has(nextToken.index)) {
|
|
1933
|
+
return undefined;
|
|
1934
|
+
}
|
|
1935
|
+
const nextNormalized = normalizeTokenLower(nextToken);
|
|
1936
|
+
if (nextNormalized === "unit" ||
|
|
1937
|
+
nextNormalized === "units" ||
|
|
1938
|
+
nextNormalized === "u" ||
|
|
1939
|
+
nextNormalized === "iu" ||
|
|
1940
|
+
nextNormalized === "ius") {
|
|
1941
|
+
return { unit: "IU", consumedIndices: [index, index + 1] };
|
|
1942
|
+
}
|
|
1943
|
+
}
|
|
1944
|
+
return undefined;
|
|
1945
|
+
}
|
|
1946
|
+
function resolveNumericDoseUnit(tokens, numberIndex, value, consumed, options) {
|
|
1947
|
+
const directUnit = resolveUnitTokenAt(tokens, numberIndex + 1, consumed, options);
|
|
1948
|
+
if (directUnit) {
|
|
1949
|
+
return {
|
|
1950
|
+
doseValue: value,
|
|
1951
|
+
unit: directUnit.unit,
|
|
1952
|
+
consumedIndices: directUnit.consumedIndices
|
|
1953
|
+
};
|
|
1954
|
+
}
|
|
1955
|
+
const scaleToken = tokens[numberIndex + 1];
|
|
1956
|
+
if (!scaleToken || consumed.has(scaleToken.index)) {
|
|
1957
|
+
return { doseValue: value, consumedIndices: [] };
|
|
1958
|
+
}
|
|
1959
|
+
const multiplier = DOSE_SCALE_MULTIPLIERS[normalizeTokenLower(scaleToken)];
|
|
1960
|
+
if (!multiplier) {
|
|
1961
|
+
return { doseValue: value, consumedIndices: [] };
|
|
1962
|
+
}
|
|
1963
|
+
const scaledUnit = resolveUnitTokenAt(tokens, numberIndex + 2, consumed, options);
|
|
1964
|
+
if (!scaledUnit) {
|
|
1965
|
+
return { doseValue: value, consumedIndices: [] };
|
|
1966
|
+
}
|
|
1967
|
+
return {
|
|
1968
|
+
doseValue: value * multiplier,
|
|
1969
|
+
unit: scaledUnit.unit,
|
|
1970
|
+
consumedIndices: [numberIndex + 1, ...scaledUnit.consumedIndices]
|
|
1971
|
+
};
|
|
1972
|
+
}
|
|
1751
1973
|
function parseInternal(input, options) {
|
|
1752
1974
|
var _a, _b, _c, _d, _e, _f, _g, _h;
|
|
1753
1975
|
const tokens = tokenize(input);
|
|
@@ -2063,11 +2285,13 @@ function parseInternal(input, options) {
|
|
|
2063
2285
|
}
|
|
2064
2286
|
}
|
|
2065
2287
|
// Day of week
|
|
2066
|
-
const
|
|
2067
|
-
if (
|
|
2068
|
-
|
|
2069
|
-
|
|
2070
|
-
|
|
2288
|
+
const rangeConsumed = tryConsumeDayRangeTokens(internal, tokens, i);
|
|
2289
|
+
if (rangeConsumed > 0) {
|
|
2290
|
+
continue;
|
|
2291
|
+
}
|
|
2292
|
+
const days = resolveDayTokenDays(normalizeTokenLower(token));
|
|
2293
|
+
if (days) {
|
|
2294
|
+
addDayOfWeekList(internal, days);
|
|
2071
2295
|
mark(internal.consumed, token);
|
|
2072
2296
|
continue;
|
|
2073
2297
|
}
|
|
@@ -2210,29 +2434,27 @@ function parseInternal(input, options) {
|
|
|
2210
2434
|
internal.doseRange = rangeValue;
|
|
2211
2435
|
}
|
|
2212
2436
|
mark(internal.consumed, token);
|
|
2213
|
-
const
|
|
2214
|
-
if (
|
|
2215
|
-
|
|
2216
|
-
|
|
2217
|
-
internal.
|
|
2218
|
-
mark(internal.consumed, unitToken);
|
|
2437
|
+
const resolvedUnit = resolveUnitTokenAt(tokens, i + 1, internal.consumed, options);
|
|
2438
|
+
if (resolvedUnit) {
|
|
2439
|
+
internal.unit = resolvedUnit.unit;
|
|
2440
|
+
for (const consumedIndex of resolvedUnit.consumedIndices) {
|
|
2441
|
+
mark(internal.consumed, tokens[consumedIndex]);
|
|
2219
2442
|
}
|
|
2220
2443
|
}
|
|
2221
2444
|
continue;
|
|
2222
2445
|
}
|
|
2223
2446
|
if (/^[0-9]+(?:\.[0-9]+)?$/.test(token.lower)) {
|
|
2224
2447
|
const value = parseFloat(token.original);
|
|
2448
|
+
const resolvedDose = resolveNumericDoseUnit(tokens, i, value, internal.consumed, options);
|
|
2225
2449
|
if (internal.dose === undefined) {
|
|
2226
|
-
internal.dose =
|
|
2450
|
+
internal.dose = resolvedDose.doseValue;
|
|
2227
2451
|
}
|
|
2228
2452
|
mark(internal.consumed, token);
|
|
2229
|
-
|
|
2230
|
-
|
|
2231
|
-
|
|
2232
|
-
|
|
2233
|
-
|
|
2234
|
-
mark(internal.consumed, unitToken);
|
|
2235
|
-
}
|
|
2453
|
+
if (resolvedDose.unit) {
|
|
2454
|
+
internal.unit = resolvedDose.unit;
|
|
2455
|
+
}
|
|
2456
|
+
for (const consumedIndex of resolvedDose.consumedIndices) {
|
|
2457
|
+
mark(internal.consumed, tokens[consumedIndex]);
|
|
2236
2458
|
}
|
|
2237
2459
|
continue;
|
|
2238
2460
|
}
|