rollup-plugin-dk
Version:
Seamless migration from es5 to es6 for `dk-fe` project
219 lines (184 loc) • 6.95 kB
JavaScript
;
function _interopDefault (ex) { return (ex && (typeof ex === 'object') && 'default' in ex) ? ex['default'] : ex; }
var fs = _interopDefault(require('fs'));
var path = _interopDefault(require('path'));
var R = _interopDefault(require('ramda'));
/* eslint-disable */
var transform = function (tmpl) {
function unescape(code) {
return code.replace(/\\('|\\)/g, "$1").replace(/[\r\t\n]/g, " ");
}
var c = {
func : /{{#\s*([\w$]+)\s*(\([^)]*\)|)\s*}}([\s\S]*?){{#}}/g,
evaluate: /\{\{([\s\S]+?(\}?)+)\}\}/g,
interpolate: /\{\{=([\s\S]+?)\}\}/g,
conditional: /\{\{\?(\?)?\s*([\s\S]*?)\s*\}\}/g,
transclude: /\{\{\-(\-)?\s*([\s\S]*?)\s*\}\}/g,
iterate: /\{\{~\s*(?:\}\}|([\s\S]+?)\s*\:\s*([\w$]+)\s*(?:\:\s*([\w$]+))?\s*\}\})/g,
};
var cse = {
start: "'+(",
end: ")+'"
}, sid = 0, indv;
// 只替换{{#func()}}{{#}}里面的内容
tmpl = tmpl.replace(c.func, function(m, def, args, str) {
// 转译特殊字符,在html拼接的时候出现语法错误
str = str.replace(/('|\\)/g, '\\$1');
// 干掉所有空白符, 通过连字符解决,保持文件格式
//str = str.replace(/(^|\r|\n)\t* +| +\t*(\r|\n|$)/g,"")
//.replace(/\r|\n|\t/g,"")
// 拼接方法名
str = "function " + def + (args || "()") + " {var out='" + str;
// 替换各种标志符
str = str
.replace(c.interpolate, function(m, code) {
return cse.start + unescape(code) + cse.end;
})
.replace(c.conditional, function(m, elsecase, code) {
return elsecase ?
(code ? "';}else if(" + unescape(code) + ") {out+='" : "';}else {out+='") :
(code ? "';if(" + unescape(code) + ") {out+='" : "';}out+='");
})
.replace(c.transclude, function(m, elsecase, code) {
function formatCode() {
if (!/\)$/.test(code)) {
// {{-page}}, 无argsBody
code = code + '(';
} else if (/\(\s*\)$/.test(code)) {
// {{-bem(page)()}}, 有body, 但是最后一个是空括号
code = code.substr(0, code.length - 1);
} else {
// {{-bem(page)(1)}}, 有body, 也有内容
code = code.substr(0, code.length - 1) + ',';
}
return code;
}
return elsecase ?
"';return out;})(), (function() {var out='';out+='":
(code ? "';out+=" + unescape(formatCode()) + "(function() {var out=''; out+='" : "';return out;})());out+='");
})
.replace(c.iterate, function(m, iterate, vname, iname) {
if (!iterate) return "';} } out+='";
sid+=1; indv=iname || "i"+sid; iterate=unescape(iterate);
return "';var arr"+sid+"="+iterate+";if(arr"+sid+") {var "+vname+","+indv+"=-1,l"+sid+"=arr"+sid+".length-1;while("+indv+"<l"+sid+") {"
+vname+"=arr"+sid+"["+indv+"+=1];out+='";
})
.replace(c.evaluate, function(m, code) {
// 因为此处是js, 所以需要将特殊字符转回来
return "';" + unescape(code) + "out+='";
})
.replace(/(\s|;|\}|^|\{)out\+='';/g, "$1").replace(/\+''/g, "");
// 拼接方法结尾
str = str + "';return out;}";
// 把所有字符串链接起来, 并且保持行数不变
str = str.replace(/(\r|\n|\r\n)/g, '\\\n');
return str;
});
return tmpl;
};
const includesReg = /include\s*\(\[([^\]]+)\]\)\s*;?/;
// 同时包含 exported注释 和 函数声明时,才认为需要 export
const exportedReg = /\/\*\s+(?:public|exported)\s+([$\w]+)\s+\*\//;
const declareReg = /(?:^function\s+([$\w]+)|^var\s+([$\w]+))/;
function nonNullFilter (item) {
return !!item
}
function readFile (filepath) {
// css 不解析
if (filepath.match(/\.css$/)) return null
// 转译模板
return transform(fs.readFileSync(filepath, 'utf8'))
}
function isEs6Code (cnt) {
return !!cnt.match(/import.*?from/) || !!cnt.match(/export.*?\{[^}]+\}/)
}
function hasInclude (cnt) {
return includesReg.test(cnt)
}
function needParse (cnt) {
// es6 module无需解析
// 但是es6 module 和 include 混用时要解析
if (isEs6Code(cnt) && !hasInclude(cnt)) {
return false
}
return true
}
function parseDeclared (m) {
// function | var
return m.match(declareReg)[1] || m.match(declareReg)[2]
}
function parseIncludes (dir, cnt) {
const match = cnt.match(includesReg);
if (!match) return []
return match[1].split(',').map(line => {
if (!line.trim()) {
return
}
return line.match(/\s*['"]([^'"]+)['"]\s*/)[1]
}).filter(nonNullFilter).map(filepath => path.normalize(dir + filepath))
}
function parseExports (cnt) {
if (!cnt || !needParse(cnt)) return null
let exports = R.compose(
R.uniq,
R.map(exported => exportedReg.exec(exported)[1]),
R.match(new RegExp(exportedReg, 'g'))
)(cnt);
if (exports.length) return exports
// 没有exported 函数时,将所有的函数都暴露
let fnMatchs = cnt.match(new RegExp(declareReg, 'mg'));
if (!fnMatchs) return null
return fnMatchs.map(parseDeclared)
}
function removeIncludes (cnt) {
return cnt.replace(/include\(\[[\s\S]+?\]\)\s*;\s*/, '')
}
function generateImports (dir, cnt, paths) {
let importCache = [];
return paths.map(filepath => {
let fromCnt = readFile(filepath);
let imports = parseExports(fromCnt);
if (!imports) return null
let declaredFns = R.compose(
R.map(parseDeclared),
R.match(new RegExp(declareReg, 'mg'))
)(cnt);
imports = R.compose(
// 排除已经import的函数
R.reject(importFn => R.contains(importFn, importCache)),
// 排除本文件声明过的函数
R.reject(importFn => R.contains(importFn, declaredFns))
)(imports);
importCache = R.concat(importCache, imports);
return `import { ${R.join(',', imports)} } from '${filepath}';`
}).filter(nonNullFilter).join('\n')
}
function generateExports (fns) {
if (!fns) return ''
return `export {\n ${fns.join(',\n ')}\n}`
}
function getCurrDir (path$$1) {
return path$$1.replace(/(.*\/)(.*)/, '$1')
}
var index = function () {
return {
name: 'dk',
load (id) {
let cnt = readFile(id);
if (!needParse(cnt)) {
return cnt
}
let currDir = getCurrDir(id);
let includePaths = R.compose(
R.reject(R.equals(id)),
R.uniq,
parseIncludes
)(currDir, cnt);
let exportedFns = parseExports(cnt);
let code = `${generateImports(currDir, cnt, includePaths)}\n${removeIncludes(cnt)}\n${generateExports(exportedFns)}\n`;
return code
}
}
};
module.exports = index;
//# sourceMappingURL=rollup-plugin-dk.cjs.js.map