Compare commits
6 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 51892c296e | |||
| c5b699db00 | |||
| ee4dd7d4bf | |||
| 4801f649df | |||
| 9888569dcb | |||
| 1ade5a0892 |
+1
-24
@@ -1,25 +1,2 @@
|
|||||||
.rvmrc
|
dist
|
||||||
.DS_Store
|
|
||||||
/tmp/
|
|
||||||
*.sublime-project
|
|
||||||
*.sublime-workspace
|
|
||||||
npm-debug.log
|
|
||||||
sauce_connect.log*
|
|
||||||
.idea
|
|
||||||
yarn-error.log
|
|
||||||
node_modules
|
node_modules
|
||||||
/handlebars-release.tgz
|
|
||||||
.nyc_output
|
|
||||||
|
|
||||||
# Generated files
|
|
||||||
lib/handlebars/compiler/parser.js
|
|
||||||
/coverage/
|
|
||||||
/dist/
|
|
||||||
/integration-testing/*/dist/
|
|
||||||
|
|
||||||
# Third-party or files that must remain unchanged
|
|
||||||
/spec/expected/
|
|
||||||
/spec/vendor
|
|
||||||
|
|
||||||
# JS-Snippets
|
|
||||||
src/*.js
|
|
||||||
|
|||||||
+103
-50
@@ -1,66 +1,119 @@
|
|||||||
module.exports = {
|
module.exports = {
|
||||||
extends: ['eslint:recommended', 'plugin:compat/recommended', 'prettier'],
|
"extends": ["eslint:recommended","plugin:compat/recommended"],
|
||||||
globals: {
|
"globals": {
|
||||||
self: false
|
"self": false,
|
||||||
|
"SOURCE_MAPS": true
|
||||||
},
|
},
|
||||||
env: {
|
"env": {
|
||||||
node: true,
|
"node": true,
|
||||||
es6: true
|
"es6": true
|
||||||
},
|
},
|
||||||
rules: {
|
"rules": {
|
||||||
'no-console': 'warn',
|
// 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",
|
||||||
|
|
||||||
// temporarily disabled until the violating places are fixed.
|
|
||||||
'no-func-assign': 'off',
|
|
||||||
'no-sparse-arrays': 'off',
|
|
||||||
|
|
||||||
// Best Practices //
|
// Best Practices //
|
||||||
//----------------//
|
//----------------//
|
||||||
'default-case': 'warn',
|
"curly": "error",
|
||||||
'guard-for-in': 'warn',
|
"default-case": "warn",
|
||||||
'no-alert': 'error',
|
"dot-notation": ["error", { "allowKeywords": false }],
|
||||||
'no-caller': 'error',
|
"guard-for-in": "warn",
|
||||||
'no-div-regex': 'warn',
|
"no-alert": "error",
|
||||||
'no-eval': 'error',
|
"no-caller": "error",
|
||||||
'no-extend-native': 'error',
|
"no-div-regex": "warn",
|
||||||
'no-extra-bind': 'error',
|
"no-eval": "error",
|
||||||
'no-floating-decimal': 'error',
|
"no-extend-native": "error",
|
||||||
'no-implied-eval': 'error',
|
"no-extra-bind": "error",
|
||||||
'no-iterator': 'error',
|
"no-floating-decimal": "error",
|
||||||
'no-labels': 'error',
|
"no-implied-eval": "error",
|
||||||
'no-lone-blocks': 'error',
|
"no-iterator": "error",
|
||||||
'no-loop-func': 'error',
|
"no-labels": "error",
|
||||||
'no-multi-str': 'warn',
|
"no-lone-blocks": "error",
|
||||||
'no-global-assign': 'error',
|
"no-loop-func": "error",
|
||||||
'no-new': 'error',
|
"no-multi-spaces": "error",
|
||||||
'no-new-func': 'error',
|
"no-multi-str": "warn",
|
||||||
'no-new-wrappers': 'error',
|
"no-global-assign": "error",
|
||||||
'no-octal-escape': 'error',
|
"no-new": "error",
|
||||||
'no-process-env': 'error',
|
"no-new-func": "error",
|
||||||
'no-proto': 'error',
|
"no-new-wrappers": "error",
|
||||||
'no-return-assign': 'error',
|
"no-octal-escape": "error",
|
||||||
'no-script-url': 'error',
|
"no-process-env": "error",
|
||||||
'no-self-compare': 'error',
|
"no-proto": "error",
|
||||||
'no-sequences': 'error',
|
"no-return-assign": "error",
|
||||||
'no-throw-literal': 'error',
|
"no-script-url": "error",
|
||||||
'no-unused-expressions': 'error',
|
"no-self-compare": "error",
|
||||||
'no-warning-comments': 'warn',
|
"no-sequences": "error",
|
||||||
'no-with': 'error',
|
"no-throw-literal": "error",
|
||||||
radix: 'error',
|
"no-unused-expressions": "error",
|
||||||
|
"no-warning-comments": "warn",
|
||||||
|
"no-with": "error",
|
||||||
|
"radix": "error",
|
||||||
|
"wrap-iife": "error",
|
||||||
|
"no-prototype-builtins": "error",
|
||||||
|
|
||||||
|
|
||||||
// Variables //
|
// Variables //
|
||||||
//-----------//
|
//-----------//
|
||||||
'no-label-var': 'error',
|
"no-catch-shadow": "error",
|
||||||
'no-undef-init': 'error',
|
"no-label-var": "error",
|
||||||
'no-use-before-define': ['error', 'nofunc'],
|
"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 //
|
// ECMAScript 6 //
|
||||||
//--------------//
|
//--------------//
|
||||||
'no-var': 'error'
|
"no-var": "warn"
|
||||||
},
|
},
|
||||||
parserOptions: {
|
"parserOptions": {
|
||||||
sourceType: 'module',
|
"sourceType": "module",
|
||||||
ecmaVersion: 2018,
|
"ecmaVersion": 6,
|
||||||
ecmaFeatures: {}
|
"ecmaFeatures": {}
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|||||||
+6
-11
@@ -1,20 +1,15 @@
|
|||||||
|
vendor
|
||||||
.rvmrc
|
.rvmrc
|
||||||
.DS_Store
|
.DS_Store
|
||||||
|
lib/handlebars/compiler/parser.js
|
||||||
|
/dist/
|
||||||
/tmp/
|
/tmp/
|
||||||
|
/coverage/
|
||||||
|
node_modules
|
||||||
*.sublime-project
|
*.sublime-project
|
||||||
*.sublime-workspace
|
*.sublime-workspace
|
||||||
npm-debug.log
|
npm-debug.log
|
||||||
sauce_connect.log*
|
sauce_connect.log*
|
||||||
.idea
|
.idea
|
||||||
/yarn-error.log
|
yarn-error.log
|
||||||
/yarn.lock
|
|
||||||
node_modules
|
|
||||||
/handlebars-release.tgz
|
/handlebars-release.tgz
|
||||||
.nyc_output
|
|
||||||
|
|
||||||
# Generated files
|
|
||||||
lib/handlebars/compiler/parser.js
|
|
||||||
/coverage/
|
|
||||||
/dist/
|
|
||||||
/integration-testing/*/dist/
|
|
||||||
/spec/tmp/*
|
|
||||||
@@ -0,0 +1,2 @@
|
|||||||
|
instrumentation:
|
||||||
|
excludes: ['**/spec/**', '**/handlebars/compiler/parser.js']
|
||||||
@@ -1,22 +0,0 @@
|
|||||||
.rvmrc
|
|
||||||
.DS_Store
|
|
||||||
/tmp/
|
|
||||||
*.sublime-project
|
|
||||||
*.sublime-workspace
|
|
||||||
npm-debug.log
|
|
||||||
sauce_connect.log*
|
|
||||||
.idea
|
|
||||||
yarn-error.log
|
|
||||||
node_modules
|
|
||||||
/handlebars-release.tgz
|
|
||||||
.nyc_output
|
|
||||||
|
|
||||||
# Generated files
|
|
||||||
lib/handlebars/compiler/parser.js
|
|
||||||
/coverage/
|
|
||||||
/dist/
|
|
||||||
/integration-testing/*/dist/
|
|
||||||
|
|
||||||
# Third-party or files that must remain unchanged
|
|
||||||
/spec/expected/
|
|
||||||
/spec/vendor
|
|
||||||
+20
-33
@@ -1,39 +1,26 @@
|
|||||||
language: node_js
|
language: node_js
|
||||||
jobs:
|
before_install:
|
||||||
include:
|
- npm install -g grunt-cli
|
||||||
- stage: test
|
script:
|
||||||
name: check javascript (eslint)
|
- grunt --stack travis
|
||||||
node_js: lts/*
|
|
||||||
script: npm run lint
|
|
||||||
- stage: test
|
|
||||||
name: check formatting (prettier)
|
|
||||||
node_js: lts/*
|
|
||||||
script: npm run check-format
|
|
||||||
- stage: test
|
|
||||||
name: check typescript definitions (dtslint)
|
|
||||||
node_js: lts/*
|
|
||||||
script: npm run dtslint
|
|
||||||
- stage: test
|
|
||||||
name: extensive tests and publish to aws
|
|
||||||
script: npm run extensive-tests-and-publish-to-aws
|
|
||||||
env:
|
|
||||||
- S3_BUCKET_NAME=builds.handlebarsjs.com
|
|
||||||
- secure: ckyEe5dzjdFDjmZ6wIrhGm0CFBEnKq8c1dYptfgVV/Q5/nJFGzu8T0yTjouS/ERxzdT2H327/63VCxhFnLCRHrsh4rlW/rCy4XI3O/0TeMLgFPa4TXkO8359qZ4CB44TBb3NsJyQXNMYdJpPLTCVTMpuiqqkFFOr+6OeggR7ufA=
|
|
||||||
- secure: Nm4AgSfsgNB21kgKrF9Tl7qVZU8YYREhouQunFracTcZZh2NZ2XH5aHuSiXCj88B13Cr/jGbJKsZ4T3QS3wWYtz6lkyVOx3H3iI+TMtqhD9RM3a7A4O+4vVN8IioB2YjhEu0OKjwgX5gp+0uF+pLEi7Hpj6fupD3AbbL5uYcKg8=
|
|
||||||
- SAUCE_USERNAME=handlebars
|
|
||||||
- secure: 1VkLQhbsEug4ZMQ52tTOus/WLvW3Etqe7GbCzZfzsI8d2ygJPjFfzU8fNm4pVVwoTI21MaM5AQq7SVPu8DWN1YbDjJycMdY1zO3DsB9aZBxTal98fIB7ZIUce9r5z2EP6mETrsbYjZkeckzIBI0A4UVa+F2BO4KbRDXP1Db3u3I=
|
|
||||||
node_js: '10'
|
|
||||||
- stage: test
|
|
||||||
name: test with latest nodejs-lts
|
|
||||||
node_js: lts/*
|
|
||||||
script: npm run test
|
|
||||||
- stage: test
|
|
||||||
name: test with active nodejs
|
|
||||||
node_js: node
|
|
||||||
script: npm run test
|
|
||||||
cache: npm
|
|
||||||
email:
|
email:
|
||||||
on_failure: change
|
on_failure: change
|
||||||
on_success: never
|
on_success: never
|
||||||
|
env:
|
||||||
|
global:
|
||||||
|
- S3_BUCKET_NAME=builds.handlebarsjs.com
|
||||||
|
- secure: ckyEe5dzjdFDjmZ6wIrhGm0CFBEnKq8c1dYptfgVV/Q5/nJFGzu8T0yTjouS/ERxzdT2H327/63VCxhFnLCRHrsh4rlW/rCy4XI3O/0TeMLgFPa4TXkO8359qZ4CB44TBb3NsJyQXNMYdJpPLTCVTMpuiqqkFFOr+6OeggR7ufA=
|
||||||
|
- secure: Nm4AgSfsgNB21kgKrF9Tl7qVZU8YYREhouQunFracTcZZh2NZ2XH5aHuSiXCj88B13Cr/jGbJKsZ4T3QS3wWYtz6lkyVOx3H3iI+TMtqhD9RM3a7A4O+4vVN8IioB2YjhEu0OKjwgX5gp+0uF+pLEi7Hpj6fupD3AbbL5uYcKg8=
|
||||||
|
matrix:
|
||||||
|
include:
|
||||||
|
- node_js: '10'
|
||||||
|
env:
|
||||||
|
- PUBLISH=true
|
||||||
|
- secure: pLTzghtVll9yGKJI0AaB0uI8GypfWxLTaIB0ZL8//yN3nAEIKMhf/RRilYTsn/rKj2NUa7vt2edYILi3lttOUlCBOwTc9amiRms1W8Lwr/3IdWPeBLvLuH1zNJRm2lBAwU4LBSqaOwhGaxOQr6KHTnWudhNhgOucxpZfvfI/dFw=
|
||||||
|
- secure: yERYCf7AwL11D9uMtacly/THGV8BlzsMmrt+iQVvGA3GaY6QMmfYqf6P6cCH98sH5etd1Y+1e6YrPeMjqI6lyRllT7FptoyOdHulazQe86VQN4sc0EpqMlH088kB7gGjTut9Z+X9ViooT5XEh9WA5jXEI9pXhQJNoIHkWPuwGuY=
|
||||||
|
cache:
|
||||||
|
directories:
|
||||||
|
- node_modules
|
||||||
|
|
||||||
git:
|
git:
|
||||||
depth: 100
|
depth: 100
|
||||||
|
|||||||
+20
-42
@@ -12,8 +12,8 @@ Documentation issues on the handlebarsjs.com site should be reported on [handleb
|
|||||||
|
|
||||||
## Branches
|
## Branches
|
||||||
|
|
||||||
- The branch `4.x` contains the currently released version. Bugfixes should be made in this branch.
|
* 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
|
* 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.
|
should merge the branch `4.x` into the master branch regularly.
|
||||||
|
|
||||||
## Pull Requests
|
## Pull Requests
|
||||||
@@ -21,7 +21,6 @@ Documentation issues on the handlebarsjs.com site should be reported on [handleb
|
|||||||
We also accept [pull requests][pull-request]!
|
We also accept [pull requests][pull-request]!
|
||||||
|
|
||||||
Generally we like to see pull requests that
|
Generally we like to see pull requests that
|
||||||
|
|
||||||
- Maintain the existing code style
|
- Maintain the existing code style
|
||||||
- Are focused on a single change (i.e. avoid large refactoring or style adjustments in untouched code if not the primary goal of the pull request)
|
- Are focused on a single change (i.e. avoid large refactoring or style adjustments in untouched code if not the primary goal of the pull request)
|
||||||
- Have [good commit messages](http://tbaggery.com/2008/04/19/a-note-about-git-commit-messages.html)
|
- Have [good commit messages](http://tbaggery.com/2008/04/19/a-note-about-git-commit-messages.html)
|
||||||
@@ -32,8 +31,8 @@ Generally we like to see pull requests that
|
|||||||
|
|
||||||
To build Handlebars.js you'll need a few things installed.
|
To build Handlebars.js you'll need a few things installed.
|
||||||
|
|
||||||
- Node.js
|
* Node.js
|
||||||
- [Grunt](http://gruntjs.com/getting-started)
|
* [Grunt](http://gruntjs.com/getting-started)
|
||||||
|
|
||||||
Before building, you need to make sure that the Git submodule `spec/mustache` is included (i.e. the directory `spec/mustache` should not be empty). To include it, if using Git version 1.6.5 or newer, use `git clone --recursive` rather than `git clone`. Or, if you already cloned without `--recursive`, use `git submodule update --init`.
|
Before building, you need to make sure that the Git submodule `spec/mustache` is included (i.e. the directory `spec/mustache` should not be empty). To include it, if using Git version 1.6.5 or newer, use `git clone --recursive` rather than `git clone`. Or, if you already cloned without `--recursive`, use `git submodule update --init`.
|
||||||
|
|
||||||
@@ -52,13 +51,11 @@ If you notice any problems, please report them to the GitHub issue tracker at
|
|||||||
##Running Tests
|
##Running Tests
|
||||||
|
|
||||||
To run tests locally, first install all dependencies.
|
To run tests locally, first install all dependencies.
|
||||||
|
|
||||||
```sh
|
```sh
|
||||||
npm install
|
npm install
|
||||||
```
|
```
|
||||||
|
|
||||||
Clone the mustache specs into the spec/mustache folder.
|
Clone the mustache specs into the spec/mustache folder.
|
||||||
|
|
||||||
```sh
|
```sh
|
||||||
cd spec
|
cd spec
|
||||||
rm -r mustache
|
rm -r mustache
|
||||||
@@ -66,40 +63,27 @@ git clone https://github.com/mustache/spec.git mustache
|
|||||||
```
|
```
|
||||||
|
|
||||||
From the root directory, run the tests.
|
From the root directory, run the tests.
|
||||||
|
|
||||||
```sh
|
```sh
|
||||||
npm test
|
npm test
|
||||||
```
|
```
|
||||||
|
|
||||||
## Linting and Formatting
|
## Ember testing
|
||||||
|
|
||||||
Handlebars uses `eslint` to enforce best-practices and `prettier` to auto-format files.
|
The current ember distribution should be tested as part of the handlebars release process. This requires building the `handlebars-source` gem locally and then executing the ember test script.
|
||||||
We do linting and formatting in two phases:
|
|
||||||
|
|
||||||
- Committed files are linted and formatted in a pre-commit hook. In this stage eslint-errors are forbidden,
|
```sh
|
||||||
while warnings are allowed.
|
npm link
|
||||||
- The travis-ci job also lints all files and checks if they are formatted correctly. In this stage, warnings
|
grunt build release
|
||||||
are forbidden.
|
cp dist/*.js $emberRepoDir/bower_components/handlebars/
|
||||||
|
|
||||||
You can use the following scripts to make sure that the travis-job does not fail:
|
cd $emberRepoDir
|
||||||
|
npm link handlebars
|
||||||
- **npm run lint** will run `eslint` and fail on warnings
|
npm test
|
||||||
- **npm run format** will run `prettier` on all files
|
```
|
||||||
- **npm run check-before-pull-request** will perform all most checks that travis does in its build-job, excluding the "integration-test".
|
|
||||||
- **npm run integration-test** will run integration tests (using old NodeJS versions and integrations with webpack, babel and so on)
|
|
||||||
These tests only work on a Linux-machine with `nvm` installed (for running tests in multiple versions of NodeJS).
|
|
||||||
|
|
||||||
## Releasing the latest version
|
## Releasing the latest version
|
||||||
|
|
||||||
Before attempting the release Handlebars, please make sure that you have the following authorizations:
|
*When releasing a previous version of Handlebars, please look into the CONTRIBUNG.md in the corresponding branch.*
|
||||||
|
|
||||||
- Push-access to `wycats/handlebars.js`
|
|
||||||
- Publishing rights on npmjs.com for the `handlebars` package
|
|
||||||
- Publishing rights on gemfury for the `handlebars-source` package
|
|
||||||
- Push-access to the repo for legacy package managers: `components/handlebars`
|
|
||||||
- Push-access to the production-repo of the handlebars site: `handlebars-lang/handlebarsjs.com-github-pages`
|
|
||||||
|
|
||||||
_When releasing a previous version of Handlebars, please look into the CONTRIBUNG.md in the corresponding branch._
|
|
||||||
|
|
||||||
Handlebars utilizes the [release yeoman generator][generator-release] to perform most release tasks.
|
Handlebars utilizes the [release yeoman generator][generator-release] to perform most release tasks.
|
||||||
|
|
||||||
@@ -119,18 +103,12 @@ gem push handlebars-source-*.gem
|
|||||||
After the release, you should check that all places have really been updated. Especially verify that the `latest`-tags
|
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
|
in those places still point to the latest version
|
||||||
|
|
||||||
- [The npm-package](https://www.npmjs.com/package/handlebars) (check latest-tag)
|
* [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 bower package](https://github.com/components/handlebars.js) (check the package.json)
|
||||||
- [The AWS S3 Bucket](https://s3.amazonaws.com/builds.handlebarsjs.com) (check latest-tag)
|
* [The AWS S3 Bucket](https://s3.amazonaws.com/builds.handlebarsjs.com) (check latest-tag)
|
||||||
- [RubyGems](https://rubygems.org/gems/handlebars-source)
|
* [RubyGems](https://rubygems.org/gems/handlebars-source)
|
||||||
|
|
||||||
When everything is OK, the **handlebars site** needs to be updated.
|
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.
|
||||||
|
|
||||||
Go to the master branch of the repo [handlebars-lang/handlebarsjs.com-github-pages](https://github.com/handlebars-lang/handlebarsjs.com-github-pages/tree/master)
|
|
||||||
and make a minimal change to the README. This will invoke a github-action that redeploys
|
|
||||||
the site, fetching the latest version-number from the npm-registry.
|
|
||||||
(note that the default-branch of this repo is not the master and regular changes are done
|
|
||||||
in the `handlebars-lang/docs`-repo).
|
|
||||||
|
|
||||||
[generator-release]: https://github.com/walmartlabs/generator-release
|
[generator-release]: https://github.com/walmartlabs/generator-release
|
||||||
[pull-request]: https://github.com/wycats/handlebars.js/pull/new/master
|
[pull-request]: https://github.com/wycats/handlebars.js/pull/new/master
|
||||||
|
|||||||
+91
-220
@@ -1,151 +1,82 @@
|
|||||||
/* eslint-disable no-process-env */
|
/* eslint-disable no-process-env */
|
||||||
module.exports = function(grunt) {
|
module.exports = function(grunt) {
|
||||||
|
|
||||||
grunt.initConfig({
|
grunt.initConfig({
|
||||||
pkg: grunt.file.readJSON('package.json'),
|
pkg: grunt.file.readJSON('package.json'),
|
||||||
|
|
||||||
clean: [
|
eslint: {
|
||||||
'tmp',
|
files: [
|
||||||
'dist',
|
'*.js',
|
||||||
'lib/handlebars/compiler/parser.js',
|
'bench/**/*.js',
|
||||||
'integration-testing/**/node_modules'
|
'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'
|
||||||
|
]
|
||||||
|
},
|
||||||
|
|
||||||
|
clean: ['tmp', 'dist', 'lib/handlebars/compiler/parser.js', 'integration-testing/**/node_modules'],
|
||||||
|
|
||||||
copy: {
|
copy: {
|
||||||
dist: {
|
dist: {
|
||||||
options: {
|
options: {
|
||||||
processContent: function(content) {
|
processContent: function(content) {
|
||||||
return (
|
return grunt.template.process('/**!\n\n @license\n <%= pkg.name %> v<%= pkg.version %>\n\n<%= grunt.file.read("LICENSE") %>\n*/\n')
|
||||||
grunt.template.process(
|
+ content;
|
||||||
'/**!\n\n @license\n <%= pkg.name %> v<%= pkg.version %>\n\n<%= grunt.file.read("LICENSE") %>\n*/\n'
|
|
||||||
) + content
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
files: [{ expand: true, cwd: 'dist/', src: ['*.js'], dest: 'dist/' }]
|
files: [
|
||||||
|
{expand: true, cwd: 'dist/', src: ['*.js'], dest: 'dist/'}
|
||||||
|
]
|
||||||
},
|
},
|
||||||
cdnjs: {
|
cdnjs: {
|
||||||
files: [
|
files: [
|
||||||
{ expand: true, cwd: 'dist/', src: ['*.js'], dest: 'dist/cdnjs' }
|
{expand: true, cwd: 'dist/', src: ['*.js'], dest: 'dist/cdnjs'}
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
components: {
|
components: {
|
||||||
files: [
|
files: [
|
||||||
{
|
{expand: true, cwd: 'components/', src: ['**'], dest: 'dist/components'},
|
||||||
expand: true,
|
{expand: true, cwd: 'dist/', src: ['*.js'], dest: 'dist/components'}
|
||||||
cwd: 'components/',
|
|
||||||
src: ['**'],
|
|
||||||
dest: 'dist/components'
|
|
||||||
},
|
|
||||||
{ expand: true, cwd: 'dist/', src: ['*.js'], dest: 'dist/components' }
|
|
||||||
]
|
|
||||||
}
|
|
||||||
},
|
|
||||||
|
|
||||||
babel: {
|
|
||||||
options: {
|
|
||||||
sourceMaps: 'inline',
|
|
||||||
loose: ['es6.modules'],
|
|
||||||
auxiliaryCommentBefore: 'istanbul ignore next'
|
|
||||||
},
|
|
||||||
amd: {
|
|
||||||
options: {
|
|
||||||
modules: 'amd'
|
|
||||||
},
|
|
||||||
files: [
|
|
||||||
{
|
|
||||||
expand: true,
|
|
||||||
cwd: 'lib/',
|
|
||||||
src: '**/!(index).js',
|
|
||||||
dest: 'dist/amd/'
|
|
||||||
}
|
|
||||||
]
|
|
||||||
},
|
|
||||||
|
|
||||||
cjs: {
|
|
||||||
options: {
|
|
||||||
modules: 'common'
|
|
||||||
},
|
|
||||||
files: [
|
|
||||||
{
|
|
||||||
cwd: 'lib/',
|
|
||||||
expand: true,
|
|
||||||
src: '**/!(index).js',
|
|
||||||
dest: 'dist/cjs/'
|
|
||||||
}
|
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
webpack: {
|
webpack: {
|
||||||
|
build: require('./webpack.config')
|
||||||
|
},
|
||||||
|
babel: {
|
||||||
options: {
|
options: {
|
||||||
context: __dirname,
|
sourceMaps: 'inline',
|
||||||
module: {
|
auxiliaryCommentBefore: 'istanbul ignore next'
|
||||||
loaders: [
|
},
|
||||||
// the optional 'runtime' transformer tells babel to require the runtime instead of inlining it.
|
amd: {
|
||||||
{
|
options: {
|
||||||
test: /\.jsx?$/,
|
plugins: ['@babel/plugin-transform-modules-amd']
|
||||||
exclude: /node_modules/,
|
},
|
||||||
loader:
|
files: [{
|
||||||
'babel-loader?optional=runtime&loose=es6.modules&auxiliaryCommentBefore=istanbul%20ignore%20next'
|
expand: true,
|
||||||
}
|
cwd: 'lib/',
|
||||||
|
src: '**/!(index).js',
|
||||||
|
dest: 'dist/amd/'
|
||||||
|
}]
|
||||||
|
},
|
||||||
|
|
||||||
|
cjs: {
|
||||||
|
options: {
|
||||||
|
plugins: [
|
||||||
|
'@babel/plugin-transform-modules-commonjs',
|
||||||
|
// support "import * as Handlebars" for backward-compatibility
|
||||||
|
'babel-plugin-add-module-exports'
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
output: {
|
files: [{
|
||||||
path: 'dist/',
|
cwd: 'lib/',
|
||||||
library: 'Handlebars',
|
expand: true,
|
||||||
libraryTarget: 'umd'
|
src: '**/!(index).js',
|
||||||
}
|
dest: 'dist/cjs/'
|
||||||
},
|
}]
|
||||||
handlebars: {
|
|
||||||
entry: './lib/handlebars.js',
|
|
||||||
output: {
|
|
||||||
filename: 'handlebars.js'
|
|
||||||
}
|
|
||||||
},
|
|
||||||
runtime: {
|
|
||||||
entry: './lib/handlebars.runtime.js',
|
|
||||||
output: {
|
|
||||||
filename: 'handlebars.runtime.js'
|
|
||||||
}
|
|
||||||
}
|
|
||||||
},
|
|
||||||
|
|
||||||
requirejs: {
|
|
||||||
options: {
|
|
||||||
optimize: 'none',
|
|
||||||
baseUrl: 'dist/amd/'
|
|
||||||
},
|
|
||||||
dist: {
|
|
||||||
options: {
|
|
||||||
name: 'handlebars',
|
|
||||||
out: 'dist/handlebars.amd.js'
|
|
||||||
}
|
|
||||||
},
|
|
||||||
runtime: {
|
|
||||||
options: {
|
|
||||||
name: 'handlebars.runtime',
|
|
||||||
out: 'dist/handlebars.runtime.amd.js'
|
|
||||||
}
|
|
||||||
}
|
|
||||||
},
|
|
||||||
|
|
||||||
uglify: {
|
|
||||||
options: {
|
|
||||||
mangle: true,
|
|
||||||
compress: true,
|
|
||||||
preserveComments: /(?:^!|@(?:license|preserve|cc_on))/
|
|
||||||
},
|
|
||||||
dist: {
|
|
||||||
files: [
|
|
||||||
{
|
|
||||||
cwd: 'dist/',
|
|
||||||
expand: true,
|
|
||||||
src: ['handlebars*.js', '!*.min.js'],
|
|
||||||
dest: 'dist/',
|
|
||||||
rename: function(dest, src) {
|
|
||||||
return dest + src.replace(/\.js$/, '.min.js');
|
|
||||||
}
|
|
||||||
}
|
|
||||||
]
|
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
@@ -165,78 +96,48 @@ module.exports = function(grunt) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
karma: {
|
|
||||||
options: {
|
|
||||||
configFile: 'karma.conf.js'
|
|
||||||
},
|
|
||||||
saucelabs: {
|
|
||||||
build: process.env.TRAVIS_JOB_ID || 'non-travis',
|
|
||||||
configFile: 'karma-setup/default/karma.conf.js',
|
|
||||||
...require('./karma-setup/shared/saucelabs'),
|
|
||||||
singleRun: true
|
|
||||||
},
|
|
||||||
default: {
|
|
||||||
browsers: [],
|
|
||||||
configFile: 'karma-setup/default/karma.conf.js',
|
|
||||||
singleRun: false,
|
|
||||||
autoWatch: true
|
|
||||||
},
|
|
||||||
amd: {
|
|
||||||
configFile: 'karma-setup/amd/karma.conf.js',
|
|
||||||
browsers: [],
|
|
||||||
singleRun: false,
|
|
||||||
autoWatch: true
|
|
||||||
}
|
|
||||||
},
|
|
||||||
'saucelabs-mocha': {
|
'saucelabs-mocha': {
|
||||||
all: {
|
all: {
|
||||||
options: {
|
options: {
|
||||||
build: process.env.TRAVIS_JOB_ID,
|
build: process.env.TRAVIS_JOB_ID,
|
||||||
urls: [
|
urls: ['http://localhost:9999/spec/?headless=true', 'http://localhost:9999/spec/amd.html?headless=true'],
|
||||||
'http://localhost:9999/spec/?headless=true',
|
|
||||||
'http://localhost:9999/spec/amd.html?headless=true'
|
|
||||||
],
|
|
||||||
detailedError: true,
|
detailedError: true,
|
||||||
concurrency: 4,
|
concurrency: 4,
|
||||||
browsers: [
|
browsers: [
|
||||||
{ browserName: 'chrome' },
|
{browserName: 'chrome'},
|
||||||
{ browserName: 'firefox', platform: 'Linux' },
|
{browserName: 'firefox', platform: 'Linux'},
|
||||||
{ browserName: 'safari', version: 9, platform: 'OS X 10.11' },
|
// {browserName: 'safari', version: 9, platform: 'OS X 10.11'},
|
||||||
{ browserName: 'safari', version: 8, platform: 'OS X 10.10' },
|
// {browserName: 'safari', version: 8, platform: 'OS X 10.10'},
|
||||||
{
|
{browserName: 'internet explorer', version: 11, platform: 'Windows 8.1'},
|
||||||
browserName: 'internet explorer',
|
{browserName: 'internet explorer', version: 10, platform: 'Windows 8'}
|
||||||
version: 11,
|
|
||||||
platform: 'Windows 8.1'
|
|
||||||
},
|
|
||||||
{
|
|
||||||
browserName: 'internet explorer',
|
|
||||||
version: 10,
|
|
||||||
platform: 'Windows 8'
|
|
||||||
}
|
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
sanity: {
|
sanity: {
|
||||||
options: {
|
options: {
|
||||||
build: process.env.TRAVIS_JOB_ID,
|
build: process.env.TRAVIS_JOB_ID,
|
||||||
urls: [
|
urls: ['http://localhost:9999/spec/umd.html?headless=true', 'http://localhost:9999/spec/amd-runtime.html?headless=true', 'http://localhost:9999/spec/umd-runtime.html?headless=true'],
|
||||||
'http://localhost:9999/spec/umd.html?headless=true',
|
|
||||||
'http://localhost:9999/spec/amd-runtime.html?headless=true',
|
|
||||||
'http://localhost:9999/spec/umd-runtime.html?headless=true'
|
|
||||||
],
|
|
||||||
detailedError: true,
|
detailedError: true,
|
||||||
concurrency: 2,
|
concurrency: 2,
|
||||||
browsers: [{ browserName: 'chrome' }]
|
browsers: [
|
||||||
|
{browserName: 'chrome'}
|
||||||
|
]
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
bgShell: {
|
bgShell: {
|
||||||
|
checkTypes: {
|
||||||
|
cmd: 'npm run checkTypes',
|
||||||
|
bg: false,
|
||||||
|
fail: true
|
||||||
|
},
|
||||||
integrationTests: {
|
integrationTests: {
|
||||||
cmd: './integration-testing/run-integration-tests.sh',
|
cmd: './integration-testing/run-integration-tests.sh',
|
||||||
bg: false,
|
bg: false,
|
||||||
fail: true
|
fail: true
|
||||||
}
|
}
|
||||||
|
|
||||||
},
|
},
|
||||||
|
|
||||||
watch: {
|
watch: {
|
||||||
@@ -246,76 +147,46 @@ module.exports = function(grunt) {
|
|||||||
},
|
},
|
||||||
|
|
||||||
files: ['src/*', 'lib/**/*.js', 'spec/**/*.js'],
|
files: ['src/*', 'lib/**/*.js', 'spec/**/*.js'],
|
||||||
tasks: ['on-file-change']
|
tasks: ['build', 'amd', 'tests', 'test']
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
// Build a new version of the library
|
||||||
|
this.registerTask('build', 'Builds a distributable version of the current project', [
|
||||||
|
'eslint',
|
||||||
|
'bgShell:checkTypes',
|
||||||
|
'parser',
|
||||||
|
'node',
|
||||||
|
'globals']);
|
||||||
|
|
||||||
|
this.registerTask('amd', ['babel:amd']);
|
||||||
|
this.registerTask('node', ['babel:cjs']);
|
||||||
|
this.registerTask('globals', ['webpack']);
|
||||||
|
this.registerTask('tests', ['concat:tests']);
|
||||||
|
|
||||||
|
this.registerTask('release', 'Build final packages', ['eslint', 'amd', 'test:min', 'copy:dist', 'copy:components', 'copy:cdnjs']);
|
||||||
|
|
||||||
// Load tasks from npm
|
// Load tasks from npm
|
||||||
grunt.loadNpmTasks('grunt-contrib-clean');
|
grunt.loadNpmTasks('grunt-contrib-clean');
|
||||||
grunt.loadNpmTasks('grunt-contrib-concat');
|
grunt.loadNpmTasks('grunt-contrib-concat');
|
||||||
grunt.loadNpmTasks('grunt-contrib-connect');
|
grunt.loadNpmTasks('grunt-contrib-connect');
|
||||||
grunt.loadNpmTasks('grunt-contrib-copy');
|
grunt.loadNpmTasks('grunt-contrib-copy');
|
||||||
grunt.loadNpmTasks('grunt-contrib-requirejs');
|
|
||||||
grunt.loadNpmTasks('grunt-contrib-uglify');
|
|
||||||
grunt.loadNpmTasks('grunt-contrib-watch');
|
grunt.loadNpmTasks('grunt-contrib-watch');
|
||||||
grunt.loadNpmTasks('grunt-babel');
|
grunt.loadNpmTasks('grunt-babel');
|
||||||
grunt.loadNpmTasks('grunt-bg-shell');
|
grunt.loadNpmTasks('grunt-bg-shell');
|
||||||
grunt.loadNpmTasks('grunt-karma');
|
grunt.loadNpmTasks('grunt-eslint');
|
||||||
|
grunt.loadNpmTasks('@knappi/grunt-saucelabs');
|
||||||
grunt.loadNpmTasks('grunt-webpack');
|
grunt.loadNpmTasks('grunt-webpack');
|
||||||
|
|
||||||
grunt.task.loadTasks('tasks');
|
grunt.task.loadTasks('tasks');
|
||||||
|
|
||||||
this.registerTask(
|
|
||||||
'build',
|
|
||||||
'Builds a distributable version of the current project',
|
|
||||||
['parser', 'node', 'globals']
|
|
||||||
);
|
|
||||||
|
|
||||||
this.registerTask('node', ['babel:cjs']);
|
|
||||||
this.registerTask('globals', ['webpack']);
|
|
||||||
|
|
||||||
this.registerTask('release', 'Build final packages', [
|
|
||||||
'amd',
|
|
||||||
'uglify',
|
|
||||||
'test:min',
|
|
||||||
'copy:dist',
|
|
||||||
'copy:components',
|
|
||||||
'copy:cdnjs'
|
|
||||||
]);
|
|
||||||
|
|
||||||
this.registerTask('amd', ['babel:amd', 'requirejs']);
|
|
||||||
|
|
||||||
this.registerTask('test', ['test:bin', 'test:cov']);
|
|
||||||
|
|
||||||
grunt.registerTask('bench', ['metrics']);
|
grunt.registerTask('bench', ['metrics']);
|
||||||
|
grunt.registerTask('sauce', process.env.SAUCE_USERNAME ? ['tests', 'connect', 'saucelabs-mocha'] : []);
|
||||||
|
|
||||||
if (process.env.SAUCE_ACCESS_KEY) {
|
grunt.registerTask('travis', process.env.PUBLISH ? ['default', 'bgShell:integrationTests', 'sauce', 'metrics', 'publish:latest'] : ['default']);
|
||||||
grunt.registerTask('sauce', ['karma:saucelabs']);
|
|
||||||
} else {
|
|
||||||
grunt.registerTask('sauce', []);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Requires secret properties (saucelabs-credentials etc.) from .travis.yaml
|
|
||||||
grunt.registerTask('extensive-tests-and-publish-to-aws', [
|
|
||||||
'default',
|
|
||||||
'bgShell:integrationTests',
|
|
||||||
'sauce',
|
|
||||||
'metrics',
|
|
||||||
'publish-to-aws'
|
|
||||||
]);
|
|
||||||
grunt.registerTask('on-file-change', [
|
|
||||||
'build',
|
|
||||||
'amd',
|
|
||||||
'concat:tests',
|
|
||||||
'test'
|
|
||||||
]);
|
|
||||||
|
|
||||||
// === Primary tasks ===
|
|
||||||
grunt.registerTask('dev', ['clean', 'connect', 'watch']);
|
grunt.registerTask('dev', ['clean', 'connect', 'watch']);
|
||||||
grunt.registerTask('default', ['clean', 'build', 'test', 'release']);
|
grunt.registerTask('default', ['clean', 'build', 'test', 'release']);
|
||||||
grunt.registerTask('integration-tests', [
|
grunt.registerTask('integration-tests', ['default', 'bgShell:integrationTests']);
|
||||||
'default',
|
|
||||||
'bgShell:integrationTests'
|
|
||||||
]);
|
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
Copyright (C) 2011-2019 by Yehuda Katz
|
Copyright (C) 2011-2017 by Yehuda Katz
|
||||||
|
|
||||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
of this software and associated documentation files (the "Software"), to deal
|
of this software and associated documentation files (the "Software"), to deal
|
||||||
|
|||||||
+9
-9
@@ -11,12 +11,12 @@ Handlebars.js and Mustache are both logicless templating languages that
|
|||||||
keep the view and the code separated like we all know they should be.
|
keep the view and the code separated like we all know they should be.
|
||||||
|
|
||||||
Checkout the official Handlebars docs site at
|
Checkout the official Handlebars docs site at
|
||||||
[https://handlebarsjs.com/](https://handlebarsjs.com) and the live demo at [http://tryhandlebarsjs.com/](http://tryhandlebarsjs.com/).
|
[http://www.handlebarsjs.com](http://www.handlebarsjs.com) and the live demo at [http://tryhandlebarsjs.com/](http://tryhandlebarsjs.com/).
|
||||||
|
|
||||||
Installing
|
Installing
|
||||||
----------
|
----------
|
||||||
|
|
||||||
See our [installation documentation](https://handlebarsjs.com/installation/).
|
See our [installation documentation](http://handlebarsjs.com/installation.html).
|
||||||
|
|
||||||
Usage
|
Usage
|
||||||
-----
|
-----
|
||||||
@@ -46,23 +46,23 @@ var result = template(data);
|
|||||||
// </ul>
|
// </ul>
|
||||||
```
|
```
|
||||||
|
|
||||||
Full documentation and more examples are at [handlebarsjs.com](https://handlebarsjs.com/).
|
Full documentation and more examples are at [handlebarsjs.com](http://handlebarsjs.com/).
|
||||||
|
|
||||||
Precompiling Templates
|
Precompiling Templates
|
||||||
----------------------
|
----------------------
|
||||||
|
|
||||||
Handlebars allows templates to be precompiled and included as javascript code rather than the handlebars template allowing for faster startup time. Full details are located [here](https://handlebarsjs.com/installation/precompilation.html).
|
Handlebars allows templates to be precompiled and included as javascript code rather than the handlebars template allowing for faster startup time. Full details are located [here](http://handlebarsjs.com/precompilation.html).
|
||||||
|
|
||||||
Differences Between Handlebars.js and Mustache
|
Differences Between Handlebars.js and Mustache
|
||||||
----------------------------------------------
|
----------------------------------------------
|
||||||
Handlebars.js adds a couple of additional features to make writing
|
Handlebars.js adds a couple of additional features to make writing
|
||||||
templates easier and also changes a tiny detail of how partials work.
|
templates easier and also changes a tiny detail of how partials work.
|
||||||
|
|
||||||
- [Nested Paths](https://handlebarsjs.com/guide/expressions.html#path-expressions)
|
- [Nested Paths](http://handlebarsjs.com/#paths)
|
||||||
- [Helpers](https://handlebarsjs.com/guide/expressions.html#helpers)
|
- [Helpers](http://handlebarsjs.com/#helpers)
|
||||||
- [Block Expressions](https://handlebarsjs.com/guide/block-helpers.html#basic-blocks)
|
- [Block Expressions](http://handlebarsjs.com/#block-expressions)
|
||||||
- [Literal Values](https://handlebarsjs.com/guide/expressions.html#literal-segments)
|
- [Literal Values](http://handlebarsjs.com/#literals)
|
||||||
- [Delimited Comments](https://handlebarsjs.com/guide/#template-comments)
|
- [Delimited Comments](http://handlebarsjs.com/#comments)
|
||||||
|
|
||||||
Block expressions have the same syntax as mustache sections but should not be confused with one another. Sections are akin to an implicit `each` or `with` statement depending on the input data and helpers are explicit pieces of code that are free to implement whatever behavior they like. The [mustache spec](http://mustache.github.io/mustache.5.html) defines the exact behavior of sections. In the case of name conflicts, helpers are given priority.
|
Block expressions have the same syntax as mustache sections but should not be confused with one another. Sections are akin to an implicit `each` or `with` statement depending on the input data and helpers are explicit pieces of code that are free to implement whatever behavior they like. The [mustache spec](http://mustache.github.io/mustache.5.html) defines the exact behavior of sections. In the case of name conflicts, helpers are given priority.
|
||||||
|
|
||||||
|
|||||||
+3
-2
@@ -13,7 +13,8 @@ install:
|
|||||||
# Clone submodules (mustache spec)
|
# Clone submodules (mustache spec)
|
||||||
- cmd: git submodule update --init --recursive
|
- cmd: git submodule update --init --recursive
|
||||||
# Install modules
|
# Install modules
|
||||||
- cmd: npm ci
|
- cmd: npm install
|
||||||
|
- cmd: npm install -g grunt-cli
|
||||||
|
|
||||||
|
|
||||||
# Post-install test scripts
|
# Post-install test scripts
|
||||||
@@ -22,7 +23,7 @@ test_script:
|
|||||||
- cmd: node --version
|
- cmd: node --version
|
||||||
- cmd: npm --version
|
- cmd: npm --version
|
||||||
# Run tests
|
# Run tests
|
||||||
- cmd: npm run test
|
- cmd: grunt --stack travis
|
||||||
|
|
||||||
# Don't actually build
|
# Don't actually build
|
||||||
build: off
|
build: off
|
||||||
|
|||||||
@@ -0,0 +1,7 @@
|
|||||||
|
module.exports = function(api) {
|
||||||
|
api.cache(false);
|
||||||
|
return {
|
||||||
|
presets: ['@babel/preset-env'],
|
||||||
|
plugins: ['@babel/plugin-transform-runtime']
|
||||||
|
};
|
||||||
|
};
|
||||||
@@ -1,5 +1,4 @@
|
|||||||
{
|
{
|
||||||
"extends": "prettier",
|
|
||||||
"globals": {
|
"globals": {
|
||||||
"require": true
|
"require": true
|
||||||
},
|
},
|
||||||
|
|||||||
+6
-11
@@ -1,14 +1,12 @@
|
|||||||
var async = require('neo-async'),
|
var async = require('neo-async'),
|
||||||
fs = require('fs'),
|
fs = require('fs'),
|
||||||
zlib = require('zlib');
|
zlib = require('zlib');
|
||||||
|
|
||||||
module.exports = function(grunt, callback) {
|
module.exports = function(grunt, callback) {
|
||||||
var distFiles = fs.readdirSync('dist'),
|
var distFiles = fs.readdirSync('dist'),
|
||||||
distSizes = {};
|
distSizes = {};
|
||||||
|
|
||||||
async.each(
|
async.each(distFiles, function(file, callback) {
|
||||||
distFiles,
|
|
||||||
function(file, callback) {
|
|
||||||
var content;
|
var content;
|
||||||
try {
|
try {
|
||||||
content = fs.readFileSync('dist/' + file);
|
content = fs.readFileSync('dist/' + file);
|
||||||
@@ -34,10 +32,7 @@ module.exports = function(grunt, callback) {
|
|||||||
});
|
});
|
||||||
},
|
},
|
||||||
function() {
|
function() {
|
||||||
grunt.log.writeln(
|
grunt.log.writeln('Distribution sizes: ' + JSON.stringify(distSizes, undefined, 2));
|
||||||
'Distribution sizes: ' + JSON.stringify(distSizes, undefined, 2)
|
|
||||||
);
|
|
||||||
callback([distSizes]);
|
callback([distSizes]);
|
||||||
}
|
});
|
||||||
);
|
|
||||||
};
|
};
|
||||||
|
|||||||
+1
-1
@@ -2,7 +2,7 @@ var fs = require('fs');
|
|||||||
|
|
||||||
var metrics = fs.readdirSync(__dirname);
|
var metrics = fs.readdirSync(__dirname);
|
||||||
metrics.forEach(function(metric) {
|
metrics.forEach(function(metric) {
|
||||||
if (metric === 'index.js' || !/(.*)\.js$/.test(metric)) {
|
if (metric === 'index.js' || !(/(.*)\.js$/.test(metric))) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
var _ = require('underscore'),
|
var _ = require('underscore'),
|
||||||
templates = require('./templates');
|
templates = require('./templates');
|
||||||
|
|
||||||
module.exports = function(grunt, callback) {
|
module.exports = function(grunt, callback) {
|
||||||
// Deferring to here in case we have a build for parser, etc as part of this grunt exec
|
// Deferring to here in case we have a build for parser, etc as part of this grunt exec
|
||||||
@@ -8,17 +8,12 @@ module.exports = function(grunt, callback) {
|
|||||||
var templateSizes = {};
|
var templateSizes = {};
|
||||||
_.each(templates, function(info, template) {
|
_.each(templates, function(info, template) {
|
||||||
var src = info.handlebars,
|
var src = info.handlebars,
|
||||||
compiled = Handlebars.precompile(src, {}),
|
compiled = Handlebars.precompile(src, {}),
|
||||||
knownHelpers = Handlebars.precompile(src, {
|
knownHelpers = Handlebars.precompile(src, {knownHelpersOnly: true, knownHelpers: info.helpers});
|
||||||
knownHelpersOnly: true,
|
|
||||||
knownHelpers: info.helpers
|
|
||||||
});
|
|
||||||
|
|
||||||
templateSizes[template] = compiled.length;
|
templateSizes[template] = compiled.length;
|
||||||
templateSizes['knownOnly_' + template] = knownHelpers.length;
|
templateSizes['knownOnly_' + template] = knownHelpers.length;
|
||||||
});
|
});
|
||||||
grunt.log.writeln(
|
grunt.log.writeln('Precompiled sizes: ' + JSON.stringify(templateSizes, undefined, 2));
|
||||||
'Precompiled sizes: ' + JSON.stringify(templateSizes, undefined, 2)
|
|
||||||
);
|
|
||||||
callback([templateSizes]);
|
callback([templateSizes]);
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -8,6 +8,5 @@ module.exports = {
|
|||||||
bar: true
|
bar: true
|
||||||
},
|
},
|
||||||
|
|
||||||
handlebars:
|
handlebars: '{{foo person "person" 1 true foo=bar foo="person" foo=1 foo=true}}'
|
||||||
'{{foo person "person" 1 true foo=bar foo="person" foo=1 foo=true}}'
|
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -1,12 +1,5 @@
|
|||||||
module.exports = {
|
module.exports = {
|
||||||
context: {
|
context: { names: [{name: 'Moe'}, {name: 'Larry'}, {name: 'Curly'}, {name: 'Shemp'}] },
|
||||||
names: [
|
|
||||||
{ name: 'Moe' },
|
|
||||||
{ name: 'Larry' },
|
|
||||||
{ name: 'Curly' },
|
|
||||||
{ name: 'Shemp' }
|
|
||||||
]
|
|
||||||
},
|
|
||||||
handlebars: '{{#each names}}{{name}}{{/each}}',
|
handlebars: '{{#each names}}{{name}}{{/each}}',
|
||||||
dust: '{#names}{name}{/names}',
|
dust: '{#names}{name}{/names}',
|
||||||
mustache: '{{#names}}{{name}}{{/names}}',
|
mustache: '{{#names}}{{name}}{{/names}}',
|
||||||
|
|||||||
@@ -1,11 +1,4 @@
|
|||||||
module.exports = {
|
module.exports = {
|
||||||
context: {
|
context: { names: [{name: 'Moe'}, {name: 'Larry'}, {name: 'Curly'}, {name: 'Shemp'}] },
|
||||||
names: [
|
|
||||||
{ name: 'Moe' },
|
|
||||||
{ name: 'Larry' },
|
|
||||||
{ name: 'Curly' },
|
|
||||||
{ name: 'Shemp' }
|
|
||||||
]
|
|
||||||
},
|
|
||||||
handlebars: '{{#names}}{{name}}{{/names}}'
|
handlebars: '{{#names}}{{name}}{{/names}}'
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -7,9 +7,9 @@ module.exports = {
|
|||||||
},
|
},
|
||||||
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: [
|
items: [
|
||||||
{ name: 'red', current: true, url: '#Red' },
|
{name: 'red', current: true, url: '#Red'},
|
||||||
{ name: 'green', current: false, url: '#Green' },
|
{name: 'green', current: false, url: '#Green'},
|
||||||
{ name: 'blue', current: false, url: '#Blue' }
|
{name: 'blue', current: false, url: '#Blue'}
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
|
|
||||||
|
|||||||
@@ -1,11 +1,4 @@
|
|||||||
module.exports = {
|
module.exports = {
|
||||||
context: {
|
context: { names: [{name: 'Moe'}, {name: 'Larry'}, {name: 'Curly'}, {name: 'Shemp'}] },
|
||||||
names: [
|
|
||||||
{ name: 'Moe' },
|
|
||||||
{ name: 'Larry' },
|
|
||||||
{ name: 'Curly' },
|
|
||||||
{ name: 'Shemp' }
|
|
||||||
]
|
|
||||||
},
|
|
||||||
handlebars: '{{#each names}}{{@index}}{{name}}{{/each}}'
|
handlebars: '{{#each names}}{{@index}}{{name}}{{/each}}'
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -1,13 +1,5 @@
|
|||||||
module.exports = {
|
module.exports = {
|
||||||
context: {
|
context: { names: [{name: 'Moe'}, {name: 'Larry'}, {name: 'Curly'}, {name: 'Shemp'}], foo: 'bar' },
|
||||||
names: [
|
|
||||||
{ name: 'Moe' },
|
|
||||||
{ name: 'Larry' },
|
|
||||||
{ name: 'Curly' },
|
|
||||||
{ name: 'Shemp' }
|
|
||||||
],
|
|
||||||
foo: 'bar'
|
|
||||||
},
|
|
||||||
handlebars: '{{#each names}}{{../foo}}{{/each}}',
|
handlebars: '{{#each names}}{{../foo}}{{/each}}',
|
||||||
mustache: '{{#names}}{{foo}}{{/names}}',
|
mustache: '{{#names}}{{foo}}{{/names}}',
|
||||||
eco: '<% for item in @names: %><%= @foo %><% end %>'
|
eco: '<% for item in @names: %><%= @foo %><% end %>'
|
||||||
|
|||||||
@@ -1,16 +1,6 @@
|
|||||||
module.exports = {
|
module.exports = {
|
||||||
context: {
|
context: { names: [{bat: 'foo', name: ['Moe']}, {bat: 'foo', name: ['Larry']}, {bat: 'foo', name: ['Curly']}, {bat: 'foo', name: ['Shemp']}], foo: 'bar' },
|
||||||
names: [
|
handlebars: '{{#each names}}{{#each name}}{{../bat}}{{../../foo}}{{/each}}{{/each}}',
|
||||||
{ bat: 'foo', name: ['Moe'] },
|
|
||||||
{ bat: 'foo', name: ['Larry'] },
|
|
||||||
{ bat: 'foo', name: ['Curly'] },
|
|
||||||
{ bat: 'foo', name: ['Shemp'] }
|
|
||||||
],
|
|
||||||
foo: 'bar'
|
|
||||||
},
|
|
||||||
handlebars:
|
|
||||||
'{{#each names}}{{#each name}}{{../bat}}{{../../foo}}{{/each}}{{/each}}',
|
|
||||||
mustache: '{{#names}}{{#name}}{{bat}}{{foo}}{{/name}}{{/names}}',
|
mustache: '{{#names}}{{#name}}{{bat}}{{foo}}{{/name}}{{/names}}',
|
||||||
eco:
|
eco: '<% for item in @names: %><% for child in item.name: %><%= item.bat %><%= @foo %><% end %><% end %>'
|
||||||
'<% for item in @names: %><% for child in item.name: %><%= item.bat %><%= @foo %><% end %><% end %>'
|
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -2,7 +2,7 @@ var fs = require('fs');
|
|||||||
|
|
||||||
var templates = fs.readdirSync(__dirname);
|
var templates = fs.readdirSync(__dirname);
|
||||||
templates.forEach(function(template) {
|
templates.forEach(function(template) {
|
||||||
if (template === 'index.js' || !/(.*)\.js$/.test(template)) {
|
if (template === 'index.js' || !(/(.*)\.js$/.test(template))) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
module.exports[RegExp.$1] = require('./' + RegExp.$1);
|
module.exports[RegExp.$1] = require('./' + RegExp.$1);
|
||||||
|
|||||||
@@ -1,8 +1,5 @@
|
|||||||
module.exports = {
|
module.exports = {
|
||||||
context: {
|
context: { name: '1', kids: [{ name: '1.1', kids: [{name: '1.1.1', kids: []}] }] },
|
||||||
name: '1',
|
|
||||||
kids: [{ name: '1.1', kids: [{ name: '1.1.1', kids: [] }] }]
|
|
||||||
},
|
|
||||||
partials: {
|
partials: {
|
||||||
mustache: { recursion: '{{name}}{{#kids}}{{>recursion}}{{/kids}}' },
|
mustache: { recursion: '{{name}}{{#kids}}{{>recursion}}{{/kids}}' },
|
||||||
handlebars: { recursion: '{{name}}{{#each kids}}{{>recursion}}{{/each}}' }
|
handlebars: { recursion: '{{name}}{{#each kids}}{{>recursion}}{{/each}}' }
|
||||||
|
|||||||
@@ -1,16 +1,8 @@
|
|||||||
module.exports = {
|
module.exports = {
|
||||||
context: {
|
context: { peeps: [{name: 'Moe', count: 15}, {name: 'Larry', count: 5}, {name: 'Curly', count: 1}] },
|
||||||
peeps: [
|
|
||||||
{ name: 'Moe', count: 15 },
|
|
||||||
{ name: 'Larry', count: 5 },
|
|
||||||
{ name: 'Curly', count: 1 }
|
|
||||||
]
|
|
||||||
},
|
|
||||||
partials: {
|
partials: {
|
||||||
mustache: { variables: 'Hello {{name}}! You have {{count}} new messages.' },
|
mustache: { variables: 'Hello {{name}}! You have {{count}} new messages.' },
|
||||||
handlebars: {
|
handlebars: { variables: 'Hello {{name}}! You have {{count}} new messages.' }
|
||||||
variables: 'Hello {{name}}! You have {{count}} new messages.'
|
|
||||||
}
|
|
||||||
},
|
},
|
||||||
|
|
||||||
handlebars: '{{#each peeps}}{{>variables}}{{/each}}',
|
handlebars: '{{#each peeps}}{{>variables}}{{/each}}',
|
||||||
|
|||||||
@@ -1,9 +1,7 @@
|
|||||||
module.exports = {
|
module.exports = {
|
||||||
context: { person: { name: { bar: { baz: 'Larry' } }, age: 45 } },
|
context: { person: { name: {bar: {baz: 'Larry'}}, age: 45 } },
|
||||||
handlebars:
|
handlebars: '{{person.name.bar.baz}}{{person.age}}{{person.foo}}{{animal.age}}',
|
||||||
'{{person.name.bar.baz}}{{person.age}}{{person.foo}}{{animal.age}}',
|
|
||||||
dust: '{person.name.bar.baz}{person.age}{person.foo}{animal.age}',
|
dust: '{person.name.bar.baz}{person.age}{person.foo}{animal.age}',
|
||||||
eco:
|
eco: '<%= @person.name.bar.baz %><%= @person.age %><%= @person.foo %><% if @animal: %><%= @animal.age %><% end %>',
|
||||||
'<%= @person.name.bar.baz %><%= @person.age %><%= @person.foo %><% if @animal: %><%= @animal.age %><% end %>',
|
|
||||||
mustache: '{{person.name.bar.baz}}{{person.age}}{{person.foo}}{{animal.age}}'
|
mustache: '{{person.name.bar.baz}}{{person.age}}{{person.foo}}{{animal.age}}'
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -1,7 +1,8 @@
|
|||||||
module.exports = {
|
module.exports = {
|
||||||
context: { name: 'Mick', count: 30 },
|
context: {name: 'Mick', count: 30},
|
||||||
handlebars: 'Hello {{name}}! You have {{count}} new messages.',
|
handlebars: 'Hello {{name}}! You have {{count}} new messages.',
|
||||||
dust: 'Hello {name}! You have {count} new messages.',
|
dust: 'Hello {name}! You have {count} new messages.',
|
||||||
mustache: 'Hello {{name}}! You have {{count}} new messages.',
|
mustache: 'Hello {{name}}! You have {{count}} new messages.',
|
||||||
eco: 'Hello <%= @name %>! You have <%= @count %> new messages.'
|
eco: 'Hello <%= @name %>! You have <%= @count %> new messages.'
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
+25
-49
@@ -1,27 +1,19 @@
|
|||||||
var _ = require('underscore'),
|
var _ = require('underscore'),
|
||||||
runner = require('./util/template-runner'),
|
runner = require('./util/template-runner'),
|
||||||
eco,
|
|
||||||
dust,
|
eco, dust, Handlebars, Mustache;
|
||||||
Handlebars,
|
|
||||||
Mustache;
|
|
||||||
|
|
||||||
try {
|
try {
|
||||||
dust = require('dustjs-linkedin');
|
dust = require('dustjs-linkedin');
|
||||||
} catch (err) {
|
} catch (err) { /* NOP */ }
|
||||||
/* NOP */
|
|
||||||
}
|
|
||||||
|
|
||||||
try {
|
try {
|
||||||
Mustache = require('mustache');
|
Mustache = require('mustache');
|
||||||
} catch (err) {
|
} catch (err) { /* NOP */ }
|
||||||
/* NOP */
|
|
||||||
}
|
|
||||||
|
|
||||||
try {
|
try {
|
||||||
eco = require('eco');
|
eco = require('eco');
|
||||||
} catch (err) {
|
} catch (err) { /* NOP */ }
|
||||||
/* NOP */
|
|
||||||
}
|
|
||||||
|
|
||||||
function error() {
|
function error() {
|
||||||
throw new Error('EWOT');
|
throw new Error('EWOT');
|
||||||
@@ -30,28 +22,21 @@ function error() {
|
|||||||
function makeSuite(bench, name, template, handlebarsOnly) {
|
function makeSuite(bench, name, template, handlebarsOnly) {
|
||||||
// Create aliases to minimize any impact from having to walk up the closure tree.
|
// Create aliases to minimize any impact from having to walk up the closure tree.
|
||||||
var templateName = name,
|
var templateName = name,
|
||||||
context = template.context,
|
|
||||||
partials = template.partials,
|
|
||||||
handlebarsOut,
|
|
||||||
compatOut,
|
|
||||||
dustOut,
|
|
||||||
ecoOut,
|
|
||||||
mustacheOut;
|
|
||||||
|
|
||||||
var handlebar = Handlebars.compile(template.handlebars, { data: false }),
|
context = template.context,
|
||||||
compat = Handlebars.compile(template.handlebars, {
|
partials = template.partials,
|
||||||
data: false,
|
|
||||||
compat: true
|
handlebarsOut,
|
||||||
}),
|
compatOut,
|
||||||
options = { helpers: template.helpers };
|
dustOut,
|
||||||
_.each(template.partials && template.partials.handlebars, function(
|
ecoOut,
|
||||||
partial,
|
mustacheOut;
|
||||||
partialName
|
|
||||||
) {
|
var handlebar = Handlebars.compile(template.handlebars, {data: false}),
|
||||||
Handlebars.registerPartial(
|
compat = Handlebars.compile(template.handlebars, {data: false, compat: true}),
|
||||||
partialName,
|
options = {helpers: template.helpers};
|
||||||
Handlebars.compile(partial, { data: false })
|
_.each(template.partials && template.partials.handlebars, function(partial, partialName) {
|
||||||
);
|
Handlebars.registerPartial(partialName, Handlebars.compile(partial, {data: false}));
|
||||||
});
|
});
|
||||||
|
|
||||||
handlebarsOut = handlebar(context, options);
|
handlebarsOut = handlebar(context, options);
|
||||||
@@ -73,9 +58,7 @@ function makeSuite(bench, name, template, handlebarsOnly) {
|
|||||||
dustOut = false;
|
dustOut = false;
|
||||||
dust.loadSource(dust.compile(template.dust, templateName));
|
dust.loadSource(dust.compile(template.dust, templateName));
|
||||||
|
|
||||||
dust.render(templateName, context, function(err, out) {
|
dust.render(templateName, context, function(err, out) { dustOut = out; });
|
||||||
dustOut = out;
|
|
||||||
});
|
|
||||||
|
|
||||||
bench('dust', function() {
|
bench('dust', function() {
|
||||||
dust.render(templateName, context, function() {});
|
dust.render(templateName, context, function() {});
|
||||||
@@ -101,7 +84,7 @@ function makeSuite(bench, name, template, handlebarsOnly) {
|
|||||||
|
|
||||||
if (Mustache) {
|
if (Mustache) {
|
||||||
var mustacheSource = template.mustache,
|
var mustacheSource = template.mustache,
|
||||||
mustachePartials = partials && partials.mustache;
|
mustachePartials = partials && partials.mustache;
|
||||||
|
|
||||||
if (mustacheSource) {
|
if (mustacheSource) {
|
||||||
mustacheOut = Mustache.to_html(mustacheSource, context, mustachePartials);
|
mustacheOut = Mustache.to_html(mustacheSource, context, mustachePartials);
|
||||||
@@ -124,16 +107,9 @@ function makeSuite(bench, name, template, handlebarsOnly) {
|
|||||||
b = b.replace(/\s/g, '');
|
b = b.replace(/\s/g, '');
|
||||||
|
|
||||||
if (handlebarsOut !== b) {
|
if (handlebarsOut !== b) {
|
||||||
throw new Error(
|
throw new Error('Template output mismatch: ' + name
|
||||||
'Template output mismatch: ' +
|
+ '\n\nHandlebars: ' + handlebarsOut
|
||||||
name +
|
+ '\n\n' + lang + ': ' + b);
|
||||||
'\n\nHandlebars: ' +
|
|
||||||
handlebarsOut +
|
|
||||||
'\n\n' +
|
|
||||||
lang +
|
|
||||||
': ' +
|
|
||||||
b
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
+20
-47
@@ -1,5 +1,5 @@
|
|||||||
var _ = require('underscore'),
|
var _ = require('underscore'),
|
||||||
Benchmark = require('benchmark');
|
Benchmark = require('benchmark');
|
||||||
|
|
||||||
function BenchWarmer() {
|
function BenchWarmer() {
|
||||||
this.benchmarks = [];
|
this.benchmarks = [];
|
||||||
@@ -33,21 +33,16 @@ BenchWarmer.prototype = {
|
|||||||
this.names.push(name);
|
this.names.push(name);
|
||||||
}
|
}
|
||||||
|
|
||||||
var first = this.first,
|
var first = this.first, suiteName = this.suiteName, self = this;
|
||||||
suiteName = this.suiteName,
|
|
||||||
self = this;
|
|
||||||
this.first = false;
|
this.first = false;
|
||||||
|
|
||||||
var bench = new Benchmark(fn, {
|
var bench = new Benchmark(fn, {
|
||||||
name: this.suiteName + ': ' + name,
|
name: this.suiteName + ': ' + name,
|
||||||
onComplete: function() {
|
onComplete: function() {
|
||||||
if (first) {
|
if (first) { self.startLine(suiteName); }
|
||||||
self.startLine(suiteName);
|
|
||||||
}
|
|
||||||
self.writeBench(bench);
|
self.writeBench(bench);
|
||||||
self.currentBenches.push(bench);
|
self.currentBenches.push(bench);
|
||||||
},
|
}, onError: function() {
|
||||||
onError: function() {
|
|
||||||
self.errors[this.name] = this;
|
self.errors[this.name] = this;
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
@@ -80,14 +75,10 @@ BenchWarmer.prototype = {
|
|||||||
});
|
});
|
||||||
print('\n');
|
print('\n');
|
||||||
|
|
||||||
var errors = false,
|
var errors = false, prop, bench;
|
||||||
prop,
|
|
||||||
bench;
|
|
||||||
for (prop in self.errors) {
|
for (prop in self.errors) {
|
||||||
if (
|
if (Object.prototype.hasOwnProperty.call(self, prop)
|
||||||
Object.prototype.hasOwnProperty.call(self, prop) &&
|
&& self.errors[prop].error.message !== 'EWOT') {
|
||||||
self.errors[prop].error.message !== 'EWOT'
|
|
||||||
) {
|
|
||||||
errors = true;
|
errors = true;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
@@ -116,39 +107,23 @@ BenchWarmer.prototype = {
|
|||||||
},
|
},
|
||||||
|
|
||||||
scaleTimes: function() {
|
scaleTimes: function() {
|
||||||
var scaled = (this.scaled = {});
|
var scaled = this.scaled = {};
|
||||||
_.each(
|
_.each(this.times, function(times, name) {
|
||||||
this.times,
|
var output = scaled[name] = {};
|
||||||
function(times, name) {
|
|
||||||
var output = (scaled[name] = {});
|
|
||||||
|
|
||||||
_.each(
|
_.each(times, function(time, lang) {
|
||||||
times,
|
output[lang] = ((time - this.minimum) / (this.maximum - this.minimum) * 100).toFixed(2);
|
||||||
function(time, lang) {
|
}, this);
|
||||||
output[lang] = (
|
}, this);
|
||||||
((time - this.minimum) / (this.maximum - this.minimum)) *
|
|
||||||
100
|
|
||||||
).toFixed(2);
|
|
||||||
},
|
|
||||||
this
|
|
||||||
);
|
|
||||||
},
|
|
||||||
this
|
|
||||||
);
|
|
||||||
},
|
},
|
||||||
|
|
||||||
printHeader: function(title, winners) {
|
printHeader: function(title, winners) {
|
||||||
var benchSize = 0,
|
var benchSize = 0, names = this.names, i, l;
|
||||||
names = this.names,
|
|
||||||
i,
|
|
||||||
l;
|
|
||||||
|
|
||||||
for (i = 0, l = names.length; i < l; i++) {
|
for (i = 0, l = names.length; i < l; i++) {
|
||||||
var name = names[i];
|
var name = names[i];
|
||||||
|
|
||||||
if (benchSize < name.length) {
|
if (benchSize < name.length) { benchSize = name.length; }
|
||||||
benchSize = name.length;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
this.nameSize = benchSize + 2;
|
this.nameSize = benchSize + 2;
|
||||||
@@ -171,9 +146,7 @@ BenchWarmer.prototype = {
|
|||||||
},
|
},
|
||||||
|
|
||||||
startLine: function(name) {
|
startLine: function(name) {
|
||||||
var winners = Benchmark.map(this.winners(this.currentBenches), function(
|
var winners = Benchmark.map(this.winners(this.currentBenches), function(bench) {
|
||||||
bench
|
|
||||||
) {
|
|
||||||
return bench.name.split(': ')[1];
|
return bench.name.split(': ')[1];
|
||||||
});
|
});
|
||||||
|
|
||||||
@@ -191,9 +164,9 @@ BenchWarmer.prototype = {
|
|||||||
|
|
||||||
if (!bench.error) {
|
if (!bench.error) {
|
||||||
var count = bench.hz,
|
var count = bench.hz,
|
||||||
moe = (count * bench.stats.rme) / 100,
|
moe = count * bench.stats.rme / 100,
|
||||||
minimum,
|
minimum,
|
||||||
maximum;
|
maximum;
|
||||||
|
|
||||||
count = Math.round(count / 1000);
|
count = Math.round(count / 1000);
|
||||||
moe = Math.round(moe / 1000);
|
moe = Math.round(moe / 1000);
|
||||||
|
|||||||
@@ -1,12 +1,12 @@
|
|||||||
var _ = require('underscore'),
|
var _ = require('underscore'),
|
||||||
BenchWarmer = require('./benchwarmer'),
|
BenchWarmer = require('./benchwarmer'),
|
||||||
templates = require('../templates');
|
templates = require('../templates');
|
||||||
|
|
||||||
module.exports = function(grunt, makeSuite, callback) {
|
module.exports = function(grunt, makeSuite, callback) {
|
||||||
var warmer = new BenchWarmer();
|
var warmer = new BenchWarmer();
|
||||||
|
|
||||||
var handlebarsOnly = grunt.option('handlebars-only'),
|
var handlebarsOnly = grunt.option('handlebars-only'),
|
||||||
grep = grunt.option('grep');
|
grep = grunt.option('grep');
|
||||||
if (grep) {
|
if (grep) {
|
||||||
grep = new RegExp(grep);
|
grep = new RegExp(grep);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,6 +0,0 @@
|
|||||||
module.exports = {
|
|
||||||
rules: {
|
|
||||||
'no-console': 0,
|
|
||||||
'no-var': 0
|
|
||||||
}
|
|
||||||
};
|
|
||||||
+111
-159
@@ -1,176 +1,128 @@
|
|||||||
#!/usr/bin/env node
|
#!/usr/bin/env node
|
||||||
|
|
||||||
var argv = parseArgs({
|
var optimist = require('optimist')
|
||||||
'f': {
|
.usage('Precompile handlebar templates.\nUsage: $0 [template|directory]...', {
|
||||||
'type': 'string',
|
'f': {
|
||||||
'description': 'Output File',
|
'type': 'string',
|
||||||
'alias': 'output'
|
'description': 'Output File',
|
||||||
},
|
'alias': 'output'
|
||||||
'map': {
|
},
|
||||||
'type': 'string',
|
'map': {
|
||||||
'description': 'Source Map File'
|
'type': 'string',
|
||||||
},
|
'description': 'Source Map File'
|
||||||
'a': {
|
},
|
||||||
'type': 'boolean',
|
'a': {
|
||||||
'description': 'Exports amd style (require.js)',
|
'type': 'boolean',
|
||||||
'alias': 'amd'
|
'description': 'Exports amd style (require.js)',
|
||||||
},
|
'alias': 'amd'
|
||||||
'c': {
|
},
|
||||||
'type': 'string',
|
'c': {
|
||||||
'description': 'Exports CommonJS style, path to Handlebars module',
|
'type': 'string',
|
||||||
'alias': 'commonjs',
|
'description': 'Exports CommonJS style, path to Handlebars module',
|
||||||
'default': null
|
'alias': 'commonjs',
|
||||||
},
|
'default': null
|
||||||
'h': {
|
},
|
||||||
'type': 'string',
|
'h': {
|
||||||
'description': 'Path to handlebar.js (only valid for amd-style)',
|
'type': 'string',
|
||||||
'alias': 'handlebarPath',
|
'description': 'Path to handlebar.js (only valid for amd-style)',
|
||||||
'default': ''
|
'alias': 'handlebarPath',
|
||||||
},
|
'default': ''
|
||||||
'k': {
|
},
|
||||||
'type': 'string',
|
'k': {
|
||||||
'description': 'Known helpers',
|
'type': 'string',
|
||||||
'alias': 'known'
|
'description': 'Known helpers',
|
||||||
},
|
'alias': 'known'
|
||||||
'o': {
|
},
|
||||||
'type': 'boolean',
|
'o': {
|
||||||
'description': 'Known helpers only',
|
'type': 'boolean',
|
||||||
'alias': 'knownOnly'
|
'description': 'Known helpers only',
|
||||||
},
|
'alias': 'knownOnly'
|
||||||
'm': {
|
},
|
||||||
'type': 'boolean',
|
'm': {
|
||||||
'description': 'Minimize output',
|
'type': 'boolean',
|
||||||
'alias': 'min'
|
'description': 'Minimize output',
|
||||||
},
|
'alias': 'min'
|
||||||
'n': {
|
},
|
||||||
'type': 'string',
|
'n': {
|
||||||
'description': 'Template namespace',
|
'type': 'string',
|
||||||
'alias': 'namespace',
|
'description': 'Template namespace',
|
||||||
'default': 'Handlebars.templates'
|
'alias': 'namespace',
|
||||||
},
|
'default': 'Handlebars.templates'
|
||||||
's': {
|
},
|
||||||
'type': 'boolean',
|
's': {
|
||||||
'description': 'Output template function only.',
|
'type': 'boolean',
|
||||||
'alias': 'simple'
|
'description': 'Output template function only.',
|
||||||
},
|
'alias': 'simple'
|
||||||
'N': {
|
},
|
||||||
'type': 'string',
|
'N': {
|
||||||
'description': 'Name of passed string templates. Optional if running in a simple mode. Required when operating on multiple templates.',
|
'type': 'string',
|
||||||
'alias': 'name'
|
'description': 'Name of passed string templates. Optional if running in a simple mode. Required when operating on multiple templates.',
|
||||||
},
|
'alias': 'name'
|
||||||
'i': {
|
},
|
||||||
'type': 'string',
|
'i': {
|
||||||
'description': 'Generates a template from the passed CLI argument.\n"-" is treated as a special value and causes stdin to be read for the template value.',
|
'type': 'string',
|
||||||
'alias': 'string'
|
'description': 'Generates a template from the passed CLI argument.\n"-" is treated as a special value and causes stdin to be read for the template value.',
|
||||||
},
|
'alias': 'string'
|
||||||
'r': {
|
},
|
||||||
'type': 'string',
|
'r': {
|
||||||
'description': 'Template root. Base value that will be stripped from template names.',
|
'type': 'string',
|
||||||
'alias': 'root'
|
'description': 'Template root. Base value that will be stripped from template names.',
|
||||||
},
|
'alias': 'root'
|
||||||
'p': {
|
},
|
||||||
'type': 'boolean',
|
'p': {
|
||||||
'description': 'Compiling a partial template',
|
'type': 'boolean',
|
||||||
'alias': 'partial'
|
'description': 'Compiling a partial template',
|
||||||
},
|
'alias': 'partial'
|
||||||
'd': {
|
},
|
||||||
'type': 'boolean',
|
'd': {
|
||||||
'description': 'Include data when compiling',
|
'type': 'boolean',
|
||||||
'alias': 'data'
|
'description': 'Include data when compiling',
|
||||||
},
|
'alias': 'data'
|
||||||
'e': {
|
},
|
||||||
'type': 'string',
|
'e': {
|
||||||
'description': 'Template extension.',
|
'type': 'string',
|
||||||
'alias': 'extension',
|
'description': 'Template extension.',
|
||||||
'default': 'handlebars'
|
'alias': 'extension',
|
||||||
},
|
'default': 'handlebars'
|
||||||
'b': {
|
},
|
||||||
'type': 'boolean',
|
'b': {
|
||||||
'description': 'Removes the BOM (Byte Order Mark) from the beginning of the templates.',
|
'type': 'boolean',
|
||||||
'alias': 'bom'
|
'description': 'Removes the BOM (Byte Order Mark) from the beginning of the templates.',
|
||||||
},
|
'alias': 'bom'
|
||||||
'v': {
|
},
|
||||||
'type': 'boolean',
|
'v': {
|
||||||
'description': 'Prints the current compiler version',
|
'type': 'boolean',
|
||||||
'alias': 'version'
|
'description': 'Prints the current compiler version',
|
||||||
},
|
'alias': 'version'
|
||||||
'help': {
|
},
|
||||||
'type': 'boolean',
|
|
||||||
'description': 'Outputs this message'
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
|
'help': {
|
||||||
|
'type': 'boolean',
|
||||||
|
'description': 'Outputs this message'
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
.wrap(120)
|
||||||
|
.check(function(argv) {
|
||||||
|
if (argv.version) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
|
||||||
|
var argv = optimist.argv;
|
||||||
argv.files = argv._;
|
argv.files = argv._;
|
||||||
delete argv._;
|
delete argv._;
|
||||||
|
|
||||||
var Precompiler = require('../dist/cjs/precompiler');
|
var Precompiler = require('../dist/cjs/precompiler');
|
||||||
Precompiler.loadTemplates(argv, function(err, opts) {
|
Precompiler.loadTemplates(argv, function(err, opts) {
|
||||||
|
|
||||||
if (err) {
|
if (err) {
|
||||||
throw err;
|
throw err;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (opts.help || (!opts.templates.length && !opts.version)) {
|
if (opts.help || (!opts.templates.length && !opts.version)) {
|
||||||
printUsage(argv._spec, 120);
|
optimist.showHelp();
|
||||||
} else {
|
} else {
|
||||||
Precompiler.cli(opts);
|
Precompiler.cli(opts);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
function pad(n) {
|
|
||||||
var str = '';
|
|
||||||
while (str.length < n) {
|
|
||||||
str += ' ';
|
|
||||||
}
|
|
||||||
return str;
|
|
||||||
}
|
|
||||||
|
|
||||||
function parseArgs(spec) {
|
|
||||||
var opts = { alias: {}, boolean: [], default: {}, string: [] };
|
|
||||||
|
|
||||||
Object.keys(spec).forEach(function (arg) {
|
|
||||||
var opt = spec[arg];
|
|
||||||
opts[opt.type].push(arg);
|
|
||||||
if ('alias' in opt) opts.alias[arg] = opt.alias;
|
|
||||||
if ('default' in opt) opts.default[arg] = opt.default;
|
|
||||||
});
|
|
||||||
|
|
||||||
var argv = require('minimist')(process.argv.slice(2), opts);
|
|
||||||
argv._spec = spec;
|
|
||||||
return argv;
|
|
||||||
}
|
|
||||||
|
|
||||||
function printUsage(spec, wrap) {
|
|
||||||
var wordwrap = require('wordwrap');
|
|
||||||
|
|
||||||
console.log('Precompile handlebar templates.');
|
|
||||||
console.log('Usage: handlebars [template|directory]...');
|
|
||||||
|
|
||||||
var opts = [];
|
|
||||||
var width = 0;
|
|
||||||
Object.keys(spec).forEach(function (arg) {
|
|
||||||
var opt = spec[arg];
|
|
||||||
|
|
||||||
var name = (arg.length === 1 ? '-' : '--') + arg;
|
|
||||||
if ('alias' in opt) name += ', --' + opt.alias;
|
|
||||||
|
|
||||||
var meta = '[' + opt.type + ']';
|
|
||||||
if ('default' in opt) meta += ' [default: ' + JSON.stringify(opt.default) + ']';
|
|
||||||
|
|
||||||
opts.push({ name: name, desc: opt.description, meta: meta });
|
|
||||||
if (name.length > width) width = name.length;
|
|
||||||
});
|
|
||||||
|
|
||||||
console.log('Options:');
|
|
||||||
opts.forEach(function (opt) {
|
|
||||||
var desc = wordwrap(width + 4, wrap + 1)(opt.desc);
|
|
||||||
|
|
||||||
console.log(' %s%s%s%s%s',
|
|
||||||
opt.name,
|
|
||||||
pad(width - opt.name.length + 2),
|
|
||||||
desc.slice(width + 4),
|
|
||||||
pad(wrap - opt.meta.length - desc.split(/\n/).pop().length),
|
|
||||||
opt.meta
|
|
||||||
);
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"name": "handlebars",
|
"name": "handlebars",
|
||||||
"version": "4.7.6",
|
"version": "4.5.3",
|
||||||
"main": "handlebars.js",
|
"main": "handlebars.js",
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"dependencies": {}
|
"dependencies": {}
|
||||||
|
|||||||
@@ -2,7 +2,7 @@
|
|||||||
<package>
|
<package>
|
||||||
<metadata>
|
<metadata>
|
||||||
<id>handlebars.js</id>
|
<id>handlebars.js</id>
|
||||||
<version>4.7.6</version>
|
<version>4.5.3</version>
|
||||||
<authors>handlebars.js Authors</authors>
|
<authors>handlebars.js Authors</authors>
|
||||||
<licenseUrl>https://github.com/wycats/handlebars.js/blob/master/LICENSE</licenseUrl>
|
<licenseUrl>https://github.com/wycats/handlebars.js/blob/master/LICENSE</licenseUrl>
|
||||||
<projectUrl>https://github.com/wycats/handlebars.js/</projectUrl>
|
<projectUrl>https://github.com/wycats/handlebars.js/</projectUrl>
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"name": "handlebars",
|
"name": "handlebars",
|
||||||
"version": "4.7.6",
|
"version": "4.5.3",
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"jspm": {
|
"jspm": {
|
||||||
"main": "handlebars",
|
"main": "handlebars",
|
||||||
|
|||||||
@@ -1,13 +1,12 @@
|
|||||||
module.exports = {
|
module.exports = {
|
||||||
extends: ['eslint:recommended', 'plugin:es5/no-es2015', 'prettier'],
|
"extends": "eslint:recommended",
|
||||||
globals: {
|
"globals": {
|
||||||
self: false
|
"self": false
|
||||||
},
|
},
|
||||||
env: {
|
"env": {
|
||||||
node: true
|
"node": true
|
||||||
},
|
},
|
||||||
rules: {
|
"rules": {
|
||||||
'no-console': 'off',
|
'no-console': 'off'
|
||||||
'no-var': 'off'
|
|
||||||
}
|
}
|
||||||
};
|
}
|
||||||
@@ -5,7 +5,7 @@ var Handlebars = require('handlebars');
|
|||||||
console.log('Testing built Handlebars with Node version ' + process.version);
|
console.log('Testing built Handlebars with Node version ' + process.version);
|
||||||
|
|
||||||
var template = Handlebars.compile('Author: {{author}}');
|
var template = Handlebars.compile('Author: {{author}}');
|
||||||
var output = template({ author: 'Yehuda' });
|
var output = template({author: 'Yehuda'});
|
||||||
assert.strictEqual(output, 'Author: Yehuda');
|
assert.strictEqual(output, 'Author: Yehuda');
|
||||||
|
|
||||||
console.log('Success');
|
console.log('Success');
|
||||||
|
|||||||
@@ -1,7 +1,5 @@
|
|||||||
#!/bin/bash
|
#!/bin/bash
|
||||||
|
|
||||||
set -e
|
|
||||||
|
|
||||||
cd "$( dirname "$( readlink -f "$0" )" )" || exit 1
|
cd "$( dirname "$( readlink -f "$0" )" )" || exit 1
|
||||||
# shellcheck disable=SC1090
|
# shellcheck disable=SC1090
|
||||||
[ -s "$NVM_DIR/nvm.sh" ] && \. "$NVM_DIR/nvm.sh"
|
[ -s "$NVM_DIR/nvm.sh" ] && \. "$NVM_DIR/nvm.sh"
|
||||||
@@ -14,16 +12,15 @@ cd "$( dirname "$( readlink -f "$0" )" )" || exit 1
|
|||||||
# It does (almost) not test for correctness, because that is already done in the mocha-tests.
|
# 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.
|
# And it does not use any NodeJS based testing framwork to make this part independent of the Node version.
|
||||||
|
|
||||||
unset npm_config_prefix
|
# A list of NodeJS versions is expected as cli-args
|
||||||
|
|
||||||
echo "Handlebars should be able to run in various versions of NodeJS"
|
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 12 13 ; do
|
for i in 0.10 0.12 4 5 6 7 8 9 10 11 ; do
|
||||||
rm target node_modules package-lock.json -rf
|
rm target node_modules package-lock.json -rf
|
||||||
mkdir target
|
mkdir target
|
||||||
nvm install "$i"
|
nvm install "$i"
|
||||||
nvm exec "$i" npm install
|
nvm exec "$i" npm install
|
||||||
nvm exec "$i" npm run test
|
nvm exec "$i" npm run test || exit 1
|
||||||
nvm exec "$i" npm run test-precompile
|
nvm exec "$i" npm run test-precompile || exit 1
|
||||||
|
|
||||||
echo Success
|
echo Success
|
||||||
done
|
done
|
||||||
@@ -1,15 +1,13 @@
|
|||||||
#!/bin/bash
|
#!/bin/bash
|
||||||
|
|
||||||
set -e
|
cd "$( dirname "$( readlink -f "$0" )" )" || exit 1
|
||||||
|
|
||||||
cd "$( dirname "$( readlink -f "$0" )" )"
|
|
||||||
|
|
||||||
for i in */test.sh ; do
|
for i in */test.sh ; do
|
||||||
(
|
(
|
||||||
echo "----------------------------------------"
|
echo "----------------------------------------"
|
||||||
echo "-- Running integration test: $i"
|
echo "-- Running integration test: $i"
|
||||||
echo "----------------------------------------"
|
echo "----------------------------------------"
|
||||||
cd "$( dirname "$i" )"
|
cd "$( dirname "$i" )" || exit 1
|
||||||
./test.sh
|
./test.sh || exit 1
|
||||||
)
|
)
|
||||||
done
|
done
|
||||||
@@ -1,12 +1,12 @@
|
|||||||
import * as Handlebars from 'handlebars/runtime';
|
import * as Handlebars from 'handlebars/runtime';
|
||||||
import hbs from 'handlebars-inline-precompile';
|
import hbs from 'handlebars-inline-precompile';
|
||||||
import { assertEquals } from '../../webpack-test/src/lib/assert';
|
import {assertEquals} from '../../webpack-test/src/lib/assert';
|
||||||
|
|
||||||
Handlebars.registerHelper('loud', function(text) {
|
Handlebars.registerHelper('loud', function(text) {
|
||||||
return text.toUpperCase();
|
return text.toUpperCase();
|
||||||
});
|
});
|
||||||
|
|
||||||
const template = hbs`{{loud name}}`;
|
const template = hbs`{{loud name}}`;
|
||||||
const output = template({ name: 'yehuda' });
|
const output = template({name: 'yehuda'});
|
||||||
|
|
||||||
assertEquals(output, 'YEHUDA');
|
assertEquals(output, 'YEHUDA');
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
export function assertEquals(actual, expected) {
|
export function assertEquals(actual, expected) {
|
||||||
if (actual !== expected) {
|
if (actual !== expected) {
|
||||||
throw new Error(`Expected "${actual}" to equal "${expected}"`);
|
throw new Error(`Expected "${actual}" to equal "${expected}"`);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -3,30 +3,31 @@ const fs = require('fs');
|
|||||||
const testFiles = fs.readdirSync('src');
|
const testFiles = fs.readdirSync('src');
|
||||||
const entryPoints = {};
|
const entryPoints = {};
|
||||||
testFiles
|
testFiles
|
||||||
.filter(file => file.match(/-test.js$/))
|
.filter(file => file.match(/-test.js$/))
|
||||||
.forEach(file => {
|
.forEach(file => {
|
||||||
entryPoints[file] = `./src/${file}`;
|
entryPoints[file] = `./src/${file}`;
|
||||||
});
|
});
|
||||||
|
|
||||||
module.exports = {
|
module.exports = {
|
||||||
entry: entryPoints,
|
entry: entryPoints,
|
||||||
output: {
|
mode: 'production',
|
||||||
filename: '[name]',
|
output: {
|
||||||
path: __dirname + '/dist'
|
filename: '[name]',
|
||||||
},
|
path: __dirname + '/dist'
|
||||||
module: {
|
},
|
||||||
rules: [
|
module: {
|
||||||
{
|
rules: [
|
||||||
test: /\.js?$/,
|
{
|
||||||
exclude: /node_modules/,
|
test: /\.js?$/,
|
||||||
use: {
|
exclude: /node_modules/,
|
||||||
loader: 'babel-loader',
|
use: {
|
||||||
options: { cacheDirectory: false }
|
loader: 'babel-loader',
|
||||||
}
|
options: { cacheDirectory: false },
|
||||||
}
|
}
|
||||||
]
|
}
|
||||||
},
|
]
|
||||||
optimization: {
|
},
|
||||||
minimize: false
|
optimization: {
|
||||||
}
|
minimize: false
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
import Handlebars from 'handlebars/dist/handlebars';
|
import Handlebars from 'handlebars/dist/handlebars';
|
||||||
|
|
||||||
import { assertEquals } from './lib/assert';
|
import {assertEquals} from './lib/assert';
|
||||||
|
|
||||||
const template = Handlebars.compile('Author: {{author}}');
|
const template = Handlebars.compile('Author: {{author}}');
|
||||||
assertEquals(template({ author: 'Yehuda' }), 'Author: Yehuda');
|
assertEquals(template({author: 'Yehuda'}), 'Author: Yehuda');
|
||||||
|
|||||||
@@ -1,5 +1,6 @@
|
|||||||
import Handlebars from 'handlebars';
|
import Handlebars from 'handlebars';
|
||||||
import { assertEquals } from './lib/assert';
|
import {assertEquals} from './lib/assert';
|
||||||
|
|
||||||
|
|
||||||
const template = Handlebars.compile('Author: {{author}}');
|
const template = Handlebars.compile('Author: {{author}}');
|
||||||
assertEquals(template({ author: 'Yehuda' }), 'Author: Yehuda');
|
assertEquals(template({author: 'Yehuda'}), 'Author: Yehuda');
|
||||||
|
|||||||
@@ -1,10 +1,8 @@
|
|||||||
import { assertEquals } from './lib/assert';
|
import {assertEquals} from './lib/assert';
|
||||||
|
|
||||||
import testTemplate from './test-template.handlebars';
|
import testTemplate from './test-template.handlebars';
|
||||||
assertEquals(testTemplate({ author: 'Yehuda' }).trim(), 'Author: Yehuda');
|
assertEquals(testTemplate({author: 'Yehuda'}).trim(), 'Author: Yehuda');
|
||||||
|
|
||||||
|
|
||||||
const testTemplateRequire = require('./test-template.handlebars');
|
const testTemplateRequire = require('./test-template.handlebars');
|
||||||
assertEquals(
|
assertEquals(testTemplateRequire({author: 'Yehuda'}).trim(), 'Author: Yehuda');
|
||||||
testTemplateRequire({ author: 'Yehuda' }).trim(),
|
|
||||||
'Author: Yehuda'
|
|
||||||
);
|
|
||||||
|
|||||||
@@ -1,10 +1,10 @@
|
|||||||
import * as HandlebarsViaImport from 'handlebars';
|
import * as HandlebarsViaImport from 'handlebars';
|
||||||
const HandlebarsViaRequire = require('handlebars');
|
const HandlebarsViaRequire = require('handlebars');
|
||||||
import { assertEquals } from './lib/assert';
|
import {assertEquals} from './lib/assert';
|
||||||
|
|
||||||
HandlebarsViaImport.registerHelper('loud', function(text) {
|
HandlebarsViaImport.registerHelper('loud', function(text) {
|
||||||
return text.toUpperCase();
|
return text.toUpperCase();
|
||||||
});
|
});
|
||||||
|
|
||||||
const template = HandlebarsViaRequire.compile('Author: {{loud author}}');
|
const template = HandlebarsViaRequire.compile('Author: {{loud author}}');
|
||||||
assertEquals(template({ author: 'Yehuda' }), 'Author: YEHUDA');
|
assertEquals(template({author: 'Yehuda'}), 'Author: YEHUDA');
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
import * as Handlebars from 'handlebars/dist/handlebars';
|
import * as Handlebars from 'handlebars/dist/handlebars';
|
||||||
|
|
||||||
import { assertEquals } from './lib/assert';
|
import {assertEquals} from './lib/assert';
|
||||||
|
|
||||||
const template = Handlebars.compile('Author: {{author}}');
|
const template = Handlebars.compile('Author: {{author}}');
|
||||||
assertEquals(template({ author: 'Yehuda' }), 'Author: Yehuda');
|
assertEquals(template({author: 'Yehuda'}), 'Author: Yehuda');
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
import * as Handlebars from 'handlebars';
|
import * as Handlebars from 'handlebars';
|
||||||
import { assertEquals } from './lib/assert';
|
import {assertEquals} from './lib/assert';
|
||||||
|
|
||||||
const template = Handlebars.compile('Author: {{author}}');
|
const template = Handlebars.compile('Author: {{author}}');
|
||||||
assertEquals(template({ author: 'Yehuda' }), 'Author: Yehuda');
|
assertEquals(template({author: 'Yehuda'}), 'Author: Yehuda');
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
export function assertEquals(actual, expected) {
|
export function assertEquals(actual, expected) {
|
||||||
if (actual !== expected) {
|
if (actual !== expected) {
|
||||||
throw new Error(`Expected "${actual}" to equal "${expected}"`);
|
throw new Error(`Expected "${actual}" to equal "${expected}"`);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -3,18 +3,20 @@ const fs = require('fs');
|
|||||||
const testFiles = fs.readdirSync('src');
|
const testFiles = fs.readdirSync('src');
|
||||||
const entryPoints = {};
|
const entryPoints = {};
|
||||||
testFiles
|
testFiles
|
||||||
.filter(file => file.match(/-test.js$/))
|
.filter(file => file.match(/-test.js$/))
|
||||||
.forEach(file => {
|
.forEach(file => {
|
||||||
entryPoints[file] = `./src/${file}`;
|
entryPoints[file] = `./src/${file}`;
|
||||||
});
|
});
|
||||||
|
|
||||||
module.exports = {
|
module.exports = {
|
||||||
entry: entryPoints,
|
entry: entryPoints,
|
||||||
output: {
|
output: {
|
||||||
filename: '[name]',
|
filename: '[name]',
|
||||||
path: __dirname + '/dist'
|
path: __dirname + '/dist'
|
||||||
},
|
},
|
||||||
module: {
|
module: {
|
||||||
rules: [{ test: /\.handlebars$/, loader: 'handlebars-loader' }]
|
rules: [
|
||||||
}
|
{test: /\.handlebars$/, loader: 'handlebars-loader'}
|
||||||
|
]
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -1,56 +0,0 @@
|
|||||||
{
|
|
||||||
"extends": [
|
|
||||||
"../.eslintrc.js"
|
|
||||||
],
|
|
||||||
"overrides": [
|
|
||||||
{
|
|
||||||
"extends": [
|
|
||||||
"plugin:es5/no-es2015",
|
|
||||||
"prettier"
|
|
||||||
],
|
|
||||||
"files": ["**/*.browser.js"],
|
|
||||||
"plugins": [
|
|
||||||
"es5"
|
|
||||||
],
|
|
||||||
"globals": {
|
|
||||||
"TODO: clean this up": true,
|
|
||||||
"CompilerContext": true,
|
|
||||||
"Handlebars": true,
|
|
||||||
"handlebarsEnv": true,
|
|
||||||
"shouldCompileTo": true,
|
|
||||||
"shouldCompileToWithPartials": true,
|
|
||||||
"shouldThrow": true,
|
|
||||||
"expectTemplate": true,
|
|
||||||
"compileWithPartials": true,
|
|
||||||
"console": true,
|
|
||||||
"require": true,
|
|
||||||
"suite": true,
|
|
||||||
"equal": true,
|
|
||||||
"equals": true,
|
|
||||||
"test": true,
|
|
||||||
"testBoth": true,
|
|
||||||
"raises": true,
|
|
||||||
"deepEqual": true,
|
|
||||||
"start": true,
|
|
||||||
"stop": true,
|
|
||||||
"ok": true,
|
|
||||||
"sinon": true,
|
|
||||||
"strictEqual": true,
|
|
||||||
"define": true,
|
|
||||||
"expect": true,
|
|
||||||
"chai": true
|
|
||||||
},
|
|
||||||
"env": {
|
|
||||||
"mocha": true
|
|
||||||
},
|
|
||||||
"rules": {
|
|
||||||
// Disabling for tests, for now.
|
|
||||||
"no-path-concat": "off",
|
|
||||||
|
|
||||||
"no-var": "off",
|
|
||||||
"dot-notation": "off"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
]
|
|
||||||
|
|
||||||
}
|
|
||||||
@@ -1,19 +0,0 @@
|
|||||||
module.exports = function(config) {
|
|
||||||
config.set({
|
|
||||||
basePath: '../..',
|
|
||||||
reporters: ['dots'],
|
|
||||||
frameworks: ['mocha', 'requirejs'],
|
|
||||||
browsers: ['Chrome'],
|
|
||||||
files: [
|
|
||||||
{ pattern: 'node_modules/sinon/pkg/sinon.js', included: false },
|
|
||||||
{ pattern: 'node_modules/chai/chai.js', included: false },
|
|
||||||
{ pattern: 'node_modules/dirty-chai/lib/dirty-chai.js', included: false },
|
|
||||||
{ pattern: 'dist/handlebars.amd.js', included: false },
|
|
||||||
'karma-setup/shared/*.browser.js',
|
|
||||||
'karma-setup/amd/*.browser.js',
|
|
||||||
'spec/vendor/json2.js',
|
|
||||||
'spec/env/common.js',
|
|
||||||
{ pattern: 'spec/*.js', included: false }
|
|
||||||
]
|
|
||||||
});
|
|
||||||
};
|
|
||||||
@@ -1,38 +0,0 @@
|
|||||||
/* global requirejs */
|
|
||||||
|
|
||||||
var tests = Object.keys(window.__karma__.files).filter(function(file) {
|
|
||||||
return file.match(/^\/base\/spec\/[^/]*\.js/);
|
|
||||||
});
|
|
||||||
|
|
||||||
requirejs.config({
|
|
||||||
// Karma serves files from '/base'
|
|
||||||
baseUrl: '/base',
|
|
||||||
|
|
||||||
paths: {
|
|
||||||
handlebars: 'dist/handlebars.amd',
|
|
||||||
sinon: 'node_modules/sinon/pkg/sinon',
|
|
||||||
chai: 'node_modules/chai/chai',
|
|
||||||
dirtyChai: 'node_modules/dirty-chai/lib/dirty-chai'
|
|
||||||
},
|
|
||||||
|
|
||||||
// start test run, once Require.js is done
|
|
||||||
callback: function() {
|
|
||||||
require(['handlebars', 'chai', 'dirtyChai', 'sinon'], function(
|
|
||||||
Handlebars,
|
|
||||||
chai,
|
|
||||||
dirtyChai,
|
|
||||||
sinon
|
|
||||||
) {
|
|
||||||
window.Handlebars = Handlebars;
|
|
||||||
|
|
||||||
chai.use(dirtyChai);
|
|
||||||
window.expect = chai.expect;
|
|
||||||
|
|
||||||
window.sinon = sinon;
|
|
||||||
|
|
||||||
require(tests, function() {
|
|
||||||
window.__karma__.start();
|
|
||||||
});
|
|
||||||
});
|
|
||||||
}
|
|
||||||
});
|
|
||||||
@@ -1 +0,0 @@
|
|||||||
window.expect = chai.expect;
|
|
||||||
@@ -1,20 +0,0 @@
|
|||||||
module.exports = function(config) {
|
|
||||||
config.set({
|
|
||||||
basePath: '../..',
|
|
||||||
reporters: ['dots'],
|
|
||||||
frameworks: ['mocha'],
|
|
||||||
browsers: ['Chrome'],
|
|
||||||
files: [
|
|
||||||
'node_modules/sinon/pkg/sinon.js',
|
|
||||||
'node_modules/chai/chai.js',
|
|
||||||
'node_modules/dirty-chai/lib/dirty-chai.js',
|
|
||||||
'karma-setup/shared/*.browser.js',
|
|
||||||
'karma-setup/default/*.browser.js',
|
|
||||||
'spec/vendor/json2.js',
|
|
||||||
'spec/env/common.js',
|
|
||||||
|
|
||||||
'dist/handlebars.js',
|
|
||||||
'spec/*.js'
|
|
||||||
]
|
|
||||||
});
|
|
||||||
};
|
|
||||||
@@ -1,22 +0,0 @@
|
|||||||
window.CompilerContext = {
|
|
||||||
compile: function(template, options) {
|
|
||||||
var templateSpec = handlebarsEnv.precompile(template, options);
|
|
||||||
return handlebarsEnv.template(safeEval(templateSpec));
|
|
||||||
},
|
|
||||||
compileWithPartial: function(template, options) {
|
|
||||||
return handlebarsEnv.compile(template, options);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
function safeEval(templateSpec) {
|
|
||||||
try {
|
|
||||||
var ret;
|
|
||||||
// eslint-disable-next-line no-eval
|
|
||||||
eval('ret = ' + templateSpec);
|
|
||||||
return ret;
|
|
||||||
} catch (err) {
|
|
||||||
// eslint-disable-next-line no-console
|
|
||||||
console.error(templateSpec);
|
|
||||||
throw err;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,47 +0,0 @@
|
|||||||
// Example set of browsers to run on Sauce Labs
|
|
||||||
// Check out https://saucelabs.com/platforms for all browser/platform combos
|
|
||||||
const customLaunchers = {
|
|
||||||
sl_chrome: {
|
|
||||||
base: 'SauceLabs',
|
|
||||||
browserName: 'chrome'
|
|
||||||
},
|
|
||||||
sl_firefox: {
|
|
||||||
base: 'SauceLabs',
|
|
||||||
browserName: 'firefox',
|
|
||||||
platform: 'Linux'
|
|
||||||
},
|
|
||||||
sl_safari_9: {
|
|
||||||
base: 'SauceLabs',
|
|
||||||
browserName: 'safari',
|
|
||||||
version: 9,
|
|
||||||
platform: 'OS X 10.11'
|
|
||||||
},
|
|
||||||
sl_safari_8: {
|
|
||||||
base: 'SauceLabs',
|
|
||||||
browserName: 'safari',
|
|
||||||
version: 8,
|
|
||||||
platform: 'OS X 10.10'
|
|
||||||
},
|
|
||||||
sl_ie_10: {
|
|
||||||
base: 'SauceLabs',
|
|
||||||
browserName: 'internet explorer',
|
|
||||||
version: 10,
|
|
||||||
platform: 'Windows 8'
|
|
||||||
},
|
|
||||||
sl_ie_11: {
|
|
||||||
base: 'SauceLabs',
|
|
||||||
browserName: 'internet explorer',
|
|
||||||
platform: 'Windows 8.1',
|
|
||||||
version: '11'
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
const browsers = Object.keys(customLaunchers);
|
|
||||||
|
|
||||||
module.exports = {
|
|
||||||
customLaunchers,
|
|
||||||
browsers,
|
|
||||||
sauceLabs: {
|
|
||||||
testName: 'handlebars-unit-tests'
|
|
||||||
}
|
|
||||||
};
|
|
||||||
+3
-10
@@ -2,21 +2,16 @@ import runtime from './handlebars.runtime';
|
|||||||
|
|
||||||
// Compiler imports
|
// Compiler imports
|
||||||
import AST from './handlebars/compiler/ast';
|
import AST from './handlebars/compiler/ast';
|
||||||
import {
|
import { parser as Parser, parse, parseWithoutProcessing } from './handlebars/compiler/base';
|
||||||
parser as Parser,
|
|
||||||
parse,
|
|
||||||
parseWithoutProcessing
|
|
||||||
} from './handlebars/compiler/base';
|
|
||||||
import { Compiler, compile, precompile } from './handlebars/compiler/compiler';
|
import { Compiler, compile, precompile } from './handlebars/compiler/compiler';
|
||||||
import JavaScriptCompiler from './handlebars/compiler/javascript-compiler';
|
import JavaScriptCompiler from './handlebars/compiler/javascript-compiler';
|
||||||
import Visitor from './handlebars/compiler/visitor';
|
import Visitor from './handlebars/compiler/visitor';
|
||||||
|
|
||||||
import noConflict from './handlebars/no-conflict';
|
import noConflict from './handlebars/no-conflict';
|
||||||
|
|
||||||
let _create = runtime.create;
|
|
||||||
function create() {
|
function create() {
|
||||||
let hb = _create();
|
let hb = runtime.create();
|
||||||
|
hb.create = create;
|
||||||
hb.compile = function(input, options) {
|
hb.compile = function(input, options) {
|
||||||
return compile(input, options, hb);
|
return compile(input, options, hb);
|
||||||
};
|
};
|
||||||
@@ -35,8 +30,6 @@ function create() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
let inst = create();
|
let inst = create();
|
||||||
inst.create = create;
|
|
||||||
|
|
||||||
noConflict(inst);
|
noConflict(inst);
|
||||||
|
|
||||||
inst.Visitor = Visitor;
|
inst.Visitor = Visitor;
|
||||||
|
|||||||
+31
-10
@@ -4,31 +4,52 @@ import * as base from './handlebars/base';
|
|||||||
// (This is done to easily share code between commonjs and browse envs)
|
// (This is done to easily share code between commonjs and browse envs)
|
||||||
import SafeString from './handlebars/safe-string';
|
import SafeString from './handlebars/safe-string';
|
||||||
import Exception from './handlebars/exception';
|
import Exception from './handlebars/exception';
|
||||||
import * as Utils from './handlebars/utils';
|
import {
|
||||||
import * as runtime from './handlebars/runtime';
|
extend,
|
||||||
|
toString,
|
||||||
|
isFunction,
|
||||||
|
isArray,
|
||||||
|
indexOf,
|
||||||
|
escapeExpression,
|
||||||
|
isEmpty,
|
||||||
|
createFrame,
|
||||||
|
blockParams,
|
||||||
|
appendContextPath
|
||||||
|
} from './handlebars/utils';
|
||||||
|
import {checkRevision, template, wrapProgram, resolvePartial, invokePartial, noop} from './handlebars/runtime';
|
||||||
|
|
||||||
import noConflict from './handlebars/no-conflict';
|
import noConflict from './handlebars/no-conflict';
|
||||||
|
|
||||||
// For compatibility and usage outside of module systems, make the Handlebars object a namespace
|
// For compatibility and usage outside of module systems, make the Handlebars object a namespace
|
||||||
function create() {
|
export function create() {
|
||||||
let hb = new base.HandlebarsEnvironment();
|
let hb = new base.HandlebarsEnvironment();
|
||||||
|
|
||||||
Utils.extend(hb, base);
|
extend(hb, base);
|
||||||
hb.SafeString = SafeString;
|
hb.SafeString = SafeString;
|
||||||
hb.Exception = Exception;
|
hb.Exception = Exception;
|
||||||
hb.Utils = Utils;
|
hb.Utils = {
|
||||||
hb.escapeExpression = Utils.escapeExpression;
|
extend,
|
||||||
|
toString,
|
||||||
hb.VM = runtime;
|
isFunction,
|
||||||
|
isArray,
|
||||||
|
indexOf,
|
||||||
|
escapeExpression,
|
||||||
|
isEmpty,
|
||||||
|
createFrame,
|
||||||
|
blockParams,
|
||||||
|
appendContextPath
|
||||||
|
};
|
||||||
|
hb.escapeExpression = escapeExpression;
|
||||||
|
hb.create = create;
|
||||||
|
hb.VM = {checkRevision, template, wrapProgram, resolvePartial, invokePartial, noop};
|
||||||
hb.template = function(spec) {
|
hb.template = function(spec) {
|
||||||
return runtime.template(spec, hb);
|
return template(spec, hb);
|
||||||
};
|
};
|
||||||
|
|
||||||
return hb;
|
return hb;
|
||||||
}
|
}
|
||||||
|
|
||||||
let inst = create();
|
let inst = create();
|
||||||
inst.create = create;
|
|
||||||
|
|
||||||
noConflict(inst);
|
noConflict(inst);
|
||||||
|
|
||||||
|
|||||||
+8
-22
@@ -1,11 +1,10 @@
|
|||||||
import { createFrame, extend, toString } from './utils';
|
import {createFrame, extend, toString} from './utils';
|
||||||
import Exception from './exception';
|
import Exception from './exception';
|
||||||
import { registerDefaultHelpers } from './helpers';
|
import {registerDefaultHelpers} from './helpers';
|
||||||
import { registerDefaultDecorators } from './decorators';
|
import {registerDefaultDecorators} from './decorators';
|
||||||
import logger from './logger';
|
import logger from './logger';
|
||||||
import { resetLoggedProperties } from './internal/proto-access';
|
|
||||||
|
|
||||||
export const VERSION = '4.7.6';
|
export const VERSION = '4.5.3';
|
||||||
export const COMPILER_REVISION = 8;
|
export const COMPILER_REVISION = 8;
|
||||||
export const LAST_COMPATIBLE_COMPILER_REVISION = 7;
|
export const LAST_COMPATIBLE_COMPILER_REVISION = 7;
|
||||||
|
|
||||||
@@ -39,9 +38,7 @@ HandlebarsEnvironment.prototype = {
|
|||||||
|
|
||||||
registerHelper: function(name, fn) {
|
registerHelper: function(name, fn) {
|
||||||
if (toString.call(name) === objectType) {
|
if (toString.call(name) === objectType) {
|
||||||
if (fn) {
|
if (fn) { throw new Exception('Arg not supported with multiple helpers'); }
|
||||||
throw new Exception('Arg not supported with multiple helpers');
|
|
||||||
}
|
|
||||||
extend(this.helpers, name);
|
extend(this.helpers, name);
|
||||||
} else {
|
} else {
|
||||||
this.helpers[name] = fn;
|
this.helpers[name] = fn;
|
||||||
@@ -56,9 +53,7 @@ HandlebarsEnvironment.prototype = {
|
|||||||
extend(this.partials, name);
|
extend(this.partials, name);
|
||||||
} else {
|
} else {
|
||||||
if (typeof partial === 'undefined') {
|
if (typeof partial === 'undefined') {
|
||||||
throw new Exception(
|
throw new Exception(`Attempting to register a partial called "${name}" as undefined`);
|
||||||
`Attempting to register a partial called "${name}" as undefined`
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
this.partials[name] = partial;
|
this.partials[name] = partial;
|
||||||
}
|
}
|
||||||
@@ -69,9 +64,7 @@ HandlebarsEnvironment.prototype = {
|
|||||||
|
|
||||||
registerDecorator: function(name, fn) {
|
registerDecorator: function(name, fn) {
|
||||||
if (toString.call(name) === objectType) {
|
if (toString.call(name) === objectType) {
|
||||||
if (fn) {
|
if (fn) { throw new Exception('Arg not supported with multiple decorators'); }
|
||||||
throw new Exception('Arg not supported with multiple decorators');
|
|
||||||
}
|
|
||||||
extend(this.decorators, name);
|
extend(this.decorators, name);
|
||||||
} else {
|
} else {
|
||||||
this.decorators[name] = fn;
|
this.decorators[name] = fn;
|
||||||
@@ -79,16 +72,9 @@ HandlebarsEnvironment.prototype = {
|
|||||||
},
|
},
|
||||||
unregisterDecorator: function(name) {
|
unregisterDecorator: function(name) {
|
||||||
delete this.decorators[name];
|
delete this.decorators[name];
|
||||||
},
|
|
||||||
/**
|
|
||||||
* Reset the memory of illegal property accesses that have already been logged.
|
|
||||||
* @deprecated should only be used in handlebars test-cases
|
|
||||||
*/
|
|
||||||
resetLoggedPropertyAccesses() {
|
|
||||||
resetLoggedProperties();
|
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
export let log = logger.log;
|
export let log = logger.log;
|
||||||
|
|
||||||
export { createFrame, logger };
|
export {createFrame, logger};
|
||||||
|
|||||||
@@ -5,28 +5,24 @@ let AST = {
|
|||||||
// * it is an eligible helper, and
|
// * it is an eligible helper, and
|
||||||
// * it has at least one parameter or hash segment
|
// * it has at least one parameter or hash segment
|
||||||
helperExpression: function(node) {
|
helperExpression: function(node) {
|
||||||
return (
|
return (node.type === 'SubExpression')
|
||||||
node.type === 'SubExpression' ||
|
|| ((node.type === 'MustacheStatement' || node.type === 'BlockStatement')
|
||||||
((node.type === 'MustacheStatement' ||
|
&& !!((node.params && node.params.length) || node.hash));
|
||||||
node.type === 'BlockStatement') &&
|
|
||||||
!!((node.params && node.params.length) || node.hash))
|
|
||||||
);
|
|
||||||
},
|
},
|
||||||
|
|
||||||
scopedId: function(path) {
|
scopedId: function(path) {
|
||||||
return /^\.|this\b/.test(path.original);
|
return (/^\.|this\b/).test(path.original);
|
||||||
},
|
},
|
||||||
|
|
||||||
// an ID is simple if it only has one part, and that part is not
|
// an ID is simple if it only has one part, and that part is not
|
||||||
// `..` or `this`.
|
// `..` or `this`.
|
||||||
simpleId: function(path) {
|
simpleId: function(path) {
|
||||||
return (
|
return path.parts.length === 1 && !AST.helpers.scopedId(path) && !path.depth;
|
||||||
path.parts.length === 1 && !AST.helpers.scopedId(path) && !path.depth
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
// Must be exported as an object rather than the root of the module as the jison lexer
|
// Must be exported as an object rather than the root of the module as the jison lexer
|
||||||
// must modify the object to operate properly.
|
// must modify the object to operate properly.
|
||||||
export default AST;
|
export default AST;
|
||||||
|
|||||||
@@ -10,9 +10,7 @@ extend(yy, Helpers);
|
|||||||
|
|
||||||
export function parseWithoutProcessing(input, options) {
|
export function parseWithoutProcessing(input, options) {
|
||||||
// Just return if an already-compiled AST was passed in.
|
// Just return if an already-compiled AST was passed in.
|
||||||
if (input.type === 'Program') {
|
if (input.type === 'Program') { return input; }
|
||||||
return input;
|
|
||||||
}
|
|
||||||
|
|
||||||
parser.yy = yy;
|
parser.yy = yy;
|
||||||
|
|
||||||
|
|||||||
@@ -1,16 +1,11 @@
|
|||||||
/* global define */
|
import {isArray} from '../utils';
|
||||||
import { isArray } from '../utils';
|
|
||||||
|
|
||||||
let SourceNode;
|
let SourceNode;
|
||||||
|
|
||||||
try {
|
try {
|
||||||
/* istanbul ignore next */
|
// the 'source-map' map package is ignored in 'umd' and 'amd' builds (via webpack-config)
|
||||||
if (typeof define !== 'function' || !define.amd) {
|
let SourceMap = require('source-map');
|
||||||
// We don't support this in AMD environments. For these environments, we asusme that
|
SourceNode = SourceMap.SourceNode;
|
||||||
// they are running on the browser and thus have no need for the source-map library.
|
|
||||||
let SourceMap = require('source-map');
|
|
||||||
SourceNode = SourceMap.SourceNode;
|
|
||||||
}
|
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
/* NOP */
|
/* NOP */
|
||||||
}
|
}
|
||||||
@@ -38,7 +33,7 @@ if (!SourceNode) {
|
|||||||
this.src = chunks + this.src;
|
this.src = chunks + this.src;
|
||||||
},
|
},
|
||||||
toStringWithSourceMap: function() {
|
toStringWithSourceMap: function() {
|
||||||
return { code: this.toString() };
|
return {code: this.toString()};
|
||||||
},
|
},
|
||||||
toString: function() {
|
toString: function() {
|
||||||
return this.src;
|
return this.src;
|
||||||
@@ -46,6 +41,7 @@ if (!SourceNode) {
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
function castChunk(chunk, codeGen, loc) {
|
function castChunk(chunk, codeGen, loc) {
|
||||||
if (isArray(chunk)) {
|
if (isArray(chunk)) {
|
||||||
let ret = [];
|
let ret = [];
|
||||||
@@ -61,6 +57,7 @@ function castChunk(chunk, codeGen, loc) {
|
|||||||
return chunk;
|
return chunk;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
function CodeGen(srcFile) {
|
function CodeGen(srcFile) {
|
||||||
this.srcFile = srcFile;
|
this.srcFile = srcFile;
|
||||||
this.source = [];
|
this.source = [];
|
||||||
@@ -92,22 +89,17 @@ CodeGen.prototype = {
|
|||||||
},
|
},
|
||||||
|
|
||||||
empty: function() {
|
empty: function() {
|
||||||
let loc = this.currentLocation || { start: {} };
|
let loc = this.currentLocation || {start: {}};
|
||||||
return new SourceNode(loc.start.line, loc.start.column, this.srcFile);
|
return new SourceNode(loc.start.line, loc.start.column, this.srcFile);
|
||||||
},
|
},
|
||||||
wrap: function(chunk, loc = this.currentLocation || { start: {} }) {
|
wrap: function(chunk, loc = this.currentLocation || {start: {}}) {
|
||||||
if (chunk instanceof SourceNode) {
|
if (chunk instanceof SourceNode) {
|
||||||
return chunk;
|
return chunk;
|
||||||
}
|
}
|
||||||
|
|
||||||
chunk = castChunk(chunk, this, loc);
|
chunk = castChunk(chunk, this, loc);
|
||||||
|
|
||||||
return new SourceNode(
|
return new SourceNode(loc.start.line, loc.start.column, this.srcFile, chunk);
|
||||||
loc.start.line,
|
|
||||||
loc.start.column,
|
|
||||||
this.srcFile,
|
|
||||||
chunk
|
|
||||||
);
|
|
||||||
},
|
},
|
||||||
|
|
||||||
functionCall: function(fn, type, params) {
|
functionCall: function(fn, type, params) {
|
||||||
@@ -116,17 +108,13 @@ CodeGen.prototype = {
|
|||||||
},
|
},
|
||||||
|
|
||||||
quotedString: function(str) {
|
quotedString: function(str) {
|
||||||
return (
|
return '"' + (str + '')
|
||||||
'"' +
|
.replace(/\\/g, '\\\\')
|
||||||
(str + '')
|
.replace(/"/g, '\\"')
|
||||||
.replace(/\\/g, '\\\\')
|
.replace(/\n/g, '\\n')
|
||||||
.replace(/"/g, '\\"')
|
.replace(/\r/g, '\\r')
|
||||||
.replace(/\n/g, '\\n')
|
.replace(/\u2028/g, '\\u2028') // Per Ecma-262 7.3 + 7.8.4
|
||||||
.replace(/\r/g, '\\r')
|
.replace(/\u2029/g, '\\u2029') + '"';
|
||||||
.replace(/\u2028/g, '\\u2028') // Per Ecma-262 7.3 + 7.8.4
|
|
||||||
.replace(/\u2029/g, '\\u2029') +
|
|
||||||
'"'
|
|
||||||
);
|
|
||||||
},
|
},
|
||||||
|
|
||||||
objectLiteral: function(obj) {
|
objectLiteral: function(obj) {
|
||||||
@@ -145,6 +133,7 @@ CodeGen.prototype = {
|
|||||||
return ret;
|
return ret;
|
||||||
},
|
},
|
||||||
|
|
||||||
|
|
||||||
generateList: function(entries) {
|
generateList: function(entries) {
|
||||||
let ret = this.empty();
|
let ret = this.empty();
|
||||||
|
|
||||||
@@ -169,3 +158,4 @@ CodeGen.prototype = {
|
|||||||
};
|
};
|
||||||
|
|
||||||
export default CodeGen;
|
export default CodeGen;
|
||||||
|
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
/* eslint-disable new-cap */
|
/* eslint-disable new-cap */
|
||||||
|
|
||||||
import Exception from '../exception';
|
import Exception from '../exception';
|
||||||
import { isArray, indexOf, extend } from '../utils';
|
import {isArray, indexOf, extend} from '../utils';
|
||||||
import AST from './ast';
|
import AST from './ast';
|
||||||
|
|
||||||
const slice = [].slice;
|
const slice = [].slice;
|
||||||
@@ -24,11 +24,8 @@ Compiler.prototype = {
|
|||||||
|
|
||||||
for (let i = 0; i < len; i++) {
|
for (let i = 0; i < len; i++) {
|
||||||
let opcode = this.opcodes[i],
|
let opcode = this.opcodes[i],
|
||||||
otherOpcode = other.opcodes[i];
|
otherOpcode = other.opcodes[i];
|
||||||
if (
|
if (opcode.opcode !== otherOpcode.opcode || !argEquals(opcode.args, otherOpcode.args)) {
|
||||||
opcode.opcode !== otherOpcode.opcode ||
|
|
||||||
!argEquals(opcode.args, otherOpcode.args)
|
|
||||||
) {
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -57,28 +54,24 @@ Compiler.prototype = {
|
|||||||
|
|
||||||
options.blockParams = options.blockParams || [];
|
options.blockParams = options.blockParams || [];
|
||||||
|
|
||||||
options.knownHelpers = extend(
|
options.knownHelpers = extend(Object.create(null), {
|
||||||
Object.create(null),
|
'helperMissing': true,
|
||||||
{
|
'blockHelperMissing': true,
|
||||||
helperMissing: true,
|
'each': true,
|
||||||
blockHelperMissing: true,
|
'if': true,
|
||||||
each: true,
|
'unless': true,
|
||||||
if: true,
|
'with': true,
|
||||||
unless: true,
|
'log': true,
|
||||||
with: true,
|
'lookup': true
|
||||||
log: true,
|
}, options.knownHelpers);
|
||||||
lookup: true
|
|
||||||
},
|
|
||||||
options.knownHelpers
|
|
||||||
);
|
|
||||||
|
|
||||||
return this.accept(program);
|
return this.accept(program);
|
||||||
},
|
},
|
||||||
|
|
||||||
compileProgram: function(program) {
|
compileProgram: function(program) {
|
||||||
let childCompiler = new this.compiler(), // eslint-disable-line new-cap
|
let childCompiler = new this.compiler(), // eslint-disable-line new-cap
|
||||||
result = childCompiler.compile(program, this.options),
|
result = childCompiler.compile(program, this.options),
|
||||||
guid = this.guid++;
|
guid = this.guid++;
|
||||||
|
|
||||||
this.usePartial = this.usePartial || result.usePartial;
|
this.usePartial = this.usePartial || result.usePartial;
|
||||||
|
|
||||||
@@ -104,7 +97,7 @@ Compiler.prototype = {
|
|||||||
this.options.blockParams.unshift(program.blockParams);
|
this.options.blockParams.unshift(program.blockParams);
|
||||||
|
|
||||||
let body = program.body,
|
let body = program.body,
|
||||||
bodyLength = body.length;
|
bodyLength = body.length;
|
||||||
for (let i = 0; i < bodyLength; i++) {
|
for (let i = 0; i < bodyLength; i++) {
|
||||||
this.accept(body[i]);
|
this.accept(body[i]);
|
||||||
}
|
}
|
||||||
@@ -121,7 +114,7 @@ Compiler.prototype = {
|
|||||||
transformLiteralToPath(block);
|
transformLiteralToPath(block);
|
||||||
|
|
||||||
let program = block.program,
|
let program = block.program,
|
||||||
inverse = block.inverse;
|
inverse = block.inverse;
|
||||||
|
|
||||||
program = program && this.compileProgram(program);
|
program = program && this.compileProgram(program);
|
||||||
inverse = inverse && this.compileProgram(inverse);
|
inverse = inverse && this.compileProgram(inverse);
|
||||||
@@ -156,7 +149,7 @@ Compiler.prototype = {
|
|||||||
DecoratorBlock(decorator) {
|
DecoratorBlock(decorator) {
|
||||||
let program = decorator.program && this.compileProgram(decorator.program);
|
let program = decorator.program && this.compileProgram(decorator.program);
|
||||||
let params = this.setupFullMustacheParams(decorator, program, undefined),
|
let params = this.setupFullMustacheParams(decorator, program, undefined),
|
||||||
path = decorator.path;
|
path = decorator.path;
|
||||||
|
|
||||||
this.useDecorators = true;
|
this.useDecorators = true;
|
||||||
this.opcode('registerDecorator', params.length, path.original);
|
this.opcode('registerDecorator', params.length, path.original);
|
||||||
@@ -172,20 +165,17 @@ Compiler.prototype = {
|
|||||||
|
|
||||||
let params = partial.params;
|
let params = partial.params;
|
||||||
if (params.length > 1) {
|
if (params.length > 1) {
|
||||||
throw new Exception(
|
throw new Exception('Unsupported number of partial arguments: ' + params.length, partial);
|
||||||
'Unsupported number of partial arguments: ' + params.length,
|
|
||||||
partial
|
|
||||||
);
|
|
||||||
} else if (!params.length) {
|
} else if (!params.length) {
|
||||||
if (this.options.explicitPartialContext) {
|
if (this.options.explicitPartialContext) {
|
||||||
this.opcode('pushLiteral', 'undefined');
|
this.opcode('pushLiteral', 'undefined');
|
||||||
} else {
|
} else {
|
||||||
params.push({ type: 'PathExpression', parts: [], depth: 0 });
|
params.push({type: 'PathExpression', parts: [], depth: 0});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
let partialName = partial.name.original,
|
let partialName = partial.name.original,
|
||||||
isDynamic = partial.name.type === 'SubExpression';
|
isDynamic = partial.name.type === 'SubExpression';
|
||||||
if (isDynamic) {
|
if (isDynamic) {
|
||||||
this.accept(partial.name);
|
this.accept(partial.name);
|
||||||
}
|
}
|
||||||
@@ -218,6 +208,7 @@ Compiler.prototype = {
|
|||||||
this.DecoratorBlock(decorator);
|
this.DecoratorBlock(decorator);
|
||||||
},
|
},
|
||||||
|
|
||||||
|
|
||||||
ContentStatement: function(content) {
|
ContentStatement: function(content) {
|
||||||
if (content.value) {
|
if (content.value) {
|
||||||
this.opcode('appendContent', content.value);
|
this.opcode('appendContent', content.value);
|
||||||
@@ -240,8 +231,8 @@ Compiler.prototype = {
|
|||||||
},
|
},
|
||||||
ambiguousSexpr: function(sexpr, program, inverse) {
|
ambiguousSexpr: function(sexpr, program, inverse) {
|
||||||
let path = sexpr.path,
|
let path = sexpr.path,
|
||||||
name = path.parts[0],
|
name = path.parts[0],
|
||||||
isBlock = program != null || inverse != null;
|
isBlock = program != null || inverse != null;
|
||||||
|
|
||||||
this.opcode('getContext', path.depth);
|
this.opcode('getContext', path.depth);
|
||||||
|
|
||||||
@@ -263,27 +254,19 @@ Compiler.prototype = {
|
|||||||
|
|
||||||
helperSexpr: function(sexpr, program, inverse) {
|
helperSexpr: function(sexpr, program, inverse) {
|
||||||
let params = this.setupFullMustacheParams(sexpr, program, inverse),
|
let params = this.setupFullMustacheParams(sexpr, program, inverse),
|
||||||
path = sexpr.path,
|
path = sexpr.path,
|
||||||
name = path.parts[0];
|
name = path.parts[0];
|
||||||
|
|
||||||
if (this.options.knownHelpers[name]) {
|
if (this.options.knownHelpers[name]) {
|
||||||
this.opcode('invokeKnownHelper', params.length, name);
|
this.opcode('invokeKnownHelper', params.length, name);
|
||||||
} else if (this.options.knownHelpersOnly) {
|
} else if (this.options.knownHelpersOnly) {
|
||||||
throw new Exception(
|
throw new Exception('You specified knownHelpersOnly, but used the unknown helper ' + name, sexpr);
|
||||||
'You specified knownHelpersOnly, but used the unknown helper ' + name,
|
|
||||||
sexpr
|
|
||||||
);
|
|
||||||
} else {
|
} else {
|
||||||
path.strict = true;
|
path.strict = true;
|
||||||
path.falsy = true;
|
path.falsy = true;
|
||||||
|
|
||||||
this.accept(path);
|
this.accept(path);
|
||||||
this.opcode(
|
this.opcode('invokeHelper', params.length, path.original, AST.helpers.simpleId(path));
|
||||||
'invokeHelper',
|
|
||||||
params.length,
|
|
||||||
path.original,
|
|
||||||
AST.helpers.simpleId(path)
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
@@ -292,8 +275,8 @@ Compiler.prototype = {
|
|||||||
this.opcode('getContext', path.depth);
|
this.opcode('getContext', path.depth);
|
||||||
|
|
||||||
let name = path.parts[0],
|
let name = path.parts[0],
|
||||||
scoped = AST.helpers.scopedId(path),
|
scoped = AST.helpers.scopedId(path),
|
||||||
blockParamId = !path.depth && !scoped && this.blockParamIndex(name);
|
blockParamId = !path.depth && !scoped && this.blockParamIndex(name);
|
||||||
|
|
||||||
if (blockParamId) {
|
if (blockParamId) {
|
||||||
this.opcode('lookupBlockParam', blockParamId, path.parts);
|
this.opcode('lookupBlockParam', blockParamId, path.parts);
|
||||||
@@ -304,13 +287,7 @@ Compiler.prototype = {
|
|||||||
this.options.data = true;
|
this.options.data = true;
|
||||||
this.opcode('lookupData', path.depth, path.parts, path.strict);
|
this.opcode('lookupData', path.depth, path.parts, path.strict);
|
||||||
} else {
|
} else {
|
||||||
this.opcode(
|
this.opcode('lookupOnContext', path.parts, path.falsy, path.strict, scoped);
|
||||||
'lookupOnContext',
|
|
||||||
path.parts,
|
|
||||||
path.falsy,
|
|
||||||
path.strict,
|
|
||||||
scoped
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
@@ -336,8 +313,8 @@ Compiler.prototype = {
|
|||||||
|
|
||||||
Hash: function(hash) {
|
Hash: function(hash) {
|
||||||
let pairs = hash.pairs,
|
let pairs = hash.pairs,
|
||||||
i = 0,
|
i = 0,
|
||||||
l = pairs.length;
|
l = pairs.length;
|
||||||
|
|
||||||
this.opcode('pushHash');
|
this.opcode('pushHash');
|
||||||
|
|
||||||
@@ -352,11 +329,7 @@ Compiler.prototype = {
|
|||||||
|
|
||||||
// HELPERS
|
// HELPERS
|
||||||
opcode: function(name) {
|
opcode: function(name) {
|
||||||
this.opcodes.push({
|
this.opcodes.push({ opcode: name, args: slice.call(arguments, 1), loc: this.sourceNode[0].loc });
|
||||||
opcode: name,
|
|
||||||
args: slice.call(arguments, 1),
|
|
||||||
loc: this.sourceNode[0].loc
|
|
||||||
});
|
|
||||||
},
|
},
|
||||||
|
|
||||||
addDepth: function(depth) {
|
addDepth: function(depth) {
|
||||||
@@ -385,7 +358,7 @@ Compiler.prototype = {
|
|||||||
// An eligible helper is one that does not have a complex path, i.e. `this.foo`, `../foo` etc.
|
// An eligible helper is one that does not have a complex path, i.e. `this.foo`, `../foo` etc.
|
||||||
if (isEligible && !isHelper) {
|
if (isEligible && !isHelper) {
|
||||||
let name = sexpr.path.parts[0],
|
let name = sexpr.path.parts[0],
|
||||||
options = this.options;
|
options = this.options;
|
||||||
if (options.knownHelpers[name]) {
|
if (options.knownHelpers[name]) {
|
||||||
isHelper = true;
|
isHelper = true;
|
||||||
} else if (options.knownHelpersOnly) {
|
} else if (options.knownHelpersOnly) {
|
||||||
@@ -413,7 +386,9 @@ Compiler.prototype = {
|
|||||||
|
|
||||||
if (this.stringParams) {
|
if (this.stringParams) {
|
||||||
if (value.replace) {
|
if (value.replace) {
|
||||||
value = value.replace(/^(\.?\.\/)*/g, '').replace(/\//g, '.');
|
value = value
|
||||||
|
.replace(/^(\.?\.\/)*/g, '')
|
||||||
|
.replace(/\//g, '.');
|
||||||
}
|
}
|
||||||
|
|
||||||
if (val.depth) {
|
if (val.depth) {
|
||||||
@@ -431,7 +406,7 @@ Compiler.prototype = {
|
|||||||
if (this.trackIds) {
|
if (this.trackIds) {
|
||||||
let blockParamIndex;
|
let blockParamIndex;
|
||||||
if (val.parts && !AST.helpers.scopedId(val) && !val.depth) {
|
if (val.parts && !AST.helpers.scopedId(val) && !val.depth) {
|
||||||
blockParamIndex = this.blockParamIndex(val.parts[0]);
|
blockParamIndex = this.blockParamIndex(val.parts[0]);
|
||||||
}
|
}
|
||||||
if (blockParamIndex) {
|
if (blockParamIndex) {
|
||||||
let blockParamChild = val.parts.slice(1).join('.');
|
let blockParamChild = val.parts.slice(1).join('.');
|
||||||
@@ -440,9 +415,9 @@ Compiler.prototype = {
|
|||||||
value = val.original || value;
|
value = val.original || value;
|
||||||
if (value.replace) {
|
if (value.replace) {
|
||||||
value = value
|
value = value
|
||||||
.replace(/^this(?:\.|$)/, '')
|
.replace(/^this(?:\.|$)/, '')
|
||||||
.replace(/^\.\//, '')
|
.replace(/^\.\//, '')
|
||||||
.replace(/^\.$/, '');
|
.replace(/^\.$/, '');
|
||||||
}
|
}
|
||||||
|
|
||||||
this.opcode('pushId', val.type, value);
|
this.opcode('pushId', val.type, value);
|
||||||
@@ -469,13 +444,9 @@ Compiler.prototype = {
|
|||||||
},
|
},
|
||||||
|
|
||||||
blockParamIndex: function(name) {
|
blockParamIndex: function(name) {
|
||||||
for (
|
for (let depth = 0, len = this.options.blockParams.length; depth < len; depth++) {
|
||||||
let depth = 0, len = this.options.blockParams.length;
|
|
||||||
depth < len;
|
|
||||||
depth++
|
|
||||||
) {
|
|
||||||
let blockParams = this.options.blockParams[depth],
|
let blockParams = this.options.blockParams[depth],
|
||||||
param = blockParams && indexOf(blockParams, name);
|
param = blockParams && indexOf(blockParams, name);
|
||||||
if (blockParams && param >= 0) {
|
if (blockParams && param >= 0) {
|
||||||
return [depth, param];
|
return [depth, param];
|
||||||
}
|
}
|
||||||
@@ -484,14 +455,8 @@ Compiler.prototype = {
|
|||||||
};
|
};
|
||||||
|
|
||||||
export function precompile(input, options, env) {
|
export function precompile(input, options, env) {
|
||||||
if (
|
if (input == null || (typeof input !== 'string' && input.type !== 'Program')) {
|
||||||
input == null ||
|
throw new Exception('You must pass a string or Handlebars AST to Handlebars.precompile. You passed ' + input);
|
||||||
(typeof input !== 'string' && input.type !== 'Program')
|
|
||||||
) {
|
|
||||||
throw new Exception(
|
|
||||||
'You must pass a string or Handlebars AST to Handlebars.precompile. You passed ' +
|
|
||||||
input
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
options = options || {};
|
options = options || {};
|
||||||
@@ -503,19 +468,13 @@ export function precompile(input, options, env) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
let ast = env.parse(input, options),
|
let ast = env.parse(input, options),
|
||||||
environment = new env.Compiler().compile(ast, options);
|
environment = new env.Compiler().compile(ast, options);
|
||||||
return new env.JavaScriptCompiler().compile(environment, options);
|
return new env.JavaScriptCompiler().compile(environment, options);
|
||||||
}
|
}
|
||||||
|
|
||||||
export function compile(input, options = {}, env) {
|
export function compile(input, options = {}, env) {
|
||||||
if (
|
if (input == null || (typeof input !== 'string' && input.type !== 'Program')) {
|
||||||
input == null ||
|
throw new Exception('You must pass a string or Handlebars AST to Handlebars.compile. You passed ' + input);
|
||||||
(typeof input !== 'string' && input.type !== 'Program')
|
|
||||||
) {
|
|
||||||
throw new Exception(
|
|
||||||
'You must pass a string or Handlebars AST to Handlebars.compile. You passed ' +
|
|
||||||
input
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
options = extend({}, options);
|
options = extend({}, options);
|
||||||
@@ -530,13 +489,8 @@ export function compile(input, options = {}, env) {
|
|||||||
|
|
||||||
function compileInput() {
|
function compileInput() {
|
||||||
let ast = env.parse(input, options),
|
let ast = env.parse(input, options),
|
||||||
environment = new env.Compiler().compile(ast, options),
|
environment = new env.Compiler().compile(ast, options),
|
||||||
templateSpec = new env.JavaScriptCompiler().compile(
|
templateSpec = new env.JavaScriptCompiler().compile(environment, options, undefined, true);
|
||||||
environment,
|
|
||||||
options,
|
|
||||||
undefined,
|
|
||||||
true
|
|
||||||
);
|
|
||||||
return env.template(templateSpec);
|
return env.template(templateSpec);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -4,12 +4,9 @@ function validateClose(open, close) {
|
|||||||
close = close.path ? close.path.original : close;
|
close = close.path ? close.path.original : close;
|
||||||
|
|
||||||
if (open.path.original !== close) {
|
if (open.path.original !== close) {
|
||||||
let errorNode = { loc: open.path.loc };
|
let errorNode = {loc: open.path.loc};
|
||||||
|
|
||||||
throw new Exception(
|
throw new Exception(open.path.original + " doesn't match " + close, errorNode);
|
||||||
open.path.original + " doesn't match " + close,
|
|
||||||
errorNode
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -41,26 +38,27 @@ export function stripFlags(open, close) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
export function stripComment(comment) {
|
export function stripComment(comment) {
|
||||||
return comment.replace(/^\{\{~?!-?-?/, '').replace(/-?-?~?\}\}$/, '');
|
return comment.replace(/^\{\{~?!-?-?/, '')
|
||||||
|
.replace(/-?-?~?\}\}$/, '');
|
||||||
}
|
}
|
||||||
|
|
||||||
export function preparePath(data, parts, loc) {
|
export function preparePath(data, parts, loc) {
|
||||||
loc = this.locInfo(loc);
|
loc = this.locInfo(loc);
|
||||||
|
|
||||||
let original = data ? '@' : '',
|
let original = data ? '@' : '',
|
||||||
dig = [],
|
dig = [],
|
||||||
depth = 0;
|
depth = 0;
|
||||||
|
|
||||||
for (let i = 0, l = parts.length; i < l; i++) {
|
for (let i = 0, l = parts.length; i < l; i++) {
|
||||||
let part = parts[i].part,
|
let part = parts[i].part,
|
||||||
// If we have [] syntax then we do not treat path references as operators,
|
// If we have [] syntax then we do not treat path references as operators,
|
||||||
// i.e. foo.[this] resolves to approximately context.foo['this']
|
// i.e. foo.[this] resolves to approximately context.foo['this']
|
||||||
isLiteral = parts[i].original !== part;
|
isLiteral = parts[i].original !== part;
|
||||||
original += (parts[i].separator || '') + part;
|
original += (parts[i].separator || '') + part;
|
||||||
|
|
||||||
if (!isLiteral && (part === '..' || part === '.' || part === 'this')) {
|
if (!isLiteral && (part === '..' || part === '.' || part === 'this')) {
|
||||||
if (dig.length > 0) {
|
if (dig.length > 0) {
|
||||||
throw new Exception('Invalid path: ' + original, { loc });
|
throw new Exception('Invalid path: ' + original, {loc});
|
||||||
} else if (part === '..') {
|
} else if (part === '..') {
|
||||||
depth++;
|
depth++;
|
||||||
}
|
}
|
||||||
@@ -82,9 +80,9 @@ export function preparePath(data, parts, loc) {
|
|||||||
export function prepareMustache(path, params, hash, open, strip, locInfo) {
|
export function prepareMustache(path, params, hash, open, strip, locInfo) {
|
||||||
// Must use charAt to support IE pre-10
|
// Must use charAt to support IE pre-10
|
||||||
let escapeFlag = open.charAt(3) || open.charAt(2),
|
let escapeFlag = open.charAt(3) || open.charAt(2),
|
||||||
escaped = escapeFlag !== '{' && escapeFlag !== '&';
|
escaped = escapeFlag !== '{' && escapeFlag !== '&';
|
||||||
|
|
||||||
let decorator = /\*/.test(open);
|
let decorator = (/\*/.test(open));
|
||||||
return {
|
return {
|
||||||
type: decorator ? 'Decorator' : 'MustacheStatement',
|
type: decorator ? 'Decorator' : 'MustacheStatement',
|
||||||
path,
|
path,
|
||||||
@@ -120,30 +118,21 @@ export function prepareRawBlock(openRawBlock, contents, close, locInfo) {
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
export function prepareBlock(
|
export function prepareBlock(openBlock, program, inverseAndProgram, close, inverted, locInfo) {
|
||||||
openBlock,
|
|
||||||
program,
|
|
||||||
inverseAndProgram,
|
|
||||||
close,
|
|
||||||
inverted,
|
|
||||||
locInfo
|
|
||||||
) {
|
|
||||||
if (close && close.path) {
|
if (close && close.path) {
|
||||||
validateClose(openBlock, close);
|
validateClose(openBlock, close);
|
||||||
}
|
}
|
||||||
|
|
||||||
let decorator = /\*/.test(openBlock.open);
|
let decorator = (/\*/.test(openBlock.open));
|
||||||
|
|
||||||
program.blockParams = openBlock.blockParams;
|
program.blockParams = openBlock.blockParams;
|
||||||
|
|
||||||
let inverse, inverseStrip;
|
let inverse,
|
||||||
|
inverseStrip;
|
||||||
|
|
||||||
if (inverseAndProgram) {
|
if (inverseAndProgram) {
|
||||||
if (decorator) {
|
if (decorator) {
|
||||||
throw new Exception(
|
throw new Exception('Unexpected inverse block on decorator', inverseAndProgram);
|
||||||
'Unexpected inverse block on decorator',
|
|
||||||
inverseAndProgram
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (inverseAndProgram.chain) {
|
if (inverseAndProgram.chain) {
|
||||||
@@ -177,7 +166,7 @@ export function prepareBlock(
|
|||||||
export function prepareProgram(statements, loc) {
|
export function prepareProgram(statements, loc) {
|
||||||
if (!loc && statements.length) {
|
if (!loc && statements.length) {
|
||||||
const firstLoc = statements[0].loc,
|
const firstLoc = statements[0].loc,
|
||||||
lastLoc = statements[statements.length - 1].loc;
|
lastLoc = statements[statements.length - 1].loc;
|
||||||
|
|
||||||
/* istanbul ignore else */
|
/* istanbul ignore else */
|
||||||
if (firstLoc && lastLoc) {
|
if (firstLoc && lastLoc) {
|
||||||
@@ -203,6 +192,7 @@ export function prepareProgram(statements, loc) {
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
export function preparePartialBlock(open, program, close, locInfo) {
|
export function preparePartialBlock(open, program, close, locInfo) {
|
||||||
validateClose(open, close);
|
validateClose(open, close);
|
||||||
|
|
||||||
@@ -217,3 +207,4 @@ export function preparePartialBlock(open, program, close, locInfo) {
|
|||||||
loc: this.locInfo(locInfo)
|
loc: this.locInfo(locInfo)
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -1,7 +1,8 @@
|
|||||||
import { COMPILER_REVISION, REVISION_CHANGES } from '../base';
|
import { COMPILER_REVISION, REVISION_CHANGES } from '../base';
|
||||||
import Exception from '../exception';
|
import Exception from '../exception';
|
||||||
import { isArray } from '../utils';
|
import {isArray} from '../utils';
|
||||||
import CodeGen from './code-gen';
|
import CodeGen from './code-gen';
|
||||||
|
import {dangerousPropertyRegex} from '../helpers/lookup';
|
||||||
|
|
||||||
function Literal(value) {
|
function Literal(value) {
|
||||||
this.value = value;
|
this.value = value;
|
||||||
@@ -12,8 +13,20 @@ function JavaScriptCompiler() {}
|
|||||||
JavaScriptCompiler.prototype = {
|
JavaScriptCompiler.prototype = {
|
||||||
// PUBLIC API: You can override these methods in a subclass to provide
|
// PUBLIC API: You can override these methods in a subclass to provide
|
||||||
// alternative compiled forms for name lookup and buffering semantics
|
// alternative compiled forms for name lookup and buffering semantics
|
||||||
nameLookup: function(parent, name /*, type */) {
|
nameLookup: function(parent, name/* , type*/) {
|
||||||
return this.internalNameLookup(parent, name);
|
if (dangerousPropertyRegex.test(name)) {
|
||||||
|
const isEnumerable = [ this.aliasable('container.propertyIsEnumerable'), '.call(', parent, ',', JSON.stringify(name), ')'];
|
||||||
|
return ['(', isEnumerable, '?', _actualLookup(), ' : undefined)'];
|
||||||
|
}
|
||||||
|
return _actualLookup();
|
||||||
|
|
||||||
|
function _actualLookup() {
|
||||||
|
if (JavaScriptCompiler.isValidJavaScriptVariableName(name)) {
|
||||||
|
return [parent, '.', name];
|
||||||
|
} else {
|
||||||
|
return [parent, '[', JSON.stringify(name), ']'];
|
||||||
|
}
|
||||||
|
}
|
||||||
},
|
},
|
||||||
depthedLookup: function(name) {
|
depthedLookup: function(name) {
|
||||||
return [this.aliasable('container.lookup'), '(depths, "', name, '")'];
|
return [this.aliasable('container.lookup'), '(depths, "', name, '")'];
|
||||||
@@ -21,7 +34,7 @@ JavaScriptCompiler.prototype = {
|
|||||||
|
|
||||||
compilerInfo: function() {
|
compilerInfo: function() {
|
||||||
const revision = COMPILER_REVISION,
|
const revision = COMPILER_REVISION,
|
||||||
versions = REVISION_CHANGES[revision];
|
versions = REVISION_CHANGES[revision];
|
||||||
return [revision, versions];
|
return [revision, versions];
|
||||||
},
|
},
|
||||||
|
|
||||||
@@ -49,12 +62,6 @@ JavaScriptCompiler.prototype = {
|
|||||||
return this.quotedString('');
|
return this.quotedString('');
|
||||||
},
|
},
|
||||||
// END PUBLIC API
|
// END PUBLIC API
|
||||||
internalNameLookup: function(parent, name) {
|
|
||||||
this.lookupPropertyFunctionIsUsed = true;
|
|
||||||
return ['lookupProperty(', parent, ',', JSON.stringify(name), ')'];
|
|
||||||
},
|
|
||||||
|
|
||||||
lookupPropertyFunctionIsUsed: false,
|
|
||||||
|
|
||||||
compile: function(environment, options, context, asObject) {
|
compile: function(environment, options, context, asObject) {
|
||||||
this.environment = environment;
|
this.environment = environment;
|
||||||
@@ -84,18 +91,14 @@ JavaScriptCompiler.prototype = {
|
|||||||
|
|
||||||
this.compileChildren(environment, options);
|
this.compileChildren(environment, options);
|
||||||
|
|
||||||
this.useDepths =
|
this.useDepths = this.useDepths || environment.useDepths || environment.useDecorators || this.options.compat;
|
||||||
this.useDepths ||
|
|
||||||
environment.useDepths ||
|
|
||||||
environment.useDecorators ||
|
|
||||||
this.options.compat;
|
|
||||||
this.useBlockParams = this.useBlockParams || environment.useBlockParams;
|
this.useBlockParams = this.useBlockParams || environment.useBlockParams;
|
||||||
|
|
||||||
let opcodes = environment.opcodes,
|
let opcodes = environment.opcodes,
|
||||||
opcode,
|
opcode,
|
||||||
firstLoc,
|
firstLoc,
|
||||||
i,
|
i,
|
||||||
l;
|
l;
|
||||||
|
|
||||||
for (i = 0, l = opcodes.length; i < l; i++) {
|
for (i = 0, l = opcodes.length; i < l; i++) {
|
||||||
opcode = opcodes[i];
|
opcode = opcodes[i];
|
||||||
@@ -117,28 +120,13 @@ JavaScriptCompiler.prototype = {
|
|||||||
if (!this.decorators.isEmpty()) {
|
if (!this.decorators.isEmpty()) {
|
||||||
this.useDecorators = true;
|
this.useDecorators = true;
|
||||||
|
|
||||||
this.decorators.prepend([
|
this.decorators.prepend('var decorators = container.decorators;\n');
|
||||||
'var decorators = container.decorators, ',
|
|
||||||
this.lookupPropertyFunctionVarDeclaration(),
|
|
||||||
';\n'
|
|
||||||
]);
|
|
||||||
this.decorators.push('return fn;');
|
this.decorators.push('return fn;');
|
||||||
|
|
||||||
if (asObject) {
|
if (asObject) {
|
||||||
this.decorators = Function.apply(this, [
|
this.decorators = Function.apply(this, ['fn', 'props', 'container', 'depth0', 'data', 'blockParams', 'depths', this.decorators.merge()]);
|
||||||
'fn',
|
|
||||||
'props',
|
|
||||||
'container',
|
|
||||||
'depth0',
|
|
||||||
'data',
|
|
||||||
'blockParams',
|
|
||||||
'depths',
|
|
||||||
this.decorators.merge()
|
|
||||||
]);
|
|
||||||
} else {
|
} else {
|
||||||
this.decorators.prepend(
|
this.decorators.prepend('function(fn, props, container, depth0, data, blockParams, depths) {\n');
|
||||||
'function(fn, props, container, depth0, data, blockParams, depths) {\n'
|
|
||||||
);
|
|
||||||
this.decorators.push('}\n');
|
this.decorators.push('}\n');
|
||||||
this.decorators = this.decorators.merge();
|
this.decorators = this.decorators.merge();
|
||||||
}
|
}
|
||||||
@@ -158,7 +146,7 @@ JavaScriptCompiler.prototype = {
|
|||||||
ret.useDecorators = true;
|
ret.useDecorators = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
let { programs, decorators } = this.context;
|
let {programs, decorators} = this.context;
|
||||||
for (i = 0, l = programs.length; i < l; i++) {
|
for (i = 0, l = programs.length; i < l; i++) {
|
||||||
if (programs[i]) {
|
if (programs[i]) {
|
||||||
ret[i] = programs[i];
|
ret[i] = programs[i];
|
||||||
@@ -188,11 +176,11 @@ JavaScriptCompiler.prototype = {
|
|||||||
if (!asObject) {
|
if (!asObject) {
|
||||||
ret.compiler = JSON.stringify(ret.compiler);
|
ret.compiler = JSON.stringify(ret.compiler);
|
||||||
|
|
||||||
this.source.currentLocation = { start: { line: 1, column: 0 } };
|
this.source.currentLocation = {start: {line: 1, column: 0}};
|
||||||
ret = this.objectLiteral(ret);
|
ret = this.objectLiteral(ret);
|
||||||
|
|
||||||
if (options.srcName) {
|
if (options.srcName) {
|
||||||
ret = ret.toStringWithSourceMap({ file: options.destName });
|
ret = ret.toStringWithSourceMap({file: options.destName});
|
||||||
ret.map = ret.map && ret.map.toString();
|
ret.map = ret.map && ret.map.toString();
|
||||||
} else {
|
} else {
|
||||||
ret = ret.toString();
|
ret = ret.toString();
|
||||||
@@ -233,15 +221,11 @@ JavaScriptCompiler.prototype = {
|
|||||||
Object.keys(this.aliases).forEach(alias => {
|
Object.keys(this.aliases).forEach(alias => {
|
||||||
let node = this.aliases[alias];
|
let node = this.aliases[alias];
|
||||||
if (node.children && node.referenceCount > 1) {
|
if (node.children && node.referenceCount > 1) {
|
||||||
varDeclarations += ', alias' + ++aliasCount + '=' + alias;
|
varDeclarations += ', alias' + (++aliasCount) + '=' + alias;
|
||||||
node.children[0] = 'alias' + aliasCount;
|
node.children[0] = 'alias' + aliasCount;
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
if (this.lookupPropertyFunctionIsUsed) {
|
|
||||||
varDeclarations += ', ' + this.lookupPropertyFunctionVarDeclaration();
|
|
||||||
}
|
|
||||||
|
|
||||||
let params = ['container', 'depth0', 'helpers', 'partials', 'data'];
|
let params = ['container', 'depth0', 'helpers', 'partials', 'data'];
|
||||||
|
|
||||||
if (this.useBlockParams || this.useDepths) {
|
if (this.useBlockParams || this.useDepths) {
|
||||||
@@ -259,23 +243,18 @@ JavaScriptCompiler.prototype = {
|
|||||||
|
|
||||||
return Function.apply(this, params);
|
return Function.apply(this, params);
|
||||||
} else {
|
} else {
|
||||||
return this.source.wrap([
|
return this.source.wrap(['function(', params.join(','), ') {\n ', source, '}']);
|
||||||
'function(',
|
|
||||||
params.join(','),
|
|
||||||
') {\n ',
|
|
||||||
source,
|
|
||||||
'}'
|
|
||||||
]);
|
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
mergeSource: function(varDeclarations) {
|
mergeSource: function(varDeclarations) {
|
||||||
let isSimple = this.environment.isSimple,
|
let isSimple = this.environment.isSimple,
|
||||||
appendOnly = !this.forceBuffer,
|
appendOnly = !this.forceBuffer,
|
||||||
appendFirst,
|
appendFirst,
|
||||||
sourceSeen,
|
|
||||||
bufferStart,
|
sourceSeen,
|
||||||
bufferEnd;
|
bufferStart,
|
||||||
this.source.each(line => {
|
bufferEnd;
|
||||||
|
this.source.each((line) => {
|
||||||
if (line.appendToBuffer) {
|
if (line.appendToBuffer) {
|
||||||
if (bufferStart) {
|
if (bufferStart) {
|
||||||
line.prepend(' + ');
|
line.prepend(' + ');
|
||||||
@@ -301,6 +280,7 @@ JavaScriptCompiler.prototype = {
|
|||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
||||||
if (appendOnly) {
|
if (appendOnly) {
|
||||||
if (bufferStart) {
|
if (bufferStart) {
|
||||||
bufferStart.prepend('return ');
|
bufferStart.prepend('return ');
|
||||||
@@ -309,8 +289,7 @@ JavaScriptCompiler.prototype = {
|
|||||||
this.source.push('return "";');
|
this.source.push('return "";');
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
varDeclarations +=
|
varDeclarations += ', buffer = ' + (appendFirst ? '' : this.initializeBuffer());
|
||||||
', buffer = ' + (appendFirst ? '' : this.initializeBuffer());
|
|
||||||
|
|
||||||
if (bufferStart) {
|
if (bufferStart) {
|
||||||
bufferStart.prepend('return buffer + ');
|
bufferStart.prepend('return buffer + ');
|
||||||
@@ -321,25 +300,12 @@ JavaScriptCompiler.prototype = {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (varDeclarations) {
|
if (varDeclarations) {
|
||||||
this.source.prepend(
|
this.source.prepend('var ' + varDeclarations.substring(2) + (appendFirst ? '' : ';\n'));
|
||||||
'var ' + varDeclarations.substring(2) + (appendFirst ? '' : ';\n')
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return this.source.merge();
|
return this.source.merge();
|
||||||
},
|
},
|
||||||
|
|
||||||
lookupPropertyFunctionVarDeclaration: function() {
|
|
||||||
return `
|
|
||||||
lookupProperty = container.lookupProperty || function(parent, propertyName) {
|
|
||||||
if (Object.prototype.hasOwnProperty.call(parent, propertyName)) {
|
|
||||||
return parent[propertyName];
|
|
||||||
}
|
|
||||||
return undefined
|
|
||||||
}
|
|
||||||
`.trim();
|
|
||||||
},
|
|
||||||
|
|
||||||
// [blockValue]
|
// [blockValue]
|
||||||
//
|
//
|
||||||
// On stack, before: hash, inverse, program, value
|
// On stack, before: hash, inverse, program, value
|
||||||
@@ -350,10 +316,8 @@ JavaScriptCompiler.prototype = {
|
|||||||
// replace it on the stack with the result of properly
|
// replace it on the stack with the result of properly
|
||||||
// invoking blockHelperMissing.
|
// invoking blockHelperMissing.
|
||||||
blockValue: function(name) {
|
blockValue: function(name) {
|
||||||
let blockHelperMissing = this.aliasable(
|
let blockHelperMissing = this.aliasable('container.hooks.blockHelperMissing'),
|
||||||
'container.hooks.blockHelperMissing'
|
params = [this.contextName(0)];
|
||||||
),
|
|
||||||
params = [this.contextName(0)];
|
|
||||||
this.setupHelperArgs(name, 0, params);
|
this.setupHelperArgs(name, 0, params);
|
||||||
|
|
||||||
let blockName = this.popStack();
|
let blockName = this.popStack();
|
||||||
@@ -370,10 +334,8 @@ JavaScriptCompiler.prototype = {
|
|||||||
// On stack, after, if lastHelper: value
|
// On stack, after, if lastHelper: value
|
||||||
ambiguousBlockValue: function() {
|
ambiguousBlockValue: function() {
|
||||||
// We're being a bit cheeky and reusing the options value from the prior exec
|
// We're being a bit cheeky and reusing the options value from the prior exec
|
||||||
let blockHelperMissing = this.aliasable(
|
let blockHelperMissing = this.aliasable('container.hooks.blockHelperMissing'),
|
||||||
'container.hooks.blockHelperMissing'
|
params = [this.contextName(0)];
|
||||||
),
|
|
||||||
params = [this.contextName(0)];
|
|
||||||
this.setupHelperArgs('', 0, params, true);
|
this.setupHelperArgs('', 0, params, true);
|
||||||
|
|
||||||
this.flushInline();
|
this.flushInline();
|
||||||
@@ -382,14 +344,9 @@ JavaScriptCompiler.prototype = {
|
|||||||
params.splice(1, 0, current);
|
params.splice(1, 0, current);
|
||||||
|
|
||||||
this.pushSource([
|
this.pushSource([
|
||||||
'if (!',
|
'if (!', this.lastHelper, ') { ',
|
||||||
this.lastHelper,
|
current, ' = ', this.source.functionCall(blockHelperMissing, 'call', params),
|
||||||
') { ',
|
'}']);
|
||||||
current,
|
|
||||||
' = ',
|
|
||||||
this.source.functionCall(blockHelperMissing, 'call', params),
|
|
||||||
'}'
|
|
||||||
]);
|
|
||||||
},
|
},
|
||||||
|
|
||||||
// [appendContent]
|
// [appendContent]
|
||||||
@@ -419,24 +376,14 @@ JavaScriptCompiler.prototype = {
|
|||||||
// Otherwise, the empty string is appended
|
// Otherwise, the empty string is appended
|
||||||
append: function() {
|
append: function() {
|
||||||
if (this.isInline()) {
|
if (this.isInline()) {
|
||||||
this.replaceStack(current => [' != null ? ', current, ' : ""']);
|
this.replaceStack((current) => [' != null ? ', current, ' : ""']);
|
||||||
|
|
||||||
this.pushSource(this.appendToBuffer(this.popStack()));
|
this.pushSource(this.appendToBuffer(this.popStack()));
|
||||||
} else {
|
} else {
|
||||||
let local = this.popStack();
|
let local = this.popStack();
|
||||||
this.pushSource([
|
this.pushSource(['if (', local, ' != null) { ', this.appendToBuffer(local, undefined, true), ' }']);
|
||||||
'if (',
|
|
||||||
local,
|
|
||||||
' != null) { ',
|
|
||||||
this.appendToBuffer(local, undefined, true),
|
|
||||||
' }'
|
|
||||||
]);
|
|
||||||
if (this.environment.isSimple) {
|
if (this.environment.isSimple) {
|
||||||
this.pushSource([
|
this.pushSource(['else { ', this.appendToBuffer("''", undefined, true), ' }']);
|
||||||
'else { ',
|
|
||||||
this.appendToBuffer("''", undefined, true),
|
|
||||||
' }'
|
|
||||||
]);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
@@ -448,14 +395,8 @@ JavaScriptCompiler.prototype = {
|
|||||||
//
|
//
|
||||||
// Escape `value` and append it to the buffer
|
// Escape `value` and append it to the buffer
|
||||||
appendEscaped: function() {
|
appendEscaped: function() {
|
||||||
this.pushSource(
|
this.pushSource(this.appendToBuffer(
|
||||||
this.appendToBuffer([
|
[this.aliasable('container.escapeExpression'), '(', this.popStack(), ')']));
|
||||||
this.aliasable('container.escapeExpression'),
|
|
||||||
'(',
|
|
||||||
this.popStack(),
|
|
||||||
')'
|
|
||||||
])
|
|
||||||
);
|
|
||||||
},
|
},
|
||||||
|
|
||||||
// [getContext]
|
// [getContext]
|
||||||
@@ -539,7 +480,7 @@ JavaScriptCompiler.prototype = {
|
|||||||
let len = parts.length;
|
let len = parts.length;
|
||||||
for (; i < len; i++) {
|
for (; i < len; i++) {
|
||||||
/* eslint-disable no-loop-func */
|
/* eslint-disable no-loop-func */
|
||||||
this.replaceStack(current => {
|
this.replaceStack((current) => {
|
||||||
let lookup = this.nameLookup(current, parts[i], type);
|
let lookup = this.nameLookup(current, parts[i], type);
|
||||||
// We want to ensure that zero and false are handled properly if the context (falsy flag)
|
// We want to ensure that zero and false are handled properly if the context (falsy flag)
|
||||||
// needs to have the special handling for these values.
|
// needs to have the special handling for these values.
|
||||||
@@ -562,14 +503,7 @@ JavaScriptCompiler.prototype = {
|
|||||||
// If the `value` is a lambda, replace it on the stack by
|
// If the `value` is a lambda, replace it on the stack by
|
||||||
// the return value of the lambda
|
// the return value of the lambda
|
||||||
resolvePossibleLambda: function() {
|
resolvePossibleLambda: function() {
|
||||||
this.push([
|
this.push([this.aliasable('container.lambda'), '(', this.popStack(), ', ', this.contextName(0), ')']);
|
||||||
this.aliasable('container.lambda'),
|
|
||||||
'(',
|
|
||||||
this.popStack(),
|
|
||||||
', ',
|
|
||||||
this.contextName(0),
|
|
||||||
')'
|
|
||||||
]);
|
|
||||||
},
|
},
|
||||||
|
|
||||||
// [pushStringParam]
|
// [pushStringParam]
|
||||||
@@ -609,7 +543,7 @@ JavaScriptCompiler.prototype = {
|
|||||||
if (this.hash) {
|
if (this.hash) {
|
||||||
this.hashes.push(this.hash);
|
this.hashes.push(this.hash);
|
||||||
}
|
}
|
||||||
this.hash = { values: {}, types: [], contexts: [], ids: [] };
|
this.hash = {values: {}, types: [], contexts: [], ids: []};
|
||||||
},
|
},
|
||||||
popHash: function() {
|
popHash: function() {
|
||||||
let hash = this.hash;
|
let hash = this.hash;
|
||||||
@@ -673,16 +607,11 @@ JavaScriptCompiler.prototype = {
|
|||||||
// and inserts the decorator into the decorators list.
|
// and inserts the decorator into the decorators list.
|
||||||
registerDecorator(paramSize, name) {
|
registerDecorator(paramSize, name) {
|
||||||
let foundDecorator = this.nameLookup('decorators', name, 'decorator'),
|
let foundDecorator = this.nameLookup('decorators', name, 'decorator'),
|
||||||
options = this.setupHelperArgs(name, paramSize);
|
options = this.setupHelperArgs(name, paramSize);
|
||||||
|
|
||||||
this.decorators.push([
|
this.decorators.push([
|
||||||
'fn = ',
|
'fn = ',
|
||||||
this.decorators.functionCall(foundDecorator, '', [
|
this.decorators.functionCall(foundDecorator, '', ['fn', 'props', 'container', options]),
|
||||||
'fn',
|
|
||||||
'props',
|
|
||||||
'container',
|
|
||||||
options
|
|
||||||
]),
|
|
||||||
' || fn;'
|
' || fn;'
|
||||||
]);
|
]);
|
||||||
},
|
},
|
||||||
@@ -698,32 +627,21 @@ JavaScriptCompiler.prototype = {
|
|||||||
// If the helper is not found, `helperMissing` is called.
|
// If the helper is not found, `helperMissing` is called.
|
||||||
invokeHelper: function(paramSize, name, isSimple) {
|
invokeHelper: function(paramSize, name, isSimple) {
|
||||||
let nonHelper = this.popStack(),
|
let nonHelper = this.popStack(),
|
||||||
helper = this.setupHelper(paramSize, name);
|
helper = this.setupHelper(paramSize, name);
|
||||||
|
|
||||||
let possibleFunctionCalls = [];
|
let possibleFunctionCalls = [];
|
||||||
|
|
||||||
if (isSimple) {
|
if (isSimple) { // direct call to helper
|
||||||
// direct call to helper
|
|
||||||
possibleFunctionCalls.push(helper.name);
|
possibleFunctionCalls.push(helper.name);
|
||||||
}
|
}
|
||||||
// call a function from the input object
|
// call a function from the input object
|
||||||
possibleFunctionCalls.push(nonHelper);
|
possibleFunctionCalls.push(nonHelper);
|
||||||
if (!this.options.strict) {
|
if (!this.options.strict) {
|
||||||
possibleFunctionCalls.push(
|
possibleFunctionCalls.push(this.aliasable('container.hooks.helperMissing'));
|
||||||
this.aliasable('container.hooks.helperMissing')
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
let functionLookupCode = [
|
let functionLookupCode = ['(', this.itemsSeparatedBy(possibleFunctionCalls, '||'), ')'];
|
||||||
'(',
|
let functionCall = this.source.functionCall(functionLookupCode, 'call', helper.callParams);
|
||||||
this.itemsSeparatedBy(possibleFunctionCalls, '||'),
|
|
||||||
')'
|
|
||||||
];
|
|
||||||
let functionCall = this.source.functionCall(
|
|
||||||
functionLookupCode,
|
|
||||||
'call',
|
|
||||||
helper.callParams
|
|
||||||
);
|
|
||||||
this.push(functionCall);
|
this.push(functionCall);
|
||||||
},
|
},
|
||||||
|
|
||||||
@@ -767,31 +685,22 @@ JavaScriptCompiler.prototype = {
|
|||||||
this.emptyHash();
|
this.emptyHash();
|
||||||
let helper = this.setupHelper(0, name, helperCall);
|
let helper = this.setupHelper(0, name, helperCall);
|
||||||
|
|
||||||
let helperName = (this.lastHelper = this.nameLookup(
|
let helperName = this.lastHelper = this.nameLookup('helpers', name, 'helper');
|
||||||
'helpers',
|
|
||||||
name,
|
|
||||||
'helper'
|
|
||||||
));
|
|
||||||
|
|
||||||
let lookup = ['(', '(helper = ', helperName, ' || ', nonHelper, ')'];
|
let lookup = ['(', '(helper = ', helperName, ' || ', nonHelper, ')'];
|
||||||
if (!this.options.strict) {
|
if (!this.options.strict) {
|
||||||
lookup[0] = '(helper = ';
|
lookup[0] = '(helper = ';
|
||||||
lookup.push(
|
lookup.push(
|
||||||
' != null ? helper : ',
|
' != null ? helper : ',
|
||||||
this.aliasable('container.hooks.helperMissing')
|
this.aliasable('container.hooks.helperMissing')
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
this.push([
|
this.push([
|
||||||
'(',
|
'(', lookup,
|
||||||
lookup,
|
(helper.paramsInit ? ['),(', helper.paramsInit] : []), '),',
|
||||||
helper.paramsInit ? ['),(', helper.paramsInit] : [],
|
'(typeof helper === ', this.aliasable('"function"'), ' ? ',
|
||||||
'),',
|
this.source.functionCall('helper', 'call', helper.callParams), ' : helper))'
|
||||||
'(typeof helper === ',
|
|
||||||
this.aliasable('"function"'),
|
|
||||||
' ? ',
|
|
||||||
this.source.functionCall('helper', 'call', helper.callParams),
|
|
||||||
' : helper))'
|
|
||||||
]);
|
]);
|
||||||
},
|
},
|
||||||
|
|
||||||
@@ -804,7 +713,7 @@ JavaScriptCompiler.prototype = {
|
|||||||
// and pushes the result of the invocation back.
|
// and pushes the result of the invocation back.
|
||||||
invokePartial: function(isDynamic, name, indent) {
|
invokePartial: function(isDynamic, name, indent) {
|
||||||
let params = [],
|
let params = [],
|
||||||
options = this.setupParams(name, 1, params);
|
options = this.setupParams(name, 1, params);
|
||||||
|
|
||||||
if (isDynamic) {
|
if (isDynamic) {
|
||||||
name = this.popStack();
|
name = this.popStack();
|
||||||
@@ -841,9 +750,9 @@ JavaScriptCompiler.prototype = {
|
|||||||
// Pops a value off the stack and assigns it to the current hash
|
// Pops a value off the stack and assigns it to the current hash
|
||||||
assignToHash: function(key) {
|
assignToHash: function(key) {
|
||||||
let value = this.popStack(),
|
let value = this.popStack(),
|
||||||
context,
|
context,
|
||||||
type,
|
type,
|
||||||
id;
|
id;
|
||||||
|
|
||||||
if (this.trackIds) {
|
if (this.trackIds) {
|
||||||
id = this.popStack();
|
id = this.popStack();
|
||||||
@@ -869,13 +778,8 @@ JavaScriptCompiler.prototype = {
|
|||||||
pushId: function(type, name, child) {
|
pushId: function(type, name, child) {
|
||||||
if (type === 'BlockParam') {
|
if (type === 'BlockParam') {
|
||||||
this.pushStackLiteral(
|
this.pushStackLiteral(
|
||||||
'blockParams[' +
|
'blockParams[' + name[0] + '].path[' + name[1] + ']'
|
||||||
name[0] +
|
+ (child ? ' + ' + JSON.stringify('.' + child) : ''));
|
||||||
'].path[' +
|
|
||||||
name[1] +
|
|
||||||
']' +
|
|
||||||
(child ? ' + ' + JSON.stringify('.' + child) : '')
|
|
||||||
);
|
|
||||||
} else if (type === 'PathExpression') {
|
} else if (type === 'PathExpression') {
|
||||||
this.pushString(name);
|
this.pushString(name);
|
||||||
} else if (type === 'SubExpression') {
|
} else if (type === 'SubExpression') {
|
||||||
@@ -890,9 +794,7 @@ JavaScriptCompiler.prototype = {
|
|||||||
compiler: JavaScriptCompiler,
|
compiler: JavaScriptCompiler,
|
||||||
|
|
||||||
compileChildren: function(environment, options) {
|
compileChildren: function(environment, options) {
|
||||||
let children = environment.children,
|
let children = environment.children, child, compiler;
|
||||||
child,
|
|
||||||
compiler;
|
|
||||||
|
|
||||||
for (let i = 0, l = children.length; i < l; i++) {
|
for (let i = 0, l = children.length; i < l; i++) {
|
||||||
child = children[i];
|
child = children[i];
|
||||||
@@ -905,12 +807,7 @@ JavaScriptCompiler.prototype = {
|
|||||||
let index = this.context.programs.length;
|
let index = this.context.programs.length;
|
||||||
child.index = index;
|
child.index = index;
|
||||||
child.name = 'program' + index;
|
child.name = 'program' + index;
|
||||||
this.context.programs[index] = compiler.compile(
|
this.context.programs[index] = compiler.compile(child, options, this.context, !this.precompile);
|
||||||
child,
|
|
||||||
options,
|
|
||||||
this.context,
|
|
||||||
!this.precompile
|
|
||||||
);
|
|
||||||
this.context.decorators[index] = compiler.decorators;
|
this.context.decorators[index] = compiler.decorators;
|
||||||
this.context.environments[index] = child;
|
this.context.environments[index] = child;
|
||||||
|
|
||||||
@@ -938,7 +835,7 @@ JavaScriptCompiler.prototype = {
|
|||||||
|
|
||||||
programExpression: function(guid) {
|
programExpression: function(guid) {
|
||||||
let child = this.environment.children[guid],
|
let child = this.environment.children[guid],
|
||||||
programParams = [child.index, 'data', child.blockParams];
|
programParams = [child.index, 'data', child.blockParams];
|
||||||
|
|
||||||
if (this.useBlockParams || this.useDepths) {
|
if (this.useBlockParams || this.useDepths) {
|
||||||
programParams.push('blockParams');
|
programParams.push('blockParams');
|
||||||
@@ -973,11 +870,7 @@ JavaScriptCompiler.prototype = {
|
|||||||
pushSource: function(source) {
|
pushSource: function(source) {
|
||||||
if (this.pendingContent) {
|
if (this.pendingContent) {
|
||||||
this.source.push(
|
this.source.push(
|
||||||
this.appendToBuffer(
|
this.appendToBuffer(this.source.quotedString(this.pendingContent), this.pendingLocation));
|
||||||
this.source.quotedString(this.pendingContent),
|
|
||||||
this.pendingLocation
|
|
||||||
)
|
|
||||||
);
|
|
||||||
this.pendingContent = undefined;
|
this.pendingContent = undefined;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -988,9 +881,9 @@ JavaScriptCompiler.prototype = {
|
|||||||
|
|
||||||
replaceStack: function(callback) {
|
replaceStack: function(callback) {
|
||||||
let prefix = ['('],
|
let prefix = ['('],
|
||||||
stack,
|
stack,
|
||||||
createdStack,
|
createdStack,
|
||||||
usedLiteral;
|
usedLiteral;
|
||||||
|
|
||||||
/* istanbul ignore next */
|
/* istanbul ignore next */
|
||||||
if (!this.isInline()) {
|
if (!this.isInline()) {
|
||||||
@@ -1027,9 +920,7 @@ JavaScriptCompiler.prototype = {
|
|||||||
|
|
||||||
incrStack: function() {
|
incrStack: function() {
|
||||||
this.stackSlot++;
|
this.stackSlot++;
|
||||||
if (this.stackSlot > this.stackVars.length) {
|
if (this.stackSlot > this.stackVars.length) { this.stackVars.push('stack' + this.stackSlot); }
|
||||||
this.stackVars.push('stack' + this.stackSlot);
|
|
||||||
}
|
|
||||||
return this.topStackName();
|
return this.topStackName();
|
||||||
},
|
},
|
||||||
topStackName: function() {
|
topStackName: function() {
|
||||||
@@ -1056,9 +947,9 @@ JavaScriptCompiler.prototype = {
|
|||||||
|
|
||||||
popStack: function(wrapped) {
|
popStack: function(wrapped) {
|
||||||
let inline = this.isInline(),
|
let inline = this.isInline(),
|
||||||
item = (inline ? this.inlineStack : this.compileStack).pop();
|
item = (inline ? this.inlineStack : this.compileStack).pop();
|
||||||
|
|
||||||
if (!wrapped && item instanceof Literal) {
|
if (!wrapped && (item instanceof Literal)) {
|
||||||
return item.value;
|
return item.value;
|
||||||
} else {
|
} else {
|
||||||
if (!inline) {
|
if (!inline) {
|
||||||
@@ -1073,8 +964,8 @@ JavaScriptCompiler.prototype = {
|
|||||||
},
|
},
|
||||||
|
|
||||||
topStack: function() {
|
topStack: function() {
|
||||||
let stack = this.isInline() ? this.inlineStack : this.compileStack,
|
let stack = (this.isInline() ? this.inlineStack : this.compileStack),
|
||||||
item = stack[stack.length - 1];
|
item = stack[stack.length - 1];
|
||||||
|
|
||||||
/* istanbul ignore if */
|
/* istanbul ignore if */
|
||||||
if (item instanceof Literal) {
|
if (item instanceof Literal) {
|
||||||
@@ -1116,13 +1007,9 @@ JavaScriptCompiler.prototype = {
|
|||||||
|
|
||||||
setupHelper: function(paramSize, name, blockHelper) {
|
setupHelper: function(paramSize, name, blockHelper) {
|
||||||
let params = [],
|
let params = [],
|
||||||
paramsInit = this.setupHelperArgs(name, paramSize, params, blockHelper);
|
paramsInit = this.setupHelperArgs(name, paramSize, params, blockHelper);
|
||||||
let foundHelper = this.nameLookup('helpers', name, 'helper'),
|
let foundHelper = this.nameLookup('helpers', name, 'helper'),
|
||||||
callContext = this.aliasable(
|
callContext = this.aliasable(`${this.contextName(0)} != null ? ${this.contextName(0)} : (container.nullContext || {})`);
|
||||||
`${this.contextName(0)} != null ? ${this.contextName(
|
|
||||||
0
|
|
||||||
)} : (container.nullContext || {})`
|
|
||||||
);
|
|
||||||
|
|
||||||
return {
|
return {
|
||||||
params: params,
|
params: params,
|
||||||
@@ -1134,11 +1021,11 @@ JavaScriptCompiler.prototype = {
|
|||||||
|
|
||||||
setupParams: function(helper, paramSize, params) {
|
setupParams: function(helper, paramSize, params) {
|
||||||
let options = {},
|
let options = {},
|
||||||
contexts = [],
|
contexts = [],
|
||||||
types = [],
|
types = [],
|
||||||
ids = [],
|
ids = [],
|
||||||
objectArgs = !params,
|
objectArgs = !params,
|
||||||
param;
|
param;
|
||||||
|
|
||||||
if (objectArgs) {
|
if (objectArgs) {
|
||||||
params = [];
|
params = [];
|
||||||
@@ -1156,7 +1043,7 @@ JavaScriptCompiler.prototype = {
|
|||||||
}
|
}
|
||||||
|
|
||||||
let inverse = this.popStack(),
|
let inverse = this.popStack(),
|
||||||
program = this.popStack();
|
program = this.popStack();
|
||||||
|
|
||||||
// Avoid setting fn and inverse if neither are set. This allows
|
// Avoid setting fn and inverse if neither are set. This allows
|
||||||
// helpers to do a check for `if (options.fn)`
|
// helpers to do a check for `if (options.fn)`
|
||||||
@@ -1219,6 +1106,7 @@ JavaScriptCompiler.prototype = {
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
(function() {
|
(function() {
|
||||||
const reservedWords = (
|
const reservedWords = (
|
||||||
'break else new var' +
|
'break else new var' +
|
||||||
@@ -1239,27 +1127,21 @@ JavaScriptCompiler.prototype = {
|
|||||||
' null true false'
|
' null true false'
|
||||||
).split(' ');
|
).split(' ');
|
||||||
|
|
||||||
const compilerWords = (JavaScriptCompiler.RESERVED_WORDS = {});
|
const compilerWords = JavaScriptCompiler.RESERVED_WORDS = {};
|
||||||
|
|
||||||
for (let i = 0, l = reservedWords.length; i < l; i++) {
|
for (let i = 0, l = reservedWords.length; i < l; i++) {
|
||||||
compilerWords[reservedWords[i]] = true;
|
compilerWords[reservedWords[i]] = true;
|
||||||
}
|
}
|
||||||
})();
|
}());
|
||||||
|
|
||||||
/**
|
|
||||||
* @deprecated May be removed in the next major version
|
|
||||||
*/
|
|
||||||
JavaScriptCompiler.isValidJavaScriptVariableName = function(name) {
|
JavaScriptCompiler.isValidJavaScriptVariableName = function(name) {
|
||||||
return (
|
return !JavaScriptCompiler.RESERVED_WORDS[name] && (/^[a-zA-Z_$][0-9a-zA-Z_$]*$/).test(name);
|
||||||
!JavaScriptCompiler.RESERVED_WORDS[name] &&
|
|
||||||
/^[a-zA-Z_$][0-9a-zA-Z_$]*$/.test(name)
|
|
||||||
);
|
|
||||||
};
|
};
|
||||||
|
|
||||||
function strictLookup(requireTerminal, compiler, parts, type) {
|
function strictLookup(requireTerminal, compiler, parts, type) {
|
||||||
let stack = compiler.popStack(),
|
let stack = compiler.popStack(),
|
||||||
i = 0,
|
i = 0,
|
||||||
len = parts.length;
|
len = parts.length;
|
||||||
if (requireTerminal) {
|
if (requireTerminal) {
|
||||||
len--;
|
len--;
|
||||||
}
|
}
|
||||||
@@ -1269,16 +1151,7 @@ function strictLookup(requireTerminal, compiler, parts, type) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (requireTerminal) {
|
if (requireTerminal) {
|
||||||
return [
|
return [compiler.aliasable('container.strict'), '(', stack, ', ', compiler.quotedString(parts[i]), ', ', JSON.stringify(compiler.source.currentLocation), ' )'];
|
||||||
compiler.aliasable('container.strict'),
|
|
||||||
'(',
|
|
||||||
stack,
|
|
||||||
', ',
|
|
||||||
compiler.quotedString(parts[i]),
|
|
||||||
', ',
|
|
||||||
JSON.stringify(compiler.source.currentLocation),
|
|
||||||
' )'
|
|
||||||
];
|
|
||||||
} else {
|
} else {
|
||||||
return stack;
|
return stack;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -24,14 +24,13 @@ PrintVisitor.prototype.pad = function(string) {
|
|||||||
|
|
||||||
PrintVisitor.prototype.Program = function(program) {
|
PrintVisitor.prototype.Program = function(program) {
|
||||||
let out = '',
|
let out = '',
|
||||||
body = program.body,
|
body = program.body,
|
||||||
i,
|
i, l;
|
||||||
l;
|
|
||||||
|
|
||||||
if (program.blockParams) {
|
if (program.blockParams) {
|
||||||
let blockParams = 'BLOCK PARAMS: [';
|
let blockParams = 'BLOCK PARAMS: [';
|
||||||
for (i = 0, l = program.blockParams.length; i < l; i++) {
|
for (i = 0, l = program.blockParams.length; i < l; i++) {
|
||||||
blockParams += ' ' + program.blockParams[i];
|
blockParams += ' ' + program.blockParams[i];
|
||||||
}
|
}
|
||||||
blockParams += ' ]';
|
blockParams += ' ]';
|
||||||
out += this.pad(blockParams);
|
out += this.pad(blockParams);
|
||||||
@@ -53,14 +52,11 @@ PrintVisitor.prototype.Decorator = function(mustache) {
|
|||||||
return this.pad('{{ DIRECTIVE ' + this.SubExpression(mustache) + ' }}');
|
return this.pad('{{ DIRECTIVE ' + this.SubExpression(mustache) + ' }}');
|
||||||
};
|
};
|
||||||
|
|
||||||
PrintVisitor.prototype.BlockStatement = PrintVisitor.prototype.DecoratorBlock = function(
|
PrintVisitor.prototype.BlockStatement =
|
||||||
block
|
PrintVisitor.prototype.DecoratorBlock = function(block) {
|
||||||
) {
|
|
||||||
let out = '';
|
let out = '';
|
||||||
|
|
||||||
out += this.pad(
|
out += this.pad((block.type === 'DecoratorBlock' ? 'DIRECTIVE ' : '') + 'BLOCK:');
|
||||||
(block.type === 'DecoratorBlock' ? 'DIRECTIVE ' : '') + 'BLOCK:'
|
|
||||||
);
|
|
||||||
this.padding++;
|
this.padding++;
|
||||||
out += this.pad(this.SubExpression(block));
|
out += this.pad(this.SubExpression(block));
|
||||||
if (block.program) {
|
if (block.program) {
|
||||||
@@ -70,16 +66,12 @@ PrintVisitor.prototype.BlockStatement = PrintVisitor.prototype.DecoratorBlock =
|
|||||||
this.padding--;
|
this.padding--;
|
||||||
}
|
}
|
||||||
if (block.inverse) {
|
if (block.inverse) {
|
||||||
if (block.program) {
|
if (block.program) { this.padding++; }
|
||||||
this.padding++;
|
|
||||||
}
|
|
||||||
out += this.pad('{{^}}');
|
out += this.pad('{{^}}');
|
||||||
this.padding++;
|
this.padding++;
|
||||||
out += this.accept(block.inverse);
|
out += this.accept(block.inverse);
|
||||||
this.padding--;
|
this.padding--;
|
||||||
if (block.program) {
|
if (block.program) { this.padding--; }
|
||||||
this.padding--;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
this.padding--;
|
this.padding--;
|
||||||
|
|
||||||
@@ -123,8 +115,8 @@ PrintVisitor.prototype.CommentStatement = function(comment) {
|
|||||||
|
|
||||||
PrintVisitor.prototype.SubExpression = function(sexpr) {
|
PrintVisitor.prototype.SubExpression = function(sexpr) {
|
||||||
let params = sexpr.params,
|
let params = sexpr.params,
|
||||||
paramStrings = [],
|
paramStrings = [],
|
||||||
hash;
|
hash;
|
||||||
|
|
||||||
for (let i = 0, l = params.length; i < l; i++) {
|
for (let i = 0, l = params.length; i < l; i++) {
|
||||||
paramStrings.push(this.accept(params[i]));
|
paramStrings.push(this.accept(params[i]));
|
||||||
@@ -142,6 +134,7 @@ PrintVisitor.prototype.PathExpression = function(id) {
|
|||||||
return (id.data ? '@' : '') + 'PATH:' + path;
|
return (id.data ? '@' : '') + 'PATH:' + path;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
PrintVisitor.prototype.StringLiteral = function(string) {
|
PrintVisitor.prototype.StringLiteral = function(string) {
|
||||||
return '"' + string.value + '"';
|
return '"' + string.value + '"';
|
||||||
};
|
};
|
||||||
@@ -164,7 +157,7 @@ PrintVisitor.prototype.NullLiteral = function() {
|
|||||||
|
|
||||||
PrintVisitor.prototype.Hash = function(hash) {
|
PrintVisitor.prototype.Hash = function(hash) {
|
||||||
let pairs = hash.pairs,
|
let pairs = hash.pairs,
|
||||||
joinedPairs = [];
|
joinedPairs = [];
|
||||||
|
|
||||||
for (let i = 0, l = pairs.length; i < l; i++) {
|
for (let i = 0, l = pairs.length; i < l; i++) {
|
||||||
joinedPairs.push(this.accept(pairs[i]));
|
joinedPairs.push(this.accept(pairs[i]));
|
||||||
|
|||||||
@@ -15,14 +15,7 @@ Visitor.prototype = {
|
|||||||
// Hacky sanity check: This may have a few false positives for type for the helper
|
// Hacky sanity check: This may have a few false positives for type for the helper
|
||||||
// methods but will generally do the right thing without a lot of overhead.
|
// methods but will generally do the right thing without a lot of overhead.
|
||||||
if (value && !Visitor.prototype[value.type]) {
|
if (value && !Visitor.prototype[value.type]) {
|
||||||
throw new Exception(
|
throw new Exception('Unexpected node type "' + value.type + '" found when accepting ' + name + ' on ' + node.type);
|
||||||
'Unexpected node type "' +
|
|
||||||
value.type +
|
|
||||||
'" found when accepting ' +
|
|
||||||
name +
|
|
||||||
' on ' +
|
|
||||||
node.type
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
node[name] = value;
|
node[name] = value;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -14,18 +14,18 @@ WhitespaceControl.prototype.Program = function(program) {
|
|||||||
let body = program.body;
|
let body = program.body;
|
||||||
for (let i = 0, l = body.length; i < l; i++) {
|
for (let i = 0, l = body.length; i < l; i++) {
|
||||||
let current = body[i],
|
let current = body[i],
|
||||||
strip = this.accept(current);
|
strip = this.accept(current);
|
||||||
|
|
||||||
if (!strip) {
|
if (!strip) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
let _isPrevWhitespace = isPrevWhitespace(body, i, isRoot),
|
let _isPrevWhitespace = isPrevWhitespace(body, i, isRoot),
|
||||||
_isNextWhitespace = isNextWhitespace(body, i, isRoot),
|
_isNextWhitespace = isNextWhitespace(body, i, isRoot),
|
||||||
openStandalone = strip.openStandalone && _isPrevWhitespace,
|
|
||||||
closeStandalone = strip.closeStandalone && _isNextWhitespace,
|
openStandalone = strip.openStandalone && _isPrevWhitespace,
|
||||||
inlineStandalone =
|
closeStandalone = strip.closeStandalone && _isNextWhitespace,
|
||||||
strip.inlineStandalone && _isPrevWhitespace && _isNextWhitespace;
|
inlineStandalone = strip.inlineStandalone && _isPrevWhitespace && _isNextWhitespace;
|
||||||
|
|
||||||
if (strip.close) {
|
if (strip.close) {
|
||||||
omitRight(body, i, true);
|
omitRight(body, i, true);
|
||||||
@@ -41,7 +41,7 @@ WhitespaceControl.prototype.Program = function(program) {
|
|||||||
// If we are on a standalone node, save the indent info for partials
|
// If we are on a standalone node, save the indent info for partials
|
||||||
if (current.type === 'PartialStatement') {
|
if (current.type === 'PartialStatement') {
|
||||||
// Pull out the whitespace from the final line
|
// Pull out the whitespace from the final line
|
||||||
current.indent = /([ \t]+$)/.exec(body[i - 1].original)[1];
|
current.indent = (/([ \t]+$)/).exec(body[i - 1].original)[1];
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -62,17 +62,17 @@ WhitespaceControl.prototype.Program = function(program) {
|
|||||||
return program;
|
return program;
|
||||||
};
|
};
|
||||||
|
|
||||||
WhitespaceControl.prototype.BlockStatement = WhitespaceControl.prototype.DecoratorBlock = WhitespaceControl.prototype.PartialBlockStatement = function(
|
WhitespaceControl.prototype.BlockStatement =
|
||||||
block
|
WhitespaceControl.prototype.DecoratorBlock =
|
||||||
) {
|
WhitespaceControl.prototype.PartialBlockStatement = function(block) {
|
||||||
this.accept(block.program);
|
this.accept(block.program);
|
||||||
this.accept(block.inverse);
|
this.accept(block.inverse);
|
||||||
|
|
||||||
// Find the inverse program that is involed with whitespace stripping.
|
// Find the inverse program that is involed with whitespace stripping.
|
||||||
let program = block.program || block.inverse,
|
let program = block.program || block.inverse,
|
||||||
inverse = block.program && block.inverse,
|
inverse = block.program && block.inverse,
|
||||||
firstInverse = inverse,
|
firstInverse = inverse,
|
||||||
lastInverse = inverse;
|
lastInverse = inverse;
|
||||||
|
|
||||||
if (inverse && inverse.chained) {
|
if (inverse && inverse.chained) {
|
||||||
firstInverse = inverse.body[0].program;
|
firstInverse = inverse.body[0].program;
|
||||||
@@ -112,11 +112,9 @@ WhitespaceControl.prototype.BlockStatement = WhitespaceControl.prototype.Decorat
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Find standalone else statments
|
// Find standalone else statments
|
||||||
if (
|
if (!this.options.ignoreStandalone
|
||||||
!this.options.ignoreStandalone &&
|
&& isPrevWhitespace(program.body)
|
||||||
isPrevWhitespace(program.body) &&
|
&& isNextWhitespace(firstInverse.body)) {
|
||||||
isNextWhitespace(firstInverse.body)
|
|
||||||
) {
|
|
||||||
omitLeft(program.body);
|
omitLeft(program.body);
|
||||||
omitRight(firstInverse.body);
|
omitRight(firstInverse.body);
|
||||||
}
|
}
|
||||||
@@ -127,15 +125,13 @@ WhitespaceControl.prototype.BlockStatement = WhitespaceControl.prototype.Decorat
|
|||||||
return strip;
|
return strip;
|
||||||
};
|
};
|
||||||
|
|
||||||
WhitespaceControl.prototype.Decorator = WhitespaceControl.prototype.MustacheStatement = function(
|
WhitespaceControl.prototype.Decorator =
|
||||||
mustache
|
WhitespaceControl.prototype.MustacheStatement = function(mustache) {
|
||||||
) {
|
|
||||||
return mustache.strip;
|
return mustache.strip;
|
||||||
};
|
};
|
||||||
|
|
||||||
WhitespaceControl.prototype.PartialStatement = WhitespaceControl.prototype.CommentStatement = function(
|
WhitespaceControl.prototype.PartialStatement =
|
||||||
node
|
WhitespaceControl.prototype.CommentStatement = function(node) {
|
||||||
) {
|
|
||||||
/* istanbul ignore next */
|
/* istanbul ignore next */
|
||||||
let strip = node.strip || {};
|
let strip = node.strip || {};
|
||||||
return {
|
return {
|
||||||
@@ -145,6 +141,7 @@ WhitespaceControl.prototype.PartialStatement = WhitespaceControl.prototype.Comme
|
|||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
function isPrevWhitespace(body, i, isRoot) {
|
function isPrevWhitespace(body, i, isRoot) {
|
||||||
if (i === undefined) {
|
if (i === undefined) {
|
||||||
i = body.length;
|
i = body.length;
|
||||||
@@ -153,15 +150,13 @@ function isPrevWhitespace(body, i, isRoot) {
|
|||||||
// Nodes that end with newlines are considered whitespace (but are special
|
// Nodes that end with newlines are considered whitespace (but are special
|
||||||
// cased for strip operations)
|
// cased for strip operations)
|
||||||
let prev = body[i - 1],
|
let prev = body[i - 1],
|
||||||
sibling = body[i - 2];
|
sibling = body[i - 2];
|
||||||
if (!prev) {
|
if (!prev) {
|
||||||
return isRoot;
|
return isRoot;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (prev.type === 'ContentStatement') {
|
if (prev.type === 'ContentStatement') {
|
||||||
return (sibling || !isRoot ? /\r?\n\s*?$/ : /(^|\r?\n)\s*?$/).test(
|
return (sibling || !isRoot ? (/\r?\n\s*?$/) : (/(^|\r?\n)\s*?$/)).test(prev.original);
|
||||||
prev.original
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
function isNextWhitespace(body, i, isRoot) {
|
function isNextWhitespace(body, i, isRoot) {
|
||||||
@@ -170,15 +165,13 @@ function isNextWhitespace(body, i, isRoot) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
let next = body[i + 1],
|
let next = body[i + 1],
|
||||||
sibling = body[i + 2];
|
sibling = body[i + 2];
|
||||||
if (!next) {
|
if (!next) {
|
||||||
return isRoot;
|
return isRoot;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (next.type === 'ContentStatement') {
|
if (next.type === 'ContentStatement') {
|
||||||
return (sibling || !isRoot ? /^\s*?\r?\n/ : /^\s*?(\r?\n|$)/).test(
|
return (sibling || !isRoot ? (/^\s*?\r?\n/) : (/^\s*?(\r?\n|$)/)).test(next.original);
|
||||||
next.original
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -191,19 +184,12 @@ function isNextWhitespace(body, i, isRoot) {
|
|||||||
// content is met.
|
// content is met.
|
||||||
function omitRight(body, i, multiple) {
|
function omitRight(body, i, multiple) {
|
||||||
let current = body[i == null ? 0 : i + 1];
|
let current = body[i == null ? 0 : i + 1];
|
||||||
if (
|
if (!current || current.type !== 'ContentStatement' || (!multiple && current.rightStripped)) {
|
||||||
!current ||
|
|
||||||
current.type !== 'ContentStatement' ||
|
|
||||||
(!multiple && current.rightStripped)
|
|
||||||
) {
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
let original = current.value;
|
let original = current.value;
|
||||||
current.value = current.value.replace(
|
current.value = current.value.replace(multiple ? (/^\s+/) : (/^[ \t]*\r?\n?/), '');
|
||||||
multiple ? /^\s+/ : /^[ \t]*\r?\n?/,
|
|
||||||
''
|
|
||||||
);
|
|
||||||
current.rightStripped = current.value !== original;
|
current.rightStripped = current.value !== original;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -216,17 +202,13 @@ function omitRight(body, i, multiple) {
|
|||||||
// content is met.
|
// content is met.
|
||||||
function omitLeft(body, i, multiple) {
|
function omitLeft(body, i, multiple) {
|
||||||
let current = body[i == null ? body.length - 1 : i - 1];
|
let current = body[i == null ? body.length - 1 : i - 1];
|
||||||
if (
|
if (!current || current.type !== 'ContentStatement' || (!multiple && current.leftStripped)) {
|
||||||
!current ||
|
|
||||||
current.type !== 'ContentStatement' ||
|
|
||||||
(!multiple && current.leftStripped)
|
|
||||||
) {
|
|
||||||
return;
|
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 preceded by a non-content node.
|
||||||
let original = current.value;
|
let original = current.value;
|
||||||
current.value = current.value.replace(multiple ? /\s+$/ : /[ \t]+$/, '');
|
current.value = current.value.replace(multiple ? (/\s+$/) : (/[ \t]+$/), '');
|
||||||
current.leftStripped = current.value !== original;
|
current.leftStripped = current.value !== original;
|
||||||
return current.leftStripped;
|
return current.leftStripped;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -3,3 +3,4 @@ import registerInline from './decorators/inline';
|
|||||||
export function registerDefaultDecorators(instance) {
|
export function registerDefaultDecorators(instance) {
|
||||||
registerInline(instance);
|
registerInline(instance);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
import { extend } from '../utils';
|
import {extend} from '../utils';
|
||||||
|
|
||||||
export default function(instance) {
|
export default function(instance) {
|
||||||
instance.registerDecorator('inline', function(fn, props, container, options) {
|
instance.registerDecorator('inline', function(fn, props, container, options) {
|
||||||
|
|||||||
@@ -1,20 +1,12 @@
|
|||||||
const errorProps = [
|
|
||||||
'description',
|
const errorProps = ['description', 'fileName', 'lineNumber', 'endLineNumber', 'message', 'name', 'number', 'stack'];
|
||||||
'fileName',
|
|
||||||
'lineNumber',
|
|
||||||
'endLineNumber',
|
|
||||||
'message',
|
|
||||||
'name',
|
|
||||||
'number',
|
|
||||||
'stack'
|
|
||||||
];
|
|
||||||
|
|
||||||
function Exception(message, node) {
|
function Exception(message, node) {
|
||||||
let loc = node && node.loc,
|
let loc = node && node.loc,
|
||||||
line,
|
line,
|
||||||
endLineNumber,
|
endLineNumber,
|
||||||
column,
|
column,
|
||||||
endColumn;
|
endColumn;
|
||||||
|
|
||||||
if (loc) {
|
if (loc) {
|
||||||
line = loc.start.line;
|
line = loc.start.line;
|
||||||
|
|||||||
@@ -1,9 +1,9 @@
|
|||||||
import { appendContextPath, createFrame, isArray } from '../utils';
|
import {appendContextPath, createFrame, isArray} from '../utils';
|
||||||
|
|
||||||
export default function(instance) {
|
export default function(instance) {
|
||||||
instance.registerHelper('blockHelperMissing', function(context, options) {
|
instance.registerHelper('blockHelperMissing', function(context, options) {
|
||||||
let inverse = options.inverse,
|
let inverse = options.inverse,
|
||||||
fn = options.fn;
|
fn = options.fn;
|
||||||
|
|
||||||
if (context === true) {
|
if (context === true) {
|
||||||
return fn(this);
|
return fn(this);
|
||||||
@@ -22,11 +22,8 @@ export default function(instance) {
|
|||||||
} else {
|
} else {
|
||||||
if (options.data && options.ids) {
|
if (options.data && options.ids) {
|
||||||
let data = createFrame(options.data);
|
let data = createFrame(options.data);
|
||||||
data.contextPath = appendContextPath(
|
data.contextPath = appendContextPath(options.data.contextPath, options.name);
|
||||||
options.data.contextPath,
|
options = {data: data};
|
||||||
options.name
|
|
||||||
);
|
|
||||||
options = { data: data };
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return fn(context, options);
|
return fn(context, options);
|
||||||
|
|||||||
@@ -1,10 +1,4 @@
|
|||||||
import {
|
import {appendContextPath, blockParams, createFrame, isArray, isFunction} from '../utils';
|
||||||
appendContextPath,
|
|
||||||
blockParams,
|
|
||||||
createFrame,
|
|
||||||
isArray,
|
|
||||||
isFunction
|
|
||||||
} from '../utils';
|
|
||||||
import Exception from '../exception';
|
import Exception from '../exception';
|
||||||
|
|
||||||
export default function(instance) {
|
export default function(instance) {
|
||||||
@@ -14,20 +8,17 @@ export default function(instance) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
let fn = options.fn,
|
let fn = options.fn,
|
||||||
inverse = options.inverse,
|
inverse = options.inverse,
|
||||||
i = 0,
|
i = 0,
|
||||||
ret = '',
|
ret = '',
|
||||||
data,
|
data,
|
||||||
contextPath;
|
contextPath;
|
||||||
|
|
||||||
if (options.data && options.ids) {
|
if (options.data && options.ids) {
|
||||||
contextPath =
|
contextPath = appendContextPath(options.data.contextPath, options.ids[0]) + '.';
|
||||||
appendContextPath(options.data.contextPath, options.ids[0]) + '.';
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (isFunction(context)) {
|
if (isFunction(context)) { context = context.call(this); }
|
||||||
context = context.call(this);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (options.data) {
|
if (options.data) {
|
||||||
data = createFrame(options.data);
|
data = createFrame(options.data);
|
||||||
@@ -45,15 +36,10 @@ export default function(instance) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
ret =
|
ret = ret + fn(context[field], {
|
||||||
ret +
|
data: data,
|
||||||
fn(context[field], {
|
blockParams: blockParams([context[field], field], [contextPath + field, null])
|
||||||
data: data,
|
});
|
||||||
blockParams: blockParams(
|
|
||||||
[context[field], field],
|
|
||||||
[contextPath + field, null]
|
|
||||||
)
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (context && typeof context === 'object') {
|
if (context && typeof context === 'object') {
|
||||||
|
|||||||
@@ -7,9 +7,7 @@ export default function(instance) {
|
|||||||
return undefined;
|
return undefined;
|
||||||
} else {
|
} else {
|
||||||
// Someone is actually trying to call something, blow up.
|
// Someone is actually trying to call something, blow up.
|
||||||
throw new Exception(
|
throw new Exception('Missing helper: "' + arguments[arguments.length - 1].name + '"');
|
||||||
'Missing helper: "' + arguments[arguments.length - 1].name + '"'
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -3,12 +3,8 @@ import Exception from '../exception';
|
|||||||
|
|
||||||
export default function(instance) {
|
export default function(instance) {
|
||||||
instance.registerHelper('if', function(conditional, options) {
|
instance.registerHelper('if', function(conditional, options) {
|
||||||
if (arguments.length != 2) {
|
if (arguments.length != 2) { throw new Exception('#if requires exactly one argument');}
|
||||||
throw new Exception('#if requires exactly one argument');
|
if (isFunction(conditional)) { conditional = conditional.call(this); }
|
||||||
}
|
|
||||||
if (isFunction(conditional)) {
|
|
||||||
conditional = conditional.call(this);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Default behavior is to render the positive path if the value is truthy and not empty.
|
// Default behavior is to render the positive path if the value is truthy and not empty.
|
||||||
// The `includeZero` option may be set to treat the condtional as purely not empty based on the
|
// The `includeZero` option may be set to treat the condtional as purely not empty based on the
|
||||||
@@ -21,13 +17,7 @@ export default function(instance) {
|
|||||||
});
|
});
|
||||||
|
|
||||||
instance.registerHelper('unless', function(conditional, options) {
|
instance.registerHelper('unless', function(conditional, options) {
|
||||||
if (arguments.length != 2) {
|
if (arguments.length != 2) { throw new Exception('#unless requires exactly one argument');}
|
||||||
throw new Exception('#unless requires exactly one argument');
|
return instance.helpers['if'].call(this, conditional, {fn: options.inverse, inverse: options.fn, hash: options.hash});
|
||||||
}
|
|
||||||
return instance.helpers['if'].call(this, conditional, {
|
|
||||||
fn: options.inverse,
|
|
||||||
inverse: options.fn,
|
|
||||||
hash: options.hash
|
|
||||||
});
|
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
export default function(instance) {
|
export default function(instance) {
|
||||||
instance.registerHelper('log', function(/* message, options */) {
|
instance.registerHelper('log', function(/* message, options */) {
|
||||||
let args = [undefined],
|
let args = [undefined],
|
||||||
options = arguments[arguments.length - 1];
|
options = arguments[arguments.length - 1];
|
||||||
for (let i = 0; i < arguments.length - 1; i++) {
|
for (let i = 0; i < arguments.length - 1; i++) {
|
||||||
args.push(arguments[i]);
|
args.push(arguments[i]);
|
||||||
}
|
}
|
||||||
@@ -14,6 +14,6 @@ export default function(instance) {
|
|||||||
}
|
}
|
||||||
args[0] = level;
|
args[0] = level;
|
||||||
|
|
||||||
instance.log(...args);
|
instance.log(... args);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,9 +1,13 @@
|
|||||||
|
export const dangerousPropertyRegex = /^(constructor|__defineGetter__|__defineSetter__|__lookupGetter__|__proto__)$/;
|
||||||
|
|
||||||
export default function(instance) {
|
export default function(instance) {
|
||||||
instance.registerHelper('lookup', function(obj, field, options) {
|
instance.registerHelper('lookup', function(obj, field) {
|
||||||
if (!obj) {
|
if (!obj) {
|
||||||
// Note for 5.0: Change to "obj == null" in 5.0
|
|
||||||
return obj;
|
return obj;
|
||||||
}
|
}
|
||||||
return options.lookupProperty(obj, field);
|
if (dangerousPropertyRegex.test(String(field)) && !Object.prototype.propertyIsEnumerable.call(obj, field)) {
|
||||||
|
return undefined;
|
||||||
|
}
|
||||||
|
return obj[field];
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,20 +1,10 @@
|
|||||||
import {
|
import { appendContextPath, blockParams, createFrame, isEmpty, isFunction } from '../utils';
|
||||||
appendContextPath,
|
|
||||||
blockParams,
|
|
||||||
createFrame,
|
|
||||||
isEmpty,
|
|
||||||
isFunction
|
|
||||||
} from '../utils';
|
|
||||||
import Exception from '../exception';
|
import Exception from '../exception';
|
||||||
|
|
||||||
export default function(instance) {
|
export default function(instance) {
|
||||||
instance.registerHelper('with', function(context, options) {
|
instance.registerHelper('with', function(context, options) {
|
||||||
if (arguments.length != 2) {
|
if (arguments.length != 2) { throw new Exception('#with requires exactly one argument');}
|
||||||
throw new Exception('#with requires exactly one argument');
|
if (isFunction(context)) { context = context.call(this); }
|
||||||
}
|
|
||||||
if (isFunction(context)) {
|
|
||||||
context = context.call(this);
|
|
||||||
}
|
|
||||||
|
|
||||||
let fn = options.fn;
|
let fn = options.fn;
|
||||||
|
|
||||||
@@ -22,10 +12,7 @@ export default function(instance) {
|
|||||||
let data = options.data;
|
let data = options.data;
|
||||||
if (options.data && options.ids) {
|
if (options.data && options.ids) {
|
||||||
data = createFrame(options.data);
|
data = createFrame(options.data);
|
||||||
data.contextPath = appendContextPath(
|
data.contextPath = appendContextPath(options.data.contextPath, options.ids[0]);
|
||||||
options.data.contextPath,
|
|
||||||
options.ids[0]
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return fn(context, {
|
return fn(context, {
|
||||||
|
|||||||
@@ -1,11 +0,0 @@
|
|||||||
import { extend } from '../utils';
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Create a new object with "null"-prototype to avoid truthy results on prototype properties.
|
|
||||||
* The resulting object can be used with "object[property]" to check if a property exists
|
|
||||||
* @param {...object} sources a varargs parameter of source objects that will be merged
|
|
||||||
* @returns {object}
|
|
||||||
*/
|
|
||||||
export function createNewLookupObject(...sources) {
|
|
||||||
return extend(Object.create(null), ...sources);
|
|
||||||
}
|
|
||||||
@@ -1,70 +0,0 @@
|
|||||||
import { createNewLookupObject } from './create-new-lookup-object';
|
|
||||||
import * as logger from '../logger';
|
|
||||||
|
|
||||||
const loggedProperties = Object.create(null);
|
|
||||||
|
|
||||||
export function createProtoAccessControl(runtimeOptions) {
|
|
||||||
let defaultMethodWhiteList = Object.create(null);
|
|
||||||
defaultMethodWhiteList['constructor'] = false;
|
|
||||||
defaultMethodWhiteList['__defineGetter__'] = false;
|
|
||||||
defaultMethodWhiteList['__defineSetter__'] = false;
|
|
||||||
defaultMethodWhiteList['__lookupGetter__'] = false;
|
|
||||||
|
|
||||||
let defaultPropertyWhiteList = Object.create(null);
|
|
||||||
// eslint-disable-next-line no-proto
|
|
||||||
defaultPropertyWhiteList['__proto__'] = false;
|
|
||||||
|
|
||||||
return {
|
|
||||||
properties: {
|
|
||||||
whitelist: createNewLookupObject(
|
|
||||||
defaultPropertyWhiteList,
|
|
||||||
runtimeOptions.allowedProtoProperties
|
|
||||||
),
|
|
||||||
defaultValue: runtimeOptions.allowProtoPropertiesByDefault
|
|
||||||
},
|
|
||||||
methods: {
|
|
||||||
whitelist: createNewLookupObject(
|
|
||||||
defaultMethodWhiteList,
|
|
||||||
runtimeOptions.allowedProtoMethods
|
|
||||||
),
|
|
||||||
defaultValue: runtimeOptions.allowProtoMethodsByDefault
|
|
||||||
}
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
export function resultIsAllowed(result, protoAccessControl, propertyName) {
|
|
||||||
if (typeof result === 'function') {
|
|
||||||
return checkWhiteList(protoAccessControl.methods, propertyName);
|
|
||||||
} else {
|
|
||||||
return checkWhiteList(protoAccessControl.properties, propertyName);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
function checkWhiteList(protoAccessControlForType, propertyName) {
|
|
||||||
if (protoAccessControlForType.whitelist[propertyName] !== undefined) {
|
|
||||||
return protoAccessControlForType.whitelist[propertyName] === true;
|
|
||||||
}
|
|
||||||
if (protoAccessControlForType.defaultValue !== undefined) {
|
|
||||||
return protoAccessControlForType.defaultValue;
|
|
||||||
}
|
|
||||||
logUnexpecedPropertyAccessOnce(propertyName);
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
function logUnexpecedPropertyAccessOnce(propertyName) {
|
|
||||||
if (loggedProperties[propertyName] !== true) {
|
|
||||||
loggedProperties[propertyName] = true;
|
|
||||||
logger.log(
|
|
||||||
'error',
|
|
||||||
`Handlebars: Access has been denied to resolve the property "${propertyName}" because it is not an "own property" of its parent.\n` +
|
|
||||||
`You can add a runtime option to disable the check or this warning:\n` +
|
|
||||||
`See https://handlebarsjs.com/api-reference/runtime-options.html#options-to-control-prototype-access for details`
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
export function resetLoggedProperties() {
|
|
||||||
Object.keys(loggedProperties).forEach(propertyName => {
|
|
||||||
delete loggedProperties[propertyName];
|
|
||||||
});
|
|
||||||
}
|
|
||||||
@@ -1,13 +0,0 @@
|
|||||||
export function wrapHelper(helper, transformOptionsFn) {
|
|
||||||
if (typeof helper !== 'function') {
|
|
||||||
// This should not happen, but apparently it does in https://github.com/wycats/handlebars.js/issues/1639
|
|
||||||
// We try to make the wrapper least-invasive by not wrapping it, if the helper is not a function.
|
|
||||||
return helper;
|
|
||||||
}
|
|
||||||
let wrapper = function(/* dynamic arguments */) {
|
|
||||||
const options = arguments[arguments.length - 1];
|
|
||||||
arguments[arguments.length - 1] = transformOptionsFn(options);
|
|
||||||
return helper.apply(this, arguments);
|
|
||||||
};
|
|
||||||
return wrapper;
|
|
||||||
}
|
|
||||||
@@ -1,4 +1,4 @@
|
|||||||
import { indexOf } from './utils';
|
import {indexOf} from './utils';
|
||||||
|
|
||||||
let logger = {
|
let logger = {
|
||||||
methodMap: ['debug', 'info', 'warn', 'error'],
|
methodMap: ['debug', 'info', 'warn', 'error'],
|
||||||
@@ -22,13 +22,9 @@ let logger = {
|
|||||||
log: function(level, ...message) {
|
log: function(level, ...message) {
|
||||||
level = logger.lookupLevel(level);
|
level = logger.lookupLevel(level);
|
||||||
|
|
||||||
if (
|
if (typeof console !== 'undefined' && logger.lookupLevel(logger.level) <= level) {
|
||||||
typeof console !== 'undefined' &&
|
|
||||||
logger.lookupLevel(logger.level) <= level
|
|
||||||
) {
|
|
||||||
let method = logger.methodMap[level];
|
let method = logger.methodMap[level];
|
||||||
// eslint-disable-next-line no-console
|
if (!console[method]) { // eslint-disable-line no-console
|
||||||
if (!console[method]) {
|
|
||||||
method = 'log';
|
method = 'log';
|
||||||
}
|
}
|
||||||
console[method](...message); // eslint-disable-line no-console
|
console[method](...message); // eslint-disable-line no-console
|
||||||
|
|||||||
@@ -1,7 +1,8 @@
|
|||||||
|
/* global window */
|
||||||
export default function(Handlebars) {
|
export default function(Handlebars) {
|
||||||
/* istanbul ignore next */
|
/* istanbul ignore next */
|
||||||
let root = typeof global !== 'undefined' ? global : window,
|
let root = typeof global !== 'undefined' ? global : window,
|
||||||
$Handlebars = root.Handlebars;
|
$Handlebars = root.Handlebars;
|
||||||
/* istanbul ignore next */
|
/* istanbul ignore next */
|
||||||
Handlebars.noConflict = function() {
|
Handlebars.noConflict = function() {
|
||||||
if (root.Handlebars === Handlebars) {
|
if (root.Handlebars === Handlebars) {
|
||||||
|
|||||||
+50
-207
@@ -1,52 +1,30 @@
|
|||||||
import * as Utils from './utils';
|
import {extend, escapeExpression} from './utils';
|
||||||
import Exception from './exception';
|
import Exception from './exception';
|
||||||
import {
|
import {COMPILER_REVISION, createFrame, LAST_COMPATIBLE_COMPILER_REVISION, REVISION_CHANGES} from './base';
|
||||||
COMPILER_REVISION,
|
import {moveHelperToHooks} from './helpers';
|
||||||
createFrame,
|
|
||||||
LAST_COMPATIBLE_COMPILER_REVISION,
|
|
||||||
REVISION_CHANGES
|
|
||||||
} from './base';
|
|
||||||
import { moveHelperToHooks } from './helpers';
|
|
||||||
import { wrapHelper } from './internal/wrapHelper';
|
|
||||||
import {
|
|
||||||
createProtoAccessControl,
|
|
||||||
resultIsAllowed
|
|
||||||
} from './internal/proto-access';
|
|
||||||
|
|
||||||
export function checkRevision(compilerInfo) {
|
export function checkRevision(compilerInfo) {
|
||||||
const compilerRevision = (compilerInfo && compilerInfo[0]) || 1,
|
const compilerRevision = compilerInfo && compilerInfo[0] || 1,
|
||||||
currentRevision = COMPILER_REVISION;
|
currentRevision = COMPILER_REVISION;
|
||||||
|
|
||||||
if (
|
if (compilerRevision >= LAST_COMPATIBLE_COMPILER_REVISION && compilerRevision <= COMPILER_REVISION) {
|
||||||
compilerRevision >= LAST_COMPATIBLE_COMPILER_REVISION &&
|
|
||||||
compilerRevision <= COMPILER_REVISION
|
|
||||||
) {
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (compilerRevision < LAST_COMPATIBLE_COMPILER_REVISION) {
|
if (compilerRevision < LAST_COMPATIBLE_COMPILER_REVISION) {
|
||||||
const runtimeVersions = REVISION_CHANGES[currentRevision],
|
const runtimeVersions = REVISION_CHANGES[currentRevision],
|
||||||
compilerVersions = REVISION_CHANGES[compilerRevision];
|
compilerVersions = REVISION_CHANGES[compilerRevision];
|
||||||
throw new Exception(
|
throw new Exception('Template was precompiled with an older version of Handlebars than the current runtime. ' +
|
||||||
'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 + ').');
|
||||||
'Please update your precompiler to a newer version (' +
|
|
||||||
runtimeVersions +
|
|
||||||
') or downgrade your runtime to an older version (' +
|
|
||||||
compilerVersions +
|
|
||||||
').'
|
|
||||||
);
|
|
||||||
} else {
|
} else {
|
||||||
// Use the embedded version info since the runtime doesn't know about this revision yet
|
// Use the embedded version info since the runtime doesn't know about this revision yet
|
||||||
throw new Exception(
|
throw new Exception('Template was precompiled with a newer version of Handlebars than the current runtime. ' +
|
||||||
'Template was precompiled with a newer version of Handlebars than the current runtime. ' +
|
'Please update your runtime to a newer version (' + compilerInfo[1] + ').');
|
||||||
'Please update your runtime to a newer version (' +
|
|
||||||
compilerInfo[1] +
|
|
||||||
').'
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
export function template(templateSpec, env) {
|
export function template(templateSpec, env) {
|
||||||
|
|
||||||
/* istanbul ignore next */
|
/* istanbul ignore next */
|
||||||
if (!env) {
|
if (!env) {
|
||||||
throw new Exception('No environment passed to template');
|
throw new Exception('No environment passed to template');
|
||||||
@@ -62,37 +40,24 @@ export function template(templateSpec, env) {
|
|||||||
env.VM.checkRevision(templateSpec.compiler);
|
env.VM.checkRevision(templateSpec.compiler);
|
||||||
|
|
||||||
// backwards compatibility for precompiled templates with compiler-version 7 (<4.3.0)
|
// backwards compatibility for precompiled templates with compiler-version 7 (<4.3.0)
|
||||||
const templateWasPrecompiledWithCompilerV7 =
|
const templateWasPrecompiledWithCompilerV7 = templateSpec.compiler && templateSpec.compiler[0] === 7;
|
||||||
templateSpec.compiler && templateSpec.compiler[0] === 7;
|
|
||||||
|
|
||||||
function invokePartialWrapper(partial, context, options) {
|
function invokePartialWrapper(partial, context, options) {
|
||||||
if (options.hash) {
|
if (options.hash) {
|
||||||
context = Utils.extend({}, context, options.hash);
|
context = extend({}, context, options.hash);
|
||||||
if (options.ids) {
|
if (options.ids) {
|
||||||
options.ids[0] = true;
|
options.ids[0] = true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
partial = env.VM.resolvePartial.call(this, partial, context, options);
|
partial = env.VM.resolvePartial.call(this, partial, context, options);
|
||||||
|
|
||||||
let extendedOptions = Utils.extend({}, options, {
|
let optionsWithHooks = extend({}, options, {hooks: this.hooks});
|
||||||
hooks: this.hooks,
|
|
||||||
protoAccessControl: this.protoAccessControl
|
|
||||||
});
|
|
||||||
|
|
||||||
let result = env.VM.invokePartial.call(
|
let result = env.VM.invokePartial.call(this, partial, context, optionsWithHooks);
|
||||||
this,
|
|
||||||
partial,
|
|
||||||
context,
|
|
||||||
extendedOptions
|
|
||||||
);
|
|
||||||
|
|
||||||
if (result == null && env.compile) {
|
if (result == null && env.compile) {
|
||||||
options.partials[options.name] = env.compile(
|
options.partials[options.name] = env.compile(partial, templateSpec.compilerOptions, env);
|
||||||
partial,
|
result = options.partials[options.name](context, optionsWithHooks);
|
||||||
templateSpec.compilerOptions,
|
|
||||||
env
|
|
||||||
);
|
|
||||||
result = options.partials[options.name](context, extendedOptions);
|
|
||||||
}
|
}
|
||||||
if (result != null) {
|
if (result != null) {
|
||||||
if (options.indent) {
|
if (options.indent) {
|
||||||
@@ -108,11 +73,7 @@ export function template(templateSpec, env) {
|
|||||||
}
|
}
|
||||||
return result;
|
return result;
|
||||||
} else {
|
} else {
|
||||||
throw new Exception(
|
throw new Exception('The partial ' + options.name + ' could not be compiled when running in runtime-only mode');
|
||||||
'The partial ' +
|
|
||||||
options.name +
|
|
||||||
' could not be compiled when running in runtime-only mode'
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -120,31 +81,14 @@ export function template(templateSpec, env) {
|
|||||||
let container = {
|
let container = {
|
||||||
strict: function(obj, name, loc) {
|
strict: function(obj, name, loc) {
|
||||||
if (!obj || !(name in obj)) {
|
if (!obj || !(name in obj)) {
|
||||||
throw new Exception('"' + name + '" not defined in ' + obj, {
|
throw new Exception('"' + name + '" not defined in ' + obj, { loc: loc });
|
||||||
loc: loc
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
return obj[name];
|
return obj[name];
|
||||||
},
|
},
|
||||||
lookupProperty: function(parent, propertyName) {
|
|
||||||
let result = parent[propertyName];
|
|
||||||
if (result == null) {
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
if (Object.prototype.hasOwnProperty.call(parent, propertyName)) {
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (resultIsAllowed(result, container.protoAccessControl, propertyName)) {
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
return undefined;
|
|
||||||
},
|
|
||||||
lookup: function(depths, name) {
|
lookup: function(depths, name) {
|
||||||
const len = depths.length;
|
const len = depths.length;
|
||||||
for (let i = 0; i < len; i++) {
|
for (let i = 0; i < len; i++) {
|
||||||
let result = depths[i] && container.lookupProperty(depths[i], name);
|
if (depths[i] && depths[i][name] != null) {
|
||||||
if (result != null) {
|
|
||||||
return depths[i][name];
|
return depths[i][name];
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -153,7 +97,7 @@ export function template(templateSpec, env) {
|
|||||||
return typeof current === 'function' ? current.call(context) : current;
|
return typeof current === 'function' ? current.call(context) : current;
|
||||||
},
|
},
|
||||||
|
|
||||||
escapeExpression: Utils.escapeExpression,
|
escapeExpression: escapeExpression,
|
||||||
invokePartial: invokePartialWrapper,
|
invokePartial: invokePartialWrapper,
|
||||||
|
|
||||||
fn: function(i) {
|
fn: function(i) {
|
||||||
@@ -165,17 +109,9 @@ export function template(templateSpec, env) {
|
|||||||
programs: [],
|
programs: [],
|
||||||
program: function(i, data, declaredBlockParams, blockParams, depths) {
|
program: function(i, data, declaredBlockParams, blockParams, depths) {
|
||||||
let programWrapper = this.programs[i],
|
let programWrapper = this.programs[i],
|
||||||
fn = this.fn(i);
|
fn = this.fn(i);
|
||||||
if (data || depths || blockParams || declaredBlockParams) {
|
if (data || depths || blockParams || declaredBlockParams) {
|
||||||
programWrapper = wrapProgram(
|
programWrapper = wrapProgram(this, i, fn, data, declaredBlockParams, blockParams, depths);
|
||||||
this,
|
|
||||||
i,
|
|
||||||
fn,
|
|
||||||
data,
|
|
||||||
declaredBlockParams,
|
|
||||||
blockParams,
|
|
||||||
depths
|
|
||||||
);
|
|
||||||
} else if (!programWrapper) {
|
} else if (!programWrapper) {
|
||||||
programWrapper = this.programs[i] = wrapProgram(this, i, fn);
|
programWrapper = this.programs[i] = wrapProgram(this, i, fn);
|
||||||
}
|
}
|
||||||
@@ -188,15 +124,6 @@ export function template(templateSpec, env) {
|
|||||||
}
|
}
|
||||||
return value;
|
return value;
|
||||||
},
|
},
|
||||||
mergeIfNeeded: function(param, common) {
|
|
||||||
let obj = param || common;
|
|
||||||
|
|
||||||
if (param && common && param !== common) {
|
|
||||||
obj = Utils.extend({}, common, param);
|
|
||||||
}
|
|
||||||
|
|
||||||
return obj;
|
|
||||||
},
|
|
||||||
// An empty object to use as replacement for null-contexts
|
// An empty object to use as replacement for null-contexts
|
||||||
nullContext: Object.seal({}),
|
nullContext: Object.seal({}),
|
||||||
|
|
||||||
@@ -212,82 +139,47 @@ export function template(templateSpec, env) {
|
|||||||
data = initData(context, data);
|
data = initData(context, data);
|
||||||
}
|
}
|
||||||
let depths,
|
let depths,
|
||||||
blockParams = templateSpec.useBlockParams ? [] : undefined;
|
blockParams = templateSpec.useBlockParams ? [] : undefined;
|
||||||
if (templateSpec.useDepths) {
|
if (templateSpec.useDepths) {
|
||||||
if (options.depths) {
|
if (options.depths) {
|
||||||
depths =
|
depths = context != options.depths[0] ? [context].concat(options.depths) : options.depths;
|
||||||
context != options.depths[0]
|
|
||||||
? [context].concat(options.depths)
|
|
||||||
: options.depths;
|
|
||||||
} else {
|
} else {
|
||||||
depths = [context];
|
depths = [context];
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
function main(context /*, options*/) {
|
function main(context/*, options*/) {
|
||||||
return (
|
return '' + templateSpec.main(container, context, container.helpers, container.partials, data, blockParams, depths);
|
||||||
'' +
|
|
||||||
templateSpec.main(
|
|
||||||
container,
|
|
||||||
context,
|
|
||||||
container.helpers,
|
|
||||||
container.partials,
|
|
||||||
data,
|
|
||||||
blockParams,
|
|
||||||
depths
|
|
||||||
)
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
|
main = executeDecorators(templateSpec.main, main, container, options.depths || [], data, blockParams);
|
||||||
main = executeDecorators(
|
|
||||||
templateSpec.main,
|
|
||||||
main,
|
|
||||||
container,
|
|
||||||
options.depths || [],
|
|
||||||
data,
|
|
||||||
blockParams
|
|
||||||
);
|
|
||||||
return main(context, options);
|
return main(context, options);
|
||||||
}
|
}
|
||||||
|
|
||||||
ret.isTop = true;
|
ret.isTop = true;
|
||||||
|
|
||||||
ret._setup = function(options) {
|
ret._setup = function(options) {
|
||||||
if (!options.partial) {
|
if (!options.partial) {
|
||||||
let mergedHelpers = Utils.extend({}, env.helpers, options.helpers);
|
container.helpers = extend({}, env.helpers, options.helpers);
|
||||||
wrapHelpersToPassLookupProperty(mergedHelpers, container);
|
|
||||||
container.helpers = mergedHelpers;
|
|
||||||
|
|
||||||
if (templateSpec.usePartial) {
|
if (templateSpec.usePartial) {
|
||||||
// Use mergeIfNeeded here to prevent compiling global partials multiple times
|
container.partials = extend({}, env.partials, options.partials);
|
||||||
container.partials = container.mergeIfNeeded(
|
|
||||||
options.partials,
|
|
||||||
env.partials
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
if (templateSpec.usePartial || templateSpec.useDecorators) {
|
if (templateSpec.usePartial || templateSpec.useDecorators) {
|
||||||
container.decorators = Utils.extend(
|
container.decorators = extend({}, env.decorators, options.decorators);
|
||||||
{},
|
|
||||||
env.decorators,
|
|
||||||
options.decorators
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
container.hooks = {};
|
container.hooks = {};
|
||||||
container.protoAccessControl = createProtoAccessControl(options);
|
|
||||||
|
|
||||||
let keepHelperInHelpers =
|
let keepHelperInHelpers = options.allowCallsToHelperMissing || templateWasPrecompiledWithCompilerV7;
|
||||||
options.allowCallsToHelperMissing ||
|
|
||||||
templateWasPrecompiledWithCompilerV7;
|
|
||||||
moveHelperToHooks(container, 'helperMissing', keepHelperInHelpers);
|
moveHelperToHooks(container, 'helperMissing', keepHelperInHelpers);
|
||||||
moveHelperToHooks(container, 'blockHelperMissing', keepHelperInHelpers);
|
moveHelperToHooks(container, 'blockHelperMissing', keepHelperInHelpers);
|
||||||
|
|
||||||
} else {
|
} else {
|
||||||
container.protoAccessControl = options.protoAccessControl; // internal option
|
|
||||||
container.helpers = options.helpers;
|
container.helpers = options.helpers;
|
||||||
container.partials = options.partials;
|
container.partials = options.partials;
|
||||||
container.decorators = options.decorators;
|
container.decorators = options.decorators;
|
||||||
container.hooks = options.hooks;
|
container.hooks = options.hooks;
|
||||||
}
|
}
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
||||||
ret._child = function(i, data, blockParams, depths) {
|
ret._child = function(i, data, blockParams, depths) {
|
||||||
@@ -298,47 +190,24 @@ export function template(templateSpec, env) {
|
|||||||
throw new Exception('must pass parent depths');
|
throw new Exception('must pass parent depths');
|
||||||
}
|
}
|
||||||
|
|
||||||
return wrapProgram(
|
return wrapProgram(container, i, templateSpec[i], data, 0, blockParams, depths);
|
||||||
container,
|
|
||||||
i,
|
|
||||||
templateSpec[i],
|
|
||||||
data,
|
|
||||||
0,
|
|
||||||
blockParams,
|
|
||||||
depths
|
|
||||||
);
|
|
||||||
};
|
};
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
export function wrapProgram(
|
export function wrapProgram(container, i, fn, data, declaredBlockParams, blockParams, depths) {
|
||||||
container,
|
|
||||||
i,
|
|
||||||
fn,
|
|
||||||
data,
|
|
||||||
declaredBlockParams,
|
|
||||||
blockParams,
|
|
||||||
depths
|
|
||||||
) {
|
|
||||||
function prog(context, options = {}) {
|
function prog(context, options = {}) {
|
||||||
let currentDepths = depths;
|
let currentDepths = depths;
|
||||||
if (
|
if (depths && context != depths[0] && !(context === container.nullContext && depths[0] === null)) {
|
||||||
depths &&
|
|
||||||
context != depths[0] &&
|
|
||||||
!(context === container.nullContext && depths[0] === null)
|
|
||||||
) {
|
|
||||||
currentDepths = [context].concat(depths);
|
currentDepths = [context].concat(depths);
|
||||||
}
|
}
|
||||||
|
|
||||||
return fn(
|
return fn(container,
|
||||||
container,
|
context,
|
||||||
context,
|
container.helpers, container.partials,
|
||||||
container.helpers,
|
options.data || data,
|
||||||
container.partials,
|
blockParams && [options.blockParams].concat(blockParams),
|
||||||
options.data || data,
|
currentDepths);
|
||||||
blockParams && [options.blockParams].concat(blockParams),
|
|
||||||
currentDepths
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
prog = executeDecorators(fn, prog, container, depths, data, blockParams);
|
prog = executeDecorators(fn, prog, container, depths, data, blockParams);
|
||||||
@@ -380,10 +249,8 @@ export function invokePartial(partial, context, options) {
|
|||||||
options.data = createFrame(options.data);
|
options.data = createFrame(options.data);
|
||||||
// Wrapper function to get access to currentPartialBlock from the closure
|
// Wrapper function to get access to currentPartialBlock from the closure
|
||||||
let fn = options.fn;
|
let fn = options.fn;
|
||||||
partialBlock = options.data['partial-block'] = function partialBlockWrapper(
|
partialBlock = options.data['partial-block'] = function partialBlockWrapper(context, options = {}) {
|
||||||
context,
|
|
||||||
options = {}
|
|
||||||
) {
|
|
||||||
// Restore the partial-block from the closure for the execution of the block
|
// Restore the partial-block from the closure for the execution of the block
|
||||||
// i.e. the part inside the block of the partial call.
|
// i.e. the part inside the block of the partial call.
|
||||||
options.data = createFrame(options.data);
|
options.data = createFrame(options.data);
|
||||||
@@ -391,7 +258,7 @@ export function invokePartial(partial, context, options) {
|
|||||||
return fn(context, options);
|
return fn(context, options);
|
||||||
};
|
};
|
||||||
if (fn.partials) {
|
if (fn.partials) {
|
||||||
options.partials = Utils.extend({}, options.partials, fn.partials);
|
options.partials = extend({}, options.partials, fn.partials);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -406,9 +273,7 @@ export function invokePartial(partial, context, options) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
export function noop() {
|
export function noop() { return ''; }
|
||||||
return '';
|
|
||||||
}
|
|
||||||
|
|
||||||
function initData(context, data) {
|
function initData(context, data) {
|
||||||
if (!data || !('root' in data)) {
|
if (!data || !('root' in data)) {
|
||||||
@@ -421,30 +286,8 @@ function initData(context, data) {
|
|||||||
function executeDecorators(fn, prog, container, depths, data, blockParams) {
|
function executeDecorators(fn, prog, container, depths, data, blockParams) {
|
||||||
if (fn.decorator) {
|
if (fn.decorator) {
|
||||||
let props = {};
|
let props = {};
|
||||||
prog = fn.decorator(
|
prog = fn.decorator(prog, props, container, depths && depths[0], data, blockParams, depths);
|
||||||
prog,
|
extend(prog, props);
|
||||||
props,
|
|
||||||
container,
|
|
||||||
depths && depths[0],
|
|
||||||
data,
|
|
||||||
blockParams,
|
|
||||||
depths
|
|
||||||
);
|
|
||||||
Utils.extend(prog, props);
|
|
||||||
}
|
}
|
||||||
return prog;
|
return prog;
|
||||||
}
|
}
|
||||||
|
|
||||||
function wrapHelpersToPassLookupProperty(mergedHelpers, container) {
|
|
||||||
Object.keys(mergedHelpers).forEach(helperName => {
|
|
||||||
let helper = mergedHelpers[helperName];
|
|
||||||
mergedHelpers[helperName] = passLookupPropertyOption(helper, container);
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
function passLookupPropertyOption(helper, container) {
|
|
||||||
const lookupProperty = container.lookupProperty;
|
|
||||||
return wrapHelper(helper, options => {
|
|
||||||
return Utils.extend({ lookupProperty }, options);
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|||||||
+25
-25
@@ -1,3 +1,4 @@
|
|||||||
|
|
||||||
const escape = {
|
const escape = {
|
||||||
'&': '&',
|
'&': '&',
|
||||||
'<': '<',
|
'<': '<',
|
||||||
@@ -9,13 +10,13 @@ const escape = {
|
|||||||
};
|
};
|
||||||
|
|
||||||
const badChars = /[&<>"'`=]/g,
|
const badChars = /[&<>"'`=]/g,
|
||||||
possible = /[&<>"'`=]/;
|
possible = /[&<>"'`=]/;
|
||||||
|
|
||||||
function escapeChar(chr) {
|
function escapeChar(chr) {
|
||||||
return escape[chr];
|
return escape[chr];
|
||||||
}
|
}
|
||||||
|
|
||||||
export function extend(obj /* , ...source */) {
|
export function extend(obj/* , ...source */) {
|
||||||
for (let i = 1; i < arguments.length; i++) {
|
for (let i = 1; i < arguments.length; i++) {
|
||||||
for (let key in arguments[i]) {
|
for (let key in arguments[i]) {
|
||||||
if (Object.prototype.hasOwnProperty.call(arguments[i], key)) {
|
if (Object.prototype.hasOwnProperty.call(arguments[i], key)) {
|
||||||
@@ -32,30 +33,28 @@ export let toString = Object.prototype.toString;
|
|||||||
// Sourced from lodash
|
// Sourced from lodash
|
||||||
// https://github.com/bestiejs/lodash/blob/master/LICENSE.txt
|
// https://github.com/bestiejs/lodash/blob/master/LICENSE.txt
|
||||||
/* eslint-disable func-style */
|
/* eslint-disable func-style */
|
||||||
let isFunction = function(value) {
|
export const isFunction = createIsFunction();
|
||||||
return typeof value === 'function';
|
|
||||||
};
|
|
||||||
// fallback for older versions of Chrome and Safari
|
function createIsFunction() {
|
||||||
/* istanbul ignore next */
|
// istanbul ignore next
|
||||||
if (isFunction(/x/)) {
|
// eslint-disable-next-line no-constant-condition
|
||||||
isFunction = function(value) {
|
if (typeof /x/ === 'function') {
|
||||||
return (
|
// fallback for older chrome/firefox versions
|
||||||
typeof value === 'function' &&
|
return function isFunction(value) {
|
||||||
toString.call(value) === '[object Function]'
|
return typeof value === 'function' && toString.call(value) === '[object Function]';
|
||||||
);
|
};
|
||||||
|
}
|
||||||
|
return function isFunction(value) {
|
||||||
|
return typeof value === 'function';
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
export { isFunction };
|
|
||||||
/* eslint-enable func-style */
|
|
||||||
|
|
||||||
/* istanbul ignore next */
|
/* istanbul ignore next */
|
||||||
export const isArray =
|
export const isArray = Array.isArray || function(value) {
|
||||||
Array.isArray ||
|
return (value && typeof value === 'object') ? toString.call(value) === '[object Array]' : false;
|
||||||
function(value) {
|
};
|
||||||
return value && typeof value === 'object'
|
|
||||||
? toString.call(value) === '[object Array]'
|
|
||||||
: false;
|
|
||||||
};
|
|
||||||
|
|
||||||
// Older IE versions do not directly support indexOf so we must implement our own, sadly.
|
// Older IE versions do not directly support indexOf so we must implement our own, sadly.
|
||||||
export function indexOf(array, value) {
|
export function indexOf(array, value) {
|
||||||
@@ -67,6 +66,8 @@ export function indexOf(array, value) {
|
|||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
export function escapeExpression(string) {
|
export function escapeExpression(string) {
|
||||||
if (typeof string !== 'string') {
|
if (typeof string !== 'string') {
|
||||||
// don't escape SafeStrings, since they're already safe
|
// don't escape SafeStrings, since they're already safe
|
||||||
@@ -84,12 +85,11 @@ export function escapeExpression(string) {
|
|||||||
string = '' + string;
|
string = '' + string;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!possible.test(string)) {
|
if (!possible.test(string)) { return string; }
|
||||||
return string;
|
|
||||||
}
|
|
||||||
return string.replace(badChars, escapeChar);
|
return string.replace(badChars, escapeChar);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
export function isEmpty(value) {
|
export function isEmpty(value) {
|
||||||
if (!value && value !== 0) {
|
if (!value && value !== 0) {
|
||||||
return true;
|
return true;
|
||||||
|
|||||||
+80
-122
@@ -1,9 +1,10 @@
|
|||||||
/* eslint-disable no-console */
|
/* eslint-disable no-console */
|
||||||
import Async from 'neo-async';
|
import Async from 'neo-async';
|
||||||
import fs from 'fs';
|
import fs from 'fs';
|
||||||
import * as Handlebars from './handlebars';
|
import Handlebars from './handlebars';
|
||||||
import { basename } from 'path';
|
import {basename} from 'path';
|
||||||
import { SourceMapConsumer, SourceNode } from 'source-map';
|
import {SourceMapConsumer, SourceNode} from 'source-map';
|
||||||
|
|
||||||
|
|
||||||
module.exports.loadTemplates = function(opts, callback) {
|
module.exports.loadTemplates = function(opts, callback) {
|
||||||
loadStrings(opts, function(err, strings) {
|
loadStrings(opts, function(err, strings) {
|
||||||
@@ -24,19 +25,14 @@ module.exports.loadTemplates = function(opts, callback) {
|
|||||||
|
|
||||||
function loadStrings(opts, callback) {
|
function loadStrings(opts, callback) {
|
||||||
let strings = arrayCast(opts.string),
|
let strings = arrayCast(opts.string),
|
||||||
names = arrayCast(opts.name);
|
names = arrayCast(opts.name);
|
||||||
|
|
||||||
if (names.length !== strings.length && strings.length > 1) {
|
if (names.length !== strings.length
|
||||||
return callback(
|
&& strings.length > 1) {
|
||||||
new Handlebars.Exception(
|
return callback(new Handlebars.Exception('Number of names did not match the number of string inputs'));
|
||||||
'Number of names did not match the number of string inputs'
|
|
||||||
)
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
Async.map(
|
Async.map(strings, function(string, callback) {
|
||||||
strings,
|
|
||||||
function(string, callback) {
|
|
||||||
if (string !== '-') {
|
if (string !== '-') {
|
||||||
callback(undefined, string);
|
callback(undefined, string);
|
||||||
} else {
|
} else {
|
||||||
@@ -59,94 +55,80 @@ function loadStrings(opts, callback) {
|
|||||||
source: string
|
source: string
|
||||||
}));
|
}));
|
||||||
callback(err, strings);
|
callback(err, strings);
|
||||||
}
|
});
|
||||||
);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
function loadFiles(opts, callback) {
|
function loadFiles(opts, callback) {
|
||||||
// Build file extension pattern
|
// Build file extension pattern
|
||||||
let extension = (opts.extension || 'handlebars').replace(
|
let extension = (opts.extension || 'handlebars').replace(/[\\^$*+?.():=!|{}\-[\]]/g, function(arg) { return '\\' + arg; });
|
||||||
/[\\^$*+?.():=!|{}\-[\]]/g,
|
|
||||||
function(arg) {
|
|
||||||
return '\\' + arg;
|
|
||||||
}
|
|
||||||
);
|
|
||||||
extension = new RegExp('\\.' + extension + '$');
|
extension = new RegExp('\\.' + extension + '$');
|
||||||
|
|
||||||
let ret = [],
|
let ret = [],
|
||||||
queue = (opts.files || []).map(template => ({ template, root: opts.root }));
|
queue = (opts.files || []).map((template) => ({template, root: opts.root}));
|
||||||
Async.whilst(
|
Async.whilst(() => queue.length, function(callback) {
|
||||||
() => queue.length,
|
let {template: path, root} = queue.shift();
|
||||||
function(callback) {
|
|
||||||
let { template: path, root } = queue.shift();
|
|
||||||
|
|
||||||
fs.stat(path, function(err, stat) {
|
fs.stat(path, function(err, stat) {
|
||||||
if (err) {
|
|
||||||
return callback(
|
|
||||||
new Handlebars.Exception(`Unable to open template file "${path}"`)
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (stat.isDirectory()) {
|
|
||||||
opts.hasDirectory = true;
|
|
||||||
|
|
||||||
fs.readdir(path, function(err, children) {
|
|
||||||
/* istanbul ignore next : Race condition that being too lazy to test */
|
|
||||||
if (err) {
|
|
||||||
return callback(err);
|
|
||||||
}
|
|
||||||
children.forEach(function(file) {
|
|
||||||
let childPath = path + '/' + file;
|
|
||||||
|
|
||||||
if (
|
|
||||||
extension.test(childPath) ||
|
|
||||||
fs.statSync(childPath).isDirectory()
|
|
||||||
) {
|
|
||||||
queue.push({ template: childPath, root: root || path });
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
callback();
|
|
||||||
});
|
|
||||||
} else {
|
|
||||||
fs.readFile(path, 'utf8', function(err, data) {
|
|
||||||
/* istanbul ignore next : Race condition that being too lazy to test */
|
|
||||||
if (err) {
|
|
||||||
return callback(err);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (opts.bom && data.indexOf('\uFEFF') === 0) {
|
|
||||||
data = data.substring(1);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Clean the template name
|
|
||||||
let name = path;
|
|
||||||
if (!root) {
|
|
||||||
name = basename(name);
|
|
||||||
} else if (name.indexOf(root) === 0) {
|
|
||||||
name = name.substring(root.length + 1);
|
|
||||||
}
|
|
||||||
name = name.replace(extension, '');
|
|
||||||
|
|
||||||
ret.push({
|
|
||||||
path: path,
|
|
||||||
name: name,
|
|
||||||
source: data
|
|
||||||
});
|
|
||||||
|
|
||||||
callback();
|
|
||||||
});
|
|
||||||
}
|
|
||||||
});
|
|
||||||
},
|
|
||||||
function(err) {
|
|
||||||
if (err) {
|
if (err) {
|
||||||
callback(err);
|
return callback(new Handlebars.Exception(`Unable to open template file "${path}"`));
|
||||||
} else {
|
|
||||||
callback(undefined, ret);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (stat.isDirectory()) {
|
||||||
|
opts.hasDirectory = true;
|
||||||
|
|
||||||
|
fs.readdir(path, function(err, children) {
|
||||||
|
/* istanbul ignore next : Race condition that being too lazy to test */
|
||||||
|
if (err) {
|
||||||
|
return callback(err);
|
||||||
|
}
|
||||||
|
children.forEach(function(file) {
|
||||||
|
let childPath = path + '/' + file;
|
||||||
|
|
||||||
|
if (extension.test(childPath) || fs.statSync(childPath).isDirectory()) {
|
||||||
|
queue.push({template: childPath, root: root || path});
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
callback();
|
||||||
|
});
|
||||||
|
} else {
|
||||||
|
fs.readFile(path, 'utf8', function(err, data) {
|
||||||
|
/* istanbul ignore next : Race condition that being too lazy to test */
|
||||||
|
if (err) {
|
||||||
|
return callback(err);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (opts.bom && data.indexOf('\uFEFF') === 0) {
|
||||||
|
data = data.substring(1);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Clean the template name
|
||||||
|
let name = path;
|
||||||
|
if (!root) {
|
||||||
|
name = basename(name);
|
||||||
|
} else if (name.indexOf(root) === 0) {
|
||||||
|
name = name.substring(root.length + 1);
|
||||||
|
}
|
||||||
|
name = name.replace(extension, '');
|
||||||
|
|
||||||
|
ret.push({
|
||||||
|
path: path,
|
||||||
|
name: name,
|
||||||
|
source: data
|
||||||
|
});
|
||||||
|
|
||||||
|
callback();
|
||||||
|
});
|
||||||
|
}
|
||||||
|
});
|
||||||
|
},
|
||||||
|
function(err) {
|
||||||
|
if (err) {
|
||||||
|
callback(err);
|
||||||
|
} else {
|
||||||
|
callback(undefined, ret);
|
||||||
}
|
}
|
||||||
);
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
module.exports.cli = function(opts) {
|
module.exports.cli = function(opts) {
|
||||||
@@ -156,9 +138,7 @@ module.exports.cli = function(opts) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (!opts.templates.length && !opts.hasDirectory) {
|
if (!opts.templates.length && !opts.hasDirectory) {
|
||||||
throw new Handlebars.Exception(
|
throw new Handlebars.Exception('Must define at least one template or directory.');
|
||||||
'Must define at least one template or directory.'
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (opts.simple && opts.min) {
|
if (opts.simple && opts.min) {
|
||||||
@@ -167,18 +147,12 @@ module.exports.cli = function(opts) {
|
|||||||
|
|
||||||
const multiple = opts.templates.length !== 1 || opts.hasDirectory;
|
const multiple = opts.templates.length !== 1 || opts.hasDirectory;
|
||||||
if (opts.simple && multiple) {
|
if (opts.simple && multiple) {
|
||||||
throw new Handlebars.Exception(
|
throw new Handlebars.Exception('Unable to output multiple templates in simple mode');
|
||||||
'Unable to output multiple templates in simple mode'
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Force simple mode if we have only one template and it's unnamed.
|
// Force simple mode if we have only one template and it's unnamed.
|
||||||
if (
|
if (!opts.amd && !opts.commonjs && opts.templates.length === 1
|
||||||
!opts.amd &&
|
&& !opts.templates[0].name) {
|
||||||
!opts.commonjs &&
|
|
||||||
opts.templates.length === 1 &&
|
|
||||||
!opts.templates[0].name
|
|
||||||
) {
|
|
||||||
opts.simple = true;
|
opts.simple = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -198,11 +172,7 @@ module.exports.cli = function(opts) {
|
|||||||
let output = new SourceNode();
|
let output = new SourceNode();
|
||||||
if (!opts.simple) {
|
if (!opts.simple) {
|
||||||
if (opts.amd) {
|
if (opts.amd) {
|
||||||
output.add(
|
output.add('define([\'' + opts.handlebarPath + 'handlebars.runtime\'], function(Handlebars) {\n Handlebars = Handlebars["default"];');
|
||||||
"define(['" +
|
|
||||||
opts.handlebarPath +
|
|
||||||
'handlebars.runtime\'], function(Handlebars) {\n Handlebars = Handlebars["default"];'
|
|
||||||
);
|
|
||||||
} else if (opts.commonjs) {
|
} else if (opts.commonjs) {
|
||||||
output.add('var Handlebars = require("' + opts.commonjs + '");');
|
output.add('var Handlebars = require("' + opts.commonjs + '");');
|
||||||
} else {
|
} else {
|
||||||
@@ -236,10 +206,7 @@ module.exports.cli = function(opts) {
|
|||||||
// If we are generating a source map, we have to reconstruct the SourceNode object
|
// If we are generating a source map, we have to reconstruct the SourceNode object
|
||||||
if (opts.map) {
|
if (opts.map) {
|
||||||
let consumer = new SourceMapConsumer(precompiled.map);
|
let consumer = new SourceMapConsumer(precompiled.map);
|
||||||
precompiled = SourceNode.fromStringWithSourceMap(
|
precompiled = SourceNode.fromStringWithSourceMap(precompiled.code, consumer);
|
||||||
precompiled.code,
|
|
||||||
consumer
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (opts.simple) {
|
if (opts.simple) {
|
||||||
@@ -252,14 +219,7 @@ module.exports.cli = function(opts) {
|
|||||||
if (opts.amd && !multiple) {
|
if (opts.amd && !multiple) {
|
||||||
output.add('return ');
|
output.add('return ');
|
||||||
}
|
}
|
||||||
output.add([
|
output.add([objectName, '[\'', template.name, '\'] = template(', precompiled, ');\n']);
|
||||||
objectName,
|
|
||||||
"['",
|
|
||||||
template.name,
|
|
||||||
"'] = template(",
|
|
||||||
precompiled,
|
|
||||||
');\n'
|
|
||||||
]);
|
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
@@ -326,9 +286,7 @@ function minify(output, sourceMapFile) {
|
|||||||
throw e;
|
throw e;
|
||||||
}
|
}
|
||||||
// it does not exist!
|
// it does not exist!
|
||||||
console.error(
|
console.error('Code minimization is disabled due to missing uglify-js dependency');
|
||||||
'Code minimization is disabled due to missing uglify-js dependency'
|
|
||||||
);
|
|
||||||
return output;
|
return output;
|
||||||
}
|
}
|
||||||
return require('uglify-js').minify(output.code, {
|
return require('uglify-js').minify(output.code, {
|
||||||
|
|||||||
@@ -1,9 +0,0 @@
|
|||||||
module.exports = {
|
|
||||||
'check-coverage': true,
|
|
||||||
branches: 100,
|
|
||||||
lines: 100,
|
|
||||||
functions: 100,
|
|
||||||
statements: 100,
|
|
||||||
exclude: ['**/spec/**', '**/handlebars/compiler/parser.js'],
|
|
||||||
reporter: 'html'
|
|
||||||
};
|
|
||||||
Generated
+8504
-7314
File diff suppressed because it is too large
Load Diff
+21
-54
@@ -1,7 +1,7 @@
|
|||||||
{
|
{
|
||||||
"name": "handlebars",
|
"name": "handlebars",
|
||||||
"barename": "handlebars",
|
"barename": "handlebars",
|
||||||
"version": "4.7.6",
|
"version": "4.5.3",
|
||||||
"description": "Handlebars provides the power necessary to let you build semantic templates effectively with no frustration",
|
"description": "Handlebars provides the power necessary to let you build semantic templates effectively with no frustration",
|
||||||
"homepage": "http://www.handlebarsjs.com/",
|
"homepage": "http://www.handlebarsjs.com/",
|
||||||
"keywords": [
|
"keywords": [
|
||||||
@@ -21,64 +21,54 @@
|
|||||||
"node": ">=0.4.7"
|
"node": ">=0.4.7"
|
||||||
},
|
},
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"minimist": "^1.2.5",
|
|
||||||
"neo-async": "^2.6.0",
|
"neo-async": "^2.6.0",
|
||||||
"source-map": "^0.6.1",
|
"optimist": "^0.6.1",
|
||||||
"wordwrap": "^1.0.0"
|
"source-map": "^0.6.1"
|
||||||
},
|
},
|
||||||
"optionalDependencies": {
|
"optionalDependencies": {
|
||||||
"uglify-js": "^3.1.4"
|
"uglify-js": "^3.1.4"
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
|
"@babel/core": "^7.7.4",
|
||||||
|
"@babel/plugin-transform-modules-amd": "^7.7.4",
|
||||||
|
"@babel/plugin-transform-modules-commonjs": "^7.7.4",
|
||||||
|
"@babel/plugin-transform-runtime": "^7.7.4",
|
||||||
|
"@babel/preset-env": "^7.7.4",
|
||||||
|
"@babel/runtime": "^7.7.4",
|
||||||
"@knappi/grunt-saucelabs": "^9.0.2",
|
"@knappi/grunt-saucelabs": "^9.0.2",
|
||||||
"aws-sdk": "^2.1.49",
|
"aws-sdk": "^2.1.49",
|
||||||
"babel-loader": "^5.0.0",
|
"babel-loader": "^8.0.6",
|
||||||
"babel-runtime": "^5.1.10",
|
"babel-plugin-add-module-exports": "^1.0.2",
|
||||||
"benchmark": "~1.0",
|
"benchmark": "~1.0",
|
||||||
"chai": "^4.2.0",
|
"chai": "^4.2.0",
|
||||||
"chai-diff": "^1.0.1",
|
|
||||||
"concurrently": "^5.0.0",
|
|
||||||
"dirty-chai": "^2.0.1",
|
"dirty-chai": "^2.0.1",
|
||||||
"dtslint": "^0.5.5",
|
"dtslint": "^0.5.5",
|
||||||
"dustjs-linkedin": "^2.0.2",
|
"dustjs-linkedin": "^2.0.2",
|
||||||
"eco": "~1.1.0-rc-3",
|
"eco": "~1.1.0-rc-3",
|
||||||
"eslint": "^6.7.2",
|
|
||||||
"eslint-config-prettier": "^6.7.0",
|
|
||||||
"eslint-plugin-compat": "^3.3.0",
|
"eslint-plugin-compat": "^3.3.0",
|
||||||
"eslint-plugin-es5": "^1.4.1",
|
"eslint-plugin-es5": "^1.4.1",
|
||||||
"fs-extra": "^8.1.0",
|
|
||||||
"grunt": "^1.0.4",
|
"grunt": "^1.0.4",
|
||||||
"grunt-babel": "^5.0.0",
|
"grunt-babel": "^8.0.0",
|
||||||
"grunt-bg-shell": "^2.3.3",
|
"grunt-bg-shell": "^2.3.3",
|
||||||
"grunt-cli": "^1",
|
"grunt-cli": "^1",
|
||||||
"grunt-contrib-clean": "^1",
|
"grunt-contrib-clean": "^1",
|
||||||
"grunt-contrib-concat": "^1",
|
"grunt-contrib-concat": "^1",
|
||||||
"grunt-contrib-connect": "^1",
|
"grunt-contrib-connect": "^1",
|
||||||
"grunt-contrib-copy": "^1",
|
"grunt-contrib-copy": "^1",
|
||||||
"grunt-contrib-requirejs": "^1",
|
|
||||||
"grunt-contrib-uglify": "^1",
|
|
||||||
"grunt-contrib-watch": "^1.1.0",
|
"grunt-contrib-watch": "^1.1.0",
|
||||||
"grunt-karma": "^4.0.0",
|
"grunt-eslint": "^20.1.0",
|
||||||
"grunt-webpack": "^1.0.8",
|
"grunt-webpack": "^3.1.3",
|
||||||
"husky": "^3.1.0",
|
"istanbul": "^0.3.0",
|
||||||
"jison": "~0.3.0",
|
"jison": "~0.3.0",
|
||||||
"karma": "^5.0.5",
|
|
||||||
"karma-chrome-launcher": "^3.1.0",
|
|
||||||
"karma-mocha": "^2.0.1",
|
|
||||||
"karma-requirejs": "^1.1.0",
|
|
||||||
"karma-sauce-launcher": "^4.1.4",
|
|
||||||
"lint-staged": "^9.5.0",
|
|
||||||
"mocha": "^5",
|
"mocha": "^5",
|
||||||
"mock-stdin": "^0.3.0",
|
"mock-stdin": "^0.3.0",
|
||||||
"mustache": "^2.1.3",
|
"mustache": "^2.1.3",
|
||||||
"nyc": "^14.1.1",
|
|
||||||
"prettier": "^1.19.1",
|
|
||||||
"semver": "^5.0.1",
|
"semver": "^5.0.1",
|
||||||
"sinon": "^7.5.0",
|
"sinon": "^7.5.0",
|
||||||
"typescript": "^3.4.3",
|
"typescript": "^3.4.3",
|
||||||
"underscore": "^1.5.1",
|
"underscore": "^1.5.1",
|
||||||
"webpack": "^1.12.6",
|
"webpack": "^4.41.2",
|
||||||
"webpack-dev-server": "^1.12.1"
|
"webpack-dev-server": "^3.9.0"
|
||||||
},
|
},
|
||||||
"main": "lib/index.js",
|
"main": "lib/index.js",
|
||||||
"types": "types/index.d.ts",
|
"types": "types/index.d.ts",
|
||||||
@@ -90,15 +80,8 @@
|
|||||||
"handlebars": "bin/handlebars"
|
"handlebars": "bin/handlebars"
|
||||||
},
|
},
|
||||||
"scripts": {
|
"scripts": {
|
||||||
"format": "prettier --write '**/*.js' && eslint --fix .",
|
"checkTypes": "dtslint types",
|
||||||
"check-format": "prettier --check '**/*.js'",
|
"test": "grunt"
|
||||||
"lint": "eslint --max-warnings 0 .",
|
|
||||||
"dtslint": "dtslint types",
|
|
||||||
"test": "grunt",
|
|
||||||
"extensive-tests-and-publish-to-aws": "npx mocha tasks/task-tests/ && grunt --stack extensive-tests-and-publish-to-aws",
|
|
||||||
"integration-test": "grunt integration-tests",
|
|
||||||
"--- combined tasks ---": "",
|
|
||||||
"check-before-pull-request": "concurrently --kill-others-on-fail npm:lint npm:dtslint npm:check-format npm:test"
|
|
||||||
},
|
},
|
||||||
"jspm": {
|
"jspm": {
|
||||||
"main": "handlebars",
|
"main": "handlebars",
|
||||||
@@ -118,22 +101,6 @@
|
|||||||
"print-script",
|
"print-script",
|
||||||
"release-notes.md",
|
"release-notes.md",
|
||||||
"runtime.js",
|
"runtime.js",
|
||||||
"types/*.d.ts",
|
"types/*.d.ts"
|
||||||
"runtime.d.ts"
|
]
|
||||||
],
|
|
||||||
"husky": {
|
|
||||||
"hooks": {
|
|
||||||
"pre-commit": "lint-staged"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"lint-staged": {
|
|
||||||
"*.{js,css,json,md}": [
|
|
||||||
"prettier --write",
|
|
||||||
"git add"
|
|
||||||
],
|
|
||||||
"*.js": [
|
|
||||||
"eslint --fix",
|
|
||||||
"git add"
|
|
||||||
]
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,5 +0,0 @@
|
|||||||
module.exports = {
|
|
||||||
tabWidth: 2,
|
|
||||||
semi: true,
|
|
||||||
singleQuote: true
|
|
||||||
};
|
|
||||||
+42
-236
@@ -2,154 +2,18 @@
|
|||||||
|
|
||||||
## Development
|
## Development
|
||||||
|
|
||||||
[Commits](https://github.com/wycats/handlebars.js/compare/v4.7.6...master)
|
[Commits](https://github.com/wycats/handlebars.js/compare/v4.5.3...master)
|
||||||
|
|
||||||
## v4.7.6 - April 3rd, 2020
|
|
||||||
|
|
||||||
Chore/Housekeeping:
|
|
||||||
|
|
||||||
- [#1672](https://github.com/wycats/handlebars.js/issues/1672) - Switch cmd parser to latest minimist ([@dougwilson](https://api.github.com/users/dougwilson)
|
|
||||||
|
|
||||||
Compatibility notes:
|
|
||||||
|
|
||||||
- Restored Node.js compatibility
|
|
||||||
|
|
||||||
[Commits](https://github.com/wycats/handlebars.js/compare/v4.7.5...v4.7.6)
|
|
||||||
|
|
||||||
## v4.7.5 - April 2nd, 2020
|
|
||||||
|
|
||||||
Chore/Housekeeping:
|
|
||||||
|
|
||||||
- ~Node.js version support has been changed to v6+~ Reverted in 4.7.6
|
|
||||||
|
|
||||||
Compatibility notes:
|
|
||||||
|
|
||||||
- ~Node.js < v6 is no longer supported~ Reverted in 4.7.6
|
|
||||||
|
|
||||||
[Commits](https://github.com/wycats/handlebars.js/compare/v4.7.4...v4.7.5)
|
|
||||||
|
|
||||||
## v4.7.4 - April 1st, 2020
|
|
||||||
|
|
||||||
Chore/Housekeeping:
|
|
||||||
|
|
||||||
- [#1666](https://github.com/wycats/handlebars.js/issues/1666) - Replaced minimist with yargs for handlebars CLI ([@aorinevo](https://api.github.com/users/aorinevo), [@AviVahl](https://api.github.com/users/AviVahl) & [@fabb](https://api.github.com/users/fabb))
|
|
||||||
|
|
||||||
Compatibility notes:
|
|
||||||
|
|
||||||
- No incompatibilities are to be expected
|
|
||||||
|
|
||||||
[Commits](https://github.com/wycats/handlebars.js/compare/v4.7.3...v4.7.4)
|
|
||||||
|
|
||||||
## v4.7.3 - February 5th, 2020
|
|
||||||
|
|
||||||
Chore/Housekeeping:
|
|
||||||
|
|
||||||
- [#1644](https://github.com/wycats/handlebars.js/issues/1644) - Download links to aws broken on handlebarsjs.com - access denied ([@Tea56](https://api.github.com/users/Tea56))
|
|
||||||
- Fix spelling and punctuation in changelog - d78cc73
|
|
||||||
|
|
||||||
Bugfixes:
|
|
||||||
|
|
||||||
- Add Type Definition for Handlebars.VERSION, Fixes #1647 - 4de51fe
|
|
||||||
- Include Type Definition for runtime.js in Package - a32d05f
|
|
||||||
|
|
||||||
Compatibility notes:
|
|
||||||
|
|
||||||
- No incompatibilities are to be expected
|
|
||||||
|
|
||||||
[Commits](https://github.com/wycats/handlebars.js/compare/v4.7.2...v4.7.3)
|
|
||||||
|
|
||||||
## v4.7.2 - January 13th, 2020
|
|
||||||
|
|
||||||
Bugfixes:
|
|
||||||
|
|
||||||
- fix: don't wrap helpers that are not functions - 9d5aa36, #1639
|
|
||||||
|
|
||||||
Chore/Build:
|
|
||||||
|
|
||||||
- chore: execute saucelabs-task only if access-key exists - a4fd391
|
|
||||||
|
|
||||||
Compatibility notes:
|
|
||||||
|
|
||||||
- No breaking changes are to be expected
|
|
||||||
|
|
||||||
[Commits](https://github.com/wycats/handlebars.js/compare/v4.7.1...v4.7.2)
|
|
||||||
|
|
||||||
## v4.7.1 - January 12th, 2020
|
|
||||||
|
|
||||||
Bugfixes:
|
|
||||||
|
|
||||||
- fix: fix log output in case of illegal property access - f152dfc
|
|
||||||
- fix: log error for illegal property access only once per property - 3c1e252
|
|
||||||
|
|
||||||
Compatibility notes:
|
|
||||||
|
|
||||||
- no incompatibilities are to be expected.
|
|
||||||
|
|
||||||
[Commits](https://github.com/wycats/handlebars.js/compare/v4.7.0...v4.7.1)
|
|
||||||
|
|
||||||
## v4.7.0 - January 10th, 2020
|
|
||||||
|
|
||||||
Features:
|
|
||||||
|
|
||||||
- feat: default options for controlling proto access - 7af1c12, #1635
|
|
||||||
- This makes it possible to disable the prototype access restrictions added in 4.6.0
|
|
||||||
- an error is logged in the console, if access to prototype properties is attempted and denied
|
|
||||||
and no explicit configuration has taken place.
|
|
||||||
|
|
||||||
Compatibility notes:
|
|
||||||
|
|
||||||
- no compatibilities are expected
|
|
||||||
|
|
||||||
[Commits](https://github.com/wycats/handlebars.js/compare/v4.6.0...v4.7.0)
|
|
||||||
|
|
||||||
## v4.6.0 - January 8th, 2020
|
|
||||||
|
|
||||||
Features:
|
|
||||||
|
|
||||||
- feat: access control to prototype properties via whitelist (#1633)- d03b6ec
|
|
||||||
|
|
||||||
Bugfixes:
|
|
||||||
|
|
||||||
- fix(runtime.js): partials compile not caching (#1600) - 23d58e7
|
|
||||||
|
|
||||||
Chores, docs:
|
|
||||||
|
|
||||||
- various refactorings and improvements to tests - d7f0dcf, 187d611, d337f40
|
|
||||||
- modernize the build-setup
|
|
||||||
- use prettier to format and eslint to verify - c40d9f3, 8901c28, e97685e, 1f61f21
|
|
||||||
- use nyc instead of istanbul to collect coverage - 164b7ff, 1ebce2b
|
|
||||||
- update build code to use modern javascript and make it cleaner - 14b621c, 1ec1737, 3a5b65e, dde108e, 04b1984, 587e7a3
|
|
||||||
- restructur build commands - e913dc5,
|
|
||||||
- eslint rule changes - ac4655e, dc54952
|
|
||||||
- Update (C) year in the LICENSE file - d1fb07b
|
|
||||||
- chore: try to fix saucelabs credentials (#1627) -
|
|
||||||
- Update readme.md with updated links (#1620) - edcc84f
|
|
||||||
|
|
||||||
BREAKING CHANGES:
|
|
||||||
|
|
||||||
- access to prototype properties is forbidden completely by default,
|
|
||||||
specific properties or methods can be allowed via runtime-options.
|
|
||||||
See #1633 for details.
|
|
||||||
If you are using Handlebars as documented, you should not be accessing prototype
|
|
||||||
properties from your template anyway, so the changes should not be a problem
|
|
||||||
for you. Only the use of undocumented features can break your build.
|
|
||||||
|
|
||||||
That is why we only bump the minor version despite mentioning breaking changes.
|
|
||||||
|
|
||||||
[Commits](https://github.com/wycats/handlebars.js/compare/v4.5.3...v4.6.0)
|
|
||||||
|
|
||||||
## v4.5.3 - November 18th, 2019
|
## v4.5.3 - November 18th, 2019
|
||||||
|
|
||||||
Bugfixes:
|
Bugfixes:
|
||||||
|
|
||||||
- fix: add "no-prototype-builtins" eslint-rule and fix all occurences - f7f05d7
|
- fix: add "no-prototype-builtins" eslint-rule and fix all occurences - f7f05d7
|
||||||
- fix: add more properties required to be enumerable - 1988878
|
- fix: add more properties required to be enumerable - 1988878
|
||||||
|
|
||||||
Chores / Build:
|
Chores / Build:
|
||||||
|
|
||||||
- fix: use !== 0 instead of != 0 - c02b05f
|
- fix: use !== 0 instead of != 0 - c02b05f
|
||||||
- add chai and dirty-chai and sinon, for cleaner test-assertions and spies,
|
- add chai and dirty-chai and sinon, for cleaner test-assertions and spies,
|
||||||
deprecate old assertion-methods - 93e284e, 886ba86, 0817dad, 93516a0
|
deprecate old assertion-methods - 93e284e, 886ba86, 0817dad, 93516a0
|
||||||
|
|
||||||
Security:
|
Security:
|
||||||
|
|
||||||
@@ -165,11 +29,11 @@ Compatibility notes:
|
|||||||
- Due to the security-fixes. The semantics of the templates using
|
- Due to the security-fixes. The semantics of the templates using
|
||||||
`__proto__`, `__defineGetter__`, `__defineSetter__` and `__lookupGetter__` in the respect that those expression now return
|
`__proto__`, `__defineGetter__`, `__defineSetter__` and `__lookupGetter__` in the respect that those expression now return
|
||||||
`undefined` rather than their actual value from the proto.
|
`undefined` rather than their actual value from the proto.
|
||||||
- The semantics have not changed in cases where the properties are enumerable, as in:
|
- The semantics have not changed in cases where the properties are enumerable, as in:
|
||||||
|
|
||||||
```js
|
```js
|
||||||
{
|
{
|
||||||
__proto__: 'some string';
|
__proto__: 'some string'
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
@@ -178,145 +42,133 @@ Compatibility notes:
|
|||||||
are not intended, undocumented and far less important than fixing
|
are not intended, undocumented and far less important than fixing
|
||||||
Remote-Code-Execution exploits on existing systems.
|
Remote-Code-Execution exploits on existing systems.
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
[Commits](https://github.com/wycats/handlebars.js/compare/v4.5.2...v4.5.3)
|
[Commits](https://github.com/wycats/handlebars.js/compare/v4.5.2...v4.5.3)
|
||||||
|
|
||||||
## v4.5.2 - November 13th, 2019
|
## v4.5.2 - November 13th, 2019
|
||||||
|
|
||||||
# Bugfixes
|
# Bugfixes
|
||||||
|
|
||||||
- fix: use String(field) in lookup when checking for "constructor" - d541378
|
- fix: use String(field) in lookup when checking for "constructor" - d541378
|
||||||
- test: add fluent API for testing Handlebars - c2ac79c
|
- test: add fluent API for testing Handlebars - c2ac79c
|
||||||
|
|
||||||
Compatibility notes:
|
Compatibility notes:
|
||||||
|
|
||||||
- no incompatibility are to be expected
|
- no incompatibility are to be expected
|
||||||
|
|
||||||
[Commits](https://github.com/wycats/handlebars.js/compare/v4.5.1...v4.5.2)
|
[Commits](https://github.com/wycats/handlebars.js/compare/v4.5.1...v4.5.2)
|
||||||
|
|
||||||
## v4.5.1 - October 29th, 2019
|
## v4.5.1 - October 29th, 2019
|
||||||
|
|
||||||
Bugfixs
|
Bugfixs
|
||||||
|
|
||||||
- fix: move "eslint-plugin-compat" to devDependencies - 5e9d17f (#1589)
|
- fix: move "eslint-plugin-compat" to devDependencies - 5e9d17f (#1589)
|
||||||
|
|
||||||
Compatibility notes:
|
Compatibility notes:
|
||||||
|
|
||||||
- No compatibility issues are to be expected
|
- No compatibility issues are to be expected
|
||||||
|
|
||||||
|
|
||||||
[Commits](https://github.com/wycats/handlebars.js/compare/v4.5.0...v4.5.1)
|
[Commits](https://github.com/wycats/handlebars.js/compare/v4.5.0...v4.5.1)
|
||||||
|
|
||||||
## v4.5.0 - October 28th, 2019
|
## v4.5.0 - October 28th, 2019
|
||||||
|
|
||||||
Features / Improvements
|
Features / Improvements
|
||||||
|
|
||||||
- Add method Handlebars.parseWithoutProcessing (#1584) - 62ed3c2
|
- Add method Handlebars.parseWithoutProcessing (#1584) - 62ed3c2
|
||||||
- add guard to if & unless helpers (#1549)
|
- add guard to if & unless helpers (#1549)
|
||||||
- show source location for the strict lookup exceptions - feb60f8
|
- show source location for the strict lookup exceptions - feb60f8
|
||||||
|
|
||||||
Bugfixes:
|
Bugfixes:
|
||||||
|
|
||||||
- Use objects for hash value tracking - 7fcf9d2
|
- Use objects for hash value tracking - 7fcf9d2
|
||||||
|
|
||||||
Chore:
|
Chore:
|
||||||
|
|
||||||
- Resolve deprecation warning message from eslint while running eslint (#1586) - 7052e88
|
- Resolve deprecation warning message from eslint while running eslint (#1586) - 7052e88
|
||||||
- chore: add eslint-plugin-compat and eslint-plugin-es5 - 088e618
|
- chore: add eslint-plugin-compat and eslint-plugin-es5 - 088e618
|
||||||
|
|
||||||
Compatibility notes:
|
Compatibility notes:
|
||||||
|
|
||||||
- No compatibility issues are to be expected
|
- No compatibility issues are to be expected
|
||||||
|
|
||||||
[Commits](https://github.com/wycats/handlebars.js/compare/v4.4.5...v4.5.0)
|
[Commits](https://github.com/wycats/handlebars.js/compare/v4.4.5...v4.5.0)
|
||||||
|
|
||||||
## v4.4.5 - October 20th, 2019
|
## v4.4.5 - October 20th, 2019
|
||||||
|
|
||||||
Bugfixes:
|
Bugfixes:
|
||||||
|
|
||||||
- Contents of raw-blocks must be matched with non-eager regex-matching - 8d5530e, #1579
|
- Contents of raw-blocks must be matched with non-eager regex-matching - 8d5530e, #1579
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
[Commits](https://github.com/wycats/handlebars.js/compare/v4.4.4...v4.4.5)
|
[Commits](https://github.com/wycats/handlebars.js/compare/v4.4.4...v4.4.5)
|
||||||
|
|
||||||
## v4.4.4 - October 20th, 2019
|
## v4.4.4 - October 20th, 2019
|
||||||
|
|
||||||
Bugfixes:
|
Bugfixes:
|
||||||
|
|
||||||
- fix: prevent zero length tokens in raw-blocks (#1577, #1578) - f1752fe
|
- fix: prevent zero length tokens in raw-blocks (#1577, #1578) - f1752fe
|
||||||
|
|
||||||
Chore:
|
Chore:
|
||||||
|
|
||||||
- chore: link to s3 bucket with https, add "npm ci" to build instructions - 0b593bf
|
- chore: link to s3 bucket with https, add "npm ci" to build instructions - 0b593bf
|
||||||
|
|
||||||
Compatibility notes:
|
Compatibility notes:
|
||||||
|
|
||||||
- no compatibility issues are expected
|
- no compatibility issues are expected
|
||||||
|
|
||||||
[Commits](https://github.com/wycats/handlebars.js/compare/v4.4.3...v4.4.4)
|
[Commits](https://github.com/wycats/handlebars.js/compare/v4.4.3...v4.4.4)
|
||||||
|
|
||||||
## v4.4.3 - October 8th, 2019
|
## v4.4.3 - October 8th, 2019
|
||||||
|
|
||||||
Bugfixes
|
Bugfixes
|
||||||
|
|
||||||
Typings:
|
Typings:
|
||||||
|
|
||||||
- add missing type fields to AST typings and add tests for them - 0440af2
|
- add missing type fields to AST typings and add tests for them - 0440af2
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
[Commits](https://github.com/wycats/handlebars.js/compare/v4.4.2...v4.4.3)
|
[Commits](https://github.com/wycats/handlebars.js/compare/v4.4.2...v4.4.3)
|
||||||
|
|
||||||
## v4.4.2 - October 2nd, 2019
|
## v4.4.2 - October 2nd, 2019
|
||||||
|
|
||||||
- chore: fix grunt-saucelabs dependency - b7eada0
|
- chore: fix grunt-saucelabs dependency - b7eada0
|
||||||
|
|
||||||
|
|
||||||
[Commits](https://github.com/wycats/handlebars.js/compare/v4.4.1...v4.4.2)
|
[Commits](https://github.com/wycats/handlebars.js/compare/v4.4.1...v4.4.2)
|
||||||
|
|
||||||
## v4.4.1 - October 2nd, 2019
|
## v4.4.1 - October 2nd, 2019
|
||||||
|
|
||||||
- [#1562](https://github.com/wycats/handlebars.js/issues/1562) - Error message for syntax error missing location in 4.2.1+
|
- [#1562](https://github.com/wycats/handlebars.js/issues/1562) - Error message for syntax error missing location in 4.2.1+
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
[Commits](https://github.com/wycats/handlebars.js/compare/v4.4.0...v4.4.1)
|
[Commits](https://github.com/wycats/handlebars.js/compare/v4.4.0...v4.4.1)
|
||||||
|
|
||||||
## v4.4.0 - September 29th, 2019
|
## v4.4.0 - September 29th, 2019
|
||||||
|
|
||||||
- Added support for iterable objects in {{#each}} helper (#1557) - cf7545e
|
- Added support for iterable objects in {{#each}} helper (#1557) - cf7545e
|
||||||
|
|
||||||
|
|
||||||
[Commits](https://github.com/wycats/handlebars.js/compare/v4.3.4...v4.4.0)
|
[Commits](https://github.com/wycats/handlebars.js/compare/v4.3.4...v4.4.0)
|
||||||
|
|
||||||
## v4.3.4 - September 28th, 2019
|
## v4.3.4 - September 28th, 2019
|
||||||
|
|
||||||
- fix: harden "propertyIsEnumerable"-check - ff4d827
|
- fix: harden "propertyIsEnumerable"-check - ff4d827
|
||||||
|
|
||||||
Compatibility notes:
|
Compatibility notes:
|
||||||
|
|
||||||
- No incompatibilities are known.
|
- No incompatibilities are known.
|
||||||
|
|
||||||
[Commits](https://github.com/wycats/handlebars.js/compare/v4.3.3...v4.3.4)
|
[Commits](https://github.com/wycats/handlebars.js/compare/v4.3.3...v4.3.4)
|
||||||
|
|
||||||
## v4.3.3 - September 27th, 2019
|
## v4.3.3 - September 27th, 2019
|
||||||
|
- fix test case for browsers that do not support __defineGetter__ - 8742bde
|
||||||
|
|
||||||
- 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)
|
[Commits](https://github.com/wycats/handlebars.js/compare/v4.3.2...v4.3.3)
|
||||||
|
|
||||||
## v4.3.2 - September 26th, 2019
|
## v4.3.2 - September 26th, 2019
|
||||||
|
|
||||||
- Use Object.prototype.propertyIsEnumerable to check for constructors - 213c0bb, #1563
|
- Use Object.prototype.propertyIsEnumerable to check for constructors - 213c0bb, #1563
|
||||||
|
|
||||||
Compatibility notes:
|
Compatibility notes:
|
||||||
|
|
||||||
- There are no breaking changes
|
- There are no breaking changes
|
||||||
|
|
||||||
[Commits](https://github.com/wycats/handlebars.js/compare/v4.3.1...v4.3.2)
|
[Commits](https://github.com/wycats/handlebars.js/compare/v4.3.1...v4.3.2)
|
||||||
|
|
||||||
## v4.3.1 - September 25th, 2019
|
## v4.3.1 - September 25th, 2019
|
||||||
|
|
||||||
Fixes:
|
Fixes:
|
||||||
|
|
||||||
- do not break on precompiled templates from Handlebars >=4.0.0 <4.3.0 - 1266838, #1561
|
- 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
|
- 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)
|
[Commits](https://github.com/wycats/handlebars.js/compare/v4.3.0...v4.3.1)
|
||||||
|
|
||||||
## v4.3.0 - September 24th, 2019
|
## v4.3.0 - September 24th, 2019
|
||||||
|
|
||||||
Fixes:
|
Fixes:
|
||||||
|
|
||||||
- Security: Disallow calling "helperMissing" and "blockHelperMissing" directly - 2078c72
|
- Security: Disallow calling "helperMissing" and "blockHelperMissing" directly - 2078c72
|
||||||
@@ -329,9 +181,7 @@ Features:
|
|||||||
Breaking changes:
|
Breaking changes:
|
||||||
|
|
||||||
Compatibility notes:
|
Compatibility notes:
|
||||||
|
|
||||||
- Compiler revision increased - 06b7224
|
- Compiler revision increased - 06b7224
|
||||||
|
|
||||||
- This means that template compiled with versions prior to 4.3.0 will not work with runtimes >= 4.3.0
|
- 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
|
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
|
to the internal "container.hooks" object, so old templates will not be able to call them anymore. We suggest
|
||||||
@@ -340,9 +190,9 @@ Compatibility notes:
|
|||||||
- Disallow calling "helperMissing" and "blockHelperMissing" directly - 2078c72
|
- Disallow calling "helperMissing" and "blockHelperMissing" directly - 2078c72
|
||||||
- Calling "helperMissing" and "blockHelperMissing" directly from a template (like in `{{blockHelperMissing}}` was
|
- 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
|
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
|
(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 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.
|
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
|
- If you really need this behavior, you can set the runtime option `allowCallsToHelperMissing` to `true` and the
|
||||||
calls will again be possible
|
calls will again be possible
|
||||||
|
|
||||||
@@ -350,64 +200,57 @@ Both bullet points imly that Handlebars is not 100% percent compatible to 4.2.0,
|
|||||||
|
|
||||||
We consider it more important to resolve a major security issue than to maintain 100% compatibility.
|
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)
|
[Commits](https://github.com/wycats/handlebars.js/compare/v4.2.1...v4.3.0)
|
||||||
|
|
||||||
## v4.2.1 - September 20th, 2019
|
## v4.2.1 - September 20th, 2019
|
||||||
|
|
||||||
Bugfixes:
|
Bugfixes:
|
||||||
|
|
||||||
- The "browser" property in the package.json has been updated to use the common-js builds instead of the minified UMD - c55a7be, #1553
|
- 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:
|
Compatibility notes:
|
||||||
|
|
||||||
- No compatibility issues should arise
|
- No compatibility issues should arise
|
||||||
|
|
||||||
[Commits](https://github.com/wycats/handlebars.js/compare/v4.2.0...v4.2.1)
|
[Commits](https://github.com/wycats/handlebars.js/compare/v4.2.0...v4.2.1)
|
||||||
|
|
||||||
## v4.2.0 - September 3rd, 2019
|
## v4.2.0 - September 3rd, 2019
|
||||||
|
|
||||||
Chore/Test:
|
Chore/Test:
|
||||||
|
|
||||||
- Use custom `grunt-saucelab` with current sauce-connect proxy - f119497
|
- Use custom `grunt-saucelab` with current sauce-connect proxy - f119497
|
||||||
- Add framework for various integration tests - f9cce4d
|
- Add framework for various integration tests - f9cce4d
|
||||||
- Add integration test for webpack - a57b682
|
- Add integration test for webpack - a57b682
|
||||||
|
|
||||||
Bugfixes:
|
|
||||||
|
|
||||||
|
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))
|
- [#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))
|
- [#1534](https://github.com/wycats/handlebars.js/pull/1534) - Add typings for "Handlebars.VM.resolvePartial ([@AndrewLeedham](https://api.github.com/users/AndrewLeedham))
|
||||||
|
|
||||||
Features:
|
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))
|
- [#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:
|
Compatibility notes:
|
||||||
|
|
||||||
- The new "browser"-property should not break anything, but you can never be sure. The integration test for webpack
|
- 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.
|
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)
|
[Commits](https://github.com/wycats/handlebars.js/compare/v4.1.2-0...v4.2.0)
|
||||||
|
|
||||||
## v4.1.2-0 - August 25th, 2019
|
## 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))
|
[#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:
|
Compatibility notes:
|
||||||
|
|
||||||
- We are not sure if imports via webpack are still working, which is why this release is a pre-release
|
- 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)
|
[Commits](https://github.com/wycats/handlebars.js/compare/v4.1.2...v4.1.2-0)
|
||||||
|
|
||||||
## v4.1.2 - April 13th, 2019
|
## v4.1.2 - April 13th, 2019
|
||||||
|
|
||||||
Chore/Test:
|
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))
|
- [#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
|
- chore: add missing typescript dependency, add package-lock.json - 594f1e3
|
||||||
- test: remove safari from saucelabs - 871accc
|
- test: remove safari from saucelabs - 871accc
|
||||||
|
|
||||||
Bugfixes:
|
Bugfixes:
|
||||||
|
|
||||||
- fix: prevent RCE through the "lookup"-helper - cd38583
|
- fix: prevent RCE through the "lookup"-helper - cd38583
|
||||||
|
|
||||||
Compatibility notes:
|
Compatibility notes:
|
||||||
@@ -423,24 +266,20 @@ and the issue may not be resolved on many systems).
|
|||||||
[Commits](https://github.com/wycats/handlebars.js/compare/v4.1.1...v4.1.2)
|
[Commits](https://github.com/wycats/handlebars.js/compare/v4.1.1...v4.1.2)
|
||||||
|
|
||||||
## v4.1.1 - March 16th, 2019
|
## v4.1.1 - March 16th, 2019
|
||||||
|
|
||||||
Bugfixes:
|
Bugfixes:
|
||||||
|
|
||||||
- fix: add "runtime.d.ts" to allow "require('handlebars/runtime')" in TypeScript - 5cedd62
|
- fix: add "runtime.d.ts" to allow "require('handlebars/runtime')" in TypeScript - 5cedd62
|
||||||
|
|
||||||
Refactorings:
|
Refactorings:
|
||||||
|
|
||||||
- replace "async" with "neo-async" - 048f2ce
|
- replace "async" with "neo-async" - 048f2ce
|
||||||
- use "substring"-function instead of "substr" - 445ae12
|
- use "substring"-function instead of "substr" - 445ae12
|
||||||
|
|
||||||
Compatibility notes:
|
Compatibility notes:
|
||||||
|
|
||||||
- This is a bugfix release. There are no breaking change and no new features.
|
- 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)
|
[Commits](https://github.com/wycats/handlebars.js/compare/v4.1.0...v4.1.1)
|
||||||
|
|
||||||
## v4.1.0 - February 7th, 2019
|
## v4.1.0 - February 7th, 2019
|
||||||
|
|
||||||
New Features
|
New Features
|
||||||
|
|
||||||
- import TypeScript typings - 27ac1ee
|
- import TypeScript typings - 27ac1ee
|
||||||
@@ -473,10 +312,11 @@ document.getElementById('output').innerHTML = template(new SomeClass());
|
|||||||
|
|
||||||
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).
|
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)
|
[Commits](https://github.com/wycats/handlebars.js/compare/v4.0.12...v4.1.0)
|
||||||
|
|
||||||
## v4.0.12 - September 4th, 2018
|
## v4.0.12 - September 4th, 2018
|
||||||
|
|
||||||
New features:
|
New features:
|
||||||
|
|
||||||
- none
|
- none
|
||||||
@@ -501,27 +341,25 @@ Removed obsolete code:
|
|||||||
- Update jsfiddle to 4.0.11 - 8947dd0
|
- Update jsfiddle to 4.0.11 - 8947dd0
|
||||||
|
|
||||||
Compatibility notes:
|
Compatibility notes:
|
||||||
|
|
||||||
- No compatibility issues are to be expected
|
- No compatibility issues are to be expected
|
||||||
|
|
||||||
[Commits](https://github.com/wycats/handlebars.js/compare/v4.0.11...v4.0.12)
|
[Commits](https://github.com/wycats/handlebars.js/compare/v4.0.11...v4.0.12)
|
||||||
|
|
||||||
## v4.0.11 - October 17th, 2017
|
## 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))
|
- [#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))
|
- [#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
|
- Update (C) year in the LICENSE file - 21386b6
|
||||||
|
|
||||||
Compatibility notes:
|
Compatibility notes:
|
||||||
|
|
||||||
- This is a bugfix release. There are no breaking change and no new features.
|
- 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)
|
[Commits](https://github.com/wycats/handlebars.js/compare/v4.0.10...v4.0.11)
|
||||||
|
|
||||||
## v4.0.10 - May 21st, 2017
|
## v4.0.10 - May 21st, 2017
|
||||||
|
|
||||||
- Fix regression in 4.0.9: Replace "Object.assign" (not support in IE) by "util/extend" - 0e953d1
|
- 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)
|
[Commits](https://github.com/wycats/handlebars.js/compare/v4.0.9...v4.0.10)
|
||||||
|
|
||||||
## v4.0.9 - May 21st, 2017
|
## v4.0.9 - May 21st, 2017
|
||||||
@@ -529,44 +367,39 @@ Compatibility notes:
|
|||||||
- [#1327](https://github.com/wycats/handlebars.js/issues/1327) Handlebars.compile() does not modify "options" anymore
|
- [#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
|
- pending [#1331](https://github.com/wycats/handlebars.js/issues/1331) Attempts to build Handlebars in a Windows environment
|
||||||
- Fix build in windows - cc554a5
|
- Fix build in windows - cc554a5
|
||||||
- Ensure LF line-edings in handlebars-template fixtures (\*.hbs) - ed879a6
|
- Ensure LF line-edings in handlebars-template fixtures (*.hbs) - ed879a6
|
||||||
- Run integration test with `node handlebars -a ...` on Windows - 2e21e2b
|
- Run integration test with `node handlebars -a ...` on Windows - 2e21e2b
|
||||||
- Ensure LF line-edings in lexer-files (\*.l) - bdfdbea
|
- Ensure LF line-edings in lexer-files (*.l) - bdfdbea
|
||||||
- Force LF line-endings for spec/artifacts - b50ef03
|
- Force LF line-endings for spec/artifacts - b50ef03
|
||||||
- Use istanbul/lib/cli.js instead of node_modules/.bin/istanbul - 6e6269f
|
- Use istanbul/lib/cli.js instead of node_modules/.bin/istanbul - 6e6269f
|
||||||
- TravisCI: Publish valid semver tags independently of the branch - 7378f85
|
- TravisCI: Publish valid semver tags independently of the branch - 7378f85
|
||||||
|
|
||||||
Compatibility notes:
|
Compatibility notes:
|
||||||
|
|
||||||
- No compatibility issues are expected.
|
- No compatibility issues are expected.
|
||||||
|
|
||||||
[Commits](https://github.com/wycats/handlebars.js/compare/v4.0.8...v4.0.9)
|
[Commits](https://github.com/wycats/handlebars.js/compare/v4.0.8...v4.0.9)
|
||||||
|
|
||||||
## v4.0.8 - May 2nd, 2017
|
## 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
|
- [#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:
|
Compatibility notes:
|
||||||
|
|
||||||
- No breaking changes
|
- No breaking changes
|
||||||
|
|
||||||
[Commits](https://github.com/wycats/handlebars.js/compare/v4.0.7...v4.0.8)
|
[Commits](https://github.com/wycats/handlebars.js/compare/v4.0.7...v4.0.8)
|
||||||
|
|
||||||
## v4.0.7 - April 29th, 2017
|
## 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
|
- [#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
|
- [#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
|
- [#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
|
- [#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
|
- [#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
|
- [#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) [#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
|
- [#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/wycats/handlebars.js/compare/v4.0.6...v4.0.7)
|
[Commits](https://github.com/lawnsea/handlebars.js/compare/v4.0.6...v4.0.7)
|
||||||
|
|
||||||
## v4.0.6 - November 12th, 2016
|
## 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))
|
- [#1243](https://github.com/wycats/handlebars.js/pull/1243) - Walk up data frames for nested @partial-block ([@lawnsea](https://github.com/lawnsea))
|
||||||
- [#1210](https://github.com/wycats/handlebars.js/pull/1210) - Add a new lightweight package based on handlebars in the README ([@kabirbaidhya](https://github.com/kabirbaidhya))
|
- [#1210](https://github.com/wycats/handlebars.js/pull/1210) - Add a new lightweight package based on handlebars in the README ([@kabirbaidhya](https://github.com/kabirbaidhya))
|
||||||
- [#1187](https://github.com/wycats/handlebars.js/pull/1187) - Ensure that existing blockParams and depths are respected on dupe programs ([@charleso](https://github.com/charleso))
|
- [#1187](https://github.com/wycats/handlebars.js/pull/1187) - Ensure that existing blockParams and depths are respected on dupe programs ([@charleso](https://github.com/charleso))
|
||||||
@@ -574,7 +407,7 @@ Compatibility notes:
|
|||||||
- [#1177](https://github.com/wycats/handlebars.js/pull/1177) - Preserve License info in Closure Compiler ([@gennadiylitvinyuk](https://github.com/gennadiylitvinyuk))
|
- [#1177](https://github.com/wycats/handlebars.js/pull/1177) - Preserve License info in Closure Compiler ([@gennadiylitvinyuk](https://github.com/gennadiylitvinyuk))
|
||||||
- [#1171](https://github.com/wycats/handlebars.js/pull/1171) - Contributing doc fix: failing thats -> failing tests ([@paulfalgout](https://github.com/paulfalgout))
|
- [#1171](https://github.com/wycats/handlebars.js/pull/1171) - Contributing doc fix: failing thats -> failing tests ([@paulfalgout](https://github.com/paulfalgout))
|
||||||
- [#1166](https://github.com/wycats/handlebars.js/pull/1166) - Update license date ([@timwangdev](https://github.com/timwangdev))
|
- [#1166](https://github.com/wycats/handlebars.js/pull/1166) - Update license date ([@timwangdev](https://github.com/timwangdev))
|
||||||
- Update jsfiddle to point to latest - 959ee55 (originally dfc7554 by [@kpdecker](https://github.com/kpdecker))
|
- Update jsfiddle to point to latest - 959ee55 (originally dfc7554 by [@kpdecker](https://github.com/kpdecker))
|
||||||
- [#1163](https://github.com/wycats/handlebars.js/pull/1163) - Fix typos on decorators-api.md. ([@adjohnson916](https://github.com/adjohnson916))
|
- [#1163](https://github.com/wycats/handlebars.js/pull/1163) - Fix typos on decorators-api.md. ([@adjohnson916](https://github.com/adjohnson916))
|
||||||
- Drop extra Error params - 8c19874 (originally 63fdb92 by [@kpdecker](https://github.com/kpdecker))
|
- Drop extra Error params - 8c19874 (originally 63fdb92 by [@kpdecker](https://github.com/kpdecker))
|
||||||
- [#1153](https://github.com/wycats/handlebars.js/pull/1153) - Add documentation for running tests to contributing.md ([@ryanmurakami](https://github.com/ryanmurakami))
|
- [#1153](https://github.com/wycats/handlebars.js/pull/1153) - Add documentation for running tests to contributing.md ([@ryanmurakami](https://github.com/ryanmurakami))
|
||||||
@@ -588,7 +421,6 @@ Compatibility notes:
|
|||||||
[Commits](https://github.com/wycats/handlebars.js/compare/v4.0.5...v4.0.6)
|
[Commits](https://github.com/wycats/handlebars.js/compare/v4.0.5...v4.0.6)
|
||||||
|
|
||||||
## v4.0.5 - November 19th, 2015
|
## 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))
|
- [#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))
|
- [#1129](https://github.com/wycats/handlebars.js/issues/1129) - Minified lib returns an empty string ([@bricss](https://github.com/bricss))
|
||||||
- Return current handlebars instance from noConflict - 685cf92
|
- Return current handlebars instance from noConflict - 685cf92
|
||||||
@@ -601,14 +433,12 @@ Compatibility notes:
|
|||||||
[Commits](https://github.com/wycats/handlebars.js/compare/v4.0.4...v4.0.5)
|
[Commits](https://github.com/wycats/handlebars.js/compare/v4.0.4...v4.0.5)
|
||||||
|
|
||||||
## v4.0.4 - October 29th, 2015
|
## 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))
|
- [#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))
|
- [#1125](https://github.com/wycats/handlebars.js/pull/1125) - Add promised-handlebars to "in-the-wild"-list ([@nknapp](https://github.com/nknapp))
|
||||||
|
|
||||||
[Commits](https://github.com/wycats/handlebars.js/compare/v4.0.3...v4.0.4)
|
[Commits](https://github.com/wycats/handlebars.js/compare/v4.0.3...v4.0.4)
|
||||||
|
|
||||||
## v4.0.3 - September 23rd, 2015
|
## v4.0.3 - September 23rd, 2015
|
||||||
|
|
||||||
- [#1099](https://github.com/wycats/handlebars.js/issues/1099) - @partial-block is overridden ([@btmorex](https://github.com/btmorex))
|
- [#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))
|
- [#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))
|
- [#1092](https://github.com/wycats/handlebars.js/issues/1092) - Square braces in key name ([@distantnative](https://github.com/distantnative))
|
||||||
@@ -616,26 +446,22 @@ Compatibility notes:
|
|||||||
- [#1090](https://github.com/wycats/handlebars.js/pull/1090) - grammar fixes in 4.0.0 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))
|
||||||
|
|
||||||
Compatibility notes:
|
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.
|
- `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.
|
||||||
- `]` can now be included in `[]` wrapped identifiers by escaping with `\`. Any `[]` identifiers that include `\` will now have to properly escape these values.
|
- `]` can now be included in `[]` wrapped identifiers by escaping with `\`. Any `[]` identifiers that include `\` will now have to properly escape these values.
|
||||||
|
|
||||||
[Commits](https://github.com/wycats/handlebars.js/compare/v4.0.2...v4.0.3)
|
[Commits](https://github.com/wycats/handlebars.js/compare/v4.0.2...v4.0.3)
|
||||||
|
|
||||||
## v4.0.2 - September 4th, 2015
|
## 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://github.com/michaellopez))
|
||||||
|
|
||||||
[Commits](https://github.com/wycats/handlebars.js/compare/v4.0.1...v4.0.2)
|
[Commits](https://github.com/wycats/handlebars.js/compare/v4.0.1...v4.0.2)
|
||||||
|
|
||||||
## v4.0.1 - September 2nd, 2015
|
## v4.0.1 - September 2nd, 2015
|
||||||
|
|
||||||
- Fix failure when using decorators in partials - 05b82a2
|
- Fix failure when using decorators in partials - 05b82a2
|
||||||
|
|
||||||
[Commits](https://github.com/wycats/handlebars.js/compare/v4.0.0...v4.0.1)
|
[Commits](https://github.com/wycats/handlebars.js/compare/v4.0.0...v4.0.1)
|
||||||
|
|
||||||
## v4.0.0 - September 1st, 2015
|
## v4.0.0 - September 1st, 2015
|
||||||
|
|
||||||
- [#1082](https://github.com/wycats/handlebars.js/pull/1082) - Decorators and Inline Partials ([@kpdecker](https://github.com/kpdecker))
|
- [#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))
|
- [#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))
|
- [#1087](https://github.com/wycats/handlebars.js/pull/1087) - Fix #each when last object entry has empty key ([@denniskuczynski](https://github.com/denniskuczynski))
|
||||||
@@ -671,7 +497,6 @@ Compatibility notes:
|
|||||||
- Fix location information for programs - [93faffa](https://github.com/wycats/handlebars.js/commit/93faffa)
|
- Fix location information for programs - [93faffa](https://github.com/wycats/handlebars.js/commit/93faffa)
|
||||||
|
|
||||||
Compatibility notes:
|
Compatibility notes:
|
||||||
|
|
||||||
- Depthed paths are now conditionally pushed on to the stack. If the helper uses the same context, then a new stack is not created. This leads to behavior that better matches expectations for helpers like `if` that do not seem to alter the context. Any instances of `../` in templates will need to be checked for the correct behavior under 4.0.0. In general templates will either reduce the number of `../` instances or leave them as is. See [#1028](https://github.com/wycats/handlebars.js/issues/1028).
|
- Depthed paths are now conditionally pushed on to the stack. If the helper uses the same context, then a new stack is not created. This leads to behavior that better matches expectations for helpers like `if` that do not seem to alter the context. Any instances of `../` in templates will need to be checked for the correct behavior under 4.0.0. In general templates will either reduce the number of `../` instances or leave them as is. See [#1028](https://github.com/wycats/handlebars.js/issues/1028).
|
||||||
- The `=` character is now HTML escaped. This closes a potential exploit case when using unquoted attributes, i.e. `<div foo={{bar}}>`. In general it's recommended that attributes always be quoted when their values are generated from a mustache to avoid any potential exploit surfaces.
|
- The `=` character is now HTML escaped. This closes a potential exploit case when using unquoted attributes, i.e. `<div foo={{bar}}>`. In general it's recommended that attributes always be quoted when their values are generated from a mustache to avoid any potential exploit surfaces.
|
||||||
- AST constructors have been dropped in favor of plain old javascript objects
|
- AST constructors have been dropped in favor of plain old javascript objects
|
||||||
@@ -680,25 +505,22 @@ Compatibility notes:
|
|||||||
[Commits](https://github.com/wycats/handlebars.js/compare/v3.0.3...v4.0.0)
|
[Commits](https://github.com/wycats/handlebars.js/compare/v3.0.3...v4.0.0)
|
||||||
|
|
||||||
## v3.0.3 - April 28th, 2015
|
## 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://github.com/boskee))
|
||||||
|
|
||||||
[Commits](https://github.com/wycats/handlebars.js/compare/v3.0.2...v3.0.3)
|
[Commits](https://github.com/wycats/handlebars.js/compare/v3.0.2...v3.0.3)
|
||||||
|
|
||||||
## v3.0.2 - April 20th, 2015
|
## 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))
|
- [#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))
|
- [#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))
|
- [#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))
|
- [#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))
|
- [#967](https://github.com/wycats/handlebars.js/issues/967) - can't access "this" property ([@75lb](https://github.com/75lb))
|
||||||
- Use captureStackTrace for error handler - a009a97
|
- Use captureStackTrace for error handler - a009a97
|
||||||
- Ignore branches tested without coverage monitoring - 37a664b
|
- Ignore branches tested without coverage monitoring - 37a664b
|
||||||
|
|
||||||
[Commits](https://github.com/wycats/handlebars.js/compare/v3.0.1...v3.0.2)
|
[Commits](https://github.com/wycats/handlebars.js/compare/v3.0.1...v3.0.2)
|
||||||
|
|
||||||
## v3.0.1 - March 24th, 2015
|
## 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))
|
- [#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))
|
- [#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))
|
- [#966](https://github.com/wycats/handlebars.js/issues/966) - "handlebars --version" does not work with v3.0.0 ([@abloomston](https://github.com/abloomston))
|
||||||
@@ -708,7 +530,6 @@ Compatibility notes:
|
|||||||
[Commits](https://github.com/wycats/handlebars.js/compare/v3.0.0...v3.0.1)
|
[Commits](https://github.com/wycats/handlebars.js/compare/v3.0.0...v3.0.1)
|
||||||
|
|
||||||
## v3.0.0 - February 10th, 2015
|
## 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))
|
- [#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))
|
- [#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))
|
- [#938](https://github.com/wycats/handlebars.js/pull/938) - Fix example using #with helper ([@diwo](https://github.com/diwo))
|
||||||
@@ -738,7 +559,6 @@ Compatibility notes:
|
|||||||
- Lookup partials when undefined - 617dd57
|
- Lookup partials when undefined - 617dd57
|
||||||
|
|
||||||
Compatibility notes:
|
Compatibility notes:
|
||||||
|
|
||||||
- Runtime breaking changes. Must match 3.x runtime and precompiler.
|
- Runtime breaking changes. Must match 3.x runtime and precompiler.
|
||||||
- The AST has been upgraded to a public API.
|
- The AST has been upgraded to a public API.
|
||||||
- There are a number of changes to this, but the format is now documented in docs/compiler-api.md
|
- There are a number of changes to this, but the format is now documented in docs/compiler-api.md
|
||||||
@@ -748,7 +568,6 @@ Compatibility notes:
|
|||||||
- `SafeString` is now duck typed on `toHTML`
|
- `SafeString` is now duck typed on `toHTML`
|
||||||
|
|
||||||
New Features:
|
New Features:
|
||||||
|
|
||||||
- noConflict
|
- noConflict
|
||||||
- Source Maps
|
- Source Maps
|
||||||
- Block Params
|
- Block Params
|
||||||
@@ -761,7 +580,6 @@ New Features:
|
|||||||
[Commits](https://github.com/wycats/handlebars.js/compare/v2.0.0...v3.0.0)
|
[Commits](https://github.com/wycats/handlebars.js/compare/v2.0.0...v3.0.0)
|
||||||
|
|
||||||
## v2.0.0 - September 1st, 2014
|
## v2.0.0 - September 1st, 2014
|
||||||
|
|
||||||
- Update jsfiddle to 2.0.0-beta.1 - 0670f65
|
- Update jsfiddle to 2.0.0-beta.1 - 0670f65
|
||||||
- Add contrib note regarding handlebarsjs.com docs - 4d17e3c
|
- Add contrib note regarding handlebarsjs.com docs - 4d17e3c
|
||||||
- Play nice with gemspec version numbers - 64d5481
|
- Play nice with gemspec version numbers - 64d5481
|
||||||
@@ -769,7 +587,6 @@ New Features:
|
|||||||
[Commits](https://github.com/wycats/handlebars.js/compare/v2.0.0-beta.1...v2.0.0)
|
[Commits](https://github.com/wycats/handlebars.js/compare/v2.0.0-beta.1...v2.0.0)
|
||||||
|
|
||||||
## v2.0.0-beta.1 - August 26th, 2014
|
## 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))
|
- [#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))
|
- [#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))
|
- [#767](https://github.com/wycats/handlebars.js/issues/767) - Subexpressions bug with hash and context ([@evensoul](https://github.com/evensoul))
|
||||||
@@ -779,7 +596,7 @@ New Features:
|
|||||||
- [#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))
|
- [#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))
|
- [#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))
|
- [#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))
|
- [#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))
|
- [#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))
|
- [#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))
|
- [#823](https://github.com/wycats/handlebars.js/pull/823) - Support inverse sections on the with helper ([@dan-manges](https://github.com/dan-manges))
|
||||||
@@ -792,7 +609,6 @@ New Features:
|
|||||||
- Fix compiler program de-duping - 9e3f824
|
- Fix compiler program de-duping - 9e3f824
|
||||||
|
|
||||||
Compatibility notes:
|
Compatibility notes:
|
||||||
|
|
||||||
- The default build now outputs a generic UMD wrapper. This should be transparent change but may cause issues in some environments.
|
- The default build now outputs a generic UMD wrapper. This should be transparent change but may cause issues in some environments.
|
||||||
- Runtime compatibility breaks in both directions. Ensure that both compiler and client are upgraded to 2.0.0-beta.1 or higher at the same time.
|
- Runtime compatibility breaks in both directions. Ensure that both compiler and client are upgraded to 2.0.0-beta.1 or higher at the same time.
|
||||||
- `programWithDepth` has been removed an instead an array of context values is passed to fields needing depth lookups.
|
- `programWithDepth` has been removed an instead an array of context values is passed to fields needing depth lookups.
|
||||||
@@ -814,13 +630,11 @@ Compatibility notes:
|
|||||||
[Commits](https://github.com/wycats/handlebars.js/compare/v2.0.0-alpha.4...v2.0.0-beta.1)
|
[Commits](https://github.com/wycats/handlebars.js/compare/v2.0.0-alpha.4...v2.0.0-beta.1)
|
||||||
|
|
||||||
## v2.0.0-alpha.4 - May 19th, 2014
|
## v2.0.0-alpha.4 - May 19th, 2014
|
||||||
|
|
||||||
- Expose setup wrappers for compiled templates - 3638874
|
- Expose setup wrappers for compiled templates - 3638874
|
||||||
|
|
||||||
[Commits](https://github.com/wycats/handlebars.js/compare/v2.0.0-alpha.3...v2.0.0-alpha.4)
|
[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
|
## 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))
|
- [#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))
|
- [#793](https://github.com/wycats/handlebars.js/pull/793) - Ensure isHelper is coerced to a boolean ([@mmun](https://github.com/mmun))
|
||||||
- Refactor template init logic - 085e5e1
|
- Refactor template init logic - 085e5e1
|
||||||
@@ -828,7 +642,6 @@ Compatibility notes:
|
|||||||
[Commits](https://github.com/wycats/handlebars.js/compare/v2.0.0-alpha.2...v2.0.0-alpha.3)
|
[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
|
## 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))
|
- [#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))
|
- [#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))
|
- [#743](https://github.com/wycats/handlebars.js/issues/743) - subexpression confusion/problem? ([@waynedpj](https://github.com/waynedpj))
|
||||||
@@ -838,13 +651,11 @@ Compatibility notes:
|
|||||||
- Temporarily kill the AWS publish CI step - 8347ee2
|
- Temporarily kill the AWS publish CI step - 8347ee2
|
||||||
|
|
||||||
Compatibility notes:
|
Compatibility notes:
|
||||||
|
|
||||||
- A JSON polyfill is required to run the compiler under IE8 and below. It's recommended that the precompiler be used in lieu of running the compiler on these legacy environments.
|
- A JSON polyfill is required to run the compiler under IE8 and below. It's recommended that the precompiler be used in lieu of running the compiler on these legacy environments.
|
||||||
|
|
||||||
[Commits](https://github.com/wycats/handlebars.js/compare/v2.0.0-alpha.1...v2.0.0-alpha.2)
|
[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
|
## 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))
|
- [#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))
|
- [#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))
|
- [#472](https://github.com/wycats/handlebars.js/issues/472) - Helpers cannot have decimal parameters ([@kayleg](https://github.com/kayleg))
|
||||||
@@ -867,7 +678,6 @@ Compatibility notes:
|
|||||||
- [#704](https://github.com/wycats/handlebars.js/pull/704) - JavaScript Compiler Cleanup ([@blakeembrey](https://github.com/blakeembrey))
|
- [#704](https://github.com/wycats/handlebars.js/pull/704) - JavaScript Compiler Cleanup ([@blakeembrey](https://github.com/blakeembrey))
|
||||||
|
|
||||||
Compatibility notes:
|
Compatibility notes:
|
||||||
|
|
||||||
- `helperMissing` helper no longer has the indexed name argument. Helper name is now available via `options.name`.
|
- `helperMissing` helper no longer has the indexed name argument. Helper name is now available via `options.name`.
|
||||||
- Precompiler output has changed, which breaks compatibility with prior versions of the runtime and precompiled output.
|
- Precompiler output has changed, which breaks compatibility with prior versions of the runtime and precompiled output.
|
||||||
- `JavaScriptCompiler.compilerInfo` now returns generic objects rather than javascript source.
|
- `JavaScriptCompiler.compilerInfo` now returns generic objects rather than javascript source.
|
||||||
@@ -880,7 +690,6 @@ Compatibility notes:
|
|||||||
[Commits](https://github.com/wycats/handlebars.js/compare/v1.3.0...v2.0.0-alpha.1)
|
[Commits](https://github.com/wycats/handlebars.js/compare/v1.3.0...v2.0.0-alpha.1)
|
||||||
|
|
||||||
## v1.3.0 - January 1st, 2014
|
## v1.3.0 - January 1st, 2014
|
||||||
|
|
||||||
- [#690](https://github.com/wycats/handlebars.js/pull/690) - Added support for subexpressions ([@machty](https://github.com/machty))
|
- [#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))
|
- [#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))
|
- [#692](https://github.com/wycats/handlebars.js/pull/692) - add line numbers to nodes when parsing ([@fivetanley](https://github.com/fivetanley))
|
||||||
@@ -895,14 +704,12 @@ Compatibility notes:
|
|||||||
[Commits](https://github.com/wycats/handlebars.js/compare/v1.2.1...v1.3.0)
|
[Commits](https://github.com/wycats/handlebars.js/compare/v1.2.1...v1.3.0)
|
||||||
|
|
||||||
## v1.2.1 - December 26th, 2013
|
## 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))
|
- [#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))
|
- [#686](https://github.com/wycats/handlebars.js/pull/686) - Falsy AMD module names in version 1.2.0 ([@kpdecker](https://github.com/kpdecker))
|
||||||
|
|
||||||
[Commits](https://github.com/wycats/handlebars.js/compare/v1.2.0...v1.2.1)
|
[Commits](https://github.com/wycats/handlebars.js/compare/v1.2.0...v1.2.1)
|
||||||
|
|
||||||
## v1.2.0 - December 23rd, 2013
|
## 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))
|
- [#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))
|
- [#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))
|
- [#655](https://github.com/wycats/handlebars.js/issues/655) - Loading Handlebars using bower ([@niki4810](https://github.com/niki4810))
|
||||||
@@ -922,7 +729,6 @@ Compatibility notes:
|
|||||||
- Fix handling of boolean escape in MustacheNode - b4968bb
|
- Fix handling of boolean escape in MustacheNode - b4968bb
|
||||||
|
|
||||||
Compatibility notes:
|
Compatibility notes:
|
||||||
|
|
||||||
- `@index` and `@first` are now supported for `each` iteration on objects
|
- `@index` and `@first` are now supported for `each` iteration on objects
|
||||||
- `Handlebars.VM.checkRevision` and `Handlebars.JavaScriptCompiler.prototype.compilerInfo` now available to modify the version checking behavior.
|
- `Handlebars.VM.checkRevision` and `Handlebars.JavaScriptCompiler.prototype.compilerInfo` now available to modify the version checking behavior.
|
||||||
- Browserify users may link to the runtime library via `require('handlebars/runtime')`
|
- Browserify users may link to the runtime library via `require('handlebars/runtime')`
|
||||||
@@ -964,8 +770,8 @@ Compatibility notes:
|
|||||||
- [#571](https://github.com/wycats/handlebars.js/issues/571) - uglify upgrade breaks compatibility with older versions of node
|
- [#571](https://github.com/wycats/handlebars.js/issues/571) - uglify upgrade breaks compatibility with older versions of node
|
||||||
- [#587](https://github.com/wycats/handlebars.js/issues/587) - Partial inside partial breaks?
|
- [#587](https://github.com/wycats/handlebars.js/issues/587) - Partial inside partial breaks?
|
||||||
|
|
||||||
Compatibility notes:
|
|
||||||
|
|
||||||
|
Compatibility notes:
|
||||||
- The project now includes separate artifacts for AMD, CommonJS, and global objects.
|
- The project now includes separate artifacts for AMD, CommonJS, and global objects.
|
||||||
- AMD: Users may load the bundled `handlebars.amd.js` or `handlebars.runtime.amd.js` files or load individual modules directly. AMD users should also note that the handlebars object is exposed via the `default` field on the imported object. This [gist](https://gist.github.com/wycats/7417be0dc361a69d5916) provides some discussion of possible compatibility shims.
|
- AMD: Users may load the bundled `handlebars.amd.js` or `handlebars.runtime.amd.js` files or load individual modules directly. AMD users should also note that the handlebars object is exposed via the `default` field on the imported object. This [gist](https://gist.github.com/wycats/7417be0dc361a69d5916) provides some discussion of possible compatibility shims.
|
||||||
- CommonJS/Node: Node loading occurs as normal via `require`
|
- CommonJS/Node: Node loading occurs as normal via `require`
|
||||||
@@ -973,6 +779,7 @@ Compatibility notes:
|
|||||||
- Build artifacts have been removed from the repository. [npm][npm], [components/handlebars.js][components], [cdnjs][cdnjs], or the [builds page][builds-page] should now be used as the source of built artifacts.
|
- Build artifacts have been removed from the repository. [npm][npm], [components/handlebars.js][components], [cdnjs][cdnjs], or the [builds page][builds-page] should now be used as the source of built artifacts.
|
||||||
- Context-stored helpers are now always passed the `options` hash. Previously no-argument helpers did not have this argument.
|
- Context-stored helpers are now always passed the `options` hash. Previously no-argument helpers did not have this argument.
|
||||||
|
|
||||||
|
|
||||||
[Commits](https://github.com/wycats/handlebars.js/compare/v1.0.12...v1.1.0)
|
[Commits](https://github.com/wycats/handlebars.js/compare/v1.0.12...v1.1.0)
|
||||||
|
|
||||||
## v1.0.12 / 1.0.0 - May 31 2013
|
## v1.0.12 / 1.0.0 - May 31 2013
|
||||||
@@ -990,7 +797,6 @@ Compatibility notes:
|
|||||||
- Docs updates
|
- Docs updates
|
||||||
|
|
||||||
Compatibility notes:
|
Compatibility notes:
|
||||||
|
|
||||||
- The parser is now stricter on `{{{`, requiring that the end token be `}}}`. Templates that do not
|
- The parser is now stricter on `{{{`, requiring that the end token be `}}}`. Templates that do not
|
||||||
follow this convention should add the additional brace value.
|
follow this convention should add the additional brace value.
|
||||||
- Code that relies on global the namespace being muted when custom helpers or partials are passed will need to explicitly pass an `undefined` value for any helpers that should not be available.
|
- Code that relies on global the namespace being muted when custom helpers or partials are passed will need to explicitly pass an `undefined` value for any helpers that should not be available.
|
||||||
@@ -1057,13 +863,13 @@ changed.
|
|||||||
Instead of:
|
Instead of:
|
||||||
|
|
||||||
```js
|
```js
|
||||||
template(context, helpers, partials, [data]);
|
template(context, helpers, partials, [data])
|
||||||
```
|
```
|
||||||
|
|
||||||
Use:
|
Use:
|
||||||
|
|
||||||
```js
|
```js
|
||||||
template(context, { helpers: helpers, partials: partials, data: data });
|
template(context, {helpers: helpers, partials: partials, data: data})
|
||||||
```
|
```
|
||||||
|
|
||||||
[builds-page]: http://builds.handlebarsjs.com.s3.amazonaws.com/index.html
|
[builds-page]: http://builds.handlebarsjs.com.s3.amazonaws.com/index.html
|
||||||
|
|||||||
+1
-2
@@ -1,8 +1,7 @@
|
|||||||
{
|
{
|
||||||
"extends": [
|
"extends": [
|
||||||
"../.eslintrc.js",
|
"../.eslintrc.js",
|
||||||
"plugin:es5/no-es2015",
|
"plugin:es5/no-es2015"
|
||||||
"prettier"
|
|
||||||
],
|
],
|
||||||
"plugins": [
|
"plugins": [
|
||||||
"es5"
|
"es5"
|
||||||
|
|||||||
@@ -26,8 +26,7 @@
|
|||||||
window.expect = chai.expect;
|
window.expect = chai.expect;
|
||||||
mocha.setup('bdd');
|
mocha.setup('bdd');
|
||||||
</script>
|
</script>
|
||||||
<script src="/spec/vendor/json2.js"></script>
|
<script src="/spec/env/require.js"></script>
|
||||||
<script src="/spec/vendor/require.js"></script>
|
|
||||||
|
|
||||||
<script src="/spec/env/common.js"></script>
|
<script src="/spec/env/common.js"></script>
|
||||||
<script>
|
<script>
|
||||||
|
|||||||
+3
-4
@@ -27,9 +27,7 @@
|
|||||||
window.expect = chai.expect;
|
window.expect = chai.expect;
|
||||||
mocha.setup('bdd');
|
mocha.setup('bdd');
|
||||||
</script>
|
</script>
|
||||||
<script src="/spec/vendor/json2.js"></script>
|
<script src="/spec/env/require.js"></script>
|
||||||
<script src="/spec/vendor/require.js"></script>
|
|
||||||
|
|
||||||
<script src="/spec/env/common.js"></script>
|
<script src="/spec/env/common.js"></script>
|
||||||
<script>
|
<script>
|
||||||
var requireFailure;
|
var requireFailure;
|
||||||
@@ -112,7 +110,8 @@
|
|||||||
failedTests.push({
|
failedTests.push({
|
||||||
name: test.title,
|
name: test.title,
|
||||||
result: false,
|
result: false,
|
||||||
message: err.message, stack: err.stack,
|
message: err.message,
|
||||||
|
stack: err.stack,
|
||||||
titles: flattenTitles(test)
|
titles: flattenTitles(test)
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,6 +0,0 @@
|
|||||||
{{#someHelper true}}
|
|
||||||
<div>Some known helper</div>
|
|
||||||
{{#anotherHelper true}}
|
|
||||||
<div>Another known helper</div>
|
|
||||||
{{/anotherHelper}}
|
|
||||||
{{/someHelper}}
|
|
||||||
@@ -1 +0,0 @@
|
|||||||
<div>This is a test</div>
|
|
||||||
@@ -1 +0,0 @@
|
|||||||
<div>Test Partial</div>
|
|
||||||
+78
-158
@@ -7,102 +7,44 @@ describe('ast', function() {
|
|||||||
|
|
||||||
describe('BlockStatement', function() {
|
describe('BlockStatement', function() {
|
||||||
it('should throw on mustache mismatch', function() {
|
it('should throw on mustache mismatch', function() {
|
||||||
shouldThrow(
|
shouldThrow(function() {
|
||||||
function() {
|
handlebarsEnv.parse('\n {{#foo}}{{/bar}}');
|
||||||
handlebarsEnv.parse('\n {{#foo}}{{/bar}}');
|
}, Handlebars.Exception, "foo doesn't match bar - 2:5");
|
||||||
},
|
|
||||||
Handlebars.Exception,
|
|
||||||
"foo doesn't match bar - 2:5"
|
|
||||||
);
|
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
describe('helpers', function() {
|
describe('helpers', function() {
|
||||||
describe('#helperExpression', function() {
|
describe('#helperExpression', function() {
|
||||||
it('should handle mustache statements', function() {
|
it('should handle mustache statements', function() {
|
||||||
equals(
|
equals(AST.helpers.helperExpression({type: 'MustacheStatement', params: [], hash: undefined}), false);
|
||||||
AST.helpers.helperExpression({
|
equals(AST.helpers.helperExpression({type: 'MustacheStatement', params: [1], hash: undefined}), true);
|
||||||
type: 'MustacheStatement',
|
equals(AST.helpers.helperExpression({type: 'MustacheStatement', params: [], hash: {}}), true);
|
||||||
params: [],
|
|
||||||
hash: undefined
|
|
||||||
}),
|
|
||||||
false
|
|
||||||
);
|
|
||||||
equals(
|
|
||||||
AST.helpers.helperExpression({
|
|
||||||
type: 'MustacheStatement',
|
|
||||||
params: [1],
|
|
||||||
hash: undefined
|
|
||||||
}),
|
|
||||||
true
|
|
||||||
);
|
|
||||||
equals(
|
|
||||||
AST.helpers.helperExpression({
|
|
||||||
type: 'MustacheStatement',
|
|
||||||
params: [],
|
|
||||||
hash: {}
|
|
||||||
}),
|
|
||||||
true
|
|
||||||
);
|
|
||||||
});
|
});
|
||||||
it('should handle block statements', function() {
|
it('should handle block statements', function() {
|
||||||
equals(
|
equals(AST.helpers.helperExpression({type: 'BlockStatement', params: [], hash: undefined}), false);
|
||||||
AST.helpers.helperExpression({
|
equals(AST.helpers.helperExpression({type: 'BlockStatement', params: [1], hash: undefined}), true);
|
||||||
type: 'BlockStatement',
|
equals(AST.helpers.helperExpression({type: 'BlockStatement', params: [], hash: {}}), true);
|
||||||
params: [],
|
|
||||||
hash: undefined
|
|
||||||
}),
|
|
||||||
false
|
|
||||||
);
|
|
||||||
equals(
|
|
||||||
AST.helpers.helperExpression({
|
|
||||||
type: 'BlockStatement',
|
|
||||||
params: [1],
|
|
||||||
hash: undefined
|
|
||||||
}),
|
|
||||||
true
|
|
||||||
);
|
|
||||||
equals(
|
|
||||||
AST.helpers.helperExpression({
|
|
||||||
type: 'BlockStatement',
|
|
||||||
params: [],
|
|
||||||
hash: {}
|
|
||||||
}),
|
|
||||||
true
|
|
||||||
);
|
|
||||||
});
|
});
|
||||||
it('should handle subexpressions', function() {
|
it('should handle subexpressions', function() {
|
||||||
equals(AST.helpers.helperExpression({ type: 'SubExpression' }), true);
|
equals(AST.helpers.helperExpression({type: 'SubExpression'}), true);
|
||||||
});
|
});
|
||||||
it('should work with non-helper nodes', function() {
|
it('should work with non-helper nodes', function() {
|
||||||
equals(AST.helpers.helperExpression({ type: 'Program' }), false);
|
equals(AST.helpers.helperExpression({type: 'Program'}), false);
|
||||||
|
|
||||||
equals(
|
equals(AST.helpers.helperExpression({type: 'PartialStatement'}), false);
|
||||||
AST.helpers.helperExpression({ type: 'PartialStatement' }),
|
equals(AST.helpers.helperExpression({type: 'ContentStatement'}), false);
|
||||||
false
|
equals(AST.helpers.helperExpression({type: 'CommentStatement'}), false);
|
||||||
);
|
|
||||||
equals(
|
|
||||||
AST.helpers.helperExpression({ type: 'ContentStatement' }),
|
|
||||||
false
|
|
||||||
);
|
|
||||||
equals(
|
|
||||||
AST.helpers.helperExpression({ type: 'CommentStatement' }),
|
|
||||||
false
|
|
||||||
);
|
|
||||||
|
|
||||||
equals(AST.helpers.helperExpression({ type: 'PathExpression' }), false);
|
equals(AST.helpers.helperExpression({type: 'PathExpression'}), false);
|
||||||
|
|
||||||
equals(AST.helpers.helperExpression({ type: 'StringLiteral' }), false);
|
equals(AST.helpers.helperExpression({type: 'StringLiteral'}), false);
|
||||||
equals(AST.helpers.helperExpression({ type: 'NumberLiteral' }), false);
|
equals(AST.helpers.helperExpression({type: 'NumberLiteral'}), false);
|
||||||
equals(AST.helpers.helperExpression({ type: 'BooleanLiteral' }), false);
|
equals(AST.helpers.helperExpression({type: 'BooleanLiteral'}), false);
|
||||||
equals(
|
equals(AST.helpers.helperExpression({type: 'UndefinedLiteral'}), false);
|
||||||
AST.helpers.helperExpression({ type: 'UndefinedLiteral' }),
|
equals(AST.helpers.helperExpression({type: 'NullLiteral'}), false);
|
||||||
false
|
|
||||||
);
|
|
||||||
equals(AST.helpers.helperExpression({ type: 'NullLiteral' }), false);
|
|
||||||
|
|
||||||
equals(AST.helpers.helperExpression({ type: 'Hash' }), false);
|
equals(AST.helpers.helperExpression({type: 'Hash'}), false);
|
||||||
equals(AST.helpers.helperExpression({ type: 'HashPair' }), false);
|
equals(AST.helpers.helperExpression({type: 'HashPair'}), false);
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
@@ -119,18 +61,17 @@ describe('ast', function() {
|
|||||||
|
|
||||||
/* eslint-disable no-multi-spaces */
|
/* eslint-disable no-multi-spaces */
|
||||||
ast = Handlebars.parse(
|
ast = Handlebars.parse(
|
||||||
'line 1 {{line1Token}}\n' + // 1
|
'line 1 {{line1Token}}\n' // 1
|
||||||
' line 2 {{line2token}}\n' + // 2
|
+ ' line 2 {{line2token}}\n' // 2
|
||||||
' line 3 {{#blockHelperOnLine3}}\n' + // 3
|
+ ' line 3 {{#blockHelperOnLine3}}\n' // 3
|
||||||
'line 4{{line4token}}\n' + // 4
|
+ 'line 4{{line4token}}\n' // 4
|
||||||
'line5{{else}}\n' + // 5
|
+ 'line5{{else}}\n' // 5
|
||||||
'{{line6Token}}\n' + // 6
|
+ '{{line6Token}}\n' // 6
|
||||||
'{{/blockHelperOnLine3}}\n' + // 7
|
+ '{{/blockHelperOnLine3}}\n' // 7
|
||||||
'{{#open}}\n' + // 8
|
+ '{{#open}}\n' // 8
|
||||||
'{{else inverse}}\n' + // 9
|
+ '{{else inverse}}\n' // 9
|
||||||
'{{else}}\n' + // 10
|
+ '{{else}}\n' // 10
|
||||||
'{{/open}}'
|
+ '{{/open}}'); // 11
|
||||||
); // 11
|
|
||||||
/* eslint-enable no-multi-spaces */
|
/* eslint-enable no-multi-spaces */
|
||||||
body = ast.body;
|
body = ast.body;
|
||||||
|
|
||||||
@@ -151,35 +92,35 @@ describe('ast', function() {
|
|||||||
it('gets MustacheStatement line numbers correct across newlines', function() {
|
it('gets MustacheStatement line numbers correct across newlines', function() {
|
||||||
var secondMustacheStatement = body[3];
|
var secondMustacheStatement = body[3];
|
||||||
testColumns(secondMustacheStatement, 2, 2, 8, 22);
|
testColumns(secondMustacheStatement, 2, 2, 8, 22);
|
||||||
});
|
});
|
||||||
|
|
||||||
it('gets the block helper information correct', function() {
|
it('gets the block helper information correct', function() {
|
||||||
var blockHelperNode = body[5];
|
var blockHelperNode = body[5];
|
||||||
testColumns(blockHelperNode, 3, 7, 8, 23);
|
testColumns(blockHelperNode, 3, 7, 8, 23);
|
||||||
});
|
});
|
||||||
|
|
||||||
it('correctly records the line numbers the program of a block helper', function() {
|
it('correctly records the line numbers the program of a block helper', function() {
|
||||||
var blockHelperNode = body[5],
|
var blockHelperNode = body[5],
|
||||||
program = blockHelperNode.program;
|
program = blockHelperNode.program;
|
||||||
|
|
||||||
testColumns(program, 3, 5, 31, 5);
|
testColumns(program, 3, 5, 31, 5);
|
||||||
});
|
});
|
||||||
|
|
||||||
it('correctly records the line numbers of an inverse of a block helper', function() {
|
it('correctly records the line numbers of an inverse of a block helper', function() {
|
||||||
var blockHelperNode = body[5],
|
var blockHelperNode = body[5],
|
||||||
inverse = blockHelperNode.inverse;
|
inverse = blockHelperNode.inverse;
|
||||||
|
|
||||||
testColumns(inverse, 5, 7, 13, 0);
|
testColumns(inverse, 5, 7, 13, 0);
|
||||||
});
|
});
|
||||||
|
|
||||||
it('correctly records the line number of chained inverses', function() {
|
it('correctly records the line number of chained inverses', function() {
|
||||||
var chainInverseNode = body[7];
|
var chainInverseNode = body[7];
|
||||||
|
|
||||||
testColumns(chainInverseNode.program, 8, 9, 9, 0);
|
testColumns(chainInverseNode.program, 8, 9, 9, 0);
|
||||||
testColumns(chainInverseNode.inverse, 9, 10, 16, 0);
|
testColumns(chainInverseNode.inverse, 9, 10, 16, 0);
|
||||||
testColumns(chainInverseNode.inverse.body[0].program, 9, 10, 16, 0);
|
testColumns(chainInverseNode.inverse.body[0].program, 9, 10, 16, 0);
|
||||||
testColumns(chainInverseNode.inverse.body[0].inverse, 10, 11, 8, 0);
|
testColumns(chainInverseNode.inverse.body[0].inverse, 10, 11, 8, 0);
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
describe('whitespace control', function() {
|
describe('whitespace control', function() {
|
||||||
@@ -208,9 +149,7 @@ describe('ast', function() {
|
|||||||
});
|
});
|
||||||
|
|
||||||
it('block statements', function() {
|
it('block statements', function() {
|
||||||
var ast = Handlebars.parseWithoutProcessing(
|
var ast = Handlebars.parseWithoutProcessing(' {{# comment~}} \nfoo\n {{~/comment}}');
|
||||||
' {{# comment~}} \nfoo\n {{~/comment}}'
|
|
||||||
);
|
|
||||||
|
|
||||||
equals(ast.body[0].value, ' ');
|
equals(ast.body[0].value, ' ');
|
||||||
equals(ast.body[1].program.body[0].value, ' \nfoo\n ');
|
equals(ast.body[1].program.body[0].value, ' \nfoo\n ');
|
||||||
@@ -228,9 +167,7 @@ describe('ast', function() {
|
|||||||
});
|
});
|
||||||
describe('blocks - parseWithoutProcessing', function() {
|
describe('blocks - parseWithoutProcessing', function() {
|
||||||
it('block mustaches', function() {
|
it('block mustaches', function() {
|
||||||
var ast = Handlebars.parseWithoutProcessing(
|
var ast = Handlebars.parseWithoutProcessing(' {{# comment}} \nfoo\n {{else}} \n bar \n {{/comment}} '),
|
||||||
' {{# comment}} \nfoo\n {{else}} \n bar \n {{/comment}} '
|
|
||||||
),
|
|
||||||
block = ast.body[1];
|
block = ast.body[1];
|
||||||
|
|
||||||
equals(ast.body[0].value, ' ');
|
equals(ast.body[0].value, ' ');
|
||||||
@@ -241,17 +178,13 @@ describe('ast', function() {
|
|||||||
equals(ast.body[2].value, ' ');
|
equals(ast.body[2].value, ' ');
|
||||||
});
|
});
|
||||||
it('initial block mustaches', function() {
|
it('initial block mustaches', function() {
|
||||||
var ast = Handlebars.parseWithoutProcessing(
|
var ast = Handlebars.parseWithoutProcessing('{{# comment}} \nfoo\n {{/comment}}'),
|
||||||
'{{# comment}} \nfoo\n {{/comment}}'
|
|
||||||
),
|
|
||||||
block = ast.body[0];
|
block = ast.body[0];
|
||||||
|
|
||||||
equals(block.program.body[0].value, ' \nfoo\n ');
|
equals(block.program.body[0].value, ' \nfoo\n ');
|
||||||
});
|
});
|
||||||
it('mustaches with children', function() {
|
it('mustaches with children', function() {
|
||||||
var ast = Handlebars.parseWithoutProcessing(
|
var ast = Handlebars.parseWithoutProcessing('{{# comment}} \n{{foo}}\n {{/comment}}'),
|
||||||
'{{# comment}} \n{{foo}}\n {{/comment}}'
|
|
||||||
),
|
|
||||||
block = ast.body[0];
|
block = ast.body[0];
|
||||||
|
|
||||||
equals(block.program.body[0].value, ' \n');
|
equals(block.program.body[0].value, ' \n');
|
||||||
@@ -259,9 +192,7 @@ describe('ast', function() {
|
|||||||
equals(block.program.body[2].value, '\n ');
|
equals(block.program.body[2].value, '\n ');
|
||||||
});
|
});
|
||||||
it('nested block mustaches', function() {
|
it('nested block mustaches', function() {
|
||||||
var ast = Handlebars.parseWithoutProcessing(
|
var ast = Handlebars.parseWithoutProcessing('{{#foo}} \n{{# comment}} \nfoo\n {{else}} \n bar \n {{/comment}} \n{{/foo}}'),
|
||||||
'{{#foo}} \n{{# comment}} \nfoo\n {{else}} \n bar \n {{/comment}} \n{{/foo}}'
|
|
||||||
),
|
|
||||||
body = ast.body[0].program.body,
|
body = ast.body[0].program.body,
|
||||||
block = body[1];
|
block = body[1];
|
||||||
|
|
||||||
@@ -271,10 +202,8 @@ describe('ast', function() {
|
|||||||
equals(block.inverse.body[0].value, ' \n bar \n ');
|
equals(block.inverse.body[0].value, ' \n bar \n ');
|
||||||
});
|
});
|
||||||
it('column 0 block mustaches', function() {
|
it('column 0 block mustaches', function() {
|
||||||
var ast = Handlebars.parseWithoutProcessing(
|
var ast = Handlebars.parseWithoutProcessing('test\n{{# comment}} \nfoo\n {{else}} \n bar \n {{/comment}} '),
|
||||||
'test\n{{# comment}} \nfoo\n {{else}} \n bar \n {{/comment}} '
|
block = ast.body[1];
|
||||||
),
|
|
||||||
block = ast.body[1];
|
|
||||||
|
|
||||||
equals(ast.body[0].omit, undefined);
|
equals(ast.body[0].omit, undefined);
|
||||||
|
|
||||||
@@ -286,10 +215,8 @@ describe('ast', function() {
|
|||||||
});
|
});
|
||||||
describe('blocks', function() {
|
describe('blocks', function() {
|
||||||
it('marks block mustaches as standalone', function() {
|
it('marks block mustaches as standalone', function() {
|
||||||
var ast = Handlebars.parse(
|
var ast = Handlebars.parse(' {{# comment}} \nfoo\n {{else}} \n bar \n {{/comment}} '),
|
||||||
' {{# comment}} \nfoo\n {{else}} \n bar \n {{/comment}} '
|
block = ast.body[1];
|
||||||
),
|
|
||||||
block = ast.body[1];
|
|
||||||
|
|
||||||
equals(ast.body[0].value, '');
|
equals(ast.body[0].value, '');
|
||||||
|
|
||||||
@@ -300,24 +227,22 @@ describe('ast', function() {
|
|||||||
});
|
});
|
||||||
it('marks initial block mustaches as standalone', function() {
|
it('marks initial block mustaches as standalone', function() {
|
||||||
var ast = Handlebars.parse('{{# comment}} \nfoo\n {{/comment}}'),
|
var ast = Handlebars.parse('{{# comment}} \nfoo\n {{/comment}}'),
|
||||||
block = ast.body[0];
|
block = ast.body[0];
|
||||||
|
|
||||||
equals(block.program.body[0].value, 'foo\n');
|
equals(block.program.body[0].value, 'foo\n');
|
||||||
});
|
});
|
||||||
it('marks mustaches with children as standalone', function() {
|
it('marks mustaches with children as standalone', function() {
|
||||||
var ast = Handlebars.parse('{{# comment}} \n{{foo}}\n {{/comment}}'),
|
var ast = Handlebars.parse('{{# comment}} \n{{foo}}\n {{/comment}}'),
|
||||||
block = ast.body[0];
|
block = ast.body[0];
|
||||||
|
|
||||||
equals(block.program.body[0].value, '');
|
equals(block.program.body[0].value, '');
|
||||||
equals(block.program.body[1].path.original, 'foo');
|
equals(block.program.body[1].path.original, 'foo');
|
||||||
equals(block.program.body[2].value, '\n');
|
equals(block.program.body[2].value, '\n');
|
||||||
});
|
});
|
||||||
it('marks nested block mustaches as standalone', function() {
|
it('marks nested block mustaches as standalone', function() {
|
||||||
var ast = Handlebars.parse(
|
var ast = Handlebars.parse('{{#foo}} \n{{# comment}} \nfoo\n {{else}} \n bar \n {{/comment}} \n{{/foo}}'),
|
||||||
'{{#foo}} \n{{# comment}} \nfoo\n {{else}} \n bar \n {{/comment}} \n{{/foo}}'
|
body = ast.body[0].program.body,
|
||||||
),
|
block = body[1];
|
||||||
body = ast.body[0].program.body,
|
|
||||||
block = body[1];
|
|
||||||
|
|
||||||
equals(body[0].value, '');
|
equals(body[0].value, '');
|
||||||
|
|
||||||
@@ -327,11 +252,9 @@ describe('ast', function() {
|
|||||||
equals(body[0].value, '');
|
equals(body[0].value, '');
|
||||||
});
|
});
|
||||||
it('does not mark nested block mustaches as standalone', function() {
|
it('does not mark nested block mustaches as standalone', function() {
|
||||||
var ast = Handlebars.parse(
|
var ast = Handlebars.parse('{{#foo}} {{# comment}} \nfoo\n {{else}} \n bar \n {{/comment}} {{/foo}}'),
|
||||||
'{{#foo}} {{# comment}} \nfoo\n {{else}} \n bar \n {{/comment}} {{/foo}}'
|
body = ast.body[0].program.body,
|
||||||
),
|
block = body[1];
|
||||||
body = ast.body[0].program.body,
|
|
||||||
block = body[1];
|
|
||||||
|
|
||||||
equals(body[0].omit, undefined);
|
equals(body[0].omit, undefined);
|
||||||
|
|
||||||
@@ -341,11 +264,9 @@ describe('ast', function() {
|
|||||||
equals(body[0].omit, undefined);
|
equals(body[0].omit, undefined);
|
||||||
});
|
});
|
||||||
it('does not mark nested initial block mustaches as standalone', function() {
|
it('does not mark nested initial block mustaches as standalone', function() {
|
||||||
var ast = Handlebars.parse(
|
var ast = Handlebars.parse('{{#foo}}{{# comment}} \nfoo\n {{else}} \n bar \n {{/comment}}{{/foo}}'),
|
||||||
'{{#foo}}{{# comment}} \nfoo\n {{else}} \n bar \n {{/comment}}{{/foo}}'
|
body = ast.body[0].program.body,
|
||||||
),
|
block = body[0];
|
||||||
body = ast.body[0].program.body,
|
|
||||||
block = body[0];
|
|
||||||
|
|
||||||
equals(block.program.body[0].value, ' \nfoo\n');
|
equals(block.program.body[0].value, ' \nfoo\n');
|
||||||
equals(block.inverse.body[0].value, ' bar \n ');
|
equals(block.inverse.body[0].value, ' bar \n ');
|
||||||
@@ -354,10 +275,8 @@ describe('ast', function() {
|
|||||||
});
|
});
|
||||||
|
|
||||||
it('marks column 0 block mustaches as standalone', function() {
|
it('marks column 0 block mustaches as standalone', function() {
|
||||||
var ast = Handlebars.parse(
|
var ast = Handlebars.parse('test\n{{# comment}} \nfoo\n {{else}} \n bar \n {{/comment}} '),
|
||||||
'test\n{{# comment}} \nfoo\n {{else}} \n bar \n {{/comment}} '
|
block = ast.body[1];
|
||||||
),
|
|
||||||
block = ast.body[1];
|
|
||||||
|
|
||||||
equals(ast.body[0].omit, undefined);
|
equals(ast.body[0].omit, undefined);
|
||||||
|
|
||||||
@@ -429,3 +348,4 @@ describe('ast', function() {
|
|||||||
});
|
});
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|||||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user