Socket
Socket
Sign inDemoInstall

css-tree

Package Overview
Dependencies
1
Maintainers
1
Versions
55
Alerts
File Explorer

Advanced tools

Install Socket

Detect and block malicious and high-risk dependencies

Install

Comparing version 1.0.0-alpha7 to 1.0.0-alpha8

data/mdn-data-properties.json

28

data/index.js

@@ -1,2 +0,3 @@

var mozilla = require('./mozilla-cssdata.json');
var mdnProperties = require('./mdn-data-properties.json');
var mdnSyntaxes = require('./mdn-data-syntaxes.json');
var patch = require('./patch.json');

@@ -12,2 +13,3 @@ var data = {

.replace(/>/g, '>')
.replace(/ /g, ' ')
.replace(/&/g, '&');

@@ -18,6 +20,10 @@ }

for (var key in patch.properties) {
if (key in mozilla.properties) {
mozilla.properties[key].syntax = patch.properties[key].syntax;
if (key in mdnProperties) {
if (patch.properties[key]) {
mdnProperties[key].syntax = patch.properties[key].syntax;
} else {
delete mdnProperties[key];
}
} else {
mozilla.properties[key] = patch.properties[key];
mdnProperties[key] = patch.properties[key];
}

@@ -28,17 +34,17 @@ }

if (patch.syntaxes[key].syntax) {
mozilla.syntaxes[key] = patch.syntaxes[key].syntax;
mdnSyntaxes[key] = patch.syntaxes[key].syntax;
} else {
delete mozilla.syntaxes[key];
delete mdnSyntaxes[key];
}
}
// normalize source mozilla syntaxes, since it uses html token
for (var key in mozilla.properties) {
data.properties[key] = normalizeSyntax(mozilla.properties[key].syntax);
// normalize source mdnProperties syntaxes, since it uses html token
for (var key in mdnProperties) {
data.properties[key] = normalizeSyntax(mdnProperties[key].syntax);
}
for (var key in mozilla.syntaxes) {
data.types[key] = normalizeSyntax(mozilla.syntaxes[key]);
for (var key in mdnSyntaxes) {
data.types[key] = normalizeSyntax(mdnSyntaxes[key]);
}
module.exports = data;
{
"properties": {
"--*": null,
"-moz-background-clip": {

@@ -122,9 +123,5 @@ "comment": "deprecated syntax in old Firefox, https://developer.mozilla.org/en/docs/Web/CSS/background-clip",

},
"-webkit-mask-attachment": {
"comment": "extra space between [ and ,",
"syntax": "<attachment> [, <attachment> ]*"
},
"-webkit-mask-box-image": {
"comment": "missed; https://developer.mozilla.org/en-US/docs/Web/CSS/-webkit-mask-box-image",
"syntax": "[ <uri> | <gradient> | none ] [ <length-percentage>{4} <-webkit-mask-box-repeat>{2} ]?"
"syntax": "[ <url> | <gradient> | none ] [ <length-percentage>{4} <-webkit-mask-box-repeat>{2} ]?"
},

@@ -135,26 +132,2 @@ "-webkit-mask-clip": {

},
"-webkit-mask-composite": {
"comment": "extra space between [ and ,",
"syntax": "&lt;composite-style&gt; [, &lt;composite-style&gt; ]*"
},
"-webkit-mask-image": {
"comment": "extra space between [ and ,",
"syntax": "&lt;mask-image&gt; [, &lt;mask-image&gt; ]*"
},
"-webkit-mask-origin": {
"comment": "missed spaces between brackets, extra space between [ and ,",
"syntax": "[ padding | border | content ] [, [ border | padding | content ] ]*"
},
"-webkit-mask-position": {
"comment": "# instead of *, extra space between [ and ,",
"syntax": "&lt;mask-position&gt; [, &lt;mask-position&gt; ]*"
},
"-webkit-mask-position-y": {
"comment": "extra space after `top`",
"syntax": "[ &lt;length-percentage&gt; | top | center | bottom ]#"
},
"-webkit-mask-repeat": {
"comment": "extra space between [ and ,",
"syntax": "&lt;repeat-style&gt; [, &lt;repeat-style&gt; ]*"
},
"-webkit-overflow-scrolling": {

@@ -171,6 +144,2 @@ "comment": "missed; https://developer.mozilla.org/en-US/docs/Web/CSS/-webkit-overflow-scrolling",

},
"-webkit-tap-highlight-color": {
"comment": "broken syntax",
"syntax": "&lt;color&gt;#"
},
"-webkit-text-security": {

@@ -195,25 +164,2 @@ "comment": "missed; http://help.dottoro.com/lcbkewgt.php",

},
"animation-timing-function": {
"comment": "<timing-function> -> <single-timing-function> https://drafts.csswg.org/css-animations/#animation-timing-function",
"syntax": "<single-timing-function>#"
},
"appearance": {
"comment": "CSS Basic User Interface Module Level 4",
"references": [
"https://drafts.csswg.org/css-ui-4/#appearance-switching"
],
"syntax": "auto | none"
},
"azimuth": {
"comment": "missed space",
"syntax": "&lt;angle&gt; | [ [ left-side | far-left | left | center-left | center | center-right | right | far-right | right-side ] || behind ] | leftwards | rightwards"
},
"background-position-x": {
"comment": "added missed multiplicator `?` https://drafts.csswg.org/css-backgrounds-4/#background-position-longhands",
"syntax": "[ center | [ left | right | x-start | x-end ]? &lt;length-percentage&gt;? ]#"
},
"background-position-y": {
"comment": "added missed multiplicator `?` https://drafts.csswg.org/css-backgrounds-4/#background-position-longhands",
"syntax": "[ center | [ top | bottom | y-start | y-end ]? &lt;length-percentage&gt;? ]#"
},
"baseline-shift": {

@@ -247,7 +193,7 @@ "comment": "added SVG property",

"comment": "https://www.w3.org/TR/css3-speech/#property-index",
"syntax": "<uri> <decibel>? | none"
"syntax": "<url> <decibel>? | none"
},
"cue-before": {
"comment": "https://www.w3.org/TR/css3-speech/#property-index",
"syntax": "<uri> <decibel>? | none"
"syntax": "<url> <decibel>? | none"
},

@@ -257,3 +203,3 @@ "cursor": {

"refenrences": ["https://www.sitepoint.com/css3-cursor-styles/"],
"syntax": "[ [ &lt;uri&gt; [ &lt;x&gt; &lt;y&gt; ]? , ]* [ auto | default | none | context-menu | help | pointer | progress | wait | cell | crosshair | text | vertical-text | alias | copy | move | no-drop | not-allowed | e-resize | n-resize | ne-resize | nw-resize | s-resize | se-resize | sw-resize | w-resize | ew-resize | ns-resize | nesw-resize | nwse-resize | col-resize | row-resize | all-scroll | zoom-in | zoom-out | grab | grabbing | hand | -webkit-grab | -webkit-grabbing | -webkit-zoom-in | -webkit-zoom-out | -moz-grab | -moz-grabbing | -moz-zoom-in | -moz-zoom-out ] ]"
"syntax": "[ [ &lt;url&gt; [ &lt;x&gt; &lt;y&gt; ]? , ]* [ auto | default | none | context-menu | help | pointer | progress | wait | cell | crosshair | text | vertical-text | alias | copy | move | no-drop | not-allowed | e-resize | n-resize | ne-resize | nw-resize | s-resize | se-resize | sw-resize | w-resize | ew-resize | ns-resize | nesw-resize | nwse-resize | col-resize | row-resize | all-scroll | zoom-in | zoom-out | grab | grabbing | hand | -webkit-grab | -webkit-grabbing | -webkit-zoom-in | -webkit-zoom-out | -moz-grab | -moz-grabbing | -moz-zoom-in | -moz-zoom-out ] ]"
},

@@ -305,17 +251,5 @@ "display": {

"font": {
"comment": "wrong quotes",
"comment": "extend with non-standart fonts",
"syntax": "[ [ &lt;'font-style'&gt; || &lt;font-variant-css21&gt; || &lt;'font-weight'&gt; || &lt;'font-stretch'&gt; ]? &lt;'font-size'&gt; [ / &lt;'line-height'&gt; ]? &lt;'font-family'&gt; ] | caption | icon | menu | message-box | small-caption | status-bar | <-non-standart-font>"
},
"font-variant": {
"comment": "# should stick to term, missed spaces for function body, trailing space",
"syntax": "normal | none | [ &lt;common-lig-values&gt; || &lt;discretionary-lig-values&gt; || &lt;historical-lig-values&gt; || &lt;contextual-alt-values&gt; || stylistic( &lt;feature-value-name&gt; ) || historical-forms || styleset( &lt;feature-value-name&gt;# ) || character-variant( &lt;feature-value-name&gt;# ) || swash( &lt;feature-value-name&gt; ) || ornaments( &lt;feature-value-name&gt; ) || annotation( &lt;feature-value-name&gt; ) || [ small-caps | all-small-caps | petite-caps | all-petite-caps | unicase | titling-caps ] || &lt;numeric-figure-values&gt; || &lt;numeric-spacing-values&gt; || &lt;numeric-fraction-values&gt; || ordinal || slashed-zero || &lt;east-asian-variant-values&gt; || &lt;east-asian-width-values&gt; || ruby ]"
},
"font-variant-alternates": {
"comment": "# should stick to term, missed spaces for function body, trailing space",
"syntax": "normal | [ stylistic( &lt;feature-value-name&gt; ) || historical-forms || styleset( &lt;feature-value-name&gt;# ) || character-variant( &lt;feature-value-name&gt;# ) || swash( &lt;feature-value-name&gt; ) || ornaments( &lt;feature-value-name&gt; ) || annotation( &lt;feature-value-name&gt; ) ]"
},
"font-variant-east-asian": {
"comment": "trailing space",
"syntax": "normal | [ &lt;east-asian-variant-values&gt; || &lt;east-asian-width-values&gt; || ruby ]"
},
"glyph-orientation-horizontal": {

@@ -344,2 +278,5 @@ "comment": "added SVG property",

"comment": "fix syntax <length> -> <length-percentage>",
"references": [
"https://developer.mozilla.org/en-US/docs/Web/SVG/Attribute/letter-spacing"
],
"syntax": "normal | &lt;length-percentage&gt;"

@@ -411,10 +348,2 @@ },

},
"scroll-snap-points-x": {
"comment": "missed spaces in function body",
"syntax": "none | repeat( &lt;length&gt; )"
},
"scroll-snap-points-y": {
"comment": "missed spaces in function body",
"syntax": "none | repeat( &lt;length&gt; )"
},
"shape-rendering": {

@@ -502,18 +431,2 @@ "comment": "added SVG property",

},
"text-emphasis-style": {
"comment": "missed between brackets",
"syntax": "none | [ [ filled | open ] || [ dot | circle | double-circle | triangle | sesame ] ] | &lt;string&gt;"
},
"text-indent": {
"comment": "wrong syntax, replaced for https://drafts.csswg.org/css-text-3/#text-indent-property",
"syntax": "[ <length-percentage> ] && hanging? && each-line?"
},
"text-size-adjust": {
"comment": "trailing space",
"syntax": "none | auto | &lt;percentage&gt;"
},
"touch-action": {
"comment": "missed between brackets",
"syntax": "auto | none | [ [ pan-x | pan-left | pan-right ] || [ pan-y | pan-up | pan-down ] ] | manipulation"
},
"transform-origin": {

@@ -523,6 +436,2 @@ "comment": "move first group to the end since less collecting",

},
"transition-timing-function": {
"comment": "extra space in the beginning",
"syntax": "&lt;single-transition-timing-function&gt;#"
},
"unicode-bidi": {

@@ -684,6 +593,2 @@ "comment": "added prefixed keywords https://developer.mozilla.org/en-US/docs/Web/CSS/unicode-bidi",

},
"an-plus-b": {
"comment": "syntax is incorrect and can't be parsed, drop for now",
"syntax": null
},
"attr()": {

@@ -693,6 +598,2 @@ "comment": "drop it since it's a generic",

},
"blend-mode": {
"comment": "missed, https://drafts.fxtf.org/compositing-1/#ltblendmodegt",
"syntax": "normal | multiply | screen | overlay | darken | lighten | color-dodge | color-burn | hard-light | soft-light | difference | exclusion | hue | saturation | color | luminosity"
},
"border-radius": {

@@ -714,10 +615,2 @@ "comment": "missed, https://drafts.csswg.org/css-backgrounds-3/#the-border-radius",

},
"family-name": {
"comment": "upper case",
"syntax": "&lt;string&gt; | &lt;ident&gt;+"
},
"feature-value-name": {
"comment": "missed angle brackets",
"syntax": "<ident>"
},
"inset()": {

@@ -754,6 +647,2 @@ "comment": "changed <border-radius> to <'border-radius'>",

},
"mask-position": {
"comment": "extra space after `top`",
"syntax": "[ &lt;length-percentage&gt; | left | center | right ] [ &lt;length-percentage&gt; | top | center | bottom ]?"
},
"matrix()": {

@@ -775,6 +664,2 @@ "comment": "redundant max",

},
"namespace-prefix": {
"comment": "missed angle brackets",
"syntax": "<ident>"
},
"outline-radius": {

@@ -800,6 +685,2 @@ "comment": "missed, looks like it's a similar to <border-radius> https://developer.mozilla.org/en/docs/Web/CSS/-moz-outline-radius",

},
"scale3d()": {
"comment": "missed space before comma",
"syntax": "scale3d( &lt;number&gt; , &lt;number&gt; , &lt;number&gt; )"
},
"shape": {

@@ -809,6 +690,2 @@ "comment": "missed spaces in function body and add backwards compatible syntax",

},
"single-animation-name": {
"comment": "missed angle brackets",
"syntax": "none | <ident>"
},
"single-transition": {

@@ -818,10 +695,2 @@ "comment": "moved <single-transition-timing-function> in the beginning to avoid wrong match to <single-transition-property>",

},
"single-transition-property": {
"comment": "missed angle brackets",
"syntax": "all | <ident>"
},
"single-transition-timing-function": {
"comment": "missed spaces",
"syntax": "ease | linear | ease-in | ease-out | ease-in-out | step-start | step-end | steps( &lt;integer&gt; [, [ start | end ] ]? ) | cubic-bezier( &lt;number&gt;, &lt;number&gt;, &lt;number&gt;, &lt;number&gt; )"
},
"svg-length": {

@@ -846,6 +715,2 @@ "comment": "All coordinates and lengths in SVG can be specified with or without a unit identifier",

},
"uri": {
"comment": "deprecated, add alias to not change syntaxes",
"syntax": "<url>"
},
"quote": {

@@ -862,4 +727,121 @@ "comment": "missed -> https://drafts.csswg.org/css-content/#typedef-quote",

"syntax": "<number>"
},
"var()": {
"comment": "drop it since it's a generic (also syntax is incorrect and can't be parsed)",
"syntax": null
},
"an-plus-b": {
"comment": "syntax is incorrect and can't be parsed, drop for now",
"syntax": null
},
"feature-type": {
"comment": "syntax is incorrect and can't be parsed, drop for now",
"syntax": null
},
"feature-value-block": {
"comment": "syntax is incorrect and can't be parsed, drop for now",
"syntax": null
},
"feature-value-declaration": {
"comment": "syntax is incorrect and can't be parsed, drop for now",
"syntax": null
},
"feature-value-block-list": {
"comment": "syntax is incorrect and can't be parsed, drop for now",
"syntax": null
},
"feature-value-declaration-list": {
"comment": "syntax is incorrect and can't be parsed, drop for now",
"syntax": null
},
"general-enclosed": {
"comment": "syntax is incorrect and can't be parsed, drop for now",
"syntax": null
},
"keyframe-block": {
"comment": "syntax is incorrect and can't be parsed, drop for now",
"syntax": null
},
"keyframe-block-list": {
"comment": "syntax is incorrect and can't be parsed, drop for now",
"syntax": null
},
"mf-plain": {
"comment": "syntax is incorrect and can't be parsed, drop for now",
"syntax": null
},
"mf-range": {
"comment": "syntax is incorrect and can't be parsed, drop for now",
"syntax": null
},
"mf-value": {
"comment": "syntax is incorrect and can't be parsed, drop for now",
"syntax": null
},
"minmax()": {
"comment": "syntax is incorrect and can't be parsed, drop for now",
"syntax": null
},
"media-and": {
"comment": "syntax is incorrect and can't be parsed, drop for now",
"syntax": null
},
"media-condition": {
"comment": "syntax is incorrect and can't be parsed, drop for now",
"syntax": null
},
"media-not": {
"comment": "syntax is incorrect and can't be parsed, drop for now",
"syntax": null
},
"media-or": {
"comment": "syntax is incorrect and can't be parsed, drop for now",
"syntax": null
},
"media-in-parens": {
"comment": "syntax is incorrect and can't be parsed, drop for now",
"syntax": null
},
"media-feature": {
"comment": "syntax is incorrect and can't be parsed, drop for now",
"syntax": null
},
"media-condition-without-or": {
"comment": "syntax is incorrect and can't be parsed, drop for now",
"syntax": null
},
"media-query": {
"comment": "syntax is incorrect and can't be parsed, drop for now",
"syntax": null
},
"media-query-list": {
"comment": "syntax is incorrect and can't be parsed, drop for now",
"syntax": null
},
"page-selector": {
"comment": "syntax is incorrect and can't be parsed, drop for now",
"syntax": null
},
"page-selector-list": {
"comment": "syntax is incorrect and can't be parsed, drop for now",
"syntax": null
},
"page-body": {
"comment": "syntax is incorrect and can't be parsed, drop for now",
"syntax": null
},
"page-margin-box": {
"comment": "syntax is incorrect and can't be parsed, drop for now",
"syntax": null
},
"page-margin-box-type": {
"comment": "syntax is incorrect and can't be parsed, drop for now",
"syntax": null
},
"pseudo-page": {
"comment": "syntax is incorrect and can't be parsed, drop for now",
"syntax": null
}
}
}

@@ -0,1 +1,16 @@

## 1.0.0-alpha8 (November 11, 2016)
- Fixed `Scanner#skip()` issue method when cursor is moving to the end of source
- Simplified `Progid` node
- Changed behaviour for bad selector processing, now parsing fails instead of selector ignoring
- Fixed `<id-selector>` generic syntax
- Added `q` unit for `<length>` generic syntax
- Refactored syntax parser (performance)
- Reduced startup time by implementing lazy syntax parsing (default syntax doesn't parse on module load)
- Updated syntax dictionaries and used [`mdn/data`](https://github.com/mdn/data) instead of `Template:CSSData`
- Renamed `syntax.stringify()` method to `syntax.translate()`
- Simplified generic syntax functions, those functions receive a single AST node for checking and should return `true` or `false`
- Added exception for values that contains `var()`, those values are always valid for now
- Added more tests and increase code coverage to `98.5%`
## 1.0.0-alpha7 (October 7, 2016)

@@ -2,0 +17,0 @@

@@ -78,5 +78,8 @@ 'use strict';

function getInfo() {
function getInfo(start) {
if (needPositions) {
return scanner.getLocation(scanner.tokenStart, filename);
return scanner.getLocation(
start !== undefined ? start : scanner.tokenStart,
filename
);
}

@@ -88,9 +91,5 @@

function getStylesheet(nested) {
var start = scanner.tokenStart;
var rules = new List();
var child;
var node = {
type: 'StyleSheet',
info: getInfo(),
rules: rules
};

@@ -104,2 +103,9 @@ scan:

case RIGHTCURLYBRACKET:
if (!nested) {
scanner.error('Unexpected right curly brace');
}
break scan;
case COMMENT:

@@ -119,9 +125,2 @@ // ignore comments except exclamation comments (i.e. /*! .. */) on top level

case RIGHTCURLYBRACKET:
if (!nested) {
scanner.error('Unexpected right curly brace');
}
break scan;
default:

@@ -134,3 +133,7 @@ child = getRule();

return node;
return {
type: 'StyleSheet',
info: getInfo(start),
rules: rules
};
}

@@ -154,10 +157,6 @@

function getAtruleExpression() {
var start = scanner.tokenStart;
var sequence = new List();
var wasSpace = false;
var child;
var node = {
type: 'AtruleExpression',
info: getInfo(),
sequence: sequence
};

@@ -210,3 +209,7 @@ readSC();

return node;
return {
type: 'AtruleExpression',
info: getInfo(start),
sequence: sequence
};
}

@@ -225,3 +228,2 @@

// at-rule expression can ends with semicolon, left curly bracket or eof
switch (scanner.tokenType) {

@@ -241,2 +243,4 @@ case SEMICOLON:

break;
// at-rule expression can ends with semicolon, left curly bracket or eof - no other options
}

@@ -248,20 +252,21 @@

function getRule() {
return {
var node = {
type: 'Rule',
info: getInfo(),
selector: getSelector(),
block: getBlockWithBrackets()
block: null
};
scanner.eat(LEFTCURLYBRACKET);
node.block = getBlock();
scanner.eat(RIGHTCURLYBRACKET);
return node;
}
function getSelector() {
var start = scanner.tokenStart;
var selectors = new List();
var simpleSelector;
var isBadSelector = false;
var lastComma = true;
var node = {
type: 'Selector',
info: getInfo(),
selectors: selectors
};
var lastComma = -2;

@@ -275,7 +280,7 @@ scan:

case COMMA:
if (lastComma) {
isBadSelector = true;
if (lastComma !== -1) {
scanner.error('Unexpected comma');
}
lastComma = true;
lastComma = scanner.tokenStart;
scanner.next();

@@ -285,7 +290,3 @@ break;

default:
if (!lastComma) {
isBadSelector = true;
}
lastComma = false;
lastComma = -1;
simpleSelector = getSimpleSelector();

@@ -295,3 +296,3 @@ selectors.appendData(simpleSelector);

if (simpleSelector.sequence.isEmpty()) {
isBadSelector = true;
scanner.error('Simple selector expected');
}

@@ -301,15 +302,15 @@ }

if (lastComma) {
isBadSelector = true;
// scanner.error('Unexpected trailing comma');
if (lastComma !== -1 && lastComma !== -2) { // TODO: fail on empty selector rules?
scanner.error('Unexpected trailing comma', lastComma);
}
if (isBadSelector) {
selectors.clear();
}
return node;
return {
type: 'Selector',
info: getInfo(start),
selectors: selectors
};
}
function getSimpleSelector(nested) {
var start = scanner.tokenStart;
var sequence = new List();

@@ -319,7 +320,2 @@ var combinator = null;

var child;
var node = {
type: 'SimpleSelector',
info: getInfo(),
sequence: sequence
};

@@ -381,3 +377,3 @@ scan:

case NUMBERSIGN:
child = getShash();
child = getId();
break;

@@ -397,3 +393,3 @@

case NUMBER:
child = getPercentage(getInfo(), readNumber());
child = getPercentage();
break;

@@ -410,3 +406,3 @@

type: 'Combinator',
info: needPositions ? scanner.getLocation(combinatorOffset, filename) : null,
info: getInfo(combinatorOffset),
name: ' '

@@ -427,6 +423,11 @@ };

return node;
return {
type: 'SimpleSelector',
info: getInfo(start),
sequence: sequence
};
}
function getDeclarations() {
function getBlock() {
var start = scanner.tokenStart;
var declarations = new List();

@@ -451,16 +452,5 @@

return declarations;
}
function getBlockWithBrackets() {
var info = getInfo();
var declarations;
scanner.eat(LEFTCURLYBRACKET);
declarations = getDeclarations();
scanner.eat(RIGHTCURLYBRACKET);
return {
type: 'Block',
info: info,
info: getInfo(start),
declarations: declarations

@@ -470,12 +460,4 @@ };

function getBlock() {
return {
type: 'Block',
info: getInfo(),
declarations: getDeclarations()
};
}
function getDeclaration(nested) {
var info = getInfo();
var start = scanner.tokenStart;
var property = readProperty();

@@ -485,2 +467,3 @@ var important = false;

readSC();
scanner.eat(COLON);

@@ -495,3 +478,3 @@ value = getValue(nested, property);

type: 'Declaration',
info: info,
info: getInfo(start),
important: important,

@@ -505,7 +488,5 @@ property: property,

var start = scanner.tokenStart;
var name;
var type;
for (; !scanner.eof; scanner.next()) {
var type = scanner.tokenType;
for (; type = scanner.tokenType; scanner.next()) {
if (type !== SOLIDUS &&

@@ -519,7 +500,4 @@ type !== ASTERISK &&

scanIdent(true);
name = scanner.substrToCursor(start);
readSC();
return name;
return scanner.substrToCursor(start);
}

@@ -533,10 +511,6 @@

var start = scanner.tokenStart;
var sequence = new List();
var wasSpace = false;
var child;
var node = {
type: 'Value',
info: getInfo(),
sequence: sequence
};

@@ -611,6 +585,29 @@ readSC();

return node;
return {
type: 'Value',
info: getInfo(start),
sequence: sequence
};
}
// any = string | percentage | dimension | number | uri | functionExpression | funktion | unary | operator | ident
function getFilterValue() {
var start = scanner.tokenStart;
var sequence = new List();
var progid;
while (progid = checkProgid()) {
readSC();
sequence.appendData(getProgid(progid));
}
readSC();
return {
type: 'Value',
info: getInfo(start),
sequence: sequence
};
}
// any = percentage | dimension | number | operator | ident | function
function getAny(scope) {

@@ -632,20 +629,17 @@ switch (scanner.tokenType) {

case NUMBER:
var info = getInfo();
var number = readNumber();
var type = scanner.tokenType;
switch (scanner.lookupType(1)) {
case PERCENTSIGN:
return getPercentage();
if (type === PERCENTSIGN) {
return getPercentage(info, number);
}
case IDENTIFIER:
return getDimension();
if (type === IDENTIFIER) {
return getDimension(info, number);
default:
return {
type: 'Number',
info: getInfo(),
value: readNumber()
};
}
return {
type: 'Number',
info: info,
value: number
};
default:

@@ -655,3 +649,2 @@ scanner.error();

var info = getInfo();
var start = scanner.tokenStart;

@@ -662,3 +655,3 @@

if (scanner.tokenType === LEFTPARENTHESIS) {
return getFunction(scope, info, scanner.substrToCursor(start));
return getFunction(scope, getInfo(start), scanner.substrToCursor(start));
}

@@ -668,3 +661,3 @@

type: 'Identifier',
info: info,
info: getInfo(start),
name: scanner.substrToCursor(start)

@@ -711,7 +704,5 @@ };

scanner.eat(LEFTSQUAREBRACKET);
readSC();
node.name = getAttributeName();
readSC();

@@ -748,13 +739,9 @@

function getParentheses(scope) {
var start = scanner.tokenStart;
var sequence = new List();
var wasSpace = false;
var child;
var node = {
type: 'Parentheses',
info: getInfo(),
sequence: sequence
};
// left brace
scanner.next();
scanner.eat(LEFTPARENTHESIS);
readSC();

@@ -811,3 +798,7 @@

return node;
return {
type: 'Parentheses',
info: getInfo(start),
sequence: sequence
};
}

@@ -817,3 +808,3 @@

function getClass() {
var info = getInfo();
var start = scanner.tokenStart;

@@ -824,3 +815,3 @@ scanner.eat(FULLSTOP);

type: 'Class',
info: info,
info: getInfo(start),
name: readIdent(false)

@@ -831,4 +822,4 @@ };

// '#' ident
function getShash() {
var info = getInfo();
function getId() {
var start = scanner.tokenStart;

@@ -839,3 +830,3 @@ scanner.eat(NUMBERSIGN);

type: 'Id',
info: info,
info: getInfo(start),
name: readIdent(false)

@@ -847,3 +838,3 @@ };

function getCombinator() {
var info = getInfo();
var start = scanner.tokenStart;
var combinator;

@@ -880,3 +871,3 @@

type: 'Combinator',
info: info,
info: getInfo(start),
name: combinator

@@ -888,3 +879,2 @@ };

function getComment() {
var info = getInfo();
var start = scanner.tokenStart + 2;

@@ -903,3 +893,3 @@ var end = scanner.tokenEnd;

type: 'Comment',
info: info,
info: getInfo(start),
value: scanner.source.substring(start, end)

@@ -930,7 +920,7 @@ };

// number ident
function getDimension(info, number) {
function getDimension() {
return {
type: 'Dimension',
info: info,
value: number,
info: getInfo(),
value: readNumber(),
unit: readUnit()

@@ -940,3 +930,6 @@ };

function getPercentage(info, number) {
function getPercentage() {
var start = scanner.tokenStart;
var number = readNumber();
scanner.eat(PERCENTSIGN);

@@ -946,3 +939,3 @@

type: 'Percentage',
info: info,
info: getInfo(start),
value: number

@@ -1063,2 +1056,3 @@ };

// TODO: -> getSimpleSelectorList
function getNotFunctionArguments() {

@@ -1132,7 +1126,3 @@ var args = new List();

function getUri(scope, info) {
var node = {
type: 'Url',
info: info,
value: null
};
var value;

@@ -1143,7 +1133,7 @@ scanner.eat(LEFTPARENTHESIS); // (

if (scanner.tokenType === STRING) {
node.value = getString();
value = getString();
} else {
var rawInfo = getInfo();
var start = scanner.tokenStart;
// TODO: fix me, looks like incorrect raw scan
for (; !scanner.eof; scanner.next()) {

@@ -1159,5 +1149,5 @@ var type = scanner.tokenType;

node.value = {
value = {
type: 'Raw',
info: rawInfo,
info: getInfo(start),
value: scanner.substrToCursor(start)

@@ -1170,3 +1160,7 @@ };

return node;
return {
type: 'Url',
info: info,
value: value
};
}

@@ -1271,4 +1265,2 @@

}
return hexLength;
}

@@ -1278,3 +1270,2 @@

var start = scanner.tokenStart;
var info = getInfo();

@@ -1286,3 +1277,3 @@ scanner.next(); // U or u

type: 'UnicodeRange',
info: info,
info: getInfo(start),
name: scanner.substrToCursor(start)

@@ -1319,3 +1310,2 @@ };

var info = getInfo();
var start = scanner.tokenStart;

@@ -1356,3 +1346,3 @@ var expectIdentifier = false;

type: 'Identifier',
info: info,
info: getInfo(start),
name: scanner.substrToCursor(start)

@@ -1363,3 +1353,2 @@ };

function getTypeOrUniversal() {
var info = getInfo();
var start = scanner.tokenStart;

@@ -1391,3 +1380,3 @@ var universal = false;

type: universal ? 'Universal' : 'Type',
info: info,
info: getInfo(start),
name: scanner.substrToCursor(start)

@@ -1419,15 +1408,8 @@ };

function getNthSelector() {
var info = getInfo();
var start = scanner.tokenStart;
var sequence = new List();
var node;
var name;
scanner.eat(COLON);
node = {
type: 'PseudoClass',
info: info,
name: readIdent(false),
sequence: sequence
};
name = readIdent(false);
scanner.eat(LEFTPARENTHESIS);

@@ -1443,3 +1425,3 @@ readSC();

type: 'Nth',
info: getInfo(),
info: info,
value: scanner.substrToCursor(start)

@@ -1583,3 +1565,8 @@ });

return node;
return {
type: 'PseudoClass',
info: getInfo(start),
name: name,
sequence: sequence
};
}

@@ -1597,29 +1584,11 @@

function getOperator() {
var node = {
type: 'Operator',
info: getInfo(),
value: scanner.getTokenValue()
};
var start = scanner.tokenStart;
scanner.next();
return node;
}
function getFilterValue() { // TODO
var sequence = new List();
var progid;
var node = {
type: 'Value',
info: getInfo(),
sequence: sequence
return {
type: 'Operator',
info: getInfo(start),
value: scanner.substrToCursor(start)
};
while (progid = checkProgid()) {
sequence.appendData(getProgid(progid));
}
readSC();
return node;
}

@@ -1629,13 +1598,3 @@

function checkProgid() {
function checkSC(offset) {
for (var type; type = scanner.lookupType(offset); offset++) {
if (type !== WHITESPACE && type !== COMMENT) {
break;
}
}
return offset;
}
var startOffset = checkSC(0);
var startOffset = findNonSCOffset(0);
var offset = startOffset;

@@ -1653,3 +1612,3 @@

offset += 2;
offset = checkSC(offset);
offset = findNonSCOffset(offset);

@@ -1665,3 +1624,3 @@ if (scanner.lookupValue(offset + 0, 'dximagetransform') === false ||

offset += 5;
offset = checkSC(offset);
offset = findNonSCOffset(offset);
}

@@ -1675,3 +1634,3 @@

if (type === RIGHTPARENTHESIS) {
return offset - startOffset;
return offset - startOffset + 1;
}

@@ -1684,25 +1643,11 @@ }

function getProgid(progidEnd) {
var node = {
type: 'Progid',
info: getInfo(),
value: null
};
readSC();
var rawInfo = getInfo();
var start = scanner.tokenStart;
scanner.skip(progidEnd);
scanner.eat(RIGHTPARENTHESIS);
node.value = {
type: 'Raw',
info: rawInfo,
return {
type: 'Progid',
info: getInfo(start),
value: scanner.substrToCursor(start)
};
readSC();
return node;
}

@@ -1738,3 +1683,3 @@

function getPseudoElement() {
var info = getInfo();
var start = scanner.tokenStart;

@@ -1746,3 +1691,3 @@ scanner.eat(COLON);

type: 'PseudoElement',
info: info,
info: getInfo(start),
name: readIdent(false),

@@ -1759,3 +1704,3 @@ legacy: false

function getLegacyPseudoElement() {
var info = getInfo();
var start = scanner.tokenStart;

@@ -1766,3 +1711,3 @@ scanner.eat(COLON);

type: 'PseudoElement',
info: info,
info: getInfo(start),
name: readIdent(false),

@@ -1775,4 +1720,3 @@ legacy: true

function getPseudoClass() {
var info = getInfo();
var start = scanner.tokenStart + 1;
var start = scanner.tokenStart;

@@ -1783,3 +1727,3 @@ scanner.eat(COLON);

if (scanner.tokenType === LEFTPARENTHESIS) {
return getFunction(SCOPE_SELECTOR, info, scanner.substrToCursor(start));
return getFunction(SCOPE_SELECTOR, getInfo(start), scanner.substrToCursor(start + 1));
}

@@ -1789,4 +1733,4 @@

type: 'PseudoClass',
info: info,
name: scanner.substrToCursor(start),
info: getInfo(start),
name: scanner.substrToCursor(start + 1),
sequence: null

@@ -1796,2 +1740,12 @@ };

function findNonSCOffset(offset) {
for (var type; type = scanner.lookupType(offset); offset++) {
if (type !== WHITESPACE && type !== COMMENT) {
break;
}
}
return offset;
}
function readSC() {

@@ -1801,4 +1755,2 @@ while (scanner.tokenType === WHITESPACE || scanner.tokenType === COMMENT) {

}
return null;
}

@@ -1808,11 +1760,11 @@

function getString() {
var node = {
type: 'String',
info: getInfo(),
value: scanner.getTokenValue()
};
var start = scanner.tokenStart;
scanner.next();
return node;
return {
type: 'String',
info: getInfo(start),
value: scanner.substrToCursor(start)
};
}

@@ -1822,4 +1774,3 @@

function getHash() {
var info = getInfo();
var start = scanner.tokenStart + 1;
var start = scanner.tokenStart;

@@ -1842,4 +1793,4 @@ scanner.eat(NUMBERSIGN);

type: 'Hash',
info: info,
value: scanner.substrToCursor(start)
info: getInfo(start),
value: scanner.substrToCursor(start + 1) // skip #
};

@@ -1879,4 +1830,4 @@ }

// fix soft deoptimizations (insufficient type feedback)
parse('a.b#c:e:NOT(a)::g,* b>c+d~e/deep/f,100%{v:1 2em t a(2%, var(--a)) url(..) -foo-bar !important}');
parse('a.b#c:e:NOT(a)::g,* b >c+d~e/deep/f,100%{v:1 2em t a(2%, var(--a)) url(..) -foo-bar !important}');
module.exports = parse;

@@ -33,8 +33,9 @@ 'use strict';

var MIN_ARRAY_SIZE = 16 * 1024;
var MIN_BUFFER_SIZE = 16 * 1024;
var OFFSET_MASK = 0x00FFFFFF;
var TYPE_OFFSET = 24;
var SafeUint32Array = typeof Uint32Array !== 'undefined' ? Uint32Array : Array; // fallback on Array when TypedArray is not supported
var lastIndexOf = Array.prototype.lastIndexOf; // some browser implementations have no TypedArray#lastIndexOf
var LongArray = typeof Uint32Array !== 'undefined' ? Uint32Array : Array;
var offsetAndType = new LongArray(MIN_ARRAY_SIZE);
var offsetAndType = new SafeUint32Array(MIN_BUFFER_SIZE);
var lines = null;

@@ -56,3 +57,3 @@

if (lines === null || lines.length < sourceLength + 1) {
lines = new LongArray(Math.max(sourceLength + 1024, MIN_ARRAY_SIZE));
lines = new SafeUint32Array(Math.max(sourceLength + 1024, MIN_BUFFER_SIZE));
}

@@ -231,3 +232,3 @@

if (offsetAndType.length < sourceLength + 1) {
offsetAndType = new LongArray(sourceLength + 1024);
offsetAndType = new SafeUint32Array(sourceLength + 1024);
}

@@ -283,3 +284,3 @@

offsetAndType[tokenCount++] = (type << 24) | offset;
offsetAndType[tokenCount++] = (type << TYPE_OFFSET) | offset;
prevType = type;

@@ -323,6 +324,6 @@ }

if (offset < this.tokenCount) {
return this.offsetAndType[offset] >> 24;
return this.offsetAndType[offset] >> TYPE_OFFSET;
}
return 0;
return NULL;
},

@@ -358,5 +359,6 @@ lookupValue: function(offset, referenceStr) {

next = this.offsetAndType[next];
this.tokenType = next >> 24;
this.tokenType = next >> TYPE_OFFSET;
this.tokenEnd = next & OFFSET_MASK;
} else {
this.currentToken = this.tokenCount;
this.next();

@@ -372,3 +374,3 @@ }

next = this.offsetAndType[next];
this.tokenType = next >> 24;
this.tokenType = next >> TYPE_OFFSET;
this.tokenEnd = next & OFFSET_MASK;

@@ -384,16 +386,14 @@ } else {

eat: function(tokenType) {
if (this.tokenType === tokenType) {
this.next();
return true;
if (this.tokenType !== tokenType) {
this.error(TokenName[tokenType] + ' is expected');
}
this.error(TokenName[tokenType] + ' is expected');
this.next();
},
expectIdentifier: function(name) {
if (this.tokenType === IDENTIFIER && cmpStr(this.source, this.tokenStart, this.tokenEnd, name)) {
this.next();
return true;
if (this.tokenType !== IDENTIFIER || cmpStr(this.source, this.tokenStart, this.tokenEnd, name) === false) {
this.error('Identifier `' + name + '` is expected');
}
this.error('Identifier `' + name + '` is expected');
this.next();
},

@@ -452,3 +452,3 @@

return Array.prototype.slice.call(this.offsetAndType, 0, this.tokenCount).map(function(item) {
return TokenName[item >> 24];
return TokenName[item >> TYPE_OFFSET];
});

@@ -455,0 +455,0 @@ }

@@ -1,2 +0,2 @@

var stringifySyntax = require('./stringify');
var translateSyntax = require('./translate');
var translateCss = require('../utils/translate');

@@ -49,3 +49,3 @@ var walk = require('../utils/walk').all;

error.rawMessage = message;
error.syntax = syntax ? stringifySyntax(syntax) : '<generic>';
error.syntax = syntax ? translateSyntax(syntax) : '<generic>';
error.css = css;

@@ -52,0 +52,0 @@ error.line = badNode && badNode.info ? badNode.info.line : undefined;

var names = require('../utils/names.js');
// https://www.w3.org/TR/css-values-3/#lengths
var LENGTH = {

@@ -10,2 +12,3 @@ // absolute length units

'pc': true,
'q': true,

@@ -43,2 +46,3 @@ // relative length units

// https://www.w3.org/TR/css-values-3/#resolution
// https://www.w3.org/TR/css3-images/#resolution-type

@@ -80,13 +84,17 @@ var RESOLUTION = {

// there were some prefixed implementations
return keyword.vendor === '' || keyword.vendor === '-moz-' || keyword.vendor === '-webkit-';
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) {
if (node && (isCalc(node) || (node.data.type === 'Dimension' && type.hasOwnProperty(node.data.unit.toLowerCase())))) {
return {
next: node.next,
match: [node.data]
};
}
return isCalc(node) ||
(node.data.type === 'Dimension' && type.hasOwnProperty(node.data.unit.toLowerCase()));
};

@@ -96,137 +104,63 @@ }

function length(node) {
if (node && (
isCalc(node)
||
(node.data.type === 'Dimension' && LENGTH.hasOwnProperty(node.data.unit.toLowerCase()))
||
(node.data.type === 'Number' && Number(node.data.value) === 0)
)
) {
return {
next: node.next,
match: [node.data]
};
}
return isCalc(node) ||
(node.data.type === 'Dimension' && LENGTH.hasOwnProperty(node.data.unit.toLowerCase())) ||
(node.data.type === 'Number' && Number(node.data.value) === 0);
}
function attr(node) {
if (node && node.data.type === 'Function' && node.data.name.toLowerCase() === 'attr') {
return {
next: node.next,
match: [node.data]
};
}
return node.data.type === 'Function' && node.data.name.toLowerCase() === 'attr';
}
function astNode(type) {
return function(node) {
if (node && node.data.type === type) {
return {
next: node.next,
match: [node.data]
};
}
};
}
function number(node) {
if (node && (isCalc(node) || node.data.type === 'Number')) {
return {
next: node.next,
match: [node.data]
};
}
return isCalc(node) || node.data.type === 'Number';
}
function numberZeroOne(node) {
if (node && (isCalc(node) || node.data.type === 'Number')) {
if (isCalc(node) || node.data.type === 'Number') {
var value = Number(node.data.value);
if (value >= 0 && value <= 1) {
return {
next: node.next,
match: [node.data]
};
}
return value >= 0 && value <= 1;
}
return false;
}
function numberOneOrGreater(node) {
if (node && (isCalc(node) || node.data.type === 'Number')) {
var value = Number(node.data.value);
if (value >= 1) {
return {
next: node.next,
match: [node.data]
};
}
if (isCalc(node) || node.data.type === 'Number') {
return Number(node.data.value) >= 1;
}
return false;
}
// TODO: fail on 10e-2
function integer(node) {
if (node && (isCalc(node) || (node.data.type === 'Number' && node.data.value.indexOf('.') === -1))) {
return {
next: node.next,
match: [node.data]
};
}
return isCalc(node) ||
(node.data.type === 'Number' && node.data.value.indexOf('.') === -1);
}
// TODO: fail on 10e-2
function positiveInteger(node) {
if (node && (isCalc(node) || (node.data.type === 'Number' && node.data.value.indexOf('.') === -1 && node.data.value.charAt(0) !== '-'))) {
return {
next: node.next,
match: [node.data]
};
}
return isCalc(node) ||
(node.data.type === 'Number' && node.data.value.indexOf('.') === -1 && node.data.value.charAt(0) !== '-');
}
function percentage(node) {
if (node && (isCalc(node) || node.data.type === 'Percentage')) {
return {
next: node.next,
match: [node.data]
};
}
return isCalc(node) ||
node.data.type === 'Percentage';
}
function hexColor(node) {
if (!node || node.data.type !== 'Hash') {
return;
if (node.data.type !== 'Hash') {
return false;
}
var hex = node.data.value;
if (/^[0-9a-fA-F]{3,8}$/.test(hex) &&
(hex.length === 3 || hex.length === 4 || hex.length === 6 || hex.length === 8)) {
return {
next: node.next,
match: [node.data]
};
}
}
function idSelector(node) {
if (!node || node.data.type !== 'Hash') {
return;
}
var cursor = node.next;
var match = [node.data];
while (cursor && (cursor.data.type === 'Number' || cursor.data.type === 'Identifier')) {
match.push(cursor.data);
cursor = cursor.next;
}
return {
next: cursor,
match: match
};
return /^[0-9a-fA-F]{3,8}$/.test(hex) &&
(hex.length === 3 || hex.length === 4 || hex.length === 6 || hex.length === 8);
}
function expression(node) {
if (node && node.data.type === 'Function' && node.data.name.toLowerCase() === 'expression') {
return {
next: node.next,
match: [node.data]
};
}
return node.data.type === 'Function' && node.data.name.toLowerCase() === 'expression';
}

@@ -236,4 +170,4 @@

function customIdent(node) {
if (!node || node.data.type !== 'Identifier') {
return;
if (node.data.type !== 'Identifier') {
return false;
}

@@ -245,3 +179,3 @@

if (name === 'unset' || name === 'initial' || name === 'inherit') {
return;
return false;
}

@@ -251,6 +185,3 @@

return {
next: node.next,
match: [node.data]
};
return true;
}

@@ -267,3 +198,3 @@

'hex-color': hexColor,
'id-selector': idSelector, // element( <id-selector> )
'id-selector': astNode('Hash'), // element( <id-selector> )
'ident': astNode('Identifier'),

@@ -270,0 +201,0 @@ 'integer': integer,

@@ -6,4 +6,4 @@ module.exports = {

parse: require('./parse'),
stringify: require('./stringify'),
translate: require('./translate'),
walk: require('./walk')
};
var names = require('../utils/names');
var MULTIPLIER_DEFAULT = {
comma: false,
min: 1,
max: 1,
value: ''
};

@@ -13,4 +19,5 @@ function skipSpaces(node) {

var result = [];
var min = syntaxNode.min === 0 || syntaxNode.min ? syntaxNode.min : 1;
var max = syntaxNode.max === null ? Infinity : (syntaxNode.max || 1);
var multiplier = syntaxNode.multiplier || MULTIPLIER_DEFAULT;
var min = multiplier.min;
var max = multiplier.max === 0 ? Infinity : multiplier.max;
var lastCommaTermCount;

@@ -351,3 +358,3 @@ var lastComma;

if (syntaxNode.comma) {
if (multiplier.comma) {
if (lastComma && lastCommaTermCount === result.length) {

@@ -354,0 +361,0 @@ // nothing match after comma

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 = {

@@ -8,223 +33,234 @@ ' ': 1,

};
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 spaces = /[ \r\n\f]/;
var nameChar = /[a-zA-Z0-9\-]/;
var number = /\d/;
var Scanner = function(str) {
this.str = str;
this.pos = 0;
};
Scanner.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;
},
function readWord(str, start) {
var end = start;
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) + '`');
}
while (nameChar.test(str.charAt(end))) {
end++;
this.pos++;
}
};
return str.substring(start, end);
function scanSpaces(scanner) {
var end = scanner.pos + 1;
for (; end < scanner.str.length; end++) {
var code = scanner.str.charCodeAt(end);
if (code !== R && code !== N && code !== F && code !== SPACE && code !== TAB) {
break;
}
}
return scanner.substringToPos(end);
}
function readNumber(str, start) {
var end = start;
function scanWord(scanner) {
var end = scanner.pos;
while (number.test(str.charAt(end))) {
end++;
for (; end < scanner.str.length; end++) {
var code = scanner.str.charCodeAt(end);
if (code >= 128 || NAME_CHAR[code] === 0) {
break;
}
}
return str.substring(start, end);
if (scanner.pos === end) {
error(scanner, scanner.pos, 'Expect a keyword');
}
return scanner.substringToPos(end);
}
function readString(str, start) {
var end = start + 1;
function scanNumber(scanner) {
var end = scanner.pos;
while (str.charAt(end) !== '\'') {
end++;
for (; end < scanner.str.length; end++) {
var code = scanner.str.charCodeAt(end);
if (code < 48 || code > 57) {
break;
}
}
end += eat(str, end, '\'');
if (scanner.pos === end) {
error(scanner, scanner.pos, 'Expect a number');
}
return str.substring(start, end);
return scanner.substringToPos(end);
}
function readMultiplier(str, pos) {
function readRange() {
var min = null;
var max = null;
function scanString(scanner) {
var end = scanner.str.indexOf('\'', scanner.pos + 1);
pos += eat(str, pos, '{');
if (end === -1) {
error(scanner, scanner.str.length, 'Expect a quote');
}
min = readNumber(str, pos) || error(str, pos);
pos += min.length;
return scanner.substringToPos(end + 1);
}
if (str.charAt(pos) === ',') {
pos++;
if (str.charAt(pos) !== '}') {
max = readNumber(str, pos) || error(str, pos);
pos += max.length;
}
} else {
max = min;
}
function readMultiplierRange(scanner, comma) {
var min = null;
var max = null;
pos += eat(str, pos, '}');
scanner.eat(LEFTCURLYBRACKET);
return {
min: Number(min),
max: max ? Number(max) : null
};
min = scanNumber(scanner);
if (scanner.charCode() === COMMA) {
scanner.pos++;
if (scanner.charCode() !== RIGHTCURLYBRACKET) {
max = scanNumber(scanner);
}
} else {
max = min;
}
switch (str.charAt(pos)) {
case '*':
return {
comma: false,
min: 0,
max: null,
value: '*'
};
scanner.eat(RIGHTCURLYBRACKET);
case '+':
return {
comma: false,
min: 1,
max: null,
value: '+'
};
return {
comma: comma,
min: Number(min),
max: max ? Number(max) : 0
};
}
case '?':
return {
comma: false,
min: 0,
max: 1,
value: '?'
};
function readMultiplier(scanner) {
switch (scanner.charCode()) {
case ASTERISK:
scanner.pos++;
return MULTIPLIER_ZERO_OR_MORE;
case '#':
var start = pos;
case PLUSSIGN:
scanner.pos++;
return MULTIPLIER_ONE_OR_MORE;
pos++; // #
case QUESTIONMARK:
scanner.pos++;
return MULTIPLIER_ZERO_OR_ONE;
if (str.charAt(pos) === '{') {
var range = readRange();
if (range) {
return {
comma: true,
min: range.min,
max: range.max,
value: str.substring(start, pos)
};
}
case NUMBERSIGN:
scanner.pos++;
if (scanner.charCode() !== LEFTCURLYBRACKET) {
return MULTIPLIER_ONE_OR_MORE_COMMA_SEPARATED;
}
return {
comma: true,
min: 1,
max: null,
value: '#'
};
return readMultiplierRange(scanner, true);
case '{':
var start = pos;
var range = readRange();
if (range) {
return {
comma: false,
min: range.min,
max: range.max,
value: str.substring(start, pos)
};
}
break;
case LEFTCURLYBRACKET:
return readMultiplierRange(scanner, false);
}
return {
comma: false,
min: 1,
max: 1,
value: ''
};
return MULTIPLIER_DEFAULT;
}
function readProperty(str, start) {
var end = start;
var multiplier;
function readProperty(scanner) {
var name;
end += eat(str, end, '<');
end += eat(str, end, '\'');
scanner.eat(LESSTHANSIGN);
scanner.eat(APOSTROPHE);
name = readWord(str, end) || error(str, end);
end += name.length;
name = scanWord(scanner);
end += eat(str, end, '\'');
end += eat(str, end, '>');
scanner.eat(APOSTROPHE);
scanner.eat(GREATERTHANSIGN);
multiplier = readMultiplier(str, end);
end += multiplier.value.length;
return {
type: 'Property',
name: name,
comma: multiplier.comma,
min: multiplier.min,
max: multiplier.max,
value: str.substring(start, end)
multiplier: readMultiplier(scanner)
};
}
function readType(str, start) {
var end = start;
var multiplier;
function readType(scanner) {
var name;
end += eat(str, end, '<');
scanner.eat(LESSTHANSIGN);
name = scanWord(scanner);
name = readWord(str, end) || error(str, end);
end += name.length;
if (str.charAt(end) === '(' && str.charAt(end + 1) === ')') {
if (scanner.charCode() === LEFTPARENTHESIS &&
scanner.nextCharCode() === RIGHTPARENTHESIS) {
scanner.pos += 2;
name += '()';
end += 2;
}
end += eat(str, end, '>');
scanner.eat(GREATERTHANSIGN);
multiplier = readMultiplier(str, end);
end += multiplier.value.length;
return {
type: 'Type',
name: name,
comma: multiplier.comma,
min: multiplier.min,
max: multiplier.max,
value: str.substring(start, end)
multiplier: readMultiplier(scanner)
};
}
function readKeywordOrFunction(str, start) {
var end = start;
function readKeywordOrFunction(scanner) {
var sequence = null;
var multiplier;
var name;
name = readWord(str, end) || error(str, end);
end += name.length;
name = scanWord(scanner);
if (str.charAt(end) === '(') {
sequence = readSequence(str, end + 1);
end += sequence.value.length + 1;
if (scanner.charCode() === LEFTPARENTHESIS) {
scanner.pos++;
sequence = readSequence(scanner);
scanner.eat(RIGHTPARENTHESIS);
end += eat(str, end, ')');
return {
type: 'Function',
name: name,
sequence: sequence,
multiplier: readMultiplier(scanner)
};
}
multiplier = readMultiplier(str, end);
end += multiplier.value.length;
return {
type: sequence ? 'Function' : 'Keyword',
type: 'Keyword',
name: name,
sequence: sequence,
comma: multiplier.comma,
min: multiplier.min,
max: multiplier.max,
value: str.substring(start, end)
multiplier: readMultiplier(scanner)
};

@@ -283,19 +319,19 @@ }

function readSequence(str, start) {
function readSequence(scanner) {
var terms = [];
var combinators = {};
var end = start;
var token;
var lastToken;
var prevToken = null;
var prevTokenPos = scanner.pos;
while (token = peek(str, end)) {
while (token = peek(scanner)) {
if (token.type !== 'Spaces') {
if (token.type === 'Combinator') {
// check for combinator in group beginning and double combinator sequence
if (!lastToken || lastToken.type === 'Combinator') {
error(str, end);
if (prevToken === null || prevToken.type === 'Combinator') {
error(scanner, prevTokenPos, 'Unexpected combinator');
}
combinators[token.value] = true;
} else if (lastToken && lastToken.type !== 'Combinator') {
} else if (prevToken !== null && prevToken.type !== 'Combinator') {
combinators[' '] = true; // a b

@@ -309,11 +345,10 @@ terms.push({

terms.push(token);
lastToken = token;
prevToken = token;
prevTokenPos = scanner.pos;
}
end += token.value.length;
}
// check for combinator in group ending
if (lastToken && lastToken.type === 'Combinator') {
error(str, end - lastToken.value.length);
if (prevToken !== null && prevToken.type === 'Combinator') {
error(scanner, scanner.pos - prevTokenPos, 'Unexpected combinator');
}

@@ -324,25 +359,19 @@

terms: terms,
combinator: regroupTerms(terms, combinators) || ' ',
value: str.substring(start, end)
combinator: regroupTerms(terms, combinators) || ' '
};
}
function readGroup(str, start) {
function readGroup(scanner) {
var sequence;
var nonEmpty = false;
var multiplier;
var end = start;
end += eat(str, end, '[');
scanner.eat(LEFTSQUAREBRACKET);
sequence = readSequence(scanner);
sequence = readSequence(str, end);
end += sequence.value.length;
scanner.eat(RIGHTSQUAREBRACKET);
multiplier = readMultiplier(scanner);
end += eat(str, end, ']');
multiplier = readMultiplier(str, end);
end += multiplier.value.length;
if (str.charAt(end) === '!') {
end++;
if (scanner.charCode() === EXCLAMATIONMARK) {
scanner.pos++;
nonEmpty = true;

@@ -356,60 +385,40 @@ }

nonEmpty: nonEmpty,
comma: multiplier.comma,
min: multiplier.min,
max: multiplier.max,
value: str.substring(start, end)
multiplier: multiplier
};
}
function readSpaces(str, start) {
var end = start + 1;
while (spaces.test(str.charAt(end))) {
end++;
}
return {
type: 'Spaces',
value: str.substring(start, end)
};
}
function peek(scanner) {
var code = scanner.charCode();
function peek(str, start) {
var c = str.charAt(start);
var end = start + 1;
if (spaces.test(c)) {
return readSpaces(str, start);
if (code < 128 && NAME_CHAR[code] === 1) {
return readKeywordOrFunction(scanner);
}
if (nameChar.test(c)) {
return readKeywordOrFunction(str, start);
}
switch (code) {
case LEFTSQUAREBRACKET:
return readGroup(scanner);
switch (c) {
case '[':
return readGroup(str, start);
case '<':
if (str.charAt(start + 1) === '\'') {
return readProperty(str, start);
case LESSTHANSIGN:
if (scanner.nextCharCode() === APOSTROPHE) {
return readProperty(scanner);
} else {
return readType(str, start);
return readType(scanner);
}
case '|':
end += str.charAt(end) === '|';
case VERTICALLINE:
return {
type: 'Combinator',
value: str.substring(start, end)
value: scanner.substringToPos(scanner.nextCharCode() === VERTICALLINE ? scanner.pos + 2 : scanner.pos + 1)
};
case '&':
if (str.charAt(end) === '&') {
return {
type: 'Combinator',
value: '&&'
};
}
break;
case AMPERSAND:
scanner.pos++;
scanner.eat(AMPERSAND);
return {
type: 'Combinator',
value: '&&'
};
case ',':
case COMMA:
scanner.pos++;
return {

@@ -420,3 +429,4 @@ type: 'Comma',

case '/':
case SOLIDUS:
scanner.pos++;
return {

@@ -427,3 +437,4 @@ type: 'Slash',

case '%': // looks like exception, needs for attr()'s <type-or-unit>
case PERCENTSIGN: // looks like exception, needs for attr()'s <type-or-unit>
scanner.pos++;
return {

@@ -434,38 +445,40 @@ type: 'Percent',

case '(':
var sequence = readSequence(str, end);
end += sequence.value.length;
end += eat(str, end, ')');
case LEFTPARENTHESIS:
scanner.pos++;
var sequence = readSequence(scanner);
scanner.eat(RIGHTPARENTHESIS);
return {
type: 'Parentheses',
sequence: sequence,
value: str.substring(start, end)
sequence: sequence
};
case '\'':
case APOSTROPHE:
return {
type: 'String',
value: readString(str, start)
value: scanString(scanner)
};
}
}
function eat(str, pos, ch) {
if (str.charAt(pos) !== ch) {
error(str, pos, 'Expect `' + ch + '`');
case SPACE:
case TAB:
case N:
case R:
case F:
return {
type: 'Spaces',
value: scanSpaces(scanner)
};
}
return 1;
}
function error(str, pos, msg) {
throw new SyntaxParseError(msg || 'Unexpected input', str, pos);
function error(scanner, pos, msg) {
throw new SyntaxParseError(msg || 'Unexpected input', scanner.str, pos);
}
module.exports = function parse(str) {
var result = readSequence(str, 0);
function parse(str) {
var scanner = new Scanner(str);
var result = readSequence(scanner);
if (result.value !== str) {
error(str, result.value.length);
if (scanner.pos !== str.length) {
error(scanner, scanner.pos);
}

@@ -479,2 +492,8 @@

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;
var MatchError = require('./error').MatchError;
var walkAst = require('../utils/walk').all;
var names = require('../utils/names');
var generic = require('./generic');
var parse = require('./parse');
var stringify = require('./stringify');
var translate = require('./translate');
var walk = require('./walk');

@@ -16,3 +17,3 @@ var match = require('./match');

if (map[name].syntax) {
result[name] = syntaxAsAst ? map[name].syntax : stringify(map[name].syntax);
result[name] = syntaxAsAst ? map[name].syntax : translate(map[name].syntax);
}

@@ -28,5 +29,26 @@ }

function valueHasVar(value) {
var hasVar = false;
walkAst(value, function(node) {
if (node.type === 'Function' && node.name.toLowerCase() === 'var') {
hasVar = true;
}
});
return hasVar;
}
function matchSyntax(dictionary, syntax, value) {
var result = match(dictionary, dictionary.valueCommonSyntax, value.sequence.head);
var result;
if (valueHasVar(value)) {
return {
type: 'NoMatch',
comment: 'Due to matching for value with var() is very complex those values are always valid for now'
};
}
result = match(dictionary, dictionary.valueCommonSyntax, value.sequence.head);
if (!result.match) {

@@ -83,2 +105,3 @@ result = syntax.match(value.sequence.head);

createDescriptor: function(syntax) {
var self = this;
var descriptor = {

@@ -90,6 +113,32 @@ syntax: null,

if (typeof syntax === 'function') {
descriptor.match = syntax;
descriptor.match = function(node) {
if (node && syntax(node)) {
return {
badNode: null,
lastNode: null,
next: node.next,
match: [node.data]
};
}
return null;
};
} else {
descriptor.syntax = typeof syntax === 'string' ? parse(syntax) : syntax;
descriptor.match = match.bind(null, this, descriptor.syntax);
if (typeof syntax === 'string') {
Object.defineProperty(descriptor, 'syntax', {
get: function() {
Object.defineProperty(descriptor, 'syntax', {
value: parse(syntax)
});
return descriptor.syntax;
}
});
} else {
descriptor.syntax = syntax;
}
descriptor.match = function(ast) {
return match(self, descriptor.syntax, ast);
};
}

@@ -96,0 +145,0 @@

@@ -30,18 +30,16 @@ //

Object.defineProperty(List.prototype, 'size', {
get: function() {
var size = 0;
var cursor = this.head;
List.createItem = createItem;
List.prototype.createItem = createItem;
while (cursor) {
size++;
cursor = cursor.next;
}
List.prototype.getSize = function() {
var size = 0;
var cursor = this.head;
return size;
while (cursor) {
size++;
cursor = cursor.next;
}
});
List.createItem = createItem;
List.prototype.createItem = createItem;
return size;
};

@@ -82,6 +80,5 @@ List.prototype.fromArray = function(array) {

};
List.prototype.toJSON = function() {
return this.toArray();
};
List.prototype.toJSON = List.prototype.toArray;
List.prototype.isEmpty = function() {

@@ -88,0 +85,0 @@ return this.head === null;

@@ -153,3 +153,3 @@ function each(list) {

case 'Progid':
return translate(node.value);
return node.value;

@@ -156,0 +156,0 @@ case 'Combinator':

@@ -227,3 +227,3 @@ var SourceMapGenerator = require('source-map').SourceMapGenerator;

case 'Progid':
return translate(node.value);
return node.value;

@@ -230,0 +230,0 @@ case 'Combinator':

@@ -175,3 +175,2 @@ function walkRules(node, item, list) {

case 'Url':
case 'Progid':
walkAll.call(this, node.value);

@@ -181,2 +180,3 @@ break;

// nothig to do with
// case 'Progid':
// case 'Property':

@@ -183,0 +183,0 @@ // case 'Combinator':

{
"name": "css-tree",
"version": "1.0.0-alpha7",
"version": "1.0.0-alpha8",
"description": "Detailed CSS parser",

@@ -5,0 +5,0 @@ "keywords": [

@@ -0,1 +1,7 @@

<img align="right" width="111" height="111"
alt="CSSTree logo"
src="https://cloud.githubusercontent.com/assets/270491/19243723/6f9136c6-8f21-11e6-82ac-eeeee4c6c452.png"/>
# CSSTree
[![NPM version](https://img.shields.io/npm/v/css-tree.svg)](https://www.npmjs.com/package/css-tree)

@@ -7,6 +13,12 @@ [![Build Status](https://travis-ci.org/csstree/csstree.svg?branch=master)](https://travis-ci.org/csstree/csstree)

Fast detailed CSS parser
> Work in progress
Docs and tools:
* [CSS syntax reference](https://csstree.github.io/docs/syntax.html)
* [CSS syntax validator](https://csstree.github.io/docs/validator.html)
Related:
Related projects:

@@ -18,4 +30,4 @@ * [csstree-validator](https://github.com/csstree/validator) – NPM package to validate CSS

* [Sublime plugin](https://github.com/csstree/SublimeLinter-contrib-csstree)
* [VS Code plugin](https://github.com/csstree/vscode-csstree)
* [Atom plugin](https://github.com/csstree/atom-csstree-validator)
* [VS Code plugin](https://github.com/csstree/vscode-plugin)
* [Atom plugin](https://github.com/csstree/atom-plugin)

@@ -191,2 +203,2 @@ ## Install

[Template:CSSData](https://developer.mozilla.org/en-US/docs/Template:CSSData) by Mozilla Contributors is licensed under [CC-BY-SA 2.5](http://creativecommons.org/licenses/by-sa/2.5/)
Syntax matching use [mdn/data](https://github.com/mdn/data) dictionaries by Mozilla Contributors

Sorry, the diff of this file is too big to display

Sorry, the diff of this file is not supported yet

SocketSocket SOC 2 Logo

Product

  • Package Alerts
  • Integrations
  • Docs
  • Pricing
  • FAQ
  • Roadmap

Stay in touch

Get open source security insights delivered straight into your inbox.


  • Terms
  • Privacy
  • Security

Made with ⚡️ by Socket Inc