diff options
author | kpdecker <kpdecker@gmail.com> | 2015-04-16 15:42:46 -0500 |
---|---|---|
committer | kpdecker <kpdecker@gmail.com> | 2015-04-16 16:43:01 -0500 |
commit | e3d3eda2e1e03e997d417affc09974446b4ca701 (patch) | |
tree | a6513f267482b1693fd002c20488c6e92095ff2b | |
parent | 2a02261a5bc78f246c63dd8d467a12f2c1f63734 (diff) | |
download | handlebars.js-e3d3eda2e1e03e997d417affc09974446b4ca701.zip handlebars.js-e3d3eda2e1e03e997d417affc09974446b4ca701.tar.gz handlebars.js-e3d3eda2e1e03e997d417affc09974446b4ca701.tar.bz2 |
Add full support for es6
Converts the tool chain to use babel, eslint, and webpack vs. the previous proprietary solutions.
Additionally begins enforcing additional linting concerns as well as updates the code to reflect these rules.
Fixes #855
Fixes #993
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..4863004 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', + libraryType: '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>'] ], |