Skip to content

Commit a5c2221

Browse files
committed
Merge pull request #128 from kizu/quotes
Added `quotes` option
2 parents ba20374 + 3bd2cf3 commit a5c2221

8 files changed

Lines changed: 215 additions & 2 deletions

File tree

README.md

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -156,6 +156,7 @@ Example configuration:
156156
"element-case": "lower",
157157
"eof-newline": true,
158158
"leading-zero": false,
159+
"quotes": "single",
159160
"remove-empty-rulesets": true,
160161
"rule-indent": " ",
161162
"stick-brace": "\n",
@@ -499,6 +500,20 @@ p { padding: 0.5em }
499500
p { padding: .5em }
500501
```
501502
503+
### quotes
504+
505+
Available values: `{String}` `single` or `double`
506+
507+
Example: `{ "quotes": "single" }`
508+
509+
```css
510+
/* before */
511+
p[href^="https://"]:before { content: "secure" }
512+
513+
/* after */
514+
p[href^='https://']:before { content: 'secure' }
515+
```
516+
502517
### remove-empty-rulesets
503518
504519
Available values: `{Boolean}` `true`

config/csscomb.json

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@
1212
"element-case": "lower",
1313
"eof-newline": true,
1414
"leading-zero": false,
15+
"quotes": "single",
1516
"remove-empty-rulesets": true,
1617
"rule-indent": " ",
1718
"stick-brace": "\n",

lib/csscomb.js

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@ var Comb = function() {
2020
'color-shorthand',
2121
'element-case',
2222
'leading-zero',
23+
'quotes',
2324
'strip-spaces',
2425
'eof-newline',
2526
'stick-brace',

lib/options/quotes.js

Lines changed: 55 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,55 @@
1+
module.exports = {
2+
3+
/**
4+
* Sets handler value.
5+
*
6+
* @param {String|Boolean} value Option value
7+
* @returns {Object|undefined}
8+
*/
9+
setValue: function(value) {
10+
if (value === 'single' || value === 'double' ) {
11+
this._value = value;
12+
}
13+
14+
if (!this._value) return;
15+
return this;
16+
},
17+
18+
/**
19+
* Processes tree node.
20+
* @param {String} nodeType
21+
* @param {node} node
22+
*/
23+
process: function(nodeType, node) {
24+
if (nodeType === 'string') {
25+
if (node[0][0] === '"' && this._value === 'single') {
26+
node[0] = node[0]
27+
.replace(/\\"/g, '"') // unescape all escaped double quotes
28+
.replace(/([^\\])'/g, '$1\\\'') // escape all the single quotes
29+
.replace(/^"|"$/g, '\''); // replace the first and the last quote
30+
31+
} else if (node[0][0] === '\'' && this._value === 'double') {
32+
node[0] = node[0]
33+
.replace(/\\'/g, '\'') // unescape all escaped single quotes
34+
.replace(/([^\\])"/g, '$1\\\"') // escape all the double quotes
35+
.replace(/^'|'$/g, '"'); // replace the first and the last quote
36+
}
37+
}
38+
},
39+
40+
/**
41+
* Detects the value of an option at the tree node.
42+
*
43+
* @param {String} nodeType
44+
* @param {node} node
45+
*/
46+
detect: function(nodeType, node) {
47+
if (nodeType === 'string') {
48+
if (node[0][0] === '"') {
49+
return 'double';
50+
} else if (node[0][0] === '\'') {
51+
return 'single';
52+
}
53+
}
54+
}
55+
};

test/integral.expect.css

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -14,8 +14,10 @@
1414
}
1515

1616
/* :after — фон */
17-
.radio-button_theme_normal .radio-button__radio:after
17+
.radio-button_theme_normal .radio-button__radio[class^='radio']:after
1818
{
19+
content: 'it\'s something different';
20+
1921
background: #fff;
2022
background: -webkit-linear-gradient(top, #fff 0,#eee 100%);
2123
background: -moz-linear-gradient(top, #fff 0, #eee 100%);
@@ -26,6 +28,8 @@
2628
/* _focused_yes */
2729
.radio-button_theme_normal .radio-button__radio_focused_yes:before
2830
{
31+
content: 'hello';
32+
2933
-moz-box-shadow: 0 0 6px 2px rgba(255,204,0,.7), 0 1px 0 rgba(0,0,0,.07);
3034
box-shadow: 0 0 6px 2px rgba(255,204,0,.7), 0 1px 0 rgba(0,0,0,.07);
3135
}

test/integral.js

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -40,6 +40,7 @@ vow.all(['origin', 'expect'].map(function(type) {
4040
'color-shorthand': true,
4141
'element-case': 'lower',
4242
'leading-zero': false,
43+
'quotes': 'single',
4344
'strip-spaces': true,
4445
'eof-newline': true,
4546
'stick-brace': '\n',

test/integral.origin.css

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12,18 +12,20 @@
1212
}
1313

1414
/* :after — фон */
15-
.radio-button_theme_normal .radio-button__radio:after
15+
.radio-button_theme_normal .radio-button__radio[class^="radio"]:after
1616
{
1717
background: #fFf;
1818
background: -webkit-linear-gradient(top, #FffFff 0,#eeeeEe 100%);
1919
background: -moz-linear-gradient(top, #fff 0, #eEe 100%);
2020
background: -o-linear-gradient(top, #fff 0,#eee 100%);
2121
background: linear-gradient(to bottom, #ffffff 0,#eeEeee 100%);
22+
content: "it's something different";
2223
}
2324

2425
/* _focused_yes */
2526
.radio-button_theme_normal .radio-button__radio_focused_yes:before
2627
{
28+
content: "hello";
2729
-moz-box-shadow: 0 0 6px 2px rgba(255,204,0,.7), 0px 1px 0px rgba(0,0,0,.07);
2830
box-shadow: 0 0 6px 2px rgba(255,204,0,.7), 0px 1px 0px rgba(0,0,0,.07);
2931
}

test/quotes.js

Lines changed: 134 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,134 @@
1+
var Comb = require('../lib/csscomb');
2+
var assert = require('assert');
3+
4+
describe('options/quotes', function() {
5+
var comb;
6+
beforeEach(function() {
7+
comb = new Comb();
8+
});
9+
10+
it('Invalid String should not change quotes', function() {
11+
comb.configure({ quotes: 'foobar' });
12+
assert.equal(
13+
comb.processString(
14+
'a { content: "" }' +
15+
'b { content: \'\' }'
16+
),
17+
'a { content: "" }' +
18+
'b { content: \'\' }'
19+
);
20+
});
21+
22+
it('`single` value should set the quotes to single', function() {
23+
comb.configure({ quotes: 'single' });
24+
assert.equal(
25+
comb.processString(
26+
'a { content: "" }' +
27+
'b { content: \'\' }'
28+
),
29+
'a { content: \'\' }' +
30+
'b { content: \'\' }'
31+
);
32+
});
33+
34+
it('`double` value should set the quotes to double', function() {
35+
comb.configure({ quotes: 'double' });
36+
assert.equal(
37+
comb.processString(
38+
'a { content: "" }' +
39+
'b { content: \'\' }'
40+
),
41+
'a { content: "" }' +
42+
'b { content: "" }'
43+
);
44+
});
45+
46+
it('`double` value should set the quotes to double in attrs and urls', function() {
47+
comb.configure({ quotes: 'double' });
48+
assert.equal(
49+
comb.processString(
50+
'a[class^=\'foo\'] { background: url(\'foo.png\') }'
51+
),
52+
'a[class^="foo"] { background: url("foo.png") }'
53+
);
54+
});
55+
56+
it('`double` value should escape the unescaped double quotes on change', function() {
57+
comb.configure({ quotes: 'double' });
58+
assert.equal(
59+
comb.processString(
60+
'a { content: "\\"" }' +
61+
'b { content: \'"\' }'
62+
),
63+
'a { content: "\\"" }' +
64+
'b { content: "\\"" }'
65+
);
66+
});
67+
68+
69+
it('`single` value should unescape the escaped double quotes on change', function() {
70+
comb.configure({ quotes: 'single' });
71+
assert.equal(
72+
comb.processString(
73+
'a { content: "\\"" }'
74+
),
75+
'a { content: \'"\' }'
76+
);
77+
});
78+
79+
// Helper to check the detection
80+
function should_detect(options, a, b) {
81+
assert.equal(
82+
JSON.stringify(comb.detectInString(a, options)),
83+
JSON.stringify(b)
84+
);
85+
}
86+
87+
it('Should not detect quotes when there are none', function() {
88+
should_detect(
89+
['quotes'],
90+
'a { color:red }',
91+
{}
92+
);
93+
});
94+
95+
it('Should detect double quotes', function() {
96+
should_detect(
97+
['quotes'],
98+
'a { content: "foo" }',
99+
{
100+
quotes: 'double'
101+
}
102+
);
103+
});
104+
105+
it('Should detect single quotes', function() {
106+
should_detect(
107+
['quotes'],
108+
'a { content: \'foo\' }',
109+
{
110+
quotes: 'single'
111+
}
112+
);
113+
});
114+
115+
it('Should detect single quotes in attribute', function() {
116+
should_detect(
117+
['quotes'],
118+
'a[class^=\'foo\'] { color: red }',
119+
{
120+
quotes: 'single'
121+
}
122+
);
123+
});
124+
125+
it('Should detect double quotes in url', function() {
126+
should_detect(
127+
['quotes'],
128+
'a { background: url("foo.png") }',
129+
{
130+
quotes: 'double'
131+
}
132+
);
133+
});
134+
});

0 commit comments

Comments
 (0)