chore(ask): reorganize docs and fix repo checks

This commit is contained in:
Erik Kotsiuba
2026-04-18 21:31:39 +02:00
parent 3ec7af2fd8
commit 884c5fcf0d
38 changed files with 704 additions and 519 deletions
+17 -10
View File
@@ -1,6 +1,10 @@
import assert from "node:assert/strict";
import test from "node:test";
import { applyNumberShortcut, createInitialState, enterQuestionNoteMode } from "../src/state.ts";
import { createInitialState } from "../src/state/create.ts";
import {
applyNumberShortcut,
enterQuestionNoteMode,
} from "../src/state/transitions.ts";
import { getInputCommand } from "../src/ui/input.ts";
function inputState() {
@@ -30,15 +34,18 @@ test("editing views let up and down move navigation", () => {
});
test("note editing views let up and down move navigation", () => {
const state = enterQuestionNoteMode(createInitialState({
questions: [
{
id: "q1",
prompt: "Question?",
options: [{ value: "a", label: "A" }],
},
],
}), "q1");
const state = enterQuestionNoteMode(
createInitialState({
questions: [
{
id: "q1",
prompt: "Question?",
options: [{ value: "a", label: "A" }],
},
],
}),
"q1"
);
assert.deepEqual(getInputCommand(state, "\x1b[A"), {
kind: "editMoveOption",
+8 -4
View File
@@ -2,6 +2,10 @@ import assert from "node:assert/strict";
import test from "node:test";
import { renderEditorBlock } from "../src/ui/render-helpers.ts";
const ABC_PATTERN = /abc/;
const BORDER_PATTERN = /┌|└/;
const TYPE_YOUR_PATTERN = /Type your/;
function mockTheme() {
return {
fg(color: string, text: string) {
@@ -25,8 +29,8 @@ test("renderEditorBlock strips editor borders", () => {
});
assert.equal(lines.length, 1);
assert.match(lines[0], /abc/);
assert.doesNotMatch(lines[0], /┌|└/);
assert.match(lines[0], ABC_PATTERN);
assert.doesNotMatch(lines[0], BORDER_PATTERN);
});
test("renderEditorBlock shows a muted placeholder when empty", () => {
@@ -43,6 +47,6 @@ test("renderEditorBlock shows a muted placeholder when empty", () => {
});
assert.equal(lines.length, 1);
assert.match(lines[0], /Type your/);
assert.doesNotMatch(lines[0], /┌|└/);
assert.match(lines[0], TYPE_YOUR_PATTERN);
assert.doesNotMatch(lines[0], BORDER_PATTERN);
});
+8 -7
View File
@@ -1,7 +1,8 @@
import assert from "node:assert/strict";
import test from "node:test";
import { applyNumberShortcut, createInitialState } from "../src/state.ts";
import { createInitialState } from "../src/state/create.ts";
import { getRenderableOptions } from "../src/state/selectors.ts";
import { applyNumberShortcut } from "../src/state/transitions.ts";
import { renderQuestionScreen } from "../src/ui/render-question.ts";
function mockTheme() {
@@ -42,13 +43,13 @@ test("custom option stays labeled before selection", () => {
const lines: string[] = [];
renderQuestionScreen({
editor: mockEditor(),
lines,
state,
question: state.questions[0],
options: getRenderableOptions(state.questions[0]),
question: state.questions[0],
state,
theme: mockTheme(),
width: 80,
editor: mockEditor(),
});
assert(lines.some((line) => line.includes("Type your own")));
@@ -69,13 +70,13 @@ test("selected custom option becomes inline input", () => {
const lines: string[] = [];
renderQuestionScreen({
editor: mockEditor(""),
lines,
state,
question: state.questions[0],
options: getRenderableOptions(state.questions[0]),
question: state.questions[0],
state,
theme: mockTheme(),
width: 80,
editor: mockEditor(""),
});
assert(lines.some((line) => line.includes("Type your answer...")));
+6 -7
View File
@@ -1,16 +1,15 @@
import assert from "node:assert/strict";
import test from "node:test";
import { renderResultText } from "../src/result.ts";
import { createInitialState } from "../src/state/create.ts";
import { summarizeResult, toAskResult } from "../src/state/result.ts";
import {
applyNumberShortcut,
createInitialState,
enterOptionNoteMode,
enterQuestionNoteMode,
saveNote,
submitCustomAnswer,
summarizeResult,
toAskResult,
} from "../src/state.ts";
} from "../src/state/transitions.ts";
test("summarizeResult formats selected answers", () => {
let state = createInitialState({
@@ -53,7 +52,7 @@ test("summaries include custom text answers", () => {
assert.equal(summarizeResult(result), "Notes: Please include examples");
assert.equal(
renderResultText(result),
"✓ Notes: (wrote) Please include examples",
"✓ Notes: (wrote) Please include examples"
);
});
@@ -85,7 +84,7 @@ test("summaries and result text include question and selected option notes", ()
"Framework: Vue",
"Framework note: Need SSR support",
"Framework / Vue note: Team has prior experience",
].join("\n"),
].join("\n")
);
assert.equal(
renderResultText(result),
@@ -93,7 +92,7 @@ test("summaries and result text include question and selected option notes", ()
"✓ Framework: Vue",
" note: Need SSR support",
" Vue note: Team has prior experience",
].join("\n"),
].join("\n")
);
});
+11 -11
View File
@@ -1,21 +1,21 @@
import assert from "node:assert/strict";
import test from "node:test";
import { createInitialState } from "../src/state/create.ts";
import { toAskResult } from "../src/state/result.ts";
import { getRenderableOptions } from "../src/state/selectors.ts";
import {
applyNumberShortcut,
cancelFlow,
confirmCurrentSelection,
createInitialState,
enterOptionNoteMode,
enterQuestionNoteMode,
getRenderableOptions,
moveOption,
moveTab,
saveCustomAnswer,
saveNote,
submitCustomAnswer,
toAskResult,
toggleCurrentMultiOption,
} from "../src/state.ts";
} from "../src/state/transitions.ts";
import type { AskParams } from "../src/types.ts";
function sampleParams(): AskParams {
@@ -61,11 +61,11 @@ test("normalize defaults via initial state", () => {
assert.equal(state.questions[0].required, true);
assert.equal(
getRenderableOptions(state.questions[0]).at(-1)?.label,
"Type your own",
"Type your own"
);
assert.equal(
getRenderableOptions(state.questions[0]).at(-1)?.isCustomOption,
true,
true
);
});
@@ -86,7 +86,7 @@ test("preview questions keep their type and option previews", () => {
assert.equal(state.questions[0].options[0].preview, "Example");
assert.equal(
getRenderableOptions(state.questions[0]).at(-1)?.isCustomOption,
undefined,
undefined
);
assert.equal(getRenderableOptions(state.questions[0]).length, 1);
});
@@ -106,14 +106,14 @@ test("multi-select space toggles current option and enter advances to submit", (
state = toggleCurrentMultiOption(state);
assert.deepEqual(
state.answers.fe.selected.map((selection) => selection.label),
["React"],
["React"]
);
state = moveOption(state, 1);
state = toggleCurrentMultiOption(state);
assert.deepEqual(
state.answers.fe.selected.map((selection) => selection.label),
["React", "Vue"],
["React", "Vue"]
);
state = confirmCurrentSelection(state);
@@ -254,13 +254,13 @@ test("option notes can exist before selection but only selected option notes are
state = toggleCurrentMultiOption(state);
assert.deepEqual(
state.answers.q1.selected.map((selection) => selection.value),
["react"],
["react"]
);
state = moveOption(state, 1);
state = toggleCurrentMultiOption(state);
assert.deepEqual(
state.answers.q1.selected.map((selection) => selection.value),
["react", "vue"],
["react", "vue"]
);
assert.deepEqual(toAskResult(state).answers.q1.optionNotes, {
vue: "maybe later",