Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Sign up
Appearance settings

Commit 23b3560

Browse files
AlbertLuciantogajus
authored andcommitted
feat: add autoResolveMultiImports option (#234)
* feat: add autoResolveMultiImports option * test: add test cases for autoResolveMultiImports option * docs: add for autoResolveMultiImports option
1 parent 37fe030 commit 23b3560

File tree

30 files changed

+219
-58
lines changed

30 files changed

+219
-58
lines changed

‎README.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -199,6 +199,7 @@ Configure the options for the plugin within your `.babelrc` as follows:
199199
|`handleMissingStyleName`|`"throw"`, `"warn"`, `"ignore"`|Determines what should be done for undefined CSS modules (using a `styleName` for which there is no CSS module defined). Setting this option to `"ignore"` is equivalent to setting `errorWhenNotFound: false` in [react-css-modules](https://github.com/gajus/react-css-modules#errorwhennotfound). |`"throw"`|
200200
|`attributeNames`|`?AttributeNameMapType`|Refer to [Custom Attribute Mapping](#custom-attribute-mapping)|`{"styleName": "className"}`|
201201
|`skip`|`boolean`|Whether to apply plugin if no matching `attributeNames` found in the file|`false`|
202+
|`autoResolveMultipleImports`|`boolean`|Allow multiple anonymous imports if `styleName` is only in one of them.|`false`|
202203

203204
Missing a configuration? [Raise an issue](https://github.com/gajus/babel-plugin-react-css-modules/issues/new?title=New%20configuration:).
204205

‎src/createObjectExpression.js

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,9 @@ const createObjectExpression = (t: BabelTypes, object: InputObjectType): ObjectE
2828
newValue = createObjectExpression(t, value);
2929
} else if (typeof value === 'boolean') {
3030
newValue = t.booleanLiteral(value);
31+
} else if (typeof value === 'undefined') {
32+
// eslint-disable-next-line no-continue
33+
continue;
3134
} else {
3235
throw new TypeError('Unexpected type: ' + typeof value);
3336
}

‎src/getClassName.js

Lines changed: 58 additions & 39 deletions
Original file line numberDiff line numberDiff line change
@@ -3,18 +3,26 @@
33
import type {
44
StyleModuleMapType,
55
StyleModuleImportMapType,
6-
HandleMissingStyleNameOptionType
6+
HandleMissingStyleNameOptionType,
7+
GetClassNameOptionsType
78
} from './types';
89
import optionsDefaults from './schemas/optionsDefaults';
910

10-
type OptionsType = {|
11-
handleMissingStyleName: HandleMissingStyleNameOptionType
12-
|};
13-
1411
const isNamespacedStyleName = (styleName: string): boolean => {
1512
return styleName.indexOf('.') !== -1;
1613
};
1714

15+
const handleError = (message: string, handleMissingStyleName: HandleMissingStyleNameOptionType): null => {
16+
if (handleMissingStyleName === 'throw') {
17+
throw new Error(message);
18+
} else if (handleMissingStyleName === 'warn') {
19+
// eslint-disable-next-line no-console
20+
console.warn(message);
21+
}
22+
23+
return null;
24+
};
25+
1826
const getClassNameForNamespacedStyleName = (
1927
styleName: string,
2028
styleModuleImportMap: StyleModuleImportMapType,
@@ -30,47 +38,60 @@ const getClassNameForNamespacedStyleName = (
3038
optionsDefaults.handleMissingStyleName;
3139

3240
if (!moduleName) {
33-
if (handleMissingStyleName === 'throw') {
34-
throw new Error('Invalid style name: ' + styleName);
35-
} else if (handleMissingStyleName === 'warn') {
36-
// eslint-disable-next-line no-console
37-
console.warn('Invalid style name: ' + styleName);
38-
} else {
39-
return null;
40-
}
41+
return handleError('Invalid style name: ' + styleName, handleMissingStyleName);
4142
}
4243

4344
if (!styleModuleImportMap[importName]) {
44-
if (handleMissingStyleName === 'throw') {
45-
throw new Error('CSS module import does not exist: ' + importName);
46-
} else if (handleMissingStyleName === 'warn') {
47-
// eslint-disable-next-line no-console
48-
console.warn('CSS module import does not exist: ' + importName);
49-
} else {
50-
return null;
51-
}
45+
return handleError('CSS module import does not exist: ' + importName, handleMissingStyleName);
5246
}
5347

5448
if (!styleModuleImportMap[importName][moduleName]) {
55-
if (handleMissingStyleName === 'throw') {
56-
throw new Error('CSS module does not exist: ' + moduleName);
57-
} else if (handleMissingStyleName === 'warn') {
58-
// eslint-disable-next-line no-console
59-
console.warn('CSS module does not exist: ' + moduleName);
60-
} else {
61-
return null;
62-
}
49+
return handleError('CSS module does not exist: ' + moduleName, handleMissingStyleName);
6350
}
6451

6552
return styleModuleImportMap[importName][moduleName];
6653
};
6754

68-
export default (styleNameValue: string, styleModuleImportMap: StyleModuleImportMapType, options?: OptionsType): string => {
55+
const getClassNameFromMultipleImports = (
56+
styleName: string,
57+
styleModuleImportMap: StyleModuleImportMapType,
58+
handleMissingStyleNameOption?: HandleMissingStyleNameOptionType
59+
): ?string => {
60+
const handleMissingStyleName = handleMissingStyleNameOption ||
61+
optionsDefaults.handleMissingStyleName;
62+
63+
const importKeysWithMatches = Object.keys(styleModuleImportMap)
64+
.map((importKey) => {
65+
return styleModuleImportMap[importKey][styleName] && importKey;
66+
})
67+
.filter((importKey) => {
68+
return importKey;
69+
});
70+
71+
if (importKeysWithMatches.length > 1) {
72+
throw new Error('Cannot resolve styleName "' + styleName + '" because it is present in multiple imports:' +
73+
'\n\n\t' + importKeysWithMatches.join('\n\t') +
74+
'\n\nYou can resolve this by using a named import, e.g:' +
75+
'\n\n\timport foo from "' + importKeysWithMatches[0] + '";' +
76+
'\n\t<div styleName="foo.' + styleName + '" />' +
77+
'\n\n');
78+
}
79+
80+
if (importKeysWithMatches.length === 0) {
81+
return handleError('Could not resolve the styleName \'' + styleName + '\'.', handleMissingStyleName);
82+
}
83+
84+
return styleModuleImportMap[importKeysWithMatches[0]][styleName];
85+
};
86+
87+
export default (styleNameValue: string, styleModuleImportMap: StyleModuleImportMapType, options?: GetClassNameOptionsType): string => {
6988
const styleModuleImportMapKeys = Object.keys(styleModuleImportMap);
7089

7190
const handleMissingStyleName = options && options.handleMissingStyleName ||
7291
optionsDefaults.handleMissingStyleName;
7392

93+
const autoResolveMultipleImports = options && options.autoResolveMultipleImports;
94+
7495
if (!styleNameValue) {
7596
return '';
7697
}
@@ -91,20 +112,18 @@ export default (styleNameValue: string, styleModuleImportMap: StyleModuleImportM
91112
}
92113

93114
if (styleModuleImportMapKeys.length > 1) {
94-
throw new Error('Cannot use anonymous style name \'' + styleName +
95-
'\' with more than one stylesheet import.');
115+
if (!autoResolveMultipleImports) {
116+
throw new Error('Cannot use anonymous style name \'' + styleName +
117+
'\' with more than one stylesheet import without setting \'autoResolveMultipleImports\' to true.');
118+
}
119+
120+
return getClassNameFromMultipleImports(styleName, styleModuleImportMap, handleMissingStyleName);
96121
}
97122

98123
const styleModuleMap: StyleModuleMapType = styleModuleImportMap[styleModuleImportMapKeys[0]];
99124

100125
if (!styleModuleMap[styleName]) {
101-
if (handleMissingStyleName === 'throw') {
102-
throw new Error('Could not resolve the styleName \'' + styleName + '\'.');
103-
}
104-
if (handleMissingStyleName === 'warn') {
105-
// eslint-disable-next-line no-console
106-
console.warn('Could not resolve the styleName \'' + styleName + '\'.');
107-
}
126+
return handleError('Could not resolve the styleName \'' + styleName + '\'.', handleMissingStyleName);
108127
}
109128

110129
return styleModuleMap[styleName];

‎src/index.js

Lines changed: 8 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -212,19 +212,23 @@ export default ({
212212
}
213213

214214
const handleMissingStyleName = stats.opts && stats.opts.handleMissingStyleName || optionsDefaults.handleMissingStyleName;
215+
const autoResolveMultipleImports = stats.opts && stats.opts.autoResolveMultipleImports || optionsDefaults.autoResolveMultipleImports;
215216

216217
for (const attribute of attributes) {
217218
const destinationName = attributeNames[attribute.name.name];
218219

220+
const options = {
221+
autoResolveMultipleImports,
222+
handleMissingStyleName
223+
};
224+
219225
if (t.isStringLiteral(attribute.value)) {
220226
resolveStringLiteral(
221227
path,
222228
filenameMap[filename].styleModuleImportMap,
223229
attribute,
224230
destinationName,
225-
{
226-
handleMissingStyleName
227-
}
231+
options
228232
);
229233
} else if (t.isJSXExpressionContainer(attribute.value)) {
230234
if (!filenameMap[filename].importedHelperIndentifier) {
@@ -237,9 +241,7 @@ export default ({
237241
destinationName,
238242
filenameMap[filename].importedHelperIndentifier,
239243
filenameMap[filename].styleModuleImportMapIdentifier,
240-
{
241-
handleMissingStyleName
242-
}
244+
options
243245
);
244246
}
245247
}

‎src/replaceJsxExpressionContainer.js

Lines changed: 4 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -11,16 +11,12 @@ import BabelTypes, {
1111
jSXIdentifier
1212
} from '@babel/types';
1313
import type {
14-
HandleMissingStyleNameOptionType
14+
GetClassNameOptionsType
1515
} from './types';
1616
import conditionalClassMerge from './conditionalClassMerge';
1717
import createObjectExpression from './createObjectExpression';
1818
import optionsDefaults from './schemas/optionsDefaults';
1919

20-
type OptionsType = {|
21-
handleMissingStyleName: HandleMissingStyleNameOptionType
22-
|};
23-
2420
export default (
2521
t: BabelTypes,
2622
// eslint-disable-next-line flowtype/no-weak-types
@@ -29,7 +25,7 @@ export default (
2925
destinationName: string,
3026
importedHelperIndentifier: Identifier,
3127
styleModuleImportMapIdentifier: Identifier,
32-
options: OptionsType
28+
options: GetClassNameOptionsType
3329
): void => {
3430
const expressionContainerValue = sourceAttribute.value;
3531
const destinationAttribute = path.node.openingElement.attributes
@@ -50,7 +46,8 @@ export default (
5046

5147
// Only provide options argument if the options are something other than default
5248
// This helps save a few bits in the generated user code
53-
if (options.handleMissingStyleName !== optionsDefaults.handleMissingStyleName) {
49+
if (options.handleMissingStyleName !== optionsDefaults.handleMissingStyleName ||
50+
options.autoResolveMultipleImports !== optionsDefaults.autoResolveMultipleImports) {
5451
args.push(createObjectExpression(t, options));
5552
}
5653

‎src/resolveStringLiteral.js

Lines changed: 2 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -10,13 +10,9 @@ import conditionalClassMerge from './conditionalClassMerge';
1010
import getClassName from './getClassName';
1111
import type {
1212
StyleModuleImportMapType,
13-
HandleMissingStyleNameOptionType
13+
GetClassNameOptionsType
1414
} from './types';
1515

16-
type OptionsType = {|
17-
handleMissingStyleName: HandleMissingStyleNameOptionType
18-
|};
19-
2016
/**
2117
* Updates the className value of a JSX element using a provided styleName attribute.
2218
*/
@@ -25,7 +21,7 @@ export default (
2521
styleModuleImportMap: StyleModuleImportMapType,
2622
sourceAttribute: JSXAttribute,
2723
destinationName: string,
28-
options: OptionsType
24+
options: GetClassNameOptionsType
2925
): void => {
3026
const resolvedStyleName = getClassName(sourceAttribute.value.value, styleModuleImportMap, options);
3127

‎src/schemas/optionsSchema.json

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -72,6 +72,9 @@
7272
},
7373
"skip": {
7474
"type": "boolean"
75+
},
76+
"autoResolveMultipleImports": {
77+
"type": "boolean"
7578
}
7679
},
7780
"type": "object"

‎src/types.js

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,3 +13,8 @@ export type GenerateScopedNameType = (localName: string, resourcePath: string) =
1313
export type GenerateScopedNameConfigurationType = GenerateScopedNameType | string;
1414

1515
export type HandleMissingStyleNameOptionType = 'throw' | 'warn' | 'ignore';
16+
17+
export type GetClassNameOptionsType = {|
18+
handleMissingStyleName: HandleMissingStyleNameOptionType,
19+
autoResolveMultipleImports: boolean
20+
|};
Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
.a {}
2+
3+
.b {}
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
.b {}

0 commit comments

Comments
(0)

AltStyle によって変換されたページ (->オリジナル) /