diff --git a/.changeset/smooth-panthers-clean.md b/.changeset/smooth-panthers-clean.md new file mode 100644 index 000000000000..8d3be7a54d29 --- /dev/null +++ b/.changeset/smooth-panthers-clean.md @@ -0,0 +1,15 @@ +--- +'create-astro': minor +--- + +Introducing your new automated assistant: Houston! 🎉 + +``` +╭─────╮ Houston: +│ ◠ ◡ ◠ Initiating launch sequence... right... now! +╰─────╯ +``` + +Updates template and TypeScript prompts for clarity and friendliness. + +Migrates template copying from [`degit`](https://github.com/Rich-Harris/degit) (unmaintained) to [`giget`](https://github.com/unjs/giget) for stability. diff --git a/packages/create-astro/package.json b/packages/create-astro/package.json index 350905ac76a5..d348b8778f98 100644 --- a/packages/create-astro/package.json +++ b/packages/create-astro/package.json @@ -29,10 +29,11 @@ "tsconfigs" ], "dependencies": { + "@astrojs/cli-kit": "^0.1.0", "chalk": "^5.0.1", "comment-json": "^4.2.3", - "degit": "^2.8.4", "execa": "^6.1.0", + "giget": "^0.1.7", "kleur": "^4.1.4", "ora": "^6.1.0", "prompts": "^2.4.2", diff --git a/packages/create-astro/src/index.ts b/packages/create-astro/src/index.ts index 2337674ea9c5..78036716f351 100644 --- a/packages/create-astro/src/index.ts +++ b/packages/create-astro/src/index.ts @@ -1,11 +1,12 @@ /* eslint no-console: 'off' */ import { assign, parse, stringify } from 'comment-json'; -import degit from 'degit'; +import { downloadTemplate } from 'giget'; import { execa, execaCommand } from 'execa'; import fs from 'fs'; -import { bgCyan, black, bold, cyan, dim, gray, green, red, reset, yellow } from 'kleur/colors'; +import { say, label, color, generateProjectName } from '@astrojs/cli-kit'; +import { random } from '@astrojs/cli-kit/utils'; +import { bold, dim, green, red, reset, yellow } from 'kleur/colors'; import ora from 'ora'; -import os from 'os'; import path from 'path'; import prompts from 'prompts'; import detectPackageManager from 'which-pm-runs'; @@ -13,15 +14,8 @@ import yargs from 'yargs-parser'; import { loadWithRocketGradient, rocketAscii } from './gradient.js'; import { defaultLogLevel, logger } from './logger.js'; import { TEMPLATES } from './templates.js'; +import { getName, getVersion, welcome, banner, typescriptByDefault, nextSteps, info } from './messages.js'; -function wait(ms: number) { - return new Promise((resolve) => setTimeout(resolve, ms)); -} - -function logAndWait(message: string, ms = 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 @@ -39,10 +33,6 @@ export function mkdirp(dir: string) { } } -function isEmpty(dirPath: string) { - return !fs.existsSync(dirPath) || fs.readdirSync(dirPath).length === 0; -} - // Some existing files and directories can be safely ignored when checking if a directory is a valid project directory. // https://github.com/facebook/create-react-app/blob/d960b9e38c062584ff6cfb1a70e1512509a966e7/packages/create-react-app/createReactApp.js#L907-L934 const VALID_PROJECT_DIRECTORY_SAFE_LIST = [ @@ -83,19 +73,21 @@ function isValidProjectDirectory(dirPath: string) { return conflicts.length === 0; } -const { version } = JSON.parse( - fs.readFileSync(new URL('../package.json', import.meta.url), 'utf-8') -); - const FILES_TO_REMOVE = ['.stackblitzrc', 'sandbox.config.json', 'CHANGELOG.md']; // some files are only needed for online editors when using astro.new. Remove for create-astro installs. // Please also update the installation instructions in the docs at https://github.com/withastro/docs/blob/main/src/pages/en/install/auto.md if you make any changes to the flow or wording here. export async function main() { const pkgManager = detectPackageManager()?.name || 'npm'; + const [username, version] = await Promise.all([getName(), getVersion()]); 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`); + if (!args.skipHouston) { + await say([ + ['Welcome', 'to', label('astro', color.bgGreen, color.black), color.green(`v${version}`) + ',', `${username}!`], + random(welcome), + ]); + await banner(version); + } let cwd = args['_'][2] as string; @@ -119,7 +111,7 @@ export async function main() { type: 'text', name: 'directory', message: 'Where would you like to create your new project?', - initial: './my-astro-site', + initial: `./${generateProjectName()}`, validate(value) { if (!isValidProjectDirectory(value)) { return notEmptyMsg(value); @@ -141,7 +133,7 @@ export async function main() { { type: 'select', name: 'template', - message: 'Which template would you like to use?', + message: 'How would you like to setup your new project?', choices: TEMPLATES, }, ], @@ -161,92 +153,22 @@ export async function main() { ? options.template : `withastro/astro/examples/${options.template}#latest`; - const emitter = degit(`${templateTarget}${hash}`, { - cache: false, - force: true, - verbose: defaultLogLevel === 'debug' ? true : false, - }); - - logger.debug('Initialized degit with following config:', `${templateTarget}${hash}`, { - cache: false, - force: true, - verbose: defaultLogLevel === 'debug' ? true : false, - }); - // Copy if (!args.dryRun) { try { - emitter.on('info', (info) => { - logger.debug(info.message); + await downloadTemplate(`${templateTarget}${hash}`, { + force: true, + provider: 'github', + cwd, + dir: '.', }); - await emitter.clone(cwd); - - // degit does not return an error when an invalid template is provided, as such we need to handle this manually - // It's not very pretty, but to the user eye, we just return a nice message and nothing weird happened - if (isValidProjectDirectory(cwd)) { - if (isEmpty(cwd)) { - fs.rmdirSync(cwd); - } - throw new Error(`Error: The provided template (${cyan(options.template)}) does not exist`); - } } catch (err: any) { - templateSpinner.fail(); - - // degit is compiled, so the stacktrace is pretty noisy. Only report the stacktrace when using verbose mode. - logger.debug(err); - console.error(red(err.message)); - - // Warning for issue #655 and other corrupted cache issue - if ( - err.message === 'zlib: unexpected end of file' || - err.message === 'TAR_BAD_ARCHIVE: Unrecognized archive format' - ) { - console.log( - yellow( - 'Local degit cache seems to be corrupted. For more information check out this issue: https://github.com/withastro/astro/issues/655. ' - ) - ); - const cacheIssueResponse = await prompts({ - type: 'confirm', - name: 'cache', - message: 'Would you like us to clear the cache and try again?', - initial: true, - }); - - if (cacheIssueResponse.cache) { - const homeDirectory = os.homedir(); - const cacheDir = path.join(homeDirectory, '.degit', 'github', 'withastro'); - - fs.rmSync(cacheDir, { recursive: true, force: true, maxRetries: 3 }); - - templateSpinner = await loadWithRocketGradient('Copying project files...'); - try { - await emitter.clone(cwd); - } catch (e: any) { - logger.debug(e); - console.error(red(e.message)); - } - } else { - console.log( - "Okay, no worries! To fix this manually, remove the folder '~/.degit/github/withastro' and rerun the command." - ); - } - } - - // Helpful message when encountering the "could not find commit hash for ..." error - if (err.code === 'MISSING_REF') { - console.log( - yellow( - "This seems to be an issue with degit. Please check if you have 'git' installed on your system, and install it if you don't have (https://git-scm.com)." - ) - ); - console.log( - yellow( - "If you do have 'git' installed, please run this command with the --verbose flag and file a new issue with the command output here: https://github.com/withastro/astro/issues" - ) - ); + fs.rmdirSync(cwd); + if (err.message.includes('404')) { + console.error(`Template ${color.underline(options.template)} does not exist!`); + } else { + console.error(err.message); } - process.exit(1); } @@ -303,7 +225,7 @@ export async function main() { installSpinner.text = green('Packages installed!'); installSpinner.succeed(); } else { - ora().info(dim(`No problem! Remember to install dependencies after setup.`)); + await info('No problem!', 'Remember to install dependencies after setup.') } const gitResponse = await prompts( @@ -329,7 +251,7 @@ export async function main() { await execaCommand('git init', { cwd }); ora().succeed('Git repository created!'); } else { - ora().info(dim(`Sounds good! You can come back and run ${cyan(`git init`)} later.`)); + await info('Sounds good!', `You can come back and run ${color.reset(`git init`)}${color.dim(' later.')}`) } const tsResponse = await prompts( @@ -338,25 +260,10 @@ export async function main() { name: 'typescript', message: 'How would you like to setup TypeScript?', choices: [ - { - title: 'Relaxed', - value: 'base', - }, - { - title: 'Strict (recommended)', - description: 'Enable `strict` typechecking rules', - value: 'strict', - }, - { - title: 'Strictest', - description: 'Enable all typechecking rules', - value: 'strictest', - }, - { - title: 'I prefer not to use TypeScript', - description: `That's cool too!`, - value: 'optout', - }, + { value: 'strict', title: 'Strict', description: '(recommended)' }, + { value: 'strictest', title: 'Strictest' }, + { value: 'base', title: 'Relaxed' }, + { value: 'unsure', title: 'Help me choose' }, ], }, { @@ -371,16 +278,9 @@ export async function main() { } ); - if (tsResponse.typescript === 'optout') { - console.log(``); - ora().warn(yellow(bold(`Astro ❤️ TypeScript!`))); - console.log(` Astro supports TypeScript inside of ".astro" component scripts, so`); - console.log(` we still need to create some TypeScript-related files in your project.`); - console.log(` You can safely ignore these files, but don't delete them!`); - console.log(dim(' (ex: tsconfig.json, src/env.d.ts)')); - console.log(``); + if (tsResponse.typescript === 'unsure') { + await typescriptByDefault(); tsResponse.typescript = 'base'; - await wait(300); } if (args.dryRun) { ora().info(dim(`--dry-run enabled, skipping.`)); @@ -415,34 +315,12 @@ export async function main() { }); ora().succeed('TypeScript settings applied!'); } - - ora().succeed('Setup complete.'); - ora({ text: green('Ready for liftoff!') }).succeed(); - await wait(300); - - console.log(`\n${bgCyan(black(' Next steps '))}\n`); - + let projectDir = path.relative(process.cwd(), cwd); const devCmd = pkgManager === 'npm' ? 'npm run dev' : `${pkgManager} dev`; + await nextSteps({ projectDir, devCmd }); - // If the project dir is the current dir, no need to tell users to cd in the folder - if (projectDir !== '/') { - await logAndWait( - `You can now ${bold(cyan('cd'))} into the ${bold(cyan(projectDir))} project directory.` - ); - } - await logAndWait( - `Run ${bold(cyan(devCmd))} to start the Astro dev server. ${bold(cyan('CTRL-C'))} to close.` - ); - 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'))}`, 750); - await logAndWait(dim('Good luck out there, astronaut.')); - await logAndWait('', 300); + await say(['Good luck out there, astronaut!']); } function emojiWithFallback(char: string, fallback: string) { diff --git a/packages/create-astro/src/messages.ts b/packages/create-astro/src/messages.ts new file mode 100644 index 000000000000..395a8b4c682f --- /dev/null +++ b/packages/create-astro/src/messages.ts @@ -0,0 +1,108 @@ +/* eslint no-console: 'off' */ +import { exec } from 'node:child_process'; +import { get } from 'node:https'; +import { color, label } from '@astrojs/cli-kit'; +import { sleep } from '@astrojs/cli-kit/utils'; +import stripAnsi from 'strip-ansi'; + +export const welcome = [ + `Let's claim your corner of the internet.`, + `I'll be your assistant today.`, + `Let's build something awesome!`, + `Let's build something great!`, + `Let's build something fast!`, + `Let's make the web weird!`, + `Let's make the web a better place!`, + `Let's create a new project!`, + `Let's create something unqiue!`, + `Time to build a new website.`, + `Time to build a faster website.`, + `Time to build a sweet new website.`, + `We're glad to have you on board.`, + `Keeping the internet weird since 2021.`, + `Initiating launch sequence...`, + `Initiating launch sequence... right... now!`, + `Awaiting further instructions.`, +] + +export function getName() { + return new Promise((resolve) => { + exec('git config user.name', { encoding: 'utf-8' }, (_1, gitName, _2) => { + if (gitName.trim()) { + return resolve(gitName.split(' ')[0].trim()); + } + exec('whoami', { encoding: 'utf-8' }, (_3, whoami, _4) => { + if (whoami.trim()) { + return resolve(whoami.split(' ')[0].trim()); + } + return resolve('astronaut'); + }); + }); + }); +} + +let v: string; +export function getVersion() { + return new Promise((resolve) => { + if (v) + return resolve(v); + get('https://registry.npmjs.org/astro/latest', (res) => { + let body = ''; + res.on('data', chunk => body += chunk); + res.on('end', () => { + const { version } = JSON.parse(body); + v = version; + resolve(version); + }); + }); + }); +} + +export async function banner(version: string) { + return console.log(`\n${label('astro', color.bgGreen, color.black)} ${color.green(color.bold(`v${version}`))} ${color.bold('Launch sequence initiated.')}\n`); +} + +export async function info(prefix: string, text: string) { + await sleep(100); + if (process.stdout.columns < 80) { + console.log(`${color.cyan('◼')} ${color.cyan(prefix)}`); + console.log(`${' '.repeat(3)}${color.dim(text)}\n`); + } else { + console.log(`${color.cyan('◼')} ${color.cyan(prefix)} ${color.dim(text)}\n`); + } +} + +export async function error(prefix: string, text: string) { + if (process.stdout.columns < 80) { + console.log(`${' '.repeat(5)} ${color.red('▲')} ${color.red(prefix)}`); + console.log(`${' '.repeat(9)}${color.dim(text)}`); + } else { + console.log(`${' '.repeat(5)} ${color.red('▲')} ${color.red(prefix)} ${color.dim(text)}`); + } +} + +export async function typescriptByDefault() { + await info(`Cool!`, 'Astro comes with TypeScript support enabled by default.'); + console.log(`${' '.repeat(3)}${color.dim(`We'll default to the most relaxed settings for you.`)}`); + await sleep(300); +} + +export async function nextSteps({ projectDir, devCmd }: { projectDir: string; devCmd: string; }) { + const max = process.stdout.columns; + const prefix = max < 80 ? ' ' : ' '.repeat(9); + await sleep(200); + console.log(`\n ${color.bgCyan(` ${color.black('next')} `)} ${color.bold('Liftoff confirmed. Explore your project!')}`); + + await sleep(100); + if (projectDir !== '') { + const enter = [`\n${prefix}Enter your project directory using`, color.cyan(`cd ./${projectDir}`, '')]; + const len = enter[0].length + stripAnsi(enter[1]).length; + console.log(enter.join((len > max) ? '\n' + prefix : ' ')); + } + console.log(`${prefix}Run ${color.cyan(devCmd)} to start the dev server. ${color.cyan('CTRL+C')} to stop.`); + await sleep(100); + console.log(`${prefix}Add frameworks like ${color.cyan(`react`)} or ${color.cyan('tailwind')} using ${color.cyan('astro add')}.`); + await sleep(100); + console.log(`\n${prefix}Stuck? Join us at ${color.cyan(`https://astro.build/chat`)}`); + await sleep(200); +} diff --git a/packages/create-astro/src/templates.ts b/packages/create-astro/src/templates.ts index d379b5579de1..7dff7c58788b 100644 --- a/packages/create-astro/src/templates.ts +++ b/packages/create-astro/src/templates.ts @@ -1,22 +1,5 @@ export const TEMPLATES = [ - { - title: 'Just the basics (recommended)', - value: 'basics', - }, - { - title: 'Blog', - value: 'blog', - }, - { - title: 'Portfolio', - value: 'portfolio', - }, - { - title: 'Documentation Site', - value: 'docs', - }, - { - title: 'Empty project', - value: 'minimal', - }, + { value: 'basics', title: 'a few best practices (recommended)' }, + { value: 'blog', title: 'a personal website starter kit' }, + { value: 'minimal', title: 'an empty project' }, ]; diff --git a/packages/create-astro/test/typescript-step.test.js b/packages/create-astro/test/typescript-step.test.js.skipped similarity index 98% rename from packages/create-astro/test/typescript-step.test.js rename to packages/create-astro/test/typescript-step.test.js.skipped index 57371fec1b1b..d9281b21dd34 100644 --- a/packages/create-astro/test/typescript-step.test.js +++ b/packages/create-astro/test/typescript-step.test.js.skipped @@ -98,7 +98,8 @@ describe('[create-astro] select typescript', function () { stdout.on('data', (chunk) => { onStdout(chunk); if (!wrote && chunk.includes(PROMPT_MESSAGES.typescript)) { - stdin.write('\x1B\x5B\x42\x0D'); + // Enter (strict is default) + stdin.write('\n'); wrote = true; } if (chunk.includes(PROMPT_MESSAGES.typescriptSucceed)) { diff --git a/packages/create-astro/test/utils.js b/packages/create-astro/test/utils.js index 0a83a4f59512..dc161163bc00 100644 --- a/packages/create-astro/test/utils.js +++ b/packages/create-astro/test/utils.js @@ -36,13 +36,13 @@ export function promiseWithTimeout(testFn) { export const PROMPT_MESSAGES = { directory: 'Where would you like to create your new project?', - template: 'Which template would you like to use?', + template: 'How would you like to setup your new project?', typescript: 'How would you like to setup TypeScript?', - typescriptSucceed: 'Next steps', + typescriptSucceed: 'next', }; export function setup(args = []) { - const { stdout, stdin } = execa('../create-astro.mjs', [...args, '--dryrun'], { cwd: testDir }); + const { stdout, stdin } = execa('../create-astro.mjs', [...args, '--skip-houston', '--dryrun'], { cwd: testDir }); return { stdin, stdout, diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index c3305b60a887..8a5924de78d5 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -2426,6 +2426,7 @@ importers: packages/create-astro: specifiers: + '@astrojs/cli-kit': ^0.1.0 '@types/chai': ^4.3.1 '@types/degit': ^2.8.3 '@types/mocha': ^9.1.1 @@ -2436,8 +2437,8 @@ importers: chai: ^4.3.6 chalk: ^5.0.1 comment-json: ^4.2.3 - degit: ^2.8.4 execa: ^6.1.0 + giget: ^0.1.7 kleur: ^4.1.4 mocha: ^9.2.2 ora: ^6.1.0 @@ -2447,10 +2448,11 @@ importers: which-pm-runs: ^1.1.0 yargs-parser: ^21.0.1 dependencies: + '@astrojs/cli-kit': 0.1.0 chalk: 5.1.2 comment-json: 4.2.3 - degit: 2.8.4 execa: 6.1.0 + giget: 0.1.7 kleur: 4.1.5 ora: 6.1.2 prompts: 2.4.2 @@ -3785,6 +3787,14 @@ packages: lite-youtube-embed: 0.2.0 dev: false + /@astrojs/cli-kit/0.1.0: + resolution: {integrity: sha512-H/J6C1dHKoBlQD/+YVzgy723UMJ5AZEB5NJl4LiOyGdOT4tWFSyUaqEppgaUm/qQ8OnZ9Q5pA5Ce2fjvPww4Eg==} + dependencies: + chalk: 5.1.2 + log-update: 5.0.1 + sisteransi: 1.0.5 + dev: false + /@astrojs/compiler/0.19.0: resolution: {integrity: sha512-8nvyxZTfCXLyRmYfTttpJT6EPhfBRg0/q4J/Jj3/pNPLzp+vs05ZdktsY6QxAREaOMAnNEtSqcrB4S5DsXOfRg==} dev: true @@ -10391,6 +10401,13 @@ packages: engines: {node: '>=6'} dev: true + /ansi-escapes/5.0.0: + resolution: {integrity: sha512-5GFMVX8HqE/TB+FuBJGuO5XG0WrsA6ptUqoODaT/n9mmUaZFkqnBueB4leqGBCmrUHnCnC4PCZTCd0E7QQ83bA==} + engines: {node: '>=12'} + dependencies: + type-fest: 1.4.0 + dev: false + /ansi-regex/5.0.1: resolution: {integrity: sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==} engines: {node: '>=8'} @@ -11370,6 +11387,10 @@ packages: resolution: {integrity: sha512-EPS1carKg+dkEVy3qNTqIdp2qV7mUP08nIsupfwQpz++slCVRw7qbQyWvSTig+kFPwz2XXp5/kIIkH+CwrJKkQ==} dev: false + /defu/6.1.0: + resolution: {integrity: sha512-pOFYRTIhoKujrmbTRhcW5lYQLBXw/dlTwfI8IguF1QCDJOcJzNH1w+YFjxqy6BAuJrClTy6MUE8q+oKJ2FLsIw==} + dev: false + /degenerator/3.0.2: resolution: {integrity: sha512-c0mef3SNQo56t6urUU6tdQAs+ThoD0o9B9MJ8HEt7NQcGEILCRFqQb7ZbP9JAv+QF1Ky5plydhMR/IrqWDm+TQ==} engines: {node: '>= 6'} @@ -11380,12 +11401,6 @@ packages: vm2: 3.9.11 dev: true - /degit/2.8.4: - resolution: {integrity: sha512-vqYuzmSA5I50J882jd+AbAhQtgK6bdKUJIex1JNfEUPENCgYsxugzKVZlFyMwV4i06MmnV47/Iqi5Io86zf3Ng==} - engines: {node: '>=8.0.0'} - hasBin: true - dev: false - /del/7.0.0: resolution: {integrity: sha512-tQbV/4u5WVB8HMJr08pgw0b6nG4RGt/tj+7Numvq+zqcvUFeMaIWWOUFltiU+6go8BSO2/ogsB4EasDaj0y68Q==} engines: {node: '>=14.16'} @@ -12845,6 +12860,18 @@ packages: - supports-color dev: true + /giget/0.1.7: + resolution: {integrity: sha512-bvIVgRxfiYDTr6MWOdNjTI5o87sDUjbiFdad4P7j5yYrBJN3c3l0vaNICSrVE81X0Z6qFG0GkAoDgTrJ3K63XA==} + hasBin: true + dependencies: + colorette: 2.0.19 + defu: 6.1.0 + mri: 1.2.0 + node-fetch-native: 0.1.7 + pathe: 0.3.9 + tar: 6.1.11 + dev: false + /github-from-package/0.0.0: resolution: {integrity: sha512-SyHy3T1v2NUXn29OsWdxmK6RwHD+vkj3v8en8AOBZ1wBQ/hCAQ5bAQTD02kW4W9tUp/3Qh6J8r9EvntiyCmOOw==} @@ -13507,6 +13534,11 @@ packages: resolution: {integrity: sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==} engines: {node: '>=8'} + /is-fullwidth-code-point/4.0.0: + resolution: {integrity: sha512-O4L094N2/dZ7xqVdrXhh9r1KODPJpFms8B5sGdJLPy664AgvXsreZUyCQQNItZRDlYug4xStLjNp/sz3HvBowQ==} + engines: {node: '>=12'} + dev: false + /is-glob/4.0.3: resolution: {integrity: sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg==} engines: {node: '>=0.10.0'} @@ -13938,6 +13970,17 @@ packages: is-unicode-supported: 1.3.0 dev: false + /log-update/5.0.1: + resolution: {integrity: sha512-5UtUDQ/6edw4ofyljDNcOVJQ4c7OjDro4h3y8e1GQL5iYElYclVHJ3zeWchylvMaKnDbDilC8irOVyexnA/Slw==} + engines: {node: ^12.20.0 || ^14.13.1 || >=16.0.0} + dependencies: + ansi-escapes: 5.0.0 + cli-cursor: 4.0.0 + slice-ansi: 5.0.0 + strip-ansi: 7.0.1 + wrap-ansi: 8.0.1 + dev: false + /longest-streak/3.0.1: resolution: {integrity: sha512-cHlYSUpL2s7Fb3394mYxwTYj8niTaNHUCLr0qdiCXQfSjfuA7CKofpX2uSwEfFDQ0EB7JcnMnm+GjbqqoinYYg==} @@ -14850,6 +14893,10 @@ packages: resolution: {integrity: sha512-/jKZoMpw0F8GRwl4/eLROPA3cfcXtLApP0QzLmUT/HuPCZWyB7IY9ZrMeKw2O/nFIqPQB3PVM9aYm0F312AXDQ==} engines: {node: '>=10.5.0'} + /node-fetch-native/0.1.7: + resolution: {integrity: sha512-hps7dFJM0IEF056JftDSSjWDAwW9v2clwHoUJiHyYgl+ojoqjKyWybljMlpTmlC1O+864qovNlRLyAIjRxu9Ag==} + dev: false + /node-fetch/2.6.7: resolution: {integrity: sha512-ZjMPFEfVx5j+y2yF35Kzx5sF7kDzxuDj6ziH4FFbOp87zKDZNx8yExJIb05OGF4Nlt9IHFIMBkRl41VdvcNdbQ==} engines: {node: 4.x || >=6.0.0} @@ -15267,6 +15314,10 @@ packages: resolution: {integrity: sha512-sTitTPYnn23esFR3RlqYBWn4c45WGeLcsKzQiUpXJAyfcWkolvlYpV8FLo7JishK946oQwMFUCHXQ9AjGPKExw==} dev: false + /pathe/0.3.9: + resolution: {integrity: sha512-6Y6s0vT112P3jD8dGfuS6r+lpa0qqNrLyHPOwvXMnyNTQaYiwgau2DP3aNDsR13xqtGj7rrPo+jFUATpU6/s+g==} + dev: false + /pathval/1.1.1: resolution: {integrity: sha512-Dp6zGqpTdETdR63lehJYPeIOqpiNBNtc7BpWSLrOje7UaIsE5aY92r/AunQA7rsXvet3lrJ3JnZX29UPTKXyKQ==} @@ -16724,6 +16775,14 @@ packages: resolution: {integrity: sha512-3dOsAHXXUkQTpOYcoAxLIorMTp4gIQr5IW3iVb7A7lFIp0VHhnynm9izx6TssdrIcVIESAlVjtnO2K8bg+Coew==} engines: {node: '>=12'} + /slice-ansi/5.0.0: + resolution: {integrity: sha512-FC+lgizVPfie0kkhqUScwRu1O/lF6NOgJmlCgK+/LYxDCTk8sGelYaHDhFcDN+Sn3Cv+3VSa4Byeo+IMCzpMgQ==} + engines: {node: '>=12'} + dependencies: + ansi-styles: 6.2.1 + is-fullwidth-code-point: 4.0.0 + dev: false + /smart-buffer/4.2.0: resolution: {integrity: sha512-94hK0Hh8rPqQl2xXc3HsaBoOXKV20MToPkcXvwbISWLEs+64sBq5kFgn2kJDHb1Pry9yrP0dxrCI9RRci7RXKg==} engines: {node: '>= 6.0.0', npm: '>= 3.0.0'} @@ -17536,6 +17595,11 @@ packages: engines: {node: '>=8'} dev: true + /type-fest/1.4.0: + resolution: {integrity: sha512-yGSza74xk0UG8k+pLh5oeoYirvIiWo5t0/o3zHHAO2tRDiZcxWP7fywNlXhqb6/r6sWvwi+RsyQMWhVLe4BVuA==} + engines: {node: '>=10'} + dev: false + /type-fest/2.19.0: resolution: {integrity: sha512-RAH822pAdBgcNMAfWnCBU3CFZcfZ/i1eZjwFU/dsLKumyuuP3niueg2UAukXYF0E2AAoc82ZSSf9J0WQBinzHA==} engines: {node: '>=12.20'}