parse static method

UEpubNode? parse(
  1. String source
)

Implementation

static UEpubNode? parse(String source) {
  if (source.trim().isEmpty) return null;
  final UEpubNode root = UEpubNode(tag: "#root");
  final List<UEpubNode> stack = <UEpubNode>[root];
  int index = 0;
  int guard = 0;
  while (index < source.length && guard < 2000000) {
    guard++;
    final int open = source.indexOf("<", index);
    if (open < 0) {
      _addText(stack.last, source.substring(index));
      break;
    }
    if (open > index) _addText(stack.last, source.substring(index, open));
    if (source.startsWith("<!--", open)) {
      final int end = source.indexOf("-->", open);
      index = end < 0 ? source.length : end + 3;
      continue;
    }
    if (source.startsWith("<![CDATA[", open)) {
      final int end = source.indexOf("]]>", open);
      final int stop = end < 0 ? source.length : end;
      _addText(stack.last, source.substring(open + 9, stop));
      index = end < 0 ? source.length : end + 3;
      continue;
    }
    if (source.startsWith("<!", open) || source.startsWith("<?", open)) {
      final int end = source.indexOf(">", open);
      index = end < 0 ? source.length : end + 1;
      continue;
    }
    final int close = _findTagEnd(source, open);
    if (close < 0) {
      _addText(stack.last, source.substring(open));
      break;
    }
    final String raw = source.substring(open + 1, close).trim();
    index = close + 1;
    if (raw.isEmpty) continue;
    if (raw.startsWith("/")) {
      final String name = _localName(raw.substring(1).trim());
      for (int i = stack.length - 1; i > 0; i--) {
        if (stack[i].tag == name) {
          stack.removeRange(i, stack.length);
          break;
        }
      }
      continue;
    }
    final bool selfClosing = raw.endsWith("/");
    final String body = selfClosing ? raw.substring(0, raw.length - 1) : raw;
    final int space = body.indexOf(RegExp(r"\s"));
    final String name = _localName(space < 0 ? body : body.substring(0, space));
    final Map<String, String> attributes = space < 0 ? <String, String>{} : _attributes(body.substring(space + 1));
    final UEpubNode node = UEpubNode(tag: name, attributes: attributes);
    node.parent = stack.last;
    stack.last.children.add(node);
    if (!selfClosing && !_void.contains(name)) stack.add(node);
    if (stack.length > 200) stack.removeRange(1, stack.length - 100);
  }
  return root;
}