first commit
This commit is contained in:
347
build/node_modules/css-tree/lib/lexer/Lexer.js
generated
vendored
Normal file
347
build/node_modules/css-tree/lib/lexer/Lexer.js
generated
vendored
Normal file
@@ -0,0 +1,347 @@
|
||||
'use strict';
|
||||
|
||||
var SyntaxReferenceError = require('./error').SyntaxReferenceError;
|
||||
var MatchError = require('./error').MatchError;
|
||||
var names = require('../utils/names');
|
||||
var generic = require('./generic');
|
||||
var parse = require('./grammar/parse');
|
||||
var translate = require('./grammar/translate');
|
||||
var walk = require('./grammar/walk');
|
||||
var match = require('./match');
|
||||
var trace = require('./trace');
|
||||
var search = require('./search');
|
||||
var getStructureFromConfig = require('./structure').getStructureFromConfig;
|
||||
var cssWideKeywords = parse('inherit | initial | unset');
|
||||
var cssWideKeywordsWithExpression = parse('inherit | initial | unset | <expression>');
|
||||
|
||||
function dumpMapSyntax(map, syntaxAsAst) {
|
||||
var result = {};
|
||||
|
||||
for (var name in map) {
|
||||
if (map[name].syntax) {
|
||||
result[name] = syntaxAsAst ? map[name].syntax : translate(map[name].syntax);
|
||||
}
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
function unwrapNode(item) {
|
||||
return item && item.data;
|
||||
}
|
||||
|
||||
function valueHasVar(value) {
|
||||
var hasVar = false;
|
||||
|
||||
this.syntax.walk(value, function(node) {
|
||||
if (node.type === 'Function' && node.name.toLowerCase() === 'var') {
|
||||
hasVar = true;
|
||||
}
|
||||
});
|
||||
|
||||
return hasVar;
|
||||
}
|
||||
|
||||
// check node is \0 or \9 hack
|
||||
function isHack(node) {
|
||||
return node.type === 'Identifier' && /^\\[09]/.test(node.name);
|
||||
}
|
||||
|
||||
// white spaces, comments and some hacks can to be ignored at the end of value
|
||||
function isNextMayToBeIgnored(cursor) {
|
||||
while (cursor !== null) {
|
||||
if (cursor.data.type !== 'WhiteSpace' &&
|
||||
cursor.data.type !== 'Comment' &&
|
||||
!isHack(cursor.data)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
cursor = cursor.next;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
function buildMatchResult(match, error) {
|
||||
return {
|
||||
matched: match,
|
||||
error: error,
|
||||
getTrace: trace.getTrace,
|
||||
isType: trace.isType,
|
||||
isProperty: trace.isProperty,
|
||||
isKeyword: trace.isKeyword
|
||||
};
|
||||
}
|
||||
|
||||
function matchSyntax(lexer, syntax, value) {
|
||||
var result;
|
||||
|
||||
if (!value || value.type !== 'Value') {
|
||||
return buildMatchResult(null, new Error('Not a Value node'));
|
||||
}
|
||||
|
||||
if (valueHasVar.call(lexer, value)) {
|
||||
return buildMatchResult(null, new Error('Matching for a value with var() is not supported'));
|
||||
}
|
||||
|
||||
result = match(lexer, lexer.valueCommonSyntax, value.children.head);
|
||||
|
||||
if (!result.match) {
|
||||
result = syntax.match(value.children.head);
|
||||
if (!result.match) {
|
||||
return buildMatchResult(null, new MatchError('Mismatch', lexer, syntax.syntax, value, result.badNode || unwrapNode(result.next) || value));
|
||||
}
|
||||
}
|
||||
|
||||
// enhance top-level match wrapper
|
||||
if (result.match.type === 'ASTNode') {
|
||||
result.match = {
|
||||
syntax: {
|
||||
type: syntax.type,
|
||||
name: syntax.name
|
||||
},
|
||||
match: [result.match]
|
||||
};
|
||||
} else if (result.match.syntax.type === 'Group') {
|
||||
result.match.syntax = {
|
||||
type: syntax.type,
|
||||
name: syntax.name
|
||||
};
|
||||
}
|
||||
|
||||
if (result.next && !isNextMayToBeIgnored(result.next)) {
|
||||
return buildMatchResult(null, new MatchError('Uncomplete match', lexer, syntax.syntax, value, result.badNode || unwrapNode(result.next) || value));
|
||||
}
|
||||
|
||||
return buildMatchResult(result.match, null);
|
||||
}
|
||||
|
||||
var Lexer = function(config, syntax, structure) {
|
||||
this.valueCommonSyntax = cssWideKeywords;
|
||||
this.syntax = syntax;
|
||||
this.generic = false;
|
||||
this.properties = {};
|
||||
this.types = {};
|
||||
this.structure = structure || getStructureFromConfig(config);
|
||||
|
||||
if (config) {
|
||||
if (config.generic) {
|
||||
this.generic = true;
|
||||
for (var name in generic) {
|
||||
this.addType_(name, generic[name]);
|
||||
}
|
||||
}
|
||||
|
||||
if (config.types) {
|
||||
for (var name in config.types) {
|
||||
this.addType_(name, config.types[name]);
|
||||
}
|
||||
}
|
||||
|
||||
if (config.properties) {
|
||||
for (var name in config.properties) {
|
||||
this.addProperty_(name, config.properties[name]);
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
Lexer.prototype = {
|
||||
structure: {},
|
||||
checkStructure: function(ast) {
|
||||
function collectWarning(node, message) {
|
||||
warns.push({
|
||||
node: node,
|
||||
message: message
|
||||
});
|
||||
}
|
||||
|
||||
var structure = this.structure;
|
||||
var 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: function(syntax, type, name) {
|
||||
var self = this;
|
||||
var descriptor = {
|
||||
type: type,
|
||||
name: name,
|
||||
syntax: null,
|
||||
match: null
|
||||
};
|
||||
|
||||
if (typeof syntax === 'function') {
|
||||
// convert syntax to pseudo syntax node
|
||||
// NOTE: that's not a part of match result tree
|
||||
syntax = {
|
||||
type: 'ASTNode',
|
||||
match: syntax
|
||||
};
|
||||
|
||||
descriptor.match = function(item) {
|
||||
return match(self, syntax, item);
|
||||
};
|
||||
} else {
|
||||
if (typeof syntax === 'string') {
|
||||
// lazy parsing on first access
|
||||
Object.defineProperty(descriptor, 'syntax', {
|
||||
get: function() {
|
||||
Object.defineProperty(descriptor, 'syntax', {
|
||||
value: parse(syntax)
|
||||
});
|
||||
|
||||
return descriptor.syntax;
|
||||
}
|
||||
});
|
||||
} else {
|
||||
descriptor.syntax = syntax;
|
||||
}
|
||||
|
||||
descriptor.match = function(item) {
|
||||
return match(self, descriptor.syntax, item);
|
||||
};
|
||||
}
|
||||
|
||||
return descriptor;
|
||||
},
|
||||
addProperty_: function(name, syntax) {
|
||||
this.properties[name] = this.createDescriptor(syntax, 'Property', name);
|
||||
},
|
||||
addType_: function(name, syntax) {
|
||||
this.types[name] = this.createDescriptor(syntax, 'Type', name);
|
||||
|
||||
if (syntax === generic.expression) {
|
||||
this.valueCommonSyntax = cssWideKeywordsWithExpression;
|
||||
}
|
||||
},
|
||||
|
||||
matchDeclaration: function(node) {
|
||||
if (node.type !== 'Declaration') {
|
||||
return buildMatchResult(null, new Error('Not a Declaration node'));
|
||||
}
|
||||
|
||||
return this.matchProperty(node.property, node.value);
|
||||
},
|
||||
matchProperty: function(propertyName, value) {
|
||||
var property = names.property(propertyName);
|
||||
|
||||
// don't match syntax for a custom property
|
||||
if (property.custom) {
|
||||
return buildMatchResult(null, new Error('Lexer matching doesn\'t applicable for custom properties'));
|
||||
}
|
||||
|
||||
var propertySyntax = property.vendor
|
||||
? this.getProperty(property.vendor + property.name) || this.getProperty(property.name)
|
||||
: this.getProperty(property.name);
|
||||
|
||||
if (!propertySyntax) {
|
||||
return buildMatchResult(null, new SyntaxReferenceError('Unknown property', propertyName));
|
||||
}
|
||||
|
||||
return matchSyntax(this, propertySyntax, value);
|
||||
},
|
||||
matchType: function(typeName, value) {
|
||||
var typeSyntax = this.getType(typeName);
|
||||
|
||||
if (!typeSyntax) {
|
||||
return buildMatchResult(null, new SyntaxReferenceError('Unknown type', typeName));
|
||||
}
|
||||
|
||||
return matchSyntax(this, typeSyntax, value);
|
||||
},
|
||||
|
||||
findValueFragments: function(propertyName, value, type, name) {
|
||||
return search.matchFragments(this, value, this.matchProperty(propertyName, value), type, name);
|
||||
},
|
||||
findDeclarationValueFragments: function(declaration, type, name) {
|
||||
return search.matchFragments(this, declaration.value, this.matchDeclaration(declaration), type, name);
|
||||
},
|
||||
findAllFragments: function(ast, type, name) {
|
||||
var result = [];
|
||||
|
||||
this.syntax.walkDeclarations(ast, function(declaration) {
|
||||
result.push.apply(result, this.findDeclarationValueFragments(declaration, type, name));
|
||||
}.bind(this));
|
||||
|
||||
return result;
|
||||
},
|
||||
|
||||
getProperty: function(name) {
|
||||
return this.properties.hasOwnProperty(name) ? this.properties[name] : null;
|
||||
},
|
||||
getType: function(name) {
|
||||
return this.types.hasOwnProperty(name) ? this.types[name] : null;
|
||||
},
|
||||
|
||||
validate: function() {
|
||||
function validate(syntax, name, broken, descriptor) {
|
||||
if (broken.hasOwnProperty(name)) {
|
||||
return broken[name];
|
||||
}
|
||||
|
||||
broken[name] = false;
|
||||
if (descriptor.syntax !== null) {
|
||||
walk(descriptor.syntax, function(node) {
|
||||
if (node.type !== 'Type' && node.type !== 'Property') {
|
||||
return;
|
||||
}
|
||||
|
||||
var map = node.type === 'Type' ? syntax.types : syntax.properties;
|
||||
var brokenMap = node.type === 'Type' ? brokenTypes : brokenProperties;
|
||||
|
||||
if (!map.hasOwnProperty(node.name) || validate(syntax, node.name, brokenMap, map[node.name])) {
|
||||
broken[name] = true;
|
||||
}
|
||||
}, this);
|
||||
}
|
||||
}
|
||||
|
||||
var brokenTypes = {};
|
||||
var brokenProperties = {};
|
||||
|
||||
for (var key in this.types) {
|
||||
validate(this, key, brokenTypes, this.types[key]);
|
||||
}
|
||||
|
||||
for (var key in this.properties) {
|
||||
validate(this, key, brokenProperties, this.properties[key]);
|
||||
}
|
||||
|
||||
brokenTypes = Object.keys(brokenTypes).filter(function(name) {
|
||||
return brokenTypes[name];
|
||||
});
|
||||
brokenProperties = Object.keys(brokenProperties).filter(function(name) {
|
||||
return brokenProperties[name];
|
||||
});
|
||||
|
||||
if (brokenTypes.length || brokenProperties.length) {
|
||||
return {
|
||||
types: brokenTypes,
|
||||
properties: brokenProperties
|
||||
};
|
||||
}
|
||||
|
||||
return null;
|
||||
},
|
||||
dump: function(syntaxAsAst) {
|
||||
return {
|
||||
generic: this.generic,
|
||||
types: dumpMapSyntax(this.types, syntaxAsAst),
|
||||
properties: dumpMapSyntax(this.properties, syntaxAsAst)
|
||||
};
|
||||
},
|
||||
toString: function() {
|
||||
return JSON.stringify(this.dump());
|
||||
}
|
||||
};
|
||||
|
||||
module.exports = Lexer;
|
||||
62
build/node_modules/css-tree/lib/lexer/error.js
generated
vendored
Normal file
62
build/node_modules/css-tree/lib/lexer/error.js
generated
vendored
Normal file
@@ -0,0 +1,62 @@
|
||||
'use strict';
|
||||
|
||||
var createCustomError = require('../utils/createCustomError');
|
||||
var translateGrammar = require('./grammar/translate');
|
||||
|
||||
function getLocation(node, point) {
|
||||
var loc = node && node.loc && node.loc[point];
|
||||
|
||||
return loc
|
||||
? { offset: loc.offset,
|
||||
line: loc.line,
|
||||
column: loc.column }
|
||||
: null;
|
||||
}
|
||||
|
||||
var SyntaxReferenceError = function(type, referenceName) {
|
||||
var error = createCustomError('SyntaxReferenceError', type + ' `' + referenceName + '`');
|
||||
|
||||
error.reference = referenceName;
|
||||
|
||||
return error;
|
||||
};
|
||||
|
||||
var MatchError = function(message, lexer, syntax, value, badNode) {
|
||||
var error = createCustomError('SyntaxMatchError', message);
|
||||
var errorOffset = -1;
|
||||
var start = getLocation(badNode, 'start');
|
||||
var end = getLocation(badNode, 'end');
|
||||
var css = lexer.syntax.translateMarkup(value, function(node, buffer) {
|
||||
if (node === badNode) {
|
||||
errorOffset = buffer.length;
|
||||
}
|
||||
});
|
||||
|
||||
if (errorOffset === -1) {
|
||||
errorOffset = css.length;
|
||||
}
|
||||
|
||||
error.rawMessage = message;
|
||||
error.syntax = syntax ? translateGrammar(syntax) : '<generic>';
|
||||
error.css = css;
|
||||
error.mismatchOffset = errorOffset;
|
||||
error.loc = {
|
||||
source: badNode && badNode.loc && badNode.loc.source || '<unknown>',
|
||||
start: start,
|
||||
end: end
|
||||
};
|
||||
error.line = start ? start.line : undefined;
|
||||
error.column = start ? start.column : undefined;
|
||||
error.offset = start ? start.offset : undefined;
|
||||
error.message = message + '\n' +
|
||||
' syntax: ' + error.syntax + '\n' +
|
||||
' value: ' + (error.css || '<empty string>') + '\n' +
|
||||
' --------' + new Array(error.mismatchOffset + 1).join('-') + '^';
|
||||
|
||||
return error;
|
||||
};
|
||||
|
||||
module.exports = {
|
||||
SyntaxReferenceError: SyntaxReferenceError,
|
||||
MatchError: MatchError
|
||||
};
|
||||
221
build/node_modules/css-tree/lib/lexer/generic.js
generated
vendored
Normal file
221
build/node_modules/css-tree/lib/lexer/generic.js
generated
vendored
Normal file
@@ -0,0 +1,221 @@
|
||||
'use strict';
|
||||
|
||||
var names = require('../utils/names.js');
|
||||
|
||||
// https://www.w3.org/TR/css-values-3/#lengths
|
||||
var LENGTH = {
|
||||
// absolute length units
|
||||
'px': true,
|
||||
'mm': true,
|
||||
'cm': true,
|
||||
'in': true,
|
||||
'pt': true,
|
||||
'pc': true,
|
||||
'q': true,
|
||||
|
||||
// relative length units
|
||||
'em': true,
|
||||
'ex': true,
|
||||
'ch': true,
|
||||
'rem': true,
|
||||
|
||||
// viewport-percentage lengths
|
||||
'vh': true,
|
||||
'vw': true,
|
||||
'vmin': true,
|
||||
'vmax': true,
|
||||
'vm': true
|
||||
};
|
||||
|
||||
var ANGLE = {
|
||||
'deg': true,
|
||||
'grad': true,
|
||||
'rad': true,
|
||||
'turn': true
|
||||
};
|
||||
|
||||
var TIME = {
|
||||
's': true,
|
||||
'ms': true
|
||||
};
|
||||
|
||||
var FREQUENCY = {
|
||||
'hz': true,
|
||||
'khz': true
|
||||
};
|
||||
|
||||
// https://www.w3.org/TR/css-values-3/#resolution (https://drafts.csswg.org/css-values/#resolution)
|
||||
var RESOLUTION = {
|
||||
'dpi': true,
|
||||
'dpcm': true,
|
||||
'dppx': true,
|
||||
'x': true // https://github.com/w3c/csswg-drafts/issues/461
|
||||
};
|
||||
|
||||
// https://drafts.csswg.org/css-grid/#fr-unit
|
||||
var FLEX = {
|
||||
'fr': true
|
||||
};
|
||||
|
||||
// https://www.w3.org/TR/css3-speech/#mixing-props-voice-volume
|
||||
var DECIBEL = {
|
||||
'db': true
|
||||
};
|
||||
|
||||
// https://www.w3.org/TR/css3-speech/#voice-props-voice-pitch
|
||||
var SEMITONES = {
|
||||
'st': true
|
||||
};
|
||||
|
||||
// can be used wherever <length>, <frequency>, <angle>, <time>, <percentage>, <number>, or <integer> values are allowed
|
||||
// https://drafts.csswg.org/css-values/#calc-notation
|
||||
function isCalc(node) {
|
||||
if (node.data.type !== 'Function') {
|
||||
return false;
|
||||
}
|
||||
|
||||
var keyword = names.keyword(node.data.name);
|
||||
|
||||
if (keyword.name !== 'calc') {
|
||||
return false;
|
||||
}
|
||||
|
||||
// there were some prefixed implementations
|
||||
return keyword.vendor === '' ||
|
||||
keyword.vendor === '-moz-' ||
|
||||
keyword.vendor === '-webkit-';
|
||||
}
|
||||
|
||||
function astNode(type) {
|
||||
return function(node) {
|
||||
return node.data.type === type;
|
||||
};
|
||||
}
|
||||
|
||||
function dimension(type) {
|
||||
return function(node) {
|
||||
return isCalc(node) ||
|
||||
(node.data.type === 'Dimension' && type.hasOwnProperty(node.data.unit.toLowerCase()));
|
||||
};
|
||||
}
|
||||
|
||||
function zeroUnitlessDimension(type) {
|
||||
return function(node) {
|
||||
return isCalc(node) ||
|
||||
(node.data.type === 'Dimension' && type.hasOwnProperty(node.data.unit.toLowerCase())) ||
|
||||
(node.data.type === 'Number' && Number(node.data.value) === 0);
|
||||
};
|
||||
}
|
||||
|
||||
function attr(node) {
|
||||
return node.data.type === 'Function' && node.data.name.toLowerCase() === 'attr';
|
||||
}
|
||||
|
||||
function number(node) {
|
||||
return isCalc(node) || node.data.type === 'Number';
|
||||
}
|
||||
|
||||
function numberZeroOne(node) {
|
||||
if (isCalc(node) || node.data.type === 'Number') {
|
||||
var value = Number(node.data.value);
|
||||
|
||||
return value >= 0 && value <= 1;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
function numberOneOrGreater(node) {
|
||||
if (isCalc(node) || node.data.type === 'Number') {
|
||||
return Number(node.data.value) >= 1;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
// TODO: fail on 10e-2
|
||||
function integer(node) {
|
||||
return isCalc(node) ||
|
||||
(node.data.type === 'Number' && node.data.value.indexOf('.') === -1);
|
||||
}
|
||||
|
||||
// TODO: fail on 10e-2
|
||||
function positiveInteger(node) {
|
||||
return isCalc(node) ||
|
||||
(node.data.type === 'Number' && node.data.value.indexOf('.') === -1 && node.data.value.charAt(0) !== '-');
|
||||
}
|
||||
|
||||
function percentage(node) {
|
||||
return isCalc(node) ||
|
||||
node.data.type === 'Percentage';
|
||||
}
|
||||
|
||||
function hexColor(node) {
|
||||
if (node.data.type !== 'HexColor') {
|
||||
return false;
|
||||
}
|
||||
|
||||
var hex = node.data.value;
|
||||
|
||||
return /^[0-9a-fA-F]{3,8}$/.test(hex) &&
|
||||
(hex.length === 3 || hex.length === 4 || hex.length === 6 || hex.length === 8);
|
||||
}
|
||||
|
||||
function expression(node) {
|
||||
return node.data.type === 'Function' && node.data.name.toLowerCase() === 'expression';
|
||||
}
|
||||
|
||||
// https://developer.mozilla.org/en-US/docs/Web/CSS/custom-ident
|
||||
// https://drafts.csswg.org/css-values-4/#identifier-value
|
||||
function customIdent(node) {
|
||||
if (node.data.type !== 'Identifier') {
|
||||
return false;
|
||||
}
|
||||
|
||||
var name = node.data.name.toLowerCase();
|
||||
|
||||
// § 3.2. Author-defined Identifiers: the <custom-ident> type
|
||||
// The CSS-wide keywords are not valid <custom-ident>s
|
||||
if (name === 'unset' || name === 'initial' || name === 'inherit') {
|
||||
return false;
|
||||
}
|
||||
|
||||
// The default keyword is reserved and is also not a valid <custom-ident>
|
||||
if (name === 'default') {
|
||||
return false;
|
||||
}
|
||||
|
||||
// TODO: ignore property specific keywords (as described https://developer.mozilla.org/en-US/docs/Web/CSS/custom-ident)
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
module.exports = {
|
||||
'angle': zeroUnitlessDimension(ANGLE),
|
||||
'attr()': attr,
|
||||
'custom-ident': customIdent,
|
||||
'decibel': dimension(DECIBEL),
|
||||
'dimension': astNode('Dimension'),
|
||||
'frequency': dimension(FREQUENCY),
|
||||
'flex': dimension(FLEX),
|
||||
'hex-color': hexColor,
|
||||
'id-selector': astNode('IdSelector'), // element( <id-selector> )
|
||||
'ident': astNode('Identifier'),
|
||||
'integer': integer,
|
||||
'length': zeroUnitlessDimension(LENGTH),
|
||||
'number': number,
|
||||
'number-zero-one': numberZeroOne,
|
||||
'number-one-or-greater': numberOneOrGreater,
|
||||
'percentage': percentage,
|
||||
'positive-integer': positiveInteger,
|
||||
'resolution': dimension(RESOLUTION),
|
||||
'semitones': dimension(SEMITONES),
|
||||
'string': astNode('String'),
|
||||
'time': dimension(TIME),
|
||||
'unicode-range': astNode('UnicodeRange'),
|
||||
'url': astNode('Url'),
|
||||
|
||||
// old IE stuff
|
||||
'progid': astNode('Raw'),
|
||||
'expression': expression
|
||||
};
|
||||
20
build/node_modules/css-tree/lib/lexer/grammar/error.js
generated
vendored
Normal file
20
build/node_modules/css-tree/lib/lexer/grammar/error.js
generated
vendored
Normal file
@@ -0,0 +1,20 @@
|
||||
'use strict';
|
||||
|
||||
var createCustomError = require('../../utils/createCustomError');
|
||||
|
||||
var SyntaxParseError = function(message, syntaxStr, offset) {
|
||||
var error = createCustomError('SyntaxParseError', message);
|
||||
|
||||
error.rawMessage = message;
|
||||
error.syntax = syntaxStr;
|
||||
error.offset = offset;
|
||||
error.message = error.rawMessage + '\n' +
|
||||
' ' + error.syntax + '\n' +
|
||||
'--' + new Array((error.offset || error.syntax.length) + 1).join('-') + '^';
|
||||
|
||||
return error;
|
||||
};
|
||||
|
||||
module.exports = {
|
||||
SyntaxParseError: SyntaxParseError
|
||||
};
|
||||
6
build/node_modules/css-tree/lib/lexer/grammar/index.js
generated
vendored
Normal file
6
build/node_modules/css-tree/lib/lexer/grammar/index.js
generated
vendored
Normal file
@@ -0,0 +1,6 @@
|
||||
module.exports = {
|
||||
SyntaxParseError: require('./error').SyntaxParseError,
|
||||
parse: require('./parse'),
|
||||
translate: require('./translate'),
|
||||
walk: require('./walk')
|
||||
};
|
||||
503
build/node_modules/css-tree/lib/lexer/grammar/parse.js
generated
vendored
Normal file
503
build/node_modules/css-tree/lib/lexer/grammar/parse.js
generated
vendored
Normal file
@@ -0,0 +1,503 @@
|
||||
'use strict';
|
||||
|
||||
var SyntaxParseError = require('./error').SyntaxParseError;
|
||||
|
||||
var TAB = 9;
|
||||
var N = 10;
|
||||
var F = 12;
|
||||
var R = 13;
|
||||
var SPACE = 32;
|
||||
var EXCLAMATIONMARK = 33; // !
|
||||
var NUMBERSIGN = 35; // #
|
||||
var PERCENTSIGN = 37; // %
|
||||
var AMPERSAND = 38; // &
|
||||
var APOSTROPHE = 39; // '
|
||||
var LEFTPARENTHESIS = 40; // (
|
||||
var RIGHTPARENTHESIS = 41; // )
|
||||
var ASTERISK = 42; // *
|
||||
var PLUSSIGN = 43; // +
|
||||
var COMMA = 44; // ,
|
||||
var SOLIDUS = 47; // /
|
||||
var LESSTHANSIGN = 60; // <
|
||||
var GREATERTHANSIGN = 62; // >
|
||||
var QUESTIONMARK = 63; // ?
|
||||
var LEFTSQUAREBRACKET = 91; // [
|
||||
var RIGHTSQUAREBRACKET = 93; // ]
|
||||
var LEFTCURLYBRACKET = 123; // {
|
||||
var VERTICALLINE = 124; // |
|
||||
var RIGHTCURLYBRACKET = 125; // }
|
||||
var COMBINATOR_PRECEDENCE = {
|
||||
' ': 1,
|
||||
'&&': 2,
|
||||
'||': 3,
|
||||
'|': 4
|
||||
};
|
||||
var MULTIPLIER_DEFAULT = {
|
||||
comma: false,
|
||||
min: 1,
|
||||
max: 1
|
||||
};
|
||||
var MULTIPLIER_ZERO_OR_MORE = {
|
||||
comma: false,
|
||||
min: 0,
|
||||
max: 0
|
||||
};
|
||||
var MULTIPLIER_ONE_OR_MORE = {
|
||||
comma: false,
|
||||
min: 1,
|
||||
max: 0
|
||||
};
|
||||
var MULTIPLIER_ONE_OR_MORE_COMMA_SEPARATED = {
|
||||
comma: true,
|
||||
min: 1,
|
||||
max: 0
|
||||
};
|
||||
var MULTIPLIER_ZERO_OR_ONE = {
|
||||
comma: false,
|
||||
min: 0,
|
||||
max: 1
|
||||
};
|
||||
var NAME_CHAR = (function() {
|
||||
var array = typeof Uint32Array === 'function' ? new Uint32Array(128) : new Array(128);
|
||||
for (var i = 0; i < 128; i++) {
|
||||
array[i] = /[a-zA-Z0-9\-]/.test(String.fromCharCode(i)) ? 1 : 0;
|
||||
}
|
||||
return array;
|
||||
})();
|
||||
|
||||
var Tokenizer = function(str) {
|
||||
this.str = str;
|
||||
this.pos = 0;
|
||||
};
|
||||
Tokenizer.prototype = {
|
||||
charCode: function() {
|
||||
return this.pos < this.str.length ? this.str.charCodeAt(this.pos) : 0;
|
||||
},
|
||||
nextCharCode: function() {
|
||||
return this.pos + 1 < this.str.length ? this.str.charCodeAt(this.pos + 1) : 0;
|
||||
},
|
||||
substringToPos: function(end) {
|
||||
return this.str.substring(this.pos, this.pos = end);
|
||||
},
|
||||
eat: function(code) {
|
||||
if (this.charCode() !== code) {
|
||||
error(this, this.pos, 'Expect `' + String.fromCharCode(code) + '`');
|
||||
}
|
||||
|
||||
this.pos++;
|
||||
}
|
||||
};
|
||||
|
||||
function scanSpaces(tokenizer) {
|
||||
var end = tokenizer.pos + 1;
|
||||
|
||||
for (; end < tokenizer.str.length; end++) {
|
||||
var code = tokenizer.str.charCodeAt(end);
|
||||
if (code !== R && code !== N && code !== F && code !== SPACE && code !== TAB) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return tokenizer.substringToPos(end);
|
||||
}
|
||||
|
||||
function scanWord(tokenizer) {
|
||||
var end = tokenizer.pos;
|
||||
|
||||
for (; end < tokenizer.str.length; end++) {
|
||||
var code = tokenizer.str.charCodeAt(end);
|
||||
if (code >= 128 || NAME_CHAR[code] === 0) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (tokenizer.pos === end) {
|
||||
error(tokenizer, tokenizer.pos, 'Expect a keyword');
|
||||
}
|
||||
|
||||
return tokenizer.substringToPos(end);
|
||||
}
|
||||
|
||||
function scanNumber(tokenizer) {
|
||||
var end = tokenizer.pos;
|
||||
|
||||
for (; end < tokenizer.str.length; end++) {
|
||||
var code = tokenizer.str.charCodeAt(end);
|
||||
if (code < 48 || code > 57) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (tokenizer.pos === end) {
|
||||
error(tokenizer, tokenizer.pos, 'Expect a number');
|
||||
}
|
||||
|
||||
return tokenizer.substringToPos(end);
|
||||
}
|
||||
|
||||
function scanString(tokenizer) {
|
||||
var end = tokenizer.str.indexOf('\'', tokenizer.pos + 1);
|
||||
|
||||
if (end === -1) {
|
||||
error(tokenizer, tokenizer.str.length, 'Expect a quote');
|
||||
}
|
||||
|
||||
return tokenizer.substringToPos(end + 1);
|
||||
}
|
||||
|
||||
function readMultiplierRange(tokenizer, comma) {
|
||||
var min = null;
|
||||
var max = null;
|
||||
|
||||
tokenizer.eat(LEFTCURLYBRACKET);
|
||||
|
||||
min = scanNumber(tokenizer);
|
||||
|
||||
if (tokenizer.charCode() === COMMA) {
|
||||
tokenizer.pos++;
|
||||
if (tokenizer.charCode() !== RIGHTCURLYBRACKET) {
|
||||
max = scanNumber(tokenizer);
|
||||
}
|
||||
} else {
|
||||
max = min;
|
||||
}
|
||||
|
||||
tokenizer.eat(RIGHTCURLYBRACKET);
|
||||
|
||||
return {
|
||||
comma: comma,
|
||||
min: Number(min),
|
||||
max: max ? Number(max) : 0
|
||||
};
|
||||
}
|
||||
|
||||
function readMultiplier(tokenizer) {
|
||||
switch (tokenizer.charCode()) {
|
||||
case ASTERISK:
|
||||
tokenizer.pos++;
|
||||
return MULTIPLIER_ZERO_OR_MORE;
|
||||
|
||||
case PLUSSIGN:
|
||||
tokenizer.pos++;
|
||||
return MULTIPLIER_ONE_OR_MORE;
|
||||
|
||||
case QUESTIONMARK:
|
||||
tokenizer.pos++;
|
||||
return MULTIPLIER_ZERO_OR_ONE;
|
||||
|
||||
case NUMBERSIGN:
|
||||
tokenizer.pos++;
|
||||
|
||||
if (tokenizer.charCode() !== LEFTCURLYBRACKET) {
|
||||
return MULTIPLIER_ONE_OR_MORE_COMMA_SEPARATED;
|
||||
}
|
||||
|
||||
return readMultiplierRange(tokenizer, true);
|
||||
|
||||
case LEFTCURLYBRACKET:
|
||||
return readMultiplierRange(tokenizer, false);
|
||||
}
|
||||
|
||||
return MULTIPLIER_DEFAULT;
|
||||
}
|
||||
|
||||
function maybeMultiplied(tokenizer, node) {
|
||||
var multiplier = readMultiplier(tokenizer);
|
||||
|
||||
if (multiplier !== MULTIPLIER_DEFAULT) {
|
||||
return {
|
||||
type: 'Group',
|
||||
terms: [node],
|
||||
combinator: '|', // `|` combinator is simplest in implementation (and therefore faster)
|
||||
disallowEmpty: false,
|
||||
multiplier: multiplier,
|
||||
explicit: false
|
||||
};
|
||||
}
|
||||
|
||||
return node;
|
||||
}
|
||||
|
||||
function readProperty(tokenizer) {
|
||||
var name;
|
||||
|
||||
tokenizer.eat(LESSTHANSIGN);
|
||||
tokenizer.eat(APOSTROPHE);
|
||||
|
||||
name = scanWord(tokenizer);
|
||||
|
||||
tokenizer.eat(APOSTROPHE);
|
||||
tokenizer.eat(GREATERTHANSIGN);
|
||||
|
||||
return maybeMultiplied(tokenizer, {
|
||||
type: 'Property',
|
||||
name: name
|
||||
});
|
||||
}
|
||||
|
||||
function readType(tokenizer) {
|
||||
var name;
|
||||
|
||||
tokenizer.eat(LESSTHANSIGN);
|
||||
name = scanWord(tokenizer);
|
||||
|
||||
if (tokenizer.charCode() === LEFTPARENTHESIS &&
|
||||
tokenizer.nextCharCode() === RIGHTPARENTHESIS) {
|
||||
tokenizer.pos += 2;
|
||||
name += '()';
|
||||
}
|
||||
|
||||
tokenizer.eat(GREATERTHANSIGN);
|
||||
|
||||
return maybeMultiplied(tokenizer, {
|
||||
type: 'Type',
|
||||
name: name
|
||||
});
|
||||
}
|
||||
|
||||
function readKeywordOrFunction(tokenizer) {
|
||||
var children = null;
|
||||
var name;
|
||||
|
||||
name = scanWord(tokenizer);
|
||||
|
||||
if (tokenizer.charCode() === LEFTPARENTHESIS) {
|
||||
tokenizer.pos++;
|
||||
children = readImplicitGroup(tokenizer);
|
||||
tokenizer.eat(RIGHTPARENTHESIS);
|
||||
|
||||
return maybeMultiplied(tokenizer, {
|
||||
type: 'Function',
|
||||
name: name,
|
||||
children: children
|
||||
});
|
||||
}
|
||||
|
||||
return maybeMultiplied(tokenizer, {
|
||||
type: 'Keyword',
|
||||
name: name
|
||||
});
|
||||
}
|
||||
|
||||
function regroupTerms(terms, combinators) {
|
||||
function createGroup(terms, combinator) {
|
||||
return {
|
||||
type: 'Group',
|
||||
terms: terms,
|
||||
combinator: combinator,
|
||||
disallowEmpty: false,
|
||||
multiplier: MULTIPLIER_DEFAULT,
|
||||
explicit: false
|
||||
};
|
||||
}
|
||||
|
||||
combinators = Object.keys(combinators).sort(function(a, b) {
|
||||
return COMBINATOR_PRECEDENCE[a] - COMBINATOR_PRECEDENCE[b];
|
||||
});
|
||||
|
||||
while (combinators.length > 0) {
|
||||
var combinator = combinators.shift();
|
||||
for (var i = 0, subgroupStart = 0; i < terms.length; i++) {
|
||||
var term = terms[i];
|
||||
if (term.type === 'Combinator') {
|
||||
if (term.value === combinator) {
|
||||
if (subgroupStart === -1) {
|
||||
subgroupStart = i - 1;
|
||||
}
|
||||
terms.splice(i, 1);
|
||||
i--;
|
||||
} else {
|
||||
if (subgroupStart !== -1 && i - subgroupStart > 1) {
|
||||
terms.splice(
|
||||
subgroupStart,
|
||||
i - subgroupStart,
|
||||
createGroup(terms.slice(subgroupStart, i), combinator)
|
||||
);
|
||||
i = subgroupStart + 1;
|
||||
}
|
||||
subgroupStart = -1;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (subgroupStart !== -1 && combinators.length) {
|
||||
terms.splice(
|
||||
subgroupStart,
|
||||
i - subgroupStart,
|
||||
createGroup(terms.slice(subgroupStart, i), combinator)
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
return combinator;
|
||||
}
|
||||
|
||||
function readImplicitGroup(tokenizer) {
|
||||
var terms = [];
|
||||
var combinators = {};
|
||||
var token;
|
||||
var prevToken = null;
|
||||
var prevTokenPos = tokenizer.pos;
|
||||
|
||||
while (token = peek(tokenizer)) {
|
||||
if (token.type !== 'Spaces') {
|
||||
if (token.type === 'Combinator') {
|
||||
// check for combinator in group beginning and double combinator sequence
|
||||
if (prevToken === null || prevToken.type === 'Combinator') {
|
||||
error(tokenizer, prevTokenPos, 'Unexpected combinator');
|
||||
}
|
||||
|
||||
combinators[token.value] = true;
|
||||
} else if (prevToken !== null && prevToken.type !== 'Combinator') {
|
||||
combinators[' '] = true; // a b
|
||||
terms.push({
|
||||
type: 'Combinator',
|
||||
value: ' '
|
||||
});
|
||||
}
|
||||
|
||||
terms.push(token);
|
||||
prevToken = token;
|
||||
prevTokenPos = tokenizer.pos;
|
||||
}
|
||||
}
|
||||
|
||||
// check for combinator in group ending
|
||||
if (prevToken !== null && prevToken.type === 'Combinator') {
|
||||
error(tokenizer, tokenizer.pos - prevTokenPos, 'Unexpected combinator');
|
||||
}
|
||||
|
||||
return {
|
||||
type: 'Group',
|
||||
terms: terms,
|
||||
combinator: regroupTerms(terms, combinators) || ' ',
|
||||
disallowEmpty: false,
|
||||
multiplier: MULTIPLIER_DEFAULT,
|
||||
explicit: false
|
||||
};
|
||||
}
|
||||
|
||||
function readGroup(tokenizer) {
|
||||
var result;
|
||||
|
||||
tokenizer.eat(LEFTSQUAREBRACKET);
|
||||
result = readImplicitGroup(tokenizer);
|
||||
tokenizer.eat(RIGHTSQUAREBRACKET);
|
||||
|
||||
result.explicit = true;
|
||||
result.multiplier = readMultiplier(tokenizer);
|
||||
|
||||
if (tokenizer.charCode() === EXCLAMATIONMARK) {
|
||||
tokenizer.pos++;
|
||||
result.disallowEmpty = true;
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
function peek(tokenizer) {
|
||||
var code = tokenizer.charCode();
|
||||
|
||||
if (code < 128 && NAME_CHAR[code] === 1) {
|
||||
return readKeywordOrFunction(tokenizer);
|
||||
}
|
||||
|
||||
switch (code) {
|
||||
case LEFTSQUAREBRACKET:
|
||||
return readGroup(tokenizer);
|
||||
|
||||
case LESSTHANSIGN:
|
||||
if (tokenizer.nextCharCode() === APOSTROPHE) {
|
||||
return readProperty(tokenizer);
|
||||
} else {
|
||||
return readType(tokenizer);
|
||||
}
|
||||
|
||||
case VERTICALLINE:
|
||||
return {
|
||||
type: 'Combinator',
|
||||
value: tokenizer.substringToPos(tokenizer.nextCharCode() === VERTICALLINE ? tokenizer.pos + 2 : tokenizer.pos + 1)
|
||||
};
|
||||
|
||||
case AMPERSAND:
|
||||
tokenizer.pos++;
|
||||
tokenizer.eat(AMPERSAND);
|
||||
return {
|
||||
type: 'Combinator',
|
||||
value: '&&'
|
||||
};
|
||||
|
||||
case COMMA:
|
||||
tokenizer.pos++;
|
||||
return {
|
||||
type: 'Comma',
|
||||
value: ','
|
||||
};
|
||||
|
||||
case SOLIDUS:
|
||||
tokenizer.pos++;
|
||||
return {
|
||||
type: 'Slash',
|
||||
value: '/'
|
||||
};
|
||||
|
||||
case PERCENTSIGN: // looks like exception, needs for attr()'s <type-or-unit>
|
||||
tokenizer.pos++;
|
||||
return {
|
||||
type: 'Percent',
|
||||
value: '%'
|
||||
};
|
||||
|
||||
case LEFTPARENTHESIS:
|
||||
tokenizer.pos++;
|
||||
var children = readImplicitGroup(tokenizer);
|
||||
tokenizer.eat(RIGHTPARENTHESIS);
|
||||
|
||||
return {
|
||||
type: 'Parentheses',
|
||||
children: children
|
||||
};
|
||||
|
||||
case APOSTROPHE:
|
||||
return {
|
||||
type: 'String',
|
||||
value: scanString(tokenizer)
|
||||
};
|
||||
|
||||
case SPACE:
|
||||
case TAB:
|
||||
case N:
|
||||
case R:
|
||||
case F:
|
||||
return {
|
||||
type: 'Spaces',
|
||||
value: scanSpaces(tokenizer)
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
function error(tokenizer, pos, msg) {
|
||||
throw new SyntaxParseError(msg || 'Unexpected input', tokenizer.str, pos);
|
||||
}
|
||||
|
||||
function parse(str) {
|
||||
var tokenizer = new Tokenizer(str);
|
||||
var result = readImplicitGroup(tokenizer);
|
||||
|
||||
if (tokenizer.pos !== str.length) {
|
||||
error(tokenizer, tokenizer.pos);
|
||||
}
|
||||
|
||||
// reduce redundant groups with single group term
|
||||
if (result.terms.length === 1 && result.terms[0].type === 'Group') {
|
||||
result = result.terms[0];
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
// warm up parse to elimitate code branches that never execute
|
||||
// fix soft deoptimizations (insufficient type feedback)
|
||||
parse('[a&&<b>#|<\'c\'>*||e(){2,} f{2} /,(% g#{1,2})]!');
|
||||
|
||||
module.exports = parse;
|
||||
106
build/node_modules/css-tree/lib/lexer/grammar/translate.js
generated
vendored
Normal file
106
build/node_modules/css-tree/lib/lexer/grammar/translate.js
generated
vendored
Normal file
@@ -0,0 +1,106 @@
|
||||
'use strict';
|
||||
|
||||
function isNodeType(node, type) {
|
||||
return node && node.type === type;
|
||||
}
|
||||
|
||||
function serializeMultiplier(multiplier) {
|
||||
if (multiplier.min === 0 && multiplier.max === 0) {
|
||||
return '*';
|
||||
}
|
||||
|
||||
if (multiplier.min === 0 && multiplier.max === 1) {
|
||||
return '?';
|
||||
}
|
||||
|
||||
if (multiplier.min === 1 && multiplier.max === 0) {
|
||||
return multiplier.comma ? '#' : '+';
|
||||
}
|
||||
|
||||
if (multiplier.min === 1 && multiplier.max === 1) {
|
||||
return '';
|
||||
}
|
||||
|
||||
return (
|
||||
(multiplier.comma ? '#' : '') +
|
||||
'{' + multiplier.min + (multiplier.min !== multiplier.max ? ',' + (multiplier.max !== 0 ? multiplier.max : '') : '') + '}'
|
||||
);
|
||||
}
|
||||
|
||||
function translateSequence(node, forceBraces, decorate) {
|
||||
var result = '';
|
||||
|
||||
if (node.explicit || forceBraces) {
|
||||
result += '[' + (!isNodeType(node.terms[0], 'Comma') ? ' ' : '');
|
||||
}
|
||||
|
||||
result += node.terms.map(function(term) {
|
||||
return translate(term, forceBraces, decorate);
|
||||
}).join(node.combinator === ' ' ? ' ' : ' ' + node.combinator + ' ');
|
||||
|
||||
if (node.explicit || forceBraces) {
|
||||
result += ' ]';
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
function translateParentheses(group, forceBraces, decorate) {
|
||||
if (!group.terms.length) {
|
||||
return '()';
|
||||
}
|
||||
|
||||
return '( ' + translateSequence(group, forceBraces, decorate) + ' )';
|
||||
}
|
||||
|
||||
function translate(node, forceBraces, decorate) {
|
||||
var result;
|
||||
|
||||
switch (node.type) {
|
||||
case 'Group':
|
||||
result =
|
||||
translateSequence(node, forceBraces, decorate) +
|
||||
(node.disallowEmpty ? '!' : '') +
|
||||
serializeMultiplier(node.multiplier);
|
||||
break;
|
||||
|
||||
case 'Keyword':
|
||||
result = node.name;
|
||||
break;
|
||||
|
||||
case 'Function':
|
||||
result = node.name + translateParentheses(node.children, forceBraces, decorate);
|
||||
break;
|
||||
|
||||
case 'Parentheses': // replace for seq('(' seq(...node.children) ')')
|
||||
result = translateParentheses(node.children, forceBraces, decorate);
|
||||
break;
|
||||
|
||||
case 'Type':
|
||||
result = '<' + node.name + '>';
|
||||
break;
|
||||
|
||||
case 'Property':
|
||||
result = '<\'' + node.name + '\'>';
|
||||
break;
|
||||
|
||||
case 'Combinator': // remove?
|
||||
case 'Slash': // replace for String? '/'
|
||||
case 'Percent': // replace for String? '%'
|
||||
case 'String':
|
||||
case 'Comma':
|
||||
result = node.value;
|
||||
break;
|
||||
|
||||
default:
|
||||
throw new Error('Unknown node type `' + node.type + '`');
|
||||
}
|
||||
|
||||
if (typeof decorate === 'function') {
|
||||
result = decorate(result, node);
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
module.exports = translate;
|
||||
31
build/node_modules/css-tree/lib/lexer/grammar/walk.js
generated
vendored
Normal file
31
build/node_modules/css-tree/lib/lexer/grammar/walk.js
generated
vendored
Normal file
@@ -0,0 +1,31 @@
|
||||
'use strict';
|
||||
|
||||
module.exports = function walk(node, fn, context) {
|
||||
switch (node.type) {
|
||||
case 'Group':
|
||||
node.terms.forEach(function(term) {
|
||||
walk(term, fn, context);
|
||||
});
|
||||
break;
|
||||
|
||||
case 'Function':
|
||||
case 'Parentheses':
|
||||
walk(node.children, fn, context);
|
||||
break;
|
||||
|
||||
case 'Keyword':
|
||||
case 'Type':
|
||||
case 'Property':
|
||||
case 'Combinator':
|
||||
case 'Comma':
|
||||
case 'Slash':
|
||||
case 'String':
|
||||
case 'Percent':
|
||||
break;
|
||||
|
||||
default:
|
||||
throw new Error('Unknown type: ' + node.type);
|
||||
}
|
||||
|
||||
fn.call(context, node);
|
||||
};
|
||||
6
build/node_modules/css-tree/lib/lexer/index.js
generated
vendored
Normal file
6
build/node_modules/css-tree/lib/lexer/index.js
generated
vendored
Normal file
@@ -0,0 +1,6 @@
|
||||
'use strict';
|
||||
|
||||
module.exports = {
|
||||
Lexer: require('./Lexer'),
|
||||
grammar: require('./grammar')
|
||||
};
|
||||
515
build/node_modules/css-tree/lib/lexer/match.js
generated
vendored
Normal file
515
build/node_modules/css-tree/lib/lexer/match.js
generated
vendored
Normal file
@@ -0,0 +1,515 @@
|
||||
'use strict';
|
||||
|
||||
var names = require('../utils/names');
|
||||
var MULTIPLIER_DEFAULT = {
|
||||
comma: false,
|
||||
min: 1,
|
||||
max: 1
|
||||
};
|
||||
|
||||
function skipSpaces(node) {
|
||||
while (node !== null && (node.data.type === 'WhiteSpace' || node.data.type === 'Comment')) {
|
||||
node = node.next;
|
||||
}
|
||||
|
||||
return node;
|
||||
}
|
||||
|
||||
function putResult(buffer, match) {
|
||||
var type = match.type || match.syntax.type;
|
||||
|
||||
// ignore groups
|
||||
if (type === 'Group') {
|
||||
buffer.push.apply(buffer, match.match);
|
||||
} else {
|
||||
buffer.push(match);
|
||||
}
|
||||
}
|
||||
|
||||
function matchToJSON() {
|
||||
return {
|
||||
type: this.syntax.type,
|
||||
name: this.syntax.name,
|
||||
match: this.match,
|
||||
node: this.node
|
||||
};
|
||||
}
|
||||
|
||||
function buildMatchNode(badNode, lastNode, next, match) {
|
||||
if (badNode) {
|
||||
return {
|
||||
badNode: badNode,
|
||||
lastNode: null,
|
||||
next: null,
|
||||
match: null
|
||||
};
|
||||
}
|
||||
|
||||
return {
|
||||
badNode: null,
|
||||
lastNode: lastNode,
|
||||
next: next,
|
||||
match: match
|
||||
};
|
||||
}
|
||||
|
||||
function matchGroup(lexer, syntaxNode, node) {
|
||||
var result = [];
|
||||
var buffer;
|
||||
var multiplier = syntaxNode.multiplier || MULTIPLIER_DEFAULT;
|
||||
var min = multiplier.min;
|
||||
var max = multiplier.max === 0 ? Infinity : multiplier.max;
|
||||
var lastCommaTermCount;
|
||||
var lastComma;
|
||||
var matchCount = 0;
|
||||
var lastNode = null;
|
||||
var badNode = null;
|
||||
|
||||
mismatch:
|
||||
while (matchCount < max) {
|
||||
node = skipSpaces(node);
|
||||
buffer = [];
|
||||
|
||||
switch (syntaxNode.combinator) {
|
||||
case '|':
|
||||
for (var i = 0; i < syntaxNode.terms.length; i++) {
|
||||
var term = syntaxNode.terms[i];
|
||||
var res = matchSyntax(lexer, term, node);
|
||||
|
||||
if (res.match) {
|
||||
putResult(buffer, res.match);
|
||||
node = res.next;
|
||||
break; // continue matching
|
||||
} else if (res.badNode) {
|
||||
badNode = res.badNode;
|
||||
break mismatch;
|
||||
} else if (res.lastNode) {
|
||||
lastNode = res.lastNode;
|
||||
}
|
||||
}
|
||||
|
||||
if (buffer.length === 0) {
|
||||
break mismatch; // nothing found -> stop matching
|
||||
}
|
||||
|
||||
break;
|
||||
|
||||
case ' ':
|
||||
var beforeMatchNode = node;
|
||||
var lastMatchedTerm = null;
|
||||
var hasTailMatch = false;
|
||||
var commaMissed = false;
|
||||
|
||||
for (var i = 0; i < syntaxNode.terms.length; i++) {
|
||||
var term = syntaxNode.terms[i];
|
||||
var res = matchSyntax(lexer, term, node);
|
||||
|
||||
if (res.match) {
|
||||
if (term.type === 'Comma' && i !== 0 && !hasTailMatch) {
|
||||
// recover cursor to state before last match and stop matching
|
||||
lastNode = node && node.data;
|
||||
node = beforeMatchNode;
|
||||
break mismatch;
|
||||
}
|
||||
|
||||
// non-empty match (res.next will refer to another node)
|
||||
if (res.next !== node) {
|
||||
// match should be preceded by a comma
|
||||
if (commaMissed) {
|
||||
lastNode = node && node.data;
|
||||
node = beforeMatchNode;
|
||||
break mismatch;
|
||||
}
|
||||
|
||||
hasTailMatch = term.type !== 'Comma';
|
||||
lastMatchedTerm = term;
|
||||
}
|
||||
|
||||
putResult(buffer, res.match);
|
||||
node = skipSpaces(res.next);
|
||||
} else if (res.badNode) {
|
||||
badNode = res.badNode;
|
||||
break mismatch;
|
||||
} else {
|
||||
if (res.lastNode) {
|
||||
lastNode = res.lastNode;
|
||||
}
|
||||
|
||||
// it's ok when comma doesn't match when no matches yet
|
||||
// but only if comma is not first or last term
|
||||
if (term.type === 'Comma' && i !== 0 && i !== syntaxNode.terms.length - 1) {
|
||||
if (hasTailMatch) {
|
||||
commaMissed = true;
|
||||
}
|
||||
continue;
|
||||
}
|
||||
|
||||
// recover cursor to state before last match and stop matching
|
||||
lastNode = res.lastNode || (node && node.data);
|
||||
node = beforeMatchNode;
|
||||
break mismatch;
|
||||
}
|
||||
}
|
||||
|
||||
// don't allow empty match when [ ]!
|
||||
if (!lastMatchedTerm && syntaxNode.disallowEmpty) {
|
||||
// empty match but shouldn't
|
||||
// recover cursor to state before last match and stop matching
|
||||
lastNode = node && node.data;
|
||||
node = beforeMatchNode;
|
||||
break mismatch;
|
||||
}
|
||||
|
||||
// don't allow comma at the end but only if last term isn't a comma
|
||||
if (lastMatchedTerm && lastMatchedTerm.type === 'Comma' && term.type !== 'Comma') {
|
||||
lastNode = node && node.data;
|
||||
node = beforeMatchNode;
|
||||
break mismatch;
|
||||
}
|
||||
|
||||
break;
|
||||
|
||||
case '&&':
|
||||
var beforeMatchNode = node;
|
||||
var lastMatchedTerm = null;
|
||||
var terms = syntaxNode.terms.slice();
|
||||
|
||||
while (terms.length) {
|
||||
var wasMatch = false;
|
||||
var emptyMatched = 0;
|
||||
|
||||
for (var i = 0; i < terms.length; i++) {
|
||||
var term = terms[i];
|
||||
var res = matchSyntax(lexer, term, node);
|
||||
|
||||
if (res.match) {
|
||||
// non-empty match (res.next will refer to another node)
|
||||
if (res.next !== node) {
|
||||
lastMatchedTerm = term;
|
||||
} else {
|
||||
emptyMatched++;
|
||||
continue;
|
||||
}
|
||||
|
||||
wasMatch = true;
|
||||
terms.splice(i--, 1);
|
||||
putResult(buffer, res.match);
|
||||
node = skipSpaces(res.next);
|
||||
break;
|
||||
} else if (res.badNode) {
|
||||
badNode = res.badNode;
|
||||
break mismatch;
|
||||
} else if (res.lastNode) {
|
||||
lastNode = res.lastNode;
|
||||
}
|
||||
}
|
||||
|
||||
if (!wasMatch) {
|
||||
// terms left, but they all are optional
|
||||
if (emptyMatched === terms.length) {
|
||||
break;
|
||||
}
|
||||
|
||||
// not ok
|
||||
lastNode = node && node.data;
|
||||
node = beforeMatchNode;
|
||||
break mismatch;
|
||||
}
|
||||
}
|
||||
|
||||
if (!lastMatchedTerm && syntaxNode.disallowEmpty) { // don't allow empty match when [ ]!
|
||||
// empty match but shouldn't
|
||||
// recover cursor to state before last match and stop matching
|
||||
lastNode = node && node.data;
|
||||
node = beforeMatchNode;
|
||||
break mismatch;
|
||||
}
|
||||
|
||||
break;
|
||||
|
||||
case '||':
|
||||
var beforeMatchNode = node;
|
||||
var lastMatchedTerm = null;
|
||||
var terms = syntaxNode.terms.slice();
|
||||
|
||||
while (terms.length) {
|
||||
var wasMatch = false;
|
||||
var emptyMatched = 0;
|
||||
|
||||
for (var i = 0; i < terms.length; i++) {
|
||||
var term = terms[i];
|
||||
var res = matchSyntax(lexer, term, node);
|
||||
|
||||
if (res.match) {
|
||||
// non-empty match (res.next will refer to another node)
|
||||
if (res.next !== node) {
|
||||
lastMatchedTerm = term;
|
||||
} else {
|
||||
emptyMatched++;
|
||||
continue;
|
||||
}
|
||||
|
||||
wasMatch = true;
|
||||
terms.splice(i--, 1);
|
||||
putResult(buffer, res.match);
|
||||
node = skipSpaces(res.next);
|
||||
break;
|
||||
} else if (res.badNode) {
|
||||
badNode = res.badNode;
|
||||
break mismatch;
|
||||
} else if (res.lastNode) {
|
||||
lastNode = res.lastNode;
|
||||
}
|
||||
}
|
||||
|
||||
if (!wasMatch) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// don't allow empty match
|
||||
if (!lastMatchedTerm && (emptyMatched !== terms.length || syntaxNode.disallowEmpty)) {
|
||||
// empty match but shouldn't
|
||||
// recover cursor to state before last match and stop matching
|
||||
lastNode = node && node.data;
|
||||
node = beforeMatchNode;
|
||||
break mismatch;
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
// flush buffer
|
||||
result.push.apply(result, buffer);
|
||||
matchCount++;
|
||||
|
||||
if (!node) {
|
||||
break;
|
||||
}
|
||||
|
||||
if (multiplier.comma) {
|
||||
if (lastComma && lastCommaTermCount === result.length) {
|
||||
// nothing match after comma
|
||||
break mismatch;
|
||||
}
|
||||
|
||||
node = skipSpaces(node);
|
||||
if (node !== null && node.data.type === 'Operator' && node.data.value === ',') {
|
||||
result.push({
|
||||
syntax: syntaxNode,
|
||||
match: [{
|
||||
type: 'ASTNode',
|
||||
node: node.data,
|
||||
childrenMatch: null
|
||||
}]
|
||||
});
|
||||
lastCommaTermCount = result.length;
|
||||
lastComma = node;
|
||||
node = node.next;
|
||||
} else {
|
||||
lastNode = node !== null ? node.data : null;
|
||||
break mismatch;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// console.log(syntaxNode.type, badNode, lastNode);
|
||||
|
||||
if (lastComma && lastCommaTermCount === result.length) {
|
||||
// nothing match after comma
|
||||
node = lastComma;
|
||||
result.pop();
|
||||
}
|
||||
|
||||
return buildMatchNode(badNode, lastNode, node, matchCount < min ? null : {
|
||||
syntax: syntaxNode,
|
||||
match: result,
|
||||
toJSON: matchToJSON
|
||||
});
|
||||
}
|
||||
|
||||
function matchSyntax(lexer, syntaxNode, node) {
|
||||
var badNode = null;
|
||||
var lastNode = null;
|
||||
var match = null;
|
||||
|
||||
switch (syntaxNode.type) {
|
||||
case 'Group':
|
||||
return matchGroup(lexer, syntaxNode, node);
|
||||
|
||||
case 'Function':
|
||||
// expect a function node
|
||||
if (!node || node.data.type !== 'Function') {
|
||||
break;
|
||||
}
|
||||
|
||||
var keyword = names.keyword(node.data.name);
|
||||
var name = syntaxNode.name.toLowerCase();
|
||||
|
||||
// check function name with vendor consideration
|
||||
if (name !== keyword.vendor + keyword.name) {
|
||||
break;
|
||||
}
|
||||
|
||||
var res = matchSyntax(lexer, syntaxNode.children, node.data.children.head);
|
||||
if (!res.match || res.next) {
|
||||
badNode = res.badNode || res.lastNode || (res.next ? res.next.data : null) || node.data;
|
||||
break;
|
||||
}
|
||||
|
||||
match = [{
|
||||
type: 'ASTNode',
|
||||
node: node.data,
|
||||
childrenMatch: res.match.match
|
||||
}];
|
||||
|
||||
// Use node.next instead of res.next here since syntax is matching
|
||||
// for internal list and it should be completelly matched (res.next is null at this point).
|
||||
// Therefore function is matched and we are going to next node
|
||||
node = node.next;
|
||||
break;
|
||||
|
||||
case 'Parentheses':
|
||||
if (!node || node.data.type !== 'Parentheses') {
|
||||
break;
|
||||
}
|
||||
|
||||
var res = matchSyntax(lexer, syntaxNode.children, node.data.children.head);
|
||||
if (!res.match || res.next) {
|
||||
badNode = res.badNode || res.lastNode || (res.next ? res.next.data : null) || node.data; // TODO: case when res.next === null
|
||||
break;
|
||||
}
|
||||
|
||||
match = [{
|
||||
type: 'ASTNode',
|
||||
node: node.data,
|
||||
childrenMatch: res.match.match
|
||||
}];
|
||||
|
||||
node = res.next;
|
||||
break;
|
||||
|
||||
case 'Type':
|
||||
var typeSyntax = lexer.getType(syntaxNode.name);
|
||||
if (!typeSyntax) {
|
||||
throw new Error('Unknown syntax type `' + syntaxNode.name + '`');
|
||||
}
|
||||
|
||||
var res = typeSyntax.match(node);
|
||||
if (!res.match) {
|
||||
badNode = res && res.badNode; // TODO: case when res.next === null
|
||||
lastNode = (res && res.lastNode) || (node && node.data);
|
||||
break;
|
||||
}
|
||||
|
||||
node = res.next;
|
||||
putResult(match = [], res.match);
|
||||
if (match.length === 0) {
|
||||
match = null;
|
||||
}
|
||||
break;
|
||||
|
||||
case 'Property':
|
||||
var propertySyntax = lexer.getProperty(syntaxNode.name);
|
||||
if (!propertySyntax) {
|
||||
throw new Error('Unknown property `' + syntaxNode.name + '`');
|
||||
}
|
||||
|
||||
var res = propertySyntax.match(node);
|
||||
if (!res.match) {
|
||||
badNode = res && res.badNode; // TODO: case when res.next === null
|
||||
lastNode = (res && res.lastNode) || (node && node.data);
|
||||
break;
|
||||
}
|
||||
|
||||
node = res.next;
|
||||
putResult(match = [], res.match);
|
||||
if (match.length === 0) {
|
||||
match = null;
|
||||
}
|
||||
break;
|
||||
|
||||
case 'Keyword':
|
||||
if (!node) {
|
||||
break;
|
||||
}
|
||||
|
||||
if (node.data.type === 'Identifier') {
|
||||
var keyword = names.keyword(node.data.name);
|
||||
var keywordName = keyword.name;
|
||||
var name = syntaxNode.name.toLowerCase();
|
||||
|
||||
// drop \0 and \9 hack from keyword name
|
||||
if (keywordName.indexOf('\\') !== -1) {
|
||||
keywordName = keywordName.replace(/\\[09].*$/, '');
|
||||
}
|
||||
|
||||
if (name !== keyword.vendor + keywordName) {
|
||||
break;
|
||||
}
|
||||
} else {
|
||||
// keyword may to be a number (e.g. font-weight: 400 )
|
||||
if (node.data.type !== 'Number' || node.data.value !== syntaxNode.name) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
match = [{
|
||||
type: 'ASTNode',
|
||||
node: node.data,
|
||||
childrenMatch: null
|
||||
}];
|
||||
node = node.next;
|
||||
break;
|
||||
|
||||
case 'Slash':
|
||||
case 'Comma':
|
||||
if (!node || node.data.type !== 'Operator' || node.data.value !== syntaxNode.value) {
|
||||
break;
|
||||
}
|
||||
|
||||
match = [{
|
||||
type: 'ASTNode',
|
||||
node: node.data,
|
||||
childrenMatch: null
|
||||
}];
|
||||
node = node.next;
|
||||
break;
|
||||
|
||||
case 'String':
|
||||
if (!node || node.data.type !== 'String') {
|
||||
break;
|
||||
}
|
||||
|
||||
match = [{
|
||||
type: 'ASTNode',
|
||||
node: node.data,
|
||||
childrenMatch: null
|
||||
}];
|
||||
node = node.next;
|
||||
break;
|
||||
|
||||
case 'ASTNode':
|
||||
if (node && syntaxNode.match(node)) {
|
||||
match = {
|
||||
type: 'ASTNode',
|
||||
node: node.data,
|
||||
childrenMatch: null
|
||||
};
|
||||
node = node.next;
|
||||
}
|
||||
return buildMatchNode(badNode, lastNode, node, match);
|
||||
|
||||
default:
|
||||
throw new Error('Not implemented yet node type: ' + syntaxNode.type);
|
||||
}
|
||||
|
||||
return buildMatchNode(badNode, lastNode, node, match === null ? null : {
|
||||
syntax: syntaxNode,
|
||||
match: match,
|
||||
toJSON: matchToJSON
|
||||
});
|
||||
|
||||
};
|
||||
|
||||
module.exports = matchSyntax;
|
||||
84
build/node_modules/css-tree/lib/lexer/search.js
generated
vendored
Normal file
84
build/node_modules/css-tree/lib/lexer/search.js
generated
vendored
Normal file
@@ -0,0 +1,84 @@
|
||||
var List = require('../utils/list');
|
||||
|
||||
function getFirstMatchNode(matchNode) {
|
||||
if (matchNode.type === 'ASTNode') {
|
||||
return matchNode.node;
|
||||
}
|
||||
|
||||
if (matchNode.match.length !== 0) {
|
||||
return getFirstMatchNode(matchNode.match[0]);
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
function getLastMatchNode(matchNode) {
|
||||
if (matchNode.type === 'ASTNode') {
|
||||
return matchNode.node;
|
||||
}
|
||||
|
||||
if (matchNode.match.length !== 0) {
|
||||
return getLastMatchNode(matchNode.match[matchNode.match.length - 1]);
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
function matchFragments(lexer, ast, match, type, name) {
|
||||
function findFragments(matchNode) {
|
||||
if (matchNode.type === 'ASTNode') {
|
||||
return;
|
||||
}
|
||||
|
||||
if (matchNode.syntax.type === type &&
|
||||
matchNode.syntax.name === name) {
|
||||
var start = getFirstMatchNode(matchNode);
|
||||
var end = getLastMatchNode(matchNode);
|
||||
|
||||
lexer.syntax.walk(ast, function(node, item, list) {
|
||||
if (node === start) {
|
||||
var nodes = new List();
|
||||
var loc = null;
|
||||
|
||||
do {
|
||||
nodes.appendData(item.data);
|
||||
|
||||
if (item.data === end) {
|
||||
break;
|
||||
}
|
||||
|
||||
item = item.next;
|
||||
} while (item !== null);
|
||||
|
||||
if (start.loc !== null && end.loc !== null) {
|
||||
loc = {
|
||||
source: start.loc.source,
|
||||
start: start.loc.start,
|
||||
end: end.loc.end
|
||||
};
|
||||
}
|
||||
|
||||
fragments.push({
|
||||
parent: list,
|
||||
loc: loc,
|
||||
nodes: nodes
|
||||
});
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
matchNode.match.forEach(findFragments);
|
||||
}
|
||||
|
||||
var fragments = [];
|
||||
|
||||
if (match.matched !== null) {
|
||||
findFragments(match.matched);
|
||||
}
|
||||
|
||||
return fragments;
|
||||
}
|
||||
|
||||
module.exports = {
|
||||
matchFragments: matchFragments
|
||||
};
|
||||
163
build/node_modules/css-tree/lib/lexer/structure.js
generated
vendored
Normal file
163
build/node_modules/css-tree/lib/lexer/structure.js
generated
vendored
Normal file
@@ -0,0 +1,163 @@
|
||||
var List = require('../utils/list');
|
||||
var hasOwnProperty = Object.prototype.hasOwnProperty;
|
||||
|
||||
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 (var key in node) {
|
||||
var 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)) {
|
||||
for (var i = 0, valid = false; !valid && i < fields[key].length; i++) {
|
||||
var 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;
|
||||
}
|
||||
}
|
||||
}
|
||||
} else {
|
||||
warn(node, 'Unknown field `' + key + '` for ' + type + ' node type');
|
||||
}
|
||||
|
||||
if (!valid) {
|
||||
warn(node, 'Bad value for `' + type + '.' + key + '`');
|
||||
}
|
||||
}
|
||||
|
||||
for (var key in fields) {
|
||||
if (hasOwnProperty.call(fields, key) &&
|
||||
hasOwnProperty.call(node, key) === false) {
|
||||
warn(node, 'Field `' + type + '.' + key + '` is missed');
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
function processStructure(name, nodeType) {
|
||||
var structure = nodeType.structure;
|
||||
var fields = {
|
||||
type: String,
|
||||
loc: true
|
||||
};
|
||||
var docs = {
|
||||
type: '"' + name + '"'
|
||||
};
|
||||
|
||||
for (var key in structure) {
|
||||
if (hasOwnProperty.call(structure, key) === false) {
|
||||
continue;
|
||||
}
|
||||
|
||||
var docsTypes = [];
|
||||
var fieldTypes = fields[key] = Array.isArray(structure[key])
|
||||
? structure[key].slice()
|
||||
: [structure[key]];
|
||||
|
||||
for (var i = 0; i < fieldTypes.length; i++) {
|
||||
var 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: docs,
|
||||
check: createNodeStructureChecker(name, fields)
|
||||
};
|
||||
}
|
||||
|
||||
module.exports = {
|
||||
getStructureFromConfig: function(config) {
|
||||
var structure = {};
|
||||
|
||||
if (config.node) {
|
||||
for (var name in config.node) {
|
||||
if (hasOwnProperty.call(config.node, name)) {
|
||||
var 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;
|
||||
}
|
||||
};
|
||||
76
build/node_modules/css-tree/lib/lexer/trace.js
generated
vendored
Normal file
76
build/node_modules/css-tree/lib/lexer/trace.js
generated
vendored
Normal file
@@ -0,0 +1,76 @@
|
||||
function getTrace(node) {
|
||||
function hasMatch(matchNode) {
|
||||
if (matchNode.type === 'ASTNode') {
|
||||
if (matchNode.node === node) {
|
||||
result = [];
|
||||
return true;
|
||||
}
|
||||
|
||||
if (matchNode.childrenMatch) {
|
||||
// use for-loop for better perfomance
|
||||
for (var i = 0; i < matchNode.childrenMatch.length; i++) {
|
||||
if (hasMatch(matchNode.childrenMatch[i])) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
} else {
|
||||
// use for-loop for better perfomance
|
||||
for (var i = 0; i < matchNode.match.length; i++) {
|
||||
if (hasMatch(matchNode.match[i])) {
|
||||
if (matchNode.syntax.type === 'Type' ||
|
||||
matchNode.syntax.type === 'Property' ||
|
||||
matchNode.syntax.type === 'Keyword') {
|
||||
result.unshift(matchNode.syntax);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
var result = null;
|
||||
|
||||
if (this.matched !== null) {
|
||||
hasMatch(this.matched);
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
function testNode(match, node, fn) {
|
||||
var trace = getTrace.call(match, node);
|
||||
|
||||
if (trace === null) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return trace.some(fn);
|
||||
}
|
||||
|
||||
function isType(node, type) {
|
||||
return testNode(this, node, function(matchNode) {
|
||||
return matchNode.type === 'Type' && matchNode.name === type;
|
||||
});
|
||||
}
|
||||
|
||||
function isProperty(node, property) {
|
||||
return testNode(this, node, function(matchNode) {
|
||||
return matchNode.type === 'Property' && matchNode.name === property;
|
||||
});
|
||||
}
|
||||
|
||||
function isKeyword(node) {
|
||||
return testNode(this, node, function(matchNode) {
|
||||
return matchNode.type === 'Keyword';
|
||||
});
|
||||
}
|
||||
|
||||
module.exports = {
|
||||
getTrace: getTrace,
|
||||
isType: isType,
|
||||
isProperty: isProperty,
|
||||
isKeyword: isKeyword
|
||||
};
|
||||
Reference in New Issue
Block a user