From 88ee4757e77f97afb206132eddb64e688700eb37 Mon Sep 17 00:00:00 2001 From: Yehuda Katz Date: Mon, 1 Jul 2013 13:59:58 -0700 Subject: [PATCH] Initial work on ES6 modules --- Gruntfile.js | 51 ++++ configurations/browser.js | 6 + configurations/concat.js | 16 ++ configurations/connect.js | 8 + configurations/transpile.js | 25 ++ configurations/watch.js | 4 + lib/handlebars.js | 22 +- lib/handlebars/base.js | 246 +++++++++--------- lib/handlebars/compiler/ast.js | 39 ++- lib/handlebars/compiler/base.js | 25 +- lib/handlebars/compiler/compiler.js | 46 ++-- .../compiler/javascript-compiler.js | 24 +- lib/handlebars/runtime.js | 202 +++++++------- lib/handlebars/utils.js | 83 +++--- package.json | 54 ++-- 15 files changed, 452 insertions(+), 399 deletions(-) create mode 100644 Gruntfile.js create mode 100644 configurations/browser.js create mode 100644 configurations/concat.js create mode 100644 configurations/connect.js create mode 100644 configurations/transpile.js create mode 100644 configurations/watch.js diff --git a/Gruntfile.js b/Gruntfile.js new file mode 100644 index 000000000..56231b7c8 --- /dev/null +++ b/Gruntfile.js @@ -0,0 +1,51 @@ +function config(name) { + return require('./configurations/' + name); +} + +module.exports = function(grunt) { + + grunt.initConfig({ + pkg: grunt.file.readJSON('package.json'), + + clean: ["dist"], + watch: config('watch') , + concat: config('concat'), + browser: config('browser'), + connect: config('connect'), + transpile: config('transpile') + }); + + // By default, (i.e., if you invoke `grunt` without arguments), do + // a new build. + this.registerTask('default', ['build']); + + // Build a new version of the library + this.registerTask('build', "Builds a distributable version of the current project", [ + 'clean', + 'transpile:amd', + 'concat:library', + 'concat:browser', + 'browser:dist', + 'bytes']); + + this.registerTask('tests', "Builds the test package", [ + 'build', + 'concat:deps', + 'transpile:tests']); + + // Run a server. This is ideal for running the QUnit tests in the browser. + this.registerTask('server', [ + 'build', + 'tests', + 'connect', + 'watch']); + + // Load tasks from npm + grunt.loadNpmTasks('grunt-contrib-clean'); + grunt.loadNpmTasks('grunt-contrib-concat'); + grunt.loadNpmTasks('grunt-contrib-connect'); + grunt.loadNpmTasks('grunt-contrib-watch'); + grunt.loadNpmTasks('grunt-es6-module-transpiler'); + + grunt.task.loadTasks('tasks'); +}; diff --git a/configurations/browser.js b/configurations/browser.js new file mode 100644 index 000000000..e3d0dc3b2 --- /dev/null +++ b/configurations/browser.js @@ -0,0 +1,6 @@ +module.exports = { + dist: { + src: 'tmp/<%= pkg.barename %>.browser1.js', + dest: 'dist/<%= pkg.name %>-<%= pkg.version %>.js' + } +}; diff --git a/configurations/concat.js b/configurations/concat.js new file mode 100644 index 000000000..4111eee6b --- /dev/null +++ b/configurations/concat.js @@ -0,0 +1,16 @@ +module.exports = { + library: { + src: ['tmp/<%= pkg.barename %>.amd.js'], + dest: 'dist/<%= pkg.name %>-<%= pkg.version %>.amd.js' + }, + + deps: { + src: ['vendor/deps/*.js'], + dest: 'tmp/deps.amd.js' + }, + + browser: { + src: ['vendor/loader.js', 'tmp/<%= pkg.barename %>.amd.js'], + dest: 'tmp/<%= pkg.barename %>.browser1.js' + } +}; diff --git a/configurations/connect.js b/configurations/connect.js new file mode 100644 index 000000000..dacc7600b --- /dev/null +++ b/configurations/connect.js @@ -0,0 +1,8 @@ +module.exports = { + server: {}, + options: { + hostname: '0.0.0.0', + port: 8000, + base: '.' + } +}; diff --git a/configurations/transpile.js b/configurations/transpile.js new file mode 100644 index 000000000..e912ecfb4 --- /dev/null +++ b/configurations/transpile.js @@ -0,0 +1,25 @@ +module.exports = { + amd: { + type: 'amd', + src: ["lib/<%= pkg.barename %>.js", "lib/*/**/*.js"], + dest: "tmp/<%= pkg.barename %>.amd.js" + }, + + cjs: { + type: 'cjs', + src: ["lib/<%= pkg.barename %>.js", "lib/*/**/*.js"], + dest: "tmp/<%= pkg.barename %>.cjs.js" + }, + + globals: { + type: 'globals', + src: ["lib/<%= pkg.barename %>.js", "lib/*/**/*.js"], + dest: "tmp/<%= pkg.barename %>.globals.js" + }, + + tests: { + type: 'amd', + src: ['test/test_helpers.js', 'test/tests.js', 'test/tests/**/*_test.js'], + dest: 'tmp/tests.amd.js' + } +}; diff --git a/configurations/watch.js b/configurations/watch.js new file mode 100644 index 000000000..49b1c49bd --- /dev/null +++ b/configurations/watch.js @@ -0,0 +1,4 @@ +module.exports = { + files: ['lib/**', 'vendor/*', 'test/**/*'], + tasks: ['build', 'tests'] +}; diff --git a/lib/handlebars.js b/lib/handlebars.js index f82ec3bad..e051aa5c0 100644 --- a/lib/handlebars.js +++ b/lib/handlebars.js @@ -1,15 +1,19 @@ -var handlebars = require("./handlebars/base"), +import handlebars 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) - utils = require("./handlebars/utils"), - compiler = require("./handlebars/compiler"), - runtime = require("./handlebars/runtime"); +import { SafeString, Exception, extend, escapeExpression, isEmpty } from "handlebars/utils"; +import compiler from "handlebars/compiler"; +import runtime from "handlebars/runtime"; +// For compatibility and usage outside of module systems, make the Handlebars object a namespace var create = function() { var hb = handlebars.create(); - utils.attach(hb); + hb.SafeString = SafeString; + hb.Exception = Exception; + hb.utils = { extend: extend, escapeExpression: escapeExpression, isEmpty: isEmpty }; + compiler.attach(hb); runtime.attach(hb); @@ -19,10 +23,10 @@ var create = function() { var Handlebars = create(); Handlebars.create = create; -module.exports = Handlebars; // instantiate an instance +export default Handlebars; // Publish a Node.js require() handler for .handlebars and .hbs files -if (require.extensions) { +if (typeof require !== 'undefined' && require.extensions) { var extension = function(module, filename) { var fs = require("fs"); var templateString = fs.readFileSync(filename, "utf8"); @@ -32,10 +36,6 @@ if (require.extensions) { require.extensions[".hbs"] = extension; } -// BEGIN(BROWSER) - -// END(BROWSER) - // USAGE: // var handlebars = require('handlebars'); diff --git a/lib/handlebars/base.js b/lib/handlebars/base.js index 44a369c5e..98496786d 100644 --- a/lib/handlebars/base.js +++ b/lib/handlebars/base.js @@ -1,166 +1,168 @@ /*jshint eqnull: true */ -module.exports.create = function() { +import { Exception, extend } from "handlebars/utils"; -var Handlebars = {}; +var K = function() { return this; }; -// BEGIN(BROWSER) +export VERSION = "1.0.0"; +export COMPILER_REVISION = 4; -Handlebars.VERSION = "1.0.0"; -Handlebars.COMPILER_REVISION = 4; - -Handlebars.REVISION_CHANGES = { +export 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', 4: '>= 1.0.0' }; -Handlebars.helpers = {}; -Handlebars.partials = {}; +// TODO: Make this a class +export default function(helpers, partials) { -var toString = Object.prototype.toString, - functionType = '[object Function]', - objectType = '[object Object]'; + var exports = {}; -Handlebars.registerHelper = function(name, fn, inverse) { - if (toString.call(name) === objectType) { - if (inverse || fn) { throw new Handlebars.Exception('Arg not supported with multiple helpers'); } - Handlebars.Utils.extend(this.helpers, name); - } else { - if (inverse) { fn.not = inverse; } - this.helpers[name] = fn; - } -}; -Handlebars.registerPartial = function(name, str) { - if (toString.call(name) === objectType) { - Handlebars.Utils.extend(this.partials, name); - } else { - this.partials[name] = str; - } -}; - -Handlebars.registerHelper('helperMissing', function(arg) { - if(arguments.length === 2) { - return undefined; - } else { - throw new Error("Missing helper: '" + arg + "'"); - } -}); + helpers = helpers || {}; + partials = partials || {}; -Handlebars.registerHelper('blockHelperMissing', function(context, options) { - var inverse = options.inverse || function() {}, fn = options.fn; + var toString = Object.prototype.toString, + functionType = '[object Function]', + objectType = '[object Object]'; - var type = toString.call(context); + exports.registerHelper(name, fn, inverse) { + if (toString.call(name) === objectType) { + if (inverse || fn) { throw new Exception('Arg not supported with multiple helpers'); } + extend(helpers, name); + } else { + if (inverse) { fn.not = inverse; } + helpers[name] = fn; + } + }; - if(type === functionType) { context = context.call(this); } + exports.registerPartial(name, str) { + if (toString.call(name) === objectType) { + extend(partials, name); + } else { + partials[name] = str; + } + }; - if(context === true) { - return fn(this); - } else if(context === false || context == null) { - return inverse(this); - } else if(type === "[object Array]") { - if(context.length > 0) { - return Handlebars.helpers.each(context, options); + exports.registerHelper('helperMissing', function(arg) { + if(arguments.length === 2) { + return undefined; } else { - return inverse(this); + throw new Error("Missing helper: '" + arg + "'"); } - } else { - return fn(context); - } -}); + }); -Handlebars.K = function() {}; + exports.registerHelper('blockHelperMissing', function(context, options) { + var inverse = options.inverse || function() {}, fn = options.fn; -Handlebars.createFrame = Object.create || function(object) { - Handlebars.K.prototype = object; - var obj = new Handlebars.K(); - Handlebars.K.prototype = null; - return obj; -}; - -Handlebars.logger = { - DEBUG: 0, INFO: 1, WARN: 2, ERROR: 3, level: 3, + var type = toString.call(context); - methodMap: {0: 'debug', 1: 'info', 2: 'warn', 3: 'error'}, + if(type === functionType) { context = context.call(this); } - // can be overridden in the host environment - log: function(level, obj) { - if (Handlebars.logger.level <= level) { - var method = Handlebars.logger.methodMap[level]; - if (typeof console !== 'undefined' && console[method]) { - console[method].call(console, obj); + if(context === true) { + return fn(this); + } else if(context === false || context == null) { + return inverse(this); + } else if(type === "[object Array]") { + if(context.length > 0) { + return Handlebars.helpers.each(context, options); + } else { + return inverse(this); } + } else { + return fn(context); } - } -}; - -Handlebars.log = function(level, obj) { Handlebars.logger.log(level, obj); }; + }); -Handlebars.registerHelper('each', function(context, options) { - var fn = options.fn, inverse = options.inverse; - var i = 0, ret = "", data; + exports.registerHelper('each', function(context, options) { + var fn = options.fn, inverse = options.inverse; + var i = 0, ret = "", data; - var type = toString.call(context); - if(type === functionType) { context = context.call(this); } + var type = toString.call(context); + if(type === functionType) { context = context.call(this); } - if (options.data) { - data = Handlebars.createFrame(options.data); - } + if (options.data) { + data = Handlebars.createFrame(options.data); + } - if(context && typeof context === 'object') { - if(context instanceof Array){ - for(var j = context.length; i=0.4.7" - }, - "dependencies": { - "optimist": "~0.3", - "uglify-js": "~2.3" + "url": "https://github.com/wycats/handlebars.js.git" }, + "author": "Yehuda Katz", + "license": "BSD", + "readmeFilename": "README.md", "devDependencies": { - "benchmark": "~1.0", - "dust": "~0.3", - "jison": "~0.3", - "mocha": "*", - "mustache": "~0.7.2", - "should": "~1.2.2" - }, - "main": "lib/handlebars.js", - "bin": { - "handlebars": "bin/handlebars" - }, - "scripts": { - "test": "node ./spec/env/runner" - }, - "optionalDependencies": {} + "grunt": "~0.4.1", + "connect": "~2.7.4", + "grunt-contrib-concat": "~0.3.0", + "grunt-contrib-clean": "~0.4.1", + "grunt-contrib-connect": "~0.3.0", + "grunt-contrib-watch": "~0.4.4", + "grunt-hang": "~0.1.2", + "grunt-es6-module-transpiler": "~0.3.0" + } }