@optionfactory/fml 9.0.0-rc2 → 9.0.0-rc20

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.
Files changed (44) hide show
  1. package/README.md +16 -89
  2. package/dist/client-errors.iife.js +23 -37
  3. package/dist/client-errors.iife.js.map +1 -1
  4. package/dist/client-errors.iife.min.js +1 -1
  5. package/dist/client-errors.iife.min.js.map +1 -1
  6. package/dist/custom-elements.json +459 -36
  7. package/dist/fml.css +24 -19
  8. package/dist/fml.css.map +1 -1
  9. package/dist/fml.iife.js +4646 -1779
  10. package/dist/fml.iife.js.map +1 -1
  11. package/dist/fml.iife.min.js +1 -1
  12. package/dist/fml.iife.min.js.map +1 -1
  13. package/dist/ftl.d.mts +395 -224
  14. package/dist/ftl.iife.js +402 -332
  15. package/dist/ftl.iife.js.map +1 -1
  16. package/dist/ftl.iife.min.js +1 -1
  17. package/dist/ftl.iife.min.js.map +1 -1
  18. package/dist/ftl.min.mjs +1 -1
  19. package/dist/ftl.min.mjs.map +1 -1
  20. package/dist/ftl.mjs +402 -332
  21. package/dist/ftl.mjs.map +1 -1
  22. package/dist/ful.css +24 -19
  23. package/dist/ful.css.map +1 -1
  24. package/dist/ful.d.mts +2801 -519
  25. package/dist/ful.iife.js +4096 -1275
  26. package/dist/ful.iife.js.map +1 -1
  27. package/dist/ful.iife.min.js +1 -1
  28. package/dist/ful.iife.min.js.map +1 -1
  29. package/dist/ful.min.mjs +1 -1
  30. package/dist/ful.min.mjs.map +1 -1
  31. package/dist/ful.mjs +4093 -1277
  32. package/dist/ful.mjs.map +1 -1
  33. package/dist/httpc.d.mts +139 -121
  34. package/dist/httpc.iife.js +137 -166
  35. package/dist/httpc.iife.js.map +1 -1
  36. package/dist/httpc.iife.min.js +1 -1
  37. package/dist/httpc.iife.min.js.map +1 -1
  38. package/dist/httpc.min.mjs +1 -1
  39. package/dist/httpc.min.mjs.map +1 -1
  40. package/dist/httpc.mjs +137 -166
  41. package/dist/httpc.mjs.map +1 -1
  42. package/dist/vscode.html-custom-data.json +215 -27
  43. package/dist/web-types.json +463 -36
  44. package/package.json +1 -1
package/dist/ftl.d.mts CHANGED
@@ -1,10 +1,6 @@
1
1
  /**
2
- * A Map bounded by entry count, evicting in insertion order: not an LRU (a hit
3
- * does not refresh an entry), just a cap keeping unbounded key spaces (parsed
4
- * expressions, compiled masks, formatter instances) from growing forever. The
5
- * capacity is sized so eviction never happens on a sane page: hitting it means
6
- * dynamically generated keys, where FIFO's worst case (evicting a hot entry)
7
- * costs one recomputation.
2
+ * A Map bounded by entry count, evicting the oldest entry when full. A hit does
3
+ * not refresh an entry: eviction follows insertion order, not use.
8
4
  */
9
5
  declare class BoundedCache {
10
6
  #private;
@@ -20,6 +16,7 @@ declare class BoundedCache {
20
16
  * @returns {V}
21
17
  */
22
18
  getOrCompute<K, V>(key: K, compute: (key: K) => V): V;
19
+ /** @returns {number} the number of entries held */
23
20
  get size(): number;
24
21
  }
25
22
  /**
@@ -31,22 +28,29 @@ declare class BoundedCache {
31
28
  */
32
29
  declare class Expressions {
33
30
  #private;
31
+ /** Parses the whole text as one expression: `user.name`. */
34
32
  static MODE_EXPRESSION: symbol;
33
+ /**
34
+ * Parses text with interpolations, `Hello {{ user.name }}`, evaluating to
35
+ * its parts: `{ type, value }` for each literal run and each `{{ }}` (text),
36
+ * `{{{ }}}` (html) or `{{{{ }}}}` (node) interpolation, in order.
37
+ */
35
38
  static MODE_TEMPLATED: symbol;
36
39
  /**
37
- * Parses an expression.
40
+ * Parses an expression, caching the ast by mode and text.
38
41
  * @param {string} expression
39
- * @param {(typeof Expressions.MODE_EXPRESSION | typeof Expressions.MODE_TEMPLATED)?} [mode]
40
- * @returns the ast
42
+ * @param {(typeof Expressions.MODE_EXPRESSION | typeof Expressions.MODE_TEMPLATED)?} [mode] MODE_EXPRESSION when omitted
43
+ * @returns {any} the ast
44
+ * @throws a peggy syntax error when the text does not parse
41
45
  */
42
46
  static parse(expression: string, mode?: (typeof Expressions.MODE_EXPRESSION | typeof Expressions.MODE_TEMPLATED) | null): any;
43
47
  /**
44
- * Evaluates an expression.
48
+ * Evaluates a parsed ast against the modules and the data stack.
45
49
  * @param {{[k: string]: any } | null | undefined } modules
46
- * @param {any[]} dataStack
47
- * @param {any} ast
48
- * @param {(typeof Expressions.MODE_EXPRESSION | typeof Expressions.MODE_TEMPLATED)?} [mode]
49
- * @returns the result
50
+ * @param {any[]} dataStack innermost overlay last
51
+ * @param {any} ast what `parse` answered
52
+ * @param {(typeof Expressions.MODE_EXPRESSION | typeof Expressions.MODE_TEMPLATED)?} [mode] the mode it was parsed in
53
+ * @returns {any} the value, or the list of parts in MODE_TEMPLATED
50
54
  */
51
55
  static evaluate(modules: {
52
56
  [k: string]: any;
@@ -54,10 +58,10 @@ declare class Expressions {
54
58
  /**
55
59
  * Parses and evaluates an expression.
56
60
  * @param {{ [x: string]: any; } | null | undefined} modules
57
- * @param {any[]} dataStack
61
+ * @param {any[]} dataStack innermost overlay last
58
62
  * @param {string} expression
59
- * @param {(typeof Expressions.MODE_EXPRESSION | typeof Expressions.MODE_TEMPLATED)?} [mode]
60
- * @returns the result
63
+ * @param {(typeof Expressions.MODE_EXPRESSION | typeof Expressions.MODE_TEMPLATED)?} [mode] MODE_EXPRESSION when omitted
64
+ * @returns {any} the value, or the list of parts in MODE_TEMPLATED
61
65
  */
62
66
  static interpret(modules: {
63
67
  [x: string]: any;
@@ -71,81 +75,116 @@ declare class Expressions {
71
75
  */
72
76
  declare class ExpressionEvaluator {
73
77
  #private;
74
- constructor(modules: any, dataStack: any);
75
- withModule(name: any, value: any): ExpressionEvaluator;
78
+ /**
79
+ * @param {{ [k: string]: any } | null | undefined} modules
80
+ * @param {any[]} dataStack innermost overlay last
81
+ */
82
+ constructor(modules: {
83
+ [k: string]: any;
84
+ } | null | undefined, dataStack: any[]);
85
+ /**
86
+ * A new evaluator with one more module: `#name:fn()` resolves into it, and an
87
+ * empty name merges a whole map whose functions resolve bare, as `#fn()`.
88
+ * @param {string} name
89
+ * @param {object} value
90
+ * @returns {ExpressionEvaluator}
91
+ */
92
+ withModule(name: string, value: object): ExpressionEvaluator;
93
+ /**
94
+ * A new evaluator with the data pushed as the innermost overlays, the last
95
+ * one winning a shared name.
96
+ * @param {...any} data
97
+ * @returns {ExpressionEvaluator}
98
+ */
76
99
  withOverlay(...data: any[]): ExpressionEvaluator;
77
100
  /**
78
101
  * Resolves a name against the data stack, with no parse round trip: the
79
102
  * lookup a template's bare identifier makes, for an imperative caller.
80
103
  * @param {string} name
104
+ * @returns {any} undefined when no overlay carries the name
81
105
  */
82
106
  resolve(name: string): any;
83
- /** Evaluates an expression against this scope. */
84
- evaluateExpression(expression: any): any;
85
- /** Evaluates a templated text, the `{{ }}` form, against this scope. */
86
- evaluateTemplated(text: any): any;
107
+ /**
108
+ * Evaluates an expression against this scope.
109
+ * @param {string} expression
110
+ * @returns {any}
111
+ */
112
+ evaluateExpression(expression: string): any;
113
+ /**
114
+ * Evaluates a templated text, the `{{ }}` form, against this scope.
115
+ * @param {string} text
116
+ * @returns {{ type: symbol, value: any }[]} its parts, as MODE_TEMPLATED describes
117
+ */
118
+ evaluateTemplated(text: string): {
119
+ type: symbol;
120
+ value: any;
121
+ }[];
87
122
  }
88
- /** Creates and inspects the DocumentFragments a Template renders into. */
123
+ /** Creates, serializes and inspects DocumentFragments. */
89
124
  declare class Fragments {
90
125
  /**
91
- * Creates a DocumentFragment from an string.
92
- * @param {...string} html
93
- * @returns {DocumentFragment} the fragment
126
+ * Parses html into a DocumentFragment adopted by the document, each piece
127
+ * trimmed and the pieces joined.
128
+ * @param {...string} html
129
+ * @returns {DocumentFragment}
94
130
  */
95
131
  static fromHtml(...html: string[]): DocumentFragment;
96
132
  /**
97
- * Creates a string representation (HTML) of a DocumentFragment, consuming it:
98
- * the nodes are moved out, not copied, and the fragment is left empty. Pass
133
+ * Serializes a fragment, or a single node, to html, consuming it: the nodes
134
+ * are moved out, not copied, and a fragment is left empty. Pass
99
135
  * `fragment.cloneNode(true)` to keep the original usable.
100
- * @param {DocumentFragment} fragment
101
- * @returns {string} the html
136
+ * @param {DocumentFragment|Node} fragment
137
+ * @returns {string}
102
138
  */
103
- static toHtml(fragment: DocumentFragment): string;
139
+ static toHtml(fragment: DocumentFragment | Node): string;
104
140
  /**
105
- * Checks if a fragment contains only blank text nodes
141
+ * Whether a fragment holds no element and no text but whitespace.
106
142
  * @param {DocumentFragment} fragment
107
- * @returns {boolean} true if the fragment is blank
143
+ * @returns {boolean}
108
144
  */
109
145
  static isBlank(fragment: DocumentFragment): boolean;
110
146
  /**
111
- * Creates a DocumentFragment from nodes.
112
- * @param {...Node} nodes
113
- * @returns {DocumentFragment} the fragment
147
+ * Moves the nodes, in order, into a new DocumentFragment.
148
+ * @param {...Node} nodes
149
+ * @returns {DocumentFragment}
114
150
  */
115
151
  static from(...nodes: Node[]): DocumentFragment;
116
152
  /**
117
- * Creates a DocumentFragment from childNodes of an element.
153
+ * Moves the children of a node into a new DocumentFragment, leaving the
154
+ * node empty.
118
155
  * @param {Node} el
119
- * @returns {DocumentFragment} the fragment
156
+ * @returns {DocumentFragment}
120
157
  */
121
158
  static fromChildNodes(el: Node): DocumentFragment;
122
159
  }
123
- /** Attribute reads and writes where a nullish value removes the attribute instead of setting it to the string 'null'. */
160
+ /** Attribute helpers: unique ids, defaults, prefixed forwarding, and writes where a nullish value removes the attribute. */
124
161
  declare class Attributes {
125
162
  static id: number;
126
163
  /**
127
- * Creates a unique id with the given prefix.
164
+ * A page-unique id under the prefix, as `prefix-n`.
128
165
  * @param {string} prefix
129
- * @returns
166
+ * @returns {string}
130
167
  */
131
168
  static uid(prefix: string): string;
132
169
  /**
133
- * Sets an attribute if not present.
170
+ * Sets an attribute when the element does not carry it.
134
171
  * @param {Element} el
135
172
  * @param {string} k
136
173
  * @param {string} v
137
- * @returns
174
+ * @returns {string|null} the attribute's value afterwards
138
175
  */
139
176
  static defaultValue(el: Element, k: string, v: string): string | null;
140
177
  /**
141
- * Forwards prefixed attributes from an element to another (removing the prefix).
178
+ * Copies every attribute whose name starts with the prefix onto another
179
+ * element, under the name without the prefix. `<prefix>class` adds its
180
+ * classes to the target's instead of replacing them.
142
181
  * @param {string} prefix
143
182
  * @param {Element} from
144
183
  * @param {Element} to
145
184
  */
146
185
  static forward(prefix: string, from: Element, to: Element): void;
147
186
  /**
148
- * Sets the value of an attribute. nullish values remove the attribute.
187
+ * Sets an attribute, or removes it when the value is nullish.
149
188
  * @param {Element} el
150
189
  * @param {string} attr
151
190
  * @param {string | null | undefined} value
@@ -160,67 +199,64 @@ declare class Attributes {
160
199
  */
161
200
  declare class LightSlots {
162
201
  /**
163
- * Extracts light slots from an element. For non default slots in a template tag, the content is extracted.
202
+ * Takes an element's children apart into slots, leaving the element empty.
203
+ * A named child is removed and contributes what `slotFromNode` answers;
204
+ * children sharing a name are gathered in order. A child with an empty
205
+ * `slot` belongs to the default slot, in document order among the rest.
164
206
  * @param {Element} el
165
- * @returns the slots
207
+ * @returns {Record<string, DocumentFragment>} the slots by name, `default` always present
166
208
  */
167
- static from(el: Element): {
168
- default: DocumentFragment;
169
- };
170
- static slotFromNode(el: any): any;
209
+ static from(el: Element): Record<string, DocumentFragment>;
210
+ /**
211
+ * What a slotted node contributes: a template's content, the parsed markup
212
+ * of a `<script type="text/html">`, or the node itself.
213
+ * @param {Element} el
214
+ * @returns {Element|DocumentFragment}
215
+ */
216
+ static slotFromNode(el: Element): Element | DocumentFragment;
171
217
  }
172
- /** Waits for the parser and for the document, for elements that upgrade before their own markup is complete. */
218
+ /** Waits on the parser and the document, and queries an element's own children. */
173
219
  declare class Nodes {
174
220
  /**
175
- * Checks if an element is already parsed.
221
+ * Whether the parser has moved past the element: the element, or one of
222
+ * its ancestors, has a next sibling.
176
223
  * @param {Element} el
177
- * @returns
224
+ * @returns {boolean}
178
225
  */
179
226
  static isParsed(el: Element): boolean;
180
227
  /**
181
- * Waits for the document's DOMContentLoaded, resolving immediately when
182
- * that moment already passed. 'interactive' alone cannot tell a document
183
- * still waiting for deferred scripts (the event comes, however late) from
184
- * a module imported past it (the event is gone): the two events order
185
- * themselves, DOMContentLoaded always precedes load, so racing the two
186
- * resolves with DCL whenever it is still coming and with load otherwise,
187
- * never early.
228
+ * Waits for the document's DOMContentLoaded. Resolves at once when that
229
+ * moment already passed, and for a document with no view, which receives
230
+ * no events. Never resolves early for a document still running its
231
+ * deferred scripts.
232
+ * @param {Document} doc
233
+ * @returns {Promise<void>}
188
234
  */
189
- static waitDomContentLoaded(doc: any): Promise<any>;
235
+ static waitDomContentLoaded(doc: Document): Promise<void>;
190
236
  /**
191
237
  * Waits for the element's closing tag to be parsed: one MutationObserver
192
238
  * resolves once the element, or any of its ancestors, gains a next sibling,
193
239
  * which is the parser having moved past this subtree. The document's
194
240
  * DOMContentLoaded is the deadline. Resolves immediately for an element
195
241
  * that is already parsed.
196
- *
197
- * Every ancestor is watched, not only the parent, because that is what the
198
- * predicate reads: an element last among its siblings becomes parsed when
199
- * an ancestor gains one, and a childList observer on the parent never sees
200
- * that. Formatted markup usually hides the difference, the whitespace
201
- * before a closing tag being a text node the parent does gain, so the gap
202
- * shows on whitespace-free markup, where the wait fell back to the
203
- * deadline. One observer takes many targets, so the cost is one observe()
204
- * per level, and it is disconnected at the first checkpoint past the
205
- * element either way.
206
- * @param {any} el
207
- * @returns {Promise<any>}
208
- */
209
- static waitParsed(el: any): Promise<any>;
210
- /**
211
- * Returns the first child of the element element (if exists) matching the selector.
212
242
  * @param {Element} el
243
+ * @returns {Promise<Element>} the element
244
+ */
245
+ static waitParsed(el: Element): Promise<Element>;
246
+ /**
247
+ * The first child element matching the selector, descendants excluded.
248
+ * @param {Element|DocumentFragment} el
213
249
  * @param {string} selector
214
- * @returns
250
+ * @returns {Element|null}
215
251
  */
216
- static queryChildren(el: Element, selector: string): Element | null;
252
+ static queryChildren(el: Element | DocumentFragment, selector: string): Element | null;
217
253
  /**
218
- * Returns all children of the element matching the selector.
219
- * @param {Element} el
254
+ * Every child element matching the selector, descendants excluded.
255
+ * @param {Element|DocumentFragment} el
220
256
  * @param {string} selector
221
- * @returns
257
+ * @returns {Element[]}
222
258
  */
223
- static queryChildrenAll(el: Element, selector: string): Element[];
259
+ static queryChildrenAll(el: Element | DocumentFragment, selector: string): Element[];
224
260
  }
225
261
  /**
226
262
  * A compiled fragment together with the scope it renders in. Both are
@@ -231,41 +267,45 @@ declare class Nodes {
231
267
  declare class Template {
232
268
  #private;
233
269
  /**
234
- * Creates a template from a string.
270
+ * Creates a template from html.
235
271
  * @param {string} html
236
272
  * @param {{ [k: string] : any }?} [modules]
237
- * @param {...*} data
238
- * @returns the template
273
+ * @param {...*} data the data stack, innermost last
274
+ * @returns {Template}
239
275
  */
240
276
  static fromHtml(html: string, modules?: {
241
277
  [k: string]: any;
242
278
  } | null, ...data: any[]): Template;
243
279
  /**
244
- * Creates a template from the content of the first template element matching the selector.
280
+ * Creates a template from the content of the first element matching the
281
+ * selector, which is adopted: the template element is left empty.
245
282
  * @param {string} selector for an HTMLTemplateElement
246
283
  * @param {{ [k: string] : any }?} [modules]
247
- * @param {...*} data
248
- * @returns the template
284
+ * @param {...*} data the data stack, innermost last
285
+ * @returns {Template}
286
+ * @throws when the selector matches no template element
249
287
  */
250
288
  static fromSelector(selector: string, modules?: {
251
289
  [k: string]: any;
252
290
  } | null, ...data: any[]): Template;
253
291
  /**
254
- * Creates a template from the content of an HTMLTemplateElement.
292
+ * Creates a template from the content of a template element, which is
293
+ * adopted: the template element is left empty.
255
294
  * @param {HTMLTemplateElement} templateEl
256
295
  * @param {{ [k: string] : any }?} [modules]
257
- * @param {...*} data
258
- * @returns the template
296
+ * @param {...*} data the data stack, innermost last
297
+ * @returns {Template}
259
298
  */
260
299
  static fromTemplate(templateEl: HTMLTemplateElement, modules?: {
261
300
  [k: string]: any;
262
301
  } | null, ...data: any[]): Template;
263
302
  /**
264
- * Creates a template from a DocumentFragment.
303
+ * Creates a template over a fragment, which is imported afresh on every
304
+ * render and never modified.
265
305
  * @param {DocumentFragment} fragment
266
306
  * @param { { [k: string] : any }? } [modules]
267
- * @param {...*} data
268
- * @returns the template
307
+ * @param {...*} data the data stack, innermost last
308
+ * @returns {Template}
269
309
  */
270
310
  static fromFragment(fragment: DocumentFragment, modules?: {
271
311
  [k: string]: any;
@@ -280,117 +320,151 @@ declare class Template {
280
320
  * Creates a new Template rendering in another scope: the one way to rebind
281
321
  * a compiled template to a registry's modules and data.
282
322
  * @param {ExpressionEvaluator} evaluator
323
+ * @returns {Template}
283
324
  */
284
325
  withEvaluator(evaluator: ExpressionEvaluator): Template;
285
326
  /**
286
- * Creates a new Template replacing the fragment.
327
+ * Creates a new Template over another fragment, in the same scope.
287
328
  * @param {DocumentFragment} fragment
329
+ * @returns {Template}
288
330
  */
289
331
  withFragment(fragment: DocumentFragment): Template;
290
332
  /**
291
- * Creates a new Template with a new module added.
333
+ * Creates a new Template with a module added, as `ExpressionEvaluator.withModule` does.
292
334
  * @param {string?} name
293
335
  * @param {{[k: string]: any}} value
336
+ * @returns {Template}
294
337
  */
295
338
  withModule(name: string | null, value: {
296
339
  [k: string]: any;
297
340
  }): Template;
298
341
  /**
299
- * Creates a new Template with new a data overlay added to the stack.
342
+ * Creates a new Template with the data pushed as the innermost overlays.
300
343
  * @param {...*} data
344
+ * @returns {Template}
301
345
  */
302
346
  withOverlay(...data: any[]): Template;
303
347
  /**
304
348
  * Evaluates an expression in this template's scope, widened by the overlays.
305
349
  * @param {string} expression
306
350
  * @param {...*} data
307
- * @returns the evaluated expression result
351
+ * @returns {any}
308
352
  */
309
353
  evaluateExpression(expression: string, ...data: any[]): any;
310
354
  /**
311
355
  * Evaluates a templated text, the `{{ }}` form, in this template's scope.
312
356
  * @param {string} text
313
357
  * @param {...*} data
314
- * @returns the parts the text evaluates to
358
+ * @returns {{ type: symbol, value: any }[]} the parts, as `Expressions.MODE_TEMPLATED` describes
315
359
  */
316
- evaluateTemplated(text: string, ...data: any[]): any;
360
+ evaluateTemplated(text: string, ...data: any[]): {
361
+ type: symbol;
362
+ value: any;
363
+ }[];
317
364
  /**
318
- * Returns an expression evaluator with bound modules and dataStack.
365
+ * The scope this template renders in.
366
+ * @returns {ExpressionEvaluator}
319
367
  */
320
368
  evaluator(): ExpressionEvaluator;
321
369
  /**
322
- * Renders the template.
323
- * @returns a DocumentFragment
370
+ * Renders the template into a new fragment, applying the `data-tpl-*`
371
+ * commands and bindings and the `{{ }}` interpolations.
372
+ * @returns {DocumentFragment}
373
+ * @throws {RenderError} naming the node and the directive that failed
324
374
  */
325
375
  render(): DocumentFragment;
326
376
  /**
327
- * Renders this template on the Element (replacing children).
377
+ * Renders this template into the element, replacing its children.
328
378
  * @param {Element} el
379
+ * @throws {RenderError}
329
380
  */
330
381
  renderTo(el: Element): void;
331
382
  /**
332
- * Renders this template appending the resulting fragment to the Element.
383
+ * Renders this template and appends the result to the element.
333
384
  * @param {Element} el
385
+ * @throws {RenderError}
334
386
  */
335
387
  appendTo(el: Element): void;
336
388
  /**
337
- * Renders this template on the first Element matching the selector (replacing children), if exists.
389
+ * Renders this template into the first element matching the selector,
390
+ * replacing its children; does nothing when none matches.
338
391
  * @param {string} selector
392
+ * @throws {RenderError}
339
393
  */
340
394
  renderToSelector(selector: string): void;
341
395
  /**
342
- * Renders this template appending the resulting fragment to the Element matching the selector, if exists.
396
+ * Renders this template and appends the result to the first element
397
+ * matching the selector; does nothing when none matches.
343
398
  * @param {string} selector
399
+ * @throws {RenderError}
344
400
  */
345
401
  appendToSelector(selector: string): void;
346
402
  }
347
403
  /**
348
- * A render failure, one frame per nesting level. Each frame names the node it
349
- * failed on and what was being evaluated there, so the chain reads as the path
350
- * from the template's root down to the offending expression. The frame carries
351
- * the node's identification only, an open tag rather than its whole subtree:
352
- * the markup is serialized on demand through `html`, and the live node stays on
353
- * `node`, so a failure costs no clone and a nested failure does not embed the
354
- * page in its own message.
404
+ * A render failure, one frame per nesting level, chained through `cause` from
405
+ * the outermost frame down to the error that failed the expression. A frame's
406
+ * message names what was being evaluated and the node's open tag, with the
407
+ * attributes it still carries: the directive being evaluated is already off
408
+ * the tag. The subtree is not in the message; `html` serializes it on demand.
355
409
  */
356
410
  declare class RenderError extends Error {
357
411
  #private;
358
- /**
359
- * How many frames a chain keeps. The innermost are the specific ones, so a
360
- * deeper nesting drops the outer context rather than the failure site: three
361
- * frames name the offending node and the two levels that hold it, which is
362
- * the path a reader follows without the page arriving with it.
363
- */
412
+ /** How many frames a chain keeps: a deeper nesting drops the outermost ones and marks the chain `truncated`. */
364
413
  static FRAMES: number;
365
- /** true when the budget dropped the outer frames of this chain */
414
+ /** Whether the chain dropped outer frames to stay within FRAMES. */
366
415
  truncated: boolean;
367
416
  /**
368
- * Frames a failure, unless the chain already spent its budget: then the
369
- * cause travels on, marked so a report can say the outer context was
370
- * dropped.
371
- */
372
- static wrap(message: any, nodeOrFragment: any, cause: any): RenderError;
373
- constructor(message: any, nodeOrFragment: any, cause: any);
374
- /** How many frames this chain carries, this one included. */
375
- get depth(): any;
376
- /** The node the render failed on, live: it keeps its place in the fragment being built. */
377
- get node(): any;
378
- /** The node's markup, serialized when asked for rather than on every failure. */
417
+ * Frames a failure, unless the chain already holds FRAMES frames: then the
418
+ * cause is returned as it is, marked `truncated`.
419
+ * @param {string} message
420
+ * @param {Node} nodeOrFragment the node that failed
421
+ * @param {any} cause
422
+ * @returns {RenderError}
423
+ */
424
+ static wrap(message: string, nodeOrFragment: Node, cause: any): RenderError;
425
+ /**
426
+ * @param {string} message
427
+ * @param {Node} nodeOrFragment the node that failed
428
+ * @param {any} cause
429
+ */
430
+ constructor(message: string, nodeOrFragment: Node, cause: any);
431
+ /**
432
+ * How many frames this chain carries, this one included.
433
+ * @returns {number}
434
+ */
435
+ get depth(): number;
436
+ /**
437
+ * The node the render failed on, live in the fragment being built.
438
+ * @returns {Node}
439
+ */
440
+ get node(): Node;
441
+ /**
442
+ * The failed node's markup, whitespace trimmed, serialized on each read.
443
+ * @returns {string}
444
+ */
379
445
  get html(): string;
380
446
  /**
381
447
  * What identifies a node in a frame: an element by its open tag, a text node
382
- * by its source, a fragment by the open tags of the elements it holds.
448
+ * by its source, a fragment by the open tags of the elements it holds, cut
449
+ * at 120 characters.
450
+ * @param {Node} nodeOrFragment
451
+ * @returns {string}
452
+ */
453
+ static describe(nodeOrFragment: Node): string;
454
+ /**
455
+ * A node's markup with its whitespace-only text dropped and the rest trimmed.
456
+ * @param {Node} nodeOrFragment left untouched: a clone is serialized
457
+ * @returns {string}
383
458
  */
384
- static describe(nodeOrFragment: any): any;
385
- static stringify(nodeOrFragment: any): string;
459
+ static stringify(nodeOrFragment: Node): string;
386
460
  }
387
461
  /**
388
462
  * The page's single source of truth for elements, modules, data, components
389
463
  * and attribute mappers. Elements defined before configure() are deferred and
390
464
  * defined by it; from then on every defineElement takes effect immediately.
391
465
  * The exported `registry` singleton is the page's own; a `new Registry()` is a
392
- * separate instance, and Rendering and the ftl:ready machinery wait on the
393
- * singleton alone.
466
+ * separate instance with its own upgrade queue, which dispatches its own
467
+ * ftl:ready on the document, while Rendering waits on the singleton alone.
394
468
  */
395
469
  declare class Registry {
396
470
  #private;
@@ -398,11 +472,14 @@ declare class Registry {
398
472
  * Registers a custom element under its tag: the class is augmented with its
399
473
  * BITS (observed attributes, mappers, templates) and handed to the platform.
400
474
  * Before configure() the definition is deferred, so import order never
401
- * matters.
475
+ * matters. The element resolves its templates and components through this
476
+ * registry, whichever one a module imports, and its `static config` is read
477
+ * here, so a page replacing it does so before the definition.
402
478
  * @param {string} tag
403
479
  * @param {*} klass a ParsedElement subclass
480
+ * @returns {Registry} this registry
404
481
  */
405
- defineElement(tag: string, klass: any): this;
482
+ defineElement(tag: string, klass: any): Registry;
406
483
  /**
407
484
  * The attribute declarations a class composes along its inheritance chain,
408
485
  * base first: `observed` stay live after the upgrade and drive the property
@@ -411,13 +488,8 @@ declare class Registry {
411
488
  * ancestors', so a base class declares what every subclass keeps observing
412
489
  * (a protocol attribute such as Field's disabled claim) and a leaf refines a
413
490
  * mapping, or moves a name's position, without repeating the whole list.
414
- *
415
- * The walk stops where the platform's own class hierarchy begins: no earlier
416
- * stop can work, since a registered ancestor carries an own BITS of its own,
417
- * and nothing above the elements declares anything.
418
- *
419
- * Everything deriving a component's attribute vocabulary reads it here, so
420
- * the runtime and whatever documents it cannot walk the chain differently.
491
+ * The observed attributes are applied in the composed order, a re-declared
492
+ * name taking the position of its last declaration.
421
493
  * @param {*} klass a ParsedElement subclass
422
494
  * @returns {{ observed: string[], attributes: string[] }}
423
495
  */
@@ -429,14 +501,7 @@ declare class Registry {
429
501
  * The property an observed attribute drives, by the platform's own
430
502
  * dash-to-camel rule: the one `dataset` applies, so `clear-invalid-on-change`
431
503
  * would reach `clearInvalidOnChange` the way `data-clear-invalid-on-change`
432
- * reaches `dataset.clearInvalidOnChange`. A single-word name is returned
433
- * unchanged, which is what every observed attribute in the library is.
434
- *
435
- * It exists because the observed tier is the one that becomes properties:
436
- * without it an attribute could only be observed if its name happened to be
437
- * a usable identifier, which is why every multiword observed attribute here
438
- * used to be squashed into one word while the configuration tier, which
439
- * never becomes a property, spelled the same idea with a dash.
504
+ * reaches `dataset.clearInvalidOnChange`.
440
505
  *
441
506
  * Only this direction is mapped. A property never derives its attribute: a
442
507
  * setter reflects through `reflectTo`, naming the attribute it writes.
@@ -450,65 +515,86 @@ declare class Registry {
450
515
  * as `#fn`.
451
516
  * @param {string} name
452
517
  * @param {object} value
518
+ * @returns {Registry} this registry
453
519
  */
454
- defineModule(name: string, value: object): this;
520
+ defineModule(name: string, value: object): Registry;
455
521
  /**
456
522
  * Replaces the whole module map.
457
523
  * @param {object} ms
524
+ * @returns {Registry} this registry
458
525
  */
459
- defineModules(ms: object): this;
526
+ defineModules(ms: object): Registry;
460
527
  /**
461
528
  * Registers a named component (a loader, a response mapper), fetched back
462
529
  * through component().
463
530
  * @param {string} name
464
531
  * @param {*} value
532
+ * @returns {Registry} this registry
465
533
  */
466
- defineComponent(name: string, value: any): this;
534
+ defineComponent(name: string, value: any): Registry;
467
535
  /**
468
536
  * Replaces the data stack the templates evaluate over.
469
537
  * @param {...any} data
538
+ * @returns {Registry} this registry
470
539
  */
471
- defineData(...data: any[]): this;
540
+ defineData(...data: any[]): Registry;
472
541
  /**
473
542
  * Appends to the data stack, the later entry winning a shared name.
474
543
  * @param {...any} data
544
+ * @returns {Registry} this registry
475
545
  */
476
- defineOverlay(...data: any[]): this;
546
+ defineOverlay(...data: any[]): Registry;
477
547
  /**
478
548
  * Registers a custom attribute mapper type, available to every later
479
549
  * `name:type` declaration.
480
550
  * @param {string} k
481
551
  * @param {{ unmarshal(str: string|null, name: string, el: Element): any, marshal(value: any, name: string, el: Element): string|null }} v
552
+ * @returns {Registry} this registry
482
553
  */
483
554
  defineMapper(k: string, v: {
484
555
  unmarshal(str: string | null, name: string, el: Element): any;
485
556
  marshal(value: any, name: string, el: Element): string | null;
486
- }): this;
557
+ }): Registry;
487
558
  /**
488
559
  * Hands the registry over to the plugin's configure.
489
560
  * @param {{ configure(registry: Registry): void }} p
561
+ * @returns {Registry} this registry
490
562
  */
491
563
  plugin(p: {
492
564
  configure(registry: Registry): void;
493
- }): this;
565
+ }): Registry;
494
566
  /**
495
567
  * Defines every element deferred so far; from then on, defineElement takes
496
568
  * effect immediately.
569
+ * @returns {Registry} this registry
497
570
  */
498
- configure(): this;
571
+ configure(): Registry;
499
572
  /**
500
573
  * Waits for the queued upgrades the filter accepts, rejecting with the first
501
- * that failed: the rejecting barrier Rendering is a facade over.
574
+ * that failed, the upgrades enqueued meanwhile included: the rejecting
575
+ * barrier Rendering is a facade over.
502
576
  * @param {(el: Element) => boolean} accept
577
+ * @returns {Promise<void>}
503
578
  */
504
579
  settle(accept: (el: Element) => boolean): Promise<void>;
505
- /** The pending upgrade of one element, undefined when it is not queued. */
506
- whenUpgraded(el: any): any;
507
- /** The elements whose upgrade is still pending, in queue order. */
508
- pending(): any[];
509
580
  /**
510
- * Waits for the page's readiness: the same moment the ftl:ready event is
511
- * dispatched at, resolving immediately when that moment already passed.
581
+ * The pending upgrade of one element: resolving when it has rendered,
582
+ * rejecting with what its upgrade threw.
583
+ * @param {Element} el
584
+ * @returns {Promise<void>|undefined} undefined when the element is not queued
585
+ */
586
+ whenUpgraded(el: Element): Promise<void> | undefined;
587
+ /**
588
+ * The elements whose upgrade is still pending, in queue order.
589
+ * @returns {Element[]}
590
+ */
591
+ pending(): Element[];
592
+ /**
593
+ * Waits for this registry's readiness: resolves right after its ftl:ready
594
+ * event is dispatched on the document, and immediately when that already
595
+ * happened. Never rejects: a failed upgrade counts as settled, and its
596
+ * rejection is left unhandled so it still reaches the console and the
597
+ * page's error reporting.
512
598
  * @returns {Promise<void>}
513
599
  */
514
600
  ready(): Promise<void>;
@@ -516,29 +602,60 @@ declare class Registry {
516
602
  * The scope every template on this registry renders in: the modules and the
517
603
  * data stack, as one value. Replaced whenever either is defined, so a holder
518
604
  * of an older one keeps rendering against what it was handed.
605
+ * @returns {ExpressionEvaluator}
519
606
  */
520
607
  evaluator(): ExpressionEvaluator;
521
- /** The component registered under the name, undefined when none is. */
522
- component(name: any): any;
608
+ /**
609
+ * The component registered under the name.
610
+ * @param {string} name
611
+ * @returns {any} undefined when none is
612
+ */
613
+ component(name: string): any;
523
614
  }
524
615
  declare const registry: Registry;
525
- /** The Template factories, each bound to the page registry's scope. */
526
616
  /** The Template factories bound to the page's own registry: the same four sources, with its modules and data already applied. */
527
617
  declare class Templates {
528
- static fromHtml(html: any): Template;
529
- static fromSelector(selector: any): Template;
530
- static fromTemplate(templateEl: any): Template;
531
- static fromFragment(fragment: any): Template;
618
+ /**
619
+ * @param {string} html
620
+ * @returns {Template}
621
+ */
622
+ static fromHtml(html: string): Template;
623
+ /**
624
+ * @param {string} selector for an HTMLTemplateElement
625
+ * @returns {Template}
626
+ */
627
+ static fromSelector(selector: string): Template;
628
+ /**
629
+ * @param {HTMLTemplateElement} templateEl consumed: its content is adopted
630
+ * @returns {Template}
631
+ */
632
+ static fromTemplate(templateEl: HTMLTemplateElement): Template;
633
+ /**
634
+ * @param {DocumentFragment} fragment
635
+ * @returns {Template}
636
+ */
637
+ static fromFragment(fragment: DocumentFragment): Template;
532
638
  }
533
639
  /**
534
- * Awaitable rendering barriers over the registry's upgrade queue. These are
535
- * the rejecting waits: a failed upgrade among the awaited components rejects
536
- * the wait, where registry.ready() only ever means the queue drained and
537
- * leaves a failed component to its own unhandled-rejection report.
640
+ * Waits for elements queued on the page's `registry` to render. Unlike
641
+ * `registry.ready()`, these reject when an awaited upgrade fails. An element
642
+ * defined by another Registry is awaited through that registry instead.
538
643
  */
539
644
  declare class Rendering {
540
- static waitFor(el: any): Promise<void>;
541
- static waitForChildren(el: any): Promise<void>;
645
+ /**
646
+ * Waits for the element and its descendants, the ones their own renders
647
+ * enqueue included.
648
+ * @param {Element} el
649
+ * @returns {Promise<void>} rejecting with the first upgrade that failed
650
+ */
651
+ static waitFor(el: Element): Promise<void>;
652
+ /**
653
+ * Waits for the element's descendants, the element itself excluded: what a
654
+ * component awaits from inside its own render.
655
+ * @param {Element} el
656
+ * @returns {Promise<void>} rejecting with the first upgrade that failed
657
+ */
658
+ static waitForChildren(el: Element): Promise<void>;
542
659
  }
543
660
  export type Mapper = {
544
661
  unmarshal: (val: string | null | undefined, name: string, el: Element) => any;
@@ -551,6 +668,13 @@ export type Mapper = {
551
668
  * @property {(val: string|null|undefined, name: string, el: Element) => any} unmarshal
552
669
  * @property {(val: any, name: string, el: Element) => string|null} marshal
553
670
  */
671
+ /**
672
+ * The base of every fml element. A subclass declares its attributes, slots and
673
+ * templates in statics and builds its dom in `render`; the base reads the light
674
+ * slots, reads the declared attributes through their mappers, renders once, and
675
+ * then forwards observed attribute writes to the matching properties. An element
676
+ * resolves templates and components through the registry that defined it.
677
+ */
554
678
  declare class ParsedElement extends HTMLElement {
555
679
  #private;
556
680
  static BITS: {
@@ -572,41 +696,65 @@ declare class ParsedElement extends HTMLElement {
572
696
  static get observedAttributes(): string[];
573
697
  constructor();
574
698
  /**
575
- * The platform's window into the element's own state. The base attaches it
576
- * for every element, so a subclass never calls attachInternals itself: the
577
- * platform allows it once, and a second call throws. Form association is a
578
- * property of the definition rather than of who attached, so a subclass
579
- * declaring `static formAssociated` still gets the form apis here.
580
- *
581
- * A subclass must not redeclare it: a class field with no initializer
582
- * assigns undefined after super() returns, which would wipe it.
699
+ * The element's ElementInternals, attached by the base for every element: a
700
+ * subclass never calls attachInternals itself, since a second call throws.
701
+ * A subclass declaring `static formAssociated` gets the form apis here.
702
+ * A subclass must not redeclare the field: a class field without an
703
+ * initializer assigns undefined after super() returns, wiping it.
704
+ * @type {ElementInternals}
583
705
  */
584
706
  internals: ElementInternals;
585
- unmarshal(attr: any, str: any): any;
586
- marshal(attr: any, value: any): string | null;
587
707
  /**
588
- * @param {string} [name] - The name of the template target, defaults to 'default'
708
+ * Reads an attribute value through the mapper it was declared with.
709
+ * @param {string} attr
710
+ * @param {string|null} str
711
+ * @returns {any}
712
+ * @throws when the class declares no such attribute; read undeclared ones with getAttribute
589
713
  */
590
- /** The registry that defined this element, the page's own for an undefined one. */
591
- get _registry(): Registry;
714
+ unmarshal(attr: string, str: string | null): any;
715
+ /**
716
+ * Writes a value as the attribute string its declared mapper produces.
717
+ * @param {string} attr
718
+ * @param {any} value
719
+ * @returns {string|null} null for a value that removes the attribute
720
+ * @throws when the class declares no such attribute
721
+ */
722
+ marshal(attr: string, value: any): string | null;
723
+ /**
724
+ * The registry that defined this element, the page's own for an undefined one.
725
+ * @returns {typeof registry}
726
+ */
727
+ get _registry(): typeof registry;
592
728
  /**
593
729
  * The component registered under the name on this element's registry, the
594
730
  * one every ful loader and mapper resolves through.
595
731
  * @param {string} name
732
+ * @returns {any} undefined when none is registered
596
733
  */
597
734
  component(name: string): any;
598
- template(name: any): any;
735
+ /**
736
+ * One of the class's templates, bound to its registry's scope with the
737
+ * class's `static config` overlaid as `config`.
738
+ * @param {string} [name] 'default', the `static template`, when omitted
739
+ * @returns {Template}
740
+ * @throws when the class declares no template of that name
741
+ */
742
+ template(name?: string): Template;
599
743
  connectedCallback(): void;
600
744
  attributeChangedCallback(attr: any, oldValue: any, newValue: any): void;
601
745
  /**
602
- * Upgrades once: reads the declared attributes, keeps the observed half open
603
- * to writes made while the render is pending, applies them to the properties
604
- * when the render returns, and only then lets an attribute write forward.
746
+ * Upgrades once, however often the element is connected: reads the declared
747
+ * attributes, keeps the observed ones open to writes made while the render is
748
+ * pending, renders, then applies the observed values to their properties in
749
+ * the order the registry composed them, a base class's before a subclass's.
750
+ * Only then do attribute writes forward to properties, and the element gains
751
+ * the `rendered` custom state. A render that throws leaves the forwarding
752
+ * shut and the state unset.
605
753
  *
606
754
  * An observed attribute drives the property the registry's `propertyOf`
607
755
  * names, so a hyphenated attribute is authored with its dashes and read as
608
- * a camelCase property. A single-word attribute is its own property name,
609
- * which is what every observed attribute in the library is.
756
+ * a camelCase property.
757
+ * @returns {Promise<void>} rejecting with what the render threw
610
758
  */
611
759
  upgrade(): Promise<void>;
612
760
  /**
@@ -614,12 +762,13 @@ declare class ParsedElement extends HTMLElement {
614
762
  * drive, and the base applies the declared state onto the properties as
615
763
  * soon as it returns. A render needing a declared value while it builds
616
764
  * reads it through `declared(name)`. The slots are undefined for an element
617
- * declaring no slots.
618
- * @param {{ slots: any }} c
765
+ * declaring no slots. It may be async; the upgrade awaits it.
766
+ * @param {{ slots: Record<string, DocumentFragment> | undefined }} c
767
+ * @returns {void | Promise<void>}
619
768
  */
620
769
  render(c: {
621
- slots: any;
622
- }): void;
770
+ slots: Record<string, DocumentFragment> | undefined;
771
+ }): void | Promise<void>;
623
772
  /**
624
773
  * The declared value of an attribute, unmarshalled through its mapper.
625
774
  *
@@ -629,21 +778,21 @@ declare class ParsedElement extends HTMLElement {
629
778
  * observed name answers the snapshot while the render is pending, kept
630
779
  * open to attribute writes landing in that window, and the live attribute
631
780
  * afterwards, the property being live by then.
632
- *
633
- * The snapshot exists rather than a read of the dom because an element may
634
- * write its own observed attributes while it renders, whether a reflection
635
- * or a value the platform normalizes on the way in, and what the author
636
- * declared is what the base applies, not what the render left behind.
637
781
  * @param {string} name
782
+ * @returns {any}
783
+ * @throws when the class declares no such attribute
638
784
  */
639
785
  declared(name: string): any;
640
- /** Whether the element's render completed: the moment its properties went live. */
786
+ /**
787
+ * Whether the element's render completed: the moment its properties went
788
+ * live, which css reads as `:state(rendered)`. Unlike `:defined`, which holds
789
+ * from the constructor, it is false until the dom exists.
790
+ * @returns {boolean}
791
+ */
641
792
  get rendered(): boolean;
642
793
  /**
643
794
  * Projects a property back onto its observed attribute, marshalled through
644
- * the mapper the attribute was declared with: the one place a property
645
- * reaches its attribute, so a setter never has to know how its own type
646
- * serializes.
795
+ * the mapper the attribute was declared with.
647
796
  *
648
797
  * A value the attribute already carries is not written at all, so reflecting
649
798
  * what an attribute write just delivered ends there rather than looping, and
@@ -674,6 +823,9 @@ declare class Localization {
674
823
  *
675
824
  * @param {string} key
676
825
  * @param {...any} args
826
+ * Each problem (a missing key, placeholder or plural form) is warned once
827
+ * per page.
828
+ *
677
829
  * @this {Receiver}
678
830
  * @returns {string} the message, or the key itself when the translations do not carry it
679
831
  */
@@ -684,16 +836,18 @@ declare class Localization {
684
836
  * @param {Date | number} value
685
837
  * @param {Intl.DateTimeFormatOptions} [options]
686
838
  * @this {Receiver}
839
+ * @returns {string}
687
840
  */
688
- static date(this: Receiver, value: Date | number, options?: Intl.DateTimeFormatOptions): any;
841
+ static date(this: Receiver, value: Date | number, options?: Intl.DateTimeFormatOptions): string;
689
842
  /**
690
843
  * Formats a number through Intl.NumberFormat in the receiver's locale.
691
844
  *
692
845
  * @param {number} value
693
846
  * @param {Intl.NumberFormatOptions} [options]
694
847
  * @this {Receiver}
848
+ * @returns {string}
695
849
  */
696
- static number(this: Receiver, value: number, options?: Intl.NumberFormatOptions): any;
850
+ static number(this: Receiver, value: number, options?: Intl.NumberFormatOptions): string;
697
851
  /**
698
852
  * Formats a byte size with binary thresholds and literal unit suffixes:
699
853
  * the digits honor the locale, the units are the near-universal KiB/MiB/GiB.
@@ -701,21 +855,38 @@ declare class Localization {
701
855
  *
702
856
  * @param {number} value
703
857
  * @this {Receiver}
858
+ * @returns {string}
704
859
  */
705
860
  static bytes(this: Receiver, value: number): string;
861
+ /**
862
+ * What went wrong, as text for the reader. A value carrying a non-empty
863
+ * `problems` array reads as their reasons, one per line, a blank or missing
864
+ * reason reading as the `failure.no-reason` message. Any other value with a
865
+ * `message` reads as that message; anything else as its string form, and
866
+ * null or undefined as the empty string.
867
+ *
868
+ * @param {any} value what was thrown or rejected with
869
+ * @this {Receiver}
870
+ * @returns {string}
871
+ */
872
+ static failure(this: Receiver, value: any): string;
706
873
  /**
707
874
  * An imperative facade over the module functions, resolving the translations
708
- * and the locale from the registry overlays on every call.
875
+ * and the locale from the registry overlays on every call, the same lookup a
876
+ * template makes: a facade taken at module scope, before the plugin
877
+ * configures, still sees the translations.
709
878
  *
710
879
  * @param {{ locale?: string }} [overrides] an explicit locale, winning over the registry one
880
+ * @returns {{ t: (key: string, ...args: any[]) => string, date: (value: Date | number, options?: Intl.DateTimeFormatOptions) => string, number: (value: number, options?: Intl.NumberFormatOptions) => string, bytes: (value: number) => string, failure: (value: any) => string }}
711
881
  */
712
882
  static of(overrides?: {
713
883
  locale?: string;
714
884
  }): {
715
- t: (...args: any[]) => any;
716
- date: (...args: any[]) => any;
717
- number: (...args: any[]) => any;
718
- bytes: (...args: any[]) => any;
885
+ t: (key: string, ...args: any[]) => string;
886
+ date: (value: Date | number, options?: Intl.DateTimeFormatOptions) => string;
887
+ number: (value: number, options?: Intl.NumberFormatOptions) => string;
888
+ bytes: (value: number) => string;
889
+ failure: (value: any) => string;
719
890
  };
720
891
  }
721
892
  export { Attributes, BoundedCache, ExpressionEvaluator, Expressions, Fragments, LightSlots, Localization, Nodes, ParsedElement, Registry, RenderError, Rendering, Template, Templates, registry };