express-hbs 3.0.0 → 4.0.0
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/README.md +2 -2
- package/lib/hbs.js +7 -1
- package/package.json +16 -12
- package/.editorconfig +0 -8
- package/.github/workflows/publish.yml +0 -73
- package/.github/workflows/test.yml +0 -48
- package/.jsbeautifyrc +0 -17
- package/.nvmrc +0 -1
- package/.nycrc.json +0 -16
- package/.oxfmtrc.json +0 -19
- package/.oxlintrc.json +0 -32
- package/AGENTS.md +0 -40
- package/SECURITY.md +0 -9
- package/example/app-layoutsDir.js +0 -99
- package/example/app.js +0 -103
- package/example/public/css/style.css +0 -17
- package/example/views/fruits/details-layoutsDir.hbs +0 -3
- package/example/views/fruits/details.hbs +0 -4
- package/example/views/fruits/index-layoutsDir.hbs +0 -20
- package/example/views/fruits/index.hbs +0 -20
- package/example/views/index.hbs +0 -34
- package/example/views/layout/default.hbs +0 -13
- package/example/views/layout/fruit-details.hbs +0 -9
- package/example/views/layout/fruits.hbs +0 -6
- package/example/views/layout/html-struct.hbs +0 -21
- package/example/views/layout/veggie-details.hbs +0 -9
- package/example/views/layout/veggie.hbs +0 -6
- package/example/views/partials/scripts.hbs +0 -5
- package/example/views/partials/sub/comment.hbs +0 -1
- package/example/views/partials-other/other.hbs +0 -1
- package/example/views/replace.hbs +0 -6
- package/example/views/tos.txt +0 -3
- package/example/views/veggies/details.hbs +0 -1
- package/example/views/veggies.hbs +0 -17
- package/renovate.json +0 -13
- package/test/apps/async/index.js +0 -139
- package/test/apps/async/views/failer.hbs +0 -4
- package/test/apps/async/views/index.hbs +0 -16
- package/test/apps/async/views/layout.hbs +0 -1
- package/test/apps/i18n/index.js +0 -57
- package/test/apps/i18n/locales/en.json +0 -8
- package/test/apps/i18n/locales/fr.json +0 -8
- package/test/apps/i18n/views/index.hbs +0 -3
- package/test/asyncSpecs.js +0 -69
- package/test/cacheSpecs.js +0 -135
- package/test/customExtension.js +0 -35
- package/test/handlebarsSpecs.js +0 -92
- package/test/helperSpecs.js +0 -58
- package/test/helpers.js +0 -24
- package/test/i18nSpecs.js +0 -36
- package/test/issues/144/index.hbs +0 -1
- package/test/issues/153/index.hbs +0 -3
- package/test/issues/21/views/index.hbs +0 -1
- package/test/issues/21/views/layouts/default.hbs +0 -1
- package/test/issues/21/views/layouts/sub/child.hbs +0 -1
- package/test/issues/21/views/sub/relativeLayout.hbs +0 -1
- package/test/issues/21/views/sub/sub.hbs +0 -1
- package/test/issues/21/views/useLayoutInDir.hbs +0 -1
- package/test/issues/22/layout1.hbs +0 -1
- package/test/issues/22/layout2.hbs +0 -1
- package/test/issues/22/template.hbs +0 -1
- package/test/issues/23/empty.hbs +0 -0
- package/test/issues/23/emptyComment.hbs +0 -1
- package/test/issues/23/emptyPartial.hbs +0 -1
- package/test/issues/23/index.hbs +0 -4
- package/test/issues/23/layout.hbs +0 -1
- package/test/issues/23/partials/custom/comment-only.hbs +0 -1
- package/test/issues/23/partials/custom/empty.hbs +0 -0
- package/test/issues/23/partials/hello.hbs +0 -1
- package/test/issues/49/error.hbs +0 -1
- package/test/issues/49/front/error.hbs +0 -1
- package/test/issues/49/index.hbs +0 -2
- package/test/issues/49/layouts/default.hbs +0 -1
- package/test/issues/49/partial.hbs +0 -1
- package/test/issues/49/partials/partial-error.hbs +0 -1
- package/test/issues/53/default.hbs +0 -15
- package/test/issues/53/index.hbs +0 -7
- package/test/issues/53/partials/.gitkeep +0 -0
- package/test/issues/59/index.hbs +0 -2
- package/test/issues/62/basic.hbs +0 -2
- package/test/issues/62/block.hbs +0 -11
- package/test/issues/73/index.hbs +0 -5
- package/test/issues/73/partials/partial.hbs +0 -6
- package/test/issues/76/mypartial.hbs +0 -0
- package/test/issues/84/index.hbs +0 -1
- package/test/issues/84/partials/abc/def/ghi/test.hbs +0 -1
- package/test/issues.js +0 -490
- package/test/layoutSpecs.js +0 -116
- package/test/localTemplateOptions/data-access-template.hbs +0 -1
- package/test/localTemplateOptions/template.hbs +0 -1
- package/test/localTemplateOptions.js +0 -125
- package/test/multiple.js +0 -115
- package/test/nonExpress.js +0 -36
- package/test/optionsSpecs.js +0 -22
- package/test/resolverSpecs.js +0 -54
- package/test/views/beautify/expected.hbs +0 -9
- package/test/views/beautify/index.hbs +0 -2
- package/test/views/customExtension/layout.server.view.html +0 -1
- package/test/views/customExtension/partialsDir/partial1.server.view.html +0 -1
- package/test/views/customExtension/partialsDir/partial2.server.view.html +0 -1
- package/test/views/customExtension/partialsDir/subs/subPartial1.server.view.html +0 -1
- package/test/views/customExtension/partialsDir/subs/subPartial2.server.view.html +0 -1
- package/test/views/customExtension/template.server.view.html +0 -5
- package/test/views/disableLayoutDirective/aside.hbs +0 -1
- package/test/views/disableLayoutDirective/index.hbs +0 -2
- package/test/views/disableLayoutDirective/layouts/default.hbs +0 -1
- package/test/views/helpers/home/async.hbs +0 -6
- package/test/views/helpers/home/index.hbs +0 -3
- package/test/views/helpers/layouts/default.hbs +0 -1
- package/test/views/multiple/views1/collide.hbs +0 -1
- package/test/views/multiple/views1/error.hbs +0 -1
- package/test/views/multiple/views1/test1.hbs +0 -1
- package/test/views/multiple/views2/collide.hbs +0 -1
- package/test/views/multiple/views2/error.hbs +0 -1
- package/test/views/multiple/views2/test2.hbs +0 -1
- package/test/views/viewsDir/layouts/default.hbs +0 -1
- package/test/views/viewsDir/sub/directive.hbs +0 -2
- package/test/views/viewsDir/sub/lay.hbs +0 -1
package/README.md
CHANGED
|
@@ -10,8 +10,8 @@ layout inheritance and block-style content regions while keeping the familiar
|
|
|
10
10
|
|
|
11
11
|
## Requirements
|
|
12
12
|
|
|
13
|
-
- Node.js
|
|
14
|
-
- pnpm
|
|
13
|
+
- Node.js 22 or later
|
|
14
|
+
- the pinned pnpm version when working on this repository
|
|
15
15
|
|
|
16
16
|
## v2.0.0
|
|
17
17
|
|
package/lib/hbs.js
CHANGED
|
@@ -99,7 +99,13 @@ ExpressHbs.prototype.cacheLayout = function (layoutFile, useCache, cb) {
|
|
|
99
99
|
var self = this;
|
|
100
100
|
|
|
101
101
|
if (this.restrictLayoutsTo) {
|
|
102
|
-
|
|
102
|
+
var relativePath = path.relative(this.restrictLayoutsTo, layoutFile);
|
|
103
|
+
var outside =
|
|
104
|
+
relativePath === '..' ||
|
|
105
|
+
relativePath.startsWith('..' + path.sep) ||
|
|
106
|
+
path.isAbsolute(relativePath);
|
|
107
|
+
|
|
108
|
+
if (outside) {
|
|
103
109
|
var err = new Error(
|
|
104
110
|
'Cannot read ' + layoutFile + ' it does not reside in ' + this.restrictLayoutsTo,
|
|
105
111
|
);
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "express-hbs",
|
|
3
|
-
"version": "
|
|
3
|
+
"version": "4.0.0",
|
|
4
4
|
"description": "Express handlebars template engine complete with multiple layouts, partials and blocks.",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"express4",
|
|
@@ -10,8 +10,12 @@
|
|
|
10
10
|
"partials"
|
|
11
11
|
],
|
|
12
12
|
"main": "index.js",
|
|
13
|
+
"files": [
|
|
14
|
+
"index.js",
|
|
15
|
+
"lib"
|
|
16
|
+
],
|
|
13
17
|
"engines": {
|
|
14
|
-
"node": ">=
|
|
18
|
+
"node": ">=22"
|
|
15
19
|
},
|
|
16
20
|
"directories": {
|
|
17
21
|
"example": "example"
|
|
@@ -24,21 +28,21 @@
|
|
|
24
28
|
"author": "Mario Gutierrez <mario@barc.com>",
|
|
25
29
|
"license": "MIT",
|
|
26
30
|
"devDependencies": {
|
|
31
|
+
"@tryghost/pro-ship": "2.0.1",
|
|
27
32
|
"cookie-parser": "1.4.7",
|
|
28
|
-
"express": "5.
|
|
29
|
-
"i18n": "0.15.
|
|
30
|
-
"mocha": "
|
|
33
|
+
"express": "5.3.0",
|
|
34
|
+
"i18n": "0.15.4",
|
|
35
|
+
"mocha": "12.0.3",
|
|
31
36
|
"nyc": "18.0.0",
|
|
32
|
-
"oxfmt": "0.
|
|
33
|
-
"oxlint": "1.
|
|
37
|
+
"oxfmt": "0.76.0",
|
|
38
|
+
"oxlint": "1.91.0",
|
|
34
39
|
"rewire": "9.0.1",
|
|
35
|
-
"supertest": "7.
|
|
40
|
+
"supertest": "7.3.2"
|
|
36
41
|
},
|
|
37
42
|
"dependencies": {
|
|
38
|
-
"
|
|
39
|
-
"
|
|
40
|
-
"
|
|
41
|
-
"readdirp": "3.6.0"
|
|
43
|
+
"handlebars": "^4.7.10",
|
|
44
|
+
"lodash": "^4.18.1",
|
|
45
|
+
"readdirp": "^3.6.0"
|
|
42
46
|
},
|
|
43
47
|
"optionalDependencies": {
|
|
44
48
|
"js-beautify": "^2.0.0"
|
package/.editorconfig
DELETED
|
@@ -1,73 +0,0 @@
|
|
|
1
|
-
name: Publish
|
|
2
|
-
|
|
3
|
-
on:
|
|
4
|
-
push:
|
|
5
|
-
branches:
|
|
6
|
-
- main
|
|
7
|
-
paths:
|
|
8
|
-
- 'package.json'
|
|
9
|
-
workflow_dispatch:
|
|
10
|
-
inputs:
|
|
11
|
-
dry-run:
|
|
12
|
-
description: 'Preview what would be published without actually publishing'
|
|
13
|
-
required: false
|
|
14
|
-
type: boolean
|
|
15
|
-
default: true
|
|
16
|
-
|
|
17
|
-
concurrency:
|
|
18
|
-
group: ${{ github.workflow }}-${{ github.ref }}
|
|
19
|
-
|
|
20
|
-
jobs:
|
|
21
|
-
publish:
|
|
22
|
-
name: Publish to npm
|
|
23
|
-
runs-on: ubuntu-latest
|
|
24
|
-
|
|
25
|
-
permissions:
|
|
26
|
-
# OIDC trusted publishing to npm. Provenance is enabled because this
|
|
27
|
-
# repository is public; public repos can generate a provenance
|
|
28
|
-
# attestation at publish time.
|
|
29
|
-
id-token: write
|
|
30
|
-
contents: read
|
|
31
|
-
|
|
32
|
-
env:
|
|
33
|
-
FORCE_COLOR: 1
|
|
34
|
-
CI: true
|
|
35
|
-
NPM_CONFIG_PROVENANCE: true
|
|
36
|
-
NPM_CONFIG_REGISTRY: 'https://registry.npmjs.org'
|
|
37
|
-
|
|
38
|
-
steps:
|
|
39
|
-
- uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7
|
|
40
|
-
with:
|
|
41
|
-
persist-credentials: false
|
|
42
|
-
|
|
43
|
-
- uses: actions/setup-node@48b55a011bda9f5d6aeb4c2d9c7362e8dae4041e # v6
|
|
44
|
-
with:
|
|
45
|
-
node-version: '24.14.1'
|
|
46
|
-
registry-url: 'https://registry.npmjs.org'
|
|
47
|
-
|
|
48
|
-
- name: Install Corepack
|
|
49
|
-
run: npm install --global corepack@0.34.6
|
|
50
|
-
- name: Enable corepack
|
|
51
|
-
run: corepack enable
|
|
52
|
-
|
|
53
|
-
- name: Install dependencies
|
|
54
|
-
run: pnpm install --frozen-lockfile --prefer-offline
|
|
55
|
-
|
|
56
|
-
- name: Determine whether to publish
|
|
57
|
-
id: pub
|
|
58
|
-
run: |
|
|
59
|
-
name=$(jq -r .name package.json)
|
|
60
|
-
version=$(jq -r .version package.json)
|
|
61
|
-
if [ -n "$(npm view "$name@$version" version 2>/dev/null)" ]; then
|
|
62
|
-
echo "$name@$version is already published; nothing to do"
|
|
63
|
-
echo "publish=false" >> "$GITHUB_OUTPUT"
|
|
64
|
-
else
|
|
65
|
-
echo "queueing $name@$version"
|
|
66
|
-
echo "publish=true" >> "$GITHUB_OUTPUT"
|
|
67
|
-
fi
|
|
68
|
-
|
|
69
|
-
- name: Publish to npm
|
|
70
|
-
if: steps.pub.outputs.publish == 'true'
|
|
71
|
-
# --no-git-checks is required because actions/checkout leaves the repo on
|
|
72
|
-
# a detached HEAD, which pnpm's default publish branch check rejects.
|
|
73
|
-
run: pnpm publish --no-git-checks ${{ (github.event.inputs['dry-run'] == 'true' && '--dry-run') || '' }}
|
|
@@ -1,48 +0,0 @@
|
|
|
1
|
-
name: Test
|
|
2
|
-
|
|
3
|
-
on:
|
|
4
|
-
pull_request:
|
|
5
|
-
push:
|
|
6
|
-
branches:
|
|
7
|
-
- main
|
|
8
|
-
|
|
9
|
-
permissions:
|
|
10
|
-
contents: read
|
|
11
|
-
|
|
12
|
-
concurrency:
|
|
13
|
-
group: ${{ github.workflow }}-${{ github.event.pull_request.number || github.ref }}
|
|
14
|
-
cancel-in-progress: true
|
|
15
|
-
|
|
16
|
-
jobs:
|
|
17
|
-
build:
|
|
18
|
-
runs-on: ubuntu-latest
|
|
19
|
-
timeout-minutes: 20
|
|
20
|
-
strategy:
|
|
21
|
-
fail-fast: false
|
|
22
|
-
matrix:
|
|
23
|
-
node: [20, 22, 24]
|
|
24
|
-
name: Node ${{ matrix.node }}
|
|
25
|
-
steps:
|
|
26
|
-
- uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0
|
|
27
|
-
with:
|
|
28
|
-
persist-credentials: false
|
|
29
|
-
- uses: pnpm/action-setup@0ebf47130e4866e96fce0953f49152a61190b271 # v6.0.9
|
|
30
|
-
- uses: actions/setup-node@48b55a011bda9f5d6aeb4c2d9c7362e8dae4041e # v6.4.0
|
|
31
|
-
with:
|
|
32
|
-
node-version: ${{ matrix.node }}
|
|
33
|
-
cache: pnpm
|
|
34
|
-
- run: pnpm install --frozen-lockfile
|
|
35
|
-
- run: pnpm lint
|
|
36
|
-
- name: Run tests with coverage
|
|
37
|
-
run: pnpm coverage
|
|
38
|
-
|
|
39
|
-
required-checks-pass:
|
|
40
|
-
name: Required checks pass
|
|
41
|
-
if: always()
|
|
42
|
-
needs: [build]
|
|
43
|
-
runs-on: ubuntu-latest
|
|
44
|
-
timeout-minutes: 5
|
|
45
|
-
steps:
|
|
46
|
-
- name: Verify all required jobs succeeded
|
|
47
|
-
if: contains(needs.*.result, 'failure') || contains(needs.*.result, 'cancelled')
|
|
48
|
-
run: exit 1
|
package/.jsbeautifyrc
DELETED
|
@@ -1,17 +0,0 @@
|
|
|
1
|
-
{
|
|
2
|
-
"indent_size": 2,
|
|
3
|
-
"indent_char": " ",
|
|
4
|
-
"indent_level": 0,
|
|
5
|
-
"indent_with_tabs": false,
|
|
6
|
-
"preserve_newlines": true,
|
|
7
|
-
"max_preserve_newlines": 10,
|
|
8
|
-
"jslint_happy": false,
|
|
9
|
-
"brace_style": "collapse",
|
|
10
|
-
"keep_array_indentation": false,
|
|
11
|
-
"keep_function_indentation": false,
|
|
12
|
-
"space_before_conditional": true,
|
|
13
|
-
"break_chained_methods": false,
|
|
14
|
-
"eval_code": false,
|
|
15
|
-
"unescape_strings": false,
|
|
16
|
-
"wrap_line_length": 0
|
|
17
|
-
}
|
package/.nvmrc
DELETED
|
@@ -1 +0,0 @@
|
|
|
1
|
-
20
|
package/.nycrc.json
DELETED
package/.oxfmtrc.json
DELETED
|
@@ -1,19 +0,0 @@
|
|
|
1
|
-
{
|
|
2
|
-
"$schema": "./node_modules/oxfmt/configuration_schema.json",
|
|
3
|
-
"singleQuote": true,
|
|
4
|
-
"tabWidth": 2,
|
|
5
|
-
"sortPackageJson": false,
|
|
6
|
-
"ignorePatterns": [
|
|
7
|
-
"**/node_modules/**",
|
|
8
|
-
"**/coverage/**",
|
|
9
|
-
"pnpm-lock.yaml",
|
|
10
|
-
"**/*.json",
|
|
11
|
-
"**/*.jsonc",
|
|
12
|
-
"**/*.yml",
|
|
13
|
-
"**/*.yaml",
|
|
14
|
-
"**/*.md",
|
|
15
|
-
"**/*.hbs",
|
|
16
|
-
"**/*.html",
|
|
17
|
-
"**/*.css"
|
|
18
|
-
]
|
|
19
|
-
}
|
package/.oxlintrc.json
DELETED
|
@@ -1,32 +0,0 @@
|
|
|
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
|
-
}
|
package/AGENTS.md
DELETED
|
@@ -1,40 +0,0 @@
|
|
|
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 pnpm 10 on Node.js 20 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.
|
package/SECURITY.md
DELETED
|
@@ -1,9 +0,0 @@
|
|
|
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 🙏.
|
|
@@ -1,99 +0,0 @@
|
|
|
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
|
-
}
|
package/example/app.js
DELETED
|
@@ -1,103 +0,0 @@
|
|
|
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
|
-
}
|
|
@@ -1,20 +0,0 @@
|
|
|
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>
|
|
@@ -1,20 +0,0 @@
|
|
|
1
|
-
<!-- name of layout -->
|
|
2
|
-
{{!< ../layout/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>
|
package/example/views/index.hbs
DELETED
|
@@ -1,34 +0,0 @@
|
|
|
1
|
-
{{#contentFor 'pageStyles'}}
|
|
2
|
-
<style>
|
|
3
|
-
.clicker {
|
|
4
|
-
color: blue;
|
|
5
|
-
};
|
|
6
|
-
</style>
|
|
7
|
-
{{/contentFor}}
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
{{#contentFor 'pageScripts'}}
|
|
11
|
-
<script>
|
|
12
|
-
$(function() {
|
|
13
|
-
$('.clicker').click(function() {
|
|
14
|
-
$(this).text('Hello express-hbs!');
|
|
15
|
-
});
|
|
16
|
-
});
|
|
17
|
-
</script>
|
|
18
|
-
{{/contentFor}}
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
<h1>{{title}}</h1>
|
|
22
|
-
<p class='clicker'>Click me!</p>
|
|
23
|
-
<p>
|
|
24
|
-
<a href='/fruits'>Favorite fruits</a>
|
|
25
|
-
</p>
|
|
26
|
-
<p>
|
|
27
|
-
<!-- sync helper -->
|
|
28
|
-
{{{link 'Vegetables' href='/veggies'}}}
|
|
29
|
-
</p>
|
|
30
|
-
|
|
31
|
-
<!-- async helper -->
|
|
32
|
-
<div>
|
|
33
|
-
{{{readFile 'tos.txt'}}}
|
|
34
|
-
</div>
|