From 84dc991b53f3a7460344e9333ee3a473b722b77f Mon Sep 17 00:00:00 2001 From: Ido Rosenthal Date: Mon, 17 Jun 2024 21:50:52 +0300 Subject: [PATCH] feat(formatter): group similar name at-rules (#2964) --- packages/code-formatter/src/format-css.ts | 13 +++++++++---- .../test/formatter-experimental.spec.ts | 13 +++++++++++++ 2 files changed, 22 insertions(+), 4 deletions(-) diff --git a/packages/code-formatter/src/format-css.ts b/packages/code-formatter/src/format-css.ts index 112e137aa..f58da2baf 100644 --- a/packages/code-formatter/src/format-css.ts +++ b/packages/code-formatter/src/format-css.ts @@ -181,19 +181,24 @@ function formatAst(ast: AnyNode, index: number, options: FormatOptions) { ast.value ||= ' '; // minimal space } } else if (ast.type === 'atrule') { - const prevType = ast.prev()?.type; + const prevNode = ast.prev(); + const prevType = prevNode?.type; + const childrenLen = ast.nodes?.length ?? -1; + const hasNestedChildren = childrenLen === -1; const hasCommentBefore = prevType === 'comment'; const hasRuleBefore = prevType === 'rule'; + const isSameTypeAsPrev = prevType === 'atrule' && prevNode?.name === ast.name; - /* The postcss type does not represent the reality there are atRules without nodes */ - const childrenLen = ast.nodes?.length ?? -1; const separation = - (childrenLen === -1 && !hasRuleBefore) || hasCommentBefore ? 0 : linesBetween; + hasCommentBefore || (hasNestedChildren && !hasRuleBefore && isSameTypeAsPrev) + ? 0 + : linesBetween; ast.raws.before = index !== 0 || indentLevel > 0 ? NL.repeat(index !== 0 ? separation + 1 : 1) + indent.repeat(indentLevel) : ''; + ast.raws.after = childrenLen ? NL + indent.repeat(indentLevel) : ''; ast.raws.afterName = ast.params.length ? enforceOneSpaceAround(ast.raws.afterName || '') diff --git a/packages/code-formatter/test/formatter-experimental.spec.ts b/packages/code-formatter/test/formatter-experimental.spec.ts index ea21ca53d..688a2c761 100644 --- a/packages/code-formatter/test/formatter-experimental.spec.ts +++ b/packages/code-formatter/test/formatter-experimental.spec.ts @@ -1032,6 +1032,18 @@ describe('formatter - experimental', () => { `, }); }); + it('should group similar named atRules with no body', () => { + testFormatCss({ + message: 'top-level', + source: `@aaa 1;@aaa 2;@bbb 1;@bbb 2;@aaa 3`, + expect: `@aaa 1;\n@aaa 2;\n\n@bbb 1;\n@bbb 2;\n\n@aaa 3\n`, + }); + testFormatCss({ + message: 'nested', + source: `@top {@aaa 1;@aaa 2;@bbb 1;@bbb 2;@aaa 3}`, + expect: `@top {\n @aaa 1;\n @aaa 2;\n\n @bbb 1;\n @bbb 2;\n\n @aaa 3\n}\n`, + }); + }); it('should set body into lines and indent accordingly', () => { testFormatCss({ deindent: true, @@ -1126,6 +1138,7 @@ describe('formatter - experimental', () => { @parens (a1: 1px, (a2: 2px) (a3: 3px)) {} @function f(b1, b2, f-nest(b3)) {} + @square [c1, c2, c3[c4]) {} `,