ezmedicationinput 0.1.1 → 0.1.2
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 +19 -19
- package/dist/context.js +10 -5
- package/dist/fhir.d.ts +1 -1
- package/dist/fhir.js +40 -32
- package/dist/format.d.ts +3 -2
- package/dist/format.js +371 -86
- package/dist/i18n.d.ts +31 -0
- package/dist/i18n.js +664 -0
- package/dist/index.d.ts +5 -3
- package/dist/index.js +53 -19
- package/dist/internal-types.d.ts +33 -0
- package/dist/internal-types.js +2 -0
- package/dist/maps.d.ts +1 -0
- package/dist/maps.js +410 -341
- package/dist/package.json +3 -0
- package/dist/parser.d.ts +2 -31
- package/dist/parser.js +689 -142
- package/dist/safety.js +7 -4
- package/dist/schedule.js +148 -76
- package/dist/suggest.js +11 -6
- package/dist/types.d.ts +16 -8
- package/dist/types.js +12 -9
- package/dist/utils/array.d.ts +1 -0
- package/dist/utils/array.js +11 -0
- package/dist/utils/enum.d.ts +2 -0
- package/dist/utils/enum.js +7 -0
- package/dist/utils/object.d.ts +7 -0
- package/dist/utils/object.js +34 -0
- package/package.json +2 -2
package/dist/parser.js
CHANGED
|
@@ -1,7 +1,13 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.tokenize = tokenize;
|
|
4
|
+
exports.parseInternal = parseInternal;
|
|
5
|
+
const maps_1 = require("./maps");
|
|
6
|
+
const context_1 = require("./context");
|
|
7
|
+
const safety_1 = require("./safety");
|
|
8
|
+
const types_1 = require("./types");
|
|
9
|
+
const object_1 = require("./utils/object");
|
|
10
|
+
const array_1 = require("./utils/array");
|
|
5
11
|
const BODY_SITE_HINTS = new Set([
|
|
6
12
|
"left",
|
|
7
13
|
"right",
|
|
@@ -31,75 +37,491 @@ const BODY_SITE_HINTS = new Set([
|
|
|
31
37
|
"upper",
|
|
32
38
|
"lower",
|
|
33
39
|
"forearm",
|
|
34
|
-
"back"
|
|
40
|
+
"back",
|
|
41
|
+
"mouth",
|
|
42
|
+
"tongue",
|
|
43
|
+
"tongues",
|
|
44
|
+
"cheek",
|
|
45
|
+
"cheeks",
|
|
46
|
+
"gum",
|
|
47
|
+
"gums",
|
|
48
|
+
"tooth",
|
|
49
|
+
"teeth",
|
|
50
|
+
"nose",
|
|
51
|
+
"nares",
|
|
52
|
+
"hair",
|
|
53
|
+
"skin",
|
|
54
|
+
"scalp",
|
|
55
|
+
"face",
|
|
56
|
+
"forehead",
|
|
57
|
+
"chin",
|
|
58
|
+
"neck",
|
|
59
|
+
"buttock",
|
|
60
|
+
"buttocks",
|
|
61
|
+
"gluteal",
|
|
62
|
+
"glute",
|
|
63
|
+
"muscle",
|
|
64
|
+
"muscles",
|
|
65
|
+
"vein",
|
|
66
|
+
"veins",
|
|
67
|
+
"vagina",
|
|
68
|
+
"vaginal",
|
|
69
|
+
"rectum",
|
|
70
|
+
"rectal",
|
|
71
|
+
"anus",
|
|
72
|
+
"perineum"
|
|
73
|
+
]);
|
|
74
|
+
const SITE_CONNECTORS = new Set(["to", "in", "into", "on", "onto", "at"]);
|
|
75
|
+
const SITE_FILLER_WORDS = new Set([
|
|
76
|
+
"the",
|
|
77
|
+
"a",
|
|
78
|
+
"an",
|
|
79
|
+
"your",
|
|
80
|
+
"his",
|
|
81
|
+
"her",
|
|
82
|
+
"their",
|
|
83
|
+
"my"
|
|
84
|
+
]);
|
|
85
|
+
const OCULAR_DIRECTION_WORDS = new Set([
|
|
86
|
+
"left",
|
|
87
|
+
"right",
|
|
88
|
+
"both",
|
|
89
|
+
"either",
|
|
90
|
+
"each",
|
|
91
|
+
"bilateral"
|
|
92
|
+
]);
|
|
93
|
+
const OCULAR_SITE_WORDS = new Set([
|
|
94
|
+
"eye",
|
|
95
|
+
"eyes",
|
|
96
|
+
"eyelid",
|
|
97
|
+
"eyelids",
|
|
98
|
+
"ocular",
|
|
99
|
+
"ophthalmic",
|
|
100
|
+
"oculus"
|
|
35
101
|
]);
|
|
36
102
|
const COMBO_EVENT_TIMINGS = {
|
|
37
|
-
"early morning": EventTiming["Early Morning"],
|
|
38
|
-
"late morning": EventTiming["Late Morning"],
|
|
39
|
-
"early afternoon": EventTiming["Early Afternoon"],
|
|
40
|
-
"late afternoon": EventTiming["Late Afternoon"],
|
|
41
|
-
"early evening": EventTiming["Early Evening"],
|
|
42
|
-
"late evening": EventTiming["Late Evening"],
|
|
43
|
-
"after sleep": EventTiming["After Sleep"],
|
|
44
|
-
"upon waking": EventTiming.Wake
|
|
103
|
+
"early morning": types_1.EventTiming["Early Morning"],
|
|
104
|
+
"late morning": types_1.EventTiming["Late Morning"],
|
|
105
|
+
"early afternoon": types_1.EventTiming["Early Afternoon"],
|
|
106
|
+
"late afternoon": types_1.EventTiming["Late Afternoon"],
|
|
107
|
+
"early evening": types_1.EventTiming["Early Evening"],
|
|
108
|
+
"late evening": types_1.EventTiming["Late Evening"],
|
|
109
|
+
"after sleep": types_1.EventTiming["After Sleep"],
|
|
110
|
+
"upon waking": types_1.EventTiming.Wake
|
|
45
111
|
};
|
|
46
112
|
// Tracking explicit breakfast/lunch/dinner markers lets the meal-expansion
|
|
47
113
|
// logic bail early when the clinician already specified precise events.
|
|
48
114
|
const SPECIFIC_MEAL_TIMINGS = new Set([
|
|
49
|
-
EventTiming["Before Breakfast"],
|
|
50
|
-
EventTiming["Before Lunch"],
|
|
51
|
-
EventTiming["Before Dinner"],
|
|
52
|
-
EventTiming["After Breakfast"],
|
|
53
|
-
EventTiming["After Lunch"],
|
|
54
|
-
EventTiming["After Dinner"],
|
|
55
|
-
EventTiming.Breakfast,
|
|
56
|
-
EventTiming.Lunch,
|
|
57
|
-
EventTiming.Dinner
|
|
115
|
+
types_1.EventTiming["Before Breakfast"],
|
|
116
|
+
types_1.EventTiming["Before Lunch"],
|
|
117
|
+
types_1.EventTiming["Before Dinner"],
|
|
118
|
+
types_1.EventTiming["After Breakfast"],
|
|
119
|
+
types_1.EventTiming["After Lunch"],
|
|
120
|
+
types_1.EventTiming["After Dinner"],
|
|
121
|
+
types_1.EventTiming.Breakfast,
|
|
122
|
+
types_1.EventTiming.Lunch,
|
|
123
|
+
types_1.EventTiming.Dinner
|
|
58
124
|
]);
|
|
59
125
|
// Ocular shorthand tokens commonly used in ophthalmic sigs.
|
|
60
126
|
const EYE_SITE_TOKENS = {
|
|
61
|
-
od: { site: "right eye", route: RouteCode["Ophthalmic route"] },
|
|
62
|
-
re: { site: "right eye", route: RouteCode["Ophthalmic route"] },
|
|
63
|
-
os: { site: "left eye", route: RouteCode["Ophthalmic route"] },
|
|
64
|
-
le: { site: "left eye", route: RouteCode["Ophthalmic route"] },
|
|
65
|
-
ou: { site: "both eyes", route: RouteCode["Ophthalmic route"] },
|
|
66
|
-
be: { site: "both eyes", route: RouteCode["Ophthalmic route"] },
|
|
127
|
+
od: { site: "right eye", route: types_1.RouteCode["Ophthalmic route"] },
|
|
128
|
+
re: { site: "right eye", route: types_1.RouteCode["Ophthalmic route"] },
|
|
129
|
+
os: { site: "left eye", route: types_1.RouteCode["Ophthalmic route"] },
|
|
130
|
+
le: { site: "left eye", route: types_1.RouteCode["Ophthalmic route"] },
|
|
131
|
+
ou: { site: "both eyes", route: types_1.RouteCode["Ophthalmic route"] },
|
|
132
|
+
be: { site: "both eyes", route: types_1.RouteCode["Ophthalmic route"] },
|
|
67
133
|
vod: {
|
|
68
134
|
site: "right eye",
|
|
69
|
-
route: RouteCode["Intravitreal route (qualifier value)"]
|
|
135
|
+
route: types_1.RouteCode["Intravitreal route (qualifier value)"]
|
|
70
136
|
},
|
|
71
137
|
vos: {
|
|
72
138
|
site: "left eye",
|
|
73
|
-
route: RouteCode["Intravitreal route (qualifier value)"]
|
|
139
|
+
route: types_1.RouteCode["Intravitreal route (qualifier value)"]
|
|
74
140
|
},
|
|
75
141
|
ivtod: {
|
|
76
142
|
site: "right eye",
|
|
77
|
-
route: RouteCode["Intravitreal route (qualifier value)"]
|
|
143
|
+
route: types_1.RouteCode["Intravitreal route (qualifier value)"]
|
|
78
144
|
},
|
|
79
145
|
ivtre: {
|
|
80
146
|
site: "right eye",
|
|
81
|
-
route: RouteCode["Intravitreal route (qualifier value)"]
|
|
147
|
+
route: types_1.RouteCode["Intravitreal route (qualifier value)"]
|
|
82
148
|
},
|
|
83
149
|
ivtos: {
|
|
84
150
|
site: "left eye",
|
|
85
|
-
route: RouteCode["Intravitreal route (qualifier value)"]
|
|
151
|
+
route: types_1.RouteCode["Intravitreal route (qualifier value)"]
|
|
86
152
|
},
|
|
87
153
|
ivtle: {
|
|
88
154
|
site: "left eye",
|
|
89
|
-
route: RouteCode["Intravitreal route (qualifier value)"]
|
|
155
|
+
route: types_1.RouteCode["Intravitreal route (qualifier value)"]
|
|
90
156
|
},
|
|
91
157
|
ivtou: {
|
|
92
158
|
site: "both eyes",
|
|
93
|
-
route: RouteCode["Intravitreal route (qualifier value)"]
|
|
159
|
+
route: types_1.RouteCode["Intravitreal route (qualifier value)"]
|
|
94
160
|
},
|
|
95
161
|
ivtbe: {
|
|
96
162
|
site: "both eyes",
|
|
97
|
-
route: RouteCode["Intravitreal route (qualifier value)"]
|
|
163
|
+
route: types_1.RouteCode["Intravitreal route (qualifier value)"]
|
|
98
164
|
}
|
|
99
165
|
};
|
|
100
|
-
|
|
166
|
+
const OPHTHALMIC_ROUTE_CODES = new Set([
|
|
167
|
+
types_1.RouteCode["Ophthalmic route"],
|
|
168
|
+
types_1.RouteCode["Intravitreal route (qualifier value)"]
|
|
169
|
+
]);
|
|
170
|
+
const OPHTHALMIC_CONTEXT_TOKENS = new Set([
|
|
171
|
+
"drop",
|
|
172
|
+
"drops",
|
|
173
|
+
"gtt",
|
|
174
|
+
"gtts",
|
|
175
|
+
"eye",
|
|
176
|
+
"eyes",
|
|
177
|
+
"eyelid",
|
|
178
|
+
"eyelids",
|
|
179
|
+
"ocular",
|
|
180
|
+
"ophthalmic",
|
|
181
|
+
"ophth",
|
|
182
|
+
"oculus",
|
|
183
|
+
"os",
|
|
184
|
+
"ou",
|
|
185
|
+
"re",
|
|
186
|
+
"le",
|
|
187
|
+
"be"
|
|
188
|
+
]);
|
|
189
|
+
function normalizeTokenLower(token) {
|
|
190
|
+
return token.lower.replace(/\./g, "");
|
|
191
|
+
}
|
|
192
|
+
function hasOphthalmicContextHint(tokens, index) {
|
|
193
|
+
for (let offset = -3; offset <= 3; offset++) {
|
|
194
|
+
if (offset === 0) {
|
|
195
|
+
continue;
|
|
196
|
+
}
|
|
197
|
+
const neighbor = tokens[index + offset];
|
|
198
|
+
if (!neighbor) {
|
|
199
|
+
continue;
|
|
200
|
+
}
|
|
201
|
+
const normalized = normalizeTokenLower(neighbor);
|
|
202
|
+
if (OPHTHALMIC_CONTEXT_TOKENS.has(normalized) || normalized.includes("eye")) {
|
|
203
|
+
return true;
|
|
204
|
+
}
|
|
205
|
+
}
|
|
206
|
+
return false;
|
|
207
|
+
}
|
|
208
|
+
function shouldInterpretOdAsOnceDaily(internal, tokens, index, treatAsSite) {
|
|
209
|
+
var _a;
|
|
210
|
+
if (treatAsSite) {
|
|
211
|
+
return false;
|
|
212
|
+
}
|
|
213
|
+
const hasCadenceAssigned = internal.frequency !== undefined ||
|
|
214
|
+
internal.frequencyMax !== undefined ||
|
|
215
|
+
internal.period !== undefined ||
|
|
216
|
+
internal.periodMax !== undefined ||
|
|
217
|
+
internal.timingCode !== undefined;
|
|
218
|
+
const hasPriorSiteContext = hasBodySiteContextBefore(internal, tokens, index);
|
|
219
|
+
const hasUpcomingSiteContext = hasBodySiteContextAfter(internal, tokens, index);
|
|
220
|
+
const previous = tokens[index - 1];
|
|
221
|
+
const previousNormalized = previous ? normalizeTokenLower(previous) : undefined;
|
|
222
|
+
const previousIsOd = previousNormalized === "od";
|
|
223
|
+
const previousConsumed = previousIsOd && internal.consumed.has(previous.index);
|
|
224
|
+
const previousOdProvidedSite = previousConsumed && /eye/i.test((_a = internal.siteText) !== null && _a !== void 0 ? _a : "");
|
|
225
|
+
if (previousOdProvidedSite) {
|
|
226
|
+
return true;
|
|
227
|
+
}
|
|
228
|
+
const previousEyeToken = previousNormalized && previousNormalized !== "od"
|
|
229
|
+
? EYE_SITE_TOKENS[previousNormalized]
|
|
230
|
+
: undefined;
|
|
231
|
+
if (previousEyeToken && internal.consumed.has(previous.index)) {
|
|
232
|
+
return true;
|
|
233
|
+
}
|
|
234
|
+
if (previousNormalized === "od" &&
|
|
235
|
+
internal.siteSource === "abbreviation" &&
|
|
236
|
+
internal.siteText &&
|
|
237
|
+
/eye/i.test(internal.siteText)) {
|
|
238
|
+
return true;
|
|
239
|
+
}
|
|
240
|
+
if (hasPriorSiteContext || hasUpcomingSiteContext) {
|
|
241
|
+
return !hasCadenceAssigned;
|
|
242
|
+
}
|
|
243
|
+
if (hasCadenceAssigned) {
|
|
244
|
+
return false;
|
|
245
|
+
}
|
|
246
|
+
if (internal.routeCode && !OPHTHALMIC_ROUTE_CODES.has(internal.routeCode)) {
|
|
247
|
+
return true;
|
|
248
|
+
}
|
|
249
|
+
if (internal.unit && internal.unit !== "drop") {
|
|
250
|
+
return true;
|
|
251
|
+
}
|
|
252
|
+
if (internal.siteText && !/eye/i.test(internal.siteText)) {
|
|
253
|
+
return true;
|
|
254
|
+
}
|
|
255
|
+
const hasNonOdToken = tokens.some((token, tokenIndex) => {
|
|
256
|
+
if (tokenIndex === index) {
|
|
257
|
+
return false;
|
|
258
|
+
}
|
|
259
|
+
return normalizeTokenLower(token) !== "od";
|
|
260
|
+
});
|
|
261
|
+
if (!hasNonOdToken) {
|
|
262
|
+
return false;
|
|
263
|
+
}
|
|
264
|
+
const ophthalmicContext = hasOphthalmicContextHint(tokens, index) ||
|
|
265
|
+
(internal.routeCode !== undefined && OPHTHALMIC_ROUTE_CODES.has(internal.routeCode)) ||
|
|
266
|
+
(internal.siteText !== undefined && /eye/i.test(internal.siteText));
|
|
267
|
+
if (ophthalmicContext && hasSpelledOcularSiteBefore(tokens, index)) {
|
|
268
|
+
return true;
|
|
269
|
+
}
|
|
270
|
+
return !ophthalmicContext;
|
|
271
|
+
}
|
|
272
|
+
function hasBodySiteContextBefore(internal, tokens, index) {
|
|
273
|
+
const currentToken = tokens[index];
|
|
274
|
+
const currentTokenIndex = currentToken ? currentToken.index : index;
|
|
275
|
+
if (internal.siteText) {
|
|
276
|
+
return true;
|
|
277
|
+
}
|
|
278
|
+
for (const tokenIndex of internal.siteTokenIndices) {
|
|
279
|
+
if (tokenIndex < currentTokenIndex) {
|
|
280
|
+
return true;
|
|
281
|
+
}
|
|
282
|
+
}
|
|
283
|
+
for (let i = 0; i < index; i++) {
|
|
284
|
+
const token = tokens[i];
|
|
285
|
+
if (!token) {
|
|
286
|
+
continue;
|
|
287
|
+
}
|
|
288
|
+
if (internal.consumed.has(token.index)) {
|
|
289
|
+
if (internal.siteTokenIndices.has(token.index) && token.index < currentTokenIndex) {
|
|
290
|
+
return true;
|
|
291
|
+
}
|
|
292
|
+
continue;
|
|
293
|
+
}
|
|
294
|
+
const normalized = normalizeTokenLower(token);
|
|
295
|
+
if (BODY_SITE_HINTS.has(normalized)) {
|
|
296
|
+
return true;
|
|
297
|
+
}
|
|
298
|
+
if (EYE_SITE_TOKENS[normalized]) {
|
|
299
|
+
return true;
|
|
300
|
+
}
|
|
301
|
+
}
|
|
302
|
+
return false;
|
|
303
|
+
}
|
|
304
|
+
function hasBodySiteContextAfter(internal, tokens, index) {
|
|
305
|
+
const currentToken = tokens[index];
|
|
306
|
+
const currentTokenIndex = currentToken ? currentToken.index : index;
|
|
307
|
+
for (const tokenIndex of internal.siteTokenIndices) {
|
|
308
|
+
if (tokenIndex > currentTokenIndex) {
|
|
309
|
+
return true;
|
|
310
|
+
}
|
|
311
|
+
}
|
|
312
|
+
let seenConnector = false;
|
|
313
|
+
for (let i = index + 1; i < tokens.length; i++) {
|
|
314
|
+
const token = tokens[i];
|
|
315
|
+
if (!token) {
|
|
316
|
+
continue;
|
|
317
|
+
}
|
|
318
|
+
if (internal.consumed.has(token.index)) {
|
|
319
|
+
if (internal.siteTokenIndices.has(token.index) && token.index > currentTokenIndex) {
|
|
320
|
+
return true;
|
|
321
|
+
}
|
|
322
|
+
continue;
|
|
323
|
+
}
|
|
324
|
+
const normalized = normalizeTokenLower(token);
|
|
325
|
+
if (SITE_CONNECTORS.has(normalized)) {
|
|
326
|
+
seenConnector = true;
|
|
327
|
+
continue;
|
|
328
|
+
}
|
|
329
|
+
if (SITE_FILLER_WORDS.has(normalized)) {
|
|
330
|
+
continue;
|
|
331
|
+
}
|
|
332
|
+
if (BODY_SITE_HINTS.has(normalized)) {
|
|
333
|
+
return true;
|
|
334
|
+
}
|
|
335
|
+
if (seenConnector) {
|
|
336
|
+
break;
|
|
337
|
+
}
|
|
338
|
+
if (!seenConnector) {
|
|
339
|
+
break;
|
|
340
|
+
}
|
|
341
|
+
}
|
|
342
|
+
return false;
|
|
343
|
+
}
|
|
344
|
+
function hasSpelledOcularSiteBefore(tokens, index) {
|
|
345
|
+
let hasOcularWord = false;
|
|
346
|
+
let hasDirectionalCue = false;
|
|
347
|
+
for (let i = 0; i < index; i++) {
|
|
348
|
+
const token = tokens[i];
|
|
349
|
+
if (!token) {
|
|
350
|
+
continue;
|
|
351
|
+
}
|
|
352
|
+
const normalized = normalizeTokenLower(token);
|
|
353
|
+
if (SITE_CONNECTORS.has(normalized) || OCULAR_DIRECTION_WORDS.has(normalized)) {
|
|
354
|
+
hasDirectionalCue = true;
|
|
355
|
+
}
|
|
356
|
+
if (OCULAR_SITE_WORDS.has(normalized) || normalized.includes("eye")) {
|
|
357
|
+
hasOcularWord = true;
|
|
358
|
+
}
|
|
359
|
+
if (hasDirectionalCue && hasOcularWord) {
|
|
360
|
+
return true;
|
|
361
|
+
}
|
|
362
|
+
}
|
|
363
|
+
return false;
|
|
364
|
+
}
|
|
365
|
+
function shouldTreatEyeTokenAsSite(internal, tokens, index, context) {
|
|
366
|
+
var _a;
|
|
367
|
+
const currentToken = tokens[index];
|
|
368
|
+
const normalizedSelf = normalizeTokenLower(currentToken);
|
|
369
|
+
const eyeMeta = EYE_SITE_TOKENS[normalizedSelf];
|
|
370
|
+
if (internal.routeCode && !OPHTHALMIC_ROUTE_CODES.has(internal.routeCode)) {
|
|
371
|
+
return false;
|
|
372
|
+
}
|
|
373
|
+
if (internal.siteText) {
|
|
374
|
+
return false;
|
|
375
|
+
}
|
|
376
|
+
if (internal.siteSource === "abbreviation") {
|
|
377
|
+
return false;
|
|
378
|
+
}
|
|
379
|
+
const dosageForm = (_a = context === null || context === void 0 ? void 0 : context.dosageForm) === null || _a === void 0 ? void 0 : _a.toLowerCase();
|
|
380
|
+
const contextImpliesOphthalmic = Boolean(dosageForm && /(eye|ophth|ocular|intravit)/i.test(dosageForm));
|
|
381
|
+
const eyeRouteImpliesOphthalmic = (eyeMeta === null || eyeMeta === void 0 ? void 0 : eyeMeta.route) === types_1.RouteCode["Intravitreal route (qualifier value)"];
|
|
382
|
+
const ophthalmicContext = hasOphthalmicContextHint(tokens, index) ||
|
|
383
|
+
(internal.routeCode !== undefined && OPHTHALMIC_ROUTE_CODES.has(internal.routeCode)) ||
|
|
384
|
+
contextImpliesOphthalmic ||
|
|
385
|
+
eyeRouteImpliesOphthalmic;
|
|
386
|
+
if (hasBodySiteContextAfter(internal, tokens, index)) {
|
|
387
|
+
return false;
|
|
388
|
+
}
|
|
389
|
+
if (!ophthalmicContext) {
|
|
390
|
+
const hasOtherActiveTokens = tokens.some((token, tokenIndex) => tokenIndex !== index && !internal.consumed.has(token.index));
|
|
391
|
+
const onlyEyeTokens = tokens.every((token, tokenIndex) => {
|
|
392
|
+
if (tokenIndex === index || internal.consumed.has(token.index)) {
|
|
393
|
+
return true;
|
|
394
|
+
}
|
|
395
|
+
return normalizeTokenLower(token) === "od";
|
|
396
|
+
});
|
|
397
|
+
if (!hasOtherActiveTokens) {
|
|
398
|
+
return internal.unit === undefined && internal.routeCode === undefined;
|
|
399
|
+
}
|
|
400
|
+
if (onlyEyeTokens) {
|
|
401
|
+
return true;
|
|
402
|
+
}
|
|
403
|
+
return false;
|
|
404
|
+
}
|
|
405
|
+
for (let i = 0; i < index; i++) {
|
|
406
|
+
const candidate = tokens[i];
|
|
407
|
+
if (internal.consumed.has(candidate.index)) {
|
|
408
|
+
continue;
|
|
409
|
+
}
|
|
410
|
+
const normalized = normalizeTokenLower(candidate);
|
|
411
|
+
if (SITE_CONNECTORS.has(normalized)) {
|
|
412
|
+
continue;
|
|
413
|
+
}
|
|
414
|
+
if (BODY_SITE_HINTS.has(normalized)) {
|
|
415
|
+
return false;
|
|
416
|
+
}
|
|
417
|
+
if (EYE_SITE_TOKENS[normalized]) {
|
|
418
|
+
return false;
|
|
419
|
+
}
|
|
420
|
+
if (maps_1.DEFAULT_ROUTE_SYNONYMS[normalized]) {
|
|
421
|
+
return false;
|
|
422
|
+
}
|
|
423
|
+
}
|
|
424
|
+
return true;
|
|
425
|
+
}
|
|
426
|
+
function tryParseNumericCadence(internal, tokens, index) {
|
|
427
|
+
const token = tokens[index];
|
|
428
|
+
if (!/^[0-9]+(?:\.[0-9]+)?$/.test(token.lower)) {
|
|
429
|
+
return false;
|
|
430
|
+
}
|
|
431
|
+
if (internal.frequency !== undefined ||
|
|
432
|
+
internal.frequencyMax !== undefined ||
|
|
433
|
+
internal.period !== undefined ||
|
|
434
|
+
internal.periodMax !== undefined) {
|
|
435
|
+
return false;
|
|
436
|
+
}
|
|
437
|
+
let nextIndex = index + 1;
|
|
438
|
+
const connectors = [];
|
|
439
|
+
while (true) {
|
|
440
|
+
const connector = tokens[nextIndex];
|
|
441
|
+
if (!connector || internal.consumed.has(connector.index)) {
|
|
442
|
+
break;
|
|
443
|
+
}
|
|
444
|
+
const normalized = normalizeTokenLower(connector);
|
|
445
|
+
if (normalized === "per" || normalized === "a" || normalized === "each" || normalized === "every") {
|
|
446
|
+
connectors.push(connector);
|
|
447
|
+
nextIndex += 1;
|
|
448
|
+
continue;
|
|
449
|
+
}
|
|
450
|
+
break;
|
|
451
|
+
}
|
|
452
|
+
if (!connectors.length) {
|
|
453
|
+
return false;
|
|
454
|
+
}
|
|
455
|
+
const unitToken = tokens[nextIndex];
|
|
456
|
+
if (!unitToken || internal.consumed.has(unitToken.index)) {
|
|
457
|
+
return false;
|
|
458
|
+
}
|
|
459
|
+
const unitCode = mapIntervalUnit(normalizeTokenLower(unitToken));
|
|
460
|
+
if (!unitCode) {
|
|
461
|
+
return false;
|
|
462
|
+
}
|
|
463
|
+
const value = parseFloat(token.original);
|
|
464
|
+
if (!Number.isFinite(value)) {
|
|
465
|
+
return false;
|
|
466
|
+
}
|
|
467
|
+
internal.frequency = value;
|
|
468
|
+
internal.period = 1;
|
|
469
|
+
internal.periodUnit = unitCode;
|
|
470
|
+
if (value === 1 && unitCode === types_1.FhirPeriodUnit.Day && !internal.timingCode) {
|
|
471
|
+
internal.timingCode = "QD";
|
|
472
|
+
}
|
|
473
|
+
mark(internal.consumed, token);
|
|
474
|
+
for (const connector of connectors) {
|
|
475
|
+
mark(internal.consumed, connector);
|
|
476
|
+
}
|
|
477
|
+
mark(internal.consumed, unitToken);
|
|
478
|
+
return true;
|
|
479
|
+
}
|
|
480
|
+
const SITE_UNIT_ROUTE_HINTS = [
|
|
481
|
+
{ pattern: /\beye(s)?\b/i, route: types_1.RouteCode["Ophthalmic route"] },
|
|
482
|
+
{ pattern: /\beyelid(s)?\b/i, route: types_1.RouteCode["Ophthalmic route"] },
|
|
483
|
+
{ pattern: /\bintravitreal\b/i, route: types_1.RouteCode["Intravitreal route (qualifier value)"] },
|
|
484
|
+
{ pattern: /\bear(s)?\b/i, route: types_1.RouteCode["Otic route"] },
|
|
485
|
+
{ pattern: /\bnostril(s)?\b/i, route: types_1.RouteCode["Nasal route"] },
|
|
486
|
+
{ pattern: /\bnares?\b/i, route: types_1.RouteCode["Nasal route"] },
|
|
487
|
+
{ pattern: /\bnose\b/i, route: types_1.RouteCode["Nasal route"] },
|
|
488
|
+
{ pattern: /\bmouth\b/i, route: types_1.RouteCode["Oral route"] },
|
|
489
|
+
{ pattern: /\boral\b/i, route: types_1.RouteCode["Oral route"] },
|
|
490
|
+
{ pattern: /\bunder (the )?tongue\b/i, route: types_1.RouteCode["Sublingual route"] },
|
|
491
|
+
{ pattern: /\btongue\b/i, route: types_1.RouteCode["Sublingual route"] },
|
|
492
|
+
{ pattern: /\bcheek(s)?\b/i, route: types_1.RouteCode["Buccal route"] },
|
|
493
|
+
{ pattern: /\blung(s)?\b/i, route: types_1.RouteCode["Respiratory tract route (qualifier value)"] },
|
|
494
|
+
{ pattern: /\brespiratory tract\b/i, route: types_1.RouteCode["Respiratory tract route (qualifier value)"] },
|
|
495
|
+
{ pattern: /\bskin\b/i, route: types_1.RouteCode["Topical route"] },
|
|
496
|
+
{ pattern: /\bscalp\b/i, route: types_1.RouteCode["Topical route"] },
|
|
497
|
+
{ pattern: /\bface\b/i, route: types_1.RouteCode["Topical route"] },
|
|
498
|
+
{ pattern: /\bhand(s)?\b/i, route: types_1.RouteCode["Topical route"] },
|
|
499
|
+
{ pattern: /(\bfoot\b|\bfeet\b)/i, route: types_1.RouteCode["Topical route"] },
|
|
500
|
+
{ pattern: /\belbow(s)?\b/i, route: types_1.RouteCode["Topical route"] },
|
|
501
|
+
{ pattern: /\bknee(s)?\b/i, route: types_1.RouteCode["Topical route"] },
|
|
502
|
+
{ pattern: /\bleg(s)?\b/i, route: types_1.RouteCode["Topical route"] },
|
|
503
|
+
{ pattern: /\barm(s)?\b/i, route: types_1.RouteCode["Topical route"] },
|
|
504
|
+
{ pattern: /\bpatch(es)?\b/i, route: types_1.RouteCode["Transdermal route"] },
|
|
505
|
+
{ pattern: /\babdomen\b/i, route: types_1.RouteCode["Subcutaneous route"] },
|
|
506
|
+
{ pattern: /\bbelly\b/i, route: types_1.RouteCode["Subcutaneous route"] },
|
|
507
|
+
{ pattern: /\bstomach\b/i, route: types_1.RouteCode["Subcutaneous route"] },
|
|
508
|
+
{ pattern: /\bthigh(s)?\b/i, route: types_1.RouteCode["Subcutaneous route"] },
|
|
509
|
+
{ pattern: /\bupper arm\b/i, route: types_1.RouteCode["Subcutaneous route"] },
|
|
510
|
+
{ pattern: /\bbuttock(s)?\b/i, route: types_1.RouteCode["Intramuscular route"] },
|
|
511
|
+
{ pattern: /\bglute(al)?\b/i, route: types_1.RouteCode["Intramuscular route"] },
|
|
512
|
+
{ pattern: /\bdeltoid\b/i, route: types_1.RouteCode["Intramuscular route"] },
|
|
513
|
+
{ pattern: /\bmuscle(s)?\b/i, route: types_1.RouteCode["Intramuscular route"] },
|
|
514
|
+
{ pattern: /\bvein(s)?\b/i, route: types_1.RouteCode["Intravenous route"] },
|
|
515
|
+
{ pattern: /\brectum\b/i, route: types_1.RouteCode["Per rectum"] },
|
|
516
|
+
{ pattern: /\banus\b/i, route: types_1.RouteCode["Per rectum"] },
|
|
517
|
+
{ pattern: /\brectal\b/i, route: types_1.RouteCode["Per rectum"] },
|
|
518
|
+
{ pattern: /\bvagina\b/i, route: types_1.RouteCode["Per vagina"] },
|
|
519
|
+
{ pattern: /\bvaginal\b/i, route: types_1.RouteCode["Per vagina"] }
|
|
520
|
+
];
|
|
521
|
+
function tokenize(input) {
|
|
101
522
|
const separators = /[(),]/g;
|
|
102
523
|
let normalized = input.trim().replace(separators, " ");
|
|
524
|
+
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}`);
|
|
103
525
|
normalized = normalized.replace(/(\d+)\s*\/\s*(\d+)/g, (match, num, den) => {
|
|
104
526
|
const numerator = parseFloat(num);
|
|
105
527
|
const denominator = parseFloat(den);
|
|
@@ -154,7 +576,7 @@ function mark(consumed, token) {
|
|
|
154
576
|
consumed.add(token.index);
|
|
155
577
|
}
|
|
156
578
|
function addWhen(target, code) {
|
|
157
|
-
if (!
|
|
579
|
+
if (!(0, array_1.arrayIncludes)(target, code)) {
|
|
158
580
|
target.push(code);
|
|
159
581
|
}
|
|
160
582
|
}
|
|
@@ -173,68 +595,69 @@ function computeMealExpansions(base, frequency, pairPreference) {
|
|
|
173
595
|
if (frequency < 1 || frequency > 4) {
|
|
174
596
|
return undefined;
|
|
175
597
|
}
|
|
176
|
-
const bedtime = EventTiming["Before Sleep"];
|
|
598
|
+
const bedtime = types_1.EventTiming["Before Sleep"];
|
|
177
599
|
const beforePair = pairPreference === "breakfast+lunch"
|
|
178
|
-
? [EventTiming["Before Breakfast"], EventTiming["Before Lunch"]]
|
|
179
|
-
: [EventTiming["Before Breakfast"], EventTiming["Before Dinner"]];
|
|
600
|
+
? [types_1.EventTiming["Before Breakfast"], types_1.EventTiming["Before Lunch"]]
|
|
601
|
+
: [types_1.EventTiming["Before Breakfast"], types_1.EventTiming["Before Dinner"]];
|
|
180
602
|
const afterPair = pairPreference === "breakfast+lunch"
|
|
181
|
-
? [EventTiming["After Breakfast"], EventTiming["After Lunch"]]
|
|
182
|
-
: [EventTiming["After Breakfast"], EventTiming["After Dinner"]];
|
|
603
|
+
? [types_1.EventTiming["After Breakfast"], types_1.EventTiming["After Lunch"]]
|
|
604
|
+
: [types_1.EventTiming["After Breakfast"], types_1.EventTiming["After Dinner"]];
|
|
183
605
|
const withPair = pairPreference === "breakfast+lunch"
|
|
184
|
-
? [EventTiming.Breakfast, EventTiming.Lunch]
|
|
185
|
-
: [EventTiming.Breakfast, EventTiming.Dinner];
|
|
606
|
+
? [types_1.EventTiming.Breakfast, types_1.EventTiming.Lunch]
|
|
607
|
+
: [types_1.EventTiming.Breakfast, types_1.EventTiming.Dinner];
|
|
186
608
|
if (base === "before") {
|
|
187
609
|
if (frequency === 1)
|
|
188
|
-
return [EventTiming["Before Breakfast"]];
|
|
610
|
+
return [types_1.EventTiming["Before Breakfast"]];
|
|
189
611
|
if (frequency === 2)
|
|
190
612
|
return beforePair;
|
|
191
613
|
if (frequency === 3) {
|
|
192
614
|
return [
|
|
193
|
-
EventTiming["Before Breakfast"],
|
|
194
|
-
EventTiming["Before Lunch"],
|
|
195
|
-
EventTiming["Before Dinner"]
|
|
615
|
+
types_1.EventTiming["Before Breakfast"],
|
|
616
|
+
types_1.EventTiming["Before Lunch"],
|
|
617
|
+
types_1.EventTiming["Before Dinner"]
|
|
196
618
|
];
|
|
197
619
|
}
|
|
198
620
|
return [
|
|
199
|
-
EventTiming["Before Breakfast"],
|
|
200
|
-
EventTiming["Before Lunch"],
|
|
201
|
-
EventTiming["Before Dinner"],
|
|
621
|
+
types_1.EventTiming["Before Breakfast"],
|
|
622
|
+
types_1.EventTiming["Before Lunch"],
|
|
623
|
+
types_1.EventTiming["Before Dinner"],
|
|
202
624
|
bedtime
|
|
203
625
|
];
|
|
204
626
|
}
|
|
205
627
|
if (base === "after") {
|
|
206
628
|
if (frequency === 1)
|
|
207
|
-
return [EventTiming["After Breakfast"]];
|
|
629
|
+
return [types_1.EventTiming["After Breakfast"]];
|
|
208
630
|
if (frequency === 2)
|
|
209
631
|
return afterPair;
|
|
210
632
|
if (frequency === 3) {
|
|
211
633
|
return [
|
|
212
|
-
EventTiming["After Breakfast"],
|
|
213
|
-
EventTiming["After Lunch"],
|
|
214
|
-
EventTiming["After Dinner"]
|
|
634
|
+
types_1.EventTiming["After Breakfast"],
|
|
635
|
+
types_1.EventTiming["After Lunch"],
|
|
636
|
+
types_1.EventTiming["After Dinner"]
|
|
215
637
|
];
|
|
216
638
|
}
|
|
217
639
|
return [
|
|
218
|
-
EventTiming["After Breakfast"],
|
|
219
|
-
EventTiming["After Lunch"],
|
|
220
|
-
EventTiming["After Dinner"],
|
|
640
|
+
types_1.EventTiming["After Breakfast"],
|
|
641
|
+
types_1.EventTiming["After Lunch"],
|
|
642
|
+
types_1.EventTiming["After Dinner"],
|
|
221
643
|
bedtime
|
|
222
644
|
];
|
|
223
645
|
}
|
|
224
646
|
// base === "with"
|
|
225
647
|
if (frequency === 1)
|
|
226
|
-
return [EventTiming.Breakfast];
|
|
648
|
+
return [types_1.EventTiming.Breakfast];
|
|
227
649
|
if (frequency === 2)
|
|
228
650
|
return withPair;
|
|
229
651
|
if (frequency === 3) {
|
|
230
|
-
return [EventTiming.Breakfast, EventTiming.Lunch, EventTiming.Dinner];
|
|
652
|
+
return [types_1.EventTiming.Breakfast, types_1.EventTiming.Lunch, types_1.EventTiming.Dinner];
|
|
231
653
|
}
|
|
232
|
-
return [EventTiming.Breakfast, EventTiming.Lunch, EventTiming.Dinner, bedtime];
|
|
654
|
+
return [types_1.EventTiming.Breakfast, types_1.EventTiming.Lunch, types_1.EventTiming.Dinner, bedtime];
|
|
233
655
|
}
|
|
234
656
|
// Optionally replace generic meal tokens with concrete breakfast/lunch/dinner
|
|
235
657
|
// EventTiming codes when the cadence makes the intent obvious.
|
|
236
658
|
function expandMealTimings(internal, options) {
|
|
237
|
-
|
|
659
|
+
var _a;
|
|
660
|
+
if (!(options === null || options === void 0 ? void 0 : options.smartMealExpansion)) {
|
|
238
661
|
return;
|
|
239
662
|
}
|
|
240
663
|
if (!internal.when.length) {
|
|
@@ -249,7 +672,7 @@ function expandMealTimings(internal, options) {
|
|
|
249
672
|
}
|
|
250
673
|
if (internal.period !== undefined &&
|
|
251
674
|
internal.periodUnit !== undefined &&
|
|
252
|
-
(internal.periodUnit !== FhirPeriodUnit.Day || internal.period !== 1)) {
|
|
675
|
+
(internal.periodUnit !== types_1.FhirPeriodUnit.Day || internal.period !== 1)) {
|
|
253
676
|
return;
|
|
254
677
|
}
|
|
255
678
|
if (internal.period !== undefined &&
|
|
@@ -257,30 +680,30 @@ function expandMealTimings(internal, options) {
|
|
|
257
680
|
internal.period !== 1) {
|
|
258
681
|
return;
|
|
259
682
|
}
|
|
260
|
-
if (internal.periodUnit && internal.periodUnit !== FhirPeriodUnit.Day) {
|
|
683
|
+
if (internal.periodUnit && internal.periodUnit !== types_1.FhirPeriodUnit.Day) {
|
|
261
684
|
return;
|
|
262
685
|
}
|
|
263
686
|
if (internal.frequencyMax !== undefined || internal.periodMax !== undefined) {
|
|
264
687
|
return;
|
|
265
688
|
}
|
|
266
|
-
const pairPreference = options.twoPerDayPair
|
|
689
|
+
const pairPreference = (_a = options.twoPerDayPair) !== null && _a !== void 0 ? _a : "breakfast+dinner";
|
|
267
690
|
const replacements = [];
|
|
268
|
-
if (internal.when.
|
|
691
|
+
if ((0, array_1.arrayIncludes)(internal.when, types_1.EventTiming["Before Meal"])) {
|
|
269
692
|
const specifics = computeMealExpansions("before", frequency, pairPreference);
|
|
270
693
|
if (specifics) {
|
|
271
|
-
replacements.push({ general: EventTiming["Before Meal"], specifics });
|
|
694
|
+
replacements.push({ general: types_1.EventTiming["Before Meal"], specifics });
|
|
272
695
|
}
|
|
273
696
|
}
|
|
274
|
-
if (internal.when.
|
|
697
|
+
if ((0, array_1.arrayIncludes)(internal.when, types_1.EventTiming["After Meal"])) {
|
|
275
698
|
const specifics = computeMealExpansions("after", frequency, pairPreference);
|
|
276
699
|
if (specifics) {
|
|
277
|
-
replacements.push({ general: EventTiming["After Meal"], specifics });
|
|
700
|
+
replacements.push({ general: types_1.EventTiming["After Meal"], specifics });
|
|
278
701
|
}
|
|
279
702
|
}
|
|
280
|
-
if (internal.when.
|
|
703
|
+
if ((0, array_1.arrayIncludes)(internal.when, types_1.EventTiming.Meal)) {
|
|
281
704
|
const specifics = computeMealExpansions("with", frequency, pairPreference);
|
|
282
705
|
if (specifics) {
|
|
283
|
-
replacements.push({ general: EventTiming.Meal, specifics });
|
|
706
|
+
replacements.push({ general: types_1.EventTiming.Meal, specifics });
|
|
284
707
|
}
|
|
285
708
|
}
|
|
286
709
|
for (const { general, specifics } of replacements) {
|
|
@@ -292,15 +715,15 @@ function expandMealTimings(internal, options) {
|
|
|
292
715
|
}
|
|
293
716
|
function setRoute(internal, code, text) {
|
|
294
717
|
internal.routeCode = code;
|
|
295
|
-
internal.routeText = text
|
|
718
|
+
internal.routeText = text !== null && text !== void 0 ? text : maps_1.ROUTE_TEXT[code];
|
|
296
719
|
}
|
|
297
720
|
/**
|
|
298
721
|
* Convert hour-based values into minutes when fractional quantities appear so
|
|
299
722
|
* the resulting FHIR repeat payloads avoid unwieldy decimals.
|
|
300
723
|
*/
|
|
301
724
|
function normalizePeriodValue(value, unit) {
|
|
302
|
-
if (unit === FhirPeriodUnit.Hour && (!Number.isInteger(value) || value < 1)) {
|
|
303
|
-
return { value: Math.round(value * 60 * 1000) / 1000, unit: FhirPeriodUnit.Minute };
|
|
725
|
+
if (unit === types_1.FhirPeriodUnit.Hour && (!Number.isInteger(value) || value < 1)) {
|
|
726
|
+
return { value: Math.round(value * 60 * 1000) / 1000, unit: types_1.FhirPeriodUnit.Minute };
|
|
304
727
|
}
|
|
305
728
|
return { value, unit };
|
|
306
729
|
}
|
|
@@ -309,28 +732,28 @@ function normalizePeriodValue(value, unit) {
|
|
|
309
732
|
* demand conversion into minutes.
|
|
310
733
|
*/
|
|
311
734
|
function normalizePeriodRange(low, high, unit) {
|
|
312
|
-
if (unit === FhirPeriodUnit.Hour && (!Number.isInteger(low) || !Number.isInteger(high) || low < 1 || high < 1)) {
|
|
735
|
+
if (unit === types_1.FhirPeriodUnit.Hour && (!Number.isInteger(low) || !Number.isInteger(high) || low < 1 || high < 1)) {
|
|
313
736
|
return {
|
|
314
737
|
low: Math.round(low * 60 * 1000) / 1000,
|
|
315
738
|
high: Math.round(high * 60 * 1000) / 1000,
|
|
316
|
-
unit: FhirPeriodUnit.Minute
|
|
739
|
+
unit: types_1.FhirPeriodUnit.Minute
|
|
317
740
|
};
|
|
318
741
|
}
|
|
319
742
|
return { low, high, unit };
|
|
320
743
|
}
|
|
321
744
|
function periodUnitSuffix(unit) {
|
|
322
745
|
switch (unit) {
|
|
323
|
-
case FhirPeriodUnit.Minute:
|
|
746
|
+
case types_1.FhirPeriodUnit.Minute:
|
|
324
747
|
return "min";
|
|
325
|
-
case FhirPeriodUnit.Hour:
|
|
748
|
+
case types_1.FhirPeriodUnit.Hour:
|
|
326
749
|
return "h";
|
|
327
|
-
case FhirPeriodUnit.Day:
|
|
750
|
+
case types_1.FhirPeriodUnit.Day:
|
|
328
751
|
return "d";
|
|
329
|
-
case FhirPeriodUnit.Week:
|
|
752
|
+
case types_1.FhirPeriodUnit.Week:
|
|
330
753
|
return "wk";
|
|
331
|
-
case FhirPeriodUnit.Month:
|
|
754
|
+
case types_1.FhirPeriodUnit.Month:
|
|
332
755
|
return "mo";
|
|
333
|
-
case FhirPeriodUnit.Year:
|
|
756
|
+
case types_1.FhirPeriodUnit.Year:
|
|
334
757
|
return "a";
|
|
335
758
|
default:
|
|
336
759
|
return undefined;
|
|
@@ -342,8 +765,8 @@ function maybeAssignTimingCode(internal, value, unit) {
|
|
|
342
765
|
return;
|
|
343
766
|
}
|
|
344
767
|
const key = `q${value}${suffix}`;
|
|
345
|
-
const descriptor = TIMING_ABBREVIATIONS[key];
|
|
346
|
-
if (descriptor
|
|
768
|
+
const descriptor = maps_1.TIMING_ABBREVIATIONS[key];
|
|
769
|
+
if ((descriptor === null || descriptor === void 0 ? void 0 : descriptor.code) && !internal.timingCode) {
|
|
347
770
|
internal.timingCode = descriptor.code;
|
|
348
771
|
}
|
|
349
772
|
}
|
|
@@ -352,18 +775,19 @@ function maybeAssignTimingCode(internal, value, unit) {
|
|
|
352
775
|
* period clearly represents common cadences (daily/weekly/monthly).
|
|
353
776
|
*/
|
|
354
777
|
function applyPeriod(internal, period, unit) {
|
|
778
|
+
var _a, _b, _c;
|
|
355
779
|
const normalized = normalizePeriodValue(period, unit);
|
|
356
780
|
internal.period = normalized.value;
|
|
357
781
|
internal.periodUnit = normalized.unit;
|
|
358
782
|
maybeAssignTimingCode(internal, normalized.value, normalized.unit);
|
|
359
|
-
if (normalized.unit === FhirPeriodUnit.Day && normalized.value === 1) {
|
|
360
|
-
internal.frequency = internal.frequency
|
|
783
|
+
if (normalized.unit === types_1.FhirPeriodUnit.Day && normalized.value === 1) {
|
|
784
|
+
internal.frequency = (_a = internal.frequency) !== null && _a !== void 0 ? _a : 1;
|
|
361
785
|
}
|
|
362
|
-
if (normalized.unit === FhirPeriodUnit.Week && normalized.value === 1) {
|
|
363
|
-
internal.timingCode = internal.timingCode
|
|
786
|
+
if (normalized.unit === types_1.FhirPeriodUnit.Week && normalized.value === 1) {
|
|
787
|
+
internal.timingCode = (_b = internal.timingCode) !== null && _b !== void 0 ? _b : "WK";
|
|
364
788
|
}
|
|
365
|
-
if (normalized.unit === FhirPeriodUnit.Month && normalized.value === 1) {
|
|
366
|
-
internal.timingCode = internal.timingCode
|
|
789
|
+
if (normalized.unit === types_1.FhirPeriodUnit.Month && normalized.value === 1) {
|
|
790
|
+
internal.timingCode = (_c = internal.timingCode) !== null && _c !== void 0 ? _c : "MO";
|
|
367
791
|
}
|
|
368
792
|
}
|
|
369
793
|
/**
|
|
@@ -406,7 +830,7 @@ function tryParseCompactQ(internal, tokens, index) {
|
|
|
406
830
|
}
|
|
407
831
|
function applyFrequencyDescriptor(internal, token, descriptor, options) {
|
|
408
832
|
if (descriptor.discouraged) {
|
|
409
|
-
const check = checkDiscouraged(token.original, options);
|
|
833
|
+
const check = (0, safety_1.checkDiscouraged)(token.original, options);
|
|
410
834
|
if (check.warning) {
|
|
411
835
|
internal.warnings.push(check.warning);
|
|
412
836
|
}
|
|
@@ -447,11 +871,11 @@ function parseMealContext(internal, tokens, index, code) {
|
|
|
447
871
|
applyWhenToken(internal, token, code);
|
|
448
872
|
return;
|
|
449
873
|
}
|
|
450
|
-
const meal = MEAL_KEYWORDS[next.lower];
|
|
874
|
+
const meal = maps_1.MEAL_KEYWORDS[next.lower];
|
|
451
875
|
if (meal) {
|
|
452
|
-
const whenCode = code === EventTiming["After Meal"]
|
|
876
|
+
const whenCode = code === types_1.EventTiming["After Meal"]
|
|
453
877
|
? meal.pc
|
|
454
|
-
: code === EventTiming["Before Meal"]
|
|
878
|
+
: code === types_1.EventTiming["Before Meal"]
|
|
455
879
|
? meal.ac
|
|
456
880
|
: code;
|
|
457
881
|
applyWhenToken(internal, token, whenCode);
|
|
@@ -519,19 +943,19 @@ function mapIntervalUnit(token) {
|
|
|
519
943
|
token === "minute" ||
|
|
520
944
|
token === "minutes" ||
|
|
521
945
|
token === "m") {
|
|
522
|
-
return FhirPeriodUnit.Minute;
|
|
946
|
+
return types_1.FhirPeriodUnit.Minute;
|
|
523
947
|
}
|
|
524
948
|
if (token === "h" || token === "hr" || token === "hrs" || token === "hour" || token === "hours") {
|
|
525
|
-
return FhirPeriodUnit.Hour;
|
|
949
|
+
return types_1.FhirPeriodUnit.Hour;
|
|
526
950
|
}
|
|
527
951
|
if (token === "d" || token === "day" || token === "days") {
|
|
528
|
-
return FhirPeriodUnit.Day;
|
|
952
|
+
return types_1.FhirPeriodUnit.Day;
|
|
529
953
|
}
|
|
530
954
|
if (token === "wk" || token === "w" || token === "week" || token === "weeks") {
|
|
531
|
-
return FhirPeriodUnit.Week;
|
|
955
|
+
return types_1.FhirPeriodUnit.Week;
|
|
532
956
|
}
|
|
533
957
|
if (token === "mo" || token === "month" || token === "months") {
|
|
534
|
-
return FhirPeriodUnit.Month;
|
|
958
|
+
return types_1.FhirPeriodUnit.Month;
|
|
535
959
|
}
|
|
536
960
|
return undefined;
|
|
537
961
|
}
|
|
@@ -547,7 +971,8 @@ function parseNumericRange(token) {
|
|
|
547
971
|
}
|
|
548
972
|
return { low, high };
|
|
549
973
|
}
|
|
550
|
-
|
|
974
|
+
function parseInternal(input, options) {
|
|
975
|
+
var _a, _b, _c, _d, _e, _f;
|
|
551
976
|
const tokens = tokenize(input);
|
|
552
977
|
const internal = {
|
|
553
978
|
input,
|
|
@@ -555,11 +980,12 @@ export function parseInternal(input, options) {
|
|
|
555
980
|
consumed: new Set(),
|
|
556
981
|
dayOfWeek: [],
|
|
557
982
|
when: [],
|
|
558
|
-
warnings: []
|
|
983
|
+
warnings: [],
|
|
984
|
+
siteTokenIndices: new Set()
|
|
559
985
|
};
|
|
560
|
-
const context = options
|
|
561
|
-
const customRouteMap = options
|
|
562
|
-
? new Map(
|
|
986
|
+
const context = (_a = options === null || options === void 0 ? void 0 : options.context) !== null && _a !== void 0 ? _a : undefined;
|
|
987
|
+
const customRouteMap = (options === null || options === void 0 ? void 0 : options.routeMap)
|
|
988
|
+
? new Map((0, object_1.objectEntries)(options.routeMap).map(([key, value]) => [
|
|
563
989
|
key.toLowerCase(),
|
|
564
990
|
value
|
|
565
991
|
]))
|
|
@@ -577,12 +1003,12 @@ export function parseInternal(input, options) {
|
|
|
577
1003
|
prnReasonStart = i + 1;
|
|
578
1004
|
break;
|
|
579
1005
|
}
|
|
580
|
-
if (token.lower === "as" && tokens[i + 1]
|
|
1006
|
+
if (token.lower === "as" && ((_b = tokens[i + 1]) === null || _b === void 0 ? void 0 : _b.lower) === "needed") {
|
|
581
1007
|
internal.asNeeded = true;
|
|
582
1008
|
mark(internal.consumed, token);
|
|
583
1009
|
mark(internal.consumed, tokens[i + 1]);
|
|
584
1010
|
let reasonIndex = i + 2;
|
|
585
|
-
if (tokens[reasonIndex]
|
|
1011
|
+
if (((_c = tokens[reasonIndex]) === null || _c === void 0 ? void 0 : _c.lower) === "for") {
|
|
586
1012
|
mark(internal.consumed, tokens[reasonIndex]);
|
|
587
1013
|
reasonIndex += 1;
|
|
588
1014
|
}
|
|
@@ -603,7 +1029,7 @@ export function parseInternal(input, options) {
|
|
|
603
1029
|
}
|
|
604
1030
|
internal.frequency = freq;
|
|
605
1031
|
internal.period = 1;
|
|
606
|
-
internal.periodUnit = FhirPeriodUnit.Day;
|
|
1032
|
+
internal.periodUnit = types_1.FhirPeriodUnit.Day;
|
|
607
1033
|
mark(internal.consumed, token);
|
|
608
1034
|
}
|
|
609
1035
|
}
|
|
@@ -616,14 +1042,17 @@ export function parseInternal(input, options) {
|
|
|
616
1042
|
continue;
|
|
617
1043
|
}
|
|
618
1044
|
const phrase = slice.map((part) => part.lower).join(" ");
|
|
619
|
-
const customCode = customRouteMap
|
|
1045
|
+
const customCode = customRouteMap === null || customRouteMap === void 0 ? void 0 : customRouteMap.get(phrase);
|
|
620
1046
|
const synonym = customCode
|
|
621
|
-
? { code: customCode, text: ROUTE_TEXT[customCode] }
|
|
622
|
-
: DEFAULT_ROUTE_SYNONYMS[phrase];
|
|
1047
|
+
? { code: customCode, text: maps_1.ROUTE_TEXT[customCode] }
|
|
1048
|
+
: maps_1.DEFAULT_ROUTE_SYNONYMS[phrase];
|
|
623
1049
|
if (synonym) {
|
|
624
1050
|
setRoute(internal, synonym.code, synonym.text);
|
|
625
1051
|
for (const part of slice) {
|
|
626
1052
|
mark(internal.consumed, part);
|
|
1053
|
+
if (BODY_SITE_HINTS.has(part.lower)) {
|
|
1054
|
+
internal.siteTokenIndices.add(part.index);
|
|
1055
|
+
}
|
|
627
1056
|
}
|
|
628
1057
|
return true;
|
|
629
1058
|
}
|
|
@@ -635,12 +1064,13 @@ export function parseInternal(input, options) {
|
|
|
635
1064
|
if (internal.consumed.has(token.index)) {
|
|
636
1065
|
continue;
|
|
637
1066
|
}
|
|
1067
|
+
const normalizedLower = normalizeTokenLower(token);
|
|
638
1068
|
if (token.lower === "bld" || token.lower === "b-l-d") {
|
|
639
|
-
const check = checkDiscouraged(token.original, options);
|
|
1069
|
+
const check = (0, safety_1.checkDiscouraged)(token.original, options);
|
|
640
1070
|
if (check.warning) {
|
|
641
1071
|
internal.warnings.push(check.warning);
|
|
642
1072
|
}
|
|
643
|
-
applyWhenToken(internal, token, EventTiming.Meal);
|
|
1073
|
+
applyWhenToken(internal, token, types_1.EventTiming.Meal);
|
|
644
1074
|
continue;
|
|
645
1075
|
}
|
|
646
1076
|
if (token.lower === "q") {
|
|
@@ -648,8 +1078,25 @@ export function parseInternal(input, options) {
|
|
|
648
1078
|
continue;
|
|
649
1079
|
}
|
|
650
1080
|
}
|
|
1081
|
+
if (tryParseNumericCadence(internal, tokens, i)) {
|
|
1082
|
+
continue;
|
|
1083
|
+
}
|
|
1084
|
+
const eyeSite = EYE_SITE_TOKENS[normalizedLower];
|
|
1085
|
+
const treatEyeTokenAsSite = eyeSite
|
|
1086
|
+
? shouldTreatEyeTokenAsSite(internal, tokens, i, context)
|
|
1087
|
+
: false;
|
|
1088
|
+
if (normalizedLower === "od") {
|
|
1089
|
+
const descriptor = maps_1.TIMING_ABBREVIATIONS.od;
|
|
1090
|
+
if (descriptor &&
|
|
1091
|
+
shouldInterpretOdAsOnceDaily(internal, tokens, i, treatEyeTokenAsSite)) {
|
|
1092
|
+
applyFrequencyDescriptor(internal, token, descriptor, options);
|
|
1093
|
+
continue;
|
|
1094
|
+
}
|
|
1095
|
+
}
|
|
651
1096
|
// Frequency abbreviation map
|
|
652
|
-
const freqDescriptor =
|
|
1097
|
+
const freqDescriptor = normalizedLower === "od"
|
|
1098
|
+
? undefined
|
|
1099
|
+
: (_d = maps_1.TIMING_ABBREVIATIONS[token.lower]) !== null && _d !== void 0 ? _d : maps_1.TIMING_ABBREVIATIONS[normalizedLower];
|
|
653
1100
|
if (freqDescriptor) {
|
|
654
1101
|
applyFrequencyDescriptor(internal, token, freqDescriptor, options);
|
|
655
1102
|
continue;
|
|
@@ -660,34 +1107,34 @@ export function parseInternal(input, options) {
|
|
|
660
1107
|
// Event timing tokens
|
|
661
1108
|
if (token.lower === "pc" || token.lower === "ac") {
|
|
662
1109
|
parseMealContext(internal, tokens, i, token.lower === "pc"
|
|
663
|
-
? EventTiming["After Meal"]
|
|
664
|
-
: EventTiming["Before Meal"]);
|
|
1110
|
+
? types_1.EventTiming["After Meal"]
|
|
1111
|
+
: types_1.EventTiming["Before Meal"]);
|
|
665
1112
|
continue;
|
|
666
1113
|
}
|
|
667
1114
|
const nextToken = tokens[i + 1];
|
|
668
1115
|
if (nextToken && !internal.consumed.has(nextToken.index)) {
|
|
669
1116
|
const combo = `${token.lower} ${nextToken.lower}`;
|
|
670
|
-
const comboWhen = COMBO_EVENT_TIMINGS[combo]
|
|
1117
|
+
const comboWhen = (_e = COMBO_EVENT_TIMINGS[combo]) !== null && _e !== void 0 ? _e : maps_1.EVENT_TIMING_TOKENS[combo];
|
|
671
1118
|
if (comboWhen) {
|
|
672
1119
|
applyWhenToken(internal, token, comboWhen);
|
|
673
1120
|
mark(internal.consumed, nextToken);
|
|
674
1121
|
continue;
|
|
675
1122
|
}
|
|
676
1123
|
}
|
|
677
|
-
const customWhen = options
|
|
1124
|
+
const customWhen = (_f = options === null || options === void 0 ? void 0 : options.whenMap) === null || _f === void 0 ? void 0 : _f[token.lower];
|
|
678
1125
|
if (customWhen) {
|
|
679
1126
|
applyWhenToken(internal, token, customWhen);
|
|
680
1127
|
continue;
|
|
681
1128
|
}
|
|
682
|
-
const whenCode = EVENT_TIMING_TOKENS[token.lower];
|
|
1129
|
+
const whenCode = maps_1.EVENT_TIMING_TOKENS[token.lower];
|
|
683
1130
|
if (whenCode) {
|
|
684
1131
|
applyWhenToken(internal, token, whenCode);
|
|
685
1132
|
continue;
|
|
686
1133
|
}
|
|
687
1134
|
// Day of week
|
|
688
|
-
const day = DAY_OF_WEEK_TOKENS[token.lower];
|
|
1135
|
+
const day = maps_1.DAY_OF_WEEK_TOKENS[token.lower];
|
|
689
1136
|
if (day) {
|
|
690
|
-
if (!internal.dayOfWeek
|
|
1137
|
+
if (!(0, array_1.arrayIncludes)(internal.dayOfWeek, day)) {
|
|
691
1138
|
internal.dayOfWeek.push(day);
|
|
692
1139
|
}
|
|
693
1140
|
mark(internal.consumed, token);
|
|
@@ -697,9 +1144,9 @@ export function parseInternal(input, options) {
|
|
|
697
1144
|
if (tryRouteSynonym(i)) {
|
|
698
1145
|
continue;
|
|
699
1146
|
}
|
|
700
|
-
|
|
701
|
-
if (eyeSite) {
|
|
1147
|
+
if (eyeSite && treatEyeTokenAsSite) {
|
|
702
1148
|
internal.siteText = eyeSite.site;
|
|
1149
|
+
internal.siteSource = "abbreviation";
|
|
703
1150
|
if (eyeSite.route && !internal.routeCode) {
|
|
704
1151
|
setRoute(internal, eyeSite.route);
|
|
705
1152
|
}
|
|
@@ -750,7 +1197,7 @@ export function parseInternal(input, options) {
|
|
|
750
1197
|
continue;
|
|
751
1198
|
}
|
|
752
1199
|
// Words for frequency
|
|
753
|
-
const wordFreq = WORD_FREQUENCIES[token.lower];
|
|
1200
|
+
const wordFreq = maps_1.WORD_FREQUENCIES[token.lower];
|
|
754
1201
|
if (wordFreq) {
|
|
755
1202
|
internal.frequency = wordFreq.frequency;
|
|
756
1203
|
internal.period = 1;
|
|
@@ -759,7 +1206,7 @@ export function parseInternal(input, options) {
|
|
|
759
1206
|
continue;
|
|
760
1207
|
}
|
|
761
1208
|
// Skip generic connectors
|
|
762
|
-
if (token.lower === "per" || token.lower === "a" || token.lower === "every") {
|
|
1209
|
+
if (token.lower === "per" || token.lower === "a" || token.lower === "every" || token.lower === "each") {
|
|
763
1210
|
mark(internal.consumed, token);
|
|
764
1211
|
continue;
|
|
765
1212
|
}
|
|
@@ -778,13 +1225,19 @@ export function parseInternal(input, options) {
|
|
|
778
1225
|
}
|
|
779
1226
|
}
|
|
780
1227
|
if (internal.unit === undefined) {
|
|
781
|
-
internal.unit = inferUnitFromContext(context);
|
|
1228
|
+
internal.unit = (0, context_1.inferUnitFromContext)(context);
|
|
1229
|
+
}
|
|
1230
|
+
if (internal.unit === undefined) {
|
|
1231
|
+
const fallbackUnit = inferUnitFromRouteHints(internal);
|
|
1232
|
+
if (fallbackUnit) {
|
|
1233
|
+
internal.unit = fallbackUnit;
|
|
1234
|
+
}
|
|
782
1235
|
}
|
|
783
1236
|
// Frequency defaults when timing code implies it
|
|
784
1237
|
if (internal.frequency === undefined &&
|
|
785
1238
|
internal.period === undefined &&
|
|
786
1239
|
internal.timingCode) {
|
|
787
|
-
const descriptor = TIMING_ABBREVIATIONS[internal.timingCode.toLowerCase()];
|
|
1240
|
+
const descriptor = maps_1.TIMING_ABBREVIATIONS[internal.timingCode.toLowerCase()];
|
|
788
1241
|
if (descriptor) {
|
|
789
1242
|
if (descriptor.frequency !== undefined) {
|
|
790
1243
|
internal.frequency = descriptor.frequency;
|
|
@@ -804,7 +1257,7 @@ export function parseInternal(input, options) {
|
|
|
804
1257
|
}
|
|
805
1258
|
if (!internal.timingCode &&
|
|
806
1259
|
internal.frequency !== undefined &&
|
|
807
|
-
internal.periodUnit === FhirPeriodUnit.Day &&
|
|
1260
|
+
internal.periodUnit === types_1.FhirPeriodUnit.Day &&
|
|
808
1261
|
(internal.period === undefined || internal.period === 1)) {
|
|
809
1262
|
if (internal.frequency === 2) {
|
|
810
1263
|
internal.timingCode = "BID";
|
|
@@ -820,19 +1273,76 @@ export function parseInternal(input, options) {
|
|
|
820
1273
|
expandMealTimings(internal, options);
|
|
821
1274
|
// Determine site text from leftover tokens (excluding PRN reason tokens)
|
|
822
1275
|
const leftoverTokens = tokens.filter((t) => !internal.consumed.has(t.index));
|
|
823
|
-
|
|
824
|
-
|
|
825
|
-
if (
|
|
826
|
-
|
|
827
|
-
|
|
828
|
-
|
|
829
|
-
|
|
830
|
-
|
|
831
|
-
|
|
1276
|
+
const siteCandidateIndices = new Set();
|
|
1277
|
+
for (const token of leftoverTokens) {
|
|
1278
|
+
if (BODY_SITE_HINTS.has(token.lower)) {
|
|
1279
|
+
siteCandidateIndices.add(token.index);
|
|
1280
|
+
}
|
|
1281
|
+
}
|
|
1282
|
+
for (const idx of internal.siteTokenIndices) {
|
|
1283
|
+
siteCandidateIndices.add(idx);
|
|
1284
|
+
}
|
|
1285
|
+
if (siteCandidateIndices.size > 0) {
|
|
1286
|
+
const indicesToInclude = new Set(siteCandidateIndices);
|
|
1287
|
+
for (const idx of siteCandidateIndices) {
|
|
1288
|
+
let prev = idx - 1;
|
|
1289
|
+
while (prev >= 0) {
|
|
1290
|
+
const token = tokens[prev];
|
|
1291
|
+
if (!token) {
|
|
1292
|
+
break;
|
|
1293
|
+
}
|
|
1294
|
+
const lower = token.lower;
|
|
1295
|
+
if (SITE_CONNECTORS.has(lower) || BODY_SITE_HINTS.has(lower)) {
|
|
1296
|
+
indicesToInclude.add(token.index);
|
|
1297
|
+
prev -= 1;
|
|
1298
|
+
continue;
|
|
832
1299
|
}
|
|
1300
|
+
break;
|
|
833
1301
|
}
|
|
834
|
-
|
|
835
|
-
|
|
1302
|
+
let next = idx + 1;
|
|
1303
|
+
while (next < tokens.length) {
|
|
1304
|
+
const token = tokens[next];
|
|
1305
|
+
if (!token) {
|
|
1306
|
+
break;
|
|
1307
|
+
}
|
|
1308
|
+
const lower = token.lower;
|
|
1309
|
+
if (SITE_CONNECTORS.has(lower) || BODY_SITE_HINTS.has(lower)) {
|
|
1310
|
+
indicesToInclude.add(token.index);
|
|
1311
|
+
next += 1;
|
|
1312
|
+
continue;
|
|
1313
|
+
}
|
|
1314
|
+
break;
|
|
1315
|
+
}
|
|
1316
|
+
}
|
|
1317
|
+
const sortedIndices = Array.from(indicesToInclude).sort((a, b) => a - b);
|
|
1318
|
+
const displayWords = [];
|
|
1319
|
+
for (const index of sortedIndices) {
|
|
1320
|
+
const token = tokens[index];
|
|
1321
|
+
if (!token) {
|
|
1322
|
+
continue;
|
|
1323
|
+
}
|
|
1324
|
+
const lower = token.lower;
|
|
1325
|
+
if (!SITE_CONNECTORS.has(lower) && !SITE_FILLER_WORDS.has(lower)) {
|
|
1326
|
+
displayWords.push(token.original);
|
|
1327
|
+
}
|
|
1328
|
+
mark(internal.consumed, token);
|
|
1329
|
+
}
|
|
1330
|
+
const normalizedSite = displayWords
|
|
1331
|
+
.filter((word) => !SITE_CONNECTORS.has(word.trim().toLowerCase()))
|
|
1332
|
+
.join(" ")
|
|
1333
|
+
.trim();
|
|
1334
|
+
if (normalizedSite) {
|
|
1335
|
+
internal.siteText = normalizedSite;
|
|
1336
|
+
if (!internal.siteSource) {
|
|
1337
|
+
internal.siteSource = "text";
|
|
1338
|
+
}
|
|
1339
|
+
}
|
|
1340
|
+
}
|
|
1341
|
+
if (!internal.routeCode && internal.siteText) {
|
|
1342
|
+
for (const { pattern, route } of SITE_UNIT_ROUTE_HINTS) {
|
|
1343
|
+
if (pattern.test(internal.siteText)) {
|
|
1344
|
+
setRoute(internal, route);
|
|
1345
|
+
break;
|
|
836
1346
|
}
|
|
837
1347
|
}
|
|
838
1348
|
}
|
|
@@ -851,20 +1361,57 @@ export function parseInternal(input, options) {
|
|
|
851
1361
|
internal.asNeededReason = reasonTokens.join(" ");
|
|
852
1362
|
}
|
|
853
1363
|
}
|
|
854
|
-
if (internal.routeCode === RouteCode["Intravitreal route (qualifier value)"] &&
|
|
1364
|
+
if (internal.routeCode === types_1.RouteCode["Intravitreal route (qualifier value)"] &&
|
|
855
1365
|
(!internal.siteText || !/eye/i.test(internal.siteText))) {
|
|
856
1366
|
internal.warnings.push("Intravitreal administrations require an eye site (e.g., OD/OS/OU).");
|
|
857
1367
|
}
|
|
858
1368
|
return internal;
|
|
859
1369
|
}
|
|
860
1370
|
function normalizeUnit(token, options) {
|
|
861
|
-
|
|
1371
|
+
var _a;
|
|
1372
|
+
const override = (_a = options === null || options === void 0 ? void 0 : options.unitMap) === null || _a === void 0 ? void 0 : _a[token];
|
|
862
1373
|
if (override) {
|
|
863
1374
|
return override;
|
|
864
1375
|
}
|
|
865
|
-
const defaultUnit = DEFAULT_UNIT_SYNONYMS[token];
|
|
1376
|
+
const defaultUnit = maps_1.DEFAULT_UNIT_SYNONYMS[token];
|
|
866
1377
|
if (defaultUnit) {
|
|
867
1378
|
return defaultUnit;
|
|
868
1379
|
}
|
|
869
1380
|
return undefined;
|
|
870
1381
|
}
|
|
1382
|
+
function inferUnitFromRouteHints(internal) {
|
|
1383
|
+
if (internal.routeCode) {
|
|
1384
|
+
const unit = maps_1.DEFAULT_UNIT_BY_ROUTE[internal.routeCode];
|
|
1385
|
+
if (unit) {
|
|
1386
|
+
return unit;
|
|
1387
|
+
}
|
|
1388
|
+
}
|
|
1389
|
+
if (internal.routeText) {
|
|
1390
|
+
const normalized = internal.routeText.trim().toLowerCase();
|
|
1391
|
+
const synonym = maps_1.DEFAULT_ROUTE_SYNONYMS[normalized];
|
|
1392
|
+
if (synonym) {
|
|
1393
|
+
const unit = maps_1.DEFAULT_UNIT_BY_ROUTE[synonym.code];
|
|
1394
|
+
if (unit) {
|
|
1395
|
+
return unit;
|
|
1396
|
+
}
|
|
1397
|
+
}
|
|
1398
|
+
}
|
|
1399
|
+
if (internal.siteText) {
|
|
1400
|
+
const unit = inferUnitFromSiteText(internal.siteText);
|
|
1401
|
+
if (unit) {
|
|
1402
|
+
return unit;
|
|
1403
|
+
}
|
|
1404
|
+
}
|
|
1405
|
+
return undefined;
|
|
1406
|
+
}
|
|
1407
|
+
function inferUnitFromSiteText(siteText) {
|
|
1408
|
+
for (const { pattern, route } of SITE_UNIT_ROUTE_HINTS) {
|
|
1409
|
+
if (pattern.test(siteText)) {
|
|
1410
|
+
const unit = maps_1.DEFAULT_UNIT_BY_ROUTE[route];
|
|
1411
|
+
if (unit) {
|
|
1412
|
+
return unit;
|
|
1413
|
+
}
|
|
1414
|
+
}
|
|
1415
|
+
}
|
|
1416
|
+
return undefined;
|
|
1417
|
+
}
|