flattenNestedSelectorsForRule.mjs 1.8 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667
  1. import resolveNestedSelector from 'postcss-resolve-nested-selector';
  2. import selectorParser from 'postcss-selector-parser';
  3. import getRuleSelector from './getRuleSelector.mjs';
  4. import isStandardSyntaxSelector from './isStandardSyntaxSelector.mjs';
  5. import parseSelector from './parseSelector.mjs';
  6. /** @import { Selector, Root } from 'postcss-selector-parser' */
  7. /** @import { Rule } from 'postcss' */
  8. /** @import { PostcssResult } from 'stylelint' */
  9. /**
  10. * Flatten the selectors of the current rule against it's parent rules and at-rules.
  11. *
  12. * The selectors for the current rule are assumed to be standard CSS selectors.
  13. *
  14. * @typedef {{selector: Selector, resolvedSelectors: Root, nested: boolean}} FlattenedSelector
  15. *
  16. * @param {Rule} rule
  17. * @param {PostcssResult} result
  18. * @returns {Array<FlattenedSelector>}
  19. */
  20. export default function flattenNestedSelectorsForRule(rule, result) {
  21. const ownAST = parseSelector(getRuleSelector(rule), result, rule);
  22. if (!ownAST) return [];
  23. /** @type {Array<FlattenedSelector>} */
  24. const flattenedSelectors = [];
  25. for (const selectorAST of ownAST.nodes) {
  26. const selector = selectorAST.toString();
  27. const resolvedSelectors = resolveNestedSelector(selector, rule);
  28. if (resolvedSelectors.length === 1 && resolvedSelectors[0] === selector) {
  29. flattenedSelectors.push({
  30. selector: selectorAST,
  31. resolvedSelectors: selectorParser.root({
  32. value: '',
  33. nodes: [selectorAST],
  34. }),
  35. nested: false,
  36. });
  37. continue;
  38. }
  39. for (const resolvedSelector of resolvedSelectors) {
  40. if (!isStandardSyntaxSelector(resolvedSelector)) return [];
  41. const resolvedRoot = parseSelector(resolvedSelector, result, rule);
  42. if (!resolvedRoot) {
  43. continue;
  44. }
  45. flattenedSelectors.push({
  46. selector: selectorAST,
  47. resolvedSelectors: resolvedRoot,
  48. nested: true,
  49. });
  50. }
  51. }
  52. return flattenedSelectors;
  53. }