Compare commits
4 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| ee913e28bd | |||
| 7a77f61c44 | |||
| 72753bcaa3 | |||
| f3d266a66e |
@@ -1,25 +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
|
|
||||||
|
|
||||||
# JS-Snippets
|
|
||||||
src/*.js
|
|
||||||
@@ -0,0 +1,200 @@
|
|||||||
|
{
|
||||||
|
"globals": {
|
||||||
|
"self": false
|
||||||
|
},
|
||||||
|
"env": {
|
||||||
|
"node": true
|
||||||
|
},
|
||||||
|
"ecmaFeatures": {
|
||||||
|
// Enabling features that can be implemented without polyfills. Want to avoid polyfills at this time.
|
||||||
|
"arrowFunctions": true,
|
||||||
|
"blockBindings": true,
|
||||||
|
"defaultParams": true,
|
||||||
|
"destructuring": true,
|
||||||
|
"modules": true,
|
||||||
|
"objectLiteralComputedProperties": true,
|
||||||
|
"objectLiteralDuplicateProperties": true,
|
||||||
|
"objectLiteralShorthandMethods": true,
|
||||||
|
"objectLiteralShorthandProperties": true,
|
||||||
|
"restParams": true,
|
||||||
|
"spread": true,
|
||||||
|
"templateStrings": true
|
||||||
|
},
|
||||||
|
"rules": {
|
||||||
|
// Possible Errors //
|
||||||
|
//-----------------//
|
||||||
|
|
||||||
|
"comma-dangle": [2, "never"],
|
||||||
|
"no-cond-assign": [2, "except-parens"],
|
||||||
|
|
||||||
|
// Allow for debugging
|
||||||
|
"no-console": 1,
|
||||||
|
|
||||||
|
"no-constant-condition": 2,
|
||||||
|
"no-control-regex": 2,
|
||||||
|
|
||||||
|
// Allow for debugging
|
||||||
|
"no-debugger": 1,
|
||||||
|
|
||||||
|
"no-dupe-args": 2,
|
||||||
|
"no-dupe-keys": 2,
|
||||||
|
"no-duplicate-case": 2,
|
||||||
|
"no-empty": 2,
|
||||||
|
"no-empty-character-class": 2,
|
||||||
|
"no-ex-assign": 2,
|
||||||
|
"no-extra-boolean-cast": 2,
|
||||||
|
"no-extra-parens": 0,
|
||||||
|
"no-extra-semi": 2,
|
||||||
|
"no-func-assign": 0,
|
||||||
|
|
||||||
|
// Stylistic... might consider disallowing in the future
|
||||||
|
"no-inner-declarations": 0,
|
||||||
|
|
||||||
|
"no-invalid-regexp": 2,
|
||||||
|
"no-irregular-whitespace": 2,
|
||||||
|
"no-negated-in-lhs": 2,
|
||||||
|
"no-obj-calls": 2,
|
||||||
|
"no-regex-spaces": 2,
|
||||||
|
"quote-props": [2, "as-needed", {"keywords": true}],
|
||||||
|
"no-sparse-arrays": 0,
|
||||||
|
|
||||||
|
// Optimizer and coverage will handle/highlight this and can be useful for debugging
|
||||||
|
"no-unreachable": 1,
|
||||||
|
|
||||||
|
"use-isnan": 2,
|
||||||
|
"valid-jsdoc": 0,
|
||||||
|
"valid-typeof": 2,
|
||||||
|
|
||||||
|
|
||||||
|
// Best Practices //
|
||||||
|
//----------------//
|
||||||
|
"block-scoped-var": 0,
|
||||||
|
"complexity": 0,
|
||||||
|
"consistent-return": 0,
|
||||||
|
"curly": 2,
|
||||||
|
"default-case": 1,
|
||||||
|
"dot-notation": [2, {"allowKeywords": false}],
|
||||||
|
"eqeqeq": 0,
|
||||||
|
"guard-for-in": 1,
|
||||||
|
"no-alert": 2,
|
||||||
|
"no-caller": 2,
|
||||||
|
"no-div-regex": 1,
|
||||||
|
"no-else-return": 0,
|
||||||
|
"no-empty-label": 2,
|
||||||
|
"no-eq-null": 0,
|
||||||
|
"no-eval": 2,
|
||||||
|
"no-extend-native": 2,
|
||||||
|
"no-extra-bind": 2,
|
||||||
|
"no-fallthrough": 2,
|
||||||
|
"no-floating-decimal": 2,
|
||||||
|
"no-implied-eval": 2,
|
||||||
|
"no-iterator": 2,
|
||||||
|
"no-labels": 2,
|
||||||
|
"no-lone-blocks": 2,
|
||||||
|
"no-loop-func": 2,
|
||||||
|
"no-multi-spaces": 2,
|
||||||
|
"no-multi-str": 1,
|
||||||
|
"no-native-reassign": 2,
|
||||||
|
"no-new": 2,
|
||||||
|
"no-new-func": 2,
|
||||||
|
"no-new-wrappers": 2,
|
||||||
|
"no-octal": 2,
|
||||||
|
"no-octal-escape": 2,
|
||||||
|
"no-param-reassign": 0,
|
||||||
|
"no-process-env": 2,
|
||||||
|
"no-proto": 2,
|
||||||
|
"no-redeclare": 2,
|
||||||
|
"no-return-assign": 2,
|
||||||
|
"no-script-url": 2,
|
||||||
|
"no-self-compare": 2,
|
||||||
|
"no-sequences": 2,
|
||||||
|
"no-throw-literal": 2,
|
||||||
|
"no-unused-expressions": 2,
|
||||||
|
"no-void": 0,
|
||||||
|
"no-warning-comments": 1,
|
||||||
|
"no-with": 2,
|
||||||
|
"radix": 2,
|
||||||
|
"vars-on-top": 0,
|
||||||
|
"wrap-iife": 2,
|
||||||
|
"yoda": 0,
|
||||||
|
|
||||||
|
|
||||||
|
// Strict //
|
||||||
|
//--------//
|
||||||
|
"strict": 0,
|
||||||
|
|
||||||
|
|
||||||
|
// Variables //
|
||||||
|
//-----------//
|
||||||
|
"no-catch-shadow": 2,
|
||||||
|
"no-delete-var": 2,
|
||||||
|
"no-label-var": 2,
|
||||||
|
"no-shadow": 0,
|
||||||
|
"no-shadow-restricted-names": 2,
|
||||||
|
"no-undef": 2,
|
||||||
|
"no-undef-init": 2,
|
||||||
|
"no-undefined": 0,
|
||||||
|
"no-unused-vars": [2, {"vars": "all", "args": "after-used"}],
|
||||||
|
"no-use-before-define": [2, "nofunc"],
|
||||||
|
|
||||||
|
|
||||||
|
// Node.js //
|
||||||
|
//---------//
|
||||||
|
// Others left to environment defaults
|
||||||
|
"no-mixed-requires": 0,
|
||||||
|
|
||||||
|
|
||||||
|
// Stylistic //
|
||||||
|
//-----------//
|
||||||
|
"indent": 0,
|
||||||
|
"brace-style": [2, "1tbs", {"allowSingleLine": true}],
|
||||||
|
"camelcase": 2,
|
||||||
|
"comma-spacing": [2, {"before": false, "after": true}],
|
||||||
|
"comma-style": [2, "last"],
|
||||||
|
"consistent-this": [1, "self"],
|
||||||
|
"eol-last": 2,
|
||||||
|
"func-names": 0,
|
||||||
|
"func-style": [2, "declaration"],
|
||||||
|
"key-spacing": [2, {
|
||||||
|
"beforeColon": false,
|
||||||
|
"afterColon": true
|
||||||
|
}],
|
||||||
|
"max-nested-callbacks": 0,
|
||||||
|
"new-cap": 2,
|
||||||
|
"new-parens": 2,
|
||||||
|
"newline-after-var": 0,
|
||||||
|
"no-array-constructor": 2,
|
||||||
|
"no-continue": 0,
|
||||||
|
"no-inline-comments": 0,
|
||||||
|
"no-lonely-if": 2,
|
||||||
|
"no-mixed-spaces-and-tabs": 2,
|
||||||
|
"no-multiple-empty-lines": 0,
|
||||||
|
"no-nested-ternary": 1,
|
||||||
|
"no-new-object": 2,
|
||||||
|
"no-spaced-func": 2,
|
||||||
|
"no-ternary": 0,
|
||||||
|
"no-trailing-spaces": 2,
|
||||||
|
"no-underscore-dangle": 0,
|
||||||
|
"no-extra-parens": [2, "functions"],
|
||||||
|
"one-var": 0,
|
||||||
|
"operator-assignment": 0,
|
||||||
|
"padded-blocks": 0,
|
||||||
|
"quote-props": 0,
|
||||||
|
"quotes": [2, "single", "avoid-escape"],
|
||||||
|
"semi": 2,
|
||||||
|
"semi-spacing": [2, {"before": false, "after": true}],
|
||||||
|
"sort-vars": 0,
|
||||||
|
"space-after-keywords": [2, "always"],
|
||||||
|
"space-before-blocks": [2, "always"],
|
||||||
|
"space-before-function-paren": [2, {"anonymous": "never", "named": "never"}],
|
||||||
|
"space-in-brackets": 0,
|
||||||
|
"space-in-parens": [2, "never"],
|
||||||
|
"space-infix-ops": 2,
|
||||||
|
"space-return-throw-case": 2,
|
||||||
|
"space-unary-ops": 2,
|
||||||
|
"spaced-comment": [2, "always", {"markers": [","]}],
|
||||||
|
"wrap-regex": 1,
|
||||||
|
|
||||||
|
"no-var": 1
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -1,66 +0,0 @@
|
|||||||
module.exports = {
|
|
||||||
extends: ['eslint:recommended', 'plugin:compat/recommended', 'prettier'],
|
|
||||||
globals: {
|
|
||||||
self: false
|
|
||||||
},
|
|
||||||
env: {
|
|
||||||
node: true,
|
|
||||||
es6: true
|
|
||||||
},
|
|
||||||
rules: {
|
|
||||||
'no-console': 'warn',
|
|
||||||
|
|
||||||
// temporarily disabled until the violating places are fixed.
|
|
||||||
'no-func-assign': 'off',
|
|
||||||
'no-sparse-arrays': 'off',
|
|
||||||
|
|
||||||
// Best Practices //
|
|
||||||
//----------------//
|
|
||||||
'default-case': 'warn',
|
|
||||||
'guard-for-in': 'warn',
|
|
||||||
'no-alert': 'error',
|
|
||||||
'no-caller': 'error',
|
|
||||||
'no-div-regex': 'warn',
|
|
||||||
'no-eval': 'error',
|
|
||||||
'no-extend-native': 'error',
|
|
||||||
'no-extra-bind': 'error',
|
|
||||||
'no-floating-decimal': 'error',
|
|
||||||
'no-implied-eval': 'error',
|
|
||||||
'no-iterator': 'error',
|
|
||||||
'no-labels': 'error',
|
|
||||||
'no-lone-blocks': 'error',
|
|
||||||
'no-loop-func': 'error',
|
|
||||||
'no-multi-str': 'warn',
|
|
||||||
'no-global-assign': 'error',
|
|
||||||
'no-new': 'error',
|
|
||||||
'no-new-func': 'error',
|
|
||||||
'no-new-wrappers': 'error',
|
|
||||||
'no-octal-escape': 'error',
|
|
||||||
'no-process-env': 'error',
|
|
||||||
'no-proto': 'error',
|
|
||||||
'no-return-assign': 'error',
|
|
||||||
'no-script-url': 'error',
|
|
||||||
'no-self-compare': 'error',
|
|
||||||
'no-sequences': 'error',
|
|
||||||
'no-throw-literal': 'error',
|
|
||||||
'no-unused-expressions': 'error',
|
|
||||||
'no-warning-comments': 'warn',
|
|
||||||
'no-with': 'error',
|
|
||||||
radix: 'error',
|
|
||||||
|
|
||||||
// Variables //
|
|
||||||
//-----------//
|
|
||||||
'no-label-var': 'error',
|
|
||||||
'no-undef-init': 'error',
|
|
||||||
'no-use-before-define': ['error', 'nofunc'],
|
|
||||||
|
|
||||||
// ECMAScript 6 //
|
|
||||||
//--------------//
|
|
||||||
'no-var': 'error'
|
|
||||||
},
|
|
||||||
parserOptions: {
|
|
||||||
sourceType: 'module',
|
|
||||||
ecmaVersion: 6,
|
|
||||||
ecmaFeatures: {}
|
|
||||||
}
|
|
||||||
};
|
|
||||||
@@ -1,6 +0,0 @@
|
|||||||
# Handlebars-template fixtures in test cases need deterministic eol
|
|
||||||
*.handlebars text eol=lf
|
|
||||||
*.hbs text eol=lf
|
|
||||||
|
|
||||||
# Lexer files as well
|
|
||||||
*.l text eol=lf
|
|
||||||
+5
-12
@@ -1,19 +1,12 @@
|
|||||||
|
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
|
|
||||||
/yarn-error.log
|
|
||||||
/yarn.lock
|
|
||||||
node_modules
|
|
||||||
/handlebars-release.tgz
|
|
||||||
.nyc_output
|
|
||||||
|
|
||||||
# Generated files
|
|
||||||
lib/handlebars/compiler/parser.js
|
|
||||||
/coverage/
|
|
||||||
/dist/
|
|
||||||
/integration-testing/*/dist/
|
|
||||||
|
|||||||
@@ -0,0 +1,2 @@
|
|||||||
|
instrumentation:
|
||||||
|
excludes: ['**/spec/**']
|
||||||
+25
@@ -0,0 +1,25 @@
|
|||||||
|
.DS_Store
|
||||||
|
.gitignore
|
||||||
|
.rvmrc
|
||||||
|
.eslintrc
|
||||||
|
.travis.yml
|
||||||
|
.rspec
|
||||||
|
Gemfile
|
||||||
|
Gemfile.lock
|
||||||
|
Rakefile
|
||||||
|
Gruntfile.js
|
||||||
|
*.gemspec
|
||||||
|
*.nuspec
|
||||||
|
*.log
|
||||||
|
bench/*
|
||||||
|
configurations/*
|
||||||
|
components/*
|
||||||
|
coverage/*
|
||||||
|
dist/cdnjs/*
|
||||||
|
dist/components/*
|
||||||
|
spec/*
|
||||||
|
src/*
|
||||||
|
tasks/*
|
||||||
|
tmp/*
|
||||||
|
publish/*
|
||||||
|
vendor/*
|
||||||
@@ -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
|
|
||||||
+21
-33
@@ -1,39 +1,27 @@
|
|||||||
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: '5'
|
||||||
|
env:
|
||||||
|
- PUBLISH=true
|
||||||
|
- secure: pLTzghtVll9yGKJI0AaB0uI8GypfWxLTaIB0ZL8//yN3nAEIKMhf/RRilYTsn/rKj2NUa7vt2edYILi3lttOUlCBOwTc9amiRms1W8Lwr/3IdWPeBLvLuH1zNJRm2lBAwU4LBSqaOwhGaxOQr6KHTnWudhNhgOucxpZfvfI/dFw=
|
||||||
|
- secure: yERYCf7AwL11D9uMtacly/THGV8BlzsMmrt+iQVvGA3GaY6QMmfYqf6P6cCH98sH5etd1Y+1e6YrPeMjqI6lyRllT7FptoyOdHulazQe86VQN4sc0EpqMlH088kB7gGjTut9Z+X9ViooT5XEh9WA5jXEI9pXhQJNoIHkWPuwGuY=
|
||||||
|
- node_js: '4'
|
||||||
|
cache:
|
||||||
|
directories:
|
||||||
|
- node_modules
|
||||||
|
|
||||||
git:
|
git:
|
||||||
depth: 100
|
depth: 100
|
||||||
|
|||||||
+5
-44
@@ -10,18 +10,11 @@ Pull requests containing only failing tests demonstrating the issue are welcomed
|
|||||||
|
|
||||||
Documentation issues on the handlebarsjs.com site should be reported on [handlebars-site](https://github.com/wycats/handlebars-site).
|
Documentation issues on the handlebarsjs.com site should be reported on [handlebars-site](https://github.com/wycats/handlebars-site).
|
||||||
|
|
||||||
## Branches
|
|
||||||
|
|
||||||
- The branch `4.x` contains the currently released version. Bugfixes should be made in this branch.
|
|
||||||
- The branch `master` contains the next version. A release date is not yet specified. Maintainers
|
|
||||||
should merge the branch `4.x` into the master branch regularly.
|
|
||||||
|
|
||||||
## Pull Requests
|
## Pull Requests
|
||||||
|
|
||||||
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 +25,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 +45,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,29 +57,10 @@ 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
|
|
||||||
|
|
||||||
Handlebars uses `eslint` to enforce best-practices and `prettier` to auto-format files.
|
|
||||||
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,
|
|
||||||
while warnings are allowed.
|
|
||||||
- The travis-ci job also lints all files and checks if they are formatted correctly. In this stage, warnings
|
|
||||||
are forbidden.
|
|
||||||
|
|
||||||
You can use the following scripts to make sure that the travis-job does not fail:
|
|
||||||
|
|
||||||
- **npm run lint** will run `eslint` and fail on warnings
|
|
||||||
- **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).
|
|
||||||
|
|
||||||
## Ember testing
|
## Ember testing
|
||||||
|
|
||||||
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.
|
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.
|
||||||
@@ -103,16 +75,13 @@ npm link handlebars
|
|||||||
npm test
|
npm test
|
||||||
```
|
```
|
||||||
|
|
||||||
## Releasing the latest version
|
## Releasing
|
||||||
|
|
||||||
_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.
|
||||||
|
|
||||||
A full release may be completed with the following:
|
A full release may be completed with the following:
|
||||||
|
|
||||||
```
|
```
|
||||||
npm ci
|
|
||||||
yo release
|
yo release
|
||||||
npm publish
|
npm publish
|
||||||
yo release:publish components handlebars.js dist/components/
|
yo release:publish components handlebars.js dist/components/
|
||||||
@@ -122,17 +91,9 @@ gem build handlebars-source.gemspec
|
|||||||
gem push handlebars-source-*.gem
|
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 this point the handlebars site needs to be updated to point to the new version numbers. The jsfiddle link should be updated to point to the most recent distribution for all instances in our documentation.
|
||||||
in those places still point to the latest version
|
|
||||||
|
|
||||||
- [The npm-package](https://www.npmjs.com/package/handlebars) (check latest-tag)
|
|
||||||
- [The bower package](https://github.com/components/handlebars.js) (check the package.json)
|
|
||||||
- [The AWS S3 Bucket](https://s3.amazonaws.com/builds.handlebarsjs.com) (check latest-tag)
|
|
||||||
- [RubyGems](https://rubygems.org/gems/handlebars-source)
|
|
||||||
|
|
||||||
When everything is OK, the handlebars site needs to be updated to point to the new version numbers. The jsfiddle link should be updated to point to the most recent distribution for all instances in our documentation.
|
|
||||||
|
|
||||||
[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
|
||||||
[issue]: https://github.com/wycats/handlebars.js/issues/new
|
[issue]: https://github.com/wycats/handlebars.js/issues/new
|
||||||
[jsfiddle]: https://jsfiddle.net/9D88g/180/
|
[jsfiddle]: https://jsfiddle.net/9D88g/47/
|
||||||
|
|||||||
+73
-134
@@ -1,42 +1,44 @@
|
|||||||
/* 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',
|
options: {
|
||||||
'dist',
|
},
|
||||||
'lib/handlebars/compiler/parser.js',
|
files: [
|
||||||
'integration-testing/**/node_modules'
|
'*.js',
|
||||||
],
|
'bench/**/*.js',
|
||||||
|
'tasks/**/*.js',
|
||||||
|
'lib/**/!(*.min|parser).js',
|
||||||
|
'spec/**/!(*.amd|json2|require).js'
|
||||||
|
]
|
||||||
|
},
|
||||||
|
|
||||||
|
clean: ['tmp', 'dist', 'lib/handlebars/compiler/parser.js'],
|
||||||
|
|
||||||
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' }
|
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
@@ -51,28 +53,24 @@ module.exports = function(grunt) {
|
|||||||
options: {
|
options: {
|
||||||
modules: 'amd'
|
modules: 'amd'
|
||||||
},
|
},
|
||||||
files: [
|
files: [{
|
||||||
{
|
expand: true,
|
||||||
expand: true,
|
cwd: 'lib/',
|
||||||
cwd: 'lib/',
|
src: '**/!(index).js',
|
||||||
src: '**/!(index).js',
|
dest: 'dist/amd/'
|
||||||
dest: 'dist/amd/'
|
}]
|
||||||
}
|
|
||||||
]
|
|
||||||
},
|
},
|
||||||
|
|
||||||
cjs: {
|
cjs: {
|
||||||
options: {
|
options: {
|
||||||
modules: 'common'
|
modules: 'common'
|
||||||
},
|
},
|
||||||
files: [
|
files: [{
|
||||||
{
|
cwd: 'lib/',
|
||||||
cwd: 'lib/',
|
expand: true,
|
||||||
expand: true,
|
src: '**/!(index).js',
|
||||||
src: '**/!(index).js',
|
dest: 'dist/cjs/'
|
||||||
dest: 'dist/cjs/'
|
}]
|
||||||
}
|
|
||||||
]
|
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
webpack: {
|
webpack: {
|
||||||
@@ -81,12 +79,7 @@ module.exports = function(grunt) {
|
|||||||
module: {
|
module: {
|
||||||
loaders: [
|
loaders: [
|
||||||
// the optional 'runtime' transformer tells babel to require the runtime instead of inlining it.
|
// the optional 'runtime' transformer tells babel to require the runtime instead of inlining it.
|
||||||
{
|
{ test: /\.jsx?$/, exclude: /node_modules/, loader: 'babel-loader?optional=runtime&loose=es6.modules&auxiliaryCommentBefore=istanbul%20ignore%20next' }
|
||||||
test: /\.jsx?$/,
|
|
||||||
exclude: /node_modules/,
|
|
||||||
loader:
|
|
||||||
'babel-loader?optional=runtime&loose=es6.modules&auxiliaryCommentBefore=istanbul%20ignore%20next'
|
|
||||||
}
|
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
output: {
|
output: {
|
||||||
@@ -135,17 +128,15 @@ module.exports = function(grunt) {
|
|||||||
preserveComments: /(?:^!|@(?:license|preserve|cc_on))/
|
preserveComments: /(?:^!|@(?:license|preserve|cc_on))/
|
||||||
},
|
},
|
||||||
dist: {
|
dist: {
|
||||||
files: [
|
files: [{
|
||||||
{
|
cwd: 'dist/',
|
||||||
cwd: 'dist/',
|
expand: true,
|
||||||
expand: true,
|
src: ['handlebars*.js', '!*.min.js'],
|
||||||
src: ['handlebars*.js', '!*.min.js'],
|
dest: 'dist/',
|
||||||
dest: 'dist/',
|
rename: function(dest, src) {
|
||||||
rename: function(dest, src) {
|
return dest + src.replace(/\.js$/, '.min.js');
|
||||||
return dest + src.replace(/\.js$/, '.min.js');
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
]
|
}]
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
@@ -169,53 +160,32 @@ module.exports = function(grunt) {
|
|||||||
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: {
|
|
||||||
integrationTests: {
|
|
||||||
cmd: './integration-testing/run-integration-tests.sh',
|
|
||||||
bg: false,
|
|
||||||
fail: true
|
|
||||||
}
|
|
||||||
},
|
|
||||||
|
|
||||||
watch: {
|
watch: {
|
||||||
scripts: {
|
scripts: {
|
||||||
options: {
|
options: {
|
||||||
@@ -223,11 +193,25 @@ 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',
|
||||||
|
'parser',
|
||||||
|
'node',
|
||||||
|
'globals']);
|
||||||
|
|
||||||
|
this.registerTask('amd', ['babel:amd', 'requirejs']);
|
||||||
|
this.registerTask('node', ['babel:cjs']);
|
||||||
|
this.registerTask('globals', ['webpack']);
|
||||||
|
this.registerTask('tests', ['concat:tests']);
|
||||||
|
|
||||||
|
this.registerTask('release', 'Build final packages', ['eslint', 'amd', 'uglify', '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');
|
||||||
@@ -237,62 +221,17 @@ module.exports = function(grunt) {
|
|||||||
grunt.loadNpmTasks('grunt-contrib-uglify');
|
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-eslint');
|
||||||
grunt.loadNpmTasks('@knappi/grunt-saucelabs');
|
grunt.loadNpmTasks('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', 'sauce', 'metrics', 'publish:latest'] : ['default']);
|
||||||
grunt.registerTask('sauce', ['concat:tests', 'connect', 'saucelabs-mocha']);
|
|
||||||
} 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', [
|
|
||||||
'default',
|
|
||||||
'bgShell:integrationTests'
|
|
||||||
]);
|
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
Copyright (C) 2011-2019 by Yehuda Katz
|
Copyright (C) 2011-2016 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
-10
@@ -1,5 +1,4 @@
|
|||||||
[](https://travis-ci.org/wycats/handlebars.js)
|
[](https://travis-ci.org/wycats/handlebars.js)
|
||||||
[](https://ci.appveyor.com/project/wycats/handlebars-js)
|
|
||||||
[](https://saucelabs.com/u/handlebars)
|
[](https://saucelabs.com/u/handlebars)
|
||||||
|
|
||||||
Handlebars.js
|
Handlebars.js
|
||||||
@@ -11,12 +10,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 +45,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.
|
||||||
|
|
||||||
|
|||||||
@@ -1,36 +0,0 @@
|
|||||||
# Test against these versions of Node.js
|
|
||||||
environment:
|
|
||||||
matrix:
|
|
||||||
- nodejs_version: "10"
|
|
||||||
|
|
||||||
platform:
|
|
||||||
- x64
|
|
||||||
|
|
||||||
# Install scripts (runs after repo cloning)
|
|
||||||
install:
|
|
||||||
# Get the latest stable version of Node.js
|
|
||||||
- ps: Install-Product node $env:nodejs_version $env:platform
|
|
||||||
# Clone submodules (mustache spec)
|
|
||||||
- cmd: git submodule update --init --recursive
|
|
||||||
# Install modules
|
|
||||||
- cmd: npm ci
|
|
||||||
|
|
||||||
|
|
||||||
# Post-install test scripts
|
|
||||||
test_script:
|
|
||||||
# Output useful info for debugging
|
|
||||||
- cmd: node --version
|
|
||||||
- cmd: npm --version
|
|
||||||
# Run tests
|
|
||||||
- cmd: npm run test
|
|
||||||
|
|
||||||
# Don't actually build
|
|
||||||
build: off
|
|
||||||
|
|
||||||
on_failure:
|
|
||||||
- cmd: 7z a coverage.zip coverage
|
|
||||||
- cmd: appveyor PushArtifact coverage.zip
|
|
||||||
|
|
||||||
|
|
||||||
# Set build version format here instead of in the admin panel
|
|
||||||
version: "{build}"
|
|
||||||
+1
-2
@@ -1,5 +1,4 @@
|
|||||||
{
|
{
|
||||||
"extends": "prettier",
|
|
||||||
"globals": {
|
"globals": {
|
||||||
"require": true
|
"require": true
|
||||||
},
|
},
|
||||||
@@ -12,4 +11,4 @@
|
|||||||
"handle-callback-err": 0,
|
"handle-callback-err": 0,
|
||||||
"no-console": 0
|
"no-console": 0
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
+7
-12
@@ -1,14 +1,12 @@
|
|||||||
var async = require('neo-async'),
|
var async = require('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}}'
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -5,11 +5,11 @@ module.exports = {
|
|||||||
header: function() {
|
header: function() {
|
||||||
return 'Colors';
|
return 'Colors';
|
||||||
},
|
},
|
||||||
hasItems: true, // To make things fairer in mustache land due to no `{{if}}` construct on arrays
|
hasItems: true, // To make things fairer in mustache land due to no `{{if}}` construct on arrays
|
||||||
items: [
|
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
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
+26
-52
@@ -1,5 +1,5 @@
|
|||||||
var _ = require('underscore'),
|
var _ = require('underscore'),
|
||||||
Benchmark = require('benchmark');
|
Benchmark = require('benchmark');
|
||||||
|
|
||||||
function BenchWarmer() {
|
function BenchWarmer() {
|
||||||
this.benchmarks = [];
|
this.benchmarks = [];
|
||||||
@@ -11,7 +11,7 @@ function BenchWarmer() {
|
|||||||
this.errors = {};
|
this.errors = {};
|
||||||
}
|
}
|
||||||
|
|
||||||
var print = require('util').print;
|
var print = require('sys').print;
|
||||||
|
|
||||||
BenchWarmer.prototype = {
|
BenchWarmer.prototype = {
|
||||||
winners: function(benches) {
|
winners: function(benches) {
|
||||||
@@ -29,25 +29,20 @@ BenchWarmer.prototype = {
|
|||||||
});
|
});
|
||||||
},
|
},
|
||||||
push: function(name, fn) {
|
push: function(name, fn) {
|
||||||
if (this.names.indexOf(name) === -1) {
|
if (this.names.indexOf(name) == -1) {
|
||||||
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 (self.errors.hasOwnProperty(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;
|
||||||
}
|
}
|
||||||
@@ -95,8 +86,9 @@ BenchWarmer.prototype = {
|
|||||||
|
|
||||||
if (errors) {
|
if (errors) {
|
||||||
print('\n\nErrors:\n');
|
print('\n\nErrors:\n');
|
||||||
Object.keys(self.errors).forEach(function(prop) {
|
for (prop in self.errors) {
|
||||||
if (self.errors[prop].error.message !== 'EWOT') {
|
if (self.errors.hasOwnProperty(prop)
|
||||||
|
&& self.errors[prop].error.message !== 'EWOT') {
|
||||||
bench = self.errors[prop];
|
bench = self.errors[prop];
|
||||||
print('\n' + bench.name + ':\n');
|
print('\n' + bench.name + ':\n');
|
||||||
print(bench.error.message);
|
print(bench.error.message);
|
||||||
@@ -105,7 +97,7 @@ BenchWarmer.prototype = {
|
|||||||
}
|
}
|
||||||
print('\n');
|
print('\n');
|
||||||
}
|
}
|
||||||
});
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
callback();
|
callback();
|
||||||
@@ -116,39 +108,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 +147,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 +165,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 +1,6 @@
|
|||||||
{
|
{
|
||||||
"name": "handlebars",
|
"name": "handlebars",
|
||||||
"version": "4.7.2",
|
"version": "4.0.6",
|
||||||
"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.2</version>
|
<version>4.0.6</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,20 +0,0 @@
|
|||||||
{
|
|
||||||
"name": "handlebars",
|
|
||||||
"version": "4.7.2",
|
|
||||||
"license": "MIT",
|
|
||||||
"jspm": {
|
|
||||||
"main": "handlebars",
|
|
||||||
"shim": {
|
|
||||||
"handlebars": {
|
|
||||||
"exports": "Handlebars"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"files": [
|
|
||||||
"handlebars.js",
|
|
||||||
"handlebars.runtime.js"
|
|
||||||
],
|
|
||||||
"buildConfig": {
|
|
||||||
"minify": true
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
+7
-57
@@ -16,34 +16,6 @@ var ast = Handlebars.parse(myTemplate);
|
|||||||
Handlebars.precompile(ast);
|
Handlebars.precompile(ast);
|
||||||
```
|
```
|
||||||
|
|
||||||
### Parsing
|
|
||||||
|
|
||||||
There are two primary APIs that are used to parse an existing template into the AST:
|
|
||||||
|
|
||||||
#### parseWithoutProcessing
|
|
||||||
|
|
||||||
`Handlebars.parseWithoutProcessing` is the primary mechanism to turn a raw template string into the Handlebars AST described in this document. No processing is done on the resulting AST which makes this ideal for codemod (for source to source transformation) tooling.
|
|
||||||
|
|
||||||
Example:
|
|
||||||
|
|
||||||
```js
|
|
||||||
let ast = Handlebars.parseWithoutProcessing(myTemplate);
|
|
||||||
```
|
|
||||||
|
|
||||||
#### parse
|
|
||||||
|
|
||||||
`Handlebars.parse` will parse the template with `parseWithoutProcessing` (see above) then it will update the AST to strip extraneous whitespace. The whitespace stripping functionality handles two distinct situations:
|
|
||||||
|
|
||||||
* Removes whitespace around dynamic statements that are on a line by themselves (aka "stand alone")
|
|
||||||
* Applies "whitespace control" characters (i.e. `~`) by truncating the `ContentStatement` `value` property appropriately (e.g. `\n\n{{~foo}}` would have a `ContentStatement` with a `value` of `''`)
|
|
||||||
|
|
||||||
`Handlebars.parse` is used internally by `Handlebars.precompile` and `Handlebars.compile`.
|
|
||||||
|
|
||||||
Example:
|
|
||||||
|
|
||||||
```js
|
|
||||||
let ast = Handlebars.parse(myTemplate);
|
|
||||||
```
|
|
||||||
|
|
||||||
### Basic
|
### Basic
|
||||||
|
|
||||||
@@ -94,7 +66,7 @@ interface MustacheStatement <: Statement {
|
|||||||
|
|
||||||
interface BlockStatement <: Statement {
|
interface BlockStatement <: Statement {
|
||||||
type: "BlockStatement";
|
type: "BlockStatement";
|
||||||
path: PathExpression | Literal;
|
path: PathExpression;
|
||||||
params: [ Expression ];
|
params: [ Expression ];
|
||||||
hash: Hash;
|
hash: Hash;
|
||||||
|
|
||||||
@@ -324,43 +296,21 @@ The `Handlebars.JavaScriptCompiler` object has a number of methods that may be c
|
|||||||
- `initializeBuffer()`
|
- `initializeBuffer()`
|
||||||
Allows for buffers other than the default string buffer to be used. Generally needs to be paired with a custom `appendToBuffer` implementation.
|
Allows for buffers other than the default string buffer to be used. Generally needs to be paired with a custom `appendToBuffer` implementation.
|
||||||
|
|
||||||
### Example for the compiler api.
|
|
||||||
|
|
||||||
This example changes all lookups of properties are performed by a helper (`lookupLowerCase`) which looks for `test` if `{{Test}}` occurs in the template. This is just to illustrate how compiler behavior can be change.
|
|
||||||
|
|
||||||
There is also [a jsfiddle with this code](https://jsfiddle.net/9D88g/162/) if you want to play around with it.
|
|
||||||
|
|
||||||
|
|
||||||
```javascript
|
```javascript
|
||||||
function MyCompiler() {
|
function MyCompiler() {
|
||||||
Handlebars.JavaScriptCompiler.apply(this, arguments);
|
Handlebars.JavaScriptCompiler.apply(this, arguments);
|
||||||
}
|
}
|
||||||
MyCompiler.prototype = new Handlebars.JavaScriptCompiler();
|
MyCompiler.prototype = Object.create(Handlebars.JavaScriptCompiler);
|
||||||
|
|
||||||
// Use this compile to compile BlockStatment-Blocks
|
MyCompiler.nameLookup = function(parent, name, type) {
|
||||||
MyCompiler.prototype.compiler = MyCompiler
|
if (type === 'partial') {
|
||||||
|
return 'MyPartialList[' + JSON.stringify(name) ']';
|
||||||
MyCompiler.prototype.nameLookup = function(parent, name, type) {
|
|
||||||
if (type === 'context') {
|
|
||||||
return this.source.functionCall('helpers.lookupLowerCase', '', [parent, JSON.stringify(name)])
|
|
||||||
} else {
|
} else {
|
||||||
return Handlebars.JavaScriptCompiler.prototype.nameLookup.call(this, parent, name, type);
|
return Handlebars.JavaScriptCompiler.prototype.nameLookup.call(this, parent, name, type);
|
||||||
}
|
}
|
||||||
}
|
};
|
||||||
|
|
||||||
var env = Handlebars.create();
|
var env = Handlebars.create();
|
||||||
env.registerHelper('lookupLowerCase', function(parent, name) {
|
|
||||||
return parent[name.toLowerCase()]
|
|
||||||
})
|
|
||||||
|
|
||||||
env.JavaScriptCompiler = MyCompiler;
|
env.JavaScriptCompiler = MyCompiler;
|
||||||
|
env.compile('my template');
|
||||||
var template = env.compile('{{#each Test}} ({{Value}}) {{/each}}');
|
|
||||||
console.log(template({
|
|
||||||
test: [
|
|
||||||
{value: 'a'},
|
|
||||||
{value: 'b'},
|
|
||||||
{value: 'c'}
|
|
||||||
]
|
|
||||||
}));
|
|
||||||
```
|
```
|
||||||
|
|||||||
@@ -1,12 +0,0 @@
|
|||||||
Add a new integration test by creating a new subfolder
|
|
||||||
|
|
||||||
Add a file "test.sh" to that runs the test. "test.sh" should exit with a non-zero exit code
|
|
||||||
and display an error message, if something goes wrong.
|
|
||||||
|
|
||||||
* An integration test should reflect real-world setups that use handlebars.
|
|
||||||
* It should compile a minimal template and compare the output to an expected output.
|
|
||||||
* It should use "../.." as dependency for Handlebars so that the currently built library is used.
|
|
||||||
|
|
||||||
Currently, integration tests are only running on Linux, especially in travis-ci.
|
|
||||||
|
|
||||||
|
|
||||||
@@ -1,13 +0,0 @@
|
|||||||
module.exports = {
|
|
||||||
extends: ['eslint:recommended', 'plugin:es5/no-es2015', 'prettier'],
|
|
||||||
globals: {
|
|
||||||
self: false
|
|
||||||
},
|
|
||||||
env: {
|
|
||||||
node: true
|
|
||||||
},
|
|
||||||
rules: {
|
|
||||||
'no-console': 'off',
|
|
||||||
'no-var': 'off'
|
|
||||||
}
|
|
||||||
};
|
|
||||||
@@ -1,2 +0,0 @@
|
|||||||
target
|
|
||||||
package-lock.json
|
|
||||||
@@ -1,16 +0,0 @@
|
|||||||
{
|
|
||||||
"name": "multi-nodejs-test",
|
|
||||||
"version": "1.0.0",
|
|
||||||
"description": "Simple integration test with all relevant NodeJS-versions.",
|
|
||||||
"keywords": [],
|
|
||||||
"author": "Nils Knappmeier",
|
|
||||||
"private": true,
|
|
||||||
"license": "MIT",
|
|
||||||
"dependencies": {
|
|
||||||
"handlebars": "file:../.."
|
|
||||||
},
|
|
||||||
"scripts": {
|
|
||||||
"test": "node run-handlebars.js",
|
|
||||||
"test-precompile": "handlebars precompile-test-template.txt.hbs"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1 +0,0 @@
|
|||||||
Author: {{author}}
|
|
||||||
@@ -1,11 +0,0 @@
|
|||||||
// This test should run successfully with node 0.10++ as long as Handlebars has been compiled before
|
|
||||||
var assert = require('assert');
|
|
||||||
var Handlebars = require('handlebars');
|
|
||||||
|
|
||||||
console.log('Testing built Handlebars with Node version ' + process.version);
|
|
||||||
|
|
||||||
var template = Handlebars.compile('Author: {{author}}');
|
|
||||||
var output = template({ author: 'Yehuda' });
|
|
||||||
assert.strictEqual(output, 'Author: Yehuda');
|
|
||||||
|
|
||||||
console.log('Success');
|
|
||||||
@@ -1,27 +0,0 @@
|
|||||||
#!/bin/bash
|
|
||||||
|
|
||||||
cd "$( dirname "$( readlink -f "$0" )" )" || exit 1
|
|
||||||
# shellcheck disable=SC1090
|
|
||||||
[ -s "$NVM_DIR/nvm.sh" ] && \. "$NVM_DIR/nvm.sh"
|
|
||||||
|
|
||||||
# This script tests with precompiler and the built distribution with multiple NodeJS version.
|
|
||||||
# The rest of the travis-build will only work with newer NodeJS versions, because the build
|
|
||||||
# tools don't support older versions.
|
|
||||||
# However, the built distribution should work with older NodeJS versions as well.
|
|
||||||
# This test is simple by design. It merely ensures, that calling Handlebars does not fail with old versions.
|
|
||||||
# It does (almost) not test for correctness, because that is already done in the mocha-tests.
|
|
||||||
# And it does not use any NodeJS based testing framwork to make this part independent of the Node version.
|
|
||||||
|
|
||||||
unset npm_config_prefix
|
|
||||||
|
|
||||||
echo "Handlebars should be able to run in various versions of NodeJS"
|
|
||||||
for i in 0.10 0.12 4 5 6 7 8 9 10 11 ; do
|
|
||||||
rm target node_modules package-lock.json -rf
|
|
||||||
mkdir target
|
|
||||||
nvm install "$i"
|
|
||||||
nvm exec "$i" npm install
|
|
||||||
nvm exec "$i" npm run test || exit 1
|
|
||||||
nvm exec "$i" npm run test-precompile || exit 1
|
|
||||||
|
|
||||||
echo Success
|
|
||||||
done
|
|
||||||
@@ -1,13 +0,0 @@
|
|||||||
#!/bin/bash
|
|
||||||
|
|
||||||
cd "$( dirname "$( readlink -f "$0" )" )" || exit 1
|
|
||||||
|
|
||||||
for i in */test.sh ; do
|
|
||||||
(
|
|
||||||
echo "----------------------------------------"
|
|
||||||
echo "-- Running integration test: $i"
|
|
||||||
echo "----------------------------------------"
|
|
||||||
cd "$( dirname "$i" )" || exit 1
|
|
||||||
./test.sh || exit 1
|
|
||||||
)
|
|
||||||
done
|
|
||||||
@@ -1,11 +0,0 @@
|
|||||||
{
|
|
||||||
"plugins": [
|
|
||||||
"@roundingwellos/babel-plugin-handlebars-inline-precompile"
|
|
||||||
// "istanbul"
|
|
||||||
],
|
|
||||||
"presets": [
|
|
||||||
[
|
|
||||||
"@babel/preset-env"
|
|
||||||
]
|
|
||||||
]
|
|
||||||
}
|
|
||||||
@@ -1,3 +0,0 @@
|
|||||||
node_modules
|
|
||||||
dist
|
|
||||||
package-lock.json
|
|
||||||
@@ -1,24 +0,0 @@
|
|||||||
{
|
|
||||||
"name": "webpack-babel-test",
|
|
||||||
"version": "1.0.0",
|
|
||||||
"description": "",
|
|
||||||
"main": "index.js",
|
|
||||||
"keywords": [],
|
|
||||||
"author": "",
|
|
||||||
"license": "ISC",
|
|
||||||
"dependencies": {
|
|
||||||
"@babel/core": "^7.5.5",
|
|
||||||
"@babel/preset-env": "^7.5.5",
|
|
||||||
"@roundingwellos/babel-plugin-handlebars-inline-precompile": "^3.0.1",
|
|
||||||
"babel-loader": "^8.0.6",
|
|
||||||
"babel-plugin-istanbul": "^5.2.0",
|
|
||||||
"handlebars": "file:../..",
|
|
||||||
"handlebars-loader": "^1.7.1",
|
|
||||||
"nyc": "^14.1.1",
|
|
||||||
"webpack": "^4.39.3",
|
|
||||||
"webpack-cli": "^3.3.7"
|
|
||||||
},
|
|
||||||
"scripts": {
|
|
||||||
"build": "webpack --config webpack.config.js"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,12 +0,0 @@
|
|||||||
import * as Handlebars from 'handlebars/runtime';
|
|
||||||
import hbs from 'handlebars-inline-precompile';
|
|
||||||
import { assertEquals } from '../../webpack-test/src/lib/assert';
|
|
||||||
|
|
||||||
Handlebars.registerHelper('loud', function(text) {
|
|
||||||
return text.toUpperCase();
|
|
||||||
});
|
|
||||||
|
|
||||||
const template = hbs`{{loud name}}`;
|
|
||||||
const output = template({ name: 'yehuda' });
|
|
||||||
|
|
||||||
assertEquals(output, 'YEHUDA');
|
|
||||||
@@ -1,5 +0,0 @@
|
|||||||
export function assertEquals(actual, expected) {
|
|
||||||
if (actual !== expected) {
|
|
||||||
throw new Error(`Expected "${actual}" to equal "${expected}"`);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,16 +0,0 @@
|
|||||||
#!/bin/bash
|
|
||||||
|
|
||||||
set -e
|
|
||||||
|
|
||||||
# Cleanup: package-lock and "npm ci" is not working with local dependencies
|
|
||||||
rm dist package-lock.json -rf
|
|
||||||
npm install
|
|
||||||
npm run build
|
|
||||||
|
|
||||||
for i in dist/*-test.js ; do
|
|
||||||
echo "----------------------"
|
|
||||||
echo "-- Running $i"
|
|
||||||
echo "----------------------"
|
|
||||||
node "$i"
|
|
||||||
echo "Success"
|
|
||||||
done
|
|
||||||
@@ -1,32 +0,0 @@
|
|||||||
const fs = require('fs');
|
|
||||||
|
|
||||||
const testFiles = fs.readdirSync('src');
|
|
||||||
const entryPoints = {};
|
|
||||||
testFiles
|
|
||||||
.filter(file => file.match(/-test.js$/))
|
|
||||||
.forEach(file => {
|
|
||||||
entryPoints[file] = `./src/${file}`;
|
|
||||||
});
|
|
||||||
|
|
||||||
module.exports = {
|
|
||||||
entry: entryPoints,
|
|
||||||
output: {
|
|
||||||
filename: '[name]',
|
|
||||||
path: __dirname + '/dist'
|
|
||||||
},
|
|
||||||
module: {
|
|
||||||
rules: [
|
|
||||||
{
|
|
||||||
test: /\.js?$/,
|
|
||||||
exclude: /node_modules/,
|
|
||||||
use: {
|
|
||||||
loader: 'babel-loader',
|
|
||||||
options: { cacheDirectory: false }
|
|
||||||
}
|
|
||||||
}
|
|
||||||
]
|
|
||||||
},
|
|
||||||
optimization: {
|
|
||||||
minimize: false
|
|
||||||
}
|
|
||||||
};
|
|
||||||
@@ -1,3 +0,0 @@
|
|||||||
node_modules
|
|
||||||
dist
|
|
||||||
package-lock.json
|
|
||||||
@@ -1,21 +0,0 @@
|
|||||||
{
|
|
||||||
"name": "webpack-test",
|
|
||||||
"description": "Various tests with Handlebars and Webpack",
|
|
||||||
"version": "1.0.0",
|
|
||||||
"main": "index.js",
|
|
||||||
"scripts": {
|
|
||||||
"build": "webpack --config webpack.config.js",
|
|
||||||
"test": "node dist/main.js"
|
|
||||||
},
|
|
||||||
"private": true,
|
|
||||||
"keywords": [],
|
|
||||||
"author": "",
|
|
||||||
"license": "ISC",
|
|
||||||
"dependencies": {},
|
|
||||||
"devDependencies": {
|
|
||||||
"handlebars": "file:../..",
|
|
||||||
"handlebars-loader": "^1.7.1",
|
|
||||||
"webpack": "^4.39.3",
|
|
||||||
"webpack-cli": "^3.3.7"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,6 +0,0 @@
|
|||||||
import Handlebars from 'handlebars/dist/handlebars';
|
|
||||||
|
|
||||||
import { assertEquals } from './lib/assert';
|
|
||||||
|
|
||||||
const template = Handlebars.compile('Author: {{author}}');
|
|
||||||
assertEquals(template({ author: 'Yehuda' }), 'Author: Yehuda');
|
|
||||||
@@ -1,5 +0,0 @@
|
|||||||
import Handlebars from 'handlebars';
|
|
||||||
import { assertEquals } from './lib/assert';
|
|
||||||
|
|
||||||
const template = Handlebars.compile('Author: {{author}}');
|
|
||||||
assertEquals(template({ author: 'Yehuda' }), 'Author: Yehuda');
|
|
||||||
@@ -1,10 +0,0 @@
|
|||||||
import { assertEquals } from './lib/assert';
|
|
||||||
|
|
||||||
import testTemplate from './test-template.handlebars';
|
|
||||||
assertEquals(testTemplate({ author: 'Yehuda' }).trim(), 'Author: Yehuda');
|
|
||||||
|
|
||||||
const testTemplateRequire = require('./test-template.handlebars');
|
|
||||||
assertEquals(
|
|
||||||
testTemplateRequire({ author: 'Yehuda' }).trim(),
|
|
||||||
'Author: Yehuda'
|
|
||||||
);
|
|
||||||
@@ -1,10 +0,0 @@
|
|||||||
import * as HandlebarsViaImport from 'handlebars';
|
|
||||||
const HandlebarsViaRequire = require('handlebars');
|
|
||||||
import { assertEquals } from './lib/assert';
|
|
||||||
|
|
||||||
HandlebarsViaImport.registerHelper('loud', function(text) {
|
|
||||||
return text.toUpperCase();
|
|
||||||
});
|
|
||||||
|
|
||||||
const template = HandlebarsViaRequire.compile('Author: {{loud author}}');
|
|
||||||
assertEquals(template({ author: 'Yehuda' }), 'Author: YEHUDA');
|
|
||||||
@@ -1,6 +0,0 @@
|
|||||||
import * as Handlebars from 'handlebars/dist/handlebars';
|
|
||||||
|
|
||||||
import { assertEquals } from './lib/assert';
|
|
||||||
|
|
||||||
const template = Handlebars.compile('Author: {{author}}');
|
|
||||||
assertEquals(template({ author: 'Yehuda' }), 'Author: Yehuda');
|
|
||||||
@@ -1,5 +0,0 @@
|
|||||||
import * as Handlebars from 'handlebars';
|
|
||||||
import { assertEquals } from './lib/assert';
|
|
||||||
|
|
||||||
const template = Handlebars.compile('Author: {{author}}');
|
|
||||||
assertEquals(template({ author: 'Yehuda' }), 'Author: Yehuda');
|
|
||||||
@@ -1,5 +0,0 @@
|
|||||||
export function assertEquals(actual, expected) {
|
|
||||||
if (actual !== expected) {
|
|
||||||
throw new Error(`Expected "${actual}" to equal "${expected}"`);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,2 +0,0 @@
|
|||||||
Author: {{author}}
|
|
||||||
|
|
||||||
@@ -1,16 +0,0 @@
|
|||||||
#!/bin/bash
|
|
||||||
|
|
||||||
set -e
|
|
||||||
|
|
||||||
# Cleanup: package-lock and "npm ci" is not working with local dependencies
|
|
||||||
rm dist package-lock.json -rf
|
|
||||||
npm install
|
|
||||||
npm run build
|
|
||||||
|
|
||||||
for i in dist/*-test.js ; do
|
|
||||||
echo "----------------------"
|
|
||||||
echo "-- Running $i"
|
|
||||||
echo "----------------------"
|
|
||||||
node "$i"
|
|
||||||
echo "Success"
|
|
||||||
done
|
|
||||||
@@ -1,20 +0,0 @@
|
|||||||
const fs = require('fs');
|
|
||||||
|
|
||||||
const testFiles = fs.readdirSync('src');
|
|
||||||
const entryPoints = {};
|
|
||||||
testFiles
|
|
||||||
.filter(file => file.match(/-test.js$/))
|
|
||||||
.forEach(file => {
|
|
||||||
entryPoints[file] = `./src/${file}`;
|
|
||||||
});
|
|
||||||
|
|
||||||
module.exports = {
|
|
||||||
entry: entryPoints,
|
|
||||||
output: {
|
|
||||||
filename: '[name]',
|
|
||||||
path: __dirname + '/dist'
|
|
||||||
},
|
|
||||||
module: {
|
|
||||||
rules: [{ test: /\.handlebars$/, loader: 'handlebars-loader' }]
|
|
||||||
}
|
|
||||||
};
|
|
||||||
+1
-6
@@ -2,11 +2,7 @@ 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 } 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';
|
||||||
@@ -29,7 +25,6 @@ function create() {
|
|||||||
hb.JavaScriptCompiler = JavaScriptCompiler;
|
hb.JavaScriptCompiler = JavaScriptCompiler;
|
||||||
hb.Parser = Parser;
|
hb.Parser = Parser;
|
||||||
hb.parse = parse;
|
hb.parse = parse;
|
||||||
hb.parseWithoutProcessing = parseWithoutProcessing;
|
|
||||||
|
|
||||||
return hb;
|
return hb;
|
||||||
}
|
}
|
||||||
|
|||||||
+10
-26
@@ -1,13 +1,11 @@
|
|||||||
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.2';
|
export const VERSION = '4.0.6';
|
||||||
export const COMPILER_REVISION = 8;
|
export const COMPILER_REVISION = 7;
|
||||||
export const LAST_COMPATIBLE_COMPILER_REVISION = 7;
|
|
||||||
|
|
||||||
export const REVISION_CHANGES = {
|
export const REVISION_CHANGES = {
|
||||||
1: '<= 1.0.rc.2', // 1.0.rc.2 is actually rev2 but doesn't report it
|
1: '<= 1.0.rc.2', // 1.0.rc.2 is actually rev2 but doesn't report it
|
||||||
@@ -16,8 +14,7 @@ export const REVISION_CHANGES = {
|
|||||||
4: '== 1.x.x',
|
4: '== 1.x.x',
|
||||||
5: '== 2.0.0-alpha.x',
|
5: '== 2.0.0-alpha.x',
|
||||||
6: '>= 2.0.0-beta.1',
|
6: '>= 2.0.0-beta.1',
|
||||||
7: '>= 4.0.0 <4.3.0',
|
7: '>= 4.0.0'
|
||||||
8: '>= 4.3.0'
|
|
||||||
};
|
};
|
||||||
|
|
||||||
const objectType = '[object Object]';
|
const objectType = '[object Object]';
|
||||||
@@ -39,9 +36,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 +51,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 +62,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 +70,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;
|
||||||
|
|||||||
@@ -8,11 +8,9 @@ export { parser };
|
|||||||
let yy = {};
|
let yy = {};
|
||||||
extend(yy, Helpers);
|
extend(yy, Helpers);
|
||||||
|
|
||||||
export function parseWithoutProcessing(input, options) {
|
export function parse(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;
|
||||||
|
|
||||||
@@ -21,14 +19,6 @@ export function parseWithoutProcessing(input, options) {
|
|||||||
return new yy.SourceLocation(options && options.srcName, locInfo);
|
return new yy.SourceLocation(options && options.srcName, locInfo);
|
||||||
};
|
};
|
||||||
|
|
||||||
let ast = parser.parse(input);
|
|
||||||
|
|
||||||
return ast;
|
|
||||||
}
|
|
||||||
|
|
||||||
export function parse(input, options) {
|
|
||||||
let ast = parseWithoutProcessing(input, options);
|
|
||||||
let strip = new WhitespaceControl(options);
|
let strip = new WhitespaceControl(options);
|
||||||
|
return strip.accept(parser.parse(input));
|
||||||
return strip.accept(ast);
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
/* global define */
|
/* global define */
|
||||||
import { isArray } from '../utils';
|
import {isArray} from '../utils';
|
||||||
|
|
||||||
let SourceNode;
|
let SourceNode;
|
||||||
|
|
||||||
@@ -38,7 +38,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 +46,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 +62,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 +94,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,28 +113,26 @@ 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) {
|
||||||
let pairs = [];
|
let pairs = [];
|
||||||
|
|
||||||
Object.keys(obj).forEach(key => {
|
for (let key in obj) {
|
||||||
let value = castChunk(obj[key], this);
|
if (obj.hasOwnProperty(key)) {
|
||||||
if (value !== 'undefined') {
|
let value = castChunk(obj[key], this);
|
||||||
pairs.push([this.quotedString(key), ':', value]);
|
if (value !== 'undefined') {
|
||||||
|
pairs.push([this.quotedString(key), ':', value]);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
});
|
}
|
||||||
|
|
||||||
let ret = this.generateList(pairs);
|
let ret = this.generateList(pairs);
|
||||||
ret.prepend('{');
|
ret.prepend('{');
|
||||||
@@ -145,6 +140,7 @@ CodeGen.prototype = {
|
|||||||
return ret;
|
return ret;
|
||||||
},
|
},
|
||||||
|
|
||||||
|
|
||||||
generateList: function(entries) {
|
generateList: function(entries) {
|
||||||
let ret = this.empty();
|
let ret = this.empty();
|
||||||
|
|
||||||
@@ -169,3 +165,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} 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,34 @@ Compiler.prototype = {
|
|||||||
|
|
||||||
options.blockParams = options.blockParams || [];
|
options.blockParams = options.blockParams || [];
|
||||||
|
|
||||||
options.knownHelpers = extend(
|
// These changes will propagate to the other compiler components
|
||||||
Object.create(null),
|
let knownHelpers = options.knownHelpers;
|
||||||
{
|
options.knownHelpers = {
|
||||||
helperMissing: true,
|
'helperMissing': true,
|
||||||
blockHelperMissing: true,
|
'blockHelperMissing': true,
|
||||||
each: true,
|
'each': true,
|
||||||
if: true,
|
'if': true,
|
||||||
unless: true,
|
'unless': true,
|
||||||
with: true,
|
'with': true,
|
||||||
log: true,
|
'log': true,
|
||||||
lookup: true
|
'lookup': true
|
||||||
},
|
};
|
||||||
options.knownHelpers
|
if (knownHelpers) {
|
||||||
);
|
for (let name in knownHelpers) {
|
||||||
|
/* istanbul ignore else */
|
||||||
|
if (name in knownHelpers) {
|
||||||
|
options.knownHelpers[name] = knownHelpers[name];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
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 +107,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 +124,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 +159,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 +175,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 +218,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 +241,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 +264,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 +285,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 +297,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 +323,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 +339,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 +368,8 @@ 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 +397,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 +417,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 +426,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 +455,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 +466,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,22 +479,15 @@ 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);
|
|
||||||
if (!('data' in options)) {
|
if (!('data' in options)) {
|
||||||
options.data = true;
|
options.data = true;
|
||||||
}
|
}
|
||||||
@@ -530,13 +499,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
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -27,7 +24,7 @@ export function SourceLocation(source, locInfo) {
|
|||||||
|
|
||||||
export function id(token) {
|
export function id(token) {
|
||||||
if (/^\[.*\]$/.test(token)) {
|
if (/^\[.*\]$/.test(token)) {
|
||||||
return token.substring(1, token.length - 1);
|
return token.substr(1, token.length - 2);
|
||||||
} else {
|
} else {
|
||||||
return token;
|
return token;
|
||||||
}
|
}
|
||||||
@@ -41,28 +38,31 @@ 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,
|
||||||
|
depthString = '';
|
||||||
|
|
||||||
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++;
|
||||||
|
depthString += '../';
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
dig.push(part);
|
dig.push(part);
|
||||||
@@ -82,9 +82,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 +120,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 +168,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 +194,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 +209,4 @@ export function preparePartialBlock(open, program, close, locInfo) {
|
|||||||
loc: this.locInfo(locInfo)
|
loc: this.locInfo(locInfo)
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
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';
|
||||||
|
|
||||||
function Literal(value) {
|
function Literal(value) {
|
||||||
@@ -12,8 +12,12 @@ 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 (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 +25,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 +53,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 +82,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 +111,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();
|
||||||
}
|
}
|
||||||
@@ -154,11 +133,11 @@ JavaScriptCompiler.prototype = {
|
|||||||
};
|
};
|
||||||
|
|
||||||
if (this.decorators) {
|
if (this.decorators) {
|
||||||
ret.main_d = this.decorators; // eslint-disable-line camelcase
|
ret.main_d = this.decorators; // eslint-disable-line camelcase
|
||||||
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 +167,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();
|
||||||
@@ -230,16 +209,13 @@ JavaScriptCompiler.prototype = {
|
|||||||
// aliases will not be used, but this case is already being run on the client and
|
// aliases will not be used, but this case is already being run on the client and
|
||||||
// we aren't concern about minimizing the template size.
|
// we aren't concern about minimizing the template size.
|
||||||
let aliasCount = 0;
|
let aliasCount = 0;
|
||||||
Object.keys(this.aliases).forEach(alias => {
|
for (let alias in this.aliases) { // eslint-disable-line guard-for-in
|
||||||
let node = this.aliases[alias];
|
let node = this.aliases[alias];
|
||||||
if (node.children && node.referenceCount > 1) {
|
|
||||||
varDeclarations += ', alias' + ++aliasCount + '=' + alias;
|
if (this.aliases.hasOwnProperty(alias) && node.children && node.referenceCount > 1) {
|
||||||
|
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'];
|
||||||
@@ -259,23 +235,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 +272,7 @@ JavaScriptCompiler.prototype = {
|
|||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
||||||
if (appendOnly) {
|
if (appendOnly) {
|
||||||
if (bufferStart) {
|
if (bufferStart) {
|
||||||
bufferStart.prepend('return ');
|
bufferStart.prepend('return ');
|
||||||
@@ -309,8 +281,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 +292,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 +308,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('helpers.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 +326,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('helpers.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 +336,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 +368,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 +387,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 +472,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 +495,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 +535,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 +599,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,43 +619,18 @@ 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),
|
||||||
|
simple = isSimple ? [helper.name, ' || '] : '';
|
||||||
|
|
||||||
let possibleFunctionCalls = [];
|
let lookup = ['('].concat(simple, nonHelper);
|
||||||
|
|
||||||
if (isSimple) {
|
|
||||||
// direct call to helper
|
|
||||||
possibleFunctionCalls.push(helper.name);
|
|
||||||
}
|
|
||||||
// call a function from the input object
|
|
||||||
possibleFunctionCalls.push(nonHelper);
|
|
||||||
if (!this.options.strict) {
|
if (!this.options.strict) {
|
||||||
possibleFunctionCalls.push(
|
lookup.push(' || ', this.aliasable('helpers.helperMissing'));
|
||||||
this.aliasable('container.hooks.helperMissing')
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
|
lookup.push(')');
|
||||||
|
|
||||||
let functionLookupCode = [
|
this.push(this.source.functionCall(lookup, 'call', helper.callParams));
|
||||||
'(',
|
|
||||||
this.itemsSeparatedBy(possibleFunctionCalls, '||'),
|
|
||||||
')'
|
|
||||||
];
|
|
||||||
let functionCall = this.source.functionCall(
|
|
||||||
functionLookupCode,
|
|
||||||
'call',
|
|
||||||
helper.callParams
|
|
||||||
);
|
|
||||||
this.push(functionCall);
|
|
||||||
},
|
},
|
||||||
|
|
||||||
itemsSeparatedBy: function(items, separator) {
|
|
||||||
let result = [];
|
|
||||||
result.push(items[0]);
|
|
||||||
for (let i = 1; i < items.length; i++) {
|
|
||||||
result.push(separator, items[i]);
|
|
||||||
}
|
|
||||||
return result;
|
|
||||||
},
|
|
||||||
// [invokeKnownHelper]
|
// [invokeKnownHelper]
|
||||||
//
|
//
|
||||||
// On stack, before: hash, inverse, program, params..., ...
|
// On stack, before: hash, inverse, program, params..., ...
|
||||||
@@ -767,31 +663,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('helpers.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 +691,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 +728,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 +756,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,27 +772,20 @@ 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];
|
||||||
compiler = new this.compiler(); // eslint-disable-line new-cap
|
compiler = new this.compiler(); // eslint-disable-line new-cap
|
||||||
|
|
||||||
let existing = this.matchExistingProgram(child);
|
let existing = this.matchExistingProgram(child);
|
||||||
|
|
||||||
if (existing == null) {
|
if (existing == null) {
|
||||||
this.context.programs.push(''); // Placeholder to prevent name conflicts for nested children
|
this.context.programs.push(''); // Placeholder to prevent name conflicts for nested children
|
||||||
let index = this.context.programs.length;
|
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 +813,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 +848,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 +859,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 +898,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 +925,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 +942,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 +985,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)} : {}`);
|
||||||
`${this.contextName(0)} != null ? ${this.contextName(
|
|
||||||
0
|
|
||||||
)} : (container.nullContext || {})`
|
|
||||||
);
|
|
||||||
|
|
||||||
return {
|
return {
|
||||||
params: params,
|
params: params,
|
||||||
@@ -1134,11 +999,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 +1021,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)`
|
||||||
@@ -1204,7 +1069,6 @@ JavaScriptCompiler.prototype = {
|
|||||||
|
|
||||||
setupHelperArgs: function(helper, paramSize, params, useRegister) {
|
setupHelperArgs: function(helper, paramSize, params, useRegister) {
|
||||||
let options = this.setupParams(helper, paramSize, params);
|
let options = this.setupParams(helper, paramSize, params);
|
||||||
options.loc = JSON.stringify(this.source.currentLocation);
|
|
||||||
options = this.objectLiteral(options);
|
options = this.objectLiteral(options);
|
||||||
if (useRegister) {
|
if (useRegister) {
|
||||||
this.useRegister('options');
|
this.useRegister('options');
|
||||||
@@ -1219,6 +1083,7 @@ JavaScriptCompiler.prototype = {
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
(function() {
|
(function() {
|
||||||
const reservedWords = (
|
const reservedWords = (
|
||||||
'break else new var' +
|
'break else new var' +
|
||||||
@@ -1239,27 +1104,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 +1128,7 @@ function strictLookup(requireTerminal, compiler, parts, type) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (requireTerminal) {
|
if (requireTerminal) {
|
||||||
return [
|
return [compiler.aliasable('container.strict'), '(', stack, ', ', compiler.quotedString(parts[i]), ')'];
|
||||||
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 preceeded 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,26 +1,13 @@
|
|||||||
const errorProps = [
|
|
||||||
'description',
|
const errorProps = ['description', 'fileName', 'lineNumber', '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,
|
column;
|
||||||
column,
|
|
||||||
endColumn;
|
|
||||||
|
|
||||||
if (loc) {
|
if (loc) {
|
||||||
line = loc.start.line;
|
line = loc.start.line;
|
||||||
endLineNumber = loc.end.line;
|
|
||||||
column = loc.start.column;
|
column = loc.start.column;
|
||||||
endColumn = loc.end.column;
|
|
||||||
|
|
||||||
message += ' - ' + line + ':' + column;
|
message += ' - ' + line + ':' + column;
|
||||||
}
|
}
|
||||||
@@ -40,7 +27,6 @@ function Exception(message, node) {
|
|||||||
try {
|
try {
|
||||||
if (loc) {
|
if (loc) {
|
||||||
this.lineNumber = line;
|
this.lineNumber = line;
|
||||||
this.endLineNumber = endLineNumber;
|
|
||||||
|
|
||||||
// Work around issue under safari where we can't directly set the column value
|
// Work around issue under safari where we can't directly set the column value
|
||||||
/* istanbul ignore next */
|
/* istanbul ignore next */
|
||||||
@@ -49,13 +35,8 @@ function Exception(message, node) {
|
|||||||
value: column,
|
value: column,
|
||||||
enumerable: true
|
enumerable: true
|
||||||
});
|
});
|
||||||
Object.defineProperty(this, 'endColumn', {
|
|
||||||
value: endColumn,
|
|
||||||
enumerable: true
|
|
||||||
});
|
|
||||||
} else {
|
} else {
|
||||||
this.column = column;
|
this.column = column;
|
||||||
this.endColumn = endColumn;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} catch (nop) {
|
} catch (nop) {
|
||||||
|
|||||||
@@ -15,12 +15,3 @@ export function registerDefaultHelpers(instance) {
|
|||||||
registerLookup(instance);
|
registerLookup(instance);
|
||||||
registerWith(instance);
|
registerWith(instance);
|
||||||
}
|
}
|
||||||
|
|
||||||
export function moveHelperToHooks(instance, helperName, keepHelper) {
|
|
||||||
if (instance.helpers[helperName]) {
|
|
||||||
instance.hooks[helperName] = instance.helpers[helperName];
|
|
||||||
if (!keepHelper) {
|
|
||||||
delete instance.helpers[helperName];
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|||||||
@@ -1,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') {
|
||||||
@@ -63,29 +49,21 @@ export default function(instance) {
|
|||||||
execIteration(i, i, i === context.length - 1);
|
execIteration(i, i, i === context.length - 1);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} else if (global.Symbol && context[global.Symbol.iterator]) {
|
|
||||||
const newContext = [];
|
|
||||||
const iterator = context[global.Symbol.iterator]();
|
|
||||||
for (let it = iterator.next(); !it.done; it = iterator.next()) {
|
|
||||||
newContext.push(it.value);
|
|
||||||
}
|
|
||||||
context = newContext;
|
|
||||||
for (let j = context.length; i < j; i++) {
|
|
||||||
execIteration(i, i, i === context.length - 1);
|
|
||||||
}
|
|
||||||
} else {
|
} else {
|
||||||
let priorKey;
|
let priorKey;
|
||||||
|
|
||||||
Object.keys(context).forEach(key => {
|
for (let key in context) {
|
||||||
// We're running the iterations one step out of sync so we can detect
|
if (context.hasOwnProperty(key)) {
|
||||||
// the last iteration without have to scan the object twice and create
|
// We're running the iterations one step out of sync so we can detect
|
||||||
// an itermediate keys array.
|
// the last iteration without have to scan the object twice and create
|
||||||
if (priorKey !== undefined) {
|
// an itermediate keys array.
|
||||||
execIteration(priorKey, i - 1);
|
if (priorKey !== undefined) {
|
||||||
|
execIteration(priorKey, i - 1);
|
||||||
|
}
|
||||||
|
priorKey = key;
|
||||||
|
i++;
|
||||||
}
|
}
|
||||||
priorKey = key;
|
}
|
||||||
i++;
|
|
||||||
});
|
|
||||||
if (priorKey !== undefined) {
|
if (priorKey !== undefined) {
|
||||||
execIteration(priorKey, i - 1, true);
|
execIteration(priorKey, i - 1, true);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -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 + '"'
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,14 +1,8 @@
|
|||||||
import { isEmpty, isFunction } from '../utils';
|
import {isEmpty, isFunction} from '../utils';
|
||||||
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 (isFunction(conditional)) { conditional = conditional.call(this); }
|
||||||
throw new Exception('#if requires exactly one argument');
|
|
||||||
}
|
|
||||||
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 +15,6 @@ export default function(instance) {
|
|||||||
});
|
});
|
||||||
|
|
||||||
instance.registerHelper('unless', function(conditional, options) {
|
instance.registerHelper('unless', function(conditional, options) {
|
||||||
if (arguments.length != 2) {
|
return instance.helpers['if'].call(this, conditional, {fn: options.inverse, inverse: options.fn, hash: options.hash});
|
||||||
throw new Exception('#unless requires exactly one argument');
|
|
||||||
}
|
|
||||||
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,5 @@
|
|||||||
export default function(instance) {
|
export default function(instance) {
|
||||||
instance.registerHelper('lookup', function(obj, field, options) {
|
instance.registerHelper('lookup', function(obj, field) {
|
||||||
if (!obj) {
|
return obj && obj[field];
|
||||||
// Note for 5.0: Change to "obj == null" in 5.0
|
|
||||||
return obj;
|
|
||||||
}
|
|
||||||
return options.lookupProperty(obj, field);
|
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,20 +1,8 @@
|
|||||||
import {
|
import {appendContextPath, blockParams, createFrame, isEmpty, isFunction} from '../utils';
|
||||||
appendContextPath,
|
|
||||||
blockParams,
|
|
||||||
createFrame,
|
|
||||||
isEmpty,
|
|
||||||
isFunction
|
|
||||||
} from '../utils';
|
|
||||||
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 (isFunction(context)) { context = context.call(this); }
|
||||||
throw new Exception('#with requires exactly one argument');
|
|
||||||
}
|
|
||||||
if (isFunction(context)) {
|
|
||||||
context = context.call(this);
|
|
||||||
}
|
|
||||||
|
|
||||||
let fn = options.fn;
|
let fn = options.fn;
|
||||||
|
|
||||||
@@ -22,10 +10,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,16 +22,12 @@ 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) {
|
||||||
|
|||||||
+48
-220
@@ -1,48 +1,22 @@
|
|||||||
import * as Utils from './utils';
|
import * as Utils from './utils';
|
||||||
import Exception from './exception';
|
import Exception from './exception';
|
||||||
import {
|
import { COMPILER_REVISION, REVISION_CHANGES, createFrame } from './base';
|
||||||
COMPILER_REVISION,
|
|
||||||
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 !== currentRevision) {
|
||||||
compilerRevision >= LAST_COMPATIBLE_COMPILER_REVISION &&
|
if (compilerRevision < currentRevision) {
|
||||||
compilerRevision <= COMPILER_REVISION
|
const runtimeVersions = REVISION_CHANGES[currentRevision],
|
||||||
) {
|
compilerVersions = REVISION_CHANGES[compilerRevision];
|
||||||
return;
|
throw new Exception('Template was precompiled with an older version of Handlebars than the current runtime. ' +
|
||||||
}
|
'Please update your precompiler to a newer version (' + runtimeVersions + ') or downgrade your runtime to an older version (' + compilerVersions + ').');
|
||||||
|
} else {
|
||||||
if (compilerRevision < LAST_COMPATIBLE_COMPILER_REVISION) {
|
// Use the embedded version info since the runtime doesn't know about this revision yet
|
||||||
const runtimeVersions = REVISION_CHANGES[currentRevision],
|
throw new Exception('Template was precompiled with a newer version of Handlebars than the current runtime. ' +
|
||||||
compilerVersions = REVISION_CHANGES[compilerRevision];
|
'Please update your runtime to a newer version (' + compilerInfo[1] + ').');
|
||||||
throw new Exception(
|
}
|
||||||
'Template was precompiled with an older version of Handlebars than the current runtime. ' +
|
|
||||||
'Please update your precompiler to a newer version (' +
|
|
||||||
runtimeVersions +
|
|
||||||
') or downgrade your runtime to an older version (' +
|
|
||||||
compilerVersions +
|
|
||||||
').'
|
|
||||||
);
|
|
||||||
} else {
|
|
||||||
// Use the embedded version info since the runtime doesn't know about this revision yet
|
|
||||||
throw new Exception(
|
|
||||||
'Template was precompiled with a newer version of Handlebars than the current runtime. ' +
|
|
||||||
'Please update your runtime to a newer version (' +
|
|
||||||
compilerInfo[1] +
|
|
||||||
').'
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -58,13 +32,9 @@ export function template(templateSpec, env) {
|
|||||||
templateSpec.main.decorator = templateSpec.main_d;
|
templateSpec.main.decorator = templateSpec.main_d;
|
||||||
|
|
||||||
// Note: Using env.VM references rather than local var references throughout this section to allow
|
// Note: Using env.VM references rather than local var references throughout this section to allow
|
||||||
// for external users to override these as pseudo-supported APIs.
|
// for external users to override these as psuedo-supported APIs.
|
||||||
env.VM.checkRevision(templateSpec.compiler);
|
env.VM.checkRevision(templateSpec.compiler);
|
||||||
|
|
||||||
// backwards compatibility for precompiled templates with compiler-version 7 (<4.3.0)
|
|
||||||
const templateWasPrecompiledWithCompilerV7 =
|
|
||||||
templateSpec.compiler && templateSpec.compiler[0] === 7;
|
|
||||||
|
|
||||||
function invokePartialWrapper(partial, context, options) {
|
function invokePartialWrapper(partial, context, options) {
|
||||||
if (options.hash) {
|
if (options.hash) {
|
||||||
context = Utils.extend({}, context, options.hash);
|
context = Utils.extend({}, context, options.hash);
|
||||||
@@ -72,27 +42,13 @@ export function template(templateSpec, env) {
|
|||||||
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 result = env.VM.invokePartial.call(this, partial, context, options);
|
||||||
let extendedOptions = Utils.extend({}, options, {
|
|
||||||
hooks: this.hooks,
|
|
||||||
protoAccessControl: this.protoAccessControl
|
|
||||||
});
|
|
||||||
|
|
||||||
let result = env.VM.invokePartial.call(
|
|
||||||
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, options);
|
||||||
templateSpec.compilerOptions,
|
|
||||||
env
|
|
||||||
);
|
|
||||||
result = options.partials[options.name](context, extendedOptions);
|
|
||||||
}
|
}
|
||||||
if (result != null) {
|
if (result != null) {
|
||||||
if (options.indent) {
|
if (options.indent) {
|
||||||
@@ -108,43 +64,22 @@ 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'
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Just add water
|
// Just add water
|
||||||
let container = {
|
let container = {
|
||||||
strict: function(obj, name, loc) {
|
strict: function(obj, name) {
|
||||||
if (!obj || !(name in obj)) {
|
if (!(name in obj)) {
|
||||||
throw new Exception('"' + name + '" not defined in ' + obj, {
|
throw new Exception('"' + name + '" not defined in ' + obj);
|
||||||
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];
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -165,17 +100,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,17 +115,15 @@ export function template(templateSpec, env) {
|
|||||||
}
|
}
|
||||||
return value;
|
return value;
|
||||||
},
|
},
|
||||||
mergeIfNeeded: function(param, common) {
|
merge: function(param, common) {
|
||||||
let obj = param || common;
|
let obj = param || common;
|
||||||
|
|
||||||
if (param && common && param !== common) {
|
if (param && common && (param !== common)) {
|
||||||
obj = Utils.extend({}, common, param);
|
obj = Utils.extend({}, common, param);
|
||||||
}
|
}
|
||||||
|
|
||||||
return obj;
|
return obj;
|
||||||
},
|
},
|
||||||
// An empty object to use as replacement for null-contexts
|
|
||||||
nullContext: Object.seal({}),
|
|
||||||
|
|
||||||
noop: env.VM.noop,
|
noop: env.VM.noop,
|
||||||
compilerInfo: templateSpec.compiler
|
compilerInfo: templateSpec.compiler
|
||||||
@@ -212,81 +137,37 @@ 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 = container.merge(options.helpers, env.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 = container.merge(options.partials, env.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 = container.merge(options.decorators, env.decorators);
|
||||||
{},
|
|
||||||
env.decorators,
|
|
||||||
options.decorators
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
container.hooks = {};
|
|
||||||
container.protoAccessControl = createProtoAccessControl(options);
|
|
||||||
|
|
||||||
let keepHelperInHelpers =
|
|
||||||
options.allowCallsToHelperMissing ||
|
|
||||||
templateWasPrecompiledWithCompilerV7;
|
|
||||||
moveHelperToHooks(container, 'helperMissing', 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;
|
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -298,47 +179,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]) {
|
||||||
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);
|
||||||
@@ -349,9 +207,6 @@ export function wrapProgram(
|
|||||||
return prog;
|
return prog;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* This is currently part of the official API, therefore implementation details should not be changed.
|
|
||||||
*/
|
|
||||||
export function resolvePartial(partial, context, options) {
|
export function resolvePartial(partial, context, options) {
|
||||||
if (!partial) {
|
if (!partial) {
|
||||||
if (options.name === '@partial-block') {
|
if (options.name === '@partial-block') {
|
||||||
@@ -380,10 +235,7 @@ 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);
|
||||||
@@ -406,9 +258,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 +271,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,
|
|
||||||
props,
|
|
||||||
container,
|
|
||||||
depths && depths[0],
|
|
||||||
data,
|
|
||||||
blockParams,
|
|
||||||
depths
|
|
||||||
);
|
|
||||||
Utils.extend(prog, props);
|
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);
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|||||||
+9
-17
@@ -9,13 +9,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)) {
|
||||||
@@ -39,23 +39,16 @@ let isFunction = function(value) {
|
|||||||
/* istanbul ignore next */
|
/* istanbul ignore next */
|
||||||
if (isFunction(/x/)) {
|
if (isFunction(/x/)) {
|
||||||
isFunction = function(value) {
|
isFunction = function(value) {
|
||||||
return (
|
return typeof value === 'function' && toString.call(value) === '[object Function]';
|
||||||
typeof value === 'function' &&
|
|
||||||
toString.call(value) === '[object Function]'
|
|
||||||
);
|
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
export { isFunction };
|
export {isFunction};
|
||||||
/* eslint-enable func-style */
|
/* 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 +60,7 @@ 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,9 +78,7 @@ 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);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
+89
-153
@@ -1,9 +1,10 @@
|
|||||||
/* eslint-disable no-console */
|
/* eslint-disable no-console */
|
||||||
import Async from 'neo-async';
|
import Async from 'async';
|
||||||
import fs from 'fs';
|
import fs from 'fs';
|
||||||
import * as Handlebars from './handlebars';
|
import * as Handlebars from './handlebars';
|
||||||
import { basename } from 'path';
|
import {basename} from 'path';
|
||||||
import { SourceMapConsumer, SourceNode } from 'source-map';
|
import {SourceMapConsumer, SourceNode} from 'source-map';
|
||||||
|
import uglify from 'uglify-js';
|
||||||
|
|
||||||
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'
|
|
||||||
]);
|
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
@@ -275,6 +235,7 @@ module.exports.cli = function(opts) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
if (opts.map) {
|
if (opts.map) {
|
||||||
output.add('\n//# sourceMappingURL=' + opts.map + '\n');
|
output.add('\n//# sourceMappingURL=' + opts.map + '\n');
|
||||||
}
|
}
|
||||||
@@ -283,7 +244,15 @@ module.exports.cli = function(opts) {
|
|||||||
output.map = output.map + '';
|
output.map = output.map + '';
|
||||||
|
|
||||||
if (opts.min) {
|
if (opts.min) {
|
||||||
output = minify(output, opts.map);
|
output = uglify.minify(output.code, {
|
||||||
|
fromString: true,
|
||||||
|
|
||||||
|
outSourceMap: opts.map,
|
||||||
|
inSourceMap: JSON.parse(output.map)
|
||||||
|
});
|
||||||
|
if (opts.map) {
|
||||||
|
output.code += '\n//# sourceMappingURL=' + opts.map + '\n';
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (opts.map) {
|
if (opts.map) {
|
||||||
@@ -305,36 +274,3 @@ function arrayCast(value) {
|
|||||||
}
|
}
|
||||||
return value;
|
return value;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Run uglify to minify the compiled template, if uglify exists in the dependencies.
|
|
||||||
*
|
|
||||||
* We are using `require` instead of `import` here, because es6-modules do not allow
|
|
||||||
* dynamic imports and uglify-js is an optional dependency. Since we are inside NodeJS here, this
|
|
||||||
* should not be a problem.
|
|
||||||
*
|
|
||||||
* @param {string} output the compiled template
|
|
||||||
* @param {string} sourceMapFile the file to write the source map to.
|
|
||||||
*/
|
|
||||||
function minify(output, sourceMapFile) {
|
|
||||||
try {
|
|
||||||
// Try to resolve uglify-js in order to see if it does exist
|
|
||||||
require.resolve('uglify-js');
|
|
||||||
} catch (e) {
|
|
||||||
if (e.code !== 'MODULE_NOT_FOUND') {
|
|
||||||
// Something else seems to be wrong
|
|
||||||
throw e;
|
|
||||||
}
|
|
||||||
// it does not exist!
|
|
||||||
console.error(
|
|
||||||
'Code minimization is disabled due to missing uglify-js dependency'
|
|
||||||
);
|
|
||||||
return output;
|
|
||||||
}
|
|
||||||
return require('uglify-js').minify(output.code, {
|
|
||||||
sourceMap: {
|
|
||||||
content: output.map,
|
|
||||||
url: sourceMapFile
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|||||||
@@ -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
-11185
File diff suppressed because it is too large
Load Diff
+18
-72
@@ -1,7 +1,7 @@
|
|||||||
{
|
{
|
||||||
"name": "handlebars",
|
"name": "handlebars",
|
||||||
"barename": "handlebars",
|
"barename": "handlebars",
|
||||||
"version": "4.7.2",
|
"version": "4.0.6",
|
||||||
"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,77 +21,49 @@
|
|||||||
"node": ">=0.4.7"
|
"node": ">=0.4.7"
|
||||||
},
|
},
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"neo-async": "^2.6.0",
|
"async": "^1.4.0",
|
||||||
"optimist": "^0.6.1",
|
"optimist": "^0.6.1",
|
||||||
"source-map": "^0.6.1"
|
"source-map": "^0.4.4"
|
||||||
},
|
},
|
||||||
"optionalDependencies": {
|
"optionalDependencies": {
|
||||||
"uglify-js": "^3.1.4"
|
"uglify-js": "^2.6"
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"@knappi/grunt-saucelabs": "^9.0.2",
|
|
||||||
"aws-sdk": "^2.1.49",
|
"aws-sdk": "^2.1.49",
|
||||||
"babel-loader": "^5.0.0",
|
"babel-loader": "^5.0.0",
|
||||||
"babel-runtime": "^5.1.10",
|
"babel-runtime": "^5.1.10",
|
||||||
"benchmark": "~1.0",
|
"benchmark": "~1.0",
|
||||||
"chai": "^4.2.0",
|
|
||||||
"chai-diff": "^1.0.1",
|
|
||||||
"concurrently": "^5.0.0",
|
|
||||||
"dirty-chai": "^2.0.1",
|
|
||||||
"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",
|
"grunt": "~0.4.1",
|
||||||
"eslint-config-prettier": "^6.7.0",
|
|
||||||
"eslint-plugin-compat": "^3.3.0",
|
|
||||||
"eslint-plugin-es5": "^1.4.1",
|
|
||||||
"fs-extra": "^8.1.0",
|
|
||||||
"grunt": "^1.0.4",
|
|
||||||
"grunt-babel": "^5.0.0",
|
"grunt-babel": "^5.0.0",
|
||||||
"grunt-bg-shell": "^2.3.3",
|
"grunt-cli": "~0.1.10",
|
||||||
"grunt-cli": "^1",
|
"grunt-contrib-clean": "0.x",
|
||||||
"grunt-contrib-clean": "^1",
|
"grunt-contrib-concat": "0.x",
|
||||||
"grunt-contrib-concat": "^1",
|
"grunt-contrib-connect": "0.x",
|
||||||
"grunt-contrib-connect": "^1",
|
"grunt-contrib-copy": "0.x",
|
||||||
"grunt-contrib-copy": "^1",
|
"grunt-contrib-requirejs": "0.x",
|
||||||
"grunt-contrib-requirejs": "^1",
|
"grunt-contrib-uglify": "0.x",
|
||||||
"grunt-contrib-uglify": "^1",
|
"grunt-contrib-watch": "0.x",
|
||||||
"grunt-contrib-watch": "^1.1.0",
|
"grunt-eslint": "^17.1.0",
|
||||||
|
"grunt-saucelabs": "8.x",
|
||||||
"grunt-webpack": "^1.0.8",
|
"grunt-webpack": "^1.0.8",
|
||||||
"husky": "^3.1.0",
|
"istanbul": "^0.3.0",
|
||||||
"jison": "~0.3.0",
|
"jison": "~0.3.0",
|
||||||
"lint-staged": "^9.5.0",
|
"mocha": "~1.20.0",
|
||||||
"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",
|
|
||||||
"typescript": "^3.4.3",
|
|
||||||
"underscore": "^1.5.1",
|
"underscore": "^1.5.1",
|
||||||
"webpack": "^1.12.6",
|
"webpack": "^1.12.6",
|
||||||
"webpack-dev-server": "^1.12.1"
|
"webpack-dev-server": "^1.12.1"
|
||||||
},
|
},
|
||||||
"main": "lib/index.js",
|
"main": "lib/index.js",
|
||||||
"types": "types/index.d.ts",
|
|
||||||
"browser": {
|
|
||||||
".": "./dist/cjs/handlebars.js",
|
|
||||||
"./runtime": "./dist/cjs/handlebars.runtime.js"
|
|
||||||
},
|
|
||||||
"bin": {
|
"bin": {
|
||||||
"handlebars": "bin/handlebars"
|
"handlebars": "bin/handlebars"
|
||||||
},
|
},
|
||||||
"scripts": {
|
"scripts": {
|
||||||
"format": "prettier --write '**/*.js' && eslint --fix .",
|
"test": "grunt"
|
||||||
"check-format": "prettier --check '**/*.js'",
|
|
||||||
"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",
|
||||||
@@ -101,31 +73,5 @@
|
|||||||
"buildConfig": {
|
"buildConfig": {
|
||||||
"minify": true
|
"minify": true
|
||||||
}
|
}
|
||||||
},
|
|
||||||
"files": [
|
|
||||||
"bin",
|
|
||||||
"dist/*.js",
|
|
||||||
"dist/amd/**/*.js",
|
|
||||||
"dist/cjs/**/*.js",
|
|
||||||
"lib",
|
|
||||||
"print-script",
|
|
||||||
"release-notes.md",
|
|
||||||
"runtime.js",
|
|
||||||
"types/*.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
|
|
||||||
};
|
|
||||||
+135
-670
File diff suppressed because it is too large
Load Diff
Vendored
-5
@@ -1,5 +0,0 @@
|
|||||||
import Handlebars = require('handlebars')
|
|
||||||
|
|
||||||
declare module "handlebars/runtime" {
|
|
||||||
|
|
||||||
}
|
|
||||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user