module Utils from "./utils"; import Exception from "./exception"; import { COMPILER_REVISION, REVISION_CHANGES, createFrame } from "./base"; export function checkRevision(compilerInfo) { var compilerRevision = compilerInfo && compilerInfo[0] || 1, currentRevision = COMPILER_REVISION; if (compilerRevision !== currentRevision) { if (compilerRevision < currentRevision) { var runtimeVersions = REVISION_CHANGES[currentRevision], compilerVersions = REVISION_CHANGES[compilerRevision]; throw new Exception("Template was precompiled with an older version of Handlebars than the current runtime. "+ "Please update your precompiler to a newer version ("+runtimeVersions+") or downgrade your runtime to an older version ("+compilerVersions+")."); } else { // Use the embedded version info since the runtime doesn't know about this revision yet throw new Exception("Template was precompiled with a newer version of Handlebars than the current runtime. "+ "Please update your runtime to a newer version ("+compilerInfo[1]+")."); } } } // TODO: Remove this line and break up compilePartial export function template(templateSpec, env) { /* istanbul ignore next */ if (!env) { throw new Exception("No environment passed to template"); } if (!templateSpec || !templateSpec.main) { throw new Exception('Unknown template object: ' + typeof templateSpec); } // Note: Using env.VM references rather than local var references throughout this section to allow // for external users to override these as psuedo-supported APIs. env.VM.checkRevision(templateSpec.compiler); var invokePartialWrapper = function(partial, indent, name, context, hash, helpers, partials, data, depths) { if (hash) { context = Utils.extend({}, context, hash); } var result = env.VM.invokePartial.call(this, partial, name, context, helpers, partials, data, depths); if (result == null && env.compile) { var options = { helpers: helpers, partials: partials, data: data, depths: depths }; partials[name] = env.compile(partial, { data: data !== undefined, compat: templateSpec.compat }, env); result = partials[name](context, options); } if (result != null) { if (indent) { var lines = result.split('\n'); for (var i = 0, l = lines.length; i < l; i++) { if (!lines[i] && i + 1 === l) { break; } lines[i] = indent + lines[i]; } result = lines.join('\n'); } return result; } else { throw new Exception("The partial " + name + " could not be compiled when running in runtime-only mode"); } }; // Just add water var container = { lookup: function(depths, name) { var len = depths.length; for (var i = 0; i < len; i++) { if (depths[i] && depths[i][name] != null) { return depths[i][name]; } } }, lambda: function(current, context) { return typeof current === 'function' ? current.call(context) : current; }, escapeExpression: Utils.escapeExpression, invokePartial: invokePartialWrapper, fn: function(i) { return templateSpec[i]; }, programs: [], program: function(i, data, depths) { var programWrapper = this.programs[i], fn = this.fn(i); if (data || depths) { programWrapper = program(this, i, fn, data, depths); } else if (!programWrapper) { programWrapper = this.programs[i] = program(this, i, fn); } return programWrapper; }, data: function(data, depth) { while (data && depth--) { data = data._parent; } return data; }, merge: function(param, common) { var ret = param || common; if (param && common && (param !== common)) { ret = Utils.extend({}, common, param); } return ret; }, noop: env.VM.noop, compilerInfo: templateSpec.compiler }; var ret = function(context, options) { options = options || {}; var data = options.data; ret._setup(options); if (!options.partial && templateSpec.useData) { data = initData(context, data); } var depths; if (templateSpec.useDepths) { depths = options.depths ? [context].concat(options.depths) : [context]; } return templateSpec.main.call(container, context, container.helpers, container.partials, data, depths); }; ret.isTop = true; ret._setup = function(options) { if (!options.partial) { container.helpers = container.merge(options.helpers, env.helpers); if (templateSpec.usePartial) { container.partials = container.merge(options.partials, env.partials); } } else { container.helpers = options.helpers; container.partials = options.partials; } }; ret._child = function(i, data, depths) { if (templateSpec.useDepths && !depths) { throw new Exception('must pass parent depths'); } return program(container, i, templateSpec[i], data, depths); }; return ret; } export function program(container, i, fn, data, depths) { var prog = function(context, options) { options = options || {}; return fn.call(container, context, container.helpers, container.partials, options.data || data, depths && [context].concat(depths)); }; prog.program = i; prog.depth = depths ? depths.length : 0; return prog; } export function invokePartial(partial, name, context, helpers, partials, data, depths) { var options = { partial: true, helpers: helpers, partials: partials, data: data, depths: depths }; if(partial === undefined) { throw new Exception("The partial " + name + " could not be found"); } else if(partial instanceof Function) { return partial(context, options); } } export function noop() { return ""; } function initData(context, data) { if (!data || !('root' in data)) { data = data ? createFrame(data) : {}; data.root = context; } return data; }