|
@@ -6,7 +6,7 @@
|
|
|
* It is free to use for any purpose. No attribution, permission, or reproduction of this license is require
|
|
* It is free to use for any purpose. No attribution, permission, or reproduction of this license is require
|
|
|
*/
|
|
*/
|
|
|
|
|
|
|
|
-// Modified by Gildas Lormeau (ES5 -> ES6)
|
|
|
|
|
|
|
+// Modified by Gildas Lormeau (ES5 -> ES6, removed unused code)
|
|
|
|
|
|
|
|
// https://github.com/tabatkins/parse-css
|
|
// https://github.com/tabatkins/parse-css
|
|
|
this.parseCss = this.parseCss || (() => {
|
|
this.parseCss = this.parseCss || (() => {
|
|
@@ -23,7 +23,6 @@ this.parseCss = this.parseCss || (() => {
|
|
|
function nonprintable(code) { return between(code, 0, 8) || code == 0xb || between(code, 0xe, 0x1f) || code == 0x7f; }
|
|
function nonprintable(code) { return between(code, 0, 8) || code == 0xb || between(code, 0xe, 0x1f) || code == 0x7f; }
|
|
|
function newline(code) { return code == 0xa; }
|
|
function newline(code) { return code == 0xa; }
|
|
|
function whitespace(code) { return newline(code) || code == 9 || code == 0x20; }
|
|
function whitespace(code) { return newline(code) || code == 9 || code == 0x20; }
|
|
|
- // function badescape(code) { return newline(code) || isNaN(code); }
|
|
|
|
|
|
|
|
|
|
const maximumallowedcodepoint = 0x10ffff;
|
|
const maximumallowedcodepoint = 0x10ffff;
|
|
|
|
|
|
|
@@ -204,11 +203,7 @@ this.parseCss = this.parseCss || (() => {
|
|
|
}
|
|
}
|
|
|
}
|
|
}
|
|
|
else if (code == 0x40) {
|
|
else if (code == 0x40) {
|
|
|
- if (wouldStartAnIdentifier(next(1), next(2), next(3))) {
|
|
|
|
|
- return new AtKeywordToken(consumeAName());
|
|
|
|
|
- } else {
|
|
|
|
|
- return new DelimToken(code);
|
|
|
|
|
- }
|
|
|
|
|
|
|
+ return new DelimToken(code);
|
|
|
}
|
|
}
|
|
|
else if (code == 0x5b) return new OpenSquareToken();
|
|
else if (code == 0x5b) return new OpenSquareToken();
|
|
|
else if (code == 0x5c) {
|
|
else if (code == 0x5c) {
|
|
@@ -265,7 +260,7 @@ this.parseCss = this.parseCss || (() => {
|
|
|
const consumeComments = function () {
|
|
const consumeComments = function () {
|
|
|
while (next(1) == 0x2f && next(2) == 0x2a) {
|
|
while (next(1) == 0x2f && next(2) == 0x2a) {
|
|
|
consume(2);
|
|
consume(2);
|
|
|
- while (true) {
|
|
|
|
|
|
|
+ while (true) { // eslint-disable-line no-constant-condition
|
|
|
consume();
|
|
consume();
|
|
|
if (code == 0x2a && next() == 0x2f) {
|
|
if (code == 0x2a && next() == 0x2f) {
|
|
|
consume();
|
|
consume();
|
|
@@ -542,11 +537,7 @@ this.parseCss = this.parseCss || (() => {
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
function CSSParserToken() { throw "Abstract Base Class"; }
|
|
function CSSParserToken() { throw "Abstract Base Class"; }
|
|
|
- CSSParserToken.prototype.toJSON = function () {
|
|
|
|
|
- return { token: this.tokenType };
|
|
|
|
|
- };
|
|
|
|
|
CSSParserToken.prototype.toString = function () { return this.tokenType; };
|
|
CSSParserToken.prototype.toString = function () { return this.tokenType; };
|
|
|
- CSSParserToken.prototype.toSource = function () { return "" + this; };
|
|
|
|
|
|
|
|
|
|
function BadStringToken() { return this; }
|
|
function BadStringToken() { return this; }
|
|
|
BadStringToken.prototype = Object.create(CSSParserToken.prototype);
|
|
BadStringToken.prototype = Object.create(CSSParserToken.prototype);
|
|
@@ -560,17 +551,14 @@ this.parseCss = this.parseCss || (() => {
|
|
|
WhitespaceToken.prototype = Object.create(CSSParserToken.prototype);
|
|
WhitespaceToken.prototype = Object.create(CSSParserToken.prototype);
|
|
|
WhitespaceToken.prototype.tokenType = "WHITESPACE";
|
|
WhitespaceToken.prototype.tokenType = "WHITESPACE";
|
|
|
WhitespaceToken.prototype.toString = function () { return "WS"; };
|
|
WhitespaceToken.prototype.toString = function () { return "WS"; };
|
|
|
- WhitespaceToken.prototype.toSource = function () { return " "; };
|
|
|
|
|
|
|
|
|
|
function CDOToken() { return this; }
|
|
function CDOToken() { return this; }
|
|
|
CDOToken.prototype = Object.create(CSSParserToken.prototype);
|
|
CDOToken.prototype = Object.create(CSSParserToken.prototype);
|
|
|
CDOToken.prototype.tokenType = "CDO";
|
|
CDOToken.prototype.tokenType = "CDO";
|
|
|
- CDOToken.prototype.toSource = function () { return "<!--"; };
|
|
|
|
|
|
|
|
|
|
function CDCToken() { return this; }
|
|
function CDCToken() { return this; }
|
|
|
CDCToken.prototype = Object.create(CSSParserToken.prototype);
|
|
CDCToken.prototype = Object.create(CSSParserToken.prototype);
|
|
|
CDCToken.prototype.tokenType = "CDC";
|
|
CDCToken.prototype.tokenType = "CDC";
|
|
|
- CDCToken.prototype.toSource = function () { return "-->"; };
|
|
|
|
|
|
|
|
|
|
function ColonToken() { return this; }
|
|
function ColonToken() { return this; }
|
|
|
ColonToken.prototype = Object.create(CSSParserToken.prototype);
|
|
ColonToken.prototype = Object.create(CSSParserToken.prototype);
|
|
@@ -638,7 +626,6 @@ this.parseCss = this.parseCss || (() => {
|
|
|
function EOFToken() { return this; }
|
|
function EOFToken() { return this; }
|
|
|
EOFToken.prototype = Object.create(CSSParserToken.prototype);
|
|
EOFToken.prototype = Object.create(CSSParserToken.prototype);
|
|
|
EOFToken.prototype.tokenType = "EOF";
|
|
EOFToken.prototype.tokenType = "EOF";
|
|
|
- EOFToken.prototype.toSource = function () { return ""; };
|
|
|
|
|
|
|
|
|
|
function DelimToken(code) {
|
|
function DelimToken(code) {
|
|
|
this.value = stringFromCode(code);
|
|
this.value = stringFromCode(code);
|
|
@@ -647,28 +634,12 @@ this.parseCss = this.parseCss || (() => {
|
|
|
DelimToken.prototype = Object.create(CSSParserToken.prototype);
|
|
DelimToken.prototype = Object.create(CSSParserToken.prototype);
|
|
|
DelimToken.prototype.tokenType = "DELIM";
|
|
DelimToken.prototype.tokenType = "DELIM";
|
|
|
DelimToken.prototype.toString = function () { return "DELIM(" + this.value + ")"; };
|
|
DelimToken.prototype.toString = function () { return "DELIM(" + this.value + ")"; };
|
|
|
- DelimToken.prototype.toJSON = function () {
|
|
|
|
|
- const json = this.constructor.prototype.constructor.prototype.toJSON.call(this);
|
|
|
|
|
- json.value = this.value;
|
|
|
|
|
- return json;
|
|
|
|
|
- };
|
|
|
|
|
- DelimToken.prototype.toSource = function () {
|
|
|
|
|
- if (this.value == "\\")
|
|
|
|
|
- return "\\\n";
|
|
|
|
|
- else
|
|
|
|
|
- return this.value;
|
|
|
|
|
- };
|
|
|
|
|
|
|
|
|
|
function StringValuedToken() { throw "Abstract Base Class"; }
|
|
function StringValuedToken() { throw "Abstract Base Class"; }
|
|
|
StringValuedToken.prototype = Object.create(CSSParserToken.prototype);
|
|
StringValuedToken.prototype = Object.create(CSSParserToken.prototype);
|
|
|
StringValuedToken.prototype.ASCIIMatch = function (str) {
|
|
StringValuedToken.prototype.ASCIIMatch = function (str) {
|
|
|
return this.value.toLowerCase() == str.toLowerCase();
|
|
return this.value.toLowerCase() == str.toLowerCase();
|
|
|
};
|
|
};
|
|
|
- StringValuedToken.prototype.toJSON = function () {
|
|
|
|
|
- const json = this.constructor.prototype.constructor.prototype.toJSON.call(this);
|
|
|
|
|
- json.value = this.value;
|
|
|
|
|
- return json;
|
|
|
|
|
- };
|
|
|
|
|
|
|
|
|
|
function IdentToken(val) {
|
|
function IdentToken(val) {
|
|
|
this.value = val;
|
|
this.value = val;
|
|
@@ -676,9 +647,6 @@ this.parseCss = this.parseCss || (() => {
|
|
|
IdentToken.prototype = Object.create(StringValuedToken.prototype);
|
|
IdentToken.prototype = Object.create(StringValuedToken.prototype);
|
|
|
IdentToken.prototype.tokenType = "IDENT";
|
|
IdentToken.prototype.tokenType = "IDENT";
|
|
|
IdentToken.prototype.toString = function () { return "IDENT(" + this.value + ")"; };
|
|
IdentToken.prototype.toString = function () { return "IDENT(" + this.value + ")"; };
|
|
|
- IdentToken.prototype.toSource = function () {
|
|
|
|
|
- return escapeIdent(this.value);
|
|
|
|
|
- };
|
|
|
|
|
|
|
|
|
|
function FunctionToken(val) {
|
|
function FunctionToken(val) {
|
|
|
this.value = val;
|
|
this.value = val;
|
|
@@ -687,19 +655,6 @@ this.parseCss = this.parseCss || (() => {
|
|
|
FunctionToken.prototype = Object.create(StringValuedToken.prototype);
|
|
FunctionToken.prototype = Object.create(StringValuedToken.prototype);
|
|
|
FunctionToken.prototype.tokenType = "FUNCTION";
|
|
FunctionToken.prototype.tokenType = "FUNCTION";
|
|
|
FunctionToken.prototype.toString = function () { return "FUNCTION(" + this.value + ")"; };
|
|
FunctionToken.prototype.toString = function () { return "FUNCTION(" + this.value + ")"; };
|
|
|
- FunctionToken.prototype.toSource = function () {
|
|
|
|
|
- return escapeIdent(this.value) + "(";
|
|
|
|
|
- };
|
|
|
|
|
-
|
|
|
|
|
- function AtKeywordToken(val) {
|
|
|
|
|
- this.value = val;
|
|
|
|
|
- }
|
|
|
|
|
- AtKeywordToken.prototype = Object.create(StringValuedToken.prototype);
|
|
|
|
|
- AtKeywordToken.prototype.tokenType = "AT-KEYWORD";
|
|
|
|
|
- AtKeywordToken.prototype.toString = function () { return "AT(" + this.value + ")"; };
|
|
|
|
|
- AtKeywordToken.prototype.toSource = function () {
|
|
|
|
|
- return "@" + escapeIdent(this.value);
|
|
|
|
|
- };
|
|
|
|
|
|
|
|
|
|
function HashToken(val) {
|
|
function HashToken(val) {
|
|
|
this.value = val;
|
|
this.value = val;
|
|
@@ -708,28 +663,12 @@ this.parseCss = this.parseCss || (() => {
|
|
|
HashToken.prototype = Object.create(StringValuedToken.prototype);
|
|
HashToken.prototype = Object.create(StringValuedToken.prototype);
|
|
|
HashToken.prototype.tokenType = "HASH";
|
|
HashToken.prototype.tokenType = "HASH";
|
|
|
HashToken.prototype.toString = function () { return "HASH(" + this.value + ")"; };
|
|
HashToken.prototype.toString = function () { return "HASH(" + this.value + ")"; };
|
|
|
- HashToken.prototype.toJSON = function () {
|
|
|
|
|
- const json = this.constructor.prototype.constructor.prototype.toJSON.call(this);
|
|
|
|
|
- json.value = this.value;
|
|
|
|
|
- json.type = this.type;
|
|
|
|
|
- return json;
|
|
|
|
|
- };
|
|
|
|
|
- HashToken.prototype.toSource = function () {
|
|
|
|
|
- if (this.type == "id") {
|
|
|
|
|
- return "#" + escapeIdent(this.value);
|
|
|
|
|
- } else {
|
|
|
|
|
- return "#" + escapeHash(this.value);
|
|
|
|
|
- }
|
|
|
|
|
- };
|
|
|
|
|
|
|
|
|
|
function StringToken(val) {
|
|
function StringToken(val) {
|
|
|
this.value = val;
|
|
this.value = val;
|
|
|
}
|
|
}
|
|
|
StringToken.prototype = Object.create(StringValuedToken.prototype);
|
|
StringToken.prototype = Object.create(StringValuedToken.prototype);
|
|
|
StringToken.prototype.tokenType = "STRING";
|
|
StringToken.prototype.tokenType = "STRING";
|
|
|
- StringToken.prototype.toString = function () {
|
|
|
|
|
- return "\"" + escapeString(this.value) + "\"";
|
|
|
|
|
- };
|
|
|
|
|
|
|
|
|
|
function URLToken(val) {
|
|
function URLToken(val) {
|
|
|
this.value = val;
|
|
this.value = val;
|
|
@@ -737,9 +676,6 @@ this.parseCss = this.parseCss || (() => {
|
|
|
URLToken.prototype = Object.create(StringValuedToken.prototype);
|
|
URLToken.prototype = Object.create(StringValuedToken.prototype);
|
|
|
URLToken.prototype.tokenType = "URL";
|
|
URLToken.prototype.tokenType = "URL";
|
|
|
URLToken.prototype.toString = function () { return "URL(" + this.value + ")"; };
|
|
URLToken.prototype.toString = function () { return "URL(" + this.value + ")"; };
|
|
|
- URLToken.prototype.toSource = function () {
|
|
|
|
|
- return "url(\"" + escapeString(this.value) + "\")";
|
|
|
|
|
- };
|
|
|
|
|
|
|
|
|
|
function NumberToken() {
|
|
function NumberToken() {
|
|
|
this.value = null;
|
|
this.value = null;
|
|
@@ -753,14 +689,6 @@ this.parseCss = this.parseCss || (() => {
|
|
|
return "INT(" + this.value + ")";
|
|
return "INT(" + this.value + ")";
|
|
|
return "NUMBER(" + this.value + ")";
|
|
return "NUMBER(" + this.value + ")";
|
|
|
};
|
|
};
|
|
|
- NumberToken.prototype.toJSON = function () {
|
|
|
|
|
- const json = this.constructor.prototype.constructor.prototype.toJSON.call(this);
|
|
|
|
|
- json.value = this.value;
|
|
|
|
|
- json.type = this.type;
|
|
|
|
|
- json.repr = this.repr;
|
|
|
|
|
- return json;
|
|
|
|
|
- };
|
|
|
|
|
- NumberToken.prototype.toSource = function () { return this.repr; };
|
|
|
|
|
|
|
|
|
|
function PercentageToken() {
|
|
function PercentageToken() {
|
|
|
this.value = null;
|
|
this.value = null;
|
|
@@ -769,13 +697,6 @@ this.parseCss = this.parseCss || (() => {
|
|
|
PercentageToken.prototype = Object.create(CSSParserToken.prototype);
|
|
PercentageToken.prototype = Object.create(CSSParserToken.prototype);
|
|
|
PercentageToken.prototype.tokenType = "PERCENTAGE";
|
|
PercentageToken.prototype.tokenType = "PERCENTAGE";
|
|
|
PercentageToken.prototype.toString = function () { return "PERCENTAGE(" + this.value + ")"; };
|
|
PercentageToken.prototype.toString = function () { return "PERCENTAGE(" + this.value + ")"; };
|
|
|
- PercentageToken.prototype.toJSON = function () {
|
|
|
|
|
- const json = this.constructor.prototype.constructor.prototype.toJSON.call(this);
|
|
|
|
|
- json.value = this.value;
|
|
|
|
|
- json.repr = this.repr;
|
|
|
|
|
- return json;
|
|
|
|
|
- };
|
|
|
|
|
- PercentageToken.prototype.toSource = function () { return this.repr + "%"; };
|
|
|
|
|
|
|
|
|
|
function DimensionToken() {
|
|
function DimensionToken() {
|
|
|
this.value = null;
|
|
this.value = null;
|
|
@@ -786,106 +707,6 @@ this.parseCss = this.parseCss || (() => {
|
|
|
DimensionToken.prototype = Object.create(CSSParserToken.prototype);
|
|
DimensionToken.prototype = Object.create(CSSParserToken.prototype);
|
|
|
DimensionToken.prototype.tokenType = "DIMENSION";
|
|
DimensionToken.prototype.tokenType = "DIMENSION";
|
|
|
DimensionToken.prototype.toString = function () { return "DIM(" + this.value + "," + this.unit + ")"; };
|
|
DimensionToken.prototype.toString = function () { return "DIM(" + this.value + "," + this.unit + ")"; };
|
|
|
- DimensionToken.prototype.toJSON = function () {
|
|
|
|
|
- const json = this.constructor.prototype.constructor.prototype.toJSON.call(this);
|
|
|
|
|
- json.value = this.value;
|
|
|
|
|
- json.type = this.type;
|
|
|
|
|
- json.repr = this.repr;
|
|
|
|
|
- json.unit = this.unit;
|
|
|
|
|
- return json;
|
|
|
|
|
- };
|
|
|
|
|
- DimensionToken.prototype.toSource = function () {
|
|
|
|
|
- const source = this.repr;
|
|
|
|
|
- let unit = escapeIdent(this.unit);
|
|
|
|
|
- if (unit[0].toLowerCase() == "e" && (unit[1] == "-" || between(unit.charCodeAt(1), 0x30, 0x39))) {
|
|
|
|
|
- // Unit is ambiguous with scinot
|
|
|
|
|
- // Remove the leading "e", replace with escape.
|
|
|
|
|
- unit = "\\65 " + unit.slice(1, unit.length);
|
|
|
|
|
- }
|
|
|
|
|
- return source + unit;
|
|
|
|
|
- };
|
|
|
|
|
-
|
|
|
|
|
- function escapeIdent(string) {
|
|
|
|
|
- string = "" + string;
|
|
|
|
|
- let result = "";
|
|
|
|
|
- const firstcode = string.charCodeAt(0);
|
|
|
|
|
- for (let i = 0; i < string.length; i++) {
|
|
|
|
|
- const code = string.charCodeAt(i);
|
|
|
|
|
- if (code == 0x0) {
|
|
|
|
|
- throw new InvalidCharacterError("Invalid character: the input contains U+0000.");
|
|
|
|
|
- }
|
|
|
|
|
-
|
|
|
|
|
- if (
|
|
|
|
|
- between(code, 0x1, 0x1f) || code == 0x7f ||
|
|
|
|
|
- (i == 0 && between(code, 0x30, 0x39)) ||
|
|
|
|
|
- (i == 1 && between(code, 0x30, 0x39) && firstcode == 0x2d)
|
|
|
|
|
- ) {
|
|
|
|
|
- result += "\\" + code.toString(16) + " ";
|
|
|
|
|
- } else if (
|
|
|
|
|
- code >= 0x80 ||
|
|
|
|
|
- code == 0x2d ||
|
|
|
|
|
- code == 0x5f ||
|
|
|
|
|
- between(code, 0x30, 0x39) ||
|
|
|
|
|
- between(code, 0x41, 0x5a) ||
|
|
|
|
|
- between(code, 0x61, 0x7a)
|
|
|
|
|
- ) {
|
|
|
|
|
- result += string[i];
|
|
|
|
|
- } else {
|
|
|
|
|
- result += "\\" + string[i];
|
|
|
|
|
- }
|
|
|
|
|
- }
|
|
|
|
|
- return result;
|
|
|
|
|
- }
|
|
|
|
|
-
|
|
|
|
|
- function escapeHash(string) {
|
|
|
|
|
- // Escapes the contents of "unrestricted"-type hash tokens.
|
|
|
|
|
- // Won't preserve the ID-ness of "id"-type hash tokens;
|
|
|
|
|
- // use escapeIdent() for that.
|
|
|
|
|
- string = "" + string;
|
|
|
|
|
- let result = "";
|
|
|
|
|
- // let firstcode = string.charCodeAt(0);
|
|
|
|
|
- for (let i = 0; i < string.length; i++) {
|
|
|
|
|
- const code = string.charCodeAt(i);
|
|
|
|
|
- if (code == 0x0) {
|
|
|
|
|
- throw new InvalidCharacterError("Invalid character: the input contains U+0000.");
|
|
|
|
|
- }
|
|
|
|
|
-
|
|
|
|
|
- if (
|
|
|
|
|
- code >= 0x80 ||
|
|
|
|
|
- code == 0x2d ||
|
|
|
|
|
- code == 0x5f ||
|
|
|
|
|
- between(code, 0x30, 0x39) ||
|
|
|
|
|
- between(code, 0x41, 0x5a) ||
|
|
|
|
|
- between(code, 0x61, 0x7a)
|
|
|
|
|
- ) {
|
|
|
|
|
- result += string[i];
|
|
|
|
|
- } else {
|
|
|
|
|
- result += "\\" + code.toString(16) + " ";
|
|
|
|
|
- }
|
|
|
|
|
- }
|
|
|
|
|
- return result;
|
|
|
|
|
- }
|
|
|
|
|
-
|
|
|
|
|
- function escapeString(string) {
|
|
|
|
|
- string = "" + string;
|
|
|
|
|
- let result = "";
|
|
|
|
|
- for (let i = 0; i < string.length; i++) {
|
|
|
|
|
- const code = string.charCodeAt(i);
|
|
|
|
|
-
|
|
|
|
|
- if (code == 0x0) {
|
|
|
|
|
- throw new InvalidCharacterError("Invalid character: the input contains U+0000.");
|
|
|
|
|
- }
|
|
|
|
|
-
|
|
|
|
|
- if (between(code, 0x1, 0x1f) || code == 0x7f) {
|
|
|
|
|
- result += "\\" + code.toString(16) + " ";
|
|
|
|
|
- } else if (code == 0x22 || code == 0x5c) {
|
|
|
|
|
- result += "\\" + string[i];
|
|
|
|
|
- } else {
|
|
|
|
|
- result += string[i];
|
|
|
|
|
- }
|
|
|
|
|
- }
|
|
|
|
|
- return result;
|
|
|
|
|
- }
|
|
|
|
|
|
|
|
|
|
// ---
|
|
// ---
|
|
|
function TokenStream(tokens) {
|
|
function TokenStream(tokens) {
|
|
@@ -917,66 +738,6 @@ this.parseCss = this.parseCss || (() => {
|
|
|
}
|
|
}
|
|
|
function donothing() { return true; }
|
|
function donothing() { return true; }
|
|
|
|
|
|
|
|
- function consumeAListOfRules(s, topLevel) {
|
|
|
|
|
- const rules = [];
|
|
|
|
|
- let rule;
|
|
|
|
|
- while (s.consume()) {
|
|
|
|
|
- if (s.token instanceof WhitespaceToken) {
|
|
|
|
|
- continue;
|
|
|
|
|
- } else if (s.token instanceof EOFToken) {
|
|
|
|
|
- return rules;
|
|
|
|
|
- } else if (s.token instanceof CDOToken || s.token instanceof CDCToken) {
|
|
|
|
|
- if (topLevel == "top-level") continue;
|
|
|
|
|
- s.reconsume();
|
|
|
|
|
- if (rule = consumeAQualifiedRule(s)) rules.push(rule);
|
|
|
|
|
- } else if (s.token instanceof AtKeywordToken) {
|
|
|
|
|
- s.reconsume();
|
|
|
|
|
- if (rule = consumeAnAtRule(s)) rules.push(rule);
|
|
|
|
|
- } else {
|
|
|
|
|
- s.reconsume();
|
|
|
|
|
- if (rule = consumeAQualifiedRule(s)) rules.push(rule);
|
|
|
|
|
- }
|
|
|
|
|
- }
|
|
|
|
|
- }
|
|
|
|
|
-
|
|
|
|
|
- function consumeAnAtRule(s) {
|
|
|
|
|
- s.consume();
|
|
|
|
|
- const rule = new AtRule(s.token.value);
|
|
|
|
|
- while (s.consume()) {
|
|
|
|
|
- if (s.token instanceof SemicolonToken || s.token instanceof EOFToken) {
|
|
|
|
|
- return rule;
|
|
|
|
|
- } else if (s.token instanceof OpenCurlyToken) {
|
|
|
|
|
- rule.value = consumeASimpleBlock(s);
|
|
|
|
|
- return rule;
|
|
|
|
|
- } else if (s.token instanceof SimpleBlock && s.token.name == "{") {
|
|
|
|
|
- rule.value = s.token;
|
|
|
|
|
- return rule;
|
|
|
|
|
- } else {
|
|
|
|
|
- s.reconsume();
|
|
|
|
|
- rule.prelude.push(consumeAComponentValue(s));
|
|
|
|
|
- }
|
|
|
|
|
- }
|
|
|
|
|
- }
|
|
|
|
|
-
|
|
|
|
|
- function consumeAQualifiedRule(s) {
|
|
|
|
|
- const rule = new QualifiedRule();
|
|
|
|
|
- while (s.consume()) {
|
|
|
|
|
- if (s.token instanceof EOFToken) {
|
|
|
|
|
- parseerror(s, "Hit EOF when trying to parse the prelude of a qualified rule.");
|
|
|
|
|
- return;
|
|
|
|
|
- } else if (s.token instanceof OpenCurlyToken) {
|
|
|
|
|
- rule.value = consumeASimpleBlock(s);
|
|
|
|
|
- return rule;
|
|
|
|
|
- } else if (s.token instanceof SimpleBlock && s.token.name == "{") {
|
|
|
|
|
- rule.value = s.token;
|
|
|
|
|
- return rule;
|
|
|
|
|
- } else {
|
|
|
|
|
- s.reconsume();
|
|
|
|
|
- rule.prelude.push(consumeAComponentValue(s));
|
|
|
|
|
- }
|
|
|
|
|
- }
|
|
|
|
|
- }
|
|
|
|
|
-
|
|
|
|
|
function consumeAListOfDeclarations(s) {
|
|
function consumeAListOfDeclarations(s) {
|
|
|
const decls = [];
|
|
const decls = [];
|
|
|
while (s.consume()) {
|
|
while (s.consume()) {
|
|
@@ -984,15 +745,12 @@ this.parseCss = this.parseCss || (() => {
|
|
|
donothing();
|
|
donothing();
|
|
|
} else if (s.token instanceof EOFToken) {
|
|
} else if (s.token instanceof EOFToken) {
|
|
|
return decls;
|
|
return decls;
|
|
|
- } else if (s.token instanceof AtKeywordToken) {
|
|
|
|
|
- s.reconsume();
|
|
|
|
|
- decls.push(consumeAnAtRule(s));
|
|
|
|
|
} else if (s.token instanceof IdentToken) {
|
|
} else if (s.token instanceof IdentToken) {
|
|
|
const temp = [s.token];
|
|
const temp = [s.token];
|
|
|
while (!(s.next() instanceof SemicolonToken || s.next() instanceof EOFToken))
|
|
while (!(s.next() instanceof SemicolonToken || s.next() instanceof EOFToken))
|
|
|
temp.push(consumeAComponentValue(s));
|
|
temp.push(consumeAComponentValue(s));
|
|
|
- let decl;
|
|
|
|
|
- if (decl = consumeADeclaration(new TokenStream(temp))) decls.push(decl);
|
|
|
|
|
|
|
+ let decl = consumeADeclaration(new TokenStream(temp));
|
|
|
|
|
+ if (decl) decls.push(decl);
|
|
|
} else {
|
|
} else {
|
|
|
parseerror(s);
|
|
parseerror(s);
|
|
|
s.reconsume();
|
|
s.reconsume();
|
|
@@ -1035,26 +793,11 @@ this.parseCss = this.parseCss || (() => {
|
|
|
|
|
|
|
|
function consumeAComponentValue(s) {
|
|
function consumeAComponentValue(s) {
|
|
|
s.consume();
|
|
s.consume();
|
|
|
- if (s.token instanceof OpenCurlyToken || s.token instanceof OpenSquareToken || s.token instanceof OpenParenToken)
|
|
|
|
|
- return consumeASimpleBlock(s);
|
|
|
|
|
if (s.token instanceof FunctionToken)
|
|
if (s.token instanceof FunctionToken)
|
|
|
return consumeAFunction(s);
|
|
return consumeAFunction(s);
|
|
|
return s.token;
|
|
return s.token;
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
- function consumeASimpleBlock(s) {
|
|
|
|
|
- const mirror = s.token.mirror;
|
|
|
|
|
- const block = new SimpleBlock(s.token.value);
|
|
|
|
|
- while (s.consume()) {
|
|
|
|
|
- if (s.token instanceof EOFToken || (s.token instanceof GroupingToken && s.token.value == mirror))
|
|
|
|
|
- return block;
|
|
|
|
|
- else {
|
|
|
|
|
- s.reconsume();
|
|
|
|
|
- block.value.push(consumeAComponentValue(s));
|
|
|
|
|
- }
|
|
|
|
|
- }
|
|
|
|
|
- }
|
|
|
|
|
-
|
|
|
|
|
function consumeAFunction(s) {
|
|
function consumeAFunction(s) {
|
|
|
const func = new Func(s.token.value);
|
|
const func = new Func(s.token.value);
|
|
|
while (s.consume()) {
|
|
while (s.consume()) {
|
|
@@ -1070,145 +813,15 @@ this.parseCss = this.parseCss || (() => {
|
|
|
function normalizeInput(input) {
|
|
function normalizeInput(input) {
|
|
|
if (typeof input == "string")
|
|
if (typeof input == "string")
|
|
|
return new TokenStream(tokenize(input));
|
|
return new TokenStream(tokenize(input));
|
|
|
- if (input instanceof TokenStream)
|
|
|
|
|
- return input;
|
|
|
|
|
- if (input.length !== undefined)
|
|
|
|
|
- return new TokenStream(input);
|
|
|
|
|
else throw SyntaxError(input);
|
|
else throw SyntaxError(input);
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
- function parseAStylesheet(s) {
|
|
|
|
|
- s = normalizeInput(s);
|
|
|
|
|
- const sheet = new Stylesheet();
|
|
|
|
|
- sheet.value = consumeAListOfRules(s, "top-level");
|
|
|
|
|
- return sheet;
|
|
|
|
|
- }
|
|
|
|
|
-
|
|
|
|
|
- function parseAListOfRules(s) {
|
|
|
|
|
- s = normalizeInput(s);
|
|
|
|
|
- return consumeAListOfRules(s);
|
|
|
|
|
- }
|
|
|
|
|
-
|
|
|
|
|
- function parseARule(s) {
|
|
|
|
|
- s = normalizeInput(s);
|
|
|
|
|
- while (s.next() instanceof WhitespaceToken) s.consume();
|
|
|
|
|
- if (s.next() instanceof EOFToken) throw SyntaxError();
|
|
|
|
|
- let rule;
|
|
|
|
|
- if (s.next() instanceof AtKeywordToken) {
|
|
|
|
|
- rule = consumeAnAtRule(s);
|
|
|
|
|
- } else {
|
|
|
|
|
- rule = consumeAQualifiedRule(s);
|
|
|
|
|
- if (!rule) throw SyntaxError();
|
|
|
|
|
- }
|
|
|
|
|
- while (s.next() instanceof WhitespaceToken) s.consume();
|
|
|
|
|
- if (s.next() instanceof EOFToken)
|
|
|
|
|
- return rule;
|
|
|
|
|
- throw SyntaxError();
|
|
|
|
|
- }
|
|
|
|
|
-
|
|
|
|
|
- function parseADeclaration(s) {
|
|
|
|
|
- s = normalizeInput(s);
|
|
|
|
|
- while (s.next() instanceof WhitespaceToken) s.consume();
|
|
|
|
|
- if (!(s.next() instanceof IdentToken)) throw SyntaxError();
|
|
|
|
|
- const decl = consumeADeclaration(s);
|
|
|
|
|
- if (decl)
|
|
|
|
|
- return decl;
|
|
|
|
|
- else
|
|
|
|
|
- throw SyntaxError();
|
|
|
|
|
- }
|
|
|
|
|
-
|
|
|
|
|
function parseAListOfDeclarations(s) {
|
|
function parseAListOfDeclarations(s) {
|
|
|
s = normalizeInput(s);
|
|
s = normalizeInput(s);
|
|
|
return consumeAListOfDeclarations(s);
|
|
return consumeAListOfDeclarations(s);
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
- function parseAComponentValue(s) {
|
|
|
|
|
- s = normalizeInput(s);
|
|
|
|
|
- while (s.next() instanceof WhitespaceToken) s.consume();
|
|
|
|
|
- if (s.next() instanceof EOFToken) throw SyntaxError();
|
|
|
|
|
- const val = consumeAComponentValue(s);
|
|
|
|
|
- if (!val) throw SyntaxError();
|
|
|
|
|
- while (s.next() instanceof WhitespaceToken) s.consume();
|
|
|
|
|
- if (s.next() instanceof EOFToken)
|
|
|
|
|
- return val;
|
|
|
|
|
- throw SyntaxError();
|
|
|
|
|
- }
|
|
|
|
|
-
|
|
|
|
|
- function parseAListOfComponentValues(s) {
|
|
|
|
|
- s = normalizeInput(s);
|
|
|
|
|
- const vals = [];
|
|
|
|
|
- while (true) {
|
|
|
|
|
- const val = consumeAComponentValue(s);
|
|
|
|
|
- if (val instanceof EOFToken)
|
|
|
|
|
- return vals;
|
|
|
|
|
- else
|
|
|
|
|
- vals.push(val);
|
|
|
|
|
- }
|
|
|
|
|
- }
|
|
|
|
|
-
|
|
|
|
|
- function parseACommaSeparatedListOfComponentValues(s) {
|
|
|
|
|
- s = normalizeInput(s);
|
|
|
|
|
- const listOfCVLs = [];
|
|
|
|
|
- while (true) {
|
|
|
|
|
- const vals = [];
|
|
|
|
|
- while (true) {
|
|
|
|
|
- const val = consumeAComponentValue(s);
|
|
|
|
|
- if (val instanceof EOFToken) {
|
|
|
|
|
- listOfCVLs.push(vals);
|
|
|
|
|
- return listOfCVLs;
|
|
|
|
|
- } else if (val instanceof CommaToken) {
|
|
|
|
|
- listOfCVLs.push(vals);
|
|
|
|
|
- break;
|
|
|
|
|
- } else {
|
|
|
|
|
- vals.push(val);
|
|
|
|
|
- }
|
|
|
|
|
- }
|
|
|
|
|
- }
|
|
|
|
|
- }
|
|
|
|
|
-
|
|
|
|
|
-
|
|
|
|
|
function CSSParserRule() { throw "Abstract Base Class"; }
|
|
function CSSParserRule() { throw "Abstract Base Class"; }
|
|
|
- CSSParserRule.prototype.toString = function (indent) {
|
|
|
|
|
- return JSON.stringify(this, null, indent);
|
|
|
|
|
- };
|
|
|
|
|
- CSSParserRule.prototype.toJSON = function () {
|
|
|
|
|
- return { type: this.type, value: this.value };
|
|
|
|
|
- };
|
|
|
|
|
-
|
|
|
|
|
- function Stylesheet() {
|
|
|
|
|
- this.value = [];
|
|
|
|
|
- return this;
|
|
|
|
|
- }
|
|
|
|
|
- Stylesheet.prototype = Object.create(CSSParserRule.prototype);
|
|
|
|
|
- Stylesheet.prototype.type = "STYLESHEET";
|
|
|
|
|
-
|
|
|
|
|
- function AtRule(name) {
|
|
|
|
|
- this.name = name;
|
|
|
|
|
- this.prelude = [];
|
|
|
|
|
- this.value = null;
|
|
|
|
|
- return this;
|
|
|
|
|
- }
|
|
|
|
|
- AtRule.prototype = Object.create(CSSParserRule.prototype);
|
|
|
|
|
- AtRule.prototype.type = "AT-RULE";
|
|
|
|
|
- AtRule.prototype.toJSON = function () {
|
|
|
|
|
- const json = this.constructor.prototype.constructor.prototype.toJSON.call(this);
|
|
|
|
|
- json.name = this.name;
|
|
|
|
|
- json.prelude = this.prelude;
|
|
|
|
|
- return json;
|
|
|
|
|
- };
|
|
|
|
|
-
|
|
|
|
|
- function QualifiedRule() {
|
|
|
|
|
- this.prelude = [];
|
|
|
|
|
- this.value = [];
|
|
|
|
|
- return this;
|
|
|
|
|
- }
|
|
|
|
|
- QualifiedRule.prototype = Object.create(CSSParserRule.prototype);
|
|
|
|
|
- QualifiedRule.prototype.type = "QUALIFIED-RULE";
|
|
|
|
|
- QualifiedRule.prototype.toJSON = function () {
|
|
|
|
|
- const json = this.constructor.prototype.constructor.prototype.toJSON.call(this);
|
|
|
|
|
- json.prelude = this.prelude;
|
|
|
|
|
- return json;
|
|
|
|
|
- };
|
|
|
|
|
|
|
|
|
|
function Declaration(name) {
|
|
function Declaration(name) {
|
|
|
this.name = name;
|
|
this.name = name;
|
|
@@ -1218,25 +831,6 @@ this.parseCss = this.parseCss || (() => {
|
|
|
}
|
|
}
|
|
|
Declaration.prototype = Object.create(CSSParserRule.prototype);
|
|
Declaration.prototype = Object.create(CSSParserRule.prototype);
|
|
|
Declaration.prototype.type = "DECLARATION";
|
|
Declaration.prototype.type = "DECLARATION";
|
|
|
- Declaration.prototype.toJSON = function () {
|
|
|
|
|
- const json = this.constructor.prototype.constructor.prototype.toJSON.call(this);
|
|
|
|
|
- json.name = this.name;
|
|
|
|
|
- json.important = this.important;
|
|
|
|
|
- return json;
|
|
|
|
|
- };
|
|
|
|
|
-
|
|
|
|
|
- function SimpleBlock(type) {
|
|
|
|
|
- this.name = type;
|
|
|
|
|
- this.value = [];
|
|
|
|
|
- return this;
|
|
|
|
|
- }
|
|
|
|
|
- SimpleBlock.prototype = Object.create(CSSParserRule.prototype);
|
|
|
|
|
- SimpleBlock.prototype.type = "BLOCK";
|
|
|
|
|
- SimpleBlock.prototype.toJSON = function () {
|
|
|
|
|
- const json = this.constructor.prototype.constructor.prototype.toJSON.call(this);
|
|
|
|
|
- json.name = this.name;
|
|
|
|
|
- return json;
|
|
|
|
|
- };
|
|
|
|
|
|
|
|
|
|
function Func(name) {
|
|
function Func(name) {
|
|
|
this.name = name;
|
|
this.name = name;
|
|
@@ -1245,169 +839,11 @@ this.parseCss = this.parseCss || (() => {
|
|
|
}
|
|
}
|
|
|
Func.prototype = Object.create(CSSParserRule.prototype);
|
|
Func.prototype = Object.create(CSSParserRule.prototype);
|
|
|
Func.prototype.type = "FUNCTION";
|
|
Func.prototype.type = "FUNCTION";
|
|
|
- Func.prototype.toJSON = function () {
|
|
|
|
|
- const json = this.constructor.prototype.constructor.prototype.toJSON.call(this);
|
|
|
|
|
- json.name = this.name;
|
|
|
|
|
- return json;
|
|
|
|
|
- };
|
|
|
|
|
-
|
|
|
|
|
-
|
|
|
|
|
- /* Grammar Application */
|
|
|
|
|
-
|
|
|
|
|
- function canonicalize(rule, grammar, topGrammar) {
|
|
|
|
|
- if (grammar === undefined) grammar = CSSGrammar;
|
|
|
|
|
- if (topGrammar === undefined) topGrammar = grammar;
|
|
|
|
|
- let unknownTransformer;
|
|
|
|
|
- if (grammar) {
|
|
|
|
|
- if (grammar.stylesheet) grammar = topGrammar;
|
|
|
|
|
- unknownTransformer = grammar.unknown || function () { return; };
|
|
|
|
|
- }
|
|
|
|
|
- const ret = { "type": rule.type.toLowerCase() };
|
|
|
|
|
- let contents, unparsedContents;
|
|
|
|
|
- if (rule.type == "STYLESHEET") {
|
|
|
|
|
- contents = rule.value;
|
|
|
|
|
- } else if (rule.type == "BLOCK") {
|
|
|
|
|
- unparsedContents = rule.value;
|
|
|
|
|
- ret.name = rule.name;
|
|
|
|
|
- } else if (rule.type == "QUALIFIED-RULE") {
|
|
|
|
|
- unparsedContents = rule.value.value;
|
|
|
|
|
- ret.prelude = rule.prelude;
|
|
|
|
|
- } else if (rule.type == "AT-RULE") {
|
|
|
|
|
- unparsedContents = rule.value.value;
|
|
|
|
|
- ret.name = rule.name;
|
|
|
|
|
- ret.prelude = rule.prelude;
|
|
|
|
|
- } else if (rule.type == "DECLARATION") {
|
|
|
|
|
- // I don't do grammar-checking of declarations yet.
|
|
|
|
|
- ret.name = rule.name;
|
|
|
|
|
- ret.value = rule.value;
|
|
|
|
|
- ret.important = rule.important;
|
|
|
|
|
- return ret;
|
|
|
|
|
- }
|
|
|
|
|
- if (unparsedContents) {
|
|
|
|
|
- if (grammar.declarations) {
|
|
|
|
|
- contents = parseAListOfDeclarations(unparsedContents);
|
|
|
|
|
- } else if (grammar.qualified) {
|
|
|
|
|
- contents = parseAListOfRules(unparsedContents);
|
|
|
|
|
- }
|
|
|
|
|
- }
|
|
|
|
|
-
|
|
|
|
|
- if (!grammar) {
|
|
|
|
|
- return ret;
|
|
|
|
|
- } else if (grammar.declarations) {
|
|
|
|
|
- ret.declarations = {}; // simple key/value map of declarations
|
|
|
|
|
- ret.rules = []; // in-order list of both decls and at-rules
|
|
|
|
|
- ret.errors = [];
|
|
|
|
|
- for (let i = 0; i < contents.length; i++) {
|
|
|
|
|
- const rule = contents[i];
|
|
|
|
|
- if (rule instanceof Declaration) {
|
|
|
|
|
- const decl = canonicalize(rule, {}, topGrammar);
|
|
|
|
|
- ret.declarations[rule.name] = decl;
|
|
|
|
|
- ret.rules.push(decl);
|
|
|
|
|
- } else { // rule is instanceof AtRule
|
|
|
|
|
- const subGrammar = grammar["@" + rule.name];
|
|
|
|
|
- if (subGrammar) { // Rule is valid in this context
|
|
|
|
|
- ret.rules.push(canonicalize(rule, subGrammar, topGrammar));
|
|
|
|
|
- } else {
|
|
|
|
|
- const result = unknownTransformer(rule);
|
|
|
|
|
- if (result) {
|
|
|
|
|
- ret.rules.push(result);
|
|
|
|
|
- } else {
|
|
|
|
|
- ret.errors.push(result);
|
|
|
|
|
- }
|
|
|
|
|
- }
|
|
|
|
|
- }
|
|
|
|
|
- }
|
|
|
|
|
- } else {
|
|
|
|
|
- ret.rules = [];
|
|
|
|
|
- ret.errors = [];
|
|
|
|
|
- for (let i = 0; i < contents.length; i++) {
|
|
|
|
|
- const rule = contents[i];
|
|
|
|
|
- if (rule instanceof QualifiedRule) {
|
|
|
|
|
- ret.rules.push(canonicalize(rule, grammar.qualified, topGrammar));
|
|
|
|
|
- } else {
|
|
|
|
|
- const subGrammar = grammar["@" + rule.name];
|
|
|
|
|
- if (subGrammar) { // Rule is valid in this context
|
|
|
|
|
- ret.rules.push(canonicalize(rule, subGrammar, topGrammar));
|
|
|
|
|
- } else {
|
|
|
|
|
- const result = unknownTransformer(rule);
|
|
|
|
|
- if (result) {
|
|
|
|
|
- ret.rules.push(result);
|
|
|
|
|
- } else {
|
|
|
|
|
- ret.errors.push(result);
|
|
|
|
|
- }
|
|
|
|
|
- }
|
|
|
|
|
- }
|
|
|
|
|
- }
|
|
|
|
|
- }
|
|
|
|
|
- return ret;
|
|
|
|
|
- }
|
|
|
|
|
-
|
|
|
|
|
- const CSSGrammar = {
|
|
|
|
|
- qualified: { declarations: true },
|
|
|
|
|
- "@media": { stylesheet: true },
|
|
|
|
|
- "@keyframes": { qualified: { declarations: true } },
|
|
|
|
|
- "@font-face": { declarations: true },
|
|
|
|
|
- "@supports": { stylesheet: true },
|
|
|
|
|
- "@scope": { stylesheet: true },
|
|
|
|
|
- "@counter-style": { declarations: true },
|
|
|
|
|
- "@import": null,
|
|
|
|
|
- "@font-feature-values": {
|
|
|
|
|
- // No qualified rules actually allowed,
|
|
|
|
|
- // but have to declare it one way or the other.
|
|
|
|
|
- qualified: true,
|
|
|
|
|
- "@stylistic": { declarations: true },
|
|
|
|
|
- "@styleset": { declarations: true },
|
|
|
|
|
- "@character-variants": { declarations: true },
|
|
|
|
|
- "@swash": { declarations: true },
|
|
|
|
|
- "@ornaments": { declarations: true },
|
|
|
|
|
- "@annotation": { declarations: true },
|
|
|
|
|
- },
|
|
|
|
|
- "@viewport": { declarations: true },
|
|
|
|
|
- "@page": {
|
|
|
|
|
- declarations: true,
|
|
|
|
|
- "@top-left-corner": { declarations: true },
|
|
|
|
|
- "@top-left": { declarations: true },
|
|
|
|
|
- "@top-center": { declarations: true },
|
|
|
|
|
- "@top-right": { declarations: true },
|
|
|
|
|
- "@top-right-corner": { declarations: true },
|
|
|
|
|
- "@right-top": { declarations: true },
|
|
|
|
|
- "@right-middle": { declarations: true },
|
|
|
|
|
- "@right-bottom": { declarations: true },
|
|
|
|
|
- "@right-bottom-corner": { declarations: true },
|
|
|
|
|
- "@bottom-right": { declarations: true },
|
|
|
|
|
- "@bottom-center": { declarations: true },
|
|
|
|
|
- "@bottom-left": { declarations: true },
|
|
|
|
|
- "@bottom-left-corner": { declarations: true },
|
|
|
|
|
- "@left-bottom": { declarations: true },
|
|
|
|
|
- "@left-center": { declarations: true },
|
|
|
|
|
- "@left-top": { declarations: true },
|
|
|
|
|
- },
|
|
|
|
|
- "@custom-selector": null,
|
|
|
|
|
- "@custom-media": null
|
|
|
|
|
- };
|
|
|
|
|
-
|
|
|
|
|
-
|
|
|
|
|
|
|
|
|
|
// Exportation.
|
|
// Exportation.
|
|
|
|
|
|
|
|
return {
|
|
return {
|
|
|
- CSSParserRule: CSSParserRule,
|
|
|
|
|
- Stylesheet: Stylesheet,
|
|
|
|
|
- AtRule: AtRule,
|
|
|
|
|
- QualifiedRule: QualifiedRule,
|
|
|
|
|
- Declaration: Declaration,
|
|
|
|
|
- SimpleBlock: SimpleBlock,
|
|
|
|
|
- Func: Func,
|
|
|
|
|
- parseAStylesheet: parseAStylesheet,
|
|
|
|
|
- parseAListOfRules: parseAListOfRules,
|
|
|
|
|
- parseARule: parseARule,
|
|
|
|
|
- parseADeclaration: parseADeclaration,
|
|
|
|
|
- parseAListOfDeclarations: parseAListOfDeclarations,
|
|
|
|
|
- parseAComponentValue: parseAComponentValue,
|
|
|
|
|
- parseAListOfComponentValues: parseAListOfComponentValues,
|
|
|
|
|
- parseACommaSeparatedListOfComponentValues: parseACommaSeparatedListOfComponentValues,
|
|
|
|
|
- canonicalizeRule: canonicalize,
|
|
|
|
|
- CSSGrammar: CSSGrammar
|
|
|
|
|
|
|
+ parseAListOfDeclarations: parseAListOfDeclarations
|
|
|
};
|
|
};
|
|
|
|
|
|
|
|
})();
|
|
})();
|