var isDigit = require('../tokenizer').isDigit; var cmpChar = require('../tokenizer').cmpChar; var TYPE = require('../tokenizer').TYPE; var CHARCODE = require('../tokenizer').CHARCODE; 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 = CHARCODE.PlusSign; var HYPHENMINUS = CHARCODE.HyphenMinus; var N = 110; // 'n'.charCodeAt(0) 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; } // ... // ... ['+' | '-'] 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) { var offset = 0; if (!token) { return 0; } // if (token.type === NUMBER) { return checkInteger(token, 0, ALLOW_SIGN, offset); // b } // -n // -n // -n ['+' | '-'] // -n- // 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 // -n ['+' | '-'] case 2: return consumeB(getNextToken(++offset), offset, getNextToken); // -n- 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); // default: if (token.value.charCodeAt(2) !== HYPHENMINUS) { return 0; } return checkInteger(token, 3, DISALLOW_SIGN, offset); } } // '+'? n // '+'? n // '+'? n ['+' | '-'] // '+'? n- // '+'? 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 // '+'? n ['+' | '-'] case 1: return consumeB(getNextToken(++offset), offset, getNextToken); // '+'? n- 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); // '+'? default: if (token.value.charCodeAt(1) !== HYPHENMINUS) { return 0; } return checkInteger(token, 2, DISALLOW_SIGN, offset); } } // // // // // ['+' | '-'] 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; } // // // ['+' | '-'] if (i + 1 === token.value.length) { return consumeB(getNextToken(++offset), offset, getNextToken); } else { if (token.value.charCodeAt(i + 1) !== HYPHENMINUS) { return 0; } // if (i + 2 === token.value.length) { offset = skipSC(getNextToken(++offset), offset, getNextToken); token = getNextToken(offset); return checkInteger(token, 0, DISALLOW_SIGN, offset); } // else { return checkInteger(token, i + 2, DISALLOW_SIGN, offset); } } } return 0; };