Skip to content

Commit 12dc04a

Browse files
authored
feat(selectors): optimize old->new selectors conversion for text (#4671)
1 parent c8e9b05 commit 12dc04a

File tree

3 files changed

+19
-19
lines changed

3 files changed

+19
-19
lines changed

src/server/common/cssParser.ts

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,8 @@
1616

1717
import * as css from './cssTokenizer';
1818

19-
type ClauseCombinator = '' | '>' | '+' | '~';
19+
// Note: '>=' is used internally for text engine to preserve backwards compatibility.
20+
type ClauseCombinator = '' | '>' | '+' | '~' | '>=';
2021
// TODO: consider
2122
// - key=value
2223
// - operators like `=`, `|=`, `~=`, `*=`, `/`

src/server/common/selectorParser.ts

Lines changed: 4 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -55,7 +55,7 @@ export function parseSelector(selector: string, customNames: Set<string>): Parse
5555
}
5656

5757
const chain = (from: number, to: number): CSSComplexSelector => {
58-
let result: CSSComplexSelector = { simples: [] };
58+
const result: CSSComplexSelector = { simples: [] };
5959
for (const part of v1.parts.slice(from, to)) {
6060
let name = part.name;
6161
let wrapInLight = false;
@@ -70,24 +70,14 @@ export function parseSelector(selector: string, customNames: Set<string>): Parse
7070
simple = callWith('is', parsed.selector);
7171
} else if (name === 'text') {
7272
simple = textSelectorToSimple(part.body);
73+
if (result.simples.length)
74+
result.simples[result.simples.length - 1].combinator = '>=';
7375
} else {
7476
simple = callWith(name, [part.body]);
7577
}
7678
if (wrapInLight)
7779
simple = callWith('light', [simpleToComplex(simple)]);
78-
if (name === 'text') {
79-
const copy = result.simples.map(one => {
80-
return { selector: copySimple(one.selector), combinator: one.combinator };
81-
});
82-
copy.push({ selector: simple, combinator: '' });
83-
if (!result.simples.length)
84-
result.simples.push({ selector: callWith('scope', []), combinator: '' });
85-
const last = result.simples[result.simples.length - 1];
86-
last.selector.functions.push({ name: 'is', args: [simpleToComplex(simple)] });
87-
result = simpleToComplex(callWith('is', [{ simples: copy }, result]));
88-
} else {
89-
result.simples.push({ selector: simple, combinator: '' });
90-
}
80+
result.simples.push({ selector: simple, combinator: '' });
9181
}
9282
return result;
9383
};
@@ -110,10 +100,6 @@ function simpleToComplex(simple: CSSSimpleSelector): CSSComplexSelector {
110100
return { simples: [{ selector: simple, combinator: '' }]};
111101
}
112102

113-
function copySimple(simple: CSSSimpleSelector): CSSSimpleSelector {
114-
return { css: simple.css, functions: simple.functions.slice() };
115-
}
116-
117103
function textSelectorToSimple(selector: string): CSSSimpleSelector {
118104
function unescape(s: string): string {
119105
if (!s.includes('\\'))

src/server/injected/selectorEvaluator.ts

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -214,6 +214,19 @@ export class SelectorEvaluatorImpl implements SelectorEvaluator {
214214
}
215215
return false;
216216
}
217+
if (combinator === '>=') {
218+
let parent: Element | undefined = element;
219+
while (parent) {
220+
if (this._matchesSimple(parent, simple, context)) {
221+
if (this._matchesParents(parent, complex, index - 1, context))
222+
return true;
223+
if (complex.simples[index - 1].combinator === '')
224+
break;
225+
}
226+
parent = parentElementOrShadowHostInContext(parent, context);
227+
}
228+
return false;
229+
}
217230
throw new Error(`Unsupported combinator "${combinator}"`);
218231
});
219232
}

0 commit comments

Comments
 (0)