mancha 0.16.7 → 0.17.3
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/.github/workflows/ci.yml +8 -7
- package/README.md +88 -25
- package/dist/browser.d.ts +42 -3
- package/dist/browser.js +1 -1
- package/dist/browser.js.map +1 -1
- package/dist/css_gen_utils.js +323 -412
- package/dist/css_gen_utils.js.map +1 -1
- package/dist/dome.d.ts +2 -2
- package/dist/dome.js +17 -0
- package/dist/dome.js.map +1 -1
- package/dist/expressions/ast.d.ts +79 -0
- package/dist/expressions/ast.js +6 -0
- package/dist/expressions/ast.js.map +1 -0
- package/dist/expressions/ast.test.d.ts +1 -0
- package/dist/expressions/ast.test.js +122 -0
- package/dist/expressions/ast.test.js.map +1 -0
- package/dist/expressions/ast_factory.d.ts +37 -0
- package/dist/expressions/ast_factory.js +119 -0
- package/dist/expressions/ast_factory.js.map +1 -0
- package/dist/expressions/ast_factory.test.d.ts +1 -0
- package/dist/expressions/ast_factory.test.js +88 -0
- package/dist/expressions/ast_factory.test.js.map +1 -0
- package/dist/expressions/constants.d.ts +6 -0
- package/dist/expressions/constants.js +72 -0
- package/dist/expressions/constants.js.map +1 -0
- package/dist/expressions/constants.test.d.ts +1 -0
- package/dist/expressions/constants.test.js +84 -0
- package/dist/expressions/constants.test.js.map +1 -0
- package/dist/expressions/eval.d.ts +101 -0
- package/dist/expressions/eval.js +375 -0
- package/dist/expressions/eval.js.map +1 -0
- package/dist/expressions/eval.test.d.ts +1 -0
- package/dist/expressions/eval.test.js +141 -0
- package/dist/expressions/eval.test.js.map +1 -0
- package/dist/expressions/expressions.test.d.ts +6 -0
- package/dist/expressions/expressions.test.js +7 -0
- package/dist/expressions/expressions.test.js.map +1 -0
- package/dist/expressions/index.d.ts +6 -0
- package/dist/expressions/index.js +7 -0
- package/dist/expressions/index.js.map +1 -0
- package/dist/expressions/parser.d.ts +32 -0
- package/dist/expressions/parser.js +341 -0
- package/dist/expressions/parser.js.map +1 -0
- package/dist/expressions/parser.test.d.ts +1 -0
- package/dist/expressions/parser.test.js +176 -0
- package/dist/expressions/parser.test.js.map +1 -0
- package/dist/expressions/tokenizer.d.ts +49 -0
- package/dist/expressions/tokenizer.js +253 -0
- package/dist/expressions/tokenizer.js.map +1 -0
- package/dist/expressions/tokenizer.test.d.ts +1 -0
- package/dist/expressions/tokenizer.test.js +99 -0
- package/dist/expressions/tokenizer.test.js.map +1 -0
- package/dist/index.d.ts +2 -0
- package/dist/index.js +1 -0
- package/dist/index.js.map +1 -1
- package/dist/interfaces.d.ts +1 -1
- package/dist/mancha.d.ts +1 -1
- package/dist/mancha.js +1 -1
- package/dist/mancha.js.map +1 -1
- package/dist/plugins.js +94 -23
- package/dist/plugins.js.map +1 -1
- package/dist/renderer.d.ts +5 -2
- package/dist/renderer.js +6 -2
- package/dist/renderer.js.map +1 -1
- package/dist/safe_browser.d.ts +4 -3
- package/dist/safe_browser.js +1 -1
- package/dist/safe_browser.js.map +1 -1
- package/dist/store.d.ts +59 -13
- package/dist/store.js +112 -38
- package/dist/store.js.map +1 -1
- package/dist/test_utils.d.ts +2 -0
- package/dist/test_utils.js +14 -1
- package/dist/test_utils.js.map +1 -1
- package/dist/trusted_attributes.js +2 -0
- package/dist/trusted_attributes.js.map +1 -1
- package/dist/type_checker.d.ts +1 -0
- package/dist/type_checker.js +113 -41
- package/dist/type_checker.js.map +1 -1
- package/dist/worker.d.ts +2 -0
- package/dist/worker.js +1 -0
- package/dist/worker.js.map +1 -1
- package/docs/quickstart.md +200 -0
- package/gulpfile.js +5 -1
- package/package.json +19 -6
- package/tsec_exemptions.json +1 -1
package/.github/workflows/ci.yml
CHANGED
|
@@ -10,7 +10,7 @@ on:
|
|
|
10
10
|
permissions:
|
|
11
11
|
contents: read
|
|
12
12
|
pages: write
|
|
13
|
-
id-token: write
|
|
13
|
+
id-token: write # Required for GitHub Pages and npm OIDC trusted publishing
|
|
14
14
|
|
|
15
15
|
concurrency:
|
|
16
16
|
group: "pages"
|
|
@@ -27,7 +27,7 @@ jobs:
|
|
|
27
27
|
- name: Setup Node.js
|
|
28
28
|
uses: actions/setup-node@v4
|
|
29
29
|
with:
|
|
30
|
-
node-version: '
|
|
30
|
+
node-version: '24'
|
|
31
31
|
registry-url: 'https://registry.npmjs.org'
|
|
32
32
|
|
|
33
33
|
- name: Install dependencies
|
|
@@ -77,6 +77,9 @@ jobs:
|
|
|
77
77
|
runs-on: ubuntu-latest
|
|
78
78
|
name: Publish to NPM
|
|
79
79
|
if: startsWith(github.ref, 'refs/tags/v')
|
|
80
|
+
permissions:
|
|
81
|
+
contents: read
|
|
82
|
+
id-token: write # Required for npm OIDC trusted publishing
|
|
80
83
|
steps:
|
|
81
84
|
- name: Checkout code
|
|
82
85
|
uses: actions/checkout@v4
|
|
@@ -84,7 +87,7 @@ jobs:
|
|
|
84
87
|
- name: Setup Node.js
|
|
85
88
|
uses: actions/setup-node@v4
|
|
86
89
|
with:
|
|
87
|
-
node-version: '
|
|
90
|
+
node-version: '24'
|
|
88
91
|
registry-url: 'https://registry.npmjs.org'
|
|
89
92
|
|
|
90
93
|
- name: Install dependencies
|
|
@@ -96,7 +99,5 @@ jobs:
|
|
|
96
99
|
name: build-artifacts
|
|
97
100
|
path: dist/
|
|
98
101
|
|
|
99
|
-
- name: Publish to NPM
|
|
100
|
-
run: npm publish
|
|
101
|
-
env:
|
|
102
|
-
NODE_AUTH_TOKEN: ${{ secrets.NPM_TOKEN }}
|
|
102
|
+
- name: Publish to NPM with provenance
|
|
103
|
+
run: npm publish --provenance --access public
|
package/README.md
CHANGED
|
@@ -47,7 +47,7 @@ None of them have all the key features that make `mancha` unique:
|
|
|
47
47
|
| Feature | mancha | Svelte | React.js | Vue.js | petite-vue | Alpine.js |
|
|
48
48
|
| --------------------- | ------ | ------ | -------- | ------ | ---------- | --------- |
|
|
49
49
|
| Simple to learn | ✔️ | ❌ | ❌ | ❌ | ✔️ | ✔️ |
|
|
50
|
-
| <
|
|
50
|
+
| < 16kb compressed | ✔️ | ✔️ | ❌ | ❌ | ✔️ | ❌ |
|
|
51
51
|
| Custom web components | ✔️ | ✔️ | ✔️ | ✔️ | ❌ | ❌ |
|
|
52
52
|
| Client-side rendering | ✔️ | ❌ | ❌ | ✔️ | ✔️ | ✔️ |
|
|
53
53
|
| Server-side rendering | ✔️ | ✔️ | ✔️ | ✔️ | ❌ | ❌ |
|
|
@@ -157,6 +157,17 @@ element tag or attributes match a specific criteria. Here's the list of attribut
|
|
|
157
157
|
```html
|
|
158
158
|
<video :prop:src="buildSrc()"></video>
|
|
159
159
|
```
|
|
160
|
+
- `:render` links an element to a JavaScript ES module for initialization
|
|
161
|
+
```html
|
|
162
|
+
<canvas :render="./chart-init.js"></canvas>
|
|
163
|
+
```
|
|
164
|
+
The module's default export is called with the element and renderer:
|
|
165
|
+
```js
|
|
166
|
+
// chart-init.js
|
|
167
|
+
export default function (elem, renderer) {
|
|
168
|
+
new Chart(elem, { type: "bar" });
|
|
169
|
+
}
|
|
170
|
+
```
|
|
160
171
|
- `{{ value }}` replaces `value` in text nodes
|
|
161
172
|
```html
|
|
162
173
|
<button :data="{label: 'Click Me'}">{{ label }}</button>
|
|
@@ -177,8 +188,9 @@ element tag or attributes match a specific criteria. Here's the list of attribut
|
|
|
177
188
|
## Evaluation
|
|
178
189
|
|
|
179
190
|
To avoid violation of Content Security Policy (CSP) that forbids the use of `eval()`, `Mancha`
|
|
180
|
-
evaluates all expressions using
|
|
181
|
-
allowed,
|
|
191
|
+
evaluates all expressions using a safe expression parser. This means that only simple expressions are
|
|
192
|
+
allowed, but it supports many modern JavaScript features, including optional chaining, the spread
|
|
193
|
+
operator, and arrow functions. For example:
|
|
182
194
|
|
|
183
195
|
```html
|
|
184
196
|
<!-- Valid expression: string concatenation -->
|
|
@@ -186,6 +198,21 @@ allowed, and spaces must be used to separate different expression tokens. For ex
|
|
|
186
198
|
<p :text="'you are number ' + pos + ' in the queue'"></p>
|
|
187
199
|
</body>
|
|
188
200
|
|
|
201
|
+
<!-- Valid expression: optional chaining -->
|
|
202
|
+
<body :data="{ user: null }">
|
|
203
|
+
<p :text="user?.name ?? 'Anonymous'"></p>
|
|
204
|
+
</body>
|
|
205
|
+
|
|
206
|
+
<!-- Valid expression: spread operator -->
|
|
207
|
+
<body :data="{ list: [1, 2], extra: 3 }">
|
|
208
|
+
<div :for="item in [...list, extra]">{{ item }}</div>
|
|
209
|
+
</body>
|
|
210
|
+
|
|
211
|
+
<!-- Valid expression: arrow functions (e.g. in map) -->
|
|
212
|
+
<body :data="{ items: [1, 2, 3] }">
|
|
213
|
+
<div :for="n in items.map((x) => x * 2)">{{ n }}</div>
|
|
214
|
+
</body>
|
|
215
|
+
|
|
189
216
|
<!-- Valid expression: boolean logic -->
|
|
190
217
|
<body :data="{ pos: 1, finished: false }">
|
|
191
218
|
<p :show="pos >= 1 && !finished">you are number {{ pos }} in the queue</p>
|
|
@@ -215,24 +242,13 @@ allowed, and spaces must be used to separate different expression tokens. For ex
|
|
|
215
242
|
<button :on:click="pos = pos + 1">Click to get there faster</button>
|
|
216
243
|
</body>
|
|
217
244
|
|
|
218
|
-
<!-- Invalid expression: missing spaces -->
|
|
219
|
-
<body :data="{ pos: 1 }">
|
|
220
|
-
<p :text="'you are number '+pos+' in the queue'"></p>
|
|
221
|
-
</body>
|
|
222
|
-
|
|
223
245
|
<!-- Invalid expression: multiple statements -->
|
|
224
246
|
<button :on:click="console.log('yes'); answer = 'no'"></button>
|
|
225
247
|
|
|
226
|
-
<!-- Invalid expression: function definition -->
|
|
227
|
-
<body :data="{ foo: ()
|
|
248
|
+
<!-- Invalid expression: function definition (top-level) -->
|
|
249
|
+
<body :data="{ foo: function() { return 'yes'; } }">
|
|
228
250
|
<p :text="foo()"></p>
|
|
229
251
|
</body>
|
|
230
|
-
|
|
231
|
-
<!-- Invalid expression: complex assignment -->
|
|
232
|
-
<body :data="{ pos: 1 }">
|
|
233
|
-
<p :text="'you are number ' + pos + ' in the queue'"></p>
|
|
234
|
-
<button :on:click="pos++">Click to get there faster</button>
|
|
235
|
-
</body>
|
|
236
252
|
```
|
|
237
253
|
|
|
238
254
|
## Variable Scoping
|
|
@@ -245,7 +261,7 @@ illustrated with an example:
|
|
|
245
261
|
<!-- Hello, stranger -->
|
|
246
262
|
<h1>Hello, {{ name }}</h1>
|
|
247
263
|
|
|
248
|
-
<!-- undefined -->
|
|
264
|
+
<!-- Initially "undefined", but reactive to later changes -->
|
|
249
265
|
<span>{{ message }}</span>
|
|
250
266
|
|
|
251
267
|
<!-- How are you, danger? The secret message is "secret" and the key is "1234" -->
|
|
@@ -258,8 +274,10 @@ illustrated with an example:
|
|
|
258
274
|
By default, the target root element is the `body` tag. So, any variables defined in the body's
|
|
259
275
|
`:data` attribute are available to the main renderer.
|
|
260
276
|
|
|
261
|
-
In the example above, the
|
|
262
|
-
|
|
277
|
+
In the example above, the `<span>` references `message` which is not defined in the body's `:data`.
|
|
278
|
+
This auto-initializes `message` to `undefined` and attaches an observer, so setting `$.message`
|
|
279
|
+
later will update the `<span>` content. The `<p>` tag has its own local `message` variable which
|
|
280
|
+
shadows any parent value. Since the variables are not accessible via the global object, you'll need
|
|
263
281
|
to retrieve the renderer from the element's properties:
|
|
264
282
|
|
|
265
283
|
```js
|
|
@@ -270,8 +288,9 @@ await $.mount(document.body);
|
|
|
270
288
|
// This modifies the `name` variable in all the renderer contexts.
|
|
271
289
|
$.name = "world";
|
|
272
290
|
|
|
273
|
-
// This
|
|
274
|
-
//
|
|
291
|
+
// This updates the `<span>` content to "bandit" because `message` was
|
|
292
|
+
// auto-initialized when the template referenced it. However, the `<p>` tag
|
|
293
|
+
// still shows "secret" because it has its own local `message` variable.
|
|
275
294
|
$.message = "bandit";
|
|
276
295
|
|
|
277
296
|
// We extract the subrenderer from the element's properties. Only elements
|
|
@@ -284,7 +303,7 @@ subrenderer.$.message = "banana";
|
|
|
284
303
|
|
|
285
304
|
When accessing variables, `mancha` searches the current renderer first, then the parent, the
|
|
286
305
|
parent's parent, and so forth until the root renderer is reached. If the requested variable is not
|
|
287
|
-
found in the current renderer or any of the ancestor renderers, then `
|
|
306
|
+
found in the current renderer or any of the ancestor renderers, then `undefined` is returned:
|
|
288
307
|
|
|
289
308
|
```html
|
|
290
309
|
<body :data="{ name: 'stranger' }">
|
|
@@ -293,6 +312,52 @@ found in the current renderer or any of the ancestor renderers, then `null` is r
|
|
|
293
312
|
</body>
|
|
294
313
|
```
|
|
295
314
|
|
|
315
|
+
### Reactive Undefined Variables
|
|
316
|
+
|
|
317
|
+
When a variable is referenced in a template expression but not yet defined, `mancha` automatically
|
|
318
|
+
initializes it to `undefined` and attaches an observer. This means you can set the variable later
|
|
319
|
+
using the same renderer (or a subrenderer) and the template will reactively update:
|
|
320
|
+
|
|
321
|
+
```html
|
|
322
|
+
<body>
|
|
323
|
+
<!-- Initially shows "undefined", but updates reactively when `message` is set -->
|
|
324
|
+
<p>{{ message }}</p>
|
|
325
|
+
</body>
|
|
326
|
+
<script type="module">
|
|
327
|
+
const { $ } = Mancha;
|
|
328
|
+
await $.mount(document.body);
|
|
329
|
+
|
|
330
|
+
// The template initially renders with `message` as undefined.
|
|
331
|
+
// Setting it now will trigger a reactive update.
|
|
332
|
+
$.message = "Hello, World!";
|
|
333
|
+
</script>
|
|
334
|
+
```
|
|
335
|
+
|
|
336
|
+
This behavior is particularly useful with the `:render` attribute, where a JavaScript module can
|
|
337
|
+
set variables that are already referenced in the template:
|
|
338
|
+
|
|
339
|
+
```html
|
|
340
|
+
<div :render="./init.js">
|
|
341
|
+
<!-- These variables are set by the :render callback -->
|
|
342
|
+
<span>{{ title }}</span>
|
|
343
|
+
<ul :for="item in items">
|
|
344
|
+
<li>{{ item }}</li>
|
|
345
|
+
</ul>
|
|
346
|
+
</div>
|
|
347
|
+
```
|
|
348
|
+
|
|
349
|
+
```js
|
|
350
|
+
// init.js
|
|
351
|
+
export default async function (elem, renderer) {
|
|
352
|
+
await renderer.set("title", "My List");
|
|
353
|
+
await renderer.set("items", ["a", "b", "c"]);
|
|
354
|
+
}
|
|
355
|
+
```
|
|
356
|
+
|
|
357
|
+
The auto-initialization only happens when variables are accessed during an effect (such as template
|
|
358
|
+
rendering). Accessing a variable outside of an effect context will return `undefined` without
|
|
359
|
+
creating an observer.
|
|
360
|
+
|
|
296
361
|
When setting a variable, there are 3 possible cases:
|
|
297
362
|
|
|
298
363
|
1. The variable has already been defined in the current renderer. Then it gets updated in the
|
|
@@ -457,7 +522,5 @@ For a more complete example, see [examples/wrangler](./examples/wrangler).
|
|
|
457
522
|
|
|
458
523
|
## Dependencies
|
|
459
524
|
|
|
460
|
-
The browser bundle contains
|
|
525
|
+
The browser bundle contains no external dependencies. The unbundled version
|
|
461
526
|
can use `htmlparser2`, which is compatible with web workers, or `jsdom`.
|
|
462
|
-
|
|
463
|
-
[jexpr]: https://github.com/justinfagnani/jexpr
|
package/dist/browser.d.ts
CHANGED
|
@@ -1,8 +1,11 @@
|
|
|
1
1
|
import { IRenderer } from "./renderer.js";
|
|
2
|
-
import {
|
|
2
|
+
import type { StoreState } from "./store.js";
|
|
3
|
+
import type { ParserParams, RenderParams } from "./interfaces.js";
|
|
4
|
+
export { IRenderer } from "./renderer.js";
|
|
5
|
+
export type { ParserParams, RenderParams, RendererPlugin } from "./interfaces.js";
|
|
3
6
|
export { default as basicCssRules } from "./css_gen_basic.js";
|
|
4
7
|
export { default as utilsCssRules } from "./css_gen_utils.js";
|
|
5
|
-
export declare class Renderer extends IRenderer {
|
|
8
|
+
export declare class Renderer<T extends StoreState = StoreState> extends IRenderer<T> {
|
|
6
9
|
readonly impl = "browser";
|
|
7
10
|
protected readonly dirpath: string;
|
|
8
11
|
parseHTML(content: string, params?: ParserParams): Document | DocumentFragment;
|
|
@@ -11,4 +14,40 @@ export declare class Renderer extends IRenderer {
|
|
|
11
14
|
createElement(tag: string, owner?: Document | null): Element;
|
|
12
15
|
textContent(node: Node, content: string): void;
|
|
13
16
|
}
|
|
14
|
-
export declare const Mancha: Renderer
|
|
17
|
+
export declare const Mancha: Renderer<StoreState>;
|
|
18
|
+
/** Options for CSS injection. */
|
|
19
|
+
export type CssName = "basic" | "utils";
|
|
20
|
+
/**
|
|
21
|
+
* Injects CSS rules into the document head.
|
|
22
|
+
* @param names - Array of CSS names to inject ("basic", "utils").
|
|
23
|
+
*/
|
|
24
|
+
export declare function injectCss(names: CssName[]): void;
|
|
25
|
+
/**
|
|
26
|
+
* Injects the basic CSS rules into the document head.
|
|
27
|
+
*/
|
|
28
|
+
export declare function injectBasicCss(): void;
|
|
29
|
+
/**
|
|
30
|
+
* Injects the utils CSS rules into the document head.
|
|
31
|
+
*/
|
|
32
|
+
export declare function injectUtilsCss(): void;
|
|
33
|
+
/** Options for initializing Mancha. */
|
|
34
|
+
export interface InitManchaOptions {
|
|
35
|
+
/** CSS styles to inject before mounting. */
|
|
36
|
+
css?: CssName[];
|
|
37
|
+
/** Target selector(s) to mount the renderer to. */
|
|
38
|
+
target?: string | string[];
|
|
39
|
+
/** Enable debug mode. */
|
|
40
|
+
debug?: boolean;
|
|
41
|
+
/** Cache policy for fetch requests. */
|
|
42
|
+
cache?: RequestCache;
|
|
43
|
+
/** Initial state to set before mounting. */
|
|
44
|
+
state?: Record<string, unknown>;
|
|
45
|
+
}
|
|
46
|
+
/**
|
|
47
|
+
* Initializes Mancha with the provided options.
|
|
48
|
+
* This is a convenience function for bundled environments.
|
|
49
|
+
*
|
|
50
|
+
* @param options - Initialization options.
|
|
51
|
+
* @returns A promise that resolves to the Renderer instance.
|
|
52
|
+
*/
|
|
53
|
+
export declare function initMancha<T extends StoreState = StoreState>(options?: InitManchaOptions): Promise<Renderer<T>>;
|