@kosatyi/ejs 0.0.97 → 0.0.98

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/dist/esm/index.js CHANGED
@@ -1,5 +1,5 @@
1
- import fs from 'fs';
2
- import path from 'path';
1
+ import fs from 'node:fs';
2
+ import path from 'node:path';
3
3
 
4
4
  const typeProp = function () {
5
5
  const args = [].slice.call(arguments);
@@ -60,13 +60,22 @@ const symbols = (string) => {
60
60
 
61
61
  const safeValue = (value, escape) => {
62
62
  const check = value;
63
- return check == null ? '' : Boolean(escape) === true ? entities(check) : check
63
+ return check == null
64
+ ? ''
65
+ : Boolean(escape) === true
66
+ ? entities(check)
67
+ : check
64
68
  };
65
69
 
66
70
  const instanceOf = (object, instance) => {
67
71
  return Boolean(object instanceof instance)
68
72
  };
69
73
 
74
+ const assertInstanceOf = (object, instance) => {
75
+ if (instanceOf(object, instance) === false)
76
+ throw new TypeError(`${object} in not instance of ${instance}`)
77
+ };
78
+
70
79
  const getPath = (context, name, strict) => {
71
80
  let data = context;
72
81
  let chunks = String(name).split('.');
@@ -88,6 +97,14 @@ const getPath = (context, name, strict) => {
88
97
  return [data, prop]
89
98
  };
90
99
 
100
+ const bindContext = (object, methods = []) => {
101
+ methods.forEach((name) => {
102
+ if (name in object) {
103
+ object[name] = object[name].bind(object);
104
+ }
105
+ });
106
+ };
107
+
91
108
  const ext = (path, defaults) => {
92
109
  const ext = path.split('.').pop();
93
110
  if (ext !== defaults) {
@@ -155,6 +172,12 @@ const omit = (object, list) => {
155
172
  })
156
173
  };
157
174
 
175
+ /**
176
+ *
177
+ * @param object
178
+ * @param prop
179
+ * @return {boolean}
180
+ */
158
181
  const hasProp = (object, prop) => {
159
182
  return object && object.hasOwnProperty(prop)
160
183
  };
@@ -165,6 +188,18 @@ const joinPath = (path, template) => {
165
188
  return template
166
189
  };
167
190
 
191
+ const matchTokens = (regex, text, callback) => {
192
+ let index = 0;
193
+ text.replace(regex, function () {
194
+ const params = [].slice.call(arguments, 0, -1);
195
+ const offset = params.pop();
196
+ const match = params.shift();
197
+ callback(params, index, offset);
198
+ index = offset + match.length;
199
+ return match
200
+ });
201
+ };
202
+
168
203
  const defaults = {};
169
204
 
170
205
  defaults.export = 'ejsPrecompiled';
@@ -243,153 +278,142 @@ const configSchema = (config, options) => {
243
278
 
244
279
  const global = typeof globalThis !== 'undefined' ? globalThis : window || self;
245
280
 
246
- function Cache(config) {
247
- if (instanceOf(this, Cache) === false) return new Cache()
248
- const cache = {
249
- enabled: true,
250
- list: {},
251
- };
252
- this.configure = function (config) {
253
- cache.enabled = config.cache;
254
- if (isNode() === false) {
255
- this.load(global[config.export]);
256
- }
257
- };
258
- this.clear = function () {
259
- cache.list = {};
260
- };
261
- this.load = function (data) {
262
- if (cache.enabled) {
263
- extend(cache.list, data || {});
281
+ class Cache {
282
+ #enabled = true
283
+ #list = {}
284
+ constructor(config) {
285
+ bindContext(this, ['configure']);
286
+ this.configure(config);
287
+ }
288
+ load(data) {
289
+ if (this.#enabled) {
290
+ extend(this.#list, data || {});
264
291
  }
265
- return this
266
- };
267
- this.get = function (key) {
268
- if (cache.enabled) {
269
- return cache.list[key]
292
+ }
293
+ get(key) {
294
+ if (this.#enabled) {
295
+ return this.#list[key]
270
296
  }
271
- };
272
- this.set = function (key, value) {
273
- if (cache.enabled) {
274
- cache.list[key] = value;
297
+ }
298
+ set(key, value) {
299
+ if (this.#enabled) {
300
+ this.#list[key] = value;
275
301
  }
276
- return this
277
- };
278
- this.resolve = function (key) {
302
+ }
303
+ exist(key) {
304
+ return hasProp(this.#list, key)
305
+ }
306
+ clear() {
307
+ this.#list = {};
308
+ }
309
+ remove(key) {
310
+ delete this.#list[key];
311
+ }
312
+ resolve(key) {
279
313
  return Promise.resolve(this.get(key))
280
- };
281
- this.remove = function (key) {
282
- delete cache.list[key];
283
- };
284
- this.exist = function (key) {
285
- return hasProp(cache.list, key)
286
- };
314
+ }
315
+ configure(config) {
316
+ this.#enabled = config.cache;
317
+ if (isNode() === false) {
318
+ this.load(global[config.export]);
319
+ }
320
+ }
287
321
  }
288
322
 
289
- const tagList = [
290
- {
291
- symbol: '-',
292
- format(value) {
293
- return `')\n${this.BUFFER}(${this.SAFE}(${value},1))\n${this.BUFFER}('`
323
+ class Compiler {
324
+ #config = {}
325
+ #symbols = [
326
+ {
327
+ symbol: '-',
328
+ format(value) {
329
+ return `')\n${this.BUFFER}(${this.SAFE}(${value},1))\n${this.BUFFER}('`
330
+ },
294
331
  },
295
- },
296
- {
297
- symbol: '=',
298
- format(value) {
299
- return `')\n${this.BUFFER}(${this.SAFE}(${value}))\n${this.BUFFER}('`
332
+ {
333
+ symbol: '=',
334
+ format(value) {
335
+ return `')\n${this.BUFFER}(${this.SAFE}(${value}))\n${this.BUFFER}('`
336
+ },
300
337
  },
301
- },
302
- {
303
- symbol: '#',
304
- format(value) {
305
- return `')\n/**${value}**/\n${this.BUFFER}('`
338
+ {
339
+ symbol: '#',
340
+ format(value) {
341
+ return `')\n/**${value}**/\n${this.BUFFER}('`
342
+ },
306
343
  },
307
- },
308
- {
309
- symbol: '',
310
- format(value) {
311
- return `')\n${value.trim()}\n${this.BUFFER}('`
344
+ {
345
+ symbol: '',
346
+ format(value) {
347
+ return `')\n${value.trim()}\n${this.BUFFER}('`
348
+ },
312
349
  },
313
- },
314
- ];
315
-
316
- function matchTokens(regex, text, callback) {
317
- let index = 0;
318
- text.replace(regex, function () {
319
- const params = [].slice.call(arguments, 0, -1);
320
- const offset = params.pop();
321
- const match = params.shift();
322
- callback(params, index, offset);
323
- index = offset + match.length;
324
- return match
325
- });
326
- }
327
-
328
- function Compiler(config) {
329
- if (instanceOf(this, Compiler) === false) return new Compiler(config)
330
-
331
- const compiler = {};
332
-
333
- this.configure = function (config) {
334
- compiler.withObject = config.withObject;
335
- compiler.rmWhitespace = config.rmWhitespace;
336
- compiler.token = config.token;
337
- compiler.vars = config.vars;
338
- compiler.globalHelpers = config.globalHelpers;
339
- compiler.matches = [];
340
- compiler.formats = [];
341
- compiler.slurp = {
342
- match: '[\s\t\n]*',
343
- start: [compiler.token.start, '_'],
344
- end: ['_', compiler.token.end],
350
+ ]
351
+ constructor(config) {
352
+ bindContext(this, ['configure', 'compile']);
353
+ this.configure(config);
354
+ }
355
+ configure(config) {
356
+ this.#config.withObject = config.withObject;
357
+ this.#config.rmWhitespace = config.rmWhitespace;
358
+ this.#config.token = config.token;
359
+ this.#config.vars = config.vars;
360
+ this.#config.globalHelpers = config.globalHelpers;
361
+ this.#config.matches = [];
362
+ this.#config.formats = [];
363
+ this.#config.slurp = {
364
+ match: '[s\t\n]*',
365
+ start: [this.#config.token.start, '_'],
366
+ end: ['_', this.#config.token.end],
345
367
  };
346
- tagList.forEach((item) => {
347
- compiler.matches.push(
348
- compiler.token.start
368
+ this.#symbols.forEach((item) => {
369
+ this.#config.matches.push(
370
+ this.#config.token.start
349
371
  .concat(item.symbol)
350
- .concat(compiler.token.regex)
351
- .concat(compiler.token.end)
372
+ .concat(this.#config.token.regex)
373
+ .concat(this.#config.token.end)
352
374
  );
353
- compiler.formats.push(item.format.bind(compiler.vars));
375
+ this.#config.formats.push(item.format.bind(this.#config.vars));
354
376
  });
355
- compiler.regex = new RegExp(
356
- compiler.matches.join('|').concat('|$'),
377
+ this.#config.regex = new RegExp(
378
+ this.#config.matches.join('|').concat('|$'),
357
379
  'g'
358
380
  );
359
- compiler.slurpStart = new RegExp(
360
- [compiler.slurp.match, compiler.slurp.start.join('')].join(''),
381
+ this.#config.slurpStart = new RegExp(
382
+ [this.#config.slurp.match, this.#config.slurp.start.join('')].join(
383
+ ''
384
+ ),
361
385
  'gm'
362
386
  );
363
- compiler.slurpEnd = new RegExp(
364
- [compiler.slurp.end.join(''), compiler.slurp.match].join(''),
387
+ this.#config.slurpEnd = new RegExp(
388
+ [this.#config.slurp.end.join(''), this.#config.slurp.match].join(
389
+ ''
390
+ ),
365
391
  'gm'
366
392
  );
367
- };
368
-
369
- this.compile = function (content, path) {
370
- const { SCOPE, SAFE, BUFFER, COMPONENT } = compiler.vars;
371
- const GLOBALS = compiler.globalHelpers;
372
- content = String(content);
373
- if (compiler.rmWhitespace) {
374
- content = content
393
+ }
394
+ compile(content, path) {
395
+ const { SCOPE, SAFE, BUFFER, COMPONENT } = this.#config.vars;
396
+ const GLOBALS = this.#config.globalHelpers;
397
+ if (this.#config.rmWhitespace) {
398
+ content = String(content)
375
399
  .replace(/[\r\n]+/g, '\n')
376
400
  .replace(/^\s+|\s+$/gm, '');
377
401
  }
378
- content = content
379
- .replace(compiler.slurpStart, compiler.token.start)
380
- .replace(compiler.slurpEnd, compiler.token.end);
402
+ content = String(content)
403
+ .replace(this.#config.slurpStart, this.#config.token.start)
404
+ .replace(this.#config.slurpEnd, this.#config.token.end);
381
405
  let source = `${BUFFER}('`;
382
- matchTokens(compiler.regex, content, (params, index, offset) => {
406
+ matchTokens(this.#config.regex, content, (params, index, offset) => {
383
407
  source += symbols(content.slice(index, offset));
384
408
  params.forEach((value, index) => {
385
409
  if (value) {
386
- source += compiler.formats[index](value);
410
+ source += this.#config.formats[index](value);
387
411
  }
388
412
  });
389
413
  });
390
414
  source += `');`;
391
415
  source = `try{${source}}catch(e){return ${BUFFER}.error(e)}`;
392
- if (compiler.withObject) {
416
+ if (this.#config.withObject) {
393
417
  source = `with(${SCOPE}){${source}}`;
394
418
  }
395
419
  source = `${BUFFER}.start();${source}return ${BUFFER}.end();`;
@@ -405,57 +429,50 @@ function Compiler(config) {
405
429
  throw e
406
430
  }
407
431
  return result
408
- };
409
-
410
- this.configure(config);
432
+ }
411
433
  }
412
434
 
413
- function Template(config, cache, compiler) {
414
- if (instanceOf(this, Template) === false)
415
- return new Template(config, cache, compiler)
416
-
417
- if (instanceOf(cache, Cache) === false)
418
- throw new TypeError('cache is not instance of Cache')
419
-
420
- if (instanceOf(compiler, Compiler) === false)
421
- throw new TypeError('compiler is not instance of Compiler')
422
-
423
- const template = {};
424
-
425
- const result = (template, content) => {
426
- cache.set(template, content);
435
+ class Template {
436
+ #path
437
+ #cache
438
+ #compiler
439
+ #resolver
440
+ constructor(config, cache, compiler) {
441
+ assertInstanceOf(cache, Cache);
442
+ assertInstanceOf(compiler, Compiler);
443
+ this.#cache = cache;
444
+ this.#compiler = compiler;
445
+ bindContext(this, ['configure', 'get']);
446
+ this.configure(config);
447
+ }
448
+ #resolve(path) {
449
+ return this.#resolver(this.#path, path)
450
+ }
451
+ #result(template, content) {
452
+ this.#cache.set(template, content);
427
453
  return content
428
- };
429
-
430
- const resolve = (path) => {
431
- return template.resolver(template.path, path)
432
- };
433
-
434
- const compile = (content, template) => {
454
+ }
455
+ #compile(content, template) {
435
456
  if (isFunction(content)) {
436
457
  return content
437
458
  } else {
438
- return compiler.compile(content, template)
459
+ return this.#compiler.compile(content, template)
439
460
  }
440
- };
441
-
442
- this.configure = function (config) {
443
- template.path = config.path;
444
- template.cache = config.cache;
461
+ }
462
+ configure(config) {
463
+ this.#path = config.path;
445
464
  if (isFunction(config.resolver)) {
446
- template.resolver = config.resolver;
465
+ this.#resolver = config.resolver;
447
466
  }
448
- };
449
-
450
- this.get = function (template) {
451
- if (cache.exist(template)) {
452
- return cache.resolve(template)
467
+ }
468
+ get(template) {
469
+ if (this.#cache.exist(template)) {
470
+ return this.#cache.resolve(template)
453
471
  }
454
- return resolve(template).then((content) =>
455
- result(template, compile(content, template))
472
+ return this.#resolve(template).then((content) =>
473
+ this.#result(template, this.#compile(content, template))
456
474
  )
457
- };
458
- this.configure(config);
475
+ }
459
476
  }
460
477
 
461
478
  const selfClosed = [
@@ -503,475 +520,431 @@ const element = (tag, attrs, content) => {
503
520
  return result.join('')
504
521
  };
505
522
 
506
- /**
507
- * @extends Error
508
- * @property code
509
- * @param {string} message
510
- * @constructor
511
- */
512
- function TemplateError(message) {
513
- this.name = 'TemplateError';
514
- this.message = message;
515
- Error.call(this);
523
+ class TemplateError extends Error {
524
+ code = 0
525
+ constructor(message) {
526
+ super();
527
+ this.message = message;
528
+ }
529
+ getCode() {
530
+ return this.code
531
+ }
532
+ getMessage() {
533
+ return this.message
534
+ }
535
+ toString() {
536
+ return this.getMessage()
537
+ }
516
538
  }
517
539
 
518
- /**
519
- *
520
- */
521
- Object.setPrototypeOf(TemplateError.prototype, Error.prototype);
522
- Object.assign(TemplateError.prototype, { code: 1 });
523
- /**
524
- *
525
- * @return {number}
526
- */
527
- TemplateError.prototype.getCode = function() {
528
- return this.code
529
- };
530
- /**
531
- *
532
- * @return {string}
533
- */
534
- TemplateError.prototype.getMessage = function() {
535
- return this.message
536
- };
537
- /**
538
- * @return {string}
539
- */
540
- TemplateError.prototype.toString = function() {
541
- return this.getMessage()
542
- };
543
-
544
- /**
545
- * @extends TemplateError
546
- * @param {string} message
547
- * @constructor
548
- */
549
- function TemplateNotFound(message) {
550
- TemplateError.call(this);
551
- this.name = 'TemplateNotFound';
552
- this.message = message;
540
+ class TemplateNotFound extends TemplateError {
541
+ code = 404
553
542
  }
554
543
 
555
- /**
556
- *
557
- */
558
- Object.setPrototypeOf(TemplateNotFound.prototype, TemplateError.prototype);
559
- Object.assign(TemplateNotFound.prototype, { code: 404 });
560
- /**
561
- * @extends TemplateError
562
- * @param {string} message
563
- * @constructor
564
- */
565
- function TemplateSyntaxError(message) {
566
- TemplateError.call(this);
567
- this.name = 'TemplateSyntaxError';
568
- this.message = message;
544
+ class TemplateSyntaxError extends TemplateError {
545
+ code = 500
569
546
  }
570
547
 
571
- /**
572
- *
573
- */
574
- Object.setPrototypeOf(TemplateSyntaxError.prototype, TemplateError.prototype);
575
- Object.assign(TemplateSyntaxError.prototype, { code: 500 });
576
-
577
548
  function resolve(list) {
578
- return Promise.all(list || []).then((list) => list.join('')).catch((e) => e)
549
+ return Promise.all(list || [])
550
+ .then((list) => list.join(''))
551
+ .catch((e) => e)
579
552
  }
580
553
 
581
554
  function reject(error) {
582
555
  return Promise.reject(new TemplateSyntaxError(error.message))
583
556
  }
584
557
 
558
+ /**
559
+ *
560
+ * @return {buffer}
561
+ */
585
562
  function createBuffer() {
586
563
  let store = [],
587
564
  array = [];
588
565
 
589
- function buffer(value) {
566
+ const buffer = (value) => {
590
567
  array.push(value);
591
- }
568
+ };
592
569
 
593
- buffer.start = function() {
570
+ buffer.start = () => {
594
571
  array = [];
595
572
  };
596
- buffer.backup = function() {
573
+ buffer.backup = () => {
597
574
  store.push(array.concat());
598
575
  array = [];
599
576
  };
600
- buffer.restore = function() {
577
+ buffer.restore = () => {
601
578
  const result = array.concat();
602
579
  array = store.pop();
603
580
  return resolve(result)
604
581
  };
605
- buffer.error = function(e) {
582
+ buffer.error = (e) => {
606
583
  return reject(e)
607
584
  };
608
- buffer.end = function() {
585
+ buffer.end = () => {
609
586
  return resolve(array)
610
587
  };
611
588
  return buffer
612
589
  }
613
590
 
614
- function Context(config) {
615
- if (instanceOf(this, Context) === false) return new Context(config)
616
- this.configure = function (config, methods) {
617
- const { BLOCKS, MACRO, EXTEND, LAYOUT, BUFFER, COMPONENT } = config.vars;
618
-
619
- this.create = function (data) {
620
- return new Scope(data)
621
- };
622
-
623
- this.helpers = function (methods) {
624
- extend(Scope.prototype, methods || {});
625
- };
626
- /**
627
- * @name ContextScope
628
- * @param data
629
- * @constructor
630
- */
631
- function Scope(data) {
632
- this[BLOCKS] = {};
633
- this[MACRO] = {};
634
- extend(this, data || {});
635
- }
591
+ const createScope = (config, methods) => {
592
+ const { BLOCKS, MACRO, EXTEND, LAYOUT, BUFFER, COMPONENT, SAFE, SCOPE } =
593
+ config.vars;
594
+ /**
595
+ * @name ContextScope
596
+ * @param data
597
+ * @constructor
598
+ */
599
+ function ContextScope(data) {
600
+ this[BLOCKS] = {};
601
+ this[MACRO] = {};
602
+ Object.assign(this, omit(data, [SCOPE, BUFFER, SAFE, COMPONENT]));
603
+ }
636
604
 
637
- Scope.prototype = extend({}, methods || {});
638
- Object.defineProperties(Scope.prototype, {
639
- [BUFFER]: {
640
- value: createBuffer(),
641
- writable: true,
642
- configurable: false,
643
- enumerable: false,
644
- },
645
- [BLOCKS]: {
646
- value: {},
647
- writable: true,
648
- configurable: false,
649
- enumerable: false,
650
- },
651
- [MACRO]: {
652
- value: {},
653
- writable: true,
654
- configurable: false,
655
- enumerable: false,
656
- },
657
- [LAYOUT]: {
658
- value: false,
659
- writable: true,
660
- configurable: false,
661
- enumerable: false,
662
- },
663
- [EXTEND]: {
664
- value: false,
665
- writable: true,
666
- configurable: false,
667
- enumerable: false,
668
- },
669
- getMacro: {
670
- value() {
671
- return this[MACRO]
672
- },
673
- writable: false,
674
- configurable: false,
675
- enumerable: false,
605
+ Object.assign(ContextScope.prototype, methods);
606
+ Object.defineProperties(ContextScope.prototype, {
607
+ [BUFFER]: {
608
+ value: createBuffer(),
609
+ },
610
+ [BLOCKS]: {
611
+ value: {},
612
+ writable: true,
613
+ },
614
+ [MACRO]: {
615
+ value: {},
616
+ writable: true,
617
+ },
618
+ [LAYOUT]: {
619
+ value: false,
620
+ writable: true,
621
+ },
622
+ [EXTEND]: {
623
+ value: false,
624
+ writable: true,
625
+ },
626
+ /** @type {()=>this[MACRO]} */
627
+ getMacro: {
628
+ value() {
629
+ return this[MACRO]
676
630
  },
677
- getBuffer: {
678
- value() {
679
- return this[BUFFER]
680
- },
681
- writable: false,
682
- configurable: false,
683
- enumerable: false,
631
+ },
632
+ /** @type {function} */
633
+ getBuffer: {
634
+ value() {
635
+ return this[BUFFER]
684
636
  },
685
- getComponent: {
686
- value() {
687
- const context = this;
688
- if (COMPONENT in context) {
689
- return function () {
690
- return context[COMPONENT].apply(context, arguments)
691
- }
692
- }
637
+ },
638
+ /** @type {function} */
639
+ getComponent: {
640
+ value() {
641
+ const context = this;
642
+ if (COMPONENT in context) {
693
643
  return function () {
694
- console.log('%s function not defined', COMPONENT);
644
+ return context[COMPONENT].apply(context, arguments)
695
645
  }
696
- },
697
- writable: false,
698
- configurable: false,
699
- enumerable: false,
646
+ }
647
+ return function () {
648
+ console.log('%s function not defined', COMPONENT);
649
+ }
700
650
  },
701
- getBlocks: {
702
- value() {
703
- return this[BLOCKS]
704
- },
705
- writable: false,
706
- configurable: false,
707
- enumerable: false,
651
+ },
652
+ /** @type {function} */
653
+ getBlocks: {
654
+ value() {
655
+ return this[BLOCKS]
708
656
  },
709
- setExtend: {
710
- value(value) {
711
- this[EXTEND] = value;
712
- },
713
- writable: false,
714
- configurable: false,
715
- enumerable: false,
657
+ },
658
+ /** @type {function} */
659
+ setExtend: {
660
+ value(value) {
661
+ this[EXTEND] = value;
716
662
  },
717
- getExtend: {
718
- value() {
719
- return this[EXTEND]
720
- },
721
- writable: false,
722
- configurable: false,
723
- enumerable: false,
663
+ },
664
+ /** @type {function} */
665
+ getExtend: {
666
+ value() {
667
+ return this[EXTEND]
724
668
  },
725
- setLayout: {
726
- value(layout) {
727
- this[LAYOUT] = layout;
728
- },
729
- writable: false,
730
- configurable: false,
731
- enumerable: false,
669
+ },
670
+ /** @type {function} */
671
+ setLayout: {
672
+ value(layout) {
673
+ this[LAYOUT] = layout;
732
674
  },
733
- getLayout: {
734
- value() {
735
- return this[LAYOUT]
736
- },
737
- writable: false,
738
- configurable: false,
739
- enumerable: false,
675
+ },
676
+ /** @type {function} */
677
+ getLayout: {
678
+ value() {
679
+ return this[LAYOUT]
740
680
  },
741
- clone: {
742
- value(exclude_blocks) {
743
- const filter = [LAYOUT, EXTEND, BUFFER];
744
- if (exclude_blocks === true) {
745
- filter.push(BLOCKS);
746
- }
747
- return omit(this, filter)
748
- },
749
- writable: false,
750
- configurable: false,
751
- enumerable: false,
681
+ },
682
+ /** @type {function} */
683
+ clone: {
684
+ value(exclude_blocks) {
685
+ const filter = [LAYOUT, EXTEND, BUFFER];
686
+ if (exclude_blocks === true) {
687
+ filter.push(BLOCKS);
688
+ }
689
+ return omit(this, filter)
752
690
  },
753
- extend: {
754
- value(layout) {
755
- this.setExtend(true);
756
- this.setLayout(layout);
757
- },
758
- writable: false,
759
- configurable: false,
760
- enumerable: false,
691
+ },
692
+ /** @type {function} */
693
+ extend: {
694
+ value(layout) {
695
+ this.setExtend(true);
696
+ this.setLayout(layout);
761
697
  },
762
- echo: {
763
- value(layout) {
764
- const buffer = this.getBuffer();
765
- const params = [].slice.call(arguments);
766
- params.forEach(buffer);
767
- },
768
- writable: false,
769
- configurable: false,
770
- enumerable: false,
698
+ },
699
+ /** @type {function} */
700
+ echo: {
701
+ value(layout) {
702
+ const buffer = this.getBuffer();
703
+ const params = [].slice.call(arguments);
704
+ params.forEach(buffer);
771
705
  },
772
- fn: {
773
- value(callback) {
774
- const buffer = this.getBuffer();
775
- const context = this;
776
- return function () {
777
- buffer.backup();
778
- if (isFunction(callback)) {
779
- callback.apply(context, arguments);
780
- }
781
- return buffer.restore()
706
+ },
707
+ /** @type {function} */
708
+ fn: {
709
+ value(callback) {
710
+ const buffer = this.getBuffer();
711
+ const context = this;
712
+ return function () {
713
+ buffer.backup();
714
+ if (isFunction(callback)) {
715
+ callback.apply(context, arguments);
782
716
  }
783
- },
784
- writable: false,
785
- configurable: false,
786
- enumerable: false,
717
+ return buffer.restore()
718
+ }
787
719
  },
788
- get: {
789
- value(name, defaults) {
790
- const path = getPath(this, name, true);
791
- const result = path.shift();
792
- const prop = path.pop();
793
- return hasProp(result, prop) ? result[prop] : defaults
794
- },
795
- writable: true,
796
- configurable: true,
797
- enumerable: false,
720
+ },
721
+ /** @type {function} */
722
+ get: {
723
+ value(name, defaults) {
724
+ const path = getPath(this, name, true);
725
+ const result = path.shift();
726
+ const prop = path.pop();
727
+ return hasProp(result, prop) ? result[prop] : defaults
798
728
  },
799
- set: {
800
- value(name, value) {
801
- const path = getPath(this, name, false);
802
- const result = path.shift();
803
- const prop = path.pop();
804
- if (this.getExtend() && hasProp(result, prop)) {
805
- return result[prop]
806
- }
807
- return (result[prop] = value)
808
- },
809
- writable: false,
810
- configurable: false,
811
- enumerable: false,
729
+ },
730
+ /** @type {function} */
731
+ set: {
732
+ value(name, value) {
733
+ const path = getPath(this, name, false);
734
+ const result = path.shift();
735
+ const prop = path.pop();
736
+ if (this.getExtend() && hasProp(result, prop)) {
737
+ return result[prop]
738
+ }
739
+ return (result[prop] = value)
812
740
  },
813
- macro: {
814
- value(name, callback) {
815
- const list = this.getMacro();
816
- const macro = this.fn(callback);
817
- const context = this;
818
- list[name] = function () {
819
- return context.echo(macro.apply(undefined, arguments))
820
- };
821
- },
822
- writable: false,
823
- configurable: false,
824
- enumerable: false,
741
+ },
742
+ /** @type {function} */
743
+ macro: {
744
+ value(name, callback) {
745
+ const list = this.getMacro();
746
+ const macro = this.fn(callback);
747
+ const context = this;
748
+ list[name] = function () {
749
+ return context.echo(macro.apply(undefined, arguments))
750
+ };
825
751
  },
826
- call: {
827
- value(name) {
828
- const list = this.getMacro();
829
- const macro = list[name];
830
- const params = [].slice.call(arguments, 1);
831
- if (isFunction(macro)) {
832
- return macro.apply(macro, params)
833
- }
834
- },
835
- writable: false,
836
- configurable: false,
837
- enumerable: false,
752
+ },
753
+ /** @type {function} */
754
+ call: {
755
+ value(name) {
756
+ const list = this.getMacro();
757
+ const macro = list[name];
758
+ const params = [].slice.call(arguments, 1);
759
+ if (isFunction(macro)) {
760
+ return macro.apply(macro, params)
761
+ }
838
762
  },
839
- block: {
840
- value(name, callback) {
841
- const blocks = this.getBlocks();
842
- blocks[name] = blocks[name] || [];
843
- blocks[name].push(this.fn(callback));
844
- if (this.getExtend()) return
845
- const list = Object.assign([], blocks[name]);
846
- const current = function () {
847
- return list.shift()
848
- };
849
- const next = () => {
850
- const parent = current();
851
- if (parent) {
852
- return () => {
853
- this.echo(parent(next()));
854
- }
855
- } else {
856
- return noop
763
+ },
764
+ /** @type {function} */
765
+ block: {
766
+ value(name, callback) {
767
+ const blocks = this.getBlocks();
768
+ blocks[name] = blocks[name] || [];
769
+ blocks[name].push(this.fn(callback));
770
+ if (this.getExtend()) return
771
+ const list = Object.assign([], blocks[name]);
772
+ const current = function () {
773
+ return list.shift()
774
+ };
775
+ const next = () => {
776
+ const parent = current();
777
+ if (parent) {
778
+ return () => {
779
+ this.echo(parent(next()));
857
780
  }
858
- };
859
- this.echo(current()(next()));
860
- },
861
- writable: false,
862
- configurable: false,
863
- enumerable: false,
781
+ } else {
782
+ return noop
783
+ }
784
+ };
785
+ this.echo(current()(next()));
864
786
  },
865
- hasBlock: {
866
- value(name) {
867
- return this.getBlocks().hasOwnProperty(name)
868
- },
869
- writable: false,
870
- configurable: false,
871
- enumerable: false,
787
+ },
788
+ /** @type {function} */
789
+ hasBlock: {
790
+ value(name) {
791
+ return this.getBlocks().hasOwnProperty(name)
872
792
  },
873
- include: {
874
- value(path, data, cx) {
875
- const context = cx === false ? {} : this.clone(true);
876
- const params = extend(context, data || {});
877
- const promise = this.render(path, params);
878
- this.echo(promise);
879
- },
880
- writable: false,
881
- configurable: false,
882
- enumerable: false,
793
+ },
794
+ /** @type {function} */
795
+ include: {
796
+ value(path, data, cx) {
797
+ const context = cx === false ? {} : this.clone(true);
798
+ const params = extend(context, data || {});
799
+ const promise = this.render(path, params);
800
+ this.echo(promise);
883
801
  },
884
- promiseResolve: {
885
- value(value, callback) {
886
- return Promise.resolve(
887
- isFunction(value) ? this.fn(value)() : value
888
- ).then(callback.bind(this))
889
- },
890
- writable: false,
891
- configurable: false,
892
- enumerable: false,
802
+ },
803
+ /** @type {function} */
804
+ promiseResolve: {
805
+ value(value, callback) {
806
+ return Promise.resolve(
807
+ isFunction(value) ? this.fn(value)() : value
808
+ ).then(callback.bind(this))
893
809
  },
894
- use: {
895
- value(path, namespace) {
896
- this.echo(
897
- this.promiseResolve(
898
- this.require(path),
899
- function (exports) {
900
- const list = this.getMacro();
901
- each(exports, function (macro, name) {
902
- list[[namespace, name].join('.')] = macro;
903
- });
904
- }
905
- )
906
- );
907
- },
908
- writable: false,
909
- configurable: false,
910
- enumerable: false,
810
+ },
811
+ /** @type {function} */
812
+ use: {
813
+ value(path, namespace) {
814
+ this.echo(
815
+ this.promiseResolve(this.require(path), function (exports) {
816
+ const list = this.getMacro();
817
+ each(exports, function (macro, name) {
818
+ list[[namespace, name].join('.')] = macro;
819
+ });
820
+ })
821
+ );
911
822
  },
912
- async: {
913
- value(promise, callback) {
914
- this.echo(
915
- this.promiseResolve(promise, function (data) {
916
- return this.fn(callback)(data)
917
- })
918
- );
919
- },
920
- writable: false,
921
- configurable: false,
922
- enumerable: false,
823
+ },
824
+ /** @type {function} */
825
+ async: {
826
+ value(promise, callback) {
827
+ this.echo(
828
+ this.promiseResolve(promise, function (data) {
829
+ return this.fn(callback)(data)
830
+ })
831
+ );
923
832
  },
924
- each: {
925
- value: function (object, callback) {
926
- if (isString(object)) {
927
- object = this.get(object, []);
928
- }
929
- each(object, callback);
930
- },
931
- writable: false,
932
- configurable: false,
933
- enumerable: false,
833
+ },
834
+ /** @type {function} */
835
+ each: {
836
+ value: function (object, callback) {
837
+ if (isString(object)) {
838
+ object = this.get(object, []);
839
+ }
840
+ each(object, callback);
934
841
  },
935
- element: {
936
- value(tag, attr, content) {
937
- return element(tag, attr, content)
938
- },
939
- writable: false,
940
- configurable: false,
941
- enumerable: false,
842
+ },
843
+ /** @type {function} */
844
+ element: {
845
+ value(tag, attr, content) {
846
+ return element(tag, attr, content)
942
847
  },
943
- el: {
944
- value(tag, attr, content) {
945
- this.echo(
946
- this.promiseResolve(content, function (content) {
947
- return this.element(tag, attr, content)
948
- })
949
- );
950
- },
951
- writable: false,
952
- configurable: false,
953
- enumerable: false,
848
+ },
849
+ /** @type {function} */
850
+ el: {
851
+ value(tag, attr, content) {
852
+ this.echo(
853
+ this.promiseResolve(content, function (content) {
854
+ return this.element(tag, attr, content)
855
+ })
856
+ );
954
857
  },
955
- });
956
- };
957
- this.configure(config);
958
- }
858
+ },
859
+ });
860
+ return ContextScope
861
+ };
959
862
 
960
- function EJS(options) {
961
- if (instanceOf(this, EJS) === false) return new EJS(options)
863
+ class Context {
864
+ #scope
962
865
 
963
- const scope = {};
964
- const config = {};
866
+ constructor(config, methods) {
867
+ bindContext(this, ['create', 'helpers', 'configure']);
868
+ this.configure(config, methods);
869
+ }
965
870
 
966
- configSchema(config, options || {});
871
+ create(data) {
872
+ return new this.#scope(data)
873
+ }
967
874
 
968
- const context = new Context(config);
969
- const compiler = new Compiler(config);
970
- const cache = new Cache();
971
- const template = new Template(config, cache, compiler);
875
+ configure(config, methods) {
876
+ this.#scope = createScope(config, methods);
877
+ }
878
+
879
+ helpers(methods) {
880
+ extend(this.#scope.prototype, methods || {});
881
+ }
882
+ }
972
883
 
973
- const output = (path, scope) => {
974
- const { globalHelpers } = config;
884
+ class EJS {
885
+ #config = {}
886
+ #extend = {}
887
+ #context
888
+ #compiler
889
+ #cache
890
+ #template
891
+ constructor(options) {
892
+ configSchema(this.#config, options || {});
893
+ this.#context = new Context(this.#config, this.#extend);
894
+ this.#compiler = new Compiler(this.#config);
895
+ this.#cache = new Cache(this.#config);
896
+ this.#template = new Template(this.#config, this.#cache, this.#compiler);
897
+ //
898
+ bindContext(this, [
899
+ 'configure',
900
+ 'create',
901
+ 'render',
902
+ 'context',
903
+ 'preload',
904
+ 'compile',
905
+ 'helpers',
906
+ ]);
907
+ //
908
+ this.helpers({ require: this.#require, render: this.render });
909
+ }
910
+ configure(options) {
911
+ configSchema(this.#config, options || {});
912
+ this.#context.configure(this.#config, this.#extend);
913
+ this.#compiler.configure(this.#config);
914
+ this.#cache.configure(this.#config);
915
+ this.#template.configure(this.#config);
916
+ return this.#config
917
+ }
918
+ render(name, data) {
919
+ const filepath = ext(name, this.#config.extension);
920
+ const scope = this.context(data);
921
+ return this.#output(filepath, scope).then((content) => {
922
+ if (scope.getExtend()) {
923
+ scope.setExtend(false);
924
+ const layout = scope.getLayout();
925
+ const data = scope.clone();
926
+ return this.render(layout, data)
927
+ }
928
+ return content
929
+ })
930
+ }
931
+ helpers(methods) {
932
+ this.#context.helpers(extend(this.#extend, methods));
933
+ }
934
+ context(data) {
935
+ return this.#context.create(data)
936
+ }
937
+ compile(content, path) {
938
+ return this.#compiler.compile(content, path)
939
+ }
940
+ preload(list) {
941
+ return this.#cache.load(list || {})
942
+ }
943
+ create(options) {
944
+ return new this.constructor(options)
945
+ }
946
+ #output(path, scope) {
947
+ const { globalHelpers } = this.#config;
975
948
  const params = [
976
949
  scope,
977
950
  scope.getComponent(),
@@ -982,60 +955,168 @@ function EJS(options) {
982
955
  .filter((name) => isFunction(scope[name]))
983
956
  .map((name) => scope[name].bind(scope))
984
957
  );
985
- return template
958
+ return this.#template
986
959
  .get(path)
987
960
  .then((callback) => callback.apply(scope, params))
988
- };
989
-
990
- const require = (name) => {
991
- const filepath = ext(name, config.extension);
992
- const scope = context.create({});
993
- return output(filepath, scope).then(() => scope.getMacro())
994
- };
995
- const render = (name, data) => {
996
- const filepath = ext(name, config.extension);
997
- const scope = context.create(data);
998
- return output(filepath, scope).then((content) => {
999
- if (scope.getExtend()) {
1000
- scope.setExtend(false);
1001
- const layout = scope.getLayout();
1002
- const data = scope.clone();
1003
- return render(layout, data)
1004
- }
1005
- return content
1006
- })
1007
- };
1008
- this.configure = function (options) {
1009
- options = options || {};
1010
- configSchema(config, options);
1011
- context.configure(config, scope);
1012
- compiler.configure(config);
1013
- cache.configure(config);
1014
- template.configure(config);
1015
- return config
1016
- };
1017
- this.render = function (name, data) {
1018
- return render(name, data)
1019
- };
1020
- this.helpers = function (methods) {
1021
- context.helpers(extend(scope, methods));
1022
- };
1023
- this.preload = function (list) {
1024
- return cache.load(list || {})
1025
- };
1026
- this.create = function (options) {
1027
- return new EJS(options)
1028
- };
1029
- this.compile = function (content, path) {
1030
- return compiler.compile(content, path)
1031
- };
1032
- this.context = function (data) {
1033
- return context.create(data)
1034
- };
1035
- this.helpers({ require, render });
1036
- return this
961
+ }
962
+ #require(name) {
963
+ const filepath = ext(name, this.#config.extension);
964
+ const scope = this.context({});
965
+ return this.#output(filepath, scope).then(() => scope.getMacro())
966
+ }
1037
967
  }
1038
968
 
969
+ // export function EJS2(options) {
970
+ // const self = {
971
+ // config: {},
972
+ // helpers: {},
973
+ // /**
974
+ // * @type {Context}
975
+ // */
976
+ // context: null,
977
+ // /**
978
+ // * @type {Compiler}
979
+ // */
980
+ // compiler: null,
981
+ // /**
982
+ // * @type {Template}
983
+ // */
984
+ // template: null,
985
+ // /**
986
+ // * @type {Cache}
987
+ // */
988
+ // cache: null,
989
+ // }
990
+ // /**
991
+ // *
992
+ // */
993
+ // configSchema(self.config, options || {})
994
+ // self.context = useContext(self.config, self.helpers)
995
+ // self.compiler = useCompiler(self.config)
996
+ // self.cache = useCache(self.config)
997
+ // self.template = useTemplate(self.config, self.cache, self.compiler)
998
+ // /**
999
+ // *
1000
+ // * @param {string} path
1001
+ // * @param {ContextScope} scope
1002
+ // * @return {Promise<string>}
1003
+ // */
1004
+ // const output = (path, scope) => {
1005
+ // const { globalHelpers } = self.config
1006
+ // const params = [
1007
+ // scope,
1008
+ // scope.getComponent(),
1009
+ // scope.getBuffer(),
1010
+ // safeValue,
1011
+ // ].concat(
1012
+ // globalHelpers
1013
+ // .filter((name) => isFunction(scope[name]))
1014
+ // .map((name) => scope[name].bind(scope))
1015
+ // )
1016
+ // return self.template
1017
+ // .get(path)
1018
+ // .then((callback) => callback.apply(scope, params))
1019
+ // }
1020
+ // /**
1021
+ // *
1022
+ // * @param name
1023
+ // * @return {Promise<string>}
1024
+ // */
1025
+ // const require = (name) => {
1026
+ // const filepath = ext(name, self.config.extension)
1027
+ // const scope = context({})
1028
+ // return output(filepath, scope).then(() => scope.getMacro())
1029
+ // }
1030
+ // /**
1031
+ // *
1032
+ // * @param {string} name
1033
+ // * @param {{}} [data]
1034
+ // * @return {Promise<string>}
1035
+ // */
1036
+ // const render = (name, data) => {
1037
+ // const filepath = ext(name, self.config.extension)
1038
+ // const scope = context(data)
1039
+ // return output(filepath, scope).then((content) => {
1040
+ // if (scope.getExtend()) {
1041
+ // scope.setExtend(false)
1042
+ // const layout = scope.getLayout()
1043
+ // const data = scope.clone()
1044
+ // return render(layout, data)
1045
+ // }
1046
+ // return content
1047
+ // })
1048
+ // }
1049
+ // /**
1050
+ // *
1051
+ // * @param options
1052
+ // * @return {{}}
1053
+ // */
1054
+ // const configure = (options = {}) => {
1055
+ // configSchema(self.config, options || {})
1056
+ // self.context.configure(self.config, self.helpers)
1057
+ // self.compiler.configure(self.config)
1058
+ // self.cache.configure(self.config)
1059
+ // self.template.configure(self.config)
1060
+ // return self.config
1061
+ // }
1062
+ // /**
1063
+ // *
1064
+ // * @param methods
1065
+ // */
1066
+ // const helpers = (methods) => {
1067
+ // self.context.helpers(extend(self.helpers, methods))
1068
+ // }
1069
+ // /**
1070
+ // *
1071
+ // * @param list
1072
+ // * @return {*}
1073
+ // */
1074
+ // const preload = (list) => {
1075
+ // return self.cache.load(list || {})
1076
+ // }
1077
+ // /**
1078
+ // *
1079
+ // * @param options
1080
+ // * @return {any}
1081
+ // */
1082
+ // const create = (options) => {
1083
+ // return EJS(options)
1084
+ // }
1085
+ // /**
1086
+ // *
1087
+ // * @param content
1088
+ // * @param path
1089
+ // * @return {Function}
1090
+ // */
1091
+ // const compile = (content, path) => {
1092
+ // return self.compiler.compile(content, path)
1093
+ // }
1094
+ // /**
1095
+ // *
1096
+ // * @param data
1097
+ // * @return {ContextScope}
1098
+ // */
1099
+ // const context = (data = {}) => {
1100
+ // return self.context.create(data)
1101
+ // }
1102
+ // /**
1103
+ // *
1104
+ // */
1105
+ // helpers({ require, render })
1106
+ // /**
1107
+ // *
1108
+ // */
1109
+ // return {
1110
+ // configure,
1111
+ // helpers,
1112
+ // preload,
1113
+ // context,
1114
+ // compile,
1115
+ // create,
1116
+ // render,
1117
+ // }
1118
+ // }
1119
+
1039
1120
  function readFile(path, template) {
1040
1121
  return new Promise((resolve, reject) => {
1041
1122
  fs.readFile(joinPath(path, template), (error, data) => {
@@ -1050,10 +1131,11 @@ function readFile(path, template) {
1050
1131
 
1051
1132
  /**
1052
1133
  *
1053
- * @param {EJS} ejs
1054
- * @return {function(name, options, callback): Promise<String>}
1134
+ * @param {function(config: object):object} configure
1135
+ * @param {function(name: string, data?: object):Promise<string>} render
1136
+ * @return {function(name:any, options:any, callback: any): Promise<void>}
1055
1137
  */
1056
- function expressRenderer(ejs) {
1138
+ function expressRenderer(configure, render) {
1057
1139
  return function (name, options, callback) {
1058
1140
  if (isFunction(options)) {
1059
1141
  callback = options;
@@ -1071,9 +1153,8 @@ function expressRenderer(ejs) {
1071
1153
  const filename = path.relative(viewPath, name);
1072
1154
  viewOptions.path = viewPath;
1073
1155
  viewOptions.cache = viewCache;
1074
- ejs.configure(viewOptions);
1075
- return ejs
1076
- .render(filename, options)
1156
+ configure(viewOptions);
1157
+ return render(filename, options)
1077
1158
  .then((content) => {
1078
1159
  callback(null, content);
1079
1160
  })
@@ -1083,10 +1164,11 @@ function expressRenderer(ejs) {
1083
1164
  }
1084
1165
  }
1085
1166
 
1086
- const ejs = new EJS({ resolver: readFile });
1087
-
1088
- const { render, context, compile, helpers, preload, configure, create } = ejs;
1167
+ const { render, context, compile, helpers, preload, configure, create } =
1168
+ new EJS({
1169
+ resolver: readFile,
1170
+ });
1089
1171
 
1090
- const __express = expressRenderer(ejs);
1172
+ const __express = expressRenderer(configure, render);
1091
1173
 
1092
1174
  export { TemplateError, TemplateNotFound, TemplateSyntaxError, __express, compile, configure, context, create, helpers, preload, render };