diff --git a/.changeset/lucky-apes-yell.md b/.changeset/lucky-apes-yell.md new file mode 100644 index 0000000000..ea244403e5 --- /dev/null +++ b/.changeset/lucky-apes-yell.md @@ -0,0 +1,5 @@ +--- +'astro': patch +--- + +Update "astro add" output to remove confusing multi-select prompt. diff --git a/.changeset/perfect-drinks-fold.md b/.changeset/perfect-drinks-fold.md new file mode 100644 index 0000000000..2af9edabaf --- /dev/null +++ b/.changeset/perfect-drinks-fold.md @@ -0,0 +1,5 @@ +--- +'astro': patch +--- + +Update the help output to improve formatting diff --git a/packages/astro/src/cli/index.ts b/packages/astro/src/cli/index.ts index 7fd3b25728..ab38daa094 100644 --- a/packages/astro/src/cli/index.ts +++ b/packages/astro/src/cli/index.ts @@ -37,26 +37,27 @@ type CLICommand = function printAstroHelp() { printHelp({ commandName: 'astro', + usage: '[command] [...flags]', headline: 'Futuristic web development tool.', - commands: [ - ['add', 'Add an integration to your configuration.'], - ['docs', "Launch Astro's Doc site directly from the terminal. "], - ['dev', 'Run Astro in development mode.'], - ['build', 'Build a pre-compiled production-ready site.'], - ['preview', 'Preview your build locally before deploying.'], - ['check', 'Check your project for errors.'], - ['telemetry', 'Enable/disable anonymous data collection.'], - ['--version', 'Show the version number and exit.'], - ['--help', 'Show this help message.'], - ], - flags: [ - ['--host [optional IP]', 'Expose server on network'], - ['--config ', 'Specify the path to the Astro config file.'], - ['--root ', 'Specify the path to the project root folder.'], - ['--drafts', 'Include markdown draft pages in the build.'], - ['--verbose', 'Enable verbose logging'], - ['--silent', 'Disable logging'], - ], + tables: { + Commands: [ + ['add', 'Add an integration.'], + ['build', 'Build your project and write it to disk.'], + ['check', 'Check your project for errors.'], + ['dev', 'Start the development server.'], + ['docs', "Open documentation in your web browser."], + ['preview', 'Preview your build locally.'], + ['telemetry', 'Configure telemetry settings.'], + ], + 'Global Flags': [ + ['--config ', 'Specify your config file.'], + ['--root ', 'Specify your project root folder.'], + ['--verbose', 'Enable verbose logging.'], + ['--silent', 'Disable all logging.'], + ['--version', 'Show the version number and exit.'], + ['--help', 'Show this help message.'], + ], + }, }); } diff --git a/packages/astro/src/cli/telemetry.ts b/packages/astro/src/cli/telemetry.ts index 8247b459da..ded7bc7a15 100644 --- a/packages/astro/src/cli/telemetry.ts +++ b/packages/astro/src/cli/telemetry.ts @@ -15,12 +15,14 @@ export async function update(subcommand: string, { flags, telemetry }: Telemetry if (flags.help || !isValid) { msg.printHelp({ commandName: 'astro telemetry', - usage: '', - commands: [ - ['enable', 'Enable anonymous data collection.'], - ['disable', 'Disable anonymous data collection.'], - ['reset', 'Reset anonymous data collection settings.'], - ], + usage: '[command]', + tables: { + Commands: [ + ['enable', 'Enable anonymous data collection.'], + ['disable', 'Disable anonymous data collection.'], + ['reset', 'Reset anonymous data collection settings.'], + ], + }, }); return; } diff --git a/packages/astro/src/core/add/consts.ts b/packages/astro/src/core/add/consts.ts deleted file mode 100644 index e17d704d59..0000000000 --- a/packages/astro/src/core/add/consts.ts +++ /dev/null @@ -1,27 +0,0 @@ -export const FIRST_PARTY_FRAMEWORKS = [ - { value: 'react', title: 'React' }, - { value: 'preact', title: 'Preact' }, - { value: 'vue', title: 'Vue' }, - { value: 'svelte', title: 'Svelte' }, - { value: 'solid-js', title: 'Solid' }, - { value: 'lit', title: 'Lit' }, -]; -export const FIRST_PARTY_ADDONS = [ - { value: 'tailwind', title: 'Tailwind' }, - { value: 'turbolinks', title: 'Turbolinks' }, - { value: 'partytown', title: 'Partytown' }, - { value: 'sitemap', title: 'Sitemap' }, -]; -export const ALIASES = new Map([ - ['solid', 'solid-js'], - ['tailwindcss', 'tailwind'], -]); -export const CONFIG_STUB = `import { defineConfig } from 'astro/config';\n\nexport default defineConfig({});`; -export const TAILWIND_CONFIG_STUB = `/** @type {import('tailwindcss').Config} */ -module.exports = { - content: ['./src/**/*.{astro,html,js,jsx,md,svelte,ts,tsx,vue}'], - theme: { - extend: {}, - }, - plugins: [], -}\n`; diff --git a/packages/astro/src/core/add/index.ts b/packages/astro/src/core/add/index.ts index f66a2006d0..9fb3f40150 100644 --- a/packages/astro/src/core/add/index.ts +++ b/packages/astro/src/core/add/index.ts @@ -11,14 +11,13 @@ import prompts from 'prompts'; import { fileURLToPath, pathToFileURL } from 'url'; import type yargs from 'yargs-parser'; import { resolveConfigURL } from '../config.js'; -import { debug, error, info, LogOptions } from '../logger/core.js'; +import { debug, info, LogOptions } from '../logger/core.js'; import * as msg from '../messages.js'; import { printHelp } from '../messages.js'; import { appendForwardSlash } from '../path.js'; import { apply as applyPolyfill } from '../polyfill.js'; import { parseNpmName } from '../util.js'; import { generate, parse, t, visit } from './babel.js'; -import * as CONSTS from './consts.js'; import { ensureImport } from './imports.js'; import { wrapDefaultExport } from './wrapper.js'; @@ -34,71 +33,71 @@ export interface IntegrationInfo { packageName: string; dependencies: [name: string, version: string][]; } +const ALIASES = new Map([ + ['solid', 'solid-js'], + ['tailwindcss', 'tailwind'], +]); +const ASTRO_CONFIG_STUB = `import { defineConfig } from 'astro/config';\n\ndefault defineConfig({});`; +const TAILWIND_CONFIG_STUB = `/** @type {import('tailwindcss').Config} */ +module.exports = { + content: ['./src/**/*.{astro,html,js,jsx,md,svelte,ts,tsx,vue}'], + theme: { + extend: {}, + }, + plugins: [], +}\n`; export default async function add(names: string[], { cwd, flags, logging, telemetry }: AddOptions) { - if (flags.help) { + if (flags.help || names.length === 0) { printHelp({ commandName: 'astro add', - usage: '[FLAGS] [INTEGRATIONS...]', - flags: [ - ['--yes', 'Add the integration without user interaction.'], - ['--help', 'Show this help message.'], - ], + usage: '[integration]', + tables: { + Flags: [ + ['--yes', 'Accept all prompts.'], + ['--help', 'Show this help message.'], + ], + 'Recommended: UI Frameworks': [ + ['react', 'astro add react'], + ['preact', 'astro add preact'], + ['vue', 'astro add vue'], + ['svelte', 'astro add svelte'], + ['solid-js', 'astro add solid-js'], + ['lit', 'astro add lit'], + ], + 'Recommended: Integrations': [ + ['tailwind', 'astro add tailwind'], + ['partytown', 'astro add partytown'], + ['sitemap', 'astro add sitemap'], + ], + }, + description: `For more integrations, check out: ${cyan('https://astro.build/integrations')}`, }); return; } let configURL: URL | undefined; const root = pathToFileURL(cwd ? path.resolve(cwd) : process.cwd()); - // TODO: improve error handling for invalid configs configURL = await resolveConfigURL({ cwd, flags }); - - if (configURL?.pathname.endsWith('package.json')) { - throw new Error( - `Unable to use astro add with package.json#astro configuration! Try migrating to \`astro.config.mjs\` and try again.` - ); - } applyPolyfill(); - - // If no integrations were given, prompt the user for some popular ones. - if (names.length === 0) { - const response = await prompts([ - { - type: 'multiselect', - name: 'frameworks', - message: 'What frameworks would you like to enable?', - instructions: '\n Space to select. Return to submit', - choices: CONSTS.FIRST_PARTY_FRAMEWORKS, - }, - { - type: 'multiselect', - name: 'addons', - message: 'What additional integrations would you like to enable?', - instructions: '\n Space to select. Return to submit', - choices: CONSTS.FIRST_PARTY_ADDONS, - }, - ]); - - names = [...(response.frameworks ?? []), ...(response.addons ?? [])]; - } - - // If still empty after prompting, exit gracefully. - if (names.length === 0) { - error(logging, null, `No integrations specified.`); - return; - } - - // Some packages might have a common alias! We normalize those here. - names = names.map((name) => (CONSTS.ALIASES.has(name) ? CONSTS.ALIASES.get(name)! : name)); - + if (configURL) { debug('add', `Found config at ${configURL}`); } else { info(logging, 'add', `Unable to locate a config file, generating one for you.`); configURL = new URL('./astro.config.mjs', appendForwardSlash(root.href)); - await fs.writeFile(fileURLToPath(configURL), CONSTS.CONFIG_STUB, { encoding: 'utf-8' }); + await fs.writeFile(fileURLToPath(configURL), ASTRO_CONFIG_STUB, { encoding: 'utf-8' }); } - const integrations = await validateIntegrations(names); + // TODO: improve error handling for invalid configs + if (configURL?.pathname.endsWith('package.json')) { + throw new Error( + `Unable to use "astro add" with package.json configuration. Try migrating to \`astro.config.mjs\` and try again.` + ); + } + + // Some packages might have a common alias! We normalize those here. + const integrationNames = names.map((name) => (ALIASES.has(name) ? ALIASES.get(name)! : name)); + const integrations = await validateIntegrations(integrationNames); let ast: t.File | null = null; try { @@ -194,7 +193,7 @@ export default async function add(names: string[], { cwd, flags, logging, teleme if (await askToContinue({ flags })) { await fs.writeFile( fileURLToPath(new URL('./tailwind.config.cjs', configURL)), - CONSTS.TAILWIND_CONFIG_STUB, + TAILWIND_CONFIG_STUB, { encoding: 'utf-8' } ); debug('add', `Generated default ./tailwind.config.cjs file`); diff --git a/packages/astro/src/core/logger/node.ts b/packages/astro/src/core/logger/node.ts index b655b26319..ed2c869c00 100644 --- a/packages/astro/src/core/logger/node.ts +++ b/packages/astro/src/core/logger/node.ts @@ -126,6 +126,7 @@ export const logger = { export function enableVerboseLogging() { //debugPackage.enable('*,-babel'); + console.log('ah!'); debug('cli', '--verbose flag enabled! Enabling: DEBUG="*,-babel"'); debug( 'cli', diff --git a/packages/astro/src/core/messages.ts b/packages/astro/src/core/messages.ts index 7da96d6961..561457368c 100644 --- a/packages/astro/src/core/messages.ts +++ b/packages/astro/src/core/messages.ts @@ -248,29 +248,28 @@ export function printHelp({ commandName, headline, usage, - commands, - flags, + tables, + description, }: { commandName: string; headline?: string; usage?: string; - commands?: [command: string, help: string][]; - flags?: [flag: string, help: string][]; + tables?: Record; + description?: string, }) { const linebreak = () => ''; const title = (label: string) => ` ${bgWhite(black(` ${label} `))}`; - const table = (rows: [string, string][], opts: { padding: number; prefix: string }) => { - const split = rows.some((row) => { - const message = `${opts.prefix}${' '.repeat(opts.padding)}${row[1]}`; - return message.length > process.stdout.columns; - }); - + const table = (rows: [string, string][], { padding }: { padding: number }) => { + const split = process.stdout.columns < 60; let raw = ''; for (const row of rows) { - raw += `${opts.prefix}${bold(`${row[0]}`.padStart(opts.padding - opts.prefix.length))}`; - if (split) raw += '\n '; - raw += ' ' + dim(row[1]) + '\n'; + if (split) { + raw += ` ${row[0]}\n `; + } else { + raw += `${(`${row[0]}`.padStart(padding))}`; + } + raw += ' ' + dim(row[1]) + '\n'; } return raw.slice(0, -1); // remove latest \n @@ -291,18 +290,21 @@ export function printHelp({ message.push(linebreak(), ` ${green(commandName)} ${bold(usage)}`); } - if (commands) { - message.push( - linebreak(), - title('Commands'), - table(commands, { padding: 28, prefix: ` ${commandName || 'astro'} ` }) - ); + if (tables) { + function calculateTablePadding(rows: [string, string][]) { + return rows.reduce((val, [first]) => Math.max(val, first.length), 0) + 2; + }; + const tableEntries = Object.entries(tables); + const padding = Math.max(...tableEntries.map(([, rows]) => calculateTablePadding(rows))); + for (const [tableTitle, tableRows] of tableEntries) { + message.push(linebreak(), title(tableTitle), table(tableRows, { padding })); + } } - if (flags) { - message.push(linebreak(), title('Flags'), table(flags, { padding: 28, prefix: ' ' })); + if (description) { + message.push(linebreak(), `${description}`); } // eslint-disable-next-line no-console - console.log(message.join('\n')); + console.log(message.join('\n') + '\n'); }