Closed michalpechnet closed 9 months ago
Thank you for the reporting and providing the repository!
The error comes from postcss-selector-parser
and not from postcss-styled-syntax
. We see it in the stack trace. Stylelint uses postcss-selector-parser
internally. Stylelint usually does a good job filtering non-standard selectors. But here it didn't catch incompatible syntax and we see an error.
There also issue with postcss-styled-syntax
. Because it parser rule selector incorrectly.
Given this example:
export const StyledContainer = styled.div`
${(props) => props.prop1 && ''}
${(props) => props.prop2 && css`box-shadow: none;`}
a {}
`
Parser produce a rule with selector ${(props) => props.prop2 &&\n css`box-shadow: none;`}\n\n a
instead of a
.
Need to find why this happens.
Issue is not reproducible if we don't have two interpolations one after another:
export const StyledContainer = styled.div`
${(props) => props.prop1 && ''}
display: flex;
${(props) => props.prop2 && css`box-shadow: none;`}
a {}
`
Hi @hudochenkov , thanks for reply. I also created issue in postcss-selector-parser
package. If there is any way, how can I help you or provide you more information, please let me know.
https://github.com/postcss/postcss-selector-parser/issues/285
It's not a problem with postcss-selector-parser
. postcss-styled-syntax
produces wrong AST, then stylelint
takes it and pass it postcss-selector-parser
.
Most of the time we have checks in Stylelint to ignore non-standard CSS syntax. Most likely one of rules (or some of them) don't have such check. I would suggest open an issue in Stylelint and close issue in postcss-selector-parser
.
When you open issue in Stylelint it would be nice if you could find which rules specifically are not ignoring non-standard CSS.
I recently received similar errors when upgrading to Prettier v3, which includes some different formatting heuristics for CSS-in-JS:
Original (unformatted) code
const styles = css`
${!isReviewingAnswer &&
`&:hover {
background-color: #ddd;
}`}
input {
position: absolute;
opacity: 0;
cursor: pointer;
}
`;
Problematic (formatted) code
const styles = css`
${!isReviewingAnswer &&
css`
&:hover {
background-color: #ddd;
}
`} input {
position: absolute;
opacity: 0;
cursor: pointer;
}
`;
My error with the formatted code was:
Error: Unexpected '!'. Escaping special characters with \ may help.
at /Users/k/p/courses/packages/quiz-multi-choice/index.tsx:216:3
at Root._error (/Users/k/p/project/node_modules/postcss-selector-parser/dist/parser.js:130:16)
at Root.error (/Users/k/p/project/node_modules/postcss-selector-parser/dist/selectors/root.js:30:19)
at Parser.error (/Users/k/p/project/node_modules/postcss-selector-parser/dist/parser.js:596:21)
at Parser.unexpected (/Users/k/p/project/node_modules/postcss-selector-parser/dist/parser.js:610:17)
at Parser.parse (/Users/k/p/project/node_modules/postcss-selector-parser/dist/parser.js:908:14)
at Parser.loop (/Users/k/p/project/node_modules/postcss-selector-parser/dist/parser.js:853:12)
at new Parser (/Users/k/p/project/node_modules/postcss-selector-parser/dist/parser.js:123:10)
at Processor._root (/Users/k/p/project/node_modules/postcss-selector-parser/dist/processor.js:40:18)
at Processor._runSync (/Users/k/p/project/node_modules/postcss-selector-parser/dist/processor.js:78:21)
at Processor.processSync (/Users/k/p/project/node_modules/postcss-selector-parser/dist/processor.js:164:23)
error Command failed with exit code 1.
The confusing part for me is that the !
from the error message was actually not the problem, but rather the lack of line break after the `}
.
Adding a semicolon after the `}
seems to resolve it for us:
Fixed (formatted) code
const styles = css`
${!isReviewingAnswer &&
css`
&:hover {
background-color: #ddd;
}
`};
input {
position: absolute;
opacity: 0;
cursor: pointer;
}
`;
Another failure case, this time not related to Prettier v3 formatting:
import { css } from '@emotion/react';
const breakpoint = '64em';
const chevronListItemStyles = css`
@media (min-width: ${breakpoint}) {
font-size: 10px;
}
`;
Error:
pnpm stylelint '**/*.{js,tsx}'
components/ChevronListItem/index.tsx
7:10 ✖ Unexpected invalid media query "(min-width: ${breakpoint})" media-query-no-invalid
import { css, SerializedStyles } from '@emotion/react';
function breakpoint(style: SerializedStyles) {
return css`
@media (min-width: 52em) {
${style}
}
`;
}
const chevronListItemStyles = css`
${breakpoint(css`
font-size: ${theme.fontSizes[1]}px;
`)}
`;
cc @43081j because it seems like you may be having similar errors in postcss-styled-components
:
Unexpected invalid media query "(min-width: ${breakpoint})" media-query-no-invalid
@karlhorky This should be reported to the Stylelint repository. media-query-no-invalid
Stylelint rule should ignore non-standard media queries.
@hudochenkov hm, are you sure? It seems like media-query-no-invalid
is specifically for the purpose of showing invalid CSS media queries?
media-query-no-invalid
Disallow invalid media queries.
Media queries must be grammatically valid according to the Media Queries Level 5 specification.
Or are you saying that this is grammatically valid?
I thought that postcss-styled-syntax
would somehow interpolate this value so that ${
and }
does not show up there... 🤔 But maybe I'm misunderstanding what postcss-styled-syntax
is intended to do in this case.
I'm sure. Core Stylelint rules are only targeted standard CSS syntax. @media (min-width: ${breakpoint}) {}
is not a standard CSS syntax. For such cases many rules ignore non-standard syntaxes to avoid false positives.
I thought that postcss-styled-syntax would somehow interpolate this value so that ${ and } does not show up there... 🤔 But maybe I'm misunderstanding what postcss-styled-syntax is intended to do in this case.
postcss-styled-syntax
does not compile or do any computations on the code. It's job is to take a string (source file) and transform it to PostCSS Abstract Syntax Tree (AST), so tool like Stylelint could work with it. For this example:
@media (min-width: ${breakpoint}) {
font-size: 10px;
}
AST would say that there is a media
at-rule with (min-width: ${breakpoint})
parameter. Then it's up to tool, which work with AST to decide what to do with that.
Parsing issue should be fixed in 0.6.0
.
Interesting, upgrading to postcss-styled-syntax@0.6.1
resolved some of the parsing issues, which is great 👍
However, the latest upgrade also broke this code pattern:
const StyledLink2 = styled('a', {
shouldForwardProp,
})/* css */ `
color: red;
`;
The css
comment outside of the template string (which is used to enable CSS syntax highlighting even with the multi-line styled()
function call) is causing a CssSyntaxError
:
pnpm stylelint '**/*.{js,tsx}'
components/Header/index.tsx
49:1 ✖ Unknown word CssSyntaxError
Removing the css
comment (which disables the syntax highlighting) causes the error to disappear:
const StyledLink2 = styled('a', {
shouldForwardProp,
})`
color: red;
`;
Use further interpolation to create the /* css */
comment:
const StyledLink2 = styled('a', {
shouldForwardProp,
})`
${/* css */ `
color: red;
`}
`;
Warning: If you use this method, verify that it is not altering your styling
Use an identity tagged template literal function (a no-op function) to enable the syntax highlighting:
// noop (identity) function to enable syntax highlighting for css
// https://github.com/hudochenkov/postcss-styled-syntax/issues/24#issuecomment-1872433249
const css = (
strings: TemplateStringsArray,
...expressions: unknown[]
): string => {
let result = strings[0]!;
for (let i = 1, l = strings.length; i < l; i++) {
result += expressions[i - 1];
result += strings[i];
}
return result;
};
const StyledLink2 = styled('a', {
shouldForwardProp,
})(css`
color: red;
`);
I'm still receiving the "Unexpected invalid media query" error with postcss-styled-syntax@0.6.1
too...
But maybe that should be reported to Stylelint instead as @hudochenkov mentioned.
However, the latest upgrade also broke this code pattern:
@karlhorky thank you for reporting! It is fixed in 0.6.2
. Peculiar use case, never seen a comment between a tag function and template literal :)
But maybe that should be reported to Stylelint instead
Yes, it should.
I try to migrate to latest version of
stylelint
v15
in my project usingstyled-components
. However I run into problem with parser.Description
Stylelint parser throws
Error: Expected a pseudo-class or pseudo-element
when parsingstyled-components
code.Error
Example repository
I've prepared example repository where you can reproduce this error. See https://github.com/michalpechnet/stylelint-styled-components-debug.
Steps to reproduce
yarn install
yarn lint:css
and see error