diff --git a/lib/generator/index.js b/lib/generator/index.js index 3e6425b5..28d35152 100644 --- a/lib/generator/index.js +++ b/lib/generator/index.js @@ -2,41 +2,33 @@ var hasOwnProperty = Object.prototype.hasOwnProperty; -function each(list) { +function each(processChunk, list) { var cursor = list.head; - var result = []; while (cursor !== null) { - result.push(this.generate(cursor.data, cursor, list)); + this.generate(processChunk, cursor.data, cursor, list); cursor = cursor.next; } - - return result; } -function eachComma(list) { +function eachComma(processChunk, list) { var cursor = list.head; - var result = []; while (cursor !== null) { if (cursor.prev) { - result.push(',', this.generate(cursor.data)); - } else { - result.push(this.generate(cursor.data)); + processChunk(','); } + this.generate(processChunk, cursor.data, cursor, list); cursor = cursor.next; } - - return result; } function createGenerator(types) { var context = { - generate: function(node, item, list) { + generate: function(processChunk, node, item, list) { if (hasOwnProperty.call(types, node.type)) { - var ret = types[node.type].call(this, node, item, list); - return typeof ret === 'string' ? ret : ret.join(''); + types[node.type].call(this, processChunk, node, item, list); } else { throw new Error('Unknown node type: ' + node.type); } @@ -45,19 +37,30 @@ function createGenerator(types) { eachComma: eachComma }; - return function(node) { - return context.generate(node); + return function(node, fn) { + if (typeof fn !== 'function') { + var buffer = []; + context.generate(function() { + buffer.push.apply(buffer, arguments); + }, node); + return buffer.join(''); + } + context.generate(fn, node); }; } function createMarkupGenerator(types) { var context = { - generate: function(node, item, list) { + generate: function(buffer, node, item, list) { if (hasOwnProperty.call(types, node.type)) { - return { + var nodeBuffer = []; + types[node.type].call(this, function() { + nodeBuffer.push.apply(nodeBuffer, arguments); + }, node, item, list); + buffer({ node: node, - value: types[node.type].call(this, node, item, list) - }; + value: nodeBuffer + }); } else { throw new Error('Unknown node type: ' + node.type); } @@ -96,7 +99,11 @@ function createMarkupGenerator(types) { after = function() {}; } - return walk(context.generate(node), ''); + var buffer = []; + context.generate(function() { + buffer.push.apply(buffer, arguments); + }, node); + return walk(buffer[0], ''); }; } diff --git a/lib/syntax/node/AnPlusB.js b/lib/syntax/node/AnPlusB.js index 1bd186ef..cf2752a5 100644 --- a/lib/syntax/node/AnPlusB.js +++ b/lib/syntax/node/AnPlusB.js @@ -151,29 +151,27 @@ module.exports = { b: b }; }, - generate: function(node) { + generate: function(processChunk, node) { var a = node.a !== null && node.a !== undefined; var b = node.b !== null && node.b !== undefined; - var result; if (a) { - result = + processChunk( node.a === '+1' || node.a === '1' ? 'n' : node.a === '-1' ? '-n' : - node.a + 'n'; + node.a + 'n' + ); if (b) { b = String(node.b); if (b.charAt(0) === '-' || b.charAt(0) === '+') { - result = [result, b.charAt(0), b.substr(1)]; + processChunk(b.charAt(0), b.substr(1)); } else { - result = [result, '+', b]; + processChunk('+', b); } } } else { - result = String(node.b); + processChunk(String(node.b)); } - - return result; } }; diff --git a/lib/syntax/node/Atrule.js b/lib/syntax/node/Atrule.js index fc61f5e2..16a6d9b6 100644 --- a/lib/syntax/node/Atrule.js +++ b/lib/syntax/node/Atrule.js @@ -83,16 +83,19 @@ module.exports = { block: block }; }, - generate: function(node) { - var result = ['@', node.name]; + generate: function(processChunk, node) { + processChunk('@', node.name); if (node.expression !== null) { - result.push(' ', this.generate(node.expression)); + processChunk(' '); + this.generate(processChunk, node.expression); } - result.push(node.block ? this.generate(node.block) : ';'); - - return result; + if (node.block) { + this.generate(processChunk, node.block); + } else { + processChunk(';'); + } }, walkContext: 'atrule' }; diff --git a/lib/syntax/node/AtruleExpression.js b/lib/syntax/node/AtruleExpression.js index d8c0f5d4..38ce2754 100644 --- a/lib/syntax/node/AtruleExpression.js +++ b/lib/syntax/node/AtruleExpression.js @@ -37,8 +37,8 @@ module.exports = { children: children }; }, - generate: function(node) { - return this.each(node.children); + generate: function(processChunk, node) { + this.each(processChunk, node.children); }, walkContext: 'atruleExpression' }; diff --git a/lib/syntax/node/AttributeSelector.js b/lib/syntax/node/AttributeSelector.js index f26a5a70..0f8c1f0e 100644 --- a/lib/syntax/node/AttributeSelector.js +++ b/lib/syntax/node/AttributeSelector.js @@ -133,15 +133,17 @@ module.exports = { flags: flags }; }, - generate: function(node) { - var result = ['[', this.generate(node.name)]; + generate: function(processChunk, node) { var flagsPrefix = ' '; + processChunk('['); + this.generate(processChunk, node.name); + if (node.operator !== null) { - result.push(node.operator); + processChunk(node.operator); if (node.value !== null) { - result.push(this.generate(node.value)); + this.generate(processChunk, node.value); // space between string and flags is not required if (node.value.type === 'String') { @@ -151,11 +153,9 @@ module.exports = { } if (node.flags !== null) { - result.push(flagsPrefix, node.flags); + processChunk(flagsPrefix, node.flags); } - result.push(']'); - - return result; + processChunk(']'); } }; diff --git a/lib/syntax/node/Block.js b/lib/syntax/node/Block.js index 8deaa95c..dc38c30d 100644 --- a/lib/syntax/node/Block.js +++ b/lib/syntax/node/Block.js @@ -50,8 +50,10 @@ module.exports = { children: children }; }, - generate: function(node) { - return [].concat('{', this.each(node.children), '}'); + generate: function(processChunk, node) { + processChunk('{'); + this.each(processChunk, node.children); + processChunk('}'); }, walkContext: 'block' }; diff --git a/lib/syntax/node/Brackets.js b/lib/syntax/node/Brackets.js index fe5b3527..915c59aa 100644 --- a/lib/syntax/node/Brackets.js +++ b/lib/syntax/node/Brackets.js @@ -24,7 +24,9 @@ module.exports = { children: children }; }, - generate: function(node) { - return [].concat('[', this.each(node.children), ']'); + generate: function(processChunk, node) { + processChunk('['); + this.each(processChunk, node.children); + processChunk(']'); } }; diff --git a/lib/syntax/node/CDC.js b/lib/syntax/node/CDC.js index d922d23b..d9e28b9b 100644 --- a/lib/syntax/node/CDC.js +++ b/lib/syntax/node/CDC.js @@ -13,7 +13,7 @@ module.exports = { loc: this.getLocation(start, this.scanner.tokenStart) }; }, - generate: function() { - return '-->'; + generate: function(processChunk) { + processChunk('-->'); } }; diff --git a/lib/syntax/node/CDO.js b/lib/syntax/node/CDO.js index 3a79eef7..fd9e3f69 100644 --- a/lib/syntax/node/CDO.js +++ b/lib/syntax/node/CDO.js @@ -13,7 +13,7 @@ module.exports = { loc: this.getLocation(start, this.scanner.tokenStart) }; }, - generate: function() { - return '