fix(formatter_css): fix layouts found in mdn-content repo (css-in-md) (#27326)

- `@supports`: keep `not` on its term's line, open over-wide parenthesized terms
- custom function prelude: indent the continuation after `returns type(...)`
- media ratio: print the spacing around `/` as written
- spaced `/`: glue to its left operand and break after
- a comment leading a comma list item: measure the item's first chunk
- `calc()` parenthesized operand: open its parens when over-wide
- do not follow postcss-values' re-split of a signed word (`Arial, -apple-system`, `-600px`)
- re-pin DIVERGENCES.md#fill-break-position
This commit is contained in:
leaysgur committed 2026-10-05 00:25:07 +00:00
1 parent df85b4cd78
commit e9ae2d8fa6
28 files changed
+2982 -916

No files matched your search

@@ -228,7 +228,7 @@
## less
### Option 1: 402/409 (98.29%)
### Option 1: 403/409 (98.53%)
```json
{"printWidth":80}
@@ -236,8 +236,6 @@
- [externals/ng-zorro-antd/components/style/mixins/customize.less](diffs/less/externals__ng-zorro-antd__components__style__mixins__customize.less.md)
- crates/oxc_formatter_css/DIVERGENCES.md#less-guard-list-inline
- [externals/ng-zorro-antd/components/style/themes/compact.less](diffs/less/externals__ng-zorro-antd__components__style__themes__compact.less.md)
- crates/oxc_formatter_css/DIVERGENCES.md#fill-break-position
- [externals/ng-zorro-antd/components/style/themes/dark.less](diffs/less/externals__ng-zorro-antd__components__style__themes__dark.less.md)
- crates/oxc_formatter_css/DIVERGENCES.md#trailing-line-comment-print-width
- [externals/ng-zorro-antd/components/style/themes/default.less](diffs/less/externals__ng-zorro-antd__components__style__themes__default.less.md)
@@ -245,7 +243,7 @@
- [externals/ng-zorro-antd/components/style/themes/variable.less](diffs/less/externals__ng-zorro-antd__components__style__themes__variable.less.md)
- crates/oxc_formatter_css/DIVERGENCES.md#trailing-line-comment-print-width, crates/oxc_formatter_css/DIVERGENCES.md#fill-break-position
- [externals/ng-zorro-antd/components/table/style/index.less](diffs/less/externals__ng-zorro-antd__components__table__style__index.less.md)
- crates/oxc_formatter_css/DIVERGENCES.md#fill-break-position
- crates/oxc_formatter_css/DIVERGENCES.md#signed-value-resplit
- [externals/ng-zorro-antd/components/table/style/rtl.less](diffs/less/externals__ng-zorro-antd__components__table__style__rtl.less.md)
- crates/oxc_formatter_css/DIVERGENCES.md#fill-break-position
@@ -345,7 +343,7 @@
## scss
### Option 1: 203/217 (93.55%)
### Option 1: 202/217 (93.09%)
```json
{"printWidth":80}
@@ -357,6 +355,8 @@
- crates/oxc_formatter_css/DIVERGENCES.md#media-query-operator-spacing
- [externals/gitlab/stylesheets/framework/variables_overrides.scss](diffs/scss/externals__gitlab__stylesheets__framework__variables_overrides.scss.md)
- crates/oxc_formatter_css/DIVERGENCES.md#map-item-break-comma-lists-only
- [externals/gitlab/stylesheets/framework/variables.scss](diffs/scss/externals__gitlab__stylesheets__framework__variables.scss.md)
- crates/oxc_formatter_css/DIVERGENCES.md#signed-value-resplit
- [externals/gitlab/stylesheets/highlight/conflict_colors.scss](diffs/scss/externals__gitlab__stylesheets__highlight__conflict_colors.scss.md)
- crates/oxc_formatter_css/DIVERGENCES.md#map-paren-value-blank-lines
- [externals/gitlab/stylesheets/page_bundles/_ide_theme_overrides.scss](diffs/scss/externals__gitlab__stylesheets__page_bundles___ide_theme_overrides.scss.md)
@@ -380,7 +380,7 @@
- [externals/gitlab/stylesheets/pages/settings.scss](diffs/scss/externals__gitlab__stylesheets__pages__settings.scss.md)
- crates/oxc_formatter_css/DIVERGENCES.md#media-query-operator-spacing
### Option 2: 204/217 (94.01%)
### Option 2: 203/217 (93.55%)
```json
{"printWidth":100}
@@ -392,6 +392,8 @@
- crates/oxc_formatter_css/DIVERGENCES.md#fill-break-position
- [externals/gitlab/stylesheets/framework/variables_overrides.scss](diffs/scss/externals__gitlab__stylesheets__framework__variables_overrides.scss.md)
- crates/oxc_formatter_css/DIVERGENCES.md#map-item-break-comma-lists-only
- [externals/gitlab/stylesheets/framework/variables.scss](diffs/scss/externals__gitlab__stylesheets__framework__variables.scss.md)
- crates/oxc_formatter_css/DIVERGENCES.md#signed-value-resplit
- [externals/gitlab/stylesheets/highlight/conflict_colors.scss](diffs/scss/externals__gitlab__stylesheets__highlight__conflict_colors.scss.md)
- crates/oxc_formatter_css/DIVERGENCES.md#map-paren-value-blank-lines
- [externals/gitlab/stylesheets/page_bundles/_ide_theme_overrides.scss](diffs/scss/externals__gitlab__stylesheets__page_bundles___ide_theme_overrides.scss.md)
@@ -1,657 +0,0 @@
# externals/ng-zorro-antd/components/style/themes/compact.less
## Option 1
`````json
{"printWidth":80}
`````
### Diff
`````diff
===================================================================
--- prettier
+++ oxfmt
@@ -104,15 +104,12 @@
// Input
// ---
@input-padding-vertical-base: round(
max(
- (
- round(
- ((@input-height-base - @font-size-base * @line-height-base) / 2) *
- 10
- ) /
- 10
- ) -
+ (round(
+ ((@input-height-base - @font-size-base * @line-height-base) / 2) * 10
+ ) /
+ 10) -
@border-width-base,
2px
)
);
`````
### Actual (oxfmt)
`````less
@import "./default.less";
@line-height-base: 1.66667;
@line-height-lg: 1.5715;
@mode: compact;
@font-size-base: 12px;
@font-size-lg: @font-size-base + 2px;
// default paddings
@default-padding-lg: 24px; // containers
@default-padding-md: 16px; // small containers and buttons
@default-padding-sm: 12px; // Form controls and items
@default-padding-xs: 8px; // small items
@default-padding-xss: 4px; // more small
// vertical paddings
@padding-lg: 16px; // containers
@padding-md: 8px; // small containers and buttons
@padding-sm: 8px; // Form controls and items
@padding-xs: 4px; // small items
@padding-xss: 0px; // more small
// vertical padding for all form controls
@control-padding-horizontal: @padding-sm;
@control-padding-horizontal-sm: @default-padding-xs;
// vertical margins
@margin-lg: 16px; // containers
@margin-md: 8px; // small containers and buttons
@margin-sm: 8px; // Form controls and items
@margin-xs: 4px; // small items
@margin-xss: 0px; // more small
// height rules
@height-base: 28px;
@height-lg: 32px;
@height-sm: 22px;
// Button
// ---
@btn-padding-horizontal-base: @default-padding-sm - 1px;
@btn-padding-horizontal-lg: @btn-padding-horizontal-base;
@btn-padding-horizontal-sm: @default-padding-xs - 1px;
@btn-square-only-icon-size-lg: 16px;
@btn-square-only-icon-size: 14px;
@btn-square-only-icon-size-sm: 12px;
// Breadcrumb
// ---
@breadcrumb-font-size: @font-size-base;
@breadcrumb-icon-font-size: @font-size-base;
//Dropdown
@dropdown-line-height: 18px;
// Menu
@menu-item-padding-horizontal: 12px;
@menu-horizontal-line-height: 38px;
@menu-inline-toplevel-item-height: 32px;
@menu-item-height: 32px;
@menu-item-vertical-margin: 0px;
@menu-item-boundary-margin: 0px;
@menu-icon-margin-right: 8px;
// Checkbox
@checkbox-size: 14px;
@checkbox-group-item-margin-right: 6px;
// picker
@picker-panel-cell-height: 22px;
@picker-panel-cell-width: 32px;
@picker-text-height: 32px;
@picker-time-panel-cell-height: 24px;
@picker-panel-without-time-cell-height: 48px;
// Form
// ---
@form-item-margin-bottom: 16px;
@form-vertical-label-padding: 0 0 4px;
// Rate
// ---
@rate-star-size: 16px;
// Radio
// ---
@radio-size: 14px;
@radio-wrapper-margin-right: 6px;
// Switch
// ---
@switch-height: 20px;
@switch-sm-height: 14px;
@switch-min-width: 40px;
@switch-sm-min-width: 24px;
@switch-inner-margin-min: 4px;
@switch-inner-margin-max: 22px;
// Slider
// ---
@slider-handle-size: 12px;
@slider-handle-margin-top: -4px;
// Input
// ---
@input-padding-vertical-base: round(
max(
(round(
((@input-height-base - @font-size-base * @line-height-base) / 2) * 10
) /
10) -
@border-width-base,
2px
)
);
@input-padding-horizontal-lg: 11px;
// PageHeader
// ---
@page-header-padding: 16px;
@page-header-padding-vertical: 8px;
@page-header-heading-title: 16px;
@page-header-heading-sub-title: 12px;
@page-header-tabs-tab-font-size: 14px;
// Pagination
// ---
@pagination-mini-options-size-changer-top: 1px;
@pagination-item-size-sm: 22px;
// Cascader
// ----
@cascader-dropdown-line-height: @dropdown-line-height;
// Select
// ---
@select-dropdown-height: @height-base;
@select-single-item-height-lg: 32px;
@select-multiple-item-height: @input-height-base -
max(@input-padding-vertical-base, 4) * 2; // Normal 24px
@select-multiple-item-height-lg: 24px;
@select-multiple-item-spacing-half: 3px;
// Tree
// ---
@tree-title-height: 20px;
// Transfer
// ---
@transfer-item-padding-vertical: 3px;
@transfer-list-search-icon-top: 8px;
@transfer-header-height: 36px;
// Comment
// ---
@comment-actions-margin-bottom: 0px;
@comment-actions-margin-top: @margin-xs;
@comment-content-detail-p-margin-bottom: 0px;
// Steps
// ---
@steps-icon-size: 24px;
@steps-icon-custom-size: 20px;
@steps-icon-custom-font-size: 20px;
@steps-icon-custom-top: 2px;
@steps-icon-margin: 2px 8px 2px 0;
@steps-icon-font-size: @font-size-base;
@steps-dot-top: 4px;
@steps-icon-top: 0px;
@steps-small-icon-size: 20px;
@steps-vertical-icon-width: 12px;
@steps-vertical-tail-width: 12px;
@steps-vertical-tail-width-sm: 10px;
// Collapse
// ---
//@collapse-header-padding-extra: 32px;
@collapse-content-padding: @padding-md @padding-lg;
// List
// ---
@list-item-meta-description-font-size: @font-size-sm;
@list-item-padding-sm: 4px 12px;
@list-item-padding-lg: 12px 16px;
// Drawer
// ---
@drawer-header-padding: 11px @padding-lg;
@drawer-footer-padding-vertical: @padding-sm;
@drawer-footer-padding-horizontal: @padding-sm;
@drawer-header-close-size: 44px;
// Modal
// --
@modal-header-padding-vertical: 11px;
@modal-header-padding: @modal-header-padding-vertical
@modal-header-padding-horizontal;
@modal-footer-padding-vertical: @padding-sm;
@modal-header-close-size: @modal-header-title-line-height + 2 *
@modal-header-padding-vertical;
@modal-confirm-body-padding: 24px 24px 16px;
// Message
// ---
@message-notice-content-padding: 8px 16px;
// popover
// --
@popover-min-height: 28px;
@popover-padding-horizontal: @default-padding-sm;
// Card
// ---
@card-head-height: 36px;
@card-head-font-size: @card-head-font-size-sm;
@card-head-padding: 8.5px;
@card-padding-base: 12px;
@card-padding-base-sm: @card-padding-base;
@card-head-height-sm: 30px;
@card-head-padding-sm: 6px;
@card-actions-li-margin: 4px 0;
@card-head-tabs-margin-bottom: -9px;
// Table
// ---
@table-padding-vertical: 12px;
@table-padding-horizontal: 8px;
@table-padding-vertical-md: 8px;
@table-padding-horizontal-md: 8px;
@table-padding-vertical-sm: 4px;
@table-padding-horizontal-sm: 4px;
@table-selection-column-width: 32px;
// Statistic
// ---
@statistic-content-font-size: 20px;
// Alert
// ---
@alert-with-description-no-icon-padding-vertical: 7px;
@alert-with-description-padding-vertical: 11px;
@alert-icon-top: 7px + @font-size-base * (@line-height-base / 2) -
(@font-size-base / 2);
@alert-with-description-icon-size: 20px;
// Skeleton
// ---
@skeleton-paragraph-margin-top: 20px;
@skeleton-paragraph-li-margin-top: 12px;
@skeleton-paragraph-li-height: 14px;
@skeleton-title-height: 14px;
@skeleton-title-paragraph-margin-top: 20px;
// Descriptions
@descriptions-title-margin-bottom: 8px;
@descriptions-default-padding: 12px @padding-lg;
@descriptions-item-padding-bottom: @padding-xs;
// Avatar
// ---
@avatar-size-base: 28px;
@avatar-size-lg: 32px;
@avatar-size-sm: 22px;
@avatar-font-size-base: 16px;
@avatar-font-size-lg: 20px;
@avatar-font-size-sm: 12px;
// Badge
// ---
@badge-height: 18px;
// Tag
// ---
@tag-line-height: 18px;
// Notification
// ---
@notification-padding-vertical: 12px;
@notification-padding-horizontal: 16px;
// Result
// ---
@result-title-font-size: 20px;
@result-icon-font-size: 64px;
@result-extra-margin: 24px 0 0 0;
// Anchor
// ---
@anchor-link-top: 4px;
@anchor-link-left: 16px;
@anchor-link-padding: @anchor-link-top 0 @anchor-link-top @anchor-link-left;
// Tabs
// ---
@tabs-card-horizontal-padding: 4px @padding-md;
// Progress
// ---
@progress-circle-text-font-size: 0.833333em;
// Image
// ---
@image-size-base: 48px;
@image-font-size-base: 24px;
`````
### Expected (prettier)
`````less
@import "./default.less";
@line-height-base: 1.66667;
@line-height-lg: 1.5715;
@mode: compact;
@font-size-base: 12px;
@font-size-lg: @font-size-base + 2px;
// default paddings
@default-padding-lg: 24px; // containers
@default-padding-md: 16px; // small containers and buttons
@default-padding-sm: 12px; // Form controls and items
@default-padding-xs: 8px; // small items
@default-padding-xss: 4px; // more small
// vertical paddings
@padding-lg: 16px; // containers
@padding-md: 8px; // small containers and buttons
@padding-sm: 8px; // Form controls and items
@padding-xs: 4px; // small items
@padding-xss: 0px; // more small
// vertical padding for all form controls
@control-padding-horizontal: @padding-sm;
@control-padding-horizontal-sm: @default-padding-xs;
// vertical margins
@margin-lg: 16px; // containers
@margin-md: 8px; // small containers and buttons
@margin-sm: 8px; // Form controls and items
@margin-xs: 4px; // small items
@margin-xss: 0px; // more small
// height rules
@height-base: 28px;
@height-lg: 32px;
@height-sm: 22px;
// Button
// ---
@btn-padding-horizontal-base: @default-padding-sm - 1px;
@btn-padding-horizontal-lg: @btn-padding-horizontal-base;
@btn-padding-horizontal-sm: @default-padding-xs - 1px;
@btn-square-only-icon-size-lg: 16px;
@btn-square-only-icon-size: 14px;
@btn-square-only-icon-size-sm: 12px;
// Breadcrumb
// ---
@breadcrumb-font-size: @font-size-base;
@breadcrumb-icon-font-size: @font-size-base;
//Dropdown
@dropdown-line-height: 18px;
// Menu
@menu-item-padding-horizontal: 12px;
@menu-horizontal-line-height: 38px;
@menu-inline-toplevel-item-height: 32px;
@menu-item-height: 32px;
@menu-item-vertical-margin: 0px;
@menu-item-boundary-margin: 0px;
@menu-icon-margin-right: 8px;
// Checkbox
@checkbox-size: 14px;
@checkbox-group-item-margin-right: 6px;
// picker
@picker-panel-cell-height: 22px;
@picker-panel-cell-width: 32px;
@picker-text-height: 32px;
@picker-time-panel-cell-height: 24px;
@picker-panel-without-time-cell-height: 48px;
// Form
// ---
@form-item-margin-bottom: 16px;
@form-vertical-label-padding: 0 0 4px;
// Rate
// ---
@rate-star-size: 16px;
// Radio
// ---
@radio-size: 14px;
@radio-wrapper-margin-right: 6px;
// Switch
// ---
@switch-height: 20px;
@switch-sm-height: 14px;
@switch-min-width: 40px;
@switch-sm-min-width: 24px;
@switch-inner-margin-min: 4px;
@switch-inner-margin-max: 22px;
// Slider
// ---
@slider-handle-size: 12px;
@slider-handle-margin-top: -4px;
// Input
// ---
@input-padding-vertical-base: round(
max(
(
round(
((@input-height-base - @font-size-base * @line-height-base) / 2) *
10
) /
10
) -
@border-width-base,
2px
)
);
@input-padding-horizontal-lg: 11px;
// PageHeader
// ---
@page-header-padding: 16px;
@page-header-padding-vertical: 8px;
@page-header-heading-title: 16px;
@page-header-heading-sub-title: 12px;
@page-header-tabs-tab-font-size: 14px;
// Pagination
// ---
@pagination-mini-options-size-changer-top: 1px;
@pagination-item-size-sm: 22px;
// Cascader
// ----
@cascader-dropdown-line-height: @dropdown-line-height;
// Select
// ---
@select-dropdown-height: @height-base;
@select-single-item-height-lg: 32px;
@select-multiple-item-height: @input-height-base -
max(@input-padding-vertical-base, 4) * 2; // Normal 24px
@select-multiple-item-height-lg: 24px;
@select-multiple-item-spacing-half: 3px;
// Tree
// ---
@tree-title-height: 20px;
// Transfer
// ---
@transfer-item-padding-vertical: 3px;
@transfer-list-search-icon-top: 8px;
@transfer-header-height: 36px;
// Comment
// ---
@comment-actions-margin-bottom: 0px;
@comment-actions-margin-top: @margin-xs;
@comment-content-detail-p-margin-bottom: 0px;
// Steps
// ---
@steps-icon-size: 24px;
@steps-icon-custom-size: 20px;
@steps-icon-custom-font-size: 20px;
@steps-icon-custom-top: 2px;
@steps-icon-margin: 2px 8px 2px 0;
@steps-icon-font-size: @font-size-base;
@steps-dot-top: 4px;
@steps-icon-top: 0px;
@steps-small-icon-size: 20px;
@steps-vertical-icon-width: 12px;
@steps-vertical-tail-width: 12px;
@steps-vertical-tail-width-sm: 10px;
// Collapse
// ---
//@collapse-header-padding-extra: 32px;
@collapse-content-padding: @padding-md @padding-lg;
// List
// ---
@list-item-meta-description-font-size: @font-size-sm;
@list-item-padding-sm: 4px 12px;
@list-item-padding-lg: 12px 16px;
// Drawer
// ---
@drawer-header-padding: 11px @padding-lg;
@drawer-footer-padding-vertical: @padding-sm;
@drawer-footer-padding-horizontal: @padding-sm;
@drawer-header-close-size: 44px;
// Modal
// --
@modal-header-padding-vertical: 11px;
@modal-header-padding: @modal-header-padding-vertical
@modal-header-padding-horizontal;
@modal-footer-padding-vertical: @padding-sm;
@modal-header-close-size: @modal-header-title-line-height + 2 *
@modal-header-padding-vertical;
@modal-confirm-body-padding: 24px 24px 16px;
// Message
// ---
@message-notice-content-padding: 8px 16px;
// popover
// --
@popover-min-height: 28px;
@popover-padding-horizontal: @default-padding-sm;
// Card
// ---
@card-head-height: 36px;
@card-head-font-size: @card-head-font-size-sm;
@card-head-padding: 8.5px;
@card-padding-base: 12px;
@card-padding-base-sm: @card-padding-base;
@card-head-height-sm: 30px;
@card-head-padding-sm: 6px;
@card-actions-li-margin: 4px 0;
@card-head-tabs-margin-bottom: -9px;
// Table
// ---
@table-padding-vertical: 12px;
@table-padding-horizontal: 8px;
@table-padding-vertical-md: 8px;
@table-padding-horizontal-md: 8px;
@table-padding-vertical-sm: 4px;
@table-padding-horizontal-sm: 4px;
@table-selection-column-width: 32px;
// Statistic
// ---
@statistic-content-font-size: 20px;
// Alert
// ---
@alert-with-description-no-icon-padding-vertical: 7px;
@alert-with-description-padding-vertical: 11px;
@alert-icon-top: 7px + @font-size-base * (@line-height-base / 2) -
(@font-size-base / 2);
@alert-with-description-icon-size: 20px;
// Skeleton
// ---
@skeleton-paragraph-margin-top: 20px;
@skeleton-paragraph-li-margin-top: 12px;
@skeleton-paragraph-li-height: 14px;
@skeleton-title-height: 14px;
@skeleton-title-paragraph-margin-top: 20px;
// Descriptions
@descriptions-title-margin-bottom: 8px;
@descriptions-default-padding: 12px @padding-lg;
@descriptions-item-padding-bottom: @padding-xs;
// Avatar
// ---
@avatar-size-base: 28px;
@avatar-size-lg: 32px;
@avatar-size-sm: 22px;
@avatar-font-size-base: 16px;
@avatar-font-size-lg: 20px;
@avatar-font-size-sm: 12px;
// Badge
// ---
@badge-height: 18px;
// Tag
// ---
@tag-line-height: 18px;
// Notification
// ---
@notification-padding-vertical: 12px;
@notification-padding-horizontal: 16px;
// Result
// ---
@result-title-font-size: 20px;
@result-icon-font-size: 64px;
@result-extra-margin: 24px 0 0 0;
// Anchor
// ---
@anchor-link-top: 4px;
@anchor-link-left: 16px;
@anchor-link-padding: @anchor-link-top 0 @anchor-link-top @anchor-link-left;
// Tabs
// ---
@tabs-card-horizontal-padding: 4px @padding-md;
// Progress
// ---
@progress-circle-text-font-size: 0.833333em;
// Image
// ---
@image-size-base: 48px;
@image-font-size-base: 24px;
`````
@@ -55,38 +55,7 @@
@background-color-dark: hsv(0, 0, 94%); // dark grey background color
// Disabled states
@@ -465,24 +453,18 @@
@input-padding-horizontal-base: @input-padding-horizontal;
@input-padding-horizontal-sm: @control-padding-horizontal-sm - @line-width;
@input-padding-horizontal-lg: @input-padding-horizontal;
@input-padding-vertical-base: max(
- (
- round(
- ((@input-height-base - @font-size-base * @line-height-base) / 2) * 10
- ) /
- 10
- ) -
+ (round(
+ ((@input-height-base - @font-size-base * @line-height-base) / 2) * 10
+ ) /
+ 10) -
@border-width-base,
3px
);
@input-padding-vertical-sm: max(
- (
- round(
- ((@input-height-sm - @font-size-base * @line-height-base) / 2) * 10
- ) /
- 10
- ) -
+ (round(((@input-height-sm - @font-size-base * @line-height-base) / 2) * 10) /
+ 10) -
@border-width-base,
0
);
@input-padding-vertical-lg: (
@@ -846,11 +828,12 @@
@@ -846,11 +834,12 @@
@tabs-card-head-background: @background-color-light;
@tabs-card-height: 40px;
@tabs-card-active-color: @primary-color;
@@ -564,16 +533,22 @@
@input-padding-horizontal-sm: @control-padding-horizontal-sm - @line-width;
@input-padding-horizontal-lg: @input-padding-horizontal;
@input-padding-vertical-base: max(
(round(
((@input-height-base - @font-size-base * @line-height-base) / 2) * 10
) /
10) -
(
round(
((@input-height-base - @font-size-base * @line-height-base) / 2) * 10
) /
10
) -
@border-width-base,
3px
);
@input-padding-vertical-sm: max(
(round(((@input-height-sm - @font-size-base * @line-height-base) / 2) * 10) /
10) -
(
round(
((@input-height-sm - @font-size-base * @line-height-base) / 2) * 10
) /
10
) -
@border-width-base,
0
);
@@ -27,38 +27,7 @@
@background-color-dark: hsv(0, 0, 94%); // dark grey background color
// Disabled states
@@ -530,24 +526,18 @@
@input-padding-horizontal-base: @input-padding-horizontal;
@input-padding-horizontal-sm: @control-padding-horizontal-sm - @line-width;
@input-padding-horizontal-lg: @input-padding-horizontal;
@input-padding-vertical-base: max(
- (
- round(
- ((@input-height-base - @font-size-base * @line-height-base) / 2) * 10
- ) /
- 10
- ) -
+ (round(
+ ((@input-height-base - @font-size-base * @line-height-base) / 2) * 10
+ ) /
+ 10) -
@border-width-base,
3px
);
@input-padding-vertical-sm: max(
- (
- round(
- ((@input-height-sm - @font-size-base * @line-height-base) / 2) * 10
- ) /
- 10
- ) -
+ (round(((@input-height-sm - @font-size-base * @line-height-base) / 2) * 10) /
+ 10) -
@border-width-base,
0
);
@input-padding-vertical-lg: (
@@ -910,11 +900,12 @@
@@ -910,11 +906,12 @@
@tabs-card-head-background: @background-color-light;
@tabs-card-height: 40px;
@tabs-card-active-color: @primary-color;
@@ -609,16 +578,22 @@
@input-padding-horizontal-sm: @control-padding-horizontal-sm - @line-width;
@input-padding-horizontal-lg: @input-padding-horizontal;
@input-padding-vertical-base: max(
(round(
((@input-height-base - @font-size-base * @line-height-base) / 2) * 10
) /
10) -
(
round(
((@input-height-base - @font-size-base * @line-height-base) / 2) * 10
) /
10
) -
@border-width-base,
3px
);
@input-padding-vertical-sm: max(
(round(((@input-height-sm - @font-size-base * @line-height-base) / 2) * 10) /
10) -
(
round(
((@input-height-sm - @font-size-base * @line-height-base) / 2) * 10
) /
10
) -
@border-width-base,
0
);
+55 -13
View File
@@ -845,6 +845,44 @@ Prettier glues the sign to the number (removing the source space, a postcss word
Matching that gluing is ad-hoc work for a torture-test-only shape.
A sign GLUED in the source never gains a space in either implementation (that direction is the parser's folded-sign handling, not a divergence).
## signed-value-resplit
- Why: uniform-rule (same construct, same output: the item in first position, an unsigned item)
- Pin: `tests/fixtures/format/css/signed-value-resplit.css`
- Conformance: `css/fill-value/fill.css`
- Oxfmt: `externals/gitlab/stylesheets/framework/variables.scss`, `externals/ng-zorro-antd/components/table/style/index.less`
```css
/* input */
font-family: Arial, -apple-system;
-webkit-mask-position-x: 50px, 25%, -3em;
background: url("/shared-assets/images/examples/web-animations/cat_sprite.png") -600px 0 no-repeat;
/* ours */
font-family: Arial, -apple-system;
-webkit-mask-position-x: 50px, 25%, -3em;
background: url("/shared-assets/images/examples/web-animations/cat_sprite.png")
-600px 0 no-repeat;
/* prettier */
font-family:
Arial,
-apple-system;
-webkit-mask-position-x:
50px,
25%,
-3em;
background: url("/shared-assets/images/examples/web-animations/cat_sprite.png") -600px
0 no-repeat;
```
postcss-values splits a signed word (`-apple-system`, `-3em`, `-@var`) past the first position into an operator + word,
the re-split word AGENTS.md's "Acceptance" does not follow:
- as a two-node item, it breaks the comma list one item per line (`shouldBreakList`), though `-apple-system, Arial` and `50px, 25%, 3em` stay on one line
- as a math operator, it glues to the word before it, overflowing the line
Ours prints a signed item as one word, like the same item in first position or unsigned.
## css-glued-minus-paren
- Why: uniform-rule (same construct, same output: the `-(` shapes Prettier keeps glued)
@@ -873,29 +911,33 @@ Css mode only (hence the prefix): in Less and Scss, Prettier keeps `3px -(4px)`
## fill-break-position
- Why: cost
- Pin: `tests/fixtures/format/css/fill-math-chunk-break.css`
- Conformance: `css/fill-value/fill.css`
- Pin: `tests/fixtures/format/scss/fill-break-position.scss`
- Oxfmt: `externals/webawesome/number-input/number-input.styles.ts`, `externals/webawesome/page/page.styles.ts`,
`externals/ng-zorro-antd/components/style/themes/compact.less`, `externals/ng-zorro-antd/components/style/themes/default.less`, `externals/ng-zorro-antd/components/style/themes/variable.less`, `externals/ng-zorro-antd/components/table/style/index.less`, `externals/ng-zorro-antd/components/table/style/rtl.less`,
`externals/ng-zorro-antd/components/style/themes/default.less`, `externals/ng-zorro-antd/components/style/themes/variable.less`, `externals/ng-zorro-antd/components/table/style/rtl.less`,
`externals/gitlab/stylesheets/components/content_editor.scss`, `externals/gitlab/stylesheets/page_bundles/_ide_theme_overrides.scss`, `externals/gitlab/stylesheets/framework/sidebar.scss`
```css
/* input (nested one level, print width 80) */
margin-left: sg-layout-width(logo-shopify) / 2 * -1 + sg-offset-x(page-nav) / 2;
```scss
/* input (nested three levels, print width 80) */
height: calc(#{$calc-application-viewport-height} - #{$mr-sticky-header-height} - var(--mr-review-bar-height));
/* ours */
margin-left: sg-layout-width(logo-shopify) / 2 * -1 + sg-offset-x(page-nav)
/ 2;
height: calc(
#{$calc-application-viewport-height} - #{$mr-sticky-header-height} -
var(--mr-review-bar-height)
);
/* prettier */
margin-left: sg-layout-width(logo-shopify) / 2 * -1 +
sg-offset-x(page-nav) / 2;
height: calc(
#{$calc-application-viewport-height} -
#{$mr-sticky-header-height} - var(--mr-review-bar-height)
);
```
An over-wide math-y value run (css token soup here):
Prettier's fill fit-check breaks INSIDE the wide chunk;
our core `fill` (biome semantics) breaks the SEPARATOR instead.
A math-y value run (token soup here):
Prettier's fill breaks at an earlier separator, though the next chunk still fits;
our core `fill` (biome semantics) breaks only at the last fitting separator.
Layout-only, the principled fix is the shared core-fill fit-check change (needs a JS-conformance impact experiment first).
A spaced `/` is not part of this: it glues to its left operand and breaks after, as in Prettier (`tests/fixtures/format/css/fill-math-chunk-break.css`).
## less-value-interpolation-rejected
+92 -57
View File
@@ -11,8 +11,9 @@ use oxc_css_parser::{
KeyframesName, LessImportOptions, LessImportPrelude, MediaCondition,
MediaConditionAfterMediaType, MediaConditionKind, MediaFeature, MediaFeatureComparisonKind,
MediaFeatureName, MediaInParens, MediaInParensKind, MediaQuery, MediaQueryList,
NamespacePreludeUri, SassAtRootKind, SimpleBlock, SupportsCondition, SupportsConditionKind,
SupportsInParens, SupportsInParensKind, TokenSeq, UnknownAtRulePrelude,
NamespacePreludeUri, SassAtRootKind, SimpleBlock, SupportsAnd, SupportsCondition,
SupportsConditionKind, SupportsInParens, SupportsInParensKind, SupportsNot, SupportsOr,
TokenSeq, UnknownAtRulePrelude,
},
pos::Span,
token::{Token, TokenWithSpan},
@@ -21,10 +22,10 @@ use oxc_css_parser::{
use oxc_formatter_core::{
Buffer, Format, FormatElement, arena_cow_str,
builders::{
empty_line, group, hard_line_break, indent, soft_line_break, soft_line_break_or_space,
space, text,
empty_line, group, hard_line_break, indent, soft_block_indent, soft_line_break,
soft_line_break_or_space, space, text,
},
write,
format_args, write,
};
use crate::{
@@ -1050,12 +1051,7 @@ fn write_token_value<'a>(
let only = groups[0];
// `name( ... )` covering the whole group:
// the parens govern breaking/indent; anything else gets the continuation indent.
let whole_call = only.len() > 2
&& matches!(&only[only.len() - 1].token, Token::RParen(_))
&& (matches!(&only[0].token, Token::LParen(_))
|| (matches!(&only[0].token, Token::Ident(_))
&& matches!(&only[1].token, Token::LParen(_))));
if whole_call {
if only.len() > 2 && is_one_paren_region(only) {
write_token_comma_group(only, top_level, f);
} else if top_level {
let body = format_with(move |f: &mut CssFormatter<'_, 'a>| {
@@ -1225,6 +1221,26 @@ fn write_token_comma_group_after<'a>(
filler.finish();
}
/// Whether `tokens` is one `( ... )` or `name( ... )` region:
/// the opening paren closes at the last token
/// (`--f(a) returns type(b)` ends with a `)` too, but is two regions).
fn is_one_paren_region(tokens: &[TokenWithSpan<'_>]) -> bool {
let open = match tokens {
[TokenWithSpan { token: Token::LParen(_), .. }, ..] => 0,
[
TokenWithSpan { token: Token::Ident(_), .. },
TokenWithSpan { token: Token::LParen(_), .. },
..,
] => 1,
_ => return false,
};
let mut depth = 0;
tokens[open..].iter().position(|t| {
depth += value::token_depth_delta(&t.token);
depth == 0
}) == Some(tokens.len() - open - 1)
}
/// Wrapper: a comma group is its own breakable group with indent.
/// Except when it contains paren regions,
/// which provide their own indentation (avoids double-indenting `name(...)` contents).
@@ -1234,12 +1250,7 @@ fn write_token_comma_group_grouped<'a>(
f: &mut CssFormatter<'_, 'a>,
) {
// A group that IS one call/paren region delegates breaking to the parens
let whole_region = !tokens.is_empty()
&& matches!(&tokens[tokens.len() - 1].token, Token::RParen(_))
&& (matches!(&tokens[0].token, Token::LParen(_))
|| (tokens.len() > 1
&& matches!(&tokens[0].token, Token::Ident(_))
&& matches!(&tokens[1].token, Token::LParen(_))));
let whole_region = is_one_paren_region(tokens);
// A `$key: (region)` pair also delegates to the parens
let kv_region = !whole_region
&& matches!(tokens.last().map(|t| &t.token), Some(Token::RParen(_)))
@@ -2159,57 +2170,81 @@ fn write_supports_condition<'a>(condition: &SupportsCondition<'a>, f: &mut CssFo
// A fill of keywords and parenthesized terms:
// a long condition breaks AFTER `and`/`or`, one indent in
// (`postcss-values` prints the params as a value group, so each word/paren is its own fill entry).
let condition_end = to_span(condition.span()).end;
let body = format_with(move |f: &mut CssFormatter<'_, 'a>| {
let mut filler = f.fill();
for kind in &condition.conditions {
let (keyword, in_parens) = match kind {
SupportsConditionKind::SupportsInParens(in_parens) => (None, in_parens),
SupportsConditionKind::And(and) => (Some(&and.keyword), &and.condition),
SupportsConditionKind::Or(or) => (Some(&or.keyword), &or.condition),
SupportsConditionKind::Not(not) => (Some(&not.keyword), &not.condition),
};
// A `//` among the entries breaks the condition
if let Some(keyword) = keyword {
let kw = format_with(move |f: &mut CssFormatter<'_, 'a>| {
let span = to_span(keyword.span());
value::write_with_comments(span, condition_end, f, |f| {
write_maybe_lowercase(f.context().source_text().text_for(&span), f);
});
});
filler.entry(&soft_line_break_or_space(), &kw);
}
let term = format_with(move |f: &mut CssFormatter<'_, 'a>| {
value::write_with_comments(to_span(in_parens.span()), condition_end, f, |f| {
write_supports_in_parens(in_parens, f);
});
let end = to_span(condition.span()).end;
let keyword = |keyword| format_with(move |f| write_supports_keyword(keyword, end, f));
let term = |in_parens| format_with(move |f| write_supports_term(in_parens, end, f));
let not = |not| format_with(move |f| write_supports_not(not, end, f));
match condition.conditions.as_slice() {
// A lone term is no fill entry, so its parens see what follows when deciding to open.
// It may carry hardlines of its own (`selector(\n :focus-visible // c\n)`) that must not be re-indented.
[SupportsConditionKind::SupportsInParens(in_parens)] => write!(f, group(&term(in_parens))),
[SupportsConditionKind::Not(n)] => write!(f, group(&not(n))),
conditions => {
let body = format_with(|f: &mut CssFormatter<'_, 'a>| {
let mut filler = f.fill();
for kind in conditions {
match kind {
SupportsConditionKind::SupportsInParens(in_parens) => {
filler.entry(&soft_line_break_or_space(), &term(in_parens));
}
SupportsConditionKind::And(SupportsAnd {
keyword: kw, condition, ..
})
| SupportsConditionKind::Or(SupportsOr {
keyword: kw, condition, ..
}) => {
filler.entry(&soft_line_break_or_space(), &keyword(kw));
filler.entry(&soft_line_break_or_space(), &term(condition));
}
SupportsConditionKind::Not(n) => {
filler.entry(&soft_line_break_or_space(), &not(n));
}
}
}
filler.finish();
});
filler.entry(&soft_line_break_or_space(), &term);
write!(f, group(&indent(&body)));
}
filler.finish();
});
// Only a multi-term condition gets the indent:
// a lone term may carry hardlines of its own (`selector(\n :focus-visible // c\n)`)
// that must not be re-indented.
if condition.conditions.len() > 1 {
write!(f, group(&indent(&body)));
} else {
write!(f, group(&body));
}
}
/// `and` / `or` / `not`, lowercased; a `//` after it breaks the condition.
fn write_supports_keyword<'a>(keyword: &Ident<'a>, end: u32, f: &mut CssFormatter<'_, 'a>) {
let span = to_span(keyword.span());
value::write_with_comments(span, end, f, |f| {
write_maybe_lowercase(f.context().source_text().text_for(&span), f);
});
}
/// `not` only ever leads its term, so it stays on the term's line.
fn write_supports_not<'a>(not: &SupportsNot<'a>, end: u32, f: &mut CssFormatter<'_, 'a>) {
write_supports_keyword(&not.keyword, end, f);
write!(f, space());
write_supports_term(&not.condition, end, f);
}
fn write_supports_term<'a>(
in_parens: &SupportsInParens<'a>,
end: u32,
f: &mut CssFormatter<'_, 'a>,
) {
value::write_with_comments(to_span(in_parens.span()), end, f, |f| {
write_supports_in_parens(in_parens, f);
});
}
fn write_supports_in_parens<'a>(in_parens: &SupportsInParens<'a>, f: &mut CssFormatter<'_, 'a>) {
let source = f.context().source_text();
match &in_parens.kind {
// An over-wide term opens its parens (Prettier's parenthesized value group)
SupportsInParensKind::SupportsCondition(condition) => {
write!(f, "(");
write_supports_condition(condition, f);
write!(f, ")");
let content = format_with(|f| write_supports_condition(condition, f));
write!(f, group(&format_args!("(", soft_block_indent(&content), ")")));
}
SupportsInParensKind::Feature(feature) => {
write!(f, "(");
statement::write_declaration(&feature.decl, f);
write!(f, ")");
let content = format_with(|f| statement::write_declaration(&feature.decl, f));
write!(f, group(&format_args!("(", soft_block_indent(&content), ")")));
}
SupportsInParensKind::Selector(list) => {
write!(f, "selector(");
+2 -2
View File
@@ -118,7 +118,7 @@ pub(super) fn top_level_value_breaks_hard<'a>(
.iter_before(value_span.end)
.any(|c| c.span.start >= value_span.start);
has_comments
|| elements.iter().enumerate().any(|(i, el)| {
|| elements.iter().any(|el| {
let group = match el {
ComponentValue::SassList(inner) if inner.comma_spans.is_none() => {
&inner.elements[..]
@@ -128,7 +128,7 @@ pub(super) fn top_level_value_breaks_hard<'a>(
}
other => std::slice::from_ref(other),
};
value::comma_group_is_multi(group, i == 0)
value::comma_group_is_multi(group)
})
}
+54 -60
View File
@@ -26,8 +26,8 @@ use oxc_css_parser::{
use oxc_formatter_core::{
Buffer, SourceText, arena_cow_str,
builders::{
empty_line, group, hard_line_break, if_group_breaks, indent, soft_line_break,
soft_line_break_or_space, space, text, token,
empty_line, group, hard_line_break, if_group_breaks, indent, soft_block_indent,
soft_line_break, soft_line_break_or_space, space, text, token,
},
format_args,
spec::{format_trimmed_number, normalize_string},
@@ -574,29 +574,19 @@ pub(super) fn write_declaration_value<'a>(
let has_comments =
f.context().comments().iter_before(value_end).any(|c| c.span.start >= value_start);
let force_hard_line = !ctx.decl_prop.is_some_and(|p| p.starts_with("--"))
&& (groups.iter().enumerate().any(|(i, (g, _))| comma_group_is_multi(g, i == 0))
|| has_comments);
&& (groups.iter().any(|(g, _)| comma_group_is_multi(g)) || has_comments);
write_value_groups(&groups, ctx, force_hard_line, false, f);
}
/// Does this comma group count as a `value-comma_group` for Prettier's `shouldBreakList`?
/// Multi-element groups do; so does a single ident with a leading `-` in non-initial position,
/// which postcss-values splits into an operator + word
/// (`Arial, -apple-system` breaks the list while `-apple-system, Arial` does not).
pub(super) fn comma_group_is_multi(group: &[ComponentValue<'_>], is_first: bool) -> bool {
if group.len() > 1 {
return true;
}
/// Multi-element groups do.
/// A signed item (`Arial, -apple-system`, `0, -1px`) does not, though postcss-values splits it into an operator + word
/// past the first position (DIVERGENCES.md#signed-value-resplit).
pub(super) fn comma_group_is_multi(group: &[ComponentValue<'_>]) -> bool {
// Less `~'...'` lexes as TWO postcss-values nodes (`~` word + string),
// so it is a real `value-comma_group` in ANY position.
if matches!(group.first(), Some(ComponentValue::LessEscapedStr(_))) {
return true;
}
!is_first
&& matches!(group.first(),
Some(ComponentValue::InterpolableIdent(InterpolableIdent::Literal(id)))
if id.raw.starts_with('-') && !id.raw.starts_with("--"))
group.len() > 1 || matches!(group.first(), Some(ComponentValue::LessEscapedStr(_)))
}
/// A group's separator comma:
@@ -804,12 +794,15 @@ pub(super) fn write_value_groups<'a>(
} else {
// Prettier-fill the comments with the group they lead.
// Simulated with static widths:
// the last comment stays on the line when the group's first chunk fits after it
// (its glued run, the comma too when that is the whole group);
// the group's fit must NOT include its declaration tail, which our entry would.
let width = u32::from(f.options().line_width.value());
let group_w =
group_values.first().zip(group_values.last()).map_or(0, |(first, last)| {
to_span(last.span()).end - to_span(first.span()).start
}) + u32::from(!is_last);
let source = f.context().source_text();
let chunk_len = run_end(group_values, 0, gctx, source);
let group_w = to_span(group_values[chunk_len - 1].span()).end
- to_span(group_values[0].span()).start
+ u32::from(!is_last && chunk_len == group_values.len());
let mut x = 4u32; // hardline indent under the value
for (k, &comment) in lead.iter().enumerate() {
x += comment.span.end - comment.span.start;
@@ -1177,16 +1170,7 @@ pub(super) fn write_comma_group<'a>(
sep = Separator::Hard;
}
}
// Merge runs of tight / non-breaking-space components into one fill entry
let mut run_end = i + 1;
while run_end < values.len()
&& matches!(
separator_between(values, run_end, ctx, source),
Separator::Tight | Separator::Word | Separator::Space
)
{
run_end += 1;
}
let run_end = run_end(values, i, ctx, source);
let run_start = i;
let run = &values[i..run_end];
let start = to_span(values[i].span()).start;
@@ -1319,6 +1303,23 @@ fn raw_token<'b, 'a>(value: &'b ComponentValue<'a>) -> Option<&'b Token<'a>> {
if let ComponentValue::TokenWithSpan(token) = value { Some(&token.token) } else { None }
}
/// The end of the run starting at `values[start]`: tight / non-breaking-space components merge into one fill entry.
fn run_end(
values: &[ComponentValue<'_>],
start: usize,
ctx: ValueContext<'_>,
source: SourceText<'_>,
) -> usize {
(start + 1..values.len())
.find(|&i| {
!matches!(
separator_between(values, i, ctx, source),
Separator::Tight | Separator::Word | Separator::Space
)
})
.unwrap_or(values.len())
}
/// Decides the separator BEFORE `values[i]` (i >= 1).
fn separator_between(
values: &[ComponentValue<'_>],
@@ -1405,7 +1406,8 @@ fn base_separator(values: &[ComponentValue<'_>], i: usize, ctx: ValueContext<'_>
if tight_rule && position_rule {
return Separator::Tight;
}
return Separator::Line;
// A spaced `/` glues to its left operand and breaks after (Prettier's math operator chunk)
return if is_solidus(curr) { Separator::Space } else { Separator::Line };
}
// Less lookups: `@var [@result]` loses the gap (`var [@lookup]` rule).
@@ -1531,7 +1533,7 @@ fn base_separator(values: &[ComponentValue<'_>], i: usize, ctx: ValueContext<'_>
};
if is_solidus_tok(curr) {
let require_space = wordish(values.get(i + 1)) || wordish(Some(prev));
return if gap_empty && !require_space { Separator::Tight } else { Separator::Line };
return if gap_empty && !require_space { Separator::Tight } else { Separator::Space };
}
if is_solidus_tok(prev) {
let require_space = wordish(Some(curr)) || wordish(values.get(i.wrapping_sub(2)));
@@ -1614,9 +1616,16 @@ pub(super) fn write_component_value<'a>(
write_number(&percentage.value, f);
write!(f, "%");
}
// The spacing around `/` prints as written, as in a declaration value
ComponentValue::Ratio(ratio) => {
write_number(&ratio.numerator, f);
if !is_glued(&ratio.numerator.span, &ratio.solidus_span) {
write!(f, space());
}
write!(f, "/");
if !is_glued(&ratio.solidus_span, &ratio.denominator.span) {
write!(f, space());
}
write_number(&ratio.denominator, f);
}
ComponentValue::HexColor(hex) => {
@@ -1657,11 +1666,7 @@ pub(super) fn write_component_value<'a>(
}
ComponentValue::Function(func) => write_function(func, ctx, f),
ComponentValue::Calc(calc) => write_calc(calc, ctx, f),
ComponentValue::CalcParenthesized(paren) => {
write!(f, "(");
write_component_value(&paren.expr, ctx, f);
write!(f, ")");
}
ComponentValue::CalcParenthesized(paren) => write_parenthesized(&paren.expr, ctx, f),
ComponentValue::SassMap(map) => scss::write_sass_map(map, ctx, f),
ComponentValue::SassList(list) => scss::write_sass_list(list, ctx, f),
ComponentValue::SassParenthesizedExpression(paren) => {
@@ -1828,7 +1833,7 @@ pub(super) fn write_component_value<'a>(
// `+`/`-` as a binary operator (see `write_less_binary_operation`).
ComponentValue::LessBinaryOperation(op) => write_less_binary_operation(op, ctx, f),
ComponentValue::LessParenthesizedOperation(paren) => {
write_less_parenthesized_operation(paren, ctx, f);
write_parenthesized(&paren.operation, ctx, f);
}
// A css-in-js placeholder becomes a typed marker the host replaces with `${expr}`
ComponentValue::Placeholder(placeholder) => {
@@ -2221,7 +2226,7 @@ fn write_less_binary_operation<'a>(
for piece in chunk {
match piece {
Piece::Operand(operand) => write_component_value(operand, ctx, f),
Piece::Paren(paren) => write_less_parenthesized_operation(paren, ctx, f),
Piece::Paren(paren) => write_parenthesized(&paren.operation, ctx, f),
Piece::Op(op) => write!(f, token(op)),
Piece::Space => write!(f, " "),
}
@@ -2252,32 +2257,21 @@ fn write_less_binary_operation<'a>(
write!(f, group(&indent(&body)));
}
/// A Less parenthesized operation (`(@a - @b)`):
/// A parenthesized operand (Less operation `(@a - @b)`, `calc()` sub-expression):
/// its own group, so when it breaks the `(` / `)` land on their own lines
/// with the inner operation indented one level (Prettier's `printParenthesizedValueGroup`).
/// with the content indented one level (Prettier's `printParenthesizedValueGroup`).
/// When it fits, it stays inline (`(@a - @b)`).
fn write_less_parenthesized_operation<'a>(
paren: &LessParenthesizedOperation<'a>,
fn write_parenthesized<'a>(
value: &ComponentValue<'a>,
ctx: ValueContext<'a>,
f: &mut CssFormatter<'_, 'a>,
) {
let content = format_with(move |f| write_component_value(value, ctx, f));
if ctx.no_break {
write!(f, "(");
write_component_value(&paren.operation, ctx, f);
write!(f, ")");
return;
write!(f, ["(", content, ")"]);
} else {
write!(f, [text("("), group(&soft_block_indent(&content)), text(")")]);
}
let body = format_with(move |f: &mut CssFormatter<'_, 'a>| {
write!(
f,
indent(&format_with(move |f: &mut CssFormatter<'_, 'a>| {
write!(f, soft_line_break());
write_component_value(&paren.operation, ctx, f);
}))
);
write!(f, soft_line_break());
});
write!(f, [text("("), group(&body), text(")")]);
}
/// Function call: `name(` + args + `)`.
@@ -0,0 +1,6 @@
@function --transparent(--color type(<color>), --alpha type(<number>)) returns type(<color>) {
result: oklch(from var(--color) l c h / var(--alpha));
}
@function --transparent-color-with-a-long-name(--color type(<color>), --alpha type(<number>)) {
result: oklch(from var(--color) l c h / var(--alpha));
}
@@ -0,0 +1,37 @@
---
source: crates/oxc_formatter_css/tests/fixtures/mod.rs
---
==================== Input ====================
@function --transparent(--color type(<color>), --alpha type(<number>)) returns type(<color>) {
result: oklch(from var(--color) l c h / var(--alpha));
}
@function --transparent-color-with-a-long-name(--color type(<color>), --alpha type(<number>)) {
result: oklch(from var(--color) l c h / var(--alpha));
}
==================== Output ====================
------------------
{ printWidth: 80 }
------------------
@function --transparent(--color type(<color>), --alpha type(<number>)) returns
type(<color>) {
result: oklch(from var(--color) l c h / var(--alpha));
}
@function --transparent-color-with-a-long-name(
--color type(<color>),
--alpha type(<number>)
) {
result: oklch(from var(--color) l c h / var(--alpha));
}
-------------------
{ printWidth: 100 }
-------------------
@function --transparent(--color type(<color>), --alpha type(<number>)) returns type(<color>) {
result: oklch(from var(--color) l c h / var(--alpha));
}
@function --transparent-color-with-a-long-name(--color type(<color>), --alpha type(<number>)) {
result: oklch(from var(--color) l c h / var(--alpha));
}
===================== End =====================
@@ -27,3 +27,5 @@ a {
position: sticky;
}
}
@supports (transform-style: preserve-3d) or ((-moz-transform-style: preserve-3d) or (-webkit-transform-style: preserve-3d)) {}
@supports not (background-image: light-dark(url("light.png"), url("dark.png"))) {}
@@ -31,6 +31,8 @@ a {
position: sticky;
}
}
@supports (transform-style: preserve-3d) or ((-moz-transform-style: preserve-3d) or (-webkit-transform-style: preserve-3d)) {}
@supports not (background-image: light-dark(url("light.png"), url("dark.png"))) {}
==================== Output ====================
------------------
@@ -75,6 +77,16 @@ a {
position: sticky;
}
}
@supports (transform-style: preserve-3d) or
(
(-moz-transform-style: preserve-3d) or
(-webkit-transform-style: preserve-3d)
) {
}
@supports not (
background-image: light-dark(url("light.png"), url("dark.png"))
) {
}
-------------------
{ printWidth: 100 }
@@ -117,5 +129,10 @@ a {
position: sticky;
}
}
@supports (transform-style: preserve-3d) or
((-moz-transform-style: preserve-3d) or (-webkit-transform-style: preserve-3d)) {
}
@supports not (background-image: light-dark(url("light.png"), url("dark.png"))) {
}
===================== End =====================
@@ -15,3 +15,7 @@
height: calc(50% + ((100% - 20px)));
min-height: calc(((10vh)) + calc((5vh)));
}
/* an over-wide operand opens its parens */
.c {
opacity: calc((progress(var(--container-width), var(--custom-min-width), var(--custom-max-width)) / 2) + 0.5);
}
@@ -19,6 +19,10 @@ source: crates/oxc_formatter_css/tests/fixtures/mod.rs
height: calc(50% + ((100% - 20px)));
min-height: calc(((10vh)) + calc((5vh)));
}
/* an over-wide operand opens its parens */
.c {
opacity: calc((progress(var(--container-width), var(--custom-min-width), var(--custom-max-width)) / 2) + 0.5);
}
==================== Output ====================
------------------
@@ -45,6 +49,20 @@ source: crates/oxc_formatter_css/tests/fixtures/mod.rs
height: calc(50% + ((100% - 20px)));
min-height: calc(((10vh)) + calc((5vh)));
}
/* an over-wide operand opens its parens */
.c {
opacity: calc(
(
progress(
var(--container-width),
var(--custom-min-width),
var(--custom-max-width)
) /
2
) +
0.5
);
}
-------------------
{ printWidth: 100 }
@@ -67,5 +85,11 @@ source: crates/oxc_formatter_css/tests/fixtures/mod.rs
height: calc(50% + ((100% - 20px)));
min-height: calc(((10vh)) + calc((5vh)));
}
/* an over-wide operand opens its parens */
.c {
opacity: calc(
(progress(var(--container-width), var(--custom-min-width), var(--custom-max-width)) / 2) + 0.5
);
}
===================== End =====================
@@ -1,11 +1,13 @@
/*
* Break-point in an over-wide math-y value run: our core fill (biome semantics)
* breaks at the last fitting SEPARATOR (before `/ 2`).
* DIVERGES from Prettier (DIVERGENCES.md#fill-break-position),
* whose fill fit-check breaks INSIDE the wide chunk (after `+`).
* Break-point in an over-wide math-y value run:
* a spaced `/` glues to its left operand and the fill breaks after it (Prettier's math operator chunk),
* in the token soup and in a typed value alike.
*/
.SearchBox {
.inner {
margin-left: sg-layout-width(logo-shopify) / 2 * -1 + sg-offset-x(page-nav) / 2;
}
}
a {
border-image: aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa 30 fill / 30px / 30px space;
}
@@ -3,47 +3,54 @@ source: crates/oxc_formatter_css/tests/fixtures/mod.rs
---
==================== Input ====================
/*
* Break-point in an over-wide math-y value run: our core fill (biome semantics)
* breaks at the last fitting SEPARATOR (before `/ 2`).
* DIVERGES from Prettier (DIVERGENCES.md#fill-break-position),
* whose fill fit-check breaks INSIDE the wide chunk (after `+`).
* Break-point in an over-wide math-y value run:
* a spaced `/` glues to its left operand and the fill breaks after it (Prettier's math operator chunk),
* in the token soup and in a typed value alike.
*/
.SearchBox {
.inner {
margin-left: sg-layout-width(logo-shopify) / 2 * -1 + sg-offset-x(page-nav) / 2;
}
}
a {
border-image: aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa 30 fill / 30px / 30px space;
}
==================== Output ====================
------------------
{ printWidth: 80 }
------------------
/*
* Break-point in an over-wide math-y value run: our core fill (biome semantics)
* breaks at the last fitting SEPARATOR (before `/ 2`).
* DIVERGES from Prettier (DIVERGENCES.md#fill-break-position),
* whose fill fit-check breaks INSIDE the wide chunk (after `+`).
* Break-point in an over-wide math-y value run:
* a spaced `/` glues to its left operand and the fill breaks after it (Prettier's math operator chunk),
* in the token soup and in a typed value alike.
*/
.SearchBox {
.inner {
margin-left: sg-layout-width(logo-shopify) / 2 * -1 + sg-offset-x(page-nav)
/ 2;
margin-left: sg-layout-width(logo-shopify) / 2 * -1 +
sg-offset-x(page-nav) / 2;
}
}
a {
border-image: aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa 30 fill /
30px / 30px space;
}
-------------------
{ printWidth: 100 }
-------------------
/*
* Break-point in an over-wide math-y value run: our core fill (biome semantics)
* breaks at the last fitting SEPARATOR (before `/ 2`).
* DIVERGES from Prettier (DIVERGENCES.md#fill-break-position),
* whose fill fit-check breaks INSIDE the wide chunk (after `+`).
* Break-point in an over-wide math-y value run:
* a spaced `/` glues to its left operand and the fill breaks after it (Prettier's math operator chunk),
* in the token soup and in a typed value alike.
*/
.SearchBox {
.inner {
margin-left: sg-layout-width(logo-shopify) / 2 * -1 + sg-offset-x(page-nav) / 2;
}
}
a {
border-image: aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa 30 fill / 30px / 30px space;
}
===================== End =====================
@@ -0,0 +1,3 @@
@media (aspect-ratio > 16 / 9) {}
@media (aspect-ratio: 16/9) {}
@media (16/ 9 < aspect-ratio < 21 / 9) {}
@@ -0,0 +1,30 @@
---
source: crates/oxc_formatter_css/tests/fixtures/mod.rs
---
==================== Input ====================
@media (aspect-ratio > 16 / 9) {}
@media (aspect-ratio: 16/9) {}
@media (16/ 9 < aspect-ratio < 21 / 9) {}
==================== Output ====================
------------------
{ printWidth: 80 }
------------------
@media (aspect-ratio > 16 / 9) {
}
@media (aspect-ratio: 16/9) {
}
@media (16/ 9 < aspect-ratio < 21 / 9) {
}
-------------------
{ printWidth: 100 }
-------------------
@media (aspect-ratio > 16 / 9) {
}
@media (aspect-ratio: 16/9) {
}
@media (16/ 9 < aspect-ratio < 21 / 9) {
}
===================== End =====================
@@ -93,12 +93,7 @@ $raw-paren: (
/* multi-value lists in $var declarations break one per line */
$fontFamily:
"Lato",
-apple-system,
"Helvetica Neue",
Helvetica,
Arial,
sans-serif;
"Lato", -apple-system, "Helvetica Neue", Helvetica, Arial, sans-serif;
-------------------
{ printWidth: 100 }
@@ -145,12 +140,6 @@ $raw-paren: (
}
/* multi-value lists in $var declarations break one per line */
$fontFamily:
"Lato",
-apple-system,
"Helvetica Neue",
Helvetica,
Arial,
sans-serif;
$fontFamily: "Lato", -apple-system, "Helvetica Neue", Helvetica, Arial, sans-serif;
===================== End =====================
@@ -0,0 +1,9 @@
/* A signed item past the first position prints like an unsigned one (DIVERGENCES.md#signed-value-resplit):
it does not break the list, and it does not glue to the word before it. */
a {
font-family: Arial, -apple-system;
font-family: -apple-system, Arial;
-webkit-mask-position-x: 50px, 25%, -3em;
-webkit-mask-position-x: 50px, 25%, 3em;
background: url("/shared-assets/images/examples/web-animations/cat_sprite.png") -600px 0 no-repeat;
}
@@ -0,0 +1,43 @@
---
source: crates/oxc_formatter_css/tests/fixtures/mod.rs
---
==================== Input ====================
/* A signed item past the first position prints like an unsigned one (DIVERGENCES.md#signed-value-resplit):
it does not break the list, and it does not glue to the word before it. */
a {
font-family: Arial, -apple-system;
font-family: -apple-system, Arial;
-webkit-mask-position-x: 50px, 25%, -3em;
-webkit-mask-position-x: 50px, 25%, 3em;
background: url("/shared-assets/images/examples/web-animations/cat_sprite.png") -600px 0 no-repeat;
}
==================== Output ====================
------------------
{ printWidth: 80 }
------------------
/* A signed item past the first position prints like an unsigned one (DIVERGENCES.md#signed-value-resplit):
it does not break the list, and it does not glue to the word before it. */
a {
font-family: Arial, -apple-system;
font-family: -apple-system, Arial;
-webkit-mask-position-x: 50px, 25%, -3em;
-webkit-mask-position-x: 50px, 25%, 3em;
background: url("/shared-assets/images/examples/web-animations/cat_sprite.png")
-600px 0 no-repeat;
}
-------------------
{ printWidth: 100 }
-------------------
/* A signed item past the first position prints like an unsigned one (DIVERGENCES.md#signed-value-resplit):
it does not break the list, and it does not glue to the word before it. */
a {
font-family: Arial, -apple-system;
font-family: -apple-system, Arial;
-webkit-mask-position-x: 50px, 25%, -3em;
-webkit-mask-position-x: 50px, 25%, 3em;
background: url("/shared-assets/images/examples/web-animations/cat_sprite.png") -600px 0 no-repeat;
}
===================== End =====================
@@ -0,0 +1,7 @@
/* A comment leading a list item stays on its line when the item's first chunk fits after it */
a {
mask:
url("masks.svg#star") left / 16px repeat-y,
/* 16px-wide mask on the left side */ url("masks.svg#circle") right / 16px
repeat-y; /* 16px-wide mask against right side */
}
@@ -0,0 +1,35 @@
---
source: crates/oxc_formatter_css/tests/fixtures/mod.rs
---
==================== Input ====================
/* A comment leading a list item stays on its line when the item's first chunk fits after it */
a {
mask:
url("masks.svg#star") left / 16px repeat-y,
/* 16px-wide mask on the left side */ url("masks.svg#circle") right / 16px
repeat-y; /* 16px-wide mask against right side */
}
==================== Output ====================
------------------
{ printWidth: 80 }
------------------
/* A comment leading a list item stays on its line when the item's first chunk fits after it */
a {
mask:
url("masks.svg#star") left / 16px repeat-y,
/* 16px-wide mask on the left side */ url("masks.svg#circle") right / 16px
repeat-y; /* 16px-wide mask against right side */
}
-------------------
{ printWidth: 100 }
-------------------
/* A comment leading a list item stays on its line when the item's first chunk fits after it */
a {
mask:
url("masks.svg#star") left / 16px repeat-y,
/* 16px-wide mask on the left side */ url("masks.svg#circle") right / 16px repeat-y; /* 16px-wide mask against right side */
}
===================== End =====================
@@ -0,0 +1,9 @@
// Break-point in a math-y value run: Prettier breaks at an earlier separator than our core fill
// (DIVERGENCES.md#fill-break-position).
.a {
.b {
.c {
height: calc(#{$calc-application-viewport-height} - #{$mr-sticky-header-height} - var(--mr-review-bar-height));
}
}
}
@@ -0,0 +1,48 @@
---
source: crates/oxc_formatter_css/tests/fixtures/mod.rs
---
==================== Input ====================
// Break-point in a math-y value run: Prettier breaks at an earlier separator than our core fill
// (DIVERGENCES.md#fill-break-position).
.a {
.b {
.c {
height: calc(#{$calc-application-viewport-height} - #{$mr-sticky-header-height} - var(--mr-review-bar-height));
}
}
}
==================== Output ====================
------------------
{ printWidth: 80 }
------------------
// Break-point in a math-y value run: Prettier breaks at an earlier separator than our core fill
// (DIVERGENCES.md#fill-break-position).
.a {
.b {
.c {
height: calc(
#{$calc-application-viewport-height} - #{$mr-sticky-header-height} -
var(--mr-review-bar-height)
);
}
}
}
-------------------
{ printWidth: 100 }
-------------------
// Break-point in a math-y value run: Prettier breaks at an earlier separator than our core fill
// (DIVERGENCES.md#fill-break-position).
.a {
.b {
.c {
height: calc(
#{$calc-application-viewport-height} - #{$mr-sticky-header-height} -
var(--mr-review-bar-height)
);
}
}
}
===================== End =====================
@@ -36,12 +36,7 @@ div {
border-left: 1px solid
mix($warningBackgroundColors, $warningBorderColors, 50%);
$fontFamily:
"Lato",
-apple-system,
"Helvetica Neue",
Helvetica,
Arial,
sans-serif;
"Lato", -apple-system, "Helvetica Neue", Helvetica, Arial, sans-serif;
}
$colours: (
"text": $light-100,
@@ -68,13 +63,7 @@ body {
-------------------
div {
border-left: 1px solid mix($warningBackgroundColors, $warningBorderColors, 50%);
$fontFamily:
"Lato",
-apple-system,
"Helvetica Neue",
Helvetica,
Arial,
sans-serif;
$fontFamily: "Lato", -apple-system, "Helvetica Neue", Helvetica, Arial, sans-serif;
}
$colours: (
"text": $light-100,
@@ -9,7 +9,7 @@ css compatibility: 142/151 (94.04%), 13 files skipped
| Spec path | Failed or Passed | Match ratio |
| :-------- | :--------------: | :---------: |
| css/comments/declaration.css | 💥 | 98.88% |
| css/fill-value/fill.css | 💥 | 96.36% |
| css/fill-value/fill.css | 💥 | 93.33% |
| css/parens/empty-lines.css | 💥 | 31.58% |
| css/parens/parens.css | 💥 | 93.12% |
| css/postcss-8-improment/test.css | 💥 | 88.24% |