feat: docker compose maybe
This commit is contained in:
470
node_modules/css-tree/cjs/lexer/Lexer.cjs
generated
vendored
Normal file
470
node_modules/css-tree/cjs/lexer/Lexer.cjs
generated
vendored
Normal file
@ -0,0 +1,470 @@
|
||||
'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');
|
||||
|
||||
const cssWideKeywordsSyntax = matchGraph.buildMatchGraph(genericConst.cssWideKeywords.join(' | '));
|
||||
|
||||
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 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.cssWideKeywordsSyntax = cssWideKeywordsSyntax;
|
||||
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.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 in config.types) {
|
||||
this.addType_(name, config.types[name]);
|
||||
}
|
||||
}
|
||||
|
||||
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 in config.atrules) {
|
||||
this.addAtrule_(name, config.atrules[name]);
|
||||
}
|
||||
}
|
||||
|
||||
if (config.properties) {
|
||||
for (const name in config.properties) {
|
||||
this.addProperty_(name, config.properties[name]);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
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
|
||||
};
|
||||
|
||||
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;
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
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 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) || validate(syntax, node.name, brokenMap, map[node.name])) {
|
||||
broken.set(name, true);
|
||||
}
|
||||
}, this);
|
||||
}
|
||||
}
|
||||
|
||||
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]);
|
||||
}
|
||||
|
||||
brokenTypes = [...brokenTypes.keys()].filter(name => brokenTypes.get(name));
|
||||
brokenProperties = [...brokenProperties.keys()].filter(name => brokenProperties.get(name));
|
||||
|
||||
if (brokenTypes.length || brokenProperties.length) {
|
||||
return {
|
||||
types: brokenTypes,
|
||||
properties: brokenProperties
|
||||
};
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
dump(syntaxAsAst, pretty) {
|
||||
return {
|
||||
generic: this.generic,
|
||||
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;
|
128
node_modules/css-tree/cjs/lexer/error.cjs
generated
vendored
Normal file
128
node_modules/css-tree/cjs/lexer/error.cjs
generated
vendored
Normal file
@ -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;
|
235
node_modules/css-tree/cjs/lexer/generic-an-plus-b.cjs
generated
vendored
Normal file
235
node_modules/css-tree/cjs/lexer/generic-an-plus-b.cjs
generated
vendored
Normal file
@ -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;
|
12
node_modules/css-tree/cjs/lexer/generic-const.cjs
generated
vendored
Normal file
12
node_modules/css-tree/cjs/lexer/generic-const.cjs
generated
vendored
Normal file
@ -0,0 +1,12 @@
|
||||
'use strict';
|
||||
|
||||
// https://drafts.csswg.org/css-cascade-5/
|
||||
const cssWideKeywords = [
|
||||
'initial',
|
||||
'inherit',
|
||||
'unset',
|
||||
'revert',
|
||||
'revert-layer'
|
||||
];
|
||||
|
||||
exports.cssWideKeywords = cssWideKeywords;
|
149
node_modules/css-tree/cjs/lexer/generic-urange.cjs
generated
vendored
Normal file
149
node_modules/css-tree/cjs/lexer/generic-urange.cjs
generated
vendored
Normal file
@ -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;
|
573
node_modules/css-tree/cjs/lexer/generic.cjs
generated
vendored
Normal file
573
node_modules/css-tree/cjs/lexer/generic.cjs
generated
vendored
Normal file
@ -0,0 +1,573 @@
|
||||
'use strict';
|
||||
|
||||
const genericConst = require('./generic-const.cjs');
|
||||
const genericAnPlusB = require('./generic-an-plus-b.cjs');
|
||||
const genericUrange = require('./generic-urange.cjs');
|
||||
const types = require('../tokenizer/types.cjs');
|
||||
const charCodeDefinitions = require('../tokenizer/char-code-definitions.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-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 valid identifier
|
||||
// that starts with two dashes, except -- itself, which is reserved for future use by CSS.
|
||||
// NOTE: Current implementation treat `--` as a valid name since most (all?) major browsers treat it as valid.
|
||||
function customPropertyName(token) {
|
||||
// ... defined as any valid identifier
|
||||
if (token === null || token.type !== types.Ident) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
// ... that starts 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-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,
|
||||
'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;
|
7
node_modules/css-tree/cjs/lexer/index.cjs
generated
vendored
Normal file
7
node_modules/css-tree/cjs/lexer/index.cjs
generated
vendored
Normal file
@ -0,0 +1,7 @@
|
||||
'use strict';
|
||||
|
||||
const Lexer = require('./Lexer.cjs');
|
||||
|
||||
|
||||
|
||||
exports.Lexer = Lexer.Lexer;
|
459
node_modules/css-tree/cjs/lexer/match-graph.cjs
generated
vendored
Normal file
459
node_modules/css-tree/cjs/lexer/match-graph.cjs
generated
vendored
Normal file
@ -0,0 +1,459 @@
|
||||
'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 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);
|
||||
|
||||
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;
|
632
node_modules/css-tree/cjs/lexer/match.cjs
generated
vendored
Normal file
632
node_modules/css-tree/cjs/lexer/match.cjs
generated
vendored
Normal file
@ -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.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;
|
54
node_modules/css-tree/cjs/lexer/prepare-tokens.cjs
generated
vendored
Normal file
54
node_modules/css-tree/cjs/lexer/prepare-tokens.cjs
generated
vendored
Normal file
@ -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;
|
65
node_modules/css-tree/cjs/lexer/search.cjs
generated
vendored
Normal file
65
node_modules/css-tree/cjs/lexer/search.cjs
generated
vendored
Normal file
@ -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;
|
168
node_modules/css-tree/cjs/lexer/structure.cjs
generated
vendored
Normal file
168
node_modules/css-tree/cjs/lexer/structure.cjs
generated
vendored
Normal file
@ -0,0 +1,168 @@
|
||||
'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 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 docsTypes = [];
|
||||
const fieldTypes = fields[key] = Array.isArray(structure[key])
|
||||
? structure[key].slice()
|
||||
: [structure[key]];
|
||||
|
||||
for (let i = 0; i < fieldTypes.length; i++) {
|
||||
const fieldType = fieldTypes[i];
|
||||
if (fieldType === String || fieldType === Boolean) {
|
||||
docsTypes.push(fieldType.name);
|
||||
} else if (fieldType === null) {
|
||||
docsTypes.push('null');
|
||||
} else if (typeof fieldType === 'string') {
|
||||
docsTypes.push('<' + fieldType + '>');
|
||||
} else if (Array.isArray(fieldType)) {
|
||||
docsTypes.push('List'); // TODO: use type enum
|
||||
} else {
|
||||
throw new Error('Wrong value `' + fieldType + '` in `' + name + '.' + key + '` structure definition');
|
||||
}
|
||||
}
|
||||
|
||||
docs[key] = docsTypes.join(' | ');
|
||||
}
|
||||
|
||||
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;
|
73
node_modules/css-tree/cjs/lexer/trace.cjs
generated
vendored
Normal file
73
node_modules/css-tree/cjs/lexer/trace.cjs
generated
vendored
Normal file
@ -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;
|
38
node_modules/css-tree/cjs/lexer/units.cjs
generated
vendored
Normal file
38
node_modules/css-tree/cjs/lexer/units.cjs
generated
vendored
Normal file
@ -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;
|
Reference in New Issue
Block a user