node-tailor
Version:
Tailor assembles a web page from multiple fragments
79 lines (73 loc) • 2.93 kB
JavaScript
;
const parse5 = require('parse5');
const treeAdapter = parse5.treeAdapters.htmlparser2;
const CustomSerializer = require('./serializer');
/**
* Handles the parsing and serialization of templates. Also takes care of
* merging the base and page templates
*/
module.exports = class Transform {
constructor(handleTags, insertBeforePipeTags) {
this.handleTags = handleTags;
this.pipeTags = insertBeforePipeTags;
}
/**
* Parse and serialize the html.
*
* @param {string} baseTemplate - Base template that contains all the necessary tags and fragments for the given page (Used by multiple pages)
* @param {string=} childTemplate - The current page template that gets merged in to the base template
* @returns {Array} Array consiting of Buffers and Objects
*/
applyTransforms(baseTemplate, childTemplate, fullRendering) {
const options = { treeAdapter };
const rootNodes = fullRendering
? parse5.parse(baseTemplate, options)
: parse5.parseFragment(baseTemplate, options);
const slotMap =
childTemplate && typeof childTemplate === 'string'
? this._groupSlots(parse5.parseFragment(childTemplate, options))
: new Map();
const serializerOptions = {
treeAdapter,
slotMap,
pipeTags: this.pipeTags,
handleTags: this.handleTags,
fullRendering
};
const serializer = new CustomSerializer(rootNodes, serializerOptions);
return serializer.serialize();
}
/**
* Group all the nodes after parsing the child template. Nodes with unnamed slots are
* added to default slots
*
* @param {Object} root - The root node of the child template
* @returns {Map} Map with keys as slot attribute name and corresponding values consisting of array of matching nodes
*/
_groupSlots(root) {
const slotMap = new Map([['default', []]]);
const nodes = treeAdapter.getChildNodes(root);
nodes.forEach(node => {
if (!treeAdapter.isTextNode(node)) {
const { slot = 'default' } = node.attribs || {};
const slotNodes = slotMap.get(slot) || [];
const updatedSlotNodes = [...slotNodes, node];
slotMap.set(slot, updatedSlotNodes);
this._pushText(node.next, updatedSlotNodes);
node.attribs && delete node.attribs.slot;
}
});
return slotMap;
}
/**
* Add the text node to the Slot Map
*
* @param {Object} nextNode
* @param {Array} slot - Array of matching nodes
*/
_pushText(nextNode, slot) {
if (nextNode && treeAdapter.isTextNode(nextNode)) {
slot.push(nextNode);
}
}
};