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