diff options
author | Kevin Decker <kpdecker@gmail.com> | 2015-04-16 17:12:40 -0500 |
---|---|---|
committer | Kevin Decker <kpdecker@gmail.com> | 2015-04-16 17:12:40 -0500 |
commit | c6ab044fa88d54ace17200b47213c80cdb24ead6 (patch) | |
tree | 2bbdad0c644ba83acc219702500390b874f3ac90 | |
parent | 2a02261a5bc78f246c63dd8d467a12f2c1f63734 (diff) | |
parent | fdc94207a32ad60336a60cdb97b08726d10cae39 (diff) | |
download | handlebars.js-c6ab044fa88d54ace17200b47213c80cdb24ead6.zip handlebars.js-c6ab044fa88d54ace17200b47213c80cdb24ead6.tar.gz handlebars.js-c6ab044fa88d54ace17200b47213c80cdb24ead6.tar.bz2 |
Merge pull request #998 from wycats/babel
Add full support for es6
51 files changed, 1789 insertions, 1542 deletions
diff --git a/.eslintrc b/.eslintrc new file mode 100644 index 0000000..b6420d1 --- /dev/null +++ b/.eslintrc @@ -0,0 +1,186 @@ +{ + "globals": { + "self": false + }, + "env": { + "node": true + }, + "ecmaFeatures": { + "modules": 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-class": 2, + "no-ex-assign": 2, + "no-extra-boolean-cast": 2, + "no-extra-parens": 0, + "no-extra-semi": 2, + "no-func-assign": 2, + + // 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, + "no-reserved-keys": 2, // Important for IE + "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-empty-label": 2, + "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": 2, + "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-wrap-func": 2, + "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"], + "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-line-comment": 2, + "wrap-regex": 1 + } +}
\ No newline at end of file diff --git a/Gruntfile.js b/Gruntfile.js index b739740..cff9945 100644 --- a/Gruntfile.js +++ b/Gruntfile.js @@ -1,16 +1,16 @@ -var childProcess = require('child_process'); - +/*eslint-disable no-process-env */ module.exports = function(grunt) { grunt.initConfig({ pkg: grunt.file.readJSON('package.json'), - jshint: { + eslint: { options: { - jshintrc: '.jshintrc' }, files: [ - 'dist/cjs/**/!(*.min|parser).js' + '*.js', + 'lib/**/!(*.min|parser).js', + 'spec/**/!(*.amd|json2|require).js' ] }, @@ -19,7 +19,7 @@ module.exports = function(grunt) { copy: { dist: { options: { - processContent: function(content, path) { + processContent: function(content) { return grunt.template.process('/*!\n\n <%= pkg.name %> v<%= pkg.version %>\n\n<%= grunt.file.read("LICENSE") %>\n@license\n*/\n') + content; } @@ -41,54 +41,78 @@ module.exports = function(grunt) { } }, - packager: { - global: { - type: 'umd', - export: 'Handlebars', - files: [{ - cwd: 'lib/', - expand: true, - src: ['handlebars*.js'], - dest: 'dist/' - }] + babel: { + options: { + loose: ['es6.modules'] }, - amd: { - type: 'amd', - anonymous: true, + options: { + modules: 'amd' + }, files: [{ expand: true, cwd: 'lib/', - src: '**/!(index).js', + src: '**/!(index|precompiler).js', dest: 'dist/amd/' }] }, cjs: { - type: 'cjs', + options: { + modules: 'common' + }, files: [{ - expand: true, cwd: 'lib/', + expand: true, src: '**/!(index).js', dest: 'dist/cjs/' }] } }, + 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' } + ] + }, + output: { + path: 'dist/', + library: 'Handlebars', + libraryTarget: 'umd' + } + }, + handlebars: { + entry: './lib/handlebars.js', + output: { + filename: 'handlebars.js' + } + }, + runtime: { + entry: './lib/handlebars.runtime.js', + output: { + filename: 'handlebars.runtime.js' + } + } + }, + requirejs: { options: { - optimize: "none", - baseUrl: "dist/amd/" + optimize: 'none', + baseUrl: 'dist/amd/' }, dist: { options: { - name: "handlebars", - out: "dist/handlebars.amd.js" + name: 'handlebars', + out: 'dist/handlebars.amd.js' } }, runtime: { options: { - name: "handlebars.runtime", - out: "dist/handlebars.runtime.amd.js" + name: 'handlebars.runtime', + out: 'dist/handlebars.runtime.amd.js' } } }, @@ -172,18 +196,18 @@ module.exports = function(grunt) { }); // Build a new version of the library - this.registerTask('build', "Builds a distributable version of the current project", [ + this.registerTask('build', 'Builds a distributable version of the current project', [ + 'eslint', 'parser', 'node', - 'globals', - 'jshint']); + 'globals']); - this.registerTask('amd', ['packager:amd', 'requirejs']); - this.registerTask('node', ['packager:cjs']); - this.registerTask('globals', ['packager:global']); + 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', ['amd', 'jshint', 'uglify', 'copy:dist', 'copy:components', 'copy:cdnjs']); + this.registerTask('release', 'Build final packages', ['eslint', 'amd', 'uglify', 'copy:dist', 'copy:components', 'copy:cdnjs']); // Load tasks from npm grunt.loadNpmTasks('grunt-contrib-clean'); @@ -191,11 +215,12 @@ module.exports = function(grunt) { grunt.loadNpmTasks('grunt-contrib-connect'); grunt.loadNpmTasks('grunt-contrib-copy'); grunt.loadNpmTasks('grunt-contrib-requirejs'); - grunt.loadNpmTasks('grunt-contrib-jshint'); grunt.loadNpmTasks('grunt-contrib-uglify'); grunt.loadNpmTasks('grunt-contrib-watch'); + grunt.loadNpmTasks('grunt-babel'); + grunt.loadNpmTasks('grunt-eslint'); grunt.loadNpmTasks('grunt-saucelabs'); - grunt.loadNpmTasks('es6-module-packager'); + grunt.loadNpmTasks('grunt-webpack'); grunt.task.loadTasks('tasks'); diff --git a/lib/handlebars.js b/lib/handlebars.js index 6398a05..38144a3 100644 --- a/lib/handlebars.js +++ b/lib/handlebars.js @@ -1,21 +1,20 @@ -/*globals Handlebars: true */ -import Handlebars from "./handlebars.runtime"; +import Handlebars from './handlebars.runtime'; // Compiler imports -import AST from "./handlebars/compiler/ast"; -import { parser as Parser, parse } from "./handlebars/compiler/base"; -import { Compiler, compile, precompile } from "./handlebars/compiler/compiler"; -import JavaScriptCompiler from "./handlebars/compiler/javascript-compiler"; -import Visitor from "./handlebars/compiler/visitor"; +import AST from './handlebars/compiler/ast'; +import { parser as Parser, parse } from './handlebars/compiler/base'; +import { Compiler, compile, precompile } from './handlebars/compiler/compiler'; +import JavaScriptCompiler from './handlebars/compiler/javascript-compiler'; +import Visitor from './handlebars/compiler/visitor'; var _create = Handlebars.create; -var create = function() { +function create() { var hb = _create(); 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); }; @@ -26,24 +25,23 @@ var create = function() { hb.parse = parse; return hb; -}; +} -Handlebars = create(); -Handlebars.create = create; +var inst = create(); +inst.create = create; -Handlebars.Visitor = Visitor; +inst.Visitor = Visitor; /*jshint -W040 */ /* istanbul ignore next */ -var root = typeof global !== 'undefined' ? global : window, - $Handlebars = root.Handlebars; +var $Handlebars = global.Handlebars; /* istanbul ignore next */ -Handlebars.noConflict = function() { - if (root.Handlebars === Handlebars) { - root.Handlebars = $Handlebars; +inst.noConflict = function() { + if (global.Handlebars === inst) { + global.Handlebars = $Handlebars; } }; -Handlebars['default'] = Handlebars; +inst['default'] = inst; -export default Handlebars; +export default inst; diff --git a/lib/handlebars.runtime.js b/lib/handlebars.runtime.js index ef00e28..c502b5c 100644 --- a/lib/handlebars.runtime.js +++ b/lib/handlebars.runtime.js @@ -1,15 +1,15 @@ -/*globals Handlebars: true */ -module base from "./handlebars/base"; +/*global window */ +import * as base from './handlebars/base'; // Each of these augment the Handlebars object. No need to setup here. // (This is done to easily share code between commonjs and browse envs) -import SafeString from "./handlebars/safe-string"; -import Exception from "./handlebars/exception"; -module Utils from "./handlebars/utils"; -module runtime from "./handlebars/runtime"; +import SafeString from './handlebars/safe-string'; +import Exception from './handlebars/exception'; +import * as Utils from './handlebars/utils'; +import * as runtime from './handlebars/runtime'; // For compatibility and usage outside of module systems, make the Handlebars object a namespace -var create = function() { +function create() { var hb = new base.HandlebarsEnvironment(); Utils.extend(hb, base); @@ -24,7 +24,7 @@ var create = function() { }; return hb; -}; +} var Handlebars = create(); Handlebars.create = create; diff --git a/lib/handlebars/base.js b/lib/handlebars/base.js index 293d5ea..771cb9c 100644 --- a/lib/handlebars/base.js +++ b/lib/handlebars/base.js @@ -1,7 +1,7 @@ -module Utils from "./utils"; -import Exception from "./exception"; +import * as Utils from './utils'; +import Exception from './exception'; -export var VERSION = "3.0.1"; +export var VERSION = '3.0.1'; export var COMPILER_REVISION = 6; export var REVISION_CHANGES = { @@ -45,7 +45,7 @@ HandlebarsEnvironment.prototype = { registerPartial: function(name, partial) { if (toString.call(name) === objectType) { - Utils.extend(this.partials, name); + Utils.extend(this.partials, name); } else { if (typeof partial === 'undefined') { throw new Exception('Attempting to register a partial as undefined'); @@ -60,12 +60,12 @@ HandlebarsEnvironment.prototype = { function registerDefaultHelpers(instance) { instance.registerHelper('helperMissing', function(/* [args, ]options */) { - if(arguments.length === 1) { + if (arguments.length === 1) { // A missing field in a {{foo}} constuct. return undefined; } else { // Someone is actually trying to call something, blow up. - throw new Exception("Missing helper: '" + arguments[arguments.length-1].name + "'"); + throw new Exception('Missing helper: "' + arguments[arguments.length - 1].name + '"'); } }); @@ -73,12 +73,12 @@ function registerDefaultHelpers(instance) { var inverse = options.inverse, fn = options.fn; - if(context === true) { + if (context === true) { return fn(this); - } else if(context === false || context == null) { + } else if (context === false || context == null) { return inverse(this); } else if (isArray(context)) { - if(context.length > 0) { + if (context.length > 0) { if (options.ids) { options.ids = [options.name]; } @@ -104,7 +104,7 @@ function registerDefaultHelpers(instance) { } var fn = options.fn, inverse = options.inverse; - var i = 0, ret = "", data; + var i = 0, ret = '', data; var contextPath; if (options.data && options.ids) { @@ -117,51 +117,51 @@ function registerDefaultHelpers(instance) { data = createFrame(options.data); } - function execIteration(key, i, last) { + function execIteration(field, index, last) { if (data) { - data.key = key; - data.index = i; - data.first = i === 0; - data.last = !!last; + data.key = field; + data.index = index; + data.first = index === 0; + data.last = !!last; if (contextPath) { - data.contextPath = contextPath + key; + data.contextPath = contextPath + field; } } - ret = ret + fn(context[key], { + ret = ret + fn(context[field], { data: data, - blockParams: Utils.blockParams([context[key], key], [contextPath + key, null]) + blockParams: Utils.blockParams([context[field], field], [contextPath + field, null]) }); } - if(context && typeof context === 'object') { + if (context && typeof context === 'object') { if (isArray(context)) { - for(var j = context.length; i<j; i++) { - execIteration(i, i, i === context.length-1); + for (var j = context.length; i < j; i++) { + execIteration(i, i, i === context.length - 1); } } else { var priorKey; - for(var key in context) { - if(context.hasOwnProperty(key)) { + for (var key in context) { + if (context.hasOwnProperty(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 itermediate keys array. + // an itermediate keys array. if (priorKey) { - execIteration(priorKey, i-1); + execIteration(priorKey, i - 1); } priorKey = key; i++; } } if (priorKey) { - execIteration(priorKey, i-1, true); + execIteration(priorKey, i - 1, true); } } } - if(i === 0){ + if (i === 0) { ret = inverse(this); } @@ -194,7 +194,7 @@ function registerDefaultHelpers(instance) { if (options.data && options.ids) { var data = createFrame(options.data); data.contextPath = Utils.appendContextPath(options.data.contextPath, options.ids[0]); - options = {data:data}; + options = {data: data}; } return fn(context, options); @@ -227,15 +227,15 @@ export var logger = { log: function(level, message) { if (typeof console !== 'undefined' && logger.level <= level) { var method = logger.methodMap[level]; - (console[method] || console.log).call(console, message); + (console[method] || console.log).call(console, message); // eslint-disable-line no-console } } }; export var log = logger.log; -export var createFrame = function(object) { +export function createFrame(object) { var frame = Utils.extend({}, object); frame._parent = object; return frame; -}; +} diff --git a/lib/handlebars/compiler/ast.js b/lib/handlebars/compiler/ast.js index e5904c6..1ecf59b 100644 --- a/lib/handlebars/compiler/ast.js +++ b/lib/handlebars/compiler/ast.js @@ -27,8 +27,8 @@ var AST = { this.path = path; this.params = params || []; this.hash = hash; - this.program = program; - this.inverse = inverse; + this.program = program; + this.inverse = inverse; this.openStrip = openStrip; this.inverseStrip = inverseStrip; @@ -76,8 +76,8 @@ var AST = { this.data = data; this.original = original; - this.parts = parts; - this.depth = depth; + this.parts = parts; + this.depth = depth; }, StringLiteral: function(string, locInfo) { @@ -130,7 +130,6 @@ var AST = { // a mustache is definitely a helper if: // * it is an eligible helper, and // * it has at least one parameter or hash segment - // TODO: Make these public utility methods helperExpression: function(node) { return !!(node.type === 'SubExpression' || node.params.length || node.hash); }, diff --git a/lib/handlebars/compiler/base.js b/lib/handlebars/compiler/base.js index 167b844..02e174f 100644 --- a/lib/handlebars/compiler/base.js +++ b/lib/handlebars/compiler/base.js @@ -1,8 +1,8 @@ -import parser from "./parser"; -import AST from "./ast"; -import WhitespaceControl from "./whitespace-control"; -module Helpers from "./helpers"; -import { extend } from "../utils"; +import parser from './parser'; +import AST from './ast'; +import WhitespaceControl from './whitespace-control'; +import * as Helpers from './helpers'; +import { extend } from '../utils'; export { parser }; diff --git a/lib/handlebars/compiler/code-gen.js b/lib/handlebars/compiler/code-gen.js index 92020f0..0c40e00 100644 --- a/lib/handlebars/compiler/code-gen.js +++ b/lib/handlebars/compiler/code-gen.js @@ -1,4 +1,5 @@ -import {isArray} from "../utils"; +/*global define */ +import {isArray} from '../utils'; var SourceNode; @@ -56,7 +57,7 @@ function castChunk(chunk, codeGen, loc) { return ret; } else if (typeof chunk === 'boolean' || typeof chunk === 'number') { // Handle primitives that the SourceNode will throw up on - return chunk+''; + return chunk + ''; } return chunk; } @@ -90,7 +91,7 @@ CodeGen.prototype = { }, empty: function(loc) { - loc = loc || this.currentLocation || {start:{}}; + loc = loc || this.currentLocation || {start: {}}; return new SourceNode(loc.start.line, loc.start.column, this.srcFile); }, wrap: function(chunk, loc) { @@ -98,7 +99,7 @@ CodeGen.prototype = { return chunk; } - loc = loc || this.currentLocation || {start:{}}; + loc = loc || this.currentLocation || {start: {}}; chunk = castChunk(chunk, this, loc); return new SourceNode(loc.start.line, loc.start.column, this.srcFile, chunk); diff --git a/lib/handlebars/compiler/compiler.js b/lib/handlebars/compiler/compiler.js index a39082d..a9bfc85 100644 --- a/lib/handlebars/compiler/compiler.js +++ b/lib/handlebars/compiler/compiler.js @@ -1,6 +1,6 @@ -import Exception from "../exception"; -import {isArray, indexOf} from "../utils"; -import AST from "./ast"; +import Exception from '../exception'; +import {isArray, indexOf} from '../utils'; +import AST from './ast'; var slice = [].slice; @@ -67,7 +67,9 @@ Compiler.prototype = { }; if (knownHelpers) { for (var name in knownHelpers) { - options.knownHelpers[name] = knownHelpers[name]; + if (name in knownHelpers) { + options.knownHelpers[name] = knownHelpers[name]; + } } } @@ -75,7 +77,7 @@ Compiler.prototype = { }, compileProgram: function(program) { - var result = new this.compiler().compile(program, this.options); + var result = new this.compiler().compile(program, this.options); // eslint-disable-line new-cap var guid = this.guid++; this.usePartial = this.usePartial || result.usePartial; @@ -97,7 +99,7 @@ Compiler.prototype = { this.options.blockParams.unshift(program.blockParams); var body = program.body; - for(var i=0, l=body.length; i<l; i++) { + for (var i = 0, l = body.length; i < l; i++) { this.accept(body[i]); } @@ -174,9 +176,9 @@ Compiler.prototype = { }, MustacheStatement: function(mustache) { - this.SubExpression(mustache); + this.SubExpression(mustache); // eslint-disable-line new-cap - if(mustache.escaped && !this.options.noEscape) { + if (mustache.escaped && !this.options.noEscape) { this.opcode('appendEscaped'); } else { this.opcode('append'); @@ -231,7 +233,7 @@ Compiler.prototype = { if (this.options.knownHelpers[name]) { this.opcode('invokeKnownHelper', params.length, name); } else if (this.options.knownHelpersOnly) { - throw new Exception("You specified knownHelpersOnly, but used the unknown helper " + name, sexpr); + throw new Exception('You specified knownHelpersOnly, but used the unknown helper ' + name, sexpr); } else { path.falsy = true; @@ -250,7 +252,7 @@ Compiler.prototype = { if (blockParamId) { this.opcode('lookupBlockParam', blockParamId, path.parts); - } else if (!name) { + } else if (!name) { // Context reference, i.e. `{{foo .}}` or `{{foo ..}}` this.opcode('pushContext'); } else if (path.data) { @@ -286,7 +288,7 @@ Compiler.prototype = { this.opcode('pushHash'); - for (i=0, l=pairs.length; i<l; i++) { + for (i = 0, l = pairs.length; i < l; i++) { this.pushParam(pairs[i].value); } while (i--) { @@ -336,13 +338,17 @@ Compiler.prototype = { } } - if (isHelper) { return 'helper'; } - else if (isEligible) { return 'ambiguous'; } - else { return 'simple'; } + if (isHelper) { + return 'helper'; + } else if (isEligible) { + return 'ambiguous'; + } else { + return 'simple'; + } }, pushParams: function(params) { - for(var i=0, l=params.length; i<l; i++) { + for (var i = 0, l = params.length; i < l; i++) { this.pushParam(params[i]); } }, @@ -357,7 +363,7 @@ Compiler.prototype = { .replace(/\//g, '.'); } - if(val.depth) { + if (val.depth) { this.addDepth(val.depth); } this.opcode('getContext', val.depth || 0); @@ -421,7 +427,7 @@ 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); + throw new Exception('You must pass a string or Handlebars AST to Handlebars.precompile. You passed ' + input); } options = options || {}; @@ -439,7 +445,7 @@ export function precompile(input, options, env) { 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); + throw new Exception('You must pass a string or Handlebars AST to Handlebars.compile. You passed ' + input); } options = options || {}; @@ -461,17 +467,17 @@ export function compile(input, options, env) { } // Template is only compiled on first use and cached after that point. - var ret = function(context, options) { + function ret(context, execOptions) { if (!compiled) { compiled = compileInput(); } - return compiled.call(this, context, options); - }; - ret._setup = function(options) { + return compiled.call(this, context, execOptions); + } + ret._setup = function(setupOptions) { if (!compiled) { compiled = compileInput(); } - return compiled._setup(options); + return compiled._setup(setupOptions); }; ret._child = function(i, data, blockParams, depths) { if (!compiled) { @@ -502,6 +508,6 @@ function transformLiteralToPath(sexpr) { var literal = sexpr.path; // Casting to string here to make false and 0 literal values play nicely with the rest // of the system. - sexpr.path = new AST.PathExpression(false, 0, [literal.original+''], literal.original+'', literal.loc); + sexpr.path = new AST.PathExpression(false, 0, [literal.original + ''], literal.original + '', literal.loc); } } diff --git a/lib/handlebars/compiler/helpers.js b/lib/handlebars/compiler/helpers.js index 4a502d8..7f784ad 100644 --- a/lib/handlebars/compiler/helpers.js +++ b/lib/handlebars/compiler/helpers.js @@ -1,4 +1,4 @@ -import Exception from "../exception"; +import Exception from '../exception'; export function SourceLocation(source, locInfo) { this.source = source; @@ -23,7 +23,7 @@ export function id(token) { export function stripFlags(open, close) { return { open: open.charAt(2) === '~', - close: close.charAt(close.length-3) === '~' + close: close.charAt(close.length - 3) === '~' }; } @@ -41,7 +41,7 @@ export function preparePath(data, parts, locInfo) { depth = 0, depthString = ''; - for(var i=0,l=parts.length; i<l; i++) { + for (var i = 0, l = parts.length; i < l; i++) { var part = parts[i].part, // If we have [] syntax then we do not treat path references as operators, // i.e. foo.[this] resolves to approximately context.foo['this'] diff --git a/lib/handlebars/compiler/javascript-compiler.js b/lib/handlebars/compiler/javascript-compiler.js index a027edb..e278162 100644 --- a/lib/handlebars/compiler/javascript-compiler.js +++ b/lib/handlebars/compiler/javascript-compiler.js @@ -1,7 +1,7 @@ -import { COMPILER_REVISION, REVISION_CHANGES } from "../base"; -import Exception from "../exception"; -import {isArray} from "../utils"; -import CodeGen from "./code-gen"; +import { COMPILER_REVISION, REVISION_CHANGES } from '../base'; +import Exception from '../exception'; +import {isArray} from '../utils'; +import CodeGen from './code-gen'; function Literal(value) { this.value = value; @@ -14,7 +14,7 @@ JavaScriptCompiler.prototype = { // alternative compiled forms for name lookup and buffering semantics nameLookup: function(parent, name /* , type*/) { if (JavaScriptCompiler.isValidJavaScriptVariableName(name)) { - return [parent, ".", name]; + return [parent, '.', name]; } else { return [parent, "['", name, "']"]; } @@ -50,7 +50,7 @@ JavaScriptCompiler.prototype = { }, initializeBuffer: function() { - return this.quotedString(""); + return this.quotedString(''); }, // END PUBLIC API @@ -169,8 +169,8 @@ JavaScriptCompiler.prototype = { var varDeclarations = ''; var locals = this.stackVars.concat(this.registers.list); - if(locals.length > 0) { - varDeclarations += ", " + locals.join(", "); + if (locals.length > 0) { + varDeclarations += ', ' + locals.join(', '); } // Generate minimizer alias mappings @@ -180,7 +180,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. var aliasCount = 0; - for (var alias in this.aliases) { + for (var alias in this.aliases) { // eslint-disable-line guard-for-in var node = this.aliases[alias]; if (this.aliases.hasOwnProperty(alias) && node.children && node.referenceCount > 1) { @@ -189,7 +189,7 @@ JavaScriptCompiler.prototype = { } } - var params = ["depth0", "helpers", "partials", "data"]; + var params = ['depth0', 'helpers', 'partials', 'data']; if (this.useBlockParams || this.useDepths) { params.push('blockParams'); @@ -252,7 +252,7 @@ JavaScriptCompiler.prototype = { this.source.push('return "";'); } } else { - varDeclarations += ", buffer = " + (appendFirst ? '' : this.initializeBuffer()); + varDeclarations += ', buffer = ' + (appendFirst ? '' : this.initializeBuffer()); if (bufferStart) { bufferStart.prepend('return buffer + '); @@ -446,6 +446,7 @@ JavaScriptCompiler.prototype = { var len = parts.length; for (; i < len; i++) { + /*eslint-disable no-loop-func */ this.replaceStack(function(current) { var lookup = this.nameLookup(current, parts[i], type); // We want to ensure that zero and false are handled properly if the context (falsy flag) @@ -457,6 +458,7 @@ JavaScriptCompiler.prototype = { return [' && ', lookup]; } }); + /*eslint-enable no-loop-func */ } }, @@ -633,7 +635,7 @@ JavaScriptCompiler.prototype = { '(', lookup, (helper.paramsInit ? ['),(', helper.paramsInit] : []), '),', '(typeof helper === ', this.aliasable('"function"'), ' ? ', - this.source.functionCall('helper','call', helper.callParams), ' : helper))' + this.source.functionCall('helper', 'call', helper.callParams), ' : helper))' ]); }, @@ -728,9 +730,9 @@ JavaScriptCompiler.prototype = { compileChildren: function(environment, options) { var children = environment.children, child, compiler; - for(var i=0, l=children.length; i<l; i++) { + for (var i = 0, l = children.length; i < l; i++) { child = children[i]; - compiler = new this.compiler(); + compiler = new this.compiler(); // eslint-disable-line new-cap var index = this.matchExistingProgram(child); @@ -777,7 +779,7 @@ JavaScriptCompiler.prototype = { }, useRegister: function(name) { - if(!this.registers[name]) { + if (!this.registers[name]) { this.registers[name] = true; this.registers.list.push(name); } @@ -849,11 +851,11 @@ JavaScriptCompiler.prototype = { incrStack: function() { this.stackSlot++; - if(this.stackSlot > this.stackVars.length) { this.stackVars.push("stack" + this.stackSlot); } + if (this.stackSlot > this.stackVars.length) { this.stackVars.push('stack' + this.stackSlot); } return this.topStackName(); }, topStackName: function() { - return "stack" + this.stackSlot; + return 'stack' + this.stackSlot; }, flushInline: function() { var inlineStack = this.inlineStack; @@ -1019,33 +1021,35 @@ JavaScriptCompiler.prototype = { }; -var reservedWords = ( - "break else new var" + - " case finally return void" + - " catch for switch while" + - " continue function this with" + - " default if throw" + - " delete in try" + - " do instanceof typeof" + - " abstract enum int short" + - " boolean export interface static" + - " byte extends long super" + - " char final native synchronized" + - " class float package throws" + - " const goto private transient" + - " debugger implements protected volatile" + - " double import public let yield await" + - " null true false" -).split(" "); - -var compilerWords = JavaScriptCompiler.RESERVED_WORDS = {}; - -for(var i=0, l=reservedWords.length; i<l; i++) { - compilerWords[reservedWords[i]] = true; -} +(function() { + var reservedWords = ( + 'break else new var' + + ' case finally return void' + + ' catch for switch while' + + ' continue function this with' + + ' default if throw' + + ' delete in try' + + ' do instanceof typeof' + + ' abstract enum int short' + + ' boolean export interface static' + + ' byte extends long super' + + ' char final native synchronized' + + ' class float package throws' + + ' const goto private transient' + + ' debugger implements protected volatile' + + ' double import public let yield await' + + ' null true false' + ).split(' '); + + var compilerWords = JavaScriptCompiler.RESERVED_WORDS = {}; + + for (var i = 0, l = reservedWords.length; i < l; i++) { + compilerWords[reservedWords[i]] = true; + } +}()); JavaScriptCompiler.isValidJavaScriptVariableName = function(name) { - return !JavaScriptCompiler.RESERVED_WORDS[name] && /^[a-zA-Z_$][0-9a-zA-Z_$]*$/.test(name); + return !JavaScriptCompiler.RESERVED_WORDS[name] && (/^[a-zA-Z_$][0-9a-zA-Z_$]*$/).test(name); }; function strictLookup(requireTerminal, compiler, parts, type) { diff --git a/lib/handlebars/compiler/printer.js b/lib/handlebars/compiler/printer.js index dcc73c3..5c708a1 100644 --- a/lib/handlebars/compiler/printer.js +++ b/lib/handlebars/compiler/printer.js @@ -1,4 +1,5 @@ -import Visitor from "./visitor"; +/*eslint-disable new-cap */ +import Visitor from './visitor'; export function print(ast) { return new PrintVisitor().accept(ast); @@ -11,13 +12,13 @@ export function PrintVisitor() { PrintVisitor.prototype = new Visitor(); PrintVisitor.prototype.pad = function(string) { - var out = ""; + var out = ''; - for(var i=0,l=this.padding; i<l; i++) { - out = out + " "; + for (var i = 0, l = this.padding; i < l; i++) { + out = out + ' '; } - out = out + string + "\n"; + out = out + string + '\n'; return out; }; @@ -28,14 +29,14 @@ PrintVisitor.prototype.Program = function(program) { if (program.blockParams) { var blockParams = 'BLOCK PARAMS: ['; - for(i=0, l=program.blockParams.length; i<l; i++) { + for (i = 0, l = program.blockParams.length; i < l; i++) { blockParams += ' ' + program.blockParams[i]; } blockParams += ' ]'; out += this.pad(blockParams); } - for(i=0, l=body.length; i<l; i++) { + for (i = 0, l = body.length; i < l; i++) { out = out + this.accept(body[i]); } @@ -49,7 +50,7 @@ PrintVisitor.prototype.MustacheStatement = function(mustache) { }; PrintVisitor.prototype.BlockStatement = function(block) { - var out = ""; + var out = ''; out = out + this.pad('BLOCK:'); this.padding++; @@ -75,7 +76,7 @@ PrintVisitor.prototype.BlockStatement = function(block) { PrintVisitor.prototype.PartialStatement = function(partial) { var content = 'PARTIAL:' + partial.name.original; - if(partial.params[0]) { + if (partial.params[0]) { content += ' ' + this.accept(partial.params[0]); } if (partial.hash) { @@ -95,15 +96,15 @@ PrintVisitor.prototype.CommentStatement = function(comment) { PrintVisitor.prototype.SubExpression = function(sexpr) { var params = sexpr.params, paramStrings = [], hash; - for(var i=0, l=params.length; i<l; i++) { + for (var i = 0, l = params.length; i < l; i++) { paramStrings.push(this.accept(params[i])); } - params = "[" + paramStrings.join(", ") + "]"; + params = '[' + paramStrings.join(', ') + ']'; - hash = sexpr.hash ? " " + this.accept(sexpr.hash) : ""; + hash = sexpr.hash ? ' ' + this.accept(sexpr.hash) : ''; - return this.accept(sexpr.path) + " " + params + hash; + return this.accept(sexpr.path) + ' ' + params + hash; }; PrintVisitor.prototype.PathExpression = function(id) { @@ -117,11 +118,11 @@ PrintVisitor.prototype.StringLiteral = function(string) { }; PrintVisitor.prototype.NumberLiteral = function(number) { - return "NUMBER{" + number.value + "}"; + return 'NUMBER{' + number.value + '}'; }; PrintVisitor.prototype.BooleanLiteral = function(bool) { - return "BOOLEAN{" + bool.value + "}"; + return 'BOOLEAN{' + bool.value + '}'; }; PrintVisitor.prototype.UndefinedLiteral = function() { @@ -136,7 +137,7 @@ PrintVisitor.prototype.Hash = function(hash) { var pairs = hash.pairs; var joinedPairs = []; - for (var i=0, l=pairs.length; i<l; i++) { + for (var i = 0, l = pairs.length; i < l; i++) { joinedPairs.push(this.accept(pairs[i])); } @@ -145,3 +146,4 @@ PrintVisitor.prototype.Hash = function(hash) { PrintVisitor.prototype.HashPair = function(pair) { return pair.key + '=' + this.accept(pair.value); }; +/*eslint-enable new-cap */ diff --git a/lib/handlebars/compiler/visitor.js b/lib/handlebars/compiler/visitor.js index b45b268..692a511 100644 --- a/lib/handlebars/compiler/visitor.js +++ b/lib/handlebars/compiler/visitor.js @@ -1,5 +1,5 @@ -import Exception from "../exception"; -import AST from "./ast"; +import Exception from '../exception'; +import AST from './ast'; function Visitor() { this.parents = []; diff --git a/lib/handlebars/compiler/whitespace-control.js b/lib/handlebars/compiler/whitespace-control.js index 9786612..aabe45a 100644 --- a/lib/handlebars/compiler/whitespace-control.js +++ b/lib/handlebars/compiler/whitespace-control.js @@ -1,4 +1,4 @@ -import Visitor from "./visitor"; +import Visitor from './visitor'; function WhitespaceControl() { } @@ -38,7 +38,7 @@ WhitespaceControl.prototype.Program = function(program) { // If we are on a standalone node, save the indent info for partials if (current.type === 'PartialStatement') { // Pull out the whitespace from the final line - current.indent = (/([ \t]+$)/).exec(body[i-1].original)[1]; + current.indent = (/([ \t]+$)/).exec(body[i - 1].original)[1]; } } } @@ -73,7 +73,7 @@ WhitespaceControl.prototype.BlockStatement = function(block) { // Walk the inverse chain to find the last inverse that is actually in the chain. while (lastInverse.chained) { - lastInverse = lastInverse.body[lastInverse.body.length-1].program; + lastInverse = lastInverse.body[lastInverse.body.length - 1].program; } } @@ -108,14 +108,11 @@ WhitespaceControl.prototype.BlockStatement = function(block) { // Find standalone else statments if (isPrevWhitespace(program.body) && isNextWhitespace(firstInverse.body)) { - omitLeft(program.body); omitRight(firstInverse.body); } - } else { - if (block.closeStrip.open) { - omitLeft(program.body, null, true); - } + } else if (block.closeStrip.open) { + omitLeft(program.body, null, true); } return strip; @@ -125,7 +122,7 @@ WhitespaceControl.prototype.MustacheStatement = function(mustache) { return mustache.strip; }; -WhitespaceControl.prototype.PartialStatement = +WhitespaceControl.prototype.PartialStatement = WhitespaceControl.prototype.CommentStatement = function(node) { /* istanbul ignore next */ var strip = node.strip || {}; @@ -144,8 +141,8 @@ function isPrevWhitespace(body, i, isRoot) { // Nodes that end with newlines are considered whitespace (but are special // cased for strip operations) - var prev = body[i-1], - sibling = body[i-2]; + var prev = body[i - 1], + sibling = body[i - 2]; if (!prev) { return isRoot; } @@ -159,8 +156,8 @@ function isNextWhitespace(body, i, isRoot) { i = -1; } - var next = body[i+1], - sibling = body[i+2]; + var next = body[i + 1], + sibling = body[i + 2]; if (!next) { return isRoot; } diff --git a/lib/handlebars/runtime.js b/lib/handlebars/runtime.js index 4e8c33a..f1839aa 100644 --- a/lib/handlebars/runtime.js +++ b/lib/handlebars/runtime.js @@ -1,6 +1,6 @@ -module Utils from "./utils"; -import Exception from "./exception"; -import { COMPILER_REVISION, REVISION_CHANGES, createFrame } from "./base"; +import * as Utils from './utils'; +import Exception from './exception'; +import { COMPILER_REVISION, REVISION_CHANGES, createFrame } from './base'; export function checkRevision(compilerInfo) { var compilerRevision = compilerInfo && compilerInfo[0] || 1, @@ -10,12 +10,12 @@ export function checkRevision(compilerInfo) { if (compilerRevision < currentRevision) { var runtimeVersions = REVISION_CHANGES[currentRevision], compilerVersions = REVISION_CHANGES[compilerRevision]; - throw new Exception("Template was precompiled with an older version of Handlebars than the current runtime. "+ - "Please update your precompiler to a newer version ("+runtimeVersions+") or downgrade your runtime to an older version ("+compilerVersions+")."); + throw new Exception('Template was precompiled with an older version of Handlebars than the current runtime. ' + + 'Please update your precompiler to a newer version (' + runtimeVersions + ') or downgrade your runtime to an older version (' + compilerVersions + ').'); } else { // Use the embedded version info since the runtime doesn't know about this revision yet - throw new Exception("Template was precompiled with a newer version of Handlebars than the current runtime. "+ - "Please update your runtime to a newer version ("+compilerInfo[1]+")."); + throw new Exception('Template was precompiled with a newer version of Handlebars than the current runtime. ' + + 'Please update your runtime to a newer version (' + compilerInfo[1] + ').'); } } } @@ -25,7 +25,7 @@ export function checkRevision(compilerInfo) { export function template(templateSpec, env) { /* istanbul ignore next */ if (!env) { - throw new Exception("No environment passed to template"); + throw new Exception('No environment passed to template'); } if (!templateSpec || !templateSpec.main) { throw new Exception('Unknown template object: ' + typeof templateSpec); @@ -35,7 +35,7 @@ export function template(templateSpec, env) { // for external users to override these as psuedo-supported APIs. env.VM.checkRevision(templateSpec.compiler); - var invokePartialWrapper = function(partial, context, options) { + function invokePartialWrapper(partial, context, options) { if (options.hash) { context = Utils.extend({}, context, options.hash); } @@ -61,9 +61,9 @@ export function template(templateSpec, env) { } return result; } else { - throw new Exception("The partial " + options.name + " could not be compiled when running in runtime-only mode"); + throw new Exception('The partial ' + options.name + ' could not be compiled when running in runtime-only mode'); } - }; + } // Just add water var container = { @@ -97,34 +97,34 @@ export function template(templateSpec, env) { var programWrapper = this.programs[i], fn = this.fn(i); if (data || depths || blockParams || declaredBlockParams) { - programWrapper = program(this, i, fn, data, declaredBlockParams, blockParams, depths); + programWrapper = wrapProgram(this, i, fn, data, declaredBlockParams, blockParams, depths); } else if (!programWrapper) { - programWrapper = this.programs[i] = program(this, i, fn); + programWrapper = this.programs[i] = wrapProgram(this, i, fn); } return programWrapper; }, - data: function(data, depth) { - while (data && depth--) { - data = data._parent; + data: function(value, depth) { + while (value && depth--) { + value = value._parent; } - return data; + return value; }, merge: function(param, common) { - var ret = param || common; + var obj = param || common; if (param && common && (param !== common)) { - ret = Utils.extend({}, common, param); + obj = Utils.extend({}, common, param); } - return ret; + return obj; }, noop: env.VM.noop, compilerInfo: templateSpec.compiler }; - var ret = function(context, options) { + function ret(context, options) { options = options || {}; var data = options.data; @@ -139,7 +139,7 @@ export function template(templateSpec, env) { } return templateSpec.main.call(container, context, container.helpers, container.partials, data, blockParams, depths); - }; + } ret.isTop = true; ret._setup = function(options) { @@ -163,13 +163,13 @@ export function template(templateSpec, env) { throw new Exception('must pass parent depths'); } - return program(container, i, templateSpec[i], data, 0, blockParams, depths); + return wrapProgram(container, i, templateSpec[i], data, 0, blockParams, depths); }; return ret; } -export function program(container, i, fn, data, declaredBlockParams, blockParams, depths) { - var prog = function(context, options) { +export function wrapProgram(container, i, fn, data, declaredBlockParams, blockParams, depths) { + function prog(context, options) { options = options || {}; return fn.call(container, @@ -178,7 +178,7 @@ export function program(container, i, fn, data, declaredBlockParams, blockParams options.data || data, blockParams && [options.blockParams].concat(blockParams), depths && [context].concat(depths)); - }; + } prog.program = i; prog.depth = depths ? depths.length : 0; prog.blockParams = declaredBlockParams || 0; @@ -199,14 +199,14 @@ export function resolvePartial(partial, context, options) { export function invokePartial(partial, context, options) { options.partial = true; - if(partial === undefined) { - throw new Exception("The partial " + options.name + " could not be found"); - } else if(partial instanceof Function) { + if (partial === undefined) { + throw new Exception('The partial ' + options.name + ' could not be found'); + } else if (partial instanceof Function) { return partial(context, options); } } -export function noop() { return ""; } +export function noop() { return ''; } function initData(context, data) { if (!data || !('root' in data)) { diff --git a/lib/handlebars/safe-string.js b/lib/handlebars/safe-string.js index a6b8ecf..4680194 100644 --- a/lib/handlebars/safe-string.js +++ b/lib/handlebars/safe-string.js @@ -4,7 +4,7 @@ function SafeString(string) { } SafeString.prototype.toString = SafeString.prototype.toHTML = function() { - return "" + this.string; + return '' + this.string; }; export default SafeString; diff --git a/lib/handlebars/utils.js b/lib/handlebars/utils.js index 41495e1..07e9b77 100644 --- a/lib/handlebars/utils.js +++ b/lib/handlebars/utils.js @@ -1,11 +1,11 @@ /*jshint -W004 */ var escape = { - "&": "&", - "<": "<", - ">": ">", - '"': """, - "'": "'", - "`": "`" + '&': '&', + '<': '<', + '>': '>', + '"': '"', + "'": ''', + '`': '`' }; var badChars = /[&<>"'`]/g; @@ -31,6 +31,7 @@ export var toString = Object.prototype.toString; // Sourced from lodash // https://github.com/bestiejs/lodash/blob/master/LICENSE.txt +/*eslint-disable func-style */ var isFunction = function(value) { return typeof value === 'function'; }; @@ -42,6 +43,7 @@ if (isFunction(/x/)) { }; } export var isFunction; +/*eslint-enable func-style */ /* istanbul ignore next */ export var isArray = Array.isArray || function(value) { diff --git a/lib/index.js b/lib/index.js index 8213d14..ac55967 100644 --- a/lib/index.js +++ b/lib/index.js @@ -3,7 +3,7 @@ // var local = handlebars.create(); -var handlebars = require('../dist/cjs/handlebars')["default"]; +var handlebars = require('../dist/cjs/handlebars')['default']; var printer = require('../dist/cjs/handlebars/compiler/printer'); handlebars.PrintVisitor = printer.PrintVisitor; @@ -12,13 +12,13 @@ handlebars.print = printer.print; module.exports = handlebars; // Publish a Node.js require() handler for .handlebars and .hbs files +function extension(module, filename) { + var fs = require('fs'); + var templateString = fs.readFileSync(filename, 'utf8'); + module.exports = handlebars.compile(templateString); +} /* istanbul ignore else */ if (typeof require !== 'undefined' && require.extensions) { - var extension = function(module, filename) { - var fs = require("fs"); - var templateString = fs.readFileSync(filename, "utf8"); - module.exports = handlebars.compile(templateString); - }; - require.extensions[".handlebars"] = extension; - require.extensions[".hbs"] = extension; + require.extensions['.handlebars'] = extension; + require.extensions['.hbs'] = extension; } diff --git a/lib/precompiler.js b/lib/precompiler.js index f673479..f0955e7 100644 --- a/lib/precompiler.js +++ b/lib/precompiler.js @@ -1,4 +1,4 @@ - +/*eslint-disable no-console */ var fs = require('fs'), Handlebars = require('./index'), basename = require('path').basename, @@ -70,10 +70,10 @@ module.exports.cli = function(opts) { stat = fs.statSync(path); if (stat.isDirectory()) { fs.readdirSync(template).map(function(file) { - var path = template + '/' + file; + var childPath = template + '/' + file; - if (extension.test(path) || fs.statSync(path).isDirectory()) { - processTemplate(path, root || template); + if (extension.test(childPath) || fs.statSync(childPath).isDirectory()) { + processTemplate(childPath, root || template); } }); } else { @@ -99,7 +99,7 @@ module.exports.cli = function(opts) { if (!root) { template = basename(template); } else if (template.indexOf(root) === 0) { - template = template.substring(root.length+1); + template = template.substring(root.length + 1); } template = template.replace(extension, ''); @@ -114,12 +114,12 @@ module.exports.cli = function(opts) { if (opts.simple) { output.add([precompiled, '\n']); } else if (opts.partial) { - if(opts.amd && (opts.templates.length == 1 && !fs.statSync(opts.templates[0]).isDirectory())) { + if (opts.amd && (opts.templates.length == 1 && !fs.statSync(opts.templates[0]).isDirectory())) { output.add('return '); } output.add(['Handlebars.partials[\'', template, '\'] = template(', precompiled, ');\n']); } else { - if(opts.amd && (opts.templates.length == 1 && !fs.statSync(opts.templates[0]).isDirectory())) { + if (opts.amd && (opts.templates.length == 1 && !fs.statSync(opts.templates[0]).isDirectory())) { output.add('return '); } output.add(['templates[\'', template, '\'] = template(', precompiled, ');\n']); @@ -134,8 +134,8 @@ module.exports.cli = function(opts) { // Output the content if (!opts.simple) { if (opts.amd) { - if(opts.templates.length > 1 || (opts.templates.length == 1 && fs.statSync(opts.templates[0]).isDirectory())) { - if(opts.partial){ + if (opts.templates.length > 1 || (opts.templates.length == 1 && fs.statSync(opts.templates[0]).isDirectory())) { + if (opts.partial) { output.add('return Handlebars.partials;\n'); } else { output.add('return templates;\n'); diff --git a/package.json b/package.json index f653a3f..b23b783 100644 --- a/package.json +++ b/package.json @@ -30,11 +30,13 @@ "devDependencies": { "async": "^0.9.0", "aws-sdk": "~1.5.0", + "babel-loader": "^5.0.0", + "babel-runtime": "^5.1.10", "benchmark": "~1.0", "dustjs-linkedin": "^2.0.2", "eco": "~1.1.0-rc-3", - "es6-module-packager": "^2.0.0", "grunt": "~0.4.1", + "grunt-babel": "^5.0.0", "grunt-cli": "~0.1.10", "grunt-contrib-clean": "0.x", "grunt-contrib-concat": "0.x", @@ -44,7 +46,9 @@ "grunt-contrib-requirejs": "0.x", "grunt-contrib-uglify": "0.x", "grunt-contrib-watch": "0.x", + "grunt-eslint": "^11.0.0", "grunt-saucelabs": "8.x", + "grunt-webpack": "^1.0.8", "istanbul": "^0.3.0", "jison": "~0.3.0", "keen.io": "0.0.3", diff --git a/spec/.eslintrc b/spec/.eslintrc new file mode 100644 index 0000000..2d05814 --- /dev/null +++ b/spec/.eslintrc @@ -0,0 +1,34 @@ +{ + "globals": { + "CompilerContext": true, + "Handlebars": true, + "handlebarsEnv": true, + + "shouldCompileTo": true, + "shouldCompileToWithPartials": true, + "shouldThrow": true, + "compileWithPartials": true, + + "console": true, + "require": true, + "suite": true, + "equal": true, + "equals": true, + "test": true, + "testBoth": true, + "raises": true, + "deepEqual": true, + "start": true, + "stop": true, + "ok": true, + "strictEqual": true, + "define": true + }, + "env": { + "mocha": true + }, + "rules": { + // Disabling for tests, for now. + "no-path-concat": 0 + } +}
\ No newline at end of file diff --git a/spec/ast.js b/spec/ast.js index 3b2a4ae..6f492fd 100644 --- a/spec/ast.js +++ b/spec/ast.js @@ -1,4 +1,3 @@ -/*global Handlebars, handlebarsEnv, shouldThrow */ describe('ast', function() { if (!Handlebars.AST) { return; @@ -15,7 +14,7 @@ describe('ast', function() { } }; - function testLocationInfoStorage(node){ + function testLocationInfoStorage(node) { equals(node.loc.start.line, 1); equals(node.loc.start.column, 1); equals(node.loc.end.line, 1); @@ -24,9 +23,7 @@ describe('ast', function() { describe('MustacheStatement', function() { it('should store args', function() { - var id = {isSimple: true}, - hash = {}, - mustache = new handlebarsEnv.AST.MustacheStatement({}, null, null, true, {}, LOCATION_INFO); + var mustache = new handlebarsEnv.AST.MustacheStatement({}, null, null, true, {}, LOCATION_INFO); equals(mustache.type, 'MustacheStatement'); equals(mustache.escaped, true); testLocationInfoStorage(mustache); @@ -35,11 +32,11 @@ describe('ast', function() { describe('BlockStatement', function() { it('should throw on mustache mismatch', function() { shouldThrow(function() { - handlebarsEnv.parse("\n {{#foo}}{{/bar}}"); + handlebarsEnv.parse('\n {{#foo}}{{/bar}}'); }, Handlebars.Exception, "foo doesn't match bar - 2:5"); }); - it('stores location info', function(){ + it('stores location info', function() { var mustacheNode = new handlebarsEnv.AST.MustacheStatement([{ original: 'foo'}], null, null, false, {}); var block = new handlebarsEnv.AST.BlockStatement( mustacheNode, @@ -54,114 +51,114 @@ describe('ast', function() { }); }); describe('PathExpression', function() { - it('stores location info', function(){ + it('stores location info', function() { var idNode = new handlebarsEnv.AST.PathExpression(false, 0, [], 'foo', LOCATION_INFO); testLocationInfoStorage(idNode); }); }); - describe('Hash', function(){ - it('stores location info', function(){ + describe('Hash', function() { + it('stores location info', function() { var hash = new handlebarsEnv.AST.Hash([], LOCATION_INFO); testLocationInfoStorage(hash); }); }); - describe('ContentStatement', function(){ - it('stores location info', function(){ - var content = new handlebarsEnv.AST.ContentStatement("HI", LOCATION_INFO); + describe('ContentStatement', function() { + it('stores location info', function() { + var content = new handlebarsEnv.AST.ContentStatement('HI', LOCATION_INFO); testLocationInfoStorage(content); }); }); - describe('CommentStatement', function(){ - it('stores location info', function(){ - var comment = new handlebarsEnv.AST.CommentStatement("HI", {}, LOCATION_INFO); + describe('CommentStatement', function() { + it('stores location info', function() { + var comment = new handlebarsEnv.AST.CommentStatement('HI', {}, LOCATION_INFO); testLocationInfoStorage(comment); }); }); - describe('NumberLiteral', function(){ - it('stores location info', function(){ - var integer = new handlebarsEnv.AST.NumberLiteral("6", LOCATION_INFO); + describe('NumberLiteral', function() { + it('stores location info', function() { + var integer = new handlebarsEnv.AST.NumberLiteral('6', LOCATION_INFO); testLocationInfoStorage(integer); }); }); - describe('StringLiteral', function(){ - it('stores location info', function(){ - var string = new handlebarsEnv.AST.StringLiteral("6", LOCATION_INFO); + describe('StringLiteral', function() { + it('stores location info', function() { + var string = new handlebarsEnv.AST.StringLiteral('6', LOCATION_INFO); testLocationInfoStorage(string); }); }); - describe('BooleanLiteral', function(){ - it('stores location info', function(){ - var bool = new handlebarsEnv.AST.BooleanLiteral("true", LOCATION_INFO); + describe('BooleanLiteral', function() { + it('stores location info', function() { + var bool = new handlebarsEnv.AST.BooleanLiteral('true', LOCATION_INFO); testLocationInfoStorage(bool); }); }); - describe('PartialStatement', function(){ - it('stores location info', function(){ + describe('PartialStatement', function() { + it('stores location info', function() { var pn = new handlebarsEnv.AST.PartialStatement('so_partial', [], {}, {}, LOCATION_INFO); testLocationInfoStorage(pn); }); }); - describe('Program', function(){ - it('storing location info', function(){ + describe('Program', function() { + it('storing location info', function() { var pn = new handlebarsEnv.AST.Program([], null, {}, LOCATION_INFO); testLocationInfoStorage(pn); }); }); - describe("Line Numbers", function(){ + describe('Line Numbers', function() { var ast, body; - function testColumns(node, firstLine, lastLine, firstColumn, lastColumn){ + function testColumns(node, firstLine, lastLine, firstColumn, lastColumn) { equals(node.loc.start.line, firstLine); equals(node.loc.start.column, firstColumn); equals(node.loc.end.line, lastLine); equals(node.loc.end.column, lastColumn); } - ast = Handlebars.parse("line 1 {{line1Token}}\n line 2 {{line2token}}\n line 3 {{#blockHelperOnLine3}}\nline 4{{line4token}}\n" + - "line5{{else}}\n{{line6Token}}\n{{/blockHelperOnLine3}}"); + ast = Handlebars.parse('line 1 {{line1Token}}\n line 2 {{line2token}}\n line 3 {{#blockHelperOnLine3}}\nline 4{{line4token}}\n' + + 'line5{{else}}\n{{line6Token}}\n{{/blockHelperOnLine3}}'); 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, 8, 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; @@ -169,7 +166,7 @@ describe('ast', function() { }); }); - describe('standalone flags', function(){ + describe('standalone flags', function() { describe('mustache', function() { it('does not mark mustaches as standalone', function() { var ast = Handlebars.parse(' {{comment}} '); diff --git a/spec/basic.js b/spec/basic.js index 323a103..f9b781b 100644 --- a/spec/basic.js +++ b/spec/basic.js @@ -1,38 +1,37 @@ -/*global CompilerContext, Handlebars, beforeEach, shouldCompileTo, shouldThrow */ global.handlebarsEnv = null; beforeEach(function() { global.handlebarsEnv = Handlebars.create(); }); -describe("basic context", function() { - it("most basic", function() { - shouldCompileTo("{{foo}}", { foo: "foo" }, "foo"); +describe('basic context', function() { + it('most basic', function() { + shouldCompileTo('{{foo}}', { foo: 'foo' }, 'foo'); }); - it("escaping", function() { - shouldCompileTo("\\{{foo}}", { foo: "food" }, "{{foo}}"); - shouldCompileTo("content \\{{foo}}", { foo: "food" }, "content {{foo}}"); - shouldCompileTo("\\\\{{foo}}", { foo: "food" }, "\\food"); - shouldCompileTo("content \\\\{{foo}}", { foo: "food" }, "content \\food"); - shouldCompileTo("\\\\ {{foo}}", { foo: "food" }, "\\\\ food"); + it('escaping', function() { + shouldCompileTo('\\{{foo}}', { foo: 'food' }, '{{foo}}'); + shouldCompileTo('content \\{{foo}}', { foo: 'food' }, 'content {{foo}}'); + shouldCompileTo('\\\\{{foo}}', { foo: 'food' }, '\\food'); + shouldCompileTo('content \\\\{{foo}}', { foo: 'food' }, 'content \\food'); + shouldCompileTo('\\\\ {{foo}}', { foo: 'food' }, '\\\\ food'); }); - it("compiling with a basic context", function() { - shouldCompileTo("Goodbye\n{{cruel}}\n{{world}}!", {cruel: "cruel", world: "world"}, "Goodbye\ncruel\nworld!", - "It works if all the required keys are provided"); + it('compiling with a basic context', function() { + shouldCompileTo('Goodbye\n{{cruel}}\n{{world}}!', {cruel: 'cruel', world: 'world'}, 'Goodbye\ncruel\nworld!', + 'It works if all the required keys are provided'); }); - it("compiling with an undefined context", function() { - shouldCompileTo("Goodbye\n{{cruel}}\n{{world.bar}}!", undefined, "Goodbye\n\n!"); + it('compiling with an undefined context', function() { + shouldCompileTo('Goodbye\n{{cruel}}\n{{world.bar}}!', undefined, 'Goodbye\n\n!'); - shouldCompileTo("{{#unless foo}}Goodbye{{../test}}{{test2}}{{/unless}}", undefined, "Goodbye"); + shouldCompileTo('{{#unless foo}}Goodbye{{../test}}{{test2}}{{/unless}}', undefined, 'Goodbye'); }); - it("comments", function() { - shouldCompileTo("{{! Goodbye}}Goodbye\n{{cruel}}\n{{world}}!", - {cruel: "cruel", world: "world"}, "Goodbye\ncruel\nworld!", - "comments are ignored"); + it('comments', function() { + shouldCompileTo('{{! Goodbye}}Goodbye\n{{cruel}}\n{{world}}!', + {cruel: 'cruel', world: 'world'}, 'Goodbye\ncruel\nworld!', + 'comments are ignored'); shouldCompileTo(' {{~! comment ~}} blah', {}, 'blah'); shouldCompileTo(' {{~!-- long-comment --~}} blah', {}, 'blah'); @@ -42,28 +41,30 @@ describe("basic context", function() { shouldCompileTo(' {{~!-- long-comment --}} blah', {}, ' blah'); }); - it("boolean", function() { - var string = "{{#goodbye}}GOODBYE {{/goodbye}}cruel {{world}}!"; - shouldCompileTo(string, {goodbye: true, world: "world"}, "GOODBYE cruel world!", - "booleans show the contents when true"); + it('boolean', function() { + var string = '{{#goodbye}}GOODBYE {{/goodbye}}cruel {{world}}!'; + shouldCompileTo(string, {goodbye: true, world: 'world'}, 'GOODBYE cruel world!', + 'booleans show the contents when true'); - shouldCompileTo(string, {goodbye: false, world: "world"}, "cruel world!", - "booleans do not show the contents when false"); + shouldCompileTo(string, {goodbye: false, world: 'world'}, 'cruel world!', + 'booleans do not show the contents when false'); }); - it("zeros", function() { - shouldCompileTo("num1: {{num1}}, num2: {{num2}}", {num1: 42, num2: 0}, - "num1: 42, num2: 0"); - shouldCompileTo("num: {{.}}", 0, "num: 0"); - shouldCompileTo("num: {{num1/num2}}", {num1: {num2: 0}}, "num: 0"); + it('zeros', function() { + shouldCompileTo('num1: {{num1}}, num2: {{num2}}', {num1: 42, num2: 0}, + 'num1: 42, num2: 0'); + shouldCompileTo('num: {{.}}', 0, 'num: 0'); + shouldCompileTo('num: {{num1/num2}}', {num1: {num2: 0}}, 'num: 0'); }); it('false', function() { + /*eslint-disable no-new-wrappers */ shouldCompileTo('val1: {{val1}}, val2: {{val2}}', {val1: false, val2: new Boolean(false)}, 'val1: false, val2: false'); shouldCompileTo('val: {{.}}', false, 'val: false'); shouldCompileTo('val: {{val1/val2}}', {val1: {val2: false}}, 'val: false'); shouldCompileTo('val1: {{{val1}}}, val2: {{{val2}}}', {val1: false, val2: new Boolean(false)}, 'val1: false, val2: false'); shouldCompileTo('val: {{{val1/val2}}}', {val1: {val2: false}}, 'val: false'); + /*eslint-enable */ }); it('should handle undefined and null', function() { @@ -90,143 +91,143 @@ describe("basic context", function() { 'null!'); }); - it("newlines", function() { + it('newlines', function() { shouldCompileTo("Alan's\nTest", {}, "Alan's\nTest"); shouldCompileTo("Alan's\rTest", {}, "Alan's\rTest"); }); - it("escaping text", function() { + it('escaping text', function() { shouldCompileTo("Awesome's", {}, "Awesome's", "text is escaped so that it doesn't get caught on single quotes"); - shouldCompileTo("Awesome\\", {}, "Awesome\\", "text is escaped so that the closing quote can't be ignored"); - shouldCompileTo("Awesome\\\\ foo", {}, "Awesome\\\\ foo", "text is escaped so that it doesn't mess up backslashes"); - shouldCompileTo("Awesome {{foo}}", {foo: '\\'}, "Awesome \\", "text is escaped so that it doesn't mess up backslashes"); - shouldCompileTo(' " " ', {}, ' " " ', "double quotes never produce invalid javascript"); + shouldCompileTo('Awesome\\', {}, 'Awesome\\', "text is escaped so that the closing quote can't be ignored"); + shouldCompileTo('Awesome\\\\ foo', {}, 'Awesome\\\\ foo', "text is escaped so that it doesn't mess up backslashes"); + shouldCompileTo('Awesome {{foo}}', {foo: '\\'}, 'Awesome \\', "text is escaped so that it doesn't mess up backslashes"); + shouldCompileTo(" ' ' ", {}, " ' ' ", 'double quotes never produce invalid javascript'); }); - it("escaping expressions", function() { - shouldCompileTo("{{{awesome}}}", {awesome: "&\"\\<>"}, '&\"\\<>', + it('escaping expressions', function() { + shouldCompileTo('{{{awesome}}}', {awesome: '&\'\\<>'}, '&\'\\<>', "expressions with 3 handlebars aren't escaped"); - shouldCompileTo("{{&awesome}}", {awesome: "&\"\\<>"}, '&\"\\<>', + shouldCompileTo('{{&awesome}}', {awesome: '&\'\\<>'}, '&\'\\<>', "expressions with {{& handlebars aren't escaped"); - shouldCompileTo("{{awesome}}", {awesome: "&\"'`\\<>"}, '&"'`\\<>', - "by default expressions should be escaped"); + shouldCompileTo('{{awesome}}', {awesome: "&\"'`\\<>"}, '&"'`\\<>', + 'by default expressions should be escaped'); - shouldCompileTo("{{awesome}}", {awesome: "Escaped, <b> looks like: <b>"}, 'Escaped, <b> looks like: &lt;b&gt;', - "escaping should properly handle amperstands"); + shouldCompileTo('{{awesome}}', {awesome: 'Escaped, <b> looks like: <b>'}, 'Escaped, <b> looks like: &lt;b&gt;', + 'escaping should properly handle amperstands'); }); it("functions returning safestrings shouldn't be escaped", function() { - var hash = {awesome: function() { return new Handlebars.SafeString("&\"\\<>"); }}; - shouldCompileTo("{{awesome}}", hash, '&\"\\<>', + var hash = {awesome: function() { return new Handlebars.SafeString('&\'\\<>'); }}; + shouldCompileTo('{{awesome}}', hash, '&\'\\<>', "functions returning safestrings aren't escaped"); }); - it("functions", function() { - shouldCompileTo("{{awesome}}", {awesome: function() { return "Awesome"; }}, "Awesome", - "functions are called and render their output"); - shouldCompileTo("{{awesome}}", {awesome: function() { return this.more; }, more: "More awesome"}, "More awesome", - "functions are bound to the context"); + it('functions', function() { + shouldCompileTo('{{awesome}}', {awesome: function() { return 'Awesome'; }}, 'Awesome', + 'functions are called and render their output'); + shouldCompileTo('{{awesome}}', {awesome: function() { return this.more; }, more: 'More awesome'}, 'More awesome', + 'functions are bound to the context'); }); - it("functions with context argument", function() { - shouldCompileTo("{{awesome frank}}", + it('functions with context argument', function() { + shouldCompileTo('{{awesome frank}}', {awesome: function(context) { return context; }, - frank: "Frank"}, - "Frank", "functions are called with context arguments"); + frank: 'Frank'}, + 'Frank', 'functions are called with context arguments'); }); - it("pathed functions with context argument", function() { - shouldCompileTo("{{bar.awesome frank}}", + it('pathed functions with context argument', function() { + shouldCompileTo('{{bar.awesome frank}}', {bar: {awesome: function(context) { return context; }}, - frank: "Frank"}, - "Frank", "functions are called with context arguments"); + frank: 'Frank'}, + 'Frank', 'functions are called with context arguments'); }); - it("depthed functions with context argument", function() { - shouldCompileTo("{{#with frank}}{{../awesome .}}{{/with}}", + it('depthed functions with context argument', function() { + shouldCompileTo('{{#with frank}}{{../awesome .}}{{/with}}', {awesome: function(context) { return context; }, - frank: "Frank"}, - "Frank", "functions are called with context arguments"); + frank: 'Frank'}, + 'Frank', 'functions are called with context arguments'); }); - it("block functions with context argument", function() { - shouldCompileTo("{{#awesome 1}}inner {{.}}{{/awesome}}", + it('block functions with context argument', function() { + shouldCompileTo('{{#awesome 1}}inner {{.}}{{/awesome}}', {awesome: function(context, options) { return options.fn(context); }}, - "inner 1", "block functions are called with context and options"); + 'inner 1', 'block functions are called with context and options'); }); - it("depthed block functions with context argument", function() { - shouldCompileTo("{{#with value}}{{#../awesome 1}}inner {{.}}{{/../awesome}}{{/with}}", + it('depthed block functions with context argument', function() { + shouldCompileTo('{{#with value}}{{#../awesome 1}}inner {{.}}{{/../awesome}}{{/with}}', {value: true, awesome: function(context, options) { return options.fn(context); }}, - "inner 1", "block functions are called with context and options"); + 'inner 1', 'block functions are called with context and options'); }); - it("block functions without context argument", function() { - shouldCompileTo("{{#awesome}}inner{{/awesome}}", + it('block functions without context argument', function() { + shouldCompileTo('{{#awesome}}inner{{/awesome}}', {awesome: function(options) { return options.fn(this); }}, - "inner", "block functions are called with options"); + 'inner', 'block functions are called with options'); }); - it("pathed block functions without context argument", function() { - shouldCompileTo("{{#foo.awesome}}inner{{/foo.awesome}}", + it('pathed block functions without context argument', function() { + shouldCompileTo('{{#foo.awesome}}inner{{/foo.awesome}}', {foo: {awesome: function() { return this; }}}, - "inner", "block functions are called with options"); + 'inner', 'block functions are called with options'); }); - it("depthed block functions without context argument", function() { - shouldCompileTo("{{#with value}}{{#../awesome}}inner{{/../awesome}}{{/with}}", + it('depthed block functions without context argument', function() { + shouldCompileTo('{{#with value}}{{#../awesome}}inner{{/../awesome}}{{/with}}', {value: true, awesome: function() { return this; }}, - "inner", "block functions are called with options"); + 'inner', 'block functions are called with options'); }); - it("paths with hyphens", function() { - shouldCompileTo("{{foo-bar}}", {"foo-bar": "baz"}, "baz", "Paths can contain hyphens (-)"); - shouldCompileTo("{{foo.foo-bar}}", {foo: {"foo-bar": "baz"}}, "baz", "Paths can contain hyphens (-)"); - shouldCompileTo("{{foo/foo-bar}}", {foo: {"foo-bar": "baz"}}, "baz", "Paths can contain hyphens (-)"); + it('paths with hyphens', function() { + shouldCompileTo('{{foo-bar}}', {'foo-bar': 'baz'}, 'baz', 'Paths can contain hyphens (-)'); + shouldCompileTo('{{foo.foo-bar}}', {foo: {'foo-bar': 'baz'}}, 'baz', 'Paths can contain hyphens (-)'); + shouldCompileTo('{{foo/foo-bar}}', {foo: {'foo-bar': 'baz'}}, 'baz', 'Paths can contain hyphens (-)'); }); - it("nested paths", function() { - shouldCompileTo("Goodbye {{alan/expression}} world!", {alan: {expression: "beautiful"}}, - "Goodbye beautiful world!", "Nested paths access nested objects"); + it('nested paths', function() { + shouldCompileTo('Goodbye {{alan/expression}} world!', {alan: {expression: 'beautiful'}}, + 'Goodbye beautiful world!', 'Nested paths access nested objects'); }); - it("nested paths with empty string value", function() { - shouldCompileTo("Goodbye {{alan/expression}} world!", {alan: {expression: ""}}, - "Goodbye world!", "Nested paths access nested objects with empty string"); + it('nested paths with empty string value', function() { + shouldCompileTo('Goodbye {{alan/expression}} world!', {alan: {expression: ''}}, + 'Goodbye world!', 'Nested paths access nested objects with empty string'); }); - it("literal paths", function() { - shouldCompileTo("Goodbye {{[@alan]/expression}} world!", {"@alan": {expression: "beautiful"}}, - "Goodbye beautiful world!", "Literal paths can be used"); - shouldCompileTo("Goodbye {{[foo bar]/expression}} world!", {"foo bar": {expression: "beautiful"}}, - "Goodbye beautiful world!", "Literal paths can be used"); + it('literal paths', function() { + shouldCompileTo('Goodbye {{[@alan]/expression}} world!', {'@alan': {expression: 'beautiful'}}, + 'Goodbye beautiful world!', 'Literal paths can be used'); + shouldCompileTo('Goodbye {{[foo bar]/expression}} world!', {'foo bar': {expression: 'beautiful'}}, + 'Goodbye beautiful world!', 'Literal paths can be used'); }); it('literal references', function() { - shouldCompileTo("Goodbye {{[foo bar]}} world!", {"foo bar": "beautiful"}, - "Goodbye beautiful world!", "Literal paths can be used"); + shouldCompileTo('Goodbye {{[foo bar]}} world!', {'foo bar': 'beautiful'}, + 'Goodbye beautiful world!', 'Literal paths can be used'); }); it("that current context path ({{.}}) doesn't hit helpers", function() { - shouldCompileTo("test: {{.}}", [null, {helper: "awesome"}], "test: "); + shouldCompileTo('test: {{.}}', [null, {helper: 'awesome'}], 'test: '); }); - it("complex but empty paths", function() { - shouldCompileTo("{{person/name}}", {person: {name: null}}, ""); - shouldCompileTo("{{person/name}}", {person: {}}, ""); + it('complex but empty paths', function() { + shouldCompileTo('{{person/name}}', {person: {name: null}}, ''); + shouldCompileTo('{{person/name}}', {person: {}}, ''); }); - it("this keyword in paths", function() { - var string = "{{#goodbyes}}{{this}}{{/goodbyes}}"; - var hash = {goodbyes: ["goodbye", "Goodbye", "GOODBYE"]}; - shouldCompileTo(string, hash, "goodbyeGoodbyeGOODBYE", - "This keyword in paths evaluates to current context"); + it('this keyword in paths', function() { + var string = '{{#goodbyes}}{{this}}{{/goodbyes}}'; + var hash = {goodbyes: ['goodbye', 'Goodbye', 'GOODBYE']}; + shouldCompileTo(string, hash, 'goodbyeGoodbyeGOODBYE', + 'This keyword in paths evaluates to current context'); - string = "{{#hellos}}{{this/text}}{{/hellos}}"; - hash = {hellos: [{text: "hello"}, {text: "Hello"}, {text: "HELLO"}]}; - shouldCompileTo(string, hash, "helloHelloHELLO", "This keyword evaluates in more complex paths"); + string = '{{#hellos}}{{this/text}}{{/hellos}}'; + hash = {hellos: [{text: 'hello'}, {text: 'Hello'}, {text: 'HELLO'}]}; + shouldCompileTo(string, hash, 'helloHelloHELLO', 'This keyword evaluates in more complex paths'); }); - it("this keyword nested inside path", function() { + it('this keyword nested inside path', function() { shouldThrow(function() { CompilerContext.compile('{{#hellos}}{{text/this/foo}}{{/hellos}}'); }, Error, 'Invalid path: text/this - 1:13'); @@ -235,22 +236,22 @@ describe("basic context", function() { shouldCompileTo('{{text/[this]}}', {text: {'this': 'bar'}}, 'bar'); }); - it("this keyword in helpers", function() { + it('this keyword in helpers', function() { var helpers = {foo: function(value) { return 'bar ' + value; }}; - var string = "{{#goodbyes}}{{foo this}}{{/goodbyes}}"; - var hash = {goodbyes: ["goodbye", "Goodbye", "GOODBYE"]}; - shouldCompileTo(string, [hash, helpers], "bar goodbyebar Goodbyebar GOODBYE", - "This keyword in paths evaluates to current context"); + var string = '{{#goodbyes}}{{foo this}}{{/goodbyes}}'; + var hash = {goodbyes: ['goodbye', 'Goodbye', 'GOODBYE']}; + shouldCompileTo(string, [hash, helpers], 'bar goodbyebar Goodbyebar GOODBYE', + 'This keyword in paths evaluates to current context'); - string = "{{#hellos}}{{foo this/text}}{{/hellos}}"; - hash = {hellos: [{text: "hello"}, {text: "Hello"}, {text: "HELLO"}]}; - shouldCompileTo(string, [hash, helpers], "bar hellobar Hellobar HELLO", "This keyword evaluates in more complex paths"); + string = '{{#hellos}}{{foo this/text}}{{/hellos}}'; + hash = {hellos: [{text: 'hello'}, {text: 'Hello'}, {text: 'HELLO'}]}; + shouldCompileTo(string, [hash, helpers], 'bar hellobar Hellobar HELLO', 'This keyword evaluates in more complex paths'); }); - it("this keyword nested inside helpers param", function() { - var string = "{{#hellos}}{{foo text/this/foo}}{{/hellos}}"; + it('this keyword nested inside helpers param', function() { + var string = '{{#hellos}}{{foo text/this/foo}}{{/hellos}}'; shouldThrow(function() { CompilerContext.compile(string); }, Error, 'Invalid path: text/this - 1:17'); diff --git a/spec/blocks.js b/spec/blocks.js index 21fb718..80f1580 100644 --- a/spec/blocks.js +++ b/spec/blocks.js @@ -1,112 +1,111 @@ -/*global CompilerContext, shouldCompileTo, shouldThrow */ describe('blocks', function() { - it("array", function() { - var string = "{{#goodbyes}}{{text}}! {{/goodbyes}}cruel {{world}}!"; - var hash = {goodbyes: [{text: "goodbye"}, {text: "Goodbye"}, {text: "GOODBYE"}], world: "world"}; - shouldCompileTo(string, hash, "goodbye! Goodbye! GOODBYE! cruel world!", - "Arrays iterate over the contents when not empty"); - - shouldCompileTo(string, {goodbyes: [], world: "world"}, "cruel world!", - "Arrays ignore the contents when empty"); + it('array', function() { + var string = '{{#goodbyes}}{{text}}! {{/goodbyes}}cruel {{world}}!'; + var hash = {goodbyes: [{text: 'goodbye'}, {text: 'Goodbye'}, {text: 'GOODBYE'}], world: 'world'}; + shouldCompileTo(string, hash, 'goodbye! Goodbye! GOODBYE! cruel world!', + 'Arrays iterate over the contents when not empty'); + + shouldCompileTo(string, {goodbyes: [], world: 'world'}, 'cruel world!', + 'Arrays ignore the contents when empty'); }); it('array without data', function() { - var string = '{{#goodbyes}}{{text}}{{/goodbyes}} {{#goodbyes}}{{text}}{{/goodbyes}}'; - var hash = {goodbyes: [{text: 'goodbye'}, {text: 'Goodbye'}, {text: 'GOODBYE'}], world: 'world'}; - shouldCompileTo(string, [hash,,,,false], 'goodbyeGoodbyeGOODBYE goodbyeGoodbyeGOODBYE'); + var string = '{{#goodbyes}}{{text}}{{/goodbyes}} {{#goodbyes}}{{text}}{{/goodbyes}}'; + var hash = {goodbyes: [{text: 'goodbye'}, {text: 'Goodbye'}, {text: 'GOODBYE'}], world: 'world'}; + shouldCompileTo(string, [hash,,, false], 'goodbyeGoodbyeGOODBYE goodbyeGoodbyeGOODBYE'); }); - it("array with @index", function() { - var string = "{{#goodbyes}}{{@index}}. {{text}}! {{/goodbyes}}cruel {{world}}!"; - var hash = {goodbyes: [{text: "goodbye"}, {text: "Goodbye"}, {text: "GOODBYE"}], world: "world"}; + it('array with @index', function() { + var string = '{{#goodbyes}}{{@index}}. {{text}}! {{/goodbyes}}cruel {{world}}!'; + var hash = {goodbyes: [{text: 'goodbye'}, {text: 'Goodbye'}, {text: 'GOODBYE'}], world: 'world'}; var template = CompilerContext.compile(string); var result = template(hash); - equal(result, "0. goodbye! 1. Goodbye! 2. GOODBYE! cruel world!", "The @index variable is used"); + equal(result, '0. goodbye! 1. Goodbye! 2. GOODBYE! cruel world!', 'The @index variable is used'); }); - - it("empty block", function() { - var string = "{{#goodbyes}}{{/goodbyes}}cruel {{world}}!"; - var hash = {goodbyes: [{text: "goodbye"}, {text: "Goodbye"}, {text: "GOODBYE"}], world: "world"}; - shouldCompileTo(string, hash, "cruel world!", - "Arrays iterate over the contents when not empty"); - - shouldCompileTo(string, {goodbyes: [], world: "world"}, "cruel world!", - "Arrays ignore the contents when empty"); + + it('empty block', function() { + var string = '{{#goodbyes}}{{/goodbyes}}cruel {{world}}!'; + var hash = {goodbyes: [{text: 'goodbye'}, {text: 'Goodbye'}, {text: 'GOODBYE'}], world: 'world'}; + shouldCompileTo(string, hash, 'cruel world!', + 'Arrays iterate over the contents when not empty'); + + shouldCompileTo(string, {goodbyes: [], world: 'world'}, 'cruel world!', + 'Arrays ignore the contents when empty'); }); - it("block with complex lookup", function() { - var string = "{{#goodbyes}}{{text}} cruel {{../name}}! {{/goodbyes}}"; - var hash = {name: "Alan", goodbyes: [{text: "goodbye"}, {text: "Goodbye"}, {text: "GOODBYE"}]}; + it('block with complex lookup', function() { + var string = '{{#goodbyes}}{{text}} cruel {{../name}}! {{/goodbyes}}'; + var hash = {name: 'Alan', goodbyes: [{text: 'goodbye'}, {text: 'Goodbye'}, {text: 'GOODBYE'}]}; - shouldCompileTo(string, hash, "goodbye cruel Alan! Goodbye cruel Alan! GOODBYE cruel Alan! ", - "Templates can access variables in contexts up the stack with relative path syntax"); + shouldCompileTo(string, hash, 'goodbye cruel Alan! Goodbye cruel Alan! GOODBYE cruel Alan! ', + 'Templates can access variables in contexts up the stack with relative path syntax'); }); it('multiple blocks with complex lookup', function() { var string = '{{#goodbyes}}{{../name}}{{../name}}{{/goodbyes}}'; - var hash = {name: 'Alan', goodbyes: [{text: 'goodbye'}, {text: 'Goodbye'}, {text: 'GOODBYE'}]}; + var hash = {name: 'Alan', goodbyes: [{text: 'goodbye'}, {text: 'Goodbye'}, {text: 'GOODBYE'}]}; shouldCompileTo(string, hash, 'AlanAlanAlanAlanAlanAlan'); }); - it("block with complex lookup using nested context", function() { - var string = "{{#goodbyes}}{{text}} cruel {{foo/../name}}! {{/goodbyes}}"; + it('block with complex lookup using nested context', function() { + var string = '{{#goodbyes}}{{text}} cruel {{foo/../name}}! {{/goodbyes}}'; shouldThrow(function() { CompilerContext.compile(string); }, Error); }); - it("block with deep nested complex lookup", function() { - var string = "{{#outer}}Goodbye {{#inner}}cruel {{../sibling}} {{../../omg}}{{/inner}}{{/outer}}"; - var hash = {omg: "OMG!", outer: [{ sibling: 'sad', inner: [{ text: "goodbye" }] }] }; + it('block with deep nested complex lookup', function() { + var string = '{{#outer}}Goodbye {{#inner}}cruel {{../sibling}} {{../../omg}}{{/inner}}{{/outer}}'; + var hash = {omg: 'OMG!', outer: [{ sibling: 'sad', inner: [{ text: 'goodbye' }] }] }; - shouldCompileTo(string, hash, "Goodbye cruel sad OMG!"); + shouldCompileTo(string, hash, 'Goodbye cruel sad OMG!'); }); describe('inverted sections', function() { - it("inverted sections with unset value", function() { - var string = "{{#goodbyes}}{{this}}{{/goodbyes}}{{^goodbyes}}Right On!{{/goodbyes}}"; + it('inverted sections with unset value', function() { + var string = '{{#goodbyes}}{{this}}{{/goodbyes}}{{^goodbyes}}Right On!{{/goodbyes}}'; var hash = {}; - shouldCompileTo(string, hash, "Right On!", "Inverted section rendered when value isn't set."); + shouldCompileTo(string, hash, 'Right On!', "Inverted section rendered when value isn't set."); }); - it("inverted section with false value", function() { - var string = "{{#goodbyes}}{{this}}{{/goodbyes}}{{^goodbyes}}Right On!{{/goodbyes}}"; + it('inverted section with false value', function() { + var string = '{{#goodbyes}}{{this}}{{/goodbyes}}{{^goodbyes}}Right On!{{/goodbyes}}'; var hash = {goodbyes: false}; - shouldCompileTo(string, hash, "Right On!", "Inverted section rendered when value is false."); + shouldCompileTo(string, hash, 'Right On!', 'Inverted section rendered when value is false.'); }); - it("inverted section with empty set", function() { - var string = "{{#goodbyes}}{{this}}{{/goodbyes}}{{^goodbyes}}Right On!{{/goodbyes}}"; + it('inverted section with empty set', function() { + var string = '{{#goodbyes}}{{this}}{{/goodbyes}}{{^goodbyes}}Right On!{{/goodbyes}}'; var hash = {goodbyes: []}; - shouldCompileTo(string, hash, "Right On!", "Inverted section rendered when value is empty set."); + shouldCompileTo(string, hash, 'Right On!', 'Inverted section rendered when value is empty set.'); }); - it("block inverted sections", function() { - shouldCompileTo("{{#people}}{{name}}{{^}}{{none}}{{/people}}", {none: "No people"}, - "No people"); + it('block inverted sections', function() { + shouldCompileTo('{{#people}}{{name}}{{^}}{{none}}{{/people}}', {none: 'No people'}, + 'No people'); }); - it("chained inverted sections", function() { - shouldCompileTo("{{#people}}{{name}}{{else if none}}{{none}}{{/people}}", {none: "No people"}, - "No people"); - shouldCompileTo("{{#people}}{{name}}{{else if nothere}}fail{{else unless nothere}}{{none}}{{/people}}", {none: "No people"}, - "No people"); - shouldCompileTo("{{#people}}{{name}}{{else if none}}{{none}}{{else}}fail{{/people}}", {none: "No people"}, - "No people"); + it('chained inverted sections', function() { + shouldCompileTo('{{#people}}{{name}}{{else if none}}{{none}}{{/people}}', {none: 'No people'}, + 'No people'); + shouldCompileTo('{{#people}}{{name}}{{else if nothere}}fail{{else unless nothere}}{{none}}{{/people}}', {none: 'No people'}, + 'No people'); + shouldCompileTo('{{#people}}{{name}}{{else if none}}{{none}}{{else}}fail{{/people}}', {none: 'No people'}, + 'No people'); }); - it("chained inverted sections with mismatch", function() { + it('chained inverted sections with mismatch', function() { shouldThrow(function() { - shouldCompileTo("{{#people}}{{name}}{{else if none}}{{none}}{{/if}}", {none: "No people"}, - "No people"); + shouldCompileTo('{{#people}}{{name}}{{else if none}}{{none}}{{/if}}', {none: 'No people'}, + 'No people'); }, Error); }); - it("block inverted sections with empty arrays", function() { - shouldCompileTo("{{#people}}{{name}}{{^}}{{none}}{{/people}}", {none: "No people", people: []}, - "No people"); + it('block inverted sections with empty arrays', function() { + shouldCompileTo('{{#people}}{{name}}{{^}}{{none}}{{/people}}', {none: 'No people', people: []}, + 'No people'); }); }); @@ -131,23 +130,23 @@ describe('blocks', function() { }); describe('compat mode', function() { - it("block with deep recursive lookup lookup", function() { - var string = "{{#outer}}Goodbye {{#inner}}cruel {{omg}}{{/inner}}{{/outer}}"; - var hash = {omg: "OMG!", outer: [{ inner: [{ text: "goodbye" }] }] }; + it('block with deep recursive lookup lookup', function() { + var string = '{{#outer}}Goodbye {{#inner}}cruel {{omg}}{{/inner}}{{/outer}}'; + var hash = {omg: 'OMG!', outer: [{ inner: [{ text: 'goodbye' }] }] }; - shouldCompileTo(string, [hash, undefined, undefined, true], "Goodbye cruel OMG!"); + shouldCompileTo(string, [hash, undefined, undefined, true], 'Goodbye cruel OMG!'); }); - it("block with deep recursive pathed lookup", function() { - var string = "{{#outer}}Goodbye {{#inner}}cruel {{omg.yes}}{{/inner}}{{/outer}}"; - var hash = {omg: {yes: "OMG!"}, outer: [{ inner: [{ yes: 'no', text: "goodbye" }] }] }; + it('block with deep recursive pathed lookup', function() { + var string = '{{#outer}}Goodbye {{#inner}}cruel {{omg.yes}}{{/inner}}{{/outer}}'; + var hash = {omg: {yes: 'OMG!'}, outer: [{ inner: [{ yes: 'no', text: 'goodbye' }] }] }; - shouldCompileTo(string, [hash, undefined, undefined, true], "Goodbye cruel OMG!"); + shouldCompileTo(string, [hash, undefined, undefined, true], 'Goodbye cruel OMG!'); }); - it("block with missed recursive lookup", function() { - var string = "{{#outer}}Goodbye {{#inner}}cruel {{omg.yes}}{{/inner}}{{/outer}}"; - var hash = {omg: {no: "OMG!"}, outer: [{ inner: [{ yes: 'no', text: "goodbye" }] }] }; + it('block with missed recursive lookup', function() { + var string = '{{#outer}}Goodbye {{#inner}}cruel {{omg.yes}}{{/inner}}{{/outer}}'; + var hash = {omg: {no: 'OMG!'}, outer: [{ inner: [{ yes: 'no', text: 'goodbye' }] }] }; - shouldCompileTo(string, [hash, undefined, undefined, true], "Goodbye cruel "); + shouldCompileTo(string, [hash, undefined, undefined, true], 'Goodbye cruel '); }); }); }); diff --git a/spec/builtins.js b/spec/builtins.js index f3b4baa..46d70ba 100644 --- a/spec/builtins.js +++ b/spec/builtins.js @@ -1,52 +1,51 @@ -/*global CompilerContext, shouldCompileTo, shouldThrow, compileWithPartials, handlebarsEnv */ describe('builtin helpers', function() { describe('#if', function() { - it("if", function() { - var string = "{{#if goodbye}}GOODBYE {{/if}}cruel {{world}}!"; - shouldCompileTo(string, {goodbye: true, world: "world"}, "GOODBYE cruel world!", - "if with boolean argument shows the contents when true"); - shouldCompileTo(string, {goodbye: "dummy", world: "world"}, "GOODBYE cruel world!", - "if with string argument shows the contents"); - shouldCompileTo(string, {goodbye: false, world: "world"}, "cruel world!", - "if with boolean argument does not show the contents when false"); - shouldCompileTo(string, {world: "world"}, "cruel world!", - "if with undefined does not show the contents"); - shouldCompileTo(string, {goodbye: ['foo'], world: "world"}, "GOODBYE cruel world!", - "if with non-empty array shows the contents"); - shouldCompileTo(string, {goodbye: [], world: "world"}, "cruel world!", - "if with empty array does not show the contents"); - shouldCompileTo(string, {goodbye: 0, world: "world"}, "cruel world!", - "if with zero does not show the contents"); - shouldCompileTo("{{#if goodbye includeZero=true}}GOODBYE {{/if}}cruel {{world}}!", - {goodbye: 0, world: "world"}, "GOODBYE cruel world!", - "if with zero does not show the contents"); - }); - - it("if with function argument", function() { - var string = "{{#if goodbye}}GOODBYE {{/if}}cruel {{world}}!"; - shouldCompileTo(string, {goodbye: function() {return true;}, world: "world"}, "GOODBYE cruel world!", - "if with function shows the contents when function returns true"); - shouldCompileTo(string, {goodbye: function() {return this.world;}, world: "world"}, "GOODBYE cruel world!", - "if with function shows the contents when function returns string"); - shouldCompileTo(string, {goodbye: function() {return false;}, world: "world"}, "cruel world!", - "if with function does not show the contents when returns false"); - shouldCompileTo(string, {goodbye: function() {return this.foo;}, world: "world"}, "cruel world!", - "if with function does not show the contents when returns undefined"); + it('if', function() { + var string = '{{#if goodbye}}GOODBYE {{/if}}cruel {{world}}!'; + shouldCompileTo(string, {goodbye: true, world: 'world'}, 'GOODBYE cruel world!', + 'if with boolean argument shows the contents when true'); + shouldCompileTo(string, {goodbye: 'dummy', world: 'world'}, 'GOODBYE cruel world!', + 'if with string argument shows the contents'); + shouldCompileTo(string, {goodbye: false, world: 'world'}, 'cruel world!', + 'if with boolean argument does not show the contents when false'); + shouldCompileTo(string, {world: 'world'}, 'cruel world!', + 'if with undefined does not show the contents'); + shouldCompileTo(string, {goodbye: ['foo'], world: 'world'}, 'GOODBYE cruel world!', + 'if with non-empty array shows the contents'); + shouldCompileTo(string, {goodbye: [], world: 'world'}, 'cruel world!', + 'if with empty array does not show the contents'); + shouldCompileTo(string, {goodbye: 0, world: 'world'}, 'cruel world!', + 'if with zero does not show the contents'); + shouldCompileTo('{{#if goodbye includeZero=true}}GOODBYE {{/if}}cruel {{world}}!', + {goodbye: 0, world: 'world'}, 'GOODBYE cruel world!', + 'if with zero does not show the contents'); + }); + + it('if with function argument', function() { + var string = '{{#if goodbye}}GOODBYE {{/if}}cruel {{world}}!'; + shouldCompileTo(string, {goodbye: function() {return true; }, world: 'world'}, 'GOODBYE cruel world!', + 'if with function shows the contents when function returns true'); + shouldCompileTo(string, {goodbye: function() {return this.world; }, world: 'world'}, 'GOODBYE cruel world!', + 'if with function shows the contents when function returns string'); + shouldCompileTo(string, {goodbye: function() {return false; }, world: 'world'}, 'cruel world!', + 'if with function does not show the contents when returns false'); + shouldCompileTo(string, {goodbye: function() {return this.foo; }, world: 'world'}, 'cruel world!', + 'if with function does not show the contents when returns undefined'); }); }); describe('#with', function() { - it("with", function() { - var string = "{{#with person}}{{first}} {{last}}{{/with}}"; - shouldCompileTo(string, {person: {first: "Alan", last: "Johnson"}}, "Alan Johnson"); + it('with', function() { + var string = '{{#with person}}{{first}} {{last}}{{/with}}'; + shouldCompileTo(string, {person: {first: 'Alan', last: 'Johnson'}}, 'Alan Johnson'); }); - it("with with function argument", function() { - var string = "{{#with person}}{{first}} {{last}}{{/with}}"; - shouldCompileTo(string, {person: function() { return {first: "Alan", last: "Johnson"};}}, "Alan Johnson"); + it('with with function argument', function() { + var string = '{{#with person}}{{first}} {{last}}{{/with}}'; + shouldCompileTo(string, {person: function() { return {first: 'Alan', last: 'Johnson'}; }}, 'Alan Johnson'); }); - it("with with else", function() { - var string = "{{#with person}}Person is present{{else}}Person is not present{{/with}}"; - shouldCompileTo(string, {}, "Person is not present"); + it('with with else', function() { + var string = '{{#with person}}Person is present{{else}}Person is not present{{/with}}'; + shouldCompileTo(string, {}, 'Person is not present'); }); }); @@ -57,73 +56,73 @@ describe('builtin helpers', function() { }); }); - it("each", function() { - var string = "{{#each goodbyes}}{{text}}! {{/each}}cruel {{world}}!"; - var hash = {goodbyes: [{text: "goodbye"}, {text: "Goodbye"}, {text: "GOODBYE"}], world: "world"}; - shouldCompileTo(string, hash, "goodbye! Goodbye! GOODBYE! cruel world!", - "each with array argument iterates over the contents when not empty"); - shouldCompileTo(string, {goodbyes: [], world: "world"}, "cruel world!", - "each with array argument ignores the contents when empty"); + it('each', function() { + var string = '{{#each goodbyes}}{{text}}! {{/each}}cruel {{world}}!'; + var hash = {goodbyes: [{text: 'goodbye'}, {text: 'Goodbye'}, {text: 'GOODBYE'}], world: 'world'}; + shouldCompileTo(string, hash, 'goodbye! Goodbye! GOODBYE! cruel world!', + 'each with array argument iterates over the contents when not empty'); + shouldCompileTo(string, {goodbyes: [], world: 'world'}, 'cruel world!', + 'each with array argument ignores the contents when empty'); }); it('each without data', function() { - var string = '{{#each goodbyes}}{{text}}! {{/each}}cruel {{world}}!'; - var hash = {goodbyes: [{text: 'goodbye'}, {text: 'Goodbye'}, {text: 'GOODBYE'}], world: 'world'}; - shouldCompileTo(string, [hash,,,,false], 'goodbye! Goodbye! GOODBYE! cruel world!'); + var string = '{{#each goodbyes}}{{text}}! {{/each}}cruel {{world}}!'; + var hash = {goodbyes: [{text: 'goodbye'}, {text: 'Goodbye'}, {text: 'GOODBYE'}], world: 'world'}; + shouldCompileTo(string, [hash,,,, false], 'goodbye! Goodbye! GOODBYE! cruel world!'); hash = {goodbyes: 'cruel', world: 'world'}; - shouldCompileTo('{{#each .}}{{.}}{{/each}}', [hash,,,,false], 'cruelworld'); + shouldCompileTo('{{#each .}}{{.}}{{/each}}', [hash,,,, false], 'cruelworld'); }); it('each without context', function() { - var string = '{{#each goodbyes}}{{text}}! {{/each}}cruel {{world}}!'; - shouldCompileTo(string, [,,,,], 'cruel !'); + var string = '{{#each goodbyes}}{{text}}! {{/each}}cruel {{world}}!'; + shouldCompileTo(string, [,,,, ], 'cruel !'); }); - it("each with an object and @key", function() { - var string = "{{#each goodbyes}}{{@key}}. {{text}}! {{/each}}cruel {{world}}!"; + it('each with an object and @key', function() { + var string = '{{#each goodbyes}}{{@key}}. {{text}}! {{/each}}cruel {{world}}!'; function Clazz() { this['<b>#1</b>'] = {text: 'goodbye'}; this[2] = {text: 'GOODBYE'}; } Clazz.prototype.foo = 'fail'; - var hash = {goodbyes: new Clazz(), world: 'world'}; + var hash = {goodbyes: new Clazz(), world: 'world'}; // Object property iteration order is undefined according to ECMA spec, // so we need to check both possible orders // @see http://stackoverflow.com/questions/280713/elements-order-in-a-for-in-loop var actual = compileWithPartials(string, hash); - var expected1 = "<b>#1</b>. goodbye! 2. GOODBYE! cruel world!"; - var expected2 = "2. GOODBYE! <b>#1</b>. goodbye! cruel world!"; + var expected1 = '<b>#1</b>. goodbye! 2. GOODBYE! cruel world!'; + var expected2 = '2. GOODBYE! <b>#1</b>. goodbye! cruel world!'; - equals(actual === expected1 || actual === expected2, true, "each with object argument iterates over the contents when not empty"); + equals(actual === expected1 || actual === expected2, true, 'each with object argument iterates over the contents when not empty'); shouldCompileTo(string, {goodbyes: {}, world: 'world'}, 'cruel world!'); }); - it("each with @index", function() { - var string = "{{#each goodbyes}}{{@index}}. {{text}}! {{/each}}cruel {{world}}!"; - var hash = {goodbyes: [{text: "goodbye"}, {text: "Goodbye"}, {text: "GOODBYE"}], world: "world"}; + it('each with @index', function() { + var string = '{{#each goodbyes}}{{@index}}. {{text}}! {{/each}}cruel {{world}}!'; + var hash = {goodbyes: [{text: 'goodbye'}, {text: 'Goodbye'}, {text: 'GOODBYE'}], world: 'world'}; var template = CompilerContext.compile(string); var result = template(hash); - equal(result, "0. goodbye! 1. Goodbye! 2. GOODBYE! cruel world!", "The @index variable is used"); + equal(result, '0. goodbye! 1. Goodbye! 2. GOODBYE! cruel world!', 'The @index variable is used'); }); - it("each with nested @index", function() { - var string = "{{#each goodbyes}}{{@index}}. {{text}}! {{#each ../goodbyes}}{{@index}} {{/each}}After {{@index}} {{/each}}{{@index}}cruel {{world}}!"; - var hash = {goodbyes: [{text: "goodbye"}, {text: "Goodbye"}, {text: "GOODBYE"}], world: "world"}; + it('each with nested @index', function() { + var string = '{{#each goodbyes}}{{@index}}. {{text}}! {{#each ../goodbyes}}{{@index}} {{/each}}After {{@index}} {{/each}}{{@index}}cruel {{world}}!'; + var hash = {goodbyes: [{text: 'goodbye'}, {text: 'Goodbye'}, {text: 'GOODBYE'}], world: 'world'}; var template = CompilerContext.compile(string); var result = template(hash); - equal(result, "0. goodbye! 0 1 2 After 0 1. Goodbye! 0 1 2 After 1 2. GOODBYE! 0 1 2 After 2 cruel world!", "The @index variable is used"); + equal(result, '0. goodbye! 0 1 2 After 0 1. Goodbye! 0 1 2 After 1 2. GOODBYE! 0 1 2 After 2 cruel world!', 'The @index variable is used'); }); it('each with block params', function() { var string = '{{#each goodbyes as |value index|}}{{index}}. {{value.text}}! {{#each ../goodbyes as |childValue childIndex|}} {{index}} {{childIndex}}{{/each}} After {{index}} {{/each}}{{index}}cruel {{world}}!'; - var hash = {goodbyes: [{text: 'goodbye'}, {text: 'Goodbye'}], world: 'world'}; + var hash = {goodbyes: [{text: 'goodbye'}, {text: 'Goodbye'}], world: 'world'}; var template = CompilerContext.compile(string); var result = template(hash); @@ -131,88 +130,88 @@ describe('builtin helpers', function() { equal(result, '0. goodbye! 0 0 0 1 After 0 1. Goodbye! 1 0 1 1 After 1 cruel world!'); }); - it("each object with @index", function() { - var string = "{{#each goodbyes}}{{@index}}. {{text}}! {{/each}}cruel {{world}}!"; - var hash = {goodbyes: {'a': {text: "goodbye"}, b: {text: "Goodbye"}, c: {text: "GOODBYE"}}, world: "world"}; + it('each object with @index', function() { + var string = '{{#each goodbyes}}{{@index}}. {{text}}! {{/each}}cruel {{world}}!'; + var hash = {goodbyes: {'a': {text: 'goodbye'}, b: {text: 'Goodbye'}, c: {text: 'GOODBYE'}}, world: 'world'}; var template = CompilerContext.compile(string); var result = template(hash); - equal(result, "0. goodbye! 1. Goodbye! 2. GOODBYE! cruel world!", "The @index variable is used"); + equal(result, '0. goodbye! 1. Goodbye! 2. GOODBYE! cruel world!', 'The @index variable is used'); }); - it("each with @first", function() { - var string = "{{#each goodbyes}}{{#if @first}}{{text}}! {{/if}}{{/each}}cruel {{world}}!"; - var hash = {goodbyes: [{text: "goodbye"}, {text: "Goodbye"}, {text: "GOODBYE"}], world: "world"}; + it('each with @first', function() { + var string = '{{#each goodbyes}}{{#if @first}}{{text}}! {{/if}}{{/each}}cruel {{world}}!'; + var hash = {goodbyes: [{text: 'goodbye'}, {text: 'Goodbye'}, {text: 'GOODBYE'}], world: 'world'}; var template = CompilerContext.compile(string); var result = template(hash); - equal(result, "goodbye! cruel world!", "The @first variable is used"); + equal(result, 'goodbye! cruel world!', 'The @first variable is used'); }); - it("each with nested @first", function() { - var string = "{{#each goodbyes}}({{#if @first}}{{text}}! {{/if}}{{#each ../goodbyes}}{{#if @first}}{{text}}!{{/if}}{{/each}}{{#if @first}} {{text}}!{{/if}}) {{/each}}cruel {{world}}!"; - var hash = {goodbyes: [{text: "goodbye"}, {text: "Goodbye"}, {text: "GOODBYE"}], world: "world"}; + it('each with nested @first', function() { + var string = '{{#each goodbyes}}({{#if @first}}{{text}}! {{/if}}{{#each ../goodbyes}}{{#if @first}}{{text}}!{{/if}}{{/each}}{{#if @first}} {{text}}!{{/if}}) {{/each}}cruel {{world}}!'; + var hash = {goodbyes: [{text: 'goodbye'}, {text: 'Goodbye'}, {text: 'GOODBYE'}], world: 'world'}; var template = CompilerContext.compile(string); var result = template(hash); - equal(result, "(goodbye! goodbye! goodbye!) (goodbye!) (goodbye!) cruel world!", "The @first variable is used"); + equal(result, '(goodbye! goodbye! goodbye!) (goodbye!) (goodbye!) cruel world!', 'The @first variable is used'); }); - it("each object with @first", function() { - var string = "{{#each goodbyes}}{{#if @first}}{{text}}! {{/if}}{{/each}}cruel {{world}}!"; - var hash = {goodbyes: {'foo': {text: "goodbye"}, bar: {text: "Goodbye"}}, world: "world"}; + it('each object with @first', function() { + var string = '{{#each goodbyes}}{{#if @first}}{{text}}! {{/if}}{{/each}}cruel {{world}}!'; + var hash = {goodbyes: {'foo': {text: 'goodbye'}, bar: {text: 'Goodbye'}}, world: 'world'}; var template = CompilerContext.compile(string); var result = template(hash); - equal(result, "goodbye! cruel world!", "The @first variable is used"); + equal(result, 'goodbye! cruel world!', 'The @first variable is used'); }); - it("each with @last", function() { - var string = "{{#each goodbyes}}{{#if @last}}{{text}}! {{/if}}{{/each}}cruel {{world}}!"; - var hash = {goodbyes: [{text: "goodbye"}, {text: "Goodbye"}, {text: "GOODBYE"}], world: "world"}; + it('each with @last', function() { + var string = '{{#each goodbyes}}{{#if @last}}{{text}}! {{/if}}{{/each}}cruel {{world}}!'; + var hash = {goodbyes: [{text: 'goodbye'}, {text: 'Goodbye'}, {text: 'GOODBYE'}], world: 'world'}; var template = CompilerContext.compile(string); var result = template(hash); - equal(result, "GOODBYE! cruel world!", "The @last variable is used"); + equal(result, 'GOODBYE! cruel world!', 'The @last variable is used'); }); - it("each object with @last", function() { - var string = "{{#each goodbyes}}{{#if @last}}{{text}}! {{/if}}{{/each}}cruel {{world}}!"; - var hash = {goodbyes: {'foo': {text: "goodbye"}, bar: {text: "Goodbye"}}, world: "world"}; + it('each object with @last', function() { + var string = '{{#each goodbyes}}{{#if @last}}{{text}}! {{/if}}{{/each}}cruel {{world}}!'; + var hash = {goodbyes: {'foo': {text: 'goodbye'}, bar: {text: 'Goodbye'}}, world: 'world'}; var template = CompilerContext.compile(string); var result = template(hash); - equal(result, "Goodbye! cruel world!", "The @last variable is used"); + equal(result, 'Goodbye! cruel world!', 'The @last variable is used'); }); - it("each with nested @last", function() { - var string = "{{#each goodbyes}}({{#if @last}}{{text}}! {{/if}}{{#each ../goodbyes}}{{#if @last}}{{text}}!{{/if}}{{/each}}{{#if @last}} {{text}}!{{/if}}) {{/each}}cruel {{world}}!"; - var hash = {goodbyes: [{text: "goodbye"}, {text: "Goodbye"}, {text: "GOODBYE"}], world: "world"}; + it('each with nested @last', function() { + var string = '{{#each goodbyes}}({{#if @last}}{{text}}! {{/if}}{{#each ../goodbyes}}{{#if @last}}{{text}}!{{/if}}{{/each}}{{#if @last}} {{text}}!{{/if}}) {{/each}}cruel {{world}}!'; + var hash = {goodbyes: [{text: 'goodbye'}, {text: 'Goodbye'}, {text: 'GOODBYE'}], world: 'world'}; var template = CompilerContext.compile(string); var result = template(hash); - equal(result, "(GOODBYE!) (GOODBYE!) (GOODBYE! GOODBYE! GOODBYE!) cruel world!", "The @last variable is used"); + equal(result, '(GOODBYE!) (GOODBYE!) (GOODBYE! GOODBYE! GOODBYE!) cruel world!', 'The @last variable is used'); }); - it("each with function argument", function() { - var string = "{{#each goodbyes}}{{text}}! {{/each}}cruel {{world}}!"; - var hash = {goodbyes: function () { return [{text: "goodbye"}, {text: "Goodbye"}, {text: "GOODBYE"}];}, world: "world"}; - shouldCompileTo(string, hash, "goodbye! Goodbye! GOODBYE! cruel world!", - "each with array function argument iterates over the contents when not empty"); - shouldCompileTo(string, {goodbyes: [], world: "world"}, "cruel world!", - "each with array function argument ignores the contents when empty"); + it('each with function argument', function() { + var string = '{{#each goodbyes}}{{text}}! {{/each}}cruel {{world}}!'; + var hash = {goodbyes: function() { return [{text: 'goodbye'}, {text: 'Goodbye'}, {text: 'GOODBYE'}]; }, world: 'world'}; + shouldCompileTo(string, hash, 'goodbye! Goodbye! GOODBYE! cruel world!', + 'each with array function argument iterates over the contents when not empty'); + shouldCompileTo(string, {goodbyes: [], world: 'world'}, 'cruel world!', + 'each with array function argument ignores the contents when empty'); }); - it("data passed to helpers", function() { - var string = "{{#each letters}}{{this}}{{detectDataInsideEach}}{{/each}}"; + it('data passed to helpers', function() { + var string = '{{#each letters}}{{this}}{{detectDataInsideEach}}{{/each}}'; var hash = {letters: ['a', 'b', 'c']}; var template = CompilerContext.compile(string); @@ -224,106 +223,108 @@ describe('builtin helpers', function() { equal(result, 'a!b!c!', 'should output data'); }); - it("each on implicit context", function() { + it('each on implicit context', function() { shouldThrow(function() { - var template = CompilerContext.compile("{{#each}}{{text}}! {{/each}}cruel world!"); + var template = CompilerContext.compile('{{#each}}{{text}}! {{/each}}cruel world!'); template({}); }, handlebarsEnv.Exception, 'Must pass iterator to #each'); }); }); - describe("#log", function() { + describe('#log', function() { + /*eslint-disable no-console */ if (typeof console === 'undefined') { return; } - var log, - info, - error; + var $log, + $info, + $error; beforeEach(function() { - log = console.log; - info = console.info; - error = console.error; + $log = console.log; + $info = console.info; + $error = console.error; }); afterEach(function() { - console.log = log; - console.info = info; - console.error = error; + console.log = $log; + console.info = $info; + console.error = $error; }); it('should call logger at default level', function() { - var string = "{{log blah}}"; - var hash = { blah: "whee" }; + var string = '{{log blah}}'; + var hash = { blah: 'whee' }; var levelArg, logArg; - handlebarsEnv.log = function(level, arg){ + handlebarsEnv.log = function(level, arg) { levelArg = level; logArg = arg; }; - shouldCompileTo(string, hash, "", "log should not display"); - equals(1, levelArg, "should call log with 1"); - equals("whee", logArg, "should call log with 'whee'"); + shouldCompileTo(string, hash, '', 'log should not display'); + equals(1, levelArg, 'should call log with 1'); + equals('whee', logArg, "should call log with 'whee'"); }); it('should call logger at data level', function() { - var string = "{{log blah}}"; - var hash = { blah: "whee" }; + var string = '{{log blah}}'; + var hash = { blah: 'whee' }; var levelArg, logArg; - handlebarsEnv.log = function(level, arg){ + handlebarsEnv.log = function(level, arg) { levelArg = level; logArg = arg; }; - shouldCompileTo(string, [hash,,,,{level: '03'}], ""); + shouldCompileTo(string, [hash,,,, {level: '03'}], ''); equals(3, levelArg); - equals("whee", logArg); + equals('whee', logArg); }); it('should output to info', function() { - var string = "{{log blah}}"; - var hash = { blah: "whee" }; + var string = '{{log blah}}'; + var hash = { blah: 'whee' }; var called; - console.info = function(log) { - equals("whee", log); + console.info = function(info) { + equals('whee', info); called = true; }; console.log = function(log) { - equals("whee", log); + equals('whee', log); called = true; }; - shouldCompileTo(string, hash, ""); + shouldCompileTo(string, hash, ''); equals(true, called); }); it('should log at data level', function() { - var string = "{{log blah}}"; - var hash = { blah: "whee" }; + var string = '{{log blah}}'; + var hash = { blah: 'whee' }; var called; console.error = function(log) { - equals("whee", log); + equals('whee', log); called = true; }; - shouldCompileTo(string, [hash,,,,{level: '03'}], ""); + shouldCompileTo(string, [hash,,,, {level: '03'}], ''); equals(true, called); }); it('should handle missing logger', function() { - var string = "{{log blah}}"; - var hash = { blah: "whee" }; + var string = '{{log blah}}'; + var hash = { blah: 'whee' }; console.error = undefined; - shouldCompileTo(string, [hash,,,,{level: '03'}], ""); + shouldCompileTo(string, [hash,,,, {level: '03'}], ''); }); + /*eslint-enable no-console */ }); describe('#lookup', function() { it('should lookup arbitrary content', function() { var string = '{{#each goodbyes}}{{lookup ../data .}}{{/each}}', - hash = {goodbyes: [0, 1], data: ['foo', 'bar']}; + hash = {goodbyes: [0, 1], data: ['foo', 'bar']}; var template = CompilerContext.compile(string); var result = template(hash); @@ -332,7 +333,7 @@ describe('builtin helpers', function() { }); it('should not fail on undefined value', function() { var string = '{{#each goodbyes}}{{lookup ../bar .}}{{/each}}', - hash = {goodbyes: [0, 1], data: ['foo', 'bar']}; + hash = {goodbyes: [0, 1], data: ['foo', 'bar']}; var template = CompilerContext.compile(string); var result = template(hash); diff --git a/spec/compiler.js b/spec/compiler.js index f9eba28..fe4b63a 100644 --- a/spec/compiler.js +++ b/spec/compiler.js @@ -1,5 +1,3 @@ -/*global Handlebars, shouldThrow */ - describe('compiler', function() { if (!Handlebars.compile) { return; @@ -41,10 +39,10 @@ describe('compiler', function() { }); it('can utilize AST instance', function() { - equal(Handlebars.compile(new Handlebars.AST.Program([ new Handlebars.AST.ContentStatement("Hello")], null, {}))(), 'Hello'); + equal(Handlebars.compile(new Handlebars.AST.Program([ new Handlebars.AST.ContentStatement('Hello')], null, {}))(), 'Hello'); }); - it("can pass through an empty string", function() { + it('can pass through an empty string', function() { equal(Handlebars.compile('')(), ''); }); }); @@ -60,10 +58,10 @@ describe('compiler', function() { }); it('can utilize AST instance', function() { - equal(/return "Hello"/.test(Handlebars.precompile(new Handlebars.AST.Program([ new Handlebars.AST.ContentStatement("Hello")]), null, {})), true); + equal(/return "Hello"/.test(Handlebars.precompile(new Handlebars.AST.Program([ new Handlebars.AST.ContentStatement('Hello')]), null, {})), 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 1678eea..547a266 100644 --- a/spec/data.js +++ b/spec/data.js @@ -1,25 +1,24 @@ -/*global CompilerContext, Handlebars, handlebarsEnv, shouldThrow */ describe('data', function() { - it("passing in data to a compiled function that expects data - works with helpers", function() { - var template = CompilerContext.compile("{{hello}}", {data: true}); + it('passing in data to a compiled function that expects data - works with helpers', function() { + var template = CompilerContext.compile('{{hello}}', {data: true}); var helpers = { hello: function(options) { - return options.data.adjective + " " + this.noun; + return options.data.adjective + ' ' + this.noun; } }; - var result = template({noun: "cat"}, {helpers: helpers, data: {adjective: "happy"}}); - equals("happy cat", result, "Data output by helper"); + var result = template({noun: 'cat'}, {helpers: helpers, data: {adjective: 'happy'}}); + equals('happy cat', result, 'Data output by helper'); }); - it("data can be looked up via @foo", function() { - var template = CompilerContext.compile("{{@hello}}"); - var result = template({}, { data: { hello: "hello" } }); - equals("hello", result, "@foo retrieves template data"); + it('data can be looked up via @foo', function() { + var template = CompilerContext.compile('{{@hello}}'); + var result = template({}, { data: { hello: 'hello' } }); + equals('hello', result, '@foo retrieves template data'); }); - it("deep @foo triggers automatic top-level data", function() { + it('deep @foo triggers automatic top-level data', function() { var template = CompilerContext.compile('{{#let world="world"}}{{#if foo}}{{#if foo}}Hello {{@world}}{{/if}}{{/if}}{{/let}}'); var helpers = Handlebars.createFrame(handlebarsEnv.helpers); @@ -28,65 +27,67 @@ describe('data', function() { var frame = Handlebars.createFrame(options.data); for (var prop in options.hash) { - frame[prop] = options.hash[prop]; + if (prop in options.hash) { + frame[prop] = options.hash[prop]; + } } return options.fn(this, { data: frame }); }; var result = template({ foo: true }, { helpers: helpers }); - equals("Hello world", result, "Automatic data was triggered"); + equals('Hello world', result, 'Automatic data was triggered'); }); - it("parameter data can be looked up via @foo", function() { - var template = CompilerContext.compile("{{hello @world}}"); + it('parameter data can be looked up via @foo', function() { + var template = CompilerContext.compile('{{hello @world}}'); var helpers = { hello: function(noun) { - return "Hello " + noun; + return 'Hello ' + noun; } }; - var result = template({}, { helpers: helpers, data: { world: "world" } }); - equals("Hello world", result, "@foo as a parameter retrieves template data"); + var result = template({}, { helpers: helpers, data: { world: 'world' } }); + equals('Hello world', result, '@foo as a parameter retrieves template data'); }); - it("hash values can be looked up via @foo", function() { - var template = CompilerContext.compile("{{hello noun=@world}}"); + it('hash values can be looked up via @foo', function() { + var template = CompilerContext.compile('{{hello noun=@world}}'); var helpers = { hello: function(options) { - return "Hello " + options.hash.noun; + return 'Hello ' + options.hash.noun; } }; - var result = template({}, { helpers: helpers, data: { world: "world" } }); - equals("Hello world", result, "@foo as a parameter retrieves template data"); + var result = template({}, { helpers: helpers, data: { world: 'world' } }); + equals('Hello world', result, '@foo as a parameter retrieves template data'); }); - it("nested parameter data can be looked up via @foo.bar", function() { - var template = CompilerContext.compile("{{hello @world.bar}}"); + it('nested parameter data can be looked up via @foo.bar', function() { + var template = CompilerContext.compile('{{hello @world.bar}}'); var helpers = { hello: function(noun) { - return "Hello " + noun; + return 'Hello ' + noun; } }; - var result = template({}, { helpers: helpers, data: { world: {bar: "world" } } }); - equals("Hello world", result, "@foo as a parameter retrieves template data"); + var result = template({}, { helpers: helpers, data: { world: {bar: 'world' } } }); + equals('Hello world', result, '@foo as a parameter retrieves template data'); }); - it("nested parameter data does not fail with @world.bar", function() { - var template = CompilerContext.compile("{{hello @world.bar}}"); + it('nested parameter data does not fail with @world.bar', function() { + var template = CompilerContext.compile('{{hello @world.bar}}'); var helpers = { hello: function(noun) { - return "Hello " + noun; + return 'Hello ' + noun; } }; - var result = template({}, { helpers: helpers, data: { foo: {bar: "world" } } }); - equals("Hello undefined", result, "@foo as a parameter retrieves template data"); + var result = template({}, { helpers: helpers, data: { foo: {bar: 'world' } } }); + equals('Hello undefined', result, '@foo as a parameter retrieves template data'); }); - it("parameter data throws when using complex scope references", function() { - var string = "{{#goodbyes}}{{text}} cruel {{@foo/../name}}! {{/goodbyes}}"; + it('parameter data throws when using complex scope references', function() { + var string = '{{#goodbyes}}{{text}} cruel {{@foo/../name}}! {{/goodbyes}}'; shouldThrow(function() { CompilerContext.compile(string); @@ -104,131 +105,133 @@ describe('data', function() { equals('hello', result); }); - it("data is inherited downstream", function() { - var template = CompilerContext.compile("{{#let foo=1 bar=2}}{{#let foo=bar.baz}}{{@bar}}{{@foo}}{{/let}}{{@foo}}{{/let}}", { data: true }); + it('data is inherited downstream', function() { + var template = CompilerContext.compile('{{#let foo=1 bar=2}}{{#let foo=bar.baz}}{{@bar}}{{@foo}}{{/let}}{{@foo}}{{/let}}', { data: true }); var helpers = { let: function(options) { var frame = Handlebars.createFrame(options.data); for (var prop in options.hash) { - frame[prop] = options.hash[prop]; + if (prop in options.hash) { + frame[prop] = options.hash[prop]; + } } return options.fn(this, {data: frame}); } }; - var result = template({ bar: { baz: "hello world" } }, { helpers: helpers, data: {} }); - equals("2hello world1", result, "data variables are inherited downstream"); + var result = template({ bar: { baz: 'hello world' } }, { helpers: helpers, data: {} }); + equals('2hello world1', result, 'data variables are inherited downstream'); }); - it("passing in data to a compiled function that expects data - works with helpers in partials", function() { - var template = CompilerContext.compile("{{>my_partial}}", {data: true}); + it('passing in data to a compiled function that expects data - works with helpers in partials', function() { + var template = CompilerContext.compile('{{>myPartial}}', {data: true}); var partials = { - my_partial: CompilerContext.compile("{{hello}}", {data: true}) + myPartial: CompilerContext.compile('{{hello}}', {data: true}) }; var helpers = { hello: function(options) { - return options.data.adjective + " " + this.noun; + return options.data.adjective + ' ' + this.noun; } }; - var result = template({noun: "cat"}, {helpers: helpers, partials: partials, data: {adjective: "happy"}}); - equals("happy cat", result, "Data output by helper inside partial"); + var result = template({noun: 'cat'}, {helpers: helpers, partials: partials, data: {adjective: 'happy'}}); + equals('happy cat', result, 'Data output by helper inside partial'); }); - it("passing in data to a compiled function that expects data - works with helpers and parameters", function() { - var template = CompilerContext.compile("{{hello world}}", {data: true}); + it('passing in data to a compiled function that expects data - works with helpers and parameters', function() { + var template = CompilerContext.compile('{{hello world}}', {data: true}); var helpers = { hello: function(noun, options) { - return options.data.adjective + " " + noun + (this.exclaim ? "!" : ""); + return options.data.adjective + ' ' + noun + (this.exclaim ? '!' : ''); } }; - var result = template({exclaim: true, world: "world"}, {helpers: helpers, data: {adjective: "happy"}}); - equals("happy world!", result, "Data output by helper"); + var result = template({exclaim: true, world: 'world'}, {helpers: helpers, data: {adjective: 'happy'}}); + equals('happy world!', result, 'Data output by helper'); }); - it("passing in data to a compiled function that expects data - works with block helpers", function() { - var template = CompilerContext.compile("{{#hello}}{{world}}{{/hello}}", {data: true}); + it('passing in data to a compiled function that expects data - works with block helpers', function() { + var template = CompilerContext.compile('{{#hello}}{{world}}{{/hello}}', {data: true}); var helpers = { hello: function(options) { return options.fn(this); }, world: function(options) { - return options.data.adjective + " world" + (this.exclaim ? "!" : ""); + return options.data.adjective + ' world' + (this.exclaim ? '!' : ''); } }; - var result = template({exclaim: true}, {helpers: helpers, data: {adjective: "happy"}}); - equals("happy world!", result, "Data output by helper"); + var result = template({exclaim: true}, {helpers: helpers, data: {adjective: 'happy'}}); + equals('happy world!', result, 'Data output by helper'); }); - it("passing in data to a compiled function that expects data - works with block helpers that use ..", function() { - var template = CompilerContext.compile("{{#hello}}{{world ../zomg}}{{/hello}}", {data: true}); + it('passing in data to a compiled function that expects data - works with block helpers that use ..', function() { + var template = CompilerContext.compile('{{#hello}}{{world ../zomg}}{{/hello}}', {data: true}); var helpers = { hello: function(options) { - return options.fn({exclaim: "?"}); + return options.fn({exclaim: '?'}); }, world: function(thing, options) { - return options.data.adjective + " " + thing + (this.exclaim || ""); + return options.data.adjective + ' ' + thing + (this.exclaim || ''); } }; - var result = template({exclaim: true, zomg: "world"}, {helpers: helpers, data: {adjective: "happy"}}); - equals("happy world?", result, "Data output by helper"); + var result = template({exclaim: true, zomg: 'world'}, {helpers: helpers, data: {adjective: 'happy'}}); + equals('happy world?', result, 'Data output by helper'); }); - it("passing in data to a compiled function that expects data - data is passed to with block helpers where children use ..", function() { - var template = CompilerContext.compile("{{#hello}}{{world ../zomg}}{{/hello}}", {data: true}); + it('passing in data to a compiled function that expects data - data is passed to with block helpers where children use ..', function() { + var template = CompilerContext.compile('{{#hello}}{{world ../zomg}}{{/hello}}', {data: true}); var helpers = { hello: function(options) { - return options.data.accessData + " " + options.fn({exclaim: "?"}); + return options.data.accessData + ' ' + options.fn({exclaim: '?'}); }, world: function(thing, options) { - return options.data.adjective + " " + thing + (this.exclaim || ""); + return options.data.adjective + ' ' + thing + (this.exclaim || ''); } }; - var result = template({exclaim: true, zomg: "world"}, {helpers: helpers, data: {adjective: "happy", accessData: "#win"}}); - equals("#win happy world?", result, "Data output by helper"); + var result = template({exclaim: true, zomg: 'world'}, {helpers: helpers, data: {adjective: 'happy', accessData: '#win'}}); + equals('#win happy world?', result, 'Data output by helper'); }); - it("you can override inherited data when invoking a helper", function() { - var template = CompilerContext.compile("{{#hello}}{{world zomg}}{{/hello}}", {data: true}); + it('you can override inherited data when invoking a helper', function() { + var template = CompilerContext.compile('{{#hello}}{{world zomg}}{{/hello}}', {data: true}); var helpers = { hello: function(options) { - return options.fn({exclaim: "?", zomg: "world"}, { data: {adjective: "sad"} }); + return options.fn({exclaim: '?', zomg: 'world'}, { data: {adjective: 'sad'} }); }, world: function(thing, options) { - return options.data.adjective + " " + thing + (this.exclaim || ""); + return options.data.adjective + ' ' + thing + (this.exclaim || ''); } }; - var result = template({exclaim: true, zomg: "planet"}, {helpers: helpers, data: {adjective: "happy"}}); - equals("sad world?", result, "Overriden data output by helper"); + var result = template({exclaim: true, zomg: 'planet'}, {helpers: helpers, data: {adjective: 'happy'}}); + equals('sad world?', result, 'Overriden data output by helper'); }); - it("you can override inherited data when invoking a helper with depth", function() { - var template = CompilerContext.compile("{{#hello}}{{world ../zomg}}{{/hello}}", {data: true}); + it('you can override inherited data when invoking a helper with depth', function() { + var template = CompilerContext.compile('{{#hello}}{{world ../zomg}}{{/hello}}', {data: true}); var helpers = { hello: function(options) { - return options.fn({exclaim: "?"}, { data: {adjective: "sad"} }); + return options.fn({exclaim: '?'}, { data: {adjective: 'sad'} }); }, world: function(thing, options) { - return options.data.adjective + " " + thing + (this.exclaim || ""); + return options.data.adjective + ' ' + thing + (this.exclaim || ''); } }; - var result = template({exclaim: true, zomg: "world"}, {helpers: helpers, data: {adjective: "happy"}}); - equals("sad world?", result, "Overriden data output by helper"); + var result = template({exclaim: true, zomg: 'world'}, {helpers: helpers, data: {adjective: 'happy'}}); + equals('sad world?', result, 'Overriden data output by helper'); }); describe('@root', function() { diff --git a/spec/env/browser.js b/spec/env/browser.js index a9042e3..c9414d4 100644 --- a/spec/env/browser.js +++ b/spec/env/browser.js @@ -1,8 +1,6 @@ -/*global handlebarsEnv */ require('./common'); -var _ = require('underscore'), - fs = require('fs'), +var fs = require('fs'), vm = require('vm'); global.Handlebars = 'no-conflict'; @@ -21,10 +19,12 @@ global.CompilerContext = { }; function safeEval(templateSpec) { + /*eslint-disable no-eval, no-console */ try { return eval('(' + templateSpec + ')'); } catch (err) { console.error(templateSpec); throw err; } + /*eslint-enable no-eval, no-console */ } diff --git a/spec/env/common.js b/spec/env/common.js index 9ffbc14..e4c8ae5 100644 --- a/spec/env/common.js +++ b/spec/env/common.js @@ -1,4 +1,3 @@ -/*global CompilerContext, compileWithPartials, shouldCompileToWithPartials */ global.shouldCompileTo = function(string, hashOrArray, expected, message) { shouldCompileToWithPartials(string, hashOrArray, false, expected, message); }; @@ -14,7 +13,7 @@ global.compileWithPartials = function(string, hashOrArray, partials) { var template, ary, options; - if(Object.prototype.toString.call(hashOrArray) === "[object Array]") { + if (Object.prototype.toString.call(hashOrArray) === '[object Array]') { ary = []; ary.push(hashOrArray[0]); ary.push({ helpers: hashOrArray[1], partials: hashOrArray[2] }); @@ -34,7 +33,7 @@ global.compileWithPartials = function(string, hashOrArray, partials) { global.equals = global.equal = function(a, b, msg) { if (a !== b) { - throw new Error("'" + a + "' should === '" + b + "'" + (msg ? ": " + msg : '')); + throw new Error("'" + a + "' should === '" + b + "'" + (msg ? ': ' + msg : '')); } }; diff --git a/spec/env/node.js b/spec/env/node.js index d7db853..62d9fe9 100644 --- a/spec/env/node.js +++ b/spec/env/node.js @@ -1,4 +1,3 @@ -/*global handlebarsEnv */ require('./common'); global.Handlebars = require('../../lib'); @@ -14,10 +13,12 @@ global.CompilerContext = { }; function safeEval(templateSpec) { + /*eslint-disable no-eval, no-console */ try { return eval('(' + templateSpec + ')'); } catch (err) { console.error(templateSpec); throw err; } + /*eslint-enable no-eval, no-console */ } diff --git a/spec/env/runner.js b/spec/env/runner.js index 143d300..56fc8d4 100644 --- a/spec/env/runner.js +++ b/spec/env/runner.js @@ -1,3 +1,4 @@ +/*eslint-disable no-console */ var fs = require('fs'), Mocha = require('mocha'), path = require('path'); @@ -6,7 +7,7 @@ var errors = 0, testDir = path.dirname(__dirname), grep = process.argv[2]; -var files = [ testDir + "/basic.js" ]; +var files = [ testDir + '/basic.js' ]; var files = fs.readdirSync(testDir) .filter(function(name) { return (/.*\.js$/).test(name); }) @@ -15,7 +16,9 @@ var files = fs.readdirSync(testDir) run('./node', function() { run('./browser', function() { run('./runtime', function() { + /*eslint-disable no-process-exit */ process.exit(errors); + /*eslint-enable no-process-exit */ }); }); }); diff --git a/spec/env/runtime.js b/spec/env/runtime.js index 0c14406..a7b42f5 100644 --- a/spec/env/runtime.js +++ b/spec/env/runtime.js @@ -1,8 +1,6 @@ -/*global handlebarsEnv */ require('./common'); -var _ = require('underscore'), - fs = require('fs'), +var fs = require('fs'), vm = require('vm'); global.Handlebars = 'no-conflict'; @@ -10,15 +8,15 @@ vm.runInThisContext(fs.readFileSync(__dirname + '/../../dist/handlebars.runtime. var parse = require('../../dist/cjs/handlebars/compiler/base').parse; var compiler = require('../../dist/cjs/handlebars/compiler/compiler'); -var JavaScriptCompiler = require('../../dist/cjs/handlebars/compiler/javascript-compiler')['default']; +var JavaScriptCompiler = require('../../dist/cjs/handlebars/compiler/javascript-compiler'); global.CompilerContext = { browser: true, compile: function(template, options) { // Hack the compiler on to the environment for these specific tests - handlebarsEnv.precompile = function(template, options) { - return compiler.precompile(template, options, handlebarsEnv); + handlebarsEnv.precompile = function(precompileTemplate, precompileOptions) { + return compiler.precompile(precompileTemplate, precompileOptions, handlebarsEnv); }; handlebarsEnv.parse = parse; handlebarsEnv.Compiler = compiler.Compiler; @@ -29,8 +27,8 @@ global.CompilerContext = { }, compileWithPartial: function(template, options) { // Hack the compiler on to the environment for these specific tests - handlebarsEnv.compile = function(template, options) { - return compiler.compile(template, options, handlebarsEnv); + handlebarsEnv.compile = function(compileTemplate, compileOptions) { + return compiler.compile(compileTemplate, compileOptions, handlebarsEnv); }; handlebarsEnv.parse = parse; handlebarsEnv.Compiler = compiler.Compiler; @@ -41,10 +39,12 @@ global.CompilerContext = { }; function safeEval(templateSpec) { + /*eslint-disable no-eval, no-console */ try { return eval('(' + templateSpec + ')'); } catch (err) { console.error(templateSpec); throw err; } + /*eslint-enable no-eval, no-console */ } diff --git a/spec/helpers.js b/spec/helpers.js index 712bb00..54ef0f2 100644 --- a/spec/helpers.js +++ b/spec/helpers.js @@ -1,165 +1,164 @@ -/*global CompilerContext, Handlebars, shouldCompileTo, shouldCompileToWithPartials, shouldThrow, handlebarsEnv */ describe('helpers', function() { - it("helper with complex lookup$", function() { - var string = "{{#goodbyes}}{{{link ../prefix}}}{{/goodbyes}}"; - var hash = {prefix: "/root", goodbyes: [{text: "Goodbye", url: "goodbye"}]}; + it('helper with complex lookup$', function() { + var string = '{{#goodbyes}}{{{link ../prefix}}}{{/goodbyes}}'; + var hash = {prefix: '/root', goodbyes: [{text: 'Goodbye', url: 'goodbye'}]}; var helpers = {link: function(prefix) { - return "<a href='" + prefix + "/" + this.url + "'>" + this.text + "</a>"; + return '<a href="' + prefix + '/' + this.url + '">' + this.text + '</a>'; }}; - shouldCompileTo(string, [hash, helpers], "<a href='/root/goodbye'>Goodbye</a>"); + shouldCompileTo(string, [hash, helpers], '<a href="/root/goodbye">Goodbye</a>'); }); - it("helper for raw block gets raw content", function() { - var string = "{{{{raw}}}} {{test}} {{{{/raw}}}}"; - var hash = { test: "hello" }; + it('helper for raw block gets raw content', function() { + var string = '{{{{raw}}}} {{test}} {{{{/raw}}}}'; + var hash = { test: 'hello' }; var helpers = { raw: function(options) { return options.fn(); } }; - shouldCompileTo(string, [hash, helpers], " {{test}} ", - "raw block helper gets raw content"); + shouldCompileTo(string, [hash, helpers], ' {{test}} ', + 'raw block helper gets raw content'); }); - - it("helper for raw block gets parameters", function() { - var string = "{{{{raw 1 2 3}}}} {{test}} {{{{/raw}}}}"; - var hash = { test: "hello" }; + + it('helper for raw block gets parameters', function() { + var string = '{{{{raw 1 2 3}}}} {{test}} {{{{/raw}}}}'; + var hash = { test: 'hello' }; var helpers = { raw: function(a, b, c, options) { return options.fn() + a + b + c; } }; - shouldCompileTo(string, [hash, helpers], " {{test}} 123", - "raw block helper gets raw content"); + shouldCompileTo(string, [hash, helpers], ' {{test}} 123', + 'raw block helper gets raw content'); }); - - it("helper block with complex lookup expression", function() { - var string = "{{#goodbyes}}{{../name}}{{/goodbyes}}"; - var hash = {name: "Alan"}; + + it('helper block with complex lookup expression', function() { + var string = '{{#goodbyes}}{{../name}}{{/goodbyes}}'; + var hash = {name: 'Alan'}; var helpers = {goodbyes: function(options) { - var out = ""; - var byes = ["Goodbye", "goodbye", "GOODBYE"]; - for (var i = 0,j = byes.length; i < j; i++) { - out += byes[i] + " " + options.fn(this) + "! "; + var out = ''; + var byes = ['Goodbye', 'goodbye', 'GOODBYE']; + for (var i = 0, j = byes.length; i < j; i++) { + out += byes[i] + ' ' + options.fn(this) + '! '; } return out; }}; - shouldCompileTo(string, [hash, helpers], "Goodbye Alan! goodbye Alan! GOODBYE Alan! "); + shouldCompileTo(string, [hash, helpers], 'Goodbye Alan! goodbye Alan! GOODBYE Alan! '); }); - it("helper with complex lookup and nested template", function() { - var string = "{{#goodbyes}}{{#link ../prefix}}{{text}}{{/link}}{{/goodbyes}}"; - var hash = {prefix: '/root', goodbyes: [{text: "Goodbye", url: "goodbye"}]}; - var helpers = {link: function (prefix, options) { - return "<a href='" + prefix + "/" + this.url + "'>" + options.fn(this) + "</a>"; + it('helper with complex lookup and nested template', function() { + var string = '{{#goodbyes}}{{#link ../prefix}}{{text}}{{/link}}{{/goodbyes}}'; + var hash = {prefix: '/root', goodbyes: [{text: 'Goodbye', url: 'goodbye'}]}; + var helpers = {link: function(prefix, options) { + return '<a href="' + prefix + '/' + this.url + '">' + options.fn(this) + '</a>'; }}; - shouldCompileToWithPartials(string, [hash, helpers], false, "<a href='/root/goodbye'>Goodbye</a>"); + shouldCompileToWithPartials(string, [hash, helpers], false, '<a href="/root/goodbye">Goodbye</a>'); }); - it("helper with complex lookup and nested template in VM+Compiler", function() { - var string = "{{#goodbyes}}{{#link ../prefix}}{{text}}{{/link}}{{/goodbyes}}"; - var hash = {prefix: '/root', goodbyes: [{text: "Goodbye", url: "goodbye"}]}; - var helpers = {link: function (prefix, options) { - return "<a href='" + prefix + "/" + this.url + "'>" + options.fn(this) + "</a>"; + it('helper with complex lookup and nested template in VM+Compiler', function() { + var string = '{{#goodbyes}}{{#link ../prefix}}{{text}}{{/link}}{{/goodbyes}}'; + var hash = {prefix: '/root', goodbyes: [{text: 'Goodbye', url: 'goodbye'}]}; + var helpers = {link: function(prefix, options) { + return '<a href="' + prefix + '/' + this.url + '">' + options.fn(this) + '</a>'; }}; - shouldCompileToWithPartials(string, [hash, helpers], true, "<a href='/root/goodbye'>Goodbye</a>"); + shouldCompileToWithPartials(string, [hash, helpers], true, '<a href="/root/goodbye">Goodbye</a>'); }); it('helper returning undefined value', function() { shouldCompileTo(' {{nothere}}', [{}, {nothere: function() {}}], ' '); shouldCompileTo(' {{#nothere}}{{/nothere}}', [{}, {nothere: function() {}}], ' '); }); - it("block helper", function() { - var string = "{{#goodbyes}}{{text}}! {{/goodbyes}}cruel {{world}}!"; + it('block helper', function() { + var string = '{{#goodbyes}}{{text}}! {{/goodbyes}}cruel {{world}}!'; var template = CompilerContext.compile(string); - var result = template({world: "world"}, { helpers: {goodbyes: function(options) { return options.fn({text: "GOODBYE"}); }}}); - equal(result, "GOODBYE! cruel world!", "Block helper executed"); + var result = template({world: 'world'}, { helpers: {goodbyes: function(options) { return options.fn({text: 'GOODBYE'}); }}}); + equal(result, 'GOODBYE! cruel world!', 'Block helper executed'); }); - it("block helper staying in the same context", function() { - var string = "{{#form}}<p>{{name}}</p>{{/form}}"; + it('block helper staying in the same context', function() { + var string = '{{#form}}<p>{{name}}</p>{{/form}}'; var template = CompilerContext.compile(string); - var result = template({name: "Yehuda"}, {helpers: {form: function(options) { return "<form>" + options.fn(this) + "</form>"; } }}); - equal(result, "<form><p>Yehuda</p></form>", "Block helper executed with current context"); + var result = template({name: 'Yehuda'}, {helpers: {form: function(options) { return '<form>' + options.fn(this) + '</form>'; } }}); + equal(result, '<form><p>Yehuda</p></form>', 'Block helper executed with current context'); }); - it("block helper should have context in this", function() { - var source = "<ul>{{#people}}<li>{{#link}}{{name}}{{/link}}</li>{{/people}}</ul>"; - var link = function(options) { + it('block helper should have context in this', function() { + var source = '<ul>{{#people}}<li>{{#link}}{{name}}{{/link}}</li>{{/people}}</ul>'; + function link(options) { return '<a href="/people/' + this.id + '">' + options.fn(this) + '</a>'; - }; - var data = { "people": [ - { "name": "Alan", "id": 1 }, - { "name": "Yehuda", "id": 2 } + } + var data = { 'people': [ + { 'name': 'Alan', 'id': 1 }, + { 'name': 'Yehuda', 'id': 2 } ]}; - shouldCompileTo(source, [data, {link: link}], "<ul><li><a href=\"/people/1\">Alan</a></li><li><a href=\"/people/2\">Yehuda</a></li></ul>"); + shouldCompileTo(source, [data, {link: link}], '<ul><li><a href=\"/people/1\">Alan</a></li><li><a href=\"/people/2\">Yehuda</a></li></ul>'); }); - it("block helper for undefined value", function() { - shouldCompileTo("{{#empty}}shouldn't render{{/empty}}", {}, ""); + it('block helper for undefined value', function() { + shouldCompileTo("{{#empty}}shouldn't render{{/empty}}", {}, ''); }); - it("block helper passing a new context", function() { - var string = "{{#form yehuda}}<p>{{name}}</p>{{/form}}"; + it('block helper passing a new context', function() { + var string = '{{#form yehuda}}<p>{{name}}</p>{{/form}}'; var template = CompilerContext.compile(string); - var result = template({yehuda: {name: "Yehuda"}}, { helpers: {form: function(context, options) { return "<form>" + options.fn(context) + "</form>"; }}}); - equal(result, "<form><p>Yehuda</p></form>", "Context variable resolved"); + var result = template({yehuda: {name: 'Yehuda'}}, { helpers: {form: function(context, options) { return '<form>' + options.fn(context) + '</form>'; }}}); + equal(result, '<form><p>Yehuda</p></form>', 'Context variable resolved'); }); - it("block helper passing a complex path context", function() { - var string = "{{#form yehuda/cat}}<p>{{name}}</p>{{/form}}"; + it('block helper passing a complex path context', function() { + var string = '{{#form yehuda/cat}}<p>{{name}}</p>{{/form}}'; var template = CompilerContext.compile(string); - var result = template({yehuda: {name: "Yehuda", cat: {name: "Harold"}}}, { helpers: {form: function(context, options) { return "<form>" + options.fn(context) + "</form>"; }}}); - equal(result, "<form><p>Harold</p></form>", "Complex path variable resolved"); + var result = template({yehuda: {name: 'Yehuda', cat: {name: 'Harold'}}}, { helpers: {form: function(context, options) { return '<form>' + options.fn(context) + '</form>'; }}}); + equal(result, '<form><p>Harold</p></form>', 'Complex path variable resolved'); }); - it("nested block helpers", function() { - var string = "{{#form yehuda}}<p>{{name}}</p>{{#link}}Hello{{/link}}{{/form}}"; + it('nested block helpers', function() { + var string = '{{#form yehuda}}<p>{{name}}</p>{{#link}}Hello{{/link}}{{/form}}'; var template = CompilerContext.compile(string); var result = template({ - yehuda: {name: "Yehuda" } + yehuda: {name: 'Yehuda' } }, { helpers: { - link: function(options) { return "<a href='" + this.name + "'>" + options.fn(this) + "</a>"; }, - form: function(context, options) { return "<form>" + options.fn(context) + "</form>"; } + link: function(options) { return '<a href="' + this.name + '">' + options.fn(this) + '</a>'; }, + form: function(context, options) { return '<form>' + options.fn(context) + '</form>'; } } }); - equal(result, "<form><p>Yehuda</p><a href='Yehuda'>Hello</a></form>", "Both blocks executed"); + equal(result, '<form><p>Yehuda</p><a href="Yehuda">Hello</a></form>', 'Both blocks executed'); }); - it("block helper inverted sections", function() { - var string = "{{#list people}}{{name}}{{^}}<em>Nobody's here</em>{{/list}}"; - var list = function(context, options) { + it('block helper inverted sections', function() { + var string = '{{#list people}}{{name}}{{^}}<em>Nobody\'s here</em>{{/list}}'; + function list(context, options) { if (context.length > 0) { - var out = "<ul>"; - for(var i = 0,j=context.length; i < j; i++) { - out += "<li>"; + var out = '<ul>'; + for (var i = 0, j = context.length; i < j; i++) { + out += '<li>'; out += options.fn(context[i]); - out += "</li>"; + out += '</li>'; } - out += "</ul>"; + out += '</ul>'; return out; } else { - return "<p>" + options.inverse(this) + "</p>"; + return '<p>' + options.inverse(this) + '</p>'; } - }; + } - var hash = {people: [{name: "Alan"}, {name: "Yehuda"}]}; + var hash = {people: [{name: 'Alan'}, {name: 'Yehuda'}]}; var empty = {people: []}; var rootMessage = { people: [], - message: "Nobody's here" + message: 'Nobody\'s here' }; - var messageString = "{{#list people}}Hello{{^}}{{message}}{{/list}}"; + var messageString = '{{#list people}}Hello{{^}}{{message}}{{/list}}'; // the meaning here may be kind of hard to catch, but list.not is always called, // so we should see the output of both - shouldCompileTo(string, [hash, { list: list }], "<ul><li>Alan</li><li>Yehuda</li></ul>", "an inverse wrapper is passed in as a new context"); - shouldCompileTo(string, [empty, { list: list }], "<p><em>Nobody's here</em></p>", "an inverse wrapper can be optionally called"); - shouldCompileTo(messageString, [rootMessage, { list: list }], "<p>Nobody's here</p>", "the context of an inverse is the parent of the block"); + shouldCompileTo(string, [hash, { list: list }], '<ul><li>Alan</li><li>Yehuda</li></ul>', 'an inverse wrapper is passed in as a new context'); + shouldCompileTo(string, [empty, { list: list }], '<p><em>Nobody\'s here</em></p>', 'an inverse wrapper can be optionally called'); + shouldCompileTo(messageString, [rootMessage, { list: list }], '<p>Nobody's here</p>', 'the context of an inverse is the parent of the block'); }); it('pathed lambas with parameters', function() { @@ -178,43 +177,47 @@ describe('helpers', function() { shouldCompileTo('{{hash/helper 1}}', [hash, helpers], 'winning'); }); - describe("helpers hash", function() { - it("providing a helpers hash", function() { - shouldCompileTo("Goodbye {{cruel}} {{world}}!", [{cruel: "cruel"}, {world: function() { return "world"; }}], "Goodbye cruel world!", - "helpers hash is available"); + describe('helpers hash', function() { + it('providing a helpers hash', function() { + shouldCompileTo('Goodbye {{cruel}} {{world}}!', [{cruel: 'cruel'}, {world: function() { return 'world'; }}], 'Goodbye cruel world!', + 'helpers hash is available'); - shouldCompileTo("Goodbye {{#iter}}{{cruel}} {{world}}{{/iter}}!", [{iter: [{cruel: "cruel"}]}, {world: function() { return "world"; }}], - "Goodbye cruel world!", "helpers hash is available inside other blocks"); + shouldCompileTo('Goodbye {{#iter}}{{cruel}} {{world}}{{/iter}}!', [{iter: [{cruel: 'cruel'}]}, {world: function() { return 'world'; }}], + 'Goodbye cruel world!', 'helpers hash is available inside other blocks'); }); - it("in cases of conflict, helpers win", function() { - shouldCompileTo("{{{lookup}}}", [{lookup: 'Explicit'}, {lookup: function() { return 'helpers'; }}], "helpers", - "helpers hash has precedence escaped expansion"); - shouldCompileTo("{{lookup}}", [{lookup: 'Explicit'}, {lookup: function() { return 'helpers'; }}], "helpers", - "helpers hash has precedence simple expansion"); + it('in cases of conflict, helpers win', function() { + shouldCompileTo('{{{lookup}}}', [{lookup: 'Explicit'}, {lookup: function() { return 'helpers'; }}], 'helpers', + 'helpers hash has precedence escaped expansion'); + shouldCompileTo('{{lookup}}', [{lookup: 'Explicit'}, {lookup: function() { return 'helpers'; }}], 'helpers', + 'helpers hash has precedence simple expansion'); }); - it("the helpers hash is available is nested contexts", function() { - shouldCompileTo("{{#outer}}{{#inner}}{{helper}}{{/inner}}{{/outer}}", - [{'outer': {'inner': {'unused':[]}}}, {'helper': function() { return 'helper'; }}], "helper", - "helpers hash is available in nested contexts."); + it('the helpers hash is available is nested contexts', function() { + shouldCompileTo( + '{{#outer}}{{#inner}}{{helper}}{{/inner}}{{/outer}}', + [ + {'outer': {'inner': {'unused': []}}}, + {'helper': function() { return 'helper'; }} + ], + 'helper', + 'helpers hash is available in nested contexts.'); }); - it("the helper hash should augment the global hash", function() { + it('the helper hash should augment the global hash', function() { handlebarsEnv.registerHelper('test_helper', function() { return 'found it!'; }); shouldCompileTo( - "{{test_helper}} {{#if cruel}}Goodbye {{cruel}} {{world}}!{{/if}}", [ - {cruel: "cruel"}, - {world: function() { return "world!"; }} + '{{test_helper}} {{#if cruel}}Goodbye {{cruel}} {{world}}!{{/if}}', [ + {cruel: 'cruel'}, + {world: function() { return 'world!'; }} ], - "found it! Goodbye cruel world!!"); + 'found it! Goodbye cruel world!!'); }); }); describe('registration', function() { it('unregisters', function() { - var helpers = handlebarsEnv.helpers; handlebarsEnv.helpers = {}; handlebarsEnv.registerHelper('foo', function() { @@ -230,134 +233,128 @@ describe('helpers', function() { handlebarsEnv.registerHelper({ 'if': helpers['if'], - world: function() { return "world!"; }, - test_helper: function() { return 'found it!'; } + world: function() { return 'world!'; }, + testHelper: function() { return 'found it!'; } }); shouldCompileTo( - "{{test_helper}} {{#if cruel}}Goodbye {{cruel}} {{world}}!{{/if}}", - [{cruel: "cruel"}], - "found it! Goodbye cruel world!!"); + '{{testHelper}} {{#if cruel}}Goodbye {{cruel}} {{world}}!{{/if}}', + [{cruel: 'cruel'}], + 'found it! Goodbye cruel world!!'); }); it('fails with multiple and args', function() { shouldThrow(function() { handlebarsEnv.registerHelper({ - world: function() { return "world!"; }, - test_helper: function() { return 'found it!'; } + world: function() { return 'world!'; }, + testHelper: function() { return 'found it!'; } }, {}); }, Error, 'Arg not supported with multiple helpers'); }); }); - it("decimal number literals work", function() { - var string = 'Message: {{hello -1.2 1.2}}'; - var hash = {}; - var helpers = {hello: function(times, times2) { - if(typeof times !== 'number') { times = "NaN"; } - if(typeof times2 !== 'number') { times2 = "NaN"; } - return "Hello " + times + " " + times2 + " times"; + it('decimal number literals work', function() { + var string = 'Message: {{hello -1.2 1.2}}'; + var helpers = {hello: function(times, times2) { + if (typeof times !== 'number') { times = 'NaN'; } + if (typeof times2 !== 'number') { times2 = 'NaN'; } + return 'Hello ' + times + ' ' + times2 + ' times'; }}; - shouldCompileTo(string, [hash, helpers], "Message: Hello -1.2 1.2 times", "template with a negative integer literal"); + shouldCompileTo(string, [{}, helpers], 'Message: Hello -1.2 1.2 times', 'template with a negative integer literal'); }); - it("negative number literals work", function() { - var string = 'Message: {{hello -12}}'; - var hash = {}; - var helpers = {hello: function(times) { - if(typeof times !== 'number') { times = "NaN"; } - return "Hello " + times + " times"; + it('negative number literals work', function() { + var string = 'Message: {{hello -12}}'; + var helpers = {hello: function(times) { + if (typeof times !== 'number') { times = 'NaN'; } + return 'Hello ' + times + ' times'; }}; - shouldCompileTo(string, [hash, helpers], "Message: Hello -12 times", "template with a negative integer literal"); + shouldCompileTo(string, [{}, helpers], 'Message: Hello -12 times', 'template with a negative integer literal'); }); - describe("String literal parameters", function() { - it("simple literals work", function() { - var string = 'Message: {{hello "world" 12 true false}}'; - var hash = {}; - var helpers = {hello: function(param, times, bool1, bool2) { - if(typeof times !== 'number') { times = "NaN"; } - if(typeof bool1 !== 'boolean') { bool1 = "NaB"; } - if(typeof bool2 !== 'boolean') { bool2 = "NaB"; } - return "Hello " + param + " " + times + " times: " + bool1 + " " + bool2; + describe('String literal parameters', function() { + it('simple literals work', function() { + var string = 'Message: {{hello "world" 12 true false}}'; + var helpers = {hello: function(param, times, bool1, bool2) { + if (typeof times !== 'number') { times = 'NaN'; } + if (typeof bool1 !== 'boolean') { bool1 = 'NaB'; } + if (typeof bool2 !== 'boolean') { bool2 = 'NaB'; } + return 'Hello ' + param + ' ' + times + ' times: ' + bool1 + ' ' + bool2; }}; - shouldCompileTo(string, [hash, helpers], "Message: Hello world 12 times: true false", "template with a simple String literal"); + shouldCompileTo(string, [{}, helpers], 'Message: Hello world 12 times: true false', 'template with a simple String literal'); }); - it("using a quote in the middle of a parameter raises an error", function() { - var string = 'Message: {{hello wo"rld"}}'; + it('using a quote in the middle of a parameter raises an error', function() { + var string = 'Message: {{hello wo"rld"}}'; shouldThrow(function() { CompilerContext.compile(string); }, Error); }); - it("escaping a String is possible", function(){ - var string = 'Message: {{{hello "\\"world\\""}}}'; - var hash = {}; - var helpers = {hello: function(param) { return "Hello " + param; }}; - shouldCompileTo(string, [hash, helpers], "Message: Hello \"world\"", "template with an escaped String literal"); + it('escaping a String is possible', function() { + var string = 'Message: {{{hello "\\"world\\""}}}'; + var helpers = {hello: function(param) { return 'Hello ' + param; }}; + shouldCompileTo(string, [{}, helpers], 'Message: Hello "world"', 'template with an escaped String literal'); }); it("it works with ' marks", function() { - var string = 'Message: {{{hello "Alan\'s world"}}}'; - var hash = {}; - var helpers = {hello: function(param) { return "Hello " + param; }}; - shouldCompileTo(string, [hash, helpers], "Message: Hello Alan's world", "template with a ' mark"); + var string = 'Message: {{{hello "Alan\'s world"}}}'; + var helpers = {hello: function(param) { return 'Hello ' + param; }}; + shouldCompileTo(string, [{}, helpers], "Message: Hello Alan's world", "template with a ' mark"); }); }); - it("negative number literals work", function() { - var string = 'Message: {{hello -12}}'; - var hash = {}; - var helpers = {hello: function(times) { - if(typeof times !== 'number') { times = "NaN"; } - return "Hello " + times + " times"; + it('negative number literals work', function() { + var string = 'Message: {{hello -12}}'; + var helpers = {hello: function(times) { + if (typeof times !== 'number') { times = 'NaN'; } + return 'Hello ' + times + ' times'; }}; - shouldCompileTo(string, [hash, helpers], "Message: Hello -12 times", "template with a negative integer literal"); + shouldCompileTo(string, [{}, helpers], 'Message: Hello -12 times', 'template with a negative integer literal'); }); - describe("multiple parameters", function() { - it("simple multi-params work", function() { - var string = 'Message: {{goodbye cruel world}}'; - var hash = {cruel: "cruel", world: "world"}; - var helpers = {goodbye: function(cruel, world) { return "Goodbye " + cruel + " " + world; }}; - shouldCompileTo(string, [hash, helpers], "Message: Goodbye cruel world", "regular helpers with multiple params"); + describe('multiple parameters', function() { + it('simple multi-params work', function() { + var string = 'Message: {{goodbye cruel world}}'; + var hash = {cruel: 'cruel', world: 'world'}; + var helpers = {goodbye: function(cruel, world) { return 'Goodbye ' + cruel + ' ' + world; }}; + shouldCompileTo(string, [hash, helpers], 'Message: Goodbye cruel world', 'regular helpers with multiple params'); }); - it("block multi-params work", function() { - var string = 'Message: {{#goodbye cruel world}}{{greeting}} {{adj}} {{noun}}{{/goodbye}}'; - var hash = {cruel: "cruel", world: "world"}; + it('block multi-params work', function() { + var string = 'Message: {{#goodbye cruel world}}{{greeting}} {{adj}} {{noun}}{{/goodbye}}'; + var hash = {cruel: 'cruel', world: 'world'}; var helpers = {goodbye: function(cruel, world, options) { - return options.fn({greeting: "Goodbye", adj: cruel, noun: world}); + return options.fn({greeting: 'Goodbye', adj: cruel, noun: world}); }}; - shouldCompileTo(string, [hash, helpers], "Message: Goodbye cruel world", "block helpers with multiple params"); + shouldCompileTo(string, [hash, helpers], 'Message: Goodbye cruel world', 'block helpers with multiple params'); }); }); describe('hash', function() { - it("helpers can take an optional hash", function() { + it('helpers can take an optional hash', function() { var template = CompilerContext.compile('{{goodbye cruel="CRUEL" world="WORLD" times=12}}'); var helpers = { goodbye: function(options) { - return "GOODBYE " + options.hash.cruel + " " + options.hash.world + " " + options.hash.times + " TIMES"; + return 'GOODBYE ' + options.hash.cruel + ' ' + options.hash.world + ' ' + options.hash.times + ' TIMES'; } }; var context = {}; var result = template(context, {helpers: helpers}); - equals(result, "GOODBYE CRUEL WORLD 12 TIMES", "Helper output hash"); + equals(result, 'GOODBYE CRUEL WORLD 12 TIMES', 'Helper output hash'); }); - it("helpers can take an optional hash with booleans", function() { + it('helpers can take an optional hash with booleans', function() { var helpers = { goodbye: function(options) { if (options.hash.print === true) { - return "GOODBYE " + options.hash.cruel + " " + options.hash.world; + return 'GOODBYE ' + options.hash.cruel + ' ' + options.hash.world; } else if (options.hash.print === false) { - return "NOT PRINTING"; + return 'NOT PRINTING'; } else { - return "THIS SHOULD NOT HAPPEN"; + return 'THIS SHOULD NOT HAPPEN'; } } }; @@ -366,161 +363,161 @@ describe('helpers', function() { var template = CompilerContext.compile('{{goodbye cruel="CRUEL" world="WORLD" print=true}}'); var result = template(context, {helpers: helpers}); - equals(result, "GOODBYE CRUEL WORLD", "Helper output hash"); + equals(result, 'GOODBYE CRUEL WORLD', 'Helper output hash'); template = CompilerContext.compile('{{goodbye cruel="CRUEL" world="WORLD" print=false}}'); result = template(context, {helpers: helpers}); - equals(result, "NOT PRINTING", "Boolean helper parameter honored"); + equals(result, 'NOT PRINTING', 'Boolean helper parameter honored'); }); - it("block helpers can take an optional hash", function() { + it('block helpers can take an optional hash', function() { var template = CompilerContext.compile('{{#goodbye cruel="CRUEL" times=12}}world{{/goodbye}}'); var helpers = { goodbye: function(options) { - return "GOODBYE " + options.hash.cruel + " " + options.fn(this) + " " + options.hash.times + " TIMES"; + return 'GOODBYE ' + options.hash.cruel + ' ' + options.fn(this) + ' ' + options.hash.times + ' TIMES'; } }; var result = template({}, {helpers: helpers}); - equals(result, "GOODBYE CRUEL world 12 TIMES", "Hash parameters output"); + equals(result, 'GOODBYE CRUEL world 12 TIMES', 'Hash parameters output'); }); - it("block helpers can take an optional hash with single quoted stings", function() { - var template = CompilerContext.compile("{{#goodbye cruel='CRUEL' times=12}}world{{/goodbye}}"); + it('block helpers can take an optional hash with single quoted stings', function() { + var template = CompilerContext.compile('{{#goodbye cruel="CRUEL" times=12}}world{{/goodbye}}'); var helpers = { goodbye: function(options) { - return "GOODBYE " + options.hash.cruel + " " + options.fn(this) + " " + options.hash.times + " TIMES"; + return 'GOODBYE ' + options.hash.cruel + ' ' + options.fn(this) + ' ' + options.hash.times + ' TIMES'; } }; var result = template({}, {helpers: helpers}); - equals(result, "GOODBYE CRUEL world 12 TIMES", "Hash parameters output"); + equals(result, 'GOODBYE CRUEL world 12 TIMES', 'Hash parameters output'); }); - it("block helpers can take an optional hash with booleans", function() { + it('block helpers can take an optional hash with booleans', function() { var helpers = { goodbye: function(options) { if (options.hash.print === true) { - return "GOODBYE " + options.hash.cruel + " " + options.fn(this); + return 'GOODBYE ' + options.hash.cruel + ' ' + options.fn(this); } else if (options.hash.print === false) { - return "NOT PRINTING"; + return 'NOT PRINTING'; } else { - return "THIS SHOULD NOT HAPPEN"; + return 'THIS SHOULD NOT HAPPEN'; } } }; var template = CompilerContext.compile('{{#goodbye cruel="CRUEL" print=true}}world{{/goodbye}}'); var result = template({}, {helpers: helpers}); - equals(result, "GOODBYE CRUEL world", "Boolean hash parameter honored"); + equals(result, 'GOODBYE CRUEL world', 'Boolean hash parameter honored'); template = CompilerContext.compile('{{#goodbye cruel="CRUEL" print=false}}world{{/goodbye}}'); result = template({}, {helpers: helpers}); - equals(result, "NOT PRINTING", "Boolean hash parameter honored"); + equals(result, 'NOT PRINTING', 'Boolean hash parameter honored'); }); }); - 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() { shouldThrow(function() { - var template = CompilerContext.compile("{{hello}} {{link_to world}}"); + var template = CompilerContext.compile('{{hello}} {{link_to world}}'); template({}); - }, undefined, /Missing helper: 'link_to'/); + }, undefined, /Missing helper: "link_to"/); }); - it("if a context is not found, custom helperMissing is used", function() { - var string = "{{hello}} {{link_to world}}"; - var context = { hello: "Hello", world: "world" }; + it('if a context is not found, custom helperMissing is used', function() { + var string = '{{hello}} {{link_to world}}'; + var context = { hello: 'Hello', world: 'world' }; var helpers = { helperMissing: function(mesg, options) { - if(options.name === "link_to") { - return new Handlebars.SafeString("<a>" + mesg + "</a>"); + if (options.name === 'link_to') { + return new Handlebars.SafeString('<a>' + mesg + '</a>'); } } }; - shouldCompileTo(string, [context, helpers], "Hello <a>world</a>"); + shouldCompileTo(string, [context, helpers], 'Hello <a>world</a>'); }); - it("if a value is not found, custom helperMissing is used", function() { - var string = "{{hello}} {{link_to}}"; - var context = { hello: "Hello", world: "world" }; + it('if a value is not found, custom helperMissing is used', function() { + var string = '{{hello}} {{link_to}}'; + var context = { hello: 'Hello', world: 'world' }; var helpers = { helperMissing: function(options) { - if(options.name === "link_to") { - return new Handlebars.SafeString("<a>winning</a>"); + if (options.name === 'link_to') { + return new Handlebars.SafeString('<a>winning</a>'); } } }; - shouldCompileTo(string, [context, helpers], "Hello <a>winning</a>"); + shouldCompileTo(string, [context, helpers], 'Hello <a>winning</a>'); }); }); - describe("knownHelpers", function() { - it("Known helper should render helper", function() { - var template = CompilerContext.compile("{{hello}}", {knownHelpers: {"hello" : true}}); + describe('knownHelpers', function() { + it('Known helper should render helper', function() { + var template = CompilerContext.compile('{{hello}}', {knownHelpers: {hello: true}}); - var result = template({}, {helpers: {hello: function() { return "foo"; }}}); - equal(result, "foo", "'foo' should === '" + result); + var result = template({}, {helpers: {hello: function() { return 'foo'; }}}); + equal(result, 'foo', "'foo' should === '" + result); }); - it("Unknown helper in knownHelpers only mode should be passed as undefined", function() { - var template = CompilerContext.compile("{{typeof hello}}", {knownHelpers: {'typeof': true}, knownHelpersOnly: true}); + it('Unknown helper in knownHelpers only mode should be passed as undefined', function() { + var template = CompilerContext.compile('{{typeof hello}}', {knownHelpers: {'typeof': true}, knownHelpersOnly: true}); - var result = template({}, {helpers: {'typeof': function(arg) { return typeof arg; }, hello: function() { return "foo"; }}}); - equal(result, "undefined", "'undefined' should === '" + result); + var result = template({}, {helpers: {'typeof': function(arg) { return typeof arg; }, hello: function() { return 'foo'; }}}); + equal(result, 'undefined', "'undefined' should === '" + result); }); - it("Builtin helpers available in knownHelpers only mode", function() { - var template = CompilerContext.compile("{{#unless foo}}bar{{/unless}}", {knownHelpersOnly: true}); + it('Builtin helpers available in knownHelpers only mode', function() { + var template = CompilerContext.compile('{{#unless foo}}bar{{/unless}}', {knownHelpersOnly: true}); var result = template({}); - equal(result, "bar", "'bar' should === '" + result); + equal(result, 'bar', "'bar' should === '" + result); }); - it("Field lookup works in knownHelpers only mode", function() { - var template = CompilerContext.compile("{{foo}}", {knownHelpersOnly: true}); + it('Field lookup works in knownHelpers only mode', function() { + var template = CompilerContext.compile('{{foo}}', {knownHelpersOnly: true}); var result = template({foo: 'bar'}); - equal(result, "bar", "'bar' should === '" + result); + equal(result, 'bar', "'bar' should === '" + result); }); - it("Conditional blocks work in knownHelpers only mode", function() { - var template = CompilerContext.compile("{{#foo}}bar{{/foo}}", {knownHelpersOnly: true}); + it('Conditional blocks work in knownHelpers only mode', function() { + var template = CompilerContext.compile('{{#foo}}bar{{/foo}}', {knownHelpersOnly: true}); var result = template({foo: 'baz'}); - equal(result, "bar", "'bar' should === '" + result); + equal(result, 'bar', "'bar' should === '" + result); }); - it("Invert blocks work in knownHelpers only mode", function() { - var template = CompilerContext.compile("{{^foo}}bar{{/foo}}", {knownHelpersOnly: true}); + it('Invert blocks work in knownHelpers only mode', function() { + var template = CompilerContext.compile('{{^foo}}bar{{/foo}}', {knownHelpersOnly: true}); var result = template({foo: false}); - equal(result, "bar", "'bar' should === '" + result); + equal(result, 'bar', "'bar' should === '" + result); }); - it("Functions are bound to the context in knownHelpers only mode", function() { - var template = CompilerContext.compile("{{foo}}", {knownHelpersOnly: true}); + it('Functions are bound to the context in knownHelpers only mode', function() { + var template = CompilerContext.compile('{{foo}}', {knownHelpersOnly: true}); var result = template({foo: function() { return this.bar; }, bar: 'bar'}); - equal(result, "bar", "'bar' should === '" + result); + equal(result, 'bar', "'bar' should === '" + result); }); - it("Unknown helper call in knownHelpers only mode should throw", function() { + it('Unknown helper call in knownHelpers only mode should throw', function() { shouldThrow(function() { - CompilerContext.compile("{{typeof hello}}", {knownHelpersOnly: true}); + CompilerContext.compile('{{typeof hello}}', {knownHelpersOnly: true}); }, Error); }); }); - describe("blockHelperMissing", function() { - it("lambdas are resolved by blockHelperMissing, not handlebars proper", function() { - var string = "{{#truthy}}yep{{/truthy}}"; + describe('blockHelperMissing', function() { + it('lambdas are resolved by blockHelperMissing, not handlebars proper', function() { + var string = '{{#truthy}}yep{{/truthy}}'; var data = { truthy: function() { return true; } }; - shouldCompileTo(string, data, "yep"); + shouldCompileTo(string, data, 'yep'); }); - it("lambdas resolved by blockHelperMissing are bound to the context", function() { - var string = "{{#truthy}}yep{{/truthy}}"; + it('lambdas resolved by blockHelperMissing are bound to the context', function() { + var string = '{{#truthy}}yep{{/truthy}}'; var boundData = { truthy: function() { return this.truthiness(); }, truthiness: function() { return false; } }; - shouldCompileTo(string, boundData, ""); + shouldCompileTo(string, boundData, ''); }); }); @@ -528,13 +525,13 @@ describe('helpers', function() { var context = {}; var helpers = { blockHelperMissing: function() { - return 'missing: ' + arguments[arguments.length-1].name; + return 'missing: ' + arguments[arguments.length - 1].name; }, helperMissing: function() { - return 'helper missing: ' + arguments[arguments.length-1].name; + return 'helper missing: ' + arguments[arguments.length - 1].name; }, helper: function() { - return 'ran: ' + arguments[arguments.length-1].name; + return 'ran: ' + arguments[arguments.length - 1].name; } }; @@ -554,7 +551,7 @@ describe('helpers', function() { shouldCompileTo('{{#helper 1}}{{/helper}}', [context, helpers], 'ran: helper'); }); it('should include in known helper calls', function() { - var template = CompilerContext.compile("{{helper}}", {knownHelpers: {'helper': true}, knownHelpersOnly: true}); + var template = CompilerContext.compile('{{helper}}', {knownHelpers: {'helper': true}, knownHelpersOnly: true}); equal(template({}, {helpers: helpers}), 'ran: helper'); }); @@ -569,8 +566,8 @@ describe('helpers', function() { }); describe('name conflicts', function() { - it("helpers take precedence over same-named context properties", function() { - var template = CompilerContext.compile("{{goodbye}} {{cruel world}}"); + it('helpers take precedence over same-named context properties', function() { + var template = CompilerContext.compile('{{goodbye}} {{cruel world}}'); var helpers = { goodbye: function() { @@ -578,21 +575,21 @@ describe('helpers', function() { }, cruel: function(world) { - return "cruel " + world.toUpperCase(); + return 'cruel ' + world.toUpperCase(); } }; var context = { - goodbye: "goodbye", - world: "world" + goodbye: 'goodbye', + world: 'world' }; var result = template(context, {helpers: helpers}); - equals(result, "GOODBYE cruel WORLD", "Helper executed"); + equals(result, 'GOODBYE cruel WORLD', 'Helper executed'); }); - it("helpers take precedence over same-named context properties$", function() { - var template = CompilerContext.compile("{{#goodbye}} {{cruel world}}{{/goodbye}}"); + it('helpers take precedence over same-named context properties$', function() { + var template = CompilerContext.compile('{{#goodbye}} {{cruel world}}{{/goodbye}}'); var helpers = { goodbye: function(options) { @@ -600,21 +597,21 @@ describe('helpers', function() { }, cruel: function(world) { - return "cruel " + world.toUpperCase(); + return 'cruel ' + world.toUpperCase(); } }; var context = { - goodbye: "goodbye", - world: "world" + goodbye: 'goodbye', + world: 'world' }; var result = template(context, {helpers: helpers}); - equals(result, "GOODBYE cruel WORLD", "Helper executed"); + equals(result, 'GOODBYE cruel WORLD', 'Helper executed'); }); - it("Scoped names take precedence over helpers", function() { - var template = CompilerContext.compile("{{this.goodbye}} {{cruel world}} {{cruel this.goodbye}}"); + it('Scoped names take precedence over helpers', function() { + var template = CompilerContext.compile('{{this.goodbye}} {{cruel world}} {{cruel this.goodbye}}'); var helpers = { goodbye: function() { @@ -622,21 +619,21 @@ describe('helpers', function() { }, cruel: function(world) { - return "cruel " + world.toUpperCase(); + return 'cruel ' + world.toUpperCase(); } }; var context = { - goodbye: "goodbye", - world: "world" + goodbye: 'goodbye', + world: 'world' }; var result = template(context, {helpers: helpers}); - equals(result, "goodbye cruel WORLD cruel GOODBYE", "Helper not executed"); + equals(result, 'goodbye cruel WORLD cruel GOODBYE', 'Helper not executed'); }); - it("Scoped names take precedence over block helpers", function() { - var template = CompilerContext.compile("{{#goodbye}} {{cruel world}}{{/goodbye}} {{this.goodbye}}"); + it('Scoped names take precedence over block helpers', function() { + var template = CompilerContext.compile('{{#goodbye}} {{cruel world}}{{/goodbye}} {{this.goodbye}}'); var helpers = { goodbye: function(options) { @@ -644,17 +641,17 @@ describe('helpers', function() { }, cruel: function(world) { - return "cruel " + world.toUpperCase(); + return 'cruel ' + world.toUpperCase(); } }; var context = { - goodbye: "goodbye", - world: "world" + goodbye: 'goodbye', + world: 'world' }; var result = template(context, {helpers: helpers}); - equals(result, "GOODBYE cruel WORLD goodbye", "Helper executed"); + equals(result, 'GOODBYE cruel WORLD goodbye', 'Helper executed'); }); }); diff --git a/spec/javascript-compiler.js b/spec/javascript-compiler.js index fb78658..28e6988 100644 --- a/spec/javascript-compiler.js +++ b/spec/javascript-compiler.js @@ -1,4 +1,3 @@ -/*global Handlebars, beforeEach, handlebarsEnv, shouldCompileTo */ describe('javascript-compiler api', function() { if (!Handlebars.JavaScriptCompiler) { return; @@ -17,13 +16,15 @@ describe('javascript-compiler api', function() { handlebarsEnv.JavaScriptCompiler.prototype.nameLookup = function(parent, name) { return parent + '.bar_' + name; }; - shouldCompileTo("{{foo}}", { bar_foo: "food" }, "food"); + /*eslint-disable camelcase */ + shouldCompileTo('{{foo}}', { bar_foo: 'food' }, 'food'); + /*eslint-enable camelcase */ }); // Tests nameLookup dot vs. bracket behavior. Bracket is required in certain cases // to avoid errors in older browsers. it('should handle reserved words', function() { - shouldCompileTo("{{foo}} {{~null~}}", { foo: "food" }, "food"); + shouldCompileTo('{{foo}} {{~null~}}', { foo: 'food' }, 'food'); }); }); describe('#compilerInfo', function() { @@ -45,7 +46,7 @@ describe('javascript-compiler api', function() { throw new Error('It didn\'t work'); } }; - shouldCompileTo("{{foo}} ", { foo: "food" }, "food "); + shouldCompileTo('{{foo}} ', { foo: 'food' }, 'food '); }); }); describe('buffer', function() { @@ -65,13 +66,13 @@ describe('javascript-compiler api', function() { handlebarsEnv.JavaScriptCompiler.prototype.initializeBuffer = function() { return this.quotedString('foo_'); }; - shouldCompileTo("{{foo}} ", { foo: "food" }, "foo_food "); + shouldCompileTo('{{foo}} ', { foo: 'food' }, 'foo_food '); }); it('should allow append buffer override', function() { handlebarsEnv.JavaScriptCompiler.prototype.appendToBuffer = function(string) { return $superAppend.call(this, [string, ' + "_foo"']); }; - shouldCompileTo("{{foo}}", { foo: "food" }, "food_foo"); + shouldCompileTo('{{foo}}', { foo: 'food' }, 'food_foo'); }); }); }); diff --git a/spec/parser.js b/spec/parser.js index d799e08..c378874 100644 --- a/spec/parser.js +++ b/spec/parser.js @@ -1,235 +1,234 @@ -/*global Handlebars, shouldThrow */ describe('parser', function() { if (!Handlebars.print) { return; } - function ast_for(template) { + function astFor(template) { var ast = Handlebars.parse(template); return Handlebars.print(ast); } it('parses simple mustaches', function() { - equals(ast_for('{{123}}'), "{{ NUMBER{123} [] }}\n"); - equals(ast_for('{{"foo"}}'), '{{ "foo" [] }}\n'); - equals(ast_for('{{false}}'), '{{ BOOLEAN{false} [] }}\n'); - equals(ast_for('{{true}}'), '{{ BOOLEAN{true} [] }}\n'); - equals(ast_for('{{foo}}'), "{{ PATH:foo [] }}\n"); - equals(ast_for('{{foo?}}'), "{{ PATH:foo? [] }}\n"); - equals(ast_for('{{foo_}}'), "{{ PATH:foo_ [] }}\n"); - equals(ast_for('{{foo-}}'), "{{ PATH:foo- [] }}\n"); - equals(ast_for('{{foo:}}'), "{{ PATH:foo: [] }}\n"); + equals(astFor('{{123}}'), '{{ NUMBER{123} [] }}\n'); + equals(astFor('{{"foo"}}'), '{{ "foo" [] }}\n'); + equals(astFor('{{false}}'), '{{ BOOLEAN{false} [] }}\n'); + equals(astFor('{{true}}'), '{{ BOOLEAN{true} [] }}\n'); + equals(astFor('{{foo}}'), '{{ PATH:foo [] }}\n'); + equals(astFor('{{foo?}}'), '{{ PATH:foo? [] }}\n'); + equals(astFor('{{foo_}}'), '{{ PATH:foo_ [] }}\n'); + equals(astFor('{{foo-}}'), '{{ PATH:foo- [] }}\n'); + equals(astFor('{{foo:}}'), '{{ PATH:foo: [] }}\n'); }); it('parses simple mustaches with data', function() { - equals(ast_for("{{@foo}}"), "{{ @PATH:foo [] }}\n"); + equals(astFor('{{@foo}}'), '{{ @PATH:foo [] }}\n'); }); it('parses simple mustaches with data paths', function() { - equals(ast_for("{{@../foo}}"), "{{ @PATH:foo [] }}\n"); + equals(astFor('{{@../foo}}'), '{{ @PATH:foo [] }}\n'); }); it('parses mustaches with paths', function() { - equals(ast_for("{{foo/bar}}"), "{{ PATH:foo/bar [] }}\n"); + equals(astFor('{{foo/bar}}'), '{{ PATH:foo/bar [] }}\n'); }); it('parses mustaches with this/foo', function() { - equals(ast_for("{{this/foo}}"), "{{ PATH:foo [] }}\n"); + equals(astFor('{{this/foo}}'), '{{ PATH:foo [] }}\n'); }); it('parses mustaches with - in a path', function() { - equals(ast_for("{{foo-bar}}"), "{{ PATH:foo-bar [] }}\n"); + equals(astFor('{{foo-bar}}'), '{{ PATH:foo-bar [] }}\n'); }); it('parses mustaches with parameters', function() { - equals(ast_for("{{foo bar}}"), "{{ PATH:foo [PATH:bar] }}\n"); + equals(astFor('{{foo bar}}'), '{{ PATH:foo [PATH:bar] }}\n'); }); it('parses mustaches with string parameters', function() { - equals(ast_for("{{foo bar \"baz\" }}"), '{{ PATH:foo [PATH:bar, "baz"] }}\n'); + equals(astFor('{{foo bar \"baz\" }}'), '{{ PATH:foo [PATH:bar, "baz"] }}\n'); }); it('parses mustaches with NUMBER parameters', function() { - equals(ast_for("{{foo 1}}"), "{{ PATH:foo [NUMBER{1}] }}\n"); + equals(astFor('{{foo 1}}'), '{{ PATH:foo [NUMBER{1}] }}\n'); }); it('parses mustaches with BOOLEAN parameters', function() { - equals(ast_for("{{foo true}}"), "{{ PATH:foo [BOOLEAN{true}] }}\n"); - equals(ast_for("{{foo false}}"), "{{ PATH:foo [BOOLEAN{false}] }}\n"); + equals(astFor('{{foo true}}'), '{{ PATH:foo [BOOLEAN{true}] }}\n'); + equals(astFor('{{foo false}}'), '{{ PATH:foo [BOOLEAN{false}] }}\n'); }); it('parses mustaches with undefined and null paths', function() { - equals(ast_for("{{undefined}}"), "{{ UNDEFINED [] }}\n"); - equals(ast_for("{{null}}"), "{{ NULL [] }}\n"); + equals(astFor('{{undefined}}'), '{{ UNDEFINED [] }}\n'); + equals(astFor('{{null}}'), '{{ NULL [] }}\n'); }); it('parses mustaches with undefined and null parameters', function() { - equals(ast_for("{{foo undefined null}}"), "{{ PATH:foo [UNDEFINED, NULL] }}\n"); + equals(astFor('{{foo undefined null}}'), '{{ PATH:foo [UNDEFINED, NULL] }}\n'); }); it('parses mutaches with DATA parameters', function() { - equals(ast_for("{{foo @bar}}"), "{{ PATH:foo [@PATH:bar] }}\n"); + equals(astFor('{{foo @bar}}'), '{{ PATH:foo [@PATH:bar] }}\n'); }); it('parses mustaches with hash arguments', function() { - equals(ast_for("{{foo bar=baz}}"), "{{ PATH:foo [] HASH{bar=PATH:baz} }}\n"); - equals(ast_for("{{foo bar=1}}"), "{{ PATH:foo [] HASH{bar=NUMBER{1}} }}\n"); - equals(ast_for("{{foo bar=true}}"), "{{ PATH:foo [] HASH{bar=BOOLEAN{true}} }}\n"); - equals(ast_for("{{foo bar=false}}"), "{{ PATH:foo [] HASH{bar=BOOLEAN{false}} }}\n"); - equals(ast_for("{{foo bar=@baz}}"), "{{ PATH:foo [] HASH{bar=@PATH:baz} }}\n"); + equals(astFor('{{foo bar=baz}}'), '{{ PATH:foo [] HASH{bar=PATH:baz} }}\n'); + equals(astFor('{{foo bar=1}}'), '{{ PATH:foo [] HASH{bar=NUMBER{1}} }}\n'); + equals(astFor('{{foo bar=true}}'), '{{ PATH:foo [] HASH{bar=BOOLEAN{true}} }}\n'); + equals(astFor('{{foo bar=false}}'), '{{ PATH:foo [] HASH{bar=BOOLEAN{false}} }}\n'); + equals(astFor('{{foo bar=@baz}}'), '{{ PATH:foo [] HASH{bar=@PATH:baz} }}\n'); - equals(ast_for("{{foo bar=baz bat=bam}}"), "{{ PATH:foo [] HASH{bar=PATH:baz, bat=PATH:bam} }}\n"); - equals(ast_for("{{foo bar=baz bat=\"bam\"}}"), '{{ PATH:foo [] HASH{bar=PATH:baz, bat="bam"} }}\n'); + equals(astFor('{{foo bar=baz bat=bam}}'), '{{ PATH:foo [] HASH{bar=PATH:baz, bat=PATH:bam} }}\n'); + equals(astFor('{{foo bar=baz bat="bam"}}'), '{{ PATH:foo [] HASH{bar=PATH:baz, bat="bam"} }}\n'); - equals(ast_for("{{foo bat='bam'}}"), '{{ PATH:foo [] HASH{bat="bam"} }}\n'); + equals(astFor("{{foo bat='bam'}}"), '{{ PATH:foo [] HASH{bat="bam"} }}\n'); - equals(ast_for("{{foo omg bar=baz bat=\"bam\"}}"), '{{ PATH:foo [PATH:omg] HASH{bar=PATH:baz, bat="bam"} }}\n'); - equals(ast_for("{{foo omg bar=baz bat=\"bam\" baz=1}}"), '{{ PATH:foo [PATH:omg] HASH{bar=PATH:baz, bat="bam", baz=NUMBER{1}} }}\n'); - equals(ast_for("{{foo omg bar=baz bat=\"bam\" baz=true}}"), '{{ PATH:foo [PATH:omg] HASH{bar=PATH:baz, bat="bam", baz=BOOLEAN{true}} }}\n'); - equals(ast_for("{{foo omg bar=baz bat=\"bam\" baz=false}}"), '{{ PATH:foo [PATH:omg] HASH{bar=PATH:baz, bat="bam", baz=BOOLEAN{false}} }}\n'); + equals(astFor('{{foo omg bar=baz bat=\"bam\"}}'), '{{ PATH:foo [PATH:omg] HASH{bar=PATH:baz, bat="bam"} }}\n'); + equals(astFor('{{foo omg bar=baz bat=\"bam\" baz=1}}'), '{{ PATH:foo [PATH:omg] HASH{bar=PATH:baz, bat="bam", baz=NUMBER{1}} }}\n'); + equals(astFor('{{foo omg bar=baz bat=\"bam\" baz=true}}'), '{{ PATH:foo [PATH:omg] HASH{bar=PATH:baz, bat="bam", baz=BOOLEAN{true}} }}\n'); + equals(astFor('{{foo omg bar=baz bat=\"bam\" baz=false}}'), '{{ PATH:foo [PATH:omg] HASH{bar=PATH:baz, bat="bam", baz=BOOLEAN{false}} }}\n'); }); it('parses contents followed by a mustache', function() { - equals(ast_for("foo bar {{baz}}"), "CONTENT[ \'foo bar \' ]\n{{ PATH:baz [] }}\n"); + equals(astFor('foo bar {{baz}}'), 'CONTENT[ \'foo bar \' ]\n{{ PATH:baz [] }}\n'); }); it('parses a partial', function() { - equals(ast_for("{{> foo }}"), "{{> PARTIAL:foo }}\n"); - equals(ast_for("{{> 'foo' }}"), "{{> PARTIAL:foo }}\n"); - equals(ast_for("{{> 1 }}"), "{{> PARTIAL:1 }}\n"); + equals(astFor('{{> foo }}'), '{{> PARTIAL:foo }}\n'); + equals(astFor('{{> "foo" }}'), '{{> PARTIAL:foo }}\n'); + equals(astFor('{{> 1 }}'), '{{> PARTIAL:1 }}\n'); }); it('parses a partial with context', function() { - equals(ast_for("{{> foo bar}}"), "{{> PARTIAL:foo PATH:bar }}\n"); + equals(astFor('{{> foo bar}}'), '{{> PARTIAL:foo PATH:bar }}\n'); }); it('parses a partial with hash', function() { - equals(ast_for("{{> foo bar=bat}}"), "{{> PARTIAL:foo HASH{bar=PATH:bat} }}\n"); + equals(astFor('{{> foo bar=bat}}'), '{{> PARTIAL:foo HASH{bar=PATH:bat} }}\n'); }); it('parses a partial with context and hash', function() { - equals(ast_for("{{> foo bar bat=baz}}"), "{{> PARTIAL:foo PATH:bar HASH{bat=PATH:baz} }}\n"); + equals(astFor('{{> foo bar bat=baz}}'), '{{> PARTIAL:foo PATH:bar HASH{bat=PATH:baz} }}\n'); }); it('parses a partial with a complex name', function() { - equals(ast_for("{{> shared/partial?.bar}}"), "{{> PARTIAL:shared/partial?.bar }}\n"); + equals(astFor('{{> shared/partial?.bar}}'), '{{> PARTIAL:shared/partial?.bar }}\n'); }); it('parses a comment', function() { - equals(ast_for("{{! this is a comment }}"), "{{! ' this is a comment ' }}\n"); + equals(astFor('{{! this is a comment }}'), "{{! ' this is a comment ' }}\n"); }); it('parses a multi-line comment', function() { - equals(ast_for("{{!\nthis is a multi-line comment\n}}"), "{{! \'\nthis is a multi-line comment\n\' }}\n"); + equals(astFor('{{!\nthis is a multi-line comment\n}}'), "{{! \'\nthis is a multi-line comment\n\' }}\n"); }); it('parses an inverse section', function() { - equals(ast_for("{{#foo}} bar {{^}} baz {{/foo}}"), "BLOCK:\n PATH:foo []\n PROGRAM:\n CONTENT[ ' bar ' ]\n {{^}}\n CONTENT[ ' baz ' ]\n"); + equals(astFor('{{#foo}} bar {{^}} baz {{/foo}}'), "BLOCK:\n PATH:foo []\n PROGRAM:\n CONTENT[ ' bar ' ]\n {{^}}\n CONTENT[ ' baz ' ]\n"); }); it('parses an inverse (else-style) section', function() { - equals(ast_for("{{#foo}} bar {{else}} baz {{/foo}}"), "BLOCK:\n PATH:foo []\n PROGRAM:\n CONTENT[ ' bar ' ]\n {{^}}\n CONTENT[ ' baz ' ]\n"); + equals(astFor('{{#foo}} bar {{else}} baz {{/foo}}'), "BLOCK:\n PATH:foo []\n PROGRAM:\n CONTENT[ ' bar ' ]\n {{^}}\n CONTENT[ ' baz ' ]\n"); }); it('parses multiple inverse sections', function() { - equals(ast_for("{{#foo}} bar {{else if bar}}{{else}} baz {{/foo}}"), "BLOCK:\n PATH:foo []\n PROGRAM:\n CONTENT[ ' bar ' ]\n {{^}}\n BLOCK:\n PATH:if [PATH:bar]\n PROGRAM:\n {{^}}\n CONTENT[ ' baz ' ]\n"); + equals(astFor('{{#foo}} bar {{else if bar}}{{else}} baz {{/foo}}'), "BLOCK:\n PATH:foo []\n PROGRAM:\n CONTENT[ ' bar ' ]\n {{^}}\n BLOCK:\n PATH:if [PATH:bar]\n PROGRAM:\n {{^}}\n CONTENT[ ' baz ' ]\n"); }); it('parses empty blocks', function() { - equals(ast_for("{{#foo}}{{/foo}}"), "BLOCK:\n PATH:foo []\n PROGRAM:\n"); + equals(astFor('{{#foo}}{{/foo}}'), 'BLOCK:\n PATH:foo []\n PROGRAM:\n'); }); it('parses empty blocks with empty inverse section', function() { - equals(ast_for("{{#foo}}{{^}}{{/foo}}"), "BLOCK:\n PATH:foo []\n PROGRAM:\n {{^}}\n"); + equals(astFor('{{#foo}}{{^}}{{/foo}}'), 'BLOCK:\n PATH:foo []\n PROGRAM:\n {{^}}\n'); }); it('parses empty blocks with empty inverse (else-style) section', function() { - equals(ast_for("{{#foo}}{{else}}{{/foo}}"), "BLOCK:\n PATH:foo []\n PROGRAM:\n {{^}}\n"); + equals(astFor('{{#foo}}{{else}}{{/foo}}'), 'BLOCK:\n PATH:foo []\n PROGRAM:\n {{^}}\n'); }); it('parses non-empty blocks with empty inverse section', function() { - equals(ast_for("{{#foo}} bar {{^}}{{/foo}}"), "BLOCK:\n PATH:foo []\n PROGRAM:\n CONTENT[ ' bar ' ]\n {{^}}\n"); + equals(astFor('{{#foo}} bar {{^}}{{/foo}}'), "BLOCK:\n PATH:foo []\n PROGRAM:\n CONTENT[ ' bar ' ]\n {{^}}\n"); }); it('parses non-empty blocks with empty inverse (else-style) section', function() { - equals(ast_for("{{#foo}} bar {{else}}{{/foo}}"), "BLOCK:\n PATH:foo []\n PROGRAM:\n CONTENT[ ' bar ' ]\n {{^}}\n"); + equals(astFor('{{#foo}} bar {{else}}{{/foo}}'), "BLOCK:\n PATH:foo []\n PROGRAM:\n CONTENT[ ' bar ' ]\n {{^}}\n"); }); it('parses empty blocks with non-empty inverse section', function() { - equals(ast_for("{{#foo}}{{^}} bar {{/foo}}"), "BLOCK:\n PATH:foo []\n PROGRAM:\n {{^}}\n CONTENT[ ' bar ' ]\n"); + equals(astFor('{{#foo}}{{^}} bar {{/foo}}'), "BLOCK:\n PATH:foo []\n PROGRAM:\n {{^}}\n CONTENT[ ' bar ' ]\n"); }); it('parses empty blocks with non-empty inverse (else-style) section', function() { - equals(ast_for("{{#foo}}{{else}} bar {{/foo}}"), "BLOCK:\n PATH:foo []\n PROGRAM:\n {{^}}\n CONTENT[ ' bar ' ]\n"); + equals(astFor('{{#foo}}{{else}} bar {{/foo}}'), "BLOCK:\n PATH:foo []\n PROGRAM:\n {{^}}\n CONTENT[ ' bar ' ]\n"); }); it('parses a standalone inverse section', function() { - equals(ast_for("{{^foo}}bar{{/foo}}"), "BLOCK:\n PATH:foo []\n {{^}}\n CONTENT[ 'bar' ]\n"); + equals(astFor('{{^foo}}bar{{/foo}}'), "BLOCK:\n PATH:foo []\n {{^}}\n CONTENT[ 'bar' ]\n"); }); it('throws on old inverse section', function() { shouldThrow(function() { - ast_for("{{else foo}}bar{{/foo}}"); + astFor('{{else foo}}bar{{/foo}}'); }, Error); }); it('parses block with block params', function() { - equals(ast_for("{{#foo as |bar baz|}}content{{/foo}}"), "BLOCK:\n PATH:foo []\n PROGRAM:\n BLOCK PARAMS: [ bar baz ]\n CONTENT[ 'content' ]\n"); + equals(astFor('{{#foo as |bar baz|}}content{{/foo}}'), "BLOCK:\n PATH:foo []\n PROGRAM:\n BLOCK PARAMS: [ bar baz ]\n CONTENT[ 'content' ]\n"); }); it('parses inverse block with block params', function() { - equals(ast_for("{{^foo as |bar baz|}}content{{/foo}}"), "BLOCK:\n PATH:foo []\n {{^}}\n BLOCK PARAMS: [ bar baz ]\n CONTENT[ 'content' ]\n"); + equals(astFor('{{^foo as |bar baz|}}content{{/foo}}'), "BLOCK:\n PATH:foo []\n {{^}}\n BLOCK PARAMS: [ bar baz ]\n CONTENT[ 'content' ]\n"); }); it('parses chained inverse block with block params', function() { - equals(ast_for("{{#foo}}{{else foo as |bar baz|}}content{{/foo}}"), "BLOCK:\n PATH:foo []\n PROGRAM:\n {{^}}\n BLOCK:\n PATH:foo []\n PROGRAM:\n BLOCK PARAMS: [ bar baz ]\n CONTENT[ 'content' ]\n"); + equals(astFor('{{#foo}}{{else foo as |bar baz|}}content{{/foo}}'), "BLOCK:\n PATH:foo []\n PROGRAM:\n {{^}}\n BLOCK:\n PATH:foo []\n PROGRAM:\n BLOCK PARAMS: [ bar baz ]\n CONTENT[ 'content' ]\n"); }); - it("raises if there's a Parse error", function() { + it('raises if there\'s a Parse error', function() { shouldThrow(function() { - ast_for("foo{{^}}bar"); + astFor('foo{{^}}bar'); }, Error, /Parse error on line 1/); shouldThrow(function() { - ast_for("{{foo}"); + astFor('{{foo}'); }, Error, /Parse error on line 1/); shouldThrow(function() { - ast_for("{{foo &}}"); + astFor('{{foo &}}'); }, Error, /Parse error on line 1/); shouldThrow(function() { - ast_for("{{#goodbyes}}{{/hellos}}"); + astFor('{{#goodbyes}}{{/hellos}}'); }, Error, /goodbyes doesn't match hellos/); shouldThrow(function() { - ast_for("{{{{goodbyes}}}} {{{{/hellos}}}}"); + astFor('{{{{goodbyes}}}} {{{{/hellos}}}}'); }, Error, /goodbyes doesn't match hellos/); }); it('should handle invalid paths', function() { shouldThrow(function() { - ast_for("{{foo/../bar}}"); + astFor('{{foo/../bar}}'); }, Error, /Invalid path: foo\/\.\. - 1:2/); shouldThrow(function() { - ast_for("{{foo/./bar}}"); + astFor('{{foo/./bar}}'); }, Error, /Invalid path: foo\/\. - 1:2/); shouldThrow(function() { - ast_for("{{foo/this/bar}}"); + astFor('{{foo/this/bar}}'); }, Error, /Invalid path: foo\/this - 1:2/); }); it('knows how to report the correct line number in errors', function() { shouldThrow(function() { - ast_for("hello\nmy\n{{foo}"); + astFor('hello\nmy\n{{foo}'); }, Error, /Parse error on line 3/); shouldThrow(function() { - ast_for("hello\n\nmy\n\n{{foo}"); + astFor('hello\n\nmy\n\n{{foo}'); }, Error, /Parse error on line 5/); }); it('knows how to report the correct line number in errors when the first character is a newline', function() { shouldThrow(function() { - ast_for("\n\nhello\n\nmy\n\n{{foo}"); + astFor('\n\nhello\n\nmy\n\n{{foo}'); }, Error, /Parse error on line 7/); }); describe('externally compiled AST', function() { it('can pass through an already-compiled AST', function() { - equals(ast_for(new Handlebars.AST.Program([new Handlebars.AST.ContentStatement("Hello")], null)), "CONTENT[ \'Hello\' ]\n"); + equals(astFor(new Handlebars.AST.Program([new Handlebars.AST.ContentStatement('Hello')], null)), 'CONTENT[ \'Hello\' ]\n'); }); }); }); diff --git a/spec/partials.js b/spec/partials.js index 0c9e0f6..22d2dc9 100644 --- a/spec/partials.js +++ b/spec/partials.js @@ -1,11 +1,10 @@ -/*global CompilerContext, Handlebars, handlebarsEnv, shouldCompileTo, shouldCompileToWithPartials, shouldThrow */ 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'}]}; shouldCompileToWithPartials(string, [hash, {}, {dude: partial}], true, 'Dudes: Yehuda (http://yehuda) Alan (http://alan) '); - shouldCompileToWithPartials(string, [hash, {}, {dude: partial},,false], true, 'Dudes: Yehuda (http://yehuda) Alan (http://alan) '); + shouldCompileToWithPartials(string, [hash, {}, {dude: partial},, false], true, 'Dudes: Yehuda (http://yehuda) Alan (http://alan) '); }); it('dynamic partials', function() { @@ -18,7 +17,7 @@ describe('partials', function() { } }; shouldCompileToWithPartials(string, [hash, helpers, {dude: partial}], true, 'Dudes: Yehuda (http://yehuda) Alan (http://alan) '); - shouldCompileToWithPartials(string, [hash, helpers, {dude: partial},,false], true, 'Dudes: Yehuda (http://yehuda) Alan (http://alan) '); + shouldCompileToWithPartials(string, [hash, helpers, {dude: partial},, false], true, 'Dudes: Yehuda (http://yehuda) Alan (http://alan) '); }); it('failing dynamic partials', function() { var string = 'Dudes: {{#dudes}}{{> (partial)}}{{/dudes}}'; @@ -34,19 +33,19 @@ describe('partials', function() { }, Handlebars.Exception, 'The partial missing could not be found'); }); - it("partials with context", function() { - var string = "Dudes: {{>dude dudes}}"; - var partial = "{{#this}}{{name}} ({{url}}) {{/this}}"; - var hash = {dudes: [{name: "Yehuda", url: "http://yehuda"}, {name: "Alan", url: "http://alan"}]}; - shouldCompileToWithPartials(string, [hash, {}, {dude: partial}], true, "Dudes: Yehuda (http://yehuda) Alan (http://alan) ", - "Partials can be passed a context"); + it('partials with context', function() { + var string = 'Dudes: {{>dude dudes}}'; + var partial = '{{#this}}{{name}} ({{url}}) {{/this}}'; + var hash = {dudes: [{name: 'Yehuda', url: 'http://yehuda'}, {name: 'Alan', url: 'http://alan'}]}; + shouldCompileToWithPartials(string, [hash, {}, {dude: partial}], true, 'Dudes: Yehuda (http://yehuda) Alan (http://alan) ', + 'Partials can be passed a context'); }); - it("partials with undefined context", function() { - var string = "Dudes: {{>dude dudes}}"; - var partial = "{{foo}} Empty"; + it('partials with undefined context', function() { + var string = 'Dudes: {{>dude dudes}}'; + var partial = '{{foo}} Empty'; var hash = {}; - shouldCompileToWithPartials(string, [hash, {}, {dude: partial}], true, "Dudes: Empty"); + shouldCompileToWithPartials(string, [hash, {}, {dude: partial}], true, 'Dudes: Empty'); }); it('partials with duplicate parameters', function() { @@ -55,133 +54,133 @@ describe('partials', function() { }, Error, 'Unsupported number of partial arguments: 2 - 1:7'); }); - it("partials with parameters", function() { - var string = "Dudes: {{#dudes}}{{> dude others=..}}{{/dudes}}"; - var partial = "{{others.foo}}{{name}} ({{url}}) "; - var hash = {foo: 'bar', dudes: [{name: "Yehuda", url: "http://yehuda"}, {name: "Alan", url: "http://alan"}]}; - shouldCompileToWithPartials(string, [hash, {}, {dude: partial}], true, "Dudes: barYehuda (http://yehuda) barAlan (http://alan) ", - "Basic partials output based on current context."); + it('partials with parameters', function() { + var string = 'Dudes: {{#dudes}}{{> dude others=..}}{{/dudes}}'; + var partial = '{{others.foo}}{{name}} ({{url}}) '; + var hash = {foo: 'bar', dudes: [{name: 'Yehuda', url: 'http://yehuda'}, {name: 'Alan', url: 'http://alan'}]}; + shouldCompileToWithPartials(string, [hash, {}, {dude: partial}], true, 'Dudes: barYehuda (http://yehuda) barAlan (http://alan) ', + 'Basic partials output based on current context.'); }); - it("partial in a partial", function() { - var string = "Dudes: {{#dudes}}{{>dude}}{{/dudes}}"; - var dude = "{{name}} {{> url}} "; - var url = "<a href='{{url}}'>{{url}}</a>"; - var hash = {dudes: [{name: "Yehuda", url: "http://yehuda"}, {name: "Alan", url: "http://alan"}]}; - shouldCompileToWithPartials(string, [hash, {}, {dude: dude, url: url}], true, "Dudes: Yehuda <a href='http://yehuda'>http://yehuda</a> Alan <a href='http://alan'>http://alan</a> ", "Partials are rendered inside of other partials"); + it('partial in a partial', function() { + var string = 'Dudes: {{#dudes}}{{>dude}}{{/dudes}}'; + var dude = '{{name}} {{> url}} '; + var url = '<a href="{{url}}">{{url}}</a>'; + var hash = {dudes: [{name: 'Yehuda', url: 'http://yehuda'}, {name: 'Alan', url: 'http://alan'}]}; + shouldCompileToWithPartials(string, [hash, {}, {dude: dude, url: url}], true, 'Dudes: Yehuda <a href="http://yehuda">http://yehuda</a> Alan <a href="http://alan">http://alan</a> ', 'Partials are rendered inside of other partials'); }); - it("rendering undefined partial throws an exception", function() { + it('rendering undefined partial throws an exception', function() { shouldThrow(function() { - var template = CompilerContext.compile("{{> whatever}}"); + var template = CompilerContext.compile('{{> whatever}}'); template(); }, 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() { var undef; handlebarsEnv.registerPartial('undefined_test', undef); }, Handlebars.Exception, 'Attempting to register a partial as undefined'); }); - it("rendering template partial in vm mode throws an exception", function() { + it('rendering template partial in vm mode throws an exception', function() { shouldThrow(function() { - var template = CompilerContext.compile("{{> whatever}}"); + var template = CompilerContext.compile('{{> whatever}}'); template(); }, Handlebars.Exception, 'The partial whatever could not be found'); }); - it("rendering function partial in vm mode", function() { - var string = "Dudes: {{#dudes}}{{> dude}}{{/dudes}}"; - var partial = function(context) { + it('rendering function partial in vm mode', function() { + var string = 'Dudes: {{#dudes}}{{> dude}}{{/dudes}}'; + function partial(context) { return context.name + ' (' + context.url + ') '; - }; - var hash = {dudes: [{name: "Yehuda", url: "http://yehuda"}, {name: "Alan", url: "http://alan"}]}; - shouldCompileTo(string, [hash, {}, {dude: partial}], "Dudes: Yehuda (http://yehuda) Alan (http://alan) ", - "Function partials output based in VM."); + } + var hash = {dudes: [{name: 'Yehuda', url: 'http://yehuda'}, {name: 'Alan', url: 'http://alan'}]}; + shouldCompileTo(string, [hash, {}, {dude: partial}], 'Dudes: Yehuda (http://yehuda) Alan (http://alan) ', + 'Function partials output based in VM.'); }); - it("GH-14: a partial preceding a selector", function() { - var string = "Dudes: {{>dude}} {{another_dude}}"; - var dude = "{{name}}"; - var hash = {name:"Jeepers", another_dude:"Creepers"}; - shouldCompileToWithPartials(string, [hash, {}, {dude:dude}], true, "Dudes: Jeepers Creepers", "Regular selectors can follow a partial"); + it('GH-14: a partial preceding a selector', function() { + var string = 'Dudes: {{>dude}} {{anotherDude}}'; + var dude = '{{name}}'; + var hash = {name: 'Jeepers', anotherDude: 'Creepers'}; + shouldCompileToWithPartials(string, [hash, {}, {dude: dude}], true, 'Dudes: Jeepers Creepers', 'Regular selectors can follow a partial'); }); - it("Partials with slash paths", function() { - var string = "Dudes: {{> shared/dude}}"; - var dude = "{{name}}"; - var hash = {name:"Jeepers", another_dude:"Creepers"}; - shouldCompileToWithPartials(string, [hash, {}, {'shared/dude':dude}], true, "Dudes: Jeepers", "Partials can use literal paths"); + it('Partials with slash paths', function() { + var string = 'Dudes: {{> shared/dude}}'; + var dude = '{{name}}'; + var hash = {name: 'Jeepers', anotherDude: 'Creepers'}; + shouldCompileToWithPartials(string, [hash, {}, {'shared/dude': dude}], true, 'Dudes: Jeepers', 'Partials can use literal paths'); }); - it("Partials with slash and point paths", function() { - var string = "Dudes: {{> shared/dude.thing}}"; - var dude = "{{name}}"; - var hash = {name:"Jeepers", another_dude:"Creepers"}; - shouldCompileToWithPartials(string, [hash, {}, {'shared/dude.thing':dude}], true, "Dudes: Jeepers", "Partials can use literal with points in paths"); + it('Partials with slash and point paths', function() { + var string = 'Dudes: {{> shared/dude.thing}}'; + var dude = '{{name}}'; + var hash = {name: 'Jeepers', anotherDude: 'Creepers'}; + shouldCompileToWithPartials(string, [hash, {}, {'shared/dude.thing': dude}], true, 'Dudes: Jeepers', 'Partials can use literal with points in paths'); }); - it("Global Partials", function() { - handlebarsEnv.registerPartial('global_test', '{{another_dude}}'); + it('Global Partials', function() { + handlebarsEnv.registerPartial('globalTest', '{{anotherDude}}'); - var string = "Dudes: {{> shared/dude}} {{> global_test}}"; - var dude = "{{name}}"; - var hash = {name:"Jeepers", another_dude:"Creepers"}; - shouldCompileToWithPartials(string, [hash, {}, {'shared/dude':dude}], true, "Dudes: Jeepers Creepers", "Partials can use globals or passed"); + var string = 'Dudes: {{> shared/dude}} {{> globalTest}}'; + var dude = '{{name}}'; + var hash = {name: 'Jeepers', anotherDude: 'Creepers'}; + shouldCompileToWithPartials(string, [hash, {}, {'shared/dude': dude}], true, 'Dudes: Jeepers Creepers', 'Partials can use globals or passed'); - handlebarsEnv.unregisterPartial('global_test'); - equals(handlebarsEnv.partials.global_test, undefined); + handlebarsEnv.unregisterPartial('globalTest'); + equals(handlebarsEnv.partials.globalTest, undefined); }); - it("Multiple partial registration", function() { + it('Multiple partial registration', function() { handlebarsEnv.registerPartial({ 'shared/dude': '{{name}}', - global_test: '{{another_dude}}' + globalTest: '{{anotherDude}}' }); - var string = "Dudes: {{> shared/dude}} {{> global_test}}"; - var hash = {name:"Jeepers", another_dude:"Creepers"}; - shouldCompileToWithPartials(string, [hash], true, "Dudes: Jeepers Creepers", "Partials can use globals or passed"); + var string = 'Dudes: {{> shared/dude}} {{> globalTest}}'; + var hash = {name: 'Jeepers', anotherDude: 'Creepers'}; + shouldCompileToWithPartials(string, [hash], true, 'Dudes: Jeepers Creepers', 'Partials can use globals or passed'); }); - it("Partials with integer path", function() { - var string = "Dudes: {{> 404}}"; - var dude = "{{name}}"; - var hash = {name:"Jeepers", another_dude:"Creepers"}; - shouldCompileToWithPartials(string, [hash, {}, {404:dude}], true, "Dudes: Jeepers", "Partials can use literal paths"); + it('Partials with integer path', function() { + var string = 'Dudes: {{> 404}}'; + var dude = '{{name}}'; + var hash = {name: 'Jeepers', anotherDude: 'Creepers'}; + shouldCompileToWithPartials(string, [hash, {}, {404: dude}], true, 'Dudes: Jeepers', 'Partials can use literal paths'); }); - it("Partials with complex path", function() { - var string = "Dudes: {{> 404/asdf?.bar}}"; - var dude = "{{name}}"; - var hash = {name:"Jeepers", another_dude:"Creepers"}; - shouldCompileToWithPartials(string, [hash, {}, {'404/asdf?.bar':dude}], true, "Dudes: Jeepers", "Partials can use literal paths"); + it('Partials with complex path', function() { + var string = 'Dudes: {{> 404/asdf?.bar}}'; + var dude = '{{name}}'; + var hash = {name: 'Jeepers', anotherDude: 'Creepers'}; + shouldCompileToWithPartials(string, [hash, {}, {'404/asdf?.bar': dude}], true, 'Dudes: Jeepers', 'Partials can use literal paths'); }); - it("Partials with escaped", function() { - var string = "Dudes: {{> [+404/asdf?.bar]}}"; - var dude = "{{name}}"; - var hash = {name:"Jeepers", another_dude:"Creepers"}; - shouldCompileToWithPartials(string, [hash, {}, {'+404/asdf?.bar':dude}], true, "Dudes: Jeepers", "Partials can use literal paths"); + it('Partials with escaped', function() { + var string = 'Dudes: {{> [+404/asdf?.bar]}}'; + var dude = '{{name}}'; + var hash = {name: 'Jeepers', anotherDude: 'Creepers'}; + shouldCompileToWithPartials(string, [hash, {}, {'+404/asdf?.bar': dude}], true, 'Dudes: Jeepers', 'Partials can use literal paths'); }); - it("Partials with string", function() { - var string = "Dudes: {{> \"+404/asdf?.bar\"}}"; - var dude = "{{name}}"; - var hash = {name:"Jeepers", another_dude:"Creepers"}; - shouldCompileToWithPartials(string, [hash, {}, {'+404/asdf?.bar':dude}], true, "Dudes: Jeepers", "Partials can use literal paths"); + it('Partials with string', function() { + var string = 'Dudes: {{> \'+404/asdf?.bar\'}}'; + var dude = '{{name}}'; + var hash = {name: 'Jeepers', anotherDude: 'Creepers'}; + shouldCompileToWithPartials(string, [hash, {}, {'+404/asdf?.bar': dude}], true, 'Dudes: Jeepers', 'Partials can use literal paths'); }); it('should handle empty partial', function() { - var string = "Dudes: {{#dudes}}{{> dude}}{{/dudes}}"; - var partial = ""; - var hash = {dudes: [{name: "Yehuda", url: "http://yehuda"}, {name: "Alan", url: "http://alan"}]}; - shouldCompileToWithPartials(string, [hash, {}, {dude: partial}], true, "Dudes: "); + var string = 'Dudes: {{#dudes}}{{> dude}}{{/dudes}}'; + var partial = ''; + var hash = {dudes: [{name: 'Yehuda', url: 'http://yehuda'}, {name: 'Alan', url: 'http://alan'}]}; + shouldCompileToWithPartials(string, [hash, {}, {dude: partial}], true, 'Dudes: '); }); - it("throw on missing partial", function() { + it('throw on missing partial', function() { var compile = handlebarsEnv.compile; handlebarsEnv.compile = undefined; shouldThrow(function() { @@ -200,28 +199,28 @@ describe('partials', function() { }); describe('standalone partials', function() { - it("indented partials", function() { - var string = "Dudes:\n{{#dudes}}\n {{>dude}}\n{{/dudes}}"; - var dude = "{{name}}\n"; - var hash = {dudes: [{name: "Yehuda", url: "http://yehuda"}, {name: "Alan", url: "http://alan"}]}; + it('indented partials', function() { + var string = 'Dudes:\n{{#dudes}}\n {{>dude}}\n{{/dudes}}'; + var dude = '{{name}}\n'; + var hash = {dudes: [{name: 'Yehuda', url: 'http://yehuda'}, {name: 'Alan', url: 'http://alan'}]}; shouldCompileToWithPartials(string, [hash, {}, {dude: dude}], true, - "Dudes:\n Yehuda\n Alan\n"); + 'Dudes:\n Yehuda\n Alan\n'); }); - it("nested indented partials", function() { - var string = "Dudes:\n{{#dudes}}\n {{>dude}}\n{{/dudes}}"; - var dude = "{{name}}\n {{> url}}"; - var url = "{{url}}!\n"; - var hash = {dudes: [{name: "Yehuda", url: "http://yehuda"}, {name: "Alan", url: "http://alan"}]}; + it('nested indented partials', function() { + var string = 'Dudes:\n{{#dudes}}\n {{>dude}}\n{{/dudes}}'; + var dude = '{{name}}\n {{> url}}'; + var url = '{{url}}!\n'; + var hash = {dudes: [{name: 'Yehuda', url: 'http://yehuda'}, {name: 'Alan', url: 'http://alan'}]}; shouldCompileToWithPartials(string, [hash, {}, {dude: dude, url: url}], true, - "Dudes:\n Yehuda\n http://yehuda!\n Alan\n http://alan!\n"); + 'Dudes:\n Yehuda\n http://yehuda!\n Alan\n http://alan!\n'); }); - it("prevent nested indented partials", function() { - var string = "Dudes:\n{{#dudes}}\n {{>dude}}\n{{/dudes}}"; - var dude = "{{name}}\n {{> url}}"; - var url = "{{url}}!\n"; - var hash = {dudes: [{name: "Yehuda", url: "http://yehuda"}, {name: "Alan", url: "http://alan"}]}; + it('prevent nested indented partials', function() { + var string = 'Dudes:\n{{#dudes}}\n {{>dude}}\n{{/dudes}}'; + var dude = '{{name}}\n {{> url}}'; + var url = '{{url}}!\n'; + var hash = {dudes: [{name: 'Yehuda', url: 'http://yehuda'}, {name: 'Alan', url: 'http://alan'}]}; shouldCompileToWithPartials(string, [hash, {}, {dude: dude, url: url}, {preventIndent: true}], true, - "Dudes:\n Yehuda\n http://yehuda!\n Alan\n http://alan!\n"); + 'Dudes:\n Yehuda\n http://yehuda!\n Alan\n http://alan!\n'); }); }); diff --git a/spec/precompiler.js b/spec/precompiler.js index cbbfdf7..f877c29 100644 --- a/spec/precompiler.js +++ b/spec/precompiler.js @@ -1,6 +1,4 @@ -/*global shouldThrow */ - - +/*eslint-disable no-console */ describe('precompiler', function() { // NOP Under non-node environments if (typeof process === 'undefined') { diff --git a/spec/regressions.js b/spec/regressions.js index 84b9d0c..247c1c9 100644 --- a/spec/regressions.js +++ b/spec/regressions.js @@ -1,26 +1,34 @@ -/*global CompilerContext, shouldCompileTo, shouldThrow */ describe('Regressions', function() { - it("GH-94: Cannot read property of undefined", function() { - var data = {"books":[{"title":"The origin of species","author":{"name":"Charles Darwin"}},{"title":"Lazarillo de Tormes"}]}; - var string = "{{#books}}{{title}}{{author.name}}{{/books}}"; - shouldCompileTo(string, data, "The origin of speciesCharles DarwinLazarillo de Tormes", - "Renders without an undefined property error"); + it('GH-94: Cannot read property of undefined', function() { + var data = { + 'books': [{ + 'title': 'The origin of species', + 'author': { + 'name': 'Charles Darwin' + } + }, { + 'title': 'Lazarillo de Tormes' + }] + }; + var string = '{{#books}}{{title}}{{author.name}}{{/books}}'; + shouldCompileTo(string, data, 'The origin of speciesCharles DarwinLazarillo de Tormes', + 'Renders without an undefined property error'); }); it("GH-150: Inverted sections print when they shouldn't", function() { - var string = "{{^set}}not set{{/set}} :: {{#set}}set{{/set}}"; + var string = '{{^set}}not set{{/set}} :: {{#set}}set{{/set}}'; - shouldCompileTo(string, {}, "not set :: ", "inverted sections run when property isn't present in context"); - shouldCompileTo(string, {set: undefined}, "not set :: ", "inverted sections run when property is undefined"); - shouldCompileTo(string, {set: false}, "not set :: ", "inverted sections run when property is false"); - shouldCompileTo(string, {set: true}, " :: set", "inverted sections don't run when property is true"); + shouldCompileTo(string, {}, 'not set :: ', "inverted sections run when property isn't present in context"); + shouldCompileTo(string, {set: undefined}, 'not set :: ', 'inverted sections run when property is undefined'); + shouldCompileTo(string, {set: false}, 'not set :: ', 'inverted sections run when property is false'); + shouldCompileTo(string, {set: true}, ' :: set', "inverted sections don't run when property is true"); }); - it("GH-158: Using array index twice, breaks the template", function() { - var string = "{{arr.[0]}}, {{arr.[1]}}"; - var data = { "arr": [1,2] }; + it('GH-158: Using array index twice, breaks the template', function() { + var string = '{{arr.[0]}}, {{arr.[1]}}'; + var data = { 'arr': [1, 2] }; - shouldCompileTo(string, data, "1, 2", "it works as expected"); + shouldCompileTo(string, data, '1, 2', 'it works as expected'); }); it("bug reported by @fat where lambdas weren't being properly resolved", function() { @@ -39,12 +47,12 @@ describe('Regressions', function() { + '{{/hasThings}}'; var data = { thing: function() { - return "blah"; + return 'blah'; }, things: [ - {className: "one", word: "@fat"}, - {className: "two", word: "@dhg"}, - {className: "three", word:"@sayrer"} + {className: 'one', word: '@fat'}, + {className: 'two', word: '@dhg'}, + {className: 'three', word: '@sayrer'} ], hasThings: function() { return true; @@ -63,14 +71,14 @@ describe('Regressions', function() { it('GH-408: Multiple loops fail', function() { var context = [ - { name: "John Doe", location: { city: "Chicago" } }, - { name: "Jane Doe", location: { city: "New York"} } + { name: 'John Doe', location: { city: 'Chicago' } }, + { name: 'Jane Doe', location: { city: 'New York'} } ]; var template = CompilerContext.compile('{{#.}}{{name}}{{/.}}{{#.}}{{name}}{{/.}}{{#.}}{{name}}{{/.}}'); var result = template(context); - equals(result, "John DoeJane DoeJohn DoeJane DoeJohn DoeJane Doe", 'It should output multiple times'); + equals(result, 'John DoeJane DoeJohn DoeJane DoeJohn DoeJane Doe', 'It should output multiple times'); }); it('GS-428: Nested if else rendering', function() { @@ -95,11 +103,13 @@ describe('Regressions', function() { }); it('GH-534: Object prototype aliases', function() { + /*eslint-disable no-extend-native */ Object.prototype[0xD834] = true; shouldCompileTo('{{foo}}', { foo: 'bar' }, 'bar'); delete Object.prototype[0xD834]; + /*eslint-enable no-extend-native */ }); it('GH-437: Matching escaping', function() { @@ -111,23 +121,23 @@ describe('Regressions', function() { }, Error); }); - it("GH-676: Using array in escaping mustache fails", function() { - var string = "{{arr}}"; - var data = { "arr": [1,2] }; + it('GH-676: Using array in escaping mustache fails', function() { + var string = '{{arr}}'; + var data = { 'arr': [1, 2] }; - shouldCompileTo(string, data, data.arr.toString(), "it works as expected"); + shouldCompileTo(string, data, data.arr.toString(), 'it works as expected'); }); - it("Mustache man page", function() { - var string = "Hello {{name}}. You have just won ${{value}}!{{#in_ca}} Well, ${{taxed_value}}, after taxes.{{/in_ca}}"; + it('Mustache man page', function() { + var string = 'Hello {{name}}. You have just won ${{value}}!{{#in_ca}} Well, ${{taxed_value}}, after taxes.{{/in_ca}}'; var data = { - "name": "Chris", - "value": 10000, - "taxed_value": 10000 - (10000 * 0.4), - "in_ca": true + 'name': 'Chris', + 'value': 10000, + 'taxed_value': 10000 - (10000 * 0.4), + 'in_ca': true }; - shouldCompileTo(string, data, "Hello Chris. You have just won $10000! Well, $6000, after taxes.", "the hello world mustache example works"); + shouldCompileTo(string, data, 'Hello Chris. You have just won $10000! Well, $6000, after taxes.', 'the hello world mustache example works'); }); it('GH-731: zero context rendering', function() { diff --git a/spec/require.js b/spec/require.js index 11b7a0c..6c0b5ae 100644 --- a/spec/require.js +++ b/spec/require.js @@ -1,21 +1,21 @@ -if (typeof(require) !== 'undefined' && require.extensions[".handlebars"]) { +if (typeof require !== 'undefined' && require.extensions['.handlebars']) { describe('Require', function() { it('Load .handlebars files with require()', function() { - var template = require("./artifacts/example_1"); - equal(template, require("./artifacts/example_1.handlebars")); + var template = require('./artifacts/example_1'); + equal(template, require('./artifacts/example_1.handlebars')); var expected = 'foo\n'; - var result = template({foo: "foo"}); + var result = template({foo: 'foo'}); equal(result, expected); }); it('Load .hbs files with require()', function() { - var template = require("./artifacts/example_2"); - equal(template, require("./artifacts/example_2.hbs")); + var template = require('./artifacts/example_2'); + equal(template, require('./artifacts/example_2.hbs')); var expected = 'Hello, World!\n'; - var result = template({name: "World"}); + var result = template({name: 'World'}); equal(result, expected); }); diff --git a/spec/runtime.js b/spec/runtime.js index ce8b14c..502a843 100644 --- a/spec/runtime.js +++ b/spec/runtime.js @@ -1,5 +1,3 @@ -/*globals Handlebars, shouldThrow */ - describe('runtime', function() { describe('#template', function() { it('should throw on invalid templates', function() { diff --git a/spec/source-map.js b/spec/source-map.js index 8037b88..54e5e4d 100644 --- a/spec/source-map.js +++ b/spec/source-map.js @@ -1,8 +1,7 @@ -/*global CompilerContext, Handlebars */ try { if (typeof define !== 'function' || !define.amd) { var SourceMap = require('source-map'), - SourceMapConsumer = SourceMap.SourceMapConsumer; + SourceMapConsumer = SourceMap.SourceMapConsumer; } } catch (err) { /* NOP for in browser */ @@ -20,13 +19,13 @@ describe('source-map', function() { equal(!!template.map, !CompilerContext.browser); }); it('should map source properly', function() { - var source = ' b{{hello}} \n {{bar}}a {{#block arg hash=(subex 1 subval)}}{{/block}}', - template = Handlebars.precompile(source, {destName: 'dest.js', srcName: 'src.hbs'}); + var templateSource = ' b{{hello}} \n {{bar}}a {{#block arg hash=(subex 1 subval)}}{{/block}}', + template = Handlebars.precompile(templateSource, {destName: 'dest.js', srcName: 'src.hbs'}); if (template.map) { var consumer = new SourceMapConsumer(template.map), lines = template.code.split('\n'), - srcLines = source.split('\n'), + srcLines = templateSource.split('\n'), generated = grepLine('" b"', lines), source = grepLine(' b', srcLines); @@ -43,7 +42,7 @@ function grepLine(token, lines) { var column = lines[i].indexOf(token); if (column >= 0) { return { - line: i+1, + line: i + 1, column: column }; } diff --git a/spec/spec.js b/spec/spec.js index 2dd2bd8..ae1ec38 100644 --- a/spec/spec.js +++ b/spec/spec.js @@ -5,12 +5,11 @@ describe('spec', function() { } var _ = require('underscore'), - Handlebars = require('../lib'), fs = require('fs'); - var specDir =__dirname + '/mustache/specs/'; + var specDir = __dirname + '/mustache/specs/'; var specs = _.filter(fs.readdirSync(specDir), function(name) { - return /.*\.json$/.test(name); + return (/.*\.json$/).test(name); }); _.each(specs, function(name) { @@ -26,8 +25,8 @@ describe('spec', function() { // We nest the entire response from partials, not just the literals || (name === 'partials.json' && test.name === 'Standalone Indentation') - || /\{\{\=/.test(test.template) - || _.any(test.partials, function(partial) { return /\{\{\=/.test(partial); })) { + || (/\{\{\=/).test(test.template) + || _.any(test.partials, function(partial) { return (/\{\{\=/).test(partial); })) { it.skip(name + ' - ' + test.name); return; } @@ -35,7 +34,9 @@ describe('spec', function() { var data = _.clone(test.data); if (data.lambda) { // Blergh + /*eslint-disable no-eval */ data.lambda = eval('(' + data.lambda.js + ')'); + /*eslint-enable no-eval */ } it(name + ' - ' + test.name, function() { if (test.partials) { diff --git a/spec/strict.js b/spec/strict.js index f701866..2aef134 100644 --- a/spec/strict.js +++ b/spec/strict.js @@ -1,4 +1,3 @@ -/*global CompilerContext, Handlebars, shouldThrow */ var Exception = Handlebars.Exception; describe('strict', function() { diff --git a/spec/string-params.js b/spec/string-params.js index 4704a84..b76f291 100644 --- a/spec/string-params.js +++ b/spec/string-params.js @@ -1,44 +1,43 @@ -/*global CompilerContext */ describe('string params mode', function() { - it("arguments to helpers can be retrieved from options hash in string form", 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; + 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"); + 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() { + 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 + ' ' + + 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"); + 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() { + 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; + return 'STOP ME FROM READING HACKER NEWS I ' + + options.contexts[0][desire] + ' ' + noun; }, - "with": function(context, options) { + 'with': function(context, options) { return options.fn(options.contexts[0][context]); } }; @@ -49,31 +48,31 @@ describe('string params mode', function() { need: 'need-a' }, {helpers: helpers}); - equals(result, "STOP ME FROM READING HACKER NEWS I need-a dad.joke", "Proper context variable output"); + 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 }); + 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"; + 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"); + 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 }); + 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) { @@ -94,43 +93,43 @@ describe('string params mode', function() { 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 }); + 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(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.desire, 'need'); + equal(options.hash.noun, 'dad.joke'); equal(options.hash.bool, true); - return "Helper called"; + return 'Helper called'; }, - "with": function(context, options) { - return options.fn(options.contexts[0][context]); + 'with': function(withContext, options) { + return options.fn(options.contexts[0][withContext]); } }; var result = template(context, { helpers: helpers }); - equal(result, "Helper called"); + 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() { + 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 + " " + + return 'STOP ME FROM READING HACKER NEWS I ' + + options.contexts[0][desire] + ' ' + noun + ' ' + options.fn(this); }, - "with": function(context, options) { + 'with': function(context, options) { return options.fn(options.contexts[0][context]); } }; @@ -141,23 +140,23 @@ describe('string params mode', function() { need: 'need-a' }, {helpers: helpers}); - equals(result, "STOP ME FROM READING HACKER NEWS I need-a dad.joke wot", "Proper context variable output"); + equals(result, 'STOP ME FROM READING HACKER NEWS I need-a dad.joke wot', 'Proper context variable output'); }); - it("with nested block ambiguous", function() { + it('with nested block ambiguous', function() { var template = CompilerContext.compile('{{#with content}}{{#view}}{{firstName}} {{lastName}}{{/view}}{{/with}}', {stringParams: true}); - var helpers = { - 'with': function(options) { - return "WITH"; + var helpers = { + 'with': function() { + return 'WITH'; }, view: function() { - return "VIEW"; + return 'VIEW'; } }; var result = template({}, {helpers: helpers}); - equals(result, "WITH"); + equals(result, 'WITH'); }); it('should handle DATA', function() { diff --git a/spec/subexpressions.js b/spec/subexpressions.js index 1fb8775..dad741e 100644 --- a/spec/subexpressions.js +++ b/spec/subexpressions.js @@ -1,134 +1,133 @@ -/*global CompilerContext, Handlebars, shouldCompileTo, shouldThrow */ describe('subexpressions', function() { - it("arg-less helper", function() { - var string = "{{foo (bar)}}!"; - var context = {}; - var helpers = { + it('arg-less helper', function() { + var string = '{{foo (bar)}}!'; + var context = {}; + var helpers = { foo: function(val) { - return val+val; + return val + val; }, bar: function() { - return "LOL"; + return 'LOL'; } }; - shouldCompileTo(string, [context, helpers], "LOLLOL!"); + shouldCompileTo(string, [context, helpers], 'LOLLOL!'); }); - it("helper w args", function() { - var string = '{{blog (equal a b)}}'; + it('helper w args', function() { + var string = '{{blog (equal a b)}}'; - var context = { bar: "LOL" }; - var helpers = { + var context = { bar: 'LOL' }; + var helpers = { blog: function(val) { - return "val is " + val; + return 'val is ' + val; }, equal: function(x, y) { return x === y; } }; - shouldCompileTo(string, [context, helpers], "val is true"); + shouldCompileTo(string, [context, helpers], 'val is true'); }); - it("mixed paths and helpers", function() { - var string = '{{blog baz.bat (equal a b) baz.bar}}'; + it('mixed paths and helpers', function() { + var string = '{{blog baz.bat (equal a b) baz.bar}}'; - var context = { bar: "LOL", baz: {bat: 'foo!', bar: 'bar!'} }; - var helpers = { + var context = { bar: 'LOL', baz: {bat: 'foo!', bar: 'bar!'} }; + var helpers = { blog: function(val, that, theOther) { - return "val is " + val + ', ' + that + ' and ' + theOther; + return 'val is ' + val + ', ' + that + ' and ' + theOther; }, equal: function(x, y) { return x === y; } }; - shouldCompileTo(string, [context, helpers], "val is foo!, true and bar!"); + shouldCompileTo(string, [context, helpers], 'val is foo!, true and bar!'); }); - it("supports much nesting", function() { - var string = '{{blog (equal (equal true true) true)}}'; + it('supports much nesting', function() { + var string = '{{blog (equal (equal true true) true)}}'; - var context = { bar: "LOL" }; - var helpers = { + var context = { bar: 'LOL' }; + var helpers = { blog: function(val) { - return "val is " + val; + return 'val is ' + val; }, equal: function(x, y) { return x === y; } }; - shouldCompileTo(string, [context, helpers], "val is true"); + shouldCompileTo(string, [context, helpers], 'val is true'); }); it('GH-800 : Complex subexpressions', function() { - var context = {a: 'a', b:'b', c:{c:'c'}, d:'d', e: {e: 'e'}}; - var helpers = { + var context = {a: 'a', b: 'b', c: {c: 'c'}, d: 'd', e: {e: 'e'}}; + var helpers = { dash: function(a, b) { - return a + "-" + b; + return a + '-' + b; }, concat: function(a, b) { return a + b; } }; - shouldCompileTo('{{dash "abc" (concat a b)}}', [context, helpers], 'abc-ab'); + shouldCompileTo("{{dash 'abc' (concat a b)}}", [context, helpers], 'abc-ab'); shouldCompileTo('{{dash d (concat a b)}}', [context, helpers], 'd-ab'); shouldCompileTo('{{dash c.c (concat a b)}}', [context, helpers], 'c-ab'); shouldCompileTo('{{dash (concat a b) c.c}}', [context, helpers], 'ab-c'); shouldCompileTo('{{dash (concat a e.e) c.c}}', [context, helpers], 'ae-c'); }); - it("provides each nested helper invocation its own options hash", function() { + it('provides each nested helper invocation its own options hash', function() { var string = '{{equal (equal true true) true}}'; var lastOptions = null; - var helpers = { + var helpers = { equal: function(x, y, options) { if (!options || options === lastOptions) { - throw new Error("options hash was reused"); + throw new Error('options hash was reused'); } lastOptions = options; return x === y; } }; - shouldCompileTo(string, [{}, helpers], "true"); + shouldCompileTo(string, [{}, helpers], 'true'); }); - it("with hashes", function() { - var string = '{{blog (equal (equal true true) true fun="yes")}}'; + it('with hashes', function() { + var string = "{{blog (equal (equal true true) true fun='yes')}}"; - var context = { bar: "LOL" }; - var helpers = { + var context = { bar: 'LOL' }; + var helpers = { blog: function(val) { - return "val is " + val; + return 'val is ' + val; }, equal: function(x, y) { return x === y; } }; - shouldCompileTo(string, [context, helpers], "val is true"); + shouldCompileTo(string, [context, helpers], 'val is true'); }); - it("as hashes", function() { - var string = '{{blog fun=(equal (blog fun=1) "val is 1")}}'; + it('as hashes', function() { + var string = "{{blog fun=(equal (blog fun=1) 'val is 1')}}"; - var helpers = { + var helpers = { blog: function(options) { - return "val is " + options.hash.fun; + return 'val is ' + options.hash.fun; }, equal: function(x, y) { return x === y; } }; - shouldCompileTo(string, [{}, helpers], "val is true"); + shouldCompileTo(string, [{}, helpers], 'val is true'); }); - it("multiple subexpressions in a hash", function() { + it('multiple subexpressions in a hash', function() { var string = '{{input aria-label=(t "Name") placeholder=(t "Example User")}}'; var helpers = { input: function(options) { - var hash = options.hash; - var ariaLabel = Handlebars.Utils.escapeExpression(hash['aria-label']); + var hash = options.hash; + var ariaLabel = Handlebars.Utils.escapeExpression(hash['aria-label']); var placeholder = Handlebars.Utils.escapeExpression(hash.placeholder); return new Handlebars.SafeString('<input aria-label="' + ariaLabel + '" placeholder="' + placeholder + '" />'); }, @@ -139,20 +138,20 @@ describe('subexpressions', function() { shouldCompileTo(string, [{}, helpers], '<input aria-label="Name" placeholder="Example User" />'); }); - it("multiple subexpressions in a hash with context", function() { + it('multiple subexpressions in a hash with context', function() { var string = '{{input aria-label=(t item.field) placeholder=(t item.placeholder)}}'; var context = { item: { - field: "Name", - placeholder: "Example User" - } + field: 'Name', + placeholder: 'Example User' + } }; var helpers = { input: function(options) { - var hash = options.hash; - var ariaLabel = Handlebars.Utils.escapeExpression(hash['aria-label']); + var hash = options.hash; + var ariaLabel = Handlebars.Utils.escapeExpression(hash['aria-label']); var placeholder = Handlebars.Utils.escapeExpression(hash.placeholder); return new Handlebars.SafeString('<input aria-label="' + ariaLabel + '" placeholder="' + placeholder + '" />'); }, @@ -161,23 +160,23 @@ describe('subexpressions', function() { } }; shouldCompileTo(string, [context, helpers], '<input aria-label="Name" placeholder="Example User" />'); - }); + }); - it("in string params mode,", function() { + 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"); + 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"); + 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; } }; @@ -187,54 +186,53 @@ describe('subexpressions', function() { yeah: {} }, {helpers: helpers}); - equals(result, "fooyeah"); + equals(result, 'fooyeah'); }); - it("as hashes in string params mode", function() { - + it('as hashes in string params mode', function() { var template = CompilerContext.compile('{{blog fun=(bork)}}', {stringParams: true}); - var helpers = { + var helpers = { blog: function(options) { equals(options.hashTypes.fun, 'SubExpression'); - return "val is " + options.hash.fun; + return 'val is ' + options.hash.fun; }, bork: function() { - return "BORK"; + return 'BORK'; } }; var result = template({}, {helpers: helpers}); - equals(result, "val is BORK"); + equals(result, 'val is BORK'); }); - it("subexpression functions on the context", function() { - var string = "{{foo (bar)}}!"; - var context = { + it('subexpression functions on the context', function() { + var string = '{{foo (bar)}}!'; + var context = { bar: function() { - return "LOL"; + return 'LOL'; } }; - var helpers = { + var helpers = { foo: function(val) { - return val+val; + return val + val; } }; - shouldCompileTo(string, [context, helpers], "LOLLOL!"); + shouldCompileTo(string, [context, helpers], 'LOLLOL!'); }); it("subexpressions can't just be property lookups", function() { - var string = "{{foo (bar)}}!"; - var context = { - bar: "LOL" + var string = '{{foo (bar)}}!'; + var context = { + bar: 'LOL' }; - var helpers = { + var helpers = { foo: function(val) { - return val+val; + return val + val; } }; shouldThrow(function() { - shouldCompileTo(string, [context, helpers], "LOLLOL!"); + shouldCompileTo(string, [context, helpers], 'LOLLOL!'); }); }); }); diff --git a/spec/tokenizer.js b/spec/tokenizer.js index 26a1c3b..ad71dc9 100644 --- a/spec/tokenizer.js +++ b/spec/tokenizer.js @@ -1,4 +1,3 @@ -/*global Handlebars */ function shouldMatchTokens(result, tokens) { for (var index = 0; index < result.length; index++) { equals(result[index].name, tokens[index]); @@ -22,7 +21,7 @@ describe('Tokenizer', function() { var out = [], token; - while (token = lexer.lex()) { + while ((token = lexer.lex())) { var result = parser.terminals_[token] || token; if (!result || result === 'EOF' || result === 'INVALID') { break; @@ -34,292 +33,292 @@ describe('Tokenizer', function() { } it('tokenizes a simple mustache as "OPEN ID CLOSE"', function() { - var result = tokenize("{{foo}}"); + var result = tokenize('{{foo}}'); shouldMatchTokens(result, ['OPEN', 'ID', 'CLOSE']); - shouldBeToken(result[1], "ID", "foo"); + shouldBeToken(result[1], 'ID', 'foo'); }); it('supports unescaping with &', function() { - var result = tokenize("{{&bar}}"); + var result = tokenize('{{&bar}}'); shouldMatchTokens(result, ['OPEN', 'ID', 'CLOSE']); - shouldBeToken(result[0], "OPEN", "{{&"); - shouldBeToken(result[1], "ID", "bar"); + shouldBeToken(result[0], 'OPEN', '{{&'); + shouldBeToken(result[1], 'ID', 'bar'); }); it('supports unescaping with {{{', function() { - var result = tokenize("{{{bar}}}"); + var result = tokenize('{{{bar}}}'); shouldMatchTokens(result, ['OPEN_UNESCAPED', 'ID', 'CLOSE_UNESCAPED']); - shouldBeToken(result[1], "ID", "bar"); + shouldBeToken(result[1], 'ID', 'bar'); }); it('supports escaping delimiters', function() { - var result = tokenize("{{foo}} \\{{bar}} {{baz}}"); + var result = tokenize('{{foo}} \\{{bar}} {{baz}}'); shouldMatchTokens(result, ['OPEN', 'ID', 'CLOSE', 'CONTENT', 'CONTENT', 'OPEN', 'ID', 'CLOSE']); - shouldBeToken(result[3], "CONTENT", " "); - shouldBeToken(result[4], "CONTENT", "{{bar}} "); + shouldBeToken(result[3], 'CONTENT', ' '); + shouldBeToken(result[4], 'CONTENT', '{{bar}} '); }); it('supports escaping multiple delimiters', function() { - var result = tokenize("{{foo}} \\{{bar}} \\{{baz}}"); + var result = tokenize('{{foo}} \\{{bar}} \\{{baz}}'); shouldMatchTokens(result, ['OPEN', 'ID', 'CLOSE', 'CONTENT', 'CONTENT', 'CONTENT']); - shouldBeToken(result[3], "CONTENT", " "); - shouldBeToken(result[4], "CONTENT", "{{bar}} "); - shouldBeToken(result[5], "CONTENT", "{{baz}}"); + shouldBeToken(result[3], 'CONTENT', ' '); + shouldBeToken(result[4], 'CONTENT', '{{bar}} '); + shouldBeToken(result[5], 'CONTENT', '{{baz}}'); }); it('supports escaping a triple stash', function() { - var result = tokenize("{{foo}} \\{{{bar}}} {{baz}}"); + var result = tokenize('{{foo}} \\{{{bar}}} {{baz}}'); shouldMatchTokens(result, ['OPEN', 'ID', 'CLOSE', 'CONTENT', 'CONTENT', 'OPEN', 'ID', 'CLOSE']); - shouldBeToken(result[4], "CONTENT", "{{{bar}}} "); + shouldBeToken(result[4], 'CONTENT', '{{{bar}}} '); }); it('supports escaping escape character', function() { - var result = tokenize("{{foo}} \\\\{{bar}} {{baz}}"); + var result = tokenize('{{foo}} \\\\{{bar}} {{baz}}'); shouldMatchTokens(result, ['OPEN', 'ID', 'CLOSE', 'CONTENT', 'OPEN', 'ID', 'CLOSE', 'CONTENT', 'OPEN', 'ID', 'CLOSE']); - shouldBeToken(result[3], "CONTENT", " \\"); - shouldBeToken(result[5], "ID", "bar"); + shouldBeToken(result[3], 'CONTENT', ' \\'); + shouldBeToken(result[5], 'ID', 'bar'); }); it('supports escaping multiple escape characters', function() { - var result = tokenize("{{foo}} \\\\{{bar}} \\\\{{baz}}"); + var result = tokenize('{{foo}} \\\\{{bar}} \\\\{{baz}}'); shouldMatchTokens(result, ['OPEN', 'ID', 'CLOSE', 'CONTENT', 'OPEN', 'ID', 'CLOSE', 'CONTENT', 'OPEN', 'ID', 'CLOSE']); - shouldBeToken(result[3], "CONTENT", " \\"); - shouldBeToken(result[5], "ID", "bar"); - shouldBeToken(result[7], "CONTENT", " \\"); - shouldBeToken(result[9], "ID", "baz"); + shouldBeToken(result[3], 'CONTENT', ' \\'); + shouldBeToken(result[5], 'ID', 'bar'); + shouldBeToken(result[7], 'CONTENT', ' \\'); + shouldBeToken(result[9], 'ID', 'baz'); }); it('supports escaped mustaches after escaped escape characters', function() { - var result = tokenize("{{foo}} \\\\{{bar}} \\{{baz}}"); + var result = tokenize('{{foo}} \\\\{{bar}} \\{{baz}}'); shouldMatchTokens(result, ['OPEN', 'ID', 'CLOSE', 'CONTENT', 'OPEN', 'ID', 'CLOSE', 'CONTENT', 'CONTENT', 'CONTENT']); - shouldBeToken(result[3], "CONTENT", " \\"); - shouldBeToken(result[4], "OPEN", "{{"); - shouldBeToken(result[5], "ID", "bar"); - shouldBeToken(result[7], "CONTENT", " "); - shouldBeToken(result[8], "CONTENT", "{{baz}}"); + shouldBeToken(result[3], 'CONTENT', ' \\'); + shouldBeToken(result[4], 'OPEN', '{{'); + shouldBeToken(result[5], 'ID', 'bar'); + shouldBeToken(result[7], 'CONTENT', ' '); + shouldBeToken(result[8], 'CONTENT', '{{baz}}'); }); it('supports escaped escape characters after escaped mustaches', function() { - var result = tokenize("{{foo}} \\{{bar}} \\\\{{baz}}"); + var result = tokenize('{{foo}} \\{{bar}} \\\\{{baz}}'); shouldMatchTokens(result, ['OPEN', 'ID', 'CLOSE', 'CONTENT', 'CONTENT', 'CONTENT', 'OPEN', 'ID', 'CLOSE']); - shouldBeToken(result[4], "CONTENT", "{{bar}} "); - shouldBeToken(result[5], "CONTENT", "\\"); - shouldBeToken(result[6], "OPEN", "{{"); - shouldBeToken(result[7], "ID", "baz"); + shouldBeToken(result[4], 'CONTENT', '{{bar}} '); + shouldBeToken(result[5], 'CONTENT', '\\'); + shouldBeToken(result[6], 'OPEN', '{{'); + shouldBeToken(result[7], 'ID', 'baz'); }); it('supports escaped escape character on a triple stash', function() { - var result = tokenize("{{foo}} \\\\{{{bar}}} {{baz}}"); + var result = tokenize('{{foo}} \\\\{{{bar}}} {{baz}}'); shouldMatchTokens(result, ['OPEN', 'ID', 'CLOSE', 'CONTENT', 'OPEN_UNESCAPED', 'ID', 'CLOSE_UNESCAPED', 'CONTENT', 'OPEN', 'ID', 'CLOSE']); - shouldBeToken(result[3], "CONTENT", " \\"); - shouldBeToken(result[5], "ID", "bar"); + shouldBeToken(result[3], 'CONTENT', ' \\'); + shouldBeToken(result[5], 'ID', 'bar'); }); it('tokenizes a simple path', function() { - var result = tokenize("{{foo/bar}}"); + var result = tokenize('{{foo/bar}}'); shouldMatchTokens(result, ['OPEN', 'ID', 'SEP', 'ID', 'CLOSE']); }); it('allows dot notation', function() { - var result = tokenize("{{foo.bar}}"); + var result = tokenize('{{foo.bar}}'); shouldMatchTokens(result, ['OPEN', 'ID', 'SEP', 'ID', 'CLOSE']); - shouldMatchTokens(tokenize("{{foo.bar.baz}}"), ['OPEN', 'ID', 'SEP', 'ID', 'SEP', 'ID', 'CLOSE']); + shouldMatchTokens(tokenize('{{foo.bar.baz}}'), ['OPEN', 'ID', 'SEP', 'ID', 'SEP', 'ID', 'CLOSE']); }); it('allows path literals with []', function() { - var result = tokenize("{{foo.[bar]}}"); + var result = tokenize('{{foo.[bar]}}'); shouldMatchTokens(result, ['OPEN', 'ID', 'SEP', 'ID', 'CLOSE']); }); it('allows multiple path literals on a line with []', function() { - var result = tokenize("{{foo.[bar]}}{{foo.[baz]}}"); + var result = tokenize('{{foo.[bar]}}{{foo.[baz]}}'); shouldMatchTokens(result, ['OPEN', 'ID', 'SEP', 'ID', 'CLOSE', 'OPEN', 'ID', 'SEP', 'ID', 'CLOSE']); }); it('tokenizes {{.}} as OPEN ID CLOSE', function() { - var result = tokenize("{{.}}"); + var result = tokenize('{{.}}'); shouldMatchTokens(result, ['OPEN', 'ID', 'CLOSE']); }); it('tokenizes a path as "OPEN (ID SEP)* ID CLOSE"', function() { - var result = tokenize("{{../foo/bar}}"); + var result = tokenize('{{../foo/bar}}'); shouldMatchTokens(result, ['OPEN', 'ID', 'SEP', 'ID', 'SEP', 'ID', 'CLOSE']); - shouldBeToken(result[1], "ID", ".."); + shouldBeToken(result[1], 'ID', '..'); }); it('tokenizes a path with .. as a parent path', function() { - var result = tokenize("{{../foo.bar}}"); + var result = tokenize('{{../foo.bar}}'); shouldMatchTokens(result, ['OPEN', 'ID', 'SEP', 'ID', 'SEP', 'ID', 'CLOSE']); - shouldBeToken(result[1], "ID", ".."); + shouldBeToken(result[1], 'ID', '..'); }); it('tokenizes a path with this/foo as OPEN ID SEP ID CLOSE', function() { - var result = tokenize("{{this/foo}}"); + var result = tokenize('{{this/foo}}'); shouldMatchTokens(result, ['OPEN', 'ID', 'SEP', 'ID', 'CLOSE']); - shouldBeToken(result[1], "ID", "this"); - shouldBeToken(result[3], "ID", "foo"); + shouldBeToken(result[1], 'ID', 'this'); + shouldBeToken(result[3], 'ID', 'foo'); }); it('tokenizes a simple mustache with spaces as "OPEN ID CLOSE"', function() { - var result = tokenize("{{ foo }}"); + var result = tokenize('{{ foo }}'); shouldMatchTokens(result, ['OPEN', 'ID', 'CLOSE']); - shouldBeToken(result[1], "ID", "foo"); + shouldBeToken(result[1], 'ID', 'foo'); }); it('tokenizes a simple mustache with line breaks as "OPEN ID ID CLOSE"', function() { - var result = tokenize("{{ foo \n bar }}"); + var result = tokenize('{{ foo \n bar }}'); shouldMatchTokens(result, ['OPEN', 'ID', 'ID', 'CLOSE']); - shouldBeToken(result[1], "ID", "foo"); + shouldBeToken(result[1], 'ID', 'foo'); }); it('tokenizes raw content as "CONTENT"', function() { - var result = tokenize("foo {{ bar }} baz"); + var result = tokenize('foo {{ bar }} baz'); shouldMatchTokens(result, ['CONTENT', 'OPEN', 'ID', 'CLOSE', 'CONTENT']); - shouldBeToken(result[0], "CONTENT", "foo "); - shouldBeToken(result[4], "CONTENT", " baz"); + shouldBeToken(result[0], 'CONTENT', 'foo '); + shouldBeToken(result[4], 'CONTENT', ' baz'); }); it('tokenizes a partial as "OPEN_PARTIAL ID CLOSE"', function() { - var result = tokenize("{{> foo}}"); + var result = tokenize('{{> foo}}'); shouldMatchTokens(result, ['OPEN_PARTIAL', 'ID', 'CLOSE']); }); it('tokenizes a partial with context as "OPEN_PARTIAL ID ID CLOSE"', function() { - var result = tokenize("{{> foo bar }}"); + var result = tokenize('{{> foo bar }}'); shouldMatchTokens(result, ['OPEN_PARTIAL', 'ID', 'ID', 'CLOSE']); }); it('tokenizes a partial without spaces as "OPEN_PARTIAL ID CLOSE"', function() { - var result = tokenize("{{>foo}}"); + var result = tokenize('{{>foo}}'); shouldMatchTokens(result, ['OPEN_PARTIAL', 'ID', 'CLOSE']); }); it('tokenizes a partial space at the }); as "OPEN_PARTIAL ID CLOSE"', function() { - var result = tokenize("{{>foo }}"); + var result = tokenize('{{>foo }}'); shouldMatchTokens(result, ['OPEN_PARTIAL', 'ID', 'CLOSE']); }); it('tokenizes a partial space at the }); as "OPEN_PARTIAL ID CLOSE"', function() { - var result = tokenize("{{>foo/bar.baz }}"); + var result = tokenize('{{>foo/bar.baz }}'); shouldMatchTokens(result, ['OPEN_PARTIAL', 'ID', 'SEP', 'ID', 'SEP', 'ID', 'CLOSE']); }); it('tokenizes a comment as "COMMENT"', function() { - var result = tokenize("foo {{! this is a comment }} bar {{ baz }}"); + var result = tokenize('foo {{! this is a comment }} bar {{ baz }}'); shouldMatchTokens(result, ['CONTENT', 'COMMENT', 'CONTENT', 'OPEN', 'ID', 'CLOSE']); - shouldBeToken(result[1], "COMMENT", "{{! this is a comment }}"); + shouldBeToken(result[1], 'COMMENT', '{{! this is a comment }}'); }); it('tokenizes a block comment as "COMMENT"', function() { - var result = tokenize("foo {{!-- this is a {{comment}} --}} bar {{ baz }}"); + var result = tokenize('foo {{!-- this is a {{comment}} --}} bar {{ baz }}'); shouldMatchTokens(result, ['CONTENT', 'COMMENT', 'CONTENT', 'OPEN', 'ID', 'CLOSE']); - shouldBeToken(result[1], "COMMENT", "{{!-- this is a {{comment}} --}}"); + shouldBeToken(result[1], 'COMMENT', '{{!-- this is a {{comment}} --}}'); }); it('tokenizes a block comment with whitespace as "COMMENT"', function() { - var result = tokenize("foo {{!-- this is a\n{{comment}}\n--}} bar {{ baz }}"); + var result = tokenize('foo {{!-- this is a\n{{comment}}\n--}} bar {{ baz }}'); shouldMatchTokens(result, ['CONTENT', 'COMMENT', 'CONTENT', 'OPEN', 'ID', 'CLOSE']); - shouldBeToken(result[1], "COMMENT", "{{!-- this is a\n{{comment}}\n--}}"); + shouldBeToken(result[1], 'COMMENT', '{{!-- this is a\n{{comment}}\n--}}'); }); it('tokenizes open and closing blocks as OPEN_BLOCK, ID, CLOSE ..., OPEN_ENDBLOCK ID CLOSE', function() { - var result = tokenize("{{#foo}}content{{/foo}}"); + var result = tokenize('{{#foo}}content{{/foo}}'); shouldMatchTokens(result, ['OPEN_BLOCK', 'ID', 'CLOSE', 'CONTENT', 'OPEN_ENDBLOCK', 'ID', 'CLOSE']); }); it('tokenizes inverse sections as "INVERSE"', function() { - shouldMatchTokens(tokenize("{{^}}"), ['INVERSE']); - shouldMatchTokens(tokenize("{{else}}"), ['INVERSE']); - shouldMatchTokens(tokenize("{{ else }}"), ['INVERSE']); + shouldMatchTokens(tokenize('{{^}}'), ['INVERSE']); + shouldMatchTokens(tokenize('{{else}}'), ['INVERSE']); + shouldMatchTokens(tokenize('{{ else }}'), ['INVERSE']); }); it('tokenizes inverse sections with ID as "OPEN_INVERSE ID CLOSE"', function() { - var result = tokenize("{{^foo}}"); + var result = tokenize('{{^foo}}'); shouldMatchTokens(result, ['OPEN_INVERSE', 'ID', 'CLOSE']); - shouldBeToken(result[1], "ID", "foo"); + shouldBeToken(result[1], 'ID', 'foo'); }); it('tokenizes inverse sections with ID and spaces as "OPEN_INVERSE ID CLOSE"', function() { - var result = tokenize("{{^ foo }}"); + var result = tokenize('{{^ foo }}'); shouldMatchTokens(result, ['OPEN_INVERSE', 'ID', 'CLOSE']); - shouldBeToken(result[1], "ID", "foo"); + shouldBeToken(result[1], 'ID', 'foo'); }); it('tokenizes mustaches with params as "OPEN ID ID ID CLOSE"', function() { - var result = tokenize("{{ foo bar baz }}"); + var result = tokenize('{{ foo bar baz }}'); shouldMatchTokens(result, ['OPEN', 'ID', 'ID', 'ID', 'CLOSE']); - shouldBeToken(result[1], "ID", "foo"); - shouldBeToken(result[2], "ID", "bar"); - shouldBeToken(result[3], "ID", "baz"); + shouldBeToken(result[1], 'ID', 'foo'); + shouldBeToken(result[2], 'ID', 'bar'); + shouldBeToken(result[3], 'ID', 'baz'); }); it('tokenizes mustaches with String params as "OPEN ID ID STRING CLOSE"', function() { - var result = tokenize("{{ foo bar \"baz\" }}"); + var result = tokenize('{{ foo bar \'baz\' }}'); shouldMatchTokens(result, ['OPEN', 'ID', 'ID', 'STRING', 'CLOSE']); - shouldBeToken(result[3], "STRING", "baz"); + shouldBeToken(result[3], 'STRING', 'baz'); }); it('tokenizes mustaches with String params using single quotes as "OPEN ID ID STRING CLOSE"', function() { var result = tokenize("{{ foo bar \'baz\' }}"); shouldMatchTokens(result, ['OPEN', 'ID', 'ID', 'STRING', 'CLOSE']); - shouldBeToken(result[3], "STRING", "baz"); + shouldBeToken(result[3], 'STRING', 'baz'); }); it('tokenizes String params with spaces inside as "STRING"', function() { - var result = tokenize("{{ foo bar \"baz bat\" }}"); + var result = tokenize('{{ foo bar "baz bat" }}'); shouldMatchTokens(result, ['OPEN', 'ID', 'ID', 'STRING', 'CLOSE']); - shouldBeToken(result[3], "STRING", "baz bat"); + shouldBeToken(result[3], 'STRING', 'baz bat'); }); it('tokenizes String params with escapes quotes as STRING', function() { var result = tokenize('{{ foo "bar\\"baz" }}'); shouldMatchTokens(result, ['OPEN', 'ID', 'STRING', 'CLOSE']); - shouldBeToken(result[2], "STRING", 'bar"baz'); + shouldBeToken(result[2], 'STRING', 'bar"baz'); }); it('tokenizes String params using single quotes with escapes quotes as STRING', function() { var result = tokenize("{{ foo 'bar\\'baz' }}"); shouldMatchTokens(result, ['OPEN', 'ID', 'STRING', 'CLOSE']); - shouldBeToken(result[2], "STRING", "bar'baz"); + shouldBeToken(result[2], 'STRING', "bar'baz"); }); it('tokenizes numbers', function() { var result = tokenize('{{ foo 1 }}'); shouldMatchTokens(result, ['OPEN', 'ID', 'NUMBER', 'CLOSE']); - shouldBeToken(result[2], "NUMBER", "1"); + shouldBeToken(result[2], 'NUMBER', '1'); result = tokenize('{{ foo 1.1 }}'); shouldMatchTokens(result, ['OPEN', 'ID', 'NUMBER', 'CLOSE']); - shouldBeToken(result[2], "NUMBER", "1.1"); + shouldBeToken(result[2], 'NUMBER', '1.1'); result = tokenize('{{ foo -1 }}'); shouldMatchTokens(result, ['OPEN', 'ID', 'NUMBER', 'CLOSE']); - shouldBeToken(result[2], "NUMBER", "-1"); + shouldBeToken(result[2], 'NUMBER', '-1'); result = tokenize('{{ foo -1.1 }}'); shouldMatchTokens(result, ['OPEN', 'ID', 'NUMBER', 'CLOSE']); - shouldBeToken(result[2], "NUMBER", "-1.1"); + shouldBeToken(result[2], 'NUMBER', '-1.1'); }); it('tokenizes booleans', function() { var result = tokenize('{{ foo true }}'); shouldMatchTokens(result, ['OPEN', 'ID', 'BOOLEAN', 'CLOSE']); - shouldBeToken(result[2], "BOOLEAN", "true"); + shouldBeToken(result[2], 'BOOLEAN', 'true'); result = tokenize('{{ foo false }}'); shouldMatchTokens(result, ['OPEN', 'ID', 'BOOLEAN', 'CLOSE']); - shouldBeToken(result[2], "BOOLEAN", "false"); + shouldBeToken(result[2], 'BOOLEAN', 'false'); }); it('tokenizes undefined and null', function() { @@ -330,77 +329,77 @@ describe('Tokenizer', function() { }); it('tokenizes hash arguments', function() { - var result = tokenize("{{ foo bar=baz }}"); + var result = tokenize('{{ foo bar=baz }}'); shouldMatchTokens(result, ['OPEN', 'ID', 'ID', 'EQUALS', 'ID', 'CLOSE']); - result = tokenize("{{ foo bar baz=bat }}"); + result = tokenize('{{ foo bar baz=bat }}'); shouldMatchTokens(result, ['OPEN', 'ID', 'ID', 'ID', 'EQUALS', 'ID', 'CLOSE']); - result = tokenize("{{ foo bar baz=1 }}"); + result = tokenize('{{ foo bar baz=1 }}'); shouldMatchTokens(result, ['OPEN', 'ID', 'ID', 'ID', 'EQUALS', 'NUMBER', 'CLOSE']); - result = tokenize("{{ foo bar baz=true }}"); + result = tokenize('{{ foo bar baz=true }}'); shouldMatchTokens(result, ['OPEN', 'ID', 'ID', 'ID', 'EQUALS', 'BOOLEAN', 'CLOSE']); - result = tokenize("{{ foo bar baz=false }}"); + result = tokenize('{{ foo bar baz=false }}'); shouldMatchTokens(result, ['OPEN', 'ID', 'ID', 'ID', 'EQUALS', 'BOOLEAN', 'CLOSE']); - result = tokenize("{{ foo bar\n baz=bat }}"); + result = tokenize('{{ foo bar\n baz=bat }}'); shouldMatchTokens(result, ['OPEN', 'ID', 'ID', 'ID', 'EQUALS', 'ID', 'CLOSE']); - result = tokenize("{{ foo bar baz=\"bat\" }}"); + result = tokenize('{{ foo bar baz=\"bat\" }}'); shouldMatchTokens(result, ['OPEN', 'ID', 'ID', 'ID', 'EQUALS', 'STRING', 'CLOSE']); - result = tokenize("{{ foo bar baz=\"bat\" bam=wot }}"); + result = tokenize('{{ foo bar baz=\"bat\" bam=wot }}'); shouldMatchTokens(result, ['OPEN', 'ID', 'ID', 'ID', 'EQUALS', 'STRING', 'ID', 'EQUALS', 'ID', 'CLOSE']); - result = tokenize("{{foo omg bar=baz bat=\"bam\"}}"); + result = tokenize('{{foo omg bar=baz bat=\"bam\"}}'); shouldMatchTokens(result, ['OPEN', 'ID', 'ID', 'ID', 'EQUALS', 'ID', 'ID', 'EQUALS', 'STRING', 'CLOSE']); - shouldBeToken(result[2], "ID", "omg"); + shouldBeToken(result[2], 'ID', 'omg'); }); it('tokenizes special @ identifiers', function() { - var result = tokenize("{{ @foo }}"); + var result = tokenize('{{ @foo }}'); shouldMatchTokens(result, ['OPEN', 'DATA', 'ID', 'CLOSE']); - shouldBeToken(result[2], "ID", "foo"); + shouldBeToken(result[2], 'ID', 'foo'); - result = tokenize("{{ foo @bar }}"); + result = tokenize('{{ foo @bar }}'); shouldMatchTokens(result, ['OPEN', 'ID', 'DATA', 'ID', 'CLOSE']); - shouldBeToken(result[3], "ID", "bar"); + shouldBeToken(result[3], 'ID', 'bar'); - result = tokenize("{{ foo bar=@baz }}"); + result = tokenize('{{ foo bar=@baz }}'); shouldMatchTokens(result, ['OPEN', 'ID', 'ID', 'EQUALS', 'DATA', 'ID', 'CLOSE']); - shouldBeToken(result[5], "ID", "baz"); + shouldBeToken(result[5], 'ID', 'baz'); }); it('does not time out in a mustache with a single } followed by EOF', function() { - shouldMatchTokens(tokenize("{{foo}"), ['OPEN', 'ID']); + shouldMatchTokens(tokenize('{{foo}'), ['OPEN', 'ID']); }); it('does not time out in a mustache when invalid ID characters are used', function() { - shouldMatchTokens(tokenize("{{foo & }}"), ['OPEN', 'ID']); + shouldMatchTokens(tokenize('{{foo & }}'), ['OPEN', 'ID']); }); it('tokenizes subexpressions', function() { - var result = tokenize("{{foo (bar)}}"); + var result = tokenize('{{foo (bar)}}'); shouldMatchTokens(result, ['OPEN', 'ID', 'OPEN_SEXPR', 'ID', 'CLOSE_SEXPR', 'CLOSE']); - shouldBeToken(result[1], "ID", "foo"); - shouldBeToken(result[3], "ID", "bar"); + shouldBeToken(result[1], 'ID', 'foo'); + shouldBeToken(result[3], 'ID', 'bar'); - result = tokenize("{{foo (a-x b-y)}}"); + result = tokenize('{{foo (a-x b-y)}}'); shouldMatchTokens(result, ['OPEN', 'ID', 'OPEN_SEXPR', 'ID', 'ID', 'CLOSE_SEXPR', 'CLOSE']); - shouldBeToken(result[1], "ID", "foo"); - shouldBeToken(result[3], "ID", "a-x"); - shouldBeToken(result[4], "ID", "b-y"); + shouldBeToken(result[1], 'ID', 'foo'); + shouldBeToken(result[3], 'ID', 'a-x'); + shouldBeToken(result[4], 'ID', 'b-y'); }); it('tokenizes nested subexpressions', function() { - var result = tokenize("{{foo (bar (lol rofl)) (baz)}}"); + var result = tokenize('{{foo (bar (lol rofl)) (baz)}}'); shouldMatchTokens(result, ['OPEN', 'ID', 'OPEN_SEXPR', 'ID', 'OPEN_SEXPR', 'ID', 'ID', 'CLOSE_SEXPR', 'CLOSE_SEXPR', 'OPEN_SEXPR', 'ID', 'CLOSE_SEXPR', 'CLOSE']); - shouldBeToken(result[3], "ID", "bar"); - shouldBeToken(result[5], "ID", "lol"); - shouldBeToken(result[6], "ID", "rofl"); - shouldBeToken(result[10], "ID", "baz"); + shouldBeToken(result[3], 'ID', 'bar'); + shouldBeToken(result[5], 'ID', 'lol'); + shouldBeToken(result[6], 'ID', 'rofl'); + shouldBeToken(result[10], 'ID', 'baz'); }); it('tokenizes nested subexpressions: literals', function() { @@ -409,19 +408,19 @@ describe('Tokenizer', function() { }); it('tokenizes block params', function() { - var result = tokenize("{{#foo as |bar|}}"); + var result = tokenize('{{#foo as |bar|}}'); shouldMatchTokens(result, ['OPEN_BLOCK', 'ID', 'OPEN_BLOCK_PARAMS', 'ID', 'CLOSE_BLOCK_PARAMS', 'CLOSE']); - result = tokenize("{{#foo as |bar baz|}}"); + result = tokenize('{{#foo as |bar baz|}}'); shouldMatchTokens(result, ['OPEN_BLOCK', 'ID', 'OPEN_BLOCK_PARAMS', 'ID', 'ID', 'CLOSE_BLOCK_PARAMS', 'CLOSE']); - result = tokenize("{{#foo as | bar baz |}}"); + result = tokenize('{{#foo as | bar baz |}}'); shouldMatchTokens(result, ['OPEN_BLOCK', 'ID', 'OPEN_BLOCK_PARAMS', 'ID', 'ID', 'CLOSE_BLOCK_PARAMS', 'CLOSE']); - result = tokenize("{{#foo as as | bar baz |}}"); + result = tokenize('{{#foo as as | bar baz |}}'); shouldMatchTokens(result, ['OPEN_BLOCK', 'ID', 'ID', 'OPEN_BLOCK_PARAMS', 'ID', 'ID', 'CLOSE_BLOCK_PARAMS', 'CLOSE']); - result = tokenize("{{else foo as |bar baz|}}"); + result = tokenize('{{else foo as |bar baz|}}'); shouldMatchTokens(result, ['OPEN_INVERSE_CHAIN', 'ID', 'OPEN_BLOCK_PARAMS', 'ID', 'ID', 'CLOSE_BLOCK_PARAMS', 'CLOSE']); }); }); diff --git a/spec/track-ids.js b/spec/track-ids.js index f337fbe..7a8b59e 100644 --- a/spec/track-ids.js +++ b/spec/track-ids.js @@ -1,4 +1,3 @@ -/*global CompilerContext */ describe('track ids', function() { var context; beforeEach(function() { @@ -27,7 +26,7 @@ describe('track ids', function() { 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; + return 'HELP ME MY BOSS ' + options.ids[0] + ':' + passiveVoice + ' ' + options.ids[1] + ':' + noun; } }; @@ -41,7 +40,7 @@ describe('track ids', function() { 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; + return 'HELP ME MY BOSS ' + options.hashIds.bat + ':' + options.hash.bat + ' ' + options.hashIds.baz + ':' + options.hash.baz; } }; @@ -55,7 +54,7 @@ describe('track ids', function() { 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; + return 'HELP ME MY BOSS ' + options.ids[0] + ':' + passiveVoice + ' ' + options.ids[1] + ':' + noun; } }; @@ -69,11 +68,11 @@ describe('track ids', function() { 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; + 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'); + equals(template({}, {helpers: helpers, data: context}), 'HELP ME MY BOSS @is.a:foo @slave.driver:bar'); }); it('should return null for constants', function() { @@ -85,7 +84,7 @@ describe('track ids', function() { equal(options.ids[1], null); equal(options.hashIds.key, null); - return "HELP ME MY BOSS " + passiveVoice + ' ' + noun + ' ' + options.hash.key; + return 'HELP ME MY BOSS ' + passiveVoice + ' ' + noun + ' ' + options.hash.key; } }; @@ -99,7 +98,7 @@ describe('track ids', function() { wycats: function(passiveVoice, options) { equal(options.ids[0], true); - return "HELP ME MY BOSS " + passiveVoice; + return 'HELP ME MY BOSS ' + passiveVoice; } }; @@ -120,7 +119,7 @@ describe('track ids', function() { equal(options.ids[1], 'slave.driver'); equal(options.ids[2], 'zomg'); - return "HELP ME MY BOSS " + options.ids[0] + ':' + passiveVoice + ' ' + options.ids[1] + ':' + noun; + return 'HELP ME MY BOSS ' + options.ids[0] + ':' + passiveVoice + ' ' + options.ids[1] + ':' + noun; } }; @@ -129,6 +128,9 @@ describe('track ids', function() { 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'; } @@ -151,13 +153,7 @@ describe('track ids', function() { equals(template({array: [{name: 'foo'}, {name: 'bar'}]}, {helpers: helpers}), 'foo:.array..0\nbar:.array..1\n'); }); it('should handle block params', function() { - var helpers = { - wycats: function(name, options) { - return name + ':' + options.ids[0] + '\n'; - } - }; - - var template = CompilerContext.compile('{{#each array as |value|}}{{wycats value.name}}{{/each}}', {trackIds: true}); + 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'); }); diff --git a/spec/utils.js b/spec/utils.js index 4582e24..81732c5 100644 --- a/spec/utils.js +++ b/spec/utils.js @@ -1,19 +1,17 @@ -/*global Handlebars, shouldCompileTo */ - describe('utils', function() { describe('#SafeString', function() { - it("constructing a safestring from a string and checking its type", function() { - var safe = new Handlebars.SafeString("testing 1, 2, 3"); + it('constructing a safestring from a string and checking its type', function() { + var safe = new Handlebars.SafeString('testing 1, 2, 3'); if (!(safe instanceof Handlebars.SafeString)) { throw new Error('Must be instance of SafeString'); } - equals(safe == 'testing 1, 2, 3', true, 'SafeString is equivalent to its underlying string'); + equals(safe.toString(), 'testing 1, 2, 3', 'SafeString is equivalent to its underlying string'); }); - it("it should not escape SafeString properties", function() { - var name = new Handlebars.SafeString("<em>Sean O'Malley</em>"); + it('it should not escape SafeString properties', function() { + var name = new Handlebars.SafeString('<em>Sean O'Malley</em>'); - shouldCompileTo('{{name}}', [{ name: name }], "<em>Sean O'Malley</em>"); + shouldCompileTo('{{name}}', [{name: name}], '<em>Sean O'Malley</em>'); }); }); diff --git a/spec/visitor.js b/spec/visitor.js index 8b9ef9f..1f50d79 100644 --- a/spec/visitor.js +++ b/spec/visitor.js @@ -1,5 +1,3 @@ -/*global Handlebars, shouldThrow */ - describe('Visitor', function() { if (!Handlebars.Visitor || !Handlebars.print) { return; diff --git a/spec/whitespace-control.js b/spec/whitespace-control.js index cce9405..a5c9bf1 100644 --- a/spec/whitespace-control.js +++ b/spec/whitespace-control.js @@ -1,5 +1,3 @@ -/*global shouldCompileTo, shouldCompileToWithPartials */ - describe('whitespace control', function() { it('should strip whitespace around mustache calls', function() { var hash = {foo: 'bar<'}; diff --git a/tasks/version.js b/tasks/version.js index c622a22..e6bfe59 100644 --- a/tasks/version.js +++ b/tasks/version.js @@ -18,7 +18,7 @@ module.exports = function(grunt) { grunt.log.writeln('Updating to version ' + version); async.each([ - ['lib/handlebars/base.js', /var VERSION = "(.*)";/, 'var VERSION = "' + version + '";'], + ['lib/handlebars/base.js', /var VERSION = ['"](.*)['"];/, 'var VERSION = "' + version + '";'], ['components/bower.json', /"version":.*/, '"version": "' + version + '",'], ['components/handlebars.js.nuspec', /<version>.*<\/version>/, '<version>' + version + '</version>'] ], |