代码语言:javascript复制
/**
* 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')
}
}