11var defaults = require ( 'lodash/defaults' ) ;
2+ var mapKeys = require ( 'lodash/mapKeys' ) ;
3+ var isArray = require ( 'lodash/isArray' ) ;
4+ var omit = require ( 'lodash/omit' ) ;
5+ var isString = require ( 'lodash/isString' ) ;
6+ var isNumber = require ( 'lodash/isNumber' ) ;
27var loaderUtils = require ( 'loader-utils' ) ;
38var dangerousStyleValue = require ( 'react/lib/dangerousStyleValue' ) ;
49var hyphenateStyleName = require ( 'fbjs/lib/hyphenateStyleName' ) ;
@@ -15,38 +20,69 @@ function line(pretty) {
1520 return pretty ? '\n' : '' ;
1621}
1722
18- function parse ( config , styles , level ) {
19- level = level === undefined ? 0 : level ;
23+ function isProp ( value ) {
24+ return isArray ( value ) ?
25+ isProp ( value [ 0 ] , true ) :
26+ isString ( value ) || isNumber ( value ) ;
27+ }
28+
29+ function format ( config , value , name , level , inProp ) {
30+ level = level !== undefined ? level : 0 ;
2031
2132 var pretty = config . pretty ;
2233 var css = '' ;
34+ var indentLevel = level ;
2335
24- for ( var styleName in styles ) {
25- if ( ! styles . hasOwnProperty ( styleName ) ) {
26- continue ;
36+ if ( isArray ( value ) ) {
37+ for ( var i = 0 , len = value . length ; i < len ; i ++ ) {
38+ css += format ( config , value [ i ] , name , level , inProp ) ;
2739 }
40+ return css ;
41+ }
2842
29- // Extract the style definition or nested block.
30- var styleValue = styles [ styleName ] ;
31-
32- if ( styleValue === null ) {
33- continue ;
43+ if ( inProp ) {
44+ // The `name` and `value` args currently represent a css property and value.
45+ // Use React's css style processing funcs to generate css markup.
46+
47+ css += indent ( pretty , indentLevel ) + hyphenateStyleName ( name ) + ':' + space ( pretty ) ;
48+ css += dangerousStyleValue ( name , value ) + ';' + line ( pretty ) ;
49+ } else {
50+ // The `name` and `value` args currently represent a block containing css
51+ // properties or further nested blocks. Iterate through and parse
52+ // the nested values.
53+
54+ if ( name ) {
55+ // Unless we are in the global css scope (`name` is undefined), add a new
56+ // block to the markup.
57+ css += indent ( pretty , indentLevel ) + name + space ( pretty ) + '{' + line ( pretty ) ;
58+ indentLevel += 1 ;
3459 }
3560
36- // Remove whitespace from selector/block.
37- styleName = styleName . trim ( ) ;
61+ for ( var key in value ) {
62+ if ( ! value . hasOwnProperty ( key ) ) {
63+ continue ;
64+ }
3865
39- var block = Object . prototype . toString . call ( styleValue ) === '[object Object]' ;
66+ // Extract the style definition or nested block.
67+ var innerValue = value [ key ] ;
4068
41- if ( block ) {
42- css += indent ( pretty , level ) + styleName + space ( pretty ) + '{' + line ( pretty ) ;
43- css += parse ( config , styleValue , level + 1 ) ;
44- css += indent ( pretty , level ) + '}' + line ( pretty ) + line ( pretty ) ;
45- continue ;
69+ if ( innerValue === null ) {
70+ continue ;
71+ }
72+
73+ // Determine if the inner value is a block or a property.
74+ var innerIsProp = isProp ( innerValue ) ;
75+
76+ // Remove whitespace from selector/block/property.
77+ var innerName = key . trim ( ) ;
78+
79+ css += format ( config , innerValue , innerName , level + 1 , innerIsProp ) ;
4680 }
4781
48- css += indent ( pretty , level + 1 ) + hyphenateStyleName ( styleName ) + ':' + space ( pretty ) ;
49- css += dangerousStyleValue ( styleName , styleValue ) + ';' + line ( pretty ) ;
82+ if ( name ) {
83+ // Close the open block.
84+ css += indent ( pretty , level ) + '}' + line ( pretty ) + line ( pretty ) ;
85+ }
5086 }
5187
5288 return css ;
@@ -55,9 +91,45 @@ function parse(config, styles, level) {
5591module . exports = function ( content ) {
5692 this . cacheable ( ) ;
5793
58- config = defaults ( loaderUtils . getLoaderConfig ( this , 'jsCssLoader' ) , { pretty : process . env . NODE_ENV !== 'production' } ) ;
94+ config = defaults (
95+ loaderUtils . getLoaderConfig ( this , 'jsCssLoader' ) ,
96+ { pretty : process . env . NODE_ENV !== 'production' }
97+ ) ;
5998
6099 var styles = this . exec ( content , this . resourcePath ) ;
61100
62- return parse ( config , styles . __esModule ? styles . default : styles ) ;
101+ var css = '' ;
102+
103+ if ( styles . __esModule ) {
104+ // When using Babel, css classes can be defined as named es6 exports.
105+ //
106+ // e.x.
107+ //
108+ // ```
109+ // export default {
110+ // '.base': {
111+ // color: 'black'
112+ // }
113+ // };
114+ // ```
115+ //
116+ // is the same as
117+ //
118+ // ```
119+ // export const base = {
120+ // color: 'black'
121+ // };
122+ // ```
123+ return format ( config , [
124+ styles . default ,
125+ mapKeys (
126+ omit ( styles , 'default' ) ,
127+ function ( value , key ) {
128+ return '.' + key ;
129+ }
130+ ) ,
131+ ] ) ;
132+ }
133+
134+ return format ( config , styles ) ;
63135} ;
0 commit comments