onMatch method

  1. @override
bool onMatch(
  1. InlineParser parser,
  2. Match match
)
override

Processes match, adding nodes to parser and possibly advancing parser.

Returns whether the caller should advance parser by match[0].length.

Implementation

@override
bool onMatch(InlineParser parser, Match match) {
  var url = match[1]!;
  var href = url;
  var matchLength = url.length;

  if (url[0] == '>' || url.startsWith(regExpWhiteSpace)) {
    url = url.substring(1, url.length - 1);
    href = href.substring(1, href.length - 1);
    parser.pos++;
    matchLength--;
  }

  // Prevent accidental standard autolink matches
  if (url.endsWith('>') && parser.source![parser.pos - 1] == '<') {
    return false;
  }

  // When an autolink ends in ), we scan the entire autolink for the total
  // number of parentheses. If there is a greater number of closing
  // parentheses than opening ones, we don’t consider the last character
  // part of the autolink, in order to facilitate including an autolink
  // inside a parenthesis:
  // https://github.github.com/gfm/#example-600
  if (url.endsWith(')')) {
    final opening = _countChars(url, '(');
    final closing = _countChars(url, ')');

    if (closing > opening) {
      url = url.substring(0, url.length - 1);
      href = href.substring(0, href.length - 1);
      matchLength--;
    }
  }

  // Trailing punctuation (specifically, ?, !, ., ,, :, *, _, and ~) will
  // not be considered part of the autolink, though they may be included
  // in the interior of the link:
  // https://github.github.com/gfm/#example-599
  final trailingPunc = regExpTrailingPunc.firstMatch(url);
  if (trailingPunc != null) {
    var trailingLength = trailingPunc.match.length;
    url = url.substring(0, url.length - trailingLength);
    href = href.substring(0, href.length - trailingLength);
    matchLength -= trailingLength;
  }

  // If an autolink ends in a semicolon (;), we check to see if it appears
  // to resemble an
  // [entity reference](https://github.github.com/gfm/#entity-references);
  // if the preceding text is & followed by one or more alphanumeric
  // characters. If so, it is excluded from the autolink:
  // https://github.github.com/gfm/#example-602
  if (url.endsWith(';')) {
    final entityRef = regExpEndsWithColon.firstMatch(url);
    if (entityRef != null) {
      // Strip out HTML entity reference
      var entityRefLength = entityRef.match.length;
      url = url.substring(0, url.length - entityRefLength);
      href = href.substring(0, href.length - entityRefLength);
      matchLength -= entityRefLength;
    }
  }

  // The scheme http will be inserted automatically
  if (!href.startsWith('http://') &&
      !href.startsWith('https://') &&
      !href.startsWith('ftp://')) {
    href = 'http://$href';
  }

  final text = parser._encodeHtml ? escapeHtml(url) : url;
  final anchor = Element.text('a', text);
  anchor.attributes['href'] = Uri.encodeFull(href);
  parser.addNode(anchor);

  parser.consume(matchLength);
  return false;
}