@stylable/core
Version:
CSS for Components
209 lines • 8.11 kB
JavaScript
;
var __importDefault = (this && this.__importDefault) || function (mod) {
return (mod && mod.__esModule) ? mod : { "default": mod };
};
Object.defineProperty(exports, "__esModule", { value: true });
exports.scopeNestedSelector = exports.isCompRoot = exports.matchTypeAndValue = exports.isInPseudoClassContext = exports.createCombinatorSelector = exports.convertToPseudoClass = exports.convertToSelector = exports.convertToInvalid = exports.convertToAttribute = exports.convertToClass = exports.flattenFunctionalSelector = exports.isSimpleSelector = exports.cloneSelector = exports.parseSelectorWithCache = exports.walkSelector = exports.stringifySelector = exports.parseSelector = void 0;
const css_selector_parser_1 = require("@tokey/css-selector-parser");
const lodash_clonedeep_1 = __importDefault(require("lodash.clonedeep"));
exports.parseSelector = css_selector_parser_1.parseCssSelector;
exports.stringifySelector = css_selector_parser_1.stringifySelectorAst;
exports.walkSelector = css_selector_parser_1.walk;
/**
* parse selectors and cache them
*/
const selectorAstCache = new Map();
function parseSelectorWithCache(selector, options = {}) {
if (!selectorAstCache.has(selector)) {
if (selectorAstCache.size > 10000) {
selectorAstCache.delete(selectorAstCache.keys().next().value);
}
selectorAstCache.set(selector, (0, css_selector_parser_1.parseCssSelector)(selector));
}
const cachedValue = selectorAstCache.get(selector);
return options.clone
? (0, lodash_clonedeep_1.default)(cachedValue)
: cachedValue;
}
exports.parseSelectorWithCache = parseSelectorWithCache;
function cloneSelector(s) {
return (0, lodash_clonedeep_1.default)(s);
}
exports.cloneSelector = cloneSelector;
/**
* returns for each selector if it contains only
* a single class or an element selector.
*/
function isSimpleSelector(selector) {
const selectorList = parseSelectorWithCache(selector);
return selectorList.map((selector) => {
let foundType = ``;
(0, css_selector_parser_1.walk)(selector, (node) => {
if ((node.type !== `class` && node.type !== `type`) || foundType || node.nodes) {
foundType = `complex`;
return css_selector_parser_1.walk.stopAll;
}
foundType = node.type;
return;
}, { ignoreList: [`selector`, `comment`] });
if (foundType === `class` || foundType === `type`) {
return { type: foundType, isSimple: true };
}
else {
return { type: `complex`, isSimple: false };
}
});
}
exports.isSimpleSelector = isSimpleSelector;
/**
* take an ast node with nested nodes "XXX(nest1, nest2)"
* and convert it to a flat selector as node: "nest1, nest2"
*/
function flattenFunctionalSelector(node) {
node.value = ``;
return convertToSelector(node);
}
exports.flattenFunctionalSelector = flattenFunctionalSelector;
/**
* ast convertors
*/
function convertToClass(node) {
const castedNode = node;
castedNode.type = `class`;
castedNode.dotComments = [];
return castedNode;
}
exports.convertToClass = convertToClass;
function convertToAttribute(node) {
const castedNode = node;
castedNode.type = `attribute`;
return castedNode;
}
exports.convertToAttribute = convertToAttribute;
function convertToInvalid(node) {
const castedNode = node;
castedNode.type = `invalid`;
return castedNode;
}
exports.convertToInvalid = convertToInvalid;
function convertToSelector(node) {
const castedNode = node;
castedNode.type = `selector`;
castedNode.before || (castedNode.before = ``);
castedNode.after || (castedNode.after = ``);
// ToDo: should this fix castedNode.end?
return castedNode;
}
exports.convertToSelector = convertToSelector;
function convertToPseudoClass(node, name, nestedSelectors) {
const castedNode = node;
castedNode.type = 'pseudo_class';
castedNode.value = name;
castedNode.colonComments = [];
if (nestedSelectors) {
castedNode.nodes = nestedSelectors;
}
else {
delete castedNode.nodes;
}
return castedNode;
}
exports.convertToPseudoClass = convertToPseudoClass;
function createCombinatorSelector(partial) {
const type = partial.combinator || 'space';
return {
type: `combinator`,
combinator: type,
value: partial.value ?? (type === 'space' ? ` ` : type),
before: partial.before ?? ``,
after: partial.after ?? ``,
start: partial.start ?? 0,
end: partial.end ?? 0,
invalid: partial.invalid ?? false,
};
}
exports.createCombinatorSelector = createCombinatorSelector;
function isInPseudoClassContext(parents) {
for (const parent of parents) {
if (parent.type === `pseudo_class`) {
return true;
}
}
return false;
}
exports.isInPseudoClassContext = isInPseudoClassContext;
function matchTypeAndValue(a, b) {
return a.type === b.type && a.value === b.value;
}
exports.matchTypeAndValue = matchTypeAndValue;
function isCompRoot(name) {
return name.charAt(0).match(/[A-Z]/);
}
exports.isCompRoot = isCompRoot;
const isNestedNode = (node) => node.type === 'nesting';
/**
* combine 2 selector lists.
* - add each scoping selector at the begging of each nested selector
* - replace any nesting `&` nodes in the nested selector with the scoping selector nodes
*/
function scopeNestedSelector(scopeSelectorAst, nestedSelectorAst, rootScopeLevel = false, isAnchor = isNestedNode) {
const resultSelectors = [];
nestedSelectorAst.forEach((targetAst) => {
scopeSelectorAst.forEach((scopeAst) => {
const outputAst = (0, lodash_clonedeep_1.default)(targetAst);
outputAst.before = scopeAst.before || outputAst.before;
let first = outputAst.nodes[0];
// search first actual first selector part
(0, exports.walkSelector)(outputAst, (node) => {
first = node;
return exports.walkSelector.stopAll;
}, { ignoreList: [`selector`] });
// merge scope flags
const nestStartWithNesting = first.type === `nesting`;
const nestedStartWithGlobal = rootScopeLevel && first.type === `pseudo_class` && first.value === `global`;
const nestStartWithScope = rootScopeLevel &&
scopeAst.nodes.every((node, i) => {
return matchTypeAndValue(node, outputAst.nodes[i]);
});
let scopeAlreadyMerged = false;
// merge scope into selector
(0, exports.walkSelector)(outputAst, (node, i, nodes) => {
if (isAnchor(node)) {
scopeAlreadyMerged = true;
nodes.splice(i, 1, {
type: `selector`,
nodes: (0, lodash_clonedeep_1.default)(scopeAst.nodes),
start: node.start,
end: node.end,
after: ``,
before: ``,
});
}
});
// merge scope at the beginning of selector
if (first &&
!nestStartWithNesting &&
!nestStartWithScope &&
!nestedStartWithGlobal &&
!scopeAlreadyMerged) {
outputAst.nodes.unshift(...(0, lodash_clonedeep_1.default)(scopeAst.nodes), {
type: `combinator`,
combinator: `space`,
value: ` `,
before: ``,
after: ``,
start: first.start,
end: first.start,
invalid: false,
});
}
resultSelectors.push(outputAst);
});
});
return {
selector: (0, exports.stringifySelector)(resultSelectors),
ast: resultSelectors,
};
}
exports.scopeNestedSelector = scopeNestedSelector;
//# sourceMappingURL=selector.js.map