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