mancha 0.9.0 → 0.9.4

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/plugins.js CHANGED
@@ -1,16 +1,6 @@
1
- import { appendChild, attributeNameToCamelCase, cloneAttribute, createElement, ellipsize, firstElementChild, getAttribute, getNodeValue, insertBefore, nodeToString, removeAttribute, removeChild, replaceChildren, replaceWith, setAttribute, setNodeValue, setTextContent, traverse, } from "./dome.js";
2
- import { isRelativePath } from "./core.js";
1
+ import { safeAnchorEl, safeAreaEl } from "safevalues/dom";
2
+ import { appendChild, attributeNameToCamelCase, cloneAttribute, ellipsize, firstElementChild, getAttribute, insertBefore, isRelativePath, nodeToString, removeAttribute, removeChild, replaceChildren, replaceWith, setAttribute, traverse, } from "./dome.js";
3
3
  import { Iterator } from "./iterator.js";
4
- import { makeAsyncEvalFunction } from "./store.js";
5
- const KW_ATTRIBUTES = new Set([
6
- ":bind",
7
- ":bind-events",
8
- ":data",
9
- ":for",
10
- ":show",
11
- "@watch",
12
- "$html",
13
- ]);
14
4
  /** @internal */
15
5
  export var RendererPlugins;
16
6
  (function (RendererPlugins) {
@@ -77,52 +67,38 @@ export var RendererPlugins;
77
67
  // We have to retrieve the attribute, because the node property is always an absolute path.
78
68
  const src = getAttribute(elem, "src");
79
69
  const href = getAttribute(elem, "href");
80
- const data = getAttribute(elem, "data");
81
70
  // Early exit: if there is no element attribute to rebase, we can skip this step.
82
- const anyattr = src || href || data;
83
- if (!anyattr)
84
- return;
85
- if (anyattr && isRelativePath(anyattr)) {
86
- this.log("Rebasing relative path as:", params.dirpath, "/", anyattr);
87
- }
88
- if (tagName === "img" && src && isRelativePath(src)) {
89
- setAttribute(elem, "src", `${params.dirpath}/${src}`);
90
- }
91
- else if (tagName === "a" && href && isRelativePath(href)) {
92
- setAttribute(elem, "href", `${params.dirpath}/${href}`);
93
- }
94
- else if (tagName === "link" && href && isRelativePath(href)) {
95
- setAttribute(elem, "href", `${params.dirpath}/${href}`);
96
- }
97
- else if (tagName === "script" && src && isRelativePath(src)) {
98
- setAttribute(elem, "src", `${params.dirpath}/${src}`);
99
- }
100
- else if (tagName === "source" && src && isRelativePath(src)) {
101
- setAttribute(elem, "src", `${params.dirpath}/${src}`);
102
- }
103
- else if (tagName === "audio" && src && isRelativePath(src)) {
104
- setAttribute(elem, "src", `${params.dirpath}/${src}`);
105
- }
106
- else if (tagName === "video" && src && isRelativePath(src)) {
107
- setAttribute(elem, "src", `${params.dirpath}/${src}`);
108
- }
109
- else if (tagName === "track" && src && isRelativePath(src)) {
110
- setAttribute(elem, "src", `${params.dirpath}/${src}`);
111
- }
112
- else if (tagName === "iframe" && src && isRelativePath(src)) {
113
- setAttribute(elem, "src", `${params.dirpath}/${src}`);
114
- }
115
- else if (tagName === "object" && data && isRelativePath(data)) {
116
- setAttribute(elem, "data", `${params.dirpath}/${data}`);
117
- }
118
- else if (tagName === "input" && src && isRelativePath(src)) {
119
- setAttribute(elem, "src", `${params.dirpath}/${src}`);
120
- }
121
- else if (tagName === "area" && href && isRelativePath(href)) {
122
- setAttribute(elem, "href", `${params.dirpath}/${href}`);
123
- }
124
- else if (tagName === "base" && href && isRelativePath(href)) {
125
- setAttribute(elem, "href", `${params.dirpath}/${href}`);
71
+ const pathref = src || href;
72
+ if (pathref && isRelativePath(pathref)) {
73
+ const relpath = `${params.dirpath}/${pathref}`;
74
+ this.log("Rebasing relative path as:", relpath);
75
+ if (tagName === "img") {
76
+ elem.src = relpath;
77
+ }
78
+ else if (tagName === "a") {
79
+ safeAnchorEl.setHref(elem, relpath);
80
+ }
81
+ else if (tagName === "source") {
82
+ elem.src = relpath;
83
+ }
84
+ else if (tagName === "audio") {
85
+ elem.src = relpath;
86
+ }
87
+ else if (tagName === "video") {
88
+ elem.src = relpath;
89
+ }
90
+ else if (tagName === "track") {
91
+ elem.src = relpath;
92
+ }
93
+ else if (tagName === "input") {
94
+ elem.src = relpath;
95
+ }
96
+ else if (tagName === "area") {
97
+ safeAreaEl.setHref(elem, relpath);
98
+ }
99
+ else {
100
+ this.log("Unable to rebase relative path for element:", tagName);
101
+ }
126
102
  }
127
103
  };
128
104
  RendererPlugins.registerCustomElements = async function (node, params) {
@@ -160,7 +136,7 @@ export var RendererPlugins;
160
136
  }
161
137
  };
162
138
  RendererPlugins.resolveTextNodeExpressions = async function (node, params) {
163
- const content = getNodeValue(node) || "";
139
+ const content = node.nodeValue || "";
164
140
  if (node.nodeType !== 3 || !content?.trim())
165
141
  return;
166
142
  this.log(`Processing node content value:\n`, ellipsize(content, 128));
@@ -175,7 +151,7 @@ export var RendererPlugins;
175
151
  const result = this.eval(expr, { $elem: node });
176
152
  updatedContent = updatedContent.replace(`{{ ${expr} }}`, String(result));
177
153
  }
178
- setNodeValue(node, updatedContent);
154
+ node.nodeValue = updatedContent;
179
155
  });
180
156
  };
181
157
  RendererPlugins.resolveDataAttribute = async function (node, params) {
@@ -190,9 +166,9 @@ export var RendererPlugins;
190
166
  // Create a subrenderer and process the tag, unless it's the root node.
191
167
  const subrenderer = params?.rootNode === node ? this : this.clone();
192
168
  node.renderer = subrenderer;
193
- // Do not call eval() directly, we will use an async version instead.
194
- const fn = makeAsyncEvalFunction(dataAttr, this.evalkeys);
195
- const result = await fn.call(subrenderer.$, { $elem: node });
169
+ // Evaluate the expression.
170
+ const result = subrenderer.eval(dataAttr, { $elem: node });
171
+ // Await any promises in the result object.
196
172
  await Promise.all(Object.entries(result).map(([key, value]) => subrenderer.set(key, value)));
197
173
  // Skip all the children of the current node, if it's a subrenderer.
198
174
  if (subrenderer !== this) {
@@ -204,18 +180,21 @@ export var RendererPlugins;
204
180
  await subrenderer.mount(node, params);
205
181
  }
206
182
  };
207
- RendererPlugins.resolveWatchAttribute = async function (node, params) {
183
+ RendererPlugins.resolveClassAttribute = async function (node, params) {
208
184
  if (this._skipNodes.has(node))
209
185
  return;
210
186
  const elem = node;
211
- const watchAttr = getAttribute(elem, "@watch");
212
- if (watchAttr) {
213
- this.log("@watch attribute found in:\n", nodeToString(node, 128));
187
+ const classAttr = getAttribute(elem, ":class");
188
+ if (classAttr) {
189
+ this.log(":class attribute found in:\n", nodeToString(node, 128));
214
190
  // Remove the attribute from the node.
215
- removeAttribute(elem, "@watch");
191
+ removeAttribute(elem, ":class");
192
+ // Store the original class attribute, if any.
193
+ const originalClass = getAttribute(elem, "class") || "";
216
194
  // Compute the function's result.
217
- await this.effect(function () {
218
- return this.eval(watchAttr, { $elem: node });
195
+ return this.effect(function () {
196
+ const result = this.eval(classAttr, { $elem: node });
197
+ setAttribute(elem, "class", (result ? `${originalClass} ${result}` : originalClass).trim());
219
198
  });
220
199
  }
221
200
  };
@@ -223,14 +202,15 @@ export var RendererPlugins;
223
202
  if (this._skipNodes.has(node))
224
203
  return;
225
204
  const elem = node;
226
- const textAttr = getAttribute(elem, "$text");
205
+ const textAttr = getAttribute(elem, ":text");
227
206
  if (textAttr) {
228
- this.log("$text attribute found in:\n", nodeToString(node, 128));
207
+ this.log(":text attribute found in:\n", nodeToString(node, 128));
229
208
  // Remove the attribute from the node.
230
- removeAttribute(elem, "$text");
209
+ removeAttribute(elem, ":text");
231
210
  // Compute the function's result and track dependencies.
211
+ const setTextContent = (content) => this.textContent(node, content);
232
212
  return this.effect(function () {
233
- setTextContent(node, this.eval(textAttr, { $elem: node }));
213
+ setTextContent(this.eval(textAttr, { $elem: node }));
234
214
  });
235
215
  }
236
216
  };
@@ -238,11 +218,11 @@ export var RendererPlugins;
238
218
  if (this._skipNodes.has(node))
239
219
  return;
240
220
  const elem = node;
241
- const htmlAttr = getAttribute(elem, "$html");
221
+ const htmlAttr = getAttribute(elem, ":html");
242
222
  if (htmlAttr) {
243
- this.log("$html attribute found in:\n", nodeToString(node, 128));
223
+ this.log(":html attribute found in:\n", nodeToString(node, 128));
244
224
  // Remove the attribute from the node.
245
- removeAttribute(elem, "$html");
225
+ removeAttribute(elem, ":html");
246
226
  // Compute the function's result and track dependencies.
247
227
  return this.effect(function () {
248
228
  const result = this.eval(htmlAttr, { $elem: node });
@@ -255,50 +235,16 @@ export var RendererPlugins;
255
235
  });
256
236
  }
257
237
  };
258
- RendererPlugins.resolvePropAttributes = async function (node, params) {
259
- if (this._skipNodes.has(node))
260
- return;
261
- const elem = node;
262
- for (const attr of Array.from(elem.attributes || [])) {
263
- if (attr.name.startsWith("$") && !KW_ATTRIBUTES.has(attr.name)) {
264
- this.log(attr.name, "attribute found in:\n", nodeToString(node, 128));
265
- // Remove the attribute from the node.
266
- removeAttribute(elem, attr.name);
267
- // Compute the function's result and track dependencies.
268
- const propName = attributeNameToCamelCase(attr.name.slice(1));
269
- await this.effect(function () {
270
- node[propName] = this.eval(attr.value, { $elem: node });
271
- });
272
- }
273
- }
274
- };
275
- RendererPlugins.resolveAttrAttributes = async function (node, params) {
276
- if (this._skipNodes.has(node))
277
- return;
278
- const elem = node;
279
- for (const attr of Array.from(elem.attributes || [])) {
280
- if (attr.name.startsWith(":") && !KW_ATTRIBUTES.has(attr.name)) {
281
- this.log(attr.name, "attribute found in:\n", nodeToString(node, 128));
282
- // Remove the processed attributes from node.
283
- removeAttribute(elem, attr.name);
284
- // Compute the function's result and track dependencies.
285
- const attrName = attr.name.slice(1);
286
- this.effect(function () {
287
- setAttribute(elem, attrName, this.eval(attr.value, { $elem: node }));
288
- });
289
- }
290
- }
291
- };
292
238
  RendererPlugins.resolveEventAttributes = async function (node, params) {
293
239
  if (this._skipNodes.has(node))
294
240
  return;
295
241
  const elem = node;
296
242
  for (const attr of Array.from(elem.attributes || [])) {
297
- if (attr.name.startsWith("@") && !KW_ATTRIBUTES.has(attr.name)) {
243
+ if (attr.name.startsWith(":on:")) {
298
244
  this.log(attr.name, "attribute found in:\n", nodeToString(node, 128));
299
245
  // Remove the processed attributes from node.
300
246
  removeAttribute(elem, attr.name);
301
- node.addEventListener?.(attr.name.substring(1), (event) => {
247
+ node.addEventListener?.(attr.name.substring(4), (event) => {
302
248
  return this.eval(attr.value, { $elem: node, $event: event });
303
249
  });
304
250
  }
@@ -319,7 +265,7 @@ export var RendererPlugins;
319
265
  }
320
266
  // Place the template node into a template element.
321
267
  const parent = node.parentNode;
322
- const template = createElement("template", node.ownerDocument);
268
+ const template = this.createElement("template", node.ownerDocument);
323
269
  insertBefore(parent, template, node);
324
270
  removeChild(parent, node);
325
271
  appendChild(template, node);
@@ -380,16 +326,15 @@ export var RendererPlugins;
380
326
  this.log(":bind attribute found in:\n", nodeToString(node, 128));
381
327
  // The change events we listen for can be overriden by user.
382
328
  const defaultEvents = ["change", "input"];
383
- const updateEvents = getAttribute(elem, ":bind-events")?.split(",") || defaultEvents;
329
+ const updateEvents = getAttribute(elem, ":bind:on")?.split(",") || defaultEvents;
384
330
  // Remove the processed attributes from node.
385
331
  removeAttribute(elem, ":bind");
386
- removeAttribute(elem, ":bind-events");
332
+ removeAttribute(elem, ":bind:on");
387
333
  // If the element is of type checkbox, we bind to the "checked" property.
388
334
  const prop = getAttribute(elem, "type") === "checkbox" ? "checked" : "value";
389
335
  // Watch for updates in the store and bind our property ==> node value.
390
- const propExpr = `$elem.${prop} = ${bindExpr}`;
391
336
  this.effect(function () {
392
- const result = this.eval(propExpr, { $elem: node });
337
+ const result = this.eval(bindExpr, { $elem: node });
393
338
  elem[prop] = result;
394
339
  });
395
340
  // Bind node value ==> our property.
@@ -432,4 +377,21 @@ export var RendererPlugins;
432
377
  });
433
378
  }
434
379
  };
380
+ RendererPlugins.resolveCustomAttribute = async function (node, params) {
381
+ if (this._skipNodes.has(node))
382
+ return;
383
+ const elem = node;
384
+ for (const attr of Array.from(elem.attributes || [])) {
385
+ if (attr.name.startsWith(":")) {
386
+ this.log(attr.name, "attribute found in:\n", nodeToString(node, 128));
387
+ // Remove the processed attributes from node.
388
+ removeAttribute(elem, attr.name);
389
+ const propName = attributeNameToCamelCase(attr.name.substring(1));
390
+ this.effect(function () {
391
+ const propValue = this.eval(attr.value, { $elem: node });
392
+ elem[propName] = propValue;
393
+ });
394
+ }
395
+ }
396
+ };
435
397
  })(RendererPlugins || (RendererPlugins = {}));
@@ -0,0 +1,7 @@
1
+ import { Renderer as BrowserRenderer } from "./browser.js";
2
+ import { ParserParams } from "./interfaces.js";
3
+ export declare class Renderer extends BrowserRenderer {
4
+ protected readonly dirpath: string;
5
+ parseHTML(content: string, params?: ParserParams): Document | DocumentFragment;
6
+ }
7
+ export declare const Mancha: Renderer;
@@ -0,0 +1,19 @@
1
+ import { sanitizeHtml } from "safevalues";
2
+ import { safeRange, safeDomParser } from "safevalues/dom";
3
+ import { Renderer as BrowserRenderer } from "./browser.js";
4
+ import { dirname } from "./dome.js";
5
+ export class Renderer extends BrowserRenderer {
6
+ dirpath = dirname(self.location.href);
7
+ parseHTML(content, params = { rootDocument: false }) {
8
+ if (params.rootDocument) {
9
+ const parser = new DOMParser();
10
+ return safeDomParser.parseFromString(parser, sanitizeHtml(content), "text/html");
11
+ }
12
+ else {
13
+ const range = document.createRange();
14
+ range.selectNodeContents(document.body);
15
+ return safeRange.createContextualFragment(range, sanitizeHtml(content));
16
+ }
17
+ }
18
+ }
19
+ export const Mancha = new Renderer();
package/dist/store.d.ts CHANGED
@@ -8,14 +8,6 @@ declare abstract class IDebouncer {
8
8
  }
9
9
  /** Default debouncer time in millis. */
10
10
  export declare const REACTIVE_DEBOUNCE_MILLIS = 10;
11
- /**
12
- * Creates an evaluation function based on the provided code and arguments.
13
- * @param code The code to be evaluated.
14
- * @param args The arguments to be passed to the evaluation function. Default is an empty array.
15
- * @returns The evaluation function.
16
- */
17
- export declare function makeEvalFunction(code: string, args?: string[]): Function;
18
- export declare function makeAsyncEvalFunction(code: string, args?: string[]): Function;
19
11
  export declare class SignalStore extends IDebouncer {
20
12
  protected readonly evalkeys: string[];
21
13
  protected readonly expressionCache: Map<string, Function>;
@@ -38,7 +30,13 @@ export declare class SignalStore extends IDebouncer {
38
30
  private proxify;
39
31
  get $(): SignalStoreProxy;
40
32
  /**
41
- * Retrieves or creates a cached expression function based on the provided expression.
33
+ * Creates an evaluation function for the provided expression.
34
+ * @param expr The expression to be evaluated.
35
+ * @returns The evaluation function.
36
+ */
37
+ private makeEvalFunction;
38
+ /**
39
+ * Retrieves or creates a cached expression function for the provided expression.
42
40
  * @param expr - The expression to retrieve or create a cached function for.
43
41
  * @returns The cached expression function.
44
42
  */
package/dist/store.js CHANGED
@@ -1,3 +1,4 @@
1
+ import * as jexpr from "jexpr";
1
2
  class IDebouncer {
2
3
  timeouts = new Map();
3
4
  debounce(millis, callback) {
@@ -19,18 +20,8 @@ class IDebouncer {
19
20
  }
20
21
  /** Default debouncer time in millis. */
21
22
  export const REACTIVE_DEBOUNCE_MILLIS = 10;
22
- /**
23
- * Creates an evaluation function based on the provided code and arguments.
24
- * @param code The code to be evaluated.
25
- * @param args The arguments to be passed to the evaluation function. Default is an empty array.
26
- * @returns The evaluation function.
27
- */
28
- export function makeEvalFunction(code, args = []) {
29
- return new Function(...args, `with (this) { return (${code}); }`);
30
- }
31
- export function makeAsyncEvalFunction(code, args = []) {
32
- return new Function(...args, `with (this) { return (async () => (${code}))(); }`);
33
- }
23
+ /** Shared AST factory. */
24
+ const AST_FACTORY = new jexpr.EvalAstFactory();
34
25
  function isProxified(object) {
35
26
  return object instanceof SignalStore || object["__is_proxy__"];
36
27
  }
@@ -152,13 +143,46 @@ export class SignalStore extends IDebouncer {
152
143
  return this.proxify();
153
144
  }
154
145
  /**
155
- * Retrieves or creates a cached expression function based on the provided expression.
146
+ * Creates an evaluation function for the provided expression.
147
+ * @param expr The expression to be evaluated.
148
+ * @returns The evaluation function.
149
+ */
150
+ makeEvalFunction(expr) {
151
+ // Throw an error if the expression is not a simple one-liner.
152
+ if (expr.includes(";")) {
153
+ throw new Error("Complex expressions are not supported.");
154
+ }
155
+ // If the expression includes assignment, save the left-hand side for later.
156
+ let assignResult = null;
157
+ if (expr.includes("=")) {
158
+ const [lhs, rhs] = expr.split("=");
159
+ assignResult = lhs.trim();
160
+ expr = rhs.trim();
161
+ }
162
+ // Otherwise, just return the simple expression function.
163
+ return (thisArg, args) => {
164
+ const ast = jexpr.parse(expr, AST_FACTORY);
165
+ const ctx = ast
166
+ ?.getIds([])
167
+ ?.map((id) => [id, args[id] ?? thisArg[id] ?? globalThis[id]]);
168
+ const res = ast?.evaluate(Object.fromEntries(ctx || []));
169
+ if (assignResult) {
170
+ thisArg[assignResult] = res;
171
+ }
172
+ else {
173
+ return res;
174
+ }
175
+ };
176
+ }
177
+ /**
178
+ * Retrieves or creates a cached expression function for the provided expression.
156
179
  * @param expr - The expression to retrieve or create a cached function for.
157
180
  * @returns The cached expression function.
158
181
  */
159
182
  cachedExpressionFunction(expr) {
183
+ expr = expr.trim();
160
184
  if (!this.expressionCache.has(expr)) {
161
- this.expressionCache.set(expr, makeEvalFunction(expr, this.evalkeys));
185
+ this.expressionCache.set(expr, this.makeEvalFunction(expr));
162
186
  }
163
187
  return this.expressionCache.get(expr);
164
188
  }
@@ -172,11 +196,7 @@ export class SignalStore extends IDebouncer {
172
196
  else {
173
197
  // Otherwise, perform the expression evaluation.
174
198
  const fn = this.cachedExpressionFunction(expr);
175
- const argvals = this.evalkeys.map((key) => args[key]);
176
- if (Object.keys(args).some((key) => !this.evalkeys.includes(key))) {
177
- throw new Error(`Invalid argument key, must be one of: ${this.evalkeys.join(", ")}`);
178
- }
179
- return fn.call(thisArg, ...argvals);
199
+ return fn(thisArg, args);
180
200
  }
181
201
  }
182
202
  }
@@ -0,0 +1,2 @@
1
+ export declare function innerHTML(elem: Element): string;
2
+ export declare function getTextContent(elem: Element): string | null;
@@ -0,0 +1,14 @@
1
+ import { DomUtils } from "htmlparser2";
2
+ import { hasProperty } from "./dome.js";
3
+ export function innerHTML(elem) {
4
+ if (hasProperty(elem, "innerHTML"))
5
+ return elem.innerHTML;
6
+ else
7
+ return DomUtils.getInnerHTML(elem);
8
+ }
9
+ export function getTextContent(elem) {
10
+ if (hasProperty(elem, "textContent"))
11
+ return elem.textContent;
12
+ else
13
+ return DomUtils.textContent(elem);
14
+ }
package/dist/worker.d.ts CHANGED
@@ -1,7 +1,9 @@
1
1
  import { IRenderer } from "./core.js";
2
2
  import { ParserParams } from "./interfaces.js";
3
3
  export declare class Renderer extends IRenderer {
4
- parseHTML(content: string, params?: ParserParams): DocumentFragment;
4
+ parseHTML(content: string, params?: ParserParams): Document | DocumentFragment;
5
5
  serializeHTML(root: Node | DocumentFragment | Document): string;
6
+ createElement(tag: string, owner?: Document | null): globalThis.Element;
7
+ textContent(node: Node, content: string): void;
6
8
  }
7
9
  export declare const Mancha: Renderer;
package/dist/worker.js CHANGED
@@ -1,4 +1,5 @@
1
1
  import * as htmlparser2 from "htmlparser2";
2
+ import { Element, Text } from "domhandler";
2
3
  import { render as renderDOM } from "dom-serializer";
3
4
  import { IRenderer } from "./core.js";
4
5
  export class Renderer extends IRenderer {
@@ -8,6 +9,12 @@ export class Renderer extends IRenderer {
8
9
  serializeHTML(root) {
9
10
  return renderDOM(root);
10
11
  }
12
+ createElement(tag, owner) {
13
+ return new Element(tag, {});
14
+ }
15
+ textContent(node, content) {
16
+ node.children = [new Text(content)];
17
+ }
11
18
  }
12
19
  // Export the renderer instance directly.
13
20
  export const Mancha = new Renderer();
package/gulpfile.js CHANGED
@@ -13,7 +13,7 @@ GulpClient.task("clean", function (done) {
13
13
 
14
14
  GulpClient.task("ts", function () {
15
15
  // The gulp-typescript plugin is deprecated.
16
- return run("tsc -p .").exec();
16
+ return run("tsec -p .").exec();
17
17
  });
18
18
 
19
19
  GulpClient.task("css", function () {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "mancha",
3
- "version": "0.9.0",
3
+ "version": "0.9.4",
4
4
  "description": "Javscript HTML rendering engine",
5
5
  "main": "dist/index.js",
6
6
  "type": "module",
@@ -9,7 +9,7 @@
9
9
  "scripts": {
10
10
  "clean": "rm -rf dist/",
11
11
  "build": "gulp build && webpack",
12
- "test": "mocha dist/*.test.js",
12
+ "test": "node --test dist/*.test.js",
13
13
  "webpack": "webpack",
14
14
  "cli": "node dist/cli.js"
15
15
  },
@@ -31,17 +31,14 @@
31
31
  "dependencies": {
32
32
  "dom-serializer": "^2.0.0",
33
33
  "htmlparser2": "^9.1.0",
34
+ "jexpr": "^1.0.0-pre.9",
34
35
  "jsdom": "^24.0.0",
35
- "through2": "^4.0.2",
36
- "yargs": "^17.7.2"
36
+ "safevalues": "^0.6.0"
37
37
  },
38
38
  "devDependencies": {
39
- "@types/gulp": "^4.0.8",
40
39
  "@types/jsdom": "^21.1.6",
41
- "@types/mocha": "^10.0.3",
42
40
  "@types/node": "^20.12.11",
43
41
  "@types/path-browserify": "^1.0.1",
44
- "@types/through2": "^2.0.36",
45
42
  "@types/yargs": "^17.0.29",
46
43
  "css-loader": "^7.1.2",
47
44
  "csso": "^5.0.5",
@@ -49,11 +46,13 @@
49
46
  "gulp-csso": "^4.0.1",
50
47
  "gulp-run": "^1.7.1",
51
48
  "gulp-typescript": "^6.0.0-alpha.1",
52
- "mocha": "^10.2.0",
53
49
  "static-server": "^3.0.0",
50
+ "terser-webpack-plugin": "^5.3.10",
54
51
  "ts-node": "^10.9.2",
52
+ "tsec": "^0.2.8",
55
53
  "typescript": "5.4.5",
56
54
  "webpack": "5.91.0",
57
- "webpack-cli": "^5.1.4"
55
+ "webpack-cli": "^5.1.4",
56
+ "yargs": "^17.7.2"
58
57
  }
59
58
  }
package/tsconfig.json CHANGED
@@ -1,14 +1,20 @@
1
1
  {
2
- "compilerOptions": {
3
- "target": "ES2022",
4
- "module": "ES2022",
5
- "outDir": "dist",
6
- "rootDir": "src",
7
- "declaration": true,
8
- "noImplicitAny": true,
9
- "skipLibCheck": true,
10
- "strict": true,
11
- "stripInternal": true,
12
- "moduleResolution": "node",
13
- },
14
- }
2
+ "compilerOptions": {
3
+ "target": "ES2022",
4
+ "module": "ES2022",
5
+ "outDir": "dist",
6
+ "rootDir": "src",
7
+ "declaration": true,
8
+ "noImplicitAny": true,
9
+ "skipLibCheck": true,
10
+ "strict": true,
11
+ "stripInternal": true,
12
+ "moduleResolution": "node",
13
+ "plugins": [
14
+ {
15
+ "name": "tsec",
16
+ "exemptionConfig": "./tsec_exemptions.json"
17
+ }
18
+ ]
19
+ }
20
+ }
@@ -0,0 +1,4 @@
1
+ {
2
+ "ban-domparser-parsefromstring": ["src/browser.ts"],
3
+ "ban-range-createcontextualfragment": ["src/browser.ts"]
4
+ }
package/webpack.config.js CHANGED
@@ -1,16 +1,14 @@
1
+ import TerserPlugin from "terser-webpack-plugin";
1
2
 
2
3
  export default {
3
4
  target: "web",
4
5
  mode: "production",
5
6
  entry: {
6
- mancha: "./dist/browser.js",
7
+ mancha: "./dist/mancha.js",
7
8
  },
8
9
  output: {
9
10
  filename: "[name].js",
10
11
  },
11
- externals: {
12
- htmlparser2: "window.htmlparser2",
13
- },
14
12
  module: {
15
13
  rules: [
16
14
  {
@@ -19,4 +17,8 @@ export default {
19
17
  },
20
18
  ],
21
19
  },
20
+ optimization: {
21
+ minimize: true,
22
+ minimizer: [new TerserPlugin({ extractComments: false })],
23
+ },
22
24
  };
@@ -1 +0,0 @@
1
- html{max-width:70ch;padding:2em 1em;margin:auto;line-height:1.75;font-size:1.25em;font-family:sans-serif}h1,h2,h3,h4,h5,h6{margin:1em 0 .5em}ol,p,ul{margin-bottom:1em;color:#1d1d1d}
@@ -1,15 +0,0 @@
1
- /// <reference types="node" />
2
- import * as stream from "stream";
3
- /**
4
- * Main entrypoint to be used in Gulp. Usage:
5
- *
6
- * var mancha = require('mancha/dist/gulp')
7
- * gulp.src(...).pipe(mancha({myvar: myval})).pipe(...)
8
- *
9
- * @param context <key, value> pairs of literal string replacements. `key` will become `{{ key }}`
10
- * before replacing it with `value` in the processed files.
11
- */
12
- declare function mancha(context?: {
13
- [key: string]: string;
14
- }): stream.Transform;
15
- export default mancha;