entityAt function

({int next, String value})? entityAt(
  1. String text,
  2. int i
)

The reference starting at the & at i, decoded, and the index just past its ; — or null when the text there is not a reference.

Implementation

({String value, int next})? entityAt(String text, int i) {
  final n = text.length;
  if (i >= n || text.codeUnitAt(i) != _amp) {
    return null;
  }
  var j = i + 1;
  if (j < n && text.codeUnitAt(j) == _hashUnit) {
    j += 1;
    final hex = j < n && (text.codeUnitAt(j) | 0x20) == 0x78; // x / X
    if (hex) {
      j += 1;
    }
    final start = j;
    final maxDigits = hex ? 6 : 7;
    while (j < n &&
        j - start < maxDigits &&
        _isDigit(text.codeUnitAt(j), hex)) {
      j += 1;
    }
    if (j == start || j >= n || text.codeUnitAt(j) != _semicolon) {
      return null;
    }
    var codePoint = int.parse(text.substring(start, j), radix: hex ? 16 : 10);
    // CommonMark: an invalid code point, and U+0000, become U+FFFD.
    if (codePoint == 0 ||
        codePoint > 0x10FFFF ||
        (codePoint >= 0xD800 && codePoint <= 0xDFFF)) {
      codePoint = 0xFFFD;
    }
    return (value: String.fromCharCode(codePoint), next: j + 1);
  }
  final start = j;
  while (j < n && j - start < 32 && _isAlphanumeric(text.codeUnitAt(j))) {
    j += 1;
  }
  if (j == start || j >= n || text.codeUnitAt(j) != _semicolon) {
    return null;
  }
  final value = _named[text.substring(start, j)];
  if (value == null) {
    return null;
  }
  return (value: value, next: j + 1);
}