Comparing version 1.0.0-alpha10 to 1.0.0-alpha11
@@ -0,1 +1,29 @@ | ||
## 1.0.0-alpha11 (January 18, 2017) | ||
- Added support for `:matches(<selector-list>)` (#28) | ||
- Added support for `:has(<relative-selector-list>)` | ||
- Added support for `::slotted(<compound-selector>)` | ||
- Implemented `Brackets` node type | ||
- Implemented basic support for at-rule inside rule block (#24) | ||
- Renamed `Selector` node type to `SelectorList` | ||
- Renamed `SimpleSelector` node type to `Selector` | ||
- Renamed `UnicodeRange.name` property to `UnicodeRange.value` | ||
- Replaced `Negation` node type for regular `PseudoClass` | ||
- Unified name of node property to store nested nodes, it always `children` now: | ||
- `StyleSheet.rules` -> `StyleSheet.children` | ||
- `SelectorList.selectors` -> `SelectorList.children` | ||
- `Block.declarations` -> `Block.children` | ||
- `*.sequence` -> `*.children` | ||
- Fixed edge cases in parsing `Hex` and `UnicodeRange` when number not an integer | ||
- Changed `nth-` pseudos parsing | ||
- Implemented `An+B` node type to represent expressions like `2n + 1` or `-3n` | ||
- Fixed edge cases when `a` or `b` is not an integer | ||
- Changed `odd` and `even` keywords processing, keywords are storing as `Identifier` node type now | ||
- Changed `Nth` node type format to store a `nth`-query and an optional `selector` | ||
- Implemented `of` clause for `nth-` pseudos (a.e. `:nth-child(2n + 1 of li, img)`) | ||
- Limited `Nth` parsing rules to `:nth-child()`, `:nth-last-child()`, `:nth-of-type()` and `:nth-last-of-type()` pseudos | ||
- Changed the way to store locations | ||
- Renamed `info` node property to `loc` | ||
- Changed format of `loc` to store `start` and `end` positions | ||
## 1.0.0-alpha10 (January 11, 2017) | ||
@@ -2,0 +30,0 @@ |
@@ -0,1 +1,3 @@ | ||
'use strict'; | ||
var walkers = require('./utils/walk'); | ||
@@ -2,0 +4,0 @@ var names = require('./utils/names'); |
@@ -8,4 +8,4 @@ 'use strict'; | ||
var cmpChar = Scanner.cmpChar; | ||
var cmpStr = Scanner.cmpStr; | ||
var endsWith = Scanner.endsWith; | ||
var isNumber = Scanner.isNumber; | ||
var isHex = Scanner.isHex; | ||
@@ -17,2 +17,5 @@ var needPositions; | ||
var SPACE_NODE = { type: 'Space' }; | ||
var NESTED = true; | ||
var ABSOLUTE = false; | ||
var RELATIVE = true; | ||
@@ -56,3 +59,5 @@ var WHITESPACE = Scanner.TYPE.Whitespace; | ||
url: getUri, | ||
not: getNotFunction | ||
not: getSelectorListFunction, | ||
matches: getSelectorListFunction, | ||
has: getRelativeSelectorListFunction | ||
}; | ||
@@ -70,4 +75,4 @@ var SCOPE_VALUE = { | ||
rule: getRule, | ||
selectorList: getSelectorList, | ||
selector: getSelector, | ||
simpleSelector: getSimpleSelector, | ||
block: getBlock, | ||
@@ -78,10 +83,7 @@ declaration: getDeclaration, | ||
function isNumber(code) { | ||
return code >= 48 && code <= 57; | ||
} | ||
function getInfo(start) { | ||
function getLocation(start, end) { | ||
if (needPositions) { | ||
return scanner.getLocation( | ||
start !== undefined ? start : scanner.tokenStart, | ||
return scanner.getLocationRange( | ||
start, | ||
end, | ||
filename | ||
@@ -96,3 +98,3 @@ ); | ||
var start = scanner.tokenStart; | ||
var rules = new List(); | ||
var children = new List(); | ||
var child; | ||
@@ -132,3 +134,3 @@ | ||
rules.appendData(child); | ||
children.appendData(child); | ||
} | ||
@@ -138,4 +140,4 @@ | ||
type: 'StyleSheet', | ||
info: getInfo(start), | ||
rules: rules | ||
loc: getLocation(start, scanner.tokenStart), | ||
children: children | ||
}; | ||
@@ -160,8 +162,10 @@ } | ||
function getAtruleExpression() { | ||
var start = scanner.tokenStart; | ||
var sequence = new List(); | ||
var start; | ||
var children = new List(); | ||
var wasSpace = false; | ||
var lastNonSpace = null; | ||
var child; | ||
readSC(); | ||
start = scanner.tokenStart; | ||
@@ -206,6 +210,7 @@ scan: | ||
wasSpace = false; | ||
sequence.appendData(SPACE_NODE); | ||
children.appendData(SPACE_NODE); | ||
} | ||
sequence.appendData(child); | ||
lastNonSpace = scanner.tokenStart; | ||
children.appendData(child); | ||
} | ||
@@ -215,4 +220,4 @@ | ||
type: 'AtruleExpression', | ||
info: getInfo(start), | ||
sequence: sequence | ||
loc: getLocation(start, lastNonSpace !== null ? lastNonSpace : scanner.tokenStart), | ||
children: children | ||
}; | ||
@@ -222,11 +227,11 @@ } | ||
function getAtrule() { | ||
var start = scanner.tokenStart; | ||
var name; | ||
var expression; | ||
var block = null; | ||
scanner.eat(COMMERCIALAT); | ||
var node = { | ||
type: 'Atrule', | ||
info: getInfo(), | ||
name: readIdent(false), | ||
expression: getAtruleExpression(), | ||
block: null | ||
}; | ||
name = readIdent(false); | ||
expression = getAtruleExpression(); | ||
@@ -241,5 +246,5 @@ switch (scanner.tokenType) { | ||
node.block = isBlockAtrule() | ||
block = isBlockAtrule() | ||
? getBlock() | ||
: getStylesheet(true); | ||
: getStylesheet(NESTED); | ||
@@ -252,24 +257,32 @@ scanner.eat(RIGHTCURLYBRACKET); | ||
return node; | ||
return { | ||
type: 'Atrule', | ||
loc: getLocation(start, scanner.tokenStart), | ||
name: name, | ||
expression: expression, | ||
block: block | ||
}; | ||
} | ||
function getRule() { | ||
var node = { | ||
type: 'Rule', | ||
info: getInfo(), | ||
selector: getSelector(), | ||
block: null | ||
}; | ||
var start = scanner.tokenStart; | ||
var selector = getSelectorList(); | ||
var block; | ||
scanner.eat(LEFTCURLYBRACKET); | ||
node.block = getBlock(); | ||
block = getBlock(); | ||
scanner.eat(RIGHTCURLYBRACKET); | ||
return node; | ||
return { | ||
type: 'Rule', | ||
loc: getLocation(start, scanner.tokenStart), | ||
selector: selector, | ||
block: block | ||
}; | ||
} | ||
function getSelector() { | ||
function getSelectorList(nested, relative) { | ||
var start = scanner.tokenStart; | ||
var selectors = new List(); | ||
var simpleSelector; | ||
var children = new List(); | ||
var selector; | ||
var lastComma = -2; | ||
@@ -281,4 +294,14 @@ | ||
case LEFTCURLYBRACKET: | ||
if (nested) { | ||
scanner.error(); | ||
} | ||
break scan; | ||
case RIGHTPARENTHESIS: | ||
if (!nested) { | ||
scanner.error(); | ||
} | ||
break scan; | ||
case COMMA: | ||
@@ -295,6 +318,6 @@ if (lastComma !== -1) { | ||
lastComma = -1; | ||
simpleSelector = getSimpleSelector(); | ||
selectors.appendData(simpleSelector); | ||
selector = getSelector(nested, relative); | ||
children.appendData(selector); | ||
if (simpleSelector.sequence.isEmpty()) { | ||
if (selector.children.isEmpty()) { | ||
scanner.error('Simple selector expected'); | ||
@@ -310,11 +333,11 @@ } | ||
return { | ||
type: 'Selector', | ||
info: getInfo(start), | ||
selectors: selectors | ||
type: 'SelectorList', | ||
loc: getLocation(start, scanner.tokenStart), | ||
children: children | ||
}; | ||
} | ||
function getSimpleSelector(nested) { | ||
function getSelector(nested, relative) { | ||
var start = scanner.tokenStart; | ||
var sequence = new List(); | ||
var children = new List(); | ||
var combinator = null; | ||
@@ -349,3 +372,3 @@ var combinatorOffset = -1; | ||
case WHITESPACE: | ||
if (combinator === null && sequence.head !== null) { | ||
if (combinator === null && children.head !== null) { | ||
combinatorOffset = scanner.tokenStart; | ||
@@ -362,3 +385,3 @@ combinator = DESCENDANT_COMBINATOR; | ||
case SOLIDUS: | ||
if ((sequence.head === null) || // combinator in the beginning | ||
if ((children.head === null && !relative) || // combinator in the beginning | ||
(combinator !== null && combinator !== DESCENDANT_COMBINATOR)) { | ||
@@ -408,3 +431,3 @@ scanner.error('Unexpected combinator'); | ||
type: 'Combinator', | ||
info: getInfo(combinatorOffset), | ||
loc: getLocation(combinatorOffset, combinatorOffset + 1), | ||
name: ' ' | ||
@@ -414,7 +437,7 @@ }; | ||
sequence.appendData(combinator); | ||
children.appendData(combinator); | ||
combinator = null; | ||
} | ||
sequence.appendData(child); | ||
children.appendData(child); | ||
} | ||
@@ -427,11 +450,87 @@ | ||
return { | ||
type: 'SimpleSelector', | ||
info: getInfo(start), | ||
sequence: sequence | ||
type: 'Selector', | ||
loc: getLocation(start, scanner.tokenStart), | ||
children: children | ||
}; | ||
} | ||
function getCompoundSelector(nested) { | ||
var start = scanner.tokenStart; | ||
var children = new List(); | ||
var child; | ||
readSC(); | ||
scan: | ||
while (!scanner.eof) { | ||
switch (scanner.tokenType) { | ||
case COMMA: | ||
break scan; | ||
case LEFTCURLYBRACKET: | ||
if (nested) { | ||
scanner.error(); | ||
} | ||
break scan; | ||
case RIGHTPARENTHESIS: | ||
if (!nested) { | ||
scanner.error(); | ||
} | ||
break scan; | ||
case COMMENT: | ||
scanner.next(); | ||
continue; | ||
case WHITESPACE: | ||
readSC(); | ||
break scan; | ||
case FULLSTOP: | ||
child = getClass(); | ||
break; | ||
case LEFTSQUAREBRACKET: | ||
child = getAttribute(); | ||
break; | ||
case NUMBERSIGN: | ||
child = getId(); | ||
break; | ||
case COLON: | ||
child = getPseudo(); | ||
break; | ||
case HYPHENMINUS: | ||
case IDENTIFIER: | ||
case ASTERISK: | ||
case VERTICALLINE: | ||
child = getTypeOrUniversal(); | ||
break; | ||
default: | ||
scanner.error(); | ||
} | ||
children.appendData(child); | ||
} | ||
if (children.isEmpty()) { | ||
scanner.error('Simple selector expected'); | ||
} | ||
return { | ||
type: 'Selector', | ||
loc: getLocation(start, scanner.tokenStart), | ||
children: children | ||
}; | ||
} | ||
function getBlock() { | ||
var start = scanner.tokenStart; | ||
var declarations = new List(); | ||
var children = new List(); | ||
@@ -450,4 +549,8 @@ scan: | ||
case COMMERCIALAT: | ||
children.appendData(getAtrule()); | ||
break; | ||
default: | ||
declarations.appendData(getDeclaration()); | ||
children.appendData(getDeclaration()); | ||
} | ||
@@ -458,4 +561,4 @@ } | ||
type: 'Block', | ||
info: getInfo(start), | ||
declarations: declarations | ||
loc: getLocation(start, scanner.tokenStart), | ||
children: children | ||
}; | ||
@@ -478,5 +581,10 @@ } | ||
// TODO: include or not to include semicolon to range? | ||
// if (scanner.tokenType === SEMICOLON) { | ||
// scanner.next(); | ||
// } | ||
return { | ||
type: 'Declaration', | ||
info: getInfo(start), | ||
loc: getLocation(start, scanner.tokenStart), | ||
important: important, | ||
@@ -512,3 +620,3 @@ property: property, | ||
var start = scanner.tokenStart; | ||
var sequence = new List(); | ||
var children = new List(); | ||
var wasSpace = false; | ||
@@ -556,2 +664,6 @@ var child; | ||
case LEFTSQUAREBRACKET: | ||
child = getBrackets(); | ||
break; | ||
case STRING: | ||
@@ -580,6 +692,6 @@ child = getString(); | ||
wasSpace = false; | ||
sequence.appendData(SPACE_NODE); | ||
children.appendData(SPACE_NODE); | ||
} | ||
sequence.appendData(child); | ||
children.appendData(child); | ||
} | ||
@@ -589,4 +701,4 @@ | ||
type: 'Value', | ||
info: getInfo(start), | ||
sequence: sequence | ||
loc: getLocation(start, scanner.tokenStart), | ||
children: children | ||
}; | ||
@@ -597,3 +709,3 @@ } | ||
var start = scanner.tokenStart; | ||
var sequence = new List(); | ||
var children = new List(); | ||
var progid; | ||
@@ -603,3 +715,3 @@ | ||
readSC(); | ||
sequence.appendData(getProgid(progid)); | ||
children.appendData(getProgid(progid)); | ||
} | ||
@@ -611,4 +723,4 @@ | ||
type: 'Value', | ||
info: getInfo(start), | ||
sequence: sequence | ||
loc: getLocation(start, scanner.tokenStart), | ||
children: children | ||
}; | ||
@@ -644,3 +756,3 @@ } | ||
type: 'Number', | ||
info: getInfo(), | ||
loc: getLocation(scanner.tokenStart, scanner.tokenEnd), | ||
value: readNumber() | ||
@@ -659,3 +771,3 @@ }; | ||
if (scanner.tokenType === LEFTPARENTHESIS) { | ||
return getFunction(scope, getInfo(start), scanner.substrToCursor(start)); | ||
return getFunction(scope, start, scanner.substrToCursor(start)); | ||
} | ||
@@ -665,3 +777,3 @@ | ||
type: 'Identifier', | ||
info: getInfo(start), | ||
loc: getLocation(start, scanner.tokenStart), | ||
name: scanner.substrToCursor(start) | ||
@@ -698,10 +810,7 @@ }; | ||
function getAttribute() { | ||
var node = { | ||
type: 'Attribute', | ||
info: getInfo(), | ||
name: null, | ||
operator: null, | ||
value: null, | ||
flags: null | ||
}; | ||
var start = scanner.tokenStart; | ||
var name; | ||
var operator = null; | ||
var value = null; | ||
var flags = null; | ||
@@ -711,3 +820,3 @@ scanner.eat(LEFTSQUAREBRACKET); | ||
node.name = getAttributeName(); | ||
name = getAttributeName(); | ||
readSC(); | ||
@@ -718,7 +827,7 @@ | ||
if (scanner.tokenType !== IDENTIFIER) { | ||
node.operator = readAttrselector(); | ||
operator = readAttrselector(); | ||
readSC(); | ||
node.value = scanner.tokenType === STRING | ||
value = scanner.tokenType === STRING | ||
? getString() | ||
@@ -732,3 +841,3 @@ : getIdentifier(false); | ||
if (scanner.tokenType === IDENTIFIER) { | ||
node.flags = scanner.getTokenValue(); | ||
flags = scanner.getTokenValue(); | ||
scanner.next(); | ||
@@ -742,3 +851,10 @@ | ||
return node; | ||
return { | ||
type: 'Attribute', | ||
loc: getLocation(start, scanner.tokenStart), | ||
name: name, | ||
operator: operator, | ||
value: value, | ||
flags: flags | ||
}; | ||
} | ||
@@ -748,7 +864,7 @@ | ||
var start = scanner.tokenStart; | ||
var sequence = new List(); | ||
var children = new List(); | ||
var wasSpace = false; | ||
var child; | ||
// left brace | ||
// left parenthesis | ||
scanner.eat(LEFTPARENTHESIS); | ||
@@ -797,9 +913,9 @@ readSC(); | ||
wasSpace = false; | ||
sequence.appendData(SPACE_NODE); | ||
children.appendData(SPACE_NODE); | ||
} | ||
sequence.appendData(child); | ||
children.appendData(child); | ||
} | ||
// right brace | ||
// right parenthesis | ||
scanner.eat(RIGHTPARENTHESIS); | ||
@@ -809,17 +925,69 @@ | ||
type: 'Parentheses', | ||
info: getInfo(start), | ||
sequence: sequence | ||
loc: getLocation(start, scanner.tokenStart), | ||
children: children | ||
}; | ||
} | ||
// currently only Grid Layout uses square brackets | ||
// https://drafts.csswg.org/css-grid/#track-sizing | ||
// [ ident* ] | ||
function getBrackets() { | ||
var start = scanner.tokenStart; | ||
var children = new List(); | ||
var wasSpace = false; | ||
var child; | ||
// left bracket | ||
scanner.eat(LEFTSQUAREBRACKET); | ||
readSC(); | ||
scan: | ||
while (!scanner.eof) { | ||
switch (scanner.tokenType) { | ||
case RIGHTSQUAREBRACKET: | ||
break scan; | ||
case WHITESPACE: | ||
wasSpace = true; | ||
scanner.next(); | ||
continue; | ||
case COMMENT: // ignore comments | ||
scanner.next(); | ||
continue; | ||
default: | ||
child = getIdentifier(false); | ||
} | ||
if (wasSpace) { | ||
wasSpace = false; | ||
children.appendData(SPACE_NODE); | ||
} | ||
children.appendData(child); | ||
} | ||
// right bracket | ||
scanner.eat(RIGHTSQUAREBRACKET); | ||
return { | ||
type: 'Brackets', | ||
loc: getLocation(start, scanner.tokenStart), | ||
children: children | ||
}; | ||
} | ||
// '.' ident | ||
function getClass() { | ||
var start = scanner.tokenStart; | ||
var name; | ||
scanner.eat(FULLSTOP); | ||
name = readIdent(false); | ||
return { | ||
type: 'Class', | ||
info: getInfo(start), | ||
name: readIdent(false) | ||
loc: getLocation(start, scanner.tokenStart), | ||
name: name | ||
}; | ||
@@ -831,9 +999,11 @@ } | ||
var start = scanner.tokenStart; | ||
var name; | ||
scanner.eat(NUMBERSIGN); | ||
name = readIdent(false); | ||
return { | ||
type: 'Id', | ||
info: getInfo(start), | ||
name: readIdent(false) | ||
loc: getLocation(start, scanner.tokenStart), | ||
name: name | ||
}; | ||
@@ -876,3 +1046,3 @@ } | ||
type: 'Combinator', | ||
info: getInfo(start), | ||
loc: getLocation(start, scanner.tokenStart), | ||
name: combinator | ||
@@ -884,6 +1054,6 @@ }; | ||
function getComment() { | ||
var start = scanner.tokenStart + 2; | ||
var start = scanner.tokenStart; | ||
var end = scanner.tokenEnd; | ||
if ((end - start) >= 2 && | ||
if ((end - start + 2) >= 2 && | ||
scanner.source.charCodeAt(end - 2) === ASTERISK && | ||
@@ -898,4 +1068,4 @@ scanner.source.charCodeAt(end - 1) === SOLIDUS) { | ||
type: 'Comment', | ||
info: getInfo(start), | ||
value: scanner.source.substring(start, end) | ||
loc: getLocation(start, scanner.tokenStart), | ||
value: scanner.source.substring(start + 2, end) | ||
}; | ||
@@ -926,7 +1096,11 @@ } | ||
function getDimension() { | ||
var start = scanner.tokenStart; | ||
var value = readNumber(); | ||
var unit = readUnit(); | ||
return { | ||
type: 'Dimension', | ||
info: getInfo(), | ||
value: readNumber(), | ||
unit: readUnit() | ||
loc: getLocation(start, scanner.tokenStart), | ||
value: value, | ||
unit: unit | ||
}; | ||
@@ -943,3 +1117,3 @@ } | ||
type: 'Percentage', | ||
info: getInfo(start), | ||
loc: getLocation(start, scanner.tokenStart), | ||
value: number | ||
@@ -949,5 +1123,4 @@ }; | ||
// ident '(' functionBody ')' | | ||
// not '(' <simpleSelector>* ')' | ||
function getFunction(scope, info, name) { | ||
// ident '(' functionBody ')' | ||
function getFunction(scope, start, name) { | ||
// parse special functions | ||
@@ -959,3 +1132,3 @@ var nameLowerCase = name.toLowerCase(); | ||
if (SCOPE_SELECTOR.hasOwnProperty(nameLowerCase)) { | ||
return SCOPE_SELECTOR[nameLowerCase](scope, info, name); | ||
return SCOPE_SELECTOR[nameLowerCase](scope, start, name); | ||
} | ||
@@ -965,3 +1138,3 @@ break; | ||
if (SCOPE_VALUE.hasOwnProperty(nameLowerCase)) { | ||
return SCOPE_VALUE[nameLowerCase](scope, info, name); | ||
return SCOPE_VALUE[nameLowerCase](scope, start, name); | ||
} | ||
@@ -971,3 +1144,3 @@ break; | ||
if (SCOPE_ATRULE_EXPRESSION.hasOwnProperty(nameLowerCase)) { | ||
return SCOPE_ATRULE_EXPRESSION[nameLowerCase](scope, info, name); | ||
return SCOPE_ATRULE_EXPRESSION[nameLowerCase](scope, start, name); | ||
} | ||
@@ -977,10 +1150,10 @@ break; | ||
return getFunctionInternal(getFunctionArguments, scope, info, name); | ||
return getFunctionInternal(getFunctionArguments, scope, start, name); | ||
} | ||
function getFunctionInternal(readSequence, scope, info, name) { | ||
var sequence; | ||
function getFunctionInternal(readSequence, scope, start, name) { | ||
var children; | ||
scanner.eat(LEFTPARENTHESIS); | ||
sequence = readSequence(scope); | ||
children = readSequence(scope); | ||
scanner.eat(RIGHTPARENTHESIS); | ||
@@ -990,5 +1163,5 @@ | ||
type: scope === SCOPE_SELECTOR ? 'PseudoClass' : 'Function', | ||
info: info, | ||
loc: getLocation(start, scanner.tokenStart), | ||
name: name, | ||
sequence: sequence | ||
children: children | ||
}; | ||
@@ -998,3 +1171,3 @@ } | ||
function getFunctionArguments(scope) { | ||
var sequence = new List(); | ||
var children = new List(); | ||
var wasSpace = false; | ||
@@ -1051,7 +1224,7 @@ var prevNonSpaceOperator = false; | ||
if (!nonSpaceOperator && !prevNonSpaceOperator) { | ||
sequence.appendData(SPACE_NODE); | ||
children.appendData(SPACE_NODE); | ||
} | ||
} | ||
sequence.appendData(child); | ||
children.appendData(child); | ||
prevNonSpaceOperator = nonSpaceOperator; | ||
@@ -1061,55 +1234,19 @@ nonSpaceOperator = false; | ||
return sequence; | ||
return children; | ||
} | ||
function getVarFunction(scope, info, name) { | ||
return getFunctionInternal(getVarFunctionArguments, scope, info, name); | ||
function getSelectorListFunction(scope, start, name) { | ||
return getFunctionInternal(function() { | ||
return new List().appendData(getSelectorList(NESTED, ABSOLUTE)); | ||
}, scope, start, name); | ||
} | ||
// TODO: -> getSimpleSelectorList | ||
function getNotFunctionArguments() { | ||
var args = new List(); | ||
var wasSelector = false; | ||
scan: | ||
while (!scanner.eof) { | ||
switch (scanner.tokenType) { | ||
case RIGHTPARENTHESIS: | ||
if (!wasSelector) { | ||
scanner.error('Simple selector is expected'); | ||
} | ||
break scan; | ||
case COMMA: | ||
if (!wasSelector) { | ||
scanner.error('Simple selector is expected'); | ||
} | ||
wasSelector = false; | ||
scanner.next(); | ||
break; | ||
default: | ||
wasSelector = true; | ||
args.appendData(getSimpleSelector(true)); | ||
} | ||
} | ||
return args; | ||
function getRelativeSelectorListFunction(scope, start, name) { | ||
return getFunctionInternal(function() { | ||
return new List().appendData(getSelectorList(NESTED, RELATIVE)); | ||
}, scope, start, name); | ||
} | ||
function getNotFunction(scope, info) { | ||
var selectors; | ||
scanner.eat(LEFTPARENTHESIS); | ||
selectors = getNotFunctionArguments(scope); | ||
scanner.eat(RIGHTPARENTHESIS); | ||
return { | ||
type: 'Negation', | ||
info: info, | ||
// name: name, // TODO: add name? | ||
sequence: selectors // TODO: sequence -> selectors | ||
}; | ||
function getVarFunction(scope, start, name) { | ||
return getFunctionInternal(getVarFunctionArguments, scope, start, name); | ||
} | ||
@@ -1119,21 +1256,21 @@ | ||
function getVarFunctionArguments() { // TODO: special type Variable? | ||
var sequence = new List(); | ||
var children = new List(); | ||
readSC(); | ||
sequence.appendData(getIdentifier(true)); | ||
children.appendData(getIdentifier(true)); | ||
readSC(); | ||
if (scanner.tokenType === COMMA) { | ||
sequence.appendData(getOperator()); | ||
children.appendData(getOperator()); | ||
readSC(); | ||
sequence.appendData(getValue(true, null)); | ||
children.appendData(getValue(true, null)); | ||
readSC(); | ||
} | ||
return sequence; | ||
return children; | ||
} | ||
// url '(' ws* (string | raw) ws* ')' | ||
function getUri(scope, info) { | ||
function getUri(scope, start) { | ||
var value; | ||
@@ -1147,3 +1284,3 @@ | ||
} else { | ||
var start = scanner.tokenStart; | ||
var rawStart = scanner.tokenStart; | ||
@@ -1163,4 +1300,4 @@ // TODO: fix me, looks like incorrect raw scan | ||
type: 'Raw', | ||
info: getInfo(start), | ||
value: scanner.substrToCursor(start) | ||
loc: getLocation(rawStart, scanner.tokenStart), | ||
value: scanner.substrToCursor(rawStart) | ||
}; | ||
@@ -1174,3 +1311,3 @@ } | ||
type: 'Url', | ||
info: info, | ||
loc: getLocation(start, scanner.tokenStart), | ||
value: value | ||
@@ -1181,5 +1318,5 @@ }; | ||
// expression '(' raw ')' | ||
function getOldIEExpression(scope, info, name) { | ||
var start = scanner.tokenStart + 1; // skip open parenthesis | ||
var raw; | ||
function getOldIEExpression(scope, start, name) { | ||
var rawStart = scanner.tokenStart + 1; // skip open parenthesis | ||
var rawNode; | ||
@@ -1201,3 +1338,7 @@ scanner.eat(LEFTPARENTHESIS); | ||
raw = scanner.substrToCursor(start); | ||
rawNode = { | ||
type: 'Raw', | ||
loc: getLocation(rawStart, scanner.tokenStart), | ||
value: scanner.substrToCursor(rawStart) | ||
}; | ||
@@ -1208,11 +1349,23 @@ scanner.eat(RIGHTPARENTHESIS); | ||
type: 'Function', | ||
info: info, | ||
loc: getLocation(start, scanner.tokenStart), | ||
name: name, | ||
sequence: new List().appendData({ | ||
type: 'Raw', | ||
value: raw | ||
}) | ||
children: new List().appendData(rawNode) | ||
}; | ||
} | ||
function scanUnicodeNumber() { | ||
for (var pos = scanner.tokenStart + 1; pos < scanner.tokenEnd; pos++) { | ||
var code = scanner.source.charCodeAt(pos); | ||
// break on fullstop or hyperminus/plussign after exponent | ||
if (code === FULLSTOP || code === PLUSSIGN) { | ||
// break token, exclude symbol | ||
scanner.tokenStart = pos; | ||
return false; | ||
} | ||
} | ||
return true; | ||
} | ||
// https://drafts.csswg.org/css-syntax-3/#urange | ||
@@ -1223,21 +1376,32 @@ function scanUnicodeRange() { | ||
scanner.next(); // always PLUSSIGN or NUMBER | ||
scan: { | ||
if (scanner.tokenType === NUMBER) { | ||
if (scanner.source.charCodeAt(scanner.tokenStart) !== FULLSTOP && scanUnicodeNumber()) { | ||
scanner.next(); | ||
} else if (scanner.source.charCodeAt(scanner.tokenStart) !== HYPHENMINUS) { | ||
break scan; | ||
} | ||
} else { | ||
scanner.next(); // PLUSSIGN | ||
} | ||
if (scanner.tokenType === HYPHENMINUS) { | ||
scanner.next(); | ||
} | ||
if (scanner.tokenType === HYPHENMINUS) { | ||
scanner.next(); | ||
} | ||
if (scanner.tokenType === NUMBER) { | ||
scanner.next(); | ||
} | ||
if (scanner.tokenType === NUMBER) { | ||
scanner.next(); | ||
} | ||
if (scanner.tokenType === IDENTIFIER) { | ||
scanner.next(); | ||
} | ||
if (scanner.tokenType === IDENTIFIER) { | ||
scanner.next(); | ||
} | ||
if (scanner.tokenStart === hexStart) { | ||
scanner.error('Unexpected input', hexStart); | ||
if (scanner.tokenStart === hexStart) { | ||
scanner.error('Unexpected input', hexStart); | ||
} | ||
} | ||
// validate hex for U+xxxxxx or U+xxxxxx-xxxxxx | ||
// validate for U+x{1,6} or U+x{1,6}-x{1,6} | ||
// where x is [0-9a-fA-F] | ||
// TODO: check hex sequence length | ||
@@ -1270,2 +1434,7 @@ for (var i = hexStart, wasHyphenMinus = false; i < scanner.tokenStart; i++) { | ||
// check we have a non-zero sequence | ||
if (hexLength === 0) { | ||
scanner.error('Unexpected input', i - 1); | ||
} | ||
// U+abc??? | ||
@@ -1292,4 +1461,4 @@ if (!wasHyphenMinus) { | ||
type: 'UnicodeRange', | ||
info: getInfo(start), | ||
name: scanner.substrToCursor(start) | ||
loc: getLocation(start, scanner.tokenStart), | ||
value: scanner.substrToCursor(start) | ||
}; | ||
@@ -1360,3 +1529,3 @@ } | ||
type: 'Identifier', | ||
info: getInfo(start), | ||
loc: getLocation(start, scanner.tokenStart), | ||
name: scanner.substrToCursor(start) | ||
@@ -1393,3 +1562,3 @@ }; | ||
type: universal ? 'Universal' : 'Type', | ||
info: getInfo(start), | ||
loc: getLocation(start, scanner.tokenStart), | ||
name: scanner.substrToCursor(start) | ||
@@ -1400,6 +1569,9 @@ }; | ||
function getIdentifier(varAllowed) { | ||
var start = scanner.tokenStart; | ||
var name = readIdent(varAllowed); | ||
return { | ||
type: 'Identifier', | ||
info: getInfo(), | ||
name: readIdent(varAllowed) | ||
loc: getLocation(start, scanner.tokenStart), | ||
name: name | ||
}; | ||
@@ -1420,6 +1592,22 @@ } | ||
function checkTokenIsInteger() { | ||
var pos = scanner.tokenStart; | ||
if (scanner.source.charCodeAt(pos) === PLUSSIGN || | ||
scanner.source.charCodeAt(pos) === HYPHENMINUS) { | ||
pos++; | ||
} | ||
for (; pos < scanner.tokenEnd; pos++) { | ||
if (!isNumber(scanner.source.charCodeAt(pos))) { | ||
scanner.error('Unexpected input', pos); | ||
} | ||
} | ||
} | ||
// https://drafts.csswg.org/css-syntax-3/#the-anb-type | ||
function getNthSelector() { | ||
function getNthSelector(allowOfClause) { | ||
var start = scanner.tokenStart; | ||
var sequence = new List(); | ||
var selector = null; | ||
var query; | ||
var name; | ||
@@ -1432,16 +1620,16 @@ | ||
var nthStart = scanner.tokenStart; | ||
if (scanner.lookupValue(0, 'odd') || scanner.lookupValue(0, 'even')) { | ||
var start = scanner.tokenStart; | ||
var info = getInfo(); | ||
scanner.next(); | ||
sequence.appendData({ | ||
type: 'Nth', | ||
info: info, | ||
value: scanner.substrToCursor(start) | ||
}); | ||
query = { | ||
type: 'Identifier', | ||
loc: getLocation(nthStart, scanner.tokenStart), | ||
name: scanner.substrToCursor(nthStart) | ||
}; | ||
} else { | ||
// scan An+B microsyntax https://www.w3.org/TR/css-syntax-3/#anb | ||
var prefix = ''; | ||
var start = scanner.tokenStart; | ||
var info = getInfo(); | ||
var a = null; | ||
var b = null; | ||
@@ -1451,2 +1639,3 @@ if (scanner.tokenType === HYPHENMINUS || | ||
scanner.tokenType === NUMBER) { | ||
checkTokenIsInteger(); | ||
prefix = scanner.getTokenValue(); | ||
@@ -1461,26 +1650,19 @@ scanner.next(); | ||
sequence.appendData({ | ||
type: 'Nth', | ||
info: info, | ||
value: prefix + scanner.source.charAt(scanner.tokenStart) | ||
}); | ||
a = prefix === '' || prefix === '+' ? '1' : | ||
prefix === '-' ? '-1' : | ||
prefix; | ||
var len = scanner.tokenEnd - scanner.tokenStart; | ||
if (len > 1) { | ||
var start = scanner.tokenStart; | ||
var bStart = scanner.tokenStart; | ||
// ..n-.. | ||
if (scanner.source.charCodeAt(start + 1) !== HYPHENMINUS) { | ||
scanner.error('Unexpected input', start + 1); | ||
if (scanner.source.charCodeAt(bStart + 1) !== HYPHENMINUS) { | ||
scanner.error('Unexpected input', bStart + 1); | ||
} | ||
scanner.tokenStart = start + 1; | ||
sequence.appendData({ | ||
type: 'Operator', | ||
info: getInfo(), | ||
value: scanner.source.charAt(start + 1) | ||
}); | ||
scanner.tokenStart = bStart + 1; | ||
// ..n-{number}.. | ||
if (len > 2) { | ||
for (var i = start + 2; i < scanner.tokenEnd; i++) { | ||
for (var i = bStart + 2; i < scanner.tokenEnd; i++) { | ||
if (!isNumber(scanner.source.charCodeAt(i))) { | ||
@@ -1491,12 +1673,4 @@ scanner.error('Unexpected input', i); | ||
scanner.tokenStart = start + 2; | ||
var info = getInfo(); | ||
scanner.next(); | ||
sequence.appendData({ | ||
type: 'Nth', | ||
info: info, | ||
value: scanner.substrToCursor(start + 2) | ||
}); | ||
b = '-' + scanner.substrToCursor(bStart + 2); | ||
} else { | ||
@@ -1512,8 +1686,3 @@ scanner.next(); | ||
sequence.appendData({ | ||
type: 'Nth', | ||
info: getInfo(), | ||
value: scanner.getTokenValue() | ||
}); | ||
b = '-' + scanner.getTokenValue(); | ||
scanner.next(); | ||
@@ -1528,3 +1697,2 @@ } | ||
scanner.tokenType === PLUSSIGN) { | ||
info = getInfo(); | ||
prefix = scanner.getTokenValue(); | ||
@@ -1536,31 +1704,25 @@ scanner.next(); | ||
if (scanner.tokenType === NUMBER) { | ||
var sign = ''; | ||
checkTokenIsInteger(); | ||
if (cmpChar(scanner.source, scanner.tokenStart, PLUSSIGN) || | ||
cmpChar(scanner.source, scanner.tokenStart, HYPHENMINUS)) { | ||
info = getInfo(); | ||
sign = scanner.source.charAt(scanner.tokenStart); | ||
// prefix or sign should be specified but not both | ||
if (prefix !== '') { | ||
scanner.error(); | ||
} | ||
prefix = scanner.source.charAt(scanner.tokenStart); | ||
scanner.tokenStart++; | ||
} | ||
// prefix or sign should be specified but not both | ||
if (!(prefix === '' ^ sign === '')) { | ||
if (prefix === '') { | ||
// should be an operator before number | ||
scanner.error(); | ||
} else if (prefix === '+') { | ||
// plus is using by default | ||
prefix = ''; | ||
} | ||
if (sign) { | ||
scanner.tokenStart++; | ||
} | ||
b = prefix + scanner.getTokenValue(); | ||
sequence.appendData({ | ||
type: 'Operator', | ||
info: info, | ||
value: prefix || sign | ||
}); | ||
sequence.appendData({ | ||
type: 'Nth', | ||
info: getInfo(), | ||
value: scanner.getTokenValue() | ||
}); | ||
scanner.next(); | ||
@@ -1574,11 +1736,20 @@ } | ||
sequence.appendData({ | ||
type: 'Nth', | ||
info: info, | ||
value: prefix | ||
}); | ||
b = prefix; | ||
} | ||
query = { | ||
type: 'An+B', | ||
loc: getLocation(nthStart, scanner.tokenStart), | ||
a: a, | ||
b: b | ||
}; | ||
} | ||
readSC(); | ||
if (allowOfClause && scanner.lookupValue(0, 'of')) { | ||
scanner.next(); | ||
selector = getSelectorList(NESTED); | ||
} | ||
scanner.eat(RIGHTPARENTHESIS); | ||
@@ -1588,5 +1759,9 @@ | ||
type: 'PseudoClass', | ||
info: getInfo(start), | ||
loc: getLocation(start, scanner.tokenStart), | ||
name: name, | ||
sequence: sequence | ||
children: new List().appendData({ // TODO: add loc | ||
type: 'Nth', | ||
nth: query, | ||
selector: selector | ||
}) | ||
}; | ||
@@ -1611,3 +1786,3 @@ } | ||
type: 'Operator', | ||
info: getInfo(start), | ||
loc: getLocation(start, scanner.tokenStart), | ||
value: scanner.substrToCursor(start) | ||
@@ -1666,3 +1841,3 @@ }; | ||
type: 'Progid', | ||
info: getInfo(start), | ||
loc: getLocation(start, scanner.tokenStart), | ||
value: scanner.substrToCursor(start) | ||
@@ -1690,5 +1865,11 @@ }; | ||
if (cmpStr(scanner.source, scanner.tokenEnd, scanner.tokenEnd + 4, 'nth-')) { | ||
return getNthSelector(); | ||
if (scanner.lookupValue(1, 'nth-child') || | ||
scanner.lookupValue(1, 'nth-last-child')) { | ||
return getNthSelector(true); | ||
} | ||
if (scanner.lookupValue(1, 'nth-of-type') || | ||
scanner.lookupValue(1, 'nth-last-of-type')) { | ||
return getNthSelector(false); | ||
} | ||
} | ||
@@ -1702,2 +1883,4 @@ | ||
var start = scanner.tokenStart; | ||
var name; | ||
var children = null; | ||
@@ -1707,6 +1890,17 @@ scanner.eat(COLON); | ||
// https://drafts.csswg.org/css-scoping/#slotted-pseudo | ||
if (scanner.lookupValue(0, 'slotted')) { | ||
name = readIdent(false); | ||
scanner.eat(LEFTPARENTHESIS); | ||
children = new List().appendData(getCompoundSelector(true)); | ||
scanner.eat(RIGHTPARENTHESIS); | ||
} else { | ||
name = readIdent(false); | ||
} | ||
return { | ||
type: 'PseudoElement', | ||
info: getInfo(start), | ||
name: readIdent(false), | ||
loc: getLocation(start, scanner.tokenStart), | ||
name: name, | ||
children: children, | ||
legacy: false | ||
@@ -1723,9 +1917,12 @@ }; | ||
var start = scanner.tokenStart; | ||
var name; | ||
scanner.eat(COLON); | ||
name = readIdent(false); | ||
return { | ||
type: 'PseudoElement', | ||
info: getInfo(start), | ||
name: readIdent(false), | ||
loc: getLocation(start, scanner.tokenStart), | ||
name: name, | ||
children: null, | ||
legacy: true | ||
@@ -1743,3 +1940,3 @@ }; | ||
if (scanner.tokenType === LEFTPARENTHESIS) { | ||
return getFunction(SCOPE_SELECTOR, getInfo(start), scanner.substrToCursor(start + 1)); | ||
return getFunction(SCOPE_SELECTOR, start, scanner.substrToCursor(start + 1)); | ||
} | ||
@@ -1749,5 +1946,5 @@ | ||
type: 'PseudoClass', | ||
info: getInfo(start), | ||
loc: getLocation(start, scanner.tokenStart), | ||
name: scanner.substrToCursor(start + 1), | ||
sequence: null | ||
children: null | ||
}; | ||
@@ -1780,3 +1977,3 @@ } | ||
type: 'String', | ||
info: getInfo(start), | ||
loc: getLocation(start, scanner.tokenStart), | ||
value: scanner.substrToCursor(start) | ||
@@ -1792,12 +1989,36 @@ }; | ||
if (scanner.tokenType !== NUMBER && | ||
scanner.tokenType !== IDENTIFIER) { | ||
scanner.error('Number or identifier is expected'); | ||
} | ||
scan: | ||
switch (scanner.tokenType) { | ||
case NUMBER: | ||
if (!isNumber(scanner.source.charCodeAt(scanner.tokenStart))) { | ||
scanner.error('Unexpected input', scanner.tokenStart); | ||
} | ||
scanner.next(); // number or identifier | ||
for (var pos = scanner.tokenStart + 1; pos < scanner.tokenEnd; pos++) { | ||
var code = scanner.source.charCodeAt(pos); | ||
// there was a number before identifier | ||
if (scanner.tokenType === IDENTIFIER) { | ||
scanner.next(); | ||
// break on fullstop or hyperminus/plussign after exponent | ||
if (code === FULLSTOP || code === HYPHENMINUS || code === PLUSSIGN) { | ||
// break token, exclude symbol | ||
scanner.tokenStart = pos; | ||
break scan; | ||
} | ||
} | ||
// number contains digits only, go to next token | ||
scanner.next(); | ||
// if next token is identifier add it to result | ||
if (scanner.tokenType === IDENTIFIER) { | ||
scanner.next(); | ||
} | ||
break; | ||
case IDENTIFIER: | ||
scanner.next(); // add token to result | ||
break; | ||
default: | ||
scanner.error('Number or identifier is expected'); | ||
} | ||
@@ -1807,3 +2028,3 @@ | ||
type: 'Hash', | ||
info: getInfo(start), | ||
loc: getLocation(start, scanner.tokenStart), | ||
value: scanner.substrToCursor(start + 1) // skip # | ||
@@ -1842,4 +2063,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):Nth-child(2n+1)::g,* b >c+d~e/deep/f,100%{v:1 2em t a(2%, var(--a)) url(..) -foo-bar !important}'); | ||
module.exports = parse; |
@@ -0,1 +1,3 @@ | ||
'use strict'; | ||
// token types (note: value shouldn't intersect with used char codes) | ||
@@ -2,0 +4,0 @@ var WHITESPACE = 1; |
@@ -0,1 +1,3 @@ | ||
'use strict'; | ||
var MAX_LINE_LENGTH = 100; | ||
@@ -2,0 +4,0 @@ var OFFSET_CORRECTION = 60; |
@@ -43,5 +43,4 @@ 'use strict'; | ||
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 | ||
function computeLines(scanner, source) { | ||
function computeLinesAndColumns(scanner, source) { | ||
var sourceLength = source.length; | ||
@@ -51,5 +50,8 @@ var start = firstCharOffset(source); | ||
var line = scanner.initLine; | ||
var columns = scanner.columns; | ||
var column = scanner.initColumn; | ||
if (lines === null || lines.length < sourceLength + 1) { | ||
lines = new SafeUint32Array(Math.max(sourceLength + 1024, MIN_BUFFER_SIZE)); | ||
columns = new SafeUint32Array(lines.length); | ||
} | ||
@@ -61,2 +63,3 @@ | ||
lines[i] = line; | ||
columns[i] = column++; | ||
@@ -67,4 +70,7 @@ if (code === N || code === R || code === F) { | ||
lines[i] = line; | ||
columns[i] = column; | ||
} | ||
line++; | ||
column = 1; | ||
} | ||
@@ -74,5 +80,7 @@ } | ||
lines[i] = line; | ||
columns[i] = column; | ||
scanner.lineComputed = true; | ||
scanner.linesAnsColumnsComputed = true; | ||
scanner.lines = lines; | ||
scanner.columns = columns; | ||
} | ||
@@ -156,2 +164,3 @@ | ||
this.lines = null; | ||
this.columns = null; | ||
@@ -167,6 +176,4 @@ this.setSource(source || '', initLine, initColumn); | ||
this.initLine = typeof initLine === 'undefined' ? 1 : initLine; | ||
this.initColumn = (typeof initColumn === 'undefined' ? 1 : initColumn) - start; | ||
this.lastLocationLine = this.initLine; | ||
this.lastLocationLineOffset = 1 - this.initColumn; | ||
this.lineComputed = false; | ||
this.initColumn = typeof initColumn === 'undefined' ? 1 : initColumn; | ||
this.linesAnsColumnsComputed = false; | ||
@@ -260,32 +267,32 @@ this.eof = false; | ||
getLocation: function(offset, source) { | ||
if (!this.lineComputed) { | ||
computeLines(this, this.source); | ||
getLocation: function(offset, filename) { | ||
if (!this.linesAnsColumnsComputed) { | ||
computeLinesAndColumns(this, this.source); | ||
} | ||
var line = this.lines[offset]; | ||
var column = offset; | ||
var lineOffset; | ||
return { | ||
source: filename, | ||
offset: offset, | ||
line: this.lines[offset], | ||
column: this.columns[offset] | ||
}; | ||
}, | ||
if (line === this.initLine) { | ||
column += this.initColumn; | ||
} else { | ||
// try get precomputed line offset | ||
if (line === this.lastLocationLine) { | ||
lineOffset = this.lastLocationLineOffset; | ||
} else { | ||
// try avoid to compute line offset since it's expensive for long lines | ||
lineOffset = lastIndexOf.call(this.lines, line - 1, offset); | ||
this.lastLocationLine = line; | ||
this.lastLocationLineOffset = lineOffset; | ||
} | ||
column -= lineOffset; | ||
getLocationRange: function(start, end, filename) { | ||
if (!this.linesAnsColumnsComputed) { | ||
computeLinesAndColumns(this, this.source); | ||
} | ||
return { | ||
source: source, | ||
offset: offset, | ||
line: line, | ||
column: column | ||
source: filename, | ||
start: { | ||
offset: start, | ||
line: this.lines[start], | ||
column: this.columns[start] | ||
}, | ||
end: { | ||
offset: end, | ||
line: this.lines[end], | ||
column: this.columns[end] | ||
} | ||
}; | ||
@@ -292,0 +299,0 @@ }, |
@@ -0,1 +1,3 @@ | ||
'use strict'; | ||
var constants = require('./const'); | ||
@@ -2,0 +4,0 @@ var PUNCTUATION = constants.PUNCTUATION; |
@@ -0,1 +1,3 @@ | ||
'use strict'; | ||
var data = require('../../data'); | ||
@@ -2,0 +4,0 @@ |
@@ -0,1 +1,3 @@ | ||
'use strict'; | ||
var translateSyntax = require('./translate'); | ||
@@ -34,3 +36,3 @@ var translateCss = require('../utils/translate'); | ||
value.sequence.each(function(node) { | ||
value.children.each(function(node) { | ||
if (badNode === node || (badNode && contains(node, badNode))) { | ||
@@ -52,4 +54,4 @@ errorOffset = css.length; | ||
error.css = css; | ||
error.line = badNode && badNode.info ? badNode.info.line : undefined; | ||
error.column = badNode && badNode.info ? badNode.info.column : undefined; | ||
error.line = badNode && badNode.loc && badNode.loc.start ? badNode.loc.start.line : undefined; | ||
error.column = badNode && badNode.loc && badNode.loc.start ? badNode.loc.start.column : undefined; | ||
error.offset = errorOffset; | ||
@@ -56,0 +58,0 @@ error.message = message + '\n' + |
@@ -0,1 +1,3 @@ | ||
'use strict'; | ||
var names = require('../utils/names.js'); | ||
@@ -2,0 +4,0 @@ |
@@ -0,1 +1,3 @@ | ||
'use strict'; | ||
module.exports = { | ||
@@ -2,0 +4,0 @@ defaultSyntax: require('./default'), |
@@ -0,1 +1,3 @@ | ||
'use strict'; | ||
var names = require('../utils/names'); | ||
@@ -244,3 +246,3 @@ var MULTIPLIER_DEFAULT = { | ||
var res = match(syntax, syntaxNode.sequence, node.data.sequence.head); | ||
var res = match(syntax, syntaxNode.sequence, node.data.children.head); | ||
if (!res.match || res.next) { | ||
@@ -263,3 +265,3 @@ badNode = res.badNode || res.lastNode || (res.next ? res.next.data : null) || node.data; | ||
var res = match(syntax, syntaxNode.sequence, node.data.sequence.head); | ||
var res = match(syntax, syntaxNode.sequence, node.data.children.head); | ||
if (!res.match || res.next) { | ||
@@ -266,0 +268,0 @@ badNode = res.badNode || res.lastNode || (res.next ? res.next.data : null) || node.data; // TODO: case when res.next === null |
@@ -0,1 +1,3 @@ | ||
'use strict'; | ||
var SyntaxParseError = require('./error').SyntaxParseError; | ||
@@ -2,0 +4,0 @@ |
@@ -0,1 +1,3 @@ | ||
'use strict'; | ||
var MatchError = require('./error').MatchError; | ||
@@ -50,6 +52,6 @@ var walkAst = require('../utils/walk').all; | ||
result = match(dictionary, dictionary.valueCommonSyntax, value.sequence.head); | ||
result = match(dictionary, dictionary.valueCommonSyntax, value.children.head); | ||
if (!result.match) { | ||
result = syntax.match(value.sequence.head); | ||
result = syntax.match(value.children.head); | ||
if (!result || !result.match) { | ||
@@ -56,0 +58,0 @@ dictionary.lastMatchError = new MatchError('Mismatch', syntax.syntax, value, result.badNode || unwrapNode(result.next)); |
@@ -0,1 +1,3 @@ | ||
'use strict'; | ||
function isTokenType(token/*, type, type*/) { | ||
@@ -2,0 +4,0 @@ if (token) { |
@@ -0,1 +1,3 @@ | ||
'use strict'; | ||
module.exports = function walk(node, fn, context) { | ||
@@ -2,0 +4,0 @@ switch (node.type) { |
@@ -0,1 +1,3 @@ | ||
'use strict'; | ||
var List = require('./list'); | ||
@@ -2,0 +4,0 @@ |
@@ -0,1 +1,3 @@ | ||
'use strict'; | ||
// | ||
@@ -2,0 +4,0 @@ // item item item item |
@@ -0,1 +1,3 @@ | ||
'use strict'; | ||
var hasOwnProperty = Object.prototype.hasOwnProperty; | ||
@@ -2,0 +4,0 @@ var knownKeywords = Object.create(null); |
@@ -0,1 +1,3 @@ | ||
'use strict'; | ||
function each(list) { | ||
@@ -48,3 +50,3 @@ var cursor = list.head; | ||
if (node.expression && !node.expression.sequence.isEmpty()) { | ||
if (node.expression && !node.expression.children.isEmpty()) { | ||
result += ' ' + translate(node.expression); | ||
@@ -62,3 +64,3 @@ } | ||
function translateSimpleSelector(list) { | ||
function translateSelector(list) { | ||
var cursor = list.head; | ||
@@ -91,3 +93,3 @@ var result = ''; | ||
case 'StyleSheet': | ||
return each(node.rules); | ||
return each(node.children); | ||
@@ -100,10 +102,10 @@ case 'Atrule': | ||
case 'SelectorList': | ||
return eachDelim(node.children, ','); | ||
case 'Selector': | ||
return eachDelim(node.selectors, ','); | ||
return translateSelector(node.children); | ||
case 'SimpleSelector': | ||
return translateSimpleSelector(node.sequence); | ||
case 'Block': | ||
return eachDelim(node.declarations, ';'); | ||
return eachDelim(node.children, ';'); | ||
@@ -116,4 +118,11 @@ case 'Declaration': | ||
case 'Value': | ||
return each(node.sequence); | ||
return each(node.children); | ||
case 'Nth': | ||
var result = translate(node.nth); | ||
if (node.selector !== null) { | ||
result += ' of ' + translate(node.selector); | ||
} | ||
return result; | ||
case 'Attribute': | ||
@@ -143,12 +152,12 @@ var result = translate(node.name); | ||
case 'Function': | ||
return node.name + '(' + each(node.sequence) + ')'; | ||
return node.name + '(' + each(node.children) + ')'; | ||
case 'Negation': | ||
return ':not(' + eachDelim(node.sequence, ',') + ')'; | ||
case 'Parentheses': | ||
return '(' + each(node.sequence) + ')'; | ||
return '(' + each(node.children) + ')'; | ||
case 'Brackets': | ||
return '[' + each(node.children) + ']'; | ||
case 'AtruleExpression': | ||
return each(node.sequence); | ||
return each(node.children); | ||
@@ -173,8 +182,5 @@ case 'Url': | ||
case 'UnicodeRange': | ||
return node.name; | ||
case 'PseudoClass': | ||
return node.sequence !== null | ||
? ':' + node.name + '(' + each(node.sequence) + ')' | ||
return node.children !== null | ||
? ':' + node.name + '(' + each(node.children) + ')' | ||
: ':' + node.name; | ||
@@ -185,3 +191,5 @@ | ||
? ':' + node.name // :before, :after, :first-letter and :first-line | ||
: '::' + node.name; | ||
: node.children !== null | ||
? '::' + node.name + '(' + each(node.children) + ')' | ||
: '::' + node.name; | ||
@@ -194,2 +202,5 @@ case 'Class': | ||
case 'UnicodeRange': | ||
return node.value; | ||
case 'Hash': | ||
@@ -201,5 +212,26 @@ return '#' + node.value; | ||
case 'Nth': | ||
return node.value; | ||
case 'An+B': | ||
var result = ''; | ||
var a = node.a !== null && node.a !== undefined; | ||
var b = node.b !== null && node.b !== undefined; | ||
if (a) { | ||
result += node.a === '+1' || node.a === '1' ? 'n' : | ||
node.a === '-1' ? '-n' : | ||
node.a + 'n'; | ||
} | ||
if (a && b) { | ||
if (String(node.b).charAt(0) !== '-' && | ||
String(node.b).charAt(0) !== '+') { | ||
result += '+'; | ||
} | ||
} | ||
if (b) { | ||
result += node.b; | ||
} | ||
return result; | ||
case 'Number': | ||
@@ -206,0 +238,0 @@ return node.value; |
@@ -0,1 +1,3 @@ | ||
'use strict'; | ||
var SourceMapGenerator = require('source-map').SourceMapGenerator; | ||
@@ -86,17 +88,17 @@ var SourceNode = require('source-map').SourceNode; | ||
function createSourceNode(info, children) { | ||
if (info.primary) { | ||
function createSourceNode(loc, children) { | ||
if (loc.primary) { | ||
// special marker node to add several references to original | ||
// var merged = createSourceNode(info.merged, []); | ||
// var merged = createSourceNode(loc.merged, []); | ||
// merged.merged = true; | ||
// children.unshift(merged); | ||
// use recursion, because primary can also has a primary/merged info | ||
return createSourceNode(info.primary, children); | ||
// use recursion, because primary can also has a primary/merged loc | ||
return createSourceNode(loc.primary, children); | ||
} | ||
return new SourceNode( | ||
info.line, | ||
info.column - 1, | ||
info.source, | ||
loc.start ? loc.start.line : null, | ||
loc.start ? loc.start.column - 1 : null, | ||
loc.source, | ||
children | ||
@@ -118,18 +120,6 @@ ); | ||
function eachDelim(list, delimeter) { | ||
if (list.head === null) { | ||
return ''; | ||
} | ||
if (list.head === list.tail) { | ||
return translate(list.head.data); | ||
} | ||
return list.map(translate).join(delimeter); | ||
} | ||
function translate(node) { | ||
switch (node.type) { | ||
case 'StyleSheet': | ||
return createAnonymousSourceNode(node.rules.map(translate)); | ||
return createAnonymousSourceNode(node.children.map(translate)); | ||
@@ -139,3 +129,3 @@ case 'Atrule': | ||
if (node.expression && !node.expression.sequence.isEmpty()) { | ||
if (node.expression && !node.expression.children.isEmpty()) { | ||
nodes.push(' ', translate(node.expression)); | ||
@@ -150,3 +140,3 @@ } | ||
return createSourceNode(node.info, nodes); | ||
return createSourceNode(node.loc, nodes); | ||
@@ -158,7 +148,7 @@ case 'Rule': | ||
case 'SelectorList': | ||
return createAnonymousSourceNode(node.children.map(translate)).join(','); | ||
case 'Selector': | ||
return createAnonymousSourceNode(node.selectors.map(translate)).join(','); | ||
case 'SimpleSelector': | ||
var nodes = node.sequence.map(function(node) { | ||
var nodes = node.children.map(function(node) { | ||
// add extra spaces around /deep/ combinator since comment beginning/ending may to be produced | ||
@@ -172,6 +162,6 @@ if (node.type === 'Combinator' && node.name === '/deep/') { | ||
return createSourceNode(node.info, nodes); | ||
return createSourceNode(node.loc, nodes); | ||
case 'Block': | ||
return createAnonymousSourceNode(node.declarations.map(translate)).join(';'); | ||
return createAnonymousSourceNode(node.children.map(translate)).join(';'); | ||
@@ -181,3 +171,3 @@ case 'Declaration': | ||
return createSourceNode( | ||
node.info, | ||
node.loc, | ||
[node.property, ':', translate(node.value), '!important'] | ||
@@ -187,3 +177,3 @@ ); | ||
return createSourceNode( | ||
node.info, | ||
node.loc, | ||
[node.property, ':', translate(node.value)] | ||
@@ -194,4 +184,11 @@ ); | ||
case 'Value': | ||
return each(node.sequence); | ||
return each(node.children); | ||
case 'Nth': | ||
var nodes = [translate(node.nth)]; | ||
if (node.selector !== null) { | ||
nodes.push(' of ', translate(node.selector)); | ||
} | ||
return createAnonymousSourceNode(nodes); | ||
case 'Attribute': | ||
@@ -221,12 +218,12 @@ var result = translate(node.name); | ||
case 'Function': | ||
return node.name + '(' + each(node.sequence) + ')'; | ||
return node.name + '(' + each(node.children) + ')'; | ||
case 'Negation': | ||
return ':not(' + eachDelim(node.sequence, ',') + ')'; | ||
case 'Parentheses': | ||
return '(' + each(node.sequence) + ')'; | ||
return '(' + each(node.children) + ')'; | ||
case 'Brackets': | ||
return '[' + each(node.children) + ']'; | ||
case 'AtruleExpression': | ||
return each(node.sequence); | ||
return each(node.children); | ||
@@ -251,8 +248,5 @@ case 'Url': | ||
case 'UnicodeRange': | ||
return node.name; | ||
case 'PseudoClass': | ||
return node.sequence !== null | ||
? ':' + node.name + '(' + each(node.sequence) + ')' | ||
return node.children !== null | ||
? ':' + node.name + '(' + each(node.children) + ')' | ||
: ':' + node.name; | ||
@@ -263,3 +257,5 @@ | ||
? ':' + node.name // :before, :after, :first-letter and :first-line | ||
: '::' + node.name; | ||
: node.children !== null | ||
? '::' + node.name + '(' + each(node.children) + ')' | ||
: '::' + node.name; | ||
@@ -272,2 +268,5 @@ case 'Class': | ||
case 'UnicodeRange': | ||
return node.value; | ||
case 'Hash': | ||
@@ -279,5 +278,26 @@ return '#' + node.value; | ||
case 'Nth': | ||
return node.value; | ||
case 'An+B': | ||
var result = ''; | ||
var a = node.a !== null && node.a !== undefined; | ||
var b = node.b !== null && node.b !== undefined; | ||
if (a) { | ||
result += node.a === '+1' || node.a === '1' ? 'n' : | ||
node.a === '-1' ? '-n' : | ||
node.a + 'n'; | ||
} | ||
if (a && b) { | ||
if (String(node.b).charAt(0) !== '-' && | ||
String(node.b).charAt(0) !== '+') { | ||
result += '+'; | ||
} | ||
} | ||
if (b) { | ||
result += node.b; | ||
} | ||
return result; | ||
case 'Number': | ||
@@ -284,0 +304,0 @@ return node.value; |
@@ -0,1 +1,3 @@ | ||
'use strict'; | ||
function walkRules(node, item, list) { | ||
@@ -7,3 +9,3 @@ switch (node.type) { | ||
node.rules.each(walkRules, this); | ||
node.children.each(walkRules, this); | ||
@@ -23,2 +25,9 @@ this.stylesheet = oldStylesheet; | ||
this.fn(node, item, list); | ||
var oldRule = this.rule; | ||
this.rule = node; | ||
node.block.children.each(walkRules, this); | ||
this.rule = oldRule; | ||
break; | ||
@@ -35,3 +44,3 @@ } | ||
node.rules.eachRight(walkRulesRight, this); | ||
node.children.eachRight(walkRulesRight, this); | ||
@@ -50,2 +59,9 @@ this.stylesheet = oldStylesheet; | ||
case 'Rule': | ||
var oldRule = this.rule; | ||
this.rule = node; | ||
node.block.children.eachRight(walkRulesRight, this); | ||
this.rule = oldRule; | ||
this.fn(node, item, list); | ||
@@ -62,3 +78,3 @@ break; | ||
node.rules.each(walkDeclarations, this); | ||
node.children.each(walkDeclarations, this); | ||
@@ -69,3 +85,3 @@ this.stylesheet = oldStylesheet; | ||
case 'Atrule': | ||
if (node.block !== null && node.block.type === 'StyleSheet') { | ||
if (node.block !== null) { | ||
walkDeclarations.call(this, node.block); | ||
@@ -76,10 +92,21 @@ } | ||
case 'Rule': | ||
var oldRule = this.rule; | ||
this.rule = node; | ||
if (node.block !== null) { | ||
node.block.declarations.each(this.fn); | ||
walkDeclarations.call(this, node.block); | ||
} | ||
this.rule = null; | ||
this.rule = oldRule; | ||
break; | ||
case 'Block': | ||
node.children.each(function(node, item, list) { | ||
if (node.type === 'Declaration') { | ||
this.fn(node, item, list); | ||
} else { | ||
walkDeclarations.call(this, node); | ||
} | ||
}, this); | ||
break; | ||
} | ||
@@ -104,3 +131,3 @@ } | ||
node.rules.each(walk, this); | ||
node.children.each(walk, this); | ||
@@ -130,7 +157,7 @@ this.stylesheet = oldStylesheet; | ||
case 'Selector': | ||
case 'SelectorList': | ||
var oldSelector = this.selector; | ||
this.selector = node; | ||
node.selectors.each(walk, this); | ||
node.children.each(walk, this); | ||
@@ -140,4 +167,11 @@ this.selector = oldSelector; | ||
case 'Nth': | ||
walk.call(this, node.nth); | ||
if (node.selector !== null) { | ||
walk.call(this, node.selector); | ||
} | ||
break; | ||
case 'Block': | ||
node.declarations.each(walk, this); | ||
node.children.each(walk, this); | ||
break; | ||
@@ -161,6 +195,6 @@ | ||
case 'PseudoClass': | ||
if (node.sequence !== null) { | ||
if (node.children !== null) { | ||
this['function'] = node; | ||
node.sequence.each(walk, this); | ||
node.children.each(walk, this); | ||
@@ -171,6 +205,16 @@ this['function'] = null; | ||
case 'PseudoElement': | ||
if (node.children !== null) { | ||
this['function'] = node; | ||
node.children.each(walk, this); | ||
this['function'] = null; | ||
} | ||
break; | ||
case 'Function': | ||
this['function'] = node; | ||
node.sequence.each(walk, this); | ||
node.children.each(walk, this); | ||
@@ -183,3 +227,3 @@ this['function'] = null; | ||
node.sequence.each(walk, this); | ||
node.children.each(walk, this); | ||
@@ -189,8 +233,7 @@ this.atruleExpression = null; | ||
case 'Selector': | ||
case 'Value': | ||
case 'Argument': | ||
case 'SimpleSelector': | ||
case 'Parentheses': | ||
case 'Negation': | ||
node.sequence.each(walk, this); | ||
case 'Brackets': | ||
node.children.each(walk, this); | ||
break; | ||
@@ -212,8 +255,6 @@ | ||
// case 'UnicodeRange': | ||
// case 'Nth': | ||
// case 'An+B': | ||
// case 'Class': | ||
// case 'Id': | ||
// case 'Percentage': | ||
// case 'PseudoClass': | ||
// case 'PseudoElement': | ||
// case 'Space': | ||
@@ -220,0 +261,0 @@ // case 'Number': |
{ | ||
"name": "css-tree", | ||
"version": "1.0.0-alpha10", | ||
"description": "Detailed CSS parser", | ||
"version": "1.0.0-alpha11", | ||
"description": "Fast detailed CSS parser", | ||
"keywords": [ | ||
@@ -6,0 +6,0 @@ "css", |
Sorry, the diff of this file is too big to display
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
Major refactor
Supply chain riskPackage has recently undergone a major refactor. It may be unstable or indicate significant internal changes. Use caution when updating to versions that include significant changes.
Found 1 instance in 1 package
545331
12321
0