processDirective method

CSSRule? processDirective()

Directive grammar:

import:             '@import' [string | URI] media_list?
media:              '@media' media_query_list '{' ruleset '}'
page:               '@page' [':' IDENT]? '{' declarations '}'
stylet:             '@stylet' IDENT '{' ruleset '}'
media_query_list:   IDENT [',' IDENT]
keyframes:          '@-webkit-keyframes ...' (see grammar below).
font_face:          '@font-face' '{' declarations '}'
namespace:          '@namespace name url("xmlns")
host:               '@host '{' ruleset '}'
mixin:              '@mixin name [(args,...)] '{' declarations/ruleset '}'
include:            '@include name [(@arg,@arg1)]
                    '@include name [(@arg...)]
content:            '@content'
-moz-document:      '@-moz-document' [ <url> | url-prefix(<string>) |
                        domain(<string>) | regexp(<string) ]# '{'
                      declarations
                    '}'
supports:           '@supports' supports_condition group_rule_body

Implementation

CSSRule? processDirective() {
  var tokenId = _peek();
  switch (tokenId) {
    case TokenKind.DIRECTIVE_IMPORT:
      _next();
      return null;

    case TokenKind.DIRECTIVE_MEDIA:
      while (!_maybeEat(TokenKind.END_OF_FILE) && !_maybeEat(TokenKind.RBRACE)) {
        _next();
      }
      return null;
    case TokenKind.DIRECTIVE_HOST:
      _next();

      return null;

    case TokenKind.DIRECTIVE_PAGE:
      // @page S* IDENT? pseudo_page?
      //      S* '{' S*
      //      [ declaration | margin ]?
      //      [ ';' S* [ declaration | margin ]? ]* '}' S*
      //
      // pseudo_page :
      //      ':' [ "left" | "right" | "first" ]
      //
      // margin :
      //      margin_sym S* '{' declaration [ ';' S* declaration? ]* '}' S*
      //
      // margin_sym : @top-left-corner, @top-left, @bottom-left, etc.
      //
      // See http://www.w3.org/TR/css3-page/#CSS21
      _next();

      return null;
    case TokenKind.DIRECTIVE_CHARSET:
      // @charset S* STRING S* ';'
      _next();

      processQuotedString(false);

      return null;

    // TODO(terry): Workaround Dart2js bug continue not implemented in switch
    //              see https://code.google.com/p/dart/issues/detail?id=8270
    /*
    case TokenKind.DIRECTIVE_MS_KEYFRAMES:
      // TODO(terry): For now only IE 10 (are base level) supports @keyframes,
      // -moz- has only been optional since Oct 2012 release of Firefox, not
      // all versions of webkit support @keyframes and opera doesn't yet
      // support w/o -o- prefix.  Add more warnings for other prefixes when
      // they become optional.
      if (isChecked) {
        _warning('@-ms-keyframes should be @keyframes');
      }
      continue keyframeDirective;

    keyframeDirective:
    */
    case TokenKind.DIRECTIVE_KEYFRAMES:
    case TokenKind.DIRECTIVE_WEB_KIT_KEYFRAMES:
    case TokenKind.DIRECTIVE_MOZ_KEYFRAMES:
    case TokenKind.DIRECTIVE_O_KEYFRAMES:
    // TODO(terry): Remove workaround when bug 8270 is fixed.
    case TokenKind.DIRECTIVE_MS_KEYFRAMES:
      if (tokenId == TokenKind.DIRECTIVE_MS_KEYFRAMES && isChecked) {
        _warning('@-ms-keyframes should be @keyframes');
      }
      // TODO(terry): End of workaround.

      // Key frames grammar:
      //
      //     @[browser]? keyframes [IDENT|STRING] '{' keyframes-blocks '}';
      //
      //     browser: [-webkit-, -moz-, -ms-, -o-]
      //
      //     keyframes-blocks:
      //       [keyframe-selectors '{' declarations '}']* ;
      //
      //     keyframe-selectors:
      //       ['from'|'to'|PERCENTAGE] [',' ['from'|'to'|PERCENTAGE] ]* ;
      _next();

      String name = '';
      if (_peekIdentifier()) {
        name = identifier().name;
      }
      assert(name.isNotEmpty, 'keyframes rule name must not be null');
      _eat(TokenKind.LBRACE);

      var keyframe = CSSKeyframesRule(tokenId, name);
      do {
        List<String> selectors = [];
        do {
          var selector = _next().text;
          final text = _peekToken.text;
          // ignore unit type
          if (TokenKind.matchUnits(text, 0, text.length) != -1) {
            if (_peekToken.kind == TokenKind.PERCENT) {
              selector += text; // join selector & unit
            }
            _next();
          }
          selectors.add(selector);
        } while (_maybeEat(TokenKind.COMMA));

        final declarations = processDeclarations();
        if (declarations.last is CSSStyleDeclaration) {
          keyframe.add(KeyFrameBlock(selectors, declarations.last));
        }
      } while (!_maybeEat(TokenKind.RBRACE) && !isPrematureEndOfFile());

      return keyframe;

    case TokenKind.DIRECTIVE_FONTFACE:
      _next();
      _eat(TokenKind.LBRACE);
      List data = processDeclarations();
      assert(data.isNotEmpty);
      return CSSFontFaceRule(data[0]);
    case TokenKind.DIRECTIVE_STYLET:
      // Stylet grammar:
      //
      //     @stylet IDENT '{'
      //       ruleset
      //     '}'
      _next();

      return null;
    case TokenKind.DIRECTIVE_NAMESPACE:
      // Namespace grammar:
      //
      // @namespace S* [namespace_prefix S*]? [STRING|URI] S* ';' S*
      // namespace_prefix : IDENT
      _next();

      return null;

    case TokenKind.DIRECTIVE_MIXIN:
      return null;

    case TokenKind.DIRECTIVE_INCLUDE:
      return null;
    case TokenKind.DIRECTIVE_CONTENT:
      // TODO(terry): TBD
      _warning('@content not implemented.');
      return null;
    case TokenKind.DIRECTIVE_MOZ_DOCUMENT:
      return null;
    case TokenKind.DIRECTIVE_SUPPORTS:
      return null;
    case TokenKind.DIRECTIVE_VIEWPORT:
    case TokenKind.DIRECTIVE_MS_VIEWPORT:
      return null;
  }
  return null;
}