@expressots/cli
Version:
Expressots CLI - modern, fast, lightweight nodejs web framework (@cli)
315 lines (314 loc) • 11.9 kB
JavaScript
;
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
if (k2 === undefined) k2 = k;
var desc = Object.getOwnPropertyDescriptor(m, k);
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
desc = { enumerable: true, get: function() { return m[k]; } };
}
Object.defineProperty(o, k2, desc);
}) : (function(o, m, k, k2) {
if (k2 === undefined) k2 = k;
o[k2] = m[k];
}));
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
Object.defineProperty(o, "default", { enumerable: true, value: v });
}) : function(o, v) {
o["default"] = v;
});
var __importStar = (this && this.__importStar) || function (mod) {
if (mod && mod.__esModule) return mod;
var result = {};
if (mod != null) for (var k in mod) if (k !== "default" && Object.prototype.hasOwnProperty.call(mod, k)) __createBinding(result, mod, k);
__setModuleDefault(result, mod);
return result;
};
var __importDefault = (this && this.__importDefault) || function (mod) {
return (mod && mod.__esModule) ? mod : { "default": mod };
};
Object.defineProperty(exports, "__esModule", { value: true });
exports.checkPathStyle = exports.extractFirstWord = exports.getNameWithScaffoldPattern = exports.schematicFolder = exports.writeTemplate = exports.getHttpMethod = exports.splitTarget = exports.getFileNameWithoutExtension = exports.validateAndPrepareFile = void 0;
const node_fs_1 = require("node:fs");
const nodePath = __importStar(require("node:path"));
const mustache_1 = require("mustache");
const string_utils_1 = require("./string-utils");
const cli_ui_1 = require("../../utils/cli-ui");
const verify_file_exists_1 = require("../../utils/verify-file-exists");
const compiler_1 = __importDefault(require("../../utils/compiler"));
/**
* Create a template based on the schematic
* @param fp
* @returns the file created
*/
async function validateAndPrepareFile(fp) {
const { sourceRoot, scaffoldSchematics, opinionated } = fp.expressoConfig;
if (sourceRoot === "") {
(0, cli_ui_1.printError)("You must specify a source root in your expressots.config.ts", "sourceRoot");
process.exit(1);
}
if (opinionated) {
const folderSchematic = (0, exports.schematicFolder)(fp.schematic);
const folderToScaffold = `${sourceRoot}/${folderSchematic}`;
const { path, file, className, moduleName, modulePath } = await (0, exports.splitTarget)({
target: fp.target,
schematic: fp.schematic,
});
const outputPath = `${folderToScaffold}/${path}/${file}`;
await (0, verify_file_exists_1.verifyIfFileExists)(outputPath, fp.schematic);
(0, node_fs_1.mkdirSync)(`${folderToScaffold}/${path}`, { recursive: true });
return {
path,
file,
className,
moduleName,
modulePath,
outputPath,
folderToScaffold,
fileName: getFileNameWithoutExtension(file),
schematic: fp.schematic,
};
}
const folderSchematic = "";
const folderToScaffold = `${sourceRoot}/${folderSchematic}`;
const { path, file, className, moduleName, modulePath } = await (0, exports.splitTarget)({
target: fp.target,
schematic: fp.schematic,
});
const fileBaseSchema = scaffoldSchematics?.[fp.schematic];
const validateFileSchema = fileBaseSchema !== undefined
? file.replace(fp.schematic, fileBaseSchema)
: file;
const outputPath = `${folderToScaffold}/${path}/${validateFileSchema}`;
await (0, verify_file_exists_1.verifyIfFileExists)(outputPath, fp.schematic);
(0, node_fs_1.mkdirSync)(`${folderToScaffold}/${path}`, { recursive: true });
return {
path,
file,
className,
moduleName,
modulePath,
outputPath,
folderToScaffold,
fileName: getFileNameWithoutExtension(file),
schematic: fileBaseSchema !== undefined ? fileBaseSchema : fp.schematic,
};
}
exports.validateAndPrepareFile = validateAndPrepareFile;
/**
* Get the file name without the extension
* @param filePath
* @returns the file name
*/
function getFileNameWithoutExtension(filePath) {
return filePath.split(".")[0];
}
exports.getFileNameWithoutExtension = getFileNameWithoutExtension;
/**
* Split the target into path, file, class name, module name and module path
* @param target
* @param schematic
* @returns the split target
*/
const splitTarget = async ({ target, schematic, }) => {
const pathContent = target
.split("/")
.filter((item) => item !== "");
const endsWithSlash = target.endsWith("/");
let path = "";
let fileName = "";
let module = "";
let modulePath = "";
if (target.includes("/") ||
target.includes("\\") ||
target.includes("//")) {
if (schematic === "service")
schematic = "controller";
if (schematic === "service" ||
(schematic === "controller" && pathContent.length > 4)) {
(0, cli_ui_1.printError)("Max path depth is 4.", pathContent.join("/"));
process.exit(1);
}
if (endsWithSlash) {
fileName = pathContent[pathContent.length - 1];
path = pathContent.join("/");
module =
pathContent.length == 1
? pathContent[pathContent.length - 1]
: pathContent[pathContent.length - 2];
modulePath = pathContent.slice(0, -1).join("/");
}
else {
fileName = pathContent[pathContent.length - 1];
path = pathContent.slice(0, -1).join("/");
module =
pathContent.length == 2
? pathContent[pathContent.length - 2]
: pathContent[pathContent.length - 3];
modulePath = pathContent.slice(0, -2).join("/");
}
return {
path,
file: `${await (0, exports.getNameWithScaffoldPattern)(fileName)}.${schematic}.ts`,
className: (0, string_utils_1.anyCaseToPascalCase)(fileName),
moduleName: module,
modulePath,
};
}
else {
if (schematic === "service")
schematic = "controller";
// 1. Extract the name (first part of the target)
const [name, ...remainingPath] = target.split("/");
// 2. Check if the name is camelCase or kebab-case
const camelCaseRegex = /[A-Z]/;
const kebabCaseRegex = /[_\-\s]+/;
const isCamelCase = camelCaseRegex.test(name);
const isKebabCase = kebabCaseRegex.test(name);
if (isCamelCase || isKebabCase) {
const [wordName, ...path] = name
? name
.split(isCamelCase ? /(?=[A-Z])/ : kebabCaseRegex)
.map((word) => word.toLowerCase())
: [];
return {
path: `${wordName}/${pathEdgeCase(path)}${pathEdgeCase(remainingPath)}`,
file: `${await (0, exports.getNameWithScaffoldPattern)(name)}.${schematic}.ts`,
className: (0, string_utils_1.anyCaseToPascalCase)(name),
moduleName: wordName,
modulePath: pathContent[0].split("-")[1],
};
}
// 3. Return the base case
return {
path: "",
file: `${await (0, exports.getNameWithScaffoldPattern)(name)}.${schematic}.ts`,
className: (0, string_utils_1.anyCaseToPascalCase)(name),
moduleName: name,
modulePath: "",
};
}
};
exports.splitTarget = splitTarget;
/**
* Write the template based on the http method
* @param method - the http method
* @returns decorator - the decorator to be used
*/
const getHttpMethod = (method) => {
switch (method) {
case "put":
return "Put";
case "post":
return "Post";
case "patch":
return "Patch";
case "delete":
return "Delete";
default:
return "Get";
}
};
exports.getHttpMethod = getHttpMethod;
/**
* Write the template based on the schematics
* @param outputPath - the output path
* @param template - the template to be used
* @returns void
*/
const writeTemplate = ({ outputPath, template: { path, data }, }) => {
(0, node_fs_1.writeFileSync)(outputPath, (0, mustache_1.render)((0, node_fs_1.readFileSync)(nodePath.join(__dirname, path), "utf8"), data));
};
exports.writeTemplate = writeTemplate;
/**
* Returns the folder where the schematic should be placed
* @param schematic
*/
const schematicFolder = (schematic) => {
switch (schematic) {
case "usecase":
return "useCases";
case "controller":
return "useCases";
case "dto":
return "useCases";
case "service":
return "useCases";
case "provider":
return "providers";
case "entity":
return "entities";
case "middleware":
return "providers/middlewares";
case "module":
return "useCases";
}
return undefined;
};
exports.schematicFolder = schematicFolder;
/**
* Get the name with the scaffold pattern
* @param name
* @returns the name in the scaffold pattern
*/
const getNameWithScaffoldPattern = async (name) => {
const configObject = await compiler_1.default.loadConfig();
switch (configObject.scaffoldPattern) {
case "lowercase" /* Pattern.LOWER_CASE */:
return (0, string_utils_1.anyCaseToLowerCase)(name);
case "kebab-case" /* Pattern.KEBAB_CASE */:
return (0, string_utils_1.anyCaseToKebabCase)(name);
case "PascalCase" /* Pattern.PASCAL_CASE */:
return (0, string_utils_1.anyCaseToPascalCase)(name);
case "camelCase" /* Pattern.CAMEL_CASE */:
return (0, string_utils_1.anyCaseToCamelCase)(name);
}
};
exports.getNameWithScaffoldPattern = getNameWithScaffoldPattern;
/**
* Get the path edge case
* @param path
* @returns the path edge case from the last element of the path
*/
const pathEdgeCase = (path) => {
return `${path.join("/")}${path.length > 0 ? "/" : ""}`;
};
/**
* Extract the first word from a file and convert it to the scaffold pattern
* @param file
* @returns the first word in the scaffold pattern
*/
async function extractFirstWord(file) {
const f = file.split(".")[0];
const regex = /(?:-|(?<=[a-z])(?=[A-Z]))/;
const firstWord = f.split(regex)[0];
const config = await compiler_1.default.loadConfig();
switch (config.scaffoldPattern) {
case "lowercase" /* Pattern.LOWER_CASE */:
return (0, string_utils_1.anyCaseToLowerCase)(firstWord);
case "kebab-case" /* Pattern.KEBAB_CASE */:
return (0, string_utils_1.anyCaseToKebabCase)(firstWord);
case "PascalCase" /* Pattern.PASCAL_CASE */:
return (0, string_utils_1.anyCaseToPascalCase)(firstWord);
case "camelCase" /* Pattern.CAMEL_CASE */:
return (0, string_utils_1.anyCaseToCamelCase)(firstWord);
}
}
exports.extractFirstWord = extractFirstWord;
/**
* Check if the path is a nested path, a single path or a sugar path
* @param path
* @returns the path style
*/
const checkPathStyle = (path) => {
const singleOrNestedPathRegex = /\/|\\/;
const sugarPathRegex = /^\w+-\w+$/;
if (singleOrNestedPathRegex.test(path)) {
return "nested" /* PathStyle.Nested */;
}
else if (sugarPathRegex.test(path)) {
return "sugar" /* PathStyle.Sugar */;
}
else {
return "single" /* PathStyle.Single */;
}
};
exports.checkPathStyle = checkPathStyle;