next-yak 0.0.22 → 0.0.23
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/loaders/__tests__/cssloader.test.ts +59 -59
- package/loaders/__tests__/getCssName.test.ts +83 -0
- package/loaders/__tests__/tsloader.test.ts +19 -19
- package/loaders/babel-yak-plugin.cjs +4 -1
- package/loaders/cssloader.cjs +3 -1
- package/loaders/lib/getCssName.cjs +131 -0
- package/package.json +1 -1
|
@@ -40,7 +40,7 @@ const headline = css\`
|
|
|
40
40
|
`
|
|
41
41
|
)
|
|
42
42
|
).toMatchInlineSnapshot(`
|
|
43
|
-
".
|
|
43
|
+
".yak_0 {
|
|
44
44
|
font-size: 2rem;
|
|
45
45
|
font-weight: bold;
|
|
46
46
|
color: red;
|
|
@@ -77,15 +77,15 @@ const headline = css\`
|
|
|
77
77
|
`
|
|
78
78
|
)
|
|
79
79
|
).toMatchInlineSnapshot(`
|
|
80
|
-
".
|
|
80
|
+
".yak_0 {
|
|
81
81
|
font-size: 2rem;
|
|
82
82
|
font-weight: bold;
|
|
83
83
|
color: red;
|
|
84
|
-
&:where(.
|
|
84
|
+
&:where(.yak_1) {
|
|
85
85
|
color: orange;
|
|
86
86
|
}
|
|
87
87
|
|
|
88
|
-
&:where(.
|
|
88
|
+
&:where(.yak_2) {
|
|
89
89
|
color: teal;
|
|
90
90
|
}
|
|
91
91
|
&:hover {
|
|
@@ -113,9 +113,9 @@ const headline = css\`
|
|
|
113
113
|
`
|
|
114
114
|
)
|
|
115
115
|
).toMatchInlineSnapshot(`
|
|
116
|
-
".
|
|
116
|
+
".yak_0 {
|
|
117
117
|
/* comment */
|
|
118
|
-
&:where(.
|
|
118
|
+
&:where(.yak_1) {
|
|
119
119
|
color: blue;
|
|
120
120
|
}
|
|
121
121
|
}"
|
|
@@ -138,12 +138,12 @@ const headline = css\`
|
|
|
138
138
|
`
|
|
139
139
|
)
|
|
140
140
|
).toMatchInlineSnapshot(`
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
141
|
+
".yak_0 {
|
|
142
|
+
&:hover {
|
|
143
|
+
color: var(--🦬18fi82j0);
|
|
144
|
+
}
|
|
145
|
+
}"
|
|
146
|
+
`);
|
|
147
147
|
});
|
|
148
148
|
|
|
149
149
|
it("should support attrs on intrinsic elements", async () => {
|
|
@@ -211,14 +211,14 @@ const headline = css\`
|
|
|
211
211
|
`
|
|
212
212
|
)
|
|
213
213
|
).toMatchInlineSnapshot(`
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
214
|
+
".yak_0 {
|
|
215
|
+
transition: color var(--🦬18fi82j0) var(--🦬18fi82j1);
|
|
216
|
+
display: block;
|
|
217
|
+
&:where(.yak_1) {
|
|
218
|
+
color: orange
|
|
219
|
+
}
|
|
220
|
+
}"
|
|
221
|
+
`);
|
|
222
222
|
});
|
|
223
223
|
|
|
224
224
|
it("should replace breakpoint references with actual media queries", async () => {
|
|
@@ -241,18 +241,18 @@ const headline = css\`
|
|
|
241
241
|
`
|
|
242
242
|
)
|
|
243
243
|
).toMatchInlineSnapshot(`
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
}
|
|
249
|
-
transition: color var(--🦬18fi82j0) var(--🦬18fi82j1);
|
|
250
|
-
display: block;
|
|
251
|
-
&:where(._yak_1) {
|
|
252
|
-
color: orange
|
|
244
|
+
".yak_0 {
|
|
245
|
+
color: blue;
|
|
246
|
+
@media (min-width: 640px) {
|
|
247
|
+
color: red;
|
|
253
248
|
}
|
|
254
|
-
|
|
255
|
-
|
|
249
|
+
transition: color var(--🦬18fi82j0) var(--🦬18fi82j1);
|
|
250
|
+
display: block;
|
|
251
|
+
&:where(.yak_1) {
|
|
252
|
+
color: orange
|
|
253
|
+
}
|
|
254
|
+
}"
|
|
255
|
+
`);
|
|
256
256
|
});
|
|
257
257
|
|
|
258
258
|
it("should replace breakpoint references with actual media queries from single quote imports", async () => {
|
|
@@ -275,18 +275,18 @@ const headline = css\`
|
|
|
275
275
|
`
|
|
276
276
|
)
|
|
277
277
|
).toMatchInlineSnapshot(`
|
|
278
|
-
|
|
279
|
-
|
|
280
|
-
|
|
281
|
-
|
|
282
|
-
}
|
|
283
|
-
transition: color var(--🦬18fi82j0) var(--🦬18fi82j1);
|
|
284
|
-
display: block;
|
|
285
|
-
&:where(._yak_1) {
|
|
286
|
-
color: orange
|
|
278
|
+
".yak_0 {
|
|
279
|
+
color: blue;
|
|
280
|
+
@media (min-width: 640px) {
|
|
281
|
+
color: red;
|
|
287
282
|
}
|
|
288
|
-
|
|
289
|
-
|
|
283
|
+
transition: color var(--🦬18fi82j0) var(--🦬18fi82j1);
|
|
284
|
+
display: block;
|
|
285
|
+
&:where(.yak_1) {
|
|
286
|
+
color: orange
|
|
287
|
+
}
|
|
288
|
+
}"
|
|
289
|
+
`);
|
|
290
290
|
});
|
|
291
291
|
|
|
292
292
|
it("should prevent double escaped chars", async () => {
|
|
@@ -311,16 +311,16 @@ const headline = css\`
|
|
|
311
311
|
`
|
|
312
312
|
)
|
|
313
313
|
).toMatchInlineSnapshot(`
|
|
314
|
-
|
|
315
|
-
|
|
316
|
-
|
|
317
|
-
|
|
318
|
-
|
|
319
|
-
|
|
320
|
-
|
|
321
|
-
|
|
322
|
-
|
|
323
|
-
|
|
314
|
+
".yak_0 {
|
|
315
|
+
:before {
|
|
316
|
+
content: \\"\\\\2022\\";
|
|
317
|
+
}
|
|
318
|
+
:after {
|
|
319
|
+
content: \\"\\\\2022\\";
|
|
320
|
+
}
|
|
321
|
+
content: \\"\\\\\\\\\\"
|
|
322
|
+
}"
|
|
323
|
+
`);
|
|
324
324
|
});
|
|
325
325
|
|
|
326
326
|
it("should convert keyframes", async () => {
|
|
@@ -481,16 +481,16 @@ const Component2 = styled.div\`
|
|
|
481
481
|
".Component {
|
|
482
482
|
background-color: red;
|
|
483
483
|
color: white;
|
|
484
|
-
&:where(.
|
|
484
|
+
&:where(.active_0) {
|
|
485
485
|
background-color: blue;
|
|
486
486
|
}
|
|
487
487
|
border: 1px solid black;
|
|
488
488
|
|
|
489
489
|
&:focus {
|
|
490
490
|
background-color: green;
|
|
491
|
-
&:where(.
|
|
491
|
+
&:where(.active_1) {
|
|
492
492
|
background-color: blue;
|
|
493
|
-
&:where(.
|
|
493
|
+
&:where(.active_2) {
|
|
494
494
|
background-color: brown;
|
|
495
495
|
}
|
|
496
496
|
}
|
|
@@ -535,17 +535,17 @@ const Component = styled.div\`
|
|
|
535
535
|
".Component {
|
|
536
536
|
background-color: red;
|
|
537
537
|
color: white;
|
|
538
|
-
&:where(.
|
|
538
|
+
&:where(.active_0) {
|
|
539
539
|
background-color: blue;
|
|
540
540
|
}
|
|
541
|
-
&:where(.
|
|
541
|
+
&:where(.not_active_1) {
|
|
542
542
|
background-color: var(--🦬18fi82j0);
|
|
543
543
|
}
|
|
544
544
|
border: 1px solid black;
|
|
545
|
-
&:where(.
|
|
545
|
+
&:where(.active_2) {
|
|
546
546
|
color: orange;
|
|
547
547
|
}
|
|
548
|
-
&:where(.
|
|
548
|
+
&:where(.not_active_3) {
|
|
549
549
|
transition: color var(--🦬18fi82j1) var(--🦬18fi82j2);
|
|
550
550
|
}
|
|
551
551
|
}"
|
|
@@ -0,0 +1,83 @@
|
|
|
1
|
+
import { parse, traverse } from "@babel/core";
|
|
2
|
+
import { NodePath } from "@babel/core";
|
|
3
|
+
import getCssName from "../lib/getCssName.cjs";
|
|
4
|
+
import type { TaggedTemplateExpression } from "@babel/types";
|
|
5
|
+
import { describe, it, expect } from "vitest";
|
|
6
|
+
|
|
7
|
+
function extractConditionsWithBabel(code: string) {
|
|
8
|
+
let result: string = "";
|
|
9
|
+
const ast = parse(code);
|
|
10
|
+
if (!ast) {
|
|
11
|
+
throw new Error("Could not parse code");
|
|
12
|
+
}
|
|
13
|
+
traverse(ast, {
|
|
14
|
+
TaggedTemplateExpression(path: NodePath<TaggedTemplateExpression>) {
|
|
15
|
+
if (path.node.tag.type === "Identifier" && path.node.tag.name === "css") {
|
|
16
|
+
result = getCssName(path);
|
|
17
|
+
}
|
|
18
|
+
},
|
|
19
|
+
});
|
|
20
|
+
return result;
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
describe("getCssName", () => {
|
|
24
|
+
it("should guess the css name from the condition of a logical expression", () => {
|
|
25
|
+
const code = `({$active}) => $active && css\`\``;
|
|
26
|
+
const cssName = extractConditionsWithBabel(code);
|
|
27
|
+
expect(cssName).toBe("active");
|
|
28
|
+
});
|
|
29
|
+
|
|
30
|
+
it("should guess the css name from the condition of a ternary expression", () => {
|
|
31
|
+
const code = `({$active}) => $active ? css\`\` : null`;
|
|
32
|
+
const cssName = extractConditionsWithBabel(code);
|
|
33
|
+
expect(cssName).toBe("active");
|
|
34
|
+
});
|
|
35
|
+
|
|
36
|
+
it("should guess the css name from the condition of a logical expression with negation", () => {
|
|
37
|
+
const code = `({$active}) => !$active && css\`\``;
|
|
38
|
+
const cssName = extractConditionsWithBabel(code);
|
|
39
|
+
expect(cssName).toBe("not_active");
|
|
40
|
+
});
|
|
41
|
+
|
|
42
|
+
it("should guess the css name from the condition of a ternary expression for the else case", () => {
|
|
43
|
+
const code = `({$active}) => $active ? null : css\`\``;
|
|
44
|
+
const cssName = extractConditionsWithBabel(code);
|
|
45
|
+
expect(cssName).toBe("not_active");
|
|
46
|
+
});
|
|
47
|
+
|
|
48
|
+
it("should guess the css name from the condition of a logical expression with multiple conditions", () => {
|
|
49
|
+
const code = `({$active, $visible}) => $active && $visible && css\`\``;
|
|
50
|
+
const cssName = extractConditionsWithBabel(code);
|
|
51
|
+
expect(cssName).toBe("active_and_visible");
|
|
52
|
+
});
|
|
53
|
+
|
|
54
|
+
it("should guess the css name from the condition of a ternary expression with multiple conditions", () => {
|
|
55
|
+
const code = `({$active, $visible}) => $active ? ($visible ? css\`\` : null) : null`;
|
|
56
|
+
const cssName = extractConditionsWithBabel(code);
|
|
57
|
+
expect(cssName).toBe("active_and_visible");
|
|
58
|
+
});
|
|
59
|
+
|
|
60
|
+
it("should guess the css name from the condition of a logical expression with negation and multiple conditions", () => {
|
|
61
|
+
const code = `({$active, $visible}) => !$active && $visible && css\`\``;
|
|
62
|
+
const cssName = extractConditionsWithBabel(code);
|
|
63
|
+
expect(cssName).toBe("not_active_and_visible");
|
|
64
|
+
});
|
|
65
|
+
|
|
66
|
+
it("should guess the css name from the condition of a ternary expression with negation and multiple conditions", () => {
|
|
67
|
+
const code = `({$active, $visible}) => !$active ? ($visible ? css\`\`: null) : null`;
|
|
68
|
+
const cssName = extractConditionsWithBabel(code);
|
|
69
|
+
expect(cssName).toBe("not_active_and_visible");
|
|
70
|
+
});
|
|
71
|
+
|
|
72
|
+
it("should guess the css name from the condition of a logical expression with negation and multiple conditions for the else case", () => {
|
|
73
|
+
const code = `({$active, $visible}) => $active && !$visible && css\`\``;
|
|
74
|
+
const cssName = extractConditionsWithBabel(code);
|
|
75
|
+
expect(cssName).toBe("active_and_not_visible");
|
|
76
|
+
});
|
|
77
|
+
|
|
78
|
+
it("should guess the css name from the condition of a ternary expression with negation and multiple conditions for the else case", () => {
|
|
79
|
+
const code = `({$active, $visible}) => $active ? ($visible ? null : css\`\`) : null`;
|
|
80
|
+
const cssName = extractConditionsWithBabel(code);
|
|
81
|
+
expect(cssName).toBe("active_and_not_visible");
|
|
82
|
+
});
|
|
83
|
+
});
|
|
@@ -60,7 +60,7 @@ export const Main = () => <h1 className={headline({}).className}>Hello World</h1
|
|
|
60
60
|
import { css } from \\"next-yak\\";
|
|
61
61
|
import __styleYak from \\"./page.yak.module.css!=!./page?./page.yak.module.css\\";
|
|
62
62
|
type x = number;
|
|
63
|
-
const headline = css(__styleYak.
|
|
63
|
+
const headline = css(__styleYak.yak_0);
|
|
64
64
|
export const Main = () => <h1 className={headline({}).className}>Hello World</h1>;"
|
|
65
65
|
`);
|
|
66
66
|
});
|
|
@@ -91,7 +91,7 @@ const headline = css\`
|
|
|
91
91
|
import { css } from \\"next-yak\\";
|
|
92
92
|
import __styleYak from \\"./page.yak.module.css!=!./page?./page.yak.module.css\\";
|
|
93
93
|
const x = Math.random();
|
|
94
|
-
const headline = css(__styleYak.
|
|
94
|
+
const headline = css(__styleYak.yak_0, x > 0.5 && css(__styleYak.yak_1));"
|
|
95
95
|
`);
|
|
96
96
|
});
|
|
97
97
|
|
|
@@ -125,7 +125,7 @@ const FancyButton = styled(Button)\`
|
|
|
125
125
|
import { styled, css } from \\"next-yak\\";
|
|
126
126
|
import __styleYak from \\"./page.yak.module.css!=!./page?./page.yak.module.css\\";
|
|
127
127
|
const x = Math.random();
|
|
128
|
-
const Button = styled.button(__styleYak.Button, x > 0.5 && css(__styleYak.
|
|
128
|
+
const Button = styled.button(__styleYak.Button, x > 0.5 && css(__styleYak.yak_0));
|
|
129
129
|
const FancyButton = styled(Button)(__styleYak.FancyButton);"
|
|
130
130
|
`);
|
|
131
131
|
});
|
|
@@ -162,7 +162,7 @@ const FancyButton = styled(Button)\`
|
|
|
162
162
|
const x = Math.random();
|
|
163
163
|
const Button = styled.button(__styleYak.Button, ({
|
|
164
164
|
theme
|
|
165
|
-
}) => theme.mode === \\"dark\\" && css(__styleYak.
|
|
165
|
+
}) => theme.mode === \\"dark\\" && css(__styleYak.yak_0));
|
|
166
166
|
const FancyButton = styled(Button)(__styleYak.FancyButton);"
|
|
167
167
|
`);
|
|
168
168
|
});
|
|
@@ -240,7 +240,7 @@ const headline = css\`
|
|
|
240
240
|
import { css } from \\"next-yak\\";
|
|
241
241
|
import __styleYak from \\"./page.yak.module.css!=!./page?./page.yak.module.css\\";
|
|
242
242
|
import { easing } from \\"styleguide\\";
|
|
243
|
-
const headline = css(__styleYak.
|
|
243
|
+
const headline = css(__styleYak.yak_0, css(__styleYak.yak_1), css(__styleYak.yak_2), {
|
|
244
244
|
\\"style\\": {
|
|
245
245
|
\\"--\\\\uD83E\\\\uDDAC18fi82j0\\": ({
|
|
246
246
|
i
|
|
@@ -477,12 +477,12 @@ const headline = css\`
|
|
|
477
477
|
`
|
|
478
478
|
)
|
|
479
479
|
).toMatchInlineSnapshot(`
|
|
480
|
-
|
|
481
|
-
|
|
482
|
-
|
|
483
|
-
|
|
484
|
-
|
|
485
|
-
`);
|
|
480
|
+
"import styles from \\"./page.module.css\\";
|
|
481
|
+
import { css } from \\"next-yak\\";
|
|
482
|
+
import __styleYak from \\"./page.yak.module.css!=!./page?./page.yak.module.css\\";
|
|
483
|
+
const x = Math.random();
|
|
484
|
+
const headline = css(__styleYak.yak_0, x > 0.5 && css(__styleYak.yak_1));"
|
|
485
|
+
`);
|
|
486
486
|
});
|
|
487
487
|
|
|
488
488
|
it("should show error when a dynamic selector is used after a comma", async () => {
|
|
@@ -552,13 +552,13 @@ const Button = styled.button\`
|
|
|
552
552
|
`
|
|
553
553
|
)
|
|
554
554
|
).toMatchInlineSnapshot(`
|
|
555
|
-
|
|
556
|
-
|
|
557
|
-
|
|
558
|
-
|
|
559
|
-
|
|
560
|
-
|
|
561
|
-
|
|
562
|
-
|
|
555
|
+
"import styles from \\"./page.module.css\\";
|
|
556
|
+
import { styled, css } from \\"next-yak\\";
|
|
557
|
+
import __styleYak from \\"./page.yak.module.css!=!./page?./page.yak.module.css\\";
|
|
558
|
+
const Icon = styled.svg(__styleYak.Icon);
|
|
559
|
+
const Button = styled.button(__styleYak.Button, ({
|
|
560
|
+
$primary
|
|
561
|
+
}) => $primary && css(__styleYak.primary_0));"
|
|
562
|
+
`);
|
|
563
563
|
});
|
|
564
564
|
});
|
|
@@ -5,6 +5,7 @@ const murmurhash2_32_gc = require("./lib/hash.cjs");
|
|
|
5
5
|
const { relative, resolve, basename } = require("path");
|
|
6
6
|
const localIdent = require("./lib/localIdent.cjs");
|
|
7
7
|
const getStyledComponentName = require("./lib/getStyledComponentName.cjs");
|
|
8
|
+
const getCssName = require("./lib/getCssName.cjs");
|
|
8
9
|
|
|
9
10
|
/** @typedef {{replaces: Record<string, unknown>, rootContext?: string}} YakBabelPluginOptions */
|
|
10
11
|
/** @typedef {{ css: string | undefined, styled: string | undefined, keyframes: string | undefined }} YakLocalIdentifierNames */
|
|
@@ -246,11 +247,13 @@ module.exports = function (babel, options) {
|
|
|
246
247
|
const variableName =
|
|
247
248
|
styledApi || expressionType === "keyframesLiteral"
|
|
248
249
|
? getStyledComponentName(path)
|
|
250
|
+
: expressionType === "cssLiteral" ?
|
|
251
|
+
getCssName(path)
|
|
249
252
|
: null;
|
|
250
253
|
|
|
251
254
|
const identifier = localIdent(
|
|
252
255
|
variableName || "_yak",
|
|
253
|
-
variableName ? null : this.classNameCount++,
|
|
256
|
+
variableName && expressionType !== "cssLiteral" ? null : this.classNameCount++,
|
|
254
257
|
expressionType === "keyframesLiteral" ? "animation" : "className"
|
|
255
258
|
);
|
|
256
259
|
|
package/loaders/cssloader.cjs
CHANGED
|
@@ -5,6 +5,7 @@ const quasiClassifier = require("./lib/quasiClassifier.cjs");
|
|
|
5
5
|
const localIdent = require("./lib/localIdent.cjs");
|
|
6
6
|
const replaceQuasiExpressionTokens = require("./lib/replaceQuasiExpressionTokens.cjs");
|
|
7
7
|
const getStyledComponentName = require("./lib/getStyledComponentName.cjs");
|
|
8
|
+
const getCssName = require("./lib/getCssName.cjs");
|
|
8
9
|
const murmurhash2_32_gc = require("./lib/hash.cjs");
|
|
9
10
|
const { relative } = require("path");
|
|
10
11
|
|
|
@@ -192,11 +193,12 @@ module.exports = async function cssLoader(source) {
|
|
|
192
193
|
const variableName =
|
|
193
194
|
isStyledLiteral || isStyledCall || isAttrsCall || isKeyFrameLiteral
|
|
194
195
|
? getStyledComponentName(path)
|
|
196
|
+
: isCssLiteral ? getCssName(path)
|
|
195
197
|
: null
|
|
196
198
|
|
|
197
199
|
const literalSelector = localIdent(
|
|
198
200
|
variableName || "_yak",
|
|
199
|
-
variableName ? null : index++,
|
|
201
|
+
variableName && !isCssLiteral ? null : index++,
|
|
200
202
|
isKeyFrameLiteral ? "keyframes" : "selector"
|
|
201
203
|
);
|
|
202
204
|
|
|
@@ -0,0 +1,131 @@
|
|
|
1
|
+
// @ts-check
|
|
2
|
+
|
|
3
|
+
/** @typedef {import("@babel/types")} babel */
|
|
4
|
+
|
|
5
|
+
/**
|
|
6
|
+
* Try to get the name of a css literal
|
|
7
|
+
*
|
|
8
|
+
* e.g. ({$disabled}) => $disabled && css`...` -> "is_$disabled"
|
|
9
|
+
*
|
|
10
|
+
* @param {babel.NodePath<babel.types.TaggedTemplateExpression>} path
|
|
11
|
+
* @returns {string}
|
|
12
|
+
*/
|
|
13
|
+
function getCssName(path) {
|
|
14
|
+
const conditions = extractConditions(path);
|
|
15
|
+
if (conditions.length === 0) {
|
|
16
|
+
return "yak";
|
|
17
|
+
}
|
|
18
|
+
return conditions
|
|
19
|
+
.map((condition) => {
|
|
20
|
+
if (condition === "&&") {
|
|
21
|
+
return "and";
|
|
22
|
+
}
|
|
23
|
+
if (condition === "||") {
|
|
24
|
+
return "or";
|
|
25
|
+
}
|
|
26
|
+
return condition;
|
|
27
|
+
})
|
|
28
|
+
.join("_")
|
|
29
|
+
.replace(/\$/g, "")
|
|
30
|
+
.replace(/!/g, "not_");
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
/**
|
|
34
|
+
* Extracts the conditions from a given path.
|
|
35
|
+
*
|
|
36
|
+
* @param {babel.NodePath} path - The path to extract conditions from.
|
|
37
|
+
*/
|
|
38
|
+
function extractConditions(path) {
|
|
39
|
+
const conditions = [];
|
|
40
|
+
let currentPath = path.parentPath;
|
|
41
|
+
let child = path.node;
|
|
42
|
+
while (
|
|
43
|
+
currentPath &&
|
|
44
|
+
(currentPath.isLogicalExpression() || currentPath.isConditionalExpression())
|
|
45
|
+
) {
|
|
46
|
+
if (currentPath.isConditionalExpression() && conditions.length > 0) {
|
|
47
|
+
conditions.push(operatorToWord("&&", false));
|
|
48
|
+
}
|
|
49
|
+
let left = currentPath.isLogicalExpression()
|
|
50
|
+
? currentPath.node.left
|
|
51
|
+
: currentPath.node.test;
|
|
52
|
+
const negated = currentPath.isConditionalExpression() && currentPath.node.alternate === child;
|
|
53
|
+
const leftName = extractIdentifier(left, negated);
|
|
54
|
+
if (leftName) {
|
|
55
|
+
conditions.push(leftName);
|
|
56
|
+
}
|
|
57
|
+
while (left && left.type === "LogicalExpression") {
|
|
58
|
+
if (left.type === "LogicalExpression" && left.right !== path.node) {
|
|
59
|
+
const rightName = extractIdentifier(left.right, negated);
|
|
60
|
+
if (rightName) {
|
|
61
|
+
conditions.push(rightName);
|
|
62
|
+
conditions.push(operatorToWord(left.operator, negated));
|
|
63
|
+
}
|
|
64
|
+
}
|
|
65
|
+
left = left.left;
|
|
66
|
+
const leftName = extractIdentifier(left, negated);
|
|
67
|
+
if (leftName) {
|
|
68
|
+
conditions.push(leftName);
|
|
69
|
+
}
|
|
70
|
+
}
|
|
71
|
+
child = currentPath.node;
|
|
72
|
+
currentPath = currentPath.parentPath;
|
|
73
|
+
}
|
|
74
|
+
return conditions.reverse();
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
/**
|
|
78
|
+
* Extracts the identifier from a given node.
|
|
79
|
+
* @param {babel.types.Node} node - The node to extract the identifier from.
|
|
80
|
+
* @param {boolean} negated - Whether the node is negated.
|
|
81
|
+
*/
|
|
82
|
+
function extractIdentifier(node, negated) {
|
|
83
|
+
if (node.type === "Identifier") {
|
|
84
|
+
return prepend(node.name, "!", negated);
|
|
85
|
+
}
|
|
86
|
+
if (node.type === "MemberExpression" && node.object.type === "Identifier" && node.property.type === "Identifier") {
|
|
87
|
+
return prepend(node.object.name + node.property.name[0].toUpperCase() + node.property.name.slice(1), "!", negated);
|
|
88
|
+
}
|
|
89
|
+
if (node.type === "UnaryExpression" && node.argument.type === "Identifier") {
|
|
90
|
+
return prepend(node.argument.name, "!", !negated);
|
|
91
|
+
}
|
|
92
|
+
if (
|
|
93
|
+
node.type === "UnaryExpression" &&
|
|
94
|
+
node.argument.type === "UnaryExpression" &&
|
|
95
|
+
node.argument.argument.type === "Identifier"
|
|
96
|
+
) {
|
|
97
|
+
return prepend(node.argument.argument.name, "!", negated);
|
|
98
|
+
}
|
|
99
|
+
return null;
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
|
|
103
|
+
/**
|
|
104
|
+
* Negates the operator if negated is true.
|
|
105
|
+
*
|
|
106
|
+
* @param {string} operator
|
|
107
|
+
* @param {boolean} negated
|
|
108
|
+
|
|
109
|
+
*/
|
|
110
|
+
function operatorToWord(operator, negated) {
|
|
111
|
+
switch (operator) {
|
|
112
|
+
case "&&":
|
|
113
|
+
return negated ? "or" : "and";
|
|
114
|
+
case "||":
|
|
115
|
+
return negated ? "and" : "or";
|
|
116
|
+
default:
|
|
117
|
+
return operator;
|
|
118
|
+
}
|
|
119
|
+
}
|
|
120
|
+
|
|
121
|
+
/**
|
|
122
|
+
* Prepends a prefix to a string if active is true.
|
|
123
|
+
* @param {string} str - The string to prepend the prefix to.
|
|
124
|
+
* @param {string} prefix - The prefix to prepend.
|
|
125
|
+
* @param {boolean} active - Whether to prepend the prefix.
|
|
126
|
+
*/
|
|
127
|
+
function prepend(str, prefix, active) {
|
|
128
|
+
return active ? prefix + str : str;
|
|
129
|
+
}
|
|
130
|
+
|
|
131
|
+
module.exports = getCssName;
|