From b9e5f2862e538f83ff3a1bf75e037dbfe5e70be3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marko=20Stanimirovi=C4=87?= Date: Thu, 18 Aug 2022 23:46:07 +0200 Subject: [PATCH] feat(create-analog): set start command based on package manager (#43) --- packages/create-analog/__tests__/cli.spec.ts | 2 +- packages/create-analog/index.js | 213 ++++++++++--------- 2 files changed, 108 insertions(+), 107 deletions(-) diff --git a/packages/create-analog/__tests__/cli.spec.ts b/packages/create-analog/__tests__/cli.spec.ts index aa72ee03f..20a23fe05 100644 --- a/packages/create-analog/__tests__/cli.spec.ts +++ b/packages/create-analog/__tests__/cli.spec.ts @@ -26,7 +26,7 @@ const createNonEmptyDir = () => { writeFileSync(pkgJson, '{ "foo": "bar" }'); }; -// Vue 3 starter template +// Angular 14 starter template let templateFiles = readdirSync(join(CLI_PATH, 'template-angular-v14')); templateFiles.push('.git'); // _gitignore is renamed to .gitignore diff --git a/packages/create-analog/index.js b/packages/create-analog/index.js index 72f04f8e4..03e13e4ed 100755 --- a/packages/create-analog/index.js +++ b/packages/create-analog/index.js @@ -1,27 +1,18 @@ #!/usr/bin/env node // @ts-check -import fs from 'node:fs' -import path from 'node:path' -import { fileURLToPath } from 'node:url' -import minimist from 'minimist' -import prompts from 'prompts' -import { - blue, - cyan, - green, - lightRed, - magenta, - red, - reset, - yellow -} from 'kolorist' -import { execSync } from 'node:child_process' +import fs from 'node:fs'; +import path from 'node:path'; +import { fileURLToPath } from 'node:url'; +import minimist from 'minimist'; +import prompts from 'prompts'; +import { red, reset, yellow } from 'kolorist'; +import { execSync } from 'node:child_process'; // Avoids autoconversion to number of the project name by defining that the args // non associated with an option ( _ ) needs to be parsed as a string. See #4606 -const argv = minimist(process.argv.slice(2), { string: ['_'] }) -const cwd = process.cwd() +const argv = minimist(process.argv.slice(2), { string: ['_'] }); +const cwd = process.cwd(); const APPS = [ { @@ -31,29 +22,29 @@ const APPS = [ { name: 'angular-v14', display: 'TypeScript', - color: yellow - } - ] - } -] + color: yellow, + }, + ], + }, +]; const TEMPLATES = APPS.map( (f) => (f.variants && f.variants.map((v) => v.name)) || [f.name] -).reduce((a, b) => a.concat(b), []) +).reduce((a, b) => a.concat(b), []); const renameFiles = { - _gitignore: '.gitignore' -} + _gitignore: '.gitignore', +}; async function init() { - let targetDir = formatTargetDir(argv._[0]) - let template = argv.template || argv.t + let targetDir = formatTargetDir(argv._[0]); + let template = argv.template || argv.t; - const defaultTargetDir = 'analog-project' + const defaultTargetDir = 'analog-project'; const getProjectName = () => - targetDir === '.' ? path.basename(path.resolve()) : targetDir + targetDir === '.' ? path.basename(path.resolve()) : targetDir; - let result = {} + let result = {}; try { result = await prompts( @@ -64,8 +55,8 @@ async function init() { message: reset('Project name:'), initial: defaultTargetDir, onState: (state) => { - targetDir = formatTargetDir(state.value) || defaultTargetDir - } + targetDir = formatTargetDir(state.value) || defaultTargetDir; + }, }, { type: () => @@ -75,16 +66,16 @@ async function init() { (targetDir === '.' ? 'Current directory' : `Target directory "${targetDir}"`) + - ` is not empty. Remove existing files and continue?` + ` is not empty. Remove existing files and continue?`, }, { type: (_, { overwrite } = {}) => { if (overwrite === false) { - throw new Error(red('✖') + ' Operation cancelled') + throw new Error(red('✖') + ' Operation cancelled'); } - return null + return null; }, - name: 'overwriteChecker' + name: 'overwriteChecker', }, { type: () => (isValidPackageName(getProjectName()) ? null : 'text'), @@ -92,7 +83,7 @@ async function init() { message: reset('Package name:'), initial: () => toValidPackageName(getProjectName()), validate: (dir) => - isValidPackageName(dir) || 'Invalid package.json name' + isValidPackageName(dir) || 'Invalid package.json name', }, { type: template && TEMPLATES.includes(template) ? null : 'select', @@ -105,12 +96,12 @@ async function init() { : reset('Select a template:'), initial: 0, choices: APPS.map((framework) => { - const frameworkColor = framework.color + const frameworkColor = framework.color; return { title: frameworkColor(framework.name), - value: framework - } - }) + value: framework, + }; + }), }, { type: (framework) => @@ -120,107 +111,101 @@ async function init() { // @ts-ignore choices: (framework) => framework.variants.map((variant) => { - const variantColor = variant.color + const variantColor = variant.color; return { title: variantColor(variant.name), - value: variant.name - } - }) - } + value: variant.name, + }; + }), + }, ], { onCancel: () => { - throw new Error(red('✖') + ' Operation cancelled') - } + throw new Error(red('✖') + ' Operation cancelled'); + }, } - ) + ); } catch (cancelled) { - console.log(cancelled.message) - return + console.log(cancelled.message); + return; } // user choice associated with prompts - const { framework, overwrite, packageName, variant } = result + const { framework, overwrite, packageName, variant } = result; - const root = path.join(cwd, targetDir) + const root = path.join(cwd, targetDir); if (overwrite) { - emptyDir(root) + emptyDir(root); } else if (!fs.existsSync(root)) { - fs.mkdirSync(root, { recursive: true }) + fs.mkdirSync(root, { recursive: true }); } // determine template - template = variant || framework || template + template = variant || framework || template; - console.log(`\nScaffolding project in ${root}...`) + console.log(`\nScaffolding project in ${root}...`); const templateDir = path.resolve( fileURLToPath(import.meta.url), '..', `template-${template}` - ) + ); const write = (file, content) => { const targetPath = renameFiles[file] ? path.join(root, renameFiles[file]) - : path.join(root, file) + : path.join(root, file); if (content) { - fs.writeFileSync(targetPath, content) + fs.writeFileSync(targetPath, content); } else { - copy(path.join(templateDir, file), targetPath) + copy(path.join(templateDir, file), targetPath); } - } + }; - const files = fs.readdirSync(templateDir) + const files = fs.readdirSync(templateDir); for (const file of files.filter((f) => f !== 'package.json')) { - write(file) + write(file); } + const pkgInfo = pkgFromUserAgent(process.env.npm_config_user_agent); + const pkgManager = pkgInfo ? pkgInfo.name : 'npm'; const pkg = JSON.parse( fs.readFileSync(path.join(templateDir, `package.json`), 'utf-8') - ) + ); - pkg.name = packageName || getProjectName() + pkg.name = packageName || getProjectName(); + pkg.scripts.start = getStartCommand(pkgManager); - write('package.json', JSON.stringify(pkg, null, 2)) + write('package.json', JSON.stringify(pkg, null, 2)); console.log(`\nInitializing git repository:`); - execSync(`git init ${targetDir} && cd ${targetDir} && git add . && git commit -m "initial commit"`); + execSync( + `git init ${targetDir} && cd ${targetDir} && git add . && git commit -m "initial commit"` + ); - const pkgInfo = pkgFromUserAgent(process.env.npm_config_user_agent) - const pkgManager = pkgInfo ? pkgInfo.name : 'npm' - - console.log(`\nDone. Now run:\n`) + console.log(`\nDone. Now run:\n`); if (root !== cwd) { - console.log(` cd ${path.relative(cwd, root)}`) - } - switch (pkgManager) { - case 'yarn': - console.log(' yarn') - console.log(' yarn dev') - break - default: - console.log(` ${pkgManager} install`) - console.log(` ${pkgManager} run dev`) - break + console.log(` cd ${path.relative(cwd, root)}`); } - console.log() + console.log(` ${getInstallCommand(pkgManager)}`); + console.log(` ${getStartCommand(pkgManager)}`); + console.log(); } /** * @param {string | undefined} targetDir */ function formatTargetDir(targetDir) { - return targetDir?.trim().replace(/\/+$/g, '') + return targetDir?.trim().replace(/\/+$/g, ''); } function copy(src, dest) { - const stat = fs.statSync(src) + const stat = fs.statSync(src); if (stat.isDirectory()) { - copyDir(src, dest) + copyDir(src, dest); } else { - fs.copyFileSync(src, dest) + fs.copyFileSync(src, dest); } } @@ -230,7 +215,7 @@ function copy(src, dest) { function isValidPackageName(projectName) { return /^(?:@[a-z0-9-*~][a-z0-9-*._~]*\/)?[a-z0-9-~][a-z0-9-._~]*$/.test( projectName - ) + ); } /** @@ -242,7 +227,7 @@ function toValidPackageName(projectName) { .toLowerCase() .replace(/\s+/g, '-') .replace(/^[._]/, '') - .replace(/[^a-z0-9-~]+/g, '-') + .replace(/[^a-z0-9-~]+/g, '-'); } /** @@ -250,11 +235,11 @@ function toValidPackageName(projectName) { * @param {string} destDir */ function copyDir(srcDir, destDir) { - fs.mkdirSync(destDir, { recursive: true }) + fs.mkdirSync(destDir, { recursive: true }); for (const file of fs.readdirSync(srcDir)) { - const srcFile = path.resolve(srcDir, file) - const destFile = path.resolve(destDir, file) - copy(srcFile, destFile) + const srcFile = path.resolve(srcDir, file); + const destFile = path.resolve(destDir, file); + copy(srcFile, destFile); } } @@ -262,8 +247,8 @@ function copyDir(srcDir, destDir) { * @param {string} path */ function isEmpty(path) { - const files = fs.readdirSync(path) - return files.length === 0 || (files.length === 1 && files[0] === '.git') + const files = fs.readdirSync(path); + return files.length === 0 || (files.length === 1 && files[0] === '.git'); } /** @@ -271,10 +256,10 @@ function isEmpty(path) { */ function emptyDir(dir) { if (!fs.existsSync(dir)) { - return + return; } for (const file of fs.readdirSync(dir)) { - fs.rmSync(path.resolve(dir, file), { recursive: true, force: true }) + fs.rmSync(path.resolve(dir, file), { recursive: true, force: true }); } } @@ -283,15 +268,31 @@ function emptyDir(dir) { * @returns object | undefined */ function pkgFromUserAgent(userAgent) { - if (!userAgent) return undefined - const pkgSpec = userAgent.split(' ')[0] - const pkgSpecArr = pkgSpec.split('/') + if (!userAgent) return undefined; + const pkgSpec = userAgent.split(' ')[0]; + const pkgSpecArr = pkgSpec.split('/'); return { name: pkgSpecArr[0], - version: pkgSpecArr[1] - } + version: pkgSpecArr[1], + }; +} + +/** + * @param {string} pkgManager + * @returns string + */ +function getInstallCommand(pkgManager) { + return pkgManager === 'yarn' ? 'yarn' : `${pkgManager} install`; +} + +/** + * @param {string} pkgManager + * @returns string + */ +function getStartCommand(pkgManager) { + return pkgManager === 'yarn' ? 'yarn dev' : `${pkgManager} run dev`; } init().catch((e) => { - console.error(e) -}) + console.error(e); +});