diff --git a/.eslintrc b/.eslintrc new file mode 100644 index 000000000..253a1bb29 --- /dev/null +++ b/.eslintrc @@ -0,0 +1,199 @@ +{ + "globals": { + "self": false + }, + "env": { + "node": true + }, + "ecmaFeatures": { + // Enabling features that can be implemented without polyfills. Want to avoid polyfills at this time. + "arrowFunctions": true, + "blockBindings": true, + "defaultParams": true, + "destructuring": true, + "modules": true, + "objectLiteralComputedProperties": true, + "objectLiteralDuplicateProperties": true, + "objectLiteralShorthandMethods": true, + "objectLiteralShorthandProperties": true, + "spread": true, + "templateStrings": true + }, + "rules": { + // Possible Errors // + //-----------------// + + "comma-dangle": [2, "never"], + "no-cond-assign": [2, "except-parens"], + + // Allow for debugging + "no-console": 1, + + "no-constant-condition": 2, + "no-control-regex": 2, + + // Allow for debugging + "no-debugger": 1, + + "no-dupe-args": 2, + "no-dupe-keys": 2, + "no-duplicate-case": 2, + "no-empty": 2, + "no-empty-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-var": 1 + } +} \ No newline at end of file diff --git a/Gruntfile.js b/Gruntfile.js index b73974059..70239bf8b 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,21 +41,14 @@ 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/', @@ -65,30 +58,61 @@ module.exports = function(grunt) { }, cjs: { - type: 'cjs', + options: { + modules: 'common' + }, files: [{ - expand: true, cwd: 'lib/', + expand: true, src: '**/!(index).js', dest: 'dist/cjs/' }] } }, + webpack: { + options: { + context: __dirname, + module: { + loaders: [ + // the optional 'runtime' transformer tells babel to require the runtime instead of inlining it. + { test: /\.jsx?$/, exclude: /node_modules/, loader: 'babel-loader?optional=runtime&loose=es6.modules' } + ] + }, + output: { + path: 'dist/', + library: 'Handlebars', + libraryTarget: 'umd' + } + }, + handlebars: { + entry: './lib/handlebars.js', + output: { + filename: 'handlebars.js' + } + }, + runtime: { + entry: './lib/handlebars.runtime.js', + output: { + filename: 'handlebars.runtime.js' + } + } + }, + requirejs: { options: { - optimize: "none", - baseUrl: "dist/amd/" + optimize: 'none', + baseUrl: 'dist/amd/' }, dist: { options: { - name: "handlebars", - out: "dist/handlebars.amd.js" + name: 'handlebars', + out: 'dist/handlebars.amd.js' } }, runtime: { options: { - name: "handlebars.runtime", - out: "dist/handlebars.runtime.amd.js" + name: 'handlebars.runtime', + out: 'dist/handlebars.runtime.amd.js' } } }, @@ -172,18 +196,18 @@ module.exports = function(grunt) { }); // Build a new version of the library - this.registerTask('build', "Builds a distributable version of the current project", [ + this.registerTask('build', 'Builds a distributable version of the current project', [ + 'eslint', 'parser', 'node', - 'globals', - 'jshint']); + 'globals']); - this.registerTask('amd', ['packager:amd', 'requirejs']); - this.registerTask('node', ['packager:cjs']); - this.registerTask('globals', ['packager:global']); + this.registerTask('amd', ['babel:amd', 'requirejs']); + this.registerTask('node', ['babel:cjs']); + this.registerTask('globals', ['webpack']); this.registerTask('tests', ['concat:tests']); - this.registerTask('release', 'Build final packages', ['amd', 'jshint', 'uglify', 'copy:dist', 'copy:components', 'copy:cdnjs']); + this.registerTask('release', 'Build final packages', ['eslint', 'amd', 'uglify', 'copy:dist', 'copy:components', 'copy:cdnjs']); // Load tasks from npm grunt.loadNpmTasks('grunt-contrib-clean'); @@ -191,11 +215,12 @@ module.exports = function(grunt) { grunt.loadNpmTasks('grunt-contrib-connect'); grunt.loadNpmTasks('grunt-contrib-copy'); grunt.loadNpmTasks('grunt-contrib-requirejs'); - grunt.loadNpmTasks('grunt-contrib-jshint'); grunt.loadNpmTasks('grunt-contrib-uglify'); grunt.loadNpmTasks('grunt-contrib-watch'); + grunt.loadNpmTasks('grunt-babel'); + grunt.loadNpmTasks('grunt-eslint'); grunt.loadNpmTasks('grunt-saucelabs'); - grunt.loadNpmTasks('es6-module-packager'); + grunt.loadNpmTasks('grunt-webpack'); grunt.task.loadTasks('tasks'); diff --git a/bin/handlebars b/bin/handlebars index bf64784aa..4ed98b372 100755 --- a/bin/handlebars +++ b/bin/handlebars @@ -108,4 +108,4 @@ if (argv.help || (!argv.templates.length && !argv.version)) { return; } -return require('../lib/precompiler').cli(argv); +return require('../dist/cjs/precompiler').cli(argv); diff --git a/components/bower.json b/components/bower.json index 0726c8468..7163ae75b 100644 --- a/components/bower.json +++ b/components/bower.json @@ -1,6 +1,6 @@ { "name": "handlebars", - "version": "3.0.1", + "version": "3.0.2", "main": "handlebars.js", "dependencies": {} } diff --git a/components/handlebars.js.nuspec b/components/handlebars.js.nuspec index 9525fcf4c..20e3840b7 100644 --- a/components/handlebars.js.nuspec +++ b/components/handlebars.js.nuspec @@ -2,7 +2,7 @@ handlebars.js - 3.0.1 + 3.0.2 handlebars.js Authors https://github.com/wycats/handlebars.js/blob/master/LICENSE https://github.com/wycats/handlebars.js/ diff --git a/docs/compiler-api.md b/docs/compiler-api.md index 40ded8fd2..c09414f0b 100644 --- a/docs/compiler-api.md +++ b/docs/compiler-api.md @@ -164,6 +164,14 @@ interface NumberLiteral <: Literal { value: number; original: number; } + +interface UndefinedLiteral <: Literal { + type: "UndefinedLiteral"; +} + +interface NullLiteral <: Literal { + type: "NullLiteral"; +} ``` diff --git a/lib/handlebars.js b/lib/handlebars.js index 81b7cfbd2..3e566a798 100644 --- a/lib/handlebars.js +++ b/lib/handlebars.js @@ -1,20 +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 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() { - var hb = _create(); +let _create = Handlebars.create; +function create() { + let 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); }; @@ -25,22 +25,23 @@ var create = function() { hb.parse = parse; return hb; -}; +} + +let inst = create(); +inst.create = create; -Handlebars = create(); -Handlebars.create = create; +inst.Visitor = Visitor; /*jshint -W040 */ /* istanbul ignore next */ -var root = typeof global !== 'undefined' ? global : window, - $Handlebars = root.Handlebars; +let $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 ef00e2856..e7b149b73 100644 --- a/lib/handlebars.runtime.js +++ b/lib/handlebars.runtime.js @@ -1,16 +1,16 @@ -/*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() { - var hb = new base.HandlebarsEnvironment(); +function create() { + let hb = new base.HandlebarsEnvironment(); Utils.extend(hb, base); hb.SafeString = SafeString; @@ -24,14 +24,14 @@ var create = function() { }; return hb; -}; +} -var Handlebars = create(); +let Handlebars = create(); Handlebars.create = create; /*jshint -W040 */ /* istanbul ignore next */ -var root = typeof global !== 'undefined' ? global : window, +let root = typeof global !== 'undefined' ? global : window, $Handlebars = root.Handlebars; /* istanbul ignore next */ Handlebars.noConflict = function() { diff --git a/lib/handlebars/base.js b/lib/handlebars/base.js index 293d5eaef..cfe1e917c 100644 --- a/lib/handlebars/base.js +++ b/lib/handlebars/base.js @@ -1,10 +1,10 @@ -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 COMPILER_REVISION = 6; +export const VERSION = '3.0.1'; +export const COMPILER_REVISION = 6; -export var REVISION_CHANGES = { +export const REVISION_CHANGES = { 1: '<= 1.0.rc.2', // 1.0.rc.2 is actually rev2 but doesn't report it 2: '== 1.0.0-rc.3', 3: '== 1.0.0-rc.4', @@ -13,10 +13,10 @@ export var REVISION_CHANGES = { 6: '>= 2.0.0-beta.1' }; -var isArray = Utils.isArray, - isFunction = Utils.isFunction, - toString = Utils.toString, - objectType = '[object Object]'; +const isArray = Utils.isArray, + isFunction = Utils.isFunction, + toString = Utils.toString, + objectType = '[object Object]'; export function HandlebarsEnvironment(helpers, partials) { this.helpers = helpers || {}; @@ -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,25 +60,25 @@ 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 + '"'); } }); instance.registerHelper('blockHelperMissing', function(context, options) { - var inverse = options.inverse, + let 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]; } @@ -89,7 +89,7 @@ function registerDefaultHelpers(instance) { } } else { if (options.data && options.ids) { - var data = createFrame(options.data); + let data = createFrame(options.data); data.contextPath = Utils.appendContextPath(options.data.contextPath, options.name); options = {data: data}; } @@ -103,10 +103,13 @@ function registerDefaultHelpers(instance) { throw new Exception('Must pass iterator to #each'); } - var fn = options.fn, inverse = options.inverse; - var i = 0, ret = "", data; + let fn = options.fn, + inverse = options.inverse, + i = 0, + ret = '', + data, + contextPath; - var contextPath; if (options.data && options.ids) { contextPath = Utils.appendContextPath(options.data.contextPath, options.ids[0]) + '.'; } @@ -117,51 +120,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 1) { throw new Exception('Unsupported number of partial arguments: ' + params.length, partial); } else if (!params.length) { params.push({type: 'PathExpression', parts: [], depth: 0}); } - var partialName = partial.name.original, + let partialName = partial.name.original, isDynamic = partial.name.type === 'SubExpression'; if (isDynamic) { this.accept(partial.name); @@ -163,7 +166,7 @@ Compiler.prototype = { this.setupFullMustacheParams(partial, undefined, undefined, true); - var indent = partial.indent || ''; + let indent = partial.indent || ''; if (this.options.preventIndent && indent) { this.opcode('appendContent', indent); indent = ''; @@ -174,9 +177,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'); @@ -193,7 +196,7 @@ Compiler.prototype = { SubExpression: function(sexpr) { transformLiteralToPath(sexpr); - var type = this.classifySexpr(sexpr); + let type = this.classifySexpr(sexpr); if (type === 'simple') { this.simpleSexpr(sexpr); @@ -204,7 +207,7 @@ Compiler.prototype = { } }, ambiguousSexpr: function(sexpr, program, inverse) { - var path = sexpr.path, + let path = sexpr.path, name = path.parts[0], isBlock = program != null || inverse != null; @@ -224,14 +227,14 @@ Compiler.prototype = { }, helperSexpr: function(sexpr, program, inverse) { - var params = this.setupFullMustacheParams(sexpr, program, inverse), + let params = this.setupFullMustacheParams(sexpr, program, inverse), path = sexpr.path, name = path.parts[0]; 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; @@ -244,13 +247,13 @@ Compiler.prototype = { this.addDepth(path.depth); this.opcode('getContext', path.depth); - var name = path.parts[0], + let name = path.parts[0], scoped = AST.helpers.scopedId(path), blockParamId = !path.depth && !scoped && this.blockParamIndex(name); 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) { @@ -273,12 +276,22 @@ Compiler.prototype = { this.opcode('pushLiteral', bool.value); }, + UndefinedLiteral: function() { + this.opcode('pushLiteral', 'undefined'); + }, + + NullLiteral: function() { + this.opcode('pushLiteral', 'null'); + }, + Hash: function(hash) { - var pairs = hash.pairs, i, l; + let pairs = hash.pairs, + i = 0, + l = pairs.length; this.opcode('pushHash'); - for (i=0, l=pairs.length; i= 0) { return [depth, param]; @@ -413,7 +429,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 || {}; @@ -424,18 +440,16 @@ export function precompile(input, options, env) { options.useDepths = true; } - var ast = env.parse(input, options); - var environment = new env.Compiler().compile(ast, options); + let ast = env.parse(input, options), + environment = new env.Compiler().compile(ast, options); return new env.JavaScriptCompiler().compile(environment, options); } -export function compile(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 || {}; - if (!('data' in options)) { options.data = true; } @@ -443,27 +457,27 @@ export function compile(input, options, env) { options.useDepths = true; } - var compiled; + let compiled; function compileInput() { - var ast = env.parse(input, options); - var environment = new env.Compiler().compile(ast, options); - var templateSpec = new env.JavaScriptCompiler().compile(environment, options, undefined, true); + let ast = env.parse(input, options), + environment = new env.Compiler().compile(ast, options), + templateSpec = new env.JavaScriptCompiler().compile(environment, options, undefined, true); return env.template(templateSpec); } // 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) { @@ -480,7 +494,7 @@ function argEquals(a, b) { } if (isArray(a) && isArray(b) && a.length === b.length) { - for (var i = 0; i < a.length; i++) { + for (let i = 0; i < a.length; i++) { if (!argEquals(a[i], b[i])) { return false; } @@ -491,9 +505,9 @@ function argEquals(a, b) { function transformLiteralToPath(sexpr) { if (!sexpr.path.parts) { - var literal = sexpr.path; + let 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 beaf98869..31daf6df9 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; @@ -12,10 +12,18 @@ export function SourceLocation(source, locInfo) { }; } +export function id(token) { + if (/^\[.*\]$/.test(token)) { + return token.substr(1, token.length - 2); + } else { + return token; + } +} + export function stripFlags(open, close) { return { open: open.charAt(2) === '~', - close: close.charAt(close.length-3) === '~' + close: close.charAt(close.length - 3) === '~' }; } @@ -28,16 +36,19 @@ export function preparePath(data, parts, locInfo) { /*jshint -W040 */ locInfo = this.locInfo(locInfo); - var original = data ? '@' : '', + let original = data ? '@' : '', dig = [], depth = 0, depthString = ''; - for(var i=0,l=parts.length; i 0) { throw new Exception('Invalid path: ' + original, {loc: locInfo}); } else if (part === '..') { @@ -55,7 +66,7 @@ export function preparePath(data, parts, locInfo) { export function prepareMustache(path, params, hash, open, strip, locInfo) { /*jshint -W040 */ // Must use charAt to support IE pre-10 - var escapeFlag = open.charAt(3) || open.charAt(2), + let escapeFlag = open.charAt(3) || open.charAt(2), escaped = escapeFlag !== '{' && escapeFlag !== '&'; return new this.MustacheStatement(path, params, hash, escaped, strip, this.locInfo(locInfo)); @@ -64,13 +75,13 @@ export function prepareMustache(path, params, hash, open, strip, locInfo) { export function prepareRawBlock(openRawBlock, content, close, locInfo) { /*jshint -W040 */ if (openRawBlock.path.original !== close) { - var errorNode = {loc: openRawBlock.path.loc}; + let errorNode = {loc: openRawBlock.path.loc}; throw new Exception(openRawBlock.path.original + " doesn't match " + close, errorNode); } locInfo = this.locInfo(locInfo); - var program = new this.Program([content], null, {}, locInfo); + let program = new this.Program([content], null, {}, locInfo); return new this.BlockStatement( openRawBlock.path, openRawBlock.params, openRawBlock.hash, @@ -83,14 +94,14 @@ export function prepareBlock(openBlock, program, inverseAndProgram, close, inver /*jshint -W040 */ // When we are chaining inverse calls, we will not have a close path if (close && close.path && openBlock.path.original !== close.path.original) { - var errorNode = {loc: openBlock.path.loc}; + let errorNode = {loc: openBlock.path.loc}; throw new Exception(openBlock.path.original + ' doesn\'t match ' + close.path.original, errorNode); } program.blockParams = openBlock.blockParams; - var inverse, + let inverse, inverseStrip; if (inverseAndProgram) { diff --git a/lib/handlebars/compiler/javascript-compiler.js b/lib/handlebars/compiler/javascript-compiler.js index a027edb91..75e50d2fe 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, "']"]; } @@ -24,8 +24,8 @@ JavaScriptCompiler.prototype = { }, compilerInfo: function() { - var revision = COMPILER_REVISION, - versions = REVISION_CHANGES[revision]; + const revision = COMPILER_REVISION, + versions = REVISION_CHANGES[revision]; return [revision, versions]; }, @@ -50,7 +50,7 @@ JavaScriptCompiler.prototype = { }, initializeBuffer: function() { - return this.quotedString(""); + return this.quotedString(''); }, // END PUBLIC API @@ -84,7 +84,7 @@ JavaScriptCompiler.prototype = { this.useDepths = this.useDepths || environment.useDepths || this.options.compat; this.useBlockParams = this.useBlockParams || environment.useBlockParams; - var opcodes = environment.opcodes, + let opcodes = environment.opcodes, opcode, firstLoc, i, @@ -107,13 +107,13 @@ JavaScriptCompiler.prototype = { throw new Exception('Compile completed with content left on stack'); } - var fn = this.createFunctionContext(asObject); + let fn = this.createFunctionContext(asObject); if (!this.isChild) { - var ret = { + let ret = { compiler: this.compilerInfo(), main: fn }; - var programs = this.context.programs; + let programs = this.context.programs; for (i = 0, l = programs.length; i < l; i++) { if (programs[i]) { ret[i] = programs[i]; @@ -166,11 +166,11 @@ JavaScriptCompiler.prototype = { }, createFunctionContext: function(asObject) { - var varDeclarations = ''; + let varDeclarations = ''; - var locals = this.stackVars.concat(this.registers.list); - if(locals.length > 0) { - varDeclarations += ", " + locals.join(", "); + let locals = this.stackVars.concat(this.registers.list); + if (locals.length > 0) { + varDeclarations += ', ' + locals.join(', '); } // Generate minimizer alias mappings @@ -179,9 +179,9 @@ JavaScriptCompiler.prototype = { // as the source nodes are reused in situ. For the non-source node compilation mode, // 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) { - var node = this.aliases[alias]; + let aliasCount = 0; + for (let alias in this.aliases) { // eslint-disable-line guard-for-in + let node = this.aliases[alias]; if (this.aliases.hasOwnProperty(alias) && node.children && node.referenceCount > 1) { varDeclarations += ', alias' + (++aliasCount) + '=' + alias; @@ -189,7 +189,7 @@ JavaScriptCompiler.prototype = { } } - var params = ["depth0", "helpers", "partials", "data"]; + let params = ['depth0', 'helpers', 'partials', 'data']; if (this.useBlockParams || this.useDepths) { params.push('blockParams'); @@ -199,7 +199,7 @@ JavaScriptCompiler.prototype = { } // Perform a second pass over the output to merge content when possible - var source = this.mergeSource(varDeclarations); + let source = this.mergeSource(varDeclarations); if (asObject) { params.push(source); @@ -210,14 +210,14 @@ JavaScriptCompiler.prototype = { } }, mergeSource: function(varDeclarations) { - var isSimple = this.environment.isSimple, + let isSimple = this.environment.isSimple, appendOnly = !this.forceBuffer, appendFirst, sourceSeen, bufferStart, bufferEnd; - this.source.each(function(line) { + this.source.each((line) => { if (line.appendToBuffer) { if (bufferStart) { line.prepend(' + '); @@ -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 + '); @@ -279,11 +279,11 @@ JavaScriptCompiler.prototype = { // replace it on the stack with the result of properly // invoking blockHelperMissing. blockValue: function(name) { - var blockHelperMissing = this.aliasable('helpers.blockHelperMissing'), + let blockHelperMissing = this.aliasable('helpers.blockHelperMissing'), params = [this.contextName(0)]; this.setupHelperArgs(name, 0, params); - var blockName = this.popStack(); + let blockName = this.popStack(); params.splice(1, 0, blockName); this.push(this.source.functionCall(blockHelperMissing, 'call', params)); @@ -297,13 +297,13 @@ JavaScriptCompiler.prototype = { // On stack, after, if lastHelper: value ambiguousBlockValue: function() { // We're being a bit cheeky and reusing the options value from the prior exec - var blockHelperMissing = this.aliasable('helpers.blockHelperMissing'), + let blockHelperMissing = this.aliasable('helpers.blockHelperMissing'), params = [this.contextName(0)]; this.setupHelperArgs('', 0, params, true); this.flushInline(); - var current = this.topStack(); + let current = this.topStack(); params.splice(1, 0, current); this.pushSource([ @@ -339,13 +339,11 @@ JavaScriptCompiler.prototype = { // Otherwise, the empty string is appended append: function() { if (this.isInline()) { - this.replaceStack(function(current) { - return [' != null ? ', current, ' : ""']; - }); + this.replaceStack((current) => [' != null ? ', current, ' : ""']); this.pushSource(this.appendToBuffer(this.popStack())); } else { - var local = this.popStack(); + let local = this.popStack(); this.pushSource(['if (', local, ' != null) { ', this.appendToBuffer(local, undefined, true), ' }']); if (this.environment.isSimple) { this.pushSource(['else { ', this.appendToBuffer("''", undefined, true), ' }']); @@ -393,7 +391,7 @@ JavaScriptCompiler.prototype = { // Looks up the value of `name` on the current context and pushes // it onto the stack. lookupOnContext: function(parts, falsy, scoped) { - var i = 0; + let i = 0; if (!scoped && this.options.compat && !this.lastContext) { // The depthed query is expected to handle the undefined logic for the root level that @@ -444,10 +442,11 @@ JavaScriptCompiler.prototype = { return; } - var len = parts.length; + let len = parts.length; for (; i < len; i++) { - this.replaceStack(function(current) { - var lookup = this.nameLookup(current, parts[i], type); + /*eslint-disable no-loop-func */ + this.replaceStack((current) => { + let lookup = this.nameLookup(current, parts[i], type); // We want to ensure that zero and false are handled properly if the context (falsy flag) // needs to have the special handling for these values. if (!falsy) { @@ -457,6 +456,7 @@ JavaScriptCompiler.prototype = { return [' && ', lookup]; } }); + /*eslint-enable no-loop-func */ } }, @@ -511,7 +511,7 @@ JavaScriptCompiler.prototype = { this.hash = {values: [], types: [], contexts: [], ids: []}; }, popHash: function() { - var hash = this.hash; + let hash = this.hash; this.hash = this.hashes.pop(); if (this.trackIds) { @@ -573,11 +573,11 @@ JavaScriptCompiler.prototype = { // // If the helper is not found, `helperMissing` is called. invokeHelper: function(paramSize, name, isSimple) { - var nonHelper = this.popStack(); - var helper = this.setupHelper(paramSize, name); - var simple = isSimple ? [helper.name, ' || '] : ''; + let nonHelper = this.popStack(), + helper = this.setupHelper(paramSize, name), + simple = isSimple ? [helper.name, ' || '] : ''; - var lookup = ['('].concat(simple, nonHelper); + let lookup = ['('].concat(simple, nonHelper); if (!this.options.strict) { lookup.push(' || ', this.aliasable('helpers.helperMissing')); } @@ -594,7 +594,7 @@ JavaScriptCompiler.prototype = { // This operation is used when the helper is known to exist, // so a `helperMissing` fallback is not required. invokeKnownHelper: function(paramSize, name) { - var helper = this.setupHelper(paramSize, name); + let helper = this.setupHelper(paramSize, name); this.push(this.source.functionCall(helper.name, 'call', helper.callParams)); }, @@ -613,14 +613,14 @@ JavaScriptCompiler.prototype = { invokeAmbiguous: function(name, helperCall) { this.useRegister('helper'); - var nonHelper = this.popStack(); + let nonHelper = this.popStack(); this.emptyHash(); - var helper = this.setupHelper(0, name, helperCall); + let helper = this.setupHelper(0, name, helperCall); - var helperName = this.lastHelper = this.nameLookup('helpers', name, 'helper'); + let helperName = this.lastHelper = this.nameLookup('helpers', name, 'helper'); - var lookup = ['(', '(helper = ', helperName, ' || ', nonHelper, ')']; + let lookup = ['(', '(helper = ', helperName, ' || ', nonHelper, ')']; if (!this.options.strict) { lookup[0] = '(helper = '; lookup.push( @@ -633,7 +633,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))' ]); }, @@ -645,7 +645,7 @@ JavaScriptCompiler.prototype = { // This operation pops off a context, invokes a partial with that context, // and pushes the result of the invocation back. invokePartial: function(isDynamic, name, indent) { - var params = [], + let params = [], options = this.setupParams(name, 1, params, false); if (isDynamic) { @@ -681,7 +681,7 @@ JavaScriptCompiler.prototype = { // // Pops a value off the stack and assigns it to the current hash assignToHash: function(key) { - var value = this.popStack(), + let value = this.popStack(), context, type, id; @@ -694,7 +694,7 @@ JavaScriptCompiler.prototype = { context = this.popStack(); } - var hash = this.hash; + let hash = this.hash; if (context) { hash.contexts[key] = context; } @@ -726,13 +726,13 @@ JavaScriptCompiler.prototype = { compiler: JavaScriptCompiler, compileChildren: function(environment, options) { - var children = environment.children, child, compiler; + let children = environment.children, child, compiler; - for(var i=0, l=children.length; i 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; + let inlineStack = this.inlineStack; this.inlineStack = []; - for (var i = 0, len = inlineStack.length; i < len; i++) { - var entry = inlineStack[i]; + for (let i = 0, len = inlineStack.length; i < len; i++) { + let entry = inlineStack[i]; /* istanbul ignore if */ if (entry instanceof Literal) { this.compileStack.push(entry); } else { - var stack = this.incrStack(); + let stack = this.incrStack(); this.pushSource([stack, ' = ', entry, ';']); this.compileStack.push(stack); } @@ -875,7 +875,7 @@ JavaScriptCompiler.prototype = { }, popStack: function(wrapped) { - var inline = this.isInline(), + let inline = this.isInline(), item = (inline ? this.inlineStack : this.compileStack).pop(); if (!wrapped && (item instanceof Literal)) { @@ -893,7 +893,7 @@ JavaScriptCompiler.prototype = { }, topStack: function() { - var stack = (this.isInline() ? this.inlineStack : this.compileStack), + let stack = (this.isInline() ? this.inlineStack : this.compileStack), item = stack[stack.length - 1]; /* istanbul ignore if */ @@ -921,7 +921,7 @@ JavaScriptCompiler.prototype = { }, aliasable: function(name) { - var ret = this.aliases[name]; + let ret = this.aliases[name]; if (ret) { ret.referenceCount++; return ret; @@ -935,9 +935,9 @@ JavaScriptCompiler.prototype = { }, setupHelper: function(paramSize, name, blockHelper) { - var params = [], + let params = [], paramsInit = this.setupHelperArgs(name, paramSize, params, blockHelper); - var foundHelper = this.nameLookup('helpers', name, 'helper'); + let foundHelper = this.nameLookup('helpers', name, 'helper'); return { params: params, @@ -948,7 +948,7 @@ JavaScriptCompiler.prototype = { }, setupParams: function(helper, paramSize, params) { - var options = {}, contexts = [], types = [], ids = [], param; + let options = {}, contexts = [], types = [], ids = [], param; options.name = this.quotedString(helper); options.hash = this.popStack(); @@ -961,7 +961,7 @@ JavaScriptCompiler.prototype = { options.hashContexts = this.popStack(); } - var inverse = this.popStack(), + let inverse = this.popStack(), program = this.popStack(); // Avoid setting fn and inverse if neither are set. This allows @@ -973,7 +973,7 @@ JavaScriptCompiler.prototype = { // The parameters go on to the stack in order (making sure that they are evaluated in order) // so we need to pop them off the stack in reverse order - var i = paramSize; + let i = paramSize; while (i--) { param = this.popStack(); params[i] = param; @@ -1005,7 +1005,7 @@ JavaScriptCompiler.prototype = { }, setupHelperArgs: function(helper, paramSize, params, useRegister) { - var options = this.setupParams(helper, paramSize, params, true); + let options = this.setupParams(helper, paramSize, params, true); options = this.objectLiteral(options); if (useRegister) { this.useRegister('options'); @@ -1019,39 +1019,40 @@ 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": ">", - '"': """, - "'": "'", - "`": "`" +const escape = { + '&': '&', + '<': '<', + '>': '>', + '"': '"', + "'": ''', + '`': '`' }; -var badChars = /[&<>"'`]/g; -var possible = /[&<>"'`]/; +const badChars = /[&<>"'`]/g, + possible = /[&<>"'`]/; function escapeChar(chr) { return escape[chr]; } export function extend(obj /* , ...source */) { - for (var i = 1; i < arguments.length; i++) { - for (var key in arguments[i]) { + for (let i = 1; i < arguments.length; i++) { + for (let key in arguments[i]) { if (Object.prototype.hasOwnProperty.call(arguments[i], key)) { obj[key] = arguments[i][key]; } @@ -27,10 +27,11 @@ export function extend(obj /* , ...source */) { return obj; } -export var toString = Object.prototype.toString; +export let toString = Object.prototype.toString; // Sourced from lodash // https://github.com/bestiejs/lodash/blob/master/LICENSE.txt +/*eslint-disable func-style, no-var */ var isFunction = function(value) { return typeof value === 'function'; }; @@ -42,15 +43,16 @@ if (isFunction(/x/)) { }; } export var isFunction; +/*eslint-enable func-style, no-var */ /* istanbul ignore next */ -export var isArray = Array.isArray || function(value) { +export const isArray = Array.isArray || function(value) { return (value && typeof value === 'object') ? toString.call(value) === '[object Array]' : false; }; // Older IE versions do not directly support indexOf so we must implement our own, sadly. export function indexOf(array, value) { - for (var i = 0, len = array.length; i < len; i++) { + for (let i = 0, len = array.length; i < len; i++) { if (array[i] === value) { return i; } diff --git a/lib/index.js b/lib/index.js index 790aab73a..0383c02f7 100644 --- a/lib/index.js +++ b/lib/index.js @@ -1,11 +1,10 @@ // USAGE: // var handlebars = require('handlebars'); +/* eslint-disable no-var */ // var local = handlebars.create(); -var handlebars = require('../dist/cjs/handlebars')["default"]; - -handlebars.Visitor = require('../dist/cjs/handlebars/compiler/visitor')["default"]; +var handlebars = require('../dist/cjs/handlebars')['default']; var printer = require('../dist/cjs/handlebars/compiler/printer'); handlebars.PrintVisitor = printer.PrintVisitor; @@ -14,13 +13,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 f67347984..48cfebd1a 100644 --- a/lib/precompiler.js +++ b/lib/precompiler.js @@ -1,11 +1,9 @@ - -var fs = require('fs'), - Handlebars = require('./index'), - basename = require('path').basename, - SourceMap = require('source-map'), - SourceMapConsumer = SourceMap.SourceMapConsumer, - SourceNode = SourceMap.SourceNode, - uglify = require('uglify-js'); +/*eslint-disable no-console */ +import fs from 'fs'; +import * as Handlebars from './handlebars'; +import {basename} from 'path'; +import {SourceMapConsumer, SourceNode} from 'source-map'; +import uglify from 'uglify-js'; module.exports.cli = function(opts) { if (opts.version) { @@ -21,7 +19,7 @@ module.exports.cli = function(opts) { try { fs.statSync(template); } catch (err) { - throw new Handlebars.Exception('Unable to open template file "' + template + '"'); + throw new Handlebars.Exception(`Unable to open template file "${template}"`); } }); @@ -33,21 +31,21 @@ module.exports.cli = function(opts) { } // Convert the known list into a hash - var known = {}; + let known = {}; if (opts.known && !Array.isArray(opts.known)) { opts.known = [opts.known]; } if (opts.known) { - for (var i = 0, len = opts.known.length; i < len; i++) { + for (let i = 0, len = opts.known.length; i < len; i++) { known[opts.known[i]] = true; } } // Build file extension pattern - var extension = opts.extension.replace(/[\\^$*+?.():=!|{}\-\[\]]/g, function(arg) { return '\\' + arg; }); + let extension = opts.extension.replace(/[\\^$*+?.():=!|{}\-\[\]]/g, function(arg) { return '\\' + arg; }); extension = new RegExp('\\.' + extension + '$'); - var output = new SourceNode(); + let output = new SourceNode(); if (!opts.simple) { if (opts.amd) { output.add('define([\'' + opts.handlebarPath + 'handlebars.runtime\'], function(Handlebars) {\n Handlebars = Handlebars["default"];'); @@ -66,24 +64,24 @@ module.exports.cli = function(opts) { output.add('{};\n'); } function processTemplate(template, root) { - var path = template, + let path = template, stat = fs.statSync(path); if (stat.isDirectory()) { fs.readdirSync(template).map(function(file) { - var path = template + '/' + file; + let 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 { - var data = fs.readFileSync(path, 'utf8'); + let data = fs.readFileSync(path, 'utf8'); if (opts.bom && data.indexOf('\uFEFF') === 0) { data = data.substring(1); } - var options = { + let options = { knownHelpers: known, knownHelpersOnly: opts.o }; @@ -99,27 +97,27 @@ 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, ''); - var precompiled = Handlebars.precompile(data, options); + let precompiled = Handlebars.precompile(data, options); // If we are generating a source map, we have to reconstruct the SourceNode object if (opts.map) { - var consumer = new SourceMapConsumer(precompiled.map); + let consumer = new SourceMapConsumer(precompiled.map); precompiled = SourceNode.fromStringWithSourceMap(precompiled.code, consumer); } 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 +132,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 f653a3f89..bc4be6894 100644 --- a/package.json +++ b/package.json @@ -1,7 +1,7 @@ { "name": "handlebars", "barename": "handlebars", - "version": "3.0.1", + "version": "3.0.2", "description": "Handlebars provides the power necessary to let you build semantic templates effectively with no frustration", "homepage": "http://www.handlebarsjs.com/", "keywords": [ @@ -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/release-notes.md b/release-notes.md index 1d6787eee..b41226161 100644 --- a/release-notes.md +++ b/release-notes.md @@ -2,7 +2,18 @@ ## Development -[Commits](https://github.com/wycats/handlebars.js/compare/v3.0.1...master) +[Commits](https://github.com/wycats/handlebars.js/compare/v3.0.2...master) + +## v3.0.2 - April 20th, 2015 +- [#998](https://github.com/wycats/handlebars.js/pull/998) - Add full support for es6 ([@kpdecker](https://api.github.com/users/kpdecker)) +- [#994](https://github.com/wycats/handlebars.js/issues/994) - Access Handlebars.Visitor in browser ([@tamlyn](https://api.github.com/users/tamlyn)) +- [#990](https://github.com/wycats/handlebars.js/issues/990) - Allow passing null/undefined literals subexpressions ([@blimmer](https://api.github.com/users/blimmer)) +- [#989](https://github.com/wycats/handlebars.js/issues/989) - Source-map error with requirejs ([@SteppeEagle](https://api.github.com/users/SteppeEagle)) +- [#967](https://github.com/wycats/handlebars.js/issues/967) - can't access "this" property ([@75lb](https://api.github.com/users/75lb)) +- Use captureStackTrace for error handler - a009a97 +- Ignore branches tested without coverage monitoring - 37a664b + +[Commits](https://github.com/wycats/handlebars.js/compare/v3.0.1...v3.0.2) ## v3.0.1 - March 24th, 2015 - [#984](https://github.com/wycats/handlebars.js/pull/984) - Adding documentation for passing arguments into partials ([@johneke](https://api.github.com/users/johneke)) diff --git a/spec/.eslintrc b/spec/.eslintrc new file mode 100644 index 000000000..21871d52f --- /dev/null +++ b/spec/.eslintrc @@ -0,0 +1,36 @@ +{ + "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-var": 0 + } +} \ No newline at end of file diff --git a/spec/amd-runtime.html b/spec/amd-runtime.html index 19bccdbf5..7cc64f190 100644 --- a/spec/amd-runtime.html +++ b/spec/amd-runtime.html @@ -28,11 +28,16 @@