Skip to content

Commit

Permalink
show error messages for nested mixins which can not be extracted
Browse files Browse the repository at this point in the history
  • Loading branch information
jantimon committed Dec 13, 2023
1 parent e1ff511 commit 30f1984
Show file tree
Hide file tree
Showing 11 changed files with 501 additions and 198 deletions.
133 changes: 133 additions & 0 deletions packages/next-yak/loaders/__tests__/classifier.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,133 @@
import quasiClassifier from '../lib/quasiClassifier.cjs';
import { describe, it, expect } from "vitest";

describe('quasiClassifier', () => {
it('should classify empty quasi', () => {
expect(quasiClassifier('', [])).toEqual({
empty: true,
unknownSelector: false,
insideCssValue: false,
currentNestingScopes: [],
});
});
it("should recognize a comment as empty", () => {
expect(quasiClassifier("/* comment */", [])).toEqual({
empty: true,
unknownSelector: false,
insideCssValue: false,
currentNestingScopes: [],
});
});
it("should find incomplete css - unknownSelector", () => {
expect(quasiClassifier("{ color: blue;", [])).toEqual({
empty: false,
unknownSelector: true,
insideCssValue: false,
currentNestingScopes: [],
});
});
it("should find incomplete css - insideCssValue", () => {
expect(quasiClassifier("color: ", [
".foo"
])).toEqual({
empty: false,
unknownSelector: false,
insideCssValue: true,
currentNestingScopes: [".foo"],
});
});
it("should find incomplete css - insideCssValue after a media query", () => {
expect(quasiClassifier("} .foo { color: ", [
"@media (min-width: 640px)"
])).toEqual({
empty: false,
unknownSelector: false,
insideCssValue: true,
currentNestingScopes: [".foo"],
});
});
it("should find incomplete css - insideCssValue in a multi value", () => {
expect(quasiClassifier("} .foo { transition: 200ms ", [
"@media (min-width: 640px)"
])).toEqual({
empty: false,
unknownSelector: false,
insideCssValue: true,
currentNestingScopes: [".foo"],
});
});
it("should find nesting scopes", () => {
expect(quasiClassifier(`
.foo {
.bar {
@supports (display: grid) {
`, [
"@media (min-width: 640px)"
])).toEqual({
empty: false,
unknownSelector: false,
insideCssValue: false,
currentNestingScopes: [
"@media (min-width: 640px)",
".foo",
".bar",
"@supports (display: grid)",
],
});
});
it("should find nesting scopes with properties", () => {
expect(quasiClassifier(`
.foo {
color: purple;
.x {
color: green;
}
.bar {
color: orange;
@supports (display: grid) {
color: blue;
`, [
"@media (min-width: 640px)"
])).toEqual({
empty: false,
unknownSelector: false,
insideCssValue: false,
currentNestingScopes: [
"@media (min-width: 640px)",
".foo",
".bar",
"@supports (display: grid)",
],
});
});

it("should find nesting scopes with properties and closing nestings", () => {
expect(quasiClassifier(`
.foo {
/* }}}}} */
color: purple;
.x {
color: green;
}
.bar {
:before {
content: '{';
}
color: orange;
@supports (display: grid) {
color: blue;
}
}
`, [
"@media (min-width: 640px)"
])).toEqual({
empty: false,
unknownSelector: false,
insideCssValue: false,
currentNestingScopes: [
"@media (min-width: 640px)",
".foo",
],
});
});
});
148 changes: 100 additions & 48 deletions packages/next-yak/loaders/__tests__/tsloader.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -166,13 +166,12 @@ const FancyButton = styled(Button)\`
const FancyButton = styled(Button)(__styleYak.FancyButton_2);"
`);
});
});

it("should support attrs on intrinsic elements", async () => {
expect(
await tsloader.call(
loaderContext,
`
it("should support attrs on intrinsic elements", async () => {
expect(
await tsloader.call(
loaderContext,
`
import { styled } from "next-yak";
const headline = styled.input.attrs({
Expand All @@ -181,21 +180,21 @@ const headline = styled.input.attrs({
color: red;
\`;
`
)
).toMatchInlineSnapshot(`
)
).toMatchInlineSnapshot(`
"import { styled } from \\"next-yak\\";
import __styleYak from \\"./page.yak.module.css!=!./page?./page.yak.module.css\\";
const headline = styled.input.attrs({
type: \\"text\\"
})(__styleYak.headline_0);"
`);
});
});

it("should support attrs on wrapped elements", async () => {
expect(
await tsloader.call(
loaderContext,
`
it("should support attrs on wrapped elements", async () => {
expect(
await tsloader.call(
loaderContext,
`
import { styled } from "next-yak";
const headline = styled.input\`
Expand All @@ -208,22 +207,22 @@ const newHeadline = styled(headline).attrs({
color: black;
\`;
`
)
).toMatchInlineSnapshot(`
)
).toMatchInlineSnapshot(`
"import { styled } from \\"next-yak\\";
import __styleYak from \\"./page.yak.module.css!=!./page?./page.yak.module.css\\";
const headline = styled.input(__styleYak.headline_0);
const newHeadline = styled(headline).attrs({
type: \\"text\\"
})(__styleYak.newHeadline_1);"
`);
});
});

it("should support css variables with spaces", async () => {
expect(
await tsloader.call(
loaderContext,
`
it("should support css variables with spaces", async () => {
expect(
await tsloader.call(
loaderContext,
`
import styles from "./page.module.css";
import { css } from "next-yak";
import { easing } from "styleguide";
Expand All @@ -235,8 +234,8 @@ const headline = css\`
\${css\`color: blue\`}
\`;
`
)
).toMatchInlineSnapshot(`
)
).toMatchInlineSnapshot(`
"import styles from \\"./page.module.css\\";
import { css } from \\"next-yak\\";
import __styleYak from \\"./page.yak.module.css!=!./page?./page.yak.module.css\\";
Expand All @@ -250,13 +249,13 @@ const headline = css\`
}
});"
`);
});
});

it("should convert keyframes", async () => {
expect(
await tsloader.call(
loaderContext,
`
it("should convert keyframes", async () => {
expect(
await tsloader.call(
loaderContext,
`
import styles from "./page.module.css";
import { styled, keyframes } from "next-yak";
Expand All @@ -273,8 +272,8 @@ const FadeInButton = styled.button\`
animation: 1s \${fadeIn} ease-out;
\`
`
)
).toMatchInlineSnapshot(`
)
).toMatchInlineSnapshot(`
"import styles from \\"./page.module.css\\";
import { styled, keyframes } from \\"next-yak\\";
import __styleYak from \\"./page.yak.module.css!=!./page?./page.yak.module.css\\";
Expand All @@ -285,13 +284,13 @@ const FadeInButton = styled.button\`
}
});"
`);
});
});

it("should allow to target components", async () => {
expect(
await tsloader.call(
loaderContext,
`
it("should allow to target components", async () => {
expect(
await tsloader.call(
loaderContext,
`
import { styled, keyframes } from "next-yak";
const Link = styled.a\`
Expand All @@ -317,21 +316,21 @@ const Wrapper = styled.div\`
\`
`
)
).toMatchInlineSnapshot(`
)
).toMatchInlineSnapshot(`
"import { styled, keyframes } from \\"next-yak\\";
import __styleYak from \\"./page.yak.module.css!=!./page?./page.yak.module.css\\";
const Link = styled.a(__styleYak.Link_0);
const Icon = styled.svg(__styleYak.Icon_1);
const Wrapper = styled.div(__styleYak.Wrapper_2);"
`);
});
});

it("should allow to target components even if they don't have styles", async () => {
expect(
await tsloader.call(
loaderContext,
`
it("should allow to target components even if they don't have styles", async () => {
expect(
await tsloader.call(
loaderContext,
`
import { styled, keyframes } from "next-yak";
const Link = styled.a\`
Expand All @@ -347,12 +346,65 @@ const Wrapper = styled.div\`
\`
`
)
).toMatchInlineSnapshot(`
)
).toMatchInlineSnapshot(`
"import { styled, keyframes } from \\"next-yak\\";
import __styleYak from \\"./page.yak.module.css!=!./page?./page.yak.module.css\\";
const Link = styled.a();
const Icon = styled.svg(__styleYak.Icon_1);
const Wrapper = styled.div(__styleYak.Wrapper_2);"
`);
});

it("should show error when mixin is used in nested selector", async () => {
await expect(() =>
tsloader.call(
loaderContext,
`
import { styled, css } from "next-yak";
const bold = css\`
font-weight: bold;
\`
const Icon = styled.div\`
@media (min-width: 640px) {
.bar {
\${bold}
}
}
\`
`
)
).rejects.toThrowErrorMatchingInlineSnapshot(`
"/some/special/path/page.tsx: Expressions are not allowed inside nested selectors:
line 11: found \\"bold\\" inside \\"@media (min-width: 640px) { .bar {\\""
`);
});

it("should show error when mixin is used in nested selector inside a css", async () => {
await expect(() =>
tsloader.call(
loaderContext,
`
import { styled, css } from "next-yak";
const bold = css\`
font-weight: bold;
\`
const Icon = styled.div\`
@media (min-width: 640px) {
.bar {
\${() => css\`\${bold}\`}
}
}
\`
`
)
).rejects.toThrowErrorMatchingInlineSnapshot(`
"/some/special/path/page.tsx: Expressions are not allowed inside nested selectors:
line 11: found Expression inside \\"@media (min-width: 640px) { .bar {\\""
`);
});
});
Loading

0 comments on commit 30f1984

Please sign in to comment.