ezmedicationinput 0.1.27 → 0.1.29
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/format.js +5 -1
- package/dist/i18n.js +58 -4
- package/dist/internal-types.d.ts +9 -3
- package/dist/maps.js +53 -23
- package/dist/parser.js +43 -18
- package/dist/suggest.js +56 -2
- package/dist/types.d.ts +2 -0
- package/package.json +1 -1
package/dist/format.js
CHANGED
|
@@ -587,6 +587,7 @@ function formatLong(internal) {
|
|
|
587
587
|
const frequencyPart = describeFrequency(internal);
|
|
588
588
|
const eventParts = collectWhenPhrases(internal);
|
|
589
589
|
if ((_b = internal.timeOfDay) === null || _b === void 0 ? void 0 : _b.length) {
|
|
590
|
+
const timeStrings = [];
|
|
590
591
|
for (const time of internal.timeOfDay) {
|
|
591
592
|
const parts = time.split(":");
|
|
592
593
|
const h = parseInt(parts[0], 10);
|
|
@@ -594,7 +595,10 @@ function formatLong(internal) {
|
|
|
594
595
|
const isAm = h < 12;
|
|
595
596
|
const displayH = h % 12 || 12;
|
|
596
597
|
const displayM = m < 10 ? `0${m}` : `${m}`;
|
|
597
|
-
|
|
598
|
+
timeStrings.push(`${displayH}:${displayM}${isAm ? " am" : " pm"}`);
|
|
599
|
+
}
|
|
600
|
+
if (timeStrings.length > 0) {
|
|
601
|
+
eventParts.push(`at ${timeStrings.join(", ")}`);
|
|
598
602
|
}
|
|
599
603
|
}
|
|
600
604
|
const timing = combineFrequencyAndEvents(frequencyPart, eventParts);
|
package/dist/i18n.js
CHANGED
|
@@ -625,15 +625,18 @@ function describeDayOfWeekThai(internal) {
|
|
|
625
625
|
return `ใน${joinWithAndThai(days)}`;
|
|
626
626
|
}
|
|
627
627
|
function formatAsNeededThai(internal) {
|
|
628
|
+
var _a, _b;
|
|
628
629
|
if (!internal.asNeeded) {
|
|
629
630
|
return undefined;
|
|
630
631
|
}
|
|
631
632
|
if (internal.asNeededReason) {
|
|
632
|
-
|
|
633
|
+
const translation = (_b = (_a = internal.asNeededReasonCoding) === null || _a === void 0 ? void 0 : _a.i18n) === null || _b === void 0 ? void 0 : _b.th;
|
|
634
|
+
return `ใช้เมื่อจำเป็นสำหรับ ${translation || internal.asNeededReason}`;
|
|
633
635
|
}
|
|
634
636
|
return "ใช้เมื่อจำเป็น";
|
|
635
637
|
}
|
|
636
638
|
function formatShortThai(internal) {
|
|
639
|
+
var _a;
|
|
637
640
|
const parts = [];
|
|
638
641
|
const dose = formatDoseThaiShort(internal);
|
|
639
642
|
if (dose) {
|
|
@@ -671,6 +674,10 @@ function formatShortThai(internal) {
|
|
|
671
674
|
parts.push(events.join(" "));
|
|
672
675
|
}
|
|
673
676
|
}
|
|
677
|
+
if ((_a = internal.timeOfDay) === null || _a === void 0 ? void 0 : _a.length) {
|
|
678
|
+
const times = internal.timeOfDay.map((t) => t.slice(0, 5)).join(",");
|
|
679
|
+
parts.push(times);
|
|
680
|
+
}
|
|
674
681
|
if (internal.dayOfWeek.length) {
|
|
675
682
|
const days = internal.dayOfWeek
|
|
676
683
|
.map((d) => { var _a, _b; return (_b = (_a = DAY_NAMES_THAI[d]) === null || _a === void 0 ? void 0 : _a.replace(/^วัน/, "")) !== null && _b !== void 0 ? _b : d; })
|
|
@@ -687,13 +694,27 @@ function formatShortThai(internal) {
|
|
|
687
694
|
return parts.filter(Boolean).join(" ");
|
|
688
695
|
}
|
|
689
696
|
function formatLongThai(internal) {
|
|
690
|
-
var _a;
|
|
697
|
+
var _a, _b;
|
|
691
698
|
const grammar = resolveRouteGrammarThai(internal);
|
|
692
699
|
const dosePart = (_a = formatDoseThaiLong(internal)) !== null && _a !== void 0 ? _a : "ยา";
|
|
693
700
|
const sitePart = formatSiteThai(internal, grammar);
|
|
694
701
|
const routePart = buildRoutePhraseThai(internal, grammar, Boolean(sitePart));
|
|
695
702
|
const frequencyPart = describeFrequencyThai(internal);
|
|
696
703
|
const eventParts = collectWhenPhrasesThai(internal);
|
|
704
|
+
if ((_b = internal.timeOfDay) === null || _b === void 0 ? void 0 : _b.length) {
|
|
705
|
+
const timeStrings = [];
|
|
706
|
+
for (const time of internal.timeOfDay) {
|
|
707
|
+
const parts = time.split(":");
|
|
708
|
+
const h = parseInt(parts[0], 10);
|
|
709
|
+
const m = parseInt(parts[1], 10);
|
|
710
|
+
const displayM = m < 10 ? `0${m}` : `${m}`;
|
|
711
|
+
const displayH = h < 10 ? `0${h}` : `${h}`;
|
|
712
|
+
timeStrings.push(`${displayH}:${displayM}`);
|
|
713
|
+
}
|
|
714
|
+
if (timeStrings.length > 0) {
|
|
715
|
+
eventParts.push(`เวลา ${timeStrings.join(", ")}`);
|
|
716
|
+
}
|
|
717
|
+
}
|
|
697
718
|
const timing = combineFrequencyAndEventsThai(frequencyPart, eventParts);
|
|
698
719
|
const dayPart = describeDayOfWeekThai(internal);
|
|
699
720
|
const countPart = internal.count !== undefined
|
|
@@ -724,9 +745,42 @@ function formatLongThai(internal) {
|
|
|
724
745
|
}
|
|
725
746
|
const body = segments.filter(Boolean).join(" ").replace(/\s+/g, " ").trim();
|
|
726
747
|
if (!body) {
|
|
727
|
-
|
|
748
|
+
const instructionText = formatAdditionalInstructionsThai(internal);
|
|
749
|
+
if (!instructionText) {
|
|
750
|
+
return `${grammar.verb}.`;
|
|
751
|
+
}
|
|
752
|
+
return `${grammar.verb}. ${instructionText}`.trim();
|
|
753
|
+
}
|
|
754
|
+
const instructionText = formatAdditionalInstructionsThai(internal);
|
|
755
|
+
const baseSentence = `${grammar.verb} ${body}.`;
|
|
756
|
+
return instructionText ? `${baseSentence} ${instructionText}` : baseSentence;
|
|
757
|
+
}
|
|
758
|
+
function formatAdditionalInstructionsThai(internal) {
|
|
759
|
+
var _a;
|
|
760
|
+
if (!((_a = internal.additionalInstructions) === null || _a === void 0 ? void 0 : _a.length)) {
|
|
761
|
+
return undefined;
|
|
762
|
+
}
|
|
763
|
+
const phrases = internal.additionalInstructions
|
|
764
|
+
.map((instruction) => {
|
|
765
|
+
var _a, _b, _c;
|
|
766
|
+
const translation = (_b = (_a = instruction.coding) === null || _a === void 0 ? void 0 : _a.i18n) === null || _b === void 0 ? void 0 : _b.th;
|
|
767
|
+
if (translation)
|
|
768
|
+
return translation;
|
|
769
|
+
const original = instruction.text || ((_c = instruction.coding) === null || _c === void 0 ? void 0 : _c.display);
|
|
770
|
+
if (!original)
|
|
771
|
+
return undefined;
|
|
772
|
+
return original.trim();
|
|
773
|
+
})
|
|
774
|
+
.filter((text) => Boolean(text))
|
|
775
|
+
.map((text) => text.trim())
|
|
776
|
+
.filter((text) => text.length > 0);
|
|
777
|
+
if (!phrases.length) {
|
|
778
|
+
return undefined;
|
|
728
779
|
}
|
|
729
|
-
return
|
|
780
|
+
return phrases
|
|
781
|
+
.map((phrase) => (/[.!?]$/.test(phrase) ? phrase : `${phrase}.`))
|
|
782
|
+
.join(" ")
|
|
783
|
+
.trim();
|
|
730
784
|
}
|
|
731
785
|
function stripTrailingZero(value) {
|
|
732
786
|
const text = value.toString();
|
package/dist/internal-types.d.ts
CHANGED
|
@@ -36,12 +36,16 @@ export interface ParsedSigInternal {
|
|
|
36
36
|
timingCode?: string;
|
|
37
37
|
asNeeded?: boolean;
|
|
38
38
|
asNeededReason?: string;
|
|
39
|
-
asNeededReasonCoding?: FhirCoding
|
|
39
|
+
asNeededReasonCoding?: FhirCoding & {
|
|
40
|
+
i18n?: Record<string, string>;
|
|
41
|
+
};
|
|
40
42
|
warnings: string[];
|
|
41
43
|
siteText?: string;
|
|
42
44
|
siteSource?: "abbreviation" | "text";
|
|
43
45
|
siteTokenIndices: Set<number>;
|
|
44
|
-
siteCoding?: FhirCoding
|
|
46
|
+
siteCoding?: FhirCoding & {
|
|
47
|
+
i18n?: Record<string, string>;
|
|
48
|
+
};
|
|
45
49
|
siteLookupRequest?: SiteCodeLookupRequest;
|
|
46
50
|
siteLookups: SiteLookupDetail[];
|
|
47
51
|
customSiteHints?: Set<string>;
|
|
@@ -49,6 +53,8 @@ export interface ParsedSigInternal {
|
|
|
49
53
|
prnReasonLookups: PrnReasonLookupDetail[];
|
|
50
54
|
additionalInstructions: Array<{
|
|
51
55
|
text?: string;
|
|
52
|
-
coding?: FhirCoding
|
|
56
|
+
coding?: FhirCoding & {
|
|
57
|
+
i18n?: Record<string, string>;
|
|
58
|
+
};
|
|
53
59
|
}>;
|
|
54
60
|
}
|
package/dist/maps.js
CHANGED
|
@@ -673,6 +673,9 @@ exports.EVENT_TIMING_TOKENS = {
|
|
|
673
673
|
breakfast: types_1.EventTiming.Breakfast,
|
|
674
674
|
bfast: types_1.EventTiming.Breakfast,
|
|
675
675
|
brkfst: types_1.EventTiming.Breakfast,
|
|
676
|
+
meal: types_1.EventTiming.Meal,
|
|
677
|
+
meals: types_1.EventTiming.Meal,
|
|
678
|
+
food: types_1.EventTiming.Meal,
|
|
676
679
|
brk: types_1.EventTiming.Breakfast,
|
|
677
680
|
cd: types_1.EventTiming.Lunch,
|
|
678
681
|
lunch: types_1.EventTiming.Lunch,
|
|
@@ -717,6 +720,10 @@ registerMealKeywords(["dinner", "dinnertime", "supper", "suppertime"], {
|
|
|
717
720
|
pc: types_1.EventTiming["After Dinner"],
|
|
718
721
|
ac: types_1.EventTiming["Before Dinner"]
|
|
719
722
|
});
|
|
723
|
+
registerMealKeywords(["meal", "meals", "food"], {
|
|
724
|
+
pc: types_1.EventTiming["After Meal"],
|
|
725
|
+
ac: types_1.EventTiming["Before Meal"]
|
|
726
|
+
});
|
|
720
727
|
exports.MEAL_KEYWORDS = (0, object_1.objectFromEntries)(MEAL_KEYWORD_ENTRIES);
|
|
721
728
|
exports.DISCOURAGED_TOKENS = {
|
|
722
729
|
qd: "QD",
|
|
@@ -1281,14 +1288,16 @@ const DEFAULT_PRN_REASON_SOURCE = [
|
|
|
1281
1288
|
names: ["pain", "ache", "aches", "pains"],
|
|
1282
1289
|
definition: {
|
|
1283
1290
|
coding: { system: SNOMED_SYSTEM, code: "22253000", display: "Pain" },
|
|
1284
|
-
text: "Pain"
|
|
1291
|
+
text: "Pain",
|
|
1292
|
+
i18n: { th: "ปวด" }
|
|
1285
1293
|
}
|
|
1286
1294
|
},
|
|
1287
1295
|
{
|
|
1288
1296
|
names: ["nausea", "queasiness", "vomiting", "n/v", "nausea and vomiting"],
|
|
1289
1297
|
definition: {
|
|
1290
1298
|
coding: { system: SNOMED_SYSTEM, code: "422587007", display: "Nausea" },
|
|
1291
|
-
text: "Nausea"
|
|
1299
|
+
text: "Nausea",
|
|
1300
|
+
i18n: { th: "คลื่นไส้" }
|
|
1292
1301
|
}
|
|
1293
1302
|
},
|
|
1294
1303
|
{
|
|
@@ -1299,14 +1308,16 @@ const DEFAULT_PRN_REASON_SOURCE = [
|
|
|
1299
1308
|
code: "418363000",
|
|
1300
1309
|
display: "Itching of skin"
|
|
1301
1310
|
},
|
|
1302
|
-
text: "Itching"
|
|
1311
|
+
text: "Itching",
|
|
1312
|
+
i18n: { th: "คัน" }
|
|
1303
1313
|
}
|
|
1304
1314
|
},
|
|
1305
1315
|
{
|
|
1306
1316
|
names: ["anxiety", "nervousness"],
|
|
1307
1317
|
definition: {
|
|
1308
1318
|
coding: { system: SNOMED_SYSTEM, code: "48694002", display: "Anxiety" },
|
|
1309
|
-
text: "Anxiety"
|
|
1319
|
+
text: "Anxiety",
|
|
1320
|
+
i18n: { th: "วิตกกังวล" }
|
|
1310
1321
|
}
|
|
1311
1322
|
},
|
|
1312
1323
|
{
|
|
@@ -1317,28 +1328,32 @@ const DEFAULT_PRN_REASON_SOURCE = [
|
|
|
1317
1328
|
code: "193462001",
|
|
1318
1329
|
display: "Insomnia"
|
|
1319
1330
|
},
|
|
1320
|
-
text: "Sleep"
|
|
1331
|
+
text: "Sleep",
|
|
1332
|
+
i18n: { th: "นอนหลับ" }
|
|
1321
1333
|
}
|
|
1322
1334
|
},
|
|
1323
1335
|
{
|
|
1324
1336
|
names: ["cough", "coughing"],
|
|
1325
1337
|
definition: {
|
|
1326
1338
|
coding: { system: SNOMED_SYSTEM, code: "49727002", display: "Cough" },
|
|
1327
|
-
text: "Cough"
|
|
1339
|
+
text: "Cough",
|
|
1340
|
+
i18n: { th: "ไอ" }
|
|
1328
1341
|
}
|
|
1329
1342
|
},
|
|
1330
1343
|
{
|
|
1331
1344
|
names: ["fever", "temperature", "pyrexia"],
|
|
1332
1345
|
definition: {
|
|
1333
1346
|
coding: { system: SNOMED_SYSTEM, code: "386661006", display: "Fever" },
|
|
1334
|
-
text: "Fever"
|
|
1347
|
+
text: "Fever",
|
|
1348
|
+
i18n: { th: "ไข้" }
|
|
1335
1349
|
}
|
|
1336
1350
|
},
|
|
1337
1351
|
{
|
|
1338
1352
|
names: ["spasm", "spasms", "muscle spasm"],
|
|
1339
1353
|
definition: {
|
|
1340
1354
|
coding: { system: SNOMED_SYSTEM, code: "45352006", display: "Spasm" },
|
|
1341
|
-
text: "Spasm"
|
|
1355
|
+
text: "Spasm",
|
|
1356
|
+
i18n: { th: "ตะคริวหรือเกร็ง" }
|
|
1342
1357
|
}
|
|
1343
1358
|
},
|
|
1344
1359
|
{
|
|
@@ -1349,7 +1364,8 @@ const DEFAULT_PRN_REASON_SOURCE = [
|
|
|
1349
1364
|
code: "14760008",
|
|
1350
1365
|
display: "Constipation"
|
|
1351
1366
|
},
|
|
1352
|
-
text: "Constipation"
|
|
1367
|
+
text: "Constipation",
|
|
1368
|
+
i18n: { th: "ท้องผูก" }
|
|
1353
1369
|
}
|
|
1354
1370
|
},
|
|
1355
1371
|
{
|
|
@@ -1360,7 +1376,8 @@ const DEFAULT_PRN_REASON_SOURCE = [
|
|
|
1360
1376
|
code: "257553007",
|
|
1361
1377
|
display: "Irritation"
|
|
1362
1378
|
},
|
|
1363
|
-
text: "Irritation"
|
|
1379
|
+
text: "Irritation",
|
|
1380
|
+
i18n: { th: "ระคายเคือง" }
|
|
1364
1381
|
}
|
|
1365
1382
|
},
|
|
1366
1383
|
{
|
|
@@ -1371,7 +1388,8 @@ const DEFAULT_PRN_REASON_SOURCE = [
|
|
|
1371
1388
|
code: "267036007",
|
|
1372
1389
|
display: "Dyspnea"
|
|
1373
1390
|
},
|
|
1374
|
-
text: "Shortness of breath"
|
|
1391
|
+
text: "Shortness of breath",
|
|
1392
|
+
i18n: { th: "เหนื่อยหรือหายใจลำบาก" }
|
|
1375
1393
|
}
|
|
1376
1394
|
}
|
|
1377
1395
|
];
|
|
@@ -1412,7 +1430,8 @@ const DEFAULT_ADDITIONAL_INSTRUCTION_SOURCE = [
|
|
|
1412
1430
|
code: "311504000",
|
|
1413
1431
|
display: "With or after food"
|
|
1414
1432
|
},
|
|
1415
|
-
text: "Take with or after food"
|
|
1433
|
+
text: "Take with or after food",
|
|
1434
|
+
i18n: { th: "รับประทานพร้อมหรือหลังอาหาร" }
|
|
1416
1435
|
}
|
|
1417
1436
|
},
|
|
1418
1437
|
{
|
|
@@ -1423,7 +1442,8 @@ const DEFAULT_ADDITIONAL_INSTRUCTION_SOURCE = [
|
|
|
1423
1442
|
code: "311501008",
|
|
1424
1443
|
display: "Half to one hour before food"
|
|
1425
1444
|
},
|
|
1426
|
-
text: "Take before food"
|
|
1445
|
+
text: "Take before food",
|
|
1446
|
+
i18n: { th: "รับประทานก่อนอาหาร" }
|
|
1427
1447
|
}
|
|
1428
1448
|
},
|
|
1429
1449
|
{
|
|
@@ -1434,7 +1454,8 @@ const DEFAULT_ADDITIONAL_INSTRUCTION_SOURCE = [
|
|
|
1434
1454
|
code: "717154004",
|
|
1435
1455
|
display: "Take on an empty stomach (qualifier value)"
|
|
1436
1456
|
},
|
|
1437
|
-
text: "Take on an empty stomach"
|
|
1457
|
+
text: "Take on an empty stomach",
|
|
1458
|
+
i18n: { th: "รับประทานขณะท้องว่าง" }
|
|
1438
1459
|
}
|
|
1439
1460
|
},
|
|
1440
1461
|
{
|
|
@@ -1445,7 +1466,8 @@ const DEFAULT_ADDITIONAL_INSTRUCTION_SOURCE = [
|
|
|
1445
1466
|
code: "419303009",
|
|
1446
1467
|
display: "With plenty of water"
|
|
1447
1468
|
},
|
|
1448
|
-
text: "Take with plenty of water"
|
|
1469
|
+
text: "Take with plenty of water",
|
|
1470
|
+
i18n: { th: "รับประทานพร้อมน้ำดื่มจำนวนมาก" }
|
|
1449
1471
|
}
|
|
1450
1472
|
},
|
|
1451
1473
|
{
|
|
@@ -1456,7 +1478,8 @@ const DEFAULT_ADDITIONAL_INSTRUCTION_SOURCE = [
|
|
|
1456
1478
|
code: "417995008",
|
|
1457
1479
|
display: "Dissolve or mix with water before taking"
|
|
1458
1480
|
},
|
|
1459
|
-
text: "Dissolve or mix with water before taking"
|
|
1481
|
+
text: "Dissolve or mix with water before taking",
|
|
1482
|
+
i18n: { th: "ละลายหรือผสมน้ำก่อนรับประทาน" }
|
|
1460
1483
|
}
|
|
1461
1484
|
},
|
|
1462
1485
|
{
|
|
@@ -1467,7 +1490,8 @@ const DEFAULT_ADDITIONAL_INSTRUCTION_SOURCE = [
|
|
|
1467
1490
|
code: "419822006",
|
|
1468
1491
|
display: "Warning. Avoid alcoholic drink (qualifier value)"
|
|
1469
1492
|
},
|
|
1470
|
-
text: "Avoid alcoholic drinks"
|
|
1493
|
+
text: "Avoid alcoholic drinks",
|
|
1494
|
+
i18n: { th: "หลีกเลี่ยงเครื่องดื่มแอลกอฮอล์" }
|
|
1471
1495
|
}
|
|
1472
1496
|
},
|
|
1473
1497
|
{
|
|
@@ -1478,7 +1502,8 @@ const DEFAULT_ADDITIONAL_INSTRUCTION_SOURCE = [
|
|
|
1478
1502
|
code: "418954008",
|
|
1479
1503
|
display: "Warning. May cause drowsiness. If affected do not drive or operate machinery (qualifier value)"
|
|
1480
1504
|
},
|
|
1481
|
-
text: "May cause drowsiness; do not drive if affected"
|
|
1505
|
+
text: "May cause drowsiness; do not drive if affected",
|
|
1506
|
+
i18n: { th: "อาจทำให้ง่วงซึม; ห้ามขับขี่ยานพาหนะหรือทำงานกับเครื่องจักรหากมีอาการ" }
|
|
1482
1507
|
}
|
|
1483
1508
|
},
|
|
1484
1509
|
{
|
|
@@ -1499,7 +1524,8 @@ const DEFAULT_ADDITIONAL_INSTRUCTION_SOURCE = [
|
|
|
1499
1524
|
code: "418914006",
|
|
1500
1525
|
display: "Warning. May cause drowsiness. If affected do not drive or operate machinery. Avoid alcoholic drink (qualifier value)"
|
|
1501
1526
|
},
|
|
1502
|
-
text: "May cause drowsiness; avoid driving or alcohol"
|
|
1527
|
+
text: "May cause drowsiness; avoid driving or alcohol",
|
|
1528
|
+
i18n: { th: "อาจทำให้ง่วงซึม; หลีกเลี่ยงการขับขี่ยานพาหนะหรือดื่มแอลกอฮอล์" }
|
|
1503
1529
|
}
|
|
1504
1530
|
},
|
|
1505
1531
|
{
|
|
@@ -1516,7 +1542,8 @@ const DEFAULT_ADDITIONAL_INSTRUCTION_SOURCE = [
|
|
|
1516
1542
|
code: "418071006",
|
|
1517
1543
|
display: "Warning. Causes drowsiness which may continue the next day. If affected do not drive or operate machinery. Avoid alcoholic drink (qualifier value)"
|
|
1518
1544
|
},
|
|
1519
|
-
text: "May cause next-day drowsiness; avoid driving or alcohol"
|
|
1545
|
+
text: "May cause next-day drowsiness; avoid driving or alcohol",
|
|
1546
|
+
i18n: { th: "อาจทำให้ง่วงซึมในวันถัดมา; หลีกเลี่ยงการขับขี่ยานพาหนะหรือดื่มแอลกอฮอล์" }
|
|
1520
1547
|
}
|
|
1521
1548
|
},
|
|
1522
1549
|
{
|
|
@@ -1527,7 +1554,8 @@ const DEFAULT_ADDITIONAL_INSTRUCTION_SOURCE = [
|
|
|
1527
1554
|
code: "418521000",
|
|
1528
1555
|
display: "Avoid exposure of skin to direct sunlight or sun lamps (qualifier value)"
|
|
1529
1556
|
},
|
|
1530
|
-
text: "Avoid sunlight or sun lamps"
|
|
1557
|
+
text: "Avoid sunlight or sun lamps",
|
|
1558
|
+
i18n: { th: "หลีกเลี่ยงแสงแดดหรือหลอดไฟแสงยูวี" }
|
|
1531
1559
|
}
|
|
1532
1560
|
},
|
|
1533
1561
|
{
|
|
@@ -1538,7 +1566,8 @@ const DEFAULT_ADDITIONAL_INSTRUCTION_SOURCE = [
|
|
|
1538
1566
|
code: "418693002",
|
|
1539
1567
|
display: "Swallowed whole, not chewed (qualifier value)"
|
|
1540
1568
|
},
|
|
1541
|
-
text: "Swallow whole; do not crush or chew"
|
|
1569
|
+
text: "Swallow whole; do not crush or chew",
|
|
1570
|
+
i18n: { th: "กลืนทั้งเม็ด; ห้ามเคี้ยวหรือบด" }
|
|
1542
1571
|
}
|
|
1543
1572
|
},
|
|
1544
1573
|
{
|
|
@@ -1549,7 +1578,8 @@ const DEFAULT_ADDITIONAL_INSTRUCTION_SOURCE = [
|
|
|
1549
1578
|
code: "418991002",
|
|
1550
1579
|
display: "Sucked or chewed (qualifier value)"
|
|
1551
1580
|
},
|
|
1552
|
-
text: "Suck or chew before swallowing"
|
|
1581
|
+
text: "Suck or chew before swallowing",
|
|
1582
|
+
i18n: { th: "เคี้ยวหรืออมให้ละลายก่อนกลืน" }
|
|
1553
1583
|
}
|
|
1554
1584
|
}
|
|
1555
1585
|
];
|
package/dist/parser.js
CHANGED
|
@@ -781,15 +781,40 @@ function tryParseTimeBasedSchedule(internal, tokens, index) {
|
|
|
781
781
|
const token = tokens[index];
|
|
782
782
|
if (internal.consumed.has(token.index))
|
|
783
783
|
return false;
|
|
784
|
-
|
|
785
|
-
|
|
784
|
+
// Handle connectors like "and at" or just "and" before a time.
|
|
785
|
+
// This prevents rogue "and" from leaking into Additional Instructions
|
|
786
|
+
// when it serves as a connector between schedule parts.
|
|
787
|
+
let isAndPrefix = false;
|
|
788
|
+
let isAtPrefix = token.lower === "@" || token.lower === "at";
|
|
789
|
+
if (token.lower === "and" && !isAtPrefix) {
|
|
790
|
+
const next = tokens[index + 1];
|
|
791
|
+
if (next && !internal.consumed.has(next.index)) {
|
|
792
|
+
const nextLower = next.lower;
|
|
793
|
+
// If "and" is followed by "at", "@", or a number, it's a connector for this time block
|
|
794
|
+
if (nextLower === "@" || nextLower === "at" || /^\d/.test(nextLower)) {
|
|
795
|
+
isAndPrefix = true;
|
|
796
|
+
if (nextLower === "@" || nextLower === "at") {
|
|
797
|
+
isAtPrefix = true;
|
|
798
|
+
}
|
|
799
|
+
}
|
|
800
|
+
}
|
|
801
|
+
}
|
|
802
|
+
if (!isAtPrefix && !isAndPrefix && !/^\d/.test(token.lower))
|
|
786
803
|
return false;
|
|
787
|
-
let nextIndex =
|
|
804
|
+
let nextIndex = index;
|
|
805
|
+
if (isAndPrefix)
|
|
806
|
+
nextIndex++;
|
|
807
|
+
if (isAtPrefix)
|
|
808
|
+
nextIndex++;
|
|
788
809
|
const times = [];
|
|
789
810
|
const consumedIndices = [];
|
|
790
811
|
const timeTokens = [];
|
|
791
|
-
if (
|
|
812
|
+
if (isAndPrefix)
|
|
792
813
|
consumedIndices.push(index);
|
|
814
|
+
if (isAtPrefix) {
|
|
815
|
+
// If we have "and at", at is the second token (index + 1)
|
|
816
|
+
consumedIndices.push(isAndPrefix ? index + 1 : index);
|
|
817
|
+
}
|
|
793
818
|
while (nextIndex < tokens.length) {
|
|
794
819
|
const nextToken = tokens[nextIndex];
|
|
795
820
|
if (!nextToken || internal.consumed.has(nextToken.index))
|
|
@@ -1918,15 +1943,19 @@ function parseInternal(input, options) {
|
|
|
1918
1943
|
: types_1.EventTiming["Before Meal"]);
|
|
1919
1944
|
continue;
|
|
1920
1945
|
}
|
|
1921
|
-
if (token.lower === "at" || token.lower === "@" || token.lower === "on") {
|
|
1946
|
+
if (token.lower === "at" || token.lower === "@" || token.lower === "on" || token.lower === "with") {
|
|
1922
1947
|
if (parseAnchorSequence(internal, tokens, i)) {
|
|
1923
1948
|
continue;
|
|
1924
1949
|
}
|
|
1925
1950
|
if (tryParseTimeBasedSchedule(internal, tokens, i)) {
|
|
1926
1951
|
continue;
|
|
1927
1952
|
}
|
|
1928
|
-
|
|
1929
|
-
|
|
1953
|
+
// If none of the above consume it, and it's a known anchor prefix, mark it
|
|
1954
|
+
// but only if it's not "with" which might be part of other phrases later.
|
|
1955
|
+
if (token.lower !== "with") {
|
|
1956
|
+
mark(internal.consumed, token);
|
|
1957
|
+
continue;
|
|
1958
|
+
}
|
|
1930
1959
|
}
|
|
1931
1960
|
const nextToken = tokens[i + 1];
|
|
1932
1961
|
if (nextToken && !internal.consumed.has(nextToken.index)) {
|
|
@@ -1938,12 +1967,6 @@ function parseInternal(input, options) {
|
|
|
1938
1967
|
mark(internal.consumed, nextToken);
|
|
1939
1968
|
continue;
|
|
1940
1969
|
}
|
|
1941
|
-
// Issue 2: Support "with meal" and "with food" combos explicitly if needed
|
|
1942
|
-
if (token.lower === "with" && (lowerNext === "meal" || lowerNext === "food")) {
|
|
1943
|
-
applyWhenToken(internal, token, types_1.EventTiming.Meal);
|
|
1944
|
-
mark(internal.consumed, nextToken);
|
|
1945
|
-
continue;
|
|
1946
|
-
}
|
|
1947
1970
|
}
|
|
1948
1971
|
const customWhen = (_g = options === null || options === void 0 ? void 0 : options.whenMap) === null || _g === void 0 ? void 0 : _g[token.lower];
|
|
1949
1972
|
if (customWhen) {
|
|
@@ -2813,12 +2836,12 @@ function findAdditionalInstructionDefinition(text, canonical) {
|
|
|
2813
2836
|
if (!entry.canonical) {
|
|
2814
2837
|
continue;
|
|
2815
2838
|
}
|
|
2839
|
+
// Check for exact canonical match first
|
|
2816
2840
|
if (entry.canonical === canonical) {
|
|
2817
2841
|
return entry.definition;
|
|
2818
2842
|
}
|
|
2819
|
-
|
|
2820
|
-
|
|
2821
|
-
}
|
|
2843
|
+
// Avoid broad includes checks (like "with" matching "with meal")
|
|
2844
|
+
// to prevent leakage of common connectors into additional instructions.
|
|
2822
2845
|
for (const term of entry.terms) {
|
|
2823
2846
|
const normalizedTerm = (0, maps_1.normalizeAdditionalInstructionKey)(term);
|
|
2824
2847
|
if (!normalizedTerm) {
|
|
@@ -3145,7 +3168,8 @@ function collectAdditionalInstructions(internal, tokens) {
|
|
|
3145
3168
|
? {
|
|
3146
3169
|
code: definition.coding.code,
|
|
3147
3170
|
display: definition.coding.display,
|
|
3148
|
-
system: (_f = definition.coding.system) !== null && _f !== void 0 ? _f : SNOMED_SYSTEM
|
|
3171
|
+
system: (_f = definition.coding.system) !== null && _f !== void 0 ? _f : SNOMED_SYSTEM,
|
|
3172
|
+
i18n: definition.i18n
|
|
3149
3173
|
}
|
|
3150
3174
|
: undefined
|
|
3151
3175
|
});
|
|
@@ -3375,7 +3399,8 @@ function applyPrnReasonDefinition(internal, definition) {
|
|
|
3375
3399
|
? {
|
|
3376
3400
|
code: coding.code,
|
|
3377
3401
|
display: coding.display,
|
|
3378
|
-
system: (_a = coding.system) !== null && _a !== void 0 ? _a : SNOMED_SYSTEM
|
|
3402
|
+
system: (_a = coding.system) !== null && _a !== void 0 ? _a : SNOMED_SYSTEM,
|
|
3403
|
+
i18n: definition.i18n
|
|
3379
3404
|
}
|
|
3380
3405
|
: undefined;
|
|
3381
3406
|
if (definition.text && !internal.asNeededReason) {
|
package/dist/suggest.js
CHANGED
|
@@ -347,6 +347,43 @@ function canonicalizeLowercaseForMatching(value) {
|
|
|
347
347
|
function canonicalizeForMatching(value) {
|
|
348
348
|
return canonicalizeLowercaseForMatching(value.toLowerCase());
|
|
349
349
|
}
|
|
350
|
+
function buildTimeTokens(input) {
|
|
351
|
+
const tokens = new Set();
|
|
352
|
+
// Add common times
|
|
353
|
+
for (let i = 1; i <= 12; i++) {
|
|
354
|
+
tokens.add(`at ${i}:00 am`);
|
|
355
|
+
tokens.add(`at ${i}:00 pm`);
|
|
356
|
+
}
|
|
357
|
+
// Analyze input for specific time requests to provide more granular suggestions
|
|
358
|
+
const match = input.match(/(?:at|@)\s*(\d{1,2})(?::(\d{0,2}))?/i);
|
|
359
|
+
if (match) {
|
|
360
|
+
const h = parseInt(match[1], 10);
|
|
361
|
+
if (h >= 1 && h <= 12) {
|
|
362
|
+
const m = match[2] || "00";
|
|
363
|
+
if (m.length === 1) {
|
|
364
|
+
tokens.add(`at ${h}:${m}0 am`);
|
|
365
|
+
tokens.add(`at ${h}:${m}0 pm`);
|
|
366
|
+
}
|
|
367
|
+
else {
|
|
368
|
+
tokens.add(`at ${h}:${m} am`);
|
|
369
|
+
tokens.add(`at ${h}:${m} pm`);
|
|
370
|
+
}
|
|
371
|
+
}
|
|
372
|
+
else if (h > 12 && h < 24) {
|
|
373
|
+
// Input seems to be 24h, but we format as am/pm usually.
|
|
374
|
+
// Let's add the 24h format as well if that's what they are typing?
|
|
375
|
+
// Or convert to am/pm? Let's add both for robustness.
|
|
376
|
+
const m = match[2] || "00";
|
|
377
|
+
if (m.length === 1) {
|
|
378
|
+
tokens.add(`at ${h}:${m}0`);
|
|
379
|
+
}
|
|
380
|
+
else {
|
|
381
|
+
tokens.add(`at ${h}:${m}`);
|
|
382
|
+
}
|
|
383
|
+
}
|
|
384
|
+
}
|
|
385
|
+
return [...tokens];
|
|
386
|
+
}
|
|
350
387
|
function tokensMatch(prefixTokens, candidateTokens) {
|
|
351
388
|
if (prefixTokens.length === 0) {
|
|
352
389
|
return true;
|
|
@@ -461,7 +498,7 @@ function getCandidateFingerprint(candidateLower) {
|
|
|
461
498
|
}
|
|
462
499
|
return fingerprint;
|
|
463
500
|
}
|
|
464
|
-
function generateCandidateDirections(pairs, doseValues, prnReasons, intervalTokens, whenSequences, limit, matcher) {
|
|
501
|
+
function generateCandidateDirections(pairs, doseValues, prnReasons, intervalTokens, timeTokens, whenSequences, limit, matcher) {
|
|
465
502
|
const suggestions = [];
|
|
466
503
|
const seen = new Set();
|
|
467
504
|
const doseVariantMap = new Map();
|
|
@@ -502,6 +539,7 @@ function generateCandidateDirections(pairs, doseValues, prnReasons, intervalToke
|
|
|
502
539
|
const whenSuffixes = whenSequences === PRECOMPUTED_WHEN_SEQUENCES
|
|
503
540
|
? PRECOMPUTED_WHEN_SEQUENCE_SUFFIXES
|
|
504
541
|
: whenSequences.map((sequence) => ` ${sequence.join(" ")}`);
|
|
542
|
+
const timeSuffixes = timeTokens.map((token) => ` ${token}`);
|
|
505
543
|
for (let pairIndex = 0; pairIndex < pairs.length; pairIndex += 1) {
|
|
506
544
|
const pair = pairs[pairIndex];
|
|
507
545
|
const unitVariants = getUnitVariants(pair.unit);
|
|
@@ -593,6 +631,21 @@ function generateCandidateDirections(pairs, doseValues, prnReasons, intervalToke
|
|
|
593
631
|
return suggestions;
|
|
594
632
|
}
|
|
595
633
|
}
|
|
634
|
+
for (let timeIndex = 0; timeIndex < timeSuffixes.length; timeIndex += 1) {
|
|
635
|
+
const timeSuffix = timeSuffixes[timeIndex];
|
|
636
|
+
for (let unitIndex = 0; unitIndex < unitDoseVariants.length; unitIndex += 1) {
|
|
637
|
+
const doseBases = unitDoseVariants[unitIndex];
|
|
638
|
+
for (let doseIndex = 0; doseIndex < doseBases.length; doseIndex += 1) {
|
|
639
|
+
const base = doseBases[doseIndex];
|
|
640
|
+
if (push(base.value + timeSuffix, base.lower + timeSuffix)) {
|
|
641
|
+
return suggestions;
|
|
642
|
+
}
|
|
643
|
+
}
|
|
644
|
+
}
|
|
645
|
+
if (push(route + timeSuffix, routeLower + timeSuffix)) {
|
|
646
|
+
return suggestions;
|
|
647
|
+
}
|
|
648
|
+
}
|
|
596
649
|
for (let reasonIndex = 0; reasonIndex < prnSuffixes.length; reasonIndex += 1) {
|
|
597
650
|
const reasonSuffix = prnSuffixes[reasonIndex];
|
|
598
651
|
for (let unitIndex = 0; unitIndex < unitDoseVariants.length; unitIndex += 1) {
|
|
@@ -712,7 +765,8 @@ function suggestSig(input, options) {
|
|
|
712
765
|
const doseValues = buildDoseValues(input);
|
|
713
766
|
const prnReasons = buildPrnReasons(options === null || options === void 0 ? void 0 : options.prnReasons);
|
|
714
767
|
const intervalTokens = buildIntervalTokens(input);
|
|
768
|
+
const timeTokens = buildTimeTokens(input);
|
|
715
769
|
const whenSequences = PRECOMPUTED_WHEN_SEQUENCES;
|
|
716
770
|
const matcher = (candidate, candidateLower) => matchesPrefix(candidate, candidateLower, prefixContext);
|
|
717
|
-
return generateCandidateDirections(pairs, doseValues, prnReasons, intervalTokens, whenSequences, limit, matcher);
|
|
771
|
+
return generateCandidateDirections(pairs, doseValues, prnReasons, intervalTokens, timeTokens, whenSequences, limit, matcher);
|
|
718
772
|
}
|
package/dist/types.d.ts
CHANGED
|
@@ -316,6 +316,8 @@ export interface CodeableConceptDefinition {
|
|
|
316
316
|
coding?: FhirCoding;
|
|
317
317
|
text?: string;
|
|
318
318
|
aliases?: string[];
|
|
319
|
+
/** Optional translations for different locales (e.g., { "th": "ปวด" }) */
|
|
320
|
+
i18n?: Record<string, string>;
|
|
319
321
|
}
|
|
320
322
|
export interface PrnReasonDefinition extends CodeableConceptDefinition {
|
|
321
323
|
}
|