Skip to content

Instantly share code, notes, and snippets.

@chrisdickinson
Last active December 12, 2015 17:09
Show Gist options
  • Star 1 You must be signed in to star a gist
  • Fork 1 You must be signed in to fork a gist
  • Save chrisdickinson/4a1643f8f6b38bea3e99 to your computer and use it in GitHub Desktop.
Save chrisdickinson/4a1643f8f6b38bea3e99 to your computer and use it in GitHub Desktop.

make your templating language even better yet!

<ul>
{% for item in items %}
    <li>{% if item.okay %}it's okay{% else %}it's not okay{% endif %}</li>
{% endfor %}
</ul>
{{ message }}

the api should look like this:

var language = require('your-language-module')
  , if_tag = require('your-if-tag')
  , for_tag = require('your-for-tag')
  , compile
  , template

compile = language({
    'if': if_tag
  , 'for': for_tag
})
 
template = compile("<template string from above>")

template({
    items: [{okay: true}, {okay: false}]
  , message: "hello world"
}) // should render the above template

an example tag module:

// an example for tag
module.exports = function(parser, contents) { 
  var bits = contents.split(/\s+/)  // ["for", "item", "in", "items"]
    , contextTarget = bits[1]
    , lookupContextVariable = parser.lookup(bits[3]) 
    , forBody
    , emptyBody

  parser.parse({
      'endfor': endfor
    , 'empty': empty
  })

  return function(context) {
    var target = lookupContextVariable(context)
      , output = []
      , loopContext

    if(!target || !target.length) {
      return emptyBody ? emptyBody(context) : ''
    }

    for(var i = 0, len = target.length; i < len; ++i) {
      loopContext = Object.create(context)
      loopContext[contextTarget] = target[i]
      loopContext.forloop = {
          parent: loopContext.forloop
        , index: i
        , isfirst: i === 0
        , islast: i === len - 1
        , length: len
      } 
      output.push(forBody(loopContext))   
    }

    return output.join('')
  }

  function empty(tpl) {
    forBody = tpl
    parser.parse({'endfor': endfor})
  }

  function endfor(tpl) {
    if(forBody) {
      emptyBody = tpl
    } else {
      forBody = tpl
    }
  }
}

project 3 (it's big!):

  • write the module that exports a function that takes an object mapping tag names to parse functions and returns a function representing a compiler for strings in that language (fn(obj) -> fn(str) -> fn(obj) -> str is the chain). you will need to use your dotpathlookup module and your templatelanguage modules to build this module.

    the module should:

    • define a Parser type
    • export a function that takes the object mapping.

    the Parser should:

    • define a parse(obj?) function
    • define a lookup(str) function: lookup(str) -> function(obj) -> str

    the exported function should:

    • instantiate Parser with the mapping object when the exported function is called
    • match tags by /{%\s*([\w\d\s\-\.]*)\s*%}/
    • see if there's a tag parser function defined by the first word in match[1]
    • call that tag parser function with itself and match[1]
  • write a module that works like the above example tag module but implements simple if and else checking.

  • add to the above for module; let users use {% for item in items reversed %}.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment