@amplitude/rrweb-utils
Version:
This package contains the shared utility functions used across rrweb packages. See the [guide](../../guide.md) for more info on rrweb.
168 lines (167 loc) • 5.32 kB
JavaScript
const testableAccessors = {
Node: ["childNodes", "parentNode", "parentElement", "textContent"],
ShadowRoot: ["host", "styleSheets"],
Element: ["shadowRoot", "querySelector", "querySelectorAll"],
MutationObserver: []
};
const testableMethods = {
Node: ["contains", "getRootNode"],
ShadowRoot: ["getSelection"],
Element: [],
MutationObserver: ["constructor"]
};
const untaintedBasePrototype = {};
function angularZoneUnpatchedAlternative(key) {
var _a, _b;
const angularUnpatchedVersionSymbol = (_b = (_a = globalThis == null ? void 0 : globalThis.Zone) == null ? void 0 : _a.__symbol__) == null ? void 0 : _b.call(_a, key);
if (angularUnpatchedVersionSymbol && globalThis[angularUnpatchedVersionSymbol]) {
return globalThis[angularUnpatchedVersionSymbol];
} else {
return void 0;
}
}
function getUntaintedPrototype(key) {
if (untaintedBasePrototype[key])
return untaintedBasePrototype[key];
const candidate = angularZoneUnpatchedAlternative(key) || globalThis[key];
const defaultPrototype = candidate.prototype;
const accessorNames = key in testableAccessors ? testableAccessors[key] : void 0;
const isUntaintedAccessors = Boolean(
accessorNames && // @ts-expect-error 2345
accessorNames.every(
(accessor) => {
var _a, _b;
return Boolean(
(_b = (_a = Object.getOwnPropertyDescriptor(defaultPrototype, accessor)) == null ? void 0 : _a.get) == null ? void 0 : _b.toString().includes("[native code]")
);
}
)
);
const methodNames = key in testableMethods ? testableMethods[key] : void 0;
const isUntaintedMethods = Boolean(
methodNames && methodNames.every(
// @ts-expect-error 2345
(method) => {
var _a;
return typeof defaultPrototype[method] === "function" && ((_a = defaultPrototype[method]) == null ? void 0 : _a.toString().includes("[native code]"));
}
)
);
if (isUntaintedAccessors && isUntaintedMethods) {
untaintedBasePrototype[key] = candidate.prototype;
return candidate.prototype;
}
try {
const iframeEl = document.createElement("iframe");
document.body.appendChild(iframeEl);
const win = iframeEl.contentWindow;
if (!win) return candidate.prototype;
const untaintedObject = win[key].prototype;
document.body.removeChild(iframeEl);
if (!untaintedObject) return defaultPrototype;
return untaintedBasePrototype[key] = untaintedObject;
} catch {
return defaultPrototype;
}
}
const untaintedAccessorCache = {};
function getUntaintedAccessor(key, instance, accessor) {
var _a;
const cacheKey = `${key}.${String(accessor)}`;
if (untaintedAccessorCache[cacheKey])
return untaintedAccessorCache[cacheKey].call(
instance
);
const untaintedPrototype = getUntaintedPrototype(key);
const untaintedAccessor = (_a = Object.getOwnPropertyDescriptor(
untaintedPrototype,
accessor
)) == null ? void 0 : _a.get;
if (!untaintedAccessor) return instance[accessor];
untaintedAccessorCache[cacheKey] = untaintedAccessor;
return untaintedAccessor.call(instance);
}
const untaintedMethodCache = {};
function getUntaintedMethod(key, instance, method) {
const cacheKey = `${key}.${String(method)}`;
if (untaintedMethodCache[cacheKey])
return untaintedMethodCache[cacheKey].bind(
instance
);
const untaintedPrototype = getUntaintedPrototype(key);
const untaintedMethod = untaintedPrototype[method];
if (typeof untaintedMethod !== "function") return instance[method];
untaintedMethodCache[cacheKey] = untaintedMethod;
return untaintedMethod.bind(instance);
}
function childNodes(n) {
return getUntaintedAccessor("Node", n, "childNodes");
}
function parentNode(n) {
return getUntaintedAccessor("Node", n, "parentNode");
}
function parentElement(n) {
return getUntaintedAccessor("Node", n, "parentElement");
}
function textContent(n) {
return getUntaintedAccessor("Node", n, "textContent");
}
function contains(n, other) {
return getUntaintedMethod("Node", n, "contains")(other);
}
function getRootNode(n) {
return getUntaintedMethod("Node", n, "getRootNode")();
}
function host(n) {
if (!n || !("host" in n)) return null;
return getUntaintedAccessor("ShadowRoot", n, "host");
}
function styleSheets(n) {
return n.styleSheets;
}
function shadowRoot(n) {
if (!n || !("shadowRoot" in n)) return null;
return getUntaintedAccessor("Element", n, "shadowRoot");
}
function querySelector(n, selectors) {
return getUntaintedAccessor("Element", n, "querySelector")(selectors);
}
function querySelectorAll(n, selectors) {
return getUntaintedAccessor("Element", n, "querySelectorAll")(selectors);
}
function mutationObserverCtor() {
return getUntaintedPrototype("MutationObserver").constructor;
}
const index = {
childNodes,
parentNode,
parentElement,
textContent,
contains,
getRootNode,
host,
styleSheets,
shadowRoot,
querySelector,
querySelectorAll,
mutationObserver: mutationObserverCtor
};
export {
childNodes,
contains,
index as default,
getRootNode,
getUntaintedAccessor,
getUntaintedMethod,
getUntaintedPrototype,
host,
mutationObserverCtor,
parentElement,
parentNode,
querySelector,
querySelectorAll,
shadowRoot,
styleSheets,
textContent
};
//# sourceMappingURL=rrweb-utils.js.map