questionnaire: Guard empty options and dedup IDs
Amolith
created 1 week ago
When a question has no options and allowOther is false, the opts array
is empty but optionIndex is 0. Accessing opts[0].isOther crashes with a
TypeError on undefined. Add an early return when the selected option
does not exist.
Deduplicate question IDs at normalization time by appending _2, _3, etc.
to collisions. Duplicate IDs caused answer map overwrites where only the
last answer for a given ID survived.
Change summary
packages/questionnaire/src/index.ts | 24 ++++++++++++++++++------
1 file changed, 18 insertions(+), 6 deletions(-)
Detailed changes
@@ -101,12 +101,23 @@ export default function questionnaire(pi: ExtensionAPI) {
return errorResult("Error: No questions provided");
}
- // Normalize questions with defaults
- const questions: Question[] = params.questions.map((q, i) => ({
- ...q,
- label: q.label || `Q${i + 1}`,
- allowOther: q.allowOther !== false,
- }));
+ // Normalize questions with defaults and deduplicate IDs
+ const seenIds = new Set<string>();
+ const questions: Question[] = params.questions.map((q, i) => {
+ let id = q.id;
+ if (seenIds.has(id)) {
+ let suffix = 2;
+ while (seenIds.has(`${id}_${suffix}`)) suffix++;
+ id = `${id}_${suffix}`;
+ }
+ seenIds.add(id);
+ return {
+ ...q,
+ id,
+ label: q.label || `Q${i + 1}`,
+ allowOther: q.allowOther !== false,
+ };
+ });
const isMulti = questions.length > 1;
const totalTabs = questions.length + 1; // questions + Submit
@@ -284,6 +295,7 @@ export default function questionnaire(pi: ExtensionAPI) {
// Select option
if (matchesKey(data, Key.enter) && q) {
const opt = opts[optionIndex];
+ if (!opt) return; // no options available
if (opt.isOther) {
inputMode = true;
inputQuestionId = q.id;