UNPKG

@ginstone/nga-api

Version:

206 lines (205 loc) 7.66 kB
"use strict"; // 标签解析 Object.defineProperty(exports, "__esModule", { value: true }); exports.BbsTagParser = void 0; // 匹配连续[randomblock]的正则 const TagName_1 = require("./TagName"); const PatternFactory_1 = require("./PatternFactory"); const BbsTag_1 = require("./BbsTag"); const RANDOMBLOCK_PATTERN = /(\[randomblock].+?\[\/randomblock])+/g; // 匹配回复模板的正则 const REPLY_PATTERN = /(\[b]Reply to.+?\[\/b])/g; // 匹配不规范的td标签 const TD_PATTERN = /\[td(\d+)]/g; // 匹配不规范的td标签 const TD_PATTERN_2 = /\[td (.+?)]/g; // 匹配heading的不规范写法 const HEADING_PATTERN = /===(.*?)===/g; // li标签规范化 const LI_PATTERN_1 = /(<br\/>)*\[\*]/g; const LI_PATTERN_3 = /\[\/list]/g; const LI_PATTERN_4 = /\[list]/g; const LI_PATTERN_5 = /\[li]\[\/li]/g; class BbsTagParser { /** * 解析正文(总入口) * @param content 正文 */ static parseContent(content) { if (!content) { return new Array(); } content = this.preHandle(content); // console.log(content) return this.parseCode(content); } /** * 解析标签,将一段bbsCode解析为一个标签数组 * @param code 标签 */ static parseCode(code) { const res = new Array; if (!code) { return res; } let i = 0; // 逐个字符检查是否遇到了可识别的bbsCode // console.log(code) while (i < code.length) { // 如果当前位置不是 [ , 继续搜索 if (code.charAt(i) !== '[') { i++; continue; } // 裁剪code const prefixCode = code.substring(0, i); const suffixCode = code.substring(i); //当前位置是 [ , 尝试匹配标签名称 const tagName = TagName_1.TagNameUtils.matcher(suffixCode); if (tagName != null) { //标签名匹配成功 if (i > 0) { // 如果i大于0,把前方字符串作为文本加入 res.push(BbsTag_1.BbsTag.text(prefixCode)); } // 从后段代码中正确的位置截取代码范围 const subCode = this.getSubCode(suffixCode, tagName); if (subCode) { // 匹配成功 // 添加本段代码到列表 res.push(new BbsTag_1.BbsTag(tagName, subCode)); // 截断原代码段 code = suffixCode.substring(subCode.length); i = 0; } else { console.warn("截取失败:", tagName); console.warn("失败代码:", suffixCode); i++; } } else { i++; } } if (i > 0) { // 循环结束,i依然大于0,表示有剩余文字,添加一个文本节点 res.push(BbsTag_1.BbsTag.text(code)); } return res; } /** * 对本就会渲染为一行的标签,删除其首尾多余的br换行符 * @param content 正文 * @param tagName 标签名称 */ static removeBr(content, tagName) { const pattern = PatternFactory_1.PatternFactory.getPattern("(<br\\/*>)+\\[(\\/*)" + tagName + "]", 'g'); return content.replace(pattern, `[$2${tagName}]`); } /** * 从代码片段中截取指定标签名称的分段 * @param suffixCode 代码片段 * @param tagName 标签名称 */ static getSubCode(suffixCode, tagName) { let i = 0; const start = "[" + tagName; const end = "[/" + tagName + "]"; while (i < suffixCode.length) { // 尝试截取的片段 const endIndex = suffixCode.indexOf(end, i) + end.length; const s = suffixCode.substring(0, endIndex); // 如果截取范围内标签的起止标记数量相同,认为匹配 if (this.countMatches(s, start) == this.countMatches(s, end)) { return s; } if (endIndex > i) { i = endIndex; } else { return undefined; } } return undefined; } /** * 统计子字符串在母串中出现的次数 * @param s 母串 * @param search 子串 */ static countMatches(s, search) { let count = 0; let i; while ((i = s.indexOf(search)) > -1) { count++; s = s.substring(i + search.length); } return count; } /** * 正文的预处理 * @param content 正文 */ static preHandle(content) { // 替换不规范的 === { content = content.replace(HEADING_PATTERN, "[h]$1[/h]"); } // [*] 标签规范化 { content = content // 把所有 [*] 替换为 [/li][li] ,包括前面带/不带换行符的 .replace(LI_PATTERN_1, "[/li][li]") // 在 [/list] 前添加 [/li] .replace(LI_PATTERN_3, "[/li][/ul]") // 在 [list] 后添加 [li] .replace(LI_PATTERN_4, "[ul][li]") // 删除多余的空 li .replace(LI_PATTERN_5, ""); } // [randomblock] 标签规范化 { const replacement = new Array; let matcher; while (matcher = RANDOMBLOCK_PATTERN.exec(content)) { replacement.push(matcher[0]); } replacement.forEach(r => content = content.replace(r, `[${TagName_1.TagName.randomblocks}]${r}[/${TagName_1.TagName.randomblocks}]`)); } // 为预设的回复模板添加 quote { content = content.replace(REPLY_PATTERN, "[quote]$1[/quote]"); } //[u][b][i][r][l][h]规范化 { content = content.replace(/\[(\/*)u]/g, `[$1${TagName_1.TagName.underline}]`); content = content.replace(/\[(\/*)b]/g, `[$1${TagName_1.TagName.bold}]`); content = content.replace(/\[(\/*)i]/g, `[$1${TagName_1.TagName.italic}]`); content = content.replace(/\[(\/*)r]/g, `[$1${TagName_1.TagName.right}]`); content = content.replace(/\[(\/*)l]/g, `[$1${TagName_1.TagName.left}]`); content = content.replace(/\[(\/*)h]/g, `[$1${TagName_1.TagName.heading}]`); } //删除多余的空格 h list quote { content = this.removeBr(content, TagName_1.TagName.heading); content = this.removeBr(content, TagName_1.TagName.list); content = this.removeBr(content, TagName_1.TagName.quote); content = this.removeBr(content, TagName_1.TagName.randomblock); content = this.removeBr(content, TagName_1.TagName.tr); content = this.removeBr(content, TagName_1.TagName.td); content = this.removeBr(content, TagName_1.TagName.table); } // td 标签规范化 { content = content.replace(TD_PATTERN, "[td=width$1]"); content = content.replace(TD_PATTERN_2, "[td=$1]"); } // @标签规范化 { content = content.replace(/\[@(.+?)]/g, `[${TagName_1.TagName.at}=$1]$1[/${TagName_1.TagName.at}]`); } return content; } } exports.BbsTagParser = BbsTagParser;