diff --git a/packages/rrweb-snapshot/src/snapshot.ts b/packages/rrweb-snapshot/src/snapshot.ts index 51e764ce..02619296 100644 --- a/packages/rrweb-snapshot/src/snapshot.ts +++ b/packages/rrweb-snapshot/src/snapshot.ts @@ -22,7 +22,6 @@ import { stringifyStylesheet, getInputType, toLowerCase, - validateStringifiedCssRule, } from './utils'; let _id = 1; diff --git a/packages/rrweb-snapshot/src/utils.ts b/packages/rrweb-snapshot/src/utils.ts index 2b432459..02043995 100644 --- a/packages/rrweb-snapshot/src/utils.ts +++ b/packages/rrweb-snapshot/src/utils.ts @@ -119,26 +119,29 @@ export function stringifyRule(rule: CSSRule): string { } catch (error) { // ignore } + } else if (isCSSStyleRule(rule) && rule.selectorText.includes(':')) { + // Safari does not escape selectors with : properly + // see https://bugs.webkit.org/show_bug.cgi?id=184604 + return fixSafariColons(rule.cssText); } - return validateStringifiedCssRule(importStringified || rule.cssText); + return importStringified || rule.cssText; } -export function validateStringifiedCssRule(cssStringified: string): string { - // Safari does not escape selectors with : properly - if (cssStringified.includes(':')) { - // Replace e.g. [aa:bb] with [aa\\:bb] - const regex = /(\[(?:[\w-]+)[^\\])(:(?:[\w-]+)\])/gm; - return cssStringified.replace(regex, '$1\\$2'); - } - - return cssStringified; +export function fixSafariColons(cssStringified: string): string { + // Replace e.g. [aa:bb] with [aa\\:bb] + const regex = /(\[(?:[\w-]+)[^\\])(:(?:[\w-]+)\])/gm; + return cssStringified.replace(regex, '$1\\$2'); } export function isCSSImportRule(rule: CSSRule): rule is CSSImportRule { return 'styleSheet' in rule; } +export function isCSSStyleRule(rule: CSSRule): rule is CSSStyleRule { + return 'selectorText' in rule; +} + export class Mirror implements IMirror { private idNodeMap: idNodeMap = new Map(); private nodeMetaMap: nodeMetaMap = new WeakMap(); diff --git a/packages/rrweb-snapshot/test/css.test.ts b/packages/rrweb-snapshot/test/css.test.ts index 6599839d..28183860 100644 --- a/packages/rrweb-snapshot/test/css.test.ts +++ b/packages/rrweb-snapshot/test/css.test.ts @@ -1,8 +1,5 @@ import { parse, Rule, Media } from '../src/css'; -import { - validateStringifiedCssRule, - escapeImportStatement, -} from './../src/utils'; +import { fixSafariColons, escapeImportStatement } from './../src/utils'; describe('css parser', () => { it('should save the filename and source', () => { @@ -112,15 +109,13 @@ describe('css parser', () => { }); it('parses : in attribute selectors correctly', () => { - const out1 = validateStringifiedCssRule('[data-foo] { color: red; }'); + const out1 = fixSafariColons('[data-foo] { color: red; }'); expect(out1).toEqual('[data-foo] { color: red; }'); - const out2 = validateStringifiedCssRule('[data-foo:other] { color: red; }'); + const out2 = fixSafariColons('[data-foo:other] { color: red; }'); expect(out2).toEqual('[data-foo\\:other] { color: red; }'); - const out3 = validateStringifiedCssRule( - '[data-aa\\:other] { color: red; }', - ); + const out3 = fixSafariColons('[data-aa\\:other] { color: red; }'); expect(out3).toEqual('[data-aa\\:other] { color: red; }'); }); diff --git a/yarn.lock b/yarn.lock index 784f857d..34c29fb6 100644 --- a/yarn.lock +++ b/yarn.lock @@ -5522,15 +5522,10 @@ csso@^4.0.2: dependencies: css-tree "^1.1.2" -cssom@^0.4.4, "cssom@https://registry.npmjs.org/rrweb-cssom/-/rrweb-cssom-0.6.0.tgz": +cssom@^0.4.4, cssom@^0.5.0, "cssom@https://registry.npmjs.org/rrweb-cssom/-/rrweb-cssom-0.6.0.tgz": version "0.6.0" resolved "https://registry.npmjs.org/rrweb-cssom/-/rrweb-cssom-0.6.0.tgz#ed298055b97cbddcdeb278f904857629dec5e0e1" -cssom@^0.5.0: - version "0.5.0" - resolved "https://registry.yarnpkg.com/cssom/-/cssom-0.5.0.tgz#d254fa92cd8b6fbd83811b9fbaed34663cc17c36" - integrity sha512-iKuQcq+NdHqlAcwUY0o/HL69XQrUaQdMjmStJ8JFmUaiiQErlhrmuigkg/CU4E2J0IyUKUrMAgl36TvN67MqTw== - cssom@~0.3.6: version "0.3.8" resolved "https://registry.yarnpkg.com/cssom/-/cssom-0.3.8.tgz#9f1276f5b2b463f2114d3f2c75250af8c1a36f4a"