ezmedicationinput 0.1.3 → 0.1.5

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/parser.js CHANGED
@@ -110,6 +110,7 @@ const COMBO_EVENT_TIMINGS = {
110
110
  "after sleep": types_1.EventTiming["After Sleep"],
111
111
  "upon waking": types_1.EventTiming.Wake
112
112
  };
113
+ const MEAL_CONTEXT_CONNECTORS = new Set(["and", "or", "&", "+", "plus"]);
113
114
  // Tracking explicit breakfast/lunch/dinner markers lets the meal-expansion
114
115
  // logic bail early when the clinician already specified precise events.
115
116
  const SPECIFIC_MEAL_TIMINGS = new Set([
@@ -976,20 +977,31 @@ function applyWhenToken(internal, token, code) {
976
977
  }
977
978
  function parseMealContext(internal, tokens, index, code) {
978
979
  const token = tokens[index];
979
- const next = tokens[index + 1];
980
- if (!next || internal.consumed.has(next.index)) {
981
- applyWhenToken(internal, token, code);
982
- return;
983
- }
984
- const meal = maps_1.MEAL_KEYWORDS[next.lower];
985
- if (meal) {
980
+ let converted = 0;
981
+ for (let lookahead = index + 1; lookahead < tokens.length; lookahead++) {
982
+ const nextToken = tokens[lookahead];
983
+ if (internal.consumed.has(nextToken.index)) {
984
+ continue;
985
+ }
986
+ if (MEAL_CONTEXT_CONNECTORS.has(nextToken.lower)) {
987
+ mark(internal.consumed, nextToken);
988
+ continue;
989
+ }
990
+ const meal = maps_1.MEAL_KEYWORDS[nextToken.lower];
991
+ if (!meal) {
992
+ break;
993
+ }
986
994
  const whenCode = code === types_1.EventTiming["After Meal"]
987
995
  ? meal.pc
988
996
  : code === types_1.EventTiming["Before Meal"]
989
997
  ? meal.ac
990
998
  : code;
991
- applyWhenToken(internal, token, whenCode);
992
- mark(internal.consumed, next);
999
+ addWhen(internal.when, whenCode);
1000
+ mark(internal.consumed, nextToken);
1001
+ converted++;
1002
+ }
1003
+ if (converted > 0) {
1004
+ mark(internal.consumed, token);
993
1005
  return;
994
1006
  }
995
1007
  applyWhenToken(internal, token, code);
package/dist/suggest.js CHANGED
@@ -288,6 +288,7 @@ function buildWhenSequences() {
288
288
  }
289
289
  return sequences;
290
290
  }
291
+ const PRECOMPUTED_WHEN_SEQUENCES = buildWhenSequences();
291
292
  function tokenizeForMatching(value) {
292
293
  return value
293
294
  .toLowerCase()
@@ -403,68 +404,94 @@ function buildDoseValues(input) {
403
404
  }
404
405
  return [...values];
405
406
  }
406
- function generateCandidateDirections(pairs, doseValues, prnReasons, intervalTokens, whenSequences) {
407
+ function generateCandidateDirections(pairs, doseValues, prnReasons, intervalTokens, whenSequences, limit, matcher) {
407
408
  const suggestions = [];
408
409
  const seen = new Set();
409
410
  const push = (value) => {
410
411
  const normalized = normalizeSpacing(value);
411
412
  if (!normalized) {
412
- return;
413
+ return false;
413
414
  }
414
415
  const key = normalizeKey(normalized);
415
416
  if (seen.has(key)) {
416
- return;
417
+ return false;
417
418
  }
418
419
  seen.add(key);
420
+ if (!matcher(normalized)) {
421
+ return false;
422
+ }
419
423
  suggestions.push(normalized);
424
+ return suggestions.length >= limit;
420
425
  };
421
426
  for (const pair of pairs) {
422
427
  const unitVariants = getUnitVariants(pair.unit);
423
428
  for (const code of FREQUENCY_CODES) {
424
429
  for (const unitVariant of unitVariants) {
425
430
  for (const dose of doseValues) {
426
- push(`${dose} ${unitVariant} ${pair.route} ${code}`);
431
+ if (push(`${dose} ${unitVariant} ${pair.route} ${code}`)) {
432
+ return suggestions;
433
+ }
427
434
  }
428
435
  }
429
- push(`${pair.route} ${code}`);
436
+ if (push(`${pair.route} ${code}`)) {
437
+ return suggestions;
438
+ }
430
439
  }
431
440
  for (const interval of intervalTokens) {
432
441
  for (const unitVariant of unitVariants) {
433
442
  for (const dose of doseValues) {
434
- push(`${dose} ${unitVariant} ${pair.route} ${interval}`);
443
+ if (push(`${dose} ${unitVariant} ${pair.route} ${interval}`)) {
444
+ return suggestions;
445
+ }
435
446
  for (const reason of prnReasons) {
436
- push(`${dose} ${unitVariant} ${pair.route} ${interval} prn ${reason}`);
447
+ if (push(`${dose} ${unitVariant} ${pair.route} ${interval} prn ${reason}`)) {
448
+ return suggestions;
449
+ }
437
450
  }
438
451
  }
439
452
  }
440
- push(`${pair.route} ${interval}`);
453
+ if (push(`${pair.route} ${interval}`)) {
454
+ return suggestions;
455
+ }
441
456
  }
442
457
  for (const freq of FREQUENCY_NUMBERS) {
443
458
  const freqToken = FREQ_TOKEN_BY_NUMBER[freq];
444
459
  if (!freqToken) {
445
460
  continue;
446
461
  }
447
- push(`1x${freq} ${pair.route} ${freqToken}`);
462
+ if (push(`1x${freq} ${pair.route} ${freqToken}`)) {
463
+ return suggestions;
464
+ }
448
465
  for (const when of CORE_WHEN_TOKENS) {
449
- push(`1x${freq} ${pair.route} ${when}`);
466
+ if (push(`1x${freq} ${pair.route} ${when}`)) {
467
+ return suggestions;
468
+ }
450
469
  }
451
470
  }
452
471
  for (const whenSequence of whenSequences) {
453
472
  const suffix = whenSequence.join(" ");
454
473
  for (const unitVariant of unitVariants) {
455
474
  for (const dose of doseValues) {
456
- push(`${dose} ${unitVariant} ${pair.route} ${suffix}`);
475
+ if (push(`${dose} ${unitVariant} ${pair.route} ${suffix}`)) {
476
+ return suggestions;
477
+ }
457
478
  }
458
479
  }
459
- push(`${pair.route} ${suffix}`);
480
+ if (push(`${pair.route} ${suffix}`)) {
481
+ return suggestions;
482
+ }
460
483
  }
461
484
  for (const reason of prnReasons) {
462
485
  for (const unitVariant of unitVariants) {
463
486
  for (const dose of doseValues) {
464
- push(`${dose} ${unitVariant} ${pair.route} prn ${reason}`);
487
+ if (push(`${dose} ${unitVariant} ${pair.route} prn ${reason}`)) {
488
+ return suggestions;
489
+ }
465
490
  }
466
491
  }
467
- push(`${pair.route} prn ${reason}`);
492
+ if (push(`${pair.route} prn ${reason}`)) {
493
+ return suggestions;
494
+ }
468
495
  }
469
496
  }
470
497
  return suggestions;
@@ -507,6 +534,9 @@ function matchesPrefix(candidate, prefix, prefixCompact, prefixTokens, prefixTok
507
534
  function suggestSig(input, options) {
508
535
  var _a, _b;
509
536
  const limit = (_a = options === null || options === void 0 ? void 0 : options.limit) !== null && _a !== void 0 ? _a : DEFAULT_LIMIT;
537
+ if (limit <= 0) {
538
+ return [];
539
+ }
510
540
  const prefix = normalizeSpacing(input.toLowerCase());
511
541
  const prefixCompact = prefix.replace(/\s+/g, "");
512
542
  const prefixNoDashes = prefix.replace(/-/g, "");
@@ -520,16 +550,7 @@ function suggestSig(input, options) {
520
550
  const doseValues = buildDoseValues(input);
521
551
  const prnReasons = buildPrnReasons(options === null || options === void 0 ? void 0 : options.prnReasons);
522
552
  const intervalTokens = buildIntervalTokens(input);
523
- const whenSequences = buildWhenSequences();
524
- const candidates = generateCandidateDirections(pairs, doseValues, prnReasons, intervalTokens, whenSequences);
525
- const results = [];
526
- for (const candidate of candidates) {
527
- if (matchesPrefix(candidate, prefix, prefixCompact, prefixTokens, prefixTokensNoDashes, prefixCanonical, prefixCanonicalCompact, prefixNoDashes, prefixCanonicalNoDashes)) {
528
- results.push(candidate);
529
- }
530
- if (results.length >= limit) {
531
- break;
532
- }
533
- }
534
- return results;
553
+ const whenSequences = PRECOMPUTED_WHEN_SEQUENCES;
554
+ const matcher = (candidate) => matchesPrefix(candidate, prefix, prefixCompact, prefixTokens, prefixTokensNoDashes, prefixCanonical, prefixCanonicalCompact, prefixNoDashes, prefixCanonicalNoDashes);
555
+ return generateCandidateDirections(pairs, doseValues, prnReasons, intervalTokens, whenSequences, limit, matcher);
535
556
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "ezmedicationinput",
3
- "version": "0.1.3",
3
+ "version": "0.1.5",
4
4
  "description": "Parse concise medication sigs into FHIR R5 Dosage JSON",
5
5
  "type": "module",
6
6
  "main": "dist/index.js",