├── .gitignore ├── .npmignore ├── .travis.yml ├── CHANGELOG.md ├── LICENSE ├── README.md ├── index.js ├── package.json └── test ├── fixtures ├── any-pattern-works.css ├── any-pattern-works.expected.css ├── correct-arm-expression-chosen.css ├── correct-arm-expression-chosen.expected.css ├── multiple-patterns-works.css ├── multiple-patterns-works.expected.css ├── multiple-properties-in-expression-works.css └── multiple-properties-in-expression-works.expected.css └── index.js /.gitignore: -------------------------------------------------------------------------------- 1 | node_modules/ 2 | npm-debug.log 3 | -------------------------------------------------------------------------------- /.npmignore: -------------------------------------------------------------------------------- 1 | .gitignore 2 | 3 | node_modules/ 4 | 5 | test/ 6 | .travis.yml 7 | 8 | gulpfile.js 9 | -------------------------------------------------------------------------------- /.travis.yml: -------------------------------------------------------------------------------- 1 | sudo: false 2 | language: node_js 3 | node_js: 4 | - iojs 5 | - "0.12" 6 | - "0.10" 7 | -------------------------------------------------------------------------------- /CHANGELOG.md: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rtsao/postcss-match/12b0db9a2c39898c56103abc8b5300b251a8e60d/CHANGELOG.md -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Copyright 2015 Ryan Tsao 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 | # PostCSS Match [![Build Status][ci-img]][ci] 2 | 3 | [PostCSS] plugin for Rust-style pattern matching. 4 | 5 | [PostCSS]: https://github.com/postcss/postcss 6 | [ci-img]: https://travis-ci.org/rtsao/postcss-match.svg 7 | [ci]: https://travis-ci.org/rtsao/postcss-match 8 | [postcss-simple-vars]: https://github.com/postcss/postcss-simple-vars 9 | 10 | ```css 11 | .blah { 12 | @match baz { 13 | foo => { color: red; }, 14 | bar | baz => { background: green; } 15 | } 16 | } 17 | ``` 18 | 19 | ```css 20 | .blah { 21 | background: green 22 | } 23 | ``` 24 | 25 | In conjunction with [postcss-simple-vars]: 26 | 27 | ```css 28 | $animal: bear; 29 | 30 | .zoo { 31 | @match $animal { 32 | snake => { color: green; }, 33 | buffalo | bear => { background: brown; }, 34 | lion => { font-weight: bold; }, 35 | _ => { 36 | font-style: italic; 37 | color: gray; 38 | } 39 | } 40 | } 41 | ``` 42 | 43 | ```css 44 | .zoo { 45 | background: brown 46 | } 47 | ``` 48 | 49 | ## Usage 50 | 51 | ```js 52 | postcss([ require('postcss-match') ]) 53 | ``` 54 | 55 | See [PostCSS] docs for examples for your environment. 56 | 57 | ## Differences from Rust and other known limitations 58 | 59 | * Braces around arm expressions are non-optional 60 | * Nested `@match` at-rules are currently unsupported 61 | * Rust-style range patterns are currently unsupported 62 | * Pattern exhaustiveness is not checked 63 | * Pattern unreachability is not checked 64 | -------------------------------------------------------------------------------- /index.js: -------------------------------------------------------------------------------- 1 | var postcss = require('postcss'); 2 | 3 | var ANY = '_'; 4 | 5 | function getPatterns(str) { 6 | return str.replace(/=>|,|\s/g, '').split('|'); 7 | } 8 | 9 | module.exports = postcss.plugin('postcss-match', function plugin() { 10 | return function process(css) { 11 | css.eachAtRule('match', function processMatch(rule) { 12 | var value = rule.params; 13 | var found = rule.some(function checkArm(child) { 14 | var patterns = getPatterns(child.selector); 15 | return patterns.some(function checkPattern(pattern) { 16 | if (pattern === value || pattern === ANY) { 17 | rule.replaceWith(child.nodes); 18 | return true; 19 | } 20 | }); 21 | }); 22 | if (!found) { 23 | rule.removeSelf(); 24 | } 25 | }); 26 | }; 27 | }); 28 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "postcss-match", 3 | "version": "1.0.0", 4 | "description": "PostCSS plugin for Rust-style pattern matching", 5 | "keywords": [ 6 | "postcss", 7 | "css", 8 | "postcss-plugin", 9 | "rust", 10 | "match", 11 | "pattern" 12 | ], 13 | "author": "Ryan Tsao ", 14 | "license": "MIT", 15 | "repository": { 16 | "type": "git", 17 | "url": "https://github.com/rtsao/postcss-match.git" 18 | }, 19 | "bugs": { 20 | "url": "https://github.com/rtsao/postcss-match/issues" 21 | }, 22 | "homepage": "https://github.com/rtsao/postcss-match", 23 | "dependencies": { 24 | "postcss": "^4.1.13" 25 | }, 26 | "devDependencies": { 27 | "tap-spec": "^4.0.2", 28 | "tape": "^4.0.3" 29 | }, 30 | "scripts": { 31 | "test": "node test/index.js | tap-spec" 32 | } 33 | } 34 | -------------------------------------------------------------------------------- /test/fixtures/any-pattern-works.css: -------------------------------------------------------------------------------- 1 | .blah { 2 | @match xyz { 3 | foo => { color: red; }, 4 | bar => { background: green; }, 5 | _ => { font-weight: bold; } 6 | } 7 | } 8 | -------------------------------------------------------------------------------- /test/fixtures/any-pattern-works.expected.css: -------------------------------------------------------------------------------- 1 | .blah { 2 | font-weight: bold 3 | } 4 | -------------------------------------------------------------------------------- /test/fixtures/correct-arm-expression-chosen.css: -------------------------------------------------------------------------------- 1 | .blah { 2 | @match bar { 3 | foo => { color: red; }, 4 | bar => { background: green; }, 5 | baz => { font-weight: bold; } 6 | } 7 | } 8 | -------------------------------------------------------------------------------- /test/fixtures/correct-arm-expression-chosen.expected.css: -------------------------------------------------------------------------------- 1 | .blah { 2 | background: green 3 | } 4 | -------------------------------------------------------------------------------- /test/fixtures/multiple-patterns-works.css: -------------------------------------------------------------------------------- 1 | .blah { 2 | @match baz { 3 | foo => { color: red; }, 4 | bar | baz => { background: green; }, 5 | _ => { font-weight: bold; } 6 | } 7 | } 8 | -------------------------------------------------------------------------------- /test/fixtures/multiple-patterns-works.expected.css: -------------------------------------------------------------------------------- 1 | .blah { 2 | background: green 3 | } 4 | -------------------------------------------------------------------------------- /test/fixtures/multiple-properties-in-expression-works.css: -------------------------------------------------------------------------------- 1 | .blah { 2 | @match baz { 3 | foo => { color: red; }, 4 | bar => { background: green; }, 5 | baz => { 6 | font-weight: bold; 7 | color: orange; 8 | } 9 | } 10 | } 11 | -------------------------------------------------------------------------------- /test/fixtures/multiple-properties-in-expression-works.expected.css: -------------------------------------------------------------------------------- 1 | .blah { 2 | font-weight: bold; 3 | color: orange 4 | } 5 | -------------------------------------------------------------------------------- /test/index.js: -------------------------------------------------------------------------------- 1 | var fs = require('fs'); 2 | var path = require('path'); 3 | var test = require('tape'); 4 | var postcss = require('postcss'); 5 | var plugin = require('../'); 6 | 7 | var FIXTURES_DIR = './test/fixtures'; 8 | 9 | function isTestFixture(filename) { 10 | return filename.match(/^((?!\.expected).)*\.css$/); 11 | } 12 | 13 | function expectedName(filename) { 14 | return filename.replace(/\.css$/, '.expected.css'); 15 | } 16 | 17 | function getFixture(filename) { 18 | return fs.readFileSync(path.join(FIXTURES_DIR, filename), 'utf8'); 19 | } 20 | 21 | function getTestName(filename) { 22 | return filename.replace(/(-|\.css$)/g, ' '); 23 | } 24 | 25 | function processCss(source, resultHandler, errorHandler) { 26 | postcss(plugin()).process(source) 27 | .then(resultHandler) 28 | .catch(errorHandler); 29 | } 30 | 31 | function runTest(filename) { 32 | var input = getFixture(filename); 33 | var expected = getFixture(expectedName(filename)); 34 | processCss(input, function handleResult(result) { 35 | test(getTestName(filename), function (t) { 36 | t.plan(2); 37 | t.equal(result.css, expected, 'output matches expected'); 38 | t.equal(result.warnings().length, 0, 'no warnings'); 39 | t.end(); 40 | }); 41 | }, function handleError(error) { 42 | console.error(error); 43 | }); 44 | } 45 | 46 | var tests = fs.readdirSync(FIXTURES_DIR).filter(isTestFixture); 47 | tests.forEach(runTest); 48 | --------------------------------------------------------------------------------