ember-scoped-css 2.1.0 → 2.2.0
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/dist/cjs/all-CFsaG5pM.cjs +1416 -0
- package/dist/cjs/all.cjs +1 -1
- package/dist/cjs/babel.cjs +1 -1
- package/dist/cjs/rollup.cjs +1 -1
- package/dist/cjs/vite.cjs +1 -1
- package/package.json +4 -3
- package/src/build/template-plugin.js +53 -9
- package/src/build/template-plugin.test.ts +140 -1
- package/src/build/unplugin-colocated.js +54 -1
- package/src/build/unplugin-inline.js +53 -13
- package/src/lib/css/rewrite.js +18 -16
- package/src/lib/css/rewrite.test.ts +68 -52
- package/src/lib/css/utils.js +107 -3
- package/src/lib/request.js +10 -2
- package/dist/cjs/all-Bimr-GZ4.cjs +0 -1319
|
@@ -22,7 +22,8 @@ it('should use a custom layer', function () {
|
|
|
22
22
|
@layer utils {
|
|
23
23
|
.foo_postfix { color: red; }
|
|
24
24
|
}
|
|
25
|
-
"
|
|
25
|
+
"
|
|
26
|
+
`);
|
|
26
27
|
});
|
|
27
28
|
|
|
28
29
|
it(`understands nth-of-type syntax`, function () {
|
|
@@ -40,7 +41,8 @@ it(`understands nth-of-type syntax`, function () {
|
|
|
40
41
|
|
|
41
42
|
li.postfix:nth-of-type(odd) {}
|
|
42
43
|
li.postfix:nth-of-type(even) {}
|
|
43
|
-
"
|
|
44
|
+
"
|
|
45
|
+
`);
|
|
44
46
|
});
|
|
45
47
|
|
|
46
48
|
describe('@container', () => {
|
|
@@ -64,7 +66,8 @@ describe('@container', () => {
|
|
|
64
66
|
font-size: 1.5em;
|
|
65
67
|
}
|
|
66
68
|
}
|
|
67
|
-
"
|
|
69
|
+
"
|
|
70
|
+
`);
|
|
68
71
|
});
|
|
69
72
|
|
|
70
73
|
it('handles parameters', () => {
|
|
@@ -120,7 +123,8 @@ describe('@container', () => {
|
|
|
120
123
|
color: white;
|
|
121
124
|
}
|
|
122
125
|
}
|
|
123
|
-
"
|
|
126
|
+
"
|
|
127
|
+
`);
|
|
124
128
|
});
|
|
125
129
|
});
|
|
126
130
|
|
|
@@ -142,8 +146,9 @@ describe('@media', () => {
|
|
|
142
146
|
@media (height >= 680px), screen and (orientation: portrait) {
|
|
143
147
|
.foo_postfix { color: red; }
|
|
144
148
|
}
|
|
145
|
-
}
|
|
146
|
-
"
|
|
149
|
+
}
|
|
150
|
+
"
|
|
151
|
+
`);
|
|
147
152
|
});
|
|
148
153
|
});
|
|
149
154
|
|
|
@@ -170,8 +175,9 @@ describe('@keyframe', () => {
|
|
|
170
175
|
padding-top: 1rem;
|
|
171
176
|
}
|
|
172
177
|
}
|
|
173
|
-
}
|
|
174
|
-
"
|
|
178
|
+
}
|
|
179
|
+
"
|
|
180
|
+
`);
|
|
175
181
|
});
|
|
176
182
|
|
|
177
183
|
it(`references are also scoped`, function () {
|
|
@@ -200,7 +206,7 @@ describe('@keyframe', () => {
|
|
|
200
206
|
|
|
201
207
|
expect(rewritten).toMatchInlineSnapshot(`
|
|
202
208
|
"/* foo.css */
|
|
203
|
-
@layer components {
|
|
209
|
+
@layer components {
|
|
204
210
|
|
|
205
211
|
p.postfix {
|
|
206
212
|
animation-duration: 3s;
|
|
@@ -218,8 +224,9 @@ describe('@keyframe', () => {
|
|
|
218
224
|
scale: 100% 1;
|
|
219
225
|
}
|
|
220
226
|
}
|
|
221
|
-
}
|
|
222
|
-
"
|
|
227
|
+
}
|
|
228
|
+
"
|
|
229
|
+
`);
|
|
223
230
|
});
|
|
224
231
|
|
|
225
232
|
it('handles multiple references and keyframes', () => {
|
|
@@ -268,7 +275,7 @@ describe('@keyframe', () => {
|
|
|
268
275
|
|
|
269
276
|
expect(rewritten).toMatchInlineSnapshot(`
|
|
270
277
|
"/* foo.css */
|
|
271
|
-
@layer components {
|
|
278
|
+
@layer components {
|
|
272
279
|
|
|
273
280
|
p.postfix {
|
|
274
281
|
animation-duration: 3s;
|
|
@@ -307,8 +314,9 @@ describe('@keyframe', () => {
|
|
|
307
314
|
color: magenta;
|
|
308
315
|
}
|
|
309
316
|
}
|
|
310
|
-
}
|
|
311
|
-
"
|
|
317
|
+
}
|
|
318
|
+
"
|
|
319
|
+
`);
|
|
312
320
|
});
|
|
313
321
|
|
|
314
322
|
it('works in shorthand combo-declarations', () => {
|
|
@@ -333,7 +341,7 @@ describe('@keyframe', () => {
|
|
|
333
341
|
|
|
334
342
|
expect(rewritten).toMatchInlineSnapshot(`
|
|
335
343
|
"/* foo.css */
|
|
336
|
-
@layer components {
|
|
344
|
+
@layer components {
|
|
337
345
|
|
|
338
346
|
div.postfix {
|
|
339
347
|
width: 100px;
|
|
@@ -347,8 +355,9 @@ describe('@keyframe', () => {
|
|
|
347
355
|
from {top: 0px;}
|
|
348
356
|
to {top: 200px;}
|
|
349
357
|
}
|
|
350
|
-
}
|
|
351
|
-
"
|
|
358
|
+
}
|
|
359
|
+
"
|
|
360
|
+
`);
|
|
352
361
|
});
|
|
353
362
|
});
|
|
354
363
|
|
|
@@ -375,8 +384,9 @@ describe('@counter-style', () => {
|
|
|
375
384
|
symbols: Ⓐ Ⓑ Ⓒ Ⓓ Ⓔ Ⓕ Ⓖ Ⓗ Ⓘ Ⓙ Ⓚ Ⓛ Ⓜ Ⓝ Ⓞ Ⓟ Ⓠ Ⓡ Ⓢ Ⓣ Ⓤ Ⓥ Ⓦ Ⓧ Ⓨ Ⓩ;
|
|
376
385
|
suffix: " ";
|
|
377
386
|
}
|
|
378
|
-
}
|
|
379
|
-
"
|
|
387
|
+
}
|
|
388
|
+
"
|
|
389
|
+
`);
|
|
380
390
|
});
|
|
381
391
|
|
|
382
392
|
it('updates references', () => {
|
|
@@ -398,19 +408,20 @@ describe('@counter-style', () => {
|
|
|
398
408
|
|
|
399
409
|
expect(rewritten).toMatchInlineSnapshot(`
|
|
400
410
|
"/* foo.css */
|
|
401
|
-
@layer components {
|
|
411
|
+
@layer components {
|
|
402
412
|
|
|
403
|
-
|
|
404
|
-
|
|
405
|
-
|
|
406
|
-
|
|
407
|
-
|
|
413
|
+
@counter-style circled-alpha__postfix {
|
|
414
|
+
system: fixed;
|
|
415
|
+
symbols: Ⓐ Ⓑ Ⓒ Ⓓ Ⓔ Ⓕ Ⓖ Ⓗ Ⓘ Ⓙ Ⓚ Ⓛ Ⓜ Ⓝ Ⓞ Ⓟ Ⓠ Ⓡ Ⓢ Ⓣ Ⓤ Ⓥ Ⓦ Ⓧ Ⓨ Ⓩ;
|
|
416
|
+
suffix: " ";
|
|
417
|
+
}
|
|
408
418
|
|
|
409
|
-
|
|
410
|
-
|
|
411
|
-
|
|
412
|
-
}
|
|
413
|
-
"
|
|
419
|
+
.items_postfix {
|
|
420
|
+
list-style: circled-alpha__postfix;
|
|
421
|
+
}
|
|
422
|
+
}
|
|
423
|
+
"
|
|
424
|
+
`);
|
|
414
425
|
});
|
|
415
426
|
});
|
|
416
427
|
|
|
@@ -430,15 +441,16 @@ describe('@position-try', () => {
|
|
|
430
441
|
|
|
431
442
|
expect(rewritten).toMatchInlineSnapshot(`
|
|
432
443
|
"/* foo.css */
|
|
433
|
-
@layer components {
|
|
444
|
+
@layer components {
|
|
434
445
|
|
|
435
446
|
@position-try --custom-left__postfix {
|
|
436
447
|
position-area: left;
|
|
437
448
|
width: 100px;
|
|
438
449
|
margin-right: 10px;
|
|
439
450
|
}
|
|
440
|
-
}
|
|
441
|
-
"
|
|
451
|
+
}
|
|
452
|
+
"
|
|
453
|
+
`);
|
|
442
454
|
});
|
|
443
455
|
|
|
444
456
|
it('updates references', () => {
|
|
@@ -461,20 +473,21 @@ describe('@position-try', () => {
|
|
|
461
473
|
|
|
462
474
|
expect(rewritten).toMatchInlineSnapshot(`
|
|
463
475
|
"/* foo.css */
|
|
464
|
-
@layer components {
|
|
476
|
+
@layer components {
|
|
465
477
|
|
|
466
|
-
|
|
467
|
-
|
|
468
|
-
|
|
469
|
-
|
|
470
|
-
|
|
478
|
+
@position-try --custom-left__postfix {
|
|
479
|
+
position-area: left;
|
|
480
|
+
width: 100px;
|
|
481
|
+
margin-right: 10px;
|
|
482
|
+
}
|
|
471
483
|
|
|
472
|
-
|
|
473
|
-
|
|
474
|
-
|
|
475
|
-
|
|
476
|
-
}
|
|
477
|
-
"
|
|
484
|
+
.infobox_postfix {
|
|
485
|
+
position-try-fallbacks:
|
|
486
|
+
--custom-left__postfix;
|
|
487
|
+
}
|
|
488
|
+
}
|
|
489
|
+
"
|
|
490
|
+
`);
|
|
478
491
|
});
|
|
479
492
|
});
|
|
480
493
|
|
|
@@ -494,15 +507,16 @@ describe('@property', () => {
|
|
|
494
507
|
|
|
495
508
|
expect(rewritten).toMatchInlineSnapshot(`
|
|
496
509
|
"/* foo.css */
|
|
497
|
-
@layer components {
|
|
510
|
+
@layer components {
|
|
498
511
|
|
|
499
512
|
@property --item-size__postfix {
|
|
500
513
|
syntax: "<percentage>";
|
|
501
514
|
inherits: true;
|
|
502
515
|
initial-value: 40%;
|
|
503
516
|
}
|
|
504
|
-
}
|
|
505
|
-
"
|
|
517
|
+
}
|
|
518
|
+
"
|
|
519
|
+
`);
|
|
506
520
|
});
|
|
507
521
|
|
|
508
522
|
it('updates references', () => {
|
|
@@ -537,7 +551,7 @@ describe('@property', () => {
|
|
|
537
551
|
|
|
538
552
|
expect(rewritten).toMatchInlineSnapshot(`
|
|
539
553
|
"/* foo.css */
|
|
540
|
-
@layer components {
|
|
554
|
+
@layer components {
|
|
541
555
|
|
|
542
556
|
@property --item-size__postfix {
|
|
543
557
|
syntax: "<percentage>";
|
|
@@ -561,8 +575,9 @@ describe('@property', () => {
|
|
|
561
575
|
height: var(--item-size__postfix);
|
|
562
576
|
background-color: var(--item-color);
|
|
563
577
|
}
|
|
564
|
-
}
|
|
565
|
-
"
|
|
578
|
+
}
|
|
579
|
+
"
|
|
580
|
+
`);
|
|
566
581
|
});
|
|
567
582
|
});
|
|
568
583
|
|
|
@@ -584,6 +599,7 @@ describe('@supports', () => {
|
|
|
584
599
|
@supports (transform-origin: 5% 5%) {}
|
|
585
600
|
@supports selector(h2 > p) {}
|
|
586
601
|
}
|
|
587
|
-
"
|
|
602
|
+
"
|
|
603
|
+
`);
|
|
588
604
|
});
|
|
589
605
|
});
|
package/src/lib/css/utils.js
CHANGED
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import { existsSync, readFileSync } from 'fs';
|
|
2
2
|
import postcss from 'postcss';
|
|
3
|
+
import scssSyntax from 'postcss-scss';
|
|
3
4
|
import parser from 'postcss-selector-parser';
|
|
4
5
|
|
|
5
6
|
import { md5 } from '../path/md5.js';
|
|
@@ -39,17 +40,25 @@ export function getCSSInfo(cssPath) {
|
|
|
39
40
|
* to see if we need to leave it alone or transform it
|
|
40
41
|
*
|
|
41
42
|
* @param {string} css the CSS's contents
|
|
43
|
+
* @param {string} [lang] optional language hint (e.g. 'scss', 'sass', 'less')
|
|
42
44
|
* @return {{ classes: Set<string>, tags: Set<string>, css: string, id: string }}
|
|
43
45
|
*/
|
|
44
|
-
export function getCSSContentInfo(css) {
|
|
46
|
+
export function getCSSContentInfo(css, lang) {
|
|
45
47
|
const classes = new Set();
|
|
46
48
|
const tags = new Set();
|
|
47
49
|
|
|
48
|
-
const
|
|
50
|
+
const parseOptions =
|
|
51
|
+
lang === 'scss' || lang === 'sass' ? { syntax: scssSyntax } : {};
|
|
52
|
+
|
|
53
|
+
const ast = postcss.parse(css, parseOptions);
|
|
54
|
+
|
|
55
|
+
const isScss = lang === 'scss' || lang === 'sass';
|
|
49
56
|
|
|
50
57
|
ast.walk((node) => {
|
|
51
58
|
if (node.type === 'rule') {
|
|
52
|
-
|
|
59
|
+
const selector = isScss ? resolveNestedSassSelector(node) : node.selector;
|
|
60
|
+
|
|
61
|
+
getClassesAndTags(selector, classes, tags);
|
|
53
62
|
}
|
|
54
63
|
});
|
|
55
64
|
|
|
@@ -58,6 +67,36 @@ export function getCSSContentInfo(css) {
|
|
|
58
67
|
return { classes, tags, css, id };
|
|
59
68
|
}
|
|
60
69
|
|
|
70
|
+
/**
|
|
71
|
+
* Resolves a nested SCSS selector by substituting `&` with the fully-resolved
|
|
72
|
+
* parent selector, recursively. This converts e.g. `&--modifier` (child of
|
|
73
|
+
* `.block`) into `.block--modifier`, and handles arbitrary nesting depth so
|
|
74
|
+
* that `&--modifier` inside `&--modifier` inside `.block` yields
|
|
75
|
+
* `.block--modifier--modifier`.
|
|
76
|
+
*
|
|
77
|
+
* @param {import('postcss').Rule} node
|
|
78
|
+
* @return {string}
|
|
79
|
+
*/
|
|
80
|
+
function resolveNestedSassSelector(node) {
|
|
81
|
+
const { selector } = node;
|
|
82
|
+
|
|
83
|
+
if (!selector.includes('&')) {
|
|
84
|
+
return selector;
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
const parent = node.parent;
|
|
88
|
+
|
|
89
|
+
if (!parent || parent.type !== 'rule') {
|
|
90
|
+
// No parent rule — `&` has nothing to substitute, return as-is
|
|
91
|
+
return selector;
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
// Recursively resolve the parent first, then substitute into this selector
|
|
95
|
+
const resolvedParent = resolveNestedSassSelector(parent);
|
|
96
|
+
|
|
97
|
+
return selector.replace(/&/g, resolvedParent);
|
|
98
|
+
}
|
|
99
|
+
|
|
61
100
|
function getClassesAndTags(sel, classes, tags) {
|
|
62
101
|
const transform = (sls) => {
|
|
63
102
|
sls.walk((selector) => {
|
|
@@ -85,4 +124,69 @@ if (import.meta.vitest) {
|
|
|
85
124
|
expect(tags.size).to.equal(1);
|
|
86
125
|
expect([...tags]).to.have.members(['div']);
|
|
87
126
|
});
|
|
127
|
+
|
|
128
|
+
it('should parse SCSS nesting syntax without crashing when lang=scss', function () {
|
|
129
|
+
const scss = `
|
|
130
|
+
$base-color: #c6538c;
|
|
131
|
+
$border-dark: rgba($base-color, 0.88);
|
|
132
|
+
|
|
133
|
+
.parent {
|
|
134
|
+
&:hover { color: $base-color; }
|
|
135
|
+
.child { border: 1px solid $border-dark; }
|
|
136
|
+
color: red;
|
|
137
|
+
}
|
|
138
|
+
`;
|
|
139
|
+
const { classes } = getCSSContentInfo(scss, 'scss');
|
|
140
|
+
|
|
141
|
+
expect([...classes]).toMatchInlineSnapshot(`
|
|
142
|
+
[
|
|
143
|
+
"parent",
|
|
144
|
+
"child",
|
|
145
|
+
]
|
|
146
|
+
`);
|
|
147
|
+
});
|
|
148
|
+
|
|
149
|
+
it('should parse SCSS nesting syntax without crashing when lang=sass', function () {
|
|
150
|
+
const scss = `
|
|
151
|
+
$base-color: green;
|
|
152
|
+
.block {
|
|
153
|
+
&--modifier { color: $base-color; }
|
|
154
|
+
}
|
|
155
|
+
`;
|
|
156
|
+
const { classes } = getCSSContentInfo(scss, 'sass');
|
|
157
|
+
|
|
158
|
+
expect([...classes]).toMatchInlineSnapshot(`
|
|
159
|
+
[
|
|
160
|
+
"block",
|
|
161
|
+
"block--modifier",
|
|
162
|
+
]
|
|
163
|
+
`);
|
|
164
|
+
});
|
|
165
|
+
|
|
166
|
+
it('should parse SCSS deeply nested BEM when lang=sass', function () {
|
|
167
|
+
const scss = `
|
|
168
|
+
$base-color: green;
|
|
169
|
+
.block {
|
|
170
|
+
&--modifier {
|
|
171
|
+
color: $base-color;
|
|
172
|
+
&--modifier {
|
|
173
|
+
color: $base-color;
|
|
174
|
+
&--modifier {
|
|
175
|
+
color: $base-color;
|
|
176
|
+
}
|
|
177
|
+
}
|
|
178
|
+
}
|
|
179
|
+
}
|
|
180
|
+
`;
|
|
181
|
+
const { classes } = getCSSContentInfo(scss, 'sass');
|
|
182
|
+
|
|
183
|
+
expect([...classes]).toMatchInlineSnapshot(`
|
|
184
|
+
[
|
|
185
|
+
"block",
|
|
186
|
+
"block--modifier",
|
|
187
|
+
"block--modifier--modifier",
|
|
188
|
+
"block--modifier--modifier--modifier",
|
|
189
|
+
]
|
|
190
|
+
`);
|
|
191
|
+
});
|
|
88
192
|
}
|
package/src/lib/request.js
CHANGED
|
@@ -19,9 +19,16 @@ export const request = {
|
|
|
19
19
|
* @param {string} cssHash the hash of the CSS contents
|
|
20
20
|
* @param {string} postfix the hash of the file that _includes_ the linked file
|
|
21
21
|
* @param {string} cssContents the contents of the CSS file
|
|
22
|
+
* @param {string} [lang] optional preprocessor language (e.g. 'scss', 'sass', 'less')
|
|
22
23
|
*/
|
|
23
|
-
create(cssHash, postfix, cssContents) {
|
|
24
|
-
|
|
24
|
+
create(cssHash, postfix, cssContents, lang) {
|
|
25
|
+
let url = `./${postfix}${SEP}${cssHash}.${KEY}?css=${encodeURIComponent(cssContents)}`;
|
|
26
|
+
|
|
27
|
+
if (lang) {
|
|
28
|
+
url += `&lang=${encodeURIComponent(lang)}`;
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
return url;
|
|
25
32
|
},
|
|
26
33
|
decode(request) {
|
|
27
34
|
let [left, qps] = request.split('?');
|
|
@@ -37,6 +44,7 @@ export const request = {
|
|
|
37
44
|
postfix,
|
|
38
45
|
css: search.get('css'),
|
|
39
46
|
from: search.get('from'),
|
|
47
|
+
lang: search.get('lang'),
|
|
40
48
|
};
|
|
41
49
|
},
|
|
42
50
|
},
|