Ai
2 Star 5 Fork 0

String-for-100w/String

加入 Gitee
与超过 1200万 开发者一起发现、参与优秀开源项目,私有仓库也完全免费 :)
免费加入
文件
克隆/下载
render.js 11.54 KB
一键复制 编辑 原始数据 按行查看 历史
ashou 提交于 2020-09-12 09:46 +08:00 . 添加整体框架代码
const fs = require("fs");
const path = require("path");
const filterObj = require("../public/services/filter.js");
var EACH_START = /{{each/g,
EACH_END = /{{\/each}}/g,
IF_START = /{{if/g,
IF_END = /{{\/if}}/g,
ELSEIF = /{{elseif/g,
ELSE = /{{\s*else\s*}}/g;
function render(str, obj, isEach, isIf, target) {
var that = target || this;
obj = obj || {};
if (!isEach) str = filter(str, obj, EACH_START, EACH_END, renderEachType, 9, that);
if (!isIf) str = filter(str, obj, IF_START, IF_END, renderIfType, 7, that);
var newStr = str.replace(/{?{{\s*[a-zA-Z_$][\w$]*(\.[a-zA-Z_$][\w$]*)*\s*(\|\s*[a-zA-Z_$][\w$]*)*\s*}}}?/g, function (match) {
if (ELSE.test(match)) return match;
var isdecode = match.indexOf("{{{") > -1;
var len = isdecode ? 3 : 2;
return getProperty(obj, match.slice(len, -len).replace(/^\s+|\s+$/g, ""), that, !isdecode);
});
return newStr;
}
function getIndexList(str, pattern) {
var list = [],
matches = pattern.exec(str);
while (matches) {
list.push(matches.index);
matches = pattern.exec(str);
}
return list;
}
function getConditionStr(str, start, end, slen) {
var result = [],
s, e, strArray = [],
len = 0,
bIndex, eIndex,
startArray = getIndexList(str, start),
endArray = getIndexList(str, end);
if (startArray.length !== endArray.length) throw new Error("没有对应语句,请查看模板代码是否错误");
while (startArray.length > 0 || endArray.length > 0) {
s = typeof startArray[0] === "undefined" ? Infinity : startArray[0];
e = endArray[0] ? endArray[0] : 0;
if (s > e) {
result.push({
type: 0,
index: endArray[0] + slen
});
endArray.splice(0, 1);
} else {
result.push({
type: 1,
index: startArray[0]
});
startArray.splice(0, 1);
}
}
for (var i = 0; i < result.length; i++) {
var r = result[i];
if (r.type === 1) {
len++;
if (len === 1) bIndex = r.index;
} else {
len--;
if (len === 0) {
eIndex = r.index;
strArray.push({
str: str.slice(bIndex, eIndex),
start: bIndex,
end: eIndex
});
}
}
}
return strArray;
}
function splitConditionArray(str, list) {
if (list.length == 0) return [{
type: 0,
str: str
}];
var result = [];
if (list[0].start > 0) {
result.push({
type: 0,
str: str.slice(0, list[0].start)
});
}
var len = list.length;
for (var i = 0; i < len; i++) {
result.push({
type: 1,
str: str.slice(list[i].start, list[i].end)
});
if (list[i + 1] && list[i + 1].start > list[i].end) {
result.push({
type: 0,
str: str.slice(list[i].end, list[i + 1].start)
});
}
}
if (str.length > list[len - 1].end) result.push({
type: 0,
str: str.slice(list[len - 1].end, str.length)
});
return result;
}
function filter(str, obj, startStr, endStr, iterater, len, target) {
var result = getConditionStr(str, startStr, endStr, len);
var list = splitConditionArray(str, result);
var resultStr = list.map(function (strObj) {
return iterater(strObj, obj, target);
}).join("");
return resultStr;
}
function renderEachType(strObj, obj, target) {
if (strObj.type === 0) return render(strObj.str, obj, true, true, target);
else if (strObj.type === 1) {
var str = "";
var pattern = /^{{each\s+([^}]*?)}}([\s\S]*){{\/each}}$/;
var testArray = pattern.exec(strObj.str);
if (testArray) {
var sub = testArray[2];
if (testArray[1].indexOf("as") === -1) {
var left = getProperty(obj, testArray[1], target);
for (var i = 0; i < left.length; i++) {
var subObj = JSON.parse(JSON.stringify(obj)),
tempObj = left[i];
for (var key in tempObj) {
subObj[key] = tempObj[key];
}
subObj.index = i + 1;
str += render(sub, subObj, false, false, target);
}
} else {
var testPattern = /(\S+)\s+as\s+(\S+)/;
var tArray = testPattern.exec(testArray[1]);
var left = getProperty(obj, tArray[2], target),
name = tArray[1];
for (var i = 0; i < left.length; i++) {
var subObj = JSON.parse(JSON.stringify(obj)),
tempObj = left[i];
var tObj = subObj[name] = {};
for (var key in tempObj) {
tObj[key] = tempObj[key];
}
tObj.index = i + 1;
str += render(sub, subObj, false, false, target);
}
}
}
return str;
}
}
function getTestArray(str) {
var ifArray = getIndexList(str, IF_START),
elseifArray = getIndexList(str, ELSEIF),
elseArray = getIndexList(str, ELSE),
endArray = getIndexList(str, IF_END);
var result = [{
type: 0,
index: ifArray[0]
}],
i, index;
for (i = 0; i < elseifArray.length; i++) {
index = elseifArray[i];
var ifLen = 0,
j;
for (j = 0; j < ifArray.length; j++) {
if (index > ifArray[j]) ifLen++;
else break;
}
for (j = 0; j < endArray.length; j++) {
if (index > endArray[j]) ifLen--;
else break;
}
if (ifLen === 1) result.push({
type: 1,
index: index
});
}
for (i = 0; i < elseArray.length; i++) {
index = elseArray[i];
var elseLen = 0,
j;
for (j = 0; j < ifArray.length; j++) {
if (index > ifArray[j]) elseLen++;
else break;
}
for (j = 0; j < endArray.length; j++) {
if (index > endArray[j]) elseLen--;
else break;
}
if (elseLen === 1) result.push({
type: 2,
index: index
});
}
result = result.sort(function (prev, next) {
return prev.index - next.index;
});
var resultObj = {
conditions: [],
addition: {
content: ""
}
};
for (var i = 0; i < result.length; i++) {
var contentStr;
var current = result[i];
if (i < result.length - 1) contentStr = str.slice(result[i].index, result[i + 1].index);
else contentStr = str.slice(result[i].index);
if (current.type !== 2) {
var pattern = /{{(?:elseif|if)\s+([^}]*)}}/;
var testArray = pattern.exec(contentStr);
if (testArray) {
var startIndex = contentStr.indexOf(testArray[0]) + testArray[0].length;
var endIndex = contentStr.lastIndexOf("{{/if}}");
if (endIndex + "{{/if}}".length !== contentStr.length ||
(result[i + 1] && result[i + 1].type === 2)) endIndex = -1;
var content = endIndex === -1 ? contentStr.slice(startIndex) : contentStr.slice(startIndex, endIndex);
resultObj.conditions.push({
str: testArray[1],
content: content
});
}
} else {
var pattern = /{{else}}([\s\S]*?){{\/if}}$/;
var testArray = pattern.exec(contentStr);
if (testArray) {
resultObj.addition.content = testArray[1];
}
}
}
return resultObj;
}
function renderIfType(strObj, obj, target) {
if (strObj.type === 0) return render(strObj.str, obj, true, true, target);
else if (strObj.type === 1) {
var testObj = getTestArray(strObj.str);
for (var i = 0; i < testObj.conditions.length; i++) {
if (compute(obj, testObj.conditions[i].str, target)) {
return render(testObj.conditions[i].content, obj, true, false, target);
}
}
return render(testObj.addition.content, obj, true, false, target);
}
}
function compute(obj, str, target) {
var testExp = /([\s\S]*?)\s+(!=|==|>=|<=|>|<)\s+([\s\S]*)/;
var testArray = testExp.exec(str);
if (testArray) {
var left = testArray[1],
operation = testArray[2],
right = testArray[3];
var computeLeft = getProperty(obj, left, target);
if (operation && right) {
return compare[operation](computeLeft, right);
}
} else {
if (str.indexOf("!") === 0) return !getProperty(obj, str.slice(1), target);
return getProperty(obj, str, target)
}
}
function getProperty(obj, keyStr, target, isCode) {
var strArray = keyStr.split("|").map(function (item) {
return item.replace(/\s+/g, "");
})
var tempArray = strArray[0].split('.');
var property = obj[tempArray[0]],
i = 1,
len = tempArray.length;
while (len - i >= 1) {
property = property[tempArray[i]];
i++;
}
var filterStr = strArray[1];
if (filterStr) {
if (filterStr in filterObj) property = filterObj[filterStr](property);
}
if (isCode) {
property += "";
property = property.replace(/[<>"&]/g, function (match) {
return {
"<": "&lt;",
">": "&gt;",
'"': "&quot;",
"&": "&amp;"
} [match];
});
}
return property;
}
var compare = {
"==": function (left, right) {
return left == right;
},
"!=": function (left, right) {
return left != right;
},
">=": function (left, right) {
return left >= right;
},
"<=": function (left, right) {
return left <= right;
},
"<": function (left, right) {
return left < right;
},
">": function (left, right) {
return left > right;
}
};
var cache = {};
var indexPath, staticPath, dirName = __dirname;
function getHtml(path) {
if (cache[path]) return cache[path];
return new Promise((resolve, reject) => {
fs.readFile(path, {
encoding: "utf8"
}, (err, data) => {
if (err) throw new Error(err);
// cache[path] = data;
resolve(data);
})
})
}
module.exports = {
render: function (pagename, ap, obj) {
obj = obj || {};
return new Promise(async (resolve, reject) => {
let index = getHtml(path.join(dirName, indexPath)),
static = getHtml(path.join(dirName, staticPath)),
page = getHtml(path.join(dirName, ap));
let staticHtml = render(await static, {
page: await page,
text: pagename,
title: obj.title
}),
indexHtml = render(await index, {
body: staticHtml,
title: obj.title,
keyword: obj.keyword,
detail: obj.detail
});
resolve(indexHtml);
})
},
setDirName: function (dn) {
dirName = dn;
},
setLayout: function (lp) {
indexPath = lp;
},
setStatic: function (sp) {
staticPath = sp;
}
}
Loading...
马建仓 AI 助手
尝试更多
代码解读
代码找茬
代码优化
JavaScript
1
https://gitee.com/string-for-100w/string.git
git@gitee.com:string-for-100w/string.git
string-for-100w
string
String
master

搜索帮助