feat(selectors): optimize old->new selectors conversion for text (#4671)
This commit is contained in:
parent
c8e9b0542b
commit
12dc04a304
|
|
@ -16,7 +16,8 @@
|
|||
|
||||
import * as css from './cssTokenizer';
|
||||
|
||||
type ClauseCombinator = '' | '>' | '+' | '~';
|
||||
// Note: '>=' is used internally for text engine to preserve backwards compatibility.
|
||||
type ClauseCombinator = '' | '>' | '+' | '~' | '>=';
|
||||
// TODO: consider
|
||||
// - key=value
|
||||
// - operators like `=`, `|=`, `~=`, `*=`, `/`
|
||||
|
|
|
|||
|
|
@ -55,7 +55,7 @@ export function parseSelector(selector: string, customNames: Set<string>): Parse
|
|||
}
|
||||
|
||||
const chain = (from: number, to: number): CSSComplexSelector => {
|
||||
let result: CSSComplexSelector = { simples: [] };
|
||||
const result: CSSComplexSelector = { simples: [] };
|
||||
for (const part of v1.parts.slice(from, to)) {
|
||||
let name = part.name;
|
||||
let wrapInLight = false;
|
||||
|
|
@ -70,24 +70,14 @@ export function parseSelector(selector: string, customNames: Set<string>): Parse
|
|||
simple = callWith('is', parsed.selector);
|
||||
} else if (name === 'text') {
|
||||
simple = textSelectorToSimple(part.body);
|
||||
if (result.simples.length)
|
||||
result.simples[result.simples.length - 1].combinator = '>=';
|
||||
} else {
|
||||
simple = callWith(name, [part.body]);
|
||||
}
|
||||
if (wrapInLight)
|
||||
simple = callWith('light', [simpleToComplex(simple)]);
|
||||
if (name === 'text') {
|
||||
const copy = result.simples.map(one => {
|
||||
return { selector: copySimple(one.selector), combinator: one.combinator };
|
||||
});
|
||||
copy.push({ selector: simple, combinator: '' });
|
||||
if (!result.simples.length)
|
||||
result.simples.push({ selector: callWith('scope', []), combinator: '' });
|
||||
const last = result.simples[result.simples.length - 1];
|
||||
last.selector.functions.push({ name: 'is', args: [simpleToComplex(simple)] });
|
||||
result = simpleToComplex(callWith('is', [{ simples: copy }, result]));
|
||||
} else {
|
||||
result.simples.push({ selector: simple, combinator: '' });
|
||||
}
|
||||
result.simples.push({ selector: simple, combinator: '' });
|
||||
}
|
||||
return result;
|
||||
};
|
||||
|
|
@ -110,10 +100,6 @@ function simpleToComplex(simple: CSSSimpleSelector): CSSComplexSelector {
|
|||
return { simples: [{ selector: simple, combinator: '' }]};
|
||||
}
|
||||
|
||||
function copySimple(simple: CSSSimpleSelector): CSSSimpleSelector {
|
||||
return { css: simple.css, functions: simple.functions.slice() };
|
||||
}
|
||||
|
||||
function textSelectorToSimple(selector: string): CSSSimpleSelector {
|
||||
function unescape(s: string): string {
|
||||
if (!s.includes('\\'))
|
||||
|
|
|
|||
|
|
@ -214,6 +214,19 @@ export class SelectorEvaluatorImpl implements SelectorEvaluator {
|
|||
}
|
||||
return false;
|
||||
}
|
||||
if (combinator === '>=') {
|
||||
let parent: Element | undefined = element;
|
||||
while (parent) {
|
||||
if (this._matchesSimple(parent, simple, context)) {
|
||||
if (this._matchesParents(parent, complex, index - 1, context))
|
||||
return true;
|
||||
if (complex.simples[index - 1].combinator === '')
|
||||
break;
|
||||
}
|
||||
parent = parentElementOrShadowHostInContext(parent, context);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
throw new Error(`Unsupported combinator "${combinator}"`);
|
||||
});
|
||||
}
|
||||
|
|
|
|||
Loading…
Reference in a new issue