wakeb-starter-cli
Version:
A powerful CLI tool for generating CRUD modules, common modules, and components with Vue 3 form schemas, featuring intelligent field detection and automatic schema generation
194 lines (155 loc) ⢠5.73 kB
JavaScript
#!/usr/bin/env node
import fs from "fs";
import path from "path";
import inquirer from "inquirer";
import { fileURLToPath } from "url";
import parsePayloadFormat from "../utils/handlePayloadFormat.js";
import { copyFolderRecursiveSync } from "../utils/helper.js";
import updateRouter from "../utils/handleRouter.js";
import { updateSidebarLinks } from "../utils/updateSidebarLinks.js";
import {
generateSchemaFromPayload,
generateBasicSchema,
} from "../utils/schemaGenerator.js";
import { parseInputToObjects, extractNames } from "../utils/helper.js";
import { toCamelCase, toKebabCase, toSnakeCase } from "../utils/stringUtils.js";
const __filename = fileURLToPath(import.meta.url);
const __dirname = path.dirname(__filename);
const TEMPLATE_FOLDER = path.join(__dirname, "../../templates");
const TARGET_FOLDER = path.join(process.cwd(), "src", "modules");
export default async function createCrud() {
console.log("š Creating CRUD module...\n");
const { moduleName } = await inquirer.prompt({
name: "moduleName",
message: "Enter the module name (e.g., user, product):",
});
const modulePath = path.join(TARGET_FOLDER, moduleName);
let targetFolder = modulePath;
let crudName = moduleName;
let multipleCruds = false;
const moduleExists = fs.existsSync(modulePath);
if (moduleExists) {
const { hasMultiple } = await inquirer.prompt({
type: "confirm",
name: "hasMultiple",
message: `Module "${moduleName}" already exists. Do you want to add a new CRUD to it?`,
default: true,
});
multipleCruds = hasMultiple;
if (multipleCruds) {
const { newCrudName } = await inquirer.prompt({
name: "newCrudName",
message: "Enter the CRUD name (e.g., createInvoice, feature-groups):",
});
crudName = newCrudName;
targetFolder = modulePath;
} else {
crudName = "index";
targetFolder = modulePath;
}
} else {
const { hasMultiple } = await inquirer.prompt({
type: "confirm",
name: "hasMultiple",
message: "Does this module have multiple CRUDs?",
default: false,
});
multipleCruds = hasMultiple;
crudName = multipleCruds
? await inquirer
.prompt({ name: "newCrudName", message: "Enter the CRUD name:" })
.then((a) => a.newCrudName)
: "index";
targetFolder = modulePath;
}
const { layoutType } = await inquirer.prompt({
type: "list",
name: "layoutType",
message: "Choose layout type:",
choices: ["Modal", "Pages"],
});
const { helpModels } = await inquirer.prompt({
name: "helpModels",
message: "Enter help models (comma separated), or leave blank:",
});
const { helpEnums } = await inquirer.prompt({
name: "helpEnums",
message: "Enter help enums (comma separated), or leave blank:",
});
const helpModelsArray = parseInputToObjects(helpModels);
const helpEnumsArray = parseInputToObjects(helpEnums);
const { wantsSchema } = await inquirer.prompt({
type: "confirm",
name: "wantsSchema",
message: "Do you want to auto-generate a form schema from payload?",
default: false,
});
const schemaDir = path.join(targetFolder, "schema");
if (!fs.existsSync(schemaDir)) fs.mkdirSync(schemaDir, { recursive: true });
const crudCamel = toCamelCase(crudName);
const schemaPath = path.join(schemaDir, `${crudCamel}.js`);
if (wantsSchema) {
console.log(
"\nš Paste your payload (key:value) below. Press Enter twice or type 'END':\n"
);
const { payloadText } = await inquirer.prompt({
type: "editor",
name: "payloadText",
message: "Paste your payload:",
default: "",
});
const convertedPayload = parsePayloadFormat(payloadText);
const helpModelsNames = extractNames(helpModelsArray);
const helpEnumsNames = extractNames(helpEnumsArray);
const generatedSchemaCode = generateSchemaFromPayload(
convertedPayload,
crudCamel,
helpModelsNames,
helpEnumsNames
);
fs.writeFileSync(schemaPath, generatedSchemaCode, "utf8");
} else {
const basicSchemaCode = generateBasicSchema(crudCamel);
fs.writeFileSync(schemaPath, basicSchemaCode, "utf8");
}
const selectedTemplate = path.join(TEMPLATE_FOLDER, layoutType);
copyFolderRecursiveSync(
selectedTemplate,
targetFolder,
crudName,
helpModelsArray,
helpEnumsArray
);
updateRouter(modulePath, crudName);
console.log(`ā
Route "${crudName}" added successfully.`);
const { addSidebar } = await inquirer.prompt({
type: "confirm",
name: "addSidebar",
message: "Do you want to add this CRUD to sidebarLinks.js?",
default: true,
});
if (addSidebar) {
const { iconName } = await inquirer.prompt({
name: "iconName",
message:
"Enter icon name (without 'icons.'), e.g., 'dashboard' or 'users':",
});
const routePath = multipleCruds
? `/${toKebabCase(moduleName)}`
: `/${toKebabCase(moduleName)}`;
const crudPath = multipleCruds ? `/${toKebabCase(crudName)}` : null;
updateSidebarLinks({
moduleName: toKebabCase(moduleName),
moduleKey: `sidebar.${toSnakeCase(moduleName)}`,
iconName,
isMultiple: multipleCruds,
crudName: toKebabCase(crudName),
crudKey: `sidebar.${toSnakeCase(crudName)}`,
moduleRoute: routePath,
crudRoute: crudPath,
});
}
console.log(
`ā
CRUD "${crudName}" created successfully in module "${moduleName}" (${layoutType})`
);
}