@kosatyi/ejs 0.0.112 → 0.0.114

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.
@@ -0,0 +1,27 @@
1
+ import { E as EjsInstance } from './index-BiIhwNBq.js';
2
+ import { j as joinPath } from './element-CEdJaM42.js';
3
+ export { e as element, a as escapeValue } from './element-CEdJaM42.js';
4
+
5
+ const resolver = async (path, template, error) => {
6
+ return fetch(joinPath(path, template)).then(
7
+ (response) => {
8
+ if (response.ok) return response.text()
9
+ return error(1, `template ${template} not found`)
10
+ },
11
+ (reason) => error(0, reason),
12
+ )
13
+ };
14
+
15
+ const {
16
+ render,
17
+ configure,
18
+ create,
19
+ helpers,
20
+ createContext,
21
+ compile,
22
+ preload,
23
+ } = new EjsInstance({
24
+ resolver,
25
+ });
26
+
27
+ export { compile, configure, create, createContext, helpers, preload, render };
@@ -0,0 +1,155 @@
1
+ import fs from 'node:fs/promises';
2
+ import globWatch from 'glob-watcher';
3
+ import { join, dirname } from 'node:path';
4
+ import { glob } from 'glob';
5
+ import { b as bindContext } from './element-CEdJaM42.js';
6
+ import { create } from './index.js';
7
+ import './index-BiIhwNBq.js';
8
+
9
+ class EjsBundler {
10
+ #templates = {}
11
+ #bundlerOptions = {
12
+ target: [],
13
+ umd: true,
14
+ minify: true,
15
+ }
16
+ #compile
17
+ #ejsOptions
18
+ #buildInProgress
19
+ static exports = ['build', 'watch', 'concat', 'output']
20
+
21
+ constructor(bundlerOptions = {}, ejsOptions = {}) {
22
+ bindContext(this, this.constructor.exports);
23
+ const { compile, configure } = create(ejsOptions);
24
+ Object.assign(this.#bundlerOptions, bundlerOptions);
25
+ this.#compile = compile;
26
+ this.#ejsOptions = configure({});
27
+ this.#buildInProgress = false;
28
+ this.#templates = {};
29
+ }
30
+
31
+ async #stageRead(path) {
32
+ return fs
33
+ .readFile(join(this.#ejsOptions.path, path))
34
+ .then((response) => response.toString())
35
+ }
36
+
37
+ #stageCompile(content, name) {
38
+ return this.#compile(content, name).source
39
+ }
40
+
41
+ #getBundle() {
42
+ const umd = this.#bundlerOptions.umd;
43
+ const strict = this.#ejsOptions.strict;
44
+ const module = this.#ejsOptions.precompiled;
45
+ const out = [];
46
+ if (umd) {
47
+ out.push('(function(global,factory){');
48
+ out.push(
49
+ 'typeof exports === "object" && typeof module !== "undefined" ?',
50
+ );
51
+ out.push('module.exports = factory():');
52
+ out.push(
53
+ 'typeof define === "function" && define.amd ? define(factory):',
54
+ );
55
+ out.push(
56
+ '(global = typeof globalThis !== "undefined" ? globalThis:',
57
+ );
58
+ out.push(`global || self,global["${module}"] = factory())`);
59
+ out.push('})(this,(function(){');
60
+ }
61
+ if (strict) out.push(`'use strict'`);
62
+ out.push('const templates = {}');
63
+ Object.entries(this.#templates).forEach(([name, content]) => {
64
+ name = JSON.stringify(name);
65
+ content = String(content);
66
+ out.push(`templates[${name}] = ${content}`);
67
+ });
68
+ if (umd) {
69
+ out.push('return templates}))');
70
+ } else {
71
+ out.push('export default templates');
72
+ }
73
+ return out.join('\n')
74
+ }
75
+
76
+ async build() {
77
+ if (this.#buildInProgress === true) return false
78
+ this.#buildInProgress = true;
79
+ await this.concat().catch(console.error);
80
+ await this.output().catch(console.error);
81
+ console.log('✅', 'bundle complete:', this.#bundlerOptions.target);
82
+ this.#buildInProgress = false;
83
+ }
84
+
85
+ async watch() {
86
+ console.log('🔍', 'watch directory:', this.#ejsOptions.path);
87
+ const pattern = '**/*.'.concat(this.#ejsOptions.extension);
88
+ const watcher = globWatch(pattern, { cwd: this.#ejsOptions.path });
89
+ const state = { build: null };
90
+ watcher.on('change', (path) => {
91
+ if (state.build) return
92
+ console.log('⟳', 'file change:', path);
93
+ state.build = this.build().then(() => {
94
+ state.build = null;
95
+ });
96
+ });
97
+ watcher.on('add', (path) => {
98
+ if (state.build) return
99
+ console.log('+', 'file added:', path);
100
+ state.build = this.build().then(() => {
101
+ state.build = null;
102
+ });
103
+ });
104
+ }
105
+
106
+ async concat() {
107
+ const pattern = '**/*.'.concat(this.#ejsOptions.extension);
108
+ const list = await glob(
109
+ pattern,
110
+ { cwd: this.#ejsOptions.path },
111
+ () => {},
112
+ );
113
+ for (let template of list) {
114
+ let content = '';
115
+ content = await this.#stageRead(template);
116
+ content = await this.#stageCompile(content, template);
117
+ this.#templates[template] = content;
118
+ }
119
+ }
120
+
121
+ async output() {
122
+ const target = [].concat(this.#bundlerOptions.target);
123
+ const content = this.#getBundle();
124
+ for (const file of target) {
125
+ const folderPath = dirname(file);
126
+ const folderExists = await fs
127
+ .stat(folderPath)
128
+ .then(() => true)
129
+ .catch(() => false);
130
+ if (folderExists === false) {
131
+ await fs.mkdir(folderPath, { recursive: true });
132
+ }
133
+ await fs.writeFile(file, content);
134
+ }
135
+ }
136
+ }
137
+
138
+ const bundler = (bundlerOptions = {}, ejsOptions = {}) => {
139
+ return new EjsBundler(bundlerOptions, ejsOptions)
140
+ };
141
+
142
+ const ejsRollupBundler = (bundlerOptions, ejsOptions) => {
143
+ const bundle = bundler(bundlerOptions, ejsOptions);
144
+ return {
145
+ name: 'ejs-bundler',
146
+ async buildStart() {
147
+ await bundle.concat();
148
+ },
149
+ async buildEnd() {
150
+ await bundle.output();
151
+ },
152
+ }
153
+ };
154
+
155
+ export { EjsBundler, bundler, ejsRollupBundler };
@@ -0,0 +1,178 @@
1
+ const jsVariableName = /^[a-zA-Z_$][0-9a-zA-Z_$]*$/;
2
+
3
+ const typeProp = function () {
4
+ const args = [].slice.call(arguments);
5
+ const callback = args.shift();
6
+ return args.filter(callback).pop()
7
+ };
8
+ const isArray = (value) => Array.isArray(value);
9
+ const isFunction = (value) => typeof value === 'function';
10
+ const isString = (value) => typeof value === 'string';
11
+ const isBoolean = (value) => typeof value === 'boolean';
12
+ const isArrayOfVariables = (value) => {
13
+ if (!isArray(value)) return false
14
+ return value.filter((name) => {
15
+ const valid = jsVariableName.test(name);
16
+ if (valid === false)
17
+ console.log(
18
+ `ejsConfig.globals: expected '${name}' to be valid variable name --> skipped`,
19
+ );
20
+ return valid
21
+ })
22
+ };
23
+
24
+ const symbolEntities = {
25
+ "'": "'",
26
+ '\\': '\\',
27
+ '\r': 'r',
28
+ '\n': 'n',
29
+ '\t': 't',
30
+ '\u2028': 'u2028',
31
+ '\u2029': 'u2029',
32
+ };
33
+
34
+ const htmlEntities = {
35
+ '&': '&',
36
+ '<': '&lt;',
37
+ '>': '&gt;',
38
+ '"': '&quot;',
39
+ "'": '&#x27;',
40
+ };
41
+
42
+ const regexKeys = (obj) =>
43
+ new RegExp(['[', Object.keys(obj).join(''), ']'].join(''), 'g');
44
+
45
+ const htmlEntitiesMatch = regexKeys(htmlEntities);
46
+
47
+ const symbolEntitiesMatch = regexKeys(symbolEntities);
48
+
49
+ const entities = (string = '') => {
50
+ return ('' + string).replace(
51
+ htmlEntitiesMatch,
52
+ (match) => htmlEntities[match],
53
+ )
54
+ };
55
+
56
+ const symbols = (string) => {
57
+ return ('' + string).replace(
58
+ symbolEntitiesMatch,
59
+ (match) => '\\' + symbolEntities[match],
60
+ )
61
+ };
62
+
63
+ const escapeValue = (value, escape) => {
64
+ const check = value;
65
+ return check == null
66
+ ? ''
67
+ : Boolean(escape) === true
68
+ ? entities(check)
69
+ : check
70
+ };
71
+
72
+ const getPath = (context, name, strict) => {
73
+ let data = context;
74
+ let chunks = String(name).split('.');
75
+ let prop = chunks.pop();
76
+ for (let i = 0; i < chunks.length; i++) {
77
+ const part = chunks[i];
78
+ if (isFunction(data['toJSON'])) {
79
+ data = data.toJSON();
80
+ }
81
+ if (strict && data.hasOwnProperty(part) === false) {
82
+ data = {};
83
+ break
84
+ }
85
+ data = data[part] = data[part] || {};
86
+ }
87
+ if (isFunction(data['toJSON'])) {
88
+ data = data.toJSON();
89
+ }
90
+ return [data, prop]
91
+ };
92
+
93
+ const each = (object, callback) => {
94
+ let prop;
95
+ for (prop in object) {
96
+ if (hasProp(object, prop)) {
97
+ callback(object[prop], prop, object);
98
+ }
99
+ }
100
+ };
101
+
102
+ const omit = (object, list) => {
103
+ const result = { ...object };
104
+ for (const key of list) {
105
+ delete result[key];
106
+ }
107
+ return result
108
+ };
109
+
110
+ const hasProp = (object, prop) => {
111
+ return object && Object.hasOwn(object, prop)
112
+ };
113
+
114
+ const joinPath = (path, template) => {
115
+ template = [path, template].join('/');
116
+ template = template.replace(/\/\//g, '/');
117
+ return template
118
+ };
119
+
120
+ const bindContext = (object, methods = []) => {
121
+ for (let i = 0, len = methods.length; i < len; i++) {
122
+ const name = methods[i];
123
+ if (name in object) {
124
+ object[name] = object[name].bind(object);
125
+ }
126
+ }
127
+ };
128
+
129
+ const selfClosed = [
130
+ 'area',
131
+ 'base',
132
+ 'br',
133
+ 'col',
134
+ 'embed',
135
+ 'hr',
136
+ 'img',
137
+ 'input',
138
+ 'link',
139
+ 'meta',
140
+ 'param',
141
+ 'source',
142
+ 'track',
143
+ 'wbr',
144
+ ];
145
+
146
+ const space = ' ';
147
+ const quote = '"';
148
+ const equal = '=';
149
+ const slash = '/';
150
+ const lt = '<';
151
+ const gt = '>';
152
+
153
+ const eachAttribute = ([key, value]) => {
154
+ if (value !== null && value !== undefined) {
155
+ return [entities(key), [quote, entities(value), quote].join('')].join(
156
+ equal,
157
+ )
158
+ }
159
+ };
160
+
161
+ const element = (tag, attrs, content) => {
162
+ const result = [];
163
+ const hasClosedTag = selfClosed.indexOf(tag) === -1;
164
+ const attributes = Object.entries(attrs ?? {})
165
+ .map(eachAttribute)
166
+ .filter((e) => e)
167
+ .join(space);
168
+ result.push([lt, tag, space, attributes, gt].join(''));
169
+ if (content && hasClosedTag) {
170
+ result.push(Array.isArray(content) ? content.join('') : content);
171
+ }
172
+ if (hasClosedTag) {
173
+ result.push([lt, slash, tag, gt].join(''));
174
+ }
175
+ return result.join('')
176
+ };
177
+
178
+ export { escapeValue as a, bindContext as b, isString as c, isBoolean as d, element as e, isArrayOfVariables as f, isArray as g, each as h, isFunction as i, joinPath as j, getPath as k, hasProp as l, omit as o, symbols as s, typeProp as t };
@@ -0,0 +1 @@
1
+ export { e as element, a as escapeValue } from './element-CEdJaM42.js';
@@ -0,0 +1,785 @@
1
+ import { t as typeProp, f as isArrayOfVariables, g as isArray, d as isBoolean, c as isString, i as isFunction, b as bindContext, s as symbols, e as element, h as each, k as getPath, l as hasProp, o as omit, a as escapeValue } from './element-CEdJaM42.js';
2
+
3
+ /**
4
+ * @type {EjsConfig}
5
+ */
6
+ const ejsDefaults = {
7
+ precompiled: 'ejsPrecompiled',
8
+ cache: true,
9
+ path: 'views',
10
+ extension: 'ejs',
11
+ rmWhitespace: true,
12
+ strict: true,
13
+ resolver: (path, template) => {
14
+ return Promise.resolve(
15
+ ['resolver is not defined', path, template].join(' '),
16
+ )
17
+ },
18
+ globals: [],
19
+ vars: {
20
+ SCOPE: 'ejs',
21
+ COMPONENT: 'ui',
22
+ ELEMENT: 'el',
23
+ EXTEND: '$$e',
24
+ BUFFER: '$$a',
25
+ LAYOUT: '$$l',
26
+ BLOCKS: '$$b',
27
+ MACRO: '$$m',
28
+ SAFE: '$$v',
29
+ },
30
+ token: {
31
+ start: '<%',
32
+ end: '%>',
33
+ regex: '([\\s\\S]+?)',
34
+ },
35
+ };
36
+
37
+ const configSchema = (config, options) => {
38
+ return Object.assign(config, {
39
+ path: typeProp(isString, ejsDefaults.path, config.path, options.path),
40
+ precompiled: typeProp(
41
+ isString,
42
+ ejsDefaults.precompiled,
43
+ config.export,
44
+ options.export,
45
+ ),
46
+ resolver: typeProp(
47
+ isFunction,
48
+ ejsDefaults.resolver,
49
+ config.resolver,
50
+ options.resolver,
51
+ ),
52
+ extension: typeProp(
53
+ isString,
54
+ ejsDefaults.extension,
55
+ config.extension,
56
+ options.extension,
57
+ ),
58
+ strict: typeProp(
59
+ isBoolean,
60
+ ejsDefaults.strict,
61
+ config.strict,
62
+ options.strict,
63
+ ),
64
+ rmWhitespace: typeProp(
65
+ isBoolean,
66
+ ejsDefaults.rmWhitespace,
67
+ config.rmWhitespace,
68
+ options.rmWhitespace,
69
+ ),
70
+ cache: typeProp(
71
+ isBoolean,
72
+ ejsDefaults.cache,
73
+ config.cache,
74
+ options.cache,
75
+ ),
76
+ globals: typeProp(
77
+ isArray,
78
+ ejsDefaults.globals,
79
+ config.globals,
80
+ isArrayOfVariables(options.globals),
81
+ ),
82
+ token: Object.assign(
83
+ {},
84
+ ejsDefaults.token,
85
+ config.token,
86
+ options.token,
87
+ ),
88
+ vars: Object.assign({}, ejsDefaults.vars, config.vars, options.vars),
89
+ })
90
+ };
91
+
92
+ class EjsError extends Error {
93
+ constructor(code, content) {
94
+ super(content);
95
+ this.code = code;
96
+ if (content instanceof Error) {
97
+ this.stack = content.stack;
98
+ this.message = content.message;
99
+ }
100
+ }
101
+ }
102
+
103
+ const error = (code, content) => {
104
+ throw new EjsError(code, content)
105
+ };
106
+
107
+ class EjsTemplate {
108
+ #path
109
+ #resolver
110
+ #cache
111
+ #compiler
112
+ static exports = ['configure', 'get']
113
+ constructor(options, cache, compiler) {
114
+ bindContext(this, this.constructor.exports);
115
+ this.#cache = cache;
116
+ this.#compiler = compiler;
117
+ this.configure(options ?? {});
118
+ }
119
+ configure(options) {
120
+ this.#path = options.path;
121
+ if (isFunction(options.resolver)) {
122
+ this.#resolver = options.resolver;
123
+ }
124
+ }
125
+ #resolve(template) {
126
+ const cached = this.#cache.get(template);
127
+ if (cached instanceof Promise) return cached
128
+ const result = Promise.resolve(
129
+ this.#resolver(this.#path, template, error),
130
+ );
131
+ this.#cache.set(template, result);
132
+ return result
133
+ }
134
+ #compile(content, template) {
135
+ const cached = this.#cache.get(template);
136
+ if (typeof cached === 'function') return cached
137
+ if (typeof content === 'string') {
138
+ content = this.#compiler.compile(content, template);
139
+ }
140
+ if (typeof content === 'function') {
141
+ this.#cache.set(template, content);
142
+ return content
143
+ }
144
+ }
145
+ get(template) {
146
+ return this.#resolve(template).then((content) => {
147
+ return this.#compile(content, template)
148
+ })
149
+ }
150
+ }
151
+
152
+ const tokenList = [
153
+ ['-', (v, b, s) => `')\n${b}(${s}(${v},1))\n${b}('`],
154
+ ['=', (v, b, s) => `')\n${b}(${s}(${v}))\n${b}('`],
155
+ ['#', (v, b) => `')\n/**${v}**/\n${b}('`],
156
+ ['', (v, b) => `')\n${v}\n${b}('`],
157
+ ];
158
+
159
+ const tokensMatch = (regex, content, callback) => {
160
+ let index = 0;
161
+ content.replace(regex, function () {
162
+ const params = [].slice.call(arguments, 0, -1);
163
+ const offset = params.pop();
164
+ const match = params.shift();
165
+ callback(params, index, offset);
166
+ index = offset + match.length;
167
+ return match
168
+ });
169
+ };
170
+
171
+ class EjsCompiler {
172
+ #config = {}
173
+ static exports = ['configure', 'compile']
174
+ constructor(options) {
175
+ bindContext(this, this.constructor.exports);
176
+ this.configure(options);
177
+ }
178
+ configure(options) {
179
+ this.#config.strict = options.strict;
180
+ this.#config.rmWhitespace = options.rmWhitespace;
181
+ this.#config.token = options.token;
182
+ this.#config.vars = options.vars;
183
+ this.#config.globals = options.globals;
184
+ this.#config.legacy = options.legacy ?? true;
185
+ this.#config.slurp = {
186
+ match: '[s\t\n]*',
187
+ start: [this.#config.token.start, '_'],
188
+ end: ['_', this.#config.token.end],
189
+ };
190
+ this.#config.matches = [];
191
+ this.#config.formats = [];
192
+ for (const [symbol, format] of tokenList) {
193
+ this.#config.matches.push(
194
+ this.#config.token.start
195
+ .concat(symbol)
196
+ .concat(this.#config.token.regex)
197
+ .concat(this.#config.token.end),
198
+ );
199
+ this.#config.formats.push(format);
200
+ }
201
+ this.#config.regex = new RegExp(
202
+ this.#config.matches.join('|').concat('|$'),
203
+ 'g',
204
+ );
205
+ this.#config.slurpStart = new RegExp(
206
+ [this.#config.slurp.match, this.#config.slurp.start.join('')].join(
207
+ '',
208
+ ),
209
+ 'gm',
210
+ );
211
+ this.#config.slurpEnd = new RegExp(
212
+ [this.#config.slurp.end.join(''), this.#config.slurp.match].join(
213
+ '',
214
+ ),
215
+ 'gm',
216
+ );
217
+ if (this.#config.globals.length) {
218
+ if (this.#config.legacy) {
219
+ this.#config.globalVariables = `const ${this.#config.globals
220
+ .map((name) => `${name}=${this.#config.vars.SCOPE}.${name}`)
221
+ .join(',')};`;
222
+ } else {
223
+ this.#config.globalVariables = `const {${this.#config.globals.join(',')}} = ${this.#config.vars.SCOPE};`;
224
+ }
225
+ }
226
+ }
227
+ compile(content, path) {
228
+ const GLOBALS = this.#config.globalVariables;
229
+ const { SCOPE, SAFE, BUFFER, COMPONENT, ELEMENT } = this.#config.vars;
230
+ if (this.#config.rmWhitespace) {
231
+ content = String(content)
232
+ .replace(/[\r\n]+/g, '\n')
233
+ .replace(/^\s+|\s+$/gm, '');
234
+ }
235
+ content = String(content)
236
+ .replace(this.#config.slurpStart, this.#config.token.start)
237
+ .replace(this.#config.slurpEnd, this.#config.token.end);
238
+ let OUTPUT = `${BUFFER}('`;
239
+ tokensMatch(this.#config.regex, content, (params, index, offset) => {
240
+ OUTPUT += symbols(content.slice(index, offset));
241
+ params.forEach((value, index) => {
242
+ if (value) {
243
+ OUTPUT += this.#config.formats[index](
244
+ value.trim(),
245
+ BUFFER,
246
+ SAFE,
247
+ );
248
+ }
249
+ });
250
+ });
251
+ OUTPUT += `');`;
252
+ OUTPUT = `try{${OUTPUT}}catch(e){return ${BUFFER}.error(e)}`;
253
+ if (this.#config.strict === false) {
254
+ OUTPUT = `with(${SCOPE}){${OUTPUT}}`;
255
+ }
256
+ OUTPUT = `${BUFFER}.start();${OUTPUT}return ${BUFFER}.end();`;
257
+ OUTPUT += `\n//# sourceURL=${path}`;
258
+ if (GLOBALS) {
259
+ OUTPUT = `${GLOBALS}\n${OUTPUT}`;
260
+ }
261
+ try {
262
+ const params = [SCOPE, COMPONENT, ELEMENT, BUFFER, SAFE];
263
+ const result = Function.apply(null, params.concat(OUTPUT));
264
+ result.source = `(function(${params.join(',')}){\n${OUTPUT}\n});`;
265
+ return result
266
+ } catch (e) {
267
+ e.filename = path;
268
+ e.source = OUTPUT;
269
+ error(0, e);
270
+ }
271
+ }
272
+ }
273
+
274
+ class EjsCache {
275
+ static exports = [
276
+ 'load',
277
+ 'set',
278
+ 'get',
279
+ 'exist',
280
+ 'clear',
281
+ 'remove',
282
+ 'resolve',
283
+ ]
284
+ #cache = true
285
+ #precompiled
286
+ #list = {}
287
+ constructor(options) {
288
+ bindContext(this, this.constructor.exports);
289
+ this.configure(options);
290
+ }
291
+ get(key) {
292
+ if (this.#cache) {
293
+ return this.#list[key]
294
+ }
295
+ }
296
+ set(key, value) {
297
+ if (this.#cache) {
298
+ this.#list[key] = value;
299
+ }
300
+ }
301
+ exist(key) {
302
+ if (this.#cache) {
303
+ return this.#list.hasOwnProperty(key)
304
+ }
305
+ }
306
+ clear() {
307
+ Object.keys(this.#list).forEach(this.remove);
308
+ }
309
+ remove(key) {
310
+ delete this.#list[key];
311
+ }
312
+ resolve(key) {
313
+ return Promise.resolve(this.get(key))
314
+ }
315
+ load(data) {
316
+ if (this.#cache) {
317
+ Object.assign(this.#list, data || {});
318
+ }
319
+ }
320
+ configure(options) {
321
+ this.#cache = options.cache;
322
+ this.#precompiled = options.precompiled;
323
+ if (typeof window === 'object') {
324
+ this.load(window[this.#precompiled]);
325
+ }
326
+ }
327
+ }
328
+
329
+ const resolve = (list) => {
330
+ return Promise.all(list || [])
331
+ .then((list) => list.join(''))
332
+ .catch((e) => error(0, e))
333
+ };
334
+
335
+ const reject = (e) => {
336
+ return Promise.reject(error(0, e))
337
+ };
338
+
339
+ const EjsBuffer = () => {
340
+ let store = [];
341
+ let array = [];
342
+ /**
343
+ *
344
+ * @param value
345
+ * @constructor
346
+ */
347
+ const EjsBuffer = (value) => {
348
+ array.push(value);
349
+ };
350
+ EjsBuffer.start = () => {
351
+ array = [];
352
+ };
353
+ EjsBuffer.backup = () => {
354
+ store.push(array.concat());
355
+ array = [];
356
+ };
357
+ EjsBuffer.restore = () => {
358
+ const result = array.concat();
359
+ array = store.pop();
360
+ return resolve(result)
361
+ };
362
+ EjsBuffer.error = (e) => {
363
+ return reject(e)
364
+ };
365
+ EjsBuffer.end = () => {
366
+ return resolve(array)
367
+ };
368
+ return EjsBuffer
369
+ };
370
+
371
+ const PARENT = Symbol('EjsContext.parentTemplate');
372
+
373
+ const createContext = (config, methods) => {
374
+ const globals = config.globals || [];
375
+ const {
376
+ BLOCKS,
377
+ MACRO,
378
+ EXTEND,
379
+ LAYOUT,
380
+ BUFFER,
381
+ SAFE,
382
+ SCOPE,
383
+ COMPONENT,
384
+ ELEMENT,
385
+ } = config.vars;
386
+ class Context {
387
+ constructor(data) {
388
+ this[PARENT] = null;
389
+ this[BLOCKS] = {};
390
+ this[MACRO] = {};
391
+ Object.assign(
392
+ this,
393
+ omit(data, [SCOPE, BUFFER, SAFE, COMPONENT, ELEMENT]),
394
+ );
395
+ }
396
+ }
397
+ Object.defineProperties(Context.prototype, {
398
+ [BUFFER]: {
399
+ value: EjsBuffer(),
400
+ },
401
+ [BLOCKS]: {
402
+ value: {},
403
+ writable: true,
404
+ },
405
+ [MACRO]: {
406
+ value: {},
407
+ writable: true,
408
+ },
409
+ [LAYOUT]: {
410
+ value: false,
411
+ writable: true,
412
+ },
413
+ [EXTEND]: {
414
+ value: false,
415
+ writable: true,
416
+ },
417
+ [PARENT]: {
418
+ value: null,
419
+ writable: true,
420
+ },
421
+ setParentTemplate: {
422
+ value(value) {
423
+ this[PARENT] = value;
424
+ return this
425
+ },
426
+ },
427
+ getParentTemplate: {
428
+ value() {
429
+ return this[PARENT]
430
+ },
431
+ },
432
+ useEscapeValue: {
433
+ value() {
434
+ return escapeValue
435
+ },
436
+ },
437
+ useComponent: {
438
+ value() {
439
+ if (isFunction(this[COMPONENT])) {
440
+ return this[COMPONENT].bind(this)
441
+ } else {
442
+ return function () {
443
+ error(2, `${COMPONENT} must be a function`);
444
+ }
445
+ }
446
+ },
447
+ },
448
+ useElement: {
449
+ value() {
450
+ if (isFunction(this[ELEMENT])) {
451
+ return this[ELEMENT].bind(this)
452
+ } else {
453
+ return () => {
454
+ error(2, `${ELEMENT} must be a function`);
455
+ }
456
+ }
457
+ },
458
+ },
459
+ useBuffer: {
460
+ value() {
461
+ return this[BUFFER]
462
+ },
463
+ },
464
+ getMacro: {
465
+ value() {
466
+ return this[MACRO]
467
+ },
468
+ },
469
+ getBlocks: {
470
+ value() {
471
+ return this[BLOCKS]
472
+ },
473
+ },
474
+ setExtend: {
475
+ value(value) {
476
+ this[EXTEND] = value;
477
+ return this
478
+ },
479
+ },
480
+ getExtend: {
481
+ value() {
482
+ return this[EXTEND]
483
+ },
484
+ },
485
+ setLayout: {
486
+ value(layout) {
487
+ this[LAYOUT] = layout;
488
+ return this
489
+ },
490
+ },
491
+ getLayout: {
492
+ value() {
493
+ return this[LAYOUT]
494
+ },
495
+ },
496
+ clone: {
497
+ value(exclude_blocks) {
498
+ const filter = [LAYOUT, EXTEND, BUFFER];
499
+ if (exclude_blocks === true) {
500
+ filter.push(BLOCKS);
501
+ }
502
+ return omit(this, filter)
503
+ },
504
+ },
505
+ extend: {
506
+ value(layout) {
507
+ this.setExtend(true);
508
+ this.setLayout(layout);
509
+ },
510
+ },
511
+ echo: {
512
+ value() {
513
+ return [].slice.call(arguments).forEach(this.useBuffer())
514
+ },
515
+ },
516
+ fn: {
517
+ value(callback) {
518
+ const buffer = this.useBuffer();
519
+ const context = this;
520
+ return function () {
521
+ if (isFunction(callback)) {
522
+ buffer.backup();
523
+ buffer(callback.apply(context, arguments));
524
+ return buffer.restore()
525
+ }
526
+ }
527
+ },
528
+ },
529
+ macro: {
530
+ value(name, callback) {
531
+ const list = this.getMacro();
532
+ const macro = this.fn(callback);
533
+ const context = this;
534
+ list[name] = function () {
535
+ return context.echo(macro.apply(undefined, arguments))
536
+ };
537
+ },
538
+ },
539
+ call: {
540
+ value(name) {
541
+ const list = this.getMacro();
542
+ const macro = list[name];
543
+ const params = [].slice.call(arguments, 1);
544
+ if (isFunction(macro)) {
545
+ return macro.apply(macro, params)
546
+ }
547
+ },
548
+ },
549
+ block: {
550
+ value(name, callback) {
551
+ const blocks = this.getBlocks();
552
+ blocks[name] = blocks[name] || [];
553
+ blocks[name].push(this.fn(callback));
554
+ if (this.getExtend()) return
555
+ const context = this;
556
+ const list = Object.assign([], blocks[name]);
557
+ const shift = function () {
558
+ return list.shift()
559
+ };
560
+ const next = function () {
561
+ const parent = shift();
562
+ if (parent) {
563
+ return function () {
564
+ context.echo(parent(next()));
565
+ }
566
+ } else {
567
+ return function () {}
568
+ }
569
+ };
570
+ this.echo(shift()(next()));
571
+ },
572
+ },
573
+ hasBlock: {
574
+ value(name) {
575
+ return this.getBlocks().hasOwnProperty(name)
576
+ },
577
+ },
578
+ include: {
579
+ value(path, data, cx) {
580
+ const context = cx === false ? {} : this.clone(true);
581
+ const params = Object.assign(context, data || {});
582
+ const promise = this.render(path, params);
583
+ this.echo(promise);
584
+ },
585
+ },
586
+ use: {
587
+ value(path, namespace) {
588
+ this.echo(
589
+ Promise.resolve(this.require(path)).then((exports$1) => {
590
+ const list = this.getMacro();
591
+ each(exports$1, (macro, name) => {
592
+ list[[namespace, name].join('.')] = macro;
593
+ });
594
+ }),
595
+ );
596
+ },
597
+ },
598
+ get: {
599
+ value(name, defaults) {
600
+ const path = getPath(this, name, true);
601
+ const result = path.shift();
602
+ const prop = path.pop();
603
+ return hasProp(result, prop) ? result[prop] : defaults
604
+ },
605
+ },
606
+ set: {
607
+ value(name, value) {
608
+ const path = getPath(this, name, false);
609
+ const result = path.shift();
610
+ const prop = path.pop();
611
+ if (this.getParentTemplate() && hasProp(result, prop)) {
612
+ return result[prop]
613
+ }
614
+ return (result[prop] = value)
615
+ },
616
+ },
617
+ each: {
618
+ value(object, callback) {
619
+ if (isString(object)) {
620
+ object = this.get(object, []);
621
+ }
622
+ each(object, callback);
623
+ },
624
+ writable: true,
625
+ },
626
+ el: {
627
+ value(tag, attr, content) {
628
+ content = isFunction(content) ? this.fn(content)() : content;
629
+ this.echo(
630
+ Promise.resolve(content).then((content) =>
631
+ element(tag, attr, content),
632
+ ),
633
+ );
634
+ },
635
+ writable: true,
636
+ },
637
+ ui: {
638
+ value() {},
639
+ writable: true,
640
+ },
641
+ require: {
642
+ value() {},
643
+ writable: true,
644
+ },
645
+ render: {
646
+ value() {},
647
+ writable: true,
648
+ },
649
+ });
650
+ Object.entries(methods).forEach(([name, value]) => {
651
+ if (isFunction(value) && globals.includes(name)) {
652
+ value = value.bind(Context.prototype);
653
+ }
654
+ Context.prototype[name] = value;
655
+ });
656
+ return Context
657
+ };
658
+
659
+ class EjsContext {
660
+ #context
661
+ static exports = ['create', 'globals', 'helpers']
662
+ constructor(options, methods) {
663
+ bindContext(this, this.constructor.exports);
664
+ this.configure(options, methods);
665
+ }
666
+ create(data) {
667
+ return new this.#context(data)
668
+ }
669
+ helpers(methods) {
670
+ Object.assign(this.#context.prototype, methods);
671
+ }
672
+ configure(options, methods) {
673
+ this.#context = createContext(options, methods);
674
+ }
675
+ }
676
+
677
+ class EjsInstance {
678
+ #cache
679
+ #context
680
+ #compiler
681
+ #template
682
+ #config = {}
683
+ #methods = {}
684
+ static exports = [
685
+ 'configure',
686
+ 'create',
687
+ 'createContext',
688
+ 'render',
689
+ 'require',
690
+ 'preload',
691
+ 'compile',
692
+ 'helpers',
693
+ ]
694
+ /**
695
+ *
696
+ * @param {EjsConfig} options
697
+ */
698
+ constructor(options = {}) {
699
+ bindContext(this, this.constructor.exports);
700
+ this.#methods = {};
701
+ this.#config = configSchema({}, options);
702
+ this.#context = new EjsContext(this.#config, this.#methods);
703
+ this.#compiler = new EjsCompiler(this.#config);
704
+ this.#cache = new EjsCache(this.#config);
705
+ this.#template = new EjsTemplate(
706
+ this.#config,
707
+ this.#cache,
708
+ this.#compiler,
709
+ );
710
+ this.helpers({ render: this.render, require: this.require });
711
+ }
712
+ create(options) {
713
+ return new this.constructor(options)
714
+ }
715
+ configure(options) {
716
+ if (options) {
717
+ configSchema(this.#config, options);
718
+ this.#context.configure(this.#config, this.#methods);
719
+ this.#compiler.configure(this.#config);
720
+ this.#cache.configure(this.#config);
721
+ this.#template.configure(this.#config);
722
+ }
723
+ return this.#config
724
+ }
725
+ createContext(data) {
726
+ return this.#context.create(data)
727
+ }
728
+ preload(list) {
729
+ return this.#cache.load(list || {})
730
+ }
731
+ compile(content, path) {
732
+ return this.#compiler.compile(content, path)
733
+ }
734
+ helpers(methods) {
735
+ this.#context.helpers(Object.assign(this.#methods, methods));
736
+ }
737
+ async render(name, params) {
738
+ const data = this.createContext(params);
739
+ return this.#output(this.#path(name), data).then(
740
+ this.#outputContent(name, data),
741
+ )
742
+ }
743
+ async require(name) {
744
+ const data = this.createContext({});
745
+ return this.#output(this.#path(name), data).then(() => data.getMacro())
746
+ }
747
+ #path(name) {
748
+ const ext = name.split('.').pop();
749
+ if (ext !== this.#config.extension) {
750
+ name = [name, this.#config.extension].join('.');
751
+ }
752
+ return name
753
+ }
754
+ #output(path, data) {
755
+ return this.#template
756
+ .get(path)
757
+ .then((callback) =>
758
+ callback.apply(data, [
759
+ data,
760
+ data.useComponent(),
761
+ data.useElement(),
762
+ data.useBuffer(),
763
+ data.useEscapeValue(),
764
+ ]),
765
+ )
766
+ }
767
+ #renderLayout(name, params, parentTemplate) {
768
+ const data = this.createContext(params);
769
+ if (parentTemplate) data.setParentTemplate(parentTemplate);
770
+ return this.#output(this.#path(name), data).then(
771
+ this.#outputContent(name, data),
772
+ )
773
+ }
774
+ #outputContent(name, data) {
775
+ return (content) => {
776
+ if (data.getExtend()) {
777
+ data.setExtend(false);
778
+ return this.#renderLayout(data.getLayout(), data, name)
779
+ }
780
+ return content
781
+ }
782
+ }
783
+ }
784
+
785
+ export { EjsInstance as E, ejsDefaults as e };
@@ -0,0 +1,58 @@
1
+ import fs from 'node:fs/promises';
2
+ import path from 'node:path';
3
+ import { j as joinPath, t as typeProp, c as isString, d as isBoolean, i as isFunction } from './element-CEdJaM42.js';
4
+ export { e as element, a as escapeValue } from './element-CEdJaM42.js';
5
+ import { E as EjsInstance, e as ejsDefaults } from './index-BiIhwNBq.js';
6
+
7
+ const resolver = async (path, template, error) => {
8
+ return fs
9
+ .readFile(joinPath(path, template))
10
+ .then((contents) => contents.toString())
11
+ .catch((e) => {
12
+ if (e.code === 'ENOENT') {
13
+ return error(1, `template ${template} not found`)
14
+ }
15
+ return error(0, e)
16
+ })
17
+ };
18
+
19
+ const {
20
+ render,
21
+ helpers,
22
+ configure,
23
+ create,
24
+ createContext,
25
+ compile,
26
+ preload,
27
+ } = new EjsInstance({
28
+ resolver,
29
+ });
30
+
31
+ const __express = function (name, options, callback) {
32
+ if (isFunction(options)) {
33
+ callback = options;
34
+ options = {};
35
+ }
36
+ options = options || {};
37
+ const settings = Object.assign({}, options.settings);
38
+ const viewPath = typeProp(isString, ejsDefaults.path, settings['views']);
39
+ const viewCache = typeProp(
40
+ isBoolean,
41
+ ejsDefaults.cache,
42
+ settings['view cache'],
43
+ );
44
+ const viewOptions = Object.assign({}, settings['view options']);
45
+ const filename = path.relative(viewPath, name);
46
+ viewOptions.path = viewPath;
47
+ viewOptions.cache = viewCache;
48
+ configure(viewOptions);
49
+ return render(filename, options)
50
+ .then((content) => {
51
+ callback(null, content);
52
+ })
53
+ .catch((error) => {
54
+ callback(error);
55
+ })
56
+ };
57
+
58
+ export { __express, compile, configure, create, createContext, helpers, preload, render };
@@ -0,0 +1,46 @@
1
+ import { i as isFunction } from './element-CEdJaM42.js';
2
+ export { e as element, a as escapeValue } from './element-CEdJaM42.js';
3
+ import { E as EjsInstance } from './index-BiIhwNBq.js';
4
+
5
+ const templateCache = {};
6
+
7
+ const getOrigin = (url, secure) => {
8
+ url = URL.parse(url);
9
+ url.protocol = secure ? 'https:' : 'http:';
10
+ return url.origin
11
+ };
12
+
13
+ const resolver = async (path, name, error) => {
14
+ if (isFunction(templateCache[name])) {
15
+ return templateCache[name]
16
+ }
17
+ error(1, `template ${name} not found`);
18
+ };
19
+
20
+ const { render, createContext, helpers, configure } = new EjsInstance({
21
+ cache: false,
22
+ strict: true,
23
+ resolver,
24
+ });
25
+
26
+ function useTemplates(templates = {}) {
27
+ Object.assign(templateCache, templates);
28
+ }
29
+
30
+ function useRenderer(options = {}) {
31
+ useTemplates(options.templates ?? {});
32
+ return async (c, next) => {
33
+ c.data = createContext({});
34
+ c.data.set('version', options.version);
35
+ c.data.set('origin', getOrigin(c.req.url, options.secure ?? true));
36
+ c.data.set('path', c.req.path);
37
+ c.data.set('query', c.req.query());
38
+ c.ejs = async (name, data) =>
39
+ render(name, Object.assign({ param: c.req.param() }, c.data, data));
40
+ c.helpers = (methods) => helpers(methods);
41
+ c.render = async (name, data) => c.html(c.ejs(name, data));
42
+ await next();
43
+ }
44
+ }
45
+
46
+ export { configure, createContext, helpers, render, useRenderer, useTemplates };
package/package.json CHANGED
@@ -3,7 +3,7 @@
3
3
  "description": "EJS Templates",
4
4
  "homepage": "https://github.com/kosatyi/ejs",
5
5
  "type": "module",
6
- "version": "0.0.112",
6
+ "version": "0.0.114",
7
7
  "main": "dist/cjs/index.js",
8
8
  "module": "dist/esm/index.js",
9
9
  "browser": "dist/umd/browser.js",
@@ -1,3 +1,4 @@
1
+ export { element, escapeValue } from './element.js'
1
2
  export {
2
3
  create,
3
4
  render,
@@ -1,6 +1,4 @@
1
- import { EjsMethods } from './ejs'
2
-
3
- export interface EjsContext extends EjsMethods {
1
+ export interface EjsContext {
4
2
  /**
5
3
  * extend layout with blocks in current template file
6
4
  * @param layout
package/types/ejs.d.ts CHANGED
@@ -1,6 +1,6 @@
1
1
  import { EjsContext } from './context.js'
2
2
  import { error } from './error.js'
3
- import { element, escapeValue } from './element.js'
3
+
4
4
  export declare type EjsConfigVars = {
5
5
  SCOPE: string
6
6
  COMPONENT: string
@@ -78,8 +78,6 @@ declare type configure = <T extends EjsConfig>(options?: T) => EjsConfig & T
78
78
 
79
79
  declare type compile = (content: string, path: string) => Function
80
80
 
81
- declare type EjsMethods = { [p: string]: any }
82
-
83
81
  declare type createContext = (data: { [p: string]: any }) => EjsContext
84
82
 
85
83
  declare type render = (
@@ -91,9 +89,7 @@ declare type require = (name: string) => Promise<{ [x: string]: any }>
91
89
 
92
90
  declare type preload = (list: { [p: string]: any }) => void
93
91
 
94
- declare type helpers<T extends EjsMethods> = (
95
- extendMethods: T,
96
- ) => EjsContext & T
92
+ declare type helpers = (extendMethods: Record<string, any>) => EjsContext
97
93
 
98
94
  declare type create = (config: EjsConfig) => EjsInstance
99
95
 
@@ -105,9 +101,7 @@ declare type EjsInterface = {
105
101
  require: require
106
102
  preload: preload
107
103
  compile: compile
108
- helpers: helpers<EjsMethods>
109
- element: typeof element
110
- escapeValue: typeof escapeValue
104
+ helpers: helpers
111
105
  }
112
106
 
113
107
  declare type EjsInstance = (config: EjsConfig) => EjsInterface
@@ -122,7 +116,7 @@ export const require: require
122
116
 
123
117
  export const preload: preload
124
118
 
125
- export const helpers: helpers<EjsMethods>
119
+ export const helpers: helpers
126
120
 
127
121
  export const compile: compile
128
122
 
package/types/index.d.ts CHANGED
@@ -1,3 +1,5 @@
1
+ export { element, escapeValue } from './element.js'
2
+
1
3
  export {
2
4
  create,
3
5
  render,
package/types/worker.d.ts CHANGED
@@ -1,3 +1,5 @@
1
+ export { element, escapeValue } from './element.js'
2
+
1
3
  export {
2
4
  create,
3
5
  render,