Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
Download
80698 views
1
module Utils from "./utils";
2
import Exception from "./exception";
3
import { COMPILER_REVISION, REVISION_CHANGES, createFrame } from "./base";
4
5
export function checkRevision(compilerInfo) {
6
var compilerRevision = compilerInfo && compilerInfo[0] || 1,
7
currentRevision = COMPILER_REVISION;
8
9
if (compilerRevision !== currentRevision) {
10
if (compilerRevision < currentRevision) {
11
var runtimeVersions = REVISION_CHANGES[currentRevision],
12
compilerVersions = REVISION_CHANGES[compilerRevision];
13
throw new Exception("Template was precompiled with an older version of Handlebars than the current runtime. "+
14
"Please update your precompiler to a newer version ("+runtimeVersions+") or downgrade your runtime to an older version ("+compilerVersions+").");
15
} else {
16
// Use the embedded version info since the runtime doesn't know about this revision yet
17
throw new Exception("Template was precompiled with a newer version of Handlebars than the current runtime. "+
18
"Please update your runtime to a newer version ("+compilerInfo[1]+").");
19
}
20
}
21
}
22
23
// TODO: Remove this line and break up compilePartial
24
25
export function template(templateSpec, env) {
26
/* istanbul ignore next */
27
if (!env) {
28
throw new Exception("No environment passed to template");
29
}
30
if (!templateSpec || !templateSpec.main) {
31
throw new Exception('Unknown template object: ' + typeof templateSpec);
32
}
33
34
// Note: Using env.VM references rather than local var references throughout this section to allow
35
// for external users to override these as psuedo-supported APIs.
36
env.VM.checkRevision(templateSpec.compiler);
37
38
var invokePartialWrapper = function(partial, context, options) {
39
if (options.hash) {
40
context = Utils.extend({}, context, options.hash);
41
}
42
43
partial = env.VM.resolvePartial.call(this, partial, context, options);
44
var result = env.VM.invokePartial.call(this, partial, context, options);
45
46
if (result == null && env.compile) {
47
options.partials[options.name] = env.compile(partial, templateSpec.compilerOptions, env);
48
result = options.partials[options.name](context, options);
49
}
50
if (result != null) {
51
if (options.indent) {
52
var lines = result.split('\n');
53
for (var i = 0, l = lines.length; i < l; i++) {
54
if (!lines[i] && i + 1 === l) {
55
break;
56
}
57
58
lines[i] = options.indent + lines[i];
59
}
60
result = lines.join('\n');
61
}
62
return result;
63
} else {
64
throw new Exception("The partial " + options.name + " could not be compiled when running in runtime-only mode");
65
}
66
};
67
68
// Just add water
69
var container = {
70
strict: function(obj, name) {
71
if (!(name in obj)) {
72
throw new Exception('"' + name + '" not defined in ' + obj);
73
}
74
return obj[name];
75
},
76
lookup: function(depths, name) {
77
var len = depths.length;
78
for (var i = 0; i < len; i++) {
79
if (depths[i] && depths[i][name] != null) {
80
return depths[i][name];
81
}
82
}
83
},
84
lambda: function(current, context) {
85
return typeof current === 'function' ? current.call(context) : current;
86
},
87
88
escapeExpression: Utils.escapeExpression,
89
invokePartial: invokePartialWrapper,
90
91
fn: function(i) {
92
return templateSpec[i];
93
},
94
95
programs: [],
96
program: function(i, data, declaredBlockParams, blockParams, depths) {
97
var programWrapper = this.programs[i],
98
fn = this.fn(i);
99
if (data || depths || blockParams || declaredBlockParams) {
100
programWrapper = program(this, i, fn, data, declaredBlockParams, blockParams, depths);
101
} else if (!programWrapper) {
102
programWrapper = this.programs[i] = program(this, i, fn);
103
}
104
return programWrapper;
105
},
106
107
data: function(data, depth) {
108
while (data && depth--) {
109
data = data._parent;
110
}
111
return data;
112
},
113
merge: function(param, common) {
114
var ret = param || common;
115
116
if (param && common && (param !== common)) {
117
ret = Utils.extend({}, common, param);
118
}
119
120
return ret;
121
},
122
123
noop: env.VM.noop,
124
compilerInfo: templateSpec.compiler
125
};
126
127
var ret = function(context, options) {
128
options = options || {};
129
var data = options.data;
130
131
ret._setup(options);
132
if (!options.partial && templateSpec.useData) {
133
data = initData(context, data);
134
}
135
var depths,
136
blockParams = templateSpec.useBlockParams ? [] : undefined;
137
if (templateSpec.useDepths) {
138
depths = options.depths ? [context].concat(options.depths) : [context];
139
}
140
141
return templateSpec.main.call(container, context, container.helpers, container.partials, data, blockParams, depths);
142
};
143
ret.isTop = true;
144
145
ret._setup = function(options) {
146
if (!options.partial) {
147
container.helpers = container.merge(options.helpers, env.helpers);
148
149
if (templateSpec.usePartial) {
150
container.partials = container.merge(options.partials, env.partials);
151
}
152
} else {
153
container.helpers = options.helpers;
154
container.partials = options.partials;
155
}
156
};
157
158
ret._child = function(i, data, blockParams, depths) {
159
if (templateSpec.useBlockParams && !blockParams) {
160
throw new Exception('must pass block params');
161
}
162
if (templateSpec.useDepths && !depths) {
163
throw new Exception('must pass parent depths');
164
}
165
166
return program(container, i, templateSpec[i], data, 0, blockParams, depths);
167
};
168
return ret;
169
}
170
171
export function program(container, i, fn, data, declaredBlockParams, blockParams, depths) {
172
var prog = function(context, options) {
173
options = options || {};
174
175
return fn.call(container,
176
context,
177
container.helpers, container.partials,
178
options.data || data,
179
blockParams && [options.blockParams].concat(blockParams),
180
depths && [context].concat(depths));
181
};
182
prog.program = i;
183
prog.depth = depths ? depths.length : 0;
184
prog.blockParams = declaredBlockParams || 0;
185
return prog;
186
}
187
188
export function resolvePartial(partial, context, options) {
189
if (!partial) {
190
partial = options.partials[options.name];
191
} else if (!partial.call && !options.name) {
192
// This is a dynamic partial that returned a string
193
options.name = partial;
194
partial = options.partials[partial];
195
}
196
return partial;
197
}
198
199
export function invokePartial(partial, context, options) {
200
options.partial = true;
201
202
if(partial === undefined) {
203
throw new Exception("The partial " + options.name + " could not be found");
204
} else if(partial instanceof Function) {
205
return partial(context, options);
206
}
207
}
208
209
export function noop() { return ""; }
210
211
function initData(context, data) {
212
if (!data || !('root' in data)) {
213
data = data ? createFrame(data) : {};
214
data.root = context;
215
}
216
return data;
217
}
218
219