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,1293 @@
1
+ import { COMPILER_REVISION, REVISION_CHANGES } from '../base';
2
+ import Exception from '../exception';
3
+ import { isArray } from '../utils';
4
+ import CodeGen from './code-gen';
5
+
6
+ function Literal(value) {
7
+ this.value = value;
8
+ }
9
+
10
+ function JavaScriptCompiler() {}
11
+
12
+ JavaScriptCompiler.prototype = {
13
+ // PUBLIC API: You can override these methods in a subclass to provide
14
+ // alternative compiled forms for name lookup and buffering semantics
15
+ nameLookup: function(parent, name /*, type */) {
16
+ return this.internalNameLookup(parent, name);
17
+ },
18
+ depthedLookup: function(name) {
19
+ return [
20
+ this.aliasable('container.lookup'),
21
+ '(depths, ',
22
+ JSON.stringify(name),
23
+ ')'
24
+ ];
25
+ },
26
+
27
+ compilerInfo: function() {
28
+ const revision = COMPILER_REVISION,
29
+ versions = REVISION_CHANGES[revision];
30
+ return [revision, versions];
31
+ },
32
+
33
+ appendToBuffer: function(source, location, explicit) {
34
+ // Force a source as this simplifies the merge logic.
35
+ if (!isArray(source)) {
36
+ source = [source];
37
+ }
38
+ source = this.source.wrap(source, location);
39
+
40
+ if (this.environment.isSimple) {
41
+ return ['return ', source, ';'];
42
+ } else if (explicit) {
43
+ // This is a case where the buffer operation occurs as a child of another
44
+ // construct, generally braces. We have to explicitly output these buffer
45
+ // operations to ensure that the emitted code goes in the correct location.
46
+ return ['buffer += ', source, ';'];
47
+ } else {
48
+ source.appendToBuffer = true;
49
+ return source;
50
+ }
51
+ },
52
+
53
+ initializeBuffer: function() {
54
+ return this.quotedString('');
55
+ },
56
+ // END PUBLIC API
57
+ internalNameLookup: function(parent, name) {
58
+ this.lookupPropertyFunctionIsUsed = true;
59
+ return ['lookupProperty(', parent, ',', JSON.stringify(name), ')'];
60
+ },
61
+
62
+ lookupPropertyFunctionIsUsed: false,
63
+
64
+ compile: function(environment, options, context, asObject) {
65
+ this.environment = environment;
66
+ this.options = options;
67
+ this.stringParams = this.options.stringParams;
68
+ this.trackIds = this.options.trackIds;
69
+ this.precompile = !asObject;
70
+
71
+ this.name = this.environment.name;
72
+ this.isChild = !!context;
73
+ this.context = context || {
74
+ decorators: [],
75
+ programs: [],
76
+ environments: []
77
+ };
78
+
79
+ this.preamble();
80
+
81
+ this.stackSlot = 0;
82
+ this.stackVars = [];
83
+ this.aliases = {};
84
+ this.registers = { list: [] };
85
+ this.hashes = [];
86
+ this.compileStack = [];
87
+ this.inlineStack = [];
88
+ this.blockParams = [];
89
+
90
+ this.compileChildren(environment, options);
91
+
92
+ this.useDepths =
93
+ this.useDepths ||
94
+ environment.useDepths ||
95
+ environment.useDecorators ||
96
+ this.options.compat;
97
+ this.useBlockParams = this.useBlockParams || environment.useBlockParams;
98
+
99
+ let opcodes = environment.opcodes,
100
+ opcode,
101
+ firstLoc,
102
+ i,
103
+ l;
104
+
105
+ for (i = 0, l = opcodes.length; i < l; i++) {
106
+ opcode = opcodes[i];
107
+
108
+ this.source.currentLocation = opcode.loc;
109
+ firstLoc = firstLoc || opcode.loc;
110
+ this[opcode.opcode].apply(this, opcode.args);
111
+ }
112
+
113
+ // Flush any trailing content that might be pending.
114
+ this.source.currentLocation = firstLoc;
115
+ this.pushSource('');
116
+
117
+ /* istanbul ignore next */
118
+ if (this.stackSlot || this.inlineStack.length || this.compileStack.length) {
119
+ throw new Exception('Compile completed with content left on stack');
120
+ }
121
+
122
+ if (!this.decorators.isEmpty()) {
123
+ this.useDecorators = true;
124
+
125
+ this.decorators.prepend([
126
+ 'var decorators = container.decorators, ',
127
+ this.lookupPropertyFunctionVarDeclaration(),
128
+ ';\n'
129
+ ]);
130
+ this.decorators.push('return fn;');
131
+
132
+ if (asObject) {
133
+ this.decorators = Function.apply(this, [
134
+ 'fn',
135
+ 'props',
136
+ 'container',
137
+ 'depth0',
138
+ 'data',
139
+ 'blockParams',
140
+ 'depths',
141
+ this.decorators.merge()
142
+ ]);
143
+ } else {
144
+ this.decorators.prepend(
145
+ 'function(fn, props, container, depth0, data, blockParams, depths) {\n'
146
+ );
147
+ this.decorators.push('}\n');
148
+ this.decorators = this.decorators.merge();
149
+ }
150
+ } else {
151
+ this.decorators = undefined;
152
+ }
153
+
154
+ let fn = this.createFunctionContext(asObject);
155
+ if (!this.isChild) {
156
+ let ret = {
157
+ compiler: this.compilerInfo(),
158
+ main: fn
159
+ };
160
+
161
+ if (this.decorators) {
162
+ ret.main_d = this.decorators; // eslint-disable-line camelcase
163
+ ret.useDecorators = true;
164
+ }
165
+
166
+ let { programs, decorators } = this.context;
167
+ for (i = 0, l = programs.length; i < l; i++) {
168
+ if (programs[i]) {
169
+ ret[i] = programs[i];
170
+ if (decorators[i]) {
171
+ ret[i + '_d'] = decorators[i];
172
+ ret.useDecorators = true;
173
+ }
174
+ }
175
+ }
176
+
177
+ if (this.environment.usePartial) {
178
+ ret.usePartial = true;
179
+ }
180
+ if (this.options.data) {
181
+ ret.useData = true;
182
+ }
183
+ if (this.useDepths) {
184
+ ret.useDepths = true;
185
+ }
186
+ if (this.useBlockParams) {
187
+ ret.useBlockParams = true;
188
+ }
189
+ if (this.options.compat) {
190
+ ret.compat = true;
191
+ }
192
+
193
+ if (!asObject) {
194
+ ret.compiler = JSON.stringify(ret.compiler);
195
+
196
+ this.source.currentLocation = { start: { line: 1, column: 0 } };
197
+ ret = this.objectLiteral(ret);
198
+
199
+ if (options.srcName) {
200
+ ret = ret.toStringWithSourceMap({ file: options.destName });
201
+ ret.map = ret.map && ret.map.toString();
202
+ } else {
203
+ ret = ret.toString();
204
+ }
205
+ } else {
206
+ ret.compilerOptions = this.options;
207
+ }
208
+
209
+ return ret;
210
+ } else {
211
+ return fn;
212
+ }
213
+ },
214
+
215
+ preamble: function() {
216
+ // track the last context pushed into place to allow skipping the
217
+ // getContext opcode when it would be a noop
218
+ this.lastContext = 0;
219
+ this.source = new CodeGen(this.options.srcName);
220
+ this.decorators = new CodeGen(this.options.srcName);
221
+ },
222
+
223
+ createFunctionContext: function(asObject) {
224
+ let varDeclarations = '';
225
+
226
+ let locals = this.stackVars.concat(this.registers.list);
227
+ if (locals.length > 0) {
228
+ varDeclarations += ', ' + locals.join(', ');
229
+ }
230
+
231
+ // Generate minimizer alias mappings
232
+ //
233
+ // When using true SourceNodes, this will update all references to the given alias
234
+ // as the source nodes are reused in situ. For the non-source node compilation mode,
235
+ // aliases will not be used, but this case is already being run on the client and
236
+ // we aren't concern about minimizing the template size.
237
+ let aliasCount = 0;
238
+ Object.keys(this.aliases).forEach(alias => {
239
+ let node = this.aliases[alias];
240
+ if (node.children && node.referenceCount > 1) {
241
+ varDeclarations += ', alias' + ++aliasCount + '=' + alias;
242
+ node.children[0] = 'alias' + aliasCount;
243
+ }
244
+ });
245
+
246
+ if (this.lookupPropertyFunctionIsUsed) {
247
+ varDeclarations += ', ' + this.lookupPropertyFunctionVarDeclaration();
248
+ }
249
+
250
+ let params = ['container', 'depth0', 'helpers', 'partials', 'data'];
251
+
252
+ if (this.useBlockParams || this.useDepths) {
253
+ params.push('blockParams');
254
+ }
255
+ if (this.useDepths) {
256
+ params.push('depths');
257
+ }
258
+
259
+ // Perform a second pass over the output to merge content when possible
260
+ let source = this.mergeSource(varDeclarations);
261
+
262
+ if (asObject) {
263
+ params.push(source);
264
+
265
+ return Function.apply(this, params);
266
+ } else {
267
+ return this.source.wrap([
268
+ 'function(',
269
+ params.join(','),
270
+ ') {\n ',
271
+ source,
272
+ '}'
273
+ ]);
274
+ }
275
+ },
276
+ mergeSource: function(varDeclarations) {
277
+ let isSimple = this.environment.isSimple,
278
+ appendOnly = !this.forceBuffer,
279
+ appendFirst,
280
+ sourceSeen,
281
+ bufferStart,
282
+ bufferEnd;
283
+ this.source.each(line => {
284
+ if (line.appendToBuffer) {
285
+ if (bufferStart) {
286
+ line.prepend(' + ');
287
+ } else {
288
+ bufferStart = line;
289
+ }
290
+ bufferEnd = line;
291
+ } else {
292
+ if (bufferStart) {
293
+ if (!sourceSeen) {
294
+ appendFirst = true;
295
+ } else {
296
+ bufferStart.prepend('buffer += ');
297
+ }
298
+ bufferEnd.add(';');
299
+ bufferStart = bufferEnd = undefined;
300
+ }
301
+
302
+ sourceSeen = true;
303
+ if (!isSimple) {
304
+ appendOnly = false;
305
+ }
306
+ }
307
+ });
308
+
309
+ if (appendOnly) {
310
+ if (bufferStart) {
311
+ bufferStart.prepend('return ');
312
+ bufferEnd.add(';');
313
+ } else if (!sourceSeen) {
314
+ this.source.push('return "";');
315
+ }
316
+ } else {
317
+ varDeclarations +=
318
+ ', buffer = ' + (appendFirst ? '' : this.initializeBuffer());
319
+
320
+ if (bufferStart) {
321
+ bufferStart.prepend('return buffer + ');
322
+ bufferEnd.add(';');
323
+ } else {
324
+ this.source.push('return buffer;');
325
+ }
326
+ }
327
+
328
+ if (varDeclarations) {
329
+ this.source.prepend(
330
+ 'var ' + varDeclarations.substring(2) + (appendFirst ? '' : ';\n')
331
+ );
332
+ }
333
+
334
+ return this.source.merge();
335
+ },
336
+
337
+ lookupPropertyFunctionVarDeclaration: function() {
338
+ return `
339
+ lookupProperty = container.lookupProperty || function(parent, propertyName) {
340
+ if (Object.prototype.hasOwnProperty.call(parent, propertyName)) {
341
+ return parent[propertyName];
342
+ }
343
+ return undefined
344
+ }
345
+ `.trim();
346
+ },
347
+
348
+ // [blockValue]
349
+ //
350
+ // On stack, before: hash, inverse, program, value
351
+ // On stack, after: return value of blockHelperMissing
352
+ //
353
+ // The purpose of this opcode is to take a block of the form
354
+ // `{{#this.foo}}...{{/this.foo}}`, resolve the value of `foo`, and
355
+ // replace it on the stack with the result of properly
356
+ // invoking blockHelperMissing.
357
+ blockValue: function(name) {
358
+ let blockHelperMissing = this.aliasable(
359
+ 'container.hooks.blockHelperMissing'
360
+ ),
361
+ params = [this.contextName(0)];
362
+ this.setupHelperArgs(name, 0, params);
363
+
364
+ let blockName = this.popStack();
365
+ params.splice(1, 0, blockName);
366
+
367
+ this.push(this.source.functionCall(blockHelperMissing, 'call', params));
368
+ },
369
+
370
+ // [ambiguousBlockValue]
371
+ //
372
+ // On stack, before: hash, inverse, program, value
373
+ // Compiler value, before: lastHelper=value of last found helper, if any
374
+ // On stack, after, if no lastHelper: same as [blockValue]
375
+ // On stack, after, if lastHelper: value
376
+ ambiguousBlockValue: function() {
377
+ // We're being a bit cheeky and reusing the options value from the prior exec
378
+ let blockHelperMissing = this.aliasable(
379
+ 'container.hooks.blockHelperMissing'
380
+ ),
381
+ params = [this.contextName(0)];
382
+ this.setupHelperArgs('', 0, params, true);
383
+
384
+ this.flushInline();
385
+
386
+ let current = this.topStack();
387
+ params.splice(1, 0, current);
388
+
389
+ this.pushSource([
390
+ 'if (!',
391
+ this.lastHelper,
392
+ ') { ',
393
+ current,
394
+ ' = ',
395
+ this.source.functionCall(blockHelperMissing, 'call', params),
396
+ '}'
397
+ ]);
398
+ },
399
+
400
+ // [appendContent]
401
+ //
402
+ // On stack, before: ...
403
+ // On stack, after: ...
404
+ //
405
+ // Appends the string value of `content` to the current buffer
406
+ appendContent: function(content) {
407
+ if (this.pendingContent) {
408
+ content = this.pendingContent + content;
409
+ } else {
410
+ this.pendingLocation = this.source.currentLocation;
411
+ }
412
+
413
+ this.pendingContent = content;
414
+ },
415
+
416
+ // [append]
417
+ //
418
+ // On stack, before: value, ...
419
+ // On stack, after: ...
420
+ //
421
+ // Coerces `value` to a String and appends it to the current buffer.
422
+ //
423
+ // If `value` is truthy, or 0, it is coerced into a string and appended
424
+ // Otherwise, the empty string is appended
425
+ append: function() {
426
+ if (this.isInline()) {
427
+ this.replaceStack(current => [' != null ? ', current, ' : ""']);
428
+
429
+ this.pushSource(this.appendToBuffer(this.popStack()));
430
+ } else {
431
+ let local = this.popStack();
432
+ this.pushSource([
433
+ 'if (',
434
+ local,
435
+ ' != null) { ',
436
+ this.appendToBuffer(local, undefined, true),
437
+ ' }'
438
+ ]);
439
+ if (this.environment.isSimple) {
440
+ this.pushSource([
441
+ 'else { ',
442
+ this.appendToBuffer("''", undefined, true),
443
+ ' }'
444
+ ]);
445
+ }
446
+ }
447
+ },
448
+
449
+ // [appendEscaped]
450
+ //
451
+ // On stack, before: value, ...
452
+ // On stack, after: ...
453
+ //
454
+ // Escape `value` and append it to the buffer
455
+ appendEscaped: function() {
456
+ this.pushSource(
457
+ this.appendToBuffer([
458
+ this.aliasable('container.escapeExpression'),
459
+ '(',
460
+ this.popStack(),
461
+ ')'
462
+ ])
463
+ );
464
+ },
465
+
466
+ // [getContext]
467
+ //
468
+ // On stack, before: ...
469
+ // On stack, after: ...
470
+ // Compiler value, after: lastContext=depth
471
+ //
472
+ // Set the value of the `lastContext` compiler value to the depth
473
+ getContext: function(depth) {
474
+ this.lastContext = depth;
475
+ },
476
+
477
+ // [pushContext]
478
+ //
479
+ // On stack, before: ...
480
+ // On stack, after: currentContext, ...
481
+ //
482
+ // Pushes the value of the current context onto the stack.
483
+ pushContext: function() {
484
+ this.pushStackLiteral(this.contextName(this.lastContext));
485
+ },
486
+
487
+ // [lookupOnContext]
488
+ //
489
+ // On stack, before: ...
490
+ // On stack, after: currentContext[name], ...
491
+ //
492
+ // Looks up the value of `name` on the current context and pushes
493
+ // it onto the stack.
494
+ lookupOnContext: function(parts, falsy, strict, scoped) {
495
+ let i = 0;
496
+
497
+ if (!scoped && this.options.compat && !this.lastContext) {
498
+ // The depthed query is expected to handle the undefined logic for the root level that
499
+ // is implemented below, so we evaluate that directly in compat mode
500
+ this.push(this.depthedLookup(parts[i++]));
501
+ } else {
502
+ this.pushContext();
503
+ }
504
+
505
+ this.resolvePath('context', parts, i, falsy, strict);
506
+ },
507
+
508
+ // [lookupBlockParam]
509
+ //
510
+ // On stack, before: ...
511
+ // On stack, after: blockParam[name], ...
512
+ //
513
+ // Looks up the value of `parts` on the given block param and pushes
514
+ // it onto the stack.
515
+ lookupBlockParam: function(blockParamId, parts) {
516
+ this.useBlockParams = true;
517
+
518
+ this.push(['blockParams[', blockParamId[0], '][', blockParamId[1], ']']);
519
+ this.resolvePath('context', parts, 1);
520
+ },
521
+
522
+ // [lookupData]
523
+ //
524
+ // On stack, before: ...
525
+ // On stack, after: data, ...
526
+ //
527
+ // Push the data lookup operator
528
+ lookupData: function(depth, parts, strict) {
529
+ if (!depth) {
530
+ this.pushStackLiteral('data');
531
+ } else {
532
+ this.pushStackLiteral('container.data(data, ' + depth + ')');
533
+ }
534
+
535
+ this.resolvePath('data', parts, 0, true, strict);
536
+ },
537
+
538
+ resolvePath: function(type, parts, i, falsy, strict) {
539
+ if (this.options.strict || this.options.assumeObjects) {
540
+ this.push(
541
+ strictLookup(this.options.strict && strict, this, parts, i, type)
542
+ );
543
+ return;
544
+ }
545
+
546
+ let len = parts.length;
547
+ for (; i < len; i++) {
548
+ /* eslint-disable no-loop-func */
549
+ this.replaceStack(current => {
550
+ let lookup = this.nameLookup(current, parts[i], type);
551
+ // We want to ensure that zero and false are handled properly if the context (falsy flag)
552
+ // needs to have the special handling for these values.
553
+ if (!falsy) {
554
+ return [' != null ? ', lookup, ' : ', current];
555
+ } else {
556
+ // Otherwise we can use generic falsy handling
557
+ return [' && ', lookup];
558
+ }
559
+ });
560
+ /* eslint-enable no-loop-func */
561
+ }
562
+ },
563
+
564
+ // [resolvePossibleLambda]
565
+ //
566
+ // On stack, before: value, ...
567
+ // On stack, after: resolved value, ...
568
+ //
569
+ // If the `value` is a lambda, replace it on the stack by
570
+ // the return value of the lambda
571
+ resolvePossibleLambda: function() {
572
+ this.push([
573
+ this.aliasable('container.lambda'),
574
+ '(',
575
+ this.popStack(),
576
+ ', ',
577
+ this.contextName(0),
578
+ ')'
579
+ ]);
580
+ },
581
+
582
+ // [pushStringParam]
583
+ //
584
+ // On stack, before: ...
585
+ // On stack, after: string, currentContext, ...
586
+ //
587
+ // This opcode is designed for use in string mode, which
588
+ // provides the string value of a parameter along with its
589
+ // depth rather than resolving it immediately.
590
+ pushStringParam: function(string, type) {
591
+ this.pushContext();
592
+ this.pushString(type);
593
+
594
+ // If it's a subexpression, the string result
595
+ // will be pushed after this opcode.
596
+ if (type !== 'SubExpression') {
597
+ if (typeof string === 'string') {
598
+ this.pushString(string);
599
+ } else {
600
+ this.pushStackLiteral(string);
601
+ }
602
+ }
603
+ },
604
+
605
+ emptyHash: function(omitEmpty) {
606
+ if (this.trackIds) {
607
+ this.push('{}'); // hashIds
608
+ }
609
+ if (this.stringParams) {
610
+ this.push('{}'); // hashContexts
611
+ this.push('{}'); // hashTypes
612
+ }
613
+ this.pushStackLiteral(omitEmpty ? 'undefined' : '{}');
614
+ },
615
+ pushHash: function() {
616
+ if (this.hash) {
617
+ this.hashes.push(this.hash);
618
+ }
619
+ this.hash = { values: {}, types: [], contexts: [], ids: [] };
620
+ },
621
+ popHash: function() {
622
+ let hash = this.hash;
623
+ this.hash = this.hashes.pop();
624
+
625
+ if (this.trackIds) {
626
+ this.push(this.objectLiteral(hash.ids));
627
+ }
628
+ if (this.stringParams) {
629
+ this.push(this.objectLiteral(hash.contexts));
630
+ this.push(this.objectLiteral(hash.types));
631
+ }
632
+
633
+ this.push(this.objectLiteral(hash.values));
634
+ },
635
+
636
+ // [pushString]
637
+ //
638
+ // On stack, before: ...
639
+ // On stack, after: quotedString(string), ...
640
+ //
641
+ // Push a quoted version of `string` onto the stack
642
+ pushString: function(string) {
643
+ this.pushStackLiteral(this.quotedString(string));
644
+ },
645
+
646
+ // [pushLiteral]
647
+ //
648
+ // On stack, before: ...
649
+ // On stack, after: value, ...
650
+ //
651
+ // Pushes a value onto the stack. This operation prevents
652
+ // the compiler from creating a temporary variable to hold
653
+ // it.
654
+ pushLiteral: function(value) {
655
+ this.pushStackLiteral(value);
656
+ },
657
+
658
+ // [pushProgram]
659
+ //
660
+ // On stack, before: ...
661
+ // On stack, after: program(guid), ...
662
+ //
663
+ // Push a program expression onto the stack. This takes
664
+ // a compile-time guid and converts it into a runtime-accessible
665
+ // expression.
666
+ pushProgram: function(guid) {
667
+ if (guid != null) {
668
+ this.pushStackLiteral(this.programExpression(guid));
669
+ } else {
670
+ this.pushStackLiteral(null);
671
+ }
672
+ },
673
+
674
+ // [registerDecorator]
675
+ //
676
+ // On stack, before: hash, program, params..., ...
677
+ // On stack, after: ...
678
+ //
679
+ // Pops off the decorator's parameters, invokes the decorator,
680
+ // and inserts the decorator into the decorators list.
681
+ registerDecorator(paramSize, name) {
682
+ let foundDecorator = this.nameLookup('decorators', name, 'decorator'),
683
+ options = this.setupHelperArgs(name, paramSize);
684
+
685
+ this.decorators.push([
686
+ 'fn = ',
687
+ this.decorators.functionCall(foundDecorator, '', [
688
+ 'fn',
689
+ 'props',
690
+ 'container',
691
+ options
692
+ ]),
693
+ ' || fn;'
694
+ ]);
695
+ },
696
+
697
+ // [invokeHelper]
698
+ //
699
+ // On stack, before: hash, inverse, program, params..., ...
700
+ // On stack, after: result of helper invocation
701
+ //
702
+ // Pops off the helper's parameters, invokes the helper,
703
+ // and pushes the helper's return value onto the stack.
704
+ //
705
+ // If the helper is not found, `helperMissing` is called.
706
+ invokeHelper: function(paramSize, name, isSimple) {
707
+ let nonHelper = this.popStack(),
708
+ helper = this.setupHelper(paramSize, name);
709
+
710
+ let possibleFunctionCalls = [];
711
+
712
+ if (isSimple) {
713
+ // direct call to helper
714
+ possibleFunctionCalls.push(helper.name);
715
+ }
716
+ // call a function from the input object
717
+ possibleFunctionCalls.push(nonHelper);
718
+ if (!this.options.strict) {
719
+ possibleFunctionCalls.push(
720
+ this.aliasable('container.hooks.helperMissing')
721
+ );
722
+ }
723
+
724
+ let functionLookupCode = [
725
+ '(',
726
+ this.itemsSeparatedBy(possibleFunctionCalls, '||'),
727
+ ')'
728
+ ];
729
+ let functionCall = this.source.functionCall(
730
+ functionLookupCode,
731
+ 'call',
732
+ helper.callParams
733
+ );
734
+ this.push(functionCall);
735
+ },
736
+
737
+ itemsSeparatedBy: function(items, separator) {
738
+ let result = [];
739
+ result.push(items[0]);
740
+ for (let i = 1; i < items.length; i++) {
741
+ result.push(separator, items[i]);
742
+ }
743
+ return result;
744
+ },
745
+ // [invokeKnownHelper]
746
+ //
747
+ // On stack, before: hash, inverse, program, params..., ...
748
+ // On stack, after: result of helper invocation
749
+ //
750
+ // This operation is used when the helper is known to exist,
751
+ // so a `helperMissing` fallback is not required.
752
+ invokeKnownHelper: function(paramSize, name) {
753
+ let helper = this.setupHelper(paramSize, name);
754
+ this.push(this.source.functionCall(helper.name, 'call', helper.callParams));
755
+ },
756
+
757
+ // [invokeAmbiguous]
758
+ //
759
+ // On stack, before: hash, inverse, program, params..., ...
760
+ // On stack, after: result of disambiguation
761
+ //
762
+ // This operation is used when an expression like `{{foo}}`
763
+ // is provided, but we don't know at compile-time whether it
764
+ // is a helper or a path.
765
+ //
766
+ // This operation emits more code than the other options,
767
+ // and can be avoided by passing the `knownHelpers` and
768
+ // `knownHelpersOnly` flags at compile-time.
769
+ invokeAmbiguous: function(name, helperCall) {
770
+ this.useRegister('helper');
771
+
772
+ let nonHelper = this.popStack();
773
+
774
+ this.emptyHash();
775
+ let helper = this.setupHelper(0, name, helperCall);
776
+
777
+ let helperName = (this.lastHelper = this.nameLookup(
778
+ 'helpers',
779
+ name,
780
+ 'helper'
781
+ ));
782
+
783
+ let lookup = ['(', '(helper = ', helperName, ' || ', nonHelper, ')'];
784
+ if (!this.options.strict) {
785
+ lookup[0] = '(helper = ';
786
+ lookup.push(
787
+ ' != null ? helper : ',
788
+ this.aliasable('container.hooks.helperMissing')
789
+ );
790
+ }
791
+
792
+ this.push([
793
+ '(',
794
+ lookup,
795
+ helper.paramsInit ? ['),(', helper.paramsInit] : [],
796
+ '),',
797
+ '(typeof helper === ',
798
+ this.aliasable('"function"'),
799
+ ' ? ',
800
+ this.source.functionCall('helper', 'call', helper.callParams),
801
+ ' : helper))'
802
+ ]);
803
+ },
804
+
805
+ // [invokePartial]
806
+ //
807
+ // On stack, before: context, ...
808
+ // On stack after: result of partial invocation
809
+ //
810
+ // This operation pops off a context, invokes a partial with that context,
811
+ // and pushes the result of the invocation back.
812
+ invokePartial: function(isDynamic, name, indent) {
813
+ let params = [],
814
+ options = this.setupParams(name, 1, params);
815
+
816
+ if (isDynamic) {
817
+ name = this.popStack();
818
+ delete options.name;
819
+ }
820
+
821
+ if (indent) {
822
+ options.indent = JSON.stringify(indent);
823
+ }
824
+ options.helpers = 'helpers';
825
+ options.partials = 'partials';
826
+ options.decorators = 'container.decorators';
827
+
828
+ if (!isDynamic) {
829
+ params.unshift(this.nameLookup('partials', name, 'partial'));
830
+ } else {
831
+ params.unshift(name);
832
+ }
833
+
834
+ if (this.options.compat) {
835
+ options.depths = 'depths';
836
+ }
837
+ options = this.objectLiteral(options);
838
+ params.push(options);
839
+
840
+ this.push(this.source.functionCall('container.invokePartial', '', params));
841
+ },
842
+
843
+ // [assignToHash]
844
+ //
845
+ // On stack, before: value, ..., hash, ...
846
+ // On stack, after: ..., hash, ...
847
+ //
848
+ // Pops a value off the stack and assigns it to the current hash
849
+ assignToHash: function(key) {
850
+ let value = this.popStack(),
851
+ context,
852
+ type,
853
+ id;
854
+
855
+ if (this.trackIds) {
856
+ id = this.popStack();
857
+ }
858
+ if (this.stringParams) {
859
+ type = this.popStack();
860
+ context = this.popStack();
861
+ }
862
+
863
+ let hash = this.hash;
864
+ if (context) {
865
+ hash.contexts[key] = context;
866
+ }
867
+ if (type) {
868
+ hash.types[key] = type;
869
+ }
870
+ if (id) {
871
+ hash.ids[key] = id;
872
+ }
873
+ hash.values[key] = value;
874
+ },
875
+
876
+ pushId: function(type, name, child) {
877
+ if (type === 'BlockParam') {
878
+ this.pushStackLiteral(
879
+ 'blockParams[' +
880
+ name[0] +
881
+ '].path[' +
882
+ name[1] +
883
+ ']' +
884
+ (child ? ' + ' + JSON.stringify('.' + child) : '')
885
+ );
886
+ } else if (type === 'PathExpression') {
887
+ this.pushString(name);
888
+ } else if (type === 'SubExpression') {
889
+ this.pushStackLiteral('true');
890
+ } else {
891
+ this.pushStackLiteral('null');
892
+ }
893
+ },
894
+
895
+ // HELPERS
896
+
897
+ compiler: JavaScriptCompiler,
898
+
899
+ compileChildren: function(environment, options) {
900
+ let children = environment.children,
901
+ child,
902
+ compiler;
903
+
904
+ for (let i = 0, l = children.length; i < l; i++) {
905
+ child = children[i];
906
+ compiler = new this.compiler(); // eslint-disable-line new-cap
907
+
908
+ let existing = this.matchExistingProgram(child);
909
+
910
+ if (existing == null) {
911
+ this.context.programs.push(''); // Placeholder to prevent name conflicts for nested children
912
+ let index = this.context.programs.length;
913
+ child.index = index;
914
+ child.name = 'program' + index;
915
+ this.context.programs[index] = compiler.compile(
916
+ child,
917
+ options,
918
+ this.context,
919
+ !this.precompile
920
+ );
921
+ this.context.decorators[index] = compiler.decorators;
922
+ this.context.environments[index] = child;
923
+
924
+ this.useDepths = this.useDepths || compiler.useDepths;
925
+ this.useBlockParams = this.useBlockParams || compiler.useBlockParams;
926
+ child.useDepths = this.useDepths;
927
+ child.useBlockParams = this.useBlockParams;
928
+ } else {
929
+ child.index = existing.index;
930
+ child.name = 'program' + existing.index;
931
+
932
+ this.useDepths = this.useDepths || existing.useDepths;
933
+ this.useBlockParams = this.useBlockParams || existing.useBlockParams;
934
+ }
935
+ }
936
+ },
937
+ matchExistingProgram: function(child) {
938
+ for (let i = 0, len = this.context.environments.length; i < len; i++) {
939
+ let environment = this.context.environments[i];
940
+ if (environment && environment.equals(child)) {
941
+ return environment;
942
+ }
943
+ }
944
+ },
945
+
946
+ programExpression: function(guid) {
947
+ let child = this.environment.children[guid],
948
+ programParams = [child.index, 'data', child.blockParams];
949
+
950
+ if (this.useBlockParams || this.useDepths) {
951
+ programParams.push('blockParams');
952
+ }
953
+ if (this.useDepths) {
954
+ programParams.push('depths');
955
+ }
956
+
957
+ return 'container.program(' + programParams.join(', ') + ')';
958
+ },
959
+
960
+ useRegister: function(name) {
961
+ if (!this.registers[name]) {
962
+ this.registers[name] = true;
963
+ this.registers.list.push(name);
964
+ }
965
+ },
966
+
967
+ push: function(expr) {
968
+ if (!(expr instanceof Literal)) {
969
+ expr = this.source.wrap(expr);
970
+ }
971
+
972
+ this.inlineStack.push(expr);
973
+ return expr;
974
+ },
975
+
976
+ pushStackLiteral: function(item) {
977
+ this.push(new Literal(item));
978
+ },
979
+
980
+ pushSource: function(source) {
981
+ if (this.pendingContent) {
982
+ this.source.push(
983
+ this.appendToBuffer(
984
+ this.source.quotedString(this.pendingContent),
985
+ this.pendingLocation
986
+ )
987
+ );
988
+ this.pendingContent = undefined;
989
+ }
990
+
991
+ if (source) {
992
+ this.source.push(source);
993
+ }
994
+ },
995
+
996
+ replaceStack: function(callback) {
997
+ let prefix = ['('],
998
+ stack,
999
+ createdStack,
1000
+ usedLiteral;
1001
+
1002
+ /* istanbul ignore next */
1003
+ if (!this.isInline()) {
1004
+ throw new Exception('replaceStack on non-inline');
1005
+ }
1006
+
1007
+ // We want to merge the inline statement into the replacement statement via ','
1008
+ let top = this.popStack(true);
1009
+
1010
+ if (top instanceof Literal) {
1011
+ // Literals do not need to be inlined
1012
+ stack = [top.value];
1013
+ prefix = ['(', stack];
1014
+ usedLiteral = true;
1015
+ } else {
1016
+ // Get or create the current stack name for use by the inline
1017
+ createdStack = true;
1018
+ let name = this.incrStack();
1019
+
1020
+ prefix = ['((', this.push(name), ' = ', top, ')'];
1021
+ stack = this.topStack();
1022
+ }
1023
+
1024
+ let item = callback.call(this, stack);
1025
+
1026
+ if (!usedLiteral) {
1027
+ this.popStack();
1028
+ }
1029
+ if (createdStack) {
1030
+ this.stackSlot--;
1031
+ }
1032
+ this.push(prefix.concat(item, ')'));
1033
+ },
1034
+
1035
+ incrStack: function() {
1036
+ this.stackSlot++;
1037
+ if (this.stackSlot > this.stackVars.length) {
1038
+ this.stackVars.push('stack' + this.stackSlot);
1039
+ }
1040
+ return this.topStackName();
1041
+ },
1042
+ topStackName: function() {
1043
+ return 'stack' + this.stackSlot;
1044
+ },
1045
+ flushInline: function() {
1046
+ let inlineStack = this.inlineStack;
1047
+ this.inlineStack = [];
1048
+ for (let i = 0, len = inlineStack.length; i < len; i++) {
1049
+ let entry = inlineStack[i];
1050
+ /* istanbul ignore if */
1051
+ if (entry instanceof Literal) {
1052
+ this.compileStack.push(entry);
1053
+ } else {
1054
+ let stack = this.incrStack();
1055
+ this.pushSource([stack, ' = ', entry, ';']);
1056
+ this.compileStack.push(stack);
1057
+ }
1058
+ }
1059
+ },
1060
+ isInline: function() {
1061
+ return this.inlineStack.length;
1062
+ },
1063
+
1064
+ popStack: function(wrapped) {
1065
+ let inline = this.isInline(),
1066
+ item = (inline ? this.inlineStack : this.compileStack).pop();
1067
+
1068
+ if (!wrapped && item instanceof Literal) {
1069
+ return item.value;
1070
+ } else {
1071
+ if (!inline) {
1072
+ /* istanbul ignore next */
1073
+ if (!this.stackSlot) {
1074
+ throw new Exception('Invalid stack pop');
1075
+ }
1076
+ this.stackSlot--;
1077
+ }
1078
+ return item;
1079
+ }
1080
+ },
1081
+
1082
+ topStack: function() {
1083
+ let stack = this.isInline() ? this.inlineStack : this.compileStack,
1084
+ item = stack[stack.length - 1];
1085
+
1086
+ /* istanbul ignore if */
1087
+ if (item instanceof Literal) {
1088
+ return item.value;
1089
+ } else {
1090
+ return item;
1091
+ }
1092
+ },
1093
+
1094
+ contextName: function(context) {
1095
+ if (this.useDepths && context) {
1096
+ return 'depths[' + context + ']';
1097
+ } else {
1098
+ return 'depth' + context;
1099
+ }
1100
+ },
1101
+
1102
+ quotedString: function(str) {
1103
+ return this.source.quotedString(str);
1104
+ },
1105
+
1106
+ objectLiteral: function(obj) {
1107
+ return this.source.objectLiteral(obj);
1108
+ },
1109
+
1110
+ aliasable: function(name) {
1111
+ let ret = this.aliases[name];
1112
+ if (ret) {
1113
+ ret.referenceCount++;
1114
+ return ret;
1115
+ }
1116
+
1117
+ ret = this.aliases[name] = this.source.wrap(name);
1118
+ ret.aliasable = true;
1119
+ ret.referenceCount = 1;
1120
+
1121
+ return ret;
1122
+ },
1123
+
1124
+ setupHelper: function(paramSize, name, blockHelper) {
1125
+ let params = [],
1126
+ paramsInit = this.setupHelperArgs(name, paramSize, params, blockHelper);
1127
+ let foundHelper = this.nameLookup('helpers', name, 'helper'),
1128
+ callContext = this.aliasable(
1129
+ `${this.contextName(0)} != null ? ${this.contextName(
1130
+ 0
1131
+ )} : (container.nullContext || {})`
1132
+ );
1133
+
1134
+ return {
1135
+ params: params,
1136
+ paramsInit: paramsInit,
1137
+ name: foundHelper,
1138
+ callParams: [callContext].concat(params)
1139
+ };
1140
+ },
1141
+
1142
+ setupParams: function(helper, paramSize, params) {
1143
+ let options = {},
1144
+ contexts = [],
1145
+ types = [],
1146
+ ids = [],
1147
+ objectArgs = !params,
1148
+ param;
1149
+
1150
+ if (objectArgs) {
1151
+ params = [];
1152
+ }
1153
+
1154
+ options.name = this.quotedString(helper);
1155
+ options.hash = this.popStack();
1156
+
1157
+ if (this.trackIds) {
1158
+ options.hashIds = this.popStack();
1159
+ }
1160
+ if (this.stringParams) {
1161
+ options.hashTypes = this.popStack();
1162
+ options.hashContexts = this.popStack();
1163
+ }
1164
+
1165
+ let inverse = this.popStack(),
1166
+ program = this.popStack();
1167
+
1168
+ // Avoid setting fn and inverse if neither are set. This allows
1169
+ // helpers to do a check for `if (options.fn)`
1170
+ if (program || inverse) {
1171
+ options.fn = program || 'container.noop';
1172
+ options.inverse = inverse || 'container.noop';
1173
+ }
1174
+
1175
+ // The parameters go on to the stack in order (making sure that they are evaluated in order)
1176
+ // so we need to pop them off the stack in reverse order
1177
+ let i = paramSize;
1178
+ while (i--) {
1179
+ param = this.popStack();
1180
+ params[i] = param;
1181
+
1182
+ if (this.trackIds) {
1183
+ ids[i] = this.popStack();
1184
+ }
1185
+ if (this.stringParams) {
1186
+ types[i] = this.popStack();
1187
+ contexts[i] = this.popStack();
1188
+ }
1189
+ }
1190
+
1191
+ if (objectArgs) {
1192
+ options.args = this.source.generateArray(params);
1193
+ }
1194
+
1195
+ if (this.trackIds) {
1196
+ options.ids = this.source.generateArray(ids);
1197
+ }
1198
+ if (this.stringParams) {
1199
+ options.types = this.source.generateArray(types);
1200
+ options.contexts = this.source.generateArray(contexts);
1201
+ }
1202
+
1203
+ if (this.options.data) {
1204
+ options.data = 'data';
1205
+ }
1206
+ if (this.useBlockParams) {
1207
+ options.blockParams = 'blockParams';
1208
+ }
1209
+ return options;
1210
+ },
1211
+
1212
+ setupHelperArgs: function(helper, paramSize, params, useRegister) {
1213
+ let options = this.setupParams(helper, paramSize, params);
1214
+ options.loc = JSON.stringify(this.source.currentLocation);
1215
+ options = this.objectLiteral(options);
1216
+ if (useRegister) {
1217
+ this.useRegister('options');
1218
+ params.push('options');
1219
+ return ['options=', options];
1220
+ } else if (params) {
1221
+ params.push(options);
1222
+ return '';
1223
+ } else {
1224
+ return options;
1225
+ }
1226
+ }
1227
+ };
1228
+
1229
+ (function() {
1230
+ const reservedWords = (
1231
+ 'break else new var' +
1232
+ ' case finally return void' +
1233
+ ' catch for switch while' +
1234
+ ' continue function this with' +
1235
+ ' default if throw' +
1236
+ ' delete in try' +
1237
+ ' do instanceof typeof' +
1238
+ ' abstract enum int short' +
1239
+ ' boolean export interface static' +
1240
+ ' byte extends long super' +
1241
+ ' char final native synchronized' +
1242
+ ' class float package throws' +
1243
+ ' const goto private transient' +
1244
+ ' debugger implements protected volatile' +
1245
+ ' double import public let yield await' +
1246
+ ' null true false'
1247
+ ).split(' ');
1248
+
1249
+ const compilerWords = (JavaScriptCompiler.RESERVED_WORDS = {});
1250
+
1251
+ for (let i = 0, l = reservedWords.length; i < l; i++) {
1252
+ compilerWords[reservedWords[i]] = true;
1253
+ }
1254
+ })();
1255
+
1256
+ /**
1257
+ * @deprecated May be removed in the next major version
1258
+ */
1259
+ JavaScriptCompiler.isValidJavaScriptVariableName = function(name) {
1260
+ return (
1261
+ !JavaScriptCompiler.RESERVED_WORDS[name] &&
1262
+ /^[a-zA-Z_$][0-9a-zA-Z_$]*$/.test(name)
1263
+ );
1264
+ };
1265
+
1266
+ function strictLookup(requireTerminal, compiler, parts, i, type) {
1267
+ let stack = compiler.popStack(),
1268
+ len = parts.length;
1269
+ if (requireTerminal) {
1270
+ len--;
1271
+ }
1272
+
1273
+ for (; i < len; i++) {
1274
+ stack = compiler.nameLookup(stack, parts[i], type);
1275
+ }
1276
+
1277
+ if (requireTerminal) {
1278
+ return [
1279
+ compiler.aliasable('container.strict'),
1280
+ '(',
1281
+ stack,
1282
+ ', ',
1283
+ compiler.quotedString(parts[i]),
1284
+ ', ',
1285
+ JSON.stringify(compiler.source.currentLocation),
1286
+ ' )'
1287
+ ];
1288
+ } else {
1289
+ return stack;
1290
+ }
1291
+ }
1292
+
1293
+ export default JavaScriptCompiler;