express-hbs 2.4.2 → 3.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/.github/workflows/publish.yml +73 -0
- package/.github/workflows/test.yml +32 -8
- package/.nvmrc +1 -0
- package/.nycrc.json +16 -0
- package/.oxfmtrc.json +19 -0
- package/.oxlintrc.json +32 -0
- package/AGENTS.md +40 -0
- package/LICENSE +1 -1
- package/README.md +51 -22
- package/example/app-layoutsDir.js +32 -38
- package/example/app.js +27 -33
- package/lib/hbs.js +90 -89
- package/lib/resolver.js +10 -9
- package/package.json +29 -22
- package/renovate.json +9 -2
- package/test/apps/async/index.js +54 -41
- package/test/apps/i18n/index.js +9 -6
- package/test/asyncSpecs.js +12 -12
- package/test/cacheSpecs.js +18 -21
- package/test/customExtension.js +15 -15
- package/test/handlebarsSpecs.js +16 -19
- package/test/helperSpecs.js +24 -20
- package/test/helpers.js +3 -3
- package/test/i18nSpecs.js +10 -8
- package/test/issues.js +164 -122
- package/test/layoutSpecs.js +35 -19
- package/test/localTemplateOptions.js +48 -42
- package/test/multiple.js +30 -32
- package/test/nonExpress.js +11 -10
- package/test/optionsSpecs.js +5 -7
- package/test/resolverSpecs.js +54 -0
- package/.eslintrc +0 -42
package/lib/hbs.js
CHANGED
|
@@ -10,12 +10,12 @@ var _ = require('lodash');
|
|
|
10
10
|
/**
|
|
11
11
|
* Regex pattern for layout directive. {{!< layout }}
|
|
12
12
|
*/
|
|
13
|
-
var layoutPattern = /{{!<\s+([A-Za-z0-9
|
|
13
|
+
var layoutPattern = /{{!<\s+([A-Za-z0-9._\-/]+)\s*}}/;
|
|
14
14
|
|
|
15
15
|
/**
|
|
16
16
|
* Constructor
|
|
17
17
|
*/
|
|
18
|
-
var ExpressHbs = function() {
|
|
18
|
+
var ExpressHbs = function () {
|
|
19
19
|
this.handlebars = handlebars.create();
|
|
20
20
|
this.SafeString = this.handlebars.SafeString;
|
|
21
21
|
this.Utils = this.handlebars.Utils;
|
|
@@ -33,7 +33,7 @@ var ExpressHbs = function() {
|
|
|
33
33
|
* <link rel="stylesheet" href='{{{URL "css/style.css"}}}' />
|
|
34
34
|
* {{/contentFor}}
|
|
35
35
|
*/
|
|
36
|
-
ExpressHbs.prototype.content = function(name, options, context) {
|
|
36
|
+
ExpressHbs.prototype.content = function (name, options, context) {
|
|
37
37
|
var block = options.data.root.blockCache[name] || (options.data.root.blockCache[name] = []);
|
|
38
38
|
block.push(options.fn(context));
|
|
39
39
|
};
|
|
@@ -46,9 +46,8 @@ ExpressHbs.prototype.content = function(name, options, context) {
|
|
|
46
46
|
* @param {String} filename Path to template file.
|
|
47
47
|
* @param {String} layout Layout path.
|
|
48
48
|
*/
|
|
49
|
-
ExpressHbs.prototype.layoutPath = function(filename, layout) {
|
|
50
|
-
var dirs,
|
|
51
|
-
layoutPath;
|
|
49
|
+
ExpressHbs.prototype.layoutPath = function (filename, layout) {
|
|
50
|
+
var dirs, layoutPath;
|
|
52
51
|
if (layout[0] === '.') {
|
|
53
52
|
dirs = path.dirname(filename);
|
|
54
53
|
} else if (this.layoutsDir) {
|
|
@@ -71,7 +70,7 @@ ExpressHbs.prototype.layoutPath = function(filename, layout) {
|
|
|
71
70
|
* @param {String} filename Path to template
|
|
72
71
|
* @returns {String|undefined} Returns the path to layout.
|
|
73
72
|
*/
|
|
74
|
-
ExpressHbs.prototype.declaredLayoutFile = function(str, filename) {
|
|
73
|
+
ExpressHbs.prototype.declaredLayoutFile = function (str, filename) {
|
|
75
74
|
var matches = str.match(layoutPattern);
|
|
76
75
|
if (matches) {
|
|
77
76
|
var layout = matches[1];
|
|
@@ -96,9 +95,18 @@ ExpressHbs.prototype.declaredLayoutFile = function(str, filename) {
|
|
|
96
95
|
* @param {Boolean} useCache Cache the compiled layout?
|
|
97
96
|
* @param {Function} cb Callback called with layouts stack
|
|
98
97
|
*/
|
|
99
|
-
ExpressHbs.prototype.cacheLayout = function(layoutFile, useCache, cb) {
|
|
98
|
+
ExpressHbs.prototype.cacheLayout = function (layoutFile, useCache, cb) {
|
|
100
99
|
var self = this;
|
|
101
100
|
|
|
101
|
+
if (this.restrictLayoutsTo) {
|
|
102
|
+
if (!layoutFile.startsWith(this.restrictLayoutsTo)) {
|
|
103
|
+
var err = new Error(
|
|
104
|
+
'Cannot read ' + layoutFile + ' it does not reside in ' + this.restrictLayoutsTo,
|
|
105
|
+
);
|
|
106
|
+
return cb(err, null);
|
|
107
|
+
}
|
|
108
|
+
}
|
|
109
|
+
|
|
102
110
|
// assume hbs extension
|
|
103
111
|
if (path.extname(layoutFile) === '') layoutFile += this._options.extname;
|
|
104
112
|
|
|
@@ -106,14 +114,14 @@ ExpressHbs.prototype.cacheLayout = function(layoutFile, useCache, cb) {
|
|
|
106
114
|
var layoutTemplates = this.cache[layoutFile];
|
|
107
115
|
if (layoutTemplates) return cb(null, layoutTemplates);
|
|
108
116
|
|
|
109
|
-
fs.readFile(layoutFile, 'utf8', function(err, str) {
|
|
117
|
+
fs.readFile(layoutFile, 'utf8', function (err, str) {
|
|
110
118
|
if (err) return cb(err);
|
|
111
119
|
|
|
112
120
|
// File path of eventual declared parent layout
|
|
113
121
|
var parentLayoutFile = self.declaredLayoutFile(str, layoutFile);
|
|
114
122
|
|
|
115
123
|
// This function returns the current layout stack to the caller
|
|
116
|
-
var _returnLayouts = function(layouts) {
|
|
124
|
+
var _returnLayouts = function (layouts) {
|
|
117
125
|
var currentLayout;
|
|
118
126
|
layouts = layouts.slice(0);
|
|
119
127
|
currentLayout = self.compile(str, layoutFile);
|
|
@@ -126,7 +134,7 @@ ExpressHbs.prototype.cacheLayout = function(layoutFile, useCache, cb) {
|
|
|
126
134
|
|
|
127
135
|
if (parentLayoutFile) {
|
|
128
136
|
// Recursively compile/cache parent layouts
|
|
129
|
-
self.cacheLayout(parentLayoutFile, useCache, function(err, parentLayouts) {
|
|
137
|
+
self.cacheLayout(parentLayoutFile, useCache, function (err, parentLayouts) {
|
|
130
138
|
if (err) return cb(err);
|
|
131
139
|
_returnLayouts(parentLayouts);
|
|
132
140
|
});
|
|
@@ -140,7 +148,7 @@ ExpressHbs.prototype.cacheLayout = function(layoutFile, useCache, cb) {
|
|
|
140
148
|
/**
|
|
141
149
|
* Cache partial templates found under directories configure in partialsDir.
|
|
142
150
|
*/
|
|
143
|
-
ExpressHbs.prototype.cachePartials = function(cb) {
|
|
151
|
+
ExpressHbs.prototype.cachePartials = function (cb) {
|
|
144
152
|
var self = this;
|
|
145
153
|
|
|
146
154
|
if (!(this.partialsDir instanceof Array)) {
|
|
@@ -151,36 +159,36 @@ ExpressHbs.prototype.cachePartials = function(cb) {
|
|
|
151
159
|
var count = 0;
|
|
152
160
|
|
|
153
161
|
function readNext() {
|
|
154
|
-
readdirp(self.partialsDir[count], {fileFilter: '*' + self._options.extname})
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
162
|
+
readdirp(self.partialsDir[count], { fileFilter: '*' + self._options.extname })
|
|
163
|
+
.on('warn', function (err) {
|
|
164
|
+
console.warn('Non-fatal error in express-hbs cachePartials.', err);
|
|
165
|
+
})
|
|
166
|
+
.on('error', function (err) {
|
|
167
|
+
console.error('Fatal error in express-hbs cachePartials', err);
|
|
168
|
+
return cb(err);
|
|
169
|
+
})
|
|
170
|
+
.on('data', function (entry) {
|
|
171
|
+
if (!entry) return;
|
|
172
|
+
var source = fs.readFileSync(entry.fullPath, 'utf8');
|
|
173
|
+
var dirname = path.dirname(entry.path);
|
|
174
|
+
dirname = dirname === '.' ? '' : dirname + '/';
|
|
175
|
+
|
|
176
|
+
var name = dirname + path.basename(entry.basename, self._options.extname);
|
|
177
|
+
// fix the path in windows
|
|
178
|
+
name = name.split('\\').join('/');
|
|
179
|
+
self.registerPartial(name, source, entry.fullPath);
|
|
180
|
+
})
|
|
181
|
+
.on('end', function () {
|
|
182
|
+
count += 1;
|
|
183
|
+
|
|
184
|
+
// If all directories aren't read, read the next directory
|
|
185
|
+
if (count < self.partialsDir.length) {
|
|
186
|
+
readNext();
|
|
187
|
+
} else {
|
|
188
|
+
self.isPartialCachingComplete = true;
|
|
189
|
+
if (cb) cb(null, true);
|
|
190
|
+
}
|
|
191
|
+
});
|
|
184
192
|
}
|
|
185
193
|
|
|
186
194
|
readNext();
|
|
@@ -203,7 +211,7 @@ ExpressHbs.prototype.cachePartials = function(cb) {
|
|
|
203
211
|
* }
|
|
204
212
|
* }
|
|
205
213
|
*/
|
|
206
|
-
ExpressHbs.prototype.express3 = function(options) {
|
|
214
|
+
ExpressHbs.prototype.express3 = function (options) {
|
|
207
215
|
var self = this;
|
|
208
216
|
|
|
209
217
|
// Set defaults
|
|
@@ -220,31 +228,31 @@ ExpressHbs.prototype.express3 = function(options) {
|
|
|
220
228
|
|
|
221
229
|
if (options.i18n) {
|
|
222
230
|
var i18n = options.i18n;
|
|
223
|
-
this.handlebars.registerHelper('__', function() {
|
|
231
|
+
this.handlebars.registerHelper('__', function () {
|
|
224
232
|
var args = Array.prototype.slice.call(arguments);
|
|
225
233
|
var options = args.pop();
|
|
226
234
|
return i18n.__.apply(options.data.root, args);
|
|
227
235
|
});
|
|
228
|
-
this.handlebars.registerHelper('__n', function() {
|
|
236
|
+
this.handlebars.registerHelper('__n', function () {
|
|
229
237
|
var args = Array.prototype.slice.call(arguments);
|
|
230
238
|
var options = args.pop();
|
|
231
239
|
return i18n.__n.apply(options.data.root, args);
|
|
232
240
|
});
|
|
233
241
|
}
|
|
234
242
|
|
|
235
|
-
this.handlebars.registerHelper(this._options.blockHelperName, function(name, options) {
|
|
243
|
+
this.handlebars.registerHelper(this._options.blockHelperName, function (name, options) {
|
|
236
244
|
var val = options.data.root.blockCache[name];
|
|
237
245
|
if (val === undefined && typeof options.fn === 'function') {
|
|
238
246
|
val = options.fn(this);
|
|
239
247
|
}
|
|
240
248
|
if (Array.isArray(val)) {
|
|
241
|
-
val = val.join('\n');
|
|
249
|
+
val = val.join('\n');
|
|
242
250
|
}
|
|
243
251
|
return val;
|
|
244
252
|
});
|
|
245
253
|
|
|
246
254
|
// Pass 'this' as context of helper function to don't lose context call of helpers.
|
|
247
|
-
this.handlebars.registerHelper(this._options.contentHelperName, function(name, options) {
|
|
255
|
+
this.handlebars.registerHelper(this._options.contentHelperName, function (name, options) {
|
|
248
256
|
return self.content(name, options, this);
|
|
249
257
|
});
|
|
250
258
|
|
|
@@ -254,6 +262,8 @@ ExpressHbs.prototype.express3 = function(options) {
|
|
|
254
262
|
// Absolute path to the layouts directory
|
|
255
263
|
this.layoutsDir = this._options.layoutsDir;
|
|
256
264
|
|
|
265
|
+
this.restrictLayoutsTo = this._options.restrictLayoutsTo;
|
|
266
|
+
|
|
257
267
|
// express passes this through ___express func, gulp pass in an option
|
|
258
268
|
this.viewsDir = null;
|
|
259
269
|
this.viewsDirOpt = this._options.viewsDir;
|
|
@@ -291,12 +301,12 @@ ExpressHbs.prototype.express4 = ExpressHbs.prototype.express3;
|
|
|
291
301
|
*
|
|
292
302
|
* @param {Boolean} useCache Whether to cache.
|
|
293
303
|
*/
|
|
294
|
-
ExpressHbs.prototype.loadDefaultLayout = function(useCache, cb) {
|
|
304
|
+
ExpressHbs.prototype.loadDefaultLayout = function (useCache, cb) {
|
|
295
305
|
var self = this;
|
|
296
306
|
if (!this._options.defaultLayout) return cb();
|
|
297
307
|
if (useCache && this.defaultLayoutTemplates) return cb(null, this.defaultLayoutTemplates);
|
|
298
308
|
|
|
299
|
-
this.cacheLayout(this._options.defaultLayout, useCache, function(err, templates) {
|
|
309
|
+
this.cacheLayout(this._options.defaultLayout, useCache, function (err, templates) {
|
|
300
310
|
if (err) return cb(err);
|
|
301
311
|
self.defaultLayoutTemplates = templates.slice(0);
|
|
302
312
|
return cb(null, templates);
|
|
@@ -306,7 +316,7 @@ ExpressHbs.prototype.loadDefaultLayout = function(useCache, cb) {
|
|
|
306
316
|
/**
|
|
307
317
|
* Expose useful methods.
|
|
308
318
|
*/
|
|
309
|
-
ExpressHbs.prototype.registerHelper = function(name, fn) {
|
|
319
|
+
ExpressHbs.prototype.registerHelper = function (name, fn) {
|
|
310
320
|
this.handlebars.registerHelper(name, fn);
|
|
311
321
|
};
|
|
312
322
|
|
|
@@ -316,7 +326,7 @@ ExpressHbs.prototype.registerHelper = function(name, fn) {
|
|
|
316
326
|
* @param {String} name The name of the partial as used in a template.
|
|
317
327
|
* @param {String} source String source of the partial.
|
|
318
328
|
*/
|
|
319
|
-
ExpressHbs.prototype.registerPartial = function(name, source, filename) {
|
|
329
|
+
ExpressHbs.prototype.registerPartial = function (name, source, filename) {
|
|
320
330
|
this.handlebars.registerPartial(name, this.compile(source, filename));
|
|
321
331
|
};
|
|
322
332
|
|
|
@@ -326,7 +336,7 @@ ExpressHbs.prototype.registerPartial = function(name, source, filename) {
|
|
|
326
336
|
* @param {String} source The source to compile.
|
|
327
337
|
* @param {String} filename The path used to embed into __filename for errors.
|
|
328
338
|
*/
|
|
329
|
-
ExpressHbs.prototype.compile = function(source, filename) {
|
|
339
|
+
ExpressHbs.prototype.compile = function (source, filename) {
|
|
330
340
|
// Handlebars has a bug with comment only partial causes errors. This must
|
|
331
341
|
// be a string so the block below can add a space.
|
|
332
342
|
if (typeof source !== 'string') {
|
|
@@ -359,53 +369,46 @@ ExpressHbs.prototype.compile = function(source, filename) {
|
|
|
359
369
|
* @param {String} name The name of the partial as used in a template.
|
|
360
370
|
* @param {String} fn The `function(options, cb)`
|
|
361
371
|
*/
|
|
362
|
-
ExpressHbs.prototype.registerAsyncHelper = function(name, fn) {
|
|
363
|
-
this.handlebars.registerHelper(name, function(context, options) {
|
|
364
|
-
var resolverCache =
|
|
372
|
+
ExpressHbs.prototype.registerAsyncHelper = function (name, fn) {
|
|
373
|
+
this.handlebars.registerHelper(name, function (context, options) {
|
|
374
|
+
var resolverCache =
|
|
375
|
+
this.resolverCache ||
|
|
365
376
|
_.get(context, 'data.root.resolverCache') ||
|
|
366
377
|
_.get(options, 'data.root.resolverCache');
|
|
367
378
|
if (!resolverCache) {
|
|
368
379
|
throw new Error('Could not find resolver cache in async helper ' + name + '.');
|
|
369
380
|
}
|
|
370
381
|
if (options && fn.length > 2) {
|
|
371
|
-
var resolveFunc = function(arr, cb) {
|
|
382
|
+
var resolveFunc = function (arr, cb) {
|
|
372
383
|
return fn.call(this, arr[0], arr[1], cb);
|
|
373
384
|
};
|
|
374
385
|
|
|
375
|
-
return resolver.resolve(
|
|
376
|
-
resolverCache,
|
|
377
|
-
resolveFunc.bind(this),
|
|
378
|
-
[context, options]
|
|
379
|
-
);
|
|
386
|
+
return resolver.resolve(resolverCache, resolveFunc.bind(this), [context, options]);
|
|
380
387
|
}
|
|
381
|
-
return resolver.resolve(
|
|
382
|
-
resolverCache,
|
|
383
|
-
fn.bind(this),
|
|
384
|
-
context
|
|
385
|
-
);
|
|
388
|
+
return resolver.resolve(resolverCache, fn.bind(this), context);
|
|
386
389
|
});
|
|
387
390
|
};
|
|
388
391
|
|
|
389
|
-
ExpressHbs.prototype.getTemplateOptions = function() {
|
|
392
|
+
ExpressHbs.prototype.getTemplateOptions = function () {
|
|
390
393
|
return this._options.templateOptions;
|
|
391
394
|
};
|
|
392
395
|
|
|
393
|
-
ExpressHbs.prototype.updateTemplateOptions = function(templateOptions) {
|
|
396
|
+
ExpressHbs.prototype.updateTemplateOptions = function (templateOptions) {
|
|
394
397
|
this._options.templateOptions = templateOptions;
|
|
395
398
|
};
|
|
396
399
|
|
|
397
|
-
ExpressHbs.prototype.getLocalTemplateOptions = function(locals) {
|
|
400
|
+
ExpressHbs.prototype.getLocalTemplateOptions = function (locals) {
|
|
398
401
|
return locals._templateOptions || {};
|
|
399
402
|
};
|
|
400
403
|
|
|
401
|
-
ExpressHbs.prototype.updateLocalTemplateOptions = function(locals, localTemplateOptions) {
|
|
402
|
-
return locals._templateOptions = localTemplateOptions;
|
|
404
|
+
ExpressHbs.prototype.updateLocalTemplateOptions = function (locals, localTemplateOptions) {
|
|
405
|
+
return (locals._templateOptions = localTemplateOptions);
|
|
403
406
|
};
|
|
404
407
|
|
|
405
408
|
/**
|
|
406
409
|
* Creates a new instance of ExpressHbs.
|
|
407
410
|
*/
|
|
408
|
-
ExpressHbs.prototype.create = function() {
|
|
411
|
+
ExpressHbs.prototype.create = function () {
|
|
409
412
|
return new ExpressHbs();
|
|
410
413
|
};
|
|
411
414
|
|
|
@@ -499,7 +502,6 @@ ExpressHbs.prototype.___express = function ___express(filename, source, options,
|
|
|
499
502
|
cb(null, res);
|
|
500
503
|
}
|
|
501
504
|
|
|
502
|
-
|
|
503
505
|
/**
|
|
504
506
|
* Renders `template` with an optional set of nested `layoutTemplates` using
|
|
505
507
|
* data in `locals`.
|
|
@@ -511,7 +513,7 @@ ExpressHbs.prototype.___express = function ___express(filename, source, options,
|
|
|
511
513
|
// being passed the rendered string of the previous ones as `body`
|
|
512
514
|
var i = layoutTemplates.length - 1;
|
|
513
515
|
|
|
514
|
-
var _stackRenderer = function(err, htmlStr) {
|
|
516
|
+
var _stackRenderer = function (err, htmlStr) {
|
|
515
517
|
if (err) return cb(err);
|
|
516
518
|
|
|
517
519
|
if (i >= 0) {
|
|
@@ -526,7 +528,6 @@ ExpressHbs.prototype.___express = function ___express(filename, source, options,
|
|
|
526
528
|
renderTemplate(template, locals, _stackRenderer);
|
|
527
529
|
}
|
|
528
530
|
|
|
529
|
-
|
|
530
531
|
/**
|
|
531
532
|
* Lazy loads js-beautify, which should not be used in production env.
|
|
532
533
|
*/
|
|
@@ -552,14 +553,14 @@ ExpressHbs.prototype.___express = function ___express(filename, source, options,
|
|
|
552
553
|
}
|
|
553
554
|
}
|
|
554
555
|
|
|
555
|
-
fs.readFile(filename, 'utf8', function(err, source) {
|
|
556
|
+
fs.readFile(filename, 'utf8', function (err, source) {
|
|
556
557
|
if (err) return cb(err);
|
|
557
558
|
|
|
558
559
|
var template = self.compile(source, filename);
|
|
559
560
|
if (options.cache) {
|
|
560
561
|
self.cache[filename] = {
|
|
561
562
|
source: source,
|
|
562
|
-
template: template
|
|
563
|
+
template: template,
|
|
563
564
|
};
|
|
564
565
|
}
|
|
565
566
|
return cb(null, source, template);
|
|
@@ -570,16 +571,16 @@ ExpressHbs.prototype.___express = function ___express(filename, source, options,
|
|
|
570
571
|
* Compiles a file into a template and a layoutTemplate, then renders it above.
|
|
571
572
|
*/
|
|
572
573
|
function compileFile(locals, cb) {
|
|
573
|
-
getSourceTemplate(function(err, source, template) {
|
|
574
|
+
getSourceTemplate(function (err, source, template) {
|
|
574
575
|
if (err) return cb(err);
|
|
575
576
|
|
|
576
577
|
// Try to get the layout
|
|
577
|
-
parseLayout(source, filename, function(err, layoutTemplates) {
|
|
578
|
+
parseLayout(source, filename, function (err, layoutTemplates) {
|
|
578
579
|
if (err) return cb(err);
|
|
579
580
|
|
|
580
581
|
function renderIt(layoutTemplates) {
|
|
581
582
|
if (self._options.beautify) {
|
|
582
|
-
return render(template, locals, layoutTemplates, function(err, html) {
|
|
583
|
+
return render(template, locals, layoutTemplates, function (err, html) {
|
|
583
584
|
if (err) return cb(err);
|
|
584
585
|
loadBeautify();
|
|
585
586
|
return cb(null, self.beautify(html, self.beautifyrc));
|
|
@@ -599,7 +600,7 @@ ExpressHbs.prototype.___express = function ___express(filename, source, options,
|
|
|
599
600
|
} else if (typeof options.layout !== 'undefined' && options.layout) {
|
|
600
601
|
// 2. Layout specified by options from render
|
|
601
602
|
var layoutFile = self.layoutPath(filename, options.layout);
|
|
602
|
-
self.cacheLayout(layoutFile, options.cache, function(err, layoutTemplates) {
|
|
603
|
+
self.cacheLayout(layoutFile, options.cache, function (err, layoutTemplates) {
|
|
603
604
|
if (err) return cb(err);
|
|
604
605
|
renderIt(layoutTemplates);
|
|
605
606
|
});
|
|
@@ -616,11 +617,11 @@ ExpressHbs.prototype.___express = function ___express(filename, source, options,
|
|
|
616
617
|
|
|
617
618
|
function replaceValue(values, text) {
|
|
618
619
|
if (typeof text === 'string') {
|
|
619
|
-
Object.keys(values).forEach(function(id) {
|
|
620
|
-
text = text.replace(id, function() {
|
|
620
|
+
Object.keys(values).forEach(function (id) {
|
|
621
|
+
text = text.replace(id, function () {
|
|
621
622
|
return values[id];
|
|
622
623
|
});
|
|
623
|
-
text = text.replace(self.Utils.escapeExpression(id), function() {
|
|
624
|
+
text = text.replace(self.Utils.escapeExpression(id), function () {
|
|
624
625
|
return self.Utils.escapeExpression(values[id]);
|
|
625
626
|
});
|
|
626
627
|
});
|
|
@@ -631,9 +632,9 @@ ExpressHbs.prototype.___express = function ___express(filename, source, options,
|
|
|
631
632
|
// Handles waiting for async helpers
|
|
632
633
|
function handleAsync(err, res) {
|
|
633
634
|
if (err) return cb(err);
|
|
634
|
-
resolver.done(options.resolverCache, function(err, values) {
|
|
635
|
+
resolver.done(options.resolverCache, function (err, values) {
|
|
635
636
|
if (err) return cb(err);
|
|
636
|
-
Object.keys(values).forEach(function(key) {
|
|
637
|
+
Object.keys(values).forEach(function (key) {
|
|
637
638
|
values[key] = replaceValue(values, values[key]);
|
|
638
639
|
});
|
|
639
640
|
res = replaceValue(values, res);
|
|
@@ -645,13 +646,13 @@ ExpressHbs.prototype.___express = function ___express(filename, source, options,
|
|
|
645
646
|
}
|
|
646
647
|
|
|
647
648
|
// kick it off by loading default template (if any)
|
|
648
|
-
this.loadDefaultLayout(options.cache, function(err) {
|
|
649
|
+
this.loadDefaultLayout(options.cache, function (err) {
|
|
649
650
|
if (err) return cb(err);
|
|
650
651
|
|
|
651
652
|
// Force reloading of all partials if caching is not used. Inefficient but there
|
|
652
653
|
// is no loading partial event.
|
|
653
654
|
if (self.partialsDir && (!options.cache || !self.isPartialCachingComplete)) {
|
|
654
|
-
return self.cachePartials(function(err) {
|
|
655
|
+
return self.cachePartials(function (err) {
|
|
655
656
|
if (err) return cb(err);
|
|
656
657
|
return compileFile(options, handleAsync);
|
|
657
658
|
});
|
package/lib/resolver.js
CHANGED
|
@@ -14,9 +14,9 @@ var ID_SUFFIX = '__';
|
|
|
14
14
|
|
|
15
15
|
function resolve(cache, fn, context) {
|
|
16
16
|
var id = ID_PREFIX + ID_ESCAPED_STRING + generateId(ID_LENGTH) + ID_SUFFIX;
|
|
17
|
-
cache[id] = new Promise(function(passed, failed) {
|
|
17
|
+
cache[id] = new Promise(function (passed, failed) {
|
|
18
18
|
try {
|
|
19
|
-
fn(context, function(res) {
|
|
19
|
+
fn(context, function (res) {
|
|
20
20
|
passed(res);
|
|
21
21
|
});
|
|
22
22
|
} catch (error) {
|
|
@@ -29,23 +29,24 @@ function resolve(cache, fn, context) {
|
|
|
29
29
|
// cache is an object where the keys are cache keys and values are promises. See above.
|
|
30
30
|
function done(cache, callback) {
|
|
31
31
|
return Promise.all(Object.values(cache))
|
|
32
|
-
.then(function(values) {
|
|
32
|
+
.then(function (values) {
|
|
33
33
|
var resolvedCache = {};
|
|
34
34
|
var keys = Object.keys(cache);
|
|
35
|
-
values.forEach(function(value, index) {
|
|
35
|
+
values.forEach(function (value, index) {
|
|
36
36
|
resolvedCache[keys[index]] = value;
|
|
37
37
|
});
|
|
38
38
|
callback(null, resolvedCache);
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
39
|
+
})
|
|
40
|
+
.catch(function (error) {
|
|
41
|
+
callback(error);
|
|
42
|
+
});
|
|
42
43
|
}
|
|
43
44
|
|
|
44
45
|
function hasResolvers(text) {
|
|
45
46
|
// NOTE: We specifically search the text for the ID_PREFIX **NOT** including the escapable character
|
|
46
47
|
// This is because that character can be escaped in the text, and lead us to not finding unresolved
|
|
47
48
|
// async helper outputs.
|
|
48
|
-
if (text.search(ID_PREFIX)
|
|
49
|
+
if (text.search(ID_PREFIX) >= 0) {
|
|
49
50
|
return true;
|
|
50
51
|
}
|
|
51
52
|
return false;
|
|
@@ -54,5 +55,5 @@ function hasResolvers(text) {
|
|
|
54
55
|
module.exports = {
|
|
55
56
|
done: done,
|
|
56
57
|
hasResolvers: hasResolvers,
|
|
57
|
-
resolve: resolve
|
|
58
|
+
resolve: resolve,
|
|
58
59
|
};
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "express-hbs",
|
|
3
|
-
"version": "
|
|
3
|
+
"version": "3.0.0",
|
|
4
4
|
"description": "Express handlebars template engine complete with multiple layouts, partials and blocks.",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"express4",
|
|
@@ -10,17 +10,12 @@
|
|
|
10
10
|
"partials"
|
|
11
11
|
],
|
|
12
12
|
"main": "index.js",
|
|
13
|
+
"engines": {
|
|
14
|
+
"node": ">=20"
|
|
15
|
+
},
|
|
13
16
|
"directories": {
|
|
14
17
|
"example": "example"
|
|
15
18
|
},
|
|
16
|
-
"scripts": {
|
|
17
|
-
"lint": "eslint --ext .js --cache lib/**",
|
|
18
|
-
"test": "mocha",
|
|
19
|
-
"posttest": "yarn lint",
|
|
20
|
-
"coverage": "nyc yarn test",
|
|
21
|
-
"preship": "yarn test",
|
|
22
|
-
"ship": "STATUS=$(git status --porcelain); echo $STATUS; if [ -z \"$STATUS\" ]; then yarn publish && git push --follow-tags; fi"
|
|
23
|
-
},
|
|
24
19
|
"repository": {
|
|
25
20
|
"type": "git",
|
|
26
21
|
"url": "https://github.com/TryGhost/express-hbs"
|
|
@@ -29,21 +24,33 @@
|
|
|
29
24
|
"author": "Mario Gutierrez <mario@barc.com>",
|
|
30
25
|
"license": "MIT",
|
|
31
26
|
"devDependencies": {
|
|
32
|
-
"cookie-parser": "1.4.
|
|
33
|
-
"
|
|
34
|
-
"
|
|
35
|
-
"
|
|
36
|
-
"
|
|
37
|
-
"
|
|
38
|
-
"
|
|
39
|
-
"
|
|
27
|
+
"cookie-parser": "1.4.7",
|
|
28
|
+
"express": "5.2.1",
|
|
29
|
+
"i18n": "0.15.3",
|
|
30
|
+
"mocha": "11.7.6",
|
|
31
|
+
"nyc": "18.0.0",
|
|
32
|
+
"oxfmt": "0.57.0",
|
|
33
|
+
"oxlint": "1.72.0",
|
|
34
|
+
"rewire": "9.0.1",
|
|
35
|
+
"supertest": "7.2.2"
|
|
40
36
|
},
|
|
41
37
|
"dependencies": {
|
|
42
|
-
"
|
|
43
|
-
"
|
|
44
|
-
"
|
|
38
|
+
"@tryghost/pro-ship": "1.1.5",
|
|
39
|
+
"handlebars": "4.7.9",
|
|
40
|
+
"lodash": "4.18.1",
|
|
41
|
+
"readdirp": "3.6.0"
|
|
45
42
|
},
|
|
46
43
|
"optionalDependencies": {
|
|
47
|
-
"js-beautify": "^
|
|
44
|
+
"js-beautify": "^2.0.0"
|
|
45
|
+
},
|
|
46
|
+
"scripts": {
|
|
47
|
+
"lint": "oxlint --quiet && oxfmt --check .",
|
|
48
|
+
"lint:fix": "oxlint --fix && oxfmt .",
|
|
49
|
+
"format": "oxfmt .",
|
|
50
|
+
"test": "mocha",
|
|
51
|
+
"posttest": "pnpm lint",
|
|
52
|
+
"coverage": "nyc --check-coverage mocha",
|
|
53
|
+
"preship": "pnpm test",
|
|
54
|
+
"ship": "pro-ship"
|
|
48
55
|
}
|
|
49
|
-
}
|
|
56
|
+
}
|
package/renovate.json
CHANGED
|
@@ -1,6 +1,13 @@
|
|
|
1
1
|
{
|
|
2
|
+
"$schema": "https://docs.renovatebot.com/renovate-schema.json",
|
|
2
3
|
"extends": [
|
|
3
|
-
"
|
|
4
|
-
|
|
4
|
+
"local>TryGhost/renovate-config"
|
|
5
|
+
],
|
|
6
|
+
"packageRules": [
|
|
7
|
+
{
|
|
8
|
+
"description": "Keep pnpm on 10.x while this repo supports Node 20; pnpm 11 requires Node 22.13 or newer.",
|
|
9
|
+
"matchPackageNames": ["pnpm"],
|
|
10
|
+
"allowedVersions": "<11"
|
|
11
|
+
}
|
|
5
12
|
]
|
|
6
13
|
}
|