diff options
Diffstat (limited to 'lib/template/index.js')
-rw-r--r-- | lib/template/index.js | 126 |
1 files changed, 72 insertions, 54 deletions
diff --git a/lib/template/index.js b/lib/template/index.js index 9a5d92f..13a9922 100644 --- a/lib/template/index.js +++ b/lib/template/index.js @@ -10,6 +10,8 @@ var defaultBlocks = require('./blocks'); var defaultFilters = require('./filters'); var Loader = require('./loader'); +var NODE_ENDARGS = '%%endargs%%'; + // Return extension name for a specific block function blockExtName(name) { return 'Block'+name+'Extension'; @@ -21,6 +23,12 @@ function normBlockResult(blk) { return blk; } +// Extract kwargs from an arguments array +function extractKwargs(args) { + var last = _.last(args) + return (_.isObject(last) && last.__keywords)? args.pop() : {}; +} + function TemplateEngine(output) { this.output = output; this.book = output.book; @@ -182,87 +190,97 @@ TemplateEngine.prototype.addBlock = function(name, block) { var lastBlockName = null; var lastBlockArgs = null; var allBlocks = block.blocks.concat([block.end]); - var subbodies = {}; + // Parse first block var tok = parser.nextToken(); - var args = parser.parseSignature(null, true); + lastBlockArgs = parser.parseSignature(null, true); parser.advanceAfterBlockEnd(tok.value); + var args = new nodes.NodeList(); + var bodies = []; + var blockNamesNode = new nodes.Array(tok.lineno, tok.colno); + var blockArgCounts = new nodes.Array(tok.lineno, tok.colno); + + // Parse while we found "end<block>" do { // Read body var currentBody = parser.parseUntilBlocks.apply(parser, allBlocks); // Handle body with previous block name and args - if (lastBlockName) { - subbodies[lastBlockName] = subbodies[lastBlockName] || []; - subbodies[lastBlockName].push({ - body: currentBody, - args: lastBlockArgs - }); - } else { - body = currentBody; - } + blockNamesNode.addChild(new nodes.Literal(args.lineno, args.colno, lastBlockName)); + blockArgCounts.addChild(new nodes.Literal(args.lineno, args.colno, lastBlockArgs.children.length)); + bodies.push(currentBody); + + // Append arguments of this block as arguments of the run function + _.each(lastBlockArgs.children, function(child) { + args.addChild(child); + }); // Read new block - lastBlockName = parser.peekToken().value; + lastBlockName = parser.nextToken().value; // Parse signature and move to the end of the block if (lastBlockName != block.end) { lastBlockArgs = parser.parseSignature(null, true); - parser.advanceAfterBlockEnd(lastBlockName); } - } while (lastBlockName != block.end); - - parser.advanceAfterBlockEnd(); - var bodies = [body]; - _.each(block.blocks, function(blockName) { - subbodies[blockName] = subbodies[blockName] || []; - if (subbodies[blockName].length === 0) { - subbodies[blockName].push({ - args: new nodes.NodeList(), - body: new nodes.NodeList() - }); - } + parser.advanceAfterBlockEnd(lastBlockName); + } while (lastBlockName != block.end); - bodies.push(subbodies[blockName][0].body); - }); + args.addChild(blockNamesNode); + args.addChild(blockArgCounts); + args.addChild(new nodes.Literal(args.lineno, args.colno, NODE_ENDARGS)); return new nodes.CallExtensionAsync(this, 'run', args, bodies); }; this.run = function(context) { - var args = Array.prototype.slice.call(arguments, 1); - var callback = args.pop(); - - // Extract blocks - var blocks = args - .concat([]) - .slice(-block.blocks.length); - - // Eliminate blocks from list - if (block.blocks.length > 0) args = args.slice(0, -block.blocks.length); - - // Extract main body and kwargs - var body = args.pop(); - var kwargs = _.isObject(_.last(args))? args.pop() : {}; - - // Extract blocks body - var _blocks = _.map(block.blocks, function(blockName, i){ - return { - name: blockName, - body: blocks[i]() - }; + var fnArgs = Array.prototype.slice.call(arguments, 1); + + var args; + var blocks = []; + var bodies = []; + var blockNames; + var blockArgCounts; + var callback; + + // Extract callback + callback = fnArgs.pop(); + + // Detect end of arguments + var endArgIndex = fnArgs.indexOf(NODE_ENDARGS); + + // Extract arguments and bodies + args = fnArgs.slice(0, endArgIndex); + bodies = fnArgs.slice(endArgIndex + 1); + + // Extract block counts + blockArgCounts = args.pop(); + blockNames = args.pop(); + + // Recreate list of blocks + _.each(blockNames, function(name, i) { + var countArgs = blockArgCounts[i]; + var blockBody = bodies.shift(); + + var blockArgs = countArgs > 0? args.slice(0, countArgs) : []; + args = args.slice(countArgs); + var blockKwargs = extractKwargs(blockArgs); + + blocks.push({ + name: name, + body: blockBody(), + args: blockArgs, + kwargs: blockKwargs + }); }); + var mainBlock = blocks.shift(); + mainBlock.blocks = blocks; + Promise() .then(function() { - return that.applyBlock(name, { - body: body(), - args: args, - kwargs: kwargs, - blocks: _blocks - }, context); + return that.applyBlock(name, mainBlock, context); }) // Process the block returned |