@es-joy/jsoe 0.2.0 → 0.4.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/.eslintignore +3 -0
- package/.eslintrc.cjs +2 -0
- package/.ncurc.cjs +9 -0
- package/CHANGES.md +9 -0
- package/README.md +2 -2
- package/demo/index.html +8 -0
- package/demo/index.js +1 -1
- package/dist/formatAndTypeChoices.d.ts +56 -0
- package/dist/formatAndTypeChoices.d.ts.map +1 -0
- package/dist/formats/indexedDBKey.d.ts +4 -0
- package/dist/formats/indexedDBKey.d.ts.map +1 -0
- package/dist/formats/json.d.ts +4 -0
- package/dist/formats/json.d.ts.map +1 -0
- package/dist/formats/schemaAndArbitrary.d.ts +6 -0
- package/dist/formats/schemaAndArbitrary.d.ts.map +1 -0
- package/dist/formats/schemaOnly.d.ts +6 -0
- package/dist/formats/schemaOnly.d.ts.map +1 -0
- package/dist/formats/structuredCloning.d.ts +20 -0
- package/dist/formats/structuredCloning.d.ts.map +1 -0
- package/dist/formats.d.ts +26 -0
- package/dist/formats.d.ts.map +1 -0
- package/dist/fundamentalTypes/BooleanObjectType.d.ts +8 -0
- package/dist/fundamentalTypes/BooleanObjectType.d.ts.map +1 -0
- package/dist/fundamentalTypes/NumberObjectType.d.ts +6 -0
- package/dist/fundamentalTypes/NumberObjectType.d.ts.map +1 -0
- package/dist/fundamentalTypes/StringObjectType.d.ts +6 -0
- package/dist/fundamentalTypes/StringObjectType.d.ts.map +1 -0
- package/dist/fundamentalTypes/arrayReferenceType.d.ts +8 -0
- package/dist/fundamentalTypes/arrayReferenceType.d.ts.map +1 -0
- package/dist/fundamentalTypes/arrayType.d.ts +60 -0
- package/dist/fundamentalTypes/arrayType.d.ts.map +1 -0
- package/dist/fundamentalTypes/bigintType.d.ts +6 -0
- package/dist/fundamentalTypes/bigintType.d.ts.map +1 -0
- package/dist/fundamentalTypes/dateType.d.ts +26 -0
- package/dist/fundamentalTypes/dateType.d.ts.map +1 -0
- package/dist/fundamentalTypes/nullType.d.ts +6 -0
- package/dist/fundamentalTypes/nullType.d.ts.map +1 -0
- package/dist/fundamentalTypes/numberType.d.ts +6 -0
- package/dist/fundamentalTypes/numberType.d.ts.map +1 -0
- package/dist/fundamentalTypes/objectReferenceType.d.ts +8 -0
- package/dist/fundamentalTypes/objectReferenceType.d.ts.map +1 -0
- package/dist/fundamentalTypes/objectType.d.ts +6 -0
- package/dist/fundamentalTypes/objectType.d.ts.map +1 -0
- package/dist/fundamentalTypes/regexpType.d.ts +8 -0
- package/dist/fundamentalTypes/regexpType.d.ts.map +1 -0
- package/dist/fundamentalTypes/sparseUndefinedType.d.ts +6 -0
- package/dist/fundamentalTypes/sparseUndefinedType.d.ts.map +1 -0
- package/dist/fundamentalTypes/stringType.d.ts +6 -0
- package/dist/fundamentalTypes/stringType.d.ts.map +1 -0
- package/dist/fundamentalTypes/undefinedType.d.ts +6 -0
- package/dist/fundamentalTypes/undefinedType.d.ts.map +1 -0
- package/dist/index.d.ts +5 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/src/deepEqual.d.ts +3 -0
- package/dist/src/deepEqual.d.ts.map +1 -0
- package/dist/src/formatAndTypeChoices.d.ts +47 -0
- package/dist/src/formatAndTypeChoices.d.ts.map +1 -0
- package/dist/src/formats/indexedDBKey.d.ts +9 -0
- package/dist/src/formats/indexedDBKey.d.ts.map +1 -0
- package/dist/src/formats/json.d.ts +9 -0
- package/dist/src/formats/json.d.ts.map +1 -0
- package/dist/src/formats/schemaAndArbitrary.d.ts +6 -0
- package/dist/src/formats/schemaAndArbitrary.d.ts.map +1 -0
- package/dist/src/formats/schemaOnly.d.ts +6 -0
- package/dist/src/formats/schemaOnly.d.ts.map +1 -0
- package/dist/src/formats/structuredCloning.d.ts +15 -0
- package/dist/src/formats/structuredCloning.d.ts.map +1 -0
- package/dist/src/formats.d.ts +18 -0
- package/dist/src/formats.d.ts.map +1 -0
- package/dist/src/fundamentalTypes/BooleanObjectType.d.ts +6 -0
- package/dist/src/fundamentalTypes/BooleanObjectType.d.ts.map +1 -0
- package/dist/src/fundamentalTypes/NumberObjectType.d.ts +6 -0
- package/dist/src/fundamentalTypes/NumberObjectType.d.ts.map +1 -0
- package/dist/src/fundamentalTypes/StringObjectType.d.ts +6 -0
- package/dist/src/fundamentalTypes/StringObjectType.d.ts.map +1 -0
- package/dist/src/fundamentalTypes/arrayReferenceType.d.ts +6 -0
- package/dist/src/fundamentalTypes/arrayReferenceType.d.ts.map +1 -0
- package/dist/src/fundamentalTypes/arrayType.d.ts +6 -0
- package/dist/src/fundamentalTypes/arrayType.d.ts.map +1 -0
- package/dist/src/fundamentalTypes/bigintType.d.ts +6 -0
- package/dist/src/fundamentalTypes/bigintType.d.ts.map +1 -0
- package/dist/src/fundamentalTypes/dateType.d.ts +6 -0
- package/dist/src/fundamentalTypes/dateType.d.ts.map +1 -0
- package/dist/src/fundamentalTypes/nullType.d.ts +6 -0
- package/dist/src/fundamentalTypes/nullType.d.ts.map +1 -0
- package/dist/src/fundamentalTypes/numberType.d.ts +6 -0
- package/dist/src/fundamentalTypes/numberType.d.ts.map +1 -0
- package/dist/src/fundamentalTypes/objectReferenceType.d.ts +6 -0
- package/dist/src/fundamentalTypes/objectReferenceType.d.ts.map +1 -0
- package/dist/src/fundamentalTypes/objectType.d.ts +6 -0
- package/dist/src/fundamentalTypes/objectType.d.ts.map +1 -0
- package/dist/src/fundamentalTypes/regexpType.d.ts +6 -0
- package/dist/src/fundamentalTypes/regexpType.d.ts.map +1 -0
- package/dist/src/fundamentalTypes/sparseUndefinedType.d.ts +6 -0
- package/dist/src/fundamentalTypes/sparseUndefinedType.d.ts.map +1 -0
- package/dist/src/fundamentalTypes/stringType.d.ts +6 -0
- package/dist/src/fundamentalTypes/stringType.d.ts.map +1 -0
- package/dist/src/fundamentalTypes/undefinedType.d.ts +6 -0
- package/dist/src/fundamentalTypes/undefinedType.d.ts.map +1 -0
- package/dist/src/index.d.ts +5 -0
- package/dist/src/index.d.ts.map +1 -0
- package/dist/src/subTypes/blobHTMLType.d.ts +26 -0
- package/dist/src/subTypes/blobHTMLType.d.ts.map +1 -0
- package/dist/src/subTypes/falseType.d.ts +6 -0
- package/dist/src/subTypes/falseType.d.ts.map +1 -0
- package/dist/src/subTypes/trueType.d.ts +6 -0
- package/dist/src/subTypes/trueType.d.ts.map +1 -0
- package/dist/src/superTypes/SpecialNumberSuperType.d.ts +11 -0
- package/dist/src/superTypes/SpecialNumberSuperType.d.ts.map +1 -0
- package/dist/src/superTypes/SpecialRealNumberSuperType.d.ts +6 -0
- package/dist/src/superTypes/SpecialRealNumberSuperType.d.ts.map +1 -0
- package/dist/src/typeChoices.d.ts +30 -0
- package/dist/src/typeChoices.d.ts.map +1 -0
- package/dist/src/types.d.ts +333 -0
- package/dist/src/types.d.ts.map +1 -0
- package/dist/src/utils/dialogs.d.ts +29 -0
- package/dist/src/utils/dialogs.d.ts.map +1 -0
- package/dist/src/utils/jsonPointer.d.ts +42 -0
- package/dist/src/utils/jsonPointer.d.ts.map +1 -0
- package/dist/src/utils/templateUtils.d.ts +59 -0
- package/dist/src/utils/templateUtils.d.ts.map +1 -0
- package/dist/src/utils/types.d.ts +2 -0
- package/dist/src/utils/types.d.ts.map +1 -0
- package/dist/subTypes/blobHTMLType.d.ts +14 -0
- package/dist/subTypes/blobHTMLType.d.ts.map +1 -0
- package/dist/subTypes/falseType.d.ts +8 -0
- package/dist/subTypes/falseType.d.ts.map +1 -0
- package/dist/subTypes/trueType.d.ts +8 -0
- package/dist/subTypes/trueType.d.ts.map +1 -0
- package/dist/superTypes/SpecialNumberSuperType.d.ts +14 -0
- package/dist/superTypes/SpecialNumberSuperType.d.ts.map +1 -0
- package/dist/superTypes/SpecialRealNumberSuperType.d.ts +6 -0
- package/dist/superTypes/SpecialRealNumberSuperType.d.ts.map +1 -0
- package/dist/typeChoices.d.ts +103 -0
- package/dist/typeChoices.d.ts.map +1 -0
- package/dist/types.d.ts +523 -0
- package/dist/types.d.ts.map +1 -0
- package/dist/utils/dialogs.d.ts +109 -0
- package/dist/utils/dialogs.d.ts.map +1 -0
- package/dist/utils/jsonPointer.d.ts +46 -0
- package/dist/utils/jsonPointer.d.ts.map +1 -0
- package/dist/utils/templateUtils.d.ts +59 -0
- package/dist/utils/templateUtils.d.ts.map +1 -0
- package/dist/utils/types.d.ts +2 -0
- package/dist/utils/types.d.ts.map +1 -0
- package/dist/vendor/jamilih/dist/jml-es.d.ts +436 -0
- package/dist/vendor/jamilih/dist/jml-es.d.ts.map +1 -0
- package/dist/vendor/typeson-registry/dist/index.d.ts +400 -0
- package/dist/vendor/typeson-registry/dist/index.d.ts.map +1 -0
- package/dist/vendor-imports.d.ts +3 -0
- package/dist/vendor-imports.d.ts.map +1 -0
- package/package.json +19 -14
- package/postorder-traversal.js +58 -0
- package/src/formatAndTypeChoices.js +95 -50
- package/src/formats/indexedDBKey.js +49 -56
- package/src/formats/json.js +47 -56
- package/src/formats/schemaOnly.js +12 -2
- package/src/formats/structuredCloning.js +162 -105
- package/src/formats.js +38 -10
- package/src/fundamentalTypes/BooleanObjectType.js +6 -4
- package/src/fundamentalTypes/NumberObjectType.js +5 -3
- package/src/fundamentalTypes/StringObjectType.js +1 -1
- package/src/fundamentalTypes/arrayReferenceType.js +29 -14
- package/src/fundamentalTypes/arrayType.js +789 -278
- package/src/fundamentalTypes/bigintType.js +2 -2
- package/src/fundamentalTypes/dateType.js +42 -14
- package/src/fundamentalTypes/nullType.js +1 -1
- package/src/fundamentalTypes/numberType.js +2 -2
- package/src/fundamentalTypes/objectReferenceType.js +7 -5
- package/src/fundamentalTypes/regexpType.js +45 -24
- package/src/fundamentalTypes/sparseUndefinedType.js +7 -1
- package/src/fundamentalTypes/stringType.js +1 -1
- package/src/fundamentalTypes/undefinedType.js +2 -2
- package/src/jsoe.css +1 -1
- package/src/subTypes/blobHTMLType.js +42 -22
- package/src/subTypes/falseType.js +2 -2
- package/src/subTypes/trueType.js +2 -2
- package/src/superTypes/SpecialNumberSuperType.js +30 -16
- package/src/superTypes/SpecialRealNumberSuperType.js +62 -0
- package/src/typeChoices.js +137 -55
- package/src/types.js +312 -148
- package/src/utils/dialogs.js +98 -29
- package/src/utils/jsonPointer.js +4 -0
- package/src/utils/templateUtils.js +27 -12
- package/src/vendor-imports.js +8 -0
- package/tsconfig.json +18 -0
- package/typings/sceditor.d.ts +20 -0
- package/vendor/jamilih/dist/jml-es.js +1019 -389
- package/vendor/jamilih/dist/jml.d.ts +436 -0
- package/vendor/jamilih/package.json +136 -0
- package/vendor/typeson-registry/dist/index.js +382 -84
- package/src/superTypes/InfinitiesSuperType.js +0 -49
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
var _win;
|
|
1
2
|
/*
|
|
2
3
|
Possible todos:
|
|
3
4
|
0. Add XSLT to JML-string stylesheet (or even vice versa)
|
|
@@ -28,10 +29,44 @@ Other Todos:
|
|
|
28
29
|
0. Redo browser testing of jml (including ensuring IE7 can work even if test framework can't work)
|
|
29
30
|
*/
|
|
30
31
|
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
32
|
+
/**
|
|
33
|
+
* @typedef {Window & {DocumentFragment: any}} HTMLWindow
|
|
34
|
+
*/
|
|
35
|
+
|
|
36
|
+
/**
|
|
37
|
+
* @typedef {any} ArbitraryValue
|
|
38
|
+
*/
|
|
39
|
+
|
|
40
|
+
/**
|
|
41
|
+
* @typedef {number} Integer
|
|
42
|
+
*/
|
|
43
|
+
|
|
44
|
+
/**
|
|
45
|
+
* @typedef {{
|
|
46
|
+
* element: Document|Element|DocumentFragment,
|
|
47
|
+
* attribute: {name: string|null, value: JamilihAttValue},
|
|
48
|
+
* opts: JamilihOptions
|
|
49
|
+
* }} PluginSettings
|
|
50
|
+
*/
|
|
51
|
+
|
|
52
|
+
/**
|
|
53
|
+
* @typedef {object} JamilihPlugin
|
|
54
|
+
* @property {string} name
|
|
55
|
+
* @property {(opts: PluginSettings) => string} set
|
|
56
|
+
*/
|
|
57
|
+
|
|
58
|
+
/**
|
|
59
|
+
* @type {import('jsdom').DOMWindow|HTMLWindow|undefined}
|
|
60
|
+
*/
|
|
61
|
+
let win;
|
|
62
|
+
|
|
63
|
+
/* c8 ignore next */
|
|
64
|
+
if (typeof window !== 'undefined' && window) {
|
|
65
|
+
win = window;
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
/* c8 ignore next */
|
|
69
|
+
let doc = typeof document !== 'undefined' && document || ((_win = win) === null || _win === void 0 ? void 0 : _win.document);
|
|
35
70
|
|
|
36
71
|
// STATIC PROPERTIES
|
|
37
72
|
|
|
@@ -43,11 +78,7 @@ const possibleOptions = ['$plugins',
|
|
|
43
78
|
|
|
44
79
|
const NS_HTML = 'http://www.w3.org/1999/xhtml',
|
|
45
80
|
hyphenForCamelCase = /-([a-z])/gu;
|
|
46
|
-
const ATTR_MAP =
|
|
47
|
-
maxlength: 'maxLength',
|
|
48
|
-
minlength: 'minLength',
|
|
49
|
-
readonly: 'readOnly'
|
|
50
|
-
};
|
|
81
|
+
const ATTR_MAP = new Map([['maxlength', 'maxLength'], ['minlength', 'minLength'], ['readonly', 'readOnly']]);
|
|
51
82
|
|
|
52
83
|
// We define separately from ATTR_DOM for clarity (and parity with JsonML) but no current need
|
|
53
84
|
// We don't set attribute esp. for boolean atts as we want to allow setting of `undefined`
|
|
@@ -87,8 +118,27 @@ const NULLABLES = ['autocomplete', 'dir',
|
|
|
87
118
|
'max', 'min', 'minLength', 'maxLength', 'title' // HTMLElement
|
|
88
119
|
];
|
|
89
120
|
|
|
90
|
-
|
|
91
|
-
|
|
121
|
+
/**
|
|
122
|
+
* @param {string} sel
|
|
123
|
+
* @returns {Element|null}
|
|
124
|
+
*/
|
|
125
|
+
const $ = sel => {
|
|
126
|
+
if (!doc) {
|
|
127
|
+
throw new Error('No document object');
|
|
128
|
+
}
|
|
129
|
+
return doc.querySelector(sel);
|
|
130
|
+
};
|
|
131
|
+
|
|
132
|
+
/**
|
|
133
|
+
* @param {string} sel
|
|
134
|
+
* @returns {Element[]}
|
|
135
|
+
*/
|
|
136
|
+
const $$ = sel => {
|
|
137
|
+
if (!doc) {
|
|
138
|
+
return [];
|
|
139
|
+
}
|
|
140
|
+
return [...doc.querySelectorAll(sel)];
|
|
141
|
+
};
|
|
92
142
|
|
|
93
143
|
/**
|
|
94
144
|
* Retrieve the (lower-cased) HTML name of a node.
|
|
@@ -101,74 +151,20 @@ function _getHTMLNodeName(node) {
|
|
|
101
151
|
}
|
|
102
152
|
|
|
103
153
|
/**
|
|
104
|
-
* Apply styles if this is a style tag.
|
|
105
|
-
* @static
|
|
106
|
-
* @param {Node} node The element to check whether it is a style tag
|
|
107
|
-
* @returns {void}
|
|
108
|
-
*/
|
|
109
|
-
function _applyAnyStylesheet(node) {
|
|
110
|
-
// Only used in IE
|
|
111
|
-
// istanbul ignore else
|
|
112
|
-
if (!doc.createStyleSheet) {
|
|
113
|
-
return;
|
|
114
|
-
}
|
|
115
|
-
// istanbul ignore next
|
|
116
|
-
if (_getHTMLNodeName(node) === 'style') {
|
|
117
|
-
// IE
|
|
118
|
-
const ss = doc.createStyleSheet(); // Create a stylesheet to actually do something useful
|
|
119
|
-
ss.cssText = node.cssText;
|
|
120
|
-
// We continue to add the style tag, however
|
|
121
|
-
}
|
|
122
|
-
}
|
|
123
|
-
|
|
124
|
-
/**
|
|
125
|
-
* Need this function for IE since options weren't otherwise getting added.
|
|
126
154
|
* @private
|
|
127
155
|
* @static
|
|
128
|
-
* @param {Element} parent The parent to which to append the element
|
|
129
|
-
* @param {Node} child The element or other node to append to the parent
|
|
156
|
+
* @param {Document|DocumentFragment|Element} parent The parent to which to append the element
|
|
157
|
+
* @param {Node|string} child The element or other node to append to the parent
|
|
130
158
|
* @throws {Error} Rethrow if problem with `append` and unhandled
|
|
131
159
|
* @returns {void}
|
|
132
160
|
*/
|
|
133
161
|
function _appendNode(parent, child) {
|
|
134
162
|
const parentName = _getHTMLNodeName(parent);
|
|
135
|
-
|
|
136
|
-
// IE only
|
|
137
|
-
// istanbul ignore if
|
|
138
|
-
if (doc.createStyleSheet) {
|
|
139
|
-
if (parentName === 'script') {
|
|
140
|
-
parent.text = child.nodeValue;
|
|
141
|
-
return;
|
|
142
|
-
}
|
|
143
|
-
if (parentName === 'style') {
|
|
144
|
-
parent.cssText = child.nodeValue; // This will not apply it--just make it available within the DOM cotents
|
|
145
|
-
return;
|
|
146
|
-
}
|
|
147
|
-
}
|
|
148
163
|
if (parentName === 'template') {
|
|
149
|
-
parent.content.append(child);
|
|
164
|
+
/** @type {HTMLTemplateElement} */parent.content.append(child);
|
|
150
165
|
return;
|
|
151
166
|
}
|
|
152
|
-
|
|
153
|
-
parent.append(child); // IE9 is now ok with this
|
|
154
|
-
} catch (e) {
|
|
155
|
-
// istanbul ignore next
|
|
156
|
-
const childName = _getHTMLNodeName(child);
|
|
157
|
-
// istanbul ignore next
|
|
158
|
-
if (parentName === 'select' && childName === 'option') {
|
|
159
|
-
try {
|
|
160
|
-
// Since this is now DOM Level 4 standard behavior (and what IE7+ can handle), we try it first
|
|
161
|
-
parent.add(child);
|
|
162
|
-
} catch (err) {
|
|
163
|
-
// DOM Level 2 did require a second argument, so we try it too just in case the user is using an older version of Firefox, etc.
|
|
164
|
-
parent.add(child, null); // IE7 has a problem with this, but IE8+ is ok
|
|
165
|
-
}
|
|
166
|
-
|
|
167
|
-
return;
|
|
168
|
-
}
|
|
169
|
-
// istanbul ignore next
|
|
170
|
-
throw e;
|
|
171
|
-
}
|
|
167
|
+
parent.append(child); // IE9 is now ok with this
|
|
172
168
|
}
|
|
173
169
|
|
|
174
170
|
/**
|
|
@@ -194,6 +190,9 @@ function _addEvent(el, type, handler, capturing) {
|
|
|
194
190
|
* @returns {Text} The text node of the resolved reference
|
|
195
191
|
*/
|
|
196
192
|
function _createSafeReference(type, prefix, arg) {
|
|
193
|
+
if (!doc) {
|
|
194
|
+
throw new Error('No document defined');
|
|
195
|
+
}
|
|
197
196
|
// For security reasons related to innerHTML, we ensure this string only
|
|
198
197
|
// contains potential entity characters
|
|
199
198
|
if (!/^\w+$/u.test(arg)) {
|
|
@@ -228,11 +227,20 @@ function _isNullish(o) {
|
|
|
228
227
|
/**
|
|
229
228
|
* @private
|
|
230
229
|
* @static
|
|
231
|
-
* @param {string|JamilihAttributes|JamilihArray|
|
|
232
|
-
*
|
|
230
|
+
* @param {string|JamilihAttributes|JamilihArray|JamilihChildren|
|
|
231
|
+
* JamilihDocumentFragment|JamilihAttributeNode|
|
|
232
|
+
* JamilihOptions|Element|Document|DocumentFragment|null|undefined} item
|
|
233
|
+
* @returns {"string"|"null"|"array"|"element"|"fragment"|"object"|
|
|
234
|
+
* "symbol"|"bigint"|"function"|"number"|"boolean"|"undefined"|
|
|
235
|
+
* "document"|"non-container node"}
|
|
233
236
|
*/
|
|
234
237
|
function _getType(item) {
|
|
235
238
|
const type = typeof item;
|
|
239
|
+
|
|
240
|
+
// Appease TS
|
|
241
|
+
if (typeof item === 'string' || typeof item === 'undefined') {
|
|
242
|
+
return 'string';
|
|
243
|
+
}
|
|
236
244
|
switch (type) {
|
|
237
245
|
case 'object':
|
|
238
246
|
if (item === null) {
|
|
@@ -274,11 +282,16 @@ function _fragReducer(frag, node) {
|
|
|
274
282
|
/**
|
|
275
283
|
* @private
|
|
276
284
|
* @static
|
|
277
|
-
* @param {Object<
|
|
278
|
-
* @returns {string}
|
|
285
|
+
* @param {Object<string, string>} xmlnsObj
|
|
286
|
+
* @returns {(...n: string[]) => string}
|
|
279
287
|
*/
|
|
280
288
|
function _replaceDefiner(xmlnsObj) {
|
|
281
|
-
|
|
289
|
+
/**
|
|
290
|
+
* @param {string[]} n
|
|
291
|
+
* @returns {string}
|
|
292
|
+
*/
|
|
293
|
+
return function (...n) {
|
|
294
|
+
const n0 = n[0];
|
|
282
295
|
let retStr = xmlnsObj[''] ? ' xmlns="' + xmlnsObj[''] + '"' : n0; // Preserve XHTML
|
|
283
296
|
for (const [ns, xmlnsVal] of Object.entries(xmlnsObj)) {
|
|
284
297
|
if (ns !== '') {
|
|
@@ -290,48 +303,52 @@ function _replaceDefiner(xmlnsObj) {
|
|
|
290
303
|
}
|
|
291
304
|
|
|
292
305
|
/**
|
|
293
|
-
* @
|
|
294
|
-
* @
|
|
295
|
-
* @
|
|
296
|
-
|
|
297
|
-
|
|
298
|
-
/**
|
|
299
|
-
* @callback ChildrenToJMLCallback
|
|
300
|
-
* @param {JamilihArray|Jamilih} childNodeJML
|
|
301
|
-
* @param {Integer} i
|
|
302
|
-
* @returns {void}
|
|
303
|
-
*/
|
|
306
|
+
* @callback ChildrenToJMLCallback
|
|
307
|
+
* @param {JamilihArray|JamilihChildType|string} childNodeJML
|
|
308
|
+
* @param {Integer} i
|
|
309
|
+
* @returns {void}
|
|
310
|
+
*/
|
|
304
311
|
|
|
305
312
|
/**
|
|
306
|
-
* @private
|
|
307
|
-
* @static
|
|
308
|
-
* @param {Node} node
|
|
309
|
-
* @returns {ChildrenToJMLCallback}
|
|
310
|
-
*/
|
|
313
|
+
* @private
|
|
314
|
+
* @static
|
|
315
|
+
* @param {Node} node
|
|
316
|
+
* @returns {ChildrenToJMLCallback}
|
|
317
|
+
*/
|
|
311
318
|
function _childrenToJML(node) {
|
|
312
319
|
return function (childNodeJML, i) {
|
|
313
320
|
const cn = node.childNodes[i];
|
|
314
|
-
const j = Array.isArray(childNodeJML) ? jml(...childNodeJML) : jml(childNodeJML);
|
|
321
|
+
const j = Array.isArray(childNodeJML) ? jml(... /** @type {JamilihArray} */childNodeJML) : jml(childNodeJML);
|
|
315
322
|
cn.replaceWith(j);
|
|
316
323
|
};
|
|
317
324
|
}
|
|
318
325
|
|
|
326
|
+
/**
|
|
327
|
+
* Keep this in sync with `JamilihArray`'s first argument (minus `Document`).
|
|
328
|
+
* @typedef {JamilihDoc|JamilihDoctype|JamilihTextNode|
|
|
329
|
+
* JamilihAttributeNode|JamilihOptions|ElementName|Element|
|
|
330
|
+
* JamilihDocumentFragment
|
|
331
|
+
* } JamilihFirstArg
|
|
332
|
+
*/
|
|
333
|
+
|
|
319
334
|
/**
|
|
320
335
|
* @callback JamilihAppender
|
|
321
|
-
* @param {JamilihArray} childJML
|
|
336
|
+
* @param {JamilihArray|JamilihFirstArg|Node} childJML
|
|
322
337
|
* @returns {void}
|
|
323
338
|
*/
|
|
324
339
|
|
|
325
340
|
/**
|
|
326
341
|
* @private
|
|
327
342
|
* @static
|
|
328
|
-
* @param {
|
|
343
|
+
* @param {ParentNode} node
|
|
329
344
|
* @returns {JamilihAppender}
|
|
330
345
|
*/
|
|
331
346
|
function _appendJML(node) {
|
|
332
347
|
return function (childJML) {
|
|
333
348
|
if (Array.isArray(childJML)) {
|
|
334
349
|
node.append(jml(...childJML));
|
|
350
|
+
} else if (typeof childJML === 'object' && 'nodeType' in childJML) {
|
|
351
|
+
node.append(childJML);
|
|
335
352
|
} else {
|
|
336
353
|
node.append(jml(childJML));
|
|
337
354
|
}
|
|
@@ -340,14 +357,14 @@ function _appendJML(node) {
|
|
|
340
357
|
|
|
341
358
|
/**
|
|
342
359
|
* @callback appender
|
|
343
|
-
* @param {
|
|
360
|
+
* @param {JamilihArray|JamilihFirstArg|Node} childJML
|
|
344
361
|
* @returns {void}
|
|
345
362
|
*/
|
|
346
363
|
|
|
347
364
|
/**
|
|
348
365
|
* @private
|
|
349
366
|
* @static
|
|
350
|
-
* @param {
|
|
367
|
+
* @param {ParentNode} node
|
|
351
368
|
* @returns {appender}
|
|
352
369
|
*/
|
|
353
370
|
function _appendJMLOrText(node) {
|
|
@@ -356,6 +373,8 @@ function _appendJMLOrText(node) {
|
|
|
356
373
|
node.append(childJML);
|
|
357
374
|
} else if (Array.isArray(childJML)) {
|
|
358
375
|
node.append(jml(...childJML));
|
|
376
|
+
} else if (typeof childJML === 'object' && 'nodeType' in childJML) {
|
|
377
|
+
node.append(childJML);
|
|
359
378
|
} else {
|
|
360
379
|
node.append(jml(childJML));
|
|
361
380
|
}
|
|
@@ -376,43 +395,333 @@ function _DOMfromJMLOrString (childNodeJML) {
|
|
|
376
395
|
*/
|
|
377
396
|
|
|
378
397
|
/**
|
|
379
|
-
* @typedef {Element|DocumentFragment
|
|
398
|
+
* @typedef {Element|DocumentFragment|Comment|Attr|
|
|
399
|
+
* Text|Document|DocumentType|ProcessingInstruction|CDATASection} JamilihReturn
|
|
380
400
|
*/
|
|
401
|
+
// 'string|JamilihOptions|JamilihDocumentFragment|JamilihAttributes|(string|JamilihArray)[]
|
|
381
402
|
|
|
382
403
|
/**
|
|
383
|
-
*
|
|
384
|
-
|
|
404
|
+
* Can either be an array of:
|
|
405
|
+
* 1. JamilihAttributes followed by an array of JamilihArrays or Elements.
|
|
406
|
+
* (Cannot be multiple single JamilihArrays despite TS type).
|
|
407
|
+
* 2. Any number of JamilihArrays.
|
|
408
|
+
* @typedef {[(JamilihAttributes|JamilihArray|JamilihArray[]|Element), ...(JamilihArray|JamilihArray[]|Element)[]]} TemplateJamilihArray
|
|
409
|
+
*/
|
|
385
410
|
|
|
386
411
|
/**
|
|
387
|
-
* @typedef {
|
|
388
|
-
|
|
389
|
-
|
|
390
|
-
|
|
391
|
-
*
|
|
392
|
-
*
|
|
393
|
-
*
|
|
394
|
-
*
|
|
395
|
-
*
|
|
396
|
-
*
|
|
397
|
-
|
|
398
|
-
|
|
399
|
-
|
|
400
|
-
|
|
412
|
+
* @typedef {(JamilihArray|Element)[]} ShadowRootJamilihArrayContainer
|
|
413
|
+
*/
|
|
414
|
+
|
|
415
|
+
/**
|
|
416
|
+
* @typedef {{
|
|
417
|
+
* open?: boolean|ShadowRootJamilihArrayContainer,
|
|
418
|
+
* closed?: boolean|ShadowRootJamilihArrayContainer,
|
|
419
|
+
* template?: string|HTMLTemplateElement|TemplateJamilihArray,
|
|
420
|
+
* content?: ShadowRootJamilihArrayContainer|DocumentFragment
|
|
421
|
+
* }} JamilihShadowRootObject
|
|
422
|
+
*/
|
|
423
|
+
|
|
424
|
+
/**
|
|
425
|
+
* @typedef {{[key: string]: string}} XmlnsAttributeObject
|
|
426
|
+
*/
|
|
427
|
+
|
|
428
|
+
/**
|
|
429
|
+
* @typedef {null|XmlnsAttributeObject} XmlnsAttributeValue
|
|
430
|
+
*/
|
|
431
|
+
|
|
432
|
+
/**
|
|
433
|
+
* @typedef {{
|
|
434
|
+
* [key: string]: string|number|null|DatasetAttributeObject
|
|
435
|
+
* }} DatasetAttributeObject
|
|
436
|
+
*/
|
|
437
|
+
|
|
438
|
+
/**
|
|
439
|
+
* @typedef {string|undefined|{[key: string]: string|null}} StyleAttributeValue
|
|
440
|
+
*/
|
|
441
|
+
|
|
442
|
+
/**
|
|
443
|
+
* @typedef {(this: Element, event?: Event) => void} EventHandler
|
|
444
|
+
*/
|
|
401
445
|
|
|
402
446
|
/**
|
|
403
|
-
* @typedef {
|
|
404
|
-
*
|
|
447
|
+
* @typedef {{
|
|
448
|
+
* [key: string]: EventHandler|[EventHandler, boolean]
|
|
449
|
+
* }} OnAttributeObject
|
|
450
|
+
*/
|
|
451
|
+
|
|
452
|
+
/**
|
|
453
|
+
* @typedef {{
|
|
454
|
+
* $on?: OnAttributeObject|null
|
|
455
|
+
* }} OnAttribute
|
|
456
|
+
*/
|
|
457
|
+
|
|
458
|
+
/**
|
|
459
|
+
* @typedef {boolean} BooleanAttribute
|
|
460
|
+
*/
|
|
461
|
+
|
|
462
|
+
/**
|
|
463
|
+
* @typedef {((this: Element, event?: Event) => void)} HandlerAttributeValue
|
|
464
|
+
*/
|
|
465
|
+
|
|
466
|
+
/* eslint-disable jsdoc/valid-types -- jsdoc-type-pratt-parser Bug */
|
|
467
|
+
/**
|
|
468
|
+
* @typedef {{
|
|
469
|
+
* [key: string]: HandlerAttributeValue
|
|
470
|
+
* }} OnHandlerObject
|
|
471
|
+
*/
|
|
472
|
+
|
|
473
|
+
/**
|
|
474
|
+
* @typedef {number} StringifiableNumber
|
|
475
|
+
*/
|
|
476
|
+
|
|
477
|
+
/**
|
|
478
|
+
* @typedef {{
|
|
479
|
+
* name: string,
|
|
480
|
+
* systemId?: string,
|
|
481
|
+
* publicId?: string
|
|
482
|
+
* }} JamilihDocumentType
|
|
483
|
+
*/
|
|
484
|
+
|
|
485
|
+
/**
|
|
486
|
+
* @typedef {string|{extends?: string}} DefineOptions
|
|
487
|
+
*/
|
|
488
|
+
|
|
489
|
+
/**
|
|
490
|
+
* @typedef {{[key: string]: string|number|boolean|((this: DefineMixin, ...args: any[]) => any)}} DefineMixin
|
|
491
|
+
*/
|
|
492
|
+
|
|
493
|
+
/**
|
|
494
|
+
* @typedef {{
|
|
495
|
+
* new (): HTMLElement;
|
|
496
|
+
* prototype: HTMLElement & {[key: string]: any}
|
|
497
|
+
* }} DefineConstructor
|
|
498
|
+
*/
|
|
499
|
+
/* eslint-enable jsdoc/valid-types -- https://github.com/jsdoc-type-pratt-parser/jsdoc-type-pratt-parser/issues/131 */
|
|
500
|
+
|
|
501
|
+
/**
|
|
502
|
+
* @typedef {(this: HTMLElement) => void} DefineUserConstructor
|
|
503
|
+
*/
|
|
504
|
+
|
|
505
|
+
/**
|
|
506
|
+
* @typedef {[DefineConstructor|DefineUserConstructor|DefineMixin, DefineOptions?]|[DefineConstructor|DefineUserConstructor, DefineMixin?, DefineOptions?]} DefineObjectArray
|
|
507
|
+
*/
|
|
508
|
+
|
|
509
|
+
/**
|
|
510
|
+
* @typedef {DefineObjectArray|DefineConstructor|DefineMixin|DefineUserConstructor} DefineObject
|
|
511
|
+
*/
|
|
512
|
+
|
|
513
|
+
/**
|
|
514
|
+
* @typedef {{elem?: Element, [key: string]: any}} SymbolObject
|
|
515
|
+
*/
|
|
516
|
+
|
|
517
|
+
/**
|
|
518
|
+
* @typedef {[symbol|string, ((this: Element, ...args: any[]) => any)|SymbolObject]} SymbolArray
|
|
519
|
+
*/
|
|
520
|
+
|
|
521
|
+
/**
|
|
522
|
+
* @typedef {null|undefined} NullableAttributeValue
|
|
523
|
+
*/
|
|
524
|
+
|
|
525
|
+
/**
|
|
526
|
+
* @typedef {(string|NullableAttributeValue|BooleanAttribute|
|
|
527
|
+
* JamilihArray|JamilihShadowRootObject|StringifiableNumber|
|
|
528
|
+
* JamilihDocumentType|JamilihDocument|XmlnsAttributeValue|
|
|
529
|
+
* OnAttributeObject|
|
|
530
|
+
* HandlerAttributeValue|DefineObject|SymbolArray|PluginReference
|
|
531
|
+
* )} JamilihAttValue
|
|
532
|
+
*/
|
|
533
|
+
|
|
534
|
+
/**
|
|
535
|
+
* @typedef {{
|
|
536
|
+
* [key: string]: string|number|((this: Element, ...args: any[]) => any)
|
|
537
|
+
* }} DataAttributeObject
|
|
405
538
|
*/
|
|
406
539
|
|
|
407
540
|
/**
|
|
408
|
-
* @
|
|
409
|
-
*
|
|
410
|
-
*
|
|
541
|
+
* @typedef {{
|
|
542
|
+
* $data?: true|string[]|Map<any, any>|WeakMap<any, any>|DataAttributeObject|
|
|
543
|
+
* [undefined, DataAttributeObject]|
|
|
544
|
+
* [Map<any, any>|WeakMap<any, any>|undefined, DataAttributeObject]
|
|
545
|
+
* }} DataAttribute
|
|
546
|
+
*/
|
|
547
|
+
|
|
548
|
+
/**
|
|
549
|
+
* @typedef {{
|
|
550
|
+
* dataset?: DatasetAttributeObject
|
|
551
|
+
* }} DatasetAttribute
|
|
552
|
+
*/
|
|
553
|
+
|
|
554
|
+
/**
|
|
555
|
+
* @typedef {{
|
|
556
|
+
* style?: StyleAttributeValue
|
|
557
|
+
* }} StyleAttribute
|
|
558
|
+
*/
|
|
559
|
+
|
|
560
|
+
/**
|
|
561
|
+
* @typedef {{
|
|
562
|
+
* $shadow?: JamilihShadowRootObject
|
|
563
|
+
* }} JamilihShadowRootAttribute
|
|
564
|
+
*/
|
|
565
|
+
|
|
566
|
+
/* eslint-disable jsdoc/valid-types -- jsdoc-type-pratt-parser Bug */
|
|
567
|
+
/**
|
|
568
|
+
* @typedef {{
|
|
569
|
+
* is?: string|null,
|
|
570
|
+
* $define?: DefineObject
|
|
571
|
+
* }} DefineAttribute
|
|
572
|
+
*/
|
|
573
|
+
/* eslint-enable jsdoc/valid-types -- jsdoc-type-pratt-parser Bug */
|
|
574
|
+
|
|
575
|
+
/**
|
|
576
|
+
* @typedef {{
|
|
577
|
+
* $custom?: {[key: string]: any}
|
|
578
|
+
* }} CustomAttribute
|
|
579
|
+
*/
|
|
580
|
+
|
|
581
|
+
/**
|
|
582
|
+
* @typedef {{
|
|
583
|
+
* $symbol?: SymbolArray
|
|
584
|
+
* }} SymbolAttribute
|
|
585
|
+
*/
|
|
586
|
+
|
|
587
|
+
/**
|
|
588
|
+
* @typedef {{
|
|
589
|
+
* xmlns?: string|null|XmlnsAttributeObject
|
|
590
|
+
* }} XmlnsAttribute
|
|
591
|
+
*/
|
|
592
|
+
|
|
593
|
+
/**
|
|
594
|
+
* `OnHandlerObject &` wasn't working, so added `HandlerAttributeValue`.
|
|
595
|
+
* @typedef {DataAttribute & StyleAttribute & JamilihShadowRootAttribute &
|
|
596
|
+
* DefineAttribute & DatasetAttribute & CustomAttribute & SymbolAttribute &
|
|
597
|
+
* OnAttribute & XmlnsAttribute &
|
|
598
|
+
* Partial<JamilihAttributeNode> & Partial<JamilihTextNode> &
|
|
599
|
+
* Partial<JamilihDoc> & Partial<JamilihDoctype> & {
|
|
600
|
+
* [key: string]: JamilihAttValue|HandlerAttributeValue,
|
|
601
|
+
* }} JamilihAttributes
|
|
602
|
+
*/
|
|
603
|
+
|
|
604
|
+
/**
|
|
605
|
+
* @typedef {{
|
|
606
|
+
* title?: string,
|
|
607
|
+
* childNodes?: JamilihChildType[],
|
|
608
|
+
* $DOCTYPE?: JamilihDocumentType,
|
|
609
|
+
* head?: JamilihChildren
|
|
610
|
+
* body?: JamilihChildren
|
|
611
|
+
* }} JamilihDocument
|
|
612
|
+
*/
|
|
613
|
+
|
|
614
|
+
/**
|
|
615
|
+
* @typedef {{
|
|
616
|
+
* $document: JamilihDocument
|
|
617
|
+
* }} JamilihDoc
|
|
618
|
+
*/
|
|
619
|
+
|
|
620
|
+
/**
|
|
621
|
+
* @typedef {{$DOCTYPE: JamilihDocumentType}} JamilihDoctype
|
|
622
|
+
*/
|
|
623
|
+
|
|
624
|
+
/**
|
|
625
|
+
* @typedef {{'#': (JamilihArray|TextNodeString|Element)[]}} JamilihDocumentFragment
|
|
626
|
+
*/
|
|
627
|
+
|
|
628
|
+
/**
|
|
629
|
+
* @typedef {string} ElementName
|
|
630
|
+
*/
|
|
631
|
+
|
|
632
|
+
/**
|
|
633
|
+
* @typedef {string} TextNodeString
|
|
634
|
+
*/
|
|
635
|
+
|
|
636
|
+
/**
|
|
637
|
+
* @typedef {{[key: string]: string}} PluginReference
|
|
638
|
+
*/
|
|
639
|
+
|
|
640
|
+
/**
|
|
641
|
+
* @typedef {(
|
|
642
|
+
* JamilihArray|TextNodeString|Element|Comment|ProcessingInstruction|
|
|
643
|
+
* Text|DocumentFragment|JamilihProcessingInstruction|JamilihDocumentFragment|
|
|
644
|
+
* PluginReference
|
|
645
|
+
* )[]} JamilihChildren
|
|
646
|
+
*/
|
|
647
|
+
|
|
648
|
+
/**
|
|
649
|
+
* @typedef {Document|ElementName|Element|DocumentFragment|
|
|
650
|
+
* JamilihDocumentFragment|JamilihDoc|JamilihDoctype|JamilihTextNode|
|
|
651
|
+
* JamilihAttributeNode} JamilihFirstArgument
|
|
652
|
+
*/
|
|
653
|
+
|
|
654
|
+
/**
|
|
655
|
+
* This would be clearer with overrides, but using as typedef.
|
|
656
|
+
*
|
|
657
|
+
* The optional 0th argument is an Jamilih options object or fragment.
|
|
658
|
+
*
|
|
659
|
+
* The first argument is the element to create (by lower-case name) or DOM element.
|
|
660
|
+
*
|
|
661
|
+
* The second optional argument are attributes to add with the key as the
|
|
662
|
+
* attribute name and value as the attribute value.
|
|
663
|
+
* The third optional argument are an array of children for this element
|
|
664
|
+
* (but raw DOM elements are required to be specified within arrays since
|
|
665
|
+
* could not otherwise be distinguished from siblings being added).
|
|
666
|
+
* The fourth optional argument are a sequence of sibling Elements, represented
|
|
667
|
+
* as DOM elements, or string/attributes/children sequences.
|
|
668
|
+
* The fifth optional argument is the parent to which to attach the element
|
|
669
|
+
* (always the last unless followed by null, in which case it is the
|
|
670
|
+
* second-to-last).
|
|
671
|
+
* The sixth last optional argument is null, used to indicate an array of elements
|
|
672
|
+
* should be returned.
|
|
673
|
+
* @typedef {[
|
|
674
|
+
* JamilihOptions|JamilihFirstArgument,
|
|
675
|
+
* (JamilihFirstArgument|
|
|
676
|
+
* JamilihAttributes|
|
|
677
|
+
* JamilihChildren|
|
|
678
|
+
* Element|ShadowRoot|
|
|
679
|
+
* null)?,
|
|
680
|
+
* (JamilihAttributes|
|
|
681
|
+
* JamilihChildren|
|
|
682
|
+
* Element|ShadowRoot|
|
|
683
|
+
* ElementName|null)?,
|
|
684
|
+
* ...(JamilihAttributes|
|
|
685
|
+
* JamilihChildren|
|
|
686
|
+
* Element|ShadowRoot|
|
|
687
|
+
* ElementName|null)[]
|
|
688
|
+
* ]} JamilihArray
|
|
689
|
+
*/
|
|
690
|
+
|
|
691
|
+
/**
|
|
692
|
+
* @typedef {[
|
|
693
|
+
* (string|Element|ShadowRoot), (JamilihArray[]|JamilihAttributes|Element|ShadowRoot|null)?, ...(JamilihArray[]|Element|JamilihAttributes|ShadowRoot|null)[]
|
|
694
|
+
* ]} JamilihArrayPostOptions
|
|
695
|
+
*/
|
|
696
|
+
|
|
697
|
+
/**
|
|
698
|
+
* @typedef {{
|
|
699
|
+
* root: [Map<Element,any>|WeakMap<Element,any>, any],
|
|
700
|
+
* [key: string]: [Map<Element,any>|WeakMap<Element,any>, any]
|
|
701
|
+
* }} MapWithRoot
|
|
702
|
+
*/
|
|
703
|
+
|
|
704
|
+
/**
|
|
705
|
+
* @typedef {"root"|"attributeValue"|"element"|"fragment"|"children"|"fragmentChildren"} TraversalState
|
|
706
|
+
*/
|
|
707
|
+
|
|
708
|
+
/**
|
|
709
|
+
* @typedef {object} JamilihOptions
|
|
710
|
+
* @property {TraversalState} [$state]
|
|
711
|
+
* @property {JamilihPlugin[]} [$plugins]
|
|
712
|
+
* @property {MapWithRoot|[Map<Element,any>|WeakMap<Element,any>, any]} [$map]
|
|
713
|
+
*/
|
|
714
|
+
|
|
715
|
+
/**
|
|
716
|
+
* @param {Document|Element|DocumentFragment} elem
|
|
717
|
+
* @param {string|null} att
|
|
718
|
+
* @param {JamilihAttValue} attVal
|
|
411
719
|
* @param {JamilihOptions} opts
|
|
412
|
-
* @
|
|
720
|
+
* @param {TraversalState} [state]
|
|
721
|
+
* @returns {string|null}
|
|
413
722
|
*/
|
|
414
|
-
function checkPluginValue(elem, att, attVal, opts) {
|
|
415
|
-
opts.$state = 'attributeValue';
|
|
723
|
+
function checkPluginValue(elem, att, attVal, opts, state) {
|
|
724
|
+
opts.$state = state !== null && state !== void 0 ? state : 'attributeValue';
|
|
416
725
|
if (attVal && typeof attVal === 'object') {
|
|
417
726
|
const matchingPlugin = getMatchingPlugin(opts, Object.keys(attVal)[0]);
|
|
418
727
|
if (matchingPlugin) {
|
|
@@ -426,17 +735,18 @@ function checkPluginValue(elem, att, attVal, opts) {
|
|
|
426
735
|
});
|
|
427
736
|
}
|
|
428
737
|
}
|
|
429
|
-
return attVal
|
|
738
|
+
return (/** @type {string} */attVal
|
|
739
|
+
);
|
|
430
740
|
}
|
|
431
741
|
|
|
432
742
|
/**
|
|
433
743
|
* @param {JamilihOptions} opts
|
|
434
|
-
* @param {string}
|
|
435
|
-
* @returns {JamilihPlugin}
|
|
744
|
+
* @param {string} pluginName
|
|
745
|
+
* @returns {JamilihPlugin|undefined}
|
|
436
746
|
*/
|
|
437
|
-
function getMatchingPlugin(opts,
|
|
747
|
+
function getMatchingPlugin(opts, pluginName) {
|
|
438
748
|
return opts.$plugins && opts.$plugins.find(p => {
|
|
439
|
-
return p.name ===
|
|
749
|
+
return p.name === pluginName;
|
|
440
750
|
});
|
|
441
751
|
}
|
|
442
752
|
|
|
@@ -444,29 +754,47 @@ function getMatchingPlugin(opts, item) {
|
|
|
444
754
|
* Creates an XHTML or HTML element (XHTML is preferred, but only in browsers
|
|
445
755
|
* that support); any element after element can be omitted, and any subsequent
|
|
446
756
|
* type or types added afterwards.
|
|
447
|
-
* @param {
|
|
757
|
+
* @param {JamilihArray} args
|
|
448
758
|
* @returns {JamilihReturn} The newly created (and possibly already appended)
|
|
449
759
|
* element or array of elements
|
|
450
760
|
*/
|
|
451
761
|
const jml = function jml(...args) {
|
|
762
|
+
if (!win) {
|
|
763
|
+
throw new Error('No window object');
|
|
764
|
+
}
|
|
765
|
+
if (!doc) {
|
|
766
|
+
throw new Error('No document object');
|
|
767
|
+
}
|
|
768
|
+
|
|
769
|
+
/** @type {(Document|DocumentFragment|Element) & {[key: string]: any}} */
|
|
452
770
|
let elem = doc.createDocumentFragment();
|
|
453
771
|
/**
|
|
454
772
|
*
|
|
455
|
-
* @param {
|
|
773
|
+
* @param {JamilihAttributes} atts
|
|
456
774
|
* @throws {TypeError}
|
|
457
775
|
* @returns {void}
|
|
458
776
|
*/
|
|
459
777
|
function _checkAtts(atts) {
|
|
778
|
+
if (!doc) {
|
|
779
|
+
throw new Error('No document object');
|
|
780
|
+
}
|
|
460
781
|
for (let [att, attVal] of Object.entries(atts)) {
|
|
461
|
-
|
|
782
|
+
var _ATTR_MAP$get;
|
|
783
|
+
att = (_ATTR_MAP$get = ATTR_MAP.get(att)) !== null && _ATTR_MAP$get !== void 0 ? _ATTR_MAP$get : att;
|
|
784
|
+
|
|
785
|
+
/**
|
|
786
|
+
* @typedef {any} ElementExpando
|
|
787
|
+
*/
|
|
788
|
+
|
|
462
789
|
if (NULLABLES.includes(att)) {
|
|
463
|
-
attVal = checkPluginValue(elem, att, attVal, opts);
|
|
790
|
+
attVal = checkPluginValue(elem, att, /** @type {string|JamilihArray} */attVal, opts);
|
|
464
791
|
if (!_isNullish(attVal)) {
|
|
465
|
-
elem[att] = attVal;
|
|
792
|
+
/** @type {ElementExpando} */elem[att] = attVal;
|
|
466
793
|
}
|
|
467
794
|
continue;
|
|
468
795
|
} else if (ATTR_DOM.includes(att)) {
|
|
469
|
-
attVal = checkPluginValue(elem, att, attVal, opts);
|
|
796
|
+
attVal = checkPluginValue(elem, att, /** @type {string|JamilihArray} */attVal, opts);
|
|
797
|
+
/** @type {ElementExpando} */
|
|
470
798
|
elem[att] = attVal;
|
|
471
799
|
continue;
|
|
472
800
|
}
|
|
@@ -484,8 +812,8 @@ const jml = function jml(...args) {
|
|
|
484
812
|
case '#':
|
|
485
813
|
{
|
|
486
814
|
// Document fragment
|
|
487
|
-
opts.$state = '
|
|
488
|
-
nodes[nodes.length] = jml(opts, attVal);
|
|
815
|
+
opts.$state = 'fragmentChildren';
|
|
816
|
+
nodes[nodes.length] = jml(opts, /** @type {JamilihArray[]} */attVal);
|
|
489
817
|
break;
|
|
490
818
|
}
|
|
491
819
|
case '$shadow':
|
|
@@ -493,24 +821,38 @@ const jml = function jml(...args) {
|
|
|
493
821
|
const {
|
|
494
822
|
open,
|
|
495
823
|
closed
|
|
496
|
-
} = attVal;
|
|
824
|
+
} = /** @type {JamilihShadowRootObject} */attVal;
|
|
497
825
|
let {
|
|
498
826
|
content,
|
|
499
827
|
template
|
|
500
|
-
} = attVal;
|
|
501
|
-
const shadowRoot = elem.attachShadow({
|
|
828
|
+
} = /** @type {JamilihShadowRootObject} */attVal;
|
|
829
|
+
const shadowRoot = /** @type {Element} */elem.attachShadow({
|
|
502
830
|
mode: closed || open === false ? 'closed' : 'open'
|
|
503
831
|
});
|
|
504
832
|
if (template) {
|
|
505
833
|
if (Array.isArray(template)) {
|
|
506
|
-
template =
|
|
834
|
+
template = /** @type {HTMLTemplateElement} */
|
|
835
|
+
_getType(template[0]) === 'object' ? jml('template', ...
|
|
836
|
+
/**
|
|
837
|
+
* @type {[
|
|
838
|
+
* JamilihAttributes, ...(JamilihArray[]|Element)[]
|
|
839
|
+
* ]}
|
|
840
|
+
*/
|
|
841
|
+
template, doc.body) : jml('template',
|
|
842
|
+
/**
|
|
843
|
+
* @type {JamilihArray[]|Element}
|
|
844
|
+
*/
|
|
845
|
+
template, doc.body);
|
|
507
846
|
} else if (typeof template === 'string') {
|
|
508
|
-
template =
|
|
847
|
+
template = /** @type {HTMLTemplateElement} */$(template);
|
|
509
848
|
}
|
|
510
|
-
jml(
|
|
849
|
+
jml( /** @type {HTMLTemplateElement} */
|
|
850
|
+
/** @type {HTMLTemplateElement} */template.content.cloneNode(true), shadowRoot);
|
|
511
851
|
} else {
|
|
512
852
|
if (!content) {
|
|
513
|
-
|
|
853
|
+
if (open !== true) {
|
|
854
|
+
content = open || typeof closed === 'boolean' ? content : closed;
|
|
855
|
+
}
|
|
514
856
|
}
|
|
515
857
|
if (content && typeof content !== 'boolean') {
|
|
516
858
|
if (Array.isArray(content)) {
|
|
@@ -540,9 +882,11 @@ const jml = function jml(...args) {
|
|
|
540
882
|
Object.assign(elem, attVal);
|
|
541
883
|
break;
|
|
542
884
|
}
|
|
543
|
-
/* istanbul ignore next */
|
|
544
885
|
case '$define':
|
|
545
886
|
{
|
|
887
|
+
if (!('localName' in elem)) {
|
|
888
|
+
throw new Error('Element expected for `$define`');
|
|
889
|
+
}
|
|
546
890
|
const localName = elem.localName.toLowerCase();
|
|
547
891
|
// Note: customized built-ins sadly not working yet
|
|
548
892
|
const customizedBuiltIn = !localName.includes('-');
|
|
@@ -553,7 +897,7 @@ const jml = function jml(...args) {
|
|
|
553
897
|
if (customizedBuiltIn) {
|
|
554
898
|
is = elem.getAttribute('is');
|
|
555
899
|
if (!is) {
|
|
556
|
-
if (!
|
|
900
|
+
if (!Object.hasOwn(atts, 'is')) {
|
|
557
901
|
throw new TypeError(`Expected \`is\` with \`$define\` on built-in; args: ${JSON.stringify(args)}`);
|
|
558
902
|
}
|
|
559
903
|
atts.is = checkPluginValue(elem, 'is', atts.is, opts);
|
|
@@ -563,12 +907,20 @@ const jml = function jml(...args) {
|
|
|
563
907
|
} = atts);
|
|
564
908
|
}
|
|
565
909
|
}
|
|
566
|
-
const def = customizedBuiltIn ? is : localName;
|
|
910
|
+
const def = customizedBuiltIn ? /** @type {string} */is : localName;
|
|
567
911
|
if (window.customElements.get(def)) {
|
|
568
912
|
break;
|
|
569
913
|
}
|
|
914
|
+
|
|
915
|
+
/**
|
|
916
|
+
* @param {DefineUserConstructor} [cnstrct]
|
|
917
|
+
* @returns {DefineConstructor}
|
|
918
|
+
*/
|
|
570
919
|
const getConstructor = cnstrct => {
|
|
571
|
-
|
|
920
|
+
if (!doc) {
|
|
921
|
+
throw new Error('No document object');
|
|
922
|
+
}
|
|
923
|
+
const baseClass = typeof options === 'object' && typeof options.extends === 'string' ? /** @type {typeof HTMLElement} */doc.createElement(options.extends).constructor : customizedBuiltIn ? /** @type {typeof HTMLElement} */doc.createElement(localName).constructor : window.HTMLElement;
|
|
572
924
|
|
|
573
925
|
/**
|
|
574
926
|
* Class wrapping base class.
|
|
@@ -579,14 +931,24 @@ const jml = function jml(...args) {
|
|
|
579
931
|
*/
|
|
580
932
|
constructor() {
|
|
581
933
|
super();
|
|
934
|
+
/** @type {DefineUserConstructor} */
|
|
582
935
|
cnstrct.call(this);
|
|
583
936
|
}
|
|
584
937
|
} : class extends baseClass {};
|
|
585
938
|
};
|
|
586
|
-
|
|
587
|
-
|
|
588
|
-
|
|
589
|
-
|
|
939
|
+
|
|
940
|
+
/** @type {DefineConstructor|DefineUserConstructor|DefineMixin} */
|
|
941
|
+
let cnstrctr;
|
|
942
|
+
|
|
943
|
+
/**
|
|
944
|
+
* @type {DefineOptions|undefined}
|
|
945
|
+
*/
|
|
946
|
+
let options;
|
|
947
|
+
let mixin;
|
|
948
|
+
const defineObj = /** @type {DefineObject} */attVal;
|
|
949
|
+
if (Array.isArray(defineObj)) {
|
|
950
|
+
if (defineObj.length <= 2) {
|
|
951
|
+
[cnstrctr, options] = defineObj;
|
|
590
952
|
if (typeof options === 'string') {
|
|
591
953
|
// Todo: Allow creating a definition without using it;
|
|
592
954
|
// that may be the only reason to have a string here which
|
|
@@ -594,7 +956,7 @@ const jml = function jml(...args) {
|
|
|
594
956
|
options = {
|
|
595
957
|
extends: options
|
|
596
958
|
};
|
|
597
|
-
} else if (options && !
|
|
959
|
+
} else if (options && !Object.hasOwn(options, 'extends')) {
|
|
598
960
|
mixin = options;
|
|
599
961
|
}
|
|
600
962
|
if (typeof cnstrctr === 'object') {
|
|
@@ -602,21 +964,21 @@ const jml = function jml(...args) {
|
|
|
602
964
|
cnstrctr = getConstructor();
|
|
603
965
|
}
|
|
604
966
|
} else {
|
|
605
|
-
[cnstrctr, mixin, options] =
|
|
967
|
+
[cnstrctr, mixin, options] = defineObj;
|
|
606
968
|
if (typeof options === 'string') {
|
|
607
969
|
options = {
|
|
608
970
|
extends: options
|
|
609
971
|
};
|
|
610
972
|
}
|
|
611
973
|
}
|
|
612
|
-
} else if (typeof
|
|
613
|
-
cnstrctr =
|
|
974
|
+
} else if (typeof defineObj === 'function') {
|
|
975
|
+
cnstrctr = /** @type {DefineConstructor} */defineObj;
|
|
614
976
|
} else {
|
|
615
|
-
mixin =
|
|
977
|
+
mixin = defineObj;
|
|
616
978
|
cnstrctr = getConstructor();
|
|
617
979
|
}
|
|
618
980
|
if (!cnstrctr.toString().startsWith('class')) {
|
|
619
|
-
cnstrctr = getConstructor(cnstrctr);
|
|
981
|
+
cnstrctr = getConstructor( /** @type {DefineUserConstructor} */cnstrctr);
|
|
620
982
|
}
|
|
621
983
|
if (!options && customizedBuiltIn) {
|
|
622
984
|
options = {
|
|
@@ -625,29 +987,33 @@ const jml = function jml(...args) {
|
|
|
625
987
|
}
|
|
626
988
|
if (mixin) {
|
|
627
989
|
Object.entries(mixin).forEach(([methodName, method]) => {
|
|
628
|
-
cnstrctr.prototype[methodName] = method;
|
|
990
|
+
/** @type {DefineConstructor} */cnstrctr.prototype[methodName] = method;
|
|
629
991
|
});
|
|
630
992
|
}
|
|
631
993
|
// console.log('def', def, '::', typeof options === 'object' ? options : undefined);
|
|
632
|
-
window.customElements.define(def, cnstrctr, typeof options === 'object' ? options : undefined);
|
|
994
|
+
window.customElements.define(def, /** @type {DefineConstructor} */cnstrctr, typeof options === 'object' ? options : undefined);
|
|
633
995
|
break;
|
|
634
996
|
}
|
|
635
997
|
case '$symbol':
|
|
636
998
|
{
|
|
637
|
-
const [symbol, func] = attVal;
|
|
999
|
+
const [symbol, func] = /** @type {SymbolArray} */attVal;
|
|
638
1000
|
if (typeof func === 'function') {
|
|
639
|
-
const funcBound = func.bind(elem);
|
|
1001
|
+
const funcBound = func.bind( /** @type {Element} */elem);
|
|
640
1002
|
if (typeof symbol === 'string') {
|
|
1003
|
+
// @ts-expect-error
|
|
641
1004
|
elem[Symbol.for(symbol)] = funcBound;
|
|
642
1005
|
} else {
|
|
1006
|
+
// @ts-expect-error
|
|
643
1007
|
elem[symbol] = funcBound;
|
|
644
1008
|
}
|
|
645
1009
|
} else {
|
|
646
1010
|
const obj = func;
|
|
647
|
-
obj.elem = elem;
|
|
1011
|
+
obj.elem = /** @type {Element} */elem;
|
|
648
1012
|
if (typeof symbol === 'string') {
|
|
1013
|
+
// @ts-expect-error
|
|
649
1014
|
elem[Symbol.for(symbol)] = obj;
|
|
650
1015
|
} else {
|
|
1016
|
+
// @ts-expect-error
|
|
651
1017
|
elem[symbol] = obj;
|
|
652
1018
|
}
|
|
653
1019
|
}
|
|
@@ -655,72 +1021,90 @@ const jml = function jml(...args) {
|
|
|
655
1021
|
}
|
|
656
1022
|
case '$data':
|
|
657
1023
|
{
|
|
658
|
-
setMap(
|
|
1024
|
+
setMap( /** @type {true|string[]|Map<any, any>|WeakMap<any, any>|DataAttributeObject} */
|
|
1025
|
+
attVal);
|
|
659
1026
|
break;
|
|
660
1027
|
}
|
|
661
1028
|
case '$attribute':
|
|
662
1029
|
{
|
|
663
1030
|
// Attribute node
|
|
664
|
-
const
|
|
665
|
-
node
|
|
1031
|
+
const attr = /** @type {JamilihAttributeNodeValue} */attVal;
|
|
1032
|
+
const node = attr.length === 3 ? doc.createAttributeNS(attr[0], attr[1]) : doc.createAttribute( /** @type {string} */attr[0]);
|
|
1033
|
+
node.value = /** @type {string} */attr[attr.length - 1];
|
|
666
1034
|
nodes[nodes.length] = node;
|
|
667
1035
|
break;
|
|
668
1036
|
}
|
|
669
1037
|
case '$text':
|
|
670
1038
|
{
|
|
671
1039
|
// Todo: Also allow as jml(['a text node']) (or should that become a fragment)?
|
|
672
|
-
const node = doc.createTextNode(attVal);
|
|
1040
|
+
const node = doc.createTextNode( /** @type {string} */attVal);
|
|
673
1041
|
nodes[nodes.length] = node;
|
|
674
1042
|
break;
|
|
675
1043
|
}
|
|
676
1044
|
case '$document':
|
|
677
1045
|
{
|
|
678
1046
|
// Todo: Conditionally create XML document
|
|
679
|
-
const
|
|
680
|
-
if (attVal
|
|
1047
|
+
const docNode = doc.implementation.createHTMLDocument();
|
|
1048
|
+
if (!attVal) {
|
|
1049
|
+
throw new Error('Bad attribute value');
|
|
1050
|
+
}
|
|
1051
|
+
const jamlihDoc = /** @type {JamilihDocument} */attVal;
|
|
1052
|
+
if (jamlihDoc.childNodes) {
|
|
681
1053
|
// Remove any extra nodes created by createHTMLDocument().
|
|
682
|
-
const j =
|
|
683
|
-
while (
|
|
684
|
-
const cn =
|
|
1054
|
+
const j = jamlihDoc.childNodes.length;
|
|
1055
|
+
while (docNode.childNodes[j]) {
|
|
1056
|
+
const cn = docNode.childNodes[j];
|
|
685
1057
|
cn.remove();
|
|
686
1058
|
// `j` should stay the same as removing will cause node to be present
|
|
687
1059
|
}
|
|
688
1060
|
|
|
689
|
-
|
|
1061
|
+
jamlihDoc.childNodes.forEach(_childrenToJML(docNode));
|
|
690
1062
|
} else {
|
|
691
|
-
if (
|
|
1063
|
+
if (jamlihDoc.$DOCTYPE) {
|
|
1064
|
+
var _docNode$firstChild;
|
|
692
1065
|
const dt = {
|
|
693
|
-
$DOCTYPE:
|
|
1066
|
+
$DOCTYPE: jamlihDoc.$DOCTYPE
|
|
694
1067
|
};
|
|
695
1068
|
const doctype = jml(dt);
|
|
696
|
-
|
|
1069
|
+
(_docNode$firstChild = docNode.firstChild) === null || _docNode$firstChild === void 0 ? void 0 : _docNode$firstChild.replaceWith(doctype);
|
|
697
1070
|
}
|
|
698
|
-
const html =
|
|
699
|
-
const head = html.
|
|
700
|
-
const body = html.
|
|
701
|
-
if (
|
|
1071
|
+
const html = docNode.querySelector('html');
|
|
1072
|
+
const head = html === null || html === void 0 ? void 0 : html.querySelector('head');
|
|
1073
|
+
const body = html === null || html === void 0 ? void 0 : html.querySelector('body');
|
|
1074
|
+
if (jamlihDoc.title || jamlihDoc.head) {
|
|
702
1075
|
const meta = doc.createElement('meta');
|
|
703
1076
|
// eslint-disable-next-line unicorn/text-encoding-identifier-case -- HTML
|
|
704
1077
|
meta.setAttribute('charset', 'utf-8');
|
|
705
|
-
head.append(meta);
|
|
706
|
-
if (
|
|
707
|
-
|
|
1078
|
+
head === null || head === void 0 ? void 0 : head.append(meta);
|
|
1079
|
+
if (jamlihDoc.title) {
|
|
1080
|
+
docNode.title = jamlihDoc.title; // Appends after meta
|
|
708
1081
|
}
|
|
709
1082
|
|
|
710
|
-
if (
|
|
711
|
-
|
|
1083
|
+
if (jamlihDoc.head && head) {
|
|
1084
|
+
// each child of `head` is:
|
|
1085
|
+
// (JamilihArray|TextNodeString|Element|Comment|ProcessingInstruction|
|
|
1086
|
+
// Text|DocumentFragment|JamilihProcessingInstruction|JamilihDocumentFragment)
|
|
1087
|
+
|
|
1088
|
+
// * @typedef {JamilihDoc|JamilihDoctype|JamilihTextNode|
|
|
1089
|
+
// * JamilihAttributeNode|JamilihOptions|ElementName|Element|
|
|
1090
|
+
// * JamilihDocumentFragment
|
|
1091
|
+
// * } JamilihFirstArg
|
|
1092
|
+
// appender childJML param is: JamilihArray|JamilihFirstArg
|
|
1093
|
+
|
|
1094
|
+
jamlihDoc.head.forEach(_appendJML(head));
|
|
712
1095
|
}
|
|
713
1096
|
}
|
|
714
|
-
if (
|
|
715
|
-
|
|
1097
|
+
if (jamlihDoc.body && body) {
|
|
1098
|
+
jamlihDoc.body.forEach(_appendJMLOrText(body));
|
|
716
1099
|
}
|
|
717
1100
|
}
|
|
718
|
-
nodes[nodes.length] =
|
|
1101
|
+
nodes[nodes.length] = docNode;
|
|
719
1102
|
break;
|
|
720
1103
|
}
|
|
721
1104
|
case '$DOCTYPE':
|
|
722
1105
|
{
|
|
723
|
-
const
|
|
1106
|
+
const doctype = /** @type {JamilihDocumentType} */attVal;
|
|
1107
|
+
const node = doc.implementation.createDocumentType(doctype.name, doctype.publicId || '', doctype.systemId || '');
|
|
724
1108
|
nodes[nodes.length] = node;
|
|
725
1109
|
break;
|
|
726
1110
|
}
|
|
@@ -728,21 +1112,21 @@ const jml = function jml(...args) {
|
|
|
728
1112
|
{
|
|
729
1113
|
// Events
|
|
730
1114
|
// Allow for no-op by defaulting to `{}`
|
|
731
|
-
for (let [p2, val] of Object.entries(attVal || {})) {
|
|
1115
|
+
for (let [p2, val] of Object.entries( /** @type {OnAttributeObject} */attVal || {})) {
|
|
732
1116
|
if (typeof val === 'function') {
|
|
733
1117
|
val = [val, false];
|
|
734
1118
|
}
|
|
735
1119
|
if (typeof val[0] !== 'function') {
|
|
736
1120
|
throw new TypeError(`Expect a function for \`$on\`; args: ${JSON.stringify(args)}`);
|
|
737
1121
|
}
|
|
738
|
-
_addEvent(elem, p2, val[0], val[1]); // element, event name, handler, capturing
|
|
1122
|
+
_addEvent( /** @type {Element} */elem, p2, val[0], val[1]); // element, event name, handler, capturing
|
|
739
1123
|
}
|
|
740
1124
|
|
|
741
1125
|
break;
|
|
742
1126
|
}
|
|
743
1127
|
case 'className':
|
|
744
1128
|
case 'class':
|
|
745
|
-
attVal = checkPluginValue(elem, att, attVal, opts);
|
|
1129
|
+
attVal = checkPluginValue(elem, att, /** @type {string} */attVal, opts);
|
|
746
1130
|
if (!_isNullish(attVal)) {
|
|
747
1131
|
elem.className = attVal;
|
|
748
1132
|
}
|
|
@@ -750,6 +1134,11 @@ const jml = function jml(...args) {
|
|
|
750
1134
|
case 'dataset':
|
|
751
1135
|
{
|
|
752
1136
|
// Map can be keyed with hyphenated or camel-cased properties
|
|
1137
|
+
/**
|
|
1138
|
+
* @param {DatasetAttributeObject} atVal
|
|
1139
|
+
* @param {string} startProp
|
|
1140
|
+
* @returns {void}
|
|
1141
|
+
*/
|
|
753
1142
|
const recurse = (atVal, startProp) => {
|
|
754
1143
|
let prop = '';
|
|
755
1144
|
const pastInitialProp = startProp !== '';
|
|
@@ -766,7 +1155,7 @@ const jml = function jml(...args) {
|
|
|
766
1155
|
recurse(value, prop);
|
|
767
1156
|
});
|
|
768
1157
|
};
|
|
769
|
-
recurse(attVal, '');
|
|
1158
|
+
recurse( /** @type {DatasetAttributeObject} */attVal, '');
|
|
770
1159
|
break;
|
|
771
1160
|
// Todo: Disable this by default unless configuration explicitly allows (for security)
|
|
772
1161
|
}
|
|
@@ -782,13 +1171,13 @@ const jml = function jml(...args) {
|
|
|
782
1171
|
case 'htmlFor':
|
|
783
1172
|
case 'for':
|
|
784
1173
|
if (elStr === 'label') {
|
|
785
|
-
attVal = checkPluginValue(elem, att, attVal, opts);
|
|
1174
|
+
attVal = checkPluginValue(elem, att, /** @type {string} */attVal, opts);
|
|
786
1175
|
if (!_isNullish(attVal)) {
|
|
787
1176
|
elem.htmlFor = attVal;
|
|
788
1177
|
}
|
|
789
1178
|
break;
|
|
790
1179
|
}
|
|
791
|
-
attVal = checkPluginValue(elem, att, attVal, opts);
|
|
1180
|
+
attVal = checkPluginValue(elem, att, /** @type {string} */attVal, opts);
|
|
792
1181
|
elem.setAttribute(att, attVal);
|
|
793
1182
|
break;
|
|
794
1183
|
case 'xmlns':
|
|
@@ -797,13 +1186,14 @@ const jml = function jml(...args) {
|
|
|
797
1186
|
default:
|
|
798
1187
|
{
|
|
799
1188
|
if (att.startsWith('on')) {
|
|
800
|
-
attVal = checkPluginValue(elem, att, attVal, opts);
|
|
1189
|
+
attVal = checkPluginValue(elem, att, /** @type {HandlerAttributeValue} */attVal, opts);
|
|
801
1190
|
elem[att] = attVal;
|
|
802
1191
|
// _addEvent(elem, att.slice(2), attVal, false); // This worked, but perhaps the user wishes only one event
|
|
803
1192
|
break;
|
|
804
1193
|
}
|
|
805
1194
|
if (att === 'style') {
|
|
806
|
-
attVal =
|
|
1195
|
+
attVal = /** @type {string} */
|
|
1196
|
+
checkPluginValue(elem, att, /** @type {StyleAttributeValue} */attVal, opts);
|
|
807
1197
|
if (_isNullish(attVal)) {
|
|
808
1198
|
break;
|
|
809
1199
|
}
|
|
@@ -834,36 +1224,46 @@ const jml = function jml(...args) {
|
|
|
834
1224
|
*/
|
|
835
1225
|
break;
|
|
836
1226
|
}
|
|
837
|
-
const
|
|
1227
|
+
const pluginName = att;
|
|
1228
|
+
const matchingPlugin = getMatchingPlugin(opts, pluginName);
|
|
838
1229
|
if (matchingPlugin) {
|
|
839
1230
|
matchingPlugin.set({
|
|
840
1231
|
opts,
|
|
841
1232
|
element: elem,
|
|
842
1233
|
attribute: {
|
|
843
|
-
name:
|
|
844
|
-
value: attVal
|
|
1234
|
+
name: pluginName,
|
|
1235
|
+
value: /** @type {PluginReference} */attVal
|
|
845
1236
|
}
|
|
846
1237
|
});
|
|
847
1238
|
break;
|
|
848
1239
|
}
|
|
849
|
-
attVal = checkPluginValue(elem, att, attVal, opts);
|
|
1240
|
+
attVal = checkPluginValue(elem, att, /** @type {string} */attVal, opts);
|
|
850
1241
|
elem.setAttribute(att, attVal);
|
|
851
1242
|
break;
|
|
852
1243
|
}
|
|
853
1244
|
}
|
|
854
1245
|
}
|
|
855
1246
|
}
|
|
1247
|
+
|
|
1248
|
+
/**
|
|
1249
|
+
* @type {JamilihReturn[]}
|
|
1250
|
+
*/
|
|
856
1251
|
const nodes = [];
|
|
1252
|
+
|
|
1253
|
+
/** @type {string} */
|
|
857
1254
|
let elStr;
|
|
1255
|
+
|
|
1256
|
+
/** @type {JamilihOptions} */
|
|
858
1257
|
let opts;
|
|
859
1258
|
let isRoot = false;
|
|
1259
|
+
let argStart = 0;
|
|
860
1260
|
if (_getType(args[0]) === 'object' && Object.keys(args[0]).some(key => possibleOptions.includes(key))) {
|
|
861
|
-
opts = args[0];
|
|
1261
|
+
opts = /** @type {JamilihOptions} */args[0];
|
|
862
1262
|
if (opts.$state === undefined) {
|
|
863
1263
|
isRoot = true;
|
|
864
1264
|
opts.$state = 'root';
|
|
865
1265
|
}
|
|
866
|
-
if (
|
|
1266
|
+
if (Array.isArray(opts.$map)) {
|
|
867
1267
|
opts.$map = {
|
|
868
1268
|
root: opts.$map
|
|
869
1269
|
};
|
|
@@ -884,51 +1284,57 @@ const jml = function jml(...args) {
|
|
|
884
1284
|
}
|
|
885
1285
|
});
|
|
886
1286
|
}
|
|
887
|
-
|
|
1287
|
+
argStart = 1;
|
|
888
1288
|
} else {
|
|
889
1289
|
opts = {
|
|
890
1290
|
$state: undefined
|
|
891
1291
|
};
|
|
892
1292
|
}
|
|
893
1293
|
const argc = args.length;
|
|
894
|
-
const defaultMap = opts.$map && opts.$map.root;
|
|
1294
|
+
const defaultMap = opts.$map && /** @type {MapWithRoot} */opts.$map.root;
|
|
1295
|
+
|
|
1296
|
+
/**
|
|
1297
|
+
* @param {true|string[]|Map<any, any>|WeakMap<any, any>|DataAttributeObject} dataVal
|
|
1298
|
+
* @returns {void}
|
|
1299
|
+
*/
|
|
895
1300
|
const setMap = dataVal => {
|
|
896
1301
|
let map, obj;
|
|
1302
|
+
const defMap = /** @type {[Map<Element, any> | WeakMap<Element, any>, any]} */defaultMap;
|
|
897
1303
|
// Boolean indicating use of default map and object
|
|
898
1304
|
if (dataVal === true) {
|
|
899
|
-
[map, obj] =
|
|
1305
|
+
[map, obj] = defMap;
|
|
900
1306
|
} else if (Array.isArray(dataVal)) {
|
|
901
1307
|
// Array of strings mapping to default
|
|
902
1308
|
if (typeof dataVal[0] === 'string') {
|
|
903
1309
|
dataVal.forEach(dVal => {
|
|
904
|
-
setMap(opts.$map[dVal]);
|
|
1310
|
+
setMap( /** @type {MapWithRoot} */opts.$map[dVal]);
|
|
905
1311
|
});
|
|
906
1312
|
return;
|
|
907
1313
|
// Array of Map and non-map data object
|
|
908
1314
|
}
|
|
909
1315
|
|
|
910
|
-
map = dataVal[0] ||
|
|
911
|
-
obj = dataVal[1] ||
|
|
1316
|
+
map = dataVal[0] || defMap[0];
|
|
1317
|
+
obj = dataVal[1] || defMap[1];
|
|
912
1318
|
// Map
|
|
913
1319
|
} else if (/^\[object (?:Weak)?Map\]$/u.test([].toString.call(dataVal))) {
|
|
914
1320
|
map = dataVal;
|
|
915
|
-
obj =
|
|
1321
|
+
obj = defMap[1];
|
|
916
1322
|
// Non-map data object
|
|
917
1323
|
} else {
|
|
918
|
-
map =
|
|
1324
|
+
map = defMap[0];
|
|
919
1325
|
obj = dataVal;
|
|
920
1326
|
}
|
|
921
|
-
|
|
1327
|
+
/** @type {Map<Element, any> | WeakMap<Element, any>} */
|
|
1328
|
+
map.set( /** @type {Element} */
|
|
1329
|
+
elem, obj);
|
|
922
1330
|
};
|
|
923
|
-
for (let i =
|
|
1331
|
+
for (let i = argStart; i < argc; i++) {
|
|
924
1332
|
let arg = args[i];
|
|
925
1333
|
const type = _getType(arg);
|
|
926
1334
|
switch (type) {
|
|
927
1335
|
case 'null':
|
|
928
1336
|
// null always indicates a place-holder (only needed for last argument if want array returned)
|
|
929
1337
|
if (i === argc - 1) {
|
|
930
|
-
_applyAnyStylesheet(nodes[0]); // We have to execute any stylesheets even if not appending or otherwise IE will never apply them
|
|
931
|
-
// Todo: Fix to allow application of stylesheets of style tags within fragments?
|
|
932
1338
|
return nodes.length <= 1 ? nodes[0]
|
|
933
1339
|
// eslint-disable-next-line unicorn/no-array-callback-reference
|
|
934
1340
|
: nodes.reduce(_fragReducer, doc.createDocumentFragment()); // nodes;
|
|
@@ -939,21 +1345,21 @@ const jml = function jml(...args) {
|
|
|
939
1345
|
// Strings normally indicate elements
|
|
940
1346
|
switch (arg) {
|
|
941
1347
|
case '!':
|
|
942
|
-
nodes[nodes.length] = doc.createComment(args[++i]);
|
|
1348
|
+
nodes[nodes.length] = doc.createComment( /** @type {string} */args[++i]);
|
|
943
1349
|
break;
|
|
944
1350
|
case '?':
|
|
945
1351
|
{
|
|
946
|
-
arg = args[++i];
|
|
947
|
-
let procValue = args[++i];
|
|
1352
|
+
arg = /** @type {string} */args[++i];
|
|
1353
|
+
let procValue = /** @type {string} */args[++i];
|
|
948
1354
|
const val = procValue;
|
|
949
1355
|
if (val && typeof val === 'object') {
|
|
950
|
-
|
|
1356
|
+
const procValues = [];
|
|
951
1357
|
for (const [p, procInstVal] of Object.entries(val)) {
|
|
952
|
-
|
|
1358
|
+
procValues.push(p + '=' + '"' +
|
|
953
1359
|
// https://www.w3.org/TR/xml-stylesheet/#NT-PseudoAttValue
|
|
954
1360
|
procInstVal.replace(/"/gu, '"') + '"');
|
|
955
1361
|
}
|
|
956
|
-
procValue =
|
|
1362
|
+
procValue = procValues.join(' ');
|
|
957
1363
|
}
|
|
958
1364
|
// Firefox allows instructions with ">" in this method, but not if placed directly!
|
|
959
1365
|
try {
|
|
@@ -971,7 +1377,8 @@ const jml = function jml(...args) {
|
|
|
971
1377
|
// Browsers don't support doc.createEntityReference, so we just use this as a convenience
|
|
972
1378
|
}
|
|
973
1379
|
case '&':
|
|
974
|
-
nodes[nodes.length] = _createSafeReference('entity', '',
|
|
1380
|
+
nodes[nodes.length] = _createSafeReference('entity', '', /** @type {string} */
|
|
1381
|
+
args[++i]);
|
|
975
1382
|
break;
|
|
976
1383
|
case '#':
|
|
977
1384
|
// // Decimal character reference - ['#', '01234'] // Ӓ // probably easier to use JavaScript Unicode escapes
|
|
@@ -979,16 +1386,18 @@ const jml = function jml(...args) {
|
|
|
979
1386
|
break;
|
|
980
1387
|
case '#x':
|
|
981
1388
|
// Hex character reference - ['#x', '123a'] // ሺ // probably easier to use JavaScript Unicode escapes
|
|
982
|
-
nodes[nodes.length] = _createSafeReference('hexadecimal', arg,
|
|
1389
|
+
nodes[nodes.length] = _createSafeReference('hexadecimal', arg, /** @type {string} */
|
|
1390
|
+
args[++i]);
|
|
983
1391
|
break;
|
|
984
1392
|
case '![':
|
|
985
1393
|
// '![', ['escaped <&> text'] // <![CDATA[escaped <&> text]]>
|
|
986
1394
|
// CDATA valid in XML only, so we'll just treat as text for mutual compatibility
|
|
987
1395
|
// Todo: config (or detection via some kind of doc.documentType property?) of whether in XML
|
|
988
1396
|
try {
|
|
989
|
-
nodes[nodes.length] = doc.createCDATASection(args[++i]);
|
|
1397
|
+
nodes[nodes.length] = doc.createCDATASection( /** @type {string} */args[++i]);
|
|
990
1398
|
} catch (e2) {
|
|
991
|
-
nodes[nodes.length] = doc.createTextNode(
|
|
1399
|
+
nodes[nodes.length] = doc.createTextNode( /** @type {string} */
|
|
1400
|
+
args[i]); // i already incremented
|
|
992
1401
|
}
|
|
993
1402
|
|
|
994
1403
|
break;
|
|
@@ -1000,19 +1409,21 @@ const jml = function jml(...args) {
|
|
|
1000
1409
|
default:
|
|
1001
1410
|
{
|
|
1002
1411
|
// An element
|
|
1003
|
-
elStr = arg;
|
|
1412
|
+
elStr = /** @type {string} */arg;
|
|
1004
1413
|
const atts = args[i + 1];
|
|
1005
|
-
if (_getType(atts) === 'object' && atts.is) {
|
|
1414
|
+
if (atts && _getType(atts) === 'object' && /** @type {JamilihAttributes} */atts.is) {
|
|
1006
1415
|
const {
|
|
1007
1416
|
is
|
|
1008
|
-
} = atts;
|
|
1009
|
-
|
|
1010
|
-
elem = doc.createElementNS
|
|
1011
|
-
|
|
1417
|
+
} = /** @type {JamilihAttributes} */atts;
|
|
1418
|
+
/* c8 ignore next */
|
|
1419
|
+
elem = doc.createElementNS
|
|
1420
|
+
/* eslint-disable object-shorthand -- Casting */ ? doc.createElementNS(NS_HTML, elStr, {
|
|
1421
|
+
is: /** @type {string} */is
|
|
1012
1422
|
}) : doc.createElement(elStr, {
|
|
1013
|
-
is
|
|
1423
|
+
is: /** @type {string} */is
|
|
1014
1424
|
});
|
|
1015
|
-
|
|
1425
|
+
/* eslint-enable object-shorthand -- Casting */
|
|
1426
|
+
} else /* c8 ignore next */if (doc.createElementNS) {
|
|
1016
1427
|
elem = doc.createElementNS(NS_HTML, elStr);
|
|
1017
1428
|
} else {
|
|
1018
1429
|
elem = doc.createElement(elStr);
|
|
@@ -1027,24 +1438,33 @@ const jml = function jml(...args) {
|
|
|
1027
1438
|
case 'object':
|
|
1028
1439
|
{
|
|
1029
1440
|
// Non-DOM-element objects indicate attribute-value pairs
|
|
1441
|
+
if (!arg || typeof arg !== 'object') {
|
|
1442
|
+
throw new Error('Null should not reach here');
|
|
1443
|
+
}
|
|
1030
1444
|
const atts = arg;
|
|
1031
|
-
if (
|
|
1445
|
+
if ('xmlns' in atts) {
|
|
1032
1446
|
// We handle this here, as otherwise may lose events, etc.
|
|
1033
1447
|
// As namespace of element already set as XHTML, we need to change the namespace
|
|
1034
1448
|
// elem.setAttribute('xmlns', atts.xmlns); // Doesn't work
|
|
1035
1449
|
// Can't set namespaceURI dynamically, renameNode() is not supported, and setAttribute() doesn't work to change the namespace, so we resort to this hack
|
|
1036
|
-
const
|
|
1450
|
+
const xmlnsObj = /** @type {XmlnsAttributeObject} */atts;
|
|
1451
|
+
const replacer = xmlnsObj.xmlns && typeof xmlnsObj.xmlns === 'object' ? _replaceDefiner(xmlnsObj.xmlns) : ' xmlns="' + xmlnsObj.xmlns + '"';
|
|
1037
1452
|
// try {
|
|
1038
1453
|
// Also fix DOMParser to work with text/html
|
|
1039
|
-
elem = nodes[nodes.length - 1] =
|
|
1454
|
+
elem = nodes[nodes.length - 1] =
|
|
1455
|
+
// Why doesn't `HTMLWindow` have `DOMParser`?
|
|
1456
|
+
new /** @type {import('jsdom').DOMWindow} */win.DOMParser().parseFromString(new /** @type {import('jsdom').DOMWindow} */win.XMLSerializer().serializeToString(elem)
|
|
1040
1457
|
// Mozilla adds XHTML namespace
|
|
1041
|
-
.replace(' xmlns="' + NS_HTML + '"',
|
|
1458
|
+
.replace(' xmlns="' + NS_HTML + '"',
|
|
1459
|
+
// Needed to cast here, despite either overload working
|
|
1460
|
+
/** @type {string} */
|
|
1461
|
+
replacer), 'application/xml').documentElement;
|
|
1042
1462
|
// Todo: Report to plugins
|
|
1043
1463
|
opts.$state = 'element';
|
|
1044
1464
|
// }catch(e) {alert(elem.outerHTML);throw e;}
|
|
1045
1465
|
}
|
|
1046
1466
|
|
|
1047
|
-
_checkAtts(atts);
|
|
1467
|
+
_checkAtts( /** @type {JamilihAttributes} */atts);
|
|
1048
1468
|
break;
|
|
1049
1469
|
}
|
|
1050
1470
|
case 'document':
|
|
@@ -1056,26 +1476,24 @@ const jml = function jml(...args) {
|
|
|
1056
1476
|
*/
|
|
1057
1477
|
if (i === 0) {
|
|
1058
1478
|
// Allow wrapping of element, fragment, or document
|
|
1059
|
-
elem = arg;
|
|
1060
|
-
// Todo: Report to plugins
|
|
1479
|
+
elem = /** @type {Document|DocumentFragment|Element} */arg;
|
|
1480
|
+
// Todo: Report to plugins and change for document/fragment
|
|
1061
1481
|
opts.$state = 'element';
|
|
1062
1482
|
}
|
|
1063
1483
|
if (i === argc - 1 || i === argc - 2 && args[i + 1] === null) {
|
|
1064
1484
|
// parent
|
|
1065
1485
|
const elsl = nodes.length;
|
|
1066
1486
|
for (let k = 0; k < elsl; k++) {
|
|
1067
|
-
_appendNode(arg, nodes[k]);
|
|
1487
|
+
_appendNode( /** @type {Document|DocumentFragment|Element} */arg, nodes[k]);
|
|
1068
1488
|
}
|
|
1069
|
-
// Todo: Apply stylesheets if any style tags were added elsewhere besides the first element?
|
|
1070
|
-
_applyAnyStylesheet(nodes[0]); // We have to execute any stylesheets even if not appending or otherwise IE will never apply them
|
|
1071
1489
|
} else {
|
|
1072
|
-
nodes[nodes.length] = arg;
|
|
1490
|
+
nodes[nodes.length] = /** @type {Document|DocumentFragment|Element} */arg;
|
|
1073
1491
|
}
|
|
1074
1492
|
break;
|
|
1075
1493
|
case 'array':
|
|
1076
1494
|
{
|
|
1077
1495
|
// Arrays or arrays of arrays indicate child nodes
|
|
1078
|
-
const child = arg;
|
|
1496
|
+
const child = /** @type {JamilihChildren} */arg;
|
|
1079
1497
|
const cl = child.length;
|
|
1080
1498
|
for (let j = 0; j < cl; j++) {
|
|
1081
1499
|
// Go through children array container to handle elements
|
|
@@ -1089,21 +1507,30 @@ const jml = function jml(...args) {
|
|
|
1089
1507
|
case 'string':
|
|
1090
1508
|
case 'number':
|
|
1091
1509
|
case 'boolean':
|
|
1092
|
-
_appendNode(elem, doc.createTextNode(childContent));
|
|
1510
|
+
_appendNode(elem, doc.createTextNode(String(childContent)));
|
|
1093
1511
|
break;
|
|
1094
1512
|
default:
|
|
1513
|
+
if (!childContent || typeof childContent !== 'object') {
|
|
1514
|
+
throw new Error('Unexpected type');
|
|
1515
|
+
}
|
|
1095
1516
|
if (Array.isArray(childContent)) {
|
|
1096
1517
|
// Arrays representing child elements
|
|
1097
1518
|
opts.$state = 'children';
|
|
1519
|
+
// @ts-expect-error Should be ok
|
|
1098
1520
|
_appendNode(elem, jml(opts, ...childContent));
|
|
1099
|
-
} else if (
|
|
1521
|
+
} else if ('#' in childContent) {
|
|
1100
1522
|
// Fragment
|
|
1101
1523
|
opts.$state = 'fragmentChildren';
|
|
1102
1524
|
_appendNode(elem, jml(opts, childContent['#']));
|
|
1103
1525
|
} else {
|
|
1104
|
-
// Single DOM element children
|
|
1105
|
-
|
|
1106
|
-
|
|
1526
|
+
// Single DOM element children or plugin
|
|
1527
|
+
let newChildContent;
|
|
1528
|
+
if (!('nodeType' in childContent)) {
|
|
1529
|
+
newChildContent = /** @type {string} */
|
|
1530
|
+
checkPluginValue(elem, null, childContent, opts, 'children');
|
|
1531
|
+
}
|
|
1532
|
+
_appendNode(elem, /** @type {string | Element | DocumentFragment | Comment} */
|
|
1533
|
+
newChildContent || childContent);
|
|
1107
1534
|
}
|
|
1108
1535
|
break;
|
|
1109
1536
|
}
|
|
@@ -1115,34 +1542,116 @@ const jml = function jml(...args) {
|
|
|
1115
1542
|
}
|
|
1116
1543
|
}
|
|
1117
1544
|
const ret = nodes[0] || elem;
|
|
1118
|
-
if (isRoot && opts.$map && opts.$map.root) {
|
|
1545
|
+
if (isRoot && opts.$map && /** @type {MapWithRoot} */opts.$map.root) {
|
|
1119
1546
|
setMap(true);
|
|
1120
1547
|
}
|
|
1121
1548
|
return ret;
|
|
1122
1549
|
};
|
|
1123
1550
|
|
|
1551
|
+
/**
|
|
1552
|
+
* Configuration object.
|
|
1553
|
+
* @typedef {object} ToJmlConfig
|
|
1554
|
+
* @property {boolean} [stringOutput=false] Whether to output the Jamilih object as a string.
|
|
1555
|
+
* @property {boolean} [reportInvalidState=true] If true (the default), will report invalid state errors
|
|
1556
|
+
* @property {boolean} [stripWhitespace=false] Strip whitespace for text nodes
|
|
1557
|
+
*/
|
|
1558
|
+
|
|
1559
|
+
/**
|
|
1560
|
+
* @typedef {[namespace: string|null, name: string, value?: string]} JamilihAttributeNodeValue
|
|
1561
|
+
*/
|
|
1562
|
+
|
|
1563
|
+
/**
|
|
1564
|
+
* @typedef {{
|
|
1565
|
+
* $attribute: JamilihAttributeNodeValue
|
|
1566
|
+
* }} JamilihAttributeNode
|
|
1567
|
+
*/
|
|
1568
|
+
|
|
1569
|
+
/**
|
|
1570
|
+
* @typedef {{
|
|
1571
|
+
* $text: string
|
|
1572
|
+
* }} JamilihTextNode
|
|
1573
|
+
*/
|
|
1574
|
+
|
|
1575
|
+
/**
|
|
1576
|
+
* @typedef {['![', string]} JamilihCDATANode
|
|
1577
|
+
*/
|
|
1578
|
+
|
|
1579
|
+
/**
|
|
1580
|
+
* @typedef {['&', string]} JamilihEntityReference
|
|
1581
|
+
*/
|
|
1582
|
+
|
|
1583
|
+
/**
|
|
1584
|
+
* @typedef {[code: '?', target: string, value: string]} JamilihProcessingInstruction
|
|
1585
|
+
*/
|
|
1586
|
+
|
|
1587
|
+
/**
|
|
1588
|
+
* @typedef {[code: '!', value: string]} JamilihComment
|
|
1589
|
+
*/
|
|
1590
|
+
|
|
1591
|
+
/**
|
|
1592
|
+
* @typedef {{
|
|
1593
|
+
* nodeType: number,
|
|
1594
|
+
* nodeName: string
|
|
1595
|
+
* }} Entity
|
|
1596
|
+
*/
|
|
1597
|
+
|
|
1598
|
+
/* eslint-disable no-shadow, unicorn/custom-error-definition */
|
|
1599
|
+
/**
|
|
1600
|
+
* Polyfill for `DOMException`.
|
|
1601
|
+
*/
|
|
1602
|
+
class DOMException extends Error {
|
|
1603
|
+
/* eslint-enable no-shadow, unicorn/custom-error-definition */
|
|
1604
|
+
/**
|
|
1605
|
+
* @param {string} message
|
|
1606
|
+
* @param {string} name
|
|
1607
|
+
*/
|
|
1608
|
+
constructor(message, name) {
|
|
1609
|
+
super(message);
|
|
1610
|
+
this.code = 0;
|
|
1611
|
+
// eslint-disable-next-line unicorn/custom-error-definition
|
|
1612
|
+
this.name = name;
|
|
1613
|
+
}
|
|
1614
|
+
}
|
|
1615
|
+
|
|
1616
|
+
/**
|
|
1617
|
+
* @typedef {JamilihArray|JamilihDoctype|
|
|
1618
|
+
* JamilihCDATANode|JamilihEntityReference|JamilihProcessingInstruction|
|
|
1619
|
+
* JamilihComment|JamilihDocumentFragment} JamilihChildType
|
|
1620
|
+
*/
|
|
1621
|
+
|
|
1622
|
+
/**
|
|
1623
|
+
* @typedef {JamilihDoc|JamilihAttributeNode|JamilihChildType} JamilihType
|
|
1624
|
+
*/
|
|
1625
|
+
|
|
1124
1626
|
/**
|
|
1125
1627
|
* Converts a DOM object or a string of HTML into a Jamilih object (or string).
|
|
1126
|
-
* @param {string|HTMLElement}
|
|
1127
|
-
* @param {
|
|
1128
|
-
* @param {boolean} [config.stringOutput=false] Whether to output the Jamilih object as a string.
|
|
1129
|
-
* @param {boolean} [config.reportInvalidState=true] If true (the default), will report invalid state errors
|
|
1130
|
-
* @param {boolean} [config.stripWhitespace=false] Strip whitespace for text nodes
|
|
1628
|
+
* @param {string|HTMLElement|Node|Entity} nde If a string, will parse as document
|
|
1629
|
+
* @param {ToJmlConfig} [config] Configuration object
|
|
1131
1630
|
* @throws {TypeError}
|
|
1132
|
-
* @returns {
|
|
1631
|
+
* @returns {JamilihType|string} Array containing the elements which represent
|
|
1133
1632
|
* a Jamilih object, or, if `stringOutput` is true, it will be the stringified
|
|
1134
1633
|
* version of such an object
|
|
1135
1634
|
*/
|
|
1136
|
-
jml.toJML = function (
|
|
1635
|
+
jml.toJML = function (nde, {
|
|
1137
1636
|
stringOutput = false,
|
|
1138
1637
|
reportInvalidState = true,
|
|
1139
1638
|
stripWhitespace = false
|
|
1140
1639
|
} = {}) {
|
|
1141
|
-
if (
|
|
1142
|
-
|
|
1640
|
+
if (!win) {
|
|
1641
|
+
throw new Error('No window object set');
|
|
1642
|
+
}
|
|
1643
|
+
if (typeof nde === 'string') {
|
|
1644
|
+
nde = new /** @type {import('jsdom').DOMWindow} */win.DOMParser().parseFromString(nde, 'text/html'); // todo: Give option for XML once implemented and change JSDoc to allow for Element
|
|
1143
1645
|
}
|
|
1144
1646
|
|
|
1145
|
-
const
|
|
1647
|
+
const dom = /** @type {HTMLElement|Node|Entity} */nde;
|
|
1648
|
+
|
|
1649
|
+
/**
|
|
1650
|
+
* @todo Find more specific type than `any`
|
|
1651
|
+
* @typedef {{[key: (number|string)]: any}} IndexableObject
|
|
1652
|
+
*/
|
|
1653
|
+
|
|
1654
|
+
const ret = /** @type {IndexableObject} */[];
|
|
1146
1655
|
let parent = ret;
|
|
1147
1656
|
let parentIdx = 0;
|
|
1148
1657
|
|
|
@@ -1153,22 +1662,6 @@ jml.toJML = function (dom, {
|
|
|
1153
1662
|
*/
|
|
1154
1663
|
function invalidStateError(msg) {
|
|
1155
1664
|
// These are probably only necessary if working with text/html
|
|
1156
|
-
/* eslint-disable no-shadow, unicorn/custom-error-definition */
|
|
1157
|
-
/**
|
|
1158
|
-
* Polyfill for `DOMException`.
|
|
1159
|
-
*/
|
|
1160
|
-
class DOMException extends Error {
|
|
1161
|
-
/* eslint-enable no-shadow, unicorn/custom-error-definition */
|
|
1162
|
-
/**
|
|
1163
|
-
* @param {string} message
|
|
1164
|
-
* @param {string} name
|
|
1165
|
-
*/
|
|
1166
|
-
constructor(message, name) {
|
|
1167
|
-
super(message);
|
|
1168
|
-
// eslint-disable-next-line unicorn/custom-error-definition
|
|
1169
|
-
this.name = name;
|
|
1170
|
-
}
|
|
1171
|
-
}
|
|
1172
1665
|
if (reportInvalidState) {
|
|
1173
1666
|
// INVALID_STATE_ERR per section 9.3 XHTML 5: http://www.w3.org/TR/html5/the-xhtml-syntax.html
|
|
1174
1667
|
const e = new DOMException(msg, 'INVALID_STATE_ERR');
|
|
@@ -1179,8 +1672,8 @@ jml.toJML = function (dom, {
|
|
|
1179
1672
|
|
|
1180
1673
|
/**
|
|
1181
1674
|
*
|
|
1182
|
-
* @param {
|
|
1183
|
-
* @param {
|
|
1675
|
+
* @param {JamilihDocumentType} obj
|
|
1676
|
+
* @param {DocumentType} node
|
|
1184
1677
|
* @returns {void}
|
|
1185
1678
|
*/
|
|
1186
1679
|
function addExternalID(obj, node) {
|
|
@@ -1199,10 +1692,6 @@ jml.toJML = function (dom, {
|
|
|
1199
1692
|
}
|
|
1200
1693
|
}
|
|
1201
1694
|
|
|
1202
|
-
/**
|
|
1203
|
-
* @typedef {any} ArbitraryValue
|
|
1204
|
-
*/
|
|
1205
|
-
|
|
1206
1695
|
/**
|
|
1207
1696
|
*
|
|
1208
1697
|
* @param {ArbitraryValue} val
|
|
@@ -1225,7 +1714,7 @@ jml.toJML = function (dom, {
|
|
|
1225
1714
|
/**
|
|
1226
1715
|
*
|
|
1227
1716
|
* @param {string} prop1
|
|
1228
|
-
* @param {string} prop2
|
|
1717
|
+
* @param {string} [prop2]
|
|
1229
1718
|
* @returns {void}
|
|
1230
1719
|
*/
|
|
1231
1720
|
function setObj(prop1, prop2) {
|
|
@@ -1238,29 +1727,47 @@ jml.toJML = function (dom, {
|
|
|
1238
1727
|
|
|
1239
1728
|
/**
|
|
1240
1729
|
*
|
|
1241
|
-
* @param {Node}
|
|
1242
|
-
* @param {Object<
|
|
1730
|
+
* @param {Node|Entity} nodeOrEntity
|
|
1731
|
+
* @param {Object<string, string|null>} namespaces
|
|
1243
1732
|
* @throws {TypeError}
|
|
1244
1733
|
* @returns {void}
|
|
1245
1734
|
*/
|
|
1246
|
-
function parseDOM(
|
|
1735
|
+
function parseDOM(nodeOrEntity, namespaces) {
|
|
1247
1736
|
// namespaces = clone(namespaces) || {}; // Ensure we're working with a copy, so different levels in the hierarchy can treat it differently
|
|
1248
1737
|
|
|
1249
1738
|
/*
|
|
1250
|
-
if ((
|
|
1739
|
+
if ((nodeOrEntity.prefix && nodeOrEntity.prefix.includes(':')) || (nodeOrEntity.localName && nodeOrEntity.localName.includes(':'))) {
|
|
1251
1740
|
invalidStateError('Prefix cannot have a colon');
|
|
1252
1741
|
}
|
|
1253
1742
|
*/
|
|
1254
1743
|
|
|
1255
|
-
const type = 'nodeType' in
|
|
1744
|
+
const type = 'nodeType' in nodeOrEntity ? nodeOrEntity.nodeType : null;
|
|
1745
|
+
if (!type) {
|
|
1746
|
+
throw new TypeError('Not an XML type');
|
|
1747
|
+
}
|
|
1748
|
+
if (type === 5) {
|
|
1749
|
+
// ENTITY REFERENCE (though not in browsers (was already resolved
|
|
1750
|
+
// anyways), ok to keep for parity with our "entity" shorthand)
|
|
1751
|
+
set(['&', nodeOrEntity.nodeName]);
|
|
1752
|
+
return;
|
|
1753
|
+
}
|
|
1256
1754
|
namespaces = {
|
|
1257
1755
|
...namespaces
|
|
1258
1756
|
};
|
|
1259
1757
|
const xmlChars = /^([\u0009\u000A\u000D\u0020-\uD7FF\uE000-\uFFFD]|[\uD800-\uDBFF][\uDC00-\uDFFF])*$/u; // eslint-disable-line no-control-regex
|
|
1260
|
-
if ([2, 3, 4, 7, 8].includes(type) && !xmlChars.test(
|
|
1758
|
+
if ([2, 3, 4, 7, 8].includes(type) && /** @type {Node} */nodeOrEntity.nodeValue && !xmlChars.test( /** @type {Node} */nodeOrEntity.nodeValue)) {
|
|
1261
1759
|
invalidStateError('Node has bad XML character value');
|
|
1262
1760
|
}
|
|
1263
|
-
|
|
1761
|
+
|
|
1762
|
+
/**
|
|
1763
|
+
* @type {IndexableObject}
|
|
1764
|
+
*/
|
|
1765
|
+
let tmpParent;
|
|
1766
|
+
|
|
1767
|
+
/**
|
|
1768
|
+
* @type {Integer}
|
|
1769
|
+
*/
|
|
1770
|
+
let tmpParentIdx;
|
|
1264
1771
|
|
|
1265
1772
|
/**
|
|
1266
1773
|
* @returns {void}
|
|
@@ -1282,11 +1789,16 @@ jml.toJML = function (dom, {
|
|
|
1282
1789
|
case 1:
|
|
1283
1790
|
{
|
|
1284
1791
|
// ELEMENT
|
|
1792
|
+
const node = /** @type {Element} */nodeOrEntity;
|
|
1285
1793
|
setTemp();
|
|
1286
1794
|
const nodeName = node.nodeName.toLowerCase(); // Todo: for XML, should not lower-case
|
|
1287
1795
|
|
|
1288
1796
|
setChildren(); // Build child array since elements are, except at the top level, encapsulated in arrays
|
|
1289
1797
|
set(nodeName);
|
|
1798
|
+
|
|
1799
|
+
/**
|
|
1800
|
+
* @type {{[key: string]: string|null} & {xmlns?: string|null}}
|
|
1801
|
+
*/
|
|
1290
1802
|
const start = {};
|
|
1291
1803
|
let hasNamespaceDeclaration = false;
|
|
1292
1804
|
if (namespaces[node.prefix || ''] !== node.namespaceURI) {
|
|
@@ -1322,57 +1834,79 @@ jml.toJML = function (dom, {
|
|
|
1322
1834
|
}
|
|
1323
1835
|
case undefined: // Treat as attribute node until this is fixed: https://github.com/jsdom/jsdom/issues/1641 / https://github.com/jsdom/jsdom/pull/1822
|
|
1324
1836
|
case 2:
|
|
1325
|
-
|
|
1326
|
-
|
|
1327
|
-
|
|
1328
|
-
|
|
1329
|
-
|
|
1837
|
+
{
|
|
1838
|
+
// ATTRIBUTE (should only get here if passing in an attribute node)
|
|
1839
|
+
const node = /** @type {Attr} */nodeOrEntity;
|
|
1840
|
+
set({
|
|
1841
|
+
$attribute: [node.namespaceURI, node.name, node.value]
|
|
1842
|
+
});
|
|
1843
|
+
break;
|
|
1844
|
+
}
|
|
1330
1845
|
case 3:
|
|
1331
|
-
|
|
1332
|
-
|
|
1333
|
-
|
|
1334
|
-
|
|
1846
|
+
{
|
|
1847
|
+
// TEXT
|
|
1848
|
+
const node = /** @type {Text} */nodeOrEntity;
|
|
1849
|
+
/* c8 ignore next 3 */
|
|
1850
|
+
if (!node.nodeValue) {
|
|
1851
|
+
throw new Error('Unexpected null comment value');
|
|
1852
|
+
}
|
|
1853
|
+
if (stripWhitespace && /^\s+$/u.test(node.nodeValue)) {
|
|
1854
|
+
set('');
|
|
1855
|
+
return;
|
|
1856
|
+
}
|
|
1857
|
+
set(node.nodeValue);
|
|
1858
|
+
break;
|
|
1335
1859
|
}
|
|
1336
|
-
set(node.nodeValue);
|
|
1337
|
-
break;
|
|
1338
1860
|
case 4:
|
|
1339
|
-
|
|
1340
|
-
|
|
1341
|
-
|
|
1861
|
+
{
|
|
1862
|
+
var _node$nodeValue;
|
|
1863
|
+
// CDATA
|
|
1864
|
+
const node = /** @type {CDATASection} */nodeOrEntity;
|
|
1865
|
+
if ((_node$nodeValue = node.nodeValue) !== null && _node$nodeValue !== void 0 && _node$nodeValue.includes(']]' + '>')) {
|
|
1866
|
+
invalidStateError('CDATA cannot end with closing ]]>');
|
|
1867
|
+
}
|
|
1868
|
+
set(['![', node.nodeValue]);
|
|
1869
|
+
break;
|
|
1342
1870
|
}
|
|
1343
|
-
|
|
1344
|
-
|
|
1345
|
-
case 5:
|
|
1346
|
-
// ENTITY REFERENCE (though not in browsers (was already resolved
|
|
1347
|
-
// anyways), ok to keep for parity with our "entity" shorthand)
|
|
1348
|
-
set(['&', node.nodeName]);
|
|
1349
|
-
break;
|
|
1871
|
+
// case 5:
|
|
1872
|
+
// Handled earlier
|
|
1350
1873
|
case 7:
|
|
1351
|
-
|
|
1352
|
-
|
|
1353
|
-
|
|
1354
|
-
|
|
1355
|
-
|
|
1356
|
-
|
|
1357
|
-
|
|
1358
|
-
|
|
1359
|
-
|
|
1360
|
-
|
|
1361
|
-
|
|
1362
|
-
|
|
1874
|
+
{
|
|
1875
|
+
// PROCESSING INSTRUCTION
|
|
1876
|
+
const node = /** @type {ProcessingInstruction} */nodeOrEntity;
|
|
1877
|
+
if (/^xml$/iu.test(node.target)) {
|
|
1878
|
+
invalidStateError('Processing instructions cannot be "xml".');
|
|
1879
|
+
}
|
|
1880
|
+
if (node.target.includes('?>')) {
|
|
1881
|
+
invalidStateError('Processing instruction targets cannot include ?>');
|
|
1882
|
+
}
|
|
1883
|
+
if (node.target.includes(':')) {
|
|
1884
|
+
invalidStateError('The processing instruction target cannot include ":"');
|
|
1885
|
+
}
|
|
1886
|
+
if (node.data.includes('?>')) {
|
|
1887
|
+
invalidStateError('Processing instruction data cannot include ?>');
|
|
1888
|
+
}
|
|
1889
|
+
set(['?', node.target, node.data]); // Todo: Could give option to attempt to convert value back into object if has pseudo-attributes
|
|
1890
|
+
break;
|
|
1363
1891
|
}
|
|
1364
|
-
set(['?', node.target, node.data]); // Todo: Could give option to attempt to convert value back into object if has pseudo-attributes
|
|
1365
|
-
break;
|
|
1366
1892
|
case 8:
|
|
1367
|
-
|
|
1368
|
-
|
|
1369
|
-
|
|
1893
|
+
{
|
|
1894
|
+
// COMMENT
|
|
1895
|
+
const node = /** @type {Comment} */nodeOrEntity;
|
|
1896
|
+
/* c8 ignore next 3 */
|
|
1897
|
+
if (!node.nodeValue) {
|
|
1898
|
+
throw new Error('Unexpected null comment value');
|
|
1899
|
+
}
|
|
1900
|
+
if (node.nodeValue.includes('--') || node.nodeValue.length && node.nodeValue.lastIndexOf('-') === node.nodeValue.length - 1) {
|
|
1901
|
+
invalidStateError('Comments cannot include --');
|
|
1902
|
+
}
|
|
1903
|
+
set(['!', node.nodeValue]);
|
|
1904
|
+
break;
|
|
1370
1905
|
}
|
|
1371
|
-
set(['!', node.nodeValue]);
|
|
1372
|
-
break;
|
|
1373
1906
|
case 9:
|
|
1374
1907
|
{
|
|
1375
1908
|
// DOCUMENT
|
|
1909
|
+
const node = /** @type {Document} */nodeOrEntity;
|
|
1376
1910
|
setTemp();
|
|
1377
1911
|
const docObj = {
|
|
1378
1912
|
$document: {
|
|
@@ -1402,16 +1936,17 @@ jml.toJML = function (dom, {
|
|
|
1402
1936
|
case 10:
|
|
1403
1937
|
{
|
|
1404
1938
|
// DOCUMENT TYPE
|
|
1939
|
+
const node = /** @type {DocumentType} */nodeOrEntity;
|
|
1405
1940
|
setTemp();
|
|
1406
1941
|
|
|
1407
1942
|
// Can create directly by doc.implementation.createDocumentType
|
|
1408
1943
|
const start = {
|
|
1409
1944
|
$DOCTYPE: {
|
|
1410
|
-
name: node.name
|
|
1945
|
+
name: /** @type {DocumentType} */node.name
|
|
1411
1946
|
}
|
|
1412
1947
|
};
|
|
1413
1948
|
const pubIdChar = /^(\u0020|\u000D|\u000A|[a-zA-Z0-9]|[-'()+,./:=?;!*#@$_%])*$/u; // eslint-disable-line no-control-regex
|
|
1414
|
-
if (!pubIdChar.test(node.publicId)) {
|
|
1949
|
+
if (!pubIdChar.test( /** @type {DocumentType} */node.publicId)) {
|
|
1415
1950
|
invalidStateError('A publicId must have valid characters.');
|
|
1416
1951
|
}
|
|
1417
1952
|
addExternalID(start.$DOCTYPE, node);
|
|
@@ -1424,6 +1959,7 @@ jml.toJML = function (dom, {
|
|
|
1424
1959
|
case 11:
|
|
1425
1960
|
{
|
|
1426
1961
|
// DOCUMENT FRAGMENT
|
|
1962
|
+
const node = /** @type {DocumentFragment} */nodeOrEntity;
|
|
1427
1963
|
setTemp();
|
|
1428
1964
|
set({
|
|
1429
1965
|
'#': []
|
|
@@ -1451,15 +1987,23 @@ jml.toJML = function (dom, {
|
|
|
1451
1987
|
}
|
|
1452
1988
|
return ret[0];
|
|
1453
1989
|
};
|
|
1990
|
+
|
|
1991
|
+
/**
|
|
1992
|
+
* @param {string|HTMLElement} dom
|
|
1993
|
+
* @param {ToJmlConfig} [config]
|
|
1994
|
+
* @returns {string}
|
|
1995
|
+
*/
|
|
1454
1996
|
jml.toJMLString = function (dom, config) {
|
|
1455
|
-
return
|
|
1456
|
-
|
|
1457
|
-
|
|
1997
|
+
return (/** @type {string} */
|
|
1998
|
+
jml.toJML(dom, Object.assign(config || {}, {
|
|
1999
|
+
stringOutput: true
|
|
2000
|
+
}))
|
|
2001
|
+
);
|
|
1458
2002
|
};
|
|
1459
2003
|
|
|
1460
2004
|
/**
|
|
1461
2005
|
*
|
|
1462
|
-
* @param {
|
|
2006
|
+
* @param {JamilihArray} args
|
|
1463
2007
|
* @returns {JamilihReturn}
|
|
1464
2008
|
*/
|
|
1465
2009
|
jml.toDOM = function (...args) {
|
|
@@ -1469,21 +2013,75 @@ jml.toDOM = function (...args) {
|
|
|
1469
2013
|
|
|
1470
2014
|
/**
|
|
1471
2015
|
*
|
|
1472
|
-
* @param {
|
|
2016
|
+
* @param {JamilihArray} args
|
|
1473
2017
|
* @returns {string}
|
|
1474
2018
|
*/
|
|
1475
2019
|
jml.toHTML = function (...args) {
|
|
1476
2020
|
// Todo: Replace this with version of jml() that directly builds a string
|
|
1477
2021
|
const ret = jml(...args);
|
|
1478
|
-
|
|
1479
|
-
|
|
1480
|
-
|
|
1481
|
-
|
|
2022
|
+
switch (ret.nodeType) {
|
|
2023
|
+
case 1:
|
|
2024
|
+
{
|
|
2025
|
+
// Element
|
|
2026
|
+
// Todo: deal with serialization of properties like 'selected',
|
|
2027
|
+
// 'checked', 'value', 'defaultValue', 'for', 'dataset', 'on*',
|
|
2028
|
+
// 'style'! (i.e., need to build a string ourselves)
|
|
2029
|
+
return (/** @type {Element} */ret.outerHTML
|
|
2030
|
+
);
|
|
2031
|
+
}
|
|
2032
|
+
case 2:
|
|
2033
|
+
{
|
|
2034
|
+
// ATTR
|
|
2035
|
+
return `${
|
|
2036
|
+
/** @type {Attr} */ret.name}="${
|
|
2037
|
+
/** @type {Attr} */ret.value.replace(/"/gu, '"')}"`;
|
|
2038
|
+
}
|
|
2039
|
+
case 3:
|
|
2040
|
+
case 4:
|
|
2041
|
+
{
|
|
2042
|
+
// CDATA
|
|
2043
|
+
if (!ret.nodeValue) {
|
|
2044
|
+
throw new TypeError('Unexpected null Text node');
|
|
2045
|
+
}
|
|
2046
|
+
return (/** @type {Text|CDATASection} */ret.nodeValue
|
|
2047
|
+
);
|
|
2048
|
+
// case 5: // Entity
|
|
2049
|
+
}
|
|
2050
|
+
case 7:
|
|
2051
|
+
{
|
|
2052
|
+
// PROCESSING INSTRUCTION
|
|
2053
|
+
const node = /** @type {ProcessingInstruction} */ret;
|
|
2054
|
+
return `<?${node.target} ${node.data}?>`;
|
|
2055
|
+
}
|
|
2056
|
+
case 8:
|
|
2057
|
+
{
|
|
2058
|
+
// Comment
|
|
2059
|
+
return `<!--${ret.nodeValue}-->`;
|
|
2060
|
+
}
|
|
2061
|
+
case 9:
|
|
2062
|
+
{
|
|
2063
|
+
// Document
|
|
2064
|
+
throw new Error('Document serialization not yet implemented');
|
|
2065
|
+
}
|
|
2066
|
+
case 10:
|
|
2067
|
+
{
|
|
2068
|
+
// DOCUMENT TYPE
|
|
2069
|
+
const node = /** @type {DocumentType} */ret;
|
|
2070
|
+
return `<!DOCTYPE ${node.name}${node.publicId ? `PUBLIC "${node.publicId}" "${node.systemId}"` : node.systemId ? `SYSTEM "${node.systemId}"` : ``}>`;
|
|
2071
|
+
}
|
|
2072
|
+
case 11:
|
|
2073
|
+
{
|
|
2074
|
+
// DOCUMENT FRAGMENT
|
|
2075
|
+
throw new Error('Document fragment serialization not yet implemented');
|
|
2076
|
+
}
|
|
2077
|
+
default:
|
|
2078
|
+
throw new Error('Unexpected node type');
|
|
2079
|
+
}
|
|
1482
2080
|
};
|
|
1483
2081
|
|
|
1484
2082
|
/**
|
|
1485
2083
|
*
|
|
1486
|
-
* @param {
|
|
2084
|
+
* @param {JamilihArray} args
|
|
1487
2085
|
* @returns {string}
|
|
1488
2086
|
*/
|
|
1489
2087
|
jml.toDOMString = function (...args) {
|
|
@@ -1493,17 +2091,20 @@ jml.toDOMString = function (...args) {
|
|
|
1493
2091
|
|
|
1494
2092
|
/**
|
|
1495
2093
|
*
|
|
1496
|
-
* @param {
|
|
2094
|
+
* @param {JamilihArray} args
|
|
1497
2095
|
* @returns {string}
|
|
1498
2096
|
*/
|
|
1499
2097
|
jml.toXML = function (...args) {
|
|
2098
|
+
if (!win) {
|
|
2099
|
+
throw new Error('No window object set');
|
|
2100
|
+
}
|
|
1500
2101
|
const ret = jml(...args);
|
|
1501
|
-
return new win.XMLSerializer().serializeToString(ret);
|
|
2102
|
+
return new /** @type {import('jsdom').DOMWindow} */win.XMLSerializer().serializeToString(ret);
|
|
1502
2103
|
};
|
|
1503
2104
|
|
|
1504
2105
|
/**
|
|
1505
2106
|
*
|
|
1506
|
-
* @param {
|
|
2107
|
+
* @param {JamilihArray} args
|
|
1507
2108
|
* @returns {string}
|
|
1508
2109
|
*/
|
|
1509
2110
|
jml.toXMLDOMString = function (...args) {
|
|
@@ -1516,63 +2117,73 @@ jml.toXMLDOMString = function (...args) {
|
|
|
1516
2117
|
*/
|
|
1517
2118
|
class JamilihMap extends Map {
|
|
1518
2119
|
/**
|
|
1519
|
-
* @param {string|Element}
|
|
2120
|
+
* @param {?(string|Element)} element
|
|
1520
2121
|
* @returns {ArbitraryValue}
|
|
1521
2122
|
*/
|
|
1522
|
-
get(
|
|
1523
|
-
elem = typeof
|
|
2123
|
+
get(element) {
|
|
2124
|
+
const elem = typeof element === 'string' ? $(element) : element;
|
|
1524
2125
|
return super.get.call(this, elem);
|
|
1525
2126
|
}
|
|
1526
2127
|
/**
|
|
1527
|
-
* @param {string|Element}
|
|
2128
|
+
* @param {string|Element} element
|
|
1528
2129
|
* @param {ArbitraryValue} value
|
|
1529
2130
|
* @returns {ArbitraryValue}
|
|
1530
2131
|
*/
|
|
1531
|
-
set(
|
|
1532
|
-
elem = typeof
|
|
2132
|
+
set(element, value) {
|
|
2133
|
+
const elem = typeof element === 'string' ? $(element) : element;
|
|
1533
2134
|
return super.set.call(this, elem, value);
|
|
1534
2135
|
}
|
|
1535
2136
|
/**
|
|
1536
|
-
* @param {string|Element}
|
|
2137
|
+
* @param {string|Element} element
|
|
1537
2138
|
* @param {string} methodName
|
|
1538
2139
|
* @param {...ArbitraryValue} args
|
|
1539
2140
|
* @returns {ArbitraryValue}
|
|
1540
2141
|
*/
|
|
1541
|
-
invoke(
|
|
1542
|
-
elem = typeof
|
|
2142
|
+
invoke(element, methodName, ...args) {
|
|
2143
|
+
const elem = typeof element === 'string' ? $(element) : element;
|
|
1543
2144
|
return this.get(elem)[methodName](elem, ...args);
|
|
1544
2145
|
}
|
|
1545
2146
|
}
|
|
1546
2147
|
|
|
1547
2148
|
/**
|
|
1548
2149
|
* Element-aware wrapper for `WeakMap`.
|
|
2150
|
+
* @extends {WeakMap<any>}
|
|
1549
2151
|
*/
|
|
1550
2152
|
class JamilihWeakMap extends WeakMap {
|
|
1551
2153
|
/**
|
|
1552
|
-
* @param {
|
|
2154
|
+
* @param {Element} element
|
|
1553
2155
|
* @returns {ArbitraryValue}
|
|
1554
2156
|
*/
|
|
1555
|
-
get(
|
|
1556
|
-
elem = typeof
|
|
2157
|
+
get(element) {
|
|
2158
|
+
const elem = typeof element === 'string' ? $(element) : element;
|
|
2159
|
+
if (!elem) {
|
|
2160
|
+
throw new Error("Can't find the element");
|
|
2161
|
+
}
|
|
1557
2162
|
return super.get.call(this, elem);
|
|
1558
2163
|
}
|
|
1559
2164
|
/**
|
|
1560
|
-
* @param {
|
|
2165
|
+
* @param {Element} element
|
|
1561
2166
|
* @param {ArbitraryValue} value
|
|
1562
2167
|
* @returns {ArbitraryValue}
|
|
1563
2168
|
*/
|
|
1564
|
-
set(
|
|
1565
|
-
elem = typeof
|
|
2169
|
+
set(element, value) {
|
|
2170
|
+
const elem = typeof element === 'string' ? $(element) : element;
|
|
2171
|
+
if (!elem) {
|
|
2172
|
+
throw new Error("Can't find the element");
|
|
2173
|
+
}
|
|
1566
2174
|
return super.set.call(this, elem, value);
|
|
1567
2175
|
}
|
|
1568
2176
|
/**
|
|
1569
|
-
* @param {string|Element}
|
|
2177
|
+
* @param {string|Element} element
|
|
1570
2178
|
* @param {string} methodName
|
|
1571
2179
|
* @param {...ArbitraryValue} args
|
|
1572
2180
|
* @returns {ArbitraryValue}
|
|
1573
2181
|
*/
|
|
1574
|
-
invoke(
|
|
1575
|
-
elem = typeof
|
|
2182
|
+
invoke(element, methodName, ...args) {
|
|
2183
|
+
const elem = typeof element === 'string' ? $(element) : element;
|
|
2184
|
+
if (!elem) {
|
|
2185
|
+
throw new Error("Can't find the element");
|
|
2186
|
+
}
|
|
1576
2187
|
return this.get(elem)[methodName](elem, ...args);
|
|
1577
2188
|
}
|
|
1578
2189
|
}
|
|
@@ -1580,14 +2191,12 @@ jml.Map = JamilihMap;
|
|
|
1580
2191
|
jml.WeakMap = JamilihWeakMap;
|
|
1581
2192
|
|
|
1582
2193
|
/**
|
|
1583
|
-
* @typedef {
|
|
1584
|
-
|
|
1585
|
-
* @property {Element} 1
|
|
1586
|
-
*/
|
|
2194
|
+
* @typedef {[JamilihWeakMap|JamilihMap, Element]} MapAndElementArray
|
|
2195
|
+
*/
|
|
1587
2196
|
|
|
1588
2197
|
/**
|
|
1589
|
-
* @param {
|
|
1590
|
-
* @param {
|
|
2198
|
+
* @param {{[key: string]: any}} obj
|
|
2199
|
+
* @param {JamilihArrayPostOptions} args
|
|
1591
2200
|
* @returns {MapAndElementArray}
|
|
1592
2201
|
*/
|
|
1593
2202
|
jml.weak = function (obj, ...args) {
|
|
@@ -1595,12 +2204,12 @@ jml.weak = function (obj, ...args) {
|
|
|
1595
2204
|
const elem = jml({
|
|
1596
2205
|
$map: [map, obj]
|
|
1597
2206
|
}, ...args);
|
|
1598
|
-
return [map, elem];
|
|
2207
|
+
return [map, /** @type {Element} */elem];
|
|
1599
2208
|
};
|
|
1600
2209
|
|
|
1601
2210
|
/**
|
|
1602
2211
|
* @param {ArbitraryValue} obj
|
|
1603
|
-
* @param {
|
|
2212
|
+
* @param {JamilihArrayPostOptions} args
|
|
1604
2213
|
* @returns {MapAndElementArray}
|
|
1605
2214
|
*/
|
|
1606
2215
|
jml.strong = function (obj, ...args) {
|
|
@@ -1608,22 +2217,28 @@ jml.strong = function (obj, ...args) {
|
|
|
1608
2217
|
const elem = jml({
|
|
1609
2218
|
$map: [map, obj]
|
|
1610
2219
|
}, ...args);
|
|
1611
|
-
return [map, elem];
|
|
2220
|
+
return [map, /** @type {Element} */elem];
|
|
1612
2221
|
};
|
|
1613
2222
|
|
|
1614
2223
|
/**
|
|
1615
|
-
* @param {string|Element}
|
|
2224
|
+
* @param {string|Element} element If a string, will be interpreted as a selector
|
|
1616
2225
|
* @param {symbol|string} sym If a string, will be used with `Symbol.for`
|
|
1617
2226
|
* @returns {ArbitraryValue} The value associated with the symbol
|
|
1618
2227
|
*/
|
|
1619
|
-
jml.symbol = jml.sym = jml.for = function (
|
|
1620
|
-
elem = typeof
|
|
2228
|
+
jml.symbol = jml.sym = jml.for = function (element, sym) {
|
|
2229
|
+
const elem = typeof element === 'string' ? $(element) : element;
|
|
2230
|
+
|
|
2231
|
+
// @ts-expect-error Should be ok
|
|
1621
2232
|
return elem[typeof sym === 'symbol' ? sym : Symbol.for(sym)];
|
|
1622
2233
|
};
|
|
1623
2234
|
|
|
1624
2235
|
/**
|
|
1625
|
-
* @
|
|
1626
|
-
|
|
2236
|
+
* @typedef {((elem: Element, ...args: any[]) => void)|{[key: string]: (elem: Element, ...args: any[]) => void}} MapCommand
|
|
2237
|
+
*/
|
|
2238
|
+
|
|
2239
|
+
/**
|
|
2240
|
+
* @param {?(string|Element)} elem If a string, will be interpreted as a selector
|
|
2241
|
+
* @param {symbol|string|Map<Element, MapCommand>|WeakMap<Element, MapCommand>} symOrMap If a string, will be used with `Symbol.for`
|
|
1627
2242
|
* @param {string|any} methodName Can be `any` if the symbol or map directly
|
|
1628
2243
|
* points to a function (it is then used as the first argument).
|
|
1629
2244
|
* @param {ArbitraryValue[]} args
|
|
@@ -1631,16 +2246,22 @@ jml.symbol = jml.sym = jml.for = function (elem, sym) {
|
|
|
1631
2246
|
*/
|
|
1632
2247
|
jml.command = function (elem, symOrMap, methodName, ...args) {
|
|
1633
2248
|
elem = typeof elem === 'string' ? $(elem) : elem;
|
|
2249
|
+
if (!elem) {
|
|
2250
|
+
throw new Error('No element found');
|
|
2251
|
+
}
|
|
1634
2252
|
let func;
|
|
1635
2253
|
if (['symbol', 'string'].includes(typeof symOrMap)) {
|
|
1636
|
-
func = jml.sym(elem, symOrMap);
|
|
2254
|
+
func = jml.sym(elem, /** @type {symbol|string} */symOrMap);
|
|
1637
2255
|
if (typeof func === 'function') {
|
|
1638
2256
|
return func(methodName, ...args); // Already has `this` bound to `elem`
|
|
1639
2257
|
}
|
|
1640
2258
|
|
|
1641
2259
|
return func[methodName](...args);
|
|
1642
2260
|
}
|
|
1643
|
-
func = symOrMap.get(elem);
|
|
2261
|
+
func = /** @type {Map<Element, MapCommand>|WeakMap<Element, MapCommand>} */symOrMap.get(elem);
|
|
2262
|
+
if (!func) {
|
|
2263
|
+
throw new Error('No map found');
|
|
2264
|
+
}
|
|
1644
2265
|
if (typeof func === 'function') {
|
|
1645
2266
|
return func.call(elem, methodName, ...args);
|
|
1646
2267
|
}
|
|
@@ -1651,42 +2272,51 @@ jml.command = function (elem, symOrMap, methodName, ...args) {
|
|
|
1651
2272
|
/**
|
|
1652
2273
|
* Expects properties `document`, `XMLSerializer`, and `DOMParser`.
|
|
1653
2274
|
* Also updates `body` with `document.body`.
|
|
1654
|
-
* @param {
|
|
2275
|
+
* @param {import('jsdom').DOMWindow|HTMLWindow} wind
|
|
1655
2276
|
* @returns {void}
|
|
1656
2277
|
*/
|
|
1657
2278
|
jml.setWindow = wind => {
|
|
1658
2279
|
win = wind;
|
|
1659
2280
|
doc = win.document;
|
|
1660
2281
|
if (doc && doc.body) {
|
|
1661
|
-
|
|
1662
|
-
|
|
1663
|
-
} = doc);
|
|
2282
|
+
// eslint-disable-next-line prefer-destructuring -- Needed for typing
|
|
2283
|
+
body = /** @type {HTMLBodyElement} */doc.body;
|
|
1664
2284
|
}
|
|
1665
2285
|
};
|
|
1666
2286
|
|
|
1667
2287
|
/**
|
|
1668
|
-
* @returns {
|
|
2288
|
+
* @returns {import('jsdom').DOMWindow|HTMLWindow}
|
|
1669
2289
|
*/
|
|
1670
2290
|
jml.getWindow = () => {
|
|
2291
|
+
if (!win) {
|
|
2292
|
+
throw new Error('No window object set');
|
|
2293
|
+
}
|
|
1671
2294
|
return win;
|
|
1672
2295
|
};
|
|
1673
2296
|
|
|
1674
2297
|
/**
|
|
1675
2298
|
* Does not run Jamilih so can be further processed.
|
|
1676
|
-
* @param {
|
|
1677
|
-
* @param {
|
|
1678
|
-
* @returns {
|
|
2299
|
+
* @param {ArbitraryValue[]} array
|
|
2300
|
+
* @param {ArbitraryValue} glu
|
|
2301
|
+
* @returns {ArbitraryValue[]}
|
|
1679
2302
|
*/
|
|
1680
|
-
function glue(
|
|
1681
|
-
return [...
|
|
2303
|
+
function glue(array, glu) {
|
|
2304
|
+
return [...array].reduce((arr, item) => {
|
|
1682
2305
|
arr.push(item, glu);
|
|
1683
2306
|
return arr;
|
|
1684
2307
|
}, []).slice(0, -1);
|
|
1685
2308
|
}
|
|
1686
2309
|
|
|
1687
|
-
|
|
1688
|
-
|
|
2310
|
+
/**
|
|
2311
|
+
* @type {HTMLBodyElement}
|
|
2312
|
+
*/
|
|
2313
|
+
let body; // eslint-disable-line import/no-mutable-exports
|
|
1689
2314
|
|
|
2315
|
+
/* c8 ignore next 3 */
|
|
2316
|
+
if (doc && doc.body) {
|
|
2317
|
+
// eslint-disable-next-line prefer-destructuring -- Needed for type
|
|
2318
|
+
body = /** @type {HTMLBodyElement} */doc.body;
|
|
2319
|
+
}
|
|
1690
2320
|
const nbsp = '\u00A0'; // Very commonly needed in templates
|
|
1691
2321
|
|
|
1692
|
-
export { $, $$, body, jml as default, glue, jml, nbsp };
|
|
2322
|
+
export { $, $$, DOMException, body, jml as default, glue, jml, nbsp };
|