Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 1 addition & 4 deletions packages/astro/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -115,12 +115,12 @@
"@astrojs/markdown-remark": "workspace:*",
"@astrojs/telemetry": "workspace:*",
"@capsizecss/unpack": "^3.0.1",
"@clack/prompts": "1.0.0-alpha.6",
"@oslojs/encoding": "^1.1.0",
"@rollup/pluginutils": "^5.3.0",
"acorn": "^8.15.0",
"aria-query": "^5.3.2",
"axobject-query": "^4.1.0",
"boxen": "8.0.1",
"ci-info": "^4.3.1",
"clsx": "^2.1.1",
"common-ancestor-path": "^1.0.1",
Expand Down Expand Up @@ -151,7 +151,6 @@
"package-manager-detector": "^1.5.0",
"piccolore": "^0.1.3",
"picomatch": "^4.0.3",
"prompts": "^2.4.2",
"rehype": "^13.0.2",
"semver": "^7.7.3",
"shiki": "^3.15.0",
Expand All @@ -168,7 +167,6 @@
"vitefu": "^1.1.1",
"xxhash-wasm": "^1.1.0",
"yargs-parser": "^21.1.1",
"yocto-spinner": "^0.2.3",
"zod": "^3.25.76",
"zod-to-json-schema": "^3.24.6",
"zod-to-ts": "^1.2.0"
Expand All @@ -190,7 +188,6 @@
"@types/http-cache-semantics": "^4.0.4",
"@types/js-yaml": "^4.0.9",
"@types/picomatch": "^3.0.2",
"@types/prompts": "^2.4.9",
"@types/semver": "^7.7.1",
"@types/yargs-parser": "^21.0.3",
"astro-scripts": "workspace:*",
Expand Down
85 changes: 38 additions & 47 deletions packages/astro/src/cli/add/index.ts
Original file line number Diff line number Diff line change
@@ -1,16 +1,14 @@
import fsMod, { existsSync, promises as fs } from 'node:fs';
import path from 'node:path';
import { fileURLToPath, pathToFileURL } from 'node:url';
import boxen from 'boxen';
import * as clack from '@clack/prompts';
import { diffWords } from 'diff';
import { type ASTNode, builders, generateCode, loadFile, type ProxifiedModule } from 'magicast';
import { getDefaultExportOptions } from 'magicast/helpers';
import { detect, resolveCommand } from 'package-manager-detector';
import colors from 'piccolore';
import prompts from 'prompts';
import maxSatisfying from 'semver/ranges/max-satisfying.js';
import type yargsParser from 'yargs-parser';
import yoctoSpinner from 'yocto-spinner';
import {
loadTSConfig,
resolveConfig,
Expand Down Expand Up @@ -445,19 +443,19 @@ export async function add(names: string[], { flags }: AddOptions) {
),
);
if (integrations.find((integration) => integration.integrationName === 'tailwind')) {
const code = boxen(getDiffContent('---\n---', "---\nimport '../styles/global.css'\n---")!, {
margin: 0.5,
padding: 0.5,
borderStyle: 'round',
title: 'src/layouts/Layout.astro',
});
logger.warn(
'SKIP_FORMAT',
msg.actionRequired(
'You must import your Tailwind stylesheet, e.g. in a shared layout:\n',
),
);
logger.info('SKIP_FORMAT', code + '\n');
clack.box(
getDiffContent('---\n---', "---\nimport '../styles/global.css'\n---")!,
'src/layouts/Layout.astro',
{
rounded: true,
},
);
}
}
}
Expand Down Expand Up @@ -643,18 +641,15 @@ async function updateAstroConfig({
return UpdateResult.none;
}

const message = `\n${boxen(diff, {
margin: 0.5,
padding: 0.5,
borderStyle: 'round',
title: configURL.pathname.split('/').pop(),
})}\n`;

logger.info(
'SKIP_FORMAT',
`\n ${magenta('Astro will make the following changes to your config file:')}\n${message}`,
`\n ${magenta('Astro will make the following changes to your config file:')}`,
);

clack.box(diff, configURL.pathname.split('/').pop(), {
rounded: true,
});

if (logAdapterInstructions) {
logger.info(
'SKIP_FORMAT',
Expand Down Expand Up @@ -758,20 +753,19 @@ async function tryToInstallIntegrations({
);

const coloredOutput = `${bold(installCommand.command)} ${installCommand.args.join(' ')} ${cyan(installSpecifiers.join(' '))}`;
const message = `\n${boxen(coloredOutput, {
margin: 0.5,
padding: 0.5,
borderStyle: 'round',
})}\n`;
logger.info(
'SKIP_FORMAT',
`\n ${magenta('Astro will run the following command:')}\n ${dim(
'If you skip this step, you can always run it yourself later',
)}\n${message}`,
)}`,
);
clack.box(coloredOutput, undefined, {
rounded: true,
});

if (await askToContinue({ flags, logger })) {
const spinner = yoctoSpinner({ text: 'Installing dependencies...' }).start();
const spinner = clack.spinner();
spinner.start('Installing dependencies...');
try {
await exec(installCommand.command, [...installCommand.args, ...installSpecifiers], {
nodeOptions: {
Expand All @@ -780,10 +774,10 @@ async function tryToInstallIntegrations({
env: { NODE_ENV: undefined },
},
});
spinner.success();
spinner.stop('Dependencies installed.');
return UpdateResult.updated;
} catch (err: any) {
spinner.error();
spinner.error('Error installing dependencies.');
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

spinner.error makes the build fail currently

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I guess because bombshell-dev/clack#406 is unreleased

logger.debug('add', 'Error installing dependencies', err);
// NOTE: `err.stdout` can be an empty string, so log the full error instead for a more helpful log
console.error('\n', err.stdout || err.message, '\n');
Expand All @@ -799,7 +793,8 @@ async function validateIntegrations(
flags: yargsParser.Arguments,
logger: Logger,
): Promise<IntegrationInfo[]> {
const spinner = yoctoSpinner({ text: 'Resolving packages...' }).start();
const spinner = clack.spinner();
spinner.start('Resolving packages...');
try {
const integrationEntries = await Promise.all(
integrations.map(async (integration): Promise<IntegrationInfo> => {
Expand All @@ -817,17 +812,17 @@ async function validateIntegrations(
const firstPartyPkgCheck = await fetchPackageJson('@astrojs', name, tag);
if (firstPartyPkgCheck instanceof Error) {
if (firstPartyPkgCheck.message) {
spinner.warning(yellow(firstPartyPkgCheck.message));
spinner.message(yellow(firstPartyPkgCheck.message));
}
spinner.warning(yellow(`${bold(integration)} is not an official Astro package.`));
spinner.message(yellow(`${bold(integration)} is not an official Astro package.`));
if (!(await askToContinue({ flags, logger }))) {
throw new Error(
`No problem! Find our official integrations at ${cyan(
'https://astro.build/integrations',
)}`,
);
}
spinner.start('Resolving with third party packages...');
spinner.message('Resolving with third party packages...');
pkgType = 'third-party';
} else {
pkgType = 'first-party';
Expand All @@ -838,7 +833,7 @@ async function validateIntegrations(
const thirdPartyPkgCheck = await fetchPackageJson(scope, name, tag);
if (thirdPartyPkgCheck instanceof Error) {
if (thirdPartyPkgCheck.message) {
spinner.warning(yellow(thirdPartyPkgCheck.message));
spinner.message(yellow(thirdPartyPkgCheck.message));
}
throw new Error(`Unable to fetch ${bold(integration)}. Does the package exist?`);
} else {
Expand Down Expand Up @@ -896,7 +891,7 @@ async function validateIntegrations(
};
}),
);
spinner.success();
spinner.stop('Resolved packages.');
return integrationEntries;
} catch (e) {
if (e instanceof Error) {
Expand Down Expand Up @@ -955,18 +950,15 @@ async function updateTSConfig(
return UpdateResult.none;
}

const message = `\n${boxen(diff, {
margin: 0.5,
padding: 0.5,
borderStyle: 'round',
title: configFileName,
})}\n`;

logger.info(
'SKIP_FORMAT',
`\n ${magenta(`Astro will make the following changes to your ${configFileName}:`)}\n${message}`,
`\n ${magenta(`Astro will make the following changes to your ${configFileName}:`)}`,
);

clack.box(diff, configFileName, {
rounded: true,
});

// Every major framework, apart from Vue and Svelte requires different `jsxImportSource`, as such it's impossible to config
// all of them in the same `tsconfig.json`. However, Vue only need `"jsx": "preserve"` for template intellisense which
// can be compatible with some frameworks (ex: Solid)
Expand Down Expand Up @@ -1017,6 +1009,7 @@ function parseIntegrationName(spec: string) {

let hasHintedAboutYesFlag = false;


async function askToContinue({
flags,
logger,
Expand All @@ -1029,14 +1022,12 @@ async function askToContinue({
hasHintedAboutYesFlag = true;
logger.info('SKIP_FORMAT', dim(' To run this command without prompts, pass the --yes flag\n'));
}
const response = await prompts({
type: 'confirm',
name: 'askToContinue',
message: 'Continue?',
initial: true,
const response = await clack.confirm({
message: colors.bold('Continue?'),
initialValue: true,
});

return Boolean(response.askToContinue);
return response === true;
}

function getDiffContent(input: string, output: string): string | null {
Expand Down
6 changes: 3 additions & 3 deletions packages/astro/src/cli/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -105,7 +105,7 @@ async function runCommand(cmd: string, flags: yargs.Arguments) {
{ createTinyexecCommandExecutor },
{ getPackageManager },
{ createStyledDebugInfoFormatter },
{ createPromptsPrompt },
{ createClackPrompt },
{ createCliClipboard },
{ createPassthroughTextStyler },
{ infoCommand },
Expand All @@ -118,7 +118,7 @@ async function runCommand(cmd: string, flags: yargs.Arguments) {
import('./infra/tinyexec-command-executor.js'),
import('./info/core/get-package-manager.js'),
import('./info/infra/styled-debug-info-formatter.js'),
import('./info/infra/prompts-prompt.js'),
import('./info/infra/clack-prompt.js'),
import('./info/infra/cli-clipboard.js'),
import('./infra/passthrough-text-styler.js'),
import('./info/core/info.js'),
Expand All @@ -138,7 +138,7 @@ async function runCommand(cmd: string, flags: yargs.Arguments) {
}),
nodeVersionProvider,
});
const prompt = createPromptsPrompt({ force: flags.copy });
const prompt = createClackPrompt({ force: flags.copy });
const clipboard = createCliClipboard({
commandExecutor,
logger,
Expand Down
22 changes: 22 additions & 0 deletions packages/astro/src/cli/info/infra/clack-prompt.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
import { confirm } from '@clack/prompts';
import type { Prompt } from '../definitions.js';

interface Options {
force: boolean;
}

export function createClackPrompt({ force }: Options): Prompt {
return {
async confirm({ message, defaultValue }) {
if (force) {
return true;
}
const response = await confirm({
message,
initialValue: defaultValue,
});
// Response is a symbol when cancelled
return response === true;
},
};
}
23 changes: 0 additions & 23 deletions packages/astro/src/cli/info/infra/prompts-prompt.ts

This file was deleted.

34 changes: 14 additions & 20 deletions packages/astro/src/cli/install-package.ts
Original file line number Diff line number Diff line change
@@ -1,10 +1,8 @@
import { createRequire } from 'node:module';
import boxen from 'boxen';
import * as clack from '@clack/prompts';
import ci from 'ci-info';
import { detect, resolveCommand } from 'package-manager-detector';
import colors from 'piccolore';
import prompts from 'prompts';
import yoctoSpinner from 'yocto-spinner';
import type { Logger } from '../core/logger/core.js';
import { exec } from './exec.js';

Expand Down Expand Up @@ -76,34 +74,30 @@ async function installPackage(
packageNames = packageNames.map((name) => `npm:${name}`);
}
const coloredOutput = `${bold(installCommand.command)} ${installCommand.args.join(' ')} ${cyan(packageNames.join(' '))}`;
const message = `\n${boxen(coloredOutput, {
margin: 0.5,
padding: 0.5,
borderStyle: 'round',
})}\n`;
logger.info(
'SKIP_FORMAT',
`\n ${magenta('Astro will run the following command:')}\n ${dim(
'If you skip this step, you can always run it yourself later',
)}\n${message}`,
)}`,
);
clack.box(coloredOutput, undefined, {
rounded: true,
});

let response;
if (options.skipAsk) {
response = true;
} else {
response = (
await prompts({
type: 'confirm',
name: 'askToContinue',
message: 'Continue?',
initial: true,
})
).askToContinue;
response =
(await clack.confirm({
message: colors.bold('Continue?'),
initialValue: true,
})) === true;
}

if (Boolean(response)) {
const spinner = yoctoSpinner({ text: 'Installing dependencies...' }).start();
const spinner = clack.spinner();
spinner.start('Installing dependencies...');
try {
await exec(installCommand.command, [...installCommand.args, ...packageNames], {
nodeOptions: {
Expand All @@ -112,12 +106,12 @@ async function installPackage(
env: { NODE_ENV: undefined },
},
});
spinner.success();
spinner.stop('Dependencies installed.');

return true;
} catch (err) {
logger.debug('add', 'Error installing dependencies', err);
spinner.error();
spinner.error('Failed to install dependencies.');

return false;
}
Expand Down
Loading
Loading