summaryrefslogtreecommitdiffstats
path: root/lib/template
diff options
context:
space:
mode:
authorSamy Pessé <samypesse@gmail.com>2016-04-13 16:22:52 +0200
committerSamy Pessé <samypesse@gmail.com>2016-04-13 16:22:53 +0200
commitce7de93936196e40fbfaea3e6a6437889e3cc26f (patch)
treeda938905089c158611a8b0fe875a074051e9db08 /lib/template
parentef2a24fe6f76e9c1995bcbef8c331d51d00a490b (diff)
downloadgitbook-ce7de93936196e40fbfaea3e6a6437889e3cc26f.zip
gitbook-ce7de93936196e40fbfaea3e6a6437889e3cc26f.tar.gz
gitbook-ce7de93936196e40fbfaea3e6a6437889e3cc26f.tar.bz2
Improve block parsing to handle args/kwargs on subblocks
Diffstat (limited to 'lib/template')
-rw-r--r--lib/template/index.js126
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