posthtml-extend
Version:
Templates extending (Jade-like)
2 lines • 4.71 kB
JavaScript
;Object.defineProperty(exports,"__esModule",{value:!0}),exports.default=void 0;var _fs=_interopRequireDefault(require("fs")),_path=_interopRequireDefault(require("path")),_util=require("util"),_posthtmlParser=require("posthtml-parser"),_posthtmlExpressions=_interopRequireDefault(require("posthtml-expressions")),_api=require("posthtml/lib/api"),_deepmerge=_interopRequireDefault(require("deepmerge"));function _interopRequireDefault(obj){return obj&&obj.__esModule?obj:{default:obj}}const errors={EXTENDS_NO_SRC:"<extends> has no \"src\"",BLOCK_NO_NAME:"<block> has no \"name\"",UNEXPECTED_BLOCK:"Unexpected block \"%s\""},extend=(options={})=>tree=>{options.encoding=options.encoding||"utf8",options.root=options.root||"./",options.plugins=options.plugins||[],options.strict=!Object.prototype.hasOwnProperty.call(options,"strict")||!!options.strict,options.slotTagName=options.slotTagName||"block",options.fillTagName=options.fillTagName||"block",options.tagName=options.tagName||"extends",options.expressions=options.expressions||{locals:{}},tree=handleExtendsNodes(tree,options,tree.messages);const blockNodes=getBlockNodes(options.slotTagName,tree);for(const blockName of Object.keys(blockNodes)){const blockNodeList=blockNodes[blockName];for(const blockNode of blockNodeList)blockNode.tag=!1,blockNode.content=blockNode.content||[];blockNodes[blockName]=blockNodeList}return tree};function handleExtendsNodes(tree,options,messages){return _api.match.call(tree=applyPluginsToTree(tree,options.plugins),{tag:options.tagName},extendsNode=>{if(!extendsNode.attrs||!extendsNode.attrs.src)throw getError(errors.EXTENDS_NO_SRC);let locals={};if(extendsNode.attrs.locals)try{locals=JSON.parse(extendsNode.attrs.locals)}catch{}const plugins=[...options.plugins,(0,_posthtmlExpressions.default)({...options.expressions,locals:(0,_deepmerge.default)(options.expressions.locals,locals)})],layoutPath=_path.default.resolve(options.root,extendsNode.attrs.src),layoutHtml=_fs.default.readFileSync(layoutPath,options.encoding),layoutTree=handleExtendsNodes(applyPluginsToTree((0,_posthtmlParser.parser)(layoutHtml),plugins),options,messages);return extendsNode.tag=!1,extendsNode.content=mergeExtendsAndLayout(layoutTree,extendsNode,options.strict,options.slotTagName,options.fillTagName),messages.push({type:"dependency",file:layoutPath,from:options.from}),extendsNode}),tree}function applyPluginsToTree(tree,plugins){return plugins.reduce((tree,plugin)=>(tree=plugin(tree),tree),tree)}function mergeExtendsAndLayout(layoutTree,extendsNode,strictNames,slotTagName,fillTagName){const layoutBlockNodes=getBlockNodes(slotTagName,layoutTree),extendsBlockNodes=getBlockNodes(fillTagName,extendsNode.content);for(const layoutBlockName of Object.keys(layoutBlockNodes)){const extendsBlockNodeList=extendsBlockNodes[layoutBlockName];if(!extendsBlockNodeList)continue;// pick up the last block node if multiple blocks are declared in `extends` node
const extendsBlockNode=extendsBlockNodeList[extendsBlockNodeList.length-1];if(!extendsBlockNode)continue;const layoutBlockNodeList=layoutBlockNodes[layoutBlockName];for(const layoutBlockNode of layoutBlockNodeList)layoutBlockNode.content=mergeContent(extendsBlockNode.content,layoutBlockNode.content,getBlockType(extendsBlockNode));delete extendsBlockNodes[layoutBlockName]}if(strictNames)for(const extendsBlockName of Object.keys(extendsBlockNodes))throw getError(errors.UNEXPECTED_BLOCK,extendsBlockName);return layoutTree}function mergeContent(extendBlockContent,layoutBlockContent,extendBlockType){switch(extendBlockContent=extendBlockContent||[],layoutBlockContent=layoutBlockContent||[],extendBlockType){case"replace":layoutBlockContent=extendBlockContent;break;case"prepend":layoutBlockContent=extendBlockContent.concat(layoutBlockContent);break;case"append":layoutBlockContent=layoutBlockContent.concat(extendBlockContent);break;default:}return layoutBlockContent}function getBlockType(blockNode){let blockType=blockNode.attrs&&blockNode.attrs.type||"";return blockType=blockType.toLowerCase(),["replace","prepend","append"].includes(blockType)||(blockType="replace"),blockType}function getBlockNodes(tag,content=[]){const blockNodes={};return _api.match.call(content,{tag},node=>{if(!node.attrs||!node.attrs.name)throw getError(errors.BLOCK_NO_NAME);return appendBlockNode(blockNodes,node),node}),blockNodes}function appendBlockNode(blockNodes,node){const{name}=node.attrs;return null==blockNodes[name]?blockNodes[name]=[node]:blockNodes[name].push(node),blockNodes}function getError(...rest){const message=(0,_util.format)(...rest);return new Error("[posthtml-extend] "+message)}var _default=extend;exports.default=_default,module.exports=exports.default;