tildeio / htmlbars

A variant of Handlebars that emits DOM and allows you to write helpers that manipulate live DOM nodes
MIT License
1.6k stars 193 forks source link

Add `meta` to template output. #342

Closed rwjblue closed 9 years ago

rwjblue commented 9 years ago

Adds buildMeta callback to compile options.

If a buildMeta function is present in the options passed to compile or compileSpec, the return value will be used for the meta key in the template output.

This allows the host frameworks compiler to add metadata details (moduleName, revision, etc) as needed.

var template = compile('Hi, {{name}}!', {
  buildMeta: function(program) {
    return {
      isHTMLBars: true,
      revision: 'WAT@LOL.1234',
      loc: program.loc
    };
  }
});

template.meta.revision; // => 'WAT@LOL.1234'

Sample template output (no buildMeta callback):

(function() {
  return {
    meta: {},
    arity: 0,
    cachedFragment: null,
    hasRendered: false,
    buildFragment: function buildFragment(dom) {
      var el0 = dom.createDocumentFragment();
      var el1 = dom.createTextNode("Howdy ");
      dom.appendChild(el0, el1);
      var el1 = dom.createComment("");
      dom.appendChild(el0, el1);
      return el0;
    },
    buildRenderNodes: function buildRenderNodes(dom, fragment, contextualElement) {
      var morphs = new Array(1);
      morphs[0] = dom.createMorphAt(fragment,1,1,contextualElement);
      dom.insertBoundary(fragment, null);
      return morphs;
    },
    statements: [
      ["content","name"]
    ],
    locals: [],
    templates: []
  };
}())

Sample output with a general buildMeta as Ember might use it:

(function() {
  return {
    meta: {
      "isHTMLBars": true,
      "revision": "SOME@REVISION",
      "moduleName": "my-app-name/templates/foo",
      "loc": {"source":null,"start":{"line":1,"column":0},"end":{"line":1,"column":14}}
    },
    arity: 0,
    cachedFragment: null,
    hasRendered: false,
    buildFragment: function buildFragment(dom) {
      var el0 = dom.createDocumentFragment();
      var el1 = dom.createTextNode("Howdy ");
      dom.appendChild(el0, el1);
      var el1 = dom.createComment("");
      dom.appendChild(el0, el1);
      return el0;
    },
    buildRenderNodes: function buildRenderNodes(dom, fragment, contextualElement) {
      var morphs = new Array(1);
      morphs[0] = dom.createMorphAt(fragment,1,1,contextualElement);
      dom.insertBoundary(fragment, null);
      return morphs;
    },
    statements: [
      ["content","name"]
    ],
    locals: [],
    templates: []
  };
}())
rwjblue commented 9 years ago

@mmun suggested that we should not hijack loc.source for a non-absolute file path (and I agree). Will be updating shortly...

rwjblue commented 9 years ago

Completely refactored based on @mmun's feedback. Now it accepts a buildMeta callback function in options, and puts all information in meta on the template object.

rwjblue commented 9 years ago

Updated, to pass the program through to the buildMeta callback and remove loc from default meta.

rwjblue commented 9 years ago

Updated to remove some string gymnastics from the TemplateCompiler (rely on JSON.stringify for that).

mmun commented 9 years ago

:heart: