Merge branch 'master' into es6-modules
Conflicts: Gruntfile.js Rakefile dist/handlebars.js dist/handlebars.runtime.js lib/handlebars.js lib/handlebars/base.js lib/handlebars/runtime.js lib/handlebars/utils.js package.json
This commit is contained in:
@@ -29,7 +29,6 @@
|
||||
],
|
||||
|
||||
"node" : true,
|
||||
"es5" : true,
|
||||
"browser" : true,
|
||||
|
||||
"boss" : true,
|
||||
|
||||
@@ -12,4 +12,5 @@ Rakefile
|
||||
bench/*
|
||||
spec/*
|
||||
src/*
|
||||
tasks/*
|
||||
vendor/*
|
||||
|
||||
+11
-2
@@ -1,5 +1,14 @@
|
||||
---
|
||||
after_success: bundle exec rake publish
|
||||
language: node_js
|
||||
node_js:
|
||||
- "0.8"
|
||||
- "0.10"
|
||||
|
||||
before_script:
|
||||
- npm install -g grunt-cli
|
||||
|
||||
script:
|
||||
- grunt build metrics publish:latest
|
||||
|
||||
email:
|
||||
on_failure: change
|
||||
on_success: never
|
||||
|
||||
@@ -1,7 +0,0 @@
|
||||
source "http://rubygems.org"
|
||||
|
||||
gem "rake"
|
||||
gem "json"
|
||||
gem "nokogiri"
|
||||
gem "aws-sdk"
|
||||
gem "uuidtools"
|
||||
@@ -1,21 +0,0 @@
|
||||
GEM
|
||||
remote: http://rubygems.org/
|
||||
specs:
|
||||
aws-sdk (1.10.0)
|
||||
json (~> 1.4)
|
||||
nokogiri (>= 1.4.4)
|
||||
uuidtools (~> 2.1)
|
||||
json (1.8.0)
|
||||
nokogiri (1.5.9)
|
||||
rake (10.0.3)
|
||||
uuidtools (2.1.4)
|
||||
|
||||
PLATFORMS
|
||||
ruby
|
||||
|
||||
DEPENDENCIES
|
||||
aws-sdk
|
||||
json
|
||||
nokogiri
|
||||
rake
|
||||
uuidtools
|
||||
+47
-1
@@ -1,3 +1,5 @@
|
||||
var childProcess = require('child_process');
|
||||
|
||||
function config(name) {
|
||||
return require('./configurations/' + name);
|
||||
}
|
||||
@@ -7,11 +9,37 @@ module.exports = function(grunt) {
|
||||
grunt.initConfig({
|
||||
pkg: grunt.file.readJSON('package.json'),
|
||||
|
||||
jshint: {
|
||||
options: {
|
||||
jshintrc: '.jshintrc',
|
||||
force: true
|
||||
},
|
||||
files: [
|
||||
'lib/**/!(parser|browser-prefix|browser-suffix).js'
|
||||
]
|
||||
},
|
||||
|
||||
clean: ["dist"],
|
||||
watch: config('watch') ,
|
||||
concat: config('concat'),
|
||||
connect: config('connect'),
|
||||
transpile: config('transpile')
|
||||
transpile: config('transpile'),
|
||||
|
||||
uglify: {
|
||||
options: {
|
||||
mangle: true,
|
||||
compress: true,
|
||||
preserveComments: 'some'
|
||||
},
|
||||
dist: {
|
||||
src: 'dist/<%= pkg.name %>.js',
|
||||
dest: 'dist/<%= pkg.name %>.min.js'
|
||||
},
|
||||
runtime: {
|
||||
src: 'dist/<%= pkg.name %>.runtime.js',
|
||||
dest: 'dist/<%= pkg.name %>.runtime.min.js'
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
// By default, (i.e., if you invoke `grunt` without arguments), do
|
||||
@@ -40,8 +68,26 @@ module.exports = function(grunt) {
|
||||
grunt.loadNpmTasks('grunt-contrib-clean');
|
||||
grunt.loadNpmTasks('grunt-contrib-concat');
|
||||
grunt.loadNpmTasks('grunt-contrib-connect');
|
||||
grunt.loadNpmTasks('grunt-contrib-jshint');
|
||||
grunt.loadNpmTasks('grunt-contrib-uglify');
|
||||
grunt.loadNpmTasks('grunt-contrib-watch');
|
||||
grunt.loadNpmTasks('grunt-es6-module-transpiler');
|
||||
|
||||
grunt.task.loadTasks('tasks');
|
||||
|
||||
grunt.registerTask('test', function() {
|
||||
var done = this.async();
|
||||
|
||||
var runner = childProcess.fork('./spec/env/runner', [], {stdio: 'inherit'});
|
||||
runner.on('close', function(code) {
|
||||
if (code != 0) {
|
||||
grunt.fatal(code + ' tests failed');
|
||||
}
|
||||
done();
|
||||
});
|
||||
});
|
||||
grunt.registerTask('bench', ['metrics']);
|
||||
|
||||
grunt.registerTask('build', ['jshint', 'parser', 'clean', 'concat', 'uglify', 'test']);
|
||||
grunt.registerTask('default', 'build');
|
||||
};
|
||||
|
||||
+9
-9
@@ -307,6 +307,8 @@ normal.
|
||||
helpers for size and speed.
|
||||
- When all helpers are known in advance the `--knownOnly` argument may be used
|
||||
to optimize all block helper references.
|
||||
- Implementations that do not use `@data` variables can improve performance of
|
||||
iteration centric templates by specifying `{data: false}` in the compiler options.
|
||||
|
||||
Supported Environments
|
||||
----------------------
|
||||
@@ -340,8 +342,7 @@ and we will have some benchmarks in the near future.
|
||||
Building
|
||||
--------
|
||||
|
||||
To build handlebars, just run `rake build`, and you will get two files
|
||||
in the `dist` directory.
|
||||
To build handlebars, just run `grunt build`, and the build will output to the `dist` directory.
|
||||
|
||||
|
||||
Upgrading
|
||||
@@ -379,6 +380,7 @@ Handlebars in the Wild
|
||||
* [SproutCore](http://www.sproutcore.com) uses Handlebars.js as its main
|
||||
templating engine, extending it with automatic data binding support.
|
||||
* [YUI](http://yuilibrary.com/yui/docs/handlebars/) implements a port of handlebars
|
||||
* [Swag](https://github.com/elving/swag) by [@elving](https://github.com/elving) is a growing collection of helpers for handlebars.js. Give your handlebars.js templates some swag son!
|
||||
|
||||
External Resources
|
||||
------------------
|
||||
@@ -393,16 +395,14 @@ Helping Out
|
||||
To build Handlebars.js you'll need a few things installed.
|
||||
|
||||
* Node.js
|
||||
* Ruby
|
||||
* Rake
|
||||
* [Grunt](http://gruntjs.com/getting-started)
|
||||
|
||||
There's a Gemfile in the repo, so you can run `bundle` to install rake
|
||||
if you've got bundler installed.
|
||||
Project dependencies may be installed via `npm install`.
|
||||
|
||||
To build Handlebars.js from scratch, you'll want to run `rake build`
|
||||
To build Handlebars.js from scratch, you'll want to run `grunt`
|
||||
in the root of the project. That will build Handlebars and output the
|
||||
results to the dist/ folder. To run tests, run `rake spec` or `npm test`.
|
||||
You can also run our set of benchmarks with `rake bench`.
|
||||
results to the dist/ folder. To re-run tests, run `grunt test` or `npm test`.
|
||||
You can also run our set of benchmarks with `grunt bench`.
|
||||
|
||||
If you notice any problems, please report them to the GitHub issue tracker at
|
||||
[http://github.com/wycats/handlebars.js/issues](http://github.com/wycats/handlebars.js/issues).
|
||||
|
||||
@@ -1,196 +0,0 @@
|
||||
require "rubygems"
|
||||
require "bundler/setup"
|
||||
|
||||
def compile_parser
|
||||
system "./node_modules/.bin/jison -m js src/handlebars.yy src/handlebars.l"
|
||||
if $?.success?
|
||||
File.open("lib/handlebars/compiler/parser.js", "w") do |file|
|
||||
file.puts File.read("handlebars.js")
|
||||
end
|
||||
|
||||
sh "rm handlebars.js"
|
||||
else
|
||||
fail "Failed to run Jison."
|
||||
end
|
||||
end
|
||||
|
||||
file "lib/handlebars/compiler/parser.js" => ["src/handlebars.yy","src/handlebars.l"] do
|
||||
if File.exists?('./node_modules/jison')
|
||||
compile_parser
|
||||
else
|
||||
puts "Jison is not installed. Trying `npm install jison`."
|
||||
sh "npm install"
|
||||
compile_parser
|
||||
end
|
||||
end
|
||||
|
||||
task :compile => "lib/handlebars/compiler/parser.js"
|
||||
|
||||
desc "run the spec suite"
|
||||
task :spec => [:build] do
|
||||
rc = system "npm test"
|
||||
fail "npm test failed with exit code #{$?.exitstatus}" if (rc.nil? || ! rc || $?.exitstatus != 0)
|
||||
end
|
||||
|
||||
task :default => [:compile, :spec]
|
||||
|
||||
def remove_exports(string)
|
||||
match = string.match(%r{^// BEGIN\(BROWSER\)\n(.*)\n^// END\(BROWSER\)}m)
|
||||
match ? match[1] : string
|
||||
end
|
||||
|
||||
minimal_deps = %w(base compiler/parser compiler/base compiler/ast utils compiler/compiler compiler/javascript-compiler runtime).map do |file|
|
||||
"lib/handlebars/#{file}.js"
|
||||
end
|
||||
|
||||
runtime_deps = %w(base utils runtime).map do |file|
|
||||
"lib/handlebars/#{file}.js"
|
||||
end
|
||||
|
||||
directory "dist"
|
||||
|
||||
minimal_deps.unshift "dist"
|
||||
|
||||
def build_for_task(task)
|
||||
FileUtils.rm_rf("dist/*") if File.directory?("dist")
|
||||
FileUtils.mkdir_p("dist")
|
||||
|
||||
contents = ["/*\n\n" + File.read('LICENSE') + "\n@license\n*/\n"]
|
||||
task.prerequisites.each do |filename|
|
||||
next if filename == "dist"
|
||||
|
||||
contents << "// #{filename}\n" + remove_exports(File.read(filename)) + ";"
|
||||
end
|
||||
|
||||
File.open(task.name, "w") do |file|
|
||||
file.puts contents.join("\n")
|
||||
end
|
||||
end
|
||||
|
||||
file "dist/handlebars.js" => minimal_deps do |task|
|
||||
build_for_task(task)
|
||||
end
|
||||
|
||||
file "dist/handlebars.runtime.js" => runtime_deps do |task|
|
||||
build_for_task(task)
|
||||
end
|
||||
|
||||
task :build => [:compile] do |task|
|
||||
Rake::Task["dist/handlebars.js"].execute
|
||||
Rake::Task["dist/handlebars.runtime.js"].execute
|
||||
|
||||
system "./node_modules/.bin/uglifyjs -m -c --comments -o dist/handlebars.min.js dist/handlebars.js"
|
||||
system "./node_modules/.bin/uglifyjs -m -c --comments -o dist/handlebars.runtime.min.js dist/handlebars.runtime.js"
|
||||
end
|
||||
|
||||
# Updates the various version numbers.
|
||||
desc "Updates the current release version"
|
||||
task :version, [:version] => [] do |task, args|
|
||||
version = args.version
|
||||
fail "Must provide a version number" unless version
|
||||
|
||||
changed = %x{git diff-index --name-only HEAD --}
|
||||
fail "The repository must be clean" unless $?.success? && changed.empty?
|
||||
|
||||
puts "Updating to version #{version}"
|
||||
|
||||
content = File.read("lib/handlebars/base.js")
|
||||
File.open("lib/handlebars/base.js", "w") do | file|
|
||||
file.puts content.gsub(/Handlebars.VERSION = "(.*)";/, "Handlebars.VERSION = \"#{version}\";")
|
||||
end
|
||||
|
||||
content = File.read("bower.json")
|
||||
File.open("bower.json", "w") do |file|
|
||||
file.puts content.gsub(/"version":.*/, "\"version\": \"#{version}\",")
|
||||
end
|
||||
|
||||
content = File.read("handlebars.js.nuspec")
|
||||
File.open("handlebars.js.nuspec", "w") do |file|
|
||||
file.puts content.gsub(/<version>.*<\/version>/, "<version>#{version}</version>")
|
||||
end
|
||||
|
||||
Rake::Task[:build].invoke
|
||||
Rake::Task[:spec].invoke
|
||||
|
||||
# TODO : Make sure that all of these files are updated properly in git then run npm version
|
||||
end
|
||||
|
||||
|
||||
directory "vendor"
|
||||
|
||||
desc "benchmark against dust.js and mustache.js"
|
||||
task :bench => "vendor" do
|
||||
require "open-uri"
|
||||
|
||||
#if File.directory?("vendor/coffee")
|
||||
#system "cd vendor/coffee && git pull"
|
||||
#else
|
||||
#system "git clone git://github.com/jashkenas/coffee-script.git vendor/coffee"
|
||||
#end
|
||||
|
||||
#if File.directory?("vendor/eco")
|
||||
#system "cd vendor/eco && git pull && npm update"
|
||||
#else
|
||||
#system "git clone git://github.com/sstephenson/eco.git vendor/eco && cd vendor/eco && npm update"
|
||||
#end
|
||||
|
||||
system "node bench/handlebars.js"
|
||||
end
|
||||
|
||||
def dist_files(&block)
|
||||
map = {}
|
||||
|
||||
root = File.expand_path(File.dirname(__FILE__)) + '/dist/'
|
||||
|
||||
files = ['handlebars.js', 'handlebars.min.js', 'handlebars.runtime.js', 'handlebars.runtime.min.js'].map { |file| root + file }
|
||||
files = files.map do |file|
|
||||
basename = Pathname.new(file).basename.sub_ext('')
|
||||
map[file] = yield basename
|
||||
end
|
||||
map
|
||||
end
|
||||
|
||||
def publish_s3(files)
|
||||
access_key_id = ENV['S3_ACCESS_KEY_ID']
|
||||
secret_access_key = ENV['S3_SECRET_ACCESS_KEY']
|
||||
bucket_name = ENV['S3_BUCKET_NAME']
|
||||
|
||||
if files && access_key_id && secret_access_key && bucket_name
|
||||
require 'aws-sdk'
|
||||
s3 = AWS::S3.new(access_key_id: access_key_id,secret_access_key: secret_access_key)
|
||||
bucket = s3.buckets[bucket_name]
|
||||
files.each do |source, outputs|
|
||||
s3_objs = outputs.map do |file|
|
||||
bucket.objects[file]
|
||||
end
|
||||
s3_objs.each { |obj| obj.write(Pathname.new(source)) }
|
||||
end
|
||||
else
|
||||
puts "Not uploading any files to S3!"
|
||||
end
|
||||
end
|
||||
|
||||
task :publish do
|
||||
rev = `git rev-parse --short HEAD`.to_s.strip
|
||||
master_rev = `git rev-parse --short origin/master`.to_s.strip
|
||||
|
||||
if rev == master_rev
|
||||
files = dist_files do |basename|
|
||||
["#{basename}-latest.js", "#{basename}-#{rev}.js"]
|
||||
end
|
||||
end
|
||||
|
||||
publish_s3 files
|
||||
end
|
||||
|
||||
task :publish_version do
|
||||
tag = `git tag -l --points-at HEAD`.to_s.strip.split(/\n/)
|
||||
fail "The current commit must be tagged." if tag.empty?
|
||||
fail "Multiple tags, aborting: #{tag}" if tag.length > 1
|
||||
tag = tag.first
|
||||
|
||||
files = dist_files do |basename|
|
||||
["#{basename}-#{tag}.js"]
|
||||
end
|
||||
publish_s3 files
|
||||
end
|
||||
@@ -0,0 +1,29 @@
|
||||
var _ = require('underscore'),
|
||||
async = require('async'),
|
||||
fs = require('fs'),
|
||||
zlib = require('zlib');
|
||||
|
||||
module.exports = function(grunt, callback) {
|
||||
var distFiles = fs.readdirSync('dist'),
|
||||
distSizes = {};
|
||||
|
||||
async.each(distFiles, function(file, callback) {
|
||||
var content = fs.readFileSync('dist/' + file);
|
||||
|
||||
file = file.replace(/\.js/, '').replace(/\./g, '_');
|
||||
distSizes[file] = content.length;
|
||||
|
||||
zlib.gzip(content, function(err, data) {
|
||||
if (err) {
|
||||
throw err;
|
||||
}
|
||||
|
||||
distSizes[file + '_gz'] = data.length;
|
||||
callback();
|
||||
});
|
||||
},
|
||||
function() {
|
||||
grunt.log.writeln('Distribution sizes: ' + JSON.stringify(distSizes, undefined, 2));
|
||||
callback([distSizes]);
|
||||
});
|
||||
};
|
||||
@@ -1,172 +0,0 @@
|
||||
var BenchWarmer = require("./benchwarmer");
|
||||
Handlebars = require("../lib/handlebars");
|
||||
|
||||
var dust, Mustache, eco;
|
||||
|
||||
try {
|
||||
dust = require("dust");
|
||||
} catch (err) { /* NOP */ }
|
||||
|
||||
try {
|
||||
Mustache = require("mustache");
|
||||
} catch (err) { /* NOP */ }
|
||||
|
||||
try {
|
||||
var ecoExports = require("eco");
|
||||
eco = function(str) {
|
||||
return ecoExports(str);
|
||||
}
|
||||
} catch (err) { /* NOP */ }
|
||||
|
||||
var benchDetails = {
|
||||
string: {
|
||||
context: {},
|
||||
handlebars: "Hello world",
|
||||
dust: "Hello world",
|
||||
mustache: "Hello world",
|
||||
eco: "Hello world"
|
||||
},
|
||||
variables: {
|
||||
context: {name: "Mick", count: 30},
|
||||
handlebars: "Hello {{name}}! You have {{count}} new messages.",
|
||||
dust: "Hello {name}! You have {count} new messages.",
|
||||
mustache: "Hello {{name}}! You have {{count}} new messages.",
|
||||
eco: "Hello <%= @name %>! You have <%= @count %> new messages."
|
||||
},
|
||||
object: {
|
||||
context: { person: { name: "Larry", age: 45 } },
|
||||
handlebars: "{{#with person}}{{name}}{{age}}{{/with}}",
|
||||
dust: "{#person}{name}{age}{/person}",
|
||||
mustache: "{{#person}}{{name}}{{age}}{{/person}}"
|
||||
},
|
||||
array: {
|
||||
context: { names: [{name: "Moe"}, {name: "Larry"}, {name: "Curly"}, {name: "Shemp"}] },
|
||||
handlebars: "{{#each names}}{{name}}{{/each}}",
|
||||
dust: "{#names}{name}{/names}",
|
||||
mustache: "{{#names}}{{name}}{{/names}}",
|
||||
eco: "<% for item in @names: %><%= item.name %><% end %>"
|
||||
},
|
||||
partial: {
|
||||
context: { peeps: [{name: "Moe", count: 15}, {name: "Larry", count: 5}, {name: "Curly", count: 1}] },
|
||||
partials: {
|
||||
mustache: { variables: "Hello {{name}}! You have {{count}} new messages." },
|
||||
handlebars: { variables: "Hello {{name}}! You have {{count}} new messages." }
|
||||
},
|
||||
handlebars: "{{#each peeps}}{{>variables}}{{/each}}",
|
||||
dust: "{#peeps}{>variables/}{/peeps}",
|
||||
mustache: "{{#peeps}}{{>variables}}{{/peeps}}"
|
||||
},
|
||||
recursion: {
|
||||
context: { name: '1', kids: [{ name: '1.1', kids: [{name: '1.1.1', kids: []}] }] },
|
||||
partials: {
|
||||
mustache: { recursion: "{{name}}{{#kids}}{{>recursion}}{{/kids}}" },
|
||||
handlebars: { recursion: "{{name}}{{#each kids}}{{>recursion}}{{/each}}" }
|
||||
},
|
||||
handlebars: "{{name}}{{#each kids}}{{>recursion}}{{/each}}",
|
||||
dust: "{name}{#kids}{>recursion:./}{/kids}",
|
||||
mustache: "{{name}}{{#kids}}{{>recursion}}{{/kids}}"
|
||||
},
|
||||
complex: {
|
||||
handlebars: "<h1>{{header}}</h1>{{#if items}}<ul>{{#each items}}{{#if current}}" +
|
||||
"<li><strong>{{name}}</strong></li>{{^}}" +
|
||||
"<li><a href=\"{{url}}\">{{name}}</a></li>{{/if}}" +
|
||||
"{{/each}}</ul>{{^}}<p>The list is empty.</p>{{/if}}",
|
||||
|
||||
dust: "<h1>{header}</h1>\n" +
|
||||
"{?items}\n" +
|
||||
" <ul>\n" +
|
||||
" {#items}\n" +
|
||||
" {#current}\n" +
|
||||
" <li><strong>{name}</strong></li>\n" +
|
||||
" {:else}\n" +
|
||||
" <li><a href=\"{url}\">{name}</a></li>\n" +
|
||||
" {/current}\n" +
|
||||
" {/items}\n" +
|
||||
" </ul>\n" +
|
||||
"{:else}\n" +
|
||||
" <p>The list is empty.</p>\n" +
|
||||
"{/items}",
|
||||
context: {
|
||||
header: function() {
|
||||
return "Colors";
|
||||
},
|
||||
items: [
|
||||
{name: "red", current: true, url: "#Red"},
|
||||
{name: "green", current: false, url: "#Green"},
|
||||
{name: "blue", current: false, url: "#Blue"}
|
||||
]
|
||||
}
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
handlebarsTemplates = {};
|
||||
ecoTemplates = {};
|
||||
|
||||
var warmer = new BenchWarmer();
|
||||
|
||||
var makeSuite = function(name) {
|
||||
warmer.suite(name, function(bench) {
|
||||
var templateName = name;
|
||||
var details = benchDetails[templateName];
|
||||
var mustachePartials = details.partials && details.partials.mustache;
|
||||
var mustacheSource = details.mustache;
|
||||
var context = details.context;
|
||||
|
||||
var error = function() { throw new Error("EWOT"); };
|
||||
|
||||
if (dust) {
|
||||
bench("dust", function() {
|
||||
dust.render(templateName, context, function(err, out) { });
|
||||
});
|
||||
}
|
||||
|
||||
bench("handlebars", function() {
|
||||
handlebarsTemplates[templateName](context);
|
||||
});
|
||||
|
||||
if (eco) {
|
||||
if(ecoTemplates[templateName]) {
|
||||
bench("eco", function() {
|
||||
ecoTemplates[templateName](context);
|
||||
});
|
||||
} else {
|
||||
bench("eco", error);
|
||||
}
|
||||
}
|
||||
|
||||
if (Mustache && mustacheSource) {
|
||||
bench("mustache", function() {
|
||||
Mustache.to_html(mustacheSource, context, mustachePartials);
|
||||
});
|
||||
} else {
|
||||
bench("mustache", error);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
for(var name in benchDetails) {
|
||||
if(benchDetails.hasOwnProperty(name)) {
|
||||
if (dust) {
|
||||
dust.loadSource(dust.compile(benchDetails[name].dust, name));
|
||||
}
|
||||
handlebarsTemplates[name] = Handlebars.compile(benchDetails[name].handlebars);
|
||||
|
||||
if (eco && benchDetails[name].eco) {
|
||||
ecoTemplates[name] = eco(benchDetails[name].eco);
|
||||
}
|
||||
|
||||
var partials = benchDetails[name].partials;
|
||||
if(partials) {
|
||||
for(var partialName in partials.handlebars) {
|
||||
if(partials.handlebars.hasOwnProperty(partialName)) {
|
||||
Handlebars.registerPartial(partialName, partials.handlebars[partialName]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
makeSuite(name);
|
||||
}
|
||||
}
|
||||
|
||||
warmer.bench();
|
||||
@@ -0,0 +1,14 @@
|
||||
var fs = require('fs');
|
||||
|
||||
var metrics = fs.readdirSync(__dirname);
|
||||
metrics.forEach(function(metric) {
|
||||
if (metric === 'index.js' || !/(.*)\.js$/.test(metric)) {
|
||||
return;
|
||||
}
|
||||
|
||||
var name = RegExp.$1;
|
||||
metric = require('./' + name);
|
||||
if (metric instanceof Function) {
|
||||
module.exports[name] = metric;
|
||||
}
|
||||
});
|
||||
@@ -0,0 +1,19 @@
|
||||
var _ = require('underscore'),
|
||||
templates = require('./templates');
|
||||
|
||||
module.exports = function(grunt, callback) {
|
||||
// Deferring to here in case we have a build for parser, etc as part of this grunt exec
|
||||
var Handlebars = require('../lib/handlebars');
|
||||
|
||||
var templateSizes = {};
|
||||
_.each(templates, function(info, template) {
|
||||
var src = info.handlebars,
|
||||
compiled = Handlebars.precompile(src, {}),
|
||||
knownHelpers = Handlebars.precompile(src, {knownHelpersOnly: true, knownHelpers: info.helpers});
|
||||
|
||||
templateSizes[template] = compiled.length;
|
||||
templateSizes['knownOnly_' + template] = knownHelpers.length;
|
||||
});
|
||||
grunt.log.writeln('Precompiled sizes: ' + JSON.stringify(templateSizes, undefined, 2));
|
||||
callback([templateSizes]);
|
||||
};
|
||||
@@ -0,0 +1,12 @@
|
||||
module.exports = {
|
||||
helpers: {
|
||||
foo: function(options) {
|
||||
return '';
|
||||
}
|
||||
},
|
||||
context: {
|
||||
bar: true
|
||||
},
|
||||
|
||||
handlebars: '{{foo person "person" 1 true foo=bar foo="person" foo=1 foo=true}}'
|
||||
};
|
||||
@@ -0,0 +1,7 @@
|
||||
module.exports = {
|
||||
context: { names: [{name: "Moe"}, {name: "Larry"}, {name: "Curly"}, {name: "Shemp"}] },
|
||||
handlebars: "{{#each names}}{{name}}{{/each}}",
|
||||
dust: "{#names}{name}{/names}",
|
||||
mustache: "{{#names}}{{name}}{{/names}}",
|
||||
eco: "<% for item in @names: %><%= item.name %><% end %>"
|
||||
};
|
||||
@@ -0,0 +1,4 @@
|
||||
module.exports = {
|
||||
context: { names: [{name: "Moe"}, {name: "Larry"}, {name: "Curly"}, {name: "Shemp"}] },
|
||||
handlebars: "{{#names}}{{name}}{{/names}}"
|
||||
}
|
||||
@@ -0,0 +1,14 @@
|
||||
<h1>{header}</h1>
|
||||
{?items}
|
||||
<ul>
|
||||
{#items}
|
||||
{#current}
|
||||
<li><strong>{name}</strong></li>
|
||||
{:else}
|
||||
<li><a href="{url}">{name}</a></li>
|
||||
{/current}
|
||||
{/items}
|
||||
</ul>
|
||||
{:else}
|
||||
<p>The list is empty.</p>
|
||||
{/items}
|
||||
@@ -0,0 +1,14 @@
|
||||
<h1><%= @header() %></h1>
|
||||
<% if @items.length: %>
|
||||
<ul>
|
||||
<% for item in @items: %>
|
||||
<% if item.current: %>
|
||||
<li><strong><%= item.name %></strong></li>
|
||||
<% else: %>
|
||||
<li><a href="<%= item.url %>"><%= item.name %></a></li>
|
||||
<% end %>
|
||||
<% end %>
|
||||
</ul>
|
||||
<% else: %>
|
||||
<p>The list is empty.</p>
|
||||
<% end %>
|
||||
@@ -0,0 +1,14 @@
|
||||
<h1>{{header}}</h1>
|
||||
{{#if items}}
|
||||
<ul>
|
||||
{{#each items}}
|
||||
{{#if current}}
|
||||
<li><strong>{{name}}</strong></li>
|
||||
{{^}}
|
||||
<li><a href="{{url}}">{{name}}</a></li>
|
||||
{{/if}}
|
||||
{{/each}}
|
||||
</ul>
|
||||
{{^}}
|
||||
<p>The list is empty.</p>
|
||||
{{/if}}
|
||||
@@ -0,0 +1,20 @@
|
||||
var fs = require('fs');
|
||||
|
||||
module.exports = {
|
||||
context: {
|
||||
header: function() {
|
||||
return "Colors";
|
||||
},
|
||||
hasItems: true, // To make things fairer in mustache land due to no `{{if}}` construct on arrays
|
||||
items: [
|
||||
{name: "red", current: true, url: "#Red"},
|
||||
{name: "green", current: false, url: "#Green"},
|
||||
{name: "blue", current: false, url: "#Blue"}
|
||||
]
|
||||
},
|
||||
|
||||
handlebars: fs.readFileSync(__dirname + '/complex.handlebars').toString(),
|
||||
dust: fs.readFileSync(__dirname + '/complex.dust').toString(),
|
||||
eco: fs.readFileSync(__dirname + '/complex.eco').toString(),
|
||||
mustache: fs.readFileSync(__dirname + '/complex.mustache').toString()
|
||||
};
|
||||
@@ -0,0 +1,13 @@
|
||||
<h1>{{header}}</h1>
|
||||
{{#hasItems}}
|
||||
<ul>
|
||||
{{#items}}
|
||||
{{#current}}
|
||||
<li><strong>{{name}}</strong></li>
|
||||
{{/current}}
|
||||
{{^current}}
|
||||
<li><a href="{{url}}">{{name}}</a></li>
|
||||
{{/current}}
|
||||
{{/items}}
|
||||
</ul>
|
||||
{{/hasItems}}
|
||||
@@ -0,0 +1,4 @@
|
||||
module.exports = {
|
||||
context: { names: [{name: "Moe"}, {name: "Larry"}, {name: "Curly"}, {name: "Shemp"}] },
|
||||
handlebars: "{{#each names}}{{@index}}{{name}}{{/each}}"
|
||||
}
|
||||
@@ -0,0 +1,9 @@
|
||||
var fs = require('fs');
|
||||
|
||||
var templates = fs.readdirSync(__dirname);
|
||||
templates.forEach(function(template) {
|
||||
if (template === 'index.js' || !/(.*)\.js$/.test(template)) {
|
||||
return;
|
||||
}
|
||||
module.exports[RegExp.$1] = require('./' + RegExp.$1);
|
||||
});
|
||||
@@ -0,0 +1,4 @@
|
||||
module.exports = {
|
||||
context: { person: { name: "Larry", age: 45 } },
|
||||
handlebars: "{{#person}}{{name}}{{age}}{{/person}}"
|
||||
};
|
||||
@@ -0,0 +1,7 @@
|
||||
module.exports = {
|
||||
context: { person: { name: "Larry", age: 45 } },
|
||||
handlebars: "{{#with person}}{{name}}{{age}}{{/with}}",
|
||||
dust: "{#person}{name}{age}{/person}",
|
||||
eco: "<%= @person.name %><%= @person.age %>",
|
||||
mustache: "{{#person}}{{name}}{{age}}{{/person}}"
|
||||
};
|
||||
@@ -0,0 +1,10 @@
|
||||
module.exports = {
|
||||
context: { name: '1', kids: [{ name: '1.1', kids: [{name: '1.1.1', kids: []}] }] },
|
||||
partials: {
|
||||
mustache: { recursion: "{{name}}{{#kids}}{{>recursion}}{{/kids}}" },
|
||||
handlebars: { recursion: "{{name}}{{#each kids}}{{>recursion}}{{/each}}" }
|
||||
},
|
||||
handlebars: "{{name}}{{#each kids}}{{>recursion}}{{/each}}",
|
||||
dust: "{name}{#kids}{>recursion:./}{/kids}",
|
||||
mustache: "{{name}}{{#kids}}{{>recursion}}{{/kids}}"
|
||||
};
|
||||
@@ -0,0 +1,11 @@
|
||||
module.exports = {
|
||||
context: { peeps: [{name: "Moe", count: 15}, {name: "Larry", count: 5}, {name: "Curly", count: 1}] },
|
||||
partials: {
|
||||
mustache: { variables: "Hello {{name}}! You have {{count}} new messages." },
|
||||
handlebars: { variables: "Hello {{name}}! You have {{count}} new messages." }
|
||||
},
|
||||
|
||||
handlebars: "{{#each peeps}}{{>variables}}{{/each}}",
|
||||
dust: "{#peeps}{>variables/}{/peeps}",
|
||||
mustache: "{{#peeps}}{{>variables}}{{/peeps}}"
|
||||
};
|
||||
@@ -0,0 +1,7 @@
|
||||
module.exports = {
|
||||
context: { person: { name: "Larry", age: 45 } },
|
||||
handlebars: "{{person.name}}{{person.age}}{{person.foo}}{{animal.age}}",
|
||||
dust: "{person.name}{person.age}{person.foo}{animal.age}",
|
||||
eco: "<%= @person.name %><%= @person.age %><%= @person.foo %><% if @animal: %><%= @animal.age %><% end %>",
|
||||
mustache: "{{person.name}}{{person.age}}{{person.foo}}{{animal.age}}"
|
||||
};
|
||||
@@ -0,0 +1,7 @@
|
||||
module.exports = {
|
||||
context: {},
|
||||
handlebars: "Hello world",
|
||||
dust: "Hello world",
|
||||
mustache: "Hello world",
|
||||
eco: "Hello world"
|
||||
};
|
||||
@@ -0,0 +1,8 @@
|
||||
module.exports = {
|
||||
context: {name: "Mick", count: 30},
|
||||
handlebars: "Hello {{name}}! You have {{count}} new messages.",
|
||||
dust: "Hello {name}! You have {count} new messages.",
|
||||
mustache: "Hello {{name}}! You have {{count}} new messages.",
|
||||
eco: "Hello <%= @name %>! You have <%= @count %> new messages."
|
||||
};
|
||||
|
||||
@@ -0,0 +1,123 @@
|
||||
var _ = require('underscore'),
|
||||
runner = require('./util/template-runner'),
|
||||
templates = require('./templates'),
|
||||
|
||||
eco, dust, Handlebars, Mustache, eco;
|
||||
|
||||
try {
|
||||
dust = require("dustjs-linkedin");
|
||||
} catch (err) { /* NOP */ }
|
||||
|
||||
try {
|
||||
Mustache = require("mustache");
|
||||
} catch (err) { /* NOP */ }
|
||||
|
||||
try {
|
||||
eco = require("eco");
|
||||
} catch (err) { /* NOP */ }
|
||||
|
||||
function error() {
|
||||
throw new Error("EWOT");
|
||||
}
|
||||
|
||||
function makeSuite(bench, name, template, handlebarsOnly) {
|
||||
// Create aliases to minimize any impact from having to walk up the closure tree.
|
||||
var templateName = name,
|
||||
|
||||
context = template.context,
|
||||
partials = template.partials,
|
||||
|
||||
handlebarsOut,
|
||||
dustOut,
|
||||
ecoOut,
|
||||
mustacheOut;
|
||||
|
||||
var handlebar = Handlebars.compile(template.handlebars, {data: false}),
|
||||
options = {helpers: template.helpers};
|
||||
_.each(template.partials && template.partials.handlebars, function(partial, name) {
|
||||
Handlebars.registerPartial(name, Handlebars.compile(partial, {data: false}));
|
||||
});
|
||||
|
||||
handlebarsOut = handlebar(context, options);
|
||||
bench("handlebars", function() {
|
||||
handlebar(context, options);
|
||||
});
|
||||
|
||||
if (handlebarsOnly) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (dust) {
|
||||
if (template.dust) {
|
||||
dustOut = false;
|
||||
dust.loadSource(dust.compile(template.dust, templateName));
|
||||
|
||||
dust.render(templateName, context, function(err, out) { dustOut = out; });
|
||||
|
||||
bench("dust", function() {
|
||||
dust.render(templateName, context, function(err, out) { });
|
||||
});
|
||||
} else {
|
||||
bench('dust', error);
|
||||
}
|
||||
}
|
||||
|
||||
if (eco) {
|
||||
if (template.eco) {
|
||||
var ecoTemplate = eco.compile(template.eco);
|
||||
|
||||
ecoOut = ecoTemplate(context);
|
||||
|
||||
bench("eco", function() {
|
||||
ecoTemplate(context);
|
||||
});
|
||||
} else {
|
||||
bench("eco", error);
|
||||
}
|
||||
}
|
||||
|
||||
if (Mustache) {
|
||||
var mustacheSource = template.mustache,
|
||||
mustachePartials = partials && partials.mustache;
|
||||
|
||||
if (mustacheSource) {
|
||||
mustacheOut = Mustache.to_html(mustacheSource, context, mustachePartials);
|
||||
|
||||
bench("mustache", function() {
|
||||
Mustache.to_html(mustacheSource, context, mustachePartials);
|
||||
});
|
||||
} else {
|
||||
bench("mustache", error);
|
||||
}
|
||||
}
|
||||
|
||||
// Hack around whitespace until we have whitespace control
|
||||
handlebarsOut = handlebarsOut.replace(/\s/g, '');
|
||||
function compare(b, lang) {
|
||||
if (b == null) {
|
||||
return;
|
||||
}
|
||||
|
||||
b = b.replace(/\s/g, '');
|
||||
|
||||
if (handlebarsOut !== b) {
|
||||
throw new Error('Template output mismatch: ' + name
|
||||
+ '\n\nHandlebars: ' + handlebarsOut
|
||||
+ '\n\n' + lang + ': ' + b);
|
||||
}
|
||||
}
|
||||
|
||||
compare(dustOut, 'dust');
|
||||
compare(ecoOut, 'eco');
|
||||
compare(mustacheOut, 'mustache');
|
||||
}
|
||||
|
||||
module.exports = function(grunt, callback) {
|
||||
// Deferring load incase we are being run inline with the grunt build
|
||||
Handlebars = require('../lib/handlebars');
|
||||
|
||||
console.log('Execution Throughput');
|
||||
runner(grunt, makeSuite, function(times, scaled) {
|
||||
callback(scaled);
|
||||
});
|
||||
};
|
||||
@@ -1,10 +1,13 @@
|
||||
|
||||
var Benchmark = require("benchmark");
|
||||
var _ = require('underscore'),
|
||||
Benchmark = require("benchmark");
|
||||
|
||||
var BenchWarmer = function(names) {
|
||||
this.benchmarks = [];
|
||||
this.currentBenches = [];
|
||||
this.names = [];
|
||||
this.times = {};
|
||||
this.minimum = Infinity;
|
||||
this.maximum = -Infinity;
|
||||
this.errors = {};
|
||||
};
|
||||
|
||||
@@ -12,28 +15,11 @@ var print = require("sys").print;
|
||||
|
||||
BenchWarmer.prototype = {
|
||||
winners: function(benches) {
|
||||
var result = Benchmark.filter(benches, function(bench) { return bench.cycles; });
|
||||
|
||||
if (result.length > 1) {
|
||||
result.sort(function(a, b) { return b.compare(a); });
|
||||
first = result[0];
|
||||
last = result[result.length - 1];
|
||||
|
||||
var winners = [];
|
||||
|
||||
Benchmark.each(result, function(bench) {
|
||||
if (bench.compare(first) === 0) {
|
||||
winners.push(bench);
|
||||
}
|
||||
});
|
||||
|
||||
return winners;
|
||||
} else {
|
||||
return result;
|
||||
}
|
||||
return Benchmark.filter(benches, 'fastest');
|
||||
},
|
||||
suite: function(suite, fn) {
|
||||
this.suiteName = suite;
|
||||
this.times[suite] = {};
|
||||
this.first = true;
|
||||
|
||||
var self = this;
|
||||
@@ -50,9 +36,7 @@ BenchWarmer.prototype = {
|
||||
var first = this.first, suiteName = this.suiteName, self = this;
|
||||
this.first = false;
|
||||
|
||||
var bench = new Benchmark(function() {
|
||||
fn();
|
||||
}, {
|
||||
var bench = new Benchmark(fn, {
|
||||
name: this.suiteName + ": " + name,
|
||||
onComplete: function() {
|
||||
if(first) { self.startLine(suiteName); }
|
||||
@@ -62,11 +46,80 @@ BenchWarmer.prototype = {
|
||||
self.errors[this.name] = this;
|
||||
}
|
||||
});
|
||||
bench.suiteName = this.suiteName;
|
||||
bench.benchName = name;
|
||||
|
||||
this.benchmarks.push(bench);
|
||||
},
|
||||
bench: function() {
|
||||
var benchSize = 0, names = this.names, self = this, i, l;
|
||||
|
||||
bench: function(callback) {
|
||||
var self = this;
|
||||
|
||||
this.printHeader('ops/msec', true);
|
||||
|
||||
Benchmark.invoke(this.benchmarks, {
|
||||
name: "run",
|
||||
onComplete: function() {
|
||||
self.scaleTimes();
|
||||
|
||||
self.startLine('');
|
||||
|
||||
print('\n');
|
||||
self.printHeader('scaled');
|
||||
_.each(self.scaled, function(value, name) {
|
||||
self.startLine(name);
|
||||
|
||||
_.each(self.names, function(lang) {
|
||||
self.writeValue(value[lang] || '');
|
||||
});
|
||||
});
|
||||
print('\n');
|
||||
|
||||
var errors = false, prop, bench;
|
||||
for(prop in self.errors) {
|
||||
if (self.errors.hasOwnProperty(prop)
|
||||
&& self.errors[prop].error.message !== 'EWOT') {
|
||||
errors = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if(errors) {
|
||||
print("\n\nErrors:\n");
|
||||
for(prop in self.errors) {
|
||||
if (self.errors.hasOwnProperty(prop)
|
||||
&& self.errors[prop].error.message !== 'EWOT') {
|
||||
bench = self.errors[prop];
|
||||
print("\n" + bench.name + ":\n");
|
||||
print(bench.error.message);
|
||||
if(bench.error.stack) {
|
||||
print(bench.error.stack.join("\n"));
|
||||
}
|
||||
print("\n");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
callback();
|
||||
}
|
||||
});
|
||||
|
||||
print("\n");
|
||||
},
|
||||
|
||||
scaleTimes: function() {
|
||||
var scaled = this.scaled = {};
|
||||
_.each(this.times, function(times, name) {
|
||||
var output = scaled[name] = {};
|
||||
|
||||
_.each(times, function(time, lang) {
|
||||
output[lang] = ((time - this.minimum) / (this.maximum - this.minimum) * 100).toFixed(2);
|
||||
}, this);
|
||||
}, this);
|
||||
},
|
||||
|
||||
printHeader: function(title, winners) {
|
||||
var benchSize = 0, names = this.names, i, l;
|
||||
|
||||
for(i=0, l=names.length; i<l; i++) {
|
||||
var name = names[i];
|
||||
@@ -78,43 +131,21 @@ BenchWarmer.prototype = {
|
||||
this.benchSize = 20;
|
||||
var horSize = 0;
|
||||
|
||||
this.startLine("ops/msec");
|
||||
horSize = horSize + "ops/msec ".length;
|
||||
this.startLine(title);
|
||||
horSize = horSize + this.benchSize;
|
||||
for(i=0, l=names.length; i<l; i++) {
|
||||
print(names[i] + new Array(this.benchSize - names[i].length + 1).join(" "));
|
||||
this.writeValue(names[i]);
|
||||
horSize = horSize + this.benchSize;
|
||||
}
|
||||
|
||||
print("WINNER(S)");
|
||||
horSize = horSize + "WINNER(S)".length;
|
||||
if (winners) {
|
||||
print("WINNER(S)");
|
||||
horSize = horSize + "WINNER(S)".length;
|
||||
}
|
||||
|
||||
print("\n" + new Array(horSize + 1).join("-"));
|
||||
|
||||
Benchmark.invoke(this.benchmarks, {
|
||||
name: "run",
|
||||
onComplete: function() {
|
||||
var errors = false, prop, bench;
|
||||
for(prop in self.errors) { if(self.errors.hasOwnProperty(prop)) { errors = true; break; } }
|
||||
|
||||
if(errors) {
|
||||
print("\n\nErrors:\n");
|
||||
for(prop in self.errors) {
|
||||
if(self.errors.hasOwnProperty(prop)) {
|
||||
bench = self.errors[prop];
|
||||
print("\n" + bench.name + ":\n");
|
||||
print(bench.error.message);
|
||||
if(bench.error.stack) {
|
||||
print(bench.error.stack.join("\n"));
|
||||
}
|
||||
print("\n");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
print("\n");
|
||||
},
|
||||
|
||||
startLine: function(name) {
|
||||
var winners = Benchmark.map(this.winners(this.currentBenches), function(bench) {
|
||||
return bench.name.split(": ")[1];
|
||||
@@ -124,22 +155,41 @@ BenchWarmer.prototype = {
|
||||
|
||||
print(winners.join(", "));
|
||||
print("\n");
|
||||
var padding = this.nameSize - name.length + 1;
|
||||
name = name + new Array(padding).join(" ");
|
||||
print(name);
|
||||
|
||||
if (name) {
|
||||
this.writeValue(name);
|
||||
}
|
||||
},
|
||||
writeBench: function(bench) {
|
||||
var out;
|
||||
|
||||
if(!bench.error) {
|
||||
var count = bench.hz,
|
||||
moe = count * bench.stats.rme / 100;
|
||||
moe = count * bench.stats.rme / 100,
|
||||
minimum,
|
||||
maximum;
|
||||
|
||||
out = Math.round(count / 1000) + " ±" + Math.round(moe / 1000) + " (" + bench.cycles + ")";
|
||||
count = Math.round(count / 1000);
|
||||
moe = Math.round(moe / 1000);
|
||||
minimum = count - moe;
|
||||
maximum = count + moe;
|
||||
|
||||
out = count + " ±" + moe + " (" + bench.cycles + ")";
|
||||
|
||||
this.times[bench.suiteName][bench.benchName] = count;
|
||||
this.minimum = Math.min(this.minimum, minimum);
|
||||
this.maximum = Math.max(this.maximum, maximum);
|
||||
} else {
|
||||
out = "E";
|
||||
if (bench.error.message === 'EWOT') {
|
||||
out = 'NA';
|
||||
} else {
|
||||
out = 'E';
|
||||
}
|
||||
}
|
||||
this.writeValue(out);
|
||||
},
|
||||
|
||||
writeValue: function(out) {
|
||||
var padding = this.benchSize - out.length + 1;
|
||||
out = out + new Array(padding).join(" ");
|
||||
print(out);
|
||||
@@ -0,0 +1,27 @@
|
||||
var _ = require('underscore'),
|
||||
BenchWarmer = require('./benchwarmer'),
|
||||
templates = require('../templates');
|
||||
|
||||
module.exports = function(grunt, makeSuite, callback) {
|
||||
var warmer = new BenchWarmer();
|
||||
|
||||
var handlebarsOnly = grunt.option('handlebars-only'),
|
||||
grep = grunt.option('grep');
|
||||
if (grep) {
|
||||
grep = new RegExp(grep);
|
||||
}
|
||||
|
||||
_.each(templates, function(template, name) {
|
||||
if (!template.handlebars || (grep && !grep.test(name))) {
|
||||
return;
|
||||
}
|
||||
|
||||
warmer.suite(name, function(bench) {
|
||||
makeSuite(bench, name, template, handlebarsOnly);
|
||||
});
|
||||
});
|
||||
|
||||
warmer.bench(function() {
|
||||
callback && callback(warmer.times, warmer.scaled);
|
||||
});
|
||||
};
|
||||
+30
-11
@@ -1,16 +1,35 @@
|
||||
module.exports = {
|
||||
library: {
|
||||
src: ['tmp/<%= pkg.barename %>.amd.js', 'tmp/<%= pkg.barename %>/*.js'],
|
||||
dest: 'dist/<%= pkg.name %>-<%= pkg.version %>.amd.js'
|
||||
options: {
|
||||
banner: '/*!\n\n <%= pkg.name %> v<%= pkg.version %>\n\n<%= grunt.file.read("LICENSE") %>\n@license\n*/\n',
|
||||
process: function(src, name) {
|
||||
var match = /\/\/ BEGIN\(BROWSER\)\n((?:.|\n)*)\n\/\/ END\(BROWSER\)/.exec(src);
|
||||
return '\n// ' + name + '\n' + (match ? match[1] : src);
|
||||
},
|
||||
separator: ';'
|
||||
},
|
||||
|
||||
deps: {
|
||||
src: ['vendor/deps/*.js'],
|
||||
dest: 'tmp/deps.amd.js'
|
||||
dist: {
|
||||
src: [
|
||||
'lib/handlebars/browser-prefix.js',
|
||||
'lib/handlebars/base.js',
|
||||
'lib/handlebars/compiler/parser.js',
|
||||
'lib/handlebars/compiler/base.js',
|
||||
'lib/handlebars/compiler/ast.js',
|
||||
'lib/handlebars/utils.js',
|
||||
'lib/handlebars/compiler/compiler.js',
|
||||
'lib/handlebars/compiler/javascript-compiler.js',
|
||||
'lib/handlebars/runtime.js',
|
||||
'lib/handlebars/browser-suffix.js'
|
||||
],
|
||||
dest: 'dist/handlebars.js'
|
||||
},
|
||||
|
||||
browser: {
|
||||
src: ['vendor/loader.js', 'tmp/<%= pkg.barename %>.amd.js'],
|
||||
dest: 'tmp/<%= pkg.barename %>.browser1.js'
|
||||
runtime: {
|
||||
src: [
|
||||
'lib/handlebars/browser-prefix.js',
|
||||
'lib/handlebars/base.js',
|
||||
'lib/handlebars/utils.js',
|
||||
'lib/handlebars/runtime.js',
|
||||
'lib/handlebars/browser-suffix.js'
|
||||
],
|
||||
dest: 'dist/handlebars.runtime.js'
|
||||
}
|
||||
};
|
||||
|
||||
+25
-16
@@ -15,9 +15,24 @@ export var REVISION_CHANGES = {
|
||||
};
|
||||
|
||||
var toString = Object.prototype.toString,
|
||||
functionType = '[object Function]',
|
||||
objectType = '[object Object]';
|
||||
|
||||
// Sourced from lodash
|
||||
// https://github.com/bestiejs/lodash/blob/master/LICENSE.txt
|
||||
function isFunction(value) {
|
||||
return typeof value === 'function';
|
||||
}
|
||||
// fallback for older versions of Chrome and Safari
|
||||
if (isFunction(/x/)) {
|
||||
isFunction = function(value) {
|
||||
return typeof value === 'function' && toString.call(value) === '[object Function]';
|
||||
};
|
||||
}
|
||||
|
||||
function isArray(value) {
|
||||
return (value && typeof value === 'object') ? toString.call(value) === '[object Array]' : false;
|
||||
};
|
||||
|
||||
export function HandlebarsEnvironment(helpers, partials) {
|
||||
this.helpers = helpers || {};
|
||||
this.partials = partials || {};
|
||||
@@ -59,15 +74,13 @@ function registerDefaultHelpers(instance) {
|
||||
instance.registerHelper('blockHelperMissing', function(context, options) {
|
||||
var inverse = options.inverse || function() {}, fn = options.fn;
|
||||
|
||||
var type = toString.call(context);
|
||||
|
||||
if(type === functionType) { context = context.call(this); }
|
||||
if (isFunction(context)) { context = context.call(this); }
|
||||
|
||||
if(context === true) {
|
||||
return fn(this);
|
||||
} else if(context === false || context == null) {
|
||||
return inverse(this);
|
||||
} else if(type === "[object Array]") {
|
||||
} else if (isArray(context)) {
|
||||
if(context.length > 0) {
|
||||
return instance.helpers.each(context, options);
|
||||
} else {
|
||||
@@ -82,15 +95,14 @@ function registerDefaultHelpers(instance) {
|
||||
var fn = options.fn, inverse = options.inverse;
|
||||
var i = 0, ret = "", data;
|
||||
|
||||
var type = toString.call(context);
|
||||
if(type === functionType) { context = context.call(this); }
|
||||
if (isFunction(context)) { context = context.call(this); }
|
||||
|
||||
if (options.data) {
|
||||
data = createFrame(options.data);
|
||||
}
|
||||
|
||||
if(context && typeof context === 'object') {
|
||||
if(context instanceof Array){
|
||||
if (isArray(context)) {
|
||||
for(var j = context.length; i<j; i++) {
|
||||
if (data) { data.index = i; }
|
||||
ret = ret + fn(context[i], { data: data });
|
||||
@@ -114,8 +126,7 @@ function registerDefaultHelpers(instance) {
|
||||
});
|
||||
|
||||
instance.registerHelper('if', function(conditional, options) {
|
||||
var type = toString.call(conditional);
|
||||
if(type === functionType) { conditional = conditional.call(this); }
|
||||
if (isFunction(conditional)) { conditional = conditional.call(this); }
|
||||
|
||||
if (isEmpty(conditional)) {
|
||||
return options.inverse(this);
|
||||
@@ -129,8 +140,7 @@ function registerDefaultHelpers(instance) {
|
||||
});
|
||||
|
||||
instance.registerHelper('with', function(context, options) {
|
||||
var type = toString.call(context);
|
||||
if(type === functionType) { context = context.call(this); }
|
||||
if (isFunction(context)) { context = context.call(this); }
|
||||
|
||||
if (!isEmpty(context)) return options.fn(context);
|
||||
});
|
||||
@@ -161,9 +171,8 @@ export var logger = {
|
||||
|
||||
export function log(level, obj) { logger.log(level, obj); };
|
||||
|
||||
export var createFrame = Object.create || function(object) {
|
||||
K.prototype = object;
|
||||
var obj = new K();
|
||||
K.prototype = null;
|
||||
export var createFrame = function(object) {
|
||||
var obj = {};
|
||||
Handlebars.Utils.extend(obj, object);
|
||||
return obj;
|
||||
};
|
||||
|
||||
+37
-18
@@ -1,11 +1,31 @@
|
||||
import { escapeExpression, extend, Exception } from "./utils";
|
||||
import { COMPILER_REVISION, REVISION_CHANGES } from "./base";
|
||||
|
||||
function checkRevision(compilerInfo) {
|
||||
var compilerRevision = compilerInfo && compilerInfo[0] || 1,
|
||||
currentRevision = Handlebars.COMPILER_REVISION;
|
||||
|
||||
if (compilerRevision !== currentRevision) {
|
||||
if (compilerRevision < currentRevision) {
|
||||
var runtimeVersions = Handlebars.REVISION_CHANGES[currentRevision],
|
||||
compilerVersions = Handlebars.REVISION_CHANGES[compilerRevision];
|
||||
throw "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 "Template was precompiled with a newer version of Handlebars than the current runtime. "+
|
||||
"Please update your runtime to a newer version ("+compilerInfo[1]+").";
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// TODO: Remove this line and break up compilePartial
|
||||
|
||||
export function template(templateSpec, Hbars, compile) {
|
||||
if (compile) {
|
||||
var invokePartialWrapper = function(partial, name, context, helpers, partials, data) {
|
||||
// TODO : Check this for all inputs and the options handling (partial flag, etc). This feels
|
||||
// like there should be a common exec path
|
||||
var result = invokePartial.apply(this, arguments);
|
||||
if (result) { return result; }
|
||||
|
||||
@@ -42,7 +62,7 @@ export function template(templateSpec, Hbars, compile) {
|
||||
merge: function(param, common) {
|
||||
var ret = param || common;
|
||||
|
||||
if (param && common) {
|
||||
if (param && common && (param !== common)) {
|
||||
ret = {};
|
||||
extend(ret, common);
|
||||
extend(ret, param);
|
||||
@@ -56,24 +76,23 @@ export function template(templateSpec, Hbars, compile) {
|
||||
|
||||
return function(context, options) {
|
||||
options = options || {};
|
||||
var namespace = options.partial ? options : Handlebars,
|
||||
helpers,
|
||||
partials;
|
||||
|
||||
var result = templateSpec.call(container, Hbars, context, options.helpers, options.partials, options.data);
|
||||
if (!options.partial) {
|
||||
helpers = options.helpers;
|
||||
partials = options.partials;
|
||||
}
|
||||
var result = templateSpec.call(
|
||||
container,
|
||||
namespace, context,
|
||||
helpers,
|
||||
partials,
|
||||
options.data);
|
||||
|
||||
var compilerInfo = container.compilerInfo || [],
|
||||
compilerRevision = compilerInfo[0] || 1,
|
||||
currentRevision = COMPILER_REVISION;
|
||||
|
||||
if (compilerRevision !== currentRevision) {
|
||||
if (compilerRevision < currentRevision) {
|
||||
var runtimeVersions = REVISION_CHANGES[currentRevision],
|
||||
compilerVersions = REVISION_CHANGES[compilerRevision];
|
||||
throw "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 "Template was precompiled with a newer version of Handlebars than the current runtime. "+
|
||||
"Please update your runtime to a newer version ("+compilerInfo[1]+").";
|
||||
}
|
||||
if (!options.partial) {
|
||||
checkRevision(container.compilerInfo);
|
||||
}
|
||||
|
||||
return result;
|
||||
@@ -105,7 +124,7 @@ export function program(i, fn, data) {
|
||||
}
|
||||
|
||||
export function invokePartial(partial, name, context, helpers, partials, data) {
|
||||
var options = { helpers: helpers, partials: partials, data: data };
|
||||
var options = { partial: true, helpers: helpers, partials: partials, data: data };
|
||||
|
||||
if(partial === undefined) {
|
||||
throw new Exception("The partial " + name + " could not be found");
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
var toString = Object.prototype.toString;
|
||||
var toString = Object.prototype.toString,
|
||||
isArray = Array.isArray;
|
||||
|
||||
var errorProps = ['description', 'fileName', 'lineNumber', 'message', 'name', 'number', 'stack'];
|
||||
|
||||
@@ -50,7 +51,7 @@ export function escapeExpression(string) {
|
||||
// don't escape SafeStrings, since they're already safe
|
||||
if (string instanceof SafeString) {
|
||||
return string.toString();
|
||||
} else if (string == null || string === false) {
|
||||
} else if (!string && string !== 0) {
|
||||
return "";
|
||||
}
|
||||
|
||||
@@ -66,7 +67,7 @@ export function escapeExpression(string) {
|
||||
export function isEmpty(value) {
|
||||
if (!value && value !== 0) {
|
||||
return true;
|
||||
} else if(toString.call(value) === "[object Array]" && value.length === 0) {
|
||||
} else if (isArray(value) && value.length === 0) {
|
||||
return true;
|
||||
} else {
|
||||
return false;
|
||||
|
||||
+22
-7
@@ -1,12 +1,8 @@
|
||||
{
|
||||
"name": "handlebars.js",
|
||||
"barename": "handlebars",
|
||||
"version": "1.1.0",
|
||||
"version": "1.0.12",
|
||||
"description": "Handlebars provides the power necessary to let you build semantic templates effectively with no frustration",
|
||||
"main": "index.js",
|
||||
"scripts": {
|
||||
"test": "echo \"Error: no test specified\" && exit 1"
|
||||
},
|
||||
"repository": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/wycats/handlebars.js.git"
|
||||
@@ -15,17 +11,36 @@
|
||||
"license": "BSD",
|
||||
"readmeFilename": "README.md",
|
||||
"devDependencies": {
|
||||
"async": "~0.2.9",
|
||||
"aws-sdk": "~1.5.0",
|
||||
"benchmark": "~1.0",
|
||||
"dustjs-linkedin": "~2.0.2",
|
||||
"eco": "~1.1.0-rc-3",
|
||||
"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-jshint": "~0.6.3",
|
||||
"grunt-contrib-uglify": "~0.2.2",
|
||||
"grunt-contrib-watch": "~0.4.4",
|
||||
"grunt-hang": "~0.1.2",
|
||||
"grunt-es6-module-transpiler": "~0.4.1",
|
||||
"es6-module-transpiler": "*",
|
||||
"jison": "~0.3.0",
|
||||
"keen.io": "0.0.3",
|
||||
"mocha": "*",
|
||||
"should": "~1.2.2"
|
||||
}
|
||||
"mustache": "~0.7.2",
|
||||
"semver": "~2.1.0",
|
||||
"should": "~1.2.2",
|
||||
"underscore": "~1.5.1"
|
||||
},
|
||||
"main": "lib/handlebars.js",
|
||||
"bin": {
|
||||
"handlebars": "bin/handlebars"
|
||||
},
|
||||
"scripts": {
|
||||
"test": "node ./spec/env/runner"
|
||||
},
|
||||
"optionalDependencies": {}
|
||||
}
|
||||
|
||||
@@ -90,6 +90,16 @@ describe('builtin helpers', function() {
|
||||
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"};
|
||||
|
||||
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");
|
||||
});
|
||||
|
||||
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"};
|
||||
|
||||
+5
-4
@@ -110,18 +110,19 @@ describe('data', function() {
|
||||
});
|
||||
|
||||
it("data is inherited downstream", function() {
|
||||
var template = CompilerContext.compile("{{#let foo=bar.baz}}{{@foo}}{{/let}}", { data: true });
|
||||
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) {
|
||||
options.data[prop] = options.hash[prop];
|
||||
frame[prop] = options.hash[prop];
|
||||
}
|
||||
return options.fn(this);
|
||||
return options.fn(this, {data: frame});
|
||||
}
|
||||
};
|
||||
|
||||
var result = template({ bar: { baz: "hello world" } }, { helpers: helpers, data: {} });
|
||||
equals("hello world", result, "data variables are inherited downstream");
|
||||
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() {
|
||||
|
||||
@@ -0,0 +1,63 @@
|
||||
var _ = require('underscore'),
|
||||
async = require('async'),
|
||||
git = require('./util/git'),
|
||||
Keen = require('keen.io'),
|
||||
metrics = require('../bench');
|
||||
|
||||
module.exports = function(grunt) {
|
||||
grunt.registerTask('metrics', function() {
|
||||
var done = this.async(),
|
||||
execName = grunt.option('name'),
|
||||
events = {},
|
||||
|
||||
projectId = process.env.KEEN_PROJECTID,
|
||||
writeKey = process.env.KEEN_WRITEKEY,
|
||||
keen;
|
||||
|
||||
if (!execName && projectId && writeKey) {
|
||||
keen = Keen.configure({
|
||||
projectId: projectId,
|
||||
writeKey: writeKey
|
||||
});
|
||||
}
|
||||
|
||||
async.each(_.keys(metrics), function(name, complete) {
|
||||
if (/^_/.test(name) || (execName && name !== execName)) {
|
||||
return complete();
|
||||
}
|
||||
|
||||
metrics[name](grunt, function(data) {
|
||||
events[name] = data;
|
||||
complete();
|
||||
});
|
||||
},
|
||||
function() {
|
||||
if (!keen) {
|
||||
return done();
|
||||
}
|
||||
|
||||
emit(keen, events, function(err, res) {
|
||||
if (err) {
|
||||
throw err;
|
||||
}
|
||||
|
||||
grunt.log.writeln('Metrics recorded.');
|
||||
done();
|
||||
});
|
||||
});
|
||||
});
|
||||
};
|
||||
function emit(keen, collections, callback) {
|
||||
git.commitInfo(function(err, info) {
|
||||
_.each(collections, function(collection) {
|
||||
_.each(collection, function(event) {
|
||||
if (info.tagName) {
|
||||
event.tag = info.tagName;
|
||||
}
|
||||
event.sha = info.head;
|
||||
});
|
||||
});
|
||||
|
||||
keen.addEvents(collections, callback);
|
||||
});
|
||||
}
|
||||
@@ -0,0 +1,23 @@
|
||||
var childProcess = require('child_process');
|
||||
|
||||
module.exports = function(grunt) {
|
||||
grunt.registerTask('parser', 'Generate jison parser.', function() {
|
||||
var done = this.async();
|
||||
|
||||
var child = childProcess.spawn('./node_modules/.bin/jison', ['-m', 'js', 'src/handlebars.yy', 'src/handlebars.l'], {stdio: 'inherit'});
|
||||
child.on('exit', function(code) {
|
||||
if (code != 0) {
|
||||
grunt.fatal('Jison failure: ' + code);
|
||||
done();
|
||||
return;
|
||||
}
|
||||
|
||||
var src = ['src/parser-prefix.js', 'handlebars.js', 'src/parser-suffix.js'].map(grunt.file.read).join('');
|
||||
grunt.file.delete('handlebars.js');
|
||||
|
||||
grunt.file.write('lib/handlebars/compiler/parser.js', src);
|
||||
grunt.log.writeln('Parser "lib/handlebars/compiler/parser.js" created.');
|
||||
done();
|
||||
});
|
||||
});
|
||||
};
|
||||
@@ -0,0 +1,74 @@
|
||||
var _ = require('underscore'),
|
||||
async = require('async'),
|
||||
AWS = require('aws-sdk'),
|
||||
git = require('./util/git');
|
||||
|
||||
module.exports = function(grunt) {
|
||||
grunt.registerTask('publish:latest', function() {
|
||||
var done = this.async();
|
||||
initSDK();
|
||||
|
||||
git.debug(function(remotes, branches) {
|
||||
grunt.log.writeln('remotes: ' + remotes);
|
||||
grunt.log.writeln('branches: ' + branches);
|
||||
|
||||
git.commitInfo(function(err, info) {
|
||||
if (info.isMaster) {
|
||||
publish(fileMap(['-latest', '-' + info.head]), done);
|
||||
} else {
|
||||
// Silently ignore for branches
|
||||
done();
|
||||
}
|
||||
});
|
||||
});
|
||||
});
|
||||
grunt.registerTask('publish:version', function() {
|
||||
var done = this.async();
|
||||
initSDK();
|
||||
|
||||
git.commitInfo(function(err, info) {
|
||||
if (!info.tagName) {
|
||||
throw new Error('The current commit must be tagged');
|
||||
}
|
||||
publish(fileMap(['-' + info.tagName]), done);
|
||||
});
|
||||
});
|
||||
|
||||
function initSDK() {
|
||||
var bucket = process.env.S3_BUCKET_NAME,
|
||||
key = process.env.S3_ACCESS_KEY_ID,
|
||||
secret = process.env.S3_SECRET_ACCESS_KEY;
|
||||
|
||||
if (!bucket || !key || !secret) {
|
||||
throw new Error('Missing S3 config values');
|
||||
}
|
||||
|
||||
AWS.config.update({accessKeyId: key, secretAccessKey: secret});
|
||||
}
|
||||
function publish(files, callback) {
|
||||
var s3 = new AWS.S3(),
|
||||
bucket = process.env.S3_BUCKET_NAME;
|
||||
|
||||
async.forEach(_.keys(files), function(file, callback) {
|
||||
var params = {Bucket: bucket, Key: file, Body: grunt.file.read(files[file])};
|
||||
s3.putObject(params, function(err, data) {
|
||||
if (err) {
|
||||
throw err;
|
||||
} else {
|
||||
grunt.log.writeln('Published ' + file + ' to build server.');
|
||||
callback();
|
||||
}
|
||||
});
|
||||
},
|
||||
callback);
|
||||
}
|
||||
function fileMap(suffixes) {
|
||||
var map = {};
|
||||
_.each(['handlebars.js', 'handlebars.min.js', 'handlebars.runtime.js', 'handlebars.runtime.min.js'], function(file) {
|
||||
_.each(suffixes, function(suffix) {
|
||||
map[file.replace(/\.js$/, suffix + '.js')] = 'dist/' + file;
|
||||
});
|
||||
});
|
||||
return map;
|
||||
}
|
||||
};
|
||||
@@ -0,0 +1,62 @@
|
||||
var async = require('async'),
|
||||
git = require('./util/git'),
|
||||
semver = require('semver');
|
||||
|
||||
module.exports = function(grunt) {
|
||||
grunt.registerTask('version', 'Updates the current release version', function() {
|
||||
var done = this.async(),
|
||||
pkg = grunt.config('pkg'),
|
||||
version = grunt.option('ver');
|
||||
|
||||
if (version === 'major' || version === 'minor' || version === 'patch' || version === 'prerelease') {
|
||||
version = semver.inc(pkg.version, version);
|
||||
}
|
||||
if (!semver.valid(version)) {
|
||||
throw new Error('Must provide a version number (Ex: --ver=patch):\n\t' + version + '\n\n');
|
||||
}
|
||||
|
||||
pkg.version = version;
|
||||
grunt.config('pkg', pkg);
|
||||
|
||||
git.clean(function(err, clean) {
|
||||
if (err || !clean) {
|
||||
throw new Error('The repository must be clean');
|
||||
}
|
||||
|
||||
grunt.log.write('Updating to version ' + version);
|
||||
|
||||
grunt.task.run(['build', 'tag']);
|
||||
|
||||
async.each([
|
||||
['lib/handlebars/base.js', /Handlebars.VERSION = "(.*)";/, 'Handlebars.VERSION = "' + version + '";'],
|
||||
['package.json', /"version":.*/, '"version": "' + version + '",'],
|
||||
['bower.json', /"version":.*/, '"version": "' + version + '",'],
|
||||
['handlebars.js.nuspec', /<version>.*<\/version>/, '<version>' + version + '</version>']
|
||||
],
|
||||
function(args, callback) {
|
||||
replace.apply(undefined, args);
|
||||
git.add(args[0], callback);
|
||||
},
|
||||
done);
|
||||
});
|
||||
});
|
||||
|
||||
grunt.registerTask('tag', 'Tags the current release version', function() {
|
||||
var done = this.async(),
|
||||
name = 'v' + grunt.config('pkg').version;
|
||||
|
||||
async.series([
|
||||
function(callback) { git.add('dist/handlebars.js', callback); },
|
||||
function(callback) { git.add('dist/handlebars.runtime.js', callback); },
|
||||
function(callback) { git.commit(name, callback); },
|
||||
function(callback) { git.tag(name, callback); }
|
||||
],
|
||||
done);
|
||||
});
|
||||
|
||||
function replace(path, regex, replace) {
|
||||
var content = grunt.file.read(path);
|
||||
content = content.replace(regex, replace);
|
||||
grunt.file.write(path, content);
|
||||
}
|
||||
};
|
||||
@@ -0,0 +1,100 @@
|
||||
var childProcess = require('child_process');
|
||||
|
||||
module.exports = {
|
||||
debug: function(callback) {
|
||||
childProcess.exec('git remote -v', {}, function(err, remotes) {
|
||||
if (err) {
|
||||
throw new Error('git.remote: ' + err.message);
|
||||
}
|
||||
|
||||
childProcess.exec('git branch -a', {}, function(err, branches) {
|
||||
if (err) {
|
||||
throw new Error('git.branch: ' + err.message);
|
||||
}
|
||||
|
||||
callback(remotes, branches);
|
||||
});
|
||||
});
|
||||
},
|
||||
clean: function(callback) {
|
||||
childProcess.exec('git diff-index --name-only HEAD --', {}, function(err, stdout) {
|
||||
callback(undefined, !err && !stdout);
|
||||
});
|
||||
},
|
||||
|
||||
commitInfo: function(callback) {
|
||||
module.exports.head(function(err, headSha) {
|
||||
module.exports.master(function(err, masterSha) {
|
||||
module.exports.tagName(function(err, tagName) {
|
||||
callback(undefined, {
|
||||
head: headSha,
|
||||
master: masterSha,
|
||||
tagName: tagName,
|
||||
isMaster: headSha === masterSha
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
},
|
||||
|
||||
head: function(callback) {
|
||||
childProcess.exec('git rev-parse --short HEAD', {}, function(err, stdout) {
|
||||
if (err) {
|
||||
throw new Error('git.head: ' + err.message);
|
||||
}
|
||||
|
||||
callback(undefined, stdout.trim());
|
||||
});
|
||||
},
|
||||
master: function(callback) {
|
||||
childProcess.exec('git rev-parse --short origin/master', {}, function(err, stdout) {
|
||||
// This will error if master was not checked out but in this case we know we are not master
|
||||
// so we can ignore.
|
||||
if (err && !/Needed a single revision/.test(err.message)) {
|
||||
throw new Error('git.master: ' + err.message);
|
||||
}
|
||||
|
||||
callback(undefined, stdout.trim());
|
||||
});
|
||||
},
|
||||
|
||||
add: function(path, callback) {
|
||||
childProcess.exec('git add -f ' + path, {}, function(err, stdout) {
|
||||
if (err) {
|
||||
throw new Error('git.add: ' + err.message);
|
||||
}
|
||||
|
||||
callback();
|
||||
});
|
||||
},
|
||||
commit: function(name, callback) {
|
||||
childProcess.exec('git commit --message=' + name, {}, function(err, stdout) {
|
||||
if (err) {
|
||||
throw new Error('git.commit: ' + err.message);
|
||||
}
|
||||
|
||||
callback();
|
||||
});
|
||||
},
|
||||
tag: function(name, callback) {
|
||||
childProcess.exec('git tag -a --message=' + name + ' ' + name, {}, function(err, stdout, stderr) {
|
||||
if (err) {
|
||||
throw new Error('git.tag: ' + err.message);
|
||||
throw err;
|
||||
}
|
||||
|
||||
callback();
|
||||
});
|
||||
},
|
||||
tagName: function(callback) {
|
||||
childProcess.exec('git tag -l --points-at HEAD', {}, function(err, stdout) {
|
||||
if (err) {
|
||||
throw new Error('git.tagName: ' + err.message);
|
||||
}
|
||||
|
||||
var tags = stdout.trim().split(/\n/),
|
||||
versionTags = tags.filter(function(tag) { return /^v/.test(tag); });
|
||||
callback(undefined, versionTags[0] || tags[0]);
|
||||
});
|
||||
}
|
||||
};
|
||||
Reference in New Issue
Block a user