├── .gitignore ├── .travis.yml ├── .npmignore ├── gulpfile.js ├── package.json ├── LICENSE ├── README.md ├── index.js ├── CHANGELOG.md ├── test └── test.js └── .eslintrc /.gitignore: -------------------------------------------------------------------------------- 1 | node_modules/ 2 | npm-debug.log 3 | -------------------------------------------------------------------------------- /.travis.yml: -------------------------------------------------------------------------------- 1 | sudo: false 2 | language: node_js 3 | node_js: 4 | - iojs 5 | - "0.12" 6 | -------------------------------------------------------------------------------- /.npmignore: -------------------------------------------------------------------------------- 1 | .gitignore 2 | 3 | node_modules/ 4 | npm-debug.log 5 | 6 | .eslintrc 7 | 8 | test/ 9 | .travis.yml 10 | 11 | gulpfile.js 12 | -------------------------------------------------------------------------------- /gulpfile.js: -------------------------------------------------------------------------------- 1 | var gulp = require('gulp'); 2 | 3 | var files = ['index.js', 'test/*.js', 'gulpfile.js']; 4 | 5 | gulp.task('lint', function () { 6 | var eslint = require('gulp-eslint'); 7 | return gulp.src(files) 8 | .pipe(eslint()) 9 | .pipe(eslint.format()) 10 | .pipe(eslint.failAfterError()); 11 | }); 12 | 13 | gulp.task('test', function () { 14 | var mocha = require('gulp-mocha'); 15 | return gulp.src('test/*.js', { read: false }) 16 | .pipe(mocha()); 17 | }); 18 | 19 | gulp.task('default', ['lint', 'test']); 20 | 21 | gulp.task('watch', function () { 22 | gulp.watch(files, ['lint', 'test']); 23 | }); 24 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "postcss-axis", 3 | "version": "0.1.2", 4 | "description": "PostCSS plugin which adds shorthands for opposite properties", 5 | "keywords": [ 6 | "postcss", 7 | "css", 8 | "postcss-plugin", 9 | "shorthand", 10 | "margin", 11 | "padding" 12 | ], 13 | "author": "Leonard Kinday ", 14 | "license": "MIT", 15 | "repository": { 16 | "type": "git", 17 | "url": "https://github.com/kinday/postcss-axis.git" 18 | }, 19 | "bugs": { 20 | "url": "https://github.com/kinday/postcss-axis/issues" 21 | }, 22 | "homepage": "https://github.com/kinday/postcss-axis", 23 | "dependencies": { 24 | "postcss": "^5.0.2" 25 | }, 26 | "devDependencies": { 27 | "chai": "^3.2.0", 28 | "gulp": "^3.9.0", 29 | "gulp-eslint": "^1.0.0", 30 | "gulp-mocha": "^2.1.3" 31 | }, 32 | "scripts": { 33 | "test": "gulp" 34 | } 35 | } 36 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Copyright 2015 Leonard Kinday 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 Axis [![Build Status](https://travis-ci.org/kinday/postcss-axis.svg)](https://travis-ci.org/kinday/postcss-axis) 2 | 3 | [PostCSS] plugin which adds shorthands for opposite properties. 4 | 5 | [PostCSS]: https://github.com/postcss/postcss 6 | 7 | ```css 8 | /* Input example */ 9 | .foo { 10 | margin-x: 10px; 11 | padding-y: 10px 20px; 12 | border-x: 1px solid #f00; 13 | border-y-color: #fff; 14 | } 15 | ``` 16 | 17 | ```css 18 | /* Output example */ 19 | .foo { 20 | margin-left: 10px; 21 | margin-right: 10px; 22 | padding-top: 10px; 23 | padding-bottom: 20px; 24 | border-left: 1px solid #f00; 25 | border-right: 1px solid #f00; 26 | border-top-color: #fff; 27 | border-bottom-color: #fff; 28 | } 29 | ``` 30 | 31 | ## Installation 32 | 33 | ```bash 34 | npm install postcss-axis 35 | ``` 36 | 37 | ## Usage 38 | 39 | ```js 40 | postcss([ require('postcss-axis') ]) 41 | ``` 42 | 43 | ### Options 44 | 45 | #### `trbl` 46 | Type: `Boolean` 47 | Default: `false` 48 | 49 | Swaps `left` and `right` values in shorthands according to [TRBL] model. 50 | 51 | [TRBL]: https://developer.mozilla.org/en-US/docs/Web/CSS/Shorthand_properties 52 | 53 | --- 54 | 55 | See [PostCSS] docs for examples for your environment. 56 | -------------------------------------------------------------------------------- /index.js: -------------------------------------------------------------------------------- 1 | var postcss = require('postcss'); 2 | 3 | function getAttrs(axis, name, subname) { 4 | var attrs = { 5 | x: ['left', 'right'], 6 | y: ['top', 'bottom'] 7 | }; 8 | 9 | return attrs[axis].map(function (side) { 10 | var parts = [name, side]; 11 | subname && parts.push(subname); 12 | return parts.join('-'); 13 | }); 14 | } 15 | 16 | module.exports = postcss.plugin('postcss-axis', function (opts) { 17 | opts = opts || {}; 18 | 19 | return function (css) { 20 | var filter = /^(border|margin|padding)-(x|y)(?:-(color|style|width))?$/; 21 | 22 | css.walkDecls(filter, function (decl) { 23 | var match = decl.prop.match(filter); 24 | var attrs = getAttrs(match[2], match[1], match[3]); 25 | var values; 26 | 27 | if (match[1] === 'border' && !match[3]) { 28 | values = [decl.value]; 29 | } else { 30 | values = postcss.list.space(decl.value); 31 | } 32 | 33 | if ( values.length === 1 ) values[1] = values[0]; 34 | 35 | if (opts.trbl && match[2] === 'x') values = [values[1], values[0]]; 36 | 37 | decl.cloneBefore({ prop: attrs[0], value: values[0] }); 38 | decl.cloneBefore({ prop: attrs[1], value: values[1] }); 39 | 40 | decl.remove(); 41 | }); 42 | }; 43 | }); 44 | -------------------------------------------------------------------------------- /CHANGELOG.md: -------------------------------------------------------------------------------- 1 | # Change Log 2 | All notable changes to this project will be documented in this file. 3 | This project adheres to [Semantic Versioning](http://semver.org/). 4 | 5 | ## [Unpublished] 6 | ### Added 7 | - This `CHANGELOG` file to keep track of what happened 8 | 9 | ## [0.1.2] - 2016-01-03 10 | ### Fixed 11 | - Wrong `padding-bottom` value in example output (#3 by @Nitive) 12 | 13 | ## [0.1.1] - 2015-10-12 14 | ### Fixed 15 | - Bug when `trbl` set to `true` swapped `y` values (#1) 16 | 17 | ## [0.1.0] - 2015-10-10 18 | ### Added 19 | - `trbl` option to swap left and right values in `x` shorthands according to CSS TRBL model (#1) 20 | 21 | ## [0.0.3] - 2015-10-10 22 | ### Changed 23 | - Updated `README` info to install module from npm. 24 | ### Fixed 25 | - Border shorthand parsing bug (#2) 26 | 27 | ## [0.0.2] - 2015-08-27 28 | ### Added 29 | - Margin, padding and border shorthands support. 30 | - `README` with documentation and examples 31 | 32 | ## 0.0.1 - 2015-08-26 33 | ### Added 34 | - Project base scaffolded with PostCSS plugin generator. 35 | 36 | [Unpublished]: https://github.com/kinday/postcss-axis/compare/v0.1.2...HEAD 37 | [0.1.2]: https://github.com/kinday/postcss-axis/compare/v0.1.1...v0.1.2 38 | [0.1.1]: https://github.com/kinday/postcss-axis/compare/v0.1.0...v0.1.1 39 | [0.1.0]: https://github.com/kinday/postcss-axis/compare/v0.0.3...v0.1.0 40 | [0.0.3]: https://github.com/kinday/postcss-axis/compare/v0.0.2...v0.0.3 41 | [0.0.2]: https://github.com/kinday/postcss-axis/compare/v0.0.1...v0.0.2 42 | -------------------------------------------------------------------------------- /test/test.js: -------------------------------------------------------------------------------- 1 | var postcss = require('postcss'); 2 | var expect = require('chai').expect; 3 | 4 | var plugin = require('../'); 5 | 6 | var test = function (input, output, opts, done) { 7 | postcss([ plugin(opts) ]).process(input).then(function (result) { 8 | expect(result.css).to.eql(output); 9 | expect(result.warnings()).to.be.empty; 10 | done(); 11 | }).catch(function (error) { 12 | done(error); 13 | }); 14 | }; 15 | 16 | describe('postcss-axis', function () { 17 | 18 | describe('border', function () { 19 | 20 | it('sets borders', function (done) { 21 | var input = 'a{ border-x: 10px solid #000; }'; 22 | var output = [ 23 | 'a{', 24 | 'border-left: 10px solid #000;', 25 | 'border-right: 10px solid #000;', 26 | '}' 27 | ].join(' '); 28 | test(input, output, {}, done); 29 | }); 30 | 31 | }); 32 | 33 | describe('border longhands', function () { 34 | 35 | it('sets borders color', function (done) { 36 | var input = 'a{ border-x-color: #000 #333; }'; 37 | var output = [ 38 | 'a{', 39 | 'border-left-color: #000;', 40 | 'border-right-color: #333;', 41 | '}' 42 | ].join(' '); 43 | test(input, output, {}, done); 44 | }); 45 | 46 | it('sets borders color by one value', function (done) { 47 | var input = 'a{ border-x-color: #000; }'; 48 | var output = [ 49 | 'a{', 50 | 'border-left-color: #000;', 51 | 'border-right-color: #000;', 52 | '}' 53 | ].join(' '); 54 | test(input, output, {}, done); 55 | }); 56 | 57 | it('sets borders style', function (done) { 58 | var input = 'a{ border-x-style: solid dashed; }'; 59 | var output = [ 60 | 'a{', 61 | 'border-left-style: solid;', 62 | 'border-right-style: dashed;', 63 | '}' 64 | ].join(' '); 65 | test(input, output, {}, done); 66 | }); 67 | 68 | it('sets borders style by one value', function (done) { 69 | var input = 'a{ border-x-style: solid; }'; 70 | var output = [ 71 | 'a{', 72 | 'border-left-style: solid;', 73 | 'border-right-style: solid;', 74 | '}' 75 | ].join(' '); 76 | test(input, output, {}, done); 77 | }); 78 | 79 | it('sets borders width', function (done) { 80 | var input = 'a{ border-x-width: 1px 3px; }'; 81 | var output = [ 82 | 'a{', 83 | 'border-left-width: 1px;', 84 | 'border-right-width: 3px;', 85 | '}' 86 | ].join(' '); 87 | test(input, output, {}, done); 88 | }); 89 | 90 | it('sets borders width by one value', function (done) { 91 | var input = 'a{ border-x-width: 1px; }'; 92 | var output = [ 93 | 'a{', 94 | 'border-left-width: 1px;', 95 | 'border-right-width: 1px;', 96 | '}' 97 | ].join(' '); 98 | test(input, output, {}, done); 99 | }); 100 | 101 | }); 102 | 103 | describe('margin', function () { 104 | 105 | it('sets margins', function (done) { 106 | var input = 'a{ margin-x: 10px 20px; }'; 107 | var output = 'a{ margin-left: 10px; margin-right: 20px; }'; 108 | test(input, output, {}, done); 109 | }); 110 | 111 | it('sets margins by one value', function (done) { 112 | var input = 'a{ margin-x: 10px; }'; 113 | var output = 'a{ margin-left: 10px; margin-right: 10px; }'; 114 | test(input, output, {}, done); 115 | }); 116 | 117 | }); 118 | 119 | describe('padding', function () { 120 | 121 | it('sets paddings', function (done) { 122 | var input = 'a{ padding-x: 10px 20px; }'; 123 | var output = 'a{ padding-left: 10px; padding-right: 20px; }'; 124 | test(input, output, {}, done); 125 | }); 126 | 127 | it('sets paddings by one value', function (done) { 128 | var input = 'a{ padding-x: 10px; }'; 129 | var output = 'a{ padding-left: 10px; padding-right: 10px; }'; 130 | test(input, output, {}, done); 131 | }); 132 | 133 | }); 134 | 135 | describe('options', function () { 136 | 137 | describe('trbl', function () { 138 | 139 | it('swaps left and right', function (done) { 140 | var input = 'a{ padding-x: 20px 10px; }'; 141 | var output = 'a{ padding-left: 10px; padding-right: 20px; }'; 142 | test(input, output, { trbl: true }, done); 143 | }); 144 | 145 | it('doesn’t swap top and bottom', function (done) { 146 | var input = 'a{ padding-y: 10px 20px; }'; 147 | var output = 'a{ padding-top: 10px; padding-bottom: 20px; }'; 148 | test(input, output, { trbl: true }, done); 149 | }); 150 | 151 | }); 152 | 153 | }); 154 | 155 | }); 156 | -------------------------------------------------------------------------------- /.eslintrc: -------------------------------------------------------------------------------- 1 | { 2 | "rules": { 3 | "space-before-function-paren": [2, { "named": "never" }], 4 | "no-shadow-restricted-names": [2], 5 | "computed-property-spacing": [2], 6 | "no-empty-character-class": [2], 7 | "no-irregular-whitespace": [2], 8 | "no-unexpected-multiline": [2], 9 | "no-multiple-empty-lines": [2], 10 | "space-return-throw-case": [2], 11 | "no-constant-condition": [2], 12 | "no-extra-boolean-cast": [2], 13 | "no-inner-declarations": [2], 14 | "no-this-before-super": [2], 15 | "no-use-before-define": [2], 16 | "no-array-constructor": [2], 17 | "object-curly-spacing": [2, "always"], 18 | "no-floating-decimal": [2], 19 | "no-warning-comments": [2], 20 | "handle-callback-err": [2], 21 | "no-unneeded-ternary": [2], 22 | "operator-assignment": [2], 23 | "space-before-blocks": [2], 24 | "no-native-reassign": [2], 25 | "no-trailing-spaces": [2], 26 | "operator-linebreak": [2, "after"], 27 | "consistent-return": [2], 28 | "no-duplicate-case": [2], 29 | "no-invalid-regexp": [2], 30 | "no-negated-in-lhs": [2], 31 | "constructor-super": [2], 32 | "no-nested-ternary": [2], 33 | "no-extend-native": [2], 34 | "block-scoped-var": [2], 35 | "no-control-regex": [2], 36 | "no-sparse-arrays": [2], 37 | "no-throw-literal": [2], 38 | "no-return-assign": [2], 39 | "no-const-assign": [2], 40 | "no-class-assign": [2], 41 | "no-extra-parens": [2], 42 | "no-regex-spaces": [2], 43 | "no-implied-eval": [2], 44 | "no-useless-call": [2], 45 | "no-self-compare": [2], 46 | "no-octal-escape": [2], 47 | "no-new-wrappers": [2], 48 | "no-process-exit": [2], 49 | "no-catch-shadow": [2], 50 | "linebreak-style": [2], 51 | "space-infix-ops": [2], 52 | "space-unary-ops": [2], 53 | "no-cond-assign": [2], 54 | "no-func-assign": [2], 55 | "no-unreachable": [2], 56 | "accessor-pairs": [2], 57 | "no-empty-label": [2], 58 | "no-fallthrough": [2], 59 | "no-path-concat": [2], 60 | "no-new-require": [2], 61 | "no-spaced-func": [2], 62 | "no-unused-vars": [2], 63 | "spaced-comment": [2], 64 | "no-delete-var": [2], 65 | "comma-spacing": [2], 66 | "no-extra-semi": [2], 67 | "no-extra-bind": [2], 68 | "arrow-spacing": [2], 69 | "prefer-spread": [2], 70 | "no-new-object": [2], 71 | "no-multi-str": [2], 72 | "semi-spacing": [2], 73 | "no-lonely-if": [2], 74 | "dot-notation": [2], 75 | "dot-location": [2, "property"], 76 | "comma-dangle": [2, "never"], 77 | "no-dupe-args": [2], 78 | "no-dupe-keys": [2], 79 | "no-ex-assign": [2], 80 | "no-obj-calls": [2], 81 | "valid-typeof": [2], 82 | "default-case": [2], 83 | "no-redeclare": [2], 84 | "no-div-regex": [2], 85 | "no-sequences": [2], 86 | "no-label-var": [2], 87 | "comma-style": [2], 88 | "brace-style": [2], 89 | "no-debugger": [2], 90 | "quote-props": [2, "as-needed"], 91 | "no-iterator": [2], 92 | "no-new-func": [2], 93 | "key-spacing": [2, { "align": "value" }], 94 | "complexity": [2], 95 | "new-parens": [2], 96 | "no-eq-null": [2], 97 | "no-bitwise": [2], 98 | "wrap-iife": [2], 99 | "no-caller": [2], 100 | "use-isnan": [2], 101 | "no-labels": [2], 102 | "no-shadow": [2], 103 | "camelcase": [2], 104 | "eol-last": [2], 105 | "no-octal": [2], 106 | "no-empty": [2], 107 | "no-alert": [2], 108 | "no-proto": [2], 109 | "no-undef": [2], 110 | "no-eval": [2], 111 | "no-with": [2], 112 | "no-void": [2], 113 | "max-len": [2, 80], 114 | "new-cap": [2], 115 | "eqeqeq": [2], 116 | "no-new": [2], 117 | "quotes": [2, "single"], 118 | "indent": [2, 4], 119 | "semi": [2, "always"], 120 | "yoda": [2, "never"] 121 | }, 122 | "env": { 123 | "mocha": true, 124 | "node": true 125 | } 126 | } 127 | --------------------------------------------------------------------------------