From bf4ff745736b1402c6b5a9a7d5664069f0d2de57 Mon Sep 17 00:00:00 2001 From: Yun Feng Date: Sat, 25 Jun 2022 20:31:38 +1000 Subject: [PATCH 01/12] 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 02/12] 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 03/12] 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 04/12] 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 05/12] 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); From cb672d0bcaa2f41afb5c4261e3a46c5f66c683d4 Mon Sep 17 00:00:00 2001 From: Yun Feng Date: Fri, 8 Jul 2022 02:42:42 +1000 Subject: [PATCH 06/12] CI: add a github action to check ESLINT status --- .github/workflows/eslint.yml | 33 +++++++++++++++++++++++++++++++++ package.json | 3 ++- 2 files changed, 35 insertions(+), 1 deletion(-) create mode 100644 .github/workflows/eslint.yml diff --git a/.github/workflows/eslint.yml b/.github/workflows/eslint.yml new file mode 100644 index 0000000000..d1216b225f --- /dev/null +++ b/.github/workflows/eslint.yml @@ -0,0 +1,33 @@ +name: Eslint Check + +on: [pull_request, push] + +jobs: + node_test: + runs-on: ubuntu-latest + + steps: + - uses: actions/checkout@v3 + - name: Setup Node + uses: actions/setup-node@v3 + with: + node-version: 16 + cache: 'yarn' + - name: Install Dependencies + run: yarn + - name: Test Code Linting + run: yarn lerna run lint + - name: Save Code Linting Report JSON + run: yarn lint:report + # Continue to the next step even if this fails + continue-on-error: true + - name: Annotate Code Linting Results + uses: ataylorme/eslint-annotate-action@v2 + with: + repo-token: '${{ secrets.GITHUB_TOKEN }}' + report-json: 'eslint_report.json' + - name: Upload ESLint report + uses: actions/upload-artifact@v2 + with: + name: eslint_report.json + path: eslint_report.json diff --git a/package.json b/package.json index 18d5cae5cf..9fbd3b7ca6 100644 --- a/package.json +++ b/package.json @@ -36,7 +36,8 @@ "test:watch": "yarn turbo run test:watch", "dev": "yarn turbo run dev", "repl": "cd packages/rrweb && npm run repl", - "lint": "yarn run concurrently --success=all -r -m=1 'yarn run markdownlint docs' 'yarn eslint packages/*/src --ext .ts,.tsx,.js,.jsx,.svelte'" + "lint": "yarn run concurrently --success=all -r -m=1 'yarn run markdownlint docs' 'yarn eslint packages/*/src --ext .ts,.tsx,.js,.jsx,.svelte'", + "lint:report": "yarn eslint --output-file eslint_report.json --format json packages/*/src --ext .ts,.tsx,.js,.jsx" }, "resolutions": { "**/jsdom/cssom": "https://registry.npmjs.org/rrweb-cssom/-/rrweb-cssom-0.6.0.tgz" From cd05fac67aaa65284ff090cb810e4020eb0a85bc Mon Sep 17 00:00:00 2001 From: Yun Feng Date: Fri, 8 Jul 2022 03:12:14 +1000 Subject: [PATCH 07/12] CI: update github action --- .github/workflows/eslint.yml | 2 ++ 1 file changed, 2 insertions(+) diff --git a/.github/workflows/eslint.yml b/.github/workflows/eslint.yml index d1216b225f..b1a506b257 100644 --- a/.github/workflows/eslint.yml +++ b/.github/workflows/eslint.yml @@ -15,6 +15,8 @@ jobs: cache: 'yarn' - name: Install Dependencies run: yarn + - name: Build Packages + run: yarn build:all - name: Test Code Linting run: yarn lerna run lint - name: Save Code Linting Report JSON From 6a4354ed6fe8c491f90549e00d768470d21297ff Mon Sep 17 00:00:00 2001 From: Yun Feng Date: Fri, 8 Jul 2022 03:30:28 +1000 Subject: [PATCH 08/12] build: update travis CI and github action --- .github/workflows/eslint.yml | 6 +++--- .travis.yml | 6 +++--- turbo.json | 16 ++++++---------- 3 files changed, 12 insertions(+), 16 deletions(-) diff --git a/.github/workflows/eslint.yml b/.github/workflows/eslint.yml index b1a506b257..eb9a2886b3 100644 --- a/.github/workflows/eslint.yml +++ b/.github/workflows/eslint.yml @@ -1,9 +1,9 @@ name: Eslint Check -on: [pull_request, push] +on: [pull_request] jobs: - node_test: + ESLint Check and Report Upload: runs-on: ubuntu-latest steps: @@ -18,7 +18,7 @@ jobs: - name: Build Packages run: yarn build:all - name: Test Code Linting - run: yarn lerna run lint + run: yarn turbo run lint - name: Save Code Linting Report JSON run: yarn lint:report # Continue to the next step even if this fails diff --git a/.travis.yml b/.travis.yml index 9ecba610da..b122c43a8f 100644 --- a/.travis.yml +++ b/.travis.yml @@ -11,6 +11,6 @@ install: - yarn script: - - yarn lerna run prepublish - - yarn lerna run check-types - - xvfb-run --server-args="-screen 0 1920x1080x24" yarn lerna run test + - yarn build:all + - yarn turbo run check-types + - xvfb-run --server-args="-screen 0 1920x1080x24" yarn test diff --git a/turbo.json b/turbo.json index 5d1a58238b..cf58a139e7 100644 --- a/turbo.json +++ b/turbo.json @@ -3,17 +3,13 @@ "baseBranch": "origin/master", "pipeline": { "prepublish": { - "dependsOn": [ - "^prepublish" - ], - "outputs": [ - "lib/**", - "es/**", - "dist/**" - ] + "dependsOn": ["^prepublish"], + "outputs": ["lib/**", "es/**", "dist/**"] }, "test": {}, "test:watch": {}, - "dev": {} + "dev": {}, + "lint": {}, + "check-types": {} } -} \ No newline at end of file +} From 37a98811a8ec157115ac2de736b1fd1023ef1345 Mon Sep 17 00:00:00 2001 From: Yun Feng Date: Fri, 8 Jul 2022 03:45:31 +1000 Subject: [PATCH 09/12] CI: update github action --- .github/workflows/eslint.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/eslint.yml b/.github/workflows/eslint.yml index eb9a2886b3..f9216cc922 100644 --- a/.github/workflows/eslint.yml +++ b/.github/workflows/eslint.yml @@ -3,7 +3,7 @@ name: Eslint Check on: [pull_request] jobs: - ESLint Check and Report Upload: + ESLint-Check-and-Report-Upload: runs-on: ubuntu-latest steps: From 7065de6855608bf62584f3811457a4a52cebf3a7 Mon Sep 17 00:00:00 2001 From: Yun Feng Date: Fri, 8 Jul 2022 03:51:39 +1000 Subject: [PATCH 10/12] CI: update job name --- .github/workflows/eslint.yml | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/.github/workflows/eslint.yml b/.github/workflows/eslint.yml index f9216cc922..916763871a 100644 --- a/.github/workflows/eslint.yml +++ b/.github/workflows/eslint.yml @@ -3,8 +3,9 @@ name: Eslint Check on: [pull_request] jobs: - ESLint-Check-and-Report-Upload: + eslint_check_upload: runs-on: ubuntu-latest + name: ESLint Check and Report Upload steps: - uses: actions/checkout@v3 From 6cb158167b3b90dfb96c6f45b87e5f57da1e2e78 Mon Sep 17 00:00:00 2001 From: Yun Feng Date: Fri, 8 Jul 2022 03:59:24 +1000 Subject: [PATCH 11/12] CI: restore test command from turbo to lerna --- .travis.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.travis.yml b/.travis.yml index b122c43a8f..89d0ef2be3 100644 --- a/.travis.yml +++ b/.travis.yml @@ -13,4 +13,4 @@ install: script: - yarn build:all - yarn turbo run check-types - - xvfb-run --server-args="-screen 0 1920x1080x24" yarn test + - xvfb-run --server-args="-screen 0 1920x1080x24" yarn lerna run test From d598b51a11d377c38b3ea23e0715e4a69a44cdf2 Mon Sep 17 00:00:00 2001 From: Yun Feng Date: Sun, 10 Jul 2022 17:58:41 +1000 Subject: [PATCH 12/12] Merge branch master into eslint-action --- packages/rrdom-nodejs/package.json | 6 +- packages/rrdom/package.json | 6 +- packages/rrweb-player/package.json | 6 +- packages/rrweb-snapshot/package.json | 4 +- packages/rrweb/package.json | 6 +- yarn.lock | 86 ++++++++++++++++++---------- 6 files changed, 69 insertions(+), 45 deletions(-) diff --git a/packages/rrdom-nodejs/package.json b/packages/rrdom-nodejs/package.json index 9c9c890349..b4d9d0b556 100644 --- a/packages/rrdom-nodejs/package.json +++ b/packages/rrdom-nodejs/package.json @@ -1,6 +1,6 @@ { "name": "rrdom-nodejs", - "version": "0.1.2", + "version": "0.1.3", "scripts": { "dev": "rollup -c -w", "bundle": "rollup --config", @@ -49,7 +49,7 @@ "cssom": "^0.5.0", "cssstyle": "^2.3.0", "nwsapi": "^2.2.0", - "rrweb-snapshot": "^1.1.14", - "rrdom": "^0.1.2" + "rrdom": "^0.1.3", + "rrweb-snapshot": "^2.0.0-alpha.0" } } diff --git a/packages/rrdom/package.json b/packages/rrdom/package.json index c80ee641b5..234b1c28fc 100644 --- a/packages/rrdom/package.json +++ b/packages/rrdom/package.json @@ -1,6 +1,6 @@ { "name": "rrdom", - "version": "0.1.2", + "version": "0.1.3", "homepage": "https://github.com/rrweb-io/rrweb/tree/main/packages/rrdom#readme", "license": "MIT", "main": "lib/rrdom.js", @@ -32,9 +32,9 @@ "devDependencies": { "@rollup/plugin-commonjs": "^20.0.0", "@types/jest": "^27.4.1", + "@types/puppeteer": "^5.4.4", "@typescript-eslint/eslint-plugin": "^5.23.0", "@typescript-eslint/parser": "^5.23.0", - "@types/puppeteer": "^5.4.4", "eslint": "^8.15.0", "jest": "^27.5.1", "puppeteer": "^9.1.1", @@ -46,6 +46,6 @@ "typescript": "^4.7.3" }, "dependencies": { - "rrweb-snapshot": "^1.1.14" + "rrweb-snapshot": "^2.0.0-alpha.0" } } diff --git a/packages/rrweb-player/package.json b/packages/rrweb-player/package.json index fb94f95d53..1ef553b96a 100644 --- a/packages/rrweb-player/package.json +++ b/packages/rrweb-player/package.json @@ -1,10 +1,9 @@ { "name": "rrweb-player", - "version": "0.7.14", + "version": "1.0.0-alpha.0", "devDependencies": { "@rollup/plugin-commonjs": "^22.0.0", "@rollup/plugin-node-resolve": "^13.2.1", - "rollup-plugin-typescript2": "^0.31.2", "@types/offscreencanvas": "^2019.6.4", "eslint-config-google": "^0.14.0", "eslint-plugin-svelte3": "^4.0.0", @@ -14,6 +13,7 @@ "rollup-plugin-livereload": "^2.0.0", "rollup-plugin-svelte": "^7.1.0", "rollup-plugin-terser": "^7.0.2", + "rollup-plugin-typescript2": "^0.31.2", "rollup-plugin-web-worker-loader": "^1.6.1", "sirv-cli": "^0.4.4", "svelte": "^3.2.0", @@ -24,7 +24,7 @@ }, "dependencies": { "@tsconfig/svelte": "^1.0.0", - "rrweb": "^1.1.3" + "rrweb": "^2.0.0-alpha.0" }, "scripts": { "build": "rollup -c", diff --git a/packages/rrweb-snapshot/package.json b/packages/rrweb-snapshot/package.json index 4da6741fea..3e20883af0 100644 --- a/packages/rrweb-snapshot/package.json +++ b/packages/rrweb-snapshot/package.json @@ -1,6 +1,6 @@ { "name": "rrweb-snapshot", - "version": "1.1.14", + "version": "2.0.0-alpha.0", "description": "rrweb's component to take a snapshot of DOM, aka DOM serializer", "scripts": { "prepare": "npm run prepack", @@ -40,7 +40,6 @@ }, "homepage": "https://github.com/rrweb-io/rrweb/tree/master/packages/rrweb-snapshot#readme", "devDependencies": { - "rollup-plugin-typescript2": "^0.31.2", "@types/chai": "^4.1.4", "@types/jest": "^27.0.2", "@types/jsdom": "^16.2.4", @@ -53,6 +52,7 @@ "puppeteer": "^1.15.0", "rollup": "^2.45.2", "rollup-plugin-terser": "^7.0.2", + "rollup-plugin-typescript2": "^0.31.2", "ts-jest": "^27.0.5", "ts-node": "^7.0.1", "tslib": "^1.9.3", diff --git a/packages/rrweb/package.json b/packages/rrweb/package.json index 322191dd29..98e4547838 100644 --- a/packages/rrweb/package.json +++ b/packages/rrweb/package.json @@ -1,6 +1,6 @@ { "name": "rrweb", - "version": "1.1.3", + "version": "2.0.0-alpha.0", "description": "record and replay the web", "scripts": { "prepare": "npm run prepack", @@ -79,7 +79,7 @@ "base64-arraybuffer": "^1.0.1", "fflate": "^0.4.4", "mitt": "^3.0.0", - "rrdom": "^0.1.2", - "rrweb-snapshot": "^1.1.14" + "rrdom": "^0.1.3", + "rrweb-snapshot": "^2.0.0-alpha.0" } } diff --git a/yarn.lock b/yarn.lock index e4bb7ec301..9332085dcd 100644 --- a/yarn.lock +++ b/yarn.lock @@ -3983,8 +3983,8 @@ decimal.js@^10.2.1: decode-uri-component@^0.2.0: version "0.2.0" - resolved "https://registry.npmjs.org/decode-uri-component/-/decode-uri-component-0.2.0.tgz" - integrity sha1-6zkTMzRYd1y4TNGh+uBiEGu4dUU= + resolved "https://registry.yarnpkg.com/decode-uri-component/-/decode-uri-component-0.2.0.tgz#eb3913333458775cb84cd1a1fae062106bb87545" + integrity sha512-hjf+xovcEn31w/EUYdTXQh/8smFL/dzYjohQGEIgjyNavaJfBY2p5F527Bo1VPATxv0VYTUC2bOcXvqFwk78Og== dedent@^0.7.0: version "0.7.0" @@ -4958,8 +4958,8 @@ fill-range@^7.0.1: filter-obj@^1.1.0: version "1.1.0" - resolved "https://registry.npmjs.org/filter-obj/-/filter-obj-1.1.0.tgz" - integrity sha1-mzERErxsYSehbgFsbF1/GeCAXFs= + resolved "https://registry.yarnpkg.com/filter-obj/-/filter-obj-1.1.0.tgz#9b311112bc6c6127a16e016c6c5d7f19e0805c5b" + integrity sha512-8rXg1ZnX7xzy2NGDVkBVaAy+lSlPNwad13BtgSlLuxfIslyt5Vg64U7tFcCt4WS1R0hvtnQybT/IyCkGZ3DpXQ== finalhandler@~1.1.2: version "1.1.2" @@ -5121,7 +5121,7 @@ fsevents@^2.3.2, fsevents@~2.3.2: function-bind@^1.1.1: version "1.1.1" - resolved "https://registry.npmjs.org/function-bind/-/function-bind-1.1.1.tgz" + resolved "https://registry.yarnpkg.com/function-bind/-/function-bind-1.1.1.tgz#a56899d3ea3c9bab874bb9773b7c5ede92f4895d" integrity sha512-yIovAzMX49sF8Yl58fSCWJ5svSLuaibPxXQJFLmBObTuCr0Mf1KiPopGM9NiFjiYBCbfaa2Fh6breQ6ANVTI0A== functional-red-black-tree@^1.0.1: @@ -5160,7 +5160,16 @@ get-caller-file@^2.0.5: resolved "https://registry.npmjs.org/get-caller-file/-/get-caller-file-2.0.5.tgz" integrity sha512-DyFP3BM/3YHTQOCUL/w0OZHR0lpKeGrxotcHWcqNEdnltqFwXVfhEBQ94eIo34AfQpo0rGki4cyIiftY06h2Fg== -get-intrinsic@^1.0.2, get-intrinsic@^1.1.0, get-intrinsic@^1.1.1: +get-intrinsic@^1.0.2: + version "1.1.2" + resolved "https://registry.yarnpkg.com/get-intrinsic/-/get-intrinsic-1.1.2.tgz#336975123e05ad0b7ba41f152ee4aadbea6cf598" + integrity sha512-Jfm3OyCxHh9DJyc28qGk+JmfkpO41A4XkneDSujN9MDXrm4oDKdHvndhZ2dN94+ERNfkYJWDclW6k2L/ZGHjXA== + dependencies: + function-bind "^1.1.1" + has "^1.0.3" + has-symbols "^1.0.3" + +get-intrinsic@^1.1.0, get-intrinsic@^1.1.1: version "1.1.1" resolved "https://registry.npmjs.org/get-intrinsic/-/get-intrinsic-1.1.1.tgz" integrity sha512-kWZrnVM42QCiEA2Ig1bG8zjoIMOgxWwYCEeNdwY6Tv/cOSeGpcoX4pXHfKUxNKVoArnrEr2e9srnAxxGIraS9Q== @@ -5467,6 +5476,11 @@ has-symbols@^1.0.1, has-symbols@^1.0.2: resolved "https://registry.npmjs.org/has-symbols/-/has-symbols-1.0.2.tgz" integrity sha512-chXa79rL/UC2KlX17jo3vRGz0azaWEx5tGqZg5pO3NUyEJVB17dMruQlzCCOfUvElghKcm5194+BCRvi2Rv/Gw== +has-symbols@^1.0.3: + version "1.0.3" + resolved "https://registry.yarnpkg.com/has-symbols/-/has-symbols-1.0.3.tgz#bb7b2c4349251dce87b125f7bdf874aa7c8b39f8" + integrity sha512-l3LCuF6MgDNwTDKkdYGEihYjt5pRPbEg46rtlmnSPlUbgmB8LOIrKJbYYFBSbnPaJexMKtiPO8hmeRjRz2Td+A== + has-tostringtag@^1.0.0: version "1.0.0" resolved "https://registry.npmjs.org/has-tostringtag/-/has-tostringtag-1.0.0.tgz" @@ -5481,7 +5495,7 @@ has-unicode@^2.0.0, has-unicode@^2.0.1: has@^1.0.0, has@^1.0.3: version "1.0.3" - resolved "https://registry.npmjs.org/has/-/has-1.0.3.tgz" + resolved "https://registry.yarnpkg.com/has/-/has-1.0.3.tgz#722d7cbfc1f6aa8241f16dd814e011e1f41e8796" integrity sha512-f2dvO0VU6Oej7RkWJGrehjbzMAjFp5/VKPp5tTpWIV4JHHZK1/BxbFRtf/siA2SWTe09caDmVtYYzWEIbBS4zw== dependencies: function-bind "^1.1.1" @@ -6107,11 +6121,11 @@ is-shared-array-buffer@^1.0.1: integrity sha512-IU0NmyknYZN0rChcKhRO1X8LYz5Isj/Fsqh8NJOSf+N/hCOTwy29F32Ik7a+QszE63IdvmwdTPDd6cZ5pg4cwA== is-ssh@^1.3.0: - version "1.3.3" - resolved "https://registry.npmjs.org/is-ssh/-/is-ssh-1.3.3.tgz" - integrity sha512-NKzJmQzJfEEma3w5cJNcUMxoXfDjz0Zj0eyCalHn2E6VOwlzjZo0yuO2fcBSf8zhFuVCL/82/r5gRcoi6aEPVQ== + version "1.4.0" + resolved "https://registry.yarnpkg.com/is-ssh/-/is-ssh-1.4.0.tgz#4f8220601d2839d8fa624b3106f8e8884f01b8b2" + integrity sha512-x7+VxdxOdlV3CYpjvRLBv5Lo9OJerlYanjwFrPR9fuGPjCiNiCzFgAWpiLAohSbsnH4ZAys3SBh+hq5rJosxUQ== dependencies: - protocols "^1.1.0" + protocols "^2.0.1" is-stream@^2.0.0: version "2.0.1" @@ -8152,7 +8166,7 @@ normalize-url@^3.0.0: normalize-url@^6.1.0: version "6.1.0" - resolved "https://registry.npmjs.org/normalize-url/-/normalize-url-6.1.0.tgz" + resolved "https://registry.yarnpkg.com/normalize-url/-/normalize-url-6.1.0.tgz#40d0885b535deffe3f3147bec877d05fe4c5668a" integrity sha512-DlL+XwOy3NxAQ8xuC0okPgK46iuVNAK01YN7RueYBqqFeGsBjV9XmCAzAdgt+667bCl5kPh9EqKKDwnaPG1I7A== npm-bundled@^1.1.1: @@ -8294,11 +8308,16 @@ object-assign@^4.0.1, object-assign@^4.1.0: resolved "https://registry.npmjs.org/object-assign/-/object-assign-4.1.1.tgz" integrity sha1-IQmtx5ZYh8/AXLvUQsrIv7s2CGM= -object-inspect@^1.10.3, object-inspect@^1.11.0, object-inspect@^1.9.0: +object-inspect@^1.10.3, object-inspect@^1.11.0: version "1.11.0" resolved "https://registry.npmjs.org/object-inspect/-/object-inspect-1.11.0.tgz" integrity sha512-jp7ikS6Sd3GxQfZJPyH3cjcbJF6GZPClgdV+EFygjFLQ5FmW/dRUnTd9PQ9k0JhoNDabWFbpF1yCdSWCC6gexg== +object-inspect@^1.9.0: + version "1.12.2" + resolved "https://registry.yarnpkg.com/object-inspect/-/object-inspect-1.12.2.tgz#c0641f26394532f28ab8d796ab954e43c009a8ea" + integrity sha512-z+cPxW0QGUp0mcqcsgQyLVRDoXFQbXOwBaqyF7VIgI4TWNQsDHrBpUQslRmIfAoYWdYzs6UlKJtB2XJpTaNSpQ== + object-keys@^1.0.12, object-keys@^1.1.1: version "1.1.1" resolved "https://registry.npmjs.org/object-keys/-/object-keys-1.1.1.tgz" @@ -8585,10 +8604,10 @@ parse-json@^5.0.0, parse-json@^5.2.0: json-parse-even-better-errors "^2.3.0" lines-and-columns "^1.1.6" -parse-path@^4.0.0: - version "4.0.3" - resolved "https://registry.npmjs.org/parse-path/-/parse-path-4.0.3.tgz" - integrity sha512-9Cepbp2asKnWTJ9x2kpw6Fe8y9JDbqwahGCTvklzd/cEq5C5JC59x2Xb0Kx+x0QZ8bvNquGO8/BWP0cwBHzSAA== +parse-path@^4.0.4: + version "4.0.4" + resolved "https://registry.yarnpkg.com/parse-path/-/parse-path-4.0.4.tgz#4bf424e6b743fb080831f03b536af9fc43f0ffea" + integrity sha512-Z2lWUis7jlmXC1jeOG9giRO2+FsuyNipeQ43HAjqAZjwSe3SEf+q/84FGPHoso3kyntbxa4c4i77t3m6fGf8cw== dependencies: is-ssh "^1.3.0" protocols "^1.4.0" @@ -8596,13 +8615,13 @@ parse-path@^4.0.0: query-string "^6.13.8" parse-url@^6.0.0: - version "6.0.0" - resolved "https://registry.npmjs.org/parse-url/-/parse-url-6.0.0.tgz" - integrity sha512-cYyojeX7yIIwuJzledIHeLUBVJ6COVLeT4eF+2P6aKVzwvgKQPndCBv3+yQ7pcWjqToYwaligxzSYNNmGoMAvw== + version "6.0.2" + resolved "https://registry.yarnpkg.com/parse-url/-/parse-url-6.0.2.tgz#4a30b057bfc452af64512dfb1a7755c103db3ea1" + integrity sha512-uCSjOvD3T+6B/sPWhR+QowAZcU/o4bjPrVBQBGFxcDF6J6FraCGIaDBsdoQawiaaAVdHvtqBe3w3vKlfBKySOQ== dependencies: is-ssh "^1.3.0" normalize-url "^6.1.0" - parse-path "^4.0.0" + parse-path "^4.0.4" protocols "^1.4.0" parse5-htmlparser2-tree-adapter@^6.0.1: @@ -9252,11 +9271,16 @@ proto-list@~1.2.1: resolved "https://registry.npmjs.org/proto-list/-/proto-list-1.2.4.tgz" integrity sha1-IS1b/hMYMGpCD2QCuOJv85ZHqEk= -protocols@^1.1.0, protocols@^1.4.0: +protocols@^1.4.0: version "1.4.8" - resolved "https://registry.npmjs.org/protocols/-/protocols-1.4.8.tgz" + resolved "https://registry.yarnpkg.com/protocols/-/protocols-1.4.8.tgz#48eea2d8f58d9644a4a32caae5d5db290a075ce8" integrity sha512-IgjKyaUSjsROSO8/D49Ab7hP8mJgTYcqApOqdPhLoPxAplXmkp+zRvsrSQjFn5by0rhm4VH0GAUELIPpx7B1yg== +protocols@^2.0.1: + version "2.0.1" + resolved "https://registry.yarnpkg.com/protocols/-/protocols-2.0.1.tgz#8f155da3fc0f32644e83c5782c8e8212ccf70a86" + integrity sha512-/XJ368cyBJ7fzLMwLKv1e4vLxOju2MNAIokcr7meSaNcVbWz/CPcW22cP04mwxOErdA5mwjA8Q6w/cdAQxVn7Q== + proxy-addr@~2.0.5: version "2.0.7" resolved "https://registry.npmjs.org/proxy-addr/-/proxy-addr-2.0.7.tgz" @@ -9331,9 +9355,9 @@ qs@6.7.0: integrity sha512-VCdBRNFTX1fyE7Nb6FYoURo/SPe62QCaAyzJvUjwRaIsc+NePBEniHlvxFmmX56+HZphIGtV0XeCirBtpDrTyQ== qs@^6.9.4: - version "6.10.1" - resolved "https://registry.npmjs.org/qs/-/qs-6.10.1.tgz" - integrity sha512-M528Hph6wsSVOBiYUnGf+K/7w0hNshs/duGsNXPUCLH5XAqjEtiPGwNONLV0tBH8NoGb0mvD5JubnUTrujKDTg== + version "6.11.0" + resolved "https://registry.yarnpkg.com/qs/-/qs-6.11.0.tgz#fd0d963446f7a65e1367e01abd85429453f0c37a" + integrity sha512-MvjoMCJwEarSbUYk5O+nmoSzSutSsTwF85zcHPQ9OrlFoZOYIjaqBAJIqIXjptyD5vThxGq52Xu/MaJzRkIk4Q== dependencies: side-channel "^1.0.4" @@ -9344,7 +9368,7 @@ qs@~6.5.2: query-string@^6.13.8: version "6.14.1" - resolved "https://registry.npmjs.org/query-string/-/query-string-6.14.1.tgz" + resolved "https://registry.yarnpkg.com/query-string/-/query-string-6.14.1.tgz#7ac2dca46da7f309449ba0f86b1fd28255b0c86a" integrity sha512-XDxAeVmpfu1/6IjyT/gXHOl+S0vQ9owggJ30hhWKdHAsNPOcasn5o9BW0eejZqL2e4vMjhAxoW3jVHcD6mbcYw== dependencies: decode-uri-component "^0.2.0" @@ -10004,7 +10028,7 @@ shebang-regex@^3.0.0: side-channel@^1.0.4: version "1.0.4" - resolved "https://registry.npmjs.org/side-channel/-/side-channel-1.0.4.tgz" + resolved "https://registry.yarnpkg.com/side-channel/-/side-channel-1.0.4.tgz#efce5c8fdc104ee751b25c58d4290011fa5ea2cf" integrity sha512-q5XPytqFEIKHkGdiMIrY10mvLRvnQh42/+GoBlFW3b2LXLE2xxJpZFdm94we0BaoV3RwJyGqg5wS7epxTv0Zvw== dependencies: call-bind "^1.0.0" @@ -10161,7 +10185,7 @@ spdx-license-ids@^3.0.0: split-on-first@^1.0.0: version "1.1.0" - resolved "https://registry.npmjs.org/split-on-first/-/split-on-first-1.1.0.tgz" + resolved "https://registry.yarnpkg.com/split-on-first/-/split-on-first-1.1.0.tgz#f610afeee3b12bce1d0c30425e76398b78249a5f" integrity sha512-43ZssAJaMusuKWL8sKUBQXHWOpq8d6CfN/u1p4gUzfJkM05C8rxTmYrkIPTXapZpORA6LkkzcUulJ8FqA7Uudw== split2@^3.0.0: @@ -10236,8 +10260,8 @@ stack-utils@^2.0.3: strict-uri-encode@^2.0.0: version "2.0.0" - resolved "https://registry.npmjs.org/strict-uri-encode/-/strict-uri-encode-2.0.0.tgz" - integrity sha1-ucczDHBChi9rFC3CdLvMWGbONUY= + resolved "https://registry.yarnpkg.com/strict-uri-encode/-/strict-uri-encode-2.0.0.tgz#b9c7330c7042862f6b142dc274bbcc5866ce3546" + integrity sha512-QwiXZgpRcKkhTj2Scnn++4PKtWsH0kpzZ62L2R6c/LUVYv7hVnZqcg2+sMuT6R7Jusu1vviK/MFsu6kNJfWlEQ== string-hash@^1.1.1: version "1.1.3"