@nativescript/core
Version:
A JavaScript library providing an easy to use api for interacting with iOS and Android platform APIs.
934 lines • 33 kB
JavaScript
import { parse as convertToCSSWhatSelector } from 'css-what';
import '../../globals';
import { isCssVariable } from '../core/properties';
import { isNullOrUndefined } from '../../utils/types';
import { checkIfMediaQueryMatches } from '../../media-query-list';
export const MEDIA_QUERY_SEPARATOR = '&&';
var Combinator;
(function (Combinator) {
Combinator["descendant"] = " ";
Combinator["child"] = ">";
Combinator["adjacent"] = "+";
Combinator["sibling"] = "~";
// Not supported
Combinator["parent"] = "<";
Combinator["column-combinator"] = "||";
})(Combinator || (Combinator = {}));
var AttributeSelectorOperator;
(function (AttributeSelectorOperator) {
AttributeSelectorOperator["exists"] = "";
AttributeSelectorOperator["equals"] = "=";
AttributeSelectorOperator["start"] = "^=";
AttributeSelectorOperator["end"] = "$=";
AttributeSelectorOperator["any"] = "*=";
AttributeSelectorOperator["element"] = "~=";
AttributeSelectorOperator["hyphen"] = "|=";
})(AttributeSelectorOperator || (AttributeSelectorOperator = {}));
var Match;
(function (Match) {
/**
* Depends on attributes or pseudoclasses state;
*/
Match.Dynamic = true;
/**
* Depends only on the tree structure.
*/
Match.Static = false;
})(Match || (Match = {}));
function eachNodePreviousGeneralSibling(node, callback) {
if (!node.parent || !node.parent.getChildIndex || !node.parent.getChildAt || !node.parent.getChildrenCount) {
return;
}
const nodeIndex = node.parent.getChildIndex(node);
if (nodeIndex === 0) {
return;
}
const count = node.parent.getChildrenCount();
let retVal = true;
for (let i = nodeIndex - 1; i >= 0 && retVal; i--) {
const sibling = node.parent.getChildAt(i);
retVal = callback(sibling);
}
}
function getNodePreviousDirectSibling(node) {
if (!node.parent || !node.parent.getChildIndex || !node.parent.getChildAt) {
return null;
}
const nodeIndex = node.parent.getChildIndex(node);
if (nodeIndex === 0) {
return null;
}
return node.parent.getChildAt(nodeIndex - 1);
}
function SelectorProperties(specificity, rarity, dynamic = false) {
return (cls) => {
cls.prototype.specificity = specificity;
cls.prototype.rarity = rarity;
cls.prototype.combinator = undefined;
cls.prototype.dynamic = dynamic;
return cls;
};
}
function FunctionalPseudoClassProperties(specificity, rarity, pseudoSelectorListType) {
return (cls) => {
cls.prototype.specificity = specificity;
cls.prototype.rarity = rarity;
cls.prototype.combinator = undefined;
cls.prototype.dynamic = false;
cls.prototype.pseudoSelectorListType = pseudoSelectorListType;
return cls;
};
}
export class SelectorBase {
}
let SelectorCore = class SelectorCore extends SelectorBase {
lookupSort(sorter, base) {
sorter.sortAsUniversal(base || this);
}
};
SelectorCore = __decorate([
SelectorProperties(0 /* Specificity.Universal */, 0 /* Rarity.Universal */, Match.Static)
], SelectorCore);
export { SelectorCore };
export class SimpleSelector extends SelectorCore {
accumulateChanges(node, map) {
if (!this.dynamic) {
return this.match(node);
}
else if (this.mayMatch(node)) {
this.trackChanges(node, map);
return true;
}
return false;
}
mayMatch(node) {
return this.match(node);
}
trackChanges(node, map) {
// No-op, silence the tslint 'block is empty'.
// Some derived classes (dynamic) will actually fill the map with stuff here, some (static) won't do anything.
}
}
function wrap(text) {
return text ? ` ${text} ` : '';
}
let InvalidSelector = class InvalidSelector extends SimpleSelector {
constructor(e) {
super();
this.e = e;
}
toString() {
return `<${this.e}>`;
}
match(node) {
return false;
}
lookupSort(sorter, base) {
// No-op, silence the tslint 'block is empty'.
// It feels like tslint has problems with simple polymorphism...
// This selector is invalid and will never match so we won't bother sorting it to further appear in queries.
}
};
InvalidSelector = __decorate([
SelectorProperties(0 /* Specificity.Invalid */, 4 /* Rarity.Invalid */, Match.Static),
__metadata("design:paramtypes", [Error])
], InvalidSelector);
export { InvalidSelector };
let UniversalSelector = class UniversalSelector extends SimpleSelector {
toString() {
return `*${wrap(this.combinator)}`;
}
match(node) {
return true;
}
};
UniversalSelector = __decorate([
SelectorProperties(0 /* Specificity.Universal */, 0 /* Rarity.Universal */, Match.Static)
], UniversalSelector);
export { UniversalSelector };
let IdSelector = class IdSelector extends SimpleSelector {
constructor(id) {
super();
this.id = id;
}
toString() {
return `#${this.id}${wrap(this.combinator)}`;
}
match(node) {
return node.id === this.id;
}
lookupSort(sorter, base) {
sorter.sortById(this.id, base || this);
}
};
IdSelector = __decorate([
SelectorProperties(100 /* Specificity.Id */, 3 /* Rarity.Id */, Match.Static),
__metadata("design:paramtypes", [String])
], IdSelector);
export { IdSelector };
let TypeSelector = class TypeSelector extends SimpleSelector {
constructor(cssType) {
super();
this.cssType = cssType;
}
toString() {
return `${this.cssType}${wrap(this.combinator)}`;
}
match(node) {
return node.cssType === this.cssType;
}
lookupSort(sorter, base) {
sorter.sortByType(this.cssType, base || this);
}
};
TypeSelector = __decorate([
SelectorProperties(1 /* Specificity.Type */, 1 /* Rarity.Type */, Match.Static),
__metadata("design:paramtypes", [String])
], TypeSelector);
export { TypeSelector };
let ClassSelector = class ClassSelector extends SimpleSelector {
constructor(cssClass) {
super();
this.cssClass = cssClass;
}
toString() {
return `.${this.cssClass}${wrap(this.combinator)}`;
}
match(node) {
return node.cssClasses && node.cssClasses.has(this.cssClass);
}
lookupSort(sorter, base) {
sorter.sortByClass(this.cssClass, base || this);
}
};
ClassSelector = __decorate([
SelectorProperties(10 /* Specificity.Class */, 2 /* Rarity.Class */, Match.Static),
__metadata("design:paramtypes", [String])
], ClassSelector);
export { ClassSelector };
let AttributeSelector = class AttributeSelector extends SimpleSelector {
constructor(attribute, test, value, ignoreCase) {
super();
this.attribute = attribute;
this.test = test;
this.value = value;
this.ignoreCase = ignoreCase;
}
toString() {
return `[${this.attribute}${wrap(AttributeSelectorOperator[this.test] ?? this.test)}${this.value || ''}]${wrap(this.combinator)}`;
}
match(node) {
let attr = node[this.attribute];
if (this.test === 'exists') {
return !isNullOrUndefined(attr);
}
if (!this.value) {
return false;
}
// Now, convert value to string
attr += '';
if (this.ignoreCase) {
attr = attr.toLowerCase();
this.value = this.value.toLowerCase();
}
// =
if (this.test === 'equals') {
return attr === this.value;
}
// ^=
if (this.test === 'start') {
return attr.startsWith(this.value);
}
// $=
if (this.test === 'end') {
return attr.endsWith(this.value);
}
// *=
if (this.test === 'any') {
return attr.indexOf(this.value) !== -1;
}
// ~=
if (this.test === 'element') {
const words = attr.split(' ');
return words && words.indexOf(this.value) !== -1;
}
// |=
if (this.test === 'hyphen') {
return attr === this.value || attr.startsWith(this.value + '-');
}
return false;
}
mayMatch(node) {
return true;
}
trackChanges(node, map) {
map.addAttribute(node, this.attribute);
}
};
AttributeSelector = __decorate([
SelectorProperties(10 /* Specificity.Attribute */, 0 /* Rarity.Attribute */, Match.Dynamic),
__metadata("design:paramtypes", [String, String, String, Boolean])
], AttributeSelector);
export { AttributeSelector };
let PseudoClassSelector = class PseudoClassSelector extends SimpleSelector {
constructor(cssPseudoClass) {
super();
this.cssPseudoClass = cssPseudoClass;
}
toString() {
return `:${this.cssPseudoClass}${wrap(this.combinator)}`;
}
match(node) {
return node.cssPseudoClasses && node.cssPseudoClasses.has(this.cssPseudoClass);
}
mayMatch(node) {
return true;
}
trackChanges(node, map) {
map.addPseudoClass(node, this.cssPseudoClass);
}
};
PseudoClassSelector = __decorate([
SelectorProperties(10 /* Specificity.PseudoClass */, 0 /* Rarity.PseudoClass */, Match.Dynamic),
__metadata("design:paramtypes", [String])
], PseudoClassSelector);
export { PseudoClassSelector };
export class FunctionalPseudoClassSelector extends PseudoClassSelector {
constructor(cssPseudoClass, dataType) {
super(cssPseudoClass);
const selectors = [];
const needsHighestSpecificity = this.specificity === -1 /* Specificity.SelectorListHighest */;
let specificity = 0;
if (Array.isArray(dataType)) {
for (const asts of dataType) {
const selector = createSelectorFromAst(asts);
if (selector instanceof InvalidSelector) {
// Only forgiving selector list can ignore invalid selectors
if (this.selectorListType !== 1 /* PseudoClassSelectorList.Forgiving */) {
selectors.splice(0);
specificity = 0;
break;
}
continue;
}
// The specificity of some pseudo-classes is replaced by the specificity of the most specific selector in its comma-separated argument of selectors
if (needsHighestSpecificity && selector.specificity > specificity) {
specificity = selector.specificity;
}
selectors.push(selector);
}
}
this.selectors = selectors;
this.specificity = specificity;
// Functional pseudo-classes become dynamic based on selectors in selector list
this.dynamic = this.selectors.some((sel) => sel.dynamic);
}
toString() {
return `:${this.cssPseudoClass}(${this.selectors.join(', ')})${wrap(this.combinator)}`;
}
match(node) {
return false;
}
mayMatch(node) {
return true;
}
trackChanges(node, map) {
this.selectors.forEach((sel) => sel.trackChanges(node, map));
}
}
let NotFunctionalPseudoClassSelector = class NotFunctionalPseudoClassSelector extends FunctionalPseudoClassSelector {
match(node) {
return !this.selectors.some((sel) => sel.match(node));
}
};
NotFunctionalPseudoClassSelector = __decorate([
FunctionalPseudoClassProperties(-1 /* Specificity.SelectorListHighest */, 0 /* Rarity.PseudoClass */, 0 /* PseudoClassSelectorList.Regular */)
], NotFunctionalPseudoClassSelector);
export { NotFunctionalPseudoClassSelector };
let IsFunctionalPseudoClassSelector = class IsFunctionalPseudoClassSelector extends FunctionalPseudoClassSelector {
match(node) {
return this.selectors.some((sel) => sel.match(node));
}
lookupSort(sorter, base) {
// A faster lookup can be performed when selector list contains just a single selector
if (this.selectors.length === 1) {
this.selectors[0].lookupSort(sorter, base || this);
}
else {
super.lookupSort(sorter, base || this);
}
}
};
IsFunctionalPseudoClassSelector = __decorate([
FunctionalPseudoClassProperties(-1 /* Specificity.SelectorListHighest */, 0 /* Rarity.PseudoClass */, 1 /* PseudoClassSelectorList.Forgiving */)
], IsFunctionalPseudoClassSelector);
export { IsFunctionalPseudoClassSelector };
let WhereFunctionalPseudoClassSelector = class WhereFunctionalPseudoClassSelector extends FunctionalPseudoClassSelector {
match(node) {
return this.selectors.some((sel) => sel.match(node));
}
lookupSort(sorter, base) {
// A faster lookup can be performed when selector list contains just a single selector
if (this.selectors.length === 1) {
this.selectors[0].lookupSort(sorter, base || this);
}
else {
super.lookupSort(sorter, base || this);
}
}
};
WhereFunctionalPseudoClassSelector = __decorate([
FunctionalPseudoClassProperties(0 /* Specificity.Zero */, 0 /* Rarity.PseudoClass */, 1 /* PseudoClassSelectorList.Forgiving */)
], WhereFunctionalPseudoClassSelector);
export { WhereFunctionalPseudoClassSelector };
export class SimpleSelectorSequence extends SimpleSelector {
constructor(selectors) {
super();
this.selectors = selectors;
this.specificity = selectors.reduce((sum, sel) => sel.specificity + sum, 0);
this.head = selectors.reduce((prev, curr) => (!prev || curr.rarity > prev.rarity ? curr : prev), null);
this.dynamic = selectors.some((sel) => sel.dynamic);
}
toString() {
return `${this.selectors.join('')}${wrap(this.combinator)}`;
}
match(node) {
return this.selectors.every((sel) => sel.match(node));
}
mayMatch(node) {
return this.selectors.every((sel) => sel.mayMatch(node));
}
trackChanges(node, map) {
this.selectors.forEach((sel) => sel.trackChanges(node, map));
}
lookupSort(sorter, base) {
this.head.lookupSort(sorter, base || this);
}
}
export class ComplexSelector extends SelectorCore {
constructor(selectors) {
super();
this.selectors = selectors;
let siblingsToGroup;
let currentGroup;
const groups = [];
this.specificity = 0;
this.dynamic = false;
for (let i = selectors.length - 1; i >= 0; i--) {
const sel = selectors[i];
switch (sel.combinator) {
case undefined:
case Combinator.descendant:
siblingsToGroup = [];
currentGroup = [siblingsToGroup];
groups.push(currentGroup);
break;
case Combinator.child:
siblingsToGroup = [];
currentGroup.push(siblingsToGroup);
break;
case Combinator.adjacent:
case Combinator.sibling:
break;
default:
throw new Error(`Unsupported combinator "${sel.combinator}" for selector ${sel}.`);
}
this.specificity += sel.specificity;
if (sel.dynamic) {
this.dynamic = true;
}
siblingsToGroup.push(sel);
}
this.groups = groups.map((g) => new Selector.ChildGroup(g.map((selectors) => (selectors.length > 1 ? new Selector.SiblingGroup(selectors) : selectors[0]))));
this.last = selectors[selectors.length - 1];
}
toString() {
return this.selectors.join('');
}
match(node) {
return this.groups.every((group, i) => {
if (i === 0) {
node = group.getMatchingNode(node, true);
return !!node;
}
else {
let ancestor = node;
while ((ancestor = ancestor.parent ?? ancestor._modalParent)) {
if ((node = group.getMatchingNode(ancestor, true))) {
return true;
}
}
return false;
}
});
}
mayMatch(node) {
return false;
}
trackChanges(node, map) {
this.selectors.forEach((sel) => sel.trackChanges(node, map));
}
lookupSort(sorter, base) {
this.last.lookupSort(sorter, base || this);
}
accumulateChanges(node, map) {
if (!this.dynamic) {
return this.match(node);
}
const bounds = [];
const mayMatch = this.groups.every((group, i) => {
if (i === 0) {
const nextNode = group.getMatchingNode(node, false);
bounds.push({ left: node, right: node });
node = nextNode;
return !!node;
}
else {
let ancestor = node;
while ((ancestor = ancestor.parent)) {
const nextNode = group.getMatchingNode(ancestor, false);
if (nextNode) {
bounds.push({ left: ancestor, right: null });
node = nextNode;
return true;
}
}
return false;
}
});
// Calculating the right bounds for each selectors won't save much
if (!mayMatch) {
return false;
}
if (!map) {
return mayMatch;
}
for (let i = 0; i < this.groups.length; i++) {
const group = this.groups[i];
if (!group.dynamic) {
continue;
}
const bound = bounds[i];
let node = bound.left;
do {
if (group.mayMatch(node)) {
group.trackChanges(node, map);
}
} while (node !== bound.right && (node = node.parent));
}
return mayMatch;
}
}
export var Selector;
(function (Selector) {
// Non-spec. Selector sequences are grouped by ancestor then by child combinators for easier backtracking.
class ChildGroup extends SelectorBase {
constructor(selectors) {
super();
this.selectors = selectors;
this.dynamic = selectors.some((sel) => sel.dynamic);
}
getMatchingNode(node, strict) {
const funcName = strict ? 'match' : 'mayMatch';
return this.selectors.every((sel, i) => (node = i === 0 ? node : node.parent) && sel[funcName](node)) ? node : null;
}
match(node) {
return this.getMatchingNode(node, true) != null;
}
mayMatch(node) {
return this.getMatchingNode(node, false) != null;
}
trackChanges(node, map) {
this.selectors.forEach((sel, i) => {
if (i === 0) {
node && sel.trackChanges(node, map);
}
else {
node = node.parent;
if (node && sel.mayMatch(node)) {
sel.trackChanges(node, map);
}
}
});
}
}
Selector.ChildGroup = ChildGroup;
class SiblingGroup extends SelectorBase {
constructor(selectors) {
super();
this.selectors = selectors;
this.dynamic = selectors.some((sel) => sel.dynamic);
}
match(node) {
return this.selectors.every((sel, i) => {
if (i === 0) {
return node && sel.match(node);
}
if (sel.combinator === Combinator.adjacent) {
node = getNodePreviousDirectSibling(node);
return node && sel.match(node);
}
// Sibling combinator
let isMatching = false;
eachNodePreviousGeneralSibling(node, (sibling) => {
isMatching = sel.match(sibling);
return !isMatching;
});
return isMatching;
});
}
mayMatch(node) {
return this.selectors.every((sel, i) => {
if (i === 0) {
return node && sel.mayMatch(node);
}
if (sel.combinator === Combinator.adjacent) {
node = getNodePreviousDirectSibling(node);
return node && sel.mayMatch(node);
}
// Sibling combinator
let isMatching = false;
eachNodePreviousGeneralSibling(node, (sibling) => {
isMatching = sel.mayMatch(sibling);
return !isMatching;
});
return isMatching;
});
}
trackChanges(node, map) {
this.selectors.forEach((sel, i) => {
if (i === 0) {
if (node) {
sel.trackChanges(node, map);
}
}
else {
if (sel.combinator === Combinator.adjacent) {
node = getNodePreviousDirectSibling(node);
if (node && sel.mayMatch(node)) {
sel.trackChanges(node, map);
}
}
else {
// Sibling combinator
let matchingSibling;
eachNodePreviousGeneralSibling(node, (sibling) => {
const isMatching = sel.mayMatch(sibling);
if (isMatching) {
matchingSibling = sibling;
}
return !isMatching;
});
if (matchingSibling) {
sel.trackChanges(matchingSibling, map);
}
}
}
});
}
}
Selector.SiblingGroup = SiblingGroup;
})(Selector || (Selector = {}));
export class RuleSet {
constructor(selectors, declarations) {
this.selectors = selectors;
this.declarations = declarations;
this.selectors.forEach((sel) => (sel.ruleset = this));
}
toString() {
let desc = `${this.selectors.join(', ')} {${this.declarations.map((d, i) => `${i === 0 ? ' ' : ''}${d.property}: ${d.value}`).join('; ')} }`;
if (this.mediaQueryString) {
desc = ` ${this.mediaQueryString} { ${desc} }`;
}
return desc;
}
lookupSort(sorter) {
this.selectors.forEach((sel) => sel.lookupSort(sorter));
}
}
export function fromAstNode(astRule) {
const declarations = astRule.declarations.filter(isDeclaration).map(createDeclaration);
const selectors = astRule.selectors.map(createSelector);
return new RuleSet(selectors, declarations);
}
function createDeclaration(decl) {
return { property: isCssVariable(decl.property) ? decl.property : decl.property.toLowerCase(), value: decl.value };
}
function createSimpleSelectorFromAst(ast) {
if (ast.type === 'attribute') {
if (ast.name === 'class') {
return new ClassSelector(ast.value);
}
if (ast.name === 'id') {
return new IdSelector(ast.value);
}
return new AttributeSelector(ast.name, ast.action, ast.value, !!ast.ignoreCase);
}
if (ast.type === 'tag') {
return new TypeSelector(ast.name.replace('-', '').toLowerCase());
}
if (ast.type === 'pseudo') {
if (ast.name === 'is') {
return new IsFunctionalPseudoClassSelector(ast.name, ast.data);
}
if (ast.name === 'where') {
return new WhereFunctionalPseudoClassSelector(ast.name, ast.data);
}
if (ast.name === 'not') {
return new NotFunctionalPseudoClassSelector(ast.name, ast.data);
}
return new PseudoClassSelector(ast.name);
}
if (ast.type === 'universal') {
return new UniversalSelector();
}
return new InvalidSelector(new Error(ast.type));
}
function createSimpleSelectorSequenceFromAst(asts) {
if (asts.length === 0) {
return new InvalidSelector(new Error('Empty simple selector sequence.'));
}
if (asts.length === 1) {
return createSimpleSelectorFromAst(asts[0]);
}
const sequenceSelectors = [];
for (const ast of asts) {
const selector = createSimpleSelectorFromAst(ast);
if (selector instanceof InvalidSelector) {
return selector;
}
sequenceSelectors.push(selector);
}
return new SimpleSelectorSequence(sequenceSelectors);
}
function createSelectorFromAst(asts) {
let result;
if (asts.length === 0) {
return new InvalidSelector(new Error('Empty selector.'));
}
if (asts.length === 1) {
return createSimpleSelectorFromAst(asts[0]);
}
const simpleSelectorSequences = [];
let sequenceAsts = [];
let combinatorCount = 0;
for (const ast of asts) {
const combinator = Combinator[ast.type];
// Combinator means the end of a sequence
if (combinator != null) {
const selector = createSimpleSelectorSequenceFromAst(sequenceAsts);
if (selector instanceof InvalidSelector) {
return selector;
}
selector.combinator = combinator;
simpleSelectorSequences.push(selector);
combinatorCount++;
// Cleanup stored selectors for the new sequence to take place
sequenceAsts = [];
}
else {
sequenceAsts.push(ast);
}
}
if (combinatorCount > 0) {
// Create a sequence using the remaining selectors after the last combinator
if (sequenceAsts.length) {
const selector = createSimpleSelectorSequenceFromAst(sequenceAsts);
if (selector instanceof InvalidSelector) {
return selector;
}
simpleSelectorSequences.push(selector);
}
return new ComplexSelector(simpleSelectorSequences);
}
return createSimpleSelectorSequenceFromAst(sequenceAsts);
}
export function createSelector(sel) {
try {
const result = convertToCSSWhatSelector(sel);
if (!result?.length) {
return new InvalidSelector(new Error('Empty selector'));
}
return createSelectorFromAst(result[0]);
}
catch (e) {
return new InvalidSelector(e);
}
}
function isDeclaration(node) {
return node.type === 'declaration';
}
export function matchMediaQueryString(mediaQueryString, cachedQueries) {
// It can be a single or multiple queries in case of nested media queries
const mediaQueryStrings = mediaQueryString.split(MEDIA_QUERY_SEPARATOR);
return mediaQueryStrings.every((mq) => {
let isMatching;
// Query has already been validated
if (cachedQueries.includes(mq)) {
isMatching = true;
}
else {
isMatching = checkIfMediaQueryMatches(mq);
if (isMatching) {
cachedQueries.push(mq);
}
}
return isMatching;
});
}
export class SelectorScope {
constructor() {
this.id = {};
this.class = {};
this.type = {};
this.universal = [];
this.position = 0;
}
getSelectorCandidates(node) {
const { cssClasses, id, cssType } = node;
const selectorClasses = [this.universal, this.id[id], this.type[cssType]];
if (cssClasses && cssClasses.size) {
cssClasses.forEach((c) => selectorClasses.push(this.class[c]));
}
return selectorClasses.reduce((cur, next) => cur.concat(next || []), []);
}
sortById(id, sel) {
this.addToMap(this.id, id, sel);
}
sortByClass(cssClass, sel) {
this.addToMap(this.class, cssClass, sel);
}
sortByType(cssType, sel) {
this.addToMap(this.type, cssType, sel);
}
sortAsUniversal(sel) {
this.universal.push(this.makeDocSelector(sel));
}
addToMap(map, head, sel) {
if (!map[head]) {
map[head] = [];
}
map[head].push(this.makeDocSelector(sel));
}
makeDocSelector(sel) {
sel.pos = this.position++;
return sel;
}
}
export class MediaQuerySelectorScope extends SelectorScope {
constructor(mediaQueryString) {
super();
this._mediaQueryString = mediaQueryString;
}
get mediaQueryString() {
return this._mediaQueryString;
}
}
export class StyleSheetSelectorScope extends SelectorScope {
constructor(rulesets) {
super();
this.lookupRulesets(rulesets);
}
createMediaQuerySelectorScope(mediaQueryString) {
const selectorScope = new MediaQuerySelectorScope(mediaQueryString);
selectorScope.position = this.position;
if (this.mediaQuerySelectorScopes) {
this.mediaQuerySelectorScopes.push(selectorScope);
}
else {
this.mediaQuerySelectorScopes = [selectorScope];
}
return selectorScope;
}
lookupRulesets(rulesets) {
let lastMediaSelectorScope;
for (let i = 0, length = rulesets.length; i < length; i++) {
const ruleset = rulesets[i];
if (lastMediaSelectorScope && lastMediaSelectorScope.mediaQueryString !== ruleset.mediaQueryString) {
// Once done with current media query scope, update stylesheet scope position
this.position = lastMediaSelectorScope.position;
lastMediaSelectorScope = null;
}
if (ruleset.mediaQueryString) {
// Create media query selector scope and register selector lookups there
if (!lastMediaSelectorScope) {
lastMediaSelectorScope = this.createMediaQuerySelectorScope(ruleset.mediaQueryString);
}
ruleset.lookupSort(lastMediaSelectorScope);
}
else {
ruleset.lookupSort(this);
}
}
// If reference of last media selector scope is still kept, update stylesheet scope position
if (lastMediaSelectorScope) {
this.position = lastMediaSelectorScope.position;
lastMediaSelectorScope = null;
}
}
query(node) {
const selectorsMatch = new SelectorsMatch();
const selectors = this.getSelectorCandidates(node);
// Validate media queries and include their selectors if needed
if (this.mediaQuerySelectorScopes) {
// Cache media query results to avoid validations of other identical queries
const validatedMediaQueries = [];
for (let i = 0, length = this.mediaQuerySelectorScopes.length; i < length; i++) {
const selectorScope = this.mediaQuerySelectorScopes[i];
const isMatchingAllQueries = matchMediaQueryString(selectorScope.mediaQueryString, validatedMediaQueries);
if (isMatchingAllQueries) {
const mediaQuerySelectors = selectorScope.getSelectorCandidates(node);
selectors.push(...mediaQuerySelectors);
}
}
}
selectorsMatch.selectors = selectors.filter((sel) => sel.accumulateChanges(node, selectorsMatch)).sort((a, b) => a.specificity - b.specificity || a.pos - b.pos);
return selectorsMatch;
}
}
export class SelectorsMatch {
constructor() {
this.changeMap = new Map();
}
addAttribute(node, attribute) {
const deps = this.properties(node);
if (!deps.attributes) {
deps.attributes = new Set();
}
deps.attributes.add(attribute);
}
addPseudoClass(node, pseudoClass) {
const deps = this.properties(node);
if (!deps.pseudoClasses) {
deps.pseudoClasses = new Set();
}
deps.pseudoClasses.add(pseudoClass);
}
properties(node) {
let set = this.changeMap.get(node);
if (!set) {
this.changeMap.set(node, (set = {}));
}
return set;
}
}
export const CSSHelper = {
createSelector,
SelectorCore,
SimpleSelector,
InvalidSelector,
UniversalSelector,
TypeSelector,
ClassSelector,
AttributeSelector,
PseudoClassSelector,
SimpleSelectorSequence,
Selector,
RuleSet,
SelectorScope,
MediaQuerySelectorScope,
StyleSheetSelectorScope,
fromAstNode,
SelectorsMatch,
};
//# sourceMappingURL=css-selector.js.map