返回

markdown-it源码分析5-ParserInline

前端

markdown-it源码分析5-ParserInline

我们从上一节得知,markdown-it先经过ParserCore的处理之后,会生成typeinlinetoken。接下来,我们就开始进入ParserInline解析器了。ParserInline的代码如下:

ParserInline.prototype.parse = function(str, start, end, loose) {
  var state = this.state
  var Pos = this.Pos
  var relStart = start + 1
  var pos = relStart
  var max = end
  var esc = 0
  var ch
  var match
  var len
  var fence = 0
  var bracket = 0
  var token

  if (this.options.disable.length) {
    loop: while (pos < max) {
      ch = str.charCodeAt(pos)

      for (var i = 0; i < this.options.disable.length; i++) {
        if (this.options.disable[i].test(String.fromCharCode(ch))) {
          pos++
          continue loop
        }
      }

      break
    }
  }

  while (pos < max) {
    ch = str.charCodeAt(pos)

    if (this.options.extensions && this.options.extensions.inline) {
      // extensions can add additional characters
      var hooks = this.options.extensions.inline.map(function (ext) {
        return ext.regex
      })

      var m = matchHook(str, hooks, pos, loose)
      if (m) {
        fence = 0
        match = m.match
        len = match[0].length

        pos += len
        ch = str.charCodeAt(pos)

        if (ch !== 0) {
          // fence/open-bracket/close-bracket
          if (ch === 126 || ch === 96 || ch === 42) {
            pos += len - 1
            continue
          }
          if (ch === 91) {
            bracket++
          } else if (ch === 93) {
            if (bracket) { bracket-- } else {
              pos += len - 1
              continue
            }
          }
          if (ch === 124) {
            token = state.push('text', '', 0)
            token.content = String.fromCharCode(ch)
            pos += 1
            continue
          }
        }

        if (!fence) {
          if (match.closeRe && match.closeRe.test(match.markup)) {
            len += match.closeRe.lastIndex - match.closeRe.exec(match.markup)[0].length
          }

          token = state.push(match.name, match.markup, len)
          token.plugin = m.plugin
          continue
        }

        if (ch === 96 || ch === 126) {
          pos += match.closeRe.lastIndex - match.closeRe.exec(match.markup)[0].length
          fence = 0
          continue
        }
      }
    }

    if (ch === 0) {
      break
    }

    if (ch === 96 && !esc) {
      fence = fence + 1
    } else if (ch === 92) {
      esc = esc + 1
    } else {
      esc = 0
    }

    if (fence > 0 || esc % 2 === 0) {
      pos++
    } else {
      break
    }
  }

  if (bracket && this.options.strict) {
    state.pending += '[';
    state.pending += str.slice(relStart, pos)
    state.pending += ']'
  }

  return relStart
};

在代码中,我们可以看到,ParserInline首先会判断是否需要跳过一些字符。接着,它会开始遍历字符串,处理行内元素。

当它遇到一个字符时,它会首先检查是否有扩展语法需要处理。如果有,则会调用扩展语法的正则表达式来匹配字符串。如果匹配成功,则会将匹配到的内容解析成一个token,并添加到state中。

如果字符串中没有扩展语法,则ParserInline会根据字符来判断是否需要解析成token。例如,如果字符是[,则会将其解析成一个linkimagetoken

最后,如果字符串中没有任何需要解析的字符,则ParserInline会将字符串添加到state.pending中。

总结

ParserInlinemarkdown-it解析器中处理行内元素的解析器。它可以解析各种各样的行内元素,包括链接、强调、代码块等。ParserInline的解析过程非常复杂,但它的工作原理并不难理解。