|
/** |
|
* Molecular Design. (Atomic design, but technically everything is a molecule) |
|
*/ |
|
|
|
|
|
var dust = require('dustjs-linkedin') |
|
, fs = require('fs') |
|
, path = require('path') |
|
, callsite = require('callsite') |
|
|
|
|
|
var Molecule = module.exports = function(opts){ |
|
|
|
this.template = opts.template |
|
if (opts.templateFile){ |
|
this.templateFile = resolveTemplate(opts.templateFile); |
|
this.template = fs.readFileSync(this.templateFile, 'utf8') |
|
} |
|
|
|
this.name = opts.name || "Unnamed Molecule"; |
|
|
|
} |
|
|
|
|
|
Molecule.prototype.render = function(opts, cb){ |
|
var molecule = this; |
|
|
|
// Dust helper: @module is a node module (another molecule) |
|
dust.helpers.module = function(chunk, context, bodies, params){ |
|
var module = params.id |
|
, templateDir = path.dirname(molecule.templateFile) |
|
, m |
|
, ctx = params; |
|
|
|
/* |
|
* This is a little ugly - essentially we want to 'require' in |
|
* the context of the template. If the module is relative then |
|
* we need to fix the path, as we're in node_modules. |
|
* |
|
* There is probably a better way to do this. |
|
*/ |
|
if (module.charAt(0) === '.'){ |
|
module = path.join(templateDir, module) |
|
m = require(module) |
|
} else { |
|
// Must be in first level of node_modules... |
|
m = require(path.join(process.cwd(), 'node_modules', module)) |
|
} |
|
|
|
|
|
Object.keys(params).forEach(function(k){ |
|
ctx[k] = params[k] |
|
}) |
|
return chunk.map(function(chunk){ |
|
m.render(ctx, function(err, res){ |
|
if (err){ |
|
throw err; |
|
} |
|
chunk.end(res) |
|
}) |
|
}) |
|
} |
|
|
|
|
|
if (!this.template){ |
|
return cb(new Error("Cannot render: Molecule has no template")); |
|
} |
|
if (!cb){ |
|
throw new Error("render(opts, cb) requires a callback"); |
|
} |
|
|
|
console.log("# Rendering", this.name) |
|
var compiled = dust.compile(this.template, this.name); |
|
dust.loadSource(compiled); |
|
return dust.render(this.name, opts, cb); |
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
var resolveTemplate = function(template){ |
|
// Try and be smart about resolving template |
|
if (fs.existsSync(template)){ |
|
return template |
|
} |
|
if (fs.existsSync(path.join(process.cwd(), template))){ |
|
// Relative to cwd |
|
return path.join(process.cwd(), template) |
|
} |
|
if (fs.existsSync(path.join(__dirname, template))){ |
|
// Relative to Molecule.js... unlikely |
|
return path.join(__dirname, template) |
|
} |
|
|
|
// Relative to init caller -- most likely, but slowest |
|
var caller = callsite()[2].getFileName() |
|
, fn = path.join(path.dirname(caller), template); |
|
|
|
if (fs.existsSync(fn)){ |
|
return fn; |
|
} |
|
|
|
throw new Error("Couldn't find template file:" + template) |
|
} |