From 3f77b82ed00dc1d71976de76bd4f8dfb6e885f2a Mon Sep 17 00:00:00 2001 From: machty Date: Thu, 10 Dec 2015 12:25:20 -0500 Subject: [PATCH 001/154] Remove stringParams and trackIds mode Closes #1145 --- lib/handlebars/compiler/compiler.js | 46 +--- .../compiler/javascript-compiler.js | 106 +------- .../helpers/block-helper-missing.js | 12 +- lib/handlebars/helpers/each.js | 15 +- lib/handlebars/helpers/with.js | 8 +- lib/handlebars/runtime.js | 6 - lib/handlebars/utils.js | 8 - print-script | 1 - spec/string-params.js | 176 ------------- spec/subexpressions.js | 44 ---- spec/track-ids.js | 237 ------------------ 11 files changed, 8 insertions(+), 651 deletions(-) delete mode 100644 spec/string-params.js delete mode 100644 spec/track-ids.js diff --git a/lib/handlebars/compiler/compiler.js b/lib/handlebars/compiler/compiler.js index 987d0d459..9fa9dd88c 100644 --- a/lib/handlebars/compiler/compiler.js +++ b/lib/handlebars/compiler/compiler.js @@ -49,8 +49,6 @@ Compiler.prototype = { this.opcodes = []; this.children = []; this.options = options; - this.stringParams = options.stringParams; - this.trackIds = options.trackIds; options.blockParams = options.blockParams || []; @@ -393,49 +391,7 @@ Compiler.prototype = { }, pushParam: function(val) { - let value = val.value != null ? val.value : val.original || ''; - - if (this.stringParams) { - if (value.replace) { - value = value - .replace(/^(\.?\.\/)*/g, '') - .replace(/\//g, '.'); - } - - if (val.depth) { - this.addDepth(val.depth); - } - this.opcode('getContext', val.depth || 0); - this.opcode('pushStringParam', value, val.type); - - if (val.type === 'SubExpression') { - // SubExpressions get evaluated and passed in - // in string params mode. - this.accept(val); - } - } else { - if (this.trackIds) { - let blockParamIndex; - if (val.parts && !AST.helpers.scopedId(val) && !val.depth) { - blockParamIndex = this.blockParamIndex(val.parts[0]); - } - if (blockParamIndex) { - let blockParamChild = val.parts.slice(1).join('.'); - this.opcode('pushId', 'BlockParam', blockParamIndex, blockParamChild); - } else { - value = val.original || value; - if (value.replace) { - value = value - .replace(/^this(?:\.|$)/, '') - .replace(/^\.\//, '') - .replace(/^\.$/, ''); - } - - this.opcode('pushId', val.type, value); - } - } - this.accept(val); - } + this.accept(val); }, setupFullMustacheParams: function(sexpr, program, inverse, omitEmpty) { diff --git a/lib/handlebars/compiler/javascript-compiler.js b/lib/handlebars/compiler/javascript-compiler.js index 97939df00..1708032c9 100644 --- a/lib/handlebars/compiler/javascript-compiler.js +++ b/lib/handlebars/compiler/javascript-compiler.js @@ -57,8 +57,6 @@ JavaScriptCompiler.prototype = { compile: function(environment, options, context, asObject) { this.environment = environment; this.options = options; - this.stringParams = this.options.stringParams; - this.trackIds = this.options.trackIds; this.precompile = !asObject; this.name = this.environment.name; @@ -498,37 +496,7 @@ JavaScriptCompiler.prototype = { this.push([this.aliasable('container.lambda'), '(', this.popStack(), ', ', this.contextName(0), ')']); }, - // [pushStringParam] - // - // On stack, before: ... - // On stack, after: string, currentContext, ... - // - // This opcode is designed for use in string mode, which - // provides the string value of a parameter along with its - // depth rather than resolving it immediately. - pushStringParam: function(string, type) { - this.pushContext(); - this.pushString(type); - - // If it's a subexpression, the string result - // will be pushed after this opcode. - if (type !== 'SubExpression') { - if (typeof string === 'string') { - this.pushString(string); - } else { - this.pushStackLiteral(string); - } - } - }, - emptyHash: function(omitEmpty) { - if (this.trackIds) { - this.push('{}'); // hashIds - } - if (this.stringParams) { - this.push('{}'); // hashContexts - this.push('{}'); // hashTypes - } this.pushStackLiteral(omitEmpty ? 'undefined' : '{}'); }, pushHash: function() { @@ -541,14 +509,6 @@ JavaScriptCompiler.prototype = { let hash = this.hash; this.hash = this.hashes.pop(); - if (this.trackIds) { - this.push(this.objectLiteral(hash.ids)); - } - if (this.stringParams) { - this.push(this.objectLiteral(hash.contexts)); - this.push(this.objectLiteral(hash.types)); - } - this.push(this.objectLiteral(hash.values)); }, @@ -727,44 +687,7 @@ JavaScriptCompiler.prototype = { // // Pops a value off the stack and assigns it to the current hash assignToHash: function(key) { - let value = this.popStack(), - context, - type, - id; - - if (this.trackIds) { - id = this.popStack(); - } - if (this.stringParams) { - type = this.popStack(); - context = this.popStack(); - } - - let hash = this.hash; - if (context) { - hash.contexts[key] = context; - } - if (type) { - hash.types[key] = type; - } - if (id) { - hash.ids[key] = id; - } - hash.values[key] = value; - }, - - pushId: function(type, name, child) { - if (type === 'BlockParam') { - this.pushStackLiteral( - 'blockParams[' + name[0] + '].path[' + name[1] + ']' - + (child ? ' + ' + JSON.stringify('.' + child) : '')); - } else if (type === 'PathExpression') { - this.pushString(name); - } else if (type === 'SubExpression') { - this.pushStackLiteral('true'); - } else { - this.pushStackLiteral('null'); - } + this.hash.values[key] = this.popStack(); }, // HELPERS @@ -997,9 +920,6 @@ JavaScriptCompiler.prototype = { setupParams: function(helper, paramSize, params) { let options = {}, - contexts = [], - types = [], - ids = [], objectArgs = !params, param; @@ -1010,14 +930,6 @@ JavaScriptCompiler.prototype = { options.name = this.quotedString(helper); options.hash = this.popStack(); - if (this.trackIds) { - options.hashIds = this.popStack(); - } - if (this.stringParams) { - options.hashTypes = this.popStack(); - options.hashContexts = this.popStack(); - } - let inverse = this.popStack(), program = this.popStack(); @@ -1034,28 +946,12 @@ JavaScriptCompiler.prototype = { while (i--) { param = this.popStack(); params[i] = param; - - if (this.trackIds) { - ids[i] = this.popStack(); - } - if (this.stringParams) { - types[i] = this.popStack(); - contexts[i] = this.popStack(); - } } if (objectArgs) { options.args = this.source.generateArray(params); } - if (this.trackIds) { - options.ids = this.source.generateArray(ids); - } - if (this.stringParams) { - options.types = this.source.generateArray(types); - options.contexts = this.source.generateArray(contexts); - } - if (this.options.data) { options.data = 'data'; } diff --git a/lib/handlebars/helpers/block-helper-missing.js b/lib/handlebars/helpers/block-helper-missing.js index 6639ddb9d..e6d162f7f 100644 --- a/lib/handlebars/helpers/block-helper-missing.js +++ b/lib/handlebars/helpers/block-helper-missing.js @@ -1,4 +1,4 @@ -import {appendContextPath, createFrame, isArray} from '../utils'; +import {isArray} from '../utils'; export default function(instance) { instance.registerHelper('blockHelperMissing', function(context, options) { @@ -11,21 +11,11 @@ export default function(instance) { return inverse(this); } else if (isArray(context)) { if (context.length > 0) { - if (options.ids) { - options.ids = [options.name]; - } - return instance.helpers.each(context, options); } else { return inverse(this); } } else { - if (options.data && options.ids) { - let data = createFrame(options.data); - data.contextPath = appendContextPath(options.data.contextPath, options.name); - options = {data: data}; - } - return fn(context, options); } }); diff --git a/lib/handlebars/helpers/each.js b/lib/handlebars/helpers/each.js index fb11903c8..914928d6d 100644 --- a/lib/handlebars/helpers/each.js +++ b/lib/handlebars/helpers/each.js @@ -1,4 +1,4 @@ -import {appendContextPath, blockParams, createFrame, isArray, isFunction} from '../utils'; +import {createFrame, isArray, isFunction} from '../utils'; import Exception from '../exception'; export default function(instance) { @@ -11,12 +11,7 @@ export default function(instance) { inverse = options.inverse, i = 0, ret = '', - data, - contextPath; - - if (options.data && options.ids) { - contextPath = appendContextPath(options.data.contextPath, options.ids[0]) + '.'; - } + data; if (isFunction(context)) { context = context.call(this); } @@ -30,15 +25,11 @@ export default function(instance) { data.index = index; data.first = index === 0; data.last = !!last; - - if (contextPath) { - data.contextPath = contextPath + field; - } } ret = ret + fn(context[field], { data: data, - blockParams: blockParams([context[field], field], [contextPath + field, null]) + blockParams: [context[field], field] }); } diff --git a/lib/handlebars/helpers/with.js b/lib/handlebars/helpers/with.js index 7418cd066..bb352c545 100644 --- a/lib/handlebars/helpers/with.js +++ b/lib/handlebars/helpers/with.js @@ -1,4 +1,4 @@ -import {appendContextPath, blockParams, createFrame, isEmpty, isFunction} from '../utils'; +import {isEmpty, isFunction} from '../utils'; export default function(instance) { instance.registerHelper('with', function(context, options) { @@ -8,14 +8,10 @@ export default function(instance) { if (!isEmpty(context)) { let data = options.data; - if (options.data && options.ids) { - data = createFrame(options.data); - data.contextPath = appendContextPath(options.data.contextPath, options.ids[0]); - } return fn(context, { data: data, - blockParams: blockParams([context], [data && data.contextPath]) + blockParams: [context] }); } else { return options.inverse(this); diff --git a/lib/handlebars/runtime.js b/lib/handlebars/runtime.js index b47d9615d..a7a910336 100644 --- a/lib/handlebars/runtime.js +++ b/lib/handlebars/runtime.js @@ -38,9 +38,6 @@ export function template(templateSpec, env) { function invokePartialWrapper(partial, context, options) { if (options.hash) { context = Utils.extend({}, context, options.hash); - if (options.ids) { - options.ids[0] = true; - } } partial = env.VM.resolvePartial.call(this, partial, context, options); @@ -224,9 +221,6 @@ export function resolvePartial(partial, context, options) { export function invokePartial(partial, context, options) { options.partial = true; - if (options.ids) { - options.data.contextPath = options.ids[0] || options.data.contextPath; - } let partialBlock; if (options.fn && options.fn !== noop) { diff --git a/lib/handlebars/utils.js b/lib/handlebars/utils.js index 2584601ef..9d0839476 100644 --- a/lib/handlebars/utils.js +++ b/lib/handlebars/utils.js @@ -98,11 +98,3 @@ export function createFrame(object) { return frame; } -export function blockParams(params, ids) { - params.path = ids; - return params; -} - -export function appendContextPath(contextPath, id) { - return (contextPath ? contextPath + '.' : '') + id; -} diff --git a/print-script b/print-script index 046b99c17..846469871 100755 --- a/print-script +++ b/print-script @@ -16,7 +16,6 @@ var template = Handlebars.precompile(script, { assumeObjects: true, compat: false, strict: true, - trackIds: true, knownHelpersOnly: false }); diff --git a/spec/string-params.js b/spec/string-params.js deleted file mode 100644 index b76f291f7..000000000 --- a/spec/string-params.js +++ /dev/null @@ -1,176 +0,0 @@ -describe('string params mode', function() { - it('arguments to helpers can be retrieved from options hash in string form', function() { - var template = CompilerContext.compile('{{wycats is.a slave.driver}}', {stringParams: true}); - - var helpers = { - wycats: function(passiveVoice, noun) { - return 'HELP ME MY BOSS ' + passiveVoice + ' ' + noun; - } - }; - - var result = template({}, {helpers: helpers}); - - equals(result, 'HELP ME MY BOSS is.a slave.driver', 'String parameters output'); - }); - - it('when using block form, arguments to helpers can be retrieved from options hash in string form', function() { - var template = CompilerContext.compile('{{#wycats is.a slave.driver}}help :({{/wycats}}', {stringParams: true}); - - var helpers = { - wycats: function(passiveVoice, noun, options) { - return 'HELP ME MY BOSS ' + passiveVoice + ' ' + - noun + ': ' + options.fn(this); - } - }; - - var result = template({}, {helpers: helpers}); - - equals(result, 'HELP ME MY BOSS is.a slave.driver: help :(', 'String parameters output'); - }); - - it('when inside a block in String mode, .. passes the appropriate context in the options hash', function() { - var template = CompilerContext.compile('{{#with dale}}{{tomdale ../need dad.joke}}{{/with}}', {stringParams: true}); - - var helpers = { - tomdale: function(desire, noun, options) { - return 'STOP ME FROM READING HACKER NEWS I ' + - options.contexts[0][desire] + ' ' + noun; - }, - - 'with': function(context, options) { - return options.fn(options.contexts[0][context]); - } - }; - - var result = template({ - dale: {}, - - need: 'need-a' - }, {helpers: helpers}); - - equals(result, 'STOP ME FROM READING HACKER NEWS I need-a dad.joke', 'Proper context variable output'); - }); - - it('information about the types is passed along', function() { - var template = CompilerContext.compile("{{tomdale 'need' dad.joke true false}}", { stringParams: true }); - - var helpers = { - tomdale: function(desire, noun, trueBool, falseBool, options) { - equal(options.types[0], 'StringLiteral', 'the string type is passed'); - equal(options.types[1], 'PathExpression', 'the expression type is passed'); - equal(options.types[2], 'BooleanLiteral', 'the expression type is passed'); - equal(desire, 'need', 'the string form is passed for strings'); - equal(noun, 'dad.joke', 'the string form is passed for expressions'); - equal(trueBool, true, 'raw booleans are passed through'); - equal(falseBool, false, 'raw booleans are passed through'); - return 'Helper called'; - } - }; - - var result = template({}, { helpers: helpers }); - equal(result, 'Helper called'); - }); - - it('hash parameters get type information', function() { - var template = CompilerContext.compile("{{tomdale he.says desire='need' noun=dad.joke bool=true}}", { stringParams: true }); - - var helpers = { - tomdale: function(exclamation, options) { - equal(exclamation, 'he.says'); - equal(options.types[0], 'PathExpression'); - - equal(options.hashTypes.desire, 'StringLiteral'); - equal(options.hashTypes.noun, 'PathExpression'); - equal(options.hashTypes.bool, 'BooleanLiteral'); - equal(options.hash.desire, 'need'); - equal(options.hash.noun, 'dad.joke'); - equal(options.hash.bool, true); - return 'Helper called'; - } - }; - - var result = template({}, { helpers: helpers }); - equal(result, 'Helper called'); - }); - - it('hash parameters get context information', function() { - var template = CompilerContext.compile("{{#with dale}}{{tomdale he.says desire='need' noun=../dad/joke bool=true}}{{/with}}", { stringParams: true }); - - var context = {dale: {}}; - - var helpers = { - tomdale: function(exclamation, options) { - equal(exclamation, 'he.says'); - equal(options.types[0], 'PathExpression'); - - equal(options.contexts.length, 1); - equal(options.hashContexts.noun, context); - equal(options.hash.desire, 'need'); - equal(options.hash.noun, 'dad.joke'); - equal(options.hash.bool, true); - return 'Helper called'; - }, - 'with': function(withContext, options) { - return options.fn(options.contexts[0][withContext]); - } - }; - - var result = template(context, { helpers: helpers }); - equal(result, 'Helper called'); - }); - - it('when inside a block in String mode, .. passes the appropriate context in the options hash to a block helper', function() { - var template = CompilerContext.compile('{{#with dale}}{{#tomdale ../need dad.joke}}wot{{/tomdale}}{{/with}}', {stringParams: true}); - - var helpers = { - tomdale: function(desire, noun, options) { - return 'STOP ME FROM READING HACKER NEWS I ' + - options.contexts[0][desire] + ' ' + noun + ' ' + - options.fn(this); - }, - - 'with': function(context, options) { - return options.fn(options.contexts[0][context]); - } - }; - - var result = template({ - dale: {}, - - need: 'need-a' - }, {helpers: helpers}); - - equals(result, 'STOP ME FROM READING HACKER NEWS I need-a dad.joke wot', 'Proper context variable output'); - }); - - it('with nested block ambiguous', function() { - var template = CompilerContext.compile('{{#with content}}{{#view}}{{firstName}} {{lastName}}{{/view}}{{/with}}', {stringParams: true}); - - var helpers = { - 'with': function() { - return 'WITH'; - }, - view: function() { - return 'VIEW'; - } - }; - - var result = template({}, {helpers: helpers}); - equals(result, 'WITH'); - }); - - it('should handle DATA', function() { - var template = CompilerContext.compile('{{foo @bar}}', { stringParams: true }); - - var helpers = { - foo: function(bar, options) { - equal(bar, '@bar'); - equal(options.types[0], 'PathExpression'); - return 'Foo!'; - } - }; - - var result = template({}, { helpers: helpers }); - equal(result, 'Foo!'); - }); -}); diff --git a/spec/subexpressions.js b/spec/subexpressions.js index dad741e4a..3810eb85f 100644 --- a/spec/subexpressions.js +++ b/spec/subexpressions.js @@ -162,50 +162,6 @@ describe('subexpressions', function() { shouldCompileTo(string, [context, helpers], ''); }); - it('in string params mode,', function() { - var template = CompilerContext.compile('{{snog (blorg foo x=y) yeah a=b}}', {stringParams: true}); - - var helpers = { - snog: function(a, b, options) { - equals(a, 'foo'); - equals(options.types.length, 2, 'string params for outer helper processed correctly'); - equals(options.types[0], 'SubExpression', 'string params for outer helper processed correctly'); - equals(options.types[1], 'PathExpression', 'string params for outer helper processed correctly'); - return a + b; - }, - - blorg: function(a, options) { - equals(options.types.length, 1, 'string params for inner helper processed correctly'); - equals(options.types[0], 'PathExpression', 'string params for inner helper processed correctly'); - return a; - } - }; - - var result = template({ - foo: {}, - yeah: {} - }, {helpers: helpers}); - - equals(result, 'fooyeah'); - }); - - it('as hashes in string params mode', function() { - var template = CompilerContext.compile('{{blog fun=(bork)}}', {stringParams: true}); - - var helpers = { - blog: function(options) { - equals(options.hashTypes.fun, 'SubExpression'); - return 'val is ' + options.hash.fun; - }, - bork: function() { - return 'BORK'; - } - }; - - var result = template({}, {helpers: helpers}); - equals(result, 'val is BORK'); - }); - it('subexpression functions on the context', function() { var string = '{{foo (bar)}}!'; var context = { diff --git a/spec/track-ids.js b/spec/track-ids.js deleted file mode 100644 index 30a46617d..000000000 --- a/spec/track-ids.js +++ /dev/null @@ -1,237 +0,0 @@ -describe('track ids', function() { - var context; - beforeEach(function() { - context = {is: {a: 'foo'}, slave: {driver: 'bar'}}; - }); - - it('should not include anything without the flag', function() { - var template = CompilerContext.compile('{{wycats is.a slave.driver}}'); - - var helpers = { - wycats: function(passiveVoice, noun, options) { - equal(options.ids, undefined); - equal(options.hashIds, undefined); - - return 'success'; - } - }; - - equals(template({}, {helpers: helpers}), 'success'); - }); - it('should include argument ids', function() { - var template = CompilerContext.compile('{{wycats is.a slave.driver}}', {trackIds: true}); - - var helpers = { - wycats: function(passiveVoice, noun, options) { - equal(options.ids[0], 'is.a'); - equal(options.ids[1], 'slave.driver'); - - return 'HELP ME MY BOSS ' + options.ids[0] + ':' + passiveVoice + ' ' + options.ids[1] + ':' + noun; - } - }; - - equals(template(context, {helpers: helpers}), 'HELP ME MY BOSS is.a:foo slave.driver:bar'); - }); - it('should include hash ids', function() { - var template = CompilerContext.compile('{{wycats bat=is.a baz=slave.driver}}', {trackIds: true}); - - var helpers = { - wycats: function(options) { - equal(options.hashIds.bat, 'is.a'); - equal(options.hashIds.baz, 'slave.driver'); - - return 'HELP ME MY BOSS ' + options.hashIds.bat + ':' + options.hash.bat + ' ' + options.hashIds.baz + ':' + options.hash.baz; - } - }; - - equals(template(context, {helpers: helpers}), 'HELP ME MY BOSS is.a:foo slave.driver:bar'); - }); - it('should note ../ and ./ references', function() { - var template = CompilerContext.compile('{{wycats ./is.a ../slave.driver this.is.a this}}', {trackIds: true}); - - var helpers = { - wycats: function(passiveVoice, noun, thiz, thiz2, options) { - equal(options.ids[0], 'is.a'); - equal(options.ids[1], '../slave.driver'); - equal(options.ids[2], 'is.a'); - equal(options.ids[3], ''); - - return 'HELP ME MY BOSS ' + options.ids[0] + ':' + passiveVoice + ' ' + options.ids[1] + ':' + noun; - } - }; - - equals(template(context, {helpers: helpers}), 'HELP ME MY BOSS is.a:foo ../slave.driver:undefined'); - }); - it('should note @data references', function() { - var template = CompilerContext.compile('{{wycats @is.a @slave.driver}}', {trackIds: true}); - - var helpers = { - wycats: function(passiveVoice, noun, options) { - equal(options.ids[0], '@is.a'); - equal(options.ids[1], '@slave.driver'); - - return 'HELP ME MY BOSS ' + options.ids[0] + ':' + passiveVoice + ' ' + options.ids[1] + ':' + noun; - } - }; - - equals(template({}, {helpers: helpers, data: context}), 'HELP ME MY BOSS @is.a:foo @slave.driver:bar'); - }); - - it('should return null for constants', function() { - var template = CompilerContext.compile('{{wycats 1 "foo" key=false}}', {trackIds: true}); - - var helpers = { - wycats: function(passiveVoice, noun, options) { - equal(options.ids[0], null); - equal(options.ids[1], null); - equal(options.hashIds.key, null); - - return 'HELP ME MY BOSS ' + passiveVoice + ' ' + noun + ' ' + options.hash.key; - } - }; - - equals(template(context, {helpers: helpers}), 'HELP ME MY BOSS 1 foo false'); - }); - it('should return true for subexpressions', function() { - var template = CompilerContext.compile('{{wycats (sub)}}', {trackIds: true}); - - var helpers = { - sub: function() { return 1; }, - wycats: function(passiveVoice, options) { - equal(options.ids[0], true); - - return 'HELP ME MY BOSS ' + passiveVoice; - } - }; - - equals(template(context, {helpers: helpers}), 'HELP ME MY BOSS 1'); - }); - - it('should use block param paths', function() { - var template = CompilerContext.compile('{{#doIt as |is|}}{{wycats is.a slave.driver is}}{{/doIt}}', {trackIds: true}); - - var helpers = { - doIt: function(options) { - var blockParams = [this.is]; - blockParams.path = ['zomg']; - return options.fn(this, {blockParams: blockParams}); - }, - wycats: function(passiveVoice, noun, blah, options) { - equal(options.ids[0], 'zomg.a'); - equal(options.ids[1], 'slave.driver'); - equal(options.ids[2], 'zomg'); - - return 'HELP ME MY BOSS ' + options.ids[0] + ':' + passiveVoice + ' ' + options.ids[1] + ':' + noun; - } - }; - - equals(template(context, {helpers: helpers}), 'HELP ME MY BOSS zomg.a:foo slave.driver:bar'); - }); - - describe('builtin helpers', function() { - var helpers = { - blockParams: function(name, options) { - return name + ':' + options.ids[0] + '\n'; - }, - wycats: function(name, options) { - return name + ':' + options.data.contextPath + '\n'; - } - }; - - describe('#each', function() { - it('should track contextPath for arrays', function() { - var template = CompilerContext.compile('{{#each array}}{{wycats name}}{{/each}}', {trackIds: true}); - - equals(template({array: [{name: 'foo'}, {name: 'bar'}]}, {helpers: helpers}), 'foo:array.0\nbar:array.1\n'); - }); - it('should track contextPath for keys', function() { - var template = CompilerContext.compile('{{#each object}}{{wycats name}}{{/each}}', {trackIds: true}); - - equals(template({object: {foo: {name: 'foo'}, bar: {name: 'bar'}}}, {helpers: helpers}), 'foo:object.foo\nbar:object.bar\n'); - }); - it('should handle nesting', function() { - var template = CompilerContext.compile('{{#each .}}{{#each .}}{{wycats name}}{{/each}}{{/each}}', {trackIds: true}); - - equals(template({array: [{name: 'foo'}, {name: 'bar'}]}, {helpers: helpers}), 'foo:.array..0\nbar:.array..1\n'); - }); - it('should handle block params', function() { - var template = CompilerContext.compile('{{#each array as |value|}}{{blockParams value.name}}{{/each}}', {trackIds: true}); - - equals(template({array: [{name: 'foo'}, {name: 'bar'}]}, {helpers: helpers}), 'foo:array.0.name\nbar:array.1.name\n'); - }); - }); - describe('#with', function() { - it('should track contextPath', function() { - var template = CompilerContext.compile('{{#with field}}{{wycats name}}{{/with}}', {trackIds: true}); - - equals(template({field: {name: 'foo'}}, {helpers: helpers}), 'foo:field\n'); - }); - it('should handle nesting', function() { - var template = CompilerContext.compile('{{#with bat}}{{#with field}}{{wycats name}}{{/with}}{{/with}}', {trackIds: true}); - - equals(template({bat: {field: {name: 'foo'}}}, {helpers: helpers}), 'foo:bat.field\n'); - }); - }); - describe('#blockHelperMissing', function() { - it('should track contextPath for arrays', function() { - var template = CompilerContext.compile('{{#field}}{{wycats name}}{{/field}}', {trackIds: true}); - - equals(template({field: [{name: 'foo'}]}, {helpers: helpers}), 'foo:field.0\n'); - }); - it('should track contextPath for keys', function() { - var template = CompilerContext.compile('{{#field}}{{wycats name}}{{/field}}', {trackIds: true}); - - equals(template({field: {name: 'foo'}}, {helpers: helpers}), 'foo:field\n'); - }); - it('should handle nesting', function() { - var template = CompilerContext.compile('{{#bat}}{{#field}}{{wycats name}}{{/field}}{{/bat}}', {trackIds: true}); - - equals(template({bat: {field: {name: 'foo'}}}, {helpers: helpers}), 'foo:bat.field\n'); - }); - }); - }); - - describe('partials', function() { - var helpers = { - blockParams: function(name, options) { - return name + ':' + options.ids[0] + '\n'; - }, - wycats: function(name, options) { - return name + ':' + options.data.contextPath + '\n'; - } - }; - - it('should pass track id for basic partial', function() { - var template = CompilerContext.compile('Dudes: {{#dudes}}{{> dude}}{{/dudes}}', {trackIds: true}), - hash = {dudes: [{name: 'Yehuda', url: 'http://yehuda'}, {name: 'Alan', url: 'http://alan'}]}; - - var partials = { - dude: CompilerContext.compile('{{wycats name}}', {trackIds: true}) - }; - - equals(template(hash, {helpers: helpers, partials: partials}), 'Dudes: Yehuda:dudes.0\nAlan:dudes.1\n'); - }); - - it('should pass track id for context partial', function() { - var template = CompilerContext.compile('Dudes: {{> dude dudes}}', {trackIds: true}), - hash = {dudes: [{name: 'Yehuda', url: 'http://yehuda'}, {name: 'Alan', url: 'http://alan'}]}; - - var partials = { - dude: CompilerContext.compile('{{#each this}}{{wycats name}}{{/each}}', {trackIds: true}) - }; - - equals(template(hash, {helpers: helpers, partials: partials}), 'Dudes: Yehuda:dudes..0\nAlan:dudes..1\n'); - }); - - it('should invalidate context for partials with parameters', function() { - var template = CompilerContext.compile('Dudes: {{#dudes}}{{> dude . bar="foo"}}{{/dudes}}', {trackIds: true}), - hash = {dudes: [{name: 'Yehuda', url: 'http://yehuda'}, {name: 'Alan', url: 'http://alan'}]}; - - var partials = { - dude: CompilerContext.compile('{{wycats name}}', {trackIds: true}) - }; - - equals(template(hash, {helpers: helpers, partials: partials}), 'Dudes: Yehuda:true\nAlan:true\n'); - }); - }); -}); From 63a08890cce3620f3af328163f4313754df76581 Mon Sep 17 00:00:00 2001 From: kpdecker Date: Sat, 12 Dec 2015 15:27:26 -0600 Subject: [PATCH 002/154] Remove semi-documented _setup and _child APIs MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit These were a bad idea to begin with and without the trackIds implementation they don’t make much sense. --- lib/handlebars/compiler/compiler.js | 15 +----------- lib/handlebars/runtime.js | 16 +++---------- spec/runtime.js | 37 ----------------------------- 3 files changed, 4 insertions(+), 64 deletions(-) diff --git a/lib/handlebars/compiler/compiler.js b/lib/handlebars/compiler/compiler.js index 9fa9dd88c..040e99a19 100644 --- a/lib/handlebars/compiler/compiler.js +++ b/lib/handlebars/compiler/compiler.js @@ -461,25 +461,12 @@ export function compile(input, options = {}, env) { } // Template is only compiled on first use and cached after that point. - function ret(context, execOptions) { + return function(context, execOptions) { if (!compiled) { compiled = compileInput(); } return compiled.call(this, context, execOptions); - } - ret._setup = function(setupOptions) { - if (!compiled) { - compiled = compileInput(); - } - return compiled._setup(setupOptions); - }; - ret._child = function(i, data, blockParams, depths) { - if (!compiled) { - compiled = compileInput(); - } - return compiled._child(i, data, blockParams, depths); }; - return ret; } function argEquals(a, b) { diff --git a/lib/handlebars/runtime.js b/lib/handlebars/runtime.js index a7a910336..5c479a83d 100644 --- a/lib/handlebars/runtime.js +++ b/lib/handlebars/runtime.js @@ -129,7 +129,7 @@ export function template(templateSpec, env) { function ret(context, options = {}) { let data = options.data; - ret._setup(options); + _setup(options); if (!options.partial && templateSpec.useData) { data = initData(context, data); } @@ -151,7 +151,7 @@ export function template(templateSpec, env) { } ret.isTop = true; - ret._setup = function(options) { + function _setup(options) { if (!options.partial) { container.helpers = container.merge(options.helpers, env.helpers); @@ -166,18 +166,8 @@ export function template(templateSpec, env) { container.partials = options.partials; container.decorators = options.decorators; } - }; - - ret._child = function(i, data, blockParams, depths) { - if (templateSpec.useBlockParams && !blockParams) { - throw new Exception('must pass block params'); - } - if (templateSpec.useDepths && !depths) { - throw new Exception('must pass parent depths'); - } + } - return wrapProgram(container, i, templateSpec[i], data, 0, blockParams, depths); - }; return ret; } diff --git a/spec/runtime.js b/spec/runtime.js index a4830ad0c..2a8589937 100644 --- a/spec/runtime.js +++ b/spec/runtime.js @@ -32,43 +32,6 @@ describe('runtime', function() { }); }); - describe('#child', function() { - if (!Handlebars.compile) { - return; - } - - it('should throw for depthed methods without depths', function() { - shouldThrow(function() { - var template = Handlebars.compile('{{#foo}}{{../bar}}{{/foo}}'); - // Calling twice to hit the non-compiled case. - template._setup({}); - template._setup({}); - template._child(1); - }, Error, 'must pass parent depths'); - }); - - it('should throw for block param methods without params', function() { - shouldThrow(function() { - var template = Handlebars.compile('{{#foo as |foo|}}{{foo}}{{/foo}}'); - // Calling twice to hit the non-compiled case. - template._setup({}); - template._setup({}); - template._child(1); - }, Error, 'must pass block params'); - }); - it('should expose child template', function() { - var template = Handlebars.compile('{{#foo}}bar{{/foo}}'); - // Calling twice to hit the non-compiled case. - equal(template._child(1)(), 'bar'); - equal(template._child(1)(), 'bar'); - }); - it('should render depthed content', function() { - var template = Handlebars.compile('{{#foo}}{{../bar}}{{/foo}}'); - // Calling twice to hit the non-compiled case. - equal(template._child(1, undefined, [], [{bar: 'baz'}])(), 'baz'); - }); - }); - describe('#noConflict', function() { if (!CompilerContext.browser) { return; From 25458fdc2a3ad179d1eb4c8ae401c7b9bfdfb0d2 Mon Sep 17 00:00:00 2001 From: kpdecker Date: Sat, 12 Dec 2015 15:27:56 -0600 Subject: [PATCH 003/154] Relax depth check for context push Fixes #1135 --- lib/handlebars/runtime.js | 4 ++-- spec/regressions.js | 23 +++++++++++++++++++++++ 2 files changed, 25 insertions(+), 2 deletions(-) diff --git a/lib/handlebars/runtime.js b/lib/handlebars/runtime.js index 5c479a83d..55eb1c1b0 100644 --- a/lib/handlebars/runtime.js +++ b/lib/handlebars/runtime.js @@ -137,7 +137,7 @@ export function template(templateSpec, env) { blockParams = templateSpec.useBlockParams ? [] : undefined; if (templateSpec.useDepths) { if (options.depths) { - depths = context !== options.depths[0] ? [context].concat(options.depths) : options.depths; + depths = context != options.depths[0] ? [context].concat(options.depths) : options.depths; } else { depths = [context]; } @@ -174,7 +174,7 @@ export function template(templateSpec, env) { export function wrapProgram(container, i, fn, data, declaredBlockParams, blockParams, depths) { function prog(context, options = {}) { let currentDepths = depths; - if (depths && context !== depths[0]) { + if (depths && context != depths[0]) { currentDepths = [context].concat(depths); } diff --git a/spec/regressions.js b/spec/regressions.js index 83765a223..9bd00d947 100644 --- a/spec/regressions.js +++ b/spec/regressions.js @@ -247,4 +247,27 @@ describe('Regressions', function() { }; shouldCompileToWithPartials(string, [{}, {}, partials], true, 'Outer'); }); + + it('GH-1135 : Context handling within each iteration', function() { + var obj = {array: [1], name: 'John'}; + var helpers = { + myif: function(conditional, options) { + if (conditional) { + return options.fn(this); + } else { + return options.inverse(this); + } + } + }; + + shouldCompileTo(` + {{#each array}} + 1. IF: {{#if true}}{{../name}}-{{../../name}}-{{../../../name}}{{/if}} + 2. MYIF: {{#myif true}}{{../name}}={{../../name}}={{../../../name}}{{/myif}} + {{/each}} + `, [obj, helpers], ` + 1. IF: John-- + 2. MYIF: John== + `); + }); }); From 8289c0bf3afff120b5fe7e90c08cac18a8166b9c Mon Sep 17 00:00:00 2001 From: kpdecker Date: Sat, 12 Dec 2015 15:34:06 -0600 Subject: [PATCH 004/154] Update build for modern node versions --- .travis.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.travis.yml b/.travis.yml index c6e2c8439..00c8b0013 100644 --- a/.travis.yml +++ b/.travis.yml @@ -13,12 +13,12 @@ env: - secure: Nm4AgSfsgNB21kgKrF9Tl7qVZU8YYREhouQunFracTcZZh2NZ2XH5aHuSiXCj88B13Cr/jGbJKsZ4T3QS3wWYtz6lkyVOx3H3iI+TMtqhD9RM3a7A4O+4vVN8IioB2YjhEu0OKjwgX5gp+0uF+pLEi7Hpj6fupD3AbbL5uYcKg8= matrix: include: - - node_js: '0.12' + - node_js: '5' env: - PUBLISH=true - secure: pLTzghtVll9yGKJI0AaB0uI8GypfWxLTaIB0ZL8//yN3nAEIKMhf/RRilYTsn/rKj2NUa7vt2edYILi3lttOUlCBOwTc9amiRms1W8Lwr/3IdWPeBLvLuH1zNJRm2lBAwU4LBSqaOwhGaxOQr6KHTnWudhNhgOucxpZfvfI/dFw= - secure: yERYCf7AwL11D9uMtacly/THGV8BlzsMmrt+iQVvGA3GaY6QMmfYqf6P6cCH98sH5etd1Y+1e6YrPeMjqI6lyRllT7FptoyOdHulazQe86VQN4sc0EpqMlH088kB7gGjTut9Z+X9ViooT5XEh9WA5jXEI9pXhQJNoIHkWPuwGuY= - - node_js: '4.0.0' + - node_js: '4' cache: directories: - node_modules From 2ea6119a83e6c59ce3b208f95fee604a1648670b Mon Sep 17 00:00:00 2001 From: kpdecker Date: Sat, 12 Dec 2015 16:07:52 -0600 Subject: [PATCH 005/154] Fix throw when creating exception object in Safari https://github.com/jquery/esprima/issues/1290 --- lib/handlebars/exception.js | 18 ++++++++++++++---- 1 file changed, 14 insertions(+), 4 deletions(-) diff --git a/lib/handlebars/exception.js b/lib/handlebars/exception.js index 52499c0ca..24734d475 100644 --- a/lib/handlebars/exception.js +++ b/lib/handlebars/exception.js @@ -12,7 +12,7 @@ function Exception(message, node) { message += ' - ' + line + ':' + column; } - let tmp = Error.prototype.constructor.call(this, message); + let tmp = Error.prototype.constructor.call(this, message, loc && loc.source, line); // Unfortunately errors are not enumerable in Chrome (at least), so `for prop in tmp` doesn't work. for (let idx = 0; idx < errorProps.length; idx++) { @@ -24,9 +24,19 @@ function Exception(message, node) { Error.captureStackTrace(this, Exception); } - if (loc) { - this.lineNumber = line; - this.column = column; + try { + if (loc) { + this.lineNumber = line; + + // Work around issue under safari where we can't directly set the column value + if (Object.defineProperty) { + Object.defineProperty(this, 'column', {value: column}); + } else { + this.column = column; + } + } + } catch (nop) { + /* Ignore if the browser is very particular */ } } From 326734b0f3ab9e7b9431579d449d344919bb6869 Mon Sep 17 00:00:00 2001 From: kpdecker Date: Sat, 12 Dec 2015 16:14:17 -0600 Subject: [PATCH 006/154] Exclude coverage check in exception conditional --- lib/handlebars/exception.js | 1 + 1 file changed, 1 insertion(+) diff --git a/lib/handlebars/exception.js b/lib/handlebars/exception.js index 24734d475..af675d9cb 100644 --- a/lib/handlebars/exception.js +++ b/lib/handlebars/exception.js @@ -29,6 +29,7 @@ function Exception(message, node) { this.lineNumber = line; // Work around issue under safari where we can't directly set the column value + /* istanbul ignore next */ if (Object.defineProperty) { Object.defineProperty(this, 'column', {value: column}); } else { From 871c32a6f9106137061a49e731fc267933f6b79b Mon Sep 17 00:00:00 2001 From: kpdecker Date: Sat, 12 Dec 2015 16:26:48 -0600 Subject: [PATCH 007/154] Update target browser test versions --- Gruntfile.js | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/Gruntfile.js b/Gruntfile.js index fd76518a6..97cfff06e 100644 --- a/Gruntfile.js +++ b/Gruntfile.js @@ -166,11 +166,10 @@ module.exports = function(grunt) { browsers: [ {browserName: 'chrome'}, {browserName: 'firefox', platform: 'Linux'}, - {browserName: 'safari', version: 7, platform: 'OS X 10.9'}, - {browserName: 'safari', version: 6, platform: 'OS X 10.8'}, + {browserName: 'safari', version: 9, platform: 'OS X 10.11'}, + {browserName: 'safari', version: 8, platform: 'OS X 10.10'}, {browserName: 'internet explorer', version: 11, platform: 'Windows 8.1'}, - {browserName: 'internet explorer', version: 10, platform: 'Windows 8'}, - {browserName: 'internet explorer', version: 9, platform: 'Windows 7'} + {browserName: 'internet explorer', version: 10, platform: 'Windows 8'} ] } }, From a6121cae797161f74bdd5a25e0c56379992557d7 Mon Sep 17 00:00:00 2001 From: kpdecker Date: Sat, 12 Dec 2015 17:09:24 -0600 Subject: [PATCH 008/154] Avoid error in older browsers in test The tests are run through the transpiler and just reverting the user of template literal is easier than adding transpiler to the test stack. --- spec/regressions.js | 16 +++++++--------- 1 file changed, 7 insertions(+), 9 deletions(-) diff --git a/spec/regressions.js b/spec/regressions.js index 9bd00d947..a1eec2f10 100644 --- a/spec/regressions.js +++ b/spec/regressions.js @@ -260,14 +260,12 @@ describe('Regressions', function() { } }; - shouldCompileTo(` - {{#each array}} - 1. IF: {{#if true}}{{../name}}-{{../../name}}-{{../../../name}}{{/if}} - 2. MYIF: {{#myif true}}{{../name}}={{../../name}}={{../../../name}}{{/myif}} - {{/each}} - `, [obj, helpers], ` - 1. IF: John-- - 2. MYIF: John== - `); + shouldCompileTo( + '{{#each array}}\n' + + ' 1. IF: {{#if true}}{{../name}}-{{../../name}}-{{../../../name}}{{/if}}\n' + + ' 2. MYIF: {{#myif true}}{{../name}}={{../../name}}={{../../../name}}{{/myif}}\n' + + '{{/each}}', [obj, helpers], + ' 1. IF: John--\n' + + ' 2. MYIF: John==\n'); }); }); From cc0b239aafefdef0342334b90f3c9b3ac6b19cea Mon Sep 17 00:00:00 2001 From: Ryan Lewis Date: Sun, 13 Dec 2015 20:40:50 -0800 Subject: [PATCH 009/154] Adding documentation for running tests --- README.markdown | 19 +++++++++++++++++++ spec/mustache | 2 +- 2 files changed, 20 insertions(+), 1 deletion(-) diff --git a/README.markdown b/README.markdown index 904b9e0c6..65f4c77d5 100644 --- a/README.markdown +++ b/README.markdown @@ -114,6 +114,25 @@ Known Issues See [FAQ.md](https://github.com/wycats/handlebars.js/blob/master/FAQ.md) for known issues and common pitfalls. +Running Tests +--------- + +To run tests locally, first install all dependencies. +``` +npm install +``` + +Clone the mustache specs into the spec/mustache folder. +``` +cd spec +rm -r mustache +git clone https://github.com/mustache/spec.git mustache +``` + +From the root directory, run the tests. +``` +npm test +``` Handlebars in the Wild ---------------------- diff --git a/spec/mustache b/spec/mustache index 72233f3ff..83b072161 160000 --- a/spec/mustache +++ b/spec/mustache @@ -1 +1 @@ -Subproject commit 72233f3ffda9e33915fd3022d0a9ebbcce265acd +Subproject commit 83b0721610a4e11832e83df19c73ace3289972b9 From eb1ec52b453c810e9cec3131d47e4d3d1856b387 Mon Sep 17 00:00:00 2001 From: Ryan Lewis Date: Sun, 13 Dec 2015 21:42:54 -0800 Subject: [PATCH 010/154] moving test documentation to contributing.md --- CONTRIBUTING.md | 19 +++++++++++++++++++ README.markdown | 19 ------------------- 2 files changed, 19 insertions(+), 19 deletions(-) diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 79db3ba81..08147607d 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -42,6 +42,25 @@ The `grunt dev` implements watching for tests and allows for in browser testing If you notice any problems, please report them to the GitHub issue tracker at [http://github.com/wycats/handlebars.js/issues](http://github.com/wycats/handlebars.js/issues). +##Running Tests + +To run tests locally, first install all dependencies. +```sh +npm install +``` + +Clone the mustache specs into the spec/mustache folder. +```sh +cd spec +rm -r mustache +git clone https://github.com/mustache/spec.git mustache +``` + +From the root directory, run the tests. +```sh +npm test +``` + ## Ember testing The current ember distribution should be tested as part of the handlebars release process. This requires building the `handlebars-source` gem locally and then executing the ember test script. diff --git a/README.markdown b/README.markdown index 65f4c77d5..904b9e0c6 100644 --- a/README.markdown +++ b/README.markdown @@ -114,25 +114,6 @@ Known Issues See [FAQ.md](https://github.com/wycats/handlebars.js/blob/master/FAQ.md) for known issues and common pitfalls. -Running Tests ---------- - -To run tests locally, first install all dependencies. -``` -npm install -``` - -Clone the mustache specs into the spec/mustache folder. -``` -cd spec -rm -r mustache -git clone https://github.com/mustache/spec.git mustache -``` - -From the root directory, run the tests. -``` -npm test -``` Handlebars in the Wild ---------------------- From 63fdb92472cf7f6f8a576baa31f4aa2c5d1b643c Mon Sep 17 00:00:00 2001 From: kpdecker Date: Mon, 14 Dec 2015 02:19:03 -0600 Subject: [PATCH 011/154] Drop extra Error params MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This was causing a difficult to diagnose failure under IE and doesn’t give us enough value to justify the change. --- lib/handlebars/exception.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/handlebars/exception.js b/lib/handlebars/exception.js index af675d9cb..08ae531aa 100644 --- a/lib/handlebars/exception.js +++ b/lib/handlebars/exception.js @@ -12,7 +12,7 @@ function Exception(message, node) { message += ' - ' + line + ':' + column; } - let tmp = Error.prototype.constructor.call(this, message, loc && loc.source, line); + let tmp = Error.prototype.constructor.call(this, message); // Unfortunately errors are not enumerable in Chrome (at least), so `for prop in tmp` doesn't work. for (let idx = 0; idx < errorProps.length; idx++) { From 8517352e209569f5a373d7a61ef4a673582d9616 Mon Sep 17 00:00:00 2001 From: kpdecker Date: Mon, 14 Dec 2015 02:22:30 -0600 Subject: [PATCH 012/154] Remove amd files from the build Users can utilize the UMD library if they are still using require.js and if they need to have specific modules, they can consume the cjs or es6 modules via webpack or similar. Fix for #1096 --- FAQ.md | 10 +--- Gruntfile.js | 47 ++-------------- package.json | 3 +- spec/amd-runtime.html | 105 ----------------------------------- spec/amd.html | 125 ------------------------------------------ 5 files changed, 7 insertions(+), 283 deletions(-) delete mode 100644 spec/amd-runtime.html delete mode 100644 spec/amd.html diff --git a/FAQ.md b/FAQ.md index 108e839af..49462856d 100644 --- a/FAQ.md +++ b/FAQ.md @@ -47,14 +47,6 @@ Should these match, please file an issue with us, per our [issue filing guidelines](https://github.com/wycats/handlebars.js/blob/master/CONTRIBUTING.md#reporting-issues). -1. Why doesn't IE like the `default` name in the AMD module? - - Some browsers such as particular versions of IE treat `default` as a reserved word in JavaScript source files. To safely use this you need to reference this via the `Handlebars['default']` lookup method. This is an unfortunate side effect of the shims necessary to backport the Handlebars ES6 code to all current browsers. - 1. How do I load the runtime library when using AMD? - There are two options for loading under AMD environments. The first is to use the `handlebars.runtime.amd.js` file. This may require a [path mapping](https://github.com/wycats/handlebars.js/blob/master/spec/amd-runtime.html#L31) as well as access via the `default` field. - - The other option is to load the `handlebars.runtime.js` UMD build, which might not require path configuration and exposes the library as both the module root and the `default` field for compatibility. - - If not using ES6 transpilers or accessing submodules in the build the former option should be sufficient for most use cases. + The `handlebars.runtime.js` file includes a UMD build, which exposes the library as both the module root and the `default` field for compatibility. diff --git a/Gruntfile.js b/Gruntfile.js index 97cfff06e..73c521544 100644 --- a/Gruntfile.js +++ b/Gruntfile.js @@ -44,23 +44,6 @@ module.exports = function(grunt) { }, babel: { - options: { - sourceMaps: 'inline', - loose: ['es6.modules'], - auxiliaryCommentBefore: 'istanbul ignore next' - }, - amd: { - options: { - modules: 'amd' - }, - files: [{ - expand: true, - cwd: 'lib/', - src: '**/!(index).js', - dest: 'dist/amd/' - }] - }, - cjs: { options: { modules: 'common' @@ -102,25 +85,6 @@ module.exports = function(grunt) { } }, - requirejs: { - options: { - optimize: 'none', - baseUrl: 'dist/amd/' - }, - dist: { - options: { - name: 'handlebars', - out: 'dist/handlebars.amd.js' - } - }, - runtime: { - options: { - name: 'handlebars.runtime', - out: 'dist/handlebars.runtime.amd.js' - } - } - }, - uglify: { options: { mangle: true, @@ -160,7 +124,7 @@ module.exports = function(grunt) { all: { options: { build: process.env.TRAVIS_JOB_ID, - urls: ['http://localhost:9999/spec/?headless=true', 'http://localhost:9999/spec/amd.html?headless=true'], + urls: ['http://localhost:9999/spec/?headless=true'], detailedError: true, concurrency: 4, browsers: [ @@ -176,11 +140,12 @@ module.exports = function(grunt) { sanity: { options: { build: process.env.TRAVIS_JOB_ID, - urls: ['http://localhost:9999/spec/umd.html?headless=true', 'http://localhost:9999/spec/amd-runtime.html?headless=true', 'http://localhost:9999/spec/umd-runtime.html?headless=true'], + urls: ['http://localhost:9999/spec/umd.html?headless=true', 'http://localhost:9999/spec/umd-runtime.html?headless=true'], detailedError: true, concurrency: 2, browsers: [ - {browserName: 'chrome'} + {browserName: 'chrome'}, + {browserName: 'internet explorer', version: 10, platform: 'Windows 8'} ] } } @@ -205,19 +170,17 @@ module.exports = function(grunt) { 'node', 'globals']); - this.registerTask('amd', ['babel:amd', 'requirejs']); this.registerTask('node', ['babel:cjs']); this.registerTask('globals', ['webpack']); this.registerTask('tests', ['concat:tests']); - this.registerTask('release', 'Build final packages', ['eslint', 'amd', 'uglify', 'test:min', 'copy:dist', 'copy:components', 'copy:cdnjs']); + this.registerTask('release', 'Build final packages', ['eslint', 'uglify', 'test:min', 'copy:dist', 'copy:components', 'copy:cdnjs']); // Load tasks from npm grunt.loadNpmTasks('grunt-contrib-clean'); grunt.loadNpmTasks('grunt-contrib-concat'); grunt.loadNpmTasks('grunt-contrib-connect'); grunt.loadNpmTasks('grunt-contrib-copy'); - grunt.loadNpmTasks('grunt-contrib-requirejs'); grunt.loadNpmTasks('grunt-contrib-uglify'); grunt.loadNpmTasks('grunt-contrib-watch'); grunt.loadNpmTasks('grunt-babel'); diff --git a/package.json b/package.json index a5b788796..ffd742ce9 100644 --- a/package.json +++ b/package.json @@ -42,7 +42,6 @@ "grunt-contrib-concat": "0.x", "grunt-contrib-connect": "0.x", "grunt-contrib-copy": "0.x", - "grunt-contrib-requirejs": "0.x", "grunt-contrib-uglify": "0.x", "grunt-contrib-watch": "0.x", "grunt-eslint": "^17.1.0", @@ -68,7 +67,7 @@ "jspm": { "main": "handlebars", "directories": { - "lib": "dist/amd" + "lib": "dist/cjs" }, "buildConfig": { "minify": true diff --git a/spec/amd-runtime.html b/spec/amd-runtime.html deleted file mode 100644 index 7cc64f190..000000000 --- a/spec/amd-runtime.html +++ /dev/null @@ -1,105 +0,0 @@ - - - Mocha - - - - - - - - - - - - - - - - - - -
- - diff --git a/spec/amd.html b/spec/amd.html deleted file mode 100644 index 1149dc706..000000000 --- a/spec/amd.html +++ /dev/null @@ -1,125 +0,0 @@ - - - - Mocha - - - - - - - - - - - - - - - - - - -
- - From 164f1c13f7e6965c103b4b7bc64844f300acd539 Mon Sep 17 00:00:00 2001 From: kpdecker Date: Mon, 14 Dec 2015 02:46:42 -0600 Subject: [PATCH 013/154] Use istanbul fork for proper line coverage --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index ffd742ce9..6957dabdc 100644 --- a/package.json +++ b/package.json @@ -47,7 +47,7 @@ "grunt-eslint": "^17.1.0", "grunt-saucelabs": "8.x", "grunt-webpack": "^1.0.8", - "istanbul": "^0.3.0", + "istanbul": "github:kpdecker/istanbul", "jison": "~0.3.0", "mocha": "~1.20.0", "mock-stdin": "^0.3.0", From 9a94d1771f8fab4a07c9cd11876203814590c1f9 Mon Sep 17 00:00:00 2001 From: kpdecker Date: Mon, 14 Dec 2015 02:52:38 -0600 Subject: [PATCH 014/154] Restore babel compile options --- Gruntfile.js | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/Gruntfile.js b/Gruntfile.js index 73c521544..25855acca 100644 --- a/Gruntfile.js +++ b/Gruntfile.js @@ -44,6 +44,11 @@ module.exports = function(grunt) { }, babel: { + options: { + sourceMaps: 'inline', + loose: ['es6.modules'], + auxiliaryCommentBefore: 'istanbul ignore next' + }, cjs: { options: { modules: 'common' From ec64cf92935030559de11aec8ec079e7db0bacea Mon Sep 17 00:00:00 2001 From: "Anders D. Johnson" Date: Wed, 23 Dec 2015 15:28:46 -0600 Subject: [PATCH 015/154] Fix typos on decorators-api.md. --- docs/decorators-api.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/docs/decorators-api.md b/docs/decorators-api.md index e14a33ff5..566c7eb87 100644 --- a/docs/decorators-api.md +++ b/docs/decorators-api.md @@ -2,9 +2,9 @@ Decorators allow for blocks to be annotated with metadata or wrapped in functionality prior to execution of the block. This may be used to communicate with the containing helper or to setup a particular state in the system prior to running the block. -Decorators are registered through similar methods as helpers, `registerDecorators` and `unregisterDecorators`. These can then be referenced via the friendly name in the template using the `{{* decorator}}` and `{{#* decorator}}{/decorator}}` syntaxes. These syntaxs are derivitives of the normal mustache syntax and as such have all of the same argument and whitespace behaviors. +Decorators are registered through similar methods as helpers, `registerDecorators` and `unregisterDecorators`. These can then be referenced via the friendly name in the template using the `{{* decorator}}` and `{{#* decorator}}{/decorator}}` syntaxes. These syntaxes are derivatives of the normal mustache syntax and as such have all of the same argument and whitespace behaviors. -Decorators are executed when the block program is instantiated and are passed `(program, props, container, context, data, blockParams, depths)` +Decorators are executed when the block program is instantiated and are passed `(program, props, container, context, data, blockParams, depths)`. - `program`: The block to wrap - `props`: Object used to set metadata on the final function. Any values set on this object will be set on the function, regardless of if the original function is replaced or not. Metadata should be applied using this object as values applied to `program` may be masked by subsequent decorators that may wrap `program`. From 118836f390ffa882c720426db94e6b6748e69242 Mon Sep 17 00:00:00 2001 From: kpdecker Date: Thu, 24 Dec 2015 09:43:36 -0600 Subject: [PATCH 016/154] Throw exception if id tracking args are passed Fixes #1151 --- lib/handlebars/compiler/compiler.js | 52 ++++++++++++++--------------- spec/compiler.js | 13 ++++++-- 2 files changed, 37 insertions(+), 28 deletions(-) diff --git a/lib/handlebars/compiler/compiler.js b/lib/handlebars/compiler/compiler.js index 040e99a19..d120d285d 100644 --- a/lib/handlebars/compiler/compiler.js +++ b/lib/handlebars/compiler/compiler.js @@ -421,41 +421,20 @@ Compiler.prototype = { } }; -export function precompile(input, options, env) { - if (input == null || (typeof input !== 'string' && input.type !== 'Program')) { - throw new Exception('You must pass a string or Handlebars AST to Handlebars.precompile. You passed ' + input); - } - - options = options || {}; - if (!('data' in options)) { - options.data = true; - } - if (options.compat) { - options.useDepths = true; - } +export function precompile(input, options = {}, env) { + validateInput(input, options); - let ast = env.parse(input, options), - environment = new env.Compiler().compile(ast, options); + let environment = compileEnvironment(input, options, env); return new env.JavaScriptCompiler().compile(environment, options); } export function compile(input, options = {}, env) { - if (input == null || (typeof input !== 'string' && input.type !== 'Program')) { - throw new Exception('You must pass a string or Handlebars AST to Handlebars.compile. You passed ' + input); - } - - if (!('data' in options)) { - options.data = true; - } - if (options.compat) { - options.useDepths = true; - } + validateInput(input, options); let compiled; function compileInput() { - let ast = env.parse(input, options), - environment = new env.Compiler().compile(ast, options), + let environment = compileEnvironment(input, options, env), templateSpec = new env.JavaScriptCompiler().compile(environment, options, undefined, true); return env.template(templateSpec); } @@ -469,6 +448,27 @@ export function compile(input, options = {}, env) { }; } +function validateInput(input, options) { + if (input == null || (typeof input !== 'string' && input.type !== 'Program')) { + throw new Exception('You must pass a string or Handlebars AST to Handlebars.compile. You passed ' + input); + } + + if (options.trackIds || options.stringParams) { + throw new Exception('TrackIds and stringParams are no longer supported. See Github #1145'); + } + + if (!('data' in options)) { + options.data = true; + } + if (options.compat) { + options.useDepths = true; + } +} +function compileEnvironment(input, options, env) { + let ast = env.parse(input, options); + return new env.Compiler().compile(ast, options); +} + function argEquals(a, b) { if (a === b) { return true; diff --git a/spec/compiler.js b/spec/compiler.js index be1fb007d..9ae7099d6 100644 --- a/spec/compiler.js +++ b/spec/compiler.js @@ -48,16 +48,25 @@ describe('compiler', function() { it('can pass through an empty string', function() { equal(Handlebars.compile('')(), ''); }); + + it('throws on desupported options', function() { + shouldThrow(function() { + Handlebars.compile('Dudes', {trackIds: true}); + }, Error, 'TrackIds and stringParams are no longer supported. See Github #1145'); + shouldThrow(function() { + Handlebars.compile('Dudes', {stringParams: true}); + }, Error, 'TrackIds and stringParams are no longer supported. See Github #1145'); + }); }); describe('#precompile', function() { it('should fail with invalid input', function() { shouldThrow(function() { Handlebars.precompile(null); - }, Error, 'You must pass a string or Handlebars AST to Handlebars.precompile. You passed null'); + }, Error, 'You must pass a string or Handlebars AST to Handlebars.compile. You passed null'); shouldThrow(function() { Handlebars.precompile({}); - }, Error, 'You must pass a string or Handlebars AST to Handlebars.precompile. You passed [object Object]'); + }, Error, 'You must pass a string or Handlebars AST to Handlebars.compile. You passed [object Object]'); }); it('can utilize AST instance', function() { From 5302782c0842b26a151fd382b3bc9ba679c8a232 Mon Sep 17 00:00:00 2001 From: kpdecker Date: Thu, 24 Dec 2015 09:43:57 -0600 Subject: [PATCH 017/154] Drop removed amd task from watch list --- Gruntfile.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Gruntfile.js b/Gruntfile.js index 25855acca..005d1753a 100644 --- a/Gruntfile.js +++ b/Gruntfile.js @@ -163,7 +163,7 @@ module.exports = function(grunt) { }, files: ['src/*', 'lib/**/*.js', 'spec/**/*.js'], - tasks: ['build', 'amd', 'tests', 'test'] + tasks: ['build', 'tests', 'test'] } } }); From 834695e241df252e9c4cb90b2970ad7defa134a4 Mon Sep 17 00:00:00 2001 From: kpdecker Date: Thu, 24 Dec 2015 09:44:09 -0600 Subject: [PATCH 018/154] Remove cdnjs copy task --- Gruntfile.js | 7 +------ 1 file changed, 1 insertion(+), 6 deletions(-) diff --git a/Gruntfile.js b/Gruntfile.js index 005d1753a..266b0c3a2 100644 --- a/Gruntfile.js +++ b/Gruntfile.js @@ -30,11 +30,6 @@ module.exports = function(grunt) { {expand: true, cwd: 'dist/', src: ['*.js'], dest: 'dist/'} ] }, - cdnjs: { - files: [ - {expand: true, cwd: 'dist/', src: ['*.js'], dest: 'dist/cdnjs'} - ] - }, components: { files: [ {expand: true, cwd: 'components/', src: ['**'], dest: 'dist/components'}, @@ -179,7 +174,7 @@ module.exports = function(grunt) { this.registerTask('globals', ['webpack']); this.registerTask('tests', ['concat:tests']); - this.registerTask('release', 'Build final packages', ['eslint', 'uglify', 'test:min', 'copy:dist', 'copy:components', 'copy:cdnjs']); + this.registerTask('release', 'Build final packages', ['eslint', 'uglify', 'test:min', 'copy:dist', 'copy:components']); // Load tasks from npm grunt.loadNpmTasks('grunt-contrib-clean'); From 400bada31fbaba5296e9ce574dfec8e7b8c05039 Mon Sep 17 00:00:00 2001 From: kpdecker Date: Thu, 24 Dec 2015 09:44:26 -0600 Subject: [PATCH 019/154] Avoid multiple babel execution cycles --- Gruntfile.js | 13 ++----------- 1 file changed, 2 insertions(+), 11 deletions(-) diff --git a/Gruntfile.js b/Gruntfile.js index 266b0c3a2..fd960cb40 100644 --- a/Gruntfile.js +++ b/Gruntfile.js @@ -45,9 +45,6 @@ module.exports = function(grunt) { auxiliaryCommentBefore: 'istanbul ignore next' }, cjs: { - options: { - modules: 'common' - }, files: [{ cwd: 'lib/', expand: true, @@ -59,12 +56,6 @@ module.exports = function(grunt) { webpack: { options: { context: __dirname, - module: { - loaders: [ - // the optional 'runtime' transformer tells babel to require the runtime instead of inlining it. - { test: /\.jsx?$/, exclude: /node_modules/, loader: 'babel-loader?optional=runtime&loose=es6.modules&auxiliaryCommentBefore=istanbul%20ignore%20next' } - ] - }, output: { path: 'dist/', library: 'Handlebars', @@ -72,13 +63,13 @@ module.exports = function(grunt) { } }, handlebars: { - entry: './lib/handlebars.js', + entry: './dist/cjs/handlebars.js', output: { filename: 'handlebars.js' } }, runtime: { - entry: './lib/handlebars.runtime.js', + entry: './dist/cjs/handlebars.runtime.js', output: { filename: 'handlebars.runtime.js' } From dfc75545fadb5084bdf833f92b271206e6a92af3 Mon Sep 17 00:00:00 2001 From: kpdecker Date: Thu, 24 Dec 2015 09:44:36 -0600 Subject: [PATCH 020/154] Update jsfiddle to point to latest --- CONTRIBUTING.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 08147607d..d77d107aa 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -96,4 +96,4 @@ After this point the handlebars site needs to be updated to point to the new ver [generator-release]: https://github.com/walmartlabs/generator-release [pull-request]: https://github.com/wycats/handlebars.js/pull/new/master [issue]: https://github.com/wycats/handlebars.js/issues/new -[jsfiddle]: http://jsfiddle.net/9D88g/46/ +[jsfiddle]: https://jsfiddle.net/9D88g/47/ From b55a120e8222785db3dc00096f6afbf91b656e8a Mon Sep 17 00:00:00 2001 From: Tim Wang Date: Wed, 6 Jan 2016 10:47:29 +0800 Subject: [PATCH 021/154] Update license date --- LICENSE | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/LICENSE b/LICENSE index 4effa3916..307ebc1c2 100644 --- a/LICENSE +++ b/LICENSE @@ -1,4 +1,4 @@ -Copyright (C) 2011-2015 by Yehuda Katz +Copyright (C) 2011-2016 by Yehuda Katz Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal From 0b8fd1d8a8121a04a9b820c9eaba99e926890620 Mon Sep 17 00:00:00 2001 From: Paul Falgout Date: Tue, 19 Jan 2016 16:21:50 -0600 Subject: [PATCH 022/154] Contributing doc fix: failing thats -> failing tests --- CONTRIBUTING.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index d77d107aa..1ea246649 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -6,7 +6,7 @@ Please see our [FAQ](https://github.com/wycats/handlebars.js/blob/master/FAQ.md) Should you run into other issues with the project, please don't hesitate to let us know by filing an [issue][issue]! In general we are going to ask for an example of the problem failing, which can be as simple as a jsfiddle/jsbin/etc. We've put together a jsfiddle [template][jsfiddle] to ease this. (We will keep this link up to date as new releases occur, so feel free to check back here) -Pull requests containing only failing thats demonstrating the issue are welcomed and this also helps ensure that your issue won't regress in the future once it's fixed. +Pull requests containing only failing tests demonstrating the issue are welcomed and this also helps ensure that your issue won't regress in the future once it's fixed. Documentation issues on the handlebarsjs.com site should be reported on [handlebars-site](https://github.com/wycats/handlebars-site). From 7130a11539ceb665fa8bd8a240b05c2535dc7dbd Mon Sep 17 00:00:00 2001 From: Gennadiy Litvinyuk Date: Fri, 5 Feb 2016 15:03:19 +0100 Subject: [PATCH 023/154] Preserve License info in Closure Compiler To preserve license info in Closure Compiler the license has to be JSDoc-comment (not simple comment) and have @license before license text --- Gruntfile.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Gruntfile.js b/Gruntfile.js index fd960cb40..0e2981509 100644 --- a/Gruntfile.js +++ b/Gruntfile.js @@ -22,7 +22,7 @@ module.exports = function(grunt) { dist: { options: { processContent: function(content) { - return grunt.template.process('/*!\n\n <%= pkg.name %> v<%= pkg.version %>\n\n<%= grunt.file.read("LICENSE") %>\n@license\n*/\n') + return grunt.template.process('/**!\n\n @license\n <%= pkg.name %> v<%= pkg.version %>\n\n<%= grunt.file.read("LICENSE") %>\n*/\n') + content; } }, From 07578437123c1027afe9a67e942ea9dcc9a9ed02 Mon Sep 17 00:00:00 2001 From: Bogdan Chadkin Date: Thu, 11 Feb 2016 20:59:42 +0300 Subject: [PATCH 024/154] Use yargs --- bin/handlebars | 6 +++--- package.json | 4 ++-- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/bin/handlebars b/bin/handlebars index 7645adf36..deb809b13 100755 --- a/bin/handlebars +++ b/bin/handlebars @@ -1,6 +1,6 @@ #!/usr/bin/env node -var optimist = require('optimist') +var yargs = require('yargs') .usage('Precompile handlebar templates.\nUsage: $0 [template|directory]...', { 'f': { 'type': 'string', @@ -110,7 +110,7 @@ var optimist = require('optimist') }); -var argv = optimist.argv; +var argv = yargs.argv; argv.files = argv._; delete argv._; @@ -121,7 +121,7 @@ Precompiler.loadTemplates(argv, function(err, opts) { } if (opts.help || (!opts.templates.length && !opts.version)) { - optimist.showHelp(); + yargs.showHelp(); } else { Precompiler.cli(opts); } diff --git a/package.json b/package.json index 6957dabdc..9d37d8a3e 100644 --- a/package.json +++ b/package.json @@ -22,8 +22,8 @@ }, "dependencies": { "async": "^1.4.0", - "optimist": "^0.6.1", - "source-map": "^0.4.4" + "source-map": "^0.4.4", + "yargs": "^3.32.0" }, "optionalDependencies": { "uglify-js": "^2.6" From b37232fc8d8533f697219505155c68cfa1c9a488 Mon Sep 17 00:00:00 2001 From: "Mr. Leo" Date: Sat, 27 Feb 2016 12:11:25 +0100 Subject: [PATCH 025/154] Added cory --- README.markdown | 1 + 1 file changed, 1 insertion(+) diff --git a/README.markdown b/README.markdown index 904b9e0c6..8a16a3521 100644 --- a/README.markdown +++ b/README.markdown @@ -121,6 +121,7 @@ Handlebars in the Wild * [Assemble](http://assemble.io), by [@jonschlinkert](https://github.com/jonschlinkert) and [@doowb](https://github.com/doowb), is a static site generator that uses Handlebars.js as its template engine. +* [Cory](https://github.com/leo/cory), by [@leo](https://github.com/leo), is another tiny static site generator * [CoSchedule](http://coschedule.com) An editorial calendar for WordPress that uses Handlebars.js * [dashbars](https://github.com/pismute/dashbars) A modern helper library for Handlebars.js. * [Ember.js](http://www.emberjs.com) makes Handlebars.js the primary way to From c7be766902dee30fcd4e25f3674d537716e10c99 Mon Sep 17 00:00:00 2001 From: Charles O'Farrell Date: Sat, 20 Feb 2016 07:20:27 +1100 Subject: [PATCH 026/154] Ensure that existing blockParams and depths are respected on dupe programs Fixes #1186 --- lib/handlebars/compiler/javascript-compiler.js | 18 ++++++++++-------- spec/regressions.js | 9 +++++++++ 2 files changed, 19 insertions(+), 8 deletions(-) diff --git a/lib/handlebars/compiler/javascript-compiler.js b/lib/handlebars/compiler/javascript-compiler.js index 1708032c9..4e4f288ae 100644 --- a/lib/handlebars/compiler/javascript-compiler.js +++ b/lib/handlebars/compiler/javascript-compiler.js @@ -701,11 +701,11 @@ JavaScriptCompiler.prototype = { child = children[i]; compiler = new this.compiler(); // eslint-disable-line new-cap - let index = this.matchExistingProgram(child); + let existing = this.matchExistingProgram(child); - if (index == null) { + if (existing == null) { this.context.programs.push(''); // Placeholder to prevent name conflicts for nested children - index = this.context.programs.length; + let index = this.context.programs.length; child.index = index; child.name = 'program' + index; this.context.programs[index] = compiler.compile(child, options, this.context, !this.precompile); @@ -714,12 +714,14 @@ JavaScriptCompiler.prototype = { this.useDepths = this.useDepths || compiler.useDepths; this.useBlockParams = this.useBlockParams || compiler.useBlockParams; + child.useDepths = this.useDepths; + child.useBlockParams = this.useBlockParams; } else { - child.index = index; - child.name = 'program' + index; + child.index = existing.index; + child.name = 'program' + existing.index; - this.useDepths = this.useDepths || child.useDepths; - this.useBlockParams = this.useBlockParams || child.useBlockParams; + this.useDepths = this.useDepths || existing.useDepths; + this.useBlockParams = this.useBlockParams || existing.useBlockParams; } } }, @@ -727,7 +729,7 @@ JavaScriptCompiler.prototype = { for (let i = 0, len = this.context.environments.length; i < len; i++) { let environment = this.context.environments[i]; if (environment && environment.equals(child)) { - return i; + return environment; } } }, diff --git a/spec/regressions.js b/spec/regressions.js index a1eec2f10..4a2a55cd6 100644 --- a/spec/regressions.js +++ b/spec/regressions.js @@ -268,4 +268,13 @@ describe('Regressions', function() { ' 1. IF: John--\n' + ' 2. MYIF: John==\n'); }); + + it('GH-1186: Support block params for existing programs', function() { + var string = + '{{#*inline "test"}}{{> @partial-block }}{{/inline}}' + + '{{#>test }}{{#each listOne as |item|}}{{ item }}{{/each}}{{/test}}' + + '{{#>test }}{{#each listTwo as |item|}}{{ item }}{{/each}}{{/test}}'; + + shouldCompileTo(string, { listOne: ['a'], listTwo: ['b']}, 'ab', ''); + }); }); From 768ddbd6616f47a7a77ae2046775c43c2fe3e5ee Mon Sep 17 00:00:00 2001 From: kpdecker Date: Fri, 11 Mar 2016 22:16:18 -0600 Subject: [PATCH 027/154] Use objects for hash value tracking The use of arrays was incorrect for the data type and causing problems when hash keys conflicted with array behaviors. Fixes #1194 --- lib/handlebars/compiler/javascript-compiler.js | 2 +- spec/regressions.js | 11 +++++++++++ 2 files changed, 12 insertions(+), 1 deletion(-) diff --git a/lib/handlebars/compiler/javascript-compiler.js b/lib/handlebars/compiler/javascript-compiler.js index 4e4f288ae..ed1b83ef9 100644 --- a/lib/handlebars/compiler/javascript-compiler.js +++ b/lib/handlebars/compiler/javascript-compiler.js @@ -503,7 +503,7 @@ JavaScriptCompiler.prototype = { if (this.hash) { this.hashes.push(this.hash); } - this.hash = {values: [], types: [], contexts: [], ids: []}; + this.hash = {values: {}}; }, popHash: function() { let hash = this.hash; diff --git a/spec/regressions.js b/spec/regressions.js index 4a2a55cd6..4dc2ac89c 100644 --- a/spec/regressions.js +++ b/spec/regressions.js @@ -277,4 +277,15 @@ describe('Regressions', function() { shouldCompileTo(string, { listOne: ['a'], listTwo: ['b']}, 'ab', ''); }); + + it('should allow hash with protected array names', function() { + var obj = {array: [1], name: 'John'}; + var helpers = { + helpa: function(options) { + return options.hash.length; + } + }; + + shouldCompileTo('{{helpa length="foo"}}', [obj, helpers], 'foo'); + }); }); From 2ff795cf2fc9e9a10462e27ebaf508db62678933 Mon Sep 17 00:00:00 2001 From: Kabir Date: Tue, 12 Apr 2016 16:17:12 +0545 Subject: [PATCH 028/154] Add a new lightweight package based on handlebars in the README Add a new package [just-handlebars-helpers](https://github.com/leapfrogtechnology/just-handlebars-helpers) on the list. This is a lightweight package that offers a collection of common handlebars helpers. And it is [fully tested](https://codecov.io/github/leapfrogtechnology/just-handlebars-helpers) --- README.markdown | 1 + 1 file changed, 1 insertion(+) diff --git a/README.markdown b/README.markdown index 8a16a3521..89e3fc59a 100644 --- a/README.markdown +++ b/README.markdown @@ -151,6 +151,7 @@ Handlebars in the Wild * [Swag](https://github.com/elving/swag) by [@elving](https://github.com/elving) is a growing collection of helpers for handlebars.js. Give your handlebars.js templates some swag son! * [DOMBars](https://github.com/blakeembrey/dombars) is a DOM-based templating engine built on the Handlebars parser and runtime **DEPRECATED** * [promised-handlebars](https://github.com/nknapp/promised-handlebars) is a wrapper for Handlebars that allows helpers to return Promises. +* [just-handlebars-helpers](https://github.com/leapfrogtechnology/just-handlebars-helpers) A fully tested lightweight package with common Handlebars helpers. External Resources ------------------ From f0d4159a5e874164ea013373fcb16462be863b88 Mon Sep 17 00:00:00 2001 From: John Boehr Date: Thu, 21 Apr 2016 15:41:07 -0700 Subject: [PATCH 029/154] Fix test failure caused by yargs In yargs 3.2, any non-truthy return value to check will fail: https://github.com/yargs/yargs/blob/master/CHANGELOG.md#302-20150213-1650-0000 It appears that this check is no longer necessary as the other contents of the check callback no longer exist: https://github.com/wycats/handlebars.js/commit/2e7a3bd70223c0e532a24290c7d817b951354541#diff-2aff13863648736946e83d70c5e63520L86 It appears the build failed for PR #1180, not sure why it was merged --- bin/handlebars | 7 +------ 1 file changed, 1 insertion(+), 6 deletions(-) diff --git a/bin/handlebars b/bin/handlebars index deb809b13..7684271dc 100755 --- a/bin/handlebars +++ b/bin/handlebars @@ -102,12 +102,7 @@ var yargs = require('yargs') } }) - .wrap(120) - .check(function(argv) { - if (argv.version) { - return; - } - }); + .wrap(120); var argv = yargs.argv; From 094a2564fe56f39ebb78dc0a43659639efb2a124 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Luiz=20Am=C3=A9rico?= Date: Sat, 9 Jul 2016 10:12:11 -0300 Subject: [PATCH 030/154] upgrade jison to 0.4.17 --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index 9d37d8a3e..a9489b77d 100644 --- a/package.json +++ b/package.json @@ -48,7 +48,7 @@ "grunt-saucelabs": "8.x", "grunt-webpack": "^1.0.8", "istanbul": "github:kpdecker/istanbul", - "jison": "~0.3.0", + "jison": "^0.4.17", "mocha": "~1.20.0", "mock-stdin": "^0.3.0", "mustache": "^2.1.3", From e8722e255135907c3f783ff7a8abcaf52f5ceeb1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Luiz=20Am=C3=A9rico?= Date: Sat, 9 Jul 2016 11:55:03 -0300 Subject: [PATCH 031/154] stick to 0.4.16. Tests does no pass with 0.4.17 --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index a9489b77d..0918ff4f0 100644 --- a/package.json +++ b/package.json @@ -48,7 +48,7 @@ "grunt-saucelabs": "8.x", "grunt-webpack": "^1.0.8", "istanbul": "github:kpdecker/istanbul", - "jison": "^0.4.17", + "jison": "0.4.16", "mocha": "~1.20.0", "mock-stdin": "^0.3.0", "mustache": "^2.1.3", From f2211ddd650af2a28c782e736d8528f875c38dd4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Luiz=20Am=C3=A9rico?= Date: Thu, 21 Jul 2016 20:45:25 -0300 Subject: [PATCH 032/154] Update definition of BlockStatement.path As pointed in https://github.com/wycats/handlebars.js/issues/1237 BlockStatement.path accepts in practice PathExpression or Literal. Updates its definition to reflect this fact --- docs/compiler-api.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/compiler-api.md b/docs/compiler-api.md index 29382191e..c9d2e937f 100644 --- a/docs/compiler-api.md +++ b/docs/compiler-api.md @@ -66,7 +66,7 @@ interface MustacheStatement <: Statement { interface BlockStatement <: Statement { type: "BlockStatement"; - path: PathExpression; + path: PathExpression | Literal; params: [ Expression ]; hash: Hash; From bbe0a94d6e5e909361d3f1195b1bc72dc31e233f Mon Sep 17 00:00:00 2001 From: Lon Ingram Date: Tue, 16 Aug 2016 15:47:33 -0500 Subject: [PATCH 033/154] Walk up data frames for nested @partial-block The root cause of #1218 is that `invokePartial` creates a stack of data frames for nested partial blocks, but `resolvePartial` always uses the value at top of the stack without "popping" it. The result is an infinite recursive loop, as references to `@partial-block` in the partial at the top of the stack resolve to itself. So, walk up the stack of data frames when evaluating. This is accomplished by 1) setting the `partial-block` property to `noop` after use and 2) using `_parent['partial-block']` if `partial-block` is `noop` Fix #1218 --- lib/handlebars/runtime.js | 7 ++++++- spec/partials.js | 14 ++++++++++++++ 2 files changed, 20 insertions(+), 1 deletion(-) diff --git a/lib/handlebars/runtime.js b/lib/handlebars/runtime.js index 55eb1c1b0..7426f1f5e 100644 --- a/lib/handlebars/runtime.js +++ b/lib/handlebars/runtime.js @@ -197,7 +197,12 @@ export function wrapProgram(container, i, fn, data, declaredBlockParams, blockPa export function resolvePartial(partial, context, options) { if (!partial) { if (options.name === '@partial-block') { - partial = options.data['partial-block']; + let data = options.data; + while (data['partial-block'] === noop) { + data = data._parent; + } + partial = data['partial-block']; + data['partial-block'] = noop; } else { partial = options.partials[options.name]; } diff --git a/spec/partials.js b/spec/partials.js index d3ead7458..07d1c0d62 100644 --- a/spec/partials.js +++ b/spec/partials.js @@ -270,6 +270,20 @@ describe('partials', function() { true, 'success'); }); + it('should render nested partial blocks', function() { + shouldCompileToWithPartials( + '.template-start.{{#> outer}}{{value}}{{/outer}}.template-end.', + [ + {value: 'success'}, + {}, + { + outer: '.outer-start.{{#> nested}}.outer-partial-block-start.{{> @partial-block}}.outer-partial-block-end.{{/nested}}.outer-end.', + nested: '.nested-start.{{> @partial-block}}.nested-end.' + } + ], + true, + '.template-start..outer-start..nested-start..outer-partial-block-start.success.outer-partial-block-end..nested-end..outer-end..template-end.'); + }); }); describe('inline partials', function() { From 601ce8a69f2d2de77400fe207713bd81a133d8e3 Mon Sep 17 00:00:00 2001 From: Lon Ingram Date: Wed, 17 Aug 2016 13:32:50 -0500 Subject: [PATCH 034/154] Add test reproducing #1185 --- spec/partials.js | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/spec/partials.js b/spec/partials.js index 07d1c0d62..fcfc78038 100644 --- a/spec/partials.js +++ b/spec/partials.js @@ -323,6 +323,15 @@ describe('partials', function() { true, 'success'); }); + it('should render nested inline partials', function() { + shouldCompileToWithPartials( + '{{#*inline "outer"}}{{#>inner}}{{>@partial-block}}{{/inner}}{{/inline}}' + + '{{#*inline "inner"}}{{>@partial-block}}{{/inline}}' + + '{{#>outer}}{{value}}{{/outer}}', + [{value: 'success'}, {}, {}], + true, + 'success'); + }); }); it('should pass compiler flags', function() { From 21696005cd9e5a3ea2150431df44fd13da2c405c Mon Sep 17 00:00:00 2001 From: Lon Ingram Date: Wed, 17 Aug 2016 13:36:16 -0500 Subject: [PATCH 035/154] Use XML-like tags in test instead of bizarre dot delimiters --- spec/partials.js | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/spec/partials.js b/spec/partials.js index fcfc78038..d6baba504 100644 --- a/spec/partials.js +++ b/spec/partials.js @@ -272,17 +272,17 @@ describe('partials', function() { }); it('should render nested partial blocks', function() { shouldCompileToWithPartials( - '.template-start.{{#> outer}}{{value}}{{/outer}}.template-end.', + '', [ {value: 'success'}, {}, { - outer: '.outer-start.{{#> nested}}.outer-partial-block-start.{{> @partial-block}}.outer-partial-block-end.{{/nested}}.outer-end.', - nested: '.nested-start.{{> @partial-block}}.nested-end.' + outer: '{{#> nested}}{{> @partial-block}}{{/nested}}', + nested: '{{> @partial-block}}' } ], true, - '.template-start..outer-start..nested-start..outer-partial-block-start.success.outer-partial-block-end..nested-end..outer-end..template-end.'); + ''); }); }); From 275ab37b2edee3d894d6a781ba97b1219c2dac07 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Luiz=20Am=C3=A9rico?= Date: Sun, 21 Aug 2016 17:50:20 -0300 Subject: [PATCH 036/154] Fix build in windows --- tasks/test.js | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/tasks/test.js b/tasks/test.js index 18a6c26ba..803fef9fa 100644 --- a/tasks/test.js +++ b/tasks/test.js @@ -5,13 +5,14 @@ module.exports = function(grunt) { grunt.registerTask('test:bin', function() { var done = this.async(); - childProcess.exec('./bin/handlebars -a spec/artifacts/empty.handlebars', function(err, stdout) { + childProcess.exec('node ./bin/handlebars -a spec/artifacts/empty.handlebars', function(err, stdout) { if (err) { throw err; } - var expected = fs.readFileSync('./spec/expected/empty.amd.js'); - if (stdout.toString() !== expected.toString()) { + var expected = fs.readFileSync('./spec/expected/empty.amd.js').toString().replace(/\r\n/g, '\n'); + + if (stdout.toString() !== expected) { throw new Error('Expected binary output differed:\n\n"' + stdout + '"\n\n"' + expected + '"'); } From 6c92579faff9d7ecdc0e74ee9a8e093780a0a20d Mon Sep 17 00:00:00 2001 From: Nils Knappmeier Date: Fri, 2 Dec 2016 08:45:19 +0100 Subject: [PATCH 037/154] Template for issues and pull-request I've noticed that many issues are answered with "Please provide a jsfiddle". This issue template tells the reporter to do that from the start. --- .github/ISSUE_TEMPLATE.md | 10 ++++++++++ .github/PULL_REQUEST_TEMPLATE.md | 11 +++++++++++ 2 files changed, 21 insertions(+) create mode 100644 .github/ISSUE_TEMPLATE.md create mode 100644 .github/PULL_REQUEST_TEMPLATE.md diff --git a/.github/ISSUE_TEMPLATE.md b/.github/ISSUE_TEMPLATE.md new file mode 100644 index 000000000..782cf3d59 --- /dev/null +++ b/.github/ISSUE_TEMPLATE.md @@ -0,0 +1,10 @@ +Before filing issues, please check the following points first: + +- [ ] Have a look at https://github.com/wycats/handlebars.js/blob/master/CONTRIBUTING.md +- [ ] Read the FAQ at https://github.com/wycats/handlebars.js/blob/master/FAQ.md +- [ ] Use the jsfiddle-template at https://jsfiddle.net/9D88g/47/ to reproduce problems or bugs + +This will probably help you to get a solution faster. +For bugs, it would be great to have a PR with a failing test-case. + + diff --git a/.github/PULL_REQUEST_TEMPLATE.md b/.github/PULL_REQUEST_TEMPLATE.md new file mode 100644 index 000000000..8d8437ee7 --- /dev/null +++ b/.github/PULL_REQUEST_TEMPLATE.md @@ -0,0 +1,11 @@ +Before creating a pull-request, please check https://github.com/wycats/handlebars.js/blob/master/CONTRIBUTING.md first. + +Generally we like to see pull requests that + +- [ ] Maintain the existing code style +- [ ] Are focused on a single change (i.e. avoid large refactoring or style adjustments in untouched code if not the primary goal of the pull request) +- [ ] Have good commit messages +- [ ] Have tests +- [ ] Don't significantly decrease the current code coverage (see coverage/lcov-report/index.html) + + From 9a36966b16e404fbd8686805f368c6fd56c54ee8 Mon Sep 17 00:00:00 2001 From: Travis Nelson Date: Tue, 15 Nov 2016 20:32:53 -0700 Subject: [PATCH 038/154] require('sys') is deprecated, using 'util' instead (node:30288) DeprecationWarning: sys is deprecated. Use util instead. --- bench/util/benchwarmer.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/bench/util/benchwarmer.js b/bench/util/benchwarmer.js index 78b1a347e..49f66f737 100644 --- a/bench/util/benchwarmer.js +++ b/bench/util/benchwarmer.js @@ -11,7 +11,7 @@ function BenchWarmer() { this.errors = {}; } -var print = require('sys').print; +var print = require('util').print; BenchWarmer.prototype = { winners: function(benches) { From 2b7ed7e0bbeb995d6d73d7872d870b39c7a795d0 Mon Sep 17 00:00:00 2001 From: Marcos Marado Date: Sat, 12 Nov 2016 01:09:43 +0000 Subject: [PATCH 039/154] Fix istanbul dev dependency According to npm's documentation[1], dependencies on github repositories are declared with the following syntax: "module": "person/module" This commit changes the package.json syntax on istanbul's dependency, to follow the documentation. [1] https://docs.npmjs.com/files/package.json#github-urls --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index 0918ff4f0..68ad01ba2 100644 --- a/package.json +++ b/package.json @@ -47,7 +47,7 @@ "grunt-eslint": "^17.1.0", "grunt-saucelabs": "8.x", "grunt-webpack": "^1.0.8", - "istanbul": "github:kpdecker/istanbul", + "istanbul": "kpdecker/istanbul", "jison": "0.4.16", "mocha": "~1.20.0", "mock-stdin": "^0.3.0", From d117b3e0f9ab297b8868d258f141a362745c8371 Mon Sep 17 00:00:00 2001 From: Nils Knappmeier Date: Fri, 6 Jan 2017 10:03:46 +0100 Subject: [PATCH 040/154] Eslint upgrade to 19.0.0 and configuration fixes (#1294) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Original PR by @travnels, commit-message edited by @nknapp * Upgraded eslint to 19.0.0 * Cleaned up duplicate rules 'no-extra-parens', 'quote-props' * eslint rule 'no-empty-label' was replaced. Rule 'no-empty-label' was removed and replaced by: ‘no-labels’. ‘no-labels’ already in the project * eslint rule 'space-after-keywords' has been replaced Rules 'space-after-keywords' and 'space-return-throw-case' wer removed and replaced by ‘keyword-spacing’. * Added parsoer-option: sourceType='module' * Add unnecessary=false to 'quote-props' to remove warnings about unnecessarily quoted property. Code corrections * helpers.js: unused variable 'depthString' removed, detected by new eslint --- .eslintrc | 11 +++++------ lib/handlebars/compiler/helpers.js | 4 +--- package.json | 2 +- 3 files changed, 7 insertions(+), 10 deletions(-) diff --git a/.eslintrc b/.eslintrc index 8cd3bd6fe..b8cdd1949 100644 --- a/.eslintrc +++ b/.eslintrc @@ -43,7 +43,6 @@ "no-empty-character-class": 2, "no-ex-assign": 2, "no-extra-boolean-cast": 2, - "no-extra-parens": 0, "no-extra-semi": 2, "no-func-assign": 0, @@ -55,7 +54,7 @@ "no-negated-in-lhs": 2, "no-obj-calls": 2, "no-regex-spaces": 2, - "quote-props": [2, "as-needed", {"keywords": true}], + "quote-props": [2, "as-needed", {"keywords": true, "unnecessary": false}], "no-sparse-arrays": 0, // Optimizer and coverage will handle/highlight this and can be useful for debugging @@ -80,7 +79,6 @@ "no-caller": 2, "no-div-regex": 1, "no-else-return": 0, - "no-empty-label": 2, "no-eq-null": 0, "no-eval": 2, "no-extend-native": 2, @@ -179,22 +177,23 @@ "one-var": 0, "operator-assignment": 0, "padded-blocks": 0, - "quote-props": 0, "quotes": [2, "single", "avoid-escape"], "semi": 2, "semi-spacing": [2, {"before": false, "after": true}], "sort-vars": 0, - "space-after-keywords": [2, "always"], + "keyword-spacing": 2, "space-before-blocks": [2, "always"], "space-before-function-paren": [2, {"anonymous": "never", "named": "never"}], "space-in-brackets": 0, "space-in-parens": [2, "never"], "space-infix-ops": 2, - "space-return-throw-case": 2, "space-unary-ops": 2, "spaced-comment": [2, "always", {"markers": [","]}], "wrap-regex": 1, "no-var": 1 + }, + "parserOptions": { + "sourceType": "module" } } \ No newline at end of file diff --git a/lib/handlebars/compiler/helpers.js b/lib/handlebars/compiler/helpers.js index e09a08df9..3c1a38fa5 100644 --- a/lib/handlebars/compiler/helpers.js +++ b/lib/handlebars/compiler/helpers.js @@ -47,8 +47,7 @@ export function preparePath(data, parts, loc) { let original = data ? '@' : '', dig = [], - depth = 0, - depthString = ''; + depth = 0; for (let i = 0, l = parts.length; i < l; i++) { let part = parts[i].part, @@ -62,7 +61,6 @@ export function preparePath(data, parts, loc) { throw new Exception('Invalid path: ' + original, {loc}); } else if (part === '..') { depth++; - depthString += '../'; } } else { dig.push(part); diff --git a/package.json b/package.json index 68ad01ba2..29fab88e0 100644 --- a/package.json +++ b/package.json @@ -44,7 +44,7 @@ "grunt-contrib-copy": "0.x", "grunt-contrib-uglify": "0.x", "grunt-contrib-watch": "0.x", - "grunt-eslint": "^17.1.0", + "grunt-eslint": "19.0.x", "grunt-saucelabs": "8.x", "grunt-webpack": "^1.0.8", "istanbul": "kpdecker/istanbul", From 9119265204222b3dcb09cd96398db148a58fc521 Mon Sep 17 00:00:00 2001 From: Nils Knappmeier Date: Fri, 6 Jan 2017 10:14:59 +0100 Subject: [PATCH 041/154] Added ".editorconfig"-file that specifies the indent for javascript-files (#1292) * see http://editorconfig.org/ * This file only includes very basic settings. It may be expanded in the future --- .editorconfig | 7 +++++++ 1 file changed, 7 insertions(+) create mode 100644 .editorconfig diff --git a/.editorconfig b/.editorconfig new file mode 100644 index 000000000..f2bc96b02 --- /dev/null +++ b/.editorconfig @@ -0,0 +1,7 @@ +root = true + +[*.js] +indent_size = 2 +insert_final_newline = true +trim_trailing_whitespace = true + From a6476739f0ed57cfdadce38d986025fe529c4dcf Mon Sep 17 00:00:00 2001 From: Marcos Marado Date: Mon, 14 Nov 2016 20:33:48 +0000 Subject: [PATCH 042/154] add more machine-readable data about the license This small change is meant to make LibreJS happy. Closes: #1273 --- Gruntfile.js | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/Gruntfile.js b/Gruntfile.js index 0e2981509..25e1f1bd1 100644 --- a/Gruntfile.js +++ b/Gruntfile.js @@ -22,8 +22,9 @@ module.exports = function(grunt) { dist: { options: { processContent: function(content) { - return grunt.template.process('/**!\n\n @license\n <%= pkg.name %> v<%= pkg.version %>\n\n<%= grunt.file.read("LICENSE") %>\n*/\n') - + content; + return grunt.template.process('/**!\n\n @license magnet:?xt=urn:btih:d3d9a9a6595521f9666a5e94cc830dab83b65699&dn=expat.txt Expat\n <%= pkg.name %> v<%= pkg.version %>\n\n<%= grunt.file.read("LICENSE") %>\n*/\n') + + content + + '\n// @license-end\n'; } }, files: [ From 6c89939af70b51d1ba0f8a89c9e13b711517df43 Mon Sep 17 00:00:00 2001 From: Ryunosuke Sato Date: Sat, 14 Jan 2017 21:59:16 +0900 Subject: [PATCH 043/154] Fix README filename in package.json There is `README.markdown` in handlebars.js repository, not a `README.md`. --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index 29fab88e0..acf847def 100644 --- a/package.json +++ b/package.json @@ -16,7 +16,7 @@ }, "author": "Yehuda Katz", "license": "MIT", - "readmeFilename": "README.md", + "readmeFilename": "README.markdown", "engines": { "node": ">=0.4.7" }, From 6300e57f119bd7dfe7a11e640126281bb7849c07 Mon Sep 17 00:00:00 2001 From: Travis Nelson Date: Thu, 12 Jan 2017 22:51:01 -0700 Subject: [PATCH 044/154] Moved .eslintrc to .eslintrc.js and cleaned up rules Extending from eslint:recommended so we stay up to date on the latest recommended rules. --- .eslintrc | 199 --------------------------------------------------- .eslintrc.js | 129 +++++++++++++++++++++++++++++++++ 2 files changed, 129 insertions(+), 199 deletions(-) delete mode 100644 .eslintrc create mode 100644 .eslintrc.js diff --git a/.eslintrc b/.eslintrc deleted file mode 100644 index b8cdd1949..000000000 --- a/.eslintrc +++ /dev/null @@ -1,199 +0,0 @@ -{ - "globals": { - "self": false - }, - "env": { - "node": true - }, - "ecmaFeatures": { - // Enabling features that can be implemented without polyfills. Want to avoid polyfills at this time. - "arrowFunctions": true, - "blockBindings": true, - "defaultParams": true, - "destructuring": true, - "modules": true, - "objectLiteralComputedProperties": true, - "objectLiteralDuplicateProperties": true, - "objectLiteralShorthandMethods": true, - "objectLiteralShorthandProperties": true, - "restParams": true, - "spread": true, - "templateStrings": true - }, - "rules": { - // Possible Errors // - //-----------------// - - "comma-dangle": [2, "never"], - "no-cond-assign": [2, "except-parens"], - - // Allow for debugging - "no-console": 1, - - "no-constant-condition": 2, - "no-control-regex": 2, - - // Allow for debugging - "no-debugger": 1, - - "no-dupe-args": 2, - "no-dupe-keys": 2, - "no-duplicate-case": 2, - "no-empty": 2, - "no-empty-character-class": 2, - "no-ex-assign": 2, - "no-extra-boolean-cast": 2, - "no-extra-semi": 2, - "no-func-assign": 0, - - // Stylistic... might consider disallowing in the future - "no-inner-declarations": 0, - - "no-invalid-regexp": 2, - "no-irregular-whitespace": 2, - "no-negated-in-lhs": 2, - "no-obj-calls": 2, - "no-regex-spaces": 2, - "quote-props": [2, "as-needed", {"keywords": true, "unnecessary": false}], - "no-sparse-arrays": 0, - - // Optimizer and coverage will handle/highlight this and can be useful for debugging - "no-unreachable": 1, - - "use-isnan": 2, - "valid-jsdoc": 0, - "valid-typeof": 2, - - - // Best Practices // - //----------------// - "block-scoped-var": 0, - "complexity": 0, - "consistent-return": 0, - "curly": 2, - "default-case": 1, - "dot-notation": [2, {"allowKeywords": false}], - "eqeqeq": 0, - "guard-for-in": 1, - "no-alert": 2, - "no-caller": 2, - "no-div-regex": 1, - "no-else-return": 0, - "no-eq-null": 0, - "no-eval": 2, - "no-extend-native": 2, - "no-extra-bind": 2, - "no-fallthrough": 2, - "no-floating-decimal": 2, - "no-implied-eval": 2, - "no-iterator": 2, - "no-labels": 2, - "no-lone-blocks": 2, - "no-loop-func": 2, - "no-multi-spaces": 2, - "no-multi-str": 1, - "no-native-reassign": 2, - "no-new": 2, - "no-new-func": 2, - "no-new-wrappers": 2, - "no-octal": 2, - "no-octal-escape": 2, - "no-param-reassign": 0, - "no-process-env": 2, - "no-proto": 2, - "no-redeclare": 2, - "no-return-assign": 2, - "no-script-url": 2, - "no-self-compare": 2, - "no-sequences": 2, - "no-throw-literal": 2, - "no-unused-expressions": 2, - "no-void": 0, - "no-warning-comments": 1, - "no-with": 2, - "radix": 2, - "vars-on-top": 0, - "wrap-iife": 2, - "yoda": 0, - - - // Strict // - //--------// - "strict": 0, - - - // Variables // - //-----------// - "no-catch-shadow": 2, - "no-delete-var": 2, - "no-label-var": 2, - "no-shadow": 0, - "no-shadow-restricted-names": 2, - "no-undef": 2, - "no-undef-init": 2, - "no-undefined": 0, - "no-unused-vars": [2, {"vars": "all", "args": "after-used"}], - "no-use-before-define": [2, "nofunc"], - - - // Node.js // - //---------// - // Others left to environment defaults - "no-mixed-requires": 0, - - - // Stylistic // - //-----------// - "indent": 0, - "brace-style": [2, "1tbs", {"allowSingleLine": true}], - "camelcase": 2, - "comma-spacing": [2, {"before": false, "after": true}], - "comma-style": [2, "last"], - "consistent-this": [1, "self"], - "eol-last": 2, - "func-names": 0, - "func-style": [2, "declaration"], - "key-spacing": [2, { - "beforeColon": false, - "afterColon": true - }], - "max-nested-callbacks": 0, - "new-cap": 2, - "new-parens": 2, - "newline-after-var": 0, - "no-array-constructor": 2, - "no-continue": 0, - "no-inline-comments": 0, - "no-lonely-if": 2, - "no-mixed-spaces-and-tabs": 2, - "no-multiple-empty-lines": 0, - "no-nested-ternary": 1, - "no-new-object": 2, - "no-spaced-func": 2, - "no-ternary": 0, - "no-trailing-spaces": 2, - "no-underscore-dangle": 0, - "no-extra-parens": [2, "functions"], - "one-var": 0, - "operator-assignment": 0, - "padded-blocks": 0, - "quotes": [2, "single", "avoid-escape"], - "semi": 2, - "semi-spacing": [2, {"before": false, "after": true}], - "sort-vars": 0, - "keyword-spacing": 2, - "space-before-blocks": [2, "always"], - "space-before-function-paren": [2, {"anonymous": "never", "named": "never"}], - "space-in-brackets": 0, - "space-in-parens": [2, "never"], - "space-infix-ops": 2, - "space-unary-ops": 2, - "spaced-comment": [2, "always", {"markers": [","]}], - "wrap-regex": 1, - - "no-var": 1 - }, - "parserOptions": { - "sourceType": "module" - } -} \ No newline at end of file diff --git a/.eslintrc.js b/.eslintrc.js new file mode 100644 index 000000000..d240473c4 --- /dev/null +++ b/.eslintrc.js @@ -0,0 +1,129 @@ +module.exports = { + "extends": "eslint:recommended", + "globals": { + "self": false + }, + "env": { + "node": true + }, + "ecmaFeatures": { + // Enabling features that can be implemented without polyfills. Want to avoid polyfills at this time. + "arrowFunctions": true, + "blockBindings": true, + "defaultParams": true, + "destructuring": true, + "modules": true, + "objectLiteralComputedProperties": true, + "objectLiteralDuplicateProperties": true, + "objectLiteralShorthandMethods": true, + "objectLiteralShorthandProperties": true, + "restParams": true, + "spread": true, + "templateStrings": true + }, + "rules": { + // overrides eslint:recommended defaults + "no-sparse-arrays": "off", + "no-func-assign": "off", + "no-console": "warn", + "no-debugger": "warn", + "no-unreachable": "warn", + + // Possible Errors // + //-----------------// + "no-unsafe-negation": "error", + + + // Best Practices // + //----------------// + "curly": "error", + "default-case": "warn", + "dot-notation": ["error", { "allowKeywords": false }], + "guard-for-in": "warn", + "no-alert": "error", + "no-caller": "error", + "no-div-regex": "warn", + "no-eval": "error", + "no-extend-native": "error", + "no-extra-bind": "error", + "no-floating-decimal": "error", + "no-implied-eval": "error", + "no-iterator": "error", + "no-labels": "error", + "no-lone-blocks": "error", + "no-loop-func": "error", + "no-multi-spaces": "error", + "no-multi-str": "warn", + "no-global-assign": "error", + "no-new": "error", + "no-new-func": "error", + "no-new-wrappers": "error", + "no-octal-escape": "error", + "no-process-env": "error", + "no-proto": "error", + "no-return-assign": "error", + "no-script-url": "error", + "no-self-compare": "error", + "no-sequences": "error", + "no-throw-literal": "error", + "no-unused-expressions": "error", + "no-warning-comments": "warn", + "no-with": "error", + "radix": "error", + "wrap-iife": "error", + + + // Variables // + //-----------// + "no-catch-shadow": "error", + "no-label-var": "error", + "no-shadow-restricted-names": "error", + "no-undef-init": "error", + "no-use-before-define": ["error", "nofunc"], + + + // Stylistic Issues // + //------------------// + "comma-dangle": ["error", "never"], + "quote-props": ["error", "as-needed", { "keywords": true, "unnecessary": false }], + "brace-style": ["error", "1tbs", { "allowSingleLine": true }], + "camelcase": "error", + "comma-spacing": ["error", { "before": false, "after": true }], + "comma-style": ["error", "last"], + "consistent-this": ["warn", "self"], + "eol-last": "error", + "func-style": ["error", "declaration"], + "key-spacing": ["error", { + "beforeColon": false, + "afterColon": true + }], + "new-cap": "error", + "new-parens": "error", + "no-array-constructor": "error", + "no-lonely-if": "error", + "no-mixed-spaces-and-tabs": "error", + "no-nested-ternary": "warn", + "no-new-object": "error", + "no-spaced-func": "error", + "no-trailing-spaces": "error", + "no-extra-parens": ["error", "functions"], + "quotes": ["error", "single", "avoid-escape"], + "semi": "error", + "semi-spacing": ["error", { "before": false, "after": true }], + "keyword-spacing": "error", + "space-before-blocks": ["error", "always"], + "space-before-function-paren": ["error", { "anonymous": "never", "named": "never" }], + "space-in-parens": ["error", "never"], + "space-infix-ops": "error", + "space-unary-ops": "error", + "spaced-comment": ["error", "always", { "markers": [","] }], + "wrap-regex": "warn", + + // ECMAScript 6 // + //--------------// + "no-var": "warn" + }, + "parserOptions": { + "sourceType": "module" + } +} From c9970200a04a8629b5e9b1ed3c540d391ab00f26 Mon Sep 17 00:00:00 2001 From: Nils Knappmeier Date: Sun, 29 Jan 2017 07:11:01 +0100 Subject: [PATCH 045/154] Fix compiler-api example (#1303) Closes #1302 While trying to answer #1302, I noticed that the compiler-api example did not work in (because `nameLookup` is actually at the prototype). This example has a jsfiddle that proves it is working. It does not provide an solve the exact problem of the reporter, but it answers the question. --- docs/compiler-api.md | 27 +++++++++++++++++++++------ 1 file changed, 21 insertions(+), 6 deletions(-) diff --git a/docs/compiler-api.md b/docs/compiler-api.md index c9d2e937f..a0478dea5 100644 --- a/docs/compiler-api.md +++ b/docs/compiler-api.md @@ -296,21 +296,36 @@ The `Handlebars.JavaScriptCompiler` object has a number of methods that may be c - `initializeBuffer()` Allows for buffers other than the default string buffer to be used. Generally needs to be paired with a custom `appendToBuffer` implementation. +### Example for the compiler api. + +This example changes all lookups of properties are performed by a helper (`lookupLowerCase`) which looks for `test` if `{{Test}}` occurs in the template. This is just to illustrate how compiler behavior can be change. + +There is also [a jsfiddle with this code](https://jsfiddle.net/9D88g/85/) if you want to play around with it. + + ```javascript function MyCompiler() { Handlebars.JavaScriptCompiler.apply(this, arguments); } -MyCompiler.prototype = Object.create(Handlebars.JavaScriptCompiler); +MyCompiler.prototype = new Handlebars.JavaScriptCompiler(); -MyCompiler.nameLookup = function(parent, name, type) { - if (type === 'partial') { - return 'MyPartialList[' + JSON.stringify(name) ']'; +MyCompiler.prototype.nameLookup = function(parent, name, type) { + if (type === 'context') { + return this.source.functionCall('helpers.lookupLowerCase', '', [parent, JSON.stringify(name)]) } else { return Handlebars.JavaScriptCompiler.prototype.nameLookup.call(this, parent, name, type); } -}; +} var env = Handlebars.create(); +env.registerHelper('lookupLowerCase', function(parent, name) { + return parent[name.toLowerCase()] +}) + env.JavaScriptCompiler = MyCompiler; -env.compile('my template'); + +var template = env.compile('{{#each Test}}{{.}} {{/each}}'); +console.log(template({ + test: [ "a","b","c"] +})); ``` From 660a1175364aaef8903d7446f06adcb1f8d27acd Mon Sep 17 00:00:00 2001 From: Joonas Lahtinen Date: Tue, 14 Feb 2017 00:10:13 +0200 Subject: [PATCH 046/154] Avoid duplicate "sourceMappingURL=" lines. Avoid duplicate // sourceMappingURL=... lines when minifying AND generating a map. UglifyJS2 will write the line when minifying. --- lib/precompiler.js | 3 --- spec/precompiler.js | 4 ++-- 2 files changed, 2 insertions(+), 5 deletions(-) diff --git a/lib/precompiler.js b/lib/precompiler.js index a20d1419d..6ba3800cb 100644 --- a/lib/precompiler.js +++ b/lib/precompiler.js @@ -250,9 +250,6 @@ module.exports.cli = function(opts) { outSourceMap: opts.map, inSourceMap: JSON.parse(output.map) }); - if (opts.map) { - output.code += '\n//# sourceMappingURL=' + opts.map + '\n'; - } } if (opts.map) { diff --git a/spec/precompiler.js b/spec/precompiler.js index f9759a9ce..006a37e39 100644 --- a/spec/precompiler.js +++ b/spec/precompiler.js @@ -152,14 +152,14 @@ describe('precompiler', function() { Precompiler.cli({templates: [emptyTemplate], map: 'foo.js.map'}); equal(file, 'foo.js.map'); - equal(/sourceMappingURL=/.test(log), true); + equal(log.match(/sourceMappingURL=/g).length, 1); }); it('should output map', function() { Precompiler.cli({templates: [emptyTemplate], min: true, map: 'foo.js.map'}); equal(file, 'foo.js.map'); - equal(/sourceMappingURL=/.test(log), true); + equal(log.match(/sourceMappingURL=/g).length, 1); }); describe('#loadTemplates', function() { From 911e676af477f24b376462db80e0063c8d07d3d6 Mon Sep 17 00:00:00 2001 From: Nils Knappmeier Date: Tue, 14 Feb 2017 23:10:02 +0100 Subject: [PATCH 047/154] Merge branch '4.x' # Conflicts: # Gruntfile.js # lib/handlebars/exception.js # spec/partials.js # spec/regressions.js --- lib/handlebars/runtime.js | 7 +------ 1 file changed, 1 insertion(+), 6 deletions(-) diff --git a/lib/handlebars/runtime.js b/lib/handlebars/runtime.js index eb5789fc2..310b108e0 100644 --- a/lib/handlebars/runtime.js +++ b/lib/handlebars/runtime.js @@ -197,12 +197,7 @@ export function wrapProgram(container, i, fn, data, declaredBlockParams, blockPa export function resolvePartial(partial, context, options) { if (!partial) { if (options.name === '@partial-block') { - let data = options.data; - while (data['partial-block'] === noop) { - data = data._parent; - } - partial = data['partial-block']; - data['partial-block'] = noop; + partial = options.data['partial-block']; } else { partial = options.partials[options.name]; } From 508347ea9440368efd43f08e05f70435e0e8a9b6 Mon Sep 17 00:00:00 2001 From: Tobias Bieniek Date: Thu, 23 Feb 2017 17:44:31 +0100 Subject: [PATCH 048/154] Parser: Change suffix to use ES6 default module export - This export will be transpiled by Babel for the cjs distribution, but will enable others to use a pure ES6 module distribution - Instanbul: Ignore "parser.js" for coverage reporting. This file was ignored before via annotation, but this has no effect anymore due to the above change - Remove istanbul annotation from `parser-prefix` (@nknapp) Squashed by @nknapp --- .istanbul.yml | 2 +- src/parser-prefix.js | 2 +- src/parser-suffix.js | 3 +-- 3 files changed, 3 insertions(+), 4 deletions(-) diff --git a/.istanbul.yml b/.istanbul.yml index e6911f190..960643ef4 100644 --- a/.istanbul.yml +++ b/.istanbul.yml @@ -1,2 +1,2 @@ instrumentation: - excludes: ['**/spec/**'] + excludes: ['**/spec/**', '**/handlebars/compiler/parser.js'] diff --git a/src/parser-prefix.js b/src/parser-prefix.js index e26b99340..d9ed04116 100644 --- a/src/parser-prefix.js +++ b/src/parser-prefix.js @@ -1 +1 @@ -/* istanbul ignore next */ +// File ignored in coverage tests via setting in .istanbul.yml diff --git a/src/parser-suffix.js b/src/parser-suffix.js index 1f69f7a44..6e4aa20d6 100644 --- a/src/parser-suffix.js +++ b/src/parser-suffix.js @@ -1,2 +1 @@ -exports.__esModule = true; -exports['default'] = handlebars; +export default handlebars; From a5e6afb05de9155597473c8a0d8ccbf988ef1adf Mon Sep 17 00:00:00 2001 From: Godfrey Chan Date: Fri, 10 Mar 2017 15:32:34 -0800 Subject: [PATCH 049/154] Update README to be more accurate Copied from the website at @wycats' request. Addresses #1119. --- README.markdown | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/README.markdown b/README.markdown index 89e3fc59a..4c333eb9f 100644 --- a/README.markdown +++ b/README.markdown @@ -4,10 +4,8 @@ Handlebars.js ============= -Handlebars.js is an extension to the [Mustache templating -language](http://mustache.github.com/) created by Chris Wanstrath. -Handlebars.js and Mustache are both logicless templating languages that -keep the view and the code separated like we all know they should be. +Handlebars provides the power necessary to let you build **semantic templates** effectively with no frustration. +Handlebars is largely compatible with Mustache templates. In most cases it is possible to swap out Mustache with Handlebars and continue using your current templates. Checkout the official Handlebars docs site at [http://www.handlebarsjs.com](http://www.handlebarsjs.com) and the live demo at [http://tryhandlebarsjs.com/](http://tryhandlebarsjs.com/). From b6e2f76a454a9d9333f4a0d0469e7b20aa9b53f3 Mon Sep 17 00:00:00 2001 From: Robin Houston Date: Mon, 13 Mar 2017 22:03:14 +0000 Subject: [PATCH 050/154] Document whitespace compatibility difference with mustache --- README.markdown | 1 + 1 file changed, 1 insertion(+) diff --git a/README.markdown b/README.markdown index 4c333eb9f..bfcf8be2b 100644 --- a/README.markdown +++ b/README.markdown @@ -68,6 +68,7 @@ Block expressions have the same syntax as mustache sections but should not be co There are a few Mustache behaviors that Handlebars does not implement. - Handlebars deviates from Mustache slightly in that it does not perform recursive lookup by default. The compile time `compat` flag must be set to enable this functionality. Users should note that there is a performance cost for enabling this flag. The exact cost varies by template, but it's recommended that performance sensitive operations should avoid this mode and instead opt for explicit path references. - The optional Mustache-style lambdas are not supported. Instead Handlebars provides its own lambda resolution that follows the behaviors of helpers. +- Handlebars does not allow space between the opening `{{` and a command character such as `#`, `/` or `>`. The command character must immediately follow the braces, so for example `{{> partial }}` is allowed but `{{ > partial }}` is not. - Alternative delimiters are not supported. From 58ec656fbc7fe7fdde1f731d0dcd52b688922c25 Mon Sep 17 00:00:00 2001 From: Nils Knappmeier Date: Sun, 30 Apr 2017 19:30:09 +0200 Subject: [PATCH 051/154] Bump version in master-branch to 5.0-alpha.1 This is in order to make sure that the master-branch version is not confused with the stable 4.x --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index e004f0c36..b9073bedd 100644 --- a/package.json +++ b/package.json @@ -1,7 +1,7 @@ { "name": "handlebars", "barename": "handlebars", - "version": "4.0.7", + "version": "5.0.0-alpha.1", "description": "Handlebars provides the power necessary to let you build semantic templates effectively with no frustration", "homepage": "http://www.handlebarsjs.com/", "keywords": [ From 228950169dbd3ed03e025680c46c6b9b736a1cf0 Mon Sep 17 00:00:00 2001 From: Nils Knappmeier Date: Sat, 13 May 2017 08:33:14 +0200 Subject: [PATCH 052/154] Update jsfiddle-link in CONTRIBUTING.md to 4.0.8 --- CONTRIBUTING.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 1ea246649..13d1b4515 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -96,4 +96,4 @@ After this point the handlebars site needs to be updated to point to the new ver [generator-release]: https://github.com/walmartlabs/generator-release [pull-request]: https://github.com/wycats/handlebars.js/pull/new/master [issue]: https://github.com/wycats/handlebars.js/issues/new -[jsfiddle]: https://jsfiddle.net/9D88g/47/ +[jsfiddle]: https://jsfiddle.net/9D88g/95/ From 64002dc506e35c61d897d2685145d723f2659d28 Mon Sep 17 00:00:00 2001 From: Davide Mancuso Date: Tue, 30 May 2017 15:12:17 +0200 Subject: [PATCH 053/154] Update README.markdown Add incremental-bars to the list of projects using Handlebars --- README.markdown | 1 + 1 file changed, 1 insertion(+) diff --git a/README.markdown b/README.markdown index bfcf8be2b..09daebe25 100644 --- a/README.markdown +++ b/README.markdown @@ -151,6 +151,7 @@ Handlebars in the Wild * [DOMBars](https://github.com/blakeembrey/dombars) is a DOM-based templating engine built on the Handlebars parser and runtime **DEPRECATED** * [promised-handlebars](https://github.com/nknapp/promised-handlebars) is a wrapper for Handlebars that allows helpers to return Promises. * [just-handlebars-helpers](https://github.com/leapfrogtechnology/just-handlebars-helpers) A fully tested lightweight package with common Handlebars helpers. +* [incremental-bars](https://github.com/atomictag/incremental-bars) adds support for [incremental-dom](https://github.com/google/incremental-dom) as template target to Handlebars. External Resources ------------------ From 1a78717286bcdd7655f3d3702081e6fc4c0d2f22 Mon Sep 17 00:00:00 2001 From: John Kreitlow Date: Mon, 31 Jul 2017 11:30:16 -0400 Subject: [PATCH 054/154] Fix Commits links in release-notes --- release-notes.md | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/release-notes.md b/release-notes.md index 4db22231d..139dd5a47 100644 --- a/release-notes.md +++ b/release-notes.md @@ -2,14 +2,14 @@ ## Development -[Commits](https://github.com/nknapp/handlebars.js/compare/v4.0.10...master) +[Commits](https://github.com/wycats/handlebars.js/compare/v4.0.10...master) ## v4.0.10 - May 21st, 2017 - Fix regression in 4.0.9: Replace "Object.assign" (not support in IE) by "util/extend" - 0e953d1 -[Commits](https://github.com/nknapp/handlebars.js/compare/v4.0.9...v4.0.10) +[Commits](https://github.com/wycats/handlebars.js/compare/v4.0.9...v4.0.10) ## v4.0.9 - May 21st, 2017 @@ -26,7 +26,7 @@ Compatibility notes: - No compatibility issues are expected. -[Commits](https://github.com/nknapp/handlebars.js/compare/v4.0.8...v4.0.9) +[Commits](https://github.com/wycats/handlebars.js/compare/v4.0.8...v4.0.9) ## v4.0.8 - May 2nd, 2017 - [#1341](https://github.com/wycats/handlebars.js/issues/1341) [#1342](https://github.com/wycats/handlebars.js/issues/1342) Allow partial-blocks to be executed without "options" ([@nknapp](https://github.com/nknapp)) - a00c598 @@ -34,7 +34,7 @@ Compatibility notes: Compatibility notes: - No breaking changes -[Commits](https://github.com/nknapp/handlebars.js/compare/v4.0.7...v4.0.8) +[Commits](https://github.com/wycats/handlebars.js/compare/v4.0.7...v4.0.8) ## v4.0.7 - April 29th, 2017 - [#1319](https://github.com/wycats/handlebars.js/issues/1319): Fix context-stack when calling block-helpers on null values ([@nknapp](https://github.com/nknapp)) - c8f4b57 From c9333874156882b8144d5a90acab92f2679e21c8 Mon Sep 17 00:00:00 2001 From: Mike Date: Wed, 16 Aug 2017 16:06:54 -0600 Subject: [PATCH 055/154] Fix broken header tag (markdown) The # was too close to the header text. --- CONTRIBUTING.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 42cdc56d6..090798514 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -42,7 +42,7 @@ The `grunt dev` implements watching for tests and allows for in browser testing If you notice any problems, please report them to the GitHub issue tracker at [http://github.com/wycats/handlebars.js/issues](http://github.com/wycats/handlebars.js/issues). -##Running Tests +## Running Tests To run tests locally, first install all dependencies. ```sh From 33773c2cb214221241a6d26730bebc845674206e Mon Sep 17 00:00:00 2001 From: Marcos Marado Date: Thu, 5 Oct 2017 17:44:35 +0100 Subject: [PATCH 056/154] Update (C) year in the LICENSE file Welcome to 2017! --- LICENSE | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/LICENSE b/LICENSE index 307ebc1c2..b802d14e7 100644 --- a/LICENSE +++ b/LICENSE @@ -1,4 +1,4 @@ -Copyright (C) 2011-2016 by Yehuda Katz +Copyright (C) 2011-2017 by Yehuda Katz Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal From ce3cd8a6854f97237af818887e0c0aa79c59e024 Mon Sep 17 00:00:00 2001 From: Nils Knappmeier Date: Thu, 24 Aug 2017 22:16:21 +0200 Subject: [PATCH 057/154] Extend compiler-api example by replacing child-compiler closes #1376 --- docs/compiler-api.md | 13 ++++++++++--- 1 file changed, 10 insertions(+), 3 deletions(-) diff --git a/docs/compiler-api.md b/docs/compiler-api.md index a0478dea5..f419fbcd2 100644 --- a/docs/compiler-api.md +++ b/docs/compiler-api.md @@ -300,7 +300,7 @@ The `Handlebars.JavaScriptCompiler` object has a number of methods that may be c This example changes all lookups of properties are performed by a helper (`lookupLowerCase`) which looks for `test` if `{{Test}}` occurs in the template. This is just to illustrate how compiler behavior can be change. -There is also [a jsfiddle with this code](https://jsfiddle.net/9D88g/85/) if you want to play around with it. +There is also [a jsfiddle with this code](https://jsfiddle.net/9D88g/162/) if you want to play around with it. ```javascript @@ -309,6 +309,9 @@ function MyCompiler() { } MyCompiler.prototype = new Handlebars.JavaScriptCompiler(); +// Use this compile to compile BlockStatment-Blocks +MyCompiler.prototype.compiler = MyCompiler + MyCompiler.prototype.nameLookup = function(parent, name, type) { if (type === 'context') { return this.source.functionCall('helpers.lookupLowerCase', '', [parent, JSON.stringify(name)]) @@ -324,8 +327,12 @@ env.registerHelper('lookupLowerCase', function(parent, name) { env.JavaScriptCompiler = MyCompiler; -var template = env.compile('{{#each Test}}{{.}} {{/each}}'); +var template = env.compile('{{#each Test}} ({{Value}}) {{/each}}'); console.log(template({ - test: [ "a","b","c"] + test: [ + {value: 'a'}, + {value: 'b'}, + {value: 'c'} + ] })); ``` From d5caa56d6cb9484cd67b60424a9d992636a8c93b Mon Sep 17 00:00:00 2001 From: Nils Knappmeier Date: Fri, 13 Oct 2017 23:54:53 +0200 Subject: [PATCH 058/154] Gracefully handle missing uglify-js dependency closes #1391 uglify-js is an optional dependency and should be treated as such. This commit gracefully handles MODULE_NOT_FOUND errors while loading uglify. - Check for existing uglify-js (and load uglify-js) only if minification was activated - Use "require.resolve" to check if uglify exists. Otherwise, a missing dependency of uglify-js would cause the same behavior as missing uglify-js. (Only a warning, no error) - The code to load and run uglify is put into a single for readability purposes - Tests use a mockup Module._resolveFilename to simulate the missing module. This function is used by both "require" and "require.resolve", so both are mocked equally. --- lib/precompiler.js | 40 +++++++++++++++++++++++------ spec/precompiler.js | 61 +++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 93 insertions(+), 8 deletions(-) diff --git a/lib/precompiler.js b/lib/precompiler.js index 6ba3800cb..64608f1e9 100644 --- a/lib/precompiler.js +++ b/lib/precompiler.js @@ -4,7 +4,7 @@ import fs from 'fs'; import * as Handlebars from './handlebars'; import {basename} from 'path'; import {SourceMapConsumer, SourceNode} from 'source-map'; -import uglify from 'uglify-js'; + module.exports.loadTemplates = function(opts, callback) { loadStrings(opts, function(err, strings) { @@ -235,7 +235,6 @@ module.exports.cli = function(opts) { } } - if (opts.map) { output.add('\n//# sourceMappingURL=' + opts.map + '\n'); } @@ -244,12 +243,7 @@ module.exports.cli = function(opts) { output.map = output.map + ''; if (opts.min) { - output = uglify.minify(output.code, { - fromString: true, - - outSourceMap: opts.map, - inSourceMap: JSON.parse(output.map) - }); + output = minify(output, opts.map); } if (opts.map) { @@ -271,3 +265,33 @@ function arrayCast(value) { } return value; } + +/** + * Run uglify to minify the compiled template, if uglify exists in the dependencies. + * + * We are using `require` instead of `import` here, because es6-modules do not allow + * dynamic imports and uglify-js is an optional dependency. Since we are inside NodeJS here, this + * should not be a problem. + * + * @param {string} output the compiled template + * @param {string} sourceMapFile the file to write the source map to. + */ +function minify(output, sourceMapFile) { + try { + // Try to resolve uglify-js in order to see if it does exist + require.resolve('uglify-js'); + } catch (e) { + if (e.code !== 'MODULE_NOT_FOUND') { + // Something else seems to be wrong + throw e; + } + // it does not exist! + console.error('Code minimization is disabled due to missing uglify-js dependency'); + return output; + } + return require('uglify-js').minify(output.code, { + fromString: true, + outSourceMap: sourceMapFile, + inSourceMap: JSON.parse(output.map) + }); +} diff --git a/spec/precompiler.js b/spec/precompiler.js index 006a37e39..9f2a6442b 100644 --- a/spec/precompiler.js +++ b/spec/precompiler.js @@ -12,6 +12,8 @@ describe('precompiler', function() { var log, logFunction, + errorLog, + errorLogFunction, precompile, minify, @@ -26,16 +28,51 @@ describe('precompiler', function() { content, writeFileSync; + /** + * Mock the Module.prototype.require-function such that an error is thrown, when "uglify-js" is loaded. + * + * The function cleans up its mess when "callback" is finished + * + * @param {Error} loadError the error that should be thrown if uglify is loaded + * @param {function} callback a callback-function to run when the mock is active. + */ + function mockRequireUglify(loadError, callback) { + var Module = require('module'); + var _resolveFilename = Module._resolveFilename; + delete require.cache[require.resolve('uglify-js')]; + delete require.cache[require.resolve('../dist/cjs/precompiler')]; + Module._resolveFilename = function(request, mod) { + if (request === 'uglify-js') { + throw loadError; + } + return _resolveFilename.call(this, request, mod); + }; + try { + callback(); + } finally { + Module._resolveFilename = _resolveFilename; + delete require.cache[require.resolve('uglify-js')]; + delete require.cache[require.resolve('../dist/cjs/precompiler')]; + } + } + beforeEach(function() { precompile = Handlebars.precompile; minify = uglify.minify; writeFileSync = fs.writeFileSync; + // Mock stdout and stderr logFunction = console.log; log = ''; console.log = function() { log += Array.prototype.join.call(arguments, ''); }; + errorLogFunction = console.error; + errorLog = ''; + console.error = function() { + errorLog += Array.prototype.join.call(arguments, ''); + }; + fs.writeFileSync = function(_file, _content) { file = _file; content = _content; @@ -46,6 +83,7 @@ describe('precompiler', function() { uglify.minify = minify; fs.writeFileSync = writeFileSync; console.log = logFunction; + console.error = errorLogFunction; }); it('should output version', function() { @@ -148,6 +186,29 @@ describe('precompiler', function() { equal(log, 'min'); }); + it('should omit minimization gracefully, if uglify-js is missing', function() { + var error = new Error("Cannot find module 'uglify-js'"); + error.code = 'MODULE_NOT_FOUND'; + mockRequireUglify(error, function() { + var Precompiler = require('../dist/cjs/precompiler'); + Handlebars.precompile = function() { return 'amd'; }; + Precompiler.cli({templates: [emptyTemplate], min: true}); + equal(/template\(amd\)/.test(log), true); + equal(/\n/.test(log), true); + equal(/Code minimization is disabled/.test(errorLog), true); + }); + }); + + it('should fail on errors (other than missing module) while loading uglify-js', function() { + mockRequireUglify(new Error('Mock Error'), function() { + shouldThrow(function() { + var Precompiler = require('../dist/cjs/precompiler'); + Handlebars.precompile = function() { return 'amd'; }; + Precompiler.cli({templates: [emptyTemplate], min: true}); + }, Error, 'Mock Error'); + }); + }); + it('should output map', function() { Precompiler.cli({templates: [emptyTemplate], map: 'foo.js.map'}); From 999220bf2d8ab0be256b3d66ba3316484349a489 Mon Sep 17 00:00:00 2001 From: Lukas Drgon Date: Sun, 8 Oct 2017 21:29:24 +0200 Subject: [PATCH 059/154] Add jsDelivr hits badge --- README.markdown | 1 + 1 file changed, 1 insertion(+) diff --git a/README.markdown b/README.markdown index 0ff483e02..02eb1f757 100644 --- a/README.markdown +++ b/README.markdown @@ -1,6 +1,7 @@ [![Travis Build Status](https://img.shields.io/travis/wycats/handlebars.js/master.svg)](https://travis-ci.org/wycats/handlebars.js) [![Appveyor Build Status](https://ci.appveyor.com/api/projects/status/github/wycats/handlebars.js?branch=master&svg=true)](https://ci.appveyor.com/project/wycats/handlebars-js) [![Selenium Test Status](https://saucelabs.com/buildstatus/handlebars)](https://saucelabs.com/u/handlebars) +[![jsDelivr Hits](https://data.jsdelivr.com/v1/package/npm/handlebars/badge?style=rounded)](https://www.jsdelivr.com/package/npm/handlebars) Handlebars.js ============= From e1fa3101018064949065696e1955ea99b5cb3e3d Mon Sep 17 00:00:00 2001 From: Qiang Li Date: Fri, 30 Mar 2018 18:39:22 -0700 Subject: [PATCH 060/154] unnecessary check --- lib/handlebars/compiler/compiler.js | 3 --- 1 file changed, 3 deletions(-) diff --git a/lib/handlebars/compiler/compiler.js b/lib/handlebars/compiler/compiler.js index 34ef5dd18..8374f031a 100644 --- a/lib/handlebars/compiler/compiler.js +++ b/lib/handlebars/compiler/compiler.js @@ -66,10 +66,7 @@ Compiler.prototype = { }; if (knownHelpers) { for (let name in knownHelpers) { - /* istanbul ignore else */ - if (name in knownHelpers) { this.options.knownHelpers[name] = knownHelpers[name]; - } } } From d7d14ed6e537b10a2d60c79c73594cc2897dd0be Mon Sep 17 00:00:00 2001 From: Sharang Dashputre Date: Tue, 11 Sep 2018 09:17:18 +0530 Subject: [PATCH 061/154] Remove duplicate text in release-notes.md [ci skip] --- release-notes.md | 58 ------------------------------------------------ 1 file changed, 58 deletions(-) diff --git a/release-notes.md b/release-notes.md index 8af103799..782aace3f 100644 --- a/release-notes.md +++ b/release-notes.md @@ -31,64 +31,6 @@ Removed obsolete code: Compatibility notes: - No compatibility issues are to be expected -[Commits](https://github.com/wycats/handlebars.js/compare/v4.0.12...v4.0.12) - -## v4.0.12 - September 4th, 2018 -New features: - -- none - -Various dependency updates - -- [#1464](https://github.com/wycats/handlebars.js/pull/1464) - Bump versions of grunt-plugins to 1.x -- [#1398](https://github.com/wycats/handlebars.js/pull/1398) - Chore: updated various dev dependencies -- upgrade uglify-js - d3d3942 -- Update grunt-eslint to 20.1.0 - 7729aa9 -- Update dependencies "async" to 2.5.0 and "source-map" to 0.6.1 (73d5637) - -Bugfixes: - -- [components/handlebars.js#24](https://github.com/components/handlebars.js#24) Add package.json to components shim -- Updated `source-map`-package should work better with `rollup`[#1463](https://github.com/wycats/handlebars.js/issues/1463) - -Removed obsolete code: - -- unnecessary check - 0ddff8b -- Use `files` field - 69c6ca5 -- Update jsfiddle to 4.0.11 - 8947dd0 - -Compatibility notes: -- No compatibility issues are to be expected - -[Commits](https://github.com/wycats/handlebars.js/compare/v4.0.12...v4.0.12) - -## v4.0.12 - September 4th, 2018 -New features: - -- none - -Various dependency updates - -- [#1464](https://github.com/wycats/handlebars.js/pull/1464) - Bump versions of grunt-plugins to 1.x -- [#1398](https://github.com/wycats/handlebars.js/pull/1398) - Chore: updated various dev dependencies -- upgrade uglify-js - d3d3942 -- Update grunt-eslint to 20.1.0 - 7729aa9 -- Update dependencies "async" to 2.5.0 and "source-map" to 0.6.1 (73d5637) - -Bugfixes: - -- [components/handlebars.js#24](https://github.com/components/handlebars.js#24) Add package.json to components shim -- Updated `source-map`-package should work better with `rollup`[#1463](https://github.com/wycats/handlebars.js/issues/1463) - -Removed obsolete code: - -- unnecessary check - 0ddff8b -- Use `files` field - 69c6ca5 -- Update jsfiddle to 4.0.11 - 8947dd0 - -Compatibility notes: -- No compatibility issues are to be expected - [Commits](https://github.com/wycats/handlebars.js/compare/v4.0.11...v4.0.12) ## v4.0.11 - October 17th, 2017 From 913b845aa9c0ca1ec2ea75f1be94bfdb7e09d54c Mon Sep 17 00:00:00 2001 From: Nils Knappmeier Date: Wed, 2 Jan 2019 01:18:18 +0100 Subject: [PATCH 062/154] chore: bump components/handlebars.js versions to 5.0.0-alpha.1 --- components/bower.json | 2 +- components/handlebars.js.nuspec | 2 +- components/package.json | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/components/bower.json b/components/bower.json index 2bf984f20..b63db67a9 100644 --- a/components/bower.json +++ b/components/bower.json @@ -1,6 +1,6 @@ { "name": "handlebars", - "version": "4.0.12", + "version": "5.0.0-alpha.1", "main": "handlebars.js", "license": "MIT", "dependencies": {} diff --git a/components/handlebars.js.nuspec b/components/handlebars.js.nuspec index bb463ce5f..43da56977 100644 --- a/components/handlebars.js.nuspec +++ b/components/handlebars.js.nuspec @@ -2,7 +2,7 @@ handlebars.js - 4.0.12 + 5.0.0-alpha.1 handlebars.js Authors https://github.com/wycats/handlebars.js/blob/master/LICENSE https://github.com/wycats/handlebars.js/ diff --git a/components/package.json b/components/package.json index a81e45d96..035274544 100644 --- a/components/package.json +++ b/components/package.json @@ -1,6 +1,6 @@ { "name": "handlebars", - "version": "4.0.12", + "version": "5.0.0-alpha.1", "license": "MIT", "jspm": { "main": "handlebars", From 16c654579a2295850ad13787680d1f62cb17626e Mon Sep 17 00:00:00 2001 From: Nils Knappmeier Date: Fri, 8 Feb 2019 12:49:10 +0100 Subject: [PATCH 063/154] docs: include typings in PR-template --- .github/PULL_REQUEST_TEMPLATE.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/PULL_REQUEST_TEMPLATE.md b/.github/PULL_REQUEST_TEMPLATE.md index 8d8437ee7..5e3072191 100644 --- a/.github/PULL_REQUEST_TEMPLATE.md +++ b/.github/PULL_REQUEST_TEMPLATE.md @@ -6,6 +6,6 @@ Generally we like to see pull requests that - [ ] Are focused on a single change (i.e. avoid large refactoring or style adjustments in untouched code if not the primary goal of the pull request) - [ ] Have good commit messages - [ ] Have tests +- [ ] Have the [typings](https://www.typescriptlang.org/docs/handbook/declaration-files/introduction.html) (lib/handlebars.d.ts) updated on every API change. If you need help, updating those, please mention that in the PR description. - [ ] Don't significantly decrease the current code coverage (see coverage/lcov-report/index.html) - - +- [ ] Currently, the `4.x`-branch contains the latest version. Please target that branch in the PR. \ No newline at end of file From 3fc7e6feb2810c3315c48cd0c1ab1bfdf3caba2f Mon Sep 17 00:00:00 2001 From: Nils Knappmeier Date: Sun, 17 Feb 2019 20:50:34 +0100 Subject: [PATCH 064/154] chore: add text about security advisories to github templates --- .github/ISSUE_TEMPLATE.md | 1 + .github/PULL_REQUEST_TEMPLATE.md | 1 + 2 files changed, 2 insertions(+) diff --git a/.github/ISSUE_TEMPLATE.md b/.github/ISSUE_TEMPLATE.md index 782cf3d59..69a984770 100644 --- a/.github/ISSUE_TEMPLATE.md +++ b/.github/ISSUE_TEMPLATE.md @@ -1,5 +1,6 @@ Before filing issues, please check the following points first: +- [ ] Please don't open issues for security issues. Instead, file a report at https://www.npmjs.com/advisories/report?package=handlebars - [ ] Have a look at https://github.com/wycats/handlebars.js/blob/master/CONTRIBUTING.md - [ ] Read the FAQ at https://github.com/wycats/handlebars.js/blob/master/FAQ.md - [ ] Use the jsfiddle-template at https://jsfiddle.net/9D88g/47/ to reproduce problems or bugs diff --git a/.github/PULL_REQUEST_TEMPLATE.md b/.github/PULL_REQUEST_TEMPLATE.md index 5e3072191..7a6428b20 100644 --- a/.github/PULL_REQUEST_TEMPLATE.md +++ b/.github/PULL_REQUEST_TEMPLATE.md @@ -2,6 +2,7 @@ Before creating a pull-request, please check https://github.com/wycats/handlebar Generally we like to see pull requests that +- [ ] Please don't start pull requests for security issues. Instead, file a report at https://www.npmjs.com/advisories/report?package=handlebars - [ ] Maintain the existing code style - [ ] Are focused on a single change (i.e. avoid large refactoring or style adjustments in untouched code if not the primary goal of the pull request) - [ ] Have good commit messages From 1b04524a530e36596452eee09c5108666e092835 Mon Sep 17 00:00:00 2001 From: manishsaraan Date: Sat, 29 Sep 2018 12:57:30 +0530 Subject: [PATCH 065/154] apiDoc added in list --- README.markdown | 1 + 1 file changed, 1 insertion(+) diff --git a/README.markdown b/README.markdown index 02eb1f757..d5b17fa4b 100644 --- a/README.markdown +++ b/README.markdown @@ -154,6 +154,7 @@ Handlebars in the Wild * [promised-handlebars](https://github.com/nknapp/promised-handlebars) is a wrapper for Handlebars that allows helpers to return Promises. * [just-handlebars-helpers](https://github.com/leapfrogtechnology/just-handlebars-helpers) A fully tested lightweight package with common Handlebars helpers. * [incremental-bars](https://github.com/atomictag/incremental-bars) adds support for [incremental-dom](https://github.com/google/incremental-dom) as template target to Handlebars. +* [apiDoc](https://github.com/apidoc/apidoc) apiDoc uses handlebars as parsing engine for api documentation view generation. External Resources ------------------ From 2f8aa1c839535d5dbbdd9b10812687fe588240d4 Mon Sep 17 00:00:00 2001 From: Nils Knappmeier Date: Sat, 13 Apr 2019 16:49:52 +0200 Subject: [PATCH 066/154] chore: update jsfiddle link --- CONTRIBUTING.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index e321c0ef7..8ea9dd9f9 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -112,4 +112,4 @@ When everything is OK, the handlebars site needs to be updated to point to the n [generator-release]: https://github.com/walmartlabs/generator-release [pull-request]: https://github.com/wycats/handlebars.js/pull/new/master [issue]: https://github.com/wycats/handlebars.js/issues/new -[jsfiddle]: https://jsfiddle.net/9D88g/180/ +[jsfiddle]: https://jsfiddle.net/08v3cbg4/ From 3ce4425056998c1db921d7b6c0662b843acb593b Mon Sep 17 00:00:00 2001 From: Nils Knappmeier Date: Sat, 13 Apr 2019 16:51:22 +0200 Subject: [PATCH 067/154] chore: udpate package-lock.json --- package-lock.json | 298 +++++++++++++++++++++++++++++++++++----------- 1 file changed, 228 insertions(+), 70 deletions(-) diff --git a/package-lock.json b/package-lock.json index bb74117ea..9ab8923d5 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,6 +1,6 @@ { "name": "handlebars", - "version": "4.1.1", + "version": "5.0.0-alpha.1", "lockfileVersion": 1, "requires": true, "dependencies": { @@ -16,6 +16,12 @@ "integrity": "sha1-oI7cxn6z/L6Z7WMIVTRKDPKCu40=", "dev": true }, + "JSV": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/JSV/-/JSV-4.0.2.tgz", + "integrity": "sha1-0Hf2glVx+CEy+d/67Vh7QCn+/1c=", + "dev": true + }, "abbrev": { "version": "1.1.1", "resolved": "https://registry.npmjs.org/abbrev/-/abbrev-1.1.1.tgz", @@ -117,8 +123,7 @@ "ansi-regex": { "version": "2.1.1", "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-2.1.1.tgz", - "integrity": "sha1-w7M6te42DYbg5ijwRorn7yfWVN8=", - "dev": true + "integrity": "sha1-w7M6te42DYbg5ijwRorn7yfWVN8=" }, "ansi-styles": { "version": "2.2.1", @@ -919,6 +924,15 @@ "integrity": "sha512-UZK3NBx2Mca+b5LsG7bY183pHWt5Y1xts4P3Pz7ENTwGVnJOUWbRb3ocjvX7hx9tq/yTAdclXm9sZ38gNuem4A==", "dev": true }, + "cjson": { + "version": "0.3.0", + "resolved": "https://registry.npmjs.org/cjson/-/cjson-0.3.0.tgz", + "integrity": "sha1-5kObkHA9MS/24iJAl76pLOPQKhQ=", + "dev": true, + "requires": { + "jsonlint": "1.6.0" + } + }, "class-utils": { "version": "0.3.6", "resolved": "https://registry.npmjs.org/class-utils/-/class-utils-0.3.6.tgz", @@ -1032,8 +1046,7 @@ "code-point-at": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/code-point-at/-/code-point-at-1.1.0.tgz", - "integrity": "sha1-DQcLTQQ6W+ozovGkDi7bPZpMz3c=", - "dev": true + "integrity": "sha1-DQcLTQQ6W+ozovGkDi7bPZpMz3c=" }, "coffee-script": { "version": "1.12.7", @@ -1350,8 +1363,7 @@ "decamelize": { "version": "1.2.0", "resolved": "https://registry.npmjs.org/decamelize/-/decamelize-1.2.0.tgz", - "integrity": "sha1-9lNNFRSCabIDUue+4m9QH5oZEpA=", - "dev": true + "integrity": "sha1-9lNNFRSCabIDUue+4m9QH5oZEpA=" }, "decode-uri-component": { "version": "0.2.0", @@ -1450,6 +1462,22 @@ "stringset": "~0.2.1", "tryor": "~0.1.2", "yargs": "~3.27.0" + }, + "dependencies": { + "yargs": { + "version": "3.27.0", + "resolved": "https://registry.npmjs.org/yargs/-/yargs-3.27.0.tgz", + "integrity": "sha1-ISBUaTFuk5Ex1Z8toMbX+YIh6kA=", + "dev": true, + "requires": { + "camelcase": "^1.2.1", + "cliui": "^2.1.0", + "decamelize": "^1.0.0", + "os-locale": "^1.4.0", + "window-size": "^0.1.2", + "y18n": "^3.2.0" + } + } } }, "delayed-stream": { @@ -1651,6 +1679,12 @@ "cli": "^1.0.1" } }, + "ebnf-parser": { + "version": "0.1.10", + "resolved": "https://registry.npmjs.org/ebnf-parser/-/ebnf-parser-0.1.10.tgz", + "integrity": "sha1-zR9rpHfFY4xAyX7ZtXLbW6tdgzE=", + "dev": true + }, "ecc-jsbn": { "version": "0.1.2", "resolved": "https://registry.npmjs.org/ecc-jsbn/-/ecc-jsbn-0.1.2.tgz", @@ -3759,32 +3793,15 @@ } }, "handlebars": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/handlebars/-/handlebars-4.1.0.tgz", - "integrity": "sha512-l2jRuU1NAWK6AW5qqcTATWQJvNPEwkM7NEKSiv/gqOsoSQbVoWyqVEY5GS+XPQ88zLNmqASRpzfdm8d79hJS+w==", + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/handlebars/-/handlebars-4.1.2.tgz", + "integrity": "sha512-nvfrjqvt9xQ8Z/w0ijewdD/vvWDTOweBUm96NTr66Wfvo1mJenBLwcYmPs3TIBP5ruzYGD7Hx/DaM9RmhroGPw==", "dev": true, "requires": { - "async": "^2.5.0", + "neo-async": "^2.6.0", "optimist": "^0.6.1", "source-map": "^0.6.1", "uglify-js": "^3.1.4" - }, - "dependencies": { - "async": { - "version": "2.6.2", - "resolved": "https://registry.npmjs.org/async/-/async-2.6.2.tgz", - "integrity": "sha512-H1qVYh1MYhEEFLsP97cVKqCGo7KfCyTt6uEWqsTBr9SO84oK9Uwbyd/yCW+6rKJLHksBNUVWZDAjfS+Ccx0Bbg==", - "dev": true, - "requires": { - "lodash": "^4.17.11" - } - }, - "lodash": { - "version": "4.17.11", - "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.11.tgz", - "integrity": "sha512-cQKh8igo5QUhZ7lg38DYWAxMvjSAKG0A8wGSVimP07SIUEK2UO+arSRKbRZWtelMtN5V0Hkwh5ryOto/SshYIg==", - "dev": true - } } }, "har-schema": { @@ -4230,8 +4247,7 @@ "invert-kv": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/invert-kv/-/invert-kv-1.0.0.tgz", - "integrity": "sha1-EEqOSqym09jNFXqO+L+rLXo//bY=", - "dev": true + "integrity": "sha1-EEqOSqym09jNFXqO+L+rLXo//bY=" }, "ipaddr.js": { "version": "1.8.0", @@ -4487,13 +4503,13 @@ "dev": true }, "istanbul": { - "version": "0.3.22", - "resolved": "https://registry.npmjs.org/istanbul/-/istanbul-0.3.22.tgz", - "integrity": "sha1-PhZNhQIf4ZyYXR8OfvDD4i0BLrY=", + "version": "github:kpdecker/istanbul#dd1228d2f0a6e8506cbb5dba398a8297b1dbaf22", + "from": "github:kpdecker/istanbul", "dev": true, "requires": { "abbrev": "1.0.x", "async": "1.x", + "convert-source-map": "^1.1.1", "escodegen": "1.7.x", "esprima": "2.5.x", "fileset": "0.2.x", @@ -4503,6 +4519,8 @@ "nopt": "3.x", "once": "1.x", "resolve": "1.1.x", + "source-map": "^0.4.4", + "source-map-support": "^0.3.2", "supports-color": "^3.1.0", "which": "^1.1.1", "wordwrap": "^1.0.0" @@ -4532,6 +4550,35 @@ "integrity": "sha1-IDEU2CrSxe2ejgQRs5ModeiJ6Xs=", "dev": true }, + "source-map": { + "version": "0.4.4", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.4.4.tgz", + "integrity": "sha1-66T12pwNyZneaAMti092FzZSA2s=", + "dev": true, + "requires": { + "amdefine": ">=0.0.4" + } + }, + "source-map-support": { + "version": "0.3.3", + "resolved": "https://registry.npmjs.org/source-map-support/-/source-map-support-0.3.3.tgz", + "integrity": "sha1-NJAJd9W6PwfHdX7nLnO7GptTdU8=", + "dev": true, + "requires": { + "source-map": "0.1.32" + }, + "dependencies": { + "source-map": { + "version": "0.1.32", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.1.32.tgz", + "integrity": "sha1-yLbBZ3l7pHQKjqMyUhYv8IWRsmY=", + "dev": true, + "requires": { + "amdefine": ">=0.0.4" + } + } + } + }, "supports-color": { "version": "3.2.3", "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-3.2.3.tgz", @@ -4550,14 +4597,71 @@ } }, "jison": { - "version": "0.3.12", - "resolved": "https://registry.npmjs.org/jison/-/jison-0.3.12.tgz", - "integrity": "sha1-IN1EjuvCxWneJdDBMGL34adzNaI=", + "version": "0.4.16", + "resolved": "https://registry.npmjs.org/jison/-/jison-0.4.16.tgz", + "integrity": "sha1-EzcQP1lJ8O1xWTmUJohc4QzBYLU=", "dev": true, "requires": { "JSONSelect": "0.4.0", - "nomnom": "0.4.3", - "reflect": "0.0.7" + "cjson": "0.3.0", + "ebnf-parser": "0.1.10", + "escodegen": "1.3.x", + "esprima": "1.1.x", + "jison-lex": "0.3.x", + "lex-parser": "~0.1.3", + "nomnom": "1.5.2" + }, + "dependencies": { + "escodegen": { + "version": "1.3.3", + "resolved": "https://registry.npmjs.org/escodegen/-/escodegen-1.3.3.tgz", + "integrity": "sha1-8CQBb1qI4Eb9EgBQVek5gC5sXyM=", + "dev": true, + "requires": { + "esprima": "~1.1.1", + "estraverse": "~1.5.0", + "esutils": "~1.0.0", + "source-map": "~0.1.33" + } + }, + "esprima": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/esprima/-/esprima-1.1.1.tgz", + "integrity": "sha1-W28VR/TRAuZw4UDFCb5ncdautUk=", + "dev": true + }, + "estraverse": { + "version": "1.5.1", + "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-1.5.1.tgz", + "integrity": "sha1-hno+jlip+EYYr7bC3bzZFrfLr3E=", + "dev": true + }, + "esutils": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/esutils/-/esutils-1.0.0.tgz", + "integrity": "sha1-gVHTWOIMisx/t0XnRywAJf5JZXA=", + "dev": true + }, + "source-map": { + "version": "0.1.43", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.1.43.tgz", + "integrity": "sha1-wkvBRspRfBRx9drL4lcbK3+eM0Y=", + "dev": true, + "optional": true, + "requires": { + "amdefine": ">=0.0.4" + } + } + } + }, + "jison-lex": { + "version": "0.3.4", + "resolved": "https://registry.npmjs.org/jison-lex/-/jison-lex-0.3.4.tgz", + "integrity": "sha1-gcoo2E+ESZ36jFlNzePYo/Jux6U=", + "dev": true, + "requires": { + "lex-parser": "0.1.x", + "nomnom": "1.5.2" } }, "jmespath": { @@ -4647,6 +4751,16 @@ "graceful-fs": "^4.1.6" } }, + "jsonlint": { + "version": "1.6.0", + "resolved": "https://registry.npmjs.org/jsonlint/-/jsonlint-1.6.0.tgz", + "integrity": "sha1-iKpGvCiaesk7tGyuLVihh6m7SUo=", + "dev": true, + "requires": { + "JSV": ">= 4.0.x", + "nomnom": ">= 1.5.x" + } + }, "jsprim": { "version": "1.4.1", "resolved": "https://registry.npmjs.org/jsprim/-/jsprim-1.4.1.tgz", @@ -4678,7 +4792,6 @@ "version": "1.0.0", "resolved": "https://registry.npmjs.org/lcid/-/lcid-1.0.0.tgz", "integrity": "sha1-MIrMr6C8SDo4Z7S28rlQYlHRuDU=", - "dev": true, "requires": { "invert-kv": "^1.0.0" } @@ -4699,6 +4812,12 @@ "type-check": "~0.3.2" } }, + "lex-parser": { + "version": "0.1.4", + "resolved": "https://registry.npmjs.org/lex-parser/-/lex-parser-0.1.4.tgz", + "integrity": "sha1-ZMTwJfF/1Tv7RXY/rrFvAVp0dVA=", + "dev": true + }, "liftoff": { "version": "2.5.0", "resolved": "https://registry.npmjs.org/liftoff/-/liftoff-2.5.0.tgz", @@ -5317,7 +5436,8 @@ "minimist": { "version": "0.0.10", "resolved": "https://registry.npmjs.org/minimist/-/minimist-0.0.10.tgz", - "integrity": "sha1-3j+YVD2/lggr5IrRoMfNqDYwHc8=" + "integrity": "sha1-3j+YVD2/lggr5IrRoMfNqDYwHc8=", + "dev": true }, "mixin-deep": { "version": "1.3.1", @@ -5581,12 +5701,27 @@ } }, "nomnom": { - "version": "0.4.3", - "resolved": "https://registry.npmjs.org/nomnom/-/nomnom-0.4.3.tgz", - "integrity": "sha1-bC2xJH3v9vZ1fjVyASOPB9lxhOM=", + "version": "1.5.2", + "resolved": "https://registry.npmjs.org/nomnom/-/nomnom-1.5.2.tgz", + "integrity": "sha1-9DRUSKhTz71cDSYyDyR3qwUm/i8=", "dev": true, "requires": { - "underscore": ">= 1.1.5" + "colors": "0.5.x", + "underscore": "1.1.x" + }, + "dependencies": { + "colors": { + "version": "0.5.1", + "resolved": "https://registry.npmjs.org/colors/-/colors-0.5.1.tgz", + "integrity": "sha1-fQAj6usVTo7p/Oddy5I9DtFmd3Q=", + "dev": true + }, + "underscore": { + "version": "1.1.7", + "resolved": "https://registry.npmjs.org/underscore/-/underscore-1.1.7.tgz", + "integrity": "sha1-QLq4S60Z0jAJbo1u9ii/8FXYPbA=", + "dev": true + } } }, "nopt": { @@ -5631,8 +5766,7 @@ "number-is-nan": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/number-is-nan/-/number-is-nan-1.0.1.tgz", - "integrity": "sha1-CXtgK1NCKlIsGvuHkDGDNpQaAR0=", - "dev": true + "integrity": "sha1-CXtgK1NCKlIsGvuHkDGDNpQaAR0=" }, "oauth-sign": { "version": "0.9.0", @@ -5823,6 +5957,7 @@ "version": "0.6.1", "resolved": "https://registry.npmjs.org/optimist/-/optimist-0.6.1.tgz", "integrity": "sha1-2j6nRob6IaGaERwybpDrFaAZZoY=", + "dev": true, "requires": { "minimist": "~0.0.1", "wordwrap": "~0.0.2" @@ -5875,7 +6010,6 @@ "version": "1.4.0", "resolved": "https://registry.npmjs.org/os-locale/-/os-locale-1.4.0.tgz", "integrity": "sha1-IPnxeuKe00XoveWDsT0gCYA8FNk=", - "dev": true, "requires": { "lcid": "^1.0.0" } @@ -6678,12 +6812,6 @@ "strip-indent": "^1.0.1" } }, - "reflect": { - "version": "0.0.7", - "resolved": "https://registry.npmjs.org/reflect/-/reflect-0.0.7.tgz", - "integrity": "sha1-Zmbty0D+rLEgTsAImeKMcV2vQXw=", - "dev": true - }, "regenerate": { "version": "1.4.0", "resolved": "https://registry.npmjs.org/regenerate/-/regenerate-1.4.0.tgz", @@ -7611,7 +7739,6 @@ "version": "3.0.1", "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-3.0.1.tgz", "integrity": "sha1-ajhfuIU9lS1f8F0Oiq+UJ43GPc8=", - "dev": true, "requires": { "ansi-regex": "^2.0.0" } @@ -8551,19 +8678,18 @@ "window-size": { "version": "0.1.4", "resolved": "https://registry.npmjs.org/window-size/-/window-size-0.1.4.tgz", - "integrity": "sha1-+OGqHuWlPsW/FR/6CXQqatdpeHY=", - "dev": true + "integrity": "sha1-+OGqHuWlPsW/FR/6CXQqatdpeHY=" }, "wordwrap": { "version": "0.0.3", "resolved": "https://registry.npmjs.org/wordwrap/-/wordwrap-0.0.3.tgz", - "integrity": "sha1-o9XabNXAvAAI03I0u68b7WMFkQc=" + "integrity": "sha1-o9XabNXAvAAI03I0u68b7WMFkQc=", + "dev": true }, "wrap-ansi": { "version": "2.1.0", "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-2.1.0.tgz", "integrity": "sha1-2Pw9KE3QV5T+hJc8rs3Rz4JP3YU=", - "dev": true, "requires": { "string-width": "^1.0.1", "strip-ansi": "^3.0.1" @@ -8573,7 +8699,6 @@ "version": "1.0.0", "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-1.0.0.tgz", "integrity": "sha1-754xOG8DGn8NZDr4L95QxFfvAMs=", - "dev": true, "requires": { "number-is-nan": "^1.0.0" } @@ -8582,7 +8707,6 @@ "version": "1.0.2", "resolved": "https://registry.npmjs.org/string-width/-/string-width-1.0.2.tgz", "integrity": "sha1-EYvfW4zcUaKn5w0hHgfisLmxB9M=", - "dev": true, "requires": { "code-point-at": "^1.0.0", "is-fullwidth-code-point": "^1.0.0", @@ -8631,8 +8755,7 @@ "y18n": { "version": "3.2.1", "resolved": "https://registry.npmjs.org/y18n/-/y18n-3.2.1.tgz", - "integrity": "sha1-bRX7qITAhnnA136I53WegR4H+kE=", - "dev": true + "integrity": "sha1-bRX7qITAhnnA136I53WegR4H+kE=" }, "yallist": { "version": "2.1.2", @@ -8641,17 +8764,52 @@ "dev": true }, "yargs": { - "version": "3.27.0", - "resolved": "https://registry.npmjs.org/yargs/-/yargs-3.27.0.tgz", - "integrity": "sha1-ISBUaTFuk5Ex1Z8toMbX+YIh6kA=", - "dev": true, + "version": "3.32.0", + "resolved": "https://registry.npmjs.org/yargs/-/yargs-3.32.0.tgz", + "integrity": "sha1-AwiOnr+edWtpdRYR0qXvWRSCyZU=", "requires": { - "camelcase": "^1.2.1", - "cliui": "^2.1.0", - "decamelize": "^1.0.0", + "camelcase": "^2.0.1", + "cliui": "^3.0.3", + "decamelize": "^1.1.1", "os-locale": "^1.4.0", - "window-size": "^0.1.2", + "string-width": "^1.0.1", + "window-size": "^0.1.4", "y18n": "^3.2.0" + }, + "dependencies": { + "camelcase": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-2.1.1.tgz", + "integrity": "sha1-fB0W1nmhu+WcoCys7PsBHiAfWh8=" + }, + "cliui": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/cliui/-/cliui-3.2.0.tgz", + "integrity": "sha1-EgYBU3qRbSmUD5NNo7SNWFo5IT0=", + "requires": { + "string-width": "^1.0.1", + "strip-ansi": "^3.0.1", + "wrap-ansi": "^2.0.0" + } + }, + "is-fullwidth-code-point": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-1.0.0.tgz", + "integrity": "sha1-754xOG8DGn8NZDr4L95QxFfvAMs=", + "requires": { + "number-is-nan": "^1.0.0" + } + }, + "string-width": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-1.0.2.tgz", + "integrity": "sha1-EYvfW4zcUaKn5w0hHgfisLmxB9M=", + "requires": { + "code-point-at": "^1.0.0", + "is-fullwidth-code-point": "^1.0.0", + "strip-ansi": "^3.0.0" + } + } } }, "yargs-parser": { From 77e38330e6971b3856263a1f78eca72e0099a414 Mon Sep 17 00:00:00 2001 From: Jean-Baptiste Musso Date: Tue, 18 Jun 2019 07:51:15 +0200 Subject: [PATCH 068/154] Fix typo in compiler API doc: "mutation" field should read as "mutating" The `Visitor` class expects a `boolean` property named `mutating`, instead of `mutation`. --- docs/compiler-api.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/compiler-api.md b/docs/compiler-api.md index f419fbcd2..0001459b0 100644 --- a/docs/compiler-api.md +++ b/docs/compiler-api.md @@ -263,7 +263,7 @@ scanner.accept(ast); The current node's ancestors will be maintained in the `parents` array, with the most recent parent listed first. -The visitor may also be configured to operate in mutation mode by setting the `mutation` field to true. When in this mode, handler methods may return any valid AST node and it will replace the one they are currently operating on. Returning `false` will remove the given value (if valid) and returning `undefined` will leave the node in tact. This return structure only apply to mutation mode and non-mutation mode visitors are free to return whatever values they wish. +The visitor may also be configured to operate in mutation mode by setting the `mutating` field to true. When in this mode, handler methods may return any valid AST node and it will replace the one they are currently operating on. Returning `false` will remove the given value (if valid) and returning `undefined` will leave the node in tact. This return structure only apply to mutation mode and non-mutation mode visitors are free to return whatever values they wish. Implementors that may need to support mutation mode are encouraged to utilize the `acceptKey`, `acceptRequired` and `acceptArray` helpers which provide the conditional overwrite behavior as well as implement sanity checks where pertinent. From dce44541dbb933a62890471a5a49c828954f4ada Mon Sep 17 00:00:00 2001 From: Nils Knappmeier Date: Tue, 3 Sep 2019 22:10:15 +0200 Subject: [PATCH 069/154] Update jsfiddle-link --- CONTRIBUTING.md | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 8ea9dd9f9..b71c6c503 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -4,7 +4,10 @@ Please see our [FAQ](https://github.com/wycats/handlebars.js/blob/master/FAQ.md) for common issues that people run into. -Should you run into other issues with the project, please don't hesitate to let us know by filing an [issue][issue]! In general we are going to ask for an example of the problem failing, which can be as simple as a jsfiddle/jsbin/etc. We've put together a jsfiddle [template][jsfiddle] to ease this. (We will keep this link up to date as new releases occur, so feel free to check back here) +Should you run into other issues with the project, please don't hesitate to let us know by filing an [issue][issue]! + + +In general we are going to ask for an **example** of the problem failing, which can be as simple as a jsfiddle/jsbin/etc. We've put together a jsfiddle **[template][jsfiddle]** to ease this. (We will keep this link up to date as new releases occur, so feel free to check back here). Pull requests containing only failing tests demonstrating the issue are welcomed and this also helps ensure that your issue won't regress in the future once it's fixed. @@ -15,6 +18,8 @@ Documentation issues on the handlebarsjs.com site should be reported on [handleb * The branch `4.x` contains the currently released version. Bugfixes should be made in this branch. * The branch `master` contains the next version. A release date is not yet specified. Maintainers should merge the branch `4.x` into the master branch regularly. +* The branch `3.x` comtains the legacy version `3.x`. Bugfixes are applied seperately (if needed). The branch will not + be merged with any of the other branches. ## Pull Requests @@ -112,4 +117,4 @@ When everything is OK, the handlebars site needs to be updated to point to the n [generator-release]: https://github.com/walmartlabs/generator-release [pull-request]: https://github.com/wycats/handlebars.js/pull/new/master [issue]: https://github.com/wycats/handlebars.js/issues/new -[jsfiddle]: https://jsfiddle.net/08v3cbg4/ +[jsfiddle]: https://jsfiddle.net/0L92ufpv/ From 8df74a0119464d5f694972be56f427207385933d Mon Sep 17 00:00:00 2001 From: king6cong Date: Fri, 9 Feb 2018 17:19:31 +0800 Subject: [PATCH 070/154] FAQ format adjustment --- FAQ.md | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/FAQ.md b/FAQ.md index 49462856d..d0f16f776 100644 --- a/FAQ.md +++ b/FAQ.md @@ -1,22 +1,22 @@ # Frequently Asked Questions -1. How can I file a bug report: +## How can I file a bug report: See our guidelines on [reporting issues](https://github.com/wycats/handlebars.js/blob/master/CONTRIBUTING.md#reporting-issues). -1. Why isn't my Mustache template working? +## Why isn't my Mustache template working? Handlebars deviates from Mustache slightly on a few behaviors. These variations are documented in our [readme](https://github.com/wycats/handlebars.js#differences-between-handlebarsjs-and-mustache). -1. Why is it slower when compiling? +## Why is it slower when compiling? The Handlebars compiler must parse the template and construct a JavaScript program which can then be run. Under some environments such as older mobile devices this can have a performance impact which can be avoided by precompiling. Generally it's recommended that precompilation and the runtime library be used on all clients. -1. Why doesn't this work with Content Security Policy restrictions? +## Why doesn't this work with Content Security Policy restrictions? When not using the precompiler, Handlebars generates a dynamic function for each template which can cause issues with pages that have enabled Content Policy. It's recommended that templates are precompiled or the `unsafe-eval` policy is enabled for sites that must generate dynamic templates at runtime. -1. How can I include script tags in my template? +## How can I include script tags in my template? If loading the template via an inlined ` - - diff --git a/spec/umd.html b/spec/umd.html index 9e6e19d03..4137f1466 100644 --- a/spec/umd.html +++ b/spec/umd.html @@ -27,7 +27,6 @@ window.expect = chai.expect; mocha.setup('bdd'); - diff --git a/spec/vendor/json2.js b/spec/vendor/json2.js deleted file mode 100644 index deb88ec9a..000000000 --- a/spec/vendor/json2.js +++ /dev/null @@ -1,489 +0,0 @@ -/* - json2.js - 2014-02-04 - - Public Domain. - - NO WARRANTY EXPRESSED OR IMPLIED. USE AT YOUR OWN RISK. - - See http://www.JSON.org/js.html - - - This code should be minified before deployment. - See http://javascript.crockford.com/jsmin.html - - USE YOUR OWN COPY. IT IS EXTREMELY UNWISE TO LOAD CODE FROM SERVERS YOU DO - NOT CONTROL. - - - This file creates a global JSON object containing two methods: stringify - and parse. - - JSON.stringify(value, replacer, space) - value any JavaScript value, usually an object or array. - - replacer an optional parameter that determines how object - values are stringified for objects. It can be a - function or an array of strings. - - space an optional parameter that specifies the indentation - of nested structures. If it is omitted, the text will - be packed without extra whitespace. If it is a number, - it will specify the number of spaces to indent at each - level. If it is a string (such as '\t' or ' '), - it contains the characters used to indent at each level. - - This method produces a JSON text from a JavaScript value. - - When an object value is found, if the object contains a toJSON - method, its toJSON method will be called and the result will be - stringified. A toJSON method does not serialize: it returns the - value represented by the name/value pair that should be serialized, - or undefined if nothing should be serialized. The toJSON method - will be passed the key associated with the value, and this will be - bound to the value - - For example, this would serialize Dates as ISO strings. - - Date.prototype.toJSON = function (key) { - function f(n) { - // Format integers to have at least two digits. - return n < 10 ? '0' + n : n; - } - - return this.getUTCFullYear() + '-' + - f(this.getUTCMonth() + 1) + '-' + - f(this.getUTCDate()) + 'T' + - f(this.getUTCHours()) + ':' + - f(this.getUTCMinutes()) + ':' + - f(this.getUTCSeconds()) + 'Z'; - }; - - You can provide an optional replacer method. It will be passed the - key and value of each member, with this bound to the containing - object. The value that is returned from your method will be - serialized. If your method returns undefined, then the member will - be excluded from the serialization. - - If the replacer parameter is an array of strings, then it will be - used to select the members to be serialized. It filters the results - such that only members with keys listed in the replacer array are - stringified. - - Values that do not have JSON representations, such as undefined or - functions, will not be serialized. Such values in objects will be - dropped; in arrays they will be replaced with null. You can use - a replacer function to replace those with JSON values. - JSON.stringify(undefined) returns undefined. - - The optional space parameter produces a stringification of the - value that is filled with line breaks and indentation to make it - easier to read. - - If the space parameter is a non-empty string, then that string will - be used for indentation. If the space parameter is a number, then - the indentation will be that many spaces. - - Example: - - text = JSON.stringify(['e', {pluribus: 'unum'}]); - // text is '["e",{"pluribus":"unum"}]' - - - text = JSON.stringify(['e', {pluribus: 'unum'}], null, '\t'); - // text is '[\n\t"e",\n\t{\n\t\t"pluribus": "unum"\n\t}\n]' - - text = JSON.stringify([new Date()], function (key, value) { - return this[key] instanceof Date ? - 'Date(' + this[key] + ')' : value; - }); - // text is '["Date(---current time---)"]' - - - JSON.parse(text, reviver) - This method parses a JSON text to produce an object or array. - It can throw a SyntaxError exception. - - The optional reviver parameter is a function that can filter and - transform the results. It receives each of the keys and values, - and its return value is used instead of the original value. - If it returns what it received, then the structure is not modified. - If it returns undefined then the member is deleted. - - Example: - - // Parse the text. Values that look like ISO date strings will - // be converted to Date objects. - - myData = JSON.parse(text, function (key, value) { - var a; - if (typeof value === 'string') { - a = -/^(\d{4})-(\d{2})-(\d{2})T(\d{2}):(\d{2}):(\d{2}(?:\.\d*)?)Z$/.exec(value); - if (a) { - return new Date(Date.UTC(+a[1], +a[2] - 1, +a[3], +a[4], - +a[5], +a[6])); - } - } - return value; - }); - - myData = JSON.parse('["Date(09/09/2001)"]', function (key, value) { - var d; - if (typeof value === 'string' && - value.slice(0, 5) === 'Date(' && - value.slice(-1) === ')') { - d = new Date(value.slice(5, -1)); - if (d) { - return d; - } - } - return value; - }); - - - This is a reference implementation. You are free to copy, modify, or - redistribute. -*/ - -/*jslint evil: true, regexp: true */ - -/*members "", "\b", "\t", "\n", "\f", "\r", "\"", JSON, "\\", apply, - call, charCodeAt, getUTCDate, getUTCFullYear, getUTCHours, - getUTCMinutes, getUTCMonth, getUTCSeconds, hasOwnProperty, join, - lastIndex, length, parse, prototype, push, replace, slice, stringify, - test, toJSON, toString, valueOf -*/ - - -// Create a JSON object only if one does not already exist. We create the -// methods in a closure to avoid creating global variables. - -if (typeof JSON !== 'object') { - JSON = {}; -} - -(function () { - 'use strict'; - - function f(n) { - // Format integers to have at least two digits. - return n < 10 ? '0' + n : n; - } - - if (typeof Date.prototype.toJSON !== 'function') { - - Date.prototype.toJSON = function () { - - return isFinite(this.valueOf()) - ? this.getUTCFullYear() + '-' + - f(this.getUTCMonth() + 1) + '-' + - f(this.getUTCDate()) + 'T' + - f(this.getUTCHours()) + ':' + - f(this.getUTCMinutes()) + ':' + - f(this.getUTCSeconds()) + 'Z' - : null; - }; - - String.prototype.toJSON = - Number.prototype.toJSON = - Boolean.prototype.toJSON = function () { - return this.valueOf(); - }; - } - - var cx, - escapable, - gap, - indent, - meta, - rep; - - - function quote(string) { - -// If the string contains no control characters, no quote characters, and no -// backslash characters, then we can safely slap some quotes around it. -// Otherwise we must also replace the offending characters with safe escape -// sequences. - - escapable.lastIndex = 0; - return escapable.test(string) ? '"' + string.replace(escapable, function (a) { - var c = meta[a]; - return typeof c === 'string' - ? c - : '\\u' + ('0000' + a.charCodeAt(0).toString(16)).slice(-4); - }) + '"' : '"' + string + '"'; - } - - - function str(key, holder) { - -// Produce a string from holder[key]. - - var i, // The loop counter. - k, // The member key. - v, // The member value. - length, - mind = gap, - partial, - value = holder[key]; - -// If the value has a toJSON method, call it to obtain a replacement value. - - if (value && typeof value === 'object' && - typeof value.toJSON === 'function') { - value = value.toJSON(key); - } - -// If we were called with a replacer function, then call the replacer to -// obtain a replacement value. - - if (typeof rep === 'function') { - value = rep.call(holder, key, value); - } - -// What happens next depends on the value's type. - - switch (typeof value) { - case 'string': - return quote(value); - - case 'number': - -// JSON numbers must be finite. Encode non-finite numbers as null. - - return isFinite(value) ? String(value) : 'null'; - - case 'boolean': - case 'null': - -// If the value is a boolean or null, convert it to a string. Note: -// typeof null does not produce 'null'. The case is included here in -// the remote chance that this gets fixed someday. - - return String(value); - -// If the type is 'object', we might be dealing with an object or an array or -// null. - - case 'object': - -// Due to a specification blunder in ECMAScript, typeof null is 'object', -// so watch out for that case. - - if (!value) { - return 'null'; - } - -// Make an array to hold the partial results of stringifying this object value. - - gap += indent; - partial = []; - -// Is the value an array? - - if (Object.prototype.toString.apply(value) === '[object Array]') { - -// The value is an array. Stringify every element. Use null as a placeholder -// for non-JSON values. - - length = value.length; - for (i = 0; i < length; i += 1) { - partial[i] = str(i, value) || 'null'; - } - -// Join all of the elements together, separated with commas, and wrap them in -// brackets. - - v = partial.length === 0 - ? '[]' - : gap - ? '[\n' + gap + partial.join(',\n' + gap) + '\n' + mind + ']' - : '[' + partial.join(',') + ']'; - gap = mind; - return v; - } - -// If the replacer is an array, use it to select the members to be stringified. - - if (rep && typeof rep === 'object') { - length = rep.length; - for (i = 0; i < length; i += 1) { - if (typeof rep[i] === 'string') { - k = rep[i]; - v = str(k, value); - if (v) { - partial.push(quote(k) + (gap ? ': ' : ':') + v); - } - } - } - } else { - -// Otherwise, iterate through all of the keys in the object. - - for (k in value) { - if (Object.prototype.hasOwnProperty.call(value, k)) { - v = str(k, value); - if (v) { - partial.push(quote(k) + (gap ? ': ' : ':') + v); - } - } - } - } - -// Join all of the member texts together, separated with commas, -// and wrap them in braces. - - v = partial.length === 0 - ? '{}' - : gap - ? '{\n' + gap + partial.join(',\n' + gap) + '\n' + mind + '}' - : '{' + partial.join(',') + '}'; - gap = mind; - return v; - } - } - -// If the JSON object does not yet have a stringify method, give it one. - - if (typeof JSON.stringify !== 'function') { - escapable = /[\\\"\x00-\x1f\x7f-\x9f\u00ad\u0600-\u0604\u070f\u17b4\u17b5\u200c-\u200f\u2028-\u202f\u2060-\u206f\ufeff\ufff0-\uffff]/g; - meta = { // table of character substitutions - '\b': '\\b', - '\t': '\\t', - '\n': '\\n', - '\f': '\\f', - '\r': '\\r', - '"' : '\\"', - '\\': '\\\\' - }; - JSON.stringify = function (value, replacer, space) { - -// The stringify method takes a value and an optional replacer, and an optional -// space parameter, and returns a JSON text. The replacer can be a function -// that can replace values, or an array of strings that will select the keys. -// A default replacer method can be provided. Use of the space parameter can -// produce text that is more easily readable. - - var i; - gap = ''; - indent = ''; - -// If the space parameter is a number, make an indent string containing that -// many spaces. - - if (typeof space === 'number') { - for (i = 0; i < space; i += 1) { - indent += ' '; - } - -// If the space parameter is a string, it will be used as the indent string. - - } else if (typeof space === 'string') { - indent = space; - } - -// If there is a replacer, it must be a function or an array. -// Otherwise, throw an error. - - rep = replacer; - if (replacer && typeof replacer !== 'function' && - (typeof replacer !== 'object' || - typeof replacer.length !== 'number')) { - throw new Error('JSON.stringify'); - } - -// Make a fake root object containing our value under the key of ''. -// Return the result of stringifying the value. - - return str('', {'': value}); - }; - } - - -// If the JSON object does not yet have a parse method, give it one. - - if (typeof JSON.parse !== 'function') { - cx = /[\u0000\u00ad\u0600-\u0604\u070f\u17b4\u17b5\u200c-\u200f\u2028-\u202f\u2060-\u206f\ufeff\ufff0-\uffff]/g; - JSON.parse = function (text, reviver) { - -// The parse method takes a text and an optional reviver function, and returns -// a JavaScript value if the text is a valid JSON text. - - var j; - - function walk(holder, key) { - -// The walk method is used to recursively walk the resulting structure so -// that modifications can be made. - - var k, v, value = holder[key]; - if (value && typeof value === 'object') { - for (k in value) { - if (Object.prototype.hasOwnProperty.call(value, k)) { - v = walk(value, k); - if (v !== undefined) { - value[k] = v; - } else { - delete value[k]; - } - } - } - } - return reviver.call(holder, key, value); - } - - -// Parsing happens in four stages. In the first stage, we replace certain -// Unicode characters with escape sequences. JavaScript handles many characters -// incorrectly, either silently deleting them, or treating them as line endings. - - text = String(text); - cx.lastIndex = 0; - if (cx.test(text)) { - text = text.replace(cx, function (a) { - return '\\u' + - ('0000' + a.charCodeAt(0).toString(16)).slice(-4); - }); - } - -// In the second stage, we run the text against regular expressions that look -// for non-JSON patterns. We are especially concerned with '()' and 'new' -// because they can cause invocation, and '=' because it can cause mutation. -// But just to be safe, we want to reject all unexpected forms. - -// We split the second stage into 4 regexp operations in order to work around -// crippling inefficiencies in IE's and Safari's regexp engines. First we -// replace the JSON backslash pairs with '@' (a non-JSON character). Second, we -// replace all simple value tokens with ']' characters. Third, we delete all -// open brackets that follow a colon or comma or that begin the text. Finally, -// we look to see that the remaining characters are only whitespace or ']' or -// ',' or ':' or '{' or '}'. If that is so, then the text is safe for eval. - - if (/^[\],:{}\s]*$/ - .test(text.replace(/\\(?:["\\\/bfnrt]|u[0-9a-fA-F]{4})/g, '@') - .replace(/"[^"\\\n\r]*"|true|false|null|-?\d+(?:\.\d*)?(?:[eE][+\-]?\d+)?/g, ']') - .replace(/(?:^|:|,)(?:\s*\[)+/g, ''))) { - -// In the third stage we use the eval function to compile the text into a -// JavaScript structure. The '{' operator is subject to a syntactic ambiguity -// in JavaScript: it can begin a block or an object literal. We wrap the text -// in parens to eliminate the ambiguity. - - j = eval('(' + text + ')'); - -// In the optional fourth stage, we recursively walk the new structure, passing -// each name/value pair to a reviver function for possible transformation. - - return typeof reviver === 'function' - ? walk({'': j}, '') - : j; - } - -// If the text is not JSON parseable, then a SyntaxError is thrown. - - throw new SyntaxError('JSON.parse'); - }; - } -}()); diff --git a/tasks/.eslintrc.js b/tasks/.eslintrc.js index 642a9ab06..8a8c16cd9 100644 --- a/tasks/.eslintrc.js +++ b/tasks/.eslintrc.js @@ -1,10 +1,4 @@ module.exports = { - extends: ['../.eslintrc.js'], - parserOptions: { - sourceType: 'module', - ecmaVersion: 2017, - ecmaFeatures: {} - }, rules: { 'no-process-env': 'off', 'prefer-const': 'warn', diff --git a/tasks/tests/.eslintrc.js b/tasks/tests/.eslintrc.js index 604aeb2c0..bf3479fb6 100644 --- a/tasks/tests/.eslintrc.js +++ b/tasks/tests/.eslintrc.js @@ -1,9 +1,5 @@ module.exports = { - extends: '../../.eslintrc.js', env: { mocha: true - }, - parserOptions: { - ecmaVersion: 2018 } }; diff --git a/tests/.eslintrc.js b/tests/.eslintrc.js deleted file mode 100644 index 8f806f344..000000000 --- a/tests/.eslintrc.js +++ /dev/null @@ -1,10 +0,0 @@ -module.exports = { - root: true, - extends: ['eslint:recommended', 'prettier'], - env: { - node: true - }, - parserOptions: { - ecmaVersion: 6 - } -}; diff --git a/tests/bench/.eslintrc.js b/tests/bench/.eslintrc.js new file mode 100644 index 000000000..55eb52a6d --- /dev/null +++ b/tests/bench/.eslintrc.js @@ -0,0 +1,6 @@ +module.exports = { + rules: { + 'no-console': 'off', + 'no-var': 'off' + } +}; diff --git a/tests/browser/.eslintrc.js b/tests/browser/.eslintrc.js index 344096aeb..3d5b0d26f 100644 --- a/tests/browser/.eslintrc.js +++ b/tests/browser/.eslintrc.js @@ -1,5 +1,5 @@ module.exports = { parserOptions: { - ecmaVersion: 2020 + ecmaVersion: 2018 } }; diff --git a/tests/integration/multi-nodejs-test/.eslintrc.js b/tests/integration/multi-nodejs-test/.eslintrc.js index 2b9bb339c..55eb52a6d 100644 --- a/tests/integration/multi-nodejs-test/.eslintrc.js +++ b/tests/integration/multi-nodejs-test/.eslintrc.js @@ -1,11 +1,4 @@ module.exports = { - extends: ['eslint:recommended', 'prettier'], - globals: { - self: false - }, - env: { - node: true - }, rules: { 'no-console': 'off', 'no-var': 'off' diff --git a/tests/integration/rollup-test/.eslintrc.js b/tests/integration/rollup-test/.eslintrc.js deleted file mode 100644 index 506a733f4..000000000 --- a/tests/integration/rollup-test/.eslintrc.js +++ /dev/null @@ -1,11 +0,0 @@ -module.exports = { - root: true, - extends: ['eslint:recommended', 'prettier'], - env: { - browser: true - }, - parserOptions: { - sourceType: 'module', - ecmaVersion: 6 - } -}; diff --git a/tests/integration/webpack-babel-test/src/.eslintrc.js b/tests/integration/webpack-babel-test/src/.eslintrc.js index 506a733f4..fb43a7838 100644 --- a/tests/integration/webpack-babel-test/src/.eslintrc.js +++ b/tests/integration/webpack-babel-test/src/.eslintrc.js @@ -1,3 +1,4 @@ +/* eslint-env node */ module.exports = { root: true, extends: ['eslint:recommended', 'prettier'], From e534a911f3b7de9348716f566a8d9b5efafc7738 Mon Sep 17 00:00:00 2001 From: Jakob Linskeseder Date: Wed, 19 Oct 2022 22:26:53 +0200 Subject: [PATCH 127/154] Upgrade prettier to v2 Prettier v2 has the following breaking changes: * enforces spaces between `function` and params * enforces trailing commas by default --- .eslintrc.js | 10 +- Gruntfile.js | 85 ++-- bin/handlebars.js | 40 +- lib/.eslintrc.js | 4 +- lib/handlebars.js | 6 +- lib/handlebars.runtime.js | 2 +- lib/handlebars/base.js | 16 +- lib/handlebars/compiler/ast.js | 10 +- lib/handlebars/compiler/code-gen.js | 40 +- lib/handlebars/compiler/compiler.js | 68 +-- .../compiler/javascript-compiler.js | 160 +++---- lib/handlebars/decorators/inline.js | 37 +- .../helpers/block-helper-missing.js | 4 +- lib/handlebars/helpers/each.js | 8 +- lib/handlebars/helpers/helper-missing.js | 4 +- lib/handlebars/helpers/if.js | 8 +- lib/handlebars/helpers/log.js | 4 +- lib/handlebars/helpers/lookup.js | 4 +- lib/handlebars/helpers/with.js | 6 +- lib/handlebars/internal/proto-access.js | 8 +- lib/handlebars/internal/wrapHelper.js | 2 +- lib/handlebars/logger.js | 6 +- lib/handlebars/no-conflict.js | 4 +- lib/handlebars/runtime.js | 30 +- lib/handlebars/safe-string.js | 2 +- lib/handlebars/utils.js | 4 +- lib/precompiler.js | 49 ++- nyc.config.js | 2 +- package-lock.json | 19 +- package.json | 2 +- prettier.config.js | 2 +- spec/.eslintrc.js | 8 +- spec/ast.js | 68 +-- spec/basic.js | 226 +++++----- spec/blocks.js | 168 ++++---- spec/builtins.js | 254 +++++------ spec/compiler.js | 50 +-- spec/data.js | 106 ++--- spec/env/browser.js | 6 +- spec/env/common.js | 48 +-- spec/env/node.js | 6 +- spec/env/runner.js | 18 +- spec/env/runtime.js | 13 +- spec/helpers.js | 400 +++++++++--------- spec/javascript-compiler.js | 58 +-- spec/partials.js | 239 ++++++----- spec/precompiler.js | 166 ++++---- spec/regressions.js | 190 ++++----- spec/require.js | 6 +- spec/runtime.js | 30 +- spec/security.js | 166 ++++---- spec/source-map.js | 12 +- spec/spec.js | 12 +- spec/strict.js | 54 +-- spec/subexpressions.js | 102 ++--- spec/tokenizer.js | 186 ++++---- spec/utils.js | 32 +- spec/whitespace-control.js | 36 +- tasks/.eslintrc.js | 4 +- tasks/metrics.js | 10 +- tasks/publish-to-aws.js | 12 +- tasks/test-bin.js | 72 ++-- tasks/test-mocha.js | 4 +- tasks/tests/.eslintrc.js | 4 +- tasks/tests/git.test.js | 34 +- tasks/util/async-grunt-task.js | 4 +- tasks/util/exec-file.js | 4 +- tasks/util/git.js | 6 +- tasks/version.js | 14 +- tests/bench/.eslintrc.js | 4 +- tests/bench/dist-size.js | 8 +- tests/bench/index.js | 2 +- tests/bench/precompile-size.js | 6 +- tests/bench/templates/arguments.js | 8 +- tests/bench/templates/array-each.js | 6 +- tests/bench/templates/array-mustache.js | 6 +- tests/bench/templates/complex.js | 8 +- tests/bench/templates/data.js | 6 +- tests/bench/templates/depth-1.js | 6 +- tests/bench/templates/depth-2.js | 6 +- tests/bench/templates/index.js | 2 +- tests/bench/templates/object-mustache.js | 2 +- tests/bench/templates/object.js | 2 +- tests/bench/templates/partial-recursion.js | 6 +- tests/bench/templates/partial.js | 10 +- tests/bench/templates/paths.js | 2 +- tests/bench/templates/string.js | 2 +- tests/bench/templates/subexpression.js | 8 +- tests/bench/templates/variables.js | 2 +- tests/bench/throughput.js | 36 +- tests/bench/util/benchwarmer.js | 53 +-- tests/bench/util/template-runner.js | 8 +- tests/browser/.eslintrc.js | 4 +- tests/browser/playwright.config.js | 12 +- .../multi-nodejs-test/.eslintrc.js | 4 +- .../integration/rollup-test/rollup.config.js | 4 +- .../webpack-babel-test/src/.eslintrc.js | 6 +- .../src/handlebars-inline-precompile-test.js | 2 +- .../webpack-babel-test/webpack.config.js | 18 +- .../integration/webpack-test/src/.eslintrc.js | 6 +- .../src/handlebars-require-vs-import-test.js | 2 +- .../src/handlebars-runtime-test.js | 10 +- .../webpack-test/webpack.config.js | 10 +- tests/print-script.js | 10 +- 104 files changed, 1868 insertions(+), 1893 deletions(-) diff --git a/.eslintrc.js b/.eslintrc.js index 186adb77b..f03eac32f 100644 --- a/.eslintrc.js +++ b/.eslintrc.js @@ -1,14 +1,14 @@ module.exports = { extends: ['eslint:recommended', 'plugin:compat/recommended', 'prettier'], globals: { - self: false + self: false, }, env: { node: true, - es2020: true + es2020: true, }, parserOptions: { - sourceType: 'module' + sourceType: 'module', }, rules: { 'no-console': 'warn', @@ -59,6 +59,6 @@ module.exports = { // ECMAScript 6 // //--------------// - 'no-var': 'error' - } + 'no-var': 'error', + }, }; diff --git a/Gruntfile.js b/Gruntfile.js index d6d022f50..63777dcbe 100644 --- a/Gruntfile.js +++ b/Gruntfile.js @@ -1,5 +1,5 @@ /* eslint-disable no-process-env */ -module.exports = function(grunt) { +module.exports = function (grunt) { grunt.initConfig({ pkg: grunt.file.readJSON('package.json'), @@ -8,7 +8,7 @@ module.exports = function(grunt) { copy: { dist: { options: { - processContent: function(content) { + processContent: function (content) { return ( grunt.template.process( '/**!\n\n @license magnet:?xt=urn:btih:d3d9a9a6595521f9666a5e94cc830dab83b65699&dn=expat.txt Expat\n <%= pkg.name %> v<%= pkg.version %>\n\n<%= grunt.file.read("LICENSE") %>\n*/\n' @@ -16,9 +16,9 @@ module.exports = function(grunt) { content + '\n// @license-end\n' ); - } + }, }, - files: [{ expand: true, cwd: 'dist/', src: ['*.js'], dest: 'dist/' }] + files: [{ expand: true, cwd: 'dist/', src: ['*.js'], dest: 'dist/' }], }, components: { files: [ @@ -26,18 +26,23 @@ module.exports = function(grunt) { expand: true, cwd: 'components/', src: ['**'], - dest: 'dist/components' + dest: 'dist/components', + }, + { + expand: true, + cwd: 'dist/', + src: ['*.js'], + dest: 'dist/components', }, - { expand: true, cwd: 'dist/', src: ['*.js'], dest: 'dist/components' } - ] - } + ], + }, }, babel: { options: { sourceMaps: 'inline', loose: ['es6.modules'], - auxiliaryCommentBefore: 'istanbul ignore next' + auxiliaryCommentBefore: 'istanbul ignore next', }, cjs: { files: [ @@ -45,10 +50,10 @@ module.exports = function(grunt) { cwd: 'lib/', expand: true, src: '**/!(index).js', - dest: 'dist/cjs/' - } - ] - } + dest: 'dist/cjs/', + }, + ], + }, }, webpack: { options: { @@ -56,28 +61,28 @@ module.exports = function(grunt) { output: { path: 'dist/', library: 'Handlebars', - libraryTarget: 'umd' - } + libraryTarget: 'umd', + }, }, handlebars: { entry: './dist/cjs/handlebars.js', output: { - filename: 'handlebars.js' - } + filename: 'handlebars.js', + }, }, runtime: { entry: './dist/cjs/handlebars.runtime.js', output: { - filename: 'handlebars.runtime.js' - } - } + filename: 'handlebars.runtime.js', + }, + }, }, uglify: { options: { mangle: true, compress: true, - preserveComments: /(?:^!|@(?:license|preserve|cc_on))/ + preserveComments: /(?:^!|@(?:license|preserve|cc_on))/, }, dist: { files: [ @@ -86,19 +91,19 @@ module.exports = function(grunt) { expand: true, src: ['handlebars*.js', '!*.min.js'], dest: 'dist/', - rename: function(dest, src) { + rename: function (dest, src) { return dest + src.replace(/\.js$/, '.min.js'); - } - } - ] - } + }, + }, + ], + }, }, concat: { tests: { src: ['spec/!(require).js'], - dest: 'tmp/tests.js' - } + dest: 'tmp/tests.js', + }, }, connect: { @@ -106,27 +111,27 @@ module.exports = function(grunt) { options: { base: '.', hostname: '*', - port: 9999 - } - } + port: 9999, + }, + }, }, shell: { integrationTests: { - command: './tests/integration/run-integration-tests.sh' - } + command: './tests/integration/run-integration-tests.sh', + }, }, watch: { scripts: { options: { - atBegin: true + atBegin: true, }, files: ['src/*', 'lib/**/*.js', 'spec/**/*.js'], - tasks: ['on-file-change'] - } - } + tasks: ['on-file-change'], + }, + }, }); // Load tasks from npm @@ -148,7 +153,7 @@ module.exports = function(grunt) { 'uglify', 'test:min', 'copy:dist', - 'copy:components' + 'copy:components', ]); // Requires secret properties from .travis.yaml @@ -156,7 +161,7 @@ module.exports = function(grunt) { 'default', 'shell:integrationTests', 'metrics', - 'publish-to-aws' + 'publish-to-aws', ]); grunt.registerTask('on-file-change', ['build', 'concat:tests', 'test']); @@ -174,6 +179,6 @@ module.exports = function(grunt) { ); grunt.registerTask('integration-tests', [ 'default', - 'shell:integrationTests' + 'shell:integrationTests', ]); }; diff --git a/bin/handlebars.js b/bin/handlebars.js index fabbb3951..ee1156c85 100755 --- a/bin/handlebars.js +++ b/bin/handlebars.js @@ -5,103 +5,103 @@ const yargs = require('yargs') .option('f', { type: 'string', description: 'Output File', - alias: 'output' + alias: 'output', }) .option('map', { type: 'string', - description: 'Source Map File' + description: 'Source Map File', }) .option('a', { type: 'boolean', description: 'Exports amd style (require.js)', - alias: 'amd' + alias: 'amd', }) .option('c', { type: 'string', description: 'Exports CommonJS style, path to Handlebars module', alias: 'commonjs', - default: null + default: null, }) .option('h', { type: 'string', description: 'Path to handlebar.js (only valid for amd-style)', alias: 'handlebarPath', - default: '' + default: '', }) .option('k', { type: 'string', description: 'Known helpers', - alias: 'known' + alias: 'known', }) .option('o', { type: 'boolean', description: 'Known helpers only', - alias: 'knownOnly' + alias: 'knownOnly', }) .option('m', { type: 'boolean', description: 'Minimize output', - alias: 'min' + alias: 'min', }) .option('n', { type: 'string', description: 'Template namespace', alias: 'namespace', - default: 'Handlebars.templates' + default: 'Handlebars.templates', }) .option('s', { type: 'boolean', description: 'Output template function only.', - alias: 'simple' + alias: 'simple', }) .option('N', { type: 'string', description: 'Name of passed string templates. Optional if running in a simple mode. Required when operating on multiple templates.', - alias: 'name' + alias: 'name', }) .option('i', { type: 'string', description: 'Generates a template from the passed CLI argument.\n"-" is treated as a special value and causes stdin to be read for the template value.', - alias: 'string' + alias: 'string', }) .option('r', { type: 'string', description: 'Template root. Base value that will be stripped from template names.', - alias: 'root' + alias: 'root', }) .option('p', { type: 'boolean', description: 'Compiling a partial template', - alias: 'partial' + alias: 'partial', }) .option('d', { type: 'boolean', description: 'Include data when compiling', - alias: 'data' + alias: 'data', }) .option('e', { type: 'string', description: 'Template extension.', alias: 'extension', - default: 'handlebars' + default: 'handlebars', }) .option('b', { type: 'boolean', description: 'Removes the BOM (Byte Order Mark) from the beginning of the templates.', - alias: 'bom' + alias: 'bom', }) .option('v', { type: 'boolean', description: 'Prints the current compiler version', - alias: 'version' + alias: 'version', }) .option('help', { type: 'boolean', - description: 'Outputs this message' + description: 'Outputs this message', }) .wrap(120); @@ -110,7 +110,7 @@ argv.files = argv._; delete argv._; const Precompiler = require('../dist/cjs/precompiler'); -Precompiler.loadTemplates(argv, function(err, opts) { +Precompiler.loadTemplates(argv, function (err, opts) { if (err) { throw err; } diff --git a/lib/.eslintrc.js b/lib/.eslintrc.js index 16b3e5907..0bc8d6f5a 100644 --- a/lib/.eslintrc.js +++ b/lib/.eslintrc.js @@ -2,6 +2,6 @@ module.exports = { env: { // Handlebars should run natively in the browser - node: false - } + node: false, + }, }; diff --git a/lib/handlebars.js b/lib/handlebars.js index 64a288c35..68a505a20 100644 --- a/lib/handlebars.js +++ b/lib/handlebars.js @@ -2,7 +2,7 @@ import { parser as Parser, parse, parseWithoutProcessing, - Visitor + Visitor, } from '@handlebars/parser'; import runtime from './handlebars.runtime'; @@ -18,10 +18,10 @@ let _create = runtime.create; function create() { let hb = _create(); - hb.compile = function(input, options) { + hb.compile = function (input, options) { return compile(input, options, hb); }; - hb.precompile = function(input, options) { + hb.precompile = function (input, options) { return precompile(input, options, hb); }; diff --git a/lib/handlebars.runtime.js b/lib/handlebars.runtime.js index 6b6270b2f..9d33940f2 100644 --- a/lib/handlebars.runtime.js +++ b/lib/handlebars.runtime.js @@ -20,7 +20,7 @@ function create() { hb.escapeExpression = Utils.escapeExpression; hb.VM = runtime; - hb.template = function(spec) { + hb.template = function (spec) { return runtime.template(spec, hb); }; diff --git a/lib/handlebars/base.js b/lib/handlebars/base.js index a84243f5d..371398f4a 100644 --- a/lib/handlebars/base.js +++ b/lib/handlebars/base.js @@ -17,7 +17,7 @@ export const REVISION_CHANGES = { 5: '== 2.0.0-alpha.x', 6: '>= 2.0.0-beta.1', 7: '>= 4.0.0 <4.3.0', - 8: '>= 4.3.0' + 8: '>= 4.3.0', }; const objectType = '[object Object]'; @@ -37,7 +37,7 @@ HandlebarsEnvironment.prototype = { logger: logger, log: logger.log, - registerHelper: function(name, fn) { + registerHelper: function (name, fn) { if (toString.call(name) === objectType) { if (fn) { throw new Exception('Arg not supported with multiple helpers'); @@ -47,11 +47,11 @@ HandlebarsEnvironment.prototype = { this.helpers[name] = fn; } }, - unregisterHelper: function(name) { + unregisterHelper: function (name) { delete this.helpers[name]; }, - registerPartial: function(name, partial) { + registerPartial: function (name, partial) { if (toString.call(name) === objectType) { extend(this.partials, name); } else { @@ -63,11 +63,11 @@ HandlebarsEnvironment.prototype = { this.partials[name] = partial; } }, - unregisterPartial: function(name) { + unregisterPartial: function (name) { delete this.partials[name]; }, - registerDecorator: function(name, fn) { + registerDecorator: function (name, fn) { if (toString.call(name) === objectType) { if (fn) { throw new Exception('Arg not supported with multiple decorators'); @@ -77,7 +77,7 @@ HandlebarsEnvironment.prototype = { this.decorators[name] = fn; } }, - unregisterDecorator: function(name) { + unregisterDecorator: function (name) { delete this.decorators[name]; }, /** @@ -86,7 +86,7 @@ HandlebarsEnvironment.prototype = { */ resetLoggedPropertyAccesses() { resetLoggedProperties(); - } + }, }; export let log = logger.log; diff --git a/lib/handlebars/compiler/ast.js b/lib/handlebars/compiler/ast.js index d77629a52..ee1cb5727 100644 --- a/lib/handlebars/compiler/ast.js +++ b/lib/handlebars/compiler/ast.js @@ -4,7 +4,7 @@ let AST = { // a mustache is definitely a helper if: // * it is an eligible helper, and // * it has at least one parameter or hash segment - helperExpression: function(node) { + helperExpression: function (node) { return ( node.type === 'SubExpression' || ((node.type === 'MustacheStatement' || @@ -13,18 +13,18 @@ let AST = { ); }, - scopedId: function(path) { + scopedId: function (path) { return /^\.|this\b/.test(path.original); }, // an ID is simple if it only has one part, and that part is not // `..` or `this`. - simpleId: function(path) { + simpleId: function (path) { return ( path.parts.length === 1 && !AST.helpers.scopedId(path) && !path.depth ); - } - } + }, + }, }; // Must be exported as an object rather than the root of the module as the jison lexer diff --git a/lib/handlebars/compiler/code-gen.js b/lib/handlebars/compiler/code-gen.js index 9feb61096..2d03e9798 100644 --- a/lib/handlebars/compiler/code-gen.js +++ b/lib/handlebars/compiler/code-gen.js @@ -17,7 +17,7 @@ try { /* istanbul ignore if: tested but not covered in istanbul due to dist build */ if (!SourceNode) { - SourceNode = function(line, column, srcFile, chunks) { + SourceNode = function (line, column, srcFile, chunks) { this.src = ''; if (chunks) { this.add(chunks); @@ -25,24 +25,24 @@ if (!SourceNode) { }; /* istanbul ignore next */ SourceNode.prototype = { - add: function(chunks) { + add: function (chunks) { if (isArray(chunks)) { chunks = chunks.join(''); } this.src += chunks; }, - prepend: function(chunks) { + prepend: function (chunks) { if (isArray(chunks)) { chunks = chunks.join(''); } this.src = chunks + this.src; }, - toStringWithSourceMap: function() { + toStringWithSourceMap: function () { return { code: this.toString() }; }, - toString: function() { + toString: function () { return this.src; - } + }, }; } @@ -70,32 +70,32 @@ CodeGen.prototype = { isEmpty() { return !this.source.length; }, - prepend: function(source, loc) { + prepend: function (source, loc) { this.source.unshift(this.wrap(source, loc)); }, - push: function(source, loc) { + push: function (source, loc) { this.source.push(this.wrap(source, loc)); }, - merge: function() { + merge: function () { let source = this.empty(); - this.each(function(line) { + this.each(function (line) { source.add([' ', line, '\n']); }); return source; }, - each: function(iter) { + each: function (iter) { for (let i = 0, len = this.source.length; i < len; i++) { iter(this.source[i]); } }, - empty: function() { + empty: function () { let loc = this.currentLocation || { start: {} }; return new SourceNode(loc.start.line, loc.start.column, this.srcFile); }, - wrap: function(chunk, loc = this.currentLocation || { start: {} }) { + wrap: function (chunk, loc = this.currentLocation || { start: {} }) { if (chunk instanceof SourceNode) { return chunk; } @@ -110,12 +110,12 @@ CodeGen.prototype = { ); }, - functionCall: function(fn, type, params) { + functionCall: function (fn, type, params) { params = this.generateList(params); return this.wrap([fn, type ? '.' + type + '(' : '(', params, ')']); }, - quotedString: function(str) { + quotedString: function (str) { return ( '"' + (str + '') @@ -129,10 +129,10 @@ CodeGen.prototype = { ); }, - objectLiteral: function(obj) { + objectLiteral: function (obj) { let pairs = []; - Object.keys(obj).forEach(key => { + Object.keys(obj).forEach((key) => { let value = castChunk(obj[key], this); if (value !== 'undefined') { pairs.push([this.quotedString(key), ':', value]); @@ -145,7 +145,7 @@ CodeGen.prototype = { return ret; }, - generateList: function(entries) { + generateList: function (entries) { let ret = this.empty(); for (let i = 0, len = entries.length; i < len; i++) { @@ -159,13 +159,13 @@ CodeGen.prototype = { return ret; }, - generateArray: function(entries) { + generateArray: function (entries) { let ret = this.generateList(entries); ret.prepend('['); ret.add(']'); return ret; - } + }, }; export default CodeGen; diff --git a/lib/handlebars/compiler/compiler.js b/lib/handlebars/compiler/compiler.js index 83a13ab51..d68a0062d 100644 --- a/lib/handlebars/compiler/compiler.js +++ b/lib/handlebars/compiler/compiler.js @@ -16,7 +16,7 @@ export function Compiler() {} Compiler.prototype = { compiler: Compiler, - equals: function(other) { + equals: function (other) { let len = this.opcodes.length; if (other.opcodes.length !== len) { return false; @@ -47,7 +47,7 @@ Compiler.prototype = { guid: 0, - compile: function(program, options) { + compile: function (program, options) { this.sourceNode = []; this.opcodes = []; this.children = []; @@ -65,7 +65,7 @@ Compiler.prototype = { unless: true, with: true, log: true, - lookup: true + lookup: true, }, options.knownHelpers ); @@ -73,7 +73,7 @@ Compiler.prototype = { return this.accept(program); }, - compileProgram: function(program) { + compileProgram: function (program) { let childCompiler = new this.compiler(), // eslint-disable-line new-cap result = childCompiler.compile(program, this.options), guid = this.guid++; @@ -86,7 +86,7 @@ Compiler.prototype = { return guid; }, - accept: function(node) { + accept: function (node) { /* istanbul ignore next: Sanity code */ if (!this[node.type]) { throw new Exception('Unknown type: ' + node.type, node); @@ -98,7 +98,7 @@ Compiler.prototype = { return ret; }, - Program: function(program) { + Program: function (program) { this.options.blockParams.unshift(program.blockParams); let body = program.body, @@ -115,7 +115,7 @@ Compiler.prototype = { return this; }, - BlockStatement: function(block) { + BlockStatement: function (block) { transformLiteralToPath(block); let program = block.program, @@ -160,7 +160,7 @@ Compiler.prototype = { this.opcode('registerDecorator', params.length, path.original); }, - PartialStatement: function(partial) { + PartialStatement: function (partial) { this.usePartial = true; let program = partial.program; @@ -199,11 +199,11 @@ Compiler.prototype = { this.opcode('invokePartial', isDynamic, partialName, indent); this.opcode('append'); }, - PartialBlockStatement: function(partialBlock) { + PartialBlockStatement: function (partialBlock) { this.PartialStatement(partialBlock); }, - MustacheStatement: function(mustache) { + MustacheStatement: function (mustache) { this.SubExpression(mustache); if (mustache.escaped && !this.options.noEscape) { @@ -216,15 +216,15 @@ Compiler.prototype = { this.DecoratorBlock(decorator); }, - ContentStatement: function(content) { + ContentStatement: function (content) { if (content.value) { this.opcode('appendContent', content.value); } }, - CommentStatement: function() {}, + CommentStatement: function () {}, - SubExpression: function(sexpr) { + SubExpression: function (sexpr) { transformLiteralToPath(sexpr); let type = this.classifySexpr(sexpr); @@ -236,7 +236,7 @@ Compiler.prototype = { this.ambiguousSexpr(sexpr); } }, - ambiguousSexpr: function(sexpr, program, inverse) { + ambiguousSexpr: function (sexpr, program, inverse) { let path = sexpr.path, name = path.parts[0], isBlock = program != null || inverse != null; @@ -252,14 +252,14 @@ Compiler.prototype = { this.opcode('invokeAmbiguous', name, isBlock); }, - simpleSexpr: function(sexpr) { + simpleSexpr: function (sexpr) { let path = sexpr.path; path.strict = true; this.accept(path); this.opcode('resolvePossibleLambda'); }, - helperSexpr: function(sexpr, program, inverse) { + helperSexpr: function (sexpr, program, inverse) { let params = this.setupFullMustacheParams(sexpr, program, inverse), path = sexpr.path, name = path.parts[0]; @@ -285,7 +285,7 @@ Compiler.prototype = { } }, - PathExpression: function(path) { + PathExpression: function (path) { this.addDepth(path.depth); this.opcode('getContext', path.depth); @@ -312,27 +312,27 @@ Compiler.prototype = { } }, - StringLiteral: function(string) { + StringLiteral: function (string) { this.opcode('pushString', string.value); }, - NumberLiteral: function(number) { + NumberLiteral: function (number) { this.opcode('pushLiteral', number.value); }, - BooleanLiteral: function(bool) { + BooleanLiteral: function (bool) { this.opcode('pushLiteral', bool.value); }, - UndefinedLiteral: function() { + UndefinedLiteral: function () { this.opcode('pushLiteral', 'undefined'); }, - NullLiteral: function() { + NullLiteral: function () { this.opcode('pushLiteral', 'null'); }, - Hash: function(hash) { + Hash: function (hash) { let pairs = hash.pairs, i = 0, l = pairs.length; @@ -349,15 +349,15 @@ Compiler.prototype = { }, // HELPERS - opcode: function(name) { + opcode: function (name) { this.opcodes.push({ opcode: name, args: slice.call(arguments, 1), - loc: this.sourceNode[0].loc + loc: this.sourceNode[0].loc, }); }, - addDepth: function(depth) { + addDepth: function (depth) { if (!depth) { return; } @@ -365,7 +365,7 @@ Compiler.prototype = { this.useDepths = true; }, - classifySexpr: function(sexpr) { + classifySexpr: function (sexpr) { let isSimple = AST.helpers.simpleId(sexpr.path); let isBlockParam = isSimple && !!this.blockParamIndex(sexpr.path.parts[0]); @@ -400,17 +400,17 @@ Compiler.prototype = { } }, - pushParams: function(params) { + pushParams: function (params) { for (let i = 0, l = params.length; i < l; i++) { this.pushParam(params[i]); } }, - pushParam: function(val) { + pushParam: function (val) { this.accept(val); }, - setupFullMustacheParams: function(sexpr, program, inverse, omitEmpty) { + setupFullMustacheParams: function (sexpr, program, inverse, omitEmpty) { let params = sexpr.params; this.pushParams(params); @@ -426,7 +426,7 @@ Compiler.prototype = { return params; }, - blockParamIndex: function(name) { + blockParamIndex: function (name) { for ( let depth = 0, len = this.options.blockParams.length; depth < len; @@ -438,7 +438,7 @@ Compiler.prototype = { return [depth, param]; } } - } + }, }; export function precompile(input, options = {}, env) { @@ -467,7 +467,7 @@ export function compile(input, options = {}, env) { } // Template is only compiled on first use and cached after that point. - return function(context, execOptions) { + return function (context, execOptions) { if (!compiled) { compiled = compileInput(); } @@ -530,7 +530,7 @@ function transformLiteralToPath(sexpr) { depth: 0, parts: [literal.original + ''], original: literal.original + '', - loc: literal.loc + loc: literal.loc, }; } } diff --git a/lib/handlebars/compiler/javascript-compiler.js b/lib/handlebars/compiler/javascript-compiler.js index d33975e30..678b42b02 100644 --- a/lib/handlebars/compiler/javascript-compiler.js +++ b/lib/handlebars/compiler/javascript-compiler.js @@ -12,25 +12,25 @@ function JavaScriptCompiler() {} JavaScriptCompiler.prototype = { // PUBLIC API: You can override these methods in a subclass to provide // alternative compiled forms for name lookup and buffering semantics - nameLookup: function(parent, name /*, type */) { + nameLookup: function (parent, name /*, type */) { return this.internalNameLookup(parent, name); }, - depthedLookup: function(name) { + depthedLookup: function (name) { return [ this.aliasable('container.lookup'), '(depths, ', JSON.stringify(name), - ')' + ')', ]; }, - compilerInfo: function() { + compilerInfo: function () { const revision = COMPILER_REVISION, versions = REVISION_CHANGES[revision]; return [revision, versions]; }, - appendToBuffer: function(source, location, explicit) { + appendToBuffer: function (source, location, explicit) { // Force a source as this simplifies the merge logic. if (!isArray(source)) { source = [source]; @@ -50,18 +50,18 @@ JavaScriptCompiler.prototype = { } }, - initializeBuffer: function() { + initializeBuffer: function () { return this.quotedString(''); }, // END PUBLIC API - internalNameLookup: function(parent, name) { + internalNameLookup: function (parent, name) { this.lookupPropertyFunctionIsUsed = true; return ['lookupProperty(', parent, ',', JSON.stringify(name), ')']; }, lookupPropertyFunctionIsUsed: false, - compile: function(environment, options, context, asObject) { + compile: function (environment, options, context, asObject) { this.environment = environment; this.options = options; this.precompile = !asObject; @@ -71,7 +71,7 @@ JavaScriptCompiler.prototype = { this.context = context || { decorators: [], programs: [], - environments: [] + environments: [], }; this.preamble(); @@ -123,7 +123,7 @@ JavaScriptCompiler.prototype = { this.decorators.prepend([ 'var decorators = container.decorators, ', this.lookupPropertyFunctionVarDeclaration(), - ';\n' + ';\n', ]); this.decorators.push('return fn;'); @@ -137,7 +137,7 @@ JavaScriptCompiler.prototype = { 'data', 'blockParams', 'depths', - this.decorators.merge() + this.decorators.merge(), ]); } else { this.decorators.prepend( @@ -154,7 +154,7 @@ JavaScriptCompiler.prototype = { if (!this.isChild) { let ret = { compiler: this.compilerInfo(), - main: fn + main: fn, }; if (this.decorators) { @@ -211,7 +211,7 @@ JavaScriptCompiler.prototype = { } }, - preamble: function() { + preamble: function () { // track the last context pushed into place to allow skipping the // getContext opcode when it would be a noop this.lastContext = 0; @@ -219,7 +219,7 @@ JavaScriptCompiler.prototype = { this.decorators = new CodeGen(this.options.srcName); }, - createFunctionContext: function(asObject) { + createFunctionContext: function (asObject) { let varDeclarations = ''; let locals = this.stackVars.concat(this.registers.list); @@ -234,7 +234,7 @@ JavaScriptCompiler.prototype = { // aliases will not be used, but this case is already being run on the client and // we aren't concern about minimizing the template size. let aliasCount = 0; - Object.keys(this.aliases).forEach(alias => { + Object.keys(this.aliases).forEach((alias) => { let node = this.aliases[alias]; if (node.children && node.referenceCount > 1) { varDeclarations += ', alias' + ++aliasCount + '=' + alias; @@ -268,18 +268,18 @@ JavaScriptCompiler.prototype = { params.join(','), ') {\n ', source, - '}' + '}', ]); } }, - mergeSource: function(varDeclarations) { + mergeSource: function (varDeclarations) { let isSimple = this.environment.isSimple, appendOnly = !this.forceBuffer, appendFirst, sourceSeen, bufferStart, bufferEnd; - this.source.each(line => { + this.source.each((line) => { if (line.appendToBuffer) { if (bufferStart) { line.prepend(' + '); @@ -333,7 +333,7 @@ JavaScriptCompiler.prototype = { return this.source.merge(); }, - lookupPropertyFunctionVarDeclaration: function() { + lookupPropertyFunctionVarDeclaration: function () { return ` lookupProperty = container.lookupProperty || function(parent, propertyName) { if (Object.prototype.hasOwnProperty.call(parent, propertyName)) { @@ -353,7 +353,7 @@ JavaScriptCompiler.prototype = { // `{{#this.foo}}...{{/this.foo}}`, resolve the value of `foo`, and // replace it on the stack with the result of properly // invoking blockHelperMissing. - blockValue: function(name) { + blockValue: function (name) { let blockHelperMissing = this.aliasable( 'container.hooks.blockHelperMissing' ), @@ -372,7 +372,7 @@ JavaScriptCompiler.prototype = { // Compiler value, before: lastHelper=value of last found helper, if any // On stack, after, if no lastHelper: same as [blockValue] // On stack, after, if lastHelper: value - ambiguousBlockValue: function() { + ambiguousBlockValue: function () { // We're being a bit cheeky and reusing the options value from the prior exec let blockHelperMissing = this.aliasable( 'container.hooks.blockHelperMissing' @@ -392,7 +392,7 @@ JavaScriptCompiler.prototype = { current, ' = ', this.source.functionCall(blockHelperMissing, 'call', params), - '}' + '}', ]); }, @@ -402,7 +402,7 @@ JavaScriptCompiler.prototype = { // On stack, after: ... // // Appends the string value of `content` to the current buffer - appendContent: function(content) { + appendContent: function (content) { if (this.pendingContent) { content = this.pendingContent + content; } else { @@ -421,9 +421,9 @@ JavaScriptCompiler.prototype = { // // If `value` is truthy, or 0, it is coerced into a string and appended // Otherwise, the empty string is appended - append: function() { + append: function () { if (this.isInline()) { - this.replaceStack(current => [' != null ? ', current, ' : ""']); + this.replaceStack((current) => [' != null ? ', current, ' : ""']); this.pushSource(this.appendToBuffer(this.popStack())); } else { @@ -433,13 +433,13 @@ JavaScriptCompiler.prototype = { local, ' != null) { ', this.appendToBuffer(local, undefined, true), - ' }' + ' }', ]); if (this.environment.isSimple) { this.pushSource([ 'else { ', this.appendToBuffer("''", undefined, true), - ' }' + ' }', ]); } } @@ -451,13 +451,13 @@ JavaScriptCompiler.prototype = { // On stack, after: ... // // Escape `value` and append it to the buffer - appendEscaped: function() { + appendEscaped: function () { this.pushSource( this.appendToBuffer([ this.aliasable('container.escapeExpression'), '(', this.popStack(), - ')' + ')', ]) ); }, @@ -469,7 +469,7 @@ JavaScriptCompiler.prototype = { // Compiler value, after: lastContext=depth // // Set the value of the `lastContext` compiler value to the depth - getContext: function(depth) { + getContext: function (depth) { this.lastContext = depth; }, @@ -479,7 +479,7 @@ JavaScriptCompiler.prototype = { // On stack, after: currentContext, ... // // Pushes the value of the current context onto the stack. - pushContext: function() { + pushContext: function () { this.pushStackLiteral(this.contextName(this.lastContext)); }, @@ -490,7 +490,7 @@ JavaScriptCompiler.prototype = { // // Looks up the value of `name` on the current context and pushes // it onto the stack. - lookupOnContext: function(parts, falsy, strict, scoped) { + lookupOnContext: function (parts, falsy, strict, scoped) { let i = 0; if (!scoped && this.options.compat && !this.lastContext) { @@ -511,7 +511,7 @@ JavaScriptCompiler.prototype = { // // Looks up the value of `parts` on the given block param and pushes // it onto the stack. - lookupBlockParam: function(blockParamId, parts) { + lookupBlockParam: function (blockParamId, parts) { this.useBlockParams = true; this.push(['blockParams[', blockParamId[0], '][', blockParamId[1], ']']); @@ -524,7 +524,7 @@ JavaScriptCompiler.prototype = { // On stack, after: data, ... // // Push the data lookup operator - lookupData: function(depth, parts, strict) { + lookupData: function (depth, parts, strict) { if (!depth) { this.pushStackLiteral('data'); } else { @@ -534,7 +534,7 @@ JavaScriptCompiler.prototype = { this.resolvePath('data', parts, 0, true, strict); }, - resolvePath: function(type, parts, i, falsy, strict) { + resolvePath: function (type, parts, i, falsy, strict) { if (this.options.strict || this.options.assumeObjects) { this.push( strictLookup(this.options.strict && strict, this, parts, i, type) @@ -545,7 +545,7 @@ JavaScriptCompiler.prototype = { let len = parts.length; for (; i < len; i++) { /* eslint-disable no-loop-func */ - this.replaceStack(current => { + this.replaceStack((current) => { let lookup = this.nameLookup(current, parts[i], type); // We want to ensure that zero and false are handled properly if the context (falsy flag) // needs to have the special handling for these values. @@ -567,27 +567,27 @@ JavaScriptCompiler.prototype = { // // If the `value` is a lambda, replace it on the stack by // the return value of the lambda - resolvePossibleLambda: function() { + resolvePossibleLambda: function () { this.push([ this.aliasable('container.lambda'), '(', this.popStack(), ', ', this.contextName(0), - ')' + ')', ]); }, - emptyHash: function(omitEmpty) { + emptyHash: function (omitEmpty) { this.pushStackLiteral(omitEmpty ? 'undefined' : '{}'); }, - pushHash: function() { + pushHash: function () { if (this.hash) { this.hashes.push(this.hash); } this.hash = { values: {} }; }, - popHash: function() { + popHash: function () { let hash = this.hash; this.hash = this.hashes.pop(); @@ -600,7 +600,7 @@ JavaScriptCompiler.prototype = { // On stack, after: quotedString(string), ... // // Push a quoted version of `string` onto the stack - pushString: function(string) { + pushString: function (string) { this.pushStackLiteral(this.quotedString(string)); }, @@ -612,7 +612,7 @@ JavaScriptCompiler.prototype = { // Pushes a value onto the stack. This operation prevents // the compiler from creating a temporary variable to hold // it. - pushLiteral: function(value) { + pushLiteral: function (value) { this.pushStackLiteral(value); }, @@ -624,7 +624,7 @@ JavaScriptCompiler.prototype = { // Push a program expression onto the stack. This takes // a compile-time guid and converts it into a runtime-accessible // expression. - pushProgram: function(guid) { + pushProgram: function (guid) { if (guid != null) { this.pushStackLiteral(this.programExpression(guid)); } else { @@ -649,9 +649,9 @@ JavaScriptCompiler.prototype = { 'fn', 'props', 'container', - options + options, ]), - ' || fn;' + ' || fn;', ]); }, @@ -664,7 +664,7 @@ JavaScriptCompiler.prototype = { // and pushes the helper's return value onto the stack. // // If the helper is not found, `helperMissing` is called. - invokeHelper: function(paramSize, name, isSimple) { + invokeHelper: function (paramSize, name, isSimple) { let nonHelper = this.popStack(), helper = this.setupHelper(paramSize, name); @@ -685,7 +685,7 @@ JavaScriptCompiler.prototype = { let functionLookupCode = [ '(', this.itemsSeparatedBy(possibleFunctionCalls, '||'), - ')' + ')', ]; let functionCall = this.source.functionCall( functionLookupCode, @@ -695,7 +695,7 @@ JavaScriptCompiler.prototype = { this.push(functionCall); }, - itemsSeparatedBy: function(items, separator) { + itemsSeparatedBy: function (items, separator) { let result = []; result.push(items[0]); for (let i = 1; i < items.length; i++) { @@ -710,7 +710,7 @@ JavaScriptCompiler.prototype = { // // This operation is used when the helper is known to exist, // so a `helperMissing` fallback is not required. - invokeKnownHelper: function(paramSize, name) { + invokeKnownHelper: function (paramSize, name) { let helper = this.setupHelper(paramSize, name); this.push(this.source.functionCall(helper.name, 'call', helper.callParams)); }, @@ -727,7 +727,7 @@ JavaScriptCompiler.prototype = { // This operation emits more code than the other options, // and can be avoided by passing the `knownHelpers` and // `knownHelpersOnly` flags at compile-time. - invokeAmbiguous: function(name, helperCall) { + invokeAmbiguous: function (name, helperCall) { this.useRegister('helper'); let nonHelper = this.popStack(); @@ -759,7 +759,7 @@ JavaScriptCompiler.prototype = { this.aliasable('"function"'), ' ? ', this.source.functionCall('helper', 'call', helper.callParams), - ' : helper))' + ' : helper))', ]); }, @@ -770,7 +770,7 @@ JavaScriptCompiler.prototype = { // // This operation pops off a context, invokes a partial with that context, // and pushes the result of the invocation back. - invokePartial: function(isDynamic, name, indent) { + invokePartial: function (isDynamic, name, indent) { let params = [], options = this.setupParams(name, 1, params); @@ -807,7 +807,7 @@ JavaScriptCompiler.prototype = { // On stack, after: ..., hash, ... // // Pops a value off the stack and assigns it to the current hash - assignToHash: function(key) { + assignToHash: function (key) { this.hash.values[key] = this.popStack(); }, @@ -815,7 +815,7 @@ JavaScriptCompiler.prototype = { compiler: JavaScriptCompiler, - compileChildren: function(environment, options) { + compileChildren: function (environment, options) { let children = environment.children, child, compiler; @@ -853,7 +853,7 @@ JavaScriptCompiler.prototype = { } } }, - matchExistingProgram: function(child) { + matchExistingProgram: function (child) { for (let i = 0, len = this.context.environments.length; i < len; i++) { let environment = this.context.environments[i]; if (environment && environment.equals(child)) { @@ -862,7 +862,7 @@ JavaScriptCompiler.prototype = { } }, - programExpression: function(guid) { + programExpression: function (guid) { let child = this.environment.children[guid], programParams = [child.index, 'data', child.blockParams]; @@ -876,14 +876,14 @@ JavaScriptCompiler.prototype = { return 'container.program(' + programParams.join(', ') + ')'; }, - useRegister: function(name) { + useRegister: function (name) { if (!this.registers[name]) { this.registers[name] = true; this.registers.list.push(name); } }, - push: function(expr) { + push: function (expr) { if (!(expr instanceof Literal)) { expr = this.source.wrap(expr); } @@ -892,11 +892,11 @@ JavaScriptCompiler.prototype = { return expr; }, - pushStackLiteral: function(item) { + pushStackLiteral: function (item) { this.push(new Literal(item)); }, - pushSource: function(source) { + pushSource: function (source) { if (this.pendingContent) { this.source.push( this.appendToBuffer( @@ -912,7 +912,7 @@ JavaScriptCompiler.prototype = { } }, - replaceStack: function(callback) { + replaceStack: function (callback) { let prefix = ['('], stack, createdStack, @@ -951,17 +951,17 @@ JavaScriptCompiler.prototype = { this.push(prefix.concat(item, ')')); }, - incrStack: function() { + incrStack: function () { this.stackSlot++; if (this.stackSlot > this.stackVars.length) { this.stackVars.push('stack' + this.stackSlot); } return this.topStackName(); }, - topStackName: function() { + topStackName: function () { return 'stack' + this.stackSlot; }, - flushInline: function() { + flushInline: function () { let inlineStack = this.inlineStack; this.inlineStack = []; for (let i = 0, len = inlineStack.length; i < len; i++) { @@ -976,11 +976,11 @@ JavaScriptCompiler.prototype = { } } }, - isInline: function() { + isInline: function () { return this.inlineStack.length; }, - popStack: function(wrapped) { + popStack: function (wrapped) { let inline = this.isInline(), item = (inline ? this.inlineStack : this.compileStack).pop(); @@ -998,7 +998,7 @@ JavaScriptCompiler.prototype = { } }, - topStack: function() { + topStack: function () { let stack = this.isInline() ? this.inlineStack : this.compileStack, item = stack[stack.length - 1]; @@ -1010,7 +1010,7 @@ JavaScriptCompiler.prototype = { } }, - contextName: function(context) { + contextName: function (context) { if (this.useDepths && context) { return 'depths[' + context + ']'; } else { @@ -1018,15 +1018,15 @@ JavaScriptCompiler.prototype = { } }, - quotedString: function(str) { + quotedString: function (str) { return this.source.quotedString(str); }, - objectLiteral: function(obj) { + objectLiteral: function (obj) { return this.source.objectLiteral(obj); }, - aliasable: function(name) { + aliasable: function (name) { let ret = this.aliases[name]; if (ret) { ret.referenceCount++; @@ -1040,7 +1040,7 @@ JavaScriptCompiler.prototype = { return ret; }, - setupHelper: function(paramSize, name, blockHelper) { + setupHelper: function (paramSize, name, blockHelper) { let params = [], paramsInit = this.setupHelperArgs(name, paramSize, params, blockHelper); let foundHelper = this.nameLookup('helpers', name, 'helper'), @@ -1054,11 +1054,11 @@ JavaScriptCompiler.prototype = { params: params, paramsInit: paramsInit, name: foundHelper, - callParams: [callContext].concat(params) + callParams: [callContext].concat(params), }; }, - setupParams: function(helper, paramSize, params) { + setupParams: function (helper, paramSize, params) { let options = {}, objectArgs = !params, param; @@ -1101,7 +1101,7 @@ JavaScriptCompiler.prototype = { return options; }, - setupHelperArgs: function(helper, paramSize, params, useRegister) { + setupHelperArgs: function (helper, paramSize, params, useRegister) { let options = this.setupParams(helper, paramSize, params); options.loc = JSON.stringify(this.source.currentLocation); options = this.objectLiteral(options); @@ -1115,10 +1115,10 @@ JavaScriptCompiler.prototype = { } else { return options; } - } + }, }; -(function() { +(function () { const reservedWords = ( 'break else new var' + ' case finally return void' + @@ -1148,7 +1148,7 @@ JavaScriptCompiler.prototype = { /** * @deprecated May be removed in the next major version */ -JavaScriptCompiler.isValidJavaScriptVariableName = function(name) { +JavaScriptCompiler.isValidJavaScriptVariableName = function (name) { return ( !JavaScriptCompiler.RESERVED_WORDS[name] && /^[a-zA-Z_$][0-9a-zA-Z_$]*$/.test(name) @@ -1175,7 +1175,7 @@ function strictLookup(requireTerminal, compiler, parts, i, type) { compiler.quotedString(parts[i]), ', ', JSON.stringify(compiler.source.currentLocation), - ' )' + ' )', ]; } else { return stack; diff --git a/lib/handlebars/decorators/inline.js b/lib/handlebars/decorators/inline.js index 02f5be7b5..fe7a437a0 100644 --- a/lib/handlebars/decorators/inline.js +++ b/lib/handlebars/decorators/inline.js @@ -1,22 +1,25 @@ import { extend } from '../utils'; -export default function(instance) { - instance.registerDecorator('inline', function(fn, props, container, options) { - let ret = fn; - if (!props.partials) { - props.partials = {}; - ret = function(context, options) { - // Create a new partials stack frame prior to exec. - let original = container.partials; - container.partials = extend({}, original, props.partials); - let ret = fn(context, options); - container.partials = original; - return ret; - }; - } +export default function (instance) { + instance.registerDecorator( + 'inline', + function (fn, props, container, options) { + let ret = fn; + if (!props.partials) { + props.partials = {}; + ret = function (context, options) { + // Create a new partials stack frame prior to exec. + let original = container.partials; + container.partials = extend({}, original, props.partials); + let ret = fn(context, options); + container.partials = original; + return ret; + }; + } - props.partials[options.args[0]] = options.fn; + props.partials[options.args[0]] = options.fn; - return ret; - }); + return ret; + } + ); } diff --git a/lib/handlebars/helpers/block-helper-missing.js b/lib/handlebars/helpers/block-helper-missing.js index c16ad1a64..c9e1b7501 100644 --- a/lib/handlebars/helpers/block-helper-missing.js +++ b/lib/handlebars/helpers/block-helper-missing.js @@ -1,7 +1,7 @@ import { isArray } from '../utils'; -export default function(instance) { - instance.registerHelper('blockHelperMissing', function(context, options) { +export default function (instance) { + instance.registerHelper('blockHelperMissing', function (context, options) { let inverse = options.inverse, fn = options.fn; diff --git a/lib/handlebars/helpers/each.js b/lib/handlebars/helpers/each.js index 0c7e6263e..309c2786f 100644 --- a/lib/handlebars/helpers/each.js +++ b/lib/handlebars/helpers/each.js @@ -1,8 +1,8 @@ import { Exception } from '@handlebars/parser'; import { createFrame, isArray, isFunction } from '../utils'; -export default function(instance) { - instance.registerHelper('each', function(context, options) { +export default function (instance) { + instance.registerHelper('each', function (context, options) { if (!options) { throw new Exception('Must pass iterator to #each'); } @@ -33,7 +33,7 @@ export default function(instance) { ret + fn(context[field], { data: data, - blockParams: [context[field], field] + blockParams: [context[field], field], }); } @@ -57,7 +57,7 @@ export default function(instance) { } else { let priorKey; - Object.keys(context).forEach(key => { + Object.keys(context).forEach((key) => { // We're running the iterations one step out of sync so we can detect // the last iteration without have to scan the object twice and create // an intermediate keys array. diff --git a/lib/handlebars/helpers/helper-missing.js b/lib/handlebars/helpers/helper-missing.js index 6daf44253..c59a3206a 100644 --- a/lib/handlebars/helpers/helper-missing.js +++ b/lib/handlebars/helpers/helper-missing.js @@ -1,7 +1,7 @@ import { Exception } from '@handlebars/parser'; -export default function(instance) { - instance.registerHelper('helperMissing', function(/* [args, ]options */) { +export default function (instance) { + instance.registerHelper('helperMissing', function (/* [args, ]options */) { if (arguments.length === 1) { // A missing field in a {{foo}} construct. return undefined; diff --git a/lib/handlebars/helpers/if.js b/lib/handlebars/helpers/if.js index 74d5dac5a..bb2f4dfaa 100644 --- a/lib/handlebars/helpers/if.js +++ b/lib/handlebars/helpers/if.js @@ -1,8 +1,8 @@ import { Exception } from '@handlebars/parser'; import { isEmpty, isFunction } from '../utils'; -export default function(instance) { - instance.registerHelper('if', function(conditional, options) { +export default function (instance) { + instance.registerHelper('if', function (conditional, options) { if (arguments.length != 2) { throw new Exception('#if requires exactly one argument'); } @@ -20,14 +20,14 @@ export default function(instance) { } }); - instance.registerHelper('unless', function(conditional, options) { + instance.registerHelper('unless', function (conditional, options) { if (arguments.length != 2) { throw new Exception('#unless requires exactly one argument'); } return instance.helpers['if'].call(this, conditional, { fn: options.inverse, inverse: options.fn, - hash: options.hash + hash: options.hash, }); }); } diff --git a/lib/handlebars/helpers/log.js b/lib/handlebars/helpers/log.js index ab0d73646..799ec6b2f 100644 --- a/lib/handlebars/helpers/log.js +++ b/lib/handlebars/helpers/log.js @@ -1,5 +1,5 @@ -export default function(instance) { - instance.registerHelper('log', function(/* message, options */) { +export default function (instance) { + instance.registerHelper('log', function (/* message, options */) { let args = [undefined], options = arguments[arguments.length - 1]; for (let i = 0; i < arguments.length - 1; i++) { diff --git a/lib/handlebars/helpers/lookup.js b/lib/handlebars/helpers/lookup.js index 5620aba32..14bcb04a2 100644 --- a/lib/handlebars/helpers/lookup.js +++ b/lib/handlebars/helpers/lookup.js @@ -1,5 +1,5 @@ -export default function(instance) { - instance.registerHelper('lookup', function(obj, field, options) { +export default function (instance) { + instance.registerHelper('lookup', function (obj, field, options) { if (!obj) { // Note for 5.0: Change to "obj == null" in 5.0 return obj; diff --git a/lib/handlebars/helpers/with.js b/lib/handlebars/helpers/with.js index 63559be5c..908477bda 100644 --- a/lib/handlebars/helpers/with.js +++ b/lib/handlebars/helpers/with.js @@ -1,8 +1,8 @@ import { Exception } from '@handlebars/parser'; import { isEmpty, isFunction } from '../utils'; -export default function(instance) { - instance.registerHelper('with', function(context, options) { +export default function (instance) { + instance.registerHelper('with', function (context, options) { if (arguments.length != 2) { throw new Exception('#with requires exactly one argument'); } @@ -17,7 +17,7 @@ export default function(instance) { return fn(context, { data: data, - blockParams: [context] + blockParams: [context], }); } else { return options.inverse(this); diff --git a/lib/handlebars/internal/proto-access.js b/lib/handlebars/internal/proto-access.js index 1d040c4b3..9d19c23f7 100644 --- a/lib/handlebars/internal/proto-access.js +++ b/lib/handlebars/internal/proto-access.js @@ -20,15 +20,15 @@ export function createProtoAccessControl(runtimeOptions) { defaultPropertyWhiteList, runtimeOptions.allowedProtoProperties ), - defaultValue: runtimeOptions.allowProtoPropertiesByDefault + defaultValue: runtimeOptions.allowProtoPropertiesByDefault, }, methods: { whitelist: createNewLookupObject( defaultMethodWhiteList, runtimeOptions.allowedProtoMethods ), - defaultValue: runtimeOptions.allowProtoMethodsByDefault - } + defaultValue: runtimeOptions.allowProtoMethodsByDefault, + }, }; } @@ -64,7 +64,7 @@ function logUnexpectedPropertyAccessOnce(propertyName) { } export function resetLoggedProperties() { - Object.keys(loggedProperties).forEach(propertyName => { + Object.keys(loggedProperties).forEach((propertyName) => { delete loggedProperties[propertyName]; }); } diff --git a/lib/handlebars/internal/wrapHelper.js b/lib/handlebars/internal/wrapHelper.js index cd321d57e..161cce3dc 100644 --- a/lib/handlebars/internal/wrapHelper.js +++ b/lib/handlebars/internal/wrapHelper.js @@ -4,7 +4,7 @@ export function wrapHelper(helper, transformOptionsFn) { // We try to make the wrapper least-invasive by not wrapping it, if the helper is not a function. return helper; } - let wrapper = function(/* dynamic arguments */) { + let wrapper = function (/* dynamic arguments */) { const options = arguments[arguments.length - 1]; arguments[arguments.length - 1] = transformOptionsFn(options); return helper.apply(this, arguments); diff --git a/lib/handlebars/logger.js b/lib/handlebars/logger.js index bc411b250..a7022ef04 100644 --- a/lib/handlebars/logger.js +++ b/lib/handlebars/logger.js @@ -5,7 +5,7 @@ let logger = { level: 'info', // Maps a given level value to the `methodMap` indexes above. - lookupLevel: function(level) { + lookupLevel: function (level) { if (typeof level === 'string') { let levelMap = indexOf(logger.methodMap, level.toLowerCase()); if (levelMap >= 0) { @@ -19,7 +19,7 @@ let logger = { }, // Can be overridden in the host environment - log: function(level, ...message) { + log: function (level, ...message) { level = logger.lookupLevel(level); if ( @@ -33,7 +33,7 @@ let logger = { } console[method](...message); // eslint-disable-line no-console } - } + }, }; export default logger; diff --git a/lib/handlebars/no-conflict.js b/lib/handlebars/no-conflict.js index 5a6db3e9a..c19ced36a 100644 --- a/lib/handlebars/no-conflict.js +++ b/lib/handlebars/no-conflict.js @@ -1,9 +1,9 @@ -export default function(Handlebars) { +export default function (Handlebars) { /* istanbul ignore next */ let root = typeof global !== 'undefined' ? global : window, // eslint-disable-line no-undef $Handlebars = root.Handlebars; /* istanbul ignore next */ - Handlebars.noConflict = function() { + Handlebars.noConflict = function () { if (root.Handlebars === Handlebars) { root.Handlebars = $Handlebars; } diff --git a/lib/handlebars/runtime.js b/lib/handlebars/runtime.js index 999f2cb8c..1c7cc4ccb 100644 --- a/lib/handlebars/runtime.js +++ b/lib/handlebars/runtime.js @@ -4,13 +4,13 @@ import { COMPILER_REVISION, createFrame, LAST_COMPATIBLE_COMPILER_REVISION, - REVISION_CHANGES + REVISION_CHANGES, } from './base'; import { moveHelperToHooks } from './helpers'; import { wrapHelper } from './internal/wrapHelper'; import { createProtoAccessControl, - resultIsAllowed + resultIsAllowed, } from './internal/proto-access'; export function checkRevision(compilerInfo) { @@ -73,7 +73,7 @@ export function template(templateSpec, env) { let extendedOptions = Utils.extend({}, options, { hooks: this.hooks, - protoAccessControl: this.protoAccessControl + protoAccessControl: this.protoAccessControl, }); let result = env.VM.invokePartial.call( @@ -115,15 +115,15 @@ export function template(templateSpec, env) { // Just add water let container = { - strict: function(obj, name, loc) { + strict: function (obj, name, loc) { if (!obj || !(name in obj)) { throw new Exception('"' + name + '" not defined in ' + obj, { - loc: loc + loc: loc, }); } return container.lookupProperty(obj, name); }, - lookupProperty: function(parent, propertyName) { + lookupProperty: function (parent, propertyName) { let result = parent[propertyName]; if (result == null) { return result; @@ -137,7 +137,7 @@ export function template(templateSpec, env) { } return undefined; }, - lookup: function(depths, name) { + lookup: function (depths, name) { const len = depths.length; for (let i = 0; i < len; i++) { let result = depths[i] && container.lookupProperty(depths[i], name); @@ -146,21 +146,21 @@ export function template(templateSpec, env) { } } }, - lambda: function(current, context) { + lambda: function (current, context) { return typeof current === 'function' ? current.call(context) : current; }, escapeExpression: Utils.escapeExpression, invokePartial: invokePartialWrapper, - fn: function(i) { + fn: function (i) { let ret = templateSpec[i]; ret.decorator = templateSpec[i + '_d']; return ret; }, programs: [], - program: function(i, data, declaredBlockParams, blockParams, depths) { + program: function (i, data, declaredBlockParams, blockParams, depths) { let programWrapper = this.programs[i], fn = this.fn(i); if (data || depths || blockParams || declaredBlockParams) { @@ -179,13 +179,13 @@ export function template(templateSpec, env) { return programWrapper; }, - data: function(value, depth) { + data: function (value, depth) { while (value && depth--) { value = value._parent; } return value; }, - mergeIfNeeded: function(param, common) { + mergeIfNeeded: function (param, common) { let obj = param || common; if (param && common && param !== common) { @@ -198,7 +198,7 @@ export function template(templateSpec, env) { nullContext: Object.seal({}), noop: env.VM.noop, - compilerInfo: templateSpec.compiler + compilerInfo: templateSpec.compiler, }; function ret(context, options = {}) { @@ -412,7 +412,7 @@ function executeDecorators(fn, prog, container, depths, data, blockParams) { } function wrapHelpersToPassLookupProperty(mergedHelpers, container) { - Object.keys(mergedHelpers).forEach(helperName => { + Object.keys(mergedHelpers).forEach((helperName) => { let helper = mergedHelpers[helperName]; mergedHelpers[helperName] = passLookupPropertyOption(helper, container); }); @@ -420,7 +420,7 @@ function wrapHelpersToPassLookupProperty(mergedHelpers, container) { function passLookupPropertyOption(helper, container) { const lookupProperty = container.lookupProperty; - return wrapHelper(helper, options => { + return wrapHelper(helper, (options) => { return Utils.extend({ lookupProperty }, options); }); } diff --git a/lib/handlebars/safe-string.js b/lib/handlebars/safe-string.js index 468019421..c655eeea1 100644 --- a/lib/handlebars/safe-string.js +++ b/lib/handlebars/safe-string.js @@ -3,7 +3,7 @@ function SafeString(string) { this.string = string; } -SafeString.prototype.toString = SafeString.prototype.toHTML = function() { +SafeString.prototype.toString = SafeString.prototype.toHTML = function () { return '' + this.string; }; diff --git a/lib/handlebars/utils.js b/lib/handlebars/utils.js index 2fa2b6b97..c1ca0d440 100644 --- a/lib/handlebars/utils.js +++ b/lib/handlebars/utils.js @@ -5,7 +5,7 @@ const escape = { '"': '"', "'": ''', '`': '`', - '=': '=' + '=': '=', }; const badChars = /[&<>"'`=]/g, @@ -38,7 +38,7 @@ export function isFunction(value) { /* istanbul ignore next */ export const isArray = Array.isArray || - function(value) { + function (value) { return value && typeof value === 'object' ? toString.call(value) === '[object Array]' : false; diff --git a/lib/precompiler.js b/lib/precompiler.js index ab6056932..2b3fb69df 100644 --- a/lib/precompiler.js +++ b/lib/precompiler.js @@ -6,12 +6,12 @@ import * as Handlebars from './handlebars'; import { basename } from 'path'; import { SourceMapConsumer, SourceNode } from 'source-map'; -module.exports.loadTemplates = function(opts, callback) { - loadStrings(opts, function(err, strings) { +module.exports.loadTemplates = function (opts, callback) { + loadStrings(opts, function (err, strings) { if (err) { callback(err); } else { - loadFiles(opts, function(err, files) { + loadFiles(opts, function (err, files) { if (err) { callback(err); } else { @@ -37,7 +37,7 @@ function loadStrings(opts, callback) { Async.map( strings, - function(string, callback) { + function (string, callback) { if (string !== '-') { callback(undefined, string); } else { @@ -45,19 +45,19 @@ function loadStrings(opts, callback) { let buffer = ''; process.stdin.setEncoding('utf8'); - process.stdin.on('data', function(chunk) { + process.stdin.on('data', function (chunk) { buffer += chunk; }); - process.stdin.on('end', function() { + process.stdin.on('end', function () { callback(undefined, buffer); }); } }, - function(err, strings) { + function (err, strings) { strings = strings.map((string, index) => ({ name: names[index], path: names[index], - source: string + source: string, })); callback(err, strings); } @@ -68,20 +68,23 @@ function loadFiles(opts, callback) { // Build file extension pattern let extension = (opts.extension || 'handlebars').replace( /[\\^$*+?.():=!|{}\-[\]]/g, - function(arg) { + function (arg) { return '\\' + arg; } ); extension = new RegExp('\\.' + extension + '$'); let ret = [], - queue = (opts.files || []).map(template => ({ template, root: opts.root })); + queue = (opts.files || []).map((template) => ({ + template, + root: opts.root, + })); Async.whilst( () => queue.length, - function(callback) { + function (callback) { let { template: path, root } = queue.shift(); - fs.stat(path, function(err, stat) { + fs.stat(path, function (err, stat) { if (err) { return callback( new Handlebars.Exception(`Unable to open template file "${path}"`) @@ -91,12 +94,12 @@ function loadFiles(opts, callback) { if (stat.isDirectory()) { opts.hasDirectory = true; - fs.readdir(path, function(err, children) { + fs.readdir(path, function (err, children) { /* istanbul ignore next : Race condition that being too lazy to test */ if (err) { return callback(err); } - children.forEach(function(file) { + children.forEach(function (file) { let childPath = path + '/' + file; if ( @@ -110,7 +113,7 @@ function loadFiles(opts, callback) { callback(); }); } else { - fs.readFile(path, 'utf8', function(err, data) { + fs.readFile(path, 'utf8', function (err, data) { /* istanbul ignore next : Race condition that being too lazy to test */ if (err) { return callback(err); @@ -132,7 +135,7 @@ function loadFiles(opts, callback) { ret.push({ path: path, name: name, - source: data + source: data, }); callback(); @@ -140,7 +143,7 @@ function loadFiles(opts, callback) { } }); }, - function(err) { + function (err) { if (err) { callback(err); } else { @@ -150,7 +153,7 @@ function loadFiles(opts, callback) { ); } -module.exports.cli = function(opts) { +module.exports.cli = function (opts) { if (opts.version) { console.log(Handlebars.VERSION); return; @@ -219,10 +222,10 @@ module.exports.cli = function(opts) { output.add('{};\n'); } - opts.templates.forEach(function(template) { + opts.templates.forEach(function (template) { let options = { knownHelpers: known, - knownHelpersOnly: opts.o + knownHelpersOnly: opts.o, }; if (opts.map) { @@ -259,7 +262,7 @@ module.exports.cli = function(opts) { template.name, "'] = template(", precompiled, - ');\n' + ');\n', ]); } }); @@ -335,7 +338,7 @@ function minify(output, sourceMapFile) { return require('uglify-js').minify(output.code, { sourceMap: { content: output.map, - url: sourceMapFile - } + url: sourceMapFile, + }, }); } diff --git a/nyc.config.js b/nyc.config.js index 3f52f089e..b71608a8a 100644 --- a/nyc.config.js +++ b/nyc.config.js @@ -5,5 +5,5 @@ module.exports = { functions: 100, statements: 100, exclude: ['**/spec/**'], - reporter: 'html' + reporter: 'html', }; diff --git a/package-lock.json b/package-lock.json index 28e43d4f7..da1138f4c 100644 --- a/package-lock.json +++ b/package-lock.json @@ -51,7 +51,7 @@ "mock-stdin": "^0.3.0", "mustache": "^2.1.3", "nyc": "^14.1.1", - "prettier": "^1.19.1", + "prettier": "^2.7.1", "semver": "^5.0.1", "sinon": "^7.5.0", "typescript": "^3.4.3", @@ -11268,15 +11268,18 @@ } }, "node_modules/prettier": { - "version": "1.19.1", - "resolved": "https://registry.npmjs.org/prettier/-/prettier-1.19.1.tgz", - "integrity": "sha512-s7PoyDv/II1ObgQunCbB9PdLmUcBZcnWOcxDh7O0N/UwDEsHyqkW+Qh28jW+mVuCdx7gLB0BotYI1Y6uI9iyew==", + "version": "2.7.1", + "resolved": "https://registry.npmjs.org/prettier/-/prettier-2.7.1.tgz", + "integrity": "sha512-ujppO+MkdPqoVINuDFDRLClm7D78qbDt0/NR+wp5FqEZOoTNAjPHWj17QRhu7geIHJfcNhRk1XVQmF8Bp3ye+g==", "dev": true, "bin": { "prettier": "bin-prettier.js" }, "engines": { - "node": ">=4" + "node": ">=10.13.0" + }, + "funding": { + "url": "https://github.com/prettier/prettier?sponsor=1" } }, "node_modules/pretty-bytes": { @@ -23629,9 +23632,9 @@ "dev": true }, "prettier": { - "version": "1.19.1", - "resolved": "https://registry.npmjs.org/prettier/-/prettier-1.19.1.tgz", - "integrity": "sha512-s7PoyDv/II1ObgQunCbB9PdLmUcBZcnWOcxDh7O0N/UwDEsHyqkW+Qh28jW+mVuCdx7gLB0BotYI1Y6uI9iyew==", + "version": "2.7.1", + "resolved": "https://registry.npmjs.org/prettier/-/prettier-2.7.1.tgz", + "integrity": "sha512-ujppO+MkdPqoVINuDFDRLClm7D78qbDt0/NR+wp5FqEZOoTNAjPHWj17QRhu7geIHJfcNhRk1XVQmF8Bp3ye+g==", "dev": true }, "pretty-bytes": { diff --git a/package.json b/package.json index 9505c2370..7351ee8da 100644 --- a/package.json +++ b/package.json @@ -62,7 +62,7 @@ "mock-stdin": "^0.3.0", "mustache": "^2.1.3", "nyc": "^14.1.1", - "prettier": "^1.19.1", + "prettier": "^2.7.1", "semver": "^5.0.1", "sinon": "^7.5.0", "typescript": "^3.4.3", diff --git a/prettier.config.js b/prettier.config.js index 6593a6b7d..70767b70e 100644 --- a/prettier.config.js +++ b/prettier.config.js @@ -1,5 +1,5 @@ module.exports = { tabWidth: 2, semi: true, - singleQuote: true + singleQuote: true, }; diff --git a/spec/.eslintrc.js b/spec/.eslintrc.js index 99d292fea..9eaea1c47 100644 --- a/spec/.eslintrc.js +++ b/spec/.eslintrc.js @@ -22,16 +22,16 @@ module.exports = { strictEqual: true, define: true, expect: true, - chai: true + chai: true, }, env: { - mocha: true + mocha: true, }, rules: { // Disabling for tests, for now. 'no-path-concat': 'off', 'no-var': 'off', - 'dot-notation': 'off' - } + 'dot-notation': 'off', + }, }; diff --git a/spec/ast.js b/spec/ast.js index d31752048..beb38a464 100644 --- a/spec/ast.js +++ b/spec/ast.js @@ -1,14 +1,14 @@ -describe('ast', function() { +describe('ast', function () { if (!Handlebars.AST) { return; } var AST = Handlebars.AST; - describe('BlockStatement', function() { - it('should throw on mustache mismatch', function() { + describe('BlockStatement', function () { + it('should throw on mustache mismatch', function () { shouldThrow( - function() { + function () { handlebarsEnv.parse('\n {{#foo}}{{/bar}}'); }, Handlebars.Exception, @@ -17,14 +17,14 @@ describe('ast', function() { }); }); - describe('helpers', function() { - describe('#helperExpression', function() { - it('should handle mustache statements', function() { + describe('helpers', function () { + describe('#helperExpression', function () { + it('should handle mustache statements', function () { equals( AST.helpers.helperExpression({ type: 'MustacheStatement', params: [], - hash: undefined + hash: undefined, }), false ); @@ -32,7 +32,7 @@ describe('ast', function() { AST.helpers.helperExpression({ type: 'MustacheStatement', params: [1], - hash: undefined + hash: undefined, }), true ); @@ -40,17 +40,17 @@ describe('ast', function() { AST.helpers.helperExpression({ type: 'MustacheStatement', params: [], - hash: {} + hash: {}, }), true ); }); - it('should handle block statements', function() { + it('should handle block statements', function () { equals( AST.helpers.helperExpression({ type: 'BlockStatement', params: [], - hash: undefined + hash: undefined, }), false ); @@ -58,7 +58,7 @@ describe('ast', function() { AST.helpers.helperExpression({ type: 'BlockStatement', params: [1], - hash: undefined + hash: undefined, }), true ); @@ -66,15 +66,15 @@ describe('ast', function() { AST.helpers.helperExpression({ type: 'BlockStatement', params: [], - hash: {} + hash: {}, }), true ); }); - it('should handle subexpressions', function() { + it('should handle subexpressions', function () { equals(AST.helpers.helperExpression({ type: 'SubExpression' }), true); }); - it('should work with non-helper nodes', function() { + it('should work with non-helper nodes', function () { equals(AST.helpers.helperExpression({ type: 'Program' }), false); equals( @@ -107,7 +107,7 @@ describe('ast', function() { }); }); - describe('Line Numbers', function() { + describe('Line Numbers', function () { var ast, body; function testColumns(node, firstLine, lastLine, firstColumn, lastColumn) { @@ -120,59 +120,59 @@ describe('ast', function() { /* eslint-disable no-multi-spaces */ ast = Handlebars.parse( 'line 1 {{line1Token}}\n' + // 1 - ' line 2 {{line2token}}\n' + // 2 - ' line 3 {{#blockHelperOnLine3}}\n' + // 3 - 'line 4{{line4token}}\n' + // 4 - 'line5{{else}}\n' + // 5 - '{{line6Token}}\n' + // 6 - '{{/blockHelperOnLine3}}\n' + // 7 - '{{#open}}\n' + // 8 - '{{else inverse}}\n' + // 9 - '{{else}}\n' + // 10 + ' line 2 {{line2token}}\n' + // 2 + ' line 3 {{#blockHelperOnLine3}}\n' + // 3 + 'line 4{{line4token}}\n' + // 4 + 'line5{{else}}\n' + // 5 + '{{line6Token}}\n' + // 6 + '{{/blockHelperOnLine3}}\n' + // 7 + '{{#open}}\n' + // 8 + '{{else inverse}}\n' + // 9 + '{{else}}\n' + // 10 '{{/open}}' ); // 11 /* eslint-enable no-multi-spaces */ body = ast.body; - it('gets ContentNode line numbers', function() { + it('gets ContentNode line numbers', function () { var contentNode = body[0]; testColumns(contentNode, 1, 1, 0, 7); }); - it('gets MustacheStatement line numbers', function() { + it('gets MustacheStatement line numbers', function () { var mustacheNode = body[1]; testColumns(mustacheNode, 1, 1, 7, 21); }); - it('gets line numbers correct when newlines appear', function() { + it('gets line numbers correct when newlines appear', function () { testColumns(body[2], 1, 2, 21, 8); }); - it('gets MustacheStatement line numbers correct across newlines', function() { + it('gets MustacheStatement line numbers correct across newlines', function () { var secondMustacheStatement = body[3]; testColumns(secondMustacheStatement, 2, 2, 8, 22); }); - it('gets the block helper information correct', function() { + it('gets the block helper information correct', function () { var blockHelperNode = body[5]; testColumns(blockHelperNode, 3, 7, 8, 23); }); - it('correctly records the line numbers the program of a block helper', function() { + it('correctly records the line numbers the program of a block helper', function () { var blockHelperNode = body[5], program = blockHelperNode.program; testColumns(program, 3, 5, 31, 5); }); - it('correctly records the line numbers of an inverse of a block helper', function() { + it('correctly records the line numbers of an inverse of a block helper', function () { var blockHelperNode = body[5], inverse = blockHelperNode.inverse; testColumns(inverse, 5, 7, 13, 0); }); - it('correctly records the line number of chained inverses', function() { + it('correctly records the line number of chained inverses', function () { var chainInverseNode = body[7]; testColumns(chainInverseNode.program, 8, 9, 9, 0); diff --git a/spec/basic.js b/spec/basic.js index 4c7afb706..b7f4f637f 100644 --- a/spec/basic.js +++ b/spec/basic.js @@ -1,17 +1,15 @@ global.handlebarsEnv = null; -beforeEach(function() { +beforeEach(function () { global.handlebarsEnv = Handlebars.create(); }); -describe('basic context', function() { - it('most basic', function() { - expectTemplate('{{foo}}') - .withInput({ foo: 'foo' }) - .toCompileTo('foo'); +describe('basic context', function () { + it('most basic', function () { + expectTemplate('{{foo}}').withInput({ foo: 'foo' }).toCompileTo('foo'); }); - it('escaping', function() { + it('escaping', function () { expectTemplate('\\{{foo}}') .withInput({ foo: 'food' }) .toCompileTo('{{foo}}'); @@ -33,23 +31,21 @@ describe('basic context', function() { .toCompileTo('\\\\ food'); }); - it('compiling with a basic context', function() { + it('compiling with a basic context', function () { expectTemplate('Goodbye\n{{cruel}}\n{{world}}!') .withInput({ cruel: 'cruel', - world: 'world' + world: 'world', }) .withMessage('It works if all the required keys are provided') .toCompileTo('Goodbye\ncruel\nworld!'); }); - it('compiling with a string context', function() { - expectTemplate('{{.}}{{length}}') - .withInput('bye') - .toCompileTo('bye3'); + it('compiling with a string context', function () { + expectTemplate('{{.}}{{length}}').withInput('bye').toCompileTo('bye3'); }); - it('compiling with an undefined context', function() { + it('compiling with an undefined context', function () { expectTemplate('Goodbye\n{{cruel}}\n{{world.bar}}!') .withInput(undefined) .toCompileTo('Goodbye\n\n!'); @@ -59,11 +55,11 @@ describe('basic context', function() { .toCompileTo('Goodbye'); }); - it('comments', function() { + it('comments', function () { expectTemplate('{{! Goodbye}}Goodbye\n{{cruel}}\n{{world}}!') .withInput({ cruel: 'cruel', - world: 'world' + world: 'world', }) .withMessage('comments are ignored') .toCompileTo('Goodbye\ncruel\nworld!'); @@ -87,12 +83,12 @@ describe('basic context', function() { ); }); - it('boolean', function() { + it('boolean', function () { var string = '{{#goodbye}}GOODBYE {{/goodbye}}cruel {{world}}!'; expectTemplate(string) .withInput({ goodbye: true, - world: 'world' + world: 'world', }) .withMessage('booleans show the contents when true') .toCompileTo('GOODBYE cruel world!'); @@ -100,41 +96,37 @@ describe('basic context', function() { expectTemplate(string) .withInput({ goodbye: false, - world: 'world' + world: 'world', }) .withMessage('booleans do not show the contents when false') .toCompileTo('cruel world!'); }); - it('zeros', function() { + it('zeros', function () { expectTemplate('num1: {{num1}}, num2: {{num2}}') .withInput({ num1: 42, - num2: 0 + num2: 0, }) .toCompileTo('num1: 42, num2: 0'); - expectTemplate('num: {{.}}') - .withInput(0) - .toCompileTo('num: 0'); + expectTemplate('num: {{.}}').withInput(0).toCompileTo('num: 0'); expectTemplate('num: {{num1/num2}}') .withInput({ num1: { num2: 0 } }) .toCompileTo('num: 0'); }); - it('false', function() { + it('false', function () { /* eslint-disable no-new-wrappers */ expectTemplate('val1: {{val1}}, val2: {{val2}}') .withInput({ val1: false, - val2: new Boolean(false) + val2: new Boolean(false), }) .toCompileTo('val1: false, val2: false'); - expectTemplate('val: {{.}}') - .withInput(false) - .toCompileTo('val: false'); + expectTemplate('val: {{.}}').withInput(false).toCompileTo('val: false'); expectTemplate('val: {{val1/val2}}') .withInput({ val1: { val2: false } }) @@ -143,7 +135,7 @@ describe('basic context', function() { expectTemplate('val1: {{{val1}}}, val2: {{{val2}}}') .withInput({ val1: false, - val2: new Boolean(false) + val2: new Boolean(false), }) .toCompileTo('val1: false, val2: false'); @@ -153,10 +145,10 @@ describe('basic context', function() { /* eslint-enable */ }); - it('should handle undefined and null', function() { + it('should handle undefined and null', function () { expectTemplate('{{awesome undefined null}}') .withInput({ - awesome: function(_undefined, _null, options) { + awesome: function (_undefined, _null, options) { return ( (_undefined === undefined) + ' ' + @@ -164,34 +156,34 @@ describe('basic context', function() { ' ' + typeof options ); - } + }, }) .toCompileTo('true true object'); expectTemplate('{{undefined}}') .withInput({ - undefined: function() { + undefined: function () { return 'undefined!'; - } + }, }) .toCompileTo('undefined!'); expectTemplate('{{null}}') .withInput({ - null: function() { + null: function () { return 'null!'; - } + }, }) .toCompileTo('null!'); }); - it('newlines', function() { + it('newlines', function () { expectTemplate("Alan's\nTest").toCompileTo("Alan's\nTest"); expectTemplate("Alan's\rTest").toCompileTo("Alan's\rTest"); }); - it('escaping text', function() { + it('escaping text', function () { expectTemplate("Awesome's") .withMessage( "text is escaped so that it doesn't get caught on single quotes" @@ -216,7 +208,7 @@ describe('basic context', function() { .toCompileTo(" ' ' "); }); - it('escaping expressions', function() { + it('escaping expressions', function () { expectTemplate('{{{awesome}}}') .withInput({ awesome: "&'\\<>" }) .withMessage("expressions with 3 handlebars aren't escaped") @@ -238,140 +230,140 @@ describe('basic context', function() { .toCompileTo('Escaped, <b> looks like: &lt;b&gt;'); }); - it("functions returning safestrings shouldn't be escaped", function() { + it("functions returning safestrings shouldn't be escaped", function () { expectTemplate('{{awesome}}') .withInput({ - awesome: function() { + awesome: function () { return new Handlebars.SafeString("&'\\<>"); - } + }, }) .withMessage("functions returning safestrings aren't escaped") .toCompileTo("&'\\<>"); }); - it('functions', function() { + it('functions', function () { expectTemplate('{{awesome}}') .withInput({ - awesome: function() { + awesome: function () { return 'Awesome'; - } + }, }) .withMessage('functions are called and render their output') .toCompileTo('Awesome'); expectTemplate('{{awesome}}') .withInput({ - awesome: function() { + awesome: function () { return this.more; }, - more: 'More awesome' + more: 'More awesome', }) .withMessage('functions are bound to the context') .toCompileTo('More awesome'); }); - it('functions with context argument', function() { + it('functions with context argument', function () { expectTemplate('{{awesome frank}}') .withInput({ - awesome: function(context) { + awesome: function (context) { return context; }, - frank: 'Frank' + frank: 'Frank', }) .withMessage('functions are called with context arguments') .toCompileTo('Frank'); }); - it('pathed functions with context argument', function() { + it('pathed functions with context argument', function () { expectTemplate('{{bar.awesome frank}}') .withInput({ bar: { - awesome: function(context) { + awesome: function (context) { return context; - } + }, }, - frank: 'Frank' + frank: 'Frank', }) .withMessage('functions are called with context arguments') .toCompileTo('Frank'); }); - it('depthed functions with context argument', function() { + it('depthed functions with context argument', function () { expectTemplate('{{#with frank}}{{../awesome .}}{{/with}}') .withInput({ - awesome: function(context) { + awesome: function (context) { return context; }, - frank: 'Frank' + frank: 'Frank', }) .withMessage('functions are called with context arguments') .toCompileTo('Frank'); }); - it('block functions with context argument', function() { + it('block functions with context argument', function () { expectTemplate('{{#awesome 1}}inner {{.}}{{/awesome}}') .withInput({ - awesome: function(context, options) { + awesome: function (context, options) { return options.fn(context); - } + }, }) .withMessage('block functions are called with context and options') .toCompileTo('inner 1'); }); - it('depthed block functions with context argument', function() { + it('depthed block functions with context argument', function () { expectTemplate( '{{#with value}}{{#../awesome 1}}inner {{.}}{{/../awesome}}{{/with}}' ) .withInput({ value: true, - awesome: function(context, options) { + awesome: function (context, options) { return options.fn(context); - } + }, }) .withMessage('block functions are called with context and options') .toCompileTo('inner 1'); }); - it('block functions without context argument', function() { + it('block functions without context argument', function () { expectTemplate('{{#awesome}}inner{{/awesome}}') .withInput({ - awesome: function(options) { + awesome: function (options) { return options.fn(this); - } + }, }) .withMessage('block functions are called with options') .toCompileTo('inner'); }); - it('pathed block functions without context argument', function() { + it('pathed block functions without context argument', function () { expectTemplate('{{#foo.awesome}}inner{{/foo.awesome}}') .withInput({ foo: { - awesome: function() { + awesome: function () { return this; - } - } + }, + }, }) .withMessage('block functions are called with options') .toCompileTo('inner'); }); - it('depthed block functions without context argument', function() { + it('depthed block functions without context argument', function () { expectTemplate( '{{#with value}}{{#../awesome}}inner{{/../awesome}}{{/with}}' ) .withInput({ value: true, - awesome: function() { + awesome: function () { return this; - } + }, }) .withMessage('block functions are called with options') .toCompileTo('inner'); }); - it('paths with hyphens', function() { + it('paths with hyphens', function () { expectTemplate('{{foo-bar}}') .withInput({ 'foo-bar': 'baz' }) .withMessage('Paths can contain hyphens (-)') @@ -388,21 +380,21 @@ describe('basic context', function() { .toCompileTo('baz'); }); - it('nested paths', function() { + it('nested paths', function () { expectTemplate('Goodbye {{alan/expression}} world!') .withInput({ alan: { expression: 'beautiful' } }) .withMessage('Nested paths access nested objects') .toCompileTo('Goodbye beautiful world!'); }); - it('nested paths with empty string value', function() { + it('nested paths with empty string value', function () { expectTemplate('Goodbye {{alan/expression}} world!') .withInput({ alan: { expression: '' } }) .withMessage('Nested paths access nested objects with empty string') .toCompileTo('Goodbye world!'); }); - it('literal paths', function() { + it('literal paths', function () { expectTemplate('Goodbye {{[@alan]/expression}} world!') .withInput({ '@alan': { expression: 'beautiful' } }) .withMessage('Literal paths can be used') @@ -414,7 +406,7 @@ describe('basic context', function() { .toCompileTo('Goodbye beautiful world!'); }); - it('literal references', function() { + it('literal references', function () { expectTemplate('Goodbye {{[foo bar]}} world!') .withInput({ 'foo bar': 'beautiful' }) .toCompileTo('Goodbye beautiful world!'); @@ -440,24 +432,22 @@ describe('basic context', function() { .toCompileTo('Goodbye beautiful world!'); }); - it("that current context path ({{.}}) doesn't hit helpers", function() { + it("that current context path ({{.}}) doesn't hit helpers", function () { expectTemplate('test: {{.}}') .withInput(null) .withHelpers({ helper: 'awesome' }) .toCompileTo('test: '); }); - it('complex but empty paths', function() { + it('complex but empty paths', function () { expectTemplate('{{person/name}}') .withInput({ person: { name: null } }) .toCompileTo(''); - expectTemplate('{{person/name}}') - .withInput({ person: {} }) - .toCompileTo(''); + expectTemplate('{{person/name}}').withInput({ person: {} }).toCompileTo(''); }); - it('this keyword in paths', function() { + it('this keyword in paths', function () { expectTemplate('{{#goodbyes}}{{this}}{{/goodbyes}}') .withInput({ goodbyes: ['goodbye', 'Goodbye', 'GOODBYE'] }) .withMessage('This keyword in paths evaluates to current context') @@ -465,32 +455,30 @@ describe('basic context', function() { expectTemplate('{{#hellos}}{{this/text}}{{/hellos}}') .withInput({ - hellos: [{ text: 'hello' }, { text: 'Hello' }, { text: 'HELLO' }] + hellos: [{ text: 'hello' }, { text: 'Hello' }, { text: 'HELLO' }], }) .withMessage('This keyword evaluates in more complex paths') .toCompileTo('helloHelloHELLO'); }); - it('this keyword nested inside path', function() { + it('this keyword nested inside path', function () { expectTemplate('{{#hellos}}{{text/this/foo}}{{/hellos}}').toThrow( Error, 'Invalid path: text/this - 1:13' ); - expectTemplate('{{[this]}}') - .withInput({ this: 'bar' }) - .toCompileTo('bar'); + expectTemplate('{{[this]}}').withInput({ this: 'bar' }).toCompileTo('bar'); expectTemplate('{{text/[this]}}') .withInput({ text: { this: 'bar' } }) .toCompileTo('bar'); }); - it('this keyword in helpers', function() { + it('this keyword in helpers', function () { var helpers = { - foo: function(value) { + foo: function (value) { return 'bar ' + value; - } + }, }; expectTemplate('{{#goodbyes}}{{foo this}}{{/goodbyes}}') @@ -501,14 +489,14 @@ describe('basic context', function() { expectTemplate('{{#hellos}}{{foo this/text}}{{/hellos}}') .withInput({ - hellos: [{ text: 'hello' }, { text: 'Hello' }, { text: 'HELLO' }] + hellos: [{ text: 'hello' }, { text: 'Hello' }, { text: 'HELLO' }], }) .withHelpers(helpers) .withMessage('This keyword evaluates in more complex paths') .toCompileTo('bar hellobar Hellobar HELLO'); }); - it('this keyword nested inside helpers param', function() { + it('this keyword nested inside helpers param', function () { expectTemplate('{{#hellos}}{{foo text/this/foo}}{{/hellos}}').toThrow( Error, 'Invalid path: text/this - 1:17' @@ -516,79 +504,69 @@ describe('basic context', function() { expectTemplate('{{foo [this]}}') .withInput({ - foo: function(value) { + foo: function (value) { return value; }, - this: 'bar' + this: 'bar', }) .toCompileTo('bar'); expectTemplate('{{foo text/[this]}}') .withInput({ - foo: function(value) { + foo: function (value) { return value; }, - text: { this: 'bar' } + text: { this: 'bar' }, }) .toCompileTo('bar'); }); - it('pass string literals', function() { + it('pass string literals', function () { expectTemplate('{{"foo"}}').toCompileTo(''); - expectTemplate('{{"foo"}}') - .withInput({ foo: 'bar' }) - .toCompileTo('bar'); + expectTemplate('{{"foo"}}').withInput({ foo: 'bar' }).toCompileTo('bar'); expectTemplate('{{#"foo"}}{{.}}{{/"foo"}}') .withInput({ - foo: ['bar', 'baz'] + foo: ['bar', 'baz'], }) .toCompileTo('barbaz'); }); - it('pass number literals', function() { + it('pass number literals', function () { expectTemplate('{{12}}').toCompileTo(''); - expectTemplate('{{12}}') - .withInput({ '12': 'bar' }) - .toCompileTo('bar'); + expectTemplate('{{12}}').withInput({ 12: 'bar' }).toCompileTo('bar'); expectTemplate('{{12.34}}').toCompileTo(''); - expectTemplate('{{12.34}}') - .withInput({ '12.34': 'bar' }) - .toCompileTo('bar'); + expectTemplate('{{12.34}}').withInput({ 12.34: 'bar' }).toCompileTo('bar'); expectTemplate('{{12.34 1}}') .withInput({ - '12.34': function(arg) { + 12.34: function (arg) { return 'bar' + arg; - } + }, }) .toCompileTo('bar1'); }); - it('pass boolean literals', function() { + it('pass boolean literals', function () { expectTemplate('{{true}}').toCompileTo(''); - expectTemplate('{{true}}') - .withInput({ '': 'foo' }) - .toCompileTo(''); + expectTemplate('{{true}}').withInput({ '': 'foo' }).toCompileTo(''); - expectTemplate('{{false}}') - .withInput({ false: 'foo' }) - .toCompileTo('foo'); + expectTemplate('{{false}}').withInput({ false: 'foo' }).toCompileTo('foo'); }); - it('should handle literals in subexpression', function() { + it('should handle literals in subexpression', function () { expectTemplate('{{foo (false)}}') .withInput({ - false: function() { + false: function () { return 'bar'; - } + }, }) - .withHelper('foo', function(arg) { + .withHelper('foo', function (arg) { return arg; }) .toCompileTo('bar'); diff --git a/spec/blocks.js b/spec/blocks.js index f15655428..550e64c23 100644 --- a/spec/blocks.js +++ b/spec/blocks.js @@ -1,5 +1,5 @@ -describe('blocks', function() { - it('array', function() { +describe('blocks', function () { + it('array', function () { var string = '{{#goodbyes}}{{text}}! {{/goodbyes}}cruel {{world}}!'; expectTemplate(string) @@ -7,9 +7,9 @@ describe('blocks', function() { goodbyes: [ { text: 'goodbye' }, { text: 'Goodbye' }, - { text: 'GOODBYE' } + { text: 'GOODBYE' }, ], - world: 'world' + world: 'world', }) .withMessage('Arrays iterate over the contents when not empty') .toCompileTo('goodbye! Goodbye! GOODBYE! cruel world!'); @@ -17,13 +17,13 @@ describe('blocks', function() { expectTemplate(string) .withInput({ goodbyes: [], - world: 'world' + world: 'world', }) .withMessage('Arrays ignore the contents when empty') .toCompileTo('cruel world!'); }); - it('array without data', function() { + it('array without data', function () { expectTemplate( '{{#goodbyes}}{{text}}{{/goodbyes}} {{#goodbyes}}{{text}}{{/goodbyes}}' ) @@ -31,15 +31,15 @@ describe('blocks', function() { goodbyes: [ { text: 'goodbye' }, { text: 'Goodbye' }, - { text: 'GOODBYE' } + { text: 'GOODBYE' }, ], - world: 'world' + world: 'world', }) .withCompileOptions({ compat: false }) .toCompileTo('goodbyeGoodbyeGOODBYE goodbyeGoodbyeGOODBYE'); }); - it('array with @index', function() { + it('array with @index', function () { expectTemplate( '{{#goodbyes}}{{@index}}. {{text}}! {{/goodbyes}}cruel {{world}}!' ) @@ -47,15 +47,15 @@ describe('blocks', function() { goodbyes: [ { text: 'goodbye' }, { text: 'Goodbye' }, - { text: 'GOODBYE' } + { text: 'GOODBYE' }, ], - world: 'world' + world: 'world', }) .withMessage('The @index variable is used') .toCompileTo('0. goodbye! 1. Goodbye! 2. GOODBYE! cruel world!'); }); - it('empty block', function() { + it('empty block', function () { var string = '{{#goodbyes}}{{/goodbyes}}cruel {{world}}!'; expectTemplate(string) @@ -63,9 +63,9 @@ describe('blocks', function() { goodbyes: [ { text: 'goodbye' }, { text: 'Goodbye' }, - { text: 'GOODBYE' } + { text: 'GOODBYE' }, ], - world: 'world' + world: 'world', }) .withMessage('Arrays iterate over the contents when not empty') .toCompileTo('cruel world!'); @@ -73,21 +73,21 @@ describe('blocks', function() { expectTemplate(string) .withInput({ goodbyes: [], - world: 'world' + world: 'world', }) .withMessage('Arrays ignore the contents when empty') .toCompileTo('cruel world!'); }); - it('block with complex lookup', function() { + it('block with complex lookup', function () { expectTemplate('{{#goodbyes}}{{text}} cruel {{../name}}! {{/goodbyes}}') .withInput({ name: 'Alan', goodbyes: [ { text: 'goodbye' }, { text: 'Goodbye' }, - { text: 'GOODBYE' } - ] + { text: 'GOODBYE' }, + ], }) .withMessage( 'Templates can access variables in contexts up the stack with relative path syntax' @@ -97,37 +97,37 @@ describe('blocks', function() { ); }); - it('multiple blocks with complex lookup', function() { + it('multiple blocks with complex lookup', function () { expectTemplate('{{#goodbyes}}{{../name}}{{../name}}{{/goodbyes}}') .withInput({ name: 'Alan', goodbyes: [ { text: 'goodbye' }, { text: 'Goodbye' }, - { text: 'GOODBYE' } - ] + { text: 'GOODBYE' }, + ], }) .toCompileTo('AlanAlanAlanAlanAlanAlan'); }); - it('block with complex lookup using nested context', function() { + it('block with complex lookup using nested context', function () { expectTemplate( '{{#goodbyes}}{{text}} cruel {{foo/../name}}! {{/goodbyes}}' ).toThrow(Error); }); - it('block with deep nested complex lookup', function() { + it('block with deep nested complex lookup', function () { expectTemplate( '{{#outer}}Goodbye {{#inner}}cruel {{../sibling}} {{../../omg}}{{/inner}}{{/outer}}' ) .withInput({ omg: 'OMG!', - outer: [{ sibling: 'sad', inner: [{ text: 'goodbye' }] }] + outer: [{ sibling: 'sad', inner: [{ text: 'goodbye' }] }], }) .toCompileTo('Goodbye cruel sad OMG!'); }); - it('works with cached blocks', function() { + it('works with cached blocks', function () { expectTemplate( '{{#each person}}{{#with .}}{{first}} {{last}}{{/with}}{{/each}}' ) @@ -135,14 +135,14 @@ describe('blocks', function() { .withInput({ person: [ { first: 'Alan', last: 'Johnson' }, - { first: 'Alan', last: 'Johnson' } - ] + { first: 'Alan', last: 'Johnson' }, + ], }) .toCompileTo('Alan JohnsonAlan Johnson'); }); - describe('inverted sections', function() { - it('inverted sections with unset value', function() { + describe('inverted sections', function () { + it('inverted sections with unset value', function () { expectTemplate( '{{#goodbyes}}{{this}}{{/goodbyes}}{{^goodbyes}}Right On!{{/goodbyes}}' ) @@ -150,7 +150,7 @@ describe('blocks', function() { .toCompileTo('Right On!'); }); - it('inverted section with false value', function() { + it('inverted section with false value', function () { expectTemplate( '{{#goodbyes}}{{this}}{{/goodbyes}}{{^goodbyes}}Right On!{{/goodbyes}}' ) @@ -159,7 +159,7 @@ describe('blocks', function() { .toCompileTo('Right On!'); }); - it('inverted section with empty set', function() { + it('inverted section with empty set', function () { expectTemplate( '{{#goodbyes}}{{this}}{{/goodbyes}}{{^goodbyes}}Right On!{{/goodbyes}}' ) @@ -168,13 +168,13 @@ describe('blocks', function() { .toCompileTo('Right On!'); }); - it('block inverted sections', function() { + it('block inverted sections', function () { expectTemplate('{{#people}}{{name}}{{^}}{{none}}{{/people}}') .withInput({ none: 'No people' }) .toCompileTo('No people'); }); - it('chained inverted sections', function() { + it('chained inverted sections', function () { expectTemplate('{{#people}}{{name}}{{else if none}}{{none}}{{/people}}') .withInput({ none: 'No people' }) .toCompileTo('No people'); @@ -192,24 +192,24 @@ describe('blocks', function() { .toCompileTo('No people'); }); - it('chained inverted sections with mismatch', function() { + it('chained inverted sections with mismatch', function () { expectTemplate( '{{#people}}{{name}}{{else if none}}{{none}}{{/if}}' ).toThrow(Error); }); - it('block inverted sections with empty arrays', function() { + it('block inverted sections with empty arrays', function () { expectTemplate('{{#people}}{{name}}{{^}}{{none}}{{/people}}') .withInput({ none: 'No people', - people: [] + people: [], }) .toCompileTo('No people'); }); }); - describe('standalone sections', function() { - it('block standalone else sections', function() { + describe('standalone sections', function () { + it('block standalone else sections', function () { expectTemplate('{{#people}}\n{{name}}\n{{^}}\n{{none}}\n{{/people}}\n') .withInput({ none: 'No people' }) .toCompileTo('No people\n'); @@ -223,7 +223,7 @@ describe('blocks', function() { .toCompileTo('No people\n'); }); - it('block standalone else sections can be disabled', function() { + it('block standalone else sections can be disabled', function () { expectTemplate('{{#people}}\n{{name}}\n{{^}}\n{{none}}\n{{/people}}\n') .withInput({ none: 'No people' }) .withCompileOptions({ ignoreStandalone: true }) @@ -235,7 +235,7 @@ describe('blocks', function() { .toCompileTo('\nNo people\n\n'); }); - it('block standalone chained else sections', function() { + it('block standalone chained else sections', function () { expectTemplate( '{{#people}}\n{{name}}\n{{else if none}}\n{{none}}\n{{/people}}\n' ) @@ -249,17 +249,17 @@ describe('blocks', function() { .toCompileTo('No people\n'); }); - it('should handle nesting', function() { + it('should handle nesting', function () { expectTemplate('{{#data}}\n{{#if true}}\n{{.}}\n{{/if}}\n{{/data}}\nOK.') .withInput({ - data: [1, 3, 5] + data: [1, 3, 5], }) .toCompileTo('1\n3\n5\nOK.'); }); }); - describe('compat mode', function() { - it('block with deep recursive lookup lookup', function() { + describe('compat mode', function () { + it('block with deep recursive lookup lookup', function () { expectTemplate( '{{#outer}}Goodbye {{#inner}}cruel {{omg}}{{/inner}}{{/outer}}' ) @@ -268,108 +268,108 @@ describe('blocks', function() { .toCompileTo('Goodbye cruel OMG!'); }); - it('block with deep recursive pathed lookup', function() { + it('block with deep recursive pathed lookup', function () { expectTemplate( '{{#outer}}Goodbye {{#inner}}cruel {{omg.yes}}{{/inner}}{{/outer}}' ) .withInput({ omg: { yes: 'OMG!' }, - outer: [{ inner: [{ yes: 'no', text: 'goodbye' }] }] + outer: [{ inner: [{ yes: 'no', text: 'goodbye' }] }], }) .withCompileOptions({ compat: true }) .toCompileTo('Goodbye cruel OMG!'); }); - it('block with missed recursive lookup', function() { + it('block with missed recursive lookup', function () { expectTemplate( '{{#outer}}Goodbye {{#inner}}cruel {{omg.yes}}{{/inner}}{{/outer}}' ) .withInput({ omg: { no: 'OMG!' }, - outer: [{ inner: [{ yes: 'no', text: 'goodbye' }] }] + outer: [{ inner: [{ yes: 'no', text: 'goodbye' }] }], }) .withCompileOptions({ compat: true }) .toCompileTo('Goodbye cruel '); }); }); - describe('decorators', function() { - it('should apply mustache decorators', function() { + describe('decorators', function () { + it('should apply mustache decorators', function () { expectTemplate('{{#helper}}{{*decorator}}{{/helper}}') - .withHelper('helper', function(options) { + .withHelper('helper', function (options) { return options.fn.run; }) - .withDecorator('decorator', function(fn) { + .withDecorator('decorator', function (fn) { fn.run = 'success'; return fn; }) .toCompileTo('success'); }); - it('should apply allow undefined return', function() { + it('should apply allow undefined return', function () { expectTemplate('{{#helper}}{{*decorator}}suc{{/helper}}') - .withHelper('helper', function(options) { + .withHelper('helper', function (options) { return options.fn() + options.fn.run; }) - .withDecorator('decorator', function(fn) { + .withDecorator('decorator', function (fn) { fn.run = 'cess'; }) .toCompileTo('success'); }); - it('should apply block decorators', function() { + it('should apply block decorators', function () { expectTemplate( '{{#helper}}{{#*decorator}}success{{/decorator}}{{/helper}}' ) - .withHelper('helper', function(options) { + .withHelper('helper', function (options) { return options.fn.run; }) - .withDecorator('decorator', function(fn, props, container, options) { + .withDecorator('decorator', function (fn, props, container, options) { fn.run = options.fn(); return fn; }) .toCompileTo('success'); }); - it('should support nested decorators', function() { + it('should support nested decorators', function () { expectTemplate( '{{#helper}}{{#*decorator}}{{#*nested}}suc{{/nested}}cess{{/decorator}}{{/helper}}' ) - .withHelper('helper', function(options) { + .withHelper('helper', function (options) { return options.fn.run; }) .withDecorators({ - decorator: function(fn, props, container, options) { + decorator: function (fn, props, container, options) { fn.run = options.fn.nested + options.fn(); return fn; }, - nested: function(fn, props, container, options) { + nested: function (fn, props, container, options) { props.nested = options.fn(); - } + }, }) .toCompileTo('success'); }); - it('should apply multiple decorators', function() { + it('should apply multiple decorators', function () { expectTemplate( '{{#helper}}{{#*decorator}}suc{{/decorator}}{{#*decorator}}cess{{/decorator}}{{/helper}}' ) - .withHelper('helper', function(options) { + .withHelper('helper', function (options) { return options.fn.run; }) - .withDecorator('decorator', function(fn, props, container, options) { + .withDecorator('decorator', function (fn, props, container, options) { fn.run = (fn.run || '') + options.fn(); return fn; }) .toCompileTo('success'); }); - it('should access parent variables', function() { + it('should access parent variables', function () { expectTemplate('{{#helper}}{{*decorator foo}}{{/helper}}') - .withHelper('helper', function(options) { + .withHelper('helper', function (options) { return options.fn.run; }) - .withDecorator('decorator', function(fn, props, container, options) { + .withDecorator('decorator', function (fn, props, container, options) { fn.run = options.args; return fn; }) @@ -377,10 +377,10 @@ describe('blocks', function() { .toCompileTo('success'); }); - it('should work with root program', function() { + it('should work with root program', function () { var run; expectTemplate('{{*decorator "success"}}') - .withDecorator('decorator', function(fn, props, container, options) { + .withDecorator('decorator', function (fn, props, container, options) { equals(options.args[0], 'success'); run = true; return fn; @@ -390,10 +390,10 @@ describe('blocks', function() { equals(run, true); }); - it('should fail when accessing variables from root', function() { + it('should fail when accessing variables from root', function () { var run; expectTemplate('{{*decorator foo}}') - .withDecorator('decorator', function(fn, props, container, options) { + .withDecorator('decorator', function (fn, props, container, options) { equals(options.args[0], undefined); run = true; return fn; @@ -403,11 +403,11 @@ describe('blocks', function() { equals(run, true); }); - describe('registration', function() { - it('unregisters', function() { + describe('registration', function () { + it('unregisters', function () { handlebarsEnv.decorators = {}; - handlebarsEnv.registerDecorator('foo', function() { + handlebarsEnv.registerDecorator('foo', function () { return 'fail'; }); @@ -416,12 +416,12 @@ describe('blocks', function() { equals(handlebarsEnv.decorators.foo, undefined); }); - it('allows multiple globals', function() { + it('allows multiple globals', function () { handlebarsEnv.decorators = {}; handlebarsEnv.registerDecorator({ - foo: function() {}, - bar: function() {} + foo: function () {}, + bar: function () {}, }); equals(!!handlebarsEnv.decorators.foo, true); @@ -432,17 +432,17 @@ describe('blocks', function() { equals(handlebarsEnv.decorators.bar, undefined); }); - it('fails with multiple and args', function() { + it('fails with multiple and args', function () { shouldThrow( - function() { + function () { handlebarsEnv.registerDecorator( { - world: function() { + world: function () { return 'world!'; }, - testHelper: function() { + testHelper: function () { return 'found it!'; - } + }, }, {} ); diff --git a/spec/builtins.js b/spec/builtins.js index 825de237c..4c1efe4eb 100644 --- a/spec/builtins.js +++ b/spec/builtins.js @@ -1,12 +1,12 @@ -describe('builtin helpers', function() { - describe('#if', function() { - it('if', function() { +describe('builtin helpers', function () { + describe('#if', function () { + it('if', function () { var string = '{{#if goodbye}}GOODBYE {{/if}}cruel {{world}}!'; expectTemplate(string) .withInput({ goodbye: true, - world: 'world' + world: 'world', }) .withMessage('if with boolean argument shows the contents when true') .toCompileTo('GOODBYE cruel world!'); @@ -14,7 +14,7 @@ describe('builtin helpers', function() { expectTemplate(string) .withInput({ goodbye: 'dummy', - world: 'world' + world: 'world', }) .withMessage('if with string argument shows the contents') .toCompileTo('GOODBYE cruel world!'); @@ -22,7 +22,7 @@ describe('builtin helpers', function() { expectTemplate(string) .withInput({ goodbye: false, - world: 'world' + world: 'world', }) .withMessage( 'if with boolean argument does not show the contents when false' @@ -37,7 +37,7 @@ describe('builtin helpers', function() { expectTemplate(string) .withInput({ goodbye: ['foo'], - world: 'world' + world: 'world', }) .withMessage('if with non-empty array shows the contents') .toCompileTo('GOODBYE cruel world!'); @@ -45,7 +45,7 @@ describe('builtin helpers', function() { expectTemplate(string) .withInput({ goodbye: [], - world: 'world' + world: 'world', }) .withMessage('if with empty array does not show the contents') .toCompileTo('cruel world!'); @@ -53,7 +53,7 @@ describe('builtin helpers', function() { expectTemplate(string) .withInput({ goodbye: 0, - world: 'world' + world: 'world', }) .withMessage('if with zero does not show the contents') .toCompileTo('cruel world!'); @@ -63,21 +63,21 @@ describe('builtin helpers', function() { ) .withInput({ goodbye: 0, - world: 'world' + world: 'world', }) .withMessage('if with zero does not show the contents') .toCompileTo('GOODBYE cruel world!'); }); - it('if with function argument', function() { + it('if with function argument', function () { var string = '{{#if goodbye}}GOODBYE {{/if}}cruel {{world}}!'; expectTemplate(string) .withInput({ - goodbye: function() { + goodbye: function () { return true; }, - world: 'world' + world: 'world', }) .withMessage( 'if with function shows the contents when function returns true' @@ -86,10 +86,10 @@ describe('builtin helpers', function() { expectTemplate(string) .withInput({ - goodbye: function() { + goodbye: function () { return this.world; }, - world: 'world' + world: 'world', }) .withMessage( 'if with function shows the contents when function returns string' @@ -98,10 +98,10 @@ describe('builtin helpers', function() { expectTemplate(string) .withInput({ - goodbye: function() { + goodbye: function () { return false; }, - world: 'world' + world: 'world', }) .withMessage( 'if with function does not show the contents when returns false' @@ -110,10 +110,10 @@ describe('builtin helpers', function() { expectTemplate(string) .withInput({ - goodbye: function() { + goodbye: function () { return this.foo; }, - world: 'world' + world: 'world', }) .withMessage( 'if with function does not show the contents when returns undefined' @@ -121,61 +121,61 @@ describe('builtin helpers', function() { .toCompileTo('cruel world!'); }); - it('should not change the depth list', function() { + it('should not change the depth list', function () { expectTemplate( '{{#with foo}}{{#if goodbye}}GOODBYE cruel {{../world}}!{{/if}}{{/with}}' ) .withInput({ foo: { goodbye: true }, - world: 'world' + world: 'world', }) .toCompileTo('GOODBYE cruel world!'); }); }); - describe('#with', function() { - it('with', function() { + describe('#with', function () { + it('with', function () { expectTemplate('{{#with person}}{{first}} {{last}}{{/with}}') .withInput({ person: { first: 'Alan', - last: 'Johnson' - } + last: 'Johnson', + }, }) .toCompileTo('Alan Johnson'); }); - it('with with function argument', function() { + it('with with function argument', function () { expectTemplate('{{#with person}}{{first}} {{last}}{{/with}}') .withInput({ - person: function() { + person: function () { return { first: 'Alan', - last: 'Johnson' + last: 'Johnson', }; - } + }, }) .toCompileTo('Alan Johnson'); }); - it('with with else', function() { + it('with with else', function () { expectTemplate( '{{#with person}}Person is present{{else}}Person is not present{{/with}}' ).toCompileTo('Person is not present'); }); - it('with provides block parameter', function() { + it('with provides block parameter', function () { expectTemplate('{{#with person as |foo|}}{{foo.first}} {{last}}{{/with}}') .withInput({ person: { first: 'Alan', - last: 'Johnson' - } + last: 'Johnson', + }, }) .toCompileTo('Alan Johnson'); }); - it('works when data is disabled', function() { + it('works when data is disabled', function () { expectTemplate('{{#with person as |foo|}}{{foo.first}} {{last}}{{/with}}') .withInput({ person: { first: 'Alan', last: 'Johnson' } }) .withCompileOptions({ data: false }) @@ -183,14 +183,14 @@ describe('builtin helpers', function() { }); }); - describe('#each', function() { - beforeEach(function() { - handlebarsEnv.registerHelper('detectDataInsideEach', function(options) { + describe('#each', function () { + beforeEach(function () { + handlebarsEnv.registerHelper('detectDataInsideEach', function (options) { return options.data && options.data.exclaim; }); }); - it('each', function() { + it('each', function () { var string = '{{#each goodbyes}}{{text}}! {{/each}}cruel {{world}}!'; expectTemplate(string) @@ -198,9 +198,9 @@ describe('builtin helpers', function() { goodbyes: [ { text: 'goodbye' }, { text: 'Goodbye' }, - { text: 'GOODBYE' } + { text: 'GOODBYE' }, ], - world: 'world' + world: 'world', }) .withMessage( 'each with array argument iterates over the contents when not empty' @@ -210,21 +210,21 @@ describe('builtin helpers', function() { expectTemplate(string) .withInput({ goodbyes: [], - world: 'world' + world: 'world', }) .withMessage('each with array argument ignores the contents when empty') .toCompileTo('cruel world!'); }); - it('each without data', function() { + it('each without data', function () { expectTemplate('{{#each goodbyes}}{{text}}! {{/each}}cruel {{world}}!') .withInput({ goodbyes: [ { text: 'goodbye' }, { text: 'Goodbye' }, - { text: 'GOODBYE' } + { text: 'GOODBYE' }, ], - world: 'world' + world: 'world', }) .withRuntimeOptions({ data: false }) .withCompileOptions({ data: false }) @@ -237,13 +237,13 @@ describe('builtin helpers', function() { .toCompileTo('cruelworld'); }); - it('each without context', function() { + it('each without context', function () { expectTemplate('{{#each goodbyes}}{{text}}! {{/each}}cruel {{world}}!') .withInput(undefined) .toCompileTo('cruel !'); }); - it('each with an object and @key', function() { + it('each with an object and @key', function () { var string = '{{#each goodbyes}}{{@key}}. {{text}}! {{/each}}cruel {{world}}!'; @@ -272,12 +272,12 @@ describe('builtin helpers', function() { expectTemplate(string) .withInput({ goodbyes: {}, - world: 'world' + world: 'world', }) .toCompileTo('cruel world!'); }); - it('each with @index', function() { + it('each with @index', function () { expectTemplate( '{{#each goodbyes}}{{@index}}. {{text}}! {{/each}}cruel {{world}}!' ) @@ -285,15 +285,15 @@ describe('builtin helpers', function() { goodbyes: [ { text: 'goodbye' }, { text: 'Goodbye' }, - { text: 'GOODBYE' } + { text: 'GOODBYE' }, ], - world: 'world' + world: 'world', }) .withMessage('The @index variable is used') .toCompileTo('0. goodbye! 1. Goodbye! 2. GOODBYE! cruel world!'); }); - it('each with nested @index', function() { + it('each with nested @index', function () { expectTemplate( '{{#each goodbyes}}{{@index}}. {{text}}! {{#each ../goodbyes}}{{@index}} {{/each}}After {{@index}} {{/each}}{{@index}}cruel {{world}}!' ) @@ -301,9 +301,9 @@ describe('builtin helpers', function() { goodbyes: [ { text: 'goodbye' }, { text: 'Goodbye' }, - { text: 'GOODBYE' } + { text: 'GOODBYE' }, ], - world: 'world' + world: 'world', }) .withMessage('The @index variable is used') .toCompileTo( @@ -311,20 +311,20 @@ describe('builtin helpers', function() { ); }); - it('each with block params', function() { + it('each with block params', function () { expectTemplate( '{{#each goodbyes as |value index|}}{{index}}. {{value.text}}! {{#each ../goodbyes as |childValue childIndex|}} {{index}} {{childIndex}}{{/each}} After {{index}} {{/each}}{{index}}cruel {{world}}!' ) .withInput({ goodbyes: [{ text: 'goodbye' }, { text: 'Goodbye' }], - world: 'world' + world: 'world', }) .toCompileTo( '0. goodbye! 0 0 0 1 After 0 1. Goodbye! 1 0 1 1 After 1 cruel world!' ); }); - it('each with block params and strict compilation', function() { + it('each with block params and strict compilation', function () { expectTemplate( '{{#each goodbyes as |value index|}}{{index}}. {{value.text}}!{{/each}}' ) @@ -333,7 +333,7 @@ describe('builtin helpers', function() { .toCompileTo('0. goodbye!1. Goodbye!'); }); - it('each object with @index', function() { + it('each object with @index', function () { expectTemplate( '{{#each goodbyes}}{{@index}}. {{text}}! {{/each}}cruel {{world}}!' ) @@ -341,15 +341,15 @@ describe('builtin helpers', function() { goodbyes: { a: { text: 'goodbye' }, b: { text: 'Goodbye' }, - c: { text: 'GOODBYE' } + c: { text: 'GOODBYE' }, }, - world: 'world' + world: 'world', }) .withMessage('The @index variable is used') .toCompileTo('0. goodbye! 1. Goodbye! 2. GOODBYE! cruel world!'); }); - it('each with @first', function() { + it('each with @first', function () { expectTemplate( '{{#each goodbyes}}{{#if @first}}{{text}}! {{/if}}{{/each}}cruel {{world}}!' ) @@ -357,15 +357,15 @@ describe('builtin helpers', function() { goodbyes: [ { text: 'goodbye' }, { text: 'Goodbye' }, - { text: 'GOODBYE' } + { text: 'GOODBYE' }, ], - world: 'world' + world: 'world', }) .withMessage('The @first variable is used') .toCompileTo('goodbye! cruel world!'); }); - it('each with nested @first', function() { + it('each with nested @first', function () { expectTemplate( '{{#each goodbyes}}({{#if @first}}{{text}}! {{/if}}{{#each ../goodbyes}}{{#if @first}}{{text}}!{{/if}}{{/each}}{{#if @first}} {{text}}!{{/if}}) {{/each}}cruel {{world}}!' ) @@ -373,9 +373,9 @@ describe('builtin helpers', function() { goodbyes: [ { text: 'goodbye' }, { text: 'Goodbye' }, - { text: 'GOODBYE' } + { text: 'GOODBYE' }, ], - world: 'world' + world: 'world', }) .withMessage('The @first variable is used') .toCompileTo( @@ -383,19 +383,19 @@ describe('builtin helpers', function() { ); }); - it('each object with @first', function() { + it('each object with @first', function () { expectTemplate( '{{#each goodbyes}}{{#if @first}}{{text}}! {{/if}}{{/each}}cruel {{world}}!' ) .withInput({ goodbyes: { foo: { text: 'goodbye' }, bar: { text: 'Goodbye' } }, - world: 'world' + world: 'world', }) .withMessage('The @first variable is used') .toCompileTo('goodbye! cruel world!'); }); - it('each with @last', function() { + it('each with @last', function () { expectTemplate( '{{#each goodbyes}}{{#if @last}}{{text}}! {{/if}}{{/each}}cruel {{world}}!' ) @@ -403,27 +403,27 @@ describe('builtin helpers', function() { goodbyes: [ { text: 'goodbye' }, { text: 'Goodbye' }, - { text: 'GOODBYE' } + { text: 'GOODBYE' }, ], - world: 'world' + world: 'world', }) .withMessage('The @last variable is used') .toCompileTo('GOODBYE! cruel world!'); }); - it('each object with @last', function() { + it('each object with @last', function () { expectTemplate( '{{#each goodbyes}}{{#if @last}}{{text}}! {{/if}}{{/each}}cruel {{world}}!' ) .withInput({ goodbyes: { foo: { text: 'goodbye' }, bar: { text: 'Goodbye' } }, - world: 'world' + world: 'world', }) .withMessage('The @last variable is used') .toCompileTo('Goodbye! cruel world!'); }); - it('each with nested @last', function() { + it('each with nested @last', function () { expectTemplate( '{{#each goodbyes}}({{#if @last}}{{text}}! {{/if}}{{#each ../goodbyes}}{{#if @last}}{{text}}!{{/if}}{{/each}}{{#if @last}} {{text}}!{{/if}}) {{/each}}cruel {{world}}!' ) @@ -431,9 +431,9 @@ describe('builtin helpers', function() { goodbyes: [ { text: 'goodbye' }, { text: 'Goodbye' }, - { text: 'GOODBYE' } + { text: 'GOODBYE' }, ], - world: 'world' + world: 'world', }) .withMessage('The @last variable is used') .toCompileTo( @@ -441,19 +441,19 @@ describe('builtin helpers', function() { ); }); - it('each with function argument', function() { + it('each with function argument', function () { var string = '{{#each goodbyes}}{{text}}! {{/each}}cruel {{world}}!'; expectTemplate(string) .withInput({ - goodbyes: function() { + goodbyes: function () { return [ { text: 'goodbye' }, { text: 'Goodbye' }, - { text: 'GOODBYE' } + { text: 'GOODBYE' }, ]; }, - world: 'world' + world: 'world', }) .withMessage( 'each with array function argument iterates over the contents when not empty' @@ -463,7 +463,7 @@ describe('builtin helpers', function() { expectTemplate(string) .withInput({ goodbyes: [], - world: 'world' + world: 'world', }) .withMessage( 'each with array function argument ignores the contents when empty' @@ -471,7 +471,7 @@ describe('builtin helpers', function() { .toCompileTo('cruel world!'); }); - it('each object when last key is an empty string', function() { + it('each object when last key is an empty string', function () { expectTemplate( '{{#each goodbyes}}{{@index}}. {{text}}! {{/each}}cruel {{world}}!' ) @@ -479,15 +479,15 @@ describe('builtin helpers', function() { goodbyes: { a: { text: 'goodbye' }, b: { text: 'Goodbye' }, - '': { text: 'GOODBYE' } + '': { text: 'GOODBYE' }, }, - world: 'world' + world: 'world', }) .withMessage('Empty string key is not skipped') .toCompileTo('0. goodbye! 1. Goodbye! 2. GOODBYE! cruel world!'); }); - it('data passed to helpers', function() { + it('data passed to helpers', function () { expectTemplate( '{{#each letters}}{{this}}{{detectDataInsideEach}}{{/each}}' ) @@ -495,13 +495,13 @@ describe('builtin helpers', function() { .withMessage('should output data') .withRuntimeOptions({ data: { - exclaim: '!' - } + exclaim: '!', + }, }) .toCompileTo('a!b!c!'); }); - it('each on implicit context', function() { + it('each on implicit context', function () { expectTemplate('{{#each}}{{text}}! {{/each}}cruel world!').toThrow( handlebarsEnv.Exception, 'Must pass iterator to #each' @@ -509,12 +509,12 @@ describe('builtin helpers', function() { }); if (global.Symbol && global.Symbol.iterator) { - it('each on iterable', function() { + it('each on iterable', function () { function Iterator(arr) { this.arr = arr; this.index = 0; } - Iterator.prototype.next = function() { + Iterator.prototype.next = function () { var value = this.arr[this.index]; var done = this.index === this.arr.length; if (!done) { @@ -525,7 +525,7 @@ describe('builtin helpers', function() { function Iterable(arr) { this.arr = arr; } - Iterable.prototype[global.Symbol.iterator] = function() { + Iterable.prototype[global.Symbol.iterator] = function () { return new Iterator(this.arr); }; var string = '{{#each goodbyes}}{{text}}! {{/each}}cruel {{world}}!'; @@ -535,9 +535,9 @@ describe('builtin helpers', function() { goodbyes: new Iterable([ { text: 'goodbye' }, { text: 'Goodbye' }, - { text: 'GOODBYE' } + { text: 'GOODBYE' }, ]), - world: 'world' + world: 'world', }) .withMessage( 'each with array argument iterates over the contents when not empty' @@ -547,7 +547,7 @@ describe('builtin helpers', function() { expectTemplate(string) .withInput({ goodbyes: new Iterable([]), - world: 'world' + world: 'world', }) .withMessage( 'each with array argument ignores the contents when empty' @@ -557,27 +557,27 @@ describe('builtin helpers', function() { } }); - describe('#log', function() { + describe('#log', function () { /* eslint-disable no-console */ if (typeof console === 'undefined') { return; } var $log, $info, $error; - beforeEach(function() { + beforeEach(function () { $log = console.log; $info = console.info; $error = console.error; }); - afterEach(function() { + afterEach(function () { console.log = $log; console.info = $info; console.error = $error; }); - it('should call logger at default level', function() { + it('should call logger at default level', function () { var levelArg, logArg; - handlebarsEnv.log = function(level, arg) { + handlebarsEnv.log = function (level, arg) { levelArg = level; logArg = arg; }; @@ -590,9 +590,9 @@ describe('builtin helpers', function() { equals('whee', logArg, "should call log with 'whee'"); }); - it('should call logger at data level', function() { + it('should call logger at data level', function () { var levelArg, logArg; - handlebarsEnv.log = function(level, arg) { + handlebarsEnv.log = function (level, arg) { levelArg = level; logArg = arg; }; @@ -606,16 +606,16 @@ describe('builtin helpers', function() { equals('whee', logArg); }); - it('should output to info', function() { + it('should output to info', function () { var called; - console.info = function(info) { + console.info = function (info) { equals('whee', info); called = true; console.info = $info; console.log = $log; }; - console.log = function(log) { + console.log = function (log) { equals('whee', log); called = true; console.info = $info; @@ -628,10 +628,10 @@ describe('builtin helpers', function() { equals(true, called); }); - it('should log at data level', function() { + it('should log at data level', function () { var called; - console.error = function(log) { + console.error = function (log) { equals('whee', log); called = true; console.error = $error; @@ -645,11 +645,11 @@ describe('builtin helpers', function() { equals(true, called); }); - it('should handle missing logger', function() { + it('should handle missing logger', function () { var called = false; console.error = undefined; - console.log = function(log) { + console.log = function (log) { equals('whee', log); called = true; console.log = $log; @@ -663,10 +663,10 @@ describe('builtin helpers', function() { equals(true, called); }); - it('should handle string log levels', function() { + it('should handle string log levels', function () { var called; - console.error = function(log) { + console.error = function (log) { equals('whee', log); called = true; }; @@ -688,10 +688,10 @@ describe('builtin helpers', function() { equals(true, called); }); - it('should handle hash log levels', function() { + it('should handle hash log levels', function () { var called; - console.error = function(log) { + console.error = function (log) { equals('whee', log); called = true; }; @@ -702,13 +702,17 @@ describe('builtin helpers', function() { equals(true, called); }); - it('should handle hash log levels', function() { + it('should handle hash log levels', function () { var called = false; - console.info = console.log = console.error = console.debug = function() { - called = true; - console.info = console.log = console.error = console.debug = $log; - }; + console.info = + console.log = + console.error = + console.debug = + function () { + called = true; + console.info = console.log = console.error = console.debug = $log; + }; expectTemplate('{{log blah level="debug"}}') .withInput({ blah: 'whee' }) @@ -716,10 +720,10 @@ describe('builtin helpers', function() { equals(false, called); }); - it('should pass multiple log arguments', function() { + it('should pass multiple log arguments', function () { var called; - console.info = console.log = function(log1, log2, log3) { + console.info = console.log = function (log1, log2, log3) { equals('whee', log1); equals('foo', log2); equals(1, log3); @@ -733,31 +737,29 @@ describe('builtin helpers', function() { equals(true, called); }); - it('should pass zero log arguments', function() { + it('should pass zero log arguments', function () { var called; - console.info = console.log = function() { + console.info = console.log = function () { expect(arguments.length).to.equal(0); called = true; console.log = $log; }; - expectTemplate('{{log}}') - .withInput({ blah: 'whee' }) - .toCompileTo(''); + expectTemplate('{{log}}').withInput({ blah: 'whee' }).toCompileTo(''); expect(called).to.be.true(); }); /* eslint-enable no-console */ }); - describe('#lookup', function() { - it('should lookup arbitrary content', function() { + describe('#lookup', function () { + it('should lookup arbitrary content', function () { expectTemplate('{{#each goodbyes}}{{lookup ../data .}}{{/each}}') .withInput({ goodbyes: [0, 1], data: ['foo', 'bar'] }) .toCompileTo('foobar'); }); - it('should not fail on undefined value', function() { + it('should not fail on undefined value', function () { expectTemplate('{{#each goodbyes}}{{lookup ../bar .}}{{/each}}') .withInput({ goodbyes: [0, 1], data: ['foo', 'bar'] }) .toCompileTo(''); diff --git a/spec/compiler.js b/spec/compiler.js index 8b30ed4a1..22f5f5a29 100644 --- a/spec/compiler.js +++ b/spec/compiler.js @@ -1,15 +1,15 @@ -describe('compiler', function() { +describe('compiler', function () { if (!Handlebars.compile) { return; } - describe('#equals', function() { + describe('#equals', function () { function compile(string) { var ast = Handlebars.parse(string); return new Handlebars.Compiler().compile(ast, {}); } - it('should treat as equal', function() { + it('should treat as equal', function () { equal(compile('foo').equals(compile('foo')), true); equal(compile('{{foo}}').equals(compile('{{foo}}')), true); equal(compile('{{foo.bar}}').equals(compile('{{foo.bar}}')), true); @@ -30,7 +30,7 @@ describe('compiler', function() { true ); }); - it('should treat as not equal', function() { + it('should treat as not equal', function () { equal(compile('foo').equals(compile('bar')), false); equal(compile('{{foo}}').equals(compile('{{bar}}')), false); equal(compile('{{foo.bar}}').equals(compile('{{bar.bar}}')), false); @@ -59,17 +59,17 @@ describe('compiler', function() { }); }); - describe('#compile', function() { - it('should fail with invalid input', function() { + describe('#compile', function () { + it('should fail with invalid input', function () { shouldThrow( - function() { + function () { Handlebars.compile(null); }, Error, 'You must pass a string or Handlebars AST to Handlebars.compile. You passed null' ); shouldThrow( - function() { + function () { Handlebars.compile({}); }, Error, @@ -77,7 +77,7 @@ describe('compiler', function() { ); }); - it('should include the location in the error (row and column)', function() { + it('should include the location in the error (row and column)', function () { try { Handlebars.compile(' \n {{#if}}\n{{/def}}')(); equal( @@ -101,7 +101,7 @@ describe('compiler', function() { } }); - it('should include the location as enumerable property', function() { + it('should include the location as enumerable property', function () { try { Handlebars.compile(' \n {{#if}}\n{{/def}}')(); equal( @@ -118,30 +118,30 @@ describe('compiler', function() { } }); - it('can utilize AST instance', function() { + it('can utilize AST instance', function () { equal( Handlebars.compile({ type: 'Program', - body: [{ type: 'ContentStatement', value: 'Hello' }] + body: [{ type: 'ContentStatement', value: 'Hello' }], })(), 'Hello' ); }); - it('can pass through an empty string', function() { + it('can pass through an empty string', function () { equal(Handlebars.compile('')(), ''); }); - it('throws on desupported options', function() { + it('throws on desupported options', function () { shouldThrow( - function() { + function () { Handlebars.compile('Dudes', { trackIds: true }); }, Error, 'TrackIds and stringParams are no longer supported. See Github #1145' ); shouldThrow( - function() { + function () { Handlebars.compile('Dudes', { stringParams: true }); }, Error, @@ -149,7 +149,7 @@ describe('compiler', function() { ); }); - it('should not modify the options.data property(GH-1327)', function() { + it('should not modify the options.data property(GH-1327)', function () { var options = { data: [{ a: 'foo' }, { a: 'bar' }] }; Handlebars.compile('{{#each data}}{{@index}}:{{a}} {{/each}}', options)(); equal( @@ -158,7 +158,7 @@ describe('compiler', function() { ); }); - it('should not modify the options.knownHelpers property(GH-1327)', function() { + it('should not modify the options.knownHelpers property(GH-1327)', function () { var options = { knownHelpers: {} }; Handlebars.compile('{{#each data}}{{@index}}:{{a}} {{/each}}', options)(); equal( @@ -168,17 +168,17 @@ describe('compiler', function() { }); }); - describe('#precompile', function() { - it('should fail with invalid input', function() { + describe('#precompile', function () { + it('should fail with invalid input', function () { shouldThrow( - function() { + function () { Handlebars.precompile(null); }, Error, 'You must pass a string or Handlebars AST to Handlebars.compile. You passed null' ); shouldThrow( - function() { + function () { Handlebars.precompile({}); }, Error, @@ -186,19 +186,19 @@ describe('compiler', function() { ); }); - it('can utilize AST instance', function() { + it('can utilize AST instance', function () { equal( /return "Hello"/.test( Handlebars.precompile({ type: 'Program', - body: [{ type: 'ContentStatement', value: 'Hello' }] + body: [{ type: 'ContentStatement', value: 'Hello' }], }) ), true ); }); - it('can pass through an empty string', function() { + it('can pass through an empty string', function () { equal(/return ""/.test(Handlebars.precompile('')), true); }); }); diff --git a/spec/data.js b/spec/data.js index 676798123..5402c4f9d 100644 --- a/spec/data.js +++ b/spec/data.js @@ -1,8 +1,8 @@ -describe('data', function() { - it('passing in data to a compiled function that expects data - works with helpers', function() { +describe('data', function () { + it('passing in data to a compiled function that expects data - works with helpers', function () { expectTemplate('{{hello}}') .withCompileOptions({ data: true }) - .withHelper('hello', function(options) { + .withHelper('hello', function (options) { return options.data.adjective + ' ' + this.noun; }) .withRuntimeOptions({ data: { adjective: 'happy' } }) @@ -11,17 +11,17 @@ describe('data', function() { .toCompileTo('happy cat'); }); - it('data can be looked up via @foo', function() { + it('data can be looked up via @foo', function () { expectTemplate('{{@hello}}') .withRuntimeOptions({ data: { hello: 'hello' } }) .withMessage('@foo retrieves template data') .toCompileTo('hello'); }); - it('deep @foo triggers automatic top-level data', function() { + it('deep @foo triggers automatic top-level data', function () { var helpers = Handlebars.createFrame(handlebarsEnv.helpers); - helpers.let = function(options) { + helpers.let = function (options) { var frame = Handlebars.createFrame(options.data); for (var prop in options.hash) { @@ -41,83 +41,83 @@ describe('data', function() { .toCompileTo('Hello world'); }); - it('parameter data can be looked up via @foo', function() { + it('parameter data can be looked up via @foo', function () { expectTemplate('{{hello @world}}') .withRuntimeOptions({ data: { world: 'world' } }) - .withHelper('hello', function(noun) { + .withHelper('hello', function (noun) { return 'Hello ' + noun; }) .withMessage('@foo as a parameter retrieves template data') .toCompileTo('Hello world'); }); - it('hash values can be looked up via @foo', function() { + it('hash values can be looked up via @foo', function () { expectTemplate('{{hello noun=@world}}') .withRuntimeOptions({ data: { world: 'world' } }) - .withHelper('hello', function(options) { + .withHelper('hello', function (options) { return 'Hello ' + options.hash.noun; }) .withMessage('@foo as a parameter retrieves template data') .toCompileTo('Hello world'); }); - it('nested parameter data can be looked up via @foo.bar', function() { + it('nested parameter data can be looked up via @foo.bar', function () { expectTemplate('{{hello @world.bar}}') .withRuntimeOptions({ data: { world: { bar: 'world' } } }) - .withHelper('hello', function(noun) { + .withHelper('hello', function (noun) { return 'Hello ' + noun; }) .withMessage('@foo as a parameter retrieves template data') .toCompileTo('Hello world'); }); - it('nested parameter data does not fail with @world.bar', function() { + it('nested parameter data does not fail with @world.bar', function () { expectTemplate('{{hello @world.bar}}') .withRuntimeOptions({ data: { foo: { bar: 'world' } } }) - .withHelper('hello', function(noun) { + .withHelper('hello', function (noun) { return 'Hello ' + noun; }) .withMessage('@foo as a parameter retrieves template data') .toCompileTo('Hello undefined'); }); - it('parameter data throws when using complex scope references', function() { + it('parameter data throws when using complex scope references', function () { expectTemplate( '{{#goodbyes}}{{text}} cruel {{@foo/../name}}! {{/goodbyes}}' ).toThrow(Error); }); - it('data can be functions', function() { + it('data can be functions', function () { expectTemplate('{{@hello}}') .withRuntimeOptions({ data: { - hello: function() { + hello: function () { return 'hello'; - } - } + }, + }, }) .toCompileTo('hello'); }); - it('data can be functions with params', function() { + it('data can be functions with params', function () { expectTemplate('{{@hello "hello"}}') .withRuntimeOptions({ data: { - hello: function(arg) { + hello: function (arg) { return arg; - } - } + }, + }, }) .toCompileTo('hello'); }); - it('data is inherited downstream', function() { + it('data is inherited downstream', function () { expectTemplate( '{{#let foo=1 bar=2}}{{#let foo=bar.baz}}{{@bar}}{{@foo}}{{/let}}{{@foo}}{{/let}}' ) .withInput({ bar: { baz: 'hello world' } }) .withCompileOptions({ data: true }) - .withHelper('let', function(options) { + .withHelper('let', function (options) { var frame = Handlebars.createFrame(options.data); for (var prop in options.hash) { if (prop in options.hash) { @@ -131,11 +131,11 @@ describe('data', function() { .toCompileTo('2hello world1'); }); - it('passing in data to a compiled function that expects data - works with helpers in partials', function() { + it('passing in data to a compiled function that expects data - works with helpers in partials', function () { expectTemplate('{{>myPartial}}') .withCompileOptions({ data: true }) .withPartial('myPartial', '{{hello}}') - .withHelper('hello', function(options) { + .withHelper('hello', function (options) { return options.data.adjective + ' ' + this.noun; }) .withInput({ noun: 'cat' }) @@ -144,10 +144,10 @@ describe('data', function() { .toCompileTo('happy cat'); }); - it('passing in data to a compiled function that expects data - works with helpers and parameters', function() { + it('passing in data to a compiled function that expects data - works with helpers and parameters', function () { expectTemplate('{{hello world}}') .withCompileOptions({ data: true }) - .withHelper('hello', function(noun, options) { + .withHelper('hello', function (noun, options) { return options.data.adjective + ' ' + noun + (this.exclaim ? '!' : ''); }) .withInput({ exclaim: true, world: 'world' }) @@ -156,15 +156,15 @@ describe('data', function() { .toCompileTo('happy world!'); }); - it('passing in data to a compiled function that expects data - works with block helpers', function() { + it('passing in data to a compiled function that expects data - works with block helpers', function () { expectTemplate('{{#hello}}{{world}}{{/hello}}') .withCompileOptions({ - data: true + data: true, }) - .withHelper('hello', function(options) { + .withHelper('hello', function (options) { return options.fn(this); }) - .withHelper('world', function(options) { + .withHelper('world', function (options) { return options.data.adjective + ' world' + (this.exclaim ? '!' : ''); }) .withInput({ exclaim: true }) @@ -173,13 +173,13 @@ describe('data', function() { .toCompileTo('happy world!'); }); - it('passing in data to a compiled function that expects data - works with block helpers that use ..', function() { + it('passing in data to a compiled function that expects data - works with block helpers that use ..', function () { expectTemplate('{{#hello}}{{world ../zomg}}{{/hello}}') .withCompileOptions({ data: true }) - .withHelper('hello', function(options) { + .withHelper('hello', function (options) { return options.fn({ exclaim: '?' }); }) - .withHelper('world', function(thing, options) { + .withHelper('world', function (thing, options) { return options.data.adjective + ' ' + thing + (this.exclaim || ''); }) .withInput({ exclaim: true, zomg: 'world' }) @@ -188,13 +188,13 @@ describe('data', function() { .toCompileTo('happy world?'); }); - it('passing in data to a compiled function that expects data - data is passed to with block helpers where children use ..', function() { + it('passing in data to a compiled function that expects data - data is passed to with block helpers where children use ..', function () { expectTemplate('{{#hello}}{{world ../zomg}}{{/hello}}') .withCompileOptions({ data: true }) - .withHelper('hello', function(options) { + .withHelper('hello', function (options) { return options.data.accessData + ' ' + options.fn({ exclaim: '?' }); }) - .withHelper('world', function(thing, options) { + .withHelper('world', function (thing, options) { return options.data.adjective + ' ' + thing + (this.exclaim || ''); }) .withInput({ exclaim: true, zomg: 'world' }) @@ -203,16 +203,16 @@ describe('data', function() { .toCompileTo('#win happy world?'); }); - it('you can override inherited data when invoking a helper', function() { + it('you can override inherited data when invoking a helper', function () { expectTemplate('{{#hello}}{{world zomg}}{{/hello}}') .withCompileOptions({ data: true }) - .withHelper('hello', function(options) { + .withHelper('hello', function (options) { return options.fn( { exclaim: '?', zomg: 'world' }, { data: { adjective: 'sad' } } ); }) - .withHelper('world', function(thing, options) { + .withHelper('world', function (thing, options) { return options.data.adjective + ' ' + thing + (this.exclaim || ''); }) .withInput({ exclaim: true, zomg: 'planet' }) @@ -221,13 +221,13 @@ describe('data', function() { .toCompileTo('sad world?'); }); - it('you can override inherited data when invoking a helper with depth', function() { + it('you can override inherited data when invoking a helper with depth', function () { expectTemplate('{{#hello}}{{world ../zomg}}{{/hello}}') .withCompileOptions({ data: true }) - .withHelper('hello', function(options) { + .withHelper('hello', function (options) { return options.fn({ exclaim: '?' }, { data: { adjective: 'sad' } }); }) - .withHelper('world', function(thing, options) { + .withHelper('world', function (thing, options) { return options.data.adjective + ' ' + thing + (this.exclaim || ''); }) .withInput({ exclaim: true, zomg: 'world' }) @@ -236,8 +236,8 @@ describe('data', function() { .toCompileTo('sad world?'); }); - describe('@root', function() { - it('the root context can be looked up via @root', function() { + describe('@root', function () { + it('the root context can be looked up via @root', function () { expectTemplate('{{@root.foo}}') .withInput({ foo: 'hello' }) .withRuntimeOptions({ data: {} }) @@ -248,7 +248,7 @@ describe('data', function() { .toCompileTo('hello'); }); - it('passed root values take priority', function() { + it('passed root values take priority', function () { expectTemplate('{{@root.foo}}') .withInput({ foo: 'should not be used' }) .withRuntimeOptions({ data: { root: { foo: 'hello' } } }) @@ -256,21 +256,21 @@ describe('data', function() { }); }); - describe('nesting', function() { - it('the root context can be looked up via @root', function() { + describe('nesting', function () { + it('the root context can be looked up via @root', function () { expectTemplate( '{{#helper}}{{#helper}}{{@./depth}} {{@../depth}} {{@../../depth}}{{/helper}}{{/helper}}' ) .withInput({ foo: 'hello' }) - .withHelper('helper', function(options) { + .withHelper('helper', function (options) { var frame = Handlebars.createFrame(options.data); frame.depth = options.data.depth + 1; return options.fn(this, { data: frame }); }) .withRuntimeOptions({ data: { - depth: 0 - } + depth: 0, + }, }) .toCompileTo('2 1 0'); }); diff --git a/spec/env/browser.js b/spec/env/browser.js index 28541b776..19b21070b 100644 --- a/spec/env/browser.js +++ b/spec/env/browser.js @@ -26,13 +26,13 @@ vm.runInThisContext(distHandlebars, filename); global.CompilerContext = { browser: true, - compile: function(template, options) { + compile: function (template, options) { var templateSpec = handlebarsEnv.precompile(template, options); return handlebarsEnv.template(safeEval(templateSpec)); }, - compileWithPartial: function(template, options) { + compileWithPartial: function (template, options) { return handlebarsEnv.compile(template, options); - } + }, }; function safeEval(templateSpec) { diff --git a/spec/env/common.js b/spec/env/common.js index a122f4d6e..b32d71691 100644 --- a/spec/env/common.js +++ b/spec/env/common.js @@ -1,4 +1,4 @@ -var global = (function() { +var global = (function () { return this; })(); @@ -21,7 +21,7 @@ if (Error.captureStackTrace) { /** * @deprecated Use "expectTemplate(template)...toCompileTo(output)" instead */ -global.shouldCompileTo = function(string, hashOrArray, expected, message) { +global.shouldCompileTo = function (string, hashOrArray, expected, message) { shouldCompileToWithPartials(string, hashOrArray, false, expected, message); }; @@ -47,7 +47,7 @@ global.shouldCompileToWithPartials = function shouldCompileToWithPartials( /** * @deprecated Use "expectTemplate(template)...toCompileTo(output)" instead */ -global.compileWithPartials = function(string, hashOrArray, partials) { +global.compileWithPartials = function (string, hashOrArray, partials) { var template, ary, options; if (hashOrArray && hashOrArray.hash) { ary = [hashOrArray.hash, hashOrArray]; @@ -92,7 +92,7 @@ global.equals = global.equal = function equals(a, b, msg) { * @deprecated Use chai's expect-style API instead (`expect(actualValue).to.equal(expectedValue)`) * @see https://www.chaijs.com/api/bdd/#method_throw */ -global.shouldThrow = function(callback, type, msg) { +global.shouldThrow = function (callback, type, msg) { var failed; try { callback(); @@ -121,7 +121,7 @@ global.shouldThrow = function(callback, type, msg) { } }; -global.expectTemplate = function(templateAsString) { +global.expectTemplate = function (templateAsString) { return new HandlebarsTestBench(templateAsString); }; @@ -137,38 +137,38 @@ function HandlebarsTestBench(templateAsString) { this.runtimeOptions = {}; } -HandlebarsTestBench.prototype.withInput = function(input) { +HandlebarsTestBench.prototype.withInput = function (input) { this.input = input; return this; }; -HandlebarsTestBench.prototype.withHelper = function(name, helperFunction) { +HandlebarsTestBench.prototype.withHelper = function (name, helperFunction) { this.helpers[name] = helperFunction; return this; }; -HandlebarsTestBench.prototype.withHelpers = function(helperFunctions) { +HandlebarsTestBench.prototype.withHelpers = function (helperFunctions) { var self = this; - Object.keys(helperFunctions).forEach(function(name) { + Object.keys(helperFunctions).forEach(function (name) { self.withHelper(name, helperFunctions[name]); }); return this; }; -HandlebarsTestBench.prototype.withPartial = function(name, partialAsString) { +HandlebarsTestBench.prototype.withPartial = function (name, partialAsString) { this.partials[name] = partialAsString; return this; }; -HandlebarsTestBench.prototype.withPartials = function(partials) { +HandlebarsTestBench.prototype.withPartials = function (partials) { var self = this; - Object.keys(partials).forEach(function(name) { + Object.keys(partials).forEach(function (name) { self.withPartial(name, partials[name]); }); return this; }; -HandlebarsTestBench.prototype.withDecorator = function( +HandlebarsTestBench.prototype.withDecorator = function ( name, decoratorFunction ) { @@ -176,30 +176,30 @@ HandlebarsTestBench.prototype.withDecorator = function( return this; }; -HandlebarsTestBench.prototype.withDecorators = function(decorators) { +HandlebarsTestBench.prototype.withDecorators = function (decorators) { var self = this; - Object.keys(decorators).forEach(function(name) { + Object.keys(decorators).forEach(function (name) { self.withDecorator(name, decorators[name]); }); return this; }; -HandlebarsTestBench.prototype.withCompileOptions = function(compileOptions) { +HandlebarsTestBench.prototype.withCompileOptions = function (compileOptions) { this.compileOptions = compileOptions; return this; }; -HandlebarsTestBench.prototype.withRuntimeOptions = function(runtimeOptions) { +HandlebarsTestBench.prototype.withRuntimeOptions = function (runtimeOptions) { this.runtimeOptions = runtimeOptions; return this; }; -HandlebarsTestBench.prototype.withMessage = function(message) { +HandlebarsTestBench.prototype.withMessage = function (message) { this.message = message; return this; }; -HandlebarsTestBench.prototype.toCompileTo = function(expectedOutputAsString) { +HandlebarsTestBench.prototype.toCompileTo = function (expectedOutputAsString) { expect(this._compileAndExecute()).to.equal( expectedOutputAsString, this.message @@ -207,14 +207,14 @@ HandlebarsTestBench.prototype.toCompileTo = function(expectedOutputAsString) { }; // see chai "to.throw" (https://www.chaijs.com/api/bdd/#method_throw) -HandlebarsTestBench.prototype.toThrow = function(errorLike, errMsgMatcher) { +HandlebarsTestBench.prototype.toThrow = function (errorLike, errMsgMatcher) { var self = this; - expect(function() { + expect(function () { self._compileAndExecute(); }).to.throw(errorLike, errMsgMatcher, this.message); }; -HandlebarsTestBench.prototype._compileAndExecute = function() { +HandlebarsTestBench.prototype._compileAndExecute = function () { var compile = Object.keys(this.partials).length > 0 ? CompilerContext.compileWithPartial @@ -226,10 +226,10 @@ HandlebarsTestBench.prototype._compileAndExecute = function() { return template(this.input, combinedRuntimeOptions); }; -HandlebarsTestBench.prototype._combineRuntimeOptions = function() { +HandlebarsTestBench.prototype._combineRuntimeOptions = function () { var self = this; var combinedRuntimeOptions = {}; - Object.keys(this.runtimeOptions).forEach(function(key) { + Object.keys(this.runtimeOptions).forEach(function (key) { combinedRuntimeOptions[key] = self.runtimeOptions[key]; }); combinedRuntimeOptions.helpers = this.helpers; diff --git a/spec/env/node.js b/spec/env/node.js index 1d1cd09c8..bb96c1ecb 100644 --- a/spec/env/node.js +++ b/spec/env/node.js @@ -11,13 +11,13 @@ global.sinon = require('sinon'); global.Handlebars = require('../../lib'); global.CompilerContext = { - compile: function(template, options) { + compile: function (template, options) { var templateSpec = handlebarsEnv.precompile(template, options); return handlebarsEnv.template(safeEval(templateSpec)); }, - compileWithPartial: function(template, options) { + compileWithPartial: function (template, options) { return handlebarsEnv.compile(template, options); - } + }, }; function safeEval(templateSpec) { diff --git a/spec/env/runner.js b/spec/env/runner.js index 39c522cad..ffd0b8b21 100644 --- a/spec/env/runner.js +++ b/spec/env/runner.js @@ -15,25 +15,25 @@ if (grep === '--min') { var files = fs .readdirSync(testDir) - .filter(function(name) { + .filter(function (name) { return /.*\.js$/.test(name); }) - .map(function(name) { + .map(function (name) { return testDir + path.sep + name; }); if (global.minimizedTest) { - run('./runtime', function() { - run('./browser', function() { + run('./runtime', function () { + run('./browser', function () { /* eslint-disable no-process-exit */ process.exit(errors); /* eslint-enable no-process-exit */ }); }); } else { - run('./runtime', function() { - run('./browser', function() { - run('./node', function() { + run('./runtime', function () { + run('./browser', function () { + run('./node', function () { /* eslint-disable no-process-exit */ process.exit(errors); /* eslint-enable no-process-exit */ @@ -50,13 +50,13 @@ function run(env, callback) { mocha.grep(grep); } - files.forEach(function(name) { + files.forEach(function (name) { delete require.cache[name]; }); console.log('Running env: ' + env); require(env); - mocha.run(function(errorCount) { + mocha.run(function (errorCount) { errors += errorCount; callback(); }); diff --git a/spec/env/runtime.js b/spec/env/runtime.js index 2d5007a2e..43ea83171 100644 --- a/spec/env/runtime.js +++ b/spec/env/runtime.js @@ -29,9 +29,12 @@ var JavaScriptCompiler = require('../../dist/cjs/handlebars/compiler/javascript- global.CompilerContext = { browser: true, - compile: function(template, options) { + compile: function (template, options) { // Hack the compiler on to the environment for these specific tests - handlebarsEnv.precompile = function(precompileTemplate, precompileOptions) { + handlebarsEnv.precompile = function ( + precompileTemplate, + precompileOptions + ) { return compiler.precompile( precompileTemplate, precompileOptions, @@ -45,9 +48,9 @@ global.CompilerContext = { var templateSpec = handlebarsEnv.precompile(template, options); return handlebarsEnv.template(safeEval(templateSpec)); }, - compileWithPartial: function(template, options) { + compileWithPartial: function (template, options) { // Hack the compiler on to the environment for these specific tests - handlebarsEnv.compile = function(compileTemplate, compileOptions) { + handlebarsEnv.compile = function (compileTemplate, compileOptions) { return compiler.compile(compileTemplate, compileOptions, handlebarsEnv); }; handlebarsEnv.parse = parse; @@ -55,7 +58,7 @@ global.CompilerContext = { handlebarsEnv.JavaScriptCompiler = JavaScriptCompiler; return handlebarsEnv.compile(template, options); - } + }, }; function safeEval(templateSpec) { diff --git a/spec/helpers.js b/spec/helpers.js index 5166d58d6..bbea2bf60 100644 --- a/spec/helpers.js +++ b/spec/helpers.js @@ -1,11 +1,11 @@ -describe('helpers', function() { - it('helper with complex lookup$', function() { +describe('helpers', function () { + it('helper with complex lookup$', function () { expectTemplate('{{#goodbyes}}{{{link ../prefix}}}{{/goodbyes}}') .withInput({ prefix: '/root', - goodbyes: [{ text: 'Goodbye', url: 'goodbye' }] + goodbyes: [{ text: 'Goodbye', url: 'goodbye' }], }) - .withHelper('link', function(prefix) { + .withHelper('link', function (prefix) { return ( '' + this.text + '' ); @@ -13,47 +13,47 @@ describe('helpers', function() { .toCompileTo('Goodbye'); }); - it('helper for raw block gets raw content', function() { + it('helper for raw block gets raw content', function () { expectTemplate('{{{{raw}}}} {{test}} {{{{/raw}}}}') .withInput({ test: 'hello' }) - .withHelper('raw', function(options) { + .withHelper('raw', function (options) { return options.fn(); }) .withMessage('raw block helper gets raw content') .toCompileTo(' {{test}} '); }); - it('helper for raw block gets parameters', function() { + it('helper for raw block gets parameters', function () { expectTemplate('{{{{raw 1 2 3}}}} {{test}} {{{{/raw}}}}') .withInput({ test: 'hello' }) - .withHelper('raw', function(a, b, c, options) { + .withHelper('raw', function (a, b, c, options) { return options.fn() + a + b + c; }) .withMessage('raw block helper gets raw content') .toCompileTo(' {{test}} 123'); }); - describe('raw block parsing (with identity helper-function)', function() { + describe('raw block parsing (with identity helper-function)', function () { function runWithIdentityHelper(template, expected) { expectTemplate(template) - .withHelper('identity', function(options) { + .withHelper('identity', function (options) { return options.fn(); }) .toCompileTo(expected); } - it('helper for nested raw block gets raw content', function() { + it('helper for nested raw block gets raw content', function () { runWithIdentityHelper( '{{{{identity}}}} {{{{b}}}} {{{{/b}}}} {{{{/identity}}}}', ' {{{{b}}}} {{{{/b}}}} ' ); }); - it('helper for nested raw block works with empty content', function() { + it('helper for nested raw block works with empty content', function () { runWithIdentityHelper('{{{{identity}}}}{{{{/identity}}}}', ''); }); - xit('helper for nested raw block works if nested raw blocks are broken', function() { + xit('helper for nested raw block works if nested raw blocks are broken', function () { // This test was introduced in 4.4.4, but it was not the actual problem that lead to the patch release // The test is deactivated, because in 3.x this template cases an exception and it also does not work in 4.4.3 // If anyone can make this template work without breaking everything else, then go for it, @@ -64,23 +64,23 @@ describe('helpers', function() { ); }); - it('helper for nested raw block closes after first matching close', function() { + it('helper for nested raw block closes after first matching close', function () { runWithIdentityHelper( '{{{{identity}}}}abc{{{{/identity}}}} {{{{identity}}}}abc{{{{/identity}}}}', 'abc abc' ); }); - it('helper for nested raw block throw exception when with missing closing braces', function() { + it('helper for nested raw block throw exception when with missing closing braces', function () { var string = '{{{{a}}}} {{{{/a'; expectTemplate(string).toThrow(); }); }); - it('helper block with identical context', function() { + it('helper block with identical context', function () { expectTemplate('{{#goodbyes}}{{name}}{{/goodbyes}}') .withInput({ name: 'Alan' }) - .withHelper('goodbyes', function(options) { + .withHelper('goodbyes', function (options) { var out = ''; var byes = ['Goodbye', 'goodbye', 'GOODBYE']; for (var i = 0, j = byes.length; i < j; i++) { @@ -91,10 +91,10 @@ describe('helpers', function() { .toCompileTo('Goodbye Alan! goodbye Alan! GOODBYE Alan! '); }); - it('helper block with complex lookup expression', function() { + it('helper block with complex lookup expression', function () { expectTemplate('{{#goodbyes}}{{../name}}{{/goodbyes}}') .withInput({ name: 'Alan' }) - .withHelper('goodbyes', function(options) { + .withHelper('goodbyes', function (options) { var out = ''; var byes = ['Goodbye', 'goodbye', 'GOODBYE']; for (var i = 0, j = byes.length; i < j; i++) { @@ -105,15 +105,15 @@ describe('helpers', function() { .toCompileTo('Goodbye Alan! goodbye Alan! GOODBYE Alan! '); }); - it('helper with complex lookup and nested template', function() { + it('helper with complex lookup and nested template', function () { expectTemplate( '{{#goodbyes}}{{#link ../prefix}}{{text}}{{/link}}{{/goodbyes}}' ) .withInput({ prefix: '/root', - goodbyes: [{ text: 'Goodbye', url: 'goodbye' }] + goodbyes: [{ text: 'Goodbye', url: 'goodbye' }], }) - .withHelper('link', function(prefix, options) { + .withHelper('link', function (prefix, options) { return ( 'Goodbye'); }); - it('helper with complex lookup and nested template in VM+Compiler', function() { + it('helper with complex lookup and nested template in VM+Compiler', function () { expectTemplate( '{{#goodbyes}}{{#link ../prefix}}{{text}}{{/link}}{{/goodbyes}}' ) .withInput({ prefix: '/root', - goodbyes: [{ text: 'Goodbye', url: 'goodbye' }] + goodbyes: [{ text: 'Goodbye', url: 'goodbye' }], }) - .withHelper('link', function(prefix, options) { + .withHelper('link', function (prefix, options) { return ( 'Goodbye'); }); - it('helper returning undefined value', function() { + it('helper returning undefined value', function () { expectTemplate(' {{nothere}}') .withHelpers({ - nothere: function() {} + nothere: function () {}, }) .toCompileTo(' '); expectTemplate(' {{#nothere}}{{/nothere}}') .withHelpers({ - nothere: function() {} + nothere: function () {}, }) .toCompileTo(' '); }); - it('block helper', function() { + it('block helper', function () { expectTemplate('{{#goodbyes}}{{text}}! {{/goodbyes}}cruel {{world}}!') .withInput({ world: 'world' }) - .withHelper('goodbyes', function(options) { + .withHelper('goodbyes', function (options) { return options.fn({ text: 'GOODBYE' }); }) .withMessage('Block helper executed') .toCompileTo('GOODBYE! cruel world!'); }); - it('block helper staying in the same context', function() { + it('block helper staying in the same context', function () { expectTemplate('{{#form}}

{{name}}

{{/form}}') .withInput({ name: 'Yehuda' }) - .withHelper('form', function(options) { + .withHelper('form', function (options) { return '
' + options.fn(this) + '
'; }) .withMessage('Block helper executed with current context') .toCompileTo('

Yehuda

'); }); - it('block helper should have context in this', function() { + it('block helper should have context in this', function () { function link(options) { return '' + options.fn(this) + ''; } @@ -194,8 +194,8 @@ describe('helpers', function() { .withInput({ people: [ { name: 'Alan', id: 1 }, - { name: 'Yehuda', id: 2 } - ] + { name: 'Yehuda', id: 2 }, + ], }) .withHelper('link', link) .toCompileTo( @@ -203,48 +203,48 @@ describe('helpers', function() { ); }); - it('block helper for undefined value', function() { + it('block helper for undefined value', function () { expectTemplate("{{#empty}}shouldn't render{{/empty}}").toCompileTo(''); }); - it('block helper passing a new context', function() { + it('block helper passing a new context', function () { expectTemplate('{{#form yehuda}}

{{name}}

{{/form}}') .withInput({ yehuda: { name: 'Yehuda' } }) - .withHelper('form', function(context, options) { + .withHelper('form', function (context, options) { return '
' + options.fn(context) + '
'; }) .withMessage('Context variable resolved') .toCompileTo('

Yehuda

'); }); - it('block helper passing a complex path context', function() { + it('block helper passing a complex path context', function () { expectTemplate('{{#form yehuda/cat}}

{{name}}

{{/form}}') .withInput({ yehuda: { name: 'Yehuda', cat: { name: 'Harold' } } }) - .withHelper('form', function(context, options) { + .withHelper('form', function (context, options) { return '
' + options.fn(context) + '
'; }) .withMessage('Complex path variable resolved') .toCompileTo('

Harold

'); }); - it('nested block helpers', function() { + it('nested block helpers', function () { expectTemplate( '{{#form yehuda}}

{{name}}

{{#link}}Hello{{/link}}{{/form}}' ) .withInput({ - yehuda: { name: 'Yehuda' } + yehuda: { name: 'Yehuda' }, }) - .withHelper('link', function(options) { + .withHelper('link', function (options) { return '' + options.fn(this) + ''; }) - .withHelper('form', function(context, options) { + .withHelper('form', function (context, options) { return '
' + options.fn(context) + '
'; }) .withMessage('Both blocks executed') .toCompileTo('

Yehuda

Hello
'); }); - it('block helper inverted sections', function() { + it('block helper inverted sections', function () { var string = "{{#list people}}{{name}}{{^}}Nobody's here{{/list}}"; function list(context, options) { if (context.length > 0) { @@ -278,24 +278,24 @@ describe('helpers', function() { expectTemplate('{{#list people}}Hello{{^}}{{message}}{{/list}}') .withInput({ people: [], - message: "Nobody's here" + message: "Nobody's here", }) .withHelpers({ list: list }) .withMessage('the context of an inverse is the parent of the block') .toCompileTo('

Nobody's here

'); }); - it('pathed lambas with parameters', function() { + it('pathed lambas with parameters', function () { var hash = { - helper: function() { + helper: function () { return 'winning'; - } + }, }; hash.hash = hash; var helpers = { - './helper': function() { + './helper': function () { return 'fail'; - } + }, }; expectTemplate('{{./helper 1}}') @@ -309,14 +309,14 @@ describe('helpers', function() { .toCompileTo('winning'); }); - describe('helpers hash', function() { - it('providing a helpers hash', function() { + describe('helpers hash', function () { + it('providing a helpers hash', function () { expectTemplate('Goodbye {{cruel}} {{world}}!') .withInput({ cruel: 'cruel' }) .withHelpers({ - world: function() { + world: function () { return 'world'; - } + }, }) .withMessage('helpers hash is available') .toCompileTo('Goodbye cruel world!'); @@ -324,21 +324,21 @@ describe('helpers', function() { expectTemplate('Goodbye {{#iter}}{{cruel}} {{world}}{{/iter}}!') .withInput({ iter: [{ cruel: 'cruel' }] }) .withHelpers({ - world: function() { + world: function () { return 'world'; - } + }, }) .withMessage('helpers hash is available inside other blocks') .toCompileTo('Goodbye cruel world!'); }); - it('in cases of conflict, helpers win', function() { + it('in cases of conflict, helpers win', function () { expectTemplate('{{{lookup}}}') .withInput({ lookup: 'Explicit' }) .withHelpers({ - lookup: function() { + lookup: function () { return 'helpers'; - } + }, }) .withMessage('helpers hash has precedence escaped expansion') .toCompileTo('helpers'); @@ -346,28 +346,28 @@ describe('helpers', function() { expectTemplate('{{lookup}}') .withInput({ lookup: 'Explicit' }) .withHelpers({ - lookup: function() { + lookup: function () { return 'helpers'; - } + }, }) .withMessage('helpers hash has precedence simple expansion') .toCompileTo('helpers'); }); - it('the helpers hash is available is nested contexts', function() { + it('the helpers hash is available is nested contexts', function () { expectTemplate('{{#outer}}{{#inner}}{{helper}}{{/inner}}{{/outer}}') .withInput({ outer: { inner: { unused: [] } } }) .withHelpers({ - helper: function() { + helper: function () { return 'helper'; - } + }, }) .withMessage('helpers hash is available in nested contexts.') .toCompileTo('helper'); }); - it('the helper hash should augment the global hash', function() { - handlebarsEnv.registerHelper('test_helper', function() { + it('the helper hash should augment the global hash', function () { + handlebarsEnv.registerHelper('test_helper', function () { return 'found it!'; }); @@ -376,37 +376,37 @@ describe('helpers', function() { ) .withInput({ cruel: 'cruel' }) .withHelpers({ - world: function() { + world: function () { return 'world!'; - } + }, }) .toCompileTo('found it! Goodbye cruel world!!'); }); }); - describe('registration', function() { - it('unregisters', function() { + describe('registration', function () { + it('unregisters', function () { handlebarsEnv.helpers = {}; - handlebarsEnv.registerHelper('foo', function() { + handlebarsEnv.registerHelper('foo', function () { return 'fail'; }); handlebarsEnv.unregisterHelper('foo'); equals(handlebarsEnv.helpers.foo, undefined); }); - it('allows multiple globals', function() { + it('allows multiple globals', function () { var helpers = handlebarsEnv.helpers; handlebarsEnv.helpers = {}; handlebarsEnv.registerHelper({ if: helpers['if'], - world: function() { + world: function () { return 'world!'; }, - testHelper: function() { + testHelper: function () { return 'found it!'; - } + }, }); expectTemplate( @@ -416,17 +416,17 @@ describe('helpers', function() { .toCompileTo('found it! Goodbye cruel world!!'); }); - it('fails with multiple and args', function() { + it('fails with multiple and args', function () { shouldThrow( - function() { + function () { handlebarsEnv.registerHelper( { - world: function() { + world: function () { return 'world!'; }, - testHelper: function() { + testHelper: function () { return 'found it!'; - } + }, }, {} ); @@ -437,9 +437,9 @@ describe('helpers', function() { }); }); - it('decimal number literals work', function() { + it('decimal number literals work', function () { expectTemplate('Message: {{hello -1.2 1.2}}') - .withHelper('hello', function(times, times2) { + .withHelper('hello', function (times, times2) { if (typeof times !== 'number') { times = 'NaN'; } @@ -452,9 +452,9 @@ describe('helpers', function() { .toCompileTo('Message: Hello -1.2 1.2 times'); }); - it('negative number literals work', function() { + it('negative number literals work', function () { expectTemplate('Message: {{hello -12}}') - .withHelper('hello', function(times) { + .withHelper('hello', function (times) { if (typeof times !== 'number') { times = 'NaN'; } @@ -464,10 +464,10 @@ describe('helpers', function() { .toCompileTo('Message: Hello -12 times'); }); - describe('String literal parameters', function() { - it('simple literals work', function() { + describe('String literal parameters', function () { + it('simple literals work', function () { expectTemplate('Message: {{hello "world" 12 true false}}') - .withHelper('hello', function(param, times, bool1, bool2) { + .withHelper('hello', function (param, times, bool1, bool2) { if (typeof times !== 'number') { times = 'NaN'; } @@ -485,22 +485,22 @@ describe('helpers', function() { .toCompileTo('Message: Hello world 12 times: true false'); }); - it('using a quote in the middle of a parameter raises an error', function() { + it('using a quote in the middle of a parameter raises an error', function () { expectTemplate('Message: {{hello wo"rld"}}').toThrow(Error); }); - it('escaping a String is possible', function() { + it('escaping a String is possible', function () { expectTemplate('Message: {{{hello "\\"world\\""}}}') - .withHelper('hello', function(param) { + .withHelper('hello', function (param) { return 'Hello ' + param; }) .withMessage('template with an escaped String literal') .toCompileTo('Message: Hello "world"'); }); - it("it works with ' marks", function() { + it("it works with ' marks", function () { expectTemplate('Message: {{{hello "Alan\'s world"}}}') - .withHelper('hello', function(param) { + .withHelper('hello', function (param) { return 'Hello ' + param; }) .withMessage("template with a ' mark") @@ -508,9 +508,9 @@ describe('helpers', function() { }); }); - it('negative number literals work', function() { + it('negative number literals work', function () { expectTemplate('Message: {{hello -12}}') - .withHelper('hello', function(times) { + .withHelper('hello', function (times) { if (typeof times !== 'number') { times = 'NaN'; } @@ -520,23 +520,23 @@ describe('helpers', function() { .toCompileTo('Message: Hello -12 times'); }); - describe('multiple parameters', function() { - it('simple multi-params work', function() { + describe('multiple parameters', function () { + it('simple multi-params work', function () { expectTemplate('Message: {{goodbye cruel world}}') .withInput({ cruel: 'cruel', world: 'world' }) - .withHelper('goodbye', function(cruel, world) { + .withHelper('goodbye', function (cruel, world) { return 'Goodbye ' + cruel + ' ' + world; }) .withMessage('regular helpers with multiple params') .toCompileTo('Message: Goodbye cruel world'); }); - it('block multi-params work', function() { + it('block multi-params work', function () { expectTemplate( 'Message: {{#goodbye cruel world}}{{greeting}} {{adj}} {{noun}}{{/goodbye}}' ) .withInput({ cruel: 'cruel', world: 'world' }) - .withHelper('goodbye', function(cruel, world, options) { + .withHelper('goodbye', function (cruel, world, options) { return options.fn({ greeting: 'Goodbye', adj: cruel, noun: world }); }) .withMessage('block helpers with multiple params') @@ -544,10 +544,10 @@ describe('helpers', function() { }); }); - describe('hash', function() { - it('helpers can take an optional hash', function() { + describe('hash', function () { + it('helpers can take an optional hash', function () { expectTemplate('{{goodbye cruel="CRUEL" world="WORLD" times=12}}') - .withHelper('goodbye', function(options) { + .withHelper('goodbye', function (options) { return ( 'GOODBYE ' + options.hash.cruel + @@ -562,7 +562,7 @@ describe('helpers', function() { .toCompileTo('GOODBYE CRUEL WORLD 12 TIMES'); }); - it('helpers can take an optional hash with booleans', function() { + it('helpers can take an optional hash with booleans', function () { function goodbye(options) { if (options.hash.print === true) { return 'GOODBYE ' + options.hash.cruel + ' ' + options.hash.world; @@ -584,9 +584,9 @@ describe('helpers', function() { .toCompileTo('NOT PRINTING'); }); - it('block helpers can take an optional hash', function() { + it('block helpers can take an optional hash', function () { expectTemplate('{{#goodbye cruel="CRUEL" times=12}}world{{/goodbye}}') - .withHelper('goodbye', function(options) { + .withHelper('goodbye', function (options) { return ( 'GOODBYE ' + options.hash.cruel + @@ -601,9 +601,9 @@ describe('helpers', function() { .toCompileTo('GOODBYE CRUEL world 12 TIMES'); }); - it('block helpers can take an optional hash with single quoted stings', function() { + it('block helpers can take an optional hash with single quoted stings', function () { expectTemplate('{{#goodbye cruel="CRUEL" times=12}}world{{/goodbye}}') - .withHelper('goodbye', function(options) { + .withHelper('goodbye', function (options) { return ( 'GOODBYE ' + options.hash.cruel + @@ -618,7 +618,7 @@ describe('helpers', function() { .toCompileTo('GOODBYE CRUEL world 12 TIMES'); }); - it('block helpers can take an optional hash with booleans', function() { + it('block helpers can take an optional hash with booleans', function () { function goodbye(options) { if (options.hash.print === true) { return 'GOODBYE ' + options.hash.cruel + ' ' + options.fn(this); @@ -641,17 +641,17 @@ describe('helpers', function() { }); }); - describe('helperMissing', function() { - it('if a context is not found, helperMissing is used', function() { + describe('helperMissing', function () { + it('if a context is not found, helperMissing is used', function () { expectTemplate('{{hello}} {{link_to world}}').toThrow( /Missing helper: "link_to"/ ); }); - it('if a context is not found, custom helperMissing is used', function() { + it('if a context is not found, custom helperMissing is used', function () { expectTemplate('{{hello}} {{link_to world}}') .withInput({ hello: 'Hello', world: 'world' }) - .withHelper('helperMissing', function(mesg, options) { + .withHelper('helperMissing', function (mesg, options) { if (options.name === 'link_to') { return new Handlebars.SafeString('' + mesg + ''); } @@ -659,10 +659,10 @@ describe('helpers', function() { .toCompileTo('Hello world'); }); - it('if a value is not found, custom helperMissing is used', function() { + it('if a value is not found, custom helperMissing is used', function () { expectTemplate('{{hello}} {{link_to}}') .withInput({ hello: 'Hello', world: 'world' }) - .withHelper('helperMissing', function(options) { + .withHelper('helperMissing', function (options) { if (options.name === 'link_to') { return new Handlebars.SafeString('winning'); } @@ -671,175 +671,175 @@ describe('helpers', function() { }); }); - describe('knownHelpers', function() { - it('Known helper should render helper', function() { + describe('knownHelpers', function () { + it('Known helper should render helper', function () { expectTemplate('{{hello}}') .withCompileOptions({ - knownHelpers: { hello: true } + knownHelpers: { hello: true }, }) - .withHelper('hello', function() { + .withHelper('hello', function () { return 'foo'; }) .toCompileTo('foo'); }); - it('Unknown helper in knownHelpers only mode should be passed as undefined', function() { + it('Unknown helper in knownHelpers only mode should be passed as undefined', function () { expectTemplate('{{typeof hello}}') .withCompileOptions({ knownHelpers: { typeof: true }, - knownHelpersOnly: true + knownHelpersOnly: true, }) - .withHelper('typeof', function(arg) { + .withHelper('typeof', function (arg) { return typeof arg; }) - .withHelper('hello', function() { + .withHelper('hello', function () { return 'foo'; }) .toCompileTo('undefined'); }); - it('Builtin helpers available in knownHelpers only mode', function() { + it('Builtin helpers available in knownHelpers only mode', function () { expectTemplate('{{#unless foo}}bar{{/unless}}') .withCompileOptions({ - knownHelpersOnly: true + knownHelpersOnly: true, }) .toCompileTo('bar'); }); - it('Field lookup works in knownHelpers only mode', function() { + it('Field lookup works in knownHelpers only mode', function () { expectTemplate('{{foo}}') .withCompileOptions({ - knownHelpersOnly: true + knownHelpersOnly: true, }) .withInput({ foo: 'bar' }) .toCompileTo('bar'); }); - it('Conditional blocks work in knownHelpers only mode', function() { + it('Conditional blocks work in knownHelpers only mode', function () { expectTemplate('{{#foo}}bar{{/foo}}') .withCompileOptions({ - knownHelpersOnly: true + knownHelpersOnly: true, }) .withInput({ foo: 'baz' }) .toCompileTo('bar'); }); - it('Invert blocks work in knownHelpers only mode', function() { + it('Invert blocks work in knownHelpers only mode', function () { expectTemplate('{{^foo}}bar{{/foo}}') .withCompileOptions({ - knownHelpersOnly: true + knownHelpersOnly: true, }) .withInput({ foo: false }) .toCompileTo('bar'); }); - it('Functions are bound to the context in knownHelpers only mode', function() { + it('Functions are bound to the context in knownHelpers only mode', function () { expectTemplate('{{foo}}') .withCompileOptions({ - knownHelpersOnly: true + knownHelpersOnly: true, }) .withInput({ - foo: function() { + foo: function () { return this.bar; }, - bar: 'bar' + bar: 'bar', }) .toCompileTo('bar'); }); - it('Unknown helper call in knownHelpers only mode should throw', function() { + it('Unknown helper call in knownHelpers only mode should throw', function () { expectTemplate('{{typeof hello}}') .withCompileOptions({ knownHelpersOnly: true }) .toThrow(Error); }); }); - describe('blockHelperMissing', function() { - it('lambdas are resolved by blockHelperMissing, not handlebars proper', function() { + describe('blockHelperMissing', function () { + it('lambdas are resolved by blockHelperMissing, not handlebars proper', function () { expectTemplate('{{#truthy}}yep{{/truthy}}') .withInput({ - truthy: function() { + truthy: function () { return true; - } + }, }) .toCompileTo('yep'); }); - it('lambdas resolved by blockHelperMissing are bound to the context', function() { + it('lambdas resolved by blockHelperMissing are bound to the context', function () { expectTemplate('{{#truthy}}yep{{/truthy}}') .withInput({ - truthy: function() { + truthy: function () { return this.truthiness(); }, - truthiness: function() { + truthiness: function () { return false; - } + }, }) .toCompileTo(''); }); }); - describe('name field', function() { + describe('name field', function () { var helpers = { - blockHelperMissing: function() { + blockHelperMissing: function () { return 'missing: ' + arguments[arguments.length - 1].name; }, - helperMissing: function() { + helperMissing: function () { return 'helper missing: ' + arguments[arguments.length - 1].name; }, - helper: function() { + helper: function () { return 'ran: ' + arguments[arguments.length - 1].name; - } + }, }; - it('should include in ambiguous mustache calls', function() { + it('should include in ambiguous mustache calls', function () { expectTemplate('{{helper}}') .withHelpers(helpers) .toCompileTo('ran: helper'); }); - it('should include in helper mustache calls', function() { + it('should include in helper mustache calls', function () { expectTemplate('{{helper 1}}') .withHelpers(helpers) .toCompileTo('ran: helper'); }); - it('should include in ambiguous block calls', function() { + it('should include in ambiguous block calls', function () { expectTemplate('{{#helper}}{{/helper}}') .withHelpers(helpers) .toCompileTo('ran: helper'); }); - it('should include in simple block calls', function() { + it('should include in simple block calls', function () { expectTemplate('{{#./helper}}{{/./helper}}') .withHelpers(helpers) .toCompileTo('missing: ./helper'); }); - it('should include in helper block calls', function() { + it('should include in helper block calls', function () { expectTemplate('{{#helper 1}}{{/helper}}') .withHelpers(helpers) .toCompileTo('ran: helper'); }); - it('should include in known helper calls', function() { + it('should include in known helper calls', function () { expectTemplate('{{helper}}') .withCompileOptions({ knownHelpers: { helper: true }, - knownHelpersOnly: true + knownHelpersOnly: true, }) .withHelpers(helpers) .toCompileTo('ran: helper'); }); - it('should include full id', function() { + it('should include full id', function () { expectTemplate('{{#foo.helper}}{{/foo.helper}}') .withInput({ foo: {} }) .withHelpers(helpers) .toCompileTo('missing: foo.helper'); }); - it('should include full id if a hash is passed', function() { + it('should include full id if a hash is passed', function () { expectTemplate('{{#foo.helper bar=baz}}{{/foo.helper}}') .withInput({ foo: {} }) .withHelpers(helpers) @@ -847,136 +847,136 @@ describe('helpers', function() { }); }); - describe('name conflicts', function() { - it('helpers take precedence over same-named context properties', function() { + describe('name conflicts', function () { + it('helpers take precedence over same-named context properties', function () { expectTemplate('{{goodbye}} {{cruel world}}') - .withHelper('goodbye', function() { + .withHelper('goodbye', function () { return this.goodbye.toUpperCase(); }) - .withHelper('cruel', function(world) { + .withHelper('cruel', function (world) { return 'cruel ' + world.toUpperCase(); }) .withInput({ goodbye: 'goodbye', - world: 'world' + world: 'world', }) .withMessage('Helper executed') .toCompileTo('GOODBYE cruel WORLD'); }); - it('helpers take precedence over same-named context properties$', function() { + it('helpers take precedence over same-named context properties$', function () { expectTemplate('{{#goodbye}} {{cruel world}}{{/goodbye}}') - .withHelper('goodbye', function(options) { + .withHelper('goodbye', function (options) { return this.goodbye.toUpperCase() + options.fn(this); }) - .withHelper('cruel', function(world) { + .withHelper('cruel', function (world) { return 'cruel ' + world.toUpperCase(); }) .withInput({ goodbye: 'goodbye', - world: 'world' + world: 'world', }) .withMessage('Helper executed') .toCompileTo('GOODBYE cruel WORLD'); }); - it('Scoped names take precedence over helpers', function() { + it('Scoped names take precedence over helpers', function () { expectTemplate('{{this.goodbye}} {{cruel world}} {{cruel this.goodbye}}') - .withHelper('goodbye', function() { + .withHelper('goodbye', function () { return this.goodbye.toUpperCase(); }) - .withHelper('cruel', function(world) { + .withHelper('cruel', function (world) { return 'cruel ' + world.toUpperCase(); }) .withInput({ goodbye: 'goodbye', - world: 'world' + world: 'world', }) .withMessage('Helper not executed') .toCompileTo('goodbye cruel WORLD cruel GOODBYE'); }); - it('Scoped names take precedence over block helpers', function() { + it('Scoped names take precedence over block helpers', function () { expectTemplate( '{{#goodbye}} {{cruel world}}{{/goodbye}} {{this.goodbye}}' ) - .withHelper('goodbye', function(options) { + .withHelper('goodbye', function (options) { return this.goodbye.toUpperCase() + options.fn(this); }) - .withHelper('cruel', function(world) { + .withHelper('cruel', function (world) { return 'cruel ' + world.toUpperCase(); }) .withInput({ goodbye: 'goodbye', - world: 'world' + world: 'world', }) .withMessage('Helper executed') .toCompileTo('GOODBYE cruel WORLD goodbye'); }); }); - describe('block params', function() { - it('should take presedence over context values', function() { + describe('block params', function () { + it('should take presedence over context values', function () { expectTemplate('{{#goodbyes as |value|}}{{value}}{{/goodbyes}}{{value}}') .withInput({ value: 'foo' }) - .withHelper('goodbyes', function(options) { + .withHelper('goodbyes', function (options) { equals(options.fn.blockParams, 1); return options.fn({ value: 'bar' }, { blockParams: [1, 2] }); }) .toCompileTo('1foo'); }); - it('should take presedence over helper values', function() { + it('should take presedence over helper values', function () { expectTemplate('{{#goodbyes as |value|}}{{value}}{{/goodbyes}}{{value}}') - .withHelper('value', function() { + .withHelper('value', function () { return 'foo'; }) - .withHelper('goodbyes', function(options) { + .withHelper('goodbyes', function (options) { equals(options.fn.blockParams, 1); return options.fn({}, { blockParams: [1, 2] }); }) .toCompileTo('1foo'); }); - it('should not take presedence over pathed values', function() { + it('should not take presedence over pathed values', function () { expectTemplate( '{{#goodbyes as |value|}}{{./value}}{{/goodbyes}}{{value}}' ) .withInput({ value: 'bar' }) - .withHelper('value', function() { + .withHelper('value', function () { return 'foo'; }) - .withHelper('goodbyes', function(options) { + .withHelper('goodbyes', function (options) { equals(options.fn.blockParams, 1); return options.fn(this, { blockParams: [1, 2] }); }) .toCompileTo('barfoo'); }); - it('should take presednece over parent block params', function() { + it('should take presednece over parent block params', function () { var value = 1; expectTemplate( '{{#goodbyes as |value|}}{{#goodbyes}}{{value}}{{#goodbyes as |value|}}{{value}}{{/goodbyes}}{{/goodbyes}}{{/goodbyes}}{{value}}' ) .withInput({ value: 'foo' }) - .withHelper('goodbyes', function(options) { + .withHelper('goodbyes', function (options) { return options.fn( { value: 'bar' }, { blockParams: - options.fn.blockParams === 1 ? [value++, value++] : undefined + options.fn.blockParams === 1 ? [value++, value++] : undefined, } ); }) .toCompileTo('13foo'); }); - it('should allow block params on chained helpers', function() { + it('should allow block params on chained helpers', function () { expectTemplate( '{{#if bar}}{{else goodbyes as |value|}}{{value}}{{/if}}{{value}}' ) .withInput({ value: 'foo' }) - .withHelper('goodbyes', function(options) { + .withHelper('goodbyes', function (options) { equals(options.fn.blockParams, 1); return options.fn({ value: 'bar' }, { blockParams: [1, 2] }); }) @@ -984,58 +984,58 @@ describe('helpers', function() { }); }); - describe('built-in helpers malformed arguments ', function() { - it('if helper - too few arguments', function() { + describe('built-in helpers malformed arguments ', function () { + it('if helper - too few arguments', function () { expectTemplate('{{#if}}{{/if}}').toThrow( /#if requires exactly one argument/ ); }); - it('if helper - too many arguments, string', function() { + it('if helper - too many arguments, string', function () { expectTemplate('{{#if test "string"}}{{/if}}').toThrow( /#if requires exactly one argument/ ); }); - it('if helper - too many arguments, undefined', function() { + it('if helper - too many arguments, undefined', function () { expectTemplate('{{#if test undefined}}{{/if}}').toThrow( /#if requires exactly one argument/ ); }); - it('if helper - too many arguments, null', function() { + it('if helper - too many arguments, null', function () { expectTemplate('{{#if test null}}{{/if}}').toThrow( /#if requires exactly one argument/ ); }); - it('unless helper - too few arguments', function() { + it('unless helper - too few arguments', function () { expectTemplate('{{#unless}}{{/unless}}').toThrow( /#unless requires exactly one argument/ ); }); - it('unless helper - too many arguments', function() { + it('unless helper - too many arguments', function () { expectTemplate('{{#unless test null}}{{/unless}}').toThrow( /#unless requires exactly one argument/ ); }); - it('with helper - too few arguments', function() { + it('with helper - too few arguments', function () { expectTemplate('{{#with}}{{/with}}').toThrow( /#with requires exactly one argument/ ); }); - it('with helper - too many arguments', function() { + it('with helper - too many arguments', function () { expectTemplate('{{#with test "string"}}{{/with}}').toThrow( /#with requires exactly one argument/ ); }); }); - describe('the lookupProperty-option', function() { - it('should be passed to custom helpers', function() { + describe('the lookupProperty-option', function () { + it('should be passed to custom helpers', function () { expectTemplate('{{testHelper}}') .withHelper('testHelper', function testHelper(options) { return options.lookupProperty(this, 'testProperty'); diff --git a/spec/javascript-compiler.js b/spec/javascript-compiler.js index ed2dc8c56..41d8e74b5 100644 --- a/spec/javascript-compiler.js +++ b/spec/javascript-compiler.js @@ -1,19 +1,19 @@ -describe('javascript-compiler api', function() { +describe('javascript-compiler api', function () { if (!Handlebars.JavaScriptCompiler) { return; } - describe('#nameLookup', function() { + describe('#nameLookup', function () { var $superName; - beforeEach(function() { + beforeEach(function () { $superName = handlebarsEnv.JavaScriptCompiler.prototype.nameLookup; }); - afterEach(function() { + afterEach(function () { handlebarsEnv.JavaScriptCompiler.prototype.nameLookup = $superName; }); - it('should allow override', function() { - handlebarsEnv.JavaScriptCompiler.prototype.nameLookup = function( + it('should allow override', function () { + handlebarsEnv.JavaScriptCompiler.prototype.nameLookup = function ( parent, name ) { @@ -28,27 +28,27 @@ describe('javascript-compiler api', function() { // Tests nameLookup dot vs. bracket behavior. Bracket is required in certain cases // to avoid errors in older browsers. - it('should handle reserved words', function() { + it('should handle reserved words', function () { expectTemplate('{{foo}} {{~null~}}') .withInput({ foo: 'food' }) .toCompileTo('food'); }); }); - describe('#compilerInfo', function() { + describe('#compilerInfo', function () { var $superCheck, $superInfo; - beforeEach(function() { + beforeEach(function () { $superCheck = handlebarsEnv.VM.checkRevision; $superInfo = handlebarsEnv.JavaScriptCompiler.prototype.compilerInfo; }); - afterEach(function() { + afterEach(function () { handlebarsEnv.VM.checkRevision = $superCheck; handlebarsEnv.JavaScriptCompiler.prototype.compilerInfo = $superInfo; }); - it('should allow compilerInfo override', function() { - handlebarsEnv.JavaScriptCompiler.prototype.compilerInfo = function() { + it('should allow compilerInfo override', function () { + handlebarsEnv.JavaScriptCompiler.prototype.compilerInfo = function () { return 'crazy'; }; - handlebarsEnv.VM.checkRevision = function(compilerInfo) { + handlebarsEnv.VM.checkRevision = function (compilerInfo) { if (compilerInfo !== 'crazy') { throw new Error("It didn't work"); } @@ -58,30 +58,32 @@ describe('javascript-compiler api', function() { .toCompileTo('food '); }); }); - describe('buffer', function() { + describe('buffer', function () { var $superAppend, $superCreate; - beforeEach(function() { + beforeEach(function () { handlebarsEnv.JavaScriptCompiler.prototype.forceBuffer = true; $superAppend = handlebarsEnv.JavaScriptCompiler.prototype.appendToBuffer; $superCreate = handlebarsEnv.JavaScriptCompiler.prototype.initializeBuffer; }); - afterEach(function() { + afterEach(function () { handlebarsEnv.JavaScriptCompiler.prototype.forceBuffer = false; handlebarsEnv.JavaScriptCompiler.prototype.appendToBuffer = $superAppend; - handlebarsEnv.JavaScriptCompiler.prototype.initializeBuffer = $superCreate; + handlebarsEnv.JavaScriptCompiler.prototype.initializeBuffer = + $superCreate; }); - it('should allow init buffer override', function() { - handlebarsEnv.JavaScriptCompiler.prototype.initializeBuffer = function() { - return this.quotedString('foo_'); - }; + it('should allow init buffer override', function () { + handlebarsEnv.JavaScriptCompiler.prototype.initializeBuffer = + function () { + return this.quotedString('foo_'); + }; expectTemplate('{{foo}} ') .withInput({ foo: 'food' }) .toCompileTo('foo_food '); }); - it('should allow append buffer override', function() { - handlebarsEnv.JavaScriptCompiler.prototype.appendToBuffer = function( + it('should allow append buffer override', function () { + handlebarsEnv.JavaScriptCompiler.prototype.appendToBuffer = function ( string ) { return $superAppend.call(this, [string, ' + "_foo"']); @@ -92,13 +94,13 @@ describe('javascript-compiler api', function() { }); }); - describe('#isValidJavaScriptVariableName', function() { + describe('#isValidJavaScriptVariableName', function () { // It is there and accessible and could be used by someone. That's why we don't remove it // it 4.x. But if we keep it, we add a test // This test should not encourage you to use the function. It is not needed any more // and might be removed in 5.0 - ['test', 'abc123', 'abc_123'].forEach(function(validVariableName) { - it("should return true for '" + validVariableName + "'", function() { + ['test', 'abc123', 'abc_123'].forEach(function (validVariableName) { + it("should return true for '" + validVariableName + "'", function () { expect( handlebarsEnv.JavaScriptCompiler.isValidJavaScriptVariableName( validVariableName @@ -106,8 +108,8 @@ describe('javascript-compiler api', function() { ).to.be.true(); }); }); - [('123test', 'abc()', 'abc.cde')].forEach(function(invalidVariableName) { - it("should return true for '" + invalidVariableName + "'", function() { + [('123test', 'abc()', 'abc.cde')].forEach(function (invalidVariableName) { + it("should return true for '" + invalidVariableName + "'", function () { expect( handlebarsEnv.JavaScriptCompiler.isValidJavaScriptVariableName( invalidVariableName diff --git a/spec/partials.js b/spec/partials.js index df092267d..5144b4242 100644 --- a/spec/partials.js +++ b/spec/partials.js @@ -1,12 +1,12 @@ -describe('partials', function() { - it('basic partials', function() { +describe('partials', function () { + it('basic partials', function () { var string = 'Dudes: {{#dudes}}{{> dude}}{{/dudes}}'; var partial = '{{name}} ({{url}}) '; var hash = { dudes: [ { name: 'Yehuda', url: 'http://yehuda' }, - { name: 'Alan', url: 'http://alan' } - ] + { name: 'Alan', url: 'http://alan' }, + ], }; expectTemplate(string) @@ -22,19 +22,19 @@ describe('partials', function() { .toCompileTo('Dudes: Yehuda (http://yehuda) Alan (http://alan) '); }); - it('dynamic partials', function() { + it('dynamic partials', function () { var string = 'Dudes: {{#dudes}}{{> (partial)}}{{/dudes}}'; var partial = '{{name}} ({{url}}) '; var hash = { dudes: [ { name: 'Yehuda', url: 'http://yehuda' }, - { name: 'Alan', url: 'http://alan' } - ] + { name: 'Alan', url: 'http://alan' }, + ], }; var helpers = { - partial: function() { + partial: function () { return 'dude'; - } + }, }; expectTemplate(string) @@ -52,41 +52,41 @@ describe('partials', function() { .toCompileTo('Dudes: Yehuda (http://yehuda) Alan (http://alan) '); }); - it('failing dynamic partials', function() { + it('failing dynamic partials', function () { expectTemplate('Dudes: {{#dudes}}{{> (partial)}}{{/dudes}}') .withInput({ dudes: [ { name: 'Yehuda', url: 'http://yehuda' }, - { name: 'Alan', url: 'http://alan' } - ] + { name: 'Alan', url: 'http://alan' }, + ], }) - .withHelper('partial', function() { + .withHelper('partial', function () { return 'missing'; }) .withPartial('dude', '{{name}} ({{url}}) ') .toThrow(Handlebars.Exception, 'The partial missing could not be found'); }); - it('partials with context', function() { + it('partials with context', function () { expectTemplate('Dudes: {{>dude dudes}}') .withInput({ dudes: [ { name: 'Yehuda', url: 'http://yehuda' }, - { name: 'Alan', url: 'http://alan' } - ] + { name: 'Alan', url: 'http://alan' }, + ], }) .withPartial('dude', '{{#this}}{{name}} ({{url}}) {{/this}}') .withMessage('Partials can be passed a context') .toCompileTo('Dudes: Yehuda (http://yehuda) Alan (http://alan) '); }); - it('partials with no context', function() { + it('partials with no context', function () { var partial = '{{name}} ({{url}}) '; var hash = { dudes: [ { name: 'Yehuda', url: 'http://yehuda' }, - { name: 'Alan', url: 'http://alan' } - ] + { name: 'Alan', url: 'http://alan' }, + ], }; expectTemplate('Dudes: {{#dudes}}{{>dude}}{{/dudes}}') @@ -102,50 +102,50 @@ describe('partials', function() { .toCompileTo('Dudes: foo () foo () '); }); - it('partials with string context', function() { + it('partials with string context', function () { expectTemplate('Dudes: {{>dude "dudes"}}') .withPartial('dude', '{{.}}') .toCompileTo('Dudes: dudes'); }); - it('partials with undefined context', function() { + it('partials with undefined context', function () { expectTemplate('Dudes: {{>dude dudes}}') .withPartial('dude', '{{foo}} Empty') .toCompileTo('Dudes: Empty'); }); - it('partials with duplicate parameters', function() { + it('partials with duplicate parameters', function () { expectTemplate('Dudes: {{>dude dudes foo bar=baz}}').toThrow( Error, 'Unsupported number of partial arguments: 2 - 1:7' ); }); - it('partials with parameters', function() { + it('partials with parameters', function () { expectTemplate('Dudes: {{#dudes}}{{> dude others=..}}{{/dudes}}') .withInput({ foo: 'bar', dudes: [ { name: 'Yehuda', url: 'http://yehuda' }, - { name: 'Alan', url: 'http://alan' } - ] + { name: 'Alan', url: 'http://alan' }, + ], }) .withPartial('dude', '{{others.foo}}{{name}} ({{url}}) ') .withMessage('Basic partials output based on current context.') .toCompileTo('Dudes: barYehuda (http://yehuda) barAlan (http://alan) '); }); - it('partial in a partial', function() { + it('partial in a partial', function () { expectTemplate('Dudes: {{#dudes}}{{>dude}}{{/dudes}}') .withInput({ dudes: [ { name: 'Yehuda', url: 'http://yehuda' }, - { name: 'Alan', url: 'http://alan' } - ] + { name: 'Alan', url: 'http://alan' }, + ], }) .withPartials({ dude: '{{name}} {{> url}} ', - url: '{{url}}' + url: '{{url}}', }) .withMessage('Partials are rendered inside of other partials') .toCompileTo( @@ -153,16 +153,16 @@ describe('partials', function() { ); }); - it('rendering undefined partial throws an exception', function() { + it('rendering undefined partial throws an exception', function () { expectTemplate('{{> whatever}}').toThrow( Handlebars.Exception, 'The partial whatever could not be found' ); }); - it('registering undefined partial throws an exception', function() { + it('registering undefined partial throws an exception', function () { shouldThrow( - function() { + function () { var undef; handlebarsEnv.registerPartial('undefined_test', undef); }, @@ -171,14 +171,14 @@ describe('partials', function() { ); }); - it('rendering template partial in vm mode throws an exception', function() { + it('rendering template partial in vm mode throws an exception', function () { expectTemplate('{{> whatever}}').toThrow( Handlebars.Exception, 'The partial whatever could not be found' ); }); - it('rendering function partial in vm mode', function() { + it('rendering function partial in vm mode', function () { function partial(context) { return context.name + ' (' + context.url + ') '; } @@ -186,15 +186,15 @@ describe('partials', function() { .withInput({ dudes: [ { name: 'Yehuda', url: 'http://yehuda' }, - { name: 'Alan', url: 'http://alan' } - ] + { name: 'Alan', url: 'http://alan' }, + ], }) .withPartial('dude', partial) .withMessage('Function partials output based in VM.') .toCompileTo('Dudes: Yehuda (http://yehuda) Alan (http://alan) '); }); - it('GH-14: a partial preceding a selector', function() { + it('GH-14: a partial preceding a selector', function () { expectTemplate('Dudes: {{>dude}} {{anotherDude}}') .withInput({ name: 'Jeepers', anotherDude: 'Creepers' }) .withPartial('dude', '{{name}}') @@ -202,7 +202,7 @@ describe('partials', function() { .toCompileTo('Dudes: Jeepers Creepers'); }); - it('Partials with slash paths', function() { + it('Partials with slash paths', function () { expectTemplate('Dudes: {{> shared/dude}}') .withInput({ name: 'Jeepers', anotherDude: 'Creepers' }) .withPartial('shared/dude', '{{name}}') @@ -210,7 +210,7 @@ describe('partials', function() { .toCompileTo('Dudes: Jeepers'); }); - it('Partials with slash and point paths', function() { + it('Partials with slash and point paths', function () { expectTemplate('Dudes: {{> shared/dude.thing}}') .withInput({ name: 'Jeepers', anotherDude: 'Creepers' }) .withPartial('shared/dude.thing', '{{name}}') @@ -218,7 +218,7 @@ describe('partials', function() { .toCompileTo('Dudes: Jeepers'); }); - it('Global Partials', function() { + it('Global Partials', function () { handlebarsEnv.registerPartial('globalTest', '{{anotherDude}}'); expectTemplate('Dudes: {{> shared/dude}} {{> globalTest}}') @@ -231,10 +231,10 @@ describe('partials', function() { equals(handlebarsEnv.partials.globalTest, undefined); }); - it('Multiple partial registration', function() { + it('Multiple partial registration', function () { handlebarsEnv.registerPartial({ 'shared/dude': '{{name}}', - globalTest: '{{anotherDude}}' + globalTest: '{{anotherDude}}', }); expectTemplate('Dudes: {{> shared/dude}} {{> globalTest}}') @@ -244,7 +244,7 @@ describe('partials', function() { .toCompileTo('Dudes: Jeepers Creepers'); }); - it('Partials with integer path', function() { + it('Partials with integer path', function () { expectTemplate('Dudes: {{> 404}}') .withInput({ name: 'Jeepers', anotherDude: 'Creepers' }) .withPartial(404, '{{name}}') @@ -252,7 +252,7 @@ describe('partials', function() { .toCompileTo('Dudes: Jeepers'); }); - it('Partials with complex path', function() { + it('Partials with complex path', function () { expectTemplate('Dudes: {{> 404/asdf?.bar}}') .withInput({ name: 'Jeepers', anotherDude: 'Creepers' }) .withPartial('404/asdf?.bar', '{{name}}') @@ -260,7 +260,7 @@ describe('partials', function() { .toCompileTo('Dudes: Jeepers'); }); - it('Partials with escaped', function() { + it('Partials with escaped', function () { expectTemplate('Dudes: {{> [+404/asdf?.bar]}}') .withInput({ name: 'Jeepers', anotherDude: 'Creepers' }) .withPartial('+404/asdf?.bar', '{{name}}') @@ -268,7 +268,7 @@ describe('partials', function() { .toCompileTo('Dudes: Jeepers'); }); - it('Partials with string', function() { + it('Partials with string', function () { expectTemplate("Dudes: {{> '+404/asdf?.bar'}}") .withInput({ name: 'Jeepers', anotherDude: 'Creepers' }) .withPartial('+404/asdf?.bar', '{{name}}') @@ -276,19 +276,19 @@ describe('partials', function() { .toCompileTo('Dudes: Jeepers'); }); - it('should handle empty partial', function() { + it('should handle empty partial', function () { expectTemplate('Dudes: {{#dudes}}{{> dude}}{{/dudes}}') .withInput({ dudes: [ { name: 'Yehuda', url: 'http://yehuda' }, - { name: 'Alan', url: 'http://alan' } - ] + { name: 'Alan', url: 'http://alan' }, + ], }) .withPartial('dude', '') .toCompileTo('Dudes: '); }); - it('throw on missing partial', function() { + it('throw on missing partial', function () { var compile = handlebarsEnv.compile; var compileWithPartial = CompilerContext.compileWithPartial; handlebarsEnv.compile = undefined; @@ -300,18 +300,18 @@ describe('partials', function() { CompilerContext.compileWithPartial = compileWithPartial; }); - describe('partial blocks', function() { - it('should render partial block as default', function() { + describe('partial blocks', function () { + it('should render partial block as default', function () { expectTemplate('{{#> dude}}success{{/dude}}').toCompileTo('success'); }); - it('should execute default block with proper context', function() { + it('should execute default block with proper context', function () { expectTemplate('{{#> dude context}}{{value}}{{/dude}}') .withInput({ context: { value: 'success' } }) .toCompileTo('success'); }); - it('should propagate block parameters to default block', function() { + it('should propagate block parameters to default block', function () { expectTemplate( '{{#with context as |me|}}{{#> dude}}{{me.value}}{{/dude}}{{/with}}' ) @@ -319,79 +319,76 @@ describe('partials', function() { .toCompileTo('success'); }); - it('should not use partial block if partial exists', function() { + it('should not use partial block if partial exists', function () { expectTemplate('{{#> dude}}fail{{/dude}}') .withPartials({ dude: 'success' }) .toCompileTo('success'); }); - it('should render block from partial', function() { + it('should render block from partial', function () { expectTemplate('{{#> dude}}success{{/dude}}') .withPartials({ dude: '{{> @partial-block }}' }) .toCompileTo('success'); }); - it('should be able to render the partial-block twice', function() { + it('should be able to render the partial-block twice', function () { expectTemplate('{{#> dude}}success{{/dude}}') .withPartials({ dude: '{{> @partial-block }} {{> @partial-block }}' }) .toCompileTo('success success'); }); - it('should render block from partial with context', function() { + it('should render block from partial with context', function () { expectTemplate('{{#> dude}}{{value}}{{/dude}}') .withInput({ context: { value: 'success' } }) .withPartials({ - dude: '{{#with context}}{{> @partial-block }}{{/with}}' + dude: '{{#with context}}{{> @partial-block }}{{/with}}', }) .toCompileTo('success'); }); - it('should be able to access the @data frame from a partial-block', function() { + it('should be able to access the @data frame from a partial-block', function () { expectTemplate('{{#> dude}}in-block: {{@root/value}}{{/dude}}') .withInput({ value: 'success' }) .withPartials({ - dude: - 'before-block: {{@root/value}} {{> @partial-block }}' + dude: 'before-block: {{@root/value}} {{> @partial-block }}', }) .toCompileTo('before-block: success in-block: success'); }); - it('should allow the #each-helper to be used along with partial-blocks', function() { + it('should allow the #each-helper to be used along with partial-blocks', function () { expectTemplate( '' ) .withInput({ - value: ['a', 'b', 'c'] + value: ['a', 'b', 'c'], }) .withPartials({ - list: - '{{#each .}}{{> @partial-block}}{{/each}}' + list: '{{#each .}}{{> @partial-block}}{{/each}}', }) .toCompileTo( '' ); }); - it('should render block from partial with context (twice)', function() { + it('should render block from partial with context (twice)', function () { expectTemplate('{{#> dude}}{{value}}{{/dude}}') .withInput({ context: { value: 'success' } }) .withPartials({ - dude: - '{{#with context}}{{> @partial-block }} {{> @partial-block }}{{/with}}' + dude: '{{#with context}}{{> @partial-block }} {{> @partial-block }}{{/with}}', }) .toCompileTo('success success'); }); - it('should render block from partial with context', function() { + it('should render block from partial with context', function () { expectTemplate('{{#> dude}}{{../context/value}}{{/dude}}') .withInput({ context: { value: 'success' } }) .withPartials({ - dude: '{{#with context}}{{> @partial-block }}{{/with}}' + dude: '{{#with context}}{{> @partial-block }}{{/with}}', }) .toCompileTo('success'); }); - it('should render block from partial with block params', function() { + it('should render block from partial with block params', function () { expectTemplate( '{{#with context as |me|}}{{#> dude}}{{me.value}}{{/dude}}{{/with}}' ) @@ -400,52 +397,52 @@ describe('partials', function() { .toCompileTo('success'); }); - it('should render nested partial blocks', function() { + it('should render nested partial blocks', function () { expectTemplate('') .withInput({ value: 'success' }) .withPartials({ outer: '{{#> nested}}{{> @partial-block}}{{/nested}}', - nested: '{{> @partial-block}}' + nested: '{{> @partial-block}}', }) .toCompileTo( '' ); }); - it('should render nested partial blocks at different nesting levels', function() { + it('should render nested partial blocks at different nesting levels', function () { expectTemplate('') .withInput({ value: 'success' }) .withPartials({ outer: '{{#> nested}}{{> @partial-block}}{{/nested}}{{> @partial-block}}', - nested: '{{> @partial-block}}' + nested: '{{> @partial-block}}', }) .toCompileTo( '' ); }); - it('should render nested partial blocks at different nesting levels (twice)', function() { + it('should render nested partial blocks at different nesting levels (twice)', function () { expectTemplate('') .withInput({ value: 'success' }) .withPartials({ outer: '{{#> nested}}{{> @partial-block}} {{> @partial-block}}{{/nested}}{{> @partial-block}}+{{> @partial-block}}', - nested: '{{> @partial-block}}' + nested: '{{> @partial-block}}', }) .toCompileTo( '' ); }); - it('should render nested partial blocks (twice at each level)', function() { + it('should render nested partial blocks (twice at each level)', function () { expectTemplate('') .withInput({ value: 'success' }) .withPartials({ outer: '{{#> nested}}{{> @partial-block}} {{> @partial-block}}{{/nested}}', - nested: '{{> @partial-block}}{{> @partial-block}}' + nested: '{{> @partial-block}}{{> @partial-block}}', }) .toCompileTo( '