SImplify "astro add" by removing confusing multi-select (#3715)
* wip * update create-astro for new astro add * update copy * update git prompt * Update packages/astro/src/core/logger/node.ts Co-authored-by: Chris Swithinbank <swithinbank@gmail.com> * Update packages/create-astro/test/install-step.test.js Co-authored-by: Chris Swithinbank <swithinbank@gmail.com> * update git prompt * update test Co-authored-by: Chris Swithinbank <swithinbank@gmail.com>
This commit is contained in:
parent
bd4dac0e1a
commit
4d6d8644e6
13 changed files with 157 additions and 258 deletions
5
.changeset/lucky-apes-yell.md
Normal file
5
.changeset/lucky-apes-yell.md
Normal file
|
@ -0,0 +1,5 @@
|
|||
---
|
||||
'astro': patch
|
||||
---
|
||||
|
||||
Update "astro add" output to remove confusing multi-select prompt.
|
5
.changeset/perfect-drinks-fold.md
Normal file
5
.changeset/perfect-drinks-fold.md
Normal file
|
@ -0,0 +1,5 @@
|
|||
---
|
||||
'astro': patch
|
||||
---
|
||||
|
||||
Update the help output to improve formatting
|
|
@ -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 <path>', 'Specify the path to the Astro config file.'],
|
||||
['--root <path>', '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 <path>', 'Specify your config file.'],
|
||||
['--root <path>', '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.'],
|
||||
],
|
||||
},
|
||||
});
|
||||
}
|
||||
|
||||
|
|
|
@ -15,12 +15,14 @@ export async function update(subcommand: string, { flags, telemetry }: Telemetry
|
|||
if (flags.help || !isValid) {
|
||||
msg.printHelp({
|
||||
commandName: 'astro telemetry',
|
||||
usage: '<enable|disable|reset>',
|
||||
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;
|
||||
}
|
||||
|
|
|
@ -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`;
|
|
@ -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: '[...integrations]',
|
||||
tables: {
|
||||
Flags: [
|
||||
['--yes', 'Accept all prompts.'],
|
||||
['--help', 'Show this help message.'],
|
||||
],
|
||||
'Example: Add a UI Framework': [
|
||||
['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'],
|
||||
],
|
||||
'Example: Add an Integration': [
|
||||
['tailwind', 'astro add tailwind'],
|
||||
['partytown', 'astro add partytown'],
|
||||
['sitemap', 'astro add sitemap'],
|
||||
],
|
||||
},
|
||||
description: `Check out the full integration catalog: ${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`);
|
||||
|
|
|
@ -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<string, [command: string, help: string][]>;
|
||||
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');
|
||||
}
|
||||
|
|
|
@ -3,7 +3,7 @@
|
|||
|
||||
const currentVersion = process.versions.node;
|
||||
const requiredMajorVersion = parseInt(currentVersion.split('.')[0], 10);
|
||||
const minimumMajorVersion = 12;
|
||||
const minimumMajorVersion = 14;
|
||||
|
||||
if (requiredMajorVersion < minimumMajorVersion) {
|
||||
console.error(`Node.js v${currentVersion} is out of date and unsupported!`);
|
||||
|
|
|
@ -2,7 +2,7 @@
|
|||
import degit from 'degit';
|
||||
import { execa, execaCommand } from 'execa';
|
||||
import fs from 'fs';
|
||||
import { bgCyan, black, bold, cyan, gray, green, red, yellow } from 'kleur/colors';
|
||||
import { bgCyan, black, bold, cyan, dim, gray, green, red, yellow } from 'kleur/colors';
|
||||
import ora from 'ora';
|
||||
import path from 'path';
|
||||
import prompts from 'prompts';
|
||||
|
@ -11,6 +11,13 @@ import { loadWithRocketGradient, rocketAscii } from './gradient.js';
|
|||
import { defaultLogLevel, logger } from './logger.js';
|
||||
import { TEMPLATES } from './templates.js';
|
||||
|
||||
function wait(ms: number) {
|
||||
return new Promise((resolve) => setTimeout(resolve, ms));
|
||||
}
|
||||
function logAndWait(message: string, ms: number = 100) {
|
||||
console.log(message);
|
||||
return wait(ms);
|
||||
}
|
||||
// NOTE: In the v7.x version of npm, the default behavior of `npm init` was changed
|
||||
// to no longer require `--` to pass args and instead pass `--` directly to us. This
|
||||
// broke our arg parser, since `--` is a special kind of flag. Filtering for `--` here
|
||||
|
@ -43,6 +50,7 @@ export async function main() {
|
|||
|
||||
logger.debug('Verbose logging turned on');
|
||||
console.log(`\n${bold('Welcome to Astro!')} ${gray(`(create-astro v${version})`)}`);
|
||||
console.log(`Lets walk through setting up your new Astro project.\n`);
|
||||
|
||||
let cwd = args['_'][2] as string;
|
||||
|
||||
|
@ -64,7 +72,7 @@ export async function main() {
|
|||
const dirResponse = await prompts({
|
||||
type: 'text',
|
||||
name: 'directory',
|
||||
message: 'Where would you like to create your app?',
|
||||
message: 'Where would you like to create your new project?',
|
||||
initial: './my-astro-site',
|
||||
validate(value) {
|
||||
if (!isEmpty(value)) {
|
||||
|
@ -84,7 +92,7 @@ export async function main() {
|
|||
{
|
||||
type: 'select',
|
||||
name: 'template',
|
||||
message: 'Which app template would you like to use?',
|
||||
message: 'Which template would you like to use?',
|
||||
choices: TEMPLATES,
|
||||
},
|
||||
]);
|
||||
|
@ -112,7 +120,7 @@ export async function main() {
|
|||
});
|
||||
|
||||
// Copy
|
||||
if (!args.dryrun) {
|
||||
if (!args.dryRun) {
|
||||
try {
|
||||
emitter.on('info', (info) => {
|
||||
logger.debug(info.message);
|
||||
|
@ -175,11 +183,9 @@ export async function main() {
|
|||
initial: true,
|
||||
});
|
||||
|
||||
if (!installResponse) {
|
||||
process.exit(0);
|
||||
}
|
||||
|
||||
if (installResponse.install && !args.dryrun) {
|
||||
if (args.dryRun) {
|
||||
ora().info(dim(`--dry-run enabled, skipping.`));
|
||||
} else if (installResponse.install) {
|
||||
const installExec = execa(pkgManager, ['install'], { cwd });
|
||||
const installingPackagesMsg = `Installing packages${emojiWithFallback(' 📦', '...')}`;
|
||||
const installSpinner = await loadWithRocketGradient(installingPackagesMsg);
|
||||
|
@ -194,69 +200,51 @@ export async function main() {
|
|||
});
|
||||
installSpinner.text = green('Packages installed!');
|
||||
installSpinner.succeed();
|
||||
}
|
||||
|
||||
const astroAddCommand = installResponse.install
|
||||
? 'astro add --yes'
|
||||
: `${pkgManagerExecCommand(pkgManager)} astro@latest add --yes`;
|
||||
|
||||
const astroAddResponse = await prompts({
|
||||
type: 'confirm',
|
||||
name: 'astroAdd',
|
||||
message: `Run "${astroAddCommand}?" This lets you optionally add component frameworks (ex. React), CSS frameworks (ex. Tailwind), and more.`,
|
||||
initial: true,
|
||||
});
|
||||
|
||||
if (!astroAddResponse) {
|
||||
process.exit(0);
|
||||
}
|
||||
|
||||
if (!astroAddResponse.astroAdd) {
|
||||
ora().info(
|
||||
`No problem. You can always run "${pkgManagerExecCommand(pkgManager)} astro add" later!`
|
||||
);
|
||||
}
|
||||
|
||||
if (astroAddResponse.astroAdd && !args.dryrun) {
|
||||
await execaCommand(
|
||||
astroAddCommand,
|
||||
astroAddCommand === 'astro add --yes'
|
||||
? { cwd, stdio: 'inherit', localDir: cwd, preferLocal: true }
|
||||
: { cwd, stdio: 'inherit' }
|
||||
);
|
||||
} else {
|
||||
ora().info(dim(`No problem! You can install dependencies yourself after setup.`));
|
||||
}
|
||||
|
||||
const gitResponse = await prompts({
|
||||
type: 'confirm',
|
||||
name: 'git',
|
||||
message: 'Initialize a git repository?',
|
||||
message: `Initialize a new git repository? ${dim('This can be useful to track changes.')}`,
|
||||
initial: true,
|
||||
});
|
||||
|
||||
if (!gitResponse) {
|
||||
process.exit(0);
|
||||
}
|
||||
|
||||
if (gitResponse.git && !args.dryrun) {
|
||||
if (args.dryRun) {
|
||||
ora().info(dim(`--dry-run enabled, skipping.`));
|
||||
} else if (gitResponse.git) {
|
||||
await execaCommand('git init', { cwd });
|
||||
} else {
|
||||
ora().info(
|
||||
dim(`Sounds good! You can come back and run ${cyan(`git init`)} later.`)
|
||||
);
|
||||
}
|
||||
|
||||
ora({ text: green('Done. Ready for liftoff!') }).succeed();
|
||||
ora().succeed('Setup complete.');
|
||||
ora({ text: green('Ready for liftoff!') }).succeed();
|
||||
await wait(300);
|
||||
|
||||
console.log(`\n${bgCyan(black(' Next steps '))}\n`);
|
||||
|
||||
const projectDir = path.relative(process.cwd(), cwd);
|
||||
let projectDir = path.relative(process.cwd(), cwd);
|
||||
const devCmd = pkgManager === 'npm' ? 'npm run dev' : `${pkgManager} dev`;
|
||||
|
||||
console.log(
|
||||
await logAndWait(
|
||||
`You can now ${bold(cyan('cd'))} into the ${bold(cyan(projectDir))} project directory.`
|
||||
);
|
||||
console.log(
|
||||
await logAndWait(
|
||||
`Run ${bold(cyan(devCmd))} to start the Astro dev server. ${bold(cyan('CTRL-C'))} to close.`
|
||||
);
|
||||
if (!installResponse.install) {
|
||||
console.log(yellow(`Remember to install dependencies first!`));
|
||||
}
|
||||
console.log(`\nStuck? Come join us at ${bold(cyan('https://astro.build/chat'))}`);
|
||||
await logAndWait(
|
||||
`Add frameworks like ${bold(cyan('react'))} and ${bold(
|
||||
cyan('tailwind')
|
||||
)} to your project using ${bold(cyan('astro add'))}`
|
||||
);
|
||||
await logAndWait('');
|
||||
await logAndWait(`Stuck? Come join us at ${bold(cyan('https://astro.build/chat'))}`, 1000);
|
||||
await logAndWait(dim('Good luck out there, astronaut.'));
|
||||
await logAndWait('', 300);
|
||||
}
|
||||
|
||||
function emojiWithFallback(char: string, fallback: string) {
|
||||
|
|
|
@ -1,69 +0,0 @@
|
|||
import { setup, promiseWithTimeout, timeout, PROMPT_MESSAGES } from './utils.js';
|
||||
import { sep } from 'path';
|
||||
import fs from 'fs';
|
||||
import os from 'os';
|
||||
|
||||
// reset package manager in process.env
|
||||
// prevents test issues when running with pnpm
|
||||
const FAKE_PACKAGE_MANAGER = 'npm';
|
||||
let initialEnvValue = null;
|
||||
|
||||
describe('[create-astro] astro add', function () {
|
||||
this.timeout(timeout);
|
||||
let tempDir = '';
|
||||
beforeEach(async () => {
|
||||
tempDir = await fs.promises.mkdtemp(`${os.tmpdir()}${sep}`);
|
||||
});
|
||||
this.beforeAll(() => {
|
||||
initialEnvValue = process.env.npm_config_user_agent;
|
||||
process.env.npm_config_user_agent = FAKE_PACKAGE_MANAGER;
|
||||
});
|
||||
this.afterAll(() => {
|
||||
process.env.npm_config_user_agent = initialEnvValue;
|
||||
});
|
||||
|
||||
it('should use "astro add" when user has installed dependencies', function () {
|
||||
const { stdout, stdin } = setup([tempDir]);
|
||||
return promiseWithTimeout((resolve) => {
|
||||
const seen = new Set();
|
||||
const installPrompt = PROMPT_MESSAGES.install('npm');
|
||||
stdout.on('data', (chunk) => {
|
||||
if (!seen.has(PROMPT_MESSAGES.template) && chunk.includes(PROMPT_MESSAGES.template)) {
|
||||
seen.add(PROMPT_MESSAGES.template);
|
||||
// respond with "enter key"
|
||||
stdin.write('\x0D');
|
||||
}
|
||||
if (!seen.has(installPrompt) && chunk.includes(installPrompt)) {
|
||||
seen.add(installPrompt);
|
||||
stdin.write('\x0D');
|
||||
}
|
||||
if (chunk.includes(PROMPT_MESSAGES.astroAdd('astro add --yes'))) {
|
||||
resolve();
|
||||
}
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
it('should use "npx astro@latest add" when use has NOT installed dependencies', function () {
|
||||
const { stdout, stdin } = setup([tempDir]);
|
||||
return promiseWithTimeout((resolve) => {
|
||||
const seen = new Set();
|
||||
const installPrompt = PROMPT_MESSAGES.install('npm');
|
||||
stdout.on('data', (chunk) => {
|
||||
if (!seen.has(PROMPT_MESSAGES.template) && chunk.includes(PROMPT_MESSAGES.template)) {
|
||||
seen.add(PROMPT_MESSAGES.template);
|
||||
// respond with "enter key"
|
||||
stdin.write('\x0D');
|
||||
}
|
||||
if (!seen.has(installPrompt) && chunk.includes(installPrompt)) {
|
||||
seen.add(installPrompt);
|
||||
// respond with "no, then enter key"
|
||||
stdin.write('n\x0D');
|
||||
}
|
||||
if (chunk.includes(PROMPT_MESSAGES.astroAdd('npx astro@latest add --yes'))) {
|
||||
resolve();
|
||||
}
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
|
@ -44,7 +44,6 @@ describe('[create-astro] install', function () {
|
|||
return promiseWithTimeout((resolve) => {
|
||||
const seen = new Set();
|
||||
const installPrompt = PROMPT_MESSAGES.install(FAKE_PACKAGE_MANAGER);
|
||||
const astroAddPrompt = PROMPT_MESSAGES.astroAdd();
|
||||
stdout.on('data', (chunk) => {
|
||||
if (!seen.has(PROMPT_MESSAGES.template) && chunk.includes(PROMPT_MESSAGES.template)) {
|
||||
seen.add(PROMPT_MESSAGES.template);
|
||||
|
@ -56,10 +55,6 @@ describe('[create-astro] install', function () {
|
|||
// respond with "no, then enter key"
|
||||
stdin.write('n\x0D');
|
||||
}
|
||||
if (!seen.has(astroAddPrompt) && chunk.includes(astroAddPrompt)) {
|
||||
seen.add(astroAddPrompt);
|
||||
stdin.write('n\x0D');
|
||||
}
|
||||
if (!seen.has(PROMPT_MESSAGES.git) && chunk.includes(PROMPT_MESSAGES.git)) {
|
||||
seen.add(PROMPT_MESSAGES.git);
|
||||
stdin.write('\x0D');
|
||||
|
|
|
@ -24,12 +24,10 @@ export function promiseWithTimeout(testFn) {
|
|||
}
|
||||
|
||||
export const PROMPT_MESSAGES = {
|
||||
directory: 'Where would you like to create your app?',
|
||||
template: 'Which app template would you like to use?',
|
||||
directory: 'Where would you like to create your new project?',
|
||||
template: 'Which template would you like to use?',
|
||||
install: (pkgManager) => `Would you like us to run "${pkgManager} install?"`,
|
||||
astroAdd: (astroAddCommand = 'npx astro@latest add --yes') =>
|
||||
`Run "${astroAddCommand}?" This lets you optionally add component frameworks (ex. React), CSS frameworks (ex. Tailwind), and more.`,
|
||||
git: 'Initialize a git repository?',
|
||||
git: 'Initialize a new git repository?',
|
||||
};
|
||||
|
||||
export function setup(args = []) {
|
||||
|
|
2
packages/webapi/mod.d.ts
vendored
2
packages/webapi/mod.d.ts
vendored
|
@ -1,5 +1,5 @@
|
|||
export { pathToPosix } from './lib/utils';
|
||||
export { AbortController, AbortSignal, alert, atob, Blob, btoa, ByteLengthQueuingStrategy, cancelAnimationFrame, cancelIdleCallback, CanvasRenderingContext2D, CharacterData, clearTimeout, Comment, CountQueuingStrategy, CSSStyleSheet, CustomElementRegistry, CustomEvent, Document, DocumentFragment, DOMException, Element, Event, EventTarget, fetch, File, FormData, Headers, HTMLBodyElement, HTMLCanvasElement, HTMLDivElement, HTMLDocument, HTMLElement, HTMLHeadElement, HTMLHtmlElement, HTMLImageElement, HTMLSpanElement, HTMLStyleElement, HTMLTemplateElement, HTMLUnknownElement, Image, ImageData, IntersectionObserver, MediaQueryList, MutationObserver, Node, NodeFilter, NodeIterator, OffscreenCanvas, ReadableByteStreamController, ReadableStream, ReadableStreamBYOBReader, ReadableStreamBYOBRequest, ReadableStreamDefaultController, ReadableStreamDefaultReader, Request, requestAnimationFrame, requestIdleCallback, ResizeObserver, Response, setTimeout, ShadowRoot, structuredClone, StyleSheet, Text, TransformStream, TreeWalker, URLPattern, Window, WritableStream, WritableStreamDefaultController, WritableStreamDefaultWriter } from './mod.js';
|
||||
export { AbortController, AbortSignal, alert, atob, Blob, btoa, ByteLengthQueuingStrategy, cancelAnimationFrame, cancelIdleCallback, CanvasRenderingContext2D, CharacterData, clearTimeout, Comment, CountQueuingStrategy, CSSStyleSheet, CustomElementRegistry, CustomEvent, Document, DocumentFragment, DOMException, Element, Event, EventTarget, fetch, File, FormData, Headers, HTMLBodyElement, HTMLCanvasElement, HTMLDivElement, HTMLDocument, HTMLElement, HTMLHeadElement, HTMLHtmlElement, HTMLImageElement, HTMLSpanElement, HTMLStyleElement, HTMLTemplateElement, HTMLUnknownElement, Image, ImageData, IntersectionObserver, MediaQueryList, MutationObserver, Node, NodeFilter, NodeIterator, OffscreenCanvas, ReadableByteStreamController, ReadableStream, ReadableStreamBYOBReader, ReadableStreamBYOBRequest, ReadableStreamDefaultController, ReadableStreamDefaultReader, Request, requestAnimationFrame, requestIdleCallback, ResizeObserver, Response, setTimeout, ShadowRoot, structuredClone, StyleSheet, Text, TransformStream, TreeWalker, URLPattern, Window, WritableStream, WritableStreamDefaultController, WritableStreamDefaultWriter, } from './mod.js';
|
||||
export declare const polyfill: {
|
||||
(target: any, options?: PolyfillOptions): any;
|
||||
internals(target: any, name: string): any;
|
||||
|
|
Loading…
Reference in a new issue