237 lines
		
	
	
		
			6.6 KiB
		
	
	
	
		
			JavaScript
		
	
	
	
	
	
			
		
		
	
	
			237 lines
		
	
	
		
			6.6 KiB
		
	
	
	
		
			JavaScript
		
	
	
	
	
	
var isDigit = require('../tokenizer').isDigit;
 | 
						|
var cmpChar = require('../tokenizer').cmpChar;
 | 
						|
var TYPE = require('../tokenizer').TYPE;
 | 
						|
 | 
						|
var DELIM = TYPE.Delim;
 | 
						|
var WHITESPACE = TYPE.WhiteSpace;
 | 
						|
var COMMENT = TYPE.Comment;
 | 
						|
var IDENT = TYPE.Ident;
 | 
						|
var NUMBER = TYPE.Number;
 | 
						|
var DIMENSION = TYPE.Dimension;
 | 
						|
var PLUSSIGN = 0x002B;    // U+002B PLUS SIGN (+)
 | 
						|
var HYPHENMINUS = 0x002D; // U+002D HYPHEN-MINUS (-)
 | 
						|
var N = 0x006E;           // U+006E LATIN SMALL LETTER N (n)
 | 
						|
var DISALLOW_SIGN = true;
 | 
						|
var ALLOW_SIGN = false;
 | 
						|
 | 
						|
function isDelim(token, code) {
 | 
						|
    return token !== null && token.type === DELIM && token.value.charCodeAt(0) === code;
 | 
						|
}
 | 
						|
 | 
						|
function skipSC(token, offset, getNextToken) {
 | 
						|
    while (token !== null && (token.type === WHITESPACE || token.type === COMMENT)) {
 | 
						|
        token = getNextToken(++offset);
 | 
						|
    }
 | 
						|
 | 
						|
    return offset;
 | 
						|
}
 | 
						|
 | 
						|
function checkInteger(token, valueOffset, disallowSign, offset) {
 | 
						|
    if (!token) {
 | 
						|
        return 0;
 | 
						|
    }
 | 
						|
 | 
						|
    var code = token.value.charCodeAt(valueOffset);
 | 
						|
 | 
						|
    if (code === PLUSSIGN || code === HYPHENMINUS) {
 | 
						|
        if (disallowSign) {
 | 
						|
            // Number sign is not allowed
 | 
						|
            return 0;
 | 
						|
        }
 | 
						|
        valueOffset++;
 | 
						|
    }
 | 
						|
 | 
						|
    for (; valueOffset < token.value.length; valueOffset++) {
 | 
						|
        if (!isDigit(token.value.charCodeAt(valueOffset))) {
 | 
						|
            // Integer is expected
 | 
						|
            return 0;
 | 
						|
        }
 | 
						|
    }
 | 
						|
 | 
						|
    return offset + 1;
 | 
						|
}
 | 
						|
 | 
						|
// ... <signed-integer>
 | 
						|
// ... ['+' | '-'] <signless-integer>
 | 
						|
function consumeB(token, offset_, getNextToken) {
 | 
						|
    var sign = false;
 | 
						|
    var offset = skipSC(token, offset_, getNextToken);
 | 
						|
 | 
						|
    token = getNextToken(offset);
 | 
						|
 | 
						|
    if (token === null) {
 | 
						|
        return offset_;
 | 
						|
    }
 | 
						|
 | 
						|
    if (token.type !== NUMBER) {
 | 
						|
        if (isDelim(token, PLUSSIGN) || isDelim(token, HYPHENMINUS)) {
 | 
						|
            sign = true;
 | 
						|
            offset = skipSC(getNextToken(++offset), offset, getNextToken);
 | 
						|
            token = getNextToken(offset);
 | 
						|
 | 
						|
            if (token === null && token.type !== NUMBER) {
 | 
						|
                return 0;
 | 
						|
            }
 | 
						|
        } else {
 | 
						|
            return offset_;
 | 
						|
        }
 | 
						|
    }
 | 
						|
 | 
						|
    if (!sign) {
 | 
						|
        var code = token.value.charCodeAt(0);
 | 
						|
        if (code !== PLUSSIGN && code !== HYPHENMINUS) {
 | 
						|
            // Number sign is expected
 | 
						|
            return 0;
 | 
						|
        }
 | 
						|
    }
 | 
						|
 | 
						|
    return checkInteger(token, sign ? 0 : 1, sign, offset);
 | 
						|
}
 | 
						|
 | 
						|
// An+B microsyntax https://www.w3.org/TR/css-syntax-3/#anb
 | 
						|
module.exports = function anPlusB(token, getNextToken) {
 | 
						|
    /* eslint-disable brace-style*/
 | 
						|
    var offset = 0;
 | 
						|
 | 
						|
    if (!token) {
 | 
						|
        return 0;
 | 
						|
    }
 | 
						|
 | 
						|
    // <integer>
 | 
						|
    if (token.type === NUMBER) {
 | 
						|
        return checkInteger(token, 0, ALLOW_SIGN, offset); // b
 | 
						|
    }
 | 
						|
 | 
						|
    // -n
 | 
						|
    // -n <signed-integer>
 | 
						|
    // -n ['+' | '-'] <signless-integer>
 | 
						|
    // -n- <signless-integer>
 | 
						|
    // <dashndashdigit-ident>
 | 
						|
    else if (token.type === IDENT && token.value.charCodeAt(0) === HYPHENMINUS) {
 | 
						|
        // expect 1st char is N
 | 
						|
        if (!cmpChar(token.value, 1, N)) {
 | 
						|
            return 0;
 | 
						|
        }
 | 
						|
 | 
						|
        switch (token.value.length) {
 | 
						|
            // -n
 | 
						|
            // -n <signed-integer>
 | 
						|
            // -n ['+' | '-'] <signless-integer>
 | 
						|
            case 2:
 | 
						|
                return consumeB(getNextToken(++offset), offset, getNextToken);
 | 
						|
 | 
						|
            // -n- <signless-integer>
 | 
						|
            case 3:
 | 
						|
                if (token.value.charCodeAt(2) !== HYPHENMINUS) {
 | 
						|
                    return 0;
 | 
						|
                }
 | 
						|
 | 
						|
                offset = skipSC(getNextToken(++offset), offset, getNextToken);
 | 
						|
                token = getNextToken(offset);
 | 
						|
 | 
						|
                return checkInteger(token, 0, DISALLOW_SIGN, offset);
 | 
						|
 | 
						|
            // <dashndashdigit-ident>
 | 
						|
            default:
 | 
						|
                if (token.value.charCodeAt(2) !== HYPHENMINUS) {
 | 
						|
                    return 0;
 | 
						|
                }
 | 
						|
 | 
						|
                return checkInteger(token, 3, DISALLOW_SIGN, offset);
 | 
						|
        }
 | 
						|
    }
 | 
						|
 | 
						|
    // '+'? n
 | 
						|
    // '+'? n <signed-integer>
 | 
						|
    // '+'? n ['+' | '-'] <signless-integer>
 | 
						|
    // '+'? n- <signless-integer>
 | 
						|
    // '+'? <ndashdigit-ident>
 | 
						|
    else if (token.type === IDENT || (isDelim(token, PLUSSIGN) && getNextToken(offset + 1).type === IDENT)) {
 | 
						|
        // just ignore a plus
 | 
						|
        if (token.type !== IDENT) {
 | 
						|
            token = getNextToken(++offset);
 | 
						|
        }
 | 
						|
 | 
						|
        if (token === null || !cmpChar(token.value, 0, N)) {
 | 
						|
            return 0;
 | 
						|
        }
 | 
						|
 | 
						|
        switch (token.value.length) {
 | 
						|
            // '+'? n
 | 
						|
            // '+'? n <signed-integer>
 | 
						|
            // '+'? n ['+' | '-'] <signless-integer>
 | 
						|
            case 1:
 | 
						|
                return consumeB(getNextToken(++offset), offset, getNextToken);
 | 
						|
 | 
						|
            // '+'? n- <signless-integer>
 | 
						|
            case 2:
 | 
						|
                if (token.value.charCodeAt(1) !== HYPHENMINUS) {
 | 
						|
                    return 0;
 | 
						|
                }
 | 
						|
 | 
						|
                offset = skipSC(getNextToken(++offset), offset, getNextToken);
 | 
						|
                token = getNextToken(offset);
 | 
						|
 | 
						|
                return checkInteger(token, 0, DISALLOW_SIGN, offset);
 | 
						|
 | 
						|
            // '+'? <ndashdigit-ident>
 | 
						|
            default:
 | 
						|
                if (token.value.charCodeAt(1) !== HYPHENMINUS) {
 | 
						|
                    return 0;
 | 
						|
                }
 | 
						|
 | 
						|
                return checkInteger(token, 2, DISALLOW_SIGN, offset);
 | 
						|
        }
 | 
						|
    }
 | 
						|
 | 
						|
    // <ndashdigit-dimension>
 | 
						|
    // <ndash-dimension> <signless-integer>
 | 
						|
    // <n-dimension>
 | 
						|
    // <n-dimension> <signed-integer>
 | 
						|
    // <n-dimension> ['+' | '-'] <signless-integer>
 | 
						|
    else if (token.type === DIMENSION) {
 | 
						|
        var code = token.value.charCodeAt(0);
 | 
						|
        var sign = code === PLUSSIGN || code === HYPHENMINUS ? 1 : 0;
 | 
						|
 | 
						|
        for (var i = sign; i < token.value.length; i++) {
 | 
						|
            if (!isDigit(token.value.charCodeAt(i))) {
 | 
						|
                break;
 | 
						|
            }
 | 
						|
        }
 | 
						|
 | 
						|
        if (i === sign) {
 | 
						|
            // Integer is expected
 | 
						|
            return 0;
 | 
						|
        }
 | 
						|
 | 
						|
        if (!cmpChar(token.value, i, N)) {
 | 
						|
            return 0;
 | 
						|
        }
 | 
						|
 | 
						|
        // <n-dimension>
 | 
						|
        // <n-dimension> <signed-integer>
 | 
						|
        // <n-dimension> ['+' | '-'] <signless-integer>
 | 
						|
        if (i + 1 === token.value.length) {
 | 
						|
            return consumeB(getNextToken(++offset), offset, getNextToken);
 | 
						|
        } else {
 | 
						|
            if (token.value.charCodeAt(i + 1) !== HYPHENMINUS) {
 | 
						|
                return 0;
 | 
						|
            }
 | 
						|
 | 
						|
            // <ndash-dimension> <signless-integer>
 | 
						|
            if (i + 2 === token.value.length) {
 | 
						|
                offset = skipSC(getNextToken(++offset), offset, getNextToken);
 | 
						|
                token = getNextToken(offset);
 | 
						|
 | 
						|
                return checkInteger(token, 0, DISALLOW_SIGN, offset);
 | 
						|
            }
 | 
						|
            // <ndashdigit-dimension>
 | 
						|
            else {
 | 
						|
                return checkInteger(token, i + 2, DISALLOW_SIGN, offset);
 | 
						|
            }
 | 
						|
        }
 | 
						|
    }
 | 
						|
 | 
						|
    return 0;
 | 
						|
};
 |