Skip to content

Commit 569a9c5

Browse files
refactor: logic
1 parent 6c3a86b commit 569a9c5

File tree

3 files changed

+143
-75
lines changed

3 files changed

+143
-75
lines changed

README.md

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,8 @@
44

55
Transformation examples:
66

7+
Selectors (mode `local`, by default)::
8+
79
<!-- prettier-ignore-start -->
810
```css
911
.foo { ... } /* => */ :local(.foo) { ... }
@@ -28,6 +30,30 @@ Transformation examples:
2830
```
2931
<!-- prettier-ignore-end -->
3032

33+
Declarations (mode `local`, by default):
34+
35+
<!-- prettier-ignore-start -->
36+
```css
37+
.foo {
38+
animation-name: fadeInOut, global(moveLeft300px), local(bounce);
39+
}
40+
41+
.bar {
42+
animation: rotate 1s, global(spin) 3s, local(fly) 6s;
43+
}
44+
45+
/* => */
46+
47+
:local(.foo) {
48+
animation-name: :local(fadeInOut), moveLeft300px, :local(bounce);
49+
}
50+
51+
:local(.bar) {
52+
animation: :local(rotate) 1s, spin 3s, :local(fly) 6s;
53+
}
54+
```
55+
<!-- prettier-ignore-end -->
56+
3157
## Building
3258

3359
```bash

src/index.js

Lines changed: 70 additions & 75 deletions
Original file line numberDiff line numberDiff line change
@@ -328,17 +328,6 @@ function localizeDeclarationValues(localize, declaration, context) {
328328
return false;
329329
}
330330

331-
// replace `animation-name: global(example)` with `animation-name: example`
332-
if (
333-
node.type === "function" &&
334-
node.value.toLowerCase() === "global" &&
335-
/animation(-name)$/i.test(declaration.prop) &&
336-
node.nodes.length === 1
337-
) {
338-
Object.assign(node, node.nodes[0]);
339-
return;
340-
}
341-
342331
if (
343332
node.type === "word" &&
344333
specialKeywords.includes(node.value.toLowerCase())
@@ -358,24 +347,20 @@ function localizeDeclarationValues(localize, declaration, context) {
358347
declaration.value = valueNodes.toString();
359348
}
360349

361-
function localizeDeclaration(declaration, context) {
362-
const isAnimation = /animation$/i.test(declaration.prop);
350+
// letter
351+
// An uppercase letter or a lowercase letter.
352+
//
353+
// ident-start code point
354+
// A letter, a non-ASCII code point, or U+005F LOW LINE (_).
355+
//
356+
// ident code point
357+
// An ident-start code point, a digit, or U+002D HYPHEN-MINUS (-).
363358

364-
if (isAnimation) {
365-
// letter
366-
// An uppercase letter or a lowercase letter.
367-
//
368-
// ident-start code point
369-
// A letter, a non-ASCII code point, or U+005F LOW LINE (_).
370-
//
371-
// ident code point
372-
// An ident-start code point, a digit, or U+002D HYPHEN-MINUS (-).
373-
374-
// We don't validate `hex digits`, because we don't need it, it is work of linters.
375-
const validIdent =
376-
/^-?([a-z\u0080-\uFFFF_]|(\\[^\r\n\f])|-(?![0-9]))((\\[^\r\n\f])|[a-z\u0080-\uFFFF_0-9-])*$/i;
377-
378-
/*
359+
// We don't validate `hex digits`, because we don't need it, it is work of linters.
360+
const validIdent =
361+
/^-?([a-z\u0080-\uFFFF_]|(\\[^\r\n\f])|-(?![0-9]))((\\[^\r\n\f])|[a-z\u0080-\uFFFF_0-9-])*$/i;
362+
363+
/*
379364
The spec defines some keywords that you can use to describe properties such as the timing
380365
function. These are still valid animation names, so as long as there is a property that accepts
381366
a keyword, it is given priority. Only when all the properties that can take a keyword are
@@ -386,51 +371,71 @@ function localizeDeclaration(declaration, context) {
386371
The animation will repeat an infinite number of times from the first argument, and will have an
387372
animation name of infinite from the second.
388373
*/
389-
const animationKeywords = {
390-
// animation-direction
391-
$normal: 1,
392-
$reverse: 1,
393-
$alternate: 1,
394-
"$alternate-reverse": 1,
395-
// animation-fill-mode
396-
$forwards: 1,
397-
$backwards: 1,
398-
$both: 1,
399-
// animation-iteration-count
400-
$infinite: 1,
401-
// animation-play-state
402-
$paused: 1,
403-
$running: 1,
404-
// animation-timing-function
405-
$ease: 1,
406-
"$ease-in": 1,
407-
"$ease-out": 1,
408-
"$ease-in-out": 1,
409-
$linear: 1,
410-
"$step-end": 1,
411-
"$step-start": 1,
412-
// Special
413-
$none: Infinity, // No matter how many times you write none, it will never be an animation name
414-
// Global values
415-
$initial: Infinity,
416-
$inherit: Infinity,
417-
$unset: Infinity,
418-
$revert: Infinity,
419-
"$revert-layer": Infinity,
420-
};
374+
const animationKeywords = {
375+
// animation-direction
376+
$normal: 1,
377+
$reverse: 1,
378+
$alternate: 1,
379+
"$alternate-reverse": 1,
380+
// animation-fill-mode
381+
$forwards: 1,
382+
$backwards: 1,
383+
$both: 1,
384+
// animation-iteration-count
385+
$infinite: 1,
386+
// animation-play-state
387+
$paused: 1,
388+
$running: 1,
389+
// animation-timing-function
390+
$ease: 1,
391+
"$ease-in": 1,
392+
"$ease-out": 1,
393+
"$ease-in-out": 1,
394+
$linear: 1,
395+
"$step-end": 1,
396+
"$step-start": 1,
397+
// Special
398+
$none: Infinity, // No matter how many times you write none, it will never be an animation name
399+
// Global values
400+
$initial: Infinity,
401+
$inherit: Infinity,
402+
$unset: Infinity,
403+
$revert: Infinity,
404+
"$revert-layer": Infinity,
405+
};
406+
407+
function localizeDeclaration(declaration, context) {
408+
const isAnimation = /animation(-name)?$/i.test(declaration.prop);
409+
410+
if (isAnimation) {
421411
let parsedAnimationKeywords = {};
422412
const valueNodes = valueParser(declaration.value).walk((node) => {
423413
// If div-token appeared (represents as comma ','), a possibility of an animation-keywords should be reflesh.
424414
if (node.type === "div") {
425415
parsedAnimationKeywords = {};
426416

427417
return;
418+
} else if (
419+
node.type === "function" &&
420+
node.value.toLowerCase() === "local" &&
421+
node.nodes.length === 1
422+
) {
423+
node.type = "word";
424+
node.value = node.nodes[0].value;
425+
426+
return localizeDeclNode(node, {
427+
options: context.options,
428+
global: context.global,
429+
localizeNextItem: true,
430+
localAliasMap: context.localAliasMap,
431+
});
428432
} else if (node.type === "function") {
429433
// replace `animation: global(example)` with `animation-name: example`
430434
if (node.value.toLowerCase() === "global" && node.nodes.length === 1) {
431-
Object.assign(node, node.nodes[0]);
432-
return false;
435+
node.type = "word";
436+
node.value = node.nodes[0].value;
433437
}
438+
434439
// Do not handle nested functions
435440
return false;
436441
}
@@ -458,30 +463,20 @@ function localizeDeclaration(declaration, context) {
458463
}
459464
}
460465

461-
const subContext = {
466+
return localizeDeclNode(node, {
462467
options: context.options,
463468
global: context.global,
464469
localizeNextItem: shouldParseAnimationName && !context.global,
465470
localAliasMap: context.localAliasMap,
466-
};
467-
468-
return localizeDeclNode(node, subContext);
471+
});
469472
});
470473

471474
declaration.value = valueNodes.toString();
472475

473476
return;
474477
}
475478

476-
const isAnimationName = /animation(-name)?$/i.test(declaration.prop);
477-
478-
if (isAnimationName) {
479-
return localizeDeclarationValues(true, declaration, context);
480-
}
481-
482-
const hasUrl = /url\(/i.test(declaration.value);
483-
484-
if (hasUrl) {
479+
if (/url\(/i.test(declaration.value)) {
485480
return localizeDeclarationValues(false, declaration, context);
486481
}
487482
}

test/index.test.js

Lines changed: 47 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -164,6 +164,11 @@ const tests = [
164164
input: ".foo { animation-name: bar; }",
165165
expected: ":local(.foo) { animation-name: :local(bar); }",
166166
},
167+
{
168+
name: "localize a single animation-name #2",
169+
input: ".foo { animation-name: local(bar); }",
170+
expected: ":local(.foo) { animation-name: :local(bar); }",
171+
},
167172
{
168173
name: "not localize animation-name in a var function",
169174
input: ".foo { animation-name: var(--bar); }",
@@ -184,6 +189,29 @@ const tests = [
184189
input: ".foo { animation-name: global(bar); }",
185190
expected: ":local(.foo) { animation-name: bar; }",
186191
},
192+
{
193+
name: "localize and not localize animation-name in mixed case",
194+
input:
195+
".foo { animation-name: fadeInOut, global(moveLeft300px), local(bounce); }",
196+
expected:
197+
":local(.foo) { animation-name: :local(fadeInOut), moveLeft300px, :local(bounce); }",
198+
},
199+
{
200+
name: "localize and not localize animation-name in mixed case #2",
201+
options: { mode: "global" },
202+
input:
203+
".foo { animation-name: fadeInOut, global(moveLeft300px), local(bounce); }",
204+
expected:
205+
".foo { animation-name: fadeInOut, moveLeft300px, :local(bounce); }",
206+
},
207+
{
208+
name: "localize and not localize animation-name in mixed case #3",
209+
options: { mode: "pure" },
210+
input:
211+
".foo { animation-name: fadeInOut, global(moveLeft300px), local(bounce); }",
212+
expected:
213+
":local(.foo) { animation-name: :local(fadeInOut), moveLeft300px, :local(bounce); }",
214+
},
187215
{
188216
name: "not localize animation in an global function",
189217
input: ".foo { animation: global(bar); }",
@@ -194,6 +222,25 @@ const tests = [
194222
input: ".foo { animation: global(bar), foo; }",
195223
expected: ":local(.foo) { animation: bar, :local(foo); }",
196224
},
225+
{
226+
name: "localize and not localize a certain animation in mixed case",
227+
input: ".foo { animation: rotate 1s, global(spin) 3s, local(fly) 6s; }",
228+
expected:
229+
":local(.foo) { animation: :local(rotate) 1s, spin 3s, :local(fly) 6s; }",
230+
},
231+
{
232+
name: "localize and not localize a certain animation in mixed case #2",
233+
options: { mode: "global" },
234+
input: ".foo { animation: rotate 1s, global(spin) 3s, local(fly) 6s; }",
235+
expected: ".foo { animation: rotate 1s, spin 3s, :local(fly) 6s; }",
236+
},
237+
{
238+
name: "localize and not localize a certain animation in mixed case #2",
239+
options: { mode: "pure" },
240+
input: ".foo { animation: rotate 1s, global(spin) 3s, local(fly) 6s; }",
241+
expected:
242+
":local(.foo) { animation: :local(rotate) 1s, spin 3s, :local(fly) 6s; }",
243+
},
197244
{
198245
name: "not localize animation-name in an env function #2",
199246
input: ".foo { animation-name: eNv(bar); }",

0 commit comments

Comments
 (0)