refactor: eliminate eslint errors (#920)
* refactor: eliminate eslint errors as many as I can * refactor: fix more eslint errors in the record module * LINT: fix @typescript-eslint/unbound-method * LINT: fix all eslint errors in source code * LINT: fix as many eslint warnings as possible Co-authored-by: Justin Halsall <Juice10@users.noreply.github.com>
This commit is contained in:
@@ -1,3 +1,4 @@
|
||||
/* eslint-disable @typescript-eslint/no-unsafe-assignment */
|
||||
import { NodeType as RRNodeType } from 'rrweb-snapshot';
|
||||
import type { NWSAPI } from 'nwsapi';
|
||||
import type { CSSStyleDeclaration as CSSStyleDeclarationType } from 'cssstyle';
|
||||
@@ -14,8 +15,11 @@ import {
|
||||
IRRDocument,
|
||||
CSSStyleDeclaration,
|
||||
} from 'rrdom';
|
||||
// eslint-disable-next-line @typescript-eslint/no-unsafe-assignment, @typescript-eslint/no-var-requires
|
||||
const nwsapi = require('nwsapi');
|
||||
// eslint-disable-next-line @typescript-eslint/no-unsafe-assignment, @typescript-eslint/no-var-requires
|
||||
const cssom = require('cssom');
|
||||
// eslint-disable-next-line @typescript-eslint/no-unsafe-assignment, @typescript-eslint/no-var-requires
|
||||
const cssstyle = require('cssstyle');
|
||||
|
||||
export class RRNode extends BaseRRNode {}
|
||||
@@ -37,6 +41,7 @@ export class RRDocument
|
||||
private _nwsapi: NWSAPI;
|
||||
get nwsapi() {
|
||||
if (!this._nwsapi) {
|
||||
// eslint-disable-next-line @typescript-eslint/no-unsafe-assignment, @typescript-eslint/no-unsafe-call
|
||||
this._nwsapi = nwsapi({
|
||||
document: (this as unknown) as Document,
|
||||
DOMException: (null as unknown) as new (
|
||||
@@ -53,26 +58,31 @@ export class RRDocument
|
||||
return this._nwsapi;
|
||||
}
|
||||
|
||||
// eslint-disable-next-line @typescript-eslint/ban-ts-comment
|
||||
// @ts-ignore
|
||||
get documentElement(): RRElement | null {
|
||||
return super.documentElement as RRElement | null;
|
||||
}
|
||||
|
||||
// eslint-disable-next-line @typescript-eslint/ban-ts-comment
|
||||
// @ts-ignore
|
||||
get body(): RRElement | null {
|
||||
return super.body as RRElement | null;
|
||||
}
|
||||
|
||||
// eslint-disable-next-line @typescript-eslint/ban-ts-comment
|
||||
// @ts-ignore
|
||||
get head() {
|
||||
return super.head as RRElement | null;
|
||||
}
|
||||
|
||||
// eslint-disable-next-line @typescript-eslint/ban-ts-comment
|
||||
// @ts-ignore
|
||||
get implementation(): RRDocument {
|
||||
return this;
|
||||
}
|
||||
|
||||
// eslint-disable-next-line @typescript-eslint/ban-ts-comment
|
||||
// @ts-ignore
|
||||
get firstElementChild(): RRElement | null {
|
||||
return this.documentElement;
|
||||
@@ -109,8 +119,11 @@ export class RRDocument
|
||||
}
|
||||
|
||||
createDocument(
|
||||
// eslint-disable-next-line @typescript-eslint/no-unused-vars
|
||||
_namespace: string | null,
|
||||
// eslint-disable-next-line @typescript-eslint/no-unused-vars
|
||||
_qualifiedName: string | null,
|
||||
// eslint-disable-next-line @typescript-eslint/no-unused-vars
|
||||
_doctype?: DocumentType | null,
|
||||
) {
|
||||
return new RRDocument();
|
||||
@@ -191,6 +204,7 @@ export class RRElement extends BaseRRElementImpl(RRNode) {
|
||||
private _style: CSSStyleDeclarationType;
|
||||
constructor(tagName: string) {
|
||||
super(tagName);
|
||||
// eslint-disable-next-line @typescript-eslint/no-unsafe-assignment, @typescript-eslint/no-unsafe-call, @typescript-eslint/no-unsafe-member-access
|
||||
this._style = new cssstyle.CSSStyleDeclaration();
|
||||
const style = this._style;
|
||||
Object.defineProperty(this.attributes, 'style', {
|
||||
@@ -203,6 +217,7 @@ export class RRElement extends BaseRRElementImpl(RRNode) {
|
||||
});
|
||||
}
|
||||
|
||||
// eslint-disable-next-line @typescript-eslint/ban-ts-comment
|
||||
// @ts-ignore
|
||||
get style() {
|
||||
return (this._style as unknown) as CSSStyleDeclaration;
|
||||
@@ -311,7 +326,7 @@ export class RRImageElement extends RRElement {
|
||||
src: string;
|
||||
width: number;
|
||||
height: number;
|
||||
onload: ((this: GlobalEventHandlers, ev: Event) => any) | null;
|
||||
onload: ((this: GlobalEventHandlers, ev: Event) => unknown) | null;
|
||||
}
|
||||
|
||||
export class RRMediaElement extends BaseRRMediaElementImpl(RRElement) {}
|
||||
@@ -334,6 +349,7 @@ export class RRStyleElement extends RRElement {
|
||||
for (const child of this.childNodes)
|
||||
if (child.RRNodeType === RRNodeType.Text)
|
||||
result += (child as RRText).textContent;
|
||||
// eslint-disable-next-line @typescript-eslint/no-unsafe-member-access, @typescript-eslint/no-unsafe-call
|
||||
this._sheet = cssom.parse(result);
|
||||
}
|
||||
return this._sheet;
|
||||
|
||||
@@ -7,8 +7,9 @@ import { RRDocument, RRNode } from './document-nodejs';
|
||||
*/
|
||||
export function polyfillPerformance() {
|
||||
if (typeof window !== 'undefined' || 'performance' in global) return;
|
||||
((global as Window & typeof globalThis)
|
||||
.performance as unknown) = require('perf_hooks').performance;
|
||||
// eslint-disable-next-line @typescript-eslint/no-unsafe-assignment, @typescript-eslint/no-unsafe-member-access, @typescript-eslint/no-var-requires
|
||||
const performance = require('perf_hooks').performance;
|
||||
((global as Window & typeof globalThis).performance as unknown) = performance;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -22,11 +23,11 @@ export function polyfillRAF() {
|
||||
INTERVAL = 1_000 / FPS;
|
||||
let timeoutHandle: NodeJS.Timeout | null = null,
|
||||
rafCount = 0,
|
||||
requests = Object.create(null);
|
||||
requests = Object.create(null) as Record<string, (time: number) => void>;
|
||||
|
||||
function onFrameTimer() {
|
||||
const currentRequests = requests;
|
||||
requests = Object.create(null);
|
||||
requests = Object.create(null) as Record<string, (time: number) => void>;
|
||||
timeoutHandle = null;
|
||||
Object.keys(currentRequests).forEach(function (id) {
|
||||
const request = currentRequests[id];
|
||||
@@ -63,7 +64,9 @@ export function polyfillRAF() {
|
||||
*/
|
||||
export function polyfillEvent() {
|
||||
if (typeof Event !== 'undefined') return;
|
||||
(global.Event as unknown) = function () {};
|
||||
(global.Event as unknown) = function () {
|
||||
//
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -125,8 +125,8 @@ export function diff(
|
||||
const newMediaRRElement = newRRElement as RRMediaElement;
|
||||
if (newMediaRRElement.paused !== undefined)
|
||||
newMediaRRElement.paused
|
||||
? oldMediaElement.pause()
|
||||
: oldMediaElement.play();
|
||||
? void oldMediaElement.pause()
|
||||
: void oldMediaElement.play();
|
||||
if (newMediaRRElement.muted !== undefined)
|
||||
oldMediaElement.muted = newMediaRRElement.muted;
|
||||
if (newMediaRRElement.volume !== undefined)
|
||||
@@ -383,10 +383,7 @@ export function createOrGetNode(
|
||||
let tagName = (rrNode as IRRElement).tagName.toLowerCase();
|
||||
tagName = SVGTagMap[tagName] || tagName;
|
||||
if (sn && 'isSVG' in sn && sn?.isSVG) {
|
||||
node = document.createElementNS(
|
||||
NAMESPACES['svg'],
|
||||
(rrNode as IRRElement).tagName.toLowerCase(),
|
||||
);
|
||||
node = document.createElementNS(NAMESPACES['svg'], tagName);
|
||||
} else node = document.createElement((rrNode as IRRElement).tagName);
|
||||
break;
|
||||
}
|
||||
|
||||
@@ -119,6 +119,7 @@ export interface IRRCDATASection extends IRRNode {
|
||||
}
|
||||
|
||||
type ConstrainedConstructor<T = Record<string, unknown>> = new (
|
||||
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
||||
...args: any[]
|
||||
) => T;
|
||||
|
||||
@@ -138,7 +139,8 @@ export class BaseRRNode implements IRRNode {
|
||||
public readonly nodeName: string;
|
||||
public readonly RRNodeType: RRNodeType;
|
||||
|
||||
constructor(...args: any[]) {
|
||||
// eslint-disable-next-line @typescript-eslint/no-unused-vars, @typescript-eslint/no-explicit-any
|
||||
constructor(..._args: any[]) {
|
||||
//
|
||||
}
|
||||
|
||||
@@ -166,19 +168,22 @@ export class BaseRRNode implements IRRNode {
|
||||
return false;
|
||||
}
|
||||
|
||||
// eslint-disable-next-line @typescript-eslint/no-unused-vars
|
||||
public appendChild(_newChild: IRRNode): IRRNode {
|
||||
throw new Error(
|
||||
`RRDomException: Failed to execute 'appendChild' on 'RRNode': This RRNode type does not support this method.`,
|
||||
);
|
||||
}
|
||||
|
||||
// eslint-disable-next-line @typescript-eslint/no-unused-vars
|
||||
public insertBefore(_newChild: IRRNode, _refChild: IRRNode | null): IRRNode {
|
||||
throw new Error(
|
||||
`RRDomException: Failed to execute 'insertBefore' on 'RRNode': This RRNode type does not support this method.`,
|
||||
);
|
||||
}
|
||||
|
||||
public removeChild(node: IRRNode): IRRNode {
|
||||
// eslint-disable-next-line @typescript-eslint/no-unused-vars
|
||||
public removeChild(_node: IRRNode): IRRNode {
|
||||
throw new Error(
|
||||
`RRDomException: Failed to execute 'removeChild' on 'RRNode': This RRNode type does not support this method.`,
|
||||
);
|
||||
@@ -306,8 +311,8 @@ export function BaseRRDocumentImpl<
|
||||
/**
|
||||
* Adhoc implementation for setting xhtml namespace in rebuilt.ts (rrweb-snapshot).
|
||||
* There are two lines used this function:
|
||||
* 1. doc.write('<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "">')
|
||||
* 2. doc.write('<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN" "">')
|
||||
* 1. doc.write('\<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" ""\>')
|
||||
* 2. doc.write('\<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN" ""\>')
|
||||
*/
|
||||
public write(content: string) {
|
||||
let publicId;
|
||||
@@ -329,8 +334,11 @@ export function BaseRRDocumentImpl<
|
||||
}
|
||||
|
||||
createDocument(
|
||||
// eslint-disable-next-line @typescript-eslint/no-unused-vars
|
||||
_namespace: string | null,
|
||||
// eslint-disable-next-line @typescript-eslint/no-unused-vars
|
||||
_qualifiedName: string | null,
|
||||
// eslint-disable-next-line @typescript-eslint/no-unused-vars
|
||||
_doctype?: DocumentType | null,
|
||||
): IRRDocument {
|
||||
return new BaseRRDocument();
|
||||
@@ -542,12 +550,14 @@ export function BaseRRElementImpl<
|
||||
return node;
|
||||
}
|
||||
|
||||
// eslint-disable-next-line @typescript-eslint/no-unused-vars
|
||||
public attachShadow(_init: ShadowRootInit): IRRElement {
|
||||
const shadowRoot = this.ownerDocument.createElement('SHADOWROOT');
|
||||
this.shadowRoot = shadowRoot;
|
||||
return shadowRoot;
|
||||
}
|
||||
|
||||
// eslint-disable-next-line @typescript-eslint/no-unused-vars
|
||||
public dispatchEvent(_event: Event) {
|
||||
return true;
|
||||
}
|
||||
@@ -570,6 +580,7 @@ export function BaseRRMediaElementImpl<
|
||||
public volume?: number;
|
||||
public paused?: boolean;
|
||||
public muted?: boolean;
|
||||
// eslint-disable-next-line @typescript-eslint/no-unused-vars
|
||||
attachShadow(_init: ShadowRootInit): IRRElement {
|
||||
throw new Error(
|
||||
`RRDomException: Failed to execute 'attachShadow' on 'RRElement': This RRElement does not support attachShadow`,
|
||||
|
||||
@@ -35,7 +35,7 @@ import {
|
||||
export class RRDocument extends BaseRRDocumentImpl(RRNode) {
|
||||
// In the rrweb replayer, there are some unserialized nodes like the element that stores the injected style rules.
|
||||
// These unserialized nodes may interfere the execution of the diff algorithm.
|
||||
// The id of serialized node is larger than 0. So this value less than 0 is used as id for these unserialized nodes.
|
||||
// The id of serialized node is larger than 0. So this value less than 0 is used as id for these unserialized nodes.
|
||||
private _unserializedId = -1;
|
||||
|
||||
/**
|
||||
@@ -57,8 +57,11 @@ export class RRDocument extends BaseRRDocumentImpl(RRNode) {
|
||||
}
|
||||
|
||||
createDocument(
|
||||
// eslint-disable-next-line @typescript-eslint/no-unused-vars
|
||||
_namespace: string | null,
|
||||
// eslint-disable-next-line @typescript-eslint/no-unused-vars
|
||||
_qualifiedName: string | null,
|
||||
// eslint-disable-next-line @typescript-eslint/no-unused-vars
|
||||
_doctype?: DocumentType | null,
|
||||
) {
|
||||
return new RRDocument();
|
||||
@@ -201,9 +204,9 @@ function getValidTagName(element: HTMLElement): string {
|
||||
|
||||
/**
|
||||
* Build a RRNode from a real Node.
|
||||
* @param node the real Node
|
||||
* @param rrdom the RRDocument
|
||||
* @param domMirror the NodeMirror that records the real document tree
|
||||
* @param node - the real Node
|
||||
* @param rrdom - the RRDocument
|
||||
* @param domMirror - the NodeMirror that records the real document tree
|
||||
* @returns the built RRNode
|
||||
*/
|
||||
export function buildFromNode(
|
||||
@@ -225,7 +228,7 @@ export function buildFromNode(
|
||||
| 'CSS1Compat';
|
||||
}
|
||||
break;
|
||||
case NodeType.DOCUMENT_TYPE_NODE:
|
||||
case NodeType.DOCUMENT_TYPE_NODE: {
|
||||
const documentType = node as DocumentType;
|
||||
rrNode = rrdom.createDocumentType(
|
||||
documentType.name,
|
||||
@@ -233,7 +236,8 @@ export function buildFromNode(
|
||||
documentType.systemId,
|
||||
);
|
||||
break;
|
||||
case NodeType.ELEMENT_NODE:
|
||||
}
|
||||
case NodeType.ELEMENT_NODE: {
|
||||
const elementNode = node as HTMLElement;
|
||||
const tagName = getValidTagName(elementNode);
|
||||
rrNode = rrdom.createElement(tagName);
|
||||
@@ -248,6 +252,7 @@ export function buildFromNode(
|
||||
* Because if these values are changed later, the mutation will be applied through the batched input events on its RRElement after the diff algorithm is executed.
|
||||
*/
|
||||
break;
|
||||
}
|
||||
case NodeType.TEXT_NODE:
|
||||
rrNode = rrdom.createTextNode((node as Text).textContent || '');
|
||||
break;
|
||||
@@ -280,9 +285,9 @@ export function buildFromNode(
|
||||
|
||||
/**
|
||||
* Build a RRDocument from a real document tree.
|
||||
* @param dom the real document tree
|
||||
* @param domMirror the NodeMirror that records the real document tree
|
||||
* @param rrdom the rrdom object to be constructed
|
||||
* @param dom - the real document tree
|
||||
* @param domMirror - the NodeMirror that records the real document tree
|
||||
* @param rrdom - the rrdom object to be constructed
|
||||
* @returns the build rrdom
|
||||
*/
|
||||
export function buildFromDom(
|
||||
@@ -390,7 +395,7 @@ export class Mirror implements IMirror<RRNode> {
|
||||
|
||||
/**
|
||||
* Get a default serializedNodeWithId value for a RRNode.
|
||||
* @param id the serialized id to assign
|
||||
* @param id - the serialized id to assign
|
||||
*/
|
||||
export function getDefaultSN(node: IRRNode, id: number): serializedNodeWithId {
|
||||
switch (node.RRNodeType) {
|
||||
@@ -400,7 +405,7 @@ export function getDefaultSN(node: IRRNode, id: number): serializedNodeWithId {
|
||||
type: node.RRNodeType,
|
||||
childNodes: [],
|
||||
};
|
||||
case RRNodeType.DocumentType:
|
||||
case RRNodeType.DocumentType: {
|
||||
const doctype = node as IRRDocumentType;
|
||||
return {
|
||||
id,
|
||||
@@ -409,6 +414,7 @@ export function getDefaultSN(node: IRRNode, id: number): serializedNodeWithId {
|
||||
publicId: doctype.publicId,
|
||||
systemId: doctype.systemId,
|
||||
};
|
||||
}
|
||||
case RRNodeType.Element:
|
||||
return {
|
||||
id,
|
||||
@@ -438,6 +444,33 @@ export function getDefaultSN(node: IRRNode, id: number): serializedNodeWithId {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Print the RRDom as a string.
|
||||
* @param rootNode - the root node of the RRDom tree
|
||||
* @param mirror - a rrweb or rrdom Mirror
|
||||
* @returns printed string
|
||||
*/
|
||||
export function printRRDom(rootNode: IRRNode, mirror: IMirror<IRRNode>) {
|
||||
return walk(rootNode, mirror, '');
|
||||
}
|
||||
function walk(node: IRRNode, mirror: IMirror<IRRNode>, blankSpace: string) {
|
||||
let printText = `${blankSpace}${mirror.getId(node)} ${node.toString()}\n`;
|
||||
if (node.RRNodeType === RRNodeType.Element) {
|
||||
const element = node as IRRElement;
|
||||
if (element.shadowRoot)
|
||||
printText += walk(element.shadowRoot, mirror, blankSpace + ' ');
|
||||
}
|
||||
for (const child of node.childNodes)
|
||||
printText += walk(child, mirror, blankSpace + ' ');
|
||||
if (node.nodeName === 'IFRAME')
|
||||
printText += walk(
|
||||
(node as RRIFrameElement).contentDocument,
|
||||
mirror,
|
||||
blankSpace + ' ',
|
||||
);
|
||||
return printText;
|
||||
}
|
||||
|
||||
export { RRNode };
|
||||
|
||||
export {
|
||||
|
||||
@@ -33,7 +33,7 @@ const camelizeRE = /-([a-z])/g;
|
||||
const CUSTOM_PROPERTY_REGEX = /^--[a-zA-Z0-9-]+$/;
|
||||
export const camelize = (str: string): string => {
|
||||
if (CUSTOM_PROPERTY_REGEX.test(str)) return str;
|
||||
return str.replace(camelizeRE, (_, c) => (c ? c.toUpperCase() : ''));
|
||||
return str.replace(camelizeRE, (_, c: string) => (c ? c.toUpperCase() : ''));
|
||||
};
|
||||
|
||||
/**
|
||||
|
||||
@@ -905,8 +905,8 @@ describe('diff algorithm for rrdom', () => {
|
||||
/* Number of elements remains the same and no element will be added or removed. */
|
||||
let oldElementsNum = 15,
|
||||
newElementsNum = 15;
|
||||
let oldElementsIds = [],
|
||||
newElementsIds = [];
|
||||
let oldElementsIds: number[] = [],
|
||||
newElementsIds: number[] = [];
|
||||
for (let i = 1; i <= oldElementsNum; i++) {
|
||||
oldElementsIds.push(i);
|
||||
newElementsIds.push(i);
|
||||
@@ -950,8 +950,8 @@ describe('diff algorithm for rrdom', () => {
|
||||
/* May need to add or remove some elements. */
|
||||
let oldElementsNum = 20,
|
||||
newElementsNum = 30;
|
||||
let oldElementsIds = [],
|
||||
newElementsIds = [];
|
||||
let oldElementsIds: number[] = [],
|
||||
newElementsIds: number[] = [];
|
||||
for (let i = 1; i <= oldElementsNum + 10; i++) oldElementsIds.push(i);
|
||||
for (let i = 1; i <= newElementsNum + 10; i++) newElementsIds.push(i);
|
||||
shuffle(oldElementsIds);
|
||||
|
||||
@@ -118,6 +118,7 @@ export function typeOf(
|
||||
| 'undefined'
|
||||
| 'null'
|
||||
| 'object' {
|
||||
// eslint-disable-next-line @typescript-eslint/unbound-method
|
||||
const toString = Object.prototype.toString;
|
||||
const map = {
|
||||
'[object Boolean]': 'boolean',
|
||||
@@ -131,5 +132,6 @@ export function typeOf(
|
||||
'[object Null]': 'null',
|
||||
'[object Object]': 'object',
|
||||
};
|
||||
// eslint-disable-next-line @typescript-eslint/no-unsafe-return, @typescript-eslint/no-unsafe-member-access
|
||||
return map[toString.call(obj)];
|
||||
}
|
||||
|
||||
@@ -4,8 +4,7 @@
|
||||
* 1. The css library was built for node.js which does not have tree-shaking supports.
|
||||
* 2. Rewrites into typescript give us a better type interface.
|
||||
*/
|
||||
|
||||
/* tslint:disable no-conditional-assignment interface-name no-shadowed-variable */
|
||||
/* eslint-disable tsdoc/syntax */
|
||||
|
||||
export interface ParserOptions {
|
||||
/** Silently fail on parse errors */
|
||||
@@ -288,7 +287,7 @@ export function parse(css: string, options: ParserOptions = {}) {
|
||||
|
||||
function error(msg: string) {
|
||||
const err = new Error(
|
||||
options.source + ':' + lineno + ':' + column + ': ' + msg,
|
||||
`${options.source || ''}:${lineno}:${column}: ${msg}`,
|
||||
) as ParserError;
|
||||
err.reason = msg;
|
||||
err.filename = options.source;
|
||||
@@ -457,6 +456,7 @@ export function parse(css: string, options: ParserOptions = {}) {
|
||||
const pos = position();
|
||||
|
||||
// prop
|
||||
// eslint-disable-next-line no-useless-escape
|
||||
const propMatch = match(/^(\*?[-#\/\*\\\w]+(\[[0-9a-z_-]+\])?)\s*/);
|
||||
if (!propMatch) {
|
||||
return;
|
||||
@@ -469,6 +469,7 @@ export function parse(css: string, options: ParserOptions = {}) {
|
||||
}
|
||||
|
||||
// val
|
||||
// eslint-disable-next-line no-useless-escape
|
||||
const val = match(/^((?:'(?:\\'|.)*?'|"(?:\\"|.)*?"|\([^\)]*?\)|[^};])+)/);
|
||||
|
||||
const ret = pos({
|
||||
@@ -889,6 +890,7 @@ function addParent(obj: Stylesheet, parent?: Stylesheet) {
|
||||
const value = obj[k as keyof Stylesheet];
|
||||
if (Array.isArray(value)) {
|
||||
value.forEach((v) => {
|
||||
// eslint-disable-next-line @typescript-eslint/no-unsafe-argument
|
||||
addParent(v, childParent);
|
||||
});
|
||||
} else if (value && typeof value === 'object') {
|
||||
|
||||
@@ -134,7 +134,7 @@ function buildNode(
|
||||
n.publicId,
|
||||
n.systemId,
|
||||
);
|
||||
case NodeType.Element:
|
||||
case NodeType.Element: {
|
||||
const tagName = getTagName(n);
|
||||
let node: Element;
|
||||
if (n.isSVG) {
|
||||
@@ -143,7 +143,7 @@ function buildNode(
|
||||
node = doc.createElement(tagName);
|
||||
}
|
||||
for (const name in n.attributes) {
|
||||
if (!n.attributes.hasOwnProperty(name)) {
|
||||
if (!Object.prototype.hasOwnProperty.call(n.attributes, name)) {
|
||||
continue;
|
||||
}
|
||||
let value = n.attributes[name];
|
||||
@@ -290,6 +290,7 @@ function buildNode(
|
||||
}
|
||||
}
|
||||
return node;
|
||||
}
|
||||
case NodeType.Text:
|
||||
return doc.createTextNode(
|
||||
n.isStyle && hackCss
|
||||
@@ -417,7 +418,12 @@ function handleScroll(node: Node, mirror: Mirror) {
|
||||
}
|
||||
const el = node as HTMLElement;
|
||||
for (const name in n.attributes) {
|
||||
if (!(n.attributes.hasOwnProperty(name) && name.startsWith('rr_'))) {
|
||||
if (
|
||||
!(
|
||||
Object.prototype.hasOwnProperty.call(n.attributes, name) &&
|
||||
name.startsWith('rr_')
|
||||
)
|
||||
) {
|
||||
continue;
|
||||
}
|
||||
const value = n.attributes[name];
|
||||
|
||||
@@ -102,7 +102,14 @@ export function absoluteToStylesheet(
|
||||
): string {
|
||||
return (cssText || '').replace(
|
||||
URL_IN_CSS_REF,
|
||||
(origin, quote1, path1, quote2, path2, path3) => {
|
||||
(
|
||||
origin: string,
|
||||
quote1: string,
|
||||
path1: string,
|
||||
quote2: string,
|
||||
path2: string,
|
||||
path3: string,
|
||||
) => {
|
||||
const filePath = path1 || path2 || path3;
|
||||
const maybeQuote = quote1 || quote2 || '';
|
||||
if (!filePath) {
|
||||
@@ -136,7 +143,9 @@ export function absoluteToStylesheet(
|
||||
);
|
||||
}
|
||||
|
||||
// eslint-disable-next-line no-control-regex
|
||||
const SRCSET_NOT_SPACES = /^[^ \t\n\r\u000c]+/; // Don't use \s, to avoid matching non-breaking space
|
||||
// eslint-disable-next-line no-control-regex
|
||||
const SRCSET_COMMAS_OR_SPACES = /^[, \t\n\r\u000c]+/;
|
||||
function getAbsoluteSrcsetString(doc: Document, attributeValue: string) {
|
||||
/*
|
||||
@@ -165,6 +174,7 @@ function getAbsoluteSrcsetString(doc: Document, attributeValue: string) {
|
||||
}
|
||||
|
||||
const output = [];
|
||||
// eslint-disable-next-line no-constant-condition
|
||||
while (true) {
|
||||
collectCharacters(SRCSET_COMMAS_OR_SPACES);
|
||||
if (pos >= attributeValue.length) {
|
||||
@@ -182,6 +192,7 @@ function getAbsoluteSrcsetString(doc: Document, attributeValue: string) {
|
||||
let descriptorsStr = '';
|
||||
url = absoluteToDoc(doc, url);
|
||||
let inParens = false;
|
||||
// eslint-disable-next-line no-constant-condition
|
||||
while (true) {
|
||||
const c = attributeValue.charAt(pos);
|
||||
if (c === '') {
|
||||
@@ -554,7 +565,7 @@ function serializeTextNode(
|
||||
}
|
||||
} catch (err) {
|
||||
console.warn(
|
||||
`Cannot get CSS styles from text's parentNode. Error: ${err}`,
|
||||
`Cannot get CSS styles from text's parentNode. Error: ${err as string}`,
|
||||
n,
|
||||
);
|
||||
}
|
||||
@@ -740,7 +751,7 @@ function serializeElementNode(
|
||||
);
|
||||
} catch (err) {
|
||||
console.warn(
|
||||
`Cannot inline img src=${image.currentSrc}! Error: ${err}`,
|
||||
`Cannot inline img src=${image.currentSrc}! Error: ${err as string}`,
|
||||
);
|
||||
}
|
||||
oldValue
|
||||
|
||||
@@ -122,6 +122,7 @@ export function is2DCanvasBlank(canvas: HTMLCanvasElement): boolean {
|
||||
// get chunks of the canvas and check if it is blank
|
||||
for (let x = 0; x < canvas.width; x += chunkSize) {
|
||||
for (let y = 0; y < canvas.height; y += chunkSize) {
|
||||
// eslint-disable-next-line @typescript-eslint/unbound-method
|
||||
const getImageData = ctx.getImageData as PatchedGetImageData;
|
||||
const originalGetImageData =
|
||||
ORIGINAL_ATTRIBUTE_NAME in getImageData
|
||||
@@ -132,6 +133,7 @@ export function is2DCanvasBlank(canvas: HTMLCanvasElement): boolean {
|
||||
// even if we can already tell from the first chunk(s) that
|
||||
// the canvas isn't blank
|
||||
const pixelBuffer = new Uint32Array(
|
||||
// eslint-disable-next-line @typescript-eslint/no-unsafe-argument, @typescript-eslint/no-unsafe-member-access
|
||||
originalGetImageData.call(
|
||||
ctx,
|
||||
x,
|
||||
|
||||
@@ -78,7 +78,7 @@
|
||||
"@xstate/fsm": "^1.4.0",
|
||||
"base64-arraybuffer": "^1.0.1",
|
||||
"fflate": "^0.4.4",
|
||||
"mitt": "^1.1.3",
|
||||
"mitt": "^3.0.0",
|
||||
"rrdom": "^0.1.2",
|
||||
"rrweb-snapshot": "^1.1.14"
|
||||
}
|
||||
|
||||
@@ -7,7 +7,7 @@ export const unpack: UnpackFn = (raw: string) => {
|
||||
return raw;
|
||||
}
|
||||
try {
|
||||
const e: eventWithTime = JSON.parse(raw);
|
||||
const e: eventWithTime = JSON.parse(raw) as eventWithTime;
|
||||
if (e.timestamp) {
|
||||
return e;
|
||||
}
|
||||
@@ -17,7 +17,7 @@ export const unpack: UnpackFn = (raw: string) => {
|
||||
try {
|
||||
const e: eventWithTimeAndPacker = JSON.parse(
|
||||
strFromU8(unzlibSync(strToU8(raw, true))),
|
||||
);
|
||||
) as eventWithTimeAndPacker;
|
||||
if (e.v === MARK) {
|
||||
return e;
|
||||
}
|
||||
|
||||
@@ -1,3 +1,8 @@
|
||||
/* eslint-disable @typescript-eslint/no-unsafe-argument */
|
||||
/* eslint-disable @typescript-eslint/no-unsafe-assignment */
|
||||
/* eslint-disable @typescript-eslint/no-unsafe-call */
|
||||
/* eslint-disable @typescript-eslint/no-unsafe-member-access */
|
||||
/* eslint-disable @typescript-eslint/no-unsafe-return */
|
||||
// tslint:disable
|
||||
/**
|
||||
* Class StackFrame is a fork of https://github.com/stacktracejs/stackframe/blob/master/stackframe.js
|
||||
@@ -27,19 +32,9 @@ export class StackFrame {
|
||||
toString() {
|
||||
const lineNumber = this.lineNumber || '';
|
||||
const columnNumber = this.columnNumber || '';
|
||||
if (this.functionName) {
|
||||
return (
|
||||
this.functionName +
|
||||
' (' +
|
||||
this.fileName +
|
||||
':' +
|
||||
lineNumber +
|
||||
':' +
|
||||
columnNumber +
|
||||
')'
|
||||
);
|
||||
}
|
||||
return this.fileName + ':' + lineNumber + ':' + columnNumber;
|
||||
if (this.functionName)
|
||||
return `${this.functionName} (${this.fileName}:${lineNumber}:${columnNumber})`;
|
||||
return `${this.fileName}:${lineNumber}:${columnNumber}`;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -55,9 +50,6 @@ const SAFARI_NATIVE_CODE_REGEXP = /^(eval@)?(\[native code])?$/;
|
||||
export const ErrorStackParser = {
|
||||
/**
|
||||
* Given an Error object, extract the most information from it.
|
||||
*
|
||||
* @param {Error} error object
|
||||
* @return {Array} of StackFrames
|
||||
*/
|
||||
parse: function (error: Error): StackFrame[] {
|
||||
// https://github.com/rrweb-io/rrweb/issues/782
|
||||
@@ -65,8 +57,10 @@ export const ErrorStackParser = {
|
||||
return [];
|
||||
}
|
||||
if (
|
||||
// eslint-disable-next-line @typescript-eslint/ban-ts-comment
|
||||
// @ts-ignore
|
||||
typeof error.stacktrace !== 'undefined' ||
|
||||
// eslint-disable-next-line @typescript-eslint/ban-ts-comment
|
||||
// @ts-ignore
|
||||
typeof error['opera#sourceloc'] !== 'undefined'
|
||||
) {
|
||||
|
||||
@@ -59,27 +59,6 @@ export type LogData = {
|
||||
|
||||
type logCallback = (p: LogData) => void;
|
||||
|
||||
export type LogLevel =
|
||||
| 'assert'
|
||||
| 'clear'
|
||||
| 'count'
|
||||
| 'countReset'
|
||||
| 'debug'
|
||||
| 'dir'
|
||||
| 'dirxml'
|
||||
| 'error'
|
||||
| 'group'
|
||||
| 'groupCollapsed'
|
||||
| 'groupEnd'
|
||||
| 'info'
|
||||
| 'log'
|
||||
| 'table'
|
||||
| 'time'
|
||||
| 'timeEnd'
|
||||
| 'timeLog'
|
||||
| 'trace'
|
||||
| 'warn';
|
||||
|
||||
/* fork from interface Console */
|
||||
// all kinds of console functions
|
||||
export type Logger = {
|
||||
@@ -104,14 +83,26 @@ export type Logger = {
|
||||
warn?: typeof console.warn;
|
||||
};
|
||||
|
||||
export type LogLevel = keyof Logger;
|
||||
|
||||
function initLogObserver(
|
||||
cb: logCallback,
|
||||
win: IWindow, // top window or in an iframe
|
||||
logOptions: LogRecordOptions,
|
||||
options: LogRecordOptions,
|
||||
): listenerHandler {
|
||||
const logOptions = (options
|
||||
? Object.assign({}, defaultLogOptions, options)
|
||||
: defaultLogOptions) as {
|
||||
level: LogLevel[];
|
||||
lengthThreshold: number;
|
||||
stringifyOptions?: StringifyOptions;
|
||||
logger: Logger | 'console';
|
||||
};
|
||||
const loggerType = logOptions.logger;
|
||||
if (!loggerType) {
|
||||
return () => {};
|
||||
return () => {
|
||||
//
|
||||
};
|
||||
}
|
||||
let logger: Logger;
|
||||
if (typeof loggerType === 'string') {
|
||||
@@ -122,10 +113,11 @@ function initLogObserver(
|
||||
let logCount = 0;
|
||||
const cancelHandlers: listenerHandler[] = [];
|
||||
// add listener to thrown errors
|
||||
if (logOptions.level!.includes('error')) {
|
||||
if (logOptions.level.includes('error')) {
|
||||
if (window) {
|
||||
const errorHandler = (event: ErrorEvent) => {
|
||||
const { message, error } = event;
|
||||
const message = event.message,
|
||||
error = event.error as Error;
|
||||
const trace: string[] = ErrorStackParser.parse(
|
||||
error,
|
||||
).map((stackFrame: StackFrame) => stackFrame.toString());
|
||||
@@ -142,7 +134,7 @@ function initLogObserver(
|
||||
});
|
||||
}
|
||||
}
|
||||
for (const levelType of logOptions.level!) {
|
||||
for (const levelType of logOptions.level) {
|
||||
cancelHandlers.push(replace(logger, levelType));
|
||||
}
|
||||
return () => {
|
||||
@@ -151,46 +143,52 @@ function initLogObserver(
|
||||
|
||||
/**
|
||||
* replace the original console function and record logs
|
||||
* @param logger the logger object such as Console
|
||||
* @param level the name of log function to be replaced
|
||||
* @param logger - the logger object such as Console
|
||||
* @param level - the name of log function to be replaced
|
||||
*/
|
||||
function replace(_logger: Logger, level: LogLevel) {
|
||||
if (!_logger[level]) {
|
||||
return () => {};
|
||||
return () => {
|
||||
//
|
||||
};
|
||||
}
|
||||
// replace the logger.{level}. return a restore function
|
||||
return patch(_logger, level, (original) => {
|
||||
return (...args: Array<unknown>) => {
|
||||
original.apply(this, args);
|
||||
try {
|
||||
const trace = ErrorStackParser.parse(new Error())
|
||||
.map((stackFrame: StackFrame) => stackFrame.toString())
|
||||
.splice(1); // splice(1) to omit the hijacked log function
|
||||
const payload = args.map((s) =>
|
||||
stringify(s, logOptions.stringifyOptions),
|
||||
);
|
||||
logCount++;
|
||||
if (logCount < logOptions.lengthThreshold!) {
|
||||
cb({
|
||||
level,
|
||||
trace,
|
||||
payload,
|
||||
});
|
||||
} else if (logCount === logOptions.lengthThreshold) {
|
||||
// notify the user
|
||||
cb({
|
||||
level: 'warn',
|
||||
trace: [],
|
||||
payload: [
|
||||
stringify('The number of log records reached the threshold.'),
|
||||
],
|
||||
});
|
||||
return patch(
|
||||
_logger,
|
||||
level,
|
||||
(original: (...args: Array<unknown>) => void) => {
|
||||
return (...args: Array<unknown>) => {
|
||||
original.apply(this, args);
|
||||
try {
|
||||
const trace = ErrorStackParser.parse(new Error())
|
||||
.map((stackFrame: StackFrame) => stackFrame.toString())
|
||||
.splice(1); // splice(1) to omit the hijacked log function
|
||||
const payload = args.map((s) =>
|
||||
stringify(s, logOptions.stringifyOptions),
|
||||
);
|
||||
logCount++;
|
||||
if (logCount < logOptions.lengthThreshold) {
|
||||
cb({
|
||||
level,
|
||||
trace,
|
||||
payload,
|
||||
});
|
||||
} else if (logCount === logOptions.lengthThreshold) {
|
||||
// notify the user
|
||||
cb({
|
||||
level: 'warn',
|
||||
trace: [],
|
||||
payload: [
|
||||
stringify('The number of log records reached the threshold.'),
|
||||
],
|
||||
});
|
||||
}
|
||||
} catch (error) {
|
||||
original('rrweb logger error:', error, ...args);
|
||||
}
|
||||
} catch (error) {
|
||||
original('rrweb logger error:', error, ...args);
|
||||
}
|
||||
};
|
||||
});
|
||||
};
|
||||
},
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -201,7 +199,5 @@ export const getRecordConsolePlugin: (
|
||||
) => RecordPlugin = (options) => ({
|
||||
name: PLUGIN_NAME,
|
||||
observer: initLogObserver,
|
||||
options: options
|
||||
? Object.assign({}, defaultLogOptions, options)
|
||||
: defaultLogOptions,
|
||||
options: options,
|
||||
});
|
||||
|
||||
@@ -8,7 +8,7 @@ import type { StringifyOptions } from './index';
|
||||
|
||||
/**
|
||||
* transfer the node path in Event to string
|
||||
* @param node the first node in a node path array
|
||||
* @param node - the first node in a node path array
|
||||
*/
|
||||
function pathToSelector(node: HTMLElement): string | '' {
|
||||
if (!node || !node.outerHTML) {
|
||||
@@ -39,7 +39,7 @@ function pathToSelector(node: HTMLElement): string | '' {
|
||||
}
|
||||
|
||||
if (domSiblings.length > 1) {
|
||||
name += ':eq(' + domSiblings.indexOf(node) + ')';
|
||||
name += `:eq(${domSiblings.indexOf(node)})`;
|
||||
}
|
||||
path = name + (path ? '>' + path : '');
|
||||
node = parent;
|
||||
@@ -51,21 +51,24 @@ function pathToSelector(node: HTMLElement): string | '' {
|
||||
/**
|
||||
* judge is object
|
||||
*/
|
||||
function isObject(obj: any): boolean {
|
||||
function isObject(obj: unknown): boolean {
|
||||
return Object.prototype.toString.call(obj) === '[object Object]';
|
||||
}
|
||||
|
||||
/**
|
||||
* judge the object's depth
|
||||
*/
|
||||
function isObjTooDeep(obj: any, limit: number): boolean {
|
||||
function isObjTooDeep(obj: Record<string, unknown>, limit: number): boolean {
|
||||
if (limit === 0) {
|
||||
return true;
|
||||
}
|
||||
|
||||
const keys = Object.keys(obj);
|
||||
for (const key of keys) {
|
||||
if (isObject(obj[key]) && isObjTooDeep(obj[key], limit - 1)) {
|
||||
if (
|
||||
isObject(obj[key]) &&
|
||||
isObjTooDeep(obj[key] as Record<string, unknown>, limit - 1)
|
||||
) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
@@ -75,10 +78,10 @@ function isObjTooDeep(obj: any, limit: number): boolean {
|
||||
|
||||
/**
|
||||
* stringify any js object
|
||||
* @param obj the object to stringify
|
||||
* @param obj - the object to stringify
|
||||
*/
|
||||
export function stringify(
|
||||
obj: any,
|
||||
obj: unknown,
|
||||
stringifyOptions?: StringifyOptions,
|
||||
): string {
|
||||
const options: StringifyOptions = {
|
||||
@@ -86,63 +89,68 @@ export function stringify(
|
||||
depthOfLimit: 4,
|
||||
};
|
||||
Object.assign(options, stringifyOptions);
|
||||
const stack: any[] = [];
|
||||
const keys: any[] = [];
|
||||
return JSON.stringify(obj, function (key, value) {
|
||||
/**
|
||||
* forked from https://github.com/moll/json-stringify-safe/blob/master/stringify.js
|
||||
* to deCycle the object
|
||||
*/
|
||||
if (stack.length > 0) {
|
||||
const thisPos = stack.indexOf(this);
|
||||
~thisPos ? stack.splice(thisPos + 1) : stack.push(this);
|
||||
~thisPos ? keys.splice(thisPos, Infinity, key) : keys.push(key);
|
||||
if (~stack.indexOf(value)) {
|
||||
if (stack[0] === value) {
|
||||
value = '[Circular ~]';
|
||||
} else {
|
||||
value =
|
||||
'[Circular ~.' +
|
||||
keys.slice(0, stack.indexOf(value)).join('.') +
|
||||
']';
|
||||
const stack: unknown[] = [];
|
||||
const keys: unknown[] = [];
|
||||
return JSON.stringify(
|
||||
obj,
|
||||
function (key, value: string | object | null | undefined) {
|
||||
/**
|
||||
* forked from https://github.com/moll/json-stringify-safe/blob/master/stringify.js
|
||||
* to deCycle the object
|
||||
*/
|
||||
if (stack.length > 0) {
|
||||
const thisPos = stack.indexOf(this);
|
||||
~thisPos ? stack.splice(thisPos + 1) : stack.push(this);
|
||||
~thisPos ? keys.splice(thisPos, Infinity, key) : keys.push(key);
|
||||
if (~stack.indexOf(value)) {
|
||||
if (stack[0] === value) {
|
||||
value = '[Circular ~]';
|
||||
} else {
|
||||
value =
|
||||
'[Circular ~.' +
|
||||
keys.slice(0, stack.indexOf(value)).join('.') +
|
||||
']';
|
||||
}
|
||||
}
|
||||
} else {
|
||||
stack.push(value);
|
||||
}
|
||||
} else {
|
||||
stack.push(value);
|
||||
}
|
||||
/* END of the FORK */
|
||||
/* END of the FORK */
|
||||
|
||||
if (value === null || value === undefined) {
|
||||
return value;
|
||||
}
|
||||
if (shouldIgnore(value)) {
|
||||
return toString(value);
|
||||
}
|
||||
if (value instanceof Event) {
|
||||
const eventResult: any = {};
|
||||
for (const eventKey in value) {
|
||||
const eventValue = (value as any)[eventKey];
|
||||
if (Array.isArray(eventValue)) {
|
||||
eventResult[eventKey] = pathToSelector(
|
||||
eventValue.length ? eventValue[0] : null,
|
||||
);
|
||||
} else {
|
||||
eventResult[eventKey] = eventValue;
|
||||
if (value === null || value === undefined) {
|
||||
return value;
|
||||
}
|
||||
if (shouldIgnore(value as object)) {
|
||||
return toString(value as object);
|
||||
}
|
||||
if (value instanceof Event) {
|
||||
const eventResult: Record<string, unknown> = {};
|
||||
for (const eventKey in value) {
|
||||
const eventValue = ((value as unknown) as Record<string, unknown>)[
|
||||
eventKey
|
||||
];
|
||||
if (Array.isArray(eventValue)) {
|
||||
eventResult[eventKey] = pathToSelector(
|
||||
(eventValue.length ? eventValue[0] : null) as HTMLElement,
|
||||
);
|
||||
} else {
|
||||
eventResult[eventKey] = eventValue;
|
||||
}
|
||||
}
|
||||
return eventResult;
|
||||
} else if (value instanceof Node) {
|
||||
if (value instanceof HTMLElement) {
|
||||
return value ? value.outerHTML : '';
|
||||
}
|
||||
return value.nodeName;
|
||||
} else if (value instanceof Error) {
|
||||
return value.stack
|
||||
? value.stack + '\nEnd of stack for Error object'
|
||||
: value.name + ': ' + value.message;
|
||||
}
|
||||
return eventResult;
|
||||
} else if (value instanceof Node) {
|
||||
if (value instanceof HTMLElement) {
|
||||
return value ? value.outerHTML : '';
|
||||
}
|
||||
return value.nodeName;
|
||||
} else if (value instanceof Error) {
|
||||
return value.stack
|
||||
? value.stack + '\nEnd of stack for Error object'
|
||||
: value.name + ': ' + value.message;
|
||||
}
|
||||
return value;
|
||||
});
|
||||
return value;
|
||||
},
|
||||
);
|
||||
|
||||
/**
|
||||
* whether we should ignore obj's info and call toString() function instead
|
||||
@@ -163,7 +171,10 @@ export function stringify(
|
||||
*
|
||||
* issues: https://github.com/rrweb-io/rrweb/issues/653
|
||||
*/
|
||||
if (isObject(_obj) && isObjTooDeep(_obj, options.depthOfLimit)) {
|
||||
if (
|
||||
isObject(_obj) &&
|
||||
isObjTooDeep(_obj as Record<string, unknown>, options.depthOfLimit)
|
||||
) {
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
@@ -70,7 +70,7 @@ class LogReplayPlugin {
|
||||
]
|
||||
: console.log;
|
||||
logger(
|
||||
...data.payload.map((s) => JSON.parse(s)),
|
||||
...data.payload.map((s) => JSON.parse(s) as object),
|
||||
this.formatMessage(data),
|
||||
);
|
||||
};
|
||||
@@ -84,7 +84,7 @@ class LogReplayPlugin {
|
||||
]
|
||||
: console[level];
|
||||
logger(
|
||||
...data.payload.map((s) => JSON.parse(s)),
|
||||
...data.payload.map((s) => JSON.parse(s) as object),
|
||||
this.formatMessage(data),
|
||||
);
|
||||
};
|
||||
@@ -95,7 +95,7 @@ class LogReplayPlugin {
|
||||
|
||||
/**
|
||||
* format the trace data to a string
|
||||
* @param data the log data
|
||||
* @param data - the log data
|
||||
*/
|
||||
private formatMessage(data: LogData): string {
|
||||
if (data.trace.length === 0) {
|
||||
|
||||
@@ -129,7 +129,9 @@ function initMoveObserver({
|
||||
mirror,
|
||||
}: observerParam): listenerHandler {
|
||||
if (sampling.mousemove === false) {
|
||||
return () => {};
|
||||
return () => {
|
||||
//
|
||||
};
|
||||
}
|
||||
|
||||
const threshold =
|
||||
@@ -209,7 +211,9 @@ function initMouseInteractionObserver({
|
||||
sampling,
|
||||
}: observerParam): listenerHandler {
|
||||
if (sampling.mouseInteraction === false) {
|
||||
return () => {};
|
||||
return () => {
|
||||
//
|
||||
};
|
||||
}
|
||||
const disableMap: Record<string, boolean | undefined> =
|
||||
sampling.mouseInteraction === true ||
|
||||
@@ -438,7 +442,7 @@ function initInputObserver({
|
||||
hookSetter<HTMLElement>(p[0], p[1], {
|
||||
set() {
|
||||
// mock to a normal event
|
||||
eventHandler({ target: this } as Event);
|
||||
eventHandler({ target: this as EventTarget } as Event);
|
||||
},
|
||||
}),
|
||||
),
|
||||
@@ -492,31 +496,37 @@ function initStyleSheetObserver(
|
||||
{ styleSheetRuleCb, mirror }: observerParam,
|
||||
{ win }: { win: IWindow },
|
||||
): listenerHandler {
|
||||
// eslint-disable-next-line @typescript-eslint/unbound-method
|
||||
const insertRule = win.CSSStyleSheet.prototype.insertRule;
|
||||
win.CSSStyleSheet.prototype.insertRule = function (
|
||||
this: CSSStyleSheet,
|
||||
rule: string,
|
||||
index?: number,
|
||||
) {
|
||||
const id = mirror.getId(this.ownerNode);
|
||||
const id = mirror.getId(this.ownerNode as Node);
|
||||
if (id !== -1) {
|
||||
styleSheetRuleCb({
|
||||
id,
|
||||
adds: [{ rule, index }],
|
||||
});
|
||||
}
|
||||
return insertRule.apply(this, arguments);
|
||||
return insertRule.apply(this, [rule, index]);
|
||||
};
|
||||
|
||||
// eslint-disable-next-line @typescript-eslint/unbound-method
|
||||
const deleteRule = win.CSSStyleSheet.prototype.deleteRule;
|
||||
win.CSSStyleSheet.prototype.deleteRule = function (index: number) {
|
||||
const id = mirror.getId(this.ownerNode);
|
||||
win.CSSStyleSheet.prototype.deleteRule = function (
|
||||
this: CSSStyleSheet,
|
||||
index: number,
|
||||
) {
|
||||
const id = mirror.getId(this.ownerNode as Node);
|
||||
if (id !== -1) {
|
||||
styleSheetRuleCb({
|
||||
id,
|
||||
removes: [{ index }],
|
||||
});
|
||||
}
|
||||
return deleteRule.apply(this, arguments);
|
||||
return deleteRule.apply(this, [index]);
|
||||
};
|
||||
|
||||
const supportedNestedCSSRuleTypes: {
|
||||
@@ -549,12 +559,15 @@ function initStyleSheetObserver(
|
||||
|
||||
Object.entries(supportedNestedCSSRuleTypes).forEach(([typeKey, type]) => {
|
||||
unmodifiedFunctions[typeKey] = {
|
||||
// eslint-disable-next-line @typescript-eslint/unbound-method
|
||||
insertRule: type.prototype.insertRule,
|
||||
// eslint-disable-next-line @typescript-eslint/unbound-method
|
||||
deleteRule: type.prototype.deleteRule,
|
||||
};
|
||||
|
||||
type.prototype.insertRule = function (rule: string, index?: number) {
|
||||
const id = mirror.getId(this.parentStyleSheet.ownerNode);
|
||||
// eslint-disable-next-line @typescript-eslint/no-unsafe-member-access
|
||||
const id = mirror.getId(this.parentStyleSheet.ownerNode as Node);
|
||||
if (id !== -1) {
|
||||
styleSheetRuleCb({
|
||||
id,
|
||||
@@ -562,25 +575,28 @@ function initStyleSheetObserver(
|
||||
{
|
||||
rule,
|
||||
index: [
|
||||
...getNestedCSSRulePositions(this),
|
||||
...getNestedCSSRulePositions(this as CSSRule),
|
||||
index || 0, // defaults to 0
|
||||
],
|
||||
},
|
||||
],
|
||||
});
|
||||
}
|
||||
return unmodifiedFunctions[typeKey].insertRule.apply(this, arguments);
|
||||
return unmodifiedFunctions[typeKey].insertRule.apply(this, [rule, index]);
|
||||
};
|
||||
|
||||
type.prototype.deleteRule = function (index: number) {
|
||||
const id = mirror.getId(this.parentStyleSheet.ownerNode);
|
||||
// eslint-disable-next-line @typescript-eslint/no-unsafe-member-access
|
||||
const id = mirror.getId(this.parentStyleSheet.ownerNode as Node);
|
||||
if (id !== -1) {
|
||||
styleSheetRuleCb({
|
||||
id,
|
||||
removes: [{ index: [...getNestedCSSRulePositions(this), index] }],
|
||||
removes: [
|
||||
{ index: [...getNestedCSSRulePositions(this as CSSRule), index] },
|
||||
],
|
||||
});
|
||||
}
|
||||
return unmodifiedFunctions[typeKey].deleteRule.apply(this, arguments);
|
||||
return unmodifiedFunctions[typeKey].deleteRule.apply(this, [index]);
|
||||
};
|
||||
});
|
||||
|
||||
@@ -598,6 +614,7 @@ function initStyleDeclarationObserver(
|
||||
{ styleDeclarationCb, mirror }: observerParam,
|
||||
{ win }: { win: IWindow },
|
||||
): listenerHandler {
|
||||
// eslint-disable-next-line @typescript-eslint/unbound-method
|
||||
const setProperty = win.CSSStyleDeclaration.prototype.setProperty;
|
||||
win.CSSStyleDeclaration.prototype.setProperty = function (
|
||||
this: CSSStyleDeclaration,
|
||||
@@ -617,9 +634,10 @@ function initStyleDeclarationObserver(
|
||||
index: getNestedCSSRulePositions(this.parentRule!),
|
||||
});
|
||||
}
|
||||
return setProperty.apply(this, arguments);
|
||||
return setProperty.apply(this, [property, value, priority]);
|
||||
};
|
||||
|
||||
// eslint-disable-next-line @typescript-eslint/unbound-method
|
||||
const removeProperty = win.CSSStyleDeclaration.prototype.removeProperty;
|
||||
win.CSSStyleDeclaration.prototype.removeProperty = function (
|
||||
this: CSSStyleDeclaration,
|
||||
@@ -635,7 +653,7 @@ function initStyleDeclarationObserver(
|
||||
index: getNestedCSSRulePositions(this.parentRule!),
|
||||
});
|
||||
}
|
||||
return removeProperty.apply(this, arguments);
|
||||
return removeProperty.apply(this, [property]);
|
||||
};
|
||||
|
||||
return () => {
|
||||
@@ -679,7 +697,9 @@ function initMediaInteractionObserver({
|
||||
function initFontObserver({ fontCb, doc }: observerParam): listenerHandler {
|
||||
const win = doc.defaultView as IWindow;
|
||||
if (!win) {
|
||||
return () => {};
|
||||
return () => {
|
||||
//
|
||||
};
|
||||
}
|
||||
|
||||
const handlers: listenerHandler[] = [];
|
||||
@@ -689,7 +709,7 @@ function initFontObserver({ fontCb, doc }: observerParam): listenerHandler {
|
||||
const originalFontFace = win.FontFace;
|
||||
win.FontFace = (function FontFace(
|
||||
family: string,
|
||||
source: string | ArrayBufferView,
|
||||
source: string | ArrayBufferLike,
|
||||
descriptors?: FontFaceDescriptors,
|
||||
) {
|
||||
const fontFace = new originalFontFace(family, source, descriptors);
|
||||
@@ -701,23 +721,27 @@ function initFontObserver({ fontCb, doc }: observerParam): listenerHandler {
|
||||
typeof source === 'string'
|
||||
? source
|
||||
: // tslint:disable-next-line: no-any
|
||||
JSON.stringify(Array.from(new Uint8Array(source as any))),
|
||||
JSON.stringify(Array.from(new Uint8Array(source))),
|
||||
});
|
||||
return fontFace;
|
||||
} as unknown) as typeof FontFace;
|
||||
|
||||
const restoreHandler = patch(doc.fonts, 'add', function (original) {
|
||||
return function (this: FontFaceSet, fontFace: FontFace) {
|
||||
setTimeout(() => {
|
||||
const p = fontMap.get(fontFace);
|
||||
if (p) {
|
||||
fontCb(p);
|
||||
fontMap.delete(fontFace);
|
||||
}
|
||||
}, 0);
|
||||
return original.apply(this, [fontFace]);
|
||||
};
|
||||
});
|
||||
const restoreHandler = patch(
|
||||
doc.fonts,
|
||||
'add',
|
||||
function (original: (font: FontFace) => void) {
|
||||
return function (this: FontFaceSet, fontFace: FontFace) {
|
||||
setTimeout(() => {
|
||||
const p = fontMap.get(fontFace);
|
||||
if (p) {
|
||||
fontCb(p);
|
||||
fontMap.delete(fontFace);
|
||||
}
|
||||
}, 0);
|
||||
return original.apply(this, [fontFace]);
|
||||
};
|
||||
},
|
||||
);
|
||||
|
||||
handlers.push(() => {
|
||||
win.FontFace = originalFontFace;
|
||||
@@ -817,7 +841,9 @@ export function initObservers(
|
||||
): listenerHandler {
|
||||
const currentWindow = o.doc.defaultView; // basically document.window
|
||||
if (!currentWindow) {
|
||||
return () => {};
|
||||
return () => {
|
||||
//
|
||||
};
|
||||
}
|
||||
|
||||
mergeHooks(o, hooks);
|
||||
@@ -833,7 +859,11 @@ export function initObservers(
|
||||
const styleDeclarationObserver = initStyleDeclarationObserver(o, {
|
||||
win: currentWindow,
|
||||
});
|
||||
const fontObserver = o.collectFonts ? initFontObserver(o) : () => {};
|
||||
const fontObserver = o.collectFonts
|
||||
? initFontObserver(o)
|
||||
: () => {
|
||||
//
|
||||
};
|
||||
// plugins
|
||||
const pluginHandlers: listenerHandler[] = [];
|
||||
for (const plugin of o.plugins) {
|
||||
|
||||
@@ -31,7 +31,12 @@ export default function initCanvas2DMutationObserver(
|
||||
const restoreHandler = patch(
|
||||
win.CanvasRenderingContext2D.prototype,
|
||||
prop,
|
||||
function (original) {
|
||||
function (
|
||||
original: (
|
||||
this: CanvasRenderingContext2D,
|
||||
...args: unknown[]
|
||||
) => void,
|
||||
) {
|
||||
return function (
|
||||
this: CanvasRenderingContext2D,
|
||||
...args: Array<unknown>
|
||||
@@ -59,6 +64,7 @@ export default function initCanvas2DMutationObserver(
|
||||
prop,
|
||||
{
|
||||
set(v) {
|
||||
// eslint-disable-next-line @typescript-eslint/no-unsafe-argument, @typescript-eslint/no-unsafe-member-access
|
||||
cb(this.canvas, {
|
||||
type: CanvasContext['2D'],
|
||||
property: prop,
|
||||
|
||||
@@ -72,10 +72,10 @@ export class CanvasManager {
|
||||
this.initCanvasFPSObserver(sampling, win, blockClass);
|
||||
}
|
||||
|
||||
private processMutation: canvasManagerMutationCallback = function (
|
||||
private processMutation: canvasManagerMutationCallback = (
|
||||
target,
|
||||
mutation,
|
||||
) {
|
||||
) => {
|
||||
const newFrame =
|
||||
this.rafStamps.invokeId &&
|
||||
this.rafStamps.latestId !== this.rafStamps.invokeId;
|
||||
@@ -148,7 +148,8 @@ export class CanvasManager {
|
||||
lastSnapshotTime = timestamp;
|
||||
|
||||
win.document
|
||||
.querySelectorAll(`canvas:not(.${blockClass} *)`)
|
||||
.querySelectorAll(`canvas:not(.${blockClass as string} *)`)
|
||||
// eslint-disable-next-line @typescript-eslint/no-misused-promises
|
||||
.forEach(async (canvas: HTMLCanvasElement) => {
|
||||
const id = this.mirror.getId(canvas);
|
||||
if (snapshotInProgressMap.get(id)) return;
|
||||
|
||||
@@ -11,7 +11,13 @@ export default function initCanvasContextObserver(
|
||||
const restoreHandler = patch(
|
||||
win.HTMLCanvasElement.prototype,
|
||||
'getContext',
|
||||
function (original) {
|
||||
function (
|
||||
original: (
|
||||
this: ICanvas,
|
||||
contextType: string,
|
||||
...args: Array<unknown>
|
||||
) => void,
|
||||
) {
|
||||
return function (
|
||||
this: ICanvas,
|
||||
contextType: string,
|
||||
|
||||
@@ -2,7 +2,7 @@ import { encode } from 'base64-arraybuffer';
|
||||
import type { IWindow, CanvasArg } from '../../../types';
|
||||
|
||||
// TODO: unify with `replay/webgl.ts`
|
||||
type CanvasVarMap = Map<string, any[]>;
|
||||
type CanvasVarMap = Map<string, unknown[]>;
|
||||
const canvasVarMap: Map<RenderingContext, CanvasVarMap> = new Map();
|
||||
export function variableListFor(ctx: RenderingContext, ctor: string) {
|
||||
let contextMap = canvasVarMap.get(ctx);
|
||||
@@ -13,11 +13,11 @@ export function variableListFor(ctx: RenderingContext, ctor: string) {
|
||||
if (!contextMap.has(ctor)) {
|
||||
contextMap.set(ctor, []);
|
||||
}
|
||||
return contextMap.get(ctor) as any[];
|
||||
return contextMap.get(ctor) as unknown[];
|
||||
}
|
||||
|
||||
export const saveWebGLVar = (
|
||||
value: any,
|
||||
value: unknown,
|
||||
win: IWindow,
|
||||
ctx: RenderingContext,
|
||||
): number | void => {
|
||||
@@ -40,7 +40,7 @@ export const saveWebGLVar = (
|
||||
|
||||
// from webgl-recorder: https://github.com/evanw/webgl-recorder/blob/bef0e65596e981ee382126587e2dcbe0fc7748e2/webgl-recorder.js#L50-L77
|
||||
export function serializeArg(
|
||||
value: any,
|
||||
value: unknown,
|
||||
win: IWindow,
|
||||
ctx: RenderingContext,
|
||||
): CanvasArg {
|
||||
@@ -125,11 +125,11 @@ export function serializeArg(
|
||||
};
|
||||
}
|
||||
|
||||
return value;
|
||||
return value as CanvasArg;
|
||||
}
|
||||
|
||||
export const serializeArgs = (
|
||||
args: Array<any>,
|
||||
args: Array<unknown>,
|
||||
win: IWindow,
|
||||
ctx: RenderingContext,
|
||||
) => {
|
||||
@@ -137,7 +137,7 @@ export const serializeArgs = (
|
||||
};
|
||||
|
||||
export const isInstanceOfWebGLObject = (
|
||||
value: any,
|
||||
value: unknown,
|
||||
win: IWindow,
|
||||
): value is
|
||||
| WebGLActiveInfo
|
||||
|
||||
@@ -27,30 +27,36 @@ function patchGLPrototype(
|
||||
if (typeof prototype[prop as keyof typeof prototype] !== 'function') {
|
||||
continue;
|
||||
}
|
||||
const restoreHandler = patch(prototype, prop, function (original) {
|
||||
return function (this: typeof prototype, ...args: Array<unknown>) {
|
||||
const result = original.apply(this, args);
|
||||
saveWebGLVar(result, win, prototype);
|
||||
if (!isBlocked(this.canvas, blockClass, true)) {
|
||||
const restoreHandler = patch(
|
||||
prototype,
|
||||
prop,
|
||||
function (
|
||||
original: (this: typeof prototype, ...args: Array<unknown>) => void,
|
||||
) {
|
||||
return function (this: typeof prototype, ...args: Array<unknown>) {
|
||||
const result = original.apply(this, args);
|
||||
saveWebGLVar(result, win, prototype);
|
||||
if (!isBlocked(this.canvas, blockClass, true)) {
|
||||
const recordArgs = serializeArgs([...args], win, prototype);
|
||||
const mutation: canvasMutationWithType = {
|
||||
type,
|
||||
property: prop,
|
||||
args: recordArgs,
|
||||
};
|
||||
// TODO: this could potentially also be an OffscreenCanvas as well as HTMLCanvasElement
|
||||
cb(this.canvas, mutation);
|
||||
}
|
||||
|
||||
const recordArgs = serializeArgs([...args], win, prototype);
|
||||
const mutation: canvasMutationWithType = {
|
||||
type,
|
||||
property: prop,
|
||||
args: recordArgs,
|
||||
};
|
||||
// TODO: this could potentially also be an OffscreenCanvas as well as HTMLCanvasElement
|
||||
cb(this.canvas, mutation);
|
||||
}
|
||||
|
||||
return result;
|
||||
};
|
||||
});
|
||||
return result;
|
||||
};
|
||||
},
|
||||
);
|
||||
handlers.push(restoreHandler);
|
||||
} catch {
|
||||
const hookHandler = hookSetter<typeof prototype>(prototype, prop, {
|
||||
set(v) {
|
||||
// TODO: this could potentially also be an OffscreenCanvas as well as HTMLCanvasElement
|
||||
// eslint-disable-next-line @typescript-eslint/no-unsafe-member-access
|
||||
cb(this.canvas as HTMLCanvasElement, {
|
||||
type,
|
||||
property: prop,
|
||||
|
||||
@@ -34,16 +34,21 @@ export class ShadowDomManager {
|
||||
this.mirror = options.mirror;
|
||||
|
||||
// Patch 'attachShadow' to observe newly added shadow doms.
|
||||
// eslint-disable-next-line @typescript-eslint/no-this-alias
|
||||
const manager = this;
|
||||
this.restorePatches.push(
|
||||
patch(HTMLElement.prototype, 'attachShadow', function (original) {
|
||||
return function () {
|
||||
const shadowRoot = original.apply(this, arguments);
|
||||
if (this.shadowRoot)
|
||||
manager.addShadowRoot(this.shadowRoot, this.ownerDocument);
|
||||
return shadowRoot;
|
||||
};
|
||||
}),
|
||||
patch(
|
||||
HTMLElement.prototype,
|
||||
'attachShadow',
|
||||
function (original: (init: ShadowRootInit) => ShadowRoot) {
|
||||
return function (this: HTMLElement, option: ShadowRootInit) {
|
||||
const shadowRoot = original.call(this, option);
|
||||
if (this.shadowRoot)
|
||||
manager.addShadowRoot(this.shadowRoot, this.ownerDocument);
|
||||
return shadowRoot;
|
||||
};
|
||||
},
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
@@ -73,6 +78,7 @@ export class ShadowDomManager {
|
||||
*/
|
||||
public observeAttachShadow(iframeElement: HTMLIFrameElement) {
|
||||
if (iframeElement.contentWindow) {
|
||||
// eslint-disable-next-line @typescript-eslint/no-this-alias
|
||||
const manager = this;
|
||||
this.restorePatches.push(
|
||||
patch(
|
||||
@@ -80,9 +86,9 @@ export class ShadowDomManager {
|
||||
HTMLElement: { prototype: HTMLElement };
|
||||
}).HTMLElement.prototype,
|
||||
'attachShadow',
|
||||
function (original) {
|
||||
return function () {
|
||||
const shadowRoot = original.apply(this, arguments);
|
||||
function (original: (init: ShadowRootInit) => ShadowRoot) {
|
||||
return function (this: HTMLElement, option: ShadowRootInit) {
|
||||
const shadowRoot = original.call(this, option);
|
||||
if (this.shadowRoot)
|
||||
manager.addShadowRoot(
|
||||
this.shadowRoot,
|
||||
|
||||
@@ -40,6 +40,7 @@ async function getTransparentBlobFor(
|
||||
// `as any` because: https://github.com/Microsoft/TypeScript/issues/20595
|
||||
const worker: ImageBitmapDataURLResponseWorker = self;
|
||||
|
||||
// eslint-disable-next-line @typescript-eslint/no-misused-promises
|
||||
worker.onmessage = async function (e) {
|
||||
if (!('OffscreenCanvas' in globalThis))
|
||||
return worker.postMessage({ id: e.data.id });
|
||||
|
||||
@@ -20,13 +20,13 @@ export default async function canvasMutation({
|
||||
|
||||
if (mutation.setter) {
|
||||
// skip some read-only type checks
|
||||
// tslint:disable-next-line:no-any
|
||||
(ctx as any)[mutation.property] = mutation.args[0];
|
||||
((ctx as unknown) as Record<string, unknown>)[mutation.property] =
|
||||
mutation.args[0];
|
||||
return;
|
||||
}
|
||||
const original = ctx[
|
||||
mutation.property as Exclude<keyof typeof ctx, 'canvas'>
|
||||
] as Function;
|
||||
] as (ctx: CanvasRenderingContext2D, args: unknown[]) => void;
|
||||
|
||||
/**
|
||||
* We have serialized the image source into base64 string during recording,
|
||||
@@ -37,7 +37,7 @@ export default async function canvasMutation({
|
||||
mutation.property === 'drawImage' &&
|
||||
typeof mutation.args[0] === 'string'
|
||||
) {
|
||||
const image = imageMap.get(event);
|
||||
imageMap.get(event);
|
||||
original.apply(ctx, mutation.args);
|
||||
} else {
|
||||
const args = await Promise.all(
|
||||
|
||||
@@ -23,6 +23,7 @@ export function variableListFor(
|
||||
if (!contextMap.has(ctor)) {
|
||||
contextMap.set(ctor, []);
|
||||
}
|
||||
// eslint-disable-next-line @typescript-eslint/no-unsafe-return
|
||||
return contextMap.get(ctor) as any[];
|
||||
}
|
||||
|
||||
@@ -45,16 +46,21 @@ export function deserializeArg(
|
||||
if (arg && typeof arg === 'object' && 'rr_type' in arg) {
|
||||
if (preload) preload.isUnchanged = false;
|
||||
if (arg.rr_type === 'ImageBitmap' && 'args' in arg) {
|
||||
// eslint-disable-next-line @typescript-eslint/no-unsafe-assignment
|
||||
const args = await deserializeArg(imageMap, ctx, preload)(arg.args);
|
||||
// eslint-disable-next-line prefer-spread
|
||||
return await createImageBitmap.apply(null, args);
|
||||
} else if ('index' in arg) {
|
||||
if (preload || ctx === null) return arg; // we are preloading, ctx is unknown
|
||||
const { rr_type: name, index } = arg;
|
||||
// eslint-disable-next-line @typescript-eslint/no-unsafe-return
|
||||
return variableListFor(ctx, name)[index];
|
||||
} else if ('args' in arg) {
|
||||
const { rr_type: name, args } = arg;
|
||||
// eslint-disable-next-line @typescript-eslint/no-unsafe-assignment
|
||||
const ctor = window[name as keyof Window];
|
||||
|
||||
// eslint-disable-next-line @typescript-eslint/no-unsafe-return, @typescript-eslint/no-unsafe-call
|
||||
return new ctor(
|
||||
...(await Promise.all(
|
||||
args.map(deserializeArg(imageMap, ctx, preload)),
|
||||
@@ -85,6 +91,7 @@ export function deserializeArg(
|
||||
const result = await Promise.all(
|
||||
arg.map(deserializeArg(imageMap, ctx, preload)),
|
||||
);
|
||||
// eslint-disable-next-line @typescript-eslint/no-unsafe-return
|
||||
return result;
|
||||
}
|
||||
return arg;
|
||||
|
||||
@@ -11,8 +11,9 @@ function getContext(
|
||||
// you might have to do `ctx.flush()` before every webgl canvas event
|
||||
try {
|
||||
if (type === CanvasContext.WebGL) {
|
||||
return (target.getContext('webgl')! ||
|
||||
target.getContext('experimental-webgl'));
|
||||
return (
|
||||
target.getContext('webgl')! || target.getContext('experimental-webgl')
|
||||
);
|
||||
}
|
||||
return target.getContext('webgl2')!;
|
||||
} catch (e) {
|
||||
@@ -37,11 +38,15 @@ function saveToWebGLVarMap(
|
||||
ctx: WebGLRenderingContext | WebGL2RenderingContext,
|
||||
result: any,
|
||||
) {
|
||||
// eslint-disable-next-line @typescript-eslint/no-unsafe-member-access
|
||||
if (!result?.constructor) return; // probably null or undefined
|
||||
|
||||
// eslint-disable-next-line @typescript-eslint/no-unsafe-assignment, @typescript-eslint/no-unsafe-member-access
|
||||
const { name } = result.constructor;
|
||||
// eslint-disable-next-line @typescript-eslint/no-unsafe-argument
|
||||
if (!WebGLVariableConstructorsNames.includes(name)) return; // not a WebGL variable
|
||||
|
||||
// eslint-disable-next-line @typescript-eslint/no-unsafe-argument
|
||||
const variables = variableListFor(ctx, name);
|
||||
if (!variables.includes(result)) variables.push(result);
|
||||
}
|
||||
@@ -69,13 +74,16 @@ export default async function webglMutation({
|
||||
|
||||
if (mutation.setter) {
|
||||
// skip some read-only type checks
|
||||
// tslint:disable-next-line:no-any
|
||||
// eslint-disable-next-line @typescript-eslint/no-unsafe-member-access
|
||||
(ctx as any)[mutation.property] = mutation.args[0];
|
||||
return;
|
||||
}
|
||||
const original = ctx[
|
||||
mutation.property as Exclude<keyof typeof ctx, 'canvas'>
|
||||
] as Function;
|
||||
] as (
|
||||
ctx: WebGLRenderingContext | WebGL2RenderingContext,
|
||||
args: unknown[],
|
||||
) => void;
|
||||
|
||||
const args = await Promise.all(
|
||||
mutation.args.map(deserializeArg(imageMap, ctx)),
|
||||
@@ -87,16 +95,21 @@ export default async function webglMutation({
|
||||
const debugMode = false;
|
||||
if (debugMode) {
|
||||
if (mutation.property === 'compileShader') {
|
||||
// eslint-disable-next-line @typescript-eslint/no-unsafe-argument
|
||||
if (!ctx.getShaderParameter(args[0], ctx.COMPILE_STATUS))
|
||||
console.warn(
|
||||
'something went wrong in replay',
|
||||
// eslint-disable-next-line @typescript-eslint/no-unsafe-argument
|
||||
ctx.getShaderInfoLog(args[0]),
|
||||
);
|
||||
} else if (mutation.property === 'linkProgram') {
|
||||
// eslint-disable-next-line @typescript-eslint/no-unsafe-argument
|
||||
ctx.validateProgram(args[0]);
|
||||
// eslint-disable-next-line @typescript-eslint/no-unsafe-argument
|
||||
if (!ctx.getProgramParameter(args[0], ctx.LINK_STATUS))
|
||||
console.warn(
|
||||
'something went wrong in replay',
|
||||
// eslint-disable-next-line @typescript-eslint/no-unsafe-argument
|
||||
ctx.getProgramInfoLog(args[0]),
|
||||
);
|
||||
}
|
||||
@@ -107,6 +120,7 @@ export default async function webglMutation({
|
||||
webglError,
|
||||
'on command:',
|
||||
mutation.property,
|
||||
// eslint-disable-next-line @typescript-eslint/no-unsafe-argument
|
||||
...args,
|
||||
);
|
||||
}
|
||||
|
||||
@@ -42,7 +42,6 @@ import {
|
||||
viewportResizeDimension,
|
||||
missingNodeMap,
|
||||
addedNodeMutation,
|
||||
missingNode,
|
||||
incrementalSnapshotEvent,
|
||||
incrementalData,
|
||||
ReplayerEvents,
|
||||
@@ -54,7 +53,6 @@ import {
|
||||
scrollData,
|
||||
inputData,
|
||||
canvasMutationData,
|
||||
styleAttributeValue,
|
||||
styleValueWithPriority,
|
||||
mouseMovePos,
|
||||
IWindow,
|
||||
@@ -83,8 +81,7 @@ const SKIP_TIME_THRESHOLD = 10 * 1000;
|
||||
const SKIP_TIME_INTERVAL = 5 * 1000;
|
||||
|
||||
// https://github.com/rollup/rollup/issues/1267#issuecomment-296395734
|
||||
// tslint:disable-next-line
|
||||
const mitt = (mittProxy as any).default || mittProxy;
|
||||
const mitt = mittProxy.default || mittProxy;
|
||||
|
||||
const REPLAY_CONSOLE_PREFIX = '[replayer]';
|
||||
|
||||
@@ -188,7 +185,7 @@ export class Replayer {
|
||||
canvasMutationData: canvasMutationData,
|
||||
target: HTMLCanvasElement,
|
||||
) => {
|
||||
canvasMutation({
|
||||
void canvasMutation({
|
||||
event: canvasEvent,
|
||||
mutation: canvasMutationData,
|
||||
target,
|
||||
@@ -340,8 +337,10 @@ export class Replayer {
|
||||
|
||||
public setConfig(config: Partial<playerConfig>) {
|
||||
Object.keys(config).forEach((key) => {
|
||||
// @ts-ignore
|
||||
this.config[key] = config[key];
|
||||
const newConfigValue = config[key as keyof playerConfig];
|
||||
(this.config as Record<keyof playerConfig, typeof newConfigValue>)[
|
||||
key as keyof playerConfig
|
||||
] = config[key as keyof playerConfig];
|
||||
});
|
||||
if (!this.config.skipInactive) {
|
||||
this.backToNormal();
|
||||
@@ -404,7 +403,7 @@ export class Replayer {
|
||||
* So the implementation of play at any time offset will always iterate
|
||||
* all of the events, cast event before the offset synchronously
|
||||
* and cast event after the offset asynchronously with timer.
|
||||
* @param timeOffset number
|
||||
* @param timeOffset - number
|
||||
*/
|
||||
public play(timeOffset = 0) {
|
||||
if (this.service.state.matches('paused')) {
|
||||
@@ -452,7 +451,7 @@ export class Replayer {
|
||||
if (indicatesTouchDevice(event)) {
|
||||
this.mouse.classList.add('touch-device');
|
||||
}
|
||||
Promise.resolve().then(() =>
|
||||
void Promise.resolve().then(() =>
|
||||
this.service.send({ type: 'ADD_EVENT', payload: { event } }),
|
||||
);
|
||||
}
|
||||
@@ -511,7 +510,7 @@ export class Replayer {
|
||||
}
|
||||
}
|
||||
|
||||
private handleResize(dimension: viewportResizeDimension) {
|
||||
private handleResize = (dimension: viewportResizeDimension) => {
|
||||
this.iframe.style.display = 'inherit';
|
||||
for (const el of [this.mouseTail, this.iframe]) {
|
||||
if (!el) {
|
||||
@@ -520,9 +519,9 @@ export class Replayer {
|
||||
el.setAttribute('width', String(dimension.width));
|
||||
el.setAttribute('height', String(dimension.height));
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
private applyEventsSynchronously(events: Array<eventWithTime>) {
|
||||
private applyEventsSynchronously = (events: Array<eventWithTime>) => {
|
||||
for (const event of events) {
|
||||
switch (event.type) {
|
||||
case EventType.DomContentLoaded:
|
||||
@@ -546,9 +545,9 @@ export class Replayer {
|
||||
this.mouse.classList.remove('touch-active');
|
||||
}
|
||||
this.touchActive = null;
|
||||
}
|
||||
};
|
||||
|
||||
private getCastFn(event: eventWithTime, isSync = false) {
|
||||
private getCastFn = (event: eventWithTime, isSync = false) => {
|
||||
let castFn: undefined | (() => void);
|
||||
switch (event.type) {
|
||||
case EventType.DomContentLoaded:
|
||||
@@ -671,7 +670,7 @@ export class Replayer {
|
||||
this.emitter.emit(ReplayerEvents.EventCast, event);
|
||||
};
|
||||
return wrappedCastFn;
|
||||
}
|
||||
};
|
||||
|
||||
private rebuildFullSnapshot(
|
||||
event: fullSnapshotEvent & { timestamp: number },
|
||||
@@ -714,7 +713,7 @@ export class Replayer {
|
||||
this.waitForStylesheetLoad();
|
||||
}
|
||||
if (this.config.UNSAFE_replayCanvas) {
|
||||
this.preloadAllImages();
|
||||
void this.preloadAllImages();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -870,37 +869,6 @@ export class Replayer {
|
||||
}
|
||||
}
|
||||
|
||||
private hasImageArg(args: any[]): boolean {
|
||||
for (const arg of args) {
|
||||
if (!arg || typeof arg !== 'object') {
|
||||
// do nothing
|
||||
} else if ('rr_type' in arg && 'args' in arg) {
|
||||
if (this.hasImageArg(arg.args)) return true;
|
||||
} else if ('rr_type' in arg && arg.rr_type === 'HTMLImageElement') {
|
||||
return true; // has image!
|
||||
} else if (arg instanceof Array) {
|
||||
if (this.hasImageArg(arg)) return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
private getImageArgs(args: any[]): string[] {
|
||||
const images: string[] = [];
|
||||
for (const arg of args) {
|
||||
if (!arg || typeof arg !== 'object') {
|
||||
// do nothing
|
||||
} else if ('rr_type' in arg && 'args' in arg) {
|
||||
images.push(...this.getImageArgs(arg.args));
|
||||
} else if ('rr_type' in arg && arg.rr_type === 'HTMLImageElement') {
|
||||
images.push(arg.src);
|
||||
} else if (arg instanceof Array) {
|
||||
images.push(...this.getImageArgs(arg));
|
||||
}
|
||||
}
|
||||
return images;
|
||||
}
|
||||
|
||||
/**
|
||||
* pause when there are some canvas drawImage args need to be loaded
|
||||
*/
|
||||
@@ -940,7 +908,7 @@ export class Replayer {
|
||||
const ctx = canvas.getContext('2d');
|
||||
const imgd = ctx?.createImageData(canvas.width, canvas.height);
|
||||
let d = imgd?.data;
|
||||
d = JSON.parse(data.args[0]);
|
||||
d = JSON.parse(data.args[0]) as Uint8ClampedArray;
|
||||
ctx?.putImageData(imgd!, 0, 0);
|
||||
}
|
||||
}
|
||||
@@ -983,6 +951,7 @@ export class Replayer {
|
||||
try {
|
||||
this.applyMutation(d, isSync);
|
||||
} catch (error) {
|
||||
// eslint-disable-next-line @typescript-eslint/no-unsafe-member-access, @typescript-eslint/restrict-template-expressions
|
||||
this.warn(`Exception in mutation ${error.message || error}`, d);
|
||||
}
|
||||
break;
|
||||
@@ -1013,7 +982,9 @@ export class Replayer {
|
||||
});
|
||||
// add a dummy action to keep timer alive
|
||||
this.timer.addAction({
|
||||
doAction() {},
|
||||
doAction() {
|
||||
//
|
||||
},
|
||||
delay: e.delay! - d.positions[0]?.timeOffset,
|
||||
});
|
||||
}
|
||||
@@ -1174,11 +1145,12 @@ export class Replayer {
|
||||
// i.e. media will evntualy start to play when data is loaded
|
||||
// 'canplay' event fires even when currentTime attribute changes which may lead to
|
||||
// unexpeted behavior
|
||||
mediaEl.play();
|
||||
void mediaEl.play();
|
||||
}
|
||||
} catch (error) {
|
||||
if (this.config.showWarning) {
|
||||
console.warn(
|
||||
// eslint-disable-next-line @typescript-eslint/no-unsafe-member-access, @typescript-eslint/restrict-template-expressions
|
||||
`Failed to replay media interactions: ${error.message || error}`,
|
||||
);
|
||||
}
|
||||
@@ -1322,7 +1294,7 @@ export class Replayer {
|
||||
if (!target) {
|
||||
return this.debugNodeNotFound(d, d.id);
|
||||
}
|
||||
canvasMutation({
|
||||
void canvasMutation({
|
||||
event: e,
|
||||
mutation: d,
|
||||
target: target as HTMLCanvasElement,
|
||||
@@ -1337,7 +1309,9 @@ export class Replayer {
|
||||
try {
|
||||
const fontFace = new FontFace(
|
||||
d.family,
|
||||
d.buffer ? new Uint8Array(JSON.parse(d.fontSource)) : d.fontSource,
|
||||
d.buffer
|
||||
? new Uint8Array(JSON.parse(d.fontSource) as Iterable<number>)
|
||||
: d.fontSource,
|
||||
d.descriptors,
|
||||
);
|
||||
this.iframe.contentDocument?.fonts.add(fontFace);
|
||||
@@ -1711,8 +1685,8 @@ export class Replayer {
|
||||
/**
|
||||
* Apply the scroll data on real elements.
|
||||
* If the replayer is in sync mode, smooth scroll behavior should be disabled.
|
||||
* @param d the scroll data
|
||||
* @param isSync whether the replayer is in sync mode(fast-forward)
|
||||
* @param d - the scroll data
|
||||
* @param isSync - whether the replayer is in sync mode(fast-forward)
|
||||
*/
|
||||
private applyScroll(d: scrollData, isSync: boolean) {
|
||||
const target = this.mirror.getNode(d.id);
|
||||
|
||||
@@ -3,8 +3,8 @@
|
||||
* Add support of customize target window and document
|
||||
*/
|
||||
|
||||
/* eslint-disable */
|
||||
// @ts-nocheck
|
||||
// tslint:disable
|
||||
export function polyfill(w: Window = window, d = document) {
|
||||
// return if scroll behavior is supported and polyfill is not forced
|
||||
if (
|
||||
|
||||
@@ -19,7 +19,6 @@ export class Timer {
|
||||
}
|
||||
/**
|
||||
* Add an action after the timer starts.
|
||||
* @param action
|
||||
*/
|
||||
public addAction(action: actionWithDelay) {
|
||||
const index = this.findActionIndex(action);
|
||||
@@ -27,7 +26,6 @@ export class Timer {
|
||||
}
|
||||
/**
|
||||
* Add all actions before the timer starts
|
||||
* @param actions
|
||||
*/
|
||||
public addActions(actions: actionWithDelay[]) {
|
||||
this.actions = this.actions.concat(actions);
|
||||
@@ -37,25 +35,24 @@ export class Timer {
|
||||
this.timeOffset = 0;
|
||||
let lastTimestamp = performance.now();
|
||||
const { actions } = this;
|
||||
const self = this;
|
||||
function check() {
|
||||
const check = () => {
|
||||
const time = performance.now();
|
||||
self.timeOffset += (time - lastTimestamp) * self.speed;
|
||||
this.timeOffset += (time - lastTimestamp) * this.speed;
|
||||
lastTimestamp = time;
|
||||
while (actions.length) {
|
||||
const action = actions[0];
|
||||
|
||||
if (self.timeOffset >= action.delay) {
|
||||
if (this.timeOffset >= action.delay) {
|
||||
actions.shift();
|
||||
action.doAction();
|
||||
} else {
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (actions.length > 0 || self.liveMode) {
|
||||
self.raf = requestAnimationFrame(check);
|
||||
if (actions.length > 0 || this.liveMode) {
|
||||
this.raf = requestAnimationFrame(check);
|
||||
}
|
||||
}
|
||||
};
|
||||
this.raf = requestAnimationFrame(check);
|
||||
}
|
||||
|
||||
|
||||
@@ -46,6 +46,7 @@ export class RRdomTreeNode implements AnyObject {
|
||||
}
|
||||
|
||||
public setCachedIndex(parentNode: AnyObject, index: number) {
|
||||
// eslint-disable-next-line @typescript-eslint/no-unsafe-assignment
|
||||
this.cachedIndexVersion = parentNode.childrenVersion;
|
||||
this.cachedIndex = index;
|
||||
}
|
||||
|
||||
@@ -27,12 +27,12 @@ export enum EventType {
|
||||
|
||||
export type domContentLoadedEvent = {
|
||||
type: EventType.DomContentLoaded;
|
||||
data: {};
|
||||
data: unknown;
|
||||
};
|
||||
|
||||
export type loadedEvent = {
|
||||
type: EventType.Load;
|
||||
data: {};
|
||||
data: unknown;
|
||||
};
|
||||
|
||||
export type fullSnapshotEvent = {
|
||||
@@ -76,8 +76,6 @@ export type pluginEvent<T = unknown> = {
|
||||
};
|
||||
};
|
||||
|
||||
export type styleSheetEvent = {};
|
||||
|
||||
export enum IncrementalSource {
|
||||
Mutation,
|
||||
MouseMove,
|
||||
@@ -218,7 +216,11 @@ export type SamplingStrategy = Partial<{
|
||||
|
||||
export type RecordPlugin<TOptions = unknown> = {
|
||||
name: string;
|
||||
observer?: (cb: Function, win: IWindow, options: TOptions) => listenerHandler;
|
||||
observer?: (
|
||||
cb: (...args: Array<unknown>) => void,
|
||||
win: IWindow,
|
||||
options: TOptions,
|
||||
) => listenerHandler;
|
||||
eventProcessor?: <TExtend>(event: eventWithTime) => eventWithTime & TExtend;
|
||||
options: TOptions;
|
||||
};
|
||||
@@ -285,8 +287,12 @@ export type observerParam = {
|
||||
shadowDomManager: ShadowDomManager;
|
||||
canvasManager: CanvasManager;
|
||||
plugins: Array<{
|
||||
observer: Function;
|
||||
callback: Function;
|
||||
observer: (
|
||||
cb: (...arg: Array<unknown>) => void,
|
||||
win: IWindow,
|
||||
options: unknown,
|
||||
) => listenerHandler;
|
||||
callback: (...arg: Array<unknown>) => void;
|
||||
options: unknown;
|
||||
}>;
|
||||
};
|
||||
|
||||
@@ -57,6 +57,7 @@ if (typeof window !== 'undefined' && window.Proxy && window.Reflect) {
|
||||
if (prop === 'map') {
|
||||
console.error(DEPARTED_MIRROR_ACCESS_WARNING);
|
||||
}
|
||||
// eslint-disable-next-line @typescript-eslint/no-unsafe-return
|
||||
return Reflect.get(target, prop, receiver);
|
||||
},
|
||||
});
|
||||
@@ -70,14 +71,14 @@ export function throttle<T>(
|
||||
) {
|
||||
let timeout: ReturnType<typeof setTimeout> | null = null;
|
||||
let previous = 0;
|
||||
return function (arg: T) {
|
||||
return function (...args: T[]) {
|
||||
const now = Date.now();
|
||||
if (!previous && options.leading === false) {
|
||||
previous = now;
|
||||
}
|
||||
const remaining = wait - (now - previous);
|
||||
// eslint-disable-next-line @typescript-eslint/no-unsafe-assignment, @typescript-eslint/no-this-alias
|
||||
const context = this;
|
||||
const args = arguments;
|
||||
if (remaining <= 0 || remaining > wait) {
|
||||
if (timeout) {
|
||||
clearTimeout(timeout);
|
||||
@@ -129,11 +130,13 @@ export function patch(
|
||||
source: { [key: string]: any },
|
||||
name: string,
|
||||
// tslint:disable-next-line:no-any
|
||||
replacement: (...args: any[]) => any,
|
||||
replacement: (...args: unknown[]) => unknown,
|
||||
): () => void {
|
||||
try {
|
||||
if (!(name in source)) {
|
||||
return () => {};
|
||||
return () => {
|
||||
//
|
||||
};
|
||||
}
|
||||
|
||||
const original = source[name] as () => unknown;
|
||||
@@ -143,6 +146,7 @@ export function patch(
|
||||
// otherwise it'll throw "TypeError: Object.defineProperties called on non-object"
|
||||
// tslint:disable-next-line:strict-type-predicates
|
||||
if (typeof wrapped === 'function') {
|
||||
// eslint-disable-next-line @typescript-eslint/no-unsafe-assignment
|
||||
wrapped.prototype = wrapped.prototype || {};
|
||||
Object.defineProperties(wrapped, {
|
||||
__rrweb_original__: {
|
||||
@@ -158,7 +162,9 @@ export function patch(
|
||||
source[name] = original;
|
||||
};
|
||||
} catch {
|
||||
return () => {};
|
||||
return () => {
|
||||
//
|
||||
};
|
||||
// This can throw if multiple fill happens on a global object like XMLHttpRequest
|
||||
// Fixes https://github.com/getsentry/sentry-javascript/issues/2043
|
||||
}
|
||||
@@ -249,19 +255,22 @@ export function isTouchEvent(
|
||||
|
||||
export function polyfill(win = window) {
|
||||
if ('NodeList' in win && !win.NodeList.prototype.forEach) {
|
||||
// eslint-disable-next-line @typescript-eslint/unbound-method
|
||||
win.NodeList.prototype.forEach = (Array.prototype
|
||||
.forEach as unknown) as NodeList['forEach'];
|
||||
}
|
||||
|
||||
if ('DOMTokenList' in win && !win.DOMTokenList.prototype.forEach) {
|
||||
// eslint-disable-next-line @typescript-eslint/unbound-method
|
||||
win.DOMTokenList.prototype.forEach = (Array.prototype
|
||||
.forEach as unknown) as DOMTokenList['forEach'];
|
||||
}
|
||||
|
||||
// https://github.com/Financial-Times/polyfill-service/pull/183
|
||||
if (!Node.prototype.contains) {
|
||||
Node.prototype.contains = function contains(node) {
|
||||
if (!(0 in arguments)) {
|
||||
Node.prototype.contains = (...args: unknown[]) => {
|
||||
let node = args[0] as Node | null;
|
||||
if (!(0 in args)) {
|
||||
throw new TypeError('1 argument is required');
|
||||
}
|
||||
|
||||
@@ -269,7 +278,6 @@ export function polyfill(win = window) {
|
||||
if (this === node) {
|
||||
return true;
|
||||
}
|
||||
// tslint:disable-next-line: no-conditional-assignment
|
||||
} while ((node = node && node.parentNode));
|
||||
|
||||
return false;
|
||||
@@ -426,8 +434,8 @@ export function getPositionsAndIndex(nestedIndex: number[]) {
|
||||
|
||||
/**
|
||||
* Returns the latest mutation in the queue for each node.
|
||||
* @param {textMutation[]} mutations The text mutations to filter.
|
||||
* @returns {textMutation[]} The filtered text mutations.
|
||||
* @param mutations - mutations The text mutations to filter.
|
||||
* @returns The filtered text mutations.
|
||||
*/
|
||||
export function uniqueTextMutations(mutations: textMutation[]): textMutation[] {
|
||||
const idSet = new Set<number>();
|
||||
|
||||
@@ -12,7 +12,12 @@ import {
|
||||
generateRecordSnippet,
|
||||
ISuite,
|
||||
} from './utils';
|
||||
import { recordOptions, eventWithTime, EventType } from '../src/types';
|
||||
import {
|
||||
recordOptions,
|
||||
eventWithTime,
|
||||
EventType,
|
||||
RecordPlugin,
|
||||
} from '../src/types';
|
||||
import { visitSnapshot, NodeType } from 'rrweb-snapshot';
|
||||
|
||||
describe('record integration tests', function (this: ISuite) {
|
||||
@@ -442,8 +447,8 @@ describe('record integration tests', function (this: ISuite) {
|
||||
const page: puppeteer.Page = await browser.newPage();
|
||||
await page.goto('about:blank');
|
||||
await page.setContent(
|
||||
getHtml.call(this, 'log.html', {
|
||||
plugins: '[rrwebConsoleRecord.getRecordConsolePlugin()]',
|
||||
getHtml('log.html', {
|
||||
plugins: ('[rrwebConsoleRecord.getRecordConsolePlugin()]' as unknown) as RecordPlugin<unknown>[],
|
||||
}),
|
||||
);
|
||||
|
||||
|
||||
@@ -11,7 +11,8 @@
|
||||
"outDir": "build",
|
||||
"lib": ["es6", "dom"],
|
||||
"downlevelIteration": true,
|
||||
"importsNotUsedAsValues": "error"
|
||||
"importsNotUsedAsValues": "error",
|
||||
"strictBindCallApply": true
|
||||
},
|
||||
"exclude": ["test"],
|
||||
"include": [
|
||||
|
||||
@@ -15,7 +15,6 @@ export declare type LogData = {
|
||||
trace: string[];
|
||||
payload: string[];
|
||||
};
|
||||
export declare type LogLevel = 'assert' | 'clear' | 'count' | 'countReset' | 'debug' | 'dir' | 'dirxml' | 'error' | 'group' | 'groupCollapsed' | 'groupEnd' | 'info' | 'log' | 'table' | 'time' | 'timeEnd' | 'timeLog' | 'trace' | 'warn';
|
||||
export declare type Logger = {
|
||||
assert?: typeof console.assert;
|
||||
clear?: typeof console.clear;
|
||||
@@ -37,6 +36,7 @@ export declare type Logger = {
|
||||
trace?: typeof console.trace;
|
||||
warn?: typeof console.warn;
|
||||
};
|
||||
export declare type LogLevel = keyof Logger;
|
||||
export declare const PLUGIN_NAME = "rrweb/console@1";
|
||||
export declare const getRecordConsolePlugin: (options?: LogRecordOptions) => RecordPlugin;
|
||||
export {};
|
||||
|
||||
@@ -1,2 +1,2 @@
|
||||
import type { StringifyOptions } from './index';
|
||||
export declare function stringify(obj: any, stringifyOptions?: StringifyOptions): string;
|
||||
export declare function stringify(obj: unknown, stringifyOptions?: StringifyOptions): string;
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
import type { IWindow, CanvasArg } from '../../../types';
|
||||
export declare function variableListFor(ctx: RenderingContext, ctor: string): any[];
|
||||
export declare const saveWebGLVar: (value: any, win: IWindow, ctx: RenderingContext) => number | void;
|
||||
export declare function serializeArg(value: any, win: IWindow, ctx: RenderingContext): CanvasArg;
|
||||
export declare const serializeArgs: (args: Array<any>, win: IWindow, ctx: RenderingContext) => CanvasArg[];
|
||||
export declare const isInstanceOfWebGLObject: (value: any, win: IWindow) => value is WebGLTexture | WebGLShader | WebGLBuffer | WebGLVertexArrayObject | WebGLProgram | WebGLActiveInfo | WebGLUniformLocation | WebGLFramebuffer | WebGLRenderbuffer | WebGLShaderPrecisionFormat;
|
||||
export declare function variableListFor(ctx: RenderingContext, ctor: string): unknown[];
|
||||
export declare const saveWebGLVar: (value: unknown, win: IWindow, ctx: RenderingContext) => number | void;
|
||||
export declare function serializeArg(value: unknown, win: IWindow, ctx: RenderingContext): CanvasArg;
|
||||
export declare const serializeArgs: (args: Array<unknown>, win: IWindow, ctx: RenderingContext) => CanvasArg[];
|
||||
export declare const isInstanceOfWebGLObject: (value: unknown, win: IWindow) => value is WebGLTexture | WebGLShader | WebGLBuffer | WebGLVertexArrayObject | WebGLProgram | WebGLActiveInfo | WebGLUniformLocation | WebGLFramebuffer | WebGLRenderbuffer | WebGLShaderPrecisionFormat;
|
||||
|
||||
2
packages/rrweb/typings/replay/index.d.ts
vendored
2
packages/rrweb/typings/replay/index.d.ts
vendored
@@ -52,8 +52,6 @@ export declare class Replayer {
|
||||
private attachDocumentToIframe;
|
||||
private collectIframeAndAttachDocument;
|
||||
private waitForStylesheetLoad;
|
||||
private hasImageArg;
|
||||
private getImageArgs;
|
||||
private preloadAllImages;
|
||||
private preloadImages;
|
||||
private deserializeAndPreloadCanvasEvents;
|
||||
|
||||
11
packages/rrweb/typings/types.d.ts
vendored
11
packages/rrweb/typings/types.d.ts
vendored
@@ -17,11 +17,11 @@ export declare enum EventType {
|
||||
}
|
||||
export declare type domContentLoadedEvent = {
|
||||
type: EventType.DomContentLoaded;
|
||||
data: {};
|
||||
data: unknown;
|
||||
};
|
||||
export declare type loadedEvent = {
|
||||
type: EventType.Load;
|
||||
data: {};
|
||||
data: unknown;
|
||||
};
|
||||
export declare type fullSnapshotEvent = {
|
||||
type: EventType.FullSnapshot;
|
||||
@@ -59,7 +59,6 @@ export declare type pluginEvent<T = unknown> = {
|
||||
payload: T;
|
||||
};
|
||||
};
|
||||
export declare type styleSheetEvent = {};
|
||||
export declare enum IncrementalSource {
|
||||
Mutation = 0,
|
||||
MouseMove = 1,
|
||||
@@ -134,7 +133,7 @@ export declare type SamplingStrategy = Partial<{
|
||||
}>;
|
||||
export declare type RecordPlugin<TOptions = unknown> = {
|
||||
name: string;
|
||||
observer?: (cb: Function, win: IWindow, options: TOptions) => listenerHandler;
|
||||
observer?: (cb: (...args: Array<unknown>) => void, win: IWindow, options: TOptions) => listenerHandler;
|
||||
eventProcessor?: <TExtend>(event: eventWithTime) => eventWithTime & TExtend;
|
||||
options: TOptions;
|
||||
};
|
||||
@@ -198,8 +197,8 @@ export declare type observerParam = {
|
||||
shadowDomManager: ShadowDomManager;
|
||||
canvasManager: CanvasManager;
|
||||
plugins: Array<{
|
||||
observer: Function;
|
||||
callback: Function;
|
||||
observer: (cb: (...arg: Array<unknown>) => void, win: IWindow, options: unknown) => listenerHandler;
|
||||
callback: (...arg: Array<unknown>) => void;
|
||||
options: unknown;
|
||||
}>;
|
||||
};
|
||||
|
||||
4
packages/rrweb/typings/utils.d.ts
vendored
4
packages/rrweb/typings/utils.d.ts
vendored
@@ -3,11 +3,11 @@ import type { IMirror, Mirror } from 'rrweb-snapshot';
|
||||
import type { RRNode, RRIFrameElement } from 'rrdom';
|
||||
export declare function on(type: string, fn: EventListenerOrEventListenerObject, target?: Document | IWindow): listenerHandler;
|
||||
export declare let _mirror: DeprecatedMirror;
|
||||
export declare function throttle<T>(func: (arg: T) => void, wait: number, options?: throttleOptions): (arg: T) => void;
|
||||
export declare function throttle<T>(func: (arg: T) => void, wait: number, options?: throttleOptions): (...args: T[]) => void;
|
||||
export declare function hookSetter<T>(target: T, key: string | number | symbol, d: PropertyDescriptor, isRevoked?: boolean, win?: Window & typeof globalThis): hookResetter;
|
||||
export declare function patch(source: {
|
||||
[key: string]: any;
|
||||
}, name: string, replacement: (...args: any[]) => any): () => void;
|
||||
}, name: string, replacement: (...args: unknown[]) => unknown): () => void;
|
||||
export declare function getWindowHeight(): number;
|
||||
export declare function getWindowWidth(): number;
|
||||
export declare function isBlocked(node: Node | null, blockClass: blockClass, checkAncestors: boolean): boolean;
|
||||
|
||||
@@ -7945,10 +7945,10 @@ minizlib@^2.0.0, minizlib@^2.1.1:
|
||||
minipass "^3.0.0"
|
||||
yallist "^4.0.0"
|
||||
|
||||
mitt@^1.1.3:
|
||||
version "1.2.0"
|
||||
resolved "https://registry.npmjs.org/mitt/-/mitt-1.2.0.tgz"
|
||||
integrity sha512-r6lj77KlwqLhIUku9UWYes7KJtsczvolZkzp8hbaDPPaE24OmWl5s539Mytlj22siEQKosZ26qCBgda2PKwoJw==
|
||||
mitt@^3.0.0:
|
||||
version "3.0.0"
|
||||
resolved "https://registry.yarnpkg.com/mitt/-/mitt-3.0.0.tgz#69ef9bd5c80ff6f57473e8d89326d01c414be0bd"
|
||||
integrity sha512-7dX2/10ITVyqh4aOSVI9gdape+t9l2/8QxHrFmUXu4EEUpdlxl6RudZUPZoc+zuY2hk1j7XxVroIVIan/pD/SQ==
|
||||
|
||||
mkdirp-classic@^0.5.2:
|
||||
version "0.5.3"
|
||||
|
||||
Reference in New Issue
Block a user