|
|
@@ -44,16 +44,11 @@ this.parseCss = this.parseCss || (() => {
|
|
|
const DECLARATION_TYPE = "DECLARATION";
|
|
|
const FUNCTION_TYPE = "FUNCTION";
|
|
|
|
|
|
- function between(num, first, last) { return num >= first && num <= last; }
|
|
|
- function digit(code) { return between(code, 0x30, 0x39); }
|
|
|
- function hexdigit(code) { return digit(code) || between(code, 0x41, 0x46) || between(code, 0x61, 0x66); }
|
|
|
- function uppercaseletter(code) { return between(code, 0x41, 0x5a); }
|
|
|
- function lowercaseletter(code) { return between(code, 0x61, 0x7a); }
|
|
|
- function letter(code) { return uppercaseletter(code) || lowercaseletter(code); }
|
|
|
- function nonascii(code) { return code >= 0x80; }
|
|
|
- function namestartchar(code) { return letter(code) || nonascii(code) || code == 0x5f; }
|
|
|
+ function digit(code) { return code >= 0x30 && code <= 0x39; }
|
|
|
+ function hexdigit(code) { return digit(code) || code >= 0x41 && code <= 0x46 || code >= 0x61 && code <= 0x66; }
|
|
|
+ function namestartchar(code) { return code >= 0x41 && code <= 0x5a || code >= 0x61 && code <= 0x7a || code >= 0x80 || code == 0x5f; }
|
|
|
function namechar(code) { return namestartchar(code) || digit(code) || code == 0x2d; }
|
|
|
- function nonprintable(code) { return between(code, 0, 8) || code == 0xb || between(code, 0xe, 0x1f) || code == 0x7f; }
|
|
|
+ function nonprintable(code) { return code >= 0 && code <= 8 || code == 0xb || code >= 0xe && code <= 0x1f || code == 0x7f; }
|
|
|
function newline(code) { return code == 0xa; }
|
|
|
function whitespace(code) { return newline(code) || code == 9 || code == 0x20; }
|
|
|
|
|
|
@@ -64,33 +59,17 @@ this.parseCss = this.parseCss || (() => {
|
|
|
// following the preprocessing cleanup rules.
|
|
|
const codepoints = [];
|
|
|
for (let i = 0; i < str.length; i++) {
|
|
|
- let code = str.charCodeAt(i);
|
|
|
- if (code == 0xd && str.charCodeAt(i + 1) == 0xa) {
|
|
|
+ let code = str.codePointAt(i);
|
|
|
+ if (code == 0xd && str.codePointAt(i + 1) == 0xa) {
|
|
|
code = 0xa; i++;
|
|
|
}
|
|
|
if (code == 0xd || code == 0xc) code = 0xa;
|
|
|
if (code == 0x0) code = 0xfffd;
|
|
|
- if (between(code, 0xd800, 0xdbff) && between(str.charCodeAt(i + 1), 0xdc00, 0xdfff)) {
|
|
|
- // Decode a surrogate pair into an astral codepoint.
|
|
|
- const lead = code - 0xd800;
|
|
|
- const trail = str.charCodeAt(i + 1) - 0xdc00;
|
|
|
- code = Math.pow(2, 20) + lead * Math.pow(2, 10) + trail;
|
|
|
- i++;
|
|
|
- }
|
|
|
codepoints.push(code);
|
|
|
}
|
|
|
return codepoints;
|
|
|
}
|
|
|
|
|
|
- function stringFromCode(code) {
|
|
|
- if (code <= 0xffff) return String.fromCharCode(code);
|
|
|
- // Otherwise, encode astral char as surrogate pair.
|
|
|
- code -= Math.pow(2, 20);
|
|
|
- const lead = Math.floor(code / Math.pow(2, 10)) + 0xd800;
|
|
|
- const trail = code % Math.pow(2, 10) + 0xdc00;
|
|
|
- return String.fromCharCode(lead) + String.fromCharCode(trail);
|
|
|
- }
|
|
|
-
|
|
|
function consumeAToken(consume, next, eof, reconsume, parseerror, donothing) {
|
|
|
consumeComments(consume, next, eof, parseerror);
|
|
|
let code = consume();
|
|
|
@@ -108,14 +87,14 @@ this.parseCss = this.parseCss || (() => {
|
|
|
token.value = consumeAName(consume, next, eof, reconsume);
|
|
|
return token;
|
|
|
} else {
|
|
|
- return new Token(DELIM_TOKEN_TYPE, stringFromCode(code));
|
|
|
+ return new Token(DELIM_TOKEN_TYPE, String.fromCodePoint(code));
|
|
|
}
|
|
|
case 0x24:
|
|
|
if (next() == 0x3d) {
|
|
|
code = consume();
|
|
|
return new Token(SUFFIX_MATCH_TOKEN_TYPE);
|
|
|
} else {
|
|
|
- return new Token(DELIM_TOKEN_TYPE, stringFromCode(code));
|
|
|
+ return new Token(DELIM_TOKEN_TYPE, String.fromCodePoint(code));
|
|
|
}
|
|
|
case 0x27:
|
|
|
return consumeAStringToken(consume, next, eof, reconsume, parseerror, donothing, code);
|
|
|
@@ -128,14 +107,14 @@ this.parseCss = this.parseCss || (() => {
|
|
|
code = consume();
|
|
|
return new Token(SUBSTRING_MATCH_TOKEN_TYPE);
|
|
|
} else {
|
|
|
- return new Token(DELIM_TOKEN_TYPE, stringFromCode(code));
|
|
|
+ return new Token(DELIM_TOKEN_TYPE, String.fromCodePoint(code));
|
|
|
}
|
|
|
case 0x2b:
|
|
|
if (startsWithANumber(next, code)) {
|
|
|
reconsume();
|
|
|
return consumeANumericToken(consume, next, eof, reconsume);
|
|
|
} else {
|
|
|
- return new Token(DELIM_TOKEN_TYPE, stringFromCode(code));
|
|
|
+ return new Token(DELIM_TOKEN_TYPE, String.fromCodePoint(code));
|
|
|
}
|
|
|
case 0x2c:
|
|
|
return new Token(COMMA_TOKEN_TYPE);
|
|
|
@@ -150,14 +129,14 @@ this.parseCss = this.parseCss || (() => {
|
|
|
reconsume();
|
|
|
return consumeAnIdentlikeToken(consume, next, eof, reconsume, parseerror, donothing);
|
|
|
} else {
|
|
|
- return new Token(DELIM_TOKEN_TYPE, stringFromCode(code));
|
|
|
+ return new Token(DELIM_TOKEN_TYPE, String.fromCodePoint(code));
|
|
|
}
|
|
|
case 0x2e:
|
|
|
if (startsWithANumber(next, code)) {
|
|
|
reconsume();
|
|
|
return consumeANumericToken(consume, next, eof, reconsume);
|
|
|
} else {
|
|
|
- return new Token(DELIM_TOKEN_TYPE, stringFromCode(code));
|
|
|
+ return new Token(DELIM_TOKEN_TYPE, String.fromCodePoint(code));
|
|
|
}
|
|
|
case 0x3a:
|
|
|
return new Token(COLON_TOKEN_TYPE);
|
|
|
@@ -168,10 +147,10 @@ this.parseCss = this.parseCss || (() => {
|
|
|
consume(3);
|
|
|
return new Token(CDO_TOKEN_TYPE);
|
|
|
} else {
|
|
|
- return new Token(DELIM_TOKEN_TYPE, stringFromCode(code));
|
|
|
+ return new Token(DELIM_TOKEN_TYPE, String.fromCodePoint(code));
|
|
|
}
|
|
|
case 0x40:
|
|
|
- return new Token(DELIM_TOKEN_TYPE, stringFromCode(code));
|
|
|
+ return new Token(DELIM_TOKEN_TYPE, String.fromCodePoint(code));
|
|
|
case 0x5b:
|
|
|
return new Token(OPEN_SQUARE_TOKEN_TYPE);
|
|
|
case 0x5c:
|
|
|
@@ -180,7 +159,7 @@ this.parseCss = this.parseCss || (() => {
|
|
|
return consumeAnIdentlikeToken(consume, next, eof, reconsume, parseerror, donothing);
|
|
|
} else {
|
|
|
parseerror();
|
|
|
- return new Token(DELIM_TOKEN_TYPE, stringFromCode(code));
|
|
|
+ return new Token(DELIM_TOKEN_TYPE, String.fromCodePoint(code));
|
|
|
}
|
|
|
case 0x5d:
|
|
|
return new Token(CLOSE_SQUARE_TOKEN_TYPE);
|
|
|
@@ -189,7 +168,7 @@ this.parseCss = this.parseCss || (() => {
|
|
|
code = consume();
|
|
|
return new Token(PREFIX_MATCH_TOKEN_TYPE);
|
|
|
} else {
|
|
|
- return new Token(DELIM_TOKEN_TYPE, stringFromCode(code));
|
|
|
+ return new Token(DELIM_TOKEN_TYPE, String.fromCodePoint(code));
|
|
|
}
|
|
|
case 0x7b:
|
|
|
return new Token(OPEN_CURLY_TOKEN_TYPE);
|
|
|
@@ -201,7 +180,7 @@ this.parseCss = this.parseCss || (() => {
|
|
|
code = consume();
|
|
|
return new Token(COLUMN_TOKEN_TYPE);
|
|
|
} else {
|
|
|
- return new Token(DELIM_TOKEN_TYPE, stringFromCode(code));
|
|
|
+ return new Token(DELIM_TOKEN_TYPE, String.fromCodePoint(code));
|
|
|
}
|
|
|
case 0x7d:
|
|
|
return new Token(CLOSE_CURLY_TOKEN_TYPE);
|
|
|
@@ -210,7 +189,7 @@ this.parseCss = this.parseCss || (() => {
|
|
|
code = consume();
|
|
|
return new Token(INCLUDE_MATCH_TOKEN_TYPE);
|
|
|
} else {
|
|
|
- return new Token(DELIM_TOKEN_TYPE, stringFromCode(code));
|
|
|
+ return new Token(DELIM_TOKEN_TYPE, String.fromCodePoint(code));
|
|
|
}
|
|
|
default:
|
|
|
if (digit(code)) {
|
|
|
@@ -222,7 +201,7 @@ this.parseCss = this.parseCss || (() => {
|
|
|
return consumeAnIdentlikeToken(consume, next, eof, reconsume, parseerror, donothing);
|
|
|
}
|
|
|
else if (eof()) return new Token(EOF_TOKEN_TYPE);
|
|
|
- else return new Token(DELIM_TOKEN_TYPE, stringFromCode(code));
|
|
|
+ else return new Token(DELIM_TOKEN_TYPE, String.fromCodePoint(code));
|
|
|
}
|
|
|
}
|
|
|
}
|
|
|
@@ -302,10 +281,10 @@ this.parseCss = this.parseCss || (() => {
|
|
|
} else if (newline(next())) {
|
|
|
code = consume();
|
|
|
} else {
|
|
|
- string += stringFromCode(consumeEscape(consume, next, eof));
|
|
|
+ string += String.fromCodePoint(consumeEscape(consume, next, eof));
|
|
|
}
|
|
|
} else {
|
|
|
- string += stringFromCode(code);
|
|
|
+ string += String.fromCodePoint(code);
|
|
|
}
|
|
|
}
|
|
|
}
|
|
|
@@ -333,14 +312,14 @@ this.parseCss = this.parseCss || (() => {
|
|
|
return new Token(BAD_URL_TOKEN_TYPE);
|
|
|
} else if (code == 0x5c) {
|
|
|
if (startsWithAValidEscape(next, code)) {
|
|
|
- token.value += stringFromCode(consumeEscape(consume, next, eof));
|
|
|
+ token.value += String.fromCodePoint(consumeEscape(consume, next, eof));
|
|
|
} else {
|
|
|
parseerror();
|
|
|
consumeTheRemnantsOfABadURL(consume, next, eof, donothing);
|
|
|
return new Token(BAD_URL_TOKEN_TYPE);
|
|
|
}
|
|
|
} else {
|
|
|
- token.value += stringFromCode(code);
|
|
|
+ token.value += String.fromCodePoint(code);
|
|
|
}
|
|
|
}
|
|
|
}
|
|
|
@@ -417,9 +396,9 @@ this.parseCss = this.parseCss || (() => {
|
|
|
let code;
|
|
|
while (code = consume()) { // eslint-disable-line no-cond-assign
|
|
|
if (namechar(code)) {
|
|
|
- result += stringFromCode(code);
|
|
|
+ result += String.fromCodePoint(code);
|
|
|
} else if (startsWithAValidEscape(next, code)) {
|
|
|
- result += stringFromCode(consumeEscape(consume, next, eof));
|
|
|
+ result += String.fromCodePoint(consumeEscape(consume, next, eof));
|
|
|
} else {
|
|
|
reconsume();
|
|
|
return result;
|
|
|
@@ -433,45 +412,45 @@ this.parseCss = this.parseCss || (() => {
|
|
|
let code;
|
|
|
if (next() == 0x2b || next() == 0x2d) {
|
|
|
code = consume();
|
|
|
- repr += stringFromCode(code);
|
|
|
+ repr += String.fromCodePoint(code);
|
|
|
}
|
|
|
while (digit(next())) {
|
|
|
code = consume();
|
|
|
- repr += stringFromCode(code);
|
|
|
+ repr += String.fromCodePoint(code);
|
|
|
}
|
|
|
if (next(1) == 0x2e && digit(next(2))) {
|
|
|
code = consume();
|
|
|
- repr += stringFromCode(code);
|
|
|
+ repr += String.fromCodePoint(code);
|
|
|
code = consume();
|
|
|
- repr += stringFromCode(code);
|
|
|
+ repr += String.fromCodePoint(code);
|
|
|
type = "number";
|
|
|
while (digit(next())) {
|
|
|
code = consume();
|
|
|
- repr += stringFromCode(code);
|
|
|
+ repr += String.fromCodePoint(code);
|
|
|
}
|
|
|
}
|
|
|
const c1 = next(1), c2 = next(2), c3 = next(3);
|
|
|
if ((c1 == 0x45 || c1 == 0x65) && digit(c2)) {
|
|
|
code = consume();
|
|
|
- repr += stringFromCode(code);
|
|
|
+ repr += String.fromCodePoint(code);
|
|
|
code = consume();
|
|
|
- repr += stringFromCode(code);
|
|
|
+ repr += String.fromCodePoint(code);
|
|
|
type = "number";
|
|
|
while (digit(next())) {
|
|
|
code = consume();
|
|
|
- repr += stringFromCode(code);
|
|
|
+ repr += String.fromCodePoint(code);
|
|
|
}
|
|
|
} else if ((c1 == 0x45 || c1 == 0x65) && (c2 == 0x2b || c2 == 0x2d) && digit(c3)) {
|
|
|
code = consume();
|
|
|
- repr += stringFromCode(code);
|
|
|
+ repr += String.fromCodePoint(code);
|
|
|
code = consume();
|
|
|
- repr += stringFromCode(code);
|
|
|
+ repr += String.fromCodePoint(code);
|
|
|
code = consume();
|
|
|
- repr += stringFromCode(code);
|
|
|
+ repr += String.fromCodePoint(code);
|
|
|
type = "number";
|
|
|
while (digit(next())) {
|
|
|
code = consume();
|
|
|
- repr += stringFromCode(code);
|
|
|
+ repr += String.fromCodePoint(code);
|
|
|
}
|
|
|
}
|
|
|
const value = convertAStringToANumber(repr);
|
|
|
@@ -501,6 +480,7 @@ this.parseCss = this.parseCss || (() => {
|
|
|
str = preprocess(str);
|
|
|
let i = -1;
|
|
|
const tokens = [];
|
|
|
+ const strLength = str.length;
|
|
|
let code;
|
|
|
|
|
|
// Line number information.
|
|
|
@@ -517,7 +497,7 @@ this.parseCss = this.parseCss || (() => {
|
|
|
const locStart = { line, column };
|
|
|
|
|
|
const codepoint = function (i) {
|
|
|
- if (i >= str.length) {
|
|
|
+ if (i >= strLength) {
|
|
|
return -1;
|
|
|
}
|
|
|
return str[i];
|
|
|
@@ -562,7 +542,7 @@ this.parseCss = this.parseCss || (() => {
|
|
|
while (!eof(next())) {
|
|
|
tokens.push(consumeAToken(consume, next, eof, reconsume, parseerror, donothing));
|
|
|
iterationCount++;
|
|
|
- if (iterationCount > str.length * 2) return "I'm infinite-looping!";
|
|
|
+ if (iterationCount > strLength * 2) return "I'm infinite-looping!";
|
|
|
}
|
|
|
return tokens;
|
|
|
}
|