Skip to content
Browse files

working on include

  • Loading branch information...
laggingreflex committed Jan 22, 2016
1 parent 40829f9 commit 8c4d01d650577f46094317be6332fbe9b7d1557a
Showing with 59 additions and 0 deletions.
  1. +5 −0 compiler/Builder.js
  2. +30 −0 compiler/ast/Include.js
  3. +21 −0 taglibs/core/include-tag.js
  4. +3 −0 taglibs/core/marko-taglib.json
@@ -9,6 +9,7 @@ var FunctionDeclaration = require('./ast/FunctionDeclaration');
var FunctionCall = require('./ast/FunctionCall');
var Literal = require('./ast/Literal');
var Identifier = require('./ast/Identifier');
var Include = require('./ast/Include');
var If = require('./ast/If');
var ElseIf = require('./ast/ElseIf');
var Else = require('./ast/Else');
@@ -207,6 +208,10 @@ class Builder {
return new Identifier({name});

includeStatement(templatePath, dirname) {
return new Include({templatePath, dirname});

ifStatement(test, body, elseStatement) {
return new If({test, body, else: elseStatement});
@@ -0,0 +1,30 @@
'use strict';

var Node = require('./Node');

var nodePath = require('path');
var req = require;
var fs;
try {
fs = req('fs');
} catch (e) {}

class Include extends Node {
constructor(def) {
this.templatePath = def.templatePath;
this.dirname = def.dirname;

generateCode(codegen) {
var resourcePath = nodePath.resolve(this.dirname, this.templatePath);
if (!fs.existsSync(resourcePath))
throw new Error('Resource not found: ' + resourcePath);

var contents = fs.readFileSync(resourcePath, {encoding: 'utf8'});

This comment has been minimized.

Copy link

laggingreflex Jan 22, 2016

Author Owner

I don't suppose addWriteLiteral is the right method to write contents. What would be the correct method?

I also couldn't figure out how to create recursions here, for when the included templates will have include tags of their own



module.exports = Include;
@@ -0,0 +1,21 @@
module.exports = function nodeFactory(elNode, context) {

This comment has been minimized.

Copy link

patrick-steele-idem Jan 22, 2016

You are using the code-generator interface and not the node-factory interface. code-generator is the correct choice, but you need to update your function signature to be the following:

module.exports = function codeGenerator(elNode, codegen) {

For the most part, your code below does not change other than renaming context to codegen. However, I've added a few more comments below...

if (!elNode.attributes || !elNode.attributes.length) {
context.addError(elNode, 'Invalid <include> tag. "template" attribute is missing. Example; <include template=\'...\'>');
return elNode;

This comment has been minimized.

Copy link

patrick-steele-idem Jan 22, 2016

Change these lines to the following:

codegen.addError('Invalid <include> tag. Template path argument is missing. Example: <include(templatePath[, templateData]) foo="bar">');

var templatePath;
for (var i = 0; i < elNode.attributes.length; i++) {
if (elNode.attributes[i].name == 'template' && elNode.attributes[i].value && elNode.attributes[i].value.value) {
templatePath = elNode.attributes[i].value.value;
if (!templatePath) {
context.addError(elNode, 'Invalid <include> tag. "template" attribute is missing. Example; <include template=\'...\'>');
return elNode;
var dirname = context.context.dirname;

return context.builder.includeStatement(templatePath, dirname);
@@ -14,6 +14,9 @@
"<if>": {
"node-factory": "./if-tag"
"<include>": {
"code-generator": "./include-tag"
"<invoke>": {
"code-generator": "./invoke-tag"

1 comment on commit 8c4d01d


This comment has been minimized.

Copy link

patrick-steele-idem commented on 8c4d01d Jan 22, 2016

Thanks for working on this @laggingreflex. Please take a look at the expected syntax for the <include> tag in Marko v3: marko-js#178

In Marko v3, we are using tag arguments to pass the template path and, optionally, a template data object.

Also, an <include> tag supports nested body content. The code to handle a custom tag will actually have some similarity to the code to handle the include tag. Please take a look at the following:

NOTE: The CustomTag AST node is going to be more complex because it supports a "tag definition" that can be used to control how attributes are handled.

Couple things to note:

Here is the code used to import and render a template:

let templateRequirePath = context.getRequirePath(tagDef.template);
let templateVar = context.importTemplate(templateRequirePath);
let renderMethod = builder.memberExpression(templateVar, builder.identifier('render'));
let renderArgs = [ inputProps, 'out' ];
let renderFunctionCall = builder.functionCall(renderMethod, renderArgs);
return renderFunctionCall;

In the case of an <include> tag, the template path can either be a literal (static) string, or it can be a JavaScript expression that resolves to a loaded template. Your code would need to handle both.

Here is the code used to build the renderBody(out) function

renderBodyFunction = context.builder.renderBodyFunction(this.body);
Please sign in to comment.
You can’t perform that action at this time.