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:
Yun Feng
2022-07-10 17:49:20 +10:00
committed by GitHub
parent 15cb0b8cd3
commit 83394c3db4
44 changed files with 524 additions and 374 deletions

View File

@@ -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;

View File

@@ -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 () {
//
};
}
/**

View File

@@ -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;
}

View File

@@ -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`,

View File

@@ -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 {

View File

@@ -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() : ''));
};
/**

View File

@@ -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);

View File

@@ -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)];
}

View File

@@ -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') {

View File

@@ -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];

View File

@@ -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

View File

@@ -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,

View File

@@ -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"
}

View File

@@ -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;
}

View File

@@ -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'
) {

View File

@@ -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,
});

View File

@@ -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;
}

View File

@@ -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) {

View File

@@ -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) {

View File

@@ -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,

View File

@@ -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;

View File

@@ -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,

View File

@@ -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

View File

@@ -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,

View File

@@ -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,

View File

@@ -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 });

View File

@@ -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(

View File

@@ -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;

View File

@@ -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,
);
}

View File

@@ -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);

View File

@@ -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 (

View File

@@ -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);
}

View File

@@ -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;
}

View File

@@ -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;
}>;
};

View File

@@ -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>();

View File

@@ -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>[],
}),
);

View File

@@ -11,7 +11,8 @@
"outDir": "build",
"lib": ["es6", "dom"],
"downlevelIteration": true,
"importsNotUsedAsValues": "error"
"importsNotUsedAsValues": "error",
"strictBindCallApply": true
},
"exclude": ["test"],
"include": [

View File

@@ -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 {};

View File

@@ -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;

View File

@@ -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;

View File

@@ -52,8 +52,6 @@ export declare class Replayer {
private attachDocumentToIframe;
private collectIframeAndAttachDocument;
private waitForStylesheetLoad;
private hasImageArg;
private getImageArgs;
private preloadAllImages;
private preloadImages;
private deserializeAndPreloadCanvasEvents;

View File

@@ -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;
}>;
};

View File

@@ -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;

View File

@@ -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"