From 3c54d32b6d381663d9868b5bc4e2e09e6d913be7 Mon Sep 17 00:00:00 2001 From: Elliot DeNolf Date: Sun, 31 Mar 2024 23:22:38 -0400 Subject: [PATCH] feat(cpa): rework all prompts to use @clack/prompts --- packages/create-payload-app/package.json | 7 +- .../src/lib/create-project.ts | 23 +++--- .../create-payload-app/src/lib/init-next.ts | 47 ++++++------ .../src/lib/parse-project-name.ts | 25 +++--- .../src/lib/parse-template.ts | 39 ++++------ .../create-payload-app/src/lib/select-db.ts | 55 +++++--------- .../src/lib/write-env-file.ts | 7 +- packages/create-payload-app/src/main.ts | 59 ++++++++------ packages/create-payload-app/src/utils/log.ts | 25 ++---- .../create-payload-app/src/utils/messages.ts | 76 +++++++++---------- pnpm-lock.yaml | 46 ++++++++--- 11 files changed, 193 insertions(+), 216 deletions(-) diff --git a/packages/create-payload-app/package.json b/packages/create-payload-app/package.json index 5a6dccf23..bb5720263 100644 --- a/packages/create-payload-app/package.json +++ b/packages/create-payload-app/package.json @@ -21,6 +21,7 @@ "bin" ], "dependencies": { + "@clack/prompts": "^0.7.0", "@sindresorhus/slugify": "^1.1.0", "arg": "^5.0.0", "chalk": "^4.1.0", @@ -33,9 +34,6 @@ "figures": "^3.2.0", "fs-extra": "^9.0.1", "globby": "11.1.0", - "handlebars": "^4.7.7", - "ora": "^5.1.0", - "prompts": "^2.4.2", "terminal-link": "^2.1.1" }, "devDependencies": { @@ -44,8 +42,7 @@ "@types/esprima": "^4.0.6", "@types/fs-extra": "^9.0.12", "@types/jest": "^27.0.3", - "@types/node": "^16.6.2", - "@types/prompts": "^2.4.1" + "@types/node": "^16.6.2" }, "exports": { "./commands": { diff --git a/packages/create-payload-app/src/lib/create-project.ts b/packages/create-payload-app/src/lib/create-project.ts index 5babdc9cf..864245653 100644 --- a/packages/create-payload-app/src/lib/create-project.ts +++ b/packages/create-payload-app/src/lib/create-project.ts @@ -1,15 +1,14 @@ +import * as p from '@clack/prompts' import chalk from 'chalk' import degit from 'degit' import execa from 'execa' import fse from 'fs-extra' import { fileURLToPath } from 'node:url' -import ora from 'ora' import path from 'path' import type { CliArgs, DbDetails, PackageManager, ProjectTemplate } from '../types.js' -import { log } from '../utils/log.js' -import { debug, error, success, warning } from '../utils/log.js' +import { debug, error, warning } from '../utils/log.js' import { configurePayloadConfig } from './configure-payload-config.js' const filename = fileURLToPath(import.meta.url) @@ -61,14 +60,12 @@ export async function createProject(args: { const { cliArgs, dbDetails, packageManager, projectDir, projectName, template } = args if (cliArgs['--dry-run']) { - log(`\n Dry run: Creating project in ${chalk.green(projectDir)}\n`) + debug(`Dry run: Creating project in ${chalk.green(projectDir)}`) return } await createOrFindProjectDir(projectDir) - log(`\n Creating project in ${chalk.green(projectDir)}\n`) - if (cliArgs['--local-template']) { // Copy template from local path. For development purposes. const localTemplate = path.resolve( @@ -87,9 +84,11 @@ export async function createProject(args: { await emitter.clone(projectDir) } - const spinner = ora('Checking latest Payload version...').start() + const spinner = p.spinner() + spinner.start('Checking latest Payload version...') await updatePackageJSON({ projectDir, projectName }) + spinner.message('Configuring Payload...') await configurePayloadConfig({ dbDetails, projectDirOrConfigPath: { projectDir } }) // Remove yarn.lock file. This is only desired in Payload Cloud. @@ -99,18 +98,16 @@ export async function createProject(args: { } if (!cliArgs['--no-deps']) { - spinner.text = 'Installing dependencies...' + spinner.message('Installing dependencies...') const result = await installDeps({ cliArgs, packageManager, projectDir }) spinner.stop() - spinner.clear() if (result) { - success('Dependencies installed') + spinner.stop('Dependencies installed') } else { - error('Error installing dependencies') + spinner.stop('Error installing dependencies', 1) } } else { - spinner.stop() - spinner.clear() + spinner.stop('Dependency installation skipped') } } diff --git a/packages/create-payload-app/src/lib/init-next.ts b/packages/create-payload-app/src/lib/init-next.ts index 20edfed65..d4c39279a 100644 --- a/packages/create-payload-app/src/lib/init-next.ts +++ b/packages/create-payload-app/src/lib/init-next.ts @@ -1,5 +1,6 @@ import type { CompilerOptions } from 'typescript' +import * as p from '@clack/prompts' import { parse, stringify } from 'comment-json' import execa from 'execa' import fs from 'fs' @@ -7,7 +8,6 @@ import globby from 'globby' import path from 'path' import { promisify } from 'util' -import { log } from '../utils/log.js' const readFile = promisify(fs.readFile) const writeFile = promisify(fs.writeFile) @@ -16,14 +16,15 @@ const dirname = path.dirname(filename) import { fileURLToPath } from 'node:url' -import type { CliArgs, PackageManager } from '../types.js' +import type { CliArgs, DbType, PackageManager } from '../types.js' import { copyRecursiveSync } from '../utils/copy-recursive-sync.js' -import { error, info, debug as origDebug, success, warning } from '../utils/log.js' +import { debug as origDebug, warning } from '../utils/log.js' import { moveMessage } from '../utils/messages.js' import { wrapNextConfig } from './wrap-next-config.js' type InitNextArgs = Pick & { + dbType: DbType nextConfigPath: string packageManager: PackageManager projectDir: string @@ -40,7 +41,7 @@ type InitNextResult = | { isSrcDir: boolean; nextAppDir?: string; reason: string; success: false } export async function initNext(args: InitNextArgs): Promise { - const { packageManager, projectDir } = args + const { dbType: dbType, packageManager, projectDir } = args const isSrcDir = fs.existsSync(path.resolve(projectDir, 'src')) @@ -61,7 +62,7 @@ export async function initNext(args: InitNextArgs): Promise { const layoutPath = path.resolve(nextAppDir, 'layout.tsx') if (fs.existsSync(layoutPath)) { // Output directions for user to move all files from app to top-level directory named `(app)` - log(moveMessage({ nextAppDir, projectDir })) + p.log.warn(moveMessage({ nextAppDir, projectDir })) return { isSrcDir, nextAppDir, @@ -70,6 +71,9 @@ export async function initNext(args: InitNextArgs): Promise { } } + const installSpinner = p.spinner() + installSpinner.start('Installing Payload and dependencies...') + const configurationResult = installAndConfigurePayload({ ...args, isSrcDir, @@ -78,11 +82,13 @@ export async function initNext(args: InitNextArgs): Promise { }) if (configurationResult.success === false) { + installSpinner.stop(configurationResult.reason, 1) return { ...configurationResult, isSrcDir, success: false } } - const { success: installSuccess } = await installDeps(projectDir, packageManager) + const { success: installSuccess } = await installDeps(projectDir, packageManager, dbType) if (!installSuccess) { + installSpinner.stop('Failed to install dependencies', 1) return { ...configurationResult, isSrcDir, @@ -93,7 +99,7 @@ export async function initNext(args: InitNextArgs): Promise { // Add `@payload-config` to tsconfig.json `paths` await addPayloadConfigToTsConfig(projectDir, isSrcDir) - + installSpinner.stop('Successfully installed Payload and dependencies') return { ...configurationResult, isSrcDir, nextAppDir, success: true } } @@ -119,14 +125,15 @@ async function addPayloadConfigToTsConfig(projectDir: string, isSrcDir: boolean) } function installAndConfigurePayload( - args: InitNextArgs & { isSrcDir: boolean; nextAppDir: string }, + args: InitNextArgs & { + isSrcDir: boolean + nextAppDir: string + }, ): | { payloadConfigPath: string; success: true } | { payloadConfigPath?: string; reason: string; success: false } { const { '--debug': debug, isSrcDir, nextAppDir, nextConfigPath, projectDir, useDistFiles } = args - info('Initializing Payload app in Next.js project', 1) - const logDebug = (message: string) => { if (debug) origDebug(message) } @@ -174,21 +181,18 @@ function installAndConfigurePayload( // Wrap next.config.js with withPayload wrapNextConfig({ nextConfigPath }) - success('Successfully initialized.') return { payloadConfigPath: path.resolve(nextAppDir, '../payload.config.ts'), success: true, } } -async function installDeps(projectDir: string, packageManager: PackageManager) { - info(`Installing dependencies with ${packageManager}`, 1) - const packagesToInstall = [ - 'payload', - '@payloadcms/db-mongodb', - '@payloadcms/next', - '@payloadcms/richtext-lexical', - ].map((pkg) => `${pkg}@alpha`) +async function installDeps(projectDir: string, packageManager: PackageManager, dbType: DbType) { + const packagesToInstall = ['payload', '@payloadcms/next', '@payloadcms/richtext-lexical'].map( + (pkg) => `${pkg}@alpha`, + ) + + packagesToInstall.push(`@payloadcms/db-${dbType}@alpha`) let exitCode = 0 switch (packageManager) { @@ -212,10 +216,5 @@ async function installDeps(projectDir: string, packageManager: PackageManager) { } } - if (exitCode !== 0) { - error(`Failed to install dependencies with ${packageManager}`) - } else { - success(`Successfully installed dependencies`) - } return { success: exitCode === 0 } } diff --git a/packages/create-payload-app/src/lib/parse-project-name.ts b/packages/create-payload-app/src/lib/parse-project-name.ts index 75448a047..467fa965e 100644 --- a/packages/create-payload-app/src/lib/parse-project-name.ts +++ b/packages/create-payload-app/src/lib/parse-project-name.ts @@ -1,4 +1,4 @@ -import prompts from 'prompts' +import * as p from '@clack/prompts' import type { CliArgs } from '../types.js' @@ -6,19 +6,14 @@ export async function parseProjectName(args: CliArgs): Promise { if (args['--name']) return args['--name'] if (args._[0]) return args._[0] - const response = await prompts( - { - name: 'value', - type: 'text', - message: 'Project name?', - validate: (value: string) => !!value.length, + const projectName = await p.text({ + message: 'Project name?', + validate: (value) => { + if (!value) return 'Please enter a project name.' }, - { - onCancel: () => { - process.exit(0) - }, - }, - ) - - return response.value + }) + if (p.isCancel(projectName)) { + process.exit(0) + } + return projectName } diff --git a/packages/create-payload-app/src/lib/parse-template.ts b/packages/create-payload-app/src/lib/parse-template.ts index 29b519751..aa811e910 100644 --- a/packages/create-payload-app/src/lib/parse-template.ts +++ b/packages/create-payload-app/src/lib/parse-template.ts @@ -1,11 +1,11 @@ -import prompts from 'prompts' +import * as p from '@clack/prompts' import type { CliArgs, ProjectTemplate } from '../types.js' export async function parseTemplate( args: CliArgs, validTemplates: ProjectTemplate[], -): Promise { +): Promise { if (args['--template']) { const templateName = args['--template'] const template = validTemplates.find((t) => t.name === templateName) @@ -13,29 +13,20 @@ export async function parseTemplate( return template } - const response = await prompts( - { - name: 'value', - type: 'select', - choices: validTemplates.map((p) => { - return { - description: p.description, - title: p.name, - value: p.name, - } - }), - message: 'Choose project template', - validate: (value: string) => !!value.length, - }, - { - onCancel: () => { - process.exit(0) - }, - }, - ) + const response = await p.select<{ label: string; value: string }[], string>({ + message: 'Choose project template', + options: validTemplates.map((p) => { + return { + label: p.name, + value: p.name, + } + }), + }) + if (p.isCancel(response)) { + process.exit(0) + } - const template = validTemplates.find((t) => t.name === response.value) - if (!template) throw new Error('Template is undefined') + const template = validTemplates.find((t) => t.name === response) return template } diff --git a/packages/create-payload-app/src/lib/select-db.ts b/packages/create-payload-app/src/lib/select-db.ts index 57c92df6f..9b1d3a1a7 100644 --- a/packages/create-payload-app/src/lib/select-db.ts +++ b/packages/create-payload-app/src/lib/select-db.ts @@ -1,5 +1,5 @@ +import * as p from '@clack/prompts' import slugify from '@sindresorhus/slugify' -import prompts from 'prompts' import type { CliArgs, DbDetails, DbType } from '../types.js' @@ -23,7 +23,7 @@ const dbChoiceRecord: Record = { } export async function selectDb(args: CliArgs, projectName: string): Promise { - let dbType: DbType | undefined = undefined + let dbType: DbType | symbol | undefined = undefined if (args['--db']) { if (!Object.values(dbChoiceRecord).some((dbChoice) => dbChoice.value === args['--db'])) { throw new Error( @@ -34,31 +34,20 @@ export async function selectDb(args: CliArgs, projectName: string): Promise { - return { - title: dbChoice.title, - value: dbChoice.value, - } - }), - message: 'Select a database', - validate: (value: string) => !!value.length, - }, - { - onCancel: () => { - process.exit(0) - }, - }, - ) - dbType = dbTypeRes.value + dbType = await p.select<{ label: string; value: DbType }[], DbType>({ + initialValue: 'mongodb', + message: `Select a database`, + options: [ + { label: 'MongoDB', value: 'mongodb' }, + { label: 'Postgres', value: 'postgres' }, + ], + }) + if (p.isCancel(dbType)) process.exit(0) } const dbChoice = dbChoiceRecord[dbType] - let dbUri: string | undefined = undefined + let dbUri: string | symbol | undefined = undefined const initialDbUri = `${dbChoice.dbConnectionPrefix}${ projectName === '.' ? `payload-${getRandomDigitSuffix()}` : slugify(projectName) }` @@ -68,21 +57,11 @@ export async function selectDb(args: CliArgs, projectName: string): Promise !!value.length, - }, - { - onCancel: () => { - process.exit(0) - }, - }, - ) - dbUri = dbUriRes.value + dbUri = await p.text({ + initialValue: initialDbUri, + message: `Enter ${dbChoice.title.split(' ')[0]} connection string`, // strip beta from title + }) + if (p.isCancel(dbUri)) process.exit(0) } return { diff --git a/packages/create-payload-app/src/lib/write-env-file.ts b/packages/create-payload-app/src/lib/write-env-file.ts index 558db601f..bff1b7522 100644 --- a/packages/create-payload-app/src/lib/write-env-file.ts +++ b/packages/create-payload-app/src/lib/write-env-file.ts @@ -1,10 +1,9 @@ -import chalk from 'chalk' import fs from 'fs-extra' import path from 'path' import type { CliArgs, ProjectTemplate } from '../types.js' -import { error, success } from '../utils/log.js' +import { debug, error } from '../utils/log.js' /** Parse and swap .env.example values and write .env */ export async function writeEnvFile(args: { @@ -17,7 +16,7 @@ export async function writeEnvFile(args: { const { cliArgs, databaseUri, payloadSecret, projectDir, template } = args if (cliArgs['--dry-run']) { - success(`DRY RUN: .env file created`) + debug(`DRY RUN: .env file created`) return } @@ -51,8 +50,6 @@ export async function writeEnvFile(args: { const content = `MONGODB_URI=${databaseUri}\nPAYLOAD_SECRET=${payloadSecret}` await fs.outputFile(`${projectDir}/.env`, content) } - - success('.env file created') } catch (err: unknown) { error('Unable to write .env file') if (err instanceof Error) { diff --git a/packages/create-payload-app/src/main.ts b/packages/create-payload-app/src/main.ts index e550edaa0..c35ce5577 100644 --- a/packages/create-payload-app/src/main.ts +++ b/packages/create-payload-app/src/main.ts @@ -1,5 +1,7 @@ +import * as p from '@clack/prompts' import slugify from '@sindresorhus/slugify' import arg from 'arg' +import chalk from 'chalk' import { detect } from 'detect-package-manager' import globby from 'globby' import path from 'path' @@ -15,13 +17,8 @@ import { parseTemplate } from './lib/parse-template.js' import { selectDb } from './lib/select-db.js' import { getValidTemplates, validateTemplate } from './lib/templates.js' import { writeEnvFile } from './lib/write-env-file.js' -import { error, log, success } from './utils/log.js' -import { - helpMessage, - successMessage, - successfulNextInit, - welcomeMessage, -} from './utils/messages.js' +import { error, info } from './utils/log.js' +import { feedbackOutro, helpMessage, successMessage, successfulNextInit } from './utils/messages.js' export class Main { args: CliArgs @@ -73,21 +70,20 @@ export class Main { try { if (this.args['--help']) { - log(helpMessage()) + helpMessage() process.exit(0) } - log(welcomeMessage) - // Detect if inside Next.js project + // eslint-disable-next-line no-console + console.log('\n') + p.intro(chalk.bgCyan(chalk.black(' create-payload-app '))) + p.log.message("Welcome to Payload. Let's create a project!") + // Detect if inside Next.js projeckpt const nextConfigPath = ( await globby('next.config.*js', { absolute: true, cwd: process.cwd() }) )?.[0] initContext.nextConfigPath = nextConfigPath - success('Next.js app detected.') - - // TODO: Prompt to continue - if (initContext.nextConfigPath) { this.args['--name'] = slugify(path.basename(path.dirname(initContext.nextConfigPath))) } @@ -100,20 +96,30 @@ export class Main { const packageManager = await getPackageManager(this.args, projectDir) if (nextConfigPath) { + // p.note('Detected existing Next.js project.') + p.log.step(chalk.bold('Detected existing Next.js project.')) + const proceed = await p.confirm({ + initialValue: true, + message: 'Install Payload in this project?', + }) + if (p.isCancel(proceed) || !proceed) { + process.exit(0) + } + + const dbDetails = await selectDb(this.args, projectName) + const result = await initNext({ ...this.args, + dbType: dbDetails.type, nextConfigPath, packageManager, projectDir, }) + if (result.success === false) { - error(result.reason) process.exit(1) - } else { - success('Payload app successfully initialized in Next.js project') } - const dbDetails = await selectDb(this.args, projectName) await configurePayloadConfig({ dbDetails, projectDirOrConfigPath: { @@ -121,9 +127,9 @@ export class Main { }, }) - // TODO: This should continue the normal prompt flow - success('Payload project successfully created') - log(successfulNextInit()) + info('Payload project successfully created!') + p.note(successfulNextInit(), chalk.bgGreen(chalk.black(' Documentation '))) + p.outro(feedbackOutro()) return } @@ -131,13 +137,17 @@ export class Main { if (templateArg) { const valid = validateTemplate(templateArg) if (!valid) { - log(helpMessage()) + helpMessage() process.exit(1) } } const validTemplates = getValidTemplates() const template = await parseTemplate(this.args, validTemplates) + if (!template) { + p.log.error('Invalid template given') + process.exit(1) + } switch (template.type) { case 'starter': { @@ -172,8 +182,9 @@ export class Main { } } - success('Payload project successfully created') - log(successMessage(projectDir, packageManager)) + info('Payload project successfully created!') + p.note(successMessage(projectDir, packageManager), chalk.bgGreen(chalk.black(' Next Steps '))) + p.outro(feedbackOutro()) } catch (err: unknown) { error(err instanceof Error ? err.message : 'An error occurred') } diff --git a/packages/create-payload-app/src/utils/log.ts b/packages/create-payload-app/src/utils/log.ts index bac90d546..ac90478c6 100644 --- a/packages/create-payload-app/src/utils/log.ts +++ b/packages/create-payload-app/src/utils/log.ts @@ -1,34 +1,23 @@ /* eslint-disable no-console */ +import * as p from '@clack/prompts' import chalk from 'chalk' -import figures from 'figures' - -export const success = (message: string): void => { - console.log(`${chalk.green(figures.tick)} ${chalk.bold(message)}`) -} export const warning = (message: string): void => { - console.log(chalk.yellow('? ') + chalk.bold(message)) + p.log.warn(chalk.yellow('? ') + chalk.bold(message)) } -export const info = (message: string, paddingTop?: number): void => { - console.log( - `${'\n'.repeat(paddingTop || 0)}${chalk.green(figures.pointerSmall)} ${chalk.bold(message)}`, - ) +export const info = (message: string): void => { + p.log.step(chalk.bold(message)) } export const error = (message: string): void => { - console.log(`${chalk.red(figures.cross)} ${chalk.bold(message)}`) + p.log.error(chalk.bold(message)) } export const debug = (message: string): void => { - console.log( - `${chalk.gray(figures.pointerSmall)} ${chalk.bgGray('[DEBUG]')} ${chalk.gray(message)}`, - ) + p.log.step(`${chalk.bgGray('[DEBUG]')} ${chalk.gray(message)}`) } -/** - * console.log passthrough - */ export const log = (message: string): void => { - console.log(message) + p.log.message(message) } diff --git a/packages/create-payload-app/src/utils/messages.ts b/packages/create-payload-app/src/utils/messages.ts index e72d307d4..9a4cd9890 100644 --- a/packages/create-payload-app/src/utils/messages.ts +++ b/packages/create-payload-app/src/utils/messages.ts @@ -1,13 +1,14 @@ +/* eslint-disable no-console */ import chalk from 'chalk' -import figures from 'figures' import path from 'path' import terminalLink from 'terminal-link' import type { ProjectTemplate } from '../types.js' +import type { PackageManager } from '../types.js' import { getValidTemplates } from '../lib/templates.js' -const header = (message: string): string => `${chalk.yellow(figures.star)} ${chalk.bold(message)}` +const header = (message: string): string => chalk.bold(message) export const welcomeMessage = chalk` {green Welcome to Payload. Let's create a project! } @@ -15,14 +16,14 @@ export const welcomeMessage = chalk` const spacer = ' '.repeat(8) -export function helpMessage(): string { +export function helpMessage(): void { const validTemplates = getValidTemplates() - return chalk` + console.log(chalk` {bold USAGE} {dim $} {bold npx create-payload-app} {dim $} {bold npx create-payload-app} my-project - {dim $} {bold npx create-payload-app} -n my-project -t blog + {dim $} {bold npx create-payload-app} -n my-project -t template-name {bold OPTIONS} @@ -36,7 +37,7 @@ export function helpMessage(): string { --use-pnpm Use pnpm to install dependencies --no-deps Do not install any dependencies -h Show help -` +`) } function formatTemplates(templates: ProjectTemplate[]) { @@ -45,59 +46,58 @@ function formatTemplates(templates: ProjectTemplate[]) { .join(`\n${spacer}`)}` } -export function successMessage(projectDir: string, packageManager: string): string { +export function successMessage(projectDir: string, packageManager: PackageManager): string { + const relativePath = path.relative(process.cwd(), projectDir) return ` - ${header('Launch Application:')} +${header('Launch Application:')} - - cd ${projectDir} - - ${ - packageManager === 'yarn' ? 'yarn' : 'npm run' - } dev or follow directions in ${createTerminalLink( - 'README.md', - `file://${path.resolve(projectDir, 'README.md')}`, - )} + - cd ./${relativePath} + - ${ + packageManager === 'npm' ? 'npm run' : packageManager + } dev or follow directions in ${createTerminalLink( + 'README.md', + `file://${path.resolve(projectDir, 'README.md')}`, + )} - ${header('Documentation:')} +${header('Documentation:')} - - ${createTerminalLink( - 'Getting Started', - 'https://payloadcms.com/docs/getting-started/what-is-payload', - )} - - ${createTerminalLink('Configuration', 'https://payloadcms.com/docs/configuration/overview')} + - ${createTerminalLink( + 'Getting Started', + 'https://payloadcms.com/docs/getting-started/what-is-payload', + )} + - ${createTerminalLink('Configuration', 'https://payloadcms.com/docs/configuration/overview')} ` } export function successfulNextInit(): string { - return ` - ${header('Successful Payload Installation!')} - - ${header('Documentation:')} - - - ${createTerminalLink( - 'Getting Started', - 'https://payloadcms.com/docs/getting-started/what-is-payload', - )} - - ${createTerminalLink('Configuration', 'https://payloadcms.com/docs/configuration/overview')} + return `- ${createTerminalLink( + 'Getting Started', + 'https://payloadcms.com/docs/getting-started/what-is-payload', + )} +- ${createTerminalLink('Configuration', 'https://payloadcms.com/docs/configuration/overview')} ` } export function moveMessage(args: { nextAppDir: string; projectDir: string }): string { + const relativePath = path.relative(process.cwd(), args.nextAppDir) return ` - ${header('Next Steps:')} +${header('Next Steps:')} - Payload does not support a top-level layout.tsx file in your Next.js app directory. +Payload does not support a top-level layout.tsx file in your Next.js app directory. - ${chalk.bold('To continue:')} +${chalk.bold('To continue:')} - - Move all files from ${args.nextAppDir} to a top-level directory named ${chalk.bold( - '(app)', - )} or similar. +Move all files from ./${relativePath} to a named directory such as ${chalk.bold('(app)')} - Once moved, rerun the create-payload-app command again. +Once moved, rerun the create-payload-app command again. ` } +export function feedbackOutro(): string { + return `${chalk.bgCyan(chalk.black(' Have feedback? '))} Visit ${createTerminalLink('GitHub', 'https://github.com/payloadcms/payload')}` +} + // Create terminalLink with fallback for unsupported terminals function createTerminalLink(text: string, url: string) { return terminalLink(text, url, { diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 32e5bedb7..94e02c1c2 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -295,6 +295,9 @@ importers: packages/create-payload-app: dependencies: + '@clack/prompts': + specifier: ^0.7.0 + version: 0.7.0 '@sindresorhus/slugify': specifier: ^1.1.0 version: 1.1.2 @@ -331,15 +334,6 @@ importers: globby: specifier: 11.1.0 version: 11.1.0 - handlebars: - specifier: ^4.7.7 - version: 4.7.8 - ora: - specifier: ^5.1.0 - version: 5.4.1 - prompts: - specifier: ^2.4.2 - version: 2.4.2 terminal-link: specifier: ^2.1.1 version: 2.1.1 @@ -362,9 +356,6 @@ importers: '@types/node': specifier: ^16.6.2 version: 16.18.85 - '@types/prompts': - specifier: ^2.4.1 - version: 2.4.9 packages/db-mongodb: dependencies: @@ -2745,6 +2736,23 @@ packages: /@bcoe/v8-coverage@0.2.3: resolution: {integrity: sha512-0hYQ8SB4Db5zvZB4axdMHGwEaQjkZzFjQiN9LVYvIFB2nSUHW9tYpxWriPrWDASIxiaXax83REcLxuSdnGPZtw==} + /@clack/core@0.3.4: + resolution: {integrity: sha512-H4hxZDXgHtWTwV3RAVenqcC4VbJZNegbBjlPvzOzCouXtS2y3sDvlO3IsbrPNWuLWPPlYVYPghQdSF64683Ldw==} + dependencies: + picocolors: 1.0.0 + sisteransi: 1.0.5 + dev: false + + /@clack/prompts@0.7.0: + resolution: {integrity: sha512-0MhX9/B4iL6Re04jPrttDm+BsP8y6mS7byuv0BvXgdXhbV5PdlsHt55dvNsuBCPZ7xq1oTAOOuotR9NFbQyMSA==} + dependencies: + '@clack/core': 0.3.4 + picocolors: 1.0.0 + sisteransi: 1.0.5 + dev: false + bundledDependencies: + - is-unicode-supported + /@cspotcode/source-map-support@0.8.1: resolution: {integrity: sha512-IchNf6dN4tHoMFIn/7OE8LWZ19Y6q/67Bmf6vnGREv8RSbBVb9LPJxEcnwrcwX6ixSvaiGoomAUvu4YSxXrVgw==} engines: {node: '>=12'} @@ -7451,6 +7459,7 @@ packages: buffer: 5.7.1 inherits: 2.0.4 readable-stream: 3.6.2 + dev: true /body-parser@1.20.1: resolution: {integrity: sha512-jWi7abTbYwajOytWCQc37VulmWiRae5RyTpaCyDcS5/lMdtwSz5lOpDE67srw/HYe35f1z3fDQw+3txg7gNtWw==} @@ -7790,6 +7799,7 @@ packages: engines: {node: '>=8'} dependencies: restore-cursor: 3.1.0 + dev: true /cli-cursor@4.0.0: resolution: {integrity: sha512-VGtlMu3x/4DOtIUwEkRezxUZ2lBacNJCHash0N0WeZDBS+7Ux1dm3XWAgWYxLJFMMdOeXMHXorshEFhbMSGelg==} @@ -7801,6 +7811,7 @@ packages: /cli-spinners@2.9.2: resolution: {integrity: sha512-ywqV+5MmyL4E7ybXgKys4DugZbX0FC6LnwrhjuykIjnK9k8OQacQ7axGKnjDXWNhns0xot3bZI5h55H8yo9cJg==} engines: {node: '>=6'} + dev: true /cli-truncate@3.1.0: resolution: {integrity: sha512-wfOBkjXteqSnI59oPcJkcPl/ZmwvMMOj340qUIY1SKZCv0B9Cf4D4fAucRkIKQmsIuYK3x1rrgU7MeGRruiuiA==} @@ -7852,6 +7863,7 @@ packages: /clone@1.0.4: resolution: {integrity: sha512-JQHZ2QMW6l3aH/j6xCqQThY/9OH4D/9ls34cgkUBiEeocRTU04tHfKPBsUK1PqZCUQM7GiA0IIXJSuXHI64Kbg==} engines: {node: '>=0.8'} + dev: true /clsx@1.2.1: resolution: {integrity: sha512-EcR6r5a8bj6pu3ycsa/E/cKVGuTgZJZdsyUYHOksG/UHIiKfjxzRxYJpyVBwYaQeOvghal9fcc4PidlgzugAQg==} @@ -8738,6 +8750,7 @@ packages: resolution: {integrity: sha512-eFuaLoy/Rxalv2kr+lqMlUnrDWV+3j4pljOIJgLIhI058IQfWJ7vXhyEIHu+HtC738klGALYxOKDO0bQP3tg8A==} dependencies: clone: 1.0.4 + dev: true /defer-to-connect@2.0.1: resolution: {integrity: sha512-4tvttepXG1VaYGrRibk5EwJd1t4udunSOVMdLSAL6mId1ix438oPwPZMALY41FCijukO1L0twNcGsdzS7dHgDg==} @@ -10725,6 +10738,7 @@ packages: wordwrap: 1.0.0 optionalDependencies: uglify-js: 3.17.4 + dev: true /hanji@0.0.5: resolution: {integrity: sha512-Abxw1Lq+TnYiL4BueXqMau222fPSPMFtya8HdpWsz/xVAhifXou71mPh/kY2+08RgFcVccjG3uZHs6K5HAe3zw==} @@ -11234,6 +11248,7 @@ packages: /is-interactive@1.0.0: resolution: {integrity: sha512-2HvIEKRoqS62guEC+qBjpvRubdX910WCMuJTZ+I9yvqKU2/12eSL549HMwtabb4oupdj2sMP50k+XJfB/8JE6w==} engines: {node: '>=8'} + dev: true /is-interactive@2.0.0: resolution: {integrity: sha512-qP1vozQRI+BMOPcjFzrjXuQvdak2pHNUMZoeG2eRbiSqyvbEf/wQtEOTOX1guk6E3t36RkaqiSt8A/6YElNxLQ==} @@ -11366,6 +11381,7 @@ packages: /is-unicode-supported@0.1.0: resolution: {integrity: sha512-knxG2q4UC3u8stRGyAVJCOdxFmv5DZiRcdlIaAQXAbSfJya+OhopNotLQrstBhququ4ZpuKbDc/8S6mgXgPFPw==} engines: {node: '>=10'} + dev: true /is-unicode-supported@1.3.0: resolution: {integrity: sha512-43r2mRvz+8JRIKnWJ+3j8JtjRKZ6GmjzfaE/qiBJnikNnYv/6bagRJ1kUhNk8R5EX/GkobD+r+sfxCPJsiKBLQ==} @@ -12595,6 +12611,7 @@ packages: dependencies: chalk: 4.1.2 is-unicode-supported: 0.1.0 + dev: true /log-symbols@6.0.0: resolution: {integrity: sha512-i24m8rpwhmPIS4zscNzK6MSEhk0DUWa/8iYQWxhffV8jkI4Phvs3F+quL5xvS0gdQR0FyTCMMH33Y78dDTzzIw==} @@ -13060,6 +13077,7 @@ packages: /neo-async@2.6.2: resolution: {integrity: sha512-Yd3UES5mWCSqR+qNT93S3UoYUkqAZ9lLg8a7g9rimsWmYGK8cVToA4/sF3RrshdyV3sAGMXVUmpMYOw+dLpOuw==} + dev: true /netmask@2.0.2: resolution: {integrity: sha512-dBpDMdxv9Irdq66304OLfEmQ9tbNRFnFTuZiLo+bD+r332bBmMJ8GBLXklIXXgxd3+v9+KUnZaUR5PJMa75Gsg==} @@ -13489,6 +13507,7 @@ packages: log-symbols: 4.1.0 strip-ansi: 6.0.1 wcwidth: 1.0.1 + dev: true /ora@8.0.1: resolution: {integrity: sha512-ANIvzobt1rls2BDny5fWZ3ZVKyD6nscLvfFRpQgfWsythlcsVUC9kL0zq6j2Z5z9wwp1kd7wpsD/T9qNPVLCaQ==} @@ -15472,6 +15491,7 @@ packages: dependencies: onetime: 5.1.2 signal-exit: 3.0.7 + dev: true /restore-cursor@4.0.0: resolution: {integrity: sha512-I9fPXU9geO9bHOt9pHHOhOkYerIMsmVaWB0rA2AI9ERh/+x/i7MV5HKBNrg+ljO5eoPVgCcnFuRjJ9uH6I/3eg==} @@ -17014,6 +17034,7 @@ packages: engines: {node: '>=0.8.0'} hasBin: true requiresBuild: true + dev: true optional: true /unbox-primitive@1.0.2: @@ -17242,6 +17263,7 @@ packages: resolution: {integrity: sha512-XHPEwS0q6TaxcvG85+8EYkbiCux2XtWG2mkc47Ng2A77BQu9+DqIOJldST4HgPkuea7dvKSj5VgX3P1d4rW8Tg==} dependencies: defaults: 1.0.4 + dev: true /web-streams-polyfill@3.3.3: resolution: {integrity: sha512-d2JWLCivmZYTSIoge9MsgFCZrt571BikcWGYkjC1khllbTeDlGqZ2D8vD8E/lJa8WGWbb7Plm8/XJYV7IJHZZw==}