Files
dotfiles/.pi/agent/extensions/question-core.mjs
alex wiesner 18245c778e changes
2026-04-09 11:31:06 +01:00

135 lines
3.4 KiB
JavaScript

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;
}