@kosatyi/ejs 0.0.113 → 0.0.115

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.
@@ -0,0 +1,785 @@
1
+ import { t as typeProp, f as isArrayOfVariables, g as isArray, d as isBoolean, c as isString, i as isFunction, b as bindContext, s as symbols, e as element, h as each, k as getPath, l as hasProp, o as omit, a as escapeValue } from './element-CEdJaM42.js';
2
+
3
+ /**
4
+ * @type {EjsConfig}
5
+ */
6
+ const ejsDefaults = {
7
+ precompiled: 'ejsPrecompiled',
8
+ cache: true,
9
+ path: 'views',
10
+ extension: 'ejs',
11
+ rmWhitespace: true,
12
+ strict: true,
13
+ resolver: (path, template) => {
14
+ return Promise.resolve(
15
+ ['resolver is not defined', path, template].join(' '),
16
+ )
17
+ },
18
+ globals: [],
19
+ vars: {
20
+ SCOPE: 'ejs',
21
+ COMPONENT: 'ui',
22
+ ELEMENT: 'el',
23
+ EXTEND: '$$e',
24
+ BUFFER: '$$a',
25
+ LAYOUT: '$$l',
26
+ BLOCKS: '$$b',
27
+ MACRO: '$$m',
28
+ SAFE: '$$v',
29
+ },
30
+ token: {
31
+ start: '<%',
32
+ end: '%>',
33
+ regex: '([\\s\\S]+?)',
34
+ },
35
+ };
36
+
37
+ const configSchema = (config, options) => {
38
+ return Object.assign(config, {
39
+ path: typeProp(isString, ejsDefaults.path, config.path, options.path),
40
+ precompiled: typeProp(
41
+ isString,
42
+ ejsDefaults.precompiled,
43
+ config.export,
44
+ options.export,
45
+ ),
46
+ resolver: typeProp(
47
+ isFunction,
48
+ ejsDefaults.resolver,
49
+ config.resolver,
50
+ options.resolver,
51
+ ),
52
+ extension: typeProp(
53
+ isString,
54
+ ejsDefaults.extension,
55
+ config.extension,
56
+ options.extension,
57
+ ),
58
+ strict: typeProp(
59
+ isBoolean,
60
+ ejsDefaults.strict,
61
+ config.strict,
62
+ options.strict,
63
+ ),
64
+ rmWhitespace: typeProp(
65
+ isBoolean,
66
+ ejsDefaults.rmWhitespace,
67
+ config.rmWhitespace,
68
+ options.rmWhitespace,
69
+ ),
70
+ cache: typeProp(
71
+ isBoolean,
72
+ ejsDefaults.cache,
73
+ config.cache,
74
+ options.cache,
75
+ ),
76
+ globals: typeProp(
77
+ isArray,
78
+ ejsDefaults.globals,
79
+ config.globals,
80
+ isArrayOfVariables(options.globals),
81
+ ),
82
+ token: Object.assign(
83
+ {},
84
+ ejsDefaults.token,
85
+ config.token,
86
+ options.token,
87
+ ),
88
+ vars: Object.assign({}, ejsDefaults.vars, config.vars, options.vars),
89
+ })
90
+ };
91
+
92
+ class EjsError extends Error {
93
+ constructor(code, content) {
94
+ super(content);
95
+ this.code = code;
96
+ if (content instanceof Error) {
97
+ this.stack = content.stack;
98
+ this.message = content.message;
99
+ }
100
+ }
101
+ }
102
+
103
+ const error = (code, content) => {
104
+ throw new EjsError(code, content)
105
+ };
106
+
107
+ class EjsTemplate {
108
+ #path
109
+ #resolver
110
+ #cache
111
+ #compiler
112
+ static exports = ['configure', 'get']
113
+ constructor(options, cache, compiler) {
114
+ bindContext(this, this.constructor.exports);
115
+ this.#cache = cache;
116
+ this.#compiler = compiler;
117
+ this.configure(options ?? {});
118
+ }
119
+ configure(options) {
120
+ this.#path = options.path;
121
+ if (isFunction(options.resolver)) {
122
+ this.#resolver = options.resolver;
123
+ }
124
+ }
125
+ #resolve(template) {
126
+ const cached = this.#cache.get(template);
127
+ if (cached instanceof Promise) return cached
128
+ const result = Promise.resolve(
129
+ this.#resolver(this.#path, template, error),
130
+ );
131
+ this.#cache.set(template, result);
132
+ return result
133
+ }
134
+ #compile(content, template) {
135
+ const cached = this.#cache.get(template);
136
+ if (typeof cached === 'function') return cached
137
+ if (typeof content === 'string') {
138
+ content = this.#compiler.compile(content, template);
139
+ }
140
+ if (typeof content === 'function') {
141
+ this.#cache.set(template, content);
142
+ return content
143
+ }
144
+ }
145
+ get(template) {
146
+ return this.#resolve(template).then((content) => {
147
+ return this.#compile(content, template)
148
+ })
149
+ }
150
+ }
151
+
152
+ const tokenList = [
153
+ ['-', (v, b, s) => `')\n${b}(${s}(${v},1))\n${b}('`],
154
+ ['=', (v, b, s) => `')\n${b}(${s}(${v}))\n${b}('`],
155
+ ['#', (v, b) => `')\n/**${v}**/\n${b}('`],
156
+ ['', (v, b) => `')\n${v}\n${b}('`],
157
+ ];
158
+
159
+ const tokensMatch = (regex, content, callback) => {
160
+ let index = 0;
161
+ content.replace(regex, function () {
162
+ const params = [].slice.call(arguments, 0, -1);
163
+ const offset = params.pop();
164
+ const match = params.shift();
165
+ callback(params, index, offset);
166
+ index = offset + match.length;
167
+ return match
168
+ });
169
+ };
170
+
171
+ class EjsCompiler {
172
+ #config = {}
173
+ static exports = ['configure', 'compile']
174
+ constructor(options) {
175
+ bindContext(this, this.constructor.exports);
176
+ this.configure(options);
177
+ }
178
+ configure(options) {
179
+ this.#config.strict = options.strict;
180
+ this.#config.rmWhitespace = options.rmWhitespace;
181
+ this.#config.token = options.token;
182
+ this.#config.vars = options.vars;
183
+ this.#config.globals = options.globals;
184
+ this.#config.legacy = options.legacy ?? true;
185
+ this.#config.slurp = {
186
+ match: '[s\t\n]*',
187
+ start: [this.#config.token.start, '_'],
188
+ end: ['_', this.#config.token.end],
189
+ };
190
+ this.#config.matches = [];
191
+ this.#config.formats = [];
192
+ for (const [symbol, format] of tokenList) {
193
+ this.#config.matches.push(
194
+ this.#config.token.start
195
+ .concat(symbol)
196
+ .concat(this.#config.token.regex)
197
+ .concat(this.#config.token.end),
198
+ );
199
+ this.#config.formats.push(format);
200
+ }
201
+ this.#config.regex = new RegExp(
202
+ this.#config.matches.join('|').concat('|$'),
203
+ 'g',
204
+ );
205
+ this.#config.slurpStart = new RegExp(
206
+ [this.#config.slurp.match, this.#config.slurp.start.join('')].join(
207
+ '',
208
+ ),
209
+ 'gm',
210
+ );
211
+ this.#config.slurpEnd = new RegExp(
212
+ [this.#config.slurp.end.join(''), this.#config.slurp.match].join(
213
+ '',
214
+ ),
215
+ 'gm',
216
+ );
217
+ if (this.#config.globals.length) {
218
+ if (this.#config.legacy) {
219
+ this.#config.globalVariables = `const ${this.#config.globals
220
+ .map((name) => `${name}=${this.#config.vars.SCOPE}.${name}`)
221
+ .join(',')};`;
222
+ } else {
223
+ this.#config.globalVariables = `const {${this.#config.globals.join(',')}} = ${this.#config.vars.SCOPE};`;
224
+ }
225
+ }
226
+ }
227
+ compile(content, path) {
228
+ const GLOBALS = this.#config.globalVariables;
229
+ const { SCOPE, SAFE, BUFFER, COMPONENT, ELEMENT } = this.#config.vars;
230
+ if (this.#config.rmWhitespace) {
231
+ content = String(content)
232
+ .replace(/[\r\n]+/g, '\n')
233
+ .replace(/^\s+|\s+$/gm, '');
234
+ }
235
+ content = String(content)
236
+ .replace(this.#config.slurpStart, this.#config.token.start)
237
+ .replace(this.#config.slurpEnd, this.#config.token.end);
238
+ let OUTPUT = `${BUFFER}('`;
239
+ tokensMatch(this.#config.regex, content, (params, index, offset) => {
240
+ OUTPUT += symbols(content.slice(index, offset));
241
+ params.forEach((value, index) => {
242
+ if (value) {
243
+ OUTPUT += this.#config.formats[index](
244
+ value.trim(),
245
+ BUFFER,
246
+ SAFE,
247
+ );
248
+ }
249
+ });
250
+ });
251
+ OUTPUT += `');`;
252
+ OUTPUT = `try{${OUTPUT}}catch(e){return ${BUFFER}.error(e)}`;
253
+ if (this.#config.strict === false) {
254
+ OUTPUT = `with(${SCOPE}){${OUTPUT}}`;
255
+ }
256
+ OUTPUT = `${BUFFER}.start();${OUTPUT}return ${BUFFER}.end();`;
257
+ OUTPUT += `\n//# sourceURL=${path}`;
258
+ if (GLOBALS) {
259
+ OUTPUT = `${GLOBALS}\n${OUTPUT}`;
260
+ }
261
+ try {
262
+ const params = [SCOPE, COMPONENT, ELEMENT, BUFFER, SAFE];
263
+ const result = Function.apply(null, params.concat(OUTPUT));
264
+ result.source = `(function(${params.join(',')}){\n${OUTPUT}\n});`;
265
+ return result
266
+ } catch (e) {
267
+ e.filename = path;
268
+ e.source = OUTPUT;
269
+ error(0, e);
270
+ }
271
+ }
272
+ }
273
+
274
+ class EjsCache {
275
+ static exports = [
276
+ 'load',
277
+ 'set',
278
+ 'get',
279
+ 'exist',
280
+ 'clear',
281
+ 'remove',
282
+ 'resolve',
283
+ ]
284
+ #cache = true
285
+ #precompiled
286
+ #list = {}
287
+ constructor(options) {
288
+ bindContext(this, this.constructor.exports);
289
+ this.configure(options);
290
+ }
291
+ get(key) {
292
+ if (this.#cache) {
293
+ return this.#list[key]
294
+ }
295
+ }
296
+ set(key, value) {
297
+ if (this.#cache) {
298
+ this.#list[key] = value;
299
+ }
300
+ }
301
+ exist(key) {
302
+ if (this.#cache) {
303
+ return this.#list.hasOwnProperty(key)
304
+ }
305
+ }
306
+ clear() {
307
+ Object.keys(this.#list).forEach(this.remove);
308
+ }
309
+ remove(key) {
310
+ delete this.#list[key];
311
+ }
312
+ resolve(key) {
313
+ return Promise.resolve(this.get(key))
314
+ }
315
+ load(data) {
316
+ if (this.#cache) {
317
+ Object.assign(this.#list, data || {});
318
+ }
319
+ }
320
+ configure(options) {
321
+ this.#cache = options.cache;
322
+ this.#precompiled = options.precompiled;
323
+ if (typeof window === 'object') {
324
+ this.load(window[this.#precompiled]);
325
+ }
326
+ }
327
+ }
328
+
329
+ const resolve = (list) => {
330
+ return Promise.all(list || [])
331
+ .then((list) => list.join(''))
332
+ .catch((e) => error(0, e))
333
+ };
334
+
335
+ const reject = (e) => {
336
+ return Promise.reject(error(0, e))
337
+ };
338
+
339
+ const EjsBuffer = () => {
340
+ let store = [];
341
+ let array = [];
342
+ /**
343
+ *
344
+ * @param value
345
+ * @constructor
346
+ */
347
+ const EjsBuffer = (value) => {
348
+ array.push(value);
349
+ };
350
+ EjsBuffer.start = () => {
351
+ array = [];
352
+ };
353
+ EjsBuffer.backup = () => {
354
+ store.push(array.concat());
355
+ array = [];
356
+ };
357
+ EjsBuffer.restore = () => {
358
+ const result = array.concat();
359
+ array = store.pop();
360
+ return resolve(result)
361
+ };
362
+ EjsBuffer.error = (e) => {
363
+ return reject(e)
364
+ };
365
+ EjsBuffer.end = () => {
366
+ return resolve(array)
367
+ };
368
+ return EjsBuffer
369
+ };
370
+
371
+ const PARENT = Symbol('EjsContext.parentTemplate');
372
+
373
+ const createContext = (config, methods) => {
374
+ const globals = config.globals || [];
375
+ const {
376
+ BLOCKS,
377
+ MACRO,
378
+ EXTEND,
379
+ LAYOUT,
380
+ BUFFER,
381
+ SAFE,
382
+ SCOPE,
383
+ COMPONENT,
384
+ ELEMENT,
385
+ } = config.vars;
386
+ class Context {
387
+ constructor(data) {
388
+ this[PARENT] = null;
389
+ this[BLOCKS] = {};
390
+ this[MACRO] = {};
391
+ Object.assign(
392
+ this,
393
+ omit(data, [SCOPE, BUFFER, SAFE, COMPONENT, ELEMENT]),
394
+ );
395
+ }
396
+ }
397
+ Object.defineProperties(Context.prototype, {
398
+ [BUFFER]: {
399
+ value: EjsBuffer(),
400
+ },
401
+ [BLOCKS]: {
402
+ value: {},
403
+ writable: true,
404
+ },
405
+ [MACRO]: {
406
+ value: {},
407
+ writable: true,
408
+ },
409
+ [LAYOUT]: {
410
+ value: false,
411
+ writable: true,
412
+ },
413
+ [EXTEND]: {
414
+ value: false,
415
+ writable: true,
416
+ },
417
+ [PARENT]: {
418
+ value: null,
419
+ writable: true,
420
+ },
421
+ setParentTemplate: {
422
+ value(value) {
423
+ this[PARENT] = value;
424
+ return this
425
+ },
426
+ },
427
+ getParentTemplate: {
428
+ value() {
429
+ return this[PARENT]
430
+ },
431
+ },
432
+ useEscapeValue: {
433
+ value() {
434
+ return escapeValue
435
+ },
436
+ },
437
+ useComponent: {
438
+ value() {
439
+ if (isFunction(this[COMPONENT])) {
440
+ return this[COMPONENT].bind(this)
441
+ } else {
442
+ return function () {
443
+ error(2, `${COMPONENT} must be a function`);
444
+ }
445
+ }
446
+ },
447
+ },
448
+ useElement: {
449
+ value() {
450
+ if (isFunction(this[ELEMENT])) {
451
+ return this[ELEMENT].bind(this)
452
+ } else {
453
+ return () => {
454
+ error(2, `${ELEMENT} must be a function`);
455
+ }
456
+ }
457
+ },
458
+ },
459
+ useBuffer: {
460
+ value() {
461
+ return this[BUFFER]
462
+ },
463
+ },
464
+ getMacro: {
465
+ value() {
466
+ return this[MACRO]
467
+ },
468
+ },
469
+ getBlocks: {
470
+ value() {
471
+ return this[BLOCKS]
472
+ },
473
+ },
474
+ setExtend: {
475
+ value(value) {
476
+ this[EXTEND] = value;
477
+ return this
478
+ },
479
+ },
480
+ getExtend: {
481
+ value() {
482
+ return this[EXTEND]
483
+ },
484
+ },
485
+ setLayout: {
486
+ value(layout) {
487
+ this[LAYOUT] = layout;
488
+ return this
489
+ },
490
+ },
491
+ getLayout: {
492
+ value() {
493
+ return this[LAYOUT]
494
+ },
495
+ },
496
+ clone: {
497
+ value(exclude_blocks) {
498
+ const filter = [LAYOUT, EXTEND, BUFFER];
499
+ if (exclude_blocks === true) {
500
+ filter.push(BLOCKS);
501
+ }
502
+ return omit(this, filter)
503
+ },
504
+ },
505
+ extend: {
506
+ value(layout) {
507
+ this.setExtend(true);
508
+ this.setLayout(layout);
509
+ },
510
+ },
511
+ echo: {
512
+ value() {
513
+ return [].slice.call(arguments).forEach(this.useBuffer())
514
+ },
515
+ },
516
+ fn: {
517
+ value(callback) {
518
+ const buffer = this.useBuffer();
519
+ const context = this;
520
+ return function () {
521
+ if (isFunction(callback)) {
522
+ buffer.backup();
523
+ buffer(callback.apply(context, arguments));
524
+ return buffer.restore()
525
+ }
526
+ }
527
+ },
528
+ },
529
+ macro: {
530
+ value(name, callback) {
531
+ const list = this.getMacro();
532
+ const macro = this.fn(callback);
533
+ const context = this;
534
+ list[name] = function () {
535
+ return context.echo(macro.apply(undefined, arguments))
536
+ };
537
+ },
538
+ },
539
+ call: {
540
+ value(name) {
541
+ const list = this.getMacro();
542
+ const macro = list[name];
543
+ const params = [].slice.call(arguments, 1);
544
+ if (isFunction(macro)) {
545
+ return macro.apply(macro, params)
546
+ }
547
+ },
548
+ },
549
+ block: {
550
+ value(name, callback) {
551
+ const blocks = this.getBlocks();
552
+ blocks[name] = blocks[name] || [];
553
+ blocks[name].push(this.fn(callback));
554
+ if (this.getExtend()) return
555
+ const context = this;
556
+ const list = Object.assign([], blocks[name]);
557
+ const shift = function () {
558
+ return list.shift()
559
+ };
560
+ const next = function () {
561
+ const parent = shift();
562
+ if (parent) {
563
+ return function () {
564
+ context.echo(parent(next()));
565
+ }
566
+ } else {
567
+ return function () {}
568
+ }
569
+ };
570
+ this.echo(shift()(next()));
571
+ },
572
+ },
573
+ hasBlock: {
574
+ value(name) {
575
+ return this.getBlocks().hasOwnProperty(name)
576
+ },
577
+ },
578
+ include: {
579
+ value(path, data, cx) {
580
+ const context = cx === false ? {} : this.clone(true);
581
+ const params = Object.assign(context, data || {});
582
+ const promise = this.render(path, params);
583
+ this.echo(promise);
584
+ },
585
+ },
586
+ use: {
587
+ value(path, namespace) {
588
+ this.echo(
589
+ Promise.resolve(this.require(path)).then((exports$1) => {
590
+ const list = this.getMacro();
591
+ each(exports$1, (macro, name) => {
592
+ list[[namespace, name].join('.')] = macro;
593
+ });
594
+ }),
595
+ );
596
+ },
597
+ },
598
+ get: {
599
+ value(name, defaults) {
600
+ const path = getPath(this, name, true);
601
+ const result = path.shift();
602
+ const prop = path.pop();
603
+ return hasProp(result, prop) ? result[prop] : defaults
604
+ },
605
+ },
606
+ set: {
607
+ value(name, value) {
608
+ const path = getPath(this, name, false);
609
+ const result = path.shift();
610
+ const prop = path.pop();
611
+ if (this.getParentTemplate() && hasProp(result, prop)) {
612
+ return result[prop]
613
+ }
614
+ return (result[prop] = value)
615
+ },
616
+ },
617
+ each: {
618
+ value(object, callback) {
619
+ if (isString(object)) {
620
+ object = this.get(object, []);
621
+ }
622
+ each(object, callback);
623
+ },
624
+ writable: true,
625
+ },
626
+ el: {
627
+ value(tag, attr, content) {
628
+ content = isFunction(content) ? this.fn(content)() : content;
629
+ this.echo(
630
+ Promise.resolve(content).then((content) =>
631
+ element(tag, attr, content),
632
+ ),
633
+ );
634
+ },
635
+ writable: true,
636
+ },
637
+ ui: {
638
+ value() {},
639
+ writable: true,
640
+ },
641
+ require: {
642
+ value() {},
643
+ writable: true,
644
+ },
645
+ render: {
646
+ value() {},
647
+ writable: true,
648
+ },
649
+ });
650
+ Object.entries(methods).forEach(([name, value]) => {
651
+ if (isFunction(value) && globals.includes(name)) {
652
+ value = value.bind(Context.prototype);
653
+ }
654
+ Context.prototype[name] = value;
655
+ });
656
+ return Context
657
+ };
658
+
659
+ class EjsContext {
660
+ #context
661
+ static exports = ['create', 'globals', 'helpers']
662
+ constructor(options, methods) {
663
+ bindContext(this, this.constructor.exports);
664
+ this.configure(options, methods);
665
+ }
666
+ create(data) {
667
+ return new this.#context(data)
668
+ }
669
+ helpers(methods) {
670
+ Object.assign(this.#context.prototype, methods);
671
+ }
672
+ configure(options, methods) {
673
+ this.#context = createContext(options, methods);
674
+ }
675
+ }
676
+
677
+ class EjsInstance {
678
+ #cache
679
+ #context
680
+ #compiler
681
+ #template
682
+ #config = {}
683
+ #methods = {}
684
+ static exports = [
685
+ 'configure',
686
+ 'create',
687
+ 'createContext',
688
+ 'render',
689
+ 'require',
690
+ 'preload',
691
+ 'compile',
692
+ 'helpers',
693
+ ]
694
+ /**
695
+ *
696
+ * @param {EjsConfig} options
697
+ */
698
+ constructor(options = {}) {
699
+ bindContext(this, this.constructor.exports);
700
+ this.#methods = {};
701
+ this.#config = configSchema({}, options);
702
+ this.#context = new EjsContext(this.#config, this.#methods);
703
+ this.#compiler = new EjsCompiler(this.#config);
704
+ this.#cache = new EjsCache(this.#config);
705
+ this.#template = new EjsTemplate(
706
+ this.#config,
707
+ this.#cache,
708
+ this.#compiler,
709
+ );
710
+ this.helpers({ render: this.render, require: this.require });
711
+ }
712
+ create(options) {
713
+ return new this.constructor(options)
714
+ }
715
+ configure(options) {
716
+ if (options) {
717
+ configSchema(this.#config, options);
718
+ this.#context.configure(this.#config, this.#methods);
719
+ this.#compiler.configure(this.#config);
720
+ this.#cache.configure(this.#config);
721
+ this.#template.configure(this.#config);
722
+ }
723
+ return this.#config
724
+ }
725
+ createContext(data) {
726
+ return this.#context.create(data)
727
+ }
728
+ preload(list) {
729
+ return this.#cache.load(list || {})
730
+ }
731
+ compile(content, path) {
732
+ return this.#compiler.compile(content, path)
733
+ }
734
+ helpers(methods) {
735
+ this.#context.helpers(Object.assign(this.#methods, methods));
736
+ }
737
+ async render(name, params) {
738
+ const data = this.createContext(params);
739
+ return this.#output(this.#path(name), data).then(
740
+ this.#outputContent(name, data),
741
+ )
742
+ }
743
+ async require(name) {
744
+ const data = this.createContext({});
745
+ return this.#output(this.#path(name), data).then(() => data.getMacro())
746
+ }
747
+ #path(name) {
748
+ const ext = name.split('.').pop();
749
+ if (ext !== this.#config.extension) {
750
+ name = [name, this.#config.extension].join('.');
751
+ }
752
+ return name
753
+ }
754
+ #output(path, data) {
755
+ return this.#template
756
+ .get(path)
757
+ .then((callback) =>
758
+ callback.apply(data, [
759
+ data,
760
+ data.useComponent(),
761
+ data.useElement(),
762
+ data.useBuffer(),
763
+ data.useEscapeValue(),
764
+ ]),
765
+ )
766
+ }
767
+ #renderLayout(name, params, parentTemplate) {
768
+ const data = this.createContext(params);
769
+ if (parentTemplate) data.setParentTemplate(parentTemplate);
770
+ return this.#output(this.#path(name), data).then(
771
+ this.#outputContent(name, data),
772
+ )
773
+ }
774
+ #outputContent(name, data) {
775
+ return (content) => {
776
+ if (data.getExtend()) {
777
+ data.setExtend(false);
778
+ return this.#renderLayout(data.getLayout(), data, name)
779
+ }
780
+ return content
781
+ }
782
+ }
783
+ }
784
+
785
+ export { EjsInstance as E, ejsDefaults as e };