ezmedicationinput 0.1.37 → 0.1.38

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -346,6 +346,10 @@ You can specify the number of times (total count) the medication is supposed to
346
346
  combinations (e.g. `1x3` → breakfast/lunch/dinner). This also respects
347
347
  `context.mealRelation` when provided and only applies to schedules with four
348
348
  or fewer daily doses.
349
+ - `enableMealDashSyntax`: when `true`, enables shorthand meal-dose patterns
350
+ such as `1-0-1`, `1-0-1 pc`, `10-12-0 ac`, and `1-0-0-1 ac`. The parser
351
+ expands them into multiple dosage clauses aligned to breakfast/lunch/dinner
352
+ (plus bedtime for a 4th slot).
349
353
  - `twoPerDayPair`: controls whether 2× AC/PC/C doses expand to breakfast+dinner (default) or breakfast+lunch.
350
354
  - `assumeSingleDiscreteDose`: when `true`, missing discrete doses (such as
351
355
  tablets or capsules) default to a single unit when the parser can infer a
package/dist/index.js CHANGED
@@ -58,6 +58,96 @@ Object.defineProperty(exports, "DEFAULT_BODY_SITE_SNOMED_SOURCE", { enumerable:
58
58
  Object.defineProperty(exports, "DEFAULT_ROUTE_SYNONYMS", { enumerable: true, get: function () { return maps_1.DEFAULT_ROUTE_SYNONYMS; } });
59
59
  Object.defineProperty(exports, "DEFAULT_UNIT_BY_ROUTE", { enumerable: true, get: function () { return maps_1.DEFAULT_UNIT_BY_ROUTE; } });
60
60
  Object.defineProperty(exports, "KNOWN_DOSAGE_FORMS_TO_DOSE", { enumerable: true, get: function () { return maps_1.KNOWN_DOSAGE_FORMS_TO_DOSE; } });
61
+ function parseMealDashValues(token) {
62
+ if (!/^[0-9]+(?:\.[0-9]+)?(?:-[0-9]+(?:\.[0-9]+)?){2,3}$/.test(token)) {
63
+ return undefined;
64
+ }
65
+ const values = token.split("-").map((part) => Number(part));
66
+ if (values.length !== 3 && values.length !== 4) {
67
+ return undefined;
68
+ }
69
+ if (!values.every((value) => Number.isFinite(value) && value >= 0)) {
70
+ return undefined;
71
+ }
72
+ return values;
73
+ }
74
+ function mealDashEvents(length, relation) {
75
+ const base = relation === "ac"
76
+ ? ["ACM", "ACD", "ACV"]
77
+ : relation === "pc"
78
+ ? ["PCM", "PCD", "PCV"]
79
+ : ["CM", "CD", "CV"];
80
+ if (length === 4) {
81
+ return [...base, "HS"];
82
+ }
83
+ return base;
84
+ }
85
+ function formatMealDashAmount(value) {
86
+ if (Number.isInteger(value)) {
87
+ return String(value);
88
+ }
89
+ return String(value).replace(/\.0+$/, "").replace(/(\.\d*?)0+$/, "$1");
90
+ }
91
+ function expandMealDashSegment(segment) {
92
+ const tokens = (0, parser_1.tokenize)(segment.text);
93
+ if (tokens.length === 0) {
94
+ return [segment];
95
+ }
96
+ const firstToken = tokens[0];
97
+ const values = parseMealDashValues(firstToken.lower);
98
+ if (!values) {
99
+ return [segment];
100
+ }
101
+ let relation = "meal";
102
+ let relationIndex = -1;
103
+ for (let i = 1; i < tokens.length; i += 1) {
104
+ const lower = tokens[i].lower.replace(/[.,;:]/g, "");
105
+ if (lower === "ac") {
106
+ relation = "ac";
107
+ relationIndex = i;
108
+ break;
109
+ }
110
+ if (lower === "pc") {
111
+ relation = "pc";
112
+ relationIndex = i;
113
+ break;
114
+ }
115
+ }
116
+ const suffixTokens = tokens
117
+ .filter((token, index) => index !== 0 && index !== relationIndex)
118
+ .map((token) => token.original);
119
+ const events = mealDashEvents(values.length, relation);
120
+ const expanded = values
121
+ .map((value, index) => ({ value, event: events[index] }))
122
+ .filter(({ value }) => value > 0)
123
+ .map(({ value, event }) => {
124
+ const text = [formatMealDashAmount(value), ...suffixTokens, event]
125
+ .filter((part) => part && part.trim().length > 0)
126
+ .join(" ")
127
+ .replace(/\s+/g, " ")
128
+ .trim();
129
+ return {
130
+ text,
131
+ start: segment.start,
132
+ end: segment.end
133
+ };
134
+ })
135
+ .filter((item) => item.text.length > 0);
136
+ if (expanded.length === 0) {
137
+ return [segment];
138
+ }
139
+ return expanded;
140
+ }
141
+ function expandMealDashSegments(segments, options) {
142
+ if (!(options === null || options === void 0 ? void 0 : options.enableMealDashSyntax)) {
143
+ return segments;
144
+ }
145
+ const expanded = [];
146
+ for (const segment of segments) {
147
+ expanded.push(...expandMealDashSegment(segment));
148
+ }
149
+ return expanded;
150
+ }
61
151
  function toSegmentMeta(segments) {
62
152
  return segments.map((segment, index) => ({
63
153
  index,
@@ -66,7 +156,7 @@ function toSegmentMeta(segments) {
66
156
  }));
67
157
  }
68
158
  function parseSig(input, options) {
69
- const segments = (0, segment_1.splitSigSegments)(input);
159
+ const segments = expandMealDashSegments((0, segment_1.splitSigSegments)(input), options);
70
160
  const carry = {};
71
161
  const results = [];
72
162
  for (const segment of segments) {
@@ -92,7 +182,7 @@ function parseSig(input, options) {
92
182
  };
93
183
  }
94
184
  function lintSig(input, options) {
95
- const segments = (0, segment_1.splitSigSegments)(input);
185
+ const segments = expandMealDashSegments((0, segment_1.splitSigSegments)(input), options);
96
186
  const carry = {};
97
187
  const results = [];
98
188
  for (const segment of segments) {
@@ -132,7 +222,7 @@ function lintSig(input, options) {
132
222
  }
133
223
  function parseSigAsync(input, options) {
134
224
  return __awaiter(this, void 0, void 0, function* () {
135
- const segments = (0, segment_1.splitSigSegments)(input);
225
+ const segments = expandMealDashSegments((0, segment_1.splitSigSegments)(input), options);
136
226
  const carry = {};
137
227
  const results = [];
138
228
  for (const segment of segments) {
package/dist/types.d.ts CHANGED
@@ -457,6 +457,13 @@ export interface ParseOptions extends FormatOptions {
457
457
  * `context.mealRelation` when provided.
458
458
  */
459
459
  smartMealExpansion?: boolean;
460
+ /**
461
+ * Enables parsing meal dash shorthand like `1-0-1` / `1-0-0-1` into
462
+ * multiple dosage clauses aligned to breakfast/lunch/dinner/(bedtime).
463
+ * Optional trailing `ac` / `pc` maps meal anchors to before/after meal
464
+ * variants.
465
+ */
466
+ enableMealDashSyntax?: boolean;
460
467
  /**
461
468
  * Controls which meal pair is assumed for twice-daily meal expansions.
462
469
  * Defaults to "breakfast+dinner" to mirror common clinical practice.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "ezmedicationinput",
3
- "version": "0.1.37",
3
+ "version": "0.1.38",
4
4
  "description": "Parse concise medication sigs into FHIR R5 Dosage JSON",
5
5
  "type": "module",
6
6
  "main": "dist/index.js",