@eturnity/dom_to_svg 8.10.1
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/LICENSE +21 -0
- package/README.md +47 -0
- package/lib/accessibility.d.ts +3 -0
- package/lib/accessibility.d.ts.map +1 -0
- package/lib/accessibility.js +201 -0
- package/lib/accessibility.js.map +1 -0
- package/lib/css.d.ts +26 -0
- package/lib/css.d.ts.map +1 -0
- package/lib/css.js +96 -0
- package/lib/css.js.map +1 -0
- package/lib/dom.d.ts +22 -0
- package/lib/dom.d.ts.map +1 -0
- package/lib/dom.js +33 -0
- package/lib/dom.js.map +1 -0
- package/lib/element.d.ts +3 -0
- package/lib/element.d.ts.map +1 -0
- package/lib/element.js +417 -0
- package/lib/element.js.map +1 -0
- package/lib/gradients.d.ts +3 -0
- package/lib/gradients.d.ts.map +1 -0
- package/lib/gradients.js +78 -0
- package/lib/gradients.js.map +1 -0
- package/lib/index.d.ts +6 -0
- package/lib/index.d.ts.map +1 -0
- package/lib/index.js +75 -0
- package/lib/index.js.map +1 -0
- package/lib/inline.d.ts +14 -0
- package/lib/inline.d.ts.map +1 -0
- package/lib/inline.js +138 -0
- package/lib/inline.js.map +1 -0
- package/lib/stacking.d.ts +38 -0
- package/lib/stacking.d.ts.map +1 -0
- package/lib/stacking.js +125 -0
- package/lib/stacking.js.map +1 -0
- package/lib/svg.d.ts +14 -0
- package/lib/svg.d.ts.map +1 -0
- package/lib/svg.js +245 -0
- package/lib/svg.js.map +1 -0
- package/lib/test/PuppeteerAdapter.d.ts +90 -0
- package/lib/test/PuppeteerAdapter.d.ts.map +1 -0
- package/lib/test/PuppeteerAdapter.js +196 -0
- package/lib/test/PuppeteerAdapter.js.map +1 -0
- package/lib/test/injected-script.d.ts +2 -0
- package/lib/test/injected-script.d.ts.map +1 -0
- package/lib/test/injected-script.js +26 -0
- package/lib/test/injected-script.js.map +1 -0
- package/lib/test/test.d.ts +6 -0
- package/lib/test/test.d.ts.map +1 -0
- package/lib/test/test.js +245 -0
- package/lib/test/test.js.map +1 -0
- package/lib/test/util.d.ts +9 -0
- package/lib/test/util.d.ts.map +1 -0
- package/lib/test/util.js +33 -0
- package/lib/test/util.js.map +1 -0
- package/lib/text.d.ts +5 -0
- package/lib/text.d.ts.map +1 -0
- package/lib/text.js +138 -0
- package/lib/text.js.map +1 -0
- package/lib/traversal.d.ts +32 -0
- package/lib/traversal.d.ts.map +1 -0
- package/lib/traversal.js +12 -0
- package/lib/traversal.js.map +1 -0
- package/lib/util.d.ts +20 -0
- package/lib/util.d.ts.map +1 -0
- package/lib/util.js +43 -0
- package/lib/util.js.map +1 -0
- package/package.json +112 -0
package/lib/svg.js
ADDED
|
@@ -0,0 +1,245 @@
|
|
|
1
|
+
import cssValueParser from 'postcss-value-parser';
|
|
2
|
+
import { parseCSSLength } from './css.js';
|
|
3
|
+
import { isElement, isSVGAnchorElement, isSVGElement, isSVGGraphicsElement, isSVGSVGElement, isSVGTextContentElement, isTextNode, svgNamespace, } from './dom.js';
|
|
4
|
+
import { copyTextStyles } from './text.js';
|
|
5
|
+
import { assert, diagonale } from './util.js';
|
|
6
|
+
/**
|
|
7
|
+
* Recursively clone an `<svg>` element, inlining it into the output SVG document with the necessary transforms.
|
|
8
|
+
*/
|
|
9
|
+
export function handleSvgNode(node, context) {
|
|
10
|
+
if (isElement(node)) {
|
|
11
|
+
if (!isSVGElement(node)) {
|
|
12
|
+
return;
|
|
13
|
+
}
|
|
14
|
+
handleSvgElement(node, context);
|
|
15
|
+
}
|
|
16
|
+
else if (isTextNode(node)) {
|
|
17
|
+
const clonedTextNode = node.cloneNode(true);
|
|
18
|
+
context.currentSvgParent.append(clonedTextNode);
|
|
19
|
+
}
|
|
20
|
+
}
|
|
21
|
+
const ignoredElements = new Set(['script', 'style', 'foreignElement']);
|
|
22
|
+
const URL_ID_REFERENCE_REGEX = /\burl\(["']?#/;
|
|
23
|
+
export function handleSvgElement(element, context) {
|
|
24
|
+
var _a, _b, _c, _d;
|
|
25
|
+
if (ignoredElements.has(element.tagName)) {
|
|
26
|
+
return;
|
|
27
|
+
}
|
|
28
|
+
let elementToAppend;
|
|
29
|
+
if (isSVGSVGElement(element)) {
|
|
30
|
+
const contentContainer = context.svgDocument.createElementNS(svgNamespace, 'g');
|
|
31
|
+
elementToAppend = contentContainer;
|
|
32
|
+
contentContainer.classList.add('svg-content', ...element.classList);
|
|
33
|
+
contentContainer.dataset.viewBox = (_a = element.getAttribute('viewBox')) !== null && _a !== void 0 ? _a : '';
|
|
34
|
+
contentContainer.dataset.width = (_b = element.getAttribute('width')) !== null && _b !== void 0 ? _b : '';
|
|
35
|
+
contentContainer.dataset.height = (_c = element.getAttribute('height')) !== null && _c !== void 0 ? _c : '';
|
|
36
|
+
// Since the SVG is getting inlined into the output SVG, we need to transform its contents according to its
|
|
37
|
+
// viewBox, width, height and preserveAspectRatio. We can use getScreenCTM() for this on one of its
|
|
38
|
+
// SVGGraphicsElement children (in Chrome calling it on the <svg> works too, but not in Firefox:
|
|
39
|
+
// https://bugzilla.mozilla.org/show_bug.cgi?id=873106).
|
|
40
|
+
for (const child of element.children) {
|
|
41
|
+
if (!isSVGGraphicsElement(child)) {
|
|
42
|
+
continue;
|
|
43
|
+
}
|
|
44
|
+
let viewBoxTransformMatrix =
|
|
45
|
+
// When this function is called on an inline <svg> element in the original DOM, we want
|
|
46
|
+
// getScreenCTM() to map it to the DOM coordinate system. When this function is called from
|
|
47
|
+
// inlineResources() the <svg> is already embedded into the output <svg>. In that case the output
|
|
48
|
+
// SVG already has a viewBox, and the coordinate system of the SVG is not equal to the coordinate
|
|
49
|
+
// system of the screen, therefor we need to use getCTM() to map it into the output SVG's
|
|
50
|
+
// coordinate system.
|
|
51
|
+
child.ownerDocument !== context.svgDocument &&
|
|
52
|
+
// When we inline an SVG, we put a transform on it for the getScreenCTM(). When that SVG also
|
|
53
|
+
// contains another SVG, the inner SVG should just get transformed relative to the outer SVG, not
|
|
54
|
+
// relative to the screen, because the transforms will stack in the output SVG.
|
|
55
|
+
!((_d = element.parentElement) === null || _d === void 0 ? void 0 : _d.closest('svg'))
|
|
56
|
+
? child.getScreenCTM()
|
|
57
|
+
: child.getCTM();
|
|
58
|
+
// This should only be null if the <svg> is `display: none`
|
|
59
|
+
if (!viewBoxTransformMatrix) {
|
|
60
|
+
break;
|
|
61
|
+
}
|
|
62
|
+
// Make sure to handle a child that already has a transform. That transform should only apply to the
|
|
63
|
+
// child, not to the entire SVG contents, so we need to calculate it out.
|
|
64
|
+
if (child.transform.baseVal.numberOfItems > 0) {
|
|
65
|
+
child.transform.baseVal.consolidate();
|
|
66
|
+
const existingTransform = child.transform.baseVal.getItem(0).matrix;
|
|
67
|
+
viewBoxTransformMatrix = viewBoxTransformMatrix.multiply(existingTransform.inverse());
|
|
68
|
+
}
|
|
69
|
+
contentContainer.transform.baseVal.appendItem(contentContainer.transform.baseVal.createSVGTransformFromMatrix(viewBoxTransformMatrix));
|
|
70
|
+
break;
|
|
71
|
+
}
|
|
72
|
+
}
|
|
73
|
+
else {
|
|
74
|
+
// Clone element
|
|
75
|
+
if (isSVGAnchorElement(element) && !context.options.keepLinks) {
|
|
76
|
+
elementToAppend = context.svgDocument.createElementNS(svgNamespace, 'g');
|
|
77
|
+
}
|
|
78
|
+
else {
|
|
79
|
+
elementToAppend = element.cloneNode(false);
|
|
80
|
+
}
|
|
81
|
+
// Remove event handlers
|
|
82
|
+
for (const attribute of elementToAppend.attributes) {
|
|
83
|
+
if (attribute.localName.startsWith('on')) {
|
|
84
|
+
elementToAppend.attributes.removeNamedItemNS(attribute.namespaceURI, attribute.localName);
|
|
85
|
+
}
|
|
86
|
+
else if (attribute.localName === 'href' && attribute.value.startsWith('javascript:')) {
|
|
87
|
+
elementToAppend.attributes.removeNamedItemNS(attribute.namespaceURI, attribute.localName);
|
|
88
|
+
}
|
|
89
|
+
}
|
|
90
|
+
const window = element.ownerDocument.defaultView;
|
|
91
|
+
assert(window, "Element's ownerDocument has no defaultView");
|
|
92
|
+
const svgViewportElement = element.ownerSVGElement;
|
|
93
|
+
assert(svgViewportElement, 'Expected element to have ownerSVGElement');
|
|
94
|
+
const styles = window.getComputedStyle(element);
|
|
95
|
+
if (isSVGGraphicsElement(element)) {
|
|
96
|
+
copyGraphicalPresentationAttributes(styles, elementToAppend, svgViewportElement.viewBox.animVal);
|
|
97
|
+
if (isSVGTextContentElement(element)) {
|
|
98
|
+
copyTextStyles(styles, elementToAppend);
|
|
99
|
+
}
|
|
100
|
+
}
|
|
101
|
+
// Namespace ID references url(#...)
|
|
102
|
+
for (const attribute of elementToAppend.attributes) {
|
|
103
|
+
if (attribute.localName === 'href') {
|
|
104
|
+
if (attribute.value.startsWith('#')) {
|
|
105
|
+
attribute.value = attribute.value.replace('#', `#${context.idPrefix}`);
|
|
106
|
+
}
|
|
107
|
+
}
|
|
108
|
+
else if (URL_ID_REFERENCE_REGEX.test(attribute.value)) {
|
|
109
|
+
attribute.value = rewriteUrlIdReferences(attribute.value, context);
|
|
110
|
+
}
|
|
111
|
+
}
|
|
112
|
+
for (const property of elementToAppend.style) {
|
|
113
|
+
const value = elementToAppend.style.getPropertyValue(property);
|
|
114
|
+
if (URL_ID_REFERENCE_REGEX.test(value)) {
|
|
115
|
+
elementToAppend.style.setProperty(property, rewriteUrlIdReferences(value, context), elementToAppend.style.getPropertyPriority(property));
|
|
116
|
+
}
|
|
117
|
+
}
|
|
118
|
+
}
|
|
119
|
+
// Make sure all IDs are unique
|
|
120
|
+
if (elementToAppend.id) {
|
|
121
|
+
elementToAppend.id = context.idPrefix + elementToAppend.id;
|
|
122
|
+
}
|
|
123
|
+
context.currentSvgParent.append(elementToAppend);
|
|
124
|
+
for (const child of element.childNodes) {
|
|
125
|
+
handleSvgNode(child, { ...context, currentSvgParent: elementToAppend });
|
|
126
|
+
}
|
|
127
|
+
}
|
|
128
|
+
const graphicalPresentationAttributes = [
|
|
129
|
+
'alignment-baseline',
|
|
130
|
+
'baseline-shift',
|
|
131
|
+
// 'clip',
|
|
132
|
+
'clip-path',
|
|
133
|
+
'clip-rule',
|
|
134
|
+
'color',
|
|
135
|
+
'color-interpolation',
|
|
136
|
+
'color-interpolation-filters',
|
|
137
|
+
// 'color-profile',
|
|
138
|
+
'color-rendering',
|
|
139
|
+
// 'cursor',
|
|
140
|
+
'direction',
|
|
141
|
+
// 'display',
|
|
142
|
+
// 'enable-background',
|
|
143
|
+
'fill',
|
|
144
|
+
'fill-opacity',
|
|
145
|
+
'fill-rule',
|
|
146
|
+
'filter',
|
|
147
|
+
'flood-color',
|
|
148
|
+
'flood-opacity',
|
|
149
|
+
'image-rendering',
|
|
150
|
+
'lighting-color',
|
|
151
|
+
'marker-end',
|
|
152
|
+
'marker-mid',
|
|
153
|
+
'marker-start',
|
|
154
|
+
'mask',
|
|
155
|
+
'opacity',
|
|
156
|
+
// 'overflow',
|
|
157
|
+
'pointer-events',
|
|
158
|
+
'shape-rendering',
|
|
159
|
+
// 'solid-color',
|
|
160
|
+
// 'solid-opacity',
|
|
161
|
+
'stop-color',
|
|
162
|
+
'stop-opacity',
|
|
163
|
+
'stroke',
|
|
164
|
+
'stroke-dasharray',
|
|
165
|
+
'stroke-dashoffset',
|
|
166
|
+
'stroke-linecap',
|
|
167
|
+
'stroke-linejoin',
|
|
168
|
+
'stroke-miterlimit',
|
|
169
|
+
'stroke-opacity',
|
|
170
|
+
'stroke-width',
|
|
171
|
+
'transform',
|
|
172
|
+
'vector-effect',
|
|
173
|
+
'visibility',
|
|
174
|
+
];
|
|
175
|
+
const defaults = {
|
|
176
|
+
'alignment-baseline': 'auto',
|
|
177
|
+
'baseline-shift': '0px',
|
|
178
|
+
'clip-path': 'none',
|
|
179
|
+
'clip-rule': 'nonzero',
|
|
180
|
+
'color-interpolation-filters': 'linearrgb',
|
|
181
|
+
'color-interpolation': 'srgb',
|
|
182
|
+
'color-rendering': 'auto',
|
|
183
|
+
'fill-opacity': '1',
|
|
184
|
+
'fill-rule': 'nonzero',
|
|
185
|
+
'flood-color': 'rgb(0, 0, 0)',
|
|
186
|
+
'flood-opacity': '1',
|
|
187
|
+
'image-rendering': 'auto',
|
|
188
|
+
'lighting-color': 'rgb(255, 255, 255)',
|
|
189
|
+
'marker-end': 'none',
|
|
190
|
+
'marker-mid': 'none',
|
|
191
|
+
'marker-start': 'none',
|
|
192
|
+
'pointer-events': 'auto',
|
|
193
|
+
'shape-rendering': 'auto',
|
|
194
|
+
'stop-color': 'rgb(0, 0, 0)',
|
|
195
|
+
'stop-opacity': '1',
|
|
196
|
+
'stroke-dasharray': 'none',
|
|
197
|
+
'stroke-dashoffset': '0px',
|
|
198
|
+
'stroke-linecap': 'butt',
|
|
199
|
+
'stroke-linejoin': 'miter',
|
|
200
|
+
'stroke-miterlimit': '4',
|
|
201
|
+
'stroke-opacity': '1',
|
|
202
|
+
'stroke-width': '1px',
|
|
203
|
+
'vector-effect': 'none',
|
|
204
|
+
color: '',
|
|
205
|
+
direction: 'ltr',
|
|
206
|
+
fill: '',
|
|
207
|
+
filter: 'none',
|
|
208
|
+
mask: 'none',
|
|
209
|
+
opacity: '1',
|
|
210
|
+
stroke: '',
|
|
211
|
+
transform: 'none',
|
|
212
|
+
visibility: 'visible',
|
|
213
|
+
};
|
|
214
|
+
/**
|
|
215
|
+
* Prefixes all ID references of the form `url(#id)` in the given string.
|
|
216
|
+
*/
|
|
217
|
+
function rewriteUrlIdReferences(value, { idPrefix }) {
|
|
218
|
+
const parsedValue = cssValueParser(value);
|
|
219
|
+
parsedValue.walk(node => {
|
|
220
|
+
if (node.type !== 'function' || node.value !== 'url') {
|
|
221
|
+
return;
|
|
222
|
+
}
|
|
223
|
+
const urlArgument = node.nodes[0];
|
|
224
|
+
if (!urlArgument) {
|
|
225
|
+
return;
|
|
226
|
+
}
|
|
227
|
+
urlArgument.value = urlArgument.value.replace('#', `#${idPrefix}`);
|
|
228
|
+
});
|
|
229
|
+
return cssValueParser.stringify(parsedValue.nodes);
|
|
230
|
+
}
|
|
231
|
+
function copyGraphicalPresentationAttributes(styles, target, viewBox) {
|
|
232
|
+
var _a;
|
|
233
|
+
for (const attribute of graphicalPresentationAttributes) {
|
|
234
|
+
let value = styles.getPropertyValue(attribute);
|
|
235
|
+
if (value && value !== defaults[attribute]) {
|
|
236
|
+
if (value.endsWith('%')) {
|
|
237
|
+
// E.g. https://svgwg.org/svg2-draft/painting.html#StrokeWidth
|
|
238
|
+
// Percentages: refer to the normalized diagonal of the current SVG viewport (see Units)
|
|
239
|
+
value = (_a = parseCSSLength(value, diagonale(viewBox))) !== null && _a !== void 0 ? _a : 0;
|
|
240
|
+
}
|
|
241
|
+
target.setAttribute(attribute, value.toString());
|
|
242
|
+
}
|
|
243
|
+
}
|
|
244
|
+
}
|
|
245
|
+
//# sourceMappingURL=svg.js.map
|
package/lib/svg.js.map
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"svg.js","sourceRoot":"","sources":["../src/svg.ts"],"names":[],"mappings":"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","sourcesContent":["import cssValueParser from 'postcss-value-parser'\n\nimport { parseCSSLength } from './css.js'\nimport {\n\tisElement,\n\tisSVGAnchorElement,\n\tisSVGElement,\n\tisSVGGraphicsElement,\n\tisSVGSVGElement,\n\tisSVGTextContentElement,\n\tisTextNode,\n\tsvgNamespace,\n} from './dom.js'\nimport { copyTextStyles } from './text.js'\nimport { TraversalContext } from './traversal.js'\nimport { assert, diagonale } from './util.js'\n\n/**\n * Recursively clone an `<svg>` element, inlining it into the output SVG document with the necessary transforms.\n */\nexport function handleSvgNode(node: Node, context: SvgTraversalContext): void {\n\tif (isElement(node)) {\n\t\tif (!isSVGElement(node)) {\n\t\t\treturn\n\t\t}\n\t\thandleSvgElement(node, context)\n\t} else if (isTextNode(node)) {\n\t\tconst clonedTextNode = node.cloneNode(true) as Text\n\t\tcontext.currentSvgParent.append(clonedTextNode)\n\t}\n}\n\nconst ignoredElements = new Set(['script', 'style', 'foreignElement'])\n\ninterface SvgTraversalContext extends Pick<TraversalContext, 'svgDocument' | 'currentSvgParent' | 'options'> {\n\t/**\n\t * A prefix to use for all ID to make them unique inside the output SVG document.\n\t */\n\treadonly idPrefix: string\n}\n\nconst URL_ID_REFERENCE_REGEX = /\\burl\\([\"']?#/\nexport function handleSvgElement(element: SVGElement, context: SvgTraversalContext): void {\n\tif (ignoredElements.has(element.tagName)) {\n\t\treturn\n\t}\n\n\tlet elementToAppend: SVGElement\n\tif (isSVGSVGElement(element)) {\n\t\tconst contentContainer = context.svgDocument.createElementNS(svgNamespace, 'g')\n\t\telementToAppend = contentContainer\n\t\tcontentContainer.classList.add('svg-content', ...element.classList)\n\t\tcontentContainer.dataset.viewBox = element.getAttribute('viewBox') ?? ''\n\t\tcontentContainer.dataset.width = element.getAttribute('width') ?? ''\n\t\tcontentContainer.dataset.height = element.getAttribute('height') ?? ''\n\n\t\t// Since the SVG is getting inlined into the output SVG, we need to transform its contents according to its\n\t\t// viewBox, width, height and preserveAspectRatio. We can use getScreenCTM() for this on one of its\n\t\t// SVGGraphicsElement children (in Chrome calling it on the <svg> works too, but not in Firefox:\n\t\t// https://bugzilla.mozilla.org/show_bug.cgi?id=873106).\n\t\tfor (const child of element.children) {\n\t\t\tif (!isSVGGraphicsElement(child)) {\n\t\t\t\tcontinue\n\t\t\t}\n\n\t\t\tlet viewBoxTransformMatrix =\n\t\t\t\t// When this function is called on an inline <svg> element in the original DOM, we want\n\t\t\t\t// getScreenCTM() to map it to the DOM coordinate system. When this function is called from\n\t\t\t\t// inlineResources() the <svg> is already embedded into the output <svg>. In that case the output\n\t\t\t\t// SVG already has a viewBox, and the coordinate system of the SVG is not equal to the coordinate\n\t\t\t\t// system of the screen, therefor we need to use getCTM() to map it into the output SVG's\n\t\t\t\t// coordinate system.\n\t\t\t\tchild.ownerDocument !== context.svgDocument &&\n\t\t\t\t// When we inline an SVG, we put a transform on it for the getScreenCTM(). When that SVG also\n\t\t\t\t// contains another SVG, the inner SVG should just get transformed relative to the outer SVG, not\n\t\t\t\t// relative to the screen, because the transforms will stack in the output SVG.\n\t\t\t\t!element.parentElement?.closest('svg')\n\t\t\t\t\t? child.getScreenCTM()\n\t\t\t\t\t: child.getCTM()\n\n\t\t\t// This should only be null if the <svg> is `display: none`\n\t\t\tif (!viewBoxTransformMatrix) {\n\t\t\t\tbreak\n\t\t\t}\n\n\t\t\t// Make sure to handle a child that already has a transform. That transform should only apply to the\n\t\t\t// child, not to the entire SVG contents, so we need to calculate it out.\n\t\t\tif (child.transform.baseVal.numberOfItems > 0) {\n\t\t\t\tchild.transform.baseVal.consolidate()\n\t\t\t\tconst existingTransform = child.transform.baseVal.getItem(0).matrix\n\t\t\t\tviewBoxTransformMatrix = viewBoxTransformMatrix.multiply(existingTransform.inverse())\n\t\t\t}\n\n\t\t\tcontentContainer.transform.baseVal.appendItem(\n\t\t\t\tcontentContainer.transform.baseVal.createSVGTransformFromMatrix(viewBoxTransformMatrix)\n\t\t\t)\n\t\t\tbreak\n\t\t}\n\t} else {\n\t\t// Clone element\n\t\tif (isSVGAnchorElement(element) && !context.options.keepLinks) {\n\t\t\telementToAppend = context.svgDocument.createElementNS(svgNamespace, 'g')\n\t\t} else {\n\t\t\telementToAppend = element.cloneNode(false) as SVGElement\n\t\t}\n\n\t\t// Remove event handlers\n\t\tfor (const attribute of elementToAppend.attributes) {\n\t\t\tif (attribute.localName.startsWith('on')) {\n\t\t\t\telementToAppend.attributes.removeNamedItemNS(attribute.namespaceURI, attribute.localName)\n\t\t\t} else if (attribute.localName === 'href' && attribute.value.startsWith('javascript:')) {\n\t\t\t\telementToAppend.attributes.removeNamedItemNS(attribute.namespaceURI, attribute.localName)\n\t\t\t}\n\t\t}\n\n\t\tconst window = element.ownerDocument.defaultView\n\t\tassert(window, \"Element's ownerDocument has no defaultView\")\n\n\t\tconst svgViewportElement = element.ownerSVGElement\n\t\tassert(svgViewportElement, 'Expected element to have ownerSVGElement')\n\n\t\tconst styles = window.getComputedStyle(element)\n\n\t\tif (isSVGGraphicsElement(element)) {\n\t\t\tcopyGraphicalPresentationAttributes(styles, elementToAppend, svgViewportElement.viewBox.animVal)\n\n\t\t\tif (isSVGTextContentElement(element)) {\n\t\t\t\tcopyTextStyles(styles, elementToAppend)\n\t\t\t}\n\t\t}\n\n\t\t// Namespace ID references url(#...)\n\t\tfor (const attribute of elementToAppend.attributes) {\n\t\t\tif (attribute.localName === 'href') {\n\t\t\t\tif (attribute.value.startsWith('#')) {\n\t\t\t\t\tattribute.value = attribute.value.replace('#', `#${context.idPrefix}`)\n\t\t\t\t}\n\t\t\t} else if (URL_ID_REFERENCE_REGEX.test(attribute.value)) {\n\t\t\t\tattribute.value = rewriteUrlIdReferences(attribute.value, context)\n\t\t\t}\n\t\t}\n\t\tfor (const property of elementToAppend.style) {\n\t\t\tconst value = elementToAppend.style.getPropertyValue(property)\n\t\t\tif (URL_ID_REFERENCE_REGEX.test(value)) {\n\t\t\t\telementToAppend.style.setProperty(\n\t\t\t\t\tproperty,\n\t\t\t\t\trewriteUrlIdReferences(value, context),\n\t\t\t\t\telementToAppend.style.getPropertyPriority(property)\n\t\t\t\t)\n\t\t\t}\n\t\t}\n\t}\n\n\t// Make sure all IDs are unique\n\tif (elementToAppend.id) {\n\t\telementToAppend.id = context.idPrefix + elementToAppend.id\n\t}\n\n\tcontext.currentSvgParent.append(elementToAppend)\n\tfor (const child of element.childNodes) {\n\t\thandleSvgNode(child, { ...context, currentSvgParent: elementToAppend })\n\t}\n}\n\nconst graphicalPresentationAttributes = [\n\t'alignment-baseline',\n\t'baseline-shift',\n\t// 'clip',\n\t'clip-path',\n\t'clip-rule',\n\t'color',\n\t'color-interpolation',\n\t'color-interpolation-filters',\n\t// 'color-profile',\n\t'color-rendering',\n\t// 'cursor',\n\t'direction',\n\t// 'display',\n\t// 'enable-background',\n\t'fill',\n\t'fill-opacity',\n\t'fill-rule',\n\t'filter',\n\t'flood-color',\n\t'flood-opacity',\n\t'image-rendering',\n\t'lighting-color',\n\t'marker-end',\n\t'marker-mid',\n\t'marker-start',\n\t'mask',\n\t'opacity',\n\t// 'overflow',\n\t'pointer-events',\n\t'shape-rendering',\n\t// 'solid-color',\n\t// 'solid-opacity',\n\t'stop-color',\n\t'stop-opacity',\n\t'stroke',\n\t'stroke-dasharray',\n\t'stroke-dashoffset',\n\t'stroke-linecap',\n\t'stroke-linejoin',\n\t'stroke-miterlimit',\n\t'stroke-opacity',\n\t'stroke-width',\n\t'transform',\n\t'vector-effect',\n\t'visibility',\n] as const\n\nconst defaults: Record<typeof graphicalPresentationAttributes[number], string> = {\n\t'alignment-baseline': 'auto',\n\t'baseline-shift': '0px',\n\t'clip-path': 'none',\n\t'clip-rule': 'nonzero',\n\t'color-interpolation-filters': 'linearrgb',\n\t'color-interpolation': 'srgb',\n\t'color-rendering': 'auto',\n\t'fill-opacity': '1',\n\t'fill-rule': 'nonzero',\n\t'flood-color': 'rgb(0, 0, 0)',\n\t'flood-opacity': '1',\n\t'image-rendering': 'auto',\n\t'lighting-color': 'rgb(255, 255, 255)',\n\t'marker-end': 'none',\n\t'marker-mid': 'none',\n\t'marker-start': 'none',\n\t'pointer-events': 'auto',\n\t'shape-rendering': 'auto',\n\t'stop-color': 'rgb(0, 0, 0)',\n\t'stop-opacity': '1',\n\t'stroke-dasharray': 'none',\n\t'stroke-dashoffset': '0px',\n\t'stroke-linecap': 'butt',\n\t'stroke-linejoin': 'miter',\n\t'stroke-miterlimit': '4',\n\t'stroke-opacity': '1',\n\t'stroke-width': '1px',\n\t'vector-effect': 'none',\n\tcolor: '',\n\tdirection: 'ltr',\n\tfill: '',\n\tfilter: 'none',\n\tmask: 'none',\n\topacity: '1',\n\tstroke: '',\n\ttransform: 'none',\n\tvisibility: 'visible',\n}\n\n/**\n * Prefixes all ID references of the form `url(#id)` in the given string.\n */\nfunction rewriteUrlIdReferences(value: string, { idPrefix }: Pick<SvgTraversalContext, 'idPrefix'>): string {\n\tconst parsedValue = cssValueParser(value)\n\tparsedValue.walk(node => {\n\t\tif (node.type !== 'function' || node.value !== 'url') {\n\t\t\treturn\n\t\t}\n\t\tconst urlArgument = node.nodes[0]\n\t\tif (!urlArgument) {\n\t\t\treturn\n\t\t}\n\t\turlArgument.value = urlArgument.value.replace('#', `#${idPrefix}`)\n\t})\n\treturn cssValueParser.stringify(parsedValue.nodes)\n}\n\nfunction copyGraphicalPresentationAttributes(\n\tstyles: CSSStyleDeclaration,\n\ttarget: SVGElement,\n\tviewBox: DOMRectReadOnly\n): void {\n\tfor (const attribute of graphicalPresentationAttributes) {\n\t\tlet value: string | number = styles.getPropertyValue(attribute)\n\t\tif (value && value !== defaults[attribute]) {\n\t\t\tif (value.endsWith('%')) {\n\t\t\t\t// E.g. https://svgwg.org/svg2-draft/painting.html#StrokeWidth\n\t\t\t\t// Percentages:\trefer to the normalized diagonal of the current SVG viewport (see Units)\n\t\t\t\tvalue = parseCSSLength(value, diagonale(viewBox)) ?? 0\n\t\t\t}\n\t\t\ttarget.setAttribute(attribute, value.toString())\n\t\t}\n\t}\n}\n"]}
|
|
@@ -0,0 +1,90 @@
|
|
|
1
|
+
import PollyAdapter from '@pollyjs/adapter';
|
|
2
|
+
import { Polly, Request as PollyRequest } from '@pollyjs/core';
|
|
3
|
+
import type * as Puppeteer from 'puppeteer';
|
|
4
|
+
interface PollyResponse {
|
|
5
|
+
statusCode: number;
|
|
6
|
+
headers: Record<string, string>;
|
|
7
|
+
body: string;
|
|
8
|
+
isBinary: boolean;
|
|
9
|
+
}
|
|
10
|
+
/**
|
|
11
|
+
* A Puppeteer adapter for Polly that supports all request resource types.
|
|
12
|
+
*
|
|
13
|
+
* TODO: upstream this?
|
|
14
|
+
*
|
|
15
|
+
* Polly's own Puppeteer adapter hangs when attempting to capture the page's initial document
|
|
16
|
+
* (requestResourceType==='document'). See https://github.com/Netflix/pollyjs/issues/121
|
|
17
|
+
*
|
|
18
|
+
* Its very complex internal flow makes it hard to modify/fix. The internal flow of this adapter is much simpler,
|
|
19
|
+
* and handles all request resource types.
|
|
20
|
+
*
|
|
21
|
+
*/
|
|
22
|
+
export declare class PuppeteerAdapter extends PollyAdapter {
|
|
23
|
+
private subscriptions;
|
|
24
|
+
/**
|
|
25
|
+
* The puppeteer Page this adapter is attached to, obtained from
|
|
26
|
+
* options passed to the Polly constructor.
|
|
27
|
+
*/
|
|
28
|
+
private page;
|
|
29
|
+
/**
|
|
30
|
+
* The request resource types this adapter should intercept.
|
|
31
|
+
*/
|
|
32
|
+
private requestResourceTypes;
|
|
33
|
+
/**
|
|
34
|
+
* A map of all intercepted requests to their respond function, which will be called by the
|
|
35
|
+
* 'response' event listener, causing Polly to record the response content.
|
|
36
|
+
*/
|
|
37
|
+
private pendingRequests;
|
|
38
|
+
/**
|
|
39
|
+
* Maps passthrough requests to an object containing:
|
|
40
|
+
* - The response promise, which will be awaited in this.onPassthrough
|
|
41
|
+
* - A respond function, called by 'response' event listener, which resolves the response promise.
|
|
42
|
+
*/
|
|
43
|
+
private passThroughRequests;
|
|
44
|
+
/**
|
|
45
|
+
* The adapter's ID, used to reference it in the Polly constructor.
|
|
46
|
+
*/
|
|
47
|
+
static get id(): string;
|
|
48
|
+
constructor(polly: Polly);
|
|
49
|
+
/**
|
|
50
|
+
* Called when connecting to a Puppeteer page. Sets up request and response interceptors.
|
|
51
|
+
*/
|
|
52
|
+
onConnect(): void;
|
|
53
|
+
/**
|
|
54
|
+
* Called when disconnecting from a Puppeteer.page.
|
|
55
|
+
*/
|
|
56
|
+
onDisconnect(): void;
|
|
57
|
+
/**
|
|
58
|
+
* Given a request that should be allowed to pass through (not be intercepted),
|
|
59
|
+
* return a Promise of the Response for that request, which will be passed to
|
|
60
|
+
* request.respond().
|
|
61
|
+
*/
|
|
62
|
+
passthroughRequest(pollyRequest: PollyRequest): Promise<PollyResponse>;
|
|
63
|
+
/**
|
|
64
|
+
* Responds to an intercepted request with the given response.
|
|
65
|
+
*
|
|
66
|
+
* If an error happened when retreiving the response, abort the request.
|
|
67
|
+
*/
|
|
68
|
+
respondToRequest(pollyRequest: {
|
|
69
|
+
requestArguments: {
|
|
70
|
+
request: Puppeteer.Request;
|
|
71
|
+
};
|
|
72
|
+
response: PollyResponse;
|
|
73
|
+
}, error?: unknown): Promise<void>;
|
|
74
|
+
/**
|
|
75
|
+
* Called when a request is intercepted, for all requests (passthrough or stubbed).
|
|
76
|
+
*
|
|
77
|
+
* Adds an entry to pendingRequests, that will call the provided promise.resolve function
|
|
78
|
+
* when a response for this request is received.
|
|
79
|
+
*/
|
|
80
|
+
onRequest({ requestArguments: { request }, promise, }: {
|
|
81
|
+
requestArguments: {
|
|
82
|
+
request: Puppeteer.Request;
|
|
83
|
+
};
|
|
84
|
+
promise: {
|
|
85
|
+
resolve: (response: PollyResponse) => void;
|
|
86
|
+
};
|
|
87
|
+
}): void;
|
|
88
|
+
}
|
|
89
|
+
export {};
|
|
90
|
+
//# sourceMappingURL=PuppeteerAdapter.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"PuppeteerAdapter.d.ts","sourceRoot":"","sources":["../../src/test/PuppeteerAdapter.ts"],"names":[],"mappings":"AAAA,OAAO,YAAY,MAAM,kBAAkB,CAAA;AAC3C,OAAO,EAAE,KAAK,EAAE,OAAO,IAAI,YAAY,EAAE,MAAM,eAAe,CAAA;AAK9D,OAAO,KAAK,KAAK,SAAS,MAAM,WAAW,CAAA;AAuB3C,UAAU,aAAa;IACtB,UAAU,EAAE,MAAM,CAAA;IAClB,OAAO,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAA;IAC/B,IAAI,EAAE,MAAM,CAAA;IACZ,QAAQ,EAAE,OAAO,CAAA;CACjB;AAMD;;;;;;;;;;;GAWG;AACH,qBAAa,gBAAiB,SAAQ,YAAY;IACjD,OAAO,CAAC,aAAa,CAAqB;IAE1C;;;OAGG;IACH,OAAO,CAAC,IAAI,CAAgB;IAE5B;;OAEG;IACH,OAAO,CAAC,oBAAoB,CAA0B;IAEtD;;;OAGG;IACH,OAAO,CAAC,eAAe,CAA6F;IAEpH;;;;OAIG;IACH,OAAO,CAAC,mBAAmB,CAGxB;IAEH;;OAEG;IACH,WAAkB,EAAE,IAAI,MAAM,CAE7B;gBAEW,KAAK,EAAE,KAAK;IAQxB;;OAEG;IACI,SAAS,IAAI,IAAI;IAgDxB;;OAEG;IACI,YAAY,IAAI,IAAI;IAI3B;;;;OAIG;IACU,kBAAkB,CAAC,YAAY,EAAE,YAAY,GAAG,OAAO,CAAC,aAAa,CAAC;IA2BnF;;;;OAIG;IACU,gBAAgB,CAC5B,YAAY,EAAE;QACb,gBAAgB,EAAE;YAAE,OAAO,EAAE,SAAS,CAAC,OAAO,CAAA;SAAE,CAAA;QAChD,QAAQ,EAAE,aAAa,CAAA;KACvB,EACD,KAAK,CAAC,EAAE,OAAO,GACb,OAAO,CAAC,IAAI,CAAC;IAqBhB;;;;;OAKG;IACI,SAAS,CAAC,EAChB,gBAAgB,EAAE,EAAE,OAAO,EAAE,EAC7B,OAAO,GACP,EAAE;QACF,gBAAgB,EAAE;YAAE,OAAO,EAAE,SAAS,CAAC,OAAO,CAAA;SAAE,CAAA;QAChD,OAAO,EAAE;YACR,OAAO,EAAE,CAAC,QAAQ,EAAE,aAAa,KAAK,IAAI,CAAA;SAC1C,CAAA;KACD,GAAG,IAAI;CAyBR"}
|
|
@@ -0,0 +1,196 @@
|
|
|
1
|
+
import PollyAdapter from '@pollyjs/adapter';
|
|
2
|
+
import * as chardet from 'chardet';
|
|
3
|
+
import contentType from 'content-type';
|
|
4
|
+
import { mapValues } from 'lodash-es';
|
|
5
|
+
import mime from 'mime-types';
|
|
6
|
+
import { Subscription, fromEvent } from 'rxjs';
|
|
7
|
+
const GOOGLE_LOGO_URL = 'https://www.google.com/images/branding/googlelogo/2x/googlelogo_color_272x92dp.png';
|
|
8
|
+
const GOOGLE_LOGO_BODY = Buffer.from('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', 'base64');
|
|
9
|
+
function getBodyData(response, buffer) {
|
|
10
|
+
const type = response.headers()['content-type'];
|
|
11
|
+
let encoding = type ? contentType.parse(type).parameters.charset || mime.charset(type) : chardet.detect(buffer);
|
|
12
|
+
if (encoding) {
|
|
13
|
+
encoding = encoding.toLowerCase();
|
|
14
|
+
}
|
|
15
|
+
if (encoding) {
|
|
16
|
+
const decoder = new TextDecoder(encoding);
|
|
17
|
+
const body = decoder.decode(buffer);
|
|
18
|
+
return { body, isBinary: false };
|
|
19
|
+
}
|
|
20
|
+
return { body: buffer.toString('hex'), isBinary: true };
|
|
21
|
+
}
|
|
22
|
+
/**
|
|
23
|
+
* A Puppeteer adapter for Polly that supports all request resource types.
|
|
24
|
+
*
|
|
25
|
+
* TODO: upstream this?
|
|
26
|
+
*
|
|
27
|
+
* Polly's own Puppeteer adapter hangs when attempting to capture the page's initial document
|
|
28
|
+
* (requestResourceType==='document'). See https://github.com/Netflix/pollyjs/issues/121
|
|
29
|
+
*
|
|
30
|
+
* Its very complex internal flow makes it hard to modify/fix. The internal flow of this adapter is much simpler,
|
|
31
|
+
* and handles all request resource types.
|
|
32
|
+
*
|
|
33
|
+
*/
|
|
34
|
+
export class PuppeteerAdapter extends PollyAdapter {
|
|
35
|
+
constructor(polly) {
|
|
36
|
+
// eslint-disable-next-line @typescript-eslint/ban-ts-comment
|
|
37
|
+
// @ts-ignore
|
|
38
|
+
super(polly);
|
|
39
|
+
this.subscriptions = new Subscription();
|
|
40
|
+
/**
|
|
41
|
+
* A map of all intercepted requests to their respond function, which will be called by the
|
|
42
|
+
* 'response' event listener, causing Polly to record the response content.
|
|
43
|
+
*/
|
|
44
|
+
this.pendingRequests = new Map();
|
|
45
|
+
/**
|
|
46
|
+
* Maps passthrough requests to an object containing:
|
|
47
|
+
* - The response promise, which will be awaited in this.onPassthrough
|
|
48
|
+
* - A respond function, called by 'response' event listener, which resolves the response promise.
|
|
49
|
+
*/
|
|
50
|
+
this.passThroughRequests = new Map();
|
|
51
|
+
this.page = this.options.page;
|
|
52
|
+
this.requestResourceTypes = this.options.requestResourceTypes;
|
|
53
|
+
}
|
|
54
|
+
/**
|
|
55
|
+
* The adapter's ID, used to reference it in the Polly constructor.
|
|
56
|
+
*/
|
|
57
|
+
static get id() {
|
|
58
|
+
return 'puppeteer';
|
|
59
|
+
}
|
|
60
|
+
/**
|
|
61
|
+
* Called when connecting to a Puppeteer page. Sets up request and response interceptors.
|
|
62
|
+
*/
|
|
63
|
+
onConnect() {
|
|
64
|
+
this.subscriptions.add(fromEvent(this.page, 'request').subscribe(request => {
|
|
65
|
+
var _a;
|
|
66
|
+
const url = request.url();
|
|
67
|
+
const method = request.method();
|
|
68
|
+
const headers = request.headers();
|
|
69
|
+
const isPreflight = method === 'OPTIONS' && !!headers.origin && !!headers['access-control-request-method'];
|
|
70
|
+
if (isPreflight || !this.requestResourceTypes.includes(request.resourceType())) {
|
|
71
|
+
// eslint-disable-next-line @typescript-eslint/no-floating-promises
|
|
72
|
+
request.continue();
|
|
73
|
+
}
|
|
74
|
+
else {
|
|
75
|
+
// eslint-disable-next-line @typescript-eslint/ban-ts-comment
|
|
76
|
+
// @ts-ignore
|
|
77
|
+
this.handleRequest({
|
|
78
|
+
headers,
|
|
79
|
+
url,
|
|
80
|
+
method,
|
|
81
|
+
body: (_a = request.postData()) !== null && _a !== void 0 ? _a : '',
|
|
82
|
+
requestArguments: {
|
|
83
|
+
request,
|
|
84
|
+
},
|
|
85
|
+
});
|
|
86
|
+
}
|
|
87
|
+
}));
|
|
88
|
+
this.subscriptions.add(fromEvent(this.page, 'response').subscribe(response => {
|
|
89
|
+
var _a, _b;
|
|
90
|
+
const request = response.request();
|
|
91
|
+
if (this.pendingRequests.has(request)) {
|
|
92
|
+
(_a = this.pendingRequests
|
|
93
|
+
.get(request)) === null || _a === void 0 ? void 0 : _a.respond(response).catch(error => {
|
|
94
|
+
if (error.message.includes('No resource with given identifier found')) {
|
|
95
|
+
return;
|
|
96
|
+
}
|
|
97
|
+
console.error('Failed to respond:', error);
|
|
98
|
+
});
|
|
99
|
+
this.pendingRequests.delete(request);
|
|
100
|
+
}
|
|
101
|
+
if (this.passThroughRequests.has(request)) {
|
|
102
|
+
(_b = this.passThroughRequests.get(request)) === null || _b === void 0 ? void 0 : _b.respond(response);
|
|
103
|
+
}
|
|
104
|
+
}));
|
|
105
|
+
}
|
|
106
|
+
/**
|
|
107
|
+
* Called when disconnecting from a Puppeteer.page.
|
|
108
|
+
*/
|
|
109
|
+
onDisconnect() {
|
|
110
|
+
this.subscriptions.unsubscribe();
|
|
111
|
+
}
|
|
112
|
+
/**
|
|
113
|
+
* Given a request that should be allowed to pass through (not be intercepted),
|
|
114
|
+
* return a Promise of the Response for that request, which will be passed to
|
|
115
|
+
* request.respond().
|
|
116
|
+
*/
|
|
117
|
+
async passthroughRequest(pollyRequest) {
|
|
118
|
+
const { requestArguments: { request }, } = pollyRequest;
|
|
119
|
+
let respond;
|
|
120
|
+
const responsePromise = new Promise(resolve => (respond = resolve));
|
|
121
|
+
this.passThroughRequests.set(request, { respond: response => respond(response), responsePromise });
|
|
122
|
+
await request.continue();
|
|
123
|
+
const response = await responsePromise;
|
|
124
|
+
let bodyData = { isBinary: false, body: '' };
|
|
125
|
+
if (response.status() < 300 || response.status() >= 400) {
|
|
126
|
+
let buffer = await response.buffer();
|
|
127
|
+
// No idea why, but CDP/Puppeteer report the body as empty for this request.
|
|
128
|
+
if (response.url() === GOOGLE_LOGO_URL && response.status() === 200 && buffer.length === 0) {
|
|
129
|
+
buffer = GOOGLE_LOGO_BODY;
|
|
130
|
+
}
|
|
131
|
+
bodyData = getBodyData(response, buffer);
|
|
132
|
+
}
|
|
133
|
+
// Important: CDP rejects headers values separated by \n, but returns them this way for multiple header values (e.g. Vary).
|
|
134
|
+
const headers = mapValues(response.headers(), value => value.split('\n').join(', '));
|
|
135
|
+
return {
|
|
136
|
+
statusCode: response.status(),
|
|
137
|
+
headers,
|
|
138
|
+
...bodyData,
|
|
139
|
+
};
|
|
140
|
+
}
|
|
141
|
+
/**
|
|
142
|
+
* Responds to an intercepted request with the given response.
|
|
143
|
+
*
|
|
144
|
+
* If an error happened when retreiving the response, abort the request.
|
|
145
|
+
*/
|
|
146
|
+
async respondToRequest(pollyRequest, error) {
|
|
147
|
+
const { requestArguments: { request }, response: { statusCode: status, headers, body, isBinary }, } = pollyRequest;
|
|
148
|
+
// Do nothing for passthrough requests: Polly calls request.respond() internally.
|
|
149
|
+
if (this.passThroughRequests.has(request)) {
|
|
150
|
+
this.passThroughRequests.delete(request);
|
|
151
|
+
return;
|
|
152
|
+
}
|
|
153
|
+
if (error) {
|
|
154
|
+
await request.abort();
|
|
155
|
+
}
|
|
156
|
+
else {
|
|
157
|
+
await request.respond({
|
|
158
|
+
status,
|
|
159
|
+
headers,
|
|
160
|
+
body: isBinary ? Buffer.from(body, 'hex') : body,
|
|
161
|
+
});
|
|
162
|
+
}
|
|
163
|
+
}
|
|
164
|
+
/**
|
|
165
|
+
* Called when a request is intercepted, for all requests (passthrough or stubbed).
|
|
166
|
+
*
|
|
167
|
+
* Adds an entry to pendingRequests, that will call the provided promise.resolve function
|
|
168
|
+
* when a response for this request is received.
|
|
169
|
+
*/
|
|
170
|
+
onRequest({ requestArguments: { request }, promise, }) {
|
|
171
|
+
if (this.passThroughRequests.has(request)) {
|
|
172
|
+
return;
|
|
173
|
+
}
|
|
174
|
+
const respond = async (response) => {
|
|
175
|
+
let bodyData = { isBinary: false, body: '' };
|
|
176
|
+
if (response.status() < 300 || response.status() >= 400) {
|
|
177
|
+
let buffer = await response.buffer();
|
|
178
|
+
// No idea why, but CDP/Puppeteer report the body as empty for this request.
|
|
179
|
+
if (response.url() === GOOGLE_LOGO_URL && response.status() === 200 && buffer.length === 0) {
|
|
180
|
+
buffer = GOOGLE_LOGO_BODY;
|
|
181
|
+
}
|
|
182
|
+
bodyData = getBodyData(response, buffer);
|
|
183
|
+
}
|
|
184
|
+
const headers = mapValues(response.headers(), value => value.split('\n').join(', '));
|
|
185
|
+
promise.resolve({
|
|
186
|
+
statusCode: response.status(),
|
|
187
|
+
headers,
|
|
188
|
+
...bodyData,
|
|
189
|
+
});
|
|
190
|
+
};
|
|
191
|
+
this.pendingRequests.set(request, {
|
|
192
|
+
respond,
|
|
193
|
+
});
|
|
194
|
+
}
|
|
195
|
+
}
|
|
196
|
+
//# sourceMappingURL=PuppeteerAdapter.js.map
|