parse method

void parse(
  1. String source
)

Implementation

void parse(String source) {
  if (source.trim().isEmpty) return;
  final String cleaned = source.replaceAll(RegExp(r"/\*.*?\*/", dotAll: true), "");
  int index = 0;
  int guard = 0;
  while (index < cleaned.length && guard < 20000) {
    guard++;
    final int brace = cleaned.indexOf("{", index);
    if (brace < 0) break;
    final int end = cleaned.indexOf("}", brace);
    if (end < 0) break;
    final String selectorText = cleaned.substring(index, brace).trim();
    final String body = cleaned.substring(brace + 1, end);
    index = end + 1;
    if (selectorText.startsWith("@")) {
      if (selectorText.toLowerCase().startsWith("@font-face")) {
        final Map<String, String> declarations = _declarations(body);
        final String family = (declarations["font-family"] ?? "").replaceAll("\"", "").replaceAll("'", "").trim();
        if (family.isNotEmpty) fontFaces[family.toLowerCase()] = declarations;
      }
      continue;
    }
    final Map<String, String> declarations = _declarations(body);
    if (declarations.isEmpty) continue;
    for (final String selector in selectorText.split(",")) {
      final List<UEpubSelectorPart> parts = <UEpubSelectorPart>[];
      int specificity = 0;
      for (final String piece in selector.trim().split(RegExp(r"\s+"))) {
        if (piece.isEmpty || piece == ">" || piece == "+" || piece == "~") continue;
        final String withoutPseudo = piece.split(":").first;
        final RegExpMatch? match = RegExp(r"^([A-Za-z][A-Za-z0-9]*|\*)?(?:#([-\w]+))?(?:\.([-\w]+))?").firstMatch(withoutPseudo);
        if (match == null) continue;
        final String tag = (match.group(1) ?? "").toLowerCase();
        final String id = match.group(2) ?? "";
        final String className = match.group(3) ?? "";
        if (tag.isEmpty && id.isEmpty && className.isEmpty) continue;
        if (id.isNotEmpty) specificity += 100;
        if (className.isNotEmpty) specificity += 10;
        if (tag.isNotEmpty && tag != "*") specificity += 1;
        parts.add(UEpubSelectorPart(tag: tag, className: className, id: id));
      }
      if (parts.isEmpty) continue;
      rules.add(UEpubRule(parts, declarations, specificity));
    }
  }
}