|
|
var EOF = 0;
// https://drafts.csswg.org/css-syntax-3/
// § 4.2. Definitions
// digit
// A code point between U+0030 DIGIT ZERO (0) and U+0039 DIGIT NINE (9).
function isDigit(code) { return code >= 0x0030 && code <= 0x0039; }
// hex digit
// A digit, or a code point between U+0041 LATIN CAPITAL LETTER A (A) and U+0046 LATIN CAPITAL LETTER F (F),
// or a code point between U+0061 LATIN SMALL LETTER A (a) and U+0066 LATIN SMALL LETTER F (f).
function isHexDigit(code) { return ( isDigit(code) || // 0 .. 9
(code >= 0x0041 && code <= 0x0046) || // A .. F
(code >= 0x0061 && code <= 0x0066) // a .. f
); }
// uppercase letter
// A code point between U+0041 LATIN CAPITAL LETTER A (A) and U+005A LATIN CAPITAL LETTER Z (Z).
function isUppercaseLetter(code) { return code >= 0x0041 && code <= 0x005A; }
// lowercase letter
// A code point between U+0061 LATIN SMALL LETTER A (a) and U+007A LATIN SMALL LETTER Z (z).
function isLowercaseLetter(code) { return code >= 0x0061 && code <= 0x007A; }
// letter
// An uppercase letter or a lowercase letter.
function isLetter(code) { return isUppercaseLetter(code) || isLowercaseLetter(code); }
// non-ASCII code point
// A code point with a value equal to or greater than U+0080 <control>.
function isNonAscii(code) { return code >= 0x0080; }
// name-start code point
// A letter, a non-ASCII code point, or U+005F LOW LINE (_).
function isNameStart(code) { return isLetter(code) || isNonAscii(code) || code === 0x005F; }
// name code point
// A name-start code point, a digit, or U+002D HYPHEN-MINUS (-).
function isName(code) { return isNameStart(code) || isDigit(code) || code === 0x002D; }
// non-printable code point
// A code point between U+0000 NULL and U+0008 BACKSPACE, or U+000B LINE TABULATION,
// or a code point between U+000E SHIFT OUT and U+001F INFORMATION SEPARATOR ONE, or U+007F DELETE.
function isNonPrintable(code) { return ( (code >= 0x0000 && code <= 0x0008) || (code === 0x000B) || (code >= 0x000E && code <= 0x001F) || (code === 0x007F) ); }
// newline
// U+000A LINE FEED. Note that U+000D CARRIAGE RETURN and U+000C FORM FEED are not included in this definition,
// as they are converted to U+000A LINE FEED during preprocessing.
// TODO: we doesn't do a preprocessing, so check a code point for U+000D CARRIAGE RETURN and U+000C FORM FEED
function isNewline(code) { return code === 0x000A || code === 0x000D || code === 0x000C; }
// whitespace
// A newline, U+0009 CHARACTER TABULATION, or U+0020 SPACE.
function isWhiteSpace(code) { return isNewline(code) || code === 0x0020 || code === 0x0009; }
// § 4.3.8. Check if two code points are a valid escape
function isValidEscape(first, second) { // If the first code point is not U+005C REVERSE SOLIDUS (\), return false.
if (first !== 0x005C) { return false; }
// Otherwise, if the second code point is a newline or EOF, return false.
if (isNewline(second) || second === EOF) { return false; }
// Otherwise, return true.
return true; }
// § 4.3.9. Check if three code points would start an identifier
function isIdentifierStart(first, second, third) { // Look at the first code point:
// U+002D HYPHEN-MINUS
if (first === 0x002D) { // If the second code point is a name-start code point or a U+002D HYPHEN-MINUS,
// or the second and third code points are a valid escape, return true. Otherwise, return false.
return ( isNameStart(second) || second === 0x002D || isValidEscape(second, third) ); }
// name-start code point
if (isNameStart(first)) { // Return true.
return true; }
// U+005C REVERSE SOLIDUS (\)
if (first === 0x005C) { // If the first and second code points are a valid escape, return true. Otherwise, return false.
return isValidEscape(first, second); }
// anything else
// Return false.
return false; }
// § 4.3.10. Check if three code points would start a number
function isNumberStart(first, second, third) { // Look at the first code point:
// U+002B PLUS SIGN (+)
// U+002D HYPHEN-MINUS (-)
if (first === 0x002B || first === 0x002D) { // If the second code point is a digit, return true.
if (isDigit(second)) { return 2; }
// Otherwise, if the second code point is a U+002E FULL STOP (.)
// and the third code point is a digit, return true.
// Otherwise, return false.
return second === 0x002E && isDigit(third) ? 3 : 0; }
// U+002E FULL STOP (.)
if (first === 0x002E) { // If the second code point is a digit, return true. Otherwise, return false.
return isDigit(second) ? 2 : 0; }
// digit
if (isDigit(first)) { // Return true.
return 1; }
// anything else
// Return false.
return 0; }
//
// Misc
//
// detect BOM (https://en.wikipedia.org/wiki/Byte_order_mark)
function isBOM(code) { // UTF-16BE
if (code === 0xFEFF) { return 1; }
// UTF-16LE
if (code === 0xFFFE) { return 1; }
return 0; }
// Fast code category
//
// https://drafts.csswg.org/css-syntax/#tokenizer-definitions
// > non-ASCII code point
// > A code point with a value equal to or greater than U+0080 <control>
// > name-start code point
// > A letter, a non-ASCII code point, or U+005F LOW LINE (_).
// > name code point
// > A name-start code point, a digit, or U+002D HYPHEN-MINUS (-)
// That means only ASCII code points has a special meaning and we define a maps for 0..127 codes only
var CATEGORY = new Array(0x80); charCodeCategory.Eof = 0x80; charCodeCategory.WhiteSpace = 0x82; charCodeCategory.Digit = 0x83; charCodeCategory.NameStart = 0x84; charCodeCategory.NonPrintable = 0x85;
for (var i = 0; i < CATEGORY.length; i++) { switch (true) { case isWhiteSpace(i): CATEGORY[i] = charCodeCategory.WhiteSpace; break;
case isDigit(i): CATEGORY[i] = charCodeCategory.Digit; break;
case isNameStart(i): CATEGORY[i] = charCodeCategory.NameStart; break;
case isNonPrintable(i): CATEGORY[i] = charCodeCategory.NonPrintable; break;
default: CATEGORY[i] = i || charCodeCategory.Eof; } }
function charCodeCategory(code) { return code < 0x80 ? CATEGORY[code] : charCodeCategory.NameStart; };
module.exports = { isDigit: isDigit, isHexDigit: isHexDigit, isUppercaseLetter: isUppercaseLetter, isLowercaseLetter: isLowercaseLetter, isLetter: isLetter, isNonAscii: isNonAscii, isNameStart: isNameStart, isName: isName, isNonPrintable: isNonPrintable, isNewline: isNewline, isWhiteSpace: isWhiteSpace, isValidEscape: isValidEscape, isIdentifierStart: isIdentifierStart, isNumberStart: isNumberStart,
isBOM: isBOM, charCodeCategory: charCodeCategory };
|