@kosatyi/ejs 0.0.76 → 0.0.78

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.
@@ -369,6 +369,7 @@ function Compiler(config) {
369
369
  this.compile = function (content, path) {
370
370
  const { SCOPE, SAFE, BUFFER, COMPONENT } = compiler.vars;
371
371
  const GLOBALS = compiler.globalHelpers;
372
+ content = String(content);
372
373
  if (compiler.rmWhitespace) {
373
374
  content = content
374
375
  .replace(/[\r\n]+/g, '\n')
@@ -387,7 +388,7 @@ function Compiler(config) {
387
388
  });
388
389
  });
389
390
  source += `');`;
390
- source = `try{${source}}catch(e){console.info(e)}`;
391
+ source = `try{${source}}catch(e){return ${BUFFER}.error(e)}`;
391
392
  if (compiler.withObject) {
392
393
  source = `with(${SCOPE}){${source}}`;
393
394
  }
@@ -502,10 +503,40 @@ const element = (tag, attrs, content) => {
502
503
  return result.join('')
503
504
  };
504
505
 
506
+ function TemplateError(message) {
507
+ this.code = 1;
508
+ this.name = 'TemplateError';
509
+ this.message = message;
510
+ Error.call(this);
511
+ }
512
+ Object.setPrototypeOf(TemplateNotFound.prototype, Error.prototype);
513
+
514
+ function TemplateNotFound(message) {
515
+ TemplateError.call(this);
516
+ this.code = 404;
517
+ this.name = 'TemplateNotFound';
518
+ this.message = message;
519
+ }
520
+
521
+ Object.setPrototypeOf(TemplateNotFound.prototype, TemplateError.prototype);
522
+
523
+ function TemplateSyntaxError(message) {
524
+ TemplateError.call(this);
525
+ this.code = 500;
526
+ this.name = 'TemplateSyntaxError';
527
+ this.message = message;
528
+ }
529
+
530
+ Object.setPrototypeOf(TemplateSyntaxError.prototype, TemplateError.prototype);
531
+
505
532
  function resolve(list) {
506
533
  return Promise.all(list || []).then((list) => list.join(''))
507
534
  }
508
535
 
536
+ function reject(error) {
537
+ return Promise.reject(new TemplateSyntaxError(error.message))
538
+ }
539
+
509
540
  function createBuffer() {
510
541
  let store = [],
511
542
  array = [];
@@ -525,7 +556,7 @@ function createBuffer() {
525
556
  return resolve(result)
526
557
  };
527
558
  buffer.error = function (e) {
528
- throw e
559
+ return reject(e)
529
560
  };
530
561
  buffer.end = function () {
531
562
  return resolve(array)
@@ -545,7 +576,11 @@ function Context(config) {
545
576
  this.helpers = function (methods) {
546
577
  extend(Scope.prototype, methods || {});
547
578
  };
548
-
579
+ /**
580
+ * @name ContextScope
581
+ * @param data
582
+ * @constructor
583
+ */
549
584
  function Scope(data) {
550
585
  this[BLOCKS] = {};
551
586
  this[MACRO] = {};
@@ -711,8 +746,8 @@ function Context(config) {
711
746
  const prop = path.pop();
712
747
  return hasProp(result, prop) ? result[prop] : defaults
713
748
  },
714
- writable: false,
715
- configurable: false,
749
+ writable: true,
750
+ configurable: true,
716
751
  enumerable: false,
717
752
  },
718
753
  set: {
@@ -884,27 +919,27 @@ function EJS(options) {
884
919
  const cache = new Cache();
885
920
  const template = new Template(config, cache, compiler);
886
921
 
887
- const output = (path, context) => {
922
+ const output = (path, scope) => {
923
+ const { globalHelpers } = config;
888
924
  const params = [
889
- context,
890
- context.getComponent(),
891
- context.getBuffer(),
925
+ scope,
926
+ scope.getComponent(),
927
+ scope.getBuffer(),
892
928
  safeValue,
893
- ];
894
- config.globalHelpers.forEach((name) => {
895
- if (isFunction(context[name]))
896
- params.push(context[name].bind(context));
897
- });
898
- return template.get(path).then(function (callback) {
899
- return callback.apply(context, params)
900
- })
929
+ ].concat(
930
+ globalHelpers
931
+ .filter((name) => isFunction(scope[name]))
932
+ .map((name) => scope[name].bind(scope))
933
+ );
934
+ return template
935
+ .get(path)
936
+ .then((callback) => callback.apply(scope, params))
901
937
  };
938
+
902
939
  const require = (name) => {
903
940
  const filepath = ext(name, config.extension);
904
941
  const scope = context.create({});
905
- return output(filepath, scope).then(() => {
906
- return scope.getMacro()
907
- })
942
+ return output(filepath, scope).then(() => scope.getMacro())
908
943
  };
909
944
  const render = (name, data) => {
910
945
  const filepath = ext(name, config.extension);
@@ -953,7 +988,7 @@ function EJS(options) {
953
988
  const httpRequest = (path, template) => {
954
989
  return fetch(joinPath(path, template)).then(
955
990
  (response) => response.text(),
956
- (reason) => String(reason)
991
+ (reason) => new TemplateError(reason)
957
992
  )
958
993
  };
959
994
 
@@ -0,0 +1,168 @@
1
+ import { promises } from 'fs';
2
+ import { glob } from 'glob';
3
+ import { join, extname, dirname } from 'path';
4
+ import { minify } from 'terser';
5
+ import { configure, compile } from './index.js';
6
+ import babel from '@babel/core';
7
+
8
+ const isPlainObject = function (obj) {
9
+ return Object.prototype.toString.call(obj) === '[object Object]'
10
+ };
11
+
12
+ const extend = (target, ...sources) => {
13
+ return Object.assign(target, ...sources.filter(isPlainObject))
14
+ };
15
+
16
+ class Bundler {
17
+ /**
18
+ * @type {BundlerOptions}
19
+ */
20
+ options = {
21
+ target: [],
22
+ transform: true,
23
+ minify: true,
24
+ timestamp: true,
25
+ }
26
+ /**
27
+ * @type {EjsConfig}
28
+ */
29
+ config = {}
30
+ constructor(options, config) {
31
+ extend(this.options, options || {});
32
+ this.config = configure(config || {});
33
+ this.templates = {};
34
+ }
35
+ stageRead(path) {
36
+ return promises
37
+ .readFile(join(this.config.path, path))
38
+ .then((response) => response.toString())
39
+ }
40
+ stageCompile(content, name) {
41
+ return compile(content, name).source
42
+ }
43
+ async stageMinify(content) {
44
+ if (this.options.minify === false) return content
45
+ const config = {
46
+ compress: {
47
+ dead_code: false,
48
+ side_effects: false,
49
+ },
50
+ };
51
+ const response = await minify(content, config);
52
+ return response.code
53
+ }
54
+ async stageTransform(content) {
55
+ if (this.options.transform === false) return content
56
+ const config = {
57
+ presets: [['@babel/preset-env']],
58
+ sourceType: 'script',
59
+ };
60
+ const response = await babel.transformAsync(content, config);
61
+ return response.code
62
+ }
63
+ getBundle() {
64
+ const transform = this.options.transform;
65
+ const moduleId = this.config.export;
66
+ const useStrict = this.config.withObject === false;
67
+ const timestamp = this.options.timestamp;
68
+ const out = [];
69
+ if (transform) {
70
+ out.push('(function(global,factory){');
71
+ out.push(
72
+ 'typeof exports === "object" && typeof module !== "undefined" ?'
73
+ );
74
+ out.push('module.exports = factory():');
75
+ out.push(
76
+ 'typeof define === "function" && define.amd ? define(factory):'
77
+ );
78
+ out.push(
79
+ '(global = typeof globalThis !== "undefined" ? globalThis:'
80
+ );
81
+ out.push('global || self,global["' + moduleId + '"] = factory())');
82
+ out.push('})(this,(function(){');
83
+ }
84
+ if (useStrict) out.push("'use strict'");
85
+ if (timestamp) out.push('const timestamp = '.concat(String(Date.now())));
86
+ out.push('const templates = {}');
87
+ Object.entries(this.templates).forEach(([name, content]) => {
88
+ name = JSON.stringify(name);
89
+ content = String(content);
90
+ out.push(`templates[${name}] = ${content}`);
91
+ });
92
+ if (transform) {
93
+ out.push('return templates');
94
+ out.push('}))');
95
+ } else {
96
+ out.push('export default templates');
97
+ }
98
+ return out.join('\n')
99
+ }
100
+ async watch() {
101
+ console.log(`ejs-bundle: watching directory - ${this.config.path}`);
102
+ try {
103
+ const watcher = promises.watch(this.config.path, { recursive: true });
104
+ for await (const { filename } of watcher) {
105
+ if (extname(filename).slice(1) === this.config.extension) {
106
+ console.log(`ejs-bundle: file is changed - ${filename}`);
107
+ await this.build();
108
+ }
109
+ }
110
+ } catch (err) {
111
+ throw err
112
+ }
113
+ }
114
+ async build() {
115
+ if (this.buildInProgress === true) return false
116
+ this.buildInProgress = true;
117
+ await this.concat().catch(console.error);
118
+ await this.output().catch(console.error);
119
+ console.log(`ejs-bundle: bundle complete - ${this.options.target}`);
120
+ this.buildInProgress = false;
121
+ }
122
+ async concat() {
123
+ const pattern = '**/*.'.concat(this.config.extension);
124
+ const list = await glob(pattern, { cwd: this.config.path });
125
+ for (let template of list) {
126
+ let content = '';
127
+ content = await this.stageRead(template);
128
+ content = await this.stageCompile(content, template);
129
+ this.templates[template] = content;
130
+ }
131
+ }
132
+ async output() {
133
+ const target = [].concat(this.options.target);
134
+ let content = this.getBundle();
135
+ if (this.options.transform) {
136
+ content = await this.stageTransform(content);
137
+ }
138
+ if (this.options.minify) {
139
+ content = await this.stageMinify(content);
140
+ }
141
+ for (let file of target) {
142
+ const folderPath = dirname(file);
143
+ const folderExists = await promises
144
+ .stat(folderPath)
145
+ .then(() => true)
146
+ .catch(() => false);
147
+ if (folderExists === false) {
148
+ await promises.mkdir(folderPath, { recursive: true });
149
+ }
150
+ await promises.writeFile(file, content);
151
+ }
152
+ }
153
+ }
154
+
155
+ const ejsBundle = (options, config) => {
156
+ const bundler = new Bundler(options, config);
157
+ return {
158
+ name: 'ejs-bundle',
159
+ async buildStart() {
160
+ await bundler.concat();
161
+ },
162
+ async buildEnd() {
163
+ await bundler.output();
164
+ },
165
+ }
166
+ };
167
+
168
+ export { Bundler, ejsBundle };
package/dist/esm/index.js CHANGED
@@ -372,6 +372,7 @@ function Compiler(config) {
372
372
  this.compile = function (content, path) {
373
373
  const { SCOPE, SAFE, BUFFER, COMPONENT } = compiler.vars;
374
374
  const GLOBALS = compiler.globalHelpers;
375
+ content = String(content);
375
376
  if (compiler.rmWhitespace) {
376
377
  content = content
377
378
  .replace(/[\r\n]+/g, '\n')
@@ -390,7 +391,7 @@ function Compiler(config) {
390
391
  });
391
392
  });
392
393
  source += `');`;
393
- source = `try{${source}}catch(e){console.info(e)}`;
394
+ source = `try{${source}}catch(e){return ${BUFFER}.error(e)}`;
394
395
  if (compiler.withObject) {
395
396
  source = `with(${SCOPE}){${source}}`;
396
397
  }
@@ -505,10 +506,40 @@ const element = (tag, attrs, content) => {
505
506
  return result.join('')
506
507
  };
507
508
 
509
+ function TemplateError(message) {
510
+ this.code = 1;
511
+ this.name = 'TemplateError';
512
+ this.message = message;
513
+ Error.call(this);
514
+ }
515
+ Object.setPrototypeOf(TemplateNotFound.prototype, Error.prototype);
516
+
517
+ function TemplateNotFound(message) {
518
+ TemplateError.call(this);
519
+ this.code = 404;
520
+ this.name = 'TemplateNotFound';
521
+ this.message = message;
522
+ }
523
+
524
+ Object.setPrototypeOf(TemplateNotFound.prototype, TemplateError.prototype);
525
+
526
+ function TemplateSyntaxError(message) {
527
+ TemplateError.call(this);
528
+ this.code = 500;
529
+ this.name = 'TemplateSyntaxError';
530
+ this.message = message;
531
+ }
532
+
533
+ Object.setPrototypeOf(TemplateSyntaxError.prototype, TemplateError.prototype);
534
+
508
535
  function resolve(list) {
509
536
  return Promise.all(list || []).then((list) => list.join(''))
510
537
  }
511
538
 
539
+ function reject(error) {
540
+ return Promise.reject(new TemplateSyntaxError(error.message))
541
+ }
542
+
512
543
  function createBuffer() {
513
544
  let store = [],
514
545
  array = [];
@@ -528,7 +559,7 @@ function createBuffer() {
528
559
  return resolve(result)
529
560
  };
530
561
  buffer.error = function (e) {
531
- throw e
562
+ return reject(e)
532
563
  };
533
564
  buffer.end = function () {
534
565
  return resolve(array)
@@ -548,7 +579,11 @@ function Context(config) {
548
579
  this.helpers = function (methods) {
549
580
  extend(Scope.prototype, methods || {});
550
581
  };
551
-
582
+ /**
583
+ * @name ContextScope
584
+ * @param data
585
+ * @constructor
586
+ */
552
587
  function Scope(data) {
553
588
  this[BLOCKS] = {};
554
589
  this[MACRO] = {};
@@ -714,8 +749,8 @@ function Context(config) {
714
749
  const prop = path.pop();
715
750
  return hasProp(result, prop) ? result[prop] : defaults
716
751
  },
717
- writable: false,
718
- configurable: false,
752
+ writable: true,
753
+ configurable: true,
719
754
  enumerable: false,
720
755
  },
721
756
  set: {
@@ -887,27 +922,27 @@ function EJS(options) {
887
922
  const cache = new Cache();
888
923
  const template = new Template(config, cache, compiler);
889
924
 
890
- const output = (path, context) => {
925
+ const output = (path, scope) => {
926
+ const { globalHelpers } = config;
891
927
  const params = [
892
- context,
893
- context.getComponent(),
894
- context.getBuffer(),
928
+ scope,
929
+ scope.getComponent(),
930
+ scope.getBuffer(),
895
931
  safeValue,
896
- ];
897
- config.globalHelpers.forEach((name) => {
898
- if (isFunction(context[name]))
899
- params.push(context[name].bind(context));
900
- });
901
- return template.get(path).then(function (callback) {
902
- return callback.apply(context, params)
903
- })
932
+ ].concat(
933
+ globalHelpers
934
+ .filter((name) => isFunction(scope[name]))
935
+ .map((name) => scope[name].bind(scope))
936
+ );
937
+ return template
938
+ .get(path)
939
+ .then((callback) => callback.apply(scope, params))
904
940
  };
941
+
905
942
  const require = (name) => {
906
943
  const filepath = ext(name, config.extension);
907
944
  const scope = context.create({});
908
- return output(filepath, scope).then(() => {
909
- return scope.getMacro()
910
- })
945
+ return output(filepath, scope).then(() => scope.getMacro())
911
946
  };
912
947
  const render = (name, data) => {
913
948
  const filepath = ext(name, config.extension);
@@ -957,7 +992,7 @@ function readFile(path, template) {
957
992
  return new Promise((resolve, reject) => {
958
993
  fs.readFile(joinPath(path, template), (error, data) => {
959
994
  if (error) {
960
- reject(error);
995
+ reject(new TemplateError(error));
961
996
  } else {
962
997
  resolve(data.toString());
963
998
  }