xlsform2lstsv 0.2.2 → 0.2.3
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 +1 -1
- package/dist/converters/xpathTranspiler.js +45 -43
- package/dist/processors/TypeMapper.js +1 -0
- package/dist/xlsformConverter.js +70 -20
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -35,7 +35,7 @@ Convert XLSForm surveys to LimeSurvey TSV format.
|
|
|
35
35
|
- its a complex task to ensure the transpiler covers everything and we currently cannot guarantee error free/complete transpiling
|
|
36
36
|
|
|
37
37
|
- constraint_message ❌
|
|
38
|
-
- XLSForms Calculation
|
|
38
|
+
- XLSForms Calculation ✅ (`calculate` type → LimeSurvey Equation question `*`; `${var}` references in labels/hints converted to EM `{var}` syntax)
|
|
39
39
|
- XLSForms Trigger ❌
|
|
40
40
|
- Repeats ❌
|
|
41
41
|
- LimeSurvey Assessments ❌
|
|
@@ -38,7 +38,7 @@ function sanitizeName(name) {
|
|
|
38
38
|
* @returns The transpiled LimeSurvey expression string
|
|
39
39
|
* @throws Error if an unsupported node structure is encountered
|
|
40
40
|
*/
|
|
41
|
-
function transpile(node,
|
|
41
|
+
function transpile(node, ctx) {
|
|
42
42
|
if (!node)
|
|
43
43
|
return '';
|
|
44
44
|
// https://getodk.github.io/xforms-spec/#xpath-functions
|
|
@@ -46,29 +46,30 @@ function transpile(node, lookupAnswerCode) {
|
|
|
46
46
|
if (node.id) {
|
|
47
47
|
switch (node.id) {
|
|
48
48
|
case 'count':
|
|
49
|
-
return `count(${node.args?.map(arg => transpile(arg,
|
|
49
|
+
return `count(${node.args?.map(arg => transpile(arg, ctx)).join(', ') || ''})`;
|
|
50
50
|
case 'concat':
|
|
51
|
-
return node.args?.map(arg => transpile(arg,
|
|
51
|
+
return node.args?.map(arg => transpile(arg, ctx)).join(' + ') || '';
|
|
52
52
|
case 'regex':
|
|
53
|
-
return `regexMatch(${node.args?.map(arg => transpile(arg,
|
|
53
|
+
return `regexMatch(${node.args?.map(arg => transpile(arg, ctx)).join(', ') || ''})`;
|
|
54
54
|
case 'contains':
|
|
55
55
|
// Custom handling for contains
|
|
56
56
|
if (node.args?.length === 2) {
|
|
57
|
-
return `contains(${transpile(node.args[0],
|
|
57
|
+
return `contains(${transpile(node.args[0], ctx)}, ${transpile(node.args[1], ctx)})`;
|
|
58
58
|
}
|
|
59
59
|
break;
|
|
60
60
|
case 'selected':
|
|
61
|
-
// Handle selected(${field}, 'value')
|
|
61
|
+
// Handle selected(${field}, 'value')
|
|
62
62
|
if (node.args?.length === 2) {
|
|
63
63
|
const fieldArg = node.args[0];
|
|
64
64
|
const valueArg = node.args[1];
|
|
65
|
-
const fieldName = transpile(fieldArg,
|
|
66
|
-
let value = transpile(valueArg,
|
|
67
|
-
// Remove any existing quotes
|
|
65
|
+
const fieldName = transpile(fieldArg, ctx);
|
|
66
|
+
let value = transpile(valueArg, ctx);
|
|
67
|
+
// Remove any existing quotes
|
|
68
68
|
value = value.replace(/^['"]|['"]$/g, "");
|
|
69
69
|
const sanitizedField = sanitizeName(fieldName);
|
|
70
|
-
if (
|
|
71
|
-
|
|
70
|
+
// Use buildSelectedExpr if available (handles select_one vs select_multiple)
|
|
71
|
+
if (ctx?.buildSelectedExpr) {
|
|
72
|
+
return ctx.buildSelectedExpr(sanitizedField, value);
|
|
72
73
|
}
|
|
73
74
|
return `(${sanitizedField}=="${value}")`;
|
|
74
75
|
}
|
|
@@ -76,66 +77,66 @@ function transpile(node, lookupAnswerCode) {
|
|
|
76
77
|
case 'string':
|
|
77
78
|
// string() function - just return the argument
|
|
78
79
|
if (node.args?.length === 1) {
|
|
79
|
-
return transpile(node.args[0],
|
|
80
|
+
return transpile(node.args[0], ctx);
|
|
80
81
|
}
|
|
81
82
|
break;
|
|
82
83
|
case 'number':
|
|
83
84
|
// number() function - just return the argument
|
|
84
85
|
if (node.args?.length === 1) {
|
|
85
|
-
return transpile(node.args[0],
|
|
86
|
+
return transpile(node.args[0], ctx);
|
|
86
87
|
}
|
|
87
88
|
break;
|
|
88
89
|
case 'floor':
|
|
89
90
|
if (node.args?.length === 1) {
|
|
90
|
-
return `floor(${transpile(node.args[0],
|
|
91
|
+
return `floor(${transpile(node.args[0], ctx)})`;
|
|
91
92
|
}
|
|
92
93
|
break;
|
|
93
94
|
case 'ceiling':
|
|
94
95
|
if (node.args?.length === 1) {
|
|
95
|
-
return `ceil(${transpile(node.args[0],
|
|
96
|
+
return `ceil(${transpile(node.args[0], ctx)})`;
|
|
96
97
|
}
|
|
97
98
|
break;
|
|
98
99
|
case 'round':
|
|
99
100
|
if (node.args?.length === 1) {
|
|
100
|
-
return `round(${transpile(node.args[0],
|
|
101
|
+
return `round(${transpile(node.args[0], ctx)})`;
|
|
101
102
|
}
|
|
102
103
|
break;
|
|
103
104
|
case 'sum':
|
|
104
105
|
if (node.args?.length === 1) {
|
|
105
|
-
return `sum(${transpile(node.args[0],
|
|
106
|
+
return `sum(${transpile(node.args[0], ctx)})`;
|
|
106
107
|
}
|
|
107
108
|
break;
|
|
108
109
|
case 'substring':
|
|
109
110
|
if (node.args && node.args.length >= 2) {
|
|
110
|
-
const stringArg = transpile(node.args[0],
|
|
111
|
-
const startArg = transpile(node.args[1],
|
|
112
|
-
const lengthArg = node.args.length > 2 ? transpile(node.args[2],
|
|
111
|
+
const stringArg = transpile(node.args[0], ctx);
|
|
112
|
+
const startArg = transpile(node.args[1], ctx);
|
|
113
|
+
const lengthArg = node.args.length > 2 ? transpile(node.args[2], ctx) : '';
|
|
113
114
|
return `substr(${stringArg}, ${startArg}${lengthArg ? ', ' + lengthArg : ''})`;
|
|
114
115
|
}
|
|
115
116
|
break;
|
|
116
117
|
case 'string-length':
|
|
117
118
|
if (node.args?.length === 1) {
|
|
118
|
-
return `strlen(${transpile(node.args[0],
|
|
119
|
+
return `strlen(${transpile(node.args[0], ctx)})`;
|
|
119
120
|
}
|
|
120
121
|
break;
|
|
121
122
|
case 'starts-with':
|
|
122
123
|
if (node.args?.length === 2) {
|
|
123
|
-
return `startsWith(${transpile(node.args[0],
|
|
124
|
+
return `startsWith(${transpile(node.args[0], ctx)}, ${transpile(node.args[1], ctx)})`;
|
|
124
125
|
}
|
|
125
126
|
break;
|
|
126
127
|
case 'ends-with':
|
|
127
128
|
if (node.args?.length === 2) {
|
|
128
|
-
return `endsWith(${transpile(node.args[0],
|
|
129
|
+
return `endsWith(${transpile(node.args[0], ctx)}, ${transpile(node.args[1], ctx)})`;
|
|
129
130
|
}
|
|
130
131
|
break;
|
|
131
132
|
case 'not':
|
|
132
133
|
if (node.args?.length === 1) {
|
|
133
|
-
return `!(${transpile(node.args[0],
|
|
134
|
+
return `!(${transpile(node.args[0], ctx)})`;
|
|
134
135
|
}
|
|
135
136
|
break;
|
|
136
137
|
case 'if':
|
|
137
138
|
if (node.args?.length === 3) {
|
|
138
|
-
return `(${transpile(node.args[0],
|
|
139
|
+
return `(${transpile(node.args[0], ctx)} ? ${transpile(node.args[1], ctx)} : ${transpile(node.args[2], ctx)})`;
|
|
139
140
|
}
|
|
140
141
|
break;
|
|
141
142
|
case 'today':
|
|
@@ -146,15 +147,16 @@ function transpile(node, lookupAnswerCode) {
|
|
|
146
147
|
throw new Error(`Unsupported function: ${node.id}`);
|
|
147
148
|
}
|
|
148
149
|
}
|
|
149
|
-
// https://getodk.github.io/xforms-spec/#xpath-operators
|
|
150
|
+
// https://getodk.github.io/xforms-spec/#xpath-operators
|
|
150
151
|
// to https://www.limesurvey.org/manual/ExpressionScript_-_Presentation (see syntax)
|
|
151
152
|
if (node.type) {
|
|
153
|
+
const lookupAnswerCode = ctx?.lookupAnswerCode;
|
|
152
154
|
switch (node.type) {
|
|
153
155
|
// Comparison operators
|
|
154
156
|
case '<=':
|
|
155
|
-
return `${transpile(node.left,
|
|
157
|
+
return `${transpile(node.left, ctx)} <= ${transpile(node.right, ctx)}`;
|
|
156
158
|
case '>=':
|
|
157
|
-
return `${transpile(node.left,
|
|
159
|
+
return `${transpile(node.left, ctx)} >= ${transpile(node.right, ctx)}`;
|
|
158
160
|
case '=':
|
|
159
161
|
case '==': {
|
|
160
162
|
const leftNode = node.left;
|
|
@@ -167,7 +169,7 @@ function transpile(node, lookupAnswerCode) {
|
|
|
167
169
|
return `${fieldName} == "${rewritten}"`;
|
|
168
170
|
}
|
|
169
171
|
}
|
|
170
|
-
return `${transpile(leftNode,
|
|
172
|
+
return `${transpile(leftNode, ctx)} == ${transpile(rightNode, ctx)}`;
|
|
171
173
|
}
|
|
172
174
|
case '!=': {
|
|
173
175
|
const leftNode = node.left;
|
|
@@ -180,28 +182,28 @@ function transpile(node, lookupAnswerCode) {
|
|
|
180
182
|
return `${fieldName} != "${rewritten}"`;
|
|
181
183
|
}
|
|
182
184
|
}
|
|
183
|
-
return `${transpile(leftNode,
|
|
185
|
+
return `${transpile(leftNode, ctx)} != ${transpile(rightNode, ctx)}`;
|
|
184
186
|
}
|
|
185
187
|
case '<':
|
|
186
|
-
return `${transpile(node.left,
|
|
188
|
+
return `${transpile(node.left, ctx)} < ${transpile(node.right, ctx)}`;
|
|
187
189
|
case '>':
|
|
188
|
-
return `${transpile(node.left,
|
|
190
|
+
return `${transpile(node.left, ctx)} > ${transpile(node.right, ctx)}`;
|
|
189
191
|
// Arithmetic operators
|
|
190
192
|
case '+':
|
|
191
|
-
return `${transpile(node.left,
|
|
193
|
+
return `${transpile(node.left, ctx)} + ${transpile(node.right, ctx)}`;
|
|
192
194
|
case '-':
|
|
193
|
-
return `${transpile(node.left,
|
|
195
|
+
return `${transpile(node.left, ctx)} - ${transpile(node.right, ctx)}`;
|
|
194
196
|
case '*':
|
|
195
|
-
return `${transpile(node.left,
|
|
197
|
+
return `${transpile(node.left, ctx)} * ${transpile(node.right, ctx)}`;
|
|
196
198
|
case 'div':
|
|
197
|
-
return `${transpile(node.left,
|
|
199
|
+
return `${transpile(node.left, ctx)} / ${transpile(node.right, ctx)}`;
|
|
198
200
|
case 'mod':
|
|
199
|
-
return `${transpile(node.left,
|
|
201
|
+
return `${transpile(node.left, ctx)} % ${transpile(node.right, ctx)}`;
|
|
200
202
|
// Logical operators
|
|
201
203
|
case 'and':
|
|
202
|
-
return `${transpile(node.left,
|
|
204
|
+
return `${transpile(node.left, ctx)} and ${transpile(node.right, ctx)}`;
|
|
203
205
|
case 'or':
|
|
204
|
-
return `${transpile(node.left,
|
|
206
|
+
return `${transpile(node.left, ctx)} or ${transpile(node.right, ctx)}`;
|
|
205
207
|
// Unsupported operators
|
|
206
208
|
case '|':
|
|
207
209
|
case '/':
|
|
@@ -251,7 +253,7 @@ function transpile(node, lookupAnswerCode) {
|
|
|
251
253
|
* @param xpathExpr - The XPath expression to convert
|
|
252
254
|
* @returns LimeSurvey Expression Manager syntax, or null if conversion fails
|
|
253
255
|
*/
|
|
254
|
-
export async function xpathToLimeSurvey(xpathExpr,
|
|
256
|
+
export async function xpathToLimeSurvey(xpathExpr, ctx) {
|
|
255
257
|
if (!xpathExpr || xpathExpr.trim() === '') {
|
|
256
258
|
return '1'; // Default relevance expression
|
|
257
259
|
}
|
|
@@ -273,7 +275,7 @@ export async function xpathToLimeSurvey(xpathExpr, lookupAnswerCode) {
|
|
|
273
275
|
throw new Error('js-xpath module does not export parse function');
|
|
274
276
|
}
|
|
275
277
|
const parsed = jxpath.parse(processedExpr);
|
|
276
|
-
return transpile(parsed,
|
|
278
|
+
return transpile(parsed, ctx);
|
|
277
279
|
}
|
|
278
280
|
catch (error) {
|
|
279
281
|
console.error(`Transpilation error: ${error.message}`);
|
|
@@ -417,14 +419,14 @@ function parseRegexMatchArguments(argsString) {
|
|
|
417
419
|
* @param xpath - The XPath relevance expression
|
|
418
420
|
* @returns LimeSurvey Expression Manager syntax
|
|
419
421
|
*/
|
|
420
|
-
export async function convertRelevance(xpathExpr,
|
|
422
|
+
export async function convertRelevance(xpathExpr, ctx) {
|
|
421
423
|
if (!xpathExpr)
|
|
422
424
|
return '1';
|
|
423
425
|
// Preprocess: normalize operators to lowercase for jsxpath compatibility
|
|
424
426
|
let normalizedXPath = xpathExpr
|
|
425
427
|
.replace(/\bAND\b/gi, 'and')
|
|
426
428
|
.replace(/\bOR\b/gi, 'or');
|
|
427
|
-
const result = await xpathToLimeSurvey(normalizedXPath,
|
|
429
|
+
const result = await xpathToLimeSurvey(normalizedXPath, ctx);
|
|
428
430
|
// Handle edge case: selected() with just {field} (without $)
|
|
429
431
|
if (result && result.includes('selected(')) {
|
|
430
432
|
return result.replace(/selected\s*\(\s*\{(\w+)\}\s*,\s*["']([^'"]+)["']\s*\)/g, (_match, fieldName, value) => {
|
|
@@ -20,6 +20,7 @@ export const TYPE_MAPPINGS = {
|
|
|
20
20
|
select_multiple: { limeSurveyType: 'M', supportsOther: true, answerClass: 'SQ' },
|
|
21
21
|
// Other types
|
|
22
22
|
note: { limeSurveyType: 'X' },
|
|
23
|
+
calculate: { limeSurveyType: '*' },
|
|
23
24
|
rank: { limeSurveyType: 'R', answerClass: 'A', supportsOther: true },
|
|
24
25
|
};
|
|
25
26
|
export class TypeMapper {
|
package/dist/xlsformConverter.js
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { ConfigManager } from './config/ConfigManager.js';
|
|
2
|
-
import { convertRelevance, convertConstraint } from './converters/xpathTranspiler.js';
|
|
2
|
+
import { convertRelevance, convertConstraint, xpathToLimeSurvey } from './converters/xpathTranspiler.js';
|
|
3
3
|
import { FieldSanitizer } from './processors/FieldSanitizer.js';
|
|
4
4
|
import { TSVGenerator } from './processors/TSVGenerator.js';
|
|
5
5
|
import { TypeMapper } from './processors/TypeMapper.js';
|
|
@@ -7,7 +7,7 @@ import { getBaseLanguage } from './utils/languageUtils.js';
|
|
|
7
7
|
// Metadata types that should be silently skipped (no visual representation)
|
|
8
8
|
const SKIP_TYPES = [
|
|
9
9
|
'start', 'end', 'today', 'deviceid', 'username',
|
|
10
|
-
'
|
|
10
|
+
'hidden', 'audit'
|
|
11
11
|
];
|
|
12
12
|
// Unimplemented XLSForm types that should raise an error
|
|
13
13
|
const UNIMPLEMENTED_TYPES = [
|
|
@@ -51,6 +51,7 @@ export class XLSFormToTSVConverter {
|
|
|
51
51
|
this.groupContentBuffer = [];
|
|
52
52
|
this.answerCodeMap = new Map();
|
|
53
53
|
this.questionToListMap = new Map();
|
|
54
|
+
this.questionBaseTypeMap = new Map();
|
|
54
55
|
}
|
|
55
56
|
/**
|
|
56
57
|
* Get the current configuration
|
|
@@ -201,11 +202,13 @@ export class XLSFormToTSVConverter {
|
|
|
201
202
|
}
|
|
202
203
|
buildQuestionToListMap(surveyData) {
|
|
203
204
|
this.questionToListMap = new Map();
|
|
205
|
+
this.questionBaseTypeMap = new Map();
|
|
204
206
|
for (const row of surveyData) {
|
|
205
207
|
const typeInfo = this.parseType(row.type || '');
|
|
206
208
|
if (typeInfo.listName && row.name) {
|
|
207
209
|
const sanitizedName = this.sanitizeName(row.name.trim());
|
|
208
210
|
this.questionToListMap.set(sanitizedName, typeInfo.listName);
|
|
211
|
+
this.questionBaseTypeMap.set(sanitizedName, typeInfo.base);
|
|
209
212
|
}
|
|
210
213
|
}
|
|
211
214
|
}
|
|
@@ -537,6 +540,21 @@ export class XLSFormToTSVConverter {
|
|
|
537
540
|
sanitizeAnswerCode(code) {
|
|
538
541
|
return this.fieldSanitizer.sanitizeAnswerCode(code);
|
|
539
542
|
}
|
|
543
|
+
/**
|
|
544
|
+
* Convert ${varname} references in text to LimeSurvey EM syntax {sanitizedname}.
|
|
545
|
+
*/
|
|
546
|
+
convertVariableReferences(text) {
|
|
547
|
+
return text.replace(/\$\{([^}]+)\}/g, (_, name) => {
|
|
548
|
+
const sanitized = name.replace(/[_-]/g, '');
|
|
549
|
+
return `{${sanitized}}`;
|
|
550
|
+
});
|
|
551
|
+
}
|
|
552
|
+
/**
|
|
553
|
+
* Transpile an XLSForm calculation expression to a LimeSurvey EM expression.
|
|
554
|
+
*/
|
|
555
|
+
async convertCalculation(calculation) {
|
|
556
|
+
return await xpathToLimeSurvey(calculation);
|
|
557
|
+
}
|
|
540
558
|
async addGroup(row) {
|
|
541
559
|
// Auto-generate name if missing (matches LimeSurvey behavior)
|
|
542
560
|
const groupName = row.name && row.name.trim() !== ''
|
|
@@ -609,21 +627,38 @@ export class XLSFormToTSVConverter {
|
|
|
609
627
|
}
|
|
610
628
|
// Notes have special handling
|
|
611
629
|
const isNote = xfTypeInfo.base === 'note';
|
|
630
|
+
const isCalculate = xfTypeInfo.base === 'calculate';
|
|
631
|
+
// For calculate type, transpile the calculation expression to EM syntax
|
|
632
|
+
let calculationExpr = '';
|
|
633
|
+
if (isCalculate && row.calculation) {
|
|
634
|
+
calculationExpr = await this.convertCalculation(row.calculation);
|
|
635
|
+
}
|
|
612
636
|
// Add main question for each language
|
|
613
637
|
for (const lang of this.availableLanguages) {
|
|
638
|
+
let text;
|
|
639
|
+
if (isCalculate) {
|
|
640
|
+
// Equation question: the EM expression wrapped in {} IS the question text
|
|
641
|
+
text = `{${calculationExpr}}`;
|
|
642
|
+
}
|
|
643
|
+
else {
|
|
644
|
+
text = this.getLanguageSpecificValue(row.label, lang) || questionName;
|
|
645
|
+
}
|
|
646
|
+
// Convert ${var} references to EM {var} syntax in text and help
|
|
647
|
+
text = this.convertVariableReferences(text);
|
|
648
|
+
const help = this.convertVariableReferences(this.getLanguageSpecificValue(row.hint, lang) || '');
|
|
614
649
|
this.bufferRow({
|
|
615
650
|
class: 'Q',
|
|
616
651
|
'type/scale': isNote ? 'X' : lsType.type,
|
|
617
652
|
name: questionName,
|
|
618
653
|
relevance: await this.convertRelevance(row.relevant),
|
|
619
|
-
text
|
|
620
|
-
help
|
|
654
|
+
text,
|
|
655
|
+
help,
|
|
621
656
|
language: lang,
|
|
622
657
|
validation: "",
|
|
623
|
-
em_validation_q: isNote ? "" : await convertConstraint(row.constraint || ""),
|
|
624
|
-
mandatory: isNote ? '' : (row.required === 'yes' || row.required === 'true' ? 'Y' : ''),
|
|
625
|
-
other: isNote ? '' : (lsType.other ? 'Y' : ''),
|
|
626
|
-
default: isNote ? '' : (row.default || ''),
|
|
658
|
+
em_validation_q: (isNote || isCalculate) ? "" : await convertConstraint(row.constraint || ""),
|
|
659
|
+
mandatory: (isNote || isCalculate) ? '' : (row.required === 'yes' || row.required === 'true' ? 'Y' : ''),
|
|
660
|
+
other: (isNote || isCalculate) ? '' : (lsType.other ? 'Y' : ''),
|
|
661
|
+
default: (isNote || isCalculate) ? '' : (row.default || ''),
|
|
627
662
|
same_default: ''
|
|
628
663
|
});
|
|
629
664
|
}
|
|
@@ -784,20 +819,35 @@ export class XLSFormToTSVConverter {
|
|
|
784
819
|
}
|
|
785
820
|
}
|
|
786
821
|
}
|
|
822
|
+
lookupAnswerCode(fieldName, choiceValue) {
|
|
823
|
+
// Truncate to 20 chars to match converter's field sanitization
|
|
824
|
+
// (the transpiler only removes _/- but doesn't truncate)
|
|
825
|
+
const truncated = fieldName.length > 20 ? fieldName.substring(0, 20) : fieldName;
|
|
826
|
+
const listName = this.questionToListMap.get(truncated);
|
|
827
|
+
if (!listName)
|
|
828
|
+
return { code: choiceValue, listName: undefined };
|
|
829
|
+
const codeMap = this.answerCodeMap.get(listName);
|
|
830
|
+
if (!codeMap)
|
|
831
|
+
return { code: choiceValue, listName };
|
|
832
|
+
return { code: codeMap.get(choiceValue) ?? choiceValue, listName };
|
|
833
|
+
}
|
|
787
834
|
async convertRelevance(relevant) {
|
|
788
835
|
if (!relevant)
|
|
789
836
|
return '1';
|
|
790
|
-
|
|
791
|
-
|
|
792
|
-
|
|
793
|
-
|
|
794
|
-
|
|
795
|
-
|
|
796
|
-
|
|
797
|
-
|
|
798
|
-
|
|
799
|
-
|
|
800
|
-
|
|
801
|
-
|
|
837
|
+
const ctx = {
|
|
838
|
+
lookupAnswerCode: (fieldName, choiceValue) => {
|
|
839
|
+
return this.lookupAnswerCode(fieldName, choiceValue).code;
|
|
840
|
+
},
|
|
841
|
+
buildSelectedExpr: (fieldName, choiceValue) => {
|
|
842
|
+
const truncated = fieldName.length > 20 ? fieldName.substring(0, 20) : fieldName;
|
|
843
|
+
const { code } = this.lookupAnswerCode(fieldName, choiceValue);
|
|
844
|
+
const baseType = this.questionBaseTypeMap.get(truncated);
|
|
845
|
+
if (baseType === 'select_multiple') {
|
|
846
|
+
return `(${truncated}_${code}.NAOK == "Y")`;
|
|
847
|
+
}
|
|
848
|
+
return `(${truncated}.NAOK=="${code}")`;
|
|
849
|
+
},
|
|
850
|
+
};
|
|
851
|
+
return await convertRelevance(relevant, ctx);
|
|
802
852
|
}
|
|
803
853
|
}
|