feat(selectors): optimize old->new selectors conversion for text (#4671)

This commit is contained in:
Dmitry Gozman 2020-12-10 13:53:19 -08:00 committed by GitHub
parent c8e9b0542b
commit 12dc04a304
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
3 changed files with 19 additions and 19 deletions

View file

@ -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 `=`, `|=`, `~=`, `*=`, `/`

View file

@ -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('\\'))

View file

@ -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}"`);
}); });
} }