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';
|
import * as css from './cssTokenizer';
|
||||||
|
|
||||||
type ClauseCombinator = '' | '>' | '+' | '~';
|
// Note: '>=' is used internally for text engine to preserve backwards compatibility.
|
||||||
|
type ClauseCombinator = '' | '>' | '+' | '~' | '>=';
|
||||||
// TODO: consider
|
// TODO: consider
|
||||||
// - key=value
|
// - key=value
|
||||||
// - operators like `=`, `|=`, `~=`, `*=`, `/`
|
// - operators like `=`, `|=`, `~=`, `*=`, `/`
|
||||||
|
|
|
||||||
|
|
@ -55,7 +55,7 @@ export function parseSelector(selector: string, customNames: Set<string>): Parse
|
||||||
}
|
}
|
||||||
|
|
||||||
const chain = (from: number, to: number): CSSComplexSelector => {
|
const chain = (from: number, to: number): CSSComplexSelector => {
|
||||||
let result: CSSComplexSelector = { simples: [] };
|
const result: CSSComplexSelector = { simples: [] };
|
||||||
for (const part of v1.parts.slice(from, to)) {
|
for (const part of v1.parts.slice(from, to)) {
|
||||||
let name = part.name;
|
let name = part.name;
|
||||||
let wrapInLight = false;
|
let wrapInLight = false;
|
||||||
|
|
@ -70,24 +70,14 @@ export function parseSelector(selector: string, customNames: Set<string>): Parse
|
||||||
simple = callWith('is', parsed.selector);
|
simple = callWith('is', parsed.selector);
|
||||||
} else if (name === 'text') {
|
} else if (name === 'text') {
|
||||||
simple = textSelectorToSimple(part.body);
|
simple = textSelectorToSimple(part.body);
|
||||||
|
if (result.simples.length)
|
||||||
|
result.simples[result.simples.length - 1].combinator = '>=';
|
||||||
} else {
|
} else {
|
||||||
simple = callWith(name, [part.body]);
|
simple = callWith(name, [part.body]);
|
||||||
}
|
}
|
||||||
if (wrapInLight)
|
if (wrapInLight)
|
||||||
simple = callWith('light', [simpleToComplex(simple)]);
|
simple = callWith('light', [simpleToComplex(simple)]);
|
||||||
if (name === 'text') {
|
result.simples.push({ selector: simple, combinator: '' });
|
||||||
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: '' });
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
return result;
|
return result;
|
||||||
};
|
};
|
||||||
|
|
@ -110,10 +100,6 @@ function simpleToComplex(simple: CSSSimpleSelector): CSSComplexSelector {
|
||||||
return { simples: [{ selector: simple, combinator: '' }]};
|
return { simples: [{ selector: simple, combinator: '' }]};
|
||||||
}
|
}
|
||||||
|
|
||||||
function copySimple(simple: CSSSimpleSelector): CSSSimpleSelector {
|
|
||||||
return { css: simple.css, functions: simple.functions.slice() };
|
|
||||||
}
|
|
||||||
|
|
||||||
function textSelectorToSimple(selector: string): CSSSimpleSelector {
|
function textSelectorToSimple(selector: string): CSSSimpleSelector {
|
||||||
function unescape(s: string): string {
|
function unescape(s: string): string {
|
||||||
if (!s.includes('\\'))
|
if (!s.includes('\\'))
|
||||||
|
|
|
||||||
|
|
@ -214,6 +214,19 @@ export class SelectorEvaluatorImpl implements SelectorEvaluator {
|
||||||
}
|
}
|
||||||
return false;
|
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}"`);
|
throw new Error(`Unsupported combinator "${combinator}"`);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue