Skip to content

Commit

Permalink
Merge 60a3310 into 21cdc6c
Browse files Browse the repository at this point in the history
  • Loading branch information
jescalan committed Apr 5, 2017
2 parents 21cdc6c + 60a3310 commit 89638c8
Show file tree
Hide file tree
Showing 7 changed files with 1,485 additions and 1,226 deletions.
1 change: 1 addition & 0 deletions .npmignore
Original file line number Diff line number Diff line change
Expand Up @@ -5,3 +5,4 @@ coverage
.nyc_output
.travis.yml
yarn.lock
wallaby.js
17 changes: 6 additions & 11 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -44,32 +44,27 @@ By default, the css standard plugin pack includes:
Any of these plugins can be customized by passing the [options](#options) described below. You can also add additional postCSS plugins (like the popular [`lost`](https://github.com/peterramsing/lost) grid, for example) on top of this package:

```js
// app.js
const cssStandards = require('spike-css-standards')
const lost = require('lost')

// ...
postcss: (ctx) => {
const css = cssStandards({ webpack: ctx })
css.plugins.push(lost())
return css
},
// ...
const css = cssStandards()
css.plugins.push(lost())
```

### Options

| Name | Description | Default |
| ---- | ----------- | ------- |
| **root** | Root used to resolve `path`(s) from | If `webpack` option is provided, `options.context` |
| **path** | A path to a folder or an array of paths, telling postcss-import where to look for sss or css files to `@import`. | If `webpack` option is provided, `loaderContext.resourcePath` |
| **webpack** | Shortcut for webpack users to set the `root` and `path` options more easily. Pass webpack loader context. | |
| **root** | Root used to resolve `path`(s) from | |
| **path** | A path to a folder or an array of paths, telling postcss-import where to look for sss or css files to `@import`. | |
| **browsers** | Browser support provided to [autoprefixer](http://cssnext.io/usage/#browsers) | `> 1%, last 2 versions, Firefox ESR` |
| **features** | Enable or disable [cssnext features](http://cssnext.io/usage/#features) | |
| **warnForDuplicates** | Enable or disable [cssnext duplicate warnings](http://cssnext.io/usage/#warnforduplicates) | `true` |
| **rucksack** | Options passed directly to [rucksack](http://simplaio.github.io/rucksack/docs/#options) | |
| **parser** | custom css parser if desired. pass `false` to use the default css parser | `sugarss` |
| **minify** | Minifies the css output by removing excess spaces and line breaks | `false` |
| **appendPlugins** | Adds a single plugin or array of plugins after all the defaults | |
| **prependPlugins** | Adds a single plugin or array of plugins before all the defaults | |

### License & Contributing

Expand Down
45 changes: 35 additions & 10 deletions lib/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -3,36 +3,61 @@ let postcssImport = require('postcss-import')
let cssnext = require('postcss-cssnext')
let rucksack = require('rucksack-css')

/**
* Primary export, formats options and returns an object with intelligent
* defaults.
* @param {Object} [options={}] - options object
* @param {Function} [options.parser=sugarss] - if false, is set to undefined
* @param {Array|String} options.path - passed to import plugin
* @param {String} options.root - passed to import plugin
* @param {Array} options.browsers - passed to cssnext plugin
* @param {Object} options.features - passed to cssnext plugin
* @param {Boolean} options.warnForDuplicates - passed to cssnext plugin
* @param {Object} options.rucksack - passed to rucksack plugin
* @param {Boolean} options.minify - whether or not to add the minify plugin
* @return {Object} valid postcss options object
*/
module.exports = (options = {}) => {
// sugarss by default unless false or custom parser
let parser = options.parser || sugarss
if (options.parser === false) parser = undefined
options.path = options.path ? Array.prototype.concat(options.path) : []

// define root/path defaults if the webpack object is provided
if (options.webpack) {
options.root = options.webpack.options.context
options.path.push(options.webpack.resourcePath)
}

// standard options merge
const importOpt = selectiveMerge(options, ['root', 'path'])
const cssnextOpt = selectiveMerge(options, ['browsers', 'features', 'warnForDuplicates'])
const importOpt = selectKeys(options, ['root', 'path'])
const cssnextOpt = selectKeys(options, ['browsers', 'features', 'warnForDuplicates'])

// define normal plugin list
// define default plugin list
const plugins = [
postcssImport(importOpt),
cssnext(cssnextOpt),
rucksack(options.rucksack)
]

// append and prepend plugins if needed
if (options.appendPlugins) {
plugins.push(...Array.prototype.concat(options.appendPlugins))
}

if (options.prependPlugins) {
plugins.unshift(...Array.prototype.concat(options.prependPlugins))
}

// add cssnano if minify config present
if (options.minify) plugins.push(require('cssnano')())

return {parser, plugins}
}

function selectiveMerge (opts, optNames) {
/**
* Given an options object and an array of key names, return an object filtered
* to contain only the keys in the optNames array, if they exist on the options
* object.
* @param {Object} opts - full options object
* @param {Array} optNames - keys to filter
* @return {Object} object filtered for the specific keys
*/
function selectKeys (opts, optNames) {
return optNames.reduce((m, opt) => {
if (typeof opts[opt] !== 'undefined') { m[opt] = opts[opt] }; return m
}, {})
Expand Down
2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
{
"name": "spike-css-standards",
"description": "standard plugin pack for postcss",
"version": "0.2.0",
"version": "0.3.0-1",
"author": "Jeff Escalante",
"ava": {
"verbose": "true"
Expand Down
85 changes: 54 additions & 31 deletions test/index.js
Original file line number Diff line number Diff line change
@@ -1,44 +1,67 @@
const rewire = require('rewire')
const cssStandardsRewired = rewire('..')
const cssStandards = require('..')
const cssStandardsRewired = rewire('../lib')
const cssStandards = require('../lib')
const test = require('ava')

test('basic', (t) => {
cssStandardsRewired.__set__('postcssImport', (opts) => {
t.truthy(opts.root === 'test')
t.truthy(opts.path[0] === 'test/test1')
t.truthy(opts.path[1] === 'test/test2')
t.truthy(opts.path[2] === 'test') // webpack.resourcePath
})
test('passes parser opt correctly', (t) => {
const out = cssStandards({ parser: 'test' })
const out2 = cssStandards({ parser: false })
t.is(out.parser, 'test')
t.is(out2.parser, undefined)
})

cssStandardsRewired.__set__('cssnext', (opts) => {
t.truthy(opts.features === 'test')
t.truthy(opts.browsers === 'test')
t.truthy(opts.warnForDuplicates === 'test')
test('passes import opts correctly', (t) => {
const undo = cssStandardsRewired.__set__('postcssImport', (opts) => {
t.is(opts.root, 'test')
t.is(opts.path[0], 'test')
})
cssStandardsRewired({ root: 'test', path: 'test' })
undo()
})

cssStandardsRewired.__set__('rucksack', (opts) => {
t.truthy(opts === 'test')
test('passes cssnext opts correctly', (t) => {
const undo = cssStandardsRewired.__set__('cssnext', (opts) => {
t.is(opts.browsers, 'test')
t.is(opts.features, 'test')
t.is(opts.warnForDuplicates, 'test')
})

const out1 = cssStandardsRewired({
parser: false,
webpack: {
resourcePath: 'test',
options: { context: 'test' }
},
path: ['test/test1', 'test/test2'],
features: 'test',
cssStandardsRewired({
browsers: 'test',
warnForDuplicates: 'test',
rucksack: 'test'
features: 'test',
warnForDuplicates: 'test'
})
undo()
})

test('passes rucksack opts correctly', (t) => {
const undo = cssStandardsRewired.__set__('rucksack', (opts) => {
t.is(opts, 'test')
})
cssStandardsRewired({ rucksack: 'test' })
undo()
})

t.truthy(out1.plugins.length === 3)
t.falsy(out1.parser)
test('default plugins working', (t) => {
const out = cssStandards()
t.is(out.plugins.length, 3)
})

const out2 = cssStandards({ minify: true })
test('minify option working', (t) => {
const out = cssStandards({ minify: true })
t.is(out.plugins.length, 4)
t.is(out.plugins[out.plugins.length - 1].postcssPlugin, 'cssnano')
})

test('appendPlugins option', (t) => {
const out = cssStandards({ appendPlugins: ['test'] })
const out2 = cssStandards({ appendPlugins: 'test' })
t.truthy(out.plugins[out.plugins.length - 1] === 'test')
t.truthy(out2.plugins[out.plugins.length - 1] === 'test')
})

t.truthy(out2.parser)
t.truthy(out2.plugins.length === 4)
test('prependPlugins option', (t) => {
const out = cssStandards({ prependPlugins: ['test'] })
const out2 = cssStandards({ prependPlugins: 'test' })
t.truthy(out.plugins[0] === 'test')
t.truthy(out2.plugins[0] === 'test')
})
9 changes: 9 additions & 0 deletions wallaby.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
module.exports = function () {
return {
files: ['lib/**/*.js'],
tests: ['test/**/*.js'],
env: { type: 'node' },
testFramework: 'ava',
debug: true
}
}
Loading

0 comments on commit 89638c8

Please sign in to comment.