UNPKG

@stylable/core

Version:

CSS for Components

209 lines 8.11 kB
"use strict"; 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