108 lines
		
	
	
		
			3.0 KiB
		
	
	
	
		
			JavaScript
		
	
	
	
	
	
			
		
		
	
	
			108 lines
		
	
	
		
			3.0 KiB
		
	
	
	
		
			JavaScript
		
	
	
	
	
	
| 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'
 | |
| };
 | 
