Extract function for generating modules

Fully parameterized, makes it easy to test module options behavior
without testing against the entire default module list.
This commit is contained in:
Adam Wathan 2017-11-23 15:00:52 -05:00
parent 0a6c4cc5c6
commit 936a4eeefd
2 changed files with 148 additions and 0 deletions

View File

@ -0,0 +1,130 @@
import generateModules from '../src/util/generateModules'
import defineClasses from '../src/util/defineClasses'
function textAlign() {
return defineClasses({
'text-left': { 'text-align': 'left' },
'text-right': { 'text-align': 'right' },
'text-center': { 'text-align': 'center' },
})
}
function display() {
return defineClasses({
'block': { 'display': 'block' },
'inline': { 'display': 'inline' },
'inline-block': { 'display': 'inline-block' },
})
}
function borderStyle() {
return defineClasses({
'border-solid': { 'border-style': 'solid' },
'border-dashed': { 'border-style': 'dashed' },
'border-dotted': { 'border-style': 'dotted' },
})
}
test('an empty variants list generates a @variants at-rule with no parameters', () => {
const result = generateModules([
{ name: 'textAlign', generator: textAlign },
], {
textAlign: [],
})
const expected = `
@variants {
.text-left { text-align: left }
.text-right { text-align: right }
.text-center { text-align: center }
}
`
expect(result.toString()).toMatchCss(expected)
})
test('a `false` variants list generates no output', () => {
const result = generateModules([
{ name: 'textAlign', generator: textAlign },
], {
textAlign: false,
})
expect(result.toString()).toMatchCss('')
})
test('specified variants are included in the @variants at-rule', () => {
const result = generateModules([
{ name: 'textAlign', generator: textAlign },
], {
textAlign: ['responsive', 'hover'],
})
const expected = `
@variants responsive, hover {
.text-left { text-align: left }
.text-right { text-align: right }
.text-center { text-align: center }
}
`
expect(result.toString()).toMatchCss(expected)
})
test('options must provide variants for every module', () => {
expect(() => {
generateModules([
{ name: 'textAlign', generator: textAlign },
{ name: 'display', generator: display },
], {
textAlign: [],
})
}).toThrow()
})
test('variants can be different for each module', () => {
const result = generateModules([
{ name: 'textAlign', generator: textAlign },
{ name: 'display', generator: display },
{ name: 'borderStyle', generator: borderStyle },
], {
textAlign: [],
display: false,
borderStyle: ['responsive', 'hover', 'focus']
})
const expected = `
@variants {
.text-left { text-align: left }
.text-right { text-align: right }
.text-center { text-align: center }
}
@variants responsive, hover, focus {
.border-solid { border-style: solid }
.border-dashed { border-style: dashed }
.border-dotted { border-style: dotted }
}
`
expect(result.toString()).toMatchCss(expected)
})
test('generators can reference the generatorOptions object', () => {
const result = generateModules([{
name: 'parameterized',
generator: (generatorParams) => {
return defineClasses({
'foo': { 'color': generatorParams.color },
})
}
}], {
parameterized: [],
}, {
color: 'blue'
})
const expected = `
@variants {
.foo { color: blue }
}
`
expect(result.toString()).toMatchCss(expected)
})

View File

@ -0,0 +1,18 @@
import _ from 'lodash'
import postcss from 'postcss'
import wrapWithVariants from '../util/wrapWithVariants'
export default function(modules, moduleOptions, generatorOptions = {}) {
modules.forEach(module => {
if (! _.has(moduleOptions, module.name)) {
throw new Error(`Module \`${module.name}\` is missing from moduleOptions.`)
}
})
return postcss.root({
nodes: _(modules)
.reject(module => moduleOptions[module.name] === false)
.flatMap(module => wrapWithVariants(module.generator(generatorOptions), moduleOptions[module.name]))
.value()
})
}