| var TYPE = require('../../tokenizer').TYPE; | 
| var rawMode = require('./Raw').mode; | 
|   | 
| var ATKEYWORD = TYPE.AtKeyword; | 
| var SEMICOLON = TYPE.Semicolon; | 
| var LEFTCURLYBRACKET = TYPE.LeftCurlyBracket; | 
| var RIGHTCURLYBRACKET = TYPE.RightCurlyBracket; | 
|   | 
| function consumeRaw(startToken) { | 
|     return this.Raw(startToken, rawMode.leftCurlyBracketOrSemicolon, true); | 
| } | 
|   | 
| function isDeclarationBlockAtrule() { | 
|     for (var offset = 1, type; type = this.scanner.lookupType(offset); offset++) { | 
|         if (type === RIGHTCURLYBRACKET) { | 
|             return true; | 
|         } | 
|   | 
|         if (type === LEFTCURLYBRACKET || | 
|             type === ATKEYWORD) { | 
|             return false; | 
|         } | 
|     } | 
|   | 
|     return false; | 
| } | 
|   | 
| module.exports = { | 
|     name: 'Atrule', | 
|     structure: { | 
|         name: String, | 
|         prelude: ['AtrulePrelude', 'Raw', null], | 
|         block: ['Block', null] | 
|     }, | 
|     parse: function() { | 
|         var start = this.scanner.tokenStart; | 
|         var name; | 
|         var nameLowerCase; | 
|         var prelude = null; | 
|         var block = null; | 
|   | 
|         this.eat(ATKEYWORD); | 
|   | 
|         name = this.scanner.substrToCursor(start + 1); | 
|         nameLowerCase = name.toLowerCase(); | 
|         this.scanner.skipSC(); | 
|   | 
|         // parse prelude | 
|         if (this.scanner.eof === false && | 
|             this.scanner.tokenType !== LEFTCURLYBRACKET && | 
|             this.scanner.tokenType !== SEMICOLON) { | 
|             if (this.parseAtrulePrelude) { | 
|                 prelude = this.parseWithFallback(this.AtrulePrelude.bind(this, name), consumeRaw); | 
|   | 
|                 // turn empty AtrulePrelude into null | 
|                 if (prelude.type === 'AtrulePrelude' && prelude.children.head === null) { | 
|                     prelude = null; | 
|                 } | 
|             } else { | 
|                 prelude = consumeRaw.call(this, this.scanner.tokenIndex); | 
|             } | 
|   | 
|             this.scanner.skipSC(); | 
|         } | 
|   | 
|         switch (this.scanner.tokenType) { | 
|             case SEMICOLON: | 
|                 this.scanner.next(); | 
|                 break; | 
|   | 
|             case LEFTCURLYBRACKET: | 
|                 if (this.atrule.hasOwnProperty(nameLowerCase) && | 
|                     typeof this.atrule[nameLowerCase].block === 'function') { | 
|                     block = this.atrule[nameLowerCase].block.call(this); | 
|                 } else { | 
|                     // TODO: should consume block content as Raw? | 
|                     block = this.Block(isDeclarationBlockAtrule.call(this)); | 
|                 } | 
|   | 
|                 break; | 
|         } | 
|   | 
|         return { | 
|             type: 'Atrule', | 
|             loc: this.getLocation(start, this.scanner.tokenStart), | 
|             name: name, | 
|             prelude: prelude, | 
|             block: block | 
|         }; | 
|     }, | 
|     generate: function(node) { | 
|         this.chunk('@'); | 
|         this.chunk(node.name); | 
|   | 
|         if (node.prelude !== null) { | 
|             this.chunk(' '); | 
|             this.node(node.prelude); | 
|         } | 
|   | 
|         if (node.block) { | 
|             this.node(node.block); | 
|         } else { | 
|             this.chunk(';'); | 
|         } | 
|     }, | 
|     walkContext: 'atrule' | 
| }; |