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