Use css parser to add hover class name to selectors.

Previously we use a regexp to match all the CSS selectors and add
our hover class name to it, which has been proved not solid and
may be very slow in some situation.
Using a production ready css parser can handle this better and also
provide ability's to do more accurate things to the recorded
stylesheets.
This commit is contained in:
Yanzhen Yu
2019-08-04 14:35:35 +08:00
parent 0865c82948
commit 61a99c642a
5 changed files with 1054 additions and 10 deletions

View File

@@ -1,3 +1,4 @@
import { parse } from './css';
import {
serializedNodeWithId,
NodeType,
@@ -55,20 +56,23 @@ function getTagName(n: elementNode): string {
return tagName;
}
const CSS_SELECTOR = /([^\r\n,{}]+)(,(?=[^}]*{)|\s*{)/g;
const HOVER_SELECTOR = /([^\\]):hover/g;
export function addHoverClass(cssText: string): string {
return cssText.replace(CSS_SELECTOR, (match, p1: string, p2: string) => {
if (HOVER_SELECTOR.test(p1)) {
const newSelector = p1.replace(HOVER_SELECTOR, '$1.\\:hover');
return `${p1.replace(/\s*$/, '')}, ${newSelector.replace(
/^\s*/,
'',
)}${p2}`;
} else {
return match;
const ast = parse(cssText);
if (!ast.stylesheet) {
return cssText;
}
ast.stylesheet.rules.forEach(rule => {
if ('selectors' in rule) {
(rule.selectors || []).forEach((selector: string) => {
if (HOVER_SELECTOR.test(selector)) {
const newSelector = selector.replace(HOVER_SELECTOR, '$1.\\:hover');
cssText = cssText.replace(selector, `${selector}, ${newSelector}`);
}
});
}
});
return cssText;
}
function buildNode(n: serializedNodeWithId, doc: Document): Node | null {