├── .gitignore ├── LICENSE ├── README.md ├── bin └── group-css-media-queries ├── index.coffee ├── index.js ├── package.json └── test ├── fixtures ├── mixed-px-em.css ├── mixed-px-em.sorted.css ├── mixed.css ├── mixed.sorted.css ├── only-max.css ├── only-max.sorted.css ├── only-min.css ├── only-min.sorted.css ├── readme-example.css ├── readme-example.sorted.css ├── zero.css └── zero.sorted.css └── groupCssMediaQueries.test.coffee /.gitignore: -------------------------------------------------------------------------------- 1 | lib-cov 2 | *.seed 3 | *.log 4 | *.csv 5 | *.dat 6 | *.out 7 | *.pid 8 | *.gz 9 | 10 | pids 11 | logs 12 | results 13 | 14 | npm-debug.log 15 | node_modules 16 | 17 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Copyright (c) 2013 Ivan Kravchenko 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy of 6 | this software and associated documentation files (the "Software"), to deal in 7 | the Software without restriction, including without limitation the rights to 8 | use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of 9 | the Software, and to permit persons to whom the Software is furnished to do so, 10 | subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS 17 | FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR 18 | COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER 19 | IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN 20 | CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 21 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | group-css-media-queries 2 | ======================= 3 | 4 | CSS postprocessing: group media queries. Useful for postprocessing preprocessed CSS files. 5 | 6 | # What is it? 7 | 8 | You have input.css (take note on similar media query): 9 | ```css 10 | .header-main { 11 | background-image: url("/images/branding/logo.main.png"); 12 | } 13 | @media all and (-webkit-min-device-pixel-ratio:1.5),(min--moz-device-pixel-ratio:1.5),(-o-min-device-pixel-ratio:1.5/1),(min-device-pixel-ratio:1.5),(min-resolution:138dpi),(min-resolution:1.5dppx) { 14 | .header-main { 15 | background-image: url("/images/branding/logo.main@2x.png"); 16 | -webkit-background-size: auto auto; 17 | -moz-background-size: auto auto; 18 | background-size: auto auto; 19 | } 20 | } 21 | .footer-main { 22 | background-image: url("/images/branding/logo.main.png"); 23 | } 24 | @media all and (-webkit-min-device-pixel-ratio:1.5),(min--moz-device-pixel-ratio:1.5),(-o-min-device-pixel-ratio:1.5/1),(min-device-pixel-ratio:1.5),(min-resolution:138dpi),(min-resolution:1.5dppx) { 25 | .footer-main { 26 | background-image: url("/images/branding/logo.main@2x.png"); 27 | -webkit-background-size: auto auto; 28 | -moz-background-size: auto auto; 29 | background-size: auto auto; 30 | } 31 | } 32 | ``` 33 | 34 | Run this utility: 35 | ``` 36 | group-css-media-queries input.css output.css 37 | ``` 38 | 39 | The result is output.css: 40 | ```css 41 | .header-main { 42 | background-image: url("/images/branding/logo.main.png"); 43 | } 44 | 45 | .footer-main { 46 | background-image: url("/images/branding/logo.main.png"); 47 | } 48 | 49 | @media all and (-webkit-min-device-pixel-ratio:1.5),(min--moz-device-pixel-ratio:1.5),(-o-min-device-pixel-ratio:1.5/1),(min-device-pixel-ratio:1.5),(min-resolution:138dpi),(min-resolution:1.5dppx) { 50 | .header-main { 51 | background-image: url("/images/branding/logo.main@2x.png"); 52 | -webkit-background-size: auto auto; 53 | -moz-background-size: auto auto; 54 | background-size: auto auto; 55 | } 56 | 57 | .footer-main { 58 | background-image: url("/images/branding/logo.main@2x.png"); 59 | -webkit-background-size: auto auto; 60 | -moz-background-size: auto auto; 61 | background-size: auto auto; 62 | } 63 | } 64 | ``` 65 | 66 | Voila! 67 | 68 | # Installing 69 | 70 | ``` 71 | npm install -g group-css-media-queries 72 | ``` 73 | 74 | # Media Queries order 75 | Output CSS is ordered by these rules: 76 | * non-media-query code goes first unmodified, 77 | * then all only min-width rules, sorted ascending by px 78 | * then all only max-width rules, sorted descending by px 79 | * then all interval rules, without reordering 80 | * then all other rules 81 | 82 | # Changelog 83 | * 1.1.0 - adopted unit tests, refactored media queries ordering 84 | * 1.0.1 – added basic media queries sorting (thanks to @berbaquero) 85 | * 1.0.0 – initial working release 86 | -------------------------------------------------------------------------------- /bin/group-css-media-queries: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env node 2 | 3 | var fs = require('fs'); 4 | 5 | var path = require('path'); 6 | var main = require(path.join(path.dirname(fs.realpathSync(__filename)), '../')); 7 | 8 | var input = function(cb) { 9 | var inputFilename = process.argv[2]; 10 | if (inputFilename) { 11 | cb(fs.readFileSync(inputFilename, "utf8")); 12 | } else { 13 | var data = ""; 14 | process.stdin.resume(); 15 | process.stdin.setEncoding('utf8'); 16 | 17 | process.stdin.on('data', function(chunk) { 18 | data += chunk; 19 | }); 20 | 21 | process.stdin.on('end', function() { 22 | cb(data); 23 | }); 24 | } 25 | }; 26 | 27 | var output = function(data) { 28 | var outputFilename = process.argv[3]; 29 | if (outputFilename) { 30 | fs.writeFileSync(outputFilename, data); 31 | } else { 32 | console.log(data); 33 | } 34 | }; 35 | 36 | input(function(data) { 37 | result = main(data); 38 | output(result); 39 | }); 40 | -------------------------------------------------------------------------------- /index.coffee: -------------------------------------------------------------------------------- 1 | # take gorgeous visionmedia's css utilities 2 | parseCss = require 'css-parse' 3 | stringifyCss = require 'css-stringify' 4 | 5 | module.exports = (css) -> 6 | # parse it 7 | parsed = parseCss css 8 | 9 | # extract and group medias and root rules 10 | medias = {} 11 | rootRules = [] 12 | for rule in parsed.stylesheet.rules 13 | if rule.type is 'media' 14 | medias[rule.media] = [] if not medias[rule.media] 15 | medias[rule.media] = medias[rule.media].concat rule.rules 16 | else 17 | rootRules.push rule 18 | 19 | # generate media rules 20 | mediaRules = [] 21 | for media, rules of medias 22 | rule = 23 | type: "media" 24 | media: media 25 | rules: rules 26 | # extract min-width and max-width values 27 | if media.indexOf("min-width") isnt -1 28 | m = media.match ///min-width:\s*(\d+)(px|em)?/// 29 | rule.minWidth = parseInt m[1] if m && m[1] 30 | rule.unit = m[2] if m[2] 31 | if media.indexOf("max-width") isnt -1 32 | m = media.match ///max-width:\s*(\d+)(px|em)?/// 33 | rule.maxWidth = parseInt m[1] if m && m[1] 34 | rule.unit = m[2] if m[2] 35 | mediaRules.push rule 36 | 37 | # break rules into only-min, only-max, intervals and others 38 | onlyMinRules = mediaRules.filter (rule) -> 39 | rule.minWidth? and not rule.maxWidth? 40 | onlyMaxRules = mediaRules.filter (rule) -> 41 | rule.maxWidth? and not rule.minWidth? 42 | intervalRules = mediaRules.filter (rule) -> 43 | rule.minWidth? and rule.maxWidth? 44 | otherRules = mediaRules.filter (rule) -> 45 | rule not in onlyMinRules.concat(onlyMaxRules).concat(intervalRules) 46 | 47 | emToPxRatio = 16 # 1em = 16px 48 | 49 | # sort media rules 50 | onlyMinRules.sort (a, b) -> 51 | aPxValue = a.minWidth 52 | bPxValue = b.minWidth 53 | aPxValue *= emToPxRatio if a.unit is 'em' 54 | bPxValue *= emToPxRatio if b.unit is 'em' 55 | aPxValue - bPxValue # ascending 56 | onlyMaxRules.sort (a, b) -> 57 | aPxValue = a.maxWidth 58 | bPxValue = b.maxWidth 59 | aPxValue *= emToPxRatio if a.unit is 'em' 60 | bPxValue *= emToPxRatio if b.unit is 'em' 61 | bPxValue - aPxValue # descending 62 | 63 | # modify parsed AST 64 | parsed.stylesheet.rules = rootRules 65 | .concat(onlyMinRules) 66 | .concat(onlyMaxRules) 67 | .concat(intervalRules) 68 | .concat(otherRules) 69 | 70 | # output 71 | stringifyCss parsed 72 | -------------------------------------------------------------------------------- /index.js: -------------------------------------------------------------------------------- 1 | // Generated by CoffeeScript 1.10.0 2 | (function() { 3 | var parseCss, stringifyCss, 4 | indexOf = [].indexOf || function(item) { for (var i = 0, l = this.length; i < l; i++) { if (i in this && this[i] === item) return i; } return -1; }; 5 | 6 | parseCss = require('css-parse'); 7 | 8 | stringifyCss = require('css-stringify'); 9 | 10 | module.exports = function(css) { 11 | var emToPxRatio, i, intervalRules, len, m, media, mediaRules, medias, onlyMaxRules, onlyMinRules, otherRules, parsed, ref, rootRules, rule, rules; 12 | parsed = parseCss(css); 13 | medias = {}; 14 | rootRules = []; 15 | ref = parsed.stylesheet.rules; 16 | for (i = 0, len = ref.length; i < len; i++) { 17 | rule = ref[i]; 18 | if (rule.type === 'media') { 19 | if (!medias[rule.media]) { 20 | medias[rule.media] = []; 21 | } 22 | medias[rule.media] = medias[rule.media].concat(rule.rules); 23 | } else { 24 | rootRules.push(rule); 25 | } 26 | } 27 | mediaRules = []; 28 | for (media in medias) { 29 | rules = medias[media]; 30 | rule = { 31 | type: "media", 32 | media: media, 33 | rules: rules 34 | }; 35 | if (media.indexOf("min-width") !== -1) { 36 | m = media.match(/min-width:\s*(\d+)(px|em)?/); 37 | if (m && m[1]) { 38 | rule.minWidth = parseInt(m[1]); 39 | } 40 | if (m[2]) { 41 | rule.unit = m[2]; 42 | } 43 | } 44 | if (media.indexOf("max-width") !== -1) { 45 | m = media.match(/max-width:\s*(\d+)(px|em)?/); 46 | if (m && m[1]) { 47 | rule.maxWidth = parseInt(m[1]); 48 | } 49 | if (m[2]) { 50 | rule.unit = m[2]; 51 | } 52 | } 53 | mediaRules.push(rule); 54 | } 55 | onlyMinRules = mediaRules.filter(function(rule) { 56 | return (rule.minWidth != null) && (rule.maxWidth == null); 57 | }); 58 | onlyMaxRules = mediaRules.filter(function(rule) { 59 | return (rule.maxWidth != null) && (rule.minWidth == null); 60 | }); 61 | intervalRules = mediaRules.filter(function(rule) { 62 | return (rule.minWidth != null) && (rule.maxWidth != null); 63 | }); 64 | otherRules = mediaRules.filter(function(rule) { 65 | return indexOf.call(onlyMinRules.concat(onlyMaxRules).concat(intervalRules), rule) < 0; 66 | }); 67 | emToPxRatio = 16; 68 | onlyMinRules.sort(function(a, b) { 69 | var aPxValue, bPxValue; 70 | aPxValue = a.minWidth; 71 | bPxValue = b.minWidth; 72 | if (a.unit === 'em') { 73 | aPxValue *= emToPxRatio; 74 | } 75 | if (b.unit === 'em') { 76 | bPxValue *= emToPxRatio; 77 | } 78 | return aPxValue - bPxValue; 79 | }); 80 | onlyMaxRules.sort(function(a, b) { 81 | var aPxValue, bPxValue; 82 | aPxValue = a.maxWidth; 83 | bPxValue = b.maxWidth; 84 | if (a.unit === 'em') { 85 | aPxValue *= emToPxRatio; 86 | } 87 | if (b.unit === 'em') { 88 | bPxValue *= emToPxRatio; 89 | } 90 | return bPxValue - aPxValue; 91 | }); 92 | parsed.stylesheet.rules = rootRules.concat(onlyMinRules).concat(onlyMaxRules).concat(intervalRules).concat(otherRules); 93 | return stringifyCss(parsed); 94 | }; 95 | 96 | }).call(this); 97 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "group-css-media-queries", 3 | "description": "CSS postprocessing: group media queries. Useful for postprocessing preprocessed CSS files :)", 4 | "keywords": [ 5 | "css", 6 | "group", 7 | "media", 8 | "queries", 9 | "postprocessing", 10 | "postprocessor" 11 | ], 12 | "license": "MIT", 13 | "author": { 14 | "name": "Ivan Kravchenko", 15 | "email": "i@se7ensky.com" 16 | }, 17 | "repository": { 18 | "type": "git", 19 | "url": "https://github.com/Se7enSky/group-css-media-queries.git" 20 | }, 21 | "version": "1.4.1", 22 | "main": "index", 23 | "bin": { 24 | "group-css-media-queries": "./bin/group-css-media-queries" 25 | }, 26 | "dependencies": { 27 | "css-parse": "^2.0.0", 28 | "css-stringify": "^2.0.0" 29 | }, 30 | "engines": { 31 | "node": ">=0.8.0" 32 | }, 33 | "devDependencies": { 34 | "chai": "^1.10.0", 35 | "coffee-script": "*", 36 | "mocha": "^2.0.1" 37 | }, 38 | "scripts": { 39 | "prepublish": "./node_modules/.bin/coffee -c index.coffee", 40 | "test": "./node_modules/.bin/mocha --compilers coffee:coffee-script/register" 41 | } 42 | } 43 | -------------------------------------------------------------------------------- /test/fixtures/mixed-px-em.css: -------------------------------------------------------------------------------- 1 | .selector1 { 2 | property: value1; 3 | } 4 | 5 | @media (max-width: 20em) { 6 | .selector3 { 7 | property: value1; 8 | } 9 | } 10 | 11 | @media (max-width: 10em) { 12 | .selector3 { 13 | property: value2; 14 | } 15 | } 16 | 17 | @media (max-width: 165px) { 18 | .selector3 { 19 | property: value3; 20 | } 21 | } 22 | 23 | @media (max-width: 1000em) { 24 | .selector { 25 | property: value2; 26 | } 27 | } 28 | 29 | @media (min-width: 1000px) { 30 | .selector { 31 | property: value7; 32 | } 33 | } 34 | 35 | @media (max-width: 500em) { 36 | .selector { 37 | property: value4; 38 | } 39 | } 40 | 41 | @media (min-width: 500px) { 42 | .selector { 43 | property: value5; 44 | } 45 | } 46 | 47 | .selector2 { 48 | property: value2; 49 | } 50 | 51 | @media (max-width: 750em) { 52 | .selector { 53 | property: value3; 54 | } 55 | } 56 | 57 | @media (min-width: 750px) { 58 | .selector { 59 | property: value6; 60 | } 61 | } 62 | -------------------------------------------------------------------------------- /test/fixtures/mixed-px-em.sorted.css: -------------------------------------------------------------------------------- 1 | .selector1 { 2 | property: value1; 3 | } 4 | 5 | .selector2 { 6 | property: value2; 7 | } 8 | 9 | @media (min-width: 500px) { 10 | .selector { 11 | property: value5; 12 | } 13 | } 14 | 15 | @media (min-width: 750px) { 16 | .selector { 17 | property: value6; 18 | } 19 | } 20 | 21 | @media (min-width: 1000px) { 22 | .selector { 23 | property: value7; 24 | } 25 | } 26 | 27 | @media (max-width: 1000em) { 28 | .selector { 29 | property: value2; 30 | } 31 | } 32 | 33 | @media (max-width: 750em) { 34 | .selector { 35 | property: value3; 36 | } 37 | } 38 | 39 | @media (max-width: 500em) { 40 | .selector { 41 | property: value4; 42 | } 43 | } 44 | 45 | @media (max-width: 20em) { 46 | .selector3 { 47 | property: value1; 48 | } 49 | } 50 | 51 | @media (max-width: 165px) { 52 | .selector3 { 53 | property: value3; 54 | } 55 | } 56 | 57 | @media (max-width: 10em) { 58 | .selector3 { 59 | property: value2; 60 | } 61 | } 62 | -------------------------------------------------------------------------------- /test/fixtures/mixed.css: -------------------------------------------------------------------------------- 1 | .selector { 2 | property: value1; 3 | } 4 | 5 | @media (max-width: 1000px) { 6 | .selector { 7 | property: value2; 8 | } 9 | } 10 | 11 | @media (min-width: 1000px) { 12 | .selector { 13 | property: value7; 14 | } 15 | } 16 | 17 | @media (max-width: 500px) { 18 | .selector { 19 | property: value4; 20 | } 21 | } 22 | 23 | @media (min-width: 500px) { 24 | .selector { 25 | property: value5; 26 | } 27 | } 28 | 29 | @media (max-width: 750px) { 30 | .selector { 31 | property: value3; 32 | } 33 | } 34 | 35 | @media (min-width: 750px) { 36 | .selector { 37 | property: value6; 38 | } 39 | } 40 | 41 | -------------------------------------------------------------------------------- /test/fixtures/mixed.sorted.css: -------------------------------------------------------------------------------- 1 | .selector { 2 | property: value1; 3 | } 4 | 5 | @media (min-width: 500px) { 6 | .selector { 7 | property: value5; 8 | } 9 | } 10 | 11 | @media (min-width: 750px) { 12 | .selector { 13 | property: value6; 14 | } 15 | } 16 | 17 | @media (min-width: 1000px) { 18 | .selector { 19 | property: value7; 20 | } 21 | } 22 | 23 | @media (max-width: 1000px) { 24 | .selector { 25 | property: value2; 26 | } 27 | } 28 | 29 | @media (max-width: 750px) { 30 | .selector { 31 | property: value3; 32 | } 33 | } 34 | 35 | @media (max-width: 500px) { 36 | .selector { 37 | property: value4; 38 | } 39 | } -------------------------------------------------------------------------------- /test/fixtures/only-max.css: -------------------------------------------------------------------------------- 1 | .selector { 2 | property: value1; 3 | } 4 | 5 | @media (max-width: 1000px) { 6 | .selector { 7 | property: value2; 8 | } 9 | } 10 | 11 | @media (max-width: 500px) { 12 | .selector { 13 | property: value3; 14 | } 15 | } 16 | 17 | @media (max-width: 750px) { 18 | .selector { 19 | property: value4; 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /test/fixtures/only-max.sorted.css: -------------------------------------------------------------------------------- 1 | .selector { 2 | property: value1; 3 | } 4 | 5 | @media (max-width: 1000px) { 6 | .selector { 7 | property: value2; 8 | } 9 | } 10 | 11 | @media (max-width: 750px) { 12 | .selector { 13 | property: value4; 14 | } 15 | } 16 | 17 | @media (max-width: 500px) { 18 | .selector { 19 | property: value3; 20 | } 21 | } -------------------------------------------------------------------------------- /test/fixtures/only-min.css: -------------------------------------------------------------------------------- 1 | .selector { 2 | property: value1; 3 | } 4 | 5 | @media (min-width: 1000px) { 6 | .selector { 7 | property: value2; 8 | } 9 | } 10 | 11 | @media (min-width: 500px) { 12 | .selector { 13 | property: value3; 14 | } 15 | } 16 | 17 | @media (min-width: 750px) { 18 | .selector { 19 | property: value4; 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /test/fixtures/only-min.sorted.css: -------------------------------------------------------------------------------- 1 | .selector { 2 | property: value1; 3 | } 4 | 5 | @media (min-width: 500px) { 6 | .selector { 7 | property: value3; 8 | } 9 | } 10 | 11 | @media (min-width: 750px) { 12 | .selector { 13 | property: value4; 14 | } 15 | } 16 | 17 | @media (min-width: 1000px) { 18 | .selector { 19 | property: value2; 20 | } 21 | } -------------------------------------------------------------------------------- /test/fixtures/readme-example.css: -------------------------------------------------------------------------------- 1 | .header-main { 2 | background-image: url("/images/branding/logo.main.png"); 3 | } 4 | @media all and (-webkit-min-device-pixel-ratio:1.5),(min--moz-device-pixel-ratio:1.5),(-o-min-device-pixel-ratio:1.5/1),(min-device-pixel-ratio:1.5),(min-resolution:138dpi),(min-resolution:1.5dppx) { 5 | .header-main { 6 | background-image: url("/images/branding/logo.main@2x.png"); 7 | -webkit-background-size: auto auto; 8 | -moz-background-size: auto auto; 9 | background-size: auto auto; 10 | } 11 | } 12 | .footer-main { 13 | background-image: url("/images/branding/logo.main.png"); 14 | } 15 | @media all and (-webkit-min-device-pixel-ratio:1.5),(min--moz-device-pixel-ratio:1.5),(-o-min-device-pixel-ratio:1.5/1),(min-device-pixel-ratio:1.5),(min-resolution:138dpi),(min-resolution:1.5dppx) { 16 | .footer-main { 17 | background-image: url("/images/branding/logo.main@2x.png"); 18 | -webkit-background-size: auto auto; 19 | -moz-background-size: auto auto; 20 | background-size: auto auto; 21 | } 22 | } -------------------------------------------------------------------------------- /test/fixtures/readme-example.sorted.css: -------------------------------------------------------------------------------- 1 | .header-main { 2 | background-image: url("/images/branding/logo.main.png"); 3 | } 4 | 5 | .footer-main { 6 | background-image: url("/images/branding/logo.main.png"); 7 | } 8 | 9 | @media all and (-webkit-min-device-pixel-ratio:1.5),(min--moz-device-pixel-ratio:1.5),(-o-min-device-pixel-ratio:1.5/1),(min-device-pixel-ratio:1.5),(min-resolution:138dpi),(min-resolution:1.5dppx) { 10 | .header-main { 11 | background-image: url("/images/branding/logo.main@2x.png"); 12 | -webkit-background-size: auto auto; 13 | -moz-background-size: auto auto; 14 | background-size: auto auto; 15 | } 16 | 17 | .footer-main { 18 | background-image: url("/images/branding/logo.main@2x.png"); 19 | -webkit-background-size: auto auto; 20 | -moz-background-size: auto auto; 21 | background-size: auto auto; 22 | } 23 | } -------------------------------------------------------------------------------- /test/fixtures/zero.css: -------------------------------------------------------------------------------- 1 | @media (min-width: 10px) { 2 | .selector { 3 | property: value3; 4 | } 5 | } 6 | 7 | .selector { 8 | property: value1; 9 | } 10 | 11 | @media (min-width: 0) { 12 | .selector { 13 | property: value2; 14 | } 15 | } 16 | -------------------------------------------------------------------------------- /test/fixtures/zero.sorted.css: -------------------------------------------------------------------------------- 1 | .selector { 2 | property: value1; 3 | } 4 | 5 | @media (min-width: 0) { 6 | .selector { 7 | property: value2; 8 | } 9 | } 10 | 11 | @media (min-width: 10px) { 12 | .selector { 13 | property: value3; 14 | } 15 | } 16 | -------------------------------------------------------------------------------- /test/groupCssMediaQueries.test.coffee: -------------------------------------------------------------------------------- 1 | chai = require('chai') 2 | chai.should() 3 | 4 | groupCssMediaQueries = require '..' 5 | fs = require 'fs' 6 | 7 | describe 'groupCssMediaQueries', -> 8 | fixturesPath = "#{__dirname}/fixtures" 9 | allFiles = fs.readdirSync fixturesPath 10 | inputFiles = allFiles.filter (path) -> 11 | path.indexOf(".sorted.css") is -1 and path.indexOf(".css") isnt -1 12 | 13 | testInputFile = (inputFilename)-> 14 | it inputFilename, -> 15 | outputFilename = inputFilename.replace ///\.css$///, '.sorted.css' 16 | input = fs.readFileSync "#{fixturesPath}/#{inputFilename}", encoding: "utf8" 17 | output = fs.readFileSync "#{fixturesPath}/#{outputFilename}", encoding: "utf8" 18 | groupCssMediaQueries(input.trim()).should.eql(output.trim()) 19 | 20 | testInputFile inputFilename for inputFilename in inputFiles 21 | --------------------------------------------------------------------------------