From b3aff9027bff51120169b94b0da83e0c5b065c8b Mon Sep 17 00:00:00 2001 From: Vladimir Milenko Date: Sat, 3 Apr 2021 00:13:39 +0200 Subject: [PATCH 01/18] Fix sheet insertion Restore skip duration Use virtualStyleRulesMap to re-populate stylesheet on Flush event Clear virtualStyleRulesMap after flush applied --- src/replay/index.ts | 61 ++++++++++++++++++++++++++++++++++++++++--- test/replayer.test.ts | 13 +++++++++ 2 files changed, 70 insertions(+), 4 deletions(-) diff --git a/src/replay/index.ts b/src/replay/index.ts index 255083b76c..63c48efab6 100644 --- a/src/replay/index.ts +++ b/src/replay/index.ts @@ -117,6 +117,8 @@ export class Replayer { private treeIndex!: TreeIndex; private fragmentParentMap!: Map; private elementStateMap!: Map; + // Hold the list of CSSRules during in-memory state restoration + private virtualStyleRulesMap!: Map; private imageMap: Map = new Map(); @@ -160,6 +162,8 @@ export class Replayer { this.treeIndex = new TreeIndex(); this.fragmentParentMap = new Map(); this.elementStateMap = new Map(); + this.virtualStyleRulesMap = new Map(); + this.emitter.on(ReplayerEvents.Flush, () => { const { scrollMap, inputMap } = this.treeIndex.flush(); @@ -180,8 +184,13 @@ export class Replayer { // restore state of elements after they are mounted this.restoreState(parent); } + for (const [node] of this.virtualStyleRulesMap.entries()) { + // restore css rules of elements after they are mounted + this.restoreNodeSheet(node); + } this.fragmentParentMap.clear(); this.elementStateMap.clear(); + this.virtualStyleRulesMap.clear(); for (const d of scrollMap.values()) { this.applyScroll(d); @@ -913,6 +922,17 @@ export class Replayer { const styleEl = (target as Node) as HTMLStyleElement; const parent = (target.parentNode as unknown) as INode; const usingVirtualParent = this.fragmentParentMap.has(parent); + + /** + * Always use existing DOM node, when it's there. + * In in-memory replay, there is virtual node, but it's `sheet` will be removed during replacement. + * Hence, we re-create it and re-populate it on each run to not miss pre-existing styles and previously inserted + */ + const styleSheet = usingVirtualParent + ? new CSSStyleSheet() + : styleEl.sheet + ? styleEl.sheet + : new CSSStyleSheet(); let placeholderNode; if (usingVirtualParent) { @@ -927,9 +947,21 @@ export class Replayer { placeholderNode = document.createTextNode(''); parent.replaceChild(placeholderNode, target); domParent!.appendChild(target); - } - const styleSheet: CSSStyleSheet = styleEl.sheet!; + if (!this.virtualStyleRulesMap.has(target)) { + this.virtualStyleRulesMap.set( + target, + Array.from(styleEl.sheet?.rules || []), + ); + } + + const existingRules = this.virtualStyleRulesMap.get(target); + if (existingRules) { + existingRules.forEach((rule, index) => { + styleSheet?.insertRule(rule.cssText, index); + }); + } + } if (d.adds) { d.adds.forEach(({ rule, index }) => { @@ -966,11 +998,16 @@ export class Replayer { } }); } - + if (usingVirtualParent) { + // Update rules list according to new styleSheet + this.virtualStyleRulesMap.set( + target, + Array.from(styleSheet?.rules || []), + ); + } if (usingVirtualParent && placeholderNode) { parent.replaceChild(target, placeholderNode); } - break; } case IncrementalSource.CanvasMutation: { @@ -1559,6 +1596,22 @@ export class Replayer { } } + private restoreNodeSheet(node: INode) { + if (node.nodeName === 'STYLE') { + const styleNode = (node as unknown) as HTMLStyleElement; + if (this.virtualStyleRulesMap.has(node)) { + const storedRules = this.virtualStyleRulesMap.get(node); + if (!storedRules) return; + storedRules.forEach((rule, index) => { + if (styleNode?.sheet?.rules[index]) { + styleNode.sheet?.deleteRule(index); + } + styleNode.sheet?.insertRule(rule.cssText, index); + }); + } + } + } + private warnNodeNotFound(d: incrementalData, id: number) { this.warn(`Node with id '${id}' not found in`, d); } diff --git a/test/replayer.test.ts b/test/replayer.test.ts index e61c3d3714..d1ce128b45 100644 --- a/test/replayer.test.ts +++ b/test/replayer.test.ts @@ -146,6 +146,19 @@ describe('replayer', function (this: ISuite) { replayer.play(1500); replayer['timer']['actions'].length; `); + + const result = await this.page.evaluate(` + const rules = Array.from(replayer.iframe.contentDocument.head.children) + .filter(x=>x.nodeName === 'STYLE') + .reduce((acc, node) => { + acc.push(...node.sheet.rules); + return acc; + }, []); + + rules.some(x=>x.selectorText === ".css-1fbxx79") + `); + + expect(result).to.equal(true); expect(actionLength).to.equal( styleSheetRuleEvents.filter( (e) => e.timestamp - styleSheetRuleEvents[0].timestamp >= 1500, From 48016b3c0ccaf63b73f2b22af8dd9a365c2407a1 Mon Sep 17 00:00:00 2001 From: Vladimir Milenko Date: Sun, 4 Apr 2021 01:05:08 +0200 Subject: [PATCH 02/18] Support rule deletion in virtual processing --- src/replay/index.ts | 5 +++++ test/events/style-sheet-rule-events.ts | 13 +++++++++++++ test/replayer.test.ts | 25 +++++++++++++++++++++++++ 3 files changed, 43 insertions(+) diff --git a/src/replay/index.ts b/src/replay/index.ts index 63c48efab6..d8724d8d5a 100644 --- a/src/replay/index.ts +++ b/src/replay/index.ts @@ -1608,6 +1608,11 @@ export class Replayer { } styleNode.sheet?.insertRule(rule.cssText, index); }); + if(styleNode.sheet && styleNode.sheet.rules.length > storedRules.length) { + for(let i = styleNode.sheet.rules.length-1; i < storedRules.length - 1; i--) { + styleNode.sheet.removeRule(i); + } + } } } } diff --git a/test/events/style-sheet-rule-events.ts b/test/events/style-sheet-rule-events.ts index 5740f50215..bc56eae457 100644 --- a/test/events/style-sheet-rule-events.ts +++ b/test/events/style-sheet-rule-events.ts @@ -141,6 +141,19 @@ const events: eventWithTime[] = [ type: EventType.IncrementalSnapshot, timestamp: now + 1000, }, + { + data: { + id: 105, + removes: [ + { + index: 2, + }, + ], + source: IncrementalSource.StyleSheetRule, + }, + type: EventType.IncrementalSnapshot, + timestamp: now + 2500, + }, ]; export default events; diff --git a/test/replayer.test.ts b/test/replayer.test.ts index d1ce128b45..fbd59ee1af 100644 --- a/test/replayer.test.ts +++ b/test/replayer.test.ts @@ -183,6 +183,31 @@ describe('replayer', function (this: ISuite) { ); }); + it('can fast forward past StyleSheetRule deletion on virtual elements', async () => { + await this.page.evaluate( + `events = ${JSON.stringify(styleSheetRuleEvents)}`, + ); + const actionLength = await this.page.evaluate(` + const { Replayer } = rrweb; + const replayer = new Replayer(events); + replayer.play(2500); + replayer['timer']['actions'].length; + `); + + const result = await this.page.evaluate(` + const rules = Array.from(replayer.iframe.contentDocument.head.children) + .filter(x=>x.nodeName === 'STYLE') + .reduce((acc, node) => { + acc.push(...node.sheet.rules); + return acc; + }, []); + + rules.some(x=>x.selectorText === ".css-1fbxx79") + `); + + expect(result).to.equal(false); + }); + it('can stream events in live mode', async () => { const status = await this.page.evaluate(` const { Replayer } = rrweb; From d68e395921f8654d40cdf783bd63bfcf40ccb271 Mon Sep 17 00:00:00 2001 From: Vladimir Milenko Date: Sun, 4 Apr 2021 22:17:23 +0200 Subject: [PATCH 03/18] Simply restoreNodeSheet with early aborts --- src/replay/index.ts | 35 +++++++++++++++++++---------------- 1 file changed, 19 insertions(+), 16 deletions(-) diff --git a/src/replay/index.ts b/src/replay/index.ts index d8724d8d5a..529e714973 100644 --- a/src/replay/index.ts +++ b/src/replay/index.ts @@ -1597,22 +1597,25 @@ export class Replayer { } private restoreNodeSheet(node: INode) { - if (node.nodeName === 'STYLE') { - const styleNode = (node as unknown) as HTMLStyleElement; - if (this.virtualStyleRulesMap.has(node)) { - const storedRules = this.virtualStyleRulesMap.get(node); - if (!storedRules) return; - storedRules.forEach((rule, index) => { - if (styleNode?.sheet?.rules[index]) { - styleNode.sheet?.deleteRule(index); - } - styleNode.sheet?.insertRule(rule.cssText, index); - }); - if(styleNode.sheet && styleNode.sheet.rules.length > storedRules.length) { - for(let i = styleNode.sheet.rules.length-1; i < storedRules.length - 1; i--) { - styleNode.sheet.removeRule(i); - } - } + const storedRules = this.virtualStyleRulesMap.get(node); + if (node.nodeName !== 'STYLE') return; + + if(!storedRules) return; + + const styleNode = (node as unknown) as HTMLStyleElement; + + storedRules.forEach((rule, index) => { + // Esnure consistency of rules list + if (styleNode?.sheet?.rules[index]) { + styleNode.sheet?.deleteRule(index); + } + styleNode.sheet?.insertRule(rule.cssText, index); + }); + // Avoid situation, when your Node has more styles, than it should + // Otherwise, inserting will be broken + if(styleNode.sheet && styleNode.sheet.rules.length > storedRules.length) { + for(let i = styleNode.sheet.rules.length-1; i < storedRules.length - 1; i--) { + styleNode.sheet.removeRule(i); } } } From 0bc5bc3d634b083a97b3570cc8fae57f53b3ff1d Mon Sep 17 00:00:00 2001 From: Eoghan Murray Date: Wed, 30 Jun 2021 15:06:41 +0100 Subject: [PATCH 04/18] Encountered a bug where firstFullSnapshot was played twice because timer was immediately started and reached the snapshot before the setTimeout returned --- src/replay/index.ts | 21 +++++++++++++-------- 1 file changed, 13 insertions(+), 8 deletions(-) diff --git a/src/replay/index.ts b/src/replay/index.ts index 0bdd644283..e1ee678423 100644 --- a/src/replay/index.ts +++ b/src/replay/index.ts @@ -89,8 +89,8 @@ export class Replayer { private imageMap: Map = new Map(); private mirror: Mirror = createMirror(); - /** The first time the player is playing. */ - private firstPlayedEvent: eventWithTime | null = null; + + private firstFullSnapshot: eventWithTime | null = null; private newDocumentQueue: addedNodeMutation[] = []; @@ -145,7 +145,7 @@ export class Replayer { } }); this.emitter.on(ReplayerEvents.PlayBack, () => { - this.firstPlayedEvent = null; + this.firstFullSnapshot = null; this.mirror.reset(); }); @@ -207,10 +207,10 @@ export class Replayer { if (firstFullsnapshot) { setTimeout(() => { // when something has been played, there is no need to rebuild poster - if (this.firstPlayedEvent) { + if (this.firstFullSnapshot) { return; } - this.firstPlayedEvent = firstFullsnapshot; + this.firstFullSnapshot = firstFullsnapshot; this.rebuildFullSnapshot( firstFullsnapshot as fullSnapshotEvent & { timestamp: number }, ); @@ -429,9 +429,14 @@ export class Replayer { break; case EventType.FullSnapshot: castFn = () => { - // Don't build a full snapshot during the first play through since we've already built it when the player was mounted. - if (this.firstPlayedEvent && this.firstPlayedEvent === event) { - return; + if (this.firstFullSnapshot) { + if (this.firstFullSnapshot === event) { + // we've already built it when the player was mounted. + return; + } + } else { + // Timer (requestAnimationFrame) can be faster than setTimeout(..., 1) + this.firstFullSnapshot = event; } this.rebuildFullSnapshot(event, isSync); this.iframe.contentWindow!.scrollTo(event.data.initialOffset); From ff65e4cb51b6f74d0b9358ef49745b41c7c1b812 Mon Sep 17 00:00:00 2001 From: Eoghan Murray Date: Wed, 30 Jun 2021 16:49:11 +0100 Subject: [PATCH 05/18] Ignoring a FullSnapshot needs to be a one-time only thing, as otherwise we'll ignore it after scrubbing (restarting play head at a particular time). This is a problem if mutations have altered the player state, and we try to replay those mutations, so we e.g. try to remove an element that has already been removed because we haven't reset the FullSnapshot state --- src/replay/index.ts | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/src/replay/index.ts b/src/replay/index.ts index e1ee678423..1162de795f 100644 --- a/src/replay/index.ts +++ b/src/replay/index.ts @@ -208,6 +208,7 @@ export class Replayer { setTimeout(() => { // when something has been played, there is no need to rebuild poster if (this.firstFullSnapshot) { + // true if any other fullSnapshot has been executed by Timer already return; } this.firstFullSnapshot = firstFullsnapshot; @@ -431,12 +432,13 @@ export class Replayer { castFn = () => { if (this.firstFullSnapshot) { if (this.firstFullSnapshot === event) { - // we've already built it when the player was mounted. + // we've already built this exact FullSnapshot when the player was mounted, and haven't built any other FullSnapshot since + this.firstFullSnapshot = true; // forget as we might need to re-execute this FullSnapshot later e.g. to rebuild after scrubbing return; } } else { // Timer (requestAnimationFrame) can be faster than setTimeout(..., 1) - this.firstFullSnapshot = event; + this.firstFullSnapshot = true; } this.rebuildFullSnapshot(event, isSync); this.iframe.contentWindow!.scrollTo(event.data.initialOffset); From 803eb17ab4f6408d2fe92dc9cb18a3114af315f5 Mon Sep 17 00:00:00 2001 From: Eoghan Murray Date: Thu, 1 Jul 2021 10:56:40 +0100 Subject: [PATCH 06/18] Some `npm run typings` related fixups --- src/replay/index.ts | 2 +- typings/replay/index.d.ts | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/replay/index.ts b/src/replay/index.ts index 1162de795f..6ff631cd56 100644 --- a/src/replay/index.ts +++ b/src/replay/index.ts @@ -90,7 +90,7 @@ export class Replayer { private mirror: Mirror = createMirror(); - private firstFullSnapshot: eventWithTime | null = null; + private firstFullSnapshot: eventWithTime | true | null = null; private newDocumentQueue: addedNodeMutation[] = []; diff --git a/typings/replay/index.d.ts b/typings/replay/index.d.ts index fc9302092b..0f021d3298 100644 --- a/typings/replay/index.d.ts +++ b/typings/replay/index.d.ts @@ -20,7 +20,7 @@ export declare class Replayer { private elementStateMap; private imageMap; private mirror; - private firstPlayedEvent; + private firstFullSnapshot; private newDocumentQueue; constructor(events: Array, config?: Partial); on(event: string, handler: Handler): this; From 11d75722559f734867bed7eb55aa706b951248d6 Mon Sep 17 00:00:00 2001 From: Justin Halsall Date: Fri, 2 Jul 2021 22:30:16 +0200 Subject: [PATCH 07/18] add basic html snapshot functionality --- package.json | 2 + test/__snapshots__/replayer.test.ts.snap | 62 ++ test/replayer.test.ts | 9 +- test/utils.ts | 100 ++- yarn.lock | 809 ++++++++++++++++++++++- 5 files changed, 955 insertions(+), 27 deletions(-) create mode 100644 test/__snapshots__/replayer.test.ts.snap diff --git a/package.json b/package.json index 0146cd6814..609fa93746 100644 --- a/package.json +++ b/package.json @@ -44,9 +44,11 @@ "@types/puppeteer": "^5.4.3", "chai": "^4.2.0", "cross-env": "^5.2.0", + "fast-mhtml": "^1.1.9", "inquirer": "^6.2.1", "jest-snapshot": "^23.6.0", "mocha": "^5.2.0", + "node-libtidy": "^0.4.0", "prettier": "2.2.1", "puppeteer": "^9.1.1", "rollup": "^2.3.3", diff --git a/test/__snapshots__/replayer.test.ts.snap b/test/__snapshots__/replayer.test.ts.snap new file mode 100644 index 0000000000..046df0ac28 --- /dev/null +++ b/test/__snapshots__/replayer.test.ts.snap @@ -0,0 +1,62 @@ +// Jest Snapshot v1, https://goo.gl/fbAQLP + +exports[`style-sheet-rule-events-1500 1`] = ` +"file-frame-3 + + + + + + +
+
+ +
+ + + + +file-frame-4 + + + + + + + + + + + + + + +file-cid-0 +@charset \\"utf-8\\"; + +.rr-block { background: rgb(204, 204, 204); } + +noscript { display: none !important; } + +html.rrweb-paused * { animation-play-state: paused !important; } + + +file-cid-1 +@charset \\"utf-8\\"; + +.c01x { opacity: 1; transform: translateX(0px); } + + +file-cid-2 +@charset \\"utf-8\\"; + +.css-1uxxxx3 { position: fixed; top: 0px; right: 0px; left: 4rem; z-index: 15; flex-shrink: 0; height: 0.25rem; overflow: hidden; background-color: rgb(17, 171, 209); } + +.css-1c9xxxx { height: 0.25rem; background-color: rgb(190, 232, 242); opacity: 0; transition: opacity 0.5s ease 0s; } + +.css-lsxxx { padding-left: 4rem; } +" +`; diff --git a/test/replayer.test.ts b/test/replayer.test.ts index fbd59ee1af..98af6ac8f8 100644 --- a/test/replayer.test.ts +++ b/test/replayer.test.ts @@ -6,6 +6,7 @@ import * as puppeteer from 'puppeteer'; import { expect } from 'chai'; import { Suite } from 'mocha'; import { + assertDomSnapshot, launchPuppeteer, sampleEvents as events, sampleStyleSheetRemoveEvents as stylesheetRemoveEvents, @@ -147,6 +148,12 @@ describe('replayer', function (this: ISuite) { replayer['timer']['actions'].length; `); + await assertDomSnapshot( + this.page, + __filename, + 'style-sheet-rule-events-1500', + ); + const result = await this.page.evaluate(` const rules = Array.from(replayer.iframe.contentDocument.head.children) .filter(x=>x.nodeName === 'STYLE') @@ -158,12 +165,12 @@ describe('replayer', function (this: ISuite) { rules.some(x=>x.selectorText === ".css-1fbxx79") `); - expect(result).to.equal(true); expect(actionLength).to.equal( styleSheetRuleEvents.filter( (e) => e.timestamp - styleSheetRuleEvents[0].timestamp >= 1500, ).length, ); + expect(result).to.equal(true); }); it('can handle removing style elements', async () => { diff --git a/test/utils.ts b/test/utils.ts index 3b21e30f23..a8e2f60523 100644 --- a/test/utils.ts +++ b/test/utils.ts @@ -8,6 +8,7 @@ import { MouseInteractions, } from '../src/types'; import * as puppeteer from 'puppeteer'; +import { TidyDoc } from 'node-libtidy'; export async function launchPuppeteer() { return await puppeteer.launch({ @@ -61,7 +62,7 @@ function stringifySnapshots(snapshots: eventWithTime[]): string { s.data.href = 'about:blank'; } // FIXME: travis coordinates seems different with my laptop - const coordinatesReg = /(bottom|top|left|right|width|height): \d+(\.\d+)?px/g + const coordinatesReg = /(bottom|top|left|right|width|height): \d+(\.\d+)?px/g; if ( s.type === EventType.IncrementalSnapshot && s.data.source === IncrementalSource.MouseInteraction @@ -78,7 +79,10 @@ function stringifySnapshots(snapshots: eventWithTime[]): string { 'style' in a.attributes && coordinatesReg.test(a.attributes.style!) ) { - a.attributes.style = a.attributes.style!.replace(coordinatesReg, '$1: Npx'); + a.attributes.style = a.attributes.style!.replace( + coordinatesReg, + '$1: Npx', + ); } }); s.data.adds.forEach((add) => { @@ -88,7 +92,10 @@ function stringifySnapshots(snapshots: eventWithTime[]): string { typeof add.node.attributes.style === 'string' && coordinatesReg.test(add.node.attributes.style) ) { - add.node.attributes.style = add.node.attributes.style.replace(coordinatesReg, '$1: Npx'); + add.node.attributes.style = add.node.attributes.style.replace( + coordinatesReg, + '$1: Npx', + ); } }); } @@ -100,6 +107,57 @@ function stringifySnapshots(snapshots: eventWithTime[]): string { ); } +function stringifyDomSnapshot(mhtml: string): string { + const { Parser } = require('fast-mhtml'); + const resources: string[] = []; + const p = new Parser({ + rewriteFn: (filename: string): string => { + const index = resources.indexOf(filename); + const prefix = /^\w+/.exec(filename); + if (index !== -1) { + return `file-${prefix}-${index}`; + } else { + return `file-${prefix}-${resources.push(filename) - 1}`; + } + }, + }); + const result = p + .parse(mhtml) // parse file + .rewrite() // rewrite all links + .spit(); // return all contents + + const newResult: { filename: string; content: string }[] = result.map( + (asset: { filename: string; content: string }) => { + let { filename, content } = asset; + let res: string | undefined; + if (filename.includes('frame')) { + const doc = TidyDoc(); + doc.options = { + indent: 'auto', + indent_spaces: 2, + wrap: 80, + markup: true, + output_xml: false, + numeric_entities: true, + quote_marks: true, + quote_nbsp: false, + // 'show_body_only': true, + quote_ampersand: false, + break_before_br: true, + uppercase_tags: false, + // 'uppercase_attributes': false, + // 'drop_font_tags': true, + tidy_mark: false, + }; + doc.parseBufferSync(Buffer.from(content)); + res = doc.saveBufferSync().toString(); + } + return { filename, content: res || content }; + }, + ); + return newResult.map((asset) => Object.values(asset).join('\n')).join('\n\n'); +} + export function assertSnapshot( snapshots: eventWithTime[], filename: string, @@ -109,6 +167,20 @@ export function assertSnapshot( assert(result.pass, result.pass ? '' : result.report()); } +export async function assertDomSnapshot( + page: puppeteer.Page, + filename: string, + name: string, +) { + const cdp = await page.target().createCDPSession(); + const { data } = await cdp.send('Page.captureSnapshot', { + format: 'mhtml', + }); + + const result = matchSnapshot(stringifyDomSnapshot(data), filename, name); + assert(result.pass, result.pass ? '' : result.report()); +} + const now = Date.now(); export const sampleEvents: eventWithTime[] = [ { @@ -241,23 +313,23 @@ export const sampleStyleSheetRemoveEvents: eventWithTime[] = [ childNodes: [ { type: 2, - tagName: "style", + tagName: 'style', attributes: { - "data-jss": "", - "data-meta": "OverlayDrawer", - _cssText: ".OverlayDrawer-modal-187 { }.OverlayDrawer-paper-188 { width: 100%; }@media (min-width: 48em) {\n .OverlayDrawer-paper-188 { width: 38rem; }\n}@media (min-width: 48em) {\n}@media (min-width: 48em) {\n}" + 'data-jss': '', + 'data-meta': 'OverlayDrawer', + _cssText: + '.OverlayDrawer-modal-187 { }.OverlayDrawer-paper-188 { width: 100%; }@media (min-width: 48em) {\n .OverlayDrawer-paper-188 { width: 38rem; }\n}@media (min-width: 48em) {\n}@media (min-width: 48em) {\n}', }, childNodes: [ { type: 3, - textContent: "\n", + textContent: '\n', isStyle: true, - id: 5 + id: 5, }, ], - id: 4 + id: 4, }, - ], id: 3, }, @@ -290,10 +362,10 @@ export const sampleStyleSheetRemoveEvents: eventWithTime[] = [ removes: [ { parentId: 3, - id: 4 - } + id: 4, + }, ], - adds: [] + adds: [], }, timestamp: now + 2000, }, diff --git a/yarn.lock b/yarn.lock index 670017a9d5..307d19427a 100644 --- a/yarn.lock +++ b/yarn.lock @@ -188,6 +188,19 @@ resolved "https://registry.yarnpkg.com/@xstate/fsm/-/fsm-1.5.1.tgz#b1ebedc77b11e4956fda0a6429cef986cd17979e" integrity sha512-t8blLI0e90jCE71yUQHLH5uEljD1v0aC8PKkHUtNWEnXt81EOj7xBjnlwmaHn/8cmE2aSygiBElUpkRZUV9hXA== +abbrev@1: + version "1.1.1" + resolved "https://registry.yarnpkg.com/abbrev/-/abbrev-1.1.1.tgz#f8f2c887ad10bf67f634f005b6987fed3179aac8" + integrity sha512-nne9/IiQ/hzIhY6pdDnbBtz7DjPTKrY00P/zvPSm5pOFkl6xuGrGnXn/VtTNNfNtAfZ9/1RtehkszU9qcTii0Q== + +accepts@~1.3.7: + version "1.3.7" + resolved "https://registry.yarnpkg.com/accepts/-/accepts-1.3.7.tgz#531bc726517a3b2b41f850021c6cc15eaab507cd" + integrity sha512-Il80Qs2WjYlJIBNzNkK6KYqlVMTbZLXgHx2oT0pU/fjRHyEp+PEfEPY0R3WCwAGVOtauxh1hOxNgIf5bv7dQpA== + dependencies: + mime-types "~2.1.24" + negotiator "0.6.2" + agent-base@6: version "6.0.2" resolved "https://registry.yarnpkg.com/agent-base/-/agent-base-6.0.2.tgz#49fff58577cfee3f37176feab4c22e00f86d7f77" @@ -246,6 +259,19 @@ ansi-styles@^4.1.0: dependencies: color-convert "^2.0.1" +aproba@^1.0.3: + version "1.2.0" + resolved "https://registry.yarnpkg.com/aproba/-/aproba-1.2.0.tgz#6802e6264efd18c790a1b0d517f0f2627bf2c94a" + integrity sha512-Y9J6ZjXtoYh8RnXVCMOU/ttDmk1aBjunq9vO0ta5x85WDQiQfUF9sIPBITdbiiIVcBo03Hi3jMxigBtsddlXRw== + +are-we-there-yet@~1.1.2: + version "1.1.5" + resolved "https://registry.yarnpkg.com/are-we-there-yet/-/are-we-there-yet-1.1.5.tgz#4b35c2944f062a8bfcda66410760350fe9ddfc21" + integrity sha512-5hYdAkZlcG8tOLujVDTgCT+uPX0VnpAH28gWsLfzpXYm7wP6mp5Q/gYyR7YQ0cKVJcXJnl3j2kpBan13PtQf6w== + dependencies: + delegates "^1.0.0" + readable-stream "^2.0.6" + argparse@^1.0.7: version "1.0.10" resolved "https://registry.yarnpkg.com/argparse/-/argparse-1.0.10.tgz#bcd6791ea5ae09725e17e5ad988134cd40b3d911" @@ -265,6 +291,11 @@ arr-flatten@^1.0.1: resolved "https://registry.yarnpkg.com/arr-flatten/-/arr-flatten-1.1.0.tgz#36048bbff4e7b47e136644316c99669ea5ae91f1" integrity sha512-L3hKV5R/p5o81R7O02IGnwpDmkp6E982XhtbuwSe3O4qOtMMMtodicASA1Cny2U+aCXcNpml+m4dPsvsJ3jatg== +array-flatten@1.1.1: + version "1.1.1" + resolved "https://registry.yarnpkg.com/array-flatten/-/array-flatten-1.1.1.tgz#9a5f699051b1e7073328f2a008968b64ea2955d2" + integrity sha1-ml9pkFGx5wczKPKgCJaLZOopVdI= + array-unique@^0.2.1: version "0.2.1" resolved "https://registry.yarnpkg.com/array-unique/-/array-unique-0.2.1.tgz#a1d97ccafcbc2625cc70fadceb36a50c58b01a53" @@ -331,6 +362,27 @@ bl@^4.0.3: inherits "^2.0.4" readable-stream "^3.4.0" +bluebird@^3.5.2: + version "3.7.2" + resolved "https://registry.yarnpkg.com/bluebird/-/bluebird-3.7.2.tgz#9f229c15be272454ffa973ace0dbee79a1b0c36f" + integrity sha512-XpNj6GDQzdfW+r2Wnn7xiSAd7TM3jzkxGXBGTtWKuSXv1xUV+azxAm8jdWZN06QTQk+2N2XB9jRDkvbmQmcRtg== + +body-parser@1.19.0: + version "1.19.0" + resolved "https://registry.yarnpkg.com/body-parser/-/body-parser-1.19.0.tgz#96b2709e57c9c4e09a6fd66a8fd979844f69f08a" + integrity sha512-dhEPs72UPbDnAQJ9ZKMNTP6ptJaionhP5cBb541nXPlW60Jepo9RV/a4fX4XWW9CuFNK22krhrj1+rgzifNCsw== + dependencies: + bytes "3.1.0" + content-type "~1.0.4" + debug "2.6.9" + depd "~1.1.2" + http-errors "1.7.2" + iconv-lite "0.4.24" + on-finished "~2.3.0" + qs "6.7.0" + raw-body "2.4.0" + type-is "~1.6.17" + boolbase@^1.0.0, boolbase@~1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/boolbase/-/boolbase-1.0.0.tgz#68dff5fbe60c51eb37725ea9e3ed310dcc1e776e" @@ -412,6 +464,11 @@ builtin-modules@^2.0.0: resolved "https://registry.yarnpkg.com/builtin-modules/-/builtin-modules-2.0.0.tgz#60b7ef5ae6546bd7deefa74b08b62a43a232648e" integrity sha512-3U5kUA5VPsRUA3nofm/BXX7GVHKfxz0hOBAPxXrIvHzlDRkQVqEn6yi8QJegxl4LzOHLdvb7XF5dVawa/VVYBg== +bytes@3.1.0: + version "3.1.0" + resolved "https://registry.yarnpkg.com/bytes/-/bytes-3.1.0.tgz#f6cf7933a360e0588fa9fde85651cdc7f805d1f6" + integrity sha512-zauLjrfCG+xvoyaqLoV8bLVXXNGC4JqlxFCutSDWA6fJrTo2ZuvLYTqZ7aHBLZSMOopbzwv8f+wZcVzfVTI2Dg== + caller-callsite@^2.0.0: version "2.0.0" resolved "https://registry.yarnpkg.com/caller-callsite/-/caller-callsite-2.0.0.tgz#847e0fce0a223750a9a027c54b33731ad3154134" @@ -506,6 +563,30 @@ check-error@^1.0.2: resolved "https://registry.yarnpkg.com/check-error/-/check-error-1.0.2.tgz#574d312edd88bb5dd8912e9286dd6c0aed4aac82" integrity sha1-V00xLt2Iu13YkS6Sht1sCu1KrII= +cheerio-select@^1.5.0: + version "1.5.0" + resolved "https://registry.yarnpkg.com/cheerio-select/-/cheerio-select-1.5.0.tgz#faf3daeb31b17c5e1a9dabcee288aaf8aafa5823" + integrity sha512-qocaHPv5ypefh6YNxvnbABM07KMxExbtbfuJoIie3iZXX1ERwYmJcIiRrr9H05ucQP1k28dav8rpdDgjQd8drg== + dependencies: + css-select "^4.1.3" + css-what "^5.0.1" + domelementtype "^2.2.0" + domhandler "^4.2.0" + domutils "^2.7.0" + +cheerio@^1.0.0-rc.3: + version "1.0.0-rc.10" + resolved "https://registry.yarnpkg.com/cheerio/-/cheerio-1.0.0-rc.10.tgz#2ba3dcdfcc26e7956fc1f440e61d51c643379f3e" + integrity sha512-g0J0q/O6mW8z5zxQ3A8E8J1hUgp4SMOvEoW/x84OwyHKe/Zccz83PVT4y5Crcr530FV6NgmKI1qvGTKVl9XXVw== + dependencies: + cheerio-select "^1.5.0" + dom-serializer "^1.3.2" + domhandler "^4.2.0" + htmlparser2 "^6.1.0" + parse5 "^6.0.1" + parse5-htmlparser2-tree-adapter "^6.0.1" + tslib "^2.2.0" + chownr@^1.1.1: version "1.1.4" resolved "https://registry.yarnpkg.com/chownr/-/chownr-1.1.4.tgz#6fc9d7b42d32a583596337666e7d08084da2cc6b" @@ -542,6 +623,11 @@ coa@^2.0.2: chalk "^2.4.1" q "^1.1.2" +code-point-at@^1.0.0: + version "1.1.0" + resolved "https://registry.yarnpkg.com/code-point-at/-/code-point-at-1.1.0.tgz#0d070b4d043a5bea33a2f1a40e2edb3d9a4ccf77" + integrity sha1-DQcLTQQ6W+ozovGkDi7bPZpMz3c= + color-convert@^1.9.0, color-convert@^1.9.1: version "1.9.3" resolved "https://registry.yarnpkg.com/color-convert/-/color-convert-1.9.3.tgz#bb71850690e1f136567de629d2d5471deda4c1e8" @@ -626,11 +712,43 @@ configstore@^3.0.0: write-file-atomic "^2.0.0" xdg-basedir "^3.0.0" +console-control-strings@^1.0.0, console-control-strings@~1.1.0: + version "1.1.0" + resolved "https://registry.yarnpkg.com/console-control-strings/-/console-control-strings-1.1.0.tgz#3d7cf4464db6446ea644bf4b39507f9851008e8e" + integrity sha1-PXz0Rk22RG6mRL9LOVB/mFEAjo4= + +content-disposition@0.5.3: + version "0.5.3" + resolved "https://registry.yarnpkg.com/content-disposition/-/content-disposition-0.5.3.tgz#e130caf7e7279087c5616c2007d0485698984fbd" + integrity sha512-ExO0774ikEObIAEV9kDo50o+79VCUdEB6n6lzKgGwupcVeRlhrj3qGAfwq8G6uBJjkqLrhT0qEYFcWng8z1z0g== + dependencies: + safe-buffer "5.1.2" + +content-type@~1.0.4: + version "1.0.4" + resolved "https://registry.yarnpkg.com/content-type/-/content-type-1.0.4.tgz#e138cc75e040c727b1966fe5e5f8c9aee256fe3b" + integrity sha512-hIP3EEPs8tB9AT1L+NUqtwOAps4mk2Zob89MWXMHjHWg9milF/j4osnnQLXBCBFBk/tvIG/tUc9mOUJiPBhPXA== + +cookie-signature@1.0.6: + version "1.0.6" + resolved "https://registry.yarnpkg.com/cookie-signature/-/cookie-signature-1.0.6.tgz#e303a882b342cc3ee8ca513a79999734dab3ae2c" + integrity sha1-4wOogrNCzD7oylE6eZmXNNqzriw= + +cookie@0.4.0: + version "0.4.0" + resolved "https://registry.yarnpkg.com/cookie/-/cookie-0.4.0.tgz#beb437e7022b3b6d49019d088665303ebe9c14ba" + integrity sha512-+Hp8fLp57wnUSt0tY0tHEXh4voZRDnoIrZPqlo3DPiI4y9lwg/jqx+1Om94/W6ZaPDOUbnjOt/99w66zk+l1Xg== + core-js@^2.4.0: version "2.6.11" resolved "https://registry.yarnpkg.com/core-js/-/core-js-2.6.11.tgz#38831469f9922bded8ee21c9dc46985e0399308c" integrity sha512-5wjnpaT/3dV+XB4borEsnAYQchn00XSgTAWKDkEqv+K8KevjbzmofK6hfJ9TZIlpj2N0xQpazy7PiRQiWHqzWg== +core-util-is@~1.0.0: + version "1.0.2" + resolved "https://registry.yarnpkg.com/core-util-is/-/core-util-is-1.0.2.tgz#b5fd54220aa2bc5ab57aab7140c940754503c1a7" + integrity sha1-tf1UIgqivFq1eqtxQMlAdUUDwac= + cosmiconfig@^5.0.0: version "5.2.1" resolved "https://registry.yarnpkg.com/cosmiconfig/-/cosmiconfig-5.2.1.tgz#040f726809c591e77a17c0a3626ca45b4f168b1a" @@ -720,6 +838,17 @@ css-select@^2.0.0: domutils "^1.7.0" nth-check "^1.0.2" +css-select@^4.1.3: + version "4.1.3" + resolved "https://registry.yarnpkg.com/css-select/-/css-select-4.1.3.tgz#a70440f70317f2669118ad74ff105e65849c7067" + integrity sha512-gT3wBNd9Nj49rAbmtFHj1cljIAOLYSX1nZ8CB7TBO3INYckygm5B7LISU/szY//YmdiSLbJvDLOx9VnMVpMBxA== + dependencies: + boolbase "^1.0.0" + css-what "^5.0.0" + domhandler "^4.2.0" + domutils "^2.6.0" + nth-check "^2.0.0" + css-selector-tokenizer@^0.7.0: version "0.7.3" resolved "https://registry.yarnpkg.com/css-selector-tokenizer/-/css-selector-tokenizer-0.7.3.tgz#735f26186e67c749aaf275783405cf0661fae8f1" @@ -744,11 +873,24 @@ css-tree@1.0.0-alpha.39: mdn-data "2.0.6" source-map "^0.6.1" +css-tree@^1.0.0-alpha.39: + version "1.1.3" + resolved "https://registry.yarnpkg.com/css-tree/-/css-tree-1.1.3.tgz#eb4870fb6fd7707327ec95c2ff2ab09b5e8db91d" + integrity sha512-tRpdppF7TRazZrjJ6v3stzv93qxRcSsFmW6cX0Zm2NVKpxE1WV1HblnghVv9TreireHkqI/VDEsfolRF1p6y7Q== + dependencies: + mdn-data "2.0.14" + source-map "^0.6.1" + css-what@^3.2.1: version "3.4.2" resolved "https://registry.yarnpkg.com/css-what/-/css-what-3.4.2.tgz#ea7026fcb01777edbde52124e21f327e7ae950e4" integrity sha512-ACUm3L0/jiZTqfzRM3Hi9Q8eZqd6IK37mMWPLz9PJxkLWllYeRf+EHUSHYEtFop2Eqytaq1FizFVh7XfBnXCDQ== +css-what@^5.0.0, css-what@^5.0.1: + version "5.0.1" + resolved "https://registry.yarnpkg.com/css-what/-/css-what-5.0.1.tgz#3efa820131f4669a8ac2408f9c32e7c7de9f4cad" + integrity sha512-FYDTSHb/7KXsWICVsxdmiExPjCfRC4qRFBdVwv7Ax9hMnvMmEjP9RfxTEZ3qPZGmADDn2vAKSo9UcN1jKVYscg== + cssesc@^3.0.0: version "3.0.0" resolved "https://registry.yarnpkg.com/cssesc/-/cssesc-3.0.0.tgz#37741919903b868565e1c09ea747445cd18983ee" @@ -829,6 +971,13 @@ csso@^4.0.2: dependencies: css-tree "1.0.0-alpha.39" +debug@2.6.9: + version "2.6.9" + resolved "https://registry.yarnpkg.com/debug/-/debug-2.6.9.tgz#5d128515df134ff327e90a4c93f4e077a536341f" + integrity sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA== + dependencies: + ms "2.0.0" + debug@3.1.0: version "3.1.0" resolved "https://registry.yarnpkg.com/debug/-/debug-3.1.0.tgz#5bb5a0672628b64149566ba16819e61518c67261" @@ -843,6 +992,13 @@ debug@4, debug@^4.1.0, debug@^4.1.1: dependencies: ms "2.1.2" +debug@^3.2.6: + version "3.2.7" + resolved "https://registry.yarnpkg.com/debug/-/debug-3.2.7.tgz#72580b7e9145fb39b6676f9c5e5fb100b934179a" + integrity sha512-CFjzYYAi4ThfiQvizrFQevTTXHtnCqWfe7x1AhgEscTz6ZbLbfoLRLPugTQyBth6f8ZERVUSyWHFD/7Wu4t1XQ== + dependencies: + ms "^2.1.1" + deep-eql@^3.0.1: version "3.0.1" resolved "https://registry.yarnpkg.com/deep-eql/-/deep-eql-3.0.1.tgz#dfc9404400ad1c8fe023e7da1df1c147c4b444df" @@ -862,6 +1018,26 @@ define-properties@^1.1.3: dependencies: object-keys "^1.0.12" +delegates@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/delegates/-/delegates-1.0.0.tgz#84c6e159b81904fdca59a0ef44cd870d31250f9a" + integrity sha1-hMbhWbgZBP3KWaDvRM2HDTElD5o= + +depd@~1.1.2: + version "1.1.2" + resolved "https://registry.yarnpkg.com/depd/-/depd-1.1.2.tgz#9bcd52e14c097763e749b274c4346ed2e560b5a9" + integrity sha1-m81S4UwJd2PnSbJ0xDRu0uVgtak= + +destroy@~1.0.4: + version "1.0.4" + resolved "https://registry.yarnpkg.com/destroy/-/destroy-1.0.4.tgz#978857442c44749e4206613e37946205826abd80" + integrity sha1-l4hXRCxEdJ5CBmE+N5RiBYJqvYA= + +detect-libc@^1.0.3: + version "1.0.3" + resolved "https://registry.yarnpkg.com/detect-libc/-/detect-libc-1.0.3.tgz#fa137c4bd698edf55cd5cd02ac559f91a4c4ba9b" + integrity sha1-+hN8S9aY7fVc1c0CrFWfkaTEups= + devtools-protocol@0.0.869402: version "0.0.869402" resolved "https://registry.yarnpkg.com/devtools-protocol/-/devtools-protocol-0.0.869402.tgz#03ade701761742e43ae4de5dc188bcd80f156d8d" @@ -880,6 +1056,15 @@ dom-serializer@0: domelementtype "^2.0.1" entities "^2.0.0" +dom-serializer@^1.0.1, dom-serializer@^1.3.2: + version "1.3.2" + resolved "https://registry.yarnpkg.com/dom-serializer/-/dom-serializer-1.3.2.tgz#6206437d32ceefaec7161803230c7a20bc1b4d91" + integrity sha512-5c54Bk5Dw4qAxNOI1pFEizPSjVsx5+bpJKmL2kPn8JhBUq2q09tTCa3mjijun2NfK78NMouDYNMBkOrPZiS+ig== + dependencies: + domelementtype "^2.0.1" + domhandler "^4.2.0" + entities "^2.0.0" + domelementtype@1: version "1.3.1" resolved "https://registry.yarnpkg.com/domelementtype/-/domelementtype-1.3.1.tgz#d048c44b37b0d10a7f2a3d5fee3f4333d790481f" @@ -890,6 +1075,18 @@ domelementtype@^2.0.1: resolved "https://registry.yarnpkg.com/domelementtype/-/domelementtype-2.0.2.tgz#f3b6e549201e46f588b59463dd77187131fe6971" integrity sha512-wFwTwCVebUrMgGeAwRL/NhZtHAUyT9n9yg4IMDwf10+6iCMxSkVq9MGCVEH+QZWo1nNidy8kNvwmv4zWHDTqvA== +domelementtype@^2.2.0: + version "2.2.0" + resolved "https://registry.yarnpkg.com/domelementtype/-/domelementtype-2.2.0.tgz#9a0b6c2782ed6a1c7323d42267183df9bd8b1d57" + integrity sha512-DtBMo82pv1dFtUmHyr48beiuq792Sxohr+8Hm9zoxklYPfa6n0Z3Byjj2IV7bmr2IyqClnqEQhfgHJJ5QF0R5A== + +domhandler@^4.0.0, domhandler@^4.2.0: + version "4.2.0" + resolved "https://registry.yarnpkg.com/domhandler/-/domhandler-4.2.0.tgz#f9768a5f034be60a89a27c2e4d0f74eba0d8b059" + integrity sha512-zk7sgt970kzPks2Bf+dwT/PLzghLnsivb9CcxkvR8Mzr66Olr0Ofd8neSbglHJHaHa2MadfoSdNlKYAaafmWfA== + dependencies: + domelementtype "^2.2.0" + domutils@^1.7.0: version "1.7.0" resolved "https://registry.yarnpkg.com/domutils/-/domutils-1.7.0.tgz#56ea341e834e06e6748af7a1cb25da67ea9f8c2a" @@ -898,6 +1095,15 @@ domutils@^1.7.0: dom-serializer "0" domelementtype "1" +domutils@^2.5.2, domutils@^2.6.0, domutils@^2.7.0: + version "2.7.0" + resolved "https://registry.yarnpkg.com/domutils/-/domutils-2.7.0.tgz#8ebaf0c41ebafcf55b0b72ec31c56323712c5442" + integrity sha512-8eaHa17IwJUPAiB+SoTYBo5mCdeMgdcAoXJ59m6DT1vw+5iLS3gNoqYaRowaBKtGVrOF1Jz4yDTgYKLK2kvfJg== + dependencies: + dom-serializer "^1.0.1" + domelementtype "^2.2.0" + domhandler "^4.2.0" + dot-prop@^4.2.1: version "4.2.1" resolved "https://registry.yarnpkg.com/dot-prop/-/dot-prop-4.2.1.tgz#45884194a71fc2cda71cbb4bceb3a4dd2f433ba4" @@ -917,6 +1123,11 @@ duplexer3@^0.1.4: resolved "https://registry.yarnpkg.com/duplexer3/-/duplexer3-0.1.4.tgz#ee01dd1cac0ed3cbc7fdbea37dc0a8f1ce002ce2" integrity sha1-7gHdHKwO08vH/b6jfcCo8c4ALOI= +ee-first@1.1.1: + version "1.1.1" + resolved "https://registry.yarnpkg.com/ee-first/-/ee-first-1.1.1.tgz#590c61156b0ae2f4f0255732a158b266bc56b21d" + integrity sha1-WQxhFWsK4vTwJVcyoViyZrxWsh0= + electron-to-chromium@^1.3.723: version "1.3.739" resolved "https://registry.yarnpkg.com/electron-to-chromium/-/electron-to-chromium-1.3.739.tgz#f07756aa92cabd5a6eec6f491525a64fe62f98b9" @@ -927,6 +1138,11 @@ emojis-list@^3.0.0: resolved "https://registry.yarnpkg.com/emojis-list/-/emojis-list-3.0.0.tgz#5570662046ad29e2e916e71aae260abdff4f6a78" integrity sha512-/kyM18EfinwXZbno9FyUGeFh87KC8HRQBQGildHZbEuRyWFOmv1U10o9BBp8XVZDVNNuQKyIGIu5ZYAAXJ0V2Q== +encodeurl@~1.0.2: + version "1.0.2" + resolved "https://registry.yarnpkg.com/encodeurl/-/encodeurl-1.0.2.tgz#ad3ff4c86ec2d029322f5a02c3a9a606c95b3f59" + integrity sha1-rT/0yG7C0CkyL1oCw6mmBslbP1k= + end-of-stream@^1.1.0, end-of-stream@^1.4.1: version "1.4.4" resolved "https://registry.yarnpkg.com/end-of-stream/-/end-of-stream-1.4.4.tgz#5ae64a5f45057baf3626ec14da0ca5e4b2431eb0" @@ -995,6 +1211,11 @@ escalade@^3.1.1: resolved "https://registry.yarnpkg.com/escalade/-/escalade-3.1.1.tgz#d8cfdc7000965c5a0174b4a82eaa5c0552742e40" integrity sha512-k0er2gUkLf8O0zKJiAhmkTnJlTvINGv7ygDNPbeIsX/TJjGJZHuh9B2UxbsaEkmlEo9MfhrSzmhIlhRlI2GXnw== +escape-html@~1.0.3: + version "1.0.3" + resolved "https://registry.yarnpkg.com/escape-html/-/escape-html-1.0.3.tgz#0258eae4d3d0c0974de1c169188ef0051d1d1988" + integrity sha1-Aljq5NPQwJdN4cFpGI7wBR0dGYg= + escape-string-regexp@1.0.5, escape-string-regexp@^1.0.2, escape-string-regexp@^1.0.5: version "1.0.5" resolved "https://registry.yarnpkg.com/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz#1b61c0562190a8dff6ae3bb2cf0200ca130b86d4" @@ -1020,6 +1241,11 @@ esutils@^2.0.2: resolved "https://registry.yarnpkg.com/esutils/-/esutils-2.0.3.tgz#74d2eb4de0b8da1293711910d50775b9b710ef64" integrity sha512-kVscqXk4OCp68SZ0dkgEKVi6/8ij300KBWTJq32P/dYeWTSwK41WyTxalN1eRmA5Z9UU/LX9D7FWSmV9SAYx6g== +etag@~1.8.1: + version "1.8.1" + resolved "https://registry.yarnpkg.com/etag/-/etag-1.8.1.tgz#41ae2eeb65efa62268aebfea83ac7d79299b0887" + integrity sha1-Qa4u62XvpiJorr/qg6x9eSmbCIc= + eventemitter3@^4.0.4: version "4.0.7" resolved "https://registry.yarnpkg.com/eventemitter3/-/eventemitter3-4.0.7.tgz#2de9b68f6528d5644ef5c59526a1b4a07306169f" @@ -1052,6 +1278,42 @@ expand-range@^1.8.1: dependencies: fill-range "^2.1.0" +express@^4.16.4: + version "4.17.1" + resolved "https://registry.yarnpkg.com/express/-/express-4.17.1.tgz#4491fc38605cf51f8629d39c2b5d026f98a4c134" + integrity sha512-mHJ9O79RqluphRrcw2X/GTh3k9tVv8YcoyY4Kkh4WDMUYKRZUq0h1o0w2rrrxBqM7VoeUVqgb27xlEMXTnYt4g== + dependencies: + accepts "~1.3.7" + array-flatten "1.1.1" + body-parser "1.19.0" + content-disposition "0.5.3" + content-type "~1.0.4" + cookie "0.4.0" + cookie-signature "1.0.6" + debug "2.6.9" + depd "~1.1.2" + encodeurl "~1.0.2" + escape-html "~1.0.3" + etag "~1.8.1" + finalhandler "~1.1.2" + fresh "0.5.2" + merge-descriptors "1.0.1" + methods "~1.1.2" + on-finished "~2.3.0" + parseurl "~1.3.3" + path-to-regexp "0.1.7" + proxy-addr "~2.0.5" + qs "6.7.0" + range-parser "~1.2.1" + safe-buffer "5.1.2" + send "0.17.1" + serve-static "1.14.1" + setprototypeof "1.1.1" + statuses "~1.5.0" + type-is "~1.6.18" + utils-merge "1.0.1" + vary "~1.1.2" + external-editor@^3.0.3: version "3.1.0" resolved "https://registry.yarnpkg.com/external-editor/-/external-editor-3.1.0.tgz#cb03f740befae03ea4d283caed2741a83f335495" @@ -1079,6 +1341,17 @@ extract-zip@^2.0.0: optionalDependencies: "@types/yauzl" "^2.9.1" +fast-mhtml@^1.1.9: + version "1.1.9" + resolved "https://registry.yarnpkg.com/fast-mhtml/-/fast-mhtml-1.1.9.tgz#2c31e0727e0eb93423938a0812b001f67a3f6575" + integrity sha512-o+oAIqvK0xlb3o0wbReLxYXdSszbJW4gBeTFAOB3N+ByxBou2cYepTtlIkzXnlQUii4HSixJFMDVYNO4ei2s/w== + dependencies: + bluebird "^3.5.2" + cheerio "^1.0.0-rc.3" + css-tree "^1.0.0-alpha.39" + express "^4.16.4" + filenamify "^2.1.0" + fastparse@^1.1.2: version "1.1.2" resolved "https://registry.yarnpkg.com/fastparse/-/fastparse-1.1.2.tgz#91728c5a5942eced8531283c79441ee4122c35a9" @@ -1108,6 +1381,20 @@ filename-regex@^2.0.0: resolved "https://registry.yarnpkg.com/filename-regex/-/filename-regex-2.0.1.tgz#c1c4b9bee3e09725ddb106b75c1e301fe2f18b26" integrity sha1-wcS5vuPglyXdsQa3XB4wH+LxiyY= +filename-reserved-regex@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/filename-reserved-regex/-/filename-reserved-regex-2.0.0.tgz#abf73dfab735d045440abfea2d91f389ebbfa229" + integrity sha1-q/c9+rc10EVECr/qLZHzieu/oik= + +filenamify@^2.1.0: + version "2.1.0" + resolved "https://registry.yarnpkg.com/filenamify/-/filenamify-2.1.0.tgz#88faf495fb1b47abfd612300002a16228c677ee9" + integrity sha512-ICw7NTT6RsDp2rnYKVd8Fu4cr6ITzGy3+u4vUujPkabyaz+03F24NWEX7fs5fp+kBonlaqPH8fAO2NM+SXt/JA== + dependencies: + filename-reserved-regex "^2.0.0" + strip-outer "^1.0.0" + trim-repeated "^1.0.0" + fill-range@^2.1.0: version "2.2.4" resolved "https://registry.yarnpkg.com/fill-range/-/fill-range-2.2.4.tgz#eb1e773abb056dcd8df2bfdf6af59b8b3a936565" @@ -1119,6 +1406,19 @@ fill-range@^2.1.0: repeat-element "^1.1.2" repeat-string "^1.5.2" +finalhandler@~1.1.2: + version "1.1.2" + resolved "https://registry.yarnpkg.com/finalhandler/-/finalhandler-1.1.2.tgz#b7e7d000ffd11938d0fdb053506f6ebabe9f587d" + integrity sha512-aAWcW57uxVNrQZqFXjITpW3sIUQmHGG3qSb9mUah9MgMC4NeWhNOlNjXEYq3HjRAvL6arUviZGGJsBg6z0zsWA== + dependencies: + debug "2.6.9" + encodeurl "~1.0.2" + escape-html "~1.0.3" + on-finished "~2.3.0" + parseurl "~1.3.3" + statuses "~1.5.0" + unpipe "~1.0.0" + find-up@^4.0.0: version "4.1.0" resolved "https://registry.yarnpkg.com/find-up/-/find-up-4.1.0.tgz#97afe7d6cdc0bc5928584b7c8d7b16e8a9aa5d19" @@ -1146,11 +1446,28 @@ for-own@^0.1.4: dependencies: for-in "^1.0.1" +forwarded@0.2.0: + version "0.2.0" + resolved "https://registry.yarnpkg.com/forwarded/-/forwarded-0.2.0.tgz#2269936428aad4c15c7ebe9779a84bf0b2a81811" + integrity sha512-buRG0fpBtRHSTCOASe6hD258tEubFoRLb4ZNA6NxMVHNw2gOcwHo9wyablzMzOA5z9xA9L1KNjk/Nt6MT9aYow== + +fresh@0.5.2: + version "0.5.2" + resolved "https://registry.yarnpkg.com/fresh/-/fresh-0.5.2.tgz#3d8cadd90d976569fa835ab1f8e4b23a105605a7" + integrity sha1-PYyt2Q2XZWn6g1qx+OSyOhBWBac= + fs-constants@^1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/fs-constants/-/fs-constants-1.0.0.tgz#6be0de9be998ce16af8afc24497b9ee9b7ccd9ad" integrity sha512-y6OAwoSIf7FyjMIv94u+b5rdheZEjzR63GTyZJm5qh4Bi+2YgwLCcI/fPFZkL5PSixOt6ZNKm+w+Hfp/Bciwow== +fs-minipass@^1.2.5: + version "1.2.7" + resolved "https://registry.yarnpkg.com/fs-minipass/-/fs-minipass-1.2.7.tgz#ccff8570841e7fe4265693da88936c55aed7f7c7" + integrity sha512-GWSSJGFy4e9GUeCcbIkED+bgAoFyj7XF1mV8rma3QW4NIqX9Kyx79N/PF61H5udOV3aY1IaMLs6pGbH71nlCTA== + dependencies: + minipass "^2.6.0" + fs.realpath@^1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/fs.realpath/-/fs.realpath-1.0.0.tgz#1504ad2523158caa40db4a2787cb01411994ea4f" @@ -1166,6 +1483,20 @@ function-bind@^1.1.1: resolved "https://registry.yarnpkg.com/function-bind/-/function-bind-1.1.1.tgz#a56899d3ea3c9bab874bb9773b7c5ede92f4895d" integrity sha512-yIovAzMX49sF8Yl58fSCWJ5svSLuaibPxXQJFLmBObTuCr0Mf1KiPopGM9NiFjiYBCbfaa2Fh6breQ6ANVTI0A== +gauge@~2.7.3: + version "2.7.4" + resolved "https://registry.yarnpkg.com/gauge/-/gauge-2.7.4.tgz#2c03405c7538c39d7eb37b317022e325fb018bf7" + integrity sha1-LANAXHU4w51+s3sxcCLjJfsBi/c= + dependencies: + aproba "^1.0.3" + console-control-strings "^1.0.0" + has-unicode "^2.0.0" + object-assign "^4.1.0" + signal-exit "^3.0.0" + string-width "^1.0.1" + strip-ansi "^3.0.1" + wide-align "^1.1.0" + generic-names@^2.0.1: version "2.0.1" resolved "https://registry.yarnpkg.com/generic-names/-/generic-names-2.0.1.tgz#f8a378ead2ccaa7a34f0317b05554832ae41b872" @@ -1301,6 +1632,11 @@ has-symbols@^1.0.1: resolved "https://registry.yarnpkg.com/has-symbols/-/has-symbols-1.0.1.tgz#9f5214758a44196c406d9bd76cebf81ec2dd31e8" integrity sha512-PLcsoqu++dmEIZB+6totNFKq/7Do+Z0u4oT0zKOJNl3lYK6vGwwu2hjHs+68OEZbTjiUE9bgOABXbP/GvrS0Kg== +has-unicode@^2.0.0: + version "2.0.1" + resolved "https://registry.yarnpkg.com/has-unicode/-/has-unicode-2.0.1.tgz#e0e6fe6a28cf51138855e086d1691e771de2a8b9" + integrity sha1-4Ob+aijPUROIVeCG0Wkedx3iqLk= + has@^1.0.0, has@^1.0.3: version "1.0.3" resolved "https://registry.yarnpkg.com/has/-/has-1.0.3.tgz#722d7cbfc1f6aa8241f16dd814e011e1f41e8796" @@ -1333,6 +1669,38 @@ html-comment-regex@^1.1.0: resolved "https://registry.yarnpkg.com/html-comment-regex/-/html-comment-regex-1.1.2.tgz#97d4688aeb5c81886a364faa0cad1dda14d433a7" integrity sha512-P+M65QY2JQ5Y0G9KKdlDpo0zK+/OHptU5AaBwUfAIDJZk1MYf32Frm84EcOytfJE0t5JvkAnKlmjsXDnWzCJmQ== +htmlparser2@^6.1.0: + version "6.1.0" + resolved "https://registry.yarnpkg.com/htmlparser2/-/htmlparser2-6.1.0.tgz#c4d762b6c3371a05dbe65e94ae43a9f845fb8fb7" + integrity sha512-gyyPk6rgonLFEDGoeRgQNaEUvdJ4ktTmmUh/h2t7s+M8oPpIPxgNACWa+6ESR57kXstwqPiCut0V8NRpcwgU7A== + dependencies: + domelementtype "^2.0.1" + domhandler "^4.0.0" + domutils "^2.5.2" + entities "^2.0.0" + +http-errors@1.7.2: + version "1.7.2" + resolved "https://registry.yarnpkg.com/http-errors/-/http-errors-1.7.2.tgz#4f5029cf13239f31036e5b2e55292bcfbcc85c8f" + integrity sha512-uUQBt3H/cSIVfch6i1EuPNy/YsRSOUBXTVfZ+yR7Zjez3qjBz6i9+i4zjNaoqcoFVI4lQJ5plg63TvGfRSDCRg== + dependencies: + depd "~1.1.2" + inherits "2.0.3" + setprototypeof "1.1.1" + statuses ">= 1.5.0 < 2" + toidentifier "1.0.0" + +http-errors@~1.7.2: + version "1.7.3" + resolved "https://registry.yarnpkg.com/http-errors/-/http-errors-1.7.3.tgz#6c619e4f9c60308c38519498c14fbb10aacebb06" + integrity sha512-ZTTX0MWrsQ2ZAhA1cejAwDLycFsd7I7nVtnkT3Ol0aqodaKW+0CTZDQ1uBv5whptCnc8e8HeRRJxRs0kmm/Qfw== + dependencies: + depd "~1.1.2" + inherits "2.0.4" + setprototypeof "1.1.1" + statuses ">= 1.5.0 < 2" + toidentifier "1.0.0" + https-proxy-agent@^5.0.0: version "5.0.0" resolved "https://registry.yarnpkg.com/https-proxy-agent/-/https-proxy-agent-5.0.0.tgz#e2a90542abb68a762e0a0850f6c9edadfd8506b2" @@ -1341,7 +1709,7 @@ https-proxy-agent@^5.0.0: agent-base "6" debug "4" -iconv-lite@^0.4.24: +iconv-lite@0.4.24, iconv-lite@^0.4.24, iconv-lite@^0.4.4: version "0.4.24" resolved "https://registry.yarnpkg.com/iconv-lite/-/iconv-lite-0.4.24.tgz#2022b4b25fbddc21d2f524974a474aafe733908b" integrity sha512-v3MXnZAcvnywkTUEZomIActle7RXXeedOR31wwl7VlyoXO4Qi9arvSenNQWne1TcRwhCL1HwLI21bEqdpj8/rA== @@ -1358,6 +1726,13 @@ ieee754@^1.1.13: resolved "https://registry.yarnpkg.com/ieee754/-/ieee754-1.2.1.tgz#8eb7a10a63fff25d15a57b001586d177d1b0d352" integrity sha512-dcyqhDvX1C46lXZcVqCpK+FtMRQVdIMN6/Df5js2zouUsqG7I6sFxitIC+7KYK29KdXOLHdu9zL4sFnoVQnqaA== +ignore-walk@^3.0.1: + version "3.0.4" + resolved "https://registry.yarnpkg.com/ignore-walk/-/ignore-walk-3.0.4.tgz#c9a09f69b7c7b479a5d74ac1a3c0d4236d2a6335" + integrity sha512-PY6Ii8o1jMRA1z4F2hRkH/xN59ox43DavKvD3oDpfurRlOJyAHpifIwpbdv1n4jt4ov0jSpw3kQ4GhJnpBL6WQ== + dependencies: + minimatch "^3.0.4" + import-cwd@^2.0.0: version "2.1.0" resolved "https://registry.yarnpkg.com/import-cwd/-/import-cwd-2.1.0.tgz#aa6cf36e722761285cb371ec6519f53e2435b0a9" @@ -1417,11 +1792,16 @@ inflight@^1.0.4: once "^1.3.0" wrappy "1" -inherits@2, inherits@^2.0.3, inherits@^2.0.4: +inherits@2, inherits@2.0.4, inherits@^2.0.3, inherits@^2.0.4, inherits@~2.0.3: version "2.0.4" resolved "https://registry.yarnpkg.com/inherits/-/inherits-2.0.4.tgz#0fa2c64f932917c3433a0ded55363aae37416b7c" integrity sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ== +inherits@2.0.3: + version "2.0.3" + resolved "https://registry.yarnpkg.com/inherits/-/inherits-2.0.3.tgz#633c2c83e3da42a502f52466022480f4208261de" + integrity sha1-Yzwsg+PaQqUC9SRmAiSA9CCCYd4= + ini@^1.3.4, ini@~1.3.0: version "1.3.8" resolved "https://registry.yarnpkg.com/ini/-/ini-1.3.8.tgz#a29da425b48806f34767a4efce397269af28432c" @@ -1446,6 +1826,11 @@ inquirer@^6.2.1: strip-ansi "^5.1.0" through "^2.3.6" +ipaddr.js@1.9.1: + version "1.9.1" + resolved "https://registry.yarnpkg.com/ipaddr.js/-/ipaddr.js-1.9.1.tgz#bff38543eeb8984825079ff3a2a8e6cbd46781b3" + integrity sha512-0KI/607xoxSToH7GjN1FfSbLoU0+btTicjsQSWQlh/hZykN8KpmMf7uYwPW3R+akZ6R/w18ZlXSHBYXiYUPO3g== + is-absolute-url@^2.0.0: version "2.1.0" resolved "https://registry.yarnpkg.com/is-absolute-url/-/is-absolute-url-2.1.0.tgz#50530dfb84fcc9aa7dbe7852e83a37b93b9f2aa6" @@ -1529,6 +1914,13 @@ is-extglob@^1.0.0: resolved "https://registry.yarnpkg.com/is-extglob/-/is-extglob-1.0.0.tgz#ac468177c4943405a092fc8f29760c6ffc6206c0" integrity sha1-rEaBd8SUNAWgkvyPKXYMb/xiBsA= +is-fullwidth-code-point@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/is-fullwidth-code-point/-/is-fullwidth-code-point-1.0.0.tgz#ef9e31386f031a7f0d643af82fde50c457ef00cb" + integrity sha1-754xOG8DGn8NZDr4L95QxFfvAMs= + dependencies: + number-is-nan "^1.0.0" + is-fullwidth-code-point@^2.0.0: version "2.0.0" resolved "https://registry.yarnpkg.com/is-fullwidth-code-point/-/is-fullwidth-code-point-2.0.0.tgz#a3b30a5c4f199183167aaab93beefae3ddfb654f" @@ -1644,7 +2036,7 @@ is-symbol@^1.0.2: dependencies: has-symbols "^1.0.1" -isarray@1.0.0: +isarray@1.0.0, isarray@~1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/isarray/-/isarray-1.0.0.tgz#bb935d48582cba168c06834957a54a3e07124f11" integrity sha1-u5NdSFgsuhaMBoNJV6VKPgcSTxE= @@ -1851,6 +2243,11 @@ math-random@^1.0.1: resolved "https://registry.yarnpkg.com/math-random/-/math-random-1.0.4.tgz#5dd6943c938548267016d4e34f057583080c514c" integrity sha512-rUxjysqif/BZQH2yhd5Aaq7vXMSx9NdEsQcyA07uEzIvxgI7zIr33gGsh+RU0/XjmQpCW7RsVof1vlkvQVCK5A== +mdn-data@2.0.14: + version "2.0.14" + resolved "https://registry.yarnpkg.com/mdn-data/-/mdn-data-2.0.14.tgz#7113fc4281917d63ce29b43446f701e68c25ba50" + integrity sha512-dn6wd0uw5GsdswPFfsgMp5NSB0/aDe6fK94YJV/AJDYXL6HVLWBsxeq7js7Ad+mU2K9LAlwpk6kN2D5mwCPVow== + mdn-data@2.0.4: version "2.0.4" resolved "https://registry.yarnpkg.com/mdn-data/-/mdn-data-2.0.4.tgz#699b3c38ac6f1d728091a64650b65d388502fd5b" @@ -1861,11 +2258,26 @@ mdn-data@2.0.6: resolved "https://registry.yarnpkg.com/mdn-data/-/mdn-data-2.0.6.tgz#852dc60fcaa5daa2e8cf6c9189c440ed3e042978" integrity sha512-rQvjv71olwNHgiTbfPZFkJtjNMciWgswYeciZhtvWLO8bmX3TnhyA62I6sTWOyZssWHJJjY6/KiWwqQsWWsqOA== +media-typer@0.3.0: + version "0.3.0" + resolved "https://registry.yarnpkg.com/media-typer/-/media-typer-0.3.0.tgz#8710d7af0aa626f8fffa1ce00168545263255748" + integrity sha1-hxDXrwqmJvj/+hzgAWhUUmMlV0g= + +merge-descriptors@1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/merge-descriptors/-/merge-descriptors-1.0.1.tgz#b00aaa556dd8b44568150ec9d1b953f3f90cbb61" + integrity sha1-sAqqVW3YtEVoFQ7J0blT8/kMu2E= + merge-stream@^2.0.0: version "2.0.0" resolved "https://registry.yarnpkg.com/merge-stream/-/merge-stream-2.0.0.tgz#52823629a14dd00c9770fb6ad47dc6310f2c1f60" integrity sha512-abv/qOcuPfk3URPfDzmZU1LKmuw8kT+0nIHvKrKgFrwifol/doWcdA4ZqsWQ8ENrFKkd67Mfpo/LovbIUsbt3w== +methods@~1.1.2: + version "1.1.2" + resolved "https://registry.yarnpkg.com/methods/-/methods-1.1.2.tgz#5529a4d67654134edcc5266656835b0f851afcee" + integrity sha1-VSmk1nZUE07cxSZmVoNbD4Ua/O4= + micromatch@^2.3.11: version "2.3.11" resolved "https://registry.yarnpkg.com/micromatch/-/micromatch-2.3.11.tgz#86677c97d1720b363431d04d0d15293bd38c1565" @@ -1885,6 +2297,23 @@ micromatch@^2.3.11: parse-glob "^3.0.4" regex-cache "^0.4.2" +mime-db@1.48.0: + version "1.48.0" + resolved "https://registry.yarnpkg.com/mime-db/-/mime-db-1.48.0.tgz#e35b31045dd7eada3aaad537ed88a33afbef2d1d" + integrity sha512-FM3QwxV+TnZYQ2aRqhlKBMHxk10lTbMt3bBkMAp54ddrNeVSfcQYOOKuGuy3Ddrm38I04If834fOUSq1yzslJQ== + +mime-types@~2.1.24: + version "2.1.31" + resolved "https://registry.yarnpkg.com/mime-types/-/mime-types-2.1.31.tgz#a00d76b74317c61f9c2db2218b8e9f8e9c5c9e6b" + integrity sha512-XGZnNzm3QvgKxa8dpzyhFTHmpP3l5YNusmne07VUOXxou9CqUqYa/HBy124RqtVh/O2pECas/MOcsDgpilPOPg== + dependencies: + mime-db "1.48.0" + +mime@1.6.0: + version "1.6.0" + resolved "https://registry.yarnpkg.com/mime/-/mime-1.6.0.tgz#32cd9e5c64553bd58d19a568af452acff04981b1" + integrity sha512-x0Vn8spI+wuJ1O6S7gnbaQg8Pxh4NNHb7KSINmEWKiPE4RKOplvijn+NkmYmmRgP68mc70j2EbeTFRsrswaQeg== + mimic-fn@^1.0.0: version "1.2.0" resolved "https://registry.yarnpkg.com/mimic-fn/-/mimic-fn-1.2.0.tgz#820c86a39334640e99516928bd03fca88057d022" @@ -1912,6 +2341,21 @@ minimist@~0.0.1: resolved "https://registry.yarnpkg.com/minimist/-/minimist-0.0.10.tgz#de3f98543dbf96082be48ad1a0c7cda836301dcf" integrity sha1-3j+YVD2/lggr5IrRoMfNqDYwHc8= +minipass@^2.6.0, minipass@^2.8.6, minipass@^2.9.0: + version "2.9.0" + resolved "https://registry.yarnpkg.com/minipass/-/minipass-2.9.0.tgz#e713762e7d3e32fed803115cf93e04bca9fcc9a6" + integrity sha512-wxfUjg9WebH+CUDX/CdbRlh5SmfZiy/hpkxaRI16Y9W56Pa75sWgd/rvFilSgrauD9NyFymP/+JFV3KwzIsJeg== + dependencies: + safe-buffer "^5.1.2" + yallist "^3.0.0" + +minizlib@^1.2.1: + version "1.3.3" + resolved "https://registry.yarnpkg.com/minizlib/-/minizlib-1.3.3.tgz#2290de96818a34c29551c8a8d301216bd65a861d" + integrity sha512-6ZYMOEnmVsdCeTJVE0W9ZD+pVnE8h9Hma/iOwwRDsdQoePpoX56/8B6z3P9VNwppJuBKNRuFDRNRqRWexT9G9Q== + dependencies: + minipass "^2.9.0" + mitt@^1.1.3: version "1.2.0" resolved "https://registry.yarnpkg.com/mitt/-/mitt-1.2.0.tgz#cb24e6569c806e31bd4e3995787fe38a04fdf90d" @@ -1929,7 +2373,7 @@ mkdirp@0.5.1: dependencies: minimist "0.0.8" -mkdirp@^0.5.1, mkdirp@~0.5.1: +mkdirp@^0.5.0, mkdirp@^0.5.1, mkdirp@^0.5.5, mkdirp@~0.5.1: version "0.5.5" resolved "https://registry.yarnpkg.com/mkdirp/-/mkdirp-0.5.5.tgz#d91cefd62d1436ca0f41620e251288d420099def" integrity sha512-NKmAlESf6jMGym1++R0Ra7wvhV+wFW63FaSOFPwRahvea0gMUcGUhVeAg/0BC0wiv9ih5NYPB1Wn1UEI1/L+xQ== @@ -1958,21 +2402,50 @@ ms@2.0.0: resolved "https://registry.yarnpkg.com/ms/-/ms-2.0.0.tgz#5608aeadfc00be6c2901df5f9861788de0d597c8" integrity sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g= +ms@2.1.1: + version "2.1.1" + resolved "https://registry.yarnpkg.com/ms/-/ms-2.1.1.tgz#30a5864eb3ebb0a66f2ebe6d727af06a09d86e0a" + integrity sha512-tgp+dl5cGk28utYktBsrFqA7HKgrhgPsg6Z/EfhWI4gl1Hwq8B/GmY/0oXZ6nF8hDVesS/FpnYaD/kOWhYQvyg== + ms@2.1.2: version "2.1.2" resolved "https://registry.yarnpkg.com/ms/-/ms-2.1.2.tgz#d09d1f357b443f493382a8eb3ccd183872ae6009" integrity sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w== +ms@^2.1.1: + version "2.1.3" + resolved "https://registry.yarnpkg.com/ms/-/ms-2.1.3.tgz#574c8138ce1d2b5861f0b44579dbadd60c6615b2" + integrity sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA== + mute-stream@0.0.7: version "0.0.7" resolved "https://registry.yarnpkg.com/mute-stream/-/mute-stream-0.0.7.tgz#3075ce93bc21b8fab43e1bc4da7e8115ed1e7bab" integrity sha1-MHXOk7whuPq0PhvE2n6BFe0ee6s= +nan@^2.14.2: + version "2.14.2" + resolved "https://registry.yarnpkg.com/nan/-/nan-2.14.2.tgz#f5376400695168f4cc694ac9393d0c9585eeea19" + integrity sha512-M2ufzIiINKCuDfBSAUr1vWQ+vuVcA9kqx8JJUsbQi6yf1uGRyb7HfpdfUr5qLXf3B/t8dPvcjhKMmlfnP47EzQ== + natural-compare@^1.4.0: version "1.4.0" resolved "https://registry.yarnpkg.com/natural-compare/-/natural-compare-1.4.0.tgz#4abebfeed7541f2c27acfb29bdbbd15c8d5ba4f7" integrity sha1-Sr6/7tdUHywnrPspvbvRXI1bpPc= +needle@^2.5.2: + version "2.7.0" + resolved "https://registry.yarnpkg.com/needle/-/needle-2.7.0.tgz#90e020b9a1e33253fcf009d22927b130c8b2fd8b" + integrity sha512-b4f4JgOl7GZVM1p+xuWBAsHwflng1s2yOu9lOThKAzULRW7eqSFYfN4gbuUFOMuE0hVAPWJnSz/90LMOlEGErw== + dependencies: + debug "^3.2.6" + iconv-lite "^0.4.4" + sax "^1.2.4" + +negotiator@0.6.2: + version "0.6.2" + resolved "https://registry.yarnpkg.com/negotiator/-/negotiator-0.6.2.tgz#feacf7ccf525a77ae9634436a64883ffeca346fb" + integrity sha512-hZXc7K2e+PgeI1eDBe/10Ard4ekbfrrqG8Ep+8Jmf4JID2bNg7NvCPOZN+kfF574pFQI7mum2AUqDidoKqcTOw== + nice-try@^1.0.4: version "1.0.5" resolved "https://registry.yarnpkg.com/nice-try/-/nice-try-1.0.5.tgz#a3378a7696ce7d223e88fc9b764bd7ef1089e366" @@ -1983,11 +2456,43 @@ node-fetch@^2.6.1: resolved "https://registry.yarnpkg.com/node-fetch/-/node-fetch-2.6.1.tgz#045bd323631f76ed2e2b55573394416b639a0052" integrity sha512-V4aYg89jEoVRxRb2fJdAg8FHvI7cEyYdVAh94HH0UIK8oJxUfkjlDQN9RbMx+bEjP7+ggMiFRprSti032Oipxw== +node-libtidy@^0.4.0: + version "0.4.0" + resolved "https://registry.yarnpkg.com/node-libtidy/-/node-libtidy-0.4.0.tgz#794ee52f41e39c8125bc41503539b111c8a37c3c" + integrity sha512-9GMDD68Li87rLUjPI3z/N4KgXGWo3xmk0z5PWvfBlXle1d6EwxenmbBaAwFSVxwo1RwUnP2FTarKrVAIQSfLiA== + dependencies: + nan "^2.14.2" + node-pre-gyp "^0.17.0" + +node-pre-gyp@^0.17.0: + version "0.17.0" + resolved "https://registry.yarnpkg.com/node-pre-gyp/-/node-pre-gyp-0.17.0.tgz#5af3f7b4c3848b5ed00edc3d298ff836daae5f1d" + integrity sha512-abzZt1hmOjkZez29ppg+5gGqdPLUuJeAEwVPtHYEJgx0qzttCbcKFpxrCQn2HYbwCv2c+7JwH4BgEzFkUGpn4A== + dependencies: + detect-libc "^1.0.3" + mkdirp "^0.5.5" + needle "^2.5.2" + nopt "^4.0.3" + npm-packlist "^1.4.8" + npmlog "^4.1.2" + rc "^1.2.8" + rimraf "^2.7.1" + semver "^5.7.1" + tar "^4.4.13" + node-releases@^1.1.71: version "1.1.72" resolved "https://registry.yarnpkg.com/node-releases/-/node-releases-1.1.72.tgz#14802ab6b1039a79a0c7d662b610a5bbd76eacbe" integrity sha512-LLUo+PpH3dU6XizX3iVoubUNheF/owjXCZZ5yACDxNnPtgFuludV1ZL3ayK1kVep42Rmm0+R9/Y60NQbZ2bifw== +nopt@^4.0.3: + version "4.0.3" + resolved "https://registry.yarnpkg.com/nopt/-/nopt-4.0.3.tgz#a375cad9d02fd921278d954c2254d5aa57e15e48" + integrity sha512-CvaGwVMztSMJLOeXPrez7fyfObdZqNUK1cPAEzLHrTybIua9pMdmmPR5YwtfNftIOMv3DPUhFaxsZMNTQO20Kg== + dependencies: + abbrev "1" + osenv "^0.1.4" + normalize-path@^2.0.1: version "2.1.1" resolved "https://registry.yarnpkg.com/normalize-path/-/normalize-path-2.1.1.tgz#1ab28b556e198363a8c1a6f7e6fa20137fe6aed9" @@ -2000,6 +2505,27 @@ normalize-url@^3.0.0: resolved "https://registry.yarnpkg.com/normalize-url/-/normalize-url-3.3.0.tgz#b2e1c4dc4f7c6d57743df733a4f5978d18650559" integrity sha512-U+JJi7duF1o+u2pynbp2zXDW2/PADgC30f0GsHZtRh+HOcXHnw137TrNlyxxRvWW5fjKd3bcLHPxofWuCjaeZg== +npm-bundled@^1.0.1: + version "1.1.2" + resolved "https://registry.yarnpkg.com/npm-bundled/-/npm-bundled-1.1.2.tgz#944c78789bd739035b70baa2ca5cc32b8d860bc1" + integrity sha512-x5DHup0SuyQcmL3s7Rx/YQ8sbw/Hzg0rj48eN0dV7hf5cmQq5PXIeioroH3raV1QC1yh3uTYuMThvEQF3iKgGQ== + dependencies: + npm-normalize-package-bin "^1.0.1" + +npm-normalize-package-bin@^1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/npm-normalize-package-bin/-/npm-normalize-package-bin-1.0.1.tgz#6e79a41f23fd235c0623218228da7d9c23b8f6e2" + integrity sha512-EPfafl6JL5/rU+ot6P3gRSCpPDW5VmIzX959Ob1+ySFUuuYHWHekXpwdUZcKP5C+DS4GEtdJluwBjnsNDl+fSA== + +npm-packlist@^1.4.8: + version "1.4.8" + resolved "https://registry.yarnpkg.com/npm-packlist/-/npm-packlist-1.4.8.tgz#56ee6cc135b9f98ad3d51c1c95da22bbb9b2ef3e" + integrity sha512-5+AZgwru5IevF5ZdnFglB5wNlHG1AOOuw28WhUq8/8emhBmLv6jX5by4WJCh7lW0uSYZYS6DXqIsyZVIXRZU9A== + dependencies: + ignore-walk "^3.0.1" + npm-bundled "^1.0.1" + npm-normalize-package-bin "^1.0.1" + npm-run-path@^2.0.0: version "2.0.2" resolved "https://registry.yarnpkg.com/npm-run-path/-/npm-run-path-2.0.2.tgz#35a9232dfa35d7067b4cb2ddf2357b1871536c5f" @@ -2007,6 +2533,16 @@ npm-run-path@^2.0.0: dependencies: path-key "^2.0.0" +npmlog@^4.1.2: + version "4.1.2" + resolved "https://registry.yarnpkg.com/npmlog/-/npmlog-4.1.2.tgz#08a7f2a8bf734604779a9efa4ad5cc717abb954b" + integrity sha512-2uUqazuKlTaSI/dC8AzicUck7+IrEaOnN/e0jd3Xtt1KcGpwx30v50mL7oPyr/h9bL3E4aZccVwpwP+5W9Vjkg== + dependencies: + are-we-there-yet "~1.1.2" + console-control-strings "~1.1.0" + gauge "~2.7.3" + set-blocking "~2.0.0" + nth-check@^1.0.2: version "1.0.2" resolved "https://registry.yarnpkg.com/nth-check/-/nth-check-1.0.2.tgz#b2bd295c37e3dd58a3bf0700376663ba4d9cf05c" @@ -2014,6 +2550,23 @@ nth-check@^1.0.2: dependencies: boolbase "~1.0.0" +nth-check@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/nth-check/-/nth-check-2.0.0.tgz#1bb4f6dac70072fc313e8c9cd1417b5074c0a125" + integrity sha512-i4sc/Kj8htBrAiH1viZ0TgU8Y5XqCaV/FziYK6TBczxmeKm3AEFWqqF3195yKudrarqy7Zu80Ra5dobFjn9X/Q== + dependencies: + boolbase "^1.0.0" + +number-is-nan@^1.0.0: + version "1.0.1" + resolved "https://registry.yarnpkg.com/number-is-nan/-/number-is-nan-1.0.1.tgz#097b602b53422a522c1afb8790318336941a011d" + integrity sha1-CXtgK1NCKlIsGvuHkDGDNpQaAR0= + +object-assign@^4.1.0: + version "4.1.1" + resolved "https://registry.yarnpkg.com/object-assign/-/object-assign-4.1.1.tgz#2109adc7965887cfc05cbbd442cac8bfbb360863" + integrity sha1-IQmtx5ZYh8/AXLvUQsrIv7s2CGM= + object-inspect@^1.8.0: version "1.8.0" resolved "https://registry.yarnpkg.com/object-inspect/-/object-inspect-1.8.0.tgz#df807e5ecf53a609cc6bfe93eac3cc7be5b3a9d0" @@ -2060,6 +2613,13 @@ object.values@^1.1.0: function-bind "^1.1.1" has "^1.0.3" +on-finished@~2.3.0: + version "2.3.0" + resolved "https://registry.yarnpkg.com/on-finished/-/on-finished-2.3.0.tgz#20f1336481b083cd75337992a16971aa2d906947" + integrity sha1-IPEzZIGwg811M3mSoWlxqi2QaUc= + dependencies: + ee-first "1.1.1" + once@^1.3.0, once@^1.3.1, once@^1.4.0: version "1.4.0" resolved "https://registry.yarnpkg.com/once/-/once-1.4.0.tgz#583b1aa775961d4b113ac17d9c50baef9dd76bd1" @@ -2082,11 +2642,24 @@ optimist@~0.6.0: minimist "~0.0.1" wordwrap "~0.0.2" -os-tmpdir@~1.0.2: +os-homedir@^1.0.0: + version "1.0.2" + resolved "https://registry.yarnpkg.com/os-homedir/-/os-homedir-1.0.2.tgz#ffbc4988336e0e833de0c168c7ef152121aa7fb3" + integrity sha1-/7xJiDNuDoM94MFox+8VISGqf7M= + +os-tmpdir@^1.0.0, os-tmpdir@~1.0.2: version "1.0.2" resolved "https://registry.yarnpkg.com/os-tmpdir/-/os-tmpdir-1.0.2.tgz#bbe67406c79aa85c5cfec766fe5734555dfa1274" integrity sha1-u+Z0BseaqFxc/sdm/lc0VV36EnQ= +osenv@^0.1.4: + version "0.1.5" + resolved "https://registry.yarnpkg.com/osenv/-/osenv-0.1.5.tgz#85cdfafaeb28e8677f416e287592b5f3f49ea410" + integrity sha512-0CWcCECdMVc2Rw3U5w9ZjqX6ga6ubk1xDVKxtBQPK7wis/0F2r9T6k4ydGYhecl7YUBxBVxhL5oisPsNxAPe2g== + dependencies: + os-homedir "^1.0.0" + os-tmpdir "^1.0.0" + p-finally@^1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/p-finally/-/p-finally-1.0.0.tgz#3fbcfb15b899a44123b34b6dcc18b724336a2cae" @@ -2154,6 +2727,23 @@ parse-json@^4.0.0: error-ex "^1.3.1" json-parse-better-errors "^1.0.1" +parse5-htmlparser2-tree-adapter@^6.0.1: + version "6.0.1" + resolved "https://registry.yarnpkg.com/parse5-htmlparser2-tree-adapter/-/parse5-htmlparser2-tree-adapter-6.0.1.tgz#2cdf9ad823321140370d4dbf5d3e92c7c8ddc6e6" + integrity sha512-qPuWvbLgvDGilKc5BoicRovlT4MtYT6JfJyBOMDsKoiT+GiuP5qyrPCnR9HcPECIJJmZh5jRndyNThnhhb/vlA== + dependencies: + parse5 "^6.0.1" + +parse5@^6.0.1: + version "6.0.1" + resolved "https://registry.yarnpkg.com/parse5/-/parse5-6.0.1.tgz#e1a1c085c569b3dc08321184f19a39cc27f7c30b" + integrity sha512-Ofn/CTFzRGTTxwpNEs9PP93gXShHcTq255nzRYSKe8AkVpZY7e1fpmTfOyoIvjP5HG7Z2ZM7VS9PPhQGW2pOpw== + +parseurl@~1.3.3: + version "1.3.3" + resolved "https://registry.yarnpkg.com/parseurl/-/parseurl-1.3.3.tgz#9da19e7bee8d12dff0513ed5b76957793bc2e8d4" + integrity sha512-CiyeOxFT/JZyN5m0z9PfXw4SCBJ6Sygz1Dpl0wqjlhDEGGBP1GnsUVEL0p63hoG1fcj3fHynXi9NYO4nWOL+qQ== + path-exists@^4.0.0: version "4.0.0" resolved "https://registry.yarnpkg.com/path-exists/-/path-exists-4.0.0.tgz#513bdbe2d3b95d7762e8c1137efa195c6c61b5b3" @@ -2179,6 +2769,11 @@ path-parse@^1.0.6: resolved "https://registry.yarnpkg.com/path-parse/-/path-parse-1.0.6.tgz#d62dbb5679405d72c4737ec58600e9ddcf06d24c" integrity sha512-GSmOT2EbHrINBf9SR7CDELwlJ8AENk3Qn7OikK4nFYAu3Ote2+JYNVvkpAEQm3/TLNEJFD/xZJjzyxg3KBWOzw== +path-to-regexp@0.1.7: + version "0.1.7" + resolved "https://registry.yarnpkg.com/path-to-regexp/-/path-to-regexp-0.1.7.tgz#df604178005f522f15eb4490e7247a1bfaa67f8c" + integrity sha1-32BBeABfUi8V60SQ5yR6G/qmf4w= + pathval@^1.1.0: version "1.1.0" resolved "https://registry.yarnpkg.com/pathval/-/pathval-1.1.0.tgz#b942e6d4bde653005ef6b71361def8727d0645e0" @@ -2582,6 +3177,11 @@ pretty-format@^23.6.0: ansi-regex "^3.0.0" ansi-styles "^3.2.0" +process-nextick-args@~2.0.0: + version "2.0.1" + resolved "https://registry.yarnpkg.com/process-nextick-args/-/process-nextick-args-2.0.1.tgz#7820d9b16120cc55ca9ae7792680ae7dba6d7fe2" + integrity sha512-3ouUOpQhtgrbOa17J7+uxOTpITYWaGP7/AhoR3+A+/1e9skrzelGi/dXzEYyvbxubEF6Wn2ypscTKiKJFFn1ag== + progress@^2.0.1: version "2.0.3" resolved "https://registry.yarnpkg.com/progress/-/progress-2.0.3.tgz#7e8cf8d8f5b8f239c1bc68beb4eb78567d572ef8" @@ -2592,6 +3192,14 @@ promise.series@^0.2.0: resolved "https://registry.yarnpkg.com/promise.series/-/promise.series-0.2.0.tgz#2cc7ebe959fc3a6619c04ab4dbdc9e452d864bbd" integrity sha1-LMfr6Vn8OmYZwEq029yeRS2GS70= +proxy-addr@~2.0.5: + version "2.0.7" + resolved "https://registry.yarnpkg.com/proxy-addr/-/proxy-addr-2.0.7.tgz#f19fe69ceab311eeb94b42e70e8c2070f9ba1025" + integrity sha512-llQsMLSUDUPT44jdrU/O37qlnifitDP+ZwrmmZcoSKyLKvtZxpyV0n2/bD/N4tBAAZ/gJEdZU7KMraoK1+XYAg== + dependencies: + forwarded "0.2.0" + ipaddr.js "1.9.1" + proxy-from-env@^1.1.0: version "1.1.0" resolved "https://registry.yarnpkg.com/proxy-from-env/-/proxy-from-env-1.1.0.tgz#e102f16ca355424865755d2c9e8ea4f24d58c3e2" @@ -2633,6 +3241,11 @@ q@^1.1.2: resolved "https://registry.yarnpkg.com/q/-/q-1.5.1.tgz#7e32f75b41381291d04611f1bf14109ac00651d7" integrity sha1-fjL3W0E4EpHQRhHxvxQQmsAGUdc= +qs@6.7.0: + version "6.7.0" + resolved "https://registry.yarnpkg.com/qs/-/qs-6.7.0.tgz#41dc1a015e3d581f1621776be31afb2876a9b1bc" + integrity sha512-VCdBRNFTX1fyE7Nb6FYoURo/SPe62QCaAyzJvUjwRaIsc+NePBEniHlvxFmmX56+HZphIGtV0XeCirBtpDrTyQ== + randomatic@^3.0.0: version "3.1.1" resolved "https://registry.yarnpkg.com/randomatic/-/randomatic-3.1.1.tgz#b776efc59375984e36c537b2f51a1f0aff0da1ed" @@ -2649,7 +3262,22 @@ randombytes@^2.1.0: dependencies: safe-buffer "^5.1.0" -rc@^1.0.1, rc@^1.1.6: +range-parser@~1.2.1: + version "1.2.1" + resolved "https://registry.yarnpkg.com/range-parser/-/range-parser-1.2.1.tgz#3cf37023d199e1c24d1a55b84800c2f3e6468031" + integrity sha512-Hrgsx+orqoygnmhFbKaHE6c296J+HTAQXoxEF6gNupROmmGJRoyzfG3ccAveqCBrwr/2yxQ5BVd/GTl5agOwSg== + +raw-body@2.4.0: + version "2.4.0" + resolved "https://registry.yarnpkg.com/raw-body/-/raw-body-2.4.0.tgz#a1ce6fb9c9bc356ca52e89256ab59059e13d0332" + integrity sha512-4Oz8DUIwdvoa5qMJelxipzi/iJIi40O5cGV1wNYp5hvZP8ZN0T+jiNkL0QepXs+EsQ9XJ8ipEDoiH70ySUJP3Q== + dependencies: + bytes "3.1.0" + http-errors "1.7.2" + iconv-lite "0.4.24" + unpipe "1.0.0" + +rc@^1.0.1, rc@^1.1.6, rc@^1.2.8: version "1.2.8" resolved "https://registry.yarnpkg.com/rc/-/rc-1.2.8.tgz#cd924bf5200a075b83c188cd6b9e211b7fc0d3ed" integrity sha512-y3bGgqKj3QBdxLbLkomlohkvsA8gdAiUQlSBJnBhfn+BPxg4bc62d8TcBW15wavDfgexCgccckhcZvywyQYPOw== @@ -2659,6 +3287,19 @@ rc@^1.0.1, rc@^1.1.6: minimist "^1.2.0" strip-json-comments "~2.0.1" +readable-stream@^2.0.6: + version "2.3.7" + resolved "https://registry.yarnpkg.com/readable-stream/-/readable-stream-2.3.7.tgz#1eca1cf711aef814c04f62252a36a62f6cb23b57" + integrity sha512-Ebho8K4jIbHAxnuxi7o42OrZgF/ZTNcsZj6nRKyUmkhLFq8CHItp/fy6hQZuZmP/n3yZ9VBUbp4zz/mX8hmYPw== + dependencies: + core-util-is "~1.0.0" + inherits "~2.0.3" + isarray "~1.0.0" + process-nextick-args "~2.0.0" + safe-buffer "~5.1.1" + string_decoder "~1.1.1" + util-deprecate "~1.0.1" + readable-stream@^3.1.1, readable-stream@^3.4.0: version "3.6.0" resolved "https://registry.yarnpkg.com/readable-stream/-/readable-stream-3.6.0.tgz#337bbda3adc0706bd3e024426a286d4b4b2c9198" @@ -2758,6 +3399,13 @@ rgba-regex@^1.0.0: resolved "https://registry.yarnpkg.com/rgba-regex/-/rgba-regex-1.0.0.tgz#43374e2e2ca0968b0ef1523460b7d730ff22eeb3" integrity sha1-QzdOLiyglosO8VI0YLfXMP8i7rM= +rimraf@^2.7.1: + version "2.7.1" + resolved "https://registry.yarnpkg.com/rimraf/-/rimraf-2.7.1.tgz#35797f13a7fdadc566142c29d4f07ccad483e3ec" + integrity sha512-uWjbaKIK3T1OSVptzX7Nl6PvQ3qAGtKEtVRjRuazjfL3Bx5eI409VZSqgND+4UNnmzLVdPj9FqFJNPqBZFve4w== + dependencies: + glob "^7.1.3" + rimraf@^3.0.2: version "3.0.2" resolved "https://registry.yarnpkg.com/rimraf/-/rimraf-3.0.2.tgz#f1a5402ba6220ad52cc1282bac1ae3aa49fd061a" @@ -2862,7 +3510,12 @@ rxjs@^6.4.0: dependencies: tslib "^1.9.0" -safe-buffer@^5.0.1, safe-buffer@^5.1.0, safe-buffer@~5.2.0: +safe-buffer@5.1.2, safe-buffer@~5.1.0, safe-buffer@~5.1.1: + version "5.1.2" + resolved "https://registry.yarnpkg.com/safe-buffer/-/safe-buffer-5.1.2.tgz#991ec69d296e0313747d59bdfd2b745c35f8828d" + integrity sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g== + +safe-buffer@^5.0.1, safe-buffer@^5.1.0, safe-buffer@^5.1.2, safe-buffer@~5.2.0: version "5.2.1" resolved "https://registry.yarnpkg.com/safe-buffer/-/safe-buffer-5.2.1.tgz#1eaf9fa9bdb1fdd4ec75f58f9cdb4e6b7827eec6" integrity sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ== @@ -2877,7 +3530,7 @@ safe-identifier@^0.4.1: resolved "https://registry.yarnpkg.com/safer-buffer/-/safer-buffer-2.1.2.tgz#44fa161b0187b9549dd84bb91802f9bd8385cd6a" integrity sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg== -sax@~1.2.4: +sax@^1.2.4, sax@~1.2.4: version "1.2.4" resolved "https://registry.yarnpkg.com/sax/-/sax-1.2.4.tgz#2816234e2378bddc4e5354fab5caa895df7100d9" integrity sha512-NqVDv9TpANUjFm0N8uM5GxL36UgKi9/atZw+x7YFnQ8ckwFGKrl4xX4yWtrey3UJm5nP1kUbnYgLopqWNSRhWw== @@ -2889,11 +3542,30 @@ semver-diff@^2.0.0: dependencies: semver "^5.0.3" -semver@^5.0.3, semver@^5.1.0, semver@^5.5.0: +semver@^5.0.3, semver@^5.1.0, semver@^5.5.0, semver@^5.7.1: version "5.7.1" resolved "https://registry.yarnpkg.com/semver/-/semver-5.7.1.tgz#a954f931aeba508d307bbf069eff0c01c96116f7" integrity sha512-sauaDf/PZdVgrLTNYHRtpXa1iRiKcaebiKQ1BJdpQlWH2lCvexQdX55snPFyK7QzpudqbCI0qXFfOasHdyNDGQ== +send@0.17.1: + version "0.17.1" + resolved "https://registry.yarnpkg.com/send/-/send-0.17.1.tgz#c1d8b059f7900f7466dd4938bdc44e11ddb376c8" + integrity sha512-BsVKsiGcQMFwT8UxypobUKyv7irCNRHk1T0G680vk88yf6LBByGcZJOTJCrTP2xVN6yI+XjPJcNuE3V4fT9sAg== + dependencies: + debug "2.6.9" + depd "~1.1.2" + destroy "~1.0.4" + encodeurl "~1.0.2" + escape-html "~1.0.3" + etag "~1.8.1" + fresh "0.5.2" + http-errors "~1.7.2" + mime "1.6.0" + ms "2.1.1" + on-finished "~2.3.0" + range-parser "~1.2.1" + statuses "~1.5.0" + serialize-javascript@^4.0.0: version "4.0.0" resolved "https://registry.yarnpkg.com/serialize-javascript/-/serialize-javascript-4.0.0.tgz#b525e1238489a5ecfc42afacc3fe99e666f4b1aa" @@ -2901,6 +3573,26 @@ serialize-javascript@^4.0.0: dependencies: randombytes "^2.1.0" +serve-static@1.14.1: + version "1.14.1" + resolved "https://registry.yarnpkg.com/serve-static/-/serve-static-1.14.1.tgz#666e636dc4f010f7ef29970a88a674320898b2f9" + integrity sha512-JMrvUwE54emCYWlTI+hGrGv5I8dEwmco/00EvkzIIsR7MqrHonbD9pO2MOfFnpFntl7ecpZs+3mW+XbQZu9QCg== + dependencies: + encodeurl "~1.0.2" + escape-html "~1.0.3" + parseurl "~1.3.3" + send "0.17.1" + +set-blocking@~2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/set-blocking/-/set-blocking-2.0.0.tgz#045f9782d011ae9a6803ddd382b24392b3d890f7" + integrity sha1-BF+XgtARrppoA93TgrJDkrPYkPc= + +setprototypeof@1.1.1: + version "1.1.1" + resolved "https://registry.yarnpkg.com/setprototypeof/-/setprototypeof-1.1.1.tgz#7e95acb24aa92f5885e0abef5ba131330d4ae683" + integrity sha512-JvdAWfbXeIGaZ9cILp38HntZSFSo3mWg6xGcJJsd+d4aRMOqauag1C63dJfDw7OaMYwEbHMOxEZ1lqVRYP2OAw== + shebang-command@^1.2.0: version "1.2.0" resolved "https://registry.yarnpkg.com/shebang-command/-/shebang-command-1.2.0.tgz#44aac65b695b03398968c39f363fee5deafdf1ea" @@ -2968,12 +3660,26 @@ stack-utils@^1.0.1: resolved "https://registry.yarnpkg.com/stack-utils/-/stack-utils-1.0.2.tgz#33eba3897788558bebfc2db059dc158ec36cebb8" integrity sha512-MTX+MeG5U994cazkjd/9KNAapsHnibjMLnfXodlkXw76JEea0UiNzrqidzo1emMwk7w5Qhc9jd4Bn9TBb1MFwA== +"statuses@>= 1.5.0 < 2", statuses@~1.5.0: + version "1.5.0" + resolved "https://registry.yarnpkg.com/statuses/-/statuses-1.5.0.tgz#161c7dac177659fd9811f43771fa99381478628c" + integrity sha1-Fhx9rBd2Wf2YEfQ3cfqZOBR4Yow= + string-hash@^1.1.1: version "1.1.3" resolved "https://registry.yarnpkg.com/string-hash/-/string-hash-1.1.3.tgz#e8aafc0ac1855b4666929ed7dd1275df5d6c811b" integrity sha1-6Kr8CsGFW0Zmkp7X3RJ1311sgRs= -string-width@^2.0.0, string-width@^2.1.0, string-width@^2.1.1: +string-width@^1.0.1: + version "1.0.2" + resolved "https://registry.yarnpkg.com/string-width/-/string-width-1.0.2.tgz#118bdf5b8cdc51a2a7e70d211e07e2b0b9b107d3" + integrity sha1-EYvfW4zcUaKn5w0hHgfisLmxB9M= + dependencies: + code-point-at "^1.0.0" + is-fullwidth-code-point "^1.0.0" + strip-ansi "^3.0.0" + +"string-width@^1.0.2 || 2", string-width@^2.0.0, string-width@^2.1.0, string-width@^2.1.1: version "2.1.1" resolved "https://registry.yarnpkg.com/string-width/-/string-width-2.1.1.tgz#ab93f27a8dc13d28cac815c462143a6d9012ae9e" integrity sha512-nOqH59deCq9SRHlxq1Aw85Jnt4w6KvLKqWVik6oA9ZklXLNIOlqg4F2yrT1MVaTjAqvVwdfeZ7w7aCvJD7ugkw== @@ -3004,7 +3710,14 @@ string_decoder@^1.1.1: dependencies: safe-buffer "~5.2.0" -strip-ansi@^3.0.0: +string_decoder@~1.1.1: + version "1.1.1" + resolved "https://registry.yarnpkg.com/string_decoder/-/string_decoder-1.1.1.tgz#9cf1611ba62685d7030ae9e4ba34149c3af03fc8" + integrity sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg== + dependencies: + safe-buffer "~5.1.0" + +strip-ansi@^3.0.0, strip-ansi@^3.0.1: version "3.0.1" resolved "https://registry.yarnpkg.com/strip-ansi/-/strip-ansi-3.0.1.tgz#6a385fb8853d952d5ff05d0e8aaf94278dc63dcf" integrity sha1-ajhfuIU9lS1f8F0Oiq+UJ43GPc8= @@ -3035,6 +3748,13 @@ strip-json-comments@~2.0.1: resolved "https://registry.yarnpkg.com/strip-json-comments/-/strip-json-comments-2.0.1.tgz#3c531942e908c2697c0ec344858c286c7ca0a60a" integrity sha1-PFMZQukIwml8DsNEhYwobHygpgo= +strip-outer@^1.0.0: + version "1.0.1" + resolved "https://registry.yarnpkg.com/strip-outer/-/strip-outer-1.0.1.tgz#b2fd2abf6604b9d1e6013057195df836b8a9d631" + integrity sha512-k55yxKHwaXnpYGsOzg4Vl8+tDrWylxDEpknGjhTiZB8dFRU5rTo9CAzeycivxV3s+zlTKwrs6WxMxR95n26kwg== + dependencies: + escape-string-regexp "^1.0.2" + style-inject@^0.3.0: version "0.3.0" resolved "https://registry.yarnpkg.com/style-inject/-/style-inject-0.3.0.tgz#d21c477affec91811cc82355832a700d22bf8dd3" @@ -3129,6 +3849,19 @@ tar-stream@^2.1.4: inherits "^2.0.3" readable-stream "^3.1.1" +tar@^4.4.13: + version "4.4.13" + resolved "https://registry.yarnpkg.com/tar/-/tar-4.4.13.tgz#43b364bc52888d555298637b10d60790254ab525" + integrity sha512-w2VwSrBoHa5BsSyH+KxEqeQBAllHhccyMFVHtGtdMpF4W7IRWfZjFiQceJPChOeTsSDVUpER2T8FA93pr0L+QA== + dependencies: + chownr "^1.1.1" + fs-minipass "^1.2.5" + minipass "^2.8.6" + minizlib "^1.2.1" + mkdirp "^0.5.0" + safe-buffer "^5.1.2" + yallist "^3.0.3" + term-size@^1.2.0: version "1.2.0" resolved "https://registry.yarnpkg.com/term-size/-/term-size-1.2.0.tgz#458b83887f288fc56d6fffbfad262e26638efa69" @@ -3172,6 +3905,18 @@ to-fast-properties@^1.0.3: resolved "https://registry.yarnpkg.com/to-fast-properties/-/to-fast-properties-1.0.3.tgz#b83571fa4d8c25b82e231b06e3a3055de4ca1a47" integrity sha1-uDVx+k2MJbguIxsG46MFXeTKGkc= +toidentifier@1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/toidentifier/-/toidentifier-1.0.0.tgz#7e1be3470f1e77948bc43d94a3c8f4d7752ba553" + integrity sha512-yaOH/Pk/VEhBWWTlhI+qXxDFXlejDGcQipMlyxda9nthulaxLZUNcUqFxokp0vcYnvteJln5FNQDRrxj3YcbVw== + +trim-repeated@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/trim-repeated/-/trim-repeated-1.0.0.tgz#e3646a2ea4e891312bf7eace6cfb05380bc01c21" + integrity sha1-42RqLqTokTEr9+rObPsFOAvAHCE= + dependencies: + escape-string-regexp "^1.0.2" + ts-node@^7.0.1: version "7.0.1" resolved "https://registry.yarnpkg.com/ts-node/-/ts-node-7.0.1.tgz#9562dc2d1e6d248d24bc55f773e3f614337d9baf" @@ -3191,6 +3936,11 @@ tslib@^1.9.0, tslib@^1.9.3: resolved "https://registry.yarnpkg.com/tslib/-/tslib-1.14.1.tgz#cf2d38bdc34a134bcaf1091c41f6619e2f672d00" integrity sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg== +tslib@^2.2.0: + version "2.3.0" + resolved "https://registry.yarnpkg.com/tslib/-/tslib-2.3.0.tgz#803b8cdab3e12ba581a4ca41c8839bbb0dacb09e" + integrity sha512-N82ooyxVNm6h1riLCoyS9e3fuJ3AMG2zIZs2Gd1ATcSFjSA23Q0fzjjZeh0jbJvWVDZ0cJT8yaNNaaXHzueNjg== + tslint@^4.5.1: version "4.5.1" resolved "https://registry.yarnpkg.com/tslint/-/tslint-4.5.1.tgz#05356871bef23a434906734006fc188336ba824b" @@ -3216,6 +3966,14 @@ type-detect@^4.0.0, type-detect@^4.0.5: resolved "https://registry.yarnpkg.com/type-detect/-/type-detect-4.0.8.tgz#7646fb5f18871cfbb7749e69bd39a6388eb7450c" integrity sha512-0fr/mIH1dlO+x7TlcMy+bIDqKPsw/70tVyeHW787goQjhmqaZe10uwLujubK9q9Lg6Fiho1KUKDYz0Z7k7g5/g== +type-is@~1.6.17, type-is@~1.6.18: + version "1.6.18" + resolved "https://registry.yarnpkg.com/type-is/-/type-is-1.6.18.tgz#4e552cd05df09467dcbc4ef739de89f2cf37c131" + integrity sha512-TkRKr9sUTxEH8MdfuCSP7VizJyzRNMjj2J2do2Jr3Kym598JVdEksuzPQCnlFPW4ky9Q+iA+ma9BGm06XQBy8g== + dependencies: + media-typer "0.3.0" + mime-types "~2.1.24" + typescript@^3.9.5: version "3.9.7" resolved "https://registry.yarnpkg.com/typescript/-/typescript-3.9.7.tgz#98d600a5ebdc38f40cb277522f12dc800e9e25fa" @@ -3246,6 +4004,11 @@ unique-string@^1.0.0: dependencies: crypto-random-string "^1.0.0" +unpipe@1.0.0, unpipe@~1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/unpipe/-/unpipe-1.0.0.tgz#b2bf4ee8514aae6165b4817829d21b2ef49904ec" + integrity sha1-sr9O6FFKrmFltIF4KdIbLvSZBOw= + unquote@~1.1.1: version "1.1.1" resolved "https://registry.yarnpkg.com/unquote/-/unquote-1.1.1.tgz#8fded7324ec6e88a0ff8b905e7c098cdc086d544" @@ -3279,7 +4042,7 @@ url-parse-lax@^1.0.0: dependencies: prepend-http "^1.0.1" -util-deprecate@^1.0.1, util-deprecate@^1.0.2: +util-deprecate@^1.0.1, util-deprecate@^1.0.2, util-deprecate@~1.0.1: version "1.0.2" resolved "https://registry.yarnpkg.com/util-deprecate/-/util-deprecate-1.0.2.tgz#450d4dc9fa70de732762fbd2d4a28981419a0ccf" integrity sha1-RQ1Nyfpw3nMnYvvS1KKJgUGaDM8= @@ -3294,6 +4057,16 @@ util.promisify@^1.0.0, util.promisify@~1.0.0: has-symbols "^1.0.1" object.getownpropertydescriptors "^2.1.0" +utils-merge@1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/utils-merge/-/utils-merge-1.0.1.tgz#9f95710f50a267947b2ccc124741c1028427e713" + integrity sha1-n5VxD1CiZ5R7LMwSR0HBAoQn5xM= + +vary@~1.1.2: + version "1.1.2" + resolved "https://registry.yarnpkg.com/vary/-/vary-1.1.2.tgz#2299f02c6ded30d4a5961b0b9f74524a18f634fc" + integrity sha1-IpnwLG3tMNSllhsLn3RSShj2NPw= + vendors@^1.0.0: version "1.0.4" resolved "https://registry.yarnpkg.com/vendors/-/vendors-1.0.4.tgz#e2b800a53e7a29b93506c3cf41100d16c4c4ad8e" @@ -3306,6 +4079,13 @@ which@^1.2.9: dependencies: isexe "^2.0.0" +wide-align@^1.1.0: + version "1.1.3" + resolved "https://registry.yarnpkg.com/wide-align/-/wide-align-1.1.3.tgz#ae074e6bdc0c14a431e804e624549c633b000457" + integrity sha512-QGkOQc8XL6Bt5PwnsExKBPuMKBxnGxWWW3fU55Xt4feHozMUhdUMaBCk290qpm/wG5u/RSKzwdAC4i51YigihA== + dependencies: + string-width "^1.0.2 || 2" + widest-line@^2.0.0: version "2.0.1" resolved "https://registry.yarnpkg.com/widest-line/-/widest-line-2.0.1.tgz#7438764730ec7ef4381ce4df82fb98a53142a3fc" @@ -3347,6 +4127,11 @@ yallist@^2.1.2: resolved "https://registry.yarnpkg.com/yallist/-/yallist-2.1.2.tgz#1c11f9218f076089a47dd512f93c6699a6a81d52" integrity sha1-HBH5IY8HYImkfdUS+TxmmaaoHVI= +yallist@^3.0.0, yallist@^3.0.3: + version "3.1.1" + resolved "https://registry.yarnpkg.com/yallist/-/yallist-3.1.1.tgz#dbb7daf9bfd8bac9ab45ebf602b8cbad0d5d08fd" + integrity sha512-a4UGQaWPH59mOXUYnAG2ewncQS4i4F43Tv3JoAM+s2VDAmS9NsK8GpDMLrCHPksFT7h3K6TOoUNn2pb7RoXx4g== + yauzl@^2.10.0: version "2.10.0" resolved "https://registry.yarnpkg.com/yauzl/-/yauzl-2.10.0.tgz#c7eb17c93e112cb1086fa6d8e51fb0667b79a5f9" From 5f31a1daeda8b39bbbacbb2f5205dc095e6b7a02 Mon Sep 17 00:00:00 2001 From: Justin Halsall Date: Mon, 5 Jul 2021 10:51:37 +0200 Subject: [PATCH 08/18] move restoreNodeSheet to it's own module --- package.json | 7 +- src/replay/index.ts | 49 ++- src/replay/virtual-styles.ts | 32 ++ test/__snapshots__/replayer.test.ts.snap | 211 +++++++++++++ test/events/style-sheet-rule-events.ts | 20 +- test/replayer.test.ts | 73 +++-- test/replayer/virtual-styles.test.ts | 65 ++++ yarn.lock | 365 ++++++++++++++++++++++- 8 files changed, 768 insertions(+), 54 deletions(-) create mode 100644 src/replay/virtual-styles.ts create mode 100644 test/replayer/virtual-styles.test.ts diff --git a/package.json b/package.json index 609fa93746..7b6245c01f 100644 --- a/package.json +++ b/package.json @@ -5,7 +5,8 @@ "scripts": { "prepare": "npm run prepack", "prepack": "npm run bundle", - "test": "npm run bundle:browser && cross-env TS_NODE_CACHE=false TS_NODE_FILES=true mocha -r ts-node/register test/**/*.test.ts", + "test": "npm run bundle:browser && cross-env TS_NODE_CACHE=false TS_NODE_FILES=true mocha -r ts-node/register -r ignore-styles -r jsdom-global/register test/**/*.test.ts", + "test:headless": "npm run bundle:browser && cross-env TS_NODE_CACHE=false TS_NODE_FILES=true PUPPETEER_HEADLESS=true mocha -r ts-node/register -r ignore-styles -r jsdom-global/register test/**/*.test.ts", "test:watch": "PUPPETEER_HEADLESS=true npm run test -- --watch --watch-extensions js,ts", "repl": "npm run bundle:browser && cross-env TS_NODE_CACHE=false TS_NODE_FILES=true ts-node scripts/repl.ts", "bundle:browser": "cross-env BROWSER_ONLY=true rollup --config", @@ -39,14 +40,18 @@ "devDependencies": { "@types/chai": "^4.1.6", "@types/inquirer": "0.0.43", + "@types/jsdom": "^16.2.12", "@types/mocha": "^5.2.5", "@types/node": "^10.11.7", "@types/puppeteer": "^5.4.3", "chai": "^4.2.0", "cross-env": "^5.2.0", "fast-mhtml": "^1.1.9", + "ignore-styles": "^5.0.1", "inquirer": "^6.2.1", "jest-snapshot": "^23.6.0", + "jsdom": "^16.6.0", + "jsdom-global": "^3.0.2", "mocha": "^5.2.0", "node-libtidy": "^0.4.0", "prettier": "2.2.1", diff --git a/src/replay/index.ts b/src/replay/index.ts index 47d75cc208..0089ff46a2 100644 --- a/src/replay/index.ts +++ b/src/replay/index.ts @@ -42,6 +42,10 @@ import { } from '../utils'; import getInjectStyleRules from './styles/inject-style'; import './styles/style.css'; +import { + applyVirtualStyleRulesToNode, + VirtualStyleRulesMap, +} from './virtual-styles'; const SKIP_TIME_THRESHOLD = 10 * 1000; const SKIP_TIME_INTERVAL = 5 * 1000; @@ -86,7 +90,7 @@ export class Replayer { private fragmentParentMap!: Map; private elementStateMap!: Map; // Hold the list of CSSRules during in-memory state restoration - private virtualStyleRulesMap!: Map; + private virtualStyleRulesMap!: VirtualStyleRulesMap; private imageMap: Map = new Map(); @@ -130,7 +134,7 @@ export class Replayer { this.treeIndex = new TreeIndex(); this.fragmentParentMap = new Map(); this.elementStateMap = new Map(); - this.virtualStyleRulesMap = new Map(); + this.virtualStyleRulesMap = new Map(); this.emitter.on(ReplayerEvents.Flush, () => { const { scrollMap, inputMap } = this.treeIndex.flush(); @@ -946,14 +950,21 @@ export class Replayer { if (!this.virtualStyleRulesMap.has(target)) { this.virtualStyleRulesMap.set( target, - Array.from(styleEl.sheet?.rules || []), + Array.from(styleEl.sheet?.cssRules || []).map((rule, index) => [ + rule, + index, + ]), // { - styleSheet?.insertRule(rule.cssText, index); + existingRules.forEach(([rule, index]) => { + if (rule) { + styleSheet?.insertRule(rule.cssText, index); + } else { + styleSheet?.deleteRule(index); + } }); } } @@ -964,7 +975,7 @@ export class Replayer { const _index = index === undefined ? undefined - : Math.min(index, styleSheet.rules.length); + : Math.min(index, styleSheet.cssRules.length); try { styleSheet.insertRule(rule, _index); } catch (e) { @@ -984,6 +995,8 @@ export class Replayer { if (d.removes) { d.removes.forEach(({ index }) => { + if (usingVirtualParent) { + } try { styleSheet.deleteRule(index); } catch (e) { @@ -997,7 +1010,10 @@ export class Replayer { // Update rules list according to new styleSheet this.virtualStyleRulesMap.set( target, - Array.from(styleSheet?.rules || []), + Array.from(styleSheet?.cssRules || []).map((rule, index) => [ + rule, + index, + ]), ); } if (usingVirtualParent && placeholderNode) { @@ -1571,24 +1587,7 @@ export class Replayer { const styleNode = (node as unknown) as HTMLStyleElement; - storedRules.forEach((rule, index) => { - // Esnure consistency of rules list - if (styleNode?.sheet?.rules[index]) { - styleNode.sheet?.deleteRule(index); - } - styleNode.sheet?.insertRule(rule.cssText, index); - }); - // Avoid situation, when your Node has more styles, than it should - // Otherwise, inserting will be broken - if (styleNode.sheet && styleNode.sheet.rules.length > storedRules.length) { - for ( - let i = styleNode.sheet.rules.length - 1; - i < storedRules.length - 1; - i-- - ) { - styleNode.sheet.removeRule(i); - } - } + applyVirtualStyleRulesToNode(storedRules, styleNode); } private warnNodeNotFound(d: incrementalData, id: number) { diff --git a/src/replay/virtual-styles.ts b/src/replay/virtual-styles.ts new file mode 100644 index 0000000000..6c0367868a --- /dev/null +++ b/src/replay/virtual-styles.ts @@ -0,0 +1,32 @@ +import { INode } from 'rrweb-snapshot'; + +export type VirtualStyleRules = [CSSRule | false, number][]; +export type VirtualStyleRulesMap = Map; + +export function applyVirtualStyleRulesToNode( + storedRules: VirtualStyleRules, + styleNode: HTMLStyleElement, +) { + storedRules.forEach(([rule, index]) => { + // Ensure consistency of cssRules list + // if (styleNode?.sheet?.cssRules[index]) { + // styleNode.sheet?.deleteRule(index); + // } + if (rule) { + styleNode.sheet?.insertRule(rule.cssText, index); + } else { + styleNode.sheet?.deleteRule(index); + } + }); + // Avoid situation, when your Node has more styles, than it should + // Otherwise, inserting will be broken + if (styleNode.sheet && styleNode.sheet.cssRules.length > storedRules.length) { + for ( + let i = styleNode.sheet.cssRules.length - 1; + i < storedRules.length - 1; + i-- + ) { + styleNode.sheet.removeRule(i); + } + } +} diff --git a/test/__snapshots__/replayer.test.ts.snap b/test/__snapshots__/replayer.test.ts.snap index 046df0ac28..bef7cf98e2 100644 --- a/test/__snapshots__/replayer.test.ts.snap +++ b/test/__snapshots__/replayer.test.ts.snap @@ -60,3 +60,214 @@ file-cid-2 .css-lsxxx { padding-left: 4rem; } " `; + +exports[`style-sheet-rule-events-pause-at-1500 1`] = ` +"file-frame-4 + + + + + + +
+
+ +
+ + + + +file-frame-5 + + + + + + + + + + + + string + + + + +file-cid-0 +@charset \\"utf-8\\"; + +.rr-block { background: rgb(204, 204, 204); } + +noscript { display: none !important; } + +html.rrweb-paused * { animation-play-state: paused !important; } + + +file-cid-1 +@charset \\"utf-8\\"; + +.c011xx { padding: 1.3125rem; flex: 0 0 auto; width: 100%; } + + +file-cid-2 +@charset \\"utf-8\\"; + +.c01x { opacity: 1; transform: translateX(0px); } + + +file-cid-3 +@charset \\"utf-8\\"; + +.css-1fbxx79 { display: flex; flex-direction: column; min-width: 60rem; min-height: 100vh; color: blue; } + +.css-1uxxxx3 { position: fixed; top: 0px; right: 0px; left: 4rem; z-index: 15; flex-shrink: 0; height: 0.25rem; overflow: hidden; background-color: rgb(17, 171, 209); } + +.css-1c9xxxx { height: 0.25rem; background-color: rgb(190, 232, 242); opacity: 0; transition: opacity 0.5s ease 0s; } + +.css-lsxxx { padding-left: 4rem; } +" +`; + +exports[`style-sheet-rule-events-pause-at-2500 1`] = ` +"file-frame-4 + + + + + + +
+
+ +
+ + + + +file-frame-5 + + + + + + + + + + + + string + + + + +file-cid-0 +@charset \\"utf-8\\"; + +.rr-block { background: rgb(204, 204, 204); } + +noscript { display: none !important; } + +html.rrweb-paused * { animation-play-state: paused !important; } + + +file-cid-1 +@charset \\"utf-8\\"; + +.c011xx { padding: 1.3125rem; flex: 0 0 auto; width: 100%; } + + +file-cid-2 +@charset \\"utf-8\\"; + +.c01x { opacity: 1; transform: translateX(0px); } + + +file-cid-3 +@charset \\"utf-8\\"; + +.css-1fbxx79 { display: flex; flex-direction: column; min-width: 60rem; min-height: 100vh; color: blue; } + +.css-1uxxxx3 { position: fixed; top: 0px; right: 0px; left: 4rem; z-index: 15; flex-shrink: 0; height: 0.25rem; overflow: hidden; background-color: rgb(17, 171, 209); } + +.css-lsxxx { padding-left: 4rem; } +" +`; + +exports[`style-sheet-rule-events-play-at-1500 1`] = ` +"file-frame-4 + + + + + + +
+
+ +
+ + + + +file-frame-5 + + + + + + + + + + + + string + + + + +file-cid-0 +@charset \\"utf-8\\"; + +.rr-block { background: rgb(204, 204, 204); } + +noscript { display: none !important; } + +html.rrweb-paused * { animation-play-state: paused !important; } + + +file-cid-1 +@charset \\"utf-8\\"; + +.c011xx { padding: 1.3125rem; flex: 0 0 auto; width: 100%; } + + +file-cid-2 +@charset \\"utf-8\\"; + +.c01x { opacity: 1; transform: translateX(0px); } + + +file-cid-3 +@charset \\"utf-8\\"; + +.css-1fbxx79 { display: flex; flex-direction: column; min-width: 60rem; min-height: 100vh; color: blue; } + +.css-1uxxxx3 { position: fixed; top: 0px; right: 0px; left: 4rem; z-index: 15; flex-shrink: 0; height: 0.25rem; overflow: hidden; background-color: rgb(17, 171, 209); } + +.css-1c9xxxx { height: 0.25rem; background-color: rgb(190, 232, 242); opacity: 0; transition: opacity 0.5s ease 0s; } + +.css-lsxxx { padding-left: 4rem; } +" +`; diff --git a/test/events/style-sheet-rule-events.ts b/test/events/style-sheet-rule-events.ts index bc56eae457..5e6f1ae33c 100644 --- a/test/events/style-sheet-rule-events.ts +++ b/test/events/style-sheet-rule-events.ts @@ -79,7 +79,23 @@ const events: eventWithTime[] = [ type: 2, tagName: 'body', attributes: {}, - childNodes: [], + childNodes: [ + { + id: 108, + type: 2, + tagName: 'a', + attributes: { + class: 'css-1fbxx79', + }, + childNodes: [ + { + id: 109, + type: 3, + textContent: 'string', + }, + ], + }, + ], }, ], }, @@ -132,7 +148,7 @@ const events: eventWithTime[] = [ adds: [ { rule: - '.css-1fbxx79{display:-webkit-box;display:-webkit-flex;display:-ms-flexbox;display:flex;-webkit-flex-direction:column;-ms-flex-direction:column;flex-direction:column;min-width:60rem;min-height:100vh;}', + '.css-1fbxx79{display:-webkit-box;display:-webkit-flex;display:-ms-flexbox;display:flex;-webkit-flex-direction:column;-ms-flex-direction:column;flex-direction:column;min-width:60rem;min-height:100vh;color:blue;}', index: 2, }, ], diff --git a/test/replayer.test.ts b/test/replayer.test.ts index 98af6ac8f8..663c576dcc 100644 --- a/test/replayer.test.ts +++ b/test/replayer.test.ts @@ -148,28 +148,41 @@ describe('replayer', function (this: ISuite) { replayer['timer']['actions'].length; `); + expect(actionLength).to.equal( + styleSheetRuleEvents.filter( + (e) => e.timestamp - styleSheetRuleEvents[0].timestamp >= 1500, + ).length, + ); + await assertDomSnapshot( this.page, __filename, - 'style-sheet-rule-events-1500', + 'style-sheet-rule-events-play-at-1500', ); - const result = await this.page.evaluate(` - const rules = Array.from(replayer.iframe.contentDocument.head.children) - .filter(x=>x.nodeName === 'STYLE') - .reduce((acc, node) => { - acc.push(...node.sheet.rules); - return acc; - }, []); - - rules.some(x=>x.selectorText === ".css-1fbxx79") + const rules = [...replayer.iframe.contentDocument.styleSheets].map( + (sheet) => sheet.rules, + ); + rules.some((x) => x.selectorText === '.css-1fbxx79'); `); - expect(actionLength).to.equal( - styleSheetRuleEvents.filter( - (e) => e.timestamp - styleSheetRuleEvents[0].timestamp >= 1500, - ).length, + expect(result).to.equal(true); + }); + + it('should apply fast forwarded StyleSheetRules that where added', async () => { + await this.page.evaluate( + `events = ${JSON.stringify(styleSheetRuleEvents)}`, ); + const result = await this.page.evaluate(` + const { Replayer } = rrweb; + const replayer = new Replayer(events); + replayer.pause(1500); + const rules = [...replayer.iframe.contentDocument.styleSheets].map( + (sheet) => [...sheet.rules], + ).flat(); + rules.some((x) => x.selectorText === '.css-1fbxx79'); + `); + expect(result).to.equal(true); }); @@ -188,6 +201,12 @@ describe('replayer', function (this: ISuite) { (e) => e.timestamp - stylesheetRemoveEvents[0].timestamp >= 2500, ).length, ); + + await assertDomSnapshot( + this.page, + __filename, + 'style-sheet-remove-events-play-at-2500', + ); }); it('can fast forward past StyleSheetRule deletion on virtual elements', async () => { @@ -201,15 +220,25 @@ describe('replayer', function (this: ISuite) { replayer['timer']['actions'].length; `); + await assertDomSnapshot( + this.page, + __filename, + 'style-sheet-rule-events-pause-at-2500', + ); + }); + + it('should delete fast forwarded StyleSheetRules that where deleted', async () => { + await this.page.evaluate( + `events = ${JSON.stringify(styleSheetRuleEvents)}`, + ); const result = await this.page.evaluate(` - const rules = Array.from(replayer.iframe.contentDocument.head.children) - .filter(x=>x.nodeName === 'STYLE') - .reduce((acc, node) => { - acc.push(...node.sheet.rules); - return acc; - }, []); - - rules.some(x=>x.selectorText === ".css-1fbxx79") + const { Replayer } = rrweb; + const replayer = new Replayer(events); + replayer.pause(2500); + const rules = [...replayer.iframe.contentDocument.styleSheets].map( + (sheet) => [...sheet.rules], + ).flat(); + rules.some((x) => x.selectorText === '.css-1fbxx79'); `); expect(result).to.equal(false); diff --git a/test/replayer/virtual-styles.test.ts b/test/replayer/virtual-styles.test.ts new file mode 100644 index 0000000000..99a566f4ed --- /dev/null +++ b/test/replayer/virtual-styles.test.ts @@ -0,0 +1,65 @@ +import { expect } from 'chai'; +import { INode } from 'rrweb-snapshot'; +import { Replayer } from '../../src/replay'; +import { JSDOM } from 'jsdom'; +import { + applyVirtualStyleRulesToNode, + VirtualStyleRules, +} from '../../src/replay/virtual-styles'; + +describe('virtual styles', () => { + describe('applyVirtualStyleRulesToNode', () => { + it('should insert rule at index 0 in empty sheet', () => { + const dom = new JSDOM(` + + `); + const styleEl = dom.window.document.getElementsByTagName('style')[0]; + + const cssRule = '.x {border: 1px solid yellow;}'; + const virtualStyleRules: VirtualStyleRules = [ + [{ cssText: cssRule } as CSSRule, 0], + ]; + applyVirtualStyleRulesToNode(virtualStyleRules, styleEl); + + expect(styleEl.sheet?.cssRules?.length).to.equal(1); + expect(styleEl.sheet?.cssRules[0].cssText).to.equal(cssRule); + }); + + it('should insert rule at index 0 and keep exsisting rules', () => { + const dom = new JSDOM(` + + `); + const styleEl = dom.window.document.getElementsByTagName('style')[0]; + + const cssRule = '.x {border: 1px solid yellow;}'; + const virtualStyleRules: VirtualStyleRules = [ + [{ cssText: cssRule } as CSSRule, 0], + ]; + applyVirtualStyleRulesToNode(virtualStyleRules, styleEl); + + expect(styleEl.sheet?.cssRules?.length).to.equal(3); + expect(styleEl.sheet?.cssRules[0].cssText).to.equal(cssRule); + }); + + it('should delete rule at index 1', () => { + const dom = new JSDOM(` + + `); + const styleEl = dom.window.document.getElementsByTagName('style')[0]; + + const virtualStyleRules: VirtualStyleRules = [[false, 0]]; + applyVirtualStyleRulesToNode(virtualStyleRules, styleEl); + + expect(styleEl.sheet?.cssRules?.length).to.equal(1); + expect(styleEl.sheet?.cssRules[0].cssText).to.equal( + 'div {color: black;}', + ); + }); + }); +}); diff --git a/yarn.lock b/yarn.lock index 307d19427a..5fd09b5914 100644 --- a/yarn.lock +++ b/yarn.lock @@ -23,6 +23,11 @@ chalk "^2.0.0" js-tokens "^4.0.0" +"@tootallnate/once@1": + version "1.1.2" + resolved "https://registry.yarnpkg.com/@tootallnate/once/-/once-1.1.2.tgz#ccb91445360179a04e7fe6aff78c00ffc1eeaf82" + integrity sha512-RbzJvlNzmRq5c3O09UipeuXno4tA1FE6ikOjxZK0tuxVv3412l64l5t1W5pj4+rJq9vpkm/kwiR07aZXnsKPxw== + "@types/chai@^4.1.6": version "4.2.14" resolved "https://registry.yarnpkg.com/@types/chai/-/chai-4.2.14.tgz#44d2dd0b5de6185089375d976b4ec5caf6861193" @@ -41,6 +46,15 @@ "@types/rx" "*" "@types/through" "*" +"@types/jsdom@^16.2.12": + version "16.2.12" + resolved "https://registry.yarnpkg.com/@types/jsdom/-/jsdom-16.2.12.tgz#2d47f5c9f7e40b4d5d9b5f0534c736dc475f9569" + integrity sha512-rD68Q2XSKBYOl38Tb9jbPuqZeTtpw09dFeuKWi7yhlZVfY8rV4xnQmISNQQZfhkQJGpJWp2qCmmrWjhiqDFNvA== + dependencies: + "@types/node" "*" + "@types/parse5" "*" + "@types/tough-cookie" "*" + "@types/mocha@^5.2.5": version "5.2.7" resolved "https://registry.yarnpkg.com/@types/mocha/-/mocha-5.2.7.tgz#315d570ccb56c53452ff8638738df60726d5b6ea" @@ -56,6 +70,11 @@ resolved "https://registry.yarnpkg.com/@types/node/-/node-10.17.42.tgz#90dd71b26fe4f4e2929df6b07e72ef2e9648a173" integrity sha512-HElxYF7C/MSkuvlaHB2c+82zhXiuO49Cq056Dol8AQuTph7oJtduo2n6J8rFa+YhJyNgQ/Lm20ZaxqD0vxU0+Q== +"@types/parse5@*": + version "6.0.0" + resolved "https://registry.yarnpkg.com/@types/parse5/-/parse5-6.0.0.tgz#38590dc2c3cf5717154064e3ee9b6947ee21b299" + integrity sha512-oPwPSj4a1wu9rsXTEGIJz91ISU725t0BmSnUhb57sI+M8XEmvUop84lzuiYdq0Y5M6xLY8DBPg0C2xEQKLyvBA== + "@types/puppeteer@^5.4.3": version "5.4.3" resolved "https://registry.yarnpkg.com/@types/puppeteer/-/puppeteer-5.4.3.tgz#cdca84aa7751d77448d8a477dbfa0af1f11485f2" @@ -176,6 +195,11 @@ dependencies: "@types/node" "*" +"@types/tough-cookie@*": + version "4.0.1" + resolved "https://registry.yarnpkg.com/@types/tough-cookie/-/tough-cookie-4.0.1.tgz#8f80dd965ad81f3e1bc26d6f5c727e132721ff40" + integrity sha512-Y0K95ThC3esLEYD6ZuqNek29lNX2EM1qxV8y2FTLUB0ff5wWrk7az+mLrnNFUnaXcgKye22+sFBRXOgpPILZNg== + "@types/yauzl@^2.9.1": version "2.9.1" resolved "https://registry.yarnpkg.com/@types/yauzl/-/yauzl-2.9.1.tgz#d10f69f9f522eef3cf98e30afb684a1e1ec923af" @@ -188,6 +212,11 @@ resolved "https://registry.yarnpkg.com/@xstate/fsm/-/fsm-1.5.1.tgz#b1ebedc77b11e4956fda0a6429cef986cd17979e" integrity sha512-t8blLI0e90jCE71yUQHLH5uEljD1v0aC8PKkHUtNWEnXt81EOj7xBjnlwmaHn/8cmE2aSygiBElUpkRZUV9hXA== +abab@^2.0.3, abab@^2.0.5: + version "2.0.5" + resolved "https://registry.yarnpkg.com/abab/-/abab-2.0.5.tgz#c0b678fb32d60fc1219c784d6a826fe385aeb79a" + integrity sha512-9IK9EadsbHo6jLWIpxpR6pL0sazTXV6+SQv25ZB+F7Bj9mJNaOc4nCRabwd5M/JwmUa8idz6Eci6eKfJryPs6Q== + abbrev@1: version "1.1.1" resolved "https://registry.yarnpkg.com/abbrev/-/abbrev-1.1.1.tgz#f8f2c887ad10bf67f634f005b6987fed3179aac8" @@ -201,6 +230,29 @@ accepts@~1.3.7: mime-types "~2.1.24" negotiator "0.6.2" +acorn-globals@^6.0.0: + version "6.0.0" + resolved "https://registry.yarnpkg.com/acorn-globals/-/acorn-globals-6.0.0.tgz#46cdd39f0f8ff08a876619b55f5ac8a6dc770b45" + integrity sha512-ZQl7LOWaF5ePqqcX4hLuv/bLXYQNfNWw2c0/yX/TsPRKamzHcTGQnlCjHT3TsmkOUVEPS3crCxiPfdzE/Trlhg== + dependencies: + acorn "^7.1.1" + acorn-walk "^7.1.1" + +acorn-walk@^7.1.1: + version "7.2.0" + resolved "https://registry.yarnpkg.com/acorn-walk/-/acorn-walk-7.2.0.tgz#0de889a601203909b0fbe07b8938dc21d2e967bc" + integrity sha512-OPdCF6GsMIP+Az+aWfAAOEt2/+iVDKE7oy6lJ098aoe59oAmK76qV6Gw60SbZ8jHuG2wH058GF4pLFbYamYrVA== + +acorn@^7.1.1: + version "7.4.1" + resolved "https://registry.yarnpkg.com/acorn/-/acorn-7.4.1.tgz#feaed255973d2e77555b83dbc08851a6c63520fa" + integrity sha512-nQyp0o1/mNdbTO1PO6kHkwSrmgZ0MT/jCCpNiwbUjGoRN4dlBhqJtoQuCnEOKzgTVwg0ZWiCoQy6SxMebQVh8A== + +acorn@^8.2.4: + version "8.4.1" + resolved "https://registry.yarnpkg.com/acorn/-/acorn-8.4.1.tgz#56c36251fc7cabc7096adc18f05afe814321a28c" + integrity sha512-asabaBSkEKosYKMITunzX177CXxQ4Q8BSSzMTKD+FefUhipQC70gfW5SiUDhYQ3vk8G+81HqQk7Fv9OXwwn9KA== + agent-base@6: version "6.0.2" resolved "https://registry.yarnpkg.com/agent-base/-/agent-base-6.0.2.tgz#49fff58577cfee3f37176feab4c22e00f86d7f77" @@ -311,6 +363,11 @@ assertion-error@^1.1.0: resolved "https://registry.yarnpkg.com/assertion-error/-/assertion-error-1.1.0.tgz#e60b6b0e8f301bd97e5375215bda406c85118c0b" integrity sha512-jgsaNduz+ndvGyFt3uSuWqvy4lCnIJiovtouQN5JZHOKCS2QuhEdbcQHFhVksz2N2U9hXJo8odG7ETyWlEeuDw== +asynckit@^0.4.0: + version "0.4.0" + resolved "https://registry.yarnpkg.com/asynckit/-/asynckit-0.4.0.tgz#c79ed97f7f34cb8f2ba1bc9790bcc366474b4b79" + integrity sha1-x57Zf380y48robyXkLzDZkdLS3k= + babel-code-frame@^6.20.0: version "6.26.0" resolved "https://registry.yarnpkg.com/babel-code-frame/-/babel-code-frame-6.26.0.tgz#63fd43f7dc1e3bb7ce35947db8fe369a3f58c74b" @@ -418,6 +475,11 @@ braces@^1.8.2: preserve "^0.2.0" repeat-element "^1.1.2" +browser-process-hrtime@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/browser-process-hrtime/-/browser-process-hrtime-1.0.0.tgz#3c9b4b7d782c8121e56f10106d84c0d0ffc94626" + integrity sha512-9o5UecI3GhkpM6DrXr69PblIuWxPKk9Y0jHBRhdocZ2y7YECBFCsHm79Pr3OyR2AvjhDkabFJaDJMYRazHgsow== + browser-resolve@^1.11.3: version "1.11.3" resolved "https://registry.yarnpkg.com/browser-resolve/-/browser-resolve-1.11.3.tgz#9b7cbb3d0f510e4cb86bdbd796124d28b5890af6" @@ -678,6 +740,13 @@ colors@^1.1.2: resolved "https://registry.yarnpkg.com/colors/-/colors-1.4.0.tgz#c50491479d4c1bdaed2c9ced32cf7c7dc2360f78" integrity sha512-a+UqTh4kgZg/SlGvfbzDHpgRu7AAQOmmqRHJnxhRZICKFUT91brVhNNt58CMWU9PsBbv3PDCZUHbVxuDiH2mtA== +combined-stream@^1.0.8: + version "1.0.8" + resolved "https://registry.yarnpkg.com/combined-stream/-/combined-stream-1.0.8.tgz#c3d45a8b34fd730631a110a8a2520682b31d5a7f" + integrity sha512-FQN4MRfuJeHf7cBbBMJFXhKSDq+2kAArBlmRBvcvFE5BB1HZKXtSFASDhdlz9zOYwxh8lDdnvmMOe/+5cdoEdg== + dependencies: + delayed-stream "~1.0.0" + commander@2.15.1: version "2.15.1" resolved "https://registry.yarnpkg.com/commander/-/commander-2.15.1.tgz#df46e867d0fc2aec66a34662b406a9ccafff5b0f" @@ -971,6 +1040,32 @@ csso@^4.0.2: dependencies: css-tree "1.0.0-alpha.39" +cssom@^0.4.4: + version "0.4.4" + resolved "https://registry.yarnpkg.com/cssom/-/cssom-0.4.4.tgz#5a66cf93d2d0b661d80bf6a44fb65f5c2e4e0a10" + integrity sha512-p3pvU7r1MyyqbTk+WbNJIgJjG2VmTIaB10rI93LzVPrmDJKkzKYMtxxyAvQXR/NS6otuzveI7+7BBq3SjBS2mw== + +cssom@~0.3.6: + version "0.3.8" + resolved "https://registry.yarnpkg.com/cssom/-/cssom-0.3.8.tgz#9f1276f5b2b463f2114d3f2c75250af8c1a36f4a" + integrity sha512-b0tGHbfegbhPJpxpiBPU2sCkigAqtM9O121le6bbOlgyV+NyGyCmVfJ6QW9eRjz8CpNfWEOYBIMIGRYkLwsIYg== + +cssstyle@^2.3.0: + version "2.3.0" + resolved "https://registry.yarnpkg.com/cssstyle/-/cssstyle-2.3.0.tgz#ff665a0ddbdc31864b09647f34163443d90b0852" + integrity sha512-AZL67abkUzIuvcHqk7c09cezpGNcxUxU4Ioi/05xHk4DQeTkWmGYftIE6ctU6AEt+Gn4n1lDStOtj7FKycP71A== + dependencies: + cssom "~0.3.6" + +data-urls@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/data-urls/-/data-urls-2.0.0.tgz#156485a72963a970f5d5821aaf642bef2bf2db9b" + integrity sha512-X5eWTSXO/BJmpdIKCRuKUgSCgAN0OwliVK3yPKbwIWU1Tdw5BRajxlzMidvh+gwko9AfQ9zIj52pzF91Q3YAvQ== + dependencies: + abab "^2.0.3" + whatwg-mimetype "^2.3.0" + whatwg-url "^8.0.0" + debug@2.6.9: version "2.6.9" resolved "https://registry.yarnpkg.com/debug/-/debug-2.6.9.tgz#5d128515df134ff327e90a4c93f4e077a536341f" @@ -999,6 +1094,11 @@ debug@^3.2.6: dependencies: ms "^2.1.1" +decimal.js@^10.2.1: + version "10.3.1" + resolved "https://registry.yarnpkg.com/decimal.js/-/decimal.js-10.3.1.tgz#d8c3a444a9c6774ba60ca6ad7261c3a94fd5e783" + integrity sha512-V0pfhfr8suzyPGOx3nmq4aHqabehUZn6Ch9kyFpV79TGDTWFmHqUqXdabR7QHqxzrYolF4+tVmJhUG4OURg5dQ== + deep-eql@^3.0.1: version "3.0.1" resolved "https://registry.yarnpkg.com/deep-eql/-/deep-eql-3.0.1.tgz#dfc9404400ad1c8fe023e7da1df1c147c4b444df" @@ -1011,6 +1111,11 @@ deep-extend@^0.6.0: resolved "https://registry.yarnpkg.com/deep-extend/-/deep-extend-0.6.0.tgz#c4fa7c95404a17a9c3e8ca7e1537312b736330ac" integrity sha512-LOHxIOaPYdHlJRtCQfDIVZtfw/ufM8+rVj649RIHzcm/vGwQRXFt6OPqIFWsm2XEMrNIEtWR64sY1LEKD2vAOA== +deep-is@~0.1.3: + version "0.1.3" + resolved "https://registry.yarnpkg.com/deep-is/-/deep-is-0.1.3.tgz#b369d6fb5dbc13eecf524f91b070feedc357cf34" + integrity sha1-s2nW+128E+7PUk+RsHD+7cNXzzQ= + define-properties@^1.1.3: version "1.1.3" resolved "https://registry.yarnpkg.com/define-properties/-/define-properties-1.1.3.tgz#cf88da6cbee26fe6db7094f61d870cbd84cee9f1" @@ -1018,6 +1123,11 @@ define-properties@^1.1.3: dependencies: object-keys "^1.0.12" +delayed-stream@~1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/delayed-stream/-/delayed-stream-1.0.0.tgz#df3ae199acadfb7d440aaae0b29e2272b24ec619" + integrity sha1-3zrhmayt+31ECqrgsp4icrJOxhk= + delegates@^1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/delegates/-/delegates-1.0.0.tgz#84c6e159b81904fdca59a0ef44cd870d31250f9a" @@ -1080,6 +1190,13 @@ domelementtype@^2.2.0: resolved "https://registry.yarnpkg.com/domelementtype/-/domelementtype-2.2.0.tgz#9a0b6c2782ed6a1c7323d42267183df9bd8b1d57" integrity sha512-DtBMo82pv1dFtUmHyr48beiuq792Sxohr+8Hm9zoxklYPfa6n0Z3Byjj2IV7bmr2IyqClnqEQhfgHJJ5QF0R5A== +domexception@^2.0.1: + version "2.0.1" + resolved "https://registry.yarnpkg.com/domexception/-/domexception-2.0.1.tgz#fb44aefba793e1574b0af6aed2801d057529f304" + integrity sha512-yxJ2mFy/sibVQlu5qHjOkf9J3K6zgmCxgJ94u2EdvDOV09H+32LtRswEcUsmUWN72pVLOEnTSRaIVVzVQgS0dg== + dependencies: + webidl-conversions "^5.0.0" + domhandler@^4.0.0, domhandler@^4.2.0: version "4.2.0" resolved "https://registry.yarnpkg.com/domhandler/-/domhandler-4.2.0.tgz#f9768a5f034be60a89a27c2e4d0f74eba0d8b059" @@ -1221,11 +1338,28 @@ escape-string-regexp@1.0.5, escape-string-regexp@^1.0.2, escape-string-regexp@^1 resolved "https://registry.yarnpkg.com/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz#1b61c0562190a8dff6ae3bb2cf0200ca130b86d4" integrity sha1-G2HAViGQqN/2rjuyzwIAyhMLhtQ= -esprima@^4.0.0: +escodegen@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/escodegen/-/escodegen-2.0.0.tgz#5e32b12833e8aa8fa35e1bf0befa89380484c7dd" + integrity sha512-mmHKys/C8BFUGI+MAWNcSYoORYLMdPzjrknd2Vc+bUsjN5bXcr8EhrNB+UTqfL1y3I9c4fw2ihgtMPQLBRiQxw== + dependencies: + esprima "^4.0.1" + estraverse "^5.2.0" + esutils "^2.0.2" + optionator "^0.8.1" + optionalDependencies: + source-map "~0.6.1" + +esprima@^4.0.0, esprima@^4.0.1: version "4.0.1" resolved "https://registry.yarnpkg.com/esprima/-/esprima-4.0.1.tgz#13b04cdb3e6c5d19df91ab6987a8695619b0aa71" integrity sha512-eGuFFw7Upda+g4p+QHvnW0RyTX/SVeJBDM/gCtMARO0cLuT2HcEKnTPvhjV6aGeqrCB/sbNop0Kszm0jsaWU4A== +estraverse@^5.2.0: + version "5.2.0" + resolved "https://registry.yarnpkg.com/estraverse/-/estraverse-5.2.0.tgz#307df42547e6cc7324d3cf03c155d5cdb8c53880" + integrity sha512-BxbNGGNm0RyRYvUdHpIwv9IWzeM9XClbOxwoATuFdOE7ZE6wHL+HQ5T8hoPM+zHvmKzzsEqhgy0GrQ5X13afiQ== + estree-walker@^0.6.0, estree-walker@^0.6.1: version "0.6.1" resolved "https://registry.yarnpkg.com/estree-walker/-/estree-walker-0.6.1.tgz#53049143f40c6eb918b23671d1fe3219f3a1b362" @@ -1341,6 +1475,11 @@ extract-zip@^2.0.0: optionalDependencies: "@types/yauzl" "^2.9.1" +fast-levenshtein@~2.0.6: + version "2.0.6" + resolved "https://registry.yarnpkg.com/fast-levenshtein/-/fast-levenshtein-2.0.6.tgz#3d8a5c66883a16a30ca8643e851f19baa7797917" + integrity sha1-PYpcZog6FqMMqGQ+hR8Zuqd5eRc= + fast-mhtml@^1.1.9: version "1.1.9" resolved "https://registry.yarnpkg.com/fast-mhtml/-/fast-mhtml-1.1.9.tgz#2c31e0727e0eb93423938a0812b001f67a3f6575" @@ -1446,6 +1585,15 @@ for-own@^0.1.4: dependencies: for-in "^1.0.1" +form-data@^3.0.0: + version "3.0.1" + resolved "https://registry.yarnpkg.com/form-data/-/form-data-3.0.1.tgz#ebd53791b78356a99af9a300d4282c4d5eb9755f" + integrity sha512-RHkBKtLWUVwd7SqRIvCZMEvAMoGUp0XU+seQiZejj0COz3RI3hWP4sCv3gZWWLjJTd7rGwcsF5eKZGii0r/hbg== + dependencies: + asynckit "^0.4.0" + combined-stream "^1.0.8" + mime-types "^2.1.12" + forwarded@0.2.0: version "0.2.0" resolved "https://registry.yarnpkg.com/forwarded/-/forwarded-0.2.0.tgz#2269936428aad4c15c7ebe9779a84bf0b2a81811" @@ -1669,6 +1817,13 @@ html-comment-regex@^1.1.0: resolved "https://registry.yarnpkg.com/html-comment-regex/-/html-comment-regex-1.1.2.tgz#97d4688aeb5c81886a364faa0cad1dda14d433a7" integrity sha512-P+M65QY2JQ5Y0G9KKdlDpo0zK+/OHptU5AaBwUfAIDJZk1MYf32Frm84EcOytfJE0t5JvkAnKlmjsXDnWzCJmQ== +html-encoding-sniffer@^2.0.1: + version "2.0.1" + resolved "https://registry.yarnpkg.com/html-encoding-sniffer/-/html-encoding-sniffer-2.0.1.tgz#42a6dc4fd33f00281176e8b23759ca4e4fa185f3" + integrity sha512-D5JbOMBIR/TVZkubHT+OyT2705QvogUW4IBn6nHd756OwieSF9aDYFj4dv6HHEVGYbHaLETa3WggZYWWMyy3ZQ== + dependencies: + whatwg-encoding "^1.0.5" + htmlparser2@^6.1.0: version "6.1.0" resolved "https://registry.yarnpkg.com/htmlparser2/-/htmlparser2-6.1.0.tgz#c4d762b6c3371a05dbe65e94ae43a9f845fb8fb7" @@ -1701,6 +1856,15 @@ http-errors@~1.7.2: statuses ">= 1.5.0 < 2" toidentifier "1.0.0" +http-proxy-agent@^4.0.1: + version "4.0.1" + resolved "https://registry.yarnpkg.com/http-proxy-agent/-/http-proxy-agent-4.0.1.tgz#8a8c8ef7f5932ccf953c296ca8291b95aa74aa3a" + integrity sha512-k0zdNgqWTGA6aeIRVpvfVob4fL52dTfaehylg0Y4UvSySvOq/Y+BOyPrgpUrA7HylqvU8vIZGsRuXmspskV0Tg== + dependencies: + "@tootallnate/once" "1" + agent-base "6" + debug "4" + https-proxy-agent@^5.0.0: version "5.0.0" resolved "https://registry.yarnpkg.com/https-proxy-agent/-/https-proxy-agent-5.0.0.tgz#e2a90542abb68a762e0a0850f6c9edadfd8506b2" @@ -1726,6 +1890,11 @@ ieee754@^1.1.13: resolved "https://registry.yarnpkg.com/ieee754/-/ieee754-1.2.1.tgz#8eb7a10a63fff25d15a57b001586d177d1b0d352" integrity sha512-dcyqhDvX1C46lXZcVqCpK+FtMRQVdIMN6/Df5js2zouUsqG7I6sFxitIC+7KYK29KdXOLHdu9zL4sFnoVQnqaA== +ignore-styles@^5.0.1: + version "5.0.1" + resolved "https://registry.yarnpkg.com/ignore-styles/-/ignore-styles-5.0.1.tgz#b49ef2274bdafcd8a4880a966bfe38d1a0bf4671" + integrity sha1-tJ7yJ0va/NikiAqWa/440aC/RnE= + ignore-walk@^3.0.1: version "3.0.4" resolved "https://registry.yarnpkg.com/ignore-walk/-/ignore-walk-3.0.4.tgz#c9a09f69b7c7b479a5d74ac1a3c0d4236d2a6335" @@ -1990,6 +2159,11 @@ is-posix-bracket@^0.1.0: resolved "https://registry.yarnpkg.com/is-posix-bracket/-/is-posix-bracket-0.1.1.tgz#3334dc79774368e92f016e6fbc0a88f5cd6e6bc4" integrity sha1-MzTceXdDaOkvAW5vvAqI9c1ua8Q= +is-potential-custom-element-name@^1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/is-potential-custom-element-name/-/is-potential-custom-element-name-1.0.1.tgz#171ed6f19e3ac554394edf78caa05784a45bebb5" + integrity sha512-bCYeRA2rVibKZd+s2625gGnGF/t7DSqDs4dP7CrLA1m7jKWz6pps0LpYLJN8Q64HtmPKJ1hrN3nzPNKFEKOUiQ== + is-primitive@^2.0.0: version "2.0.0" resolved "https://registry.yarnpkg.com/is-primitive/-/is-primitive-2.0.0.tgz#207bab91638499c07b2adf240a41a87210034575" @@ -2139,6 +2313,44 @@ js-yaml@^3.13.1: argparse "^1.0.7" esprima "^4.0.0" +jsdom-global@^3.0.2: + version "3.0.2" + resolved "https://registry.yarnpkg.com/jsdom-global/-/jsdom-global-3.0.2.tgz#6bd299c13b0c4626b2da2c0393cd4385d606acb9" + integrity sha1-a9KZwTsMRiay2iwDk81DhdYGrLk= + +jsdom@^16.6.0: + version "16.6.0" + resolved "https://registry.yarnpkg.com/jsdom/-/jsdom-16.6.0.tgz#f79b3786682065492a3da6a60a4695da983805ac" + integrity sha512-Ty1vmF4NHJkolaEmdjtxTfSfkdb8Ywarwf63f+F8/mDD1uLSSWDxDuMiZxiPhwunLrn9LOSVItWj4bLYsLN3Dg== + dependencies: + abab "^2.0.5" + acorn "^8.2.4" + acorn-globals "^6.0.0" + cssom "^0.4.4" + cssstyle "^2.3.0" + data-urls "^2.0.0" + decimal.js "^10.2.1" + domexception "^2.0.1" + escodegen "^2.0.0" + form-data "^3.0.0" + html-encoding-sniffer "^2.0.1" + http-proxy-agent "^4.0.1" + https-proxy-agent "^5.0.0" + is-potential-custom-element-name "^1.0.1" + nwsapi "^2.2.0" + parse5 "6.0.1" + saxes "^5.0.1" + symbol-tree "^3.2.4" + tough-cookie "^4.0.0" + w3c-hr-time "^1.0.2" + w3c-xmlserializer "^2.0.0" + webidl-conversions "^6.1.0" + whatwg-encoding "^1.0.5" + whatwg-mimetype "^2.3.0" + whatwg-url "^8.5.0" + ws "^7.4.5" + xml-name-validator "^3.0.0" + json-parse-better-errors@^1.0.1: version "1.0.2" resolved "https://registry.yarnpkg.com/json-parse-better-errors/-/json-parse-better-errors-1.0.2.tgz#bb867cfb3450e69107c131d1c514bab3dc8bcaa9" @@ -2170,6 +2382,14 @@ latest-version@^3.0.0: dependencies: package-json "^4.0.0" +levn@~0.3.0: + version "0.3.0" + resolved "https://registry.yarnpkg.com/levn/-/levn-0.3.0.tgz#3b09924edf9f083c0490fdd4c0bc4421e04764ee" + integrity sha1-OwmSTt+fCDwEkP3UwLxEIeBHZO4= + dependencies: + prelude-ls "~1.1.2" + type-check "~0.3.2" + loader-utils@^1.1.0: version "1.4.0" resolved "https://registry.yarnpkg.com/loader-utils/-/loader-utils-1.4.0.tgz#c579b5e34cb34b1a74edc6c1fb36bfa371d5a613" @@ -2201,7 +2421,7 @@ lodash.uniq@^4.5.0: resolved "https://registry.yarnpkg.com/lodash.uniq/-/lodash.uniq-4.5.0.tgz#d0225373aeb652adc1bc82e4945339a842754773" integrity sha1-0CJTc662Uq3BvILklFM5qEJ1R3M= -lodash@^4.17.12, lodash@^4.17.4: +lodash@^4.17.12, lodash@^4.17.4, lodash@^4.7.0: version "4.17.21" resolved "https://registry.yarnpkg.com/lodash/-/lodash-4.17.21.tgz#679591c564c3bffaae8454cf0b3df370c3d6911c" integrity sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg== @@ -2302,7 +2522,7 @@ mime-db@1.48.0: resolved "https://registry.yarnpkg.com/mime-db/-/mime-db-1.48.0.tgz#e35b31045dd7eada3aaad537ed88a33afbef2d1d" integrity sha512-FM3QwxV+TnZYQ2aRqhlKBMHxk10lTbMt3bBkMAp54ddrNeVSfcQYOOKuGuy3Ddrm38I04If834fOUSq1yzslJQ== -mime-types@~2.1.24: +mime-types@^2.1.12, mime-types@~2.1.24: version "2.1.31" resolved "https://registry.yarnpkg.com/mime-types/-/mime-types-2.1.31.tgz#a00d76b74317c61f9c2db2218b8e9f8e9c5c9e6b" integrity sha512-XGZnNzm3QvgKxa8dpzyhFTHmpP3l5YNusmne07VUOXxou9CqUqYa/HBy124RqtVh/O2pECas/MOcsDgpilPOPg== @@ -2562,6 +2782,11 @@ number-is-nan@^1.0.0: resolved "https://registry.yarnpkg.com/number-is-nan/-/number-is-nan-1.0.1.tgz#097b602b53422a522c1afb8790318336941a011d" integrity sha1-CXtgK1NCKlIsGvuHkDGDNpQaAR0= +nwsapi@^2.2.0: + version "2.2.0" + resolved "https://registry.yarnpkg.com/nwsapi/-/nwsapi-2.2.0.tgz#204879a9e3d068ff2a55139c2c772780681a38b7" + integrity sha512-h2AatdwYH+JHiZpv7pt/gSX1XoRGb7L/qSIeuqA6GwYoF9w1vP1cw42TO0aI2pNyshRK5893hNSl+1//vHK7hQ== + object-assign@^4.1.0: version "4.1.1" resolved "https://registry.yarnpkg.com/object-assign/-/object-assign-4.1.1.tgz#2109adc7965887cfc05cbbd442cac8bfbb360863" @@ -2642,6 +2867,18 @@ optimist@~0.6.0: minimist "~0.0.1" wordwrap "~0.0.2" +optionator@^0.8.1: + version "0.8.3" + resolved "https://registry.yarnpkg.com/optionator/-/optionator-0.8.3.tgz#84fa1d036fe9d3c7e21d99884b601167ec8fb495" + integrity sha512-+IW9pACdk3XWmmTXG8m3upGUJst5XRGzxMRjXzAuJ1XnIFNvfhjjIuYkDvysnPQ7qzqVzLt78BCruntqRhWQbA== + dependencies: + deep-is "~0.1.3" + fast-levenshtein "~2.0.6" + levn "~0.3.0" + prelude-ls "~1.1.2" + type-check "~0.3.2" + word-wrap "~1.2.3" + os-homedir@^1.0.0: version "1.0.2" resolved "https://registry.yarnpkg.com/os-homedir/-/os-homedir-1.0.2.tgz#ffbc4988336e0e833de0c168c7ef152121aa7fb3" @@ -2734,7 +2971,7 @@ parse5-htmlparser2-tree-adapter@^6.0.1: dependencies: parse5 "^6.0.1" -parse5@^6.0.1: +parse5@6.0.1, parse5@^6.0.1: version "6.0.1" resolved "https://registry.yarnpkg.com/parse5/-/parse5-6.0.1.tgz#e1a1c085c569b3dc08321184f19a39cc27f7c30b" integrity sha512-Ofn/CTFzRGTTxwpNEs9PP93gXShHcTq255nzRYSKe8AkVpZY7e1fpmTfOyoIvjP5HG7Z2ZM7VS9PPhQGW2pOpw== @@ -3154,6 +3391,11 @@ postcss@^7.0.0, postcss@^7.0.1, postcss@^7.0.27: source-map "^0.6.1" supports-color "^6.1.0" +prelude-ls@~1.1.2: + version "1.1.2" + resolved "https://registry.yarnpkg.com/prelude-ls/-/prelude-ls-1.1.2.tgz#21932a549f5e52ffd9a827f570e04be62a97da54" + integrity sha1-IZMqVJ9eUv/ZqCf1cOBL5iqX2lQ= + prepend-http@^1.0.1: version "1.0.4" resolved "https://registry.yarnpkg.com/prepend-http/-/prepend-http-1.0.4.tgz#d4f4562b0ce3696e41ac52d0e002e57a635dc6dc" @@ -3210,6 +3452,11 @@ pseudomap@^1.0.2: resolved "https://registry.yarnpkg.com/pseudomap/-/pseudomap-1.0.2.tgz#f052a28da70e618917ef0a8ac34c1ae5a68286b3" integrity sha1-8FKijacOYYkX7wqKw0wa5aaChrM= +psl@^1.1.33: + version "1.8.0" + resolved "https://registry.yarnpkg.com/psl/-/psl-1.8.0.tgz#9326f8bcfb013adcc005fdff056acce020e51c24" + integrity sha512-RIdOzyoavK+hA18OGGWDqUTsCLhtA7IcZ/6NCs4fFJaHBDab+pDDmDIByWFRQJq2Cd7r1OoQxBGKOaztq+hjIQ== + pump@^3.0.0: version "3.0.0" resolved "https://registry.yarnpkg.com/pump/-/pump-3.0.0.tgz#b4a2116815bde2f4e1ea602354e8c75565107a64" @@ -3218,6 +3465,11 @@ pump@^3.0.0: end-of-stream "^1.1.0" once "^1.3.1" +punycode@^2.1.1: + version "2.1.1" + resolved "https://registry.yarnpkg.com/punycode/-/punycode-2.1.1.tgz#b58b010ac40c22c5657616c8d2c2c02c7bf479ec" + integrity sha512-XRsRjdf+j5ml+y/6GKHPZbrF/8p2Yga0JPtdqTIY2Xe5ohJPD9saDJJLPvp9+NSBprVvevdXZybnj2cv8OEd0A== + puppeteer@^9.1.1: version "9.1.1" resolved "https://registry.yarnpkg.com/puppeteer/-/puppeteer-9.1.1.tgz#f74b7facf86887efd6c6b9fabb7baae6fdce012c" @@ -3535,6 +3787,13 @@ sax@^1.2.4, sax@~1.2.4: resolved "https://registry.yarnpkg.com/sax/-/sax-1.2.4.tgz#2816234e2378bddc4e5354fab5caa895df7100d9" integrity sha512-NqVDv9TpANUjFm0N8uM5GxL36UgKi9/atZw+x7YFnQ8ckwFGKrl4xX4yWtrey3UJm5nP1kUbnYgLopqWNSRhWw== +saxes@^5.0.1: + version "5.0.1" + resolved "https://registry.yarnpkg.com/saxes/-/saxes-5.0.1.tgz#eebab953fa3b7608dbe94e5dadb15c888fa6696d" + integrity sha512-5LBh1Tls8c9xgGjw3QrMwETmTMVk0oFgvrFSvWx62llR2hcEInrKNZ2GZCCuuy2lvWrdl5jhbpeqc5hRYKFOcw== + dependencies: + xmlchars "^2.2.0" + semver-diff@^2.0.0: version "2.1.0" resolved "https://registry.yarnpkg.com/semver-diff/-/semver-diff-2.1.0.tgz#4bbb8437c8d37e4b0cf1a68fd726ec6d645d6d36" @@ -3828,6 +4087,11 @@ svgo@^1.0.0: unquote "~1.1.1" util.promisify "~1.0.0" +symbol-tree@^3.2.4: + version "3.2.4" + resolved "https://registry.yarnpkg.com/symbol-tree/-/symbol-tree-3.2.4.tgz#430637d248ba77e078883951fb9aa0eed7c63fa2" + integrity sha512-9QNk5KwDF+Bvz+PyObkmSYjI5ksVUYtjW7AU22r2NKcfLJcXp96hkDWU3+XndOsUb+AQ9QhfzfCT2O+CNWT5Tw== + tar-fs@^2.0.0: version "2.1.1" resolved "https://registry.yarnpkg.com/tar-fs/-/tar-fs-2.1.1.tgz#489a15ab85f1f0befabb370b7de4f9eb5cbe8784" @@ -3910,6 +4174,22 @@ toidentifier@1.0.0: resolved "https://registry.yarnpkg.com/toidentifier/-/toidentifier-1.0.0.tgz#7e1be3470f1e77948bc43d94a3c8f4d7752ba553" integrity sha512-yaOH/Pk/VEhBWWTlhI+qXxDFXlejDGcQipMlyxda9nthulaxLZUNcUqFxokp0vcYnvteJln5FNQDRrxj3YcbVw== +tough-cookie@^4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/tough-cookie/-/tough-cookie-4.0.0.tgz#d822234eeca882f991f0f908824ad2622ddbece4" + integrity sha512-tHdtEpQCMrc1YLrMaqXXcj6AxhYi/xgit6mZu1+EDWUn+qhUf8wMQoFIy9NXuq23zAwtcB0t/MjACGR18pcRbg== + dependencies: + psl "^1.1.33" + punycode "^2.1.1" + universalify "^0.1.2" + +tr46@^2.1.0: + version "2.1.0" + resolved "https://registry.yarnpkg.com/tr46/-/tr46-2.1.0.tgz#fa87aa81ca5d5941da8cbf1f9b749dc969a4e240" + integrity sha512-15Ih7phfcdP5YxqiB+iDtLoaTz4Nd35+IiAv0kQ5FNKHzXgdWqPoTIqEDDJmXceQt4JZk6lVPT8lnDlPpGDppw== + dependencies: + punycode "^2.1.1" + trim-repeated@^1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/trim-repeated/-/trim-repeated-1.0.0.tgz#e3646a2ea4e891312bf7eace6cfb05380bc01c21" @@ -3961,6 +4241,13 @@ tsutils@^1.1.0: resolved "https://registry.yarnpkg.com/tsutils/-/tsutils-1.9.1.tgz#b9f9ab44e55af9681831d5f28d0aeeaf5c750cb0" integrity sha1-ufmrROVa+WgYMdXyjQrur1x1DLA= +type-check@~0.3.2: + version "0.3.2" + resolved "https://registry.yarnpkg.com/type-check/-/type-check-0.3.2.tgz#5884cab512cf1d355e3fb784f30804b2b520db72" + integrity sha1-WITKtRLPHTVeP7eE8wgEsrUg23I= + dependencies: + prelude-ls "~1.1.2" + type-detect@^4.0.0, type-detect@^4.0.5: version "4.0.8" resolved "https://registry.yarnpkg.com/type-detect/-/type-detect-4.0.8.tgz#7646fb5f18871cfbb7749e69bd39a6388eb7450c" @@ -4004,6 +4291,11 @@ unique-string@^1.0.0: dependencies: crypto-random-string "^1.0.0" +universalify@^0.1.2: + version "0.1.2" + resolved "https://registry.yarnpkg.com/universalify/-/universalify-0.1.2.tgz#b646f69be3942dabcecc9d6639c80dc105efaa66" + integrity sha512-rBJeI5CXAlmy1pV+617WB9J63U6XcazHHF2f2dbJix4XzpUF0RS3Zbj0FGIOCAva5P/d/GBOYaACQ1w+0azUkg== + unpipe@1.0.0, unpipe@~1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/unpipe/-/unpipe-1.0.0.tgz#b2bf4ee8514aae6165b4817829d21b2ef49904ec" @@ -4072,6 +4364,51 @@ vendors@^1.0.0: resolved "https://registry.yarnpkg.com/vendors/-/vendors-1.0.4.tgz#e2b800a53e7a29b93506c3cf41100d16c4c4ad8e" integrity sha512-/juG65kTL4Cy2su4P8HjtkTxk6VmJDiOPBufWniqQ6wknac6jNiXS9vU+hO3wgusiyqWlzTbVHi0dyJqRONg3w== +w3c-hr-time@^1.0.2: + version "1.0.2" + resolved "https://registry.yarnpkg.com/w3c-hr-time/-/w3c-hr-time-1.0.2.tgz#0a89cdf5cc15822df9c360543676963e0cc308cd" + integrity sha512-z8P5DvDNjKDoFIHK7q8r8lackT6l+jo/Ye3HOle7l9nICP9lf1Ci25fy9vHd0JOWewkIFzXIEig3TdKT7JQ5fQ== + dependencies: + browser-process-hrtime "^1.0.0" + +w3c-xmlserializer@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/w3c-xmlserializer/-/w3c-xmlserializer-2.0.0.tgz#3e7104a05b75146cc60f564380b7f683acf1020a" + integrity sha512-4tzD0mF8iSiMiNs30BiLO3EpfGLZUT2MSX/G+o7ZywDzliWQ3OPtTZ0PTC3B3ca1UAf4cJMHB+2Bf56EriJuRA== + dependencies: + xml-name-validator "^3.0.0" + +webidl-conversions@^5.0.0: + version "5.0.0" + resolved "https://registry.yarnpkg.com/webidl-conversions/-/webidl-conversions-5.0.0.tgz#ae59c8a00b121543a2acc65c0434f57b0fc11aff" + integrity sha512-VlZwKPCkYKxQgeSbH5EyngOmRp7Ww7I9rQLERETtf5ofd9pGeswWiOtogpEO850jziPRarreGxn5QIiTqpb2wA== + +webidl-conversions@^6.1.0: + version "6.1.0" + resolved "https://registry.yarnpkg.com/webidl-conversions/-/webidl-conversions-6.1.0.tgz#9111b4d7ea80acd40f5270d666621afa78b69514" + integrity sha512-qBIvFLGiBpLjfwmYAaHPXsn+ho5xZnGvyGvsarywGNc8VyQJUMHJ8OBKGGrPER0okBeMDaan4mNBlgBROxuI8w== + +whatwg-encoding@^1.0.5: + version "1.0.5" + resolved "https://registry.yarnpkg.com/whatwg-encoding/-/whatwg-encoding-1.0.5.tgz#5abacf777c32166a51d085d6b4f3e7d27113ddb0" + integrity sha512-b5lim54JOPN9HtzvK9HFXvBma/rnfFeqsic0hSpjtDbVxR3dJKLc+KB4V6GgiGOvl7CY/KNh8rxSo9DKQrnUEw== + dependencies: + iconv-lite "0.4.24" + +whatwg-mimetype@^2.3.0: + version "2.3.0" + resolved "https://registry.yarnpkg.com/whatwg-mimetype/-/whatwg-mimetype-2.3.0.tgz#3d4b1e0312d2079879f826aff18dbeeca5960fbf" + integrity sha512-M4yMwr6mAnQz76TbJm914+gPpB/nCwvZbJU28cUD6dR004SAxDLOOSUaB1JDRqLtaOV/vi0IC5lEAGFgrjGv/g== + +whatwg-url@^8.0.0, whatwg-url@^8.5.0: + version "8.7.0" + resolved "https://registry.yarnpkg.com/whatwg-url/-/whatwg-url-8.7.0.tgz#656a78e510ff8f3937bc0bcbe9f5c0ac35941b77" + integrity sha512-gAojqb/m9Q8a5IV96E3fHJM70AzCkgt4uXYX2O7EmuyOnLrViCQlsEBmF9UQIu3/aeAIp2U17rtbpZWNntQqdg== + dependencies: + lodash "^4.7.0" + tr46 "^2.1.0" + webidl-conversions "^6.1.0" + which@^1.2.9: version "1.3.1" resolved "https://registry.yarnpkg.com/which/-/which-1.3.1.tgz#a45043d54f5805316da8d62f9f50918d3da70b0a" @@ -4093,6 +4430,11 @@ widest-line@^2.0.0: dependencies: string-width "^2.1.1" +word-wrap@~1.2.3: + version "1.2.3" + resolved "https://registry.yarnpkg.com/word-wrap/-/word-wrap-1.2.3.tgz#610636f6b1f703891bd34771ccb17fb93b47079c" + integrity sha512-Hz/mrNwitNRh/HUAtM/VT/5VH+ygD6DV7mYKZAtHOrbs8U7lvPS6xf7EJKMF0uW1KJCl0H701g3ZGus+muE5vQ== + wordwrap@~0.0.2: version "0.0.3" resolved "https://registry.yarnpkg.com/wordwrap/-/wordwrap-0.0.3.tgz#a3d5da6cd5c0bc0008d37234bbaf1bed63059107" @@ -4117,11 +4459,26 @@ ws@^7.2.3: resolved "https://registry.yarnpkg.com/ws/-/ws-7.4.6.tgz#5654ca8ecdeee47c33a9a4bf6d28e2be2980377c" integrity sha512-YmhHDO4MzaDLB+M9ym/mDA5z0naX8j7SIlT8f8z+I0VtzsRbekxEutHSme7NPS2qE8StCYQNUnfWdXta/Yu85A== +ws@^7.4.5: + version "7.5.1" + resolved "https://registry.yarnpkg.com/ws/-/ws-7.5.1.tgz#44fc000d87edb1d9c53e51fbc69a0ac1f6871d66" + integrity sha512-2c6faOUH/nhoQN6abwMloF7Iyl0ZS2E9HGtsiLrWn0zOOMWlhtDmdf/uihDt6jnuCxgtwGBNy6Onsoy2s2O2Ow== + xdg-basedir@^3.0.0: version "3.0.0" resolved "https://registry.yarnpkg.com/xdg-basedir/-/xdg-basedir-3.0.0.tgz#496b2cc109eca8dbacfe2dc72b603c17c5870ad4" integrity sha1-SWsswQnsqNus/i3HK2A8F8WHCtQ= +xml-name-validator@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/xml-name-validator/-/xml-name-validator-3.0.0.tgz#6ae73e06de4d8c6e47f9fb181f78d648ad457c6a" + integrity sha512-A5CUptxDsvxKJEU3yO6DuWBSJz/qizqzJKOMIfUJHETbBw/sFaDxgd6fxm1ewUaM0jZ444Fc5vC5ROYurg/4Pw== + +xmlchars@^2.2.0: + version "2.2.0" + resolved "https://registry.yarnpkg.com/xmlchars/-/xmlchars-2.2.0.tgz#060fe1bcb7f9c76fe2a17db86a9bc3ab894210cb" + integrity sha512-JZnDKK8B0RCDw84FNdDAIpZK+JuJw+s7Lz8nksI7SIuU3UXJJslUthsi+uWBUYOwPFwW7W7PRLRfUKpxjtjFCw== + yallist@^2.1.2: version "2.1.2" resolved "https://registry.yarnpkg.com/yallist/-/yallist-2.1.2.tgz#1c11f9218f076089a47dd512f93c6699a6a81d52" From b6ce12aa03c3c7a735b237975cfeb2f20ca78832 Mon Sep 17 00:00:00 2001 From: Justin Halsall Date: Mon, 5 Jul 2021 15:59:17 +0200 Subject: [PATCH 09/18] Refactor virtual style rules to buffer changes. Only applies changes on flush. `virtualStyleRulesMap` now works with strings instead of CSSRules. CSSRules can only be via made `.insertRule` on CSSStyleSheet in most browsers. And `new CSSStyleSheet()` only works in Chrome currently. --- src/replay/index.ts | 114 +++++++++-------------- src/replay/virtual-styles.ts | 12 +-- test/__snapshots__/replayer.test.ts.snap | 108 ++------------------- test/events/style-sheet-rule-events.ts | 4 +- test/replayer.test.ts | 14 +-- test/utils.ts | 31 ++++-- 6 files changed, 84 insertions(+), 199 deletions(-) diff --git a/src/replay/index.ts b/src/replay/index.ts index 0089ff46a2..032431e286 100644 --- a/src/replay/index.ts +++ b/src/replay/index.ts @@ -44,6 +44,7 @@ import getInjectStyleRules from './styles/inject-style'; import './styles/style.css'; import { applyVirtualStyleRulesToNode, + VirtualStyleRules, VirtualStyleRulesMap, } from './virtual-styles'; @@ -142,8 +143,8 @@ export class Replayer { this.fragmentParentMap.forEach((parent, frag) => this.restoreRealParent(frag, parent), ); - for (const [node] of this.virtualStyleRulesMap.entries()) { - // restore css rules of elements after they are mounted + for (const node of this.virtualStyleRulesMap.keys()) { + // restore css rules of style elements after they are mounted this.restoreNodeSheet(node); } this.fragmentParentMap.clear(); @@ -924,71 +925,51 @@ export class Replayer { /** * Always use existing DOM node, when it's there. - * In in-memory replay, there is virtual node, but it's `sheet` will be removed during replacement. - * Hence, we re-create it and re-populate it on each run to not miss pre-existing styles and previously inserted + * In in-memory replay, there is virtual node, but it's `sheet` is inaccessible. + * Hence, we buffer all style changes in virtualStyleRulesMap. */ - const styleSheet = usingVirtualParent - ? new CSSStyleSheet() - : styleEl.sheet - ? styleEl.sheet - : new CSSStyleSheet(); - let placeholderNode; - - if (usingVirtualParent) { + const styleSheet = usingVirtualParent ? null : styleEl.sheet; + let rules: VirtualStyleRules; + + if (!styleSheet) { /** * styleEl.sheet is only accessible if the styleEl is part of the - * dom. This doesn't work on DocumentFragments so we have to re-add - * it to the dom temporarily. + * dom. This doesn't work on DocumentFragments so we have to add the + * style mutations to the virtualStyleRulesMap. */ - const domParent = this.fragmentParentMap.get( - (target.parentNode as unknown) as INode, - ); - placeholderNode = document.createTextNode(''); - parent.replaceChild(placeholderNode, target); - domParent!.appendChild(target); - - if (!this.virtualStyleRulesMap.has(target)) { - this.virtualStyleRulesMap.set( - target, - Array.from(styleEl.sheet?.cssRules || []).map((rule, index) => [ - rule, - index, - ]), // { - if (rule) { - styleSheet?.insertRule(rule.cssText, index); - } else { - styleSheet?.deleteRule(index); - } - }); + if (this.virtualStyleRulesMap.has(target)) { + rules = this.virtualStyleRulesMap.get(target) as VirtualStyleRules; + } else { + rules = []; + this.virtualStyleRulesMap.set(target, rules); } } if (d.adds) { d.adds.forEach(({ rule, index }) => { - try { - const _index = - index === undefined - ? undefined - : Math.min(index, styleSheet.cssRules.length); + if (styleSheet) { try { - styleSheet.insertRule(rule, _index); + const _index = + index === undefined + ? undefined + : Math.min(index, styleSheet.cssRules.length); + try { + styleSheet.insertRule(rule, _index); + } catch (e) { + /** + * sometimes we may capture rules with browser prefix + * insert rule with prefixs in other browsers may cause Error + */ + } } catch (e) { /** - * sometimes we may capture rules with browser prefix - * insert rule with prefixs in other browsers may cause Error + * accessing styleSheet rules may cause SecurityError + * for specific access control settings */ } - } catch (e) { - /** - * accessing styleSheet rules may cause SecurityError - * for specific access control settings - */ + } else { + rules?.push([rule, index]); } }); } @@ -996,29 +977,18 @@ export class Replayer { if (d.removes) { d.removes.forEach(({ index }) => { if (usingVirtualParent) { - } - try { - styleSheet.deleteRule(index); - } catch (e) { - /** - * same as insertRule - */ + rules?.push([false, index]); + } else { + try { + styleSheet?.deleteRule(index); + } catch (e) { + /** + * same as insertRule + */ + } } }); } - if (usingVirtualParent) { - // Update rules list according to new styleSheet - this.virtualStyleRulesMap.set( - target, - Array.from(styleSheet?.cssRules || []).map((rule, index) => [ - rule, - index, - ]), - ); - } - if (usingVirtualParent && placeholderNode) { - parent.replaceChild(target, placeholderNode); - } break; } case IncrementalSource.CanvasMutation: { diff --git a/src/replay/virtual-styles.ts b/src/replay/virtual-styles.ts index 6c0367868a..3f251e6ceb 100644 --- a/src/replay/virtual-styles.ts +++ b/src/replay/virtual-styles.ts @@ -1,6 +1,8 @@ import { INode } from 'rrweb-snapshot'; -export type VirtualStyleRules = [CSSRule | false, number][]; +type Rule = string | false; +type Index = number | undefined; +export type VirtualStyleRules = [Rule, Index][]; export type VirtualStyleRulesMap = Map; export function applyVirtualStyleRulesToNode( @@ -8,14 +10,10 @@ export function applyVirtualStyleRulesToNode( styleNode: HTMLStyleElement, ) { storedRules.forEach(([rule, index]) => { - // Ensure consistency of cssRules list - // if (styleNode?.sheet?.cssRules[index]) { - // styleNode.sheet?.deleteRule(index); - // } if (rule) { - styleNode.sheet?.insertRule(rule.cssText, index); + styleNode.sheet?.insertRule(rule, index); } else { - styleNode.sheet?.deleteRule(index); + if (index !== undefined) styleNode.sheet?.deleteRule(index); } }); // Avoid situation, when your Node has more styles, than it should diff --git a/test/__snapshots__/replayer.test.ts.snap b/test/__snapshots__/replayer.test.ts.snap index bef7cf98e2..6f53e74397 100644 --- a/test/__snapshots__/replayer.test.ts.snap +++ b/test/__snapshots__/replayer.test.ts.snap @@ -1,7 +1,7 @@ // Jest Snapshot v1, https://goo.gl/fbAQLP -exports[`style-sheet-rule-events-1500 1`] = ` -"file-frame-3 +exports[`style-sheet-remove-events-play-at-2500 1`] = ` +"file-frame-1 @@ -19,80 +19,14 @@ exports[`style-sheet-rule-events-1500 1`] = ` -file-frame-4 - - - - - - - - - - - - - - -file-cid-0 -@charset \\"utf-8\\"; - -.rr-block { background: rgb(204, 204, 204); } - -noscript { display: none !important; } - -html.rrweb-paused * { animation-play-state: paused !important; } - - -file-cid-1 -@charset \\"utf-8\\"; - -.c01x { opacity: 1; transform: translateX(0px); } - - -file-cid-2 -@charset \\"utf-8\\"; - -.css-1uxxxx3 { position: fixed; top: 0px; right: 0px; left: 4rem; z-index: 15; flex-shrink: 0; height: 0.25rem; overflow: hidden; background-color: rgb(17, 171, 209); } - -.css-1c9xxxx { height: 0.25rem; background-color: rgb(190, 232, 242); opacity: 0; transition: opacity 0.5s ease 0s; } - -.css-lsxxx { padding-left: 4rem; } -" -`; - -exports[`style-sheet-rule-events-pause-at-1500 1`] = ` -"file-frame-4 +file-frame-2 - - - - - -
-
- -
- - - - -file-frame-5 - - - - - - string @@ -105,30 +39,6 @@ file-cid-0 noscript { display: none !important; } html.rrweb-paused * { animation-play-state: paused !important; } - - -file-cid-1 -@charset \\"utf-8\\"; - -.c011xx { padding: 1.3125rem; flex: 0 0 auto; width: 100%; } - - -file-cid-2 -@charset \\"utf-8\\"; - -.c01x { opacity: 1; transform: translateX(0px); } - - -file-cid-3 -@charset \\"utf-8\\"; - -.css-1fbxx79 { display: flex; flex-direction: column; min-width: 60rem; min-height: 100vh; color: blue; } - -.css-1uxxxx3 { position: fixed; top: 0px; right: 0px; left: 4rem; z-index: 15; flex-shrink: 0; height: 0.25rem; overflow: hidden; background-color: rgb(17, 171, 209); } - -.css-1c9xxxx { height: 0.25rem; background-color: rgb(190, 232, 242); opacity: 0; transition: opacity 0.5s ease 0s; } - -.css-lsxxx { padding-left: 4rem; } " `; @@ -163,7 +73,7 @@ file-frame-5 - string + string @@ -193,10 +103,10 @@ file-cid-2 file-cid-3 @charset \\"utf-8\\"; -.css-1fbxx79 { display: flex; flex-direction: column; min-width: 60rem; min-height: 100vh; color: blue; } - .css-1uxxxx3 { position: fixed; top: 0px; right: 0px; left: 4rem; z-index: 15; flex-shrink: 0; height: 0.25rem; overflow: hidden; background-color: rgb(17, 171, 209); } +.css-1c9xxxx { height: 0.25rem; background-color: rgb(190, 232, 242); opacity: 0; transition: opacity 0.5s ease 0s; } + .css-lsxxx { padding-left: 4rem; } " `; @@ -232,7 +142,7 @@ file-frame-5 - string + string @@ -262,12 +172,12 @@ file-cid-2 file-cid-3 @charset \\"utf-8\\"; -.css-1fbxx79 { display: flex; flex-direction: column; min-width: 60rem; min-height: 100vh; color: blue; } - .css-1uxxxx3 { position: fixed; top: 0px; right: 0px; left: 4rem; z-index: 15; flex-shrink: 0; height: 0.25rem; overflow: hidden; background-color: rgb(17, 171, 209); } .css-1c9xxxx { height: 0.25rem; background-color: rgb(190, 232, 242); opacity: 0; transition: opacity 0.5s ease 0s; } +.css-added-at-1000-deleted-at-2500 { display: flex; flex-direction: column; min-width: 60rem; min-height: 100vh; color: blue; } + .css-lsxxx { padding-left: 4rem; } " `; diff --git a/test/events/style-sheet-rule-events.ts b/test/events/style-sheet-rule-events.ts index 5e6f1ae33c..067411ed6d 100644 --- a/test/events/style-sheet-rule-events.ts +++ b/test/events/style-sheet-rule-events.ts @@ -85,7 +85,7 @@ const events: eventWithTime[] = [ type: 2, tagName: 'a', attributes: { - class: 'css-1fbxx79', + class: 'css-added-at-1000-deleted-at-2500', }, childNodes: [ { @@ -148,7 +148,7 @@ const events: eventWithTime[] = [ adds: [ { rule: - '.css-1fbxx79{display:-webkit-box;display:-webkit-flex;display:-ms-flexbox;display:flex;-webkit-flex-direction:column;-ms-flex-direction:column;flex-direction:column;min-width:60rem;min-height:100vh;color:blue;}', + '.css-added-at-1000-deleted-at-2500{display:-webkit-box;display:-webkit-flex;display:-ms-flexbox;display:flex;-webkit-flex-direction:column;-ms-flex-direction:column;flex-direction:column;min-width:60rem;min-height:100vh;color:blue;}', index: 2, }, ], diff --git a/test/replayer.test.ts b/test/replayer.test.ts index 663c576dcc..38f8b62ad0 100644 --- a/test/replayer.test.ts +++ b/test/replayer.test.ts @@ -159,14 +159,6 @@ describe('replayer', function (this: ISuite) { __filename, 'style-sheet-rule-events-play-at-1500', ); - const result = await this.page.evaluate(` - const rules = [...replayer.iframe.contentDocument.styleSheets].map( - (sheet) => sheet.rules, - ); - rules.some((x) => x.selectorText === '.css-1fbxx79'); - `); - - expect(result).to.equal(true); }); it('should apply fast forwarded StyleSheetRules that where added', async () => { @@ -180,7 +172,7 @@ describe('replayer', function (this: ISuite) { const rules = [...replayer.iframe.contentDocument.styleSheets].map( (sheet) => [...sheet.rules], ).flat(); - rules.some((x) => x.selectorText === '.css-1fbxx79'); + rules.some((x) => x.selectorText === '.css-added-at-1000-deleted-at-2500'); `); expect(result).to.equal(true); @@ -234,11 +226,11 @@ describe('replayer', function (this: ISuite) { const result = await this.page.evaluate(` const { Replayer } = rrweb; const replayer = new Replayer(events); - replayer.pause(2500); + replayer.pause(3000); const rules = [...replayer.iframe.contentDocument.styleSheets].map( (sheet) => [...sheet.rules], ).flat(); - rules.some((x) => x.selectorText === '.css-1fbxx79'); + rules.some((x) => x.selectorText === '.css-added-at-1000-deleted-at-2500'); `); expect(result).to.equal(false); diff --git a/test/utils.ts b/test/utils.ts index a8e2f60523..d096926cd8 100644 --- a/test/utils.ts +++ b/test/utils.ts @@ -107,6 +107,12 @@ function stringifySnapshots(snapshots: eventWithTime[]): string { ); } +function replaceMHTMLCID(string: string): string { + const linebreakAt = string.indexOf('='); + const output = 'cid:________________________________________@mhtml.blink'; + return output.slice(0, linebreakAt) + '=\n' + output.slice(linebreakAt); +} + function stringifyDomSnapshot(mhtml: string): string { const { Parser } = require('fast-mhtml'); const resources: string[] = []; @@ -137,16 +143,8 @@ function stringifyDomSnapshot(mhtml: string): string { indent_spaces: 2, wrap: 80, markup: true, - output_xml: false, - numeric_entities: true, quote_marks: true, - quote_nbsp: false, - // 'show_body_only': true, - quote_ampersand: false, break_before_br: true, - uppercase_tags: false, - // 'uppercase_attributes': false, - // 'drop_font_tags': true, tidy_mark: false, }; doc.parseBufferSync(Buffer.from(content)); @@ -156,6 +154,23 @@ function stringifyDomSnapshot(mhtml: string): string { }, ); return newResult.map((asset) => Object.values(asset).join('\n')).join('\n\n'); + // return mhtml + // .replace(/\r?\n/gm, '\n') + // .replace(/Date: .+/, 'Date:') + // .replace( + // /----MultipartBoundary--\w+----/g, + // '----MultipartBoundary--test----', + // ) + // .replace( + // /cid:[\w-]{40}@mhtml\.blink/g, + // 'cid:________________________________________@mhtml.blink', + // ) + // .replace( + // /frame-[\w]{32}@mhtml\.blink/g, + // 'frame-________________________________@mhtml.blink', + // ) + // .replace(/c[^@]{45,46}@mhtml\.blink/gm, replaceMHTMLCID) + // .replace(/cid:[\w\-]{40}@[\w\.=\n\r]{12,13}k/gm, replaceMHTMLCID); } export function assertSnapshot( From e8df6bf181e8fd8317c7027ce9baaba7c32e7ea0 Mon Sep 17 00:00:00 2001 From: Justin Halsall Date: Mon, 5 Jul 2021 16:04:40 +0200 Subject: [PATCH 10/18] remove unused code --- test/utils.ts | 23 ----------------------- 1 file changed, 23 deletions(-) diff --git a/test/utils.ts b/test/utils.ts index d096926cd8..348bed7164 100644 --- a/test/utils.ts +++ b/test/utils.ts @@ -107,12 +107,6 @@ function stringifySnapshots(snapshots: eventWithTime[]): string { ); } -function replaceMHTMLCID(string: string): string { - const linebreakAt = string.indexOf('='); - const output = 'cid:________________________________________@mhtml.blink'; - return output.slice(0, linebreakAt) + '=\n' + output.slice(linebreakAt); -} - function stringifyDomSnapshot(mhtml: string): string { const { Parser } = require('fast-mhtml'); const resources: string[] = []; @@ -154,23 +148,6 @@ function stringifyDomSnapshot(mhtml: string): string { }, ); return newResult.map((asset) => Object.values(asset).join('\n')).join('\n\n'); - // return mhtml - // .replace(/\r?\n/gm, '\n') - // .replace(/Date: .+/, 'Date:') - // .replace( - // /----MultipartBoundary--\w+----/g, - // '----MultipartBoundary--test----', - // ) - // .replace( - // /cid:[\w-]{40}@mhtml\.blink/g, - // 'cid:________________________________________@mhtml.blink', - // ) - // .replace( - // /frame-[\w]{32}@mhtml\.blink/g, - // 'frame-________________________________@mhtml.blink', - // ) - // .replace(/c[^@]{45,46}@mhtml\.blink/gm, replaceMHTMLCID) - // .replace(/cid:[\w\-]{40}@[\w\.=\n\r]{12,13}k/gm, replaceMHTMLCID); } export function assertSnapshot( From d2cbb2d0a9edd9e76df29f3760a809ac4d4fa843 Mon Sep 17 00:00:00 2001 From: Justin Halsall Date: Mon, 5 Jul 2021 16:05:20 +0200 Subject: [PATCH 11/18] move VirtualStyleRules from CSSRule to string in tests --- test/replayer/virtual-styles.test.ts | 8 ++------ 1 file changed, 2 insertions(+), 6 deletions(-) diff --git a/test/replayer/virtual-styles.test.ts b/test/replayer/virtual-styles.test.ts index 99a566f4ed..930a1e48e3 100644 --- a/test/replayer/virtual-styles.test.ts +++ b/test/replayer/virtual-styles.test.ts @@ -16,9 +16,7 @@ describe('virtual styles', () => { const styleEl = dom.window.document.getElementsByTagName('style')[0]; const cssRule = '.x {border: 1px solid yellow;}'; - const virtualStyleRules: VirtualStyleRules = [ - [{ cssText: cssRule } as CSSRule, 0], - ]; + const virtualStyleRules: VirtualStyleRules = [[cssRule, 0]]; applyVirtualStyleRulesToNode(virtualStyleRules, styleEl); expect(styleEl.sheet?.cssRules?.length).to.equal(1); @@ -35,9 +33,7 @@ describe('virtual styles', () => { const styleEl = dom.window.document.getElementsByTagName('style')[0]; const cssRule = '.x {border: 1px solid yellow;}'; - const virtualStyleRules: VirtualStyleRules = [ - [{ cssText: cssRule } as CSSRule, 0], - ]; + const virtualStyleRules: VirtualStyleRules = [[cssRule, 0]]; applyVirtualStyleRulesToNode(virtualStyleRules, styleEl); expect(styleEl.sheet?.cssRules?.length).to.equal(3); From af300299d3793a3fab63869c88bbff7ecb75b04c Mon Sep 17 00:00:00 2001 From: Justin Halsall Date: Mon, 5 Jul 2021 17:13:17 +0200 Subject: [PATCH 12/18] correct paths for tests --- package.json | 4 ++-- test/{replayer => replay}/virtual-styles.test.ts | 0 2 files changed, 2 insertions(+), 2 deletions(-) rename test/{replayer => replay}/virtual-styles.test.ts (100%) diff --git a/package.json b/package.json index 7b6245c01f..a3960f5bb1 100644 --- a/package.json +++ b/package.json @@ -5,8 +5,8 @@ "scripts": { "prepare": "npm run prepack", "prepack": "npm run bundle", - "test": "npm run bundle:browser && cross-env TS_NODE_CACHE=false TS_NODE_FILES=true mocha -r ts-node/register -r ignore-styles -r jsdom-global/register test/**/*.test.ts", - "test:headless": "npm run bundle:browser && cross-env TS_NODE_CACHE=false TS_NODE_FILES=true PUPPETEER_HEADLESS=true mocha -r ts-node/register -r ignore-styles -r jsdom-global/register test/**/*.test.ts", + "test": "npm run bundle:browser && cross-env TS_NODE_CACHE=false TS_NODE_FILES=true mocha -r ts-node/register -r ignore-styles -r jsdom-global/register test/**.test.ts", + "test:headless": "npm run bundle:browser && cross-env TS_NODE_CACHE=false TS_NODE_FILES=true PUPPETEER_HEADLESS=true mocha -r ts-node/register -r ignore-styles -r jsdom-global/register test/**.test.ts", "test:watch": "PUPPETEER_HEADLESS=true npm run test -- --watch --watch-extensions js,ts", "repl": "npm run bundle:browser && cross-env TS_NODE_CACHE=false TS_NODE_FILES=true ts-node scripts/repl.ts", "bundle:browser": "cross-env BROWSER_ONLY=true rollup --config", diff --git a/test/replayer/virtual-styles.test.ts b/test/replay/virtual-styles.test.ts similarity index 100% rename from test/replayer/virtual-styles.test.ts rename to test/replay/virtual-styles.test.ts From 1b367b6e9dcf151d88c58428a058eb93bf70c601 Mon Sep 17 00:00:00 2001 From: Justin Halsall Date: Mon, 5 Jul 2021 17:19:51 +0200 Subject: [PATCH 13/18] naming --- test/replayer.test.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/replayer.test.ts b/test/replayer.test.ts index 38f8b62ad0..cbbdd3b81c 100644 --- a/test/replayer.test.ts +++ b/test/replayer.test.ts @@ -219,7 +219,7 @@ describe('replayer', function (this: ISuite) { ); }); - it('should delete fast forwarded StyleSheetRules that where deleted', async () => { + it('should delete fast forwarded StyleSheetRules that where removed', async () => { await this.page.evaluate( `events = ${JSON.stringify(styleSheetRuleEvents)}`, ); From 8ee22eeb531ab4e5118b58d1f6f64feb84dd6884 Mon Sep 17 00:00:00 2001 From: Justin Halsall Date: Tue, 6 Jul 2021 12:45:03 +0200 Subject: [PATCH 14/18] create and restore style snapshots for virtual nodes --- src/replay/index.ts | 20 ++++++- src/replay/virtual-styles.ts | 70 +++++++++++++++++------ test/__snapshots__/replayer.test.ts.snap | 10 ++-- test/events/style-sheet-rule-events.ts | 18 +++++- test/replay/virtual-styles.test.ts | 72 +++++++++++++++++++++--- 5 files changed, 157 insertions(+), 33 deletions(-) diff --git a/src/replay/index.ts b/src/replay/index.ts index 032431e286..364551405b 100644 --- a/src/replay/index.ts +++ b/src/replay/index.ts @@ -44,6 +44,7 @@ import getInjectStyleRules from './styles/inject-style'; import './styles/style.css'; import { applyVirtualStyleRulesToNode, + StyleRuleType, VirtualStyleRules, VirtualStyleRulesMap, } from './virtual-styles'; @@ -969,7 +970,7 @@ export class Replayer { */ } } else { - rules?.push([rule, index]); + rules?.push({ cssText: rule, index, type: StyleRuleType.Insert }); } }); } @@ -977,7 +978,7 @@ export class Replayer { if (d.removes) { d.removes.forEach(({ index }) => { if (usingVirtualParent) { - rules?.push([false, index]); + rules?.push({ index, type: StyleRuleType.Remove }); } else { try { styleSheet?.deleteRule(index); @@ -1518,6 +1519,21 @@ export class Replayer { scroll: [parentElement.scrollLeft, parentElement.scrollTop], }); } + if (parentElement.tagName === 'STYLE') { + try { + const cssTexts = Array.from( + (parentElement as HTMLStyleElement).sheet?.cssRules || [], + ).map((rule) => rule.cssText); + this.virtualStyleRulesMap.set(parent, [ + { + type: StyleRuleType.Snapshot, + cssTexts, + }, + ]); + } catch (e) { + // we where not allowed to access stylesheet cssRules, probably due to CORS + } + } const children = parentElement.children; for (const child of Array.from(children)) { this.storeState((child as unknown) as INode); diff --git a/src/replay/virtual-styles.ts b/src/replay/virtual-styles.ts index 3f251e6ceb..cf7ffc062a 100644 --- a/src/replay/virtual-styles.ts +++ b/src/replay/virtual-styles.ts @@ -1,30 +1,64 @@ import { INode } from 'rrweb-snapshot'; -type Rule = string | false; -type Index = number | undefined; -export type VirtualStyleRules = [Rule, Index][]; +export enum StyleRuleType { + Insert, + Remove, + Snapshot, +} + +type InsertRule = { + cssText: string; + type: StyleRuleType.Insert; + index?: number; +}; +type RemoveRule = { + type: StyleRuleType.Remove; + index: number; +}; +type SnapshotRule = { + type: StyleRuleType.Snapshot; + cssTexts: string[]; +}; + +export type VirtualStyleRules = Array; export type VirtualStyleRulesMap = Map; export function applyVirtualStyleRulesToNode( storedRules: VirtualStyleRules, styleNode: HTMLStyleElement, ) { - storedRules.forEach(([rule, index]) => { - if (rule) { - styleNode.sheet?.insertRule(rule, index); - } else { - if (index !== undefined) styleNode.sheet?.deleteRule(index); + storedRules.forEach((rule) => { + if (rule.type === StyleRuleType.Insert) { + styleNode.sheet?.insertRule(rule.cssText, rule.index); + } else if (rule.type === StyleRuleType.Remove) { + styleNode.sheet?.deleteRule(rule.index); + } else if (rule.type === StyleRuleType.Snapshot) { + restoreSnapshotOfStyleRulesToNode(rule.cssTexts, styleNode); + } + }); +} + +function restoreSnapshotOfStyleRulesToNode( + cssTexts: string[], + styleNode: HTMLStyleElement, +) { + const existingRules = Array.from(styleNode.sheet?.cssRules || []).map( + (rule) => rule.cssText, + ); + const existingRulesReversed = Object.entries(existingRules).reverse(); + let lastMatch = existingRules.length; + + existingRulesReversed.forEach(([index, rule]) => { + const indexOf = cssTexts.indexOf(rule); + if (indexOf === -1 || indexOf > lastMatch) { + styleNode.sheet?.deleteRule(Number(index)); } + lastMatch = indexOf; }); - // Avoid situation, when your Node has more styles, than it should - // Otherwise, inserting will be broken - if (styleNode.sheet && styleNode.sheet.cssRules.length > storedRules.length) { - for ( - let i = styleNode.sheet.cssRules.length - 1; - i < storedRules.length - 1; - i-- - ) { - styleNode.sheet.removeRule(i); + + cssTexts.forEach((cssText, index) => { + if (styleNode.sheet?.cssRules[index]?.cssText !== cssText) { + styleNode.sheet?.insertRule(cssText, index); } - } + }); } diff --git a/test/__snapshots__/replayer.test.ts.snap b/test/__snapshots__/replayer.test.ts.snap index 6f53e74397..5bbcbfba3a 100644 --- a/test/__snapshots__/replayer.test.ts.snap +++ b/test/__snapshots__/replayer.test.ts.snap @@ -42,7 +42,7 @@ html.rrweb-paused * { animation-play-state: paused !important; } " `; -exports[`style-sheet-rule-events-pause-at-2500 1`] = ` +exports[`style-sheet-rule-events-play-at-1500 1`] = ` "file-frame-4 @@ -99,6 +99,8 @@ file-cid-2 .c01x { opacity: 1; transform: translateX(0px); } +.css-added-at-400 { border: 1px solid blue; } + file-cid-3 @charset \\"utf-8\\"; @@ -107,11 +109,13 @@ file-cid-3 .css-1c9xxxx { height: 0.25rem; background-color: rgb(190, 232, 242); opacity: 0; transition: opacity 0.5s ease 0s; } +.css-added-at-1000-deleted-at-2500 { display: flex; flex-direction: column; min-width: 60rem; min-height: 100vh; color: blue; } + .css-lsxxx { padding-left: 4rem; } " `; -exports[`style-sheet-rule-events-play-at-1500 1`] = ` +exports[`style-sheet-rule-events-play-at-2500 1`] = ` "file-frame-4 @@ -176,8 +180,6 @@ file-cid-3 .css-1c9xxxx { height: 0.25rem; background-color: rgb(190, 232, 242); opacity: 0; transition: opacity 0.5s ease 0s; } -.css-added-at-1000-deleted-at-2500 { display: flex; flex-direction: column; min-width: 60rem; min-height: 100vh; color: blue; } - .css-lsxxx { padding-left: 4rem; } " `; diff --git a/test/events/style-sheet-rule-events.ts b/test/events/style-sheet-rule-events.ts index 067411ed6d..0e26673916 100644 --- a/test/events/style-sheet-rule-events.ts +++ b/test/events/style-sheet-rule-events.ts @@ -46,8 +46,7 @@ const events: eventWithTime[] = [ type: 2, tagName: 'style', attributes: { - 'data-jss': '', - 'data-meta': 'sk, Unthemed, Static', + 'data-meta': 'from full-snapshot, gets rule added at 500', }, childNodes: [ { @@ -106,6 +105,21 @@ const events: eventWithTime[] = [ type: EventType.FullSnapshot, timestamp: now + 100, }, + // mutation that adds style rule to existing stylesheet + { + data: { + id: 101, + adds: [ + { + rule: '.css-added-at-400{border: 1px solid blue;}', + index: 1, + }, + ], + source: IncrementalSource.StyleSheetRule, + }, + type: EventType.IncrementalSnapshot, + timestamp: now + 400, + }, // mutation that adds stylesheet { data: { diff --git a/test/replay/virtual-styles.test.ts b/test/replay/virtual-styles.test.ts index 930a1e48e3..bbc44303dc 100644 --- a/test/replay/virtual-styles.test.ts +++ b/test/replay/virtual-styles.test.ts @@ -4,6 +4,7 @@ import { Replayer } from '../../src/replay'; import { JSDOM } from 'jsdom'; import { applyVirtualStyleRulesToNode, + StyleRuleType, VirtualStyleRules, } from '../../src/replay/virtual-styles'; @@ -15,12 +16,15 @@ describe('virtual styles', () => { `); const styleEl = dom.window.document.getElementsByTagName('style')[0]; - const cssRule = '.x {border: 1px solid yellow;}'; - const virtualStyleRules: VirtualStyleRules = [[cssRule, 0]]; + const cssText = '.x {border: 1px solid yellow;}'; + + const virtualStyleRules: VirtualStyleRules = [ + { cssText, index: 0, type: StyleRuleType.Insert }, + ]; applyVirtualStyleRulesToNode(virtualStyleRules, styleEl); expect(styleEl.sheet?.cssRules?.length).to.equal(1); - expect(styleEl.sheet?.cssRules[0].cssText).to.equal(cssRule); + expect(styleEl.sheet?.cssRules[0].cssText).to.equal(cssText); }); it('should insert rule at index 0 and keep exsisting rules', () => { @@ -32,12 +36,14 @@ describe('virtual styles', () => { `); const styleEl = dom.window.document.getElementsByTagName('style')[0]; - const cssRule = '.x {border: 1px solid yellow;}'; - const virtualStyleRules: VirtualStyleRules = [[cssRule, 0]]; + const cssText = '.x {border: 1px solid yellow;}'; + const virtualStyleRules: VirtualStyleRules = [ + { cssText, index: 0, type: StyleRuleType.Insert }, + ]; applyVirtualStyleRulesToNode(virtualStyleRules, styleEl); expect(styleEl.sheet?.cssRules?.length).to.equal(3); - expect(styleEl.sheet?.cssRules[0].cssText).to.equal(cssRule); + expect(styleEl.sheet?.cssRules[0].cssText).to.equal(cssText); }); it('should delete rule at index 1', () => { @@ -49,7 +55,9 @@ describe('virtual styles', () => { `); const styleEl = dom.window.document.getElementsByTagName('style')[0]; - const virtualStyleRules: VirtualStyleRules = [[false, 0]]; + const virtualStyleRules: VirtualStyleRules = [ + { index: 0, type: StyleRuleType.Remove }, + ]; applyVirtualStyleRulesToNode(virtualStyleRules, styleEl); expect(styleEl.sheet?.cssRules?.length).to.equal(1); @@ -57,5 +65,55 @@ describe('virtual styles', () => { 'div {color: black;}', ); }); + + it('should restore a snapshot by inserting missing rules', () => { + const dom = new JSDOM(` + + `); + const styleEl = dom.window.document.getElementsByTagName('style')[0]; + + const virtualStyleRules: VirtualStyleRules = [ + { + cssTexts: ['a {color: blue;}', 'div {color: black;}'], + type: StyleRuleType.Snapshot, + }, + ]; + applyVirtualStyleRulesToNode(virtualStyleRules, styleEl); + + expect(styleEl.sheet?.cssRules?.length).to.equal(2); + }); + + it('should restore a snapshot by fixing order of rules', () => { + const dom = new JSDOM(` + + `); + const styleEl = dom.window.document.getElementsByTagName('style')[0]; + + const cssTexts = ['a {color: blue;}', 'div {color: black;}']; + + const virtualStyleRules: VirtualStyleRules = [ + { + cssTexts, + type: StyleRuleType.Snapshot, + }, + ]; + applyVirtualStyleRulesToNode(virtualStyleRules, styleEl); + + console.log( + 'y', + Array.from(styleEl.sheet?.cssRules || []).map((rule) => rule.cssText), + ); + expect(styleEl.sheet?.cssRules?.length).to.equal(2); + expect( + Array.from(styleEl.sheet?.cssRules || []).map((rule) => rule.cssText), + ).to.have.ordered.members(cssTexts); + }); }); }); From a4dc7800855651d0d461cc87d134101e3f2bb5af Mon Sep 17 00:00:00 2001 From: Justin Halsall Date: Tue, 6 Jul 2021 12:49:42 +0200 Subject: [PATCH 15/18] update replayer snapshot --- test/__snapshots__/replayer.test.ts.snap | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/test/__snapshots__/replayer.test.ts.snap b/test/__snapshots__/replayer.test.ts.snap index 5bbcbfba3a..c6f8e3866d 100644 --- a/test/__snapshots__/replayer.test.ts.snap +++ b/test/__snapshots__/replayer.test.ts.snap @@ -42,7 +42,7 @@ html.rrweb-paused * { animation-play-state: paused !important; } " `; -exports[`style-sheet-rule-events-play-at-1500 1`] = ` +exports[`style-sheet-rule-events-pause-at-2500 1`] = ` "file-frame-4 @@ -109,13 +109,11 @@ file-cid-3 .css-1c9xxxx { height: 0.25rem; background-color: rgb(190, 232, 242); opacity: 0; transition: opacity 0.5s ease 0s; } -.css-added-at-1000-deleted-at-2500 { display: flex; flex-direction: column; min-width: 60rem; min-height: 100vh; color: blue; } - .css-lsxxx { padding-left: 4rem; } " `; -exports[`style-sheet-rule-events-play-at-2500 1`] = ` +exports[`style-sheet-rule-events-play-at-1500 1`] = ` "file-frame-4 @@ -172,6 +170,8 @@ file-cid-2 .c01x { opacity: 1; transform: translateX(0px); } +.css-added-at-400 { border: 1px solid blue; } + file-cid-3 @charset \\"utf-8\\"; @@ -180,6 +180,8 @@ file-cid-3 .css-1c9xxxx { height: 0.25rem; background-color: rgb(190, 232, 242); opacity: 0; transition: opacity 0.5s ease 0s; } +.css-added-at-1000-deleted-at-2500 { display: flex; flex-direction: column; min-width: 60rem; min-height: 100vh; color: blue; } + .css-lsxxx { padding-left: 4rem; } " `; From ccc2f796b9be6e15b7a1c8d5a646d95ce263731d Mon Sep 17 00:00:00 2001 From: Justin Halsall Date: Tue, 6 Jul 2021 14:11:30 +0200 Subject: [PATCH 16/18] move storeCSSRules to virtual-styles.ts --- src/replay/index.ts | 21 ++++++--------------- src/replay/virtual-styles.ts | 21 +++++++++++++++++++-- test/replayer.test.ts | 2 +- 3 files changed, 26 insertions(+), 18 deletions(-) diff --git a/src/replay/index.ts b/src/replay/index.ts index 364551405b..16bee2521b 100644 --- a/src/replay/index.ts +++ b/src/replay/index.ts @@ -44,6 +44,7 @@ import getInjectStyleRules from './styles/inject-style'; import './styles/style.css'; import { applyVirtualStyleRulesToNode, + storeCSSRules, StyleRuleType, VirtualStyleRules, VirtualStyleRulesMap, @@ -1519,21 +1520,11 @@ export class Replayer { scroll: [parentElement.scrollLeft, parentElement.scrollTop], }); } - if (parentElement.tagName === 'STYLE') { - try { - const cssTexts = Array.from( - (parentElement as HTMLStyleElement).sheet?.cssRules || [], - ).map((rule) => rule.cssText); - this.virtualStyleRulesMap.set(parent, [ - { - type: StyleRuleType.Snapshot, - cssTexts, - }, - ]); - } catch (e) { - // we where not allowed to access stylesheet cssRules, probably due to CORS - } - } + if (parentElement.tagName === 'STYLE') + storeCSSRules( + parentElement as HTMLStyleElement, + this.virtualStyleRulesMap, + ); const children = parentElement.children; for (const child of Array.from(children)) { this.storeState((child as unknown) as INode); diff --git a/src/replay/virtual-styles.ts b/src/replay/virtual-styles.ts index cf7ffc062a..0c8e66f17f 100644 --- a/src/replay/virtual-styles.ts +++ b/src/replay/virtual-styles.ts @@ -47,7 +47,6 @@ function restoreSnapshotOfStyleRulesToNode( ); const existingRulesReversed = Object.entries(existingRules).reverse(); let lastMatch = existingRules.length; - existingRulesReversed.forEach(([index, rule]) => { const indexOf = cssTexts.indexOf(rule); if (indexOf === -1 || indexOf > lastMatch) { @@ -55,10 +54,28 @@ function restoreSnapshotOfStyleRulesToNode( } lastMatch = indexOf; }); - cssTexts.forEach((cssText, index) => { if (styleNode.sheet?.cssRules[index]?.cssText !== cssText) { styleNode.sheet?.insertRule(cssText, index); } }); } + +export function storeCSSRules( + parentElement: HTMLStyleElement, + virtualStyleRulesMap: VirtualStyleRulesMap, +) { + try { + const cssTexts = Array.from( + (parentElement as HTMLStyleElement).sheet?.cssRules || [], + ).map((rule) => rule.cssText); + virtualStyleRulesMap.set((parentElement as unknown) as INode, [ + { + type: StyleRuleType.Snapshot, + cssTexts, + }, + ]); + } catch (e) { + // we were not allowed to access stylesheet cssRules, probably due to CORS + } +} diff --git a/test/replayer.test.ts b/test/replayer.test.ts index cbbdd3b81c..bc37e32f35 100644 --- a/test/replayer.test.ts +++ b/test/replayer.test.ts @@ -215,7 +215,7 @@ describe('replayer', function (this: ISuite) { await assertDomSnapshot( this.page, __filename, - 'style-sheet-rule-events-pause-at-2500', + 'style-sheet-rule-events-play-at-2500', ); }); From 501e3762bcca6512754385b33af8af9342e3a7d6 Mon Sep 17 00:00:00 2001 From: Justin Halsall Date: Tue, 6 Jul 2021 14:44:19 +0200 Subject: [PATCH 17/18] try/catch access to .sheet in case of access errors --- src/replay/index.ts | 2 +- src/replay/virtual-styles.ts | 78 +++++++++++++++++++++++++++--------- 2 files changed, 59 insertions(+), 21 deletions(-) diff --git a/src/replay/index.ts b/src/replay/index.ts index 16bee2521b..83361a059a 100644 --- a/src/replay/index.ts +++ b/src/replay/index.ts @@ -92,7 +92,7 @@ export class Replayer { private treeIndex!: TreeIndex; private fragmentParentMap!: Map; private elementStateMap!: Map; - // Hold the list of CSSRules during in-memory state restoration + // Hold the list of CSSRules for in-memory state restoration private virtualStyleRulesMap!: VirtualStyleRulesMap; private imageMap: Map = new Map(); diff --git a/src/replay/virtual-styles.ts b/src/replay/virtual-styles.ts index 0c8e66f17f..43c48be914 100644 --- a/src/replay/virtual-styles.ts +++ b/src/replay/virtual-styles.ts @@ -29,9 +29,23 @@ export function applyVirtualStyleRulesToNode( ) { storedRules.forEach((rule) => { if (rule.type === StyleRuleType.Insert) { - styleNode.sheet?.insertRule(rule.cssText, rule.index); + try { + styleNode.sheet?.insertRule(rule.cssText, rule.index); + } catch (e) { + /** + * sometimes we may capture rules with browser prefix + * insert rule with prefixs in other browsers may cause Error + */ + } } else if (rule.type === StyleRuleType.Remove) { - styleNode.sheet?.deleteRule(rule.index); + try { + styleNode.sheet?.deleteRule(rule.index); + } catch (e) { + /** + * accessing styleSheet rules may cause SecurityError + * for specific access control settings + */ + } } else if (rule.type === StyleRuleType.Snapshot) { restoreSnapshotOfStyleRulesToNode(rule.cssTexts, styleNode); } @@ -42,23 +56,44 @@ function restoreSnapshotOfStyleRulesToNode( cssTexts: string[], styleNode: HTMLStyleElement, ) { - const existingRules = Array.from(styleNode.sheet?.cssRules || []).map( - (rule) => rule.cssText, - ); - const existingRulesReversed = Object.entries(existingRules).reverse(); - let lastMatch = existingRules.length; - existingRulesReversed.forEach(([index, rule]) => { - const indexOf = cssTexts.indexOf(rule); - if (indexOf === -1 || indexOf > lastMatch) { - styleNode.sheet?.deleteRule(Number(index)); - } - lastMatch = indexOf; - }); - cssTexts.forEach((cssText, index) => { - if (styleNode.sheet?.cssRules[index]?.cssText !== cssText) { - styleNode.sheet?.insertRule(cssText, index); - } - }); + try { + const existingRules = Array.from(styleNode.sheet?.cssRules || []).map( + (rule) => rule.cssText, + ); + const existingRulesReversed = Object.entries(existingRules).reverse(); + let lastMatch = existingRules.length; + existingRulesReversed.forEach(([index, rule]) => { + const indexOf = cssTexts.indexOf(rule); + if (indexOf === -1 || indexOf > lastMatch) { + try { + styleNode.sheet?.deleteRule(Number(index)); + } catch (e) { + /** + * accessing styleSheet rules may cause SecurityError + * for specific access control settings + */ + } + } + lastMatch = indexOf; + }); + cssTexts.forEach((cssText, index) => { + try { + if (styleNode.sheet?.cssRules[index]?.cssText !== cssText) { + styleNode.sheet?.insertRule(cssText, index); + } + } catch (e) { + /** + * sometimes we may capture rules with browser prefix + * insert rule with prefixs in other browsers may cause Error + */ + } + }); + } catch (e) { + /** + * accessing styleSheet rules may cause SecurityError + * for specific access control settings + */ + } } export function storeCSSRules( @@ -76,6 +111,9 @@ export function storeCSSRules( }, ]); } catch (e) { - // we were not allowed to access stylesheet cssRules, probably due to CORS + /** + * accessing styleSheet rules may cause SecurityError + * for specific access control settings + */ } } From 13c4bf4894f5efa0eeaf5771419cc1ced8127af1 Mon Sep 17 00:00:00 2001 From: Justin Halsall Date: Tue, 6 Jul 2021 14:47:55 +0200 Subject: [PATCH 18/18] clean up tests --- test/replay/virtual-styles.test.ts | 10 ++-------- 1 file changed, 2 insertions(+), 8 deletions(-) diff --git a/test/replay/virtual-styles.test.ts b/test/replay/virtual-styles.test.ts index bbc44303dc..ef2524033e 100644 --- a/test/replay/virtual-styles.test.ts +++ b/test/replay/virtual-styles.test.ts @@ -1,6 +1,4 @@ import { expect } from 'chai'; -import { INode } from 'rrweb-snapshot'; -import { Replayer } from '../../src/replay'; import { JSDOM } from 'jsdom'; import { applyVirtualStyleRulesToNode, @@ -16,7 +14,7 @@ describe('virtual styles', () => { `); const styleEl = dom.window.document.getElementsByTagName('style')[0]; - const cssText = '.x {border: 1px solid yellow;}'; + const cssText = '.added-rule {border: 1px solid yellow;}'; const virtualStyleRules: VirtualStyleRules = [ { cssText, index: 0, type: StyleRuleType.Insert }, @@ -36,7 +34,7 @@ describe('virtual styles', () => { `); const styleEl = dom.window.document.getElementsByTagName('style')[0]; - const cssText = '.x {border: 1px solid yellow;}'; + const cssText = '.added-rule {border: 1px solid yellow;}'; const virtualStyleRules: VirtualStyleRules = [ { cssText, index: 0, type: StyleRuleType.Insert }, ]; @@ -106,10 +104,6 @@ describe('virtual styles', () => { ]; applyVirtualStyleRulesToNode(virtualStyleRules, styleEl); - console.log( - 'y', - Array.from(styleEl.sheet?.cssRules || []).map((rule) => rule.cssText), - ); expect(styleEl.sheet?.cssRules?.length).to.equal(2); expect( Array.from(styleEl.sheet?.cssRules || []).map((rule) => rule.cssText),