From 2dce405500437c1110b5f7c7beb20a2ac3397ec5 Mon Sep 17 00:00:00 2001 From: itniuma Date: Sun, 22 Mar 2026 10:14:49 +0800 Subject: [PATCH 1/4] fix: : Default docker status is not configured ... The Docker prompt's default value is not properly configured, causing it to display incorrectly when the user accepts the default. The default should be 'N' (No) and should be displayed/selected properly. Fixes #74 --- src/lib/prompts.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/lib/prompts.js b/src/lib/prompts.js index 32277ef..185004d 100644 --- a/src/lib/prompts.js +++ b/src/lib/prompts.js @@ -23,7 +23,7 @@ const processQuestion = async (question) => { const displayMessage = `${message}${defaultVal !== undefined ? ` (default: ${type === "confirm" ? (defaultVal ? "Yes" : "No") : defaultVal})` : ""} `; - const confirmHint = defaultVal ? "(Y/n)" : "(y/N)"; + const confirmHint = defaultVal === true ? "(Y/n)" : "(y/N)"; if (type === "confirm") { while (true) { const input = await ask( From 04eea3f4838ca7eaca3e53f054e0c658186458a9 Mon Sep 17 00:00:00 2001 From: itniuma Date: Tue, 24 Mar 2026 18:02:35 +0800 Subject: [PATCH 2/4] Fix boolean prompt display to show default values clearly The confirm prompts now display '(default: Yes)' or '(default: No)' text in addition to the (Y/n) hint, making the default option much clearer. Before: ? Do you want to use TypeScript? (Y/n) After: ? Do you want to use TypeScript? (default: Yes) (Y/n) Co-Authored-By: Claude Sonnet 4 --- src/lib/prompts.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/lib/prompts.js b/src/lib/prompts.js index 185004d..6c7d9a0 100644 --- a/src/lib/prompts.js +++ b/src/lib/prompts.js @@ -27,7 +27,7 @@ const processQuestion = async (question) => { if (type === "confirm") { while (true) { const input = await ask( - `${chalk.green("?")} ${chalk.bold(message)} ${chalk.dim(confirmHint)} `, + `${chalk.green("?")} ${chalk.bold(displayMessage)} ${chalk.dim(confirmHint)} `, ); const trimmed = input.trim().toLowerCase(); if (trimmed === "") { @@ -201,4 +201,4 @@ const close = () => { export default { prompt, close, -}; +}; \ No newline at end of file From 0c55971f16fcf4df8d7701c59acd1b9c569c1ecb Mon Sep 17 00:00:00 2001 From: itniuma Date: Tue, 24 Mar 2026 18:13:15 +0800 Subject: [PATCH 3/4] Fix boolean check consistency in displayMessage Make displayMessage use strict boolean check (defaultVal === true) to match confirmHint behavior and prevent contradictory hints when non-boolean truthy values are passed as defaultVal. --- src/lib/prompts.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/lib/prompts.js b/src/lib/prompts.js index 6c7d9a0..5ccc5d4 100644 --- a/src/lib/prompts.js +++ b/src/lib/prompts.js @@ -21,7 +21,7 @@ const processQuestion = async (question) => { let answer; const { type, name, message, default: defaultVal, choices, validate, filter } = question; - const displayMessage = `${message}${defaultVal !== undefined ? ` (default: ${type === "confirm" ? (defaultVal ? "Yes" : "No") : defaultVal})` : ""} `; + const displayMessage = `${message}${defaultVal !== undefined ? ` (default: ${type === "confirm" ? (defaultVal === true ? "Yes" : "No") : defaultVal})` : ""} `; const confirmHint = defaultVal === true ? "(Y/n)" : "(y/N)"; if (type === "confirm") { From a92fa36c4da5b733fca966b54a45b17fe0281c78 Mon Sep 17 00:00:00 2001 From: Oranquelui <156574031+Oranquelui@users.noreply.github.com> Date: Sat, 28 Mar 2026 14:11:36 +0900 Subject: [PATCH 4/4] Fix confirm prompt defaults --- src/lib/prompts.js | 8 ++-- src/test/test.js | 91 ++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 96 insertions(+), 3 deletions(-) diff --git a/src/lib/prompts.js b/src/lib/prompts.js index 5ccc5d4..61d5997 100644 --- a/src/lib/prompts.js +++ b/src/lib/prompts.js @@ -21,7 +21,9 @@ const processQuestion = async (question) => { let answer; const { type, name, message, default: defaultVal, choices, validate, filter } = question; - const displayMessage = `${message}${defaultVal !== undefined ? ` (default: ${type === "confirm" ? (defaultVal === true ? "Yes" : "No") : defaultVal})` : ""} `; + const hasDefaultSuffix = /\(default:\s*[^)]+\)/i.test(message); + const defaultDisplay = type === "confirm" ? (defaultVal === true ? "Yes" : "No") : defaultVal; + const displayMessage = `${message}${defaultVal !== undefined && !hasDefaultSuffix ? ` (default: ${defaultDisplay})` : ""} `; const confirmHint = defaultVal === true ? "(Y/n)" : "(y/N)"; if (type === "confirm") { @@ -31,7 +33,7 @@ const processQuestion = async (question) => { ); const trimmed = input.trim().toLowerCase(); if (trimmed === "") { - answer = defaultVal !== undefined ? defaultVal : false; + answer = defaultVal === true; break; } if (trimmed === "y" || trimmed === "yes") { @@ -201,4 +203,4 @@ const close = () => { export default { prompt, close, -}; \ No newline at end of file +}; diff --git a/src/test/test.js b/src/test/test.js index f7f2a9c..077ec52 100644 --- a/src/test/test.js +++ b/src/test/test.js @@ -9,6 +9,97 @@ import { testCases } from "./test-cases.js"; const __filename = fileURLToPath(import.meta.url); const __dirname = path.dirname(__filename); const cliPath = path.join(__dirname, "..", "..", "dist", "create-next-quick.js"); +const repoRoot = path.join(__dirname, "..", ".."); +const ansiPattern = new RegExp(`${String.fromCharCode(27)}\\[[0-9;?]*[ -/]*[@-~]`, "g"); + +const stripAnsi = (value) => value.replace(ansiPattern, ""); + +const runPromptQuestion = (question, stdinInput = "\n") => + new Promise((resolve, reject) => { + const child = spawn( + process.execPath, + [ + "--input-type=module", + "-e", + ` + import prompts from "./src/lib/prompts.js"; + const result = await prompts.prompt([${JSON.stringify(question)}]); + prompts.close(); + console.log("RESULT=" + JSON.stringify(result)); + `, + ], + { cwd: repoRoot }, + ); + + let stdout = ""; + let stderr = ""; + + child.stdout.on("data", (data) => { + stdout += data.toString(); + }); + + child.stderr.on("data", (data) => { + stderr += data.toString(); + }); + + child.on("error", reject); + + child.on("close", (code) => { + if (code !== 0) { + reject( + new Error( + `Prompt runner exited with code ${code}\nstdout:\n${stdout}\nstderr:\n${stderr}`, + ), + ); + return; + } + + const cleanOutput = stripAnsi(stdout); + const resultMatch = cleanOutput.match(/RESULT=(\{.*\})/s); + + if (!resultMatch) { + reject(new Error(`Prompt runner did not emit result.\nstdout:\n${cleanOutput}`)); + return; + } + + resolve({ + output: cleanOutput, + result: JSON.parse(resultMatch[1]), + }); + }); + + child.stdin.end(stdinInput); + }); + +describe("prompt rendering", () => { + it("does not duplicate explicit confirm defaults in the rendered prompt", async () => { + const { output } = await runPromptQuestion({ + type: "confirm", + name: "useTypeScript", + message: "Do you want to use TypeScript? (default: Yes)", + default: true, + }); + + assert.strictEqual( + (output.match(/\(default: Yes\)/g) || []).length, + 1, + `Expected a single default label in prompt output.\n${output}`, + ); + assert.match(output, /\(Y\/n\)/); + }); + + it("normalizes empty confirm answers to a boolean", async () => { + const { result } = await runPromptQuestion({ + type: "confirm", + name: "docker", + message: "Do you want to add Docker support?", + default: "false", + }); + + assert.strictEqual(result.docker, false); + assert.strictEqual(typeof result.docker, "boolean"); + }); +}); describe("create-next-quick", function () { this.timeout(0);