handlebars-jaylinski 4.7.8

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (118) hide show
  1. package/LICENSE +19 -0
  2. package/README.markdown +169 -0
  3. package/bin/.eslintrc.js +6 -0
  4. package/bin/handlebars +176 -0
  5. package/dist/amd/handlebars/base.js +106 -0
  6. package/dist/amd/handlebars/compiler/ast.js +31 -0
  7. package/dist/amd/handlebars/compiler/base.js +45 -0
  8. package/dist/amd/handlebars/compiler/code-gen.js +165 -0
  9. package/dist/amd/handlebars/compiler/compiler.js +562 -0
  10. package/dist/amd/handlebars/compiler/helpers.js +228 -0
  11. package/dist/amd/handlebars/compiler/javascript-compiler.js +1150 -0
  12. package/dist/amd/handlebars/compiler/parser.js +737 -0
  13. package/dist/amd/handlebars/compiler/printer.js +186 -0
  14. package/dist/amd/handlebars/compiler/visitor.js +138 -0
  15. package/dist/amd/handlebars/compiler/whitespace-control.js +219 -0
  16. package/dist/amd/handlebars/decorators/inline.js +25 -0
  17. package/dist/amd/handlebars/decorators.js +16 -0
  18. package/dist/amd/handlebars/exception.js +64 -0
  19. package/dist/amd/handlebars/helpers/block-helper-missing.js +35 -0
  20. package/dist/amd/handlebars/helpers/each.js +99 -0
  21. package/dist/amd/handlebars/helpers/helper-missing.js +22 -0
  22. package/dist/amd/handlebars/helpers/if.js +41 -0
  23. package/dist/amd/handlebars/helpers/log.js +24 -0
  24. package/dist/amd/handlebars/helpers/lookup.js +14 -0
  25. package/dist/amd/handlebars/helpers/with.js +38 -0
  26. package/dist/amd/handlebars/helpers.js +44 -0
  27. package/dist/amd/handlebars/internal/create-new-lookup-object.js +22 -0
  28. package/dist/amd/handlebars/internal/proto-access.js +71 -0
  29. package/dist/amd/handlebars/internal/wrapHelper.js +21 -0
  30. package/dist/amd/handlebars/logger.js +44 -0
  31. package/dist/amd/handlebars/no-conflict.js +28 -0
  32. package/dist/amd/handlebars/runtime.js +356 -0
  33. package/dist/amd/handlebars/safe-string.js +15 -0
  34. package/dist/amd/handlebars/utils.js +126 -0
  35. package/dist/amd/handlebars.js +52 -0
  36. package/dist/amd/handlebars.runtime.js +44 -0
  37. package/dist/amd/precompiler.js +314 -0
  38. package/dist/cjs/handlebars/base.js +116 -0
  39. package/dist/cjs/handlebars/compiler/ast.js +31 -0
  40. package/dist/cjs/handlebars/compiler/base.js +57 -0
  41. package/dist/cjs/handlebars/compiler/code-gen.js +168 -0
  42. package/dist/cjs/handlebars/compiler/compiler.js +566 -0
  43. package/dist/cjs/handlebars/compiler/helpers.js +228 -0
  44. package/dist/cjs/handlebars/compiler/javascript-compiler.js +1158 -0
  45. package/dist/cjs/handlebars/compiler/parser.js +737 -0
  46. package/dist/cjs/handlebars/compiler/printer.js +186 -0
  47. package/dist/cjs/handlebars/compiler/visitor.js +140 -0
  48. package/dist/cjs/handlebars/compiler/whitespace-control.js +221 -0
  49. package/dist/cjs/handlebars/decorators/inline.js +29 -0
  50. package/dist/cjs/handlebars/decorators.js +16 -0
  51. package/dist/cjs/handlebars/exception.js +64 -0
  52. package/dist/cjs/handlebars/helpers/block-helper-missing.js +39 -0
  53. package/dist/cjs/handlebars/helpers/each.js +104 -0
  54. package/dist/cjs/handlebars/helpers/helper-missing.js +25 -0
  55. package/dist/cjs/handlebars/helpers/if.js +46 -0
  56. package/dist/cjs/handlebars/helpers/log.js +26 -0
  57. package/dist/cjs/handlebars/helpers/lookup.js +16 -0
  58. package/dist/cjs/handlebars/helpers/with.js +43 -0
  59. package/dist/cjs/handlebars/helpers.js +56 -0
  60. package/dist/cjs/handlebars/internal/create-new-lookup-object.js +22 -0
  61. package/dist/cjs/handlebars/internal/proto-access.js +73 -0
  62. package/dist/cjs/handlebars/internal/wrapHelper.js +19 -0
  63. package/dist/cjs/handlebars/logger.js +47 -0
  64. package/dist/cjs/handlebars/no-conflict.js +30 -0
  65. package/dist/cjs/handlebars/runtime.js +372 -0
  66. package/dist/cjs/handlebars/safe-string.js +15 -0
  67. package/dist/cjs/handlebars/utils.js +124 -0
  68. package/dist/cjs/handlebars.js +66 -0
  69. package/dist/cjs/handlebars.runtime.js +66 -0
  70. package/dist/cjs/precompiler.js +328 -0
  71. package/dist/handlebars.amd.js +4639 -0
  72. package/dist/handlebars.amd.min.js +29 -0
  73. package/dist/handlebars.js +5972 -0
  74. package/dist/handlebars.min.js +29 -0
  75. package/dist/handlebars.runtime.amd.js +1302 -0
  76. package/dist/handlebars.runtime.amd.min.js +27 -0
  77. package/dist/handlebars.runtime.js +2563 -0
  78. package/dist/handlebars.runtime.min.js +27 -0
  79. package/lib/.eslintrc.js +8 -0
  80. package/lib/handlebars/base.js +94 -0
  81. package/lib/handlebars/compiler/ast.js +32 -0
  82. package/lib/handlebars/compiler/base.js +34 -0
  83. package/lib/handlebars/compiler/code-gen.js +171 -0
  84. package/lib/handlebars/compiler/compiler.js +594 -0
  85. package/lib/handlebars/compiler/helpers.js +219 -0
  86. package/lib/handlebars/compiler/javascript-compiler.js +1293 -0
  87. package/lib/handlebars/compiler/parser.js +622 -0
  88. package/lib/handlebars/compiler/printer.js +178 -0
  89. package/lib/handlebars/compiler/visitor.js +136 -0
  90. package/lib/handlebars/compiler/whitespace-control.js +234 -0
  91. package/lib/handlebars/decorators/inline.js +22 -0
  92. package/lib/handlebars/decorators.js +5 -0
  93. package/lib/handlebars/exception.js +68 -0
  94. package/lib/handlebars/helpers/block-helper-missing.js +35 -0
  95. package/lib/handlebars/helpers/each.js +101 -0
  96. package/lib/handlebars/helpers/helper-missing.js +15 -0
  97. package/lib/handlebars/helpers/if.js +33 -0
  98. package/lib/handlebars/helpers/log.js +19 -0
  99. package/lib/handlebars/helpers/lookup.js +9 -0
  100. package/lib/handlebars/helpers/with.js +39 -0
  101. package/lib/handlebars/helpers.js +26 -0
  102. package/lib/handlebars/internal/create-new-lookup-object.js +11 -0
  103. package/lib/handlebars/internal/proto-access.js +70 -0
  104. package/lib/handlebars/internal/wrapHelper.js +13 -0
  105. package/lib/handlebars/logger.js +39 -0
  106. package/lib/handlebars/no-conflict.js +23 -0
  107. package/lib/handlebars/runtime.js +450 -0
  108. package/lib/handlebars/safe-string.js +10 -0
  109. package/lib/handlebars/utils.js +116 -0
  110. package/lib/handlebars.js +46 -0
  111. package/lib/handlebars.runtime.js +37 -0
  112. package/lib/index.js +26 -0
  113. package/lib/precompiler.js +341 -0
  114. package/package.json +135 -0
  115. package/release-notes.md +1101 -0
  116. package/runtime.d.ts +5 -0
  117. package/runtime.js +3 -0
  118. package/types/index.d.ts +422 -0
@@ -0,0 +1,594 @@
1
+ /* eslint-disable new-cap */
2
+
3
+ import Exception from '../exception';
4
+ import { isArray, indexOf, extend } from '../utils';
5
+ import AST from './ast';
6
+
7
+ const slice = [].slice;
8
+
9
+ export function Compiler() {}
10
+
11
+ // the foundHelper register will disambiguate helper lookup from finding a
12
+ // function in a context. This is necessary for mustache compatibility, which
13
+ // requires that context functions in blocks are evaluated by blockHelperMissing,
14
+ // and then proceed as if the resulting value was provided to blockHelperMissing.
15
+
16
+ Compiler.prototype = {
17
+ compiler: Compiler,
18
+
19
+ equals: function(other) {
20
+ let len = this.opcodes.length;
21
+ if (other.opcodes.length !== len) {
22
+ return false;
23
+ }
24
+
25
+ for (let i = 0; i < len; i++) {
26
+ let opcode = this.opcodes[i],
27
+ otherOpcode = other.opcodes[i];
28
+ if (
29
+ opcode.opcode !== otherOpcode.opcode ||
30
+ !argEquals(opcode.args, otherOpcode.args)
31
+ ) {
32
+ return false;
33
+ }
34
+ }
35
+
36
+ // We know that length is the same between the two arrays because they are directly tied
37
+ // to the opcode behavior above.
38
+ len = this.children.length;
39
+ for (let i = 0; i < len; i++) {
40
+ if (!this.children[i].equals(other.children[i])) {
41
+ return false;
42
+ }
43
+ }
44
+
45
+ return true;
46
+ },
47
+
48
+ guid: 0,
49
+
50
+ compile: function(program, options) {
51
+ this.sourceNode = [];
52
+ this.opcodes = [];
53
+ this.children = [];
54
+ this.options = options;
55
+ this.stringParams = options.stringParams;
56
+ this.trackIds = options.trackIds;
57
+
58
+ options.blockParams = options.blockParams || [];
59
+
60
+ options.knownHelpers = extend(
61
+ Object.create(null),
62
+ {
63
+ helperMissing: true,
64
+ blockHelperMissing: true,
65
+ each: true,
66
+ if: true,
67
+ unless: true,
68
+ with: true,
69
+ log: true,
70
+ lookup: true
71
+ },
72
+ options.knownHelpers
73
+ );
74
+
75
+ return this.accept(program);
76
+ },
77
+
78
+ compileProgram: function(program) {
79
+ let childCompiler = new this.compiler(), // eslint-disable-line new-cap
80
+ result = childCompiler.compile(program, this.options),
81
+ guid = this.guid++;
82
+
83
+ this.usePartial = this.usePartial || result.usePartial;
84
+
85
+ this.children[guid] = result;
86
+ this.useDepths = this.useDepths || result.useDepths;
87
+
88
+ return guid;
89
+ },
90
+
91
+ accept: function(node) {
92
+ /* istanbul ignore next: Sanity code */
93
+ if (!this[node.type]) {
94
+ throw new Exception('Unknown type: ' + node.type, node);
95
+ }
96
+
97
+ this.sourceNode.unshift(node);
98
+ let ret = this[node.type](node);
99
+ this.sourceNode.shift();
100
+ return ret;
101
+ },
102
+
103
+ Program: function(program) {
104
+ this.options.blockParams.unshift(program.blockParams);
105
+
106
+ let body = program.body,
107
+ bodyLength = body.length;
108
+ for (let i = 0; i < bodyLength; i++) {
109
+ this.accept(body[i]);
110
+ }
111
+
112
+ this.options.blockParams.shift();
113
+
114
+ this.isSimple = bodyLength === 1;
115
+ this.blockParams = program.blockParams ? program.blockParams.length : 0;
116
+
117
+ return this;
118
+ },
119
+
120
+ BlockStatement: function(block) {
121
+ transformLiteralToPath(block);
122
+
123
+ let program = block.program,
124
+ inverse = block.inverse;
125
+
126
+ program = program && this.compileProgram(program);
127
+ inverse = inverse && this.compileProgram(inverse);
128
+
129
+ let type = this.classifySexpr(block);
130
+
131
+ if (type === 'helper') {
132
+ this.helperSexpr(block, program, inverse);
133
+ } else if (type === 'simple') {
134
+ this.simpleSexpr(block);
135
+
136
+ // now that the simple mustache is resolved, we need to
137
+ // evaluate it by executing `blockHelperMissing`
138
+ this.opcode('pushProgram', program);
139
+ this.opcode('pushProgram', inverse);
140
+ this.opcode('emptyHash');
141
+ this.opcode('blockValue', block.path.original);
142
+ } else {
143
+ this.ambiguousSexpr(block, program, inverse);
144
+
145
+ // now that the simple mustache is resolved, we need to
146
+ // evaluate it by executing `blockHelperMissing`
147
+ this.opcode('pushProgram', program);
148
+ this.opcode('pushProgram', inverse);
149
+ this.opcode('emptyHash');
150
+ this.opcode('ambiguousBlockValue');
151
+ }
152
+
153
+ this.opcode('append');
154
+ },
155
+
156
+ DecoratorBlock(decorator) {
157
+ let program = decorator.program && this.compileProgram(decorator.program);
158
+ let params = this.setupFullMustacheParams(decorator, program, undefined),
159
+ path = decorator.path;
160
+
161
+ this.useDecorators = true;
162
+ this.opcode('registerDecorator', params.length, path.original);
163
+ },
164
+
165
+ PartialStatement: function(partial) {
166
+ this.usePartial = true;
167
+
168
+ let program = partial.program;
169
+ if (program) {
170
+ program = this.compileProgram(partial.program);
171
+ }
172
+
173
+ let params = partial.params;
174
+ if (params.length > 1) {
175
+ throw new Exception(
176
+ 'Unsupported number of partial arguments: ' + params.length,
177
+ partial
178
+ );
179
+ } else if (!params.length) {
180
+ if (this.options.explicitPartialContext) {
181
+ this.opcode('pushLiteral', 'undefined');
182
+ } else {
183
+ params.push({ type: 'PathExpression', parts: [], depth: 0 });
184
+ }
185
+ }
186
+
187
+ let partialName = partial.name.original,
188
+ isDynamic = partial.name.type === 'SubExpression';
189
+ if (isDynamic) {
190
+ this.accept(partial.name);
191
+ }
192
+
193
+ this.setupFullMustacheParams(partial, program, undefined, true);
194
+
195
+ let indent = partial.indent || '';
196
+ if (this.options.preventIndent && indent) {
197
+ this.opcode('appendContent', indent);
198
+ indent = '';
199
+ }
200
+
201
+ this.opcode('invokePartial', isDynamic, partialName, indent);
202
+ this.opcode('append');
203
+ },
204
+ PartialBlockStatement: function(partialBlock) {
205
+ this.PartialStatement(partialBlock);
206
+ },
207
+
208
+ MustacheStatement: function(mustache) {
209
+ this.SubExpression(mustache);
210
+
211
+ if (mustache.escaped && !this.options.noEscape) {
212
+ this.opcode('appendEscaped');
213
+ } else {
214
+ this.opcode('append');
215
+ }
216
+ },
217
+ Decorator(decorator) {
218
+ this.DecoratorBlock(decorator);
219
+ },
220
+
221
+ ContentStatement: function(content) {
222
+ if (content.value) {
223
+ this.opcode('appendContent', content.value);
224
+ }
225
+ },
226
+
227
+ CommentStatement: function() {},
228
+
229
+ SubExpression: function(sexpr) {
230
+ transformLiteralToPath(sexpr);
231
+ let type = this.classifySexpr(sexpr);
232
+
233
+ if (type === 'simple') {
234
+ this.simpleSexpr(sexpr);
235
+ } else if (type === 'helper') {
236
+ this.helperSexpr(sexpr);
237
+ } else {
238
+ this.ambiguousSexpr(sexpr);
239
+ }
240
+ },
241
+ ambiguousSexpr: function(sexpr, program, inverse) {
242
+ let path = sexpr.path,
243
+ name = path.parts[0],
244
+ isBlock = program != null || inverse != null;
245
+
246
+ this.opcode('getContext', path.depth);
247
+
248
+ this.opcode('pushProgram', program);
249
+ this.opcode('pushProgram', inverse);
250
+
251
+ path.strict = true;
252
+ this.accept(path);
253
+
254
+ this.opcode('invokeAmbiguous', name, isBlock);
255
+ },
256
+
257
+ simpleSexpr: function(sexpr) {
258
+ let path = sexpr.path;
259
+ path.strict = true;
260
+ this.accept(path);
261
+ this.opcode('resolvePossibleLambda');
262
+ },
263
+
264
+ helperSexpr: function(sexpr, program, inverse) {
265
+ let params = this.setupFullMustacheParams(sexpr, program, inverse),
266
+ path = sexpr.path,
267
+ name = path.parts[0];
268
+
269
+ if (this.options.knownHelpers[name]) {
270
+ this.opcode('invokeKnownHelper', params.length, name);
271
+ } else if (this.options.knownHelpersOnly) {
272
+ throw new Exception(
273
+ 'You specified knownHelpersOnly, but used the unknown helper ' + name,
274
+ sexpr
275
+ );
276
+ } else {
277
+ path.strict = true;
278
+ path.falsy = true;
279
+
280
+ this.accept(path);
281
+ this.opcode(
282
+ 'invokeHelper',
283
+ params.length,
284
+ path.original,
285
+ AST.helpers.simpleId(path)
286
+ );
287
+ }
288
+ },
289
+
290
+ PathExpression: function(path) {
291
+ this.addDepth(path.depth);
292
+ this.opcode('getContext', path.depth);
293
+
294
+ let name = path.parts[0],
295
+ scoped = AST.helpers.scopedId(path),
296
+ blockParamId = !path.depth && !scoped && this.blockParamIndex(name);
297
+
298
+ if (blockParamId) {
299
+ this.opcode('lookupBlockParam', blockParamId, path.parts);
300
+ } else if (!name) {
301
+ // Context reference, i.e. `{{foo .}}` or `{{foo ..}}`
302
+ this.opcode('pushContext');
303
+ } else if (path.data) {
304
+ this.options.data = true;
305
+ this.opcode('lookupData', path.depth, path.parts, path.strict);
306
+ } else {
307
+ this.opcode(
308
+ 'lookupOnContext',
309
+ path.parts,
310
+ path.falsy,
311
+ path.strict,
312
+ scoped
313
+ );
314
+ }
315
+ },
316
+
317
+ StringLiteral: function(string) {
318
+ this.opcode('pushString', string.value);
319
+ },
320
+
321
+ NumberLiteral: function(number) {
322
+ this.opcode('pushLiteral', number.value);
323
+ },
324
+
325
+ BooleanLiteral: function(bool) {
326
+ this.opcode('pushLiteral', bool.value);
327
+ },
328
+
329
+ UndefinedLiteral: function() {
330
+ this.opcode('pushLiteral', 'undefined');
331
+ },
332
+
333
+ NullLiteral: function() {
334
+ this.opcode('pushLiteral', 'null');
335
+ },
336
+
337
+ Hash: function(hash) {
338
+ let pairs = hash.pairs,
339
+ i = 0,
340
+ l = pairs.length;
341
+
342
+ this.opcode('pushHash');
343
+
344
+ for (; i < l; i++) {
345
+ this.pushParam(pairs[i].value);
346
+ }
347
+ while (i--) {
348
+ this.opcode('assignToHash', pairs[i].key);
349
+ }
350
+ this.opcode('popHash');
351
+ },
352
+
353
+ // HELPERS
354
+ opcode: function(name) {
355
+ this.opcodes.push({
356
+ opcode: name,
357
+ args: slice.call(arguments, 1),
358
+ loc: this.sourceNode[0].loc
359
+ });
360
+ },
361
+
362
+ addDepth: function(depth) {
363
+ if (!depth) {
364
+ return;
365
+ }
366
+
367
+ this.useDepths = true;
368
+ },
369
+
370
+ classifySexpr: function(sexpr) {
371
+ let isSimple = AST.helpers.simpleId(sexpr.path);
372
+
373
+ let isBlockParam = isSimple && !!this.blockParamIndex(sexpr.path.parts[0]);
374
+
375
+ // a mustache is an eligible helper if:
376
+ // * its id is simple (a single part, not `this` or `..`)
377
+ let isHelper = !isBlockParam && AST.helpers.helperExpression(sexpr);
378
+
379
+ // if a mustache is an eligible helper but not a definite
380
+ // helper, it is ambiguous, and will be resolved in a later
381
+ // pass or at runtime.
382
+ let isEligible = !isBlockParam && (isHelper || isSimple);
383
+
384
+ // if ambiguous, we can possibly resolve the ambiguity now
385
+ // An eligible helper is one that does not have a complex path, i.e. `this.foo`, `../foo` etc.
386
+ if (isEligible && !isHelper) {
387
+ let name = sexpr.path.parts[0],
388
+ options = this.options;
389
+ if (options.knownHelpers[name]) {
390
+ isHelper = true;
391
+ } else if (options.knownHelpersOnly) {
392
+ isEligible = false;
393
+ }
394
+ }
395
+
396
+ if (isHelper) {
397
+ return 'helper';
398
+ } else if (isEligible) {
399
+ return 'ambiguous';
400
+ } else {
401
+ return 'simple';
402
+ }
403
+ },
404
+
405
+ pushParams: function(params) {
406
+ for (let i = 0, l = params.length; i < l; i++) {
407
+ this.pushParam(params[i]);
408
+ }
409
+ },
410
+
411
+ pushParam: function(val) {
412
+ let value = val.value != null ? val.value : val.original || '';
413
+
414
+ if (this.stringParams) {
415
+ if (value.replace) {
416
+ value = value.replace(/^(\.?\.\/)*/g, '').replace(/\//g, '.');
417
+ }
418
+
419
+ if (val.depth) {
420
+ this.addDepth(val.depth);
421
+ }
422
+ this.opcode('getContext', val.depth || 0);
423
+ this.opcode('pushStringParam', value, val.type);
424
+
425
+ if (val.type === 'SubExpression') {
426
+ // SubExpressions get evaluated and passed in
427
+ // in string params mode.
428
+ this.accept(val);
429
+ }
430
+ } else {
431
+ if (this.trackIds) {
432
+ let blockParamIndex;
433
+ if (val.parts && !AST.helpers.scopedId(val) && !val.depth) {
434
+ blockParamIndex = this.blockParamIndex(val.parts[0]);
435
+ }
436
+ if (blockParamIndex) {
437
+ let blockParamChild = val.parts.slice(1).join('.');
438
+ this.opcode('pushId', 'BlockParam', blockParamIndex, blockParamChild);
439
+ } else {
440
+ value = val.original || value;
441
+ if (value.replace) {
442
+ value = value
443
+ .replace(/^this(?:\.|$)/, '')
444
+ .replace(/^\.\//, '')
445
+ .replace(/^\.$/, '');
446
+ }
447
+
448
+ this.opcode('pushId', val.type, value);
449
+ }
450
+ }
451
+ this.accept(val);
452
+ }
453
+ },
454
+
455
+ setupFullMustacheParams: function(sexpr, program, inverse, omitEmpty) {
456
+ let params = sexpr.params;
457
+ this.pushParams(params);
458
+
459
+ this.opcode('pushProgram', program);
460
+ this.opcode('pushProgram', inverse);
461
+
462
+ if (sexpr.hash) {
463
+ this.accept(sexpr.hash);
464
+ } else {
465
+ this.opcode('emptyHash', omitEmpty);
466
+ }
467
+
468
+ return params;
469
+ },
470
+
471
+ blockParamIndex: function(name) {
472
+ for (
473
+ let depth = 0, len = this.options.blockParams.length;
474
+ depth < len;
475
+ depth++
476
+ ) {
477
+ let blockParams = this.options.blockParams[depth],
478
+ param = blockParams && indexOf(blockParams, name);
479
+ if (blockParams && param >= 0) {
480
+ return [depth, param];
481
+ }
482
+ }
483
+ }
484
+ };
485
+
486
+ export function precompile(input, options, env) {
487
+ if (
488
+ input == null ||
489
+ (typeof input !== 'string' && input.type !== 'Program')
490
+ ) {
491
+ throw new Exception(
492
+ 'You must pass a string or Handlebars AST to Handlebars.precompile. You passed ' +
493
+ input
494
+ );
495
+ }
496
+
497
+ options = options || {};
498
+ if (!('data' in options)) {
499
+ options.data = true;
500
+ }
501
+ if (options.compat) {
502
+ options.useDepths = true;
503
+ }
504
+
505
+ let ast = env.parse(input, options),
506
+ environment = new env.Compiler().compile(ast, options);
507
+ return new env.JavaScriptCompiler().compile(environment, options);
508
+ }
509
+
510
+ export function compile(input, options = {}, env) {
511
+ if (
512
+ input == null ||
513
+ (typeof input !== 'string' && input.type !== 'Program')
514
+ ) {
515
+ throw new Exception(
516
+ 'You must pass a string or Handlebars AST to Handlebars.compile. You passed ' +
517
+ input
518
+ );
519
+ }
520
+
521
+ options = extend({}, options);
522
+ if (!('data' in options)) {
523
+ options.data = true;
524
+ }
525
+ if (options.compat) {
526
+ options.useDepths = true;
527
+ }
528
+
529
+ let compiled;
530
+
531
+ function compileInput() {
532
+ let ast = env.parse(input, options),
533
+ environment = new env.Compiler().compile(ast, options),
534
+ templateSpec = new env.JavaScriptCompiler().compile(
535
+ environment,
536
+ options,
537
+ undefined,
538
+ true
539
+ );
540
+ return env.template(templateSpec);
541
+ }
542
+
543
+ // Template is only compiled on first use and cached after that point.
544
+ function ret(context, execOptions) {
545
+ if (!compiled) {
546
+ compiled = compileInput();
547
+ }
548
+ return compiled.call(this, context, execOptions);
549
+ }
550
+ ret._setup = function(setupOptions) {
551
+ if (!compiled) {
552
+ compiled = compileInput();
553
+ }
554
+ return compiled._setup(setupOptions);
555
+ };
556
+ ret._child = function(i, data, blockParams, depths) {
557
+ if (!compiled) {
558
+ compiled = compileInput();
559
+ }
560
+ return compiled._child(i, data, blockParams, depths);
561
+ };
562
+ return ret;
563
+ }
564
+
565
+ function argEquals(a, b) {
566
+ if (a === b) {
567
+ return true;
568
+ }
569
+
570
+ if (isArray(a) && isArray(b) && a.length === b.length) {
571
+ for (let i = 0; i < a.length; i++) {
572
+ if (!argEquals(a[i], b[i])) {
573
+ return false;
574
+ }
575
+ }
576
+ return true;
577
+ }
578
+ }
579
+
580
+ function transformLiteralToPath(sexpr) {
581
+ if (!sexpr.path.parts) {
582
+ let literal = sexpr.path;
583
+ // Casting to string here to make false and 0 literal values play nicely with the rest
584
+ // of the system.
585
+ sexpr.path = {
586
+ type: 'PathExpression',
587
+ data: false,
588
+ depth: 0,
589
+ parts: [literal.original + ''],
590
+ original: literal.original + '',
591
+ loc: literal.loc
592
+ };
593
+ }
594
+ }