import { normalizeText } from './normalize.js'; import type { AllergyDetail, ReactionClass } from './options.js'; import type { Tier } from './rules.js'; /** * CHK-6a (allergyTiers): how a recorded reaction is read. Swelling, breathing trouble and blistering skin (NICE CG183 * recommendation 1.1.1) are urgent; so is anything not readable as a milder reaction. Draft, for the clinical lead. */ const word = (source: string) => new RegExp(`(? normalizeText(a) === normalizeText(b); /** The detail recorded for an allergy entry, if any. */ export function detailFor(allergy: string, details: readonly AllergyDetail[] | undefined): AllergyDetail | null { return details?.find((detail) => sameEntry(detail.allergy, allergy)) ?? null; } /** How the engine reads a recorded reaction. With nothing recorded, unknown. */ export function classifyReaction(detail: AllergyDetail | null): ReactionClass { if (!detail) return 'unknown'; const kind = detail.reactionKind ?? null; if (kind === 'swelling' || kind === 'breathing' || kind === 'blistering') return kind; if (kind === 'anaphylaxis') return 'breathing'; const text = normalizeText(detail.reaction ?? ''); if (text) { if (SWELLING.test(text)) return 'swelling'; if (BREATHING.test(text)) return 'breathing'; if (BLISTERING.test(text)) return 'blistering'; } if (detail.severity === 'severe') return 'severity_severe'; if (text) return !NOT_MILD.test(text) && MILD.test(text) ? 'not_severe' : 'unknown'; // A chosen mild kind, with no text to contradict it. return kind && kind !== 'other' && kind !== 'unknown' ? 'not_severe' : 'unknown'; } const RANK: Record = { get_help_now: 4, today: 3, this_week: 2, good_to_know: 1 }; /** * The tier of an allergy finding with allergyTiers on. A medicine with the allergy's ingredient or in its class is at * least `today`, and `get_help_now` (Context: Urgent review) when the reaction was severe or is unknown. A possible * cross-reaction (a cephalosporin with a penicillin allergy) keeps the rule's own tier: the PRD covers same-class matches. */ export function allergyTier(matchKind: 'ingredient' | 'class' | 'cross', tier: Tier, reaction: ReactionClass): Tier { if (matchKind === 'cross') return tier; if (reaction !== 'not_severe') return 'get_help_now'; return RANK[tier] < RANK.today ? 'today' : tier; } /** The recorded detail as it goes on the finding, with how it was read. */ export function reactionOutput(allergy: string, detail: AllergyDetail | null) { return { allergy, reaction: detail?.reaction ?? null, reaction_kind: detail?.reactionKind ?? null, onset: detail?.onset ?? null, severity: detail?.severity ?? null, year: detail?.year ?? null, reaction_class: classifyReaction(detail), }; } export type AllergyReactionOutput = ReturnType;