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