jtlt 0.12.0 → 0.13.0
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/CHANGES.md +5 -0
- package/README.md +9 -5
- package/demo/calltemplate-params-demo.js +19 -15
- package/demo/codemirror.esm.js +140 -70
- package/demo/codemirror.js +9 -5
- package/demo/index.js +2 -1
- package/demo/vendor/fontoxpath/dist/fontoxpath.esm.js +508 -499
- package/demo/vendor/jamilih/dist/jml.mjs +516 -225
- package/demo/vendor/jsonpath-plus/dist/index-browser-esm.js +11 -5
- package/dist/AbstractJoiningTransformer.d.ts +12 -20
- package/dist/AbstractJoiningTransformer.d.ts.map +1 -1
- package/dist/DOMJoiningTransformer.d.ts +502 -19
- package/dist/DOMJoiningTransformer.d.ts.map +1 -1
- package/dist/JSONJoiningTransformer.d.ts +41 -25
- package/dist/JSONJoiningTransformer.d.ts.map +1 -1
- package/dist/JSONPathTransformer.d.ts +20 -20
- package/dist/JSONPathTransformer.d.ts.map +1 -1
- package/dist/JSONPathTransformerContext.d.ts +103 -80
- package/dist/JSONPathTransformerContext.d.ts.map +1 -1
- package/dist/StringJoiningTransformer.d.ts +42 -28
- package/dist/StringJoiningTransformer.d.ts.map +1 -1
- package/dist/XPathTransformer.d.ts +11 -11
- package/dist/XPathTransformer.d.ts.map +1 -1
- package/dist/XPathTransformerContext.d.ts +47 -45
- package/dist/XPathTransformerContext.d.ts.map +1 -1
- package/dist/XSLTStyleJSONPathResolver.d.ts +1 -1
- package/dist/XSLTStyleJSONPathResolver.d.ts.map +1 -1
- package/dist/index-browser.d.ts +2 -2
- package/dist/index-browser.d.ts.map +1 -1
- package/dist/index-node.d.ts +2 -2
- package/dist/index-node.d.ts.map +1 -1
- package/dist/index.d.ts +126 -167
- package/dist/index.d.ts.map +1 -1
- package/docs/API.expanded.md +6 -4
- package/docs/API.md +1 -1
- package/docs/TO-DO.md +4 -2
- package/eslint.config.js +17 -1
- package/package.json +23 -22
- package/pnpm-workspace.yaml +32 -4
- package/rollup.config.js +42 -0
- package/src/AbstractJoiningTransformer.js +8 -1
- package/src/DOMJoiningTransformer.js +56 -27
- package/src/JSONJoiningTransformer.js +64 -44
- package/src/JSONPathTransformer.js +86 -85
- package/src/JSONPathTransformerContext.js +95 -48
- package/src/StringJoiningTransformer.js +48 -23
- package/src/XPathTransformer.js +18 -14
- package/src/XPathTransformerContext.js +173 -123
- package/src/index-browser.js +1 -0
- package/src/index-node.js +2 -0
- package/src/index.js +125 -68
- package/test.html +17 -0
- package/test.js +45 -0
- package/tsconfig-prod.json +1 -0
- package/tsconfig.json +3 -2
- package/dist/types.d.ts +0 -204
- package/dist/types.d.ts.map +0 -1
|
@@ -1,6 +1,7 @@
|
|
|
1
|
-
/* eslint-disable sonarjs/updated-loop-counter -- Ok */
|
|
2
1
|
/* eslint-disable unicorn/prefer-global-this -- Easier */
|
|
2
|
+
/* eslint-disable unicorn/no-break-in-nested-loop -- Performance to avoid function? */
|
|
3
3
|
/* eslint-disable sonarjs/no-control-regex -- Intentional */
|
|
4
|
+
/* eslint-disable unicorn/no-top-level-assignment-in-function -- Only need module level */
|
|
4
5
|
/*
|
|
5
6
|
Possible todos:
|
|
6
7
|
0. Add XSLT to JML-string stylesheet (or even vice versa)
|
|
@@ -23,11 +24,28 @@ Other Todos:
|
|
|
23
24
|
*/
|
|
24
25
|
|
|
25
26
|
/**
|
|
26
|
-
* @typedef {Window & {DocumentFragment:
|
|
27
|
+
* @typedef {Window & {DocumentFragment: typeof DocumentFragment}} HTMLWindow
|
|
27
28
|
*/
|
|
28
29
|
|
|
29
30
|
/**
|
|
30
|
-
* @typedef {
|
|
31
|
+
* @typedef {unknown} ArbitraryValue
|
|
32
|
+
*/
|
|
33
|
+
|
|
34
|
+
/**
|
|
35
|
+
* @typedef {unknown} StoredValue
|
|
36
|
+
*/
|
|
37
|
+
|
|
38
|
+
/* eslint-disable jsdoc/reject-any-type -- user-defined callback arguments */
|
|
39
|
+
/**
|
|
40
|
+
* @typedef {any} UserArg
|
|
41
|
+
*/
|
|
42
|
+
/**
|
|
43
|
+
* @typedef {any} ElementExpando
|
|
44
|
+
*/
|
|
45
|
+
/* eslint-enable jsdoc/reject-any-type */
|
|
46
|
+
|
|
47
|
+
/**
|
|
48
|
+
* @typedef {HTMLElement & {[key: string]: ElementExpando}} ExpandoHTMLElement
|
|
31
49
|
*/
|
|
32
50
|
|
|
33
51
|
/**
|
|
@@ -49,7 +67,7 @@ Other Todos:
|
|
|
49
67
|
*/
|
|
50
68
|
|
|
51
69
|
/**
|
|
52
|
-
* @type {import('jsdom').DOMWindow|HTMLWindow|undefined}
|
|
70
|
+
* @type {import('jsdom').DOMWindow|HTMLWindow|typeof globalThis|undefined}
|
|
53
71
|
*/
|
|
54
72
|
let win;
|
|
55
73
|
|
|
@@ -152,9 +170,10 @@ function _appendNode(parent, child) {
|
|
|
152
170
|
/**
|
|
153
171
|
* Attach event in a cross-browser fashion.
|
|
154
172
|
* @static
|
|
155
|
-
* @
|
|
173
|
+
* @template {HTMLElement} T
|
|
174
|
+
* @param {T} el DOM element to which to attach the event
|
|
156
175
|
* @param {string} type The DOM event (without 'on') to attach to the element
|
|
157
|
-
* @param {(evt: Event & {target:
|
|
176
|
+
* @param {(evt: Event & {target: T}) => void} handler The event handler to attach to the element
|
|
158
177
|
* @param {boolean} [capturing] Whether or not the event should be
|
|
159
178
|
* capturing (W3C-browsers only); default is false; NOT IN USE
|
|
160
179
|
* @returns {void}
|
|
@@ -165,13 +184,13 @@ function _addEvent(el, type, handler, capturing) {
|
|
|
165
184
|
}
|
|
166
185
|
|
|
167
186
|
/**
|
|
168
|
-
* Creates a text node of the result of resolving an entity or character reference.
|
|
169
|
-
* @param {'entity'|'decimal'|'hexadecimal'} type Type of reference
|
|
170
|
-
* @param {string} prefix Text to prefix immediately after the "&"
|
|
171
|
-
* @param {string} arg The body of the reference
|
|
172
|
-
* @throws {TypeError}
|
|
173
|
-
* @returns {Text} The text node of the resolved reference
|
|
174
|
-
*/
|
|
187
|
+
* Creates a text node of the result of resolving an entity or character reference.
|
|
188
|
+
* @param {'entity'|'decimal'|'hexadecimal'} type Type of reference
|
|
189
|
+
* @param {string} prefix Text to prefix immediately after the "&"
|
|
190
|
+
* @param {string} arg The body of the reference
|
|
191
|
+
* @throws {TypeError}
|
|
192
|
+
* @returns {Text} The text node of the resolved reference
|
|
193
|
+
*/
|
|
175
194
|
function _createSafeReference(type, prefix, arg) {
|
|
176
195
|
/* c8 ignore next 3 */
|
|
177
196
|
if (!doc) {
|
|
@@ -184,16 +203,17 @@ function _createSafeReference(type, prefix, arg) {
|
|
|
184
203
|
}
|
|
185
204
|
const elContainer = doc.createElement('div');
|
|
186
205
|
// Todo: No workaround for XML?
|
|
187
|
-
//
|
|
206
|
+
// eslint-disable-next-line no-unsanitized/property
|
|
188
207
|
elContainer.innerHTML = '&' + prefix + arg + ';';
|
|
208
|
+
// eslint-disable-next-line unicorn/prefer-dom-node-html-methods -- No Safari support
|
|
189
209
|
return doc.createTextNode(elContainer.innerHTML);
|
|
190
210
|
}
|
|
191
211
|
|
|
192
212
|
/**
|
|
193
|
-
* @param {string} n0 Whole expression match (including "-")
|
|
194
|
-
* @param {string} n1 Lower-case letter match
|
|
195
|
-
* @returns {string} Uppercased letter
|
|
196
|
-
*/
|
|
213
|
+
* @param {string} n0 Whole expression match (including "-")
|
|
214
|
+
* @param {string} n1 Lower-case letter match
|
|
215
|
+
* @returns {string} Uppercased letter
|
|
216
|
+
*/
|
|
197
217
|
function _upperCase(n0, n1) {
|
|
198
218
|
return n1.toUpperCase();
|
|
199
219
|
}
|
|
@@ -207,24 +227,31 @@ function _isNullish(o) {
|
|
|
207
227
|
return o === null || o === undefined;
|
|
208
228
|
}
|
|
209
229
|
|
|
230
|
+
/**
|
|
231
|
+
* @param {unknown} item
|
|
232
|
+
* @returns {item is HTMLElement}
|
|
233
|
+
*/
|
|
234
|
+
function _isHTMLElement(item) {
|
|
235
|
+
return Boolean(item && typeof item === 'object' && 'nodeType' in item && item.nodeType === 1);
|
|
236
|
+
}
|
|
237
|
+
|
|
210
238
|
// Todo: Make as public utility, but also return types for undefined, boolean, number, document, etc.
|
|
211
239
|
/**
|
|
212
|
-
* @private
|
|
213
|
-
* @static
|
|
214
|
-
* @param {string|JamilihAttributes|JamilihArray|JamilihChildren|
|
|
215
|
-
* JamilihDocumentFragment|JamilihAttributeNode|
|
|
216
|
-
* JamilihOptions|HTMLElement|Document|DocumentFragment|null|undefined} item
|
|
217
|
-
* @returns {"string"|"null"|"array"|"element"|"fragment"|"object"|
|
|
218
|
-
* "symbol"|"bigint"|"function"|"number"|"boolean"|"undefined"|
|
|
219
|
-
* "document"|"processing-instruction"|"non-container node"}
|
|
220
|
-
*/
|
|
240
|
+
* @private
|
|
241
|
+
* @static
|
|
242
|
+
* @param {string|JamilihAttributes|JamilihArray|JamilihChildren|
|
|
243
|
+
* JamilihDocumentFragment|JamilihAttributeNode|
|
|
244
|
+
* JamilihOptions|HTMLElement|Document|DocumentFragment|null|undefined} item
|
|
245
|
+
* @returns {"string"|"null"|"array"|"element"|"fragment"|"object"|
|
|
246
|
+
* "symbol"|"bigint"|"function"|"number"|"boolean"|"undefined"|
|
|
247
|
+
* "document"|"processing-instruction"|"non-container node"}
|
|
248
|
+
*/
|
|
221
249
|
function _getType(item) {
|
|
222
|
-
const type = typeof item;
|
|
223
|
-
|
|
224
250
|
// Appease TS
|
|
225
251
|
if (typeof item === 'string' || typeof item === 'undefined') {
|
|
226
252
|
return 'string';
|
|
227
253
|
}
|
|
254
|
+
const type = typeof item;
|
|
228
255
|
switch (type) {
|
|
229
256
|
case 'object':
|
|
230
257
|
if (item === null) {
|
|
@@ -254,23 +281,31 @@ function _getType(item) {
|
|
|
254
281
|
}
|
|
255
282
|
|
|
256
283
|
/**
|
|
257
|
-
* @private
|
|
258
|
-
* @static
|
|
259
|
-
* @param {DocumentFragment} frag
|
|
260
|
-
* @param {Node} node
|
|
261
|
-
* @returns {DocumentFragment}
|
|
262
|
-
*/
|
|
284
|
+
* @private
|
|
285
|
+
* @static
|
|
286
|
+
* @param {DocumentFragment} frag
|
|
287
|
+
* @param {Node} node
|
|
288
|
+
* @returns {DocumentFragment}
|
|
289
|
+
*/
|
|
263
290
|
function _fragReducer(frag, node) {
|
|
264
291
|
frag.append(node);
|
|
265
292
|
return frag;
|
|
266
293
|
}
|
|
267
294
|
|
|
268
295
|
/**
|
|
269
|
-
* @
|
|
270
|
-
* @
|
|
271
|
-
|
|
272
|
-
|
|
273
|
-
|
|
296
|
+
* @param {string} str
|
|
297
|
+
* @returns {string}
|
|
298
|
+
*/
|
|
299
|
+
function escapeReplacer(str) {
|
|
300
|
+
return str.replaceAll('$', '$$$$');
|
|
301
|
+
}
|
|
302
|
+
|
|
303
|
+
/**
|
|
304
|
+
* @private
|
|
305
|
+
* @static
|
|
306
|
+
* @param {Object<string, string>} xmlnsObj
|
|
307
|
+
* @returns {(...n: string[]) => string}
|
|
308
|
+
*/
|
|
274
309
|
function _replaceDefiner(xmlnsObj) {
|
|
275
310
|
/**
|
|
276
311
|
* @param {string[]} n
|
|
@@ -278,10 +313,10 @@ function _replaceDefiner(xmlnsObj) {
|
|
|
278
313
|
*/
|
|
279
314
|
return function (...n) {
|
|
280
315
|
const n0 = n[0];
|
|
281
|
-
let retStr = xmlnsObj[''] ? ' xmlns="' + xmlnsObj[''] + '"' : n0; // Preserve XHTML
|
|
316
|
+
let retStr = xmlnsObj[''] ? ' xmlns="' + escapeReplacer(xmlnsObj['']) + '"' : n0; // Preserve XHTML
|
|
282
317
|
for (const [ns, xmlnsVal] of Object.entries(xmlnsObj)) {
|
|
283
318
|
if (ns !== '') {
|
|
284
|
-
retStr += ' xmlns:' + ns + '="' + xmlnsVal + '"';
|
|
319
|
+
retStr += ' xmlns:' + ns + '="' + escapeReplacer(xmlnsVal) + '"';
|
|
285
320
|
}
|
|
286
321
|
}
|
|
287
322
|
return retStr;
|
|
@@ -312,30 +347,30 @@ function _childrenToJML(node) {
|
|
|
312
347
|
/**
|
|
313
348
|
* Keep this in sync with `JamilihArray`'s first argument (minus `Document`).
|
|
314
349
|
* @typedef {JamilihDoc|JamilihDoctype|JamilihTextNode|
|
|
315
|
-
* JamilihAttributeNode|JamilihOptions|ElementName|HTMLElement|
|
|
316
|
-
* JamilihDocumentFragment
|
|
317
|
-
* } JamilihFirstArg
|
|
318
|
-
*/
|
|
350
|
+
* JamilihAttributeNode|JamilihOptions|ElementName|HTMLElement|
|
|
351
|
+
* JamilihDocumentFragment
|
|
352
|
+
* } JamilihFirstArg
|
|
353
|
+
*/
|
|
319
354
|
|
|
320
355
|
/**
|
|
321
|
-
* @callback JamilihAppender
|
|
322
|
-
* @param {JamilihArray|JamilihFirstArg|Node|TextNodeString} childJML
|
|
323
|
-
* @returns {void}
|
|
324
|
-
*/
|
|
356
|
+
* @callback JamilihAppender
|
|
357
|
+
* @param {JamilihArray|JamilihArrayLike|JamilihFirstArg|Node|TextNodeString} childJML
|
|
358
|
+
* @returns {void}
|
|
359
|
+
*/
|
|
325
360
|
|
|
326
361
|
/**
|
|
327
|
-
* @private
|
|
328
|
-
* @static
|
|
329
|
-
* @param {ParentNode} node
|
|
330
|
-
* @returns {JamilihAppender}
|
|
331
|
-
*/
|
|
362
|
+
* @private
|
|
363
|
+
* @static
|
|
364
|
+
* @param {ParentNode} node
|
|
365
|
+
* @returns {JamilihAppender}
|
|
366
|
+
*/
|
|
332
367
|
function _appendJML(node) {
|
|
333
368
|
return function (childJML) {
|
|
334
369
|
if (typeof childJML === 'string' || typeof childJML === 'number') {
|
|
335
370
|
throw new TypeError('Unexpected text string/number in the head');
|
|
336
371
|
}
|
|
337
372
|
if (Array.isArray(childJML)) {
|
|
338
|
-
node.append(jml(...childJML));
|
|
373
|
+
node.append(jml(...(/** @type {JamilihArray} */childJML)));
|
|
339
374
|
} else if (typeof childJML === 'object' && 'nodeType' in childJML) {
|
|
340
375
|
node.append(childJML);
|
|
341
376
|
} else {
|
|
@@ -345,23 +380,23 @@ function _appendJML(node) {
|
|
|
345
380
|
}
|
|
346
381
|
|
|
347
382
|
/**
|
|
348
|
-
* @callback appender
|
|
349
|
-
* @param {JamilihArray|JamilihFirstArg|Node|TextNodeString} childJML
|
|
350
|
-
* @returns {void}
|
|
351
|
-
*/
|
|
383
|
+
* @callback appender
|
|
384
|
+
* @param {JamilihArray|JamilihArrayLike|JamilihFirstArg|Node|TextNodeString} childJML
|
|
385
|
+
* @returns {void}
|
|
386
|
+
*/
|
|
352
387
|
|
|
353
388
|
/**
|
|
354
|
-
* @private
|
|
355
|
-
* @static
|
|
356
|
-
* @param {ParentNode} node
|
|
357
|
-
* @returns {appender}
|
|
358
|
-
*/
|
|
389
|
+
* @private
|
|
390
|
+
* @static
|
|
391
|
+
* @param {ParentNode} node
|
|
392
|
+
* @returns {appender}
|
|
393
|
+
*/
|
|
359
394
|
function _appendJMLOrText(node) {
|
|
360
395
|
return function (childJML) {
|
|
361
396
|
if (typeof childJML === 'string' || typeof childJML === 'number') {
|
|
362
397
|
node.append(String(childJML));
|
|
363
398
|
} else if (Array.isArray(childJML)) {
|
|
364
|
-
node.append(jml(...childJML));
|
|
399
|
+
node.append(jml(...(/** @type {JamilihArray} */childJML)));
|
|
365
400
|
} else if (typeof childJML === 'object' && 'nodeType' in childJML) {
|
|
366
401
|
node.append(childJML);
|
|
367
402
|
} else {
|
|
@@ -371,9 +406,9 @@ function _appendJMLOrText(node) {
|
|
|
371
406
|
}
|
|
372
407
|
|
|
373
408
|
/**
|
|
374
|
-
* @private
|
|
375
|
-
* @static
|
|
376
|
-
*/
|
|
409
|
+
* @private
|
|
410
|
+
* @static
|
|
411
|
+
*/
|
|
377
412
|
/*
|
|
378
413
|
function _DOMfromJMLOrString (childNodeJML) {
|
|
379
414
|
if (typeof childNodeJML === 'string') {
|
|
@@ -384,9 +419,9 @@ function _DOMfromJMLOrString (childNodeJML) {
|
|
|
384
419
|
*/
|
|
385
420
|
|
|
386
421
|
/**
|
|
387
|
-
* @typedef {HTMLElement|DocumentFragment|Comment|Attr|
|
|
388
|
-
* Text|Document|DocumentType|ProcessingInstruction|CDATASection} JamilihReturn
|
|
389
|
-
*/
|
|
422
|
+
* @typedef {HTMLElement|DocumentFragment|Comment|Attr|
|
|
423
|
+
* Text|Document|DocumentType|ProcessingInstruction|CDATASection} JamilihReturn
|
|
424
|
+
*/
|
|
390
425
|
// 'string|JamilihOptions|JamilihDocumentFragment|JamilihAttributes|(string|JamilihArray)[]
|
|
391
426
|
|
|
392
427
|
/**
|
|
@@ -403,11 +438,11 @@ function _DOMfromJMLOrString (childNodeJML) {
|
|
|
403
438
|
|
|
404
439
|
/**
|
|
405
440
|
* @typedef {{
|
|
406
|
-
* open?: boolean|ShadowRootJamilihArrayContainer,
|
|
407
|
-
* closed?: boolean|ShadowRootJamilihArrayContainer,
|
|
408
|
-
* template?: string|HTMLTemplateElement|TemplateJamilihArray,
|
|
409
|
-
* content?: ShadowRootJamilihArrayContainer|DocumentFragment
|
|
410
|
-
* }} JamilihShadowRootObject
|
|
441
|
+
* open?: boolean|ShadowRootJamilihArrayContainer,
|
|
442
|
+
* closed?: boolean|ShadowRootJamilihArrayContainer,
|
|
443
|
+
* template?: string|HTMLTemplateElement|TemplateJamilihArray,
|
|
444
|
+
* content?: ShadowRootJamilihArrayContainer|DocumentFragment
|
|
445
|
+
* }} JamilihShadowRootObject
|
|
411
446
|
*/
|
|
412
447
|
|
|
413
448
|
/**
|
|
@@ -429,18 +464,21 @@ function _DOMfromJMLOrString (childNodeJML) {
|
|
|
429
464
|
*/
|
|
430
465
|
|
|
431
466
|
/**
|
|
432
|
-
* @
|
|
467
|
+
* @template {HTMLElement} [T=HTMLElement]
|
|
468
|
+
* @typedef {(this: T, event: Event & {target: T}) => void} EventHandler
|
|
433
469
|
*/
|
|
434
470
|
|
|
435
471
|
/**
|
|
472
|
+
* @template {HTMLElement} [T=HTMLElement]
|
|
436
473
|
* @typedef {{
|
|
437
|
-
* [key: string]: EventHandler
|
|
474
|
+
* [key: string]: EventHandler<T>|[EventHandler<T>, boolean]
|
|
438
475
|
* }} OnAttributeObject
|
|
439
476
|
*/
|
|
440
477
|
|
|
441
478
|
/**
|
|
479
|
+
* @template {HTMLElement} [T=HTMLElement]
|
|
442
480
|
* @typedef {{
|
|
443
|
-
* $on?: OnAttributeObject
|
|
481
|
+
* $on?: OnAttributeObject<T>|null
|
|
444
482
|
* }} OnAttribute
|
|
445
483
|
*/
|
|
446
484
|
|
|
@@ -452,7 +490,6 @@ function _DOMfromJMLOrString (childNodeJML) {
|
|
|
452
490
|
* @typedef {((this: HTMLElement, event?: Event) => void)} HandlerAttributeValue
|
|
453
491
|
*/
|
|
454
492
|
|
|
455
|
-
/* eslint-disable jsdoc/valid-types -- jsdoc-type-pratt-parser Bug */
|
|
456
493
|
/**
|
|
457
494
|
* @typedef {{
|
|
458
495
|
* [key: string]: HandlerAttributeValue
|
|
@@ -476,23 +513,22 @@ function _DOMfromJMLOrString (childNodeJML) {
|
|
|
476
513
|
*/
|
|
477
514
|
|
|
478
515
|
/**
|
|
479
|
-
* @typedef {{[key: string]:
|
|
516
|
+
* @typedef {{[key: string]: unknown}} DefineMixin
|
|
480
517
|
*/
|
|
481
518
|
|
|
482
519
|
/**
|
|
483
520
|
* @typedef {{
|
|
484
521
|
* new (): HTMLElement;
|
|
485
|
-
* prototype: HTMLElement
|
|
522
|
+
* prototype: HTMLElement
|
|
486
523
|
* }} DefineConstructor
|
|
487
524
|
*/
|
|
488
|
-
/* eslint-enable jsdoc/valid-types -- https://github.com/jsdoc-type-pratt-parser/jsdoc-type-pratt-parser/issues/131 */
|
|
489
525
|
|
|
490
526
|
/**
|
|
491
527
|
* @typedef {(this: HTMLElement) => void} DefineUserConstructor
|
|
492
528
|
*/
|
|
493
529
|
|
|
494
530
|
/**
|
|
495
|
-
* @typedef {[DefineConstructor|DefineUserConstructor|DefineMixin, DefineOptions?]|[DefineConstructor|DefineUserConstructor, DefineMixin?, DefineOptions?]} DefineObjectArray
|
|
531
|
+
* @typedef {[DefineConstructor|DefineUserConstructor|DefineMixin, DefineOptions?]|[DefineMixin, DefineConstructor]|[DefineConstructor|DefineUserConstructor, DefineMixin?, DefineOptions?]} DefineObjectArray
|
|
496
532
|
*/
|
|
497
533
|
|
|
498
534
|
/**
|
|
@@ -500,11 +536,27 @@ function _DOMfromJMLOrString (childNodeJML) {
|
|
|
500
536
|
*/
|
|
501
537
|
|
|
502
538
|
/**
|
|
503
|
-
* @
|
|
539
|
+
* @template [T=ArbitraryValue]
|
|
540
|
+
* @template {HTMLElement} [U=HTMLElement]
|
|
541
|
+
* @typedef {T & {elem?: U}} SymbolObject
|
|
542
|
+
*/
|
|
543
|
+
|
|
544
|
+
/**
|
|
545
|
+
* @template {HTMLElement} [T=HTMLElement]
|
|
546
|
+
* @typedef {(this: T, ...args: UserArg[]) => UserArg} SymbolMethod
|
|
547
|
+
*/
|
|
548
|
+
|
|
549
|
+
/**
|
|
550
|
+
* @typedef {(...args: UserArg[]) => UserArg} BoundSymbolMethod
|
|
504
551
|
*/
|
|
505
552
|
|
|
506
553
|
/**
|
|
507
|
-
* @
|
|
554
|
+
* @template {HTMLElement} [T=HTMLElement]
|
|
555
|
+
* @typedef {[symbol|string, SymbolMethod<T>|SymbolObject<ArbitraryValue, T>]} SymbolArray
|
|
556
|
+
*/
|
|
557
|
+
|
|
558
|
+
/**
|
|
559
|
+
* @typedef {BoundSymbolMethod|SymbolObject|ArbitraryValue} SymbolResult
|
|
508
560
|
*/
|
|
509
561
|
|
|
510
562
|
/**
|
|
@@ -512,7 +564,7 @@ function _DOMfromJMLOrString (childNodeJML) {
|
|
|
512
564
|
*/
|
|
513
565
|
|
|
514
566
|
/**
|
|
515
|
-
* @typedef {[string, object]|string|
|
|
567
|
+
* @typedef {[string, object]|string|object} PluginValue
|
|
516
568
|
*/
|
|
517
569
|
|
|
518
570
|
/**
|
|
@@ -527,15 +579,15 @@ function _DOMfromJMLOrString (childNodeJML) {
|
|
|
527
579
|
|
|
528
580
|
/**
|
|
529
581
|
* @typedef {{
|
|
530
|
-
* [key: string]: string|number|((this: HTMLElement, ...args:
|
|
531
|
-
* }} DataAttributeObject
|
|
532
|
-
*/
|
|
582
|
+
* [key: string]: string|number|((this: HTMLElement, ...args: UserArg[]) => UserArg)
|
|
583
|
+
* }} DataAttributeObject
|
|
584
|
+
*/
|
|
533
585
|
|
|
534
586
|
/**
|
|
535
587
|
* @typedef {{
|
|
536
|
-
* $data?: true|string[]|Map<
|
|
588
|
+
* $data?: true|string[]|Map<HTMLElement, UserArg>|WeakMap<HTMLElement, UserArg>|DataAttributeObject|
|
|
537
589
|
* [undefined, DataAttributeObject]|
|
|
538
|
-
* [Map<
|
|
590
|
+
* [Map<HTMLElement, UserArg>|WeakMap<HTMLElement, UserArg>|undefined, DataAttributeObject]
|
|
539
591
|
* }} DataAttribute
|
|
540
592
|
*/
|
|
541
593
|
|
|
@@ -557,18 +609,16 @@ function _DOMfromJMLOrString (childNodeJML) {
|
|
|
557
609
|
* }} JamilihShadowRootAttribute
|
|
558
610
|
*/
|
|
559
611
|
|
|
560
|
-
/* eslint-disable jsdoc/valid-types -- jsdoc-type-pratt-parser Bug */
|
|
561
612
|
/**
|
|
562
613
|
* @typedef {{
|
|
563
614
|
* is?: string|null,
|
|
564
615
|
* $define?: DefineObject
|
|
565
616
|
* }} DefineAttribute
|
|
566
617
|
*/
|
|
567
|
-
/* eslint-enable jsdoc/valid-types -- jsdoc-type-pratt-parser Bug */
|
|
568
618
|
|
|
569
619
|
/**
|
|
570
620
|
* @typedef {{
|
|
571
|
-
* $custom?: {[key: string]:
|
|
621
|
+
* $custom?: {[key: string]: unknown}
|
|
572
622
|
* }} CustomAttribute
|
|
573
623
|
*/
|
|
574
624
|
|
|
@@ -641,21 +691,30 @@ function _DOMfromJMLOrString (childNodeJML) {
|
|
|
641
691
|
*/
|
|
642
692
|
|
|
643
693
|
/**
|
|
694
|
+
* @typedef {Document|ElementName|HTMLElement|DocumentFragment|
|
|
695
|
+
* JamilihDocumentFragment|JamilihDoc|JamilihDoctype|JamilihTextNode|
|
|
696
|
+
* JamilihAttributeNode} JamilihFirstArgument
|
|
697
|
+
*/
|
|
698
|
+
|
|
699
|
+
/**
|
|
700
|
+
* Array-form Jamilih input whose tuple positions were widened by operations
|
|
701
|
+
* such as `Array#map`.
|
|
644
702
|
* @typedef {(
|
|
645
|
-
*
|
|
646
|
-
*
|
|
647
|
-
*
|
|
648
|
-
* )[]} JamilihChildren
|
|
703
|
+
* JamilihFirstArg|JamilihAttributes|JamilihArrayLike|TextNodeString|
|
|
704
|
+
* ShadowRoot|null
|
|
705
|
+
* )[]} JamilihArrayLike
|
|
649
706
|
*/
|
|
650
707
|
|
|
651
|
-
// Todo: DocumentType, Comment, ProcessingInstruction, Text
|
|
652
|
-
// Todo: JamilihCDATANode, JamilihComment, JamilihProcessingInstruction
|
|
653
708
|
/**
|
|
654
|
-
* @typedef {
|
|
655
|
-
*
|
|
656
|
-
*
|
|
709
|
+
* @typedef {(
|
|
710
|
+
* JamilihArray|JamilihArrayLike|TextNodeString|HTMLElement|Comment|
|
|
711
|
+
* ProcessingInstruction|Text|DocumentFragment|JamilihProcessingInstruction|
|
|
712
|
+
* JamilihDocumentFragment|PluginReference
|
|
713
|
+
* )[]} JamilihChildren
|
|
657
714
|
*/
|
|
658
715
|
|
|
716
|
+
// Todo: DocumentType, Comment, ProcessingInstruction, Text
|
|
717
|
+
// Todo: JamilihCDATANode, JamilihComment, JamilihProcessingInstruction
|
|
659
718
|
/**
|
|
660
719
|
* This would be clearer with overrides, but using as typedef.
|
|
661
720
|
*
|
|
@@ -701,8 +760,8 @@ function _DOMfromJMLOrString (childNodeJML) {
|
|
|
701
760
|
|
|
702
761
|
/**
|
|
703
762
|
* @typedef {{
|
|
704
|
-
* root: [Map<HTMLElement,
|
|
705
|
-
* [key: string]: [Map<HTMLElement,
|
|
763
|
+
* root: [Map<HTMLElement,UserArg>|WeakMap<HTMLElement,UserArg>, UserArg],
|
|
764
|
+
* [key: string]: [Map<HTMLElement,UserArg>|WeakMap<HTMLElement,UserArg>, UserArg]
|
|
706
765
|
* }} MapWithRoot
|
|
707
766
|
*/
|
|
708
767
|
|
|
@@ -714,7 +773,7 @@ function _DOMfromJMLOrString (childNodeJML) {
|
|
|
714
773
|
* @typedef {object} JamilihOptions
|
|
715
774
|
* @property {TraversalState} [$state]
|
|
716
775
|
* @property {JamilihPlugin[]} [$plugins]
|
|
717
|
-
* @property {MapWithRoot|[Map<HTMLElement,
|
|
776
|
+
* @property {MapWithRoot|[Map<HTMLElement,UserArg>|WeakMap<HTMLElement,UserArg>, UserArg]} [$map]
|
|
718
777
|
*/
|
|
719
778
|
|
|
720
779
|
/**
|
|
@@ -754,27 +813,213 @@ function getMatchingPlugin(opts, pluginName) {
|
|
|
754
813
|
});
|
|
755
814
|
}
|
|
756
815
|
|
|
757
|
-
/* eslint-disable jsdoc/valid-types -- pratt parser bug */
|
|
758
816
|
/**
|
|
759
817
|
* @template T
|
|
760
818
|
* @typedef {T[keyof T]} ValueOf
|
|
761
819
|
*/
|
|
762
|
-
/* eslint-enable jsdoc/valid-types -- pratt parser bug */
|
|
763
820
|
|
|
764
|
-
|
|
821
|
+
/**
|
|
822
|
+
* @template {JamilihArray} T
|
|
823
|
+
* @typedef {Extract<Extract<T[number], {$custom?: {[key: string]: unknown}}>['$custom'], object>} RawCustomFromJamilihArray
|
|
824
|
+
*/
|
|
825
|
+
|
|
826
|
+
/**
|
|
827
|
+
* @template M
|
|
828
|
+
* @typedef {M extends object
|
|
829
|
+
* ? string extends keyof M
|
|
830
|
+
* ? object
|
|
831
|
+
* : M
|
|
832
|
+
* : object} SpecificDefineMixin
|
|
833
|
+
*/
|
|
834
|
+
|
|
835
|
+
/**
|
|
836
|
+
* @template D
|
|
837
|
+
* @typedef {D extends [infer First, infer Second, ...ArbitraryValue[]]
|
|
838
|
+
* ? (First extends DefineMixin
|
|
839
|
+
* ? SpecificDefineMixin<First>
|
|
840
|
+
* : Second extends DefineMixin
|
|
841
|
+
* ? SpecificDefineMixin<Second>
|
|
842
|
+
* : object)
|
|
843
|
+
* : D extends [infer First]
|
|
844
|
+
* ? First extends DefineMixin
|
|
845
|
+
* ? SpecificDefineMixin<First>
|
|
846
|
+
* : object
|
|
847
|
+
* : D extends DefineMixin
|
|
848
|
+
* ? SpecificDefineMixin<D>
|
|
849
|
+
* : object} DefineMixinFromValue
|
|
850
|
+
*/
|
|
851
|
+
|
|
852
|
+
/**
|
|
853
|
+
* @template {JamilihArray} T
|
|
854
|
+
* @typedef {T[number] extends infer Item
|
|
855
|
+
* ? Item extends {$define: infer D}
|
|
856
|
+
* ? DefineMixinFromValue<D>
|
|
857
|
+
* : never
|
|
858
|
+
* : never} RawDefineMixinFromJamilihArray
|
|
859
|
+
*/
|
|
860
|
+
|
|
861
|
+
/**
|
|
862
|
+
* @template D
|
|
863
|
+
* @typedef {D extends [infer First, infer Second, ...ArbitraryValue[]]
|
|
864
|
+
* ? First extends DefineConstructor
|
|
865
|
+
* ? First['prototype']
|
|
866
|
+
* : Second extends DefineConstructor
|
|
867
|
+
* ? Second['prototype']
|
|
868
|
+
* : never
|
|
869
|
+
* : D extends DefineConstructor
|
|
870
|
+
* ? D['prototype']
|
|
871
|
+
* : never} ElementFromDefineValue
|
|
872
|
+
*/
|
|
873
|
+
|
|
874
|
+
/**
|
|
875
|
+
* @template {JamilihArray} T
|
|
876
|
+
* @typedef {T[number] extends infer Item
|
|
877
|
+
* ? Item extends {$define: infer D}
|
|
878
|
+
* ? ElementFromDefineValue<D>
|
|
879
|
+
* : never
|
|
880
|
+
* : never} ElementFromJamilihDefine
|
|
881
|
+
*/
|
|
882
|
+
|
|
883
|
+
/**
|
|
884
|
+
* @template {JamilihArray} T
|
|
885
|
+
* @typedef {Extract<T[number], {xmlns: unknown}> extends never ? false : true} HasXmlnsFromJamilihArray
|
|
886
|
+
*/
|
|
887
|
+
|
|
888
|
+
/**
|
|
889
|
+
* @template {JamilihArray} T
|
|
890
|
+
* @typedef {T extends [infer K, ...ArbitraryValue[]]
|
|
891
|
+
* ? (HasXmlnsFromJamilihArray<T> extends true
|
|
892
|
+
* ? Element
|
|
893
|
+
* : ElementFromJamilihDefine<T> extends never
|
|
894
|
+
* ? K extends keyof HTMLElementTagNameMap
|
|
895
|
+
* ? HTMLElementTagNameMap[K]
|
|
896
|
+
* : HTMLElement
|
|
897
|
+
* : ElementFromJamilihDefine<T>)
|
|
898
|
+
* : Element} ElementFromJamilihArray
|
|
899
|
+
*/
|
|
900
|
+
|
|
901
|
+
/**
|
|
902
|
+
* @template A
|
|
903
|
+
* @template {Element} E
|
|
904
|
+
* @template X
|
|
905
|
+
* @typedef {A extends {$custom: infer C}
|
|
906
|
+
* ? (C extends object
|
|
907
|
+
* ? Omit<A, '$custom'> & {$custom?: C & ThisType<E & C & X>}
|
|
908
|
+
* : A)
|
|
909
|
+
* : A} WithCustomThis
|
|
910
|
+
*/
|
|
911
|
+
|
|
912
|
+
/**
|
|
913
|
+
* @template D
|
|
914
|
+
* @template {Element} E
|
|
915
|
+
* @template X
|
|
916
|
+
* @typedef {D extends [infer First, infer Second, ...infer Rest]
|
|
917
|
+
* ? (First extends DefineMixin
|
|
918
|
+
* ? [First & ThisType<E & First & X>, Second, ...Rest]
|
|
919
|
+
* : Second extends DefineMixin
|
|
920
|
+
* ? [First, Second & ThisType<E & Second & X>, ...Rest]
|
|
921
|
+
* : D)
|
|
922
|
+
* : D extends [infer First]
|
|
923
|
+
* ? First extends DefineMixin
|
|
924
|
+
* ? [First & ThisType<E & First & X>]
|
|
925
|
+
* : D
|
|
926
|
+
* : D extends DefineMixin
|
|
927
|
+
* ? D & ThisType<E & D & X>
|
|
928
|
+
* : D} WithDefineThisValue
|
|
929
|
+
*/
|
|
930
|
+
|
|
931
|
+
/**
|
|
932
|
+
* @template A
|
|
933
|
+
* @template {Element} E
|
|
934
|
+
* @template X
|
|
935
|
+
* @typedef {A extends {$define: infer D}
|
|
936
|
+
* ? Omit<A, '$define'> & {$define?: WithDefineThisValue<D, E, X>}
|
|
937
|
+
* : A} WithDefineThis
|
|
938
|
+
*/
|
|
939
|
+
|
|
940
|
+
/**
|
|
941
|
+
* @template A
|
|
942
|
+
* @typedef {A extends {$custom: infer C}
|
|
943
|
+
* ? C extends object ? C : object
|
|
944
|
+
* : object} CustomFromJamilihItem
|
|
945
|
+
*/
|
|
946
|
+
|
|
947
|
+
/**
|
|
948
|
+
* @template A
|
|
949
|
+
* @typedef {A extends {$define: infer D}
|
|
950
|
+
* ? DefineMixinFromValue<D>
|
|
951
|
+
* : object} DefineMixinFromJamilihItem
|
|
952
|
+
*/
|
|
953
|
+
|
|
954
|
+
/**
|
|
955
|
+
* @template {JamilihArray} T
|
|
956
|
+
* @template {Element} E
|
|
957
|
+
* @typedef {{[K in keyof T]: WithCustomThis<
|
|
958
|
+
* WithDefineThis<T[K], E, CustomFromJamilihItem<T[K]>>,
|
|
959
|
+
* E,
|
|
960
|
+
* DefineMixinFromJamilihItem<T[K]>
|
|
961
|
+
* >}} JamilihArrayWithCustomThis
|
|
962
|
+
*/
|
|
963
|
+
|
|
964
|
+
/**
|
|
965
|
+
* @template A
|
|
966
|
+
* @typedef {A extends (infer Item)[]
|
|
967
|
+
* ? (Extract<Item, JamilihFirstArg> extends never ? never : A)
|
|
968
|
+
* : A} ValidateJamilihArrayLike
|
|
969
|
+
*/
|
|
970
|
+
|
|
971
|
+
/**
|
|
972
|
+
* @template A
|
|
973
|
+
* @typedef {A extends (infer Child)[]
|
|
974
|
+
* ? A & (Child extends unknown[] ? ValidateJamilihArrayLike<Child> : Child)[]
|
|
975
|
+
* : A} ValidateJamilihChildContainer
|
|
976
|
+
*/
|
|
977
|
+
|
|
978
|
+
/**
|
|
979
|
+
* @template {JamilihArray} T
|
|
980
|
+
* @typedef {{[K in keyof T]: ValidateJamilihChildContainer<T[K]>}} ValidateJamilihArrayLikes
|
|
981
|
+
*/
|
|
982
|
+
|
|
983
|
+
/**
|
|
984
|
+
* @template {JamilihArray} T
|
|
985
|
+
* @typedef {(
|
|
986
|
+
* RawCustomFromJamilihArray<T> extends never
|
|
987
|
+
* ? object
|
|
988
|
+
* : RawCustomFromJamilihArray<T>
|
|
989
|
+
* )} CustomFromJamilihArray
|
|
990
|
+
*/
|
|
991
|
+
|
|
992
|
+
/**
|
|
993
|
+
* @template {JamilihArray} T
|
|
994
|
+
* @typedef {(
|
|
995
|
+
* RawDefineMixinFromJamilihArray<T> extends never
|
|
996
|
+
* ? object
|
|
997
|
+
* : RawDefineMixinFromJamilihArray<T>
|
|
998
|
+
* )} DefineMixinFromJamilihArray
|
|
999
|
+
*/
|
|
1000
|
+
|
|
1001
|
+
/**
|
|
1002
|
+
* @template U
|
|
1003
|
+
* @template W
|
|
1004
|
+
* @typedef {U extends void ? (ExpandoHTMLElement & W) : (U & W)} ResolvedElement
|
|
1005
|
+
*/
|
|
1006
|
+
|
|
765
1007
|
/**
|
|
766
1008
|
* Creates an XHTML or HTML element (XHTML is preferred, but only in browsers
|
|
767
1009
|
* that support); any element after element can be omitted, and any subsequent
|
|
768
1010
|
* type or types added afterwards.
|
|
769
1011
|
* @template {JamilihArray} T
|
|
770
|
-
* @
|
|
771
|
-
* @
|
|
772
|
-
*
|
|
1012
|
+
* @template {T extends [infer K, ...ArbitraryValue[]] ? (HasXmlnsFromJamilihArray<T> extends true ? Element : ElementFromJamilihDefine<T> extends never ? K extends keyof HTMLElementTagNameMap ? HTMLElementTagNameMap[K] : K extends string ? HTMLElement : void : ElementFromJamilihDefine<T>) : void} U
|
|
1013
|
+
* @template {ElementFromJamilihArray<T>} E
|
|
1014
|
+
* @template {CustomFromJamilihArray<T>} W
|
|
1015
|
+
* @template {DefineMixinFromJamilihArray<T>} D
|
|
1016
|
+
* @param {JamilihArrayWithCustomThis<T, E> & ValidateJamilihArrayLikes<T>} args
|
|
1017
|
+
* @returns {U extends void ? JamilihReturn : ResolvedElement<U, W & D>}
|
|
773
1018
|
* The newly created (and possibly already appended)
|
|
774
1019
|
* element or array of elements
|
|
775
1020
|
*/
|
|
1021
|
+
|
|
776
1022
|
const jml = function jml(...args) {
|
|
777
|
-
/* eslint-enable jsdoc/valid-types -- pratt parser bug */
|
|
778
1023
|
if (!win) {
|
|
779
1024
|
throw new Error('No window object');
|
|
780
1025
|
}
|
|
@@ -782,7 +1027,7 @@ const jml = function jml(...args) {
|
|
|
782
1027
|
throw new Error('No document object');
|
|
783
1028
|
}
|
|
784
1029
|
|
|
785
|
-
/** @type {(Document|DocumentFragment|HTMLElement) & {[key: string]:
|
|
1030
|
+
/** @type {(Document|DocumentFragment|HTMLElement) & {[key: string]: ElementExpando}} */
|
|
786
1031
|
let elem = doc.createDocumentFragment();
|
|
787
1032
|
/**
|
|
788
1033
|
*
|
|
@@ -797,20 +1042,15 @@ const jml = function jml(...args) {
|
|
|
797
1042
|
}
|
|
798
1043
|
for (let [att, attVal] of Object.entries(atts)) {
|
|
799
1044
|
att = ATTR_MAP.has(att) ? String(ATTR_MAP.get(att)) : att;
|
|
800
|
-
|
|
801
|
-
/**
|
|
802
|
-
* @typedef {any} ElementExpando
|
|
803
|
-
*/
|
|
804
|
-
|
|
805
1045
|
if (NULLABLES.has(att)) {
|
|
806
1046
|
attVal = checkPluginValue(elem, att, /** @type {string|JamilihArray} */attVal, opts);
|
|
807
1047
|
if (!_isNullish(attVal)) {
|
|
808
|
-
|
|
1048
|
+
elem[att] = attVal;
|
|
809
1049
|
}
|
|
810
1050
|
continue;
|
|
811
|
-
}
|
|
1051
|
+
}
|
|
1052
|
+
if (ATTR_DOM.has(att)) {
|
|
812
1053
|
attVal = checkPluginValue(elem, att, /** @type {string|JamilihArray} */attVal, opts);
|
|
813
|
-
/** @type {ElementExpando} */
|
|
814
1054
|
elem[att] = attVal;
|
|
815
1055
|
continue;
|
|
816
1056
|
}
|
|
@@ -895,6 +1135,9 @@ const jml = function jml(...args) {
|
|
|
895
1135
|
}
|
|
896
1136
|
case '$custom':
|
|
897
1137
|
{
|
|
1138
|
+
if (attVal !== null && (typeof attVal === 'object' || typeof attVal === 'function') && Object.prototype.propertyIsEnumerable.call(attVal, '__proto__')) {
|
|
1139
|
+
throw new TypeError('`$custom` may not define `__proto__`');
|
|
1140
|
+
}
|
|
898
1141
|
Object.assign(elem, attVal);
|
|
899
1142
|
break;
|
|
900
1143
|
}
|
|
@@ -965,7 +1208,8 @@ const jml = function jml(...args) {
|
|
|
965
1208
|
const defineObj = /** @type {DefineObject} */attVal;
|
|
966
1209
|
if (Array.isArray(defineObj)) {
|
|
967
1210
|
if (defineObj.length <= 2) {
|
|
968
|
-
[cnstrctr
|
|
1211
|
+
[cnstrctr] = defineObj;
|
|
1212
|
+
options = /** @type {DefineOptions|undefined} */defineObj[1];
|
|
969
1213
|
if (typeof options === 'string') {
|
|
970
1214
|
// Todo: Allow creating a definition without using it;
|
|
971
1215
|
// that may be the only reason to have a string here which
|
|
@@ -1004,7 +1248,7 @@ const jml = function jml(...args) {
|
|
|
1004
1248
|
}
|
|
1005
1249
|
if (mixin) {
|
|
1006
1250
|
Object.entries(mixin).forEach(([methodName, method]) => {
|
|
1007
|
-
/** @type {DefineConstructor} */cnstrctr.prototype
|
|
1251
|
+
Reflect.set(/** @type {DefineConstructor} */cnstrctr.prototype, methodName, method);
|
|
1008
1252
|
});
|
|
1009
1253
|
}
|
|
1010
1254
|
// console.log('def', def, '::', typeof options === 'object' ? options : undefined);
|
|
@@ -1013,9 +1257,13 @@ const jml = function jml(...args) {
|
|
|
1013
1257
|
}
|
|
1014
1258
|
case '$symbol':
|
|
1015
1259
|
{
|
|
1016
|
-
|
|
1260
|
+
if (!_isHTMLElement(elem)) {
|
|
1261
|
+
throw new TypeError('Element expected for `$symbol`');
|
|
1262
|
+
}
|
|
1263
|
+
const symbolElem = /** @type {ResolvedElement<U, W>} */elem;
|
|
1264
|
+
const [symbol, func] = /** @type {SymbolArray<ResolvedElement<U, W>>} */attVal;
|
|
1017
1265
|
if (typeof func === 'function') {
|
|
1018
|
-
const funcBound = func.bind(
|
|
1266
|
+
const funcBound = func.bind(symbolElem);
|
|
1019
1267
|
if (typeof symbol === 'string') {
|
|
1020
1268
|
// @ts-expect-error
|
|
1021
1269
|
elem[Symbol.for(symbol)] = funcBound;
|
|
@@ -1025,7 +1273,7 @@ const jml = function jml(...args) {
|
|
|
1025
1273
|
}
|
|
1026
1274
|
} else {
|
|
1027
1275
|
const obj = func;
|
|
1028
|
-
obj.elem =
|
|
1276
|
+
obj.elem = symbolElem;
|
|
1029
1277
|
if (typeof symbol === 'string') {
|
|
1030
1278
|
// @ts-expect-error
|
|
1031
1279
|
elem[Symbol.for(symbol)] = obj;
|
|
@@ -1038,7 +1286,7 @@ const jml = function jml(...args) {
|
|
|
1038
1286
|
}
|
|
1039
1287
|
case '$data':
|
|
1040
1288
|
{
|
|
1041
|
-
setMap(/** @type {true|string[]|Map<
|
|
1289
|
+
setMap(/** @type {true|string[]|Map<HTMLElement, unknown>|WeakMap<HTMLElement, unknown>|DataAttributeObject} */
|
|
1042
1290
|
attVal);
|
|
1043
1291
|
break;
|
|
1044
1292
|
}
|
|
@@ -1061,15 +1309,15 @@ const jml = function jml(...args) {
|
|
|
1061
1309
|
case '$document':
|
|
1062
1310
|
{
|
|
1063
1311
|
// Todo: Conditionally create XML document
|
|
1064
|
-
const docNode = doc.implementation.createHTMLDocument();
|
|
1065
1312
|
if (!attVal) {
|
|
1066
1313
|
throw new Error('Bad attribute value');
|
|
1067
1314
|
}
|
|
1315
|
+
const docNode = doc.implementation.createHTMLDocument();
|
|
1068
1316
|
const jamlihDoc = /** @type {JamilihDocument} */attVal;
|
|
1069
1317
|
if (jamlihDoc.childNodes) {
|
|
1070
1318
|
// Remove any extra nodes created by createHTMLDocument().
|
|
1071
1319
|
const j = jamlihDoc.childNodes.length;
|
|
1072
|
-
while (docNode.childNodes
|
|
1320
|
+
while (Object.hasOwn(docNode.childNodes, j)) {
|
|
1073
1321
|
const cn = docNode.childNodes[j];
|
|
1074
1322
|
cn.remove();
|
|
1075
1323
|
// `j` should stay the same as removing will cause node to be present
|
|
@@ -1094,7 +1342,7 @@ const jml = function jml(...args) {
|
|
|
1094
1342
|
if (jamlihDoc.title) {
|
|
1095
1343
|
docNode.title = jamlihDoc.title; // Appends after meta
|
|
1096
1344
|
}
|
|
1097
|
-
if (
|
|
1345
|
+
if (head && jamlihDoc.head) {
|
|
1098
1346
|
// each child of `head` is:
|
|
1099
1347
|
// (JamilihArray|TextNodeString|HTMLElement|Comment|ProcessingInstruction|
|
|
1100
1348
|
// Text|DocumentFragment|JamilihProcessingInstruction|JamilihDocumentFragment)
|
|
@@ -1108,7 +1356,7 @@ const jml = function jml(...args) {
|
|
|
1108
1356
|
jamlihDoc.head.forEach(_appendJML(head));
|
|
1109
1357
|
}
|
|
1110
1358
|
}
|
|
1111
|
-
if (
|
|
1359
|
+
if (body && jamlihDoc.body) {
|
|
1112
1360
|
jamlihDoc.body.forEach(_appendJMLOrText(body));
|
|
1113
1361
|
}
|
|
1114
1362
|
}
|
|
@@ -1135,16 +1383,17 @@ const jml = function jml(...args) {
|
|
|
1135
1383
|
case '$on':
|
|
1136
1384
|
{
|
|
1137
1385
|
// Events
|
|
1386
|
+
const onElem = /** @type {ResolvedElement<U, W>} */elem;
|
|
1138
1387
|
// Allow for no-op by defaulting to `{}`
|
|
1139
|
-
// eslint-disable-next-line prefer-const -- Ok as mixed
|
|
1140
|
-
for (let [p2, val] of Object.entries(/** @type {OnAttributeObject} */attVal || {})) {
|
|
1388
|
+
// eslint-disable-next-line prefer-const, unicorn/no-unreadable-for-of-expression -- Ok as mixed
|
|
1389
|
+
for (let [p2, val] of Object.entries(/** @type {OnAttributeObject<ResolvedElement<U, W>>} */attVal || {})) {
|
|
1141
1390
|
if (typeof val === 'function') {
|
|
1142
1391
|
val = [val, false];
|
|
1143
1392
|
}
|
|
1144
1393
|
if (typeof val[0] !== 'function') {
|
|
1145
1394
|
throw new TypeError(`Expect a function for \`$on\`; args: ${JSON.stringify(args)}`);
|
|
1146
1395
|
}
|
|
1147
|
-
_addEvent(
|
|
1396
|
+
_addEvent(onElem, p2, val[0], val[1]); // element, event name, handler, capturing
|
|
1148
1397
|
}
|
|
1149
1398
|
break;
|
|
1150
1399
|
}
|
|
@@ -1168,7 +1417,11 @@ const jml = function jml(...args) {
|
|
|
1168
1417
|
const pastInitialProp = startProp !== '';
|
|
1169
1418
|
Object.keys(atVal).forEach(key => {
|
|
1170
1419
|
const value = atVal[key];
|
|
1171
|
-
prop =
|
|
1420
|
+
prop = startProp + (pastInitialProp
|
|
1421
|
+
// eslint-disable-next-line unicorn/no-unsafe-string-replacement -- Function
|
|
1422
|
+
? key.replaceAll(hyphenForCamelCase, _upperCase).replace(/^([a-z])/u, _upperCase)
|
|
1423
|
+
// eslint-disable-next-line unicorn/no-unsafe-string-replacement -- Function
|
|
1424
|
+
: key.replaceAll(hyphenForCamelCase, _upperCase));
|
|
1172
1425
|
if (value === null || typeof value !== 'object') {
|
|
1173
1426
|
if (!_isNullish(value)) {
|
|
1174
1427
|
elem.dataset[prop] = value;
|
|
@@ -1187,7 +1440,7 @@ const jml = function jml(...args) {
|
|
|
1187
1440
|
// Don't remove this `if` block (for sake of no-innerHTML build)
|
|
1188
1441
|
case 'innerHTML':
|
|
1189
1442
|
if (!_isNullish(attVal)) {
|
|
1190
|
-
//
|
|
1443
|
+
// eslint-disable-next-line no-unsanitized/property
|
|
1191
1444
|
elem.innerHTML = attVal;
|
|
1192
1445
|
}
|
|
1193
1446
|
break;
|
|
@@ -1229,6 +1482,7 @@ const jml = function jml(...args) {
|
|
|
1229
1482
|
elem.style.cssFloat = styleVal;
|
|
1230
1483
|
elem.style.styleFloat = styleVal; // Harmless though we could make conditional on older IE instead
|
|
1231
1484
|
} else {
|
|
1485
|
+
// eslint-disable-next-line unicorn/no-unsafe-string-replacement -- Function
|
|
1232
1486
|
elem.style[p2.replaceAll(hyphenForCamelCase, _upperCase)] = styleVal;
|
|
1233
1487
|
}
|
|
1234
1488
|
}
|
|
@@ -1318,12 +1572,12 @@ const jml = function jml(...args) {
|
|
|
1318
1572
|
const defaultMap = opts.$map && /** @type {MapWithRoot} */opts.$map.root;
|
|
1319
1573
|
|
|
1320
1574
|
/**
|
|
1321
|
-
* @param {true|string[]|Map<
|
|
1575
|
+
* @param {true|string[]|Map<HTMLElement, UserArg>|WeakMap<HTMLElement, UserArg>|DataAttributeObject|[Map<HTMLElement, UserArg>|WeakMap<HTMLElement, UserArg>|undefined, DataAttributeObject|UserArg]} dataVal
|
|
1322
1576
|
* @returns {void}
|
|
1323
1577
|
*/
|
|
1324
1578
|
const setMap = dataVal => {
|
|
1325
1579
|
let map, obj;
|
|
1326
|
-
const defMap = /** @type {[Map<HTMLElement,
|
|
1580
|
+
const defMap = /** @type {[Map<HTMLElement, UserArg> | WeakMap<HTMLElement, UserArg>, UserArg]} */defaultMap;
|
|
1327
1581
|
// Boolean indicating use of default map and object
|
|
1328
1582
|
if (dataVal === true) {
|
|
1329
1583
|
[map, obj] = defMap;
|
|
@@ -1347,7 +1601,7 @@ const jml = function jml(...args) {
|
|
|
1347
1601
|
map = defMap[0];
|
|
1348
1602
|
obj = dataVal;
|
|
1349
1603
|
}
|
|
1350
|
-
/** @type {Map<HTMLElement,
|
|
1604
|
+
/** @type {Map<HTMLElement, UserArg> | WeakMap<HTMLElement, UserArg>} */
|
|
1351
1605
|
map.set(/** @type {HTMLElement} */
|
|
1352
1606
|
elem, obj);
|
|
1353
1607
|
};
|
|
@@ -1359,7 +1613,7 @@ const jml = function jml(...args) {
|
|
|
1359
1613
|
// null always indicates a place-holder (only needed for last argument if want array returned)
|
|
1360
1614
|
if (i === argc - 1) {
|
|
1361
1615
|
// Casting needing unless changing `jml()` signature with overloads
|
|
1362
|
-
return /** @type {
|
|
1616
|
+
return /** @type {U extends void ? JamilihReturn : ResolvedElement<U, W & D>} */nodes.length <= 1 ? nodes[0]
|
|
1363
1617
|
// eslint-disable-next-line unicorn/no-array-callback-reference
|
|
1364
1618
|
: nodes.reduce(_fragReducer, doc.createDocumentFragment()); // nodes;
|
|
1365
1619
|
}
|
|
@@ -1378,7 +1632,7 @@ const jml = function jml(...args) {
|
|
|
1378
1632
|
if (val && typeof val === 'object') {
|
|
1379
1633
|
const procValues = [];
|
|
1380
1634
|
for (const [p, procInstVal] of Object.entries(val)) {
|
|
1381
|
-
procValues.push(p + '=
|
|
1635
|
+
procValues.push(p + '="' +
|
|
1382
1636
|
// https://www.w3.org/TR/xml-stylesheet/#NT-PseudoAttValue
|
|
1383
1637
|
procInstVal.replaceAll('"', '"') + '"');
|
|
1384
1638
|
}
|
|
@@ -1440,13 +1694,12 @@ const jml = function jml(...args) {
|
|
|
1440
1694
|
/* c8 ignore next 4 */
|
|
1441
1695
|
elem = doc.createElementNS
|
|
1442
1696
|
// Should create separate file for this
|
|
1443
|
-
|
|
1697
|
+
? (/** @type {HTMLElement} */doc.createElementNS(NS_HTML, elStr, {
|
|
1444
1698
|
is: (/** @type {string} */is)
|
|
1445
1699
|
})
|
|
1446
1700
|
/* c8 ignore next 1 */) : doc.createElement(elStr, {
|
|
1447
1701
|
is: (/** @type {string} */is)
|
|
1448
1702
|
});
|
|
1449
|
-
/* eslint-enable object-shorthand -- Casting */
|
|
1450
1703
|
} else /* c8 ignore next */if (doc.createElementNS) {
|
|
1451
1704
|
elem = doc.createElementNS(NS_HTML, elStr);
|
|
1452
1705
|
/* c8 ignore next 3 */
|
|
@@ -1474,15 +1727,16 @@ const jml = function jml(...args) {
|
|
|
1474
1727
|
// elem.setAttribute('xmlns', atts.xmlns); // Doesn't work
|
|
1475
1728
|
// Can't set namespaceURI dynamically, renameNode() is not supported, and setAttribute() doesn't work to change the namespace, so we resort to this hack
|
|
1476
1729
|
const xmlnsObj = /** @type {XmlnsAttributeObject} */atts;
|
|
1477
|
-
const replacer = xmlnsObj.xmlns && typeof xmlnsObj.xmlns === 'object' ? _replaceDefiner(xmlnsObj.xmlns) : ' xmlns="' + xmlnsObj.xmlns + '"';
|
|
1730
|
+
const replacer = xmlnsObj.xmlns && typeof xmlnsObj.xmlns === 'object' ? _replaceDefiner(xmlnsObj.xmlns) : ' xmlns="' + escapeReplacer(xmlnsObj.xmlns) + '"';
|
|
1478
1731
|
// try {
|
|
1479
1732
|
// Also fix DOMParser to work with text/html
|
|
1480
1733
|
elem = nodes[nodes.length - 1] =
|
|
1481
1734
|
// Why doesn't `HTMLWindow` have `DOMParser`?
|
|
1482
1735
|
new /** @type {import('jsdom').DOMWindow} */win.DOMParser().parseFromString(new /** @type {import('jsdom').DOMWindow} */win.XMLSerializer().serializeToString(elem).
|
|
1483
1736
|
// Mozilla adds XHTML namespace
|
|
1484
|
-
replace(' xmlns="' + NS_HTML + '"',
|
|
1737
|
+
replace(' xmlns="' + escapeReplacer(NS_HTML) + '"',
|
|
1485
1738
|
// Needed to cast here, despite either overload working
|
|
1739
|
+
// eslint-disable-next-line unicorn/no-unsafe-string-replacement -- Escaped
|
|
1486
1740
|
/** @type {string} */
|
|
1487
1741
|
replacer), 'application/xml').documentElement;
|
|
1488
1742
|
// Todo: Report to plugins
|
|
@@ -1521,12 +1775,19 @@ const jml = function jml(...args) {
|
|
|
1521
1775
|
// Arrays or arrays of arrays indicate child nodes
|
|
1522
1776
|
const child = /** @type {JamilihChildren} */arg;
|
|
1523
1777
|
const cl = child.length;
|
|
1778
|
+
/**
|
|
1779
|
+
* @param {number} childIndex
|
|
1780
|
+
* @returns {TypeError}
|
|
1781
|
+
*/
|
|
1782
|
+
const getBadChildrenError = childIndex => {
|
|
1783
|
+
return new TypeError(`Bad children (parent array: ${JSON.stringify(args)}; index ${childIndex} of child: ${JSON.stringify(child)})`);
|
|
1784
|
+
};
|
|
1524
1785
|
for (let j = 0; j < cl; j++) {
|
|
1525
1786
|
// Go through children array container to handle elements
|
|
1526
1787
|
const childContent = child[j];
|
|
1527
1788
|
const childContentType = typeof childContent;
|
|
1528
1789
|
if (childContent === null || _isNullish(childContent)) {
|
|
1529
|
-
throw
|
|
1790
|
+
throw getBadChildrenError(j);
|
|
1530
1791
|
}
|
|
1531
1792
|
switch (childContentType) {
|
|
1532
1793
|
// Todo: determine whether null or function should have special handling or be converted to text
|
|
@@ -1538,12 +1799,17 @@ const jml = function jml(...args) {
|
|
|
1538
1799
|
default:
|
|
1539
1800
|
// bigint, symbol, function
|
|
1540
1801
|
if (typeof childContent !== 'object') {
|
|
1541
|
-
throw
|
|
1802
|
+
throw getBadChildrenError(j);
|
|
1542
1803
|
}
|
|
1543
1804
|
if (Array.isArray(childContent)) {
|
|
1544
1805
|
// Arrays representing child elements
|
|
1806
|
+
const childHeadType = typeof childContent[0];
|
|
1807
|
+
if (childContent.length === 0 || childHeadType !== 'string' && childHeadType !== 'object' || childContent[0] === null) {
|
|
1808
|
+
throw getBadChildrenError(j);
|
|
1809
|
+
}
|
|
1545
1810
|
opts.$state = 'children';
|
|
1546
|
-
|
|
1811
|
+
const childArgs = /** @type {JamilihArray} */[opts, ...childContent];
|
|
1812
|
+
_appendNode(elem, jml(...childArgs));
|
|
1547
1813
|
} else if ('#' in childContent) {
|
|
1548
1814
|
// Fragment
|
|
1549
1815
|
opts.$state = 'fragmentChildren';
|
|
@@ -1573,7 +1839,7 @@ const jml = function jml(...args) {
|
|
|
1573
1839
|
}
|
|
1574
1840
|
|
|
1575
1841
|
// Casting needing unless changing `jml()` signature with overloads
|
|
1576
|
-
return /** @type {
|
|
1842
|
+
return /** @type {U extends void ? JamilihReturn : ResolvedElement<U, W & D>} */ret;
|
|
1577
1843
|
};
|
|
1578
1844
|
|
|
1579
1845
|
/**
|
|
@@ -1643,8 +1909,8 @@ class DOMException extends Error {
|
|
|
1643
1909
|
|
|
1644
1910
|
/**
|
|
1645
1911
|
* @typedef {JamilihArray|JamilihDoctype|
|
|
1646
|
-
* JamilihCDATANode|JamilihEntityReference|JamilihProcessingInstruction|
|
|
1647
|
-
* JamilihComment|JamilihDocumentFragment} JamilihChildType
|
|
1912
|
+
* JamilihCDATANode|JamilihEntityReference|JamilihProcessingInstruction|
|
|
1913
|
+
* JamilihComment|JamilihDocumentFragment} JamilihChildType
|
|
1648
1914
|
*/
|
|
1649
1915
|
|
|
1650
1916
|
/**
|
|
@@ -1652,15 +1918,15 @@ class DOMException extends Error {
|
|
|
1652
1918
|
*/
|
|
1653
1919
|
|
|
1654
1920
|
/**
|
|
1655
|
-
* Converts a DOM object or a string of HTML into a Jamilih object (or string).
|
|
1656
|
-
* @param {string|HTMLElement|Node|Entity} nde If a string, will parse as document
|
|
1657
|
-
* @param {ToJmlConfig} [config] Configuration object
|
|
1658
|
-
* @throws {TypeError}
|
|
1659
|
-
* @returns {JamilihType|string} Array containing the elements which represent
|
|
1660
|
-
* a Jamilih object, or, if `stringOutput` is true, it will be the stringified
|
|
1661
|
-
* version of such an object
|
|
1662
|
-
*/
|
|
1663
|
-
|
|
1921
|
+
* Converts a DOM object or a string of HTML into a Jamilih object (or string).
|
|
1922
|
+
* @param {string|HTMLElement|Node|Entity} nde If a string, will parse as document
|
|
1923
|
+
* @param {ToJmlConfig} [config] Configuration object
|
|
1924
|
+
* @throws {TypeError}
|
|
1925
|
+
* @returns {JamilihType|string} Array containing the elements which represent
|
|
1926
|
+
* a Jamilih object, or, if `stringOutput` is true, it will be the stringified
|
|
1927
|
+
* version of such an object
|
|
1928
|
+
*/
|
|
1929
|
+
const toJML = function (nde, {
|
|
1664
1930
|
stringOutput = false,
|
|
1665
1931
|
reportInvalidState = true,
|
|
1666
1932
|
stripWhitespace = false
|
|
@@ -1675,7 +1941,7 @@ jml.toJML = function (nde, {
|
|
|
1675
1941
|
|
|
1676
1942
|
/**
|
|
1677
1943
|
* @todo Find more specific type than `any`
|
|
1678
|
-
* @typedef {{[key: (number|string)]:
|
|
1944
|
+
* @typedef {{[key: (number|string)]: UserArg}} IndexableObject
|
|
1679
1945
|
*/
|
|
1680
1946
|
|
|
1681
1947
|
const ret = /** @type {IndexableObject} */[];
|
|
@@ -1689,12 +1955,14 @@ jml.toJML = function (nde, {
|
|
|
1689
1955
|
*/
|
|
1690
1956
|
function invalidStateError(msg) {
|
|
1691
1957
|
// These are probably only necessary if working with text/html
|
|
1692
|
-
if (reportInvalidState) {
|
|
1693
|
-
|
|
1694
|
-
const e = new DOMException(msg, 'INVALID_STATE_ERR');
|
|
1695
|
-
e.code = 11;
|
|
1696
|
-
throw e;
|
|
1958
|
+
if (!reportInvalidState) {
|
|
1959
|
+
return;
|
|
1697
1960
|
}
|
|
1961
|
+
|
|
1962
|
+
// INVALID_STATE_ERR per section 9.3 XHTML 5: https://www.w3.org/TR/html5/the-xhtml-syntax.html
|
|
1963
|
+
const e = new DOMException(msg, 'INVALID_STATE_ERR');
|
|
1964
|
+
e.code = 11;
|
|
1965
|
+
throw e;
|
|
1698
1966
|
}
|
|
1699
1967
|
|
|
1700
1968
|
/**
|
|
@@ -1781,8 +2049,13 @@ jml.toJML = function (nde, {
|
|
|
1781
2049
|
namespaces = {
|
|
1782
2050
|
...namespaces
|
|
1783
2051
|
};
|
|
1784
|
-
const xmlChars = /^([\
|
|
1785
|
-
|
|
2052
|
+
const xmlChars = /^([\u{9}\u{A}\u{D}\u{20}-\u{D7FF}\u{E000}-\u{FFFD}]|[\uD800-\uDBFF][\uDC00-\uDFFF])*$/u; // eslint-disable-line no-control-regex
|
|
2053
|
+
|
|
2054
|
+
// eslint-disable-next-line prefer-destructuring -- TS
|
|
2055
|
+
const nodeValue = /** @type {Node} */nodeOrEntity.nodeValue;
|
|
2056
|
+
if ([2, 3, 4, 7, 8].includes(type) &&
|
|
2057
|
+
// eslint-disable-next-line unicorn/prefer-simple-condition-first -- Safer
|
|
2058
|
+
nodeValue && !xmlChars.test(nodeValue)) {
|
|
1786
2059
|
invalidStateError('Node has bad XML character value');
|
|
1787
2060
|
}
|
|
1788
2061
|
|
|
@@ -1886,6 +2159,7 @@ jml.toJML = function (nde, {
|
|
|
1886
2159
|
{
|
|
1887
2160
|
// CDATA
|
|
1888
2161
|
const node = /** @type {CDATASection} */nodeOrEntity;
|
|
2162
|
+
// eslint-disable-next-line unicorn/no-useless-concat -- Safer if pasting
|
|
1889
2163
|
if (node.nodeValue?.includes(']]' + '>')) {
|
|
1890
2164
|
invalidStateError('CDATA cannot end with closing ]]>');
|
|
1891
2165
|
}
|
|
@@ -1969,7 +2243,7 @@ jml.toJML = function (nde, {
|
|
|
1969
2243
|
name: /** @type {DocumentType} */node.name
|
|
1970
2244
|
}
|
|
1971
2245
|
};
|
|
1972
|
-
const pubIdChar = /^(\
|
|
2246
|
+
const pubIdChar = /^(\u{20}|\u{D}|\u{A}|[a-zA-Z0-9]|[-'()+,./:=?;!*#@$_%])*$/u; // eslint-disable-line no-control-regex
|
|
1973
2247
|
if (!pubIdChar.test(/** @type {DocumentType} */node.publicId)) {
|
|
1974
2248
|
invalidStateError('A publicId must have valid characters.');
|
|
1975
2249
|
}
|
|
@@ -2011,34 +2285,37 @@ jml.toJML = function (nde, {
|
|
|
2011
2285
|
}
|
|
2012
2286
|
return ret[0];
|
|
2013
2287
|
};
|
|
2288
|
+
jml.toJML = toJML;
|
|
2014
2289
|
|
|
2015
2290
|
/**
|
|
2016
2291
|
* @param {string|HTMLElement} dom
|
|
2017
2292
|
* @param {ToJmlConfig} [config]
|
|
2018
2293
|
* @returns {string}
|
|
2019
2294
|
*/
|
|
2020
|
-
|
|
2021
|
-
return /** @type {string} */
|
|
2295
|
+
const toJMLString = function (dom, config) {
|
|
2296
|
+
return /** @type {string} */toJML(dom, Object.assign(config || {}, {
|
|
2022
2297
|
stringOutput: true
|
|
2023
2298
|
}));
|
|
2024
2299
|
};
|
|
2300
|
+
jml.toJMLString = toJMLString;
|
|
2025
2301
|
|
|
2026
2302
|
/**
|
|
2027
2303
|
*
|
|
2028
2304
|
* @param {JamilihArray} args
|
|
2029
2305
|
* @returns {JamilihReturn}
|
|
2030
2306
|
*/
|
|
2031
|
-
|
|
2307
|
+
const toDOM = function (...args) {
|
|
2032
2308
|
// Alias for jml()
|
|
2033
2309
|
return jml(...args);
|
|
2034
2310
|
};
|
|
2311
|
+
jml.toDOM = toDOM;
|
|
2035
2312
|
|
|
2036
2313
|
/**
|
|
2037
2314
|
*
|
|
2038
2315
|
* @param {JamilihArray} args
|
|
2039
2316
|
* @returns {string}
|
|
2040
2317
|
*/
|
|
2041
|
-
|
|
2318
|
+
const toHTML = function (...args) {
|
|
2042
2319
|
// Todo: Replace this with version of jml() that directly builds a string
|
|
2043
2320
|
const ret = jml(...args);
|
|
2044
2321
|
switch (ret.nodeType) {
|
|
@@ -2053,18 +2330,20 @@ jml.toHTML = function (...args) {
|
|
|
2053
2330
|
case 2:
|
|
2054
2331
|
{
|
|
2055
2332
|
// ATTR
|
|
2056
|
-
return `${/** @type {Attr} */ret.name}="${/** @type {Attr} */ret.value.replaceAll('"', '"')}"`;
|
|
2333
|
+
return `${ /** @type {Attr} */ret.name}="${ /** @type {Attr} */ret.value.replaceAll('"', '"')}"`;
|
|
2057
2334
|
}
|
|
2058
2335
|
case 3:
|
|
2059
2336
|
{
|
|
2060
2337
|
// TEXT
|
|
2061
2338
|
// Fallthrough
|
|
2062
2339
|
// } case 4: { // CDATA
|
|
2340
|
+
// eslint-disable-next-line prefer-destructuring -- TS
|
|
2341
|
+
const nodeValue = /** @type {Text|CDATASection} */ret.nodeValue;
|
|
2063
2342
|
/* c8 ignore next 3 */
|
|
2064
|
-
if (!
|
|
2343
|
+
if (!nodeValue) {
|
|
2065
2344
|
throw new TypeError('Unexpected null Text node');
|
|
2066
2345
|
}
|
|
2067
|
-
return
|
|
2346
|
+
return nodeValue;
|
|
2068
2347
|
// case 5: // Entity Reference Node
|
|
2069
2348
|
// No 6: Entity Node
|
|
2070
2349
|
// No 12: Notation Node
|
|
@@ -2076,7 +2355,6 @@ jml.toHTML = function (...args) {
|
|
|
2076
2355
|
return `<?${node.target} ${node.data}?>`;
|
|
2077
2356
|
// } case 8: { // Comment
|
|
2078
2357
|
// return `<!--${ret.nodeValue}-->`;
|
|
2079
|
-
// eslint-disable-next-line sonarjs/no-fallthrough
|
|
2080
2358
|
}
|
|
2081
2359
|
case 9:
|
|
2082
2360
|
case 11:
|
|
@@ -2084,7 +2362,7 @@ jml.toHTML = function (...args) {
|
|
|
2084
2362
|
// DOCUMENT FRAGMENT
|
|
2085
2363
|
const node = /** @type {DocumentFragment} */ret;
|
|
2086
2364
|
return [...node.childNodes].map(childNode => {
|
|
2087
|
-
return
|
|
2365
|
+
return toHTML(/** @type {JamilihFirstArgument} */childNode);
|
|
2088
2366
|
}).join('');
|
|
2089
2367
|
}
|
|
2090
2368
|
case 10:
|
|
@@ -2098,47 +2376,52 @@ jml.toHTML = function (...args) {
|
|
|
2098
2376
|
throw new Error('Unexpected node type');
|
|
2099
2377
|
}
|
|
2100
2378
|
};
|
|
2379
|
+
jml.toHTML = toHTML;
|
|
2101
2380
|
|
|
2102
2381
|
/**
|
|
2103
2382
|
*
|
|
2104
2383
|
* @param {JamilihArray} args
|
|
2105
2384
|
* @returns {string}
|
|
2106
2385
|
*/
|
|
2107
|
-
|
|
2386
|
+
const toDOMString = function (...args) {
|
|
2108
2387
|
// Alias for jml.toHTML for parity with jml.toJMLString
|
|
2109
|
-
return
|
|
2388
|
+
return toHTML(...args);
|
|
2110
2389
|
};
|
|
2390
|
+
jml.toDOMString = toDOMString;
|
|
2111
2391
|
|
|
2112
2392
|
/**
|
|
2113
2393
|
*
|
|
2114
2394
|
* @param {JamilihArray} args
|
|
2115
2395
|
* @returns {string}
|
|
2116
2396
|
*/
|
|
2117
|
-
|
|
2397
|
+
const toXML = function (...args) {
|
|
2118
2398
|
if (!win) {
|
|
2119
2399
|
throw new Error('No window object set');
|
|
2120
2400
|
}
|
|
2121
2401
|
const ret = jml(...args);
|
|
2122
2402
|
return new /** @type {import('jsdom').DOMWindow} */win.XMLSerializer().serializeToString(ret);
|
|
2123
2403
|
};
|
|
2404
|
+
jml.toXML = toXML;
|
|
2124
2405
|
|
|
2125
2406
|
/**
|
|
2126
2407
|
*
|
|
2127
2408
|
* @param {JamilihArray} args
|
|
2128
2409
|
* @returns {string}
|
|
2129
2410
|
*/
|
|
2130
|
-
|
|
2411
|
+
const toXMLDOMString = function (...args) {
|
|
2131
2412
|
// Alias for jml.toXML for parity with jml.toJMLString
|
|
2132
|
-
return
|
|
2413
|
+
return toXML(...args);
|
|
2133
2414
|
};
|
|
2415
|
+
jml.toXMLDOMString = toXMLDOMString;
|
|
2134
2416
|
|
|
2135
2417
|
/**
|
|
2136
2418
|
* Element-aware wrapper for `Map`.
|
|
2419
|
+
* @template V
|
|
2137
2420
|
*/
|
|
2138
2421
|
class JamilihMap extends Map {
|
|
2139
2422
|
/**
|
|
2140
2423
|
* @param {?(string|HTMLElement)} element
|
|
2141
|
-
* @returns {
|
|
2424
|
+
* @returns {V}
|
|
2142
2425
|
*/
|
|
2143
2426
|
get(element) {
|
|
2144
2427
|
const elem = typeof element === 'string' ? $(element) : element;
|
|
@@ -2146,78 +2429,82 @@ class JamilihMap extends Map {
|
|
|
2146
2429
|
}
|
|
2147
2430
|
/**
|
|
2148
2431
|
* @param {string|HTMLElement} element
|
|
2149
|
-
* @param {
|
|
2150
|
-
* @returns {
|
|
2432
|
+
* @param {V} value
|
|
2433
|
+
* @returns {this}
|
|
2151
2434
|
*/
|
|
2152
2435
|
set(element, value) {
|
|
2153
2436
|
const elem = typeof element === 'string' ? $(element) : element;
|
|
2154
|
-
|
|
2437
|
+
super.set.call(this, elem, value);
|
|
2438
|
+
return this;
|
|
2155
2439
|
}
|
|
2156
2440
|
/**
|
|
2157
2441
|
* @param {string|HTMLElement} element
|
|
2158
2442
|
* @param {string} methodName
|
|
2159
|
-
* @param {...
|
|
2160
|
-
* @returns {
|
|
2443
|
+
* @param {...UserArg} args
|
|
2444
|
+
* @returns {StoredValue}
|
|
2161
2445
|
*/
|
|
2162
2446
|
invoke(element, methodName, ...args) {
|
|
2163
2447
|
const elem = typeof element === 'string' ? $(element) : element;
|
|
2164
|
-
return this.get(elem)[methodName](elem, ...args);
|
|
2448
|
+
return /** @type {UserArg} */this.get(elem)[methodName](elem, ...args);
|
|
2165
2449
|
}
|
|
2166
2450
|
}
|
|
2167
2451
|
|
|
2168
2452
|
/**
|
|
2169
2453
|
* Element-aware wrapper for `WeakMap`.
|
|
2170
|
-
* @
|
|
2454
|
+
* @template V
|
|
2171
2455
|
*/
|
|
2172
2456
|
class JamilihWeakMap extends WeakMap {
|
|
2173
2457
|
/**
|
|
2174
|
-
* @param {
|
|
2175
|
-
* @returns {
|
|
2458
|
+
* @param {?(string|object|symbol)} element
|
|
2459
|
+
* @returns {V}
|
|
2176
2460
|
*/
|
|
2177
2461
|
get(element) {
|
|
2178
2462
|
const elem = typeof element === 'string' ? $(element) : element;
|
|
2179
2463
|
if (!elem) {
|
|
2180
2464
|
throw new Error("Can't find the element");
|
|
2181
2465
|
}
|
|
2182
|
-
return super.get.call(this, elem);
|
|
2466
|
+
return super.get.call(this, /** @type {object} */elem);
|
|
2183
2467
|
}
|
|
2184
2468
|
/**
|
|
2185
|
-
* @param {
|
|
2186
|
-
* @param {
|
|
2187
|
-
* @returns {
|
|
2469
|
+
* @param {?(string|object|symbol)} element
|
|
2470
|
+
* @param {V} value
|
|
2471
|
+
* @returns {this}
|
|
2188
2472
|
*/
|
|
2189
2473
|
set(element, value) {
|
|
2190
2474
|
const elem = typeof element === 'string' ? $(element) : element;
|
|
2191
2475
|
if (!elem) {
|
|
2192
2476
|
throw new Error("Can't find the element");
|
|
2193
2477
|
}
|
|
2194
|
-
|
|
2478
|
+
super.set.call(this, /** @type {object} */elem, value);
|
|
2479
|
+
return this;
|
|
2195
2480
|
}
|
|
2196
2481
|
/**
|
|
2197
2482
|
* @param {string|HTMLElement} element
|
|
2198
2483
|
* @param {string} methodName
|
|
2199
|
-
* @param {...
|
|
2200
|
-
* @returns {
|
|
2484
|
+
* @param {...UserArg} args
|
|
2485
|
+
* @returns {StoredValue}
|
|
2201
2486
|
*/
|
|
2202
2487
|
invoke(element, methodName, ...args) {
|
|
2203
2488
|
const elem = typeof element === 'string' ? $(element) : element;
|
|
2204
2489
|
if (!elem) {
|
|
2205
2490
|
throw new Error("Can't find the element");
|
|
2206
2491
|
}
|
|
2207
|
-
return this.get(elem)[methodName](elem, ...args);
|
|
2492
|
+
return /** @type {UserArg} */this.get(elem)[methodName](elem, ...args);
|
|
2208
2493
|
}
|
|
2209
2494
|
}
|
|
2210
2495
|
jml.Map = JamilihMap;
|
|
2211
2496
|
jml.WeakMap = JamilihWeakMap;
|
|
2212
2497
|
|
|
2213
2498
|
/**
|
|
2214
|
-
* @
|
|
2499
|
+
* @template V
|
|
2500
|
+
* @typedef {[JamilihWeakMap<V>|JamilihMap<V>, HTMLElement]} MapAndElementArray
|
|
2215
2501
|
*/
|
|
2216
2502
|
|
|
2217
2503
|
/**
|
|
2218
|
-
* @
|
|
2504
|
+
* @template V
|
|
2505
|
+
* @param {V} obj
|
|
2219
2506
|
* @param {JamilihArrayPostOptions} args
|
|
2220
|
-
* @returns {MapAndElementArray}
|
|
2507
|
+
* @returns {MapAndElementArray<V>}
|
|
2221
2508
|
*/
|
|
2222
2509
|
jml.weak = function (obj, ...args) {
|
|
2223
2510
|
const map = new JamilihWeakMap();
|
|
@@ -2228,9 +2515,10 @@ jml.weak = function (obj, ...args) {
|
|
|
2228
2515
|
};
|
|
2229
2516
|
|
|
2230
2517
|
/**
|
|
2231
|
-
* @
|
|
2518
|
+
* @template V
|
|
2519
|
+
* @param {V} obj
|
|
2232
2520
|
* @param {JamilihArrayPostOptions} args
|
|
2233
|
-
* @returns {MapAndElementArray}
|
|
2521
|
+
* @returns {MapAndElementArray<V>}
|
|
2234
2522
|
*/
|
|
2235
2523
|
jml.strong = function (obj, ...args) {
|
|
2236
2524
|
const map = new JamilihMap();
|
|
@@ -2243,7 +2531,7 @@ jml.strong = function (obj, ...args) {
|
|
|
2243
2531
|
/**
|
|
2244
2532
|
* @param {string|HTMLElement} element If a string, will be interpreted as a selector
|
|
2245
2533
|
* @param {symbol|string} sym If a string, will be used with `Symbol.for`
|
|
2246
|
-
* @returns {
|
|
2534
|
+
* @returns {SymbolResult} The value associated with the symbol
|
|
2247
2535
|
*/
|
|
2248
2536
|
jml.symbol = jml.sym = jml.for = function (element, sym) {
|
|
2249
2537
|
const elem = typeof element === 'string' ? $(element) : element;
|
|
@@ -2253,16 +2541,16 @@ jml.symbol = jml.sym = jml.for = function (element, sym) {
|
|
|
2253
2541
|
};
|
|
2254
2542
|
|
|
2255
2543
|
/**
|
|
2256
|
-
* @typedef {((elem: HTMLElement, ...args:
|
|
2544
|
+
* @typedef {((elem: HTMLElement, ...args: UserArg[]) => void)|{[key: string]: (elem: HTMLElement, ...args: UserArg[]) => void}} MapCommand
|
|
2257
2545
|
*/
|
|
2258
2546
|
|
|
2259
2547
|
/**
|
|
2260
2548
|
* @param {?(string|HTMLElement)} elem If a string, will be interpreted as a selector
|
|
2261
2549
|
* @param {symbol|string|Map<HTMLElement, MapCommand>|WeakMap<HTMLElement, MapCommand>} symOrMap If a string, will be used with `Symbol.for`
|
|
2262
|
-
* @param {string|
|
|
2550
|
+
* @param {string|UserArg} methodName Can be `UserArg` if the symbol or map directly
|
|
2263
2551
|
* points to a function (it is then used as the first argument).
|
|
2264
|
-
* @param {
|
|
2265
|
-
* @returns {
|
|
2552
|
+
* @param {UserArg[]} args
|
|
2553
|
+
* @returns {StoredValue}
|
|
2266
2554
|
*/
|
|
2267
2555
|
jml.command = function (elem, symOrMap, methodName, ...args) {
|
|
2268
2556
|
elem = typeof elem === 'string' ? $(elem) : elem;
|
|
@@ -2275,7 +2563,7 @@ jml.command = function (elem, symOrMap, methodName, ...args) {
|
|
|
2275
2563
|
if (typeof func === 'function') {
|
|
2276
2564
|
return func(methodName, ...args); // Already has `this` bound to `elem`
|
|
2277
2565
|
}
|
|
2278
|
-
return func[methodName](...args);
|
|
2566
|
+
return /** @type {UserArg} */func[methodName](...args);
|
|
2279
2567
|
}
|
|
2280
2568
|
func = /** @type {Map<HTMLElement, MapCommand>|WeakMap<HTMLElement, MapCommand>} */symOrMap.get(elem);
|
|
2281
2569
|
if (!func) {
|
|
@@ -2291,10 +2579,10 @@ jml.command = function (elem, symOrMap, methodName, ...args) {
|
|
|
2291
2579
|
/**
|
|
2292
2580
|
* Expects properties `document`, `XMLSerializer`, and `DOMParser`.
|
|
2293
2581
|
* Also updates `body` with `document.body`.
|
|
2294
|
-
* @param {import('jsdom').DOMWindow|HTMLWindow|undefined} wind
|
|
2582
|
+
* @param {import('jsdom').DOMWindow|HTMLWindow|typeof globalThis|undefined} wind
|
|
2295
2583
|
* @returns {void}
|
|
2296
2584
|
*/
|
|
2297
|
-
|
|
2585
|
+
const setWindow = wind => {
|
|
2298
2586
|
win = wind;
|
|
2299
2587
|
doc = win?.document;
|
|
2300
2588
|
if (doc && doc.body) {
|
|
@@ -2302,28 +2590,31 @@ jml.setWindow = wind => {
|
|
|
2302
2590
|
body = /** @type {HTMLBodyElement} */doc.body;
|
|
2303
2591
|
}
|
|
2304
2592
|
};
|
|
2593
|
+
jml.setWindow = setWindow;
|
|
2305
2594
|
|
|
2306
2595
|
/**
|
|
2307
|
-
* @returns {import('jsdom').DOMWindow|HTMLWindow}
|
|
2596
|
+
* @returns {import('jsdom').DOMWindow|HTMLWindow|typeof globalThis}
|
|
2308
2597
|
*/
|
|
2309
|
-
|
|
2598
|
+
const getWindow = () => {
|
|
2310
2599
|
if (!win) {
|
|
2311
2600
|
throw new Error('No window object set');
|
|
2312
2601
|
}
|
|
2313
2602
|
return win;
|
|
2314
2603
|
};
|
|
2604
|
+
jml.getWindow = getWindow;
|
|
2315
2605
|
|
|
2316
2606
|
/**
|
|
2317
2607
|
* Does not run Jamilih so can be further processed.
|
|
2318
|
-
* @
|
|
2319
|
-
* @param {
|
|
2320
|
-
* @
|
|
2608
|
+
* @template T
|
|
2609
|
+
* @param {T[]} array
|
|
2610
|
+
* @param {T} glu
|
|
2611
|
+
* @returns {T[]}
|
|
2321
2612
|
*/
|
|
2322
2613
|
function glue(array, glu) {
|
|
2323
2614
|
return [...array].reduce((arr, item) => {
|
|
2324
2615
|
arr.push(item, glu);
|
|
2325
2616
|
return arr;
|
|
2326
|
-
}, []).slice(0, -1);
|
|
2617
|
+
}, /** @type {T[]} */[]).slice(0, -1);
|
|
2327
2618
|
}
|
|
2328
2619
|
|
|
2329
2620
|
/**
|
|
@@ -2336,6 +2627,6 @@ if (doc && doc.body) {
|
|
|
2336
2627
|
// eslint-disable-next-line prefer-destructuring -- Needed for type
|
|
2337
2628
|
body = /** @type {HTMLBodyElement} */doc.body;
|
|
2338
2629
|
}
|
|
2339
|
-
const nbsp = '\
|
|
2630
|
+
const nbsp = '\u{A0}'; // Very commonly needed in templates
|
|
2340
2631
|
|
|
2341
|
-
export { $, $$, DOMException, body,
|
|
2632
|
+
export { $, $$, DOMException, body, getWindow, glue, jml, nbsp, setWindow, toDOM, toDOMString, toHTML, toJML, toJMLString, toXML, toXMLDOMString };
|