ezmedicationinput 0.1.15 → 0.1.17
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 +56 -0
- package/dist/fhir.js +62 -7
- package/dist/format.js +39 -2
- package/dist/index.js +78 -4
- package/dist/internal-types.d.ts +12 -1
- package/dist/maps.d.ts +17 -1
- package/dist/maps.js +315 -1
- package/dist/parser.d.ts +2 -0
- package/dist/parser.js +817 -36
- package/dist/types.d.ts +65 -1
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -8,6 +8,7 @@
|
|
|
8
8
|
- Emits timing abbreviations (`timing.code`) and repeat structures simultaneously where possible.
|
|
9
9
|
- Maps meal/time blocks to the correct `Timing.repeat.when` **EventTiming** codes and can auto-expand AC/PC/C into specific meals.
|
|
10
10
|
- Outputs SNOMED CT route codings (while providing friendly text) and round-trips known SNOMED routes back into the parser.
|
|
11
|
+
- Auto-codes common PRN (as-needed) reasons and additional dosage instructions while keeping the raw text when no coding is available.
|
|
11
12
|
- Understands ocular and intravitreal shorthand (OD/OS/OU, LE/RE/BE, IVT*, VOD/VOS, etc.) and warns when intravitreal instructions omit an eye side.
|
|
12
13
|
- Parses fractional/ minute-based intervals (`q0.5h`, `q30 min`, `q1/4hr`) plus dose and timing ranges.
|
|
13
14
|
- Supports extensible dictionaries for routes, units, frequency shorthands, and event timing tokens.
|
|
@@ -50,6 +51,59 @@ Example output:
|
|
|
50
51
|
}
|
|
51
52
|
```
|
|
52
53
|
|
|
54
|
+
### PRN reasons & additional instructions
|
|
55
|
+
|
|
56
|
+
`parseSig` identifies PRN (as-needed) clauses and trailing instructions, then
|
|
57
|
+
codes them with SNOMED CT whenever possible.
|
|
58
|
+
|
|
59
|
+
```ts
|
|
60
|
+
const result = parseSig("1 tab po q4h prn headache; do not exceed 6 tabs/day");
|
|
61
|
+
|
|
62
|
+
result.fhir.asNeededFor;
|
|
63
|
+
// → [{
|
|
64
|
+
// text: "headache",
|
|
65
|
+
// coding: [{
|
|
66
|
+
// system: "http://snomed.info/sct",
|
|
67
|
+
// code: "25064002",
|
|
68
|
+
// display: "Headache"
|
|
69
|
+
// }]
|
|
70
|
+
// }]
|
|
71
|
+
|
|
72
|
+
result.fhir.additionalInstruction;
|
|
73
|
+
// → [{ text: "Do not exceed 6 tablets daily" }]
|
|
74
|
+
```
|
|
75
|
+
|
|
76
|
+
Customize the dictionaries and lookups through `ParseOptions`:
|
|
77
|
+
|
|
78
|
+
```ts
|
|
79
|
+
parseSig(input, {
|
|
80
|
+
prnReasonMap: {
|
|
81
|
+
migraine: {
|
|
82
|
+
text: "Migraine",
|
|
83
|
+
coding: {
|
|
84
|
+
system: "http://snomed.info/sct",
|
|
85
|
+
code: "37796009",
|
|
86
|
+
display: "Migraine"
|
|
87
|
+
}
|
|
88
|
+
}
|
|
89
|
+
},
|
|
90
|
+
prnReasonResolvers: async (request) => terminologyService.lookup(request),
|
|
91
|
+
prnReasonSuggestionResolvers: async (request) => terminologyService.suggest(request),
|
|
92
|
+
});
|
|
93
|
+
```
|
|
94
|
+
|
|
95
|
+
Use `{reason}` in the sig string (e.g. `prn {migraine}`) to force a lookup even
|
|
96
|
+
when a direct match exists. Additional instructions are sourced from a built-in
|
|
97
|
+
set of SNOMED CT concepts under *419492006 – Additional dosage instructions* and
|
|
98
|
+
fall back to plain text when no coding is available. Parsed instructions are
|
|
99
|
+
also echoed in `ParseResult.meta.normalized.additionalInstructions` for quick UI
|
|
100
|
+
rendering.
|
|
101
|
+
|
|
102
|
+
When a PRN reason cannot be auto-resolved, any registered suggestion resolvers
|
|
103
|
+
are invoked and their responses are surfaced through
|
|
104
|
+
`ParseResult.meta.prnReasonLookups` so client applications can prompt the user
|
|
105
|
+
to choose a coded concept.
|
|
106
|
+
|
|
53
107
|
### Sig (directions) suggestions
|
|
54
108
|
|
|
55
109
|
Use `suggestSig` to drive autocomplete experiences while the clinician is
|
|
@@ -126,6 +180,8 @@ result.fhir.site?.coding?.[0];
|
|
|
126
180
|
|
|
127
181
|
When the parser encounters an unfamiliar site, it leaves the text untouched and records nothing in `meta.siteLookups`. Wrapping the phrase in braces (e.g. `apply to {mole on scalp}`) preserves the same parsing behavior but flags the entry as a **probe** so `meta.siteLookups` always contains the request. This allows UIs to display lookup widgets even before a matching code exists. Braces are optional when the site is already recognized—they simply make the clinician's intent explicit.
|
|
128
182
|
|
|
183
|
+
Unknown body sites still populate `Dosage.site.text` and `ParseResult.meta.normalized.site.text`, allowing UIs to echo the verbatim phrase while terminology lookups run asynchronously.
|
|
184
|
+
|
|
129
185
|
You can extend or replace the built-in codings via `ParseOptions`:
|
|
130
186
|
|
|
131
187
|
```ts
|
package/dist/fhir.js
CHANGED
|
@@ -9,7 +9,7 @@ const object_1 = require("./utils/object");
|
|
|
9
9
|
const array_1 = require("./utils/array");
|
|
10
10
|
const SNOMED_SYSTEM = "http://snomed.info/sct";
|
|
11
11
|
function toFhir(internal) {
|
|
12
|
-
var _a, _b, _c, _d, _e;
|
|
12
|
+
var _a, _b, _c, _d, _e, _f, _g, _h, _j;
|
|
13
13
|
const dosage = {};
|
|
14
14
|
const repeat = {};
|
|
15
15
|
let hasRepeat = false;
|
|
@@ -115,10 +115,40 @@ function toFhir(internal) {
|
|
|
115
115
|
coding
|
|
116
116
|
};
|
|
117
117
|
}
|
|
118
|
+
if ((_f = internal.additionalInstructions) === null || _f === void 0 ? void 0 : _f.length) {
|
|
119
|
+
dosage.additionalInstruction = internal.additionalInstructions.map((instruction) => {
|
|
120
|
+
var _a, _b;
|
|
121
|
+
return ({
|
|
122
|
+
text: instruction.text,
|
|
123
|
+
coding: ((_a = instruction.coding) === null || _a === void 0 ? void 0 : _a.code)
|
|
124
|
+
? [
|
|
125
|
+
{
|
|
126
|
+
system: (_b = instruction.coding.system) !== null && _b !== void 0 ? _b : SNOMED_SYSTEM,
|
|
127
|
+
code: instruction.coding.code,
|
|
128
|
+
display: instruction.coding.display
|
|
129
|
+
}
|
|
130
|
+
]
|
|
131
|
+
: undefined
|
|
132
|
+
});
|
|
133
|
+
});
|
|
134
|
+
}
|
|
118
135
|
if (internal.asNeeded) {
|
|
119
136
|
dosage.asNeededBoolean = true;
|
|
120
|
-
if (internal.asNeededReason) {
|
|
121
|
-
|
|
137
|
+
if (internal.asNeededReason || ((_g = internal.asNeededReasonCoding) === null || _g === void 0 ? void 0 : _g.code)) {
|
|
138
|
+
const concept = {};
|
|
139
|
+
if (internal.asNeededReason) {
|
|
140
|
+
concept.text = internal.asNeededReason;
|
|
141
|
+
}
|
|
142
|
+
if ((_h = internal.asNeededReasonCoding) === null || _h === void 0 ? void 0 : _h.code) {
|
|
143
|
+
concept.coding = [
|
|
144
|
+
{
|
|
145
|
+
system: (_j = internal.asNeededReasonCoding.system) !== null && _j !== void 0 ? _j : SNOMED_SYSTEM,
|
|
146
|
+
code: internal.asNeededReasonCoding.code,
|
|
147
|
+
display: internal.asNeededReasonCoding.display
|
|
148
|
+
}
|
|
149
|
+
];
|
|
150
|
+
}
|
|
151
|
+
dosage.asNeededFor = [concept];
|
|
122
152
|
}
|
|
123
153
|
}
|
|
124
154
|
const longText = (0, format_1.formatInternal)(internal, "long");
|
|
@@ -128,7 +158,7 @@ function toFhir(internal) {
|
|
|
128
158
|
return dosage;
|
|
129
159
|
}
|
|
130
160
|
function internalFromFhir(dosage) {
|
|
131
|
-
var _a, _b, _c, _d, _e, _f, _g, _h, _j, _k, _l, _m, _o, _p, _q, _r, _s, _t, _u, _v, _w, _x, _y, _z, _0, _1, _2, _3, _4, _5, _6, _7;
|
|
161
|
+
var _a, _b, _c, _d, _e, _f, _g, _h, _j, _k, _l, _m, _o, _p, _q, _r, _s, _t, _u, _v, _w, _x, _y, _z, _0, _1, _2, _3, _4, _5, _6, _7, _8, _9, _10, _11;
|
|
132
162
|
const internal = {
|
|
133
163
|
input: (_a = dosage.text) !== null && _a !== void 0 ? _a : "",
|
|
134
164
|
tokens: [],
|
|
@@ -152,7 +182,9 @@ function internalFromFhir(dosage) {
|
|
|
152
182
|
asNeeded: dosage.asNeededBoolean,
|
|
153
183
|
asNeededReason: (_0 = (_z = dosage.asNeededFor) === null || _z === void 0 ? void 0 : _z[0]) === null || _0 === void 0 ? void 0 : _0.text,
|
|
154
184
|
siteTokenIndices: new Set(),
|
|
155
|
-
siteLookups: []
|
|
185
|
+
siteLookups: [],
|
|
186
|
+
prnReasonLookups: [],
|
|
187
|
+
additionalInstructions: []
|
|
156
188
|
};
|
|
157
189
|
const routeCoding = (_2 = (_1 = dosage.route) === null || _1 === void 0 ? void 0 : _1.coding) === null || _2 === void 0 ? void 0 : _2.find((code) => code.system === SNOMED_SYSTEM);
|
|
158
190
|
if (routeCoding === null || routeCoding === void 0 ? void 0 : routeCoding.code) {
|
|
@@ -171,13 +203,36 @@ function internalFromFhir(dosage) {
|
|
|
171
203
|
system: siteCoding.system
|
|
172
204
|
};
|
|
173
205
|
}
|
|
174
|
-
const
|
|
206
|
+
const reasonCoding = (_7 = (_6 = (_5 = dosage.asNeededFor) === null || _5 === void 0 ? void 0 : _5[0]) === null || _6 === void 0 ? void 0 : _6.coding) === null || _7 === void 0 ? void 0 : _7[0];
|
|
207
|
+
if (reasonCoding === null || reasonCoding === void 0 ? void 0 : reasonCoding.code) {
|
|
208
|
+
internal.asNeededReasonCoding = {
|
|
209
|
+
code: reasonCoding.code,
|
|
210
|
+
display: reasonCoding.display,
|
|
211
|
+
system: reasonCoding.system
|
|
212
|
+
};
|
|
213
|
+
}
|
|
214
|
+
if ((_8 = dosage.additionalInstruction) === null || _8 === void 0 ? void 0 : _8.length) {
|
|
215
|
+
internal.additionalInstructions = dosage.additionalInstruction.map((concept) => {
|
|
216
|
+
var _a;
|
|
217
|
+
return ({
|
|
218
|
+
text: concept.text,
|
|
219
|
+
coding: ((_a = concept.coding) === null || _a === void 0 ? void 0 : _a[0])
|
|
220
|
+
? {
|
|
221
|
+
code: concept.coding[0].code,
|
|
222
|
+
display: concept.coding[0].display,
|
|
223
|
+
system: concept.coding[0].system
|
|
224
|
+
}
|
|
225
|
+
: undefined
|
|
226
|
+
});
|
|
227
|
+
});
|
|
228
|
+
}
|
|
229
|
+
const doseAndRate = (_9 = dosage.doseAndRate) === null || _9 === void 0 ? void 0 : _9[0];
|
|
175
230
|
if (doseAndRate === null || doseAndRate === void 0 ? void 0 : doseAndRate.doseRange) {
|
|
176
231
|
const { low, high } = doseAndRate.doseRange;
|
|
177
232
|
if ((low === null || low === void 0 ? void 0 : low.value) !== undefined && (high === null || high === void 0 ? void 0 : high.value) !== undefined) {
|
|
178
233
|
internal.doseRange = { low: low.value, high: high.value };
|
|
179
234
|
}
|
|
180
|
-
internal.unit = (
|
|
235
|
+
internal.unit = (_11 = (_10 = low === null || low === void 0 ? void 0 : low.unit) !== null && _10 !== void 0 ? _10 : high === null || high === void 0 ? void 0 : high.unit) !== null && _11 !== void 0 ? _11 : internal.unit;
|
|
181
236
|
}
|
|
182
237
|
else if (doseAndRate === null || doseAndRate === void 0 ? void 0 : doseAndRate.doseQuantity) {
|
|
183
238
|
const dose = doseAndRate.doseQuantity;
|
package/dist/format.js
CHANGED
|
@@ -69,6 +69,11 @@ const ROUTE_GRAMMAR = {
|
|
|
69
69
|
routePhrase: ({ hasSite }) => (hasSite ? undefined : "into the eye"),
|
|
70
70
|
sitePreposition: "into"
|
|
71
71
|
},
|
|
72
|
+
[types_1.RouteCode["Per rectum"]]: {
|
|
73
|
+
verb: "Use",
|
|
74
|
+
routePhrase: ({ hasSite }) => (hasSite ? undefined : "rectally"),
|
|
75
|
+
sitePreposition: "into"
|
|
76
|
+
},
|
|
72
77
|
[types_1.RouteCode["Topical route"]]: {
|
|
73
78
|
verb: "Apply",
|
|
74
79
|
routePhrase: ({ hasSite }) => (hasSite ? undefined : "topically"),
|
|
@@ -137,6 +142,9 @@ function grammarFromRouteText(text) {
|
|
|
137
142
|
if (normalized.includes("intravenous") || normalized === "iv") {
|
|
138
143
|
return ROUTE_GRAMMAR[types_1.RouteCode["Intravenous route"]];
|
|
139
144
|
}
|
|
145
|
+
if (normalized.includes("rectal") || normalized.includes("rectum")) {
|
|
146
|
+
return ROUTE_GRAMMAR[types_1.RouteCode["Per rectum"]];
|
|
147
|
+
}
|
|
140
148
|
if (normalized.includes("nasal")) {
|
|
141
149
|
return ROUTE_GRAMMAR[types_1.RouteCode["Nasal route"]];
|
|
142
150
|
}
|
|
@@ -412,6 +420,11 @@ function formatSite(internal, grammar) {
|
|
|
412
420
|
return undefined;
|
|
413
421
|
}
|
|
414
422
|
const lower = text.toLowerCase();
|
|
423
|
+
if (internal.routeCode === types_1.RouteCode["Per rectum"]) {
|
|
424
|
+
if (lower === "rectum" || lower === "rectal") {
|
|
425
|
+
return undefined;
|
|
426
|
+
}
|
|
427
|
+
}
|
|
415
428
|
let preposition = grammar.sitePreposition;
|
|
416
429
|
if (!preposition) {
|
|
417
430
|
if (lower.includes("eye")) {
|
|
@@ -603,9 +616,33 @@ function formatLong(internal) {
|
|
|
603
616
|
}
|
|
604
617
|
const body = segments.filter(Boolean).join(" ").replace(/\s+/g, " ").trim();
|
|
605
618
|
if (!body) {
|
|
606
|
-
|
|
619
|
+
const instructionText = formatAdditionalInstructions(internal);
|
|
620
|
+
if (!instructionText) {
|
|
621
|
+
return `${grammar.verb}.`;
|
|
622
|
+
}
|
|
623
|
+
return `${grammar.verb}. ${instructionText}`.trim();
|
|
624
|
+
}
|
|
625
|
+
const instructionText = formatAdditionalInstructions(internal);
|
|
626
|
+
const baseSentence = `${grammar.verb} ${body}.`;
|
|
627
|
+
return instructionText ? `${baseSentence} ${instructionText}` : baseSentence;
|
|
628
|
+
}
|
|
629
|
+
function formatAdditionalInstructions(internal) {
|
|
630
|
+
var _a;
|
|
631
|
+
if (!((_a = internal.additionalInstructions) === null || _a === void 0 ? void 0 : _a.length)) {
|
|
632
|
+
return undefined;
|
|
633
|
+
}
|
|
634
|
+
const phrases = internal.additionalInstructions
|
|
635
|
+
.map((instruction) => { var _a; return instruction.text || ((_a = instruction.coding) === null || _a === void 0 ? void 0 : _a.display); })
|
|
636
|
+
.filter((text) => Boolean(text))
|
|
637
|
+
.map((text) => text.trim())
|
|
638
|
+
.filter((text) => text.length > 0);
|
|
639
|
+
if (!phrases.length) {
|
|
640
|
+
return undefined;
|
|
607
641
|
}
|
|
608
|
-
return
|
|
642
|
+
return phrases
|
|
643
|
+
.map((phrase) => (/[.!?]$/.test(phrase) ? phrase : `${phrase}.`))
|
|
644
|
+
.join(" ")
|
|
645
|
+
.trim();
|
|
609
646
|
}
|
|
610
647
|
function stripTrailingZero(value) {
|
|
611
648
|
const text = value.toString();
|
package/dist/index.js
CHANGED
|
@@ -46,12 +46,14 @@ Object.defineProperty(exports, "resolveSigLocalization", { enumerable: true, get
|
|
|
46
46
|
Object.defineProperty(exports, "resolveSigTranslation", { enumerable: true, get: function () { return i18n_2.resolveSigTranslation; } });
|
|
47
47
|
function parseSig(input, options) {
|
|
48
48
|
const internal = (0, parser_1.parseInternal)(input, options);
|
|
49
|
+
(0, parser_1.applyPrnReasonCoding)(internal, options);
|
|
49
50
|
(0, parser_1.applySiteCoding)(internal, options);
|
|
50
51
|
return buildParseResult(internal, options);
|
|
51
52
|
}
|
|
52
53
|
function parseSigAsync(input, options) {
|
|
53
54
|
return __awaiter(this, void 0, void 0, function* () {
|
|
54
55
|
const internal = (0, parser_1.parseInternal)(input, options);
|
|
56
|
+
yield (0, parser_1.applyPrnReasonCodingAsync)(internal, options);
|
|
55
57
|
yield (0, parser_1.applySiteCodingAsync)(internal, options);
|
|
56
58
|
return buildParseResult(internal, options);
|
|
57
59
|
});
|
|
@@ -62,7 +64,7 @@ function formatSig(dosage, style = "short", options) {
|
|
|
62
64
|
return (0, format_1.formatInternal)(internal, style, localization);
|
|
63
65
|
}
|
|
64
66
|
function fromFhirDosage(dosage, options) {
|
|
65
|
-
var _a, _b, _c;
|
|
67
|
+
var _a, _b, _c, _d, _e, _f;
|
|
66
68
|
const internal = (0, fhir_1.internalFromFhir)(dosage);
|
|
67
69
|
const localization = (0, i18n_1.resolveSigLocalization)(options === null || options === void 0 ? void 0 : options.locale, options === null || options === void 0 ? void 0 : options.i18n);
|
|
68
70
|
const shortText = (0, format_1.formatInternal)(internal, "short", localization);
|
|
@@ -89,13 +91,40 @@ function fromFhirDosage(dosage, options) {
|
|
|
89
91
|
}
|
|
90
92
|
: undefined
|
|
91
93
|
}
|
|
94
|
+
: undefined,
|
|
95
|
+
prnReason: internal.asNeededReason || ((_d = internal.asNeededReasonCoding) === null || _d === void 0 ? void 0 : _d.code)
|
|
96
|
+
? {
|
|
97
|
+
text: internal.asNeededReason,
|
|
98
|
+
coding: ((_e = internal.asNeededReasonCoding) === null || _e === void 0 ? void 0 : _e.code)
|
|
99
|
+
? {
|
|
100
|
+
code: internal.asNeededReasonCoding.code,
|
|
101
|
+
display: internal.asNeededReasonCoding.display,
|
|
102
|
+
system: internal.asNeededReasonCoding.system
|
|
103
|
+
}
|
|
104
|
+
: undefined
|
|
105
|
+
}
|
|
106
|
+
: undefined,
|
|
107
|
+
additionalInstructions: ((_f = internal.additionalInstructions) === null || _f === void 0 ? void 0 : _f.length)
|
|
108
|
+
? internal.additionalInstructions.map((instruction) => {
|
|
109
|
+
var _a;
|
|
110
|
+
return ({
|
|
111
|
+
text: instruction.text,
|
|
112
|
+
coding: ((_a = instruction.coding) === null || _a === void 0 ? void 0 : _a.code)
|
|
113
|
+
? {
|
|
114
|
+
code: instruction.coding.code,
|
|
115
|
+
display: instruction.coding.display,
|
|
116
|
+
system: instruction.coding.system
|
|
117
|
+
}
|
|
118
|
+
: undefined
|
|
119
|
+
});
|
|
120
|
+
})
|
|
92
121
|
: undefined
|
|
93
122
|
}
|
|
94
123
|
}
|
|
95
124
|
};
|
|
96
125
|
}
|
|
97
126
|
function buildParseResult(internal, options) {
|
|
98
|
-
var _a;
|
|
127
|
+
var _a, _b, _c;
|
|
99
128
|
const localization = (0, i18n_1.resolveSigLocalization)(options === null || options === void 0 ? void 0 : options.locale, options === null || options === void 0 ? void 0 : options.i18n);
|
|
100
129
|
const shortText = (0, format_1.formatInternal)(internal, "short", localization);
|
|
101
130
|
const longText = (0, format_1.formatInternal)(internal, "long", localization);
|
|
@@ -114,6 +143,28 @@ function buildParseResult(internal, options) {
|
|
|
114
143
|
system: internal.siteCoding.system
|
|
115
144
|
}
|
|
116
145
|
: undefined;
|
|
146
|
+
const prnReasonCoding = ((_b = internal.asNeededReasonCoding) === null || _b === void 0 ? void 0 : _b.code)
|
|
147
|
+
? {
|
|
148
|
+
code: internal.asNeededReasonCoding.code,
|
|
149
|
+
display: internal.asNeededReasonCoding.display,
|
|
150
|
+
system: internal.asNeededReasonCoding.system
|
|
151
|
+
}
|
|
152
|
+
: undefined;
|
|
153
|
+
const additionalInstructions = ((_c = internal.additionalInstructions) === null || _c === void 0 ? void 0 : _c.length)
|
|
154
|
+
? internal.additionalInstructions.map((instruction) => {
|
|
155
|
+
var _a;
|
|
156
|
+
return ({
|
|
157
|
+
text: instruction.text,
|
|
158
|
+
coding: ((_a = instruction.coding) === null || _a === void 0 ? void 0 : _a.code)
|
|
159
|
+
? {
|
|
160
|
+
code: instruction.coding.code,
|
|
161
|
+
display: instruction.coding.display,
|
|
162
|
+
system: instruction.coding.system
|
|
163
|
+
}
|
|
164
|
+
: undefined
|
|
165
|
+
});
|
|
166
|
+
})
|
|
167
|
+
: undefined;
|
|
117
168
|
const siteLookups = internal.siteLookups.length
|
|
118
169
|
? internal.siteLookups.map((entry) => ({
|
|
119
170
|
request: entry.request,
|
|
@@ -127,6 +178,21 @@ function buildParseResult(internal, options) {
|
|
|
127
178
|
}))
|
|
128
179
|
}))
|
|
129
180
|
: undefined;
|
|
181
|
+
const prnReasonLookups = internal.prnReasonLookups.length
|
|
182
|
+
? internal.prnReasonLookups.map((entry) => ({
|
|
183
|
+
request: entry.request,
|
|
184
|
+
suggestions: entry.suggestions.map((suggestion) => ({
|
|
185
|
+
coding: suggestion.coding
|
|
186
|
+
? {
|
|
187
|
+
code: suggestion.coding.code,
|
|
188
|
+
display: suggestion.coding.display,
|
|
189
|
+
system: suggestion.coding.system
|
|
190
|
+
}
|
|
191
|
+
: undefined,
|
|
192
|
+
text: suggestion.text
|
|
193
|
+
}))
|
|
194
|
+
}))
|
|
195
|
+
: undefined;
|
|
130
196
|
return {
|
|
131
197
|
fhir,
|
|
132
198
|
shortText,
|
|
@@ -145,9 +211,17 @@ function buildParseResult(internal, options) {
|
|
|
145
211
|
text: internal.siteText,
|
|
146
212
|
coding: siteCoding
|
|
147
213
|
}
|
|
148
|
-
: undefined
|
|
214
|
+
: undefined,
|
|
215
|
+
prnReason: internal.asNeededReason || prnReasonCoding
|
|
216
|
+
? {
|
|
217
|
+
text: internal.asNeededReason,
|
|
218
|
+
coding: prnReasonCoding
|
|
219
|
+
}
|
|
220
|
+
: undefined,
|
|
221
|
+
additionalInstructions
|
|
149
222
|
},
|
|
150
|
-
siteLookups
|
|
223
|
+
siteLookups,
|
|
224
|
+
prnReasonLookups
|
|
151
225
|
}
|
|
152
226
|
};
|
|
153
227
|
}
|
package/dist/internal-types.d.ts
CHANGED
|
@@ -1,8 +1,12 @@
|
|
|
1
|
-
import { EventTiming, FhirCoding, FhirDayOfWeek, FhirPeriodUnit, RouteCode, SiteCodeLookupRequest, SiteCodeSuggestion } from "./types";
|
|
1
|
+
import { EventTiming, FhirCoding, FhirDayOfWeek, FhirPeriodUnit, PrnReasonLookupRequest, PrnReasonSuggestion, RouteCode, SiteCodeLookupRequest, SiteCodeSuggestion } from "./types";
|
|
2
2
|
export interface SiteLookupDetail {
|
|
3
3
|
request: SiteCodeLookupRequest;
|
|
4
4
|
suggestions: SiteCodeSuggestion[];
|
|
5
5
|
}
|
|
6
|
+
export interface PrnReasonLookupDetail {
|
|
7
|
+
request: PrnReasonLookupRequest;
|
|
8
|
+
suggestions: PrnReasonSuggestion[];
|
|
9
|
+
}
|
|
6
10
|
export interface Token {
|
|
7
11
|
original: string;
|
|
8
12
|
lower: string;
|
|
@@ -31,6 +35,7 @@ export interface ParsedSigInternal {
|
|
|
31
35
|
timingCode?: string;
|
|
32
36
|
asNeeded?: boolean;
|
|
33
37
|
asNeededReason?: string;
|
|
38
|
+
asNeededReasonCoding?: FhirCoding;
|
|
34
39
|
warnings: string[];
|
|
35
40
|
siteText?: string;
|
|
36
41
|
siteSource?: "abbreviation" | "text";
|
|
@@ -39,4 +44,10 @@ export interface ParsedSigInternal {
|
|
|
39
44
|
siteLookupRequest?: SiteCodeLookupRequest;
|
|
40
45
|
siteLookups: SiteLookupDetail[];
|
|
41
46
|
customSiteHints?: Set<string>;
|
|
47
|
+
prnReasonLookupRequest?: PrnReasonLookupRequest;
|
|
48
|
+
prnReasonLookups: PrnReasonLookupDetail[];
|
|
49
|
+
additionalInstructions: Array<{
|
|
50
|
+
text?: string;
|
|
51
|
+
coding?: FhirCoding;
|
|
52
|
+
}>;
|
|
42
53
|
}
|
package/dist/maps.d.ts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { BodySiteDefinition, EventTiming, FhirDayOfWeek, FhirPeriodUnit, RouteCode, SNOMEDCTRouteCodes } from "./types";
|
|
1
|
+
import { AdditionalInstructionDefinition, BodySiteDefinition, EventTiming, FhirDayOfWeek, FhirPeriodUnit, PrnReasonDefinition, RouteCode, SNOMEDCTRouteCodes } from "./types";
|
|
2
2
|
/**
|
|
3
3
|
* SNOMED CT codings aligned with every known RouteCode. Keeping the structure
|
|
4
4
|
* data-driven ensures any additions to the enumeration are surfaced
|
|
@@ -58,3 +58,19 @@ export declare const KNOWN_DOSAGE_FORMS_TO_DOSE: Record<string, string>;
|
|
|
58
58
|
export declare const KNOWN_TMT_DOSAGE_FORM_TO_SNOMED_ROUTE: Record<string, SNOMEDCTRouteCodes>;
|
|
59
59
|
export declare const DEFAULT_UNIT_BY_NORMALIZED_FORM: Record<string, string>;
|
|
60
60
|
export declare const DEFAULT_UNIT_BY_ROUTE: Partial<Record<RouteCode, string>>;
|
|
61
|
+
export declare function normalizePrnReasonKey(value: string): string;
|
|
62
|
+
export declare function normalizeAdditionalInstructionKey(value: string): string;
|
|
63
|
+
export interface PrnReasonDictionaryEntry {
|
|
64
|
+
canonical: string;
|
|
65
|
+
definition: PrnReasonDefinition;
|
|
66
|
+
terms: string[];
|
|
67
|
+
}
|
|
68
|
+
export declare const DEFAULT_PRN_REASON_ENTRIES: PrnReasonDictionaryEntry[];
|
|
69
|
+
export declare const DEFAULT_PRN_REASON_DEFINITIONS: Record<string, PrnReasonDefinition>;
|
|
70
|
+
export interface AdditionalInstructionDictionaryEntry {
|
|
71
|
+
canonical: string;
|
|
72
|
+
definition: AdditionalInstructionDefinition;
|
|
73
|
+
terms: string[];
|
|
74
|
+
}
|
|
75
|
+
export declare const DEFAULT_ADDITIONAL_INSTRUCTION_ENTRIES: AdditionalInstructionDictionaryEntry[];
|
|
76
|
+
export declare const DEFAULT_ADDITIONAL_INSTRUCTION_DEFINITIONS: Record<string, AdditionalInstructionDefinition>;
|