Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Fix TypeError "Cannot read property 'syntax' of undefined" for nested control structures #4865

Closed
Buszmen opened this issue Jul 13, 2020 · 7 comments
Labels
status: ready to implement is ready to be worked on by someone syntax: sass relates to Sass and Sass-like syntax type: bug a problem with a feature or rule upstream relates to an upstream package

Comments

@Buszmen
Copy link

Buszmen commented Jul 13, 2020

Clearly describe the bug

A SASS code causes an error when linting:
Cannot read property 'syntax' of undefined

Which rule, if any, is the bug related to?

I don't think it's related to any specific rule.

What code is needed to reproduce the bug?

$sides: 'top' 'bottom' 'left' 'right'
$sizes: 'xxs' 'xs' 'sm' 'md' 'lg' 'xlg'

@each $side in $sides
  @each $size in $sizes
    .ac-padding-#{$side}-#{$size}
      padding-#{$side}: var(--spacing-#{$size})

What stylelint configuration is needed to reproduce the bug?

Default one?
It's even reproducible here:
Demo

Which version of stylelint are you using?

13.6.1

How are you running stylelint: CLI, PostCSS plugin, Node.js API?

stylelint src/**/*.sass

Does the bug relate to non-standard syntax (e.g. SCSS, Less etc.)?

I checked only SASS syntax

What did you expect to happen?

I expected to see linter report instead of an error.
It compiles fine if you put it here: https://www.sassmeister.com

What actually happened (e.g. what warnings or errors did you get)?

Got error:
Cannot read property 'syntax' of undefined
For me it's somewhere around
node_modules/stylelint/node_modules/postcss-syntax/patch-postcss.js:38:67

@mattxwang
Copy link
Member

mattxwang commented Jul 16, 2020

Hey @Buszmen, thank you for reporting the issue and following the template!

Did a bit of investigation and I think it's a problem with @each being evaluated as a just-CSS at-rule, instead of a SASS/SCSS control flow operator.

Here is a slightly simpler SASS example of a @each block, directly from the documentation:

$sizes: 40px, 50px, 80px

@each $size in $sizes
  .icon-#{$size}
    font-size: $size
    height: $size
    width: $size

The SASS error block for this message is a little cryptic.

However, if we switch to SCSS, with the same snippet (demo here)

$sizes: 40px, 50px, 80px;

@each $size in $sizes {
  .icon-#{$size} {
    font-size: $size;
    height: $size;
    width: $size;
  }
}

We can notice that we get the error

error Unexpected unknown at-rule "@each" (at-rule-no-unknown)

If we use a different snippet involving @for (demo here)

$base-color: #036;

@for $i from 1 through 3 {
  ul:nth-child(3n + #{$i}) {
    background-color: lighten($base-color, $i * 5%);
  }
}

We'll get the same error

error Unexpected unknown at-rule "@for" (at-rule-no-unknown)

Now, I'm not too familiar with the internals of stylelint, but my theory is that these SCSS/SASS control flow operators are being interpreted as at rules, which is causing the problem.

Looking at at-rule-no-unknown's check:

if (postcss.vendor.prefix(name) || keywordSets.atRules.has(name.toLowerCase())) {
	return;
}

We don't do any checks for SASS/SCSS control flow operators. And, if I add @each to ignoreAtRules, like in this modified SCSS demo, the problem disappears. The subsequent SASS errors probably have to do with the unfamiliar control flow syntax.

Not sure exactly how to solve this problem, since I'm not sure if just using ignoreAtRules works (the entire structure probably needs to be parsed differently) - and I could be completely wrong about everything here haha. If somebody from @stylelint/core could weigh-in, that'd be great 😄

@mattxwang mattxwang added status: needs investigation triage needs further investigation syntax: sass relates to Sass and Sass-like syntax syntax: scss relates to SCSS and SCSS-like syntax type: bug a problem with a feature or rule labels Jul 17, 2020
@Buszmen
Copy link
Author

Buszmen commented Aug 24, 2020

My colleague discovered some possible workaround.
If we modify my example to this:

$sides: 'top' 'bottom' 'left' 'right'
$sizes: 'xxs' 'xs' 'sm' 'md' 'lg' 'xlg'

@each $side in $sides
  @each $size in $sizes
    .ac-padding-#{$side}-#{$size}
      padding-#{$side}: var(--spacing-#{$size})

// Magic comment that makes all problems go away

We now have a different error message:
Cannot read property 'start' of undefined
Then, we add some more scope:

$sides: 'top' 'bottom' 'left' 'right'
$sizes: 'xxs' 'xs' 'sm' 'md' 'lg' 'xlg'

div
  @each $side in $sides
    @each $size in $sizes
      .ac-padding-#{$side}-#{$size}
        padding-#{$side}: var(--spacing-#{$size})

// Magic comment that makes all problems go away

We are no getting proper linter error about no-eol-whitespace, so if we remove this rule (I didn't check what's causing it) - it's all ok :)
Demo with workaround

@rovadi
Copy link

rovadi commented Oct 30, 2020

Hey @Buszmen , I have encountered the same error, the problem is due to a postcss bug that doesn't know how to interpret some sass flow control rules in this case the @each, but this error also happens with media queries.
I recommend the following solution:

$sides: 'top' 'bottom' 'left' 'right'
$sizes: 'xxs' 'xs' 'sm' 'md' 'lg' 'xlg'

=mixin-name
	@each $side in $sides
	  @each $size in $sizes
	    .ac-padding-#{$side}-#{$size}
	      padding-#{$side}: var(--spacing-#{$size})

+mixin-name

As you can see I simply wrap the @each inside a @mixin, I know that it's not neccesary to do so but it's not an invalid thing to do because this is allowed by sass rules and at the end it's going to compile the result that you need without adding extra html tags or comments at the end of line, hope it helps.

@KonstantinKudelko
Copy link

Hey @Buszmen , I have encountered the same error, the problem is due to a postcss bug that doesn't know how to interpret some sass flow control rules in this case the @each, but this error also happens with media queries.
I recommend the following solution:

$sides: 'top' 'bottom' 'left' 'right'
$sizes: 'xxs' 'xs' 'sm' 'md' 'lg' 'xlg'

=mixin-name
	@each $side in $sides
	  @each $size in $sizes
	    .ac-padding-#{$side}-#{$size}
	      padding-#{$side}: var(--spacing-#{$size})

+mixin-name

As you can see I simply wrap the @each inside a @mixin, I know that it's not neccesary to do so but it's not an invalid thing to do because this is allowed by sass rules and at the end it's going to compile the result that you need without adding extra html tags or comments at the end of line, hope it helps.

Do you suggest wrap each media query by mixin name too?

mktcode added a commit to alo9507/legacy-octobay-app that referenced this issue Feb 23, 2021
@thnee
Copy link

thnee commented May 24, 2021

So to summarize, the whole purpose of this project is to validate CSS with support for SCSS, yet it doesn't understand/handle basic loops that have been part of SCSS since before this project was started over 6 years ago, and nobody had any problem with this until now?

Or am I misunderstanding the situation here? Was this working at some point, and should this be considered a regression? Can any owners of this project confirm what is the status of this issue?

@jeddy3 jeddy3 added status: ready to implement is ready to be worked on by someone upstream relates to an upstream package and removed status: needs investigation triage needs further investigation syntax: scss relates to SCSS and SCSS-like syntax labels May 24, 2021
@jeddy3 jeddy3 changed the title Cannot read property 'syntax' of undefined Fix TypeError "Cannot readproperty 'syntax' of undefined" for nested control structures May 24, 2021
@jeddy3
Copy link
Member

jeddy3 commented May 24, 2021

stylelint (and the built-in rules and official configs) are geared towards validating CSS. However, stylelint can be extended by each community to support their preferred styling language. This distinction will be made clearer in the next major release (14.0.0) because:

  • styling flavours come and go, e.g. it seems whitespace SASS and Less are seldom used today whereas non-whitespace SCSS has a vibrant community and people willing to work to support it
  • stylelint is maintained by volunteers, and we need to focus our limited resources on supporting the growing CSS specifications

Can any owners of this project confirm what is the status of this issue?

@thnee I've updated to labels to reflect that this is an issue with the upstream syntax and specific to whitespace SASS syntax. I believe the postcss-sass syntax is maintained by a single contributor. Please consider volunteering your time upstream if you'd like to resolve this issue.

@Buszmen Buszmen changed the title Fix TypeError "Cannot readproperty 'syntax' of undefined" for nested control structures Fix TypeError "Cannot read property 'syntax' of undefined" for nested control structures May 24, 2021
@jeddy3
Copy link
Member

jeddy3 commented Jan 18, 2022

The syntax option was removed for the 14.0.0 release. (See the migration guide.)

Please consider opening an issue upstream and fixing the issue there as the syntax is no longer bundled by Stylelint.

@jeddy3 jeddy3 closed this as completed Jan 18, 2022
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
status: ready to implement is ready to be worked on by someone syntax: sass relates to Sass and Sass-like syntax type: bug a problem with a feature or rule upstream relates to an upstream package
Development

No branches or pull requests

6 participants