diff --git a/.changeset/promptless-commands.md b/.changeset/promptless-commands.md new file mode 100644 index 000000000..392502ac0 --- /dev/null +++ b/.changeset/promptless-commands.md @@ -0,0 +1,5 @@ +--- +'sv': patch +--- + +feat(cli): Add promptless command to `README.md` on `sv create` diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index b9ff153a7..4bc8fec2c 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -6,7 +6,7 @@ We follow the standard fork-based workflow: 1. **Fork** this repository to your GitHub account. 2. **Clone** your fork locally. -3. **Create a new branch** for your change: +3. **Create a new branch** for your change: `git checkout -b your-feature-name` 4. **Commit and push** your changes to your branch. 5. **Open a pull request** from your branch to the `main` branch of this repository. @@ -80,7 +80,9 @@ Run specific tests by specifying a project flag to the package and running the t pnpm test --project cli # core / addons / create / migrate ``` -Example of how to debug an addon failing test. Once, you ran the test command, you will have a directory in `.test-output` with the test id. A good starting point is to `cd` into the failing tests dir. Proceed to `build` it. Then `preview` it. From here you will have increased information to help in the debug process. Eg: +### Debugging + +Example of how to debug an addon failing test. Once, you ran the test command, you will have a directory in `.test-output` with the test id. A good starting point is to `cd` into the failing tests dir. Proceed to `build` it. Then `preview` it. From here you will have increased information to help in the debug process. E.g.: ```sh pnpm test --project addons tailwind # to debug the tailwind addon failing test @@ -90,6 +92,17 @@ pnpm build pnpm preview ``` +### Update snapshots + +Some snapshots are testing the output of `sv` directly from the generated binary. They are located in `packages/sv/lib/cli/tests/snapshots`. Make sure to generate a new binary before updating these snapshots. + +In one command: + +```sh +pnpm build && pnpm test:ui --project cli +# Press `u` when prompted to update snapshots. +``` + ## Style Guide ### Coding style diff --git a/packages/sv/lib/cli/add/index.ts b/packages/sv/lib/cli/add/index.ts index 84ce81469..9d0ea7145 100644 --- a/packages/sv/lib/cli/add/index.ts +++ b/packages/sv/lib/cli/add/index.ts @@ -658,7 +658,7 @@ export async function runAddonsApply({ } } - if (fromCommand === 'add') common.logArgs(packageManager, 'add', argsFormattedAddons); + if (fromCommand === 'add') common.buildAndLogArgs(packageManager, 'add', argsFormattedAddons); if (packageManager) { workspace.packageManager = packageManager; diff --git a/packages/sv/lib/cli/create.ts b/packages/sv/lib/cli/create.ts index e02d2eeb6..457393cd1 100644 --- a/packages/sv/lib/cli/create.ts +++ b/packages/sv/lib/cli/create.ts @@ -149,7 +149,7 @@ async function createProject(cwd: ProjectPath, options: Options) { directory: () => { const defaultPath = './'; if (cwd) { - return Promise.resolve(cwd); + return Promise.resolve(common.normalizePosix(cwd)); } return p.text({ message: 'Where would you like your project to be created?', @@ -307,7 +307,8 @@ async function createProject(cwd: ProjectPath, options: Options) { if (argsFormattedAddons.length > 0) argsFormatted.push('--add', ...argsFormattedAddons); - common.logArgs(packageManager, 'create', argsFormatted, [directory]); + const prompt = common.buildAndLogArgs(packageManager, 'create', argsFormatted, [directory]); + common.updateReadme(directory, prompt); await addPnpmBuildDependencies(projectPath, packageManager, ['esbuild']); if (packageManager) { diff --git a/packages/sv/lib/cli/tests/cli.ts b/packages/sv/lib/cli/tests/cli.ts index f7088f7b8..39bb080bd 100644 --- a/packages/sv/lib/cli/tests/cli.ts +++ b/packages/sv/lib/cli/tests/cli.ts @@ -45,7 +45,10 @@ describe('cli', () => { async (testCase) => { const { projectName, args } = testCase; const svBinPath = path.resolve(monoRepoPath, 'packages', 'sv', 'dist', 'bin.mjs'); - const testOutputPath = path.resolve(monoRepoPath, '.test-output', 'cli', projectName); + const testOutputPath = path.relative( + monoRepoPath, + path.resolve(monoRepoPath, '.test-output', 'cli', projectName) + ); const result = await exec( 'node', diff --git a/packages/sv/lib/cli/tests/common.ts b/packages/sv/lib/cli/tests/common.ts index 16b394bd9..66fb06071 100644 --- a/packages/sv/lib/cli/tests/common.ts +++ b/packages/sv/lib/cli/tests/common.ts @@ -1,5 +1,16 @@ import { describe, expect, it } from 'vitest'; -import { parseAddonOptions } from '../utils/common.ts'; +import { normalizePosix, parseAddonOptions } from '../utils/common.ts'; + +describe('normalizePosix', () => { + const std = 'this/is/going/forward'; + it('normalizes windows', () => { + const stdWindows = 'this\\is\\going\\forward'; + expect(normalizePosix(stdWindows)).toEqual(std); + }); + it('normalizes unix', () => { + expect(normalizePosix(std)).toEqual(std); + }); +}); describe('parseAddonOptions', () => { it('returns undefined on undefined', () => { diff --git a/packages/sv/lib/cli/tests/snapshots/create-only/README.md b/packages/sv/lib/cli/tests/snapshots/create-only/README.md index 75842c404..012e54b18 100644 --- a/packages/sv/lib/cli/tests/snapshots/create-only/README.md +++ b/packages/sv/lib/cli/tests/snapshots/create-only/README.md @@ -7,13 +7,17 @@ Everything you need to build a Svelte project, powered by [`sv`](https://github. If you're seeing this, you've probably already done this step. Congrats! ```sh -# create a new project in the current directory -npx sv create - -# create a new project in my-app +# create a new project npx sv create my-app ``` +To recreate this project with the same configuration: + +```sh +# recreate this project +npx sv create --template minimal --types ts --no-install .test-output/cli/create-only +``` + ## Developing Once you've created a project and installed dependencies with `npm install` (or `pnpm install` or `yarn`), start a development server: diff --git a/packages/sv/lib/cli/tests/snapshots/create-with-all-addons/README.md b/packages/sv/lib/cli/tests/snapshots/create-with-all-addons/README.md index 75842c404..4c4ecca27 100644 --- a/packages/sv/lib/cli/tests/snapshots/create-with-all-addons/README.md +++ b/packages/sv/lib/cli/tests/snapshots/create-with-all-addons/README.md @@ -7,13 +7,17 @@ Everything you need to build a Svelte project, powered by [`sv`](https://github. If you're seeing this, you've probably already done this step. Congrats! ```sh -# create a new project in the current directory -npx sv create - -# create a new project in my-app +# create a new project npx sv create my-app ``` +To recreate this project with the same configuration: + +```sh +# recreate this project +npx sv create --template minimal --types ts --add prettier eslint vitest="usages:unit,component" playwright tailwindcss="plugins:typography,forms" sveltekit-adapter="adapter:node" devtools-json drizzle="database:sqlite+sqlite:libsql" lucia="demo:yes" mdsvex paraglide="languageTags:en,es+demo:yes" mcp="ide:claude-code,cursor,gemini,opencode,vscode,other+setup:local" --no-install .test-output/cli/create-with-all-addons +``` + ## Developing Once you've created a project and installed dependencies with `npm install` (or `pnpm install` or `yarn`), start a development server: diff --git a/packages/sv/lib/cli/utils/common.ts b/packages/sv/lib/cli/utils/common.ts index d377525f2..e00a9fd3d 100644 --- a/packages/sv/lib/cli/utils/common.ts +++ b/packages/sv/lib/cli/utils/common.ts @@ -1,4 +1,6 @@ import pc from 'picocolors'; +import fs from 'node:fs'; +import path from 'node:path'; import pkg from '../../../package.json' with { type: 'json' }; import * as p from '@clack/prompts'; import type { Argument, HelpConfiguration, Option } from 'commander'; @@ -137,12 +139,12 @@ export function parseAddonOptions(optionFlags: string | undefined): string[] | u return options; } -export function logArgs( +export function buildAndLogArgs( agent: AgentName | null | undefined, command: 'create' | 'add', args: string[], lastArgs: string[] = [] -) { +): string { const allArgs = ['sv', command, ...args]; // Handle install option @@ -150,7 +152,36 @@ export function logArgs( else allArgs.push('--install', agent); const res = resolveCommand(agent ?? 'npm', 'execute', [...allArgs, ...lastArgs])!; - p.log.message(pc.dim([res.command, ...res.args].join(' '))); + const message = [res.command, ...res.args].join(' '); + + p.log.info(pc.dim(`Re-run without prompts:\n${message}`)); + + return message; +} + +export function updateReadme(projectPath: string, command: string) { + const readmePath = path.join(projectPath, 'README.md'); + if (!fs.existsSync(readmePath)) return; + + let content = fs.readFileSync(readmePath, 'utf-8'); + + // Check if the Creating a project section exists + const creatingSectionPattern = /## Creating a project[\s\S]*?(?=## |$)/; + const creatingSectionMatch = content.match(creatingSectionPattern); + if (!creatingSectionMatch) return; + + // Append to the existing Creating a project section + const existingSection = creatingSectionMatch[0]; + const updatedSection = + `${existingSection.trim()}\n\n` + + 'To recreate this project with the same configuration:\n\n' + + '```sh\n' + + '# recreate this project\n' + + `${command}\n` + + '```\n\n'; + + content = content.replace(creatingSectionPattern, updatedSection); + fs.writeFileSync(readmePath, content); } export function errorAndExit(message: string) { @@ -158,3 +189,7 @@ export function errorAndExit(message: string) { p.cancel('Operation failed.'); process.exit(1); } + +export const normalizePosix = (dir: string) => { + return path.posix.normalize(dir.replace(/\\/g, '/')); +}; diff --git a/packages/sv/lib/create/shared/README.md b/packages/sv/lib/create/shared/README.md index 75842c404..a0da9f54d 100644 --- a/packages/sv/lib/create/shared/README.md +++ b/packages/sv/lib/create/shared/README.md @@ -7,10 +7,7 @@ Everything you need to build a Svelte project, powered by [`sv`](https://github. If you're seeing this, you've probably already done this step. Congrats! ```sh -# create a new project in the current directory -npx sv create - -# create a new project in my-app +# create a new project npx sv create my-app ```