160 lines
		
	
	
		
			4.6 KiB
		
	
	
	
		
			JavaScript
		
	
	
	
	
	
			
		
		
	
	
			160 lines
		
	
	
		
			4.6 KiB
		
	
	
	
		
			JavaScript
		
	
	
	
	
	
var isHexDigit = require('../tokenizer').isHexDigit;
 | 
						|
var cmpChar = require('../tokenizer').cmpChar;
 | 
						|
var TYPE = require('../tokenizer').TYPE;
 | 
						|
 | 
						|
var IDENT = TYPE.Ident;
 | 
						|
var DELIM = TYPE.Delim;
 | 
						|
var NUMBER = TYPE.Number;
 | 
						|
var DIMENSION = TYPE.Dimension;
 | 
						|
var PLUSSIGN = 0x002B;     // U+002B PLUS SIGN (+)
 | 
						|
var HYPHENMINUS = 0x002D;  // U+002D HYPHEN-MINUS (-)
 | 
						|
var QUESTIONMARK = 0x003F; // U+003F QUESTION MARK (?)
 | 
						|
var U = 0x0075;            // U+0075 LATIN SMALL LETTER U (u)
 | 
						|
 | 
						|
function isDelim(token, code) {
 | 
						|
    return token !== null && token.type === DELIM && token.value.charCodeAt(0) === code;
 | 
						|
}
 | 
						|
 | 
						|
function startsWith(token, code) {
 | 
						|
    return token.value.charCodeAt(0) === code;
 | 
						|
}
 | 
						|
 | 
						|
function hexSequence(token, offset, allowDash) {
 | 
						|
    for (var pos = offset, hexlen = 0; pos < token.value.length; pos++) {
 | 
						|
        var code = token.value.charCodeAt(pos);
 | 
						|
 | 
						|
        if (code === HYPHENMINUS && allowDash && hexlen !== 0) {
 | 
						|
            if (hexSequence(token, offset + hexlen + 1, false) > 0) {
 | 
						|
                return 6; // dissallow following question marks
 | 
						|
            }
 | 
						|
 | 
						|
            return 0; // dash at the ending of a hex sequence is not allowed
 | 
						|
        }
 | 
						|
 | 
						|
        if (!isHexDigit(code)) {
 | 
						|
            return 0; // not a hex digit
 | 
						|
        }
 | 
						|
 | 
						|
        if (++hexlen > 6) {
 | 
						|
            return 0; // too many hex digits
 | 
						|
        };
 | 
						|
    }
 | 
						|
 | 
						|
    return hexlen;
 | 
						|
}
 | 
						|
 | 
						|
function withQuestionMarkSequence(consumed, length, getNextToken) {
 | 
						|
    if (!consumed) {
 | 
						|
        return 0; // nothing consumed
 | 
						|
    }
 | 
						|
 | 
						|
    while (isDelim(getNextToken(length), QUESTIONMARK)) {
 | 
						|
        if (++consumed > 6) {
 | 
						|
            return 0; // too many question marks
 | 
						|
        }
 | 
						|
 | 
						|
        length++;
 | 
						|
    }
 | 
						|
 | 
						|
    return length;
 | 
						|
}
 | 
						|
 | 
						|
// https://drafts.csswg.org/css-syntax/#urange
 | 
						|
// Informally, the <urange> production has three forms:
 | 
						|
// U+0001
 | 
						|
//      Defines a range consisting of a single code point, in this case the code point "1".
 | 
						|
// U+0001-00ff
 | 
						|
//      Defines a range of codepoints between the first and the second value, in this case
 | 
						|
//      the range between "1" and "ff" (255 in decimal) inclusive.
 | 
						|
// U+00??
 | 
						|
//      Defines a range of codepoints where the "?" characters range over all hex digits,
 | 
						|
//      in this case defining the same as the value U+0000-00ff.
 | 
						|
// In each form, a maximum of 6 digits is allowed for each hexadecimal number (if you treat "?" as a hexadecimal digit).
 | 
						|
//
 | 
						|
// <urange> =
 | 
						|
//   u '+' <ident-token> '?'* |
 | 
						|
//   u <dimension-token> '?'* |
 | 
						|
//   u <number-token> '?'* |
 | 
						|
//   u <number-token> <dimension-token> |
 | 
						|
//   u <number-token> <number-token> |
 | 
						|
//   u '+' '?'+
 | 
						|
module.exports = function urange(token, getNextToken) {
 | 
						|
    var length = 0;
 | 
						|
 | 
						|
    // should start with `u` or `U`
 | 
						|
    if (token === null || token.type !== IDENT || !cmpChar(token.value, 0, U)) {
 | 
						|
        return 0;
 | 
						|
    }
 | 
						|
 | 
						|
    token = getNextToken(++length);
 | 
						|
    if (token === null) {
 | 
						|
        return 0;
 | 
						|
    }
 | 
						|
 | 
						|
    // u '+' <ident-token> '?'*
 | 
						|
    // u '+' '?'+
 | 
						|
    if (isDelim(token, PLUSSIGN)) {
 | 
						|
        token = getNextToken(++length);
 | 
						|
        if (token === null) {
 | 
						|
            return 0;
 | 
						|
        }
 | 
						|
 | 
						|
        if (token.type === IDENT) {
 | 
						|
            // u '+' <ident-token> '?'*
 | 
						|
            return withQuestionMarkSequence(hexSequence(token, 0, true), ++length, getNextToken);
 | 
						|
        }
 | 
						|
 | 
						|
        if (isDelim(token, QUESTIONMARK)) {
 | 
						|
            // u '+' '?'+
 | 
						|
            return withQuestionMarkSequence(1, ++length, getNextToken);
 | 
						|
        }
 | 
						|
 | 
						|
        // Hex digit or question mark is expected
 | 
						|
        return 0;
 | 
						|
    }
 | 
						|
 | 
						|
    // u <number-token> '?'*
 | 
						|
    // u <number-token> <dimension-token>
 | 
						|
    // u <number-token> <number-token>
 | 
						|
    if (token.type === NUMBER) {
 | 
						|
        if (!startsWith(token, PLUSSIGN)) {
 | 
						|
            return 0;
 | 
						|
        }
 | 
						|
 | 
						|
        var consumedHexLength = hexSequence(token, 1, true);
 | 
						|
        if (consumedHexLength === 0) {
 | 
						|
            return 0;
 | 
						|
        }
 | 
						|
 | 
						|
        token = getNextToken(++length);
 | 
						|
        if (token === null) {
 | 
						|
            // u <number-token> <eof>
 | 
						|
            return length;
 | 
						|
        }
 | 
						|
 | 
						|
        if (token.type === DIMENSION || token.type === NUMBER) {
 | 
						|
            // u <number-token> <dimension-token>
 | 
						|
            // u <number-token> <number-token>
 | 
						|
            if (!startsWith(token, HYPHENMINUS) || !hexSequence(token, 1, false)) {
 | 
						|
                return 0;
 | 
						|
            }
 | 
						|
 | 
						|
            return length + 1;
 | 
						|
        }
 | 
						|
 | 
						|
        // u <number-token> '?'*
 | 
						|
        return withQuestionMarkSequence(consumedHexLength, length, getNextToken);
 | 
						|
    }
 | 
						|
 | 
						|
    // u <dimension-token> '?'*
 | 
						|
    if (token.type === DIMENSION) {
 | 
						|
        if (!startsWith(token, PLUSSIGN)) {
 | 
						|
            return 0;
 | 
						|
        }
 | 
						|
 | 
						|
        return withQuestionMarkSequence(hexSequence(token, 1, true), ++length, getNextToken);
 | 
						|
    }
 | 
						|
 | 
						|
    return 0;
 | 
						|
};
 |