@ynode/squirrellyify 1.3.0 → 1.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/README.md +26 -26
- package/index.d.ts +21 -0
- package/package.json +9 -5
- package/src/config.js +6 -25
- package/src/plugin.js +17 -33
- package/src/resolver.js +2 -9
package/README.md
CHANGED
|
@@ -76,8 +76,8 @@ fastify.listen({ port: 3000 }, (err) => {
|
|
|
76
76
|
|
|
77
77
|
### Request-Scoped View Data
|
|
78
78
|
|
|
79
|
-
`reply.view(template, data)` automatically merges request-scoped values from `reply.locals` and
|
|
80
|
-
|
|
79
|
+
`reply.view(template, data)` automatically merges request-scoped values from `reply.locals` and `reply.context` into the
|
|
80
|
+
template data:
|
|
81
81
|
|
|
82
82
|
```javascript
|
|
83
83
|
fastify.addHook("preHandler", async (request, reply) => {
|
|
@@ -100,22 +100,23 @@ Merge precedence is:
|
|
|
100
100
|
|
|
101
101
|
You can pass an options object when registering the plugin.
|
|
102
102
|
|
|
103
|
-
| Option
|
|
104
|
-
|
|
|
105
|
-
| `templates`
|
|
106
|
-
| `partials`
|
|
107
|
-
| `partialsRecursive` | `boolean`
|
|
108
|
-
| `partialsNamespace` | `boolean \| string`
|
|
109
|
-
| `layout`
|
|
110
|
-
| `defaultExtension`
|
|
111
|
-
| `cache`
|
|
112
|
-
| `sqrl`
|
|
103
|
+
| Option | Type | Default | Description |
|
|
104
|
+
| ------------------- | -------------------- | ----------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------ |
|
|
105
|
+
| `templates` | `string \| string[]` | `path.join(process.cwd(), "views")` | The directory or directories to search for page and layout templates. Searched in the provided order. |
|
|
106
|
+
| `partials` | `string \| string[]` | `[]` | The directory or directories for partial templates. All partials are loaded on startup and available by name. |
|
|
107
|
+
| `partialsRecursive` | `boolean` | `true` | If `true`, partials are loaded recursively from subdirectories. Names use forward slashes (for example, `emails/header`). |
|
|
108
|
+
| `partialsNamespace` | `boolean \| string` | `false` | Optional namespace prefix for partial names. Use `true` to prefix with each partials directory basename, or provide a custom string. |
|
|
109
|
+
| `layout` | `string` | `undefined` | The name of the default layout file to use (without extension). Can be overridden per-route. |
|
|
110
|
+
| `defaultExtension` | `string` | `"sqrl"` | The file extension for all template files. Leading `.` is optional (for example, `"html"` or `".html"`). |
|
|
111
|
+
| `cache` | `boolean` | `NODE_ENV === "production"` | If `true`, compiled templates and resolved file paths will be cached in memory. |
|
|
112
|
+
| `sqrl` | `object` | `undefined` | Squirrelly options. Supports `{ scope: "global" \| "scoped", config, helpers, filters }`. |
|
|
113
113
|
|
|
114
114
|
Runtime API after registration:
|
|
115
115
|
|
|
116
116
|
- `fastify.viewHelpers.define(name, fn)`, `fastify.viewHelpers.get(name)`, `fastify.viewHelpers.remove(name)`
|
|
117
117
|
- `fastify.viewFilters.define(name, fn)`, `fastify.viewFilters.get(name)`, `fastify.viewFilters.remove(name)`
|
|
118
|
-
- `fastify.viewPartials.define(name, templateOrFn)`, `fastify.viewPartials.get(name)`,
|
|
118
|
+
- `fastify.viewPartials.define(name, templateOrFn)`, `fastify.viewPartials.get(name)`,
|
|
119
|
+
`fastify.viewPartials.remove(name)`
|
|
119
120
|
- `fastify.viewCache.clear()`, `fastify.viewCache.stats()`
|
|
120
121
|
|
|
121
122
|
These APIs are scope-aware:
|
|
@@ -123,8 +124,8 @@ These APIs are scope-aware:
|
|
|
123
124
|
- In `global` mode they modify shared helpers/filters/partials.
|
|
124
125
|
- In `scoped` mode they only affect the current plugin registration scope.
|
|
125
126
|
|
|
126
|
-
The cache API is process-local and lets you invalidate compiled template/path caches at runtime when
|
|
127
|
-
|
|
127
|
+
The cache API is process-local and lets you invalidate compiled template/path caches at runtime when `cache: true` is
|
|
128
|
+
used.
|
|
128
129
|
|
|
129
130
|
Invalid option types are rejected at plugin registration time with descriptive errors.
|
|
130
131
|
|
|
@@ -132,8 +133,8 @@ Invalid option types are rejected at plugin registration time with descriptive e
|
|
|
132
133
|
|
|
133
134
|
### Layouts
|
|
134
135
|
|
|
135
|
-
Layouts are wrappers for your page templates. The rendered page content is injected into the `body`
|
|
136
|
-
|
|
136
|
+
Layouts are wrappers for your page templates. The rendered page content is injected into the `body` variable within the
|
|
137
|
+
layout.
|
|
137
138
|
|
|
138
139
|
**`views/layouts/main.sqrl`**
|
|
139
140
|
|
|
@@ -146,8 +147,8 @@ variable within the layout.
|
|
|
146
147
|
<body>
|
|
147
148
|
<header>My Awesome Site</header>
|
|
148
149
|
<main>
|
|
149
|
-
{{@block("content")}} {{@try}} {{it.body | safe}} {{#catch => err}} Uh-oh, error!
|
|
150
|
-
|
|
150
|
+
{{@block("content")}} {{@try}} {{it.body | safe}} {{#catch => err}} Uh-oh, error! Message was
|
|
151
|
+
'{{err.message}}' {{/try}} {{/block}}
|
|
151
152
|
</main>
|
|
152
153
|
</body>
|
|
153
154
|
</html>
|
|
@@ -191,9 +192,8 @@ You can specify a layout in three ways (in order of precedence):
|
|
|
191
192
|
|
|
192
193
|
### Partials
|
|
193
194
|
|
|
194
|
-
Partials are reusable chunks of template code. Create a `partials` directory and place your files
|
|
195
|
-
|
|
196
|
-
partials directory root.
|
|
195
|
+
Partials are reusable chunks of template code. Create a `partials` directory and place your files there. By default,
|
|
196
|
+
partials are loaded recursively and registered by forward-slash path from the partials directory root.
|
|
197
197
|
|
|
198
198
|
**`partials/user-card.sqrl`**
|
|
199
199
|
|
|
@@ -258,8 +258,8 @@ fastify.register(squirrellyify, {
|
|
|
258
258
|
|
|
259
259
|
### Scoped Configuration (Encapsulation)
|
|
260
260
|
|
|
261
|
-
This plugin supports Fastify's encapsulation model. You can register it multiple times with
|
|
262
|
-
different
|
|
261
|
+
This plugin supports Fastify's encapsulation model. You can register it multiple times with different settings for
|
|
262
|
+
different route prefixes.
|
|
263
263
|
|
|
264
264
|
```javascript
|
|
265
265
|
import Fastify from "fastify";
|
|
@@ -308,8 +308,7 @@ Use `sqrl.scope` to choose registration mode:
|
|
|
308
308
|
- `global` (default): helpers, filters, and partials are shared across plugin registrations.
|
|
309
309
|
- `scoped`: helpers, filters, and partials are isolated to each plugin registration.
|
|
310
310
|
|
|
311
|
-
You can also add/remove helpers and filters at runtime via `fastify.viewHelpers` and
|
|
312
|
-
`fastify.viewFilters`.
|
|
311
|
+
You can also add/remove helpers and filters at runtime via `fastify.viewHelpers` and `fastify.viewFilters`.
|
|
313
312
|
|
|
314
313
|
```javascript
|
|
315
314
|
fastify.register(squirrellyify, {
|
|
@@ -332,3 +331,4 @@ fastify.register(squirrellyify, {
|
|
|
332
331
|
## License
|
|
333
332
|
|
|
334
333
|
This project is licensed under the [MIT License](./LICENSE).
|
|
334
|
+
|
package/index.d.ts
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
import { FastifyPluginAsync } from "fastify";
|
|
2
|
+
|
|
3
|
+
export interface SquirrellyifyOptions {
|
|
4
|
+
/**
|
|
5
|
+
* Enable caching of templates.
|
|
6
|
+
* @default process.env.NODE_ENV === 'production'
|
|
7
|
+
*/
|
|
8
|
+
cache?: boolean;
|
|
9
|
+
/**
|
|
10
|
+
* Path to the views directory.
|
|
11
|
+
* @default './views'
|
|
12
|
+
*/
|
|
13
|
+
views?: string;
|
|
14
|
+
/**
|
|
15
|
+
* Squirrelly specific configuration options overriden.
|
|
16
|
+
*/
|
|
17
|
+
options?: Record<string, any>;
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
export const squirrellyify: FastifyPluginAsync<SquirrellyifyOptions>;
|
|
21
|
+
export default squirrellyify;
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@ynode/squirrellyify",
|
|
3
|
-
"version": "1.
|
|
3
|
+
"version": "1.5.1",
|
|
4
4
|
"description": "Fastify plugin for rendering Squirrelly templates.",
|
|
5
5
|
"main": "src/plugin.js",
|
|
6
6
|
"type": "module",
|
|
@@ -21,16 +21,18 @@
|
|
|
21
21
|
"squirrelly"
|
|
22
22
|
],
|
|
23
23
|
"engines": {
|
|
24
|
-
"node": ">=
|
|
24
|
+
"node": ">=20"
|
|
25
25
|
},
|
|
26
26
|
"devDependencies": {
|
|
27
27
|
"@eslint/js": "^9.37.0",
|
|
28
28
|
"@eslint/json": "^0.13.2",
|
|
29
29
|
"@eslint/markdown": "^7.4.0",
|
|
30
30
|
"@mikinho/autover": "^2.0.1",
|
|
31
|
+
"auto-changelog": "^2.5.0",
|
|
31
32
|
"eslint": "^9.37.0",
|
|
32
33
|
"eslint-config-prettier": "^10.1.8",
|
|
33
34
|
"eslint-plugin-prettier": "^5.5.4",
|
|
35
|
+
"eslint-plugin-simple-import-sort": "^12.1.1",
|
|
34
36
|
"fastify": "^5.8.1",
|
|
35
37
|
"globals": "^16.4.0",
|
|
36
38
|
"jsdoc": "^4.0.5",
|
|
@@ -38,6 +40,7 @@
|
|
|
38
40
|
"rimraf": "^6.0.1"
|
|
39
41
|
},
|
|
40
42
|
"scripts": {
|
|
43
|
+
"changelog": "auto-changelog -p",
|
|
41
44
|
"docs": "node scripts/gen-docs.mjs",
|
|
42
45
|
"docs:clean": "rimraf docs || rmdir /s /q docs 2> NUL || true",
|
|
43
46
|
"docs:open": "node -e \"import('node:child_process').then(m=>m.exec(process.platform==='win32'?'start docs/index.html':(process.platform==='darwin'?'open docs/index.html':'xdg-open docs/index.html')))\"",
|
|
@@ -49,14 +52,15 @@
|
|
|
49
52
|
"test:staged": "node scripts/lint-staged.mjs",
|
|
50
53
|
"ver:preview": "npx autover --no-amend --dry-run --short",
|
|
51
54
|
"ver:apply": "npx autover --guard-unchanged --short",
|
|
52
|
-
"test": "
|
|
53
|
-
"prepublishOnly": "npm test",
|
|
55
|
+
"test": "node --test",
|
|
56
|
+
"prepublishOnly": "npm run lint && npm test",
|
|
54
57
|
"postversion": "git push && git push --tags"
|
|
55
58
|
},
|
|
56
59
|
"publishConfig": {
|
|
57
60
|
"access": "public"
|
|
58
61
|
},
|
|
59
62
|
"files": [
|
|
63
|
+
"index.d.ts",
|
|
60
64
|
"src",
|
|
61
65
|
"README.md",
|
|
62
66
|
"LICENSE"
|
|
@@ -65,7 +69,7 @@
|
|
|
65
69
|
"fastify-plugin": "^5.1.0"
|
|
66
70
|
},
|
|
67
71
|
"peerDependencies": {
|
|
68
|
-
"fastify": "
|
|
72
|
+
"fastify": "5.x",
|
|
69
73
|
"squirrelly": "^9.1.0"
|
|
70
74
|
}
|
|
71
75
|
}
|
package/src/config.js
CHANGED
|
@@ -19,18 +19,13 @@ function assertOptionType(condition, message) {
|
|
|
19
19
|
function normalizeDefaultExtension(defaultExtension) {
|
|
20
20
|
const normalized = defaultExtension.replace(/^\.+/, "");
|
|
21
21
|
if (normalized.length === 0) {
|
|
22
|
-
throw new TypeError(
|
|
23
|
-
'Invalid option "defaultExtension": must contain at least one non-dot character.',
|
|
24
|
-
);
|
|
22
|
+
throw new TypeError('Invalid option "defaultExtension": must contain at least one non-dot character.');
|
|
25
23
|
}
|
|
26
24
|
return normalized;
|
|
27
25
|
}
|
|
28
26
|
|
|
29
27
|
export function validatePluginOptions(options = {}) {
|
|
30
|
-
assertOptionType(
|
|
31
|
-
isPlainObject(options),
|
|
32
|
-
"Invalid options: plugin options must be a plain object.",
|
|
33
|
-
);
|
|
28
|
+
assertOptionType(isPlainObject(options), "Invalid options: plugin options must be a plain object.");
|
|
34
29
|
|
|
35
30
|
if (options.templates !== undefined) {
|
|
36
31
|
assertOptionType(
|
|
@@ -52,8 +47,7 @@ export function validatePluginOptions(options = {}) {
|
|
|
52
47
|
}
|
|
53
48
|
if (options.partialsNamespace !== undefined) {
|
|
54
49
|
assertOptionType(
|
|
55
|
-
typeof options.partialsNamespace === "boolean" ||
|
|
56
|
-
typeof options.partialsNamespace === "string",
|
|
50
|
+
typeof options.partialsNamespace === "boolean" || typeof options.partialsNamespace === "string",
|
|
57
51
|
'Invalid option "partialsNamespace": expected a boolean or a string.',
|
|
58
52
|
);
|
|
59
53
|
}
|
|
@@ -80,10 +74,7 @@ export function validatePluginOptions(options = {}) {
|
|
|
80
74
|
);
|
|
81
75
|
}
|
|
82
76
|
if (options.sqrl.config !== undefined) {
|
|
83
|
-
assertOptionType(
|
|
84
|
-
isPlainObject(options.sqrl.config),
|
|
85
|
-
'Invalid option "sqrl.config": expected an object.',
|
|
86
|
-
);
|
|
77
|
+
assertOptionType(isPlainObject(options.sqrl.config), 'Invalid option "sqrl.config": expected an object.');
|
|
87
78
|
}
|
|
88
79
|
if (options.sqrl.helpers !== undefined) {
|
|
89
80
|
assertOptionType(
|
|
@@ -130,9 +121,7 @@ export function resolveInitialPartialsDirs(options = {}) {
|
|
|
130
121
|
|
|
131
122
|
export function resolveExtension(options = {}) {
|
|
132
123
|
const defaultExtension =
|
|
133
|
-
options.defaultExtension !== undefined
|
|
134
|
-
? normalizeDefaultExtension(options.defaultExtension)
|
|
135
|
-
: "sqrl";
|
|
124
|
+
options.defaultExtension !== undefined ? normalizeDefaultExtension(options.defaultExtension) : "sqrl";
|
|
136
125
|
return {
|
|
137
126
|
defaultExtension,
|
|
138
127
|
extensionWithDot: `.${defaultExtension}`,
|
|
@@ -153,15 +142,7 @@ function createScopedSqrlConfig(baseConfig) {
|
|
|
153
142
|
const scopedFilters = new Cacher({});
|
|
154
143
|
const scopedTemplates = new Cacher({});
|
|
155
144
|
|
|
156
|
-
for (const helperName of [
|
|
157
|
-
"each",
|
|
158
|
-
"foreach",
|
|
159
|
-
"include",
|
|
160
|
-
"extends",
|
|
161
|
-
"useScope",
|
|
162
|
-
"includeFile",
|
|
163
|
-
"extendsFile",
|
|
164
|
-
]) {
|
|
145
|
+
for (const helperName of ["each", "foreach", "include", "extends", "useScope", "includeFile", "extendsFile"]) {
|
|
165
146
|
const helperFn = Sqrl.helpers.get(helperName);
|
|
166
147
|
if (helperFn) {
|
|
167
148
|
scopedHelpers.define(helperName, helperFn);
|
package/src/plugin.js
CHANGED
|
@@ -31,19 +31,14 @@ import fp from "fastify-plugin";
|
|
|
31
31
|
import Sqrl from "squirrelly";
|
|
32
32
|
|
|
33
33
|
import {
|
|
34
|
-
validatePluginOptions,
|
|
35
34
|
resolveExtension,
|
|
36
35
|
resolveInitialPartialsDirs,
|
|
37
36
|
resolveInitialTemplateDirs,
|
|
38
37
|
resolveSqrlConfig,
|
|
39
38
|
resolveUseCache,
|
|
39
|
+
validatePluginOptions,
|
|
40
40
|
} from "./config.js";
|
|
41
|
-
import {
|
|
42
|
-
buildTemplateSearchDirs,
|
|
43
|
-
collectViewScope,
|
|
44
|
-
createTemplateResolver,
|
|
45
|
-
preloadPartials,
|
|
46
|
-
} from "./resolver.js";
|
|
41
|
+
import { buildTemplateSearchDirs, collectViewScope, createTemplateResolver, preloadPartials } from "./resolver.js";
|
|
47
42
|
import { createRuntimeApi } from "./runtime-api.js";
|
|
48
43
|
import { assertSafeName } from "./safety.js";
|
|
49
44
|
|
|
@@ -75,20 +70,20 @@ import { assertSafeName } from "./safety.js";
|
|
|
75
70
|
async function squirrellyify(fastify, options = {}) {
|
|
76
71
|
validatePluginOptions(options);
|
|
77
72
|
|
|
73
|
+
if (typeof fastify.hasDecorator === "function" && fastify.hasDecorator("Sqrl")) {
|
|
74
|
+
throw new Error("@ynode/squirrellyify has already been registered");
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
const log =
|
|
78
|
+
typeof fastify.log?.child === "function" ? fastify.log.child({ name: "@ynode/squirrellyify" }) : fastify.log;
|
|
79
|
+
|
|
78
80
|
const initialTemplatesDirs = resolveInitialTemplateDirs(options);
|
|
79
81
|
const initialPartialsDirs = resolveInitialPartialsDirs(options);
|
|
80
82
|
const initialLayout = options.layout;
|
|
81
83
|
const { extensionWithDot } = resolveExtension(options);
|
|
82
84
|
const useCache = resolveUseCache(options);
|
|
83
85
|
const { sqrlScope, sqrlConfig } = resolveSqrlConfig(options);
|
|
84
|
-
const {
|
|
85
|
-
defineSqrlHelper,
|
|
86
|
-
defineSqrlFilter,
|
|
87
|
-
defineSqrlTemplate,
|
|
88
|
-
viewHelpers,
|
|
89
|
-
viewFilters,
|
|
90
|
-
viewPartials,
|
|
91
|
-
} =
|
|
86
|
+
const { defineSqrlHelper, defineSqrlFilter, defineSqrlTemplate, viewHelpers, viewFilters, viewPartials } =
|
|
92
87
|
createRuntimeApi({
|
|
93
88
|
sqrlScope,
|
|
94
89
|
sqrlConfig,
|
|
@@ -131,10 +126,8 @@ async function squirrellyify(fastify, options = {}) {
|
|
|
131
126
|
async function view(template, data = {}) {
|
|
132
127
|
try {
|
|
133
128
|
const requestData = data && typeof data === "object" ? data : {};
|
|
134
|
-
const replyContext =
|
|
135
|
-
|
|
136
|
-
const replyLocals =
|
|
137
|
-
this.locals && typeof this.locals === "object" ? this.locals : {};
|
|
129
|
+
const replyContext = this.context && typeof this.context === "object" ? this.context : {};
|
|
130
|
+
const replyLocals = this.locals && typeof this.locals === "object" ? this.locals : {};
|
|
138
131
|
const mergedData = {
|
|
139
132
|
...replyContext,
|
|
140
133
|
...replyLocals,
|
|
@@ -148,17 +141,12 @@ async function squirrellyify(fastify, options = {}) {
|
|
|
148
141
|
|
|
149
142
|
const instance = this.request.server;
|
|
150
143
|
const { aggregatedTemplatesDirs, scopedLayout } = collectViewScope(instance);
|
|
151
|
-
const templateSearchDirs = buildTemplateSearchDirs(
|
|
152
|
-
aggregatedTemplatesDirs,
|
|
153
|
-
initialTemplatesDirs,
|
|
154
|
-
);
|
|
144
|
+
const templateSearchDirs = buildTemplateSearchDirs(aggregatedTemplatesDirs, initialTemplatesDirs);
|
|
155
145
|
|
|
156
146
|
// 1. Find and render the page template
|
|
157
147
|
const pagePath = await findTemplatePath(template, templateSearchDirs);
|
|
158
148
|
if (!pagePath) {
|
|
159
|
-
throw new Error(
|
|
160
|
-
`Template "${template}" not found in [${templateSearchDirs.join(", ")}]`,
|
|
161
|
-
);
|
|
149
|
+
throw new Error(`Template "${template}" not found in [${templateSearchDirs.join(", ")}]`);
|
|
162
150
|
}
|
|
163
151
|
|
|
164
152
|
const pageTemplate = await getTemplate(pagePath);
|
|
@@ -179,22 +167,18 @@ async function squirrellyify(fastify, options = {}) {
|
|
|
179
167
|
// 3. Find and render the layout, injecting the page content
|
|
180
168
|
const layoutPath = await findTemplatePath(layoutFile, templateSearchDirs);
|
|
181
169
|
if (!layoutPath) {
|
|
182
|
-
throw new Error(
|
|
183
|
-
`Layout "${layoutFile}" not found in [${templateSearchDirs.join(", ")}]`,
|
|
184
|
-
);
|
|
170
|
+
throw new Error(`Layout "${layoutFile}" not found in [${templateSearchDirs.join(", ")}]`);
|
|
185
171
|
}
|
|
186
172
|
|
|
187
173
|
const layoutTemplate = await getTemplate(layoutPath);
|
|
188
174
|
const layoutPayload =
|
|
189
|
-
mergedData.layoutData && typeof mergedData.layoutData === "object"
|
|
190
|
-
? mergedData.layoutData
|
|
191
|
-
: {};
|
|
175
|
+
mergedData.layoutData && typeof mergedData.layoutData === "object" ? mergedData.layoutData : {};
|
|
192
176
|
const layoutData = { ...mergedData, ...layoutPayload, body: pageHtml };
|
|
193
177
|
const finalHtml = await layoutTemplate(layoutData, sqrlConfig);
|
|
194
178
|
|
|
195
179
|
return this.type("text/html").send(finalHtml);
|
|
196
180
|
} catch (error) {
|
|
197
|
-
|
|
181
|
+
log.error(error);
|
|
198
182
|
if (process.env.NODE_ENV === "production") {
|
|
199
183
|
// In production, send a generic error and don't leak details
|
|
200
184
|
this.status(500).send("An internal server error occurred.");
|
package/src/resolver.js
CHANGED
|
@@ -79,12 +79,7 @@ export async function preloadPartials({
|
|
|
79
79
|
const files = await collectPartialFiles(partialsDir, extensionWithDot, partialsRecursive);
|
|
80
80
|
await Promise.all(
|
|
81
81
|
files.map(async (partialPath) => {
|
|
82
|
-
const partialName = resolvePartialName(
|
|
83
|
-
partialPath,
|
|
84
|
-
partialsDir,
|
|
85
|
-
extensionWithDot,
|
|
86
|
-
namespace,
|
|
87
|
-
);
|
|
82
|
+
const partialName = resolvePartialName(partialPath, partialsDir, extensionWithDot, namespace);
|
|
88
83
|
const content = await fs.readFile(partialPath, "utf-8");
|
|
89
84
|
fastify.log.trace(`Loaded partial: ${partialName}`);
|
|
90
85
|
defineSqrlTemplate(partialName, Sqrl.compile(content, sqrlConfig));
|
|
@@ -110,9 +105,7 @@ export function collectViewScope(instance) {
|
|
|
110
105
|
|
|
111
106
|
while (currentInstance) {
|
|
112
107
|
if (currentInstance.views) {
|
|
113
|
-
const dirs = Array.isArray(currentInstance.views)
|
|
114
|
-
? currentInstance.views
|
|
115
|
-
: [currentInstance.views];
|
|
108
|
+
const dirs = Array.isArray(currentInstance.views) ? currentInstance.views : [currentInstance.views];
|
|
116
109
|
aggregatedTemplatesDirs.push(...dirs);
|
|
117
110
|
}
|
|
118
111
|
if (scopedLayout === null && currentInstance.layout !== null && currentInstance.layout !== undefined) {
|