@kosatyi/ejs 0.0.107 → 0.0.109

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.
@@ -1,39 +1,75 @@
1
+ import fs from 'node:fs/promises';
1
2
  import globWatch from 'glob-watcher';
2
- import { promises } from 'node:fs';
3
- import { dirname, join } from 'node:path';
4
3
  import { glob } from 'glob';
4
+ import { join, dirname } from 'node:path';
5
5
  import { create } from './index.js';
6
6
 
7
- const isPlainObject = function (obj) {
8
- return Object.prototype.toString.call(obj) === '[object Object]'
7
+ const symbolEntities = {
8
+ "'": "'",
9
+ '\\': '\\',
10
+ '\r': 'r',
11
+ '\n': 'n',
12
+ '\t': 't',
13
+ '\u2028': 'u2028',
14
+ '\u2029': 'u2029',
9
15
  };
10
16
 
11
- const extend = (target, ...sources) => {
12
- return Object.assign(target, ...sources.filter(isPlainObject))
17
+ const htmlEntities = {
18
+ '&': '&',
19
+ '<': '&lt;',
20
+ '>': '&gt;',
21
+ '"': '&quot;',
22
+ "'": '&#x27;',
13
23
  };
14
24
 
15
- const Bundler = (params = {}, ejsParams = {}) => {
16
- const config = {
25
+ const regexKeys = (obj) =>
26
+ new RegExp(['[', Object.keys(obj).join(''), ']'].join(''), 'g');
27
+
28
+ regexKeys(htmlEntities);
29
+
30
+ regexKeys(symbolEntities);
31
+
32
+ const bindContext = (object, methods = []) => {
33
+ for (let i = 0, len = methods.length; i < len; i++) {
34
+ const name = methods[i];
35
+ if (name in object) {
36
+ object[name] = object[name].bind(object);
37
+ }
38
+ }
39
+ };
40
+
41
+ class Bundler {
42
+ #templates = {}
43
+ #bundlerOptions = {
17
44
  target: [],
18
45
  umd: true,
19
46
  minify: true,
20
- };
21
- const { compile, configure } = create();
22
- const ejsConfig = configure(ejsParams);
23
- const templates = {};
24
- extend(config, params || {});
25
- const stageRead = (path) => {
26
- return promises
27
- .readFile(join(ejsConfig.path, path))
47
+ }
48
+ #compile
49
+ #ejsOptions
50
+ #buildInProgress
51
+ static exports = ['build', 'watch', 'concat', 'output']
52
+ constructor(bundlerOptions = {}, ejsOptions = {}) {
53
+ bindContext(this, this.constructor.exports);
54
+ const { compile, configure } = create(ejsOptions);
55
+ Object.assign(this.#bundlerOptions, bundlerOptions);
56
+ this.#compile = compile;
57
+ this.#ejsOptions = configure();
58
+ this.#buildInProgress = false;
59
+ this.#templates = {};
60
+ }
61
+ async #stageRead(path) {
62
+ return fs
63
+ .readFile(join(this.#ejsOptions.path, path))
28
64
  .then((response) => response.toString())
29
- };
30
- const stageCompile = (content, name) => {
31
- return compile(content, name).source
32
- };
33
- const getBundle = () => {
34
- const umd = config.umd;
35
- const strict = ejsConfig.withObject === false;
36
- const module = ejsConfig.export;
65
+ }
66
+ #stageCompile(content, name) {
67
+ return this.#compile(content, name).source
68
+ }
69
+ #getBundle() {
70
+ const umd = this.#bundlerOptions.umd;
71
+ const strict = this.#ejsOptions.strict;
72
+ const module = this.#ejsOptions.precompiled;
37
73
  const out = [];
38
74
  if (umd) {
39
75
  out.push('(function(global,factory){');
@@ -52,7 +88,7 @@ const Bundler = (params = {}, ejsParams = {}) => {
52
88
  }
53
89
  if (strict) out.push(`'use strict'`);
54
90
  out.push('const templates = {}');
55
- Object.entries(templates).forEach(([name, content]) => {
91
+ Object.entries(this.#templates).forEach(([name, content]) => {
56
92
  name = JSON.stringify(name);
57
93
  content = String(content);
58
94
  out.push(`templates[${name}] = ${content}`);
@@ -63,79 +99,81 @@ const Bundler = (params = {}, ejsParams = {}) => {
63
99
  out.push('export default templates');
64
100
  }
65
101
  return out.join('\n')
66
- };
67
- const watch = async () => {
68
- console.log('🔍', 'watch directory:', ejsConfig.path);
69
- const pattern = '**/*.'.concat(ejsConfig.extension);
70
- const watcher = globWatch(pattern, { cwd: ejsConfig.path });
102
+ }
103
+ async build() {
104
+ if (this.#buildInProgress === true) return false
105
+ this.#buildInProgress = true;
106
+ await this.concat().catch(console.error);
107
+ await this.output().catch(console.error);
108
+ console.log('✅', 'bundle complete:', this.#bundlerOptions.target);
109
+ this.#buildInProgress = false;
110
+ }
111
+ async watch() {
112
+ console.log('🔍', 'watch directory:', this.#ejsOptions.path);
113
+ const pattern = '**/*.'.concat(this.#ejsOptions.extension);
114
+ const watcher = globWatch(pattern, { cwd: this.#ejsOptions.path });
71
115
  const state = { build: null };
72
116
  watcher.on('change', (path) => {
73
117
  if (state.build) return
74
118
  console.log('⟳', 'file change:', path);
75
- state.build = build().then(() => {
119
+ state.build = this.build().then(() => {
76
120
  state.build = null;
77
121
  });
78
122
  });
79
123
  watcher.on('add', (path) => {
80
124
  if (state.build) return
81
125
  console.log('+', 'file added:', path);
82
- state.build = build().then(() => {
126
+ state.build = this.build().then(() => {
83
127
  state.build = null;
84
128
  });
85
129
  });
86
- };
87
- const concat = async () => {
88
- const pattern = '**/*.'.concat(ejsConfig.extension);
89
- const list = await glob(pattern, { cwd: ejsConfig.path });
130
+ }
131
+ async concat() {
132
+ const pattern = '**/*.'.concat(this.#ejsOptions.extension);
133
+ const list = await glob(
134
+ pattern,
135
+ { cwd: this.#ejsOptions.path },
136
+ () => {},
137
+ );
90
138
  for (let template of list) {
91
139
  let content = '';
92
- content = await stageRead(template);
93
- content = await stageCompile(content, template);
94
- templates[template] = content;
140
+ content = await this.#stageRead(template);
141
+ content = await this.#stageCompile(content, template);
142
+ this.#templates[template] = content;
95
143
  }
96
- };
97
- const build = async () => {
98
- if (config.buildInProgress === true) return false
99
- config.buildInProgress = true;
100
- await concat().catch(console.error);
101
- await output().catch(console.error);
102
- console.log('✅', 'bundle complete:', config.target);
103
- config.buildInProgress = false;
104
- };
105
- const output = async () => {
106
- const target = [].concat(config.target);
107
- const content = getBundle();
108
- for (let file of target) {
144
+ }
145
+ async output() {
146
+ const target = [].concat(this.#bundlerOptions.target);
147
+ const content = this.#getBundle();
148
+ for (const file of target) {
109
149
  const folderPath = dirname(file);
110
- const folderExists = await promises
150
+ const folderExists = await fs
111
151
  .stat(folderPath)
112
152
  .then(() => true)
113
153
  .catch(() => false);
114
154
  if (folderExists === false) {
115
- await promises.mkdir(folderPath, { recursive: true });
155
+ await fs.mkdir(folderPath, { recursive: true });
116
156
  }
117
- await promises.writeFile(file, content);
157
+ await fs.writeFile(file, content);
118
158
  }
119
- };
120
- return {
121
- build,
122
- watch,
123
- concat,
124
- output,
125
159
  }
160
+ }
161
+
162
+ const bundler = (bundlerOptions = {}, ejsOptions = {}) => {
163
+ return new Bundler(bundlerOptions, ejsOptions)
126
164
  };
127
165
 
128
- const ejsBundler = (options, config) => {
129
- const bundler = new Bundler(options, config);
166
+ const ejsRollupBundler = (bundlerOptions, ejsOptions) => {
167
+ const bundle = new Bundler(bundlerOptions, ejsOptions);
130
168
  return {
131
169
  name: 'ejs-bundler',
132
170
  async buildStart() {
133
- await bundler.concat();
171
+ await bundle.concat();
134
172
  },
135
173
  async buildEnd() {
136
- await bundler.output();
174
+ await bundle.output();
137
175
  },
138
176
  }
139
177
  };
140
178
 
141
- export { Bundler, ejsBundler };
179
+ export { Bundler, bundler, ejsRollupBundler };
@@ -1,9 +1,3 @@
1
- const isUndefined = (v) => typeof v === 'undefined';
2
-
3
- Object.prototype.toString.call(
4
- typeof process !== 'undefined' ? process : 0,
5
- ) === '[object process]';
6
-
7
1
  const symbolEntities = {
8
2
  "'": "'",
9
3
  '\\': '\\',
@@ -45,38 +39,6 @@ const safeValue = (value, escape) => {
45
39
  : check
46
40
  };
47
41
 
48
- const each = (object, callback) => {
49
- let prop;
50
- for (prop in object) {
51
- if (hasProp(object, prop)) {
52
- callback(object[prop], prop, object);
53
- }
54
- }
55
- };
56
-
57
- const map = (object, callback, context) => {
58
- const result = [];
59
- each(
60
- object,
61
- (value, key, object) => {
62
- let item = callback(value, key, object);
63
- if (isUndefined(item) === false) {
64
- result.push(item);
65
- }
66
- });
67
- return result
68
- };
69
-
70
- /**
71
- *
72
- * @param object
73
- * @param prop
74
- * @return {boolean}
75
- */
76
- const hasProp = (object, prop) => {
77
- return object && object.hasOwnProperty(prop)
78
- };
79
-
80
42
  const selfClosed = [
81
43
  'area',
82
44
  'base',
@@ -101,20 +63,24 @@ const slash = '/';
101
63
  const lt = '<';
102
64
  const gt = '>';
103
65
 
66
+ const eachAttribute = ([key, value]) => {
67
+ if (value !== null && value !== undefined) {
68
+ return [entities(key), [quote, entities(value), quote].join('')].join(
69
+ equal,
70
+ )
71
+ }
72
+ };
73
+
104
74
  const element = (tag, attrs, content) => {
105
75
  const result = [];
106
76
  const hasClosedTag = selfClosed.indexOf(tag) === -1;
107
- const attributes = map(attrs, (value, key) => {
108
- if (value !== null && value !== undefined) {
109
- return [
110
- entities(key),
111
- [quote, entities(value), quote].join(''),
112
- ].join(equal)
113
- }
114
- }).join(space);
77
+ const attributes = Object.entries(attrs ?? {})
78
+ .map(eachAttribute)
79
+ .filter((e) => e)
80
+ .join(space);
115
81
  result.push([lt, tag, space, attributes, gt].join(''));
116
82
  if (content && hasClosedTag) {
117
- result.push(content instanceof Array ? content.join('') : content);
83
+ result.push(Array.isArray(content) ? content.join('') : content);
118
84
  }
119
85
  if (hasClosedTag) {
120
86
  result.push([lt, slash, tag, gt].join(''));