2017-08-26 14:36:40 -05:00
import _ from 'lodash'
2017-11-04 01:32:25 -05:00
import postcss from 'postcss'
2017-10-06 15:40:40 -04:00
import escapeClassName from '../util/escapeClassName'
function normalizeClassNames ( classNames ) {
2017-11-04 00:35:59 -05:00
return classNames . map ( className => {
2017-10-06 15:40:40 -04:00
return ` . ${ escapeClassName ( _ . trimStart ( className , '.' ) ) } `
} )
}
2017-08-25 16:02:12 -05:00
2017-11-10 12:18:20 -05:00
function findMixin ( css , mixin , onError ) {
const matches = [ ]
css . walkRules ( rule => {
if ( rule . selectors . includes ( mixin ) ) {
if ( rule . parent . type !== 'root' ) {
2017-11-16 08:16:59 -05:00
// prettier-ignore
onError ( ` \` @apply \` cannot be used with ${ mixin } because ${ mixin } is nested inside of an at-rule (@ ${ rule . parent . name } ). ` )
2017-11-10 12:18:20 -05:00
}
matches . push ( rule )
}
} )
2017-11-16 07:51:56 -05:00
if ( _ . isEmpty ( matches ) ) {
2017-11-16 08:16:59 -05:00
// prettier-ignore
2017-11-13 11:28:31 -05:00
onError ( ` \` @apply \` cannot be used with ${ mixin } because ${ mixin } either does not exist, or it's actual definition includes a pseudo-class like :hover, :active, etc. ` )
2017-11-10 12:18:20 -05:00
}
2017-11-16 07:54:40 -05:00
if ( matches . length > 1 ) {
2017-11-16 08:16:59 -05:00
// prettier-ignore
2017-11-16 07:54:40 -05:00
onError ( ` \` @apply \` cannot be used with ${ mixin } because ${ mixin } is included in multiple rulesets. ` )
}
2017-11-10 12:18:20 -05:00
return _ . flatten ( matches . map ( match => match . clone ( ) . nodes ) )
}
2017-11-04 01:32:25 -05:00
export default function ( ) {
2017-11-04 00:35:59 -05:00
return function ( css ) {
2017-11-04 01:32:25 -05:00
css . walkRules ( rule => {
2017-08-26 11:26:38 -04:00
rule . walkAtRules ( 'apply' , atRule => {
2017-10-06 15:40:40 -04:00
const mixins = normalizeClassNames ( postcss . list . space ( atRule . params ) )
2017-08-25 16:02:12 -05:00
2017-10-06 15:40:40 -04:00
/ *
* Don ' t wreck CSSNext - style @ apply rules :
* http : //cssnext.io/features/#custom-properties-set-apply
*
* These are deprecated in CSSNext but still playing it safe for now .
* We might consider renaming this at - rule .
* /
2017-08-26 11:26:38 -04:00
const [ customProperties , classes ] = _ . partition ( mixins , mixin => {
return _ . startsWith ( mixin , '--' )
} )
2017-08-25 16:02:12 -05:00
2017-08-26 11:26:38 -04:00
const decls = _ . flatMap ( classes , mixin => {
2017-11-10 12:18:20 -05:00
return findMixin ( css , mixin , message => {
throw atRule . error ( message )
2017-08-26 11:26:38 -04:00
} )
} )
2017-08-25 16:02:12 -05:00
2017-08-28 11:26:17 -04:00
atRule . before ( decls )
2017-08-25 16:02:12 -05:00
2017-08-26 11:26:38 -04:00
atRule . params = customProperties . join ( ' ' )
2017-08-25 16:02:12 -05:00
2017-08-26 11:26:38 -04:00
if ( _ . isEmpty ( customProperties ) ) {
atRule . remove ( )
}
} )
} )
}
2017-11-03 09:54:15 -04:00
}