@lambdatest/smartui-cli 2.0.1 → 2.0.3

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1,599 +1,609 @@
1
1
  (function() {
2
- (function (exports) {
3
- 'use strict';
4
-
5
- // Translates JavaScript properties of inputs into DOM attributes.
6
- function serializeInputElements(_ref) {
7
- let {
8
- dom,
9
- clone,
10
- warnings
11
- } = _ref;
12
- for (let elem of dom.querySelectorAll('input, textarea, select')) {
13
- let inputId = elem.getAttribute('data-smartui-element-id');
14
- let cloneEl = clone.querySelector(`[data-smartui-element-id="${inputId}"]`);
15
- switch (elem.type) {
16
- case 'checkbox':
17
- case 'radio':
18
- if (elem.checked) {
19
- cloneEl.setAttribute('checked', '');
20
- }
21
- break;
22
- case 'select-one':
23
- if (elem.selectedIndex !== -1) {
24
- cloneEl.options[elem.selectedIndex].setAttribute('selected', 'true');
25
- }
26
- break;
27
- case 'select-multiple':
28
- for (let option of elem.selectedOptions) {
29
- cloneEl.options[option.index].setAttribute('selected', 'true');
30
- }
31
- break;
32
- case 'textarea':
33
- cloneEl.innerHTML = elem.value;
34
- break;
35
- default:
36
- cloneEl.setAttribute('value', elem.value);
37
- }
2
+ (function (exports) {
3
+ 'use strict';
4
+
5
+ const process = (typeof globalThis !== "undefined" && globalThis.process) || {};
6
+ process.env = process.env || {};
7
+ process.env.__SMARTUI_BROWSERIFIED__ = true;
8
+
9
+ // Translates JavaScript properties of inputs into DOM attributes.
10
+ function serializeInputElements(_ref) {
11
+ let {
12
+ dom,
13
+ clone,
14
+ warnings
15
+ } = _ref;
16
+ for (let elem of dom.querySelectorAll('input, textarea, select')) {
17
+ let inputId = elem.getAttribute('data-smartui-element-id');
18
+ let cloneEl = clone.querySelector(`[data-smartui-element-id="${inputId}"]`);
19
+ switch (elem.type) {
20
+ case 'checkbox':
21
+ case 'radio':
22
+ if (elem.checked) {
23
+ cloneEl.setAttribute('checked', '');
24
+ }
25
+ break;
26
+ case 'select-one':
27
+ if (elem.selectedIndex !== -1) {
28
+ cloneEl.options[elem.selectedIndex].setAttribute('selected', 'true');
29
+ }
30
+ break;
31
+ case 'select-multiple':
32
+ for (let option of elem.selectedOptions) {
33
+ cloneEl.options[option.index].setAttribute('selected', 'true');
34
+ }
35
+ break;
36
+ case 'textarea':
37
+ cloneEl.innerHTML = elem.value;
38
+ break;
39
+ default:
40
+ cloneEl.setAttribute('value', elem.value);
38
41
  }
39
42
  }
40
-
41
- // Adds a `<base>` element to the serialized iframe's `<head>`. This is necessary when
42
- // embedded documents are serialized and their contents become root-relative.
43
- function setBaseURI(dom) {
44
- /* istanbul ignore if: sanity check */
45
- if (!new URL(dom.baseURI).hostname) return;
46
- let $base = document.createElement('base');
47
- $base.href = dom.baseURI;
48
- dom.querySelector('head').prepend($base);
49
- }
50
-
51
- // Recursively serializes iframe documents into srcdoc attributes.
52
- function serializeFrames(_ref) {
53
- let {
54
- dom,
55
- clone,
56
- warnings,
57
- resources,
58
- enableJavaScript,
59
- disableShadowDOM
60
- } = _ref;
61
- for (let frame of dom.querySelectorAll('iframe')) {
62
- var _clone$head;
63
- let smartuiElementId = frame.getAttribute('data-smartui-element-id');
64
- let cloneEl = clone.querySelector(`[data-smartui-element-id="${smartuiElementId}"]`);
65
- let builtWithJs = !frame.srcdoc && (!frame.src || frame.src.split(':')[0] === 'javascript');
66
-
67
- // delete frames within the head since they usually break pages when
68
- // rerendered and do not effect the visuals of a page
69
- if ((_clone$head = clone.head) !== null && _clone$head !== void 0 && _clone$head.contains(cloneEl)) {
70
- cloneEl.remove();
71
-
72
- // if the frame document is accessible and not empty, we can serialize it
73
- } else if (frame.contentDocument && frame.contentDocument.documentElement) {
74
- // js is enabled and this frame was built with js, don't serialize it
75
- if (enableJavaScript && builtWithJs) continue;
76
-
77
- // the frame has yet to load and wasn't built with js, it is unsafe to serialize
78
- if (!builtWithJs && !frame.contentWindow.performance.timing.loadEventEnd) continue;
79
-
80
- // recersively serialize contents
81
- let serialized = serializeDOM({
82
- domTransformation: setBaseURI,
83
- dom: frame.contentDocument,
84
- enableJavaScript,
85
- disableShadowDOM
86
- });
87
-
88
- // append serialized warnings and resources
89
- /* istanbul ignore next: warnings not implemented yet */
90
- for (let w of serialized.warnings) warnings.add(w);
91
- for (let r of serialized.resources) resources.add(r);
92
-
93
- // assign serialized html to srcdoc and remove src
94
- cloneEl.setAttribute('srcdoc', serialized.html);
95
- cloneEl.removeAttribute('src');
96
-
97
- // delete inaccessible frames built with js when js is disabled because they
98
- // break asset discovery by creating non-captured requests that hang
99
- } else if (!enableJavaScript && builtWithJs) {
100
- cloneEl.remove();
101
- }
43
+ }
44
+
45
+ // Adds a `<base>` element to the serialized iframe's `<head>`. This is necessary when
46
+ // embedded documents are serialized and their contents become root-relative.
47
+ function setBaseURI(dom) {
48
+ /* istanbul ignore if: sanity check */
49
+ if (!new URL(dom.baseURI).hostname) return;
50
+ let $base = document.createElement('base');
51
+ $base.href = dom.baseURI;
52
+ dom.querySelector('head').prepend($base);
53
+ }
54
+
55
+ // Recursively serializes iframe documents into srcdoc attributes.
56
+ function serializeFrames(_ref) {
57
+ let {
58
+ dom,
59
+ clone,
60
+ warnings,
61
+ resources,
62
+ enableJavaScript,
63
+ disableShadowDOM
64
+ } = _ref;
65
+ for (let frame of dom.querySelectorAll('iframe')) {
66
+ var _clone$head;
67
+ let smartuiElementId = frame.getAttribute('data-smartui-element-id');
68
+ let cloneEl = clone.querySelector(`[data-smartui-element-id="${smartuiElementId}"]`);
69
+ let builtWithJs = !frame.srcdoc && (!frame.src || frame.src.split(':')[0] === 'javascript');
70
+
71
+ // delete frames within the head since they usually break pages when
72
+ // rerendered and do not effect the visuals of a page
73
+ if ((_clone$head = clone.head) !== null && _clone$head !== void 0 && _clone$head.contains(cloneEl)) {
74
+ cloneEl.remove();
75
+
76
+ // if the frame document is accessible and not empty, we can serialize it
77
+ } else if (frame.contentDocument && frame.contentDocument.documentElement) {
78
+ // js is enabled and this frame was built with js, don't serialize it
79
+ if (enableJavaScript && builtWithJs) continue;
80
+
81
+ // the frame has yet to load and wasn't built with js, it is unsafe to serialize
82
+ if (!builtWithJs && !frame.contentWindow.performance.timing.loadEventEnd) continue;
83
+
84
+ // recersively serialize contents
85
+ let serialized = serializeDOM({
86
+ domTransformation: setBaseURI,
87
+ dom: frame.contentDocument,
88
+ enableJavaScript,
89
+ disableShadowDOM
90
+ });
91
+
92
+ // append serialized warnings and resources
93
+ /* istanbul ignore next: warnings not implemented yet */
94
+ // for (let w of serialized.warnings) warnings.add(w);
95
+ // for (let r of serialized.resources) resources.add(r);
96
+
97
+ // assign serialized html to srcdoc and remove src
98
+ cloneEl.setAttribute('srcdoc', serialized.html);
99
+ cloneEl.removeAttribute('src');
100
+
101
+ // delete inaccessible frames built with js when js is disabled because they
102
+ // break asset discovery by creating non-captured requests that hang
103
+ } else if (!enableJavaScript && builtWithJs) {
104
+ cloneEl.remove();
102
105
  }
103
106
  }
104
-
105
- // Creates a resource object from an element's unique ID and data URL
106
- function resourceFromDataURL(uid, dataURL) {
107
- // split dataURL into desired parts
108
- let [data, content] = dataURL.split(',');
109
- let [, mimetype] = data.split(':');
110
- [mimetype] = mimetype.split(';');
111
-
112
- // build a URL for the serialized asset
113
- let [, ext] = mimetype.split('/');
114
- let path = `/__serialized__/${uid}.${ext}`;
115
- let url = rewriteLocalhostURL(new URL(path, document.URL).toString());
116
-
117
- // return the url, base64 content, and mimetype
118
- return {
119
- url,
120
- content,
121
- mimetype
122
- };
123
- }
124
- function resourceFromText(uid, mimetype, data) {
125
- // build a URL for the serialized asset
126
- let [, ext] = mimetype.split('/');
127
- let path = `/__serialized__/${uid}.${ext}`;
128
- let url = rewriteLocalhostURL(new URL(path, document.URL).toString());
129
- // return the url, text content, and mimetype
130
- return {
131
- url,
132
- content: data,
133
- mimetype
134
- };
135
- }
136
- function styleSheetFromNode(node) {
137
- /* istanbul ignore if: sanity check */
138
- if (node.sheet) return node.sheet;
139
-
140
- // Cloned style nodes don't have a sheet instance unless they are within
141
- // a document; we get it by temporarily adding the rules to DOM
142
- const tempStyle = node.cloneNode();
143
- tempStyle.setAttribute('data-smartui-style-helper', '');
144
- tempStyle.innerHTML = node.innerHTML;
145
- const clone = document.cloneNode();
146
- clone.appendChild(tempStyle);
147
- const sheet = tempStyle.sheet;
148
- // Cleanup node
149
- tempStyle.remove();
150
- return sheet;
107
+ }
108
+
109
+ // Creates a resource object from an element's unique ID and data URL
110
+ function resourceFromDataURL(uid, dataURL) {
111
+ // split dataURL into desired parts
112
+ let [data, content] = dataURL.split(',');
113
+ let [, mimetype] = data.split(':');
114
+ [mimetype] = mimetype.split(';');
115
+
116
+ // build a URL for the serialized asset
117
+ let [, ext] = mimetype.split('/');
118
+ let path = `/__serialized__/${uid}.${ext}`;
119
+ let url = rewriteLocalhostURL(new URL(path, document.URL).toString());
120
+
121
+ // return the url, base64 content, and mimetype
122
+ return {
123
+ url,
124
+ content,
125
+ mimetype
126
+ };
127
+ }
128
+ function resourceFromText(uid, mimetype, data) {
129
+ // build a URL for the serialized asset
130
+ let [, ext] = mimetype.split('/');
131
+ let path = `/__serialized__/${uid}.${ext}`;
132
+ let url = rewriteLocalhostURL(new URL(path, document.URL).toString());
133
+ // return the url, text content, and mimetype
134
+ return {
135
+ url,
136
+ content: data,
137
+ mimetype
138
+ };
139
+ }
140
+ function styleSheetFromNode(node) {
141
+ /* istanbul ignore if: sanity check */
142
+ if (node.sheet) return node.sheet;
143
+
144
+ // Cloned style nodes don't have a sheet instance unless they are within
145
+ // a document; we get it by temporarily adding the rules to DOM
146
+ const tempStyle = node.cloneNode();
147
+ tempStyle.setAttribute('data-smartui-style-helper', '');
148
+ tempStyle.innerHTML = node.innerHTML;
149
+ const clone = document.cloneNode();
150
+ clone.appendChild(tempStyle);
151
+ const sheet = tempStyle.sheet;
152
+ // Cleanup node
153
+ tempStyle.remove();
154
+ return sheet;
155
+ }
156
+ function rewriteLocalhostURL(url) {
157
+ return url.replace(/(http[s]{0,1}:\/\/)localhost[:\d+]*/, '$1render.smartui.local');
158
+ }
159
+
160
+ // Returns a mostly random uid.
161
+ function uid() {
162
+ return `_${Math.random().toString(36).substr(2, 9)}`;
163
+ }
164
+ function markElement(domElement, disableShadowDOM) {
165
+ var _domElement$tagName;
166
+ // Mark elements that are to be serialized later with a data attribute.
167
+ if (['input', 'textarea', 'select', 'iframe', 'canvas', 'video', 'style'].includes((_domElement$tagName = domElement.tagName) === null || _domElement$tagName === void 0 ? void 0 : _domElement$tagName.toLowerCase())) {
168
+ if (!domElement.getAttribute('data-smartui-element-id')) {
169
+ domElement.setAttribute('data-smartui-element-id', uid());
170
+ }
151
171
  }
152
- function rewriteLocalhostURL(url) {
153
- return url.replace(/(http[s]{0,1}:\/\/)localhost[:\d+]*/, '$1render.smartui.local');
172
+
173
+ // add special marker for shadow host
174
+ if (!disableShadowDOM && domElement.shadowRoot) {
175
+ domElement.setAttribute('data-smartui-shadow-host', '');
176
+ if (!domElement.getAttribute('data-smartui-element-id')) {
177
+ domElement.setAttribute('data-smartui-element-id', uid());
178
+ }
154
179
  }
155
-
156
- // Returns a mostly random uid.
157
- function uid() {
158
- return `_${Math.random().toString(36).substr(2, 9)}`;
180
+ }
181
+
182
+ // Returns true if a stylesheet is a CSSOM-based stylesheet.
183
+ function isCSSOM(styleSheet) {
184
+ // no href, has a rulesheet, and has an owner node
185
+ return !styleSheet.href && styleSheet.cssRules && styleSheet.ownerNode;
186
+ }
187
+
188
+ // Returns false if any stylesheet rules do not match between two stylesheets
189
+ function styleSheetsMatch(sheetA, sheetB) {
190
+ for (let i = 0; i < sheetA.cssRules.length; i++) {
191
+ var _sheetB$cssRules$i;
192
+ let ruleA = sheetA.cssRules[i].cssText;
193
+ let ruleB = (_sheetB$cssRules$i = sheetB.cssRules[i]) === null || _sheetB$cssRules$i === void 0 ? void 0 : _sheetB$cssRules$i.cssText;
194
+ if (ruleA !== ruleB) return false;
159
195
  }
160
- function markElement(domElement, disableShadowDOM) {
161
- var _domElement$tagName;
162
- // Mark elements that are to be serialized later with a data attribute.
163
- if (['input', 'textarea', 'select', 'iframe', 'canvas', 'video', 'style'].includes((_domElement$tagName = domElement.tagName) === null || _domElement$tagName === void 0 ? void 0 : _domElement$tagName.toLowerCase())) {
164
- if (!domElement.getAttribute('data-smartui-element-id')) {
165
- domElement.setAttribute('data-smartui-element-id', uid());
196
+ return true;
197
+ }
198
+ function createStyleResource(styleSheet) {
199
+ const styles = Array.from(styleSheet.cssRules).map(cssRule => cssRule.cssText).join('\n');
200
+ let resource = resourceFromText(uid(), 'text/css', styles);
201
+ return resource;
202
+ }
203
+ function serializeCSSOM(_ref) {
204
+ let {
205
+ dom,
206
+ clone,
207
+ resources,
208
+ cache,
209
+ warnings
210
+ } = _ref;
211
+ // in-memory CSSOM into their respective DOM nodes.
212
+ for (let styleSheet of dom.styleSheets) {
213
+ var _styleSheet$href;
214
+ if (isCSSOM(styleSheet)) {
215
+ let styleId = styleSheet.ownerNode.getAttribute('data-smartui-element-id');
216
+ let cloneOwnerNode = clone.querySelector(`[data-smartui-element-id="${styleId}"]`);
217
+ if (styleSheetsMatch(styleSheet, styleSheetFromNode(cloneOwnerNode))) continue;
218
+ let style = document.createElement('style');
219
+ style.type = 'text/css';
220
+ style.setAttribute('data-smartui-element-id', styleId);
221
+ style.setAttribute('data-smartui-cssom-serialized', 'true');
222
+ style.innerHTML = Array.from(styleSheet.cssRules).map(cssRule => cssRule.cssText).join('\n');
223
+ cloneOwnerNode.parentNode.insertBefore(style, cloneOwnerNode.nextSibling);
224
+ cloneOwnerNode.remove();
225
+ } else if ((_styleSheet$href = styleSheet.href) !== null && _styleSheet$href !== void 0 && _styleSheet$href.startsWith('blob:')) {
226
+ const styleLink = document.createElement('link');
227
+ styleLink.setAttribute('rel', 'stylesheet');
228
+ let resource = createStyleResource(styleSheet);
229
+ resources.add(resource);
230
+ styleLink.setAttribute('data-smartui-blob-stylesheets-serialized', 'true');
231
+ styleLink.setAttribute('data-smartui-serialized-attribute-href', resource.url);
232
+
233
+ /* istanbul ignore next: tested, but coverage is stripped */
234
+ if (clone.constructor.name === 'HTMLDocument' || clone.constructor.name === 'DocumentFragment') {
235
+ // handle document and iframe
236
+ clone.body.prepend(styleLink);
237
+ } else if (clone.constructor.name === 'ShadowRoot') {
238
+ clone.prepend(styleLink);
166
239
  }
167
240
  }
168
-
169
- // add special marker for shadow host
170
- if (!disableShadowDOM && domElement.shadowRoot) {
171
- domElement.setAttribute('data-smartui-shadow-host', '');
172
- if (!domElement.getAttribute('data-smartui-element-id')) {
173
- domElement.setAttribute('data-smartui-element-id', uid());
241
+ }
242
+
243
+ // clone Adopted Stylesheets
244
+ // Regarding ordering of the adopted stylesheets - https://github.com/WICG/construct-stylesheets/issues/93
245
+ /* istanbul ignore next: tested, but coverage is stripped */
246
+ if (dom.adoptedStyleSheets) {
247
+ for (let sheet of dom.adoptedStyleSheets) {
248
+ const styleLink = document.createElement('link');
249
+ styleLink.setAttribute('rel', 'stylesheet');
250
+ if (!cache.has(sheet)) {
251
+ let resource = createStyleResource(sheet);
252
+ resources.add(resource);
253
+ cache.set(sheet, resource.url);
254
+ }
255
+ styleLink.setAttribute('data-smartui-adopted-stylesheets-serialized', 'true');
256
+ styleLink.setAttribute('data-smartui-serialized-attribute-href', cache.get(sheet));
257
+
258
+ /* istanbul ignore next: tested, but coverage is stripped */
259
+ if (clone.constructor.name === 'HTMLDocument' || clone.constructor.name === 'DocumentFragment') {
260
+ // handle document and iframe
261
+ clone.body.prepend(styleLink);
262
+ } else if (clone.constructor.name === 'ShadowRoot') {
263
+ clone.prepend(styleLink);
174
264
  }
175
265
  }
266
+ } else {
267
+ warnings.add('Skipping `adoptedStyleSheets` as it is not supported.');
176
268
  }
177
-
178
- // Returns true if a stylesheet is a CSSOM-based stylesheet.
179
- function isCSSOM(styleSheet) {
180
- // no href, has a rulesheet, and has an owner node
181
- return !styleSheet.href && styleSheet.cssRules && styleSheet.ownerNode;
182
- }
183
-
184
- // Returns false if any stylesheet rules do not match between two stylesheets
185
- function styleSheetsMatch(sheetA, sheetB) {
186
- for (let i = 0; i < sheetA.cssRules.length; i++) {
187
- var _sheetB$cssRules$i;
188
- let ruleA = sheetA.cssRules[i].cssText;
189
- let ruleB = (_sheetB$cssRules$i = sheetB.cssRules[i]) === null || _sheetB$cssRules$i === void 0 ? void 0 : _sheetB$cssRules$i.cssText;
190
- if (ruleA !== ruleB) return false;
269
+ }
270
+
271
+ // Serialize in-memory canvas elements into images.
272
+ function serializeCanvas(_ref) {
273
+ let {
274
+ dom,
275
+ clone,
276
+ resources
277
+ } = _ref;
278
+ for (let canvas of dom.querySelectorAll('canvas')) {
279
+ // Note: the `.toDataURL` API requires WebGL canvas elements to use
280
+ // `preserveDrawingBuffer: true`. This is because `.toDataURL` uses the
281
+ // drawing buffer, which is cleared after each render for WebGL by default.
282
+ let dataUrl = canvas.toDataURL();
283
+
284
+ // skip empty canvases
285
+ if (!dataUrl || dataUrl === 'data:,') continue;
286
+
287
+ // get the element's smartui id and create a resource for it
288
+ let smartuiElementId = canvas.getAttribute('data-smartui-element-id');
289
+ // let resource = resourceFromDataURL(smartuiElementId, dataUrl);
290
+ // resources.add(resource);
291
+
292
+ // create an image element in the cloned dom
293
+ let img = document.createElement('img');
294
+ // use a data attribute to avoid making a real request
295
+ // img.setAttribute('data-smartui-serialized-attribute-src', resource.url);
296
+ img.setAttribute('src', dataUrl);
297
+
298
+ // copy canvas element attributes to the image element such as style, class,
299
+ // or data attributes that may be targeted by CSS
300
+ for (let {
301
+ name,
302
+ value
303
+ } of canvas.attributes) {
304
+ img.setAttribute(name, value);
191
305
  }
192
- return true;
193
- }
194
- function createStyleResource(styleSheet) {
195
- const styles = Array.from(styleSheet.cssRules).map(cssRule => cssRule.cssText).join('\n');
196
- let resource = resourceFromText(uid(), 'text/css', styles);
197
- return resource;
306
+
307
+ // mark the image as serialized (can be targeted by CSS)
308
+ img.setAttribute('data-smartui-canvas-serialized', 'test');
309
+ // set a default max width to account for canvases that might resize with JS
310
+ img.style.maxWidth = img.style.maxWidth || '100%';
311
+
312
+ // insert the image into the cloned DOM and remove the cloned canvas element
313
+ let cloneEl = clone.querySelector(`[data-smartui-element-id=${smartuiElementId}]`);
314
+ // `parentElement` for elements directly under shadow root is `null` -> Incase of Nested Shadow DOM.
315
+ if (cloneEl.parentElement) {
316
+ cloneEl.parentElement.insertBefore(img, cloneEl);
317
+ } else {
318
+ clone.insertBefore(img, cloneEl);
319
+ }
320
+ cloneEl.remove();
198
321
  }
199
- function serializeCSSOM(_ref) {
200
- let {
201
- dom,
202
- clone,
203
- resources,
204
- cache,
205
- warnings
206
- } = _ref;
207
- // in-memory CSSOM into their respective DOM nodes.
208
- for (let styleSheet of dom.styleSheets) {
209
- var _styleSheet$href;
210
- if (isCSSOM(styleSheet)) {
211
- let styleId = styleSheet.ownerNode.getAttribute('data-smartui-element-id');
212
- let cloneOwnerNode = clone.querySelector(`[data-smartui-element-id="${styleId}"]`);
213
- if (styleSheetsMatch(styleSheet, styleSheetFromNode(cloneOwnerNode))) continue;
214
- let style = document.createElement('style');
215
- style.type = 'text/css';
216
- style.setAttribute('data-smartui-element-id', styleId);
217
- style.setAttribute('data-smartui-cssom-serialized', 'true');
218
- style.innerHTML = Array.from(styleSheet.cssRules).map(cssRule => cssRule.cssText).join('\n');
219
- cloneOwnerNode.parentNode.insertBefore(style, cloneOwnerNode.nextSibling);
220
- cloneOwnerNode.remove();
221
- } else if ((_styleSheet$href = styleSheet.href) !== null && _styleSheet$href !== void 0 && _styleSheet$href.startsWith('blob:')) {
222
- const styleLink = document.createElement('link');
223
- styleLink.setAttribute('rel', 'stylesheet');
224
- let resource = createStyleResource(styleSheet);
225
- resources.add(resource);
226
- styleLink.setAttribute('data-smartui-blob-stylesheets-serialized', 'true');
227
- styleLink.setAttribute('data-smartui-serialized-attribute-href', resource.url);
228
-
229
- /* istanbul ignore next: tested, but coverage is stripped */
230
- if (clone.constructor.name === 'HTMLDocument' || clone.constructor.name === 'DocumentFragment') {
231
- // handle document and iframe
232
- clone.body.prepend(styleLink);
233
- } else if (clone.constructor.name === 'ShadowRoot') {
234
- clone.prepend(styleLink);
235
- }
236
- }
322
+ }
323
+
324
+ // Captures the current frame of videos and sets the poster image
325
+ function serializeVideos(_ref) {
326
+ let {
327
+ dom,
328
+ clone,
329
+ resources,
330
+ warnings
331
+ } = _ref;
332
+ for (let video of dom.querySelectorAll('video')) {
333
+ let videoId = video.getAttribute('data-smartui-element-id');
334
+ let cloneEl = clone.querySelector(`[data-smartui-element-id="${videoId}"]`);
335
+ // if the video already has a poster image, no work for us to do
336
+ if (video.getAttribute('poster')) {
337
+ cloneEl.removeAttribute('src');
338
+ continue;
237
339
  }
238
-
239
- // clone Adopted Stylesheets
240
- // Regarding ordering of the adopted stylesheets - https://github.com/WICG/construct-stylesheets/issues/93
241
- /* istanbul ignore next: tested, but coverage is stripped */
242
- if (dom.adoptedStyleSheets) {
243
- for (let sheet of dom.adoptedStyleSheets) {
244
- const styleLink = document.createElement('link');
245
- styleLink.setAttribute('rel', 'stylesheet');
246
- if (!cache.has(sheet)) {
247
- let resource = createStyleResource(sheet);
248
- resources.add(resource);
249
- cache.set(sheet, resource.url);
250
- }
251
- styleLink.setAttribute('data-smartui-adopted-stylesheets-serialized', 'true');
252
- styleLink.setAttribute('data-smartui-serialized-attribute-href', cache.get(sheet));
253
-
254
- /* istanbul ignore next: tested, but coverage is stripped */
255
- if (clone.constructor.name === 'HTMLDocument' || clone.constructor.name === 'DocumentFragment') {
256
- // handle document and iframe
257
- clone.body.prepend(styleLink);
258
- } else if (clone.constructor.name === 'ShadowRoot') {
259
- clone.prepend(styleLink);
260
- }
261
- }
262
- } else {
263
- warnings.add('Skipping `adoptedStyleSheets` as it is not supported.');
340
+ let canvas = document.createElement('canvas');
341
+ let width = canvas.width = video.videoWidth;
342
+ let height = canvas.height = video.videoHeight;
343
+ let dataUrl;
344
+ canvas.getContext('2d').drawImage(video, 0, 0, width, height);
345
+ try {
346
+ dataUrl = canvas.toDataURL();
347
+ } catch (e) {
348
+ warnings.add(`data-smartui-element-id="${videoId}" : ${e.toString()}`);
264
349
  }
350
+
351
+ // if the canvas produces a blank image, skip
352
+ if (!dataUrl || dataUrl === 'data:,') continue;
353
+
354
+ // create a resource from the serialized data url
355
+ // let resource = resourceFromDataURL(videoId, dataUrl);
356
+ // resources.add(resource);
357
+
358
+ // use a data attribute to avoid making a real request
359
+ cloneEl.removeAttribute('src');
360
+ cloneEl.setAttribute('poster', dataUrl);
265
361
  }
266
-
267
- // Serialize in-memory canvas elements into images.
268
- function serializeCanvas(_ref) {
269
- let {
270
- dom,
271
- clone,
272
- resources
273
- } = _ref;
274
- for (let canvas of dom.querySelectorAll('canvas')) {
275
- // Note: the `.toDataURL` API requires WebGL canvas elements to use
276
- // `preserveDrawingBuffer: true`. This is because `.toDataURL` uses the
277
- // drawing buffer, which is cleared after each render for WebGL by default.
278
- let dataUrl = canvas.toDataURL();
279
-
280
- // skip empty canvases
281
- if (!dataUrl || dataUrl === 'data:,') continue;
282
-
283
- // get the element's smartui id and create a resource for it
284
- let smartuiElementId = canvas.getAttribute('data-smartui-element-id');
285
- let resource = resourceFromDataURL(smartuiElementId, dataUrl);
286
- resources.add(resource);
287
-
288
- // create an image element in the cloned dom
289
- let img = document.createElement('img');
290
- // use a data attribute to avoid making a real request
291
- img.setAttribute('data-smartui-serialized-attribute-src', resource.url);
292
-
293
- // copy canvas element attributes to the image element such as style, class,
294
- // or data attributes that may be targeted by CSS
295
- for (let {
296
- name,
297
- value
298
- } of canvas.attributes) {
299
- img.setAttribute(name, value);
362
+ }
363
+
364
+ // Drop loading attribute. We do not scroll page in discovery stage but we want to make sure that
365
+ // all resources are requested, so we drop loading attribute [as it can be set to lazy]
366
+ function dropLoadingAttribute(domElement) {
367
+ var _domElement$tagName;
368
+ if (!['img', 'iframe'].includes((_domElement$tagName = domElement.tagName) === null || _domElement$tagName === void 0 ? void 0 : _domElement$tagName.toLowerCase())) return;
369
+ domElement.removeAttribute('loading');
370
+ }
371
+
372
+ // All transformations that we need to apply for a successful discovery and stable render
373
+ function applyElementTransformations(domElement) {
374
+ dropLoadingAttribute(domElement);
375
+ }
376
+
377
+ /**
378
+ * Custom deep clone function that replaces SmartUI's current clone behavior.
379
+ * This enables us to capture shadow DOM in snapshots. It takes advantage of `attachShadow`'s mode option set to open
380
+ * https://developer.mozilla.org/en-US/docs/Web/API/Element/attachShadow#parameters
381
+ */
382
+
383
+ /**
384
+ * Deep clone a document while also preserving shadow roots
385
+ * returns document fragment
386
+ */
387
+
388
+ const ignoreTags = ['NOSCRIPT'];
389
+ function cloneNodeAndShadow(_ref) {
390
+ let {
391
+ dom,
392
+ disableShadowDOM
393
+ } = _ref;
394
+ // clones shadow DOM and light DOM for a given node
395
+ let cloneNode = (node, parent) => {
396
+ let walkTree = (nextn, nextp) => {
397
+ while (nextn) {
398
+ if (!ignoreTags.includes(nextn.nodeName)) {
399
+ cloneNode(nextn, nextp);
400
+ }
401
+ nextn = nextn.nextSibling;
300
402
  }
301
-
302
- // mark the image as serialized (can be targeted by CSS)
303
- img.setAttribute('data-smartui-canvas-serialized', '');
304
- // set a default max width to account for canvases that might resize with JS
305
- img.style.maxWidth = img.style.maxWidth || '100%';
306
-
307
- // insert the image into the cloned DOM and remove the cloned canvas element
308
- let cloneEl = clone.querySelector(`[data-smartui-element-id=${smartuiElementId}]`);
309
- // `parentElement` for elements directly under shadow root is `null` -> Incase of Nested Shadow DOM.
310
- if (cloneEl.parentElement) {
311
- cloneEl.parentElement.insertBefore(img, cloneEl);
403
+ };
404
+
405
+ // mark the node before cloning
406
+ markElement(node, disableShadowDOM);
407
+ let clone = node.cloneNode();
408
+
409
+ // We apply any element transformations here to avoid another treeWalk
410
+ applyElementTransformations(clone);
411
+ parent.appendChild(clone);
412
+
413
+ // shallow clone should not contain children
414
+ if (clone.children) {
415
+ Array.from(clone.children).forEach(child => clone.removeChild(child));
416
+ }
417
+
418
+ // clone shadow DOM
419
+ if (node.shadowRoot && !disableShadowDOM) {
420
+ // create shadowRoot
421
+ if (clone.shadowRoot) {
422
+ // it may be set up in a custom element's constructor
423
+ clone.shadowRoot.innerHTML = '';
312
424
  } else {
313
- clone.insertBefore(img, cloneEl);
425
+ clone.attachShadow({
426
+ mode: 'open'
427
+ });
314
428
  }
315
- cloneEl.remove();
429
+ // clone dom elements
430
+ walkTree(node.shadowRoot.firstChild, clone.shadowRoot);
316
431
  }
432
+
433
+ // clone light DOM
434
+ walkTree(node.firstChild, clone);
435
+ };
436
+ let fragment = dom.createDocumentFragment();
437
+ cloneNode(dom.documentElement, fragment);
438
+ fragment.documentElement = fragment.firstChild;
439
+ fragment.head = fragment.querySelector('head');
440
+ fragment.body = fragment.querySelector('body');
441
+ return fragment;
442
+ }
443
+
444
+ /**
445
+ * Use `getInnerHTML()` to serialize shadow dom as <template> tags. `innerHTML` and `outerHTML` don't do this. Buzzword: "declarative shadow dom"
446
+ */
447
+ function getOuterHTML(docElement) {
448
+ // firefox doesn't serialize shadow DOM, we're awaiting API's by firefox to become ready and are not polyfilling it.
449
+ if (!docElement.getInnerHTML) {
450
+ return docElement.outerHTML;
317
451
  }
318
-
319
- // Captures the current frame of videos and sets the poster image
320
- function serializeVideos(_ref) {
321
- let {
322
- dom,
323
- clone,
324
- resources,
325
- warnings
326
- } = _ref;
327
- for (let video of dom.querySelectorAll('video')) {
328
- // if the video already has a poster image, no work for us to do
329
- if (video.getAttribute('poster')) continue;
330
- let videoId = video.getAttribute('data-smartui-element-id');
331
- let cloneEl = clone.querySelector(`[data-smartui-element-id="${videoId}"]`);
332
- let canvas = document.createElement('canvas');
333
- let width = canvas.width = video.videoWidth;
334
- let height = canvas.height = video.videoHeight;
335
- let dataUrl;
336
- canvas.getContext('2d').drawImage(video, 0, 0, width, height);
337
- try {
338
- dataUrl = canvas.toDataURL();
339
- } catch (e) {
340
- warnings.add(`data-smartui-element-id="${videoId}" : ${e.toString()}`);
341
- }
342
-
343
- // if the canvas produces a blank image, skip
344
- if (!dataUrl || dataUrl === 'data:,') continue;
345
-
346
- // create a resource from the serialized data url
347
- let resource = resourceFromDataURL(videoId, dataUrl);
348
- resources.add(resource);
349
-
350
- // use a data attribute to avoid making a real request
351
- cloneEl.setAttribute('data-smartui-serialized-attribute-poster', resource.url);
352
- }
452
+ // chromium gives us declarative shadow DOM serialization API
453
+ let innerHTML = docElement.getInnerHTML({
454
+ includeShadowRoots: true
455
+ });
456
+ docElement.textContent = '';
457
+ // Note: Here we are specifically passing replacer function to avoid any replacements due to
458
+ // special characters in client's dom like $&
459
+ return docElement.outerHTML.replace('</html>', () => `${innerHTML}</html>`);
460
+ }
461
+
462
+ // we inject declarative shadow dom polyfill to allow shadow dom to load in non chromium infrastructure browsers
463
+ // Since only chromium currently supports declarative shadow DOM - https://caniuse.com/declarative-shadow-dom
464
+ function injectDeclarativeShadowDOMPolyfill(ctx) {
465
+ let clone = ctx.clone;
466
+ let scriptEl = document.createElement('script');
467
+ scriptEl.setAttribute('id', '__smartui_shadowdom_helper');
468
+ scriptEl.setAttribute('data-smartui-injected', true);
469
+ scriptEl.innerHTML = `
470
+ function reversePolyFill(root=document){
471
+ root.querySelectorAll('template[shadowroot]').forEach(template => {
472
+ const mode = template.getAttribute('shadowroot');
473
+ const shadowRoot = template.parentNode.attachShadow({ mode });
474
+ shadowRoot.appendChild(template.content);
475
+ template.remove();
476
+ });
477
+
478
+ root.querySelectorAll('[data-smartui-shadow-host]').forEach(shadowHost => reversePolyFill(shadowHost.shadowRoot));
353
479
  }
354
-
355
- // Drop loading attribute. We do not scroll page in discovery stage but we want to make sure that
356
- // all resources are requested, so we drop loading attribute [as it can be set to lazy]
357
- function dropLoadingAttribute(domElement) {
358
- var _domElement$tagName;
359
- if (!['img', 'iframe'].includes((_domElement$tagName = domElement.tagName) === null || _domElement$tagName === void 0 ? void 0 : _domElement$tagName.toLowerCase())) return;
360
- domElement.removeAttribute('loading');
480
+
481
+ if (["interactive", "complete"].includes(document.readyState)) {
482
+ reversePolyFill();
483
+ } else {
484
+ document.addEventListener("DOMContentLoaded", () => reversePolyFill());
361
485
  }
362
-
363
- // All transformations that we need to apply for a successful discovery and stable render
364
- function applyElementTransformations(domElement) {
365
- dropLoadingAttribute(domElement);
486
+ `.replace(/(\n|\s{2}|\t)/g, '');
487
+
488
+ // run polyfill as first thing post dom content is loaded
489
+ clone.head.prepend(scriptEl);
490
+ }
491
+
492
+ // Returns a copy or new doctype for a document.
493
+ function doctype(dom) {
494
+ let {
495
+ name = 'html',
496
+ publicId = '',
497
+ systemId = ''
498
+ } = (dom === null || dom === void 0 ? void 0 : dom.doctype) ?? {};
499
+ let deprecated = '';
500
+ if (publicId && systemId) {
501
+ deprecated = ` PUBLIC "${publicId}" "${systemId}"`;
502
+ } else if (publicId) {
503
+ deprecated = ` PUBLIC "${publicId}"`;
504
+ } else if (systemId) {
505
+ deprecated = ` SYSTEM "${systemId}"`;
366
506
  }
367
-
368
- /**
369
- * Custom deep clone function that replaces smartui's current clone behavior.
370
- * This enables us to capture shadow DOM in snapshots. It takes advantage of `attachShadow`'s mode option set to open
371
- * https://developer.mozilla.org/en-US/docs/Web/API/Element/attachShadow#parameters
372
- */
373
-
374
- /**
375
- * Deep clone a document while also preserving shadow roots
376
- * returns document fragment
377
- */
378
-
379
- const ignoreTags = ['NOSCRIPT'];
380
- function cloneNodeAndShadow(_ref) {
381
- let {
382
- dom,
383
- disableShadowDOM
384
- } = _ref;
385
- // clones shadow DOM and light DOM for a given node
386
- let cloneNode = (node, parent) => {
387
- let walkTree = (nextn, nextp) => {
388
- while (nextn) {
389
- if (!ignoreTags.includes(nextn.nodeName)) {
390
- cloneNode(nextn, nextp);
391
- }
392
- nextn = nextn.nextSibling;
393
- }
394
- };
395
-
396
- // mark the node before cloning
397
- markElement(node, disableShadowDOM);
398
- let clone = node.cloneNode();
399
-
400
- // We apply any element transformations here to avoid another treeWalk
401
- applyElementTransformations(clone);
402
- parent.appendChild(clone);
403
-
404
- // shallow clone should not contain children
405
- if (clone.children) {
406
- Array.from(clone.children).forEach(child => clone.removeChild(child));
407
- }
408
-
409
- // clone shadow DOM
410
- if (node.shadowRoot && !disableShadowDOM) {
411
- // create shadowRoot
412
- if (clone.shadowRoot) {
413
- // it may be set up in a custom element's constructor
414
- clone.shadowRoot.innerHTML = '';
415
- } else {
416
- clone.attachShadow({
417
- mode: 'open'
418
- });
419
- }
420
- // clone dom elements
421
- walkTree(node.shadowRoot.firstChild, clone.shadowRoot);
422
- }
423
-
424
- // clone light DOM
425
- walkTree(node.firstChild, clone);
426
- };
427
- let fragment = dom.createDocumentFragment();
428
- cloneNode(dom.documentElement, fragment);
429
- fragment.documentElement = fragment.firstChild;
430
- fragment.head = fragment.querySelector('head');
431
- fragment.body = fragment.querySelector('body');
432
- return fragment;
507
+ return `<!DOCTYPE ${name}${deprecated}>`;
508
+ }
509
+
510
+ // Serializes and returns the cloned DOM as an HTML string
511
+ function serializeHTML(ctx) {
512
+ let html = getOuterHTML(ctx.clone.documentElement);
513
+ // replace serialized data attributes with real attributes
514
+ html = html.replace(/ data-smartui-serialized-attribute-(\w+?)=/ig, ' $1=');
515
+ // include the doctype with the html string
516
+ return doctype(ctx.dom) + html;
517
+ }
518
+ function serializeElements(ctx) {
519
+ serializeInputElements(ctx);
520
+ serializeFrames(ctx);
521
+ serializeVideos(ctx);
522
+ if (!ctx.enableJavaScript) {
523
+ serializeCSSOM(ctx);
524
+ serializeCanvas(ctx);
433
525
  }
434
-
435
- /**
436
- * Use `getInnerHTML()` to serialize shadow dom as <template> tags. `innerHTML` and `outerHTML` don't do this. Buzzword: "declarative shadow dom"
437
- */
438
- function getOuterHTML(docElement) {
439
- // firefox doesn't serialize shadow DOM, we're awaiting API's by firefox to become ready and are not polyfilling it.
440
- if (!docElement.getInnerHTML) {
441
- return docElement.outerHTML;
442
- }
443
- // chromium gives us declarative shadow DOM serialization API
444
- let innerHTML = docElement.getInnerHTML({
445
- includeShadowRoots: true
446
- });
447
- docElement.textContent = '';
448
- // Note: Here we are specifically passing replacer function to avoid any replacements due to
449
- // special characters in client's dom like $&
450
- return docElement.outerHTML.replace('</html>', () => `${innerHTML}</html>`);
451
- }
452
-
453
- // we inject declarative shadow dom polyfill to allow shadow dom to load in non chromium infrastructure browsers
454
- // Since only chromium currently supports declarative shadow DOM - https://caniuse.com/declarative-shadow-dom
455
- function injectDeclarativeShadowDOMPolyfill(ctx) {
456
- let clone = ctx.clone;
457
- let scriptEl = document.createElement('script');
458
- scriptEl.setAttribute('id', '__smartui_shadowdom_helper');
459
- scriptEl.setAttribute('data-smartui-injected', true);
460
- scriptEl.innerHTML = `
461
- function reversePolyFill(root=document){
462
- root.querySelectorAll('template[shadowroot]').forEach(template => {
463
- const mode = template.getAttribute('shadowroot');
464
- const shadowRoot = template.parentNode.attachShadow({ mode });
465
- shadowRoot.appendChild(template.content);
466
- template.remove();
526
+ for (const shadowHost of ctx.dom.querySelectorAll('[data-smartui-shadow-host]')) {
527
+ let smartuiElementId = shadowHost.getAttribute('data-smartui-element-id');
528
+ let cloneShadowHost = ctx.clone.querySelector(`[data-smartui-element-id="${smartuiElementId}"]`);
529
+ if (shadowHost.shadowRoot && cloneShadowHost.shadowRoot) {
530
+ serializeElements({
531
+ ...ctx,
532
+ dom: shadowHost.shadowRoot,
533
+ clone: cloneShadowHost.shadowRoot
467
534
  });
468
-
469
- root.querySelectorAll('[data-smartui-shadow-host]').forEach(shadowHost => reversePolyFill(shadowHost.shadowRoot));
470
- }
471
-
472
- if (["interactive", "complete"].includes(document.readyState)) {
473
- reversePolyFill();
474
535
  } else {
475
- document.addEventListener("DOMContentLoaded", () => reversePolyFill());
536
+ ctx.warnings.add('data-smartui-shadow-host does not have shadowRoot');
476
537
  }
477
- `.replace(/(\n|\s{2}|\t)/g, '');
478
-
479
- // run polyfill as first thing post dom content is loaded
480
- clone.head.prepend(scriptEl);
481
538
  }
482
-
483
- // Returns a copy or new doctype for a document.
484
- function doctype(dom) {
485
- let {
486
- name = 'html',
487
- publicId = '',
488
- systemId = ''
489
- } = (dom === null || dom === void 0 ? void 0 : dom.doctype) ?? {};
490
- let deprecated = '';
491
- if (publicId && systemId) {
492
- deprecated = ` PUBLIC "${publicId}" "${systemId}"`;
493
- } else if (publicId) {
494
- deprecated = ` PUBLIC "${publicId}"`;
495
- } else if (systemId) {
496
- deprecated = ` SYSTEM "${systemId}"`;
539
+ }
540
+
541
+ // Serializes a document and returns the resulting DOM string.
542
+ function serializeDOM(options) {
543
+ let {
544
+ dom = document,
545
+ // allow snake_case or camelCase
546
+ enableJavaScript = options === null || options === void 0 ? void 0 : options.enable_javascript,
547
+ domTransformation = options === null || options === void 0 ? void 0 : options.dom_transformation,
548
+ stringifyResponse = options === null || options === void 0 ? void 0 : options.stringify_response,
549
+ disableShadowDOM = options === null || options === void 0 ? void 0 : options.disable_shadow_dom,
550
+ reshuffleInvalidTags = options === null || options === void 0 ? void 0 : options.reshuffle_invalid_tags
551
+ } = options || {};
552
+
553
+ // keep certain records throughout serialization
554
+ let ctx = {
555
+ resources: new Set(),
556
+ warnings: new Set(),
557
+ hints: new Set(),
558
+ cache: new Map(),
559
+ enableJavaScript,
560
+ disableShadowDOM
561
+ };
562
+ ctx.dom = dom;
563
+ ctx.clone = cloneNodeAndShadow(ctx);
564
+ serializeElements(ctx);
565
+ setBaseURI(ctx.clone.documentElement);
566
+ if (domTransformation) {
567
+ try {
568
+ // eslint-disable-next-line no-eval
569
+ if (typeof domTransformation === 'string') domTransformation = window.eval(domTransformation);
570
+ domTransformation(ctx.clone.documentElement);
571
+ } catch (err) {
572
+ let errorMessage = `Could not transform the dom: ${err.message}`;
573
+ ctx.warnings.add(errorMessage);
574
+ console.error(errorMessage);
497
575
  }
498
- return `<!DOCTYPE ${name}${deprecated}>`;
499
576
  }
500
-
501
- // Serializes and returns the cloned DOM as an HTML string
502
- function serializeHTML(ctx) {
503
- let html = getOuterHTML(ctx.clone.documentElement);
504
- // replace serialized data attributes with real attributes
505
- html = html.replace(/ data-smartui-serialized-attribute-(\w+?)=/ig, ' $1=');
506
- // include the doctype with the html string
507
- return doctype(ctx.dom) + html;
577
+ if (!disableShadowDOM) {
578
+ injectDeclarativeShadowDOMPolyfill(ctx);
508
579
  }
509
- function serializeElements(ctx) {
510
- serializeInputElements(ctx);
511
- serializeFrames(ctx);
512
- serializeVideos(ctx);
513
- if (!ctx.enableJavaScript) {
514
- serializeCSSOM(ctx);
515
- serializeCanvas(ctx);
516
- }
517
- for (const shadowHost of ctx.dom.querySelectorAll('[data-smartui-shadow-host]')) {
518
- let smartuiElementId = shadowHost.getAttribute('data-smartui-element-id');
519
- let cloneShadowHost = ctx.clone.querySelector(`[data-smartui-element-id="${smartuiElementId}"]`);
520
- if (shadowHost.shadowRoot && cloneShadowHost.shadowRoot) {
521
- serializeElements({
522
- ...ctx,
523
- dom: shadowHost.shadowRoot,
524
- clone: cloneShadowHost.shadowRoot
525
- });
526
- } else {
527
- ctx.warnings.add('data-smartui-shadow-host does not have shadowRoot');
528
- }
580
+ if (reshuffleInvalidTags) {
581
+ let clonedBody = ctx.clone.body;
582
+ while (clonedBody.nextSibling) {
583
+ let sibling = clonedBody.nextSibling;
584
+ clonedBody.append(sibling);
529
585
  }
586
+ } else if (ctx.clone.body.nextSibling) {
587
+ ctx.hints.add('DOM elements found outside </body>');
530
588
  }
531
-
532
- // Serializes a document and returns the resulting DOM string.
533
- function serializeDOM(options) {
534
- let {
535
- dom = document,
536
- // allow snake_case or camelCase
537
- enableJavaScript = options === null || options === void 0 ? void 0 : options.enable_javascript,
538
- domTransformation = options === null || options === void 0 ? void 0 : options.dom_transformation,
539
- stringifyResponse = options === null || options === void 0 ? void 0 : options.stringify_response,
540
- disableShadowDOM = options === null || options === void 0 ? void 0 : options.disable_shadow_dom,
541
- reshuffleInvalidTags = options === null || options === void 0 ? void 0 : options.reshuffle_invalid_tags
542
- } = options || {};
543
-
544
- // keep certain records throughout serialization
545
- let ctx = {
546
- resources: new Set(),
547
- warnings: new Set(),
548
- hints: new Set(),
549
- cache: new Map(),
550
- enableJavaScript,
551
- disableShadowDOM
552
- };
553
- ctx.dom = dom;
554
- ctx.clone = cloneNodeAndShadow(ctx);
555
- serializeElements(ctx);
556
- if (domTransformation) {
557
- try {
558
- // eslint-disable-next-line no-eval
559
- if (typeof domTransformation === 'string') domTransformation = window.eval(domTransformation);
560
- domTransformation(ctx.clone.documentElement);
561
- } catch (err) {
562
- let errorMessage = `Could not transform the dom: ${err.message}`;
563
- ctx.warnings.add(errorMessage);
564
- console.error(errorMessage);
565
- }
566
- }
567
- if (!disableShadowDOM) {
568
- injectDeclarativeShadowDOMPolyfill(ctx);
569
- }
570
- if (reshuffleInvalidTags) {
571
- let clonedBody = ctx.clone.body;
572
- while (clonedBody.nextSibling) {
573
- let sibling = clonedBody.nextSibling;
574
- clonedBody.append(sibling);
575
- }
576
- } else if (ctx.clone.body.nextSibling) {
577
- ctx.hints.add('DOM elements found outside </body>');
578
- }
579
- let result = {
580
- html: serializeHTML(ctx),
581
- warnings: Array.from(ctx.warnings),
582
- resources: Array.from(ctx.resources),
583
- hints: Array.from(ctx.hints)
584
- };
585
- return stringifyResponse ? JSON.stringify(result) : result;
586
- }
587
-
588
- exports["default"] = serializeDOM;
589
- exports.serialize = serializeDOM;
590
- exports.serializeDOM = serializeDOM;
591
-
592
- Object.defineProperty(exports, '__esModule', { value: true });
593
-
594
- })(this.SmartUIDOM = this.SmartUIDOM || {});
589
+ let result = {
590
+ html: serializeHTML(ctx),
591
+ warnings: Array.from(ctx.warnings),
592
+ resources: Array.from(ctx.resources),
593
+ hints: Array.from(ctx.hints)
594
+ };
595
+ return stringifyResponse ? JSON.stringify(result) : result;
596
+ }
597
+
598
+ exports["default"] = serializeDOM;
599
+ exports.serialize = serializeDOM;
600
+ exports.serializeDOM = serializeDOM;
601
+
602
+ Object.defineProperty(exports, '__esModule', { value: true });
603
+
604
+ })(this.SmartUIDOM = this.SmartUIDOM || {});
595
605
  }).call(window);
596
-
606
+
597
607
  if (typeof define === "function" && define.amd) {
598
608
  define("@smartui/dom", [], () => window.SmartUIDOM);
599
609
  } else if (typeof module === "object" && module.exports) {