aboutsummaryrefslogtreecommitdiffstats
path: root/vanilla/node_modules/css-tree/cjs/definition-syntax
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/cjs/definition-syntax
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/cjs/definition-syntax')
-rw-r--r--vanilla/node_modules/css-tree/cjs/definition-syntax/SyntaxError.cjs16
-rw-r--r--vanilla/node_modules/css-tree/cjs/definition-syntax/generate.cjs139
-rw-r--r--vanilla/node_modules/css-tree/cjs/definition-syntax/index.cjs13
-rw-r--r--vanilla/node_modules/css-tree/cjs/definition-syntax/parse.cjs556
-rw-r--r--vanilla/node_modules/css-tree/cjs/definition-syntax/scanner.cjs113
-rw-r--r--vanilla/node_modules/css-tree/cjs/definition-syntax/tokenizer.cjs59
-rw-r--r--vanilla/node_modules/css-tree/cjs/definition-syntax/walk.cjs57
7 files changed, 953 insertions, 0 deletions
diff --git a/vanilla/node_modules/css-tree/cjs/definition-syntax/SyntaxError.cjs b/vanilla/node_modules/css-tree/cjs/definition-syntax/SyntaxError.cjs
new file mode 100644
index 0000000..d24e7ce
--- /dev/null
+++ b/vanilla/node_modules/css-tree/cjs/definition-syntax/SyntaxError.cjs
@@ -0,0 +1,16 @@
+'use strict';
+
+const createCustomError = require('../utils/create-custom-error.cjs');
+
+function SyntaxError(message, input, offset) {
+ return Object.assign(createCustomError.createCustomError('SyntaxError', message), {
+ input,
+ offset,
+ rawMessage: message,
+ message: message + '\n' +
+ ' ' + input + '\n' +
+ '--' + new Array((offset || input.length) + 1).join('-') + '^'
+ });
+}
+
+exports.SyntaxError = SyntaxError;
diff --git a/vanilla/node_modules/css-tree/cjs/definition-syntax/generate.cjs b/vanilla/node_modules/css-tree/cjs/definition-syntax/generate.cjs
new file mode 100644
index 0000000..ff9f0ad
--- /dev/null
+++ b/vanilla/node_modules/css-tree/cjs/definition-syntax/generate.cjs
@@ -0,0 +1,139 @@
+'use strict';
+
+function noop(value) {
+ return value;
+}
+
+function generateMultiplier(multiplier) {
+ const { min, max, comma } = multiplier;
+
+ if (min === 0 && max === 0) {
+ return comma ? '#?' : '*';
+ }
+
+ if (min === 0 && max === 1) {
+ return '?';
+ }
+
+ if (min === 1 && max === 0) {
+ return comma ? '#' : '+';
+ }
+
+ if (min === 1 && max === 1) {
+ return '';
+ }
+
+ return (
+ (comma ? '#' : '') +
+ (min === max
+ ? '{' + min + '}'
+ : '{' + min + ',' + (max !== 0 ? max : '') + '}'
+ )
+ );
+}
+
+function generateTypeOpts(node) {
+ switch (node.type) {
+ case 'Range':
+ return (
+ ' [' +
+ (node.min === null ? '-∞' : node.min) +
+ ',' +
+ (node.max === null ? '∞' : node.max) +
+ ']'
+ );
+
+ default:
+ throw new Error('Unknown node type `' + node.type + '`');
+ }
+}
+
+function generateSequence(node, decorate, forceBraces, compact) {
+ const combinator = node.combinator === ' ' || compact ? node.combinator : ' ' + node.combinator + ' ';
+ const result = node.terms
+ .map(term => internalGenerate(term, decorate, forceBraces, compact))
+ .join(combinator);
+
+ if (node.explicit || forceBraces) {
+ return (compact || result[0] === ',' ? '[' : '[ ') + result + (compact ? ']' : ' ]');
+ }
+
+ return result;
+}
+
+function internalGenerate(node, decorate, forceBraces, compact) {
+ let result;
+
+ switch (node.type) {
+ case 'Group':
+ result =
+ generateSequence(node, decorate, forceBraces, compact) +
+ (node.disallowEmpty ? '!' : '');
+ break;
+
+ case 'Multiplier':
+ // return since node is a composition
+ return (
+ internalGenerate(node.term, decorate, forceBraces, compact) +
+ decorate(generateMultiplier(node), node)
+ );
+
+ case 'Boolean':
+ result = '<boolean-expr[' + internalGenerate(node.term, decorate, forceBraces, compact) + ']>';
+ break;
+
+ case 'Type':
+ result = '<' + node.name + (node.opts ? decorate(generateTypeOpts(node.opts), node.opts) : '') + '>';
+ break;
+
+ case 'Property':
+ result = '<\'' + node.name + '\'>';
+ break;
+
+ case 'Keyword':
+ result = node.name;
+ break;
+
+ case 'AtKeyword':
+ result = '@' + node.name;
+ break;
+
+ case 'Function':
+ result = node.name + '(';
+ break;
+
+ case 'String':
+ case 'Token':
+ result = node.value;
+ break;
+
+ case 'Comma':
+ result = ',';
+ break;
+
+ default:
+ throw new Error('Unknown node type `' + node.type + '`');
+ }
+
+ return decorate(result, node);
+}
+
+function generate(node, options) {
+ let decorate = noop;
+ let forceBraces = false;
+ let compact = false;
+
+ if (typeof options === 'function') {
+ decorate = options;
+ } else if (options) {
+ forceBraces = Boolean(options.forceBraces);
+ compact = Boolean(options.compact);
+ if (typeof options.decorate === 'function') {
+ decorate = options.decorate;
+ }
+ }
+
+ return internalGenerate(node, decorate, forceBraces, compact);
+}
+
+exports.generate = generate;
diff --git a/vanilla/node_modules/css-tree/cjs/definition-syntax/index.cjs b/vanilla/node_modules/css-tree/cjs/definition-syntax/index.cjs
new file mode 100644
index 0000000..0afb505
--- /dev/null
+++ b/vanilla/node_modules/css-tree/cjs/definition-syntax/index.cjs
@@ -0,0 +1,13 @@
+'use strict';
+
+const SyntaxError = require('./SyntaxError.cjs');
+const generate = require('./generate.cjs');
+const parse = require('./parse.cjs');
+const walk = require('./walk.cjs');
+
+
+
+exports.SyntaxError = SyntaxError.SyntaxError;
+exports.generate = generate.generate;
+exports.parse = parse.parse;
+exports.walk = walk.walk;
diff --git a/vanilla/node_modules/css-tree/cjs/definition-syntax/parse.cjs b/vanilla/node_modules/css-tree/cjs/definition-syntax/parse.cjs
new file mode 100644
index 0000000..b17b267
--- /dev/null
+++ b/vanilla/node_modules/css-tree/cjs/definition-syntax/parse.cjs
@@ -0,0 +1,556 @@
+'use strict';
+
+const scanner = require('./scanner.cjs');
+
+const TAB = 9;
+const N = 10;
+const F = 12;
+const R = 13;
+const SPACE = 32;
+const EXCLAMATIONMARK = 33; // !
+const NUMBERSIGN = 35; // #
+const AMPERSAND = 38; // &
+const APOSTROPHE = 39; // '
+const LEFTPARENTHESIS = 40; // (
+const RIGHTPARENTHESIS = 41; // )
+const ASTERISK = 42; // *
+const PLUSSIGN = 43; // +
+const COMMA = 44; // ,
+const HYPERMINUS = 45; // -
+const LESSTHANSIGN = 60; // <
+const GREATERTHANSIGN = 62; // >
+const QUESTIONMARK = 63; // ?
+const COMMERCIALAT = 64; // @
+const LEFTSQUAREBRACKET = 91; // [
+const RIGHTSQUAREBRACKET = 93; // ]
+const LEFTCURLYBRACKET = 123; // {
+const VERTICALLINE = 124; // |
+const RIGHTCURLYBRACKET = 125; // }
+const INFINITY = 8734; // ∞
+const COMBINATOR_PRECEDENCE = {
+ ' ': 1,
+ '&&': 2,
+ '||': 3,
+ '|': 4
+};
+
+function readMultiplierRange(scanner) {
+ let min = null;
+ let max = null;
+
+ scanner.eat(LEFTCURLYBRACKET);
+ scanner.skipWs();
+
+ min = scanner.scanNumber(scanner);
+ scanner.skipWs();
+
+ if (scanner.charCode() === COMMA) {
+ scanner.pos++;
+ scanner.skipWs();
+
+ if (scanner.charCode() !== RIGHTCURLYBRACKET) {
+ max = scanner.scanNumber(scanner);
+ scanner.skipWs();
+ }
+ } else {
+ max = min;
+ }
+
+ scanner.eat(RIGHTCURLYBRACKET);
+
+ return {
+ min: Number(min),
+ max: max ? Number(max) : 0
+ };
+}
+
+function readMultiplier(scanner) {
+ let range = null;
+ let comma = false;
+
+ switch (scanner.charCode()) {
+ case ASTERISK:
+ scanner.pos++;
+
+ range = {
+ min: 0,
+ max: 0
+ };
+
+ break;
+
+ case PLUSSIGN:
+ scanner.pos++;
+
+ range = {
+ min: 1,
+ max: 0
+ };
+
+ break;
+
+ case QUESTIONMARK:
+ scanner.pos++;
+
+ range = {
+ min: 0,
+ max: 1
+ };
+
+ break;
+
+ case NUMBERSIGN:
+ scanner.pos++;
+
+ comma = true;
+
+ if (scanner.charCode() === LEFTCURLYBRACKET) {
+ range = readMultiplierRange(scanner);
+ } else if (scanner.charCode() === QUESTIONMARK) {
+ // https://www.w3.org/TR/css-values-4/#component-multipliers
+ // > the # and ? multipliers may be stacked as #?
+ // In this case just treat "#?" as a single multiplier
+ // { min: 0, max: 0, comma: true }
+ scanner.pos++;
+ range = {
+ min: 0,
+ max: 0
+ };
+ } else {
+ range = {
+ min: 1,
+ max: 0
+ };
+ }
+
+ break;
+
+ case LEFTCURLYBRACKET:
+ range = readMultiplierRange(scanner);
+ break;
+
+ default:
+ return null;
+ }
+
+ return {
+ type: 'Multiplier',
+ comma,
+ min: range.min,
+ max: range.max,
+ term: null
+ };
+}
+
+function maybeMultiplied(scanner, node) {
+ const multiplier = readMultiplier(scanner);
+
+ if (multiplier !== null) {
+ multiplier.term = node;
+
+ // https://www.w3.org/TR/css-values-4/#component-multipliers
+ // > The + and # multipliers may be stacked as +#;
+ // Represent "+#" as nested multipliers:
+ // { ...<multiplier #>,
+ // term: {
+ // ...<multipler +>,
+ // term: node
+ // }
+ // }
+ if (scanner.charCode() === NUMBERSIGN &&
+ scanner.charCodeAt(scanner.pos - 1) === PLUSSIGN) {
+ return maybeMultiplied(scanner, multiplier);
+ }
+
+ return multiplier;
+ }
+
+ return node;
+}
+
+function maybeToken(scanner) {
+ const ch = scanner.peek();
+
+ if (ch === '') {
+ return null;
+ }
+
+ return maybeMultiplied(scanner, {
+ type: 'Token',
+ value: ch
+ });
+}
+
+function readProperty(scanner) {
+ let name;
+
+ scanner.eat(LESSTHANSIGN);
+ scanner.eat(APOSTROPHE);
+
+ name = scanner.scanWord();
+
+ scanner.eat(APOSTROPHE);
+ scanner.eat(GREATERTHANSIGN);
+
+ return maybeMultiplied(scanner, {
+ type: 'Property',
+ name
+ });
+}
+
+// https://drafts.csswg.org/css-values-3/#numeric-ranges
+// 4.1. Range Restrictions and Range Definition Notation
+//
+// Range restrictions can be annotated in the numeric type notation using CSS bracketed
+// range notation—[min,max]—within the angle brackets, after the identifying keyword,
+// indicating a closed range between (and including) min and max.
+// For example, <integer [0, 10]> indicates an integer between 0 and 10, inclusive.
+function readTypeRange(scanner) {
+ // use null for Infinity to make AST format JSON serializable/deserializable
+ let min = null; // -Infinity
+ let max = null; // Infinity
+ let sign = 1;
+
+ scanner.eat(LEFTSQUAREBRACKET);
+
+ if (scanner.charCode() === HYPERMINUS) {
+ scanner.peek();
+ sign = -1;
+ }
+
+ if (sign == -1 && scanner.charCode() === INFINITY) {
+ scanner.peek();
+ } else {
+ min = sign * Number(scanner.scanNumber(scanner));
+
+ if (scanner.isNameCharCode()) {
+ min += scanner.scanWord();
+ }
+ }
+
+ scanner.skipWs();
+ scanner.eat(COMMA);
+ scanner.skipWs();
+
+ if (scanner.charCode() === INFINITY) {
+ scanner.peek();
+ } else {
+ sign = 1;
+
+ if (scanner.charCode() === HYPERMINUS) {
+ scanner.peek();
+ sign = -1;
+ }
+
+ max = sign * Number(scanner.scanNumber(scanner));
+
+ if (scanner.isNameCharCode()) {
+ max += scanner.scanWord();
+ }
+ }
+
+ scanner.eat(RIGHTSQUAREBRACKET);
+
+ return {
+ type: 'Range',
+ min,
+ max
+ };
+}
+
+function readType(scanner) {
+ let name;
+ let opts = null;
+
+ scanner.eat(LESSTHANSIGN);
+ name = scanner.scanWord();
+
+ // https://drafts.csswg.org/css-values-5/#boolean
+ if (name === 'boolean-expr') {
+ scanner.eat(LEFTSQUAREBRACKET);
+
+ const implicitGroup = readImplicitGroup(scanner, RIGHTSQUAREBRACKET);
+
+ scanner.eat(RIGHTSQUAREBRACKET);
+ scanner.eat(GREATERTHANSIGN);
+
+ return maybeMultiplied(scanner, {
+ type: 'Boolean',
+ term: implicitGroup.terms.length === 1
+ ? implicitGroup.terms[0]
+ : implicitGroup
+ });
+ }
+
+ if (scanner.charCode() === LEFTPARENTHESIS &&
+ scanner.nextCharCode() === RIGHTPARENTHESIS) {
+ scanner.pos += 2;
+ name += '()';
+ }
+
+ if (scanner.charCodeAt(scanner.findWsEnd(scanner.pos)) === LEFTSQUAREBRACKET) {
+ scanner.skipWs();
+ opts = readTypeRange(scanner);
+ }
+
+ scanner.eat(GREATERTHANSIGN);
+
+ return maybeMultiplied(scanner, {
+ type: 'Type',
+ name,
+ opts
+ });
+}
+
+function readKeywordOrFunction(scanner) {
+ const name = scanner.scanWord();
+
+ if (scanner.charCode() === LEFTPARENTHESIS) {
+ scanner.pos++;
+
+ return {
+ type: 'Function',
+ name
+ };
+ }
+
+ return maybeMultiplied(scanner, {
+ type: 'Keyword',
+ name
+ });
+}
+
+function regroupTerms(terms, combinators) {
+ function createGroup(terms, combinator) {
+ return {
+ type: 'Group',
+ terms,
+ combinator,
+ disallowEmpty: false,
+ explicit: false
+ };
+ }
+
+ let combinator;
+
+ combinators = Object.keys(combinators)
+ .sort((a, b) => COMBINATOR_PRECEDENCE[a] - COMBINATOR_PRECEDENCE[b]);
+
+ while (combinators.length > 0) {
+ combinator = combinators.shift();
+
+ let i = 0;
+ let subgroupStart = 0;
+
+ for (; i < terms.length; i++) {
+ const term = terms[i];
+
+ if (term.type === 'Combinator') {
+ if (term.value === combinator) {
+ if (subgroupStart === -1) {
+ subgroupStart = i - 1;
+ }
+ terms.splice(i, 1);
+ i--;
+ } else {
+ if (subgroupStart !== -1 && i - subgroupStart > 1) {
+ terms.splice(
+ subgroupStart,
+ i - subgroupStart,
+ createGroup(terms.slice(subgroupStart, i), combinator)
+ );
+ i = subgroupStart + 1;
+ }
+ subgroupStart = -1;
+ }
+ }
+ }
+
+ if (subgroupStart !== -1 && combinators.length) {
+ terms.splice(
+ subgroupStart,
+ i - subgroupStart,
+ createGroup(terms.slice(subgroupStart, i), combinator)
+ );
+ }
+ }
+
+ return combinator;
+}
+
+function readImplicitGroup(scanner, stopCharCode) {
+ const combinators = Object.create(null);
+ const terms = [];
+ let token;
+ let prevToken = null;
+ let prevTokenPos = scanner.pos;
+
+ while (scanner.charCode() !== stopCharCode && (token = peek(scanner, stopCharCode))) {
+ if (token.type !== 'Spaces') {
+ if (token.type === 'Combinator') {
+ // check for combinator in group beginning and double combinator sequence
+ if (prevToken === null || prevToken.type === 'Combinator') {
+ scanner.pos = prevTokenPos;
+ scanner.error('Unexpected combinator');
+ }
+
+ combinators[token.value] = true;
+ } else if (prevToken !== null && prevToken.type !== 'Combinator') {
+ combinators[' '] = true; // a b
+ terms.push({
+ type: 'Combinator',
+ value: ' '
+ });
+ }
+
+ terms.push(token);
+ prevToken = token;
+ prevTokenPos = scanner.pos;
+ }
+ }
+
+ // check for combinator in group ending
+ if (prevToken !== null && prevToken.type === 'Combinator') {
+ scanner.pos -= prevTokenPos;
+ scanner.error('Unexpected combinator');
+ }
+
+ return {
+ type: 'Group',
+ terms,
+ combinator: regroupTerms(terms, combinators) || ' ',
+ disallowEmpty: false,
+ explicit: false
+ };
+}
+
+function readGroup(scanner, stopCharCode) {
+ let result;
+
+ scanner.eat(LEFTSQUAREBRACKET);
+ result = readImplicitGroup(scanner, stopCharCode);
+ scanner.eat(RIGHTSQUAREBRACKET);
+
+ result.explicit = true;
+
+ if (scanner.charCode() === EXCLAMATIONMARK) {
+ scanner.pos++;
+ result.disallowEmpty = true;
+ }
+
+ return result;
+}
+
+function peek(scanner, stopCharCode) {
+ let code = scanner.charCode();
+
+ switch (code) {
+ case RIGHTSQUAREBRACKET:
+ // don't eat, stop scan a group
+ break;
+
+ case LEFTSQUAREBRACKET:
+ return maybeMultiplied(scanner, readGroup(scanner, stopCharCode));
+
+ case LESSTHANSIGN:
+ return scanner.nextCharCode() === APOSTROPHE
+ ? readProperty(scanner)
+ : readType(scanner);
+
+ case VERTICALLINE:
+ return {
+ type: 'Combinator',
+ value: scanner.substringToPos(
+ scanner.pos + (scanner.nextCharCode() === VERTICALLINE ? 2 : 1)
+ )
+ };
+
+ case AMPERSAND:
+ scanner.pos++;
+ scanner.eat(AMPERSAND);
+
+ return {
+ type: 'Combinator',
+ value: '&&'
+ };
+
+ case COMMA:
+ scanner.pos++;
+ return {
+ type: 'Comma'
+ };
+
+ case APOSTROPHE:
+ return maybeMultiplied(scanner, {
+ type: 'String',
+ value: scanner.scanString()
+ });
+
+ case SPACE:
+ case TAB:
+ case N:
+ case R:
+ case F:
+ return {
+ type: 'Spaces',
+ value: scanner.scanSpaces()
+ };
+
+ case COMMERCIALAT:
+ code = scanner.nextCharCode();
+
+ if (scanner.isNameCharCode(code)) {
+ scanner.pos++;
+ return {
+ type: 'AtKeyword',
+ name: scanner.scanWord()
+ };
+ }
+
+ return maybeToken(scanner);
+
+ case ASTERISK:
+ case PLUSSIGN:
+ case QUESTIONMARK:
+ case NUMBERSIGN:
+ case EXCLAMATIONMARK:
+ // prohibited tokens (used as a multiplier start)
+ break;
+
+ case LEFTCURLYBRACKET:
+ // LEFTCURLYBRACKET is allowed since mdn/data uses it w/o quoting
+ // check next char isn't a number, because it's likely a disjoined multiplier
+ code = scanner.nextCharCode();
+
+ if (code < 48 || code > 57) {
+ return maybeToken(scanner);
+ }
+
+ break;
+
+ default:
+ if (scanner.isNameCharCode(code)) {
+ return readKeywordOrFunction(scanner);
+ }
+
+ return maybeToken(scanner);
+ }
+}
+
+function parse(source) {
+ const scanner$1 = new scanner.Scanner(source);
+ const result = readImplicitGroup(scanner$1);
+
+ if (scanner$1.pos !== source.length) {
+ scanner$1.error('Unexpected input');
+ }
+
+ // reduce redundant groups with single group term
+ if (result.terms.length === 1 && result.terms[0].type === 'Group') {
+ return result.terms[0];
+ }
+
+ return result;
+}
+
+exports.parse = parse;
diff --git a/vanilla/node_modules/css-tree/cjs/definition-syntax/scanner.cjs b/vanilla/node_modules/css-tree/cjs/definition-syntax/scanner.cjs
new file mode 100644
index 0000000..0bad36a
--- /dev/null
+++ b/vanilla/node_modules/css-tree/cjs/definition-syntax/scanner.cjs
@@ -0,0 +1,113 @@
+'use strict';
+
+const SyntaxError = require('./SyntaxError.cjs');
+
+const TAB = 9;
+const N = 10;
+const F = 12;
+const R = 13;
+const SPACE = 32;
+const NAME_CHAR = new Uint8Array(128).map((_, idx) =>
+ /[a-zA-Z0-9\-]/.test(String.fromCharCode(idx)) ? 1 : 0
+);
+
+class Scanner {
+ constructor(str) {
+ this.str = str;
+ this.pos = 0;
+ }
+
+ charCodeAt(pos) {
+ return pos < this.str.length ? this.str.charCodeAt(pos) : 0;
+ }
+ charCode() {
+ return this.charCodeAt(this.pos);
+ }
+ isNameCharCode(code = this.charCode()) {
+ return code < 128 && NAME_CHAR[code] === 1;
+ }
+ nextCharCode() {
+ return this.charCodeAt(this.pos + 1);
+ }
+ nextNonWsCode(pos) {
+ return this.charCodeAt(this.findWsEnd(pos));
+ }
+ skipWs() {
+ this.pos = this.findWsEnd(this.pos);
+ }
+ findWsEnd(pos) {
+ for (; pos < this.str.length; pos++) {
+ const code = this.str.charCodeAt(pos);
+ if (code !== R && code !== N && code !== F && code !== SPACE && code !== TAB) {
+ break;
+ }
+ }
+
+ return pos;
+ }
+ substringToPos(end) {
+ return this.str.substring(this.pos, this.pos = end);
+ }
+ eat(code) {
+ if (this.charCode() !== code) {
+ this.error('Expect `' + String.fromCharCode(code) + '`');
+ }
+
+ this.pos++;
+ }
+ peek() {
+ return this.pos < this.str.length ? this.str.charAt(this.pos++) : '';
+ }
+ error(message) {
+ throw new SyntaxError.SyntaxError(message, this.str, this.pos);
+ }
+
+ scanSpaces() {
+ return this.substringToPos(this.findWsEnd(this.pos));
+ }
+ scanWord() {
+ let end = this.pos;
+
+ for (; end < this.str.length; end++) {
+ const code = this.str.charCodeAt(end);
+ if (code >= 128 || NAME_CHAR[code] === 0) {
+ break;
+ }
+ }
+
+ if (this.pos === end) {
+ this.error('Expect a keyword');
+ }
+
+ return this.substringToPos(end);
+ }
+ scanNumber() {
+ let end = this.pos;
+
+ for (; end < this.str.length; end++) {
+ const code = this.str.charCodeAt(end);
+
+ if (code < 48 || code > 57) {
+ break;
+ }
+ }
+
+ if (this.pos === end) {
+ this.error('Expect a number');
+ }
+
+ return this.substringToPos(end);
+ }
+ scanString() {
+ const end = this.str.indexOf('\'', this.pos + 1);
+
+ if (end === -1) {
+ this.pos = this.str.length;
+ this.error('Expect an apostrophe');
+ }
+
+ return this.substringToPos(end + 1);
+ }
+}
+
+exports.Scanner = Scanner;
diff --git a/vanilla/node_modules/css-tree/cjs/definition-syntax/tokenizer.cjs b/vanilla/node_modules/css-tree/cjs/definition-syntax/tokenizer.cjs
new file mode 100644
index 0000000..2b934bd
--- /dev/null
+++ b/vanilla/node_modules/css-tree/cjs/definition-syntax/tokenizer.cjs
@@ -0,0 +1,59 @@
+'use strict';
+
+const SyntaxError = require('./SyntaxError.cjs');
+
+const TAB = 9;
+const N = 10;
+const F = 12;
+const R = 13;
+const SPACE = 32;
+
+class Tokenizer {
+ constructor(str) {
+ this.str = str;
+ this.pos = 0;
+ }
+ charCodeAt(pos) {
+ return pos < this.str.length ? this.str.charCodeAt(pos) : 0;
+ }
+ charCode() {
+ return this.charCodeAt(this.pos);
+ }
+ nextCharCode() {
+ return this.charCodeAt(this.pos + 1);
+ }
+ nextNonWsCode(pos) {
+ return this.charCodeAt(this.findWsEnd(pos));
+ }
+ skipWs() {
+ this.pos = this.findWsEnd(this.pos);
+ }
+ findWsEnd(pos) {
+ for (; pos < this.str.length; pos++) {
+ const code = this.str.charCodeAt(pos);
+ if (code !== R && code !== N && code !== F && code !== SPACE && code !== TAB) {
+ break;
+ }
+ }
+
+ return pos;
+ }
+ substringToPos(end) {
+ return this.str.substring(this.pos, this.pos = end);
+ }
+ eat(code) {
+ if (this.charCode() !== code) {
+ this.error('Expect `' + String.fromCharCode(code) + '`');
+ }
+
+ this.pos++;
+ }
+ peek() {
+ return this.pos < this.str.length ? this.str.charAt(this.pos++) : '';
+ }
+ error(message) {
+ throw new SyntaxError.SyntaxError(message, this.str, this.pos);
+ }
+}
+
+exports.Tokenizer = Tokenizer;
diff --git a/vanilla/node_modules/css-tree/cjs/definition-syntax/walk.cjs b/vanilla/node_modules/css-tree/cjs/definition-syntax/walk.cjs
new file mode 100644
index 0000000..fdba065
--- /dev/null
+++ b/vanilla/node_modules/css-tree/cjs/definition-syntax/walk.cjs
@@ -0,0 +1,57 @@
+'use strict';
+
+const noop = function() {};
+
+function ensureFunction(value) {
+ return typeof value === 'function' ? value : noop;
+}
+
+function walk(node, options, context) {
+ function walk(node) {
+ enter.call(context, node);
+
+ switch (node.type) {
+ case 'Group':
+ node.terms.forEach(walk);
+ break;
+
+ case 'Multiplier':
+ case 'Boolean':
+ walk(node.term);
+ break;
+
+ case 'Type':
+ case 'Property':
+ case 'Keyword':
+ case 'AtKeyword':
+ case 'Function':
+ case 'String':
+ case 'Token':
+ case 'Comma':
+ break;
+
+ default:
+ throw new Error('Unknown type: ' + node.type);
+ }
+
+ leave.call(context, node);
+ }
+
+ let enter = noop;
+ let leave = noop;
+
+ if (typeof options === 'function') {
+ enter = options;
+ } else if (options) {
+ enter = ensureFunction(options.enter);
+ leave = ensureFunction(options.leave);
+ }
+
+ if (enter === noop && leave === noop) {
+ throw new Error('Neither `enter` nor `leave` walker handler is set or both aren\'t a function');
+ }
+
+ walk(node);
+}
+
+exports.walk = walk;