@kosatyi/ejs 0.0.76 → 0.0.78
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 +1 -1
- package/bin/bundler.js +43 -0
- package/dist/cjs/browser.js +44 -11
- package/dist/cjs/bundler.js +171 -0
- package/dist/cjs/index.js +44 -11
- package/dist/cjs/worker.js +1278 -0
- package/dist/esm/browser.js +56 -21
- package/dist/esm/bundler.js +168 -0
- package/dist/esm/index.js +56 -21
- package/dist/esm/worker.js +1034 -0
- package/dist/umd/browser.js +44 -11
- package/dist/umd/browser.min.js +1 -1
- package/dist/umd/index.js +44 -11
- package/dist/umd/index.min.js +1 -1
- package/dist/umd/worker.js +1284 -0
- package/dist/umd/worker.min.js +1 -0
- package/package.json +23 -7
- package/types/bundler.d.ts +30 -0
- package/types/ejs.d.ts +86 -0
- package/types/global.d.ts +2 -87
- package/dist/cjs/package.json +0 -3
|
@@ -0,0 +1,1034 @@
|
|
|
1
|
+
const typeProp = function () {
|
|
2
|
+
const args = [].slice.call(arguments);
|
|
3
|
+
const callback = args.shift();
|
|
4
|
+
return args.filter(callback).pop()
|
|
5
|
+
};
|
|
6
|
+
const isArray = (v) => Array.isArray(v);
|
|
7
|
+
const isFunction = (v) => typeof v === 'function';
|
|
8
|
+
const isString = (v) => typeof v === 'string';
|
|
9
|
+
const isBoolean = (v) => typeof v === 'boolean';
|
|
10
|
+
const isUndefined = (v) => typeof v === 'undefined';
|
|
11
|
+
|
|
12
|
+
const isNodeEnv =
|
|
13
|
+
Object.prototype.toString.call(
|
|
14
|
+
typeof process !== 'undefined' ? process : 0
|
|
15
|
+
) === '[object process]';
|
|
16
|
+
|
|
17
|
+
const isNode = () => isNodeEnv;
|
|
18
|
+
|
|
19
|
+
const symbolEntities = {
|
|
20
|
+
"'": "'",
|
|
21
|
+
'\\': '\\',
|
|
22
|
+
'\r': 'r',
|
|
23
|
+
'\n': 'n',
|
|
24
|
+
'\t': 't',
|
|
25
|
+
'\u2028': 'u2028',
|
|
26
|
+
'\u2029': 'u2029',
|
|
27
|
+
};
|
|
28
|
+
|
|
29
|
+
const htmlEntities = {
|
|
30
|
+
'&': '&',
|
|
31
|
+
'<': '<',
|
|
32
|
+
'>': '>',
|
|
33
|
+
'"': '"',
|
|
34
|
+
"'": ''',
|
|
35
|
+
};
|
|
36
|
+
|
|
37
|
+
const regexKeys = (obj) =>
|
|
38
|
+
new RegExp(['[', Object.keys(obj).join(''), ']'].join(''), 'g');
|
|
39
|
+
|
|
40
|
+
const htmlEntitiesMatch = regexKeys(htmlEntities);
|
|
41
|
+
|
|
42
|
+
const symbolEntitiesMatch = regexKeys(symbolEntities);
|
|
43
|
+
|
|
44
|
+
const entities = (string = '') => {
|
|
45
|
+
return ('' + string).replace(
|
|
46
|
+
htmlEntitiesMatch,
|
|
47
|
+
(match) => htmlEntities[match]
|
|
48
|
+
)
|
|
49
|
+
};
|
|
50
|
+
|
|
51
|
+
const symbols = (string) => {
|
|
52
|
+
return ('' + string).replace(
|
|
53
|
+
symbolEntitiesMatch,
|
|
54
|
+
(match) => '\\' + symbolEntities[match]
|
|
55
|
+
)
|
|
56
|
+
};
|
|
57
|
+
|
|
58
|
+
const safeValue = (value, escape) => {
|
|
59
|
+
const check = value;
|
|
60
|
+
return check == null ? '' : escape === true ? entities(check) : check
|
|
61
|
+
};
|
|
62
|
+
|
|
63
|
+
const instanceOf = (object, instance) => {
|
|
64
|
+
return Boolean(object instanceof instance)
|
|
65
|
+
};
|
|
66
|
+
|
|
67
|
+
const getPath = (context, name, strict) => {
|
|
68
|
+
let data = context;
|
|
69
|
+
let chunks = String(name).split('.');
|
|
70
|
+
let prop = chunks.pop();
|
|
71
|
+
for (let i = 0; i < chunks.length; i++) {
|
|
72
|
+
const part = chunks[i];
|
|
73
|
+
if (isFunction(data['toJSON'])) {
|
|
74
|
+
data = data.toJSON();
|
|
75
|
+
}
|
|
76
|
+
if (strict && data.hasOwnProperty(part) === false) {
|
|
77
|
+
data = {};
|
|
78
|
+
break
|
|
79
|
+
}
|
|
80
|
+
data = data[part] = data[part] || {};
|
|
81
|
+
}
|
|
82
|
+
if (isFunction(data['toJSON'])) {
|
|
83
|
+
data = data.toJSON();
|
|
84
|
+
}
|
|
85
|
+
return [data, prop]
|
|
86
|
+
};
|
|
87
|
+
|
|
88
|
+
const ext = (path, defaults) => {
|
|
89
|
+
const ext = path.split('.').pop();
|
|
90
|
+
if (ext !== defaults) {
|
|
91
|
+
path = [path, defaults].join('.');
|
|
92
|
+
}
|
|
93
|
+
return path
|
|
94
|
+
};
|
|
95
|
+
|
|
96
|
+
/**
|
|
97
|
+
* @type {<T extends {}, U, V, W,Y>(T,U,V,W,Y)=> T & U & V & W & Y}
|
|
98
|
+
*/
|
|
99
|
+
const extend = (target, ...args) => {
|
|
100
|
+
return args
|
|
101
|
+
.filter((source) => source)
|
|
102
|
+
.reduce((target, source) => Object.assign(target, source), target)
|
|
103
|
+
};
|
|
104
|
+
|
|
105
|
+
const noop = () => {};
|
|
106
|
+
|
|
107
|
+
const each = (object, callback) => {
|
|
108
|
+
let prop;
|
|
109
|
+
for (prop in object) {
|
|
110
|
+
if (hasProp(object, prop)) {
|
|
111
|
+
callback(object[prop], prop, object);
|
|
112
|
+
}
|
|
113
|
+
}
|
|
114
|
+
};
|
|
115
|
+
|
|
116
|
+
const map = (object, callback, context) => {
|
|
117
|
+
const result = [];
|
|
118
|
+
each(
|
|
119
|
+
object,
|
|
120
|
+
(value, key, object) => {
|
|
121
|
+
let item = callback(value, key, object);
|
|
122
|
+
if (isUndefined(item) === false) {
|
|
123
|
+
result.push(item);
|
|
124
|
+
}
|
|
125
|
+
});
|
|
126
|
+
return result
|
|
127
|
+
};
|
|
128
|
+
|
|
129
|
+
const filter = (object, callback, context) => {
|
|
130
|
+
const isArray = object instanceof Array;
|
|
131
|
+
const result = isArray ? [] : {};
|
|
132
|
+
each(
|
|
133
|
+
object,
|
|
134
|
+
(value, key, object) => {
|
|
135
|
+
let item = callback(value, key, object);
|
|
136
|
+
if (isUndefined(item) === false) {
|
|
137
|
+
if (isArray) {
|
|
138
|
+
result.push(item);
|
|
139
|
+
} else {
|
|
140
|
+
result[key] = item;
|
|
141
|
+
}
|
|
142
|
+
}
|
|
143
|
+
});
|
|
144
|
+
return result
|
|
145
|
+
};
|
|
146
|
+
|
|
147
|
+
const omit = (object, list) => {
|
|
148
|
+
return filter(object, (value, key) => {
|
|
149
|
+
if (list.indexOf(key) === -1) {
|
|
150
|
+
return value
|
|
151
|
+
}
|
|
152
|
+
})
|
|
153
|
+
};
|
|
154
|
+
|
|
155
|
+
const resolve$1 = (value, callback, context) =>
|
|
156
|
+
Promise.resolve(value).then(callback.bind(context));
|
|
157
|
+
|
|
158
|
+
const hasProp = (object, prop) => {
|
|
159
|
+
return object && object.hasOwnProperty(prop)
|
|
160
|
+
};
|
|
161
|
+
|
|
162
|
+
const defaults = {};
|
|
163
|
+
|
|
164
|
+
defaults.export = 'ejsPrecompiled';
|
|
165
|
+
defaults.cache = true;
|
|
166
|
+
defaults.chokidar = null;
|
|
167
|
+
defaults.path = 'views';
|
|
168
|
+
defaults.resolver = function (path, template) {
|
|
169
|
+
return Promise.resolve(
|
|
170
|
+
['resolver is not defined', path, template].join(' ')
|
|
171
|
+
)
|
|
172
|
+
};
|
|
173
|
+
defaults.extension = 'ejs';
|
|
174
|
+
defaults.rmWhitespace = true;
|
|
175
|
+
defaults.withObject = true;
|
|
176
|
+
defaults.globalHelpers = [];
|
|
177
|
+
defaults.vars = {
|
|
178
|
+
SCOPE: 'ejs',
|
|
179
|
+
COMPONENT: 'ui',
|
|
180
|
+
EXTEND: '$$e',
|
|
181
|
+
BUFFER: '$$a',
|
|
182
|
+
LAYOUT: '$$l',
|
|
183
|
+
BLOCKS: '$$b',
|
|
184
|
+
MACRO: '$$m',
|
|
185
|
+
SAFE: '$$v',
|
|
186
|
+
};
|
|
187
|
+
defaults.token = {
|
|
188
|
+
start: '<%',
|
|
189
|
+
end: '%>',
|
|
190
|
+
regex: '([\\s\\S]+?)',
|
|
191
|
+
};
|
|
192
|
+
|
|
193
|
+
const configSchema = (config, options) => {
|
|
194
|
+
extend(config, {
|
|
195
|
+
path: typeProp(isString, defaults.path, config.path, options.path),
|
|
196
|
+
export: typeProp(
|
|
197
|
+
isString,
|
|
198
|
+
defaults.export,
|
|
199
|
+
config.export,
|
|
200
|
+
options.export
|
|
201
|
+
),
|
|
202
|
+
resolver: typeProp(
|
|
203
|
+
isFunction,
|
|
204
|
+
defaults.resolver,
|
|
205
|
+
config.resolver,
|
|
206
|
+
options.resolver
|
|
207
|
+
),
|
|
208
|
+
extension: typeProp(
|
|
209
|
+
isString,
|
|
210
|
+
defaults.extension,
|
|
211
|
+
config.extension,
|
|
212
|
+
options.extension
|
|
213
|
+
),
|
|
214
|
+
withObject: typeProp(
|
|
215
|
+
isBoolean,
|
|
216
|
+
defaults.withObject,
|
|
217
|
+
config.withObject,
|
|
218
|
+
options.withObject
|
|
219
|
+
),
|
|
220
|
+
rmWhitespace: typeProp(
|
|
221
|
+
isBoolean,
|
|
222
|
+
defaults.rmWhitespace,
|
|
223
|
+
config.rmWhitespace,
|
|
224
|
+
options.rmWhitespace
|
|
225
|
+
),
|
|
226
|
+
cache: typeProp(isBoolean, defaults.cache, config.cache, options.cache),
|
|
227
|
+
token: extend({}, defaults.token, config.token, options.token),
|
|
228
|
+
vars: extend({}, defaults.vars, config.vars, options.vars),
|
|
229
|
+
globalHelpers: typeProp(
|
|
230
|
+
isArray,
|
|
231
|
+
defaults.globalHelpers,
|
|
232
|
+
config.globalHelpers,
|
|
233
|
+
options.globalHelpers
|
|
234
|
+
),
|
|
235
|
+
});
|
|
236
|
+
};
|
|
237
|
+
|
|
238
|
+
const global = typeof globalThis !== 'undefined' ? globalThis : window || self;
|
|
239
|
+
|
|
240
|
+
function Cache(config) {
|
|
241
|
+
if (instanceOf(this, Cache) === false) return new Cache()
|
|
242
|
+
const cache = {
|
|
243
|
+
enabled: true,
|
|
244
|
+
list: {},
|
|
245
|
+
};
|
|
246
|
+
this.configure = function (config) {
|
|
247
|
+
cache.enabled = config.cache;
|
|
248
|
+
if (isNode() === false) {
|
|
249
|
+
this.load(global[config.export]);
|
|
250
|
+
}
|
|
251
|
+
};
|
|
252
|
+
this.clear = function () {
|
|
253
|
+
cache.list = {};
|
|
254
|
+
};
|
|
255
|
+
this.load = function (data) {
|
|
256
|
+
if (cache.enabled) {
|
|
257
|
+
extend(cache.list, data || {});
|
|
258
|
+
}
|
|
259
|
+
return this
|
|
260
|
+
};
|
|
261
|
+
this.get = function (key) {
|
|
262
|
+
if (cache.enabled) {
|
|
263
|
+
return cache.list[key]
|
|
264
|
+
}
|
|
265
|
+
};
|
|
266
|
+
this.set = function (key, value) {
|
|
267
|
+
if (cache.enabled) {
|
|
268
|
+
cache.list[key] = value;
|
|
269
|
+
}
|
|
270
|
+
return this
|
|
271
|
+
};
|
|
272
|
+
this.resolve = function (key) {
|
|
273
|
+
return Promise.resolve(this.get(key))
|
|
274
|
+
};
|
|
275
|
+
this.remove = function (key) {
|
|
276
|
+
delete cache.list[key];
|
|
277
|
+
};
|
|
278
|
+
this.exist = function (key) {
|
|
279
|
+
return hasProp(cache.list, key)
|
|
280
|
+
};
|
|
281
|
+
}
|
|
282
|
+
|
|
283
|
+
const tagList = [
|
|
284
|
+
{
|
|
285
|
+
symbol: '-',
|
|
286
|
+
format(value) {
|
|
287
|
+
return `')\n${this.BUFFER}(${this.SAFE}(${value},1))\n${this.BUFFER}('`
|
|
288
|
+
},
|
|
289
|
+
},
|
|
290
|
+
{
|
|
291
|
+
symbol: '=',
|
|
292
|
+
format(value) {
|
|
293
|
+
return `')\n${this.BUFFER}(${this.SAFE}(${value}))\n${this.BUFFER}('`
|
|
294
|
+
},
|
|
295
|
+
},
|
|
296
|
+
{
|
|
297
|
+
symbol: '#',
|
|
298
|
+
format(value) {
|
|
299
|
+
return `')\n/**${value}**/\n${this.BUFFER}('`
|
|
300
|
+
},
|
|
301
|
+
},
|
|
302
|
+
{
|
|
303
|
+
symbol: '',
|
|
304
|
+
format(value) {
|
|
305
|
+
return `')\n${value.trim()}\n${this.BUFFER}('`
|
|
306
|
+
},
|
|
307
|
+
},
|
|
308
|
+
];
|
|
309
|
+
|
|
310
|
+
function matchTokens(regex, text, callback) {
|
|
311
|
+
let index = 0;
|
|
312
|
+
text.replace(regex, function () {
|
|
313
|
+
const params = [].slice.call(arguments, 0, -1);
|
|
314
|
+
const offset = params.pop();
|
|
315
|
+
const match = params.shift();
|
|
316
|
+
callback(params, index, offset);
|
|
317
|
+
index = offset + match.length;
|
|
318
|
+
return match
|
|
319
|
+
});
|
|
320
|
+
}
|
|
321
|
+
|
|
322
|
+
function Compiler(config) {
|
|
323
|
+
if (instanceOf(this, Compiler) === false) return new Compiler(config)
|
|
324
|
+
|
|
325
|
+
const compiler = {};
|
|
326
|
+
|
|
327
|
+
this.configure = function (config) {
|
|
328
|
+
compiler.withObject = config.withObject;
|
|
329
|
+
compiler.rmWhitespace = config.rmWhitespace;
|
|
330
|
+
compiler.token = config.token;
|
|
331
|
+
compiler.vars = config.vars;
|
|
332
|
+
compiler.globalHelpers = config.globalHelpers;
|
|
333
|
+
compiler.matches = [];
|
|
334
|
+
compiler.formats = [];
|
|
335
|
+
compiler.slurp = {
|
|
336
|
+
match: '[ \\t]*',
|
|
337
|
+
start: [compiler.token.start, '_'],
|
|
338
|
+
end: ['_', compiler.token.end],
|
|
339
|
+
};
|
|
340
|
+
tagList.forEach((item) => {
|
|
341
|
+
compiler.matches.push(
|
|
342
|
+
compiler.token.start
|
|
343
|
+
.concat(item.symbol)
|
|
344
|
+
.concat(compiler.token.regex)
|
|
345
|
+
.concat(compiler.token.end)
|
|
346
|
+
);
|
|
347
|
+
compiler.formats.push(item.format.bind(compiler.vars));
|
|
348
|
+
});
|
|
349
|
+
compiler.regex = new RegExp(
|
|
350
|
+
compiler.matches.join('|').concat('|$'),
|
|
351
|
+
'g'
|
|
352
|
+
);
|
|
353
|
+
compiler.slurpStart = new RegExp(
|
|
354
|
+
[compiler.slurp.match, compiler.slurp.start.join('')].join(''),
|
|
355
|
+
'gm'
|
|
356
|
+
);
|
|
357
|
+
compiler.slurpEnd = new RegExp(
|
|
358
|
+
[compiler.slurp.end.join(''), compiler.slurp.match].join(''),
|
|
359
|
+
'gm'
|
|
360
|
+
);
|
|
361
|
+
};
|
|
362
|
+
|
|
363
|
+
this.compile = function (content, path) {
|
|
364
|
+
const { SCOPE, SAFE, BUFFER, COMPONENT } = compiler.vars;
|
|
365
|
+
const GLOBALS = compiler.globalHelpers;
|
|
366
|
+
content = String(content);
|
|
367
|
+
if (compiler.rmWhitespace) {
|
|
368
|
+
content = content
|
|
369
|
+
.replace(/[\r\n]+/g, '\n')
|
|
370
|
+
.replace(/^\s+|\s+$/gm, '');
|
|
371
|
+
}
|
|
372
|
+
content = content
|
|
373
|
+
.replace(compiler.slurpStart, compiler.token.start)
|
|
374
|
+
.replace(compiler.slurpEnd, compiler.token.end);
|
|
375
|
+
let source = `${BUFFER}('`;
|
|
376
|
+
matchTokens(compiler.regex, content, (params, index, offset) => {
|
|
377
|
+
source += symbols(content.slice(index, offset));
|
|
378
|
+
params.forEach((value, index) => {
|
|
379
|
+
if (value) {
|
|
380
|
+
source += compiler.formats[index](value);
|
|
381
|
+
}
|
|
382
|
+
});
|
|
383
|
+
});
|
|
384
|
+
source += `');`;
|
|
385
|
+
source = `try{${source}}catch(e){return ${BUFFER}.error(e)}`;
|
|
386
|
+
if (compiler.withObject) {
|
|
387
|
+
source = `with(${SCOPE}){${source}}`;
|
|
388
|
+
}
|
|
389
|
+
source = `${BUFFER}.start();${source}return ${BUFFER}.end();`;
|
|
390
|
+
source += `\n//# sourceURL=${path}`;
|
|
391
|
+
let result = null;
|
|
392
|
+
let params = [SCOPE, COMPONENT, BUFFER, SAFE].concat(GLOBALS);
|
|
393
|
+
try {
|
|
394
|
+
result = Function.apply(null, params.concat(source));
|
|
395
|
+
result.source = `(function(${params.join(',')}){\n${source}\n})`;
|
|
396
|
+
} catch (e) {
|
|
397
|
+
e.filename = path;
|
|
398
|
+
e.source = source;
|
|
399
|
+
throw e
|
|
400
|
+
}
|
|
401
|
+
return result
|
|
402
|
+
};
|
|
403
|
+
|
|
404
|
+
this.configure(config);
|
|
405
|
+
}
|
|
406
|
+
|
|
407
|
+
function Template(config, cache, compiler) {
|
|
408
|
+
if (instanceOf(this, Template) === false)
|
|
409
|
+
return new Template(config, cache, compiler)
|
|
410
|
+
|
|
411
|
+
if (instanceOf(cache, Cache) === false)
|
|
412
|
+
throw new TypeError('cache is not instance of Cache')
|
|
413
|
+
|
|
414
|
+
if (instanceOf(compiler, Compiler) === false)
|
|
415
|
+
throw new TypeError('compiler is not instance of Compiler')
|
|
416
|
+
|
|
417
|
+
const template = {};
|
|
418
|
+
|
|
419
|
+
const result = (template, content) => {
|
|
420
|
+
cache.set(template, content);
|
|
421
|
+
return content
|
|
422
|
+
};
|
|
423
|
+
|
|
424
|
+
const resolve = (path) => {
|
|
425
|
+
return template.resolver(template.path, path)
|
|
426
|
+
};
|
|
427
|
+
|
|
428
|
+
const compile = (content, template) => {
|
|
429
|
+
if (isFunction(content)) {
|
|
430
|
+
return content
|
|
431
|
+
} else {
|
|
432
|
+
return compiler.compile(content, template)
|
|
433
|
+
}
|
|
434
|
+
};
|
|
435
|
+
|
|
436
|
+
this.configure = function (config) {
|
|
437
|
+
template.path = config.path;
|
|
438
|
+
template.cache = config.cache;
|
|
439
|
+
if (isFunction(config.resolver)) {
|
|
440
|
+
template.resolver = config.resolver;
|
|
441
|
+
}
|
|
442
|
+
};
|
|
443
|
+
|
|
444
|
+
this.get = function (template) {
|
|
445
|
+
if (cache.exist(template)) {
|
|
446
|
+
return cache.resolve(template)
|
|
447
|
+
}
|
|
448
|
+
return resolve(template).then((content) =>
|
|
449
|
+
result(template, compile(content, template))
|
|
450
|
+
)
|
|
451
|
+
};
|
|
452
|
+
this.configure(config);
|
|
453
|
+
}
|
|
454
|
+
|
|
455
|
+
const selfClosed = [
|
|
456
|
+
'area',
|
|
457
|
+
'base',
|
|
458
|
+
'br',
|
|
459
|
+
'col',
|
|
460
|
+
'embed',
|
|
461
|
+
'hr',
|
|
462
|
+
'img',
|
|
463
|
+
'input',
|
|
464
|
+
'link',
|
|
465
|
+
'meta',
|
|
466
|
+
'param',
|
|
467
|
+
'source',
|
|
468
|
+
'track',
|
|
469
|
+
'wbr',
|
|
470
|
+
];
|
|
471
|
+
|
|
472
|
+
const space = ' ';
|
|
473
|
+
const quote = '"';
|
|
474
|
+
const equal = '=';
|
|
475
|
+
const slash = '/';
|
|
476
|
+
const lt = '<';
|
|
477
|
+
const gt = '>';
|
|
478
|
+
|
|
479
|
+
const element = (tag, attrs, content) => {
|
|
480
|
+
const result = [];
|
|
481
|
+
const hasClosedTag = selfClosed.indexOf(tag) === -1;
|
|
482
|
+
const attributes = map(attrs, (value, key) => {
|
|
483
|
+
if (value !== null && value !== undefined) {
|
|
484
|
+
return [
|
|
485
|
+
entities(key),
|
|
486
|
+
[quote, entities(value), quote].join(''),
|
|
487
|
+
].join(equal)
|
|
488
|
+
}
|
|
489
|
+
}).join(space);
|
|
490
|
+
result.push([lt, tag, space, attributes, gt].join(''));
|
|
491
|
+
if (content) {
|
|
492
|
+
result.push(content instanceof Array ? content.join('') : content);
|
|
493
|
+
}
|
|
494
|
+
if (hasClosedTag) {
|
|
495
|
+
result.push([lt, slash, tag, gt].join(''));
|
|
496
|
+
}
|
|
497
|
+
return result.join('')
|
|
498
|
+
};
|
|
499
|
+
|
|
500
|
+
function TemplateError(message) {
|
|
501
|
+
this.code = 1;
|
|
502
|
+
this.name = 'TemplateError';
|
|
503
|
+
this.message = message;
|
|
504
|
+
Error.call(this);
|
|
505
|
+
}
|
|
506
|
+
Object.setPrototypeOf(TemplateNotFound.prototype, Error.prototype);
|
|
507
|
+
|
|
508
|
+
function TemplateNotFound(message) {
|
|
509
|
+
TemplateError.call(this);
|
|
510
|
+
this.code = 404;
|
|
511
|
+
this.name = 'TemplateNotFound';
|
|
512
|
+
this.message = message;
|
|
513
|
+
}
|
|
514
|
+
|
|
515
|
+
Object.setPrototypeOf(TemplateNotFound.prototype, TemplateError.prototype);
|
|
516
|
+
|
|
517
|
+
function TemplateSyntaxError(message) {
|
|
518
|
+
TemplateError.call(this);
|
|
519
|
+
this.code = 500;
|
|
520
|
+
this.name = 'TemplateSyntaxError';
|
|
521
|
+
this.message = message;
|
|
522
|
+
}
|
|
523
|
+
|
|
524
|
+
Object.setPrototypeOf(TemplateSyntaxError.prototype, TemplateError.prototype);
|
|
525
|
+
|
|
526
|
+
function resolve(list) {
|
|
527
|
+
return Promise.all(list || []).then((list) => list.join(''))
|
|
528
|
+
}
|
|
529
|
+
|
|
530
|
+
function reject(error) {
|
|
531
|
+
return Promise.reject(new TemplateSyntaxError(error.message))
|
|
532
|
+
}
|
|
533
|
+
|
|
534
|
+
function createBuffer() {
|
|
535
|
+
let store = [],
|
|
536
|
+
array = [];
|
|
537
|
+
function buffer(value) {
|
|
538
|
+
array.push(value);
|
|
539
|
+
}
|
|
540
|
+
buffer.start = function () {
|
|
541
|
+
array = [];
|
|
542
|
+
};
|
|
543
|
+
buffer.backup = function () {
|
|
544
|
+
store.push(array.concat());
|
|
545
|
+
array = [];
|
|
546
|
+
};
|
|
547
|
+
buffer.restore = function () {
|
|
548
|
+
const result = array.concat();
|
|
549
|
+
array = store.pop();
|
|
550
|
+
return resolve(result)
|
|
551
|
+
};
|
|
552
|
+
buffer.error = function (e) {
|
|
553
|
+
return reject(e)
|
|
554
|
+
};
|
|
555
|
+
buffer.end = function () {
|
|
556
|
+
return resolve(array)
|
|
557
|
+
};
|
|
558
|
+
return buffer
|
|
559
|
+
}
|
|
560
|
+
|
|
561
|
+
function Context(config) {
|
|
562
|
+
if (instanceOf(this, Context) === false) return new Context(config)
|
|
563
|
+
this.configure = function (config, methods) {
|
|
564
|
+
const { BLOCKS, MACRO, EXTEND, LAYOUT, BUFFER, COMPONENT } = config.vars;
|
|
565
|
+
|
|
566
|
+
this.create = function (data) {
|
|
567
|
+
return new Scope(data)
|
|
568
|
+
};
|
|
569
|
+
|
|
570
|
+
this.helpers = function (methods) {
|
|
571
|
+
extend(Scope.prototype, methods || {});
|
|
572
|
+
};
|
|
573
|
+
/**
|
|
574
|
+
* @name ContextScope
|
|
575
|
+
* @param data
|
|
576
|
+
* @constructor
|
|
577
|
+
*/
|
|
578
|
+
function Scope(data) {
|
|
579
|
+
this[BLOCKS] = {};
|
|
580
|
+
this[MACRO] = {};
|
|
581
|
+
extend(this, data || {});
|
|
582
|
+
}
|
|
583
|
+
|
|
584
|
+
Scope.prototype = extend({}, methods || {});
|
|
585
|
+
Object.defineProperties(Scope.prototype, {
|
|
586
|
+
[BUFFER]: {
|
|
587
|
+
value: createBuffer(),
|
|
588
|
+
writable: true,
|
|
589
|
+
configurable: false,
|
|
590
|
+
enumerable: false,
|
|
591
|
+
},
|
|
592
|
+
[BLOCKS]: {
|
|
593
|
+
value: {},
|
|
594
|
+
writable: true,
|
|
595
|
+
configurable: false,
|
|
596
|
+
enumerable: false,
|
|
597
|
+
},
|
|
598
|
+
[MACRO]: {
|
|
599
|
+
value: {},
|
|
600
|
+
writable: true,
|
|
601
|
+
configurable: false,
|
|
602
|
+
enumerable: false,
|
|
603
|
+
},
|
|
604
|
+
[LAYOUT]: {
|
|
605
|
+
value: false,
|
|
606
|
+
writable: true,
|
|
607
|
+
configurable: false,
|
|
608
|
+
enumerable: false,
|
|
609
|
+
},
|
|
610
|
+
[EXTEND]: {
|
|
611
|
+
value: false,
|
|
612
|
+
writable: true,
|
|
613
|
+
configurable: false,
|
|
614
|
+
enumerable: false,
|
|
615
|
+
},
|
|
616
|
+
getMacro: {
|
|
617
|
+
value() {
|
|
618
|
+
return this[MACRO]
|
|
619
|
+
},
|
|
620
|
+
writable: false,
|
|
621
|
+
configurable: false,
|
|
622
|
+
enumerable: false,
|
|
623
|
+
},
|
|
624
|
+
getBuffer: {
|
|
625
|
+
value() {
|
|
626
|
+
return this[BUFFER]
|
|
627
|
+
},
|
|
628
|
+
writable: false,
|
|
629
|
+
configurable: false,
|
|
630
|
+
enumerable: false,
|
|
631
|
+
},
|
|
632
|
+
getComponent: {
|
|
633
|
+
value() {
|
|
634
|
+
const context = this;
|
|
635
|
+
if (COMPONENT in context) {
|
|
636
|
+
return function () {
|
|
637
|
+
return context[COMPONENT].apply(context, arguments)
|
|
638
|
+
}
|
|
639
|
+
}
|
|
640
|
+
return function () {
|
|
641
|
+
console.log('%s function not defined', COMPONENT);
|
|
642
|
+
}
|
|
643
|
+
},
|
|
644
|
+
writable: false,
|
|
645
|
+
configurable: false,
|
|
646
|
+
enumerable: false,
|
|
647
|
+
},
|
|
648
|
+
getBlocks: {
|
|
649
|
+
value() {
|
|
650
|
+
return this[BLOCKS]
|
|
651
|
+
},
|
|
652
|
+
writable: false,
|
|
653
|
+
configurable: false,
|
|
654
|
+
enumerable: false,
|
|
655
|
+
},
|
|
656
|
+
setExtend: {
|
|
657
|
+
value(value) {
|
|
658
|
+
this[EXTEND] = value;
|
|
659
|
+
},
|
|
660
|
+
writable: false,
|
|
661
|
+
configurable: false,
|
|
662
|
+
enumerable: false,
|
|
663
|
+
},
|
|
664
|
+
getExtend: {
|
|
665
|
+
value() {
|
|
666
|
+
return this[EXTEND]
|
|
667
|
+
},
|
|
668
|
+
writable: false,
|
|
669
|
+
configurable: false,
|
|
670
|
+
enumerable: false,
|
|
671
|
+
},
|
|
672
|
+
setLayout: {
|
|
673
|
+
value(layout) {
|
|
674
|
+
this[LAYOUT] = layout;
|
|
675
|
+
},
|
|
676
|
+
writable: false,
|
|
677
|
+
configurable: false,
|
|
678
|
+
enumerable: false,
|
|
679
|
+
},
|
|
680
|
+
getLayout: {
|
|
681
|
+
value() {
|
|
682
|
+
return this[LAYOUT]
|
|
683
|
+
},
|
|
684
|
+
writable: false,
|
|
685
|
+
configurable: false,
|
|
686
|
+
enumerable: false,
|
|
687
|
+
},
|
|
688
|
+
clone: {
|
|
689
|
+
value(exclude_blocks) {
|
|
690
|
+
const filter = [LAYOUT, EXTEND, BUFFER];
|
|
691
|
+
if (exclude_blocks === true) {
|
|
692
|
+
filter.push(BLOCKS);
|
|
693
|
+
}
|
|
694
|
+
return omit(this, filter)
|
|
695
|
+
},
|
|
696
|
+
writable: false,
|
|
697
|
+
configurable: false,
|
|
698
|
+
enumerable: false,
|
|
699
|
+
},
|
|
700
|
+
|
|
701
|
+
extend: {
|
|
702
|
+
value(layout) {
|
|
703
|
+
this.setExtend(true);
|
|
704
|
+
this.setLayout(layout);
|
|
705
|
+
},
|
|
706
|
+
writable: false,
|
|
707
|
+
configurable: false,
|
|
708
|
+
enumerable: false,
|
|
709
|
+
},
|
|
710
|
+
echo: {
|
|
711
|
+
value(layout) {
|
|
712
|
+
const buffer = this.getBuffer();
|
|
713
|
+
const params = [].slice.call(arguments);
|
|
714
|
+
params.forEach(buffer);
|
|
715
|
+
},
|
|
716
|
+
writable: false,
|
|
717
|
+
configurable: false,
|
|
718
|
+
enumerable: false,
|
|
719
|
+
},
|
|
720
|
+
fn: {
|
|
721
|
+
value(callback) {
|
|
722
|
+
const buffer = this.getBuffer();
|
|
723
|
+
const context = this;
|
|
724
|
+
return function () {
|
|
725
|
+
buffer.backup();
|
|
726
|
+
if (isFunction(callback)) {
|
|
727
|
+
callback.apply(context, arguments);
|
|
728
|
+
}
|
|
729
|
+
return buffer.restore()
|
|
730
|
+
}
|
|
731
|
+
},
|
|
732
|
+
writable: false,
|
|
733
|
+
configurable: false,
|
|
734
|
+
enumerable: false,
|
|
735
|
+
},
|
|
736
|
+
get: {
|
|
737
|
+
value(name, defaults) {
|
|
738
|
+
const path = getPath(this, name, true);
|
|
739
|
+
const result = path.shift();
|
|
740
|
+
const prop = path.pop();
|
|
741
|
+
return hasProp(result, prop) ? result[prop] : defaults
|
|
742
|
+
},
|
|
743
|
+
writable: true,
|
|
744
|
+
configurable: true,
|
|
745
|
+
enumerable: false,
|
|
746
|
+
},
|
|
747
|
+
set: {
|
|
748
|
+
value(name, value) {
|
|
749
|
+
const path = getPath(this, name, false);
|
|
750
|
+
const result = path.shift();
|
|
751
|
+
const prop = path.pop();
|
|
752
|
+
if (this.getExtend() && hasProp(result, prop)) {
|
|
753
|
+
return result[prop]
|
|
754
|
+
}
|
|
755
|
+
return (result[prop] = value)
|
|
756
|
+
},
|
|
757
|
+
writable: false,
|
|
758
|
+
configurable: false,
|
|
759
|
+
enumerable: false,
|
|
760
|
+
},
|
|
761
|
+
macro: {
|
|
762
|
+
value(name, callback) {
|
|
763
|
+
const list = this.getMacro();
|
|
764
|
+
const macro = this.fn(callback);
|
|
765
|
+
const context = this;
|
|
766
|
+
list[name] = function () {
|
|
767
|
+
return context.echo(macro.apply(undefined, arguments))
|
|
768
|
+
};
|
|
769
|
+
},
|
|
770
|
+
writable: false,
|
|
771
|
+
configurable: false,
|
|
772
|
+
enumerable: false,
|
|
773
|
+
},
|
|
774
|
+
call: {
|
|
775
|
+
value(name) {
|
|
776
|
+
const list = this.getMacro();
|
|
777
|
+
const macro = list[name];
|
|
778
|
+
const params = [].slice.call(arguments, 1);
|
|
779
|
+
if (isFunction(macro)) {
|
|
780
|
+
return macro.apply(macro, params)
|
|
781
|
+
}
|
|
782
|
+
},
|
|
783
|
+
writable: false,
|
|
784
|
+
configurable: false,
|
|
785
|
+
enumerable: false,
|
|
786
|
+
},
|
|
787
|
+
block: {
|
|
788
|
+
value(name, callback) {
|
|
789
|
+
const blocks = this.getBlocks();
|
|
790
|
+
blocks[name] = blocks[name] || [];
|
|
791
|
+
blocks[name].push(this.fn(callback));
|
|
792
|
+
if (this.getExtend()) return
|
|
793
|
+
const list = Object.assign([], blocks[name]);
|
|
794
|
+
const current = function () {
|
|
795
|
+
return list.shift()
|
|
796
|
+
};
|
|
797
|
+
const next = () => {
|
|
798
|
+
const parent = current();
|
|
799
|
+
if (parent) {
|
|
800
|
+
return () => {
|
|
801
|
+
this.echo(parent(next()));
|
|
802
|
+
}
|
|
803
|
+
} else {
|
|
804
|
+
return noop
|
|
805
|
+
}
|
|
806
|
+
};
|
|
807
|
+
this.echo(current()(next()));
|
|
808
|
+
},
|
|
809
|
+
writable: false,
|
|
810
|
+
configurable: false,
|
|
811
|
+
enumerable: false,
|
|
812
|
+
},
|
|
813
|
+
include: {
|
|
814
|
+
value(path, data, cx) {
|
|
815
|
+
const context = cx === false ? {} : this.clone(true);
|
|
816
|
+
const params = extend(context, data || {});
|
|
817
|
+
const promise = this.render(path, params);
|
|
818
|
+
this.echo(promise);
|
|
819
|
+
},
|
|
820
|
+
writable: false,
|
|
821
|
+
configurable: false,
|
|
822
|
+
enumerable: false,
|
|
823
|
+
},
|
|
824
|
+
use: {
|
|
825
|
+
value(path, namespace) {
|
|
826
|
+
const promise = this.require(path);
|
|
827
|
+
this.echo(
|
|
828
|
+
resolve$1(
|
|
829
|
+
promise,
|
|
830
|
+
function (exports) {
|
|
831
|
+
const list = this.getMacro();
|
|
832
|
+
each(exports, function (macro, name) {
|
|
833
|
+
list[[namespace, name].join('.')] = macro;
|
|
834
|
+
});
|
|
835
|
+
},
|
|
836
|
+
this
|
|
837
|
+
)
|
|
838
|
+
);
|
|
839
|
+
},
|
|
840
|
+
writable: false,
|
|
841
|
+
configurable: false,
|
|
842
|
+
enumerable: false,
|
|
843
|
+
},
|
|
844
|
+
async: {
|
|
845
|
+
value(promise, callback) {
|
|
846
|
+
this.echo(
|
|
847
|
+
resolve$1(
|
|
848
|
+
promise,
|
|
849
|
+
function (data) {
|
|
850
|
+
return this.fn(callback)(data)
|
|
851
|
+
},
|
|
852
|
+
this
|
|
853
|
+
)
|
|
854
|
+
);
|
|
855
|
+
},
|
|
856
|
+
writable: false,
|
|
857
|
+
configurable: false,
|
|
858
|
+
enumerable: false,
|
|
859
|
+
},
|
|
860
|
+
each: {
|
|
861
|
+
value: function (object, callback) {
|
|
862
|
+
if (isString(object)) {
|
|
863
|
+
object = this.get(object, []);
|
|
864
|
+
}
|
|
865
|
+
each(object, callback);
|
|
866
|
+
},
|
|
867
|
+
writable: false,
|
|
868
|
+
configurable: false,
|
|
869
|
+
enumerable: false,
|
|
870
|
+
},
|
|
871
|
+
element: {
|
|
872
|
+
value(tag, attr, content) {
|
|
873
|
+
return element(tag, attr, content)
|
|
874
|
+
},
|
|
875
|
+
writable: false,
|
|
876
|
+
configurable: false,
|
|
877
|
+
enumerable: false,
|
|
878
|
+
},
|
|
879
|
+
el: {
|
|
880
|
+
value(tag, attr, content) {
|
|
881
|
+
if (isFunction(content)) {
|
|
882
|
+
content = this.fn(content)();
|
|
883
|
+
}
|
|
884
|
+
this.echo(
|
|
885
|
+
resolve$1(
|
|
886
|
+
content,
|
|
887
|
+
function (content) {
|
|
888
|
+
return this.element(tag, attr, content)
|
|
889
|
+
},
|
|
890
|
+
this
|
|
891
|
+
)
|
|
892
|
+
);
|
|
893
|
+
},
|
|
894
|
+
writable: false,
|
|
895
|
+
configurable: false,
|
|
896
|
+
enumerable: false,
|
|
897
|
+
},
|
|
898
|
+
});
|
|
899
|
+
};
|
|
900
|
+
this.configure(config);
|
|
901
|
+
}
|
|
902
|
+
|
|
903
|
+
function EJS(options) {
|
|
904
|
+
if (instanceOf(this, EJS) === false) return new EJS(options)
|
|
905
|
+
|
|
906
|
+
const scope = {};
|
|
907
|
+
const config = {};
|
|
908
|
+
|
|
909
|
+
configSchema(config, options || {});
|
|
910
|
+
|
|
911
|
+
const context = new Context(config);
|
|
912
|
+
const compiler = new Compiler(config);
|
|
913
|
+
const cache = new Cache();
|
|
914
|
+
const template = new Template(config, cache, compiler);
|
|
915
|
+
|
|
916
|
+
const output = (path, scope) => {
|
|
917
|
+
const { globalHelpers } = config;
|
|
918
|
+
const params = [
|
|
919
|
+
scope,
|
|
920
|
+
scope.getComponent(),
|
|
921
|
+
scope.getBuffer(),
|
|
922
|
+
safeValue,
|
|
923
|
+
].concat(
|
|
924
|
+
globalHelpers
|
|
925
|
+
.filter((name) => isFunction(scope[name]))
|
|
926
|
+
.map((name) => scope[name].bind(scope))
|
|
927
|
+
);
|
|
928
|
+
return template
|
|
929
|
+
.get(path)
|
|
930
|
+
.then((callback) => callback.apply(scope, params))
|
|
931
|
+
};
|
|
932
|
+
|
|
933
|
+
const require = (name) => {
|
|
934
|
+
const filepath = ext(name, config.extension);
|
|
935
|
+
const scope = context.create({});
|
|
936
|
+
return output(filepath, scope).then(() => scope.getMacro())
|
|
937
|
+
};
|
|
938
|
+
const render = (name, data) => {
|
|
939
|
+
const filepath = ext(name, config.extension);
|
|
940
|
+
const scope = context.create(data);
|
|
941
|
+
return output(filepath, scope).then((content) => {
|
|
942
|
+
if (scope.getExtend()) {
|
|
943
|
+
scope.setExtend(false);
|
|
944
|
+
const layout = scope.getLayout();
|
|
945
|
+
const data = scope.clone();
|
|
946
|
+
return render(layout, data)
|
|
947
|
+
}
|
|
948
|
+
return content
|
|
949
|
+
})
|
|
950
|
+
};
|
|
951
|
+
this.configure = function (options) {
|
|
952
|
+
options = options || {};
|
|
953
|
+
configSchema(config, options);
|
|
954
|
+
context.configure(config, scope);
|
|
955
|
+
compiler.configure(config);
|
|
956
|
+
cache.configure(config);
|
|
957
|
+
template.configure(config);
|
|
958
|
+
return config
|
|
959
|
+
};
|
|
960
|
+
this.render = function (name, data) {
|
|
961
|
+
return render(name, data)
|
|
962
|
+
};
|
|
963
|
+
this.helpers = function (methods) {
|
|
964
|
+
context.helpers(extend(scope, methods));
|
|
965
|
+
};
|
|
966
|
+
this.preload = function (list) {
|
|
967
|
+
return cache.load(list || {})
|
|
968
|
+
};
|
|
969
|
+
this.create = function (options) {
|
|
970
|
+
return new EJS(options)
|
|
971
|
+
};
|
|
972
|
+
this.compile = function (content, path) {
|
|
973
|
+
return compiler.compile(content, path)
|
|
974
|
+
};
|
|
975
|
+
this.context = function (data) {
|
|
976
|
+
return context.create(data)
|
|
977
|
+
};
|
|
978
|
+
this.helpers({ require, render });
|
|
979
|
+
return this
|
|
980
|
+
}
|
|
981
|
+
|
|
982
|
+
const templateCache = {};
|
|
983
|
+
|
|
984
|
+
const ejs = new EJS({
|
|
985
|
+
cache: false,
|
|
986
|
+
withObject: false,
|
|
987
|
+
resolver(path, name) {
|
|
988
|
+
return new Promise((resolve, reject) => {
|
|
989
|
+
if (templateCache.hasOwnProperty(name)) {
|
|
990
|
+
resolve(templateCache[name]);
|
|
991
|
+
} else {
|
|
992
|
+
reject(new TemplateNotFound(`template ${name} not found`));
|
|
993
|
+
}
|
|
994
|
+
})
|
|
995
|
+
},
|
|
996
|
+
});
|
|
997
|
+
|
|
998
|
+
const getOrigin = (url, secure) => {
|
|
999
|
+
url = new URL(url);
|
|
1000
|
+
if (secure) url.protocol = 'https:';
|
|
1001
|
+
return url.origin
|
|
1002
|
+
};
|
|
1003
|
+
|
|
1004
|
+
function setTemplates(list) {
|
|
1005
|
+
Object.assign(templateCache, list || {});
|
|
1006
|
+
}
|
|
1007
|
+
|
|
1008
|
+
/**
|
|
1009
|
+
* @typedef {Object<string,any>} HonoContext
|
|
1010
|
+
* @property {function(*):Promise<Response>} html
|
|
1011
|
+
* @property {function(name:string,data:{}):Promise<string>} render
|
|
1012
|
+
* @property {function(name:string,data:{}):Promise<string>} ejs
|
|
1013
|
+
* @property {ContextScope} data
|
|
1014
|
+
*/
|
|
1015
|
+
|
|
1016
|
+
/**
|
|
1017
|
+
*
|
|
1018
|
+
* @param {Object<string,any>} options
|
|
1019
|
+
* @return {(function(c:Context, next): Promise<any>)|*}
|
|
1020
|
+
*/
|
|
1021
|
+
function setRenderer({ secure = true, version = '1.0' }) {
|
|
1022
|
+
return async (c, next) => {
|
|
1023
|
+
c.data = context({});
|
|
1024
|
+
c.data.set('version', version);
|
|
1025
|
+
c.data.set('origin', getOrigin(c.req.url, secure));
|
|
1026
|
+
c.ejs = (name, data) => render(name, Object.assign({}, c.data, data));
|
|
1027
|
+
c.render = (name, data) => c.html(c.ejs(name, data));
|
|
1028
|
+
await next();
|
|
1029
|
+
}
|
|
1030
|
+
}
|
|
1031
|
+
|
|
1032
|
+
const { render, context, compile, helpers, preload, configure, create } = ejs;
|
|
1033
|
+
|
|
1034
|
+
export { compile, configure, context, create, helpers, preload, render, setRenderer, setTemplates };
|