From 099366b0613e0cbdfc51344ab804eee5ac1455f2 Mon Sep 17 00:00:00 2001 From: Olyno Date: Tue, 27 Apr 2021 01:50:41 +0200 Subject: [PATCH 01/14] refactor: replace enquirer with prompts --- packages/create-app/index.js | 175 ++++++++++--------------------- packages/create-app/package.json | 4 +- 2 files changed, 57 insertions(+), 122 deletions(-) diff --git a/packages/create-app/index.js b/packages/create-app/index.js index dc9b752432958e..dd886d1ca0003d 100755 --- a/packages/create-app/index.js +++ b/packages/create-app/index.js @@ -5,7 +5,7 @@ const fs = require('fs') const path = require('path') const argv = require('minimist')(process.argv.slice(2)) // eslint-disable-next-line node/no-restricted-require -const { prompt } = require('enquirer') +const prompts = require('prompts'); const { yellow, green, @@ -127,104 +127,62 @@ const renameFiles = { async function init() { let targetDir = argv._[0] - if (!targetDir) { - /** - * @type {{ projectName: string }} - */ - const { projectName } = await prompt({ - type: 'input', - name: 'projectName', - message: `Project name:`, - initial: 'vite-project' - }) - targetDir = projectName - } - const packageName = await getValidPackageName(targetDir) - const root = path.join(cwd, targetDir) - - if (!fs.existsSync(root)) { - fs.mkdirSync(root, { recursive: true }) - } else { - const existing = fs.readdirSync(root) - if (existing.length) { - /** - * @type {{ yes: boolean }} - */ - const { yes } = await prompt({ - type: 'confirm', - name: 'yes', - initial: 'Y', - message: - (targetDir === '.' - ? 'Current directory' - : `Target directory ${targetDir}`) + - ' is not empty.\n' + - 'Remove existing files and continue?' + const initialFrameworkIndex = FRAMEWORKS.findIndex(framework => [argv.t, argv.template].includes(framework.name)); + const result = await prompts([ + { + type: 'text', + name: 'packageName', + message: 'Project name:', + initial: targetDir || 'vite-project', + validate: dir => /^(?:@[a-z0-9-*~][a-z0-9-*._~]*\/)?[a-z0-9-~][a-z0-9-._~]*$/.test(dir) || 'Invalid package.json name', + }, + { + type: targetDir => !fs.existsSync(targetDir) || isEmpty(targetDir) ? null : 'confirm', + name: 'overwrite', + message: targetDir => `Target directory ${targetDir} is not empty. Remove existing files and continue?`, + initial: false + }, + { + type: FRAMEWORKS.find(framework => [argv.t, argv.template].includes(framework.name)) ? null : 'select', + name: 'framework', + message: 'Select a framework:', + initial: initialFrameworkIndex > -1 ? initialFrameworkIndex : 0, + choices: FRAMEWORKS.map(framework => { + const frameworkColor = framework.color; + return { + title: frameworkColor(framework.name), + value: framework + } + }) + }, + { + type: framework => framework.variants ? 'select' : null, + name: 'variant', + message: 'Select a variant:', + // @ts-ignore + choices: framework => framework.variants.map(variant => { + const variantColor = variant.color; + return { + title: variantColor(variant.name), + value: variant.name + } }) - if (yes) { - emptyDir(root) - } else { - return - } } - } + ], { onCancel: () => { + throw new Error('Operation cancelled') + }}); - // determine template - let template = argv.t || argv.template - let message = 'Select a framework:' - let isValidTemplate = false + const packageName = result.packageName + const root = path.join(cwd, result.packageName) - // --template expects a value - if (typeof template === 'string') { - isValidTemplate = TEMPLATES.includes(template) - message = `${template} isn't a valid template. Please choose from below:` + if (result.overwrite) { + emptyDir(root) + } else { + fs.mkdirSync(root); } - if (!template || !isValidTemplate) { - /** - * @type {{ framework: string }} - */ - const { framework } = await prompt({ - type: 'select', - name: 'framework', - message, - format(name) { - const framework = FRAMEWORKS.find((v) => v.name === name) - return framework - ? framework.color(framework.display || framework.name) - : name - }, - choices: FRAMEWORKS.map((f) => ({ - name: f.name, - value: f.name, - message: f.color(f.display || f.name) - })) - }) - const frameworkInfo = FRAMEWORKS.find((f) => f.name === framework) - - if (frameworkInfo.variants) { - /** - * @type {{ name: string }} - */ - const { name } = await prompt({ - type: 'select', - name: 'name', - format(name) { - const variant = frameworkInfo.variants.find((v) => v.name === name) - return variant ? variant.color(variant.display || variant.name) : name - }, - message: 'Select a variant:', - choices: frameworkInfo.variants.map((v) => ({ - name: v.name, - value: v.name, - message: v.color(v.display || v.name) - })) - }) - template = name - } else { - template = frameworkInfo.name - } - } + // determine template + const template = result.variant || result.framework console.log(`\nScaffolding project in ${root}...`) @@ -272,33 +230,6 @@ function copy(src, dest) { } } -async function getValidPackageName(projectName) { - const packageNameRegExp = /^(?:@[a-z0-9-*~][a-z0-9-*._~]*\/)?[a-z0-9-~][a-z0-9-._~]*$/ - if (packageNameRegExp.test(projectName)) { - return projectName - } else { - const suggestedPackageName = projectName - .trim() - .toLowerCase() - .replace(/\s+/g, '-') - .replace(/^[._]/, '') - .replace(/[^a-z0-9-~]+/g, '-') - - /** - * @type {{ inputPackageName: string }} - */ - const { inputPackageName } = await prompt({ - type: 'input', - name: 'inputPackageName', - message: `Package name:`, - initial: suggestedPackageName, - validate: (input) => - packageNameRegExp.test(input) ? true : 'Invalid package.json name' - }) - return inputPackageName - } -} - function copyDir(srcDir, destDir) { fs.mkdirSync(destDir, { recursive: true }) for (const file of fs.readdirSync(srcDir)) { @@ -308,6 +239,10 @@ function copyDir(srcDir, destDir) { } } +function isEmpty(path) { + return fs.readdirSync(path).length === 0 +} + function emptyDir(dir) { if (!fs.existsSync(dir)) { return diff --git a/packages/create-app/package.json b/packages/create-app/package.json index 1c8ce0cb21fb06..2cef858ade3334 100644 --- a/packages/create-app/package.json +++ b/packages/create-app/package.json @@ -29,8 +29,8 @@ }, "homepage": "https://github.com/vitejs/vite/tree/main/packages/create-app#readme", "dependencies": { - "enquirer": "^2.3.6", "kolorist": "^1.2.9", - "minimist": "^1.2.5" + "minimist": "^1.2.5", + "prompts": "^2.4.1" } } From 58ff4ac4589808afb6f74a551b0e6f7764162561 Mon Sep 17 00:00:00 2001 From: Olyno Date: Tue, 27 Apr 2021 19:50:07 +0200 Subject: [PATCH 02/14] fix: error if file exists --- packages/create-app/index.js | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/packages/create-app/index.js b/packages/create-app/index.js index dd886d1ca0003d..9611c9aac2a808 100755 --- a/packages/create-app/index.js +++ b/packages/create-app/index.js @@ -5,7 +5,7 @@ const fs = require('fs') const path = require('path') const argv = require('minimist')(process.argv.slice(2)) // eslint-disable-next-line node/no-restricted-require -const prompts = require('prompts'); +const prompts = require('prompts') const { yellow, green, @@ -127,7 +127,7 @@ const renameFiles = { async function init() { let targetDir = argv._[0] - const initialFrameworkIndex = FRAMEWORKS.findIndex(framework => [argv.t, argv.template].includes(framework.name)); + const initialFrameworkIndex = FRAMEWORKS.findIndex(framework => [argv.t, argv.template].includes(framework.name)) const result = await prompts([ { type: 'text', @@ -148,7 +148,7 @@ async function init() { message: 'Select a framework:', initial: initialFrameworkIndex > -1 ? initialFrameworkIndex : 0, choices: FRAMEWORKS.map(framework => { - const frameworkColor = framework.color; + const frameworkColor = framework.color return { title: frameworkColor(framework.name), value: framework @@ -161,7 +161,7 @@ async function init() { message: 'Select a variant:', // @ts-ignore choices: framework => framework.variants.map(variant => { - const variantColor = variant.color; + const variantColor = variant.color return { title: variantColor(variant.name), value: variant.name @@ -170,15 +170,15 @@ async function init() { } ], { onCancel: () => { throw new Error('Operation cancelled') - }}); + }}) const packageName = result.packageName const root = path.join(cwd, result.packageName) if (result.overwrite) { emptyDir(root) - } else { - fs.mkdirSync(root); + } else if (!fs.existsSync(root)) { + fs.mkdirSync(root) } // determine template From ea32757f707dbbb6db84b2e52ee5e86a2901e429 Mon Sep 17 00:00:00 2001 From: Olyno Date: Wed, 28 Apr 2021 15:21:10 +0200 Subject: [PATCH 03/14] fix: target dir creation name --- packages/create-app/index.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/create-app/index.js b/packages/create-app/index.js index 9611c9aac2a808..9d0cfd8106add9 100755 --- a/packages/create-app/index.js +++ b/packages/create-app/index.js @@ -173,7 +173,7 @@ async function init() { }}) const packageName = result.packageName - const root = path.join(cwd, result.packageName) + const root = path.join(cwd, targetDir) if (result.overwrite) { emptyDir(root) From 468a3f33accaa352d7d47a6620b5151cc3d70abc Mon Sep 17 00:00:00 2001 From: Olyno Date: Wed, 28 Apr 2021 15:25:42 +0200 Subject: [PATCH 04/14] fix: default package name --- packages/create-app/index.js | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/packages/create-app/index.js b/packages/create-app/index.js index 9d0cfd8106add9..e0f144aa4c9c4a 100755 --- a/packages/create-app/index.js +++ b/packages/create-app/index.js @@ -128,12 +128,17 @@ const renameFiles = { async function init() { let targetDir = argv._[0] const initialFrameworkIndex = FRAMEWORKS.findIndex(framework => [argv.t, argv.template].includes(framework.name)) + const defaultPackageName = !targetDir ? 'vite-project' : targetDir.trim() + .toLowerCase() + .replace(/\s+/g, '-') + .replace(/^[._]/, '') + .replace(/[^a-z0-9-~]+/g, '-') const result = await prompts([ { type: 'text', name: 'packageName', message: 'Project name:', - initial: targetDir || 'vite-project', + initial: defaultPackageName, validate: dir => /^(?:@[a-z0-9-*~][a-z0-9-*._~]*\/)?[a-z0-9-~][a-z0-9-._~]*$/.test(dir) || 'Invalid package.json name', }, { From ba9ed8f35d27c6445d3cd71fc130185b78de471f Mon Sep 17 00:00:00 2001 From: Olyno Date: Wed, 28 Apr 2021 16:07:18 +0200 Subject: [PATCH 05/14] fix: show message instead of stacktrace --- packages/create-app/index.js | 92 +++++++++++++++++++----------------- 1 file changed, 49 insertions(+), 43 deletions(-) diff --git a/packages/create-app/index.js b/packages/create-app/index.js index e0f144aa4c9c4a..d6ece3e3e98916 100755 --- a/packages/create-app/index.js +++ b/packages/create-app/index.js @@ -133,49 +133,55 @@ async function init() { .replace(/\s+/g, '-') .replace(/^[._]/, '') .replace(/[^a-z0-9-~]+/g, '-') - const result = await prompts([ - { - type: 'text', - name: 'packageName', - message: 'Project name:', - initial: defaultPackageName, - validate: dir => /^(?:@[a-z0-9-*~][a-z0-9-*._~]*\/)?[a-z0-9-~][a-z0-9-._~]*$/.test(dir) || 'Invalid package.json name', - }, - { - type: targetDir => !fs.existsSync(targetDir) || isEmpty(targetDir) ? null : 'confirm', - name: 'overwrite', - message: targetDir => `Target directory ${targetDir} is not empty. Remove existing files and continue?`, - initial: false - }, - { - type: FRAMEWORKS.find(framework => [argv.t, argv.template].includes(framework.name)) ? null : 'select', - name: 'framework', - message: 'Select a framework:', - initial: initialFrameworkIndex > -1 ? initialFrameworkIndex : 0, - choices: FRAMEWORKS.map(framework => { - const frameworkColor = framework.color - return { - title: frameworkColor(framework.name), - value: framework - } - }) - }, - { - type: framework => framework.variants ? 'select' : null, - name: 'variant', - message: 'Select a variant:', - // @ts-ignore - choices: framework => framework.variants.map(variant => { - const variantColor = variant.color - return { - title: variantColor(variant.name), - value: variant.name - } - }) - } - ], { onCancel: () => { - throw new Error('Operation cancelled') - }}) + let result = {}; + try { + result = await prompts([ + { + type: 'text', + name: 'packageName', + message: 'Project name:', + initial: defaultPackageName, + validate: dir => /^(?:@[a-z0-9-*~][a-z0-9-*._~]*\/)?[a-z0-9-~][a-z0-9-._~]*$/.test(dir) || 'Invalid package.json name', + }, + { + type: targetDir => !fs.existsSync(targetDir) || isEmpty(targetDir) ? null : 'confirm', + name: 'overwrite', + message: targetDir => `Target directory ${targetDir} is not empty. Remove existing files and continue?`, + initial: false + }, + { + type: FRAMEWORKS.find(framework => [argv.t, argv.template].includes(framework.name)) ? null : 'select', + name: 'framework', + message: 'Select a framework:', + initial: initialFrameworkIndex > -1 ? initialFrameworkIndex : 0, + choices: FRAMEWORKS.map(framework => { + const frameworkColor = framework.color + return { + title: frameworkColor(framework.name), + value: framework + } + }) + }, + { + type: framework => framework.variants ? 'select' : null, + name: 'variant', + message: 'Select a variant:', + // @ts-ignore + choices: framework => framework.variants.map(variant => { + const variantColor = variant.color + return { + title: variantColor(variant.name), + value: variant.name + } + }) + } + ], { onCancel: () => { + throw new Error(red('✖') + ' Operation cancelled') + }}) + } catch (cancelled) { + console.log(cancelled.message) + return; + } const packageName = result.packageName const root = path.join(cwd, targetDir) From 157cdd0482e928c336f8acde2707ff3e170de9c2 Mon Sep 17 00:00:00 2001 From: Olyno Date: Tue, 18 May 2021 17:06:42 +0200 Subject: [PATCH 06/14] fix(create-app): root dir undefined --- packages/create-app/index.js | 120 ++++++++++++++++++++--------------- 1 file changed, 70 insertions(+), 50 deletions(-) diff --git a/packages/create-app/index.js b/packages/create-app/index.js index d6ece3e3e98916..9447f52b76d1d9 100755 --- a/packages/create-app/index.js +++ b/packages/create-app/index.js @@ -127,64 +127,84 @@ const renameFiles = { async function init() { let targetDir = argv._[0] - const initialFrameworkIndex = FRAMEWORKS.findIndex(framework => [argv.t, argv.template].includes(framework.name)) - const defaultPackageName = !targetDir ? 'vite-project' : targetDir.trim() - .toLowerCase() - .replace(/\s+/g, '-') - .replace(/^[._]/, '') - .replace(/[^a-z0-9-~]+/g, '-') - let result = {}; + const initialFrameworkIndex = FRAMEWORKS.findIndex((framework) => + [argv.t, argv.template].includes(framework.name) + ) + const defaultPackageName = !targetDir + ? 'vite-project' + : targetDir + .trim() + .toLowerCase() + .replace(/\s+/g, '-') + .replace(/^[._]/, '') + .replace(/[^a-z0-9-~]+/g, '-') + let result = {} try { - result = await prompts([ + result = await prompts( + [ + { + type: 'text', + name: 'packageName', + message: 'Project name:', + initial: defaultPackageName, + validate: (dir) => + /^(?:@[a-z0-9-*~][a-z0-9-*._~]*\/)?[a-z0-9-~][a-z0-9-._~]*$/.test( + dir + ) || 'Invalid package.json name' + }, + { + type: (targetDir) => + !fs.existsSync(targetDir) || isEmpty(targetDir) ? null : 'confirm', + name: 'overwrite', + message: (targetDir) => + `Target directory ${targetDir} is not empty. Remove existing files and continue?`, + initial: false + }, + { + type: FRAMEWORKS.find((framework) => + [argv.t, argv.template].includes(framework.name) + ) + ? null + : 'select', + name: 'framework', + message: 'Select a framework:', + initial: initialFrameworkIndex > -1 ? initialFrameworkIndex : 0, + choices: FRAMEWORKS.map((framework) => { + const frameworkColor = framework.color + return { + title: frameworkColor(framework.name), + value: framework + } + }) + }, + { + type: (framework) => (framework.variants ? 'select' : null), + name: 'variant', + message: 'Select a variant:', + // @ts-ignore + choices: (framework) => + framework.variants.map((variant) => { + const variantColor = variant.color + return { + title: variantColor(variant.name), + value: variant.name + } + }) + } + ], { - type: 'text', - name: 'packageName', - message: 'Project name:', - initial: defaultPackageName, - validate: dir => /^(?:@[a-z0-9-*~][a-z0-9-*._~]*\/)?[a-z0-9-~][a-z0-9-._~]*$/.test(dir) || 'Invalid package.json name', - }, - { - type: targetDir => !fs.existsSync(targetDir) || isEmpty(targetDir) ? null : 'confirm', - name: 'overwrite', - message: targetDir => `Target directory ${targetDir} is not empty. Remove existing files and continue?`, - initial: false - }, - { - type: FRAMEWORKS.find(framework => [argv.t, argv.template].includes(framework.name)) ? null : 'select', - name: 'framework', - message: 'Select a framework:', - initial: initialFrameworkIndex > -1 ? initialFrameworkIndex : 0, - choices: FRAMEWORKS.map(framework => { - const frameworkColor = framework.color - return { - title: frameworkColor(framework.name), - value: framework - } - }) - }, - { - type: framework => framework.variants ? 'select' : null, - name: 'variant', - message: 'Select a variant:', - // @ts-ignore - choices: framework => framework.variants.map(variant => { - const variantColor = variant.color - return { - title: variantColor(variant.name), - value: variant.name - } - }) + onCancel: () => { + throw new Error(red('✖') + ' Operation cancelled') + } } - ], { onCancel: () => { - throw new Error(red('✖') + ' Operation cancelled') - }}) + ) } catch (cancelled) { console.log(cancelled.message) - return; + return } const packageName = result.packageName - const root = path.join(cwd, targetDir) + const root = path.join(cwd, packageName) if (result.overwrite) { emptyDir(root) From 342095a59a5abdee0f8c6789a02c43df322aa95c Mon Sep 17 00:00:00 2001 From: Olyno Date: Wed, 26 May 2021 01:41:29 +0200 Subject: [PATCH 07/14] fix(create-app): update correctly targetDir --- packages/create-app/index.js | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/packages/create-app/index.js b/packages/create-app/index.js index 9447f52b76d1d9..28238a803c2b51 100755 --- a/packages/create-app/index.js +++ b/packages/create-app/index.js @@ -150,10 +150,11 @@ async function init() { validate: (dir) => /^(?:@[a-z0-9-*~][a-z0-9-*._~]*\/)?[a-z0-9-~][a-z0-9-._~]*$/.test( dir - ) || 'Invalid package.json name' + ) || 'Invalid package.json name', + onState: (state) => (targetDir = targetDir || state.value) }, { - type: (targetDir) => + type: () => !fs.existsSync(targetDir) || isEmpty(targetDir) ? null : 'confirm', name: 'overwrite', message: (targetDir) => @@ -204,7 +205,7 @@ async function init() { } const packageName = result.packageName - const root = path.join(cwd, packageName) + const root = path.join(cwd, targetDir) if (result.overwrite) { emptyDir(root) From a312a5927a8686e1f93036c9a9d4bcd7dac7f8ab Mon Sep 17 00:00:00 2001 From: Anthony Fu Date: Sun, 30 May 2021 10:18:00 +0800 Subject: [PATCH 08/14] chore: update --- packages/create-app/index.js | 30 +----------------------------- 1 file changed, 1 insertion(+), 29 deletions(-) diff --git a/packages/create-app/index.js b/packages/create-app/index.js index 1aa1e07c15b0c3..e72c0b3aca7f3b 100755 --- a/packages/create-app/index.js +++ b/packages/create-app/index.js @@ -148,7 +148,7 @@ async function init() { message: 'Project name:', initial: defaultPackageName, validate: (dir) => - /^(?:@[a-z0-9-*~][a-z0-9-*._~]*\/)?[a-z0-9-~][a-z0-9-._~]*$/.test( + /^(?:@[a-z0-9*~][a-z0-9-*._~]*\/)?[a-z0-9~][a-z0-9-._~]*$/.test( dir ) || 'Invalid package.json name', onState: (state) => (targetDir = targetDir || state.value) @@ -262,34 +262,6 @@ function copy(src, dest) { } } -async function getValidPackageName(projectName) { - const packageNameRegExp = - /^(?:@[a-z0-9-*~][a-z0-9-*._~]*\/)?[a-z0-9-~][a-z0-9-._~]*$/ - if (packageNameRegExp.test(projectName)) { - return projectName - } else { - const suggestedPackageName = projectName - .trim() - .toLowerCase() - .replace(/\s+/g, '-') - .replace(/^[._]/, '') - .replace(/[^a-z0-9-~]+/g, '-') - - /** - * @type {{ inputPackageName: string }} - */ - const { inputPackageName } = await prompt({ - type: 'input', - name: 'inputPackageName', - message: `Package name:`, - initial: suggestedPackageName, - validate: (input) => - packageNameRegExp.test(input) ? true : 'Invalid package.json name' - }) - return inputPackageName - } -} - function copyDir(srcDir, destDir) { fs.mkdirSync(destDir, { recursive: true }) for (const file of fs.readdirSync(srcDir)) { From afcd85d858de0b153af6cbedcacdf052b8fecb9f Mon Sep 17 00:00:00 2001 From: Anthony Fu Date: Sun, 30 May 2021 10:56:20 +0800 Subject: [PATCH 09/14] chore: fix tests --- packages/create-app/__tests__/cli.spec.ts | 8 +++--- packages/create-app/index.js | 32 +++++++++++------------ 2 files changed, 20 insertions(+), 20 deletions(-) diff --git a/packages/create-app/__tests__/cli.spec.ts b/packages/create-app/__tests__/cli.spec.ts index a4cf2ce29454d2..885fad0fdfc2b4 100644 --- a/packages/create-app/__tests__/cli.spec.ts +++ b/packages/create-app/__tests__/cli.spec.ts @@ -47,20 +47,20 @@ test('prompts for the framework if none supplied', () => { test('prompts for the framework on supplying an invalid template', () => { const { stdout } = run([projectName, '--template', 'unknown']) expect(stdout).toContain( - `unknown isn't a valid template. Please choose from below:` + `"unknown" isn't a valid template. Please choose from below:` ) }) test('asks to overwrite non-empty target directory', () => { createNonEmptyDir() const { stdout } = run([projectName], { cwd: __dirname }) - expect(stdout).toContain(`Target directory ${projectName} is not empty.`) + expect(stdout).toContain(`Target directory "${projectName}" is not empty.`) }) test('asks to overwrite non-empty current directory', () => { createNonEmptyDir() - const { stdout } = run(['.'], { cwd: genPath, input: 'test-app\n' }) - expect(stdout).toContain(`Current directory is not empty.`) + const { stdout } = run([], { input: 'test-app\n', cwd: __dirname }) + expect(stdout).toContain(`Target directory "test-app" is not empty.`) }) test('successfully scaffolds a project based on vue starter template', () => { diff --git a/packages/create-app/index.js b/packages/create-app/index.js index e72c0b3aca7f3b..479cf6dd41fdf5 100755 --- a/packages/create-app/index.js +++ b/packages/create-app/index.js @@ -127,9 +127,8 @@ const renameFiles = { async function init() { let targetDir = argv._[0] - const initialFrameworkIndex = FRAMEWORKS.findIndex((framework) => - [argv.t, argv.template].includes(framework.name) - ) + let template = argv.template || argv.t + const defaultPackageName = !targetDir ? 'vite-project' : targetDir @@ -139,11 +138,12 @@ async function init() { .replace(/^[._]/, '') .replace(/[^a-z0-9-~]+/g, '-') let result = {} + try { result = await prompts( [ { - type: 'text', + type: targetDir ? null : 'text', name: 'packageName', message: 'Project name:', initial: defaultPackageName, @@ -151,25 +151,25 @@ async function init() { /^(?:@[a-z0-9*~][a-z0-9-*._~]*\/)?[a-z0-9~][a-z0-9-._~]*$/.test( dir ) || 'Invalid package.json name', - onState: (state) => (targetDir = targetDir || state.value) + onState: (state) => + (targetDir = state.value.trim() || defaultPackageName) }, { type: () => !fs.existsSync(targetDir) || isEmpty(targetDir) ? null : 'confirm', name: 'overwrite', - message: (targetDir) => - `Target directory ${targetDir} is not empty. Remove existing files and continue?`, + message: () => + `Target directory "${targetDir}" is not empty. Remove existing files and continue?`, initial: false }, { - type: FRAMEWORKS.find((framework) => - [argv.t, argv.template].includes(framework.name) - ) - ? null - : 'select', + type: template && TEMPLATES.includes(template) ? null : 'select', name: 'framework', - message: 'Select a framework:', - initial: initialFrameworkIndex > -1 ? initialFrameworkIndex : 0, + message: + template && !TEMPLATES.includes(template) + ? `"${template}" isn't a valid template. Please choose from below: ` + : 'Select a framework:', + initial: 0, choices: FRAMEWORKS.map((framework) => { const frameworkColor = framework.color return { @@ -179,7 +179,7 @@ async function init() { }) }, { - type: (framework) => (framework.variants ? 'select' : null), + type: (framework) => (framework?.variants ? 'select' : null), name: 'variant', message: 'Select a variant:', // @ts-ignore @@ -214,7 +214,7 @@ async function init() { } // determine template - const template = result.variant || result.framework + template = template || result.variant || result.framework console.log(`\nScaffolding project in ${root}...`) From ed5ef45d03cc7be212f9afa627534ca387c3b125 Mon Sep 17 00:00:00 2001 From: Anthony Fu Date: Sun, 30 May 2021 11:06:57 +0800 Subject: [PATCH 10/14] chore: fix --- packages/create-app/index.js | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/packages/create-app/index.js b/packages/create-app/index.js index 479cf6dd41fdf5..8b0a6a09203517 100755 --- a/packages/create-app/index.js +++ b/packages/create-app/index.js @@ -179,7 +179,8 @@ async function init() { }) }, { - type: (framework) => (framework?.variants ? 'select' : null), + type: (framework) => + framework && framework.variants ? 'select' : null, name: 'variant', message: 'Select a variant:', // @ts-ignore From ee8e0d94ba964b9e0ce57991f3f569299646a06c Mon Sep 17 00:00:00 2001 From: patak-js Date: Sun, 30 May 2021 14:07:34 +0200 Subject: [PATCH 11/14] fix: support non valid package name as target dir --- packages/create-app/index.js | 55 +++++++++++++++++++++++++----------- 1 file changed, 38 insertions(+), 17 deletions(-) diff --git a/packages/create-app/index.js b/packages/create-app/index.js index 8b0a6a09203517..768aeda4c9761f 100755 --- a/packages/create-app/index.js +++ b/packages/create-app/index.js @@ -129,14 +129,8 @@ async function init() { let targetDir = argv._[0] let template = argv.template || argv.t - const defaultPackageName = !targetDir - ? 'vite-project' - : targetDir - .trim() - .toLowerCase() - .replace(/\s+/g, '-') - .replace(/^[._]/, '') - .replace(/[^a-z0-9-~]+/g, '-') + const defaultProjectName = !targetDir ? 'vite-project' : targetDir + let result = {} try { @@ -144,23 +138,35 @@ async function init() { [ { type: targetDir ? null : 'text', - name: 'packageName', + name: 'projectName', message: 'Project name:', - initial: defaultPackageName, - validate: (dir) => - /^(?:@[a-z0-9*~][a-z0-9-*._~]*\/)?[a-z0-9~][a-z0-9-._~]*$/.test( - dir - ) || 'Invalid package.json name', + initial: defaultProjectName, onState: (state) => - (targetDir = state.value.trim() || defaultPackageName) + (targetDir = state.value.trim() || defaultProjectName) }, { type: () => !fs.existsSync(targetDir) || isEmpty(targetDir) ? null : 'confirm', name: 'overwrite', message: () => - `Target directory "${targetDir}" is not empty. Remove existing files and continue?`, - initial: false + (targetDir === '.' + ? 'Current directory' + : `Target directory ${targetDir}`) + + ` is not empty. Remove existing files and continue?`, + initial: false, + onState: (state) => { + if (!state.value) { + throw new Error(red('✖') + ' Operation cancelled') + } + } + }, + { + type: () => (isValidPackageName(targetDir) ? null : 'text'), + name: 'packageName', + message: 'Package name:', + initial: () => toValidPackageName(targetDir), + validate: (dir) => + isValidPackageName(dir) || 'Invalid package.json name' }, { type: template && TEMPLATES.includes(template) ? null : 'select', @@ -263,6 +269,21 @@ function copy(src, dest) { } } +function isValidPackageName(projectName) { + return /^(?:@[a-z0-9-*~][a-z0-9-*._~]*\/)?[a-z0-9-~][a-z0-9-._~]*$/.test( + projectName + ) +} + +function toValidPackageName(projectName) { + return projectName + .trim() + .toLowerCase() + .replace(/\s+/g, '-') + .replace(/^[._]/, '') + .replace(/[^a-z0-9-~]+/g, '-') +} + function copyDir(srcDir, destDir) { fs.mkdirSync(destDir, { recursive: true }) for (const file of fs.readdirSync(srcDir)) { From 0c72a4ba58794cb8051bfe31ba079028d64d064f Mon Sep 17 00:00:00 2001 From: patak-js Date: Sun, 30 May 2021 14:24:44 +0200 Subject: [PATCH 12/14] fix: tests --- packages/create-app/__tests__/cli.spec.ts | 4 ++-- packages/create-app/index.js | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/packages/create-app/__tests__/cli.spec.ts b/packages/create-app/__tests__/cli.spec.ts index 885fad0fdfc2b4..465b8d737bd8c7 100644 --- a/packages/create-app/__tests__/cli.spec.ts +++ b/packages/create-app/__tests__/cli.spec.ts @@ -59,8 +59,8 @@ test('asks to overwrite non-empty target directory', () => { test('asks to overwrite non-empty current directory', () => { createNonEmptyDir() - const { stdout } = run([], { input: 'test-app\n', cwd: __dirname }) - expect(stdout).toContain(`Target directory "test-app" is not empty.`) + const { stdout } = run(['.'], { cwd: genPath, input: 'test-app\n' }) + expect(stdout).toContain(`Current directory is not empty.`) }) test('successfully scaffolds a project based on vue starter template', () => { diff --git a/packages/create-app/index.js b/packages/create-app/index.js index 768aeda4c9761f..fb9864ff5778f8 100755 --- a/packages/create-app/index.js +++ b/packages/create-app/index.js @@ -151,12 +151,12 @@ async function init() { message: () => (targetDir === '.' ? 'Current directory' - : `Target directory ${targetDir}`) + + : `Target directory "${targetDir}"`) + ` is not empty. Remove existing files and continue?`, initial: false, onState: (state) => { if (!state.value) { - throw new Error(red('✖') + ' Operation cancelled') + // TODO: throw new Error(red('✖') + ' Operation cancelled') } } }, From 9ca337620789cde4edb4050fd13b4b0d32278d24 Mon Sep 17 00:00:00 2001 From: Olyno Date: Sun, 30 May 2021 16:20:25 +0200 Subject: [PATCH 13/14] feat: cancel prompt if not overwrite --- packages/create-app/index.js | 14 +++++++++----- 1 file changed, 9 insertions(+), 5 deletions(-) diff --git a/packages/create-app/index.js b/packages/create-app/index.js index fb9864ff5778f8..90aa13635f25ab 100755 --- a/packages/create-app/index.js +++ b/packages/create-app/index.js @@ -153,12 +153,16 @@ async function init() { ? 'Current directory' : `Target directory "${targetDir}"`) + ` is not empty. Remove existing files and continue?`, - initial: false, - onState: (state) => { - if (!state.value) { - // TODO: throw new Error(red('✖') + ' Operation cancelled') + initial: false + }, + { + type: (overwrite) => { + if (!overwrite) { + throw new Error(red('✖') + ' Operation cancelled') } - } + return null + }, + name: 'overwriteChecker' }, { type: () => (isValidPackageName(targetDir) ? null : 'text'), From c786f237a9b2cea0b968ffad305191f44d90cff6 Mon Sep 17 00:00:00 2001 From: Anthony Fu Date: Tue, 1 Jun 2021 00:31:43 +0800 Subject: [PATCH 14/14] chore: fix test --- packages/create-app/index.js | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/packages/create-app/index.js b/packages/create-app/index.js index 90aa13635f25ab..d8db468f51e91a 100755 --- a/packages/create-app/index.js +++ b/packages/create-app/index.js @@ -152,12 +152,11 @@ async function init() { (targetDir === '.' ? 'Current directory' : `Target directory "${targetDir}"`) + - ` is not empty. Remove existing files and continue?`, - initial: false + ` is not empty. Remove existing files and continue?` }, { - type: (overwrite) => { - if (!overwrite) { + type: (_, { overwrite } = {}) => { + if (overwrite == false) { throw new Error(red('✖') + ' Operation cancelled') } return null