Comparing version 1.0.0-alpha24 to 1.0.0-alpha25
@@ -78,3 +78,3 @@ # AST format | ||
"name": String, | ||
"prelude": <AtrulePrelude> | null, | ||
"prelude": <AtrulePrelude> | <Raw> | null, | ||
"block": <Block> | null | ||
@@ -81,0 +81,0 @@ } |
@@ -0,1 +1,18 @@ | ||
## 1.0.0-alpha25 (October 9, 2017) | ||
- Parser | ||
- Added fallback node as argument to `onParseError()` handler | ||
- Fixed raw consuming in tolerant mode when selector is invalid (greedy consuming and redundant warnings) | ||
- Fixed exception in tolerant mode caused by unknown at-rule with unclosed block | ||
- Changed handling of semicolons: | ||
- Hanging semicolon inside declaration blocks turns into a `Raw` node instead of being ignored | ||
- Semicolon outside of declaration blocks opens a `Rule` node as part of selector instead of being ignored | ||
- Aligned `parseAtrulePrelude` behaviour to `parseRulePrelude` | ||
- Removed `Raw` node wraping into `AtrulePrelude` when `parseAtrulePrelude` is disabled | ||
- Removed error emitting when at-rule has a custom prelude customer but no prelude is found (it should be validated by a lexer later) | ||
- Generator | ||
- Fixed performance issue with `translateWithSourceMap()`, flattening the string (because of mixing building string and indexing into it) turned it into a quadratic algorithm (approximate numbers can be found in [the quiz created by this case](https://gist.github.com/lahmatiy/ea25d0e623d88ca9848384b5707d52d9)) | ||
- Added support for a single solidus hack for `property()` | ||
- Minor fixes for custom errors | ||
## 1.0.0-alpha24 (September 14, 2017) | ||
@@ -2,0 +19,0 @@ |
@@ -78,13 +78,26 @@ 'use strict'; | ||
return function(node, enter, leave) { | ||
function updatePos(str) { | ||
for (var i = 0; i < str.length; i++) { | ||
if (str.charCodeAt(i) === 10) { // \n | ||
line++; | ||
column = 0; | ||
} else { | ||
column++; | ||
} | ||
} | ||
return str; | ||
} | ||
function walk(node, buffer) { | ||
var value = node.value; | ||
enter(node.node, buffer, value); | ||
enter(node.node, buffer, line, column); | ||
if (typeof value === 'string') { | ||
buffer += value; | ||
buffer += updatePos(value); | ||
} else { | ||
for (var i = 0; i < value.length; i++) { | ||
if (typeof value[i] === 'string') { | ||
buffer += value[i]; | ||
buffer += updatePos(value[i]); | ||
} else { | ||
@@ -96,3 +109,3 @@ buffer = walk(value[i], buffer); | ||
leave(node.node, buffer, value); | ||
leave(node.node, buffer, line, column); | ||
@@ -110,5 +123,9 @@ return buffer; | ||
var buffer = []; | ||
var line = 1; | ||
var column = 0; | ||
context.generate(function() { | ||
buffer.push.apply(buffer, arguments); | ||
}, node); | ||
return walk(buffer[0], ''); | ||
@@ -115,0 +132,0 @@ }; |
@@ -11,15 +11,3 @@ 'use strict'; | ||
module.exports = function generateSourceMap(generator, ast) { | ||
function updateGeneratedPos(buffer) { | ||
for (; bufferPos < buffer.length; bufferPos++) { | ||
if (buffer.charCodeAt(bufferPos) === 10) { // \n | ||
generated.line++; | ||
generated.column = 0; | ||
} else { | ||
generated.column++; | ||
} | ||
} | ||
} | ||
var map = new SourceMapGenerator(); | ||
var bufferPos = 0; | ||
var generated = { | ||
@@ -30,3 +18,3 @@ line: 1, | ||
var original = { | ||
line: 0, | ||
line: 0, // should be zero to add first mapping | ||
column: 0 | ||
@@ -43,3 +31,3 @@ }; | ||
var css = generator(ast, function(node, buffer) { | ||
var css = generator(ast, function(node, buffer, line, column) { | ||
if (!node.loc || | ||
@@ -51,11 +39,12 @@ !node.loc.start || | ||
var line = node.loc.start.line; | ||
var column = node.loc.start.column - 1; | ||
var nodeLine = node.loc.start.line; | ||
var nodeColumn = node.loc.start.column - 1; | ||
if (original.line !== line || | ||
original.column !== column) { | ||
original.line = line; | ||
original.column = column; | ||
if (original.line !== nodeLine || | ||
original.column !== nodeColumn) { | ||
original.line = nodeLine; | ||
original.column = nodeColumn; | ||
updateGeneratedPos(buffer); | ||
generated.line = line; | ||
generated.column = column; | ||
@@ -78,7 +67,6 @@ if (sourceMappingActive) { | ||
}, function(node, buffer) { | ||
}, function(node, buffer, line, column) { | ||
if (sourceMappingActive && trackNodes.hasOwnProperty(node.type)) { | ||
updateGeneratedPos(buffer); | ||
activatedGenerated.line = generated.line; | ||
activatedGenerated.column = generated.column; | ||
activatedGenerated.line = line; | ||
activatedGenerated.column = column; | ||
} | ||
@@ -85,0 +73,0 @@ }); |
'use strict'; | ||
var createCustomError = require('../utils/createCustomError'); | ||
var translateGrammar = require('./grammar/translate'); | ||
@@ -16,9 +17,5 @@ | ||
var SyntaxReferenceError = function(type, referenceName) { | ||
// some VMs prevent setting line/column otherwise (iOS Safari 10 even throw an exception) | ||
var error = Object.create(SyntaxError.prototype); | ||
var error = createCustomError('SyntaxReferenceError', type + ' `' + referenceName + '`'); | ||
error.name = 'SyntaxReferenceError'; | ||
error.reference = referenceName; | ||
error.message = type + ' `' + referenceName + '`'; | ||
error.stack = (new Error().stack || '').replace(/^.+\n/, error.name + ': ' + error.message + '\n'); | ||
@@ -29,4 +26,3 @@ return error; | ||
var MatchError = function(message, lexer, syntax, value, badNode) { | ||
// some VMs prevent setting line/column otherwise (iOS Safari 10 even throw an exception) | ||
var error = Object.create(SyntaxError.prototype); | ||
var error = createCustomError('SyntaxMatchError', message); | ||
var errorOffset = -1; | ||
@@ -45,5 +41,3 @@ var start = getLocation(badNode, 'start'); | ||
error.name = 'SyntaxMatchError'; | ||
error.rawMessage = message; | ||
error.stack = (new Error().stack || '').replace(/^.+\n/, error.name + ': ' + message + '\n'); | ||
error.syntax = syntax ? translateGrammar(syntax) : '<generic>'; | ||
@@ -50,0 +44,0 @@ error.css = css; |
'use strict'; | ||
var createCustomError = require('../../utils/createCustomError'); | ||
var SyntaxParseError = function(message, syntaxStr, offset) { | ||
// some VMs prevent setting line/column otherwise (iOS Safari 10 even throw an exception) | ||
var error = Object.create(SyntaxError.prototype); | ||
var error = createCustomError('SyntaxParseError', message); | ||
error.name = 'SyntaxParseError'; | ||
error.rawMessage = message; | ||
error.stack = (new Error().stack || '').replace(/^.+\n/, error.name + ': ' + message + '\n'); | ||
error.syntax = syntaxStr; | ||
@@ -11,0 +10,0 @@ error.offset = offset; |
@@ -57,8 +57,2 @@ 'use strict'; | ||
function translate(node, forceBraces, decorate) { | ||
if (Array.isArray(node)) { | ||
return node.map(function(item) { | ||
return translate(item, forceBraces, decorate); | ||
}).join(''); | ||
} | ||
var result; | ||
@@ -103,3 +97,3 @@ | ||
default: | ||
throw new Error('Unknown node type: ' + node.type); | ||
throw new Error('Unknown node type `' + node.type + '`'); | ||
} | ||
@@ -106,0 +100,0 @@ |
@@ -91,4 +91,5 @@ 'use strict'; | ||
} catch (e) { | ||
this.onParseError(e); | ||
return fallback.call(this, start); | ||
var fallbackNode = fallback.call(this, start); | ||
this.onParseError(e, fallbackNode); | ||
return fallbackNode; | ||
} | ||
@@ -95,0 +96,0 @@ } else { |
@@ -5,5 +5,5 @@ module.exports = { | ||
block: function() { | ||
return this.Block(this.Declaration); | ||
return this.Block(true); | ||
} | ||
} | ||
}; |
@@ -11,5 +11,5 @@ var List = require('../../utils/list'); | ||
block: function() { | ||
return this.Block(this.Rule); | ||
return this.Block(false); | ||
} | ||
} | ||
}; |
var List = require('../../utils/list'); | ||
var TYPE = require('../../tokenizer').TYPE; | ||
var LEFTCURLYBRACKET = TYPE.LeftCurlyBracket; | ||
@@ -8,6 +6,2 @@ module.exports = { | ||
prelude: function() { | ||
if (this.scanner.lookupNonWSType(0) === LEFTCURLYBRACKET) { | ||
return null; | ||
} | ||
return new List().appendData( | ||
@@ -18,5 +12,5 @@ this.SelectorList() | ||
block: function() { | ||
return this.Block(this.Declaration); | ||
return this.Block(true); | ||
} | ||
} | ||
}; |
@@ -97,5 +97,5 @@ var List = require('../../utils/list'); | ||
block: function() { | ||
return this.Block(this.Rule); | ||
return this.Block(false); | ||
} | ||
} | ||
}; |
@@ -15,3 +15,3 @@ module.exports = { | ||
block: function() { | ||
return this.Block(this.Declaration); | ||
return this.Block(true); | ||
}, | ||
@@ -18,0 +18,0 @@ declarationList: 'DeclarationList', |
@@ -8,3 +8,7 @@ var TYPE = require('../../tokenizer').TYPE; | ||
function isBlockAtrule() { | ||
function consumeRaw(startToken) { | ||
return this.Raw(startToken, SEMICOLON, LEFTCURLYBRACKET, false, true); | ||
} | ||
function isDeclarationBlockAtrule() { | ||
for (var offset = 1, type; type = this.scanner.lookupType(offset); offset++) { | ||
@@ -21,2 +25,6 @@ if (type === RIGHTCURLYBRACKET) { | ||
if (this.tolerant) { | ||
return false; | ||
} | ||
this.scanner.skip(offset); | ||
@@ -30,3 +38,3 @@ this.scanner.eat(RIGHTCURLYBRACKET); | ||
name: String, | ||
prelude: ['AtrulePrelude', null], | ||
prelude: ['AtrulePrelude', 'Raw', null], | ||
block: ['Block', null] | ||
@@ -47,11 +55,29 @@ }, | ||
prelude = this.AtrulePrelude(name); | ||
// parse prelude | ||
if (this.scanner.eof === false && | ||
this.scanner.tokenType !== LEFTCURLYBRACKET && | ||
this.scanner.tokenType !== SEMICOLON) { | ||
if (this.parseAtrulePrelude) { | ||
var preludeStartToken = this.scanner.currentToken; | ||
prelude = this.tolerantParse(this.AtrulePrelude.bind(this, name), consumeRaw); | ||
// turn empty AtrulePrelude into null | ||
if (prelude.children.head === null) { | ||
prelude = null; | ||
if (this.tolerant && !this.scanner.eof) { | ||
if (prelude.type !== 'Raw' && | ||
this.scanner.tokenType !== LEFTCURLYBRACKET && | ||
this.scanner.tokenType !== SEMICOLON) { | ||
prelude = consumeRaw.call(this, preludeStartToken); | ||
} | ||
} | ||
// turn empty AtrulePrelude into null | ||
if (prelude.type === 'AtrulePrelude' && prelude.children.head === null) { | ||
prelude = null; | ||
} | ||
} else { | ||
prelude = consumeRaw.call(this, this.scanner.currentToken); | ||
} | ||
this.scanner.skipSC(); | ||
} | ||
this.scanner.skipSC(); | ||
if (this.atrule.hasOwnProperty(nameLowerCase)) { | ||
@@ -78,3 +104,3 @@ if (typeof this.atrule[nameLowerCase].block === 'function') { | ||
// TODO: should consume block content as Raw? | ||
block = this.Block(isBlockAtrule.call(this) ? this.Declaration : this.Rule); | ||
block = this.Block(isDeclarationBlockAtrule.call(this)); | ||
break; | ||
@@ -81,0 +107,0 @@ |
var List = require('../../utils/list'); | ||
var TYPE = require('../../tokenizer').TYPE; | ||
var SEMICOLON = TYPE.Semicolon; | ||
var LEFTCURLYBRACKET = TYPE.LeftCurlyBracket; | ||
function consumeRaw(startToken) { | ||
return new List().appendData( | ||
this.Raw(startToken, SEMICOLON, LEFTCURLYBRACKET, false, true) | ||
); | ||
} | ||
function consumeDefaultSequence() { | ||
return this.readSequence(this.scope.AtrulePrelude); | ||
} | ||
module.exports = { | ||
@@ -24,3 +10,2 @@ name: 'AtrulePrelude', | ||
var children = null; | ||
var startToken = this.scanner.currentToken; | ||
@@ -31,21 +16,11 @@ if (name !== null) { | ||
if (this.parseAtrulePrelude) { | ||
if (this.atrule.hasOwnProperty(name)) { | ||
// custom consumer | ||
if (this.atrule.hasOwnProperty(name)) { | ||
if (typeof this.atrule[name].prelude === 'function') { | ||
children = this.tolerantParse(this.atrule[name].prelude, consumeRaw); | ||
} | ||
} else { | ||
// default consumer | ||
this.scanner.skipSC(); | ||
children = this.tolerantParse(consumeDefaultSequence, consumeRaw); | ||
if (typeof this.atrule[name].prelude === 'function') { | ||
children = this.atrule[name].prelude.call(this); | ||
} | ||
if (this.tolerant) { | ||
if (this.scanner.eof || (this.scanner.tokenType !== SEMICOLON && this.scanner.tokenType !== LEFTCURLYBRACKET)) { | ||
children = consumeRaw.call(this, startToken); | ||
} | ||
} | ||
} else { | ||
children = consumeRaw.call(this, startToken); | ||
// default consumer | ||
this.scanner.skipSC(); | ||
children = this.readSequence(this.scope.AtrulePrelude); | ||
} | ||
@@ -52,0 +27,0 @@ |
@@ -12,5 +12,20 @@ var List = require('../../utils/list'); | ||
function consumeRaw(startToken) { | ||
return this.Raw(startToken, 0, 0, false, true); | ||
} | ||
function consumeRule() { | ||
return this.tolerantParse(this.Rule, consumeRaw); | ||
} | ||
function consumeRawDeclaration(startToken) { | ||
return this.Raw(startToken, 0, SEMICOLON, true, true); | ||
} | ||
function consumeDeclaration() { | ||
var node = this.tolerantParse(this.Declaration, consumeRawDeclaration); | ||
if (this.scanner.tokenType === SEMICOLON) { | ||
this.scanner.next(); | ||
} | ||
return node; | ||
} | ||
module.exports = { | ||
@@ -21,6 +36,4 @@ name: 'Block', | ||
}, | ||
parse: function(defaultConsumer) { | ||
if (!defaultConsumer) { | ||
defaultConsumer = this.Declaration; | ||
} | ||
parse: function(isDeclaration) { | ||
var consumer = isDeclaration ? consumeDeclaration : consumeRule; | ||
@@ -40,3 +53,2 @@ var start = this.scanner.tokenStart; | ||
case COMMENT: | ||
case SEMICOLON: | ||
this.scanner.next(); | ||
@@ -50,3 +62,3 @@ break; | ||
default: | ||
children.appendData(this.tolerantParse(defaultConsumer, consumeRaw)); | ||
children.appendData(consumer.call(this)); | ||
} | ||
@@ -53,0 +65,0 @@ } |
@@ -18,7 +18,19 @@ var TYPE = require('../../tokenizer').TYPE; | ||
var startOffset = this.scanner.tokenStart; | ||
var prelude = this.parseRulePrelude | ||
? this.tolerantParse(this.SelectorList, consumeRaw) | ||
: consumeRaw.call(this, startToken); | ||
var block = this.Block(this.Declaration); | ||
var prelude; | ||
var block; | ||
if (this.parseRulePrelude) { | ||
prelude = this.tolerantParse(this.SelectorList, consumeRaw); | ||
if (this.tolerant && !this.scanner.eof) { | ||
if (prelude.type !== 'Raw' && this.scanner.tokenType !== LEFTCURLYBRACKET) { | ||
prelude = consumeRaw.call(this, startToken); | ||
} | ||
} | ||
} else { | ||
prelude = consumeRaw.call(this, startToken); | ||
} | ||
block = this.Block(true); | ||
return { | ||
@@ -25,0 +37,0 @@ type: 'Rule', |
'use strict'; | ||
var createCustomError = require('../utils/createCustomError'); | ||
var MAX_LINE_LENGTH = 100; | ||
@@ -20,3 +21,3 @@ var OFFSET_CORRECTION = 60; | ||
var lines = error.source.split(/\n|\r\n?|\f/); | ||
var lines = error.source.split(/\r\n?|\n|\f/); | ||
var line = error.line; | ||
@@ -29,3 +30,3 @@ var column = error.column; | ||
// correct column according to replaced tab before column | ||
// column correction according to replaced tab before column | ||
column += (TAB_REPLACEMENT.length - 1) * (lines[line - 1].substr(0, column - 1).match(/\t/g) || []).length; | ||
@@ -52,12 +53,8 @@ | ||
processLines(line, endLine) | ||
].join('\n'); | ||
].filter(Boolean).join('\n'); | ||
} | ||
var CssSyntaxError = function(message, source, offset, line, column) { | ||
// some VMs prevent setting line/column otherwise (iOS Safari 10 even throw an exception) | ||
var error = Object.create(SyntaxError.prototype); | ||
var error = createCustomError('CssSyntaxError', message); | ||
error.name = 'CssSyntaxError'; | ||
error.message = message; | ||
error.stack = (new Error().stack || '').replace(/^.+\n/, error.name + ': ' + error.message + '\n'); | ||
error.source = source; | ||
@@ -64,0 +61,0 @@ error.offset = offset; |
@@ -55,4 +55,4 @@ 'use strict'; | ||
if (hack === '/' && property[1] === '/') { | ||
hack = '//'; | ||
if (hack === '/') { | ||
hack = property[1] === '/' ? '//' : '/'; | ||
} else if (hack !== '_' && | ||
@@ -59,0 +59,0 @@ hack !== '*' && |
{ | ||
"name": "css-tree", | ||
"version": "1.0.0-alpha24", | ||
"description": "Fast detailed CSS parser", | ||
"version": "1.0.0-alpha25", | ||
"description": "Fast detailed CSS parser and related tools", | ||
"keywords": [ | ||
"css", | ||
"ast", | ||
"tokenizer", | ||
"parser", | ||
"ast" | ||
"walker", | ||
"lexer", | ||
"generator", | ||
"utils", | ||
"syntax", | ||
"validation" | ||
], | ||
@@ -69,3 +76,3 @@ "homepage": "https://github.com/csstree/csstree", | ||
"jscs": "~3.0.7", | ||
"json-to-ast": "^1.2.15", | ||
"json-to-ast": "2.0.0-alpha1.3", | ||
"mocha": "^3.0.2", | ||
@@ -81,3 +88,3 @@ "uglify-js": "^2.6.1" | ||
"dist/csstree.js", | ||
"dist/csssyntax.js", | ||
"dist/default-syntax.json", | ||
"docs", | ||
@@ -84,0 +91,0 @@ "lib", |
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
576961
129
7858