@peopl-health/nexus 5.44.0-dev.5124 → 5.44.0-dev.5142
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.
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
const { getCtcaeCatalog } = require('../stores/CtcaeCatalog');
|
|
2
|
+
|
|
3
|
+
const FREE_TERM = 'other';
|
|
4
|
+
|
|
5
|
+
// listed, not inferred: a prefix rule would pull chest_wall_pain into pain
|
|
6
|
+
const KNOWN_ALIASES = {
|
|
7
|
+
rash: 'skin_rash',
|
|
8
|
+
palmar_plantar_erythrodysesthesia_syndrome: 'palmar_plantar_erythrodysesthesia',
|
|
9
|
+
};
|
|
10
|
+
|
|
11
|
+
function normalise(term) {
|
|
12
|
+
return String(term || '').trim().toLowerCase().replace(/[^a-z0-9]/g, '');
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
function curatedAliasFor(ctcaeTerm) {
|
|
16
|
+
const term = String(ctcaeTerm || '').trim().toLowerCase();
|
|
17
|
+
if (!term || term === FREE_TERM) return null;
|
|
18
|
+
let keys;
|
|
19
|
+
try {
|
|
20
|
+
const catalog = getCtcaeCatalog();
|
|
21
|
+
if (catalog.lookupEntry(term)?.found) return null;
|
|
22
|
+
keys = [...catalog.getCuratedSymptomsByTerm().keys()];
|
|
23
|
+
} catch {
|
|
24
|
+
return null;
|
|
25
|
+
}
|
|
26
|
+
const alias = KNOWN_ALIASES[term];
|
|
27
|
+
if (alias && keys.includes(alias)) return alias;
|
|
28
|
+
const wanted = normalise(term);
|
|
29
|
+
return keys.find((key) => normalise(key) === wanted) || null;
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
function ctcaeTermError(ctcaeTerm) {
|
|
33
|
+
const alias = curatedAliasFor(ctcaeTerm);
|
|
34
|
+
if (!alias) return null;
|
|
35
|
+
return {
|
|
36
|
+
error: `'${ctcaeTerm}' is the catalog term '${alias}' written differently. Use '${alias}' so this case joins the existing one and carries its grade scale.`,
|
|
37
|
+
useInstead: alias,
|
|
38
|
+
};
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
module.exports = {
|
|
42
|
+
curatedAliasFor,
|
|
43
|
+
ctcaeTermError,
|
|
44
|
+
};
|
|
@@ -5,6 +5,7 @@ const { ceilingGapError } = require('../helpers/ceilingGapHelper');
|
|
|
5
5
|
const { mentionProvenanceError } = require('../helpers/evidenceAnchorHelper');
|
|
6
6
|
const { gradeSourceError } = require('../services/gradeSourceService');
|
|
7
7
|
const { gradeAnchorError, hasCuratedLadder } = require('../services/gradeAnchorService');
|
|
8
|
+
const { ctcaeTermError } = require('../services/ctcaeTermService');
|
|
8
9
|
const { armOpenCeilingNet } = require('../services/contingencyDispatchService');
|
|
9
10
|
const { readSymptomCases, storeSymptomCase } = require('../../fhir');
|
|
10
11
|
const { ManagedSymptom, OPEN_STATUSES, FUNCTIONAL_ANCHORS } = require('../../shared/dtos/ManagedSymptom');
|
|
@@ -71,6 +72,11 @@ async function handler(args = {}, context = {}) {
|
|
|
71
72
|
if (missing.length) {
|
|
72
73
|
return JSON.stringify({ success: false, error: `missing required field(s): ${missing.join(', ')}`, data: {} });
|
|
73
74
|
}
|
|
75
|
+
const termGap = ctcaeTermError(ctcaeTerm);
|
|
76
|
+
if (termGap) {
|
|
77
|
+
return JSON.stringify({ success: false, error: termGap.error, data: { use_instead: termGap.useInstead } });
|
|
78
|
+
}
|
|
79
|
+
|
|
74
80
|
const patientId = runtime.patientCode;
|
|
75
81
|
const casesForTerm = await readSymptomCases({ patientId, ctcaeTerm });
|
|
76
82
|
const openCase = casesForTerm.find((symptomCase) => OPEN_STATUSES.includes(symptomCase.condition.clinicalStatus));
|