UNPKG

@practical/create

Version:

Practical CLI

172 lines (155 loc) 6.23 kB
#!/usr/bin/env node import inquirer from "inquirer"; import {exec} from 'child_process' import fs from 'fs' const isUuid = data => { return /^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/i.test(data.trim()); } const hasPackage = fs.existsSync("package.json"); const changePackageJsonName = name => { const packageJSON = name + '/package.json'; fs.readFile(packageJSON, 'utf8', function (err,data) { console.info("Setup package.json"); if (err) { return console.log(err); } const result = data.replace('@practical/base', name ); fs.writeFile(packageJSON, result, 'utf8', function (err) { if (err) return console.log(err); console.info("Practical Template"); }); }); } inquirer.prompt([ { name: 'license', type: 'input', message: 'Welcome to Practical! 🎉🥳🙌 \n –> Please enter your @practical License!', validate: async (input) => { if (!input) { return 'License is required'; } else if (!isUuid(input)) { return 'License format is not correct'; } return true; } }, { name: 'domain', type: 'input', message: 'Add your Project Domain (format: example.com)', validate: async (input) => { if (!input) { return 'Domain name is required'; } return true; } }, { name: 'presets', type: "checkbox", message: 'Choose your CMS Adapters!', default: ['yml'], choices: [ {name: 'YML - static data', value:'yml', short: 'YML'}, {name: 'Sanity Studio (sanity.io)', value:'sanity', short:'Sanity'}, {name: 'Storyblok Headless CMS (storyblok.com)', value:'storyblok', short:'Storyblok'}, {name: 'Wordpress Headless API', value:'wordpress', short:'Wordpress'}, ], validate: input => { if (!input.length) { return 'Please choose an adapter!';} return true; }, }, { name: 'projectName', type: 'input', message: 'Enter your Project name', validate: async (input) => { if (!input) { return 'Project name is required'; } /*** https://regexr.com/7qie6 */ const nameRegex = /^(@[a-z0-9-][a-z0-9-_]*\/)?[a-z0-9-][a-z0-9-_]*$/ if (!nameRegex.test(input)) { return "The name must be lowercase and one word, and may contain hyphens and underscores." } return true; } } ]).then((answers) => { /** create the .npmrc file */ const execPath = process.env.npm_execpath || ''; const isYarn = execPath.includes('yarn'); const isBun = execPath.includes('bun'); const configFile = isYarn ? '.yarnrc.yml' : (isBun ? 'bunfig.toml' : '.npmrc' ) const pkgRegistry = "practical-at.nodejs.pub" const yarnFile = `npmScopes: practical-at: npmRegistryServer: https://${pkgRegistry} npmAuthToken: ${answers.license.trim()}:${answers.domain} ` const npmrcFile = `@practical-at:registry=https://${pkgRegistry}/ //${pkgRegistry}/:_authToken=${answers.license.trim()}:${answers.domain} ` const bunfigToml = `[install.scopes] "@practical-at" = { token = "${answers.license.trim()}:${answers.domain}", url = "https://${pkgRegistry}/" }` const options = answers.presets.join(' '); const projectName = answers.projectName.trim(); const base = answers.presets.length === 1 ? 'base ': ''; const command = `${(!isYarn && !isBun) ? 'node' : ''} ${execPath ? `"${execPath}"`:''} ${isBun ? '' :'create'} @practical-at${isBun ? '/create' :''}@latest folder ${projectName} ${base + options} -y` const fileContents = isYarn ? yarnFile : ( isBun ? bunfigToml : npmrcFile); try { if (!fs.existsSync(projectName)) { fs.mkdirSync(projectName); } } catch (err) { console.error(err); } /* temp json file for windows */ !hasPackage && fs.writeFileSync('package.json', "{}"); fs.writeFile(configFile, fileContents, (err) => { if(err) {return console.error(err);} console.info("Get @practical Templates: \n", command); /** Get practical Templates via Package manager */ exec(command, (error, stdout, stderr) => { if (error) { if (stderr.includes('E422') || stderr.includes('Unprocessable Entity')) { console.error('❌ Unknown Licence. Please check if Project domain is correct and is paired with correct license.'); } else { console.error('❌ Error:', error.message); } } else { /** clean up */ fs.copyFileSync(configFile, projectName+"/"+configFile) !hasPackage && fs.rmSync("./package.json"); fs.rmSync(configFile); console.info(stdout? stdout : stderr); changePackageJsonName(projectName) console.info("@practical setup -- done") } }); }); }); // Graceful Exit Handler const gracefulExit = () => { console.log('\n'); console.log(' ┌─────────────────────────────────────┐'); console.log(' │ Thanks for using Practical! │'); console.log(' │ See you next time! 👋 │'); console.log(' └─────────────────────────────────────┘\n'); process.exit(0); }; // Handle CTRL+C gracefully process.on('SIGINT', gracefulExit); process.on('SIGTERM', gracefulExit); // Catch inquirer exit errors and handle them gracefully process.on('uncaughtException', (error) => { if (error.name === 'ExitPromptError' || error.message.includes('User force closed')) { gracefulExit(); } else { console.error('An unexpected error occurred:', error.message); process.exit(1); } });