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