nornj
Version:
A powerful template engine that can works with React, JSX enhancement or alternative tools.
253 lines (224 loc) • 7.72 kB
text/typescript
import nj from '../core';
import * as tools from '../utils/tools';
import * as tranParam from '../transforms/transformParam';
import * as tranElem from '../transforms/transformElement';
const NO_SPLIT_NEWLINE = ['style', 'script', 'textarea', 'pre', 'xmp', 'template', 'noscript', nj.textTag];
function _plainTextNode(obj, parent, parentContent, noSplitNewline, tmplRule) {
const node: any = {};
node.type = 'nj_plaintext';
node.content = [
tranParam.compiledParam(
obj,
tmplRule,
null,
null,
parent.ex != null ? tranElem.exCompileConfig(parent.ex).isBindable : null
)
];
node.allowNewline = noSplitNewline;
parent[parentContent].push(node);
}
const REGEX_REPLACE_BP = /_njBp(\d+)_/g;
//检测元素节点
export function checkElem(obj, parent, tmplRule, hasExProps?, noSplitNewline?, isLast?) {
const parentContent = 'content';
if (!tools.isArray(obj)) {
//判断是否为文本节点
if (tools.isString(obj)) {
if (!noSplitNewline) {
const braceParams = [];
const strs = obj
.replace(tmplRule.braceParamG, match => {
braceParams.push(match);
return '_njBp' + (braceParams.length - 1) + '_';
})
.split(/\n/g);
strs.forEach((str, i) => {
str = str.trim();
str !== '' &&
_plainTextNode(
str.replace(REGEX_REPLACE_BP, (all, g1) => braceParams[g1]),
parent,
parentContent,
noSplitNewline,
tmplRule
);
});
} else {
_plainTextNode(
isLast && parent.allowNewline === 'nlElem' && !nj.textMode ? tools.trimRight(obj) : obj,
parent,
parentContent,
noSplitNewline,
tmplRule
);
}
} else {
_plainTextNode(obj, parent, parentContent, noSplitNewline, tmplRule);
}
return;
}
const node: any = {},
first = obj[0];
if (tools.isString(first)) {
//第一个子节点为字符串
const len = obj.length,
last = obj[len - 1];
let isElemNode = false,
exParams;
//判断是否为xml标签
let openTagName,
hasCloseTag = false,
isParamsEx,
isDirective,
isSubTag,
needAddToProps;
const ex = tranElem.isEx(first, tmplRule);
if (!ex) {
const xmlOpenTag = tranElem.getXmlOpenTag(first, tmplRule);
if (xmlOpenTag) {
//tagname为xml标签时,则认为是元素节点
openTagName = xmlOpenTag[1];
if (/\/$/.test(openTagName)) {
openTagName = openTagName.substr(0, openTagName.length - 1);
}
if (!tranElem.isXmlSelfCloseTag(first)) {
//非自闭合标签才验证是否存在关闭标签
hasCloseTag = tranElem.isXmlCloseTag(last, openTagName);
} else {
//自闭合标签
node.selfCloseTag = true;
}
isElemNode = true;
}
} else {
//为扩展标签,也可视为一个元素节点
const exName = ex[0];
exParams = ex[1];
isParamsEx = tranElem.isParamsEx(exName);
if (!isParamsEx) {
const exConfig = tranElem.exCompileConfig(exName);
isDirective = exConfig.isDirective;
isSubTag = exConfig.isSubTag;
needAddToProps = isDirective ? !hasExProps : isSubTag;
if (exConfig.useString) {
node.useString = exConfig.useString;
}
}
node.type = 'nj_ex';
node.ex = exName;
if (exParams != null && !isParamsEx) {
if (!node.args) {
node.args = [];
}
tools.each(
exParams,
param => {
const { key, value } = param;
if (key === 'useString') {
node.useString = !(value === 'false');
return;
} else if (key === '_njIsDirective') {
node.isDirective = isDirective = true;
needAddToProps = !hasExProps;
return;
}
const paramV = tranParam.compiledParam(value, tmplRule, param.hasColon, param.onlyKey);
if (param.onlyBrace) {
//提取匿名参数
node.args.push(paramV);
} else {
if (!node.params) {
node.params = tools.obj();
}
node.params[key] = paramV;
}
},
true
);
}
isElemNode = true;
}
if (isElemNode) {
//判断是否为元素节点
let pushContent = true;
if (noSplitNewline) {
node.allowNewline = true;
}
if (!ex) {
node.type = openTagName;
//If open tag has a brace,add the typeRefer param.
const typeRefer = tranElem.getInsideBraceParam(openTagName, tmplRule);
if (typeRefer) {
node.typeRefer = tranParam.compiledParam(typeRefer[0], tmplRule);
}
//获取openTag内参数
const tagParams = tranElem.getOpenTagParams(first, tmplRule);
if (tagParams) {
if (!node.params) {
node.params = tools.obj();
}
tools.each(
tagParams,
param => {
//The parameter like "{prop}" needs to be replaced.
node.params[
param.onlyBrace ? param.onlyBrace.replace(/\.\.\//g, '') : param.key
] = tranParam.compiledParam(param.value, tmplRule, param.hasColon, param.onlyKey);
},
true
);
}
//Verify if self closing tag again, because the tag may be similar to "<br></br>".
if (!node.selfCloseTag) {
node.selfCloseTag = tranElem.verifySelfCloseTag(openTagName);
}
if (noSplitNewline == null && NO_SPLIT_NEWLINE.indexOf(openTagName.toLowerCase()) > -1) {
noSplitNewline = true;
node.allowNewline = 'nlElem';
}
} else {
if (isParamsEx || needAddToProps) {
pushContent = false;
}
if (noSplitNewline == null && node.ex === 'pre') {
noSplitNewline = true;
node.allowNewline = 'nlElem';
}
}
//放入父节点content内
if (pushContent) {
parent[parentContent].push(node);
}
//取出子节点集合
const end = len - (hasCloseTag ? 1 : 0),
content = obj.slice(1, end);
if (content && content.length) {
_checkContentElem(content, node, tmplRule, isParamsEx || (hasExProps && !isDirective), noSplitNewline);
}
//If this is params block, set on the "paramsEx" property of the parent node.
if (isParamsEx || needAddToProps) {
tranElem.addParamsEx(node, parent, isDirective, isSubTag);
}
} else {
//如果不是元素节点,则为节点集合
_checkContentElem(obj, parent, tmplRule, hasExProps, noSplitNewline);
}
} else if (tools.isArray(first)) {
//如果第一个子节点为数组,则该节点一定为节点集合(可以是多层数组嵌套的集合)
_checkContentElem(obj, parent, tmplRule, hasExProps, noSplitNewline);
}
}
//检测子元素节点
function _checkContentElem(obj, parent, tmplRule, hasExProps, noSplitNewline) {
if (!parent.content) {
parent.content = [];
}
tools.each(
obj,
(item, i, l) => {
checkElem(item, parent, tmplRule, hasExProps, noSplitNewline, i == l - 1);
},
true
);
}