UNPKG

@yuanhua/cli

Version:
173 lines (152 loc) 4.77 kB
const chalk = require('chalk'); // https://www.helplib.com/GitHub/article_108070 const Metalsmith = require('metalsmith'); const Handlebars = require('handlebars'); const async = require('async'); const render = require('consolidate').handlebars.render; const path = require('path'); const multimatch = require('multimatch'); const getOptions = require('./options'); const ask = require('./ask'); const filter = require('./filter'); const logger = require('./logger'); // register handlebars helper Handlebars.registerHelper('if_eq', function(a, b, opts) { return a === b ? opts.fn(this) : opts.inverse(this); }); Handlebars.registerHelper('unless_eq', function(a, b, opts) { return a === b ? opts.inverse(this) : opts.fn(this); }); /** * Generate a template given a `src` and `dest`. * * @param {String} name * @param {String} src * @param {String} dest * @param {Function} done */ module.exports = function generate(name, src, dest, done) { // 处理npm名和作者信息 const opts = getOptions(name, src); // 1、 一个极其简单,易于使用的可以插入 static 站点发生器 const metalsmith = Metalsmith(path.join(src, 'template')); const data = Object.assign(metalsmith.metadata(), { destDirName: name, inPlace: dest === process.cwd(), noEscape: true, }); opts.helpers && Object.keys(opts.helpers).map(key => { Handlebars.registerHelper(key, opts.helpers[key]); }); const helpers = { chalk, logger }; if (opts.metalsmith && typeof opts.metalsmith.before === 'function') { opts.metalsmith.before(metalsmith, opts, helpers); } // 2、use metalsmith .use(askQuestions(opts.prompts) /* 将给定的plugin 函数添加到中间件堆栈*/) .use(filterFiles(opts.filters)) // 将给定的plugin 函数添加到中间件堆栈 .use(renderTemplateFiles(opts.skipInterpolation)); // 将给定的plugin 函数添加到中间件堆栈 if (typeof opts.metalsmith === 'function') { opts.metalsmith(metalsmith, opts, helpers); } else if (opts.metalsmith && typeof opts.metalsmith.after === 'function') { opts.metalsmith.after(metalsmith, opts, helpers); } metalsmith .clean(false) .source('.') // 模板文件 path // start from template root instead of `./src` which is Metalsmith's default for `source` .destination(dest) // 最终编译好的文件存放位置 .build((err, files) => { done(err); if (typeof opts.complete === 'function') { const helpers = { chalk, logger, files }; opts.complete(data, helpers); } else { logMessage(opts.completeMessage, data); } }); return data; }; /** * Create a middleware for asking questions. * * @param {Object} prompts * @return {Function} */ function askQuestions(prompts) { return (files, metalsmith, done) => { ask(prompts, metalsmith.metadata(), done); }; } /** * Create a middleware for filtering files. * * @param {Object} filters * @return {Function} */ function filterFiles(filters) { return (files, metalsmith, done) => { filter(files, filters, metalsmith.metadata(), done); }; } /** * Template in place plugin. * * @param {Object} files * @param {Metalsmith} metalsmith * @param {Function} done */ function renderTemplateFiles(skipInterpolation) { skipInterpolation = typeof skipInterpolation === 'string' ? [skipInterpolation] : skipInterpolation; return (files, metalsmith, done) => { const keys = Object.keys(files); const metalsmithMetadata = metalsmith.metadata(); async.each( keys, (file, next) => { // skipping files with skipInterpolation option if (skipInterpolation && multimatch([file], skipInterpolation, { dot: true }).length) { return next(); } const str = files[file].contents.toString(); // do not attempt to render files that do not have mustaches if (!/{{([^{}]+)}}/g.test(str)) { return next(); } render(str, metalsmithMetadata, (err, res) => { if (err) { err.message = `[${file}] ${err.message}`; return next(err); } files[file].contents = new Buffer(res); next(); }); }, done ); }; } /** * Display template complete message. * * @param {String} message * @param {Object} data */ function logMessage(message, data) { if (!message) return; render(message, data, (err, res) => { if (err) { console.error('\n Error when rendering template complete message: ' + err.message.trim()); } else { console.log( '\n' + res .split(/\r?\n/g) .map(line => ' ' + line) .join('\n') ); } }); }