ezmedicationinput 0.1.49 → 0.1.50

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.
@@ -1,8 +1,11 @@
1
1
  import { FhirExtension, FhirPrimitiveElement } from "./types";
2
2
  export declare const FHIR_TRANSLATION_EXTENSION_URL = "http://hl7.org/fhir/StructureDefinition/translation";
3
3
  export declare function cloneI18nRecord(i18n: Record<string, string> | undefined): Record<string, string> | undefined;
4
+ export declare function mergeI18nRecords(...records: Array<Record<string, string> | undefined>): Record<string, string> | undefined;
4
5
  export declare function cloneExtension(extension: FhirExtension): FhirExtension;
5
6
  export declare function cloneExtensions(extensions: FhirExtension[] | undefined): FhirExtension[] | undefined;
6
7
  export declare function clonePrimitiveElement(element: FhirPrimitiveElement | undefined): FhirPrimitiveElement | undefined;
7
8
  export declare function buildTranslationPrimitiveElement(translations: Record<string, string> | undefined, base?: FhirPrimitiveElement): FhirPrimitiveElement | undefined;
9
+ export declare function mergeTranslationPrimitiveElement(base: FhirPrimitiveElement | undefined, translations: Record<string, string> | undefined): FhirPrimitiveElement | undefined;
8
10
  export declare function getPrimitiveTranslation(element: FhirPrimitiveElement | undefined, locale: string | undefined): string | undefined;
11
+ export declare function getPrimitiveTranslations(element: FhirPrimitiveElement | undefined): Record<string, string> | undefined;
package/dist/fhir.d.ts CHANGED
@@ -7,6 +7,11 @@ export interface FhirProjectionOptions {
7
7
  * Dosage.site.coding while preserving the spatial-relation extension.
8
8
  */
9
9
  bodySitePostcoordination?: boolean;
10
+ /**
11
+ * Emits FHIR primitive translation extensions on coded concepts when
12
+ * translation metadata is available.
13
+ */
14
+ includeTranslationExtensions?: boolean;
10
15
  }
11
16
  export declare function canonicalToFhir(clause: CanonicalSigClause, textOverride?: string, options?: FhirProjectionOptions): FhirDosage;
12
17
  export declare function toFhir(state: ParserState): FhirDosage;
package/dist/index.cjs CHANGED
@@ -481,6 +481,24 @@ function normalizeLocaleKey(locale) {
481
481
  function cloneI18nRecord(i18n) {
482
482
  return i18n ? __spreadValues({}, i18n) : void 0;
483
483
  }
484
+ function mergeI18nRecords(...records) {
485
+ var _a2;
486
+ const merged = {};
487
+ for (const record of records) {
488
+ if (!record) {
489
+ continue;
490
+ }
491
+ for (const locale in record) {
492
+ const normalizedLocale = normalizeLocaleKey(locale);
493
+ const content = (_a2 = record[locale]) == null ? void 0 : _a2.trim();
494
+ if (!normalizedLocale || !content) {
495
+ continue;
496
+ }
497
+ merged[normalizedLocale] = content;
498
+ }
499
+ }
500
+ return Object.keys(merged).length ? merged : void 0;
501
+ }
484
502
  function cloneExtension(extension) {
485
503
  var _a2, _b, _c, _d;
486
504
  return {
@@ -567,6 +585,32 @@ function buildTranslationPrimitiveElement(translations, base) {
567
585
  extension: nextExtensions
568
586
  };
569
587
  }
588
+ function mergeTranslationPrimitiveElement(base, translations) {
589
+ var _a2, _b, _c, _d;
590
+ const nextExtensions = (_b = (_a2 = base == null ? void 0 : base.extension) == null ? void 0 : _a2.map(cloneExtension)) != null ? _b : [];
591
+ const existingTranslationLocales = /* @__PURE__ */ new Set();
592
+ for (const extension of nextExtensions) {
593
+ if (extension.url !== FHIR_TRANSLATION_EXTENSION_URL) {
594
+ continue;
595
+ }
596
+ const { locale } = getTranslationParts(extension);
597
+ if (locale) {
598
+ existingTranslationLocales.add(locale);
599
+ }
600
+ }
601
+ const additions = (_d = (_c = buildTranslationPrimitiveElement(translations)) == null ? void 0 : _c.extension) != null ? _d : [];
602
+ for (const extension of additions) {
603
+ const { locale } = getTranslationParts(extension);
604
+ if (locale && existingTranslationLocales.has(locale)) {
605
+ continue;
606
+ }
607
+ if (locale) {
608
+ existingTranslationLocales.add(locale);
609
+ }
610
+ nextExtensions.push(extension);
611
+ }
612
+ return nextExtensions.length ? { extension: nextExtensions } : void 0;
613
+ }
570
614
  function getTranslationParts(extension) {
571
615
  var _a2, _b;
572
616
  const parts = (_a2 = extension.extension) != null ? _a2 : [];
@@ -610,6 +654,24 @@ function getPrimitiveTranslation(element, locale) {
610
654
  }
611
655
  return languagePrefixMatch;
612
656
  }
657
+ function getPrimitiveTranslations(element) {
658
+ var _a2;
659
+ if (!((_a2 = element == null ? void 0 : element.extension) == null ? void 0 : _a2.length)) {
660
+ return void 0;
661
+ }
662
+ const translations = {};
663
+ for (const extension of element.extension) {
664
+ if (extension.url !== FHIR_TRANSLATION_EXTENSION_URL) {
665
+ continue;
666
+ }
667
+ const { locale, content } = getTranslationParts(extension);
668
+ if (!locale || !content) {
669
+ continue;
670
+ }
671
+ translations[locale] = content;
672
+ }
673
+ return Object.keys(translations).length ? translations : void 0;
674
+ }
613
675
 
614
676
  // src/body-site-spatial.ts
615
677
  var SNOMED_SYSTEM2 = "http://snomed.info/sct";
@@ -4596,7 +4658,7 @@ function buildBodySiteCoding(definition) {
4596
4658
  code: coding.code,
4597
4659
  display: coding.display,
4598
4660
  system: (_a2 = coding.system) != null ? _a2 : SNOMED_SYSTEM3,
4599
- i18n: definition == null ? void 0 : definition.i18n
4661
+ i18n: mergeI18nRecords(definition == null ? void 0 : definition.i18n, coding.i18n)
4600
4662
  };
4601
4663
  }
4602
4664
  function cloneBodySiteCode(coding) {
@@ -4608,7 +4670,7 @@ function cloneBodySiteCode(coding) {
4608
4670
  code: coding.code,
4609
4671
  display: coding.display,
4610
4672
  system: (_a2 = coding.system) != null ? _a2 : SNOMED_SYSTEM3,
4611
- i18n: coding.i18n
4673
+ i18n: mergeI18nRecords(coding.i18n)
4612
4674
  };
4613
4675
  }
4614
4676
  function lookupDefinitionForCanonical(canonical, customSiteMap) {
@@ -10031,6 +10093,7 @@ var ParserState = class {
10031
10093
  for (const reason of value) {
10032
10094
  reasons.push({
10033
10095
  text: reason.text,
10096
+ i18n: cloneI18nRecord(reason.i18n),
10034
10097
  spatialRelation: cloneBodySiteSpatialRelation(reason.spatialRelation),
10035
10098
  coding: reason.coding ? {
10036
10099
  code: reason.coding.code,
@@ -10038,7 +10101,7 @@ var ParserState = class {
10038
10101
  system: reason.coding.system,
10039
10102
  extension: cloneExtensions(reason.coding.extension),
10040
10103
  _display: clonePrimitiveElement(reason.coding._display),
10041
- i18n: reason.coding.i18n
10104
+ i18n: cloneI18nRecord(reason.coding.i18n)
10042
10105
  } : void 0
10043
10106
  });
10044
10107
  }
@@ -10070,7 +10133,7 @@ var ParserState = class {
10070
10133
  system: value.system,
10071
10134
  extension: cloneExtensions(value.extension),
10072
10135
  _display: clonePrimitiveElement(value._display),
10073
- i18n: value.i18n
10136
+ i18n: cloneI18nRecord(value.i18n)
10074
10137
  } : void 0;
10075
10138
  }
10076
10139
  get siteText() {
@@ -10103,7 +10166,7 @@ var ParserState = class {
10103
10166
  code: value.code,
10104
10167
  display: value.display,
10105
10168
  system: value.system,
10106
- i18n: value.i18n
10169
+ i18n: cloneI18nRecord(value.i18n)
10107
10170
  } : void 0;
10108
10171
  }
10109
10172
  get siteSpatialRelation() {
@@ -10288,12 +10351,12 @@ function selectCanonicalSiteCoding(site, options) {
10288
10351
  );
10289
10352
  return (options == null ? void 0 : options.bodySitePostcoordination) === true ? postcoordinated != null ? postcoordinated : site == null ? void 0 : site.coding : (_a2 = site == null ? void 0 : site.coding) != null ? _a2 : postcoordinated;
10290
10353
  }
10291
- function buildSiteCodingArray(siteCoding) {
10354
+ function buildSiteCodingArray(siteCoding, options) {
10292
10355
  var _a2;
10293
10356
  if (!(siteCoding == null ? void 0 : siteCoding.code)) {
10294
10357
  return void 0;
10295
10358
  }
10296
- const displayElement = buildTranslationPrimitiveElement(siteCoding.i18n);
10359
+ const displayElement = (options == null ? void 0 : options.includeTranslationExtensions) ? buildTranslationPrimitiveElement(siteCoding.i18n) : void 0;
10297
10360
  return [
10298
10361
  __spreadValues({
10299
10362
  system: (_a2 = siteCoding.system) != null ? _a2 : SNOMED_SYSTEM5,
@@ -10313,6 +10376,18 @@ function getFallbackSiteText(site) {
10313
10376
  display: siteCoding.display
10314
10377
  }) : void 0;
10315
10378
  }
10379
+ function codeableConceptTranslationI18n(concept, coding, fallback) {
10380
+ return {
10381
+ text: mergeI18nRecords(
10382
+ fallback,
10383
+ getPrimitiveTranslations(concept == null ? void 0 : concept._text)
10384
+ ),
10385
+ display: mergeI18nRecords(
10386
+ coding == null ? void 0 : coding.i18n,
10387
+ getPrimitiveTranslations(coding == null ? void 0 : coding._display)
10388
+ )
10389
+ };
10390
+ }
10316
10391
  function lowerFirst(value) {
10317
10392
  const trimmed = value == null ? void 0 : value.trim();
10318
10393
  return trimmed ? trimmed.charAt(0).toLowerCase() + trimmed.slice(1) : void 0;
@@ -10559,7 +10634,7 @@ function appendWarning(warnings, warning) {
10559
10634
  return warnings;
10560
10635
  }
10561
10636
  function canonicalToFhir(clause, textOverride, options) {
10562
- 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;
10637
+ 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;
10563
10638
  const dosage = {};
10564
10639
  const repeat = {};
10565
10640
  let hasRepeat = false;
@@ -10659,21 +10734,21 @@ function canonicalToFhir(clause, textOverride, options) {
10659
10734
  }
10660
10735
  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)) {
10661
10736
  const siteCoding = selectCanonicalSiteCoding(clause.site, options);
10662
- const siteTextElement = buildTranslationPrimitiveElement(siteCoding == null ? void 0 : siteCoding.i18n);
10737
+ const siteTextElement = (options == null ? void 0 : options.includeTranslationExtensions) ? buildTranslationPrimitiveElement((_p = clause.site.i18n) != null ? _p : siteCoding == null ? void 0 : siteCoding.i18n) : void 0;
10663
10738
  dosage.site = __spreadProps(__spreadValues({
10664
- text: (_p = clause.site) == null ? void 0 : _p.text
10739
+ text: (_q = clause.site) == null ? void 0 : _q.text
10665
10740
  }, siteTextElement ? { _text: siteTextElement } : {}), {
10666
- coding: buildSiteCodingArray(siteCoding),
10667
- extension: buildBodySiteSpatialRelationExtensions((_q = clause.site) == null ? void 0 : _q.spatialRelation)
10741
+ coding: buildSiteCodingArray(siteCoding, options),
10742
+ extension: buildBodySiteSpatialRelationExtensions((_r = clause.site) == null ? void 0 : _r.spatialRelation)
10668
10743
  });
10669
10744
  }
10670
- if (((_r = clause.method) == null ? void 0 : _r.text) || ((_s = clause.method) == null ? void 0 : _s._text) || ((_u = (_t = clause.method) == null ? void 0 : _t.coding) == null ? void 0 : _u.code)) {
10745
+ 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)) {
10671
10746
  dosage.method = {
10672
- text: (_v = clause.method) == null ? void 0 : _v.text,
10673
- _text: clonePrimitiveElement((_w = clause.method) == null ? void 0 : _w._text),
10674
- coding: ((_y = (_x = clause.method) == null ? void 0 : _x.coding) == null ? void 0 : _y.code) ? [
10747
+ text: (_w = clause.method) == null ? void 0 : _w.text,
10748
+ _text: clonePrimitiveElement((_x = clause.method) == null ? void 0 : _x._text),
10749
+ coding: ((_z = (_y = clause.method) == null ? void 0 : _y.coding) == null ? void 0 : _z.code) ? [
10675
10750
  {
10676
- system: (_z = clause.method.coding.system) != null ? _z : SNOMED_SYSTEM5,
10751
+ system: (_A = clause.method.coding.system) != null ? _A : SNOMED_SYSTEM5,
10677
10752
  code: clause.method.coding.code,
10678
10753
  display: clause.method.coding.display,
10679
10754
  _display: clonePrimitiveElement(clause.method.coding._display)
@@ -10681,14 +10756,14 @@ function canonicalToFhir(clause, textOverride, options) {
10681
10756
  ] : void 0
10682
10757
  };
10683
10758
  }
10684
- if ((_A = clause.additionalInstructions) == null ? void 0 : _A.length) {
10759
+ if ((_B = clause.additionalInstructions) == null ? void 0 : _B.length) {
10685
10760
  dosage.additionalInstruction = [];
10686
10761
  for (const instruction of clause.additionalInstructions) {
10687
10762
  dosage.additionalInstruction.push({
10688
10763
  text: instruction.text,
10689
- coding: ((_B = instruction.coding) == null ? void 0 : _B.code) ? [
10764
+ coding: ((_C = instruction.coding) == null ? void 0 : _C.code) ? [
10690
10765
  {
10691
- system: (_C = instruction.coding.system) != null ? _C : SNOMED_SYSTEM5,
10766
+ system: (_D = instruction.coding.system) != null ? _D : SNOMED_SYSTEM5,
10692
10767
  code: instruction.coding.code,
10693
10768
  display: instruction.coding.display
10694
10769
  }
@@ -10696,9 +10771,9 @@ function canonicalToFhir(clause, textOverride, options) {
10696
10771
  });
10697
10772
  }
10698
10773
  }
10699
- if ((_D = clause.prn) == null ? void 0 : _D.enabled) {
10774
+ if ((_E = clause.prn) == null ? void 0 : _E.enabled) {
10700
10775
  dosage.asNeededBoolean = true;
10701
- const reasons = ((_E = clause.prn.reasons) == null ? void 0 : _E.length) ? clause.prn.reasons : clause.prn.reason ? [clause.prn.reason] : [];
10776
+ const reasons = ((_F = clause.prn.reasons) == null ? void 0 : _F.length) ? clause.prn.reasons : clause.prn.reason ? [clause.prn.reason] : [];
10702
10777
  if (reasons.length) {
10703
10778
  dosage.asNeededFor = [];
10704
10779
  for (const reason of reasons) {
@@ -10706,15 +10781,18 @@ function canonicalToFhir(clause, textOverride, options) {
10706
10781
  if (reason.text) {
10707
10782
  concept.text = reason.text;
10708
10783
  }
10709
- const reasonTextElement = buildTranslationPrimitiveElement((_F = reason.coding) == null ? void 0 : _F.i18n);
10784
+ const reasonTextElement = (options == null ? void 0 : options.includeTranslationExtensions) ? buildTranslationPrimitiveElement((_H = reason.i18n) != null ? _H : (_G = reason.coding) == null ? void 0 : _G.i18n) : void 0;
10710
10785
  if (reasonTextElement) {
10711
10786
  concept._text = reasonTextElement;
10712
10787
  }
10713
- if ((_G = reason.coding) == null ? void 0 : _G.code) {
10714
- const displayElement = (_H = clonePrimitiveElement(reason.coding._display)) != null ? _H : buildTranslationPrimitiveElement(reason.coding.i18n);
10788
+ if ((_I = reason.coding) == null ? void 0 : _I.code) {
10789
+ const displayElement = (options == null ? void 0 : options.includeTranslationExtensions) ? mergeTranslationPrimitiveElement(
10790
+ reason.coding._display,
10791
+ reason.coding.i18n
10792
+ ) : clonePrimitiveElement(reason.coding._display);
10715
10793
  concept.coding = [
10716
10794
  __spreadProps(__spreadValues({
10717
- system: (_I = reason.coding.system) != null ? _I : SNOMED_SYSTEM5,
10795
+ system: (_J = reason.coding.system) != null ? _J : SNOMED_SYSTEM5,
10718
10796
  code: reason.coding.code,
10719
10797
  display: reason.coding.display
10720
10798
  }, displayElement ? { _display: displayElement } : {}), {
@@ -10754,14 +10832,17 @@ function canonicalFromFhir(dosage) {
10754
10832
  const siteCoding = selectPreferredSiteCoding(dosage.site);
10755
10833
  const siteSpatialRelation = parseBodySiteSpatialRelationExtension(dosage.site);
10756
10834
  const siteText = getFallbackSiteText(dosage.site);
10835
+ const siteI18n = codeableConceptTranslationI18n(dosage.site, siteCoding);
10757
10836
  if (siteText || (siteCoding == null ? void 0 : siteCoding.code) || siteSpatialRelation) {
10758
10837
  clause.site = {
10759
10838
  text: siteText,
10839
+ i18n: siteI18n.text,
10760
10840
  spatialRelation: siteSpatialRelation,
10761
10841
  coding: (siteCoding == null ? void 0 : siteCoding.code) ? {
10762
10842
  code: siteCoding.code,
10763
10843
  display: siteCoding.display,
10764
- system: siteCoding.system
10844
+ system: siteCoding.system,
10845
+ i18n: siteI18n.display
10765
10846
  } : void 0,
10766
10847
  source: "text"
10767
10848
  };
@@ -10816,16 +10897,21 @@ function canonicalFromFhir(dosage) {
10816
10897
  };
10817
10898
  }
10818
10899
  const prnReasons = ((_y = dosage.asNeededFor) == null ? void 0 : _y.length) ? dosage.asNeededFor.map((concept) => {
10819
- var _a3;
10900
+ var _a3, _b2;
10820
10901
  const coding = (_a3 = concept.coding) == null ? void 0 : _a3.find((code) => Boolean(code.code));
10902
+ const defaultDef = (coding == null ? void 0 : coding.code) ? findPrnReasonDefinitionByCoding((_b2 = coding.system) != null ? _b2 : SNOMED_SYSTEM5, coding.code) : void 0;
10903
+ const i18n = codeableConceptTranslationI18n(concept, coding, defaultDef == null ? void 0 : defaultDef.i18n);
10821
10904
  return {
10822
10905
  text: getFallbackPrnReasonText(concept),
10906
+ i18n: i18n.text,
10823
10907
  spatialRelation: parseBodySiteSpatialRelationExtension(concept),
10824
10908
  coding: (coding == null ? void 0 : coding.code) ? {
10825
10909
  code: coding.code,
10826
10910
  display: coding.display,
10827
10911
  system: coding.system,
10828
- extension: cloneExtensions(coding.extension)
10912
+ extension: cloneExtensions(coding.extension),
10913
+ _display: clonePrimitiveElement(coding._display),
10914
+ i18n: i18n.display
10829
10915
  } : void 0
10830
10916
  };
10831
10917
  }) : void 0;
@@ -16654,7 +16740,7 @@ function applyRouteSiteDefault(state) {
16654
16740
  system: (_i = definition.coding.system) != null ? _i : "http://snomed.info/sct",
16655
16741
  code: definition.coding.code,
16656
16742
  display: definition.coding.display,
16657
- i18n: definition.i18n
16743
+ i18n: mergeI18nRecords(definition.i18n, definition.coding.i18n)
16658
16744
  };
16659
16745
  }
16660
16746
  }
@@ -17967,7 +18053,7 @@ function applySiteDefinition(internal, definition) {
17967
18053
  code: coding.code,
17968
18054
  display: coding.display,
17969
18055
  system: (_a2 = coding.system) != null ? _a2 : SNOMED_SYSTEM9,
17970
- i18n: definition.i18n
18056
+ i18n: mergeI18nRecords(definition.i18n, coding.i18n)
17971
18057
  } : void 0;
17972
18058
  if (definition.text) {
17973
18059
  internal.siteText = definition.text;
@@ -18324,7 +18410,7 @@ function seedKnownSiteCoding(state) {
18324
18410
  system: (_b = definition.coding.system) != null ? _b : SNOMED_SYSTEM10,
18325
18411
  code: definition.coding.code,
18326
18412
  display: definition.coding.display,
18327
- i18n: definition.i18n
18413
+ i18n: mergeI18nRecords(definition.i18n, definition.coding.i18n)
18328
18414
  };
18329
18415
  }
18330
18416
  function parseClauseState(input, options) {
@@ -21626,7 +21712,8 @@ function cloneBodySiteCoding2(coding) {
21626
21712
  return {
21627
21713
  code: coding.code,
21628
21714
  display: coding.display,
21629
- system: coding.system
21715
+ system: coding.system,
21716
+ i18n: cloneI18nRecord(coding.i18n)
21630
21717
  };
21631
21718
  }
21632
21719
  function buildNormalizedMetaFromClause(clause, fhir, options) {
@@ -21673,7 +21760,8 @@ function buildParseResult(state, options) {
21673
21760
  const shortText = formatCanonicalClause(clause, "short", localization, options);
21674
21761
  const longText = formatCanonicalClause(clause, "long", localization, options);
21675
21762
  const fhir = canonicalToFhir(clause, longText, {
21676
- bodySitePostcoordination: options == null ? void 0 : options.bodySitePostcoordination
21763
+ bodySitePostcoordination: options == null ? void 0 : options.bodySitePostcoordination,
21764
+ includeTranslationExtensions: Boolean((options == null ? void 0 : options.locale) || (options == null ? void 0 : options.i18n))
21677
21765
  });
21678
21766
  const consumedTokens = [];
21679
21767
  const leftoverParts = [];
package/dist/index.js CHANGED
@@ -385,6 +385,24 @@ function normalizeLocaleKey(locale) {
385
385
  function cloneI18nRecord(i18n) {
386
386
  return i18n ? __spreadValues({}, i18n) : void 0;
387
387
  }
388
+ function mergeI18nRecords(...records) {
389
+ var _a2;
390
+ const merged = {};
391
+ for (const record of records) {
392
+ if (!record) {
393
+ continue;
394
+ }
395
+ for (const locale in record) {
396
+ const normalizedLocale = normalizeLocaleKey(locale);
397
+ const content = (_a2 = record[locale]) == null ? void 0 : _a2.trim();
398
+ if (!normalizedLocale || !content) {
399
+ continue;
400
+ }
401
+ merged[normalizedLocale] = content;
402
+ }
403
+ }
404
+ return Object.keys(merged).length ? merged : void 0;
405
+ }
388
406
  function cloneExtension(extension) {
389
407
  var _a2, _b, _c, _d;
390
408
  return {
@@ -471,6 +489,32 @@ function buildTranslationPrimitiveElement(translations, base) {
471
489
  extension: nextExtensions
472
490
  };
473
491
  }
492
+ function mergeTranslationPrimitiveElement(base, translations) {
493
+ var _a2, _b, _c, _d;
494
+ const nextExtensions = (_b = (_a2 = base == null ? void 0 : base.extension) == null ? void 0 : _a2.map(cloneExtension)) != null ? _b : [];
495
+ const existingTranslationLocales = /* @__PURE__ */ new Set();
496
+ for (const extension of nextExtensions) {
497
+ if (extension.url !== FHIR_TRANSLATION_EXTENSION_URL) {
498
+ continue;
499
+ }
500
+ const { locale } = getTranslationParts(extension);
501
+ if (locale) {
502
+ existingTranslationLocales.add(locale);
503
+ }
504
+ }
505
+ const additions = (_d = (_c = buildTranslationPrimitiveElement(translations)) == null ? void 0 : _c.extension) != null ? _d : [];
506
+ for (const extension of additions) {
507
+ const { locale } = getTranslationParts(extension);
508
+ if (locale && existingTranslationLocales.has(locale)) {
509
+ continue;
510
+ }
511
+ if (locale) {
512
+ existingTranslationLocales.add(locale);
513
+ }
514
+ nextExtensions.push(extension);
515
+ }
516
+ return nextExtensions.length ? { extension: nextExtensions } : void 0;
517
+ }
474
518
  function getTranslationParts(extension) {
475
519
  var _a2, _b;
476
520
  const parts = (_a2 = extension.extension) != null ? _a2 : [];
@@ -514,6 +558,24 @@ function getPrimitiveTranslation(element, locale) {
514
558
  }
515
559
  return languagePrefixMatch;
516
560
  }
561
+ function getPrimitiveTranslations(element) {
562
+ var _a2;
563
+ if (!((_a2 = element == null ? void 0 : element.extension) == null ? void 0 : _a2.length)) {
564
+ return void 0;
565
+ }
566
+ const translations = {};
567
+ for (const extension of element.extension) {
568
+ if (extension.url !== FHIR_TRANSLATION_EXTENSION_URL) {
569
+ continue;
570
+ }
571
+ const { locale, content } = getTranslationParts(extension);
572
+ if (!locale || !content) {
573
+ continue;
574
+ }
575
+ translations[locale] = content;
576
+ }
577
+ return Object.keys(translations).length ? translations : void 0;
578
+ }
517
579
 
518
580
  // src/body-site-spatial.ts
519
581
  var SNOMED_SYSTEM2 = "http://snomed.info/sct";
@@ -4500,7 +4562,7 @@ function buildBodySiteCoding(definition) {
4500
4562
  code: coding.code,
4501
4563
  display: coding.display,
4502
4564
  system: (_a2 = coding.system) != null ? _a2 : SNOMED_SYSTEM3,
4503
- i18n: definition == null ? void 0 : definition.i18n
4565
+ i18n: mergeI18nRecords(definition == null ? void 0 : definition.i18n, coding.i18n)
4504
4566
  };
4505
4567
  }
4506
4568
  function cloneBodySiteCode(coding) {
@@ -4512,7 +4574,7 @@ function cloneBodySiteCode(coding) {
4512
4574
  code: coding.code,
4513
4575
  display: coding.display,
4514
4576
  system: (_a2 = coding.system) != null ? _a2 : SNOMED_SYSTEM3,
4515
- i18n: coding.i18n
4577
+ i18n: mergeI18nRecords(coding.i18n)
4516
4578
  };
4517
4579
  }
4518
4580
  function lookupDefinitionForCanonical(canonical, customSiteMap) {
@@ -9935,6 +9997,7 @@ var ParserState = class {
9935
9997
  for (const reason of value) {
9936
9998
  reasons.push({
9937
9999
  text: reason.text,
10000
+ i18n: cloneI18nRecord(reason.i18n),
9938
10001
  spatialRelation: cloneBodySiteSpatialRelation(reason.spatialRelation),
9939
10002
  coding: reason.coding ? {
9940
10003
  code: reason.coding.code,
@@ -9942,7 +10005,7 @@ var ParserState = class {
9942
10005
  system: reason.coding.system,
9943
10006
  extension: cloneExtensions(reason.coding.extension),
9944
10007
  _display: clonePrimitiveElement(reason.coding._display),
9945
- i18n: reason.coding.i18n
10008
+ i18n: cloneI18nRecord(reason.coding.i18n)
9946
10009
  } : void 0
9947
10010
  });
9948
10011
  }
@@ -9974,7 +10037,7 @@ var ParserState = class {
9974
10037
  system: value.system,
9975
10038
  extension: cloneExtensions(value.extension),
9976
10039
  _display: clonePrimitiveElement(value._display),
9977
- i18n: value.i18n
10040
+ i18n: cloneI18nRecord(value.i18n)
9978
10041
  } : void 0;
9979
10042
  }
9980
10043
  get siteText() {
@@ -10007,7 +10070,7 @@ var ParserState = class {
10007
10070
  code: value.code,
10008
10071
  display: value.display,
10009
10072
  system: value.system,
10010
- i18n: value.i18n
10073
+ i18n: cloneI18nRecord(value.i18n)
10011
10074
  } : void 0;
10012
10075
  }
10013
10076
  get siteSpatialRelation() {
@@ -10192,12 +10255,12 @@ function selectCanonicalSiteCoding(site, options) {
10192
10255
  );
10193
10256
  return (options == null ? void 0 : options.bodySitePostcoordination) === true ? postcoordinated != null ? postcoordinated : site == null ? void 0 : site.coding : (_a2 = site == null ? void 0 : site.coding) != null ? _a2 : postcoordinated;
10194
10257
  }
10195
- function buildSiteCodingArray(siteCoding) {
10258
+ function buildSiteCodingArray(siteCoding, options) {
10196
10259
  var _a2;
10197
10260
  if (!(siteCoding == null ? void 0 : siteCoding.code)) {
10198
10261
  return void 0;
10199
10262
  }
10200
- const displayElement = buildTranslationPrimitiveElement(siteCoding.i18n);
10263
+ const displayElement = (options == null ? void 0 : options.includeTranslationExtensions) ? buildTranslationPrimitiveElement(siteCoding.i18n) : void 0;
10201
10264
  return [
10202
10265
  __spreadValues({
10203
10266
  system: (_a2 = siteCoding.system) != null ? _a2 : SNOMED_SYSTEM5,
@@ -10217,6 +10280,18 @@ function getFallbackSiteText(site) {
10217
10280
  display: siteCoding.display
10218
10281
  }) : void 0;
10219
10282
  }
10283
+ function codeableConceptTranslationI18n(concept, coding, fallback) {
10284
+ return {
10285
+ text: mergeI18nRecords(
10286
+ fallback,
10287
+ getPrimitiveTranslations(concept == null ? void 0 : concept._text)
10288
+ ),
10289
+ display: mergeI18nRecords(
10290
+ coding == null ? void 0 : coding.i18n,
10291
+ getPrimitiveTranslations(coding == null ? void 0 : coding._display)
10292
+ )
10293
+ };
10294
+ }
10220
10295
  function lowerFirst(value) {
10221
10296
  const trimmed = value == null ? void 0 : value.trim();
10222
10297
  return trimmed ? trimmed.charAt(0).toLowerCase() + trimmed.slice(1) : void 0;
@@ -10463,7 +10538,7 @@ function appendWarning(warnings, warning) {
10463
10538
  return warnings;
10464
10539
  }
10465
10540
  function canonicalToFhir(clause, textOverride, options) {
10466
- 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;
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;
10467
10542
  const dosage = {};
10468
10543
  const repeat = {};
10469
10544
  let hasRepeat = false;
@@ -10563,21 +10638,21 @@ function canonicalToFhir(clause, textOverride, options) {
10563
10638
  }
10564
10639
  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)) {
10565
10640
  const siteCoding = selectCanonicalSiteCoding(clause.site, options);
10566
- const siteTextElement = buildTranslationPrimitiveElement(siteCoding == null ? void 0 : siteCoding.i18n);
10641
+ const siteTextElement = (options == null ? void 0 : options.includeTranslationExtensions) ? buildTranslationPrimitiveElement((_p = clause.site.i18n) != null ? _p : siteCoding == null ? void 0 : siteCoding.i18n) : void 0;
10567
10642
  dosage.site = __spreadProps(__spreadValues({
10568
- text: (_p = clause.site) == null ? void 0 : _p.text
10643
+ text: (_q = clause.site) == null ? void 0 : _q.text
10569
10644
  }, siteTextElement ? { _text: siteTextElement } : {}), {
10570
- coding: buildSiteCodingArray(siteCoding),
10571
- extension: buildBodySiteSpatialRelationExtensions((_q = clause.site) == null ? void 0 : _q.spatialRelation)
10645
+ coding: buildSiteCodingArray(siteCoding, options),
10646
+ extension: buildBodySiteSpatialRelationExtensions((_r = clause.site) == null ? void 0 : _r.spatialRelation)
10572
10647
  });
10573
10648
  }
10574
- if (((_r = clause.method) == null ? void 0 : _r.text) || ((_s = clause.method) == null ? void 0 : _s._text) || ((_u = (_t = clause.method) == null ? void 0 : _t.coding) == null ? void 0 : _u.code)) {
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)) {
10575
10650
  dosage.method = {
10576
- text: (_v = clause.method) == null ? void 0 : _v.text,
10577
- _text: clonePrimitiveElement((_w = clause.method) == null ? void 0 : _w._text),
10578
- coding: ((_y = (_x = clause.method) == null ? void 0 : _x.coding) == null ? void 0 : _y.code) ? [
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) ? [
10579
10654
  {
10580
- system: (_z = clause.method.coding.system) != null ? _z : SNOMED_SYSTEM5,
10655
+ system: (_A = clause.method.coding.system) != null ? _A : SNOMED_SYSTEM5,
10581
10656
  code: clause.method.coding.code,
10582
10657
  display: clause.method.coding.display,
10583
10658
  _display: clonePrimitiveElement(clause.method.coding._display)
@@ -10585,14 +10660,14 @@ function canonicalToFhir(clause, textOverride, options) {
10585
10660
  ] : void 0
10586
10661
  };
10587
10662
  }
10588
- if ((_A = clause.additionalInstructions) == null ? void 0 : _A.length) {
10663
+ if ((_B = clause.additionalInstructions) == null ? void 0 : _B.length) {
10589
10664
  dosage.additionalInstruction = [];
10590
10665
  for (const instruction of clause.additionalInstructions) {
10591
10666
  dosage.additionalInstruction.push({
10592
10667
  text: instruction.text,
10593
- coding: ((_B = instruction.coding) == null ? void 0 : _B.code) ? [
10668
+ coding: ((_C = instruction.coding) == null ? void 0 : _C.code) ? [
10594
10669
  {
10595
- system: (_C = instruction.coding.system) != null ? _C : SNOMED_SYSTEM5,
10670
+ system: (_D = instruction.coding.system) != null ? _D : SNOMED_SYSTEM5,
10596
10671
  code: instruction.coding.code,
10597
10672
  display: instruction.coding.display
10598
10673
  }
@@ -10600,9 +10675,9 @@ function canonicalToFhir(clause, textOverride, options) {
10600
10675
  });
10601
10676
  }
10602
10677
  }
10603
- if ((_D = clause.prn) == null ? void 0 : _D.enabled) {
10678
+ if ((_E = clause.prn) == null ? void 0 : _E.enabled) {
10604
10679
  dosage.asNeededBoolean = true;
10605
- const reasons = ((_E = clause.prn.reasons) == null ? void 0 : _E.length) ? clause.prn.reasons : clause.prn.reason ? [clause.prn.reason] : [];
10680
+ const reasons = ((_F = clause.prn.reasons) == null ? void 0 : _F.length) ? clause.prn.reasons : clause.prn.reason ? [clause.prn.reason] : [];
10606
10681
  if (reasons.length) {
10607
10682
  dosage.asNeededFor = [];
10608
10683
  for (const reason of reasons) {
@@ -10610,15 +10685,18 @@ function canonicalToFhir(clause, textOverride, options) {
10610
10685
  if (reason.text) {
10611
10686
  concept.text = reason.text;
10612
10687
  }
10613
- const reasonTextElement = buildTranslationPrimitiveElement((_F = reason.coding) == null ? void 0 : _F.i18n);
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;
10614
10689
  if (reasonTextElement) {
10615
10690
  concept._text = reasonTextElement;
10616
10691
  }
10617
- if ((_G = reason.coding) == null ? void 0 : _G.code) {
10618
- const displayElement = (_H = clonePrimitiveElement(reason.coding._display)) != null ? _H : buildTranslationPrimitiveElement(reason.coding.i18n);
10692
+ if ((_I = reason.coding) == null ? void 0 : _I.code) {
10693
+ const displayElement = (options == null ? void 0 : options.includeTranslationExtensions) ? mergeTranslationPrimitiveElement(
10694
+ reason.coding._display,
10695
+ reason.coding.i18n
10696
+ ) : clonePrimitiveElement(reason.coding._display);
10619
10697
  concept.coding = [
10620
10698
  __spreadProps(__spreadValues({
10621
- system: (_I = reason.coding.system) != null ? _I : SNOMED_SYSTEM5,
10699
+ system: (_J = reason.coding.system) != null ? _J : SNOMED_SYSTEM5,
10622
10700
  code: reason.coding.code,
10623
10701
  display: reason.coding.display
10624
10702
  }, displayElement ? { _display: displayElement } : {}), {
@@ -10658,14 +10736,17 @@ function canonicalFromFhir(dosage) {
10658
10736
  const siteCoding = selectPreferredSiteCoding(dosage.site);
10659
10737
  const siteSpatialRelation = parseBodySiteSpatialRelationExtension(dosage.site);
10660
10738
  const siteText = getFallbackSiteText(dosage.site);
10739
+ const siteI18n = codeableConceptTranslationI18n(dosage.site, siteCoding);
10661
10740
  if (siteText || (siteCoding == null ? void 0 : siteCoding.code) || siteSpatialRelation) {
10662
10741
  clause.site = {
10663
10742
  text: siteText,
10743
+ i18n: siteI18n.text,
10664
10744
  spatialRelation: siteSpatialRelation,
10665
10745
  coding: (siteCoding == null ? void 0 : siteCoding.code) ? {
10666
10746
  code: siteCoding.code,
10667
10747
  display: siteCoding.display,
10668
- system: siteCoding.system
10748
+ system: siteCoding.system,
10749
+ i18n: siteI18n.display
10669
10750
  } : void 0,
10670
10751
  source: "text"
10671
10752
  };
@@ -10720,16 +10801,21 @@ function canonicalFromFhir(dosage) {
10720
10801
  };
10721
10802
  }
10722
10803
  const prnReasons = ((_y = dosage.asNeededFor) == null ? void 0 : _y.length) ? dosage.asNeededFor.map((concept) => {
10723
- var _a3;
10804
+ var _a3, _b2;
10724
10805
  const coding = (_a3 = concept.coding) == null ? void 0 : _a3.find((code) => Boolean(code.code));
10806
+ const defaultDef = (coding == null ? void 0 : coding.code) ? findPrnReasonDefinitionByCoding((_b2 = coding.system) != null ? _b2 : SNOMED_SYSTEM5, coding.code) : void 0;
10807
+ const i18n = codeableConceptTranslationI18n(concept, coding, defaultDef == null ? void 0 : defaultDef.i18n);
10725
10808
  return {
10726
10809
  text: getFallbackPrnReasonText(concept),
10810
+ i18n: i18n.text,
10727
10811
  spatialRelation: parseBodySiteSpatialRelationExtension(concept),
10728
10812
  coding: (coding == null ? void 0 : coding.code) ? {
10729
10813
  code: coding.code,
10730
10814
  display: coding.display,
10731
10815
  system: coding.system,
10732
- extension: cloneExtensions(coding.extension)
10816
+ extension: cloneExtensions(coding.extension),
10817
+ _display: clonePrimitiveElement(coding._display),
10818
+ i18n: i18n.display
10733
10819
  } : void 0
10734
10820
  };
10735
10821
  }) : void 0;
@@ -16558,7 +16644,7 @@ function applyRouteSiteDefault(state) {
16558
16644
  system: (_i = definition.coding.system) != null ? _i : "http://snomed.info/sct",
16559
16645
  code: definition.coding.code,
16560
16646
  display: definition.coding.display,
16561
- i18n: definition.i18n
16647
+ i18n: mergeI18nRecords(definition.i18n, definition.coding.i18n)
16562
16648
  };
16563
16649
  }
16564
16650
  }
@@ -17871,7 +17957,7 @@ function applySiteDefinition(internal, definition) {
17871
17957
  code: coding.code,
17872
17958
  display: coding.display,
17873
17959
  system: (_a2 = coding.system) != null ? _a2 : SNOMED_SYSTEM9,
17874
- i18n: definition.i18n
17960
+ i18n: mergeI18nRecords(definition.i18n, coding.i18n)
17875
17961
  } : void 0;
17876
17962
  if (definition.text) {
17877
17963
  internal.siteText = definition.text;
@@ -18228,7 +18314,7 @@ function seedKnownSiteCoding(state) {
18228
18314
  system: (_b = definition.coding.system) != null ? _b : SNOMED_SYSTEM10,
18229
18315
  code: definition.coding.code,
18230
18316
  display: definition.coding.display,
18231
- i18n: definition.i18n
18317
+ i18n: mergeI18nRecords(definition.i18n, definition.coding.i18n)
18232
18318
  };
18233
18319
  }
18234
18320
  function parseClauseState(input, options) {
@@ -21530,7 +21616,8 @@ function cloneBodySiteCoding2(coding) {
21530
21616
  return {
21531
21617
  code: coding.code,
21532
21618
  display: coding.display,
21533
- system: coding.system
21619
+ system: coding.system,
21620
+ i18n: cloneI18nRecord(coding.i18n)
21534
21621
  };
21535
21622
  }
21536
21623
  function buildNormalizedMetaFromClause(clause, fhir, options) {
@@ -21577,7 +21664,8 @@ function buildParseResult(state, options) {
21577
21664
  const shortText = formatCanonicalClause(clause, "short", localization, options);
21578
21665
  const longText = formatCanonicalClause(clause, "long", localization, options);
21579
21666
  const fhir = canonicalToFhir(clause, longText, {
21580
- bodySitePostcoordination: options == null ? void 0 : options.bodySitePostcoordination
21667
+ bodySitePostcoordination: options == null ? void 0 : options.bodySitePostcoordination,
21668
+ includeTranslationExtensions: Boolean((options == null ? void 0 : options.locale) || (options == null ? void 0 : options.i18n))
21581
21669
  });
21582
21670
  const consumedTokens = [];
21583
21671
  const leftoverParts = [];
package/dist/types.d.ts CHANGED
@@ -758,6 +758,7 @@ export interface CanonicalRouteExpr {
758
758
  }
759
759
  export interface CanonicalSiteExpr {
760
760
  text?: string;
761
+ i18n?: Record<string, string>;
761
762
  coding?: BodySiteCode;
762
763
  spatialRelation?: BodySiteSpatialRelation;
763
764
  source?: "abbreviation" | "text" | "selection" | "resolver";
@@ -788,6 +789,7 @@ export interface CanonicalScheduleExpr {
788
789
  }
789
790
  export interface CanonicalPrnReasonExpr {
790
791
  text?: string;
792
+ i18n?: Record<string, string>;
791
793
  coding?: FhirCoding;
792
794
  spatialRelation?: BodySiteSpatialRelation;
793
795
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "ezmedicationinput",
3
- "version": "0.1.49",
3
+ "version": "0.1.50",
4
4
  "description": "Parse concise medication sigs into FHIR R5 Dosage JSON",
5
5
  "type": "module",
6
6
  "main": "./dist/index.cjs",