Skip to content

Commit 38d43ad

Browse files
authored
Merge pull request #829 from sasstools/release/1.9.0
Release/1.9.0
2 parents 2ca0b3b + 9db9bea commit 38d43ad

22 files changed

+615
-148
lines changed

CHANGELOG.md

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,25 @@
11
# Sass Lint Changelog
22

3+
## v1.9.0
4+
5+
**August 18, 2016**
6+
7+
**Fixes**
8+
* Fixed an issue with teh indentation rule when it encountered at-rules with no block immediately preceeding a map [#779](https://github.com/sasstools/sass-lint/issues/779) [#783](https://github.com/sasstools/sass-lint/issues/783)
9+
* Fixed an issue in `single-lint-per-selector` where inline comments were seen as selectors [#789](https://github.com/sasstools/sass-lint/issues/789)
10+
* Fixed an issue with interpolation in placeholders within the `bem-depth` rule [#782](https://github.com/sasstools/sass-lint/issues/782)
11+
* Removed duplicated code from `no-mergeable-selectors` to helper methods
12+
13+
**Documentation**
14+
* Fixed typos in no-vendor-prefixes rule documentation [#787](https://github.com/sasstools/sass-lint/issues/787)
15+
* Added link to Visual Studio extension [#815](https://github.com/sasstools/sass-lint/pull/815)
16+
17+
**New Rules**
18+
* Added the `no-color-hex` rule to disallow all hexadecimal colour definitions [#754](https://github.com/sasstools/sass-lint/issues/754)
19+
20+
**Updates**
21+
* Gonzales-pe updated to version 3.4.4 which fixes a lot of longstanding issues see the [Changelog](https://github.com/tonyganch/gonzales-pe/blob/dev/CHANGELOG.md)
22+
323
## v1.8.2
424

525
**June 23, 2016**

README.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -194,3 +194,4 @@ Our AST is [Gonzales-PE](https://github.com/tonyganch/gonzales-pe/tree/dev). Eac
194194
* [Sublime Text](https://github.com/skovhus/SublimeLinter-contrib-sass-lint)
195195
* [Brackets](https://github.com/petetnt/brackets-sass-lint)
196196
* [IntelliJ IDEA, RubyMine, WebStorm, PhpStorm, PyCharm](https://github.com/idok/sass-lint-plugin)
197+
* [Visual Studio Code](https://marketplace.visualstudio.com/items?itemName=glen-84.sass-lint)

docs/rules/no-color-hex.md

Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,33 @@
1+
# No Color Hex
2+
3+
Rule `no-color-hex` will disallow the use of hexadecimal colors
4+
5+
## Examples
6+
7+
When enabled the following are disallowed.
8+
9+
```scss
10+
$foo-color: #456;
11+
12+
.bar {
13+
background: linear-gradient(top, #3ff, #ddd);
14+
}
15+
16+
.baz {
17+
color: #fff;
18+
}
19+
```
20+
21+
When enabled the following are allowed:
22+
23+
```scss
24+
$foo-color: red;
25+
26+
.bar {
27+
background: linear-gradient(top, blue, green);
28+
}
29+
30+
.baz {
31+
color: white;
32+
}
33+
```

docs/rules/no-vendor-prefixes.md

Lines changed: 8 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -41,14 +41,14 @@ When enabled, the following are disallowed:
4141

4242
### Additional Identifiers
4343

44-
When `additional-identifiers` contains a custom prefix value of `test` as show below
44+
When `additional-identifiers` contains a custom prefix value of `khtml` as show below
4545

4646
```yaml
47-
no-vendor-prefix:
47+
no-vendor-prefixes:
4848
- 1
4949
-
50-
'additional-identifiers':
51-
- 'khtml'
50+
additional-identifiers:
51+
- khtml
5252
```
5353
5454
The following would now also be disallowed
@@ -64,12 +64,12 @@ The following would now also be disallowed
6464
When `excluded-identifiers` contains currently disallowed prefix values such as `webkit` and `moz` as show below
6565

6666
```yaml
67-
no-vendor-prefix:
67+
no-vendor-prefixes:
6868
- 1
6969
-
70-
'excluded-identifiers':
71-
- 'webkit'
72-
- 'moz'
70+
excluded-identifiers:
71+
- webkit
72+
- moz
7373
```
7474
7575
The following would now be allowed

lib/config/sass-lint.yml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@ rules:
1818

1919
# Disallows
2020
no-attribute-selectors: 0
21+
no-color-hex: 0
2122
no-color-keywords: 1
2223
no-color-literals: 1
2324
no-combinators: 0

lib/rules/bem-depth.js

Lines changed: 14 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
'use strict';
22

33
var helpers = require('../helpers');
4+
var selectorHelpers = require('../selector-helpers');
45

56
/**
67
* Get number of BEM elements in
@@ -32,18 +33,19 @@ module.exports = {
3233
maxDepth = parser.options['max-depth'];
3334

3435
if (node.is('placeholder')) {
35-
name = node.first('ident') && node.first('ident').content;
36-
depth = bemDepth(name);
37-
38-
if (name && depth > maxDepth) {
39-
result = helpers.addUnique(result, {
40-
'ruleId': parser.rule.name,
41-
'line': node.start.line,
42-
'column': node.start.column,
43-
'message': ['Placeholder \'%', name, '\' should have ', maxDepth, ' or fewer BEM elements, but ',
44-
depth, ' were found.'].join(''),
45-
'severity': parser.severity
46-
});
36+
name = selectorHelpers.constructSelector(node);
37+
if (name) {
38+
depth = bemDepth(name);
39+
if (depth > maxDepth) {
40+
result = helpers.addUnique(result, {
41+
'ruleId': parser.rule.name,
42+
'line': node.start.line,
43+
'column': node.start.column,
44+
'message': ['Placeholder \'%', name, '\' should have ', maxDepth, ' or fewer BEM elements, but ',
45+
depth, ' were found.'].join(''),
46+
'severity': parser.severity
47+
});
48+
}
4749
}
4850
}
4951
else {

lib/rules/indentation.js

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -166,7 +166,7 @@ module.exports = {
166166
mixedWarning = false;
167167
}
168168
// if we're in an atrule make we need to possibly handle multiline arguments
169-
if (n.is('atrule')) {
169+
if (n.is('atrule') && n.contains('block')) {
170170
inAtRule = true;
171171
inBlock = false;
172172
}

lib/rules/no-color-hex.js

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
'use strict';
2+
3+
var helpers = require('../helpers');
4+
5+
module.exports = {
6+
'name': 'no-color-hex',
7+
'defaults': {},
8+
'detect': function (ast, parser) {
9+
var result = [];
10+
11+
ast.traverseByType('color', function (value) {
12+
result = helpers.addUnique(result, {
13+
'ruleId': parser.rule.name,
14+
'line': value.start.line,
15+
'column': value.start.column,
16+
'message': 'Hexadecimal colors should not be used',
17+
'severity': parser.severity
18+
});
19+
});
20+
return result;
21+
}
22+
};

lib/rules/no-mergeable-selectors.js

Lines changed: 5 additions & 108 deletions
Original file line numberDiff line numberDiff line change
@@ -1,120 +1,17 @@
11
'use strict';
22

3-
var helpers = require('../helpers');
3+
var helpers = require('../helpers'),
4+
selectorHelpers = require('../selector-helpers');
45

56
var mergeableNodes = ['atrule', 'include', 'ruleset'],
67
validAtRules = ['media'],
7-
simpleIdents = ['ident', 'number', 'operator', 'combinator', 'string', 'parentSelector', 'delimiter', 'typeSelector', 'attributeMatch'],
88
curLevel = 0,
99
curSelector = [],
1010
parentSelector = [],
1111
selectorList = [],
1212
syntax = '';
1313

1414

15-
/**
16-
* Adds grammar around our content blocks to construct selectors with
17-
* more readable formats.
18-
*
19-
* @param {object} val - The current value node
20-
* @param {string} prefix - The grammar to prefix the value with
21-
* @param {string} suffix - The grammar to add after the value
22-
* @returns {string} The correct readable format
23-
*/
24-
var addGrammar = function (val, prefix, suffix) {
25-
return prefix + val.content + suffix;
26-
};
27-
28-
/**
29-
* Adds grammar around our content blocks to construct selectors with
30-
* more readable formats and loops the content as they're within sub blocks.
31-
*
32-
* @param {object} val - The current value node
33-
* @param {string} prefix - The grammar to prefix the value with
34-
* @param {string} suffix - The grammar to add after the value
35-
* @param {function} constructSelector - The callback we wish to use which means constructSelector in this instance
36-
* @returns {string} The correct readable format
37-
*/
38-
var constructSubSelector = function (val, prefix, suffix, constructSelector) {
39-
var content = prefix;
40-
val.forEach(function (subItem) {
41-
content += constructSelector(subItem);
42-
});
43-
44-
return content + suffix;
45-
};
46-
47-
/**
48-
* Constructs a syntax complete selector for our selector matching and warning output
49-
*
50-
* @param {object} val - The current node / part of our selector
51-
* @returns {string} - Content: The current node with correct syntax e.g. class my-class = '.my-class'
52-
*/
53-
var constructSelector = function (val) {
54-
var content = null;
55-
56-
if (val.is('id')) {
57-
content = addGrammar(val, '#', '');
58-
}
59-
60-
else if (val.is('class')) {
61-
content = addGrammar(val, '.', '');
62-
}
63-
64-
else if (simpleIdents.indexOf(val.type) !== -1) {
65-
content = val.content;
66-
}
67-
68-
else if (val.is('attributeSelector')) {
69-
content = constructSubSelector(val, '[', ']', constructSelector);
70-
}
71-
72-
else if (val.is('atkeyword')) {
73-
content = constructSubSelector(val, '@', '', constructSelector);
74-
}
75-
76-
else if (val.is('placeholder')) {
77-
content = constructSubSelector(val, '%', '', constructSelector);
78-
}
79-
80-
else if (val.is('variable')) {
81-
content = constructSubSelector(val, '$', '', constructSelector);
82-
}
83-
84-
else if (val.is('pseudoClass')) {
85-
content = addGrammar(val, ':', '');
86-
}
87-
88-
else if (val.is('pseudoElement')) {
89-
content = addGrammar(val, '::', '');
90-
}
91-
92-
else if (val.is('nth')) {
93-
content = addGrammar(val, '(', ')');
94-
}
95-
96-
else if (val.is('nthSelector')) {
97-
content = constructSubSelector(val, ':', '', constructSelector);
98-
}
99-
100-
else if (val.is('parentheses')) {
101-
content = constructSubSelector(val, '(', ')', constructSelector);
102-
}
103-
104-
else if (val.is('space')) {
105-
content = ' ';
106-
}
107-
108-
else if (val.is('parentSelectorExtension') || val.is('attributeName') || val.is('attributeValue') || val.is('dimension')) {
109-
content = constructSubSelector(val, '', '', constructSelector);
110-
}
111-
112-
else if (val.is('interpolation')) {
113-
content = constructSubSelector(val, '#{', '}', constructSelector);
114-
}
115-
return content;
116-
};
117-
11815
/**
11916
* Traverses a block and calls our callback function for each block encountered
12017
*
@@ -161,11 +58,11 @@ var checkRuleset = function (ruleNode) {
16158
if (!ruleNodeItem.is('block')) {
16259
if (ruleNodeItem.is('selector')) {
16360
ruleNodeItem.forEach(function (selectorContent) {
164-
ruleSet += constructSelector(selectorContent);
61+
ruleSet += selectorHelpers.constructSelector(selectorContent);
16562
});
16663
}
16764
else if (ruleNodeItem.is('delimiter') || ruleNodeItem.is('space')) {
168-
ruleSet += constructSelector(ruleNodeItem);
65+
ruleSet += selectorHelpers.constructSelector(ruleNodeItem);
16966
}
17067
}
17168
});
@@ -184,7 +81,7 @@ var checkAtRule = function (atRule) {
18481
var test = '';
18582
atRule.forEach(function (atRuleItem) {
18683
if (!atRuleItem.is('block')) {
187-
test += constructSelector(atRuleItem);
84+
test += selectorHelpers.constructSelector(atRuleItem);
18885
}
18986
});
19087
updateList(test, true, atRule.start.line, atRule.start.column);

lib/rules/single-line-per-selector.js

Lines changed: 33 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,31 @@
22

33
var helpers = require('../helpers');
44

5+
/**
6+
* Checks a ruleset for selectors or EOL characters. If a selector is found before an EOL
7+
* then it returns the selector node for reporting or returns false
8+
*
9+
* @param {Object} ruleset - The ruleset node
10+
* @param {number} index - The current index of the delimiter
11+
* @returns {Object|boolean} Either the selector node or false
12+
*/
13+
var checkLineForSelector = function (ruleset, index) {
14+
var curIndex = index += 1;
15+
if (ruleset.content[curIndex]) {
16+
for (; curIndex < ruleset.content.length; curIndex++) {
17+
var curType = ruleset.content[curIndex].type;
18+
if (curType === 'space' && helpers.hasEOL(ruleset.content[curIndex])) {
19+
return false;
20+
}
21+
if (curType === 'selector' || curType === 'typeSelector') {
22+
return ruleset.content[curIndex];
23+
}
24+
}
25+
}
26+
27+
return false;
28+
};
29+
530
module.exports = {
631
'name': 'single-line-per-selector',
732
'defaults': {},
@@ -10,22 +35,16 @@ module.exports = {
1035

1136
ast.traverseByType('ruleset', function (ruleset) {
1237
ruleset.forEach('delimiter', function (delimiter, j) {
13-
var next = ruleset.content[j + 1] || false;
38+
var next = checkLineForSelector(ruleset, j);
1439

1540
if (next) {
16-
if (next.is('selector')) {
17-
next = next.content[0];
18-
}
19-
20-
if (!(next.is('space') && helpers.hasEOL(next.content))) {
21-
result = helpers.addUnique(result, {
22-
'ruleId': parser.rule.name,
23-
'line': next.start.line,
24-
'column': next.start.column,
25-
'message': 'Selectors must be placed on new lines',
26-
'severity': parser.severity
27-
});
28-
}
41+
result = helpers.addUnique(result, {
42+
'ruleId': parser.rule.name,
43+
'line': next.start.line,
44+
'column': next.start.column,
45+
'message': 'Selectors must be placed on new lines',
46+
'severity': parser.severity
47+
});
2948
}
3049
});
3150
});

0 commit comments

Comments
 (0)