UNPKG

hades-cli

Version:
204 lines (203 loc) 11.2 kB
"use strict"; Object.defineProperty(exports, "__esModule", { value: true }); exports.FileManager = void 0; const tsyringe_1 = require("tsyringe"); const state_service_1 = require("./../services/state.service"); const cypher_1 = require("./cypher"); const chalk = require("chalk"); const ejs = require("ejs"); const fs = require("fs"); const handlebars = require("handlebars"); const handlebarsHelpers = require("handlebars-helpers"); const path = require("path"); const _ = require("lodash"); require("./../prototypes/string-to-kebab-case.interface"); require("./../prototypes/string-to-kebab-case"); require("./../prototypes/string-to-snake-case.interface"); require("./../prototypes/string-to-snake-case"); require("./../prototypes/string-to-camel-case.interface"); require("./../prototypes/string-to-camel-case"); require("./../prototypes/string-to-pascal-case.interface"); require("./../prototypes/string-to-pascal-case"); require("./../handlebars/helpers/string-to-camel-case"); require("./../handlebars/helpers/string-to-kebab-case"); require("./../handlebars/helpers/string-to-pascal-case"); require("./../handlebars/helpers/string-to-snake-case"); require("./../handlebars/helpers/has-items"); require("./../handlebars/helpers/not-in-array"); require("./../handlebars/helpers/faker"); require("./../handlebars/helpers/faker-property"); require("./../handlebars/helpers/set-var"); require("./../handlebars/helpers/loops"); class FileManager { /** * Delete all origin files from directory recursively. * @param currentPath * @param skipDirectories */ static deleteOriginFiles(currentPath) { // read all files/folders (1 level) from template folder const files = fs.readdirSync(currentPath); // loop each file/folder files.forEach(async (file) => { const originFilePath = path.join(currentPath, file); // get stats about the current file const stats = fs.statSync(originFilePath); // skip files that should not be explorer if (FileManager.stateService.cliterConfig.skipDirectories.indexOf(file) > -1) return; if (stats.isFile() && (file.endsWith('.origin.ts') || file.endsWith('.origin.graphql'))) { fs.unlinkSync(path.join(currentPath, file)); } else if (stats.isDirectory()) { // copy files/folder inside current folder recursively FileManager.deleteOriginFiles(path.join(currentPath, file)); } }); } /** * Render templates with handlebars template engine. * @param content * @param data * @param opts */ static renderContent(content, data, opts) { const ejsRendered = ejs.render(content, data, opts); // add helpers to handlebars template engine handlebarsHelpers({ handlebars: handlebars }); return handlebars.compile(ejsRendered)(data, { allowProtoPropertiesByDefault: true, allowProtoMethodsByDefault: true, }); } /** * Render filename and folder name * @param name */ static renderFilename(name) { if (name.includes('__bounded_context_name__')) name = name.replace(/__bounded_context_name__/gi, FileManager.stateService.schema.boundedContextName.toKebabCase()); if (name.includes('__module_name__')) name = name.replace(/__module_name__/gi, FileManager.stateService.schema.moduleName.toKebabCase()); if (name.includes('__module_names__')) name = name.replace(/__module_names__/gi, FileManager.stateService.schema.moduleNames.toKebabCase()); if (name.includes('__property_name__') && FileManager.stateService.currentProperty) name = name.replace(/__property_name__/gi, FileManager.stateService.currentProperty.name.toKebabCase()); if (name.includes('__property_native_name__') && FileManager.stateService.currentProperty) name = name.replace(/__property_native_name__/gi, FileManager.stateService.currentProperty.nativeName.toKebabCase()); return name; } /** * Render all files and folders from template folder * @param currentPath * @param relativePath */ static generateContents(currentPath, relativePath, rootTemplatePath) { const projectDirectory = process.cwd(); const templatesPath = path.join(__dirname, '../..', 'templates'); // read all files/folders (1 level) from template folder const filesToCreate = fs.readdirSync(currentPath); // loop each file/folder filesToCreate.forEach(async (file) => { var _a, _b; const originFilePath = path.join(currentPath, file); // get stats about the current file const stats = fs.statSync(originFilePath); if (stats.isFile()) { // avoid overwriting some files that cannot be overwritten if (FileManager.stateService.flags.force && FileManager.stateService.cliterConfig.avoidOverwritingFilesIfExist.includes(currentPath.replace(templatesPath + '/', '') + '/' + file)) return; // check if file to create is excluded in schema. // schema may not exist if is a new project from master, when we have not yet created any bounded context or module if ((_b = (_a = FileManager.stateService.schema) === null || _a === void 0 ? void 0 : _a.excluded) === null || _b === void 0 ? void 0 : _b.includes(path.join(rootTemplatePath, relativePath, FileManager.renderFilename(file)))) { FileManager.stateService.command.log(`%s ${path.join(rootTemplatePath, relativePath, FileManager.renderFilename(file))} excluded`, chalk.yellow.inverse.bold('[EXCLUDED]')); return; } // generate file template FileManager.manageFileTemplate(originFilePath, file, path.join(rootTemplatePath, relativePath)); } else if (stats.isDirectory()) { const mappedDirectory = FileManager.renderFilename(file); if (fs.existsSync(path.join(projectDirectory, rootTemplatePath, relativePath, mappedDirectory))) { if (FileManager.stateService.flags.verbose) FileManager.stateService.command.log(`${chalk.yellow.bold('[DIRECTORY EXIST]')} Directory ${mappedDirectory} exist`); } else { // create folder in destination folder fs.mkdirSync(path.join(projectDirectory, rootTemplatePath, relativePath, mappedDirectory), { recursive: true }); FileManager.stateService.command.log(`${chalk.greenBright.bold('[DIRECTORY CREATED]')} Directory ${mappedDirectory} created`); } // copy files/folder inside current folder recursively this.generateContents(path.join(currentPath, file), path.join(relativePath, mappedDirectory), rootTemplatePath); } }); } /** * Create and render file template * @param originFilePath * @param file * @param relativeDirectoryPath * @param projectDirectory */ static manageFileTemplate(originFilePath, file, relativeDirectoryPath, projectDirectory = process.cwd()) { // read file content let contents = fs.readFileSync(originFilePath, 'utf8'); // replace variables with ejs template engine contents = FileManager.renderContent(contents, FileManager.stateService, { filename: originFilePath }); // render name of file const mappedFile = FileManager.renderFilename(file); // relative path to project for create/read file lock.json const relativeFilePath = path.join(relativeDirectoryPath, mappedFile); // write file to destination folder const writePath = path.join(projectDirectory, relativeFilePath); // check if file exists const existFile = fs.existsSync(writePath); if (existFile && !FileManager.stateService.flags.force) { FileManager.stateService.command.log(`%s ${mappedFile} exist`, chalk.yellow.bold('[INFO]')); } else { // check hash for overwrite if (existFile) { // find lockFile by path const currentLockfile = FileManager.stateService.lockFiles.find(lockFile => lockFile.path === relativeFilePath); const currentFile = fs.readFileSync(writePath, 'utf8'); const currentFileFirstLine = _.head(currentFile.split(/\r?\n/)); const currentFileFirstLineHash = currentFileFirstLine ? cypher_1.Cypher.sha1(currentFileFirstLine) : undefined; const currentFileHash = cypher_1.Cypher.sha1(currentFile); if (currentFileHash === FileManager.stateService.cliterConfig.fileTags.ignoredFile || currentFileFirstLineHash === FileManager.stateService.cliterConfig.fileTags.ignoredFile || currentFileHash === FileManager.stateService.cliterConfig.fileTags.ignoredGraphQLFile || currentFileFirstLineHash === FileManager.stateService.cliterConfig.fileTags.ignoredGraphQLFile) { FileManager.stateService.command.log(`%s ${mappedFile} ignored`, chalk.cyanBright.bold('[IGNORED FILE]')); } else if (!currentLockfile || currentLockfile.integrity === `sha1:${currentFileHash}`) { // the file has not been modified fs.writeFileSync(writePath, contents, 'utf8'); if (FileManager.stateService.flags.verbose) FileManager.stateService.command.log(`%s ${mappedFile} overwritten`, chalk.magenta.bold('[FILE OVERWRITE]')); } else { // the file has been modified and we create under .origin the file that would be created fs.writeFileSync(writePath.replace(/\.(?=[^.]*$)/, '.origin.'), contents, 'utf8'); const originFileName = mappedFile.replace(/\.(?=[^.]*$)/, '.origin.'); FileManager.stateService.originFiles.push(path.join(relativeDirectoryPath, originFileName)); FileManager.stateService.command.log(`%s ${originFileName} created`, chalk.redBright.bold('[ORIGIN FILE CREATED]')); } } else { fs.writeFileSync(writePath, contents, 'utf8'); FileManager.stateService.command.log(`%s ${mappedFile} created`, chalk.green.bold('[FILE CREATED]')); } // exclude e2e-spec.ts files from lock files if (!relativeFilePath.endsWith('.e2e-spec.ts')) { // add file to lockFiles FileManager.stateService.newLockFiles.push({ path: relativeFilePath, integrity: `sha1:${cypher_1.Cypher.sha1(contents)}` }); } } } } exports.FileManager = FileManager; FileManager.stateService = tsyringe_1.container.resolve(state_service_1.StateService);