mancha 0.5.0 → 0.5.1
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/.vscode/launch.json +44 -0
- package/dist/attributes.d.ts +0 -7
- package/dist/attributes.js +1 -16
- package/dist/browser.d.ts +4 -3
- package/dist/browser.js +7 -9
- package/dist/cli.js +1 -1
- package/dist/core.d.ts +16 -33
- package/dist/core.js +75 -384
- package/dist/gulp.js +18 -8
- package/dist/index.d.ts +2 -3
- package/dist/index.js +4 -14
- package/dist/interfaces.d.ts +20 -0
- package/dist/interfaces.js +2 -0
- package/dist/iterator.d.ts +10 -0
- package/dist/iterator.js +34 -0
- package/dist/mancha.js +1 -1
- package/dist/plugins.d.ts +13 -0
- package/dist/plugins.js +434 -0
- package/dist/reactive.d.ts +26 -6
- package/dist/reactive.js +43 -32
- package/dist/worker.d.ts +3 -4
- package/dist/worker.js +3 -11
- package/package.json +3 -2
- package/webpack.config.js +0 -6
package/dist/core.js
CHANGED
|
@@ -9,16 +9,10 @@ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, ge
|
|
|
9
9
|
});
|
|
10
10
|
};
|
|
11
11
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
12
|
-
exports.IRenderer = exports.safeEval = exports.
|
|
13
|
-
const path = require("path-browserify");
|
|
12
|
+
exports.IRenderer = exports.safeEval = exports.isRelativePath = exports.dirname = exports.traverse = void 0;
|
|
14
13
|
const reactive_1 = require("./reactive");
|
|
15
|
-
const
|
|
16
|
-
const
|
|
17
|
-
const ATTR_SHORTHANDS = {
|
|
18
|
-
// ":class": ":class-name",
|
|
19
|
-
$text: "$text-content",
|
|
20
|
-
$html: "$inner-HTML",
|
|
21
|
-
};
|
|
14
|
+
const iterator_1 = require("./iterator");
|
|
15
|
+
const plugins_1 = require("./plugins");
|
|
22
16
|
function* traverse(root, skip = new Set()) {
|
|
23
17
|
const explored = new Set();
|
|
24
18
|
const frontier = Array.from(root.childNodes).filter((node) => !skip.has(node));
|
|
@@ -38,434 +32,131 @@ function* traverse(root, skip = new Set()) {
|
|
|
38
32
|
}
|
|
39
33
|
}
|
|
40
34
|
exports.traverse = traverse;
|
|
41
|
-
function
|
|
42
|
-
if (fpath.
|
|
43
|
-
return
|
|
44
|
-
}
|
|
45
|
-
else {
|
|
46
|
-
return path.dirname(fpath);
|
|
47
|
-
}
|
|
48
|
-
}
|
|
49
|
-
exports.folderPath = folderPath;
|
|
50
|
-
function resolvePath(fpath) {
|
|
51
|
-
if (fpath.includes("://")) {
|
|
52
|
-
const [scheme, remotePath] = fpath.split("://", 2);
|
|
53
|
-
return `${scheme}://${resolvePath("/" + remotePath).substring(1)}`;
|
|
35
|
+
function dirname(fpath) {
|
|
36
|
+
if (!fpath.includes("/")) {
|
|
37
|
+
return "";
|
|
54
38
|
}
|
|
55
39
|
else {
|
|
56
|
-
return
|
|
40
|
+
return fpath.split("/").slice(0, -1).join("/");
|
|
57
41
|
}
|
|
58
42
|
}
|
|
59
|
-
exports.
|
|
60
|
-
function
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
const props = [];
|
|
66
|
-
if (key.includes(".")) {
|
|
67
|
-
const parts = key.split(".");
|
|
68
|
-
key = parts[0];
|
|
69
|
-
props.push(...parts.slice(1));
|
|
70
|
-
}
|
|
71
|
-
return [orig, key, props];
|
|
72
|
-
});
|
|
43
|
+
exports.dirname = dirname;
|
|
44
|
+
function isRelativePath(fpath) {
|
|
45
|
+
return (!fpath.includes("://") &&
|
|
46
|
+
!fpath.startsWith("/") &&
|
|
47
|
+
!fpath.startsWith("#") &&
|
|
48
|
+
!fpath.startsWith("data:"));
|
|
73
49
|
}
|
|
74
|
-
exports.
|
|
50
|
+
exports.isRelativePath = isRelativePath;
|
|
75
51
|
function safeEval(code, context, args = {}) {
|
|
76
52
|
const inner = `with (this) { return (async () => (${code}))(); }`;
|
|
77
53
|
return new Function(...Object.keys(args), inner).call(context, ...Object.values(args));
|
|
78
54
|
}
|
|
79
55
|
exports.safeEval = safeEval;
|
|
80
|
-
const _DEFAULT_RENDERER_PARAMS = { maxdepth: 10 };
|
|
81
56
|
class IRenderer extends reactive_1.ReactiveProxyStore {
|
|
82
57
|
constructor() {
|
|
83
58
|
super(...arguments);
|
|
84
|
-
this.
|
|
59
|
+
this.dirpath = "";
|
|
85
60
|
this.skipNodes = new Set();
|
|
86
61
|
}
|
|
87
|
-
|
|
88
|
-
return new this.constructor(Object.fromEntries(this.store.entries()));
|
|
89
|
-
}
|
|
90
|
-
log(params, ...args) {
|
|
91
|
-
if (params === null || params === void 0 ? void 0 : params.debug)
|
|
92
|
-
console.debug(...args);
|
|
93
|
-
}
|
|
94
|
-
eval(expr_1) {
|
|
95
|
-
return __awaiter(this, arguments, void 0, function* (expr, args = {}, params) {
|
|
96
|
-
const proxy = (0, reactive_1.proxify)(this);
|
|
97
|
-
const result = yield safeEval(expr, proxy, Object.assign({}, args));
|
|
98
|
-
this.log(params, `eval \`${expr}\` => `, result);
|
|
99
|
-
return result;
|
|
100
|
-
});
|
|
101
|
-
}
|
|
102
|
-
resolveIncludes(root, params) {
|
|
103
|
-
return __awaiter(this, void 0, void 0, function* () {
|
|
104
|
-
params = Object.assign({ fsroot: this.fsroot }, _DEFAULT_RENDERER_PARAMS, params);
|
|
105
|
-
const includes = Array.from(traverse(root, this.skipNodes))
|
|
106
|
-
.map((node) => node)
|
|
107
|
-
.filter((node) => { var _a; return ((_a = node.tagName) === null || _a === void 0 ? void 0 : _a.toLocaleLowerCase()) === "include"; })
|
|
108
|
-
.map((node) => __awaiter(this, void 0, void 0, function* () {
|
|
109
|
-
var _a, _b;
|
|
110
|
-
const src = (_a = node.getAttribute) === null || _a === void 0 ? void 0 : _a.call(node, "src");
|
|
111
|
-
const dataset = Object.assign({}, node.dataset);
|
|
112
|
-
// Add all the data-* attributes as properties to current context.
|
|
113
|
-
// NOTE: this will propagate to all subsequent render calls, including nested calls.
|
|
114
|
-
Object.entries(dataset).forEach(([key, attr]) => this.set(key, (0, attributes_1.decodeHtmlAttrib)(attr)));
|
|
115
|
-
// Early exit: <include> tags must have a src attribute.
|
|
116
|
-
if (!src) {
|
|
117
|
-
throw new Error(`"src" attribute missing from ${node}.`);
|
|
118
|
-
}
|
|
119
|
-
// The included file will replace this tag.
|
|
120
|
-
const handler = (fragment) => {
|
|
121
|
-
node.replaceWith(...Array.from(fragment.childNodes));
|
|
122
|
-
};
|
|
123
|
-
// Decrement the maxdepth param.
|
|
124
|
-
params.maxdepth--;
|
|
125
|
-
// Case 1: Absolute remote path.
|
|
126
|
-
if (src.indexOf("://") !== -1) {
|
|
127
|
-
yield this.renderRemotePath(src, Object.assign(Object.assign({}, params), { isRoot: false })).then(handler);
|
|
128
|
-
// Case 2: Relative remote path.
|
|
129
|
-
}
|
|
130
|
-
else if (((_b = params.fsroot) === null || _b === void 0 ? void 0 : _b.indexOf("://")) !== -1) {
|
|
131
|
-
const relpath = `${params.fsroot}/${src}`;
|
|
132
|
-
yield this.renderRemotePath(relpath, Object.assign(Object.assign({}, params), { isRoot: false })).then(handler);
|
|
133
|
-
// Case 3: Local absolute path.
|
|
134
|
-
}
|
|
135
|
-
else if (src.charAt(0) === "/") {
|
|
136
|
-
yield this.renderLocalPath(src, Object.assign(Object.assign({}, params), { isRoot: false })).then(handler);
|
|
137
|
-
// Case 4: Local relative path.
|
|
138
|
-
}
|
|
139
|
-
else {
|
|
140
|
-
const relpath = path.join(params.fsroot, src);
|
|
141
|
-
yield this.renderLocalPath(relpath, Object.assign(Object.assign({}, params), { isRoot: false })).then(handler);
|
|
142
|
-
}
|
|
143
|
-
}));
|
|
144
|
-
// Wait for all the rendering operations to complete.
|
|
145
|
-
yield Promise.all(includes);
|
|
146
|
-
// Re-render until no changes are made.
|
|
147
|
-
if (includes.length === 0) {
|
|
148
|
-
return this;
|
|
149
|
-
}
|
|
150
|
-
else if (params.maxdepth === 0) {
|
|
151
|
-
throw new Error("Maximum recursion depth reached.");
|
|
152
|
-
}
|
|
153
|
-
else {
|
|
154
|
-
return this.resolveIncludes(root, {
|
|
155
|
-
fsroot: params.fsroot,
|
|
156
|
-
maxdepth: params.maxdepth - 1,
|
|
157
|
-
});
|
|
158
|
-
}
|
|
159
|
-
});
|
|
160
|
-
}
|
|
161
|
-
resolveTextNode(node, params) {
|
|
162
|
-
if (node.nodeType !== 3)
|
|
163
|
-
return [];
|
|
164
|
-
const content = node.nodeValue || "";
|
|
165
|
-
// Identify all the context variables found in the content.
|
|
166
|
-
const keys = extractTextNodeKeys(content).filter(([, key]) => this.store.has(key));
|
|
167
|
-
// Early exit: no keys found in content.
|
|
168
|
-
if (keys.length === 0)
|
|
169
|
-
return [];
|
|
170
|
-
this.log(params, keys, "keys found in node:", node);
|
|
171
|
-
// Apply the context variables to the content, iteratively.
|
|
172
|
-
const updateNode = () => {
|
|
173
|
-
let updatedContent = content;
|
|
174
|
-
keys.forEach(([match, key, props]) => {
|
|
175
|
-
var _a;
|
|
176
|
-
updatedContent = updatedContent.replace(match, String((_a = this.get(key, ...props)) !== null && _a !== void 0 ? _a : ""));
|
|
177
|
-
});
|
|
178
|
-
node.nodeValue = updatedContent;
|
|
179
|
-
};
|
|
180
|
-
// Update the content now, and set up the listeners for future updates.
|
|
181
|
-
updateNode();
|
|
182
|
-
this.watch(keys.map(([, key]) => key), updateNode);
|
|
183
|
-
// Return all the proxies found in the content.
|
|
184
|
-
return keys.map(([, key]) => this.store.get(key));
|
|
185
|
-
}
|
|
186
|
-
resolveDataAttribute(node, params) {
|
|
62
|
+
fetchRemote(fpath, params) {
|
|
187
63
|
return __awaiter(this, void 0, void 0, function* () {
|
|
188
64
|
var _a;
|
|
189
|
-
|
|
190
|
-
return;
|
|
191
|
-
const elem = node;
|
|
192
|
-
const dataAttr = (_a = elem.getAttribute) === null || _a === void 0 ? void 0 : _a.call(elem, ":data");
|
|
193
|
-
if (dataAttr) {
|
|
194
|
-
this.log(params, ":data attribute found in:\n", node);
|
|
195
|
-
elem.removeAttribute(":data");
|
|
196
|
-
const result = yield this.eval(dataAttr, { $elem: node }, params);
|
|
197
|
-
this.log(params, ":data", dataAttr, "=>", result);
|
|
198
|
-
yield this.update(result);
|
|
199
|
-
}
|
|
65
|
+
return fetch(fpath, { cache: (_a = params === null || params === void 0 ? void 0 : params.cache) !== null && _a !== void 0 ? _a : "default" }).then((res) => res.text());
|
|
200
66
|
});
|
|
201
67
|
}
|
|
202
|
-
|
|
68
|
+
fetchLocal(fpath, params) {
|
|
203
69
|
return __awaiter(this, void 0, void 0, function* () {
|
|
204
|
-
|
|
205
|
-
if (this.skipNodes.has(node))
|
|
206
|
-
return;
|
|
207
|
-
const elem = node;
|
|
208
|
-
const watchAttr = (_a = elem.getAttribute) === null || _a === void 0 ? void 0 : _a.call(elem, "@watch");
|
|
209
|
-
if (watchAttr) {
|
|
210
|
-
this.log(params, "@watch attribute found in:\n", node);
|
|
211
|
-
// Remove the attribute from the node.
|
|
212
|
-
elem.removeAttribute("@watch");
|
|
213
|
-
// Compute the function's result and trace dependencies.
|
|
214
|
-
const fn = () => this.eval(watchAttr, { $elem: node }, params);
|
|
215
|
-
const [result, dependencies] = yield this.trace(fn);
|
|
216
|
-
this.log(params, "@watch", watchAttr, "=>", result);
|
|
217
|
-
// Watch for updates, and re-execute function if needed.
|
|
218
|
-
this.watch(dependencies, fn);
|
|
219
|
-
}
|
|
220
|
-
});
|
|
221
|
-
}
|
|
222
|
-
resolvePropAttributes(node, params) {
|
|
223
|
-
return __awaiter(this, void 0, void 0, function* () {
|
|
224
|
-
if (this.skipNodes.has(node))
|
|
225
|
-
return;
|
|
226
|
-
const elem = node;
|
|
227
|
-
for (const attr of Array.from(elem.attributes || [])) {
|
|
228
|
-
if (attr.name.startsWith("$") && !KW_ATTRIBUTES.has(attr.name)) {
|
|
229
|
-
this.log(params, attr.name, "attribute found in:\n", node);
|
|
230
|
-
// Remove the attribute from the node.
|
|
231
|
-
elem.removeAttribute(attr.name);
|
|
232
|
-
// Apply any shorthand conversions if necessary.
|
|
233
|
-
const propName = (ATTR_SHORTHANDS[attr.name] || attr.name).slice(1);
|
|
234
|
-
// Compute the function's result and trace dependencies.
|
|
235
|
-
const fn = () => this.eval(attr.value, { $elem: node }, params);
|
|
236
|
-
const [result, dependencies] = yield this.trace(fn);
|
|
237
|
-
this.log(params, attr.name, attr.value, "=>", result, `[${dependencies}]`);
|
|
238
|
-
// Set the requested property value on the original node, and watch for updates.
|
|
239
|
-
const prop = (0, attributes_1.attributeNameToCamelCase)(propName);
|
|
240
|
-
this.watch(dependencies, () => __awaiter(this, void 0, void 0, function* () { return (node[prop] = yield fn()); }));
|
|
241
|
-
node[prop] = result;
|
|
242
|
-
}
|
|
243
|
-
}
|
|
70
|
+
return this.fetchRemote(fpath, params);
|
|
244
71
|
});
|
|
245
72
|
}
|
|
246
|
-
|
|
73
|
+
preprocessString(content, params) {
|
|
247
74
|
return __awaiter(this, void 0, void 0, function* () {
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
if (attr.name.startsWith(":") && !KW_ATTRIBUTES.has(attr.name)) {
|
|
253
|
-
this.log(params, attr.name, "attribute found in:\n", node);
|
|
254
|
-
// Remove the processed attributes from node.
|
|
255
|
-
elem.removeAttribute(attr.name);
|
|
256
|
-
// Apply any shorthand conversions if necessary.
|
|
257
|
-
const attrName = (ATTR_SHORTHANDS[attr.name] || attr.name).slice(1);
|
|
258
|
-
// Compute the function's result and trace dependencies.
|
|
259
|
-
const fn = () => this.eval(attr.value, { $elem: node }, params);
|
|
260
|
-
const [result, dependencies] = yield this.trace(fn);
|
|
261
|
-
this.log(params, attr.name, attr.value, "=>", result, `[${dependencies}]`);
|
|
262
|
-
// Set the requested property value on the original node, and watch for updates.
|
|
263
|
-
this.watch(dependencies, () => __awaiter(this, void 0, void 0, function* () { return elem.setAttribute(attrName, yield fn()); }));
|
|
264
|
-
elem.setAttribute(attrName, result);
|
|
265
|
-
}
|
|
266
|
-
}
|
|
75
|
+
this.log(params, "Preprocessing string content with params:\n", params);
|
|
76
|
+
const fragment = this.parseHTML(content, params);
|
|
77
|
+
yield this.preprocessNode(fragment, params);
|
|
78
|
+
return fragment;
|
|
267
79
|
});
|
|
268
80
|
}
|
|
269
|
-
|
|
81
|
+
preprocessLocal(fpath, params) {
|
|
270
82
|
return __awaiter(this, void 0, void 0, function* () {
|
|
271
83
|
var _a;
|
|
272
|
-
|
|
273
|
-
|
|
274
|
-
const elem = node;
|
|
275
|
-
for (const attr of Array.from(elem.attributes || [])) {
|
|
276
|
-
if (attr.name.startsWith("@") && !KW_ATTRIBUTES.has(attr.name)) {
|
|
277
|
-
this.log(params, attr.name, "attribute found in:\n", node);
|
|
278
|
-
// Remove the processed attributes from node.
|
|
279
|
-
elem.removeAttribute(attr.name);
|
|
280
|
-
(_a = node.addEventListener) === null || _a === void 0 ? void 0 : _a.call(node, attr.name.substring(1), (event) => this.eval(attr.value, { $elem: node, $event: event }, params));
|
|
281
|
-
}
|
|
282
|
-
}
|
|
84
|
+
const content = yield this.fetchLocal(fpath, params);
|
|
85
|
+
return this.preprocessString(content, Object.assign(Object.assign({}, params), { dirpath: dirname(fpath), root: (_a = params === null || params === void 0 ? void 0 : params.root) !== null && _a !== void 0 ? _a : !fpath.endsWith(".tpl.html") }));
|
|
283
86
|
});
|
|
284
87
|
}
|
|
285
|
-
|
|
88
|
+
preprocessRemote(fpath, params) {
|
|
286
89
|
return __awaiter(this, void 0, void 0, function* () {
|
|
287
90
|
var _a;
|
|
288
|
-
|
|
289
|
-
|
|
290
|
-
|
|
291
|
-
const forAttr = (_a = elem.getAttribute) === null || _a === void 0 ? void 0 : _a.call(elem, ":for");
|
|
292
|
-
if (forAttr) {
|
|
293
|
-
this.log(params, ":for attribute found in:\n", node);
|
|
294
|
-
// Remove the processed attributes from node.
|
|
295
|
-
elem.removeAttribute(":for");
|
|
296
|
-
// Ensure the node and its children are not processed by subsequent steps.
|
|
297
|
-
for (const child of traverse(node, this.skipNodes)) {
|
|
298
|
-
this.skipNodes.add(child);
|
|
299
|
-
}
|
|
300
|
-
// Place the template node into a template element.
|
|
301
|
-
const parent = node.parentNode;
|
|
302
|
-
const template = node.ownerDocument.createElement("template");
|
|
303
|
-
parent.insertBefore(template, node);
|
|
304
|
-
template.append(node);
|
|
305
|
-
this.log(params, ":for template:\n", template);
|
|
306
|
-
// Tokenize the input by splitting it based on the format "{key} in {expression}".
|
|
307
|
-
const tokens = forAttr.split(" in ", 2);
|
|
308
|
-
if (tokens.length !== 2) {
|
|
309
|
-
throw new Error(`Invalid :for format: \`${forAttr}\`. Expected "{key} in {expression}".`);
|
|
310
|
-
}
|
|
311
|
-
// Compute the container expression and trace dependencies.
|
|
312
|
-
let items = [];
|
|
313
|
-
let deps = [];
|
|
314
|
-
const [loopKey, itemsExpr] = tokens;
|
|
315
|
-
try {
|
|
316
|
-
[items, deps] = yield this.trace(() => this.eval(itemsExpr, { $elem: node }, params));
|
|
317
|
-
this.log(params, itemsExpr, "=>", items, `[${deps}]`);
|
|
318
|
-
}
|
|
319
|
-
catch (exc) {
|
|
320
|
-
console.error(exc);
|
|
321
|
-
return;
|
|
322
|
-
}
|
|
323
|
-
// Keep track of all the child nodes added.
|
|
324
|
-
const children = [];
|
|
325
|
-
// Define the function that will update the DOM.
|
|
326
|
-
const fn = (items) => __awaiter(this, void 0, void 0, function* () {
|
|
327
|
-
this.log(params, ":for list items:", items);
|
|
328
|
-
// Validate that the expression returns a list of items.
|
|
329
|
-
if (!Array.isArray(items)) {
|
|
330
|
-
console.error(`Expression did not yield a list: \`${itemsExpr}\` => \`${items}\``);
|
|
331
|
-
return;
|
|
332
|
-
}
|
|
333
|
-
// Acquire the lock atomically.
|
|
334
|
-
this.lock = this.lock.then(() => new Promise((resolve) => __awaiter(this, void 0, void 0, function* () {
|
|
335
|
-
// Remove all the previously added children, if any.
|
|
336
|
-
children.splice(0, children.length).forEach((child) => {
|
|
337
|
-
parent.removeChild(child);
|
|
338
|
-
// this.skipNodes.delete(child);
|
|
339
|
-
});
|
|
340
|
-
// Loop through the container items in reverse, because we insert from back to front.
|
|
341
|
-
for (const item of items.slice(0).reverse()) {
|
|
342
|
-
// Create a subrenderer that will hold the loop item and all node descendants.
|
|
343
|
-
const subrenderer = this.clone();
|
|
344
|
-
yield subrenderer.set(loopKey, item);
|
|
345
|
-
// Create a new HTML element for each item and add them to parent node.
|
|
346
|
-
const copy = node.cloneNode(true);
|
|
347
|
-
parent.insertBefore(copy, template.nextSibling);
|
|
348
|
-
// Also add the new element to the store.
|
|
349
|
-
children.push(copy);
|
|
350
|
-
// Since the element will be handled by a subrenderer, skip it in the source.
|
|
351
|
-
this.skipNodes.add(copy);
|
|
352
|
-
// Render the element using the subrenderer.
|
|
353
|
-
yield subrenderer.mount(copy, params);
|
|
354
|
-
this.log(params, "Rendered list child:\n", copy);
|
|
355
|
-
}
|
|
356
|
-
// Release the lock.
|
|
357
|
-
resolve();
|
|
358
|
-
})));
|
|
359
|
-
// Return the lock so the whole operation can be awaited.
|
|
360
|
-
return this.lock;
|
|
361
|
-
});
|
|
362
|
-
// Apply changes, and watch for updates in the dependencies.
|
|
363
|
-
this.watch(deps, () => __awaiter(this, void 0, void 0, function* () { return fn(yield this.eval(itemsExpr, { $elem: node }, params)); }));
|
|
364
|
-
return fn(items);
|
|
365
|
-
}
|
|
91
|
+
const cache = (params === null || params === void 0 ? void 0 : params.cache) || "default";
|
|
92
|
+
const content = yield fetch(fpath, { cache }).then((res) => res.text());
|
|
93
|
+
return this.preprocessString(content, Object.assign(Object.assign({}, params), { dirpath: dirname(fpath), root: (_a = params === null || params === void 0 ? void 0 : params.root) !== null && _a !== void 0 ? _a : !fpath.endsWith(".tpl.html") }));
|
|
366
94
|
});
|
|
367
95
|
}
|
|
368
|
-
|
|
369
|
-
return
|
|
370
|
-
|
|
371
|
-
|
|
372
|
-
|
|
373
|
-
|
|
374
|
-
|
|
375
|
-
|
|
376
|
-
|
|
377
|
-
|
|
378
|
-
|
|
379
|
-
|
|
380
|
-
|
|
381
|
-
const prop = elem.getAttribute("type") === "checkbox" ? "checked" : "value";
|
|
382
|
-
// If the key is not found in our store, create it and initialize it with the node's value.
|
|
383
|
-
if (!this.store.has(bindKey))
|
|
384
|
-
yield this.set(bindKey, elem[prop]);
|
|
385
|
-
// Set the node's value to our current value.
|
|
386
|
-
elem[prop] = this.get(bindKey);
|
|
387
|
-
// Watch for updates in the node's value.
|
|
388
|
-
for (const event of updateEvents) {
|
|
389
|
-
node.addEventListener(event, () => this.set(bindKey, elem[prop]));
|
|
390
|
-
}
|
|
391
|
-
// Watch for updates in the store.
|
|
392
|
-
this.watch([bindKey], () => (elem[prop] = this.get(bindKey)));
|
|
393
|
-
// Remove the processed attributes from node.
|
|
394
|
-
elem.removeAttribute(":bind");
|
|
395
|
-
elem.removeAttribute(":bind-events");
|
|
396
|
-
}
|
|
96
|
+
clone() {
|
|
97
|
+
return new this.constructor(Object.fromEntries(this.store.entries()));
|
|
98
|
+
}
|
|
99
|
+
log(params, ...args) {
|
|
100
|
+
if (params === null || params === void 0 ? void 0 : params.debug)
|
|
101
|
+
console.debug(...args);
|
|
102
|
+
}
|
|
103
|
+
eval(expr_1) {
|
|
104
|
+
return __awaiter(this, arguments, void 0, function* (expr, args = {}, params) {
|
|
105
|
+
const proxy = (0, reactive_1.proxify)(this);
|
|
106
|
+
const result = yield safeEval(expr, proxy, Object.assign({}, args));
|
|
107
|
+
this.log(params, `eval \`${expr}\` => `, result);
|
|
108
|
+
return result;
|
|
397
109
|
});
|
|
398
110
|
}
|
|
399
|
-
|
|
111
|
+
preprocessNode(root, params) {
|
|
400
112
|
return __awaiter(this, void 0, void 0, function* () {
|
|
401
|
-
|
|
402
|
-
|
|
403
|
-
|
|
404
|
-
|
|
405
|
-
|
|
406
|
-
|
|
407
|
-
|
|
408
|
-
|
|
409
|
-
|
|
410
|
-
|
|
411
|
-
// If the result is false, remove the element from the DOM.
|
|
412
|
-
const parent = node.parentNode;
|
|
413
|
-
if (!result)
|
|
414
|
-
parent.removeChild(node);
|
|
415
|
-
// Watch the dependencies, and re-evaluate the expression.
|
|
416
|
-
this.watch(dependencies, () => __awaiter(this, void 0, void 0, function* () {
|
|
417
|
-
if ((yield fn()) && node.parentNode !== parent)
|
|
418
|
-
parent.append(node);
|
|
419
|
-
else if (Array.from(parent.childNodes).includes(node))
|
|
420
|
-
node.remove();
|
|
421
|
-
}));
|
|
422
|
-
// Remove the processed attributes from node.
|
|
423
|
-
elem.removeAttribute(":show");
|
|
424
|
-
}
|
|
113
|
+
params = Object.assign({ dirpath: this.dirpath, maxdepth: 10 }, params);
|
|
114
|
+
const promises = new iterator_1.Iterator(traverse(root, this.skipNodes)).map((node) => __awaiter(this, void 0, void 0, function* () {
|
|
115
|
+
this.log(params, "Preprocessing node:\n", node);
|
|
116
|
+
// Resolve all the includes in the node.
|
|
117
|
+
yield plugins_1.resolveIncludes.call(this, node, params);
|
|
118
|
+
// Resolve all the relative paths in the node.
|
|
119
|
+
yield plugins_1.rebaseRelativePaths.call(this, node, params);
|
|
120
|
+
}));
|
|
121
|
+
// Wait for all the rendering operations to complete.
|
|
122
|
+
yield Promise.all(promises.generator());
|
|
425
123
|
});
|
|
426
124
|
}
|
|
427
|
-
|
|
125
|
+
renderNode(root, params) {
|
|
428
126
|
return __awaiter(this, void 0, void 0, function* () {
|
|
429
|
-
// Resolve all the includes recursively first.
|
|
430
|
-
yield this.resolveIncludes(root, params);
|
|
431
127
|
// Iterate over all the nodes and apply appropriate handlers.
|
|
432
128
|
// Do these steps one at a time to avoid any potential race conditions.
|
|
433
129
|
for (const node of traverse(root, this.skipNodes)) {
|
|
434
|
-
this.log(params, "
|
|
435
|
-
// Resolve the :show attribute in the node.
|
|
436
|
-
yield this.resolveShowAttribute(node, params);
|
|
130
|
+
this.log(params, "Rendering node:\n", node);
|
|
437
131
|
// Resolve the :data attribute in the node.
|
|
438
|
-
yield
|
|
439
|
-
// Resolve the @watch attribute in the node.
|
|
440
|
-
yield this.resolveWatchAttribute(node, params);
|
|
132
|
+
yield plugins_1.resolveDataAttribute.call(this, node, params);
|
|
441
133
|
// Resolve the :for attribute in the node.
|
|
442
|
-
yield
|
|
134
|
+
yield plugins_1.resolveForAttribute.call(this, node, params);
|
|
135
|
+
// Resolve the $html attribute in the node.
|
|
136
|
+
yield plugins_1.resolveHtmlAttribute.call(this, node, params);
|
|
137
|
+
// Resolve the :show attribute in the node.
|
|
138
|
+
yield plugins_1.resolveShowAttribute.call(this, node, params);
|
|
139
|
+
// Resolve the @watch attribute in the node.
|
|
140
|
+
yield plugins_1.resolveWatchAttribute.call(this, node, params);
|
|
443
141
|
// Resolve the :bind attribute in the node.
|
|
444
|
-
yield
|
|
142
|
+
yield plugins_1.resolveBindAttribute.call(this, node, params);
|
|
445
143
|
// Resolve all $attributes in the node.
|
|
446
|
-
yield
|
|
144
|
+
yield plugins_1.resolvePropAttributes.call(this, node, params);
|
|
447
145
|
// Resolve all :attributes in the node.
|
|
448
|
-
yield
|
|
146
|
+
yield plugins_1.resolveAttrAttributes.call(this, node, params);
|
|
449
147
|
// Resolve all @attributes in the node.
|
|
450
|
-
yield
|
|
148
|
+
yield plugins_1.resolveEventAttributes.call(this, node, params);
|
|
451
149
|
// Replace all the {{ variables }} in the text.
|
|
452
|
-
|
|
150
|
+
yield plugins_1.resolveTextNodeExpressions.call(this, node, params);
|
|
453
151
|
}
|
|
454
|
-
return this;
|
|
455
152
|
});
|
|
456
153
|
}
|
|
457
|
-
|
|
458
|
-
return __awaiter(this, void 0, void 0, function* () {
|
|
459
|
-
const fragment = this.parseHTML(content, params);
|
|
460
|
-
yield this.mount(fragment, params);
|
|
461
|
-
return fragment;
|
|
462
|
-
});
|
|
463
|
-
}
|
|
464
|
-
renderRemotePath(fpath, params) {
|
|
154
|
+
mount(root, params) {
|
|
465
155
|
return __awaiter(this, void 0, void 0, function* () {
|
|
466
|
-
|
|
467
|
-
|
|
468
|
-
|
|
156
|
+
// Preprocess all the elements recursively first.
|
|
157
|
+
yield this.preprocessNode(root, params);
|
|
158
|
+
// Now that the DOM is complete, render all the nodes.
|
|
159
|
+
yield this.renderNode(root, params);
|
|
469
160
|
});
|
|
470
161
|
}
|
|
471
162
|
}
|
package/dist/gulp.js
CHANGED
|
@@ -1,4 +1,13 @@
|
|
|
1
1
|
"use strict";
|
|
2
|
+
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
|
|
3
|
+
function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
|
|
4
|
+
return new (P || (P = Promise))(function (resolve, reject) {
|
|
5
|
+
function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
|
|
6
|
+
function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
|
|
7
|
+
function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
|
|
8
|
+
step((generator = generator.apply(thisArg, _arguments || [])).next());
|
|
9
|
+
});
|
|
10
|
+
};
|
|
2
11
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
12
|
const path = require("path");
|
|
4
13
|
const stream = require("stream");
|
|
@@ -15,13 +24,12 @@ const index_1 = require("./index");
|
|
|
15
24
|
*/
|
|
16
25
|
function mancha(context = {}, wwwroot = process.cwd()) {
|
|
17
26
|
const renderer = new index_1.RendererImpl(context);
|
|
18
|
-
// Mancha.update(context);
|
|
19
27
|
return through.obj(function (file, encoding, callback) {
|
|
20
28
|
const catcher = (err) => {
|
|
21
29
|
console.log(err);
|
|
22
30
|
callback(err, file);
|
|
23
31
|
};
|
|
24
|
-
const
|
|
32
|
+
const dirpath = path.dirname(file.path);
|
|
25
33
|
if (file.isNull()) {
|
|
26
34
|
callback(null, file);
|
|
27
35
|
}
|
|
@@ -29,12 +37,13 @@ function mancha(context = {}, wwwroot = process.cwd()) {
|
|
|
29
37
|
if (file.isBuffer()) {
|
|
30
38
|
const chunk = file.contents.toString(encoding);
|
|
31
39
|
renderer
|
|
32
|
-
.
|
|
33
|
-
.then((fragment) => {
|
|
40
|
+
.preprocessString(chunk, { dirpath, root: !file.path.endsWith(".tpl.html") })
|
|
41
|
+
.then((fragment) => __awaiter(this, void 0, void 0, function* () {
|
|
42
|
+
yield renderer.renderNode(fragment);
|
|
34
43
|
const content = renderer.serializeHTML(fragment);
|
|
35
44
|
file.contents = Buffer.from(content, encoding);
|
|
36
45
|
callback(null, file);
|
|
37
|
-
})
|
|
46
|
+
}))
|
|
38
47
|
.catch(catcher);
|
|
39
48
|
}
|
|
40
49
|
else if (file.isStream()) {
|
|
@@ -50,8 +59,9 @@ function mancha(context = {}, wwwroot = process.cwd()) {
|
|
|
50
59
|
})
|
|
51
60
|
.on("end", () => {
|
|
52
61
|
renderer
|
|
53
|
-
.
|
|
54
|
-
.then((document) => {
|
|
62
|
+
.preprocessString(docstr, { dirpath, root: !file.path.endsWith(".tpl.html") })
|
|
63
|
+
.then((document) => __awaiter(this, void 0, void 0, function* () {
|
|
64
|
+
yield renderer.renderNode(document);
|
|
55
65
|
const content = renderer.serializeHTML(document);
|
|
56
66
|
const readable = new stream.Readable();
|
|
57
67
|
readable._read = function () { };
|
|
@@ -59,7 +69,7 @@ function mancha(context = {}, wwwroot = process.cwd()) {
|
|
|
59
69
|
readable.push(null);
|
|
60
70
|
file.contents = readable;
|
|
61
71
|
callback(null, file);
|
|
62
|
-
})
|
|
72
|
+
}))
|
|
63
73
|
.catch(catcher);
|
|
64
74
|
});
|
|
65
75
|
}
|
package/dist/index.d.ts
CHANGED
|
@@ -1,8 +1,7 @@
|
|
|
1
|
-
import { ParserParams, RendererParams } from "./core";
|
|
2
1
|
import { RendererImpl as WorkerRendererImpl } from "./worker";
|
|
2
|
+
import { ParserParams, RenderParams } from "./interfaces";
|
|
3
3
|
/** The Node Mancha renderer is just like the worker renderer, but it also uses the filesystem. */
|
|
4
4
|
export declare class RendererImpl extends WorkerRendererImpl {
|
|
5
|
-
|
|
5
|
+
fetchLocal(fpath: string, params?: RenderParams & ParserParams): Promise<string>;
|
|
6
6
|
}
|
|
7
|
-
export { folderPath, resolvePath } from "./core";
|
|
8
7
|
export declare const Mancha: RendererImpl;
|
package/dist/index.js
CHANGED
|
@@ -9,27 +9,17 @@ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, ge
|
|
|
9
9
|
});
|
|
10
10
|
};
|
|
11
11
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
12
|
-
exports.Mancha = exports.
|
|
12
|
+
exports.Mancha = exports.RendererImpl = void 0;
|
|
13
13
|
const fs = require("fs/promises");
|
|
14
|
-
const core_1 = require("./core");
|
|
15
14
|
const worker_1 = require("./worker");
|
|
16
15
|
/** The Node Mancha renderer is just like the worker renderer, but it also uses the filesystem. */
|
|
17
16
|
class RendererImpl extends worker_1.RendererImpl {
|
|
18
|
-
|
|
19
|
-
return __awaiter(this,
|
|
20
|
-
|
|
21
|
-
return this.renderString(content.toString(), {
|
|
22
|
-
fsroot: (0, core_1.folderPath)(fpath),
|
|
23
|
-
// Determine whether a root node is needed based on filename.
|
|
24
|
-
isRoot: params.isRoot || !fpath.endsWith(".tpl.html"),
|
|
25
|
-
});
|
|
17
|
+
fetchLocal(fpath, params) {
|
|
18
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
19
|
+
return fs.readFile(fpath, { encoding: (params === null || params === void 0 ? void 0 : params.encoding) || "utf8" });
|
|
26
20
|
});
|
|
27
21
|
}
|
|
28
22
|
}
|
|
29
23
|
exports.RendererImpl = RendererImpl;
|
|
30
|
-
// Re-exports from core.
|
|
31
|
-
var core_2 = require("./core");
|
|
32
|
-
Object.defineProperty(exports, "folderPath", { enumerable: true, get: function () { return core_2.folderPath; } });
|
|
33
|
-
Object.defineProperty(exports, "resolvePath", { enumerable: true, get: function () { return core_2.resolvePath; } });
|
|
34
24
|
// Export the renderer instance directly.
|
|
35
25
|
exports.Mancha = new RendererImpl();
|