Skip to content

Commit 4471b98

Browse files
committed
Fix icss-composed and icss-value contract combination
1 parent 612b7b6 commit 4471b98

File tree

3 files changed

+94
-99
lines changed

3 files changed

+94
-99
lines changed

package.json

+1
Original file line numberDiff line numberDiff line change
@@ -57,6 +57,7 @@
5757
"css-selector-tokenizer": "^0.7.0",
5858
"generic-names": "^1.0.2",
5959
"icss-utils": "^3.0.1",
60+
"lodash": "^4.17.4",
6061
"postcss": "^6.0.2"
6162
},
6263
"devDependencies": {

src/index.js

+31-18
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@ import postcss from "postcss";
33
import Tokenizer from "css-selector-tokenizer";
44
import { extractICSS, createICSSRules } from "icss-utils";
55
import genericNames from "generic-names";
6+
import fromPairs from "lodash/fromPairs";
67

78
const plugin = "postcss-icss-selectors";
89

@@ -111,18 +112,15 @@ const walkRules = (css, callback) => {
111112
});
112113
};
113114

114-
const addExports = (css, aliases) => {
115-
const { icssImports, icssExports } = extractICSS(css);
116-
const exports = Object.assign({}, icssExports, aliases);
117-
css.prepend(createICSSRules(icssImports, exports));
118-
};
119-
120115
const getMessages = aliases =>
121-
Object.keys(aliases)
122-
.map(name => ({ plugin, type: "icss-scoped", name, value: aliases[name] }))
123-
.reduce((acc, msg) => [...acc, msg], []);
124-
125-
const isValue = (messages, name) =>
116+
Object.keys(aliases).map(name => ({
117+
plugin,
118+
type: "icss-scoped",
119+
name,
120+
value: aliases[name]
121+
}));
122+
123+
const getValue = (messages, name) =>
126124
messages.find(msg => msg.type === "icss-value" && msg.value === name);
127125

128126
const isRedeclared = (messages, name) =>
@@ -150,30 +148,43 @@ const composeAliases = (aliases, messages) =>
150148
{}
151149
);
152150

151+
const mapMessages = (messages, type) =>
152+
fromPairs(
153+
messages.filter(msg => msg.type === type).map(msg => [msg.name, msg.value])
154+
);
155+
156+
const composeExports = messages => {
157+
const composed = messages.filter(msg => msg.type === "icss-composed");
158+
const values = mapMessages(messages, "icss-value");
159+
const scoped = mapMessages(messages, "icss-scoped");
160+
const aliases = Object.assign({}, scoped, values);
161+
return composeAliases(aliases, composed);
162+
};
163+
153164
module.exports = postcss.plugin(plugin, (options = {}) => (css, result) => {
165+
const { icssImports, icssExports } = extractICSS(css);
154166
const generateScopedName =
155167
options.generateScopedName ||
156168
genericNames("[name]__[local]---[hash:base64:5]");
157169
const input = (css && css.source && css.source.input) || {};
158-
const composedMessages = result.messages.filter(
159-
msg => msg.type === "icss-composed"
160-
);
161170
const aliases = {};
162171
walkRules(css, rule => {
163172
const getAlias = name => {
164173
if (aliases[name]) {
165174
return aliases[name];
166175
}
167176
// icss-value contract
168-
if (isValue(result.messages, name)) {
177+
const valueMsg = getValue(result.messages, name);
178+
if (valueMsg) {
179+
aliases[valueMsg.name] = name;
169180
return name;
170181
}
171182
const alias = generateScopedName(name, input.from, input.css);
183+
aliases[name] = alias;
172184
// icss-scoped contract
173185
if (isRedeclared(result.messages, name)) {
174186
result.warn(`'${name}' already declared`, { node: rule });
175187
}
176-
aliases[name] = alias;
177188
return alias;
178189
};
179190
try {
@@ -187,6 +198,8 @@ module.exports = postcss.plugin(plugin, (options = {}) => (css, result) => {
187198
}
188199
});
189200
result.messages.push(...getMessages(aliases));
190-
// icss-composed contract
191-
addExports(css, composeAliases(aliases, composedMessages));
201+
// contracts
202+
const composedExports = composeExports(result.messages);
203+
const exports = Object.assign({}, icssExports, composedExports);
204+
css.prepend(createICSSRules(icssImports, exports));
192205
});

test/test.js

+62-81
Original file line numberDiff line numberDiff line change
@@ -40,16 +40,23 @@ const runMessages = ({
4040
plugin({ generateScopedName })
4141
]).process(strip(fixture));
4242
return processor.then(result => {
43-
expect(result.messages.filter(msg => msg.type !== "warning")).toEqual(
44-
outputMessages
45-
);
46-
expect(result.warnings().map(msg => msg.text)).toEqual(warnings);
4743
if (expected) {
4844
expect(result.css).toEqual(strip(expected));
4945
}
46+
expect(result.warnings().map(msg => msg.text)).toEqual(warnings);
47+
expect(result.messages.filter(msg => msg.type !== "warning")).toEqual(
48+
outputMessages
49+
);
5050
});
5151
};
5252

53+
const getMsg = (name, value) => ({
54+
plugin: "postcss-icss-selectors",
55+
type: "icss-scoped",
56+
name,
57+
value
58+
});
59+
5360
test("scope selectors", () => {
5461
return runCSS({
5562
fixture: `
@@ -788,24 +795,9 @@ test("icss-composed contract", () => {
788795
inputMessages,
789796
outputMessages: [
790797
...inputMessages,
791-
{
792-
plugin: "postcss-icss-selectors",
793-
type: "icss-scoped",
794-
name: "foo",
795-
value: "__scope__foo"
796-
},
797-
{
798-
plugin: "postcss-icss-selectors",
799-
type: "icss-scoped",
800-
name: "bar",
801-
value: "__scope__bar"
802-
},
803-
{
804-
plugin: "postcss-icss-selectors",
805-
type: "icss-scoped",
806-
name: "baz",
807-
value: "__scope__baz"
808-
}
798+
getMsg("foo", "__scope__foo"),
799+
getMsg("bar", "__scope__bar"),
800+
getMsg("baz", "__scope__baz")
809801
]
810802
});
811803
});
@@ -842,36 +834,11 @@ test("icss-composed contract with local dependencies", () => {
842834
inputMessages,
843835
outputMessages: [
844836
...inputMessages,
845-
{
846-
plugin: "postcss-icss-selectors",
847-
type: "icss-scoped",
848-
name: "foo",
849-
value: "__scope__foo"
850-
},
851-
{
852-
plugin: "postcss-icss-selectors",
853-
type: "icss-scoped",
854-
name: "bar",
855-
value: "__scope__bar"
856-
},
857-
{
858-
plugin: "postcss-icss-selectors",
859-
type: "icss-scoped",
860-
name: "baz",
861-
value: "__scope__baz"
862-
},
863-
{
864-
plugin: "postcss-icss-selectors",
865-
type: "icss-scoped",
866-
name: "tar",
867-
value: "__scope__tar"
868-
},
869-
{
870-
plugin: "postcss-icss-selectors",
871-
type: "icss-scoped",
872-
name: "doo",
873-
value: "__scope__doo"
874-
}
837+
getMsg("foo", "__scope__foo"),
838+
getMsg("bar", "__scope__bar"),
839+
getMsg("baz", "__scope__baz"),
840+
getMsg("tar", "__scope__tar"),
841+
getMsg("doo", "__scope__doo")
875842
]
876843
});
877844
});
@@ -897,36 +864,16 @@ test("icss-composed contract with recursive local composition", () => {
897864
inputMessages,
898865
outputMessages: [
899866
...inputMessages,
900-
{
901-
plugin: "postcss-icss-selectors",
902-
type: "icss-scoped",
903-
name: "foo",
904-
value: "__scope__foo"
905-
},
906-
{
907-
plugin: "postcss-icss-selectors",
908-
type: "icss-scoped",
909-
name: "bar",
910-
value: "__scope__bar"
911-
}
867+
getMsg("foo", "__scope__foo"),
868+
getMsg("bar", "__scope__bar")
912869
]
913870
});
914871
});
915872

916873
test("icss-value contract", () => {
917874
const inputMessages = [
918-
{
919-
plugin: "previous-plugin",
920-
type: "icss-value",
921-
name: "foo",
922-
value: "__declared__foo"
923-
},
924-
{
925-
plugin: "previous-plugin",
926-
type: "icss-value",
927-
name: "bar",
928-
value: "__declared__bar"
929-
}
875+
{ type: "icss-value", name: "foo", value: "__declared__foo" },
876+
{ type: "icss-value", name: "bar", value: "__declared__bar" }
930877
];
931878
return runMessages({
932879
fixture: `
@@ -940,6 +887,7 @@ test("icss-value contract", () => {
940887
expected: `
941888
:export {
942889
foo: __declared__foo;
890+
bar: __declared__bar;
943891
baz: __scope__baz
944892
}
945893
.__declared__foo {}
@@ -949,12 +897,45 @@ test("icss-value contract", () => {
949897
inputMessages,
950898
outputMessages: [
951899
...inputMessages,
952-
{
953-
plugin: "postcss-icss-selectors",
954-
type: "icss-scoped",
955-
name: "baz",
956-
value: "__scope__baz"
900+
getMsg("foo", "__declared__foo"),
901+
getMsg("bar", "__declared__bar"),
902+
getMsg("baz", "__scope__baz")
903+
]
904+
});
905+
});
906+
907+
test("icss-value and icss-composed together", () => {
908+
const inputMessages = [
909+
{ type: "icss-composed", name: "bar", value: "foo" },
910+
{ type: "icss-value", name: "foo", value: "__value__foo" }
911+
];
912+
return runMessages({
913+
fixture: `
914+
:import('path') {
915+
foo: __value__foo
916+
}
917+
:export {
918+
foo: __value__foo
957919
}
920+
.__value__foo {}
921+
.bar {}
922+
`,
923+
expected: `
924+
:import('path') {
925+
foo: __value__foo
926+
}
927+
:export {
928+
foo: __value__foo;
929+
bar: __scope__bar __value__foo
930+
}
931+
.__value__foo {}
932+
.__scope__bar {}
933+
`,
934+
inputMessages,
935+
outputMessages: [
936+
...inputMessages,
937+
getMsg("foo", "__value__foo"),
938+
getMsg("bar", "__scope__bar")
958939
]
959940
});
960941
});

0 commit comments

Comments
 (0)