New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Demo implementation of @csstools/selector-resolve-nested
#7496
base: main
Are you sure you want to change the base?
Demo implementation of @csstools/selector-resolve-nested
#7496
Conversation
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This currently errors, mostly because of : #7495
function removeIgnoredNodes(selector, isIgnored) { | ||
const clone = selector.clone(); | ||
|
||
clone.walk((node) => { | ||
let value = ''; | ||
|
||
switch (node.type) { | ||
case 'attribute': | ||
case 'class': | ||
case 'id': | ||
case 'tag': | ||
value = node.toString(); | ||
break; | ||
case 'pseudo': | ||
value = node.value; | ||
break; | ||
|
||
default: | ||
return | ||
} | ||
|
||
if (!value) { | ||
return; | ||
} | ||
|
||
if (isIgnored(value)) { | ||
node.replaceWith(selectorParser.universal({ | ||
value: '*', | ||
sourceIndex: node.sourceIndex, | ||
source: node.source, | ||
})); | ||
} | ||
}); | ||
|
||
return clone; | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I removed all the custom logic for specificity and instead manipulated the AST so that ignored nodes were replaced with *
which has zero specificity. This has obvious differences but I think it can be an interesting approach to ignoreSelector
in this context.
*/ | ||
const specificitySum = (specificities) => { | ||
const sum = zeroSpecificity(); | ||
function gatherSelectorsForRule(rule, result, isIgnored) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This should be a shared helper.
It walks the postcss
AST to gather all the ancestor nodes and resolves all the nested selectors.
if (typeGuards.isAtRule(child) && ast) { | ||
// `.foo, #bar { @media screen { color: red; } }` | ||
// equivalent to | ||
// `@media screen { .foo, #bar { & { color: red; } } }` | ||
// `@media screen { :is(.foo, #bar) { color: red; } }` | ||
const childAST = selectorAST('&', result, child); | ||
|
||
if (!childAST) return; | ||
|
||
ast = selectorResolveNested.resolveNestedSelector(childAST, ast); | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
for more info and demo's see : mrhenry/stylelint-mrhenry#66
This looks fantastic and is a significant step towards spec compliance! |
if (typeGuards.isAtRule(child) && ast) { | ||
// `.foo, #bar { @media screen { color: red; } }` | ||
// equivalent to | ||
// `@media screen { .foo, #bar { & { color: red; } } }` | ||
// `@media screen { :is(.foo, #bar) { color: red; } }` | ||
const childAST = selectorAST('&', result, child); | ||
|
||
if (!childAST) return; | ||
|
||
ast = selectorResolveNested.resolveNestedSelector(childAST, ast); | ||
} | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Note : the specification has since changed again, this is no longer true.
See : #6234
I wanted to gain a better understanding of the complexity that CSS nesting introduces for all rules that analyse selectors.
I also want to validate how
@csstools/selector-resolve-nested
works to make sure it works correctly and its API has the right shape.This is a draft PR as it isn't intended to be merged, but feedback is welcome!