🚀 Big News: Socket Acquires Coana to Bring Reachability Analysis to Every Appsec Team.Learn more
Socket
Book a DemoInstallSign in
Socket

css-tree

Package Overview
Dependencies
Maintainers
1
Versions
58
Alerts
File Explorer

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

css-tree - npm Package Compare versions

Comparing version

to
1.0.0-alpha15

docs/ast.md

52

HISTORY.md

@@ -0,1 +1,37 @@

## 1.0.0-alpha15 (February 8, 2017)
- Fixed broken `atruleExpression` context
- Fixed vendor prefix detection in `keyword()` and `property()`
- Fixed `property()` to not lowercase custom property names
- Added `variable` boolean flag in `property()` result
- Renamed `scanner` into `tokenizer`
- Ranamed `syntax` into `lexer`
- Moved `docs/*.html` files to [csstree/docs](https://github.com/csstree/docs) repo
- Added `element()` function for `Value` context (`-moz-element()` supported as well)
- Merged `Universal` node type into `Type`
- Renamed node types:
- `Id` -> `IdSelector`
- `Class` -> `ClassSelector`
- `Type` -> `TypeSelector`
- `Attribute` -> `AttributeSelector`
- `PseudoClass` -> `PseudoClassSelector`
- `PseudoElement` -> `PseudoElementSelector`
- `Hash` -> `HexColor`
- `Space` -> `WhiteSpace`
- `An+B` -> `AnPlusB`
- Removed `Progid` node type
- Relaxed `MediaQuery` consumer to not validate syntax on parse and to include whitespaces in children sequence as is
- Added `WhiteSpace.value` property to store whitespace sequence
- Implemented parser options to specify what should be parsed in details (when option is `false` some part of CSS represents as balanced `Raw`):
- `parseAtruleExpression` – to parse at-rule expressions (`true` by default)
- `parseSelector` – to parse rule's selector (`true` by default)
- `parseValue` - to parse declaration's value (`true` by default)
- `parseCustomProperty` – to parse value and fallback of custom property (`false` by default)
- Changed tokenization to stick leading hyphen minus to identifier token
- Changed selector parsing:
- Don't convert spaces into descendant combinator
- Don't validate selector structure on parsing (selectors may be checked by lexer later)
- Initial refactoring of [docs](https://github.com/csstree/csstree/blob/master/docs)
- Various improvements and fixes
## 1.0.0-alpha14 (February 3, 2017)

@@ -15,10 +51,10 @@

- Changed parser to use `StyleSheet` node type only for top level node (when context is `stylesheet`, that's by default)
- Changed `Parentheses`, `Brackets` and `Function` consumers to use passed sequence reader instead its own
- Changed `Value` and `AtruleExpression` consumers to use common sequence reader (that reader was used by `Value` consumer only)
- Changed `Parentheses`, `Brackets` and `Function` consumers to use passed sequence reader instead of its own
- Changed `Value` and `AtruleExpression` consumers to use common sequence reader (that reader was used by `Value` consumer before)
- Changed default sequence reader to exclude storage of spaces around `Comma`
- Changed processing of custom properties
- Consume custom property value as balanced `Raw`
- Changed processing of custom properties:
- Consume declaration value as balanced `Raw`
- Consume `var()` fallback value as balanced `Raw`
- Validate first argument of `var()` is custom property name (i.e. starts with double dash)
- Custom property's value and fallback includes spaces around its value
- Validate first argument of `var()` starts with double dash
- Custom property's value and fallback includes spaces around
- Fixed `Nth` to have a `loc` property

@@ -33,4 +69,4 @@ - Fixed `SelectorList.loc` and `Selector.loc` positions to exclude spaces

- Removed deprecated `Syntax#match()` method
- Splitted parser into modules and related changes, one step closer to an extensible parser
- Various fixes and improvements, all changes have negligible impact on performace
- Parser was splitted into modules and related changes, one step closer to an extensible parser
- Various fixes and improvements, all changes have negligible impact on performance

@@ -37,0 +73,0 @@ ## 1.0.0-alpha13 (January 19, 2017)

6

lib/index.js

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

List: require('./utils/list'),
Scanner: require('./scanner'),
Tokenizer: require('./tokenizer'),
Lexer: require('./lexer/Lexer'),
syntax: require('./syntax'),
syntax: require('./lexer'),
property: names.property,

@@ -13,0 +15,0 @@ keyword: names.keyword,

var List = require('../../utils/list');
var TYPE = require('../../scanner').TYPE;
var TYPE = require('../../tokenizer').TYPE;

@@ -27,7 +27,5 @@ var STRING = TYPE.String;

this.readSC();
if (this.scanner.tokenType === IDENTIFIER ||
this.scanner.tokenType === LEFTPARENTHESIS) {
children.appendData(this.SPACE_NODE);
if (this.scanner.lookupNonWSType(0) === IDENTIFIER ||
this.scanner.lookupNonWSType(0) === LEFTPARENTHESIS) {
children.appendData(this.WhiteSpace());
children.appendData(this.MediaQueryList());

@@ -34,0 +32,0 @@ }

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

var TYPE = require('../../scanner').TYPE;
var TYPE = require('../../tokenizer').TYPE;
var LEFTCURLYBRACKET = TYPE.LeftCurlyBracket;

@@ -3,0 +3,0 @@

var List = require('../../utils/list');
var TYPE = require('../../scanner').TYPE;
var TYPE = require('../../tokenizer').TYPE;

@@ -10,3 +10,2 @@ var WHITESPACE = TYPE.Whitespace;

var COLON = TYPE.Colon;
var DISALLOW_VAR = false;
var BALANCED = true;

@@ -28,9 +27,5 @@

index = 1;
} else if (this.scanner.tokenType === HYPHENMINUS) {
if (this.scanner.lookupType(1) === IDENTIFIER) {
index = 2;
} else if (this.scanner.lookupType(1) === HYPHENMINUS &&
this.scanner.lookupType(2) === IDENTIFIER) {
index = 3;
}
} else if (this.scanner.tokenType === HYPHENMINUS &&
this.scanner.lookupType(1) === IDENTIFIER) {
index = 2;
}

@@ -49,3 +44,3 @@

var children = new List();
var wasSpace = false;
var space = null;
var child;

@@ -59,4 +54,3 @@

case WHITESPACE:
this.scanner.next();
wasSpace = true;
space = this.WhiteSpace();
continue;

@@ -72,3 +66,3 @@

} else {
child = this.Identifier(DISALLOW_VAR);
child = this.Identifier();
}

@@ -86,5 +80,5 @@

if (wasSpace) {
wasSpace = false;
children.appendData(this.SPACE_NODE);
if (space !== null) {
children.appendData(space);
space = null;
}

@@ -91,0 +85,0 @@

var List = require('../../utils/list');
var TYPE = require('../../scanner').TYPE;
var TYPE = require('../../tokenizer').TYPE;
var IDENTIFIER = TYPE.Identifier;
var COMMA = TYPE.Comma;
var HYPHENMINUS = TYPE.HyphenMinus;
var EXCLAMATIONMARK = TYPE.ExclamationMark;
var ALLOWED_VAR = true;
var BALANCED = true;

@@ -16,10 +16,15 @@

if (this.scanner.tokenType !== HYPHENMINUS) {
this.scanner.error('Hyphen minus is expected');
var identStart = this.scanner.tokenStart;
this.scanner.eat(HYPHENMINUS);
if (this.scanner.source.charCodeAt(this.scanner.tokenStart) !== HYPHENMINUS) {
this.scanner.error('HyphenMinus is expected');
}
if (this.scanner.lookupType(1) !== HYPHENMINUS) {
this.scanner.error('Hyphen minus is expected', this.scanner.tokenStart + 1);
}
this.scanner.eat(IDENTIFIER);
children.appendData(this.Identifier(ALLOWED_VAR));
children.appendData({
type: 'Identifier',
loc: this.getLocation(identStart, this.scanner.tokenStart),
name: this.scanner.substrToCursor(identStart)
});

@@ -30,3 +35,6 @@ this.readSC();

children.appendData(this.Operator());
children.appendData(this.Raw(BALANCED, HYPHENMINUS, EXCLAMATIONMARK));
children.appendData(this.parseCustomProperty
? this.Value(null)
: this.Raw(BALANCED, HYPHENMINUS, EXCLAMATIONMARK)
);
}

@@ -33,0 +41,0 @@

@@ -1,224 +0,4 @@

'use strict';
var Scanner = require('../scanner');
var TYPE = Scanner.TYPE;
var WHITESPACE = TYPE.Whitespace;
var IDENTIFIER = TYPE.Identifier;
var COMMENT = TYPE.Comment;
var HYPHENMINUS = TYPE.HyphenMinus;
var sequence = require('./sequence');
var getAnPlusB = require('./type/An+B');
var getAtrule = require('./type/Atrule');
var getAtruleExpression = require('./type/AtruleExpression');
var getAttribute = require('./type/Attribute');
var getBlock = require('./type/Block');
var getBrackets = require('./type/Brackets');
var getClass = require('./type/Class');
var getCombinator = require('./type/Combinator');
var getComment = require('./type/Comment');
var getDeclaration = require('./type/Declaration');
var getDeclarationList = require('./type/DeclarationList');
var getDimension = require('./type/Dimention');
var getFunction = require('./type/Function');
var getHash = require('./type/Hash');
var getId = require('./type/Id');
var getIdentifier = require('./type/Identifier');
var getMediaFeature = require('./type/MediaFeature');
var getMediaQuery = require('./type/MediaQuery');
var getMediaQueryList = require('./type/MediaQueryList');
var getNth = require('./type/Nth');
var getNumber = require('./type/Number');
var getOperator = require('./type/Operator');
var getParentheses = require('./type/Parentheses');
var getPercentage = require('./type/Percentage');
var getProgid = require('./type/Progid');
var getPseudoClass = require('./type/PseudoClass');
var getPseudoElement = require('./type/PseudoElement');
var getRatio = require('./type/Ratio');
var getRaw = require('./type/Raw');
var getRule = require('./type/Rule');
var getSelector = require('./type/Selector');
var getSelectorList = require('./type/SelectorList');
var getString = require('./type/String');
var getStyleSheet = require('./type/StyleSheet');
var getType = require('./type/Type');
var getUnicodeRange = require('./type/UnicodeRange');
var getUniversal = require('./type/Universal');
var getUrl = require('./type/Url');
var getValue = require('./type/Value');
function scanIdent(varAllowed) {
// optional first -
if (this.scanner.tokenType === HYPHENMINUS) {
this.scanner.next();
// variable --
if (varAllowed && this.scanner.tokenType === HYPHENMINUS) {
this.scanner.next();
}
}
this.scanner.eat(IDENTIFIER);
}
function readIdent(varAllowed) {
var start = this.scanner.tokenStart;
this.scanIdent(varAllowed);
return this.scanner.substrToCursor(start);
}
function readSC() {
while (this.scanner.tokenType === WHITESPACE || this.scanner.tokenType === COMMENT) {
this.scanner.next();
}
}
var Parser = function() {
this.scanner = new Scanner();
this.needPositions = false;
this.filename = '<unknown>';
};
Parser.prototype = {
SPACE_NODE: Object.freeze({ type: 'Space' }),
scopeAtruleExpression: {},
scopeValue: {
expression: require('./function/expression'),
var: require('./function/var')
},
atrule: {
'import': require('./atrule/import'),
'media': require('./atrule/media'),
'page': require('./atrule/page'),
'supports': require('./atrule/supports')
},
pseudo: {
'lang': sequence.singleIdentifier,
'dir': sequence.singleIdentifier,
'not': sequence.selectorList,
'matches': sequence.selectorList,
'has': sequence.relativeSelectorList,
'nth-child': sequence.nthWithOfClause,
'nth-last-child': sequence.nthWithOfClause,
'nth-of-type': sequence.nth,
'nth-last-of-type': sequence.nth,
'slotted': sequence.compoundSelectorList
},
context: {
stylesheet: getStyleSheet,
atrule: getAtrule,
atruleExpression: getAtruleExpression,
rule: getRule,
selectorList: getSelectorList,
selector: getSelector,
block: getBlock,
declarationList: getDeclarationList,
declaration: getDeclaration,
value: getValue
},
// consumers
AnPlusB: getAnPlusB,
Atrule: getAtrule,
AtruleExpression: getAtruleExpression,
Attribute: getAttribute,
Block: getBlock,
Brackets: getBrackets,
Class: getClass,
Combinator: getCombinator,
Comment: getComment,
Declaration: getDeclaration,
DeclarationList: getDeclarationList,
Dimension: getDimension,
Function: getFunction,
Hash: getHash,
Id: getId,
Identifier: getIdentifier,
MediaFeature: getMediaFeature,
MediaQuery: getMediaQuery,
MediaQueryList: getMediaQueryList,
Nth: getNth,
Number: getNumber,
Operator: getOperator,
Parentheses: getParentheses,
Percentage: getPercentage,
Progid: getProgid,
PseudoClass: getPseudoClass,
PseudoElement: getPseudoElement,
Ratio: getRatio,
Raw: getRaw,
Rule: getRule,
Selector: getSelector,
SelectorList: getSelectorList,
String: getString,
Stylesheet: getStyleSheet,
Type: getType,
UnicodeRange: getUnicodeRange,
Universal: getUniversal,
Url: getUrl,
Value: getValue,
scanIdent: scanIdent,
readIdent: readIdent,
readSC: readSC,
readSequence: sequence.default,
getLocation: function getLocation(start, end) {
if (this.needPositions) {
return this.scanner.getLocationRange(
start,
end,
this.filename
);
}
return null;
},
parse: function parse(source, options) {
options = options || {};
var context = options.context || 'stylesheet';
var ast;
this.scanner.setSource(source, options.line, options.column);
this.filename = options.filename || '<unknown>';
this.needPositions = Boolean(options.positions);
switch (context) {
case 'value':
ast = this.Value(options.property ? String(options.property) : null);
break;
case 'atruleExpression':
ast = this.Value(options.atrule ? String(options.atrule) : null);
break;
default:
if (!this.context.hasOwnProperty(context)) {
throw new Error('Unknown context `' + context + '`');
}
ast = this.context[context].call(this);
}
if (!this.scanner.eof) {
this.scanner.error();
}
// console.log(JSON.stringify(ast, null, 4));
return ast;
}
};
var Parser = require('./Parser');
var parser = new Parser();
// warm up parse to elimitate code branches that never execute
// fix soft deoptimizations (insufficient type feedback)
parser.parse('a.b#c:e:Not(a/**/):AFTER:Nth-child(2n+1)::g::slotted(a/**/),* b >c+d~e/deep/f,100%{v:U+123 1 2em t a(2%, var(--a)) -b() url(..) -foo-bar !important}');
module.exports = parser.parse.bind(parser);
var List = require('../utils/list');
var cmpChar = require('../scanner').cmpChar;
var TYPE = require('../scanner').TYPE;
var cmpChar = require('../tokenizer').cmpChar;
var TYPE = require('../tokenizer').TYPE;

@@ -21,12 +21,8 @@ var WHITESPACE = TYPE.Whitespace;

var ABSOLUTE = false;
var RELATIVE = true;
var ALLOW_OF_CLAUSE = true;
var DISALLOW_OF_CLAUSE = false;
var DISALLOW_VAR = false;
var DISALLOW_COMBINATORS = true;
function singleIdentifier() {
return new List().appendData(
this.Identifier(DISALLOW_VAR)
this.Identifier()
);

@@ -37,3 +33,3 @@ }

return new List().appendData(
this.SelectorList(ABSOLUTE)
this.SelectorList()
);

@@ -44,9 +40,9 @@ }

return new List().appendData(
this.SelectorList(RELATIVE)
this.SelectorList()
);
}
function compoundSelectorList() {
function compoundSelector() {
return new List().appendData(
this.Selector(ABSOLUTE, DISALLOW_COMBINATORS)
this.Selector()
);

@@ -69,5 +65,5 @@ }

var children = new List();
var wasSpace = false;
var nonSpaceOperator = false;
var prevNonSpaceOperator = false;
var space = null;
var nonWSOperator = false;
var prevNonWSOperator = false;
var child;

@@ -81,4 +77,3 @@

case WHITESPACE:
wasSpace = true;
this.scanner.next();
space = this.WhiteSpace();
continue;

@@ -91,8 +86,8 @@

case NUMBERSIGN:
child = this.Hash();
child = this.HexColor();
break;
case COMMA:
wasSpace = false;
nonSpaceOperator = true;
space = null;
nonWSOperator = true;
child = this.Operator();

@@ -104,18 +99,6 @@ break;

case PLUSSIGN:
case HYPHENMINUS:
child = this.Operator();
break;
case HYPHENMINUS:
if (this.scanner.lookupType(1) === IDENTIFIER) {
if (this.scanner.lookupType(2) === LEFTPARENTHESIS) {
child = this.Function(scope, defaultSequence);
} else {
child = this.Identifier(DISALLOW_VAR);
}
} else {
child = this.Operator();
}
break;
case LEFTPARENTHESIS:

@@ -145,3 +128,2 @@ child = this.Parentheses(defaultSequence);

child = this.Number();
break;
}

@@ -163,3 +145,3 @@

} else {
child = this.Identifier(DISALLOW_VAR);
child = this.Identifier();
}

@@ -173,14 +155,14 @@

if (wasSpace) {
wasSpace = false;
if (space !== null) {
// ignore spaces around operator
if (!nonSpaceOperator && !prevNonSpaceOperator) {
children.appendData(this.SPACE_NODE);
if (!nonWSOperator && !prevNonWSOperator) {
children.appendData(space);
}
space = null;
}
children.appendData(child);
prevNonSpaceOperator = nonSpaceOperator;
nonSpaceOperator = false;
prevNonWSOperator = nonWSOperator;
nonWSOperator = false;
}

@@ -195,3 +177,3 @@

relativeSelectorList: relativeSelectorList,
compoundSelectorList: compoundSelectorList,
compoundSelector: compoundSelector,
nth: nth,

@@ -198,0 +180,0 @@ nthWithOfClause: nthWithOfClause,

@@ -1,3 +0,4 @@

var TYPE = require('../../scanner').TYPE;
var TYPE = require('../../tokenizer').TYPE;
var IDENTIFIER = TYPE.Identifier;
var SEMICOLON = TYPE.Semicolon;

@@ -7,3 +8,3 @@ var COMMERCIALAT = TYPE.CommercialAt;

var RIGHTCURLYBRACKET = TYPE.RightCurlyBracket;
var DISALLOW_VAR = false;
var BALANCED = true;

@@ -35,8 +36,12 @@ function isBlockAtrule() {

name = this.readIdent(DISALLOW_VAR);
name = this.scanner.consume(IDENTIFIER);
nameLowerCase = name.toLowerCase();
this.readSC();
expression = this.AtruleExpression(name);
this.readSC();
if (this.parseAtruleExpression) {
expression = this.AtruleExpression(name);
this.readSC();
} else {
expression = this.Raw(BALANCED, SEMICOLON, LEFTCURLYBRACKET);
}

@@ -43,0 +48,0 @@ if (this.atrule.hasOwnProperty(nameLowerCase)) {

var List = require('../../utils/list');
module.exports = function AtruleExpression(name) {
var start = this.scanner.tokenStart;
var end = start;
var children = null;
name = name.toLowerCase();
if (name !== null) {
name = name.toLowerCase();
}

@@ -14,2 +14,3 @@ // custom consumer

children = this.atrule[name].expression.call(this);
if (children instanceof List === false) {

@@ -29,11 +30,7 @@ return children;

if (this.needPositions) {
end = children.last().loc.end.offset;
}
return {
type: 'AtruleExpression',
loc: this.getLocation(start, end),
loc: this.getLocationFromList(children),
children: children
};
};
var List = require('../../utils/list');
var TYPE = require('../../scanner').TYPE;
var TYPE = require('../../tokenizer').TYPE;

@@ -4,0 +4,0 @@ var WHITESPACE = TYPE.Whitespace;

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

var TYPE = require('../../scanner').TYPE;
var TYPE = require('../../tokenizer').TYPE;
var LEFTSQUAREBRACKET = TYPE.LeftSquareBracket;

@@ -10,3 +10,3 @@ var RIGHTSQUAREBRACKET = TYPE.RightSquareBracket;

var start = this.scanner.tokenStart;
var children;
var children = null;

@@ -13,0 +13,0 @@ this.scanner.eat(LEFTSQUAREBRACKET);

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

var TYPE = require('../../scanner').TYPE;
var TYPE = require('../../tokenizer').TYPE;

@@ -3,0 +3,0 @@ var PLUSSIGN = TYPE.PlusSign;

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

var TYPE = require('../../scanner').TYPE;
var TYPE = require('../../tokenizer').TYPE;

@@ -3,0 +3,0 @@ var ASTERISK = TYPE.Asterisk;

@@ -1,3 +0,4 @@

var TYPE = require('../../scanner').TYPE;
var TYPE = require('../../tokenizer').TYPE;
var IDENTIFIER = TYPE.Identifier;
var COLON = TYPE.Colon;

@@ -16,14 +17,27 @@ var EXCLAMATIONMARK = TYPE.ExclamationMark;

var start = this.scanner.tokenStart;
var type;
var prefix = 0;
for (; type = this.scanner.tokenType; this.scanner.next()) {
if (type !== SOLIDUS &&
type !== ASTERISK &&
type !== DOLLARSIGN) {
// hacks
switch (this.scanner.tokenType) {
case ASTERISK:
case DOLLARSIGN:
prefix = 1;
break;
}
// TODO: not sure we should support this hack
case SOLIDUS:
prefix = this.scanner.lookupType(1) === SOLIDUS ? 2 : 1;
break;
}
this.scanIdent(true);
if (this.scanner.lookupType(prefix) === HYPHENMINUS) {
prefix++;
}
if (prefix) {
this.scanner.skip(prefix);
}
this.scanner.eat(IDENTIFIER);
return this.scanner.substrToCursor(start);

@@ -44,2 +58,8 @@ }

function isCustomProperty(name) {
return name.length >= 2 &&
name.charCodeAt(0) === HYPHENMINUS &&
name.charCodeAt(1) === HYPHENMINUS;
}
module.exports = function Declaration() {

@@ -54,8 +74,6 @@ var start = this.scanner.tokenStart;

if (property.length >= 2 &&
property.charCodeAt(0) === HYPHENMINUS &&
property.charCodeAt(1) === HYPHENMINUS) {
if (isCustomProperty(property) ? this.parseCustomProperty : this.parseValue) {
value = this.Value(property);
} else {
value = this.Raw(BALANCED, SEMICOLON, EXCLAMATIONMARK);
} else {
value = this.Value(property);
}

@@ -75,4 +93,4 @@

this.scanner.tokenType !== SEMICOLON &&
this.scanner.tokenType !== RIGHTCURLYBRACKET &&
this.scanner.tokenType !== RIGHTPARENTHESIS) {
this.scanner.tokenType !== RIGHTPARENTHESIS &&
this.scanner.tokenType !== RIGHTCURLYBRACKET) {
this.scanner.error();

@@ -79,0 +97,0 @@ }

var List = require('../../utils/list');
var TYPE = require('../../scanner').TYPE;
var TYPE = require('../../tokenizer').TYPE;

@@ -9,3 +9,2 @@ var WHITESPACE = TYPE.Whitespace;

module.exports = function DeclarationList() {
var start = this.scanner.tokenStart;
var children = new List();

@@ -29,5 +28,5 @@

type: 'DeclarationList',
loc: this.getLocation(start, this.scanner.tokenStart),
loc: this.getLocationFromList(children),
children: children
};
};

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

var NUMBER = require('../../scanner').TYPE.Number;
var NUMBER = require('../../tokenizer').TYPE.Number;

@@ -3,0 +3,0 @@ // special reader for units to avoid adjoined IE hacks (i.e. '1px\9')

@@ -1,6 +0,6 @@

var TYPE = require('../../scanner').TYPE;
var TYPE = require('../../tokenizer').TYPE;
var IDENTIFIER = TYPE.Identifier;
var LEFTPARENTHESIS = TYPE.LeftParenthesis;
var RIGHTPARENTHESIS = TYPE.RightParenthesis;
var DISALLOW_VAR = false;

@@ -10,3 +10,3 @@ // ident '(' <sequence> ')'

var start = this.scanner.tokenStart;
var name = this.readIdent(DISALLOW_VAR);
var name = this.scanner.consume(IDENTIFIER);
var nameLowerCase = name.toLowerCase();

@@ -13,0 +13,0 @@ var children;

@@ -1,10 +0,10 @@

module.exports = function Identifier(varAllowed) {
var start = this.scanner.tokenStart;
var name = this.readIdent(varAllowed);
var TYPE = require('../../tokenizer').TYPE;
var IDENTIFIER = TYPE.Identifier;
module.exports = function Identifier() {
return {
type: 'Identifier',
loc: this.getLocation(start, this.scanner.tokenStart),
name: name
loc: this.getLocation(this.scanner.tokenStart, this.scanner.tokenEnd),
name: this.scanner.consume(IDENTIFIER)
};
};

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

var TYPE = require('../../scanner').TYPE;
var TYPE = require('../../tokenizer').TYPE;

@@ -9,3 +9,2 @@ var IDENTIFIER = TYPE.Identifier;

var SOLIDUS = TYPE.Solidus;
var DISALLOW_VAR = false;

@@ -20,3 +19,3 @@ module.exports = function MediaFeature() {

name = this.readIdent(DISALLOW_VAR);
name = this.scanner.consume(IDENTIFIER);
this.readSC();

@@ -41,3 +40,3 @@

case IDENTIFIER:
value = this.Identifier(DISALLOW_VAR);
value = this.Identifier();

@@ -44,0 +43,0 @@ break;

var List = require('../../utils/list');
var TYPE = require('../../scanner').TYPE;
var TYPE = require('../../tokenizer').TYPE;

@@ -8,3 +8,2 @@ var WHITESPACE = TYPE.Whitespace;

var LEFTPARENTHESIS = TYPE.LeftParenthesis;
var DISALLOW_VAR = false;

@@ -14,7 +13,5 @@ module.exports = function MediaQuery() {

var start = this.scanner.tokenStart;
var end = start;
var children = new List();
var wasSpace = false;
var child = null;
var space = null;

@@ -24,24 +21,15 @@ scan:

switch (this.scanner.tokenType) {
case WHITESPACE:
wasSpace = true;
case COMMENT:
this.scanner.next();
continue;
case COMMENT:
this.scanner.next();
case WHITESPACE:
space = this.WhiteSpace();
continue;
case IDENTIFIER:
if (!children.isEmpty() && !wasSpace) {
this.scanner.error('Space is expected');
}
child = this.Identifier(DISALLOW_VAR);
child = this.Identifier();
break;
case LEFTPARENTHESIS:
if (!children.isEmpty() && !wasSpace) {
this.scanner.error('Space is expected');
}
child = this.MediaFeature();

@@ -54,2 +42,7 @@ break;

if (space !== null) {
children.appendData(space);
space = null;
}
children.appendData(child);

@@ -62,11 +55,7 @@ }

if (this.needPositions) {
end = child.loc.end.offset;
}
return {
type: 'MediaQuery',
loc: this.getLocation(start, end),
loc: this.getLocationFromList(children),
children: children
};
};
var List = require('../../utils/list');
var COMMA = require('../../scanner').TYPE.Comma;
var COMMA = require('../../tokenizer').TYPE.Comma;
module.exports = function MediaQueryList(relative) {
var children = new List();
this.readSC();
var start = this.scanner.tokenStart;
var end = start;
var children = new List();
var mediaQuery = null;
while (!this.scanner.eof) {
mediaQuery = this.MediaQuery(relative);
children.appendData(mediaQuery);
children.appendData(this.MediaQuery(relative));

@@ -23,11 +19,7 @@ if (this.scanner.tokenType !== COMMA) {

if (this.needPositions) {
end = mediaQuery.children.last().loc.end.offset;
}
return {
type: 'MediaQueryList',
loc: this.getLocation(start, end),
loc: this.getLocationFromList(children),
children: children
};
};

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

var DISALLOW_VAR = false;
// https://drafts.csswg.org/css-syntax-3/#the-anb-type

@@ -8,3 +6,3 @@ module.exports = function Nth(allowOfClause) {

var start = this.scanner.tokenStart;
var end;
var end = start;
var selector = null;

@@ -14,4 +12,3 @@ var query;

if (this.scanner.lookupValue(0, 'odd') || this.scanner.lookupValue(0, 'even')) {
query = this.Identifier(DISALLOW_VAR);
end = this.scanner.tokenStart;
query = this.Identifier();
} else {

@@ -29,3 +26,3 @@ query = this.AnPlusB();

if (this.needPositions) {
end = selector.children.last().children.last().loc.end.offset;
end = selector.children.last().loc.end.offset;
}

@@ -32,0 +29,0 @@ } else {

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

var NUMBER = require('../../scanner').TYPE.Number;
var NUMBER = require('../../tokenizer').TYPE.Number;

@@ -3,0 +3,0 @@ module.exports = function Number() {

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

var TYPE = require('../../scanner').TYPE;
var TYPE = require('../../tokenizer').TYPE;
var LEFTPARENTHESIS = TYPE.LeftParenthesis;

@@ -3,0 +3,0 @@ var RIGHTPARENTHESIS = TYPE.RightParenthesis;

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

var TYPE = require('../../scanner').TYPE;
var TYPE = require('../../tokenizer').TYPE;

@@ -3,0 +3,0 @@ var NUMBER = TYPE.Number;

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

var isNumber = require('../../scanner').isNumber;
var TYPE = require('../../scanner').TYPE;
var isNumber = require('../../tokenizer').isNumber;
var TYPE = require('../../tokenizer').TYPE;
var NUMBER = TYPE.Number;

@@ -4,0 +4,0 @@ var SOLIDUS = TYPE.Solidus;

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

var TYPE = require('../../scanner').TYPE;
var TYPE = require('../../tokenizer').TYPE;

@@ -15,11 +15,16 @@ var WHITESPACE = TYPE.Whitespace;

var popType = 0;
var type = 0;
if (balanced) {
scan:
for (; !this.scanner.eof; this.scanner.next()) {
switch (this.scanner.tokenType) {
for (var i = 0; type = this.scanner.lookupType(i); i++) {
if (popType === 0) {
if (type === endTokenType1 ||
type === endTokenType2) {
break scan;
}
}
switch (type) {
case popType:
if (stack.length === 0) {
break scan;
}
popType = stack.pop();

@@ -31,3 +36,4 @@ break;

case RIGHTSQUAREBRACKET:
if (stack.length !== 0) {
if (popType !== 0) {
this.scanner.skip(i);
this.scanner.error();

@@ -51,15 +57,6 @@ }

break;
case endTokenType1:
case endTokenType2:
if (stack.length === 0) {
break scan;
}
break;
}
}
} else {
for (; !this.scanner.eof; this.scanner.next()) {
var type = this.scanner.tokenType;
for (var i = 0; type = this.scanner.lookupType(i); i++) {
if (type === WHITESPACE ||

@@ -73,2 +70,8 @@ type === endTokenType1 ||

this.scanner.skip(i);
if (popType !== 0) {
this.scanner.eat(popType);
}
return {

@@ -75,0 +78,0 @@ type: 'Raw',

@@ -0,4 +1,8 @@

var TYPE = require('../../tokenizer').TYPE;
var LEFTCURLYBRACKET = TYPE.LeftCurlyBracket;
var BALANCED = true;
module.exports = function Rule() {
var start = this.scanner.tokenStart;
var selector = this.SelectorList();
var selector = this.parseSelector ? this.SelectorList() : this.Raw(BALANCED, LEFTCURLYBRACKET, 0);
var block = this.Block(this.Declaration);

@@ -5,0 +9,0 @@

var List = require('../../utils/list');
var TYPE = require('../../scanner').TYPE;
var DESCENDANT_COMBINATOR = {};
var TYPE = require('../../tokenizer').TYPE;

@@ -20,14 +19,10 @@ var WHITESPACE = TYPE.Whitespace;

module.exports = function Selector(relative, disallowCombinators) {
this.readSC();
var start = this.scanner.tokenStart;
var end = start;
module.exports = function Selector() {
var children = new List();
var combinator = null;
var combinatorOffset = -1;
var space = null;
var child = null;
var ignoreWSAfter = false;
var ignoreWS = false;
relative = relative || false;
disallowCombinators = disallowCombinators || false;
this.readSC();

@@ -38,7 +33,2 @@ scan:

case COMMENT:
if (disallowCombinators) {
this.readSC();
break scan;
}
this.scanner.next();

@@ -48,12 +38,6 @@ continue;

case WHITESPACE:
if (disallowCombinators) {
this.readSC();
break scan;
}
if (combinator === null && children.head !== null) {
combinatorOffset = this.scanner.tokenStart;
combinator = DESCENDANT_COMBINATOR;
if (ignoreWS) {
this.scanner.next();
} else {
this.scanner.next();
space = this.WhiteSpace();
}

@@ -65,23 +49,21 @@ continue;

case TILDE:
case SOLIDUS:
if (disallowCombinators ||
(children.head === null && !relative) || // combinator in the beginning
(combinator !== null && combinator !== DESCENDANT_COMBINATOR)) {
this.scanner.error('Unexpected combinator');
}
space = null;
ignoreWSAfter = true;
child = this.Combinator();
break;
combinatorOffset = this.scanner.tokenStart;
combinator = this.Combinator();
continue;
case SOLIDUS: // /deep/
child = this.Combinator();
break;
case FULLSTOP:
child = this.Class();
child = this.ClassSelector();
break;
case LEFTSQUAREBRACKET:
child = this.Attribute();
child = this.AttributeSelector();
break;
case NUMBERSIGN:
child = this.Id();
child = this.IdSelector();
break;

@@ -91,5 +73,5 @@

if (this.scanner.lookupType(1) === COLON) {
child = this.PseudoElement();
child = this.PseudoElementSelector();
} else {
child = this.PseudoClass();
child = this.PseudoClassSelector();
}

@@ -102,21 +84,3 @@

case VERTICALLINE:
var idx =
this.scanner.tokenType === VERTICALLINE ? 1 :
this.scanner.lookupType(1) === VERTICALLINE ? 2 :
0;
switch (this.scanner.lookupType(idx)) {
case IDENTIFIER:
child = this.Type();
break;
case ASTERISK:
child = this.Universal();
break;
default:
this.scanner.skip(idx);
this.scanner.error('Identifier or asterisk is expected');
}
child = this.TypeSelector();
break;

@@ -132,18 +96,13 @@

if (combinator !== null) {
// create descendant combinator on demand to avoid garbage
if (combinator === DESCENDANT_COMBINATOR) {
combinator = {
type: 'Combinator',
loc: this.getLocation(combinatorOffset, combinatorOffset + 1),
name: ' '
};
}
children.appendData(combinator);
combinator = null;
if (space !== null) {
children.appendData(space);
space = null;
}
children.appendData(child);
end = this.scanner.tokenStart;
if (ignoreWSAfter) {
ignoreWSAfter = false;
ignoreWS = true;
}
}

@@ -156,11 +115,7 @@

if (combinator !== null && combinator !== DESCENDANT_COMBINATOR) {
this.scanner.error('Unexpected combinator', combinatorOffset);
}
return {
type: 'Selector',
loc: this.getLocation(start, end),
loc: this.getLocationFromList(children),
children: children
};
};
var List = require('../../utils/list');
var COMMA = require('../../scanner').TYPE.Comma;
var TYPE = require('../../tokenizer').TYPE;
module.exports = function SelectorList(relative) {
this.readSC();
var COMMA = TYPE.Comma;
var LEFTCURLYBRACKET = TYPE.LeftCurlyBracket;
var BALANCED = true;
var start = this.scanner.tokenStart;
var end = start;
module.exports = function SelectorList() {
var children = new List();
var selector = null;
this.readSC();
while (!this.scanner.eof) {
selector = this.Selector(relative);
children.appendData(selector);
children.appendData(this.parseSelector
? this.Selector()
: this.Raw(BALANCED, COMMA, LEFTCURLYBRACKET)
);
if (this.needPositions) {
end = selector.children.last().loc.end.offset;
}
if (this.scanner.tokenType === COMMA) {

@@ -30,5 +29,5 @@ this.scanner.next();

type: 'SelectorList',
loc: this.getLocation(start, end),
loc: this.getLocationFromList(children),
children: children
};
};

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

var STRING = require('../../scanner').TYPE.String;
var STRING = require('../../tokenizer').TYPE.String;

@@ -3,0 +3,0 @@ module.exports = function String() {

var List = require('../../utils/list');
var TYPE = require('../../scanner').TYPE;
var TYPE = require('../../tokenizer').TYPE;

@@ -4,0 +4,0 @@ var WHITESPACE = TYPE.Whitespace;

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

var isHex = require('../../scanner').isHex;
var TYPE = require('../../scanner').TYPE;
var isHex = require('../../tokenizer').isHex;
var TYPE = require('../../tokenizer').TYPE;

@@ -4,0 +4,0 @@ var IDENTIFIER = TYPE.Identifier;

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

var TYPE = require('../../scanner').TYPE;
var TYPE = require('../../tokenizer').TYPE;

@@ -3,0 +3,0 @@ var STRING = TYPE.String;

@@ -1,12 +0,11 @@

var List = require('../../utils/list');
var endsWith = require('../../scanner').endsWith;
var TYPE = require('../../scanner').TYPE;
var endsWith = require('../../tokenizer').endsWith;
var TYPE = require('../../tokenizer').TYPE;
var WHITESPACE = TYPE.Whitespace;
var IDENTIFIER = TYPE.Identifier;
var COMMENT = TYPE.Comment;
var LEFTPARENTHESIS = TYPE.LeftParenthesis;
var RIGHTPARENTHESIS = TYPE.RightParenthesis;
var FULLSTOP = TYPE.FullStop;
var COLON = TYPE.Colon;
var SEMICOLON = TYPE.Semicolon;
var EXCLAMATIONMARK = TYPE.ExclamationMark;
var BALANCED = true;

@@ -16,3 +15,4 @@ module.exports = function Value(property) {

if (property !== null && endsWith(property, 'filter') && checkProgid.call(this)) {
return FilterValue.call(this);
this.readSC();
return this.Raw(BALANCED, SEMICOLON, EXCLAMATIONMARK);
}

@@ -30,21 +30,2 @@

function FilterValue() {
var start = this.scanner.tokenStart;
var children = new List();
var progid;
while (progid = checkProgid.call(this)) {
this.readSC();
children.appendData(this.Progid(progid));
}
this.readSC();
return {
type: 'Value',
loc: this.getLocation(start, this.scanner.tokenStart),
children: children
};
}
function findNonSCOffset(offset) {

@@ -67,3 +48,5 @@ for (var type; type = this.scanner.lookupType(offset); offset++) {

this.scanner.lookupValue(offset, 'dropshadow')) {
offset++;
if (this.scanner.lookupType(offset + 1) !== LEFTPARENTHESIS) {
return false; // fail
}
} else {

@@ -74,29 +57,5 @@ if (this.scanner.lookupValue(offset, 'progid') === false ||

}
offset += 2;
offset = findNonSCOffset.call(this, offset);
if (this.scanner.lookupValue(offset + 0, 'dximagetransform') === false ||
this.scanner.lookupType(offset + 1) !== FULLSTOP ||
this.scanner.lookupValue(offset + 2, 'microsoft') === false ||
this.scanner.lookupType(offset + 3) !== FULLSTOP ||
this.scanner.lookupType(offset + 4) !== IDENTIFIER) {
return false; // fail
}
offset += 5;
offset = findNonSCOffset.call(this, offset);
}
if (this.scanner.lookupType(offset) !== LEFTPARENTHESIS) {
return false; // fail
}
for (var type; type = this.scanner.lookupType(offset); offset++) {
if (type === RIGHTPARENTHESIS) {
return offset - startOffset + 1;
}
}
return false;
return true;
}

@@ -280,7 +280,7 @@ 'use strict';

while (cursor !== null) {
if (prevNew === true || cursor.prev === prevOld) {
if (cursor.prev === prevOld) {
cursor.prev = prevNew;
}
if (nextNew === true || cursor.next === nextOld) {
if (cursor.next === nextOld) {
cursor.next = nextNew;

@@ -287,0 +287,0 @@ }

'use strict';
var hasOwnProperty = Object.prototype.hasOwnProperty;
var knownKeywords = Object.create(null);
var knownProperties = Object.create(null);
var keywords = Object.create(null);
var properties = Object.create(null);
var HYPHENMINUS = 45; // '-'.charCodeAt()
function getVendorPrefix(string) {
if (string[0] === '-') {
// skip 2 chars to avoid wrong match with variables names
var secondDashIndex = string.indexOf('-', 2);
function isVariable(str, offset) {
return str.charCodeAt(offset) === HYPHENMINUS &&
str.charCodeAt(offset + 1) === HYPHENMINUS;
}
function getVendorPrefix(str, offset) {
if (str.charCodeAt(offset) === HYPHENMINUS) {
// vendor should contain at least one letter
var secondDashIndex = str.indexOf('-', offset + 2);
if (secondDashIndex !== -1) {
return string.substr(0, secondDashIndex + 1);
return str.substring(offset, secondDashIndex + 1);
}

@@ -21,18 +27,18 @@ }

function getKeywordInfo(keyword) {
if (hasOwnProperty.call(knownKeywords, keyword)) {
return knownKeywords[keyword];
if (hasOwnProperty.call(keywords, keyword)) {
return keywords[keyword];
}
var lowerCaseKeyword = keyword.toLowerCase();
var vendor = getVendorPrefix(lowerCaseKeyword);
var name = lowerCaseKeyword;
var name = keyword.toLowerCase();
if (vendor) {
name = name.substr(vendor.length);
if (hasOwnProperty.call(keywords, name)) {
return keywords[keyword] = keywords[name];
}
return knownKeywords[keyword] = Object.freeze({
var vendor = !isVariable(name, 0) ? getVendorPrefix(name, 0) : '';
return keywords[keyword] = Object.freeze({
vendor: vendor,
prefix: vendor,
name: name
name: name.substr(vendor.length)
});

@@ -42,30 +48,32 @@ }

function getPropertyInfo(property) {
if (hasOwnProperty.call(knownProperties, property)) {
return knownProperties[property];
if (hasOwnProperty.call(properties, property)) {
return properties[property];
}
var lowerCaseProperty = property.toLowerCase();
var hack = lowerCaseProperty[0];
var name = property;
var hack = property[0];
if (hack === '*' || hack === '_' || hack === '$') {
lowerCaseProperty = lowerCaseProperty.substr(1);
} else if (hack === '/' && property[1] === '/') {
if (hack === '/' && property[1] === '/') {
hack = '//';
lowerCaseProperty = lowerCaseProperty.substr(2);
} else {
} else if (hack !== '*' && hack !== '_' && hack !== '$') {
hack = '';
}
var vendor = getVendorPrefix(lowerCaseProperty);
var name = lowerCaseProperty;
var variable = isVariable(name, hack.length);
if (vendor) {
name = name.substr(vendor.length);
if (!variable) {
name = name.toLowerCase();
if (hasOwnProperty.call(properties, name)) {
return properties[property] = properties[name];
}
}
return knownProperties[property] = Object.freeze({
var vendor = !variable ? getVendorPrefix(name, hack.length) : '';
return properties[property] = Object.freeze({
hack: hack,
vendor: vendor,
prefix: hack + vendor,
name: name
name: name.substr(hack.length + vendor.length),
variable: variable
});

@@ -72,0 +80,0 @@ }

@@ -50,3 +50,3 @@ 'use strict';

if (node.expression && !node.expression.children.isEmpty()) {
if (node.expression !== null) {
result += ' ' + translate(node.expression);

@@ -77,8 +77,3 @@ }

while (cursor !== null) {
if (cursor.data.type === 'Combinator' && cursor.data.name === '/deep/') {
// add extra spaces around /deep/ combinator since comment beginning/ending may to be produced
result += ' ' + translate(cursor.data) + ' ';
} else {
result += translate(cursor.data);
}
result += translate(cursor.data);
cursor = cursor.next;

@@ -151,3 +146,3 @@ }

case 'Attribute':
case 'AttributeSelector':
var result = translate(node.name);

@@ -191,3 +186,3 @@ var flagsPrefix = ' ';

case 'MediaQuery':
return eachDelim(node.children, ' ');
return each(node.children);

@@ -202,18 +197,12 @@ case 'MediaFeature':

case 'Progid':
return node.value;
case 'Combinator':
return node.name;
case 'Type':
case 'TypeSelector':
return node.name;
case 'Universal':
return node.name;
case 'Identifier':
return node.name;
case 'PseudoClass':
case 'PseudoClassSelector':
return node.children !== null

@@ -223,3 +212,3 @@ ? ':' + node.name + '(' + each(node.children) + ')'

case 'PseudoElement':
case 'PseudoElementSelector':
return node.children !== null

@@ -229,6 +218,6 @@ ? '::' + node.name + '(' + each(node.children) + ')'

case 'Class':
case 'ClassSelector':
return '.' + node.name;
case 'Id':
case 'IdSelector':
return '#' + node.name;

@@ -239,3 +228,3 @@

case 'Hash':
case 'HexColor':
return '#' + node.value;

@@ -246,3 +235,3 @@

case 'An+B':
case 'AnPlusB':
var result = '';

@@ -289,4 +278,4 @@ var a = node.a !== null && node.a !== undefined;

case 'Space':
return ' ';
case 'WhiteSpace':
return node.value;

@@ -293,0 +282,0 @@ case 'Comment':

@@ -15,7 +15,2 @@ 'use strict';

if (chunk instanceof SourceNode) {
// this is a hack, because source maps doesn't support for 1(generated):N(original)
// if (chunk.merged) {
// fn('', chunk);
// }
walk(chunk, fn);

@@ -89,12 +84,2 @@ } else {

function createSourceNode(loc, children) {
if (loc.primary) {
// special marker node to add several references to original
// var merged = createSourceNode(loc.merged, []);
// merged.merged = true;
// children.unshift(merged);
// use recursion, because primary can also has a primary/merged loc
return createSourceNode(loc.primary, children);
}
return new SourceNode(

@@ -143,3 +128,3 @@ loc.start ? loc.start.line : null,

if (node.expression && !node.expression.children.isEmpty()) {
if (node.expression !== null) {
nodes.push(' ', translate(node.expression));

@@ -165,13 +150,4 @@ }

case 'Selector':
var nodes = node.children.map(function(node) {
// add extra spaces around /deep/ combinator since comment beginning/ending may to be produced
if (node.type === 'Combinator' && node.name === '/deep/') {
return ' ' + translate(node) + ' ';
}
return createSourceNode(node.loc, node.children.map(translate));
return translate(node);
});
return createSourceNode(node.loc, nodes);
case 'Block':

@@ -205,3 +181,3 @@ return createAnonymousSourceNode([

case 'Attribute':
case 'AttributeSelector':
var result = translate(node.name);

@@ -245,3 +221,3 @@ var flagsPrefix = ' ';

case 'MediaQuery':
return createAnonymousSourceNode(node.children.map(translate)).join(' ');
return each(node.children);

@@ -256,18 +232,12 @@ case 'MediaFeature':

case 'Progid':
return node.value;
case 'Combinator':
return node.name;
case 'Type':
case 'TypeSelector':
return node.name;
case 'Universal':
return node.name;
case 'Identifier':
return node.name;
case 'PseudoClass':
case 'PseudoClassSelector':
return node.children !== null

@@ -277,3 +247,3 @@ ? ':' + node.name + '(' + each(node.children) + ')'

case 'PseudoElement':
case 'PseudoElementSelector':
return node.children !== null

@@ -283,6 +253,6 @@ ? '::' + node.name + '(' + each(node.children) + ')'

case 'Class':
case 'ClassSelector':
return '.' + node.name;
case 'Id':
case 'IdSelector':
return '#' + node.name;

@@ -293,3 +263,3 @@

case 'Hash':
case 'HexColor':
return '#' + node.value;

@@ -300,3 +270,3 @@

case 'An+B':
case 'AnPlusB':
var result = '';

@@ -343,4 +313,4 @@ var a = node.a !== null && node.a !== undefined;

case 'Space':
return ' ';
case 'WhiteSpace':
return node.value;

@@ -347,0 +317,0 @@ case 'Comment':

@@ -208,3 +208,3 @@ 'use strict';

case 'Attribute':
case 'AttributeSelector':
walk.call(this, node.name);

@@ -216,3 +216,3 @@ if (node.value !== null) {

case 'PseudoClass':
case 'PseudoClassSelector':
if (node.children !== null) {

@@ -227,3 +227,3 @@ this['function'] = node;

case 'PseudoElement':
case 'PseudoElementSelector':
if (node.children !== null) {

@@ -283,23 +283,2 @@ this['function'] = node;

break;
// nothig to do with
// case 'Progid':
// case 'Property':
// case 'Combinator':
// case 'Dimension':
// case 'Hash':
// case 'Type':
// case 'Universal':
// case 'Identifier':
// case 'UnicodeRange':
// case 'An+B':
// case 'Class':
// case 'Id':
// case 'Percentage':
// case 'Space':
// case 'Number':
// case 'String':
// case 'Operator':
// case 'Raw':
// case 'Ratio':
}

@@ -306,0 +285,0 @@ }

{
"name": "css-tree",
"version": "1.0.0-alpha14",
"version": "1.0.0-alpha15",
"description": "Fast detailed CSS parser",

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

@@ -17,2 +17,14 @@ <img align="right" width="111" height="111"

- [Parsing CSS into AST](docs/parsing.md)
- [AST format](docs/ast.md)
- [Translate AST to string](docs/translate.md)
- [AST traversal](docs/traversal.md)
- [Utils to work with AST](docs/utils.md)
- [Working with syntax](docs/syntax.md)
- API references:
- [Tokenizer](docs/Tokenizer.md)
- [Parser](docs/Parser.md)
- [Lexer](docs/Lexer.md)
- [List](docs/List.md)
Docs and tools:

@@ -44,194 +56,14 @@

var csstree = require('css-tree');
var ast = csstree.parse('.example { world: "!" }');
csstree.walk(csstree.parse('.a { color: red; }'), function(node) {
console.log(node.type);
});
// StyleSheet
// Rule
// SelectorList
// Selector
// Class
// Block
// Declaration
// Value
// Identifier
```
## API
### parse(source[, options])
Parses CSS to AST.
> NOTE: Currenly parser omits redundant separators, spaces and comments (except exclamation comments, i.e. `/*! comment */`) on AST build.
Options:
- `context` String – parsing context, useful when some part of CSS is parsing (see below)
- `atrule` String – make sense for `atruleExpression` context to apply some atrule specific parse rules
- `property` String – make sense for `value` context to apply some property specific parse rules
- `positions` Boolean – should AST contains node position or not, store data in `info` property of nodes (`false` by default)
- `filename` String – filename of source that adds to info when `positions` is true, uses for source map generation (`<unknown>` by default)
- `line` Number – initial line number, useful when parse fragment of CSS to compute correct positions
- `column` Number – initial column number, useful when parse fragment of CSS to compute correct positions
Contexts:
- `stylesheet` (default) – regular stylesheet, should be suitable in most cases
- `atrule` – at-rule (e.g. `@media screen, print { ... }`)
- `atruleExpression` – at-rule expression (`screen, print` for example above)
- `rule` – rule (e.g. `.foo, .bar:hover { color: red; border: 1px solid black; }`)
- `selectorList` – selector group (`.foo, .bar:hover` for rule example)
- `selector` – selector (`.foo` or `.bar:hover` for rule example)
- `block` – block with curly braces (`{ color: red; border: 1px solid black; }` for rule example)
- `declarationList` – block content w/o curly braces (`color: red; border: 1px solid black;` for rule example), useful to parse HTML `style` attribute value
- `declaration` – declaration (`color: red` or `border: 1px solid black` for rule example)
- `value` – declaration value (`red` or `1px solid black` for rule example)
```js
// simple parsing with no options
var ast = csstree.parse('.example { color: red }');
// parse with options
var ast = csstree.parse('.foo.bar', {
context: 'simpleSelector',
positions: true
});
```
### clone(ast)
Make an AST node deep copy.
```js
var orig = csstree.parse('.test { color: red }');
var copy = csstree.clone(orig);
csstree.walk(copy, function(node) {
if (node.type === 'Class') {
node.name = 'replaced';
csstree.walk(ast, function(node) {
if (node.type === 'Class' && node.name === 'example') {
node.name = 'hello';
}
});
console.log(csstree.translate(orig));
// .test{color:red}
console.log(csstree.translate(copy));
// .replaced{color:red}
```
### translate(ast)
Converts AST to string.
```js
var ast = csstree.parse('.test { color: red }');
console.log(csstree.translate(ast));
// > .test{color:red}
// .hello{world:"!"}
```
### translateWithSourceMap(ast)
The same as `translate()` but also generates source map (nodes should contain positions in `info` property).
```js
var ast = csstree.parse('.test { color: red }', {
filename: 'my.css',
positions: true
});
console.log(csstree.translateWithSourceMap(ast));
// { css: '.test{color:red}', map: SourceMapGenerator {} }
```
### walk(ast, handler)
Visits each node of AST in natural way and calls handler for each one. `handler` receives three arguments:
- `node` – current AST node
- `item` – node wrapper when node is a list member; this wrapper contains references to `prev` and `next` nodes in list
- `list` – reference to list when node is a list member; it's useful for operations on list like `remove()` or `insert()`
Context for handler an object, that contains references to some parent nodes:
- `root` – refers to `ast` root node (actually it's a node passed to walker function)
- `stylesheet` – refers to `StyleSheet` node, usually it's a root node
- `atruleExpression` – refers to `AtruleExpression` node if any
- `rule` – refers to closest `Rule` node if any
- `selector` – refers to `SelectorList` node if any
- `block` - refers to closest `Block` node if any
- `declaration` – refers to `Declaration` node if any
- `function` – refers to closest `Function`, `PseudoClass` or `PseudoElement` node if current node inside one of them
```js
// collect all urls in declarations
var csstree = require('./lib/index.js');
var urls = [];
var ast = csstree.parse(`
@import url(import.css);
.foo { background: url('foo.jpg'); }
.bar { background-image: url(bar.png); }
`);
csstree.walk(ast, function(node) {
if (this.declaration !== null && node.type === 'Url') {
var value = node.value;
if (value.type === 'Raw') {
urls.push(value.value);
} else {
urls.push(value.value.substr(1, value.value.length - 2));
}
}
});
console.log(urls);
// [ 'foo.jpg', 'bar.png' ]
```
### walkUp(ast, handler)
Same as `walk()` but visits nodes in down-to-top order. Useful to process deepest nodes and then their parents.
```js
var csstree = require('css-tree');
var ast = csstree.parse('.a { color: red; }');
csstree.walk(ast, function(node) {
console.log(node.type);
});
// StyleSheet
// Rule
// SelectorList
// Selector
// Class
// Block
// Declaration
// Value
// Identifier
csstree.walkUp(ast, function(node) {
console.log(node.type);
});
// Class
// Selector
// SelectorList
// Identifier
// Value
// Declaration
// Block
// Rule
// StyleSheet
```
### walkRules(ast, handler)
Same as `walk()` but visits `Rule` and `Atrule` nodes only.
### walkRulesRight(ast, handler)
Same as `walkRules()` but visits nodes in reverse order (from last to first).
### walkDeclarations(ast, handler)
Visit all declarations.
## License

@@ -238,0 +70,0 @@

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