aboutsummaryrefslogtreecommitdiffstats
path: root/vanilla/node_modules/css-tree/lib/syntax/node
diff options
context:
space:
mode:
authorAdam Mathes <adam@adammathes.com>2026-02-13 21:34:48 -0800
committerAdam Mathes <adam@adammathes.com>2026-02-13 21:34:48 -0800
commit76cb9c2a39d477a64824a985ade40507e3bbade1 (patch)
tree41e997aa9c6f538d3a136af61dae9424db2005a9 /vanilla/node_modules/css-tree/lib/syntax/node
parent819a39a21ac992b1393244a4c283bbb125208c69 (diff)
downloadneko-76cb9c2a39d477a64824a985ade40507e3bbade1.tar.gz
neko-76cb9c2a39d477a64824a985ade40507e3bbade1.tar.bz2
neko-76cb9c2a39d477a64824a985ade40507e3bbade1.zip
feat(vanilla): add testing infrastructure and tests (NK-wjnczv)
Diffstat (limited to 'vanilla/node_modules/css-tree/lib/syntax/node')
-rw-r--r--vanilla/node_modules/css-tree/lib/syntax/node/AnPlusB.js292
-rw-r--r--vanilla/node_modules/css-tree/lib/syntax/node/Atrule.js100
-rw-r--r--vanilla/node_modules/css-tree/lib/syntax/node/AtrulePrelude.js47
-rw-r--r--vanilla/node_modules/css-tree/lib/syntax/node/AttributeSelector.js147
-rw-r--r--vanilla/node_modules/css-tree/lib/syntax/node/Block.js95
-rw-r--r--vanilla/node_modules/css-tree/lib/syntax/node/Brackets.js35
-rw-r--r--vanilla/node_modules/css-tree/lib/syntax/node/CDC.js19
-rw-r--r--vanilla/node_modules/css-tree/lib/syntax/node/CDO.js19
-rw-r--r--vanilla/node_modules/css-tree/lib/syntax/node/ClassSelector.js24
-rw-r--r--vanilla/node_modules/css-tree/lib/syntax/node/Combinator.js54
-rw-r--r--vanilla/node_modules/css-tree/lib/syntax/node/Comment.js33
-rw-r--r--vanilla/node_modules/css-tree/lib/syntax/node/Condition.js123
-rw-r--r--vanilla/node_modules/css-tree/lib/syntax/node/Declaration.js165
-rw-r--r--vanilla/node_modules/css-tree/lib/syntax/node/DeclarationList.js62
-rw-r--r--vanilla/node_modules/css-tree/lib/syntax/node/Dimension.js23
-rw-r--r--vanilla/node_modules/css-tree/lib/syntax/node/Feature.js103
-rw-r--r--vanilla/node_modules/css-tree/lib/syntax/node/FeatureFunction.js63
-rw-r--r--vanilla/node_modules/css-tree/lib/syntax/node/FeatureRange.js133
-rw-r--r--vanilla/node_modules/css-tree/lib/syntax/node/Function.js41
-rw-r--r--vanilla/node_modules/css-tree/lib/syntax/node/GeneralEnclosed.js66
-rw-r--r--vanilla/node_modules/css-tree/lib/syntax/node/Hash.js23
-rw-r--r--vanilla/node_modules/css-tree/lib/syntax/node/IdSelector.js26
-rw-r--r--vanilla/node_modules/css-tree/lib/syntax/node/Identifier.js18
-rw-r--r--vanilla/node_modules/css-tree/lib/syntax/node/Layer.js28
-rw-r--r--vanilla/node_modules/css-tree/lib/syntax/node/LayerList.js36
-rw-r--r--vanilla/node_modules/css-tree/lib/syntax/node/MediaQuery.js102
-rw-r--r--vanilla/node_modules/css-tree/lib/syntax/node/MediaQueryList.js34
-rw-r--r--vanilla/node_modules/css-tree/lib/syntax/node/NestingSelector.js22
-rw-r--r--vanilla/node_modules/css-tree/lib/syntax/node/Nth.js47
-rw-r--r--vanilla/node_modules/css-tree/lib/syntax/node/Number.js18
-rw-r--r--vanilla/node_modules/css-tree/lib/syntax/node/Operator.js21
-rw-r--r--vanilla/node_modules/css-tree/lib/syntax/node/Parentheses.js34
-rw-r--r--vanilla/node_modules/css-tree/lib/syntax/node/Percentage.js18
-rw-r--r--vanilla/node_modules/css-tree/lib/syntax/node/PseudoClassSelector.js65
-rw-r--r--vanilla/node_modules/css-tree/lib/syntax/node/PseudoElementSelector.js66
-rw-r--r--vanilla/node_modules/css-tree/lib/syntax/node/Ratio.js68
-rw-r--r--vanilla/node_modules/css-tree/lib/syntax/node/Raw.js41
-rw-r--r--vanilla/node_modules/css-tree/lib/syntax/node/Rule.js51
-rw-r--r--vanilla/node_modules/css-tree/lib/syntax/node/Scope.js66
-rw-r--r--vanilla/node_modules/css-tree/lib/syntax/node/Selector.js31
-rw-r--r--vanilla/node_modules/css-tree/lib/syntax/node/SelectorList.js35
-rw-r--r--vanilla/node_modules/css-tree/lib/syntax/node/String.js19
-rw-r--r--vanilla/node_modules/css-tree/lib/syntax/node/StyleSheet.js82
-rw-r--r--vanilla/node_modules/css-tree/lib/syntax/node/SupportsDeclaration.js34
-rw-r--r--vanilla/node_modules/css-tree/lib/syntax/node/TypeSelector.js52
-rw-r--r--vanilla/node_modules/css-tree/lib/syntax/node/UnicodeRange.js156
-rw-r--r--vanilla/node_modules/css-tree/lib/syntax/node/Url.js52
-rw-r--r--vanilla/node_modules/css-tree/lib/syntax/node/Value.js19
-rw-r--r--vanilla/node_modules/css-tree/lib/syntax/node/WhiteSpace.js27
-rw-r--r--vanilla/node_modules/css-tree/lib/syntax/node/index-generate.js49
-rw-r--r--vanilla/node_modules/css-tree/lib/syntax/node/index-parse-selector.js17
-rw-r--r--vanilla/node_modules/css-tree/lib/syntax/node/index-parse.js49
-rw-r--r--vanilla/node_modules/css-tree/lib/syntax/node/index.js49
53 files changed, 3099 insertions, 0 deletions
diff --git a/vanilla/node_modules/css-tree/lib/syntax/node/AnPlusB.js b/vanilla/node_modules/css-tree/lib/syntax/node/AnPlusB.js
new file mode 100644
index 0000000..05c7e44
--- /dev/null
+++ b/vanilla/node_modules/css-tree/lib/syntax/node/AnPlusB.js
@@ -0,0 +1,292 @@
+import {
+ isDigit,
+ WhiteSpace,
+ Comment,
+ Ident,
+ Number,
+ Dimension
+} from '../../tokenizer/index.js';
+
+const PLUSSIGN = 0x002B; // U+002B PLUS SIGN (+)
+const HYPHENMINUS = 0x002D; // U+002D HYPHEN-MINUS (-)
+const N = 0x006E; // U+006E LATIN SMALL LETTER N (n)
+const DISALLOW_SIGN = true;
+const ALLOW_SIGN = false;
+
+function checkInteger(offset, disallowSign) {
+ let pos = this.tokenStart + offset;
+ const code = this.charCodeAt(pos);
+
+ if (code === PLUSSIGN || code === HYPHENMINUS) {
+ if (disallowSign) {
+ this.error('Number sign is not allowed');
+ }
+ pos++;
+ }
+
+ for (; pos < this.tokenEnd; pos++) {
+ if (!isDigit(this.charCodeAt(pos))) {
+ this.error('Integer is expected', pos);
+ }
+ }
+}
+
+function checkTokenIsInteger(disallowSign) {
+ return checkInteger.call(this, 0, disallowSign);
+}
+
+function expectCharCode(offset, code) {
+ if (!this.cmpChar(this.tokenStart + offset, code)) {
+ let msg = '';
+
+ switch (code) {
+ case N:
+ msg = 'N is expected';
+ break;
+ case HYPHENMINUS:
+ msg = 'HyphenMinus is expected';
+ break;
+ }
+
+ this.error(msg, this.tokenStart + offset);
+ }
+}
+
+// ... <signed-integer>
+// ... ['+' | '-'] <signless-integer>
+function consumeB() {
+ let offset = 0;
+ let sign = 0;
+ let type = this.tokenType;
+
+ while (type === WhiteSpace || type === Comment) {
+ type = this.lookupType(++offset);
+ }
+
+ if (type !== Number) {
+ if (this.isDelim(PLUSSIGN, offset) ||
+ this.isDelim(HYPHENMINUS, offset)) {
+ sign = this.isDelim(PLUSSIGN, offset) ? PLUSSIGN : HYPHENMINUS;
+
+ do {
+ type = this.lookupType(++offset);
+ } while (type === WhiteSpace || type === Comment);
+
+ if (type !== Number) {
+ this.skip(offset);
+ checkTokenIsInteger.call(this, DISALLOW_SIGN);
+ }
+ } else {
+ return null;
+ }
+ }
+
+ if (offset > 0) {
+ this.skip(offset);
+ }
+
+ if (sign === 0) {
+ type = this.charCodeAt(this.tokenStart);
+ if (type !== PLUSSIGN && type !== HYPHENMINUS) {
+ this.error('Number sign is expected');
+ }
+ }
+
+ checkTokenIsInteger.call(this, sign !== 0);
+ return sign === HYPHENMINUS ? '-' + this.consume(Number) : this.consume(Number);
+}
+
+// An+B microsyntax https://www.w3.org/TR/css-syntax-3/#anb
+export const name = 'AnPlusB';
+export const structure = {
+ a: [String, null],
+ b: [String, null]
+};
+
+export function parse() {
+ /* eslint-disable brace-style*/
+ const start = this.tokenStart;
+ let a = null;
+ let b = null;
+
+ // <integer>
+ if (this.tokenType === Number) {
+ checkTokenIsInteger.call(this, ALLOW_SIGN);
+ b = this.consume(Number);
+ }
+
+ // -n
+ // -n <signed-integer>
+ // -n ['+' | '-'] <signless-integer>
+ // -n- <signless-integer>
+ // <dashndashdigit-ident>
+ else if (this.tokenType === Ident && this.cmpChar(this.tokenStart, HYPHENMINUS)) {
+ a = '-1';
+
+ expectCharCode.call(this, 1, N);
+
+ switch (this.tokenEnd - this.tokenStart) {
+ // -n
+ // -n <signed-integer>
+ // -n ['+' | '-'] <signless-integer>
+ case 2:
+ this.next();
+ b = consumeB.call(this);
+ break;
+
+ // -n- <signless-integer>
+ case 3:
+ expectCharCode.call(this, 2, HYPHENMINUS);
+
+ this.next();
+ this.skipSC();
+
+ checkTokenIsInteger.call(this, DISALLOW_SIGN);
+
+ b = '-' + this.consume(Number);
+ break;
+
+ // <dashndashdigit-ident>
+ default:
+ expectCharCode.call(this, 2, HYPHENMINUS);
+ checkInteger.call(this, 3, DISALLOW_SIGN);
+ this.next();
+
+ b = this.substrToCursor(start + 2);
+ }
+ }
+
+ // '+'? n
+ // '+'? n <signed-integer>
+ // '+'? n ['+' | '-'] <signless-integer>
+ // '+'? n- <signless-integer>
+ // '+'? <ndashdigit-ident>
+ else if (this.tokenType === Ident || (this.isDelim(PLUSSIGN) && this.lookupType(1) === Ident)) {
+ let sign = 0;
+ a = '1';
+
+ // just ignore a plus
+ if (this.isDelim(PLUSSIGN)) {
+ sign = 1;
+ this.next();
+ }
+
+ expectCharCode.call(this, 0, N);
+
+ switch (this.tokenEnd - this.tokenStart) {
+ // '+'? n
+ // '+'? n <signed-integer>
+ // '+'? n ['+' | '-'] <signless-integer>
+ case 1:
+ this.next();
+ b = consumeB.call(this);
+ break;
+
+ // '+'? n- <signless-integer>
+ case 2:
+ expectCharCode.call(this, 1, HYPHENMINUS);
+
+ this.next();
+ this.skipSC();
+
+ checkTokenIsInteger.call(this, DISALLOW_SIGN);
+
+ b = '-' + this.consume(Number);
+ break;
+
+ // '+'? <ndashdigit-ident>
+ default:
+ expectCharCode.call(this, 1, HYPHENMINUS);
+ checkInteger.call(this, 2, DISALLOW_SIGN);
+ this.next();
+
+ b = this.substrToCursor(start + sign + 1);
+ }
+ }
+
+ // <ndashdigit-dimension>
+ // <ndash-dimension> <signless-integer>
+ // <n-dimension>
+ // <n-dimension> <signed-integer>
+ // <n-dimension> ['+' | '-'] <signless-integer>
+ else if (this.tokenType === Dimension) {
+ const code = this.charCodeAt(this.tokenStart);
+ const sign = code === PLUSSIGN || code === HYPHENMINUS;
+ let i = this.tokenStart + sign;
+
+ for (; i < this.tokenEnd; i++) {
+ if (!isDigit(this.charCodeAt(i))) {
+ break;
+ }
+ }
+
+ if (i === this.tokenStart + sign) {
+ this.error('Integer is expected', this.tokenStart + sign);
+ }
+
+ expectCharCode.call(this, i - this.tokenStart, N);
+ a = this.substring(start, i);
+
+ // <n-dimension>
+ // <n-dimension> <signed-integer>
+ // <n-dimension> ['+' | '-'] <signless-integer>
+ if (i + 1 === this.tokenEnd) {
+ this.next();
+ b = consumeB.call(this);
+ } else {
+ expectCharCode.call(this, i - this.tokenStart + 1, HYPHENMINUS);
+
+ // <ndash-dimension> <signless-integer>
+ if (i + 2 === this.tokenEnd) {
+ this.next();
+ this.skipSC();
+ checkTokenIsInteger.call(this, DISALLOW_SIGN);
+ b = '-' + this.consume(Number);
+ }
+ // <ndashdigit-dimension>
+ else {
+ checkInteger.call(this, i - this.tokenStart + 2, DISALLOW_SIGN);
+ this.next();
+ b = this.substrToCursor(i + 1);
+ }
+ }
+ } else {
+ this.error();
+ }
+
+ if (a !== null && a.charCodeAt(0) === PLUSSIGN) {
+ a = a.substr(1);
+ }
+
+ if (b !== null && b.charCodeAt(0) === PLUSSIGN) {
+ b = b.substr(1);
+ }
+
+ return {
+ type: 'AnPlusB',
+ loc: this.getLocation(start, this.tokenStart),
+ a,
+ b
+ };
+}
+
+export function generate(node) {
+ if (node.a) {
+ const a =
+ node.a === '+1' && 'n' ||
+ node.a === '1' && 'n' ||
+ node.a === '-1' && '-n' ||
+ node.a + 'n';
+
+ if (node.b) {
+ const b = node.b[0] === '-' || node.b[0] === '+'
+ ? node.b
+ : '+' + node.b;
+ this.tokenize(a + b);
+ } else {
+ this.tokenize(a);
+ }
+ } else {
+ this.tokenize(node.b);
+ }
+}
diff --git a/vanilla/node_modules/css-tree/lib/syntax/node/Atrule.js b/vanilla/node_modules/css-tree/lib/syntax/node/Atrule.js
new file mode 100644
index 0000000..99d1284
--- /dev/null
+++ b/vanilla/node_modules/css-tree/lib/syntax/node/Atrule.js
@@ -0,0 +1,100 @@
+import {
+ AtKeyword,
+ Semicolon,
+ LeftCurlyBracket,
+ RightCurlyBracket
+} from '../../tokenizer/index.js';
+
+function consumeRaw() {
+ return this.Raw(this.consumeUntilLeftCurlyBracketOrSemicolon, true);
+}
+
+function isDeclarationBlockAtrule() {
+ for (let offset = 1, type; type = this.lookupType(offset); offset++) {
+ if (type === RightCurlyBracket) {
+ return true;
+ }
+
+ if (type === LeftCurlyBracket ||
+ type === AtKeyword) {
+ return false;
+ }
+ }
+
+ return false;
+}
+
+
+export const name = 'Atrule';
+export const walkContext = 'atrule';
+export const structure = {
+ name: String,
+ prelude: ['AtrulePrelude', 'Raw', null],
+ block: ['Block', null]
+};
+
+export function parse(isDeclaration = false) {
+ const start = this.tokenStart;
+ let name;
+ let nameLowerCase;
+ let prelude = null;
+ let block = null;
+
+ this.eat(AtKeyword);
+
+ name = this.substrToCursor(start + 1);
+ nameLowerCase = name.toLowerCase();
+ this.skipSC();
+
+ // parse prelude
+ if (this.eof === false &&
+ this.tokenType !== LeftCurlyBracket &&
+ this.tokenType !== Semicolon) {
+ if (this.parseAtrulePrelude) {
+ prelude = this.parseWithFallback(this.AtrulePrelude.bind(this, name, isDeclaration), consumeRaw);
+ } else {
+ prelude = consumeRaw.call(this, this.tokenIndex);
+ }
+
+ this.skipSC();
+ }
+
+ switch (this.tokenType) {
+ case Semicolon:
+ this.next();
+ break;
+
+ case LeftCurlyBracket:
+ if (hasOwnProperty.call(this.atrule, nameLowerCase) &&
+ typeof this.atrule[nameLowerCase].block === 'function') {
+ block = this.atrule[nameLowerCase].block.call(this, isDeclaration);
+ } else {
+ // TODO: should consume block content as Raw?
+ block = this.Block(isDeclarationBlockAtrule.call(this));
+ }
+
+ break;
+ }
+
+ return {
+ type: 'Atrule',
+ loc: this.getLocation(start, this.tokenStart),
+ name,
+ prelude,
+ block
+ };
+}
+
+export function generate(node) {
+ this.token(AtKeyword, '@' + node.name);
+
+ if (node.prelude !== null) {
+ this.node(node.prelude);
+ }
+
+ if (node.block) {
+ this.node(node.block);
+ } else {
+ this.token(Semicolon, ';');
+ }
+}
diff --git a/vanilla/node_modules/css-tree/lib/syntax/node/AtrulePrelude.js b/vanilla/node_modules/css-tree/lib/syntax/node/AtrulePrelude.js
new file mode 100644
index 0000000..5b5645a
--- /dev/null
+++ b/vanilla/node_modules/css-tree/lib/syntax/node/AtrulePrelude.js
@@ -0,0 +1,47 @@
+import {
+ Semicolon,
+ LeftCurlyBracket
+} from '../../tokenizer/index.js';
+
+export const name = 'AtrulePrelude';
+export const walkContext = 'atrulePrelude';
+export const structure = {
+ children: [[]]
+};
+
+export function parse(name) {
+ let children = null;
+
+ if (name !== null) {
+ name = name.toLowerCase();
+ }
+
+ this.skipSC();
+
+ if (hasOwnProperty.call(this.atrule, name) &&
+ typeof this.atrule[name].prelude === 'function') {
+ // custom consumer
+ children = this.atrule[name].prelude.call(this);
+ } else {
+ // default consumer
+ children = this.readSequence(this.scope.AtrulePrelude);
+ }
+
+ this.skipSC();
+
+ if (this.eof !== true &&
+ this.tokenType !== LeftCurlyBracket &&
+ this.tokenType !== Semicolon) {
+ this.error('Semicolon or block is expected');
+ }
+
+ return {
+ type: 'AtrulePrelude',
+ loc: this.getLocationFromList(children),
+ children
+ };
+}
+
+export function generate(node) {
+ this.children(node);
+}
diff --git a/vanilla/node_modules/css-tree/lib/syntax/node/AttributeSelector.js b/vanilla/node_modules/css-tree/lib/syntax/node/AttributeSelector.js
new file mode 100644
index 0000000..8578dad
--- /dev/null
+++ b/vanilla/node_modules/css-tree/lib/syntax/node/AttributeSelector.js
@@ -0,0 +1,147 @@
+import {
+ Ident,
+ String as StringToken,
+ Delim,
+ LeftSquareBracket,
+ RightSquareBracket
+} from '../../tokenizer/index.js';
+
+const DOLLARSIGN = 0x0024; // U+0024 DOLLAR SIGN ($)
+const ASTERISK = 0x002A; // U+002A ASTERISK (*)
+const EQUALSSIGN = 0x003D; // U+003D EQUALS SIGN (=)
+const CIRCUMFLEXACCENT = 0x005E; // U+005E (^)
+const VERTICALLINE = 0x007C; // U+007C VERTICAL LINE (|)
+const TILDE = 0x007E; // U+007E TILDE (~)
+
+function getAttributeName() {
+ if (this.eof) {
+ this.error('Unexpected end of input');
+ }
+
+ const start = this.tokenStart;
+ let expectIdent = false;
+
+ if (this.isDelim(ASTERISK)) {
+ expectIdent = true;
+ this.next();
+ } else if (!this.isDelim(VERTICALLINE)) {
+ this.eat(Ident);
+ }
+
+ if (this.isDelim(VERTICALLINE)) {
+ if (this.charCodeAt(this.tokenStart + 1) !== EQUALSSIGN) {
+ this.next();
+ this.eat(Ident);
+ } else if (expectIdent) {
+ this.error('Identifier is expected', this.tokenEnd);
+ }
+ } else if (expectIdent) {
+ this.error('Vertical line is expected');
+ }
+
+ return {
+ type: 'Identifier',
+ loc: this.getLocation(start, this.tokenStart),
+ name: this.substrToCursor(start)
+ };
+}
+
+function getOperator() {
+ const start = this.tokenStart;
+ const code = this.charCodeAt(start);
+
+ if (code !== EQUALSSIGN && // =
+ code !== TILDE && // ~=
+ code !== CIRCUMFLEXACCENT && // ^=
+ code !== DOLLARSIGN && // $=
+ code !== ASTERISK && // *=
+ code !== VERTICALLINE // |=
+ ) {
+ this.error('Attribute selector (=, ~=, ^=, $=, *=, |=) is expected');
+ }
+
+ this.next();
+
+ if (code !== EQUALSSIGN) {
+ if (!this.isDelim(EQUALSSIGN)) {
+ this.error('Equal sign is expected');
+ }
+
+ this.next();
+ }
+
+ return this.substrToCursor(start);
+}
+
+// '[' <wq-name> ']'
+// '[' <wq-name> <attr-matcher> [ <string-token> | <ident-token> ] <attr-modifier>? ']'
+export const name = 'AttributeSelector';
+export const structure = {
+ name: 'Identifier',
+ matcher: [String, null],
+ value: ['String', 'Identifier', null],
+ flags: [String, null]
+};
+
+export function parse() {
+ const start = this.tokenStart;
+ let name;
+ let matcher = null;
+ let value = null;
+ let flags = null;
+
+ this.eat(LeftSquareBracket);
+ this.skipSC();
+
+ name = getAttributeName.call(this);
+ this.skipSC();
+
+ if (this.tokenType !== RightSquareBracket) {
+ // avoid case `[name i]`
+ if (this.tokenType !== Ident) {
+ matcher = getOperator.call(this);
+
+ this.skipSC();
+
+ value = this.tokenType === StringToken
+ ? this.String()
+ : this.Identifier();
+
+ this.skipSC();
+ }
+
+ // attribute flags
+ if (this.tokenType === Ident) {
+ flags = this.consume(Ident);
+
+ this.skipSC();
+ }
+ }
+
+ this.eat(RightSquareBracket);
+
+ return {
+ type: 'AttributeSelector',
+ loc: this.getLocation(start, this.tokenStart),
+ name,
+ matcher,
+ value,
+ flags
+ };
+}
+
+export function generate(node) {
+ this.token(Delim, '[');
+ this.node(node.name);
+
+ if (node.matcher !== null) {
+ this.tokenize(node.matcher);
+ this.node(node.value);
+ }
+
+ if (node.flags !== null) {
+ this.token(Ident, node.flags);
+ }
+
+ this.token(Delim, ']');
+}
diff --git a/vanilla/node_modules/css-tree/lib/syntax/node/Block.js b/vanilla/node_modules/css-tree/lib/syntax/node/Block.js
new file mode 100644
index 0000000..10bf6fc
--- /dev/null
+++ b/vanilla/node_modules/css-tree/lib/syntax/node/Block.js
@@ -0,0 +1,95 @@
+import {
+ WhiteSpace,
+ Comment,
+ Semicolon,
+ AtKeyword,
+ LeftCurlyBracket,
+ RightCurlyBracket
+} from '../../tokenizer/index.js';
+
+const AMPERSAND = 0x0026; // U+0026 AMPERSAND (&)
+
+function consumeRaw() {
+ return this.Raw(null, true);
+}
+function consumeRule() {
+ return this.parseWithFallback(this.Rule, consumeRaw);
+}
+function consumeRawDeclaration() {
+ return this.Raw(this.consumeUntilSemicolonIncluded, true);
+}
+function consumeDeclaration() {
+ if (this.tokenType === Semicolon) {
+ return consumeRawDeclaration.call(this, this.tokenIndex);
+ }
+
+ const node = this.parseWithFallback(this.Declaration, consumeRawDeclaration);
+
+ if (this.tokenType === Semicolon) {
+ this.next();
+ }
+
+ return node;
+}
+
+export const name = 'Block';
+export const walkContext = 'block';
+export const structure = {
+ children: [[
+ 'Atrule',
+ 'Rule',
+ 'Declaration'
+ ]]
+};
+
+export function parse(isStyleBlock) {
+ const consumer = isStyleBlock ? consumeDeclaration : consumeRule;
+ const start = this.tokenStart;
+ let children = this.createList();
+
+ this.eat(LeftCurlyBracket);
+
+ scan:
+ while (!this.eof) {
+ switch (this.tokenType) {
+ case RightCurlyBracket:
+ break scan;
+
+ case WhiteSpace:
+ case Comment:
+ this.next();
+ break;
+
+ case AtKeyword:
+ children.push(this.parseWithFallback(this.Atrule.bind(this, isStyleBlock), consumeRaw));
+ break;
+
+ default:
+ if (isStyleBlock && this.isDelim(AMPERSAND)) {
+ children.push(consumeRule.call(this));
+ } else {
+ children.push(consumer.call(this));
+ }
+ }
+ }
+
+ if (!this.eof) {
+ this.eat(RightCurlyBracket);
+ }
+
+ return {
+ type: 'Block',
+ loc: this.getLocation(start, this.tokenStart),
+ children
+ };
+}
+
+export function generate(node) {
+ this.token(LeftCurlyBracket, '{');
+ this.children(node, prev => {
+ if (prev.type === 'Declaration') {
+ this.token(Semicolon, ';');
+ }
+ });
+ this.token(RightCurlyBracket, '}');
+}
diff --git a/vanilla/node_modules/css-tree/lib/syntax/node/Brackets.js b/vanilla/node_modules/css-tree/lib/syntax/node/Brackets.js
new file mode 100644
index 0000000..1d97a4c
--- /dev/null
+++ b/vanilla/node_modules/css-tree/lib/syntax/node/Brackets.js
@@ -0,0 +1,35 @@
+import {
+ Delim,
+ LeftSquareBracket,
+ RightSquareBracket
+} from '../../tokenizer/index.js';
+
+export const name = 'Brackets';
+export const structure = {
+ children: [[]]
+};
+
+export function parse(readSequence, recognizer) {
+ const start = this.tokenStart;
+ let children = null;
+
+ this.eat(LeftSquareBracket);
+
+ children = readSequence.call(this, recognizer);
+
+ if (!this.eof) {
+ this.eat(RightSquareBracket);
+ }
+
+ return {
+ type: 'Brackets',
+ loc: this.getLocation(start, this.tokenStart),
+ children
+ };
+}
+
+export function generate(node) {
+ this.token(Delim, '[');
+ this.children(node);
+ this.token(Delim, ']');
+}
diff --git a/vanilla/node_modules/css-tree/lib/syntax/node/CDC.js b/vanilla/node_modules/css-tree/lib/syntax/node/CDC.js
new file mode 100644
index 0000000..efed4a6
--- /dev/null
+++ b/vanilla/node_modules/css-tree/lib/syntax/node/CDC.js
@@ -0,0 +1,19 @@
+import { CDC } from '../../tokenizer/index.js';
+
+export const name = 'CDC';
+export const structure = [];
+
+export function parse() {
+ const start = this.tokenStart;
+
+ this.eat(CDC); // -->
+
+ return {
+ type: 'CDC',
+ loc: this.getLocation(start, this.tokenStart)
+ };
+}
+
+export function generate() {
+ this.token(CDC, '-->');
+}
diff --git a/vanilla/node_modules/css-tree/lib/syntax/node/CDO.js b/vanilla/node_modules/css-tree/lib/syntax/node/CDO.js
new file mode 100644
index 0000000..3a9de89
--- /dev/null
+++ b/vanilla/node_modules/css-tree/lib/syntax/node/CDO.js
@@ -0,0 +1,19 @@
+import { CDO } from '../../tokenizer/index.js';
+
+export const name = 'CDO';
+export const structure = [];
+
+export function parse() {
+ const start = this.tokenStart;
+
+ this.eat(CDO); // <!--
+
+ return {
+ type: 'CDO',
+ loc: this.getLocation(start, this.tokenStart)
+ };
+}
+
+export function generate() {
+ this.token(CDO, '<!--');
+}
diff --git a/vanilla/node_modules/css-tree/lib/syntax/node/ClassSelector.js b/vanilla/node_modules/css-tree/lib/syntax/node/ClassSelector.js
new file mode 100644
index 0000000..febb0d9
--- /dev/null
+++ b/vanilla/node_modules/css-tree/lib/syntax/node/ClassSelector.js
@@ -0,0 +1,24 @@
+import { Delim, Ident } from '../../tokenizer/index.js';
+
+const FULLSTOP = 0x002E; // U+002E FULL STOP (.)
+
+// '.' ident
+export const name = 'ClassSelector';
+export const structure = {
+ name: String
+};
+
+export function parse() {
+ this.eatDelim(FULLSTOP);
+
+ return {
+ type: 'ClassSelector',
+ loc: this.getLocation(this.tokenStart - 1, this.tokenEnd),
+ name: this.consume(Ident)
+ };
+}
+
+export function generate(node) {
+ this.token(Delim, '.');
+ this.token(Ident, node.name);
+}
diff --git a/vanilla/node_modules/css-tree/lib/syntax/node/Combinator.js b/vanilla/node_modules/css-tree/lib/syntax/node/Combinator.js
new file mode 100644
index 0000000..2e5bb1f
--- /dev/null
+++ b/vanilla/node_modules/css-tree/lib/syntax/node/Combinator.js
@@ -0,0 +1,54 @@
+import { WhiteSpace, Delim } from '../../tokenizer/index.js';
+
+const PLUSSIGN = 0x002B; // U+002B PLUS SIGN (+)
+const SOLIDUS = 0x002F; // U+002F SOLIDUS (/)
+const GREATERTHANSIGN = 0x003E; // U+003E GREATER-THAN SIGN (>)
+const TILDE = 0x007E; // U+007E TILDE (~)
+
+export const name = 'Combinator';
+export const structure = {
+ name: String
+};
+
+// + | > | ~ | /deep/
+export function parse() {
+ const start = this.tokenStart;
+ let name;
+
+ switch (this.tokenType) {
+ case WhiteSpace:
+ name = ' ';
+ break;
+
+ case Delim:
+ switch (this.charCodeAt(this.tokenStart)) {
+ case GREATERTHANSIGN:
+ case PLUSSIGN:
+ case TILDE:
+ this.next();
+ break;
+
+ case SOLIDUS:
+ this.next();
+ this.eatIdent('deep');
+ this.eatDelim(SOLIDUS);
+ break;
+
+ default:
+ this.error('Combinator is expected');
+ }
+
+ name = this.substrToCursor(start);
+ break;
+ }
+
+ return {
+ type: 'Combinator',
+ loc: this.getLocation(start, this.tokenStart),
+ name
+ };
+}
+
+export function generate(node) {
+ this.tokenize(node.name);
+}
diff --git a/vanilla/node_modules/css-tree/lib/syntax/node/Comment.js b/vanilla/node_modules/css-tree/lib/syntax/node/Comment.js
new file mode 100644
index 0000000..8a9d291
--- /dev/null
+++ b/vanilla/node_modules/css-tree/lib/syntax/node/Comment.js
@@ -0,0 +1,33 @@
+import { Comment } from '../../tokenizer/index.js';
+
+const ASTERISK = 0x002A; // U+002A ASTERISK (*)
+const SOLIDUS = 0x002F; // U+002F SOLIDUS (/)
+
+
+export const name = 'Comment';
+export const structure = {
+ value: String
+};
+
+export function parse() {
+ const start = this.tokenStart;
+ let end = this.tokenEnd;
+
+ this.eat(Comment);
+
+ if ((end - start + 2) >= 2 &&
+ this.charCodeAt(end - 2) === ASTERISK &&
+ this.charCodeAt(end - 1) === SOLIDUS) {
+ end -= 2;
+ }
+
+ return {
+ type: 'Comment',
+ loc: this.getLocation(start, this.tokenStart),
+ value: this.substring(start + 2, end)
+ };
+}
+
+export function generate(node) {
+ this.token(Comment, '/*' + node.value + '*/');
+}
diff --git a/vanilla/node_modules/css-tree/lib/syntax/node/Condition.js b/vanilla/node_modules/css-tree/lib/syntax/node/Condition.js
new file mode 100644
index 0000000..e4b1e0d
--- /dev/null
+++ b/vanilla/node_modules/css-tree/lib/syntax/node/Condition.js
@@ -0,0 +1,123 @@
+import {
+ WhiteSpace,
+ Comment,
+ Ident,
+ LeftParenthesis,
+ RightParenthesis,
+ Function as FunctionToken,
+ Colon,
+ EOF
+} from '../../tokenizer/index.js';
+
+const likelyFeatureToken = new Set([Colon, RightParenthesis, EOF]);
+
+export const name = 'Condition';
+export const structure = {
+ kind: String,
+ children: [[
+ 'Identifier',
+ 'Feature',
+ 'FeatureFunction',
+ 'FeatureRange',
+ 'SupportsDeclaration'
+ ]]
+};
+
+function featureOrRange(kind) {
+ if (this.lookupTypeNonSC(1) === Ident &&
+ likelyFeatureToken.has(this.lookupTypeNonSC(2))) {
+ return this.Feature(kind);
+ }
+
+ return this.FeatureRange(kind);
+}
+
+const parentheses = {
+ media: featureOrRange,
+ container: featureOrRange,
+ supports() {
+ return this.SupportsDeclaration();
+ }
+};
+
+export function parse(kind = 'media') {
+ const children = this.createList();
+
+ scan: while (!this.eof) {
+ switch (this.tokenType) {
+ case Comment:
+ case WhiteSpace:
+ this.next();
+ continue;
+
+ case Ident:
+ children.push(this.Identifier());
+ break;
+
+ case LeftParenthesis: {
+ let term = this.parseWithFallback(
+ () => parentheses[kind].call(this, kind),
+ () => null
+ );
+
+ if (!term) {
+ term = this.parseWithFallback(
+ () => {
+ this.eat(LeftParenthesis);
+ const res = this.Condition(kind);
+ this.eat(RightParenthesis);
+ return res;
+ },
+ () => {
+ return this.GeneralEnclosed(kind);
+ }
+ );
+ }
+
+ children.push(term);
+ break;
+ }
+
+ case FunctionToken: {
+ let term = this.parseWithFallback(
+ () => this.FeatureFunction(kind),
+ () => null
+ );
+
+ if (!term) {
+ term = this.GeneralEnclosed(kind);
+ }
+
+ children.push(term);
+ break;
+ }
+
+ default:
+ break scan;
+ }
+ }
+
+ if (children.isEmpty) {
+ this.error('Condition is expected');
+ }
+
+ return {
+ type: 'Condition',
+ loc: this.getLocationFromList(children),
+ kind,
+ children
+ };
+}
+
+export function generate(node) {
+ node.children.forEach(child => {
+ if (child.type === 'Condition') {
+ this.token(LeftParenthesis, '(');
+ this.node(child);
+ this.token(RightParenthesis, ')');
+ } else {
+ this.node(child);
+ }
+ });
+}
+
diff --git a/vanilla/node_modules/css-tree/lib/syntax/node/Declaration.js b/vanilla/node_modules/css-tree/lib/syntax/node/Declaration.js
new file mode 100644
index 0000000..af3ea60
--- /dev/null
+++ b/vanilla/node_modules/css-tree/lib/syntax/node/Declaration.js
@@ -0,0 +1,165 @@
+import { isCustomProperty } from '../../utils/names.js';
+import {
+ Ident,
+ Hash,
+ Colon,
+ Semicolon,
+ Delim,
+ WhiteSpace
+} from '../../tokenizer/index.js';
+
+const EXCLAMATIONMARK = 0x0021; // U+0021 EXCLAMATION MARK (!)
+const NUMBERSIGN = 0x0023; // U+0023 NUMBER SIGN (#)
+const DOLLARSIGN = 0x0024; // U+0024 DOLLAR SIGN ($)
+const AMPERSAND = 0x0026; // U+0026 AMPERSAND (&)
+const ASTERISK = 0x002A; // U+002A ASTERISK (*)
+const PLUSSIGN = 0x002B; // U+002B PLUS SIGN (+)
+const SOLIDUS = 0x002F; // U+002F SOLIDUS (/)
+
+function consumeValueRaw() {
+ return this.Raw(this.consumeUntilExclamationMarkOrSemicolon, true);
+}
+
+function consumeCustomPropertyRaw() {
+ return this.Raw(this.consumeUntilExclamationMarkOrSemicolon, false);
+}
+
+function consumeValue() {
+ const startValueToken = this.tokenIndex;
+ const value = this.Value();
+
+ if (value.type !== 'Raw' &&
+ this.eof === false &&
+ this.tokenType !== Semicolon &&
+ this.isDelim(EXCLAMATIONMARK) === false &&
+ this.isBalanceEdge(startValueToken) === false) {
+ this.error();
+ }
+
+ return value;
+}
+
+export const name = 'Declaration';
+export const walkContext = 'declaration';
+export const structure = {
+ important: [Boolean, String],
+ property: String,
+ value: ['Value', 'Raw']
+};
+
+export function parse() {
+ const start = this.tokenStart;
+ const startToken = this.tokenIndex;
+ const property = readProperty.call(this);
+ const customProperty = isCustomProperty(property);
+ const parseValue = customProperty ? this.parseCustomProperty : this.parseValue;
+ const consumeRaw = customProperty ? consumeCustomPropertyRaw : consumeValueRaw;
+ let important = false;
+ let value;
+
+ this.skipSC();
+ this.eat(Colon);
+
+ const valueStart = this.tokenIndex;
+
+ if (!customProperty) {
+ this.skipSC();
+ }
+
+ if (parseValue) {
+ value = this.parseWithFallback(consumeValue, consumeRaw);
+ } else {
+ value = consumeRaw.call(this, this.tokenIndex);
+ }
+
+ if (customProperty && value.type === 'Value' && value.children.isEmpty) {
+ for (let offset = valueStart - this.tokenIndex; offset <= 0; offset++) {
+ if (this.lookupType(offset) === WhiteSpace) {
+ value.children.appendData({
+ type: 'WhiteSpace',
+ loc: null,
+ value: ' '
+ });
+ break;
+ }
+ }
+ }
+
+ if (this.isDelim(EXCLAMATIONMARK)) {
+ important = getImportant.call(this);
+ this.skipSC();
+ }
+
+ // Do not include semicolon to range per spec
+ // https://drafts.csswg.org/css-syntax/#declaration-diagram
+
+ if (this.eof === false &&
+ this.tokenType !== Semicolon &&
+ this.isBalanceEdge(startToken) === false) {
+ this.error();
+ }
+
+ return {
+ type: 'Declaration',
+ loc: this.getLocation(start, this.tokenStart),
+ important,
+ property,
+ value
+ };
+}
+
+export function generate(node) {
+ this.token(Ident, node.property);
+ this.token(Colon, ':');
+ this.node(node.value);
+
+ if (node.important) {
+ this.token(Delim, '!');
+ this.token(Ident, node.important === true ? 'important' : node.important);
+ }
+}
+
+function readProperty() {
+ const start = this.tokenStart;
+
+ // hacks
+ if (this.tokenType === Delim) {
+ switch (this.charCodeAt(this.tokenStart)) {
+ case ASTERISK:
+ case DOLLARSIGN:
+ case PLUSSIGN:
+ case NUMBERSIGN:
+ case AMPERSAND:
+ this.next();
+ break;
+
+ // TODO: not sure we should support this hack
+ case SOLIDUS:
+ this.next();
+ if (this.isDelim(SOLIDUS)) {
+ this.next();
+ }
+ break;
+ }
+ }
+
+ if (this.tokenType === Hash) {
+ this.eat(Hash);
+ } else {
+ this.eat(Ident);
+ }
+
+ return this.substrToCursor(start);
+}
+
+// ! ws* important
+function getImportant() {
+ this.eat(Delim);
+ this.skipSC();
+
+ const important = this.consume(Ident);
+
+ // store original value in case it differ from `important`
+ // for better original source restoring and hacks like `!ie` support
+ return important === 'important' ? true : important;
+}
diff --git a/vanilla/node_modules/css-tree/lib/syntax/node/DeclarationList.js b/vanilla/node_modules/css-tree/lib/syntax/node/DeclarationList.js
new file mode 100644
index 0000000..2b40c99
--- /dev/null
+++ b/vanilla/node_modules/css-tree/lib/syntax/node/DeclarationList.js
@@ -0,0 +1,62 @@
+import {
+ WhiteSpace,
+ Comment,
+ Semicolon,
+ AtKeyword
+} from '../../tokenizer/index.js';
+
+const AMPERSAND = 0x0026; // U+0026 AMPERSAND (&)
+
+function consumeRaw() {
+ return this.Raw(this.consumeUntilSemicolonIncluded, true);
+}
+
+export const name = 'DeclarationList';
+export const structure = {
+ children: [[
+ 'Declaration',
+ 'Atrule',
+ 'Rule'
+ ]]
+};
+
+export function parse() {
+ const children = this.createList();
+
+ scan:
+ while (!this.eof) {
+ switch (this.tokenType) {
+ case WhiteSpace:
+ case Comment:
+ case Semicolon:
+ this.next();
+ break;
+
+ case AtKeyword:
+ children.push(this.parseWithFallback(this.Atrule.bind(this, true), consumeRaw));
+ break;
+
+ default:
+ if (this.isDelim(AMPERSAND)) {
+ children.push(this.parseWithFallback(this.Rule, consumeRaw));
+ } else {
+ children.push(this.parseWithFallback(this.Declaration, consumeRaw));
+ }
+ }
+ }
+
+ return {
+ type: 'DeclarationList',
+ loc: this.getLocationFromList(children),
+ children
+ };
+}
+
+export function generate(node) {
+ this.children(node, prev => {
+ if (prev.type === 'Declaration') {
+ this.token(Semicolon, ';');
+ }
+ });
+}
+
diff --git a/vanilla/node_modules/css-tree/lib/syntax/node/Dimension.js b/vanilla/node_modules/css-tree/lib/syntax/node/Dimension.js
new file mode 100644
index 0000000..4b9bffc
--- /dev/null
+++ b/vanilla/node_modules/css-tree/lib/syntax/node/Dimension.js
@@ -0,0 +1,23 @@
+import { Dimension } from '../../tokenizer/index.js';
+
+export const name = 'Dimension';
+export const structure = {
+ value: String,
+ unit: String
+};
+
+export function parse() {
+ const start = this.tokenStart;
+ const value = this.consumeNumber(Dimension);
+
+ return {
+ type: 'Dimension',
+ loc: this.getLocation(start, this.tokenStart),
+ value,
+ unit: this.substring(start + value.length, this.tokenStart)
+ };
+}
+
+export function generate(node) {
+ this.token(Dimension, node.value + node.unit);
+}
diff --git a/vanilla/node_modules/css-tree/lib/syntax/node/Feature.js b/vanilla/node_modules/css-tree/lib/syntax/node/Feature.js
new file mode 100644
index 0000000..2f2dc3d
--- /dev/null
+++ b/vanilla/node_modules/css-tree/lib/syntax/node/Feature.js
@@ -0,0 +1,103 @@
+import {
+ Ident,
+ Number,
+ Dimension,
+ Function as FunctionToken,
+ LeftParenthesis,
+ RightParenthesis,
+ Colon,
+ Delim
+} from '../../tokenizer/index.js';
+
+const SOLIDUS = 0x002F; // U+002F SOLIDUS (/)
+
+export const name = 'Feature';
+export const structure = {
+ kind: String,
+ name: String,
+ value: ['Identifier', 'Number', 'Dimension', 'Ratio', 'Function', null]
+};
+
+export function parse(kind) {
+ const start = this.tokenStart;
+ let name;
+ let value = null;
+
+ this.eat(LeftParenthesis);
+ this.skipSC();
+
+ name = this.consume(Ident);
+ this.skipSC();
+
+ if (this.tokenType !== RightParenthesis) {
+ this.eat(Colon);
+ this.skipSC();
+
+ switch (this.tokenType) {
+ case Number:
+ if (this.lookupNonWSType(1) === Delim) {
+ value = this.Ratio();
+ } else {
+ value = this.Number();
+ }
+
+ break;
+
+ case Dimension:
+ value = this.Dimension();
+ break;
+
+ case Ident:
+ value = this.Identifier();
+ break;
+
+ case FunctionToken:
+ value = this.parseWithFallback(
+ () => {
+ const res = this.Function(this.readSequence, this.scope.Value);
+
+ this.skipSC();
+
+ if (this.isDelim(SOLIDUS)) {
+ this.error();
+ }
+
+ return res;
+ },
+ () => {
+ return this.Ratio();
+ }
+ );
+ break;
+
+ default:
+ this.error('Number, dimension, ratio or identifier is expected');
+ }
+
+ this.skipSC();
+ }
+
+ if (!this.eof) {
+ this.eat(RightParenthesis);
+ }
+
+ return {
+ type: 'Feature',
+ loc: this.getLocation(start, this.tokenStart),
+ kind,
+ name,
+ value
+ };
+}
+
+export function generate(node) {
+ this.token(LeftParenthesis, '(');
+ this.token(Ident, node.name);
+
+ if (node.value !== null) {
+ this.token(Colon, ':');
+ this.node(node.value);
+ }
+
+ this.token(RightParenthesis, ')');
+}
diff --git a/vanilla/node_modules/css-tree/lib/syntax/node/FeatureFunction.js b/vanilla/node_modules/css-tree/lib/syntax/node/FeatureFunction.js
new file mode 100644
index 0000000..5869479
--- /dev/null
+++ b/vanilla/node_modules/css-tree/lib/syntax/node/FeatureFunction.js
@@ -0,0 +1,63 @@
+import {
+ Function as FunctionToken,
+ RightParenthesis
+} from '../../tokenizer/index.js';
+
+export const name = 'FeatureFunction';
+export const structure = {
+ kind: String,
+ feature: String,
+ value: ['Declaration', 'Selector']
+};
+
+function getFeatureParser(kind, name) {
+ const featuresOfKind = this.features[kind] || {};
+ const parser = featuresOfKind[name];
+
+ if (typeof parser !== 'function') {
+ this.error(`Unknown feature ${name}()`);
+ }
+
+ return parser;
+}
+
+export function parse(kind = 'unknown') {
+ const start = this.tokenStart;
+ const functionName = this.consumeFunctionName();
+ const valueParser = getFeatureParser.call(this, kind, functionName.toLowerCase());
+
+ this.skipSC();
+
+ const value = this.parseWithFallback(
+ () => {
+ const startValueToken = this.tokenIndex;
+ const value = valueParser.call(this);
+
+ if (this.eof === false &&
+ this.isBalanceEdge(startValueToken) === false) {
+ this.error();
+ }
+
+ return value;
+ },
+ () => this.Raw(null, false)
+ );
+
+ if (!this.eof) {
+ this.eat(RightParenthesis);
+ }
+
+ return {
+ type: 'FeatureFunction',
+ loc: this.getLocation(start, this.tokenStart),
+ kind,
+ feature: functionName,
+ value
+ };
+}
+
+export function generate(node) {
+ this.token(FunctionToken, node.feature + '(');
+ this.node(node.value);
+ this.token(RightParenthesis, ')');
+}
diff --git a/vanilla/node_modules/css-tree/lib/syntax/node/FeatureRange.js b/vanilla/node_modules/css-tree/lib/syntax/node/FeatureRange.js
new file mode 100644
index 0000000..a83e479
--- /dev/null
+++ b/vanilla/node_modules/css-tree/lib/syntax/node/FeatureRange.js
@@ -0,0 +1,133 @@
+import {
+ Ident,
+ Number,
+ Dimension,
+ Function as FunctionToken,
+ LeftParenthesis,
+ RightParenthesis
+} from '../../tokenizer/index.js';
+
+const SOLIDUS = 0x002F; // U+002F SOLIDUS (/)
+const LESSTHANSIGN = 0x003C; // U+003C LESS-THAN SIGN (<)
+const EQUALSSIGN = 0x003D; // U+003D EQUALS SIGN (=)
+const GREATERTHANSIGN = 0x003E; // U+003E GREATER-THAN SIGN (>)
+
+export const name = 'FeatureRange';
+export const structure = {
+ kind: String,
+ left: ['Identifier', 'Number', 'Dimension', 'Ratio', 'Function'],
+ leftComparison: String,
+ middle: ['Identifier', 'Number', 'Dimension', 'Ratio', 'Function'],
+ rightComparison: [String, null],
+ right: ['Identifier', 'Number', 'Dimension', 'Ratio', 'Function', null]
+};
+
+function readTerm() {
+ this.skipSC();
+
+ switch (this.tokenType) {
+ case Number:
+ if (this.isDelim(SOLIDUS, this.lookupOffsetNonSC(1))) {
+ return this.Ratio();
+ } else {
+ return this.Number();
+ }
+
+ case Dimension:
+ return this.Dimension();
+
+ case Ident:
+ return this.Identifier();
+
+ case FunctionToken:
+ return this.parseWithFallback(
+ () => {
+ const res = this.Function(this.readSequence, this.scope.Value);
+
+ this.skipSC();
+
+ if (this.isDelim(SOLIDUS)) {
+ this.error();
+ }
+
+ return res;
+ },
+ () => {
+ return this.Ratio();
+ }
+ );
+
+ default:
+ this.error('Number, dimension, ratio or identifier is expected');
+ }
+}
+
+function readComparison(expectColon) {
+ this.skipSC();
+
+ if (this.isDelim(LESSTHANSIGN) ||
+ this.isDelim(GREATERTHANSIGN)) {
+ const value = this.source[this.tokenStart];
+
+ this.next();
+
+ if (this.isDelim(EQUALSSIGN)) {
+ this.next();
+ return value + '=';
+ }
+
+ return value;
+ }
+
+ if (this.isDelim(EQUALSSIGN)) {
+ return '=';
+ }
+
+ this.error(`Expected ${expectColon ? '":", ' : ''}"<", ">", "=" or ")"`);
+}
+
+export function parse(kind = 'unknown') {
+ const start = this.tokenStart;
+
+ this.skipSC();
+ this.eat(LeftParenthesis);
+
+ const left = readTerm.call(this);
+ const leftComparison = readComparison.call(this, left.type === 'Identifier');
+ const middle = readTerm.call(this);
+ let rightComparison = null;
+ let right = null;
+
+ if (this.lookupNonWSType(0) !== RightParenthesis) {
+ rightComparison = readComparison.call(this);
+ right = readTerm.call(this);
+ }
+
+ this.skipSC();
+ this.eat(RightParenthesis);
+
+ return {
+ type: 'FeatureRange',
+ loc: this.getLocation(start, this.tokenStart),
+ kind,
+ left,
+ leftComparison,
+ middle,
+ rightComparison,
+ right
+ };
+}
+
+export function generate(node) {
+ this.token(LeftParenthesis, '(');
+ this.node(node.left);
+ this.tokenize(node.leftComparison);
+ this.node(node.middle);
+
+ if (node.right) {
+ this.tokenize(node.rightComparison);
+ this.node(node.right);
+ }
+
+ this.token(RightParenthesis, ')');
+}
diff --git a/vanilla/node_modules/css-tree/lib/syntax/node/Function.js b/vanilla/node_modules/css-tree/lib/syntax/node/Function.js
new file mode 100644
index 0000000..1fdc414
--- /dev/null
+++ b/vanilla/node_modules/css-tree/lib/syntax/node/Function.js
@@ -0,0 +1,41 @@
+import {
+ Function as FunctionToken,
+ RightParenthesis
+} from '../../tokenizer/index.js';
+
+
+export const name = 'Function';
+export const walkContext = 'function';
+export const structure = {
+ name: String,
+ children: [[]]
+};
+
+// <function-token> <sequence> )
+export function parse(readSequence, recognizer) {
+ const start = this.tokenStart;
+ const name = this.consumeFunctionName();
+ const nameLowerCase = name.toLowerCase();
+ let children;
+
+ children = recognizer.hasOwnProperty(nameLowerCase)
+ ? recognizer[nameLowerCase].call(this, recognizer)
+ : readSequence.call(this, recognizer);
+
+ if (!this.eof) {
+ this.eat(RightParenthesis);
+ }
+
+ return {
+ type: 'Function',
+ loc: this.getLocation(start, this.tokenStart),
+ name,
+ children
+ };
+}
+
+export function generate(node) {
+ this.token(FunctionToken, node.name + '(');
+ this.children(node);
+ this.token(RightParenthesis, ')');
+}
diff --git a/vanilla/node_modules/css-tree/lib/syntax/node/GeneralEnclosed.js b/vanilla/node_modules/css-tree/lib/syntax/node/GeneralEnclosed.js
new file mode 100644
index 0000000..8ac8cae
--- /dev/null
+++ b/vanilla/node_modules/css-tree/lib/syntax/node/GeneralEnclosed.js
@@ -0,0 +1,66 @@
+import {
+ Function as FunctionToken,
+ LeftParenthesis,
+ RightParenthesis
+} from '../../tokenizer/index.js';
+
+
+export const name = 'GeneralEnclosed';
+export const structure = {
+ kind: String,
+ function: [String, null],
+ children: [[]]
+};
+
+// <function-token> <any-value> )
+// ( <any-value> )
+export function parse(kind) {
+ const start = this.tokenStart;
+ let functionName = null;
+
+ if (this.tokenType === FunctionToken) {
+ functionName = this.consumeFunctionName();
+ } else {
+ this.eat(LeftParenthesis);
+ }
+
+ const children = this.parseWithFallback(
+ () => {
+ const startValueToken = this.tokenIndex;
+ const children = this.readSequence(this.scope.Value);
+
+ if (this.eof === false &&
+ this.isBalanceEdge(startValueToken) === false) {
+ this.error();
+ }
+
+ return children;
+ },
+ () => this.createSingleNodeList(
+ this.Raw(null, false)
+ )
+ );
+
+ if (!this.eof) {
+ this.eat(RightParenthesis);
+ }
+
+ return {
+ type: 'GeneralEnclosed',
+ loc: this.getLocation(start, this.tokenStart),
+ kind,
+ function: functionName,
+ children
+ };
+}
+
+export function generate(node) {
+ if (node.function) {
+ this.token(FunctionToken, node.function + '(');
+ } else {
+ this.token(LeftParenthesis, '(');
+ }
+
+ this.children(node);
+ this.token(RightParenthesis, ')');
+}
diff --git a/vanilla/node_modules/css-tree/lib/syntax/node/Hash.js b/vanilla/node_modules/css-tree/lib/syntax/node/Hash.js
new file mode 100644
index 0000000..b752752
--- /dev/null
+++ b/vanilla/node_modules/css-tree/lib/syntax/node/Hash.js
@@ -0,0 +1,23 @@
+import { Hash } from '../../tokenizer/index.js';
+
+// '#' ident
+export const xxx = 'XXX';
+export const name = 'Hash';
+export const structure = {
+ value: String
+};
+export function parse() {
+ const start = this.tokenStart;
+
+ this.eat(Hash);
+
+ return {
+ type: 'Hash',
+ loc: this.getLocation(start, this.tokenStart),
+ value: this.substrToCursor(start + 1)
+ };
+}
+export function generate(node) {
+ this.token(Hash, '#' + node.value);
+}
+
diff --git a/vanilla/node_modules/css-tree/lib/syntax/node/IdSelector.js b/vanilla/node_modules/css-tree/lib/syntax/node/IdSelector.js
new file mode 100644
index 0000000..c85c1b2
--- /dev/null
+++ b/vanilla/node_modules/css-tree/lib/syntax/node/IdSelector.js
@@ -0,0 +1,26 @@
+import { Hash, Delim } from '../../tokenizer/index.js';
+
+export const name = 'IdSelector';
+export const structure = {
+ name: String
+};
+
+export function parse() {
+ const start = this.tokenStart;
+
+ // TODO: check value is an ident
+ this.eat(Hash);
+
+ return {
+ type: 'IdSelector',
+ loc: this.getLocation(start, this.tokenStart),
+ name: this.substrToCursor(start + 1)
+ };
+}
+
+export function generate(node) {
+ // Using Delim instead of Hash is a hack to avoid for a whitespace between ident and id-selector
+ // in safe mode (e.g. "a#id"), because IE11 doesn't allow a sequence <ident-token> <hash-token>
+ // without a whitespace in values (e.g. "1px solid#000")
+ this.token(Delim, '#' + node.name);
+}
diff --git a/vanilla/node_modules/css-tree/lib/syntax/node/Identifier.js b/vanilla/node_modules/css-tree/lib/syntax/node/Identifier.js
new file mode 100644
index 0000000..067c2d0
--- /dev/null
+++ b/vanilla/node_modules/css-tree/lib/syntax/node/Identifier.js
@@ -0,0 +1,18 @@
+import { Ident } from '../../tokenizer/index.js';
+
+export const name = 'Identifier';
+export const structure = {
+ name: String
+};
+
+export function parse() {
+ return {
+ type: 'Identifier',
+ loc: this.getLocation(this.tokenStart, this.tokenEnd),
+ name: this.consume(Ident)
+ };
+}
+
+export function generate(node) {
+ this.token(Ident, node.name);
+}
diff --git a/vanilla/node_modules/css-tree/lib/syntax/node/Layer.js b/vanilla/node_modules/css-tree/lib/syntax/node/Layer.js
new file mode 100644
index 0000000..d170dcb
--- /dev/null
+++ b/vanilla/node_modules/css-tree/lib/syntax/node/Layer.js
@@ -0,0 +1,28 @@
+import { Ident, Delim } from '../../tokenizer/index.js';
+
+const FULLSTOP = 0x002E; // U+002E FULL STOP (.)
+
+export const name = 'Layer';
+export const structure = {
+ name: String
+};
+
+export function parse() {
+ let tokenStart = this.tokenStart;
+ let name = this.consume(Ident);
+
+ while (this.isDelim(FULLSTOP)) {
+ this.eat(Delim);
+ name += '.' + this.consume(Ident);
+ }
+
+ return {
+ type: 'Layer',
+ loc: this.getLocation(tokenStart, this.tokenStart),
+ name
+ };
+}
+
+export function generate(node) {
+ this.tokenize(node.name);
+}
diff --git a/vanilla/node_modules/css-tree/lib/syntax/node/LayerList.js b/vanilla/node_modules/css-tree/lib/syntax/node/LayerList.js
new file mode 100644
index 0000000..e8a05cd
--- /dev/null
+++ b/vanilla/node_modules/css-tree/lib/syntax/node/LayerList.js
@@ -0,0 +1,36 @@
+import { Comma } from '../../tokenizer/index.js';
+
+export const name = 'LayerList';
+export const structure = {
+ children: [[
+ 'Layer'
+ ]]
+};
+
+export function parse() {
+ const children = this.createList();
+
+ this.skipSC();
+
+ while (!this.eof) {
+ children.push(this.Layer());
+
+ if (this.lookupTypeNonSC(0) !== Comma) {
+ break;
+ }
+
+ this.skipSC();
+ this.next();
+ this.skipSC();
+ }
+
+ return {
+ type: 'LayerList',
+ loc: this.getLocationFromList(children),
+ children
+ };
+}
+
+export function generate(node) {
+ this.children(node, () => this.token(Comma, ','));
+}
diff --git a/vanilla/node_modules/css-tree/lib/syntax/node/MediaQuery.js b/vanilla/node_modules/css-tree/lib/syntax/node/MediaQuery.js
new file mode 100644
index 0000000..f569c75
--- /dev/null
+++ b/vanilla/node_modules/css-tree/lib/syntax/node/MediaQuery.js
@@ -0,0 +1,102 @@
+import {
+ Comma,
+ EOF,
+ Ident,
+ LeftCurlyBracket,
+ LeftParenthesis,
+ Function as FunctionToken,
+ Semicolon
+} from '../../tokenizer/index.js';
+
+export const name = 'MediaQuery';
+export const structure = {
+ modifier: [String, null],
+ mediaType: [String, null],
+ condition: ['Condition', null]
+};
+
+export function parse() {
+ const start = this.tokenStart;
+ let modifier = null;
+ let mediaType = null;
+ let condition = null;
+
+ this.skipSC();
+
+ if (this.tokenType === Ident && this.lookupTypeNonSC(1) !== LeftParenthesis) {
+ // [ not | only ]? <media-type>
+ const ident = this.consume(Ident);
+ const identLowerCase = ident.toLowerCase();
+
+ if (identLowerCase === 'not' || identLowerCase === 'only') {
+ this.skipSC();
+ modifier = identLowerCase;
+ mediaType = this.consume(Ident);
+ } else {
+ mediaType = ident;
+ }
+
+ switch (this.lookupTypeNonSC(0)) {
+ case Ident: {
+ // and <media-condition-without-or>
+ this.skipSC();
+ this.eatIdent('and');
+ condition = this.Condition('media');
+ break;
+ }
+
+ case LeftCurlyBracket:
+ case Semicolon:
+ case Comma:
+ case EOF:
+ break;
+
+ default:
+ this.error('Identifier or parenthesis is expected');
+ }
+ } else {
+ switch (this.tokenType) {
+ case Ident:
+ case LeftParenthesis:
+ case FunctionToken: {
+ // <media-condition>
+ condition = this.Condition('media');
+ break;
+ }
+
+ case LeftCurlyBracket:
+ case Semicolon:
+ case EOF:
+ break;
+
+ default:
+ this.error('Identifier or parenthesis is expected');
+ }
+ }
+
+ return {
+ type: 'MediaQuery',
+ loc: this.getLocation(start, this.tokenStart),
+ modifier,
+ mediaType,
+ condition
+ };
+}
+
+export function generate(node) {
+ if (node.mediaType) {
+ if (node.modifier) {
+ this.token(Ident, node.modifier);
+ }
+
+ this.token(Ident, node.mediaType);
+
+ if (node.condition) {
+ this.token(Ident, 'and');
+ this.node(node.condition);
+ }
+ } else if (node.condition) {
+ this.node(node.condition);
+ }
+}
+
diff --git a/vanilla/node_modules/css-tree/lib/syntax/node/MediaQueryList.js b/vanilla/node_modules/css-tree/lib/syntax/node/MediaQueryList.js
new file mode 100644
index 0000000..1c16bcd
--- /dev/null
+++ b/vanilla/node_modules/css-tree/lib/syntax/node/MediaQueryList.js
@@ -0,0 +1,34 @@
+import { Comma } from '../../tokenizer/index.js';
+
+export const name = 'MediaQueryList';
+export const structure = {
+ children: [[
+ 'MediaQuery'
+ ]]
+};
+
+export function parse() {
+ const children = this.createList();
+
+ this.skipSC();
+
+ while (!this.eof) {
+ children.push(this.MediaQuery());
+
+ if (this.tokenType !== Comma) {
+ break;
+ }
+
+ this.next();
+ }
+
+ return {
+ type: 'MediaQueryList',
+ loc: this.getLocationFromList(children),
+ children
+ };
+}
+
+export function generate(node) {
+ this.children(node, () => this.token(Comma, ','));
+}
diff --git a/vanilla/node_modules/css-tree/lib/syntax/node/NestingSelector.js b/vanilla/node_modules/css-tree/lib/syntax/node/NestingSelector.js
new file mode 100644
index 0000000..33c8b6a
--- /dev/null
+++ b/vanilla/node_modules/css-tree/lib/syntax/node/NestingSelector.js
@@ -0,0 +1,22 @@
+import { Delim } from '../../tokenizer/index.js';
+
+const AMPERSAND = 0x0026; // U+0026 AMPERSAND (&)
+
+export const name = 'NestingSelector';
+export const structure = {
+};
+
+export function parse() {
+ const start = this.tokenStart;
+
+ this.eatDelim(AMPERSAND);
+
+ return {
+ type: 'NestingSelector',
+ loc: this.getLocation(start, this.tokenStart)
+ };
+}
+
+export function generate() {
+ this.token(Delim, '&');
+}
diff --git a/vanilla/node_modules/css-tree/lib/syntax/node/Nth.js b/vanilla/node_modules/css-tree/lib/syntax/node/Nth.js
new file mode 100644
index 0000000..bfd74a1
--- /dev/null
+++ b/vanilla/node_modules/css-tree/lib/syntax/node/Nth.js
@@ -0,0 +1,47 @@
+import { Ident } from '../../tokenizer/index.js';
+
+export const name = 'Nth';
+export const structure = {
+ nth: ['AnPlusB', 'Identifier'],
+ selector: ['SelectorList', null]
+};
+
+export function parse() {
+ this.skipSC();
+
+ const start = this.tokenStart;
+ let end = start;
+ let selector = null;
+ let nth;
+
+ if (this.lookupValue(0, 'odd') || this.lookupValue(0, 'even')) {
+ nth = this.Identifier();
+ } else {
+ nth = this.AnPlusB();
+ }
+
+ end = this.tokenStart;
+ this.skipSC();
+
+ if (this.lookupValue(0, 'of')) {
+ this.next();
+
+ selector = this.SelectorList();
+ end = this.tokenStart;
+ }
+
+ return {
+ type: 'Nth',
+ loc: this.getLocation(start, end),
+ nth,
+ selector
+ };
+}
+
+export function generate(node) {
+ this.node(node.nth);
+ if (node.selector !== null) {
+ this.token(Ident, 'of');
+ this.node(node.selector);
+ }
+}
diff --git a/vanilla/node_modules/css-tree/lib/syntax/node/Number.js b/vanilla/node_modules/css-tree/lib/syntax/node/Number.js
new file mode 100644
index 0000000..a9d8f0a
--- /dev/null
+++ b/vanilla/node_modules/css-tree/lib/syntax/node/Number.js
@@ -0,0 +1,18 @@
+import { Number as NumberToken } from '../../tokenizer/index.js';
+
+export const name = 'Number';
+export const structure = {
+ value: String
+};
+
+export function parse() {
+ return {
+ type: 'Number',
+ loc: this.getLocation(this.tokenStart, this.tokenEnd),
+ value: this.consume(NumberToken)
+ };
+}
+
+export function generate(node) {
+ this.token(NumberToken, node.value);
+}
diff --git a/vanilla/node_modules/css-tree/lib/syntax/node/Operator.js b/vanilla/node_modules/css-tree/lib/syntax/node/Operator.js
new file mode 100644
index 0000000..4f1238b
--- /dev/null
+++ b/vanilla/node_modules/css-tree/lib/syntax/node/Operator.js
@@ -0,0 +1,21 @@
+// '/' | '*' | ',' | ':' | '+' | '-'
+export const name = 'Operator';
+export const structure = {
+ value: String
+};
+
+export function parse() {
+ const start = this.tokenStart;
+
+ this.next();
+
+ return {
+ type: 'Operator',
+ loc: this.getLocation(start, this.tokenStart),
+ value: this.substrToCursor(start)
+ };
+}
+
+export function generate(node) {
+ this.tokenize(node.value);
+}
diff --git a/vanilla/node_modules/css-tree/lib/syntax/node/Parentheses.js b/vanilla/node_modules/css-tree/lib/syntax/node/Parentheses.js
new file mode 100644
index 0000000..8c6cdb5
--- /dev/null
+++ b/vanilla/node_modules/css-tree/lib/syntax/node/Parentheses.js
@@ -0,0 +1,34 @@
+import {
+ LeftParenthesis,
+ RightParenthesis
+} from '../../tokenizer/index.js';
+
+export const name = 'Parentheses';
+export const structure = {
+ children: [[]]
+};
+
+export function parse(readSequence, recognizer) {
+ const start = this.tokenStart;
+ let children = null;
+
+ this.eat(LeftParenthesis);
+
+ children = readSequence.call(this, recognizer);
+
+ if (!this.eof) {
+ this.eat(RightParenthesis);
+ }
+
+ return {
+ type: 'Parentheses',
+ loc: this.getLocation(start, this.tokenStart),
+ children
+ };
+}
+
+export function generate(node) {
+ this.token(LeftParenthesis, '(');
+ this.children(node);
+ this.token(RightParenthesis, ')');
+}
diff --git a/vanilla/node_modules/css-tree/lib/syntax/node/Percentage.js b/vanilla/node_modules/css-tree/lib/syntax/node/Percentage.js
new file mode 100644
index 0000000..3c8b628
--- /dev/null
+++ b/vanilla/node_modules/css-tree/lib/syntax/node/Percentage.js
@@ -0,0 +1,18 @@
+import { Percentage } from '../../tokenizer/index.js';
+
+export const name = 'Percentage';
+export const structure = {
+ value: String
+};
+
+export function parse() {
+ return {
+ type: 'Percentage',
+ loc: this.getLocation(this.tokenStart, this.tokenEnd),
+ value: this.consumeNumber(Percentage)
+ };
+}
+
+export function generate(node) {
+ this.token(Percentage, node.value + '%');
+}
diff --git a/vanilla/node_modules/css-tree/lib/syntax/node/PseudoClassSelector.js b/vanilla/node_modules/css-tree/lib/syntax/node/PseudoClassSelector.js
new file mode 100644
index 0000000..584546c
--- /dev/null
+++ b/vanilla/node_modules/css-tree/lib/syntax/node/PseudoClassSelector.js
@@ -0,0 +1,65 @@
+import {
+ Ident,
+ Function as FunctionToken,
+ Colon,
+ RightParenthesis
+} from '../../tokenizer/index.js';
+
+
+export const name = 'PseudoClassSelector';
+export const walkContext = 'function';
+export const structure = {
+ name: String,
+ children: [['Raw'], null]
+};
+
+// : [ <ident> | <function-token> <any-value>? ) ]
+export function parse() {
+ const start = this.tokenStart;
+ let children = null;
+ let name;
+ let nameLowerCase;
+
+ this.eat(Colon);
+
+ if (this.tokenType === FunctionToken) {
+ name = this.consumeFunctionName();
+ nameLowerCase = name.toLowerCase();
+
+ if (this.lookupNonWSType(0) == RightParenthesis) {
+ children = this.createList();
+ } else if (hasOwnProperty.call(this.pseudo, nameLowerCase)) {
+ this.skipSC();
+ children = this.pseudo[nameLowerCase].call(this);
+ this.skipSC();
+ } else {
+ children = this.createList();
+ children.push(
+ this.Raw(null, false)
+ );
+ }
+
+ this.eat(RightParenthesis);
+ } else {
+ name = this.consume(Ident);
+ }
+
+ return {
+ type: 'PseudoClassSelector',
+ loc: this.getLocation(start, this.tokenStart),
+ name,
+ children
+ };
+}
+
+export function generate(node) {
+ this.token(Colon, ':');
+
+ if (node.children === null) {
+ this.token(Ident, node.name);
+ } else {
+ this.token(FunctionToken, node.name + '(');
+ this.children(node);
+ this.token(RightParenthesis, ')');
+ }
+}
diff --git a/vanilla/node_modules/css-tree/lib/syntax/node/PseudoElementSelector.js b/vanilla/node_modules/css-tree/lib/syntax/node/PseudoElementSelector.js
new file mode 100644
index 0000000..b23b9a0
--- /dev/null
+++ b/vanilla/node_modules/css-tree/lib/syntax/node/PseudoElementSelector.js
@@ -0,0 +1,66 @@
+import {
+ Ident,
+ Function as FunctionToken,
+ Colon,
+ RightParenthesis
+} from '../../tokenizer/index.js';
+
+export const name = 'PseudoElementSelector';
+export const walkContext = 'function';
+export const structure = {
+ name: String,
+ children: [['Raw'], null]
+};
+
+// :: [ <ident> | <function-token> <any-value>? ) ]
+export function parse() {
+ const start = this.tokenStart;
+ let children = null;
+ let name;
+ let nameLowerCase;
+
+ this.eat(Colon);
+ this.eat(Colon);
+
+ if (this.tokenType === FunctionToken) {
+ name = this.consumeFunctionName();
+ nameLowerCase = name.toLowerCase();
+
+ if (this.lookupNonWSType(0) == RightParenthesis) {
+ children = this.createList();
+ } else if (hasOwnProperty.call(this.pseudo, nameLowerCase)) {
+ this.skipSC();
+ children = this.pseudo[nameLowerCase].call(this);
+ this.skipSC();
+ } else {
+ children = this.createList();
+ children.push(
+ this.Raw(null, false)
+ );
+ }
+
+ this.eat(RightParenthesis);
+ } else {
+ name = this.consume(Ident);
+ }
+
+ return {
+ type: 'PseudoElementSelector',
+ loc: this.getLocation(start, this.tokenStart),
+ name,
+ children
+ };
+}
+
+export function generate(node) {
+ this.token(Colon, ':');
+ this.token(Colon, ':');
+
+ if (node.children === null) {
+ this.token(Ident, node.name);
+ } else {
+ this.token(FunctionToken, node.name + '(');
+ this.children(node);
+ this.token(RightParenthesis, ')');
+ }
+}
diff --git a/vanilla/node_modules/css-tree/lib/syntax/node/Ratio.js b/vanilla/node_modules/css-tree/lib/syntax/node/Ratio.js
new file mode 100644
index 0000000..c26cf10
--- /dev/null
+++ b/vanilla/node_modules/css-tree/lib/syntax/node/Ratio.js
@@ -0,0 +1,68 @@
+import {
+ Delim,
+ Number as NumberToken,
+ Function as FunctionToken
+} from '../../tokenizer/index.js';
+
+const SOLIDUS = 0x002F; // U+002F SOLIDUS (/)
+
+// Media Queries Level 3 defines terms of <ratio> as a positive (not zero or negative)
+// integers (see https://drafts.csswg.org/mediaqueries-3/#values)
+// However, Media Queries Level 4 removes any definition of values
+// (see https://drafts.csswg.org/mediaqueries-4/#values) and refers to
+// CSS Values and Units for detail. In CSS Values and Units Level 4 a <ratio>
+// definition was added (see https://drafts.csswg.org/css-values-4/#ratios) which
+// defines ratio as "<number [0,∞]> [ / <number [0,∞]> ]?" and based on it
+// any constrains on terms were removed. Parser also doesn't test numbers
+// in any way to make possible for linting and fixing them by the tools using CSSTree.
+// An additional syntax examination may be applied by a lexer.
+function consumeTerm() {
+ this.skipSC();
+
+ switch (this.tokenType) {
+ case NumberToken:
+ return this.Number();
+
+ case FunctionToken:
+ return this.Function(this.readSequence, this.scope.Value);
+
+ default:
+ this.error('Number of function is expected');
+ }
+}
+
+export const name = 'Ratio';
+export const structure = {
+ left: ['Number', 'Function'],
+ right: ['Number', 'Function', null]
+};
+
+// <number [0,∞]> [ / <number [0,∞]> ]?
+export function parse() {
+ const start = this.tokenStart;
+ const left = consumeTerm.call(this);
+ let right = null;
+
+ this.skipSC();
+ if (this.isDelim(SOLIDUS)) {
+ this.eatDelim(SOLIDUS);
+ right = consumeTerm.call(this);
+ }
+
+ return {
+ type: 'Ratio',
+ loc: this.getLocation(start, this.tokenStart),
+ left,
+ right
+ };
+}
+
+export function generate(node) {
+ this.node(node.left);
+ this.token(Delim, '/');
+ if (node.right) {
+ this.node(node.right);
+ } else {
+ this.node(NumberToken, 1);
+ }
+}
diff --git a/vanilla/node_modules/css-tree/lib/syntax/node/Raw.js b/vanilla/node_modules/css-tree/lib/syntax/node/Raw.js
new file mode 100644
index 0000000..0c2ea69
--- /dev/null
+++ b/vanilla/node_modules/css-tree/lib/syntax/node/Raw.js
@@ -0,0 +1,41 @@
+import { WhiteSpace } from '../../tokenizer/index.js';
+
+function getOffsetExcludeWS() {
+ if (this.tokenIndex > 0) {
+ if (this.lookupType(-1) === WhiteSpace) {
+ return this.tokenIndex > 1
+ ? this.getTokenStart(this.tokenIndex - 1)
+ : this.firstCharOffset;
+ }
+ }
+
+ return this.tokenStart;
+}
+
+export const name = 'Raw';
+export const structure = {
+ value: String
+};
+
+export function parse(consumeUntil, excludeWhiteSpace) {
+ const startOffset = this.getTokenStart(this.tokenIndex);
+ let endOffset;
+
+ this.skipUntilBalanced(this.tokenIndex, consumeUntil || this.consumeUntilBalanceEnd);
+
+ if (excludeWhiteSpace && this.tokenStart > startOffset) {
+ endOffset = getOffsetExcludeWS.call(this);
+ } else {
+ endOffset = this.tokenStart;
+ }
+
+ return {
+ type: 'Raw',
+ loc: this.getLocation(startOffset, endOffset),
+ value: this.substring(startOffset, endOffset)
+ };
+}
+
+export function generate(node) {
+ this.tokenize(node.value);
+}
diff --git a/vanilla/node_modules/css-tree/lib/syntax/node/Rule.js b/vanilla/node_modules/css-tree/lib/syntax/node/Rule.js
new file mode 100644
index 0000000..89745cf
--- /dev/null
+++ b/vanilla/node_modules/css-tree/lib/syntax/node/Rule.js
@@ -0,0 +1,51 @@
+import { LeftCurlyBracket } from '../../tokenizer/index.js';
+
+function consumeRaw() {
+ return this.Raw(this.consumeUntilLeftCurlyBracket, true);
+}
+
+function consumePrelude() {
+ const prelude = this.SelectorList();
+
+ if (prelude.type !== 'Raw' &&
+ this.eof === false &&
+ this.tokenType !== LeftCurlyBracket) {
+ this.error();
+ }
+
+ return prelude;
+}
+
+export const name = 'Rule';
+export const walkContext = 'rule';
+export const structure = {
+ prelude: ['SelectorList', 'Raw'],
+ block: ['Block']
+};
+
+export function parse() {
+ const startToken = this.tokenIndex;
+ const startOffset = this.tokenStart;
+ let prelude;
+ let block;
+
+ if (this.parseRulePrelude) {
+ prelude = this.parseWithFallback(consumePrelude, consumeRaw);
+ } else {
+ prelude = consumeRaw.call(this, startToken);
+ }
+
+ block = this.Block(true);
+
+ return {
+ type: 'Rule',
+ loc: this.getLocation(startOffset, this.tokenStart),
+ prelude,
+ block
+ };
+}
+export function generate(node) {
+ this.node(node.prelude);
+ this.node(node.block);
+}
+
diff --git a/vanilla/node_modules/css-tree/lib/syntax/node/Scope.js b/vanilla/node_modules/css-tree/lib/syntax/node/Scope.js
new file mode 100644
index 0000000..650b035
--- /dev/null
+++ b/vanilla/node_modules/css-tree/lib/syntax/node/Scope.js
@@ -0,0 +1,66 @@
+import {
+ Ident,
+ LeftParenthesis,
+ RightParenthesis
+} from '../../tokenizer/index.js';
+
+export const name = 'Scope';
+export const structure = {
+ root: ['SelectorList', 'Raw', null],
+ limit: ['SelectorList', 'Raw', null]
+};
+
+export function parse() {
+ let root = null;
+ let limit = null;
+
+ this.skipSC();
+
+ const startOffset = this.tokenStart;
+ if (this.tokenType === LeftParenthesis) {
+ this.next();
+ this.skipSC();
+ root = this.parseWithFallback(
+ this.SelectorList,
+ () => this.Raw(false, true)
+ );
+ this.skipSC();
+ this.eat(RightParenthesis);
+ }
+
+ if (this.lookupNonWSType(0) === Ident) {
+ this.skipSC();
+ this.eatIdent('to');
+ this.skipSC();
+ this.eat(LeftParenthesis);
+ this.skipSC();
+ limit = this.parseWithFallback(
+ this.SelectorList,
+ () => this.Raw(false, true)
+ );
+ this.skipSC();
+ this.eat(RightParenthesis);
+ }
+
+ return {
+ type: 'Scope',
+ loc: this.getLocation(startOffset, this.tokenStart),
+ root,
+ limit
+ };
+}
+
+export function generate(node) {
+ if (node.root) {
+ this.token(LeftParenthesis, '(');
+ this.node(node.root);
+ this.token(RightParenthesis, ')');
+ }
+
+ if (node.limit) {
+ this.token(Ident, 'to');
+ this.token(LeftParenthesis, '(');
+ this.node(node.limit);
+ this.token(RightParenthesis, ')');
+ }
+}
diff --git a/vanilla/node_modules/css-tree/lib/syntax/node/Selector.js b/vanilla/node_modules/css-tree/lib/syntax/node/Selector.js
new file mode 100644
index 0000000..36028e0
--- /dev/null
+++ b/vanilla/node_modules/css-tree/lib/syntax/node/Selector.js
@@ -0,0 +1,31 @@
+export const name = 'Selector';
+export const structure = {
+ children: [[
+ 'TypeSelector',
+ 'IdSelector',
+ 'ClassSelector',
+ 'AttributeSelector',
+ 'PseudoClassSelector',
+ 'PseudoElementSelector',
+ 'Combinator'
+ ]]
+};
+
+export function parse() {
+ const children = this.readSequence(this.scope.Selector);
+
+ // nothing were consumed
+ if (this.getFirstListNode(children) === null) {
+ this.error('Selector is expected');
+ }
+
+ return {
+ type: 'Selector',
+ loc: this.getLocationFromList(children),
+ children
+ };
+}
+
+export function generate(node) {
+ this.children(node);
+}
diff --git a/vanilla/node_modules/css-tree/lib/syntax/node/SelectorList.js b/vanilla/node_modules/css-tree/lib/syntax/node/SelectorList.js
new file mode 100644
index 0000000..ebba3cd
--- /dev/null
+++ b/vanilla/node_modules/css-tree/lib/syntax/node/SelectorList.js
@@ -0,0 +1,35 @@
+import { Comma } from '../../tokenizer/index.js';
+
+export const name = 'SelectorList';
+export const walkContext = 'selector';
+export const structure = {
+ children: [[
+ 'Selector',
+ 'Raw'
+ ]]
+};
+
+export function parse() {
+ const children = this.createList();
+
+ while (!this.eof) {
+ children.push(this.Selector());
+
+ if (this.tokenType === Comma) {
+ this.next();
+ continue;
+ }
+
+ break;
+ }
+
+ return {
+ type: 'SelectorList',
+ loc: this.getLocationFromList(children),
+ children
+ };
+}
+
+export function generate(node) {
+ this.children(node, () => this.token(Comma, ','));
+}
diff --git a/vanilla/node_modules/css-tree/lib/syntax/node/String.js b/vanilla/node_modules/css-tree/lib/syntax/node/String.js
new file mode 100644
index 0000000..95e1aaa
--- /dev/null
+++ b/vanilla/node_modules/css-tree/lib/syntax/node/String.js
@@ -0,0 +1,19 @@
+import { String as StringToken } from '../../tokenizer/index.js';
+import { decode, encode } from '../../utils/string.js';
+
+export const name = 'String';
+export const structure = {
+ value: String
+};
+
+export function parse() {
+ return {
+ type: 'String',
+ loc: this.getLocation(this.tokenStart, this.tokenEnd),
+ value: decode(this.consume(StringToken))
+ };
+}
+
+export function generate(node) {
+ this.token(StringToken, encode(node.value));
+}
diff --git a/vanilla/node_modules/css-tree/lib/syntax/node/StyleSheet.js b/vanilla/node_modules/css-tree/lib/syntax/node/StyleSheet.js
new file mode 100644
index 0000000..3bc5347
--- /dev/null
+++ b/vanilla/node_modules/css-tree/lib/syntax/node/StyleSheet.js
@@ -0,0 +1,82 @@
+import {
+ WhiteSpace,
+ Comment,
+ AtKeyword,
+ CDO,
+ CDC
+} from '../../tokenizer/index.js';
+
+const EXCLAMATIONMARK = 0x0021; // U+0021 EXCLAMATION MARK (!)
+
+function consumeRaw() {
+ return this.Raw(null, false);
+}
+
+export const name = 'StyleSheet';
+export const walkContext = 'stylesheet';
+export const structure = {
+ children: [[
+ 'Comment',
+ 'CDO',
+ 'CDC',
+ 'Atrule',
+ 'Rule',
+ 'Raw'
+ ]]
+};
+
+export function parse() {
+ const start = this.tokenStart;
+ const children = this.createList();
+ let child;
+
+ scan:
+ while (!this.eof) {
+ switch (this.tokenType) {
+ case WhiteSpace:
+ this.next();
+ continue;
+
+ case Comment:
+ // ignore comments except exclamation comments (i.e. /*! .. */) on top level
+ if (this.charCodeAt(this.tokenStart + 2) !== EXCLAMATIONMARK) {
+ this.next();
+ continue;
+ }
+
+ child = this.Comment();
+ break;
+
+ case CDO: // <!--
+ child = this.CDO();
+ break;
+
+ case CDC: // -->
+ child = this.CDC();
+ break;
+
+ // CSS Syntax Module Level 3
+ // §2.2 Error handling
+ // At the "top level" of a stylesheet, an <at-keyword-token> starts an at-rule.
+ case AtKeyword:
+ child = this.parseWithFallback(this.Atrule, consumeRaw);
+ break;
+
+ // Anything else starts a qualified rule ...
+ default:
+ child = this.parseWithFallback(this.Rule, consumeRaw);
+ }
+
+ children.push(child);
+ }
+
+ return {
+ type: 'StyleSheet',
+ loc: this.getLocation(start, this.tokenStart),
+ children
+ };
+}
+
+export function generate(node) {
+ this.children(node);
+}
diff --git a/vanilla/node_modules/css-tree/lib/syntax/node/SupportsDeclaration.js b/vanilla/node_modules/css-tree/lib/syntax/node/SupportsDeclaration.js
new file mode 100644
index 0000000..ee816e5
--- /dev/null
+++ b/vanilla/node_modules/css-tree/lib/syntax/node/SupportsDeclaration.js
@@ -0,0 +1,34 @@
+import {
+ LeftParenthesis,
+ RightParenthesis
+} from '../../tokenizer/index.js';
+
+export const name = 'SupportsDeclaration';
+export const structure = {
+ declaration: 'Declaration'
+};
+
+export function parse() {
+ const start = this.tokenStart;
+
+ this.eat(LeftParenthesis);
+ this.skipSC();
+
+ const declaration = this.Declaration();
+
+ if (!this.eof) {
+ this.eat(RightParenthesis);
+ }
+
+ return {
+ type: 'SupportsDeclaration',
+ loc: this.getLocation(start, this.tokenStart),
+ declaration
+ };
+}
+
+export function generate(node) {
+ this.token(LeftParenthesis, '(');
+ this.node(node.declaration);
+ this.token(RightParenthesis, ')');
+}
diff --git a/vanilla/node_modules/css-tree/lib/syntax/node/TypeSelector.js b/vanilla/node_modules/css-tree/lib/syntax/node/TypeSelector.js
new file mode 100644
index 0000000..272e195
--- /dev/null
+++ b/vanilla/node_modules/css-tree/lib/syntax/node/TypeSelector.js
@@ -0,0 +1,52 @@
+import { Ident } from '../../tokenizer/index.js';
+
+const ASTERISK = 0x002A; // U+002A ASTERISK (*)
+const VERTICALLINE = 0x007C; // U+007C VERTICAL LINE (|)
+
+function eatIdentifierOrAsterisk() {
+ if (this.tokenType !== Ident &&
+ this.isDelim(ASTERISK) === false) {
+ this.error('Identifier or asterisk is expected');
+ }
+
+ this.next();
+}
+
+export const name = 'TypeSelector';
+export const structure = {
+ name: String
+};
+
+// ident
+// ident|ident
+// ident|*
+// *
+// *|ident
+// *|*
+// |ident
+// |*
+export function parse() {
+ const start = this.tokenStart;
+
+ if (this.isDelim(VERTICALLINE)) {
+ this.next();
+ eatIdentifierOrAsterisk.call(this);
+ } else {
+ eatIdentifierOrAsterisk.call(this);
+
+ if (this.isDelim(VERTICALLINE)) {
+ this.next();
+ eatIdentifierOrAsterisk.call(this);
+ }
+ }
+
+ return {
+ type: 'TypeSelector',
+ loc: this.getLocation(start, this.tokenStart),
+ name: this.substrToCursor(start)
+ };
+}
+
+export function generate(node) {
+ this.tokenize(node.name);
+}
diff --git a/vanilla/node_modules/css-tree/lib/syntax/node/UnicodeRange.js b/vanilla/node_modules/css-tree/lib/syntax/node/UnicodeRange.js
new file mode 100644
index 0000000..95ee8b9
--- /dev/null
+++ b/vanilla/node_modules/css-tree/lib/syntax/node/UnicodeRange.js
@@ -0,0 +1,156 @@
+import {
+ isHexDigit,
+ Ident,
+ Number,
+ Dimension
+} from '../../tokenizer/index.js';
+
+const PLUSSIGN = 0x002B; // U+002B PLUS SIGN (+)
+const HYPHENMINUS = 0x002D; // U+002D HYPHEN-MINUS (-)
+const QUESTIONMARK = 0x003F; // U+003F QUESTION MARK (?)
+
+function eatHexSequence(offset, allowDash) {
+ let len = 0;
+
+ for (let pos = this.tokenStart + offset; pos < this.tokenEnd; pos++) {
+ const code = this.charCodeAt(pos);
+
+ if (code === HYPHENMINUS && allowDash && len !== 0) {
+ eatHexSequence.call(this, offset + len + 1, false);
+ return -1;
+ }
+
+ if (!isHexDigit(code)) {
+ this.error(
+ allowDash && len !== 0
+ ? 'Hyphen minus' + (len < 6 ? ' or hex digit' : '') + ' is expected'
+ : (len < 6 ? 'Hex digit is expected' : 'Unexpected input'),
+ pos
+ );
+ }
+
+ if (++len > 6) {
+ this.error('Too many hex digits', pos);
+ };
+ }
+
+ this.next();
+ return len;
+}
+
+function eatQuestionMarkSequence(max) {
+ let count = 0;
+
+ while (this.isDelim(QUESTIONMARK)) {
+ if (++count > max) {
+ this.error('Too many question marks');
+ }
+
+ this.next();
+ }
+}
+
+function startsWith(code) {
+ if (this.charCodeAt(this.tokenStart) !== code) {
+ this.error((code === PLUSSIGN ? 'Plus sign' : 'Hyphen minus') + ' is expected');
+ }
+}
+
+// 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 '+' '?'+
+function scanUnicodeRange() {
+ let hexLength = 0;
+
+ switch (this.tokenType) {
+ case Number:
+ // u <number-token> '?'*
+ // u <number-token> <dimension-token>
+ // u <number-token> <number-token>
+ hexLength = eatHexSequence.call(this, 1, true);
+
+ if (this.isDelim(QUESTIONMARK)) {
+ eatQuestionMarkSequence.call(this, 6 - hexLength);
+ break;
+ }
+
+ if (this.tokenType === Dimension ||
+ this.tokenType === Number) {
+ startsWith.call(this, HYPHENMINUS);
+ eatHexSequence.call(this, 1, false);
+ break;
+ }
+
+ break;
+
+ case Dimension:
+ // u <dimension-token> '?'*
+ hexLength = eatHexSequence.call(this, 1, true);
+
+ if (hexLength > 0) {
+ eatQuestionMarkSequence.call(this, 6 - hexLength);
+ }
+
+ break;
+
+ default:
+ // u '+' <ident-token> '?'*
+ // u '+' '?'+
+ this.eatDelim(PLUSSIGN);
+
+ if (this.tokenType === Ident) {
+ hexLength = eatHexSequence.call(this, 0, true);
+ if (hexLength > 0) {
+ eatQuestionMarkSequence.call(this, 6 - hexLength);
+ }
+ break;
+ }
+
+ if (this.isDelim(QUESTIONMARK)) {
+ this.next();
+ eatQuestionMarkSequence.call(this, 5);
+ break;
+ }
+
+ this.error('Hex digit or question mark is expected');
+ }
+}
+
+export const name = 'UnicodeRange';
+export const structure = {
+ value: String
+};
+
+export function parse() {
+ const start = this.tokenStart;
+
+ // U or u
+ this.eatIdent('u');
+ scanUnicodeRange.call(this);
+
+ return {
+ type: 'UnicodeRange',
+ loc: this.getLocation(start, this.tokenStart),
+ value: this.substrToCursor(start)
+ };
+}
+
+export function generate(node) {
+ this.tokenize(node.value);
+}
diff --git a/vanilla/node_modules/css-tree/lib/syntax/node/Url.js b/vanilla/node_modules/css-tree/lib/syntax/node/Url.js
new file mode 100644
index 0000000..ac52c9d
--- /dev/null
+++ b/vanilla/node_modules/css-tree/lib/syntax/node/Url.js
@@ -0,0 +1,52 @@
+import * as url from '../../utils/url.js';
+import * as string from '../../utils/string.js';
+import {
+ Function as FunctionToken,
+ String as StringToken,
+ Url,
+ RightParenthesis
+} from '../../tokenizer/index.js';
+
+export const name = 'Url';
+export const structure = {
+ value: String
+};
+
+// <url-token> | <function-token> <string> )
+export function parse() {
+ const start = this.tokenStart;
+ let value;
+
+ switch (this.tokenType) {
+ case Url:
+ value = url.decode(this.consume(Url));
+ break;
+
+ case FunctionToken:
+ if (!this.cmpStr(this.tokenStart, this.tokenEnd, 'url(')) {
+ this.error('Function name must be `url`');
+ }
+
+ this.eat(FunctionToken);
+ this.skipSC();
+ value = string.decode(this.consume(StringToken));
+ this.skipSC();
+ if (!this.eof) {
+ this.eat(RightParenthesis);
+ }
+ break;
+
+ default:
+ this.error('Url or Function is expected');
+ }
+
+ return {
+ type: 'Url',
+ loc: this.getLocation(start, this.tokenStart),
+ value
+ };
+}
+
+export function generate(node) {
+ this.token(Url, url.encode(node.value));
+}
diff --git a/vanilla/node_modules/css-tree/lib/syntax/node/Value.js b/vanilla/node_modules/css-tree/lib/syntax/node/Value.js
new file mode 100644
index 0000000..ba465bc
--- /dev/null
+++ b/vanilla/node_modules/css-tree/lib/syntax/node/Value.js
@@ -0,0 +1,19 @@
+export const name = 'Value';
+export const structure = {
+ children: [[]]
+};
+
+export function parse() {
+ const start = this.tokenStart;
+ const children = this.readSequence(this.scope.Value);
+
+ return {
+ type: 'Value',
+ loc: this.getLocation(start, this.tokenStart),
+ children
+ };
+}
+
+export function generate(node) {
+ this.children(node);
+}
diff --git a/vanilla/node_modules/css-tree/lib/syntax/node/WhiteSpace.js b/vanilla/node_modules/css-tree/lib/syntax/node/WhiteSpace.js
new file mode 100644
index 0000000..df34e6f
--- /dev/null
+++ b/vanilla/node_modules/css-tree/lib/syntax/node/WhiteSpace.js
@@ -0,0 +1,27 @@
+import { WhiteSpace } from '../../tokenizer/index.js';
+
+const SPACE = Object.freeze({
+ type: 'WhiteSpace',
+ loc: null,
+ value: ' '
+});
+
+export const name = 'WhiteSpace';
+export const structure = {
+ value: String
+};
+
+export function parse() {
+ this.eat(WhiteSpace);
+ return SPACE;
+
+ // return {
+ // type: 'WhiteSpace',
+ // loc: this.getLocation(this.tokenStart, this.tokenEnd),
+ // value: this.consume(WHITESPACE)
+ // };
+}
+
+export function generate(node) {
+ this.token(WhiteSpace, node.value);
+}
diff --git a/vanilla/node_modules/css-tree/lib/syntax/node/index-generate.js b/vanilla/node_modules/css-tree/lib/syntax/node/index-generate.js
new file mode 100644
index 0000000..568736f
--- /dev/null
+++ b/vanilla/node_modules/css-tree/lib/syntax/node/index-generate.js
@@ -0,0 +1,49 @@
+export { generate as AnPlusB } from './AnPlusB.js';
+export { generate as Atrule } from './Atrule.js';
+export { generate as AtrulePrelude } from './AtrulePrelude.js';
+export { generate as AttributeSelector } from './AttributeSelector.js';
+export { generate as Block } from './Block.js';
+export { generate as Brackets } from './Brackets.js';
+export { generate as CDC } from './CDC.js';
+export { generate as CDO } from './CDO.js';
+export { generate as ClassSelector } from './ClassSelector.js';
+export { generate as Combinator } from './Combinator.js';
+export { generate as Comment } from './Comment.js';
+export { generate as Condition } from './Condition.js';
+export { generate as Declaration } from './Declaration.js';
+export { generate as DeclarationList } from './DeclarationList.js';
+export { generate as Dimension } from './Dimension.js';
+export { generate as Feature } from './Feature.js';
+export { generate as FeatureFunction } from './FeatureFunction.js';
+export { generate as FeatureRange } from './FeatureRange.js';
+export { generate as Function } from './Function.js';
+export { generate as GeneralEnclosed } from './GeneralEnclosed.js';
+export { generate as Hash } from './Hash.js';
+export { generate as Identifier } from './Identifier.js';
+export { generate as IdSelector } from './IdSelector.js';
+export { generate as Layer } from './Layer.js';
+export { generate as LayerList } from './LayerList.js';
+export { generate as MediaQuery } from './MediaQuery.js';
+export { generate as MediaQueryList } from './MediaQueryList.js';
+export { generate as NestingSelector } from './NestingSelector.js';
+export { generate as Nth } from './Nth.js';
+export { generate as Number } from './Number.js';
+export { generate as Operator } from './Operator.js';
+export { generate as Parentheses } from './Parentheses.js';
+export { generate as Percentage } from './Percentage.js';
+export { generate as PseudoClassSelector } from './PseudoClassSelector.js';
+export { generate as PseudoElementSelector } from './PseudoElementSelector.js';
+export { generate as Ratio } from './Ratio.js';
+export { generate as Raw } from './Raw.js';
+export { generate as Rule } from './Rule.js';
+export { generate as Scope } from './Scope.js';
+export { generate as Selector } from './Selector.js';
+export { generate as SelectorList } from './SelectorList.js';
+export { generate as String } from './String.js';
+export { generate as StyleSheet } from './StyleSheet.js';
+export { generate as SupportsDeclaration } from './SupportsDeclaration.js';
+export { generate as TypeSelector } from './TypeSelector.js';
+export { generate as UnicodeRange } from './UnicodeRange.js';
+export { generate as Url } from './Url.js';
+export { generate as Value } from './Value.js';
+export { generate as WhiteSpace } from './WhiteSpace.js';
diff --git a/vanilla/node_modules/css-tree/lib/syntax/node/index-parse-selector.js b/vanilla/node_modules/css-tree/lib/syntax/node/index-parse-selector.js
new file mode 100644
index 0000000..3a0a2a3
--- /dev/null
+++ b/vanilla/node_modules/css-tree/lib/syntax/node/index-parse-selector.js
@@ -0,0 +1,17 @@
+export { parse as AnPlusB } from './AnPlusB.js';
+export { parse as AttributeSelector } from './AttributeSelector.js';
+export { parse as ClassSelector } from './ClassSelector.js';
+export { parse as Combinator } from './Combinator.js';
+export { parse as Identifier } from './Identifier.js';
+export { parse as IdSelector } from './IdSelector.js';
+export { parse as NestingSelector } from './NestingSelector.js';
+export { parse as Nth } from './Nth.js';
+export { parse as Operator } from './Operator.js';
+export { parse as Percentage } from './Percentage.js';
+export { parse as PseudoClassSelector } from './PseudoClassSelector.js';
+export { parse as PseudoElementSelector } from './PseudoElementSelector.js';
+export { parse as Raw } from './Raw.js';
+export { parse as Selector } from './Selector.js';
+export { parse as SelectorList } from './SelectorList.js';
+export { parse as String } from './String.js';
+export { parse as TypeSelector } from './TypeSelector.js';
diff --git a/vanilla/node_modules/css-tree/lib/syntax/node/index-parse.js b/vanilla/node_modules/css-tree/lib/syntax/node/index-parse.js
new file mode 100644
index 0000000..80136d3
--- /dev/null
+++ b/vanilla/node_modules/css-tree/lib/syntax/node/index-parse.js
@@ -0,0 +1,49 @@
+export { parse as AnPlusB } from './AnPlusB.js';
+export { parse as Atrule } from './Atrule.js';
+export { parse as AtrulePrelude } from './AtrulePrelude.js';
+export { parse as AttributeSelector } from './AttributeSelector.js';
+export { parse as Block } from './Block.js';
+export { parse as Brackets } from './Brackets.js';
+export { parse as CDC } from './CDC.js';
+export { parse as CDO } from './CDO.js';
+export { parse as ClassSelector } from './ClassSelector.js';
+export { parse as Combinator } from './Combinator.js';
+export { parse as Comment } from './Comment.js';
+export { parse as Condition } from './Condition.js';
+export { parse as Declaration } from './Declaration.js';
+export { parse as DeclarationList } from './DeclarationList.js';
+export { parse as Dimension } from './Dimension.js';
+export { parse as Feature } from './Feature.js';
+export { parse as FeatureFunction } from './FeatureFunction.js';
+export { parse as FeatureRange } from './FeatureRange.js';
+export { parse as Function } from './Function.js';
+export { parse as GeneralEnclosed } from './GeneralEnclosed.js';
+export { parse as Hash } from './Hash.js';
+export { parse as Identifier } from './Identifier.js';
+export { parse as IdSelector } from './IdSelector.js';
+export { parse as Layer } from './Layer.js';
+export { parse as LayerList } from './LayerList.js';
+export { parse as MediaQuery } from './MediaQuery.js';
+export { parse as MediaQueryList } from './MediaQueryList.js';
+export { parse as NestingSelector } from './NestingSelector.js';
+export { parse as Nth } from './Nth.js';
+export { parse as Number } from './Number.js';
+export { parse as Operator } from './Operator.js';
+export { parse as Parentheses } from './Parentheses.js';
+export { parse as Percentage } from './Percentage.js';
+export { parse as PseudoClassSelector } from './PseudoClassSelector.js';
+export { parse as PseudoElementSelector } from './PseudoElementSelector.js';
+export { parse as Ratio } from './Ratio.js';
+export { parse as Raw } from './Raw.js';
+export { parse as Rule } from './Rule.js';
+export { parse as Scope } from './Scope.js';
+export { parse as Selector } from './Selector.js';
+export { parse as SelectorList } from './SelectorList.js';
+export { parse as String } from './String.js';
+export { parse as StyleSheet } from './StyleSheet.js';
+export { parse as SupportsDeclaration } from './SupportsDeclaration.js';
+export { parse as TypeSelector } from './TypeSelector.js';
+export { parse as UnicodeRange } from './UnicodeRange.js';
+export { parse as Url } from './Url.js';
+export { parse as Value } from './Value.js';
+export { parse as WhiteSpace } from './WhiteSpace.js';
diff --git a/vanilla/node_modules/css-tree/lib/syntax/node/index.js b/vanilla/node_modules/css-tree/lib/syntax/node/index.js
new file mode 100644
index 0000000..4aa2dea
--- /dev/null
+++ b/vanilla/node_modules/css-tree/lib/syntax/node/index.js
@@ -0,0 +1,49 @@
+export * as AnPlusB from './AnPlusB.js';
+export * as Atrule from './Atrule.js';
+export * as AtrulePrelude from './AtrulePrelude.js';
+export * as AttributeSelector from './AttributeSelector.js';
+export * as Block from './Block.js';
+export * as Brackets from './Brackets.js';
+export * as CDC from './CDC.js';
+export * as CDO from './CDO.js';
+export * as ClassSelector from './ClassSelector.js';
+export * as Combinator from './Combinator.js';
+export * as Comment from './Comment.js';
+export * as Condition from './Condition.js';
+export * as Declaration from './Declaration.js';
+export * as DeclarationList from './DeclarationList.js';
+export * as Dimension from './Dimension.js';
+export * as Feature from './Feature.js';
+export * as FeatureFunction from './FeatureFunction.js';
+export * as FeatureRange from './FeatureRange.js';
+export * as Function from './Function.js';
+export * as GeneralEnclosed from './GeneralEnclosed.js';
+export * as Hash from './Hash.js';
+export * as Identifier from './Identifier.js';
+export * as IdSelector from './IdSelector.js';
+export * as Layer from './Layer.js';
+export * as LayerList from './LayerList.js';
+export * as MediaQuery from './MediaQuery.js';
+export * as MediaQueryList from './MediaQueryList.js';
+export * as NestingSelector from './NestingSelector.js';
+export * as Nth from './Nth.js';
+export * as Number from './Number.js';
+export * as Operator from './Operator.js';
+export * as Parentheses from './Parentheses.js';
+export * as Percentage from './Percentage.js';
+export * as PseudoClassSelector from './PseudoClassSelector.js';
+export * as PseudoElementSelector from './PseudoElementSelector.js';
+export * as Ratio from './Ratio.js';
+export * as Raw from './Raw.js';
+export * as Rule from './Rule.js';
+export * as Scope from './Scope.js';
+export * as Selector from './Selector.js';
+export * as SelectorList from './SelectorList.js';
+export * as String from './String.js';
+export * as StyleSheet from './StyleSheet.js';
+export * as SupportsDeclaration from './SupportsDeclaration.js';
+export * as TypeSelector from './TypeSelector.js';
+export * as UnicodeRange from './UnicodeRange.js';
+export * as Url from './Url.js';
+export * as Value from './Value.js';
+export * as WhiteSpace from './WhiteSpace.js';