initial commit
This commit is contained in:
134
question-core.mjs
Normal file
134
question-core.mjs
Normal file
@@ -0,0 +1,134 @@
|
||||
export const SOMETHING_ELSE_VALUE = "__something_else__";
|
||||
export const SOMETHING_ELSE_LABEL = "Something else…";
|
||||
|
||||
export function normalizeQuestions(inputQuestions) {
|
||||
return inputQuestions.map((question, index) => ({
|
||||
...question,
|
||||
label: question.label?.trim() ? question.label : `Q${index + 1}`,
|
||||
options: [
|
||||
...question.options,
|
||||
{
|
||||
value: SOMETHING_ELSE_VALUE,
|
||||
label: SOMETHING_ELSE_LABEL,
|
||||
},
|
||||
],
|
||||
}));
|
||||
}
|
||||
|
||||
export function isSomethingElseOption(option) {
|
||||
return option?.value === SOMETHING_ELSE_VALUE;
|
||||
}
|
||||
|
||||
export function createPredefinedAnswer(questionId, option, index) {
|
||||
return {
|
||||
id: questionId,
|
||||
value: option.value,
|
||||
label: option.label,
|
||||
wasCustom: false,
|
||||
index,
|
||||
};
|
||||
}
|
||||
|
||||
export function createCustomAnswer(questionId, text) {
|
||||
return {
|
||||
id: questionId,
|
||||
value: text,
|
||||
label: text,
|
||||
wasCustom: true,
|
||||
};
|
||||
}
|
||||
|
||||
export function summarizeAnswers(questions, answers) {
|
||||
const answerById = new Map(answers.map((answer) => [answer.id, answer]));
|
||||
return questions.flatMap((question) => {
|
||||
const answer = answerById.get(question.id);
|
||||
if (!answer) return [];
|
||||
if (answer.wasCustom) {
|
||||
return [`${question.label}: user wrote: ${answer.label}`];
|
||||
}
|
||||
return [`${question.label}: user selected: ${answer.index}. ${answer.label}`];
|
||||
});
|
||||
}
|
||||
|
||||
export function createCancelledResult(questions = []) {
|
||||
return {
|
||||
questions,
|
||||
answers: [],
|
||||
cancelled: true,
|
||||
};
|
||||
}
|
||||
|
||||
export function createAnsweredResult(questions, answers) {
|
||||
const order = new Map(questions.map((question, index) => [question.id, index]));
|
||||
return {
|
||||
questions,
|
||||
answers: [...answers].sort(
|
||||
(left, right) => (order.get(left.id) ?? Number.POSITIVE_INFINITY) - (order.get(right.id) ?? Number.POSITIVE_INFINITY),
|
||||
),
|
||||
cancelled: false,
|
||||
};
|
||||
}
|
||||
|
||||
export function allQuestionsAnswered(questions, answers) {
|
||||
return questions.every((question) => answers.has(question.id));
|
||||
}
|
||||
|
||||
export function nextTabAfterAnswer(currentTab, questionCount) {
|
||||
return currentTab < questionCount - 1 ? currentTab + 1 : questionCount;
|
||||
}
|
||||
|
||||
function takeWrappedSegment(text, maxWidth) {
|
||||
if (text.length <= maxWidth) {
|
||||
return { line: text, rest: "" };
|
||||
}
|
||||
|
||||
let breakpoint = -1;
|
||||
for (let index = 0; index < maxWidth; index += 1) {
|
||||
if (/\s/.test(text[index])) {
|
||||
breakpoint = index;
|
||||
}
|
||||
}
|
||||
|
||||
if (breakpoint > 0) {
|
||||
return {
|
||||
line: text.slice(0, breakpoint).trimEnd(),
|
||||
rest: text.slice(breakpoint + 1).trimStart(),
|
||||
};
|
||||
}
|
||||
|
||||
return {
|
||||
line: text.slice(0, maxWidth),
|
||||
rest: text.slice(maxWidth),
|
||||
};
|
||||
}
|
||||
|
||||
export function wrapPrefixedText(text, width, firstPrefix = "", continuationPrefix = firstPrefix) {
|
||||
const source = String(text ?? "");
|
||||
if (source.length === 0) {
|
||||
return [firstPrefix];
|
||||
}
|
||||
|
||||
const lines = [];
|
||||
const blocks = source.split(/\r?\n/);
|
||||
let isFirstLine = true;
|
||||
|
||||
for (const block of blocks) {
|
||||
let remaining = block.trim();
|
||||
if (remaining.length === 0) {
|
||||
lines.push(isFirstLine ? firstPrefix : continuationPrefix);
|
||||
isFirstLine = false;
|
||||
continue;
|
||||
}
|
||||
|
||||
while (remaining.length > 0) {
|
||||
const prefix = isFirstLine ? firstPrefix : continuationPrefix;
|
||||
const maxTextWidth = Math.max(1, width - prefix.length);
|
||||
const { line, rest } = takeWrappedSegment(remaining, maxTextWidth);
|
||||
lines.push(prefix + line);
|
||||
remaining = rest;
|
||||
isFirstLine = false;
|
||||
}
|
||||
}
|
||||
|
||||
return lines;
|
||||
}
|
||||
Reference in New Issue
Block a user