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 { NodeType as RRNodeType } from 'rrweb-snapshot';
import type { NWSAPI } from 'nwsapi'; import type { NWSAPI } from 'nwsapi';
import type { CSSStyleDeclaration as CSSStyleDeclarationType } from 'cssstyle'; import type { CSSStyleDeclaration as CSSStyleDeclarationType } from 'cssstyle';
@@ -14,8 +15,11 @@ import {
IRRDocument, IRRDocument,
CSSStyleDeclaration, CSSStyleDeclaration,
} from 'rrdom'; } from 'rrdom';
// eslint-disable-next-line @typescript-eslint/no-unsafe-assignment, @typescript-eslint/no-var-requires
const nwsapi = require('nwsapi'); const nwsapi = require('nwsapi');
// eslint-disable-next-line @typescript-eslint/no-unsafe-assignment, @typescript-eslint/no-var-requires
const cssom = require('cssom'); const cssom = require('cssom');
// eslint-disable-next-line @typescript-eslint/no-unsafe-assignment, @typescript-eslint/no-var-requires
const cssstyle = require('cssstyle'); const cssstyle = require('cssstyle');
export class RRNode extends BaseRRNode {} export class RRNode extends BaseRRNode {}
@@ -37,6 +41,7 @@ export class RRDocument
private _nwsapi: NWSAPI; private _nwsapi: NWSAPI;
get nwsapi() { get nwsapi() {
if (!this._nwsapi) { if (!this._nwsapi) {
// eslint-disable-next-line @typescript-eslint/no-unsafe-assignment, @typescript-eslint/no-unsafe-call
this._nwsapi = nwsapi({ this._nwsapi = nwsapi({
document: (this as unknown) as Document, document: (this as unknown) as Document,
DOMException: (null as unknown) as new ( DOMException: (null as unknown) as new (
@@ -53,26 +58,31 @@ export class RRDocument
return this._nwsapi; return this._nwsapi;
} }
// eslint-disable-next-line @typescript-eslint/ban-ts-comment
// @ts-ignore // @ts-ignore
get documentElement(): RRElement | null { get documentElement(): RRElement | null {
return super.documentElement as RRElement | null; return super.documentElement as RRElement | null;
} }
// eslint-disable-next-line @typescript-eslint/ban-ts-comment
// @ts-ignore // @ts-ignore
get body(): RRElement | null { get body(): RRElement | null {
return super.body as RRElement | null; return super.body as RRElement | null;
} }
// eslint-disable-next-line @typescript-eslint/ban-ts-comment
// @ts-ignore // @ts-ignore
get head() { get head() {
return super.head as RRElement | null; return super.head as RRElement | null;
} }
// eslint-disable-next-line @typescript-eslint/ban-ts-comment
// @ts-ignore // @ts-ignore
get implementation(): RRDocument { get implementation(): RRDocument {
return this; return this;
} }
// eslint-disable-next-line @typescript-eslint/ban-ts-comment
// @ts-ignore // @ts-ignore
get firstElementChild(): RRElement | null { get firstElementChild(): RRElement | null {
return this.documentElement; return this.documentElement;
@@ -109,8 +119,11 @@ export class RRDocument
} }
createDocument( createDocument(
// eslint-disable-next-line @typescript-eslint/no-unused-vars
_namespace: string | null, _namespace: string | null,
// eslint-disable-next-line @typescript-eslint/no-unused-vars
_qualifiedName: string | null, _qualifiedName: string | null,
// eslint-disable-next-line @typescript-eslint/no-unused-vars
_doctype?: DocumentType | null, _doctype?: DocumentType | null,
) { ) {
return new RRDocument(); return new RRDocument();
@@ -191,6 +204,7 @@ export class RRElement extends BaseRRElementImpl(RRNode) {
private _style: CSSStyleDeclarationType; private _style: CSSStyleDeclarationType;
constructor(tagName: string) { constructor(tagName: string) {
super(tagName); 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(); this._style = new cssstyle.CSSStyleDeclaration();
const style = this._style; const style = this._style;
Object.defineProperty(this.attributes, '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 // @ts-ignore
get style() { get style() {
return (this._style as unknown) as CSSStyleDeclaration; return (this._style as unknown) as CSSStyleDeclaration;
@@ -311,7 +326,7 @@ export class RRImageElement extends RRElement {
src: string; src: string;
width: number; width: number;
height: number; height: number;
onload: ((this: GlobalEventHandlers, ev: Event) => any) | null; onload: ((this: GlobalEventHandlers, ev: Event) => unknown) | null;
} }
export class RRMediaElement extends BaseRRMediaElementImpl(RRElement) {} export class RRMediaElement extends BaseRRMediaElementImpl(RRElement) {}
@@ -334,6 +349,7 @@ export class RRStyleElement extends RRElement {
for (const child of this.childNodes) for (const child of this.childNodes)
if (child.RRNodeType === RRNodeType.Text) if (child.RRNodeType === RRNodeType.Text)
result += (child as RRText).textContent; 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); this._sheet = cssom.parse(result);
} }
return this._sheet; return this._sheet;

View File

@@ -7,8 +7,9 @@ import { RRDocument, RRNode } from './document-nodejs';
*/ */
export function polyfillPerformance() { export function polyfillPerformance() {
if (typeof window !== 'undefined' || 'performance' in global) return; if (typeof window !== 'undefined' || 'performance' in global) return;
((global as Window & typeof globalThis) // eslint-disable-next-line @typescript-eslint/no-unsafe-assignment, @typescript-eslint/no-unsafe-member-access, @typescript-eslint/no-var-requires
.performance as unknown) = require('perf_hooks').performance; 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; INTERVAL = 1_000 / FPS;
let timeoutHandle: NodeJS.Timeout | null = null, let timeoutHandle: NodeJS.Timeout | null = null,
rafCount = 0, rafCount = 0,
requests = Object.create(null); requests = Object.create(null) as Record<string, (time: number) => void>;
function onFrameTimer() { function onFrameTimer() {
const currentRequests = requests; const currentRequests = requests;
requests = Object.create(null); requests = Object.create(null) as Record<string, (time: number) => void>;
timeoutHandle = null; timeoutHandle = null;
Object.keys(currentRequests).forEach(function (id) { Object.keys(currentRequests).forEach(function (id) {
const request = currentRequests[id]; const request = currentRequests[id];
@@ -63,7 +64,9 @@ export function polyfillRAF() {
*/ */
export function polyfillEvent() { export function polyfillEvent() {
if (typeof Event !== 'undefined') return; 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; const newMediaRRElement = newRRElement as RRMediaElement;
if (newMediaRRElement.paused !== undefined) if (newMediaRRElement.paused !== undefined)
newMediaRRElement.paused newMediaRRElement.paused
? oldMediaElement.pause() ? void oldMediaElement.pause()
: oldMediaElement.play(); : void oldMediaElement.play();
if (newMediaRRElement.muted !== undefined) if (newMediaRRElement.muted !== undefined)
oldMediaElement.muted = newMediaRRElement.muted; oldMediaElement.muted = newMediaRRElement.muted;
if (newMediaRRElement.volume !== undefined) if (newMediaRRElement.volume !== undefined)
@@ -383,10 +383,7 @@ export function createOrGetNode(
let tagName = (rrNode as IRRElement).tagName.toLowerCase(); let tagName = (rrNode as IRRElement).tagName.toLowerCase();
tagName = SVGTagMap[tagName] || tagName; tagName = SVGTagMap[tagName] || tagName;
if (sn && 'isSVG' in sn && sn?.isSVG) { if (sn && 'isSVG' in sn && sn?.isSVG) {
node = document.createElementNS( node = document.createElementNS(NAMESPACES['svg'], tagName);
NAMESPACES['svg'],
(rrNode as IRRElement).tagName.toLowerCase(),
);
} else node = document.createElement((rrNode as IRRElement).tagName); } else node = document.createElement((rrNode as IRRElement).tagName);
break; break;
} }

View File

@@ -119,6 +119,7 @@ export interface IRRCDATASection extends IRRNode {
} }
type ConstrainedConstructor<T = Record<string, unknown>> = new ( type ConstrainedConstructor<T = Record<string, unknown>> = new (
// eslint-disable-next-line @typescript-eslint/no-explicit-any
...args: any[] ...args: any[]
) => T; ) => T;
@@ -138,7 +139,8 @@ export class BaseRRNode implements IRRNode {
public readonly nodeName: string; public readonly nodeName: string;
public readonly RRNodeType: RRNodeType; 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; return false;
} }
// eslint-disable-next-line @typescript-eslint/no-unused-vars
public appendChild(_newChild: IRRNode): IRRNode { public appendChild(_newChild: IRRNode): IRRNode {
throw new Error( throw new Error(
`RRDomException: Failed to execute 'appendChild' on 'RRNode': This RRNode type does not support this method.`, `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 { public insertBefore(_newChild: IRRNode, _refChild: IRRNode | null): IRRNode {
throw new Error( throw new Error(
`RRDomException: Failed to execute 'insertBefore' on 'RRNode': This RRNode type does not support this method.`, `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( throw new Error(
`RRDomException: Failed to execute 'removeChild' on 'RRNode': This RRNode type does not support this method.`, `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). * Adhoc implementation for setting xhtml namespace in rebuilt.ts (rrweb-snapshot).
* There are two lines used this function: * There are two lines used this function:
* 1. doc.write('<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.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" "">') * 2. doc.write('\<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN" ""\>')
*/ */
public write(content: string) { public write(content: string) {
let publicId; let publicId;
@@ -329,8 +334,11 @@ export function BaseRRDocumentImpl<
} }
createDocument( createDocument(
// eslint-disable-next-line @typescript-eslint/no-unused-vars
_namespace: string | null, _namespace: string | null,
// eslint-disable-next-line @typescript-eslint/no-unused-vars
_qualifiedName: string | null, _qualifiedName: string | null,
// eslint-disable-next-line @typescript-eslint/no-unused-vars
_doctype?: DocumentType | null, _doctype?: DocumentType | null,
): IRRDocument { ): IRRDocument {
return new BaseRRDocument(); return new BaseRRDocument();
@@ -542,12 +550,14 @@ export function BaseRRElementImpl<
return node; return node;
} }
// eslint-disable-next-line @typescript-eslint/no-unused-vars
public attachShadow(_init: ShadowRootInit): IRRElement { public attachShadow(_init: ShadowRootInit): IRRElement {
const shadowRoot = this.ownerDocument.createElement('SHADOWROOT'); const shadowRoot = this.ownerDocument.createElement('SHADOWROOT');
this.shadowRoot = shadowRoot; this.shadowRoot = shadowRoot;
return shadowRoot; return shadowRoot;
} }
// eslint-disable-next-line @typescript-eslint/no-unused-vars
public dispatchEvent(_event: Event) { public dispatchEvent(_event: Event) {
return true; return true;
} }
@@ -570,6 +580,7 @@ export function BaseRRMediaElementImpl<
public volume?: number; public volume?: number;
public paused?: boolean; public paused?: boolean;
public muted?: boolean; public muted?: boolean;
// eslint-disable-next-line @typescript-eslint/no-unused-vars
attachShadow(_init: ShadowRootInit): IRRElement { attachShadow(_init: ShadowRootInit): IRRElement {
throw new Error( throw new Error(
`RRDomException: Failed to execute 'attachShadow' on 'RRElement': This RRElement does not support attachShadow`, `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) { export class RRDocument extends BaseRRDocumentImpl(RRNode) {
// In the rrweb replayer, there are some unserialized nodes like the element that stores the injected style rules. // 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. // 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; private _unserializedId = -1;
/** /**
@@ -57,8 +57,11 @@ export class RRDocument extends BaseRRDocumentImpl(RRNode) {
} }
createDocument( createDocument(
// eslint-disable-next-line @typescript-eslint/no-unused-vars
_namespace: string | null, _namespace: string | null,
// eslint-disable-next-line @typescript-eslint/no-unused-vars
_qualifiedName: string | null, _qualifiedName: string | null,
// eslint-disable-next-line @typescript-eslint/no-unused-vars
_doctype?: DocumentType | null, _doctype?: DocumentType | null,
) { ) {
return new RRDocument(); return new RRDocument();
@@ -201,9 +204,9 @@ function getValidTagName(element: HTMLElement): string {
/** /**
* Build a RRNode from a real Node. * Build a RRNode from a real Node.
* @param node the real Node * @param node - the real Node
* @param rrdom the RRDocument * @param rrdom - the RRDocument
* @param domMirror the NodeMirror that records the real document tree * @param domMirror - the NodeMirror that records the real document tree
* @returns the built RRNode * @returns the built RRNode
*/ */
export function buildFromNode( export function buildFromNode(
@@ -225,7 +228,7 @@ export function buildFromNode(
| 'CSS1Compat'; | 'CSS1Compat';
} }
break; break;
case NodeType.DOCUMENT_TYPE_NODE: case NodeType.DOCUMENT_TYPE_NODE: {
const documentType = node as DocumentType; const documentType = node as DocumentType;
rrNode = rrdom.createDocumentType( rrNode = rrdom.createDocumentType(
documentType.name, documentType.name,
@@ -233,7 +236,8 @@ export function buildFromNode(
documentType.systemId, documentType.systemId,
); );
break; break;
case NodeType.ELEMENT_NODE: }
case NodeType.ELEMENT_NODE: {
const elementNode = node as HTMLElement; const elementNode = node as HTMLElement;
const tagName = getValidTagName(elementNode); const tagName = getValidTagName(elementNode);
rrNode = rrdom.createElement(tagName); 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. * 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; break;
}
case NodeType.TEXT_NODE: case NodeType.TEXT_NODE:
rrNode = rrdom.createTextNode((node as Text).textContent || ''); rrNode = rrdom.createTextNode((node as Text).textContent || '');
break; break;
@@ -280,9 +285,9 @@ export function buildFromNode(
/** /**
* Build a RRDocument from a real document tree. * Build a RRDocument from a real document tree.
* @param dom the real document tree * @param dom - the real document tree
* @param domMirror the NodeMirror that records the real document tree * @param domMirror - the NodeMirror that records the real document tree
* @param rrdom the rrdom object to be constructed * @param rrdom - the rrdom object to be constructed
* @returns the build rrdom * @returns the build rrdom
*/ */
export function buildFromDom( export function buildFromDom(
@@ -390,7 +395,7 @@ export class Mirror implements IMirror<RRNode> {
/** /**
* Get a default serializedNodeWithId value for a 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 { export function getDefaultSN(node: IRRNode, id: number): serializedNodeWithId {
switch (node.RRNodeType) { switch (node.RRNodeType) {
@@ -400,7 +405,7 @@ export function getDefaultSN(node: IRRNode, id: number): serializedNodeWithId {
type: node.RRNodeType, type: node.RRNodeType,
childNodes: [], childNodes: [],
}; };
case RRNodeType.DocumentType: case RRNodeType.DocumentType: {
const doctype = node as IRRDocumentType; const doctype = node as IRRDocumentType;
return { return {
id, id,
@@ -409,6 +414,7 @@ export function getDefaultSN(node: IRRNode, id: number): serializedNodeWithId {
publicId: doctype.publicId, publicId: doctype.publicId,
systemId: doctype.systemId, systemId: doctype.systemId,
}; };
}
case RRNodeType.Element: case RRNodeType.Element:
return { return {
id, 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 { RRNode };
export { export {

View File

@@ -33,7 +33,7 @@ const camelizeRE = /-([a-z])/g;
const CUSTOM_PROPERTY_REGEX = /^--[a-zA-Z0-9-]+$/; const CUSTOM_PROPERTY_REGEX = /^--[a-zA-Z0-9-]+$/;
export const camelize = (str: string): string => { export const camelize = (str: string): string => {
if (CUSTOM_PROPERTY_REGEX.test(str)) return str; 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. */ /* Number of elements remains the same and no element will be added or removed. */
let oldElementsNum = 15, let oldElementsNum = 15,
newElementsNum = 15; newElementsNum = 15;
let oldElementsIds = [], let oldElementsIds: number[] = [],
newElementsIds = []; newElementsIds: number[] = [];
for (let i = 1; i <= oldElementsNum; i++) { for (let i = 1; i <= oldElementsNum; i++) {
oldElementsIds.push(i); oldElementsIds.push(i);
newElementsIds.push(i); newElementsIds.push(i);
@@ -950,8 +950,8 @@ describe('diff algorithm for rrdom', () => {
/* May need to add or remove some elements. */ /* May need to add or remove some elements. */
let oldElementsNum = 20, let oldElementsNum = 20,
newElementsNum = 30; newElementsNum = 30;
let oldElementsIds = [], let oldElementsIds: number[] = [],
newElementsIds = []; newElementsIds: number[] = [];
for (let i = 1; i <= oldElementsNum + 10; i++) oldElementsIds.push(i); for (let i = 1; i <= oldElementsNum + 10; i++) oldElementsIds.push(i);
for (let i = 1; i <= newElementsNum + 10; i++) newElementsIds.push(i); for (let i = 1; i <= newElementsNum + 10; i++) newElementsIds.push(i);
shuffle(oldElementsIds); shuffle(oldElementsIds);

View File

@@ -118,6 +118,7 @@ export function typeOf(
| 'undefined' | 'undefined'
| 'null' | 'null'
| 'object' { | 'object' {
// eslint-disable-next-line @typescript-eslint/unbound-method
const toString = Object.prototype.toString; const toString = Object.prototype.toString;
const map = { const map = {
'[object Boolean]': 'boolean', '[object Boolean]': 'boolean',
@@ -131,5 +132,6 @@ export function typeOf(
'[object Null]': 'null', '[object Null]': 'null',
'[object Object]': 'object', '[object Object]': 'object',
}; };
// eslint-disable-next-line @typescript-eslint/no-unsafe-return, @typescript-eslint/no-unsafe-member-access
return map[toString.call(obj)]; 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. * 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. * 2. Rewrites into typescript give us a better type interface.
*/ */
/* eslint-disable tsdoc/syntax */
/* tslint:disable no-conditional-assignment interface-name no-shadowed-variable */
export interface ParserOptions { export interface ParserOptions {
/** Silently fail on parse errors */ /** Silently fail on parse errors */
@@ -288,7 +287,7 @@ export function parse(css: string, options: ParserOptions = {}) {
function error(msg: string) { function error(msg: string) {
const err = new Error( const err = new Error(
options.source + ':' + lineno + ':' + column + ': ' + msg, `${options.source || ''}:${lineno}:${column}: ${msg}`,
) as ParserError; ) as ParserError;
err.reason = msg; err.reason = msg;
err.filename = options.source; err.filename = options.source;
@@ -457,6 +456,7 @@ export function parse(css: string, options: ParserOptions = {}) {
const pos = position(); const pos = position();
// prop // prop
// eslint-disable-next-line no-useless-escape
const propMatch = match(/^(\*?[-#\/\*\\\w]+(\[[0-9a-z_-]+\])?)\s*/); const propMatch = match(/^(\*?[-#\/\*\\\w]+(\[[0-9a-z_-]+\])?)\s*/);
if (!propMatch) { if (!propMatch) {
return; return;
@@ -469,6 +469,7 @@ export function parse(css: string, options: ParserOptions = {}) {
} }
// val // val
// eslint-disable-next-line no-useless-escape
const val = match(/^((?:'(?:\\'|.)*?'|"(?:\\"|.)*?"|\([^\)]*?\)|[^};])+)/); const val = match(/^((?:'(?:\\'|.)*?'|"(?:\\"|.)*?"|\([^\)]*?\)|[^};])+)/);
const ret = pos({ const ret = pos({
@@ -889,6 +890,7 @@ function addParent(obj: Stylesheet, parent?: Stylesheet) {
const value = obj[k as keyof Stylesheet]; const value = obj[k as keyof Stylesheet];
if (Array.isArray(value)) { if (Array.isArray(value)) {
value.forEach((v) => { value.forEach((v) => {
// eslint-disable-next-line @typescript-eslint/no-unsafe-argument
addParent(v, childParent); addParent(v, childParent);
}); });
} else if (value && typeof value === 'object') { } else if (value && typeof value === 'object') {

View File

@@ -134,7 +134,7 @@ function buildNode(
n.publicId, n.publicId,
n.systemId, n.systemId,
); );
case NodeType.Element: case NodeType.Element: {
const tagName = getTagName(n); const tagName = getTagName(n);
let node: Element; let node: Element;
if (n.isSVG) { if (n.isSVG) {
@@ -143,7 +143,7 @@ function buildNode(
node = doc.createElement(tagName); node = doc.createElement(tagName);
} }
for (const name in n.attributes) { for (const name in n.attributes) {
if (!n.attributes.hasOwnProperty(name)) { if (!Object.prototype.hasOwnProperty.call(n.attributes, name)) {
continue; continue;
} }
let value = n.attributes[name]; let value = n.attributes[name];
@@ -290,6 +290,7 @@ function buildNode(
} }
} }
return node; return node;
}
case NodeType.Text: case NodeType.Text:
return doc.createTextNode( return doc.createTextNode(
n.isStyle && hackCss n.isStyle && hackCss
@@ -417,7 +418,12 @@ function handleScroll(node: Node, mirror: Mirror) {
} }
const el = node as HTMLElement; const el = node as HTMLElement;
for (const name in n.attributes) { 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; continue;
} }
const value = n.attributes[name]; const value = n.attributes[name];

View File

@@ -102,7 +102,14 @@ export function absoluteToStylesheet(
): string { ): string {
return (cssText || '').replace( return (cssText || '').replace(
URL_IN_CSS_REF, 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 filePath = path1 || path2 || path3;
const maybeQuote = quote1 || quote2 || ''; const maybeQuote = quote1 || quote2 || '';
if (!filePath) { 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 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]+/; const SRCSET_COMMAS_OR_SPACES = /^[, \t\n\r\u000c]+/;
function getAbsoluteSrcsetString(doc: Document, attributeValue: string) { function getAbsoluteSrcsetString(doc: Document, attributeValue: string) {
/* /*
@@ -165,6 +174,7 @@ function getAbsoluteSrcsetString(doc: Document, attributeValue: string) {
} }
const output = []; const output = [];
// eslint-disable-next-line no-constant-condition
while (true) { while (true) {
collectCharacters(SRCSET_COMMAS_OR_SPACES); collectCharacters(SRCSET_COMMAS_OR_SPACES);
if (pos >= attributeValue.length) { if (pos >= attributeValue.length) {
@@ -182,6 +192,7 @@ function getAbsoluteSrcsetString(doc: Document, attributeValue: string) {
let descriptorsStr = ''; let descriptorsStr = '';
url = absoluteToDoc(doc, url); url = absoluteToDoc(doc, url);
let inParens = false; let inParens = false;
// eslint-disable-next-line no-constant-condition
while (true) { while (true) {
const c = attributeValue.charAt(pos); const c = attributeValue.charAt(pos);
if (c === '') { if (c === '') {
@@ -554,7 +565,7 @@ function serializeTextNode(
} }
} catch (err) { } catch (err) {
console.warn( 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, n,
); );
} }
@@ -740,7 +751,7 @@ function serializeElementNode(
); );
} catch (err) { } catch (err) {
console.warn( console.warn(
`Cannot inline img src=${image.currentSrc}! Error: ${err}`, `Cannot inline img src=${image.currentSrc}! Error: ${err as string}`,
); );
} }
oldValue oldValue

View File

@@ -122,6 +122,7 @@ export function is2DCanvasBlank(canvas: HTMLCanvasElement): boolean {
// get chunks of the canvas and check if it is blank // get chunks of the canvas and check if it is blank
for (let x = 0; x < canvas.width; x += chunkSize) { for (let x = 0; x < canvas.width; x += chunkSize) {
for (let y = 0; y < canvas.height; y += 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 getImageData = ctx.getImageData as PatchedGetImageData;
const originalGetImageData = const originalGetImageData =
ORIGINAL_ATTRIBUTE_NAME in getImageData 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 // even if we can already tell from the first chunk(s) that
// the canvas isn't blank // the canvas isn't blank
const pixelBuffer = new Uint32Array( const pixelBuffer = new Uint32Array(
// eslint-disable-next-line @typescript-eslint/no-unsafe-argument, @typescript-eslint/no-unsafe-member-access
originalGetImageData.call( originalGetImageData.call(
ctx, ctx,
x, x,

View File

@@ -78,7 +78,7 @@
"@xstate/fsm": "^1.4.0", "@xstate/fsm": "^1.4.0",
"base64-arraybuffer": "^1.0.1", "base64-arraybuffer": "^1.0.1",
"fflate": "^0.4.4", "fflate": "^0.4.4",
"mitt": "^1.1.3", "mitt": "^3.0.0",
"rrdom": "^0.1.2", "rrdom": "^0.1.2",
"rrweb-snapshot": "^1.1.14" "rrweb-snapshot": "^1.1.14"
} }

View File

@@ -7,7 +7,7 @@ export const unpack: UnpackFn = (raw: string) => {
return raw; return raw;
} }
try { try {
const e: eventWithTime = JSON.parse(raw); const e: eventWithTime = JSON.parse(raw) as eventWithTime;
if (e.timestamp) { if (e.timestamp) {
return e; return e;
} }
@@ -17,7 +17,7 @@ export const unpack: UnpackFn = (raw: string) => {
try { try {
const e: eventWithTimeAndPacker = JSON.parse( const e: eventWithTimeAndPacker = JSON.parse(
strFromU8(unzlibSync(strToU8(raw, true))), strFromU8(unzlibSync(strToU8(raw, true))),
); ) as eventWithTimeAndPacker;
if (e.v === MARK) { if (e.v === MARK) {
return e; 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 // tslint:disable
/** /**
* Class StackFrame is a fork of https://github.com/stacktracejs/stackframe/blob/master/stackframe.js * Class StackFrame is a fork of https://github.com/stacktracejs/stackframe/blob/master/stackframe.js
@@ -27,19 +32,9 @@ export class StackFrame {
toString() { toString() {
const lineNumber = this.lineNumber || ''; const lineNumber = this.lineNumber || '';
const columnNumber = this.columnNumber || ''; const columnNumber = this.columnNumber || '';
if (this.functionName) { if (this.functionName)
return ( return `${this.functionName} (${this.fileName}:${lineNumber}:${columnNumber})`;
this.functionName + return `${this.fileName}:${lineNumber}:${columnNumber}`;
' (' +
this.fileName +
':' +
lineNumber +
':' +
columnNumber +
')'
);
}
return this.fileName + ':' + lineNumber + ':' + columnNumber;
} }
} }
@@ -55,9 +50,6 @@ const SAFARI_NATIVE_CODE_REGEXP = /^(eval@)?(\[native code])?$/;
export const ErrorStackParser = { export const ErrorStackParser = {
/** /**
* Given an Error object, extract the most information from it. * Given an Error object, extract the most information from it.
*
* @param {Error} error object
* @return {Array} of StackFrames
*/ */
parse: function (error: Error): StackFrame[] { parse: function (error: Error): StackFrame[] {
// https://github.com/rrweb-io/rrweb/issues/782 // https://github.com/rrweb-io/rrweb/issues/782
@@ -65,8 +57,10 @@ export const ErrorStackParser = {
return []; return [];
} }
if ( if (
// eslint-disable-next-line @typescript-eslint/ban-ts-comment
// @ts-ignore // @ts-ignore
typeof error.stacktrace !== 'undefined' || typeof error.stacktrace !== 'undefined' ||
// eslint-disable-next-line @typescript-eslint/ban-ts-comment
// @ts-ignore // @ts-ignore
typeof error['opera#sourceloc'] !== 'undefined' typeof error['opera#sourceloc'] !== 'undefined'
) { ) {

View File

@@ -59,27 +59,6 @@ export type LogData = {
type logCallback = (p: LogData) => void; 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 */ /* fork from interface Console */
// all kinds of console functions // all kinds of console functions
export type Logger = { export type Logger = {
@@ -104,14 +83,26 @@ export type Logger = {
warn?: typeof console.warn; warn?: typeof console.warn;
}; };
export type LogLevel = keyof Logger;
function initLogObserver( function initLogObserver(
cb: logCallback, cb: logCallback,
win: IWindow, // top window or in an iframe win: IWindow, // top window or in an iframe
logOptions: LogRecordOptions, options: LogRecordOptions,
): listenerHandler { ): listenerHandler {
const logOptions = (options
? Object.assign({}, defaultLogOptions, options)
: defaultLogOptions) as {
level: LogLevel[];
lengthThreshold: number;
stringifyOptions?: StringifyOptions;
logger: Logger | 'console';
};
const loggerType = logOptions.logger; const loggerType = logOptions.logger;
if (!loggerType) { if (!loggerType) {
return () => {}; return () => {
//
};
} }
let logger: Logger; let logger: Logger;
if (typeof loggerType === 'string') { if (typeof loggerType === 'string') {
@@ -122,10 +113,11 @@ function initLogObserver(
let logCount = 0; let logCount = 0;
const cancelHandlers: listenerHandler[] = []; const cancelHandlers: listenerHandler[] = [];
// add listener to thrown errors // add listener to thrown errors
if (logOptions.level!.includes('error')) { if (logOptions.level.includes('error')) {
if (window) { if (window) {
const errorHandler = (event: ErrorEvent) => { const errorHandler = (event: ErrorEvent) => {
const { message, error } = event; const message = event.message,
error = event.error as Error;
const trace: string[] = ErrorStackParser.parse( const trace: string[] = ErrorStackParser.parse(
error, error,
).map((stackFrame: StackFrame) => stackFrame.toString()); ).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)); cancelHandlers.push(replace(logger, levelType));
} }
return () => { return () => {
@@ -151,46 +143,52 @@ function initLogObserver(
/** /**
* replace the original console function and record logs * replace the original console function and record logs
* @param logger the logger object such as Console * @param logger - the logger object such as Console
* @param level the name of log function to be replaced * @param level - the name of log function to be replaced
*/ */
function replace(_logger: Logger, level: LogLevel) { function replace(_logger: Logger, level: LogLevel) {
if (!_logger[level]) { if (!_logger[level]) {
return () => {}; return () => {
//
};
} }
// replace the logger.{level}. return a restore function // replace the logger.{level}. return a restore function
return patch(_logger, level, (original) => { return patch(
return (...args: Array<unknown>) => { _logger,
original.apply(this, args); level,
try { (original: (...args: Array<unknown>) => void) => {
const trace = ErrorStackParser.parse(new Error()) return (...args: Array<unknown>) => {
.map((stackFrame: StackFrame) => stackFrame.toString()) original.apply(this, args);
.splice(1); // splice(1) to omit the hijacked log function try {
const payload = args.map((s) => const trace = ErrorStackParser.parse(new Error())
stringify(s, logOptions.stringifyOptions), .map((stackFrame: StackFrame) => stackFrame.toString())
); .splice(1); // splice(1) to omit the hijacked log function
logCount++; const payload = args.map((s) =>
if (logCount < logOptions.lengthThreshold!) { stringify(s, logOptions.stringifyOptions),
cb({ );
level, logCount++;
trace, if (logCount < logOptions.lengthThreshold) {
payload, cb({
}); level,
} else if (logCount === logOptions.lengthThreshold) { trace,
// notify the user payload,
cb({ });
level: 'warn', } else if (logCount === logOptions.lengthThreshold) {
trace: [], // notify the user
payload: [ cb({
stringify('The number of log records reached the threshold.'), 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) => ({ ) => RecordPlugin = (options) => ({
name: PLUGIN_NAME, name: PLUGIN_NAME,
observer: initLogObserver, observer: initLogObserver,
options: options options: options,
? Object.assign({}, defaultLogOptions, options)
: defaultLogOptions,
}); });

View File

@@ -8,7 +8,7 @@ import type { StringifyOptions } from './index';
/** /**
* transfer the node path in Event to string * 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 | '' { function pathToSelector(node: HTMLElement): string | '' {
if (!node || !node.outerHTML) { if (!node || !node.outerHTML) {
@@ -39,7 +39,7 @@ function pathToSelector(node: HTMLElement): string | '' {
} }
if (domSiblings.length > 1) { if (domSiblings.length > 1) {
name += ':eq(' + domSiblings.indexOf(node) + ')'; name += `:eq(${domSiblings.indexOf(node)})`;
} }
path = name + (path ? '>' + path : ''); path = name + (path ? '>' + path : '');
node = parent; node = parent;
@@ -51,21 +51,24 @@ function pathToSelector(node: HTMLElement): string | '' {
/** /**
* judge is object * judge is object
*/ */
function isObject(obj: any): boolean { function isObject(obj: unknown): boolean {
return Object.prototype.toString.call(obj) === '[object Object]'; return Object.prototype.toString.call(obj) === '[object Object]';
} }
/** /**
* judge the object's depth * judge the object's depth
*/ */
function isObjTooDeep(obj: any, limit: number): boolean { function isObjTooDeep(obj: Record<string, unknown>, limit: number): boolean {
if (limit === 0) { if (limit === 0) {
return true; return true;
} }
const keys = Object.keys(obj); const keys = Object.keys(obj);
for (const key of keys) { 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; return true;
} }
} }
@@ -75,10 +78,10 @@ function isObjTooDeep(obj: any, limit: number): boolean {
/** /**
* stringify any js object * stringify any js object
* @param obj the object to stringify * @param obj - the object to stringify
*/ */
export function stringify( export function stringify(
obj: any, obj: unknown,
stringifyOptions?: StringifyOptions, stringifyOptions?: StringifyOptions,
): string { ): string {
const options: StringifyOptions = { const options: StringifyOptions = {
@@ -86,63 +89,68 @@ export function stringify(
depthOfLimit: 4, depthOfLimit: 4,
}; };
Object.assign(options, stringifyOptions); Object.assign(options, stringifyOptions);
const stack: any[] = []; const stack: unknown[] = [];
const keys: any[] = []; const keys: unknown[] = [];
return JSON.stringify(obj, function (key, value) { return JSON.stringify(
/** obj,
* forked from https://github.com/moll/json-stringify-safe/blob/master/stringify.js function (key, value: string | object | null | undefined) {
* to deCycle the object /**
*/ * forked from https://github.com/moll/json-stringify-safe/blob/master/stringify.js
if (stack.length > 0) { * to deCycle the object
const thisPos = stack.indexOf(this); */
~thisPos ? stack.splice(thisPos + 1) : stack.push(this); if (stack.length > 0) {
~thisPos ? keys.splice(thisPos, Infinity, key) : keys.push(key); const thisPos = stack.indexOf(this);
if (~stack.indexOf(value)) { ~thisPos ? stack.splice(thisPos + 1) : stack.push(this);
if (stack[0] === value) { ~thisPos ? keys.splice(thisPos, Infinity, key) : keys.push(key);
value = '[Circular ~]'; if (~stack.indexOf(value)) {
} else { if (stack[0] === value) {
value = value = '[Circular ~]';
'[Circular ~.' + } else {
keys.slice(0, stack.indexOf(value)).join('.') + value =
']'; '[Circular ~.' +
keys.slice(0, stack.indexOf(value)).join('.') +
']';
}
} }
} else {
stack.push(value);
} }
} else { /* END of the FORK */
stack.push(value);
}
/* END of the FORK */
if (value === null || value === undefined) { if (value === null || value === undefined) {
return value; return value;
} }
if (shouldIgnore(value)) { if (shouldIgnore(value as object)) {
return toString(value); return toString(value as object);
} }
if (value instanceof Event) { if (value instanceof Event) {
const eventResult: any = {}; const eventResult: Record<string, unknown> = {};
for (const eventKey in value) { for (const eventKey in value) {
const eventValue = (value as any)[eventKey]; const eventValue = ((value as unknown) as Record<string, unknown>)[
if (Array.isArray(eventValue)) { eventKey
eventResult[eventKey] = pathToSelector( ];
eventValue.length ? eventValue[0] : null, if (Array.isArray(eventValue)) {
); eventResult[eventKey] = pathToSelector(
} else { (eventValue.length ? eventValue[0] : null) as HTMLElement,
eventResult[eventKey] = eventValue; );
} 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; return value;
} 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;
});
/** /**
* whether we should ignore obj's info and call toString() function instead * 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 * 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; return true;
} }

View File

@@ -70,7 +70,7 @@ class LogReplayPlugin {
] ]
: console.log; : console.log;
logger( logger(
...data.payload.map((s) => JSON.parse(s)), ...data.payload.map((s) => JSON.parse(s) as object),
this.formatMessage(data), this.formatMessage(data),
); );
}; };
@@ -84,7 +84,7 @@ class LogReplayPlugin {
] ]
: console[level]; : console[level];
logger( logger(
...data.payload.map((s) => JSON.parse(s)), ...data.payload.map((s) => JSON.parse(s) as object),
this.formatMessage(data), this.formatMessage(data),
); );
}; };
@@ -95,7 +95,7 @@ class LogReplayPlugin {
/** /**
* format the trace data to a string * format the trace data to a string
* @param data the log data * @param data - the log data
*/ */
private formatMessage(data: LogData): string { private formatMessage(data: LogData): string {
if (data.trace.length === 0) { if (data.trace.length === 0) {

View File

@@ -129,7 +129,9 @@ function initMoveObserver({
mirror, mirror,
}: observerParam): listenerHandler { }: observerParam): listenerHandler {
if (sampling.mousemove === false) { if (sampling.mousemove === false) {
return () => {}; return () => {
//
};
} }
const threshold = const threshold =
@@ -209,7 +211,9 @@ function initMouseInteractionObserver({
sampling, sampling,
}: observerParam): listenerHandler { }: observerParam): listenerHandler {
if (sampling.mouseInteraction === false) { if (sampling.mouseInteraction === false) {
return () => {}; return () => {
//
};
} }
const disableMap: Record<string, boolean | undefined> = const disableMap: Record<string, boolean | undefined> =
sampling.mouseInteraction === true || sampling.mouseInteraction === true ||
@@ -438,7 +442,7 @@ function initInputObserver({
hookSetter<HTMLElement>(p[0], p[1], { hookSetter<HTMLElement>(p[0], p[1], {
set() { set() {
// mock to a normal event // 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, { styleSheetRuleCb, mirror }: observerParam,
{ win }: { win: IWindow }, { win }: { win: IWindow },
): listenerHandler { ): listenerHandler {
// eslint-disable-next-line @typescript-eslint/unbound-method
const insertRule = win.CSSStyleSheet.prototype.insertRule; const insertRule = win.CSSStyleSheet.prototype.insertRule;
win.CSSStyleSheet.prototype.insertRule = function ( win.CSSStyleSheet.prototype.insertRule = function (
this: CSSStyleSheet,
rule: string, rule: string,
index?: number, index?: number,
) { ) {
const id = mirror.getId(this.ownerNode); const id = mirror.getId(this.ownerNode as Node);
if (id !== -1) { if (id !== -1) {
styleSheetRuleCb({ styleSheetRuleCb({
id, id,
adds: [{ rule, index }], 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; const deleteRule = win.CSSStyleSheet.prototype.deleteRule;
win.CSSStyleSheet.prototype.deleteRule = function (index: number) { win.CSSStyleSheet.prototype.deleteRule = function (
const id = mirror.getId(this.ownerNode); this: CSSStyleSheet,
index: number,
) {
const id = mirror.getId(this.ownerNode as Node);
if (id !== -1) { if (id !== -1) {
styleSheetRuleCb({ styleSheetRuleCb({
id, id,
removes: [{ index }], removes: [{ index }],
}); });
} }
return deleteRule.apply(this, arguments); return deleteRule.apply(this, [index]);
}; };
const supportedNestedCSSRuleTypes: { const supportedNestedCSSRuleTypes: {
@@ -549,12 +559,15 @@ function initStyleSheetObserver(
Object.entries(supportedNestedCSSRuleTypes).forEach(([typeKey, type]) => { Object.entries(supportedNestedCSSRuleTypes).forEach(([typeKey, type]) => {
unmodifiedFunctions[typeKey] = { unmodifiedFunctions[typeKey] = {
// eslint-disable-next-line @typescript-eslint/unbound-method
insertRule: type.prototype.insertRule, insertRule: type.prototype.insertRule,
// eslint-disable-next-line @typescript-eslint/unbound-method
deleteRule: type.prototype.deleteRule, deleteRule: type.prototype.deleteRule,
}; };
type.prototype.insertRule = function (rule: string, index?: number) { 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) { if (id !== -1) {
styleSheetRuleCb({ styleSheetRuleCb({
id, id,
@@ -562,25 +575,28 @@ function initStyleSheetObserver(
{ {
rule, rule,
index: [ index: [
...getNestedCSSRulePositions(this), ...getNestedCSSRulePositions(this as CSSRule),
index || 0, // defaults to 0 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) { 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) { if (id !== -1) {
styleSheetRuleCb({ styleSheetRuleCb({
id, 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, { styleDeclarationCb, mirror }: observerParam,
{ win }: { win: IWindow }, { win }: { win: IWindow },
): listenerHandler { ): listenerHandler {
// eslint-disable-next-line @typescript-eslint/unbound-method
const setProperty = win.CSSStyleDeclaration.prototype.setProperty; const setProperty = win.CSSStyleDeclaration.prototype.setProperty;
win.CSSStyleDeclaration.prototype.setProperty = function ( win.CSSStyleDeclaration.prototype.setProperty = function (
this: CSSStyleDeclaration, this: CSSStyleDeclaration,
@@ -617,9 +634,10 @@ function initStyleDeclarationObserver(
index: getNestedCSSRulePositions(this.parentRule!), 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; const removeProperty = win.CSSStyleDeclaration.prototype.removeProperty;
win.CSSStyleDeclaration.prototype.removeProperty = function ( win.CSSStyleDeclaration.prototype.removeProperty = function (
this: CSSStyleDeclaration, this: CSSStyleDeclaration,
@@ -635,7 +653,7 @@ function initStyleDeclarationObserver(
index: getNestedCSSRulePositions(this.parentRule!), index: getNestedCSSRulePositions(this.parentRule!),
}); });
} }
return removeProperty.apply(this, arguments); return removeProperty.apply(this, [property]);
}; };
return () => { return () => {
@@ -679,7 +697,9 @@ function initMediaInteractionObserver({
function initFontObserver({ fontCb, doc }: observerParam): listenerHandler { function initFontObserver({ fontCb, doc }: observerParam): listenerHandler {
const win = doc.defaultView as IWindow; const win = doc.defaultView as IWindow;
if (!win) { if (!win) {
return () => {}; return () => {
//
};
} }
const handlers: listenerHandler[] = []; const handlers: listenerHandler[] = [];
@@ -689,7 +709,7 @@ function initFontObserver({ fontCb, doc }: observerParam): listenerHandler {
const originalFontFace = win.FontFace; const originalFontFace = win.FontFace;
win.FontFace = (function FontFace( win.FontFace = (function FontFace(
family: string, family: string,
source: string | ArrayBufferView, source: string | ArrayBufferLike,
descriptors?: FontFaceDescriptors, descriptors?: FontFaceDescriptors,
) { ) {
const fontFace = new originalFontFace(family, source, descriptors); const fontFace = new originalFontFace(family, source, descriptors);
@@ -701,23 +721,27 @@ function initFontObserver({ fontCb, doc }: observerParam): listenerHandler {
typeof source === 'string' typeof source === 'string'
? source ? source
: // tslint:disable-next-line: no-any : // tslint:disable-next-line: no-any
JSON.stringify(Array.from(new Uint8Array(source as any))), JSON.stringify(Array.from(new Uint8Array(source))),
}); });
return fontFace; return fontFace;
} as unknown) as typeof FontFace; } as unknown) as typeof FontFace;
const restoreHandler = patch(doc.fonts, 'add', function (original) { const restoreHandler = patch(
return function (this: FontFaceSet, fontFace: FontFace) { doc.fonts,
setTimeout(() => { 'add',
const p = fontMap.get(fontFace); function (original: (font: FontFace) => void) {
if (p) { return function (this: FontFaceSet, fontFace: FontFace) {
fontCb(p); setTimeout(() => {
fontMap.delete(fontFace); const p = fontMap.get(fontFace);
} if (p) {
}, 0); fontCb(p);
return original.apply(this, [fontFace]); fontMap.delete(fontFace);
}; }
}); }, 0);
return original.apply(this, [fontFace]);
};
},
);
handlers.push(() => { handlers.push(() => {
win.FontFace = originalFontFace; win.FontFace = originalFontFace;
@@ -817,7 +841,9 @@ export function initObservers(
): listenerHandler { ): listenerHandler {
const currentWindow = o.doc.defaultView; // basically document.window const currentWindow = o.doc.defaultView; // basically document.window
if (!currentWindow) { if (!currentWindow) {
return () => {}; return () => {
//
};
} }
mergeHooks(o, hooks); mergeHooks(o, hooks);
@@ -833,7 +859,11 @@ export function initObservers(
const styleDeclarationObserver = initStyleDeclarationObserver(o, { const styleDeclarationObserver = initStyleDeclarationObserver(o, {
win: currentWindow, win: currentWindow,
}); });
const fontObserver = o.collectFonts ? initFontObserver(o) : () => {}; const fontObserver = o.collectFonts
? initFontObserver(o)
: () => {
//
};
// plugins // plugins
const pluginHandlers: listenerHandler[] = []; const pluginHandlers: listenerHandler[] = [];
for (const plugin of o.plugins) { for (const plugin of o.plugins) {

View File

@@ -31,7 +31,12 @@ export default function initCanvas2DMutationObserver(
const restoreHandler = patch( const restoreHandler = patch(
win.CanvasRenderingContext2D.prototype, win.CanvasRenderingContext2D.prototype,
prop, prop,
function (original) { function (
original: (
this: CanvasRenderingContext2D,
...args: unknown[]
) => void,
) {
return function ( return function (
this: CanvasRenderingContext2D, this: CanvasRenderingContext2D,
...args: Array<unknown> ...args: Array<unknown>
@@ -59,6 +64,7 @@ export default function initCanvas2DMutationObserver(
prop, prop,
{ {
set(v) { set(v) {
// eslint-disable-next-line @typescript-eslint/no-unsafe-argument, @typescript-eslint/no-unsafe-member-access
cb(this.canvas, { cb(this.canvas, {
type: CanvasContext['2D'], type: CanvasContext['2D'],
property: prop, property: prop,

View File

@@ -72,10 +72,10 @@ export class CanvasManager {
this.initCanvasFPSObserver(sampling, win, blockClass); this.initCanvasFPSObserver(sampling, win, blockClass);
} }
private processMutation: canvasManagerMutationCallback = function ( private processMutation: canvasManagerMutationCallback = (
target, target,
mutation, mutation,
) { ) => {
const newFrame = const newFrame =
this.rafStamps.invokeId && this.rafStamps.invokeId &&
this.rafStamps.latestId !== this.rafStamps.invokeId; this.rafStamps.latestId !== this.rafStamps.invokeId;
@@ -148,7 +148,8 @@ export class CanvasManager {
lastSnapshotTime = timestamp; lastSnapshotTime = timestamp;
win.document 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) => { .forEach(async (canvas: HTMLCanvasElement) => {
const id = this.mirror.getId(canvas); const id = this.mirror.getId(canvas);
if (snapshotInProgressMap.get(id)) return; if (snapshotInProgressMap.get(id)) return;

View File

@@ -11,7 +11,13 @@ export default function initCanvasContextObserver(
const restoreHandler = patch( const restoreHandler = patch(
win.HTMLCanvasElement.prototype, win.HTMLCanvasElement.prototype,
'getContext', 'getContext',
function (original) { function (
original: (
this: ICanvas,
contextType: string,
...args: Array<unknown>
) => void,
) {
return function ( return function (
this: ICanvas, this: ICanvas,
contextType: string, contextType: string,

View File

@@ -2,7 +2,7 @@ import { encode } from 'base64-arraybuffer';
import type { IWindow, CanvasArg } from '../../../types'; import type { IWindow, CanvasArg } from '../../../types';
// TODO: unify with `replay/webgl.ts` // TODO: unify with `replay/webgl.ts`
type CanvasVarMap = Map<string, any[]>; type CanvasVarMap = Map<string, unknown[]>;
const canvasVarMap: Map<RenderingContext, CanvasVarMap> = new Map(); const canvasVarMap: Map<RenderingContext, CanvasVarMap> = new Map();
export function variableListFor(ctx: RenderingContext, ctor: string) { export function variableListFor(ctx: RenderingContext, ctor: string) {
let contextMap = canvasVarMap.get(ctx); let contextMap = canvasVarMap.get(ctx);
@@ -13,11 +13,11 @@ export function variableListFor(ctx: RenderingContext, ctor: string) {
if (!contextMap.has(ctor)) { if (!contextMap.has(ctor)) {
contextMap.set(ctor, []); contextMap.set(ctor, []);
} }
return contextMap.get(ctor) as any[]; return contextMap.get(ctor) as unknown[];
} }
export const saveWebGLVar = ( export const saveWebGLVar = (
value: any, value: unknown,
win: IWindow, win: IWindow,
ctx: RenderingContext, ctx: RenderingContext,
): number | void => { ): 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 // from webgl-recorder: https://github.com/evanw/webgl-recorder/blob/bef0e65596e981ee382126587e2dcbe0fc7748e2/webgl-recorder.js#L50-L77
export function serializeArg( export function serializeArg(
value: any, value: unknown,
win: IWindow, win: IWindow,
ctx: RenderingContext, ctx: RenderingContext,
): CanvasArg { ): CanvasArg {
@@ -125,11 +125,11 @@ export function serializeArg(
}; };
} }
return value; return value as CanvasArg;
} }
export const serializeArgs = ( export const serializeArgs = (
args: Array<any>, args: Array<unknown>,
win: IWindow, win: IWindow,
ctx: RenderingContext, ctx: RenderingContext,
) => { ) => {
@@ -137,7 +137,7 @@ export const serializeArgs = (
}; };
export const isInstanceOfWebGLObject = ( export const isInstanceOfWebGLObject = (
value: any, value: unknown,
win: IWindow, win: IWindow,
): value is ): value is
| WebGLActiveInfo | WebGLActiveInfo

View File

@@ -27,30 +27,36 @@ function patchGLPrototype(
if (typeof prototype[prop as keyof typeof prototype] !== 'function') { if (typeof prototype[prop as keyof typeof prototype] !== 'function') {
continue; continue;
} }
const restoreHandler = patch(prototype, prop, function (original) { const restoreHandler = patch(
return function (this: typeof prototype, ...args: Array<unknown>) { prototype,
const result = original.apply(this, args); prop,
saveWebGLVar(result, win, prototype); function (
if (!isBlocked(this.canvas, blockClass, true)) { 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); return result;
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;
};
});
handlers.push(restoreHandler); handlers.push(restoreHandler);
} catch { } catch {
const hookHandler = hookSetter<typeof prototype>(prototype, prop, { const hookHandler = hookSetter<typeof prototype>(prototype, prop, {
set(v) { set(v) {
// TODO: this could potentially also be an OffscreenCanvas as well as HTMLCanvasElement // 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, { cb(this.canvas as HTMLCanvasElement, {
type, type,
property: prop, property: prop,

View File

@@ -34,16 +34,21 @@ export class ShadowDomManager {
this.mirror = options.mirror; this.mirror = options.mirror;
// Patch 'attachShadow' to observe newly added shadow doms. // Patch 'attachShadow' to observe newly added shadow doms.
// eslint-disable-next-line @typescript-eslint/no-this-alias
const manager = this; const manager = this;
this.restorePatches.push( this.restorePatches.push(
patch(HTMLElement.prototype, 'attachShadow', function (original) { patch(
return function () { HTMLElement.prototype,
const shadowRoot = original.apply(this, arguments); 'attachShadow',
if (this.shadowRoot) function (original: (init: ShadowRootInit) => ShadowRoot) {
manager.addShadowRoot(this.shadowRoot, this.ownerDocument); return function (this: HTMLElement, option: ShadowRootInit) {
return shadowRoot; 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) { public observeAttachShadow(iframeElement: HTMLIFrameElement) {
if (iframeElement.contentWindow) { if (iframeElement.contentWindow) {
// eslint-disable-next-line @typescript-eslint/no-this-alias
const manager = this; const manager = this;
this.restorePatches.push( this.restorePatches.push(
patch( patch(
@@ -80,9 +86,9 @@ export class ShadowDomManager {
HTMLElement: { prototype: HTMLElement }; HTMLElement: { prototype: HTMLElement };
}).HTMLElement.prototype, }).HTMLElement.prototype,
'attachShadow', 'attachShadow',
function (original) { function (original: (init: ShadowRootInit) => ShadowRoot) {
return function () { return function (this: HTMLElement, option: ShadowRootInit) {
const shadowRoot = original.apply(this, arguments); const shadowRoot = original.call(this, option);
if (this.shadowRoot) if (this.shadowRoot)
manager.addShadowRoot( manager.addShadowRoot(
this.shadowRoot, this.shadowRoot,

View File

@@ -40,6 +40,7 @@ async function getTransparentBlobFor(
// `as any` because: https://github.com/Microsoft/TypeScript/issues/20595 // `as any` because: https://github.com/Microsoft/TypeScript/issues/20595
const worker: ImageBitmapDataURLResponseWorker = self; const worker: ImageBitmapDataURLResponseWorker = self;
// eslint-disable-next-line @typescript-eslint/no-misused-promises
worker.onmessage = async function (e) { worker.onmessage = async function (e) {
if (!('OffscreenCanvas' in globalThis)) if (!('OffscreenCanvas' in globalThis))
return worker.postMessage({ id: e.data.id }); return worker.postMessage({ id: e.data.id });

View File

@@ -20,13 +20,13 @@ export default async function canvasMutation({
if (mutation.setter) { if (mutation.setter) {
// skip some read-only type checks // skip some read-only type checks
// tslint:disable-next-line:no-any ((ctx as unknown) as Record<string, unknown>)[mutation.property] =
(ctx as any)[mutation.property] = mutation.args[0]; mutation.args[0];
return; return;
} }
const original = ctx[ const original = ctx[
mutation.property as Exclude<keyof typeof ctx, 'canvas'> 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, * We have serialized the image source into base64 string during recording,
@@ -37,7 +37,7 @@ export default async function canvasMutation({
mutation.property === 'drawImage' && mutation.property === 'drawImage' &&
typeof mutation.args[0] === 'string' typeof mutation.args[0] === 'string'
) { ) {
const image = imageMap.get(event); imageMap.get(event);
original.apply(ctx, mutation.args); original.apply(ctx, mutation.args);
} else { } else {
const args = await Promise.all( const args = await Promise.all(

View File

@@ -23,6 +23,7 @@ export function variableListFor(
if (!contextMap.has(ctor)) { if (!contextMap.has(ctor)) {
contextMap.set(ctor, []); contextMap.set(ctor, []);
} }
// eslint-disable-next-line @typescript-eslint/no-unsafe-return
return contextMap.get(ctor) as any[]; return contextMap.get(ctor) as any[];
} }
@@ -45,16 +46,21 @@ export function deserializeArg(
if (arg && typeof arg === 'object' && 'rr_type' in arg) { if (arg && typeof arg === 'object' && 'rr_type' in arg) {
if (preload) preload.isUnchanged = false; if (preload) preload.isUnchanged = false;
if (arg.rr_type === 'ImageBitmap' && 'args' in arg) { 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); const args = await deserializeArg(imageMap, ctx, preload)(arg.args);
// eslint-disable-next-line prefer-spread
return await createImageBitmap.apply(null, args); return await createImageBitmap.apply(null, args);
} else if ('index' in arg) { } else if ('index' in arg) {
if (preload || ctx === null) return arg; // we are preloading, ctx is unknown if (preload || ctx === null) return arg; // we are preloading, ctx is unknown
const { rr_type: name, index } = arg; const { rr_type: name, index } = arg;
// eslint-disable-next-line @typescript-eslint/no-unsafe-return
return variableListFor(ctx, name)[index]; return variableListFor(ctx, name)[index];
} else if ('args' in arg) { } else if ('args' in arg) {
const { rr_type: name, args } = arg; const { rr_type: name, args } = arg;
// eslint-disable-next-line @typescript-eslint/no-unsafe-assignment
const ctor = window[name as keyof Window]; const ctor = window[name as keyof Window];
// eslint-disable-next-line @typescript-eslint/no-unsafe-return, @typescript-eslint/no-unsafe-call
return new ctor( return new ctor(
...(await Promise.all( ...(await Promise.all(
args.map(deserializeArg(imageMap, ctx, preload)), args.map(deserializeArg(imageMap, ctx, preload)),
@@ -85,6 +91,7 @@ export function deserializeArg(
const result = await Promise.all( const result = await Promise.all(
arg.map(deserializeArg(imageMap, ctx, preload)), arg.map(deserializeArg(imageMap, ctx, preload)),
); );
// eslint-disable-next-line @typescript-eslint/no-unsafe-return
return result; return result;
} }
return arg; return arg;

View File

@@ -11,8 +11,9 @@ function getContext(
// you might have to do `ctx.flush()` before every webgl canvas event // you might have to do `ctx.flush()` before every webgl canvas event
try { try {
if (type === CanvasContext.WebGL) { if (type === CanvasContext.WebGL) {
return (target.getContext('webgl')! || return (
target.getContext('experimental-webgl')); target.getContext('webgl')! || target.getContext('experimental-webgl')
);
} }
return target.getContext('webgl2')!; return target.getContext('webgl2')!;
} catch (e) { } catch (e) {
@@ -37,11 +38,15 @@ function saveToWebGLVarMap(
ctx: WebGLRenderingContext | WebGL2RenderingContext, ctx: WebGLRenderingContext | WebGL2RenderingContext,
result: any, result: any,
) { ) {
// eslint-disable-next-line @typescript-eslint/no-unsafe-member-access
if (!result?.constructor) return; // probably null or undefined 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; const { name } = result.constructor;
// eslint-disable-next-line @typescript-eslint/no-unsafe-argument
if (!WebGLVariableConstructorsNames.includes(name)) return; // not a WebGL variable if (!WebGLVariableConstructorsNames.includes(name)) return; // not a WebGL variable
// eslint-disable-next-line @typescript-eslint/no-unsafe-argument
const variables = variableListFor(ctx, name); const variables = variableListFor(ctx, name);
if (!variables.includes(result)) variables.push(result); if (!variables.includes(result)) variables.push(result);
} }
@@ -69,13 +74,16 @@ export default async function webglMutation({
if (mutation.setter) { if (mutation.setter) {
// skip some read-only type checks // 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]; (ctx as any)[mutation.property] = mutation.args[0];
return; return;
} }
const original = ctx[ const original = ctx[
mutation.property as Exclude<keyof typeof ctx, 'canvas'> mutation.property as Exclude<keyof typeof ctx, 'canvas'>
] as Function; ] as (
ctx: WebGLRenderingContext | WebGL2RenderingContext,
args: unknown[],
) => void;
const args = await Promise.all( const args = await Promise.all(
mutation.args.map(deserializeArg(imageMap, ctx)), mutation.args.map(deserializeArg(imageMap, ctx)),
@@ -87,16 +95,21 @@ export default async function webglMutation({
const debugMode = false; const debugMode = false;
if (debugMode) { if (debugMode) {
if (mutation.property === 'compileShader') { if (mutation.property === 'compileShader') {
// eslint-disable-next-line @typescript-eslint/no-unsafe-argument
if (!ctx.getShaderParameter(args[0], ctx.COMPILE_STATUS)) if (!ctx.getShaderParameter(args[0], ctx.COMPILE_STATUS))
console.warn( console.warn(
'something went wrong in replay', 'something went wrong in replay',
// eslint-disable-next-line @typescript-eslint/no-unsafe-argument
ctx.getShaderInfoLog(args[0]), ctx.getShaderInfoLog(args[0]),
); );
} else if (mutation.property === 'linkProgram') { } else if (mutation.property === 'linkProgram') {
// eslint-disable-next-line @typescript-eslint/no-unsafe-argument
ctx.validateProgram(args[0]); ctx.validateProgram(args[0]);
// eslint-disable-next-line @typescript-eslint/no-unsafe-argument
if (!ctx.getProgramParameter(args[0], ctx.LINK_STATUS)) if (!ctx.getProgramParameter(args[0], ctx.LINK_STATUS))
console.warn( console.warn(
'something went wrong in replay', 'something went wrong in replay',
// eslint-disable-next-line @typescript-eslint/no-unsafe-argument
ctx.getProgramInfoLog(args[0]), ctx.getProgramInfoLog(args[0]),
); );
} }
@@ -107,6 +120,7 @@ export default async function webglMutation({
webglError, webglError,
'on command:', 'on command:',
mutation.property, mutation.property,
// eslint-disable-next-line @typescript-eslint/no-unsafe-argument
...args, ...args,
); );
} }

View File

@@ -42,7 +42,6 @@ import {
viewportResizeDimension, viewportResizeDimension,
missingNodeMap, missingNodeMap,
addedNodeMutation, addedNodeMutation,
missingNode,
incrementalSnapshotEvent, incrementalSnapshotEvent,
incrementalData, incrementalData,
ReplayerEvents, ReplayerEvents,
@@ -54,7 +53,6 @@ import {
scrollData, scrollData,
inputData, inputData,
canvasMutationData, canvasMutationData,
styleAttributeValue,
styleValueWithPriority, styleValueWithPriority,
mouseMovePos, mouseMovePos,
IWindow, IWindow,
@@ -83,8 +81,7 @@ const SKIP_TIME_THRESHOLD = 10 * 1000;
const SKIP_TIME_INTERVAL = 5 * 1000; const SKIP_TIME_INTERVAL = 5 * 1000;
// https://github.com/rollup/rollup/issues/1267#issuecomment-296395734 // https://github.com/rollup/rollup/issues/1267#issuecomment-296395734
// tslint:disable-next-line const mitt = mittProxy.default || mittProxy;
const mitt = (mittProxy as any).default || mittProxy;
const REPLAY_CONSOLE_PREFIX = '[replayer]'; const REPLAY_CONSOLE_PREFIX = '[replayer]';
@@ -188,7 +185,7 @@ export class Replayer {
canvasMutationData: canvasMutationData, canvasMutationData: canvasMutationData,
target: HTMLCanvasElement, target: HTMLCanvasElement,
) => { ) => {
canvasMutation({ void canvasMutation({
event: canvasEvent, event: canvasEvent,
mutation: canvasMutationData, mutation: canvasMutationData,
target, target,
@@ -340,8 +337,10 @@ export class Replayer {
public setConfig(config: Partial<playerConfig>) { public setConfig(config: Partial<playerConfig>) {
Object.keys(config).forEach((key) => { Object.keys(config).forEach((key) => {
// @ts-ignore const newConfigValue = config[key as keyof playerConfig];
this.config[key] = config[key]; (this.config as Record<keyof playerConfig, typeof newConfigValue>)[
key as keyof playerConfig
] = config[key as keyof playerConfig];
}); });
if (!this.config.skipInactive) { if (!this.config.skipInactive) {
this.backToNormal(); this.backToNormal();
@@ -404,7 +403,7 @@ export class Replayer {
* So the implementation of play at any time offset will always iterate * So the implementation of play at any time offset will always iterate
* all of the events, cast event before the offset synchronously * all of the events, cast event before the offset synchronously
* and cast event after the offset asynchronously with timer. * and cast event after the offset asynchronously with timer.
* @param timeOffset number * @param timeOffset - number
*/ */
public play(timeOffset = 0) { public play(timeOffset = 0) {
if (this.service.state.matches('paused')) { if (this.service.state.matches('paused')) {
@@ -452,7 +451,7 @@ export class Replayer {
if (indicatesTouchDevice(event)) { if (indicatesTouchDevice(event)) {
this.mouse.classList.add('touch-device'); this.mouse.classList.add('touch-device');
} }
Promise.resolve().then(() => void Promise.resolve().then(() =>
this.service.send({ type: 'ADD_EVENT', payload: { event } }), 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'; this.iframe.style.display = 'inherit';
for (const el of [this.mouseTail, this.iframe]) { for (const el of [this.mouseTail, this.iframe]) {
if (!el) { if (!el) {
@@ -520,9 +519,9 @@ export class Replayer {
el.setAttribute('width', String(dimension.width)); el.setAttribute('width', String(dimension.width));
el.setAttribute('height', String(dimension.height)); el.setAttribute('height', String(dimension.height));
} }
} };
private applyEventsSynchronously(events: Array<eventWithTime>) { private applyEventsSynchronously = (events: Array<eventWithTime>) => {
for (const event of events) { for (const event of events) {
switch (event.type) { switch (event.type) {
case EventType.DomContentLoaded: case EventType.DomContentLoaded:
@@ -546,9 +545,9 @@ export class Replayer {
this.mouse.classList.remove('touch-active'); this.mouse.classList.remove('touch-active');
} }
this.touchActive = null; this.touchActive = null;
} };
private getCastFn(event: eventWithTime, isSync = false) { private getCastFn = (event: eventWithTime, isSync = false) => {
let castFn: undefined | (() => void); let castFn: undefined | (() => void);
switch (event.type) { switch (event.type) {
case EventType.DomContentLoaded: case EventType.DomContentLoaded:
@@ -671,7 +670,7 @@ export class Replayer {
this.emitter.emit(ReplayerEvents.EventCast, event); this.emitter.emit(ReplayerEvents.EventCast, event);
}; };
return wrappedCastFn; return wrappedCastFn;
} };
private rebuildFullSnapshot( private rebuildFullSnapshot(
event: fullSnapshotEvent & { timestamp: number }, event: fullSnapshotEvent & { timestamp: number },
@@ -714,7 +713,7 @@ export class Replayer {
this.waitForStylesheetLoad(); this.waitForStylesheetLoad();
} }
if (this.config.UNSAFE_replayCanvas) { 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 * 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 ctx = canvas.getContext('2d');
const imgd = ctx?.createImageData(canvas.width, canvas.height); const imgd = ctx?.createImageData(canvas.width, canvas.height);
let d = imgd?.data; let d = imgd?.data;
d = JSON.parse(data.args[0]); d = JSON.parse(data.args[0]) as Uint8ClampedArray;
ctx?.putImageData(imgd!, 0, 0); ctx?.putImageData(imgd!, 0, 0);
} }
} }
@@ -983,6 +951,7 @@ export class Replayer {
try { try {
this.applyMutation(d, isSync); this.applyMutation(d, isSync);
} catch (error) { } 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); this.warn(`Exception in mutation ${error.message || error}`, d);
} }
break; break;
@@ -1013,7 +982,9 @@ export class Replayer {
}); });
// add a dummy action to keep timer alive // add a dummy action to keep timer alive
this.timer.addAction({ this.timer.addAction({
doAction() {}, doAction() {
//
},
delay: e.delay! - d.positions[0]?.timeOffset, 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 // i.e. media will evntualy start to play when data is loaded
// 'canplay' event fires even when currentTime attribute changes which may lead to // 'canplay' event fires even when currentTime attribute changes which may lead to
// unexpeted behavior // unexpeted behavior
mediaEl.play(); void mediaEl.play();
} }
} catch (error) { } catch (error) {
if (this.config.showWarning) { if (this.config.showWarning) {
console.warn( 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}`, `Failed to replay media interactions: ${error.message || error}`,
); );
} }
@@ -1322,7 +1294,7 @@ export class Replayer {
if (!target) { if (!target) {
return this.debugNodeNotFound(d, d.id); return this.debugNodeNotFound(d, d.id);
} }
canvasMutation({ void canvasMutation({
event: e, event: e,
mutation: d, mutation: d,
target: target as HTMLCanvasElement, target: target as HTMLCanvasElement,
@@ -1337,7 +1309,9 @@ export class Replayer {
try { try {
const fontFace = new FontFace( const fontFace = new FontFace(
d.family, 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, d.descriptors,
); );
this.iframe.contentDocument?.fonts.add(fontFace); this.iframe.contentDocument?.fonts.add(fontFace);
@@ -1711,8 +1685,8 @@ export class Replayer {
/** /**
* Apply the scroll data on real elements. * Apply the scroll data on real elements.
* If the replayer is in sync mode, smooth scroll behavior should be disabled. * If the replayer is in sync mode, smooth scroll behavior should be disabled.
* @param d the scroll data * @param d - the scroll data
* @param isSync whether the replayer is in sync mode(fast-forward) * @param isSync - whether the replayer is in sync mode(fast-forward)
*/ */
private applyScroll(d: scrollData, isSync: boolean) { private applyScroll(d: scrollData, isSync: boolean) {
const target = this.mirror.getNode(d.id); const target = this.mirror.getNode(d.id);

View File

@@ -3,8 +3,8 @@
* Add support of customize target window and document * Add support of customize target window and document
*/ */
/* eslint-disable */
// @ts-nocheck // @ts-nocheck
// tslint:disable
export function polyfill(w: Window = window, d = document) { export function polyfill(w: Window = window, d = document) {
// return if scroll behavior is supported and polyfill is not forced // return if scroll behavior is supported and polyfill is not forced
if ( if (

View File

@@ -19,7 +19,6 @@ export class Timer {
} }
/** /**
* Add an action after the timer starts. * Add an action after the timer starts.
* @param action
*/ */
public addAction(action: actionWithDelay) { public addAction(action: actionWithDelay) {
const index = this.findActionIndex(action); const index = this.findActionIndex(action);
@@ -27,7 +26,6 @@ export class Timer {
} }
/** /**
* Add all actions before the timer starts * Add all actions before the timer starts
* @param actions
*/ */
public addActions(actions: actionWithDelay[]) { public addActions(actions: actionWithDelay[]) {
this.actions = this.actions.concat(actions); this.actions = this.actions.concat(actions);
@@ -37,25 +35,24 @@ export class Timer {
this.timeOffset = 0; this.timeOffset = 0;
let lastTimestamp = performance.now(); let lastTimestamp = performance.now();
const { actions } = this; const { actions } = this;
const self = this; const check = () => {
function check() {
const time = performance.now(); const time = performance.now();
self.timeOffset += (time - lastTimestamp) * self.speed; this.timeOffset += (time - lastTimestamp) * this.speed;
lastTimestamp = time; lastTimestamp = time;
while (actions.length) { while (actions.length) {
const action = actions[0]; const action = actions[0];
if (self.timeOffset >= action.delay) { if (this.timeOffset >= action.delay) {
actions.shift(); actions.shift();
action.doAction(); action.doAction();
} else { } else {
break; break;
} }
} }
if (actions.length > 0 || self.liveMode) { if (actions.length > 0 || this.liveMode) {
self.raf = requestAnimationFrame(check); this.raf = requestAnimationFrame(check);
} }
} };
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) { public setCachedIndex(parentNode: AnyObject, index: number) {
// eslint-disable-next-line @typescript-eslint/no-unsafe-assignment
this.cachedIndexVersion = parentNode.childrenVersion; this.cachedIndexVersion = parentNode.childrenVersion;
this.cachedIndex = index; this.cachedIndex = index;
} }

View File

@@ -27,12 +27,12 @@ export enum EventType {
export type domContentLoadedEvent = { export type domContentLoadedEvent = {
type: EventType.DomContentLoaded; type: EventType.DomContentLoaded;
data: {}; data: unknown;
}; };
export type loadedEvent = { export type loadedEvent = {
type: EventType.Load; type: EventType.Load;
data: {}; data: unknown;
}; };
export type fullSnapshotEvent = { export type fullSnapshotEvent = {
@@ -76,8 +76,6 @@ export type pluginEvent<T = unknown> = {
}; };
}; };
export type styleSheetEvent = {};
export enum IncrementalSource { export enum IncrementalSource {
Mutation, Mutation,
MouseMove, MouseMove,
@@ -218,7 +216,11 @@ export type SamplingStrategy = Partial<{
export type RecordPlugin<TOptions = unknown> = { export type RecordPlugin<TOptions = unknown> = {
name: string; 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; eventProcessor?: <TExtend>(event: eventWithTime) => eventWithTime & TExtend;
options: TOptions; options: TOptions;
}; };
@@ -285,8 +287,12 @@ export type observerParam = {
shadowDomManager: ShadowDomManager; shadowDomManager: ShadowDomManager;
canvasManager: CanvasManager; canvasManager: CanvasManager;
plugins: Array<{ plugins: Array<{
observer: Function; observer: (
callback: Function; cb: (...arg: Array<unknown>) => void,
win: IWindow,
options: unknown,
) => listenerHandler;
callback: (...arg: Array<unknown>) => void;
options: unknown; options: unknown;
}>; }>;
}; };

View File

@@ -57,6 +57,7 @@ if (typeof window !== 'undefined' && window.Proxy && window.Reflect) {
if (prop === 'map') { if (prop === 'map') {
console.error(DEPARTED_MIRROR_ACCESS_WARNING); console.error(DEPARTED_MIRROR_ACCESS_WARNING);
} }
// eslint-disable-next-line @typescript-eslint/no-unsafe-return
return Reflect.get(target, prop, receiver); return Reflect.get(target, prop, receiver);
}, },
}); });
@@ -70,14 +71,14 @@ export function throttle<T>(
) { ) {
let timeout: ReturnType<typeof setTimeout> | null = null; let timeout: ReturnType<typeof setTimeout> | null = null;
let previous = 0; let previous = 0;
return function (arg: T) { return function (...args: T[]) {
const now = Date.now(); const now = Date.now();
if (!previous && options.leading === false) { if (!previous && options.leading === false) {
previous = now; previous = now;
} }
const remaining = wait - (now - previous); const remaining = wait - (now - previous);
// eslint-disable-next-line @typescript-eslint/no-unsafe-assignment, @typescript-eslint/no-this-alias
const context = this; const context = this;
const args = arguments;
if (remaining <= 0 || remaining > wait) { if (remaining <= 0 || remaining > wait) {
if (timeout) { if (timeout) {
clearTimeout(timeout); clearTimeout(timeout);
@@ -129,11 +130,13 @@ export function patch(
source: { [key: string]: any }, source: { [key: string]: any },
name: string, name: string,
// tslint:disable-next-line:no-any // tslint:disable-next-line:no-any
replacement: (...args: any[]) => any, replacement: (...args: unknown[]) => unknown,
): () => void { ): () => void {
try { try {
if (!(name in source)) { if (!(name in source)) {
return () => {}; return () => {
//
};
} }
const original = source[name] as () => unknown; const original = source[name] as () => unknown;
@@ -143,6 +146,7 @@ export function patch(
// otherwise it'll throw "TypeError: Object.defineProperties called on non-object" // otherwise it'll throw "TypeError: Object.defineProperties called on non-object"
// tslint:disable-next-line:strict-type-predicates // tslint:disable-next-line:strict-type-predicates
if (typeof wrapped === 'function') { if (typeof wrapped === 'function') {
// eslint-disable-next-line @typescript-eslint/no-unsafe-assignment
wrapped.prototype = wrapped.prototype || {}; wrapped.prototype = wrapped.prototype || {};
Object.defineProperties(wrapped, { Object.defineProperties(wrapped, {
__rrweb_original__: { __rrweb_original__: {
@@ -158,7 +162,9 @@ export function patch(
source[name] = original; source[name] = original;
}; };
} catch { } catch {
return () => {}; return () => {
//
};
// This can throw if multiple fill happens on a global object like XMLHttpRequest // This can throw if multiple fill happens on a global object like XMLHttpRequest
// Fixes https://github.com/getsentry/sentry-javascript/issues/2043 // Fixes https://github.com/getsentry/sentry-javascript/issues/2043
} }
@@ -249,19 +255,22 @@ export function isTouchEvent(
export function polyfill(win = window) { export function polyfill(win = window) {
if ('NodeList' in win && !win.NodeList.prototype.forEach) { if ('NodeList' in win && !win.NodeList.prototype.forEach) {
// eslint-disable-next-line @typescript-eslint/unbound-method
win.NodeList.prototype.forEach = (Array.prototype win.NodeList.prototype.forEach = (Array.prototype
.forEach as unknown) as NodeList['forEach']; .forEach as unknown) as NodeList['forEach'];
} }
if ('DOMTokenList' in win && !win.DOMTokenList.prototype.forEach) { if ('DOMTokenList' in win && !win.DOMTokenList.prototype.forEach) {
// eslint-disable-next-line @typescript-eslint/unbound-method
win.DOMTokenList.prototype.forEach = (Array.prototype win.DOMTokenList.prototype.forEach = (Array.prototype
.forEach as unknown) as DOMTokenList['forEach']; .forEach as unknown) as DOMTokenList['forEach'];
} }
// https://github.com/Financial-Times/polyfill-service/pull/183 // https://github.com/Financial-Times/polyfill-service/pull/183
if (!Node.prototype.contains) { if (!Node.prototype.contains) {
Node.prototype.contains = function contains(node) { Node.prototype.contains = (...args: unknown[]) => {
if (!(0 in arguments)) { let node = args[0] as Node | null;
if (!(0 in args)) {
throw new TypeError('1 argument is required'); throw new TypeError('1 argument is required');
} }
@@ -269,7 +278,6 @@ export function polyfill(win = window) {
if (this === node) { if (this === node) {
return true; return true;
} }
// tslint:disable-next-line: no-conditional-assignment
} while ((node = node && node.parentNode)); } while ((node = node && node.parentNode));
return false; return false;
@@ -426,8 +434,8 @@ export function getPositionsAndIndex(nestedIndex: number[]) {
/** /**
* Returns the latest mutation in the queue for each node. * Returns the latest mutation in the queue for each node.
* @param {textMutation[]} mutations The text mutations to filter. * @param mutations - mutations The text mutations to filter.
* @returns {textMutation[]} The filtered text mutations. * @returns The filtered text mutations.
*/ */
export function uniqueTextMutations(mutations: textMutation[]): textMutation[] { export function uniqueTextMutations(mutations: textMutation[]): textMutation[] {
const idSet = new Set<number>(); const idSet = new Set<number>();

View File

@@ -12,7 +12,12 @@ import {
generateRecordSnippet, generateRecordSnippet,
ISuite, ISuite,
} from './utils'; } from './utils';
import { recordOptions, eventWithTime, EventType } from '../src/types'; import {
recordOptions,
eventWithTime,
EventType,
RecordPlugin,
} from '../src/types';
import { visitSnapshot, NodeType } from 'rrweb-snapshot'; import { visitSnapshot, NodeType } from 'rrweb-snapshot';
describe('record integration tests', function (this: ISuite) { 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(); const page: puppeteer.Page = await browser.newPage();
await page.goto('about:blank'); await page.goto('about:blank');
await page.setContent( await page.setContent(
getHtml.call(this, 'log.html', { getHtml('log.html', {
plugins: '[rrwebConsoleRecord.getRecordConsolePlugin()]', plugins: ('[rrwebConsoleRecord.getRecordConsolePlugin()]' as unknown) as RecordPlugin<unknown>[],
}), }),
); );

View File

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

View File

@@ -15,7 +15,6 @@ export declare type LogData = {
trace: string[]; trace: string[];
payload: 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 = { export declare type Logger = {
assert?: typeof console.assert; assert?: typeof console.assert;
clear?: typeof console.clear; clear?: typeof console.clear;
@@ -37,6 +36,7 @@ export declare type Logger = {
trace?: typeof console.trace; trace?: typeof console.trace;
warn?: typeof console.warn; warn?: typeof console.warn;
}; };
export declare type LogLevel = keyof Logger;
export declare const PLUGIN_NAME = "rrweb/console@1"; export declare const PLUGIN_NAME = "rrweb/console@1";
export declare const getRecordConsolePlugin: (options?: LogRecordOptions) => RecordPlugin; export declare const getRecordConsolePlugin: (options?: LogRecordOptions) => RecordPlugin;
export {}; export {};

View File

@@ -1,2 +1,2 @@
import type { StringifyOptions } from './index'; 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'; import type { IWindow, CanvasArg } from '../../../types';
export declare function variableListFor(ctx: RenderingContext, ctor: string): any[]; export declare function variableListFor(ctx: RenderingContext, ctor: string): unknown[];
export declare const saveWebGLVar: (value: any, win: IWindow, ctx: RenderingContext) => number | void; export declare const saveWebGLVar: (value: unknown, win: IWindow, ctx: RenderingContext) => number | void;
export declare function serializeArg(value: any, win: IWindow, ctx: RenderingContext): CanvasArg; export declare function serializeArg(value: unknown, win: IWindow, ctx: RenderingContext): CanvasArg;
export declare const serializeArgs: (args: Array<any>, win: IWindow, ctx: RenderingContext) => CanvasArg[]; export declare const serializeArgs: (args: Array<unknown>, 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 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 attachDocumentToIframe;
private collectIframeAndAttachDocument; private collectIframeAndAttachDocument;
private waitForStylesheetLoad; private waitForStylesheetLoad;
private hasImageArg;
private getImageArgs;
private preloadAllImages; private preloadAllImages;
private preloadImages; private preloadImages;
private deserializeAndPreloadCanvasEvents; private deserializeAndPreloadCanvasEvents;

View File

@@ -17,11 +17,11 @@ export declare enum EventType {
} }
export declare type domContentLoadedEvent = { export declare type domContentLoadedEvent = {
type: EventType.DomContentLoaded; type: EventType.DomContentLoaded;
data: {}; data: unknown;
}; };
export declare type loadedEvent = { export declare type loadedEvent = {
type: EventType.Load; type: EventType.Load;
data: {}; data: unknown;
}; };
export declare type fullSnapshotEvent = { export declare type fullSnapshotEvent = {
type: EventType.FullSnapshot; type: EventType.FullSnapshot;
@@ -59,7 +59,6 @@ export declare type pluginEvent<T = unknown> = {
payload: T; payload: T;
}; };
}; };
export declare type styleSheetEvent = {};
export declare enum IncrementalSource { export declare enum IncrementalSource {
Mutation = 0, Mutation = 0,
MouseMove = 1, MouseMove = 1,
@@ -134,7 +133,7 @@ export declare type SamplingStrategy = Partial<{
}>; }>;
export declare type RecordPlugin<TOptions = unknown> = { export declare type RecordPlugin<TOptions = unknown> = {
name: string; 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; eventProcessor?: <TExtend>(event: eventWithTime) => eventWithTime & TExtend;
options: TOptions; options: TOptions;
}; };
@@ -198,8 +197,8 @@ export declare type observerParam = {
shadowDomManager: ShadowDomManager; shadowDomManager: ShadowDomManager;
canvasManager: CanvasManager; canvasManager: CanvasManager;
plugins: Array<{ plugins: Array<{
observer: Function; observer: (cb: (...arg: Array<unknown>) => void, win: IWindow, options: unknown) => listenerHandler;
callback: Function; callback: (...arg: Array<unknown>) => void;
options: unknown; options: unknown;
}>; }>;
}; };

View File

@@ -3,11 +3,11 @@ import type { IMirror, Mirror } from 'rrweb-snapshot';
import type { RRNode, RRIFrameElement } from 'rrdom'; import type { RRNode, RRIFrameElement } from 'rrdom';
export declare function on(type: string, fn: EventListenerOrEventListenerObject, target?: Document | IWindow): listenerHandler; export declare function on(type: string, fn: EventListenerOrEventListenerObject, target?: Document | IWindow): listenerHandler;
export declare let _mirror: DeprecatedMirror; 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 hookSetter<T>(target: T, key: string | number | symbol, d: PropertyDescriptor, isRevoked?: boolean, win?: Window & typeof globalThis): hookResetter;
export declare function patch(source: { export declare function patch(source: {
[key: string]: any; [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 getWindowHeight(): number;
export declare function getWindowWidth(): number; export declare function getWindowWidth(): number;
export declare function isBlocked(node: Node | null, blockClass: blockClass, checkAncestors: boolean): boolean; 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" minipass "^3.0.0"
yallist "^4.0.0" yallist "^4.0.0"
mitt@^1.1.3: mitt@^3.0.0:
version "1.2.0" version "3.0.0"
resolved "https://registry.npmjs.org/mitt/-/mitt-1.2.0.tgz" resolved "https://registry.yarnpkg.com/mitt/-/mitt-3.0.0.tgz#69ef9bd5c80ff6f57473e8d89326d01c414be0bd"
integrity sha512-r6lj77KlwqLhIUku9UWYes7KJtsczvolZkzp8hbaDPPaE24OmWl5s539Mytlj22siEQKosZ26qCBgda2PKwoJw== integrity sha512-7dX2/10ITVyqh4aOSVI9gdape+t9l2/8QxHrFmUXu4EEUpdlxl6RudZUPZoc+zuY2hk1j7XxVroIVIan/pD/SQ==
mkdirp-classic@^0.5.2: mkdirp-classic@^0.5.2:
version "0.5.3" version "0.5.3"