当前位置: 首页 > 工具软件 > Turndown > 使用案例 >

Turndown 源码解析:三、规则集

贺俊杰
2023-12-01

Rules

规则集包含一系列规则,其构造器通过传入的options配置对象获取规则列表并置于array字段中。

字段为:

  • options:配置项对象,就是用户传进来的那些
  • _keep:保留的规则列表
  • _remove:删除的规则列表
  • array:常规规则列表
  • blankRule:空白节点的规则
  • keepReplacement:保留节点的规则
  • defaultRule:默认规则
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.add()

在规则表前端插入指定规则,遍历的顺序是从前向后,所以新插入的规则会优先匹配。

  add: function (key, rule) {
    this.array.unshift(rule);
  },

Rules.keep()

在保留列表中插入指定的过滤器。

  keep: function (filter) {
    this._keep.unshift({
      filter: filter,
      replacement: this.keepReplacement
    });
  },

根据构造器,this.keepReplacement就是options.keepReplacement,然后再看看它:

    keepReplacement: function (content, node) {
      return node.isBlock ? '\n\n' + node.outerHTML + '\n\n' : node.outerHTML
    },

保留列表的作用就是,原封不动保留匹配元素的outerHTML

Rules.remove()

在移除列表中插入给定的过滤器。移除列表的作用就是保证某个元素被移除。

  remove: function (filter) {
    this._remove.unshift({
      filter: filter,
      replacement: function () {
        return ''
      }
    });
  },

Rules.forEach()

等价于this.array.forEach

  forEach: function (fn) {
    for (var i = 0; i < this.array.length; i++) fn(this.array[i], i);
  }

findRule()

遍历给定规则列表,使用每个规则匹配给定节点,如果匹配则返回当前规则,否则返回空值。

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
}

Rules.forNode()

寻找第一个匹配给定节点的规则。

顺序为:

  1. 首先通过node.isBlank判断节点是否为空白,是的话就返回空白节点规则。
  2. 依次在规则列表、保留列表、移除列表中匹配该节点,如果匹配成功返回匹配的规则
  3. 如果全部都不匹配,返回默认规则
  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
  },

其中空白节点的规则为不保留任何东西:

blankReplacement: function (content, node) {
      return node.isBlock ? '\n\n' : ''
    }

默认规则为只保留它的Markdown内容:

    defaultReplacement: function (content, node) {
      return node.isBlock ? '\n\n' + content + '\n\n' : content
    }

filterValue()

考虑三种不同类型的规则(stringstring[]function),判断给定规则是否匹配给定节点。

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')
  }
}
 类似资料: