diff options
author | Chris Rebert <code@rebertia.com> | 2015-01-19 04:10:51 +0300 |
---|---|---|
committer | Chris Rebert <code@rebertia.com> | 2015-01-19 04:12:56 +0300 |
commit | 5b3cac92b9abb5a150c6afc9efbba0da324186a6 (patch) | |
tree | 38485ce475b0d095aeed20e1b113661e3a21a708 | |
parent | 9d035dd8ce8301982f3f28b6017625c29f0f59da (diff) |
postprocessor => postprocessorFor()
Don't use postcss options because they can't be passed along when using grunt-postcss.
-rw-r--r-- | README.md | 9 | ||||
-rw-r--r-- | src/nodejs/index.js | 2 | ||||
-rw-r--r-- | src/nodejs/postprocessor.js | 76 | ||||
-rw-r--r-- | test/postprocessor_test.js | 38 |
4 files changed, 67 insertions, 58 deletions
@@ -99,7 +99,13 @@ Unofficially supported: ## API ### Node.js module; CSS postprocessor The npm module has the following properties: -* `postprocessor` - CSS postprocessor that transforms the source CSS as described above. A [PostCSS](https://github.com/postcss/postcss) processor object (that was returned from a call to the `postcss()` function). It requires that a `hoverSelectorPrefix` string option be provided; this string will be prepended to all selectors within `@media (hover: hover) {...}` blocks within the source CSS. +* `postprocessorFor` + * Arguments: an options object with one property: + * `hoverSelectorPrefix` - This string will be prepended to all selectors within `@media (hover: hover) {...}` blocks within the source CSS. + * Type: `string` + * Side-effects: none + * Return type: A [PostCSS](https://github.com/postcss/postcss) processor object (that was returned from a call to the `postcss()` function). + * Returns a CSS postprocessor that transforms the source CSS as described above. * `featureDetector` - Each of this object's properties is a string filepath to a JavaScript file containing the browser-side feature detector in a particular JavaScript module format. * `es6` - [ECMAScript 6 module](http://www.2ality.com/2014/09/es6-modules-final.html) format (this is the original from which the other versions are generated) * `cjs` - [CommonJS](http://wiki.commonjs.org/wiki/Modules/1.1) module format @@ -143,6 +149,7 @@ _Also, please don't edit files in the `dist` subdirectory as they are generated ## Release History See the [GitHub Releases page](https://github.com/cvrebert/mq4-hover-hover-shim/releases) for detailed changelogs. * (next release) - `master` +* 2015-01-18 - v0.0.4: Fix crash when CSS contains a media-type-only media query. Replaced `postprocessor` with `postprocessorFor()`. * 2015-01-14 - v0.0.3: Add jspm metadata. Improve docs. * 2015-01-09 - v0.0.2: Many improvements. jQuery is now a dependency on the client side. * 2014-12-31 - v0.0.1: Initial release diff --git a/src/nodejs/index.js b/src/nodejs/index.js index 96f0772..7bfa81f 100644 --- a/src/nodejs/index.js +++ b/src/nodejs/index.js @@ -6,7 +6,7 @@ var CLIENT_SIDE_FEATURE_DETECTOR_FILENAME = 'mq4-hover-hover-shim.js'; module.exports = { - postprocessor: require('./postprocessor'), + postprocessorFor: require('./postprocessor'), featureDetector: { es6: path.join(__dirname, '../browser', CLIENT_SIDE_FEATURE_DETECTOR_FILENAME), cjs: path.join(__dirname, '../../dist/cjs', CLIENT_SIDE_FEATURE_DETECTOR_FILENAME), diff --git a/src/nodejs/postprocessor.js b/src/nodejs/postprocessor.js index c0c5163..9597ee7 100644 --- a/src/nodejs/postprocessor.js +++ b/src/nodejs/postprocessor.js @@ -68,46 +68,48 @@ function prefixSelectorsWith(rule, selectorPrefix) { } -module.exports = postcss(function process(css, opts) { - var hoverSelectorPrefix = opts.hoverSelectorPrefix; - if ((typeof hoverSelectorPrefix) !== 'string') { - throw new Error('hoverSelectorPrefix option must be a string'); - } +module.exports = function (opts) { + return postcss(function process(css) { + var hoverSelectorPrefix = opts.hoverSelectorPrefix; + if ((typeof hoverSelectorPrefix) !== 'string') { + throw new Error('hoverSelectorPrefix option must be a string'); + } - css.eachAtRule('media', function (atRule) { - var mediaType = mediaTypeIfSimpleHoverHover(atRule); - switch (mediaType) { - case 'all': - /* falls through */ - case 'screen': { - atRule.eachRule(function (rule) { - prefixSelectorsWith(rule, hoverSelectorPrefix); - }); - if (mediaType === 'screen') { - atRule.params = 'screen'; - } - else { - // Remove tautological @media all {...} wrapper - replaceWithItsChildren(atRule); + css.eachAtRule('media', function (atRule) { + var mediaType = mediaTypeIfSimpleHoverHover(atRule); + switch (mediaType) { + case 'all': + /* falls through */ + case 'screen': { + atRule.eachRule(function (rule) { + prefixSelectorsWith(rule, hoverSelectorPrefix); + }); + if (mediaType === 'screen') { + atRule.params = 'screen'; + } + else { + // Remove tautological @media all {...} wrapper + replaceWithItsChildren(atRule); + } + return; } - return; - } - case 'print': - /* falls through */ - case 'speech': { - // These media types never support hovering - // Delete always-false media query - atRule.removeSelf(); - return; - } + case 'print': + /* falls through */ + case 'speech': { + // These media types never support hovering + // Delete always-false media query + atRule.removeSelf(); + return; + } - case undefined: { - return; // Media query irrelevant or too complicated - } - default: { - return; // Deprecated media type; take no action. + case undefined: { + return; // Media query irrelevant or too complicated + } + default: { + return; // Deprecated media type; take no action. + } } - } + }); }); -}); +}; diff --git a/test/postprocessor_test.js b/test/postprocessor_test.js index 2878ed6..3a9e36d 100644 --- a/test/postprocessor_test.js +++ b/test/postprocessor_test.js @@ -28,7 +28,7 @@ exports.mq4HoverShim = { 'has no effect when there are no media queries': function (test) { test.expect(1); test.deepEqual( - postprocessor.process(".foobar { display: none; }", {hoverSelectorPrefix: 'PREFIX>'}).css, + postprocessor({hoverSelectorPrefix: 'PREFIX>'}).process(".foobar { display: none; }").css, ".foobar { display: none; }" ); test.done(); @@ -36,7 +36,7 @@ exports.mq4HoverShim = { 'skips non-media at-rules': function (test) { test.expect(1); test.deepEqual( - postprocessor.process("@quux (hover: hover) { .foobar { display: none; } }", {hoverSelectorPrefix: 'PREFIX>'}).css, + postprocessor({hoverSelectorPrefix: 'PREFIX>'}).process("@quux (hover: hover) { .foobar { display: none; } }").css, "@quux (hover: hover) { .foobar { display: none; } }" ); test.done(); @@ -44,7 +44,7 @@ exports.mq4HoverShim = { 'skips media queries with only a media type': function (test) { test.expect(1); test.deepEqual( - postprocessor.process("@media screen { .foobar { display: none; } }", {hoverSelectorPrefix: 'PREFIX>'}).css, + postprocessor({hoverSelectorPrefix: 'PREFIX>'}).process("@media screen { .foobar { display: none; } }").css, "@media screen { .foobar { display: none; } }" ); test.done(); @@ -52,11 +52,11 @@ exports.mq4HoverShim = { 'skips media queries with ORs': function (test) { test.expect(2); test.deepEqual( - postprocessor.process("@media (hover: hover), (orientation: landscape) { .foobar { display: none; } }", {hoverSelectorPrefix: 'PREFIX>'}).css, + postprocessor({hoverSelectorPrefix: 'PREFIX>'}).process("@media (hover: hover), (orientation: landscape) { .foobar { display: none; } }").css, "@media (hover: hover), (orientation: landscape) { .foobar { display: none; } }" ); test.deepEqual( - postprocessor.process("@media screen (hover: hover), (orientation: landscape) { .foobar { display: none; } }", {hoverSelectorPrefix: 'PREFIX>'}).css, + postprocessor({hoverSelectorPrefix: 'PREFIX>'}).process("@media screen (hover: hover), (orientation: landscape) { .foobar { display: none; } }").css, "@media screen (hover: hover), (orientation: landscape) { .foobar { display: none; } }" ); test.done(); @@ -64,11 +64,11 @@ exports.mq4HoverShim = { 'skips media queries with ANDs': function (test) { test.expect(2); test.deepEqual( - postprocessor.process("@media (hover: hover) and (orientation: landscape) { .foobar { display: none; } }", {hoverSelectorPrefix: 'PREFIX>'}).css, + postprocessor({hoverSelectorPrefix: 'PREFIX>'}).process("@media (hover: hover) and (orientation: landscape) { .foobar { display: none; } }").css, "@media (hover: hover) and (orientation: landscape) { .foobar { display: none; } }" ); test.deepEqual( - postprocessor.process("@media screen (hover: hover) and (orientation: landscape) { .foobar { display: none; } }", {hoverSelectorPrefix: 'PREFIX>'}).css, + postprocessor({hoverSelectorPrefix: 'PREFIX>'}).process("@media screen (hover: hover) and (orientation: landscape) { .foobar { display: none; } }").css, "@media screen (hover: hover) and (orientation: landscape) { .foobar { display: none; } }" ); test.done(); @@ -76,7 +76,7 @@ exports.mq4HoverShim = { 'skips media queries that are not about the hover media feature': function (test) { test.expect(1); test.deepEqual( - postprocessor.process("@media (orientation: landscape) { .foobar { display: none; } }", {hoverSelectorPrefix: 'PREFIX>'}).css, + postprocessor({hoverSelectorPrefix: 'PREFIX>'}).process("@media (orientation: landscape) { .foobar { display: none; } }").css, "@media (orientation: landscape) { .foobar { display: none; } }" ); test.done(); @@ -84,11 +84,11 @@ exports.mq4HoverShim = { 'skips media queries about the hover media feature with a non-hover value': function (test) { test.expect(2); test.deepEqual( - postprocessor.process("@media (hover: none) { .foobar { display: none; } }", {hoverSelectorPrefix: 'PREFIX>'}).css, + postprocessor({hoverSelectorPrefix: 'PREFIX>'}).process("@media (hover: none) { .foobar { display: none; } }").css, "@media (hover: none) { .foobar { display: none; } }" ); test.deepEqual( - postprocessor.process("@media (hover: on-demand) { .foobar { display: none; } }", {hoverSelectorPrefix: 'PREFIX>'}).css, + postprocessor({hoverSelectorPrefix: 'PREFIX>'}).process("@media (hover: on-demand) { .foobar { display: none; } }").css, "@media (hover: on-demand) { .foobar { display: none; } }" ); test.done(); @@ -96,7 +96,7 @@ exports.mq4HoverShim = { 'works correctly on a representative example': function (test) { test.expect(1); test.deepEqual( - postprocessor.process("@media (hover: hover) { .foobar { color: white; background: red; } div .quux > input { color: blue; background: white; } }", {hoverSelectorPrefix: 'PREFIX>'}).css, + postprocessor({hoverSelectorPrefix: 'PREFIX>'}).process("@media (hover: hover) { .foobar { color: white; background: red; } div .quux > input { color: blue; background: white; } }").css, "PREFIX>.foobar {\n color: white;\n background: red;\n}\nPREFIX>div .quux > input {\n color: blue;\n background: white;\n}" ); test.done(); @@ -104,19 +104,19 @@ exports.mq4HoverShim = { 'handles nested at-rules': function (test) { test.expect(4); test.deepEqual( - postprocessor.process("@media (orientation: landscape) { @media (hover: hover) { .foobar { display: none; } } }", {hoverSelectorPrefix: 'PREFIX>'}).css, + postprocessor({hoverSelectorPrefix: 'PREFIX>'}).process("@media (orientation: landscape) { @media (hover: hover) { .foobar { display: none; } } }").css, "@media (orientation: landscape) { PREFIX>.foobar { display: none; } }" ); test.deepEqual( - postprocessor.process("@media screen (orientation: landscape) { @media (hover: hover) { .foobar { display: none; } } }", {hoverSelectorPrefix: 'PREFIX>'}).css, + postprocessor({hoverSelectorPrefix: 'PREFIX>'}).process("@media screen (orientation: landscape) { @media (hover: hover) { .foobar { display: none; } } }").css, "@media screen (orientation: landscape) { PREFIX>.foobar { display: none; } }" ); test.deepEqual( - postprocessor.process("@media (hover: hover) { @media (orientation: landscape) { .foobar { display: none; } } }", {hoverSelectorPrefix: 'PREFIX>'}).css, + postprocessor({hoverSelectorPrefix: 'PREFIX>'}).process("@media (hover: hover) { @media (orientation: landscape) { .foobar { display: none; } } }").css, "@media (orientation: landscape) {\n PREFIX>.foobar {\n display: none;\n }\n}" ); test.deepEqual( - postprocessor.process("@media (hover: hover) { @media screen (orientation: landscape) { .foobar { display: none; } } }", {hoverSelectorPrefix: 'PREFIX>'}).css, + postprocessor({hoverSelectorPrefix: 'PREFIX>'}).process("@media (hover: hover) { @media screen (orientation: landscape) { .foobar { display: none; } } }").css, "@media screen (orientation: landscape) {\n PREFIX>.foobar {\n display: none;\n }\n}" ); test.done(); @@ -124,7 +124,7 @@ exports.mq4HoverShim = { 'handles applicable media types': function (test) { test.expect(1); test.deepEqual( - postprocessor.process("@media screen (hover: hover) { .foobar { display: none; } }", {hoverSelectorPrefix: 'PREFIX>'}).css, + postprocessor({hoverSelectorPrefix: 'PREFIX>'}).process("@media screen (hover: hover) { .foobar { display: none; } }").css, "@media screen { PREFIX>.foobar { display: none; } }" ); test.done(); @@ -132,7 +132,7 @@ exports.mq4HoverShim = { 'handles non-applicable media types': function (test) { test.expect(1); test.deepEqual( - postprocessor.process("@media print (hover: hover) { .foobar { display: none; } }", {hoverSelectorPrefix: 'PREFIX>'}).css, + postprocessor({hoverSelectorPrefix: 'PREFIX>'}).process("@media print (hover: hover) { .foobar { display: none; } }").css, "" ); test.done(); @@ -141,7 +141,7 @@ exports.mq4HoverShim = { test.expect(1); test.throws(function () { /*eslint-disable no-unused-expressions */ - postprocessor.process("@media (hover: hover) { .foobar { display: none; } }", {}).css;// jshint ignore:line + postprocessor({}).process("@media (hover: hover) { .foobar { display: none; } }").css;// jshint ignore:line /*eslint-enable no-unused-expressions */ }, Error, 'hoverSelectorPrefix option must be a string'); test.done(); @@ -150,7 +150,7 @@ exports.mq4HoverShim = { test.expect(1); test.throws(function () { /*eslint-disable no-unused-expressions */ - postprocessor.process("@media (hover: hover) { .foobar { display: none; } }", {hoverSelectorPrefix: 42}).css;// jshint ignore:line + postprocessor({hoverSelectorPrefix: 42}).process("@media (hover: hover) { .foobar { display: none; } }").css;// jshint ignore:line /*eslint-enable no-unused-expressions */ }, Error, 'hoverSelectorPrefix option must be a string'); test.done(); |