Handle rule nesting, remove NestedSelector from SimpleSelector, improve logic for encapsulation

pull/9549/head
Albert Marashi 3 years ago
parent 0e67006d4b
commit d9174c4fbf

@ -129,14 +129,15 @@ function read_at_rule(parser) {
/**
* @param {import('../index.js').Parser} parser
* @param {boolean} nested Whether this rule is nested inside another rule
* @returns {import('#compiler').Css.Rule}
*/
function read_rule(parser) {
function read_rule(parser, nested = false) {
const start = parser.index;
return {
type: 'Rule',
prelude: read_selector_list(parser),
prelude: read_selector_list(parser, nested),
block: read_block(parser),
start,
end: parser.index
@ -145,16 +146,17 @@ function read_rule(parser) {
/**
* @param {import('../index.js').Parser} parser
* @param {boolean} nested Whether this selector list is nested inside another rule
* @returns {import('#compiler').Css.SelectorList}
*/
function read_selector_list(parser) {
function read_selector_list(parser, nested) {
/** @type {import('#compiler').Css.Selector[]} */
const children = [];
const start = parser.index;
while (parser.index < parser.template.length) {
children.push(read_selector(parser));
children.push(read_selector(parser, nested));
const end = parser.index;
@ -178,28 +180,29 @@ function read_selector_list(parser) {
/**
* @param {import('../index.js').Parser} parser
* @param {boolean} nested Whether this selector is nested inside another rule
* @returns {import('#compiler').Css.Selector}
*/
function read_selector(parser) {
function read_selector(parser, nested) {
const list_start = parser.index;
/** @type {Array<import('#compiler').Css.SimpleSelector | import('#compiler').Css.Combinator>} */
/** @type {Array<import('#compiler').Css.SimpleSelector | import('#compiler').Css.Combinator | import('#compiler').Css.NestingSelector>} */
const children = [];
while (parser.index < parser.template.length) {
const start = parser.index;
if (parser.eat('*')) {
if (nested && parser.eat('&')){
children.push({
type: 'TypeSelector',
name: '*',
type: 'NestedSelector',
name: '&',
start,
end: parser.index
});
} else if (parser.eat('&')){
} else if (parser.eat('*')) {
children.push({
type: 'NestedSelector',
name: '&',
type: 'TypeSelector',
name: '*',
start,
end: parser.index
});
@ -396,7 +399,7 @@ function read_declaration_or_rule(parser) {
// due to complexities with https://bugs.chromium.org/p/chromium/issues/detail?id=1427259
// as most browsers as of 17/11/2023 do not support nesting without & selector
if (parser.match('&')) {
return read_rule(parser)
return read_rule(parser, true)
} else {
return read_declaration(parser);
}

@ -100,15 +100,12 @@ export default class Selector {
while (i--) {
const selector = block.selectors[i];
if (selector.type === 'PseudoElementSelector' || selector.type === 'PseudoClassSelector') {
if (selector.name !== 'root' && selector.name !== 'host') {
if (!block.root && !block.host && !block.nested) {
if (i === 0) code.prependRight(selector.start, attr);
}
continue;
}
if (selector.type === "NestedSelector") {
// do we want to add the attr to the nested selector?
// it's kind of implied that it's a child of the parent selector
} else if (selector.type === 'TypeSelector' && selector.name === '*') {
if (selector.type === 'TypeSelector' && selector.name === '*') {
code.update(selector.start, selector.end, attr);
} else {
code.appendLeft(selector.end, attr);
@ -123,7 +120,7 @@ export default class Selector {
if (block.should_encapsulate) {
encapsulate_block(
block,
index === this.blocks.filter(block => block.nested !== true).length - 1
index === this.blocks.length - 1 + (block.nested ? 1 : 0)
? attr.repeat(amount_class_specificity_to_increase + 1)
: attr
);
@ -838,12 +835,18 @@ function group_selectors(selector) {
selector.children.forEach((child) => {
if (child.type === 'Combinator') {
if(block.nested && !block.combinator) {
block.combinator = child;
} else {
block = new Block(child);
blocks.push(block);
}
} else if (child.type === "NestedSelector") {
block.nested = true;
} else {
if (child.type === "NestedSelector") block.nested = true;
block.add(child);
}
});
return blocks;
}

@ -25,7 +25,7 @@ export interface SelectorList extends BaseNode {
export interface Selector extends BaseNode {
type: 'Selector';
children: Array<SimpleSelector | Combinator>;
children: Array<SimpleSelector | Combinator | NestingSelector>;
}
export interface TypeSelector extends BaseNode {
@ -67,11 +67,6 @@ export interface Percentage extends BaseNode {
value: string;
}
export interface NestedSelector extends BaseNode {
type: 'NestedSelector';
name: "&";
}
export type SimpleSelector =
| TypeSelector
| IdSelector
@ -79,7 +74,6 @@ export type SimpleSelector =
| AttributeSelector
| PseudoElementSelector
| PseudoClassSelector
| NestedSelector
| Percentage;
export interface Combinator extends BaseNode {
@ -87,6 +81,11 @@ export interface Combinator extends BaseNode {
name: string;
}
export interface NestingSelector extends BaseNode {
type: 'NestedSelector';
name: "&";
}
export interface Block extends BaseNode {
type: 'Block';
children: Array<Declaration | Rule | Atrule>;

Loading…
Cancel
Save