refactor(drug-reference): make collections JSON the single source for curated data (#1130)
Generate app/data/{conditions,natural_remedies,home_remedies}.ts from the
repo-root collections/*.json via `npm run gen:curated-data`, so the JSON is the
only file edited by hand. The generated modules keep the data compiled into the
image (no runtime file read, no path fragility, which is why the data was a TS
constant), and curated_data_sync.standalone.ts fails CI if a generated module
ever drifts from its JSON.
This removes the burden of hand-keeping the .json mirror and the .ts constant in
sync. Follow-up to the review discussion on #1040.
Co-authored-by: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
parent
09a651d330
commit
6c0271cd6f
|
|
@ -1,342 +1,438 @@
|
|||
/* eslint-disable */
|
||||
/**
|
||||
* "When to use what" — curated condition spine (Phase 1, runtime source of truth).
|
||||
* GENERATED FILE — DO NOT EDIT.
|
||||
*
|
||||
* A bounded, hand-curated list of common first-aid / emergency situations — a
|
||||
* "small booklet" of when-to-use-what. Each entry's `searchTerms` drive the
|
||||
* FULLTEXT search over `drug_labels.indications`.
|
||||
* Single source of truth: collections/conditions.json
|
||||
* Regenerate after editing the JSON: `npm run gen:curated-data` (from admin/).
|
||||
* curated_data_sync.standalone.ts fails CI if this file drifts from the JSON.
|
||||
*
|
||||
* WHY a TS constant (not a JSON file read at runtime):
|
||||
* The repo-root `collections/conditions.json` mirror exists for parity with
|
||||
* the kiwix-categories convention and for human discoverability, but it is
|
||||
* NOT what the running app reads. The Dockerfile copies only `admin/` into the
|
||||
* image (`ADD admin/ ./`) and ships only the compiled `build/` output, so a
|
||||
* repo-root JSON file never reaches the container filesystem. Bundling the
|
||||
* spine as a compiled module guarantees it is always present at runtime with
|
||||
* no path-resolution fragility.
|
||||
*
|
||||
* Keep this file and `collections/conditions.json` in sync (same `version`,
|
||||
* same entries) — the JSON is the public/browseable copy, this is the canonical
|
||||
* runtime copy. `parseConditionsFile` (admin/util/conditions.ts) validates the
|
||||
* shape so a hand-edit that breaks an entry degrades to "skip that entry"
|
||||
* rather than crashing the page.
|
||||
* Curated "when to use what" condition spine (Phase 1). US-government / public-domain sourcing.
|
||||
*/
|
||||
|
||||
import type { ConditionsFile } from '../../types/conditions.js'
|
||||
|
||||
export const CONDITIONS_FILE: ConditionsFile = {
|
||||
version: '2026-06-07',
|
||||
conditions: [
|
||||
// ── Pain, fever & inflammation ──────────────────────────────────────────
|
||||
"version": "2026-06-07",
|
||||
"conditions": [
|
||||
{
|
||||
slug: 'pain',
|
||||
label: 'Pain',
|
||||
category: 'Pain, fever & inflammation',
|
||||
searchTerms: ['pain', 'aches', 'minor aches', 'pain relief', 'analgesic'],
|
||||
"slug": "pain",
|
||||
"label": "Pain",
|
||||
"category": "Pain, fever & inflammation",
|
||||
"searchTerms": [
|
||||
"pain",
|
||||
"aches",
|
||||
"minor aches",
|
||||
"pain relief",
|
||||
"analgesic"
|
||||
]
|
||||
},
|
||||
{
|
||||
slug: 'headache',
|
||||
label: 'Headache',
|
||||
category: 'Pain, fever & inflammation',
|
||||
searchTerms: ['headache', 'migraine', 'head pain', 'tension headache'],
|
||||
"slug": "headache",
|
||||
"label": "Headache",
|
||||
"category": "Pain, fever & inflammation",
|
||||
"searchTerms": [
|
||||
"headache",
|
||||
"migraine",
|
||||
"head pain",
|
||||
"tension headache"
|
||||
]
|
||||
},
|
||||
{
|
||||
slug: 'muscle-joint-pain',
|
||||
label: 'Muscle & joint pain',
|
||||
category: 'Pain, fever & inflammation',
|
||||
searchTerms: [
|
||||
'muscular aches',
|
||||
'muscle aches',
|
||||
'backache',
|
||||
'arthritis',
|
||||
'joint pain',
|
||||
'minor pain of arthritis',
|
||||
],
|
||||
"slug": "muscle-joint-pain",
|
||||
"label": "Muscle & joint pain",
|
||||
"category": "Pain, fever & inflammation",
|
||||
"searchTerms": [
|
||||
"muscular aches",
|
||||
"muscle aches",
|
||||
"backache",
|
||||
"arthritis",
|
||||
"joint pain",
|
||||
"minor pain of arthritis"
|
||||
]
|
||||
},
|
||||
{
|
||||
slug: 'fever',
|
||||
label: 'Fever',
|
||||
category: 'Pain, fever & inflammation',
|
||||
searchTerms: ['fever', 'reduces fever', 'fever reducer', 'temporarily reduces fever'],
|
||||
"slug": "fever",
|
||||
"label": "Fever",
|
||||
"category": "Pain, fever & inflammation",
|
||||
"searchTerms": [
|
||||
"fever",
|
||||
"reduces fever",
|
||||
"fever reducer",
|
||||
"temporarily reduces fever"
|
||||
]
|
||||
},
|
||||
{
|
||||
slug: 'menstrual-cramps',
|
||||
label: 'Menstrual cramps',
|
||||
category: 'Pain, fever & inflammation',
|
||||
searchTerms: ['menstrual cramps', 'menstrual pain', 'period pain', 'premenstrual'],
|
||||
},
|
||||
|
||||
// ── Cold, cough & allergy ───────────────────────────────────────────────
|
||||
{
|
||||
slug: 'cough',
|
||||
label: 'Cough',
|
||||
category: 'Cold, cough & allergy',
|
||||
searchTerms: ['cough', 'cough suppressant', 'coughing', 'controls cough'],
|
||||
"slug": "menstrual-cramps",
|
||||
"label": "Menstrual cramps",
|
||||
"category": "Pain, fever & inflammation",
|
||||
"searchTerms": [
|
||||
"menstrual cramps",
|
||||
"menstrual pain",
|
||||
"period pain",
|
||||
"premenstrual"
|
||||
]
|
||||
},
|
||||
{
|
||||
slug: 'nasal-congestion',
|
||||
label: 'Nasal congestion',
|
||||
category: 'Cold, cough & allergy',
|
||||
searchTerms: [
|
||||
'nasal congestion',
|
||||
'stuffy nose',
|
||||
'sinus congestion',
|
||||
'decongestant',
|
||||
'nasal decongestant',
|
||||
],
|
||||
"slug": "cough",
|
||||
"label": "Cough",
|
||||
"category": "Cold, cough & allergy",
|
||||
"searchTerms": [
|
||||
"cough",
|
||||
"cough suppressant",
|
||||
"coughing",
|
||||
"controls cough"
|
||||
]
|
||||
},
|
||||
{
|
||||
slug: 'sore-throat',
|
||||
label: 'Sore throat',
|
||||
category: 'Cold, cough & allergy',
|
||||
searchTerms: ['sore throat', 'sore mouth', 'minor sore throat', 'throat pain'],
|
||||
"slug": "nasal-congestion",
|
||||
"label": "Nasal congestion",
|
||||
"category": "Cold, cough & allergy",
|
||||
"searchTerms": [
|
||||
"nasal congestion",
|
||||
"stuffy nose",
|
||||
"sinus congestion",
|
||||
"decongestant",
|
||||
"nasal decongestant"
|
||||
]
|
||||
},
|
||||
{
|
||||
slug: 'common-cold',
|
||||
label: 'Common cold',
|
||||
category: 'Cold, cough & allergy',
|
||||
searchTerms: ['common cold', 'cold symptoms', 'cold', 'flu symptoms'],
|
||||
"slug": "sore-throat",
|
||||
"label": "Sore throat",
|
||||
"category": "Cold, cough & allergy",
|
||||
"searchTerms": [
|
||||
"sore throat",
|
||||
"sore mouth",
|
||||
"minor sore throat",
|
||||
"throat pain"
|
||||
]
|
||||
},
|
||||
{
|
||||
slug: 'allergic-reaction',
|
||||
label: 'Allergies & allergic reactions',
|
||||
category: 'Cold, cough & allergy',
|
||||
searchTerms: [
|
||||
'allergy',
|
||||
'allergic reactions',
|
||||
'hay fever',
|
||||
'antihistamine',
|
||||
'runny nose',
|
||||
'sneezing',
|
||||
'itchy watery eyes',
|
||||
],
|
||||
},
|
||||
|
||||
// ── Stomach & digestion ─────────────────────────────────────────────────
|
||||
{
|
||||
slug: 'heartburn',
|
||||
label: 'Heartburn',
|
||||
category: 'Stomach & digestion',
|
||||
searchTerms: ['heartburn', 'acid indigestion', 'acid reducer', 'antacid', 'sour stomach'],
|
||||
"slug": "common-cold",
|
||||
"label": "Common cold",
|
||||
"category": "Cold, cough & allergy",
|
||||
"searchTerms": [
|
||||
"common cold",
|
||||
"cold symptoms",
|
||||
"cold",
|
||||
"flu symptoms"
|
||||
]
|
||||
},
|
||||
{
|
||||
slug: 'indigestion',
|
||||
label: 'Indigestion & upset stomach',
|
||||
category: 'Stomach & digestion',
|
||||
searchTerms: ['indigestion', 'upset stomach', 'gas', 'bloating', 'fullness', 'antacid'],
|
||||
"slug": "allergic-reaction",
|
||||
"label": "Allergies & allergic reactions",
|
||||
"category": "Cold, cough & allergy",
|
||||
"searchTerms": [
|
||||
"allergy",
|
||||
"allergic reactions",
|
||||
"hay fever",
|
||||
"antihistamine",
|
||||
"runny nose",
|
||||
"sneezing",
|
||||
"itchy watery eyes"
|
||||
]
|
||||
},
|
||||
{
|
||||
slug: 'nausea-vomiting',
|
||||
label: 'Nausea & vomiting',
|
||||
category: 'Stomach & digestion',
|
||||
searchTerms: ['nausea', 'vomiting', 'upset stomach associated with nausea'],
|
||||
"slug": "heartburn",
|
||||
"label": "Heartburn",
|
||||
"category": "Stomach & digestion",
|
||||
"searchTerms": [
|
||||
"heartburn",
|
||||
"acid indigestion",
|
||||
"acid reducer",
|
||||
"antacid",
|
||||
"sour stomach"
|
||||
]
|
||||
},
|
||||
{
|
||||
slug: 'diarrhea',
|
||||
label: 'Diarrhea',
|
||||
category: 'Stomach & digestion',
|
||||
searchTerms: ['diarrhea', 'antidiarrheal', 'loose stools', 'traveler’s diarrhea'],
|
||||
"slug": "indigestion",
|
||||
"label": "Indigestion & upset stomach",
|
||||
"category": "Stomach & digestion",
|
||||
"searchTerms": [
|
||||
"indigestion",
|
||||
"upset stomach",
|
||||
"gas",
|
||||
"bloating",
|
||||
"fullness",
|
||||
"antacid"
|
||||
]
|
||||
},
|
||||
{
|
||||
slug: 'constipation',
|
||||
label: 'Constipation',
|
||||
category: 'Stomach & digestion',
|
||||
searchTerms: [
|
||||
'constipation',
|
||||
'laxative',
|
||||
'irregularity',
|
||||
'occasional constipation',
|
||||
'stool softener',
|
||||
],
|
||||
"slug": "nausea-vomiting",
|
||||
"label": "Nausea & vomiting",
|
||||
"category": "Stomach & digestion",
|
||||
"searchTerms": [
|
||||
"nausea",
|
||||
"vomiting",
|
||||
"upset stomach associated with nausea"
|
||||
]
|
||||
},
|
||||
{
|
||||
slug: 'motion-sickness',
|
||||
label: 'Motion sickness',
|
||||
category: 'Stomach & digestion',
|
||||
searchTerms: ['motion sickness', 'travel sickness', 'seasickness', 'car sickness'],
|
||||
"slug": "diarrhea",
|
||||
"label": "Diarrhea",
|
||||
"category": "Stomach & digestion",
|
||||
"searchTerms": [
|
||||
"diarrhea",
|
||||
"antidiarrheal",
|
||||
"loose stools",
|
||||
"traveler’s diarrhea"
|
||||
]
|
||||
},
|
||||
{
|
||||
slug: 'gas',
|
||||
label: 'Gas & bloating',
|
||||
category: 'Stomach & digestion',
|
||||
searchTerms: ['gas', 'bloating', 'flatulence', 'antigas', 'pressure'],
|
||||
},
|
||||
|
||||
// ── Skin & wounds ───────────────────────────────────────────────────────
|
||||
{
|
||||
slug: 'wounds-cuts',
|
||||
label: 'Wounds & cuts',
|
||||
category: 'Skin & wounds',
|
||||
searchTerms: [
|
||||
'minor cuts',
|
||||
'scrapes',
|
||||
'wounds',
|
||||
'first aid antiseptic',
|
||||
'first aid to help prevent infection',
|
||||
'abrasions',
|
||||
],
|
||||
"slug": "constipation",
|
||||
"label": "Constipation",
|
||||
"category": "Stomach & digestion",
|
||||
"searchTerms": [
|
||||
"constipation",
|
||||
"laxative",
|
||||
"irregularity",
|
||||
"occasional constipation",
|
||||
"stool softener"
|
||||
]
|
||||
},
|
||||
{
|
||||
slug: 'burns',
|
||||
label: 'Burns',
|
||||
category: 'Skin & wounds',
|
||||
searchTerms: ['burns', 'minor burns', 'sunburn', 'scald', 'minor burn'],
|
||||
"slug": "motion-sickness",
|
||||
"label": "Motion sickness",
|
||||
"category": "Stomach & digestion",
|
||||
"searchTerms": [
|
||||
"motion sickness",
|
||||
"travel sickness",
|
||||
"seasickness",
|
||||
"car sickness"
|
||||
]
|
||||
},
|
||||
{
|
||||
slug: 'insect-bites-stings',
|
||||
label: 'Insect bites & stings',
|
||||
category: 'Skin & wounds',
|
||||
searchTerms: [
|
||||
'insect bites',
|
||||
'insect stings',
|
||||
'bug bites',
|
||||
'bee sting',
|
||||
'itching from insect bites',
|
||||
],
|
||||
"slug": "gas",
|
||||
"label": "Gas & bloating",
|
||||
"category": "Stomach & digestion",
|
||||
"searchTerms": [
|
||||
"gas",
|
||||
"bloating",
|
||||
"flatulence",
|
||||
"antigas",
|
||||
"pressure"
|
||||
]
|
||||
},
|
||||
{
|
||||
slug: 'skin-rash-itch',
|
||||
label: 'Rash & itching',
|
||||
category: 'Skin & wounds',
|
||||
searchTerms: [
|
||||
'itching',
|
||||
'rash',
|
||||
'skin irritation',
|
||||
'itchy skin',
|
||||
'minor skin irritations',
|
||||
'eczema',
|
||||
],
|
||||
"slug": "wounds-cuts",
|
||||
"label": "Wounds & cuts",
|
||||
"category": "Skin & wounds",
|
||||
"searchTerms": [
|
||||
"minor cuts",
|
||||
"scrapes",
|
||||
"wounds",
|
||||
"first aid antiseptic",
|
||||
"first aid to help prevent infection",
|
||||
"abrasions"
|
||||
]
|
||||
},
|
||||
{
|
||||
slug: 'poison-ivy',
|
||||
label: 'Poison ivy & plant rashes',
|
||||
category: 'Skin & wounds',
|
||||
searchTerms: ['poison ivy', 'poison oak', 'poison sumac', 'rashes due to poison ivy'],
|
||||
"slug": "burns",
|
||||
"label": "Burns",
|
||||
"category": "Skin & wounds",
|
||||
"searchTerms": [
|
||||
"burns",
|
||||
"minor burns",
|
||||
"sunburn",
|
||||
"scald",
|
||||
"minor burn"
|
||||
]
|
||||
},
|
||||
{
|
||||
slug: 'fungal-infection',
|
||||
label: 'Athlete’s foot & ringworm',
|
||||
category: 'Skin & wounds',
|
||||
searchTerms: [
|
||||
'athlete’s foot',
|
||||
'ringworm',
|
||||
'jock itch',
|
||||
'antifungal',
|
||||
'fungal infection',
|
||||
'tinea',
|
||||
],
|
||||
"slug": "insect-bites-stings",
|
||||
"label": "Insect bites & stings",
|
||||
"category": "Skin & wounds",
|
||||
"searchTerms": [
|
||||
"insect bites",
|
||||
"insect stings",
|
||||
"bug bites",
|
||||
"bee sting",
|
||||
"itching from insect bites"
|
||||
]
|
||||
},
|
||||
{
|
||||
slug: 'dry-skin',
|
||||
label: 'Dry & chapped skin',
|
||||
category: 'Skin & wounds',
|
||||
searchTerms: ['dry skin', 'chapped skin', 'chapped lips', 'skin protectant', 'cracked skin'],
|
||||
"slug": "skin-rash-itch",
|
||||
"label": "Rash & itching",
|
||||
"category": "Skin & wounds",
|
||||
"searchTerms": [
|
||||
"itching",
|
||||
"rash",
|
||||
"skin irritation",
|
||||
"itchy skin",
|
||||
"minor skin irritations",
|
||||
"eczema"
|
||||
]
|
||||
},
|
||||
{
|
||||
slug: 'acne',
|
||||
label: 'Acne',
|
||||
category: 'Skin & wounds',
|
||||
searchTerms: ['acne', 'pimples', 'blackheads', 'acne treatment'],
|
||||
},
|
||||
|
||||
// ── Eyes, ears & mouth ──────────────────────────────────────────────────
|
||||
{
|
||||
slug: 'eye-irritation',
|
||||
label: 'Eye irritation & dryness',
|
||||
category: 'Eyes, ears & mouth',
|
||||
searchTerms: [
|
||||
'eye irritation',
|
||||
'dry eyes',
|
||||
'red eyes',
|
||||
'eye redness',
|
||||
'itchy eyes',
|
||||
'lubricant eye',
|
||||
],
|
||||
"slug": "poison-ivy",
|
||||
"label": "Poison ivy & plant rashes",
|
||||
"category": "Skin & wounds",
|
||||
"searchTerms": [
|
||||
"poison ivy",
|
||||
"poison oak",
|
||||
"poison sumac",
|
||||
"rashes due to poison ivy"
|
||||
]
|
||||
},
|
||||
{
|
||||
slug: 'earache',
|
||||
label: 'Earache & ear wax',
|
||||
category: 'Eyes, ears & mouth',
|
||||
searchTerms: ['earache', 'ear wax', 'earwax removal', 'ear pain', 'swimmer’s ear'],
|
||||
"slug": "fungal-infection",
|
||||
"label": "Athlete’s foot & ringworm",
|
||||
"category": "Skin & wounds",
|
||||
"searchTerms": [
|
||||
"athlete’s foot",
|
||||
"ringworm",
|
||||
"jock itch",
|
||||
"antifungal",
|
||||
"fungal infection",
|
||||
"tinea"
|
||||
]
|
||||
},
|
||||
{
|
||||
slug: 'canker-sores',
|
||||
label: 'Canker & cold sores',
|
||||
category: 'Eyes, ears & mouth',
|
||||
searchTerms: ['canker sores', 'cold sores', 'mouth sores', 'fever blisters', 'oral pain'],
|
||||
"slug": "dry-skin",
|
||||
"label": "Dry & chapped skin",
|
||||
"category": "Skin & wounds",
|
||||
"searchTerms": [
|
||||
"dry skin",
|
||||
"chapped skin",
|
||||
"chapped lips",
|
||||
"skin protectant",
|
||||
"cracked skin"
|
||||
]
|
||||
},
|
||||
{
|
||||
slug: 'toothache',
|
||||
label: 'Toothache',
|
||||
category: 'Eyes, ears & mouth',
|
||||
searchTerms: ['toothache', 'tooth pain', 'dental pain', 'oral analgesic'],
|
||||
},
|
||||
|
||||
// ── Sleep, stress & general ─────────────────────────────────────────────
|
||||
{
|
||||
slug: 'sleeplessness',
|
||||
label: 'Sleeplessness',
|
||||
category: 'Sleep, stress & general',
|
||||
searchTerms: [
|
||||
'sleeplessness',
|
||||
'insomnia',
|
||||
'sleep aid',
|
||||
'difficulty falling asleep',
|
||||
'nighttime',
|
||||
],
|
||||
"slug": "acne",
|
||||
"label": "Acne",
|
||||
"category": "Skin & wounds",
|
||||
"searchTerms": [
|
||||
"acne",
|
||||
"pimples",
|
||||
"blackheads",
|
||||
"acne treatment"
|
||||
]
|
||||
},
|
||||
{
|
||||
slug: 'dehydration',
|
||||
label: 'Dehydration',
|
||||
category: 'Sleep, stress & general',
|
||||
searchTerms: [
|
||||
'dehydration',
|
||||
'oral rehydration',
|
||||
'electrolyte',
|
||||
'fluid loss',
|
||||
'replaces electrolytes',
|
||||
],
|
||||
"slug": "eye-irritation",
|
||||
"label": "Eye irritation & dryness",
|
||||
"category": "Eyes, ears & mouth",
|
||||
"searchTerms": [
|
||||
"eye irritation",
|
||||
"dry eyes",
|
||||
"red eyes",
|
||||
"eye redness",
|
||||
"itchy eyes",
|
||||
"lubricant eye"
|
||||
]
|
||||
},
|
||||
{
|
||||
slug: 'hemorrhoids',
|
||||
label: 'Hemorrhoids',
|
||||
category: 'Sleep, stress & general',
|
||||
searchTerms: ['hemorrhoids', 'hemorrhoidal', 'anal itching', 'rectal'],
|
||||
},
|
||||
|
||||
// ── Infections (OTC-treatable) ──────────────────────────────────────────
|
||||
{
|
||||
slug: 'yeast-infection',
|
||||
label: 'Vaginal yeast infection',
|
||||
category: 'Infections (OTC-treatable)',
|
||||
searchTerms: [
|
||||
'vaginal yeast infection',
|
||||
'yeast infection',
|
||||
'vaginal antifungal',
|
||||
'candidiasis',
|
||||
],
|
||||
"slug": "earache",
|
||||
"label": "Earache & ear wax",
|
||||
"category": "Eyes, ears & mouth",
|
||||
"searchTerms": [
|
||||
"earache",
|
||||
"ear wax",
|
||||
"earwax removal",
|
||||
"ear pain",
|
||||
"swimmer’s ear"
|
||||
]
|
||||
},
|
||||
{
|
||||
slug: 'pinworm',
|
||||
label: 'Pinworm',
|
||||
category: 'Infections (OTC-treatable)',
|
||||
searchTerms: ['pinworm', 'pinworm infection', 'pinworm treatment'],
|
||||
"slug": "canker-sores",
|
||||
"label": "Canker & cold sores",
|
||||
"category": "Eyes, ears & mouth",
|
||||
"searchTerms": [
|
||||
"canker sores",
|
||||
"cold sores",
|
||||
"mouth sores",
|
||||
"fever blisters",
|
||||
"oral pain"
|
||||
]
|
||||
},
|
||||
{
|
||||
slug: 'cold-sore-lip',
|
||||
label: 'Chapped & sun-protected lips',
|
||||
category: 'Sleep, stress & general',
|
||||
searchTerms: ['lip protectant', 'chapped lips', 'sunburn protection lips', 'lip balm'],
|
||||
"slug": "toothache",
|
||||
"label": "Toothache",
|
||||
"category": "Eyes, ears & mouth",
|
||||
"searchTerms": [
|
||||
"toothache",
|
||||
"tooth pain",
|
||||
"dental pain",
|
||||
"oral analgesic"
|
||||
]
|
||||
},
|
||||
{
|
||||
slug: 'eye-allergy',
|
||||
label: 'Eye allergies',
|
||||
category: 'Eyes, ears & mouth',
|
||||
searchTerms: [
|
||||
'eye allergy',
|
||||
'itchy eyes due to allergies',
|
||||
'ocular itching',
|
||||
'allergic conjunctivitis',
|
||||
],
|
||||
"slug": "sleeplessness",
|
||||
"label": "Sleeplessness",
|
||||
"category": "Sleep, stress & general",
|
||||
"searchTerms": [
|
||||
"sleeplessness",
|
||||
"insomnia",
|
||||
"sleep aid",
|
||||
"difficulty falling asleep",
|
||||
"nighttime"
|
||||
]
|
||||
},
|
||||
],
|
||||
{
|
||||
"slug": "dehydration",
|
||||
"label": "Dehydration",
|
||||
"category": "Sleep, stress & general",
|
||||
"searchTerms": [
|
||||
"dehydration",
|
||||
"oral rehydration",
|
||||
"electrolyte",
|
||||
"fluid loss",
|
||||
"replaces electrolytes"
|
||||
]
|
||||
},
|
||||
{
|
||||
"slug": "hemorrhoids",
|
||||
"label": "Hemorrhoids",
|
||||
"category": "Sleep, stress & general",
|
||||
"searchTerms": [
|
||||
"hemorrhoids",
|
||||
"hemorrhoidal",
|
||||
"anal itching",
|
||||
"rectal"
|
||||
]
|
||||
},
|
||||
{
|
||||
"slug": "yeast-infection",
|
||||
"label": "Vaginal yeast infection",
|
||||
"category": "Infections (OTC-treatable)",
|
||||
"searchTerms": [
|
||||
"vaginal yeast infection",
|
||||
"yeast infection",
|
||||
"vaginal antifungal",
|
||||
"candidiasis"
|
||||
]
|
||||
},
|
||||
{
|
||||
"slug": "pinworm",
|
||||
"label": "Pinworm",
|
||||
"category": "Infections (OTC-treatable)",
|
||||
"searchTerms": [
|
||||
"pinworm",
|
||||
"pinworm infection",
|
||||
"pinworm treatment"
|
||||
]
|
||||
},
|
||||
{
|
||||
"slug": "cold-sore-lip",
|
||||
"label": "Chapped & sun-protected lips",
|
||||
"category": "Sleep, stress & general",
|
||||
"searchTerms": [
|
||||
"lip protectant",
|
||||
"chapped lips",
|
||||
"sunburn protection lips",
|
||||
"lip balm"
|
||||
]
|
||||
},
|
||||
{
|
||||
"slug": "eye-allergy",
|
||||
"label": "Eye allergies",
|
||||
"category": "Eyes, ears & mouth",
|
||||
"searchTerms": [
|
||||
"eye allergy",
|
||||
"itchy eyes due to allergies",
|
||||
"ocular itching",
|
||||
"allergic conjunctivitis"
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,14 +1,13 @@
|
|||
/* eslint-disable */
|
||||
/**
|
||||
* Non-herbal home-care / self-care measures (Phase 2b, runtime source of truth).
|
||||
* GENERATED FILE — DO NOT EDIT.
|
||||
*
|
||||
* Same pattern as natural_remedies.ts / conditions.ts: the repo-root
|
||||
* collections/home_remedies.json is the browseable mirror, this compiled module
|
||||
* is what the running app reads (the image ships only compiled admin/build/).
|
||||
* Keep the two in sync. Sources are US-government public-domain pages (CDC,
|
||||
* NIH/NLM MedlinePlus summaries, FDA consumer updates) — each entry carries its
|
||||
* exact sourceUrl.
|
||||
* Single source of truth: collections/home_remedies.json
|
||||
* Regenerate after editing the JSON: `npm run gen:curated-data` (from admin/).
|
||||
* curated_data_sync.standalone.ts fails CI if this file drifts from the JSON.
|
||||
*
|
||||
* Non-herbal home-care / self-care measures from US-government public-domain pages (CDC, NIH/NLM MedlinePlus, FDA); each entry carries its own sourceUrl.
|
||||
*/
|
||||
|
||||
import type { NaturalRemediesFile } from '../../types/conditions.js'
|
||||
|
||||
export const HOME_REMEDIES_FILE: NaturalRemediesFile = {
|
||||
|
|
|
|||
|
|
@ -1,26 +1,13 @@
|
|||
/* eslint-disable */
|
||||
/**
|
||||
* "When to use what" — curated natural-remedies data (Phase 2, runtime source of truth).
|
||||
* GENERATED FILE — DO NOT EDIT.
|
||||
*
|
||||
* Hand-curated subset of NCCIH "Herbs at a Glance" (nccih.nih.gov) mapped to our
|
||||
* 36-condition spine. Source is US government / public domain; reproduction
|
||||
* encouraged with credit (credit appears in the NaturalRemediesFile.source field
|
||||
* and in the UI section caveat).
|
||||
* Single source of truth: collections/natural_remedies.json
|
||||
* Regenerate after editing the JSON: `npm run gen:curated-data` (from admin/).
|
||||
* curated_data_sync.standalone.ts fails CI if this file drifts from the JSON.
|
||||
*
|
||||
* WHY a TS constant (not a JSON file read at runtime):
|
||||
* The repo-root `collections/natural_remedies.json` mirror exists for human
|
||||
* discoverability and parity with the kiwix-categories / conditions convention,
|
||||
* but it is NOT what the running app reads. The Dockerfile copies only `admin/`
|
||||
* into the image (`ADD admin/ ./`) and ships only the compiled `build/` output,
|
||||
* so a repo-root JSON file never reaches the container filesystem. Bundling the
|
||||
* remedies as a compiled module guarantees they are always present at runtime
|
||||
* with no path-resolution fragility.
|
||||
*
|
||||
* Keep this file and `collections/natural_remedies.json` in sync — same `version`,
|
||||
* same remedy slugs, same remedy count. `parseNaturalRemediesFile` (admin/util/conditions.ts)
|
||||
* validates the shape so a hand-edit that breaks an entry degrades to "skip that
|
||||
* entry" rather than crashing the page. The standalone test asserts sync.
|
||||
* Hand-curated subset of NCCIH "Herbs at a Glance" (nccih.nih.gov), mapped to the condition spine. US-government / public domain; attribution lives in the file `source` field and the UI caveat.
|
||||
*/
|
||||
|
||||
import type { NaturalRemediesFile } from '../../types/conditions.js'
|
||||
|
||||
export const NATURAL_REMEDIES_FILE: NaturalRemediesFile = {
|
||||
|
|
|
|||
|
|
@ -12,6 +12,7 @@
|
|||
"test": "node ace test",
|
||||
"lint": "eslint .",
|
||||
"format": "prettier --write .",
|
||||
"gen:curated-data": "node --experimental-strip-types scripts/generate_curated_data.ts && prettier --write app/data/conditions.ts app/data/natural_remedies.ts app/data/home_remedies.ts",
|
||||
"typecheck": "tsc --noEmit",
|
||||
"work:downloads": "node ace queue:work --queue=downloads",
|
||||
"work:model-downloads": "node ace queue:work --queue=model-downloads",
|
||||
|
|
|
|||
|
|
@ -0,0 +1,79 @@
|
|||
/**
|
||||
* Generates the curated drug-reference data modules
|
||||
* (`app/data/{conditions,natural_remedies,home_remedies}.ts`) from the
|
||||
* single-source JSON in the repo-root `collections/` directory.
|
||||
*
|
||||
* npm run gen:curated-data (from admin/)
|
||||
*
|
||||
* The JSON files are the ONLY thing a human edits. The generated `.ts` modules
|
||||
* keep the data compiled into the image (no runtime file read, no path
|
||||
* fragility), and `tests/standalone/curated_data_sync.standalone.ts` fails CI if
|
||||
* a generated module ever drifts from its JSON. This removes the old burden of
|
||||
* hand-keeping the `.json` mirror and the `.ts` constant in sync
|
||||
* (Crosstalk-Solutions/project-nomad#1040 follow-up).
|
||||
*/
|
||||
import { readFileSync, writeFileSync } from 'node:fs'
|
||||
import { fileURLToPath } from 'node:url'
|
||||
import { dirname, resolve } from 'node:path'
|
||||
|
||||
const here = dirname(fileURLToPath(import.meta.url)) // admin/scripts
|
||||
const collectionsDir = resolve(here, '../../collections')
|
||||
const dataDir = resolve(here, '../app/data')
|
||||
|
||||
interface Spec {
|
||||
name: string
|
||||
exportName: string
|
||||
typeName: string
|
||||
provenance: string
|
||||
}
|
||||
|
||||
const SPECS: Spec[] = [
|
||||
{
|
||||
name: 'conditions',
|
||||
exportName: 'CONDITIONS_FILE',
|
||||
typeName: 'ConditionsFile',
|
||||
provenance:
|
||||
'Curated "when to use what" condition spine (Phase 1). US-government / public-domain sourcing.',
|
||||
},
|
||||
{
|
||||
name: 'natural_remedies',
|
||||
exportName: 'NATURAL_REMEDIES_FILE',
|
||||
typeName: 'NaturalRemediesFile',
|
||||
provenance:
|
||||
'Hand-curated subset of NCCIH "Herbs at a Glance" (nccih.nih.gov), mapped to the condition spine. ' +
|
||||
'US-government / public domain; attribution lives in the file `source` field and the UI caveat.',
|
||||
},
|
||||
{
|
||||
name: 'home_remedies',
|
||||
exportName: 'HOME_REMEDIES_FILE',
|
||||
typeName: 'NaturalRemediesFile',
|
||||
provenance:
|
||||
'Non-herbal home-care / self-care measures from US-government public-domain pages ' +
|
||||
'(CDC, NIH/NLM MedlinePlus, FDA); each entry carries its own sourceUrl.',
|
||||
},
|
||||
]
|
||||
|
||||
for (const spec of SPECS) {
|
||||
const json = JSON.parse(readFileSync(resolve(collectionsDir, `${spec.name}.json`), 'utf8'))
|
||||
|
||||
const banner =
|
||||
`/* eslint-disable */\n` +
|
||||
`/**\n` +
|
||||
` * GENERATED FILE — DO NOT EDIT.\n` +
|
||||
` *\n` +
|
||||
` * Single source of truth: collections/${spec.name}.json\n` +
|
||||
` * Regenerate after editing the JSON: \`npm run gen:curated-data\` (from admin/).\n` +
|
||||
` * curated_data_sync.standalone.ts fails CI if this file drifts from the JSON.\n` +
|
||||
` *\n` +
|
||||
` * ${spec.provenance}\n` +
|
||||
` */\n`
|
||||
|
||||
const module =
|
||||
`import type { ${spec.typeName} } from '../../types/conditions.js'\n\n` +
|
||||
`export const ${spec.exportName}: ${spec.typeName} = ${JSON.stringify(json, null, 2)}\n`
|
||||
|
||||
writeFileSync(resolve(dataDir, `${spec.name}.ts`), banner + module)
|
||||
console.log(`generated app/data/${spec.name}.ts ← collections/${spec.name}.json`)
|
||||
}
|
||||
|
||||
console.log('\nDone. Run `npm run format` is applied by the gen script; commit both the JSON and the generated .ts.')
|
||||
|
|
@ -0,0 +1,46 @@
|
|||
/**
|
||||
* Drift guard for the curated drug-reference data (upstream #1040 follow-up).
|
||||
*
|
||||
* node --experimental-strip-types tests/standalone/curated_data_sync.standalone.ts
|
||||
*
|
||||
* The `collections/*.json` files are the single source of truth; the matching
|
||||
* `app/data/*.ts` modules are generated from them (`npm run gen:curated-data`).
|
||||
* This test fails if a generated module ever drifts from its JSON — i.e. if
|
||||
* someone hand-edited the `.ts` instead of the JSON, or forgot to regenerate.
|
||||
* A failure means: edit the JSON, then run `npm run gen:curated-data`.
|
||||
*/
|
||||
import assert from 'node:assert/strict'
|
||||
import { readFileSync } from 'node:fs'
|
||||
import { fileURLToPath } from 'node:url'
|
||||
import { dirname, resolve } from 'node:path'
|
||||
import { CONDITIONS_FILE } from '../../app/data/conditions.ts'
|
||||
import { NATURAL_REMEDIES_FILE } from '../../app/data/natural_remedies.ts'
|
||||
import { HOME_REMEDIES_FILE } from '../../app/data/home_remedies.ts'
|
||||
|
||||
const collectionsDir = resolve(dirname(fileURLToPath(import.meta.url)), '../../../collections')
|
||||
|
||||
let passed = 0
|
||||
function check(name: string, fn: () => void) {
|
||||
fn()
|
||||
passed++
|
||||
console.log(` ok - ${name}`)
|
||||
}
|
||||
|
||||
const CASES: Array<[string, unknown]> = [
|
||||
['conditions', CONDITIONS_FILE],
|
||||
['natural_remedies', NATURAL_REMEDIES_FILE],
|
||||
['home_remedies', HOME_REMEDIES_FILE],
|
||||
]
|
||||
|
||||
for (const [name, generated] of CASES) {
|
||||
check(`app/data/${name}.ts is in sync with collections/${name}.json`, () => {
|
||||
const json = JSON.parse(readFileSync(resolve(collectionsDir, `${name}.json`), 'utf8'))
|
||||
assert.deepEqual(
|
||||
generated,
|
||||
json,
|
||||
`app/data/${name}.ts drifted from collections/${name}.json — edit the JSON, then run \`npm run gen:curated-data\``
|
||||
)
|
||||
})
|
||||
}
|
||||
|
||||
console.log(`\n${passed} passed`)
|
||||
Loading…
Reference in New Issue