atrule method

Node atrule ()

A CSS AtRule, such as:

@charset "utf-8";

Implementation

Node atrule() {
  bool hasBlock = true;
  bool hasExpression = false;
  bool hasIdentifier = false;
  bool hasUnknown = false;
  final int index = parserInput.i;
  bool isRooted = true;
  String name;
  String nonVendorSpecificName;
  Ruleset rules;
  Node value;

  if (parserInput.currentChar() != '@') return null;

  value = import() ?? options() ?? plugin() ?? apply() ?? media();
  if (value != null) return value;

  parserInput.save();

  name = parserInput.$re(_directiveRegExp1);
  if (name == null) return null;

  nonVendorSpecificName = name;
  if (name[1] == '-' && name.indexOf('-', 2) > 0) {
    nonVendorSpecificName = '@${name.substring(name.indexOf("-", 2) + 1)}';
  }

  switch (nonVendorSpecificName) {
    case '@charset':
      hasIdentifier = true;
      hasBlock = false;
      break;
    case '@namespace':
      hasExpression = true;
      hasBlock = false;
      break;
    case '@keyframes':
    case '@counter-style':
      hasIdentifier = true;
      break;
    case '@document':
    case '@supports':
      hasUnknown = true;
      isRooted = false;
      break;
    default:
      hasUnknown = true;
      break;
  }

  parserInput.commentStore.length = 0;

  if (hasIdentifier) {
    value = entity();
    if (value == null) parserInput.error('expected $name identifier');
  } else if (hasExpression) {
    value = expression();
    if (value == null) parserInput.error('expected $name expression');
  } else if (hasUnknown) {
    value = permissiveValue(untilTokensRegExp: RegExp(r'[{;]')); // /^[{;]/
    hasBlock = parserInput.currentChar() == '{';
    if (value == null) {
      if (!hasBlock && parserInput.currentChar() != ';') {
        parserInput.error('$name rule is missing block or ending semi-colon');
      }
    } else if (value.value?.isEmpty ?? true) {
      value = null;
    }
  }

  if (hasBlock) rules = blockRuleset();

  if (rules != null ||
      (!hasBlock && value != null && parserInput.$char(';') != null)) {
    parserInput.forget();
    return AtRule(name, value,
        rules: rules,
        index: index,
        currentFileInfo: fileInfo,
        debugInfo:
            isNotEmpty(context.dumpLineNumbers) ? getDebugInfo(index) : null,
        isRooted: isRooted);
  }

  parserInput.restore('at-rule options not recognised');
  return null;

//3.0.4 20180622
//atrule: function () {
//    var index = parserInput.i, name, value, rules, nonVendorSpecificName,
//        hasIdentifier, hasExpression, hasUnknown, hasBlock = true, isRooted = true;
//
//    if (parserInput.currentChar() !== '@') { return; }
//
//    value = this['import']() || this.plugin() || this.media();
//    if (value) {
//        return value;
//    }
//
//    parserInput.save();
//
//    name = parserInput.$re(/^@[a-z-]+/);
//
//    if (!name) { return; }
//
//    nonVendorSpecificName = name;
//    if (name.charAt(1) == '-' && name.indexOf('-', 2) > 0) {
//        nonVendorSpecificName = "@" + name.slice(name.indexOf('-', 2) + 1);
//    }
//
//    switch (nonVendorSpecificName) {
//        case "@charset":
//            hasIdentifier = true;
//            hasBlock = false;
//            break;
//        case "@namespace":
//            hasExpression = true;
//            hasBlock = false;
//            break;
//        case "@keyframes":
//        case "@counter-style":
//            hasIdentifier = true;
//            break;
//        case "@document":
//        case "@supports":
//            hasUnknown = true;
//            isRooted = false;
//            break;
//        default:
//            hasUnknown = true;
//            break;
//    }
//
//    parserInput.commentStore.length = 0;
//
//    if (hasIdentifier) {
//        value = this.entity();
//        if (!value) {
//            error("expected " + name + " identifier");
//        }
//    } else if (hasExpression) {
//        value = this.expression();
//        if (!value) {
//            error("expected " + name + " expression");
//        }
//    } else if (hasUnknown) {
//        value = this.permissiveValue(/^[{;]/);
//        hasBlock = (parserInput.currentChar() === '{');
//        if (!value) {
//            if (!hasBlock && parserInput.currentChar() !== ';') {
//                error(name + " rule is missing block or ending semi-colon");
//            }
//        }
//        else if (!value.value) {
//            value = null;
//        }
//    }
//
//    if (hasBlock) {
//        rules = this.blockRuleset();
//    }
//
//    if (rules || (!hasBlock && value && parserInput.$char(';'))) {
//        parserInput.forget();
//        return new (tree.AtRule)(name, value, rules, index, fileInfo,
//            context.dumpLineNumbers ? getDebugInfo(index) : null,
//            isRooted
//        );
//    }
//
//    parserInput.restore("at-rule options not recognised");
//},
}