/** * Manages a collection of rules used to convert HTML to Markdown */ export default function Rules (options) { // 配置 this.options = options // 保留规则列表 this._keep = [] // 移除规则列表 this._remove = [] // 空白规则 this.blankRule = { replacement: options.blankReplacement } // 保留规则 this.keepReplacement = options.keepReplacement // 默认规则 this.defaultRule = { replacement: options.defaultReplacement } // 初始化常规规则列表 this.array = [] for (var key in options.rules) this.array.push(options.rules[key]) } Rules.prototype = { add: function (key, rule) { // 在规则表前端插入指定规则, // 遍历的顺序是从前向后,所以新插入的规则会优先匹配。 this.array.unshift(rule) }, keep: function (filter) { // 在保留列表中插入指定的过滤器。 this._keep.unshift({ filter: filter, replacement: this.keepReplacement }) }, remove: function (filter) { // 在移除列表中插入指定的过滤器。 this._remove.unshift({ filter: filter, replacement: function () { return '' } }) }, forNode: function (node) { // 判断节点是否是空白,如果是的话返回空白规则 if (node.isBlank) return this.blankRule var rule // 依次在常规、保留、移除规则列表中寻找匹配节点的规则,如果成功就返回 if ((rule = findRule(this.array, node, this.options))) return rule if ((rule = findRule(this._keep, node, this.options))) return rule if ((rule = findRule(this._remove, node, this.options))) return rule // 都没找到就返回默认规则 return this.defaultRule }, // 等价于 this.array.forEach forEach: function (fn) { for (var i = 0; i < this.array.length; i++) fn(this.array[i], i) } } function findRule (rules, node, options) { // 遍历规则集的每个规则 for (var i = 0; i < rules.length; i++) { var rule = rules[i] // 将其与节点匹配,成功则返回当前规则 if (filterValue(rule, node, options)) return rule } // 否则返回空值 return void 0 } function filterValue (rule, node, options) { var filter = rule.filter if (typeof filter === 'string') { // 如果过滤器是字符串,判断是否和节点名称一致 if (filter === node.nodeName.toLowerCase()) return true } else if (Array.isArray(filter)) { // 如果过滤器是数组,查看是否包含节点名称 if (filter.indexOf(node.nodeName.toLowerCase()) > -1) return true } else if (typeof filter === 'function') { // 如果过滤器是函数,在节点上调用它来得到匹配结果 if (filter.call(rule, node, options)) return true } else { // 否则抛出异常 throw new TypeError('`filter` needs to be a string, array, or function') } }