diff --git a/lib/parser/index.js b/lib/parser/index.js index 87bbffa0..39a7ccd9 100644 --- a/lib/parser/index.js +++ b/lib/parser/index.js @@ -524,6 +524,10 @@ function getBlock() { scanner.next(); break; + case COMMERCIALAT: + children.appendData(getAtrule()); + break; + default: children.appendData(getDeclaration()); } diff --git a/lib/utils/walk.js b/lib/utils/walk.js index 5edad3e1..e37d9452 100644 --- a/lib/utils/walk.js +++ b/lib/utils/walk.js @@ -21,6 +21,13 @@ function walkRules(node, item, list) { case 'Rule': this.fn(node, item, list); + + var oldRule = this.rule; + this.rule = node; + + node.block.children.each(walkRules, this); + + this.rule = oldRule; break; } @@ -46,6 +53,13 @@ function walkRulesRight(node, item, list) { break; case 'Rule': + var oldRule = this.rule; + this.rule = node; + + node.block.children.eachRight(walkRulesRight, this); + + this.rule = oldRule; + this.fn(node, item, list); break; } @@ -63,19 +77,30 @@ function walkDeclarations(node) { break; case 'Atrule': - if (node.block !== null && node.block.type === 'StyleSheet') { + if (node.block !== null) { walkDeclarations.call(this, node.block); } break; case 'Rule': + var oldRule = this.rule; this.rule = node; if (node.block !== null) { - node.block.children.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; } } diff --git a/test/fixture/parse/rule/nested-atrule.json b/test/fixture/parse/rule/nested-atrule.json new file mode 100644 index 00000000..f5bef538 --- /dev/null +++ b/test/fixture/parse/rule/nested-atrule.json @@ -0,0 +1,198 @@ +{ + "basic": { + "source": ".test{@test;}", + "ast": { + "type": "Rule", + "selector": { + "type": "SelectorList", + "children": [ + { + "type": "Selector", + "children": [ + { + "type": "Class", + "name": "test" + } + ] + } + ] + }, + "block": { + "type": "Block", + "children": [ + { + "type": "Atrule", + "name": "test", + "expression": { + "type": "AtruleExpression", + "children": [] + }, + "block": null + } + ] + } + } + }, + "with expression": { + "source": ".test{@test not(something);}", + "ast": { + "type": "Rule", + "selector": { + "type": "SelectorList", + "children": [ + { + "type": "Selector", + "children": [ + { + "type": "Class", + "name": "test" + } + ] + } + ] + }, + "block": { + "type": "Block", + "children": [ + { + "type": "Atrule", + "name": "test", + "expression": { + "type": "AtruleExpression", + "children": [ + { + "type": "Function", + "name": "not", + "children": [ + { + "type": "Identifier", + "name": "something" + } + ] + } + ] + }, + "block": null + } + ] + } + } + }, + "with block": { + "source": ".test{@test foo{a:1}}", + "ast": { + "type": "Rule", + "selector": { + "type": "SelectorList", + "children": [ + { + "type": "Selector", + "children": [ + { + "type": "Class", + "name": "test" + } + ] + } + ] + }, + "block": { + "type": "Block", + "children": [ + { + "type": "Atrule", + "name": "test", + "expression": { + "type": "AtruleExpression", + "children": [ + { + "type": "Identifier", + "name": "foo" + } + ] + }, + "block": { + "type": "Block", + "children": [ + { + "type": "Declaration", + "important": false, + "property": "a", + "value": { + "type": "Value", + "children": [ + { + "type": "Number", + "value": "1" + } + ] + } + } + ] + } + } + ] + } + } + }, + "recursion": { + "source": ".test{@test foo{@test foo{}}}", + "ast": { + "type": "Rule", + "selector": { + "type": "SelectorList", + "children": [ + { + "type": "Selector", + "children": [ + { + "type": "Class", + "name": "test" + } + ] + } + ] + }, + "block": { + "type": "Block", + "children": [ + { + "type": "Atrule", + "name": "test", + "expression": { + "type": "AtruleExpression", + "children": [ + { + "type": "Identifier", + "name": "foo" + } + ] + }, + "block": { + "type": "StyleSheet", + "children": [ + { + "type": "Atrule", + "name": "test", + "expression": { + "type": "AtruleExpression", + "children": [ + { + "type": "Identifier", + "name": "foo" + } + ] + }, + "block": { + "type": "Block", + "children": [] + } + } + ] + } + } + ] + } + } + } +} diff --git a/test/walk.js b/test/walk.js index 477134b0..b69738ff 100644 --- a/test/walk.js +++ b/test/walk.js @@ -60,9 +60,9 @@ function createWalkTest(name, test, context, walker, right) { }); // type arrays should be equal - assert.equal( - actual.sort().join(','), - expectedWalk(test.ast, right).sort().join(',') + assert.deepEqual( + actual.sort(), + expectedWalk(test.ast, right).sort() ); }); } @@ -79,11 +79,11 @@ function createWalkRulesTest(test, context, walker) { }); // type arrays should be equal - assert.equal( - actual.sort().join(','), + assert.deepEqual( + actual.sort(), expectedWalk(test.ast, true).filter(function(type) { return type === 'Rule' || type === 'Atrule'; - }).sort().join(',') + }).sort() ); }); } @@ -100,13 +100,11 @@ function createWalkDeclarationsTest(test, context, walker) { }); // type arrays should be equal - assert.equal( - actual.sort().join(','), - expectedWalk(test.ast, false, function(stack, node) { - return node.type === 'Declaration' && stack.some(function(node) { - return node.type === 'Rule'; - }); - }).sort().join(',') + assert.deepEqual( + actual.sort(), + expectedWalk(test.ast, false).filter(function(type) { + return type === 'Declaration'; + }).sort() ); }); }