install gulp

This commit is contained in:
2018-05-28 13:26:25 +02:00
parent 2de92c908b
commit 04fab6ba46
8032 changed files with 709336 additions and 3100 deletions
+232
View File
@@ -0,0 +1,232 @@
# Changelog
## 3.1.7 - 2015-06-09
- Do not remove units from values starting from zeroes, like `0.5em` (#394)
## 3.1.6 - 2015-06-09
- Hotfix for issue when `unitless-zero` crashed on percentages in Less (#389)
## 3.1.5 - 2015-05-27
- Fixed dependencies
## 3.1.4 - 2015-05-24
- Fixed `space-after-opening-brace` option for empty media queries (#387)
## 3.1.3 - 2015-05-20
- Do not add extra space before combinators which go first in selectors (#381)
## 3.1.2 - 2015-05-20
- Fixed processing of hashes (#379)
## 3.1.1 - 2015-05-20
- Fixed `space-between-declarations` vs. media queries (#378)
## 3.1.0 - 2015-05-19
**Thanks to
[@1000ch](https://github.com/1000ch),
[@alexeykuzmin](https://github.com/alexeykuzmin),
[@jonrohan](https://github.com/jonrohan)**
- Used new Gonzales PE API
- Fixed nested properties (#319)
- Added support for symlinked configs
- Added support for configs with any extension
## 3.0.4 - 2014-11-15
**Thanks to
[@gonzalocasas](https://github.com/gonzalocasas),
[@tomByrer](https://github.com/tomByrer)**
- Improved docs
- Fixed Gonzales PE version
## 3.0.3 - 2014-09-29
**Thanks to
[@kizu](https://github.com/kizu),
[@necolas](https://github.com/necolas)**
- Improved README
- Added non-essential files to npmignore
- Renamed `CONTRIBUTE.md` to `CONTRIBUTING.md`
- Fixed unwanted removal of empty lines between nested rulesets (#317)
## 3.0.2 - 2014-09-21
- Fixed Gonzales PE version
## 3.0.1 - 2014-08-18
**Thanks to
[@mishanga](https://github.com/mishanga),
[@cust0dian](https://github.com/cust0dian)**
- Added `khtml` to list of vendor prefixes
- Updated docs
## 3.0.0 - 2014-07-19
**Thanks to
[@cvrebert](https://github.com/cvrebert),
[@filtercake](https://github.com/filtercake),
[@lefoy](https://github.com/lefoy),
[@L0stSoul](https://github.com/L0stSoul),
[@kizu](https://github.com/kizu),
[@schneyra](https://github.com/schneyra),
[@thejameskyle](https://github.com/thejameskyle),
[@vecmezoni](https://github.com/vecmezoni)**
New:
- Sass support
- Leftovers (#160)
- Use [CSScomb Core](https://github.com/csscomb/core)
- Plugins API (with `.use()` method)
- `sort-order-fallback` (alphabetical sort order)
- `space-before-colon`
- `space-after-colon`
- `space-before-combinator`
- `space-after-combinator`
- `space-before-selector-delimiter`
- `space-after-selector-delimiter`
- `space-before-opening-brace`
- `space-after-opening-brace`
- `space-before-closing-brace`
- `space-after-declaration`
- `tab-size`
Removed:
- `colon-space`
- `combinator-space`
- `rule-indent`
- `stick-brace`
Changed:
- Divided `process` and `detect` methods
- Made `getConfig` and `detect` static methods
- Removed "best guess" logic from options
- Excluded `bower_components/**` from processing
- Updated badges at README page
- Update Gonzales PE to v3.0
- Various fixes
## 2.0.5 - 2014-06-09
- Updated dependencies (#229)
## 2.0.4 - 2014-01-16
- Fixed relative path to config (#164)
## 2.0.3 - 2014-01-16
- Documentation moved to `doc` directory
- Fixed incorrect left indent (#153)
## 2.0.2 - 2014-01-09
- Added test coverage (#138)
- Added test helpers (#147)
- Fixed config file recursive searching (#151)
- Fixed `block-indent` detecting (#148)
- Fixed `quote` value setter (#149)
- Fixed detection integral tests (#150)
## 2.0.1 - 2013-12-23
- Fix for `remove-empty-rulesets` option (#133)
## 2.0.0 - 2013-12-18
**Great thanks for @tonyganch and @kizu!**
- Use Gonzales PE to parse *.scss and *.less files
- Support sorting properties in *.scss and *.less files
- Codestyle detection
- Option: always-semicolon (scss + less)
- Option: quotes
- Two more config examples now: `csscomb` and `zen`
- Lots of refactoring and fixes
- Lots of tests added
- Node v0.8 no longer supported
## 1.0.0 - 2013-11-06
- Option: vendor-prefix-align
- Dependencies updated
- Fixed options order in readme
## 0.1.0 - 2013-10-11
- CLI: lint mode
## 0.0.15 - 2013-10-03
- Option: remove-empty-rulesets (#67)
- Option colon-space expanded
- Some refactoring and fixes
## 0.0.14 - 2013-09-12
- Option: eof-newline (#55)
- Verbose option (#62)
- Some refactoring
## 0.0.13 - 2013-09-12
- Fixed failing on empty files (#66)
## 0.0.12 - 2013-09-11
- Option: combinator-space
- Readme update
- Some CLI fixes
- Contributor added: @anton-rudeshko
## 0.0.11 - 2013-09-10
- Option: element-case
- Fixed block-indent bug with space after at-rule opening brace
- Fixed JSDoc
- Fixed colon-space description
## 0.0.10 - 2013-09-06
- Option: color-case
- Option: color-shorthand
- Option: leading-zero
- Option: unitless-zero
- Option update: colon-space
- Contributors added: @kizu and @ignovak
- Readme updated
- Licence added
- Contributing info added
- Changelog added
## 0.0.9 - 2013-08-28
- Option: sort-order
- Sort order config fix
- JSCS version and config update
- jshint config fix
- Some codestyle fixes
## 0.0.8 - 2013-08-22
- !!! Now using Gonzales instead of CSSP
- Option: block-indent
- Option: rule-indent
- Added few links to README
- Added some debug info
- Fixed default sort order
- Fixed path processing bug
- Fixed stick-brace option
## 0.0.7 - 2013-08-09
- jshint config fix
- Codestyle fix for always-semicolon
- Integral test fix
- Removed old php code
## 0.0.6 - 2013-08-08
- Option: always-semicolon
## 0.0.5 - 2013-08-08
- Fix for value setting
- Bugfix for stick-brace
- Added integral test
## 0.0.4 - 2013-08-07
- Some refactoring
- Tests added
## 0.0.3 - 2013-08-05
- Option: colon-space
- Option: stick-brace
- Moved to github/csscomb/csscomb.js
## 0.0.2 - 2013-08-04
- Option: strip-spaces - fix
## 0.0.1 - 2013-08-03
- Initial release
- Option: strip spaces
- Travis support
+20
View File
@@ -0,0 +1,20 @@
The MIT License (MIT)
Copyright © 2013 Mikhail Troshev, http://mishanga.pro
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the “Software”), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED “AS IS”, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.
+104
View File
@@ -0,0 +1,104 @@
# CSScomb [![CSSComb](logo.png)](http://csscomb.com/)
[![Build Status](https://travis-ci.org/csscomb/csscomb.js.svg?branch=master)](http://travis-ci.org/csscomb/csscomb.js)
[![NPM version](https://badge.fury.io/js/csscomb.svg)](http://badge.fury.io/js/csscomb)
[![Dependency Status](https://david-dm.org/csscomb/csscomb.js.svg)](https://david-dm.org/csscomb/csscomb.js)
[![devDependency Status](https://david-dm.org/csscomb/csscomb.js/dev-status.svg)](https://david-dm.org/csscomb/csscomb.js#info=devDependencies)
CSScomb is a coding style formatter for CSS.
You can easily write your own [configuration](doc/configuration.md) to make
your style sheets beautiful and consistent.
The main feature is [sorting properties](doc/options.md#sort-order) in a specific order.
It was inspired by [@miripiruni](https://github.com/miripiruni)'s
[PHP-based tool](https://github.com/csscomb/csscomb) of the same name.
This is the new JavaScript version, based on the powerful CSS parser
[Gonzales PE](https://github.com/tonyganch/gonzales-pe).
## 1. Install
Global installation (for use as a command-line tool):
```bash
npm install csscomb -g
```
Local installation (for use as a command-line tool within current directory):
```bash
npm install csscomb
```
To install as a project dependency (the package will appear in your dependencies):
```bash
npm install csscomb --save
```
To install as a dev dependency (the package will appear in your devDependencies):
```bash
npm install csscomb --save-dev
```
## 2. [Configure](doc/configuration.md)
There are a number of ways to configure CSScomb:
- Use one of [predefined configs](config)
- Put `.csscomb.json` file in the project root.
- Set path to config's file
- Use `*.css` file as a template
## 3. Use
### [Command Line](doc/usage-cli.md)
```bash
csscomb assets/css
```
### [Node.js module](doc/usage-node.md)
```js
var Comb = require('csscomb');
var comb = new Comb('zen');
comb.processPath('assets/css');
```
## 4. Contribute
Anyone and everyone is welcome to contribute.
Please take a moment to review the [guidelines for contributing](CONTRIBUTING.md).
## Authors
[@mishanga](https://github.com/mishanga),
[@tonyganch](https://github.com/tonyganch)
Thanks for assistance and contributions:
[@miripiruni](https://github.com/miripiruni),
[@anton-rudeshko](https://github.com/anton-rudeshko),
[@cvrebert](https://github.com/cvrebert),
[@filtercake](https://github.com/filtercake),
[@ignovak](https://github.com/ignovak),
[@kizu](https://github.com/kizu),
[@lefoy](https://github.com/lefoy),
[@L0stSoul](https://github.com/L0stSoul),
[@mishaberezin](https://github.com/mishaberezin),
[@puzankov](https://github.com/puzankov),
[@schneyra](https://github.com/schneyra),
[@thejameskyle](https://github.com/thejameskyle),
[@vecmezoni](https://github.com/vecmezoni)
## License
This software is released under the terms of the
[MIT license](https://github.com/csscomb/csscomb.js/blob/master/LICENSE).
## Other projects
* https://github.com/senchalabs/cssbeautify
* https://github.com/css/gonzales
* https://github.com/tonyganch/gonzales-pe
* https://github.com/css/csso
* https://github.com/nzakas/parser-lib
+2
View File
@@ -0,0 +1,2 @@
#!/usr/bin/env node
require('../lib/cli');
+328
View File
@@ -0,0 +1,328 @@
{
"exclude": [
".git/**",
"node_modules/**",
"bower_components/**"
],
"always-semicolon": true,
"block-indent": " ",
"color-case": "lower",
"color-shorthand": true,
"element-case": "lower",
"eof-newline": true,
"leading-zero": false,
"quotes": "single",
"remove-empty-rulesets": true,
"space-after-colon": " ",
"space-after-combinator": " ",
"space-after-opening-brace": "\n",
"space-after-selector-delimiter": "\n",
"space-before-closing-brace": "\n",
"space-before-colon": "",
"space-before-combinator": " ",
"space-before-opening-brace": "\n",
"space-before-selector-delimiter": "",
"strip-spaces": true,
"unitless-zero": true,
"vendor-prefix-align": true,
"sort-order": [
[
"font",
"font-family",
"font-size",
"font-weight",
"font-style",
"font-variant",
"font-size-adjust",
"font-stretch",
"font-effect",
"font-emphasize",
"font-emphasize-position",
"font-emphasize-style",
"font-smooth",
"line-height"
],
[
"position",
"z-index",
"top",
"right",
"bottom",
"left"
],
[
"display",
"visibility",
"float",
"clear",
"overflow",
"overflow-x",
"overflow-y",
"-ms-overflow-x",
"-ms-overflow-y",
"clip",
"zoom",
"flex-direction",
"flex-order",
"flex-pack",
"flex-align"
],
[
"-webkit-box-sizing",
"-moz-box-sizing",
"box-sizing",
"width",
"min-width",
"max-width",
"height",
"min-height",
"max-height",
"margin",
"margin-top",
"margin-right",
"margin-bottom",
"margin-left",
"padding",
"padding-top",
"padding-right",
"padding-bottom",
"padding-left"
],
[
"table-layout",
"empty-cells",
"caption-side",
"border-spacing",
"border-collapse",
"list-style",
"list-style-position",
"list-style-type",
"list-style-image"
],
[
"content",
"quotes",
"counter-reset",
"counter-increment",
"resize",
"cursor",
"-webkit-user-select",
"-moz-user-select",
"-ms-user-select",
"user-select",
"nav-index",
"nav-up",
"nav-right",
"nav-down",
"nav-left",
"-webkit-transition",
"-moz-transition",
"-ms-transition",
"-o-transition",
"transition",
"-webkit-transition-delay",
"-moz-transition-delay",
"-ms-transition-delay",
"-o-transition-delay",
"transition-delay",
"-webkit-transition-timing-function",
"-moz-transition-timing-function",
"-ms-transition-timing-function",
"-o-transition-timing-function",
"transition-timing-function",
"-webkit-transition-duration",
"-moz-transition-duration",
"-ms-transition-duration",
"-o-transition-duration",
"transition-duration",
"-webkit-transition-property",
"-moz-transition-property",
"-ms-transition-property",
"-o-transition-property",
"transition-property",
"-webkit-transform",
"-moz-transform",
"-ms-transform",
"-o-transform",
"transform",
"-webkit-transform-origin",
"-moz-transform-origin",
"-ms-transform-origin",
"-o-transform-origin",
"transform-origin",
"-webkit-animation",
"-moz-animation",
"-ms-animation",
"-o-animation",
"animation",
"-webkit-animation-name",
"-moz-animation-name",
"-ms-animation-name",
"-o-animation-name",
"animation-name",
"-webkit-animation-duration",
"-moz-animation-duration",
"-ms-animation-duration",
"-o-animation-duration",
"animation-duration",
"-webkit-animation-play-state",
"-moz-animation-play-state",
"-ms-animation-play-state",
"-o-animation-play-state",
"animation-play-state",
"-webkit-animation-timing-function",
"-moz-animation-timing-function",
"-ms-animation-timing-function",
"-o-animation-timing-function",
"animation-timing-function",
"-webkit-animation-delay",
"-moz-animation-delay",
"-ms-animation-delay",
"-o-animation-delay",
"animation-delay",
"-webkit-animation-iteration-count",
"-moz-animation-iteration-count",
"-ms-animation-iteration-count",
"-o-animation-iteration-count",
"animation-iteration-count",
"-webkit-animation-direction",
"-moz-animation-direction",
"-ms-animation-direction",
"-o-animation-direction",
"animation-direction",
"text-align",
"-webkit-text-align-last",
"-moz-text-align-last",
"-ms-text-align-last",
"text-align-last",
"vertical-align",
"white-space",
"text-decoration",
"text-emphasis",
"text-emphasis-color",
"text-emphasis-style",
"text-emphasis-position",
"text-indent",
"-ms-text-justify",
"text-justify",
"letter-spacing",
"word-spacing",
"-ms-writing-mode",
"text-outline",
"text-transform",
"text-wrap",
"text-overflow",
"-ms-text-overflow",
"text-overflow-ellipsis",
"text-overflow-mode",
"-ms-word-wrap",
"word-wrap",
"word-break",
"-ms-word-break",
"-moz-tab-size",
"-o-tab-size",
"tab-size",
"-webkit-hyphens",
"-moz-hyphens",
"hyphens",
"pointer-events"
],
[
"opacity",
"filter:progid:DXImageTransform.Microsoft.Alpha(Opacity",
"-ms-filter:\\'progid:DXImageTransform.Microsoft.Alpha",
"-ms-interpolation-mode",
"color",
"border",
"border-width",
"border-style",
"border-color",
"border-top",
"border-top-width",
"border-top-style",
"border-top-color",
"border-right",
"border-right-width",
"border-right-style",
"border-right-color",
"border-bottom",
"border-bottom-width",
"border-bottom-style",
"border-bottom-color",
"border-left",
"border-left-width",
"border-left-style",
"border-left-color",
"-webkit-border-radius",
"-moz-border-radius",
"border-radius",
"-webkit-border-top-left-radius",
"-moz-border-radius-topleft",
"border-top-left-radius",
"-webkit-border-top-right-radius",
"-moz-border-radius-topright",
"border-top-right-radius",
"-webkit-border-bottom-right-radius",
"-moz-border-radius-bottomright",
"border-bottom-right-radius",
"-webkit-border-bottom-left-radius",
"-moz-border-radius-bottomleft",
"border-bottom-left-radius",
"-webkit-border-image",
"-moz-border-image",
"-o-border-image",
"border-image",
"-webkit-border-image-source",
"-moz-border-image-source",
"-o-border-image-source",
"border-image-source",
"-webkit-border-image-slice",
"-moz-border-image-slice",
"-o-border-image-slice",
"border-image-slice",
"-webkit-border-image-width",
"-moz-border-image-width",
"-o-border-image-width",
"border-image-width",
"-webkit-border-image-outset",
"-moz-border-image-outset",
"-o-border-image-outset",
"border-image-outset",
"-webkit-border-image-repeat",
"-moz-border-image-repeat",
"-o-border-image-repeat",
"border-image-repeat",
"outline",
"outline-width",
"outline-style",
"outline-color",
"outline-offset",
"background",
"filter:progid:DXImageTransform.Microsoft.AlphaImageLoader",
"background-color",
"background-image",
"background-repeat",
"background-attachment",
"background-position",
"background-position-x",
"-ms-background-position-x",
"background-position-y",
"-ms-background-position-y",
"-webkit-background-clip",
"-moz-background-clip",
"background-clip",
"background-origin",
"-webkit-background-size",
"-moz-background-size",
"-o-background-size",
"background-size",
"box-decoration-break",
"-webkit-box-shadow",
"-moz-box-shadow",
"box-shadow",
"filter:progid:DXImageTransform.Microsoft.gradient",
"-ms-filter:\\'progid:DXImageTransform.Microsoft.gradient",
"text-shadow"
]
]
}
+324
View File
@@ -0,0 +1,324 @@
{
"exclude": [
".git/**",
"node_modules/**",
"bower_components/**"
],
"sort-order": [
[
"position",
"z-index",
"top",
"right",
"bottom",
"left"
],
[
"display",
"visibility",
"float",
"clear",
"overflow",
"overflow-x",
"overflow-y",
"-ms-overflow-x",
"-ms-overflow-y",
"-webkit-overflow-scrolling",
"clip",
"zoom",
"flex-direction",
"flex-order",
"flex-pack",
"flex-align"
],
[
"-webkit-box-sizing",
"-moz-box-sizing",
"box-sizing",
"width",
"min-width",
"max-width",
"height",
"min-height",
"max-height",
"margin",
"margin-top",
"margin-right",
"margin-bottom",
"margin-left",
"padding",
"padding-top",
"padding-right",
"padding-bottom",
"padding-left"
],
[
"table-layout",
"empty-cells",
"caption-side",
"border-spacing",
"border-collapse",
"list-style",
"list-style-position",
"list-style-type",
"list-style-image"
],
[
"content",
"quotes",
"counter-reset",
"counter-increment",
"resize",
"cursor",
"-webkit-user-select",
"-moz-user-select",
"-ms-user-select",
"user-select",
"nav-index",
"nav-up",
"nav-right",
"nav-down",
"nav-left",
"-webkit-transition",
"-moz-transition",
"-ms-transition",
"-o-transition",
"transition",
"-webkit-transition-delay",
"-moz-transition-delay",
"-ms-transition-delay",
"-o-transition-delay",
"transition-delay",
"-webkit-transition-timing-function",
"-moz-transition-timing-function",
"-ms-transition-timing-function",
"-o-transition-timing-function",
"transition-timing-function",
"-webkit-transition-duration",
"-moz-transition-duration",
"-ms-transition-duration",
"-o-transition-duration",
"transition-duration",
"-webkit-transition-property",
"-moz-transition-property",
"-ms-transition-property",
"-o-transition-property",
"transition-property",
"-webkit-transform",
"-moz-transform",
"-ms-transform",
"-o-transform",
"transform",
"-webkit-transform-origin",
"-moz-transform-origin",
"-ms-transform-origin",
"-o-transform-origin",
"transform-origin",
"-webkit-animation",
"-moz-animation",
"-ms-animation",
"-o-animation",
"animation",
"-webkit-animation-name",
"-moz-animation-name",
"-ms-animation-name",
"-o-animation-name",
"animation-name",
"-webkit-animation-duration",
"-moz-animation-duration",
"-ms-animation-duration",
"-o-animation-duration",
"animation-duration",
"-webkit-animation-play-state",
"-moz-animation-play-state",
"-ms-animation-play-state",
"-o-animation-play-state",
"animation-play-state",
"-webkit-animation-timing-function",
"-moz-animation-timing-function",
"-ms-animation-timing-function",
"-o-animation-timing-function",
"animation-timing-function",
"-webkit-animation-delay",
"-moz-animation-delay",
"-ms-animation-delay",
"-o-animation-delay",
"animation-delay",
"-webkit-animation-iteration-count",
"-moz-animation-iteration-count",
"-ms-animation-iteration-count",
"-o-animation-iteration-count",
"animation-iteration-count",
"-webkit-animation-iteration-count",
"-moz-animation-iteration-count",
"-ms-animation-iteration-count",
"-o-animation-iteration-count",
"animation-iteration-count",
"-webkit-animation-direction",
"-moz-animation-direction",
"-ms-animation-direction",
"-o-animation-direction",
"animation-direction",
"text-align",
"-webkit-text-align-last",
"-moz-text-align-last",
"-ms-text-align-last",
"text-align-last",
"vertical-align",
"white-space",
"text-decoration",
"text-emphasis",
"text-emphasis-color",
"text-emphasis-style",
"text-emphasis-position",
"text-indent",
"-ms-text-justify",
"text-justify",
"text-transform",
"letter-spacing",
"word-spacing",
"-ms-writing-mode",
"text-outline",
"text-transform",
"text-wrap",
"text-overflow",
"-ms-text-overflow",
"text-overflow-ellipsis",
"text-overflow-mode",
"-ms-word-wrap",
"word-wrap",
"word-break",
"-ms-word-break",
"-moz-tab-size",
"-o-tab-size",
"tab-size",
"-webkit-hyphens",
"-moz-hyphens",
"hyphens",
"pointer-events"
],
[
"opacity",
"filter:progid:DXImageTransform.Microsoft.Alpha(Opacity",
"-ms-filter:\\'progid:DXImageTransform.Microsoft.Alpha",
"-ms-interpolation-mode",
"color",
"border",
"border-collapse",
"border-width",
"border-style",
"border-color",
"border-top",
"border-top-width",
"border-top-style",
"border-top-color",
"border-right",
"border-right-width",
"border-right-style",
"border-right-color",
"border-bottom",
"border-bottom-width",
"border-bottom-style",
"border-bottom-color",
"border-left",
"border-left-width",
"border-left-style",
"border-left-color",
"-webkit-border-radius",
"-moz-border-radius",
"border-radius",
"-webkit-border-top-left-radius",
"-moz-border-radius-topleft",
"border-top-left-radius",
"-webkit-border-top-right-radius",
"-moz-border-radius-topright",
"border-top-right-radius",
"-webkit-border-bottom-right-radius",
"-moz-border-radius-bottomright",
"border-bottom-right-radius",
"-webkit-border-bottom-left-radius",
"-moz-border-radius-bottomleft",
"border-bottom-left-radius",
"-webkit-border-image",
"-moz-border-image",
"-o-border-image",
"border-image",
"-webkit-border-image-source",
"-moz-border-image-source",
"-o-border-image-source",
"border-image-source",
"-webkit-border-image-slice",
"-moz-border-image-slice",
"-o-border-image-slice",
"border-image-slice",
"-webkit-border-image-width",
"-moz-border-image-width",
"-o-border-image-width",
"border-image-width",
"-webkit-border-image-outset",
"-moz-border-image-outset",
"-o-border-image-outset",
"border-image-outset",
"-webkit-border-image-repeat",
"-moz-border-image-repeat",
"-o-border-image-repeat",
"border-image-repeat",
"outline",
"outline-width",
"outline-style",
"outline-color",
"outline-offset",
"background",
"filter:progid:DXImageTransform.Microsoft.AlphaImageLoader",
"background-color",
"background-image",
"background-repeat",
"background-attachment",
"background-position",
"background-position-x",
"-ms-background-position-x",
"background-position-y",
"-ms-background-position-y",
"-webkit-background-clip",
"-moz-background-clip",
"background-clip",
"background-origin",
"-webkit-background-size",
"-moz-background-size",
"-o-background-size",
"background-size",
"box-decoration-break",
"-webkit-box-shadow",
"-moz-box-shadow",
"box-shadow",
"-webkit-box-shadow",
"-moz-box-shadow",
"box-shadow",
"-webkit-box-shadow",
"-moz-box-shadow",
"box-shadow",
"-webkit-box-shadow",
"-moz-box-shadow",
"box-shadow",
"filter:progid:DXImageTransform.Microsoft.gradient",
"-ms-filter:\\'progid:DXImageTransform.Microsoft.gradient",
"text-shadow"
],
[
"font",
"font-family",
"font-size",
"font-weight",
"font-style",
"font-variant",
"font-size-adjust",
"font-stretch",
"font-effect",
"font-emphasize",
"font-emphasize-position",
"font-emphasize-style",
"font-smooth",
"line-height"
]
]
}
+384
View File
@@ -0,0 +1,384 @@
{
"exclude": [
".git/**",
"node_modules/**",
"bower_components/**"
],
"sort-order": [ [
"position",
"top",
"right",
"bottom",
"left",
"z-index",
"display",
"visibility",
"-webkit-flex-direction",
"-moz-flex-direction",
"-ms-flex-direction",
"-o-flex-direction",
"flex-direction",
"-webkit-flex-order",
"-moz-flex-order",
"-ms-flex-order",
"-o-flex-order",
"flex-order",
"-webkit-flex-pack",
"-moz-flex-pack",
"-ms-flex-pack",
"-o-flex-pack",
"flex-pack",
"float",
"clear",
"-webkit-flex-align",
"-moz-flex-align",
"-ms-flex-align",
"-o-flex-align",
"flex-align",
"overflow",
"-ms-overflow-x",
"-ms-overflow-y",
"overflow-x",
"overflow-y",
"-webkit-overflow-scrolling",
"clip",
"-webkit-box-sizing",
"-moz-box-sizing",
"box-sizing",
"margin",
"margin-top",
"margin-right",
"margin-bottom",
"margin-left",
"padding",
"padding-top",
"padding-right",
"padding-bottom",
"padding-left",
"min-width",
"min-height",
"max-width",
"max-height",
"width",
"height",
"outline",
"outline-width",
"outline-style",
"outline-color",
"outline-offset",
"border",
"border-spacing",
"border-collapse",
"border-width",
"border-style",
"border-color",
"border-top",
"border-top-width",
"border-top-style",
"border-top-color",
"border-right",
"border-right-width",
"border-right-style",
"border-right-color",
"border-bottom",
"border-bottom-width",
"border-bottom-style",
"border-bottom-color",
"border-left",
"border-left-width",
"border-left-style",
"border-left-color",
"-webkit-border-radius",
"-moz-border-radius",
"border-radius",
"-webkit-border-top-left-radius",
"-moz-border-radius-topleft",
"border-top-left-radius",
"-webkit-border-top-right-radius",
"-moz-border-radius-topright",
"border-top-right-radius",
"-webkit-border-bottom-right-radius",
"-moz-border-radius-bottomright",
"border-bottom-right-radius",
"-webkit-border-bottom-left-radius",
"-moz-border-radius-bottomleft",
"border-bottom-left-radius",
"-webkit-border-image",
"-moz-border-image",
"-o-border-image",
"border-image",
"-webkit-border-image-source",
"-moz-border-image-source",
"-o-border-image-source",
"border-image-source",
"-webkit-border-image-slice",
"-moz-border-image-slice",
"-o-border-image-slice",
"border-image-slice",
"-webkit-border-image-width",
"-moz-border-image-width",
"-o-border-image-width",
"border-image-width",
"-webkit-border-image-outset",
"-moz-border-image-outset",
"-o-border-image-outset",
"border-image-outset",
"-webkit-border-image-repeat",
"-moz-border-image-repeat",
"-o-border-image-repeat",
"border-image-repeat",
"-webkit-border-top-image",
"-moz-border-top-image",
"-o-border-top-image",
"border-top-image",
"-webkit-border-right-image",
"-moz-border-right-image",
"-o-border-right-image",
"border-right-image",
"-webkit-border-bottom-image",
"-moz-border-bottom-image",
"-o-border-bottom-image",
"border-bottom-image",
"-webkit-border-left-image",
"-moz-border-left-image",
"-o-border-left-image",
"border-left-image",
"-webkit-border-corner-image",
"-moz-border-corner-image",
"-o-border-corner-image",
"border-corner-image",
"-webkit-border-top-left-image",
"-moz-border-top-left-image",
"-o-border-top-left-image",
"border-top-left-image",
"-webkit-border-top-right-image",
"-moz-border-top-right-image",
"-o-border-top-right-image",
"border-top-right-image",
"-webkit-border-bottom-right-image",
"-moz-border-bottom-right-image",
"-o-border-bottom-right-image",
"border-bottom-right-image",
"-webkit-border-bottom-left-image",
"-moz-border-bottom-left-image",
"-o-border-bottom-left-image",
"border-bottom-left-image",
"background",
"filter:progid:DXImageTransform.Microsoft.AlphaImageLoader",
"background-color",
"background-image",
"background-attachment",
"background-position",
"-ms-background-position-x",
"-ms-background-position-y",
"background-position-x",
"background-position-y",
"-webkit-background-clip",
"-moz-background-clip",
"background-clip",
"background-origin",
"-webkit-background-size",
"-moz-background-size",
"-o-background-size",
"background-size",
"background-repeat",
"box-decoration-break",
"-webkit-box-shadow",
"-moz-box-shadow",
"box-shadow",
"color",
"table-layout",
"caption-side",
"empty-cells",
"list-style",
"list-style-position",
"list-style-type",
"list-style-image",
"quotes",
"content",
"counter-increment",
"counter-reset",
"-ms-writing-mode",
"vertical-align",
"text-align",
"-webkit-text-align-last",
"-moz-text-align-last",
"-ms-text-align-last",
"text-align-last",
"text-decoration",
"text-emphasis",
"text-emphasis-position",
"text-emphasis-style",
"text-emphasis-color",
"text-indent",
"-ms-text-justify",
"text-justify",
"text-outline",
"text-transform",
"text-wrap",
"-ms-text-overflow",
"text-overflow",
"text-overflow-ellipsis",
"text-overflow-mode",
"text-shadow",
"white-space",
"word-spacing",
"-ms-word-wrap",
"word-wrap",
"-ms-word-break",
"word-break",
"-moz-tab-size",
"-o-tab-size",
"tab-size",
"-webkit-hyphens",
"-moz-hyphens",
"hyphens",
"letter-spacing",
"font",
"font-weight",
"font-style",
"font-variant",
"font-size-adjust",
"font-stretch",
"font-size",
"font-family",
"src",
"line-height",
"opacity",
"-ms-filter:\\'progid:DXImageTransform.Microsoft.Alpha",
"filter:progid:DXImageTransform.Microsoft.Alpha(Opacity",
"-ms-interpolation-mode",
"-webkit-filter",
"-ms-filter",
"filter",
"resize",
"cursor",
"nav-index",
"nav-up",
"nav-right",
"nav-down",
"nav-left",
"-webkit-transition",
"-moz-transition",
"-ms-transition",
"-o-transition",
"transition",
"-webkit-transition-delay",
"-moz-transition-delay",
"-ms-transition-delay",
"-o-transition-delay",
"transition-delay",
"-webkit-transition-timing-function",
"-moz-transition-timing-function",
"-ms-transition-timing-function",
"-o-transition-timing-function",
"transition-timing-function",
"-webkit-transition-duration",
"-moz-transition-duration",
"-ms-transition-duration",
"-o-transition-duration",
"transition-duration",
"-webkit-transition-property",
"-moz-transition-property",
"-ms-transition-property",
"-o-transition-property",
"transition-property",
"-webkit-transform",
"-moz-transform",
"-ms-transform",
"-o-transform",
"transform",
"-webkit-transform-origin",
"-moz-transform-origin",
"-ms-transform-origin",
"-o-transform-origin",
"transform-origin",
"-webkit-animation",
"-moz-animation",
"-ms-animation",
"-o-animation",
"animation",
"-webkit-animation-name",
"-moz-animation-name",
"-ms-animation-name",
"-o-animation-name",
"animation-name",
"-webkit-animation-duration",
"-moz-animation-duration",
"-ms-animation-duration",
"-o-animation-duration",
"animation-duration",
"-webkit-animation-play-state",
"-moz-animation-play-state",
"-ms-animation-play-state",
"-o-animation-play-state",
"animation-play-state",
"-webkit-animation-timing-function",
"-moz-animation-timing-function",
"-ms-animation-timing-function",
"-o-animation-timing-function",
"animation-timing-function",
"-webkit-animation-delay",
"-moz-animation-delay",
"-ms-animation-delay",
"-o-animation-delay",
"animation-delay",
"-webkit-animation-iteration-count",
"-moz-animation-iteration-count",
"-ms-animation-iteration-count",
"-o-animation-iteration-count",
"animation-iteration-count",
"-webkit-animation-direction",
"-moz-animation-direction",
"-ms-animation-direction",
"-o-animation-direction",
"animation-direction",
"pointer-events",
"unicode-bidi",
"direction",
"-webkit-columns",
"-moz-columns",
"columns",
"-webkit-column-span",
"-moz-column-span",
"column-span",
"-webkit-column-width",
"-moz-column-width",
"column-width",
"-webkit-column-count",
"-moz-column-count",
"column-count",
"-webkit-column-fill",
"-moz-column-fill",
"column-fill",
"-webkit-column-gap",
"-moz-column-gap",
"column-gap",
"-webkit-column-rule",
"-moz-column-rule",
"column-rule",
"-webkit-column-rule-width",
"-moz-column-rule-width",
"column-rule-width",
"-webkit-column-rule-style",
"-moz-column-rule-style",
"column-rule-style",
"-webkit-column-rule-color",
"-moz-column-rule-color",
"column-rule-color",
"break-before",
"break-inside",
"break-after",
"page-break-before",
"page-break-inside",
"page-break-after",
"orphans",
"widows",
"-ms-zoom",
"zoom",
"max-zoom",
"min-zoom",
"user-zoom",
"orientation"
] ]
}
+100
View File
@@ -0,0 +1,100 @@
/**
* Command line implementation for CSSComb
*
* Usage example:
* ./node_modules/.bin/csscomb [options] file1 [dir1 [fileN [dirN]]]
*/
var fs = require('fs');
var path = require('path');
var program = require('commander');
var vow = require('vow');
var Comb = require('./csscomb');
program
.version(require('../package.json').version)
.usage('[options] <file ...>')
.option('-v, --verbose', 'verbose mode')
.option('-c, --config [path]', 'configuration file path')
.option('-d, --detect', 'detect mode (would return detected options)')
.option('-l, --lint', 'in case some fixes needed returns an error')
.parse(process.argv);
if (!program.args.length) {
console.log('No input paths specified');
program.help();
}
var comb = new Comb();
if (program.detect) {
console.log(JSON.stringify(Comb.detectInFile(program.args[0]), false, 4));
process.exit(0);
}
var config;
var configPath = program.config &&
path.resolve(process.cwd(), program.config) ||
Comb.getCustomConfigPath();
if (!fs.existsSync(configPath)) {
config = require('../config/csscomb.json');
} else if (configPath.match(/\.css$/)) {
config = Comb.detectInFile(configPath);
} else {
config = Comb.getCustomConfig(configPath);
}
if (!config) {
console.log('Configuration file ' + configPath + ' was not found.');
process.exit(1);
}
if (config.template) {
if (fs.existsSync(config.template)) {
var templateConfig = Comb.detectInFile(config.template);
for (var attrname in templateConfig) {
if (!config[attrname]) {
config[attrname] = templateConfig[attrname];
}
}
} else {
console.log('Template configuration file ' + config.template + ' was not found.');
process.exit(1);
}
}
console.time('spent');
config.verbose = program.verbose === true || config.verbose;
config.lint = program.lint;
comb.configure(config);
vow.all(program.args.map(comb.processPath.bind(comb)))
.then(function(changedFiles) {
changedFiles = [].concat.apply([], changedFiles)
.filter(function(isChanged) {
return isChanged !== undefined;
});
for (var i = changedFiles.length, tbchanged = 0; i--;) {
tbchanged += changedFiles[i];
}
var changed = config.lint ? 0 : tbchanged;
if (config.verbose) {
console.log('');
console.log(changedFiles.length + ' file' + (changedFiles.length === 1 ? '' : 's') + ' processed');
console.log(changed + ' file' + (changed === 1 ? '' : 's') + ' fixed');
console.timeEnd('spent');
}
if (config.lint && tbchanged) {
process.exit(1);
}
})
.fail(function(e) {
console.log('stack: ', e.stack);
process.exit(1);
});
+321
View File
@@ -0,0 +1,321 @@
var Comb = require('csscomb-core');
var gonzales = require('gonzales-pe');
var fs = require('fs');
var path = require('path');
/**
* Converts CSS string to AST.
*
* @param {String} text CSS string
* @param {String} [syntax] Syntax name (e.g., `scss`)
* @param {String} [filename]
* @returns {Array} AST
*/
function cssToAST(text, syntax, filename) {
var string = JSON.stringify;
var fileInfo = filename ? ' at ' + filename : '';
var tree;
try {
tree = gonzales.parse(text, { syntax: syntax });
} catch (e) {
throw new Error('Parsing error' + fileInfo + ': ' + e.message);
}
// TODO: When can tree be undefined? <tg>
if (typeof tree === 'undefined') {
throw new Error('Undefined tree' + fileInfo + ': ' + string(text) + ' => ' + string(tree));
}
return tree;
}
/**
* Gets option's data needed for detection
*
* @param {String} optionName
* @returns {Object} Object with option's name, link to `detect()` method
* and default value for the case when nothing can be detected
*/
function getHandler(optionName) {
var option = require('./options/' + optionName);
if (!option.detect) throw new Error('Option does not have `detect()` method.');
return {
name: option.name,
detect: option.detect,
detectDefault: option.detectDefault
};
}
/**
* Processes tree node and detects options.
*
* @param {Array} node Tree node
* @param {Number} level Indent level
* @param {Object} handler Object with option's data
* @param {Object} detectedOptions
*/
function detectInNode(node, level, handler, detectedOptions) {
node.map(function(tree) {
var detected = handler.detect(tree);
var variants = detectedOptions[handler.name];
if (typeof detected === 'object') {
variants.push.apply(variants, detected);
} else if (typeof detected !== 'undefined') {
variants.push(detected);
}
//if (nodeType === 'atrulers' || nodeType === 'block') level++;
});
}
/**
* Processes tree and detects options.
*
* @param {Array} tree
* @param {Array} handlers List of options that we should look for
* @returns {Object} Map with detected options and all variants of possible
* values
*/
function detectInTree(tree, handlers) {
var detectedOptions = {};
// We walk across complete tree for each handler,
// because we need strictly maintain order in which handlers work,
// despite fact that handlers work on different level of the tree.
handlers.forEach(function(handler) {
detectedOptions[handler.name] = [];
// TODO: Pass all parameters as one object? <tg>
detectInNode(tree, 0, handler, detectedOptions);
});
return detectedOptions;
}
/**
* Gets the detected options.
*
* @param {Object} detected
* @param {Array} handlers
* @returns {Object}
*/
function getDetectedOptions(detected, handlers) {
var options = {};
Object.keys(detected).forEach(function(option) {
// List of all the detected variants from the stylesheet for the given option:
var values = detected[option];
var i;
if (!values.length) {
// If there are no values for the option, check if there is a default one:
for (i = handlers.length; i--;) {
if (handlers[i].name === option &&
handlers[i].detectDefault !== undefined) {
options[option] = handlers[i].detectDefault;
break;
}
}
} else if (values.length === 1) {
options[option] = values[0];
} else {
// If there are more than one value for the option, find the most popular one;
// `variants` would be populated with the popularity for different values.
var variants = {};
var bestGuess = null;
var maximum = 0;
for (i = values.length; i--;) {
var currentValue = values[i];
// Count the current value:
if (variants[currentValue]) {
variants[currentValue]++;
} else {
variants[currentValue] = 1;
}
// If the current variant is the most popular one, treat
// it as the best guess:
if (variants[currentValue] >= maximum) {
maximum = variants[currentValue];
bestGuess = currentValue;
}
}
if (bestGuess !== null) {
options[option] = bestGuess;
}
}
});
return options;
}
/**
* Starts Code Style processing process.
*
* @param {String|Object} config
* @constructor
* @name CSScomb
*/
var CSScomb = function(config) {
var options = fs.readdirSync(__dirname + '/options').map(function(option) {
return require('./options/' + option);
});
var comb = new Comb(options, 'css', 'less', 'scss', 'sass');
// If config was passed, configure:
if (typeof config === 'string') {
config = CSScomb.getConfig(config);
}
if (typeof config === 'object') {
comb.configure(config);
}
return comb;
};
/**
* STATIC METHODS
* Methods that can be called without creating an instance:
* - getConfig;
* - getCustomConfig;
* - getCustomConfigPath;
* - detectInFile;
* - detectInString.
* For example: `CSScomb.getConfig('zen')`
*/
/**
* Gets one of configuration files from configs' directory.
*
* @param {String} name Config's name, e.g. 'yandex'
* @returns {Object} Configuration object
*/
CSScomb.getConfig = function getConfig(name) {
var DEFAULT_CONFIG_NAME = 'csscomb';
name = name || DEFAULT_CONFIG_NAME;
if (typeof name !== 'string') {
throw new Error('Config name must be a string.');
}
var CONFIG_DIR_PATH = '../config';
var availableConfigsNames = fs.readdirSync(__dirname + '/' + CONFIG_DIR_PATH)
.map(function(configFileName) {
return configFileName.split('.')[0]; // strip file extension(s)
});
if (availableConfigsNames.indexOf(name) < 0) {
var configsNamesAsString = availableConfigsNames
.map(function(configName) {
return '\'' + configName + '\'';
})
.join(', ');
throw new Error('"' + name + '" is not a valid config name. Try one of ' +
'the following: ' + configsNamesAsString + '.');
}
return require(CONFIG_DIR_PATH + '/' + name + '.json');
};
/**
* Gets configuration from provided config path or looks for it in common
* places.
*
* @param {String} [configPath]
* @returns {Object|null}
*/
CSScomb.getCustomConfig = function getCustomConfig(configPath) {
var config;
configPath = configPath || CSScomb.getCustomConfigPath();
try {
config = JSON.parse(fs.readFileSync(configPath, 'utf8'));
} catch (e) {
config = null;
}
return config;
};
/**
* Looks for a config file: recursively from current (process) directory
* up to $HOME dir
* If no custom config file is found, return `null`.
*
* @param {String} [configPath]
* @returns {String | null}
*/
CSScomb.getCustomConfigPath = function getCustomConfigPath(configPath) {
var HOME = process.env.HOME || process.env.HOMEPATH || process.env.USERPROFILE;
configPath = configPath || path.join(process.cwd(), '.csscomb.json');
// If we've finally found a config, return its path:
if (fs.existsSync(configPath)) return fs.realpathSync(configPath);
// If we are in HOME dir already and yet no config file, return a default
// one from our package.
// If project is located not under HOME, compare to root instead.
// Since there appears to be no good way to get root path in
// Windows, assume that if current dir has no parent dir, we're in
// root.
var dirname = path.dirname(configPath);
var parentDirname = path.dirname(dirname);
if (dirname === HOME || dirname === parentDirname) return null;
// If there is no config in this directory, go one level up and look for
// a config there:
configPath = path.join(parentDirname, '.csscomb.json');
return CSScomb.getCustomConfigPath(configPath);
};
/**
* Detects the options in the given file
*
* @param {String} path Path to the stylesheet
* @param {Array} options List of options to detect
* @returns {Object} Detected options
*/
CSScomb.detectInFile = function detectInFile(path, options) {
var stylesheet = fs.readFileSync(path, 'utf8');
return CSScomb.detectInString(stylesheet, options);
};
/**
* Detects the options in the given string
*
* @param {String} text Stylesheet
* @param {Array} options List of options to detect
* @returns {Object} Detected options
*/
CSScomb.detectInString = function detectInString(text, options) {
var result;
var handlers = [];
if (!text) return text;
var optionNames = fs.readdirSync(__dirname + '/options');
optionNames.forEach(function(option) {
option = option.slice(0, -3);
if (options && options.indexOf(option) < 0) return;
try {
handlers.push(getHandler(option));
} catch (e) {
console.warn('\nFailed to load "%s" option:\n%s', option, e.message);
}
});
var tree = cssToAST(text);
var detectedOptions = detectInTree(tree, handlers);
result = getDetectedOptions(detectedOptions, handlers);
// Handle conflicting options with spaces around braces:
var blockIndent = result['block-indent'];
var spaceAfterOpeningBrace = result['space-after-opening-brace'];
if (typeof blockIndent === 'string' &&
spaceAfterOpeningBrace &&
spaceAfterOpeningBrace.indexOf('\n') > -1) {
result['space-after-opening-brace'] = '\n';
}
return result;
};
module.exports = CSScomb;
+5
View File
@@ -0,0 +1,5 @@
'use strict';
module.exports = function (string) {
return string.replace(/\n\s+/gm, ' ');
};
+4
View File
@@ -0,0 +1,4 @@
// jscs:disable
'use strict';
module.exports = require('../node_modules/csscomb-core/node_modules/gonzales-pe');
@@ -0,0 +1,73 @@
var gonzales = require('gonzales-pe');
module.exports = {
name: 'always-semicolon',
syntax: ['css', 'less', 'sass', 'scss'],
accepts: { boolean: [true] },
/**
* Processes tree node.
* @param {node} node
*/
process: function(node) {
var nodeWithoutSemicolon;
if (!node.is('block')) return;
mainLoop:
for (var i = node.length; i--;) {
var currentNode = node.get(i);
// Skip nodes that already have `;` at the end:
if (currentNode.is('declarationDelimiter')) break;
// Add semicolon only after declarations and includes.
// If current node is include, insert semicolon right into it.
// If it's declaration, look for value node:
if (currentNode.is('include')) {
nodeWithoutSemicolon = currentNode;
} else if (currentNode.is('declaration')) {
nodeWithoutSemicolon = currentNode.last('value');
} else {
continue;
}
// Check if there are spaces and comments at the end of the node:
for (var j = nodeWithoutSemicolon.length; j--; ) {
var lastNode = nodeWithoutSemicolon.get(j);
// If the node's last child is block, do not add semicolon:
// TODO: Add syntax check and run the code only for scss
if (lastNode.is('block')) {
break mainLoop;
} else if (!lastNode.is('space') &&
!lastNode.is('multilineComment') &&
!lastNode.is('singlelineComment')) {
j++;
break;
}
}
var declDelim = gonzales.createNode({ type: 'declarationDelimiter', content: ';' });
nodeWithoutSemicolon.insert(j, declDelim);
break;
}
},
/**
* Detects the value of an option at the tree node.
*
* @param {node} node
*/
detect: function(node) {
if (!node.is('block')) return;
for (var i = node.length; i--;) {
var nodeItem = node.get(i);
if (nodeItem.is('declarationDelimiter')) return true;
if (nodeItem.is('declaration')) return false;
}
}
};
@@ -0,0 +1,135 @@
module.exports = (function() {
var syntax;
var value;
function processNode(node, level) {
level = level || 0;
// XXX: Hack for braces
if (node.is('braces') || node.is('id')) return;
for (var i = 0; i < node.length; i++) {
var n = node.get(i);
if (!n) continue;
if (syntax === 'sass' && n.is('block')) {
processSassBlock(n, level, value);
}
// Continue only with space nodes inside {...}:
if (syntax !== 'sass' && level !== 0 && n.is('space')) {
processSpaceNode(n, level, value);
}
if (n.is('block') || n.is('atrulers')) level++;
processNode(n, level);
}
}
function processSassBlock(node, level, value) {
var spaces;
var whitespaceNode;
var i;
for (i = node.length; i--;) {
whitespaceNode = node.get(i);
if (!whitespaceNode.is('space')) continue;
if (whitespaceNode.content === '\n') continue;
spaces = whitespaceNode.content.replace(/[ \t]/gm, '');
spaces += new Array(level + 2).join(value);
whitespaceNode.content = spaces;
}
}
function processSpaceNode(node, level, value) {
var spaces;
// Remove all whitespaces and tabs, leave only new lines:
spaces = node.content.replace(/[ \t]/gm, '');
if (!spaces) return;
spaces += new Array(level + 1).join(value);
node.content = spaces;
}
return {
name: 'block-indent',
runBefore: 'sort-order',
syntax: ['css', 'less', 'sass', 'scss'],
accepts: {
number: true,
string: /^[ \t]*$/
},
/**
* Processes tree node.
*
* @param {node} node
*/
process: function process(node) {
var spaces;
var whitespaceNode;
var i;
if (!node.is('stylesheet')) return;
syntax = this.getSyntax();
value = this.getValue('block-indent');
for (i = node.length; i--;) {
whitespaceNode = node.get(i);
if (!whitespaceNode.is('space')) continue;
spaces = whitespaceNode.content.replace(/\n[ \t]+/gm, '\n');
if (spaces === '') {
node.remove(i);
} else {
whitespaceNode.content = spaces;
}
}
processNode(node);
},
/**
* Detects the value of an option at the tree node.
*
* @param {node} node
*/
detect: function(node) {
var result = [];
// Continue only with non-empty {...} blocks:
if (!node.is('atrulers') && !node.is('block') || !node.length)
return;
for (var i = node.length; i--;) {
var whitespaceNode = node.get(i);
if (!whitespaceNode.is('space')) continue;
var spaces = whitespaceNode.content;
var lastIndex = spaces.lastIndexOf('\n');
// Do not continue if there is no line break:
if (lastIndex < 0) continue;
// Number of spaces from beginning of line:
var spacesLength = spaces.slice(lastIndex + 1).length + 1;
result.push(new Array(spacesLength).join(' '));
}
return result;
}
};
})();
@@ -0,0 +1,34 @@
module.exports = {
name: 'color-case',
syntax: ['css', 'less', 'sass', 'scss'],
accepts: { string: /^lower|upper$/ },
/**
* Processes tree node.
* @param {node} node
*/
process: function(node) {
if (!node.is('color')) return;
node.content = this.getValue('color-case') === 'lower' ?
node.content.toLowerCase() :
node.content.toUpperCase();
},
/**
* Detects the value of an option at the tree node.
*
* @param {node} node
*/
detect: function(node) {
if (!node.is('color')) return;
if (node.content.match(/^[^A-F]*[a-f][^A-F]*$/)) {
return 'lower';
} else if (node.content.match(/^[^a-f]*[A-F][^a-f]*$/)) {
return 'upper';
}
}
};
@@ -0,0 +1,34 @@
module.exports = {
name: 'color-shorthand',
syntax: ['css', 'less', 'sass', 'scss'],
accepts: { boolean: [true, false] },
/**
* Processes tree node.
* @param {node} node
*/
process: function(node) {
if (!node.is('color')) return;
node.content = this.getValue('color-shorthand') ?
node.content.replace(/(\w)\1(\w)\2(\w)\3/i, '$1$2$3') :
node.content.replace(/^(\w)(\w)(\w)$/, '$1$1$2$2$3$3');
},
/**
* Detects the value of an option at the tree node.
*
* @param {node} node
*/
detect: function(node) {
if (!node.is('color')) return;
if (node.content.match(/^\w{3}$/)) {
return true;
} else if (node.content.match(/^(\w)\1(\w)\2(\w)\3$/)) {
return false;
}
}
};
@@ -0,0 +1,49 @@
module.exports = {
name: 'element-case',
syntax: ['css', 'less', 'sass', 'scss'],
accepts: { string: /^lower|upper$/ },
/**
* Processes tree node.
* @param {node} node
*/
process: function(node) {
if (!node.is('selector') &&
!node.is('arguments')) return;
var value = this.getValue('element-case');
node.forEach('simpleSelector', function(selector) {
selector.forEach('ident', function(ident) {
ident.content = value === 'lower' ?
ident.content.toLowerCase() :
ident.content.toUpperCase();
});
});
},
/**
* Detects the value of an option at the tree node.
*
* @param {node} node
*/
detect: function(node) {
if (!node.is('selector') &&
!node.is('arguments')) return;
var variants = [];
node.forEach('simpleSelector', function(selector) {
selector.forEach('ident', function(ident) {
if (ident.content.match(/^[a-z]+$/)) {
variants.push('lower');
} else if (ident.content.match(/^[A-Z]+$/)) {
variants.push('upper');
}
});
});
return variants;
}
};
@@ -0,0 +1,41 @@
var gonzales = require('gonzales-pe');
module.exports = {
name: 'eof-newline',
syntax: ['css', 'less', 'sass', 'scss'],
accepts: { boolean: [true, false] },
/**
* Processes tree node.
* @param {node} node
*/
process: function(node) {
if (!node.is('stylesheet')) return;
var lastChild = node.last();
if (!lastChild.is('space')) {
lastChild = gonzales.createNode({ type: 'space', content: '' });
node.content.push(lastChild);
}
lastChild.content = lastChild.content.replace(/\n$/, '');
if (this.getValue('eof-newline')) lastChild.content += '\n';
},
/**
* Detects the value of an option at the tree node.
*
* @param {node} node
*/
detect: function(node) {
if (!node.is('stylesheet')) return;
var lastChild = node.last();
if (lastChild.is('space') && lastChild.content.indexOf('\n') !== -1) {
return true;
} else {
return false;
}
}
};
@@ -0,0 +1,37 @@
module.exports = {
name: 'leading-zero',
syntax: ['css', 'less', 'sass', 'scss'],
accepts: { boolean: [true, false] },
/**
* Processes tree node.
* @param {node} node
*/
process: function(node) {
if (!node.is('number')) return;
if (this.getValue('leading-zero')) {
if (node.content[0] === '.')
node.content = '0' + node.content;
} else {
node.content = node.content.replace(/^0+(?=\.)/, '');
}
},
/**
* Detects the value of an option at the tree node.
*
* @param {node} node
*/
detect: function(node) {
if (!node.is('number')) return;
if (node.content.match(/^\.[0-9]+/)) {
return false;
} else if (node.content.match(/^0\.[0-9]+/)) {
return true;
}
}
};
+45
View File
@@ -0,0 +1,45 @@
module.exports = {
name: 'quotes',
syntax: ['css', 'less', 'sass', 'scss'],
accepts: { string: /^single|double$/ },
/**
* Processes tree node.
* @param {node} node
*/
process: function(node) {
if (!node.is('string')) return;
var value = this.getValue('quotes');
if (node.content[0] === '"' && value === 'single') {
node.content = node.content
.replace(/\\"/g, '"') // unescape all escaped double quotes
.replace(/([^\\])'/g, '$1\\\'') // escape all the single quotes
.replace(/^"|"$/g, '\''); // replace the first and the last quote
} else if (node.content[0] === '\'' && value === 'double') {
node.content = node.content
.replace(/\\'/g, '\'') // unescape all escaped single quotes
.replace(/([^\\])"/g, '$1\\\"') // escape all the double quotes
.replace(/^'|'$/g, '"'); // replace the first and the last quote
}
},
/**
* Detects the value of an option at the tree node.
*
* @param {node} node
*/
detect: function(node) {
if (!node.is('string')) return;
if (node.content[0] === '"') {
return 'double';
} else if (node.content[0] === '\'') {
return 'single';
}
}
};
@@ -0,0 +1,81 @@
module.exports = (function() {
function processNode(node) {
removeEmptyRulesets(node);
mergeAdjacentWhitespace(node);
}
function removeEmptyRulesets(stylesheet) {
stylesheet.forEach('ruleset', function(ruleset, i) {
var block = ruleset.first('block');
processNode(block);
if (isEmptyBlock(block)) stylesheet.remove(i);
});
}
/**
* Removing ruleset nodes from tree may result in two adjacent whitespace
* nodes which is not correct AST:
* [space, ruleset, space] => [space, space]
* To ensure correctness of further processing we should merge such nodes
* into one:
* [space, space] => [space]
*/
function mergeAdjacentWhitespace(node) {
var i = node.content.length - 1;
while (i-- > 0) {
if (node.get(i).is('space') && node.get(i + 1).is('space')) {
node.get(i).content += node.get(i + 1).content;
node.remove(i + 1);
}
}
}
/**
* Block is considered empty when it has nothing but spaces.
*/
function isEmptyBlock(node) {
if (!node.length) return true;
return !node.content.some(function(node) {
return !node.is('space');
});
}
return {
name: 'remove-empty-rulesets',
runBefore: 'block-indent',
syntax: ['css', 'less', 'sass', 'scss'],
accepts: { boolean: [true] },
/**
* Remove rulesets with no declarations.
*
* @param {String} node
*/
process: function(node) {
if (!node.is('stylesheet')) return;
processNode(node);
},
detectDefault: true,
/**
* Detects the value of an option at the tree node.
* This option is treated as `true` by default, but any trailing space would invalidate it.
*
* @param {node} node
*/
detect: function(node) {
if (!node.is('atrulers') && !node.is('block')) return;
if (node.length === 0 ||
(node.length === 1 && node.first().is('space'))) {
return false;
}
}
};
})();
@@ -0,0 +1,9 @@
module.exports = {
name: 'sort-order-fallback',
syntax: ['css', 'less', 'sass', 'scss'],
accepts: { string: /^abc$/ },
process: function() {}
};
@@ -0,0 +1,388 @@
var gonzales = require('gonzales-pe');
module.exports = {
name: 'sort-order',
runBefore: 'space-before-closing-brace',
syntax: ['css', 'less', 'sass', 'scss'],
/**
* Sets handler value.
*
* @param {Array} value Option value
* @returns {Array}
*/
setValue: function(value) {
if (!Array.isArray(value)) throw new Error('The option accepts only array of properties.');
var order = {};
if (typeof value[0] === 'string') {
value.forEach(function(prop, propIndex) {
order[prop] = { group: 0, prop: propIndex };
});
} else {
value.forEach(function(group, groupIndex) {
group.forEach(function(prop, propIndex) {
order[prop] = { group: groupIndex, prop: propIndex };
});
});
}
return order;
},
/**
* Processes tree node.
* @param {node} node
*/
process: function(node) {
var _this = this;
// Types of nodes that can be sorted:
var NODES = ['atruleb', 'atruler', 'atrules', 'multilineComment', 'singlelineComment',
'declaration', 'space', 'include'];
// Spaces and comments:
var SC = ['multilineComment', 'singlelineComment', 'space'];
var currentNode;
// Sort order of properties:
var order = this.getValue('sort-order');
var syntax = this.getSyntax();
// List of declarations that should be sorted:
var sorted = [];
// list of nodes that should be removed from parent node:
var deleted = [];
// List of spaces and comments that go before declaration/@-rule:
var sc0 = [];
// Value to search in sort order: either a declaration's property name
// (e.g. `color`), or @-rule's special keyword (e.g. `$import`):
var propertyName;
// Index to place the nodes that shouldn't be sorted
var lastGroupIndex = order['...'] ? order['...'].group : Infinity;
var lastPropertyIndex = order['...'] ? order['...'].prop : Infinity;
// Counters for loops:
var i;
var l;
var j;
var nl;
/**
* Remove empty lines in space node.
* @param {node} node Space node.
*/
var removeEmptyLines = function(node) {
node.content = node.content.replace(/\n[\s\t\n\r]*\n/, '\n');
};
/**
* Check if there are any comments or spaces before
* the declaration/@-rule.
* @returns {Array} List of nodes with spaces and comments
*/
var checkSC0 = function() {
// List of nodes with spaces and comments:
var sc = [];
// List of nodes that can be later deleted from parent node:
var d = [];
for (; i < l; i++) {
currentNode = node.get(i);
// If there is no node left,
// stop and do nothing with previously found spaces/comments:
if (!currentNode) {
return false;
}
// If the node is declaration or @-rule, stop and return all
// found nodes with spaces and comments (if there are any):
if (SC.indexOf(currentNode.type) === -1) break;
sc.push(currentNode);
d.push(i);
}
deleted = deleted.concat(d);
return sc;
};
/**
* Check if there are any comments or spaces after
* the declaration/@-rule.
* @returns {Array} List of nodes with spaces and comments
* @private
*/
var checkSC1 = function() {
// List of nodes with spaces and comments:
var sc = [];
// List of nodes that can be later deleted from parent node:
var d = [];
// Position of `\n` symbol inside a node with spaces:
var lbIndex;
// Check every next node:
for (; i < l; i++) {
currentNode = node.get(i + 1);
// If there is no node, or it is nor spaces neither comment, stop:
if (!currentNode || SC.indexOf(currentNode.type) === -1) break;
if (currentNode.is('multilineComment') || currentNode.is('singlelineComment')) {
sc.push(currentNode);
d.push(i + 1);
continue;
}
lbIndex = currentNode.content.indexOf('\n');
// If there are any line breaks in a node with spaces, stop and
// split the node into two: one with spaces before line break
// and one with `\n` symbol and everything that goes after.
// Combine the first one with declaration/@-rule's node:
if (lbIndex > -1) {
// TODO: Don't push an empty array
var s = currentNode.content.substring(0, lbIndex);
var space = gonzales.createNode({ type: 's', content: s });
sc.push(space);
currentNode.content = currentNode.content.substring(lbIndex);
break;
}
sc.push(currentNode);
d.push(i + 1);
}
deleted = deleted.concat(d);
return sc;
};
/**
* Combine declaration/@-rule's node with other relevant information:
* property index, semicolon, spaces and comments.
* @returns {Object} Extended node
*/
var extendNode = function() {
currentNode = node.get(i);
var nextNode = node.get(i + 1);
// Object containing current node, all corresponding spaces,
// comments and other information:
var extendedNode;
// Check if current node's property name is in sort order.
// If it is, save information about its indices:
var orderProperty = order[propertyName];
extendedNode = {
i: i,
node: currentNode,
sc0: sc0,
sc1: [],
sc2: [],
delim: []
};
// If the declaration's property is in order's list, save its
// group and property indices. Otherwise set them to 10000, so
// declaration appears at the bottom of a sorted list:
extendedNode.groupIndex = orderProperty && orderProperty.group > -1 ?
orderProperty.group : lastGroupIndex;
extendedNode.propertyIndex = orderProperty && orderProperty.prop > -1 ?
orderProperty.prop : lastPropertyIndex;
// Mark current node to remove it later from parent node:
deleted.push(i);
extendedNode.sc1 = checkSC1();
if (extendedNode.sc1.length) {
currentNode = node.get(i);
nextNode = node.get(i + 1);
}
// If there is `;` right after the declaration, save it with the
// declaration and mark it for removing from parent node:
if (currentNode && nextNode && nextNode.is('declarationDelimiter')) {
extendedNode.delim.push(nextNode);
deleted.push(i + 1);
i++;
if (syntax === 'sass') return extendedNode;
// Save spaces and comments which follow right after the declaration
// and mark them for removing from parent node:
extendedNode.sc2 = checkSC1();
}
return extendedNode;
};
/**
* Sorts properties alphabetically.
*
* @param {Object} a First extended node
* @param {Object} b Second extended node
* @returns {Number} `-1` if properties should go in order `a, b`. `1`
* if properties should go in order `b, a`.
*/
var sortLeftovers = function(a, b) {
var prefixes = ['-webkit-', '-moz-', '-ms-', '-o-', ''];
var prefixesRegExp = /^(-webkit-|-moz-|-ms-|-o-)(.*)$/;
// Get property name (i.e. `color`, `-o-animation`):
a = a.node.get(0).get(0).content;
b = b.node.get(0).get(0).content;
// Get prefix and unprefixed part. For example:
// ['-o-animation', '-o-', 'animation']
// ['color', '', 'color']
a = a.match(prefixesRegExp) || [a, '', a];
b = b.match(prefixesRegExp) || [b, '', b];
if (a[2] !== b[2]) {
// If unprefixed parts are different (i.e. `border` and
// `color`), compare them:
return a[2] < b[2] ? -1 : 1;
} else {
// If unprefixed parts are identical (i.e. `border` in
// `-moz-border` and `-o-border`), compare prefixes (they
// should go in the same order they are set in `prefixes` array):
return prefixes.indexOf(a[1]) < prefixes.indexOf(b[1]) ? -1 : 1;
}
};
// TODO: Think it through!
// Sort properties only inside blocks:
if (!node.is('block')) return;
// Check every child node.
// If it is declaration (property-value pair, e.g. `color: tomato`),
// or @-rule (e.g. `@include nani`),
// combine it with spaces, semicolon and comments and move them from
// current node to a separate list for further sorting:
for (i = 0, l = node.length; i < l; i++) {
if (NODES.indexOf(node.get(i).type) === -1) continue;
// Save preceding spaces and comments, if there are any, and mark
// them for removing from parent node:
sc0 = checkSC0();
if (!sc0) continue;
// If spaces/comments are the last nodes, stop and go to sorting:
if (!node.get(i)) {
deleted.splice(deleted.length - sc0.length, deleted.length + 1);
break;
}
// Check if the node needs to be sorted:
// it should be a special @-rule (e.g. `@include`) or a declaration
// with a valid property (e.g. `color` or `$width`).
// If not, proceed with the next node:
propertyName = null;
// Look for includes:
if (node.get(i).is('include')) {
propertyName = '$include';
} else {
for (j = 0, nl = node.get(i).length; j < nl; j++) {
currentNode = node.get(i).get(j);
if (!currentNode) continue;
if (currentNode.is('property')) {
propertyName = currentNode.get(0).is('variable') ?
'$variable' : currentNode.get(0).content;
break;
} else if (currentNode.is('atkeyword') &&
currentNode.get(0).content === 'import') { // Look for imports
propertyName = '$import';
break;
}
}
}
// If current node is not property-value pair or import or include,
// skip it and continue with the next node:
if (!propertyName) {
deleted.splice(deleted.length - sc0.length, deleted.length + 1);
continue;
}
// Make an extended node and move it to a separate list for further
// sorting:
sorted.push(extendNode());
}
// Remove all nodes, that were moved to a `sorted` list, from parent node:
for (i = deleted.length - 1; i > -1; i--) {
node.content.splice(deleted[i], 1);
}
// Sort declarations saved for sorting:
sorted.sort(function(a, b) {
// If a's group index is higher than b's group index, in a sorted
// list a appears after b:
if (a.groupIndex !== b.groupIndex) return a.groupIndex - b.groupIndex;
// If a and b belong to leftovers and `sort-order-fallback` option
// is set to `abc`, sort properties alphabetically:
if (a.groupIndex === lastGroupIndex &&
_this.getValue('sort-order-fallback')) {
return sortLeftovers(a, b);
}
// If a and b have the same group index, and a's property index is
// higher than b's property index, in a sorted list a appears after
// b:
if (a.propertyIndex !== b.propertyIndex) return a.propertyIndex - b.propertyIndex;
// If a and b have the same group index and the same property index,
// in a sorted list they appear in the same order they were in
// original array:
return a.i - b.i;
});
// Build all nodes back together. First go sorted declarations, then
// everything else:
if (sorted.length > 0) {
for (i = sorted.length - 1, l = -1; i > l; i--) {
currentNode = sorted[i];
var prevNode = sorted[i - 1];
sc0 = currentNode.sc0;
var sc1 = currentNode.sc1;
var sc2 = currentNode.sc2;
sc0.reverse().map(removeEmptyLines);
sc1.reverse().map(removeEmptyLines);
sc2.reverse().map(removeEmptyLines);
// Divide declarations from different groups with an empty line:
if (prevNode && currentNode.groupIndex > prevNode.groupIndex) {
if (sc0[0] && sc0[0].is('space') &&
(this.syntax === 'sass' ||
sc0[0].content.match(/\n/g) &&
sc0[0].content.match(/\n/g).length < 2)) {
sc0[0].content = '\n' + sc0[0].content;
}
}
for (j = 0, nl = sc2.length; j < nl; j++) {
node.content.unshift(sc2[j]);
}
if (currentNode.delim.length > 0) {
var delim = this.syntax === 'sass' ? '\n' : ';';
var declDelim = gonzales.createNode({ type: 'declarationDelimiter', content: delim });
node.content.unshift(declDelim);
}
for (j = 0, nl = sc1.length; j < nl; j++) {
node.content.unshift(sc1[j]);
}
node.content.unshift(currentNode.node);
for (j = 0, nl = sc0.length; j < nl; j++) {
node.content.unshift(sc0[j]);
}
}
}
}
};
@@ -0,0 +1,58 @@
var gonzales = require('gonzales-pe');
module.exports = {
name: 'space-after-colon',
runBefore: 'block-indent',
syntax: ['css', 'less', 'sass', 'scss'],
accepts: {
number: true,
string: /^[ \t\n]*$/
},
/**
* Processes tree node.
*
* @param {node} node
*/
process: function(node) {
if (!node.is('declaration')) return;
var value = this.getValue('space-after-colon');
for (var i = node.length; i--;) {
if (!node.get(i).is('propertyDelimiter')) continue;
if (this.getSyntax() === 'sass' && !node.get(i - 1)) break;
// Remove any spaces after colon:
if (node.get(i + 1).is('space')) node.remove(i + 1);
// If the value set in config is not empty, add spaces:
var space = gonzales.createNode({ type: 'space', content: value });
if (value !== '') node.insert(i + 1, space);
break;
}
},
/**
* Detects the value of an option at the tree node.
*
* @param {node} node
*/
detect: function(node) {
if (!node.is('declaration')) return;
for (var i = node.length; i--;) {
if (!node.get(i).is('propertyDelimiter')) continue;
if (node.get(i + 1).is('space')) {
return node.get(i + 1).content;
} else {
return '';
}
}
}
};
@@ -0,0 +1,60 @@
var gonzales = require('gonzales-pe');
module.exports = {
name: 'space-after-combinator',
runBefore: 'block-indent',
syntax: ['css', 'less', 'sass', 'scss'],
accepts: {
number: true,
string: /^[ \t\n]*$/
},
/**
* Processes tree node.
*
* @param {node} node
*/
process: function(node) {
if (!node.is('selector')) return;
var value = this.getValue('space-after-combinator');
node.forEach('simpleSelector', function(simpleSelector) {
simpleSelector.forEach('combinator', function(combinator, i) {
if (simpleSelector.get(i + 1).is('space')) {
simpleSelector.get(i + 1).content = value;
} else {
var space = gonzales.createNode({ type: 'space', content: value });
simpleSelector.insert(i + 1, space);
}
});
});
},
/**
* Detects the value of an option at the tree node.
*
* @param {node} node
*/
detect: function(node) {
if (!node.is('selector')) return;
var variants = [];
node.forEach('simpleSelector', function(simpleSelector) {
simpleSelector.forEach('combinator', function(combinator, i) {
if (simpleSelector.get(i + 1).is('space')) {
variants.push(simpleSelector.get(i + 1).content);
} else {
variants.push('');
}
});
});
return variants;
}
};
@@ -0,0 +1,49 @@
var gonzales = require('gonzales-pe');
module.exports = {
name: 'space-after-opening-brace',
runBefore: 'block-indent',
syntax: ['css', 'less', 'scss'],
accepts: {
number: true,
string: /^[ \t\n]*$/
},
/**
* Processes tree node.
*
* @param {node} node
*/
process: function(node) {
// If found block node stop at the next one for space check
if (!node.is('block') && !node.is('atrulers')) return;
var value = this.getValue('space-after-opening-brace');
if (node.first() &&
node.first().is('space')) {
node.first().content = value;
} else if (value !== '') {
var space = gonzales.createNode({ type: 'space', content: value });
node.insert(0, space);
}
},
/**
* Detects the value of an option at the tree node.
*
* @param {node} node
*/
detect: function(node) {
if (!node.is('block') && !node.is('atrulers')) return;
if (node.first().is('space')) {
return node.first().content;
} else {
return '';
}
}
};
@@ -0,0 +1,62 @@
var gonzales = require('gonzales-pe');
module.exports = {
name: 'space-after-selector-delimiter',
runBefore: 'block-indent',
syntax: ['css', 'less', 'sass', 'scss'],
accepts: {
number: true,
string: /^[ \t\n]*$/
},
/**
* Processes tree node.
*
* @param {node} node
*/
process: function(node) {
if (!node.is('selector')) return;
var value = this.getValue('space-after-selector-delimiter');
node.forEach('delimiter', function(delimiter, i) {
var nextNode = node.get(i + 1);
if (nextNode.is('space')) {
nextNode.content = value;
} else if (nextNode.first().is('space')) {
nextNode.first().content = value;
} else {
var space = gonzales.createNode({ type: 'space', content: value });
nextNode.insert(0, space);
}
});
},
/**
* Detects the value of an option at the tree node.
*
* @param {node} node
*/
detect: function(node) {
if (!node.is('selector')) return;
var variants = [];
node.forEach('delimiter', function(delimiter, i) {
var nextNode = node.get(i + 1);
if (nextNode && nextNode.is('space')) {
variants.push(nextNode.content);
} else if (nextNode.first() && nextNode.first().is('space')) {
variants.push(nextNode.first().content);
} else {
variants.push('');
}
});
return variants;
}
};
@@ -0,0 +1,103 @@
var gonzales = require('gonzales-pe');
module.exports = (function() {
var valueFromSettings;
var blockIndent;
function getLastWhitespaceNode(node) {
var lastNode = node.last();
if (!lastNode || !lastNode.content) return null;
if (lastNode.is('block')) return null;
if (lastNode.is('space')) return lastNode;
return getLastWhitespaceNode(lastNode);
}
function processBlock(x, level) {
level = level || 0;
// XXX: Hack for braces
if (x.is('braces') || x.is('id')) return;
x.forEach(function(node) {
if (!node.is('block') &&
!node.is('atrulers')) return processBlock(node, level);
level++;
var value = valueFromSettings;
if (value.indexOf('\n') > -1) {
// TODO: Check that it works for '' block indent value <tg>
if (blockIndent) {
value += new Array(level).join(blockIndent);
}
}
// If found block node stop at the next one for space check
// For the pre-block node, find its last (the deepest) child
var whitespaceNode = getLastWhitespaceNode(node);
// If it's spaces, modify this node
// If it's something different from spaces, add a space node to the end
if (whitespaceNode) {
whitespaceNode.content = value;
} else if (value !== '') {
var space = gonzales.createNode({ type: 'space', content: value });
node.content.push(space);
}
processBlock(node, level);
});
}
return {
name: 'space-before-closing-brace',
runBefore: 'tab-size',
syntax: ['css', 'less', 'scss'],
accepts: {
number: true,
string: /^[ \t\n]*$/
},
/**
* Processes tree node.
* @param {node} node
*/
process: function(node) {
valueFromSettings = this.getValue('space-before-closing-brace');
blockIndent = this.getValue('block-indent');
if (!node.is('stylesheet')) return;
processBlock(node);
},
/**
* Detects the value of an option at the tree node.
*
* @param {node} node
*/
detect: function(node) {
if (!node.is('block') && !node.is('atrulers')) return;
var variants = [];
// For the block node, find its last (the deepest) child
var whitespaceNode = getLastWhitespaceNode(node);
if (whitespaceNode) {
variants.push(whitespaceNode.content);
} else {
variants.push('');
}
return variants;
}
};
})();
@@ -0,0 +1,60 @@
var gonzales = require('gonzales-pe');
module.exports = {
name: 'space-before-colon',
runBefore: 'block-indent',
syntax: ['css', 'less', 'sass', 'scss'],
accepts: {
number: true,
string: /^[ \t\n]*$/
},
/**
* Processes tree node.
*
* @param {node} node
*/
process: function(node) {
if (!node.is('declaration')) return;
var value = this.getValue('space-before-colon');
var syntax = this.getSyntax();
node.forEach('propertyDelimiter', function(delimiter, i) {
if (syntax === 'sass' && !node.get(i - 1)) return;
// Remove any spaces before colon:
if (node.get(i - 1).is('space')) {
node.remove(--i);
}
// If the value set in config is not empty, add spaces:
var space = gonzales.createNode({ type: 'space', content: value });
if (value !== '') node.insert(i, space);
});
},
/**
* Detects the value of an option at the tree node.
*
* @param {node} node
*/
detect: function(node) {
if (!node.is('declaration')) return;
var result;
node.forEach('propertyDelimiter', function(delimiter, i) {
if (node.get(i - 1).is('space')) {
result = node.get(i - 1).content;
} else {
result = '';
}
});
return result;
}
};
@@ -0,0 +1,68 @@
var gonzales = require('gonzales-pe');
module.exports = {
name: 'space-before-combinator',
runBefore: 'block-indent',
syntax: ['css', 'less', 'sass', 'scss'],
accepts: {
number: true,
string: /^[ \t\n]*$/
},
/**
* Processes tree node.
*
* @param {node} node
*/
process: function(node) {
if (!node.is('selector')) return;
var value = this.getValue('space-before-combinator');
node.forEach(function(simpleSelector) {
var notFirst = false;
simpleSelector.forEach(function(n, i) {
if (!n.is('space') && !n.is('combinator')) notFirst = true;
// If combinator is the first thing in selector,
// do not add extra spaces:
if (!n.is('combinator') || !notFirst) return;
if (simpleSelector.get(i - 1).is('space')) {
simpleSelector.get(i - 1).content = value;
} else {
var space = gonzales.createNode({ type: 'space', content: value });
simpleSelector.insert(i, space);
}
});
});
},
/**
* Detects the value of an option at the tree node.
*
* @param {node} node
*/
detect: function(node) {
if (!node.is('selector')) return;
var variants = [];
node.forEach(function(simpleSelector) {
simpleSelector.forEach('combinator', function(combinator, i) {
if (simpleSelector.get(i - 1).is('space')) {
variants.push(simpleSelector.get(i - 1).content);
} else {
variants.push('');
}
});
});
return variants;
}
};
@@ -0,0 +1,99 @@
var gonzales = require('gonzales-pe');
module.exports = (function() {
/**
* Gets the last (the deepest) whitespace node.
*
* @param {node} node
* @returns {node|undefined} If no whitespace node is found, returns
* `undefined`
*/
function getLastWhitespaceNode(node) {
if (typeof node !== 'object') return;
if (node.is('space')) return node;
return getLastWhitespaceNode(node.last());
}
return {
name: 'space-before-opening-brace',
runBefore: 'block-indent',
syntax: ['css', 'less', 'scss'],
accepts: {
number: true,
string: /^[ \t\n]*$/
},
/**
* Processes tree node.
*
* @param {node} node
*/
process: function(node) {
var value = this.getValue('space-before-opening-brace');
// XXX: Hack for braces
if (node.is('braces') || node.is('id')) return;
node.forEach(function(block, i) {
// If found block node stop at the next one for space check:
if (!block.is('block') && !block.is('atrulers')) return;
// For the pre-block node, find its last (the deepest) child:
// TODO: Exclude nodes with braces (for example, arguments)
var previousNode = node.get(i - 1);
var whitespaceNode = getLastWhitespaceNode(previousNode);
// If it's spaces, modify this node.
// If it's something different from spaces, add a space node to
// the end:
if (whitespaceNode) {
whitespaceNode.content = value;
} else if (value !== '') {
var space = gonzales.createNode({ type: 'space', content: value });
if (previousNode && previousNode.is('atrulerq')) {
previousNode.content.push(space);
} else {
node.insert(i, space);
}
}
});
},
/**
* Detects the value of an option at the tree node.
*
* @param {node} node
*/
detect: function(node) {
var variants = [];
// XXX: Hack for braces
if (node.is('braces') || node.is('id')) return [];
node.forEach(function(block, i) {
// If found block node stop at the next one for space check:
if (!block.is('block') && !block.is('atrulers')) return;
// For the pre-block node, find its last (the deepest) child:
// TODO: Exclude nodes with braces (for example, arguments)
var previousNode = node.get(i - 1);
var whitespaceNode = getLastWhitespaceNode(previousNode);
// If it's spaces, modify this node.
// If it's something different from spaces, add a space node to
// the end:
if (whitespaceNode) {
variants.push(whitespaceNode.content);
} else {
variants.push('');
}
});
return variants;
}
};
})();
@@ -0,0 +1,57 @@
var gonzales = require('gonzales-pe');
module.exports = {
name: 'space-before-selector-delimiter',
runBefore: 'block-indent',
syntax: ['css', 'less', 'sass', 'scss'],
accepts: {
number: true,
string: /^[ \t\n]*$/
},
/**
* Processes tree node.
*
* @param {node} node
*/
process: function(node) {
if (!node.is('selector')) return;
var value = this.getValue('space-before-selector-delimiter');
node.forEach('delimiter', function(delim, i) {
var previousNode = node.get(i - 1);
if (previousNode.last().is('space')) {
previousNode.last().content = value;
} else {
var space = gonzales.createNode({ type: 'space', content: value });
previousNode.content.push(space);
}
});
},
/**
* Detects the value of an option at the tree node.
*
* @param {node} node
*/
detect: function(node) {
if (!node.is('selector')) return;
var variants = [];
node.forEach('delimiter', function(delim, i) {
var previousNode = node.get(i - 1);
if (previousNode.last().is('space')) {
variants.push(previousNode.last().content);
} else {
variants.push('');
}
});
return variants;
}
};
@@ -0,0 +1,97 @@
var gonzales = require('gonzales-pe');
module.exports = (function() {
function getDeclarationEnd(node, i) {
for (;i < node.length; i++) {
if (!node.get(i + 1) || typeof node.get(i + 1) === 'string') {
return 0;
} else if (node.get(i + 1).is('space')) {
if (node.get(i + 1).content.indexOf('\n') > -1) {
if (node.get(i + 2) && node.get(i + 2).is('declaration')) {
return i;
} else {
return 0;
}
} else if (node.get(i + 2) && node.get(i + 2).is('multilineComment')) {
if (node.get(i + 3) && node.get(i + 3).is('declaration')) {
return i + 2;
} else if (node.get(i + 3) && node.get(i + 3).is('space')) {
if (node.get(i + 4) && node.get(i + 4).is('declaration')) {
return i + 2;
} else {
return 0;
}
} else {
return 0;
}
} else if (node.get(i + 2) && node.get(i + 2).is('declaration')) {
return i;
}
} else if (node.get(i + 1).is('declaration')) {
return i;
} else if (node.get(i + 1).is('multilineComment')) {
if (node.get(i + 2) && node.get(i + 2).is('declaration')) {
return i + 1;
} else if (node.get(i + 2) && node.get(i + 2).is('space')) {
if (node.get(i + 3) && node.get(i + 3).is('declaration')) {
return i + 1;
}
} else {
return 0;
}
} else {
return 0;
}
}
}
return {
name: 'space-between-declarations',
runBefore: 'block-indent',
syntax: ['css', 'less', 'scss'],
accepts: {
number: true,
string: /^[ \t\n]*$/
},
/**
* Processes tree node.
*
* @param {node} node
*/
process: function(node) {
var value = this.getValue('space-between-declarations');
// TODO: Limit nodes to blocks, stylesheet, etc.
// XXX: Hack for braces
if (node.is('braces') || node.is('id')) return;
for (var i = 0, l = node.length; i < l; i++) {
if (!node.get(i) || !node.get(i).is('declarationDelimiter')) continue;
// Grom user's point of view "declaration" includes semicolons
// and comments placed on the same line.
// So group those things together:
var declarationEnd = getDeclarationEnd(node, i);
if (!declarationEnd) {
continue;
} else {
i = declarationEnd;
}
var nextNode = node.get(i + 1);
if (nextNode.is('space')) {
nextNode.content = value;
} else {
i++;
l++;
var space = gonzales.createNode({ type: 'space', content: value });
node.insert(i, space);
}
}
}
};
})();
@@ -0,0 +1,58 @@
module.exports = (function() {
/**
* Trim trailing spaces on each line.
* @private
* @param {String} string Spaceful string
* @returns {String}
*/
function trim(string) {
return string.replace(/[ \t]+\n/g, '\n');
}
return {
name: 'strip-spaces',
syntax: ['css', 'less', 'sass', 'scss'],
accepts: { boolean: [true] },
/**
* Processes tree node.
* @param {node} node
*/
process: function(node) {
if (node.is('space')) {
node.content = trim(node.content);
} else if (node.is('stylesheet')) {
var lastChild = node.last();
if (lastChild.is('space')) {
lastChild.content = trim(lastChild.content)
.replace(/[ \t]+$/, '')
.replace(/[\n]+/g, '\n');
}
}
},
detectDefault: true,
/**
* Detects the value of an option at the tree node.
* This option is treated as `true` by default, but any trailing space would invalidate it.
*
* @param {node} node
*/
detect: function(node) {
if (node.is('space') &&
node.content.match(/[ \t]\n/)) {
return false;
} else if (node.is('stylesheet')) {
var lastChild = node.last();
if (lastChild.is('space') &&
lastChild.content !== '\n' &&
lastChild.content.match(/^[ \n\t]+$/)) {
return false;
}
}
}
};
})();
@@ -0,0 +1,19 @@
module.exports = {
name: 'tab-size',
runBefore: 'vendor-prefix-align',
syntax: ['css', 'less', 'sass', 'scss'],
accepts: { number: true },
/**
* Processes tree node.
*
* @param {node} node
*/
process: function(node) {
if (!node.is('space')) return;
node.content = node.content.replace(/\t/, this.getValue('tab-size'));
}
};
@@ -0,0 +1,82 @@
module.exports = {
name: 'unitless-zero',
syntax: ['css', 'less', 'sass', 'scss'],
accepts: { boolean: [true] },
/**
* Processes tree node.
*
* @param {node} node
*/
process: function(node) {
var UNITS = ['cm', 'em', 'ex', 'pt', 'px'];
if (!node.is('value') && !node.is('braces')) return;
node.forEach(function(value) {
if (typeof value === 'string') return;
if (value.is('dimension')) {
var unit = value.first('ident').content;
if (value.first('number').content === '0' &&
UNITS.indexOf(unit) !== -1) {
value.remove(1);
}
} else if (value.is('percentage')) {
// XXX(tonyganch): There is a bug in Gonzales when in Less,
// percentage's content is not wrapped as an array but actually
// type of node's content is object. This bug has already been
// fixed in newer versions of Gonzales so the issue should be
// gone after update of dependencies and csscomb@4.0 release.
// This hack is here as a hotfix for csscomb@3.1 and must be
// removed once csscom@4.0 is released. See #389.
var number;
if (!Array.isArray(value.content) &&
value.content.is('number')) {
number = value.content;
} else {
number = value.first('number').content;
}
if (number === '0') {
value.type = 'number';
value.content = number;
}
}
});
},
/**
* Detects the value of an option at the tree node.
*
* @param {node} node
*/
detect: function(node) {
var result;
// If we see a zero with unit and it is not degree, then we dont have an option
if (node.is('percentage') && node.first('number').content[1] === '0') {
result = false;
} else if (node.is('dimension') &&
node.first('number').content === '0' &&
node.first('ident').content !== 'deg') {
result = false;
}
// If we see a zero and previous node is not percentage or dimension, then we have an option
if (node.is('number') &&
node.content === '0' &&
this._prev !== 'percentage' &&
this._prev !== 'dimension') {
result = true;
}
// Store the previous nodeType
this._prev = node.type;
return result;
}
};
@@ -0,0 +1,436 @@
var gonzales = require('gonzales-pe');
module.exports = (function() {
// Vendor prefixes list:
var PREFIXES = [
'webkit',
'khtml',
'moz',
'ms',
'o'
];
var oneline;
/**
* Makes namespace from property name.
*
* @param {String} propertyName
* @returns {String|undefined}
*/
function makeNamespace(propertyName) {
var info = getPrefixInfo(propertyName);
return info && info.baseName;
}
/**
* Creates object which contains info about vendor prefix used in propertyName.
*
* @param {String} propertyName property name
* @param {String} [namespace=''] namespace name
* @param {Number} [extraSymbols=0] extra symbols count
* @returns {Object|undefined}
*/
function getPrefixInfo(propertyName, namespace, extraSymbols) {
var baseName = propertyName;
var prefixLength = 0;
namespace = namespace || '';
extraSymbols = extraSymbols || 0;
if (!propertyName) return;
PREFIXES.some(function(prefix) {
prefix = '-' + prefix + '-';
if (propertyName.indexOf(prefix) !== 0) return;
baseName = baseName.substr(prefix.length);
prefixLength = prefix.length;
return true;
});
return {
id: namespace + baseName,
baseName: baseName,
prefixLength: prefixLength,
extra: extraSymbols
};
}
/**
* Returns extra indent for item in arguments
*
* @param {Array} nodes nodes to process
* @returns {Number|undefined}
*/
function extraIndent(nodes) {
if (!nodes || !nodes.length) return;
var node;
var crPos;
var tabPos;
var result = 0;
for (var i = nodes.length; i--;) {
node = nodes[i];
if (!node.content) {
crPos = -1;
} else {
crPos = node.content.lastIndexOf('\n');
tabPos = node.content.lastIndexOf('\t');
if (tabPos > crPos) crPos = tabPos;
}
if (crPos !== -1)
oneline = false;
if (node.is('space')) {
result += node.content.length - crPos - 1;
if (crPos !== -1)
break;
}
if (node.is('multilineComment')) {
if (crPos === -1) {
result += node.content.length + 4 /* comment symbols length */ ;
} else {
result += node.content.length - crPos + 1 /* only last comment symbols length - 1(not count \n)*/;
break;
}
}
}
return result;
}
/**
* Wrapper for extra indent function for `property` node.
*
* @param {Array} nodes all nodes
* @param {Number} i position in nodes array
*/
function extraIndentProperty(nodes, i) {
var subset = [];
while (i--) {
if (!nodes.get(i) || nodes.get(i).is('declarationDelimiter'))
break;
subset.unshift(nodes.get(i));
}
return extraIndent(subset);
}
/**
* Wrapper for extra indent function for val-node.
*
* @param {Array} nodes all nodes
* @param {Number} i position in nodes array
*/
function extraIndentVal(nodes, i) {
var subset = [];
var declaration = nodes.get(i);
if (!declaration.is('declaration')) return;
for (var x = declaration.length; x--;) {
if (!declaration.get(x).is('value')) continue;
x--;
while (!declaration.get(x).is('propertyDelimiter')) {
subset.push(declaration.get(x));
x--;
}
break;
}
return extraIndent(subset);
}
/**
* Walks across nodes, and call payload for every node that pass selector check.
*
* @param {Object} args arguments in form of:
* {
* node: {object} current node,
* selector: {function} propertyName selector
* payload: {function} work to do with gathered info
* namespaceSelector: {function} selector for namespace
* getExtraSymbols: {Number} extra symbols count
* }
*/
function walk(args) {
args.node.forEach(function(item, i) {
var name = args.selector(item);
var namespace = args.namespaceSelector && makeNamespace(args.namespaceSelector(item));
var extraSymbols = args.getExtraSymbols(args.node, i);
var info = name && getPrefixInfo(name, namespace, extraSymbols);
if (!info) return;
args.payload(info, i);
});
}
/**
* Returns property name.
* e.g.
* for: 'color: #fff'
* returns string: 'color'
*
* @param {node} node
* @returns {String|undefined}
*/
function getPropertyName(node) {
if (!node.is('declaration')) return;
// TODO: Check that it's not a variable
return node.get(0).get(0).content;
}
/**
* Returns property value name.
* e.g.
* for: '-webkit-transition: -webkit-transform 150ms linear'
* returns string: '-webkit-transform', and
* for: 'background: -webkit-linear-gradient(...)'
* returns string: '-webkit-linear-gradient'
*
* @param {node} node
* @returns {String|undefined}
*/
function getValName(node) {
if (!node.is('declaration')) return;
var value = node.first('value');
if (value.get(0).is('ident')) return value.get(0).content;
if (value.get(0).is('function')) return value.get(0).get(0).content;
}
/**
* Updates dict which contains info about items align.
*
* @param {Object} info,
* @param {Object} dict,
*/
function updateDict(info, dict) {
if (info.prefixLength === 0 && info.extra === 0) return;
var indent = dict[info.id] || { prefixLength: 0, extra: 0 };
dict[info.id] = indent.prefixLength + indent.extra > info.prefixLength + info.extra ?
indent :
{
prefixLength: info.prefixLength,
extra: info.extra,
};
}
/**
* Returns string with correct number of spaces for info.baseName property.
*
* @param {Object} info,
* @param {Object} dict,
* @param {String} whitespaceNode
* @returns {String}
*/
function updateIndent(info, dict, whitespaceNode) {
var item = dict[info.id];
if (!item)
return whitespaceNode;
var crPos = whitespaceNode.lastIndexOf('\n');
var tabPos = whitespaceNode.lastIndexOf('\t');
if (tabPos > crPos) crPos = tabPos;
var firstPart = whitespaceNode.substr(0, crPos + 1 );
var extraIndent = new Array(
(item.prefixLength - info.prefixLength) +
(item.extra - info.extra) +
whitespaceNode.length - firstPart.length +
1).join(' ');
return firstPart.concat(extraIndent);
}
return {
name: 'vendor-prefix-align',
syntax: ['css', 'less', 'sass', 'scss'],
accepts: { boolean: [true] },
/**
* Processes tree node.
*
* @param {node} node
*/
process: function(node) {
if (!node.is('block')) return;
oneline = true;
var dict = {};
// Gathering Info
walk({
node: node,
selector: getPropertyName,
getExtraSymbols: extraIndentProperty,
payload: function(info) {
updateDict(info, dict);
}
});
walk({
node: node,
selector: getValName,
namespaceSelector: getPropertyName,
getExtraSymbols: extraIndentVal,
payload: function(info) {
updateDict(info, dict);
}
});
if (oneline && this.getSyntax() !== 'sass') return;
// Update nodes
walk({
node: node,
selector: getValName,
namespaceSelector: getPropertyName,
getExtraSymbols: extraIndentVal,
payload: function(info, i) {
for (var x = node.get(i).length; x--;) {
if (node.get(i).get(x).is('value')) break;
}
if (!node.get(i).get(x - 1).is('space')) {
var space = gonzales.createNode({ type: 'space', content: '' });
node.get(i).insert(x, space);
++x;
}
node.get(i).get(x - 1).content = updateIndent(info, dict, node.get(i).get(x - 1).content);
}
});
if (this.getSyntax() === 'sass') return;
walk({
node: node,
selector: getPropertyName,
getExtraSymbols: extraIndentProperty,
payload: function(info, i) {
// `node.get(i - 1)` can be either space or comment:
var whitespaceNode = node.get(i - 1);
if (!whitespaceNode) return;
// If it's a comment, insert an empty space node:
if (!whitespaceNode.is('space')) {
whitespaceNode = gonzales.createNode({ type: 'space', content: '' });
node.insert(i - 1, whitespaceNode);
}
whitespaceNode.content = updateIndent(info, dict, whitespaceNode.content);
}
});
},
/**
* Detects the value of an option at the tree node.
*
* @param {node} node
*/
detect: function(node) {
if (!node.is('block')) return;
var result = {
true: 0,
false: 0
};
var maybePrefix = false;
var prevPrefixLength = false;
var prevProp;
var prevSum;
var partialResult = null;
var getResult = function(node, sum, info, i) {
var prop = info.baseName;
// If this is the last item in a row and we have a result, then catch it
if (prop !== prevProp && partialResult !== null) {
if (partialResult) {
result.true++;
} else {
result.false++;
}
partialResult = null;
}
if (prop === prevProp && info.prefixLength !== prevPrefixLength) {
maybePrefix = true;
} else {
maybePrefix = false;
}
if (maybePrefix && partialResult !== false) {
// If there is prefixed prop, check if the prefixes are aligned,
// but only if we hadn't already catched that it is false
if (sum === prevSum) {
partialResult = true;
} else {
partialResult = false;
}
}
if (node.length === i + 3 && partialResult !== null) {
// If we're at the last property and have a result, catch it
if (partialResult) {
result.true++;
} else {
result.false++;
}
}
prevPrefixLength = info.prefixLength;
prevProp = prop;
prevSum = sum;
};
// Gathering Info
walk({
node: node,
selector: getPropertyName,
getExtraSymbols: extraIndentProperty,
payload: function(info, i) {
if (node.get(i - 1) && node.get(i - 1).content) {
var sum = node.get(i - 1).content.
replace(/^[ \t]*\n+/, '').length + info.prefixLength;
getResult(node, sum, info, i);
}
}
});
walk({
node: node,
selector: getValName,
getExtraSymbols: extraIndentVal,
payload: function(info, i) {
for (var x = node.get(i).length; x--;) {
if (node.get(i).get(x).is('value')) break;
}
if (node.get(i).get(x - 1)) {
var sum = node.get(i).get(x - 1).content
.replace(/^[ \t]*\n+/, '').length + info.prefixLength;
getResult(node, sum, info, i);
}
}
});
if (result.true > 0 || result.false > 0) {
if (result.true >= result.false) {
return true;
} else {
return false;
}
}
}
};
})();
+104
View File
@@ -0,0 +1,104 @@
{
"_args": [
[
"csscomb@3.1.8",
"/mnt/data/Sites/anissabensalah.net/user/themes/anissabensalah"
]
],
"_development": true,
"_from": "csscomb@3.1.8",
"_id": "csscomb@3.1.8",
"_inBundle": false,
"_integrity": "sha1-qKc4iE9Am6817JRhr8UuHHW9I6I=",
"_location": "/csscomb",
"_phantomChildren": {},
"_requested": {
"type": "version",
"registry": true,
"raw": "csscomb@3.1.8",
"name": "csscomb",
"escapedName": "csscomb",
"rawSpec": "3.1.8",
"saveSpec": null,
"fetchSpec": "3.1.8"
},
"_requiredBy": [
"/gulp-csscomb"
],
"_resolved": "https://registry.npmjs.org/csscomb/-/csscomb-3.1.8.tgz",
"_spec": "3.1.8",
"_where": "/mnt/data/Sites/anissabensalah.net/user/themes/anissabensalah",
"author": {
"name": "Mikhail Troshev",
"email": "mishanga@yandex-team.ru"
},
"bin": {
"csscomb": "./bin/csscomb"
},
"bugs": {
"url": "https://github.com/csscomb/csscomb.js/issues"
},
"contributors": [
{
"name": "Igor Novak",
"email": "bezengi@gmail.com"
},
{
"name": "Roman Komarov",
"email": "kizmarh@ya.ru"
},
{
"name": "Denis Payase",
"email": "lostsoul@yandex-team.ru"
},
{
"name": "Mikhail Troshev",
"email": "mishanga@yandex-team.ru",
"url": "http://mishanga.pro/"
},
{
"name": "Sergey Puzankov",
"email": "puzankov@yandex-team.ru"
}
],
"dependencies": {
"commander": "2.0.0",
"csscomb-core": "3.0.0-3.1",
"gonzales-pe": "3.0.0-28",
"vow": "0.4.4"
},
"description": "CSS coding style formatter",
"devDependencies": {
"jscs": "1.4.5",
"jshint": "2.3.0",
"jshint-groups": "0.5.3",
"mocha": "1.20.1"
},
"engines": {
"node": ">= 0.10.0"
},
"files": [
"bin",
"config",
"lib"
],
"homepage": "http://csscomb.com/",
"main": "./lib/csscomb.js",
"maintainers": [
{
"name": "Tony Ganch",
"email": "tonyganch+github@gmail.com",
"url": "http://tonyganch.com/"
}
],
"name": "csscomb",
"repository": {
"type": "git",
"url": "git+https://github.com/csscomb/csscomb.js.git"
},
"scripts": {
"test": "jshint-groups && ./node_modules/.bin/jscs . && node test/mocha",
"test-cov": "rm -rf lib-cov && jscoverage lib lib-cov && TEST_COV=true node test/mocha > ./test/test-coverage.html"
},
"version": "3.1.8"
}