ezmedicationinput 0.1.42 → 0.1.44
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 +31 -1
- package/dist/advice-rules.json +772 -0
- package/dist/advice-terminology.json +104 -0
- package/dist/advice.d.ts +16 -0
- package/dist/advice.js +1375 -0
- package/dist/event-trigger.d.ts +14 -0
- package/dist/event-trigger.js +501 -0
- package/dist/fhir-translations.d.ts +5 -0
- package/dist/fhir-translations.js +117 -0
- package/dist/fhir.d.ts +6 -4
- package/dist/fhir.js +566 -134
- package/dist/format.d.ts +5 -2
- package/dist/format.js +581 -219
- package/dist/i18n.d.ts +4 -2
- package/dist/i18n.js +725 -197
- package/dist/index.d.ts +0 -1
- package/dist/index.js +221 -169
- package/dist/internal-types.d.ts +5 -5
- package/dist/ir.d.ts +4 -0
- package/dist/ir.js +178 -0
- package/dist/lexer/lex.d.ts +2 -0
- package/dist/lexer/lex.js +401 -0
- package/dist/lexer/meaning.d.ts +71 -0
- package/dist/lexer/meaning.js +619 -0
- package/dist/lexer/surface.d.ts +2 -0
- package/dist/lexer/surface.js +62 -0
- package/dist/lexer/token-types.d.ts +36 -0
- package/dist/lexer/token-types.js +19 -0
- package/dist/maps.d.ts +6 -12
- package/dist/maps.js +793 -247
- package/dist/parser-state.d.ts +101 -0
- package/dist/parser-state.js +441 -0
- package/dist/parser.d.ts +7 -7
- package/dist/parser.js +3598 -1974
- package/dist/prn.d.ts +4 -0
- package/dist/prn.js +59 -0
- package/dist/schedule.js +230 -32
- package/dist/site-phrases.d.ts +35 -0
- package/dist/site-phrases.js +344 -0
- package/dist/timing-summary.d.ts +25 -0
- package/dist/timing-summary.js +138 -0
- package/dist/types.d.ts +248 -32
- package/dist/types.js +49 -1
- package/dist/utils/text.d.ts +3 -0
- package/dist/utils/text.js +48 -0
- package/package.json +1 -1
package/dist/format.js
CHANGED
|
@@ -1,7 +1,10 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.formatCanonicalClause = formatCanonicalClause;
|
|
3
4
|
exports.formatInternal = formatInternal;
|
|
5
|
+
const prn_1 = require("./prn");
|
|
4
6
|
const types_1 = require("./types");
|
|
7
|
+
const timing_summary_1 = require("./timing-summary");
|
|
5
8
|
const ROUTE_SHORT = {
|
|
6
9
|
[types_1.RouteCode["Oral route"]]: "PO",
|
|
7
10
|
[types_1.RouteCode["Sublingual route"]]: "SL",
|
|
@@ -56,9 +59,17 @@ const DAY_NAMES = {
|
|
|
56
59
|
sat: "Saturday",
|
|
57
60
|
sun: "Sunday"
|
|
58
61
|
};
|
|
62
|
+
const EN_TIMES_PER_DAY = {
|
|
63
|
+
1: "once daily",
|
|
64
|
+
2: "twice daily",
|
|
65
|
+
3: "three times daily",
|
|
66
|
+
4: "four times daily"
|
|
67
|
+
};
|
|
68
|
+
const SLOWLY_QUALIFIER_CODE = "419443000";
|
|
69
|
+
const EMPTY_STOMACH_QUALIFIER_CODE = "717154004";
|
|
59
70
|
const DEFAULT_ROUTE_GRAMMAR = { verb: "Use" };
|
|
60
71
|
const ROUTE_GRAMMAR = {
|
|
61
|
-
[types_1.RouteCode["Oral route"]]: { verb: "Take", routePhrase: "
|
|
72
|
+
[types_1.RouteCode["Oral route"]]: { verb: "Take", routePhrase: "orally" },
|
|
62
73
|
[types_1.RouteCode["Ophthalmic route"]]: {
|
|
63
74
|
verb: "Instill",
|
|
64
75
|
routePhrase: ({ hasSite }) => (hasSite ? undefined : "in the eye"),
|
|
@@ -74,6 +85,11 @@ const ROUTE_GRAMMAR = {
|
|
|
74
85
|
routePhrase: ({ hasSite }) => (hasSite ? undefined : "rectally"),
|
|
75
86
|
sitePreposition: "into"
|
|
76
87
|
},
|
|
88
|
+
[types_1.RouteCode["Per vagina"]]: {
|
|
89
|
+
verb: "Insert",
|
|
90
|
+
routePhrase: ({ hasSite }) => (hasSite ? undefined : "vaginally"),
|
|
91
|
+
sitePreposition: "into"
|
|
92
|
+
},
|
|
77
93
|
[types_1.RouteCode["Topical route"]]: {
|
|
78
94
|
verb: "Apply",
|
|
79
95
|
routePhrase: ({ hasSite }) => (hasSite ? undefined : "topically"),
|
|
@@ -110,6 +126,10 @@ const ROUTE_GRAMMAR = {
|
|
|
110
126
|
sitePreposition: "into"
|
|
111
127
|
}
|
|
112
128
|
};
|
|
129
|
+
function scheduleOf(clause) {
|
|
130
|
+
var _a;
|
|
131
|
+
return (_a = clause.schedule) !== null && _a !== void 0 ? _a : {};
|
|
132
|
+
}
|
|
113
133
|
function grammarFromRouteText(text) {
|
|
114
134
|
if (!text) {
|
|
115
135
|
return undefined;
|
|
@@ -145,6 +165,9 @@ function grammarFromRouteText(text) {
|
|
|
145
165
|
if (normalized.includes("rectal") || normalized.includes("rectum")) {
|
|
146
166
|
return ROUTE_GRAMMAR[types_1.RouteCode["Per rectum"]];
|
|
147
167
|
}
|
|
168
|
+
if (normalized.includes("vagin")) {
|
|
169
|
+
return ROUTE_GRAMMAR[types_1.RouteCode["Per vagina"]];
|
|
170
|
+
}
|
|
148
171
|
if (normalized.includes("nasal")) {
|
|
149
172
|
return ROUTE_GRAMMAR[types_1.RouteCode["Nasal route"]];
|
|
150
173
|
}
|
|
@@ -153,41 +176,89 @@ function grammarFromRouteText(text) {
|
|
|
153
176
|
}
|
|
154
177
|
return undefined;
|
|
155
178
|
}
|
|
156
|
-
function resolveRouteGrammar(
|
|
179
|
+
function resolveRouteGrammar(clause) {
|
|
180
|
+
var _a, _b, _c, _d;
|
|
181
|
+
const routeCode = (_a = clause.route) === null || _a === void 0 ? void 0 : _a.code;
|
|
182
|
+
if (routeCode && ROUTE_GRAMMAR[routeCode]) {
|
|
183
|
+
return (_b = ROUTE_GRAMMAR[routeCode]) !== null && _b !== void 0 ? _b : DEFAULT_ROUTE_GRAMMAR;
|
|
184
|
+
}
|
|
185
|
+
return (_d = grammarFromRouteText((_c = clause.route) === null || _c === void 0 ? void 0 : _c.text)) !== null && _d !== void 0 ? _d : DEFAULT_ROUTE_GRAMMAR;
|
|
186
|
+
}
|
|
187
|
+
function resolveMethodVerb(clause, grammar) {
|
|
157
188
|
var _a, _b;
|
|
158
|
-
|
|
159
|
-
|
|
189
|
+
const methodText = (_b = (_a = clause.method) === null || _a === void 0 ? void 0 : _a.text) === null || _b === void 0 ? void 0 : _b.trim();
|
|
190
|
+
if (methodText) {
|
|
191
|
+
return methodText;
|
|
160
192
|
}
|
|
161
|
-
return
|
|
193
|
+
return grammar.verb;
|
|
162
194
|
}
|
|
163
195
|
function pluralize(unit, value) {
|
|
164
196
|
if (Math.abs(value) === 1) {
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
197
|
+
switch (unit) {
|
|
198
|
+
case "tab":
|
|
199
|
+
return "tablet";
|
|
200
|
+
case "cap":
|
|
201
|
+
return "capsule";
|
|
202
|
+
default:
|
|
203
|
+
return unit;
|
|
204
|
+
}
|
|
205
|
+
}
|
|
206
|
+
if (unit.endsWith(" ribbon")) {
|
|
169
207
|
return unit;
|
|
170
208
|
}
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
209
|
+
switch (unit) {
|
|
210
|
+
case "tab":
|
|
211
|
+
case "tablet":
|
|
212
|
+
return "tablets";
|
|
213
|
+
case "cap":
|
|
214
|
+
case "capsule":
|
|
215
|
+
return "capsules";
|
|
216
|
+
case "mL":
|
|
217
|
+
case "mg":
|
|
218
|
+
return unit;
|
|
219
|
+
case "puff":
|
|
220
|
+
return "puffs";
|
|
221
|
+
case "patch":
|
|
222
|
+
return "patches";
|
|
223
|
+
case "drop":
|
|
224
|
+
return "drops";
|
|
225
|
+
case "suppository":
|
|
226
|
+
return "suppositories";
|
|
227
|
+
case "pump":
|
|
228
|
+
return "pumps";
|
|
229
|
+
case "squeeze":
|
|
230
|
+
return "squeezes";
|
|
231
|
+
case "applicatorful":
|
|
232
|
+
return "applicatorfuls";
|
|
233
|
+
case "capful":
|
|
234
|
+
return "capfuls";
|
|
235
|
+
case "scoop":
|
|
236
|
+
return "scoops";
|
|
237
|
+
case "application":
|
|
238
|
+
return "applications";
|
|
239
|
+
case "fingertip unit":
|
|
240
|
+
return "fingertip units";
|
|
241
|
+
case "finger length":
|
|
242
|
+
return "finger lengths";
|
|
243
|
+
default:
|
|
244
|
+
return unit;
|
|
245
|
+
}
|
|
246
|
+
}
|
|
247
|
+
function formatPatientInstructionSentence(text) {
|
|
248
|
+
const trimmed = text === null || text === void 0 ? void 0 : text.trim();
|
|
249
|
+
if (!trimmed) {
|
|
250
|
+
return undefined;
|
|
251
|
+
}
|
|
252
|
+
const sentence = /^[.!?]$/.test(trimmed.slice(-1)) ? trimmed : `${trimmed}.`;
|
|
253
|
+
return sentence.charAt(0).toUpperCase() + sentence.slice(1);
|
|
188
254
|
}
|
|
189
|
-
function describeFrequency(
|
|
190
|
-
const
|
|
255
|
+
function describeFrequency(schedule) {
|
|
256
|
+
const frequency = schedule === null || schedule === void 0 ? void 0 : schedule.frequency;
|
|
257
|
+
const frequencyMax = schedule === null || schedule === void 0 ? void 0 : schedule.frequencyMax;
|
|
258
|
+
const period = schedule === null || schedule === void 0 ? void 0 : schedule.period;
|
|
259
|
+
const periodMax = schedule === null || schedule === void 0 ? void 0 : schedule.periodMax;
|
|
260
|
+
const periodUnit = schedule === null || schedule === void 0 ? void 0 : schedule.periodUnit;
|
|
261
|
+
const timingCode = schedule === null || schedule === void 0 ? void 0 : schedule.timingCode;
|
|
191
262
|
if (frequency !== undefined &&
|
|
192
263
|
frequencyMax !== undefined &&
|
|
193
264
|
periodUnit === types_1.FhirPeriodUnit.Day &&
|
|
@@ -201,16 +272,18 @@ function describeFrequency(internal) {
|
|
|
201
272
|
return `${stripTrailingZero(frequency)} to ${stripTrailingZero(frequencyMax)} times daily`;
|
|
202
273
|
}
|
|
203
274
|
if (frequency && periodUnit === types_1.FhirPeriodUnit.Day && (!period || period === 1)) {
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
if (frequency === 3)
|
|
209
|
-
return "three times daily";
|
|
210
|
-
if (frequency === 4)
|
|
211
|
-
return "four times daily";
|
|
275
|
+
const dailyText = EN_TIMES_PER_DAY[frequency];
|
|
276
|
+
if (dailyText) {
|
|
277
|
+
return dailyText;
|
|
278
|
+
}
|
|
212
279
|
return `${stripTrailingZero(frequency)} times daily`;
|
|
213
280
|
}
|
|
281
|
+
if (periodUnit === types_1.FhirPeriodUnit.Minute && period) {
|
|
282
|
+
if (periodMax && periodMax !== period) {
|
|
283
|
+
return `every ${stripTrailingZero(period)} to ${stripTrailingZero(periodMax)} minutes`;
|
|
284
|
+
}
|
|
285
|
+
return `every ${stripTrailingZero(period)} minute${period === 1 ? "" : "s"}`;
|
|
286
|
+
}
|
|
214
287
|
if (periodUnit === types_1.FhirPeriodUnit.Hour && period) {
|
|
215
288
|
if (periodMax && periodMax !== period) {
|
|
216
289
|
return `every ${stripTrailingZero(period)} to ${stripTrailingZero(periodMax)} hours`;
|
|
@@ -244,6 +317,15 @@ function describeFrequency(internal) {
|
|
|
244
317
|
}
|
|
245
318
|
return `every ${stripTrailingZero(period)} months`;
|
|
246
319
|
}
|
|
320
|
+
if (periodUnit === types_1.FhirPeriodUnit.Year && period) {
|
|
321
|
+
if (period === 1 && (!periodMax || periodMax === 1)) {
|
|
322
|
+
return "once yearly";
|
|
323
|
+
}
|
|
324
|
+
if (periodMax && periodMax !== period) {
|
|
325
|
+
return `every ${stripTrailingZero(period)} to ${stripTrailingZero(periodMax)} years`;
|
|
326
|
+
}
|
|
327
|
+
return `every ${stripTrailingZero(period)} years`;
|
|
328
|
+
}
|
|
247
329
|
if (timingCode) {
|
|
248
330
|
if (timingCode === "WK") {
|
|
249
331
|
return "once weekly";
|
|
@@ -265,81 +347,200 @@ function describeFrequency(internal) {
|
|
|
265
347
|
}
|
|
266
348
|
}
|
|
267
349
|
if (frequency && periodUnit === undefined && period === undefined) {
|
|
268
|
-
if (frequency === 1)
|
|
350
|
+
if (frequency === 1) {
|
|
269
351
|
return "once";
|
|
352
|
+
}
|
|
270
353
|
return `${stripTrailingZero(frequency)} times`;
|
|
271
354
|
}
|
|
272
355
|
return undefined;
|
|
273
356
|
}
|
|
274
|
-
function
|
|
275
|
-
if (
|
|
276
|
-
|
|
277
|
-
|
|
278
|
-
|
|
279
|
-
|
|
357
|
+
function describeFrequencyCount(count) {
|
|
358
|
+
if (!count || count <= 0) {
|
|
359
|
+
return undefined;
|
|
360
|
+
}
|
|
361
|
+
const dailyText = EN_TIMES_PER_DAY[count];
|
|
362
|
+
if (dailyText) {
|
|
363
|
+
return dailyText;
|
|
364
|
+
}
|
|
365
|
+
return `${stripTrailingZero(count)} times daily`;
|
|
366
|
+
}
|
|
367
|
+
function describeStandaloneOccurrenceCount(schedule) {
|
|
368
|
+
var _a, _b, _c;
|
|
369
|
+
const count = schedule === null || schedule === void 0 ? void 0 : schedule.count;
|
|
370
|
+
if (!count || count <= 0) {
|
|
371
|
+
return undefined;
|
|
372
|
+
}
|
|
373
|
+
if ((schedule === null || schedule === void 0 ? void 0 : schedule.frequency) !== undefined ||
|
|
374
|
+
(schedule === null || schedule === void 0 ? void 0 : schedule.frequencyMax) !== undefined ||
|
|
375
|
+
(schedule === null || schedule === void 0 ? void 0 : schedule.period) !== undefined ||
|
|
376
|
+
(schedule === null || schedule === void 0 ? void 0 : schedule.periodMax) !== undefined ||
|
|
377
|
+
(schedule === null || schedule === void 0 ? void 0 : schedule.periodUnit) !== undefined ||
|
|
378
|
+
((_a = schedule === null || schedule === void 0 ? void 0 : schedule.dayOfWeek) === null || _a === void 0 ? void 0 : _a.length) ||
|
|
379
|
+
((_b = schedule === null || schedule === void 0 ? void 0 : schedule.when) === null || _b === void 0 ? void 0 : _b.length) ||
|
|
380
|
+
((_c = schedule === null || schedule === void 0 ? void 0 : schedule.timeOfDay) === null || _c === void 0 ? void 0 : _c.length) ||
|
|
381
|
+
(schedule === null || schedule === void 0 ? void 0 : schedule.duration) !== undefined ||
|
|
382
|
+
(schedule === null || schedule === void 0 ? void 0 : schedule.durationMax) !== undefined ||
|
|
383
|
+
(schedule === null || schedule === void 0 ? void 0 : schedule.durationUnit) !== undefined ||
|
|
384
|
+
(schedule === null || schedule === void 0 ? void 0 : schedule.timingCode)) {
|
|
385
|
+
return undefined;
|
|
386
|
+
}
|
|
387
|
+
switch (count) {
|
|
388
|
+
case 1:
|
|
389
|
+
return "once";
|
|
390
|
+
case 2:
|
|
391
|
+
return "twice";
|
|
392
|
+
default:
|
|
393
|
+
return `${stripTrailingZero(count)} times`;
|
|
394
|
+
}
|
|
395
|
+
}
|
|
396
|
+
function formatDoseShort(dose) {
|
|
397
|
+
if (!dose) {
|
|
398
|
+
return undefined;
|
|
399
|
+
}
|
|
400
|
+
if (dose.range) {
|
|
401
|
+
if (dose.range.low !== undefined && dose.range.high !== undefined) {
|
|
402
|
+
const base = `${stripTrailingZero(dose.range.low)}-${stripTrailingZero(dose.range.high)}`;
|
|
403
|
+
if (dose.unit) {
|
|
404
|
+
return `${base} ${dose.unit}`;
|
|
405
|
+
}
|
|
406
|
+
return base;
|
|
407
|
+
}
|
|
408
|
+
if (dose.range.low !== undefined) {
|
|
409
|
+
const base = `>=${stripTrailingZero(dose.range.low)}`;
|
|
410
|
+
if (dose.unit) {
|
|
411
|
+
return `${base} ${dose.unit}`;
|
|
412
|
+
}
|
|
413
|
+
return base;
|
|
414
|
+
}
|
|
415
|
+
if (dose.range.high !== undefined) {
|
|
416
|
+
const base = `<=${stripTrailingZero(dose.range.high)}`;
|
|
417
|
+
if (dose.unit) {
|
|
418
|
+
return `${base} ${dose.unit}`;
|
|
419
|
+
}
|
|
420
|
+
return base;
|
|
280
421
|
}
|
|
281
|
-
return base;
|
|
282
422
|
}
|
|
283
|
-
if (
|
|
284
|
-
|
|
285
|
-
|
|
286
|
-
|
|
287
|
-
return
|
|
423
|
+
if (dose.value !== undefined) {
|
|
424
|
+
if (dose.unit) {
|
|
425
|
+
return `${stripTrailingZero(dose.value)} ${dose.unit}`;
|
|
426
|
+
}
|
|
427
|
+
return `${stripTrailingZero(dose.value)}`;
|
|
288
428
|
}
|
|
289
429
|
return undefined;
|
|
290
430
|
}
|
|
291
|
-
function formatDoseLong(
|
|
292
|
-
if (
|
|
293
|
-
|
|
294
|
-
|
|
295
|
-
|
|
431
|
+
function formatDoseLong(dose) {
|
|
432
|
+
if (!dose) {
|
|
433
|
+
return undefined;
|
|
434
|
+
}
|
|
435
|
+
if (dose.range) {
|
|
436
|
+
if (dose.range.low !== undefined && dose.range.high !== undefined) {
|
|
437
|
+
if (dose.unit) {
|
|
438
|
+
return `${stripTrailingZero(dose.range.low)} to ${stripTrailingZero(dose.range.high)} ${pluralize(dose.unit, dose.range.high)}`;
|
|
439
|
+
}
|
|
440
|
+
return `${stripTrailingZero(dose.range.low)} to ${stripTrailingZero(dose.range.high)}`;
|
|
441
|
+
}
|
|
442
|
+
if (dose.range.low !== undefined) {
|
|
443
|
+
if (dose.unit) {
|
|
444
|
+
return `at least ${stripTrailingZero(dose.range.low)} ${pluralize(dose.unit, dose.range.low)}`;
|
|
445
|
+
}
|
|
446
|
+
return `at least ${stripTrailingZero(dose.range.low)}`;
|
|
447
|
+
}
|
|
448
|
+
if (dose.range.high !== undefined) {
|
|
449
|
+
if (dose.unit) {
|
|
450
|
+
return `up to ${stripTrailingZero(dose.range.high)} ${pluralize(dose.unit, dose.range.high)}`;
|
|
451
|
+
}
|
|
452
|
+
return `up to ${stripTrailingZero(dose.range.high)}`;
|
|
296
453
|
}
|
|
297
|
-
return `${stripTrailingZero(low)} to ${stripTrailingZero(high)}`;
|
|
298
454
|
}
|
|
299
|
-
if (
|
|
300
|
-
if (
|
|
301
|
-
return `${stripTrailingZero(
|
|
455
|
+
if (dose.value !== undefined) {
|
|
456
|
+
if (dose.unit) {
|
|
457
|
+
return `${stripTrailingZero(dose.value)} ${pluralize(dose.unit, dose.value)}`;
|
|
302
458
|
}
|
|
303
|
-
return `${stripTrailingZero(
|
|
459
|
+
return `${stripTrailingZero(dose.value)}`;
|
|
304
460
|
}
|
|
305
461
|
return undefined;
|
|
306
462
|
}
|
|
307
|
-
function
|
|
308
|
-
|
|
463
|
+
function summarizeMealTimingGroup(group) {
|
|
464
|
+
let relationText = "with";
|
|
465
|
+
if (group.relation === "before") {
|
|
466
|
+
relationText = "before";
|
|
467
|
+
}
|
|
468
|
+
else if (group.relation === "after") {
|
|
469
|
+
relationText = "after";
|
|
470
|
+
}
|
|
471
|
+
return `${relationText} ${joinWithAnd(group.meals)}`;
|
|
472
|
+
}
|
|
473
|
+
function collectWhenPhrases(schedule, options) {
|
|
474
|
+
var _a, _b, _c;
|
|
475
|
+
const when = (_a = schedule === null || schedule === void 0 ? void 0 : schedule.when) !== null && _a !== void 0 ? _a : [];
|
|
476
|
+
if (!when.length) {
|
|
309
477
|
return [];
|
|
310
478
|
}
|
|
311
479
|
const unique = [];
|
|
312
480
|
const seen = new Set();
|
|
313
|
-
|
|
481
|
+
let hasSpecificAfter = false;
|
|
482
|
+
let hasSpecificBefore = false;
|
|
483
|
+
let hasSpecificWith = false;
|
|
484
|
+
for (const code of when) {
|
|
314
485
|
if (!seen.has(code)) {
|
|
315
486
|
seen.add(code);
|
|
316
487
|
unique.push(code);
|
|
488
|
+
if (code === types_1.EventTiming["After Breakfast"] ||
|
|
489
|
+
code === types_1.EventTiming["After Lunch"] ||
|
|
490
|
+
code === types_1.EventTiming["After Dinner"]) {
|
|
491
|
+
hasSpecificAfter = true;
|
|
492
|
+
}
|
|
493
|
+
if (code === types_1.EventTiming["Before Breakfast"] ||
|
|
494
|
+
code === types_1.EventTiming["Before Lunch"] ||
|
|
495
|
+
code === types_1.EventTiming["Before Dinner"]) {
|
|
496
|
+
hasSpecificBefore = true;
|
|
497
|
+
}
|
|
498
|
+
if (code === types_1.EventTiming.Breakfast || code === types_1.EventTiming.Lunch || code === types_1.EventTiming.Dinner) {
|
|
499
|
+
hasSpecificWith = true;
|
|
500
|
+
}
|
|
317
501
|
}
|
|
318
502
|
}
|
|
319
|
-
const
|
|
320
|
-
|
|
321
|
-
code === types_1.EventTiming["After Dinner"]);
|
|
322
|
-
const hasSpecificBefore = unique.some((code) => code === types_1.EventTiming["Before Breakfast"] ||
|
|
323
|
-
code === types_1.EventTiming["Before Lunch"] ||
|
|
324
|
-
code === types_1.EventTiming["Before Dinner"]);
|
|
325
|
-
const hasSpecificWith = unique.some((code) => code === types_1.EventTiming.Breakfast ||
|
|
326
|
-
code === types_1.EventTiming.Lunch ||
|
|
327
|
-
code === types_1.EventTiming.Dinner);
|
|
328
|
-
return unique
|
|
329
|
-
.filter((code) => {
|
|
503
|
+
const filtered = [];
|
|
504
|
+
for (const code of unique) {
|
|
330
505
|
if (code === types_1.EventTiming["After Meal"] && hasSpecificAfter) {
|
|
331
|
-
|
|
506
|
+
continue;
|
|
332
507
|
}
|
|
333
508
|
if (code === types_1.EventTiming["Before Meal"] && hasSpecificBefore) {
|
|
334
|
-
|
|
509
|
+
continue;
|
|
335
510
|
}
|
|
336
511
|
if (code === types_1.EventTiming.Meal && hasSpecificWith) {
|
|
337
|
-
|
|
512
|
+
continue;
|
|
338
513
|
}
|
|
339
|
-
|
|
340
|
-
}
|
|
341
|
-
|
|
342
|
-
|
|
514
|
+
filtered.push(code);
|
|
515
|
+
}
|
|
516
|
+
const mealGroup = (0, timing_summary_1.getMealTimingGroup)(filtered, options);
|
|
517
|
+
if (!mealGroup) {
|
|
518
|
+
const phrases = [];
|
|
519
|
+
for (const code of filtered) {
|
|
520
|
+
const text = (_b = WHEN_TEXT[code]) !== null && _b !== void 0 ? _b : code;
|
|
521
|
+
if (text) {
|
|
522
|
+
phrases.push(text);
|
|
523
|
+
}
|
|
524
|
+
}
|
|
525
|
+
return phrases;
|
|
526
|
+
}
|
|
527
|
+
const groupedCodes = new Set(mealGroup.codes);
|
|
528
|
+
const phrases = [];
|
|
529
|
+
let insertedGroup = false;
|
|
530
|
+
for (const code of filtered) {
|
|
531
|
+
if (groupedCodes.has(code)) {
|
|
532
|
+
if (!insertedGroup) {
|
|
533
|
+
phrases.push(summarizeMealTimingGroup(mealGroup));
|
|
534
|
+
insertedGroup = true;
|
|
535
|
+
}
|
|
536
|
+
continue;
|
|
537
|
+
}
|
|
538
|
+
const text = (_c = WHEN_TEXT[code]) !== null && _c !== void 0 ? _c : code;
|
|
539
|
+
if (text) {
|
|
540
|
+
phrases.push(text);
|
|
541
|
+
}
|
|
542
|
+
}
|
|
543
|
+
return phrases;
|
|
343
544
|
}
|
|
344
545
|
function joinWithAnd(parts) {
|
|
345
546
|
if (!parts.length) {
|
|
@@ -365,21 +566,23 @@ function combineFrequencyAndEvents(frequency, events) {
|
|
|
365
566
|
}
|
|
366
567
|
if (events.length === 1 && events[0] === "at bedtime") {
|
|
367
568
|
const lowerFrequency = frequency.toLowerCase();
|
|
368
|
-
if (lowerFrequency === "twice daily" ||
|
|
569
|
+
if (lowerFrequency === "twice daily" ||
|
|
570
|
+
lowerFrequency === "three times daily" ||
|
|
571
|
+
lowerFrequency === "four times daily") {
|
|
369
572
|
return { frequency: `${frequency} and ${events[0]}` };
|
|
370
573
|
}
|
|
371
574
|
}
|
|
372
575
|
return { frequency, event: joinWithAnd(events) };
|
|
373
576
|
}
|
|
374
|
-
function buildRoutePhrase(
|
|
375
|
-
var _a;
|
|
577
|
+
function buildRoutePhrase(clause, grammar, hasSite) {
|
|
578
|
+
var _a, _b;
|
|
376
579
|
if (typeof grammar.routePhrase === "function") {
|
|
377
|
-
return grammar.routePhrase({ hasSite,
|
|
580
|
+
return grammar.routePhrase({ hasSite, clause });
|
|
378
581
|
}
|
|
379
582
|
if (typeof grammar.routePhrase === "string") {
|
|
380
583
|
return grammar.routePhrase;
|
|
381
584
|
}
|
|
382
|
-
const text = (_a =
|
|
585
|
+
const text = (_b = (_a = clause.route) === null || _a === void 0 ? void 0 : _a.text) === null || _b === void 0 ? void 0 : _b.trim();
|
|
383
586
|
if (!text) {
|
|
384
587
|
return undefined;
|
|
385
588
|
}
|
|
@@ -388,7 +591,7 @@ function buildRoutePhrase(internal, grammar, hasSite) {
|
|
|
388
591
|
return text;
|
|
389
592
|
}
|
|
390
593
|
if (normalized === "oral") {
|
|
391
|
-
return "
|
|
594
|
+
return "orally";
|
|
392
595
|
}
|
|
393
596
|
if (normalized === "intravenous") {
|
|
394
597
|
return "intravenously";
|
|
@@ -413,17 +616,34 @@ function buildRoutePhrase(internal, grammar, hasSite) {
|
|
|
413
616
|
}
|
|
414
617
|
return `via ${text}`;
|
|
415
618
|
}
|
|
416
|
-
function formatSite(
|
|
417
|
-
var _a;
|
|
418
|
-
|
|
619
|
+
function formatSite(clause, grammar) {
|
|
620
|
+
var _a, _b, _c, _d, _e, _f, _g, _h, _j, _k, _l, _m;
|
|
621
|
+
let text = (_b = (_a = clause.site) === null || _a === void 0 ? void 0 : _a.text) === null || _b === void 0 ? void 0 : _b.trim();
|
|
622
|
+
if (!text) {
|
|
623
|
+
const display = (_e = (_d = (_c = clause.site) === null || _c === void 0 ? void 0 : _c.coding) === null || _d === void 0 ? void 0 : _d.display) === null || _e === void 0 ? void 0 : _e.trim();
|
|
624
|
+
if (display) {
|
|
625
|
+
text = display.charAt(0).toLowerCase() + display.slice(1);
|
|
626
|
+
}
|
|
627
|
+
else {
|
|
628
|
+
text = (_h = (_g = (_f = clause.site) === null || _f === void 0 ? void 0 : _f.coding) === null || _g === void 0 ? void 0 : _g.code) === null || _h === void 0 ? void 0 : _h.trim();
|
|
629
|
+
}
|
|
630
|
+
}
|
|
419
631
|
if (!text) {
|
|
420
632
|
return undefined;
|
|
421
633
|
}
|
|
422
634
|
const lower = text.toLowerCase();
|
|
423
|
-
|
|
424
|
-
|
|
425
|
-
|
|
426
|
-
|
|
635
|
+
const routeText = (_k = (_j = clause.route) === null || _j === void 0 ? void 0 : _j.text) === null || _k === void 0 ? void 0 : _k.trim().toLowerCase();
|
|
636
|
+
const isRectalRoute = ((_l = clause.route) === null || _l === void 0 ? void 0 : _l.code) === types_1.RouteCode["Per rectum"] ||
|
|
637
|
+
routeText === "rectum" ||
|
|
638
|
+
routeText === "rectal";
|
|
639
|
+
const isVaginalRoute = ((_m = clause.route) === null || _m === void 0 ? void 0 : _m.code) === types_1.RouteCode["Per vagina"] ||
|
|
640
|
+
routeText === "vagina" ||
|
|
641
|
+
routeText === "vaginal";
|
|
642
|
+
if (isRectalRoute && (lower === "rectum" || lower === "rectal")) {
|
|
643
|
+
return undefined;
|
|
644
|
+
}
|
|
645
|
+
if (isVaginalRoute && (lower === "vagina" || lower === "vaginal")) {
|
|
646
|
+
return undefined;
|
|
427
647
|
}
|
|
428
648
|
let preposition = grammar.sitePreposition;
|
|
429
649
|
if (!preposition) {
|
|
@@ -439,7 +659,7 @@ function formatSite(internal, grammar) {
|
|
|
439
659
|
else if (lower.includes("ear")) {
|
|
440
660
|
preposition = "in";
|
|
441
661
|
}
|
|
442
|
-
else if (/(skin|arm|leg|thigh|abdomen|shoulder|hand|foot|cheek|forearm|back|buttock|hip|face|hair|scalp|forehead|chin|neck)/.test(lower)) {
|
|
662
|
+
else if (/(skin|head|temple|arm|leg|thigh|abdomen|shoulder|elbow|wrist|ankle|knee|hand|foot|cheek|forearm|back|chest|breast|axilla|armpit|groin|lip|buttock|hip|face|hair|scalp|forehead|eyelid|chin|neck)/.test(lower)) {
|
|
443
663
|
preposition = "to";
|
|
444
664
|
}
|
|
445
665
|
else {
|
|
@@ -452,15 +672,7 @@ function formatSite(internal, grammar) {
|
|
|
452
672
|
function formatSiteNoun(site, preposition) {
|
|
453
673
|
const trimmed = site.trim();
|
|
454
674
|
const lower = trimmed.toLowerCase();
|
|
455
|
-
const skipArticlePrefixes = [
|
|
456
|
-
"the ",
|
|
457
|
-
"both ",
|
|
458
|
-
"each ",
|
|
459
|
-
"either ",
|
|
460
|
-
"every ",
|
|
461
|
-
"all ",
|
|
462
|
-
"bilateral ",
|
|
463
|
-
];
|
|
675
|
+
const skipArticlePrefixes = ["the ", "both ", "each ", "either ", "every ", "all ", "bilateral "];
|
|
464
676
|
for (const prefix of skipArticlePrefixes) {
|
|
465
677
|
if (lower.startsWith(prefix)) {
|
|
466
678
|
return trimmed;
|
|
@@ -470,107 +682,157 @@ function formatSiteNoun(site, preposition) {
|
|
|
470
682
|
if (needsArticle || preposition === "at") {
|
|
471
683
|
return `the ${trimmed}`;
|
|
472
684
|
}
|
|
473
|
-
if (/(eye|nostril|ear|arm|leg|thigh|abdomen|hand|foot|cheek|skin|back)/.test(lower)) {
|
|
474
|
-
return `the ${trimmed}`;
|
|
475
|
-
}
|
|
476
685
|
return `the ${trimmed}`;
|
|
477
686
|
}
|
|
478
|
-
function describeDayOfWeek(
|
|
479
|
-
|
|
687
|
+
function describeDayOfWeek(schedule) {
|
|
688
|
+
var _a, _b;
|
|
689
|
+
const dayOfWeek = (_a = schedule === null || schedule === void 0 ? void 0 : schedule.dayOfWeek) !== null && _a !== void 0 ? _a : [];
|
|
690
|
+
if (!dayOfWeek.length) {
|
|
480
691
|
return undefined;
|
|
481
692
|
}
|
|
482
|
-
const days =
|
|
483
|
-
|
|
693
|
+
const days = [];
|
|
694
|
+
for (const day of dayOfWeek) {
|
|
695
|
+
days.push((_b = DAY_NAMES[day]) !== null && _b !== void 0 ? _b : day);
|
|
696
|
+
}
|
|
697
|
+
return days.length ? `on ${joinWithAnd(days)}` : undefined;
|
|
698
|
+
}
|
|
699
|
+
function formatDurationShort(schedule) {
|
|
700
|
+
if (schedule.duration === undefined || !schedule.durationUnit) {
|
|
484
701
|
return undefined;
|
|
485
702
|
}
|
|
486
|
-
|
|
703
|
+
const base = stripTrailingZero(schedule.duration);
|
|
704
|
+
const qualifier = schedule.durationMax !== undefined && schedule.durationMax !== schedule.duration
|
|
705
|
+
? `${base}-${stripTrailingZero(schedule.durationMax)}`
|
|
706
|
+
: base;
|
|
707
|
+
return `x${qualifier}${schedule.durationUnit}`;
|
|
487
708
|
}
|
|
488
|
-
function
|
|
489
|
-
|
|
490
|
-
|
|
491
|
-
long: formatLong(internal)
|
|
492
|
-
};
|
|
493
|
-
if (!localization) {
|
|
494
|
-
return defaults[style];
|
|
709
|
+
function describeDuration(schedule) {
|
|
710
|
+
if (!schedule || schedule.duration === undefined || !schedule.durationUnit) {
|
|
711
|
+
return undefined;
|
|
495
712
|
}
|
|
496
|
-
const
|
|
497
|
-
|
|
498
|
-
|
|
499
|
-
|
|
500
|
-
|
|
501
|
-
|
|
502
|
-
|
|
503
|
-
|
|
504
|
-
|
|
713
|
+
const unit = schedule.durationUnit;
|
|
714
|
+
const label = (value) => {
|
|
715
|
+
switch (unit) {
|
|
716
|
+
case types_1.FhirPeriodUnit.Minute:
|
|
717
|
+
return value === 1 ? "minute" : "minutes";
|
|
718
|
+
case types_1.FhirPeriodUnit.Hour:
|
|
719
|
+
return value === 1 ? "hour" : "hours";
|
|
720
|
+
case types_1.FhirPeriodUnit.Day:
|
|
721
|
+
return value === 1 ? "day" : "days";
|
|
722
|
+
case types_1.FhirPeriodUnit.Week:
|
|
723
|
+
return value === 1 ? "week" : "weeks";
|
|
724
|
+
case types_1.FhirPeriodUnit.Month:
|
|
725
|
+
return value === 1 ? "month" : "months";
|
|
726
|
+
case types_1.FhirPeriodUnit.Year:
|
|
727
|
+
return value === 1 ? "year" : "years";
|
|
728
|
+
default:
|
|
729
|
+
return value === 1 ? "unit" : "units";
|
|
730
|
+
}
|
|
731
|
+
};
|
|
732
|
+
if (schedule.durationMax !== undefined && schedule.durationMax !== schedule.duration) {
|
|
733
|
+
return `for ${stripTrailingZero(schedule.duration)} to ${stripTrailingZero(schedule.durationMax)} ${label(schedule.durationMax)}`;
|
|
505
734
|
}
|
|
506
|
-
|
|
507
|
-
|
|
508
|
-
|
|
509
|
-
|
|
510
|
-
|
|
511
|
-
|
|
512
|
-
|
|
513
|
-
|
|
735
|
+
return `for ${stripTrailingZero(schedule.duration)} ${label(schedule.duration)}`;
|
|
736
|
+
}
|
|
737
|
+
function shouldUseGenericMedicationObject(clause) {
|
|
738
|
+
var _a, _b;
|
|
739
|
+
const methodText = (_b = (_a = clause.method) === null || _a === void 0 ? void 0 : _a.text) === null || _b === void 0 ? void 0 : _b.trim();
|
|
740
|
+
switch (methodText) {
|
|
741
|
+
case "Apply sunscreen":
|
|
742
|
+
case "Reapply sunscreen":
|
|
743
|
+
case "Use shampoo":
|
|
744
|
+
return false;
|
|
745
|
+
default:
|
|
746
|
+
return true;
|
|
514
747
|
}
|
|
515
|
-
return defaults[style];
|
|
516
748
|
}
|
|
517
|
-
function
|
|
749
|
+
function shouldSuppressRoutePhrase(clause, grammar, verb) {
|
|
518
750
|
var _a;
|
|
751
|
+
if (((_a = clause.route) === null || _a === void 0 ? void 0 : _a.code) !== types_1.RouteCode["Oral route"]) {
|
|
752
|
+
return false;
|
|
753
|
+
}
|
|
754
|
+
if (grammar.routePhrase !== "orally") {
|
|
755
|
+
return false;
|
|
756
|
+
}
|
|
757
|
+
switch (verb) {
|
|
758
|
+
case "Drink":
|
|
759
|
+
case "Swallow":
|
|
760
|
+
return true;
|
|
761
|
+
default:
|
|
762
|
+
return false;
|
|
763
|
+
}
|
|
764
|
+
}
|
|
765
|
+
function formatShort(clause) {
|
|
766
|
+
var _a, _b, _c, _d, _e, _f;
|
|
767
|
+
const schedule = scheduleOf(clause);
|
|
519
768
|
const parts = [];
|
|
520
|
-
const dosePart = formatDoseShort(
|
|
769
|
+
const dosePart = formatDoseShort(clause.dose);
|
|
521
770
|
if (dosePart) {
|
|
522
771
|
parts.push(dosePart);
|
|
523
772
|
}
|
|
524
|
-
|
|
525
|
-
|
|
773
|
+
const routeCode = (_a = clause.route) === null || _a === void 0 ? void 0 : _a.code;
|
|
774
|
+
const routeText = (_b = clause.route) === null || _b === void 0 ? void 0 : _b.text;
|
|
775
|
+
if (routeCode) {
|
|
776
|
+
const short = ROUTE_SHORT[routeCode];
|
|
526
777
|
if (short) {
|
|
527
778
|
parts.push(short);
|
|
528
779
|
}
|
|
529
|
-
else if (
|
|
530
|
-
parts.push(
|
|
780
|
+
else if (routeText) {
|
|
781
|
+
parts.push(routeText);
|
|
531
782
|
}
|
|
532
783
|
}
|
|
533
|
-
else if (
|
|
534
|
-
parts.push(
|
|
784
|
+
else if (routeText) {
|
|
785
|
+
parts.push(routeText);
|
|
535
786
|
}
|
|
536
|
-
if (
|
|
537
|
-
parts.push(
|
|
787
|
+
if (schedule.timingCode) {
|
|
788
|
+
parts.push(schedule.timingCode);
|
|
538
789
|
}
|
|
539
|
-
else if (
|
|
540
|
-
|
|
541
|
-
|
|
542
|
-
(!
|
|
543
|
-
parts.push(`${stripTrailingZero(
|
|
790
|
+
else if (schedule.frequency !== undefined &&
|
|
791
|
+
schedule.frequencyMax !== undefined &&
|
|
792
|
+
schedule.periodUnit === types_1.FhirPeriodUnit.Day &&
|
|
793
|
+
(!schedule.period || schedule.period === 1)) {
|
|
794
|
+
parts.push(`${stripTrailingZero(schedule.frequency)}-${stripTrailingZero(schedule.frequencyMax)}x/d`);
|
|
544
795
|
}
|
|
545
|
-
else if (
|
|
546
|
-
|
|
547
|
-
(!
|
|
548
|
-
parts.push(`${stripTrailingZero(
|
|
796
|
+
else if (schedule.frequency &&
|
|
797
|
+
schedule.periodUnit === types_1.FhirPeriodUnit.Day &&
|
|
798
|
+
(!schedule.period || schedule.period === 1)) {
|
|
799
|
+
parts.push(`${stripTrailingZero(schedule.frequency)}x/d`);
|
|
549
800
|
}
|
|
550
|
-
else if (
|
|
551
|
-
const base = stripTrailingZero(
|
|
552
|
-
const qualifier =
|
|
553
|
-
? `${base}-${stripTrailingZero(
|
|
801
|
+
else if (schedule.period && schedule.periodUnit) {
|
|
802
|
+
const base = stripTrailingZero(schedule.period);
|
|
803
|
+
const qualifier = schedule.periodMax && schedule.periodMax !== schedule.period
|
|
804
|
+
? `${base}-${stripTrailingZero(schedule.periodMax)}`
|
|
554
805
|
: base;
|
|
555
|
-
parts.push(`Q${qualifier}${
|
|
806
|
+
parts.push(`Q${qualifier}${schedule.periodUnit.toUpperCase()}`);
|
|
807
|
+
}
|
|
808
|
+
if ((_c = schedule.when) === null || _c === void 0 ? void 0 : _c.length) {
|
|
809
|
+
parts.push(schedule.when.join(" "));
|
|
556
810
|
}
|
|
557
|
-
if (
|
|
558
|
-
|
|
811
|
+
if ((_d = schedule.dayOfWeek) === null || _d === void 0 ? void 0 : _d.length) {
|
|
812
|
+
const days = [];
|
|
813
|
+
for (const day of schedule.dayOfWeek) {
|
|
814
|
+
days.push(day.charAt(0).toUpperCase() + day.slice(1, 3));
|
|
815
|
+
}
|
|
816
|
+
parts.push(days.join(","));
|
|
559
817
|
}
|
|
560
|
-
if (
|
|
561
|
-
|
|
562
|
-
|
|
563
|
-
.
|
|
818
|
+
if ((_e = schedule.timeOfDay) === null || _e === void 0 ? void 0 : _e.length) {
|
|
819
|
+
const times = [];
|
|
820
|
+
for (const time of schedule.timeOfDay) {
|
|
821
|
+
times.push(time.slice(0, 5));
|
|
822
|
+
}
|
|
823
|
+
parts.push(times.join(","));
|
|
564
824
|
}
|
|
565
|
-
if (
|
|
566
|
-
parts.push(
|
|
825
|
+
if (schedule.count !== undefined) {
|
|
826
|
+
parts.push(`x${stripTrailingZero(schedule.count)}`);
|
|
567
827
|
}
|
|
568
|
-
|
|
569
|
-
|
|
828
|
+
const durationShort = formatDurationShort(schedule);
|
|
829
|
+
if (durationShort) {
|
|
830
|
+
parts.push(durationShort);
|
|
570
831
|
}
|
|
571
|
-
if (
|
|
572
|
-
|
|
573
|
-
|
|
832
|
+
if ((_f = clause.prn) === null || _f === void 0 ? void 0 : _f.enabled) {
|
|
833
|
+
const reason = (0, prn_1.getPreferredCanonicalPrnReasonText)(clause.prn.reason, clause.prn.reasons);
|
|
834
|
+
if (reason) {
|
|
835
|
+
parts.push(`PRN ${reason}`);
|
|
574
836
|
}
|
|
575
837
|
else {
|
|
576
838
|
parts.push("PRN");
|
|
@@ -578,40 +840,50 @@ function formatShort(internal) {
|
|
|
578
840
|
}
|
|
579
841
|
return parts.filter(Boolean).join(" ");
|
|
580
842
|
}
|
|
581
|
-
function formatLong(
|
|
582
|
-
var _a, _b;
|
|
583
|
-
const
|
|
584
|
-
const
|
|
585
|
-
const
|
|
586
|
-
const
|
|
587
|
-
const
|
|
588
|
-
const
|
|
589
|
-
|
|
843
|
+
function formatLong(clause, options) {
|
|
844
|
+
var _a, _b, _c, _d, _e, _f;
|
|
845
|
+
const schedule = scheduleOf(clause);
|
|
846
|
+
const grammar = resolveRouteGrammar(clause);
|
|
847
|
+
const verb = resolveMethodVerb(clause, grammar);
|
|
848
|
+
const explicitDosePart = formatDoseLong(clause.dose);
|
|
849
|
+
const dosePart = explicitDosePart !== null && explicitDosePart !== void 0 ? explicitDosePart : (shouldUseGenericMedicationObject(clause) ? "the medication" : undefined);
|
|
850
|
+
const sitePart = formatSite(clause, grammar);
|
|
851
|
+
const routePart = shouldSuppressRoutePhrase(clause, grammar, verb)
|
|
852
|
+
? undefined
|
|
853
|
+
: buildRoutePhrase(clause, grammar, Boolean(sitePart));
|
|
854
|
+
const standaloneOccurrenceCount = describeStandaloneOccurrenceCount(schedule);
|
|
855
|
+
const frequencyPart = (_b = (_a = describeFrequency(schedule)) !== null && _a !== void 0 ? _a : standaloneOccurrenceCount) !== null && _b !== void 0 ? _b : describeFrequencyCount((0, timing_summary_1.inferDailyOccurrenceCount)(schedule, options));
|
|
856
|
+
const eventParts = collectWhenPhrases(schedule, options);
|
|
857
|
+
if ((_c = schedule.timeOfDay) === null || _c === void 0 ? void 0 : _c.length) {
|
|
590
858
|
const timeStrings = [];
|
|
591
|
-
for (const time of
|
|
859
|
+
for (const time of schedule.timeOfDay) {
|
|
592
860
|
const parts = time.split(":");
|
|
593
|
-
const
|
|
594
|
-
const
|
|
595
|
-
|
|
596
|
-
|
|
597
|
-
|
|
598
|
-
|
|
599
|
-
|
|
600
|
-
|
|
861
|
+
const hours = Number(parts[0]);
|
|
862
|
+
const minutes = Number(parts[1]);
|
|
863
|
+
if (!Number.isFinite(hours) || !Number.isFinite(minutes)) {
|
|
864
|
+
continue;
|
|
865
|
+
}
|
|
866
|
+
const isAm = hours < 12;
|
|
867
|
+
const displayHours = hours % 12 || 12;
|
|
868
|
+
const displayMinutes = minutes < 10 ? `0${minutes}` : `${minutes}`;
|
|
869
|
+
timeStrings.push(`${displayHours}:${displayMinutes}${isAm ? " am" : " pm"}`);
|
|
870
|
+
}
|
|
871
|
+
if (timeStrings.length) {
|
|
601
872
|
eventParts.push(`at ${timeStrings.join(", ")}`);
|
|
602
873
|
}
|
|
603
874
|
}
|
|
604
875
|
const timing = combineFrequencyAndEvents(frequencyPart, eventParts);
|
|
605
|
-
const dayPart = describeDayOfWeek(
|
|
606
|
-
const countPart =
|
|
607
|
-
? `for ${stripTrailingZero(
|
|
876
|
+
const dayPart = describeDayOfWeek(schedule);
|
|
877
|
+
const countPart = schedule.count !== undefined && !standaloneOccurrenceCount
|
|
878
|
+
? `for ${stripTrailingZero(schedule.count)} ${schedule.count === 1 ? "dose" : "doses"}`
|
|
608
879
|
: undefined;
|
|
609
|
-
const
|
|
610
|
-
|
|
611
|
-
|
|
612
|
-
|
|
613
|
-
|
|
614
|
-
|
|
880
|
+
const durationPart = describeDuration(schedule);
|
|
881
|
+
const reason = (0, prn_1.getPreferredCanonicalPrnReasonText)((_d = clause.prn) === null || _d === void 0 ? void 0 : _d.reason, (_e = clause.prn) === null || _e === void 0 ? void 0 : _e.reasons);
|
|
882
|
+
const asNeededPart = ((_f = clause.prn) === null || _f === void 0 ? void 0 : _f.enabled) ? (reason ? `as needed for ${reason}` : "as needed") : undefined;
|
|
883
|
+
const segments = [];
|
|
884
|
+
if (dosePart) {
|
|
885
|
+
segments.push(dosePart);
|
|
886
|
+
}
|
|
615
887
|
if (routePart) {
|
|
616
888
|
segments.push(routePart);
|
|
617
889
|
}
|
|
@@ -627,6 +899,9 @@ function formatLong(internal) {
|
|
|
627
899
|
if (countPart) {
|
|
628
900
|
segments.push(countPart);
|
|
629
901
|
}
|
|
902
|
+
if (durationPart) {
|
|
903
|
+
segments.push(durationPart);
|
|
904
|
+
}
|
|
630
905
|
if (asNeededPart) {
|
|
631
906
|
segments.push(asNeededPart);
|
|
632
907
|
}
|
|
@@ -634,34 +909,121 @@ function formatLong(internal) {
|
|
|
634
909
|
segments.push(sitePart);
|
|
635
910
|
}
|
|
636
911
|
const body = segments.filter(Boolean).join(" ").replace(/\s+/g, " ").trim();
|
|
912
|
+
const instructionPhrases = [];
|
|
913
|
+
const instructionText = formatAdditionalInstructions(clause);
|
|
914
|
+
if (instructionText) {
|
|
915
|
+
instructionPhrases.push(instructionText);
|
|
916
|
+
}
|
|
917
|
+
const patientInstruction = formatPatientInstructionSentence(clause.patientInstruction);
|
|
918
|
+
if (patientInstruction) {
|
|
919
|
+
instructionPhrases.push(patientInstruction);
|
|
920
|
+
}
|
|
921
|
+
const trailingInstructionText = instructionPhrases.join(" ").trim() || undefined;
|
|
637
922
|
if (!body) {
|
|
638
|
-
|
|
639
|
-
|
|
640
|
-
return `${grammar.verb}.`;
|
|
923
|
+
if (!trailingInstructionText) {
|
|
924
|
+
return `${verb}.`;
|
|
641
925
|
}
|
|
642
|
-
return `${
|
|
926
|
+
return `${verb}. ${trailingInstructionText}`.trim();
|
|
643
927
|
}
|
|
644
|
-
const
|
|
645
|
-
|
|
646
|
-
return instructionText ? `${baseSentence} ${instructionText}` : baseSentence;
|
|
928
|
+
const baseSentence = `${verb} ${body}.`;
|
|
929
|
+
return trailingInstructionText ? `${baseSentence} ${trailingInstructionText}` : baseSentence;
|
|
647
930
|
}
|
|
648
|
-
function formatAdditionalInstructions(
|
|
649
|
-
var _a;
|
|
650
|
-
|
|
931
|
+
function formatAdditionalInstructions(clause) {
|
|
932
|
+
var _a, _b, _c, _d, _e, _f;
|
|
933
|
+
const instructions = (_a = clause.additionalInstructions) !== null && _a !== void 0 ? _a : [];
|
|
934
|
+
if (!instructions.length) {
|
|
651
935
|
return undefined;
|
|
652
936
|
}
|
|
653
|
-
const phrases =
|
|
654
|
-
|
|
655
|
-
|
|
656
|
-
|
|
657
|
-
|
|
937
|
+
const phrases = [];
|
|
938
|
+
const grammar = resolveRouteGrammar(clause);
|
|
939
|
+
const verb = resolveMethodVerb(clause, grammar);
|
|
940
|
+
for (const instruction of instructions) {
|
|
941
|
+
if (((_b = instruction.coding) === null || _b === void 0 ? void 0 : _b.code) === SLOWLY_QUALIFIER_CODE) {
|
|
942
|
+
const contextual = verb ? `${verb} slowly` : "Slowly";
|
|
943
|
+
phrases.push(contextual);
|
|
944
|
+
continue;
|
|
945
|
+
}
|
|
946
|
+
if (((_c = instruction.coding) === null || _c === void 0 ? void 0 : _c.code) === EMPTY_STOMACH_QUALIFIER_CODE ||
|
|
947
|
+
((_d = instruction.frames) === null || _d === void 0 ? void 0 : _d.some((frame) => frame.relation === types_1.AdviceRelation.On &&
|
|
948
|
+
frame.args.some((arg) => arg.role === types_1.AdviceArgumentRole.MealState &&
|
|
949
|
+
arg.conceptId === "empty_stomach")))) {
|
|
950
|
+
phrases.push("On an empty stomach");
|
|
951
|
+
continue;
|
|
952
|
+
}
|
|
953
|
+
const text = (_e = instruction.text) !== null && _e !== void 0 ? _e : (_f = instruction.coding) === null || _f === void 0 ? void 0 : _f.display;
|
|
954
|
+
if (!text) {
|
|
955
|
+
continue;
|
|
956
|
+
}
|
|
957
|
+
const trimmed = text.trim();
|
|
958
|
+
if (trimmed) {
|
|
959
|
+
phrases.push(trimmed);
|
|
960
|
+
}
|
|
961
|
+
}
|
|
658
962
|
if (!phrases.length) {
|
|
659
963
|
return undefined;
|
|
660
964
|
}
|
|
661
|
-
return phrases
|
|
662
|
-
|
|
663
|
-
|
|
664
|
-
|
|
965
|
+
return phrases.map((phrase) => (/[.!?]$/.test(phrase) ? phrase : `${phrase}.`)).join(" ").trim();
|
|
966
|
+
}
|
|
967
|
+
function firstCanonicalClause(internal) {
|
|
968
|
+
const clauses = internal.clauses;
|
|
969
|
+
if (clauses.length > 0) {
|
|
970
|
+
return clauses[0];
|
|
971
|
+
}
|
|
972
|
+
return {
|
|
973
|
+
kind: "administration",
|
|
974
|
+
rawText: internal.input,
|
|
975
|
+
raw: { start: 0, end: internal.input.length, text: internal.input },
|
|
976
|
+
leftovers: [],
|
|
977
|
+
evidence: [],
|
|
978
|
+
confidence: 0
|
|
979
|
+
};
|
|
980
|
+
}
|
|
981
|
+
function formatCanonicalClause(clause, style, localization, options) {
|
|
982
|
+
let shortDefault;
|
|
983
|
+
let longDefault;
|
|
984
|
+
const formatDefault = (target) => {
|
|
985
|
+
switch (target) {
|
|
986
|
+
case "short":
|
|
987
|
+
if (shortDefault === undefined) {
|
|
988
|
+
shortDefault = formatShort(clause);
|
|
989
|
+
}
|
|
990
|
+
return shortDefault;
|
|
991
|
+
case "long":
|
|
992
|
+
if (longDefault === undefined) {
|
|
993
|
+
longDefault = formatLong(clause, options);
|
|
994
|
+
}
|
|
995
|
+
return longDefault;
|
|
996
|
+
}
|
|
997
|
+
};
|
|
998
|
+
if (!localization) {
|
|
999
|
+
return formatDefault(style);
|
|
1000
|
+
}
|
|
1001
|
+
if (style === "short" && localization.formatShort) {
|
|
1002
|
+
const context = {
|
|
1003
|
+
style: "short",
|
|
1004
|
+
clause,
|
|
1005
|
+
defaultText: formatDefault("short"),
|
|
1006
|
+
groupMealTimingsByRelation: Boolean(options === null || options === void 0 ? void 0 : options.groupMealTimingsByRelation),
|
|
1007
|
+
includeTimesPerDaySummary: Boolean(options === null || options === void 0 ? void 0 : options.includeTimesPerDaySummary),
|
|
1008
|
+
formatDefault
|
|
1009
|
+
};
|
|
1010
|
+
return localization.formatShort(context);
|
|
1011
|
+
}
|
|
1012
|
+
if (style === "long" && localization.formatLong) {
|
|
1013
|
+
const context = {
|
|
1014
|
+
style: "long",
|
|
1015
|
+
clause,
|
|
1016
|
+
defaultText: formatDefault("long"),
|
|
1017
|
+
groupMealTimingsByRelation: Boolean(options === null || options === void 0 ? void 0 : options.groupMealTimingsByRelation),
|
|
1018
|
+
includeTimesPerDaySummary: Boolean(options === null || options === void 0 ? void 0 : options.includeTimesPerDaySummary),
|
|
1019
|
+
formatDefault
|
|
1020
|
+
};
|
|
1021
|
+
return localization.formatLong(context);
|
|
1022
|
+
}
|
|
1023
|
+
return formatDefault(style);
|
|
1024
|
+
}
|
|
1025
|
+
function formatInternal(internal, style, localization, options) {
|
|
1026
|
+
return formatCanonicalClause(firstCanonicalClause(internal), style, localization, options);
|
|
665
1027
|
}
|
|
666
1028
|
function stripTrailingZero(value) {
|
|
667
1029
|
const text = value.toString();
|