{"id":22452617,"url":"https://github.com/totaltechgeek/handlebars-jle","last_synced_at":"2026-03-06T16:03:16.401Z","repository":{"id":262872555,"uuid":"888624652","full_name":"TotalTechGeek/handlebars-jle","owner":"TotalTechGeek","description":"A faster Handlebars Templating Engine","archived":false,"fork":false,"pushed_at":"2025-12-01T20:29:18.000Z","size":315,"stargazers_count":9,"open_issues_count":1,"forks_count":3,"subscribers_count":1,"default_branch":"main","last_synced_at":"2025-12-03T03:48:48.596Z","etag":null,"topics":[],"latest_commit_sha":null,"homepage":null,"language":"JavaScript","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/TotalTechGeek.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null,"zenodo":null,"notice":null,"maintainers":null,"copyright":null,"agents":null,"dco":null,"cla":null}},"created_at":"2024-11-14T18:07:52.000Z","updated_at":"2025-12-01T20:26:03.000Z","dependencies_parsed_at":"2025-01-24T22:18:53.350Z","dependency_job_id":"185bf57d-9118-44ac-bd53-188f895c1b07","html_url":"https://github.com/TotalTechGeek/handlebars-jle","commit_stats":null,"previous_names":["totaltechgeek/handlebars-jle"],"tags_count":4,"template":false,"template_full_name":null,"purl":"pkg:github/TotalTechGeek/handlebars-jle","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/TotalTechGeek%2Fhandlebars-jle","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/TotalTechGeek%2Fhandlebars-jle/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/TotalTechGeek%2Fhandlebars-jle/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/TotalTechGeek%2Fhandlebars-jle/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/TotalTechGeek","download_url":"https://codeload.github.com/TotalTechGeek/handlebars-jle/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/TotalTechGeek%2Fhandlebars-jle/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":30184885,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-03-06T14:42:24.748Z","status":"ssl_error","status_checked_at":"2026-03-06T14:42:14.925Z","response_time":250,"last_error":"SSL_connect returned=1 errno=0 peeraddr=140.82.121.6:443 state=error: unexpected eof while reading","robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":false,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":[],"created_at":"2024-12-06T06:11:54.353Z","updated_at":"2026-03-06T16:03:16.385Z","avatar_url":"https://github.com/TotalTechGeek.png","language":"JavaScript","funding_links":[],"categories":[],"sub_categories":[],"readme":"# Handlebars (JSON Logic Edition)\n\nHey there! The documentation for this module is still being rewritten.\n\nThis is an implementation of Handlebars that processes templates into JSON Logic, which is then used by JSON Logic Engine to optimize and evaluate the templates.\n\nThis implementation of Handlebars appears to be ~25x faster than the original implementation, and allows for more variety in execution strategy.\n\nI will admit upfront that there are some differences in this implementation compared to the original Handlebars. I will try to document these differences as I go along.\n\nSome of the obvious differences include:\n\n- Asynchronous Execution is fully supported; this means you can add async helpers natively.\n- ~~Iteration is strictly done via block expressions like `#each`, implicit iteration is not supported. (Use `#each kids` instead of `#kids`)~~\n- There are significantly more built-in helpers, which I may remove or document as I publish this module.\n- ~~The whitespace control is currently not supported in the grammar. (I may add it later) Ex. `{{~foo}}` is not supported.~~\n- Whitespace control is supported, but is handled by a preprocessor and not the grammar. This nuance probably won't affect you, but it's worth mentioning. (Essentially, the whitespace is stripped before the template is parsed)\n- Inline Partials are supported, but slightly different currently.\n- ~~To avoid additional syntax, `as` is not supported in block expressions, I chose to use hash arguments in `with` instead.~~\n- `as` is supported in block expressions, however it will incur a performance cost / disable inline optimizations as it will perform a recursive lookup. In spite of the de-optimization, it should still perform quite reasonably.\n- `with` supports hash arguments, which allows for more flexibility in how the block is executed.\n- Supports an (optimized) Interpreted Mode for both synchronous and asynchronous execution; this means you execute templates in browser contexts that disallow `new Function` or `eval`.\n- If you need to access the index / private context of an above iterator, `../@index` is used instead of `@../index`. I will likely change this to match the original handlebars. This is kind of a niche edge case, but it's worth mentioning.\n\nI believe these differences are relatively minor and do not impact most use cases, and should be easy to work aorund, but I might iterate on this in the future.\n\n## Install\n\nTo install:\n\n```bash\nbun install handlebars-jle\n```\n\n### Conditionals\n\nConditionals are done via the `if` block helper.\n\n```handlebars\n{{#if age}}\n    {{name}} is {{age}} years old.\n{{else}}\n    {{name}}'s age is unknown.\n{{/if}}\n```\n\nThere is also support for if/else if chains\n\n```handlebars\n{{#if age}}\n    {{name}} is {{age}} years old.\n{{else if dob}}\n    {{name}} was born on {{dob}}.\n{{else}}\n    {{name}}'s age is unknown.\n{{/if}}\n```\n\n### Iteration\n\nIteration is done via block expressions like `#each`, and the block helper is used to define the iteration context.\n\n```handlebars\n{{#each kids}}\n    {{name}} is {{age}} years old.\n{{/each}}\n```\n\nData:\n\n```json\n[\n    { \"name\": \"John\", \"age\": 5 },\n    { \"name\": \"Jane\", \"age\": 7 }\n]\n```\n\nAnd over objects,\n\n```handlebars\n{{#each kids}}\n    {{@key}} is {{this}} years old.\n{{/each}}\n```\n\nData:\n\n```json\n{\n    \"John\": 5,\n    \"Jane\": 7\n}\n```\n\nVariable Traversal Syntax is supported with `../` and `@key` and `@index` are supported.\n\n### With\n\nThe `with` block helper has been adjusted a bit from the original Handlebars. It now supports hash arguments, which allows for more flexibility in how the block is executed.\n\n```handlebars\n{{#with name='John Doe' age=27}}\n    {{name}} is {{age}} years old.\n{{/with}}\n```\n\n### Adding Helpers\n\nYou can add helpers by adding methods to the JSON Logic Engine.\n\n```javascript\nimport { Handlebars } from 'handlebars-jle';\n\nconst hbs = new Handlebars();\nhbs.engine.addMethod('addOne', ([a]) =\u003e a + 1, { sync: true, deterministic: true });\n\nconst template = hbs.compile('{{addOne age}}');\n\ntemplate({ age: 5 }); // 6\ntemplate({ age: 10 }); // 11\n```\n\nIf your method is synchronous and deterministic (same input always produces the same output, and it will never return a promise), you should specify that in the options. This will allow the engine to optimize the method; and if synchronous, allow it to be used by `compile`\n\nHere is a more interesting example, using async support:\n\n```javascript\nimport { AsyncHandlebars } from 'handlebars-jle';\n\nconst hbs = new AsyncHandlebars();\n\nhbs.engine.addMethod('fetch', async ([url]) =\u003e {\n    const response = await fetch(url)\n    return response.json()\n})\n\nconst template = hbs.compile(`{{#each (fetch 'https://jsonplaceholder.typicode.com/users')}}\n@{{username}} - {{name}}\n{{/each}}`)\n\ntemplate().then(console.log)\n```\n\nWould produce:\n\n```plaintext\n@Bret - Leanne Graham\n@Antonette - Ervin Howell\n@Samantha - Clementine Bauch\n@Karianne - Patricia Lebsack\n@Kamren - Chelsey Dietrich\n@Leopoldo_Corkery - Mrs. Dennis Schulist\n@Elwyn.Skiles - Kurtis Weissnat\n@Maxime_Nienow - Nicholas Runolfsdottir V\n@Delphine - Glenna Reichert\n@Moriah.Stanton - Clementina DuBuque\n```\n\n### Executing Templates\n\nThis module supports both a compiled mode and an \"interpreted\" mode.\n\nThe compiled mode is faster, but the interpreted mode is more flexible and can be used in environments that disallow `eval` or `new Function`.\n\n\nFor example:\n\n```javascript\n\nconst { Handlebars, AsyncHandlebars } = require('handlebars-jle');\n\nconst hbs = new Handlebars();\nconst hbsAsync = new AsyncHandlebars();\nconst hbsInterpreted = new Handlebars({ interpreted: true });\nconst hbsAsyncInterpreted = new AsyncHandlebars({ interpreted: true });\n\nconst hello = hbs.compile('Hello, {{name}}!')\nconst helloAsync = hbsAsync.compile('Hello, {{name}}!')\nconst helloInterpreted = hbsInterpreted.compile('Hello, {{name}}!')\nconst helloAsyncInterpreted = hbsAsyncInterpreted.compile('Hello, {{name}}!) \n```\n\nAny of these can now be run with:\n```javascript\nhello('Jesse') // Hello, Jesse!\nhelloAsync('Bob') // Promise\u003c'Hello, Bob!'\u003e\nhelloInterpreted('Steve') // Hello, Steve!\nhelloAsyncInterpreted('Tara') // Promise\u003cHello, Tara!\u003e\n```\n\nIf you have no async helpers to add to your templates, it's strongly recommended you use the synchronous class.\n\nWhile the compiler / optimizer will make the execution fully synchronous if everything in the template is not async, there is still some overhead in JavaScript engines that slow it down a bit when packing it into a promise, so it should only be used if you've added async helpers to your engine you'd like to use.\n\n\n### Adding Partials\n\nYou can add partials by using `register`, \n\n```javascript\nimport { Handlebars } from 'handlebars-jle';\n\nconst hbs = new Handlebars();\nhbs.register('greeting', 'Hello, {{name}}!')\n\nconst template = hbs.compile('{{\u003egreeting name=\"Jesse\"}}');\n\ntemplate(); // Hello, Jesse!\n```\n\nOf some note, partials that can be fully evaluated and inlined will be! In the above case, since `greeting` receives all of the information it needs as constants, it will fully evaluate the partial and inline it into the template.\n\n```javascript\nimport { Handlebars } from 'handlebars-jle';\n\nconst hbs = new Handlebars({ interpreted: true });\nhbs.register('greeting', 'Hello, {{name}}!')\n\nconst template = hbs.compile('{{\u003egreeting name=\"Jesse\"}}');\n\ntemplate(); // Hello, Jesse!\n```\n\nWorks in the exact same way, but it will not use `eval` or `new Function` to compile the partial, which is useful in environments that disallow it. While this is not \"compiled\", this too will inline the partial if it can be fully evaluated.\n\n### Inline Partials (Experimental)\n\nInline Partials are supported but have a slightly different syntax as they do not use the deprecated decorators syntax.\n\n```handlebars\n{{#inline \"greeting\"}}Hello, {{name}}!{{/inline}}\n{{\u003egreeting name=\"Jesse\"}}\n```\n\nThis will produce the same output as the previous example.\n\nThe reason they are flagged as experimental is because they currently do not scope themselves exclusively to the template that registered them. This means that if you register an inline partial in one template, it will be available in all templates. This is not ideal, and I will be working on a solution to this in the future.\n\n### Adding Block Helpers\n\nThis needs fleshed out documentation. This needs some explanation because you're able to deeply optimize the block helper in some powerful ways.\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Ftotaltechgeek%2Fhandlebars-jle","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Ftotaltechgeek%2Fhandlebars-jle","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Ftotaltechgeek%2Fhandlebars-jle/lists"}