Skip to content

Can't find a way to use this plugin without breaking my @include statements and/or conditional logic and/or dollar variables #200

Open
@ArianeBouchardConformit

Description

order/properties-order breaks @include

At first, I was only using order/properties-order, like this:

{
   rules: {
            'order/properties-order': [
               STYLELINT_PROPERTIES_ORDER, // Details at the end of the issue
               {
                  emptyLineBeforeUnspecified: 'threshold',
                  emptyLineMinimumPropertyThreshold: 5,
                  severity: SEVERITIES.warning,
                  unspecified: 'ignore',
               },
            ],
   }
}

But doing that would make my @include statements always end up in the end of blocks, which would break my styles. For example, this:

$icon-size-min: sizes.$icon-medium;
$icon-size-proportional: 1.4em;
$loading-size: 20px;

.universal-button {
   align-items: center;
   justify-content: center;

   //#region Root element

   @include mixins.button-reset;
   @include mixins.link-reset;

   display: inline-flex;
   min-height: var(--universal-button-min-height, sizes.$interactive-min-height);
   min-width: var(--universal-button-min-width, sizes.$interactive-min-width);

   border: borders.$button-around-width solid currentColor;
   border-radius: border-radiuses.$button;

   line-height: line-heights.$button;

   cursor: pointer;
   transition:
      color durations.$standard-transition-duration,
      background-color durations.$standard-transition-duration,
      border-color durations.$standard-transition-duration,
      text-decoration-color durations.$standard-transition-duration
   ;

   // ... More styles

With my config, autofixing would yield this:

.universal-button {
   display: inline-flex;
   align-items: center;
   justify-content: center;

   min-width: var(--universal-button-min-width, sizes.$interactive-min-width);
   min-height: var(--universal-button-min-height, sizes.$interactive-min-height);

   border: borders.$button-around-width solid currentColor;
   border-radius: border-radiuses.$button;

   line-height: line-heights.$button;

   cursor: pointer;

   transition:
      color durations.$standard-transition-duration,
      background-color durations.$standard-transition-duration,
      border-color durations.$standard-transition-duration,
      text-decoration-color durations.$standard-transition-duration
   ;

   //#region Root element

   @include mixins.button-reset;
   @include mixins.link-reset;

   // ... More styles

My @include statements are in the bottom, so it applies style-resetting mixins AFTER my styles, undoing them. Not cool.

order/properties-order moves my dollar variables to the bottom

See this block of styles:

   height: sizes.$circular-gauge-size;
   width: sizes.$circular-gauge-size;

   position: relative;

   margin-left: paddings.$between-icon-and-text;
   border-radius: 50%;

   $clamped-proportion-percentage: calc(var(--clamped-proportion) * 100%);
   background-image: conic-gradient(var(--color-circular-gauge-primary-color) $clamped-proportion-percentage, var(--color-circular-gauge-secondary-color) 0);

Autofixing does this to it:

   width: sizes.$circular-gauge-size;
   height: sizes.$circular-gauge-size;

   position: relative;

   margin-left: paddings.$between-icon-and-text;
   border-radius: 50%;

   background-image: conic-gradient(var(--color-circular-gauge-primary-color) $clamped-proportion-percentage, var(--color-circular-gauge-secondary-color) 0);

   $clamped-proportion-percentage: calc(var(--clamped-proportion) * 100%);

Which gives me a Sass compilation error where the value in background-image is using undefined variable $clamped-proportion-percentage

Adding order/order makes conditional logic not work anymore

So I thought, I just need to set up order/order to tell @include statements and dollar variables to go on top.

I added a config for order/order:

{
   rules: {
            'order/order': [
               [
                  {
                     name: 'use',
                     type: 'at-rule',
                  },
                  {
                     name: 'function',
                     type: 'at-rule',
                  },
                  {
                     name: 'mixin',
                     type: 'at-rule',
                  },
                  'dollar-variables',
                  'custom-properties',
                  {
                     name: 'include',
                     type: 'at-rule',
                  },
                  'declarations',
                  {
                     name: 'media',
                     type: 'at-rule',
                  },
                  {
                     name: 'container',
                     type: 'at-rule',
                  },
                  {
                     name: 'content',
                     type: 'at-rule',
                  },
                  'rules',
                  {
                     name: 'return',
                     type: 'at-rule',
                  },
               ],
               {
                  severity: SEVERITIES.warning,
                  unspecified: 'ignore',
               },
            ],
   }
}

But some mixins got broken by this. For example:

@mixin define-width-for-pill-tag(
   $label-width: 30ch,

   $font-size: font-sizes.$pill-tag-compact,
   $pill-tag-padding-x: paddings.$pill-tag-compact-x,
   $pill-tag-part-padding-x: paddings.$pill-tag-part-compact-x,

   $has-icon: true,
   $icon-size: sizes.$icon-small,
) {
   $base-paddings: calc(
      ($pill-tag-part-padding-x + $pill-tag-padding-x)
      * 2
   );
   $space-for-icon: 0;

   @if $has-icon {
      $space-for-icon: calc($icon-size + paddings.$for-icon);
   }

   // Make 'ch' relative to the pill tag
   font-size: font-sizes.$pill-tag-compact;

   @include define-width(
      $value: calc(
         $base-paddings
         + $space-for-icon
         + $label-width
      ),
      $based-on: 'body',
   );
}

This is what autofixing does to it:

@mixin define-width-for-pill-tag(
   $label-width: 30ch,

   $font-size: font-sizes.$pill-tag-compact,
   $pill-tag-padding-x: paddings.$pill-tag-compact-x,
   $pill-tag-part-padding-x: paddings.$pill-tag-part-compact-x,

   $has-icon: true,
   $icon-size: sizes.$icon-small,
) {
   $base-paddings: calc(
      ($pill-tag-part-padding-x + $pill-tag-padding-x)
      * 2
   );
   $space-for-icon: 0;

   @include define-width(
      $value: calc(
         $base-paddings
         + $space-for-icon
         + $label-width
      ),
      $based-on: 'body',
   );

   // Make 'ch' relative to the pill tag
   font-size: font-sizes.$pill-tag-compact;

   @if $has-icon {
      $space-for-icon: calc($icon-size + paddings.$for-icon);
   }
}

define-width no longer has its variable value when I call it, so it breaks.

But thing is, I can't very well just decide to put @if/@else statements in order/order and ask them to always be before @include. Because conditional logic like that can go anywhere.

Please help

I need help. I don't really care about the order of at-rules. I just want my property reordering NOT to break where among the properties a mixin is included, or where conditional logic happens.

Can stylelint-order be set up to not break any Sass? How?

Technical info

package.json

      "stylelint": "^16.14.1",
      "stylelint-config-standard-scss": "^14.0.0",
      "stylelint-config-standard-vue": "^1.0.0",
      "stylelint-order": "^6.0.4",
      "stylelint-scss": "^6.11.0",

Config extends:

   extends: [ 'stylelint-config-standard-scss', 'stylelint-config-standard-vue/scss' ],

Full value for STYLELINT_PROPERTIES_ORDER

const EMPTY_LINE_BEFORE_DEFAULT = { emptyLineBefore: 'threshold' }

const STYLELINT_PROPERTIES_ORDER = [
   {
      /**
       * Compose rules from other selectors in CSS Modules.
       * @see https://github.com/css-modules/css-modules#composition
       */
      ...EMPTY_LINE_BEFORE_DEFAULT,
      properties: [ 'composes' ],
   },
   {
      // Must be first (unless using the above).
      ...EMPTY_LINE_BEFORE_DEFAULT,
      properties: [ 'all' ],
   },
   {
      // Pseudo-element-specific properties
      properties: [ 'content' ],
   },
   {
      // Properties that cause a fundamental change and fit better up here
      ...EMPTY_LINE_BEFORE_DEFAULT,
      properties: [ 'order', 'box-sizing' ],
   },
   {
      // Display, plus flexbox-related properties
      ...EMPTY_LINE_BEFORE_DEFAULT,
      properties: [
         'display',
         'flex',
         'flex-basis',
         'flex-direction',
         'flex-flow',
         'flex-grow',
         'flex-shrink',
         'flex-wrap',
         '-webkit-box-orient',
         'place-content',
         'place-items',
         'place-self',
         'align-content',
         'align-items',
         'align-self',
         'justify-content',
         'justify-items',
         'justify-self',
      ],
   },
   {
      // Grid layout.
      ...EMPTY_LINE_BEFORE_DEFAULT,
      properties: [
         'grid',
         'grid-area',
         'grid-template',
         'grid-template-areas',
         'grid-template-rows',
         'grid-template-columns',
         'grid-row',
         'grid-row-start',
         'grid-row-end',
         'grid-column',
         'grid-column-start',
         'grid-column-end',
         'grid-auto-rows',
         'grid-auto-columns',
         'grid-auto-flow',
         'grid-gap',
         'grid-row-gap',
         'grid-column-gap',
      ],
   },
   {
      // Box model: Sizing
      ...EMPTY_LINE_BEFORE_DEFAULT,
      properties: [
         'inline-size',
         'min-inline-size',
         'max-inline-size',
         'width',
         'min-width',
         'max-width',
         'block-size',
         'min-block-size',
         'max-block-size',
         'height',
         'min-height',
         'max-height',
         'aspect-ratio',
      ],
   },
   {
      // Box model: Float, overflow and clip
      ...EMPTY_LINE_BEFORE_DEFAULT,
      properties: [
         'float',
         'clear',
         'overflow',
         'overflow-block',
         'overflow-inline',
         'overflow-x',
         'overflow-y',
         '-webkit-overflow-scrolling',
         '-ms-overflow-x',
         '-ms-overflow-y',
         '-ms-overflow-style',
         'overscroll-behavior',
         'overscroll-behavior-inline',
         'overscroll-behavior-block',
         'overscroll-behavior-x',
         'overscroll-behavior-y',
         'clip',
         'clip-path',
      ],
   },
   {
      // Position.
      ...EMPTY_LINE_BEFORE_DEFAULT,
      properties: [
         'position',
         'inset',
         'inset-block',
         'inset-block-start',
         'inset-block-end',
         'inset-inline',
         'inset-inline-start',
         'inset-inline-end',
         'top',
         'right',
         'bottom',
         'left',
         'z-index',
      ],
   },
   {
      // Gap.
      ...EMPTY_LINE_BEFORE_DEFAULT,
      properties: [ 'gap', 'row-gap', 'column-gap' ],
   },
   {
      // Box model: Spacing
      ...EMPTY_LINE_BEFORE_DEFAULT,
      properties: [
         'margin',
         'margin-block',
         'margin-block-start',
         'margin-block-end',
         'margin-inline',
         'margin-inline-start',
         'margin-inline-end',
         'margin-top',
         'margin-right',
         'margin-bottom',
         'margin-left',
         'padding',
         'padding-block',
         'padding-block-start',
         'padding-block-end',
         'padding-inline',
         'padding-inline-start',
         'padding-inline-end',
         'padding-top',
         'padding-right',
         'padding-bottom',
         'padding-left',

         'border',
         'border-color',
         'border-style',
         'border-width',
         'border-block',
         'border-block-start',
         'border-block-start-color',
         'border-block-start-style',
         'border-block-start-width',
         'border-block-end',
         'border-block-end-color',
         'border-block-end-style',
         'border-block-end-width',
         'border-inline',
         'border-inline-start',
         'border-inline-start-color',
         'border-inline-start-style',
         'border-inline-start-width',
         'border-inline-end',
         'border-inline-end-color',
         'border-inline-end-style',
         'border-inline-end-width',
         'border-top',
         'border-top-color',
         'border-top-style',
         'border-top-width',
         'border-right',
         'border-right-color',
         'border-right-style',
         'border-right-width',
         'border-bottom',
         'border-bottom-color',
         'border-bottom-style',
         'border-bottom-width',
         'border-left',
         'border-left-color',
         'border-left-style',
         'border-left-width',
         'border-radius',
         'border-start-start-radius',
         'border-start-end-radius',
         'border-end-start-radius',
         'border-end-end-radius',
         'border-top-left-radius',
         'border-top-right-radius',
         'border-bottom-right-radius',
         'border-bottom-left-radius',
         'border-image',
         'border-image-source',
         'border-image-slice',
         'border-image-width',
         'border-image-outset',
         'border-image-repeat',
      ],
   },
   {
      /**
       * Columns and paged media
       * @see https://developer.mozilla.org/en-US/docs/Web/CSS/CSS_paged_media
       */
      ...EMPTY_LINE_BEFORE_DEFAULT,
      properties: [
         'columns',
         'column-count',
         'column-width',
         'break-before',
         'break-inside',
         'break-after',
         'orphans',
         'widows',
      ],
   },
   {
      // Typography.
      ...EMPTY_LINE_BEFORE_DEFAULT,
      properties: [
         'font',
         'font-family',
         'font-size',
         'font-variation-settings',
         'font-style',
         'font-weight',
         'font-feature-settings',
         'font-optical-sizing',
         'font-kerning',
         'font-variant',
         'font-variant-ligatures',
         'font-variant-caps',
         'font-variant-alternates',
         'font-variant-numeric',
         'font-variant-east-asian',
         'font-variant-position',
         'font-size-adjust',
         'font-stretch',
         'font-effect',
         'font-emphasize',
         'font-emphasize-position',
         'font-emphasize-style',
         '-webkit-font-smoothing',
         '-moz-osx-font-smoothing',
         'font-smooth',
         'hyphens',
         'line-height',
         'color',
         '-webkit-text-fill-color',
         '-webkit-text-stroke',
         '-webkit-text-stroke-width',
         '-webkit-text-stroke-color',
         'text-align',
         'text-align-last',
         'text-emphasis',
         'text-emphasis-color',
         'text-emphasis-style',
         'text-emphasis-position',
         'text-decoration',
         'text-decoration-line',
         'text-decoration-thickness',
         'text-decoration-style',
         'text-decoration-color',
         'text-underline-position',
         'text-underline-offset',
         'text-indent',
         'text-justify',
         'text-outline',
         'text-overflow',
         'text-overflow-ellipsis',
         'text-overflow-mode',
         '-webkit-line-clamp',
         'line-clamp',
         'text-shadow',
         'text-transform',
         'text-wrap',
         '-webkit-text-size-adjust',
         '-ms-text-size-adjust',
         'letter-spacing',
         'word-break',
         'word-spacing',
         'word-wrap', // Legacy name for `overflow-wrap`
         'overflow-wrap',
         'tab-size',
         'white-space',
         'vertical-align',

         'list-style',
         'list-style-position',
         'list-style-type',
         'list-style-image',

         'src',
         'font-display',
         'unicode-range',
         'size-adjust',
         'ascent-override',
         'descent-override',
         'line-gap-override',
      ],
   },
   {
      // Accessibility & Interactions.
      ...EMPTY_LINE_BEFORE_DEFAULT,
      properties: [
         'appearance',
         'accent-color',
         'color-scheme',
         'pointer-events',
         '-ms-touch-action',
         'touch-action',
         'cursor',
         'caret-color',
         'visibility',
         'zoom',

         'table-layout',
         'empty-cells',
         'caption-side',
         'border-spacing',
         'border-collapse',

         'quotes',
         'counter-reset',
         'counter-set',
         'counter-increment',
         'resize',

         'scroll-behaviour',
         'scroll-snap-type',
         'scroll-snap-align',
         'scroll-snap-stop',
         'scroll-padding',
         'scroll-padding-inline',
         'scroll-padding-inline-start',
         'scroll-padding-inline-end',
         'scroll-padding-block',
         'scroll-padding-block-start',
         'scroll-padding-block-end',
         'scroll-padding-top',
         'scroll-padding-right',
         'scroll-padding-bottom',
         'scroll-padding-left',
         'scroll-margin',
         'scroll-margin-inline',
         'scroll-margin-inline-start',
         'scroll-margin-inline-end',
         'scroll-margin-block',
         'scroll-margin-block-start',
         'scroll-margin-block-end',
         'scroll-margin-top',
         'scroll-margin-right',
         'scroll-margin-bottom',
         'scroll-margin-left',

         'scrollbar-color',
         'scrollbar-gutter',
         'scrollbar-width',

         'user-select',
         '-webkit-user-select',
         'nav-index',
         'nav-up',
         'nav-right',
         'nav-down',
         'nav-left',
      ],
   },
   {
      // Images and backgrounds
      ...EMPTY_LINE_BEFORE_DEFAULT,
      properties: [
         'object-fit',
         'object-position',
         '-ms-interpolation-mode',
         'image-orientation',
         'image-rendering',
         'image-resolution',

         'background',
         'background-color',
         'background-image',
         "-ms-filter:\\'progid:DXImageTransform.Microsoft.gradient",
         'filter:progid:DXImageTransform.Microsoft.gradient',
         'filter:progid:DXImageTransform.Microsoft.AlphaImageLoader',
         'filter',
         'background-repeat',
         'background-attachment',
         'background-position',
         'background-position-x',
         'background-position-y',
         'background-clip',
         'background-origin',
         'background-size',
         'background-blend-mode',
         'isolation',
         'backdrop-filter',
         'outline',
         'outline-width',
         'outline-style',
         'outline-color',
         'outline-offset',
         'box-shadow',
         'mix-blend-mode',
         'filter:progid:DXImageTransform.Microsoft.Alpha(Opacity',
         "-ms-filter:\\'progid:DXImageTransform.Microsoft.Alpha",
         'opacity',
      ],
   },
   {
      // Masking.
      ...EMPTY_LINE_BEFORE_DEFAULT,
      properties: [
         'mask-border',
         'mask-border-source',
         'mask-border-slice',
         'mask-border-width',
         'mask-border-outset',
         'mask-border-repeat',
         'mask-border-mode',
         'mask',
         'mask-image',
         'mask-mode',
         'mask-repeat',
         'mask-position',
         'mask-clip',
         'mask-origin',
         'mask-size',
         'mask-composite',
      ],
   },
   {
      // SVG Presentation Attributes.
      ...EMPTY_LINE_BEFORE_DEFAULT,
      properties: [
         'alignment-baseline',
         'baseline-shift',
         'dominant-baseline',
         'text-anchor',
         'word-spacing',
         'writing-mode',

         'fill',
         'fill-opacity',
         'fill-rule',
         'stroke',
         'stroke-dasharray',
         'stroke-dashoffset',
         'stroke-linecap',
         'stroke-linejoin',
         'stroke-miterlimit',
         'stroke-opacity',
         'stroke-width',

         'color-interpolation',
         'color-interpolation-filters',
         'color-profile',
         'color-rendering',
         'flood-color',
         'flood-opacity',
         'lighting-color',
         'marker-start',
         'marker-mid',
         'marker-end',
         'shape-rendering',
         'stop-color',
         'stop-opacity',
      ],
   },
   {
      // Transitions & Animation.
      ...EMPTY_LINE_BEFORE_DEFAULT,
      properties: [
         'transition',
         'transition-delay',
         'transition-timing-function',
         'transition-duration',
         'transition-property',
         'transform',
         'transform-origin',
         'rotate',
         'scale',
         'translate',
         'perspective',
         'perspective-origin',
         'animation',
         'animation-name',
         'animation-duration',
         'animation-play-state',
         'animation-timing-function',
         'animation-delay',
         'animation-iteration-count',
         'animation-direction',
         'will-change',
      ],
   },
]

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions