Comparing version 1.0.0-alpha5 to 1.0.0-alpha6
@@ -300,3 +300,3 @@ { | ||
"comment": "wrong quotes", | ||
"syntax": "[ [ <'font-style'> || <font-variant-css21> || <'font-weight'> || <'font-stretch'> ]? <'font-size'> [ / <'line-height'> ]? <'font-family'> ] | caption | icon | menu | message-box | small-caption | status-bar" | ||
"syntax": "[ [ <'font-style'> || <font-variant-css21> || <'font-weight'> || <'font-stretch'> ]? <'font-size'> [ / <'line-height'> ]? <'font-family'> ] | caption | icon | menu | message-box | small-caption | status-bar | <-non-standart-font>" | ||
}, | ||
@@ -608,2 +608,9 @@ "font-variant": { | ||
}, | ||
"-non-standart-font": { | ||
"comment": "non standart fonts", | ||
"preferences": [ | ||
"https://webkit.org/blog/3709/using-the-system-font-in-web-content/" | ||
], | ||
"syntax": "-apple-system-body | -apple-system-headline | -apple-system-subheadline | -apple-system-caption1 | -apple-system-caption2 | -apple-system-footnote | -apple-system-short-body | -apple-system-short-headline | -apple-system-short-subheadline | -apple-system-short-caption1 | -apple-system-short-footnote | -apple-system-tall-body" | ||
}, | ||
"-non-standart-color": { | ||
@@ -715,2 +722,9 @@ "comment": "non standart colors", | ||
}, | ||
"generic-family": { | ||
"comment": "added -apple-system", | ||
"references": [ | ||
"https://webkit.org/blog/3709/using-the-system-font-in-web-content/" | ||
], | ||
"syntax": "serif | sans-serif | cursive | fantasy | monospace | -apple-system" | ||
}, | ||
"gradient": { | ||
@@ -717,0 +731,0 @@ "comment": "added -webkit-gradient() since may to be used for legacy support", |
@@ -86,6 +86,6 @@ // token types (note: value shouldn't intersect with using char codes) | ||
TokenType.CircumflexAccent, // '^' | ||
TokenType.LeftCurlyBracket, // '{' | ||
TokenType.VerticalLine, // '|' | ||
TokenType.RightCurlyBracket, // '}' | ||
TokenType.Tilde // '~' | ||
TokenType.LeftCurlyBracket, // '{' | ||
TokenType.VerticalLine, // '|' | ||
TokenType.RightCurlyBracket, // '}' | ||
TokenType.Tilde // '~' | ||
]; | ||
@@ -92,0 +92,0 @@ var SYMBOL_CATEGORY_LENGTH = Math.max.apply(null, punctuation) + 1; |
@@ -7,2 +7,3 @@ 'use strict'; | ||
var cmpStr = require('./utils').cmpStr; | ||
var endsWith = require('./utils').endsWith; | ||
var isHex = require('./utils').isHex; | ||
@@ -14,2 +15,4 @@ var needPositions; | ||
var DESCENDANT_COMBINATOR = ' '; | ||
var SPACE_NODE = { type: 'Space' }; | ||
var WHITESPACE = TokenType.Whitespace; | ||
@@ -63,3 +66,3 @@ var IDENTIFIER = TokenType.Identifier; | ||
atruleExpression: getAtruleExpression, | ||
ruleset: getRuleset, | ||
rule: getRule, | ||
selector: getSelector, | ||
@@ -122,3 +125,3 @@ simpleSelector: getSimpleSelector, | ||
default: | ||
child = getRuleset(); | ||
child = getRule(); | ||
} | ||
@@ -185,2 +188,6 @@ | ||
case STRING: | ||
child = getString(); | ||
break; | ||
default: | ||
@@ -193,3 +200,3 @@ child = getAny(SCOPE_ATRULE_EXPRESSION); | ||
if (sequence.head !== null) { // ignore spaces in the beginning | ||
sequence.appendData({ type: 'Space' }); | ||
sequence.appendData(SPACE_NODE); | ||
} | ||
@@ -239,5 +246,5 @@ } | ||
function getRuleset() { | ||
function getRule() { | ||
return { | ||
type: 'Ruleset', | ||
type: 'Rule', | ||
info: getInfo(), | ||
@@ -296,3 +303,3 @@ selector: getSelector(), | ||
if (isBadSelector) { | ||
selectors = new List(); | ||
selectors.clear(); | ||
} | ||
@@ -379,3 +386,3 @@ | ||
case DECIMALNUMBER: | ||
child = getPercentage(readNumber()); | ||
child = getPercentage(getInfo(), readNumber()); | ||
break; | ||
@@ -450,3 +457,3 @@ | ||
var info = getInfo(); | ||
var property = getProperty(); | ||
var property = readProperty(); | ||
var important = false; | ||
@@ -456,3 +463,3 @@ var value; | ||
scanner.eat(COLON); | ||
value = getValue(nested, property.name); | ||
value = getValue(nested, property); | ||
@@ -472,9 +479,5 @@ if (scanner.tokenType === EXCLAMATIONMARK) { | ||
function getProperty() { | ||
function readProperty() { | ||
var start = scanner.tokenStart; | ||
var node = { | ||
type: 'Property', | ||
info: getInfo(), | ||
name: null | ||
}; | ||
var name; | ||
@@ -492,12 +495,12 @@ for (; !scanner.eof; scanner.next()) { | ||
scanIdent(true); | ||
node.name = scanner.substrToCursor(start); | ||
name = scanner.substrToCursor(start); | ||
readSC(); | ||
return node; | ||
return name; | ||
} | ||
function getValue(nested, property) { | ||
// check it's a filter | ||
if (property && /filter$/i.test(property) && checkProgid()) { | ||
// special parser for filter property since it can contains non-standart syntax for old IE | ||
if (property !== null && endsWith(property, 'filter') && checkProgid()) { | ||
return getFilterValue(); | ||
@@ -553,3 +556,3 @@ } | ||
case TokenType.ExclamationMark: | ||
case EXCLAMATIONMARK: | ||
if (nested) { | ||
@@ -560,2 +563,6 @@ scanner.error('Unexpected exclamation mark'); | ||
case STRING: | ||
child = getString(); | ||
break; | ||
default: | ||
@@ -575,4 +582,4 @@ // check for unicode range: U+0F00, U+0F00-0FFF, u+0F00?? | ||
wasSpace = false; | ||
if (sequence.head !== null) { // ignore spaces in the beginning | ||
sequence.appendData({ type: 'Space' }); | ||
if (sequence.tail !== null) { // ignore spaces in the beginning | ||
sequence.appendData(SPACE_NODE); | ||
} | ||
@@ -590,5 +597,2 @@ } | ||
switch (scanner.tokenType) { | ||
case STRING: | ||
return getString(); | ||
case IDENTIFIER: | ||
@@ -607,7 +611,7 @@ break; | ||
if (type === PERCENTSIGN) { | ||
return getPercentage(number); | ||
return getPercentage(info, number); | ||
} | ||
if (type === IDENTIFIER) { | ||
return getDimension(number); | ||
return getDimension(info, number); | ||
} | ||
@@ -773,2 +777,6 @@ | ||
case STRING: | ||
child = getString(); | ||
break; | ||
default: | ||
@@ -780,4 +788,4 @@ child = getAny(scope); | ||
wasSpace = false; | ||
if (sequence.head !== null) { | ||
sequence.appendData({ type: 'Space' }); | ||
if (sequence.head !== null) { // ignore spaces in the beginning | ||
sequence.appendData(SPACE_NODE); | ||
} | ||
@@ -904,6 +912,6 @@ } | ||
// number ident | ||
function getDimension(number) { | ||
function getDimension(info, number) { | ||
return { | ||
type: 'Dimension', | ||
info: getInfo(), | ||
info: info, | ||
value: number, | ||
@@ -914,5 +922,3 @@ unit: readUnit() | ||
function getPercentage(number) { | ||
var info = getInfo(); | ||
function getPercentage(info, number) { | ||
scanner.eat(PERCENTSIGN); | ||
@@ -930,4 +936,2 @@ | ||
function getFunction(scope, info, name) { | ||
var defaultArguments = getFunctionArguments; | ||
// parse special functions | ||
@@ -954,10 +958,10 @@ var nameLowerCase = name.toLowerCase(); | ||
return getFunctionInternal(defaultArguments, scope, info, name); | ||
return getFunctionInternal(getFunctionArguments, scope, info, name); | ||
} | ||
function getFunctionInternal(readArguments, scope, info, name) { | ||
var args; | ||
function getFunctionInternal(readSequence, scope, info, name) { | ||
var sequence; | ||
scanner.eat(LEFTPARENTHESIS); | ||
args = readArguments(scope); | ||
sequence = readSequence(scope); | ||
scanner.eat(RIGHTPARENTHESIS); | ||
@@ -969,3 +973,3 @@ | ||
name: name, | ||
arguments: args | ||
sequence: sequence | ||
}; | ||
@@ -975,5 +979,6 @@ } | ||
function getFunctionArguments(scope) { | ||
var args = new List(); | ||
var sequence = new List(); | ||
var wasSpace = false; | ||
var argument = null; | ||
var prevNonSpaceOperator = false; | ||
var nonSpaceOperator = false; | ||
var child; | ||
@@ -1007,13 +1012,13 @@ | ||
case COMMA: | ||
argument = null; | ||
wasSpace = false; | ||
scanner.next(); | ||
continue; | ||
case SOLIDUS: | ||
case ASTERISK: | ||
case COLON: | ||
wasSpace = false; | ||
nonSpaceOperator = true; | ||
child = getOperator(); | ||
break; | ||
case STRING: | ||
child = getString(); | ||
break; | ||
default: | ||
@@ -1023,22 +1028,17 @@ child = getAny(scope); | ||
if (argument === null) { | ||
argument = { | ||
type: 'Argument', | ||
sequence: new List() | ||
}; | ||
args.appendData(argument); | ||
} | ||
if (wasSpace) { | ||
wasSpace = false; | ||
if (argument.sequence.head !== null) { // ignore spaces in the beginning | ||
argument.sequence.appendData({ type: 'Space' }); | ||
// ignore spaces in the beginning and around operator | ||
if (sequence.tail !== null && !nonSpaceOperator && !prevNonSpaceOperator) { | ||
sequence.appendData(SPACE_NODE); | ||
} | ||
} | ||
argument.sequence.appendData(child); | ||
sequence.appendData(child); | ||
prevNonSpaceOperator = nonSpaceOperator; | ||
nonSpaceOperator = false; | ||
} | ||
return args; | ||
return sequence; | ||
} | ||
@@ -1083,6 +1083,6 @@ | ||
function getNotFunction(scope, info) { | ||
var args; | ||
var selectors; | ||
scanner.eat(LEFTPARENTHESIS); | ||
args = getNotFunctionArguments(scope); | ||
selectors = getNotFunctionArguments(scope); | ||
scanner.eat(RIGHTPARENTHESIS); | ||
@@ -1094,3 +1094,3 @@ | ||
// name: name, // TODO: add name? | ||
sequence: args // FIXME: -> arguments? | ||
sequence: selectors // TODO: sequence -> selectors | ||
}; | ||
@@ -1101,26 +1101,17 @@ } | ||
function getVarFunctionArguments() { // TODO: special type Variable? | ||
var args = new List(); | ||
var sequence = new List(); | ||
readSC(); | ||
args.appendData({ | ||
type: 'Argument', | ||
sequence: new List().appendData(getIdentifier(true)) | ||
}); | ||
sequence.appendData(getIdentifier(true)); | ||
readSC(); | ||
if (scanner.tokenType === COMMA) { | ||
scanner.eat(COMMA); | ||
readSC(); | ||
sequence.appendData(getOperator()); | ||
args.appendData({ | ||
type: 'Argument', | ||
sequence: new List().appendData(getValue(true)) | ||
}); | ||
readSC(); | ||
sequence.appendData(getValue(true, null)); | ||
readSC(); | ||
} | ||
return args; | ||
return sequence; | ||
} | ||
@@ -1170,7 +1161,7 @@ | ||
function getOldIEExpression(scope, info, name) { | ||
var start = scanner.tokenStart + 1; // skip open parenthesis | ||
var raw; | ||
scanner.eat(LEFTPARENTHESIS); | ||
var start = scanner.tokenStart; | ||
var raw; | ||
for (var balance = 0; !scanner.eof; scanner.next()) { | ||
@@ -1197,8 +1188,5 @@ if (scanner.tokenType === RIGHTPARENTHESIS) { | ||
name: name, | ||
arguments: new List().appendData({ | ||
type: 'Argument', | ||
sequence: new List().appendData({ | ||
type: 'Raw', | ||
value: raw | ||
}) | ||
sequence: new List().appendData({ | ||
type: 'Raw', | ||
value: raw | ||
}) | ||
@@ -1367,6 +1355,3 @@ }; | ||
name: readIdent(false), | ||
arguments: new List().appendData({ | ||
type: 'Argument', | ||
sequence: sequence | ||
}) | ||
sequence: sequence | ||
}; | ||
@@ -1497,3 +1482,3 @@ | ||
var offset = 0; | ||
var tokenType = scanner.lookupType(offset); | ||
var tokenType = scanner.tokenType; | ||
@@ -1541,2 +1526,3 @@ if (tokenType === HYPHENMINUS) { | ||
function getFilterValue() { // TODO | ||
var sequence = new List(); | ||
var progid; | ||
@@ -1546,10 +1532,10 @@ var node = { | ||
info: getInfo(), | ||
sequence: new List() | ||
sequence: sequence | ||
}; | ||
while (progid = checkProgid()) { | ||
node.sequence.appendData(getProgid(progid)); | ||
sequence.appendData(getProgid(progid)); | ||
} | ||
readSC(node); | ||
readSC(); | ||
@@ -1750,3 +1736,3 @@ return node; | ||
if (context === 'value') { | ||
ast = initialContext.value(false, options.property); | ||
ast = getValue(false, options.property ? String(options.property) : null); | ||
} else { | ||
@@ -1753,0 +1739,0 @@ ast = initialContext[context](); |
@@ -29,12 +29,23 @@ 'use strict'; | ||
var ShortArray = typeof Uint8Array !== 'undefined' ? Uint8Array : Array; | ||
var LongArray = typeof Uint32Array !== 'undefined' && typeof Uint32Array.prototype.lastIndexOf === 'function' | ||
? Uint32Array | ||
: Array; | ||
var MIN_ARRAY_SIZE = 16 * 1024; | ||
var OFFSET_MASK = 0x00FFFFFF; | ||
var lastIndexOf = Array.prototype.lastIndexOf; // some browser implementations have no TypedArray#lastIndexOf | ||
var LongArray = typeof Uint32Array !== 'undefined' ? Uint32Array : Array; | ||
function linesLayout(scanner, source, start) { | ||
var offsetAndType = null; | ||
var lines = null; | ||
function firstCharOffset(source) { | ||
return source.charCodeAt(0) === 0xFEFF ? 1 : 0; | ||
} | ||
function computeLines(scanner, source) { | ||
var sourceLength = source.length; | ||
var start = firstCharOffset(source); | ||
var line = scanner.initLine; | ||
var lines = new LongArray(source.length + 1); | ||
if (lines === null || lines.length < sourceLength + 1) { | ||
lines = new LongArray(Math.max(sourceLength + 1024, MIN_ARRAY_SIZE)); | ||
} | ||
for (var i = start; i < sourceLength; i++) { | ||
@@ -54,5 +65,5 @@ var code = source.charCodeAt(i); | ||
lines[sourceLength] = line; | ||
lines[i] = line; | ||
scanner.lines = lines; | ||
return lines; | ||
} | ||
@@ -85,17 +96,9 @@ | ||
function findCommentEnd(source, offset) { | ||
for (; offset < source.length; offset++) { | ||
var starOffset = source.indexOf('*', offset); | ||
var commentEnd = source.indexOf('*/', offset); | ||
if (starOffset === -1) { | ||
offset = source.length; | ||
break; | ||
} | ||
offset = starOffset; | ||
if (source.charCodeAt(offset + 1) === SLASH) { | ||
return offset + 2; | ||
} | ||
if (commentEnd === -1) { | ||
return source.length; | ||
} | ||
return offset; | ||
return commentEnd + 2; | ||
} | ||
@@ -131,2 +134,25 @@ | ||
// skip escaped unicode sequence that can ends with space | ||
// [0-9a-f]{1,6}(\r\n|[ \n\r\t\f])? | ||
function findEscaseEnd(source, offset) { | ||
for (var i = 0; i < 7 && offset + i < source.length; i++) { | ||
var code = source.charCodeAt(offset + i); | ||
if (i !== 6 && isHex(code)) { | ||
continue; | ||
} | ||
if (i > 0) { | ||
offset += i - 1 + isNewline(source, offset + i, code); | ||
if (code === SPACE || code === TAB) { | ||
offset++; | ||
} | ||
} | ||
break; | ||
} | ||
return offset; | ||
} | ||
function findIdentifierEnd(source, offset) { | ||
@@ -137,22 +163,3 @@ for (; offset < source.length; offset++) { | ||
if (code === BACK_SLASH) { | ||
offset++; | ||
// skip escaped unicode sequence that can ends with space | ||
// [0-9a-f]{1,6}(\r\n|[ \n\r\t\f])? | ||
for (var i = 0; i < 7 && offset + i < source.length; i++) { | ||
code = source.charCodeAt(offset + i); | ||
if (i !== 6 && isHex(code)) { | ||
continue; | ||
} | ||
if (i > 0) { | ||
offset += i - 1 + isNewline(source, offset + i, code); | ||
if (code === SPACE || code === TAB) { | ||
offset++; | ||
} | ||
} | ||
break; | ||
} | ||
offset = findEscaseEnd(source, offset + 1); | ||
} else if (code < SYMBOL_CATEGORY_LENGTH && IS_PUNCTUATOR[code] === PUNCTUATOR) { | ||
@@ -168,10 +175,10 @@ break; | ||
var sourceLength = source.length; | ||
var offsets = new LongArray(sourceLength + 1); | ||
var types = new ShortArray(sourceLength); | ||
var tokenCount = 0; | ||
var prevType = 0; | ||
var start = startPos; | ||
var prev = 0; | ||
var end; | ||
offsets[sourceLength] = sourceLength; | ||
if (offsetAndType === null || offsetAndType.length < sourceLength + 1) { | ||
offsetAndType = new LongArray(Math.max(sourceLength + 1024, MIN_ARRAY_SIZE)); | ||
} | ||
@@ -188,14 +195,14 @@ while (start < sourceLength) { | ||
case PUNCTUATOR: | ||
if (code === STAR && prev === SLASH) { // /* | ||
if (code === STAR && prevType === SLASH) { // /* | ||
type = COMMENT; | ||
end = findCommentEnd(source, start + 1); | ||
// rewrite prev token | ||
// rewrite prevType token | ||
tokenCount--; | ||
start--; | ||
break; | ||
} else { | ||
type = code; | ||
end = start + 1; | ||
} | ||
type = code; | ||
end = start + 1; | ||
break; | ||
@@ -216,14 +223,12 @@ | ||
// console.log(type, scanner.source.substring(start, end)); | ||
offsets[tokenCount] = start; | ||
types[tokenCount] = type; | ||
offsetAndType[tokenCount] = (type << 24) | start; | ||
tokenCount++; | ||
start = end; | ||
prev = type; | ||
prevType = type; | ||
} | ||
offsets[tokenCount] = end; | ||
offsetAndType[tokenCount] = end; | ||
scanner.types = types; | ||
scanner.offsets = offsets; | ||
scanner.offsetAndType = offsetAndType; | ||
scanner.tokenCount = tokenCount; | ||
@@ -237,3 +242,3 @@ } | ||
var Scanner = function(source, initLine, initColumn) { | ||
var start = source.charCodeAt(0) === 0xFEFF ? 1 : 0; | ||
var start = firstCharOffset(source); | ||
@@ -243,6 +248,6 @@ this.source = source; | ||
this.initColumn = (typeof initColumn === 'undefined' ? 1 : initColumn) - start; | ||
this.lastLocationLine = this.initLine; | ||
this.lastLocationLineOffset = 1 - this.initColumn; | ||
this.lines = null; | ||
linesLayout(this, source, start); | ||
tokenLayout(this, source, start); | ||
this.eof = false; | ||
@@ -253,2 +258,4 @@ this.currentToken = -1; | ||
this.tokenEnd = start; | ||
tokenLayout(this, source, start); | ||
this.next(); | ||
@@ -262,3 +269,3 @@ }; | ||
if (offset < this.tokenCount) { | ||
return this.types[offset]; | ||
return this.offsetAndType[offset] >> 24; | ||
} | ||
@@ -272,3 +279,8 @@ | ||
if (offset < this.tokenCount) { | ||
return cmpStr(this.source, this.offsets[offset], this.offsets[offset + 1], referenceStr); | ||
return cmpStr( | ||
this.source, | ||
this.offsetAndType[offset] & OFFSET_MASK, | ||
this.offsetAndType[offset + 1] & OFFSET_MASK, | ||
referenceStr | ||
); | ||
} | ||
@@ -296,5 +308,5 @@ | ||
this.currentToken = next; | ||
this.tokenType = this.types[next]; | ||
this.tokenStart = this.offsets[next]; | ||
this.tokenEnd = this.offsets[next + 1]; | ||
this.tokenType = this.offsetAndType[next] >> 24; | ||
this.tokenStart = this.offsetAndType[next] & OFFSET_MASK; | ||
this.tokenEnd = this.offsetAndType[next + 1] & OFFSET_MASK; | ||
} else { | ||
@@ -312,5 +324,5 @@ this.currentToken = this.tokenCount; | ||
this.currentToken = next; | ||
this.tokenType = this.types[next]; | ||
this.tokenType = this.offsetAndType[next] >> 24; | ||
this.tokenStart = this.tokenEnd; | ||
this.tokenEnd = this.offsets[next + 1]; | ||
this.tokenEnd = this.offsetAndType[next + 1] & OFFSET_MASK; | ||
} else { | ||
@@ -342,7 +354,26 @@ this.currentToken = this.tokenCount; | ||
getLocation: function(offset, source) { | ||
if (this.lines === null) { | ||
this.lines = computeLines(this, this.source); | ||
} | ||
var line = this.lines[offset]; | ||
var column = line === this.initLine | ||
? offset + this.initColumn | ||
: offset - this.lines.lastIndexOf(line - 1, offset); | ||
var column = offset; | ||
var lineOffset; | ||
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; | ||
} | ||
return { | ||
@@ -356,3 +387,3 @@ source: source, | ||
findLastNonSpaceLocation: function() { | ||
for (var i = this.offsets[this.currentToken] - 1; i >= 0; i--) { | ||
for (var i = (this.offsetAndType[this.currentToken] & OFFSET_MASK) - 1; i >= 0; i--) { | ||
var code = this.source.charCodeAt(i); | ||
@@ -385,4 +416,4 @@ | ||
// fix soft deoptimizations (insufficient type feedback) | ||
new Scanner('\n\r\r\n\f//""\'\'/*\r\n\f*/1a;.{url(a)}'); | ||
new Scanner('\n\r\r\n\f//""\'\'/*\r\n\f*/1a;.\\31\t\+2{url(a)}'); | ||
module.exports = Scanner; |
@@ -8,7 +8,7 @@ function isHex(code) { | ||
function cmpStr(testStr, start, end, referenceStr) { | ||
if (start < 0 || end > testStr.length) { | ||
if (end - start !== referenceStr.length) { | ||
return false; | ||
} | ||
if (end - start !== referenceStr.length) { | ||
if (start < 0 || end > testStr.length) { | ||
return false; | ||
@@ -34,5 +34,10 @@ } | ||
function endsWith(testStr, referenceStr) { | ||
return cmpStr(testStr, testStr.length - referenceStr.length, testStr.length, referenceStr); | ||
} | ||
module.exports = { | ||
isHex: isHex, | ||
cmpStr: cmpStr | ||
cmpStr: cmpStr, | ||
endsWith: endsWith | ||
}; |
var stringifySyntax = require('./stringify'); | ||
var translateCss = require('../utils/translate'); | ||
var walk = require('../utils/walk').all; | ||
function contains(node, searchFor) { | ||
var found = false; | ||
walk(node, function(descendant) { | ||
if (descendant === searchFor) { | ||
found = true; | ||
} | ||
}); | ||
return found; | ||
} | ||
var SyntaxParseError = function(message, syntaxStr, offset) { | ||
@@ -22,3 +35,3 @@ var error = new SyntaxError(); | ||
value.sequence.each(function(node) { | ||
if (badNode && badNode.data === node) { | ||
if (badNode === node || (badNode && contains(node, badNode))) { | ||
errorOffset = css.length; | ||
@@ -39,4 +52,4 @@ } | ||
error.css = css; | ||
error.line = badNode && badNode.info ? badNode.info.line : 1; | ||
error.column = badNode && badNode.info ? badNode.info.column : 1; | ||
error.line = badNode && badNode.info ? badNode.info.line : undefined; | ||
error.column = badNode && badNode.info ? badNode.info.column : undefined; | ||
error.offset = errorOffset; | ||
@@ -43,0 +56,0 @@ error.message = message + '\n' + |
@@ -19,2 +19,4 @@ var List = require('../utils/list'); | ||
var matchCount = 0; | ||
var lastNode = null; | ||
var badNode = null; | ||
@@ -31,7 +33,12 @@ mismatch: | ||
for (var i = 0; i < syntaxNode.terms.length; i++) { | ||
var res = match(syntax, syntaxNode.terms[i], node); | ||
if (res && res.match) { | ||
var term = syntaxNode.terms[i]; | ||
var res = match(syntax, term, node); | ||
if (res.match) { | ||
result.push(res.match); | ||
node = res.next; | ||
break next; // continue matching | ||
} else if (res.badNode) { | ||
badNode = res.badNode; | ||
break mismatch; | ||
} | ||
@@ -46,8 +53,11 @@ } | ||
var commaMissed = false; | ||
for (var i = 0; i < syntaxNode.terms.length; i++) { | ||
var term = syntaxNode.terms[i]; | ||
var res = match(syntax, term, node); | ||
if (res && res.match) { | ||
if (res.match) { | ||
if (term.type === 'Comma' && i !== 0 && !hasTailMatch) { | ||
// recover cursor to state before last match and stop matching | ||
lastNode = node && node.data; | ||
node = beforeMatchNode; | ||
@@ -61,2 +71,3 @@ break mismatch; | ||
if (commaMissed) { | ||
lastNode = node && node.data; | ||
node = beforeMatchNode; | ||
@@ -72,2 +83,5 @@ break mismatch; | ||
node = skipSpaces(res.next); | ||
} else if (res.badNode) { | ||
badNode = res.badNode; | ||
break mismatch; | ||
} else { | ||
@@ -84,2 +98,3 @@ // it's ok when comma doesn't match when no matches yet | ||
// recover cursor to state before last match and stop matching | ||
lastNode = res.lastNode || (node && node.data); | ||
node = beforeMatchNode; | ||
@@ -94,2 +109,3 @@ break mismatch; | ||
// recover cursor to state before last match and stop matching | ||
lastNode = node && node.data; | ||
node = beforeMatchNode; | ||
@@ -101,2 +117,3 @@ break mismatch; | ||
if (lastMatchedTerm && lastMatchedTerm.type === 'Comma' && term.type !== 'Comma') { | ||
lastNode = node && node.data; | ||
node = beforeMatchNode; | ||
@@ -120,3 +137,4 @@ break mismatch; | ||
var res = match(syntax, term, node); | ||
if (res && res.match) { | ||
if (res.match) { | ||
// non-empty match | ||
@@ -135,2 +153,5 @@ if (res.match.match.length) { | ||
break; | ||
} else if (res.badNode) { | ||
badNode = res.badNode; | ||
break mismatch; | ||
} | ||
@@ -146,2 +167,3 @@ } | ||
// not ok | ||
lastNode = node && node.data; | ||
node = beforeMatchNode; | ||
@@ -155,2 +177,3 @@ break mismatch; | ||
// recover cursor to state before last match and stop matching | ||
lastNode = node && node.data; | ||
node = beforeMatchNode; | ||
@@ -174,3 +197,3 @@ break mismatch; | ||
var res = match(syntax, term, node); | ||
if (res && res.match) { | ||
if (res.match) { | ||
// non-empty match | ||
@@ -189,2 +212,5 @@ if (res.match.match.length) { | ||
break; | ||
} else if (res.badNode) { | ||
badNode = res.badNode; | ||
break mismatch; | ||
} | ||
@@ -202,2 +228,3 @@ } | ||
// recover cursor to state before last match and stop matching | ||
lastNode = node && node.data; | ||
node = beforeMatchNode; | ||
@@ -226,20 +253,5 @@ break mismatch; | ||
// convert arguments into plain list for now, otherwise it's become too complicated to match | ||
var list = new List(); | ||
if (node) { | ||
node.data.arguments.each(function(argument) { | ||
if (list.head) { | ||
list.insert(list.createItem({ | ||
type: 'Operator', | ||
info: null, | ||
value: ',' | ||
})); | ||
} | ||
list.appendList(argument.sequence.copy()); | ||
}); | ||
} | ||
var res = match(syntax, syntaxNode.sequence, list.head); | ||
if (!res || !res.match || res.next) { | ||
var res = match(syntax, syntaxNode.sequence, node.data.sequence.head); | ||
if (!res.match || res.next) { | ||
badNode = res.badNode || res.lastNode || (res.next ? res.next.data : null) || node.data; | ||
break mismatch; | ||
@@ -261,3 +273,4 @@ } | ||
var res = match(syntax, syntaxNode.sequence, node.data.sequence.head); | ||
if (!res || !res.match || res.next) { | ||
if (!res.match || res.next) { | ||
badNode = res.badNode || res.lastNode || (res.next ? res.next.data : null) || node.data; // TODO: case when res.next === null | ||
break mismatch; | ||
@@ -278,2 +291,4 @@ } | ||
if (!res || !res.match) { | ||
badNode = res && res.badNode; // TODO: case when res.next === null | ||
lastNode = (res && res.lastNode) || (node && node.data); | ||
break mismatch; | ||
@@ -294,2 +309,4 @@ } | ||
if (!res || !res.match) { | ||
badNode = res && res.badNode; // TODO: case when res.next === null | ||
lastNode = (res && res.lastNode) || (node && node.data); | ||
break mismatch; | ||
@@ -365,2 +382,3 @@ } | ||
} else { | ||
lastNode = node && node.data; | ||
break mismatch; | ||
@@ -371,2 +389,4 @@ } | ||
// console.log(syntaxNode.type, badNode, lastNode); | ||
if (lastComma && lastCommaTermCount === result.length) { | ||
@@ -377,3 +397,14 @@ // nothing match after comma | ||
if (badNode) { | ||
return { | ||
badNode: badNode, | ||
lastNode: null, | ||
next: null, | ||
match: null | ||
}; | ||
} | ||
return { | ||
badNode: null, | ||
lastNode: lastNode, | ||
next: node, | ||
@@ -380,0 +411,0 @@ match: matchCount < min ? null : { |
@@ -23,9 +23,13 @@ var MatchError = require('./error').MatchError; | ||
function unwrapNode(item) { | ||
return item && item.data; | ||
} | ||
function matchSyntax(dictionary, syntax, value) { | ||
var result = syntax.match(value.sequence.head); | ||
var result = match(dictionary, dictionary.valueCommonSyntax, value.sequence.head); | ||
if (!result || !result.match) { | ||
result = match(dictionary, dictionary.valueCommonSyntax, value.sequence.head); | ||
if (!result.match) { | ||
result = syntax.match(value.sequence.head); | ||
if (!result || !result.match) { | ||
dictionary.lastMatchError = MatchError('Mismatch', syntax.syntax, value, result.next); | ||
dictionary.lastMatchError = new MatchError('Mismatch', syntax.syntax, value, result.badNode || unwrapNode(result.next)); | ||
return null; | ||
@@ -36,3 +40,3 @@ } | ||
if (result.next) { | ||
dictionary.lastMatchError = MatchError('Uncomplete match', syntax.syntax, value, result.next); | ||
dictionary.lastMatchError = new MatchError('Uncomplete match', syntax.syntax, value, result.badNode || unwrapNode(result.next)); | ||
return null; | ||
@@ -116,3 +120,3 @@ } | ||
if (!propertySyntax) { | ||
this.lastMatchError = new Error('Unknown property for syntax match: ' + propertyName); | ||
this.lastMatchError = new Error('Unknown property: ' + propertyName); | ||
return null; | ||
@@ -127,3 +131,3 @@ } | ||
if (!typeSyntax) { | ||
this.lastMatchError = new Error('Unknown type for syntax match: ' + typeName); | ||
this.lastMatchError = new Error('Unknown type: ' + typeName); | ||
return null; | ||
@@ -130,0 +134,0 @@ } |
@@ -247,2 +247,7 @@ // | ||
List.prototype.clear = function() { | ||
this.head = null; | ||
this.tail = null; | ||
}; | ||
List.prototype.copy = function() { | ||
@@ -249,0 +254,0 @@ var result = new List(); |
function each(list) { | ||
if (list.head === null) { | ||
return ''; | ||
var cursor = list.head; | ||
var result = ''; | ||
if (cursor === null) { | ||
return result; | ||
} | ||
if (list.head === list.tail) { | ||
if (cursor === list.tail) { | ||
return translate(list.head.data); | ||
} | ||
return list.map(translate).join(''); | ||
while (cursor !== null) { | ||
result += translate(cursor.data); | ||
cursor = cursor.next; | ||
} | ||
return result; | ||
} | ||
function eachDelim(list, delimeter) { | ||
if (list.head === null) { | ||
return ''; | ||
var cursor = list.head; | ||
var result = ''; | ||
if (cursor === null) { | ||
return result; | ||
} | ||
if (list.head === list.tail) { | ||
if (cursor === list.tail) { | ||
return translate(list.head.data); | ||
} | ||
return list.map(translate).join(delimeter); | ||
while (true) { | ||
result += translate(cursor.data); | ||
cursor = cursor.next; | ||
if (cursor === null) { | ||
break; | ||
} | ||
result += delimeter; | ||
} | ||
return result; | ||
} | ||
function translateAtRule(node) { | ||
var result = '@' + node.name; | ||
if (node.expression && !node.expression.sequence.isEmpty()) { | ||
result += ' ' + translate(node.expression); | ||
} | ||
if (node.block) { | ||
result += '{' + translate(node.block) + '}'; | ||
} else { | ||
result += ';'; | ||
} | ||
return result; | ||
} | ||
function translateSimpleSelector(list) { | ||
var cursor = list.head; | ||
var result = ''; | ||
if (cursor === null) { | ||
return result; | ||
} | ||
if (cursor === list.tail) { | ||
return translate(list.head.data); | ||
} | ||
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); | ||
} | ||
cursor = cursor.next; | ||
} | ||
return result; | ||
} | ||
function translate(node) { | ||
@@ -31,17 +92,5 @@ switch (node.type) { | ||
case 'Atrule': | ||
var nodes = ['@', node.name]; | ||
return translateAtRule(node); | ||
if (node.expression && !node.expression.sequence.isEmpty()) { | ||
nodes.push(' ', translate(node.expression)); | ||
} | ||
if (node.block) { | ||
nodes.push('{', translate(node.block), '}'); | ||
} else { | ||
nodes.push(';'); | ||
} | ||
return nodes.join(''); | ||
case 'Ruleset': | ||
case 'Rule': | ||
return translate(node.selector) + '{' + translate(node.block) + '}'; | ||
@@ -53,13 +102,4 @@ | ||
case 'SimpleSelector': | ||
var nodes = node.sequence.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 translateSimpleSelector(node.sequence); | ||
return translate(node); | ||
}); | ||
return nodes.join(''); | ||
case 'Block': | ||
@@ -70,4 +110,4 @@ return eachDelim(node.declarations, ';'); | ||
return node.important | ||
? translate(node.property) + ':' + translate(node.value) + '!important' | ||
: translate(node.property) + ':' + translate(node.value); | ||
? node.property + ':' + translate(node.value) + '!important' | ||
: node.property + ':' + translate(node.value); | ||
@@ -104,6 +144,6 @@ case 'Property': | ||
case 'FunctionalPseudo': | ||
return ':' + node.name + '(' + eachDelim(node.arguments, ',') + ')'; | ||
return ':' + node.name + '(' + each(node.sequence) + ')'; | ||
case 'Function': | ||
return node.name + '(' + eachDelim(node.arguments, ',') + ')'; | ||
return node.name + '(' + each(node.sequence) + ')'; | ||
@@ -116,3 +156,2 @@ case 'Negation': | ||
case 'Argument': | ||
case 'AtruleExpression': | ||
@@ -119,0 +158,0 @@ return each(node.sequence); |
@@ -149,3 +149,3 @@ var SourceMapGenerator = require('source-map').SourceMapGenerator; | ||
case 'Ruleset': | ||
case 'Rule': | ||
return createAnonymousSourceNode([ | ||
@@ -177,3 +177,3 @@ translate(node.selector), '{', translate(node.block), '}' | ||
node.info, | ||
[translate(node.property), ':', translate(node.value), '!important'] | ||
[node.property, ':', translate(node.value), '!important'] | ||
); | ||
@@ -183,3 +183,3 @@ } else { | ||
node.info, | ||
[translate(node.property), ':', translate(node.value)] | ||
[node.property, ':', translate(node.value)] | ||
); | ||
@@ -218,6 +218,6 @@ } | ||
case 'FunctionalPseudo': | ||
return ':' + node.name + '(' + eachDelim(node.arguments, ',') + ')'; | ||
return ':' + node.name + '(' + each(node.sequence) + ')'; | ||
case 'Function': | ||
return node.name + '(' + eachDelim(node.arguments, ',') + ')'; | ||
return node.name + '(' + each(node.sequence) + ')'; | ||
@@ -230,3 +230,2 @@ case 'Negation': | ||
case 'Argument': | ||
case 'AtruleExpression': | ||
@@ -233,0 +232,0 @@ return each(node.sequence); |
@@ -20,3 +20,3 @@ function walkRules(node, item, list) { | ||
case 'Ruleset': | ||
case 'Rule': | ||
this.fn(node, item, list); | ||
@@ -47,3 +47,3 @@ break; | ||
case 'Ruleset': | ||
case 'Rule': | ||
this.fn(node, item, list); | ||
@@ -71,4 +71,4 @@ break; | ||
case 'Ruleset': | ||
this.ruleset = node; | ||
case 'Rule': | ||
this.rule = node; | ||
@@ -79,3 +79,3 @@ if (node.block !== null) { | ||
this.ruleset = null; | ||
this.rule = null; | ||
break; | ||
@@ -105,4 +105,4 @@ } | ||
case 'Ruleset': | ||
this.ruleset = node; | ||
case 'Rule': | ||
this.rule = node; | ||
@@ -114,3 +114,3 @@ if (node.selector !== null) { | ||
this.ruleset = null; | ||
this.rule = null; | ||
break; | ||
@@ -134,3 +134,2 @@ | ||
walkAll.call(this, node.property); | ||
walkAll.call(this, node.value); | ||
@@ -152,3 +151,3 @@ | ||
node.arguments.each(walkAll, this); | ||
node.sequence.each(walkAll, this); | ||
@@ -208,3 +207,3 @@ this['function'] = null; | ||
atruleExpression: null, | ||
ruleset: null, | ||
rule: null, | ||
selector: null, | ||
@@ -211,0 +210,0 @@ declaration: null, |
{ | ||
"name": "css-tree", | ||
"version": "1.0.0-alpha5", | ||
"version": "1.0.0-alpha6", | ||
"description": "Detailed CSS parser", | ||
@@ -5,0 +5,0 @@ "keywords": [ |
[![NPM version](https://img.shields.io/npm/v/css-tree.svg)](https://www.npmjs.com/package/css-tree) | ||
[![Build Status](https://travis-ci.org/csstree/csstree.svg?branch=master)](https://travis-ci.org/csstree/csstree) | ||
[![Coverage Status](https://coveralls.io/repos/github/csstree/csstree/badge.svg?branch=master)](https://coveralls.io/github/csstree/csstree?branch=master) | ||
[![Join the CSSTree chat at https://gitter.im/csstree/csstree](https://badges.gitter.im/csstree/csstree.svg)](https://gitter.im/csstree/csstree) | ||
* [CSS syntax reference](https://csstree.github.io/docs/syntax.html) | ||
@@ -16,2 +16,3 @@ * [CSS syntax validator](https://csstree.github.io/docs/validator.html) | ||
* [VS Code plugin](https://github.com/csstree/vscode-csstree) | ||
* [Atom plugin](https://github.com/csstree/atom-csstree-validator) | ||
@@ -18,0 +19,0 @@ ## Install |
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
562230
32
13147
188