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' };