apim-tools
Version:
APIM Tools
143 lines (121 loc) • 3.95 kB
JavaScript
/**
* @file etpl 模板渲染处理器
* @author wuhuiyao@baidu.com
*/
;
const fs = require('fs');
const pathUtil = require('path');
const etpl = require('etpl');
const isPlainObject = require('lodash.isplainobject');
/**
* 初始化过滤器
*
* @param {Object} engine 模板引擎
* @param {Object} filters 要初始化的过滤器
*/
function initFilters(engine, filters) {
if (!filters) {
return;
}
Object.keys(filters).forEach(name => {
let f = filters[name];
if (typeof f === 'function') {
engine.addFilter(name, f);
}
});
}
const DEFAULT_OPTIONS = {
tplDir: process.cwd(),
tplExtName: 'etpl',
encoding: 'utf-8',
engine: {
commandOpen: '{{',
commandClose: '}}',
variableOpen: '{%',
variableClose: '%}'
},
filters: {
/* eslint-disable fecs-camelcase */
json_encode: function (source) {
return JSON.stringify(source);
}
}
};
function loadAllTpls(engine, options) {
let glob = require('glob');
let templateDir = options.tplDir;
let tplExtName = options.tplExtName;
let files = glob.sync(`**/*${tplExtName}`, {
cwd: templateDir,
root: templateDir
});
let encoding = options.encoding;
files.forEach(file => {
file = pathUtil.resolve(templateDir, file);
engine.compile(fs.readFileSync(file, encoding).toString());
});
}
function loadTplFile(tplFile, options, context) {
tplFile = pathUtil.join(options.tplDir, tplFile);
try {
return fs.readFileSync(tplFile, options.encoding);
}
catch (ex) {
context.logger.error('load tpl file', tplFile, 'fail');
return false;
}
}
function createRenderEngine(options) {
let enginOptions = Object.assign({}, DEFAULT_OPTIONS.engine, options.engine);
const engine = new etpl.Engine(enginOptions);
let filterOptions = Object.assign({}, DEFAULT_OPTIONS.filters, options.filters);
initFilters(engine, filterOptions);
return engine;
}
module.exports = exports = function (mockData, options, context) {
const tplOptions = {
tplDir: options.tplDir || DEFAULT_OPTIONS.tplDir || options.baseDir,
tplExtName: options.tplExtName || DEFAULT_OPTIONS.tplExtName,
encoding: options.encoding || DEFAULT_OPTIONS.encoding
};
const engine = createRenderEngine(options);
return new Promise((resolve, reject) => {
if (!isPlainObject(mockData)) {
/* eslint-disable fecs-camelcase */
return resolve({_data: mockData});
}
let tplTarget = mockData._tplTarget;
let tplPath = mockData._tpl;
if (!tplTarget && tplPath) {
let tplContent = loadTplFile(tplPath, tplOptions, context);
if (tplContent === false) {
return reject(`load tpl ${tplPath} fail`);
}
let parseInfo = etpl.util.parseSource(tplContent, engine);
let targetNames = parseInfo.targets;
if (targetNames.length) {
tplTarget = targetNames[0];
}
}
if (!tplTarget) {
return reject('tpl target not specified in mock data');
}
try {
loadAllTpls(engine, tplOptions);
}
catch (ex) {
let errorInfo = `load tpl file fail: ${ex.toString()}`;
context.logger.error(errorInfo);
return reject(errorInfo);
}
let renderer = engine.getRenderer(tplTarget);
if (!renderer) {
return reject(`ETPL template target "${tplTarget}" not found`);
}
let tplData = context.normalizeMockData(mockData);
context.logger.debug('render etpl using data', tplData);
let result = renderer(tplData);
/* eslint-disable fecs-camelcase */
return resolve({_data: result});
});
};