@qodly/cli
Version:
Qodly CLI
207 lines (200 loc) ⢠8.06 kB
JavaScript
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