express-hbs 2.5.0 → 2.5.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.claude/worktrees/node-20-26-migration-7de0c3/.editorconfig +8 -0
- package/.claude/worktrees/node-20-26-migration-7de0c3/.github/workflows/publish.yml +73 -0
- package/.claude/worktrees/node-20-26-migration-7de0c3/.github/workflows/test.yml +48 -0
- package/.claude/worktrees/node-20-26-migration-7de0c3/.jsbeautifyrc +17 -0
- package/.claude/worktrees/node-20-26-migration-7de0c3/.nvmrc +1 -0
- package/.claude/worktrees/node-20-26-migration-7de0c3/.nycrc.json +16 -0
- package/.claude/worktrees/node-20-26-migration-7de0c3/.oxfmtrc.json +19 -0
- package/.claude/worktrees/node-20-26-migration-7de0c3/.oxlintrc.json +32 -0
- package/.claude/worktrees/node-20-26-migration-7de0c3/AGENTS.md +40 -0
- package/.claude/worktrees/node-20-26-migration-7de0c3/LICENSE +21 -0
- package/.claude/worktrees/node-20-26-migration-7de0c3/README.md +333 -0
- package/.claude/worktrees/node-20-26-migration-7de0c3/SECURITY.md +9 -0
- package/.claude/worktrees/node-20-26-migration-7de0c3/example/app-layoutsDir.js +99 -0
- package/.claude/worktrees/node-20-26-migration-7de0c3/example/app.js +103 -0
- package/.claude/worktrees/node-20-26-migration-7de0c3/example/public/css/style.css +17 -0
- package/.claude/worktrees/node-20-26-migration-7de0c3/example/views/fruits/details-layoutsDir.hbs +3 -0
- package/.claude/worktrees/node-20-26-migration-7de0c3/example/views/fruits/details.hbs +4 -0
- package/.claude/worktrees/node-20-26-migration-7de0c3/example/views/fruits/index-layoutsDir.hbs +20 -0
- package/.claude/worktrees/node-20-26-migration-7de0c3/example/views/fruits/index.hbs +20 -0
- package/.claude/worktrees/node-20-26-migration-7de0c3/example/views/index.hbs +34 -0
- package/.claude/worktrees/node-20-26-migration-7de0c3/example/views/layout/default.hbs +13 -0
- package/.claude/worktrees/node-20-26-migration-7de0c3/example/views/layout/fruit-details.hbs +9 -0
- package/.claude/worktrees/node-20-26-migration-7de0c3/example/views/layout/fruits.hbs +6 -0
- package/.claude/worktrees/node-20-26-migration-7de0c3/example/views/layout/html-struct.hbs +21 -0
- package/.claude/worktrees/node-20-26-migration-7de0c3/example/views/layout/veggie-details.hbs +9 -0
- package/.claude/worktrees/node-20-26-migration-7de0c3/example/views/layout/veggie.hbs +6 -0
- package/.claude/worktrees/node-20-26-migration-7de0c3/example/views/partials/scripts.hbs +5 -0
- package/.claude/worktrees/node-20-26-migration-7de0c3/example/views/partials/sub/comment.hbs +1 -0
- package/.claude/worktrees/node-20-26-migration-7de0c3/example/views/partials-other/other.hbs +1 -0
- package/.claude/worktrees/node-20-26-migration-7de0c3/example/views/replace.hbs +6 -0
- package/.claude/worktrees/node-20-26-migration-7de0c3/example/views/tos.txt +3 -0
- package/.claude/worktrees/node-20-26-migration-7de0c3/example/views/veggies/details.hbs +1 -0
- package/.claude/worktrees/node-20-26-migration-7de0c3/example/views/veggies.hbs +17 -0
- package/.claude/worktrees/node-20-26-migration-7de0c3/index.js +1 -0
- package/.claude/worktrees/node-20-26-migration-7de0c3/lib/generate-id.js +16 -0
- package/.claude/worktrees/node-20-26-migration-7de0c3/lib/hbs.js +671 -0
- package/.claude/worktrees/node-20-26-migration-7de0c3/lib/resolver.js +59 -0
- package/.claude/worktrees/node-20-26-migration-7de0c3/package.json +61 -0
- package/.claude/worktrees/node-20-26-migration-7de0c3/pnpm-lock.yaml +3424 -0
- package/.claude/worktrees/node-20-26-migration-7de0c3/pnpm-workspace.yaml +6 -0
- package/.claude/worktrees/node-20-26-migration-7de0c3/renovate.json +13 -0
- package/.claude/worktrees/node-20-26-migration-7de0c3/test/apps/async/index.js +139 -0
- package/.claude/worktrees/node-20-26-migration-7de0c3/test/apps/async/views/failer.hbs +4 -0
- package/.claude/worktrees/node-20-26-migration-7de0c3/test/apps/async/views/index.hbs +16 -0
- package/.claude/worktrees/node-20-26-migration-7de0c3/test/apps/async/views/layout.hbs +1 -0
- package/.claude/worktrees/node-20-26-migration-7de0c3/test/apps/i18n/index.js +57 -0
- package/.claude/worktrees/node-20-26-migration-7de0c3/test/apps/i18n/locales/en.json +8 -0
- package/.claude/worktrees/node-20-26-migration-7de0c3/test/apps/i18n/locales/fr.json +8 -0
- package/.claude/worktrees/node-20-26-migration-7de0c3/test/apps/i18n/views/index.hbs +3 -0
- package/.claude/worktrees/node-20-26-migration-7de0c3/test/asyncSpecs.js +69 -0
- package/.claude/worktrees/node-20-26-migration-7de0c3/test/cacheSpecs.js +135 -0
- package/.claude/worktrees/node-20-26-migration-7de0c3/test/customExtension.js +35 -0
- package/.claude/worktrees/node-20-26-migration-7de0c3/test/handlebarsSpecs.js +92 -0
- package/.claude/worktrees/node-20-26-migration-7de0c3/test/helperSpecs.js +58 -0
- package/.claude/worktrees/node-20-26-migration-7de0c3/test/helpers.js +24 -0
- package/.claude/worktrees/node-20-26-migration-7de0c3/test/i18nSpecs.js +36 -0
- package/.claude/worktrees/node-20-26-migration-7de0c3/test/issues/144/index.hbs +1 -0
- package/.claude/worktrees/node-20-26-migration-7de0c3/test/issues/153/index.hbs +3 -0
- package/.claude/worktrees/node-20-26-migration-7de0c3/test/issues/21/views/index.hbs +1 -0
- package/.claude/worktrees/node-20-26-migration-7de0c3/test/issues/21/views/layouts/default.hbs +1 -0
- package/.claude/worktrees/node-20-26-migration-7de0c3/test/issues/21/views/layouts/sub/child.hbs +1 -0
- package/.claude/worktrees/node-20-26-migration-7de0c3/test/issues/21/views/sub/relativeLayout.hbs +1 -0
- package/.claude/worktrees/node-20-26-migration-7de0c3/test/issues/21/views/sub/sub.hbs +1 -0
- package/.claude/worktrees/node-20-26-migration-7de0c3/test/issues/21/views/useLayoutInDir.hbs +1 -0
- package/.claude/worktrees/node-20-26-migration-7de0c3/test/issues/22/layout1.hbs +1 -0
- package/.claude/worktrees/node-20-26-migration-7de0c3/test/issues/22/layout2.hbs +1 -0
- package/.claude/worktrees/node-20-26-migration-7de0c3/test/issues/22/template.hbs +1 -0
- package/.claude/worktrees/node-20-26-migration-7de0c3/test/issues/23/empty.hbs +0 -0
- package/.claude/worktrees/node-20-26-migration-7de0c3/test/issues/23/emptyComment.hbs +1 -0
- package/.claude/worktrees/node-20-26-migration-7de0c3/test/issues/23/emptyPartial.hbs +1 -0
- package/.claude/worktrees/node-20-26-migration-7de0c3/test/issues/23/index.hbs +4 -0
- package/.claude/worktrees/node-20-26-migration-7de0c3/test/issues/23/layout.hbs +1 -0
- package/.claude/worktrees/node-20-26-migration-7de0c3/test/issues/23/partials/custom/comment-only.hbs +1 -0
- package/.claude/worktrees/node-20-26-migration-7de0c3/test/issues/23/partials/custom/empty.hbs +0 -0
- package/.claude/worktrees/node-20-26-migration-7de0c3/test/issues/23/partials/hello.hbs +1 -0
- package/.claude/worktrees/node-20-26-migration-7de0c3/test/issues/49/error.hbs +1 -0
- package/.claude/worktrees/node-20-26-migration-7de0c3/test/issues/49/front/error.hbs +1 -0
- package/.claude/worktrees/node-20-26-migration-7de0c3/test/issues/49/index.hbs +2 -0
- package/.claude/worktrees/node-20-26-migration-7de0c3/test/issues/49/layouts/default.hbs +1 -0
- package/.claude/worktrees/node-20-26-migration-7de0c3/test/issues/49/partial.hbs +1 -0
- package/.claude/worktrees/node-20-26-migration-7de0c3/test/issues/49/partials/partial-error.hbs +1 -0
- package/.claude/worktrees/node-20-26-migration-7de0c3/test/issues/53/default.hbs +15 -0
- package/.claude/worktrees/node-20-26-migration-7de0c3/test/issues/53/index.hbs +7 -0
- package/.claude/worktrees/node-20-26-migration-7de0c3/test/issues/53/partials/.gitkeep +0 -0
- package/.claude/worktrees/node-20-26-migration-7de0c3/test/issues/59/index.hbs +2 -0
- package/.claude/worktrees/node-20-26-migration-7de0c3/test/issues/62/basic.hbs +2 -0
- package/.claude/worktrees/node-20-26-migration-7de0c3/test/issues/62/block.hbs +11 -0
- package/.claude/worktrees/node-20-26-migration-7de0c3/test/issues/73/index.hbs +5 -0
- package/.claude/worktrees/node-20-26-migration-7de0c3/test/issues/73/partials/partial.hbs +6 -0
- package/.claude/worktrees/node-20-26-migration-7de0c3/test/issues/76/mypartial.hbs +0 -0
- package/.claude/worktrees/node-20-26-migration-7de0c3/test/issues/84/index.hbs +1 -0
- package/.claude/worktrees/node-20-26-migration-7de0c3/test/issues/84/partials/abc/def/ghi/test.hbs +1 -0
- package/.claude/worktrees/node-20-26-migration-7de0c3/test/issues.js +490 -0
- package/.claude/worktrees/node-20-26-migration-7de0c3/test/layoutSpecs.js +146 -0
- package/.claude/worktrees/node-20-26-migration-7de0c3/test/localTemplateOptions/data-access-template.hbs +1 -0
- package/.claude/worktrees/node-20-26-migration-7de0c3/test/localTemplateOptions/template.hbs +1 -0
- package/.claude/worktrees/node-20-26-migration-7de0c3/test/localTemplateOptions.js +125 -0
- package/.claude/worktrees/node-20-26-migration-7de0c3/test/multiple.js +115 -0
- package/.claude/worktrees/node-20-26-migration-7de0c3/test/nonExpress.js +36 -0
- package/.claude/worktrees/node-20-26-migration-7de0c3/test/optionsSpecs.js +22 -0
- package/.claude/worktrees/node-20-26-migration-7de0c3/test/resolverSpecs.js +54 -0
- package/.claude/worktrees/node-20-26-migration-7de0c3/test/views/beautify/expected.hbs +9 -0
- package/.claude/worktrees/node-20-26-migration-7de0c3/test/views/beautify/index.hbs +2 -0
- package/.claude/worktrees/node-20-26-migration-7de0c3/test/views/customExtension/layout.server.view.html +1 -0
- package/.claude/worktrees/node-20-26-migration-7de0c3/test/views/customExtension/partialsDir/partial1.server.view.html +1 -0
- package/.claude/worktrees/node-20-26-migration-7de0c3/test/views/customExtension/partialsDir/partial2.server.view.html +1 -0
- package/.claude/worktrees/node-20-26-migration-7de0c3/test/views/customExtension/partialsDir/subs/subPartial1.server.view.html +1 -0
- package/.claude/worktrees/node-20-26-migration-7de0c3/test/views/customExtension/partialsDir/subs/subPartial2.server.view.html +1 -0
- package/.claude/worktrees/node-20-26-migration-7de0c3/test/views/customExtension/template.server.view.html +5 -0
- package/.claude/worktrees/node-20-26-migration-7de0c3/test/views/disableLayoutDirective/aside.hbs +1 -0
- package/.claude/worktrees/node-20-26-migration-7de0c3/test/views/disableLayoutDirective/index.hbs +2 -0
- package/.claude/worktrees/node-20-26-migration-7de0c3/test/views/disableLayoutDirective/layouts/default.hbs +1 -0
- package/.claude/worktrees/node-20-26-migration-7de0c3/test/views/helpers/home/async.hbs +6 -0
- package/.claude/worktrees/node-20-26-migration-7de0c3/test/views/helpers/home/index.hbs +3 -0
- package/.claude/worktrees/node-20-26-migration-7de0c3/test/views/helpers/layouts/default.hbs +1 -0
- package/.claude/worktrees/node-20-26-migration-7de0c3/test/views/multiple/views1/collide.hbs +1 -0
- package/.claude/worktrees/node-20-26-migration-7de0c3/test/views/multiple/views1/error.hbs +1 -0
- package/.claude/worktrees/node-20-26-migration-7de0c3/test/views/multiple/views1/test1.hbs +1 -0
- package/.claude/worktrees/node-20-26-migration-7de0c3/test/views/multiple/views2/collide.hbs +1 -0
- package/.claude/worktrees/node-20-26-migration-7de0c3/test/views/multiple/views2/error.hbs +1 -0
- package/.claude/worktrees/node-20-26-migration-7de0c3/test/views/multiple/views2/test2.hbs +1 -0
- package/.claude/worktrees/node-20-26-migration-7de0c3/test/views/viewsDir/layouts/default.hbs +1 -0
- package/.claude/worktrees/node-20-26-migration-7de0c3/test/views/viewsDir/sub/directive.hbs +2 -0
- package/.claude/worktrees/node-20-26-migration-7de0c3/test/views/viewsDir/sub/lay.hbs +1 -0
- package/.claude/worktrees/security-patches-review-c621ea/.editorconfig +8 -0
- package/.claude/worktrees/security-patches-review-c621ea/.github/workflows/publish.yml +73 -0
- package/.claude/worktrees/security-patches-review-c621ea/.github/workflows/test.yml +48 -0
- package/.claude/worktrees/security-patches-review-c621ea/.jsbeautifyrc +17 -0
- package/.claude/worktrees/security-patches-review-c621ea/.nvmrc +1 -0
- package/.claude/worktrees/security-patches-review-c621ea/.nycrc.json +16 -0
- package/.claude/worktrees/security-patches-review-c621ea/.oxfmtrc.json +19 -0
- package/.claude/worktrees/security-patches-review-c621ea/.oxlintrc.json +32 -0
- package/.claude/worktrees/security-patches-review-c621ea/AGENTS.md +40 -0
- package/.claude/worktrees/security-patches-review-c621ea/LICENSE +21 -0
- package/.claude/worktrees/security-patches-review-c621ea/README.md +333 -0
- package/.claude/worktrees/security-patches-review-c621ea/SECURITY.md +9 -0
- package/.claude/worktrees/security-patches-review-c621ea/example/app-layoutsDir.js +99 -0
- package/.claude/worktrees/security-patches-review-c621ea/example/app.js +103 -0
- package/.claude/worktrees/security-patches-review-c621ea/example/public/css/style.css +17 -0
- package/.claude/worktrees/security-patches-review-c621ea/example/views/fruits/details-layoutsDir.hbs +3 -0
- package/.claude/worktrees/security-patches-review-c621ea/example/views/fruits/details.hbs +4 -0
- package/.claude/worktrees/security-patches-review-c621ea/example/views/fruits/index-layoutsDir.hbs +20 -0
- package/.claude/worktrees/security-patches-review-c621ea/example/views/fruits/index.hbs +20 -0
- package/.claude/worktrees/security-patches-review-c621ea/example/views/index.hbs +34 -0
- package/.claude/worktrees/security-patches-review-c621ea/example/views/layout/default.hbs +13 -0
- package/.claude/worktrees/security-patches-review-c621ea/example/views/layout/fruit-details.hbs +9 -0
- package/.claude/worktrees/security-patches-review-c621ea/example/views/layout/fruits.hbs +6 -0
- package/.claude/worktrees/security-patches-review-c621ea/example/views/layout/html-struct.hbs +21 -0
- package/.claude/worktrees/security-patches-review-c621ea/example/views/layout/veggie-details.hbs +9 -0
- package/.claude/worktrees/security-patches-review-c621ea/example/views/layout/veggie.hbs +6 -0
- package/.claude/worktrees/security-patches-review-c621ea/example/views/partials/scripts.hbs +5 -0
- package/.claude/worktrees/security-patches-review-c621ea/example/views/partials/sub/comment.hbs +1 -0
- package/.claude/worktrees/security-patches-review-c621ea/example/views/partials-other/other.hbs +1 -0
- package/.claude/worktrees/security-patches-review-c621ea/example/views/replace.hbs +6 -0
- package/.claude/worktrees/security-patches-review-c621ea/example/views/tos.txt +3 -0
- package/.claude/worktrees/security-patches-review-c621ea/example/views/veggies/details.hbs +1 -0
- package/.claude/worktrees/security-patches-review-c621ea/example/views/veggies.hbs +17 -0
- package/.claude/worktrees/security-patches-review-c621ea/index.js +1 -0
- package/.claude/worktrees/security-patches-review-c621ea/lib/generate-id.js +16 -0
- package/.claude/worktrees/security-patches-review-c621ea/lib/hbs.js +665 -0
- package/.claude/worktrees/security-patches-review-c621ea/lib/resolver.js +59 -0
- package/.claude/worktrees/security-patches-review-c621ea/package.json +57 -0
- package/.claude/worktrees/security-patches-review-c621ea/pnpm-lock.yaml +3424 -0
- package/.claude/worktrees/security-patches-review-c621ea/pnpm-workspace.yaml +6 -0
- package/.claude/worktrees/security-patches-review-c621ea/renovate.json +6 -0
- package/.claude/worktrees/security-patches-review-c621ea/test/apps/async/index.js +139 -0
- package/.claude/worktrees/security-patches-review-c621ea/test/apps/async/views/failer.hbs +4 -0
- package/.claude/worktrees/security-patches-review-c621ea/test/apps/async/views/index.hbs +16 -0
- package/.claude/worktrees/security-patches-review-c621ea/test/apps/async/views/layout.hbs +1 -0
- package/.claude/worktrees/security-patches-review-c621ea/test/apps/i18n/index.js +57 -0
- package/.claude/worktrees/security-patches-review-c621ea/test/apps/i18n/locales/en.json +8 -0
- package/.claude/worktrees/security-patches-review-c621ea/test/apps/i18n/locales/fr.json +8 -0
- package/.claude/worktrees/security-patches-review-c621ea/test/apps/i18n/views/index.hbs +3 -0
- package/.claude/worktrees/security-patches-review-c621ea/test/asyncSpecs.js +69 -0
- package/.claude/worktrees/security-patches-review-c621ea/test/cacheSpecs.js +135 -0
- package/.claude/worktrees/security-patches-review-c621ea/test/customExtension.js +35 -0
- package/.claude/worktrees/security-patches-review-c621ea/test/handlebarsSpecs.js +92 -0
- package/.claude/worktrees/security-patches-review-c621ea/test/helperSpecs.js +58 -0
- package/.claude/worktrees/security-patches-review-c621ea/test/helpers.js +24 -0
- package/.claude/worktrees/security-patches-review-c621ea/test/i18nSpecs.js +36 -0
- package/.claude/worktrees/security-patches-review-c621ea/test/issues/144/index.hbs +1 -0
- package/.claude/worktrees/security-patches-review-c621ea/test/issues/153/index.hbs +3 -0
- package/.claude/worktrees/security-patches-review-c621ea/test/issues/21/views/index.hbs +1 -0
- package/.claude/worktrees/security-patches-review-c621ea/test/issues/21/views/layouts/default.hbs +1 -0
- package/.claude/worktrees/security-patches-review-c621ea/test/issues/21/views/layouts/sub/child.hbs +1 -0
- package/.claude/worktrees/security-patches-review-c621ea/test/issues/21/views/sub/relativeLayout.hbs +1 -0
- package/.claude/worktrees/security-patches-review-c621ea/test/issues/21/views/sub/sub.hbs +1 -0
- package/.claude/worktrees/security-patches-review-c621ea/test/issues/21/views/useLayoutInDir.hbs +1 -0
- package/.claude/worktrees/security-patches-review-c621ea/test/issues/22/layout1.hbs +1 -0
- package/.claude/worktrees/security-patches-review-c621ea/test/issues/22/layout2.hbs +1 -0
- package/.claude/worktrees/security-patches-review-c621ea/test/issues/22/template.hbs +1 -0
- package/.claude/worktrees/security-patches-review-c621ea/test/issues/23/empty.hbs +0 -0
- package/.claude/worktrees/security-patches-review-c621ea/test/issues/23/emptyComment.hbs +1 -0
- package/.claude/worktrees/security-patches-review-c621ea/test/issues/23/emptyPartial.hbs +1 -0
- package/.claude/worktrees/security-patches-review-c621ea/test/issues/23/index.hbs +4 -0
- package/.claude/worktrees/security-patches-review-c621ea/test/issues/23/layout.hbs +1 -0
- package/.claude/worktrees/security-patches-review-c621ea/test/issues/23/partials/custom/comment-only.hbs +1 -0
- package/.claude/worktrees/security-patches-review-c621ea/test/issues/23/partials/custom/empty.hbs +0 -0
- package/.claude/worktrees/security-patches-review-c621ea/test/issues/23/partials/hello.hbs +1 -0
- package/.claude/worktrees/security-patches-review-c621ea/test/issues/49/error.hbs +1 -0
- package/.claude/worktrees/security-patches-review-c621ea/test/issues/49/front/error.hbs +1 -0
- package/.claude/worktrees/security-patches-review-c621ea/test/issues/49/index.hbs +2 -0
- package/.claude/worktrees/security-patches-review-c621ea/test/issues/49/layouts/default.hbs +1 -0
- package/.claude/worktrees/security-patches-review-c621ea/test/issues/49/partial.hbs +1 -0
- package/.claude/worktrees/security-patches-review-c621ea/test/issues/49/partials/partial-error.hbs +1 -0
- package/.claude/worktrees/security-patches-review-c621ea/test/issues/53/default.hbs +15 -0
- package/.claude/worktrees/security-patches-review-c621ea/test/issues/53/index.hbs +7 -0
- package/.claude/worktrees/security-patches-review-c621ea/test/issues/53/partials/.gitkeep +0 -0
- package/.claude/worktrees/security-patches-review-c621ea/test/issues/59/index.hbs +2 -0
- package/.claude/worktrees/security-patches-review-c621ea/test/issues/62/basic.hbs +2 -0
- package/.claude/worktrees/security-patches-review-c621ea/test/issues/62/block.hbs +11 -0
- package/.claude/worktrees/security-patches-review-c621ea/test/issues/73/index.hbs +5 -0
- package/.claude/worktrees/security-patches-review-c621ea/test/issues/73/partials/partial.hbs +6 -0
- package/.claude/worktrees/security-patches-review-c621ea/test/issues/76/mypartial.hbs +0 -0
- package/.claude/worktrees/security-patches-review-c621ea/test/issues/84/index.hbs +1 -0
- package/.claude/worktrees/security-patches-review-c621ea/test/issues/84/partials/abc/def/ghi/test.hbs +1 -0
- package/.claude/worktrees/security-patches-review-c621ea/test/issues.js +490 -0
- package/.claude/worktrees/security-patches-review-c621ea/test/layoutSpecs.js +116 -0
- package/.claude/worktrees/security-patches-review-c621ea/test/localTemplateOptions/data-access-template.hbs +1 -0
- package/.claude/worktrees/security-patches-review-c621ea/test/localTemplateOptions/template.hbs +1 -0
- package/.claude/worktrees/security-patches-review-c621ea/test/localTemplateOptions.js +125 -0
- package/.claude/worktrees/security-patches-review-c621ea/test/multiple.js +115 -0
- package/.claude/worktrees/security-patches-review-c621ea/test/nonExpress.js +36 -0
- package/.claude/worktrees/security-patches-review-c621ea/test/optionsSpecs.js +22 -0
- package/.claude/worktrees/security-patches-review-c621ea/test/resolverSpecs.js +54 -0
- package/.claude/worktrees/security-patches-review-c621ea/test/views/beautify/expected.hbs +9 -0
- package/.claude/worktrees/security-patches-review-c621ea/test/views/beautify/index.hbs +2 -0
- package/.claude/worktrees/security-patches-review-c621ea/test/views/customExtension/layout.server.view.html +1 -0
- package/.claude/worktrees/security-patches-review-c621ea/test/views/customExtension/partialsDir/partial1.server.view.html +1 -0
- package/.claude/worktrees/security-patches-review-c621ea/test/views/customExtension/partialsDir/partial2.server.view.html +1 -0
- package/.claude/worktrees/security-patches-review-c621ea/test/views/customExtension/partialsDir/subs/subPartial1.server.view.html +1 -0
- package/.claude/worktrees/security-patches-review-c621ea/test/views/customExtension/partialsDir/subs/subPartial2.server.view.html +1 -0
- package/.claude/worktrees/security-patches-review-c621ea/test/views/customExtension/template.server.view.html +5 -0
- package/.claude/worktrees/security-patches-review-c621ea/test/views/disableLayoutDirective/aside.hbs +1 -0
- package/.claude/worktrees/security-patches-review-c621ea/test/views/disableLayoutDirective/index.hbs +2 -0
- package/.claude/worktrees/security-patches-review-c621ea/test/views/disableLayoutDirective/layouts/default.hbs +1 -0
- package/.claude/worktrees/security-patches-review-c621ea/test/views/helpers/home/async.hbs +6 -0
- package/.claude/worktrees/security-patches-review-c621ea/test/views/helpers/home/index.hbs +3 -0
- package/.claude/worktrees/security-patches-review-c621ea/test/views/helpers/layouts/default.hbs +1 -0
- package/.claude/worktrees/security-patches-review-c621ea/test/views/multiple/views1/collide.hbs +1 -0
- package/.claude/worktrees/security-patches-review-c621ea/test/views/multiple/views1/error.hbs +1 -0
- package/.claude/worktrees/security-patches-review-c621ea/test/views/multiple/views1/test1.hbs +1 -0
- package/.claude/worktrees/security-patches-review-c621ea/test/views/multiple/views2/collide.hbs +1 -0
- package/.claude/worktrees/security-patches-review-c621ea/test/views/multiple/views2/error.hbs +1 -0
- package/.claude/worktrees/security-patches-review-c621ea/test/views/multiple/views2/test2.hbs +1 -0
- package/.claude/worktrees/security-patches-review-c621ea/test/views/viewsDir/layouts/default.hbs +1 -0
- package/.claude/worktrees/security-patches-review-c621ea/test/views/viewsDir/sub/directive.hbs +2 -0
- package/.claude/worktrees/security-patches-review-c621ea/test/views/viewsDir/sub/lay.hbs +1 -0
- package/lib/hbs.js +16 -5
- package/lib/resolver.js +10 -3
- package/package.json +1 -1
- package/test/asyncSpecs.js +60 -0
- package/test/handlebarsSpecs.js +19 -0
- package/test/layoutSpecs.js +30 -0
- package/test/resolverSpecs.js +70 -0
- package/test/views/asyncPrefix/body.hbs +1 -0
- package/test/views/asyncPrefix/index.hbs +1 -0
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
{
|
|
2
|
+
"$schema": "./node_modules/oxlint/configuration_schema.json",
|
|
3
|
+
"categories": {
|
|
4
|
+
"correctness": "error",
|
|
5
|
+
"suspicious": "warn"
|
|
6
|
+
},
|
|
7
|
+
"env": {
|
|
8
|
+
"node": true,
|
|
9
|
+
"es2024": true
|
|
10
|
+
},
|
|
11
|
+
"rules": {
|
|
12
|
+
"no-console": "error"
|
|
13
|
+
},
|
|
14
|
+
"overrides": [
|
|
15
|
+
{
|
|
16
|
+
"files": ["test/**/*.js"],
|
|
17
|
+
"env": {
|
|
18
|
+
"mocha": true
|
|
19
|
+
},
|
|
20
|
+
"rules": {
|
|
21
|
+
"no-console": "off",
|
|
22
|
+
"no-unused-vars": "off"
|
|
23
|
+
}
|
|
24
|
+
},
|
|
25
|
+
{
|
|
26
|
+
"files": ["lib/hbs.js", "example/**/*.js"],
|
|
27
|
+
"rules": {
|
|
28
|
+
"no-console": "off"
|
|
29
|
+
}
|
|
30
|
+
}
|
|
31
|
+
]
|
|
32
|
+
}
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
# express-hbs agent notes
|
|
2
|
+
|
|
3
|
+
`express-hbs` is a CommonJS Express view-engine library. Read `README.md` for
|
|
4
|
+
the public API and usage examples before changing behavior.
|
|
5
|
+
|
|
6
|
+
## Commands
|
|
7
|
+
|
|
8
|
+
Use the pnpm version pinned in package.json on Node.js 22.12 or later.
|
|
9
|
+
|
|
10
|
+
```sh
|
|
11
|
+
pnpm install --frozen-lockfile
|
|
12
|
+
pnpm lint
|
|
13
|
+
pnpm test
|
|
14
|
+
pnpm coverage
|
|
15
|
+
```
|
|
16
|
+
|
|
17
|
+
`pnpm test` runs `mocha` and then `pnpm lint` through the `posttest` script.
|
|
18
|
+
`pnpm coverage` runs the same test suite under `nyc` and enforces the coverage
|
|
19
|
+
thresholds in `package.json`.
|
|
20
|
+
|
|
21
|
+
## Boundaries
|
|
22
|
+
|
|
23
|
+
- Do not edit `pnpm-lock.yaml` by hand. Regenerate it with `pnpm install`.
|
|
24
|
+
- Keep `lib/hbs.js` and `lib/resolver.js` CommonJS; this package does not use
|
|
25
|
+
ESM.
|
|
26
|
+
- Treat files under `test/views/**`, `test/issues/**`, and `example/views/**`
|
|
27
|
+
as rendering fixtures. Seemingly odd whitespace, malformed markup, or partial
|
|
28
|
+
names may be intentional test coverage.
|
|
29
|
+
- Keep the security warning around user-controlled `layout` values and
|
|
30
|
+
`restrictLayoutsTo` in sync with behavior.
|
|
31
|
+
|
|
32
|
+
## Style notes
|
|
33
|
+
|
|
34
|
+
- Formatting is enforced by `oxfmt`; run `pnpm lint:fix` rather than doing large
|
|
35
|
+
manual formatting sweeps.
|
|
36
|
+
- The formatter intentionally ignores Handlebars, HTML, CSS, lockfile, and
|
|
37
|
+
fixture data files. Preserve their existing shape unless the test expectation
|
|
38
|
+
itself is being changed.
|
|
39
|
+
- Add or update tests for layout resolution, partial loading, async helpers,
|
|
40
|
+
template options, and caching changes.
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
The MIT License (MIT)
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2012-2025 Barc, Inc., Ghost Foundation
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy of
|
|
6
|
+
this software and associated documentation files (the "Software"), to deal in
|
|
7
|
+
the Software without restriction, including without limitation the rights to
|
|
8
|
+
use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
|
|
9
|
+
of the Software, and to permit persons to whom the Software is furnished to do
|
|
10
|
+
so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
|
@@ -0,0 +1,333 @@
|
|
|
1
|
+
# express-hbs
|
|
2
|
+
|
|
3
|
+
Express Handlebars template engine for Express apps, with nested layouts,
|
|
4
|
+
named content blocks, cached partials, i18n helpers, and asynchronous helpers.
|
|
5
|
+
|
|
6
|
+
`express-hbs` exposes Express-compatible view engine functions and a shared
|
|
7
|
+
Handlebars instance. It is used by apps that want Handlebars templates with
|
|
8
|
+
layout inheritance and block-style content regions while keeping the familiar
|
|
9
|
+
`app.engine()` integration.
|
|
10
|
+
|
|
11
|
+
## Requirements
|
|
12
|
+
|
|
13
|
+
- Node.js 22 or later
|
|
14
|
+
- the pinned pnpm version when working on this repository
|
|
15
|
+
|
|
16
|
+
## v2.0.0
|
|
17
|
+
|
|
18
|
+
Version 2 was a rewrite and cleanup, with no known breaking changes. Lots of bugs were fixed which may have subtly changed behaviour.
|
|
19
|
+
|
|
20
|
+
Full details: https://github.com/TryGhost/express-hbs/releases/tag/2.0.0
|
|
21
|
+
|
|
22
|
+
## v1.0.0 Breaking Changes
|
|
23
|
+
|
|
24
|
+
If you're upgrading from v0.8.4 to v1.0.0 there are some potentially breaking changes to be aware of:
|
|
25
|
+
|
|
26
|
+
1. Handlebars @v4.0.5 - please see the [handlebars v4.0 compatibility notes](https://github.com/wycats/handlebars.js/blob/master/release-notes.md#v400---september-1st-2015)
|
|
27
|
+
2. The file extension for partial files must now match the extension configured in `extname` - please see [the PR](https://github.com/TryGhost/express-hbs/pull/88)
|
|
28
|
+
|
|
29
|
+
## Usage
|
|
30
|
+
|
|
31
|
+
Register the engine with Express using `hbs.express4()`.
|
|
32
|
+
|
|
33
|
+
```js
|
|
34
|
+
var hbs = require('express-hbs');
|
|
35
|
+
|
|
36
|
+
// Use `.hbs` for extensions and find partials in `views/partials`.
|
|
37
|
+
app.engine('hbs', hbs.express4({
|
|
38
|
+
partialsDir: __dirname + '/views/partials'
|
|
39
|
+
}));
|
|
40
|
+
app.set('view engine', 'hbs');
|
|
41
|
+
app.set('views', __dirname + '/views');
|
|
42
|
+
```
|
|
43
|
+
|
|
44
|
+
`hbs.express3()` is still available for legacy apps and accepts the same
|
|
45
|
+
options:
|
|
46
|
+
|
|
47
|
+
```js
|
|
48
|
+
app.engine('hbs', hbs.express3({
|
|
49
|
+
partialsDir: __dirname + '/views/partials'
|
|
50
|
+
}));
|
|
51
|
+
```
|
|
52
|
+
|
|
53
|
+
Options for `express3()` and `express4()`:
|
|
54
|
+
|
|
55
|
+
```js
|
|
56
|
+
hbs.express4({
|
|
57
|
+
partialsDir: "{String/Array} [Required] Path to partials templates, one or several directories",
|
|
58
|
+
|
|
59
|
+
// OPTIONAL settings
|
|
60
|
+
restrictLayoutsTo: "{String} Absolute path to a directory to restrict layout directive reading from",
|
|
61
|
+
blockHelperName: "{String} Override 'block' helper name.",
|
|
62
|
+
contentHelperName: "{String} Override 'contentFor' helper name.",
|
|
63
|
+
defaultLayout: "{String} Absolute path to default layout template",
|
|
64
|
+
extname: "{String} Extension for templates & partials, defaults to `.hbs`",
|
|
65
|
+
handlebars: "{Module} Use external handlebars instead of express-hbs dependency",
|
|
66
|
+
i18n: "{Object} i18n object",
|
|
67
|
+
layoutsDir: "{String} Path to layout templates",
|
|
68
|
+
templateOptions: "{Object} options to pass to template()",
|
|
69
|
+
beautify: "{Boolean} whether to pretty print HTML, see github.com/einars/js-beautify .jsbeautifyrc",
|
|
70
|
+
|
|
71
|
+
// override the default compile
|
|
72
|
+
onCompile: function(exhbs, source, filename) {
|
|
73
|
+
var options;
|
|
74
|
+
if (filename && filename.indexOf('partials') > -1) {
|
|
75
|
+
options = {preventIndent: true};
|
|
76
|
+
}
|
|
77
|
+
return exhbs.handlebars.compile(source, options);
|
|
78
|
+
}
|
|
79
|
+
});
|
|
80
|
+
```
|
|
81
|
+
|
|
82
|
+
## Syntax
|
|
83
|
+
|
|
84
|
+
To mark where a layout should insert page content:
|
|
85
|
+
|
|
86
|
+
{{{body}}}
|
|
87
|
+
|
|
88
|
+
To declare a block placeholder in a layout:
|
|
89
|
+
|
|
90
|
+
{{{block "pageScripts"}}}
|
|
91
|
+
|
|
92
|
+
To define block content in a page:
|
|
93
|
+
|
|
94
|
+
{{#contentFor "pageScripts"}}
|
|
95
|
+
CONTENT HERE
|
|
96
|
+
{{/contentFor}}
|
|
97
|
+
|
|
98
|
+
## Layouts
|
|
99
|
+
|
|
100
|
+
There are three ways to use a layout, listed in precedence order:
|
|
101
|
+
|
|
102
|
+
1. Declarative within a page. Use handlebars comment
|
|
103
|
+
|
|
104
|
+
{{!< LAYOUT}}
|
|
105
|
+
|
|
106
|
+
Layout file resolution:
|
|
107
|
+
|
|
108
|
+
If path starts with '.'
|
|
109
|
+
LAYOUT is relative to template
|
|
110
|
+
Else If `layoutsDir` is set
|
|
111
|
+
LAYOUT is relative to `layoutsDir`
|
|
112
|
+
Else
|
|
113
|
+
LAYOUT from path.resolve(dirname(template), LAYOUT)
|
|
114
|
+
|
|
115
|
+
2. As an option to render
|
|
116
|
+
|
|
117
|
+
⚠️ Passing user-controlled data into the `layout` option can read arbitrary
|
|
118
|
+
files unless `restrictLayoutsTo` confines layout resolution to a safe
|
|
119
|
+
directory. Do not call `res.render('index', req.query)` or similar without
|
|
120
|
+
setting `restrictLayoutsTo`.
|
|
121
|
+
|
|
122
|
+
```js
|
|
123
|
+
res.render('veggies', {
|
|
124
|
+
title: 'My favorite veggies',
|
|
125
|
+
veggies: veggies,
|
|
126
|
+
layout: 'layout/veggie'
|
|
127
|
+
});
|
|
128
|
+
```
|
|
129
|
+
|
|
130
|
+
This option also allows layout suppression, including the default layout and
|
|
131
|
+
template-declared layouts, by passing a falsey JavaScript value:
|
|
132
|
+
|
|
133
|
+
```js
|
|
134
|
+
res.render('veggies', {
|
|
135
|
+
title: 'My favorite veggies',
|
|
136
|
+
veggies: veggies,
|
|
137
|
+
layout: null // render without using a layout template
|
|
138
|
+
});
|
|
139
|
+
```
|
|
140
|
+
|
|
141
|
+
Layout file resolution:
|
|
142
|
+
|
|
143
|
+
If path starts with '.'
|
|
144
|
+
layout is relative to template
|
|
145
|
+
Else If `layoutsDir` is set
|
|
146
|
+
layout is relative to `layoutsDir`
|
|
147
|
+
Else
|
|
148
|
+
layout from path.resolve(viewsDir, layout)
|
|
149
|
+
|
|
150
|
+
3. Lastly, use `defaultLayout` if specified in hbs configuration options.
|
|
151
|
+
|
|
152
|
+
Layouts can be nested: just include a declarative layout tag within any layout
|
|
153
|
+
template to have its content included in the declared "parent" layout. Be
|
|
154
|
+
aware that too much nesting can impact performances, and stay away from
|
|
155
|
+
infinite loops!
|
|
156
|
+
|
|
157
|
+
## Helpers
|
|
158
|
+
|
|
159
|
+
### Synchronous helpers
|
|
160
|
+
|
|
161
|
+
```js
|
|
162
|
+
hbs.registerHelper('link', function(text, options) {
|
|
163
|
+
var attrs = [];
|
|
164
|
+
for(var prop in options.hash) {
|
|
165
|
+
attrs.push(prop + '="' + options.hash[prop] + '"');
|
|
166
|
+
}
|
|
167
|
+
return new hbs.SafeString(
|
|
168
|
+
"<a " + attrs.join(" ") + ">" + text + "</a>"
|
|
169
|
+
);
|
|
170
|
+
});
|
|
171
|
+
```
|
|
172
|
+
|
|
173
|
+
in markup
|
|
174
|
+
```
|
|
175
|
+
{{{link 'barc.com' href='http://barc.com'}}}
|
|
176
|
+
```
|
|
177
|
+
|
|
178
|
+
### Asynchronous helpers
|
|
179
|
+
|
|
180
|
+
```js
|
|
181
|
+
hbs.registerAsyncHelper('readFile', function(filename, cb) {
|
|
182
|
+
fs.readFile(path.join(viewsDir, filename), 'utf8', function(err, content) {
|
|
183
|
+
cb(new hbs.SafeString(content));
|
|
184
|
+
});
|
|
185
|
+
});
|
|
186
|
+
```
|
|
187
|
+
|
|
188
|
+
in markup
|
|
189
|
+
```
|
|
190
|
+
{{{readFile 'tos.txt'}}}
|
|
191
|
+
```
|
|
192
|
+
|
|
193
|
+
|
|
194
|
+
## i18n support
|
|
195
|
+
|
|
196
|
+
Express-hbs supports [i18n](https://github.com/mashpie/i18n-node)
|
|
197
|
+
|
|
198
|
+
```js
|
|
199
|
+
var i18n = require('i18n');
|
|
200
|
+
|
|
201
|
+
// minimal config
|
|
202
|
+
i18n.configure({
|
|
203
|
+
locales: ['en', 'fr'],
|
|
204
|
+
cookie: 'locale',
|
|
205
|
+
directory: __dirname + "/locales"
|
|
206
|
+
});
|
|
207
|
+
|
|
208
|
+
app.engine('hbs', hbs.express3({
|
|
209
|
+
// ... options from above
|
|
210
|
+
i18n: i18n, // registers __ and __n helpers
|
|
211
|
+
}));
|
|
212
|
+
app.set('view engine', 'hbs');
|
|
213
|
+
app.set('views', viewsDir);
|
|
214
|
+
|
|
215
|
+
// cookies are needed
|
|
216
|
+
app.use(express.cookieParser());
|
|
217
|
+
|
|
218
|
+
// init i18n module
|
|
219
|
+
app.use(i18n.init);
|
|
220
|
+
```
|
|
221
|
+
|
|
222
|
+
## Engine Instances
|
|
223
|
+
|
|
224
|
+
Create isolated engine instances with their own cache system and handlebars engine.
|
|
225
|
+
|
|
226
|
+
```js
|
|
227
|
+
var hbs = require('express-hbs');
|
|
228
|
+
var instance1 = hbs.create();
|
|
229
|
+
var instance2 = hbs.create();
|
|
230
|
+
```
|
|
231
|
+
|
|
232
|
+
## Template options
|
|
233
|
+
|
|
234
|
+
The main use case for template options is setting the Handlebars `data` object,
|
|
235
|
+
which creates global template variables accessible with an `@` prefix.
|
|
236
|
+
|
|
237
|
+
Template options can be passed when creating an engine instance, updated with
|
|
238
|
+
`updateTemplateOptions(templateOptions)`, or set for one request with
|
|
239
|
+
`updateLocalTemplateOptions(locals, templateOptions)` on `res.locals`.
|
|
240
|
+
|
|
241
|
+
Both of these methods have a companion method `getTemplateOptions()` and `getLocalTemplateOptions(locals)`, which should be used when extending or merging the current options.
|
|
242
|
+
|
|
243
|
+
## Example
|
|
244
|
+
|
|
245
|
+
in File `app.js`
|
|
246
|
+
|
|
247
|
+
```js
|
|
248
|
+
// http://expressjs.com/api.html#app.locals
|
|
249
|
+
app.locals({
|
|
250
|
+
'PROD_MODE': 'production' === app.get('env')
|
|
251
|
+
});
|
|
252
|
+
|
|
253
|
+
```
|
|
254
|
+
|
|
255
|
+
File `views/layout/default.hbs`
|
|
256
|
+
|
|
257
|
+
```html
|
|
258
|
+
<html>
|
|
259
|
+
<head>
|
|
260
|
+
<title>{{title}}</title>
|
|
261
|
+
<link type="text/css" rel="stylesheet" href="/css/style.css"/>
|
|
262
|
+
{{{block "pageStyles"}}}
|
|
263
|
+
</head>
|
|
264
|
+
<body>
|
|
265
|
+
{{{body}}}
|
|
266
|
+
|
|
267
|
+
{{> scripts}}
|
|
268
|
+
|
|
269
|
+
{{#if PROD_MODE}}
|
|
270
|
+
{{{block 'googleAnalyticsScripts'}}}
|
|
271
|
+
{{/if}}
|
|
272
|
+
|
|
273
|
+
</body>
|
|
274
|
+
</html>
|
|
275
|
+
```
|
|
276
|
+
|
|
277
|
+
|
|
278
|
+
File `views/index.hbs`
|
|
279
|
+
|
|
280
|
+
```html
|
|
281
|
+
{{!< default}}
|
|
282
|
+
|
|
283
|
+
{{#contentFor 'pageStyles'}}
|
|
284
|
+
<style>
|
|
285
|
+
.clicker {
|
|
286
|
+
color: blue;
|
|
287
|
+
};
|
|
288
|
+
</style>
|
|
289
|
+
{{/contentFor}}
|
|
290
|
+
|
|
291
|
+
<h1>{{title}}</h1>
|
|
292
|
+
<p class="clicker">Click me!</p>
|
|
293
|
+
```
|
|
294
|
+
|
|
295
|
+
To run example project
|
|
296
|
+
|
|
297
|
+
```sh
|
|
298
|
+
pnpm install
|
|
299
|
+
node example/app.js
|
|
300
|
+
```
|
|
301
|
+
|
|
302
|
+
The example server listens on <http://localhost:3000>.
|
|
303
|
+
|
|
304
|
+
## Testing
|
|
305
|
+
|
|
306
|
+
Install dependencies and run the test suite:
|
|
307
|
+
|
|
308
|
+
```sh
|
|
309
|
+
pnpm install
|
|
310
|
+
pnpm test
|
|
311
|
+
```
|
|
312
|
+
|
|
313
|
+
Useful maintainer commands:
|
|
314
|
+
|
|
315
|
+
```sh
|
|
316
|
+
pnpm lint # oxlint plus oxfmt --check
|
|
317
|
+
pnpm lint:fix # apply safe lint fixes and formatting
|
|
318
|
+
pnpm coverage # mocha under nyc with enforced coverage thresholds
|
|
319
|
+
```
|
|
320
|
+
|
|
321
|
+
|
|
322
|
+
## Credits
|
|
323
|
+
|
|
324
|
+
Inspiration and code from [donpark/hbs](https://github.com/donpark/hbs)
|
|
325
|
+
|
|
326
|
+
Big thanks to all [CONTRIBUTORS](https://github.com/TryGhost/express-hbs/contributors)
|
|
327
|
+
|
|
328
|
+
|
|
329
|
+
## License
|
|
330
|
+
|
|
331
|
+
The MIT License (MIT)
|
|
332
|
+
|
|
333
|
+
Copyright (c) 2012-2026 Barc, Inc., Ghost Foundation - Released under the [MIT license](LICENSE).
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
# Reporting Security Vulnerabilities
|
|
2
|
+
|
|
3
|
+
Potential security vulnerabilities can be reported directly us at `security@ghost.org`. The Ghost Security Team communicates privately and works in a secured, isolated repository for tracking, testing, and resolving security-related issues.
|
|
4
|
+
|
|
5
|
+
The full, up-to-date details of our security policy and procedure can always be found in our documentation:
|
|
6
|
+
|
|
7
|
+
https://ghost.org/docs/security/
|
|
8
|
+
|
|
9
|
+
Please refer to this before emailing us. Thanks for helping make Ghost safe for everyone 🙏.
|
|
@@ -0,0 +1,99 @@
|
|
|
1
|
+
// pnpm add express express-hbs
|
|
2
|
+
|
|
3
|
+
'use strict';
|
|
4
|
+
|
|
5
|
+
var express = require('express');
|
|
6
|
+
var app = express();
|
|
7
|
+
var hbs = require('..'); // should be `require('express-hbs')` outside of this example
|
|
8
|
+
var fs = require('fs');
|
|
9
|
+
var fp = require('path');
|
|
10
|
+
|
|
11
|
+
function relative(path) {
|
|
12
|
+
return fp.join(__dirname, path);
|
|
13
|
+
}
|
|
14
|
+
var viewsDir = relative('views');
|
|
15
|
+
|
|
16
|
+
app.use(express.static(relative('public')));
|
|
17
|
+
|
|
18
|
+
// Hook in express-hbs and tell it where known directories reside
|
|
19
|
+
app.engine(
|
|
20
|
+
'hbs',
|
|
21
|
+
hbs.express4({
|
|
22
|
+
partialsDir: [relative('views/partials'), relative('views/partials-other')],
|
|
23
|
+
layoutsDir: relative('views/layout'),
|
|
24
|
+
defaultLayout: relative('views/layout/default.hbs'),
|
|
25
|
+
restrictLayoutsTo: relative('views/layout'),
|
|
26
|
+
}),
|
|
27
|
+
);
|
|
28
|
+
app.set('view engine', 'hbs');
|
|
29
|
+
app.set('views', relative('views'));
|
|
30
|
+
|
|
31
|
+
// Register sync helper
|
|
32
|
+
hbs.registerHelper('link', function (text, options) {
|
|
33
|
+
var attrs = [];
|
|
34
|
+
for (var prop in options.hash) {
|
|
35
|
+
attrs.push(prop + '="' + options.hash[prop] + '"');
|
|
36
|
+
}
|
|
37
|
+
return new hbs.SafeString('<a ' + attrs.join(' ') + '>' + text + '</a>');
|
|
38
|
+
});
|
|
39
|
+
|
|
40
|
+
// Register Async helpers
|
|
41
|
+
hbs.registerAsyncHelper('readFile', function (filename, cb) {
|
|
42
|
+
fs.readFile(fp.join(viewsDir, filename), 'utf8', function (err, content) {
|
|
43
|
+
if (err) console.error(err);
|
|
44
|
+
cb(new hbs.SafeString(content));
|
|
45
|
+
});
|
|
46
|
+
});
|
|
47
|
+
|
|
48
|
+
var fruits = [{ name: 'apple' }, { name: 'orange' }, { name: 'pear' }];
|
|
49
|
+
|
|
50
|
+
var veggies = [{ name: 'asparagus' }, { name: 'carrot' }, { name: 'spinach' }];
|
|
51
|
+
|
|
52
|
+
app.get('/', function (req, res) {
|
|
53
|
+
res.render('index', {
|
|
54
|
+
title: 'express-hbs example',
|
|
55
|
+
});
|
|
56
|
+
});
|
|
57
|
+
|
|
58
|
+
app.get('/fruits', function (req, res) {
|
|
59
|
+
res.render('fruits/index-layoutsDir', {
|
|
60
|
+
title: 'My favorite fruits',
|
|
61
|
+
fruits: fruits,
|
|
62
|
+
});
|
|
63
|
+
});
|
|
64
|
+
|
|
65
|
+
app.get('/fruits/:name', function (req, res) {
|
|
66
|
+
res.render('fruits/details-layoutsDir', {
|
|
67
|
+
fruit: req.params.name,
|
|
68
|
+
});
|
|
69
|
+
});
|
|
70
|
+
|
|
71
|
+
app.get('/veggies', function (req, res) {
|
|
72
|
+
res.render('veggies', {
|
|
73
|
+
title: 'My favorite veggies',
|
|
74
|
+
veggies: veggies,
|
|
75
|
+
layout: 'veggie',
|
|
76
|
+
});
|
|
77
|
+
});
|
|
78
|
+
|
|
79
|
+
app.get('/veggies/explicit-dir', function (req, res) {
|
|
80
|
+
res.render('veggies', {
|
|
81
|
+
title: 'My favorite veggies',
|
|
82
|
+
veggies: veggies,
|
|
83
|
+
layout: relative('views/layout/veggie'),
|
|
84
|
+
});
|
|
85
|
+
});
|
|
86
|
+
|
|
87
|
+
app.get('/veggies/:name', function (req, res) {
|
|
88
|
+
res.render('veggies/details', {
|
|
89
|
+
veggie: req.params.name,
|
|
90
|
+
layout: 'veggie-details',
|
|
91
|
+
});
|
|
92
|
+
});
|
|
93
|
+
|
|
94
|
+
if (require.main === module) {
|
|
95
|
+
app.listen(3000);
|
|
96
|
+
console.log('Express server listening on port 3000');
|
|
97
|
+
} else {
|
|
98
|
+
module.exports = app;
|
|
99
|
+
}
|
|
@@ -0,0 +1,103 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
// pnpm add express express-hbs
|
|
3
|
+
|
|
4
|
+
function create(hbs, env) {
|
|
5
|
+
if (env) process.env.NODE_ENV = env;
|
|
6
|
+
|
|
7
|
+
var express = require('express');
|
|
8
|
+
var app = express();
|
|
9
|
+
var fs = require('fs');
|
|
10
|
+
var fp = require('path');
|
|
11
|
+
|
|
12
|
+
function relative(path) {
|
|
13
|
+
return fp.join(__dirname, path);
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
var viewsDir = relative('views');
|
|
17
|
+
|
|
18
|
+
app.use(express.static(relative('public')));
|
|
19
|
+
|
|
20
|
+
// Hook in express-hbs and tell it where known directories reside
|
|
21
|
+
app.engine(
|
|
22
|
+
'hbs',
|
|
23
|
+
hbs.express4({
|
|
24
|
+
partialsDir: [relative('views/partials'), relative('views/partials-other')],
|
|
25
|
+
defaultLayout: relative('views/layout/default.hbs'),
|
|
26
|
+
restrictLayoutsTo: viewsDir,
|
|
27
|
+
}),
|
|
28
|
+
);
|
|
29
|
+
app.set('view engine', 'hbs');
|
|
30
|
+
app.set('views', viewsDir);
|
|
31
|
+
|
|
32
|
+
// Register sync helper
|
|
33
|
+
hbs.registerHelper('link', function (text, options) {
|
|
34
|
+
var attrs = [];
|
|
35
|
+
for (var prop in options.hash) {
|
|
36
|
+
attrs.push(prop + '="' + options.hash[prop] + '"');
|
|
37
|
+
}
|
|
38
|
+
return new hbs.SafeString('<a ' + attrs.join(' ') + '>' + text + '</a>');
|
|
39
|
+
});
|
|
40
|
+
|
|
41
|
+
// Register Async helpers
|
|
42
|
+
hbs.registerAsyncHelper('readFile', function (filename, cb) {
|
|
43
|
+
fs.readFile(fp.join(viewsDir, filename), 'utf8', function (err, content) {
|
|
44
|
+
if (err) console.error(err);
|
|
45
|
+
cb(new hbs.SafeString(content));
|
|
46
|
+
});
|
|
47
|
+
});
|
|
48
|
+
|
|
49
|
+
var fruits = [{ name: 'apple' }, { name: 'orange' }, { name: 'pear' }];
|
|
50
|
+
|
|
51
|
+
var veggies = [{ name: 'asparagus' }, { name: 'carrot' }, { name: 'spinach' }];
|
|
52
|
+
|
|
53
|
+
app.get('/', function (req, res) {
|
|
54
|
+
res.render('index', {
|
|
55
|
+
title: 'express-hbs example',
|
|
56
|
+
});
|
|
57
|
+
});
|
|
58
|
+
|
|
59
|
+
app.get('/replace', function (req, res) {
|
|
60
|
+
res.render('replace', {
|
|
61
|
+
title: 'express-hbs example',
|
|
62
|
+
});
|
|
63
|
+
});
|
|
64
|
+
|
|
65
|
+
app.get('/fruits', function (req, res) {
|
|
66
|
+
res.render('fruits/index', {
|
|
67
|
+
title: 'My favorite fruits',
|
|
68
|
+
fruits: fruits,
|
|
69
|
+
});
|
|
70
|
+
});
|
|
71
|
+
|
|
72
|
+
app.get('/fruits/:name', function (req, res) {
|
|
73
|
+
res.render('fruits/details', {
|
|
74
|
+
fruit: req.params.name,
|
|
75
|
+
});
|
|
76
|
+
});
|
|
77
|
+
|
|
78
|
+
app.get('/veggies', function (req, res) {
|
|
79
|
+
res.render('veggies', {
|
|
80
|
+
title: 'My favorite veggies',
|
|
81
|
+
veggies: veggies,
|
|
82
|
+
layout: 'layout/veggie',
|
|
83
|
+
});
|
|
84
|
+
});
|
|
85
|
+
|
|
86
|
+
app.get('/veggies/:name', function (req, res) {
|
|
87
|
+
res.render('veggies/details', {
|
|
88
|
+
veggie: req.params.name,
|
|
89
|
+
layout: 'layout/veggie-details',
|
|
90
|
+
});
|
|
91
|
+
});
|
|
92
|
+
|
|
93
|
+
return app;
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
if (require.main === module) {
|
|
97
|
+
var hbs = require('..');
|
|
98
|
+
var app = create(hbs);
|
|
99
|
+
app.listen(3000);
|
|
100
|
+
console.log('Express server listening on port 3000');
|
|
101
|
+
} else {
|
|
102
|
+
exports.create = create;
|
|
103
|
+
}
|
package/.claude/worktrees/security-patches-review-c621ea/example/views/fruits/index-layoutsDir.hbs
ADDED
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
<!-- name of layout -->
|
|
2
|
+
{{!< fruits}}
|
|
3
|
+
|
|
4
|
+
{{#contentFor 'pageStyles'}}
|
|
5
|
+
<style>
|
|
6
|
+
li a {
|
|
7
|
+
color: #800;
|
|
8
|
+
}
|
|
9
|
+
</style>
|
|
10
|
+
{{/contentFor}}
|
|
11
|
+
|
|
12
|
+
|
|
13
|
+
<h1>{{title}}</h1>
|
|
14
|
+
<ul>
|
|
15
|
+
{{#each fruits}}
|
|
16
|
+
<li>
|
|
17
|
+
<a href="/fruits/{{this.name}}">{{this.name}}</a>
|
|
18
|
+
</li>
|
|
19
|
+
{{/each}}
|
|
20
|
+
</ul>
|