Skip to content

Commit

Permalink
Merge pull request #133 from seka/feature/add_stylelint_extends
Browse files Browse the repository at this point in the history
Feature/add stylelint extends
  • Loading branch information
Masaaki Morishita committed May 23, 2016
2 parents c2cf12b + 3c4313d commit ef0a1f5
Show file tree
Hide file tree
Showing 12 changed files with 505 additions and 27 deletions.
2 changes: 1 addition & 1 deletion index.js
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ var formatSassVariables = require('./lib/formatSassVariables')

var stylefmt = postcss.plugin('stylefmt', function (fullPath) {
return function (root) {
return params(fullPath).then(function(params) {
return params(fullPath).then(function (params) {
formatComments(root, params)
formatAtRules(root, params)
formatRules(root, params)
Expand Down
87 changes: 61 additions & 26 deletions lib/params.js
Original file line number Diff line number Diff line change
@@ -1,35 +1,31 @@
var fs = require('fs')
var path = require('path')
if (!process) {
process = require('process') // > v0.4.0
}

var cosmiconfig = require('cosmiconfig');
var cosmiconfig = require('cosmiconfig')
var repeatString = require('repeat-string')
var editorconfig = require('editorconfig')
var objectAssign = require('object-assign')
var resolveFrom = require('resolve-from');

var isEmptyObject = require('./util').isEmptyObject

var defaultIndentWidth = repeatString(' ', 2)

function hasScssInWorkingDir(wd) {
function hasScssInWorkingDir (wd) {
var dirs = fs.readdirSync(wd)
return dirs.some(function (dir) {
return dir.match(/.*\.scss/)
})
}

function getIndentationFromEditorConfig(from, hasScss) {
function getIndentationFromEditorConfig (from, hasScss) {
var config
if (hasScss) {
config = editorconfig.parseSync(path.resolve(process.cwd(), '*.scss'))
} else {
config = editorconfig.parseSync(path.resolve(process.cwd(), '*.css'))
}
if (config == undefined) {
return defaultIndentWidth
}
switch (config.indent_style) {
switch ((config || {}).indent_style) {
case 'tab':
return '\t'
case 'space':
Expand All @@ -39,39 +35,78 @@ function getIndentationFromEditorConfig(from, hasScss) {
}
}

function getIndentationFromStylelintConfig(rules) {
function getIndentationFromStylelintRules (rules) {
var indentaiton = rules['indentation']
switch (typeof indentaiton) {
case 'string':
return '\t'
break
case 'number':
return repeatString(' ', indentaiton)
default:
return defaultIndentWidth
}
}

function parmas(from) {
var wd = path.dirname(from) || process.cwd()
var params = {}
function loadStylelintExtendConfig (params, config, configPath) {
if (isEmptyObject(config.extends)) {
return Promise.resolve(params)
}
return [].concat(config.extends).reduce(function (promise, extention) {
return promise.then(function (mergedParams) {
return augmentParams(mergedParams, extention, configPath)
})
}, Promise.resolve(params))
}

var hasScss = hasScssInWorkingDir(wd)
params.hasScss = hasScss
function augmentParams (originParams, extention, configPath) {
// same as the options in stylelint
var opts = {
configPath: resolveFrom(configPath, extention),
argv: false,
}
return cosmiconfig(extention, opts).then(function (stylelint) {
if (!stylelint) {
return Promise.resolve(originParams)
}
var config = stylelint.config
var dirname = path.dirname(stylelint.filepath)
var rules = config.rules
if (isEmptyObject(rules)) {
return loadStylelintExtendConfig(originParams, config, dirname)
}
var params = {}
params.indentWidth = getIndentationFromStylelintRules(rules)
params.stylelint = rules
var newParams = objectAssign({}, originParams, params)
return loadStylelintExtendConfig(newParams, config, dirname)
})
}

return cosmiconfig('stylelint', {
// same as the options in stylelint
function parmas (from) {
var wd = from || process.cwd()
// same as the options in stylelint
var opts = {
argv: false,
rcExtensions: true,
}).then(function (stylelint) {
if (isEmptyObject(stylelint)) {
rcExtensions: true
}
return cosmiconfig('stylelint', opts).then(function (stylelint) {
var params = {}

var hasScss = hasScssInWorkingDir(wd)
params.hasScss = hasScss

if (!stylelint) {
params.indentWidth = getIndentationFromEditorConfig(wd, hasScss)
params.stylelint = {}
} else {
params.indentWidth = getIndentationFromStylelintConfig(stylelint.config.rules)
params.stylelint = stylelint.config.rules
return Promise.resolve(params)
}

var rules = stylelint.config.rules
if (!isEmptyObject(rules)) {
params.indentWidth = getIndentationFromStylelintRules(rules)
params.stylelint = rules
}
return params
return loadStylelintExtendConfig(params, stylelint.config, wd)
})
}

Expand Down
2 changes: 2 additions & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -28,10 +28,12 @@
"css-color-list": "0.0.1",
"editorconfig": "^0.13.2",
"minimist": "^1.1.2",
"object-assign": "^4.1.0",
"postcss": "^5.0.6",
"postcss-scss": "^0.1.0",
"recursive-readdir": "^1.2.1",
"repeat-string": "^1.5.2",
"resolve-from": "^2.0.0",
"stdin": "0.0.1",
"tmp": "0.0.26"
},
Expand Down
3 changes: 3 additions & 0 deletions test/stylelint/extends/.stylelintrc
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
{
"extends": "./extend-stylelint.js"
}
91 changes: 91 additions & 0 deletions test/stylelint/extends/extend-stylelint.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,91 @@
module.exports = {
"rules": {
"at-rule-empty-line-before": [ "always", {
except: [ "blockless-group", "first-nested" ],
ignore: ["after-comment"],
} ],
"at-rule-name-case": "lower",
"at-rule-name-space-after": "always-single-line",
"at-rule-semicolon-newline-after": "always",
"block-closing-brace-newline-after": "always",
"block-closing-brace-newline-before": "always-multi-line",
"block-closing-brace-space-before": "always-single-line",
"block-no-empty": true,
"block-opening-brace-newline-after": "always-multi-line",
"block-opening-brace-space-after": "always-single-line",
"block-opening-brace-space-before": "always",
"color-hex-case": "lower",
"color-hex-length": "short",
"color-no-invalid-hex": true,
"comment-empty-line-before": [ "always", {
except: ["first-nested"],
ignore: ["stylelint-commands"],
} ],
"comment-whitespace-inside": "always",
"declaration-bang-space-after": "never",
"declaration-bang-space-before": "always",
"declaration-block-no-ignored-properties": true,
"declaration-block-no-shorthand-property-overrides": true,
"declaration-block-semicolon-newline-after": "always-multi-line",
"declaration-block-semicolon-space-after": "always-single-line",
"declaration-block-semicolon-space-before": "never",
"declaration-block-single-line-max-declarations": 1,
"declaration-block-trailing-semicolon": "always",
"declaration-colon-newline-after": "always-multi-line",
"declaration-colon-space-after": "always-single-line",
"declaration-colon-space-before": "never",
"function-calc-no-unspaced-operator": true,
"function-comma-newline-after": "always-multi-line",
"function-comma-space-after": "always-single-line",
"function-comma-space-before": "never",
"function-linear-gradient-no-nonstandard-direction": true,
"function-max-empty-lines": 0,
"function-name-case": "lower",
"function-parentheses-newline-inside": "always-multi-line",
"function-parentheses-space-inside": "never-single-line",
"function-whitespace-after": "always",
"indentation": 2,
"max-empty-lines": 1,
"media-feature-colon-space-after": "always",
"media-feature-colon-space-before": "never",
"media-feature-no-missing-punctuation": true,
"media-feature-range-operator-space-after": "always",
"media-feature-range-operator-space-before": "always",
"media-query-list-comma-newline-after": "always-multi-line",
"media-query-list-comma-space-after": "always-single-line",
"media-query-list-comma-space-before": "never",
"media-query-parentheses-space-inside": "never",
"no-eol-whitespace": true,
"no-extra-semicolons": true,
"no-invalid-double-slash-comments": true,
"no-missing-eof-newline": true,
"number-leading-zero": "always",
"number-no-trailing-zeros": true,
"number-zero-length-no-unit": true,
"property-case": "lower",
"rule-non-nested-empty-line-before": [ "always-multi-line", {
ignore: ["after-comment"],
} ],
"selector-attribute-brackets-space-inside": "never",
"selector-attribute-operator-space-after": "never",
"selector-attribute-operator-space-before": "never",
"selector-combinator-space-after": "always",
"selector-combinator-space-before": "always",
"selector-list-comma-newline-after": "always",
"selector-list-comma-space-before": "never",
"selector-max-empty-lines": 0,
"selector-pseudo-class-case": "lower",
"selector-pseudo-class-parentheses-space-inside": "never",
"selector-pseudo-element-case": "lower",
"selector-pseudo-element-colon-notation": "double",
"selector-pseudo-element-no-unknown": true,
"selector-type-case": "lower",
"shorthand-property-no-redundant-values": true,
"string-no-newline": true,
"unit-case": "lower",
"unit-no-unknown": true,
"value-list-comma-newline-after": "always-multi-line",
"value-list-comma-space-after": "always-single-line",
"value-list-comma-space-before": "never",
},
}
60 changes: 60 additions & 0 deletions test/stylelint/extends/extends.css
Original file line number Diff line number Diff line change
@@ -0,0 +1,60 @@
@import url(x.css);
@import url(y.css);
/**
* Multi-line comment
*/
.selector-1,
.selector-2,
.selector-3[type="text"] {
background: linear-gradient(#fff, rgba(0, 0, 0, 0.8));
box-sizing: border-box;
display: block;
color: #333;
}
.selector-a,
.selector-b:not(:first-child) {
padding: 10px !important;
top: calc(calc(1em * 2) / 3);
}
.selector-x { width: 10%; }
.selector-y { width: 20%; }
.selector-z { width: 30%; }
/* Single-line comment */
@media (min-width >= 60em) {
.selector {
/* Flush to parent comment */
transform: translate(1, 1) scale(3);
}
}
@media (min-orientation: portrait), projection and (color) {
.selector-i + .selector-ii {
background: color(rgb(0, 0, 0) lightness(50%));
font-family: helvetica, "arial black", sans-serif;
}
}
/* Flush single line comment */
@media
screen and (min-resolution: 192dpi),
screen and (min-resolution: 2dppx) {
.selector {
background-image:
repeating-linear-gradient(
-45deg,
transparent,
#fff 25px,
rgba(255, 255, 255, 1) 50px
);
margin: 10px;
margin-bottom: 5px;
box-shadow:
0 1px 1px #000,
0 1px 0 #fff,
2px 2px 1px 1px #ccc inset;
height: 10rem;
}
/* Flush nested single line comment */
.selector::after {
content: '→';
background-image: url(x.svg);
}
}
65 changes: 65 additions & 0 deletions test/stylelint/extends/extends.out.css
Original file line number Diff line number Diff line change
@@ -0,0 +1,65 @@
@import url(x.css);
@import url(y.css);

/**
* Multi-line comment
*/
.selector-1,
.selector-2,
.selector-3[type="text"] {
background: linear-gradient(#fff, rgba(0, 0, 0, 0.8));
box-sizing: border-box;
display: block;
color: #333;
}

.selector-a,
.selector-b:not(:first-child) {
padding: 10px !important;
top: calc(calc(1em * 2) / 3);
}

.selector-x {
width: 10%;
}

.selector-y {
width: 20%;
}

.selector-z {
width: 30%;
}

/* Single-line comment */
@media (min-width >= 60em) {
.selector {

/* Flush to parent comment */
transform: translate(1, 1) scale(3);
}
}

@media (min-orientation: portrait), projection and (color) {
.selector-i + .selector-ii {
background: color(rgb(0, 0, 0) lightness(50%));
font-family: helvetica, "arial black", sans-serif;
}
}

/* Flush single line comment */
@media screen and (min-resolution: 192dpi), screen and (min-resolution: 2dppx) {
.selector {
background-image: repeating-linear-gradient(-45deg, transparent, #fff 25px, rgba(255, 255, 255, 1) 50px);
margin: 10px;
margin-bottom: 5px;
box-shadow: 0 1px 1px #000, 0 1px 0 #fff, 2px 2px 1px 1px #ccc inset;
height: 10rem;
}

/* Flush nested single line comment */
.selector::after {
content: '→';
background-image: url(x.svg);
}
}
3 changes: 3 additions & 0 deletions test/stylelint/extends2/.stylelintrc
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
{
"extends": "./extend-stylelint.js"
}
3 changes: 3 additions & 0 deletions test/stylelint/extends2/extend-stylelint.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
{
"extends": "./extend-stylelint2.js"
}
Loading

0 comments on commit ef0a1f5

Please sign in to comment.