mirror of
https://github.com/GitbookIO/gitbook.git
synced 2026-09-24 19:32:07 +00:00
Improve block parsing to handle args/kwargs on subblocks
This commit is contained in:
+68
-50
@@ -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);
|
||||
}
|
||||
|
||||
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()
|
||||
});
|
||||
}
|
||||
|
||||
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();
|
||||
var fnArgs = Array.prototype.slice.call(arguments, 1);
|
||||
|
||||
// Extract blocks
|
||||
var blocks = args
|
||||
.concat([])
|
||||
.slice(-block.blocks.length);
|
||||
var args;
|
||||
var blocks = [];
|
||||
var bodies = [];
|
||||
var blockNames;
|
||||
var blockArgCounts;
|
||||
var callback;
|
||||
|
||||
// Eliminate blocks from list
|
||||
if (block.blocks.length > 0) args = args.slice(0, -block.blocks.length);
|
||||
// Extract callback
|
||||
callback = fnArgs.pop();
|
||||
|
||||
// Extract main body and kwargs
|
||||
var body = args.pop();
|
||||
var kwargs = _.isObject(_.last(args))? args.pop() : {};
|
||||
// Detect end of arguments
|
||||
var endArgIndex = fnArgs.indexOf(NODE_ENDARGS);
|
||||
|
||||
// Extract blocks body
|
||||
var _blocks = _.map(block.blocks, function(blockName, i){
|
||||
return {
|
||||
name: blockName,
|
||||
body: blocks[i]()
|
||||
};
|
||||
// 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
|
||||
|
||||
Reference in New Issue
Block a user