Skip to content

Commit ff9580a

Browse files
jquenseevilebottnawi
authored andcommitted
feat: don't localize imported values in selectors (#13)
BREAKING CHANGE: don't localize imported values in selectors
1 parent ba6229a commit ff9580a

File tree

4 files changed

+134
-9
lines changed

4 files changed

+134
-9
lines changed

index.js

Lines changed: 39 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -3,9 +3,24 @@
33
const postcss = require('postcss');
44
const selectorParser = require('postcss-selector-parser');
55
const valueParser = require('postcss-value-parser');
6+
const { extractICSS } = require('icss-utils');
67

78
const isSpacing = node => node.type === 'combinator' && node.value === ' ';
89

10+
function getImportLocalAliases(icssImports) {
11+
const localAliases = new Map();
12+
Object.keys(icssImports).forEach(key => {
13+
Object.keys(icssImports[key]).forEach(prop => {
14+
localAliases.set(prop, icssImports[key][prop]);
15+
});
16+
});
17+
return localAliases;
18+
}
19+
20+
function maybeLocalizeValue(value, localAliasMap) {
21+
if (localAliasMap.has(value)) return value;
22+
}
23+
924
function normalizeNodeArray(nodes) {
1025
const array = [];
1126

@@ -25,7 +40,7 @@ function normalizeNodeArray(nodes) {
2540
return array;
2641
}
2742

28-
function localizeNode(rule, mode, options) {
43+
function localizeNode(rule, mode, localAliasMap) {
2944
const isScopePseudo = node =>
3045
node.value === ':local' || node.value === ':global';
3146

@@ -191,7 +206,14 @@ function localizeNode(rule, mode, options) {
191206
}
192207
case 'id':
193208
case 'class': {
194-
if (!context.global) {
209+
if (context.global) {
210+
break;
211+
}
212+
213+
const isImportedValue = localAliasMap.has(node.value);
214+
const isImportedWithExplicitScope = isImportedValue && context.explicit;
215+
216+
if (!isImportedValue || isImportedWithExplicitScope) {
195217
const innerNode = node.clone();
196218
innerNode.spaces = { before: '', after: '' };
197219

@@ -231,8 +253,10 @@ function localizeDeclNode(node, context) {
231253
switch (node.type) {
232254
case 'word':
233255
if (context.localizeNextItem) {
234-
node.value = ':local(' + node.value + ')';
235-
context.localizeNextItem = false;
256+
if (!context.localAliasMap.has(node.value)) {
257+
node.value = ':local(' + node.value + ')';
258+
context.localizeNextItem = false;
259+
}
236260
}
237261
break;
238262

@@ -360,6 +384,7 @@ function localizeAnimationShorthandDeclValues(decl, context) {
360384
options: context.options,
361385
global: context.global,
362386
localizeNextItem: shouldParseAnimationName && !context.global,
387+
localAliasMap: context.localAliasMap,
363388
};
364389
return localizeDeclNode(node, subContext);
365390
});
@@ -374,6 +399,7 @@ function localizeDeclValues(localize, decl, context) {
374399
options: context.options,
375400
global: context.global,
376401
localizeNextItem: localize && !context.global,
402+
localAliasMap: context.localAliasMap,
377403
};
378404
nodes[index] = localizeDeclNode(node, subContext);
379405
});
@@ -423,6 +449,9 @@ module.exports = postcss.plugin('postcss-modules-local-by-default', function(
423449
const globalMode = options && options.mode === 'global';
424450

425451
return function(css) {
452+
const { icssImports } = extractICSS(css, false);
453+
const localAliasMap = getImportLocalAliases(icssImports);
454+
426455
css.walkAtRules(function(atrule) {
427456
if (/keyframes$/i.test(atrule.name)) {
428457
const globalMatch = /^\s*:global\s*\((.+)\)\s*$/.exec(atrule.params);
@@ -440,10 +469,12 @@ module.exports = postcss.plugin('postcss-modules-local-by-default', function(
440469
atrule.params = localMatch[0];
441470
globalKeyframes = false;
442471
} else if (!globalMode) {
443-
atrule.params = ':local(' + atrule.params + ')';
472+
if (atrule.params && !localAliasMap.has(atrule.params))
473+
atrule.params = ':local(' + atrule.params + ')';
444474
}
445475
atrule.walkDecls(function(decl) {
446476
localizeDecl(decl, {
477+
localAliasMap,
447478
options: options,
448479
global: globalKeyframes,
449480
});
@@ -452,6 +483,7 @@ module.exports = postcss.plugin('postcss-modules-local-by-default', function(
452483
atrule.nodes.forEach(function(decl) {
453484
if (decl.type === 'decl') {
454485
localizeDecl(decl, {
486+
localAliasMap,
455487
options: options,
456488
global: globalMode,
457489
});
@@ -478,9 +510,10 @@ module.exports = postcss.plugin('postcss-modules-local-by-default', function(
478510
return;
479511
}
480512

481-
const context = localizeNode(rule, options.mode);
513+
const context = localizeNode(rule, options.mode, localAliasMap);
482514

483515
context.options = options;
516+
context.localAliasMap = localAliasMap;
484517

485518
if (pureMode && context.hasPureGlobals) {
486519
throw rule.error(

package.json

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,7 @@
2323
"trailingComma": "es5"
2424
},
2525
"dependencies": {
26+
"icss-utils": "^4.0.0",
2627
"postcss": "^7.0.6",
2728
"postcss-selector-parser": "^6.0.0",
2829
"postcss-value-parser": "^3.3.1"

test.js

Lines changed: 86 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -529,8 +529,92 @@ const tests = [
529529
},
530530
{
531531
should: 'not ignore custom property set',
532-
input: ':root { --title-align: center; --sr-only: { position: absolute; } }',
533-
expected: ':root { --title-align: center; --sr-only: { position: absolute; } }',
532+
input:
533+
':root { --title-align: center; --sr-only: { position: absolute; } }',
534+
expected:
535+
':root { --title-align: center; --sr-only: { position: absolute; } }',
536+
},
537+
/**
538+
* Imported aliases
539+
*/
540+
{
541+
should: 'not localize imported alias',
542+
input: `
543+
:import(foo) { a_value: some-value; }
544+
545+
.foo > .a_value { }
546+
`,
547+
expected: `
548+
:import(foo) { a_value: some-value; }
549+
550+
:local(.foo) > .a_value { }
551+
`,
552+
},
553+
{
554+
should: 'not localize nested imported alias',
555+
input: `
556+
:import(foo) { a_value: some-value; }
557+
558+
.foo > .a_value > .bar { }
559+
`,
560+
expected: `
561+
:import(foo) { a_value: some-value; }
562+
563+
:local(.foo) > .a_value > :local(.bar) { }
564+
`,
565+
},
566+
567+
{
568+
should: 'ignore imported in explicit local',
569+
input: `
570+
:import(foo) { a_value: some-value; }
571+
572+
:local(.a_value) { }
573+
`,
574+
expected: `
575+
:import(foo) { a_value: some-value; }
576+
577+
:local(.a_value) { }
578+
`,
579+
},
580+
{
581+
should: 'escape local context with explict global',
582+
input: `
583+
:import(foo) { a_value: some-value; }
584+
585+
:local .foo :global(.a_value) .bar { }
586+
`,
587+
expected: `
588+
:import(foo) { a_value: some-value; }
589+
590+
:local(.foo) .a_value :local(.bar) { }
591+
`,
592+
},
593+
{
594+
should: 'respect explicit local',
595+
input: `
596+
:import(foo) { a_value: some-value; }
597+
598+
.a_value :local .a_value .foo :global .a_value { }
599+
`,
600+
expected: `
601+
:import(foo) { a_value: some-value; }
602+
603+
.a_value :local(.a_value) :local(.foo) .a_value { }
604+
`,
605+
},
606+
{
607+
should: 'not localize imported animation-name',
608+
input: `
609+
:import(file) { a_value: some-value; }
610+
611+
.foo { animation-name: a_value; }
612+
`,
613+
expected: `
614+
:import(file) { a_value: some-value; }
615+
616+
:local(.foo) { animation-name: a_value; }
617+
`,
534618
},
535619
];
536620

yarn.lock

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1221,6 +1221,13 @@ iconv-lite@^0.4.24, iconv-lite@^0.4.4:
12211221
dependencies:
12221222
safer-buffer ">= 2.1.2 < 3"
12231223

1224+
icss-utils@^4.0.0:
1225+
version "4.0.0"
1226+
resolved "https://registry.yarnpkg.com/icss-utils/-/icss-utils-4.0.0.tgz#d52cf4bcdcfa1c45c2dbefb4ffdf6b00ef608098"
1227+
integrity sha512-bA/xGiwWM17qjllIs9X/y0EjsB7e0AV08F3OL8UPsoNkNRibIuu8f1eKTnQ8QO1DteKKTxTUAn+IEWUToIwGOA==
1228+
dependencies:
1229+
postcss "^7.0.5"
1230+
12241231
ignore-walk@^3.0.1:
12251232
version "3.0.1"
12261233
resolved "https://registry.yarnpkg.com/ignore-walk/-/ignore-walk-3.0.1.tgz#a83e62e7d272ac0e3b551aaa82831a19b69f82f8"
@@ -2098,7 +2105,7 @@ postcss-value-parser@^3.3.1:
20982105
resolved "https://registry.yarnpkg.com/postcss-value-parser/-/postcss-value-parser-3.3.1.tgz#9ff822547e2893213cf1c30efa51ac5fd1ba8281"
20992106
integrity sha512-pISE66AbVkp4fDQ7VHBwRNXzAAKJjw4Vw7nWI/+Q3vuly7SNfgYXvm6i5IgFylHGK5sP/xHAbB7N49OS4gWNyQ==
21002107

2101-
postcss@^7.0.6:
2108+
postcss@^7.0.5, postcss@^7.0.6:
21022109
version "7.0.14"
21032110
resolved "https://registry.yarnpkg.com/postcss/-/postcss-7.0.14.tgz#4527ed6b1ca0d82c53ce5ec1a2041c2346bbd6e5"
21042111
integrity sha512-NsbD6XUUMZvBxtQAJuWDJeeC4QFsmWsfozWxCJPWf3M55K9iu2iMDaKqyoOdTJ1R4usBXuxlVFAIo8rZPQD4Bg==

0 commit comments

Comments
 (0)