UNPKG

@qodly/cli

Version:

Qodly CLI

207 lines (200 loc) • 8.06 kB
import { execSync } from "node:child_process"; import { randomBytes } from "node:crypto"; import { existsSync, readFileSync, writeFileSync } from "node:fs"; import path, { resolve } from "node:path"; import chalk from "chalk"; import { libDir, libPkg as pkg } from "./pkg.js"; import { cacheTemplate, TemplateChooser } from "./TemplateChooser.js"; import versions from "../assets/qodly-versions.asset.js"; const TEMPLATES_PATH = resolve(libDir, 'templates'); function upperFirst(value) { return value.charAt(0).toUpperCase() + value.slice(1); } function camelCase(value) { return value.replace(/-./g, (x)=>x[1].toUpperCase()); } function toPOSIX(value) { return value.split(path.sep).join(path.posix.sep); } function resolveTemplatesPath(path, version) { const found = versions.find((v)=>v.version === version); if (found && found.templatesFolder) { return `${path}/${found.templatesFolder}`; } else { return `${path}/v1`; } } const chooseFolderName = { type: 'input', name: 'name', message: 'project name', validate: (value)=>{ if (!/^(?:(?:@(?:[a-z0-9-*~][a-z0-9-*._~]*)?\/[a-z0-9-._~])|[a-z0-9-~])[a-z0-9-._~]*$/.test(value)) return 'Name should be a valid npm package name. See https://docs.npmjs.com/cli/v10/configuring-npm/package-json#name for more info'; if (existsSync(value)) return 'Folder already exists'; return true; } }; export default function(plop) { plop.setGenerator('project', { description: 'Generate a new project', prompts: [ chooseFolderName, { type: 'list', name: 'version', message: 'Choose a version', choices: versions.map((v)=>({ name: v.version, value: v.version })) } ], actions: (data)=>{ const { name, version } = data; const projectTemplatesPath = `${resolveTemplatesPath(TEMPLATES_PATH, version)}/project`; return [ { type: 'addMany', verbose: false, base: toPOSIX(projectTemplatesPath), destination: toPOSIX(resolve(process.cwd(), '{{name}}')), templateFiles: toPOSIX(`${projectTemplatesPath}/**`), globOptions: { dot: true }, data: { app_id: `qodly_${randomBytes(10).toString('hex')}`, pkgName: pkg.name, pkgVersion: pkg.version } }, { type: 'add', templateFile: resolve(libDir, 'templates/_gitignore'), path: resolve(process.cwd(), '{{name}}/.gitignore') }, ()=>{ const found = versions.find((v)=>v.version === version); if (!found) return `āŒ Version ${version} not found`; const { packageJson = {} } = found; const oldJson = JSON.parse(readFileSync(resolve(process.cwd(), name, 'package.json'), 'utf-8')); const newJson = typeof packageJson === 'function' ? packageJson(oldJson) : { ...oldJson, ...packageJson }; writeFileSync(resolve(process.cwd(), name, 'package.json'), JSON.stringify(newJson, null, ' ')); return `āœ… Project dependencies updated`; }, ()=>{ const cwd = resolve(process.cwd(), name); [ 'git init', `git config --global --add safe.directory ${cwd}`, 'git add .', 'git commit -nm "Initial commit"' ].forEach((cmd)=>{ execSync(cmd, { cwd }); }); return ` āœ… All done! ${chalk.bold(chalk.gray(`# Go to the project's directory`))} ${chalk.green(`cd "${name}"`)} ${chalk.bold(chalk.gray(`# Install dependencies`))} ${chalk.green(`npm i`)} ${chalk.bold(chalk.gray('# Run the development server'))} ${chalk.green('npm run dev')} ${chalk.bold(chalk.gray('# Add a new component to your project'))} ${chalk.green('npm run generate:component')} ${chalk.bold(chalk.gray('# Build your components'))} ${chalk.green('npm run build')} ${chalk.cyan('Read more about Qodly: https://qodly.com')} ${chalk.cyan('šŸ’» Happy Deving!')}`; } ]; } }); plop.setGenerator('component', { description: 'Generate a new component', prompts: [ { type: 'input', name: 'name', message: 'component name please', transformer: (value)=>{ return upperFirst(camelCase(value)); }, validate: (value)=>{ const reservedNames = [ 'container', 'stylebox' ]; if (reservedNames.find((x)=>x === value.toLowerCase())) return 'Name is reserved. List of reserved names: ' + reservedNames.join(', '); if (!/^\w[\w-_]*$/.test(value)) return 'Name should only contain alphanumeric characters and underscores and start with a letter'; if (existsSync(`src/components/${value}`)) return 'Folder already exists'; return true; } } ], actions: (data)=>{ const { version } = data; const componentTemplatesPath = `${resolveTemplatesPath(TEMPLATES_PATH, version)}/component`; return [ { type: 'addMany', verbose: false, base: toPOSIX(componentTemplatesPath), destination: toPOSIX(resolve(process.cwd(), 'src/components/{{properCase name}}')), templateFiles: toPOSIX(`${componentTemplatesPath}/**`) }, { type: 'append', unique: true, path: resolve(process.cwd(), 'src/components/index.tsx'), pattern: /\/\/ imports/g, template: "import {{properCase name}} from './{{properCase name}}';" }, { type: 'append', unique: true, path: resolve(process.cwd(), 'src/components/index.tsx'), pattern: /\/\/ components/g, template: ' {{properCase name}},' } ]; } }); plop.setPrompt('chooseTemplate', TemplateChooser); plop.setGenerator('qodly-project', { description: 'Generate a new Qodly Project', prompts: [ chooseFolderName, { type: 'chooseTemplate', name: 'template', message: 'Choose a template' } ], actions: [ async (answers)=>{ await cacheTemplate(answers.template); return 'āœ… template cached successfully'; }, { type: 'addMany', verbose: false, base: toPOSIX(resolve(libDir, '.cache/{{template}}')), destination: toPOSIX(resolve(process.cwd(), '{{name}}')), templateFiles: toPOSIX(resolve(libDir, '.cache/{{template}}/**')), globOptions: { dot: true }, data: { uuid: randomBytes(16).toString('hex') } } ] }); } //# sourceMappingURL=plopfile.js.map