@kosatyi/ejs 0.0.97 → 0.0.99

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';
@@ -180,6 +215,7 @@ defaults.globalHelpers = [];
180
215
  defaults.vars = {
181
216
  SCOPE: 'ejs',
182
217
  COMPONENT: 'ui',
218
+ ELEMENT: 'el',
183
219
  EXTEND: '$$e',
184
220
  BUFFER: '$$a',
185
221
  LAYOUT: '$$l',
@@ -240,159 +276,146 @@ const configSchema = (config, options) => {
240
276
 
241
277
  const global = typeof globalThis !== 'undefined' ? globalThis : window || self;
242
278
 
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 || {});
279
+ class Cache {
280
+ #enabled = true
281
+ #list = {}
282
+ constructor(config) {
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
+ this.configure(config);
350
+ }
351
+ configure(config) {
352
+ this.#config.withObject = config.withObject;
353
+ this.#config.rmWhitespace = config.rmWhitespace;
354
+ this.#config.token = config.token;
355
+ this.#config.vars = config.vars;
356
+ this.#config.globalHelpers = config.globalHelpers;
357
+ this.#config.matches = [];
358
+ this.#config.formats = [];
359
+ this.#config.slurp = {
360
+ match: '[s\t\n]*',
361
+ start: [this.#config.token.start, '_'],
362
+ end: ['_', this.#config.token.end],
342
363
  };
343
- tagList.forEach((item) => {
344
- compiler.matches.push(
345
- compiler.token.start
364
+ this.#symbols.forEach((item) => {
365
+ this.#config.matches.push(
366
+ this.#config.token.start
346
367
  .concat(item.symbol)
347
- .concat(compiler.token.regex)
348
- .concat(compiler.token.end)
368
+ .concat(this.#config.token.regex)
369
+ .concat(this.#config.token.end)
349
370
  );
350
- compiler.formats.push(item.format.bind(compiler.vars));
371
+ this.#config.formats.push(item.format.bind(this.#config.vars));
351
372
  });
352
- compiler.regex = new RegExp(
353
- compiler.matches.join('|').concat('|$'),
373
+ this.#config.regex = new RegExp(
374
+ this.#config.matches.join('|').concat('|$'),
354
375
  'g'
355
376
  );
356
- compiler.slurpStart = new RegExp(
357
- [compiler.slurp.match, compiler.slurp.start.join('')].join(''),
377
+ this.#config.slurpStart = new RegExp(
378
+ [this.#config.slurp.match, this.#config.slurp.start.join('')].join(
379
+ ''
380
+ ),
358
381
  'gm'
359
382
  );
360
- compiler.slurpEnd = new RegExp(
361
- [compiler.slurp.end.join(''), compiler.slurp.match].join(''),
383
+ this.#config.slurpEnd = new RegExp(
384
+ [this.#config.slurp.end.join(''), this.#config.slurp.match].join(
385
+ ''
386
+ ),
362
387
  'gm'
363
388
  );
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
389
+ }
390
+ compile(content, path) {
391
+ const { SCOPE, SAFE, BUFFER, COMPONENT, ELEMENT } = this.#config.vars;
392
+ const GLOBALS = this.#config.globalHelpers;
393
+ if (this.#config.rmWhitespace) {
394
+ content = String(content)
372
395
  .replace(/[\r\n]+/g, '\n')
373
396
  .replace(/^\s+|\s+$/gm, '');
374
397
  }
375
- content = content
376
- .replace(compiler.slurpStart, compiler.token.start)
377
- .replace(compiler.slurpEnd, compiler.token.end);
398
+ content = String(content)
399
+ .replace(this.#config.slurpStart, this.#config.token.start)
400
+ .replace(this.#config.slurpEnd, this.#config.token.end);
378
401
  let source = `${BUFFER}('`;
379
- matchTokens(compiler.regex, content, (params, index, offset) => {
402
+ matchTokens(this.#config.regex, content, (params, index, offset) => {
380
403
  source += symbols(content.slice(index, offset));
381
404
  params.forEach((value, index) => {
382
405
  if (value) {
383
- source += compiler.formats[index](value);
406
+ source += this.#config.formats[index](value);
384
407
  }
385
408
  });
386
409
  });
387
410
  source += `');`;
388
411
  source = `try{${source}}catch(e){return ${BUFFER}.error(e)}`;
389
- if (compiler.withObject) {
412
+ if (this.#config.withObject) {
390
413
  source = `with(${SCOPE}){${source}}`;
391
414
  }
392
415
  source = `${BUFFER}.start();${source}return ${BUFFER}.end();`;
393
416
  source += `\n//# sourceURL=${path}`;
394
417
  let result = null;
395
- let params = [SCOPE, COMPONENT, BUFFER, SAFE].concat(GLOBALS);
418
+ let params = [SCOPE, BUFFER, SAFE, COMPONENT, ELEMENT].concat(GLOBALS);
396
419
  try {
397
420
  result = Function.apply(null, params.concat(source));
398
421
  result.source = `(function(${params.join(',')}){\n${source}\n});`;
@@ -402,57 +425,49 @@ function Compiler(config) {
402
425
  throw e
403
426
  }
404
427
  return result
405
- };
406
-
407
- this.configure(config);
428
+ }
408
429
  }
409
430
 
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);
431
+ class Template {
432
+ #path
433
+ #cache
434
+ #compiler
435
+ #resolver
436
+ constructor(config, cache, compiler) {
437
+ assertInstanceOf(cache, Cache);
438
+ assertInstanceOf(compiler, Compiler);
439
+ this.#cache = cache;
440
+ this.#compiler = compiler;
441
+ this.configure(config);
442
+ }
443
+ #resolve(path) {
444
+ return this.#resolver(this.#path, path)
445
+ }
446
+ #result(template, content) {
447
+ this.#cache.set(template, content);
424
448
  return content
425
- };
426
-
427
- const resolve = (path) => {
428
- return template.resolver(template.path, path)
429
- };
430
-
431
- const compile = (content, template) => {
449
+ }
450
+ #compile(content, template) {
432
451
  if (isFunction(content)) {
433
452
  return content
434
453
  } else {
435
- return compiler.compile(content, template)
454
+ return this.#compiler.compile(content, template)
436
455
  }
437
- };
438
-
439
- this.configure = function (config) {
440
- template.path = config.path;
441
- template.cache = config.cache;
456
+ }
457
+ configure(config) {
458
+ this.#path = config.path;
442
459
  if (isFunction(config.resolver)) {
443
- template.resolver = config.resolver;
460
+ this.#resolver = config.resolver;
444
461
  }
445
- };
446
-
447
- this.get = function (template) {
448
- if (cache.exist(template)) {
449
- return cache.resolve(template)
462
+ }
463
+ get(template) {
464
+ if (this.#cache.exist(template)) {
465
+ return this.#cache.resolve(template)
450
466
  }
451
- return resolve(template).then((content) =>
452
- result(template, compile(content, template))
467
+ return this.#resolve(template).then((content) =>
468
+ this.#result(template, this.#compile(content, template))
453
469
  )
454
- };
455
- this.configure(config);
470
+ }
456
471
  }
457
472
 
458
473
  const selfClosed = [
@@ -500,537 +515,462 @@ const element = (tag, attrs, content) => {
500
515
  return result.join('')
501
516
  };
502
517
 
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);
518
+ class TemplateError extends Error {
519
+ code = 0
520
+ constructor(message) {
521
+ super();
522
+ this.message = message;
523
+ }
524
+ getCode() {
525
+ return this.code
526
+ }
527
+ getMessage() {
528
+ return this.message
529
+ }
530
+ toString() {
531
+ return this.getMessage()
532
+ }
513
533
  }
514
534
 
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;
535
+ class TemplateNotFound extends TemplateError {
536
+ code = 404
550
537
  }
551
538
 
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;
539
+ class TemplateSyntaxError extends TemplateError {
540
+ code = 500
566
541
  }
567
542
 
568
- /**
569
- *
570
- */
571
- Object.setPrototypeOf(TemplateSyntaxError.prototype, TemplateError.prototype);
572
- Object.assign(TemplateSyntaxError.prototype, { code: 500 });
573
-
574
543
  function resolve(list) {
575
- return Promise.all(list || []).then((list) => list.join('')).catch((e) => e)
544
+ return Promise.all(list || [])
545
+ .then((list) => list.join(''))
546
+ .catch((e) => e)
576
547
  }
577
548
 
578
549
  function reject(error) {
579
550
  return Promise.reject(new TemplateSyntaxError(error.message))
580
551
  }
581
552
 
553
+ /**
554
+ *
555
+ * @return {buffer}
556
+ */
582
557
  function createBuffer() {
583
558
  let store = [],
584
559
  array = [];
585
560
 
586
- function buffer(value) {
561
+ const buffer = (value) => {
587
562
  array.push(value);
588
- }
563
+ };
589
564
 
590
- buffer.start = function() {
565
+ buffer.start = () => {
591
566
  array = [];
592
567
  };
593
- buffer.backup = function() {
568
+ buffer.backup = () => {
594
569
  store.push(array.concat());
595
570
  array = [];
596
571
  };
597
- buffer.restore = function() {
572
+ buffer.restore = () => {
598
573
  const result = array.concat();
599
574
  array = store.pop();
600
575
  return resolve(result)
601
576
  };
602
- buffer.error = function(e) {
577
+ buffer.error = (e) => {
603
578
  return reject(e)
604
579
  };
605
- buffer.end = function() {
580
+ buffer.end = () => {
606
581
  return resolve(array)
607
582
  };
608
583
  return buffer
609
584
  }
610
585
 
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
- }
633
-
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,
586
+ const createContextScope = (config, methods) => {
587
+ const {
588
+ BLOCKS,
589
+ MACRO,
590
+ EXTEND,
591
+ LAYOUT,
592
+ BUFFER,
593
+ SAFE,
594
+ SCOPE,
595
+ COMPONENT,
596
+ ELEMENT,
597
+ } = config.vars;
598
+ /**
599
+ * @name ContextScope
600
+ * @param data
601
+ * @constructor
602
+ */
603
+ function ContextScope(data) {
604
+ this[BLOCKS] = {};
605
+ this[MACRO] = {};
606
+ Object.assign(
607
+ this,
608
+ omit(data, [SCOPE, BUFFER, SAFE, COMPONENT, ELEMENT])
609
+ );
610
+ }
611
+ Object.assign(ContextScope.prototype, methods);
612
+ Object.defineProperties(ContextScope.prototype, {
613
+ [BUFFER]: {
614
+ value: createBuffer(),
615
+ },
616
+ [BLOCKS]: {
617
+ value: {},
618
+ writable: true,
619
+ },
620
+ [MACRO]: {
621
+ value: {},
622
+ writable: true,
623
+ },
624
+ [LAYOUT]: {
625
+ value: false,
626
+ writable: true,
627
+ },
628
+ [EXTEND]: {
629
+ value: false,
630
+ writable: true,
631
+ },
632
+ /** @type {function} */
633
+ useSafeValue: {
634
+ get: () => safeValue,
635
+ },
636
+ /** @type {function} */
637
+ useComponent: {
638
+ get() {
639
+ if (isFunction(this[COMPONENT])) {
640
+ return this[COMPONENT].bind(this)
641
+ } else {
642
+ return () => {
643
+ throw new Error(`${COMPONENT} must be a function`)
644
+ }
645
+ }
665
646
  },
666
- getMacro: {
667
- value() {
668
- return this[MACRO]
669
- },
670
- writable: false,
671
- configurable: false,
672
- enumerable: false,
647
+ },
648
+ /** @type {function} */
649
+ useElement: {
650
+ get() {
651
+ if (isFunction(this[ELEMENT])) {
652
+ return this[ELEMENT].bind(this)
653
+ } else {
654
+ return () => {
655
+ throw new Error(`${ELEMENT} must be a function`)
656
+ }
657
+ }
673
658
  },
674
- getBuffer: {
675
- value() {
676
- return this[BUFFER]
677
- },
678
- writable: false,
679
- configurable: false,
680
- enumerable: false,
659
+ },
660
+ /** @type {()=>this[MACRO]} */
661
+ getMacro: {
662
+ value() {
663
+ return this[MACRO]
681
664
  },
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
- }
690
- return function () {
691
- console.log('%s function not defined', COMPONENT);
692
- }
693
- },
694
- writable: false,
695
- configurable: false,
696
- enumerable: false,
665
+ },
666
+ /** @type {function} */
667
+ getBuffer: {
668
+ value() {
669
+ return this[BUFFER]
697
670
  },
698
- getBlocks: {
699
- value() {
700
- return this[BLOCKS]
701
- },
702
- writable: false,
703
- configurable: false,
704
- enumerable: false,
671
+ },
672
+ /** @type {function} */
673
+ getBlocks: {
674
+ value() {
675
+ return this[BLOCKS]
705
676
  },
706
- setExtend: {
707
- value(value) {
708
- this[EXTEND] = value;
709
- },
710
- writable: false,
711
- configurable: false,
712
- enumerable: false,
677
+ },
678
+ /** @type {function} */
679
+ setExtend: {
680
+ value(value) {
681
+ this[EXTEND] = value;
713
682
  },
714
- getExtend: {
715
- value() {
716
- return this[EXTEND]
717
- },
718
- writable: false,
719
- configurable: false,
720
- enumerable: false,
683
+ },
684
+ /** @type {function} */
685
+ getExtend: {
686
+ value() {
687
+ return this[EXTEND]
721
688
  },
722
- setLayout: {
723
- value(layout) {
724
- this[LAYOUT] = layout;
725
- },
726
- writable: false,
727
- configurable: false,
728
- enumerable: false,
689
+ },
690
+ /** @type {function} */
691
+ setLayout: {
692
+ value(layout) {
693
+ this[LAYOUT] = layout;
729
694
  },
730
- getLayout: {
731
- value() {
732
- return this[LAYOUT]
733
- },
734
- writable: false,
735
- configurable: false,
736
- enumerable: false,
695
+ },
696
+ /** @type {function} */
697
+ getLayout: {
698
+ value() {
699
+ return this[LAYOUT]
737
700
  },
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,
701
+ },
702
+ /** @type {function} */
703
+ clone: {
704
+ value(exclude_blocks) {
705
+ const filter = [LAYOUT, EXTEND, BUFFER];
706
+ if (exclude_blocks === true) {
707
+ filter.push(BLOCKS);
708
+ }
709
+ return omit(this, filter)
749
710
  },
750
- extend: {
751
- value(layout) {
752
- this.setExtend(true);
753
- this.setLayout(layout);
754
- },
755
- writable: false,
756
- configurable: false,
757
- enumerable: false,
711
+ },
712
+ /** @type {function} */
713
+ extend: {
714
+ value(layout) {
715
+ this.setExtend(true);
716
+ this.setLayout(layout);
758
717
  },
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,
718
+ },
719
+ /** @type {function} */
720
+ echo: {
721
+ value(layout) {
722
+ const buffer = this.getBuffer();
723
+ const params = [].slice.call(arguments);
724
+ params.forEach(buffer);
768
725
  },
769
- fn: {
770
- value(callback) {
771
- const buffer = this.getBuffer();
772
- const context = this;
773
- return function () {
726
+ },
727
+ /** @type {function} */
728
+ fn: {
729
+ value(callback) {
730
+ const buffer = this.getBuffer();
731
+ const context = this;
732
+ return function () {
733
+ if (isFunction(callback)) {
774
734
  buffer.backup();
775
- if (isFunction(callback)) {
776
- callback.apply(context, arguments);
777
- }
735
+ buffer(callback.apply(context, arguments));
778
736
  return buffer.restore()
779
737
  }
780
- },
781
- writable: false,
782
- configurable: false,
783
- enumerable: false,
784
- },
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,
795
- },
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,
738
+ }
809
739
  },
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,
740
+ },
741
+ /** @type {function} */
742
+ macro: {
743
+ value(name, callback) {
744
+ const list = this.getMacro();
745
+ const macro = this.fn(callback);
746
+ const context = this;
747
+ list[name] = function () {
748
+ return context.echo(macro.apply(undefined, arguments))
749
+ };
822
750
  },
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,
751
+ },
752
+ /** @type {function} */
753
+ call: {
754
+ value(name) {
755
+ const list = this.getMacro();
756
+ const macro = list[name];
757
+ const params = [].slice.call(arguments, 1);
758
+ if (isFunction(macro)) {
759
+ return macro.apply(macro, params)
760
+ }
835
761
  },
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
762
+ },
763
+ /** @type {function} */
764
+ block: {
765
+ value(name, callback) {
766
+ const blocks = this.getBlocks();
767
+ blocks[name] = blocks[name] || [];
768
+ blocks[name].push(this.fn(callback));
769
+ if (this.getExtend()) return
770
+ const list = Object.assign([], blocks[name]);
771
+ const current = () => {
772
+ return list.shift()
773
+ };
774
+ const next = () => {
775
+ const parent = current();
776
+ if (parent) {
777
+ return () => {
778
+ this.echo(parent(next()));
854
779
  }
855
- };
856
- this.echo(current()(next()));
857
- },
858
- writable: false,
859
- configurable: false,
860
- enumerable: false,
780
+ } else {
781
+ return noop
782
+ }
783
+ };
784
+ this.echo(current()(next()));
861
785
  },
862
- hasBlock: {
863
- value(name) {
864
- return this.getBlocks().hasOwnProperty(name)
865
- },
866
- writable: false,
867
- configurable: false,
868
- enumerable: false,
786
+ },
787
+ /** @type {function} */
788
+ hasBlock: {
789
+ value(name) {
790
+ return this.getBlocks().hasOwnProperty(name)
869
791
  },
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,
792
+ },
793
+ /** @type {function} */
794
+ include: {
795
+ value(path, data, cx) {
796
+ const context = cx === false ? {} : this.clone(true);
797
+ const params = extend(context, data || {});
798
+ const promise = this.render(path, params);
799
+ this.echo(promise);
880
800
  },
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,
801
+ },
802
+ /** @type {function} */
803
+ use: {
804
+ value(path, namespace) {
805
+ this.echo(
806
+ Promise.resolve(this.require(path)).then((exports) => {
807
+ const list = this.getMacro();
808
+ each(exports, function (macro, name) {
809
+ list[[namespace, name].join('.')] = macro;
810
+ });
811
+ })
812
+ );
890
813
  },
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,
814
+ },
815
+ /** @type {function} */
816
+ async: {
817
+ value(promise, callback) {
818
+ this.echo(Promise.resolve(promise).then(callback));
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
+ get: {
823
+ value(name, defaults) {
824
+ const path = getPath(this, name, true);
825
+ const result = path.shift();
826
+ const prop = path.pop();
827
+ return hasProp(result, prop) ? result[prop] : defaults
920
828
  },
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,
829
+ },
830
+ /** @type {function} */
831
+ set: {
832
+ value(name, value) {
833
+ const path = getPath(this, name, false);
834
+ const result = path.shift();
835
+ const prop = path.pop();
836
+ if (this.getExtend() && hasProp(result, prop)) {
837
+ return result[prop]
838
+ }
839
+ return (result[prop] = value)
931
840
  },
932
- element: {
933
- value(tag, attr, content) {
934
- return element(tag, attr, content)
935
- },
936
- writable: false,
937
- configurable: false,
938
- enumerable: false,
841
+ },
842
+ /** @type {function} */
843
+ each: {
844
+ value: function (object, callback) {
845
+ if (isString(object)) {
846
+ object = this.get(object, []);
847
+ }
848
+ each(object, callback);
939
849
  },
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,
850
+ writable: true,
851
+ },
852
+ /** @type {function} */
853
+ el: {
854
+ value(tag, attr, content) {
855
+ content = isFunction(content) ? this.fn(content)() : content;
856
+ this.echo(
857
+ Promise.resolve(content).then((content) =>
858
+ element(tag, attr, content)
859
+ )
860
+ );
951
861
  },
952
- });
953
- };
954
- this.configure(config);
955
- }
956
-
957
- function EJS(options) {
958
- if (instanceOf(this, EJS) === false) return new EJS(options)
959
-
960
- const scope = {};
961
- const config = {};
962
-
963
- configSchema(config, options || {});
862
+ writable: true,
863
+ },
864
+ /** @type {function} */
865
+ ui: {
866
+ value(layout) {},
867
+ writable: true,
868
+ },
869
+ });
870
+ return ContextScope
871
+ };
964
872
 
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);
873
+ class Context {
874
+ #scope
875
+ constructor(config, methods) {
876
+ this.configure(config, methods);
877
+ }
878
+ create(data) {
879
+ return new this.#scope(data)
880
+ }
881
+ configure(config, methods) {
882
+ this.#scope = createContextScope(config, methods);
883
+ }
884
+ helpers(methods) {
885
+ extend(this.#scope.prototype, methods || {});
886
+ }
887
+ }
969
888
 
970
- const output = (path, scope) => {
971
- const { globalHelpers } = config;
889
+ class EJS {
890
+ #config = {}
891
+ #extend = {}
892
+ #context
893
+ #compiler
894
+ #cache
895
+ #template
896
+ constructor(options) {
897
+ configSchema(this.#config, options || {});
898
+ this.#context = new Context(this.#config, this.#extend);
899
+ this.#compiler = new Compiler(this.#config);
900
+ this.#cache = new Cache(this.#config);
901
+ this.#template = new Template(this.#config, this.#cache, this.#compiler);
902
+ //
903
+ bindContext(this, [
904
+ 'configure',
905
+ 'create',
906
+ 'render',
907
+ 'require',
908
+ 'context',
909
+ 'preload',
910
+ 'compile',
911
+ 'helpers',
912
+ ]);
913
+ //
914
+ this.helpers({ require: this.require, render: this.render });
915
+ }
916
+ configure(options) {
917
+ configSchema(this.#config, options || {});
918
+ this.#context.configure(this.#config, this.#extend);
919
+ this.#compiler.configure(this.#config);
920
+ this.#cache.configure(this.#config);
921
+ this.#template.configure(this.#config);
922
+ return this.#config
923
+ }
924
+ render(name, data) {
925
+ const filepath = ext(name, this.#config.extension);
926
+ const scope = this.context(data);
927
+ return this.#output(filepath, scope).then((content) => {
928
+ if (scope.getExtend()) {
929
+ scope.setExtend(false);
930
+ const layout = scope.getLayout();
931
+ const data = scope.clone();
932
+ return this.render(layout, data)
933
+ }
934
+ return content
935
+ })
936
+ }
937
+ helpers(methods) {
938
+ this.#context.helpers(extend(this.#extend, methods));
939
+ }
940
+ context(data) {
941
+ return this.#context.create(data)
942
+ }
943
+ compile(content, path) {
944
+ return this.#compiler.compile(content, path)
945
+ }
946
+ preload(list) {
947
+ return this.#cache.load(list || {})
948
+ }
949
+ create(options) {
950
+ return new this.constructor(options)
951
+ }
952
+ require(name) {
953
+ const filepath = ext(name, this.#config.extension);
954
+ const scope = this.context({});
955
+ return this.#output(filepath, scope).then(() => scope.getMacro())
956
+ }
957
+ #output(path, scope) {
958
+ const { globalHelpers } = this.#config;
972
959
  const params = [
973
960
  scope,
974
- scope.getComponent(),
975
961
  scope.getBuffer(),
976
- safeValue,
962
+ scope.useSafeValue,
963
+ scope.useComponent,
964
+ scope.useElement,
977
965
  ].concat(
978
966
  globalHelpers
979
967
  .filter((name) => isFunction(scope[name]))
980
968
  .map((name) => scope[name].bind(scope))
981
969
  );
982
- return template
970
+ return this.#template
983
971
  .get(path)
984
972
  .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
973
+ }
1034
974
  }
1035
975
 
1036
976
  const httpRequest = (path, template) => {
@@ -1040,8 +980,9 @@ const httpRequest = (path, template) => {
1040
980
  )
1041
981
  };
1042
982
 
1043
- const ejs = new EJS({ resolver: httpRequest });
1044
-
1045
- const { render, context, compile, helpers, preload, configure, create } = ejs;
983
+ const { render, context, compile, helpers, preload, configure, create } =
984
+ new EJS({
985
+ resolver: httpRequest,
986
+ });
1046
987
 
1047
988
  export { TemplateError, TemplateNotFound, TemplateSyntaxError, compile, configure, context, create, helpers, preload, render };