next-yak 0.0.28 → 0.0.29
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.
|
@@ -289,6 +289,40 @@ const headline = css\`
|
|
|
289
289
|
`);
|
|
290
290
|
});
|
|
291
291
|
|
|
292
|
+
it("should replace breakpoint references with actual media queries when using square brackets", async () => {
|
|
293
|
+
expect(
|
|
294
|
+
await cssloader.call(
|
|
295
|
+
loaderContext,
|
|
296
|
+
`
|
|
297
|
+
import { css } from "next-yak";
|
|
298
|
+
import { queries } from '@/theme.yak';
|
|
299
|
+
|
|
300
|
+
const headline = css\`
|
|
301
|
+
color: blue;
|
|
302
|
+
\${queries["sm"]} {
|
|
303
|
+
color: red;
|
|
304
|
+
}
|
|
305
|
+
transition: color \${duration} \${easing};
|
|
306
|
+
display: block;
|
|
307
|
+
\${css\`color: orange\`}
|
|
308
|
+
\`;
|
|
309
|
+
`
|
|
310
|
+
)
|
|
311
|
+
).toMatchInlineSnapshot(`
|
|
312
|
+
".headline_0 {
|
|
313
|
+
color: blue;
|
|
314
|
+
@media (min-width: 640px) {
|
|
315
|
+
color: red;
|
|
316
|
+
}
|
|
317
|
+
transition: color var(--🦬18fi82j0) var(--🦬18fi82j1);
|
|
318
|
+
display: block;
|
|
319
|
+
&:where(.headline_1) {
|
|
320
|
+
color: orange
|
|
321
|
+
}
|
|
322
|
+
}"
|
|
323
|
+
`);
|
|
324
|
+
});
|
|
325
|
+
|
|
292
326
|
it("should prevent double escaped chars", async () => {
|
|
293
327
|
// in styled-components \\ is replaced with \
|
|
294
328
|
// this test verifies that yak provides the same behavior
|
|
@@ -25,43 +25,22 @@
|
|
|
25
25
|
* @param {import("@babel/types")} t
|
|
26
26
|
*/
|
|
27
27
|
module.exports = function replaceTokensInQuasiExpressions(quasi, replacer, t) {
|
|
28
|
-
|
|
28
|
+
// Iterate over the expressions in reverse order
|
|
29
|
+
// so removing items won't affect the index of the next item
|
|
30
|
+
for (let i = quasi.expressions.length - 1; i >= 0; i--) {
|
|
29
31
|
const expression = quasi.expressions[i];
|
|
30
|
-
// replace
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
t.isMemberExpression(expression) &&
|
|
43
|
-
t.isIdentifier(expression.object)
|
|
44
|
-
) {
|
|
45
|
-
/** @type {any} */
|
|
46
|
-
let replacement = replacer(expression.object.name);
|
|
47
|
-
if (replacement === false) {
|
|
48
|
-
continue;
|
|
49
|
-
}
|
|
50
|
-
/** @type {import("@babel/types").Expression} */
|
|
51
|
-
let object = expression;
|
|
52
|
-
while (t.isMemberExpression(object)) {
|
|
53
|
-
if (!t.isIdentifier(object.property)) {
|
|
54
|
-
break;
|
|
55
|
-
}
|
|
56
|
-
if (typeof replacement !== "object" || replacement === null) {
|
|
57
|
-
break;
|
|
58
|
-
}
|
|
59
|
-
replacement = replacement[object.property.name];
|
|
60
|
-
object = object.object;
|
|
61
|
-
}
|
|
62
|
-
replaceExpressionAndMergeQuasis(quasi, i, replacement);
|
|
63
|
-
i--;
|
|
64
|
-
}
|
|
32
|
+
// find the value to replace the expression with
|
|
33
|
+
const replacement = getReplacement(expression, replacer, t);
|
|
34
|
+
// if it is a nested value, find the value of the expression
|
|
35
|
+
// e.g. x.y.z -> find the value of z
|
|
36
|
+
const replacementValue = replacement && getReplacementValueForExpression(
|
|
37
|
+
expression,
|
|
38
|
+
replacement,
|
|
39
|
+
t
|
|
40
|
+
);
|
|
41
|
+
if (replacementValue !== false) {
|
|
42
|
+
replaceExpressionAndMergeQuasis(quasi, i, replacementValue);
|
|
43
|
+
}
|
|
65
44
|
}
|
|
66
45
|
};
|
|
67
46
|
|
|
@@ -85,3 +64,98 @@ function replaceExpressionAndMergeQuasis(quasi, expressionIndex, replacement) {
|
|
|
85
64
|
stringReplacement + quasi.quasis[expressionIndex + 1].value.cooked;
|
|
86
65
|
quasi.quasis.splice(expressionIndex + 1, 1);
|
|
87
66
|
}
|
|
67
|
+
|
|
68
|
+
/**
|
|
69
|
+
* Find the replacement for the expression
|
|
70
|
+
*
|
|
71
|
+
* searches for:
|
|
72
|
+
* - `x` -> x
|
|
73
|
+
* - `x.y` -> x
|
|
74
|
+
* - `x[0]` -> x
|
|
75
|
+
* - `x()` -> x
|
|
76
|
+
* - `x.y()` -> x
|
|
77
|
+
*
|
|
78
|
+
* @param {import("@babel/types").Expression | import("@babel/types").TSType} expression
|
|
79
|
+
* @param {(name: string) => unknown} replacer
|
|
80
|
+
* @param {import("@babel/types")} t
|
|
81
|
+
*/
|
|
82
|
+
function getReplacement(expression, replacer, t) {
|
|
83
|
+
if (t.isIdentifier(expression)) {
|
|
84
|
+
return replacer(expression.name);
|
|
85
|
+
}
|
|
86
|
+
if (t.isMemberExpression(expression) && t.isIdentifier(expression.object)) {
|
|
87
|
+
return replacer(expression.object.name);
|
|
88
|
+
}
|
|
89
|
+
if (t.isCallExpression(expression) && t.isIdentifier(expression.callee)) {
|
|
90
|
+
return replacer(expression.callee.name);
|
|
91
|
+
}
|
|
92
|
+
if (
|
|
93
|
+
t.isCallExpression(expression) &&
|
|
94
|
+
t.isMemberExpression(expression.callee) &&
|
|
95
|
+
t.isIdentifier(expression.callee.object)
|
|
96
|
+
) {
|
|
97
|
+
return replacer(expression.callee.object.name);
|
|
98
|
+
}
|
|
99
|
+
return false;
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
/**
|
|
103
|
+
* The value for an expression can be a simple identifier e.g.
|
|
104
|
+
* import { x } from "demo.yak";
|
|
105
|
+
* console.log(x);
|
|
106
|
+
*
|
|
107
|
+
* However it could also be a nested value e.g.
|
|
108
|
+
* import { x } from "demo.yak";
|
|
109
|
+
* console.log(x.persons[0].hobbies["art"].name);
|
|
110
|
+
*
|
|
111
|
+
* This function recursively searches for the value of the expression
|
|
112
|
+
* or returns false if the value is not found
|
|
113
|
+
*
|
|
114
|
+
* @param {import("@babel/types").Expression | import("@babel/types").TSType} expression
|
|
115
|
+
* @param {any} value
|
|
116
|
+
* @param {import("@babel/types")} t
|
|
117
|
+
*/
|
|
118
|
+
function getReplacementValueForExpression(expression, value, t) {
|
|
119
|
+
if (value === null || value === undefined || typeof value === "boolean") {
|
|
120
|
+
return false;
|
|
121
|
+
}
|
|
122
|
+
if (t.isIdentifier(expression)) {
|
|
123
|
+
if (typeof value === "string" || typeof value === "number") {
|
|
124
|
+
return value;
|
|
125
|
+
}
|
|
126
|
+
}
|
|
127
|
+
|
|
128
|
+
if (typeof value === "object" && t.isMemberExpression(expression)) {
|
|
129
|
+
if (expression.computed) {
|
|
130
|
+
// e.g. x[0]
|
|
131
|
+
if (t.isNumericLiteral(expression.property)) {
|
|
132
|
+
return getReplacementValueForExpression(
|
|
133
|
+
expression.object,
|
|
134
|
+
value[expression.property.value],
|
|
135
|
+
t
|
|
136
|
+
);
|
|
137
|
+
}
|
|
138
|
+
// e.g. x["0"]
|
|
139
|
+
else if (t.isStringLiteral(expression.property)) {
|
|
140
|
+
return getReplacementValueForExpression(
|
|
141
|
+
expression.object,
|
|
142
|
+
value[expression.property.value],
|
|
143
|
+
t
|
|
144
|
+
);
|
|
145
|
+
} else {
|
|
146
|
+
// right now we don't support dynamic property names
|
|
147
|
+
// e.g. x[y]
|
|
148
|
+
return false;
|
|
149
|
+
}
|
|
150
|
+
}
|
|
151
|
+
// e.g. x.y
|
|
152
|
+
else if (t.isIdentifier(expression.property)) {
|
|
153
|
+
return getReplacementValueForExpression(
|
|
154
|
+
expression.object,
|
|
155
|
+
value[expression.property.name],
|
|
156
|
+
t
|
|
157
|
+
);
|
|
158
|
+
}
|
|
159
|
+
}
|
|
160
|
+
return false;
|
|
161
|
+
}
|