UNPKG

create-bfe-cttq

Version:

CTTQ大前端脚手架项目

150 lines (147 loc) 4.92 kB
/** * 各插件交互式生成API接口 */ const fs = require('fs'); const path = require('path'); const ejs = require("ejs") const { isBinaryFileSync } = require('isbinaryfile'); const mergePackage = require("./util/mergePackage"); const { isFunction, isObject, isString} = require("./util/shared"); /** * 通过模版引擎重新渲染文件 * @param {*} name 文件路径名称 * @param {*} data 替换数据 * @returns 最新的文件信息 */ function renderFile(name, data = {}) { if (fs.lstatSync(name).isDirectory()) { return null; } if (isBinaryFileSync(name)) { return fs.readFileSync(name); } return ejs.render(fs.readFileSync(name, 'utf-8'), data); } module.exports = class GeneratorAPI { /** * 构造器 * @param {*} name 插件名称 * @param {*} generator 生成器 */ constructor(name, generator) { this._name = name; this._generator = generator; } /** * 插件名称 */ get name() { return this._name; } /** * 把文件渲染写入到项目中 * @param {*} source 来源文件:文件地址、模版库中的名称、渲染函数 * @param {*} opt 可选配置信息 */ render(source, opt = {}) { let options = { isTemplate: true, ...opt, } let data = { projectName: this._generator.answers.name, projectDescription: this._generator.answers.description, }; if (isString(source)) { this._injectFileMiddleware(async (files) => { const globby = require('globby'); let cwd = source; if (options.isTemplate) { cwd = this._generator.templateManager.pathAt(source); } const _files = await globby(['**/*'], { cwd: cwd, dot: true, onlyFiles: false, markDirectories: true }); for (const rawPath of _files) { const targetPath = rawPath.split('/').map(filename => { if (filename.charAt(0) === '_' && filename.charAt(1) !== '_') { return `.${filename.slice(1)}`; } if (filename.charAt(0) === '_' && filename.charAt(1) === '_') { return `${filename.slice(1)}`; } return filename; }).join('/'); const sourcePath = path.resolve(cwd, rawPath); const content = renderFile(sourcePath, data); files[targetPath] = content; } }); } else if (isObject(source)) { this._injectFileMiddleware(files => { for (const targetPath in source) { let sourcePath = source[targetPath]; if (options.isTemplate) { sourcePath = this._generator.templateManager.pathAt(sourcePath); } const content = renderFile(sourcePath, data); files[targetPath] = content; } }); } else if (isFunction(source)) { this._injectFileMiddleware(source); } } /** * 扩充合并package.json信息 * @param {*} fields pkg字段信息 * @param {*} opt 可选配置 */ extendPackage(fields, opt = {}) { let options = { isTemplate: true, ...opt, } if (isString(fields)) { let pkg = fields; if (options.isTemplate) { pkg = this._generator.templateManager.pathAt(fields); } if (fs.existsSync(pkg)) { fields = JSON.parse(fs.readFileSync(pkg, "utf-8") || "{}"); } else { fields = {}; } } const pkg = this._generator.pkg const toMerge = isFunction(fields) ? fields(pkg, this._generator.templateManager.rootPath) : fields; mergePackage(this.name, pkg, toMerge, this._generator.conflictDepSources, options); } /** * 注册事件:创建前 * @param {*} cb 回调函数 */ onBeforeCreate(cb) { this._generator.beforeCreateCallbacks.push(cb); } /** * 注册事件:创建后 * @param {*} cb 回调函数 */ onCreated(cb) { this._generator.createdCallbacks.push(cb); } /** * 获取在模版库中的地址 * @param {*} source 模版名称 * @returns 地址 */ templatePathAt(source) { return this._generator.templateManager.pathAt(source); } /** * 注入渲染文件的函数方法 * @param {*} middleware 中间件 */ _injectFileMiddleware(middleware){ this._generator.fileMiddlewares.push(middleware) } }