aboutsummaryrefslogtreecommitdiffstats
path: root/vanilla/node_modules/css-tree/cjs/lexer
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/lexer
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/lexer')
-rw-r--r--vanilla/node_modules/css-tree/cjs/lexer/Lexer.cjs517
-rw-r--r--vanilla/node_modules/css-tree/cjs/lexer/error.cjs128
-rw-r--r--vanilla/node_modules/css-tree/cjs/lexer/generic-an-plus-b.cjs235
-rw-r--r--vanilla/node_modules/css-tree/cjs/lexer/generic-const.cjs12
-rw-r--r--vanilla/node_modules/css-tree/cjs/lexer/generic-urange.cjs149
-rw-r--r--vanilla/node_modules/css-tree/cjs/lexer/generic.cjs589
-rw-r--r--vanilla/node_modules/css-tree/cjs/lexer/index.cjs7
-rw-r--r--vanilla/node_modules/css-tree/cjs/lexer/match-graph.cjs530
-rw-r--r--vanilla/node_modules/css-tree/cjs/lexer/match.cjs632
-rw-r--r--vanilla/node_modules/css-tree/cjs/lexer/prepare-tokens.cjs54
-rw-r--r--vanilla/node_modules/css-tree/cjs/lexer/search.cjs65
-rw-r--r--vanilla/node_modules/css-tree/cjs/lexer/structure.cjs173
-rw-r--r--vanilla/node_modules/css-tree/cjs/lexer/trace.cjs73
-rw-r--r--vanilla/node_modules/css-tree/cjs/lexer/units.cjs38
14 files changed, 3202 insertions, 0 deletions
diff --git a/vanilla/node_modules/css-tree/cjs/lexer/Lexer.cjs b/vanilla/node_modules/css-tree/cjs/lexer/Lexer.cjs
new file mode 100644
index 0000000..a6d1fcb
--- /dev/null
+++ b/vanilla/node_modules/css-tree/cjs/lexer/Lexer.cjs
@@ -0,0 +1,517 @@
+'use strict';
+
+const error = require('./error.cjs');
+const names = require('../utils/names.cjs');
+const genericConst = require('./generic-const.cjs');
+const generic = require('./generic.cjs');
+const units = require('./units.cjs');
+const prepareTokens = require('./prepare-tokens.cjs');
+const matchGraph = require('./match-graph.cjs');
+const match = require('./match.cjs');
+const trace = require('./trace.cjs');
+const search = require('./search.cjs');
+const structure = require('./structure.cjs');
+const parse = require('../definition-syntax/parse.cjs');
+const generate = require('../definition-syntax/generate.cjs');
+const walk = require('../definition-syntax/walk.cjs');
+
+function dumpMapSyntax(map, compact, syntaxAsAst) {
+ const result = {};
+
+ for (const name in map) {
+ if (map[name].syntax) {
+ result[name] = syntaxAsAst
+ ? map[name].syntax
+ : generate.generate(map[name].syntax, { compact });
+ }
+ }
+
+ return result;
+}
+
+function dumpAtruleMapSyntax(map, compact, syntaxAsAst) {
+ const result = {};
+
+ for (const [name, atrule] of Object.entries(map)) {
+ result[name] = {
+ prelude: atrule.prelude && (
+ syntaxAsAst
+ ? atrule.prelude.syntax
+ : generate.generate(atrule.prelude.syntax, { compact })
+ ),
+ descriptors: atrule.descriptors && dumpMapSyntax(atrule.descriptors, compact, syntaxAsAst)
+ };
+ }
+
+ return result;
+}
+
+function valueHasVar(tokens) {
+ for (let i = 0; i < tokens.length; i++) {
+ if (tokens[i].value.toLowerCase() === 'var(') {
+ return true;
+ }
+ }
+
+ return false;
+}
+
+function syntaxHasTopLevelCommaMultiplier(syntax) {
+ const singleTerm = syntax.terms[0];
+
+ return (
+ syntax.explicit === false &&
+ syntax.terms.length === 1 &&
+ singleTerm.type === 'Multiplier' &&
+ singleTerm.comma === true
+ );
+}
+
+function buildMatchResult(matched, error, iterations) {
+ return {
+ matched,
+ iterations,
+ error,
+ ...trace
+ };
+}
+
+function matchSyntax(lexer, syntax, value, useCssWideKeywords) {
+ const tokens = prepareTokens(value, lexer.syntax);
+ let result;
+
+ if (valueHasVar(tokens)) {
+ return buildMatchResult(null, new Error('Matching for a tree with var() is not supported'));
+ }
+
+ if (useCssWideKeywords) {
+ result = match.matchAsTree(tokens, lexer.cssWideKeywordsSyntax, lexer);
+ }
+
+ if (!useCssWideKeywords || !result.match) {
+ result = match.matchAsTree(tokens, syntax.match, lexer);
+ if (!result.match) {
+ return buildMatchResult(
+ null,
+ new error.SyntaxMatchError(result.reason, syntax.syntax, value, result),
+ result.iterations
+ );
+ }
+ }
+
+ return buildMatchResult(result.match, null, result.iterations);
+}
+
+class Lexer {
+ constructor(config, syntax, structure$1) {
+ this.cssWideKeywords = genericConst.cssWideKeywords;
+ this.syntax = syntax;
+ this.generic = false;
+ this.units = { ...units };
+ this.atrules = Object.create(null);
+ this.properties = Object.create(null);
+ this.types = Object.create(null);
+ this.structure = structure$1 || structure.getStructureFromConfig(config);
+
+ if (config) {
+ if (config.cssWideKeywords) {
+ this.cssWideKeywords = config.cssWideKeywords;
+ }
+
+ if (config.units) {
+ for (const group of Object.keys(units)) {
+ if (Array.isArray(config.units[group])) {
+ this.units[group] = config.units[group];
+ }
+ }
+ }
+
+ if (config.types) {
+ for (const [name, type] of Object.entries(config.types)) {
+ this.addType_(name, type);
+ }
+ }
+
+ if (config.generic) {
+ this.generic = true;
+ for (const [name, value] of Object.entries(generic.createGenericTypes(this.units))) {
+ this.addType_(name, value);
+ }
+ }
+
+ if (config.atrules) {
+ for (const [name, atrule] of Object.entries(config.atrules)) {
+ this.addAtrule_(name, atrule);
+ }
+ }
+
+ if (config.properties) {
+ for (const [name, property] of Object.entries(config.properties)) {
+ this.addProperty_(name, property);
+ }
+ }
+ }
+
+ this.cssWideKeywordsSyntax = matchGraph.buildMatchGraph(this.cssWideKeywords.join(' | '));
+ }
+
+ checkStructure(ast) {
+ function collectWarning(node, message) {
+ warns.push({ node, message });
+ }
+
+ const structure = this.structure;
+ const warns = [];
+
+ this.syntax.walk(ast, function(node) {
+ if (structure.hasOwnProperty(node.type)) {
+ structure[node.type].check(node, collectWarning);
+ } else {
+ collectWarning(node, 'Unknown node type `' + node.type + '`');
+ }
+ });
+
+ return warns.length ? warns : false;
+ }
+
+ createDescriptor(syntax, type, name, parent = null) {
+ const ref = {
+ type,
+ name
+ };
+ const descriptor = {
+ type,
+ name,
+ parent,
+ serializable: typeof syntax === 'string' || (syntax && typeof syntax.type === 'string'),
+ syntax: null,
+ match: null,
+ matchRef: null // used for properties when a syntax referenced as <'property'> in other syntax definitions
+ };
+
+ if (typeof syntax === 'function') {
+ descriptor.match = matchGraph.buildMatchGraph(syntax, ref);
+ } else {
+ if (typeof syntax === 'string') {
+ // lazy parsing on first access
+ Object.defineProperty(descriptor, 'syntax', {
+ get() {
+ Object.defineProperty(descriptor, 'syntax', {
+ value: parse.parse(syntax)
+ });
+
+ return descriptor.syntax;
+ }
+ });
+ } else {
+ descriptor.syntax = syntax;
+ }
+
+ // lazy graph build on first access
+ Object.defineProperty(descriptor, 'match', {
+ get() {
+ Object.defineProperty(descriptor, 'match', {
+ value: matchGraph.buildMatchGraph(descriptor.syntax, ref)
+ });
+
+ return descriptor.match;
+ }
+ });
+
+ if (type === 'Property') {
+ Object.defineProperty(descriptor, 'matchRef', {
+ get() {
+ const syntax = descriptor.syntax;
+ const value = syntaxHasTopLevelCommaMultiplier(syntax)
+ ? matchGraph.buildMatchGraph({
+ ...syntax,
+ terms: [syntax.terms[0].term]
+ }, ref)
+ : null;
+
+ Object.defineProperty(descriptor, 'matchRef', {
+ value
+ });
+
+ return value;
+ }
+ });
+ }
+ }
+
+ return descriptor;
+ }
+ addAtrule_(name, syntax) {
+ if (!syntax) {
+ return;
+ }
+
+ this.atrules[name] = {
+ type: 'Atrule',
+ name: name,
+ prelude: syntax.prelude ? this.createDescriptor(syntax.prelude, 'AtrulePrelude', name) : null,
+ descriptors: syntax.descriptors
+ ? Object.keys(syntax.descriptors).reduce(
+ (map, descName) => {
+ map[descName] = this.createDescriptor(syntax.descriptors[descName], 'AtruleDescriptor', descName, name);
+ return map;
+ },
+ Object.create(null)
+ )
+ : null
+ };
+ }
+ addProperty_(name, syntax) {
+ if (!syntax) {
+ return;
+ }
+
+ this.properties[name] = this.createDescriptor(syntax, 'Property', name);
+ }
+ addType_(name, syntax) {
+ if (!syntax) {
+ return;
+ }
+
+ this.types[name] = this.createDescriptor(syntax, 'Type', name);
+ }
+
+ checkAtruleName(atruleName) {
+ if (!this.getAtrule(atruleName)) {
+ return new error.SyntaxReferenceError('Unknown at-rule', '@' + atruleName);
+ }
+ }
+ checkAtrulePrelude(atruleName, prelude) {
+ const error = this.checkAtruleName(atruleName);
+
+ if (error) {
+ return error;
+ }
+
+ const atrule = this.getAtrule(atruleName);
+
+ if (!atrule.prelude && prelude) {
+ return new SyntaxError('At-rule `@' + atruleName + '` should not contain a prelude');
+ }
+
+ if (atrule.prelude && !prelude) {
+ if (!matchSyntax(this, atrule.prelude, '', false).matched) {
+ return new SyntaxError('At-rule `@' + atruleName + '` should contain a prelude');
+ }
+ }
+ }
+ checkAtruleDescriptorName(atruleName, descriptorName) {
+ const error$1 = this.checkAtruleName(atruleName);
+
+ if (error$1) {
+ return error$1;
+ }
+
+ const atrule = this.getAtrule(atruleName);
+ const descriptor = names.keyword(descriptorName);
+
+ if (!atrule.descriptors) {
+ return new SyntaxError('At-rule `@' + atruleName + '` has no known descriptors');
+ }
+
+ if (!atrule.descriptors[descriptor.name] &&
+ !atrule.descriptors[descriptor.basename]) {
+ return new error.SyntaxReferenceError('Unknown at-rule descriptor', descriptorName);
+ }
+ }
+ checkPropertyName(propertyName) {
+ if (!this.getProperty(propertyName)) {
+ return new error.SyntaxReferenceError('Unknown property', propertyName);
+ }
+ }
+
+ matchAtrulePrelude(atruleName, prelude) {
+ const error = this.checkAtrulePrelude(atruleName, prelude);
+
+ if (error) {
+ return buildMatchResult(null, error);
+ }
+
+ const atrule = this.getAtrule(atruleName);
+
+ if (!atrule.prelude) {
+ return buildMatchResult(null, null);
+ }
+
+ return matchSyntax(this, atrule.prelude, prelude || '', false);
+ }
+ matchAtruleDescriptor(atruleName, descriptorName, value) {
+ const error = this.checkAtruleDescriptorName(atruleName, descriptorName);
+
+ if (error) {
+ return buildMatchResult(null, error);
+ }
+
+ const atrule = this.getAtrule(atruleName);
+ const descriptor = names.keyword(descriptorName);
+
+ return matchSyntax(this, atrule.descriptors[descriptor.name] || atrule.descriptors[descriptor.basename], value, false);
+ }
+ matchDeclaration(node) {
+ if (node.type !== 'Declaration') {
+ return buildMatchResult(null, new Error('Not a Declaration node'));
+ }
+
+ return this.matchProperty(node.property, node.value);
+ }
+ matchProperty(propertyName, value) {
+ // don't match syntax for a custom property at the moment
+ if (names.property(propertyName).custom) {
+ return buildMatchResult(null, new Error('Lexer matching doesn\'t applicable for custom properties'));
+ }
+
+ const error = this.checkPropertyName(propertyName);
+
+ if (error) {
+ return buildMatchResult(null, error);
+ }
+
+ return matchSyntax(this, this.getProperty(propertyName), value, true);
+ }
+ matchType(typeName, value) {
+ const typeSyntax = this.getType(typeName);
+
+ if (!typeSyntax) {
+ return buildMatchResult(null, new error.SyntaxReferenceError('Unknown type', typeName));
+ }
+
+ return matchSyntax(this, typeSyntax, value, false);
+ }
+ match(syntax, value) {
+ if (typeof syntax !== 'string' && (!syntax || !syntax.type)) {
+ return buildMatchResult(null, new error.SyntaxReferenceError('Bad syntax'));
+ }
+
+ if (typeof syntax === 'string' || !syntax.match) {
+ syntax = this.createDescriptor(syntax, 'Type', 'anonymous');
+ }
+
+ return matchSyntax(this, syntax, value, false);
+ }
+
+ findValueFragments(propertyName, value, type, name) {
+ return search.matchFragments(this, value, this.matchProperty(propertyName, value), type, name);
+ }
+ findDeclarationValueFragments(declaration, type, name) {
+ return search.matchFragments(this, declaration.value, this.matchDeclaration(declaration), type, name);
+ }
+ findAllFragments(ast, type, name) {
+ const result = [];
+
+ this.syntax.walk(ast, {
+ visit: 'Declaration',
+ enter: (declaration) => {
+ result.push.apply(result, this.findDeclarationValueFragments(declaration, type, name));
+ }
+ });
+
+ return result;
+ }
+
+ getAtrule(atruleName, fallbackBasename = true) {
+ const atrule = names.keyword(atruleName);
+ const atruleEntry = atrule.vendor && fallbackBasename
+ ? this.atrules[atrule.name] || this.atrules[atrule.basename]
+ : this.atrules[atrule.name];
+
+ return atruleEntry || null;
+ }
+ getAtrulePrelude(atruleName, fallbackBasename = true) {
+ const atrule = this.getAtrule(atruleName, fallbackBasename);
+
+ return atrule && atrule.prelude || null;
+ }
+ getAtruleDescriptor(atruleName, name) {
+ return this.atrules.hasOwnProperty(atruleName) && this.atrules.declarators
+ ? this.atrules[atruleName].declarators[name] || null
+ : null;
+ }
+ getProperty(propertyName, fallbackBasename = true) {
+ const property = names.property(propertyName);
+ const propertyEntry = property.vendor && fallbackBasename
+ ? this.properties[property.name] || this.properties[property.basename]
+ : this.properties[property.name];
+
+ return propertyEntry || null;
+ }
+ getType(name) {
+ return hasOwnProperty.call(this.types, name) ? this.types[name] : null;
+ }
+
+ validate() {
+ function syntaxRef(name, isType) {
+ return isType ? `<${name}>` : `<'${name}'>`;
+ }
+
+ function validate(syntax, name, broken, descriptor) {
+ if (broken.has(name)) {
+ return broken.get(name);
+ }
+
+ broken.set(name, false);
+ if (descriptor.syntax !== null) {
+ walk.walk(descriptor.syntax, function(node) {
+ if (node.type !== 'Type' && node.type !== 'Property') {
+ return;
+ }
+
+ const map = node.type === 'Type' ? syntax.types : syntax.properties;
+ const brokenMap = node.type === 'Type' ? brokenTypes : brokenProperties;
+
+ if (!hasOwnProperty.call(map, node.name)) {
+ errors.push(`${syntaxRef(name, broken === brokenTypes)} used missed syntax definition ${syntaxRef(node.name, node.type === 'Type')}`);
+ broken.set(name, true);
+ } else if (validate(syntax, node.name, brokenMap, map[node.name])) {
+ errors.push(`${syntaxRef(name, broken === brokenTypes)} used broken syntax definition ${syntaxRef(node.name, node.type === 'Type')}`);
+ broken.set(name, true);
+ }
+ }, this);
+ }
+ }
+
+ const errors = [];
+ let brokenTypes = new Map();
+ let brokenProperties = new Map();
+
+ for (const key in this.types) {
+ validate(this, key, brokenTypes, this.types[key]);
+ }
+
+ for (const key in this.properties) {
+ validate(this, key, brokenProperties, this.properties[key]);
+ }
+
+ const brokenTypesArray = [...brokenTypes.keys()].filter(name => brokenTypes.get(name));
+ const brokenPropertiesArray = [...brokenProperties.keys()].filter(name => brokenProperties.get(name));
+
+ if (brokenTypesArray.length || brokenPropertiesArray.length) {
+ return {
+ errors,
+ types: brokenTypesArray,
+ properties: brokenPropertiesArray
+ };
+ }
+
+ return null;
+ }
+ dump(syntaxAsAst, pretty) {
+ return {
+ generic: this.generic,
+ cssWideKeywords: this.cssWideKeywords,
+ units: this.units,
+ types: dumpMapSyntax(this.types, !pretty, syntaxAsAst),
+ properties: dumpMapSyntax(this.properties, !pretty, syntaxAsAst),
+ atrules: dumpAtruleMapSyntax(this.atrules, !pretty, syntaxAsAst)
+ };
+ }
+ toString() {
+ return JSON.stringify(this.dump());
+ }
+}
+
+exports.Lexer = Lexer;
diff --git a/vanilla/node_modules/css-tree/cjs/lexer/error.cjs b/vanilla/node_modules/css-tree/cjs/lexer/error.cjs
new file mode 100644
index 0000000..8d252ee
--- /dev/null
+++ b/vanilla/node_modules/css-tree/cjs/lexer/error.cjs
@@ -0,0 +1,128 @@
+'use strict';
+
+const createCustomError = require('../utils/create-custom-error.cjs');
+const generate = require('../definition-syntax/generate.cjs');
+
+const defaultLoc = { offset: 0, line: 1, column: 1 };
+
+function locateMismatch(matchResult, node) {
+ const tokens = matchResult.tokens;
+ const longestMatch = matchResult.longestMatch;
+ const mismatchNode = longestMatch < tokens.length ? tokens[longestMatch].node || null : null;
+ const badNode = mismatchNode !== node ? mismatchNode : null;
+ let mismatchOffset = 0;
+ let mismatchLength = 0;
+ let entries = 0;
+ let css = '';
+ let start;
+ let end;
+
+ for (let i = 0; i < tokens.length; i++) {
+ const token = tokens[i].value;
+
+ if (i === longestMatch) {
+ mismatchLength = token.length;
+ mismatchOffset = css.length;
+ }
+
+ if (badNode !== null && tokens[i].node === badNode) {
+ if (i <= longestMatch) {
+ entries++;
+ } else {
+ entries = 0;
+ }
+ }
+
+ css += token;
+ }
+
+ if (longestMatch === tokens.length || entries > 1) { // last
+ start = fromLoc(badNode || node, 'end') || buildLoc(defaultLoc, css);
+ end = buildLoc(start);
+ } else {
+ start = fromLoc(badNode, 'start') ||
+ buildLoc(fromLoc(node, 'start') || defaultLoc, css.slice(0, mismatchOffset));
+ end = fromLoc(badNode, 'end') ||
+ buildLoc(start, css.substr(mismatchOffset, mismatchLength));
+ }
+
+ return {
+ css,
+ mismatchOffset,
+ mismatchLength,
+ start,
+ end
+ };
+}
+
+function fromLoc(node, point) {
+ const value = node && node.loc && node.loc[point];
+
+ if (value) {
+ return 'line' in value ? buildLoc(value) : value;
+ }
+
+ return null;
+}
+
+function buildLoc({ offset, line, column }, extra) {
+ const loc = {
+ offset,
+ line,
+ column
+ };
+
+ if (extra) {
+ const lines = extra.split(/\n|\r\n?|\f/);
+
+ loc.offset += extra.length;
+ loc.line += lines.length - 1;
+ loc.column = lines.length === 1 ? loc.column + extra.length : lines.pop().length + 1;
+ }
+
+ return loc;
+}
+
+const SyntaxReferenceError = function(type, referenceName) {
+ const error = createCustomError.createCustomError(
+ 'SyntaxReferenceError',
+ type + (referenceName ? ' `' + referenceName + '`' : '')
+ );
+
+ error.reference = referenceName;
+
+ return error;
+};
+
+const SyntaxMatchError = function(message, syntax, node, matchResult) {
+ const error = createCustomError.createCustomError('SyntaxMatchError', message);
+ const {
+ css,
+ mismatchOffset,
+ mismatchLength,
+ start,
+ end
+ } = locateMismatch(matchResult, node);
+
+ error.rawMessage = message;
+ error.syntax = syntax ? generate.generate(syntax) : '<generic>';
+ error.css = css;
+ error.mismatchOffset = mismatchOffset;
+ error.mismatchLength = mismatchLength;
+ error.message = message + '\n' +
+ ' syntax: ' + error.syntax + '\n' +
+ ' value: ' + (css || '<empty string>') + '\n' +
+ ' --------' + new Array(error.mismatchOffset + 1).join('-') + '^';
+
+ Object.assign(error, start);
+ error.loc = {
+ source: (node && node.loc && node.loc.source) || '<unknown>',
+ start,
+ end
+ };
+
+ return error;
+};
+
+exports.SyntaxMatchError = SyntaxMatchError;
+exports.SyntaxReferenceError = SyntaxReferenceError;
diff --git a/vanilla/node_modules/css-tree/cjs/lexer/generic-an-plus-b.cjs b/vanilla/node_modules/css-tree/cjs/lexer/generic-an-plus-b.cjs
new file mode 100644
index 0000000..a5dfba3
--- /dev/null
+++ b/vanilla/node_modules/css-tree/cjs/lexer/generic-an-plus-b.cjs
@@ -0,0 +1,235 @@
+'use strict';
+
+const charCodeDefinitions = require('../tokenizer/char-code-definitions.cjs');
+const types = require('../tokenizer/types.cjs');
+const utils = require('../tokenizer/utils.cjs');
+
+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 isDelim(token, code) {
+ return token !== null && token.type === types.Delim && token.value.charCodeAt(0) === code;
+}
+
+function skipSC(token, offset, getNextToken) {
+ while (token !== null && (token.type === types.WhiteSpace || token.type === types.Comment)) {
+ token = getNextToken(++offset);
+ }
+
+ return offset;
+}
+
+function checkInteger(token, valueOffset, disallowSign, offset) {
+ if (!token) {
+ return 0;
+ }
+
+ const code = token.value.charCodeAt(valueOffset);
+
+ if (code === PLUSSIGN || code === HYPHENMINUS) {
+ if (disallowSign) {
+ // Number sign is not allowed
+ return 0;
+ }
+ valueOffset++;
+ }
+
+ for (; valueOffset < token.value.length; valueOffset++) {
+ if (!charCodeDefinitions.isDigit(token.value.charCodeAt(valueOffset))) {
+ // Integer is expected
+ return 0;
+ }
+ }
+
+ return offset + 1;
+}
+
+// ... <signed-integer>
+// ... ['+' | '-'] <signless-integer>
+function consumeB(token, offset_, getNextToken) {
+ let sign = false;
+ let offset = skipSC(token, offset_, getNextToken);
+
+ token = getNextToken(offset);
+
+ if (token === null) {
+ return offset_;
+ }
+
+ if (token.type !== types.Number) {
+ if (isDelim(token, PLUSSIGN) || isDelim(token, HYPHENMINUS)) {
+ sign = true;
+ offset = skipSC(getNextToken(++offset), offset, getNextToken);
+ token = getNextToken(offset);
+
+ if (token === null || token.type !== types.Number) {
+ return 0;
+ }
+ } else {
+ return offset_;
+ }
+ }
+
+ if (!sign) {
+ const code = token.value.charCodeAt(0);
+ if (code !== PLUSSIGN && code !== HYPHENMINUS) {
+ // Number sign is expected
+ return 0;
+ }
+ }
+
+ return checkInteger(token, sign ? 0 : 1, sign, offset);
+}
+
+// An+B microsyntax https://www.w3.org/TR/css-syntax-3/#anb
+function anPlusB(token, getNextToken) {
+ /* eslint-disable brace-style*/
+ let offset = 0;
+
+ if (!token) {
+ return 0;
+ }
+
+ // <integer>
+ if (token.type === types.Number) {
+ return checkInteger(token, 0, ALLOW_SIGN, offset); // b
+ }
+
+ // -n
+ // -n <signed-integer>
+ // -n ['+' | '-'] <signless-integer>
+ // -n- <signless-integer>
+ // <dashndashdigit-ident>
+ else if (token.type === types.Ident && token.value.charCodeAt(0) === HYPHENMINUS) {
+ // expect 1st char is N
+ if (!utils.cmpChar(token.value, 1, N)) {
+ return 0;
+ }
+
+ switch (token.value.length) {
+ // -n
+ // -n <signed-integer>
+ // -n ['+' | '-'] <signless-integer>
+ case 2:
+ return consumeB(getNextToken(++offset), offset, getNextToken);
+
+ // -n- <signless-integer>
+ case 3:
+ if (token.value.charCodeAt(2) !== HYPHENMINUS) {
+ return 0;
+ }
+
+ offset = skipSC(getNextToken(++offset), offset, getNextToken);
+ token = getNextToken(offset);
+
+ return checkInteger(token, 0, DISALLOW_SIGN, offset);
+
+ // <dashndashdigit-ident>
+ default:
+ if (token.value.charCodeAt(2) !== HYPHENMINUS) {
+ return 0;
+ }
+
+ return checkInteger(token, 3, DISALLOW_SIGN, offset);
+ }
+ }
+
+ // '+'? n
+ // '+'? n <signed-integer>
+ // '+'? n ['+' | '-'] <signless-integer>
+ // '+'? n- <signless-integer>
+ // '+'? <ndashdigit-ident>
+ else if (token.type === types.Ident || (isDelim(token, PLUSSIGN) && getNextToken(offset + 1).type === types.Ident)) {
+ // just ignore a plus
+ if (token.type !== types.Ident) {
+ token = getNextToken(++offset);
+ }
+
+ if (token === null || !utils.cmpChar(token.value, 0, N)) {
+ return 0;
+ }
+
+ switch (token.value.length) {
+ // '+'? n
+ // '+'? n <signed-integer>
+ // '+'? n ['+' | '-'] <signless-integer>
+ case 1:
+ return consumeB(getNextToken(++offset), offset, getNextToken);
+
+ // '+'? n- <signless-integer>
+ case 2:
+ if (token.value.charCodeAt(1) !== HYPHENMINUS) {
+ return 0;
+ }
+
+ offset = skipSC(getNextToken(++offset), offset, getNextToken);
+ token = getNextToken(offset);
+
+ return checkInteger(token, 0, DISALLOW_SIGN, offset);
+
+ // '+'? <ndashdigit-ident>
+ default:
+ if (token.value.charCodeAt(1) !== HYPHENMINUS) {
+ return 0;
+ }
+
+ return checkInteger(token, 2, DISALLOW_SIGN, offset);
+ }
+ }
+
+ // <ndashdigit-dimension>
+ // <ndash-dimension> <signless-integer>
+ // <n-dimension>
+ // <n-dimension> <signed-integer>
+ // <n-dimension> ['+' | '-'] <signless-integer>
+ else if (token.type === types.Dimension) {
+ let code = token.value.charCodeAt(0);
+ let sign = code === PLUSSIGN || code === HYPHENMINUS ? 1 : 0;
+ let i = sign;
+
+ for (; i < token.value.length; i++) {
+ if (!charCodeDefinitions.isDigit(token.value.charCodeAt(i))) {
+ break;
+ }
+ }
+
+ if (i === sign) {
+ // Integer is expected
+ return 0;
+ }
+
+ if (!utils.cmpChar(token.value, i, N)) {
+ return 0;
+ }
+
+ // <n-dimension>
+ // <n-dimension> <signed-integer>
+ // <n-dimension> ['+' | '-'] <signless-integer>
+ if (i + 1 === token.value.length) {
+ return consumeB(getNextToken(++offset), offset, getNextToken);
+ } else {
+ if (token.value.charCodeAt(i + 1) !== HYPHENMINUS) {
+ return 0;
+ }
+
+ // <ndash-dimension> <signless-integer>
+ if (i + 2 === token.value.length) {
+ offset = skipSC(getNextToken(++offset), offset, getNextToken);
+ token = getNextToken(offset);
+
+ return checkInteger(token, 0, DISALLOW_SIGN, offset);
+ }
+ // <ndashdigit-dimension>
+ else {
+ return checkInteger(token, i + 2, DISALLOW_SIGN, offset);
+ }
+ }
+ }
+
+ return 0;
+}
+
+module.exports = anPlusB;
diff --git a/vanilla/node_modules/css-tree/cjs/lexer/generic-const.cjs b/vanilla/node_modules/css-tree/cjs/lexer/generic-const.cjs
new file mode 100644
index 0000000..9b9f615
--- /dev/null
+++ b/vanilla/node_modules/css-tree/cjs/lexer/generic-const.cjs
@@ -0,0 +1,12 @@
+'use strict';
+
+// https://drafts.csswg.org/css-cascade-5/
+const cssWideKeywords = [
+ 'initial',
+ 'inherit',
+ 'unset',
+ 'revert',
+ 'revert-layer'
+];
+
+exports.cssWideKeywords = cssWideKeywords;
diff --git a/vanilla/node_modules/css-tree/cjs/lexer/generic-urange.cjs b/vanilla/node_modules/css-tree/cjs/lexer/generic-urange.cjs
new file mode 100644
index 0000000..ce167bb
--- /dev/null
+++ b/vanilla/node_modules/css-tree/cjs/lexer/generic-urange.cjs
@@ -0,0 +1,149 @@
+'use strict';
+
+const charCodeDefinitions = require('../tokenizer/char-code-definitions.cjs');
+const types = require('../tokenizer/types.cjs');
+const utils = require('../tokenizer/utils.cjs');
+
+const PLUSSIGN = 0x002B; // U+002B PLUS SIGN (+)
+const HYPHENMINUS = 0x002D; // U+002D HYPHEN-MINUS (-)
+const QUESTIONMARK = 0x003F; // U+003F QUESTION MARK (?)
+const U = 0x0075; // U+0075 LATIN SMALL LETTER U (u)
+
+function isDelim(token, code) {
+ return token !== null && token.type === types.Delim && token.value.charCodeAt(0) === code;
+}
+
+function startsWith(token, code) {
+ return token.value.charCodeAt(0) === code;
+}
+
+function hexSequence(token, offset, allowDash) {
+ let hexlen = 0;
+
+ for (let pos = offset; pos < token.value.length; pos++) {
+ const code = token.value.charCodeAt(pos);
+
+ if (code === HYPHENMINUS && allowDash && hexlen !== 0) {
+ hexSequence(token, offset + hexlen + 1, false);
+ return 6; // dissallow following question marks
+ }
+
+ if (!charCodeDefinitions.isHexDigit(code)) {
+ return 0; // not a hex digit
+ }
+
+ if (++hexlen > 6) {
+ return 0; // too many hex digits
+ } }
+
+ return hexlen;
+}
+
+function withQuestionMarkSequence(consumed, length, getNextToken) {
+ if (!consumed) {
+ return 0; // nothing consumed
+ }
+
+ while (isDelim(getNextToken(length), QUESTIONMARK)) {
+ if (++consumed > 6) {
+ return 0; // too many question marks
+ }
+
+ length++;
+ }
+
+ return length;
+}
+
+// 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 urange(token, getNextToken) {
+ let length = 0;
+
+ // should start with `u` or `U`
+ if (token === null || token.type !== types.Ident || !utils.cmpChar(token.value, 0, U)) {
+ return 0;
+ }
+
+ token = getNextToken(++length);
+ if (token === null) {
+ return 0;
+ }
+
+ // u '+' <ident-token> '?'*
+ // u '+' '?'+
+ if (isDelim(token, PLUSSIGN)) {
+ token = getNextToken(++length);
+ if (token === null) {
+ return 0;
+ }
+
+ if (token.type === types.Ident) {
+ // u '+' <ident-token> '?'*
+ return withQuestionMarkSequence(hexSequence(token, 0, true), ++length, getNextToken);
+ }
+
+ if (isDelim(token, QUESTIONMARK)) {
+ // u '+' '?'+
+ return withQuestionMarkSequence(1, ++length, getNextToken);
+ }
+
+ // Hex digit or question mark is expected
+ return 0;
+ }
+
+ // u <number-token> '?'*
+ // u <number-token> <dimension-token>
+ // u <number-token> <number-token>
+ if (token.type === types.Number) {
+ const consumedHexLength = hexSequence(token, 1, true);
+ if (consumedHexLength === 0) {
+ return 0;
+ }
+
+ token = getNextToken(++length);
+ if (token === null) {
+ // u <number-token> <eof>
+ return length;
+ }
+
+ if (token.type === types.Dimension || token.type === types.Number) {
+ // u <number-token> <dimension-token>
+ // u <number-token> <number-token>
+ if (!startsWith(token, HYPHENMINUS) || !hexSequence(token, 1, false)) {
+ return 0;
+ }
+
+ return length + 1;
+ }
+
+ // u <number-token> '?'*
+ return withQuestionMarkSequence(consumedHexLength, length, getNextToken);
+ }
+
+ // u <dimension-token> '?'*
+ if (token.type === types.Dimension) {
+ return withQuestionMarkSequence(hexSequence(token, 1, true), ++length, getNextToken);
+ }
+
+ return 0;
+}
+
+module.exports = urange;
diff --git a/vanilla/node_modules/css-tree/cjs/lexer/generic.cjs b/vanilla/node_modules/css-tree/cjs/lexer/generic.cjs
new file mode 100644
index 0000000..8489911
--- /dev/null
+++ b/vanilla/node_modules/css-tree/cjs/lexer/generic.cjs
@@ -0,0 +1,589 @@
+'use strict';
+
+const genericConst = require('./generic-const.cjs');
+const genericAnPlusB = require('./generic-an-plus-b.cjs');
+const genericUrange = require('./generic-urange.cjs');
+const charCodeDefinitions = require('../tokenizer/char-code-definitions.cjs');
+const types = require('../tokenizer/types.cjs');
+const utils = require('../tokenizer/utils.cjs');
+
+const calcFunctionNames = ['calc(', '-moz-calc(', '-webkit-calc('];
+const balancePair = new Map([
+ [types.Function, types.RightParenthesis],
+ [types.LeftParenthesis, types.RightParenthesis],
+ [types.LeftSquareBracket, types.RightSquareBracket],
+ [types.LeftCurlyBracket, types.RightCurlyBracket]
+]);
+
+// safe char code getter
+function charCodeAt(str, index) {
+ return index < str.length ? str.charCodeAt(index) : 0;
+}
+
+function eqStr(actual, expected) {
+ return utils.cmpStr(actual, 0, actual.length, expected);
+}
+
+function eqStrAny(actual, expected) {
+ for (let i = 0; i < expected.length; i++) {
+ if (eqStr(actual, expected[i])) {
+ return true;
+ }
+ }
+
+ return false;
+}
+
+// IE postfix hack, i.e. 123\0 or 123px\9
+function isPostfixIeHack(str, offset) {
+ if (offset !== str.length - 2) {
+ return false;
+ }
+
+ return (
+ charCodeAt(str, offset) === 0x005C && // U+005C REVERSE SOLIDUS (\)
+ charCodeDefinitions.isDigit(charCodeAt(str, offset + 1))
+ );
+}
+
+function outOfRange(opts, value, numEnd) {
+ if (opts && opts.type === 'Range') {
+ const num = Number(
+ numEnd !== undefined && numEnd !== value.length
+ ? value.substr(0, numEnd)
+ : value
+ );
+
+ if (isNaN(num)) {
+ return true;
+ }
+
+ // FIXME: when opts.min is a string it's a dimension, skip a range validation
+ // for now since it requires a type covertation which is not implmented yet
+ if (opts.min !== null && num < opts.min && typeof opts.min !== 'string') {
+ return true;
+ }
+
+ // FIXME: when opts.max is a string it's a dimension, skip a range validation
+ // for now since it requires a type covertation which is not implmented yet
+ if (opts.max !== null && num > opts.max && typeof opts.max !== 'string') {
+ return true;
+ }
+ }
+
+ return false;
+}
+
+function consumeFunction(token, getNextToken) {
+ let balanceCloseType = 0;
+ let balanceStash = [];
+ let length = 0;
+
+ // balanced token consuming
+ scan:
+ do {
+ switch (token.type) {
+ case types.RightCurlyBracket:
+ case types.RightParenthesis:
+ case types.RightSquareBracket:
+ if (token.type !== balanceCloseType) {
+ break scan;
+ }
+
+ balanceCloseType = balanceStash.pop();
+
+ if (balanceStash.length === 0) {
+ length++;
+ break scan;
+ }
+
+ break;
+
+ case types.Function:
+ case types.LeftParenthesis:
+ case types.LeftSquareBracket:
+ case types.LeftCurlyBracket:
+ balanceStash.push(balanceCloseType);
+ balanceCloseType = balancePair.get(token.type);
+ break;
+ }
+
+ length++;
+ } while (token = getNextToken(length));
+
+ return length;
+}
+
+// TODO: implement
+// can be used wherever <length>, <frequency>, <angle>, <time>, <percentage>, <number>, or <integer> values are allowed
+// https://drafts.csswg.org/css-values/#calc-notation
+function calc(next) {
+ return function(token, getNextToken, opts) {
+ if (token === null) {
+ return 0;
+ }
+
+ if (token.type === types.Function && eqStrAny(token.value, calcFunctionNames)) {
+ return consumeFunction(token, getNextToken);
+ }
+
+ return next(token, getNextToken, opts);
+ };
+}
+
+function tokenType(expectedTokenType) {
+ return function(token) {
+ if (token === null || token.type !== expectedTokenType) {
+ return 0;
+ }
+
+ return 1;
+ };
+}
+
+// =========================
+// Complex types
+//
+
+// https://drafts.csswg.org/css-values-4/#custom-idents
+// 4.2. Author-defined Identifiers: the <custom-ident> type
+// Some properties accept arbitrary author-defined identifiers as a component value.
+// This generic data type is denoted by <custom-ident>, and represents any valid CSS identifier
+// that would not be misinterpreted as a pre-defined keyword in that property’s value definition.
+//
+// See also: https://developer.mozilla.org/en-US/docs/Web/CSS/custom-ident
+function customIdent(token) {
+ if (token === null || token.type !== types.Ident) {
+ return 0;
+ }
+
+ const name = token.value.toLowerCase();
+
+ // The CSS-wide keywords are not valid <custom-ident>s
+ if (eqStrAny(name, genericConst.cssWideKeywords)) {
+ return 0;
+ }
+
+ // The default keyword is reserved and is also not a valid <custom-ident>
+ if (eqStr(name, 'default')) {
+ return 0;
+ }
+
+ // TODO: ignore property specific keywords (as described https://developer.mozilla.org/en-US/docs/Web/CSS/custom-ident)
+ // Specifications using <custom-ident> must specify clearly what other keywords
+ // are excluded from <custom-ident>, if any—for example by saying that any pre-defined keywords
+ // in that property’s value definition are excluded. Excluded keywords are excluded
+ // in all ASCII case permutations.
+
+ return 1;
+}
+
+// https://drafts.csswg.org/css-values-4/#dashed-idents
+// The <dashed-ident> production is a <custom-ident>, with all the case-sensitivity that implies,
+// with the additional restriction that it must start with two dashes (U+002D HYPHEN-MINUS).
+function dashedIdent(token) {
+ if (token === null || token.type !== types.Ident) {
+ return 0;
+ }
+
+ // ... must start with two dashes (U+002D HYPHEN-MINUS)
+ if (charCodeAt(token.value, 0) !== 0x002D || charCodeAt(token.value, 1) !== 0x002D) {
+ return 0;
+ }
+
+ return 1;
+}
+
+// https://drafts.csswg.org/css-variables/#typedef-custom-property-name
+// A custom property is any property whose name starts with two dashes (U+002D HYPHEN-MINUS), like --foo.
+// The <custom-property-name> production corresponds to this: it’s defined as any <dashed-ident>
+// (a valid identifier that starts with two dashes), except -- itself, which is reserved for future use by CSS.
+function customPropertyName(token) {
+ // ... it’s defined as any <dashed-ident>
+ if (!dashedIdent(token)) {
+ return 0;
+ }
+
+ // ... except -- itself, which is reserved for future use by CSS
+ if (token.value === '--') {
+ return 0;
+ }
+
+ return 1;
+}
+
+// https://drafts.csswg.org/css-color-4/#hex-notation
+// The syntax of a <hex-color> is a <hash-token> token whose value consists of 3, 4, 6, or 8 hexadecimal digits.
+// In other words, a hex color is written as a hash character, "#", followed by some number of digits 0-9 or
+// letters a-f (the case of the letters doesn’t matter - #00ff00 is identical to #00FF00).
+function hexColor(token) {
+ if (token === null || token.type !== types.Hash) {
+ return 0;
+ }
+
+ const length = token.value.length;
+
+ // valid values (length): #rgb (4), #rgba (5), #rrggbb (7), #rrggbbaa (9)
+ if (length !== 4 && length !== 5 && length !== 7 && length !== 9) {
+ return 0;
+ }
+
+ for (let i = 1; i < length; i++) {
+ if (!charCodeDefinitions.isHexDigit(charCodeAt(token.value, i))) {
+ return 0;
+ }
+ }
+
+ return 1;
+}
+
+function idSelector(token) {
+ if (token === null || token.type !== types.Hash) {
+ return 0;
+ }
+
+ if (!charCodeDefinitions.isIdentifierStart(charCodeAt(token.value, 1), charCodeAt(token.value, 2), charCodeAt(token.value, 3))) {
+ return 0;
+ }
+
+ return 1;
+}
+
+// https://drafts.csswg.org/css-syntax/#any-value
+// It represents the entirety of what a valid declaration can have as its value.
+function declarationValue(token, getNextToken) {
+ if (!token) {
+ return 0;
+ }
+
+ let balanceCloseType = 0;
+ let balanceStash = [];
+ let length = 0;
+
+ // The <declaration-value> production matches any sequence of one or more tokens,
+ // so long as the sequence does not contain ...
+ scan:
+ do {
+ switch (token.type) {
+ // ... <bad-string-token>, <bad-url-token>,
+ case types.BadString:
+ case types.BadUrl:
+ break scan;
+
+ // ... unmatched <)-token>, <]-token>, or <}-token>,
+ case types.RightCurlyBracket:
+ case types.RightParenthesis:
+ case types.RightSquareBracket:
+ if (token.type !== balanceCloseType) {
+ break scan;
+ }
+
+ balanceCloseType = balanceStash.pop();
+ break;
+
+ // ... or top-level <semicolon-token> tokens
+ case types.Semicolon:
+ if (balanceCloseType === 0) {
+ break scan;
+ }
+
+ break;
+
+ // ... or <delim-token> tokens with a value of "!"
+ case types.Delim:
+ if (balanceCloseType === 0 && token.value === '!') {
+ break scan;
+ }
+
+ break;
+
+ case types.Function:
+ case types.LeftParenthesis:
+ case types.LeftSquareBracket:
+ case types.LeftCurlyBracket:
+ balanceStash.push(balanceCloseType);
+ balanceCloseType = balancePair.get(token.type);
+ break;
+ }
+
+ length++;
+ } while (token = getNextToken(length));
+
+ return length;
+}
+
+// https://drafts.csswg.org/css-syntax/#any-value
+// The <any-value> production is identical to <declaration-value>, but also
+// allows top-level <semicolon-token> tokens and <delim-token> tokens
+// with a value of "!". It represents the entirety of what valid CSS can be in any context.
+function anyValue(token, getNextToken) {
+ if (!token) {
+ return 0;
+ }
+
+ let balanceCloseType = 0;
+ let balanceStash = [];
+ let length = 0;
+
+ // The <any-value> production matches any sequence of one or more tokens,
+ // so long as the sequence ...
+ scan:
+ do {
+ switch (token.type) {
+ // ... does not contain <bad-string-token>, <bad-url-token>,
+ case types.BadString:
+ case types.BadUrl:
+ break scan;
+
+ // ... unmatched <)-token>, <]-token>, or <}-token>,
+ case types.RightCurlyBracket:
+ case types.RightParenthesis:
+ case types.RightSquareBracket:
+ if (token.type !== balanceCloseType) {
+ break scan;
+ }
+
+ balanceCloseType = balanceStash.pop();
+ break;
+
+ case types.Function:
+ case types.LeftParenthesis:
+ case types.LeftSquareBracket:
+ case types.LeftCurlyBracket:
+ balanceStash.push(balanceCloseType);
+ balanceCloseType = balancePair.get(token.type);
+ break;
+ }
+
+ length++;
+ } while (token = getNextToken(length));
+
+ return length;
+}
+
+// =========================
+// Dimensions
+//
+
+function dimension(type) {
+ if (type) {
+ type = new Set(type);
+ }
+
+ return function(token, getNextToken, opts) {
+ if (token === null || token.type !== types.Dimension) {
+ return 0;
+ }
+
+ const numberEnd = utils.consumeNumber(token.value, 0);
+
+ // check unit
+ if (type !== null) {
+ // check for IE postfix hack, i.e. 123px\0 or 123px\9
+ const reverseSolidusOffset = token.value.indexOf('\\', numberEnd);
+ const unit = reverseSolidusOffset === -1 || !isPostfixIeHack(token.value, reverseSolidusOffset)
+ ? token.value.substr(numberEnd)
+ : token.value.substring(numberEnd, reverseSolidusOffset);
+
+ if (type.has(unit.toLowerCase()) === false) {
+ return 0;
+ }
+ }
+
+ // check range if specified
+ if (outOfRange(opts, token.value, numberEnd)) {
+ return 0;
+ }
+
+ return 1;
+ };
+}
+
+// =========================
+// Percentage
+//
+
+// §5.5. Percentages: the <percentage> type
+// https://drafts.csswg.org/css-values-4/#percentages
+function percentage(token, getNextToken, opts) {
+ // ... corresponds to the <percentage-token> production
+ if (token === null || token.type !== types.Percentage) {
+ return 0;
+ }
+
+ // check range if specified
+ if (outOfRange(opts, token.value, token.value.length - 1)) {
+ return 0;
+ }
+
+ return 1;
+}
+
+// =========================
+// Numeric
+//
+
+// https://drafts.csswg.org/css-values-4/#numbers
+// The value <zero> represents a literal number with the value 0. Expressions that merely
+// evaluate to a <number> with the value 0 (for example, calc(0)) do not match <zero>;
+// only literal <number-token>s do.
+function zero(next) {
+ if (typeof next !== 'function') {
+ next = function() {
+ return 0;
+ };
+ }
+
+ return function(token, getNextToken, opts) {
+ if (token !== null && token.type === types.Number) {
+ if (Number(token.value) === 0) {
+ return 1;
+ }
+ }
+
+ return next(token, getNextToken, opts);
+ };
+}
+
+// § 5.3. Real Numbers: the <number> type
+// https://drafts.csswg.org/css-values-4/#numbers
+// Number values are denoted by <number>, and represent real numbers, possibly with a fractional component.
+// ... It corresponds to the <number-token> production
+function number(token, getNextToken, opts) {
+ if (token === null) {
+ return 0;
+ }
+
+ const numberEnd = utils.consumeNumber(token.value, 0);
+ const isNumber = numberEnd === token.value.length;
+ if (!isNumber && !isPostfixIeHack(token.value, numberEnd)) {
+ return 0;
+ }
+
+ // check range if specified
+ if (outOfRange(opts, token.value, numberEnd)) {
+ return 0;
+ }
+
+ return 1;
+}
+
+// §5.2. Integers: the <integer> type
+// https://drafts.csswg.org/css-values-4/#integers
+function integer(token, getNextToken, opts) {
+ // ... corresponds to a subset of the <number-token> production
+ if (token === null || token.type !== types.Number) {
+ return 0;
+ }
+
+ // The first digit of an integer may be immediately preceded by `-` or `+` to indicate the integer’s sign.
+ let i = charCodeAt(token.value, 0) === 0x002B || // U+002B PLUS SIGN (+)
+ charCodeAt(token.value, 0) === 0x002D ? 1 : 0; // U+002D HYPHEN-MINUS (-)
+
+ // When written literally, an integer is one or more decimal digits 0 through 9 ...
+ for (; i < token.value.length; i++) {
+ if (!charCodeDefinitions.isDigit(charCodeAt(token.value, i))) {
+ return 0;
+ }
+ }
+
+ // check range if specified
+ if (outOfRange(opts, token.value, i)) {
+ return 0;
+ }
+
+ return 1;
+}
+
+// token types
+const tokenTypes = {
+ 'ident-token': tokenType(types.Ident),
+ 'function-token': tokenType(types.Function),
+ 'at-keyword-token': tokenType(types.AtKeyword),
+ 'hash-token': tokenType(types.Hash),
+ 'string-token': tokenType(types.String),
+ 'bad-string-token': tokenType(types.BadString),
+ 'url-token': tokenType(types.Url),
+ 'bad-url-token': tokenType(types.BadUrl),
+ 'delim-token': tokenType(types.Delim),
+ 'number-token': tokenType(types.Number),
+ 'percentage-token': tokenType(types.Percentage),
+ 'dimension-token': tokenType(types.Dimension),
+ 'whitespace-token': tokenType(types.WhiteSpace),
+ 'CDO-token': tokenType(types.CDO),
+ 'CDC-token': tokenType(types.CDC),
+ 'colon-token': tokenType(types.Colon),
+ 'semicolon-token': tokenType(types.Semicolon),
+ 'comma-token': tokenType(types.Comma),
+ '[-token': tokenType(types.LeftSquareBracket),
+ ']-token': tokenType(types.RightSquareBracket),
+ '(-token': tokenType(types.LeftParenthesis),
+ ')-token': tokenType(types.RightParenthesis),
+ '{-token': tokenType(types.LeftCurlyBracket),
+ '}-token': tokenType(types.RightCurlyBracket)
+};
+
+// token production types
+const productionTypes = {
+ // token type aliases
+ 'string': tokenType(types.String),
+ 'ident': tokenType(types.Ident),
+
+ // percentage
+ 'percentage': calc(percentage),
+
+ // numeric
+ 'zero': zero(),
+ 'number': calc(number),
+ 'integer': calc(integer),
+
+ // complex types
+ 'custom-ident': customIdent,
+ 'dashed-ident': dashedIdent,
+ 'custom-property-name': customPropertyName,
+ 'hex-color': hexColor,
+ 'id-selector': idSelector, // element( <id-selector> )
+ 'an-plus-b': genericAnPlusB,
+ 'urange': genericUrange,
+ 'declaration-value': declarationValue,
+ 'any-value': anyValue
+};
+
+// dimensions types depend on units set
+function createDemensionTypes(units) {
+ const {
+ angle,
+ decibel,
+ frequency,
+ flex,
+ length,
+ resolution,
+ semitones,
+ time
+ } = units || {};
+
+ return {
+ 'dimension': calc(dimension(null)),
+ 'angle': calc(dimension(angle)),
+ 'decibel': calc(dimension(decibel)),
+ 'frequency': calc(dimension(frequency)),
+ 'flex': calc(dimension(flex)),
+ 'length': calc(zero(dimension(length))),
+ 'resolution': calc(dimension(resolution)),
+ 'semitones': calc(dimension(semitones)),
+ 'time': calc(dimension(time))
+ };
+}
+
+function createGenericTypes(units) {
+ return {
+ ...tokenTypes,
+ ...productionTypes,
+ ...createDemensionTypes(units)
+ };
+}
+
+exports.createDemensionTypes = createDemensionTypes;
+exports.createGenericTypes = createGenericTypes;
+exports.productionTypes = productionTypes;
+exports.tokenTypes = tokenTypes;
diff --git a/vanilla/node_modules/css-tree/cjs/lexer/index.cjs b/vanilla/node_modules/css-tree/cjs/lexer/index.cjs
new file mode 100644
index 0000000..2e3633e
--- /dev/null
+++ b/vanilla/node_modules/css-tree/cjs/lexer/index.cjs
@@ -0,0 +1,7 @@
+'use strict';
+
+const Lexer = require('./Lexer.cjs');
+
+
+
+exports.Lexer = Lexer.Lexer;
diff --git a/vanilla/node_modules/css-tree/cjs/lexer/match-graph.cjs b/vanilla/node_modules/css-tree/cjs/lexer/match-graph.cjs
new file mode 100644
index 0000000..9f9675e
--- /dev/null
+++ b/vanilla/node_modules/css-tree/cjs/lexer/match-graph.cjs
@@ -0,0 +1,530 @@
+'use strict';
+
+const parse = require('../definition-syntax/parse.cjs');
+
+const MATCH = { type: 'Match' };
+const MISMATCH = { type: 'Mismatch' };
+const DISALLOW_EMPTY = { type: 'DisallowEmpty' };
+
+const LEFTPARENTHESIS = 40; // (
+const RIGHTPARENTHESIS = 41; // )
+
+function createCondition(match, thenBranch, elseBranch) {
+ // reduce node count
+ if (thenBranch === MATCH && elseBranch === MISMATCH) {
+ return match;
+ }
+
+ if (match === MATCH && thenBranch === MATCH && elseBranch === MATCH) {
+ return match;
+ }
+
+ if (match.type === 'If' && match.else === MISMATCH && thenBranch === MATCH) {
+ thenBranch = match.then;
+ match = match.match;
+ }
+
+ return {
+ type: 'If',
+ match,
+ then: thenBranch,
+ else: elseBranch
+ };
+}
+
+function isFunctionType(name) {
+ return (
+ name.length > 2 &&
+ name.charCodeAt(name.length - 2) === LEFTPARENTHESIS &&
+ name.charCodeAt(name.length - 1) === RIGHTPARENTHESIS
+ );
+}
+
+function isEnumCapatible(term) {
+ return (
+ term.type === 'Keyword' ||
+ term.type === 'AtKeyword' ||
+ term.type === 'Function' ||
+ term.type === 'Type' && isFunctionType(term.name)
+ );
+}
+
+function groupNode(terms, combinator = ' ', explicit = false) {
+ return {
+ type: 'Group',
+ terms,
+ combinator,
+ disallowEmpty: false,
+ explicit
+ };
+}
+
+function replaceTypeInGraph(node, replacements, visited = new Set()) {
+ if (!visited.has(node)) {
+ visited.add(node);
+
+ switch (node.type) {
+ case 'If':
+ node.match = replaceTypeInGraph(node.match, replacements, visited);
+ node.then = replaceTypeInGraph(node.then, replacements, visited);
+ node.else = replaceTypeInGraph(node.else, replacements, visited);
+ break;
+
+ case 'Type':
+ return replacements[node.name] || node;
+ }
+ }
+
+ return node;
+}
+
+function buildGroupMatchGraph(combinator, terms, atLeastOneTermMatched) {
+ switch (combinator) {
+ case ' ': {
+ // Juxtaposing components means that all of them must occur, in the given order.
+ //
+ // a b c
+ // =
+ // match a
+ // then match b
+ // then match c
+ // then MATCH
+ // else MISMATCH
+ // else MISMATCH
+ // else MISMATCH
+ let result = MATCH;
+
+ for (let i = terms.length - 1; i >= 0; i--) {
+ const term = terms[i];
+
+ result = createCondition(
+ term,
+ result,
+ MISMATCH
+ );
+ }
+ return result;
+ }
+
+ case '|': {
+ // A bar (|) separates two or more alternatives: exactly one of them must occur.
+ //
+ // a | b | c
+ // =
+ // match a
+ // then MATCH
+ // else match b
+ // then MATCH
+ // else match c
+ // then MATCH
+ // else MISMATCH
+
+ let result = MISMATCH;
+ let map = null;
+
+ for (let i = terms.length - 1; i >= 0; i--) {
+ let term = terms[i];
+
+ // reduce sequence of keywords into a Enum
+ if (isEnumCapatible(term)) {
+ if (map === null && i > 0 && isEnumCapatible(terms[i - 1])) {
+ map = Object.create(null);
+ result = createCondition(
+ {
+ type: 'Enum',
+ map
+ },
+ MATCH,
+ result
+ );
+ }
+
+ if (map !== null) {
+ const key = (isFunctionType(term.name) ? term.name.slice(0, -1) : term.name).toLowerCase();
+ if (key in map === false) {
+ map[key] = term;
+ continue;
+ }
+ }
+ }
+
+ map = null;
+
+ // create a new conditonal node
+ result = createCondition(
+ term,
+ MATCH,
+ result
+ );
+ }
+ return result;
+ }
+
+ case '&&': {
+ // A double ampersand (&&) separates two or more components,
+ // all of which must occur, in any order.
+
+ // Use MatchOnce for groups with a large number of terms,
+ // since &&-groups produces at least N!-node trees
+ if (terms.length > 5) {
+ return {
+ type: 'MatchOnce',
+ terms,
+ all: true
+ };
+ }
+
+ // Use a combination tree for groups with small number of terms
+ //
+ // a && b && c
+ // =
+ // match a
+ // then [b && c]
+ // else match b
+ // then [a && c]
+ // else match c
+ // then [a && b]
+ // else MISMATCH
+ //
+ // a && b
+ // =
+ // match a
+ // then match b
+ // then MATCH
+ // else MISMATCH
+ // else match b
+ // then match a
+ // then MATCH
+ // else MISMATCH
+ // else MISMATCH
+ let result = MISMATCH;
+
+ for (let i = terms.length - 1; i >= 0; i--) {
+ const term = terms[i];
+ let thenClause;
+
+ if (terms.length > 1) {
+ thenClause = buildGroupMatchGraph(
+ combinator,
+ terms.filter(function(newGroupTerm) {
+ return newGroupTerm !== term;
+ }),
+ false
+ );
+ } else {
+ thenClause = MATCH;
+ }
+
+ result = createCondition(
+ term,
+ thenClause,
+ result
+ );
+ }
+ return result;
+ }
+
+ case '||': {
+ // A double bar (||) separates two or more options:
+ // one or more of them must occur, in any order.
+
+ // Use MatchOnce for groups with a large number of terms,
+ // since ||-groups produces at least N!-node trees
+ if (terms.length > 5) {
+ return {
+ type: 'MatchOnce',
+ terms,
+ all: false
+ };
+ }
+
+ // Use a combination tree for groups with small number of terms
+ //
+ // a || b || c
+ // =
+ // match a
+ // then [b || c]
+ // else match b
+ // then [a || c]
+ // else match c
+ // then [a || b]
+ // else MISMATCH
+ //
+ // a || b
+ // =
+ // match a
+ // then match b
+ // then MATCH
+ // else MATCH
+ // else match b
+ // then match a
+ // then MATCH
+ // else MATCH
+ // else MISMATCH
+ let result = atLeastOneTermMatched ? MATCH : MISMATCH;
+
+ for (let i = terms.length - 1; i >= 0; i--) {
+ const term = terms[i];
+ let thenClause;
+
+ if (terms.length > 1) {
+ thenClause = buildGroupMatchGraph(
+ combinator,
+ terms.filter(function(newGroupTerm) {
+ return newGroupTerm !== term;
+ }),
+ true
+ );
+ } else {
+ thenClause = MATCH;
+ }
+
+ result = createCondition(
+ term,
+ thenClause,
+ result
+ );
+ }
+ return result;
+ }
+ }
+}
+
+function buildMultiplierMatchGraph(node) {
+ let result = MATCH;
+ let matchTerm = buildMatchGraphInternal(node.term);
+
+ if (node.max === 0) {
+ // disable repeating of empty match to prevent infinite loop
+ matchTerm = createCondition(
+ matchTerm,
+ DISALLOW_EMPTY,
+ MISMATCH
+ );
+
+ // an occurrence count is not limited, make a cycle;
+ // to collect more terms on each following matching mismatch
+ result = createCondition(
+ matchTerm,
+ null, // will be a loop
+ MISMATCH
+ );
+
+ result.then = createCondition(
+ MATCH,
+ MATCH,
+ result // make a loop
+ );
+
+ if (node.comma) {
+ result.then.else = createCondition(
+ { type: 'Comma', syntax: node },
+ result,
+ MISMATCH
+ );
+ }
+ } else {
+ // create a match node chain for [min .. max] interval with optional matches
+ for (let i = node.min || 1; i <= node.max; i++) {
+ if (node.comma && result !== MATCH) {
+ result = createCondition(
+ { type: 'Comma', syntax: node },
+ result,
+ MISMATCH
+ );
+ }
+
+ result = createCondition(
+ matchTerm,
+ createCondition(
+ MATCH,
+ MATCH,
+ result
+ ),
+ MISMATCH
+ );
+ }
+ }
+
+ if (node.min === 0) {
+ // allow zero match
+ result = createCondition(
+ MATCH,
+ MATCH,
+ result
+ );
+ } else {
+ // create a match node chain to collect [0 ... min - 1] required matches
+ for (let i = 0; i < node.min - 1; i++) {
+ if (node.comma && result !== MATCH) {
+ result = createCondition(
+ { type: 'Comma', syntax: node },
+ result,
+ MISMATCH
+ );
+ }
+
+ result = createCondition(
+ matchTerm,
+ result,
+ MISMATCH
+ );
+ }
+ }
+
+ return result;
+}
+
+function buildMatchGraphInternal(node) {
+ if (typeof node === 'function') {
+ return {
+ type: 'Generic',
+ fn: node
+ };
+ }
+
+ switch (node.type) {
+ case 'Group': {
+ let result = buildGroupMatchGraph(
+ node.combinator,
+ node.terms.map(buildMatchGraphInternal),
+ false
+ );
+
+ if (node.disallowEmpty) {
+ result = createCondition(
+ result,
+ DISALLOW_EMPTY,
+ MISMATCH
+ );
+ }
+
+ return result;
+ }
+
+ case 'Multiplier':
+ return buildMultiplierMatchGraph(node);
+
+ // https://drafts.csswg.org/css-values-5/#boolean
+ case 'Boolean': {
+ const term = buildMatchGraphInternal(node.term);
+ // <boolean-expr[ <test> ]> = not <boolean-expr-group> | <boolean-expr-group> [ [ and <boolean-expr-group> ]* | [ or <boolean-expr-group> ]* ]
+ const matchNode = buildMatchGraphInternal(groupNode([
+ groupNode([
+ { type: 'Keyword', name: 'not' },
+ { type: 'Type', name: '!boolean-group' }
+ ]),
+ groupNode([
+ { type: 'Type', name: '!boolean-group' },
+ groupNode([
+ { type: 'Multiplier', comma: false, min: 0, max: 0, term: groupNode([
+ { type: 'Keyword', name: 'and' },
+ { type: 'Type', name: '!boolean-group' }
+ ]) },
+ { type: 'Multiplier', comma: false, min: 0, max: 0, term: groupNode([
+ { type: 'Keyword', name: 'or' },
+ { type: 'Type', name: '!boolean-group' }
+ ]) }
+ ], '|')
+ ])
+ ], '|'));
+ // <boolean-expr-group> = <test> | ( <boolean-expr[ <test> ]> ) | <general-enclosed>
+ const booleanGroup = buildMatchGraphInternal(
+ groupNode([
+ { type: 'Type', name: '!term' },
+ groupNode([
+ { type: 'Token', value: '(' },
+ { type: 'Type', name: '!self' },
+ { type: 'Token', value: ')' }
+ ]),
+ { type: 'Type', name: 'general-enclosed' }
+ ], '|')
+ );
+
+ replaceTypeInGraph(booleanGroup, { '!term': term, '!self': matchNode });
+ replaceTypeInGraph(matchNode, { '!boolean-group': booleanGroup });
+
+ return matchNode;
+ }
+
+ case 'Type':
+ case 'Property':
+ return {
+ type: node.type,
+ name: node.name,
+ syntax: node
+ };
+
+ case 'Keyword':
+ return {
+ type: node.type,
+ name: node.name.toLowerCase(),
+ syntax: node
+ };
+
+ case 'AtKeyword':
+ return {
+ type: node.type,
+ name: '@' + node.name.toLowerCase(),
+ syntax: node
+ };
+
+ case 'Function':
+ return {
+ type: node.type,
+ name: node.name.toLowerCase() + '(',
+ syntax: node
+ };
+
+ case 'String':
+ // convert a one char length String to a Token
+ if (node.value.length === 3) {
+ return {
+ type: 'Token',
+ value: node.value.charAt(1),
+ syntax: node
+ };
+ }
+
+ // otherwise use it as is
+ return {
+ type: node.type,
+ value: node.value.substr(1, node.value.length - 2).replace(/\\'/g, '\''),
+ syntax: node
+ };
+
+ case 'Token':
+ return {
+ type: node.type,
+ value: node.value,
+ syntax: node
+ };
+
+ case 'Comma':
+ return {
+ type: node.type,
+ syntax: node
+ };
+
+ default:
+ throw new Error('Unknown node type:', node.type);
+ }
+}
+
+function buildMatchGraph(syntaxTree, ref) {
+ if (typeof syntaxTree === 'string') {
+ syntaxTree = parse.parse(syntaxTree);
+ }
+
+ return {
+ type: 'MatchGraph',
+ match: buildMatchGraphInternal(syntaxTree),
+ syntax: ref || null,
+ source: syntaxTree
+ };
+}
+
+exports.DISALLOW_EMPTY = DISALLOW_EMPTY;
+exports.MATCH = MATCH;
+exports.MISMATCH = MISMATCH;
+exports.buildMatchGraph = buildMatchGraph;
diff --git a/vanilla/node_modules/css-tree/cjs/lexer/match.cjs b/vanilla/node_modules/css-tree/cjs/lexer/match.cjs
new file mode 100644
index 0000000..86f44ae
--- /dev/null
+++ b/vanilla/node_modules/css-tree/cjs/lexer/match.cjs
@@ -0,0 +1,632 @@
+'use strict';
+
+const matchGraph = require('./match-graph.cjs');
+const types = require('../tokenizer/types.cjs');
+
+const { hasOwnProperty } = Object.prototype;
+const STUB = 0;
+const TOKEN = 1;
+const OPEN_SYNTAX = 2;
+const CLOSE_SYNTAX = 3;
+
+const EXIT_REASON_MATCH = 'Match';
+const EXIT_REASON_MISMATCH = 'Mismatch';
+const EXIT_REASON_ITERATION_LIMIT = 'Maximum iteration number exceeded (please fill an issue on https://github.com/csstree/csstree/issues)';
+
+const ITERATION_LIMIT = 15000;
+
+function reverseList(list) {
+ let prev = null;
+ let next = null;
+ let item = list;
+
+ while (item !== null) {
+ next = item.prev;
+ item.prev = prev;
+ prev = item;
+ item = next;
+ }
+
+ return prev;
+}
+
+function areStringsEqualCaseInsensitive(testStr, referenceStr) {
+ if (testStr.length !== referenceStr.length) {
+ return false;
+ }
+
+ for (let i = 0; i < testStr.length; i++) {
+ const referenceCode = referenceStr.charCodeAt(i);
+ let testCode = testStr.charCodeAt(i);
+
+ // testCode.toLowerCase() for U+0041 LATIN CAPITAL LETTER A (A) .. U+005A LATIN CAPITAL LETTER Z (Z).
+ if (testCode >= 0x0041 && testCode <= 0x005A) {
+ testCode = testCode | 32;
+ }
+
+ if (testCode !== referenceCode) {
+ return false;
+ }
+ }
+
+ return true;
+}
+
+function isContextEdgeDelim(token) {
+ if (token.type !== types.Delim) {
+ return false;
+ }
+
+ // Fix matching for unicode-range: U+30??, U+FF00-FF9F
+ // Probably we need to check out previous match instead
+ return token.value !== '?';
+}
+
+function isCommaContextStart(token) {
+ if (token === null) {
+ return true;
+ }
+
+ return (
+ token.type === types.Comma ||
+ token.type === types.Function ||
+ token.type === types.LeftParenthesis ||
+ token.type === types.LeftSquareBracket ||
+ token.type === types.LeftCurlyBracket ||
+ isContextEdgeDelim(token)
+ );
+}
+
+function isCommaContextEnd(token) {
+ if (token === null) {
+ return true;
+ }
+
+ return (
+ token.type === types.RightParenthesis ||
+ token.type === types.RightSquareBracket ||
+ token.type === types.RightCurlyBracket ||
+ (token.type === types.Delim && token.value === '/')
+ );
+}
+
+function internalMatch(tokens, state, syntaxes) {
+ function moveToNextToken() {
+ do {
+ tokenIndex++;
+ token = tokenIndex < tokens.length ? tokens[tokenIndex] : null;
+ } while (token !== null && (token.type === types.WhiteSpace || token.type === types.Comment));
+ }
+
+ function getNextToken(offset) {
+ const nextIndex = tokenIndex + offset;
+
+ return nextIndex < tokens.length ? tokens[nextIndex] : null;
+ }
+
+ function stateSnapshotFromSyntax(nextState, prev) {
+ return {
+ nextState,
+ matchStack,
+ syntaxStack,
+ thenStack,
+ tokenIndex,
+ prev
+ };
+ }
+
+ function pushThenStack(nextState) {
+ thenStack = {
+ nextState,
+ matchStack,
+ syntaxStack,
+ prev: thenStack
+ };
+ }
+
+ function pushElseStack(nextState) {
+ elseStack = stateSnapshotFromSyntax(nextState, elseStack);
+ }
+
+ function addTokenToMatch() {
+ matchStack = {
+ type: TOKEN,
+ syntax: state.syntax,
+ token,
+ prev: matchStack
+ };
+
+ moveToNextToken();
+ syntaxStash = null;
+
+ if (tokenIndex > longestMatch) {
+ longestMatch = tokenIndex;
+ }
+ }
+
+ function openSyntax() {
+ syntaxStack = {
+ syntax: state.syntax,
+ opts: state.syntax.opts || (syntaxStack !== null && syntaxStack.opts) || null,
+ prev: syntaxStack
+ };
+
+ matchStack = {
+ type: OPEN_SYNTAX,
+ syntax: state.syntax,
+ token: matchStack.token,
+ prev: matchStack
+ };
+ }
+
+ function closeSyntax() {
+ if (matchStack.type === OPEN_SYNTAX) {
+ matchStack = matchStack.prev;
+ } else {
+ matchStack = {
+ type: CLOSE_SYNTAX,
+ syntax: syntaxStack.syntax,
+ token: matchStack.token,
+ prev: matchStack
+ };
+ }
+
+ syntaxStack = syntaxStack.prev;
+ }
+
+ let syntaxStack = null;
+ let thenStack = null;
+ let elseStack = null;
+
+ // null – stashing allowed, nothing stashed
+ // false – stashing disabled, nothing stashed
+ // anithing else – fail stashable syntaxes, some syntax stashed
+ let syntaxStash = null;
+
+ let iterationCount = 0; // count iterations and prevent infinite loop
+ let exitReason = null;
+
+ let token = null;
+ let tokenIndex = -1;
+ let longestMatch = 0;
+ let matchStack = {
+ type: STUB,
+ syntax: null,
+ token: null,
+ prev: null
+ };
+
+ moveToNextToken();
+
+ while (exitReason === null && ++iterationCount < ITERATION_LIMIT) {
+ // function mapList(list, fn) {
+ // const result = [];
+ // while (list) {
+ // result.unshift(fn(list));
+ // list = list.prev;
+ // }
+ // return result;
+ // }
+ // console.log('--\n',
+ // '#' + iterationCount,
+ // require('util').inspect({
+ // match: mapList(matchStack, x => x.type === TOKEN ? x.token && x.token.value : x.syntax ? ({ [OPEN_SYNTAX]: '<', [CLOSE_SYNTAX]: '</' }[x.type] || x.type) + '!' + x.syntax.name : null),
+ // token: token && token.value,
+ // tokenIndex,
+ // syntax: syntax.type + (syntax.id ? ' #' + syntax.id : '')
+ // }, { depth: null })
+ // );
+ switch (state.type) {
+ case 'Match':
+ if (thenStack === null) {
+ // turn to MISMATCH when some tokens left unmatched
+ if (token !== null) {
+ // doesn't mismatch if just one token left and it's an IE hack
+ if (tokenIndex !== tokens.length - 1 || (token.value !== '\\0' && token.value !== '\\9')) {
+ state = matchGraph.MISMATCH;
+ break;
+ }
+ }
+
+ // break the main loop, return a result - MATCH
+ exitReason = EXIT_REASON_MATCH;
+ break;
+ }
+
+ // go to next syntax (`then` branch)
+ state = thenStack.nextState;
+
+ // check match is not empty
+ if (state === matchGraph.DISALLOW_EMPTY) {
+ if (thenStack.matchStack === matchStack) {
+ state = matchGraph.MISMATCH;
+ break;
+ } else {
+ state = matchGraph.MATCH;
+ }
+ }
+
+ // close syntax if needed
+ while (thenStack.syntaxStack !== syntaxStack) {
+ closeSyntax();
+ }
+
+ // pop stack
+ thenStack = thenStack.prev;
+ break;
+
+ case 'Mismatch':
+ // when some syntax is stashed
+ if (syntaxStash !== null && syntaxStash !== false) {
+ // there is no else branches or a branch reduce match stack
+ if (elseStack === null || tokenIndex > elseStack.tokenIndex) {
+ // restore state from the stash
+ elseStack = syntaxStash;
+ syntaxStash = false; // disable stashing
+ }
+ } else if (elseStack === null) {
+ // no else branches -> break the main loop
+ // return a result - MISMATCH
+ exitReason = EXIT_REASON_MISMATCH;
+ break;
+ }
+
+ // go to next syntax (`else` branch)
+ state = elseStack.nextState;
+
+ // restore all the rest stack states
+ thenStack = elseStack.thenStack;
+ syntaxStack = elseStack.syntaxStack;
+ matchStack = elseStack.matchStack;
+ tokenIndex = elseStack.tokenIndex;
+ token = tokenIndex < tokens.length ? tokens[tokenIndex] : null;
+
+ // pop stack
+ elseStack = elseStack.prev;
+ break;
+
+ case 'MatchGraph':
+ state = state.match;
+ break;
+
+ case 'If':
+ // IMPORTANT: else stack push must go first,
+ // since it stores the state of thenStack before changes
+ if (state.else !== matchGraph.MISMATCH) {
+ pushElseStack(state.else);
+ }
+
+ if (state.then !== matchGraph.MATCH) {
+ pushThenStack(state.then);
+ }
+
+ state = state.match;
+ break;
+
+ case 'MatchOnce':
+ state = {
+ type: 'MatchOnceBuffer',
+ syntax: state,
+ index: 0,
+ mask: 0
+ };
+ break;
+
+ case 'MatchOnceBuffer': {
+ const terms = state.syntax.terms;
+
+ if (state.index === terms.length) {
+ // no matches at all or it's required all terms to be matched
+ if (state.mask === 0 || state.syntax.all) {
+ state = matchGraph.MISMATCH;
+ break;
+ }
+
+ // a partial match is ok
+ state = matchGraph.MATCH;
+ break;
+ }
+
+ // all terms are matched
+ if (state.mask === (1 << terms.length) - 1) {
+ state = matchGraph.MATCH;
+ break;
+ }
+
+ for (; state.index < terms.length; state.index++) {
+ const matchFlag = 1 << state.index;
+
+ if ((state.mask & matchFlag) === 0) {
+ // IMPORTANT: else stack push must go first,
+ // since it stores the state of thenStack before changes
+ pushElseStack(state);
+ pushThenStack({
+ type: 'AddMatchOnce',
+ syntax: state.syntax,
+ mask: state.mask | matchFlag
+ });
+
+ // match
+ state = terms[state.index++];
+ break;
+ }
+ }
+ break;
+ }
+
+ case 'AddMatchOnce':
+ state = {
+ type: 'MatchOnceBuffer',
+ syntax: state.syntax,
+ index: 0,
+ mask: state.mask
+ };
+ break;
+
+ case 'Enum':
+ if (token !== null) {
+ let name = token.value.toLowerCase();
+
+ // drop \0 and \9 hack from keyword name
+ if (name.indexOf('\\') !== -1) {
+ name = name.replace(/\\[09].*$/, '');
+ }
+
+ if (hasOwnProperty.call(state.map, name)) {
+ state = state.map[name];
+ break;
+ }
+ }
+
+ state = matchGraph.MISMATCH;
+ break;
+
+ case 'Generic': {
+ const opts = syntaxStack !== null ? syntaxStack.opts : null;
+ const lastTokenIndex = tokenIndex + Math.floor(state.fn(token, getNextToken, opts));
+
+ if (!isNaN(lastTokenIndex) && lastTokenIndex > tokenIndex) {
+ while (tokenIndex < lastTokenIndex) {
+ addTokenToMatch();
+ }
+
+ state = matchGraph.MATCH;
+ } else {
+ state = matchGraph.MISMATCH;
+ }
+
+ break;
+ }
+
+ case 'Type':
+ case 'Property': {
+ const syntaxDict = state.type === 'Type' ? 'types' : 'properties';
+ const dictSyntax = hasOwnProperty.call(syntaxes, syntaxDict) ? syntaxes[syntaxDict][state.name] : null;
+
+ if (!dictSyntax || !dictSyntax.match) {
+ throw new Error(
+ 'Bad syntax reference: ' +
+ (state.type === 'Type'
+ ? '<' + state.name + '>'
+ : '<\'' + state.name + '\'>')
+ );
+ }
+
+ // stash a syntax for types with low priority
+ if (syntaxStash !== false && token !== null && state.type === 'Type') {
+ const lowPriorityMatching =
+ // https://drafts.csswg.org/css-values-4/#custom-idents
+ // When parsing positionally-ambiguous keywords in a property value, a <custom-ident> production
+ // can only claim the keyword if no other unfulfilled production can claim it.
+ (state.name === 'custom-ident' && token.type === types.Ident) ||
+
+ // https://drafts.csswg.org/css-values-4/#lengths
+ // ... if a `0` could be parsed as either a <number> or a <length> in a property (such as line-height),
+ // it must parse as a <number>
+ (state.name === 'length' && token.value === '0');
+
+ if (lowPriorityMatching) {
+ if (syntaxStash === null) {
+ syntaxStash = stateSnapshotFromSyntax(state, elseStack);
+ }
+
+ state = matchGraph.MISMATCH;
+ break;
+ }
+ }
+
+ openSyntax();
+ state = dictSyntax.matchRef || dictSyntax.match;
+ break;
+ }
+
+ case 'Keyword': {
+ const name = state.name;
+
+ if (token !== null) {
+ let keywordName = token.value;
+
+ // drop \0 and \9 hack from keyword name
+ if (keywordName.indexOf('\\') !== -1) {
+ keywordName = keywordName.replace(/\\[09].*$/, '');
+ }
+
+ if (areStringsEqualCaseInsensitive(keywordName, name)) {
+ addTokenToMatch();
+ state = matchGraph.MATCH;
+ break;
+ }
+ }
+
+ state = matchGraph.MISMATCH;
+ break;
+ }
+
+ case 'AtKeyword':
+ case 'Function':
+ if (token !== null && areStringsEqualCaseInsensitive(token.value, state.name)) {
+ addTokenToMatch();
+ state = matchGraph.MATCH;
+ break;
+ }
+
+ state = matchGraph.MISMATCH;
+ break;
+
+ case 'Token':
+ if (token !== null && token.value === state.value) {
+ addTokenToMatch();
+ state = matchGraph.MATCH;
+ break;
+ }
+
+ state = matchGraph.MISMATCH;
+ break;
+
+ case 'Comma':
+ if (token !== null && token.type === types.Comma) {
+ if (isCommaContextStart(matchStack.token)) {
+ state = matchGraph.MISMATCH;
+ } else {
+ addTokenToMatch();
+ state = isCommaContextEnd(token) ? matchGraph.MISMATCH : matchGraph.MATCH;
+ }
+ } else {
+ state = isCommaContextStart(matchStack.token) || isCommaContextEnd(token) ? matchGraph.MATCH : matchGraph.MISMATCH;
+ }
+
+ break;
+
+ case 'String':
+ let string = '';
+ let lastTokenIndex = tokenIndex;
+
+ for (; lastTokenIndex < tokens.length && string.length < state.value.length; lastTokenIndex++) {
+ string += tokens[lastTokenIndex].value;
+ }
+
+ if (areStringsEqualCaseInsensitive(string, state.value)) {
+ while (tokenIndex < lastTokenIndex) {
+ addTokenToMatch();
+ }
+
+ state = matchGraph.MATCH;
+ } else {
+ state = matchGraph.MISMATCH;
+ }
+
+ break;
+
+ default:
+ throw new Error('Unknown node type: ' + state.type);
+ }
+ }
+
+ switch (exitReason) {
+ case null:
+ console.warn('[csstree-match] BREAK after ' + ITERATION_LIMIT + ' iterations');
+ exitReason = EXIT_REASON_ITERATION_LIMIT;
+ matchStack = null;
+ break;
+
+ case EXIT_REASON_MATCH:
+ while (syntaxStack !== null) {
+ closeSyntax();
+ }
+ break;
+
+ default:
+ matchStack = null;
+ }
+
+ return {
+ tokens,
+ reason: exitReason,
+ iterations: iterationCount,
+ match: matchStack,
+ longestMatch
+ };
+}
+
+function matchAsList(tokens, matchGraph, syntaxes) {
+ const matchResult = internalMatch(tokens, matchGraph, syntaxes || {});
+
+ if (matchResult.match !== null) {
+ let item = reverseList(matchResult.match).prev;
+
+ matchResult.match = [];
+
+ while (item !== null) {
+ switch (item.type) {
+ case OPEN_SYNTAX:
+ case CLOSE_SYNTAX:
+ matchResult.match.push({
+ type: item.type,
+ syntax: item.syntax
+ });
+ break;
+
+ default:
+ matchResult.match.push({
+ token: item.token.value,
+ node: item.token.node
+ });
+ break;
+ }
+
+ item = item.prev;
+ }
+ }
+
+ return matchResult;
+}
+
+function matchAsTree(tokens, matchGraph, syntaxes) {
+ const matchResult = internalMatch(tokens, matchGraph, syntaxes || {});
+
+ if (matchResult.match === null) {
+ return matchResult;
+ }
+
+ let item = matchResult.match;
+ let host = matchResult.match = {
+ syntax: matchGraph.syntax || null,
+ match: []
+ };
+ const hostStack = [host];
+
+ // revert a list and start with 2nd item since 1st is a stub item
+ item = reverseList(item).prev;
+
+ // build a tree
+ while (item !== null) {
+ switch (item.type) {
+ case OPEN_SYNTAX:
+ host.match.push(host = {
+ syntax: item.syntax,
+ match: []
+ });
+ hostStack.push(host);
+ break;
+
+ case CLOSE_SYNTAX:
+ hostStack.pop();
+ host = hostStack[hostStack.length - 1];
+ break;
+
+ default:
+ host.match.push({
+ syntax: item.syntax || null,
+ token: item.token.value,
+ node: item.token.node
+ });
+ }
+
+ item = item.prev;
+ }
+
+ return matchResult;
+}
+
+exports.matchAsList = matchAsList;
+exports.matchAsTree = matchAsTree;
diff --git a/vanilla/node_modules/css-tree/cjs/lexer/prepare-tokens.cjs b/vanilla/node_modules/css-tree/cjs/lexer/prepare-tokens.cjs
new file mode 100644
index 0000000..24647a5
--- /dev/null
+++ b/vanilla/node_modules/css-tree/cjs/lexer/prepare-tokens.cjs
@@ -0,0 +1,54 @@
+'use strict';
+
+const index = require('../tokenizer/index.cjs');
+
+const astToTokens = {
+ decorator(handlers) {
+ const tokens = [];
+ let curNode = null;
+
+ return {
+ ...handlers,
+ node(node) {
+ const tmp = curNode;
+ curNode = node;
+ handlers.node.call(this, node);
+ curNode = tmp;
+ },
+ emit(value, type, auto) {
+ tokens.push({
+ type,
+ value,
+ node: auto ? null : curNode
+ });
+ },
+ result() {
+ return tokens;
+ }
+ };
+ }
+};
+
+function stringToTokens(str) {
+ const tokens = [];
+
+ index.tokenize(str, (type, start, end) =>
+ tokens.push({
+ type,
+ value: str.slice(start, end),
+ node: null
+ })
+ );
+
+ return tokens;
+}
+
+function prepareTokens(value, syntax) {
+ if (typeof value === 'string') {
+ return stringToTokens(value);
+ }
+
+ return syntax.generate(value, astToTokens);
+}
+
+module.exports = prepareTokens;
diff --git a/vanilla/node_modules/css-tree/cjs/lexer/search.cjs b/vanilla/node_modules/css-tree/cjs/lexer/search.cjs
new file mode 100644
index 0000000..2b1e12c
--- /dev/null
+++ b/vanilla/node_modules/css-tree/cjs/lexer/search.cjs
@@ -0,0 +1,65 @@
+'use strict';
+
+const List = require('../utils/List.cjs');
+
+function getFirstMatchNode(matchNode) {
+ if ('node' in matchNode) {
+ return matchNode.node;
+ }
+
+ return getFirstMatchNode(matchNode.match[0]);
+}
+
+function getLastMatchNode(matchNode) {
+ if ('node' in matchNode) {
+ return matchNode.node;
+ }
+
+ return getLastMatchNode(matchNode.match[matchNode.match.length - 1]);
+}
+
+function matchFragments(lexer, ast, match, type, name) {
+ function findFragments(matchNode) {
+ if (matchNode.syntax !== null &&
+ matchNode.syntax.type === type &&
+ matchNode.syntax.name === name) {
+ const start = getFirstMatchNode(matchNode);
+ const end = getLastMatchNode(matchNode);
+
+ lexer.syntax.walk(ast, function(node, item, list) {
+ if (node === start) {
+ const nodes = new List.List();
+
+ do {
+ nodes.appendData(item.data);
+
+ if (item.data === end) {
+ break;
+ }
+
+ item = item.next;
+ } while (item !== null);
+
+ fragments.push({
+ parent: list,
+ nodes
+ });
+ }
+ });
+ }
+
+ if (Array.isArray(matchNode.match)) {
+ matchNode.match.forEach(findFragments);
+ }
+ }
+
+ const fragments = [];
+
+ if (match.matched !== null) {
+ findFragments(match.matched);
+ }
+
+ return fragments;
+}
+
+exports.matchFragments = matchFragments;
diff --git a/vanilla/node_modules/css-tree/cjs/lexer/structure.cjs b/vanilla/node_modules/css-tree/cjs/lexer/structure.cjs
new file mode 100644
index 0000000..473b209
--- /dev/null
+++ b/vanilla/node_modules/css-tree/cjs/lexer/structure.cjs
@@ -0,0 +1,173 @@
+'use strict';
+
+const List = require('../utils/List.cjs');
+
+const { hasOwnProperty } = Object.prototype;
+
+function isValidNumber(value) {
+ // Number.isInteger(value) && value >= 0
+ return (
+ typeof value === 'number' &&
+ isFinite(value) &&
+ Math.floor(value) === value &&
+ value >= 0
+ );
+}
+
+function isValidLocation(loc) {
+ return (
+ Boolean(loc) &&
+ isValidNumber(loc.offset) &&
+ isValidNumber(loc.line) &&
+ isValidNumber(loc.column)
+ );
+}
+
+function createNodeStructureChecker(type, fields) {
+ return function checkNode(node, warn) {
+ if (!node || node.constructor !== Object) {
+ return warn(node, 'Type of node should be an Object');
+ }
+
+ for (let key in node) {
+ let valid = true;
+
+ if (hasOwnProperty.call(node, key) === false) {
+ continue;
+ }
+
+ if (key === 'type') {
+ if (node.type !== type) {
+ warn(node, 'Wrong node type `' + node.type + '`, expected `' + type + '`');
+ }
+ } else if (key === 'loc') {
+ if (node.loc === null) {
+ continue;
+ } else if (node.loc && node.loc.constructor === Object) {
+ if (typeof node.loc.source !== 'string') {
+ key += '.source';
+ } else if (!isValidLocation(node.loc.start)) {
+ key += '.start';
+ } else if (!isValidLocation(node.loc.end)) {
+ key += '.end';
+ } else {
+ continue;
+ }
+ }
+
+ valid = false;
+ } else if (fields.hasOwnProperty(key)) {
+ valid = false;
+
+ for (let i = 0; !valid && i < fields[key].length; i++) {
+ const fieldType = fields[key][i];
+
+ switch (fieldType) {
+ case String:
+ valid = typeof node[key] === 'string';
+ break;
+
+ case Boolean:
+ valid = typeof node[key] === 'boolean';
+ break;
+
+ case null:
+ valid = node[key] === null;
+ break;
+
+ default:
+ if (typeof fieldType === 'string') {
+ valid = node[key] && node[key].type === fieldType;
+ } else if (Array.isArray(fieldType)) {
+ valid = node[key] instanceof List.List;
+ }
+ }
+ }
+ } else {
+ warn(node, 'Unknown field `' + key + '` for ' + type + ' node type');
+ }
+
+ if (!valid) {
+ warn(node, 'Bad value for `' + type + '.' + key + '`');
+ }
+ }
+
+ for (const key in fields) {
+ if (hasOwnProperty.call(fields, key) &&
+ hasOwnProperty.call(node, key) === false) {
+ warn(node, 'Field `' + type + '.' + key + '` is missed');
+ }
+ }
+ };
+}
+
+function genTypesList(fieldTypes, path) {
+ const docsTypes = [];
+
+ for (let i = 0; i < fieldTypes.length; i++) {
+ const fieldType = fieldTypes[i];
+ if (fieldType === String || fieldType === Boolean) {
+ docsTypes.push(fieldType.name.toLowerCase());
+ } else if (fieldType === null) {
+ docsTypes.push('null');
+ } else if (typeof fieldType === 'string') {
+ docsTypes.push(fieldType);
+ } else if (Array.isArray(fieldType)) {
+ docsTypes.push('List<' + (genTypesList(fieldType, path) || 'any') + '>'); // TODO: use type enum
+ } else {
+ throw new Error('Wrong value `' + fieldType + '` in `' + path + '` structure definition');
+ }
+ }
+
+ return docsTypes.join(' | ');
+}
+
+function processStructure(name, nodeType) {
+ const structure = nodeType.structure;
+ const fields = {
+ type: String,
+ loc: true
+ };
+ const docs = {
+ type: '"' + name + '"'
+ };
+
+ for (const key in structure) {
+ if (hasOwnProperty.call(structure, key) === false) {
+ continue;
+ }
+
+ const fieldTypes = fields[key] = Array.isArray(structure[key])
+ ? structure[key].slice()
+ : [structure[key]];
+
+ docs[key] = genTypesList(fieldTypes, name + '.' + key);
+ }
+
+ return {
+ docs,
+ check: createNodeStructureChecker(name, fields)
+ };
+}
+
+function getStructureFromConfig(config) {
+ const structure = {};
+
+ if (config.node) {
+ for (const name in config.node) {
+ if (hasOwnProperty.call(config.node, name)) {
+ const nodeType = config.node[name];
+
+ if (nodeType.structure) {
+ structure[name] = processStructure(name, nodeType);
+ } else {
+ throw new Error('Missed `structure` field in `' + name + '` node type definition');
+ }
+ }
+ }
+ }
+
+ return structure;
+}
+
+exports.getStructureFromConfig = getStructureFromConfig;
diff --git a/vanilla/node_modules/css-tree/cjs/lexer/trace.cjs b/vanilla/node_modules/css-tree/cjs/lexer/trace.cjs
new file mode 100644
index 0000000..13753f2
--- /dev/null
+++ b/vanilla/node_modules/css-tree/cjs/lexer/trace.cjs
@@ -0,0 +1,73 @@
+'use strict';
+
+function getTrace(node) {
+ function shouldPutToTrace(syntax) {
+ if (syntax === null) {
+ return false;
+ }
+
+ return (
+ syntax.type === 'Type' ||
+ syntax.type === 'Property' ||
+ syntax.type === 'Keyword'
+ );
+ }
+
+ function hasMatch(matchNode) {
+ if (Array.isArray(matchNode.match)) {
+ // use for-loop for better perfomance
+ for (let i = 0; i < matchNode.match.length; i++) {
+ if (hasMatch(matchNode.match[i])) {
+ if (shouldPutToTrace(matchNode.syntax)) {
+ result.unshift(matchNode.syntax);
+ }
+
+ return true;
+ }
+ }
+ } else if (matchNode.node === node) {
+ result = shouldPutToTrace(matchNode.syntax)
+ ? [matchNode.syntax]
+ : [];
+
+ return true;
+ }
+
+ return false;
+ }
+
+ let result = null;
+
+ if (this.matched !== null) {
+ hasMatch(this.matched);
+ }
+
+ return result;
+}
+
+function isType(node, type) {
+ return testNode(this, node, match => match.type === 'Type' && match.name === type);
+}
+
+function isProperty(node, property) {
+ return testNode(this, node, match => match.type === 'Property' && match.name === property);
+}
+
+function isKeyword(node) {
+ return testNode(this, node, match => match.type === 'Keyword');
+}
+
+function testNode(match, node, fn) {
+ const trace = getTrace.call(match, node);
+
+ if (trace === null) {
+ return false;
+ }
+
+ return trace.some(fn);
+}
+
+exports.getTrace = getTrace;
+exports.isKeyword = isKeyword;
+exports.isProperty = isProperty;
+exports.isType = isType;
diff --git a/vanilla/node_modules/css-tree/cjs/lexer/units.cjs b/vanilla/node_modules/css-tree/cjs/lexer/units.cjs
new file mode 100644
index 0000000..13f4e97
--- /dev/null
+++ b/vanilla/node_modules/css-tree/cjs/lexer/units.cjs
@@ -0,0 +1,38 @@
+'use strict';
+
+const length = [
+ // absolute length units https://www.w3.org/TR/css-values-3/#lengths
+ 'cm', 'mm', 'q', 'in', 'pt', 'pc', 'px',
+ // font-relative length units https://drafts.csswg.org/css-values-4/#font-relative-lengths
+ 'em', 'rem',
+ 'ex', 'rex',
+ 'cap', 'rcap',
+ 'ch', 'rch',
+ 'ic', 'ric',
+ 'lh', 'rlh',
+ // viewport-percentage lengths https://drafts.csswg.org/css-values-4/#viewport-relative-lengths
+ 'vw', 'svw', 'lvw', 'dvw',
+ 'vh', 'svh', 'lvh', 'dvh',
+ 'vi', 'svi', 'lvi', 'dvi',
+ 'vb', 'svb', 'lvb', 'dvb',
+ 'vmin', 'svmin', 'lvmin', 'dvmin',
+ 'vmax', 'svmax', 'lvmax', 'dvmax',
+ // container relative lengths https://drafts.csswg.org/css-contain-3/#container-lengths
+ 'cqw', 'cqh', 'cqi', 'cqb', 'cqmin', 'cqmax'
+];
+const angle = ['deg', 'grad', 'rad', 'turn']; // https://www.w3.org/TR/css-values-3/#angles
+const time = ['s', 'ms']; // https://www.w3.org/TR/css-values-3/#time
+const frequency = ['hz', 'khz']; // https://www.w3.org/TR/css-values-3/#frequency
+const resolution = ['dpi', 'dpcm', 'dppx', 'x']; // https://www.w3.org/TR/css-values-3/#resolution
+const flex = ['fr']; // https://drafts.csswg.org/css-grid/#fr-unit
+const decibel = ['db']; // https://www.w3.org/TR/css3-speech/#mixing-props-voice-volume
+const semitones = ['st']; // https://www.w3.org/TR/css3-speech/#voice-props-voice-pitch
+
+exports.angle = angle;
+exports.decibel = decibel;
+exports.flex = flex;
+exports.frequency = frequency;
+exports.length = length;
+exports.resolution = resolution;
+exports.semitones = semitones;
+exports.time = time;