UNPKG

@tuzki/cli

Version:

🐇 lowcode-cli is an efficient cli tool for Rabbitpre plugin component secondary development. ❤️

150 lines (149 loc) 6.15 kB
/* * 代码生成器 * * @Author: xu.jin * @Date: 2022-12-06 09:41:48 * * Copyright © 2014-2022 Rabbitpre.com. All Rights Reserved. */ import Logger from '@tuzki/scaffold-logger'; import ejs from 'ejs'; import fg from 'fast-glob'; import fse from 'fs-extra'; import lodash from 'lodash'; import path from 'path'; const logger = Logger.get('cli:utils:generator'); const { debounce } = lodash; const RENDER_WAIT = 150; export default class Generator { constructor(options) { this.setRenderData = (renderData) => { this.renderData = renderData; }; this.debounceRender = debounce(() => { this.render(); }, RENDER_WAIT); /** 添加模板目录文件 */ this.addTemplateFiles = (templateOptions, extraData = {}) => { const { template, targetDir } = typeof templateOptions === 'string' ? { template: templateOptions, targetDir: '' } : templateOptions; // 如果 template 不为文件,获取当前目录下所有文件 const templates = path.extname(template) ? [template] : fg.sync(['**/*'], { cwd: template, dot: true }); // 遍历 templates,调用 addRenderFile,渲染文件 templates.forEach((templateFile) => { const templatePath = path.isAbsolute(templateFile) ? templateFile : path.join(template, templateFile); const filePath = path.isAbsolute(templateFile) ? path.basename(templateFile) : templateFile; const targetPath = path.join(this.targetDir, targetDir, filePath); this.addRenderFile(templatePath, targetPath, extraData); }); if (this.rerender) { this.debounceRender(); } }; // 添加渲染文件 this.addRenderFile = (templatePath, targetPath, extraData = {}) => { const renderIndex = this.renderTemplates.findIndex(([, templateTarget]) => templateTarget === targetPath); // 添加 template 到 this.renderTemplates if (renderIndex > -1) { const targetTemplate = this.renderTemplates[renderIndex]; if (targetTemplate[0] !== templatePath) { logger.error('[template]', `path ${targetPath} already been rendered as file ${targetTemplate[0]}`); } // replace template with latest content this.renderTemplates[renderIndex] = [templatePath, targetPath, extraData]; } else { this.renderTemplates.push([templatePath, targetPath, extraData]); } // 执行 render 进行渲染 if (this.rerender) { this.debounceRender(); } }; // 合并 modifyRenderData 之后的数据之后,进行文件渲染 this.render = () => { this.rerender = true; const initialRendererData = Object.assign({}, this.renderData); // 调用 this.renderDataRegistration 处理生成最终渲染数据 this.renderData = this.renderDataRegistration.reduce((previousValue, currentValue) => { if (typeof currentValue === 'function') { return currentValue(previousValue); } return previousValue; }, initialRendererData); // 遍历 this.renderTemplates 渲染文件 this.renderTemplates.forEach(args => { this.renderFile(...args); }); }; // 修改渲染数据 this.modifyRenderData = registration => { this.renderDataRegistration.push(registration); if (this.rerender) { this.debounceRender(); } }; // 文件渲染生成 this.renderFile = (templatePath, targetPath, extraData = {}) => { const renderExt = '.ejs'; const realTargetPath = path.isAbsolute(targetPath) ? targetPath : path.join(this.rootDir, targetPath); const { ext } = path.parse(templatePath); // ejs 文件通过 ejs 方式渲染 if (ext === renderExt) { const templateContent = fse.readFileSync(templatePath, 'utf-8'); let renderData = Object.assign({}, this.renderData); if (typeof extraData === 'function') { renderData = extraData(this.renderData); } else { renderData = Object.assign(Object.assign({}, renderData), extraData); } const content = ejs.render(templateContent, renderData); const finalTargetPath = realTargetPath.replace(renderExt, ''); fse.ensureFileSync(finalTargetPath); fse.writeFileSync(finalTargetPath, content, 'utf-8'); } else { // 非 ejs 文件直接 copy 到目标文件夹 fse.ensureDirSync(path.dirname(realTargetPath)); fse.copyFileSync(templatePath, realTargetPath); } }; const { rootDir, targetDir = '', defaultRenderData = {}, templates, } = options; this.rootDir = rootDir; this.targetDir = targetDir; this.renderData = defaultRenderData; this.renderTemplates = []; this.renderDataRegistration = []; this.rerender = false; if (templates) { templates.forEach(template => this.addTemplateFiles(template)); } } } /** * 获取 generatorApi * * @export * @param {Options} args 参数 * @return {*} */ export function getGeneratorApi(args) { const generator = new Generator(args); return { addRenderFile: generator.addRenderFile, addRenderTemplate: generator.addTemplateFiles, modifyRenderData: generator.modifyRenderData, renderFile: generator.renderFile, render: generator.render, }; }