Keep leading + glued in An+B notation (#19738)

This commit is contained in:
Lazizbek Ergashev authored and GitHub committed 2026-07-28 11:07:34 +08:00
1 parent 0a1416fd56
commit f426cfafb7
4 files changed
+110 -5

No files matched your search

+18
View File
@@ -0,0 +1,18 @@
#### Keep leading `+` glued in An+B notation (#19738 by @lazerg)
The An+B grammar doesn't allow whitespace between a leading `+` and the `n`, so the extra space produced invalid output.
<!-- prettier-ignore -->
```css
/* Input */
a:nth-child(+3n+2) {
}
/* Prettier stable */
a:nth-child(+ 3n + 2) {
}
/* Prettier main */
a:nth-child(+3n + 2) {
}
```
+22 -5
View File
@@ -350,13 +350,30 @@ function genericPrint(path, options, print) {
node.value === ">>>"
) {
const parentNode = path.parent;
const leading =
const isFirstNode =
parentNode.type === "selector-selector" &&
parentNode.nodes[0] === node
? ""
: line;
parentNode.nodes[0] === node;
const leading = isFirstNode ? "" : line;
return [leading, node.value, path.isLast ? "" : " "];
// The leading `+` in An+B notation (e.g. `:nth-child(+2n)`) must stay
// glued to the following token, a space there is invalid per spec.
const grandparentNode = path.grandparent;
const isNthLeadingSign =
isFirstNode &&
node.value === "+" &&
grandparentNode?.type === "selector-pseudo" &&
[
":nth-child",
":nth-last-child",
":nth-of-type",
":nth-last-of-type",
].includes(grandparentNode.value.toLowerCase());
return [
leading,
node.value,
path.isLast || isNthLeadingSign ? "" : " ",
];
}
const leading = node.value.trimStart().startsWith("(") ? line : "";
@@ -1,5 +1,56 @@
// Jest Snapshot v1, https://jestjs.io/docs/snapshot-testing
exports[`an-plus-b.css format 1`] = `
====================================options=====================================
parsers: ["css"]
printWidth: 80 (default) |
=====================================input======================================
:nth-child(+2n),
:nth-child(+n),
:nth-child(+3n+2),
:nth-last-child(+3n+1),
:nth-of-type(+2n),
:nth-last-of-type(+n+3),
:nth-child(2n+1),
:nth-child(-n+2),
:not(:nth-child(+2n)),
:not(:nth-child(+n)),
:not(:nth-child(+3n+2)),
:not(:nth-last-child(+3n+1)),
:not(:nth-of-type(+2n)),
:not(:nth-last-of-type(+n+3)),
:not(:nth-child(2n+1)),
:not(:nth-child(-n+2)) {}
:has(+ img),
:has(+img) {}
=====================================output=====================================
:nth-child(+2n),
:nth-child(+n),
:nth-child(+3n + 2),
:nth-last-child(+3n + 1),
:nth-of-type(+2n),
:nth-last-of-type(+n + 3),
:nth-child(2n + 1),
:nth-child(-n + 2),
:not(:nth-child(+2n)),
:not(:nth-child(+n)),
:not(:nth-child(+3n + 2)),
:not(:nth-last-child(+3n + 1)),
:not(:nth-of-type(+2n)),
:not(:nth-last-of-type(+n + 3)),
:not(:nth-child(2n + 1)),
:not(:nth-child(-n + 2)) {
}
:has(+ img),
:has(+ img) {
}
================================================================================
`;
exports[`combinator.css format 1`] = `
====================================options=====================================
parsers: ["css"]
+19
View File
@@ -0,0 +1,19 @@
:nth-child(+2n),
:nth-child(+n),
:nth-child(+3n+2),
:nth-last-child(+3n+1),
:nth-of-type(+2n),
:nth-last-of-type(+n+3),
:nth-child(2n+1),
:nth-child(-n+2),
:not(:nth-child(+2n)),
:not(:nth-child(+n)),
:not(:nth-child(+3n+2)),
:not(:nth-last-child(+3n+1)),
:not(:nth-of-type(+2n)),
:not(:nth-last-of-type(+n+3)),
:not(:nth-child(2n+1)),
:not(:nth-child(-n+2)) {}
:has(+ img),
:has(+img) {}