We have to remove `--failAfterWarnings` from our Rollup integration-test,
because Typescript, when targeting es5, will use global `this` for transpilation.
Rollup warns about this, since it replaces `this` with `undefined`:
```
src/index.js → dist/bundle.js...
(!) `this` has been rewritten to `undefined`
https://rollupjs.org/guide/en/#error-this-is-undefined
../../../node_modules/@handlebars/parser/dist/esm/printer.js
1: var __spreadArrays = (this && this.__spreadArrays) || function () {}
```
See https://github.com/handlebars-lang/handlebars-parser/releases/tag/v2.0.0
* Updated lock-file to fix https://github.com/npm/cli/issues/4859.
* Updated integration-tests to webpack 5 to fix
https://github.com/webpack/webpack/issues/14532.
* Added `mode` to webpack-integration-tests to avoid
the warning `The 'mode' option has not been set...`.
* Replaced outdated `grunt-bg-shell`-package to get rid of
coffee-script warnings
As explained in issue #1844 and in issue
https://github.com/webpack/webpack/issues/15007#issuecomment-996615250,
the way we used the `browser`-field was wrong.
The main reason for using the `browser`-field is the requirement of
`require('fs')` in the main-entry-file.
The workaround for this was using `require('handlebars/lib/handlebars')`,
but now it will also work via `require('handlebars')` for bundlers that
respect the `browser`-field.
The `"./runtime"`-config was removed, because it didn't have any effect.
In order to detect regressions, the webpack-integration test was
extended to test with different webpack versions.
Fixes#1174Closes#1844
By adding the `.js`-extension to the bin-file, IDEs will
know that js code-highlighting should be applied to the
file, which makes it easier for devs to read the code.
Fixes the following error when running integration-tests:
```
npm ERR! code ERESOLVE
npm ERR! ERESOLVE unable to resolve dependency tree
npm ERR!
npm ERR! While resolving: webpack-test@1.0.0
npm ERR! Found: handlebars@5.0.0-alpha.1
npm ERR! node_modules/handlebars
npm ERR! dev handlebars@"file:../../.." from the root project
npm ERR!
npm ERR! Could not resolve dependency:
npm ERR! peer handlebars@">= 1.3.0 < 5" from handlebars-loader@1.7.1
npm ERR! node_modules/handlebars-loader
npm ERR! dev handlebars-loader@"^1.7.1" from the root project
npm ERR!
```
If `global` is used and handlebars is compiled for browser
usage without a Node.js `global` polyfill, handlebars
fails with a `global is undefined` error.
Fixes#1593
The SauceLabs IE setup has problems and does not work
with the endpoints that we use to run them. This is a Saucelabs problem, but it has been there for a year now. Until we use another API, I will simply remove the browsers
somehow the variable "$i" gets overwritten in integration-testing/multi-nodejs-test/test.sh:20, which is why we now rename it to a more meaningful variable
Extracts the parser to `@handlebars/parser`, where it can be shared
between different implementations. This means that e.g. Glimmer/Ember
will be able to iterate on new features without forcing Handlebars to
adopt them immediately, and vice versa. All implementors will be able to
absorb changes as it makes sense for them.
- Add spec/tmp directory with .gitkeep file to indicate the folder is intentional
- Add the folder contents to .gitignore
- Use this folder to output the sourcemap file during bin tests. This file is a sideeffect of the main test
- adds full unit tests for all cli options
- demonstrates that nothing changes between minimist and yargs except a minor order change in the --help text
- proves b9c4b253e works the same as before
Co-authored-by: fabb <fabb@users.noreply.github.com>
- some indirect dependencies install @types packages which are not compatible with the older typescript.
- adjusted test's tsconfig to not pick these up automatically, as the actual .d.ts does not depend on these external types.
- up to now, the existance of the SAUCE_USERNAME was checked
but this variable is even present in pull-requests from other
repos. This means that builds fail, because the access key
is not there.
This change looks for SAUCE_ACCESS_KEY instead, which is
a secure variable, only present in build originating from
the handlebars.js repo.
- helpers should always be a function, but in #1639 one seems to
be undefined. This was not a problem before 4.6 because helpers
weren't wrapped then.
Now, we must take care only to wrap helpers (when adding
the "lookupProperty" function to the options), if they
are really functions.
This commmit adds the runtime options
- `allowProtoPropertiesByDefault` (boolean, default: false) and
- `allowProtoMethodsByDefault` (boolean, default: false)`
which can be used to allow access to prototype properties and
functions in general.
Specific properties and methods can still be disabled from access
via `allowedProtoProperties` and `allowedProtoMethods` by
setting the corresponding values to false.
The methods `constructor`, `__defineGetter__`, `__defineSetter__`, `__lookupGetter__`
and the property `__proto__` will be disabled, even if the allow...ByDefault-options
are set to true. In order to allow access to those properties and methods, they have
to be explicitly set to true in the 'allowedProto...'-options.
A warning is logged when the a proto-access it attempted and denied
by default (i.e. if no option is set by the user to make the access
decision explicit)
Disallow access to prototype properties and methods by default.
Access to properties is always checked via
`Object.prototype.hasOwnProperty.call(parent, propertyName)`.
New runtime options:
- **allowedProtoMethods**: a string-to-boolean map of property-names that are allowed if they are methods of the parent object.
- **allowedProtoProperties**: a string-to-boolean map of property-names that are allowed if they are properties but not methods of the parent object.
```js
const template = handlebars.compile('{{aString.trim}}')
const result = template({ aString: ' abc ' })
// result is empty, because trim is defined at String prototype
```
```js
const template = handlebars.compile('{{aString.trim}}')
const result = template({ aString: ' abc ' }, {
allowedProtoMethods: {
trim: true
}
})
// result = 'abc'
```
Implementation details: The method now "container.lookupProperty"
handles the prototype-checks and the white-lists. It is used in
- JavaScriptCompiler#nameLookup
- The "lookup"-helper (passed to all helpers as "options.lookupProperty")
- The "lookup" function at the container, which is used for recursive lookups in "compat" mode
Compatibility:
- **Old precompiled templates work with new runtimes**: The "options.lookupPropery"-function is passed to the helper by a wrapper, not by the compiled templated.
- **New templates work with old runtimes**: The template contains a function that is used as fallback if the "lookupProperty"-function cannot be found at the container. However, the runtime-options "allowedProtoProperties" and "allowedProtoMethods" only work with the newest runtime.
BREAKING CHANGE:
- access to prototype properties is forbidden completely by default
- I don't think it makes much sense. In some cases,
it is more readable to wrap property access in quotes,
some times not, but there is no universal rule
for that.
- a promises "catch"-function should not be wrapped, but it has to
be, if "allow-keywords" is set to false
- an "if"-helper should be wrapped, but it is not allowed to be
if "allow-keywords" is set to true (default).
- move dtslint (checkTypes) away from Gruntfile.js
(as it disturbs debugging `grunt`)
and call it directly as npm-script in travis-ci
- re-group task definition in Gruntfile.js
- use a multi-job travis build to
run linting, format, dtslint and tests
in parallel
- run only "npm test" on appveyor
- rename Grunt-tasks for be more descriptive
- SAUCE_USERNAME is not a secret variable anymore
it can be easily guessed anyway and the
[secure] value messes up with a lot of the
log output
- linting on commit disable during transition
- add prettier to do formatting
- add eslint-config-prettier to
disable rules conflicting with prettier
- remove eslint from grunt workflow
- use lint-stage to lint and format
on precommit
- use eslint and prettier in travis directly
- remove rules that are already part of
the "recommended" ruleset
That rational is that eslint and prettier should be run in
Travis-CI, on commit and as IDE integration (highlighting
errors directlry). They don't need to be run along with
test-cases. Getting linting errors when running the tests
because of missing semicolons is just annoying, but doesn't
help the overall code-quality.
Reintroduce "merge" function, no called "mergeIfNeeded", that only creates a new partials
object if both "env.partials" and "options.partials" are set.
closes#1598
- tests are not compiled with babel and must thus be in
es5
- we don't use polyfills, so we need to make sure no
functions aren't used that are not supported by popular browsers. (like Object.assign in Safari and IE11)
- Boths are errors that usually only appear when running
tests in SauceLabs, which happens only on _after_
merging a PR.
* Resolve eslint deprecation warning
There was a DeprecationWarning message from eslint saying that `ecmaFeatures` property has
been deprecated.
Moved it under the `parserOptions` as per recommended here -
https://eslint.org/docs/user-guide/migrating-to-2.0.0.
* Set escmaVersion = 6
* Use ES6 built-in global variables
* Remove flags in favor of ecmaVersion
When authoring tooling that parses Handlebars files and emits Handlebars
files, you often want to preserve the **exact** formatting of the input.
The changes in this commit add a new method to the `Handlebars`
namespace: `parseWithoutProcessing`. Unlike, `Handlebars.parse` (which
will mutate the parsed AST to apply whitespace control) this method will
parse the template and return it directly (**without** processing
😉).
For example, parsing the following template:
```hbs
{{#foo}}
{{~bar~}} {{baz~}}
{{/foo}}
```
Using `Handlebars.parse`, the AST returned would have truncated the
following whitespace:
* The whitespace prior to the `{{#foo}}`
* The newline following `{{#foo}}`
* The leading whitespace before `{{~bar~}}`
* The whitespace between `{{~bar~}}` and `{{baz~}}`
* The newline after `{{baz~}}`
* The whitespace prior to the `{{/foo}}`
When `Handlebars.parse` is used from `Handlebars.precompile` or
`Handlebars.compile`, this whitespace stripping is **very** important
(these behaviors are intentional, and generally lead to better rendered
output).
When the same template is parsed with
`Handlebars.parseWithoutProcessing` none of those modifications to the
AST are made. This enables "codemod tooling" (e.g. `prettier` and
`ember-template-recast`) to preserve the **exact** initial formatting.
Prior to these changes, those tools would have to _manually_ reconstruct
the whitespace that is lost prior to emitting source.
The use of arrays was incorrect for the data type and causing problems when hash keys conflicted with array behaviors.
Fixes#1194
(cherry picked from commit 768ddbd661)
The use of arrays was incorrect for the data type and causing problems when hash keys conflicted with array behaviors.
Fixes#1194
(cherry picked from commit 768ddbd661)
fixes#1548
- add a guard to show readable syntax error for if / unless helper
- prevents against 3 different errors that can be generated by different systax errors
In 4.4.4 the block-contents was matched with an eager match, which means
that with multiple raw-blocks of the same kind, the block was spanned
over the first ending-tag until the last one.
This commit replaces this by a non-eager match.
closes#1579
In 4.4.4 the block-contents was matched with an eager match, which means
that with multiple raw-blocks of the same kind, the block was spanned
over the first ending-tag until the last one.
This commit replaces this by a non-eager match.
closes#1579
* Added support for iterable object in {{#each}} helper
Currently {{#each}} helper supports either arrays, or objects,
however nowadays you can define custom iterable objects by overriding
a special method called Symbol.iterator, which results in empty result
being rendered.
* improved a test for iterables in {{#each}} returning empty result
* #each helper: using ES5 instead of generator functions in tests
* #each helper: using ES5 in the helper itself
- "container" is an internal object that is most likely
not accessible through templateing (unlike the proto of "Object", which might be.)
In order to prevent overriding this method, we
use "propertyIsEnumerable" from the constructor.
- context.propertyIsEnumerable can be replaced
via __definedGetter__
- This is a fix specific to counter a known RCE exploit.
Other fixes will follow.
closes#1563
- The version-range above have compiler version 7 and
precompiled templates expecte the (block)
HelperMissing-functions in "helpers" and not in "container.hooks".
- Handlebars now accepts precompiled templates of version 7.
- If a precompiled template with version 7 is loaded,
the (block)HelperMissing-functions are kept in "helpers"
related to #1553
- registering helpers on an instance retrieved via
`import`, compiling the template on an instance
retrieved via `require`
- using `@roundingwellos/babel-plugin-handlebars-inline-precompile` to load plugins inline
- Handlebars.VM is actually not part of the API,
but Handlebars.VM.resolvePartial is mentioned
in the documentation and is thus now treated
as part of the API.
Closes#1534
I suspect that the current problems with
saucelabs are due to a change transitive
dependency, but I'm not sure. I'm not
adding the package-lock.json to ensure
that this does not happen in the future.
- The "lookup" helper could also be used to run a remote code execution
by manipulating the template. The same check as for regular
path queries now also is done in the "lookup"-helper
The test is a simple addition to the existing tests. It should ensure
that the built Handlebars artifact only uses language features that are
available in old versions of NodeJS. A simple program and the
precompiler are started with NodeJS 0.10 to 11
This commit fixes a Remote Code Execution (RCE) reported by
npm-security. Access to non-enumerable "constructor"-properties
is now prohibited by the compiled template-code, because this
the first step on the way to creating and execution arbitrary
JavaScript code.
The vulnerability affects systems where an attacker is allowed to
inject templates into the Handlebars setup.
Further details of the attack may be disclosed by npm-security.
Closes#1267Closes#1495
This commit fixes a Remote Code Execution (RCE) reported by
npm-security. Access to non-enumerable "constructor"-properties
is now prohibited by the compiled template-code, because this
the first step on the way to creating and execution arbitrary
JavaScript code.
The vulnerability affects systems where an attacker is allowed to
inject templates into the Handlebars setup.
Further details of the attack may be disclosed by npm-security.
Closes#1267Closes#1495
- Import typings from DefinitelyTyped into repo.
- Update typings header to cite contributors from history and git blame.
- Update package.json to add typings field.
- grunt -> 1
- grunt-contrib-watch -> 1
- mocha -> 5
- in common.js: define "global" , see mochajs/mocha#1159
- in builtins.js: revert "console.log" to old value just
after using the mock (in log-helper tests), because
mocha calls "console.log" on failure, before
"afterEach"
- grunt -> 1
- grunt-contrib-watch -> 1
- mocha -> 5
- in common.js: define "global" , see mochajs/mocha#1159
- in builtins.js: revert "console.log" to old value just
after using the mock (in log-helper tests), because
mocha calls "console.log" on failure, before
"afterEach"
This is an attempt to provide a valid package.json-file to the shim
repository for bower, in order to support `bower-away`
see components/handlebars.js#24
closes#1391
uglify-js is an optional dependency and should be treated as such.
This commit gracefully handles MODULE_NOT_FOUND errors while loading
uglify.
- Check for existing uglify-js (and load uglify-js) only if minification
was activated
- Use "require.resolve" to check if uglify exists. Otherwise, a missing
dependency of uglify-js would cause the same behavior as missing
uglify-js. (Only a warning, no error)
- The code to load and run uglify is put into a single for readability
purposes
- Tests use a mockup Module._resolveFilename to simulate the missing module.
This function is used by both "require" and "require.resolve", so both
are mocked equally.
(cherry picked from commit d5caa56)
closes#1391
uglify-js is an optional dependency and should be treated as such.
This commit gracefully handles MODULE_NOT_FOUND errors while loading
uglify.
- Check for existing uglify-js (and load uglify-js) only if minification
was activated
- Use "require.resolve" to check if uglify exists. Otherwise, a missing
dependency of uglify-js would cause the same behavior as missing
uglify-js. (Only a warning, no error)
- The code to load and run uglify is put into a single for readability
purposes
- Tests use a mockup Module._resolveFilename to simulate the missing module.
This function is used by both "require" and "require.resolve", so both
are mocked equally.
Closes#1233
- Handle path-separators properly. Use "path.sep" instead of "/".
Or use "require.resolve()" if possible
- Use "execFile" instead of "exec" to run the Handlebars executable.
This prevents problems due to (missing) shell escaping.
- Use explicit call to "node" in order to run the executable on Windows.
- Add "appveyor"-CI in order to run regular tests on Windows.
Fixes#1327
- This commit creates a shallow copy of the "options" passed to
Handlebars.compile() in order to prevent modifications
- Note that "new Handlebars.Compiler().compile(..., options)" still
modify the options object. This might change in the future, if
anybody needs a fix for that.
Fixes#1331
Due to the way, "bin"-files are distributed into the node_modules/.bin
directory on Windows, the task "test:cov" did not work on Windows.
This commit uses the node-script directly.
Closes#1341
If the @partial-block is called as parameter of a helper (like in
{{#if @partial-block}}...{{/if}}, the partialBlockWrapper is executed
without "options"-parameter. It should still work in without an error
in such a case.
Fixes#1319
Original behaviour:
- When a block-helper was called on a null-context, an empty object was used
as context instead. (#1093)
- The runtime verifies that whether the current context equals the
last context and adds the current context to the stack, if it is not.
This is done, so that inside a block-helper, the ".." path can be used
to go back to the parent element.
- If the helper is called on a "null" element, the context was added, even
though it shouldn't be, because the "null != {}"
Fix:
- The commit replaces "null" by the identifiable "container.nullContext"
instead of "{}". "nullContext" is a sealed empty object.
- An additional check in the runtime verifies that the context is
only added to the stack, if it is not the nullContext.
Backwards compatibility within 4.0.x-versions:
- This commit changes the compiler and compiled templates would not work
with runtime-versions 4.0.0 - 4.0.6, because of the "nullContext"
property. That's way, the compiled code reads
"(container.nullContext || {})" so that the behavior will degrade
gracefully with older runtime versions: Everything else will work
fine, but GH-1319 will still be broken, if you use a newer compiler
with a pre 4.0.7 runtime.
- This export will be transpiled by Babel for the cjs distribution,
but will enable others to use a pure ES6 module distribution
- Instanbul: Ignore "parser.js" for coverage reporting. This file was ignored before
via annotation, but this has no effect anymore due to the above change
- Remove istanbul annotation from `parser-prefix` (@nknapp)
Squashed by @nknapp
(cherry picked from commit 508347e)
- This export will be transpiled by Babel for the cjs distribution,
but will enable others to use a pure ES6 module distribution
- Instanbul: Ignore "parser.js" for coverage reporting. This file was ignored before
via annotation, but this has no effect anymore due to the above change
- Remove istanbul annotation from `parser-prefix` (@nknapp)
Squashed by @nknapp
- Multiple partial-blocks at different nesting levels
- Calling partial-blocks twice with nested partial-blocks
- Calling the partial-block from within the #each-helper
- nested inline partials with partial-blocks on different nesting levels
- nested inline partials (twice at each level)
Fixes#1252
- This fix treats partial-blocks more like closures and uses the closure-context of
the "invokePartial"-function to store the @partial-block for the partial.
- Adds a tes for the fix
Avoid duplicate // sourceMappingURL=... lines when minifying AND
generating a map. UglifyJS2 will write the line when minifying.
(cherry picked from commit 660a117)
Closes#1302
While trying to answer #1302, I noticed that the compiler-api example did not work in (because `nameLookup` is actually at the prototype). This example has a jsfiddle that proves it is working.
It does not provide an solve the exact problem of the reporter, but it answers the question.
Original PR by @travnels, commit-message edited by @nknapp
* Upgraded eslint to 19.0.0
* Cleaned up duplicate rules 'no-extra-parens', 'quote-props'
* eslint rule 'no-empty-label' was replaced.
Rule 'no-empty-label' was removed and replaced by: ‘no-labels’. ‘no-labels’ already in the project
* eslint rule 'space-after-keywords' has been replaced
Rules 'space-after-keywords' and 'space-return-throw-case' wer removed and replaced by ‘keyword-spacing’.
* Added parsoer-option: sourceType='module'
* Add unnecessary=false to 'quote-props' to remove warnings about unnecessarily quoted property.
Code corrections
* helpers.js: unused variable 'depthString' removed, detected by new eslint
According to npm's documentation[1], dependencies on github
repositories are declared with the following syntax:
"module": "person/module"
This commit changes the package.json syntax on istanbul's dependency,
to follow the documentation.
[1] https://docs.npmjs.com/files/package.json#github-urls
Fixes#1284
Appearently, there is a use-case of stringifying the error in order to
evaluated its properties on another system. There was a regression
from 4.0.5 to 4.0.6 that the column-property of compilation errors
was not enumerable anymore in 4.0.6 (due to commit 20c965c) and
thus was not included in the output of "JSON.stringify".
The root cause of #1218 is that `invokePartial` creates a stack of data frames
for nested partial blocks, but `resolvePartial` always uses the value at top of
the stack without "popping" it. The result is an infinite recursive loop, as
references to `@partial-block` in the partial at the top of the stack resolve to
itself.
So, walk up the stack of data frames when evaluating. This is accomplished by
1) setting the `partial-block` property to `noop` after use and
2) using `_parent['partial-block']` if `partial-block` is `noop`
Fix#1218
The root cause of #1218 is that `invokePartial` creates a stack of data frames
for nested partial blocks, but `resolvePartial` always uses the value at top of
the stack without "popping" it. The result is an infinite recursive loop, as
references to `@partial-block` in the partial at the top of the stack resolve to
itself.
So, walk up the stack of data frames when evaluating. This is accomplished by
1) setting the `partial-block` property to `noop` after use and
2) using `_parent['partial-block']` if `partial-block` is `noop`
Fix#1218
Users can utilize the UMD library if they are still using require.js and if they need to have specific modules, they can consume the cjs or es6 modules via webpack or similar.
Fix for #1096
Allows for ] literal characters to be used within [] IDs by prefixing them with the \ character. `\` literal at the end of the may be referenced by the `\\` sequence if conflicting. Under most circumstances the `\\` sequence will continue to work.
Potentially breaking change for users of [] ids that have `\\` anywhere in the id or `\` at the end of the id.
Fixes#1092
If a decorator is used within a partial but not in the calling template, the hash is not passed in. For now error on the side of always including as just assigning values has minimal overhead.
Fixes#1089
Allows for partials to be defined within the current template to allow for localized code reuse as well as for conditional behavior within nested partials.
Fixes#1018
These allow for a given block to be wrapped in helper methods or metadata and allow for more control over the current container and method before the code is run.
This allows for failover for missing partials as well as limited templating ability through the `{{> @partial-block }}` partial special case.
Partial fix for #1018
There is no real need for us to do `.call(container` other than for backwards compatibility with legacy versions. Using the 4.x release as a chance to optimize this behavior.
Certain optimizations for simple templates could result in objects returned by helpers returned rather than their string representation, resulting in some odd edge cases. This ensures that strings are always returned from the API for consistency.
Fixes#1054.
This allows for `{{helper foo}}` to still operate under strict mode when `foo` is not defined on the context. This allows helpers to perform whatever existence checks they please so patterns like `{{#if foo}}{{foo}}{{/if}}` can be used to protect against missing values.
Fixes#1063
Creating a new depth value seems to confuse users as they don’t expect things like `if` to require multiple `..` to break out of. With the change, we avoid pushing a context to the depth list if it’s already on the top of the stack, effectively removing cases where `.` and `..` are the same object and multiple `..` references are required.
This is a breaking change and all templates that utilize `..` will have to check their usage and confirm that this does not break desired behavior. Helper authors now need to take care to return the same context value whenever it is conceptually the same and to avoid behaviors that may execute children under the current context in some situations and under different contexts under other situations.
Fixes#1028
Adds multiple variable support and the ability to set statement level logging semantics.
This breaks that logger API, cleaning up the manner in which enums are set, but the other behaviors are backwards compatible.
Fixes#956
The ‘ character would cause invalid javascript to be generated as it was not properly escaped. Switching to JSON.stringify safely handles all potential unescaped cases.
There appears to be a bug in our use of jison causing the parent location information to be reported to programs. I wasn’t able to work through what might be causing this so instead using the location information of the statements collection to generate the proper location information.
This is a bit of a hack but we are very far behind on the Jison release train and upgrading will likely be a less than pleasant task that doesn’t provide us much benefit.
Fixes#1024
There is two consecutive tests with the same input data: "{{ foo bar \'baz\' }}"
I suppose the first test should be about testing double quoted string.
I've written a set of helpers which implement layout blocks similar to Jade, Jinja, Swig, Twig, and others. It seems to be gaining some popularity (around 10k npm downloads per month at present) and I would be honored to have it included in the in-the-wild list in case it may prove useful to others.
Converts the tool chain to use babel, eslint, and webpack vs. the previous proprietary solutions.
Additionally begins enforcing additional linting concerns as well as updates the code to reflect these rules.
Fixes#855Fixes#993
This allows us to avoid creating unnecessary AST nodes and avoids things like isHelper.
Side effect of these changes is that @data functions can now have data parameters passed to them.
Avoids parsing against SubExpressions and instead inlines the content that a subexpression otherwise would have. This can still be based via duck typing so should not add much overhead to the compiler.
Causes templates to throw when lookup fields are not defined within the context. Strict mode will throw when any field is omitted. assumeObjects mode maintains the existing behavior of outputting an empty response when fields are not defined but allows for performance/size optimizations by not doing safety checks for intermediate objects in the lookup chain.
Strict mode effectively disables the helperMissing and inverse handling for blockHelperMissing as templates will throw rather than call those features for missing data fields.
Fixes#651Fixes#805
Fixes a very specific error case where deduped children won’t receive the depths object due to it being omitted by the caller when optimizing.
Fixes#926
Rather than keeping state in the AST, which requires some gymnastics, we create a separate visitor flow which does the top down iteration necessary to calculate all of the state needed for proper whitespace control evaluation.
This is a breaking change for string mode users as there is no longer a distinct type for data parameters. Instead data consumers should look for the @ prefix value.
Allow the precompiler to generate source maps when the srcFile parameter is passed.
This refactors large chunks of the code generation pipeline, allowing metadata to be associated with code chunks as well as breaking out much of the code generation logic into a separate helper.
Allows for us to play nicely in environments such as Node that could have multiple versions of the library loaded. Also allows for implementors to provide their own behavior, provided they know what they are doing.
Fixes#886
We don’t want to remove these as the generic code may need it in the future, but these code paths are not triggered through the existing language constructs.
This disables the standalone partial indent behavior required by the Mustache spec and allows for users to utilize partials in the same manner as under 1.x.
Fixes#858
Allows users to chain multiple helpers together using their inverse callbacks. I.e.
```
{{#if foo}}
{{else if bar}}
{{else}}
{{/if}}
```
The control flow here effectively causes the helpers to be nested. The above is actually syntactic sugar for this:
```
{{#if foo}}
{{else}}
{{#if bar}}
{{else}}
{{/if}}
{{/if}}
```
Any helper may be used in this manner, the only requirement is they support normal calls and inverse calls.
Introduces a breaking change in that `{{else foo}}` may no longer be used as a root level operator. Instead `{{^foo}}` must be used.
Fixes#72.
We already have to track these behaviors for the standalone parsing and rather than having two whitespace pruning implementations this moves all of the behavior into one place.
Fixes#852
They are no longer duplicated with the new helper calling pattern and this also introduced stack corruption issues due to improper value lookups.
Fixes#767Fixes#768
Provides the mustache behavior of recursive lookup without the use of depthed paths.
Note that this does incur a fairly dramatic performance penalty for depthed queries.
- Move the lookup null protection out of `nameLookup` and into that contexts that are aware of the needs for falsy vs. not displayed values.
- Optimize lookup for nested path operations
Fixes#731
Attempts to avoid some of the Node vs. ES6 confusion between the different styles within the application.
Also adds some simple tests in addition to the integration test.
All helper calls will have access to `options.name` which is the first id value of the mustache operation.
As part of this the helperMissing call has been simplified to remove the indexed name in order to optimize the call. This is a breaking change.
Fixes#634
Handlebars now supports subexpressions.
{{foo (bar 3)}}
Subexpressions are always evaluated as helpers; if
`3` were omitted from the above example, `bar`
would be invoked as a param-less helper, even
though a top-levell `{{bar}}` would be considered
ambiguous.
The return value of a subexpression helper is
passed in as a parameter of a parent subexpression
helper, even in string params mode. Their type,
as listed in `options.types` or `options.hashTypes`
in string params mode, is "sexpr".
The main conceptual change in the Handlebars code
is that there is a new AST.SexprNode that manages
the params/hash passed into a mustache, as well
as the logic that governs whether that mustache
is a helper invocation, property lookup, etc.
MustacheNode, which used to manage this stuff,
still exists, but only manages things like
white-space stripping and whether the mustache
is escaped or not. So, a MustacheNode _has_
a SexprNode.
The introduction of subexpressions is fully
backwards compatible, but a few things needed
to change about the compiled output of a template
in order to support subexpressions. The main one
is that the options hash is no longer stashed in
a local `options` var before being passed to
either the helper being invoked or the
`helperMissing` fallback. Rather, the options
object is inlined in these cases. This does
mean compiled template sizes will be a little
bit larger, even those that don't make use of
subexpressions, but shouldn't have any noticeable
impact on performance when actually rendering
templates as only one of these inlined objects
will actually get evaluated.
Give users the index for properties. When I am rendering a radio button I use key-value pairs, but I can't use either as unique identifiers because they likely contain invalid identifier characters. I added "first" as an index as well, but have no particular use case for first. Since there is no way to detect "last", I didn't add that property.
Escaped-escape mustaches ("\\{{") immediately following escaped
mustaches ("\{{") were being handled incorrectly.
Fix the lookahead to make sure yytext still contains the appropriate
slashes when we pop out of <emu> so they can be handled consistently
by the initial state.
Allows for monkey patching (under ES5 systems). This somewhat mirrors
the proposed behavior in https://github.com/square/es6-module-transpiler/issues/37
but applies the behavior via manual code changes rather than compiler
support.
Using prototype has a large performance impact for the common case of a
sparse set of private variable data points. Rather than incurring the
overhead of creating and walking the prototype tree for this, performing
an extend by copy.
Using string.toString() will throw errors in current versions of Safari
(6.0.5 currently) for some values. The error is a particularly cryptic
"Type Error: type error", which no indication as to the value that
caused the error. By using the '' + string form of coercion the error
doesn't seem to occur.
Depending on the browser used there is a sizable performance increase
in using the concatenation form of coercion. In instances where there
is not a performance improvement (i.e. Firefox), the speed difference
is entirely negligable. See: http://jsperf.com/convert-to-string-bj/3
The basic strategy is that there will be a global Handlebars object for
the browser build, and that object will have a `compile` on it which
uses its environment in the compiler.
It will also be possible to glue things together manually by using the
AMD build and passing the environment to `compile` directly. Some of
these details are TBD.
The idea is that the environment wraps up the mutable stuff in
Handlebars (like the helpers) and that you could theoretically create a
new one at any time and pass it in to Handlebars.template.
Every test makes a new environment and uses it in template compilation.
The install instructions in the readme were still pointing to the GitHub downloads page, which is deprecated and out of date.
Updated to point to the official site, which has a big download button.
Include program id and depth on the generated wrapper objects. This
allows helpers who are passed these objects to differentiate between
helpers for cases where they may want to cache the generated DOM
structure.
Before creating a pull-request, please check https://github.com/handlebars-lang/handlebars.js/blob/master/CONTRIBUTING.md first.
Generally we like to see pull requests that
- [ ] Please don't start pull requests for security issues. Instead, file a report at https://www.npmjs.com/advisories/report?package=handlebars
- [ ] 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)
- [ ] Have good commit messages
- [ ] Have tests
- [ ] Have the [typings](https://www.typescriptlang.org/docs/handbook/declaration-files/introduction.html) (types/index.d.ts) updated on every API change. If you need help, updating those, please mention that in the PR description.
- [ ] Don't significantly decrease the current code coverage (see coverage/lcov-report/index.html)
- [ ] Please target the `master` branch in the PR.
Please refer to our [Security Policy](https://github.com/handlebars-lang/handlebars.js/blob/master/SECURITY.md).
## Reporting Issues
Please refer to our [FAQ](https://github.com/handlebars-lang/handlebars.js/blob/master/FAQ.md) for common issues that people run into.
Should you run into other issues with the project, please don't hesitate to let us know by filing an [issue][issue]!
In general, we are going to ask for an **example** of the problem failing, which can be as simple as a jsfiddle/jsbin/etc. We've put together a jsfiddle **[template][jsfiddle]** to ease this. (We will keep this link up to date as new releases occur, so feel free to check back here).
Pull requests containing only failing tests demonstrating the issue are welcomed and this also helps ensure that your issue won't regress in the future once it's fixed.
Documentation issues on the [handlebarsjs.com](https://handlebarsjs.com) site should be reported on [handlebars-lang/docs](https://github.com/handlebars-lang/docs).
## Branches
- The branch `master` contains the current development version (v5).
- The branch `4.x` contains the previous stable version. Only critical bugfixes are backported there.
## Pull Requests
We also accept [pull requests][pull-request]!
Generally we like to see pull requests that
- 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)
- Have [good commit messages](http://tbaggery.com/2008/04/19/a-note-about-git-commit-messages.html)
- Have tests
- Don't significantly decrease the current code coverage (see coverage/lcov-report/index.html)
## Building
To build Handlebars.js you'll need Node.js installed.
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`.
Project dependencies may be installed via `npm install`.
To build Handlebars.js from scratch, run `npm run build` in the root of the project. That will compile CJS modules via SWC and bundle UMD distributions via rspack, outputting results to the dist/ folder. To run tests, use `npm test`.
If you notice any problems, please report them to the GitHub issue tracker at
See our guidelines on [reporting issues](https://github.com/handlebars-lang/handlebars.js/blob/master/CONTRIBUTING.md#reporting-issues).
## Why isn't my Mustache template working?
Handlebars deviates from Mustache slightly on a few behaviors. These variations are documented in our [readme](https://github.com/handlebars-lang/handlebars.js#differences-between-handlebarsjs-and-mustache).
## Why is it slower when compiling?
The Handlebars compiler must parse the template and construct a JavaScript program which can then be run. Under some environments such as older mobile devices this can have a performance impact which can be avoided by precompiling. Generally it's recommended that precompilation and the runtime library be used on all clients.
## Why doesn't this work with Content Security Policy restrictions?
When not using the precompiler, Handlebars generates a dynamic function for each template which can cause issues with pages that have enabled Content Policy. It's recommended that templates are precompiled or the `unsafe-eval` policy is enabled for sites that must generate dynamic templates at runtime.
## How can I include script tags in my template?
If loading the template via an inlined `<script type="text/x-handlebars">` tag then you may need to break up the script tag with an empty comment to avoid browser parser errors:
```html
<scripttype="text/x-handlebars">
foo
<scr{{!}}iptsrc="bar"></scr{{!}}ipt>
</script>
```
It's generally recommended that templates are served through external, precompiled, files, which do not suffer from this issue.
## Why are my precompiled scripts throwing exceptions?
When using the precompiler, it's important that a supporting version of the Handlebars runtime be loaded on the target page. In version 1.x there were rudimentary checks to compare the version but these did not always work. This is fixed under 2.x but the version checking does not work between these two versions. If you see unexpected errors such as `undefined is not a function` or similar, please verify that the same version is being used for both the precompiler and the client. This can be checked via:
```sh
handlebars --version
```
If using the integrated precompiler and
```javascript
console.log(Handlebars.VERSION);
```
On the client side.
We include the built client libraries in the npm package for those who want to be certain that they are using the same client libraries as the compiler.
Should these match, please file an issue with us, per our [issue filing guidelines](https://github.com/handlebars-lang/handlebars.js/blob/master/CONTRIBUTING.md#reporting-issues).
## How do I load the runtime library when using AMD?
The `handlebars.runtime.js` file includes a UMD build, which exposes the library as both the module root and the `default` field for compatibility.
Handlebars.js is an extension to the [Mustache templating language](http://mustache.github.com/) created by Chris Wanstrath. Handlebars.js and Mustache are both logicless templating languages that keep the view and the code separated like we all know they should be.
Checkout the official Handlebars docs site at [http://www.handlebarsjs.com](http://www.handlebarsjs.com).
Installing
----------
Installing Handlebars is easy. Simply [download the package from GitHub](https://github.com/wycats/handlebars.js/archives/master) and add it to your web pages (you should usually use the most recent version).
Usage
-----
In general, the syntax of Handlebars.js templates is a superset of Mustache templates. For basic syntax, check out the [Mustache manpage](http://mustache.github.com/mustache.5.html).
Once you have a template, use the Handlebars.compile method to compile the template into a function. The generated function takes a context argument, which will be used to render the template.
```js
varsource="<p>Hello, my name is {{name}}. I am from {{hometown}}. I have "+
"{{kids.length}} kids:</p>"+
"<ul>{{#kids}}<li>{{name}} is {{age}}</li>{{/kids}}</ul>";
By default, the `{{expression}}` syntax will escape its contents. This
helps to protect you against accidental XSS problems caused by malicious
data passed from the server as JSON.
To explicitly *not* escape the contents, use the triple-mustache
(`{{{}}}`). You have seen this used in the above example.
Differences Between Handlebars.js and Mustache
----------------------------------------------
Handlebars.js adds a couple of additional features to make writing templates easier and also changes a tiny detail of how partials work.
### Paths
Handlebars.js supports an extended expression syntax that we call paths. Paths are made up of typical expressions and . characters. Expressions allow you to not only display data from the current context, but to display data from contexts that are descendents and ancestors of the current context.
To display data from descendent contexts, use the `.` character. So, for example, if your data were structured like:
you could display the person's name from the top-level context with the following expression:
```
{{person.name}}
```
You can backtrack using `../`. For example, if you've already traversed into the person object you could still display the company's name with an expression like `{{../company.name}}`, so:
When you pass a String as a parameter to a helper, the literal String
gets passed to the helper function.
### Block Helpers
Handlebars.js also adds the ability to define block helpers. Block helpers are functions that can be called from anywhere in the template. Here's an example:
Whenever the block helper is called it is given two parameters, the argument that is passed to the helper, or the current context if no argument is passed and the compiled contents of the block. Inside of the block helper the value of `this` is the current context, wrapped to include a method named `__get__` that helps translate paths into values within the helpers.
### Partials
You can register additional templates as partials, which will be used by
Handlebars when it encounters a partial (`{{> partialName}}`). Partials
can either be String templates or compiled template functions. Here's an
You can add comments to your templates with the following syntax:
```js
{{!Thisisacomment}}
```
You can also use real html comments if you want them to end up in the output.
```html
<div>
{{! This comment will not end up in the output }}
<!-- This comment will show up in the output -->
</div>
```
Precompiling Templates
----------------------
Handlebars allows templates to be precompiled and included as javascript
code rather than the handlebars template allowing for faster startup time.
### Installation
The precompiler script may be installed via npm using the `npm install -g handlebars`
command.
### Usage
<pre>
Precompile handlebar templates.
Usage: handlebars template...
Options:
-a, --amd Create an AMD format function (allows loading with RequireJS) [boolean]
-f, --output Output File [string]
-k, --known Known helpers [string]
-o, --knownOnly Known helpers only [boolean]
-m, --min Minimize output [boolean]
-s, --simple Output template function only. [boolean]
-r, --root Template root. Base value that will be stripped from template names. [string]
</pre>
If using the precompiler's normal mode, the resulting templates will be stored
to the `Handlebars.templates` object using the relative template name sans the
extension. These templates may be executed in the same manner as templates.
If using the simple mode the precompiler will generate a single javascript method.
To execute this method it must be passed to the using the `Handlebars.template`
method and the resulting object may be as normal.
### Optimizations
- Rather than using the full _handlebars.js_ library, implementations that
do not need to compile templates at runtime may include _handlebars.runtime.js_
whose min+gzip size is approximately 1k.
- If a helper is known to exist in the target environment they may be defined
using the `--known name` argument may be used to optimize accesses to these
helpers for size and speed.
- When all helpers are known in advance the `--knownOnly` argument may be used
to optimize all block helper references.
Performance
-----------
In a rough performance test, precompiled Handlebars.js templates (in the original version of Handlebars.js) rendered in about half the time of Mustache templates. It would be a shame if it were any other way, since they were precompiled, but the difference in architecture does have some big performance advantages. Justin Marney, a.k.a. [gotascii](http://github.com/gotascii), confirmed that with an [independent test](http://sorescode.com/2010/09/12/benchmarks.html). The rewritten Handlebars (current version) is faster than the old version, and we will have some benchmarks in the near future.
Building
--------
To build handlebars, just run `rake release`, and you will get two files
in the `dist` directory.
Upgrading
---------
When upgrading from the Handlebars 0.9 series, be aware that the
signature for passing custom helpers or partials to templates has
* Handlebars.js can be cryptic when there's an error while rendering.
* Using a variable, helper, or partial named `class` causes errors in IE browsers. (Instead, use `className`)
Handlebars in the Wild
-----------------
* [jblotus](http://github.com/jblotus) created [http://tryhandlebarsjs.com](http://tryhandlebarsjs.com) for anyone who would
like to try out Handlebars.js in their browser.
* Don Park wrote an Express.js view engine adapter for Handlebars.js called [hbs](http://github.com/donpark/hbs).
* [sammy.js](http://github.com/quirkey/sammy) by Aaron Quint, a.k.a. quirkey, supports Handlebars.js as one of its template plugins.
* [SproutCore](http://www.sproutcore.com) uses Handlebars.js as its main templating engine, extending it with automatic data binding support.
* [Ember.js](http://www.emberjs.com) makes Handlebars.js the primary way to structure your views, also with automatic data binding support.
* Les Hill (@leshill) wrote a Rails Asset Pipeline gem named [handlebars_assets](http://github.com/leshill/handlebars_assets).
Helping Out
-----------
To build Handlebars.js you'll need a few things installed.
* Node.js
* Jison, for building the compiler - `npm install jison`
* Ruby
* therubyracer, for running tests - `gem install therubyracer`
* rspec, for running tests - `gem install rspec`
There's a Gemfile in the repo, so you can run `bundle` to install rspec and therubyracer if you've got bundler installed.
To build Handlebars.js from scratch, you'll want to run `rake compile` in the root of the project. That will build Handlebars and output the results to the dist/ folder. To run tests, run `rake spec`. You can also run our set of benchmarks with `rake bench`.
If you notice any problems, please report them to the GitHub issue tracker at [http://github.com/wycats/handlebars.js/issues](http://github.com/wycats/handlebars.js/issues). Feel free to contact commondream or wycats through GitHub with any other questions or feature requests. To submit changes fork the project and send a pull request.
Handlebars provides the power necessary to let you build **semantic templates** effectively with no frustration.
Handlebars is largely compatible with Mustache templates. In most cases it is possible to swap out Mustache with Handlebars and continue using your current templates.
Checkout the official Handlebars docs site at
[handlebarsjs.com](https://handlebarsjs.com) and try our [live demo](https://handlebarsjs.com/playground.html).
## Installing
See our [installation documentation](https://handlebarsjs.com/guide/installation/).
## Usage
In general, the syntax of Handlebars.js templates is a superset
of Mustache templates. For basic syntax, check out the [Mustache
Once you have a template, use the `Handlebars.compile` method to compile
the template into a function. The generated function takes a context
argument, which will be used to render the template.
```js
varsource=
'<p>Hello, my name is {{name}}. I am from {{hometown}}. I have '+
'{{kids.length}} kids:</p>'+
'<ul>{{#kids}}<li>{{name}} is {{age}}</li>{{/kids}}</ul>';
vartemplate=Handlebars.compile(source);
vardata={
name:'Alan',
hometown:'Somewhere, TX',
kids:[
{name:'Jimmy',age:'12'},
{name:'Sally',age:'4'},
],
};
varresult=template(data);
// Would render:
// <p>Hello, my name is Alan. I am from Somewhere, TX. I have 2 kids:</p>
// <ul>
// <li>Jimmy is 12</li>
// <li>Sally is 4</li>
// </ul>
```
Full documentation and more examples are at [handlebarsjs.com](https://handlebarsjs.com/).
## 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/guide/installation/precompilation.html).
## Differences Between Handlebars.js and Mustache
Handlebars.js adds a couple of additional features to make writing
templates easier and also changes a tiny detail of how partials work.
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](https://mustache.github.io/mustache.5.html) defines the exact behavior of sections. In the case of name conflicts, helpers are given priority.
### Compatibility
There are a few Mustache behaviors that Handlebars does not implement.
- Handlebars deviates from Mustache slightly in that it does not perform recursive lookup by default. The compile time `compat` flag must be set to enable this functionality. Users should note that there is a performance cost for enabling this flag. The exact cost varies by template, but it's recommended that performance sensitive operations should avoid this mode and instead opt for explicit path references.
- The optional Mustache-style lambdas are not supported. Instead Handlebars provides its own lambda resolution that follows the behaviors of helpers.
- Handlebars does not allow space between the opening `{{` and a command character such as `#`, `/` or `>`. The command character must immediately follow the braces, so for example `{{>partial}}` is allowed but `{{>partial}}` is not.
- Alternative delimiters are not supported.
## Supported Environments
Handlebars has been designed to work in any ECMAScript 2020 environment. This includes
- Node.js
- Chrome
- Firefox
- Safari
- Edge
If you need to support older environments, use Handlebars version 4.
## Performance
In a rough performance test, precompiled Handlebars.js templates (in
the original version of Handlebars.js) rendered in about half the
time of Mustache templates. It would be a shame if it were any other
way, since they were precompiled, but the difference in architecture
does have some big performance advantages. Justin Marney, a.k.a.
[gotascii](http://github.com/gotascii), confirmed that with an
[independent test](http://sorescode.com/2010/09/12/benchmarks.html). The
rewritten Handlebars (current version) is faster than the old version,
with many performance tests being 5 to 7 times faster than the Mustache equivalent.
### Benchmarks
The project includes a comprehensive benchmark suite (powered by [tinybench](https://github.com/tinylibs/tinybench)) that measures compilation, execution, precompilation, and end-to-end performance across templates of varying size and complexity.
```bash
# Run benchmarks (auto-labels with current git branch)
npm run bench
# Run with a custom label
npm run bench -- --label my-optimization
# Filter templates by name (regex, case-insensitive)
npm run bench -- --grep "complex|recursive"
# Run only specific sections (regex, case-insensitive)
npm run bench -- --section precompil
npm run bench -- --section "compilation|precompil"
# Compare results
npm run bench:compare
# Or specify files explicitly
npm run bench:compare -- bench/results/bench-*-main.md bench/results/bench-*-feat.md
```
Results are saved as timestamped Markdown files in `bench/results/`. Each report includes ops/sec, avg latency, p50/p75/p99 percentiles, and sample counts.
Typical workflow for comparing branches:
```bash
git checkout main && npm run bench
git checkout my-feature && npm run bench
npm run bench:compare
```
When run without arguments, `bench:compare` auto-selects two result files: if a file labelled "main" exists it is always used as the baseline, otherwise the older file is the baseline. The comparison uses p75 latency for the diff to filter outliers, and marks changes with `!` (>2%) and `!!` (>5%).
## Upgrading
See [release-notes.md](https://github.com/handlebars-lang/handlebars.js/blob/master/release-notes.md) for upgrade notes.
If you are using Handlebars in production, please regularly look for issues labeled
If this label is applied to an issue, it means that the requested change is probably not a breaking change,
but since Handlebars is widely in use by a lot of people, there's always a chance that it breaks somebody's build.
## Known Issues
See [FAQ.md](https://github.com/handlebars-lang/handlebars.js/blob/master/FAQ.md) for known issues and common pitfalls.
## Handlebars in the Wild
- [apiDoc](https://github.com/apidoc/apidoc) apiDoc uses handlebars as parsing engine for api documentation view generation.
- [Assemble](https://assemble.io), by [@jonschlinkert](https://github.com/jonschlinkert) and [@doowb](https://github.com/doowb), is a static site generator that uses Handlebars.js as its template engine.
- [CoSchedule](https://coschedule.com) An editorial calendar for WordPress that uses Handlebars.js.
- [Ember.js](https://www.emberjs.com) makes Handlebars.js the primary way to structure your views, also with automatic data binding support.
- [express-handlebars](https://github.com/express-handlebars/express-handlebars) A Handlebars view engine for Express which doesn't suck.
- [express-hbs](https://github.com/TryGhost/express-hbs) Express Handlebars template engine with inheritance, partials, i18n and async helpers.
- [Ghost](https://ghost.org/) Just a blogging platform.
- [handlebars-action](https://github.com/marketplace/actions/handlebars-action) A GitHub action to transform files in your repository with Handlebars templating.
- [handlebars_assets](https://github.com/leshill/handlebars_assets) A Rails Asset Pipeline gem from Les Hill (@leshill).
- [handlebars-helpers](https://github.com/assemble/handlebars-helpers) is an extensive library with 100+ handlebars helpers.
- [handlebars-layouts](https://github.com/shannonmoeller/handlebars-layouts) is a set of helpers which implement extensible and embeddable layout blocks as seen in other popular templating languages.
- [handlebars-loader](https://github.com/pcardune/handlebars-loader) A handlebars template loader for webpack.
- [handlebars-wax](https://github.com/shannonmoeller/handlebars-wax) The missing Handlebars API. Effortless registration of data, partials, helpers, and decorators using file-system globs, modules, and plain-old JavaScript objects.
- [hbs](https://github.com/pillarjs/hbs) An Express.js view engine adapter for Handlebars.js, from Don Park.
- [html-bundler-webpack-plugin](https://github.com/webdiscus/html-bundler-webpack-plugin) The webpack plugin to compile templates, [supports Handlebars](https://github.com/webdiscus/html-bundler-webpack-plugin#using-template-handlebars).
- [incremental-bars](https://github.com/atomictag/incremental-bars) adds support for [incremental-dom](https://github.com/google/incremental-dom) as template target to Handlebars.
- [jQuery plugin](https://71104.github.io/jquery-handlebars/) allows you to use Handlebars.js with [jQuery](http://jquery.com/).
- [just-handlebars-helpers](https://github.com/leapfrogtechnology/just-handlebars-helpers) A fully tested lightweight package with common Handlebars helpers.
- [koa-hbs](https://github.com/jwilm/koa-hbs) [koa](https://github.com/koajs/koa) generator based renderer for Handlebars.js.
- [Marionette.Handlebars](https://github.com/hashchange/marionette.handlebars) adds support for Handlebars and Mustache templates to Marionette.
- [openVALIDATION](https://github.com/openvalidation/openvalidation) a natural language compiler for validation rules. Generates program code in Java, JavaScript, C#, Python and Rust with handlebars.
- [Plop](https://plopjs.com/) is a micro-generator framework that makes it easy to create files with a level of uniformity.
- [promised-handlebars](https://github.com/nknapp/promised-handlebars) is a wrapper for Handlebars that allows helpers to return Promises.
- [sammy.js](https://github.com/quirkey/sammy) by Aaron Quint, a.k.a. quirkey, supports Handlebars.js as one of its template plugins.
- [Swag](https://github.com/elving/swag) by [@elving](https://github.com/elving) is a growing collection of helpers for handlebars.js. Give your handlebars.js templates some swag son!
- [SproutCore](https://www.sproutcore.com) uses Handlebars.js as its main templating engine, extending it with automatic data binding support.
- [vite-plugin-handlebars](https://github.com/alexlafroscia/vite-plugin-handlebars) A package for Vite 2. Allows for running your HTML files through the Handlebars compiler.
- [YUI](https://yuilibrary.com/yui/docs/handlebars/) implements a port of handlebars.
## External Resources
- [Gist about Synchronous and asynchronous loading of external handlebars templates](https://gist.github.com/2287070)
Have a project using Handlebars? Send us a [pull request][pull-request]!
We recommend always using the latest versions of Handlebars and its official companion libraries to ensure your application remains as secure as possible.
## Supported Versions
| Version | Supported |
| ------- | ------------------ |
| 5.0.x | :white_check_mark: |
| 4.7.x | :white_check_mark: |
| < 4.7 | :x: |
## Reporting a Vulnerability
To report a vulnerability, please visit https://github.com/handlebars-lang/handlebars.js/security.
"description":"Handlebars.js and Mustache are both logicless templating languages that keep the view and the code separated like we all know they should be.",
There are a number of formal APIs that tool implementors may interact with.
## AST
Other tools may interact with the formal AST as defined below. Any JSON structure matching this pattern may be used and passed into the `compile` and `precompile` methods in the same way as the text for a template.
AST structures may be generated either with the `Handlebars.parse` method and then manipulated, via the `Handlebars.AST` objects of the same name, or constructed manually as a generic JavaScript object matching the structure defined below.
```javascript
varast=Handlebars.parse(myTemplate);
// Modify 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.
`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
letast=Handlebars.parse(myTemplate);
```
### Basic
```java
interfaceNode{
type:string;
loc:SourceLocation|null;
}
interfaceSourceLocation{
source:string|null;
start:Position;
end:Position;
}
interfacePosition{
line:uint>=1;
column:uint>=0;
}
```
### Programs
```java
interfaceProgram<:Node{
type:"Program";
body:[Statement];
blockParams:[string];
}
```
### Statements
```java
interfaceStatement<:Node{}
interfaceMustacheStatement<:Statement{
type:"MustacheStatement";
path:PathExpression|Literal;
params:[Expression];
hash:Hash;
escaped:boolean;
strip:StripFlags|null;
}
interfaceBlockStatement<:Statement{
type:"BlockStatement";
path:PathExpression|Literal;
params:[Expression];
hash:Hash;
program:Program|null;
inverse:Program|null;
openStrip:StripFlags|null;
inverseStrip:StripFlags|null;
closeStrip:StripFlags|null;
}
interfacePartialStatement<:Statement{
type:"PartialStatement";
name:PathExpression|SubExpression;
params:[Expression];
hash:Hash;
indent:string;
strip:StripFlags|null;
}
interfacePartialBlockStatement<:Statement{
type:"PartialBlockStatement";
name:PathExpression|SubExpression;
params:[Expression];
hash:Hash;
program:Program|null;
indent:string;
openStrip:StripFlags|null;
closeStrip:StripFlags|null;
}
```
`name` will be a `SubExpression` when tied to a dynamic partial, i.e. `{{> (foo) }}`, otherwise this is a path or literal whose `original` value is used to lookup the desired partial.
```java
interfaceContentStatement<:Statement{
type:"ContentStatement";
value:string;
original:string;
}
interfaceCommentStatement<:Statement{
type:"CommentStatement";
value:string;
strip:StripFlags|null;
}
```
```java
interfaceDecorator<:Statement{
type:"Decorator";
path:PathExpression|Literal;
params:[Expression];
hash:Hash;
strip:StripFlags|null;
}
interfaceDecoratorBlock<:Statement{
type:"DecoratorBlock";
path:PathExpression|Literal;
params:[Expression];
hash:Hash;
program:Program|null;
openStrip:StripFlags|null;
closeStrip:StripFlags|null;
}
```
Decorator paths only utilize the `path.original` value and as a consequence do not support depthed evaluation.
### Expressions
```java
interfaceExpression<:Node{}
```
##### SubExpressions
```java
interfaceSubExpression<:Expression{
type:"SubExpression";
path:PathExpression;
params:[Expression];
hash:Hash;
}
```
##### Paths
```java
interfacePathExpression<:Expression{
type:"PathExpression";
data:boolean;
depth:uint>=0;
parts:[string];
original:string;
}
```
-`data` is true when the given expression is a `@data` reference.
-`depth` is an integer representation of which context the expression references. `0` represents the current context, `1` would be `../`, etc.
-`parts` is an array of the names in the path. `foo.bar` would be `['foo', 'bar']`. Scope references, `.`, `..`, and `this` should be omitted from this array.
-`original` is the path as entered by the user. Separator and scope references are left untouched.
##### Literals
```java
interfaceLiteral<:Expression{}
interfaceStringLiteral<:Literal{
type:"StringLiteral";
value:string;
original:string;
}
interfaceBooleanLiteral<:Literal{
type:"BooleanLiteral";
value:boolean;
original:boolean;
}
interfaceNumberLiteral<:Literal{
type:"NumberLiteral";
value:number;
original:number;
}
interfaceUndefinedLiteral<:Literal{
type:"UndefinedLiteral";
}
interfaceNullLiteral<:Literal{
type:"NullLiteral";
}
```
### Miscellaneous
```java
interfaceHash<:Node{
type:"Hash";
pairs:[HashPair];
}
interfaceHashPair<:Node{
type:"HashPair";
key:string;
value:Expression;
}
interfaceStripFlags{
open:boolean;
close:boolean;
}
```
`StripFlags` are used to signify whitespace control character that may have been entered on a given statement.
## AST Visitor
`Handlebars.Visitor` is available as a base class for general interaction with AST structures. This will by default traverse the entire tree and individual methods may be overridden to provide specific responses to particular nodes.
The current node's ancestors will be maintained in the `parents` array, with the most recent parent listed first.
The visitor may also be configured to operate in mutation mode by setting the `mutating` field to true. When in this mode, handler methods may return any valid AST node and it will replace the one they are currently operating on. Returning `false` will remove the given value (if valid) and returning `undefined` will leave the node intact. This return structure only apply to mutation mode and non-mutation mode visitors are free to return whatever values they wish.
Implementors that may need to support mutation mode are encouraged to utilize the `acceptKey`, `acceptRequired` and `acceptArray` helpers which provide the conditional overwrite behavior as well as implement sanity checks where pertinent.
## JavaScript Compiler
The `Handlebars.JavaScriptCompiler` object has a number of methods that may be customized to alter the output of the compiler:
-`nameLookup(parent, name, type)`
Used to generate the code to resolve a given path component.
-`parent` is the existing code in the path resolution
-`name` is the current path component
-`type` is the type of name being evaluated. May be one of `context`, `data`, `helper`, `decorator`, or `partial`.
Note that this does not impact dynamic partials, which implementors need to be aware of. Overriding `VM.resolvePartial` may be required to support dynamic cases.
-`depthedLookup(name)`
Used to generate code that resolves parameters within any context in the stack. Is only used in `compat` mode.
-`compilerInfo()`
Allows for custom compiler flags used in the runtime version checking logic.
-`appendToBuffer(source, location, explicit)`
Allows for code buffer emitting code. Defaults behavior is string concatenation.
-`source` is the source code whose result is to be appending
-`location` is the location of the source in the source map.
-`explicit` is a flag signaling that the emit operation must occur, vs. the lazy evaled options otherwise.
-`initializeBuffer()`
Allows for buffers other than the default string buffer to be used. Generally needs to be paired with a custom `appendToBuffer` implementation.
### Example for the compiler api.
This example changes all lookups of properties are performed by a helper (`lookupLowerCase`) which looks for `test` if `{{Test}}` occurs in the template. This is just to illustrate how compiler behavior can be change.
There is also [a jsfiddle with this code](https://jsfiddle.net/9D88g/162/) if you want to play around with it.
**Decorators are deprecated, please join the discussion at [#1574](https://github.com/handlebars-lang/handlebars.js/issues/1574) to see what we can do about it.**
Decorators allow for blocks to be annotated with metadata or wrapped in functionality prior to execution of the block. This may be used to communicate with the containing helper or to set up a particular state in the system prior to running the block.
Decorators are registered through similar methods as helpers, `registerDecorators` and `unregisterDecorators`. These can then be referenced via the friendly name in the template using the `{{* decorator}}` and `{{#* decorator}}{/decorator}}` syntaxes. These syntaxes are derivatives of the normal mustache syntax and as such have all of the same argument and whitespace behaviors.
Decorators are executed when the block program is instantiated and are passed `(program, props, container, context, data, blockParams, depths)`.
-`program`: The block to wrap
-`props`: Object used to set metadata on the final function. Any values set on this object will be set on the function, regardless of if the original function is replaced or not. Metadata should be applied using this object as values applied to `program` may be masked by subsequent decorators that may wrap `program`.
-`container`: The current runtime container
-`context`: The current context. Since the decorator is run before the block that contains it, this is the parent context.
-`data`: The current `@data` values
-`blockParams`: The current block parameters stack
-`depths`: The current context stack
Decorators may set values on `props` or return a modified function that wraps `program` in particular behaviors. If the decorator returns nothing, then `program` is left unaltered.
The [inline partial](https://github.com/handlebars-lang/handlebars.js/blob/master/lib/handlebars/decorators/inline.js) implementation provides an example of decorators being used for both metadata and wrapping behaviors.
Some files were not shown because too many files have changed in this diff
Show More
Reference in New Issue
Block a user
Blocking a user prevents them from interacting with repositories, such as opening or commenting on pull requests or issues. Learn more about blocking a user.