Compare commits

..

4 Commits

Author SHA1 Message Date
Nils Knappmeier ee913e28bd Added tests for multiple partial-block calls with inline partials
- nested inline partials with partial-blocks on different nesting levels
- nested inline partials (twice at each level)
2017-01-02 10:13:49 +01:00
Nils Knappmeier 7a77f61c44 Add more tests for different scenarios of using partial-blocks
- Multiple partial-blocks at different nesting levels
- Calling partial-blocks twice with nested partial-blocks
- Calling the partial-block from within the #each-helper
2017-01-02 10:05:21 +01:00
Nils Knappmeier 72753bcaa3 Possible fix for #1252: Refactoring for nested partial-block calls
This fix treats partial-blocks more like closures and uses the closure-context of
the "invokePartial"-function to store the @partial-block for the partial.
2017-01-01 08:45:59 +01:00
Nils Knappmeier f3d266a66e Test-case for #1252: Using @partial-block twice in a template not possible 2016-12-31 00:32:03 +01:00
89 changed files with 526 additions and 10782 deletions
+200
View File
@@ -0,0 +1,200 @@
{
"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,
"restParams": 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-character-class": 2,
"no-ex-assign": 2,
"no-extra-boolean-cast": 2,
"no-extra-parens": 0,
"no-extra-semi": 2,
"no-func-assign": 0,
// 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,
"quote-props": [2, "as-needed", {"keywords": true}],
"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": 0,
"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-extra-parens": [2, "functions"],
"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-comment": [2, "always", {"markers": [","]}],
"wrap-regex": 1,
"no-var": 1
}
}
-129
View File
@@ -1,129 +0,0 @@
module.exports = {
"extends": "eslint:recommended",
"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,
"restParams": true,
"spread": true,
"templateStrings": true
},
"rules": {
// overrides eslint:recommended defaults
"no-sparse-arrays": "off",
"no-func-assign": "off",
"no-console": "warn",
"no-debugger": "warn",
"no-unreachable": "warn",
// Possible Errors //
//-----------------//
"no-unsafe-negation": "error",
// Best Practices //
//----------------//
"curly": "error",
"default-case": "warn",
"dot-notation": ["error", { "allowKeywords": false }],
"guard-for-in": "warn",
"no-alert": "error",
"no-caller": "error",
"no-div-regex": "warn",
"no-eval": "error",
"no-extend-native": "error",
"no-extra-bind": "error",
"no-floating-decimal": "error",
"no-implied-eval": "error",
"no-iterator": "error",
"no-labels": "error",
"no-lone-blocks": "error",
"no-loop-func": "error",
"no-multi-spaces": "error",
"no-multi-str": "warn",
"no-global-assign": "error",
"no-new": "error",
"no-new-func": "error",
"no-new-wrappers": "error",
"no-octal-escape": "error",
"no-process-env": "error",
"no-proto": "error",
"no-return-assign": "error",
"no-script-url": "error",
"no-self-compare": "error",
"no-sequences": "error",
"no-throw-literal": "error",
"no-unused-expressions": "error",
"no-warning-comments": "warn",
"no-with": "error",
"radix": "error",
"wrap-iife": "error",
// Variables //
//-----------//
"no-catch-shadow": "error",
"no-label-var": "error",
"no-shadow-restricted-names": "error",
"no-undef-init": "error",
"no-use-before-define": ["error", "nofunc"],
// Stylistic Issues //
//------------------//
"comma-dangle": ["error", "never"],
"quote-props": ["error", "as-needed", { "keywords": true, "unnecessary": false }],
"brace-style": ["error", "1tbs", { "allowSingleLine": true }],
"camelcase": "error",
"comma-spacing": ["error", { "before": false, "after": true }],
"comma-style": ["error", "last"],
"consistent-this": ["warn", "self"],
"eol-last": "error",
"func-style": ["error", "declaration"],
"key-spacing": ["error", {
"beforeColon": false,
"afterColon": true
}],
"new-cap": "error",
"new-parens": "error",
"no-array-constructor": "error",
"no-lonely-if": "error",
"no-mixed-spaces-and-tabs": "error",
"no-nested-ternary": "warn",
"no-new-object": "error",
"no-spaced-func": "error",
"no-trailing-spaces": "error",
"no-extra-parens": ["error", "functions"],
"quotes": ["error", "single", "avoid-escape"],
"semi": "error",
"semi-spacing": ["error", { "before": false, "after": true }],
"keyword-spacing": "error",
"space-before-blocks": ["error", "always"],
"space-before-function-paren": ["error", { "anonymous": "never", "named": "never" }],
"space-in-parens": ["error", "never"],
"space-infix-ops": "error",
"space-unary-ops": "error",
"spaced-comment": ["error", "always", { "markers": [","] }],
"wrap-regex": "warn",
// ECMAScript 6 //
//--------------//
"no-var": "warn"
},
"parserOptions": {
"sourceType": "module"
}
}
-6
View File
@@ -1,6 +0,0 @@
# Handlebars-template fixtures in test cases need deterministic eol
*.handlebars text eol=lf
*.hbs text eol=lf
# Lexer files as well
*.l text eol=lf
-3
View File
@@ -10,6 +10,3 @@ node_modules
*.sublime-workspace
npm-debug.log
sauce_connect.log*
.idea
yarn-error.log
/handlebars-release.tgz
+1 -1
View File
@@ -1,2 +1,2 @@
instrumentation:
excludes: ['**/spec/**', '**/handlebars/compiler/parser.js']
excludes: ['**/spec/**']
+25
View File
@@ -0,0 +1,25 @@
.DS_Store
.gitignore
.rvmrc
.eslintrc
.travis.yml
.rspec
Gemfile
Gemfile.lock
Rakefile
Gruntfile.js
*.gemspec
*.nuspec
*.log
bench/*
configurations/*
components/*
coverage/*
dist/cdnjs/*
dist/components/*
spec/*
src/*
tasks/*
tmp/*
publish/*
vendor/*
+2 -1
View File
@@ -13,11 +13,12 @@ env:
- secure: Nm4AgSfsgNB21kgKrF9Tl7qVZU8YYREhouQunFracTcZZh2NZ2XH5aHuSiXCj88B13Cr/jGbJKsZ4T3QS3wWYtz6lkyVOx3H3iI+TMtqhD9RM3a7A4O+4vVN8IioB2YjhEu0OKjwgX5gp+0uF+pLEi7Hpj6fupD3AbbL5uYcKg8=
matrix:
include:
- node_js: '10'
- node_js: '5'
env:
- PUBLISH=true
- secure: pLTzghtVll9yGKJI0AaB0uI8GypfWxLTaIB0ZL8//yN3nAEIKMhf/RRilYTsn/rKj2NUa7vt2edYILi3lttOUlCBOwTc9amiRms1W8Lwr/3IdWPeBLvLuH1zNJRm2lBAwU4LBSqaOwhGaxOQr6KHTnWudhNhgOucxpZfvfI/dFw=
- secure: yERYCf7AwL11D9uMtacly/THGV8BlzsMmrt+iQVvGA3GaY6QMmfYqf6P6cCH98sH5etd1Y+1e6YrPeMjqI6lyRllT7FptoyOdHulazQe86VQN4sc0EpqMlH088kB7gGjTut9Z+X9ViooT5XEh9WA5jXEI9pXhQJNoIHkWPuwGuY=
- node_js: '4'
cache:
directories:
- node_modules
+3 -19
View File
@@ -10,12 +10,6 @@ Pull requests containing only failing tests demonstrating the issue are welcomed
Documentation issues on the handlebarsjs.com site should be reported on [handlebars-site](https://github.com/wycats/handlebars-site).
## Branches
* The branch `4.x` contains the currently released version. Bugfixes should be made in this branch.
* The branch `master` contains the next version. A release date is not yet specified. Maintainers
should merge the branch `4.x` into the master branch regularly.
## Pull Requests
We also accept [pull requests][pull-request]!
@@ -81,9 +75,7 @@ npm link handlebars
npm test
```
## Releasing the latest version
*When releasing a previous version of Handlebars, please look into the CONTRIBUNG.md in the corresponding branch.*
## Releasing
Handlebars utilizes the [release yeoman generator][generator-release] to perform most release tasks.
@@ -99,17 +91,9 @@ gem build handlebars-source.gemspec
gem push handlebars-source-*.gem
```
After the release, you should check that all places have really been updated. Especially verify that the `latest`-tags
in those places still point to the latest version
* [The npm-package](https://www.npmjs.com/package/handlebars) (check latest-tag)
* [The bower package](https://github.com/components/handlebars.js) (check the package.json)
* [The AWS S3 Bucket](http://builds.handlebarsjs.com.s3.amazonaws.com/) (check latest-tag)
* [RubyGems](https://rubygems.org/gems/handlebars-source)
When everything is OK, the handlebars site needs to be updated to point to the new version numbers. The jsfiddle link should be updated to point to the most recent distribution for all instances in our documentation.
After this point the handlebars site needs to be updated to point to the new version numbers. The jsfiddle link should be updated to point to the most recent distribution for all instances in our documentation.
[generator-release]: https://github.com/walmartlabs/generator-release
[pull-request]: https://github.com/wycats/handlebars.js/pull/new/master
[issue]: https://github.com/wycats/handlebars.js/issues/new
[jsfiddle]: https://jsfiddle.net/9D88g/180/
[jsfiddle]: https://jsfiddle.net/9D88g/47/
+7 -25
View File
@@ -5,19 +5,18 @@ module.exports = function(grunt) {
pkg: grunt.file.readJSON('package.json'),
eslint: {
options: {
},
files: [
'*.js',
'bench/**/*.js',
'tasks/**/*.js',
'lib/**/!(*.min|parser).js',
'spec/**/!(*.amd|json2|require).js',
'integration-testing/multi-nodejs-test/*.js',
'integration-testing/webpack-test/*.js',
'integration-testing/webpack-test/src/*.js'
'spec/**/!(*.amd|json2|require).js'
]
},
clean: ['tmp', 'dist', 'lib/handlebars/compiler/parser.js', 'integration-testing/**/node_modules'],
clean: ['tmp', 'dist', 'lib/handlebars/compiler/parser.js'],
copy: {
dist: {
@@ -167,8 +166,8 @@ module.exports = function(grunt) {
browsers: [
{browserName: 'chrome'},
{browserName: 'firefox', platform: 'Linux'},
// {browserName: 'safari', version: 9, platform: 'OS X 10.11'},
// {browserName: 'safari', version: 8, platform: 'OS X 10.10'},
{browserName: 'safari', version: 9, platform: 'OS X 10.11'},
{browserName: 'safari', version: 8, platform: 'OS X 10.10'},
{browserName: 'internet explorer', version: 11, platform: 'Windows 8.1'},
{browserName: 'internet explorer', version: 10, platform: 'Windows 8'}
]
@@ -187,20 +186,6 @@ module.exports = function(grunt) {
}
},
bgShell: {
checkTypes: {
cmd: 'npm run checkTypes',
bg: false,
fail: true
},
integrationTests: {
cmd: './integration-testing/run-integration-tests.sh',
bg: false,
fail: true
}
},
watch: {
scripts: {
options: {
@@ -216,7 +201,6 @@ module.exports = function(grunt) {
// Build a new version of the library
this.registerTask('build', 'Builds a distributable version of the current project', [
'eslint',
'bgShell:checkTypes',
'parser',
'node',
'globals']);
@@ -237,7 +221,6 @@ module.exports = function(grunt) {
grunt.loadNpmTasks('grunt-contrib-uglify');
grunt.loadNpmTasks('grunt-contrib-watch');
grunt.loadNpmTasks('grunt-babel');
grunt.loadNpmTasks('grunt-bg-shell');
grunt.loadNpmTasks('grunt-eslint');
grunt.loadNpmTasks('grunt-saucelabs');
grunt.loadNpmTasks('grunt-webpack');
@@ -247,9 +230,8 @@ module.exports = function(grunt) {
grunt.registerTask('bench', ['metrics']);
grunt.registerTask('sauce', process.env.SAUCE_USERNAME ? ['tests', 'connect', 'saucelabs-mocha'] : []);
grunt.registerTask('travis', process.env.PUBLISH ? ['default', 'bgShell:integrationTests', 'sauce', 'metrics', 'publish:latest'] : ['default']);
grunt.registerTask('travis', process.env.PUBLISH ? ['default', 'sauce', 'metrics', 'publish:latest'] : ['default']);
grunt.registerTask('dev', ['clean', 'connect', 'watch']);
grunt.registerTask('default', ['clean', 'build', 'test', 'release']);
grunt.registerTask('integration-tests', ['default', 'bgShell:integrationTests']);
};
+1 -1
View File
@@ -1,4 +1,4 @@
Copyright (C) 2011-2017 by Yehuda Katz
Copyright (C) 2011-2016 by Yehuda Katz
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
-1
View File
@@ -1,5 +1,4 @@
[![Travis Build Status](https://img.shields.io/travis/wycats/handlebars.js/master.svg)](https://travis-ci.org/wycats/handlebars.js)
[![Appveyor Build Status](https://ci.appveyor.com/api/projects/status/github/wycats/handlebars.js?branch=master&svg=true)](https://ci.appveyor.com/project/wycats/handlebars-js)
[![Selenium Test Status](https://saucelabs.com/buildstatus/handlebars)](https://saucelabs.com/u/handlebars)
Handlebars.js
-37
View File
@@ -1,37 +0,0 @@
# Test against these versions of Node.js
environment:
matrix:
- nodejs_version: "10"
platform:
- x64
# Install scripts (runs after repo cloning)
install:
# Get the latest stable version of Node.js
- ps: Install-Product node $env:nodejs_version $env:platform
# Clone submodules (mustache spec)
- cmd: git submodule update --init --recursive
# Install modules
- cmd: npm install
- cmd: npm install -g grunt-cli
# Post-install test scripts
test_script:
# Output useful info for debugging
- cmd: node --version
- cmd: npm --version
# Run tests
- cmd: grunt --stack travis
# Don't actually build
build: off
on_failure:
- cmd: 7z a coverage.zip coverage
- cmd: appveyor PushArtifact coverage.zip
# Set build version format here instead of in the admin panel
version: "{build}"
+1 -1
View File
@@ -1,4 +1,4 @@
var async = require('neo-async'),
var async = require('async'),
fs = require('fs'),
zlib = require('zlib');
+1 -1
View File
@@ -5,7 +5,7 @@ module.exports = {
header: function() {
return 'Colors';
},
hasItems: true, // To make things fairer in mustache land due to no `{{if}}` construct on arrays
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'},
+1 -1
View File
@@ -11,7 +11,7 @@ function BenchWarmer() {
this.errors = {};
}
var print = require('util').print;
var print = require('sys').print;
BenchWarmer.prototype = {
winners: function(benches) {
+1 -1
View File
@@ -1,6 +1,6 @@
{
"name": "handlebars",
"version": "4.3.4",
"version": "4.0.6",
"main": "handlebars.js",
"license": "MIT",
"dependencies": {}
+1 -1
View File
@@ -2,7 +2,7 @@
<package>
<metadata>
<id>handlebars.js</id>
<version>4.3.4</version>
<version>4.0.6</version>
<authors>handlebars.js Authors</authors>
<licenseUrl>https://github.com/wycats/handlebars.js/blob/master/LICENSE</licenseUrl>
<projectUrl>https://github.com/wycats/handlebars.js/</projectUrl>
-20
View File
@@ -1,20 +0,0 @@
{
"name": "handlebars",
"version": "4.3.4",
"license": "MIT",
"jspm": {
"main": "handlebars",
"shim": {
"handlebars": {
"exports": "Handlebars"
}
},
"files": [
"handlebars.js",
"handlebars.runtime.js"
],
"buildConfig": {
"minify": true
}
}
}
+7 -29
View File
@@ -66,7 +66,7 @@ interface MustacheStatement <: Statement {
interface BlockStatement <: Statement {
type: "BlockStatement";
path: PathExpression | Literal;
path: PathExpression;
params: [ Expression ];
hash: Hash;
@@ -296,43 +296,21 @@ The `Handlebars.JavaScriptCompiler` object has a number of methods that may be c
- `initializeBuffer()`
Allows for buffers other than the default string buffer to be used. Generally needs to be paired with a custom `appendToBuffer` implementation.
### Example for the compiler api.
This example changes all lookups of properties are performed by a helper (`lookupLowerCase`) which looks for `test` if `{{Test}}` occurs in the template. This is just to illustrate how compiler behavior can be change.
There is also [a jsfiddle with this code](https://jsfiddle.net/9D88g/162/) if you want to play around with it.
```javascript
function MyCompiler() {
Handlebars.JavaScriptCompiler.apply(this, arguments);
}
MyCompiler.prototype = new Handlebars.JavaScriptCompiler();
MyCompiler.prototype = Object.create(Handlebars.JavaScriptCompiler);
// Use this compile to compile BlockStatment-Blocks
MyCompiler.prototype.compiler = MyCompiler
MyCompiler.prototype.nameLookup = function(parent, name, type) {
if (type === 'context') {
return this.source.functionCall('helpers.lookupLowerCase', '', [parent, JSON.stringify(name)])
MyCompiler.nameLookup = function(parent, name, type) {
if (type === 'partial') {
return 'MyPartialList[' + JSON.stringify(name) ']';
} else {
return Handlebars.JavaScriptCompiler.prototype.nameLookup.call(this, parent, name, type);
}
}
};
var env = Handlebars.create();
env.registerHelper('lookupLowerCase', function(parent, name) {
return parent[name.toLowerCase()]
})
env.JavaScriptCompiler = MyCompiler;
var template = env.compile('{{#each Test}} ({{Value}}) {{/each}}');
console.log(template({
test: [
{value: 'a'},
{value: 'b'},
{value: 'c'}
]
}));
env.compile('my template');
```
-12
View File
@@ -1,12 +0,0 @@
Add a new integration test by creating a new subfolder
Add a file "test.sh" to that runs the test. "test.sh" should exit with a non-zero exit code
and display an error message, if something goes wrong.
* An integration test should reflect real-world setups that use handlebars.
* It should compile a minimal template and compare the output to an expected output.
* It should use "../.." as dependency for Handlebars so that the currently built library is used.
Currently, integration tests are only running on Linux, especially in travis-ci.
@@ -1,12 +0,0 @@
module.exports = {
"extends": "eslint:recommended",
"globals": {
"self": false
},
"env": {
"node": true
},
"rules": {
'no-console': 'off'
}
}
@@ -1,2 +0,0 @@
target
package-lock.json
@@ -1,16 +0,0 @@
{
"name": "multi-nodejs-test",
"version": "1.0.0",
"description": "Simple integration test with all relevant NodeJS-versions.",
"keywords": [],
"author": "Nils Knappmeier",
"private": true,
"license": "MIT",
"dependencies": {
"handlebars": "file:../.."
},
"scripts": {
"test": "node run-handlebars.js",
"test-precompile": "handlebars precompile-test-template.txt.hbs"
}
}
@@ -1 +0,0 @@
Author: {{author}}
@@ -1,11 +0,0 @@
// This test should run successfully with node 0.10++ as long as Handlebars has been compiled before
var assert = require('assert');
var Handlebars = require('handlebars');
console.log('Testing built Handlebars with Node version ' + process.version);
var template = Handlebars.compile('Author: {{author}}');
var output = template({author: 'Yehuda'});
assert.strictEqual(output, 'Author: Yehuda');
console.log('Success');
@@ -1,26 +0,0 @@
#!/bin/bash
cd "$( dirname "$( readlink -f "$0" )" )" || exit 1
# shellcheck disable=SC1090
[ -s "$NVM_DIR/nvm.sh" ] && \. "$NVM_DIR/nvm.sh"
# This script tests with precompiler and the built distribution with multiple NodeJS version.
# The rest of the travis-build will only work with newer NodeJS versions, because the build
# tools don't support older versions.
# However, the built distribution should work with older NodeJS versions as well.
# This test is simple by design. It merely ensures, that calling Handlebars does not fail with old versions.
# It does (almost) not test for correctness, because that is already done in the mocha-tests.
# And it does not use any NodeJS based testing framwork to make this part independent of the Node version.
# A list of NodeJS versions is expected as cli-args
echo "Handlebars should be able to run in various versions of NodeJS"
for i in 0.10 0.12 4 5 6 7 8 9 10 11 ; do
rm target node_modules package-lock.json -rf
mkdir target
nvm install "$i"
nvm exec "$i" npm install
nvm exec "$i" npm run test || exit 1
nvm exec "$i" npm run test-precompile || exit 1
echo Success
done
@@ -1,13 +0,0 @@
#!/bin/bash
cd "$( dirname "$( readlink -f "$0" )" )" || exit 1
for i in */test.sh ; do
(
echo "----------------------------------------"
echo "-- Running integration test: $i"
echo "----------------------------------------"
cd "$( dirname "$i" )" || exit 1
./test.sh || exit 1
)
done
@@ -1,11 +0,0 @@
{
"plugins": [
"@roundingwellos/babel-plugin-handlebars-inline-precompile"
// "istanbul"
],
"presets": [
[
"@babel/preset-env"
]
]
}
@@ -1,3 +0,0 @@
node_modules
dist
package-lock.json
@@ -1,24 +0,0 @@
{
"name": "webpack-babel-test",
"version": "1.0.0",
"description": "",
"main": "index.js",
"keywords": [],
"author": "",
"license": "ISC",
"dependencies": {
"@babel/core": "^7.5.5",
"@babel/preset-env": "^7.5.5",
"@roundingwellos/babel-plugin-handlebars-inline-precompile": "^3.0.1",
"babel-loader": "^8.0.6",
"babel-plugin-istanbul": "^5.2.0",
"handlebars": "file:../..",
"handlebars-loader": "^1.7.1",
"nyc": "^14.1.1",
"webpack": "^4.39.3",
"webpack-cli": "^3.3.7"
},
"scripts": {
"build": "webpack --config webpack.config.js"
}
}
@@ -1,12 +0,0 @@
import * as Handlebars from 'handlebars/runtime'
import hbs from 'handlebars-inline-precompile';
import {assertEquals} from "../../webpack-test/src/lib/assert";
Handlebars.registerHelper('loud', function(text) {
return text.toUpperCase();
});
const template = hbs`{{loud name}}`;
const output = template({name: 'yehuda'})
assertEquals(output, 'YEHUDA')
@@ -1,5 +0,0 @@
export function assertEquals(actual, expected) {
if (actual !== expected) {
throw new Error(`Expected "${actual}" to equal "${expected}"`);
}
}
@@ -1,16 +0,0 @@
#!/bin/bash
set -e
# Cleanup: package-lock and "npm ci" is not working with local dependencies
rm dist package-lock.json -rf
npm install
npm run build
for i in dist/*-test.js ; do
echo "----------------------"
echo "-- Running $i"
echo "----------------------"
node "$i"
echo "Success"
done
@@ -1,32 +0,0 @@
const fs = require('fs');
const testFiles = fs.readdirSync('src');
const entryPoints = {};
testFiles
.filter(file => file.match(/-test.js$/))
.forEach(file => {
entryPoints[file] = `./src/${file}`;
});
module.exports = {
entry: entryPoints,
output: {
filename: '[name]',
path: __dirname + '/dist'
},
module: {
rules: [
{
test: /\.js?$/,
exclude: /node_modules/,
use: {
loader: 'babel-loader',
options: { cacheDirectory: false },
}
}
]
},
optimization: {
minimize: false
}
};
@@ -1,3 +0,0 @@
node_modules
dist
package-lock.json
@@ -1,21 +0,0 @@
{
"name": "webpack-test",
"description": "Various tests with Handlebars and Webpack",
"version": "1.0.0",
"main": "index.js",
"scripts": {
"build": "webpack --config webpack.config.js",
"test": "node dist/main.js"
},
"private": true,
"keywords": [],
"author": "",
"license": "ISC",
"dependencies": {},
"devDependencies": {
"handlebars": "file:../..",
"handlebars-loader": "^1.7.1",
"webpack": "^4.39.3",
"webpack-cli": "^3.3.7"
}
}
@@ -1,6 +0,0 @@
import Handlebars from 'handlebars/dist/handlebars';
import {assertEquals} from './lib/assert';
const template = Handlebars.compile('Author: {{author}}');
assertEquals(template({author: 'Yehuda'}), 'Author: Yehuda');
@@ -1,6 +0,0 @@
import Handlebars from 'handlebars';
import {assertEquals} from './lib/assert';
const template = Handlebars.compile('Author: {{author}}');
assertEquals(template({author: 'Yehuda'}), 'Author: Yehuda');
@@ -1,8 +0,0 @@
import {assertEquals} from './lib/assert';
import testTemplate from './test-template.handlebars';
assertEquals(testTemplate({author: 'Yehuda'}).trim(), 'Author: Yehuda');
const testTemplateRequire = require('./test-template.handlebars');
assertEquals(testTemplateRequire({author: 'Yehuda'}).trim(), 'Author: Yehuda');
@@ -1,10 +0,0 @@
import * as HandlebarsViaImport from 'handlebars';
const HandlebarsViaRequire = require('handlebars');
import {assertEquals} from './lib/assert';
HandlebarsViaImport.registerHelper('loud', function(text) {
return text.toUpperCase();
});
const template = HandlebarsViaRequire.compile('Author: {{loud author}}');
assertEquals(template({author: 'Yehuda'}), 'Author: YEHUDA');
@@ -1,6 +0,0 @@
import * as Handlebars from 'handlebars/dist/handlebars';
import {assertEquals} from './lib/assert';
const template = Handlebars.compile('Author: {{author}}');
assertEquals(template({author: 'Yehuda'}), 'Author: Yehuda');
@@ -1,5 +0,0 @@
import * as Handlebars from 'handlebars';
import {assertEquals} from './lib/assert';
const template = Handlebars.compile('Author: {{author}}');
assertEquals(template({author: 'Yehuda'}), 'Author: Yehuda');
@@ -1,5 +0,0 @@
export function assertEquals(actual, expected) {
if (actual !== expected) {
throw new Error(`Expected "${actual}" to equal "${expected}"`);
}
}
@@ -1,2 +0,0 @@
Author: {{author}}
-16
View File
@@ -1,16 +0,0 @@
#!/bin/bash
set -e
# Cleanup: package-lock and "npm ci" is not working with local dependencies
rm dist package-lock.json -rf
npm install
npm run build
for i in dist/*-test.js ; do
echo "----------------------"
echo "-- Running $i"
echo "----------------------"
node "$i"
echo "Success"
done
@@ -1,22 +0,0 @@
const fs = require('fs');
const testFiles = fs.readdirSync('src');
const entryPoints = {};
testFiles
.filter(file => file.match(/-test.js$/))
.forEach(file => {
entryPoints[file] = `./src/${file}`;
});
module.exports = {
entry: entryPoints,
output: {
filename: '[name]',
path: __dirname + '/dist'
},
module: {
rules: [
{test: /\.handlebars$/, loader: 'handlebars-loader'}
]
}
};
+3 -5
View File
@@ -4,9 +4,8 @@ import {registerDefaultHelpers} from './helpers';
import {registerDefaultDecorators} from './decorators';
import logger from './logger';
export const VERSION = '4.3.4';
export const COMPILER_REVISION = 8;
export const LAST_COMPATIBLE_COMPILER_REVISION = 7;
export const VERSION = '4.0.6';
export const COMPILER_REVISION = 7;
export const REVISION_CHANGES = {
1: '<= 1.0.rc.2', // 1.0.rc.2 is actually rev2 but doesn't report it
@@ -15,8 +14,7 @@ export const REVISION_CHANGES = {
4: '== 1.x.x',
5: '== 2.0.0-alpha.x',
6: '>= 2.0.0-beta.1',
7: '>= 4.0.0 <4.3.0',
8: '>= 4.3.0'
7: '>= 4.0.0'
};
const objectType = '[object Object]';
+1 -1
View File
@@ -118,7 +118,7 @@ CodeGen.prototype = {
.replace(/"/g, '\\"')
.replace(/\n/g, '\\n')
.replace(/\r/g, '\\r')
.replace(/\u2028/g, '\\u2028') // Per Ecma-262 7.3 + 7.8.4
.replace(/\u2028/g, '\\u2028') // Per Ecma-262 7.3 + 7.8.4
.replace(/\u2029/g, '\\u2029') + '"';
},
+5 -6
View File
@@ -1,7 +1,7 @@
/* eslint-disable new-cap */
import Exception from '../exception';
import {isArray, indexOf, extend} from '../utils';
import {isArray, indexOf} from '../utils';
import AST from './ast';
const slice = [].slice;
@@ -67,11 +67,11 @@ Compiler.prototype = {
'lookup': true
};
if (knownHelpers) {
// the next line should use "Object.keys", but the code has been like this a long time and changing it, might
// cause backwards-compatibility issues... It's an old library...
// eslint-disable-next-line guard-for-in
for (let name in knownHelpers) {
this.options.knownHelpers[name] = knownHelpers[name];
/* istanbul ignore else */
if (name in knownHelpers) {
options.knownHelpers[name] = knownHelpers[name];
}
}
}
@@ -488,7 +488,6 @@ export function compile(input, options = {}, env) {
throw new Exception('You must pass a string or Handlebars AST to Handlebars.compile. You passed ' + input);
}
options = extend({}, options);
if (!('data' in options)) {
options.data = true;
}
+5 -3
View File
@@ -24,7 +24,7 @@ export function SourceLocation(source, locInfo) {
export function id(token) {
if (/^\[.*\]$/.test(token)) {
return token.substring(1, token.length - 1);
return token.substr(1, token.length - 2);
} else {
return token;
}
@@ -38,7 +38,7 @@ export function stripFlags(open, close) {
}
export function stripComment(comment) {
return comment.replace(/^\{\{~?!-?-?/, '')
return comment.replace(/^\{\{~?\!-?-?/, '')
.replace(/-?-?~?\}\}$/, '');
}
@@ -47,7 +47,8 @@ export function preparePath(data, parts, loc) {
let original = data ? '@' : '',
dig = [],
depth = 0;
depth = 0,
depthString = '';
for (let i = 0, l = parts.length; i < l; i++) {
let part = parts[i].part,
@@ -61,6 +62,7 @@ export function preparePath(data, parts, loc) {
throw new Exception('Invalid path: ' + original, {loc});
} else if (part === '..') {
depth++;
depthString += '../';
}
} else {
dig.push(part);
+27 -49
View File
@@ -13,19 +13,10 @@ JavaScriptCompiler.prototype = {
// PUBLIC API: You can override these methods in a subclass to provide
// alternative compiled forms for name lookup and buffering semantics
nameLookup: function(parent, name/* , type*/) {
const isEnumerable = [ this.aliasable('container.propertyIsEnumerable'), '.call(', parent, ',"constructor")'];
if (name === 'constructor') {
return ['(', isEnumerable, '?', _actualLookup(), ' : undefined)'];
}
return _actualLookup();
function _actualLookup() {
if (JavaScriptCompiler.isValidJavaScriptVariableName(name)) {
return [parent, '.', name];
} else {
return [parent, '[', JSON.stringify(name), ']'];
}
if (JavaScriptCompiler.isValidJavaScriptVariableName(name)) {
return [parent, '.', name];
} else {
return [parent, '[', JSON.stringify(name), ']'];
}
},
depthedLookup: function(name) {
@@ -142,7 +133,7 @@ JavaScriptCompiler.prototype = {
};
if (this.decorators) {
ret.main_d = this.decorators; // eslint-disable-line camelcase
ret.main_d = this.decorators; // eslint-disable-line camelcase
ret.useDecorators = true;
}
@@ -218,8 +209,9 @@ JavaScriptCompiler.prototype = {
// aliases will not be used, but this case is already being run on the client and
// we aren't concern about minimizing the template size.
let aliasCount = 0;
for (let alias in this.aliases) { // eslint-disable-line guard-for-in
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;
node.children[0] = 'alias' + aliasCount;
@@ -316,7 +308,7 @@ JavaScriptCompiler.prototype = {
// replace it on the stack with the result of properly
// invoking blockHelperMissing.
blockValue: function(name) {
let blockHelperMissing = this.aliasable('container.hooks.blockHelperMissing'),
let blockHelperMissing = this.aliasable('helpers.blockHelperMissing'),
params = [this.contextName(0)];
this.setupHelperArgs(name, 0, params);
@@ -334,7 +326,7 @@ 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
let blockHelperMissing = this.aliasable('container.hooks.blockHelperMissing'),
let blockHelperMissing = this.aliasable('helpers.blockHelperMissing'),
params = [this.contextName(0)];
this.setupHelperArgs('', 0, params, true);
@@ -344,9 +336,9 @@ JavaScriptCompiler.prototype = {
params.splice(1, 0, current);
this.pushSource([
'if (!', this.lastHelper, ') { ',
current, ' = ', this.source.functionCall(blockHelperMissing, 'call', params),
'}']);
'if (!', this.lastHelper, ') { ',
current, ' = ', this.source.functionCall(blockHelperMissing, 'call', params),
'}']);
},
// [appendContent]
@@ -627,32 +619,18 @@ JavaScriptCompiler.prototype = {
// If the helper is not found, `helperMissing` is called.
invokeHelper: function(paramSize, name, isSimple) {
let nonHelper = this.popStack(),
helper = this.setupHelper(paramSize, name);
helper = this.setupHelper(paramSize, name),
simple = isSimple ? [helper.name, ' || '] : '';
let possibleFunctionCalls = [];
if (isSimple) { // direct call to helper
possibleFunctionCalls.push(helper.name);
}
// call a function from the input object
possibleFunctionCalls.push(nonHelper);
let lookup = ['('].concat(simple, nonHelper);
if (!this.options.strict) {
possibleFunctionCalls.push(this.aliasable('container.hooks.helperMissing'));
lookup.push(' || ', this.aliasable('helpers.helperMissing'));
}
lookup.push(')');
let functionLookupCode = ['(', this.itemsSeparatedBy(possibleFunctionCalls, '||'), ')'];
let functionCall = this.source.functionCall(functionLookupCode, 'call', helper.callParams);
this.push(functionCall);
this.push(this.source.functionCall(lookup, 'call', helper.callParams));
},
itemsSeparatedBy: function(items, separator) {
let result = [];
result.push(items[0]);
for (let i = 1; i < items.length; i++) {
result.push(separator, items[i]);
}
return result;
},
// [invokeKnownHelper]
//
// On stack, before: hash, inverse, program, params..., ...
@@ -691,16 +669,16 @@ JavaScriptCompiler.prototype = {
if (!this.options.strict) {
lookup[0] = '(helper = ';
lookup.push(
' != null ? helper : ',
this.aliasable('container.hooks.helperMissing')
' != null ? helper : ',
this.aliasable('helpers.helperMissing')
);
}
this.push([
'(', lookup,
(helper.paramsInit ? ['),(', helper.paramsInit] : []), '),',
'(typeof helper === ', this.aliasable('"function"'), ' ? ',
this.source.functionCall('helper', 'call', helper.callParams), ' : helper))'
'(', lookup,
(helper.paramsInit ? ['),(', helper.paramsInit] : []), '),',
'(typeof helper === ', this.aliasable('"function"'), ' ? ',
this.source.functionCall('helper', 'call', helper.callParams), ' : helper))'
]);
},
@@ -798,12 +776,12 @@ JavaScriptCompiler.prototype = {
for (let i = 0, l = children.length; i < l; i++) {
child = children[i];
compiler = new this.compiler(); // eslint-disable-line new-cap
compiler = new this.compiler(); // eslint-disable-line new-cap
let existing = this.matchExistingProgram(child);
if (existing == null) {
this.context.programs.push(''); // Placeholder to prevent name conflicts for nested children
this.context.programs.push(''); // Placeholder to prevent name conflicts for nested children
let index = this.context.programs.length;
child.index = index;
child.name = 'program' + index;
@@ -1009,7 +987,7 @@ JavaScriptCompiler.prototype = {
let params = [],
paramsInit = this.setupHelperArgs(name, paramSize, params, blockHelper);
let foundHelper = this.nameLookup('helpers', name, 'helper'),
callContext = this.aliasable(`${this.contextName(0)} != null ? ${this.contextName(0)} : (container.nullContext || {})`);
callContext = this.aliasable(`${this.contextName(0)} != null ? ${this.contextName(0)} : {}`);
return {
params: params,
@@ -206,7 +206,7 @@ function omitLeft(body, i, multiple) {
return;
}
// We omit the last node if it's whitespace only and not preceded by a non-content node.
// We omit the last node if it's whitespace only and not preceeded by a non-content node.
let original = current.value;
current.value = current.value.replace(multiple ? (/\s+$/) : (/[ \t]+$/), '');
current.leftStripped = current.value !== original;
-9
View File
@@ -15,12 +15,3 @@ export function registerDefaultHelpers(instance) {
registerLookup(instance);
registerWith(instance);
}
export function moveHelperToHooks(instance, helperName, keepHelper) {
if (instance.helpers[helperName]) {
instance.hooks[helperName] = instance.helpers[helperName];
if (!keepHelper) {
delete instance.helpers[helperName];
}
}
}
+1 -7
View File
@@ -1,11 +1,5 @@
export default function(instance) {
instance.registerHelper('lookup', function(obj, field) {
if (!obj) {
return obj;
}
if (field === 'constructor' && !obj.propertyIsEnumerable(field)) {
return undefined;
}
return obj[field];
return obj && obj[field];
});
}
+2 -2
View File
@@ -24,10 +24,10 @@ let logger = {
if (typeof console !== 'undefined' && logger.lookupLevel(logger.level) <= level) {
let method = logger.methodMap[level];
if (!console[method]) { // eslint-disable-line no-console
if (!console[method]) { // eslint-disable-line no-console
method = 'log';
}
console[method](...message); // eslint-disable-line no-console
console[method](...message); // eslint-disable-line no-console
}
}
};
+30 -45
View File
@@ -1,30 +1,26 @@
import * as Utils from './utils';
import Exception from './exception';
import {COMPILER_REVISION, createFrame, LAST_COMPATIBLE_COMPILER_REVISION, REVISION_CHANGES} from './base';
import {moveHelperToHooks} from './helpers';
import { COMPILER_REVISION, REVISION_CHANGES, createFrame } from './base';
export function checkRevision(compilerInfo) {
const compilerRevision = compilerInfo && compilerInfo[0] || 1,
currentRevision = COMPILER_REVISION;
if (compilerRevision >= LAST_COMPATIBLE_COMPILER_REVISION && compilerRevision <= COMPILER_REVISION) {
return;
}
if (compilerRevision < LAST_COMPATIBLE_COMPILER_REVISION) {
const runtimeVersions = REVISION_CHANGES[currentRevision],
compilerVersions = REVISION_CHANGES[compilerRevision];
throw new Exception('Template was precompiled with an older version of Handlebars than the current runtime. ' +
'Please update your precompiler to a newer version (' + runtimeVersions + ') or downgrade your runtime to an older version (' + compilerVersions + ').');
} else {
// Use the embedded version info since the runtime doesn't know about this revision yet
throw new Exception('Template was precompiled with a newer version of Handlebars than the current runtime. ' +
'Please update your runtime to a newer version (' + compilerInfo[1] + ').');
if (compilerRevision !== currentRevision) {
if (compilerRevision < currentRevision) {
const runtimeVersions = REVISION_CHANGES[currentRevision],
compilerVersions = REVISION_CHANGES[compilerRevision];
throw new Exception('Template was precompiled with an older version of Handlebars than the current runtime. ' +
'Please update your precompiler to a newer version (' + runtimeVersions + ') or downgrade your runtime to an older version (' + compilerVersions + ').');
} else {
// Use the embedded version info since the runtime doesn't know about this revision yet
throw new Exception('Template was precompiled with a newer version of Handlebars than the current runtime. ' +
'Please update your runtime to a newer version (' + compilerInfo[1] + ').');
}
}
}
export function template(templateSpec, env) {
/* istanbul ignore next */
if (!env) {
throw new Exception('No environment passed to template');
@@ -36,12 +32,9 @@ export function template(templateSpec, env) {
templateSpec.main.decorator = templateSpec.main_d;
// Note: Using env.VM references rather than local var references throughout this section to allow
// for external users to override these as pseudo-supported APIs.
// for external users to override these as psuedo-supported APIs.
env.VM.checkRevision(templateSpec.compiler);
// backwards compatibility for precompiled templates with compiler-version 7 (<4.3.0)
const templateWasPrecompiledWithCompilerV7 = templateSpec.compiler && templateSpec.compiler[0] === 7;
function invokePartialWrapper(partial, context, options) {
if (options.hash) {
context = Utils.extend({}, context, options.hash);
@@ -49,15 +42,13 @@ export function template(templateSpec, env) {
options.ids[0] = true;
}
}
partial = env.VM.resolvePartial.call(this, partial, context, options);
let optionsWithHooks = Utils.extend({}, options, {hooks: this.hooks});
let result = env.VM.invokePartial.call(this, partial, context, optionsWithHooks);
let result = env.VM.invokePartial.call(this, partial, context, options);
if (result == null && env.compile) {
options.partials[options.name] = env.compile(partial, templateSpec.compilerOptions, env);
result = options.partials[options.name](context, optionsWithHooks);
result = options.partials[options.name](context, options);
}
if (result != null) {
if (options.indent) {
@@ -124,8 +115,15 @@ export function template(templateSpec, env) {
}
return value;
},
// An empty object to use as replacement for null-contexts
nullContext: Object.seal({}),
merge: function(param, common) {
let obj = param || common;
if (param && common && (param !== common)) {
obj = Utils.extend({}, common, param);
}
return obj;
},
noop: env.VM.noop,
compilerInfo: templateSpec.compiler
@@ -158,28 +156,19 @@ export function template(templateSpec, env) {
ret._setup = function(options) {
if (!options.partial) {
container.helpers = Utils.extend({}, env.helpers, options.helpers);
container.helpers = container.merge(options.helpers, env.helpers);
if (templateSpec.usePartial) {
container.partials = Utils.extend({}, env.partials, options.partials);
container.partials = container.merge(options.partials, env.partials);
}
if (templateSpec.usePartial || templateSpec.useDecorators) {
container.decorators = Utils.extend({}, env.decorators, options.decorators);
container.decorators = container.merge(options.decorators, env.decorators);
}
container.hooks = {};
let keepHelperInHelpers = options.allowCallsToHelperMissing || templateWasPrecompiledWithCompilerV7;
moveHelperToHooks(container, 'helperMissing', keepHelperInHelpers);
moveHelperToHooks(container, 'blockHelperMissing', keepHelperInHelpers);
} else {
container.helpers = options.helpers;
container.partials = options.partials;
container.decorators = options.decorators;
container.hooks = options.hooks;
}
};
ret._child = function(i, data, blockParams, depths) {
@@ -198,7 +187,7 @@ export function template(templateSpec, env) {
export function wrapProgram(container, i, fn, data, declaredBlockParams, blockParams, depths) {
function prog(context, options = {}) {
let currentDepths = depths;
if (depths && context != depths[0] && !(context === container.nullContext && depths[0] === null)) {
if (depths && context != depths[0]) {
currentDepths = [context].concat(depths);
}
@@ -218,9 +207,6 @@ export function wrapProgram(container, i, fn, data, declaredBlockParams, blockPa
return prog;
}
/**
* This is currently part of the official API, therefore implementation details should not be changed.
*/
export function resolvePartial(partial, context, options) {
if (!partial) {
if (options.name === '@partial-block') {
@@ -249,8 +235,7 @@ export function invokePartial(partial, context, options) {
options.data = createFrame(options.data);
// Wrapper function to get access to currentPartialBlock from the closure
let fn = options.fn;
partialBlock = options.data['partial-block'] = function partialBlockWrapper(context, options = {}) {
partialBlock = options.data['partial-block'] = function partialBlockWrapper(context, options) {
// Restore the partial-block from the closure for the execution of the block
// i.e. the part inside the block of the partial call.
options.data = createFrame(options.data);
-1
View File
@@ -1,4 +1,3 @@
const escape = {
'&': '&amp;',
'<': '&lt;',
+13 -35
View File
@@ -1,10 +1,10 @@
/* eslint-disable no-console */
import Async from 'neo-async';
import Async from 'async';
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.loadTemplates = function(opts, callback) {
loadStrings(opts, function(err, strings) {
@@ -60,7 +60,7 @@ function loadStrings(opts, callback) {
function loadFiles(opts, callback) {
// Build file extension pattern
let extension = (opts.extension || 'handlebars').replace(/[\\^$*+?.():=!|{}\-[\]]/g, function(arg) { return '\\' + arg; });
let extension = (opts.extension || 'handlebars').replace(/[\\^$*+?.():=!|{}\-\[\]]/g, function(arg) { return '\\' + arg; });
extension = new RegExp('\\.' + extension + '$');
let ret = [],
@@ -235,6 +235,7 @@ module.exports.cli = function(opts) {
}
}
if (opts.map) {
output.add('\n//# sourceMappingURL=' + opts.map + '\n');
}
@@ -243,7 +244,15 @@ module.exports.cli = function(opts) {
output.map = output.map + '';
if (opts.min) {
output = minify(output, opts.map);
output = uglify.minify(output.code, {
fromString: true,
outSourceMap: opts.map,
inSourceMap: JSON.parse(output.map)
});
if (opts.map) {
output.code += '\n//# sourceMappingURL=' + opts.map + '\n';
}
}
if (opts.map) {
@@ -265,34 +274,3 @@ function arrayCast(value) {
}
return value;
}
/**
* Run uglify to minify the compiled template, if uglify exists in the dependencies.
*
* We are using `require` instead of `import` here, because es6-modules do not allow
* dynamic imports and uglify-js is an optional dependency. Since we are inside NodeJS here, this
* should not be a problem.
*
* @param {string} output the compiled template
* @param {string} sourceMapFile the file to write the source map to.
*/
function minify(output, sourceMapFile) {
try {
// Try to resolve uglify-js in order to see if it does exist
require.resolve('uglify-js');
} catch (e) {
if (e.code !== 'MODULE_NOT_FOUND') {
// Something else seems to be wrong
throw e;
}
// it does not exist!
console.error('Code minimization is disabled due to missing uglify-js dependency');
return output;
}
return require('uglify-js').minify(output.code, {
sourceMap: {
content: output.map,
url: sourceMapFile
}
});
}
-8705
View File
File diff suppressed because it is too large Load Diff
+17 -37
View File
@@ -1,7 +1,7 @@
{
"name": "handlebars",
"barename": "handlebars",
"version": "4.3.4",
"version": "4.0.6",
"description": "Handlebars provides the power necessary to let you build semantic templates effectively with no frustration",
"homepage": "http://www.handlebarsjs.com/",
"keywords": [
@@ -21,57 +21,48 @@
"node": ">=0.4.7"
},
"dependencies": {
"neo-async": "^2.6.0",
"async": "^1.4.0",
"optimist": "^0.6.1",
"source-map": "^0.6.1"
"source-map": "^0.4.4"
},
"optionalDependencies": {
"uglify-js": "^3.1.4"
"uglify-js": "^2.6"
},
"devDependencies": {
"aws-sdk": "^2.1.49",
"babel-loader": "^5.0.0",
"babel-runtime": "^5.1.10",
"benchmark": "~1.0",
"dtslint": "^0.5.5",
"dustjs-linkedin": "^2.0.2",
"eco": "~1.1.0-rc-3",
"grunt": "^1.0.3",
"grunt": "~0.4.1",
"grunt-babel": "^5.0.0",
"grunt-bg-shell": "^2.3.3",
"grunt-cli": "^1",
"grunt-contrib-clean": "^1",
"grunt-contrib-concat": "^1",
"grunt-contrib-connect": "^1",
"grunt-contrib-copy": "^1",
"grunt-contrib-requirejs": "^1",
"grunt-contrib-uglify": "^1",
"grunt-contrib-watch": "^1.1.0",
"grunt-eslint": "^20.1.0",
"grunt-saucelabs": "github:nknapp/grunt-saucelabs",
"grunt-cli": "~0.1.10",
"grunt-contrib-clean": "0.x",
"grunt-contrib-concat": "0.x",
"grunt-contrib-connect": "0.x",
"grunt-contrib-copy": "0.x",
"grunt-contrib-requirejs": "0.x",
"grunt-contrib-uglify": "0.x",
"grunt-contrib-watch": "0.x",
"grunt-eslint": "^17.1.0",
"grunt-saucelabs": "8.x",
"grunt-webpack": "^1.0.8",
"istanbul": "^0.3.0",
"jison": "~0.3.0",
"mocha": "^5",
"mocha": "~1.20.0",
"mock-stdin": "^0.3.0",
"mustache": "^2.1.3",
"semver": "^5.0.1",
"typescript": "^3.4.3",
"underscore": "^1.5.1",
"webpack": "^1.12.6",
"webpack-dev-server": "^1.12.1"
},
"main": "lib/index.js",
"types": "types/index.d.ts",
"browser": {
".": "./dist/cjs/handlebars.js",
"./runtime": "./dist/cjs/handlebars.runtime.js"
},
"bin": {
"handlebars": "bin/handlebars"
},
"scripts": {
"checkTypes": "dtslint types",
"test": "grunt"
},
"jspm": {
@@ -82,16 +73,5 @@
"buildConfig": {
"minify": true
}
},
"files": [
"bin",
"dist/*.js",
"dist/amd/**/*.js",
"dist/cjs/**/*.js",
"lib",
"print-script",
"release-notes.md",
"runtime.js",
"types/*.d.ts"
]
}
}
+127 -390
View File
@@ -2,270 +2,7 @@
## Development
[Commits](https://github.com/wycats/handlebars.js/compare/v4.3.4...master)
## v4.3.4 - September 28th, 2019
- fix: harden "propertyIsEnumerable"-check - ff4d827
Compatibility notes:
- No incompatibilities are known.
[Commits](https://github.com/wycats/handlebars.js/compare/v4.3.3...v4.3.4)
## v4.3.3 - September 27th, 2019
- fix test case for browsers that do not support __defineGetter__ - 8742bde
[Commits](https://github.com/wycats/handlebars.js/compare/v4.3.2...v4.3.3)
## v4.3.2 - September 26th, 2019
- Use Object.prototype.propertyIsEnumerable to check for constructors - 213c0bb, #1563
Compatibility notes:
- There are no breaking changes
[Commits](https://github.com/wycats/handlebars.js/compare/v4.3.1...v4.3.2)
## v4.3.1 - September 25th, 2019
Fixes:
- do not break on precompiled templates from Handlebars >=4.0.0 <4.3.0 - 1266838, #1561
- Ensure allowCallsToHelperMissing runtime option is optional in typings - 93444c5, 64ecb9e, #1560
[Commits](https://github.com/wycats/handlebars.js/compare/v4.3.0...v4.3.1)
## v4.3.0 - September 24th, 2019
Fixes:
- Security: Disallow calling "helperMissing" and "blockHelperMissing" directly - 2078c72
- Disallow calling "helperMissing" and "blockHelperMissing" directly - 2078c72
Features:
- Add new runtime option `allowCallsToHelperMissing` to allow calling `blockHelperMissing` and `helperMissing`.
Breaking changes:
Compatibility notes:
- Compiler revision increased - 06b7224
- This means that template compiled with versions prior to 4.3.0 will not work with runtimes >= 4.3.0
The increase was done because the "helperMissing" and "blockHelperMissing" are now moved from the helpers
to the internal "container.hooks" object, so old templates will not be able to call them anymore. We suggest
that you always recompile your templates with the latest compiler in your build pipelines.
- Disallow calling "helperMissing" and "blockHelperMissing" directly - 2078c72
- Calling "helperMissing" and "blockHelperMissing" directly from a template (like in `{{blockHelperMissing}}` was
never intended and was part of the exploits that have been revealed early in 2019
(see https://github.com/wycats/handlebars.js/issues/1495). *It is also part of a new exploit that
is not captured by the earlier fix.* In order to harden Handlebars against such exploits, calling thos helpers
is now not possible anymore. *Overriding* those helpers is still possible.
- If you really need this behavior, you can set the runtime option `allowCallsToHelperMissing` to `true` and the
calls will again be possible
Both bullet points imly that Handlebars is not 100% percent compatible to 4.2.0, despite the minor version bump.
We consider it more important to resolve a major security issue than to maintain 100% compatibility.
[Commits](https://github.com/wycats/handlebars.js/compare/v4.2.1...v4.3.0)
## v4.2.1 - September 20th, 2019
Bugfixes:
- The "browser" property in the package.json has been updated to use the common-js builds instead of the minified UMD - c55a7be, #1553
Compatibility notes:
- No compatibility issues should arise
[Commits](https://github.com/wycats/handlebars.js/compare/v4.2.0...v4.2.1)
## v4.2.0 - September 3rd, 2019
Chore/Test:
- Use custom `grunt-saucelab` with current sauce-connect proxy - f119497
- Add framework for various integration tests - f9cce4d
- Add integration test for webpack - a57b682
Bugfixes:
- [#1544](https://github.com/wycats/handlebars.js/issues/1544) - Typescript types: `knownHelpers` doesnt allow for custom helpers ([@NickCis](https://api.github.com/users/NickCis))
- [#1534](https://github.com/wycats/handlebars.js/pull/1534) - Add typings for "Handlebars.VM.resolvePartial ([@AndrewLeedham](https://api.github.com/users/AndrewLeedham))
Features:
- [#1540](https://github.com/wycats/handlebars.js/pull/1540) - added "browser"-property to package.json, resolves #1102 ([@ouijan](https://api.github.com/users/ouijan))
Compatibility notes:
- The new "browser"-property should not break anything, but you can never be sure. The integration test for webpack
shows that it works, but if it doesn't please open an issue.
[Commits](https://github.com/wycats/handlebars.js/compare/v4.1.2-0...v4.2.0)
## v4.1.2-0 - August 25th, 2019
[#1540](https://github.com/wycats/handlebars.js/pull/1540) - added browser to package.json, resolves #1102 ([@ouijan](https://api.github.com/users/ouijan))
Compatibility notes:
- We are not sure if imports via webpack are still working, which is why this release is a pre-release
[Commits](https://github.com/wycats/handlebars.js/compare/v4.1.2...v4.1.2-0)
## v4.1.2 - April 13th, 2019
Chore/Test:
- [#1515](https://github.com/wycats/handlebars.js/pull/1515) - Port over linting and test for typings ([@zimmi88](https://api.github.com/users/zimmi88))
- chore: add missing typescript dependency, add package-lock.json - 594f1e3
- test: remove safari from saucelabs - 871accc
Bugfixes:
- fix: prevent RCE through the "lookup"-helper - cd38583
Compatibility notes:
Access to the constructor of a class thought `{{lookup obj "constructor" }}` is now prohibited. This closes
a leak that only half closed in versions 4.0.13 and 4.1.0, but it is a slight incompatibility.
This kind of access is not the intended use of Handlebars and leads to the vulnerability described
in #1495. We will **not** increase the major version, because such use is not intended or documented,
and because of the potential impact of the issue (we fear that most people won't use a new major version
and the issue may not be resolved on many systems).
[Commits](https://github.com/wycats/handlebars.js/compare/v4.1.1...v4.1.2)
## v4.1.1 - March 16th, 2019
Bugfixes:
- fix: add "runtime.d.ts" to allow "require('handlebars/runtime')" in TypeScript - 5cedd62
Refactorings:
- replace "async" with "neo-async" - 048f2ce
- use "substring"-function instead of "substr" - 445ae12
Compatibility notes:
- This is a bugfix release. There are no breaking change and no new features.
[Commits](https://github.com/wycats/handlebars.js/compare/v4.1.0...v4.1.1)
## v4.1.0 - February 7th, 2019
New Features
- import TypeScript typings - 27ac1ee
Security fixes:
- disallow access to the constructor in templates to prevent RCE - 42841c4, #1495
Housekeeping
- chore: fix components/handlebars package.json and auto-update on release - bacd473
- chore: Use node 10 to build handlebars - 78dd89c
- chore/doc: Add more release docs - 6b87c21
Compatibility notes:
Access to class constructors (i.e. `({}).constructor`) is now prohibited to prevent
Remote Code Execution. This means that following construct will no work anymore:
```
class SomeClass {
}
SomeClass.staticProperty = 'static'
var template = Handlebars.compile('{{constructor.staticProperty}}');
document.getElementById('output').innerHTML = template(new SomeClass());
// expected: 'static', but now this is empty.
```
This kind of access is not the intended use of Handlebars and leads to the vulnerability described in #1495. We will **not** increase the major version, because such use is not intended or documented, and because of the potential impact of the issue (we fear that most people won't use a new major version and the issue may not be resolved on many systems).
[Commits](https://github.com/wycats/handlebars.js/compare/v4.0.12...v4.1.0)
## v4.0.12 - September 4th, 2018
New features:
- none
Various dependency updates
- [#1464](https://github.com/wycats/handlebars.js/pull/1464) - Bump versions of grunt-plugins to 1.x
- [#1398](https://github.com/wycats/handlebars.js/pull/1398) - Chore: updated various dev dependencies
- upgrade uglify-js - d3d3942
- Update grunt-eslint to 20.1.0 - 7729aa9
- Update dependencies "async" to 2.5.0 and "source-map" to 0.6.1 (73d5637)
Bugfixes:
- [components/handlebars.js#24](https://github.com/components/handlebars.js#24) Add package.json to components shim
- Updated `source-map`-package should work better with `rollup`[#1463](https://github.com/wycats/handlebars.js/issues/1463)
Removed obsolete code:
- unnecessary check - 0ddff8b
- Use `files` field - 69c6ca5
- Update jsfiddle to 4.0.11 - 8947dd0
Compatibility notes:
- No compatibility issues are to be expected
[Commits](https://github.com/wycats/handlebars.js/compare/v4.0.11...v4.0.12)
## v4.0.11 - October 17th, 2017
- [#1391](https://github.com/wycats/handlebars.js/issues/1391) - `uglify-js` is unconditionally imported, but only listed as optional dependency ([@Turbo87](https://github.com/Turbo87))
- [#1233](https://github.com/wycats/handlebars.js/issues/1233) - Unable to build under windows - error at test:bin task ([@blikblum](https://github.com/blikblum))
- Update (C) year in the LICENSE file - 21386b6
Compatibility notes:
- This is a bugfix release. There are no breaking change and no new features.
[Commits](https://github.com/wycats/handlebars.js/compare/v4.0.10...v4.0.11)
## v4.0.10 - May 21st, 2017
- Fix regression in 4.0.9: Replace "Object.assign" (not support in IE) by "util/extend" - 0e953d1
[Commits](https://github.com/wycats/handlebars.js/compare/v4.0.9...v4.0.10)
## v4.0.9 - May 21st, 2017
- [#1327](https://github.com/wycats/handlebars.js/issues/1327) Handlebars.compile() does not modify "options" anymore
- pending [#1331](https://github.com/wycats/handlebars.js/issues/1331) Attempts to build Handlebars in a Windows environment
- Fix build in windows - cc554a5
- Ensure LF line-edings in handlebars-template fixtures (*.hbs) - ed879a6
- Run integration test with `node handlebars -a ...` on Windows - 2e21e2b
- Ensure LF line-edings in lexer-files (*.l) - bdfdbea
- Force LF line-endings for spec/artifacts - b50ef03
- Use istanbul/lib/cli.js instead of node_modules/.bin/istanbul - 6e6269f
- TravisCI: Publish valid semver tags independently of the branch - 7378f85
Compatibility notes:
- No compatibility issues are expected.
[Commits](https://github.com/wycats/handlebars.js/compare/v4.0.8...v4.0.9)
## v4.0.8 - May 2nd, 2017
- [#1341](https://github.com/wycats/handlebars.js/issues/1341) [#1342](https://github.com/wycats/handlebars.js/issues/1342) Allow partial-blocks to be executed without "options" ([@nknapp](https://github.com/nknapp)) - a00c598
Compatibility notes:
- No breaking changes
[Commits](https://github.com/wycats/handlebars.js/compare/v4.0.7...v4.0.8)
## v4.0.7 - April 29th, 2017
- [#1319](https://github.com/wycats/handlebars.js/issues/1319): Fix context-stack when calling block-helpers on null values ([@nknapp](https://github.com/nknapp)) - c8f4b57
- [#1315](https://github.com/wycats/handlebars.js/pull/1315) Parser: Change suffix to use ES6 default module export ([@Turbo87](https://github.com/Turbo87))- b617375
- [#1290](https://github.com/wycats/handlebars.js/pull/1290) [#1252](https://github.com/wycats/handlebars.js/issue/1290) Add more tests for partial-blocks and inline partials ([@nknapp](https://github.com/nknapp)) - 63a8e0c
- [#1252](https://github.com/wycats/handlebars.js/issue/1290) Using @partial-block twice in a template not possible ([@nknapp](https://github.com/nknapp)) - 5a164d0
- [#1310](https://github.com/wycats/handlebars.js/pull/1310) Avoid duplicate "sourceMappingURL=" lines. ([@joonas-lahtinen](https://github.com/joonas-lahtinen)) - 01b0f65
- [#1275](https://github.com/wycats/handlebars.js/pull/1275) require('sys') is deprecated, using 'util' instead ([@travnels](https://github.com/travnels)) - 406f2ee
- [#1285](https://github.com/wycats/handlebars.js/pull/1285) [#1284](https://github.com/wycats/handlebars.js/issues/1284) Make "column"-property of Errors enumerable ([@nknapp](https://github.com/nknapp)) - a023cb4
- [#1285](https://github.com/wycats/handlebars.js/pull/1285) Testcase to verify that compile-errors have a column-property ([@nknapp](https://github.com/nknapp)) - c7dc353
[Commits](https://github.com/lawnsea/handlebars.js/compare/v4.0.6...v4.0.7)
[Commits](https://github.com/lawnsea/handlebars.js/compare/v4.0.6...master)
## v4.0.6 - November 12th, 2016
- [#1243](https://github.com/wycats/handlebars.js/pull/1243) - Walk up data frames for nested @partial-block ([@lawnsea](https://github.com/lawnsea))
@@ -289,8 +26,8 @@ Compatibility notes:
[Commits](https://github.com/wycats/handlebars.js/compare/v4.0.5...v4.0.6)
## v4.0.5 - November 19th, 2015
- [#1132](https://github.com/wycats/handlebars.js/pull/1132) - Update uglify-js to avoid vulnerability ([@plynchnlm](https://github.com/plynchnlm))
- [#1129](https://github.com/wycats/handlebars.js/issues/1129) - Minified lib returns an empty string ([@bricss](https://github.com/bricss))
- [#1132](https://github.com/wycats/handlebars.js/pull/1132) - Update uglify-js to avoid vulnerability ([@plynchnlm](https://api.github.com/users/plynchnlm))
- [#1129](https://github.com/wycats/handlebars.js/issues/1129) - Minified lib returns an empty string ([@bricss](https://api.github.com/users/bricss))
- Return current handlebars instance from noConflict - 685cf92
- Add webpack to dev dependency to support npm 3 - 7a6c228
- Further relax uglify dependency - 0a3b3c2
@@ -301,17 +38,17 @@ Compatibility notes:
[Commits](https://github.com/wycats/handlebars.js/compare/v4.0.4...v4.0.5)
## v4.0.4 - October 29th, 2015
- [#1121](https://github.com/wycats/handlebars.js/pull/1121) - Include partial name in 'undefined partial' exception message ([@shinypb](https://github.com/shinypb))
- [#1125](https://github.com/wycats/handlebars.js/pull/1125) - Add promised-handlebars to "in-the-wild"-list ([@nknapp](https://github.com/nknapp))
- [#1121](https://github.com/wycats/handlebars.js/pull/1121) - Include partial name in 'undefined partial' exception message ([@shinypb](https://api.github.com/users/shinypb))
- [#1125](https://github.com/wycats/handlebars.js/pull/1125) - Add promised-handlebars to "in-the-wild"-list ([@nknapp](https://api.github.com/users/nknapp))
[Commits](https://github.com/wycats/handlebars.js/compare/v4.0.3...v4.0.4)
## v4.0.3 - September 23rd, 2015
- [#1099](https://github.com/wycats/handlebars.js/issues/1099) - @partial-block is overridden ([@btmorex](https://github.com/btmorex))
- [#1093](https://github.com/wycats/handlebars.js/issues/1093) - #each skips iteration on undefined values ([@florianpilz](https://github.com/florianpilz))
- [#1092](https://github.com/wycats/handlebars.js/issues/1092) - Square braces in key name ([@distantnative](https://github.com/distantnative))
- [#1091](https://github.com/wycats/handlebars.js/pull/1091) - fix typo in release notes ([@nikolas](https://github.com/nikolas))
- [#1090](https://github.com/wycats/handlebars.js/pull/1090) - grammar fixes in 4.0.0 release notes ([@nikolas](https://github.com/nikolas))
- [#1099](https://github.com/wycats/handlebars.js/issues/1099) - @partial-block is overridden ([@btmorex](https://api.github.com/users/btmorex))
- [#1093](https://github.com/wycats/handlebars.js/issues/1093) - #each skips iteration on undefined values ([@florianpilz](https://api.github.com/users/florianpilz))
- [#1092](https://github.com/wycats/handlebars.js/issues/1092) - Square braces in key name ([@distantnative](https://api.github.com/users/distantnative))
- [#1091](https://github.com/wycats/handlebars.js/pull/1091) - fix typo in release notes ([@nikolas](https://api.github.com/users/nikolas))
- [#1090](https://github.com/wycats/handlebars.js/pull/1090) - grammar fixes in 4.0.0 release notes ([@nikolas](https://api.github.com/users/nikolas))
Compatibility notes:
- `each` iteration with `undefined` values has been restored to the 3.0 behaviors. Helper calls with undefined context values will now execute against an arbitrary empty object to avoid executing against global object in non-strict mode.
@@ -320,7 +57,7 @@ Compatibility notes:
[Commits](https://github.com/wycats/handlebars.js/compare/v4.0.2...v4.0.3)
## v4.0.2 - September 4th, 2015
- [#1089](https://github.com/wycats/handlebars.js/issues/1089) - "Failover content" not working in multiple levels of inline partials ([@michaellopez](https://github.com/michaellopez))
- [#1089](https://github.com/wycats/handlebars.js/issues/1089) - "Failover content" not working in multiple levels of inline partials ([@michaellopez](https://api.github.com/users/michaellopez))
[Commits](https://github.com/wycats/handlebars.js/compare/v4.0.1...v4.0.2)
@@ -330,17 +67,17 @@ Compatibility notes:
[Commits](https://github.com/wycats/handlebars.js/compare/v4.0.0...v4.0.1)
## v4.0.0 - September 1st, 2015
- [#1082](https://github.com/wycats/handlebars.js/pull/1082) - Decorators and Inline Partials ([@kpdecker](https://github.com/kpdecker))
- [#1076](https://github.com/wycats/handlebars.js/pull/1076) - Implement partial blocks ([@kpdecker](https://github.com/kpdecker))
- [#1087](https://github.com/wycats/handlebars.js/pull/1087) - Fix #each when last object entry has empty key ([@denniskuczynski](https://github.com/denniskuczynski))
- [#1084](https://github.com/wycats/handlebars.js/pull/1084) - Bump uglify version to fix vulnerability ([@John-Steidley](https://github.com/John-Steidley))
- [#1068](https://github.com/wycats/handlebars.js/pull/1068) - Fix typo ([@0xack13](https://github.com/0xack13))
- [#1060](https://github.com/wycats/handlebars.js/pull/1060) - #1056 Fixed grammar for nested raw blocks ([@ericbn](https://github.com/ericbn))
- [#1052](https://github.com/wycats/handlebars.js/pull/1052) - Updated year in License ([@maqnouch](https://github.com/maqnouch))
- [#1037](https://github.com/wycats/handlebars.js/pull/1037) - Fix minor typos in README ([@tomxtobin](https://github.com/tomxtobin))
- [#1032](https://github.com/wycats/handlebars.js/issues/1032) - Is it possible to render a partial without the parent scope? ([@aputinski](https://github.com/aputinski))
- [#1019](https://github.com/wycats/handlebars.js/pull/1019) - Fixes typo in tests ([@aymerick](https://github.com/aymerick))
- [#1016](https://github.com/wycats/handlebars.js/issues/1016) - Version mis-match ([@mayankdedhia](https://github.com/mayankdedhia))
- [#1082](https://github.com/wycats/handlebars.js/pull/1082) - Decorators and Inline Partials ([@kpdecker](https://api.github.com/users/kpdecker))
- [#1076](https://github.com/wycats/handlebars.js/pull/1076) - Implement partial blocks ([@kpdecker](https://api.github.com/users/kpdecker))
- [#1087](https://github.com/wycats/handlebars.js/pull/1087) - Fix #each when last object entry has empty key ([@denniskuczynski](https://api.github.com/users/denniskuczynski))
- [#1084](https://github.com/wycats/handlebars.js/pull/1084) - Bump uglify version to fix vulnerability ([@John-Steidley](https://api.github.com/users/John-Steidley))
- [#1068](https://github.com/wycats/handlebars.js/pull/1068) - Fix typo ([@0xack13](https://api.github.com/users/0xack13))
- [#1060](https://github.com/wycats/handlebars.js/pull/1060) - #1056 Fixed grammar for nested raw blocks ([@ericbn](https://api.github.com/users/ericbn))
- [#1052](https://github.com/wycats/handlebars.js/pull/1052) - Updated year in License ([@maqnouch](https://api.github.com/users/maqnouch))
- [#1037](https://github.com/wycats/handlebars.js/pull/1037) - Fix minor typos in README ([@tomxtobin](https://api.github.com/users/tomxtobin))
- [#1032](https://github.com/wycats/handlebars.js/issues/1032) - Is it possible to render a partial without the parent scope? ([@aputinski](https://api.github.com/users/aputinski))
- [#1019](https://github.com/wycats/handlebars.js/pull/1019) - Fixes typo in tests ([@aymerick](https://api.github.com/users/aymerick))
- [#1016](https://github.com/wycats/handlebars.js/issues/1016) - Version mis-match ([@mayankdedhia](https://api.github.com/users/mayankdedhia))
- [#1023](https://github.com/wycats/handlebars.js/issues/1023) - is it possible for nested custom helpers to communicate between each other?
- [#893](https://github.com/wycats/handlebars.js/issues/893) - [Proposal] Section blocks.
- [#792](https://github.com/wycats/handlebars.js/issues/792) - feature request: inline partial definitions
@@ -373,55 +110,55 @@ Compatibility notes:
[Commits](https://github.com/wycats/handlebars.js/compare/v3.0.3...v4.0.0)
## v3.0.3 - April 28th, 2015
- [#1004](https://github.com/wycats/handlebars.js/issues/1004) - Latest version breaks with RequireJS (global is undefined) ([@boskee](https://github.com/boskee))
- [#1004](https://github.com/wycats/handlebars.js/issues/1004) - Latest version breaks with RequireJS (global is undefined) ([@boskee](https://api.github.com/users/boskee))
[Commits](https://github.com/wycats/handlebars.js/compare/v3.0.2...v3.0.3)
## v3.0.2 - April 20th, 2015
- [#998](https://github.com/wycats/handlebars.js/pull/998) - Add full support for es6 ([@kpdecker](https://github.com/kpdecker))
- [#994](https://github.com/wycats/handlebars.js/issues/994) - Access Handlebars.Visitor in browser ([@tamlyn](https://github.com/tamlyn))
- [#990](https://github.com/wycats/handlebars.js/issues/990) - Allow passing null/undefined literals subexpressions ([@blimmer](https://github.com/blimmer))
- [#989](https://github.com/wycats/handlebars.js/issues/989) - Source-map error with requirejs ([@SteppeEagle](https://github.com/SteppeEagle))
- [#967](https://github.com/wycats/handlebars.js/issues/967) - can't access "this" property ([@75lb](https://github.com/75lb))
- [#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://github.com/johneke))
- [#973](https://github.com/wycats/handlebars.js/issues/973) - version 3 is slower than version 2 ([@elover](https://github.com/elover))
- [#966](https://github.com/wycats/handlebars.js/issues/966) - "handlebars --version" does not work with v3.0.0 ([@abloomston](https://github.com/abloomston))
- [#964](https://github.com/wycats/handlebars.js/pull/964) - default is a reserved word ([@grassick](https://github.com/grassick))
- [#962](https://github.com/wycats/handlebars.js/pull/962) - Add dashbars' link on README. ([@pismute](https://github.com/pismute))
- [#984](https://github.com/wycats/handlebars.js/pull/984) - Adding documentation for passing arguments into partials ([@johneke](https://api.github.com/users/johneke))
- [#973](https://github.com/wycats/handlebars.js/issues/973) - version 3 is slower than version 2 ([@elover](https://api.github.com/users/elover))
- [#966](https://github.com/wycats/handlebars.js/issues/966) - "handlebars --version" does not work with v3.0.0 ([@abloomston](https://api.github.com/users/abloomston))
- [#964](https://github.com/wycats/handlebars.js/pull/964) - default is a reserved word ([@grassick](https://api.github.com/users/grassick))
- [#962](https://github.com/wycats/handlebars.js/pull/962) - Add dashbars' link on README. ([@pismute](https://api.github.com/users/pismute))
[Commits](https://github.com/wycats/handlebars.js/compare/v3.0.0...v3.0.1)
## v3.0.0 - February 10th, 2015
- [#941](https://github.com/wycats/handlebars.js/pull/941) - Add support for dynamic partial names ([@kpdecker](https://github.com/kpdecker))
- [#940](https://github.com/wycats/handlebars.js/pull/940) - Add missing reserved words so compiler knows to use array syntax: ([@mattflaschen](https://github.com/mattflaschen))
- [#938](https://github.com/wycats/handlebars.js/pull/938) - Fix example using #with helper ([@diwo](https://github.com/diwo))
- [#930](https://github.com/wycats/handlebars.js/pull/930) - Add parent tracking and mutation to AST visitors ([@kpdecker](https://github.com/kpdecker))
- [#926](https://github.com/wycats/handlebars.js/issues/926) - Depthed lookups fail when program duplicator runs ([@kpdecker](https://github.com/kpdecker))
- [#918](https://github.com/wycats/handlebars.js/pull/918) - Add instructions for 'spec/mustache' to CONTRIBUTING.md, fix a few typos ([@oneeman](https://github.com/oneeman))
- [#915](https://github.com/wycats/handlebars.js/pull/915) - Ast update ([@kpdecker](https://github.com/kpdecker))
- [#910](https://github.com/wycats/handlebars.js/issues/910) - Different behavior of {{@last}} when {{#each}} in {{#each}} ([@zordius](https://github.com/zordius))
- [#907](https://github.com/wycats/handlebars.js/issues/907) - Implement named helper variable references ([@kpdecker](https://github.com/kpdecker))
- [#906](https://github.com/wycats/handlebars.js/pull/906) - Add parser support for block params ([@mmun](https://github.com/mmun))
- [#903](https://github.com/wycats/handlebars.js/issues/903) - Only provide aliases for multiple use calls ([@kpdecker](https://github.com/kpdecker))
- [#902](https://github.com/wycats/handlebars.js/pull/902) - Generate Source Maps ([@kpdecker](https://github.com/kpdecker))
- [#901](https://github.com/wycats/handlebars.js/issues/901) - Still escapes with noEscape enabled on isolated Handlebars environment ([@zedknight](https://github.com/zedknight))
- [#896](https://github.com/wycats/handlebars.js/pull/896) - Simplify BlockNode by removing intermediate MustacheNode ([@mmun](https://github.com/mmun))
- [#892](https://github.com/wycats/handlebars.js/pull/892) - Implement parser for else chaining of helpers ([@kpdecker](https://github.com/kpdecker))
- [#889](https://github.com/wycats/handlebars.js/issues/889) - Consider extensible parser API ([@kpdecker](https://github.com/kpdecker))
- [#887](https://github.com/wycats/handlebars.js/issues/887) - Handlebars.noConflict() option? ([@bradvogel](https://github.com/bradvogel))
- [#886](https://github.com/wycats/handlebars.js/issues/886) - Add SafeString to context (or use duck-typing) ([@dominicbarnes](https://github.com/dominicbarnes))
- [#870](https://github.com/wycats/handlebars.js/pull/870) - Registering undefined partial throws exception. ([@max-b](https://github.com/max-b))
- [#866](https://github.com/wycats/handlebars.js/issues/866) - comments don't respect whitespace control ([@75lb](https://github.com/75lb))
- [#863](https://github.com/wycats/handlebars.js/pull/863) - + jsDelivr CDN info ([@tomByrer](https://github.com/tomByrer))
- [#858](https://github.com/wycats/handlebars.js/issues/858) - Disable new default auto-indent at included partials ([@majodev](https://github.com/majodev))
- [#856](https://github.com/wycats/handlebars.js/pull/856) - jspm compatibility ([@MajorBreakfast](https://github.com/MajorBreakfast))
- [#805](https://github.com/wycats/handlebars.js/issues/805) - Request: "strict" lookups ([@nzakas](https://github.com/nzakas))
- [#941](https://github.com/wycats/handlebars.js/pull/941) - Add support for dynamic partial names ([@kpdecker](https://api.github.com/users/kpdecker))
- [#940](https://github.com/wycats/handlebars.js/pull/940) - Add missing reserved words so compiler knows to use array syntax: ([@mattflaschen](https://api.github.com/users/mattflaschen))
- [#938](https://github.com/wycats/handlebars.js/pull/938) - Fix example using #with helper ([@diwo](https://api.github.com/users/diwo))
- [#930](https://github.com/wycats/handlebars.js/pull/930) - Add parent tracking and mutation to AST visitors ([@kpdecker](https://api.github.com/users/kpdecker))
- [#926](https://github.com/wycats/handlebars.js/issues/926) - Depthed lookups fail when program duplicator runs ([@kpdecker](https://api.github.com/users/kpdecker))
- [#918](https://github.com/wycats/handlebars.js/pull/918) - Add instructions for 'spec/mustache' to CONTRIBUTING.md, fix a few typos ([@oneeman](https://api.github.com/users/oneeman))
- [#915](https://github.com/wycats/handlebars.js/pull/915) - Ast update ([@kpdecker](https://api.github.com/users/kpdecker))
- [#910](https://github.com/wycats/handlebars.js/issues/910) - Different behavior of {{@last}} when {{#each}} in {{#each}} ([@zordius](https://api.github.com/users/zordius))
- [#907](https://github.com/wycats/handlebars.js/issues/907) - Implement named helper variable references ([@kpdecker](https://api.github.com/users/kpdecker))
- [#906](https://github.com/wycats/handlebars.js/pull/906) - Add parser support for block params ([@mmun](https://api.github.com/users/mmun))
- [#903](https://github.com/wycats/handlebars.js/issues/903) - Only provide aliases for multiple use calls ([@kpdecker](https://api.github.com/users/kpdecker))
- [#902](https://github.com/wycats/handlebars.js/pull/902) - Generate Source Maps ([@kpdecker](https://api.github.com/users/kpdecker))
- [#901](https://github.com/wycats/handlebars.js/issues/901) - Still escapes with noEscape enabled on isolated Handlebars environment ([@zedknight](https://api.github.com/users/zedknight))
- [#896](https://github.com/wycats/handlebars.js/pull/896) - Simplify BlockNode by removing intermediate MustacheNode ([@mmun](https://api.github.com/users/mmun))
- [#892](https://github.com/wycats/handlebars.js/pull/892) - Implement parser for else chaining of helpers ([@kpdecker](https://api.github.com/users/kpdecker))
- [#889](https://github.com/wycats/handlebars.js/issues/889) - Consider extensible parser API ([@kpdecker](https://api.github.com/users/kpdecker))
- [#887](https://github.com/wycats/handlebars.js/issues/887) - Handlebars.noConflict() option? ([@bradvogel](https://api.github.com/users/bradvogel))
- [#886](https://github.com/wycats/handlebars.js/issues/886) - Add SafeString to context (or use duck-typing) ([@dominicbarnes](https://api.github.com/users/dominicbarnes))
- [#870](https://github.com/wycats/handlebars.js/pull/870) - Registering undefined partial throws exception. ([@max-b](https://api.github.com/users/max-b))
- [#866](https://github.com/wycats/handlebars.js/issues/866) - comments don't respect whitespace control ([@75lb](https://api.github.com/users/75lb))
- [#863](https://github.com/wycats/handlebars.js/pull/863) - + jsDelivr CDN info ([@tomByrer](https://api.github.com/users/tomByrer))
- [#858](https://github.com/wycats/handlebars.js/issues/858) - Disable new default auto-indent at included partials ([@majodev](https://api.github.com/users/majodev))
- [#856](https://github.com/wycats/handlebars.js/pull/856) - jspm compatibility ([@MajorBreakfast](https://api.github.com/users/MajorBreakfast))
- [#805](https://github.com/wycats/handlebars.js/issues/805) - Request: "strict" lookups ([@nzakas](https://api.github.com/users/nzakas))
- Export the default object for handlebars/runtime - 5594416
- Lookup partials when undefined - 617dd57
@@ -455,21 +192,21 @@ New Features:
[Commits](https://github.com/wycats/handlebars.js/compare/v2.0.0-beta.1...v2.0.0)
## v2.0.0-beta.1 - August 26th, 2014
- [#787](https://github.com/wycats/handlebars.js/pull/787) - Remove whitespace surrounding standalone statements ([@kpdecker](https://github.com/kpdecker))
- [#827](https://github.com/wycats/handlebars.js/issues/827) - Render false literal as “false” ([@scoot557](https://github.com/scoot557))
- [#767](https://github.com/wycats/handlebars.js/issues/767) - Subexpressions bug with hash and context ([@evensoul](https://github.com/evensoul))
- [#787](https://github.com/wycats/handlebars.js/pull/787) - Remove whitespace surrounding standalone statements ([@kpdecker](https://api.github.com/users/kpdecker))
- [#827](https://github.com/wycats/handlebars.js/issues/827) - Render false literal as “false” ([@scoot557](https://api.github.com/users/scoot557))
- [#767](https://github.com/wycats/handlebars.js/issues/767) - Subexpressions bug with hash and context ([@evensoul](https://api.github.com/users/evensoul))
- Changes to 0/undefined handling
- [#731](https://github.com/wycats/handlebars.js/pull/731) - Strange behavior for {{#foo}} {{bar}} {{/foo}} when foo is 0 ([@kpdecker](https://github.com/kpdecker))
- [#820](https://github.com/wycats/handlebars.js/issues/820) - strange behavior for {{foo.bar}} when foo is 0 or null or false ([@zordius](https://github.com/zordius))
- [#837](https://github.com/wycats/handlebars.js/issues/837) - Strange input for custom helper ( foo.bar == false when foo is undefined ) ([@zordius](https://github.com/zordius))
- [#819](https://github.com/wycats/handlebars.js/pull/819) - Implement recursive field lookup ([@kpdecker](https://github.com/kpdecker))
- [#764](https://github.com/wycats/handlebars.js/issues/764) - This reference not working for helpers ([@kpdecker](https://github.com/kpdecker))
- [#773](https://github.com/wycats/handlebars.js/issues/773) - Implicit parameters in {{#each}} introduces a peculiarity in helpers calling convention ([@Bertrand](https://github.com/Bertrand))
- [#783](https://github.com/wycats/handlebars.js/issues/783) - helperMissing and consistency for different expression types ([@ErisDS](https://github.com/ErisDS))
- [#795](https://github.com/wycats/handlebars.js/pull/795) - Turn the precompile script into a wrapper around a module. ([@jwietelmann](https://github.com/jwietelmann))
- [#823](https://github.com/wycats/handlebars.js/pull/823) - Support inverse sections on the with helper ([@dan-manges](https://github.com/dan-manges))
- [#834](https://github.com/wycats/handlebars.js/pull/834) - Refactor blocks, programs and inverses ([@mmun](https://github.com/mmun))
- [#852](https://github.com/wycats/handlebars.js/issues/852) - {{foo~}} space control behavior is different from older version ([@zordius](https://github.com/zordius))
- [#731](https://github.com/wycats/handlebars.js/pull/731) - Strange behavior for {{#foo}} {{bar}} {{/foo}} when foo is 0 ([@kpdecker](https://api.github.com/users/kpdecker))
- [#820](https://github.com/wycats/handlebars.js/issues/820) - strange behavior for {{foo.bar}} when foo is 0 or null or false ([@zordius](https://api.github.com/users/zordius))
- [#837](https://github.com/wycats/handlebars.js/issues/837) - Strange input for custom helper ( foo.bar == false when foo is undefined ) ([@zordius](https://api.github.com/users/zordius))
- [#819](https://github.com/wycats/handlebars.js/pull/819) - Implement recursive field lookup ([@kpdecker](https://api.github.com/users/kpdecker))
- [#764](https://github.com/wycats/handlebars.js/issues/764) - This reference not working for helpers ([@kpdecker](https://api.github.com/users/kpdecker))
- [#773](https://github.com/wycats/handlebars.js/issues/773) - Implicit parameters in {{#each}} introduces a peculiarity in helpers calling convention ([@Bertrand](https://api.github.com/users/Bertrand))
- [#783](https://github.com/wycats/handlebars.js/issues/783) - helperMissing and consistency for different expression types ([@ErisDS](https://api.github.com/users/ErisDS))
- [#795](https://github.com/wycats/handlebars.js/pull/795) - Turn the precompile script into a wrapper around a module. ([@jwietelmann](https://api.github.com/users/jwietelmann))
- [#823](https://github.com/wycats/handlebars.js/pull/823) - Support inverse sections on the with helper ([@dan-manges](https://api.github.com/users/dan-manges))
- [#834](https://github.com/wycats/handlebars.js/pull/834) - Refactor blocks, programs and inverses ([@mmun](https://api.github.com/users/mmun))
- [#852](https://github.com/wycats/handlebars.js/issues/852) - {{foo~}} space control behavior is different from older version ([@zordius](https://api.github.com/users/zordius))
- [#835](https://github.com/wycats/handlebars.js/issues/835) - Templates overwritten if file is loaded twice
- Expose escapeExpression on the root object - 980c38c
@@ -484,7 +221,7 @@ Compatibility notes:
- Lines containing only block statements and whitespace are now removed. This matches the Mustache spec but may cause issues with code that expects whitespace to exist but would not otherwise.
- Partials that are standalone will now indent their rendered content
- `AST.ProgramNode`'s signature has changed.
- Numerious methods/features removed from pseudo-API classes
- Numerious methods/features removed from psuedo-API classes
- `JavaScriptCompiler.register`
- `JavaScriptCompiler.replaceStack` no longer supports non-inline replace
- `Compiler.disassemble`
@@ -503,18 +240,18 @@ Compatibility notes:
[Commits](https://github.com/wycats/handlebars.js/compare/v2.0.0-alpha.3...v2.0.0-alpha.4)
## v2.0.0-alpha.3 - May 19th, 2014
- [#797](https://github.com/wycats/handlebars.js/pull/797) - Pass full helper ID to helperMissing when options are provided ([@tomdale](https://github.com/tomdale))
- [#793](https://github.com/wycats/handlebars.js/pull/793) - Ensure isHelper is coerced to a boolean ([@mmun](https://github.com/mmun))
- [#797](https://github.com/wycats/handlebars.js/pull/797) - Pass full helper ID to helperMissing when options are provided ([@tomdale](https://api.github.com/users/tomdale))
- [#793](https://github.com/wycats/handlebars.js/pull/793) - Ensure isHelper is coerced to a boolean ([@mmun](https://api.github.com/users/mmun))
- Refactor template init logic - 085e5e1
[Commits](https://github.com/wycats/handlebars.js/compare/v2.0.0-alpha.2...v2.0.0-alpha.3)
## v2.0.0-alpha.2 - March 6th, 2014
- [#756](https://github.com/wycats/handlebars.js/pull/756) - fix bug in IE<=8 (no Array::map), closes #751 ([@jenseng](https://github.com/jenseng))
- [#749](https://github.com/wycats/handlebars.js/pull/749) - properly handle multiple subexpressions in the same hash, fixes #748 ([@jenseng](https://github.com/jenseng))
- [#743](https://github.com/wycats/handlebars.js/issues/743) - subexpression confusion/problem? ([@waynedpj](https://github.com/waynedpj))
- [#746](https://github.com/wycats/handlebars.js/issues/746) - [CLI] support `handlebars --version` ([@apfelbox](https://github.com/apfelbox))
- [#747](https://github.com/wycats/handlebars.js/pull/747) - updated grunt-saucelabs, failing tests revealed ([@Jonahss](https://github.com/Jonahss))
- [#756](https://github.com/wycats/handlebars.js/pull/756) - fix bug in IE<=8 (no Array::map), closes #751 ([@jenseng](https://api.github.com/users/jenseng))
- [#749](https://github.com/wycats/handlebars.js/pull/749) - properly handle multiple subexpressions in the same hash, fixes #748 ([@jenseng](https://api.github.com/users/jenseng))
- [#743](https://github.com/wycats/handlebars.js/issues/743) - subexpression confusion/problem? ([@waynedpj](https://api.github.com/users/waynedpj))
- [#746](https://github.com/wycats/handlebars.js/issues/746) - [CLI] support `handlebars --version` ([@apfelbox](https://api.github.com/users/apfelbox))
- [#747](https://github.com/wycats/handlebars.js/pull/747) - updated grunt-saucelabs, failing tests revealed ([@Jonahss](https://api.github.com/users/Jonahss))
- Make JSON a requirement for the compiler. - 058c0fb
- Temporarily kill the AWS publish CI step - 8347ee2
@@ -524,26 +261,26 @@ Compatibility notes:
[Commits](https://github.com/wycats/handlebars.js/compare/v2.0.0-alpha.1...v2.0.0-alpha.2)
## v2.0.0-alpha.1 - February 10th, 2014
- [#182](https://github.com/wycats/handlebars.js/pull/182) - Allow passing hash parameters to partials ([@kpdecker](https://github.com/kpdecker))
- [#392](https://github.com/wycats/handlebars.js/pull/392) - Access to root context in partials and helpers ([@kpdecker](https://github.com/kpdecker))
- [#472](https://github.com/wycats/handlebars.js/issues/472) - Helpers cannot have decimal parameters ([@kayleg](https://github.com/kayleg))
- [#569](https://github.com/wycats/handlebars.js/pull/569) - Unable to lookup array values using @index ([@kpdecker](https://github.com/kpdecker))
- [#491](https://github.com/wycats/handlebars.js/pull/491) - For nested helpers: get the @ variables of the outer helper from the inner one ([@kpdecker](https://github.com/kpdecker))
- [#669](https://github.com/wycats/handlebars.js/issues/669) - Ability to unregister a helper ([@dbachrach](https://github.com/dbachrach))
- [#730](https://github.com/wycats/handlebars.js/pull/730) - Raw block helpers ([@kpdecker](https://github.com/kpdecker))
- [#634](https://github.com/wycats/handlebars.js/pull/634) - It would be great to have the helper name passed to `blockHelperMissing` ([@kpdecker](https://github.com/kpdecker))
- [#729](https://github.com/wycats/handlebars.js/pull/729) - Convert template spec to object literal ([@kpdecker](https://github.com/kpdecker))
- [#182](https://github.com/wycats/handlebars.js/pull/182) - Allow passing hash parameters to partials ([@kpdecker](https://api.github.com/users/kpdecker))
- [#392](https://github.com/wycats/handlebars.js/pull/392) - Access to root context in partials and helpers ([@kpdecker](https://api.github.com/users/kpdecker))
- [#472](https://github.com/wycats/handlebars.js/issues/472) - Helpers cannot have decimal parameters ([@kayleg](https://api.github.com/users/kayleg))
- [#569](https://github.com/wycats/handlebars.js/pull/569) - Unable to lookup array values using @index ([@kpdecker](https://api.github.com/users/kpdecker))
- [#491](https://github.com/wycats/handlebars.js/pull/491) - For nested helpers: get the @ variables of the outer helper from the inner one ([@kpdecker](https://api.github.com/users/kpdecker))
- [#669](https://github.com/wycats/handlebars.js/issues/669) - Ability to unregister a helper ([@dbachrach](https://api.github.com/users/dbachrach))
- [#730](https://github.com/wycats/handlebars.js/pull/730) - Raw block helpers ([@kpdecker](https://api.github.com/users/kpdecker))
- [#634](https://github.com/wycats/handlebars.js/pull/634) - It would be great to have the helper name passed to `blockHelperMissing` ([@kpdecker](https://api.github.com/users/kpdecker))
- [#729](https://github.com/wycats/handlebars.js/pull/729) - Convert template spec to object literal ([@kpdecker](https://api.github.com/users/kpdecker))
- [#658](https://github.com/wycats/handlebars.js/issues/658) - Depthed helpers do not work after an upgrade from 1.0.0 ([@xibxor](https://github.com/xibxor))
- [#671](https://github.com/wycats/handlebars.js/issues/671) - Crashes on no-parameter {{#each}} ([@stepancheg](https://github.com/stepancheg))
- [#689](https://github.com/wycats/handlebars.js/issues/689) - broken template precompilation ([@AAS](https://github.com/AAS))
- [#698](https://github.com/wycats/handlebars.js/pull/698) - Fix parser generation under windows ([@osiris43](https://github.com/osiris43))
- [#699](https://github.com/wycats/handlebars.js/issues/699) - @DATA not compiles to invalid JS in stringParams mode ([@kpdecker](https://github.com/kpdecker))
- [#705](https://github.com/wycats/handlebars.js/issues/705) - 1.3.0 can not be wrapped in an IIFE ([@craigteegarden](https://github.com/craigteegarden))
- [#706](https://github.com/wycats/handlebars.js/pull/706) - README: Use with helper instead of relying on blockHelperMissing ([@scottgonzalez](https://github.com/scottgonzalez))
- [#658](https://github.com/wycats/handlebars.js/issues/658) - Depthed helpers do not work after an upgrade from 1.0.0 ([@xibxor](https://api.github.com/users/xibxor))
- [#671](https://github.com/wycats/handlebars.js/issues/671) - Crashes on no-parameter {{#each}} ([@stepancheg](https://api.github.com/users/stepancheg))
- [#689](https://github.com/wycats/handlebars.js/issues/689) - broken template precompilation ([@AAS](https://api.github.com/users/AAS))
- [#698](https://github.com/wycats/handlebars.js/pull/698) - Fix parser generation under windows ([@osiris43](https://api.github.com/users/osiris43))
- [#699](https://github.com/wycats/handlebars.js/issues/699) - @DATA not compiles to invalid JS in stringParams mode ([@kpdecker](https://api.github.com/users/kpdecker))
- [#705](https://github.com/wycats/handlebars.js/issues/705) - 1.3.0 can not be wrapped in an IIFE ([@craigteegarden](https://api.github.com/users/craigteegarden))
- [#706](https://github.com/wycats/handlebars.js/pull/706) - README: Use with helper instead of relying on blockHelperMissing ([@scottgonzalez](https://api.github.com/users/scottgonzalez))
- [#700](https://github.com/wycats/handlebars.js/pull/700) - Remove redundant conditions ([@blakeembrey](https://github.com/blakeembrey))
- [#704](https://github.com/wycats/handlebars.js/pull/704) - JavaScript Compiler Cleanup ([@blakeembrey](https://github.com/blakeembrey))
- [#700](https://github.com/wycats/handlebars.js/pull/700) - Remove redundant conditions ([@blakeembrey](https://api.github.com/users/blakeembrey))
- [#704](https://github.com/wycats/handlebars.js/pull/704) - JavaScript Compiler Cleanup ([@blakeembrey](https://api.github.com/users/blakeembrey))
Compatibility notes:
- `helperMissing` helper no longer has the indexed name argument. Helper name is now available via `options.name`.
@@ -558,12 +295,12 @@ Compatibility notes:
[Commits](https://github.com/wycats/handlebars.js/compare/v1.3.0...v2.0.0-alpha.1)
## v1.3.0 - January 1st, 2014
- [#690](https://github.com/wycats/handlebars.js/pull/690) - Added support for subexpressions ([@machty](https://github.com/machty))
- [#696](https://github.com/wycats/handlebars.js/pull/696) - Fix for reserved keyword "default" ([@nateirwin](https://github.com/nateirwin))
- [#692](https://github.com/wycats/handlebars.js/pull/692) - add line numbers to nodes when parsing ([@fivetanley](https://github.com/fivetanley))
- [#695](https://github.com/wycats/handlebars.js/pull/695) - Pull options out from param setup to allow easier extension ([@blakeembrey](https://github.com/blakeembrey))
- [#694](https://github.com/wycats/handlebars.js/pull/694) - Make the environment reusable ([@blakeembrey](https://github.com/blakeembrey))
- [#636](https://github.com/wycats/handlebars.js/issues/636) - Print line and column of errors ([@sgronblo](https://github.com/sgronblo))
- [#690](https://github.com/wycats/handlebars.js/pull/690) - Added support for subexpressions ([@machty](https://api.github.com/users/machty))
- [#696](https://github.com/wycats/handlebars.js/pull/696) - Fix for reserved keyword "default" ([@nateirwin](https://api.github.com/users/nateirwin))
- [#692](https://github.com/wycats/handlebars.js/pull/692) - add line numbers to nodes when parsing ([@fivetanley](https://api.github.com/users/fivetanley))
- [#695](https://github.com/wycats/handlebars.js/pull/695) - Pull options out from param setup to allow easier extension ([@blakeembrey](https://api.github.com/users/blakeembrey))
- [#694](https://github.com/wycats/handlebars.js/pull/694) - Make the environment reusable ([@blakeembrey](https://api.github.com/users/blakeembrey))
- [#636](https://github.com/wycats/handlebars.js/issues/636) - Print line and column of errors ([@sgronblo](https://api.github.com/users/sgronblo))
- Use literal for data lookup - c1a93d3
- Add stack handling sanity checks - cd885bf
- Fix stack id "leak" on replaceStack - ddfe457
@@ -572,25 +309,25 @@ Compatibility notes:
[Commits](https://github.com/wycats/handlebars.js/compare/v1.2.1...v1.3.0)
## v1.2.1 - December 26th, 2013
- [#684](https://github.com/wycats/handlebars.js/pull/684) - Allow any number of trailing characters for valid JavaScript variable ([@blakeembrey](https://github.com/blakeembrey))
- [#686](https://github.com/wycats/handlebars.js/pull/686) - Falsy AMD module names in version 1.2.0 ([@kpdecker](https://github.com/kpdecker))
- [#684](https://github.com/wycats/handlebars.js/pull/684) - Allow any number of trailing characters for valid JavaScript variable ([@blakeembrey](https://api.github.com/users/blakeembrey))
- [#686](https://github.com/wycats/handlebars.js/pull/686) - Falsy AMD module names in version 1.2.0 ([@kpdecker](https://api.github.com/users/kpdecker))
[Commits](https://github.com/wycats/handlebars.js/compare/v1.2.0...v1.2.1)
## v1.2.0 - December 23rd, 2013
- [#675](https://github.com/wycats/handlebars.js/issues/675) - Cannot compile empty template for partial ([@erwinw](https://github.com/erwinw))
- [#677](https://github.com/wycats/handlebars.js/issues/677) - Triple brace statements fail under IE ([@hamzaCM](https://github.com/hamzaCM))
- [#655](https://github.com/wycats/handlebars.js/issues/655) - Loading Handlebars using bower ([@niki4810](https://github.com/niki4810))
- [#657](https://github.com/wycats/handlebars.js/pull/657) - Fixes issue where cli compiles non handlebars templates ([@chrishoage](https://github.com/chrishoage))
- [#681](https://github.com/wycats/handlebars.js/pull/681) - Adds in-browser testing and Saucelabs CI ([@kpdecker](https://github.com/kpdecker))
- [#661](https://github.com/wycats/handlebars.js/pull/661) - Add @first and @index to #each object iteration ([@cgp](https://github.com/cgp))
- [#650](https://github.com/wycats/handlebars.js/pull/650) - Handlebars is MIT-licensed ([@thomasboyt](https://github.com/thomasboyt))
- [#641](https://github.com/wycats/handlebars.js/pull/641) - Document ember testing process ([@kpdecker](https://github.com/kpdecker))
- [#675](https://github.com/wycats/handlebars.js/issues/675) - Cannot compile empty template for partial ([@erwinw](https://api.github.com/users/erwinw))
- [#677](https://github.com/wycats/handlebars.js/issues/677) - Triple brace statements fail under IE ([@hamzaCM](https://api.github.com/users/hamzaCM))
- [#655](https://github.com/wycats/handlebars.js/issues/655) - Loading Handlebars using bower ([@niki4810](https://api.github.com/users/niki4810))
- [#657](https://github.com/wycats/handlebars.js/pull/657) - Fixes issue where cli compiles non handlebars templates ([@chrishoage](https://api.github.com/users/chrishoage))
- [#681](https://github.com/wycats/handlebars.js/pull/681) - Adds in-browser testing and Saucelabs CI ([@kpdecker](https://api.github.com/users/kpdecker))
- [#661](https://github.com/wycats/handlebars.js/pull/661) - Add @first and @index to #each object iteration ([@cgp](https://api.github.com/users/cgp))
- [#650](https://github.com/wycats/handlebars.js/pull/650) - Handlebars is MIT-licensed ([@thomasboyt](https://api.github.com/users/thomasboyt))
- [#641](https://github.com/wycats/handlebars.js/pull/641) - Document ember testing process ([@kpdecker](https://api.github.com/users/kpdecker))
- [#662](https://github.com/wycats/handlebars.js/issues/662) - handlebars-source 1.1.2 is missing from RubyGems.
- [#656](https://github.com/wycats/handlebars.js/issues/656) - Expose COMPILER_REVISION checks as a hook ([@machty](https://github.com/machty))
- [#668](https://github.com/wycats/handlebars.js/issues/668) - Consider publishing handlebars-runtime as a separate module on npm ([@dlmanning](https://github.com/dlmanning))
- [#679](https://github.com/wycats/handlebars.js/issues/679) - Unable to override invokePartial ([@mattbrailsford](https://github.com/mattbrailsford))
- [#646](https://github.com/wycats/handlebars.js/pull/646) - Fix "\\{{" immediately following "\{{" ([@dmarcotte](https://github.com/dmarcotte))
- [#656](https://github.com/wycats/handlebars.js/issues/656) - Expose COMPILER_REVISION checks as a hook ([@machty](https://api.github.com/users/machty))
- [#668](https://github.com/wycats/handlebars.js/issues/668) - Consider publishing handlebars-runtime as a separate module on npm ([@dlmanning](https://api.github.com/users/dlmanning))
- [#679](https://github.com/wycats/handlebars.js/issues/679) - Unable to override invokePartial ([@mattbrailsford](https://api.github.com/users/mattbrailsford))
- [#646](https://github.com/wycats/handlebars.js/pull/646) - Fix "\\{{" immediately following "\{{" ([@dmarcotte](https://api.github.com/users/dmarcotte))
- Allow extend to work with non-prototyped objects - eb53f2e
- Add JavascriptCompiler public API tests - 1a751b2
- Add AST test coverage for more complex paths - ddea5be
@@ -605,8 +342,8 @@ Compatibility notes:
## v1.1.2 - November 5th, 2013
- [#645](https://github.com/wycats/handlebars.js/issues/645) - 1.1.1 fails under IE8 ([@kpdecker](https://github.com/kpdecker))
- [#644](https://github.com/wycats/handlebars.js/issues/644) - Using precompiled templates (AMD mode) with handlebars.runtime 1.1.1 ([@fddima](https://github.com/fddima))
- [#645](https://github.com/wycats/handlebars.js/issues/645) - 1.1.1 fails under IE8 ([@kpdecker](https://api.github.com/users/kpdecker))
- [#644](https://github.com/wycats/handlebars.js/issues/644) - Using precompiled templates (AMD mode) with handlebars.runtime 1.1.1 ([@fddima](https://api.github.com/users/fddima))
- Add simple binary utility tests - 96a45a4
- Fix empty string compilation - eea708a
@@ -623,13 +360,13 @@ Compatibility notes:
## v1.1.0 - November 3rd, 2013
- [#628](https://github.com/wycats/handlebars.js/pull/628) - Convert code to ES6 modules ([@kpdecker](https://github.com/kpdecker))
- [#336](https://github.com/wycats/handlebars.js/pull/336) - Add whitespace control syntax ([@kpdecker](https://github.com/kpdecker))
- [#535](https://github.com/wycats/handlebars.js/pull/535) - Fix for probable JIT error under Safari ([@sorentwo](https://github.com/sorentwo))
- [#483](https://github.com/wycats/handlebars.js/issues/483) - Add first and last @ vars to each helper ([@denniskuczynski](https://github.com/denniskuczynski))
- [#557](https://github.com/wycats/handlebars.js/pull/557) - `\\{{foo}}` escaping only works in some situations ([@dmarcotte](https://github.com/dmarcotte))
- [#552](https://github.com/wycats/handlebars.js/pull/552) - Added BOM removal flag. ([@blessenm](https://github.com/blessenm))
- [#543](https://github.com/wycats/handlebars.js/pull/543) - publish passing master builds to s3 ([@fivetanley](https://github.com/fivetanley))
- [#628](https://github.com/wycats/handlebars.js/pull/628) - Convert code to ES6 modules ([@kpdecker](https://api.github.com/users/kpdecker))
- [#336](https://github.com/wycats/handlebars.js/pull/336) - Add whitespace control syntax ([@kpdecker](https://api.github.com/users/kpdecker))
- [#535](https://github.com/wycats/handlebars.js/pull/535) - Fix for probable JIT error under Safari ([@sorentwo](https://api.github.com/users/sorentwo))
- [#483](https://github.com/wycats/handlebars.js/issues/483) - Add first and last @ vars to each helper ([@denniskuczynski](https://api.github.com/users/denniskuczynski))
- [#557](https://github.com/wycats/handlebars.js/pull/557) - `\\{{foo}}` escaping only works in some situations ([@dmarcotte](https://api.github.com/users/dmarcotte))
- [#552](https://github.com/wycats/handlebars.js/pull/552) - Added BOM removal flag. ([@blessenm](https://api.github.com/users/blessenm))
- [#543](https://github.com/wycats/handlebars.js/pull/543) - publish passing master builds to s3 ([@fivetanley](https://api.github.com/users/fivetanley))
- [#608](https://github.com/wycats/handlebars.js/issues/608) - Add `includeZero` flag to `if` conditional
- [#498](https://github.com/wycats/handlebars.js/issues/498) - `Handlebars.compile` fails on empty string although a single blank works fine
@@ -675,7 +412,7 @@ Compatibility notes:
## v1.0.11 / 1.0.0-rc4 - May 13 2013
- [#458](https://github.com/wycats/handlebars.js/issues/458) - Fix `./foo` syntax ([@jpfiset](https://github.com/jpfiset))
- [#460](https://github.com/wycats/handlebars.js/issues/460) - Allow `:` in unescaped identifiers ([@jpfiset](https://github.com/jpfiset))
- [#460](https://github.com/wycats/handlebars.js/issues/460) - Allow `:` in unescaped identifers ([@jpfiset](https://github.com/jpfiset))
- [#471](https://github.com/wycats/handlebars.js/issues/471) - Create release notes (These!)
- [#456](https://github.com/wycats/handlebars.js/issues/456) - Allow escaping of `\\`
- [#211](https://github.com/wycats/handlebars.js/issues/211) - Fix exception in `escapeExpression`
-5
View File
@@ -1,5 +0,0 @@
import Handlebars = require('handlebars')
declare module "handlebars/runtime" {
}
-2
View File
@@ -59,7 +59,6 @@ describe('ast', function() {
equals(node.loc.end.column, lastColumn);
}
/* eslint-disable no-multi-spaces */
ast = Handlebars.parse(
'line 1 {{line1Token}}\n' // 1
+ ' line 2 {{line2token}}\n' // 2
@@ -72,7 +71,6 @@ describe('ast', function() {
+ '{{else inverse}}\n' // 9
+ '{{else}}\n' // 10
+ '{{/open}}'); // 11
/* eslint-enable no-multi-spaces */
body = ast.body;
it('gets ContentNode line numbers', function() {
+2 -9
View File
@@ -312,14 +312,10 @@ describe('builtin helpers', function() {
console.info = function(info) {
equals('whee', info);
called = true;
console.info = $info;
console.log = $log;
};
console.log = function(log) {
equals('whee', log);
called = true;
console.info = $info;
console.log = $log;
};
shouldCompileTo(string, hash, '');
@@ -333,7 +329,6 @@ describe('builtin helpers', function() {
console.error = function(log) {
equals('whee', log);
called = true;
console.error = $error;
};
shouldCompileTo(string, [hash,,,, {level: '03'}], '');
@@ -348,7 +343,6 @@ describe('builtin helpers', function() {
console.log = function(log) {
equals('whee', log);
called = true;
console.log = $log;
};
shouldCompileTo(string, [hash,,,, {level: '03'}], '');
@@ -391,9 +385,9 @@ describe('builtin helpers', function() {
var hash = { blah: 'whee' };
var called = false;
console.info = console.log = console.error = console.debug = function() {
console.info = console.log = console.error = console.debug = function(log) {
equals('whee', log);
called = true;
console.info = console.log = console.error = console.debug = $log;
};
shouldCompileTo(string, hash, '');
@@ -409,7 +403,6 @@ describe('builtin helpers', function() {
equals('foo', log2);
equals(1, log3);
called = true;
console.log = $log;
};
shouldCompileTo(string, hash, '');
-12
View File
@@ -73,18 +73,6 @@ describe('compiler', function() {
it('can pass through an empty string', function() {
equal(Handlebars.compile('')(), '');
});
it('should not modify the options.data property(GH-1327)', function() {
var options = {data: [{a: 'foo'}, {a: 'bar'}]};
Handlebars.compile('{{#each data}}{{@index}}:{{a}} {{/each}}', options)();
equal(JSON.stringify(options, 0, 2), JSON.stringify({data: [{a: 'foo'}, {a: 'bar'}]}, 0, 2));
});
it('should not modify the options.knownHelpers property(GH-1327)', function() {
var options = {knownHelpers: {}};
Handlebars.compile('{{#each data}}{{@index}}:{{a}} {{/each}}', options)();
equal(JSON.stringify(options, 0, 2), JSON.stringify({knownHelpers: {}}, 0, 2));
});
});
describe('#precompile', function() {
+1 -2
View File
@@ -9,8 +9,7 @@ var filename = 'dist/handlebars.js';
if (global.minimizedTest) {
filename = 'dist/handlebars.min.js';
}
var distHandlebars = fs.readFileSync(require.resolve(`../../${filename}`), 'utf-8');
vm.runInThisContext(distHandlebars, filename);
vm.runInThisContext(fs.readFileSync(__dirname + '/../../' + filename), filename);
global.CompilerContext = {
browser: true,
-2
View File
@@ -1,5 +1,3 @@
var global = (function() { return this; }());
var AssertError;
if (Error.captureStackTrace) {
AssertError = function AssertError(message, caller) {
+1 -1
View File
@@ -15,7 +15,7 @@ if (grep === '--min') {
var files = fs.readdirSync(testDir)
.filter(function(name) { return (/.*\.js$/).test(name); })
.map(function(name) { return testDir + path.sep + name; });
.map(function(name) { return testDir + '/' + name; });
if (global.minimizedTest) {
run('./runtime', function() {
+1 -1
View File
@@ -1,6 +1,6 @@
define(['handlebars.runtime'], function(Handlebars) {
Handlebars = Handlebars["default"]; var template = Handlebars.template, templates = Handlebars.templates = Handlebars.templates || {};
return templates['empty'] = template({"compiler":[8,">= 4.3.0"],"main":function(container,depth0,helpers,partials,data) {
return templates['empty'] = template({"compiler":[7,">= 4.0.0"],"main":function(container,depth0,helpers,partials,data) {
return "";
},"useData":true});
});
+1 -1
View File
@@ -113,7 +113,7 @@ describe('helpers', function() {
{ 'name': 'Yehuda', 'id': 2 }
]};
shouldCompileTo(source, [data, {link: link}], '<ul><li><a href="/people/1">Alan</a></li><li><a href="/people/2">Yehuda</a></li></ul>');
shouldCompileTo(source, [data, {link: link}], '<ul><li><a href=\"/people/1\">Alan</a></li><li><a href=\"/people/2\">Yehuda</a></li></ul>');
});
it('block helper for undefined value', function() {
+6 -6
View File
@@ -51,7 +51,7 @@ describe('parser', function() {
});
it('parses mustaches with string parameters', function() {
equals(astFor('{{foo bar "baz" }}'), '{{ PATH:foo [PATH:bar, "baz"] }}\n');
equals(astFor('{{foo bar \"baz\" }}'), '{{ PATH:foo [PATH:bar, "baz"] }}\n');
});
it('parses mustaches with NUMBER parameters', function() {
@@ -87,10 +87,10 @@ describe('parser', function() {
equals(astFor("{{foo bat='bam'}}"), '{{ PATH:foo [] HASH{bat="bam"} }}\n');
equals(astFor('{{foo omg bar=baz bat="bam"}}'), '{{ PATH:foo [PATH:omg] HASH{bar=PATH:baz, bat="bam"} }}\n');
equals(astFor('{{foo omg bar=baz bat="bam" baz=1}}'), '{{ PATH:foo [PATH:omg] HASH{bar=PATH:baz, bat="bam", baz=NUMBER{1}} }}\n');
equals(astFor('{{foo omg bar=baz bat="bam" baz=true}}'), '{{ PATH:foo [PATH:omg] HASH{bar=PATH:baz, bat="bam", baz=BOOLEAN{true}} }}\n');
equals(astFor('{{foo omg bar=baz bat="bam" baz=false}}'), '{{ PATH:foo [PATH:omg] HASH{bar=PATH:baz, bat="bam", baz=BOOLEAN{false}} }}\n');
equals(astFor('{{foo omg bar=baz bat=\"bam\"}}'), '{{ PATH:foo [PATH:omg] HASH{bar=PATH:baz, bat="bam"} }}\n');
equals(astFor('{{foo omg bar=baz bat=\"bam\" baz=1}}'), '{{ PATH:foo [PATH:omg] HASH{bar=PATH:baz, bat="bam", baz=NUMBER{1}} }}\n');
equals(astFor('{{foo omg bar=baz bat=\"bam\" baz=true}}'), '{{ PATH:foo [PATH:omg] HASH{bar=PATH:baz, bat="bam", baz=BOOLEAN{true}} }}\n');
equals(astFor('{{foo omg bar=baz bat=\"bam\" baz=false}}'), '{{ PATH:foo [PATH:omg] HASH{bar=PATH:baz, bat="bam", baz=BOOLEAN{false}} }}\n');
});
it('parses contents followed by a mustache', function() {
@@ -136,7 +136,7 @@ describe('parser', function() {
});
it('parses a multi-line comment', function() {
equals(astFor('{{!\nthis is a multi-line comment\n}}'), "{{! '\nthis is a multi-line comment\n' }}\n");
equals(astFor('{{!\nthis is a multi-line comment\n}}'), "{{! \'\nthis is a multi-line comment\n\' }}\n");
});
it('parses an inverse section', function() {
-9
View File
@@ -263,15 +263,6 @@ describe('partials', function() {
true,
'success');
});
it('should be able to access the @data frame from a partial-block', function() {
shouldCompileToWithPartials(
'{{#> dude}}in-block: {{@root/value}}{{/dude}}',
[{value: 'success'}, {}, {dude: '<code>before-block: {{@root/value}} {{> @partial-block }}</code>'}],
true,
'<code>before-block: success in-block: success</code>');
});
it('should allow the #each-helper to be used along with partial-blocks', function() {
shouldCompileToWithPartials(
'<template>{{#> list value}}value = {{.}}{{/list}}</template>',
+2 -63
View File
@@ -12,8 +12,6 @@ describe('precompiler', function() {
var log,
logFunction,
errorLog,
errorLogFunction,
precompile,
minify,
@@ -28,51 +26,16 @@ describe('precompiler', function() {
content,
writeFileSync;
/**
* Mock the Module.prototype.require-function such that an error is thrown, when "uglify-js" is loaded.
*
* The function cleans up its mess when "callback" is finished
*
* @param {Error} loadError the error that should be thrown if uglify is loaded
* @param {function} callback a callback-function to run when the mock is active.
*/
function mockRequireUglify(loadError, callback) {
var Module = require('module');
var _resolveFilename = Module._resolveFilename;
delete require.cache[require.resolve('uglify-js')];
delete require.cache[require.resolve('../dist/cjs/precompiler')];
Module._resolveFilename = function(request, mod) {
if (request === 'uglify-js') {
throw loadError;
}
return _resolveFilename.call(this, request, mod);
};
try {
callback();
} finally {
Module._resolveFilename = _resolveFilename;
delete require.cache[require.resolve('uglify-js')];
delete require.cache[require.resolve('../dist/cjs/precompiler')];
}
}
beforeEach(function() {
precompile = Handlebars.precompile;
minify = uglify.minify;
writeFileSync = fs.writeFileSync;
// Mock stdout and stderr
logFunction = console.log;
log = '';
console.log = function() {
log += Array.prototype.join.call(arguments, '');
};
errorLogFunction = console.error;
errorLog = '';
console.error = function() {
errorLog += Array.prototype.join.call(arguments, '');
};
fs.writeFileSync = function(_file, _content) {
file = _file;
content = _content;
@@ -83,7 +46,6 @@ describe('precompiler', function() {
uglify.minify = minify;
fs.writeFileSync = writeFileSync;
console.log = logFunction;
console.error = errorLogFunction;
});
it('should output version', function() {
@@ -186,41 +148,18 @@ describe('precompiler', function() {
equal(log, 'min');
});
it('should omit minimization gracefully, if uglify-js is missing', function() {
var error = new Error("Cannot find module 'uglify-js'");
error.code = 'MODULE_NOT_FOUND';
mockRequireUglify(error, function() {
var Precompiler = require('../dist/cjs/precompiler');
Handlebars.precompile = function() { return 'amd'; };
Precompiler.cli({templates: [emptyTemplate], min: true});
equal(/template\(amd\)/.test(log), true);
equal(/\n/.test(log), true);
equal(/Code minimization is disabled/.test(errorLog), true);
});
});
it('should fail on errors (other than missing module) while loading uglify-js', function() {
mockRequireUglify(new Error('Mock Error'), function() {
shouldThrow(function() {
var Precompiler = require('../dist/cjs/precompiler');
Handlebars.precompile = function() { return 'amd'; };
Precompiler.cli({templates: [emptyTemplate], min: true});
}, Error, 'Mock Error');
});
});
it('should output map', function() {
Precompiler.cli({templates: [emptyTemplate], map: 'foo.js.map'});
equal(file, 'foo.js.map');
equal(log.match(/sourceMappingURL=/g).length, 1);
equal(/sourceMappingURL=/.test(log), true);
});
it('should output map', function() {
Precompiler.cli({templates: [emptyTemplate], min: true, map: 'foo.js.map'});
equal(file, 'foo.js.map');
equal(log.match(/sourceMappingURL=/g).length, 1);
equal(/sourceMappingURL=/.test(log), true);
});
describe('#loadTemplates', function() {
-46
View File
@@ -277,50 +277,4 @@ describe('Regressions', function() {
shouldCompileTo(string, { listOne: ['a'], listTwo: ['b']}, 'ab', '');
});
it('GH-1319: "unless" breaks when "each" value equals "null"', function() {
var string = '{{#each list}}{{#unless ./prop}}parent={{../value}} {{/unless}}{{/each}}';
shouldCompileTo(string, { value: 'parent', list: [ null, 'a'] }, 'parent=parent parent=parent ', '');
});
it('GH-1341: 4.0.7 release breaks {{#if @partial-block}} usage', function() {
var string = 'template {{>partial}} template';
var partials = {
partialWithBlock: '{{#if @partial-block}} block {{> @partial-block}} block {{/if}}',
partial: '{{#> partialWithBlock}} partial {{/partialWithBlock}}'
};
shouldCompileToWithPartials(string, [{}, {}, partials], true, 'template block partial block template');
});
describe('GH-1561: 4.3.x should still work with precompiled templates from 4.0.0 <= x < 4.3.0', function() {
it('should compile and execute templates', function() {
var newHandlebarsInstance = Handlebars.create();
registerTemplate(newHandlebarsInstance);
newHandlebarsInstance.registerHelper('loud', function(value) {
return value.toUpperCase();
});
var result = newHandlebarsInstance.templates['test.hbs']({name: 'yehuda'});
equals(result.trim(), 'YEHUDA');
});
it('should call "helperMissing" if a helper is missing', function() {
var newHandlebarsInstance = Handlebars.create();
shouldThrow(function() {
registerTemplate(newHandlebarsInstance);
newHandlebarsInstance.templates['test.hbs']({});
}, Handlebars.Exception, 'Missing helper: "loud"');
});
// This is a only slightly modified precompiled templated from compiled with 4.2.1
function registerTemplate(Handlebars) {
var template = Handlebars.template, templates = Handlebars.templates = Handlebars.templates || {};
templates['test.hbs'] = template({'compiler': [7, '>= 4.0.0'], 'main': function(container, depth0, helpers, partials, data) {
return container.escapeExpression((helpers.loud || (depth0 && depth0.loud) || helpers.helperMissing).call(depth0 != null ? depth0 : (container.nullContext || {}), (depth0 != null ? depth0.name : depth0), {'name': 'loud', 'hash': {}, 'data': data}))
+ '\n\n';
}, 'useData': true});
}
});
});
+1 -1
View File
@@ -21,7 +21,7 @@ describe('runtime', function() {
shouldThrow(function() {
Handlebars.template({
main: {},
compiler: [Handlebars.LAST_COMPATIBLE_COMPILER_REVISION - 1]
compiler: [Handlebars.COMPILER_REVISION - 1]
});
}, Error, /Template was precompiled with an older version of Handlebars than the current runtime/);
shouldThrow(function() {
-104
View File
@@ -1,104 +0,0 @@
describe('security issues', function() {
describe('GH-1495: Prevent Remote Code Execution via constructor', function() {
it('should not allow constructors to be accessed', function() {
shouldCompileTo('{{constructor.name}}', {}, '');
shouldCompileTo('{{lookup (lookup this "constructor") "name"}}', {}, '');
});
it('should allow the "constructor" property to be accessed if it is enumerable', function() {
shouldCompileTo('{{constructor.name}}', {'constructor': {
'name': 'here we go'
}}, 'here we go');
shouldCompileTo('{{lookup (lookup this "constructor") "name"}}', {'constructor': {
'name': 'here we go'
}}, 'here we go');
});
it('should allow prototype properties that are not constructors', function() {
function TestClass() {
}
Object.defineProperty(TestClass.prototype, 'abc', {
get: function() {
return 'xyz';
}
});
shouldCompileTo('{{#with this as |obj|}}{{obj.abc}}{{/with}}',
new TestClass(), 'xyz');
shouldCompileTo('{{#with this as |obj|}}{{lookup obj "abc"}}{{/with}}',
new TestClass(), 'xyz');
});
});
describe('GH-1558: Prevent explicit call of helperMissing-helpers', function() {
if (!Handlebars.compile) {
return;
}
describe('without the option "allowExplicitCallOfHelperMissing"', function() {
it('should throw an exception when calling "{{helperMissing}}" ', function() {
shouldThrow(function() {
var template = Handlebars.compile('{{helperMissing}}');
template({});
}, Error);
});
it('should throw an exception when calling "{{#helperMissing}}{{/helperMissing}}" ', function() {
shouldThrow(function() {
var template = Handlebars.compile('{{#helperMissing}}{{/helperMissing}}');
template({});
}, Error);
});
it('should throw an exception when calling "{{blockHelperMissing "abc" .}}" ', function() {
var functionCalls = [];
shouldThrow(function() {
var template = Handlebars.compile('{{blockHelperMissing "abc" .}}');
template({ fn: function() { functionCalls.push('called'); }});
}, Error);
equals(functionCalls.length, 0);
});
it('should throw an exception when calling "{{#blockHelperMissing .}}{{/blockHelperMissing}}"', function() {
shouldThrow(function() {
var template = Handlebars.compile('{{#blockHelperMissing .}}{{/blockHelperMissing}}');
template({ fn: function() { return 'functionInData';}});
}, Error);
});
});
describe('with the option "allowCallsToHelperMissing" set to true', function() {
it('should not throw an exception when calling "{{helperMissing}}" ', function() {
var template = Handlebars.compile('{{helperMissing}}');
template({}, {allowCallsToHelperMissing: true});
});
it('should not throw an exception when calling "{{#helperMissing}}{{/helperMissing}}" ', function() {
var template = Handlebars.compile('{{#helperMissing}}{{/helperMissing}}');
template({}, {allowCallsToHelperMissing: true});
});
it('should not throw an exception when calling "{{blockHelperMissing "abc" .}}" ', function() {
var functionCalls = [];
var template = Handlebars.compile('{{blockHelperMissing "abc" .}}');
template({ fn: function() { functionCalls.push('called'); }}, {allowCallsToHelperMissing: true});
equals(functionCalls.length, 1);
});
it('should not throw an exception when calling "{{#blockHelperMissing .}}{{/blockHelperMissing}}"', function() {
var template = Handlebars.compile('{{#blockHelperMissing true}}sdads{{/blockHelperMissing}}');
template({}, {allowCallsToHelperMissing: true});
});
});
});
describe('GH-1563', function() {
it('should not allow to access constructor after overriding via __defineGetter__', function() {
if (({}).__defineGetter__ == null || ({}).__lookupGetter__ == null) {
return; // Browser does not support this exploit anyway
}
shouldCompileTo('{{__defineGetter__ "undefined" valueOf }}' +
'{{#with __lookupGetter__ }}' +
'{{__defineGetter__ "propertyIsEnumerable" (this.bind (this.bind 1)) }}' +
'{{constructor.name}}' +
'{{/with}}', {}, '');
});
});
});
+2 -2
View File
@@ -25,8 +25,8 @@ describe('spec', function() {
// We nest the entire response from partials, not just the literals
|| (name === 'partials.json' && test.name === 'Standalone Indentation')
|| (/\{\{=/).test(test.template)
|| _.any(test.partials, function(partial) { return (/\{\{=/).test(partial); })) {
|| (/\{\{\=/).test(test.template)
|| _.any(test.partials, function(partial) { return (/\{\{\=/).test(partial); })) {
it.skip(name + ' - ' + test.name);
return;
}
+5 -5
View File
@@ -282,13 +282,13 @@ describe('Tokenizer', function() {
});
it('tokenizes mustaches with String params as "OPEN ID ID STRING CLOSE"', function() {
var result = tokenize('{{ foo bar "baz" }}');
var result = tokenize('{{ foo bar \"baz\" }}');
shouldMatchTokens(result, ['OPEN', 'ID', 'ID', 'STRING', 'CLOSE']);
shouldBeToken(result[3], 'STRING', 'baz');
});
it('tokenizes mustaches with String params using single quotes as "OPEN ID ID STRING CLOSE"', function() {
var result = tokenize("{{ foo bar 'baz' }}");
var result = tokenize("{{ foo bar \'baz\' }}");
shouldMatchTokens(result, ['OPEN', 'ID', 'ID', 'STRING', 'CLOSE']);
shouldBeToken(result[3], 'STRING', 'baz');
});
@@ -365,13 +365,13 @@ describe('Tokenizer', function() {
result = tokenize('{{ foo bar\n baz=bat }}');
shouldMatchTokens(result, ['OPEN', 'ID', 'ID', 'ID', 'EQUALS', 'ID', 'CLOSE']);
result = tokenize('{{ foo bar baz="bat" }}');
result = tokenize('{{ foo bar baz=\"bat\" }}');
shouldMatchTokens(result, ['OPEN', 'ID', 'ID', 'ID', 'EQUALS', 'STRING', 'CLOSE']);
result = tokenize('{{ foo bar baz="bat" bam=wot }}');
result = tokenize('{{ foo bar baz=\"bat\" bam=wot }}');
shouldMatchTokens(result, ['OPEN', 'ID', 'ID', 'ID', 'EQUALS', 'STRING', 'ID', 'EQUALS', 'ID', 'CLOSE']);
result = tokenize('{{foo omg bar=baz bat="bam"}}');
result = tokenize('{{foo omg bar=baz bat=\"bam\"}}');
shouldMatchTokens(result, ['OPEN', 'ID', 'ID', 'ID', 'EQUALS', 'ID', 'ID', 'EQUALS', 'STRING', 'CLOSE']);
shouldBeToken(result[2], 'ID', 'omg');
});
+2 -2
View File
@@ -4,7 +4,7 @@
%{
function strip(start, end) {
return yytext = yytext.substring(start, yyleng - end + start);
return yytext = yytext.substr(start, yyleng-end);
}
%}
@@ -59,7 +59,7 @@ ID [^\s!"#%-,\.\/;->@\[-\^`\{-~]+/{LOOKAHEAD}
if (this.conditionStack[this.conditionStack.length-1] === 'raw') {
return 'CONTENT';
} else {
strip(5, 9);
yytext = yytext.substr(5, yyleng-9);
return 'END_RAW_BLOCK';
}
}
+1 -1
View File
@@ -1 +1 @@
// File ignored in coverage tests via setting in .istanbul.yml
/* istanbul ignore next */
+2 -1
View File
@@ -1 +1,2 @@
export default handlebars;
exports.__esModule = true;
exports['default'] = handlebars;
+1 -1
View File
@@ -1,5 +1,5 @@
var _ = require('underscore'),
async = require('neo-async'),
async = require('async'),
metrics = require('../bench');
module.exports = function(grunt) {
+8 -16
View File
@@ -1,5 +1,5 @@
var _ = require('underscore'),
async = require('neo-async'),
async = require('async'),
AWS = require('aws-sdk'),
git = require('./util/git'),
semver = require('semver');
@@ -15,22 +15,14 @@ module.exports = function(grunt) {
git.commitInfo(function(err, info) {
grunt.log.writeln('tag: ' + info.tagName);
var files = [];
// Publish the master as "latest" and with the commit-id
if (info.isMaster) {
files.push('-latest');
files.push('-' + info.head);
}
// Publish tags by their tag-name
if (info.tagName && semver.valid(info.tagName)) {
files.push('-' + info.tagName);
}
if (files.length > 0) {
initSDK();
grunt.log.writeln('publishing files: ' + JSON.stringify(files));
var files = ['-latest', '-' + info.head];
if (info.tagName && semver.valid(info.tagName)) {
files.push('-' + info.tagName);
}
publish(fileMap(files), done);
} else {
// Silently ignore for branches
@@ -66,7 +58,7 @@ module.exports = function(grunt) {
var s3 = new AWS.S3(),
bucket = process.env.S3_BUCKET_NAME;
async.each(_.keys(files), function(file, callback) {
async.forEach(_.keys(files), function(file, callback) {
var params = {Bucket: bucket, Key: file, Body: grunt.file.read(files[file])};
s3.putObject(params, function(err) {
if (err) {
+6 -16
View File
@@ -1,27 +1,17 @@
var childProcess = require('child_process'),
fs = require('fs'),
os = require('os');
fs = require('fs');
module.exports = function(grunt) {
grunt.registerTask('test:bin', function() {
var done = this.async();
var cmd = './bin/handlebars';
var args = [ '-a', 'spec/artifacts/empty.handlebars' ];
// On Windows, the executable handlebars.js file cannot be run directly
if (os.platform() === 'win32') {
args.unshift(cmd);
cmd = process.argv[0];
}
childProcess.execFile(cmd, args, function(err, stdout) {
childProcess.exec('./bin/handlebars -a spec/artifacts/empty.handlebars', function(err, stdout) {
if (err) {
throw err;
}
var expected = fs.readFileSync('./spec/expected/empty.amd.js').toString().replace(/\r\n/g, '\n');
if (stdout.toString() !== expected) {
var expected = fs.readFileSync('./spec/expected/empty.amd.js');
if (stdout.toString() !== expected.toString()) {
throw new Error('Expected binary output differed:\n\n"' + stdout + '"\n\n"' + expected + '"');
}
@@ -42,7 +32,7 @@ module.exports = function(grunt) {
grunt.registerTask('test:cov', function() {
var done = this.async();
var runner = childProcess.fork('node_modules/istanbul/lib/cli.js', ['cover', '--source-map', '--', './spec/env/runner.js'], {stdio: 'inherit'});
var runner = childProcess.fork('node_modules/.bin/istanbul', ['cover', '--source-map', '--', './spec/env/runner.js'], {stdio: 'inherit'});
runner.on('close', function(code) {
if (code != 0) {
grunt.fatal(code + ' tests failed');
@@ -65,7 +55,7 @@ module.exports = function(grunt) {
grunt.registerTask('test:check-cov', function() {
var done = this.async();
var runner = childProcess.fork('node_modules/istanbul/lib/cli.js', ['check-coverage', '--statements', '100', '--functions', '100', '--branches', '100', '--lines 100'], {stdio: 'inherit'});
var runner = childProcess.fork('node_modules/.bin/istanbul', ['check-coverage', '--statements', '100', '--functions', '100', '--branches', '100', '--lines 100'], {stdio: 'inherit'});
runner.on('close', function(code) {
if (code != 0) {
grunt.fatal('Coverage check failed: ' + code);
+1 -2
View File
@@ -1,4 +1,4 @@
var async = require('neo-async'),
var async = require('async'),
git = require('./util/git'),
semver = require('semver');
@@ -20,7 +20,6 @@ module.exports = function(grunt) {
async.each([
['lib/handlebars/base.js', (/const VERSION = ['"](.*)['"];/), 'const VERSION = \'' + version + '\';'],
['components/bower.json', (/"version":.*/), '"version": "' + version + '",'],
['components/package.json', /"version":.*/, '"version": "' + version + '",'],
['components/handlebars.js.nuspec', (/<version>.*<\/version>/), '<version>' + version + '</version>']
],
function(args, callback) {
-385
View File
@@ -1,385 +0,0 @@
/* These definitions were imported from https://github.com/DefinitelyTyped/DefinitelyTyped
* and includes previous contributions from the DefinitelyTyped community by:
* - Albert Willemsen <https://github.com/AlbertWillemsen-Centric>
* - Boris Yankov <https://github.com/borisyankov>
* - Jessica Franco <https://github.com/Kovensky>
* - Masahiro Wakame <https://github.com/vvakame>
* - Raanan Weber <https://github.com/RaananW>
* - Sergei Dorogin <https://github.com/evil-shrike>
* - webbiesdk <https://github.com/webbiesdk>
* - Andrew Leedham <https://github.com/AndrewLeedham>
* - Nils Knappmeier <https://github.com/nknapp>
* For full history prior to their migration to handlebars.js, please see:
* https://github.com/DefinitelyTyped/DefinitelyTyped/commits/1ce60bdc07f10e0b076778c6c953271c072bc894/types/handlebars/index.d.ts
*/
// TypeScript Version: 2.3
declare namespace Handlebars {
export interface TemplateDelegate<T = any> {
(context: T, options?: RuntimeOptions): string;
}
export type Template<T = any> = TemplateDelegate<T>|string;
export interface RuntimeOptions {
partial?: boolean;
depths?: any[];
helpers?: { [name: string]: Function };
partials?: { [name: string]: HandlebarsTemplateDelegate };
decorators?: { [name: string]: Function };
data?: any;
blockParams?: any[];
allowCallsToHelperMissing?: boolean;
}
export interface HelperOptions {
fn: TemplateDelegate;
inverse: TemplateDelegate;
hash: any;
data?: any;
}
export interface HelperDelegate {
(context?: any, arg1?: any, arg2?: any, arg3?: any, arg4?: any, arg5?: any, options?: HelperOptions): any;
}
export interface HelperDeclareSpec {
[key: string]: HelperDelegate;
}
export interface ParseOptions {
srcName?: string,
ignoreStandalone?: boolean
}
export function registerHelper(name: string, fn: HelperDelegate): void;
export function registerHelper(name: HelperDeclareSpec): void;
export function unregisterHelper(name: string): void;
export function registerPartial(name: string, fn: Template): void;
export function registerPartial(spec: { [name: string]: HandlebarsTemplateDelegate }): void;
export function unregisterPartial(name: string): void;
// TODO: replace Function with actual signature
export function registerDecorator(name: string, fn: Function): void;
export function unregisterDecorator(name: string): void;
export function K(): void;
export function createFrame(object: any): any;
export function blockParams(obj: any[], ids: any[]): any[];
export function Exception(message: string): void;
export function log(level: number, obj: any): void;
export function parse(input: string, options?: ParseOptions): hbs.AST.Program;
export function compile<T = any>(input: any, options?: CompileOptions): HandlebarsTemplateDelegate<T>;
export function precompile(input: any, options?: PrecompileOptions): TemplateSpecification;
export function template<T = any>(precompilation: TemplateSpecification): HandlebarsTemplateDelegate<T>;
export function create(): typeof Handlebars;
export const escapeExpression: typeof Utils.escapeExpression;
//export const Utils: typeof hbs.Utils;
export const logger: Logger;
export const templates: HandlebarsTemplates;
export const helpers: { [name: string]: HelperDelegate };
export const partials: { [name: string]: any };
// TODO: replace Function with actual signature
export const decorators: { [name: string]: Function };
export function noConflict(): typeof Handlebars;
export class SafeString {
constructor(str: string);
toString(): string;
toHTML(): string;
}
export namespace Utils {
export function escapeExpression(str: string): string;
export function createFrame(object: any): any;
export function blockParams(obj: any[], ids: any[]): any[];
export function isEmpty(obj: any) : boolean;
export function extend(obj: any, ...source: any[]): any;
export function toString(obj: any): string;
export function isArray(obj: any): boolean;
export function isFunction(obj: any): boolean;
}
export namespace AST {
export const helpers: hbs.AST.helpers;
}
interface ICompiler {
accept(node: hbs.AST.Node): void;
Program(program: hbs.AST.Program): void;
BlockStatement(block: hbs.AST.BlockStatement): void;
PartialStatement(partial: hbs.AST.PartialStatement): void;
PartialBlockStatement(partial: hbs.AST.PartialBlockStatement): void;
DecoratorBlock(decorator: hbs.AST.DecoratorBlock): void;
Decorator(decorator: hbs.AST.Decorator): void;
MustacheStatement(mustache: hbs.AST.MustacheStatement): void;
ContentStatement(content: hbs.AST.ContentStatement): void;
CommentStatement(comment?: hbs.AST.CommentStatement): void;
SubExpression(sexpr: hbs.AST.SubExpression): void;
PathExpression(path: hbs.AST.PathExpression): void;
StringLiteral(str: hbs.AST.StringLiteral): void;
NumberLiteral(num: hbs.AST.NumberLiteral): void;
BooleanLiteral(bool: hbs.AST.BooleanLiteral): void;
UndefinedLiteral(): void;
NullLiteral(): void;
Hash(hash: hbs.AST.Hash): void;
}
export class Visitor implements ICompiler {
accept(node: hbs.AST.Node): void;
acceptKey(node: hbs.AST.Node, name: string): void;
acceptArray(arr: hbs.AST.Expression[]): void;
Program(program: hbs.AST.Program): void;
BlockStatement(block: hbs.AST.BlockStatement): void;
PartialStatement(partial: hbs.AST.PartialStatement): void;
PartialBlockStatement(partial: hbs.AST.PartialBlockStatement): void;
DecoratorBlock(decorator: hbs.AST.DecoratorBlock): void;
Decorator(decorator: hbs.AST.Decorator): void;
MustacheStatement(mustache: hbs.AST.MustacheStatement): void;
ContentStatement(content: hbs.AST.ContentStatement): void;
CommentStatement(comment?: hbs.AST.CommentStatement): void;
SubExpression(sexpr: hbs.AST.SubExpression): void;
PathExpression(path: hbs.AST.PathExpression): void;
StringLiteral(str: hbs.AST.StringLiteral): void;
NumberLiteral(num: hbs.AST.NumberLiteral): void;
BooleanLiteral(bool: hbs.AST.BooleanLiteral): void;
UndefinedLiteral(): void;
NullLiteral(): void;
Hash(hash: hbs.AST.Hash): void;
}
export interface ResolvePartialOptions {
name: string;
helpers?: { [name: string]: Function };
partials?: { [name: string]: HandlebarsTemplateDelegate };
decorators?: { [name: string]: Function };
data?: any;
}
export namespace VM {
/**
* @deprecated
*/
export function resolvePartial<T = any>(partial: HandlebarsTemplateDelegate<T> | undefined, context: any, options: ResolvePartialOptions): HandlebarsTemplateDelegate<T>;
}
}
/**
* Implement this interface on your MVW/MVVM/MVC views such as Backbone.View
**/
interface HandlebarsTemplatable {
template: HandlebarsTemplateDelegate;
}
// NOTE: for backward compatibility of this typing
type HandlebarsTemplateDelegate<T = any> = Handlebars.TemplateDelegate<T>;
interface HandlebarsTemplates {
[index: string]: HandlebarsTemplateDelegate;
}
interface TemplateSpecification {
}
// for backward compatibility of this typing
type RuntimeOptions = Handlebars.RuntimeOptions;
interface CompileOptions {
data?: boolean;
compat?: boolean;
knownHelpers?: KnownHelpers;
knownHelpersOnly?: boolean;
noEscape?: boolean;
strict?: boolean;
assumeObjects?: boolean;
preventIndent?: boolean;
ignoreStandalone?: boolean;
explicitPartialContext?: boolean;
}
type KnownHelpers = {
[name in BuiltinHelperName | CustomHelperName]: boolean;
};
type BuiltinHelperName =
"helperMissing"|
"blockHelperMissing"|
"each"|
"if"|
"unless"|
"with"|
"log"|
"lookup";
type CustomHelperName = string;
interface PrecompileOptions extends CompileOptions {
srcName?: string;
destName?: string;
}
declare namespace hbs {
// for backward compatibility of this typing
type SafeString = Handlebars.SafeString;
type Utils = typeof Handlebars.Utils;
}
interface Logger {
DEBUG: number;
INFO: number;
WARN: number;
ERROR: number;
level: number;
methodMap: { [level: number]: string };
log(level: number, obj: string): void;
}
type CompilerInfo = [number/* revision */, string /* versions */];
declare namespace hbs {
namespace AST {
interface Node {
type: string;
loc: SourceLocation;
}
interface SourceLocation {
source: string;
start: Position;
end: Position;
}
interface Position {
line: number;
column: number;
}
interface Program extends Node {
body: Statement[];
blockParams: string[];
}
interface Statement extends Node {}
interface MustacheStatement extends Statement {
path: PathExpression | Literal;
params: Expression[];
hash: Hash;
escaped: boolean;
strip: StripFlags;
}
interface Decorator extends MustacheStatement { }
interface BlockStatement extends Statement {
path: PathExpression;
params: Expression[];
hash: Hash;
program: Program;
inverse: Program;
openStrip: StripFlags;
inverseStrip: StripFlags;
closeStrip: StripFlags;
}
interface DecoratorBlock extends BlockStatement { }
interface PartialStatement extends Statement {
name: PathExpression | SubExpression;
params: Expression[];
hash: Hash;
indent: string;
strip: StripFlags;
}
interface PartialBlockStatement extends Statement {
name: PathExpression | SubExpression;
params: Expression[];
hash: Hash;
program: Program;
openStrip: StripFlags;
closeStrip: StripFlags;
}
interface ContentStatement extends Statement {
value: string;
original: StripFlags;
}
interface CommentStatement extends Statement {
value: string;
strip: StripFlags;
}
interface Expression extends Node {}
interface SubExpression extends Expression {
path: PathExpression;
params: Expression[];
hash: Hash;
}
interface PathExpression extends Expression {
data: boolean;
depth: number;
parts: string[];
original: string;
}
interface Literal extends Expression {}
interface StringLiteral extends Literal {
value: string;
original: string;
}
interface BooleanLiteral extends Literal {
value: boolean;
original: boolean;
}
interface NumberLiteral extends Literal {
value: number;
original: number;
}
interface UndefinedLiteral extends Literal {}
interface NullLiteral extends Literal {}
interface Hash extends Node {
pairs: HashPair[];
}
interface HashPair extends Node {
key: string;
value: Expression;
}
interface StripFlags {
open: boolean;
close: boolean;
}
interface helpers {
helperExpression(node: Node): boolean;
scopeId(path: PathExpression): boolean;
simpleId(path: PathExpression): boolean;
}
}
}
declare module "handlebars" {
export = Handlebars;
}
declare module "handlebars/runtime" {
export = Handlebars;
}
-113
View File
@@ -1,113 +0,0 @@
/* These test cases were imported from https://github.com/DefinitelyTyped/DefinitelyTyped
* and includes previous contributions from the DefinitelyTyped community.
* For full history prior to their migration to handlebars.js, please see:
* https://github.com/DefinitelyTyped/DefinitelyTyped/commits/1ce60bdc07f10e0b076778c6c953271c072bc894/types/handlebars/handlebars-tests.ts
*/
import * as Handlebars from 'handlebars';
const context = {
author: { firstName: 'Alan', lastName: 'Johnson' },
body: 'I Love Handlebars',
comments: [{
author: { firstName: 'Yehuda', lastName: 'Katz' },
body: 'Me too!'
}]
};
Handlebars.registerHelper('fullName', (person: typeof context.author) => {
return person.firstName + ' ' + person.lastName;
});
Handlebars.registerHelper('agree_button', function(this: any) {
return new Handlebars.SafeString(
'<button>I agree. I ' + this.emotion + ' ' + this.name + '</button>'
);
});
const source1 = '<p>Hello, my name is {{name}}. I am from {{hometown}}. I have ' +
'{{kids.length}} kids:</p>' +
'<ul>{{#kids}}<li>{{name}} is {{age}}</li>{{/kids}}</ul>';
const template1 = Handlebars.compile(source1);
template1({ name: "Alan", hometown: "Somewhere, TX", kids: [{name: "Jimmy", age: 12}, {name: "Sally", age: 4}]});
Handlebars.registerHelper('link_to', (context: typeof post) => {
return '<a href="' + context.url + '">' + context.body + '</a>';
});
const post = { url: "/hello-world", body: "Hello World!" };
const context2 = { posts: [post] };
const source2 = '<ul>{{#posts}}<li>{{{link_to this}}}</li>{{/posts}}</ul>';
const template2: HandlebarsTemplateDelegate<{ posts: { url: string, body: string }[] }> = Handlebars.compile(source2);
template2(context2);
Handlebars.registerHelper('link_to', (title: string, context: typeof post) => {
return '<a href="/posts' + context.url + '">' + title + '!</a>';
});
const context3 = { posts: [{url: '/hello-world', body: 'Hello World!'}] };
const source3 = '<ul>{{#posts}}<li>{{{link_to "Post" this}}}</li>{{/posts}}</ul>';
const template3 = Handlebars.compile<typeof context3>(source3);
template3(context3);
const source4 = '<ul>{{#people}}<li>{{#link}}{{name}}{{/link}}</li>{{/people}}</ul>';
Handlebars.registerHelper('link', function(this: any, context: any) {
return '<a href="/people/' + this.id + '">' + context.fn(this) + '</a>';
});
const template4 = Handlebars.compile<{ people: { name: string, id: number }[] }>(source4);
const data2 = { 'people': [
{ 'name': 'Alan', 'id': 1 },
{ 'name': 'Yehuda', 'id': 2 }
]};
template4(data2);
const source5 = '<ul>{{#people}}<li>{{> link}}</li>{{/people}}</ul>';
Handlebars.registerPartial('link', '<a href="/people/{{id}}">{{name}}</a>');
const template5 = Handlebars.compile(source5);
const data3 = { 'people': [
{ 'name': 'Alan', 'id': 1 },
{ 'name': 'Yehuda', 'id': 2 }
]};
template5(data3);
const source6 = '{{#list nav}}<a href="{{url}}">{{title}}</a>{{/list}}';
const template6 = Handlebars.compile(source6);
Handlebars.registerHelper('list', (context, options: Handlebars.HelperOptions) => {
let ret = "<ul>";
for(let i=0, j=context.length; i<j; i++) {
ret = ret + "<li>" + options.fn(context[i]) + "</li>";
}
return ret + "</ul>";
});
template6([{url:"", title:""}]);
const escapedExpression = Handlebars.Utils.escapeExpression('<script>alert(\'xss\');</script>');
Handlebars.helpers !== undefined;
const parsedTmpl = Handlebars.parse('<p>Hello, my name is {{name}}.</p>', {
srcName: "/foo/bar/baz.hbs",
ignoreStandalone: true
});
const parsedTmplWithoutOptions = Handlebars.parse('<p>Hello, my name is {{name}}.</p>');
// Custom partial resolution.
const originalResolvePartial = Handlebars.VM.resolvePartial;
Handlebars.VM.resolvePartial = <T>(partial: HandlebarsTemplateDelegate<T> | undefined, context: any, options: Handlebars.ResolvePartialOptions): HandlebarsTemplateDelegate<T> => {
const name = options.name.replace(/my/,'your');
// transform name.
options.name = name;
return originalResolvePartial(partial, context, options);
};
// #1544, allow custom helpers in knownHelpers
Handlebars.compile('test', {
knownHelpers: {
each: true,
customHelper: true
}
});
Handlebars.compile('test')({},{allowCallsToHelperMissing: true});
Handlebars.compile('test')({},{});
-16
View File
@@ -1,16 +0,0 @@
{
"compilerOptions": {
"module": "commonjs",
"lib": ["es6"],
"noImplicitAny": true,
"noImplicitThis": true,
"strictNullChecks": true,
"strictFunctionTypes": true,
"noEmit": true,
"baseUrl": ".",
"paths": {
"handlebars": ["."]
}
}
}
-79
View File
@@ -1,79 +0,0 @@
{
"extends": "dtslint/dtslint.json",
"rules": {
"adjacent-overload-signatures": false,
"array-type": false,
"arrow-return-shorthand": false,
"ban-types": false,
"callable-types": false,
"comment-format": false,
"dt-header": false,
"eofline": false,
"export-just-namespace": false,
"import-spacing": false,
"interface-name": false,
"interface-over-type-literal": false,
"jsdoc-format": false,
"max-line-length": false,
"member-access": false,
"new-parens": false,
"no-any-union": false,
"no-boolean-literal-compare": false,
"no-conditional-assignment": false,
"no-consecutive-blank-lines": false,
"no-construct": false,
"no-declare-current-package": false,
"no-duplicate-imports": false,
"no-duplicate-variable": false,
"no-empty-interface": false,
"no-for-in-array": false,
"no-inferrable-types": false,
"no-internal-module": false,
"no-irregular-whitespace": false,
"no-mergeable-namespace": false,
"no-misused-new": false,
"no-namespace": false,
"no-object-literal-type-assertion": false,
"no-padding": false,
"no-redundant-jsdoc": false,
"no-redundant-jsdoc-2": false,
"no-redundant-undefined": false,
"no-reference-import": false,
"no-relative-import-in-test": false,
"no-self-import": false,
"no-single-declare-module": false,
"no-string-throw": false,
"no-unnecessary-callback-wrapper": false,
"no-unnecessary-class": false,
"no-unnecessary-generics": false,
"no-unnecessary-qualifier": false,
"no-unnecessary-type-assertion": false,
"no-useless-files": false,
"no-var-keyword": false,
"no-var-requires": false,
"no-void-expression": false,
"no-trailing-whitespace": false,
"object-literal-key-quotes": false,
"object-literal-shorthand": false,
"one-line": false,
"one-variable-per-declaration": false,
"only-arrow-functions": false,
"prefer-conditional-expression": false,
"prefer-const": false,
"prefer-declare-function": false,
"prefer-for-of": false,
"prefer-method-signature": false,
"prefer-template": false,
"radix": false,
"semicolon": false,
"space-before-function-paren": false,
"space-within-parens": false,
"strict-export-declare-modifiers": false,
"trim-file": false,
"triple-equals": false,
"typedef-whitespace": false,
"unified-signatures": false,
"void-return": false,
"whitespace": false
}
}