UNPKG

zoro-cli

Version:

https://github.com/vuejs/vue-cli

171 lines (157 loc) 5.02 kB
const debug = require('zoro-cli-util/debug')('cli-generator') const debugVerbose = require('zoro-cli-util/debug')( 'cliverbose-generator-files' ) const { removeFiles, writeFiles } = require('zoro-cli-util/fs') const { log, startSpinner, stopSpinner } = require('zoro-cli-util/logger') const sortObject = require('zoro-cli-util/sortObject') const path = require('path') const fs = require('fs') const ejs = require('ejs') const GeneratorAPI = require('./GeneratorAPI') const Types = require('./types') class Generator { constructor({ context = process.cwd(), pkg = {}, files = {}, plugins = [], rootOptions = {}, args = {}, }) { this.context = context // this.originalPkg = Object.assign({}, pkg) this.pkg = pkg this.plugins = plugins this.rootOptions = rootOptions debug.key('rootOptions') debug(rootOptions) this.fileMiddlewares = [] this.files = files this.filesToRemove = [] this.pkgKeyOrder = [] this.scriptsKeyOrder = [] this.postProcessFilesCbs = [] this.completeCbs = [] this.args = args } async generate() { await this.applyPlugins() // wait for file resolve await this.resolveFiles() // write file tree to disk await this.writeFiles() // run complete cbs if any, for example lint log('⚓ Running completion hooks...') /* eslint-disable no-restricted-syntax, no-await-in-loop */ for (const cb of this.completeCbs) { await cb() } /* eslint-enable no-restricted-syntax, no-await-in-loop */ } async applyPlugins() { const { rootOptions, pkg, args } = this /* eslint-disable no-restricted-syntax, no-await-in-loop */ for (const { id, apply, options = {} } of this.plugins) { if (apply) { const api = new GeneratorAPI({ id, generator: this, options, rootOptions, pkg, }) await apply({ api, options, rootOptions, Types, pkg, args }) } } /* eslint-enable no-restricted-syntax, no-await-in-loop */ } async resolveFiles() { /* eslint-disable no-restricted-syntax, no-await-in-loop */ for (const { type, middleware } of this.fileMiddlewares) { if (type === 'add') { const files = await middleware({ render: ejs.render, files: this.files, }) Object.assign(this.files, files) } else if (type === 'remove') { if (Array.isArray(middleware)) { this.filesToRemove.push(...middleware) } else { this.filesToRemove.push(middleware) } } } for (const postProcess of this.postProcessFilesCbs) { await postProcess({ files: this.files }) } /* eslint-enable no-restricted-syntax, no-await-in-loop */ // set package.json this.sortPkg() this.files['package.json'] = JSON.stringify(this.pkg, null, 2) + '\n' debug.key('filenames') debug(Object.keys(this.files)) debugVerbose(this.files) } sortPkg() { // ensure package.json keys has readable order this.pkg.dependencies = sortObject(this.pkg.dependencies) this.pkg.devDependencies = sortObject(this.pkg.devDependencies) this.pkg.scripts = sortObject(this.pkg.scripts, this.scriptsKeyOrder, ':') this.pkg = sortObject(this.pkg, this.pkgKeyOrder) } async writeFiles() { startSpinner('generating files') const belongToFolder = (folder, filepath) => { // 如果是 . 文件, 那么要覆盖 const firstChar = path.basename(filepath).charAt(0) if (firstChar === '_' || firstChar === '.') return false // 特殊情况要覆盖 const specialCases = [ 'src/assets/template', 'src/style/layout/html-body.css', 'src/style/layout/html-body-mobile.css', ] const isSpecial = specialCases.some( sepcialCase => filepath.indexOf(sepcialCase) !== -1 ) if (isSpecial) return false // 属于要忽略的文件夹 return ( filepath.indexOf(folder) === 0 || filepath.indexOf(`./${folder}`) === 0 ) } /* eslint-disable no-restricted-syntax, no-await-in-loop */ // skip the following folders for (const folder of [ 'src', 'code', 'pages', 'components', 'common', 'tests', 'test', 'types', ]) { if (fs.existsSync(`./${folder}`)) { log() log(`skip override ${folder}`) this.filesToRemove = this.filesToRemove.filter( filepath => !belongToFolder(folder, filepath) ) Object.keys(this.files).forEach(filepath => { if (belongToFolder(folder, filepath)) { delete this.files[filepath] } }) } } /* eslint-enable no-restricted-syntax, no-await-in-loop */ await removeFiles(this.context, this.filesToRemove) await writeFiles(this.context, this.files) stopSpinner(false) log(`files generated to ${this.context}`) } } module.exports = Generator