@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.
- package/dist/types/browser.d.ts +27 -0
- package/dist/types/bundler.d.ts +155 -0
- package/dist/types/element-CEdJaM42.d.ts +178 -0
- package/dist/types/element.d.ts +1 -0
- package/dist/types/index-BiIhwNBq.d.ts +785 -0
- package/dist/types/index.d.ts +58 -0
- package/dist/types/worker.d.ts +46 -0
- package/package.json +1 -1
- package/types/browser.d.ts +1 -0
- package/types/context.d.ts +1 -3
- package/types/ejs.d.ts +4 -10
- package/types/index.d.ts +2 -0
- package/types/worker.d.ts +2 -0
|
@@ -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
|
+
'<': '<',
|
|
37
|
+
'>': '>',
|
|
38
|
+
'"': '"',
|
|
39
|
+
"'": ''',
|
|
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
package/types/browser.d.ts
CHANGED
package/types/context.d.ts
CHANGED
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
|
-
|
|
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<
|
|
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
|
|
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
|
|
119
|
+
export const helpers: helpers
|
|
126
120
|
|
|
127
121
|
export const compile: compile
|
|
128
122
|
|
package/types/index.d.ts
CHANGED