entityAt function
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);
}