create-esmx
Version:
A scaffold tool for creating Esmx projects
167 lines (161 loc) • 4.97 kB
JavaScript
import {
cancel,
intro,
isCancel,
note,
outro,
select,
text
} from "@clack/prompts";
import minimist from "minimist";
import color from "picocolors";
import { createProjectFromTemplate } from "./project.mjs";
import { getAvailableTemplates, getEsmxVersion } from "./template.mjs";
import { formatProjectName, getCommand } from "./utils/index.mjs";
function showHelp(userAgent) {
const createCmd = getCommand("create", userAgent);
console.log(`
${color.reset(color.bold(color.blue("\u{1F680} Create Esmx Project")))}
${color.bold("Usage:")}
${createCmd} [project-name]
${createCmd} [project-name] [options]
${color.bold("Options:")}
-t, --template <template> Template to use (default: vue2-csr)
-n, --name <name> Project name or path
-f, --force Force overwrite existing directory
-h, --help Show help information
-v, --version Show version number
${color.bold("Examples:")}
${createCmd} my-project
${createCmd} my-project -t vue2-csr
${createCmd} my-project --force
${createCmd} . -f -t vue2-csr
${color.bold("Available Templates:")}
${getAvailableTemplates().map((t) => ` ${t.folder.padEnd(25)} ${t.description}`).join("\n")}
For more information, visit: ${color.cyan("https://esmx.dev")}
`);
}
async function getProjectName(argName, positionalName) {
const providedName = argName || positionalName;
if (providedName) {
return providedName;
}
const projectName = await text({
message: "Project name or path:",
placeholder: "my-esmx-project",
validate: (value) => {
if (!value.trim()) {
return "Project name or path is required";
}
if (!/^[a-zA-Z0-9_./@-]+$/.test(value.trim())) {
return "Project name or path should only contain letters, numbers, hyphens, underscores, dots, and slashes";
}
}
});
return String(projectName).trim();
}
async function getTemplateType(argTemplate) {
const availableTemplates = getAvailableTemplates();
if (argTemplate && availableTemplates.some((t) => t.folder === argTemplate)) {
return argTemplate;
}
const options = availableTemplates.map((t) => ({
label: color.reset(color.gray(`${t.folder} - `) + color.bold(t.name)),
value: t.folder,
hint: t.description
}));
const template = await select({
message: "Select a template:",
options
});
return String(template);
}
export async function cli(options = {}) {
const { argv, cwd, userAgent, version } = options;
const commandLineArgs = argv || process.argv.slice(2);
const workingDir = cwd || process.cwd();
const parsedArgs = minimist(commandLineArgs, {
string: ["template", "name"],
boolean: ["help", "version", "force"],
alias: {
t: "template",
n: "name",
f: "force",
h: "help",
v: "version"
}
});
if (parsedArgs.help) {
showHelp(userAgent);
return;
}
if (parsedArgs.version) {
console.log(getEsmxVersion());
return;
}
console.log();
intro(
color.reset(
color.bold(color.blue("\u{1F680} Welcome to Esmx Project Creator!"))
)
);
const projectNameInput = await getProjectName(
parsedArgs.name,
parsedArgs._[0]
);
if (isCancel(projectNameInput)) {
cancel("Operation cancelled");
return;
}
let name;
let root;
if (parsedArgs.name && parsedArgs._[0]) {
name = parsedArgs.name;
root = formatProjectName(parsedArgs._[0], workingDir).root;
} else {
const result = formatProjectName(projectNameInput, workingDir);
name = result.name;
root = result.root;
}
const templateType = await getTemplateType(parsedArgs.template);
if (isCancel(templateType)) {
cancel("Operation cancelled");
return;
}
const installCommand = getCommand("install", userAgent);
const devCommand = getCommand("dev", userAgent);
const buildCommand = getCommand("build", userAgent);
const startCommand = getCommand("start", userAgent);
const buildTypeCommand = getCommand("build:type", userAgent);
const lintTypeCommand = getCommand("lint:type", userAgent);
await createProjectFromTemplate(
root,
templateType,
workingDir,
parsedArgs.force,
{
projectName: name,
esmxVersion: version || getEsmxVersion(),
installCommand,
devCommand,
buildCommand,
startCommand,
buildTypeCommand,
lintTypeCommand
}
);
const installCmd = installCommand;
const devCmd = devCommand;
const targetDirForDisplay = projectNameInput === "." ? "." : projectNameInput;
const steps = [
projectNameInput !== "." ? `cd ${targetDirForDisplay}` : null,
installCmd,
`git init ${color.gray("(optional)")}`,
devCmd
].filter(Boolean);
const nextSteps = steps.map((step, index) => {
return color.reset(`${index + 1}. ${color.cyan(step)}`);
});
note(nextSteps.join("\n"), "Next steps");
outro(color.reset(color.green("Happy coding! \u{1F389}")));
}