diff --git a/packages/astro/src/cli/add/index.ts b/packages/astro/src/cli/add/index.ts index 4ed39d457..33756f378 100644 --- a/packages/astro/src/cli/add/index.ts +++ b/packages/astro/src/cli/add/index.ts @@ -22,6 +22,7 @@ import { printHelp } from '../../core/messages.js'; import { appendForwardSlash } from '../../core/path.js'; import { apply as applyPolyfill } from '../../core/polyfill.js'; import { parseNpmName } from '../../core/util.js'; +import { eventCliSession, telemetry } from '../../events/index.js'; import { generate, parse, t, visit } from './babel.js'; import { ensureImport } from './imports.js'; import { wrapDefaultExport } from './wrapper.js'; @@ -29,7 +30,6 @@ import { wrapDefaultExport } from './wrapper.js'; interface AddOptions { logging: LogOptions; flags: yargs.Arguments; - cwd?: string; } interface IntegrationInfo { @@ -86,7 +86,8 @@ async function getRegistry(): Promise { } } -export async function add(names: string[], { cwd, flags, logging }: AddOptions) { +export async function add(names: string[], { flags, logging }: AddOptions) { + telemetry.record(eventCliSession('add')); applyPolyfill(); if (flags.help || names.length === 0) { printHelp({ @@ -128,6 +129,7 @@ export async function add(names: string[], { cwd, flags, logging }: AddOptions) } // Some packages might have a common alias! We normalize those here. + const cwd = flags.root; const integrationNames = names.map((name) => (ALIASES.has(name) ? ALIASES.get(name)! : name)); const integrations = await validateIntegrations(integrationNames); let installResult = await tryToInstallIntegrations({ integrations, cwd, flags, logging }); diff --git a/packages/astro/src/cli/index.ts b/packages/astro/src/cli/index.ts index 6f5723686..7c26b2d01 100644 --- a/packages/astro/src/cli/index.ts +++ b/packages/astro/src/cli/index.ts @@ -2,15 +2,8 @@ import * as colors from 'kleur/colors'; import yargs from 'yargs-parser'; import { ASTRO_VERSION } from '../core/constants.js'; -import { collectErrorMetadata } from '../core/errors/dev/index.js'; -import { createSafeError } from '../core/errors/index.js'; -import { debug, type LogOptions } from '../core/logger/core.js'; -import { enableVerboseLogging, nodeLogDestination } from '../core/logger/node.js'; -import { formatErrorMessage, printHelp } from '../core/messages.js'; -import * as event from '../events/index.js'; -import { eventError, telemetry } from '../events/index.js'; +import type { LogOptions } from '../core/logger/core.js'; -type Arguments = yargs.Arguments; type CLICommand = | 'help' | 'version' @@ -25,7 +18,8 @@ type CLICommand = | 'telemetry'; /** Display --help flag */ -function printAstroHelp() { +async function printAstroHelp() { + const { printHelp } = await import('../core/messages.js'); printHelp({ commandName: 'astro', usage: '[command] [...flags]', @@ -63,7 +57,7 @@ function printVersion() { } /** Determine which command the user requested */ -function resolveCommand(flags: Arguments): CLICommand { +function resolveCommand(flags: yargs.Arguments): CLICommand { const cmd = flags._[2] as string; if (flags.version) return 'version'; @@ -90,23 +84,20 @@ function resolveCommand(flags: Arguments): CLICommand { * to present user-friendly error output where the fn is called. **/ async function runCommand(cmd: string, flags: yargs.Arguments) { - const root = flags.root; - // These commands can run directly without parsing the user config. switch (cmd) { case 'help': - printAstroHelp(); + await printAstroHelp(); return; case 'version': printVersion(); return; case 'info': { const { printInfo } = await import('./info/index.js'); - await printInfo({ cwd: root, flags }); + await printInfo({ flags }); return; } case 'docs': { - telemetry.record(event.eventCliSession(cmd)); const { docs } = await import('./docs/index.js'); await docs({ flags }); return; @@ -121,6 +112,7 @@ async function runCommand(cmd: string, flags: yargs.Arguments) { } } + const { enableVerboseLogging, nodeLogDestination } = await import('../core/logger/node.js'); const logging: LogOptions = { dest: nodeLogDestination, level: 'info', @@ -141,10 +133,9 @@ async function runCommand(cmd: string, flags: yargs.Arguments) { // by the end of this switch statement. switch (cmd) { case 'add': { - telemetry.record(event.eventCliSession(cmd)); const { add } = await import('./add/index.js'); const packages = flags._.slice(3) as string[]; - await add(packages, { cwd: root, flags, logging }); + await add(packages, { flags, logging }); return; } case 'dev': { @@ -177,7 +168,7 @@ async function runCommand(cmd: string, flags: yargs.Arguments) { await checkServer.watch(); return await new Promise(() => {}); // lives forever } else { - let checkResult = await checkServer.check(); + const checkResult = await checkServer.check(); return process.exit(checkResult); } } @@ -201,29 +192,7 @@ export async function cli(args: string[]) { try { await runCommand(cmd, flags); } catch (err) { + const { throwAndExit } = await import('./throw-and-exit.js'); await throwAndExit(cmd, err); } } - -/** Display error and exit */ -async function throwAndExit(cmd: string, err: unknown) { - let telemetryPromise: Promise; - let errorMessage: string; - function exitWithErrorMessage() { - console.error(errorMessage); - process.exit(1); - } - - const errorWithMetadata = collectErrorMetadata(createSafeError(err)); - telemetryPromise = telemetry.record(eventError({ cmd, err: errorWithMetadata, isFatal: true })); - errorMessage = formatErrorMessage(errorWithMetadata); - - // Timeout the error reporter (very short) because the user is waiting. - // NOTE(fks): It is better that we miss some events vs. holding too long. - // TODO(fks): Investigate using an AbortController once we drop Node v14. - setTimeout(exitWithErrorMessage, 400); - // Wait for the telemetry event to send, then exit. Ignore any error. - await telemetryPromise - .catch((err2) => debug('telemetry', `record() error: ${err2.message}`)) - .then(exitWithErrorMessage); -} diff --git a/packages/astro/src/cli/info/index.ts b/packages/astro/src/cli/info/index.ts index a32553f72..3d27d7f3f 100644 --- a/packages/astro/src/cli/info/index.ts +++ b/packages/astro/src/cli/info/index.ts @@ -7,11 +7,10 @@ import { openConfig } from '../../core/config/index.js'; import { ASTRO_VERSION } from '../../core/constants.js'; interface InfoOptions { - cwd?: string; flags: yargs.Arguments; } -export async function printInfo({ cwd, flags }: InfoOptions) { +export async function printInfo({ flags }: InfoOptions) { const packageManager = await whichPm(process.cwd()); let adapter = "Couldn't determine."; let integrations = []; @@ -24,7 +23,7 @@ export async function printInfo({ cwd, flags }: InfoOptions) { try { const { userConfig } = await openConfig({ - cwd, + cwd: flags.root, flags, cmd: 'info', }); diff --git a/packages/astro/src/cli/throw-and-exit.ts b/packages/astro/src/cli/throw-and-exit.ts new file mode 100644 index 000000000..cea76ee98 --- /dev/null +++ b/packages/astro/src/cli/throw-and-exit.ts @@ -0,0 +1,29 @@ +/* eslint-disable no-console */ +import { collectErrorMetadata } from '../core/errors/dev/index.js'; +import { createSafeError } from '../core/errors/index.js'; +import { debug } from '../core/logger/core.js'; +import { formatErrorMessage } from '../core/messages.js'; +import { eventError, telemetry } from '../events/index.js'; + +/** Display error and exit */ +export async function throwAndExit(cmd: string, err: unknown) { + let telemetryPromise: Promise; + let errorMessage: string; + function exitWithErrorMessage() { + console.error(errorMessage); + process.exit(1); + } + + const errorWithMetadata = collectErrorMetadata(createSafeError(err)); + telemetryPromise = telemetry.record(eventError({ cmd, err: errorWithMetadata, isFatal: true })); + errorMessage = formatErrorMessage(errorWithMetadata); + + // Timeout the error reporter (very short) because the user is waiting. + // NOTE(fks): It is better that we miss some events vs. holding too long. + // TODO(fks): Investigate using an AbortController once we drop Node v14. + setTimeout(exitWithErrorMessage, 400); + // Wait for the telemetry event to send, then exit. Ignore any error. + await telemetryPromise + .catch((err2) => debug('telemetry', `record() error: ${err2.message}`)) + .then(exitWithErrorMessage); +}