ezmedicationinput 0.1.50 → 0.1.53

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.js CHANGED
@@ -38,60 +38,6 @@ var __async = (__this, __arguments, generator) => {
38
38
  });
39
39
  };
40
40
 
41
- // src/prn.ts
42
- function getCanonicalPrnReasonText(reason) {
43
- var _a2, _b;
44
- return (_b = reason == null ? void 0 : reason.text) != null ? _b : (_a2 = reason == null ? void 0 : reason.coding) == null ? void 0 : _a2.display;
45
- }
46
- function joinCanonicalPrnReasonTexts(reasons, conjunction = "or") {
47
- var _a2;
48
- if (!(reasons == null ? void 0 : reasons.length)) {
49
- return void 0;
50
- }
51
- const texts = [];
52
- for (const reason of reasons) {
53
- const text = (_a2 = getCanonicalPrnReasonText(reason)) == null ? void 0 : _a2.trim();
54
- if (!text) {
55
- continue;
56
- }
57
- texts.push(text);
58
- }
59
- switch (texts.length) {
60
- case 0:
61
- return void 0;
62
- case 1:
63
- return texts[0];
64
- case 2:
65
- return `${texts[0]} ${conjunction} ${texts[1]}`;
66
- default: {
67
- let combined = "";
68
- for (let index = 0; index < texts.length; index += 1) {
69
- if (index === 0) {
70
- combined = texts[index];
71
- continue;
72
- }
73
- if (index === texts.length - 1) {
74
- combined += ` ${conjunction} ${texts[index]}`;
75
- continue;
76
- }
77
- combined += `, ${texts[index]}`;
78
- }
79
- return combined;
80
- }
81
- }
82
- }
83
- function getPreferredCanonicalPrnReasonText(reason, reasons, conjunction = "or") {
84
- var _a2;
85
- const direct = (_a2 = getCanonicalPrnReasonText(reason)) == null ? void 0 : _a2.trim();
86
- if (!(reasons == null ? void 0 : reasons.length)) {
87
- return direct;
88
- }
89
- if (!direct) {
90
- return joinCanonicalPrnReasonTexts(reasons, conjunction);
91
- }
92
- return /[,/;]/.test(direct) || /\b(?:or|and|and\/or)\b/i.test(direct) || /\s(?:หรือ|และ)\s/.test(direct) ? joinCanonicalPrnReasonTexts(reasons, conjunction) : direct;
93
- }
94
-
95
41
  // src/types.ts
96
42
  var EventTiming = /* @__PURE__ */ ((EventTiming4) => {
97
43
  EventTiming4["Before Sleep"] = "HS";
@@ -359,6 +305,328 @@ var AdviceArgumentRole = /* @__PURE__ */ ((AdviceArgumentRole2) => {
359
305
  return AdviceArgumentRole2;
360
306
  })(AdviceArgumentRole || {});
361
307
 
308
+ // src/timing-summary.ts
309
+ var MEAL_TIMING_DETAILS = {
310
+ ["ACM" /* Before Breakfast */]: { relation: "before", meal: "breakfast" },
311
+ ["ACD" /* Before Lunch */]: { relation: "before", meal: "lunch" },
312
+ ["ACV" /* Before Dinner */]: { relation: "before", meal: "dinner" },
313
+ ["PCM" /* After Breakfast */]: { relation: "after", meal: "breakfast" },
314
+ ["PCD" /* After Lunch */]: { relation: "after", meal: "lunch" },
315
+ ["PCV" /* After Dinner */]: { relation: "after", meal: "dinner" },
316
+ ["CM" /* Breakfast */]: { relation: "with", meal: "breakfast" },
317
+ ["CD" /* Lunch */]: { relation: "with", meal: "lunch" },
318
+ ["CV" /* Dinner */]: { relation: "with", meal: "dinner" }
319
+ };
320
+ var MEAL_ORDER = {
321
+ breakfast: 0,
322
+ lunch: 1,
323
+ dinner: 2
324
+ };
325
+ var INFERABLE_DAILY_EVENT_TIMINGS = /* @__PURE__ */ new Set([
326
+ "HS" /* Before Sleep */,
327
+ "ACM" /* Before Breakfast */,
328
+ "ACD" /* Before Lunch */,
329
+ "ACV" /* Before Dinner */,
330
+ "PCM" /* After Breakfast */,
331
+ "PCD" /* After Lunch */,
332
+ "PCV" /* After Dinner */,
333
+ "CM" /* Breakfast */,
334
+ "CD" /* Lunch */,
335
+ "CV" /* Dinner */,
336
+ "MORN" /* Morning */,
337
+ "MORN.early" /* Early Morning */,
338
+ "MORN.late" /* Late Morning */,
339
+ "NOON" /* Noon */,
340
+ "AFT" /* Afternoon */,
341
+ "AFT.early" /* Early Afternoon */,
342
+ "AFT.late" /* Late Afternoon */,
343
+ "EVE" /* Evening */,
344
+ "EVE.early" /* Early Evening */,
345
+ "EVE.late" /* Late Evening */,
346
+ "NIGHT" /* Night */,
347
+ "WAKE" /* Wake */,
348
+ "PHS" /* After Sleep */
349
+ ]);
350
+ function uniqueValues(values) {
351
+ const seen = /* @__PURE__ */ new Set();
352
+ const result = [];
353
+ for (const value of values) {
354
+ if (!seen.has(value)) {
355
+ seen.add(value);
356
+ result.push(value);
357
+ }
358
+ }
359
+ return result;
360
+ }
361
+ function getMealTimingGroup(when, options) {
362
+ if (!(options == null ? void 0 : options.groupMealTimingsByRelation)) {
363
+ return void 0;
364
+ }
365
+ const uniqueWhen2 = uniqueValues(when);
366
+ if (uniqueWhen2.length < 2) {
367
+ return void 0;
368
+ }
369
+ let relation;
370
+ const meals = [];
371
+ const groupedCodes = [];
372
+ let sawFirstMeal = false;
373
+ for (let i = 0; i < uniqueWhen2.length; i += 1) {
374
+ const code = uniqueWhen2[i];
375
+ const detail = MEAL_TIMING_DETAILS[code];
376
+ if (!detail) {
377
+ if (sawFirstMeal) {
378
+ break;
379
+ }
380
+ continue;
381
+ }
382
+ if (!sawFirstMeal) {
383
+ sawFirstMeal = true;
384
+ }
385
+ if (!relation) {
386
+ relation = detail.relation;
387
+ } else if (relation !== detail.relation && detail.relation !== "with") {
388
+ break;
389
+ }
390
+ meals.push(detail.meal);
391
+ groupedCodes.push(code);
392
+ }
393
+ if (groupedCodes.length < 2) {
394
+ return void 0;
395
+ }
396
+ for (let i = 1; i < meals.length; i += 1) {
397
+ const current = meals[i];
398
+ let j = i - 1;
399
+ while (j >= 0 && MEAL_ORDER[meals[j]] > MEAL_ORDER[current]) {
400
+ meals[j + 1] = meals[j];
401
+ j -= 1;
402
+ }
403
+ meals[j + 1] = current;
404
+ }
405
+ if (!relation) {
406
+ return void 0;
407
+ }
408
+ return {
409
+ relation,
410
+ meals,
411
+ codes: groupedCodes
412
+ };
413
+ }
414
+ function inferDailyOccurrenceCount(input, options) {
415
+ var _a2, _b, _c, _d;
416
+ if (!(options == null ? void 0 : options.includeTimesPerDaySummary)) {
417
+ return void 0;
418
+ }
419
+ if (input.frequency !== void 0 || input.frequencyMax !== void 0 || input.timingCode) {
420
+ return void 0;
421
+ }
422
+ if (input.period !== void 0 || input.periodMax !== void 0 || input.periodUnit !== void 0) {
423
+ return void 0;
424
+ }
425
+ if (((_b = (_a2 = input.dayOfWeek) == null ? void 0 : _a2.length) != null ? _b : 0) > 0) {
426
+ return void 0;
427
+ }
428
+ const uniqueWhen2 = uniqueValues((_c = input.when) != null ? _c : []);
429
+ for (let i = 0; i < uniqueWhen2.length; i += 1) {
430
+ if (!INFERABLE_DAILY_EVENT_TIMINGS.has(uniqueWhen2[i])) {
431
+ return void 0;
432
+ }
433
+ }
434
+ const uniqueTimes = uniqueValues((_d = input.timeOfDay) != null ? _d : []);
435
+ const occurrences = uniqueWhen2.length + uniqueTimes.length;
436
+ if (occurrences === 0) {
437
+ return void 0;
438
+ }
439
+ return occurrences;
440
+ }
441
+
442
+ // src/localized-timing.ts
443
+ function uniqueWhenEvents(schedule) {
444
+ var _a2;
445
+ const when = (_a2 = schedule == null ? void 0 : schedule.when) != null ? _a2 : [];
446
+ if (!when.length) {
447
+ return [];
448
+ }
449
+ const unique = [];
450
+ const seen = /* @__PURE__ */ new Set();
451
+ for (const code of when) {
452
+ if (!seen.has(code)) {
453
+ seen.add(code);
454
+ unique.push(code);
455
+ }
456
+ }
457
+ return unique;
458
+ }
459
+ function filterLocalizedWhenEvents(schedule) {
460
+ const unique = uniqueWhenEvents(schedule);
461
+ const specificAfter = /* @__PURE__ */ new Set();
462
+ const specificBefore = /* @__PURE__ */ new Set();
463
+ const specificWith = /* @__PURE__ */ new Set();
464
+ for (const code of unique) {
465
+ if (code === "PCM" /* After Breakfast */ || code === "PCD" /* After Lunch */ || code === "PCV" /* After Dinner */) {
466
+ specificAfter.add(code);
467
+ }
468
+ if (code === "ACM" /* Before Breakfast */ || code === "ACD" /* Before Lunch */ || code === "ACV" /* Before Dinner */) {
469
+ specificBefore.add(code);
470
+ }
471
+ if (code === "CM" /* Breakfast */ || code === "CD" /* Lunch */ || code === "CV" /* Dinner */) {
472
+ specificWith.add(code);
473
+ }
474
+ }
475
+ const hasAllAfter = specificAfter.has("PCM" /* After Breakfast */) && specificAfter.has("PCD" /* After Lunch */) && specificAfter.has("PCV" /* After Dinner */);
476
+ const hasAllBefore = specificBefore.has("ACM" /* Before Breakfast */) && specificBefore.has("ACD" /* Before Lunch */) && specificBefore.has("ACV" /* Before Dinner */);
477
+ const hasAllWith = specificWith.has("CM" /* Breakfast */) && specificWith.has("CD" /* Lunch */) && specificWith.has("CV" /* Dinner */);
478
+ const filtered = [];
479
+ for (const code of unique) {
480
+ if (code === "PC" /* After Meal */ && hasAllAfter) {
481
+ continue;
482
+ }
483
+ if (code === "AC" /* Before Meal */ && hasAllBefore) {
484
+ continue;
485
+ }
486
+ if (code === "C" /* Meal */ && hasAllWith) {
487
+ continue;
488
+ }
489
+ filtered.push(code);
490
+ }
491
+ return filtered;
492
+ }
493
+ function collectLocalizedWhenPhrases(schedule, grammar, options) {
494
+ const filtered = filterLocalizedWhenEvents(schedule);
495
+ if (!filtered.length) {
496
+ return [];
497
+ }
498
+ const mealGroup = getMealTimingGroup(filtered, options);
499
+ if (!mealGroup) {
500
+ const phrases2 = [];
501
+ for (const code of filtered) {
502
+ const text = grammar.whenText[code];
503
+ if (text) {
504
+ phrases2.push(text);
505
+ }
506
+ }
507
+ return phrases2;
508
+ }
509
+ const groupedCodes = new Set(mealGroup.codes);
510
+ const phrases = [];
511
+ let insertedGroup = false;
512
+ for (const code of filtered) {
513
+ if (groupedCodes.has(code)) {
514
+ if (!insertedGroup) {
515
+ phrases.push(grammar.summarizeMealTimingGroup(mealGroup));
516
+ insertedGroup = true;
517
+ }
518
+ continue;
519
+ }
520
+ const text = grammar.whenText[code];
521
+ if (text) {
522
+ phrases.push(text);
523
+ }
524
+ }
525
+ return phrases;
526
+ }
527
+ function inferExplicitDailyFrequency(schedule) {
528
+ var _a2;
529
+ if (!schedule) {
530
+ return void 0;
531
+ }
532
+ if (schedule.frequency !== void 0 && schedule.frequencyMax === void 0 && schedule.periodUnit === "d" /* Day */ && (schedule.period === void 0 || schedule.period === 1) && schedule.periodMax === void 0) {
533
+ return schedule.frequency;
534
+ }
535
+ switch ((_a2 = schedule.timingCode) == null ? void 0 : _a2.toUpperCase()) {
536
+ case "QD":
537
+ return 1;
538
+ case "BID":
539
+ return 2;
540
+ case "TID":
541
+ return 3;
542
+ case "QID":
543
+ return 4;
544
+ default:
545
+ return void 0;
546
+ }
547
+ }
548
+ function isBedtimeOnlyWhen(schedule) {
549
+ const filtered = filterLocalizedWhenEvents(schedule);
550
+ return filtered.length === 1 && filtered[0] === "HS" /* Before Sleep */;
551
+ }
552
+ function combineLocalizedFrequencyAndEvents(schedule, frequency, events, grammar, options) {
553
+ var _a2, _b, _c;
554
+ if (!frequency) {
555
+ if (!events.length) {
556
+ return {};
557
+ }
558
+ return { event: grammar.joinList(events) };
559
+ }
560
+ if (!events.length) {
561
+ return { frequency };
562
+ }
563
+ if (events.length === 1 && isBedtimeOnlyWhen(schedule)) {
564
+ const dailyCount = (_a2 = inferExplicitDailyFrequency(schedule)) != null ? _a2 : inferDailyOccurrenceCount(schedule != null ? schedule : {}, options);
565
+ const style = (_c = (_b = grammar.bedtimeJoinStyle) == null ? void 0 : _b.call(grammar, dailyCount)) != null ? _c : "separate";
566
+ if (style === "adjacent") {
567
+ return { frequency: `${frequency} ${events[0]}` };
568
+ }
569
+ if (style === "conjunction") {
570
+ return { frequency: grammar.joinList([frequency, events[0]]) };
571
+ }
572
+ }
573
+ return { frequency, event: grammar.joinList(events) };
574
+ }
575
+
576
+ // src/prn.ts
577
+ function getCanonicalPrnReasonText(reason) {
578
+ var _a2, _b;
579
+ return (_b = reason == null ? void 0 : reason.text) != null ? _b : (_a2 = reason == null ? void 0 : reason.coding) == null ? void 0 : _a2.display;
580
+ }
581
+ function joinCanonicalPrnReasonTexts(reasons, conjunction = "or") {
582
+ var _a2;
583
+ if (!(reasons == null ? void 0 : reasons.length)) {
584
+ return void 0;
585
+ }
586
+ const texts = [];
587
+ for (const reason of reasons) {
588
+ const text = (_a2 = getCanonicalPrnReasonText(reason)) == null ? void 0 : _a2.trim();
589
+ if (!text) {
590
+ continue;
591
+ }
592
+ texts.push(text);
593
+ }
594
+ switch (texts.length) {
595
+ case 0:
596
+ return void 0;
597
+ case 1:
598
+ return texts[0];
599
+ case 2:
600
+ return `${texts[0]} ${conjunction} ${texts[1]}`;
601
+ default: {
602
+ let combined = "";
603
+ for (let index = 0; index < texts.length; index += 1) {
604
+ if (index === 0) {
605
+ combined = texts[index];
606
+ continue;
607
+ }
608
+ if (index === texts.length - 1) {
609
+ combined += ` ${conjunction} ${texts[index]}`;
610
+ continue;
611
+ }
612
+ combined += `, ${texts[index]}`;
613
+ }
614
+ return combined;
615
+ }
616
+ }
617
+ }
618
+ function getPreferredCanonicalPrnReasonText(reason, reasons, conjunction = "or") {
619
+ var _a2;
620
+ const direct = (_a2 = getCanonicalPrnReasonText(reason)) == null ? void 0 : _a2.trim();
621
+ if (!(reasons == null ? void 0 : reasons.length)) {
622
+ return direct;
623
+ }
624
+ if (!direct) {
625
+ return joinCanonicalPrnReasonTexts(reasons, conjunction);
626
+ }
627
+ return /[,/;]/.test(direct) || /\b(?:or|and|and\/or)\b/i.test(direct) || /\s(?:หรือ|และ)\s/.test(direct) ? joinCanonicalPrnReasonTexts(reasons, conjunction) : direct;
628
+ }
629
+
362
630
  // src/snomed.ts
363
631
  var SNOMED_SYSTEM = "http://snomed.info/sct";
364
632
  var SNOMED_CT_FINDING_SITE_ATTRIBUTE_CODE = "363698007";
@@ -497,8 +765,8 @@ function mergeTranslationPrimitiveElement(base, translations) {
497
765
  if (extension.url !== FHIR_TRANSLATION_EXTENSION_URL) {
498
766
  continue;
499
767
  }
500
- const { locale } = getTranslationParts(extension);
501
- if (locale) {
768
+ const { locale, content } = getTranslationParts(extension);
769
+ if (locale && content) {
502
770
  existingTranslationLocales.add(locale);
503
771
  }
504
772
  }
@@ -1167,10 +1435,11 @@ var DEFAULT_BODY_SITE_SNOMED_SOURCE = [
1167
1435
  }
1168
1436
  },
1169
1437
  {
1170
- names: ["both eyes", "bilateral eyes", "\u0E15\u0E32\u0E17\u0E31\u0E49\u0E07\u0E2A\u0E2D\u0E07\u0E02\u0E49\u0E32\u0E07", "\u0E15\u0E32\u0E2A\u0E2D\u0E07\u0E02\u0E49\u0E32\u0E07"],
1438
+ names: ["both eyes", "bilateral eyes", "each eye", "\u0E15\u0E32\u0E17\u0E31\u0E49\u0E07\u0E2A\u0E2D\u0E07\u0E02\u0E49\u0E32\u0E07", "\u0E15\u0E32\u0E2A\u0E2D\u0E07\u0E02\u0E49\u0E32\u0E07"],
1171
1439
  definition: {
1172
1440
  coding: { code: "40638003", display: "Structure of both eyes" },
1173
1441
  text: "both eyes",
1442
+ administrationTargetCount: 2,
1174
1443
  i18n: { th: "\u0E15\u0E32\u0E17\u0E31\u0E49\u0E07\u0E2A\u0E2D\u0E07\u0E02\u0E49\u0E32\u0E07" },
1175
1444
  routeHint: RouteCode["Ophthalmic route"]
1176
1445
  }
@@ -1184,10 +1453,19 @@ var DEFAULT_BODY_SITE_SNOMED_SOURCE = [
1184
1453
  }
1185
1454
  },
1186
1455
  {
1187
- names: ["ears", "both ears", "bilateral ears", "inside ears", "\u0E2B\u0E39\u0E17\u0E31\u0E49\u0E07\u0E2A\u0E2D\u0E07\u0E02\u0E49\u0E32\u0E07", "\u0E2B\u0E39\u0E2A\u0E2D\u0E07\u0E02\u0E49\u0E32\u0E07"],
1456
+ names: [
1457
+ "ears",
1458
+ "both ears",
1459
+ "bilateral ears",
1460
+ "each ear",
1461
+ "inside ears",
1462
+ "\u0E2B\u0E39\u0E17\u0E31\u0E49\u0E07\u0E2A\u0E2D\u0E07\u0E02\u0E49\u0E32\u0E07",
1463
+ "\u0E2B\u0E39\u0E2A\u0E2D\u0E07\u0E02\u0E49\u0E32\u0E07"
1464
+ ],
1188
1465
  definition: {
1189
1466
  coding: { code: "34338003", display: "Both ears" },
1190
1467
  text: "both ears",
1468
+ administrationTargetCount: 2,
1191
1469
  routeHint: RouteCode["Otic route"]
1192
1470
  }
1193
1471
  },
@@ -1205,10 +1483,18 @@ var DEFAULT_BODY_SITE_SNOMED_SOURCE = [
1205
1483
  }
1206
1484
  },
1207
1485
  {
1208
- names: ["ear canals", "both ear canals", "inside ear canals", "both external auditory canals"],
1486
+ names: [
1487
+ "ear canals",
1488
+ "both ear canals",
1489
+ "each ear canal",
1490
+ "inside ear canals",
1491
+ "both external auditory canals",
1492
+ "each external auditory canal"
1493
+ ],
1209
1494
  definition: {
1210
1495
  coding: { code: "181178004", display: "Entire external auditory canal" },
1211
1496
  text: "both ear canals",
1497
+ administrationTargetCount: 2,
1212
1498
  routeHint: RouteCode["Otic route"]
1213
1499
  }
1214
1500
  },
@@ -1245,8 +1531,12 @@ var DEFAULT_BODY_SITE_SNOMED_SOURCE = [
1245
1531
  }
1246
1532
  },
1247
1533
  {
1248
- names: ["nostril", "nostrils"],
1249
- definition: { coding: { code: "1797002", display: "Naris" }, routeHint: RouteCode["Nasal route"] }
1534
+ names: ["nostril"],
1535
+ definition: {
1536
+ coding: { code: "1797002", display: "Naris" },
1537
+ text: "nostril",
1538
+ routeHint: RouteCode["Nasal route"]
1539
+ }
1250
1540
  },
1251
1541
  {
1252
1542
  names: ["left nostril", "left naris"],
@@ -1263,8 +1553,22 @@ var DEFAULT_BODY_SITE_SNOMED_SOURCE = [
1263
1553
  }
1264
1554
  },
1265
1555
  {
1266
- names: ["nares", "anterior nares"],
1267
- definition: { coding: { code: "244506005", display: "Anterior nares" }, routeHint: RouteCode["Nasal route"] }
1556
+ names: [
1557
+ "nostrils",
1558
+ "both nostrils",
1559
+ "bilateral nostrils",
1560
+ "each nostril",
1561
+ "nares",
1562
+ "anterior nares",
1563
+ "\u0E23\u0E39\u0E08\u0E21\u0E39\u0E01\u0E17\u0E31\u0E49\u0E07\u0E2A\u0E2D\u0E07\u0E02\u0E49\u0E32\u0E07"
1564
+ ],
1565
+ definition: {
1566
+ coding: { code: "244506005", display: "Anterior nares" },
1567
+ text: "both nostrils",
1568
+ administrationTargetCount: 2,
1569
+ i18n: { th: "\u0E23\u0E39\u0E08\u0E21\u0E39\u0E01\u0E17\u0E31\u0E49\u0E07\u0E2A\u0E2D\u0E07\u0E02\u0E49\u0E32\u0E07" },
1570
+ routeHint: RouteCode["Nasal route"]
1571
+ }
1268
1572
  },
1269
1573
  {
1270
1574
  names: ["nose"],
@@ -1790,6 +2094,24 @@ var DEFAULT_BODY_SITE_SNOMED_SOURCE = [
1790
2094
  names: ["affected area", "affected areas", "affected site", "\u0E1A\u0E23\u0E34\u0E40\u0E27\u0E13\u0E17\u0E35\u0E48\u0E40\u0E1B\u0E47\u0E19"],
1791
2095
  definition: { text: "affected area", routeHint: RouteCode["Topical route"] }
1792
2096
  },
2097
+ {
2098
+ names: ["lesion", "skin lesion"],
2099
+ definition: {
2100
+ coding: { code: "95324001", display: "Skin lesion" },
2101
+ text: "lesion",
2102
+ routeHint: RouteCode["Topical route"],
2103
+ i18n: { th: "\u0E23\u0E2D\u0E22\u0E42\u0E23\u0E04" }
2104
+ }
2105
+ },
2106
+ {
2107
+ names: ["lesions", "skin lesions"],
2108
+ definition: {
2109
+ coding: { code: "95324001", display: "Skin lesion" },
2110
+ text: "lesions",
2111
+ routeHint: RouteCode["Topical route"],
2112
+ i18n: { th: "\u0E23\u0E2D\u0E22\u0E42\u0E23\u0E04" }
2113
+ }
2114
+ },
1793
2115
  {
1794
2116
  names: ["left head", "left side of head"],
1795
2117
  definition: { coding: { code: "64237003", display: "Structure of left half of head" }, routeHint: RouteCode["Topical route"] }
@@ -1830,6 +2152,14 @@ var DEFAULT_BODY_SITE_SNOMED_SOURCE = [
1830
2152
  names: ["axilla", "axillae", "armpit", "armpits"],
1831
2153
  definition: { coding: { code: "34797008", display: "Axilla structure" }, routeHint: RouteCode["Topical route"] }
1832
2154
  },
2155
+ {
2156
+ names: ["axillary hair", "armpit hair", "armpit hairs", "underarm hair", "underarm hairs"],
2157
+ definition: {
2158
+ coding: { code: "75703003", display: "Structure of hair of axilla" },
2159
+ text: "axillary hair",
2160
+ routeHint: RouteCode["Topical route"]
2161
+ }
2162
+ },
1833
2163
  {
1834
2164
  names: ["groin"],
1835
2165
  definition: { coding: { code: "26893007", display: "Inguinal region structure" }, routeHint: RouteCode["Topical route"] }
@@ -1900,6 +2230,71 @@ var DEFAULT_BODY_SITE_SNOMED_SOURCE = [
1900
2230
  names: ["face"],
1901
2231
  definition: { coding: { code: "89545001", display: "Face" }, routeHint: RouteCode["Topical route"] }
1902
2232
  },
2233
+ {
2234
+ names: ["eyebrow", "brow"],
2235
+ definition: {
2236
+ coding: { code: "392262008", display: "Eyebrow structure" },
2237
+ text: "eyebrow",
2238
+ routeHint: RouteCode["Topical route"]
2239
+ }
2240
+ },
2241
+ {
2242
+ names: ["eyebrows", "brows"],
2243
+ definition: {
2244
+ coding: { code: "392262008", display: "Eyebrow structure" },
2245
+ text: "eyebrows",
2246
+ routeHint: RouteCode["Topical route"]
2247
+ }
2248
+ },
2249
+ {
2250
+ names: ["left eyebrow", "left brow"],
2251
+ definition: {
2252
+ coding: { code: "722011002", display: "Structure of eyebrow of left eye region" },
2253
+ text: "left eyebrow",
2254
+ routeHint: RouteCode["Topical route"]
2255
+ }
2256
+ },
2257
+ {
2258
+ names: ["right eyebrow", "right brow"],
2259
+ definition: {
2260
+ coding: { code: "722012009", display: "Structure of eyebrow of right eye region" },
2261
+ text: "right eyebrow",
2262
+ routeHint: RouteCode["Topical route"]
2263
+ }
2264
+ },
2265
+ {
2266
+ names: [
2267
+ "both eyebrows",
2268
+ "bilateral eyebrows",
2269
+ "each eyebrow",
2270
+ "left and right eyebrow",
2271
+ "left and right eyebrows",
2272
+ "right and left eyebrow",
2273
+ "right and left eyebrows",
2274
+ "left right eyebrow",
2275
+ "left right eyebrows"
2276
+ ],
2277
+ definition: {
2278
+ coding: {
2279
+ code: buildSnomedBodySiteLateralityPostcoordinationCode(
2280
+ "392262008",
2281
+ SNOMED_CT_BILATERAL_QUALIFIER_CODE
2282
+ ),
2283
+ display: "both eyebrows"
2284
+ },
2285
+ text: "both eyebrows",
2286
+ administrationTargetCount: 2,
2287
+ routeHint: RouteCode["Topical route"]
2288
+ }
2289
+ },
2290
+ {
2291
+ names: ["eyebrow hair", "eyebrow hairs", "brow hair", "brow hairs"],
2292
+ definition: {
2293
+ coding: { code: "392261001", display: "Hair structure of eyebrow" },
2294
+ text: "eyebrow hair",
2295
+ routeHint: RouteCode["Topical route"]
2296
+ }
2297
+ },
1903
2298
  {
1904
2299
  names: ["eyelid", "eyelids"],
1905
2300
  definition: { coding: { code: "80243003", display: "Eyelid" }, routeHint: RouteCode["Ophthalmic route"] }
@@ -2020,14 +2415,70 @@ var DEFAULT_BODY_SITE_SNOMED_SOURCE = [
2020
2415
  names: ["perineum"],
2021
2416
  definition: { coding: { code: "243990009", display: "Entire perineum" }, routeHint: RouteCode["Topical route"] }
2022
2417
  },
2418
+ {
2419
+ names: ["mustache", "moustache", "mustache hair", "moustache hair"],
2420
+ definition: {
2421
+ coding: { code: "256925006", display: "Structure of hair of mustache" },
2422
+ text: "mustache",
2423
+ routeHint: RouteCode["Topical route"]
2424
+ }
2425
+ },
2426
+ {
2427
+ names: ["beard", "beard hair", "facial hair"],
2428
+ definition: {
2429
+ coding: { code: "367576007", display: "Structure of beard hair" },
2430
+ text: "beard",
2431
+ routeHint: RouteCode["Topical route"]
2432
+ }
2433
+ },
2434
+ {
2435
+ names: ["pubic hair"],
2436
+ definition: {
2437
+ coding: { code: "75776007", display: "Structure of hair of pubis" },
2438
+ text: "pubic hair",
2439
+ routeHint: RouteCode["Topical route"]
2440
+ }
2441
+ },
2023
2442
  {
2024
2443
  names: ["skin"],
2025
2444
  definition: { coding: { code: "181469002", display: "Entire skin" }, routeHint: RouteCode["Topical route"] }
2026
2445
  },
2027
2446
  {
2028
- names: ["hair"],
2447
+ names: ["hair"],
2448
+ definition: {
2449
+ coding: { code: "386045008", display: "Hair structure (body structure)" },
2450
+ routeHint: RouteCode["Topical route"]
2451
+ }
2452
+ },
2453
+ {
2454
+ names: ["joint"],
2455
+ definition: {
2456
+ coding: { code: "39352004", display: "Joint structure" },
2457
+ text: "joint",
2458
+ routeHint: RouteCode["Topical route"]
2459
+ }
2460
+ },
2461
+ {
2462
+ names: ["joints"],
2463
+ definition: {
2464
+ coding: { code: "81087007", display: "Joints" },
2465
+ text: "joints",
2466
+ routeHint: RouteCode["Topical route"]
2467
+ }
2468
+ },
2469
+ {
2470
+ names: ["finger joint", "finger joints"],
2471
+ definition: {
2472
+ coding: { code: "125682004", display: "Finger joint structure" },
2473
+ text: "finger joints",
2474
+ routeHint: RouteCode["Topical route"]
2475
+ }
2476
+ },
2477
+ {
2478
+ names: ["knuckle", "knuckles"],
2029
2479
  definition: {
2030
- coding: { code: "386045008", display: "Hair structure (body structure)" },
2480
+ coding: { code: "70420003", display: "Metacarpophalangeal joint structure" },
2481
+ text: "knuckles",
2031
2482
  routeHint: RouteCode["Topical route"]
2032
2483
  }
2033
2484
  }
@@ -3941,6 +4392,7 @@ var lexical_classes_default = {
3941
4392
  "Use shampoo": "\u0E2A\u0E23\u0E30"
3942
4393
  },
3943
4394
  compoundDoseUnits: [
4395
+ { head: "cm", tails: [], requiresSiteContext: true, unit: "cm line" },
3944
4396
  { head: "cm", tails: ["ribbon", "ribbons"], unit: "cm ribbon" },
3945
4397
  { head: "cm", tails: ["strip", "strips"], unit: "cm strip" },
3946
4398
  { head: "cm", tails: ["line", "lines"], unit: "cm line" },
@@ -3949,6 +4401,8 @@ var lexical_classes_default = {
3949
4401
  { head: "fingertip", tails: ["unit", "units"], unit: "FTU" },
3950
4402
  { head: "eye", tails: ["drop", "drops"], unit: "drop" },
3951
4403
  { head: "pea-sized", tails: ["amount"], unit: "pea-sized amount" },
4404
+ { head: "pea-size", tails: ["amount"], unit: "pea-sized amount" },
4405
+ { head: "peasize", tails: [], tailSequences: [[]], unit: "pea-sized amount" },
3952
4406
  { head: "\u0E40\u0E21\u0E47\u0E14\u0E16\u0E31\u0E48\u0E27", tails: [], unit: "pea-sized amount" },
3953
4407
  { head: "\u0E40\u0E21\u0E47\u0E14\u0E16\u0E31\u0E48\u0E27\u0E40\u0E02\u0E35\u0E22\u0E27", tails: [], unit: "pea-sized amount" },
3954
4408
  { head: "\u0E40\u0E21\u0E25\u0E47\u0E14\u0E16\u0E31\u0E48\u0E27", tails: [], unit: "pea-sized amount" },
@@ -3958,7 +4412,7 @@ var lexical_classes_default = {
3958
4412
  {
3959
4413
  head: "pea",
3960
4414
  tails: [],
3961
- tailSequences: [["sized", "amount"], ["size", "amount"]],
4415
+ tailSequences: [["sized", "amount"], ["size", "amount"], ["amount"], ["sized"], ["size"], []],
3962
4416
  unit: "pea-sized amount"
3963
4417
  },
3964
4418
  { head: "hand", tails: ["print", "prints"], unit: "handprint" },
@@ -4369,6 +4823,7 @@ var BODY_SITE_FEATURE_SCORE_BONUS = bodySiteFeatureScoreBonus(lexical_classes_de
4369
4823
  var CONNECTORS = setOf(lexical_classes_default.connectors);
4370
4824
  var ROUTE_SITE_PREPOSITIONS = setOf(lexical_classes_default.routeSitePrepositions);
4371
4825
  var SITE_DISPLAY_FILLERS = SITE_FILLERS;
4826
+ var SITE_MULTIPLICITY_WORDS = setOf(["both", "each", "bilateral"]);
4372
4827
  var NON_SITE_ANCHORED_PHRASES = setOf(lexical_classes_default.nonSiteAnchoredPhrases);
4373
4828
  var EXTERNAL_SITE_LOCATIVE_PREFIXES = setOf(lexical_classes_default.externalSiteLocativePrefixes);
4374
4829
  var ROUTE_BLOCKED_BY_FOLLOWING_PARTITIVE_HEADS = setOf(
@@ -4914,140 +5369,6 @@ function resolveBodySitePhrase(text, customSiteMap, context) {
4914
5369
  };
4915
5370
  }
4916
5371
 
4917
- // src/timing-summary.ts
4918
- var MEAL_TIMING_DETAILS = {
4919
- ["ACM" /* Before Breakfast */]: { relation: "before", meal: "breakfast" },
4920
- ["ACD" /* Before Lunch */]: { relation: "before", meal: "lunch" },
4921
- ["ACV" /* Before Dinner */]: { relation: "before", meal: "dinner" },
4922
- ["PCM" /* After Breakfast */]: { relation: "after", meal: "breakfast" },
4923
- ["PCD" /* After Lunch */]: { relation: "after", meal: "lunch" },
4924
- ["PCV" /* After Dinner */]: { relation: "after", meal: "dinner" },
4925
- ["CM" /* Breakfast */]: { relation: "with", meal: "breakfast" },
4926
- ["CD" /* Lunch */]: { relation: "with", meal: "lunch" },
4927
- ["CV" /* Dinner */]: { relation: "with", meal: "dinner" }
4928
- };
4929
- var MEAL_ORDER = {
4930
- breakfast: 0,
4931
- lunch: 1,
4932
- dinner: 2
4933
- };
4934
- var INFERABLE_DAILY_EVENT_TIMINGS = /* @__PURE__ */ new Set([
4935
- "HS" /* Before Sleep */,
4936
- "ACM" /* Before Breakfast */,
4937
- "ACD" /* Before Lunch */,
4938
- "ACV" /* Before Dinner */,
4939
- "PCM" /* After Breakfast */,
4940
- "PCD" /* After Lunch */,
4941
- "PCV" /* After Dinner */,
4942
- "CM" /* Breakfast */,
4943
- "CD" /* Lunch */,
4944
- "CV" /* Dinner */,
4945
- "MORN" /* Morning */,
4946
- "MORN.early" /* Early Morning */,
4947
- "MORN.late" /* Late Morning */,
4948
- "NOON" /* Noon */,
4949
- "AFT" /* Afternoon */,
4950
- "AFT.early" /* Early Afternoon */,
4951
- "AFT.late" /* Late Afternoon */,
4952
- "EVE" /* Evening */,
4953
- "EVE.early" /* Early Evening */,
4954
- "EVE.late" /* Late Evening */,
4955
- "NIGHT" /* Night */,
4956
- "WAKE" /* Wake */,
4957
- "PHS" /* After Sleep */
4958
- ]);
4959
- function uniqueValues(values) {
4960
- const seen = /* @__PURE__ */ new Set();
4961
- const result = [];
4962
- for (const value of values) {
4963
- if (!seen.has(value)) {
4964
- seen.add(value);
4965
- result.push(value);
4966
- }
4967
- }
4968
- return result;
4969
- }
4970
- function getMealTimingGroup(when, options) {
4971
- if (!(options == null ? void 0 : options.groupMealTimingsByRelation)) {
4972
- return void 0;
4973
- }
4974
- const uniqueWhen2 = uniqueValues(when);
4975
- if (uniqueWhen2.length < 2) {
4976
- return void 0;
4977
- }
4978
- let relation;
4979
- const meals = [];
4980
- const groupedCodes = [];
4981
- let sawFirstMeal = false;
4982
- for (let i = 0; i < uniqueWhen2.length; i += 1) {
4983
- const code = uniqueWhen2[i];
4984
- const detail = MEAL_TIMING_DETAILS[code];
4985
- if (!detail) {
4986
- if (sawFirstMeal) {
4987
- break;
4988
- }
4989
- continue;
4990
- }
4991
- if (!sawFirstMeal) {
4992
- sawFirstMeal = true;
4993
- }
4994
- if (!relation) {
4995
- relation = detail.relation;
4996
- } else if (relation !== detail.relation && detail.relation !== "with") {
4997
- break;
4998
- }
4999
- meals.push(detail.meal);
5000
- groupedCodes.push(code);
5001
- }
5002
- if (groupedCodes.length < 2) {
5003
- return void 0;
5004
- }
5005
- for (let i = 1; i < meals.length; i += 1) {
5006
- const current = meals[i];
5007
- let j = i - 1;
5008
- while (j >= 0 && MEAL_ORDER[meals[j]] > MEAL_ORDER[current]) {
5009
- meals[j + 1] = meals[j];
5010
- j -= 1;
5011
- }
5012
- meals[j + 1] = current;
5013
- }
5014
- if (!relation) {
5015
- return void 0;
5016
- }
5017
- return {
5018
- relation,
5019
- meals,
5020
- codes: groupedCodes
5021
- };
5022
- }
5023
- function inferDailyOccurrenceCount(input, options) {
5024
- var _a2, _b, _c, _d;
5025
- if (!(options == null ? void 0 : options.includeTimesPerDaySummary)) {
5026
- return void 0;
5027
- }
5028
- if (input.frequency !== void 0 || input.frequencyMax !== void 0 || input.timingCode) {
5029
- return void 0;
5030
- }
5031
- if (input.period !== void 0 || input.periodMax !== void 0 || input.periodUnit !== void 0) {
5032
- return void 0;
5033
- }
5034
- if (((_b = (_a2 = input.dayOfWeek) == null ? void 0 : _a2.length) != null ? _b : 0) > 0) {
5035
- return void 0;
5036
- }
5037
- const uniqueWhen2 = uniqueValues((_c = input.when) != null ? _c : []);
5038
- for (let i = 0; i < uniqueWhen2.length; i += 1) {
5039
- if (!INFERABLE_DAILY_EVENT_TIMINGS.has(uniqueWhen2[i])) {
5040
- return void 0;
5041
- }
5042
- }
5043
- const uniqueTimes = uniqueValues((_d = input.timeOfDay) != null ? _d : []);
5044
- const occurrences = uniqueWhen2.length + uniqueTimes.length;
5045
- if (occurrences === 0) {
5046
- return void 0;
5047
- }
5048
- return occurrences;
5049
- }
5050
-
5051
5372
  // src/format.ts
5052
5373
  var ROUTE_SHORT = {
5053
5374
  [RouteCode["Oral route"]]: "PO",
@@ -5539,73 +5860,22 @@ function summarizeMealTimingGroup(group) {
5539
5860
  }
5540
5861
  return `${relationText} ${joinWithAnd(group.meals)}`;
5541
5862
  }
5542
- function collectWhenPhrases(schedule, options) {
5543
- var _a2, _b, _c;
5544
- const when = (_a2 = schedule == null ? void 0 : schedule.when) != null ? _a2 : [];
5545
- if (!when.length) {
5546
- return [];
5547
- }
5548
- const unique = [];
5549
- const seen = /* @__PURE__ */ new Set();
5550
- let hasSpecificAfter = false;
5551
- let hasSpecificBefore = false;
5552
- let hasSpecificWith = false;
5553
- for (const code of when) {
5554
- if (!seen.has(code)) {
5555
- seen.add(code);
5556
- unique.push(code);
5557
- if (code === "PCM" /* After Breakfast */ || code === "PCD" /* After Lunch */ || code === "PCV" /* After Dinner */) {
5558
- hasSpecificAfter = true;
5559
- }
5560
- if (code === "ACM" /* Before Breakfast */ || code === "ACD" /* Before Lunch */ || code === "ACV" /* Before Dinner */) {
5561
- hasSpecificBefore = true;
5562
- }
5563
- if (code === "CM" /* Breakfast */ || code === "CD" /* Lunch */ || code === "CV" /* Dinner */) {
5564
- hasSpecificWith = true;
5565
- }
5566
- }
5567
- }
5568
- const filtered = [];
5569
- for (const code of unique) {
5570
- if (code === "PC" /* After Meal */ && hasSpecificAfter) {
5571
- continue;
5572
- }
5573
- if (code === "AC" /* Before Meal */ && hasSpecificBefore) {
5574
- continue;
5575
- }
5576
- if (code === "C" /* Meal */ && hasSpecificWith) {
5577
- continue;
5578
- }
5579
- filtered.push(code);
5580
- }
5581
- const mealGroup = getMealTimingGroup(filtered, options);
5582
- if (!mealGroup) {
5583
- const phrases2 = [];
5584
- for (const code of filtered) {
5585
- const text = (_b = WHEN_TEXT[code]) != null ? _b : code;
5586
- if (text) {
5587
- phrases2.push(text);
5588
- }
5589
- }
5590
- return phrases2;
5591
- }
5592
- const groupedCodes = new Set(mealGroup.codes);
5593
- const phrases = [];
5594
- let insertedGroup = false;
5595
- for (const code of filtered) {
5596
- if (groupedCodes.has(code)) {
5597
- if (!insertedGroup) {
5598
- phrases.push(summarizeMealTimingGroup(mealGroup));
5599
- insertedGroup = true;
5600
- }
5601
- continue;
5863
+ var EN_TIMING_GRAMMAR = {
5864
+ whenText: WHEN_TEXT,
5865
+ joinList: joinWithAnd,
5866
+ summarizeMealTimingGroup,
5867
+ bedtimeJoinStyle: (dailyCount) => {
5868
+ if (dailyCount === 1) {
5869
+ return "adjacent";
5602
5870
  }
5603
- const text = (_c = WHEN_TEXT[code]) != null ? _c : code;
5604
- if (text) {
5605
- phrases.push(text);
5871
+ if (dailyCount === 2 || dailyCount === 3 || dailyCount === 4) {
5872
+ return "conjunction";
5606
5873
  }
5874
+ return "separate";
5607
5875
  }
5608
- return phrases;
5876
+ };
5877
+ function collectWhenPhrases(schedule, options) {
5878
+ return collectLocalizedWhenPhrases(schedule, EN_TIMING_GRAMMAR, options);
5609
5879
  }
5610
5880
  function joinWithAnd(parts) {
5611
5881
  if (!parts.length) {
@@ -5619,23 +5889,14 @@ function joinWithAnd(parts) {
5619
5889
  }
5620
5890
  return `${parts.slice(0, -1).join(", ")} and ${parts[parts.length - 1]}`;
5621
5891
  }
5622
- function combineFrequencyAndEvents(frequency, events) {
5623
- if (!frequency) {
5624
- if (!events.length) {
5625
- return {};
5626
- }
5627
- return { event: joinWithAnd(events) };
5628
- }
5629
- if (!events.length) {
5630
- return { frequency };
5631
- }
5632
- if (events.length === 1 && events[0] === "at bedtime") {
5633
- const lowerFrequency = frequency.toLowerCase();
5634
- if (lowerFrequency === "twice daily" || lowerFrequency === "three times daily" || lowerFrequency === "four times daily") {
5635
- return { frequency: `${frequency} and ${events[0]}` };
5636
- }
5637
- }
5638
- return { frequency, event: joinWithAnd(events) };
5892
+ function combineFrequencyAndEvents(schedule, frequency, events, options) {
5893
+ return combineLocalizedFrequencyAndEvents(
5894
+ schedule,
5895
+ frequency,
5896
+ events,
5897
+ EN_TIMING_GRAMMAR,
5898
+ options
5899
+ );
5639
5900
  }
5640
5901
  function buildRoutePhrase(clause, grammar, hasSite) {
5641
5902
  var _a2, _b;
@@ -5940,7 +6201,7 @@ function formatLong(clause, options) {
5940
6201
  eventParts.push(`at ${timeStrings.join(", ")}`);
5941
6202
  }
5942
6203
  }
5943
- const timing = combineFrequencyAndEvents(frequencyPart, eventParts);
6204
+ const timing = combineFrequencyAndEvents(schedule, frequencyPart, eventParts, options);
5944
6205
  const dayPart = describeDayOfWeek(schedule);
5945
6206
  const countPart = schedule.count !== void 0 && !standaloneOccurrenceCount ? `for ${stripTrailingZero(schedule.count)} ${schedule.count === 1 ? "dose" : "doses"}` : void 0;
5946
6207
  const durationPart = describeDuration(schedule);
@@ -9735,6 +9996,81 @@ function listSupportedBodySiteGrammar() {
9735
9996
  };
9736
9997
  }
9737
9998
 
9999
+ // src/body-site-target.ts
10000
+ var BODY_SITE_ADMINISTRATION_TARGET_COUNT_EXTENSION_URL = "urn:ezmedicationinput:body-site-administration-target-count";
10001
+ function normalizeAdministrationTargetCount(value) {
10002
+ if (!Number.isFinite(value) || value === void 0) {
10003
+ return void 0;
10004
+ }
10005
+ const rounded = Math.trunc(value);
10006
+ return rounded >= 2 ? rounded : void 0;
10007
+ }
10008
+ function siteTextFromLike(site, options) {
10009
+ if (!site) {
10010
+ return void 0;
10011
+ }
10012
+ if (typeof site === "string") {
10013
+ return site;
10014
+ }
10015
+ if ("text" in site && site.text) {
10016
+ return site.text;
10017
+ }
10018
+ const coding = "coding" in site ? Array.isArray(site.coding) ? site.coding.find((candidate) => candidate == null ? void 0 : candidate.code) : site.coding : void 0;
10019
+ return (coding == null ? void 0 : coding.code) ? getBodySiteText(
10020
+ {
10021
+ system: coding.system,
10022
+ code: coding.code,
10023
+ display: coding.display
10024
+ },
10025
+ { siteCodeMap: options == null ? void 0 : options.siteCodeMap }
10026
+ ) : void 0;
10027
+ }
10028
+ function buildBodySiteAdministrationTargetCountExtension(targetCount) {
10029
+ const normalized = normalizeAdministrationTargetCount(targetCount);
10030
+ if (normalized === void 0) {
10031
+ return void 0;
10032
+ }
10033
+ return {
10034
+ url: BODY_SITE_ADMINISTRATION_TARGET_COUNT_EXTENSION_URL,
10035
+ valueInteger: normalized
10036
+ };
10037
+ }
10038
+ function parseBodySiteAdministrationTargetCountExtension(concept) {
10039
+ var _a2;
10040
+ const extension = (_a2 = concept == null ? void 0 : concept.extension) == null ? void 0 : _a2.find(
10041
+ (candidate) => candidate.url === BODY_SITE_ADMINISTRATION_TARGET_COUNT_EXTENSION_URL
10042
+ );
10043
+ return normalizeAdministrationTargetCount(extension == null ? void 0 : extension.valueInteger);
10044
+ }
10045
+ function getBodySiteAdministrationTargetCount(site, options) {
10046
+ var _a2;
10047
+ if (!site) {
10048
+ return void 0;
10049
+ }
10050
+ if (typeof site !== "string" && "administrationTargetCount" in site) {
10051
+ const direct = normalizeAdministrationTargetCount(site.administrationTargetCount);
10052
+ if (direct !== void 0) {
10053
+ return direct;
10054
+ }
10055
+ }
10056
+ if (typeof site !== "string") {
10057
+ if ("extension" in site) {
10058
+ const fromExtension = parseBodySiteAdministrationTargetCountExtension(site);
10059
+ if (fromExtension !== void 0) {
10060
+ return fromExtension;
10061
+ }
10062
+ }
10063
+ }
10064
+ const text = siteTextFromLike(site, options);
10065
+ if (!text) {
10066
+ return void 0;
10067
+ }
10068
+ const resolved = resolveBodySitePhrase(text, options == null ? void 0 : options.siteCodeMap, {
10069
+ bodySiteContext: options == null ? void 0 : options.bodySiteContext
10070
+ });
10071
+ return normalizeAdministrationTargetCount((_a2 = resolved == null ? void 0 : resolved.definition) == null ? void 0 : _a2.administrationTargetCount);
10072
+ }
10073
+
9738
10074
  // src/parser-state.ts
9739
10075
  var ParserState = class {
9740
10076
  constructor(input, tokens, customSiteHints) {
@@ -10105,6 +10441,20 @@ var ParserState = class {
10105
10441
  sourceText: value.sourceText
10106
10442
  };
10107
10443
  }
10444
+ get siteAdministrationTargetCount() {
10445
+ var _a2;
10446
+ return (_a2 = this.clause.site) == null ? void 0 : _a2.administrationTargetCount;
10447
+ }
10448
+ set siteAdministrationTargetCount(value) {
10449
+ if (value === void 0) {
10450
+ if (this.clause.site) {
10451
+ delete this.clause.site.administrationTargetCount;
10452
+ this.cleanupSite();
10453
+ }
10454
+ return;
10455
+ }
10456
+ this.ensureSite().administrationTargetCount = value;
10457
+ }
10108
10458
  get additionalInstructions() {
10109
10459
  if (!this.clause.additionalInstructions) {
10110
10460
  this.clause.additionalInstructions = [];
@@ -10177,7 +10527,7 @@ var ParserState = class {
10177
10527
  if (!site) {
10178
10528
  return;
10179
10529
  }
10180
- if (site.text === void 0 && site.coding === void 0 && site.spatialRelation === void 0 && site.source === void 0 && site.inferred === void 0 && site.evidence === void 0) {
10530
+ if (site.text === void 0 && site.coding === void 0 && site.spatialRelation === void 0 && site.administrationTargetCount === void 0 && site.source === void 0 && site.inferred === void 0 && site.evidence === void 0) {
10181
10531
  delete this.clause.site;
10182
10532
  }
10183
10533
  }
@@ -10538,7 +10888,7 @@ function appendWarning(warnings, warning) {
10538
10888
  return warnings;
10539
10889
  }
10540
10890
  function canonicalToFhir(clause, textOverride, options) {
10541
- var _a2, _b, _c, _d, _e, _f, _g, _h, _i, _j, _k, _l, _m, _n, _o, _p, _q, _r, _s, _t, _u, _v, _w, _x, _y, _z, _A, _B, _C, _D, _E, _F, _G, _H, _I, _J;
10891
+ var _a2, _b, _c, _d, _e, _f, _g, _h, _i, _j, _k, _l, _m, _n, _o, _p, _q, _r, _s, _t, _u, _v, _w, _x, _y, _z, _A, _B, _C, _D, _E, _F, _G, _H, _I, _J, _K, _L, _M, _N;
10542
10892
  const dosage = {};
10543
10893
  const repeat = {};
10544
10894
  let hasRepeat = false;
@@ -10639,20 +10989,35 @@ function canonicalToFhir(clause, textOverride, options) {
10639
10989
  if (((_l = clause.site) == null ? void 0 : _l.text) || ((_n = (_m = clause.site) == null ? void 0 : _m.coding) == null ? void 0 : _n.code) || ((_o = clause.site) == null ? void 0 : _o.spatialRelation)) {
10640
10990
  const siteCoding = selectCanonicalSiteCoding(clause.site, options);
10641
10991
  const siteTextElement = (options == null ? void 0 : options.includeTranslationExtensions) ? buildTranslationPrimitiveElement((_p = clause.site.i18n) != null ? _p : siteCoding == null ? void 0 : siteCoding.i18n) : void 0;
10992
+ const siteTargetCount = (_r = (_q = clause.site) == null ? void 0 : _q.administrationTargetCount) != null ? _r : getBodySiteAdministrationTargetCount(clause.site);
10993
+ const inferredSiteTargetCount = getBodySiteAdministrationTargetCount({
10994
+ text: (_s = clause.site) == null ? void 0 : _s.text,
10995
+ coding: siteCoding ? {
10996
+ code: siteCoding.code,
10997
+ display: siteCoding.display,
10998
+ system: siteCoding.system,
10999
+ i18n: siteCoding.i18n
11000
+ } : void 0
11001
+ });
11002
+ const siteTargetCountExtension = siteTargetCount !== void 0 && siteTargetCount !== inferredSiteTargetCount ? buildBodySiteAdministrationTargetCountExtension(siteTargetCount) : void 0;
11003
+ const siteExtensions = [
11004
+ ...(_u = buildBodySiteSpatialRelationExtensions((_t = clause.site) == null ? void 0 : _t.spatialRelation)) != null ? _u : [],
11005
+ ...siteTargetCountExtension ? [siteTargetCountExtension] : []
11006
+ ];
10642
11007
  dosage.site = __spreadProps(__spreadValues({
10643
- text: (_q = clause.site) == null ? void 0 : _q.text
11008
+ text: (_v = clause.site) == null ? void 0 : _v.text
10644
11009
  }, siteTextElement ? { _text: siteTextElement } : {}), {
10645
11010
  coding: buildSiteCodingArray(siteCoding, options),
10646
- extension: buildBodySiteSpatialRelationExtensions((_r = clause.site) == null ? void 0 : _r.spatialRelation)
11011
+ extension: siteExtensions.length ? siteExtensions : void 0
10647
11012
  });
10648
11013
  }
10649
- if (((_s = clause.method) == null ? void 0 : _s.text) || ((_t = clause.method) == null ? void 0 : _t._text) || ((_v = (_u = clause.method) == null ? void 0 : _u.coding) == null ? void 0 : _v.code)) {
11014
+ if (((_w = clause.method) == null ? void 0 : _w.text) || ((_x = clause.method) == null ? void 0 : _x._text) || ((_z = (_y = clause.method) == null ? void 0 : _y.coding) == null ? void 0 : _z.code)) {
10650
11015
  dosage.method = {
10651
- text: (_w = clause.method) == null ? void 0 : _w.text,
10652
- _text: clonePrimitiveElement((_x = clause.method) == null ? void 0 : _x._text),
10653
- coding: ((_z = (_y = clause.method) == null ? void 0 : _y.coding) == null ? void 0 : _z.code) ? [
11016
+ text: (_A = clause.method) == null ? void 0 : _A.text,
11017
+ _text: clonePrimitiveElement((_B = clause.method) == null ? void 0 : _B._text),
11018
+ coding: ((_D = (_C = clause.method) == null ? void 0 : _C.coding) == null ? void 0 : _D.code) ? [
10654
11019
  {
10655
- system: (_A = clause.method.coding.system) != null ? _A : SNOMED_SYSTEM5,
11020
+ system: (_E = clause.method.coding.system) != null ? _E : SNOMED_SYSTEM5,
10656
11021
  code: clause.method.coding.code,
10657
11022
  display: clause.method.coding.display,
10658
11023
  _display: clonePrimitiveElement(clause.method.coding._display)
@@ -10660,14 +11025,14 @@ function canonicalToFhir(clause, textOverride, options) {
10660
11025
  ] : void 0
10661
11026
  };
10662
11027
  }
10663
- if ((_B = clause.additionalInstructions) == null ? void 0 : _B.length) {
11028
+ if ((_F = clause.additionalInstructions) == null ? void 0 : _F.length) {
10664
11029
  dosage.additionalInstruction = [];
10665
11030
  for (const instruction of clause.additionalInstructions) {
10666
11031
  dosage.additionalInstruction.push({
10667
11032
  text: instruction.text,
10668
- coding: ((_C = instruction.coding) == null ? void 0 : _C.code) ? [
11033
+ coding: ((_G = instruction.coding) == null ? void 0 : _G.code) ? [
10669
11034
  {
10670
- system: (_D = instruction.coding.system) != null ? _D : SNOMED_SYSTEM5,
11035
+ system: (_H = instruction.coding.system) != null ? _H : SNOMED_SYSTEM5,
10671
11036
  code: instruction.coding.code,
10672
11037
  display: instruction.coding.display
10673
11038
  }
@@ -10675,9 +11040,9 @@ function canonicalToFhir(clause, textOverride, options) {
10675
11040
  });
10676
11041
  }
10677
11042
  }
10678
- if ((_E = clause.prn) == null ? void 0 : _E.enabled) {
11043
+ if ((_I = clause.prn) == null ? void 0 : _I.enabled) {
10679
11044
  dosage.asNeededBoolean = true;
10680
- const reasons = ((_F = clause.prn.reasons) == null ? void 0 : _F.length) ? clause.prn.reasons : clause.prn.reason ? [clause.prn.reason] : [];
11045
+ const reasons = ((_J = clause.prn.reasons) == null ? void 0 : _J.length) ? clause.prn.reasons : clause.prn.reason ? [clause.prn.reason] : [];
10681
11046
  if (reasons.length) {
10682
11047
  dosage.asNeededFor = [];
10683
11048
  for (const reason of reasons) {
@@ -10685,18 +11050,18 @@ function canonicalToFhir(clause, textOverride, options) {
10685
11050
  if (reason.text) {
10686
11051
  concept.text = reason.text;
10687
11052
  }
10688
- const reasonTextElement = (options == null ? void 0 : options.includeTranslationExtensions) ? buildTranslationPrimitiveElement((_H = reason.i18n) != null ? _H : (_G = reason.coding) == null ? void 0 : _G.i18n) : void 0;
11053
+ const reasonTextElement = (options == null ? void 0 : options.includeTranslationExtensions) ? buildTranslationPrimitiveElement((_L = reason.i18n) != null ? _L : (_K = reason.coding) == null ? void 0 : _K.i18n) : void 0;
10689
11054
  if (reasonTextElement) {
10690
11055
  concept._text = reasonTextElement;
10691
11056
  }
10692
- if ((_I = reason.coding) == null ? void 0 : _I.code) {
11057
+ if ((_M = reason.coding) == null ? void 0 : _M.code) {
10693
11058
  const displayElement = (options == null ? void 0 : options.includeTranslationExtensions) ? mergeTranslationPrimitiveElement(
10694
11059
  reason.coding._display,
10695
11060
  reason.coding.i18n
10696
11061
  ) : clonePrimitiveElement(reason.coding._display);
10697
11062
  concept.coding = [
10698
11063
  __spreadProps(__spreadValues({
10699
- system: (_J = reason.coding.system) != null ? _J : SNOMED_SYSTEM5,
11064
+ system: (_N = reason.coding.system) != null ? _N : SNOMED_SYSTEM5,
10700
11065
  code: reason.coding.code,
10701
11066
  display: reason.coding.display
10702
11067
  }, displayElement ? { _display: displayElement } : {}), {
@@ -10737,11 +11102,13 @@ function canonicalFromFhir(dosage) {
10737
11102
  const siteSpatialRelation = parseBodySiteSpatialRelationExtension(dosage.site);
10738
11103
  const siteText = getFallbackSiteText(dosage.site);
10739
11104
  const siteI18n = codeableConceptTranslationI18n(dosage.site, siteCoding);
10740
- if (siteText || (siteCoding == null ? void 0 : siteCoding.code) || siteSpatialRelation) {
11105
+ const siteAdministrationTargetCount = getBodySiteAdministrationTargetCount(dosage.site);
11106
+ if (siteText || (siteCoding == null ? void 0 : siteCoding.code) || siteSpatialRelation || siteAdministrationTargetCount !== void 0) {
10741
11107
  clause.site = {
10742
11108
  text: siteText,
10743
11109
  i18n: siteI18n.text,
10744
11110
  spatialRelation: siteSpatialRelation,
11111
+ administrationTargetCount: siteAdministrationTargetCount,
10745
11112
  coding: (siteCoding == null ? void 0 : siteCoding.code) ? {
10746
11113
  code: siteCoding.code,
10747
11114
  display: siteCoding.display,
@@ -11822,73 +12189,22 @@ function summarizeMealTimingGroupThai(group) {
11822
12189
  }
11823
12190
  return `${relationText[group.relation]}${joinMealNamesThai(meals)}`;
11824
12191
  }
11825
- function collectWhenPhrasesThai(schedule, options) {
11826
- var _a2;
11827
- const when = (_a2 = schedule == null ? void 0 : schedule.when) != null ? _a2 : [];
11828
- if (!when.length) {
11829
- return [];
11830
- }
11831
- const unique = [];
11832
- const seen = /* @__PURE__ */ new Set();
11833
- let hasSpecificAfter = false;
11834
- let hasSpecificBefore = false;
11835
- let hasSpecificWith = false;
11836
- for (const code of when) {
11837
- if (!seen.has(code)) {
11838
- seen.add(code);
11839
- unique.push(code);
11840
- if (code === "PCM" /* After Breakfast */ || code === "PCD" /* After Lunch */ || code === "PCV" /* After Dinner */) {
11841
- hasSpecificAfter = true;
11842
- }
11843
- if (code === "ACM" /* Before Breakfast */ || code === "ACD" /* Before Lunch */ || code === "ACV" /* Before Dinner */) {
11844
- hasSpecificBefore = true;
11845
- }
11846
- if (code === "CM" /* Breakfast */ || code === "CD" /* Lunch */ || code === "CV" /* Dinner */) {
11847
- hasSpecificWith = true;
11848
- }
11849
- }
11850
- }
11851
- const filtered = [];
11852
- for (const code of unique) {
11853
- if (code === "PC" /* After Meal */ && hasSpecificAfter) {
11854
- continue;
11855
- }
11856
- if (code === "AC" /* Before Meal */ && hasSpecificBefore) {
11857
- continue;
11858
- }
11859
- if (code === "C" /* Meal */ && hasSpecificWith) {
11860
- continue;
11861
- }
11862
- filtered.push(code);
11863
- }
11864
- const mealGroup = getMealTimingGroup(filtered, options);
11865
- if (!mealGroup) {
11866
- const phrases2 = [];
11867
- for (const code of filtered) {
11868
- const text = WHEN_TEXT_THAI[code];
11869
- if (text) {
11870
- phrases2.push(text);
11871
- }
11872
- }
11873
- return phrases2;
11874
- }
11875
- const groupedCodes = new Set(mealGroup.codes);
11876
- const phrases = [];
11877
- let insertedGroup = false;
11878
- for (const code of filtered) {
11879
- if (groupedCodes.has(code)) {
11880
- if (!insertedGroup) {
11881
- phrases.push(summarizeMealTimingGroupThai(mealGroup));
11882
- insertedGroup = true;
11883
- }
11884
- continue;
12192
+ var TH_TIMING_GRAMMAR = {
12193
+ whenText: WHEN_TEXT_THAI,
12194
+ joinList: joinWithAndThai,
12195
+ summarizeMealTimingGroup: summarizeMealTimingGroupThai,
12196
+ bedtimeJoinStyle: (dailyCount) => {
12197
+ if (dailyCount === 1) {
12198
+ return "adjacent";
11885
12199
  }
11886
- const text = WHEN_TEXT_THAI[code];
11887
- if (text) {
11888
- phrases.push(text);
12200
+ if (dailyCount === 2 || dailyCount === 3 || dailyCount === 4) {
12201
+ return "conjunction";
11889
12202
  }
12203
+ return "separate";
11890
12204
  }
11891
- return phrases;
12205
+ };
12206
+ function collectWhenPhrasesThai(schedule, options) {
12207
+ return collectLocalizedWhenPhrases(schedule, TH_TIMING_GRAMMAR, options);
11892
12208
  }
11893
12209
  function joinWithAndThai(parts) {
11894
12210
  if (!parts.length) {
@@ -11902,20 +12218,14 @@ function joinWithAndThai(parts) {
11902
12218
  }
11903
12219
  return `${parts.slice(0, -1).join(", ")} \u0E41\u0E25\u0E30 ${parts[parts.length - 1]}`;
11904
12220
  }
11905
- function combineFrequencyAndEventsThai(frequency, events) {
11906
- if (!frequency) {
11907
- if (!events.length) {
11908
- return {};
11909
- }
11910
- return { event: joinWithAndThai(events) };
11911
- }
11912
- if (!events.length) {
11913
- return { frequency };
11914
- }
11915
- if (events.length === 1 && events[0] === "\u0E01\u0E48\u0E2D\u0E19\u0E19\u0E2D\u0E19" && frequency.includes("\u0E27\u0E31\u0E19\u0E25\u0E30")) {
11916
- return { frequency: `${frequency} \u0E41\u0E25\u0E30 ${events[0]}` };
11917
- }
11918
- return { frequency, event: joinWithAndThai(events) };
12221
+ function combineFrequencyAndEventsThai(schedule, frequency, events, options) {
12222
+ return combineLocalizedFrequencyAndEvents(
12223
+ schedule,
12224
+ frequency,
12225
+ events,
12226
+ TH_TIMING_GRAMMAR,
12227
+ options
12228
+ );
11919
12229
  }
11920
12230
  function isOralRouteThai(clause) {
11921
12231
  var _a2, _b, _c;
@@ -11974,7 +12284,7 @@ function buildRoutePhraseThai(clause, grammar, hasSite) {
11974
12284
  return text;
11975
12285
  }
11976
12286
  function formatSiteThai(clause, grammar) {
11977
- var _a2, _b, _c, _d, _e, _f, _g, _h, _i, _j, _k, _l, _m, _n, _o;
12287
+ var _a2, _b, _c, _d, _e, _f, _g, _h, _i, _j, _k, _l, _m, _n, _o, _p, _q, _r, _s, _t, _u, _v;
11978
12288
  const text = ((_b = (_a2 = clause.site) == null ? void 0 : _a2.text) == null ? void 0 : _b.trim()) || ((_e = (_d = (_c = clause.site) == null ? void 0 : _c.coding) == null ? void 0 : _d.display) == null ? void 0 : _e.trim());
11979
12289
  const lower = text == null ? void 0 : text.toLowerCase();
11980
12290
  const codingCode = (_g = (_f = clause.site) == null ? void 0 : _f.coding) == null ? void 0 : _g.code;
@@ -11989,14 +12299,14 @@ function formatSiteThai(clause, grammar) {
11989
12299
  if (isVaginalRoute && isVaginaSite) {
11990
12300
  return void 0;
11991
12301
  }
11992
- const translated = text ? translateSiteThai(text, codingCode, (_l = clause.site) == null ? void 0 : _l.spatialRelation) : translateSpatialSiteThai(void 0, (_m = clause.site) == null ? void 0 : _m.spatialRelation);
12302
+ const translated = (_t = (_q = (_m = (_l = clause.site) == null ? void 0 : _l.i18n) == null ? void 0 : _m.th) != null ? _q : (_p = (_o = (_n = clause.site) == null ? void 0 : _n.coding) == null ? void 0 : _o.i18n) == null ? void 0 : _p.th) != null ? _t : text ? translateSiteThai(text, codingCode, (_r = clause.site) == null ? void 0 : _r.spatialRelation) : translateSpatialSiteThai(void 0, (_s = clause.site) == null ? void 0 : _s.spatialRelation);
11993
12303
  if (!translated) {
11994
12304
  return void 0;
11995
12305
  }
11996
- if (((_n = clause.route) == null ? void 0 : _n.code) === RouteCode["Nasal route"]) {
12306
+ if (((_u = clause.route) == null ? void 0 : _u.code) === RouteCode["Nasal route"]) {
11997
12307
  return `\u0E40\u0E02\u0E49\u0E32${translated}`;
11998
12308
  }
11999
- const preposition = (_o = grammar.sitePreposition) != null ? _o : "\u0E17\u0E35\u0E48";
12309
+ const preposition = (_v = grammar.sitePreposition) != null ? _v : "\u0E17\u0E35\u0E48";
12000
12310
  const separator = /^[\u0E00-\u0E7F]/.test(translated) ? "" : " ";
12001
12311
  return `${preposition}${separator}${translated}`.trim();
12002
12312
  }
@@ -12294,7 +12604,7 @@ function formatLongThai(clause, options) {
12294
12604
  eventParts.push(`\u0E40\u0E27\u0E25\u0E32 ${timeStrings.join(", ")}`);
12295
12605
  }
12296
12606
  }
12297
- const timing = combineFrequencyAndEventsThai(frequencyPart, eventParts);
12607
+ const timing = combineFrequencyAndEventsThai(schedule, frequencyPart, eventParts, options);
12298
12608
  const dayPart = describeDayOfWeekThai(schedule);
12299
12609
  const countPart = schedule.count !== void 0 && !standaloneOccurrenceCount ? `\u0E08\u0E33\u0E19\u0E27\u0E19 ${stripTrailingZero2(schedule.count)} \u0E04\u0E23\u0E31\u0E49\u0E07` : void 0;
12300
12610
  const durationPart = describeDurationThai(schedule);
@@ -12726,6 +13036,12 @@ function sameOptionalScalar(left, right) {
12726
13036
  function mergeOptionalScalar(left, right) {
12727
13037
  return left !== void 0 ? left : right;
12728
13038
  }
13039
+ function mergeI18nRecords2(left, right) {
13040
+ if (!left && !right) {
13041
+ return void 0;
13042
+ }
13043
+ return __spreadValues(__spreadValues({}, left != null ? left : {}), right != null ? right : {});
13044
+ }
12729
13045
  function sameCoding(left, right) {
12730
13046
  var _a2, _b;
12731
13047
  if (!(left == null ? void 0 : left.code) || !(right == null ? void 0 : right.code)) {
@@ -12788,6 +13104,7 @@ function mergeSite(left, right, context) {
12788
13104
  }
12789
13105
  return {
12790
13106
  text: mergeOptionalScalar(left.text, right.text),
13107
+ i18n: mergeI18nRecords2(left.i18n, right.i18n),
12791
13108
  source: mergeOptionalScalar(left.source, right.source),
12792
13109
  coding: mergeOptionalScalar(left.coding, right.coding),
12793
13110
  spatialRelation: mergeOptionalScalar(left.spatialRelation, right.spatialRelation),
@@ -13135,6 +13452,7 @@ var TOKEN_SITE_CANDIDATES = {
13135
13452
  le: [{ text: "left eye", route: RouteCode["Ophthalmic route"], source: "abbreviation" }],
13136
13453
  ou: [{ text: "both eyes", route: RouteCode["Ophthalmic route"], source: "abbreviation" }],
13137
13454
  be: [{ text: "both eyes", route: RouteCode["Ophthalmic route"], source: "abbreviation" }],
13455
+ au: [{ text: "both ears", route: RouteCode["Otic route"], source: "abbreviation" }],
13138
13456
  vod: [
13139
13457
  {
13140
13458
  text: "right eye",
@@ -14740,6 +15058,11 @@ var unit_terminology_default = {
14740
15058
  unit: "pea-sized amount",
14741
15059
  kind: "product_specific_amount",
14742
15060
  aliases: [
15061
+ "pea",
15062
+ "pea amount",
15063
+ "peasize",
15064
+ "pea-size",
15065
+ "pea size",
14743
15066
  "pea sized amount",
14744
15067
  "pea-sized",
14745
15068
  "pea sized",
@@ -14836,10 +15159,96 @@ var unit_terminology_default = {
14836
15159
  ]
14837
15160
  };
14838
15161
 
15162
+ // src/utils/units.ts
15163
+ var MASS_UNITS = {
15164
+ kg: 1e6,
15165
+ g: 1e3,
15166
+ mg: 1,
15167
+ mcg: 1e-3,
15168
+ ug: 1e-3,
15169
+ microg: 1e-3,
15170
+ ng: 1e-6
15171
+ };
15172
+ var VOLUME_UNITS = {
15173
+ l: 1e3,
15174
+ dl: 100,
15175
+ ml: 1,
15176
+ ul: 1e-3,
15177
+ microl: 1e-3,
15178
+ cm3: 1,
15179
+ tsp: 5,
15180
+ tbsp: 15
15181
+ };
15182
+ function getUnitCategory(unit) {
15183
+ if (!unit) return "other";
15184
+ const u = unit.toLowerCase();
15185
+ if (MASS_UNITS[u] !== void 0) return "mass";
15186
+ if (VOLUME_UNITS[u] !== void 0) return "volume";
15187
+ return "other";
15188
+ }
15189
+ function getBaseUnitFactor(unit) {
15190
+ var _a2, _b;
15191
+ if (!unit) return 1;
15192
+ const u = unit.toLowerCase();
15193
+ return (_b = (_a2 = MASS_UNITS[u]) != null ? _a2 : VOLUME_UNITS[u]) != null ? _b : 1;
15194
+ }
15195
+ function convertValue(value, fromUnit, toUnit, strength) {
15196
+ const f = fromUnit.toLowerCase();
15197
+ const t = toUnit.toLowerCase();
15198
+ if (f === t) return value;
15199
+ const fCat = getUnitCategory(f);
15200
+ const tCat = getUnitCategory(t);
15201
+ if (fCat === tCat && fCat !== "other") {
15202
+ const fFactor = getBaseUnitFactor(f);
15203
+ const tFactor = getBaseUnitFactor(t);
15204
+ return value * fFactor / tFactor;
15205
+ }
15206
+ if (strength && (fCat === "mass" && tCat === "volume" || fCat === "volume" && tCat === "mass")) {
15207
+ const numUnit = strength.numerator.unit.toLowerCase();
15208
+ const denUnit = strength.denominator.unit.toLowerCase();
15209
+ const numCat = getUnitCategory(numUnit);
15210
+ const denCat = getUnitCategory(denUnit);
15211
+ if (numCat !== denCat && numCat !== "other" && denCat !== "other") {
15212
+ const massSide = numCat === "mass" ? strength.numerator : strength.denominator;
15213
+ const volSide = numCat === "volume" ? strength.numerator : strength.denominator;
15214
+ const bridgeDensity = massSide.value * getBaseUnitFactor(massSide.unit) / (volSide.value * getBaseUnitFactor(volSide.unit));
15215
+ if (fCat === "mass") {
15216
+ const valueMg = value * getBaseUnitFactor(fromUnit);
15217
+ const valueMl = valueMg / bridgeDensity;
15218
+ return valueMl / getBaseUnitFactor(toUnit);
15219
+ } else {
15220
+ const valueMl = value * getBaseUnitFactor(fromUnit);
15221
+ const valueMg = valueMl * bridgeDensity;
15222
+ return valueMg / getBaseUnitFactor(toUnit);
15223
+ }
15224
+ }
15225
+ }
15226
+ return null;
15227
+ }
15228
+
14839
15229
  // src/unit-lexicon.ts
14840
15230
  var HOUSEHOLD_VOLUME_UNIT_SET = new Set(
14841
15231
  HOUSEHOLD_VOLUME_UNITS.map((unit) => unit.toLowerCase())
14842
15232
  );
15233
+ var MASS_DISPENSED_SEMISOLID_DOSAGE_FORMS = /* @__PURE__ */ new Set([
15234
+ "cream",
15235
+ "ointment",
15236
+ "gel",
15237
+ "paste",
15238
+ "cutaneous paste",
15239
+ "vaginal cream",
15240
+ "vaginal gel",
15241
+ "oral gel",
15242
+ "oral paste",
15243
+ "oromucosal gel",
15244
+ "oromucosal paste",
15245
+ "dental gel",
15246
+ "dental paste",
15247
+ "gingival gel",
15248
+ "nasal gel",
15249
+ "eye gel",
15250
+ "eye ointment"
15251
+ ]);
14843
15252
  var DOSE_UNIT_TERMINOLOGY = unit_terminology_default.terms;
14844
15253
  var DOSE_UNIT_TERMINOLOGY_BY_KEY = /* @__PURE__ */ new Map();
14845
15254
  var DISCRETE_UNIT_KINDS = /* @__PURE__ */ new Set([
@@ -14902,6 +15311,47 @@ function unitApproximationOverride(unit, context) {
14902
15311
  }
14903
15312
  return void 0;
14904
15313
  }
15314
+ function normalizeDosageFormKey(form) {
15315
+ var _a2;
15316
+ const normalized = form == null ? void 0 : form.trim().toLowerCase();
15317
+ if (!normalized) {
15318
+ return void 0;
15319
+ }
15320
+ return (_a2 = KNOWN_DOSAGE_FORMS_TO_DOSE[normalized]) != null ? _a2 : normalized;
15321
+ }
15322
+ function getPreferredMassApproximationUnit(context) {
15323
+ var _a2;
15324
+ const normalizedDosageForm = normalizeDosageFormKey(context == null ? void 0 : context.dosageForm);
15325
+ if (!normalizedDosageForm || !MASS_DISPENSED_SEMISOLID_DOSAGE_FORMS.has(normalizedDosageForm)) {
15326
+ return void 0;
15327
+ }
15328
+ const containerUnit = (_a2 = context == null ? void 0 : context.containerUnit) == null ? void 0 : _a2.trim();
15329
+ if (containerUnit && getUnitCategory(containerUnit) === "mass") {
15330
+ return containerUnit;
15331
+ }
15332
+ const defaultUnit = normalizedDosageForm ? DEFAULT_UNIT_BY_NORMALIZED_FORM[normalizedDosageForm] : void 0;
15333
+ return defaultUnit && getUnitCategory(defaultUnit) === "mass" ? defaultUnit : void 0;
15334
+ }
15335
+ function bridgeApproximationToMassDispensedTopical(approximation, context) {
15336
+ const preferredMassUnit = getPreferredMassApproximationUnit(context);
15337
+ if (!preferredMassUnit || getUnitCategory(approximation.unit) !== "volume") {
15338
+ return approximation;
15339
+ }
15340
+ const sourceVolumeFactor = VOLUME_UNITS[approximation.unit.toLowerCase()];
15341
+ const targetMassFactor = MASS_UNITS[preferredMassUnit.toLowerCase()];
15342
+ if (!sourceVolumeFactor || !targetMassFactor) {
15343
+ return approximation;
15344
+ }
15345
+ const valueMl = approximation.value * sourceVolumeFactor;
15346
+ const valueG = valueMl;
15347
+ const convertedValue = valueG * MASS_UNITS.g / targetMassFactor;
15348
+ const bridgeBasis = "Mass-dispensed semisolid topical default bridge assumes 1 mL approximately equals 1 g unless a product-specific override is provided";
15349
+ return __spreadProps(__spreadValues({}, approximation), {
15350
+ value: convertedValue,
15351
+ unit: preferredMassUnit,
15352
+ basis: approximation.basis ? `${approximation.basis}; ${bridgeBasis}` : bridgeBasis
15353
+ });
15354
+ }
14905
15355
  function getDoseUnitTerminologyEntry(unit) {
14906
15356
  var _a2;
14907
15357
  if (!unit) {
@@ -14923,7 +15373,11 @@ function getDoseUnitApproximation(unit, context) {
14923
15373
  if (override) {
14924
15374
  return override;
14925
15375
  }
14926
- return terminologyEntry == null ? void 0 : terminologyEntry.approximateQuantity;
15376
+ const approximation = terminologyEntry == null ? void 0 : terminologyEntry.approximateQuantity;
15377
+ if (!approximation) {
15378
+ return void 0;
15379
+ }
15380
+ return bridgeApproximationToMassDispensedTopical(approximation, context);
14927
15381
  }
14928
15382
  function getDoseUnitSemantics(unit, context) {
14929
15383
  if (!unit) {
@@ -15684,6 +16138,9 @@ function inferRouteFromContext(ctx) {
15684
16138
  // src/hpsg/rules/site-rules.ts
15685
16139
  function siteBoundary(lower, context) {
15686
16140
  var _a2, _b, _c;
16141
+ if (SITE_MULTIPLICITY_WORDS.has(lower)) {
16142
+ return false;
16143
+ }
15687
16144
  const siteLike = Boolean(resolveBodySitePhrase(lower, (_a2 = context.options) == null ? void 0 : _a2.siteCodeMap, {
15688
16145
  bodySiteContext: (_c = (_b = context.options) == null ? void 0 : _b.context) == null ? void 0 : _c.bodySiteContext
15689
16146
  }));
@@ -15745,7 +16202,7 @@ function shouldSuppressEyeSiteAbbreviation(context, start, lower) {
15745
16202
  }
15746
16203
  function siteLexicalRule() {
15747
16204
  return lexicalRule("hpsg.lex.site", (context, start) => {
15748
- var _a2, _b, _c, _d, _e, _f, _g, _h, _i, _j, _k, _l, _m, _n, _o, _p, _q;
16205
+ var _a2, _b, _c, _d, _e, _f, _g, _h, _i, _j, _k, _l, _m, _n, _o, _p, _q, _r;
15749
16206
  const token = (_a2 = tokensAvailable(context, start, 1)) == null ? void 0 : _a2[0];
15750
16207
  if (!token) {
15751
16208
  return [];
@@ -15811,7 +16268,7 @@ function siteLexicalRule() {
15811
16268
  continue;
15812
16269
  }
15813
16270
  phraseTokens.push(candidate);
15814
- if (!SITE_DISPLAY_FILLERS.has(candidateLower)) {
16271
+ if (!SITE_DISPLAY_FILLERS.has(candidateLower) || SITE_MULTIPLICITY_WORDS.has(candidateLower)) {
15815
16272
  displayTokens.push(candidate);
15816
16273
  }
15817
16274
  }
@@ -15857,6 +16314,7 @@ function siteLexicalRule() {
15857
16314
  valence: {
15858
16315
  site: {
15859
16316
  text: displayText,
16317
+ i18n: (_r = resolved == null ? void 0 : resolved.definition) == null ? void 0 : _r.i18n,
15860
16318
  source: "text",
15861
16319
  coding: resolved == null ? void 0 : resolved.coding,
15862
16320
  spatialRelation: resolved == null ? void 0 : resolved.spatialRelation,
@@ -15884,7 +16342,7 @@ function siteLexicalRule() {
15884
16342
  }
15885
16343
  function bareSiteLexicalRule() {
15886
16344
  return lexicalRule("hpsg.lex.site.bare", (context, start) => {
15887
- var _a2, _b, _c, _d, _e, _f, _g, _h;
16345
+ var _a2, _b, _c, _d, _e, _f, _g, _h, _i;
15888
16346
  const signs = [];
15889
16347
  const first = (_a2 = tokensAvailable(context, start, 1)) == null ? void 0 : _a2[0];
15890
16348
  if (!first) {
@@ -15930,6 +16388,7 @@ function bareSiteLexicalRule() {
15930
16388
  valence: {
15931
16389
  site: {
15932
16390
  text: displayText,
16391
+ i18n: (_h = resolved.definition) == null ? void 0 : _h.i18n,
15933
16392
  source: "text",
15934
16393
  coding: resolved.coding,
15935
16394
  spatialRelation: resolved.spatialRelation,
@@ -15937,7 +16396,7 @@ function bareSiteLexicalRule() {
15937
16396
  originalText,
15938
16397
  text: sourceText,
15939
16398
  normalized: sourceText.toLowerCase(),
15940
- canonical: (_h = resolved.resolutionCanonical) != null ? _h : normalizeBodySiteKey(displayText),
16399
+ canonical: (_i = resolved.resolutionCanonical) != null ? _i : normalizeBodySiteKey(displayText),
15941
16400
  isProbe,
15942
16401
  inputText: context.state.input,
15943
16402
  sourceText,
@@ -16165,6 +16624,64 @@ function productLexicalRule() {
16165
16624
  }
16166
16625
  function matchCompoundDoseUnit(context, start, lower) {
16167
16626
  var _a2;
16627
+ const MAX_SITE_CONTEXT_TOKENS = 3;
16628
+ const hasSiteMeaning = (lowerValue) => {
16629
+ var _a3, _b, _c;
16630
+ return Boolean(
16631
+ lowerValue && (DEFAULT_BODY_SITE_SNOMED[normalizeBodySiteKey(lowerValue)] || resolveBodySitePhrase(lowerValue, (_a3 = context.options) == null ? void 0 : _a3.siteCodeMap, {
16632
+ bodySiteContext: (_c = (_b = context.options) == null ? void 0 : _b.context) == null ? void 0 : _c.bodySiteContext
16633
+ }))
16634
+ );
16635
+ };
16636
+ const collectForwardSitePhrases = (phraseStart) => {
16637
+ const parts = [];
16638
+ const phrases = [];
16639
+ for (let index = phraseStart; index < context.limit && parts.length < MAX_SITE_CONTEXT_TOKENS; index += 1) {
16640
+ const token = context.tokens[index];
16641
+ if (!token || context.state.consumed.has(token.index)) {
16642
+ break;
16643
+ }
16644
+ const lowerValue = normalizeTokenLower(token);
16645
+ if (!lowerValue || isPunctuation(lowerValue)) {
16646
+ break;
16647
+ }
16648
+ parts.push(lowerValue);
16649
+ phrases.push(parts.join(" "));
16650
+ }
16651
+ return phrases;
16652
+ };
16653
+ const matchesSiteContext = () => {
16654
+ const next = context.tokens[start + 1];
16655
+ const nextLower = next && !context.state.consumed.has(next.index) ? normalizeTokenLower(next) : void 0;
16656
+ if (nextLower && (ROUTE_SITE_PREPOSITIONS.has(nextLower) || SITE_ANCHORS.has(nextLower))) {
16657
+ const followingSitePhrases = collectForwardSitePhrases(start + 2);
16658
+ if (followingSitePhrases.some((phrase) => hasSiteMeaning(phrase))) {
16659
+ return true;
16660
+ }
16661
+ }
16662
+ const previous = context.tokens[start - 1];
16663
+ const previousLower = previous && !context.state.consumed.has(previous.index) ? normalizeTokenLower(previous) : void 0;
16664
+ const trailingNumberBeforeUnit = Boolean(
16665
+ previousLower && /^[0-9]+(?:\.[0-9]+)?$/.test(previousLower)
16666
+ );
16667
+ const siteEnd = start - (trailingNumberBeforeUnit ? 2 : 1);
16668
+ for (let phraseLength = 1; phraseLength <= MAX_SITE_CONTEXT_TOKENS; phraseLength += 1) {
16669
+ const phraseStart = siteEnd - phraseLength + 1;
16670
+ if (phraseStart < 0) {
16671
+ break;
16672
+ }
16673
+ const precedingAnchor = context.tokens[phraseStart - 1];
16674
+ const precedingAnchorLower = precedingAnchor && !context.state.consumed.has(precedingAnchor.index) ? normalizeTokenLower(precedingAnchor) : void 0;
16675
+ if (!precedingAnchorLower || !ROUTE_SITE_PREPOSITIONS.has(precedingAnchorLower) && !SITE_ANCHORS.has(precedingAnchorLower)) {
16676
+ continue;
16677
+ }
16678
+ const phrase = collectForwardSitePhrases(phraseStart)[phraseLength - 1];
16679
+ if (hasSiteMeaning(phrase)) {
16680
+ return true;
16681
+ }
16682
+ }
16683
+ return false;
16684
+ };
16168
16685
  for (const compound of COMPOUND_DOSE_UNITS) {
16169
16686
  if (compound.head !== lower) {
16170
16687
  continue;
@@ -16194,6 +16711,10 @@ function matchCompoundDoseUnit(context, start, lower) {
16194
16711
  return head ? { unit: compound.unit, tokens: [head, next] } : void 0;
16195
16712
  }
16196
16713
  }
16714
+ if (compound.requiresSiteContext && matchesSiteContext()) {
16715
+ const head = context.tokens[start];
16716
+ return head ? { unit: compound.unit, tokens: [head] } : void 0;
16717
+ }
16197
16718
  }
16198
16719
  return void 0;
16199
16720
  }
@@ -17964,6 +18485,9 @@ function applySiteDefinition(internal, definition) {
17964
18485
  } else if ((_b = internal.siteLookupRequest) == null ? void 0 : _b.text) {
17965
18486
  internal.siteText = internal.siteLookupRequest.text;
17966
18487
  }
18488
+ if (definition.administrationTargetCount !== void 0) {
18489
+ internal.siteAdministrationTargetCount = definition.administrationTargetCount;
18490
+ }
17967
18491
  if (definition.spatialRelation) {
17968
18492
  internal.siteSpatialRelation = definition.spatialRelation;
17969
18493
  } else if ((_c = internal.siteLookupRequest) == null ? void 0 : _c.spatialRelation) {
@@ -18316,6 +18840,9 @@ function seedKnownSiteCoding(state) {
18316
18840
  display: definition.coding.display,
18317
18841
  i18n: mergeI18nRecords(definition.i18n, definition.coding.i18n)
18318
18842
  };
18843
+ if (state.siteAdministrationTargetCount === void 0) {
18844
+ state.siteAdministrationTargetCount = definition.administrationTargetCount;
18845
+ }
18319
18846
  }
18320
18847
  function parseClauseState(input, options) {
18321
18848
  const tokens = tokenize(input);
@@ -19385,73 +19912,6 @@ function suggestSig(input, options) {
19385
19912
  );
19386
19913
  }
19387
19914
 
19388
- // src/utils/units.ts
19389
- var MASS_UNITS = {
19390
- kg: 1e6,
19391
- g: 1e3,
19392
- mg: 1,
19393
- mcg: 1e-3,
19394
- ug: 1e-3,
19395
- microg: 1e-3,
19396
- ng: 1e-6
19397
- };
19398
- var VOLUME_UNITS = {
19399
- l: 1e3,
19400
- dl: 100,
19401
- ml: 1,
19402
- ul: 1e-3,
19403
- microl: 1e-3,
19404
- cm3: 1,
19405
- tsp: 5,
19406
- tbsp: 15
19407
- };
19408
- function getUnitCategory(unit) {
19409
- if (!unit) return "other";
19410
- const u = unit.toLowerCase();
19411
- if (MASS_UNITS[u] !== void 0) return "mass";
19412
- if (VOLUME_UNITS[u] !== void 0) return "volume";
19413
- return "other";
19414
- }
19415
- function getBaseUnitFactor(unit) {
19416
- var _a2, _b;
19417
- if (!unit) return 1;
19418
- const u = unit.toLowerCase();
19419
- return (_b = (_a2 = MASS_UNITS[u]) != null ? _a2 : VOLUME_UNITS[u]) != null ? _b : 1;
19420
- }
19421
- function convertValue(value, fromUnit, toUnit, strength) {
19422
- const f = fromUnit.toLowerCase();
19423
- const t = toUnit.toLowerCase();
19424
- if (f === t) return value;
19425
- const fCat = getUnitCategory(f);
19426
- const tCat = getUnitCategory(t);
19427
- if (fCat === tCat && fCat !== "other") {
19428
- const fFactor = getBaseUnitFactor(f);
19429
- const tFactor = getBaseUnitFactor(t);
19430
- return value * fFactor / tFactor;
19431
- }
19432
- if (strength && (fCat === "mass" && tCat === "volume" || fCat === "volume" && tCat === "mass")) {
19433
- const numUnit = strength.numerator.unit.toLowerCase();
19434
- const denUnit = strength.denominator.unit.toLowerCase();
19435
- const numCat = getUnitCategory(numUnit);
19436
- const denCat = getUnitCategory(denUnit);
19437
- if (numCat !== denCat && numCat !== "other" && denCat !== "other") {
19438
- const massSide = numCat === "mass" ? strength.numerator : strength.denominator;
19439
- const volSide = numCat === "volume" ? strength.numerator : strength.denominator;
19440
- const bridgeDensity = massSide.value * getBaseUnitFactor(massSide.unit) / (volSide.value * getBaseUnitFactor(volSide.unit));
19441
- if (fCat === "mass") {
19442
- const valueMg = value * getBaseUnitFactor(fromUnit);
19443
- const valueMl = valueMg / bridgeDensity;
19444
- return valueMl / getBaseUnitFactor(toUnit);
19445
- } else {
19446
- const valueMl = value * getBaseUnitFactor(fromUnit);
19447
- const valueMg = valueMl * bridgeDensity;
19448
- return valueMg / getBaseUnitFactor(toUnit);
19449
- }
19450
- }
19451
- }
19452
- return null;
19453
- }
19454
-
19455
19915
  // src/utils/strength.ts
19456
19916
  function parseStrength(strength, context) {
19457
19917
  var _a2, _b, _c;
@@ -19646,6 +20106,21 @@ function normalizeClock(clock) {
19646
20106
  }
19647
20107
  return `${pad(hour)}:${pad(minute)}:${pad(second)}`;
19648
20108
  }
20109
+ function doseUnitSupportsPerTargetMultiplication(doseUnit, context) {
20110
+ const semantics = getDoseUnitSemantics(doseUnit, context);
20111
+ if (!semantics) {
20112
+ return false;
20113
+ }
20114
+ return semantics.kind !== "metric" && semantics.kind !== "biologic_unit";
20115
+ }
20116
+ function getAdministrationTargetMultiplier(dosage, context) {
20117
+ var _a2, _b, _c, _d;
20118
+ const doseUnit = (_c = (_b = (_a2 = dosage.doseAndRate) == null ? void 0 : _a2[0]) == null ? void 0 : _b.doseQuantity) == null ? void 0 : _c.unit;
20119
+ if (!doseUnitSupportsPerTargetMultiplication(doseUnit, context)) {
20120
+ return 1;
20121
+ }
20122
+ return (_d = getBodySiteAdministrationTargetCount(dosage.site)) != null ? _d : 1;
20123
+ }
19649
20124
  function getDateTimeFormat(timeZone) {
19650
20125
  let formatter = dateTimeFormatCache.get(timeZone);
19651
20126
  if (!formatter) {
@@ -19876,6 +20351,24 @@ function estimateIngredientQuantity(quantity, context) {
19876
20351
  if (!(numerator == null ? void 0 : numerator.unit) || numerator.value === void 0 || !(denominator == null ? void 0 : denominator.unit) || denominator.value === void 0) {
19877
20352
  return void 0;
19878
20353
  }
20354
+ const quantityCategory = getUnitCategory(quantity.unit);
20355
+ const denominatorCategory = getUnitCategory(denominator.unit);
20356
+ if (quantityCategory !== "other" && quantityCategory === denominatorCategory) {
20357
+ const quantityInDenominatorBase = quantity.value * getBaseUnitFactor(quantity.unit);
20358
+ const denominatorInBase = denominator.value * getBaseUnitFactor(denominator.unit);
20359
+ const numeratorInBase = numerator.value * getBaseUnitFactor(numerator.unit);
20360
+ if (denominatorInBase !== 0) {
20361
+ return {
20362
+ value: roundCalculatedUnits(
20363
+ quantityInDenominatorBase * numeratorInBase / denominatorInBase / getBaseUnitFactor(numerator.unit)
20364
+ ),
20365
+ unit: numerator.unit,
20366
+ confidence: quantity.confidence,
20367
+ basis: quantity.basis,
20368
+ source: quantity.source
20369
+ };
20370
+ }
20371
+ }
19879
20372
  const converted = convertValue(
19880
20373
  quantity.value,
19881
20374
  quantity.unit,
@@ -21065,7 +21558,8 @@ function calculateTotalUnitsSingle(options) {
21065
21558
  2e3
21066
21559
  );
21067
21560
  const doseQuantity = (_j = (_i = (_h = (_g = dosage.doseAndRate) == null ? void 0 : _g[0]) == null ? void 0 : _h.doseQuantity) == null ? void 0 : _i.value) != null ? _j : 0;
21068
- let totalUnits = roundCalculatedUnits(count * doseQuantity);
21561
+ const targetMultiplier = getAdministrationTargetMultiplier(dosage, context);
21562
+ let totalUnits = roundCalculatedUnits(count * doseQuantity * targetMultiplier);
21069
21563
  if (roundToMultiple && roundToMultiple > 0) {
21070
21564
  totalUnits = roundCalculatedUnits(Math.ceil(totalUnits / roundToMultiple) * roundToMultiple);
21071
21565
  }
@@ -21621,7 +22115,7 @@ function cloneBodySiteCoding2(coding) {
21621
22115
  };
21622
22116
  }
21623
22117
  function buildNormalizedMetaFromClause(clause, fhir, options) {
21624
- var _a2, _b, _c, _d, _e, _f, _g, _h, _i, _j, _k, _l, _m, _n, _o, _p, _q, _r, _s, _t, _u, _v, _w, _x, _y, _z, _A, _B, _C, _D, _E, _F;
22118
+ var _a2, _b, _c, _d, _e, _f, _g, _h, _i, _j, _k, _l, _m, _n, _o, _p, _q, _r, _s, _t, _u, _v, _w, _x, _y, _z, _A, _B, _C, _D, _E, _F, _G, _H;
21625
22119
  const additionalInstructions = ((_a2 = clause.additionalInstructions) == null ? void 0 : _a2.length) ? clause.additionalInstructions.map((instruction) => ({
21626
22120
  text: instruction.text,
21627
22121
  coding: cloneCoding2(instruction.coding)
@@ -21634,22 +22128,23 @@ function buildNormalizedMetaFromClause(clause, fhir, options) {
21634
22128
  unit: (_h = clause.dose) == null ? void 0 : _h.unit,
21635
22129
  unitKind: unitSemantics == null ? void 0 : unitSemantics.kind,
21636
22130
  unitSemantics,
21637
- site: ((_i = clause.site) == null ? void 0 : _i.text) || ((_k = (_j = clause.site) == null ? void 0 : _j.coding) == null ? void 0 : _k.code) || ((_l = clause.site) == null ? void 0 : _l.spatialRelation) ? {
21638
- text: (_m = clause.site) == null ? void 0 : _m.text,
22131
+ site: ((_i = clause.site) == null ? void 0 : _i.text) || ((_k = (_j = clause.site) == null ? void 0 : _j.coding) == null ? void 0 : _k.code) || ((_l = clause.site) == null ? void 0 : _l.spatialRelation) || ((_m = clause.site) == null ? void 0 : _m.administrationTargetCount) !== void 0 ? {
22132
+ text: (_n = clause.site) == null ? void 0 : _n.text,
21639
22133
  coding: siteCoding,
21640
- spatialRelation: cloneBodySiteSpatialRelation((_n = clause.site) == null ? void 0 : _n.spatialRelation)
22134
+ spatialRelation: cloneBodySiteSpatialRelation((_o = clause.site) == null ? void 0 : _o.spatialRelation),
22135
+ administrationTargetCount: (_p = clause.site) == null ? void 0 : _p.administrationTargetCount
21641
22136
  } : void 0,
21642
- method: ((_o = clause.method) == null ? void 0 : _o.text) || ((_q = (_p = clause.method) == null ? void 0 : _p.coding) == null ? void 0 : _q.code) ? {
21643
- text: (_r = clause.method) == null ? void 0 : _r.text,
21644
- coding: cloneCoding2((_s = clause.method) == null ? void 0 : _s.coding)
22137
+ method: ((_q = clause.method) == null ? void 0 : _q.text) || ((_s = (_r = clause.method) == null ? void 0 : _r.coding) == null ? void 0 : _s.code) ? {
22138
+ text: (_t = clause.method) == null ? void 0 : _t.text,
22139
+ coding: cloneCoding2((_u = clause.method) == null ? void 0 : _u.coding)
21645
22140
  } : void 0,
21646
22141
  patientInstruction: clause.patientInstruction,
21647
- prnReason: ((_u = (_t = clause.prn) == null ? void 0 : _t.reason) == null ? void 0 : _u.text) || ((_x = (_w = (_v = clause.prn) == null ? void 0 : _v.reason) == null ? void 0 : _w.coding) == null ? void 0 : _x.code) ? {
21648
- text: (_z = (_y = clause.prn) == null ? void 0 : _y.reason) == null ? void 0 : _z.text,
21649
- coding: cloneCoding2((_B = (_A = clause.prn) == null ? void 0 : _A.reason) == null ? void 0 : _B.coding),
21650
- spatialRelation: cloneBodySiteSpatialRelation((_D = (_C = clause.prn) == null ? void 0 : _C.reason) == null ? void 0 : _D.spatialRelation)
22142
+ prnReason: ((_w = (_v = clause.prn) == null ? void 0 : _v.reason) == null ? void 0 : _w.text) || ((_z = (_y = (_x = clause.prn) == null ? void 0 : _x.reason) == null ? void 0 : _y.coding) == null ? void 0 : _z.code) ? {
22143
+ text: (_B = (_A = clause.prn) == null ? void 0 : _A.reason) == null ? void 0 : _B.text,
22144
+ coding: cloneCoding2((_D = (_C = clause.prn) == null ? void 0 : _C.reason) == null ? void 0 : _D.coding),
22145
+ spatialRelation: cloneBodySiteSpatialRelation((_F = (_E = clause.prn) == null ? void 0 : _E.reason) == null ? void 0 : _F.spatialRelation)
21651
22146
  } : void 0,
21652
- prnReasons: ((_F = (_E = clause.prn) == null ? void 0 : _E.reasons) == null ? void 0 : _F.length) ? clause.prn.reasons.map((reason) => ({
22147
+ prnReasons: ((_H = (_G = clause.prn) == null ? void 0 : _G.reasons) == null ? void 0 : _H.length) ? clause.prn.reasons.map((reason) => ({
21653
22148
  text: reason.text,
21654
22149
  coding: cloneCoding2(reason.coding),
21655
22150
  spatialRelation: cloneBodySiteSpatialRelation(reason.spatialRelation)
@@ -21847,6 +22342,7 @@ export {
21847
22342
  AdviceModality,
21848
22343
  AdvicePolarity,
21849
22344
  AdviceRelation,
22345
+ BODY_SITE_ADMINISTRATION_TARGET_COUNT_EXTENSION_URL,
21850
22346
  BODY_SITE_SPATIAL_RELATION_EXTENSION_URL,
21851
22347
  DEFAULT_BODY_SITE_SNOMED,
21852
22348
  DEFAULT_BODY_SITE_SNOMED_SOURCE,
@@ -21871,6 +22367,7 @@ export {
21871
22367
  SNOMED_CT_TOPOGRAPHICAL_MODIFIER_CODE,
21872
22368
  SNOMED_CT_TOPOGRAPHICAL_MODIFIER_DISPLAY,
21873
22369
  SNOMED_SYSTEM,
22370
+ buildBodySiteAdministrationTargetCountExtension,
21874
22371
  buildBodySiteSpatialRelationExtension,
21875
22372
  buildBodySiteSpatialRelationExtensions,
21876
22373
  buildBodySiteTopographicalModifierCoding,
@@ -21884,6 +22381,7 @@ export {
21884
22381
  formatSig,
21885
22382
  formatSigBatch,
21886
22383
  fromFhirDosage,
22384
+ getBodySiteAdministrationTargetCount,
21887
22385
  getBodySiteCode,
21888
22386
  getBodySiteCodeAsync,
21889
22387
  getBodySiteText,
@@ -21902,6 +22400,7 @@ export {
21902
22400
  lookupBodySite,
21903
22401
  lookupBodySiteAsync,
21904
22402
  nextDueDoses,
22403
+ parseBodySiteAdministrationTargetCountExtension,
21905
22404
  parseBodySiteSpatialRelationExtension,
21906
22405
  parseSig,
21907
22406
  parseSigAsync,