Comparing version 1.0.0-alpha21 to 1.0.0-alpha22
@@ -0,1 +1,16 @@ | ||
## 1.0.0-alpha22 (September 8, 2017) | ||
- Parser | ||
- Fixed exception on parsing of unclosed `{}-block` in tolerant mode | ||
- Added tolerant mode support for `DeclarationList` | ||
- Added standalone entry point, i.e. default parser can be used via `require('css-tree/lib/parser')` (#47) | ||
- Generator | ||
- Changed generator to produce `+n` when `AnPlusB.a` is `+1` to be "round-trip" with parser | ||
- Added standalone entry point, i.e. default generators can be used via `require('css-tree/lib/generator')` | ||
- Walker | ||
- Added standalone entry point, i.e. default walkers can be used via `require('css-tree/lib/walker')` (#47) | ||
- Lexer | ||
- Added `default` keyword to the list of invalid values for `<custom-ident>` (since it reversed per [spec](https://www.w3.org/TR/css-values/#custom-idents)) | ||
- Convertors (`toPlainObject()` and `fromPlainObject()`) moved to `lib/convertor` (entry point is `require('css-tree/lib/convertor')`) | ||
## 1.0.0-alpha21 (September 5, 2017) | ||
@@ -2,0 +17,0 @@ |
@@ -1,118 +0,4 @@ | ||
'use strict'; | ||
var createGenerator = require('./create'); | ||
var config = require('../syntax/config/parser'); | ||
var hasOwnProperty = Object.prototype.hasOwnProperty; | ||
var noop = function() {}; | ||
function each(processChunk, node) { | ||
var list = node.children; | ||
var cursor = list.head; | ||
while (cursor !== null) { | ||
this.generate(processChunk, cursor.data, cursor, list); | ||
cursor = cursor.next; | ||
} | ||
} | ||
function eachComma(processChunk, node) { | ||
var list = node.children; | ||
var cursor = list.head; | ||
while (cursor !== null) { | ||
if (cursor.prev) { | ||
processChunk(','); | ||
} | ||
this.generate(processChunk, cursor.data, cursor, list); | ||
cursor = cursor.next; | ||
} | ||
} | ||
function createGenerator(types) { | ||
var context = { | ||
generate: function(processChunk, node, item, list) { | ||
if (hasOwnProperty.call(types, node.type)) { | ||
types[node.type].call(this, processChunk, node, item, list); | ||
} else { | ||
throw new Error('Unknown node type: ' + node.type); | ||
} | ||
}, | ||
each: each, | ||
eachComma: eachComma | ||
}; | ||
return function(node, fn) { | ||
if (typeof fn !== 'function') { | ||
// default generator concats all chunks in a single string | ||
var buffer = []; | ||
context.generate(function(chunk) { | ||
buffer.push(chunk); | ||
}, node); | ||
return buffer.join(''); | ||
} | ||
context.generate(fn, node); | ||
}; | ||
} | ||
function createMarkupGenerator(types) { | ||
var context = { | ||
generate: function(processChunk, node, item, list) { | ||
if (hasOwnProperty.call(types, node.type)) { | ||
var nodeBuffer = []; | ||
types[node.type].call(this, function(chunk) { | ||
nodeBuffer.push(chunk); | ||
}, node, item, list); | ||
processChunk({ | ||
node: node, | ||
value: nodeBuffer | ||
}); | ||
} else { | ||
throw new Error('Unknown node type: ' + node.type); | ||
} | ||
}, | ||
each: each, | ||
eachComma: eachComma | ||
}; | ||
return function(node, enter, leave) { | ||
function walk(node, buffer) { | ||
var value = node.value; | ||
enter(node.node, buffer, value); | ||
if (typeof value === 'string') { | ||
buffer += value; | ||
} else { | ||
for (var i = 0; i < value.length; i++) { | ||
if (typeof value[i] === 'string') { | ||
buffer += value[i]; | ||
} else { | ||
buffer = walk(value[i], buffer); | ||
} | ||
} | ||
} | ||
leave(node.node, buffer, value); | ||
return buffer; | ||
} | ||
if (typeof enter !== 'function') { | ||
enter = noop; | ||
} | ||
if (typeof leave !== 'function') { | ||
leave = noop; | ||
} | ||
var buffer = []; | ||
context.generate(function() { | ||
buffer.push.apply(buffer, arguments); | ||
}, node); | ||
return walk(buffer[0], ''); | ||
}; | ||
} | ||
module.exports = { | ||
createGenerator: createGenerator, | ||
createMarkupGenerator: createMarkupGenerator, | ||
sourceMap: require('./sourceMap') | ||
}; | ||
module.exports = createGenerator(config); |
'use strict'; | ||
module.exports = require('./syntax/default'); | ||
module.exports = require('./syntax'); |
@@ -169,2 +169,3 @@ 'use strict'; | ||
// https://developer.mozilla.org/en-US/docs/Web/CSS/custom-ident | ||
// https://drafts.csswg.org/css-values-4/#identifier-value | ||
function customIdent(node) { | ||
@@ -177,3 +178,4 @@ if (node.data.type !== 'Identifier') { | ||
// can't be a global CSS value | ||
// § 3.2. Author-defined Identifiers: the <custom-ident> type | ||
// The CSS-wide keywords are not valid <custom-ident>s | ||
if (name === 'unset' || name === 'initial' || name === 'inherit') { | ||
@@ -183,2 +185,7 @@ return false; | ||
// The default keyword is reserved and is also not a valid <custom-ident> | ||
if (name === 'default') { | ||
return false; | ||
} | ||
// TODO: ignore property specific keywords (as described https://developer.mozilla.org/en-US/docs/Web/CSS/custom-ident) | ||
@@ -185,0 +192,0 @@ |
@@ -13,2 +13,3 @@ 'use strict'; | ||
var search = require('./search'); | ||
var getStructureFromConfig = require('./structure').getStructureFromConfig; | ||
var cssWideKeywords = parse('inherit | initial | unset'); | ||
@@ -125,3 +126,3 @@ var cssWideKeywordsWithExpression = parse('inherit | initial | unset | <expression>'); | ||
this.types = {}; | ||
this.structure = structure; | ||
this.structure = structure || getStructureFromConfig(config); | ||
@@ -128,0 +129,0 @@ if (config) { |
@@ -1,95 +0,4 @@ | ||
'use strict'; | ||
var createParser = require('./create'); | ||
var config = require('../syntax/config/parser'); | ||
var Tokenizer = require('../tokenizer'); | ||
var sequence = require('./sequence'); | ||
var noop = function() {}; | ||
module.exports = function createParser(config) { | ||
var parser = { | ||
scanner: new Tokenizer(), | ||
filename: '<unknown>', | ||
needPositions: false, | ||
tolerant: false, | ||
onParseError: noop, | ||
parseAtruleExpression: true, | ||
parseSelector: true, | ||
parseValue: true, | ||
parseCustomProperty: false, | ||
readSequence: sequence, | ||
tolerantParse: function(consumer, fallback) { | ||
if (this.tolerant) { | ||
var start = this.scanner.currentToken; | ||
try { | ||
return consumer.call(this); | ||
} catch (e) { | ||
this.onParseError(e); | ||
return fallback.call(this, start); | ||
} | ||
} else { | ||
return consumer.call(this); | ||
} | ||
}, | ||
getLocation: function(start, end) { | ||
if (this.needPositions) { | ||
return this.scanner.getLocationRange( | ||
start, | ||
end, | ||
this.filename | ||
); | ||
} | ||
return null; | ||
}, | ||
getLocationFromList: function(list) { | ||
if (this.needPositions) { | ||
return this.scanner.getLocationRange( | ||
list.head !== null ? list.first().loc.start.offset - this.scanner.startOffset : this.scanner.tokenStart, | ||
list.head !== null ? list.last().loc.end.offset - this.scanner.startOffset : this.scanner.tokenStart, | ||
this.filename | ||
); | ||
} | ||
return null; | ||
}, | ||
parse: function(source, options) { | ||
options = options || {}; | ||
var context = options.context || 'default'; | ||
var ast; | ||
this.scanner.setSource(source, options.offset, options.line, options.column); | ||
this.filename = options.filename || '<unknown>'; | ||
this.needPositions = Boolean(options.positions); | ||
this.tolerant = Boolean(options.tolerant); | ||
this.onParseError = typeof options.onParseError === 'function' ? options.onParseError : noop; | ||
this.parseAtruleExpression = 'parseAtruleExpression' in options ? Boolean(options.parseAtruleExpression) : true; | ||
this.parseSelector = 'parseSelector' in options ? Boolean(options.parseSelector) : true; | ||
this.parseValue = 'parseValue' in options ? Boolean(options.parseValue) : true; | ||
this.parseCustomProperty = 'parseCustomProperty' in options ? Boolean(options.parseCustomProperty) : false; | ||
if (!this.context.hasOwnProperty(context)) { | ||
throw new Error('Unknown context `' + context + '`'); | ||
} | ||
ast = this.context[context].call(this, options); | ||
if (!this.scanner.eof) { | ||
this.scanner.error(); | ||
} | ||
// console.log(JSON.stringify(ast, null, 4)); | ||
return ast; | ||
} | ||
}; | ||
for (var key in config) { | ||
parser[key] = config[key]; | ||
} | ||
return parser.parse.bind(parser); | ||
}; | ||
module.exports = createParser(config); |
@@ -1,15 +0,9 @@ | ||
var hasOwnProperty = Object.prototype.hasOwnProperty; | ||
var List = require('../utils/list'); | ||
var createParser = require('../parser'); | ||
var createGenerator = require('../generator').createGenerator; | ||
var createMarkupGenerator = require('../generator').createMarkupGenerator; | ||
var sourceMapGenerator = require('../generator').sourceMap; | ||
var createConvertors = require('../utils/convert'); | ||
var createWalker = require('../walker'); | ||
var names = require('../utils/names'); | ||
var mix = require('./mix'); | ||
function merge() { | ||
var dest = {}; | ||
function assign(dest, src) { | ||
for (var key in src) { | ||
dest[key] = src[key]; | ||
for (var i = 0; i < arguments.length; i++) { | ||
var src = arguments[i]; | ||
for (var key in src) { | ||
dest[key] = src[key]; | ||
} | ||
} | ||
@@ -20,277 +14,8 @@ | ||
function createParseContext(name) { | ||
return function() { | ||
return this[name](); | ||
}; | ||
} | ||
function isValidNumber(value) { | ||
// Number.isInteger(value) && value >= 0 | ||
return ( | ||
typeof value === 'number' && | ||
isFinite(value) && | ||
Math.floor(value) === value && | ||
value >= 0 | ||
); | ||
} | ||
function isValidLocation(loc) { | ||
return ( | ||
Boolean(loc) && | ||
isValidNumber(loc.offset) && | ||
isValidNumber(loc.line) && | ||
isValidNumber(loc.column) | ||
); | ||
} | ||
function createNodeStructureChecker(type, fields) { | ||
return function checkNode(node, warn) { | ||
if (!node || node.constructor !== Object) { | ||
return warn('Type of node should be an object'); | ||
} | ||
for (var key in node) { | ||
if (key === 'type') { | ||
if (node.type !== type) { | ||
warn('Wrong node type `' + node.type + '` but expected `' + type + '`'); | ||
} | ||
} else if (key === 'loc') { | ||
if (node.loc === null) { | ||
continue; | ||
} else if (node.loc && node.loc.constructor === Object) { | ||
if (typeof node.loc.source === 'string' && | ||
isValidLocation(node.loc.start) && | ||
isValidLocation(node.loc.end)) { | ||
continue; | ||
} | ||
} | ||
warn('Wrong value for `' + type + '.' + key + '` field'); | ||
} else if (fields.hasOwnProperty(key)) { | ||
for (var i = 0, valid = false; !valid && i < fields[key].length; i++) { | ||
var fieldType = fields[key][i]; | ||
switch (fieldType) { | ||
case String: | ||
valid = typeof node[key] === 'string'; | ||
break; | ||
case Boolean: | ||
valid = typeof node[key] === 'boolean'; | ||
break; | ||
case null: | ||
valid = node[key] === null; | ||
break; | ||
default: | ||
if (typeof fieldType === 'string') { | ||
valid = node[key] && node[key].type === fieldType; | ||
} else if (Array.isArray(fieldType)) { | ||
valid = node[key] instanceof List; | ||
} | ||
} | ||
} | ||
if (!valid) { | ||
warn('Wrong value for `' + type + '.' + key + '` field'); | ||
} | ||
} else { | ||
warn('Unknown field `' + key + '` for ' + type); | ||
} | ||
} | ||
for (var key in fields) { | ||
if (hasOwnProperty.call(node, key) === false) { | ||
warn('Field `' + type + '.' + key + '` is missed'); | ||
} | ||
} | ||
}; | ||
} | ||
function processStructure(name, nodeType) { | ||
var structure = nodeType.structure; | ||
var fields = { | ||
type: String, | ||
loc: true | ||
}; | ||
var walkers = []; | ||
var docs = { | ||
type: '"' + name + '"' | ||
}; | ||
for (var key in structure) { | ||
var walker = { | ||
name: key, | ||
type: false, | ||
nullable: false | ||
}; | ||
var docsTypes = []; | ||
var fieldTypes = fields[key] = Array.isArray(structure[key]) | ||
? structure[key].slice() | ||
: [structure[key]]; | ||
for (var i = 0; i < fieldTypes.length; i++) { | ||
var fieldType = fieldTypes[i]; | ||
if (fieldType === String || fieldType === Boolean) { | ||
docsTypes.push(fieldType.name); | ||
} else if (fieldType === null) { | ||
walker.nullable = true; | ||
docsTypes.push('null'); | ||
} else if (typeof fieldType === 'string') { | ||
walker.type = 'node'; | ||
docsTypes.push('<' + fieldType + '>'); | ||
} else if (Array.isArray(fieldType)) { | ||
walker.type = 'list'; | ||
docsTypes.push('List'); // TODO: use type enum | ||
} else { | ||
throw new Error('Wrong value in `' + name + '` structure definition'); | ||
} | ||
} | ||
docs[key] = docsTypes.join(' | '); | ||
if (walker.type) { | ||
walkers.push(walker); | ||
} | ||
} | ||
return { | ||
docs: docs, | ||
check: createNodeStructureChecker(name, fields), | ||
walk: walkers.length ? { | ||
context: nodeType.walkContext, | ||
fields: walkers | ||
} : null | ||
}; | ||
} | ||
function createSyntax(config) { | ||
var parser = { context: {}, scope: {}, atrule: {}, pseudo: {} }; | ||
var walker = { type: {} }; | ||
var generator = {}; | ||
var lexer = { structure: {} }; | ||
if (config.parseContext) { | ||
for (var name in config.parseContext) { | ||
switch (typeof config.parseContext[name]) { | ||
case 'function': | ||
parser.context[name] = config.parseContext[name]; | ||
break; | ||
case 'string': | ||
parser.context[name] = createParseContext(config.parseContext[name]); | ||
break; | ||
} | ||
} | ||
} | ||
if (config.scope) { | ||
for (var name in config.scope) { | ||
parser.scope[name] = config.scope[name]; | ||
} | ||
} | ||
if (config.atrule) { | ||
for (var name in config.atrule) { | ||
var atrule = config.atrule[name]; | ||
if (atrule.parse) { | ||
parser.atrule[name] = atrule.parse; | ||
} | ||
} | ||
} | ||
if (config.pseudo) { | ||
for (var name in config.pseudo) { | ||
var pseudo = config.pseudo[name]; | ||
if (pseudo.parse) { | ||
parser.pseudo[name] = pseudo.parse; | ||
} | ||
} | ||
} | ||
if (config.node) { | ||
for (var name in config.node) { | ||
var nodeType = config.node[name]; | ||
parser[name] = nodeType.parse; | ||
generator[name] = nodeType.generate; | ||
if (nodeType.structure) { | ||
var structure = processStructure(name, nodeType); | ||
lexer.structure[name] = { | ||
docs: structure.docs, | ||
check: structure.check | ||
}; | ||
if (structure.walk) { | ||
walker.type[name] = structure.walk; | ||
} | ||
} else { | ||
throw new Error('Missed `structure` field in `' + name + '` node type definition'); | ||
} | ||
} | ||
} | ||
var parse = createParser(parser); | ||
var Lexer = require('../lexer/Lexer'); | ||
var walker = createWalker(walker.type); | ||
var convertors = createConvertors(walker); | ||
var markupGenerator = createMarkupGenerator(generator); | ||
var syntax = { | ||
List: require('../utils/list'), | ||
Tokenizer: require('../tokenizer'), | ||
Lexer: require('../lexer/Lexer'), | ||
property: names.property, | ||
keyword: names.keyword, | ||
lexer: null, | ||
syntax: require('../lexer'), | ||
createLexer: function(config) { | ||
return new Lexer(config, syntax, lexer.structure); | ||
}, | ||
parse: parse, | ||
walk: walker.all, | ||
walkUp: walker.allUp, | ||
walkRules: walker.rules, | ||
walkRulesRight: walker.rulesRight, | ||
walkDeclarations: walker.declarations, | ||
translate: createGenerator(generator), | ||
translateWithSourceMap: function(node) { | ||
return sourceMapGenerator(markupGenerator, node); | ||
}, | ||
translateMarkup: markupGenerator, | ||
clone: require('../utils/clone'), | ||
fromPlainObject: convertors.fromPlainObject, | ||
toPlainObject: convertors.toPlainObject, | ||
createSyntax: function(config) { | ||
return createSyntax(mix({}, config)); | ||
}, | ||
fork: function(extension) { | ||
var base = mix({}, config); // copy of config | ||
return createSyntax( | ||
typeof extension === 'function' | ||
? extension(base, assign) | ||
: mix(base, extension) | ||
); | ||
} | ||
}; | ||
syntax.lexer = new Lexer({ | ||
generic: true, | ||
types: config.types, | ||
properties: config.properties | ||
}, syntax, lexer.structure); | ||
return syntax; | ||
}; | ||
exports.create = function(config) { | ||
return createSyntax(mix({}, config)); | ||
}; | ||
module.exports = require('./create').create( | ||
merge( | ||
require('./config/lexer'), | ||
require('./config/parser'), | ||
require('./config/walker') | ||
) | ||
); |
@@ -160,3 +160,4 @@ var cmpChar = require('../../tokenizer').cmpChar; | ||
processChunk( | ||
node.a === '+1' || node.a === '1' ? 'n' : | ||
node.a === '+1' ? '+n' : | ||
node.a === '1' ? 'n' : | ||
node.a === '-1' ? '-n' : | ||
@@ -163,0 +164,0 @@ node.a + 'n' |
@@ -51,3 +51,5 @@ var List = require('../../utils/list'); | ||
this.scanner.eat(RIGHTCURLYBRACKET); | ||
if (!this.tolerant || !this.scanner.eof) { | ||
this.scanner.eat(RIGHTCURLYBRACKET); | ||
} | ||
@@ -54,0 +56,0 @@ return { |
@@ -8,2 +8,6 @@ var List = require('../../utils/list'); | ||
function consumeRaw(startToken) { | ||
return this.Raw(startToken, 0, SEMICOLON, true, true); | ||
} | ||
module.exports = { | ||
@@ -27,3 +31,3 @@ name: 'DeclarationList', | ||
default: | ||
children.appendData(this.Declaration()); | ||
children.appendData(this.tolerantParse(this.Declaration, consumeRaw)); | ||
} | ||
@@ -30,0 +34,0 @@ } |
@@ -76,6 +76,14 @@ 'use strict'; | ||
// https://drafts.csswg.org/css-syntax/#tokenizer-definitions | ||
// > non-ASCII code point | ||
// > A code point with a value equal to or greater than U+0080 <control> | ||
// > name-start code point | ||
// > A letter, a non-ASCII code point, or U+005F LOW LINE (_). | ||
// > name code point | ||
// > A name-start code point, a digit, or U+002D HYPHEN-MINUS (-) | ||
// That means only ASCII code points has a special meaning and we a maps for 0..127 codes only | ||
var SafeUint32Array = typeof Uint32Array !== 'undefined' ? Uint32Array : Array; // fallback on Array when TypedArray is not supported | ||
var SYMBOL_TYPE = new SafeUint32Array(Math.max.apply(null, Object.keys(NAME).map(Number)) + 1); | ||
var PUNCTUATION = new SafeUint32Array(SYMBOL_TYPE.length); | ||
var STOP_URL_RAW = new SafeUint32Array(SYMBOL_TYPE.length); | ||
var SYMBOL_TYPE = new SafeUint32Array(0x80); | ||
var PUNCTUATION = new SafeUint32Array(0x80); | ||
var STOP_URL_RAW = new SafeUint32Array(0x80); | ||
@@ -82,0 +90,0 @@ for (var i = 0; i < SYMBOL_TYPE.length; i++) { |
@@ -9,3 +9,2 @@ 'use strict'; | ||
var SYMBOL_TYPE = constants.SYMBOL_TYPE; | ||
var SYMBOL_TYPE_LENGTH = SYMBOL_TYPE.length; | ||
@@ -122,3 +121,3 @@ var utils = require('./utils'); | ||
var code = source.charCodeAt(offset); | ||
var type = code < SYMBOL_TYPE_LENGTH ? SYMBOL_TYPE[code] : IDENTIFIER; | ||
var type = code < 0x80 ? SYMBOL_TYPE[code] : IDENTIFIER; | ||
@@ -125,0 +124,0 @@ balance[tokenCount] = sourceLength; |
@@ -5,6 +5,3 @@ 'use strict'; | ||
var PUNCTUATION = constants.PUNCTUATION; | ||
var SYMBOL_TYPE = constants.SYMBOL_TYPE; | ||
var SYMBOL_TYPE_LENGTH = SYMBOL_TYPE.length; | ||
var STOP_URL_RAW = constants.STOP_URL_RAW; | ||
var STOP_URL_RAW_LENGTH = STOP_URL_RAW.length; | ||
var TYPE = constants.TYPE; | ||
@@ -221,3 +218,3 @@ var FULLSTOP = TYPE.FullStop; | ||
offset = findEscaseEnd(source, offset + 1); | ||
} else if (code < SYMBOL_TYPE_LENGTH && PUNCTUATION[code] === PUNCTUATOR) { | ||
} else if (code < 0x80 && PUNCTUATION[code] === PUNCTUATOR) { | ||
break; | ||
@@ -236,3 +233,3 @@ } | ||
offset = findEscaseEnd(source, offset + 1); | ||
} else if (code < STOP_URL_RAW_LENGTH && STOP_URL_RAW[code] === 1) { | ||
} else if (code < 0x80 && STOP_URL_RAW[code] === 1) { | ||
break; | ||
@@ -239,0 +236,0 @@ } |
@@ -1,214 +0,4 @@ | ||
'use strict'; | ||
var createWalker = require('./create'); | ||
var config = require('../syntax/config/walker'); | ||
function walkRules(node, item, list) { | ||
switch (node.type) { | ||
case 'StyleSheet': | ||
var oldStylesheet = this.stylesheet; | ||
this.stylesheet = node; | ||
node.children.each(walkRules, this); | ||
this.stylesheet = oldStylesheet; | ||
break; | ||
case 'Atrule': | ||
if (node.block !== null) { | ||
var oldAtrule = this.atrule; | ||
this.atrule = node; | ||
walkRules.call(this, node.block); | ||
this.atrule = oldAtrule; | ||
} | ||
this.fn(node, item, list); | ||
break; | ||
case 'Rule': | ||
this.fn(node, item, list); | ||
var oldRule = this.rule; | ||
this.rule = node; | ||
walkRules.call(this, node.block); | ||
this.rule = oldRule; | ||
break; | ||
case 'Block': | ||
var oldBlock = this.block; | ||
this.block = node; | ||
node.children.each(walkRules, this); | ||
this.block = oldBlock; | ||
break; | ||
} | ||
} | ||
function walkRulesRight(node, item, list) { | ||
switch (node.type) { | ||
case 'StyleSheet': | ||
var oldStylesheet = this.stylesheet; | ||
this.stylesheet = node; | ||
node.children.eachRight(walkRulesRight, this); | ||
this.stylesheet = oldStylesheet; | ||
break; | ||
case 'Atrule': | ||
if (node.block !== null) { | ||
var oldAtrule = this.atrule; | ||
this.atrule = node; | ||
walkRulesRight.call(this, node.block); | ||
this.atrule = oldAtrule; | ||
} | ||
this.fn(node, item, list); | ||
break; | ||
case 'Rule': | ||
var oldRule = this.rule; | ||
this.rule = node; | ||
walkRulesRight.call(this, node.block); | ||
this.rule = oldRule; | ||
this.fn(node, item, list); | ||
break; | ||
case 'Block': | ||
var oldBlock = this.block; | ||
this.block = node; | ||
node.children.eachRight(walkRulesRight, this); | ||
this.block = oldBlock; | ||
break; | ||
} | ||
} | ||
function walkDeclarations(node) { | ||
switch (node.type) { | ||
case 'StyleSheet': | ||
var oldStylesheet = this.stylesheet; | ||
this.stylesheet = node; | ||
node.children.each(walkDeclarations, this); | ||
this.stylesheet = oldStylesheet; | ||
break; | ||
case 'Atrule': | ||
if (node.block !== null) { | ||
var oldAtrule = this.atrule; | ||
this.atrule = node; | ||
walkDeclarations.call(this, node.block); | ||
this.atrule = oldAtrule; | ||
} | ||
break; | ||
case 'Rule': | ||
var oldRule = this.rule; | ||
this.rule = node; | ||
if (node.block !== null) { | ||
walkDeclarations.call(this, node.block); | ||
} | ||
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; | ||
} | ||
} | ||
function createContext(root, fn) { | ||
var context = { | ||
fn: fn, | ||
root: root, | ||
stylesheet: null, | ||
atrule: null, | ||
atruleExpression: null, | ||
rule: null, | ||
selector: null, | ||
block: null, | ||
declaration: null, | ||
function: null | ||
}; | ||
return context; | ||
} | ||
module.exports = function createWalker(types) { | ||
var walkers = {}; | ||
for (var name in types) { | ||
var config = types[name]; | ||
walkers[name] = Function('node', 'context', 'walk', | ||
(config.context ? 'var old = context.' + config.context + ';\ncontext.' + config.context + ' = node;\n' : '') + | ||
config.fields.map(function(field) { | ||
var line = field.type === 'list' | ||
? 'node.' + field.name + '.each(walk);' | ||
: 'walk(node.' + field.name + ');'; | ||
if (field.nullable) { | ||
line = 'if (node.' + field.name + ') {\n ' + line + '}'; | ||
} | ||
return line; | ||
}).join('\n') + | ||
(config.context ? '\ncontext.' + config.context + ' = old;' : '') | ||
); | ||
} | ||
return { | ||
all: function(root, fn) { | ||
function walk(node, item, list) { | ||
fn.call(context, node, item, list); | ||
if (walkers.hasOwnProperty(node.type)) { | ||
walkers[node.type](node, context, walk); | ||
} | ||
} | ||
var context = createContext(root, fn); | ||
walk(root); | ||
}, | ||
allUp: function(root, fn) { | ||
function walk(node, item, list) { | ||
if (walkers.hasOwnProperty(node.type)) { | ||
walkers[node.type](node, context, walk); | ||
} | ||
fn.call(context, node, item, list); | ||
} | ||
var context = createContext(root, fn); | ||
walk(root); | ||
}, | ||
rules: function(root, fn) { | ||
walkRules.call(createContext(root, fn), root); | ||
}, | ||
rulesRight: function(root, fn) { | ||
walkRulesRight.call(createContext(root, fn), root); | ||
}, | ||
declarations: function(root, fn) { | ||
walkDeclarations.call(createContext(root, fn), root); | ||
} | ||
}; | ||
}; | ||
module.exports = createWalker(config); |
{ | ||
"name": "css-tree", | ||
"version": "1.0.0-alpha21", | ||
"version": "1.0.0-alpha22", | ||
"description": "Fast detailed CSS parser", | ||
@@ -5,0 +5,0 @@ "keywords": [ |
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
Uses eval
Supply chain riskPackage uses dynamic code execution (e.g., eval()), which is a dangerous practice. This can prevent the code from running in certain environments and increases the risk that the code may contain exploits or malicious behavior.
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
Uses eval
Supply chain riskPackage uses dynamic code execution (e.g., eval()), which is a dangerous practice. This can prevent the code from running in certain environments and increases the risk that the code may contain exploits or malicious behavior.
Found 1 instance in 1 package
571730
128
7800