xlsform2lstsv 0.2.3 → 0.3.0
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.
|
@@ -129,14 +129,21 @@ function transpile(node, ctx) {
|
|
|
129
129
|
return `endsWith(${transpile(node.args[0], ctx)}, ${transpile(node.args[1], ctx)})`;
|
|
130
130
|
}
|
|
131
131
|
break;
|
|
132
|
+
case 'normalize-space':
|
|
133
|
+
if (node.args?.length === 1) {
|
|
134
|
+
return `trim(${transpile(node.args[0], ctx)})`;
|
|
135
|
+
}
|
|
136
|
+
break;
|
|
132
137
|
case 'not':
|
|
133
138
|
if (node.args?.length === 1) {
|
|
134
139
|
return `!(${transpile(node.args[0], ctx)})`;
|
|
135
140
|
}
|
|
136
141
|
break;
|
|
137
142
|
case 'if':
|
|
143
|
+
// Use if() function instead of ternary (? :) because EM's ternary parser
|
|
144
|
+
// can misinterpret colons inside string literals (e.g. '2026-03-CHW: Chancenwerk')
|
|
138
145
|
if (node.args?.length === 3) {
|
|
139
|
-
return `(${transpile(node.args[0], ctx)}
|
|
146
|
+
return `if(${transpile(node.args[0], ctx)}, ${transpile(node.args[1], ctx)}, ${transpile(node.args[2], ctx)})`;
|
|
140
147
|
}
|
|
141
148
|
break;
|
|
142
149
|
case 'today':
|
|
@@ -166,7 +173,7 @@ function transpile(node, ctx) {
|
|
|
166
173
|
const rawValue = rightNode.value;
|
|
167
174
|
const rewritten = lookupAnswerCode(fieldName, rawValue);
|
|
168
175
|
if (rewritten !== rawValue) {
|
|
169
|
-
return `${fieldName} ==
|
|
176
|
+
return `${fieldName} == '${rewritten}'`;
|
|
170
177
|
}
|
|
171
178
|
}
|
|
172
179
|
return `${transpile(leftNode, ctx)} == ${transpile(rightNode, ctx)}`;
|
|
@@ -179,7 +186,7 @@ function transpile(node, ctx) {
|
|
|
179
186
|
const rawValue = rightNode.value;
|
|
180
187
|
const rewritten = lookupAnswerCode(fieldName, rawValue);
|
|
181
188
|
if (rewritten !== rawValue) {
|
|
182
|
-
return `${fieldName} !=
|
|
189
|
+
return `${fieldName} != '${rewritten}'`;
|
|
183
190
|
}
|
|
184
191
|
}
|
|
185
192
|
return `${transpile(leftNode, ctx)} != ${transpile(rightNode, ctx)}`;
|
|
@@ -20,11 +20,12 @@ export class TSVGenerator {
|
|
|
20
20
|
'mandatory',
|
|
21
21
|
'other',
|
|
22
22
|
'default',
|
|
23
|
-
'same_default'
|
|
23
|
+
'same_default',
|
|
24
|
+
'hidden'
|
|
24
25
|
];
|
|
25
26
|
const lines = [headers.join('\t')];
|
|
26
27
|
for (const row of this.rows) {
|
|
27
|
-
const values = headers.map((h) => this.escapeForTSV(row[h]
|
|
28
|
+
const values = headers.map((h) => this.escapeForTSV(row[h] ?? ''));
|
|
28
29
|
lines.push(values.join('\t'));
|
|
29
30
|
}
|
|
30
31
|
return lines.join('\n');
|
package/dist/xlsformConverter.js
CHANGED
|
@@ -553,7 +553,7 @@ export class XLSFormToTSVConverter {
|
|
|
553
553
|
* Transpile an XLSForm calculation expression to a LimeSurvey EM expression.
|
|
554
554
|
*/
|
|
555
555
|
async convertCalculation(calculation) {
|
|
556
|
-
return await xpathToLimeSurvey(calculation);
|
|
556
|
+
return await xpathToLimeSurvey(calculation, this.buildTranspilerContext());
|
|
557
557
|
}
|
|
558
558
|
async addGroup(row) {
|
|
559
559
|
// Auto-generate name if missing (matches LimeSurvey behavior)
|
|
@@ -572,10 +572,10 @@ export class XLSFormToTSVConverter {
|
|
|
572
572
|
this.tsvGenerator.addRow({
|
|
573
573
|
class: 'G',
|
|
574
574
|
'type/scale': groupSeqKey,
|
|
575
|
-
name: groupName,
|
|
575
|
+
name: this.getLanguageSpecificValue(row.label, lang) || groupName,
|
|
576
576
|
relevance: await this.convertRelevance(row.relevant),
|
|
577
|
-
text: this.getLanguageSpecificValue(row.
|
|
578
|
-
help:
|
|
577
|
+
text: this.getLanguageSpecificValue(row.hint, lang) || '',
|
|
578
|
+
help: '',
|
|
579
579
|
language: lang,
|
|
580
580
|
validation: '',
|
|
581
581
|
em_validation_q: "",
|
|
@@ -659,7 +659,8 @@ export class XLSFormToTSVConverter {
|
|
|
659
659
|
mandatory: (isNote || isCalculate) ? '' : (row.required === 'yes' || row.required === 'true' ? 'Y' : ''),
|
|
660
660
|
other: (isNote || isCalculate) ? '' : (lsType.other ? 'Y' : ''),
|
|
661
661
|
default: (isNote || isCalculate) ? '' : (row.default || ''),
|
|
662
|
-
same_default: ''
|
|
662
|
+
same_default: '',
|
|
663
|
+
hidden: isCalculate ? '1' : '',
|
|
663
664
|
});
|
|
664
665
|
}
|
|
665
666
|
// Reset answer sequence for this question
|
|
@@ -831,10 +832,8 @@ export class XLSFormToTSVConverter {
|
|
|
831
832
|
return { code: choiceValue, listName };
|
|
832
833
|
return { code: codeMap.get(choiceValue) ?? choiceValue, listName };
|
|
833
834
|
}
|
|
834
|
-
|
|
835
|
-
|
|
836
|
-
return '1';
|
|
837
|
-
const ctx = {
|
|
835
|
+
buildTranspilerContext() {
|
|
836
|
+
return {
|
|
838
837
|
lookupAnswerCode: (fieldName, choiceValue) => {
|
|
839
838
|
return this.lookupAnswerCode(fieldName, choiceValue).code;
|
|
840
839
|
},
|
|
@@ -843,11 +842,15 @@ export class XLSFormToTSVConverter {
|
|
|
843
842
|
const { code } = this.lookupAnswerCode(fieldName, choiceValue);
|
|
844
843
|
const baseType = this.questionBaseTypeMap.get(truncated);
|
|
845
844
|
if (baseType === 'select_multiple') {
|
|
846
|
-
return `(${truncated}_${code}.NAOK ==
|
|
845
|
+
return `(${truncated}_${code}.NAOK == 'Y')`;
|
|
847
846
|
}
|
|
848
|
-
return `(${truncated}.NAOK==
|
|
847
|
+
return `(${truncated}.NAOK=='${code}')`;
|
|
849
848
|
},
|
|
850
849
|
};
|
|
851
|
-
|
|
850
|
+
}
|
|
851
|
+
async convertRelevance(relevant) {
|
|
852
|
+
if (!relevant)
|
|
853
|
+
return '1';
|
|
854
|
+
return await convertRelevance(relevant, this.buildTranspilerContext());
|
|
852
855
|
}
|
|
853
856
|
}
|