Skip to content

Commit b27637a

Browse files
change mediaQuery option to replace props inside rules instead of params
1 parent ab547f4 commit b27637a

File tree

7 files changed

+212
-196
lines changed

7 files changed

+212
-196
lines changed

.gitignore

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,4 +3,5 @@ logs
33
*.log
44
npm-debug.log*
55
node_modules
6+
.idea
67
postcss-px-to-em-master

example/index.js

Lines changed: 2 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -4,10 +4,8 @@ var fs = require('fs');
44
var postcss = require('postcss');
55
var pxToViewport = require('..');
66
var css = fs.readFileSync('main.css', 'utf8');
7-
var options = {
8-
replace: false
9-
};
10-
var processedCss = postcss(pxToViewport(options)).process(css).css;
7+
8+
var processedCss = postcss(pxToViewport()).process(css).css;
119

1210
fs.writeFile('main-viewport.css', processedCss, function (err) {
1311
if (err) {

example/main-viewport.css

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -14,8 +14,8 @@
1414
}
1515
@media (min-width: 750px) {
1616
.class3 {
17-
font-size: 5vw;
18-
line-height: 6.875vw;
17+
font-size: 16px;
18+
line-height: 22px;
1919
}
2020
}
2121

index.js

Lines changed: 31 additions & 45 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@
33
var postcss = require('postcss');
44
var objectAssign = require('object-assign');
55
var { createPropListMatcher } = require('./src/prop-list-matcher');
6+
var { getUnitRegexp } = require('./src/pixel-unit-regexp');
67

78
var defaults = {
89
unitToConvert: 'px',
@@ -21,68 +22,53 @@ var defaults = {
2122
module.exports = postcss.plugin('postcss-px-to-viewport', function (options) {
2223

2324
var opts = objectAssign({}, defaults, options);
24-
var pxReplace = createPxReplace(opts.viewportWidth, opts.minPixelValue, opts.unitPrecision, opts.viewportUnit);
25-
26-
// excluding regex trick: http://www.rexegg.com/regex-best-trick.html
27-
// Not anything inside double quotes
28-
// Not anything inside single quotes
29-
// Not anything inside url()
30-
// Any digit followed by px
31-
// !singlequotes|!doublequotes|!url()|pixelunit
32-
var pxRegex = new RegExp('"[^"]+"|\'[^\']+\'|url\\([^\\)]+\\)|(\\d*\\.?\\d+)' + opts.unitToConvert, 'g');
25+
var pxRegex = getUnitRegexp(opts.unitToConvert);
3326
var satisfyPropList = createPropListMatcher(opts.propList);
3427

3528
return function (css) {
36-
37-
css.walkDecls(function (decl, i) {
29+
css.walkRules(function (rule) {
30+
// Add exclude option to ignore some files like 'node_modules'
31+
var file = rule.source.input.file;
3832

39-
// Add exlclude option to ignore some files like 'node_modules'
40-
if (opts.exclude && decl.source.input.file) {
33+
if (opts.exclude && file) {
4134
if (Object.prototype.toString.call(opts.exclude) === '[object RegExp]') {
42-
if (!handleExclude(opts.exclude, decl.source.input.file)) return;
35+
if (!handleExclude(opts.exclude, file)) return;
4336
} else if (Object.prototype.toString.call(opts.exclude) === '[object Array]') {
44-
for (let i = 0; i < opts.exclude.length; ++i) {
45-
if (!handleExclude(opts.exclude[i], decl.source.input.file)) return;
37+
for (let i = 0; i < opts.exclude.length; i++) {
38+
if (!handleExclude(opts.exclude[i], file)) return;
4639
}
4740
} else {
48-
throw new Error('options.exclude should be RegExp or Array!');
41+
throw new Error('options.exclude should be RegExp or Array.');
4942
}
5043
}
44+
45+
if (rule.parent.params && !opts.mediaQuery) return;
46+
if (blacklistedSelector(opts.selectorBlackList, rule.selector)) return;
47+
48+
rule.walkDecls(function(decl, i) {
49+
if (decl.value.indexOf(opts.unitToConvert) === -1) return;
50+
if (!satisfyPropList(decl.prop)) return;
5151

52-
if (
53-
decl.value.indexOf(opts.unitToConvert) === -1 ||
54-
!satisfyPropList(decl.prop) ||
55-
blacklistedSelector(opts.selectorBlackList, decl.parent.selector)
56-
) return;
57-
58-
var unit = getUnit(decl.prop, opts);
59-
var value = decl.value.replace(pxRegex, createPxReplace(opts.viewportWidth, opts.minPixelValue, opts.unitPrecision, unit));
60-
61-
if (declarationExists(decl.parent, decl.prop, value)) return;
52+
var unit = getUnit(decl.prop, opts);
53+
var value = decl.value.replace(pxRegex, createPxReplace(opts.viewportWidth, opts.minPixelValue, opts.unitPrecision, unit));
6254

63-
if (opts.replace) {
64-
decl.value = value;
65-
} else {
66-
decl.parent.insertAfter(i, decl.clone({ value: value }));
67-
}
68-
});
55+
if (declarationExists(decl.parent, decl.prop, value)) return;
6956

70-
if (opts.mediaQuery) {
71-
css.walkAtRules('media', function (rule) {
72-
if (rule.params.indexOf(opts.unitToConvert) === -1) return;
73-
rule.params = rule.params.replace(pxRegex, pxReplace);
57+
if (opts.replace) {
58+
decl.value = value;
59+
} else {
60+
decl.parent.insertAfter(i, decl.clone({ value: value }));
61+
}
7462
});
75-
}
76-
63+
});
7764
};
7865
});
7966

8067
function handleExclude (reg, file) {
8168
if (Object.prototype.toString.call(reg) !== '[object RegExp]') {
82-
throw new Error('options.exclude should be RegExp!');
69+
throw new Error('options.exclude should be RegExp.');
8370
}
84-
if (file.match(reg) !== null) return false;
85-
return true;
71+
return file.match(reg) === null;
8672
}
8773

8874
function getUnit(prop, opts) {
@@ -114,7 +100,7 @@ function blacklistedSelector(blacklist, selector) {
114100
}
115101

116102
function declarationExists(decls, prop, value) {
117-
return decls.some(function (decl) {
118-
return (decl.prop === prop && decl.value === value);
119-
});
103+
return decls.some(function (decl) {
104+
return (decl.prop === prop && decl.value === value);
105+
});
120106
}

spec/px-to-viewport.spec.js

Lines changed: 86 additions & 69 deletions
Original file line numberDiff line numberDiff line change
@@ -46,11 +46,18 @@ describe('px-to-viewport', function() {
4646
});
4747

4848
it('should not add properties that already exist', function () {
49-
var expected = '.rule { font-size: 16px; font-size: 5vw; }';
50-
var processed = postcss(pxToViewport()).process(expected).css;
49+
var expected = '.rule { font-size: 16px; font-size: 5vw; }';
50+
var processed = postcss(pxToViewport()).process(expected).css;
5151

52-
expect(processed).toBe(expected);
52+
expect(processed).toBe(expected);
5353
});
54+
55+
it('should not replace units inside mediaQueries by default', function() {
56+
var expected = '@media (min-width: 500px) { .rule { font-size: 16px } }';
57+
var processed = postcss(pxToViewport()).process('@media (min-width: 500px) { .rule { font-size: 16px } }').css;
58+
59+
expect(processed).toBe(expected);
60+
})
5461
});
5562

5663
describe('value parsing', function() {
@@ -114,7 +121,7 @@ describe('viewportWidth', function() {
114121
var expected = '.rule { font-size: 3.125vw }';
115122
var options = {
116123
viewportWidth: 480
117-
}
124+
};
118125
var processed = postcss(pxToViewport(options)).process(basicCSS).css;
119126

120127
expect(processed).toBe(expected);
@@ -123,13 +130,13 @@ describe('viewportWidth', function() {
123130

124131
describe('unitPrecision', function () {
125132
it('should replace using a decimal of 2 places', function () {
126-
var expected = '.rule { font-size: 4.69vw }';
127-
var options = {
128-
unitPrecision: 2
129-
};
130-
var processed = postcss(pxToViewport(options)).process(basicCSS).css;
133+
var expected = '.rule { font-size: 4.69vw }';
134+
var options = {
135+
unitPrecision: 2
136+
};
137+
var processed = postcss(pxToViewport(options)).process(basicCSS).css;
131138

132-
expect(processed).toBe(expected);
139+
expect(processed).toBe(expected);
133140
});
134141
});
135142

@@ -161,104 +168,114 @@ describe('fontViewportUnit', function() {
161168

162169
describe('selectorBlackList', function () {
163170
it('should ignore selectors in the selector black list', function () {
164-
var rules = '.rule { font-size: 15px } .rule2 { font-size: 15px }';
165-
var expected = '.rule { font-size: 4.6875vw } .rule2 { font-size: 15px }';
166-
var options = {
167-
selectorBlackList: ['.rule2']
168-
};
169-
var processed = postcss(pxToViewport(options)).process(rules).css;
171+
var rules = '.rule { font-size: 15px } .rule2 { font-size: 15px }';
172+
var expected = '.rule { font-size: 4.6875vw } .rule2 { font-size: 15px }';
173+
var options = {
174+
selectorBlackList: ['.rule2']
175+
};
176+
var processed = postcss(pxToViewport(options)).process(rules).css;
170177

171-
expect(processed).toBe(expected);
178+
expect(processed).toBe(expected);
172179
});
173180

174181
it('should ignore every selector with `body$`', function () {
175-
var rules = 'body { font-size: 16px; } .class-body$ { font-size: 16px; } .simple-class { font-size: 16px; }';
176-
var expected = 'body { font-size: 5vw; } .class-body$ { font-size: 16px; } .simple-class { font-size: 5vw; }';
177-
var options = {
178-
selectorBlackList: ['body$']
179-
};
180-
var processed = postcss(pxToViewport(options)).process(rules).css;
182+
var rules = 'body { font-size: 16px; } .class-body$ { font-size: 16px; } .simple-class { font-size: 16px; }';
183+
var expected = 'body { font-size: 5vw; } .class-body$ { font-size: 16px; } .simple-class { font-size: 5vw; }';
184+
var options = {
185+
selectorBlackList: ['body$']
186+
};
187+
var processed = postcss(pxToViewport(options)).process(rules).css;
181188

182-
expect(processed).toBe(expected);
189+
expect(processed).toBe(expected);
183190
});
184191

185192
it('should only ignore exactly `body`', function () {
186-
var rules = 'body { font-size: 16px; } .class-body { font-size: 16px; } .simple-class { font-size: 16px; }';
187-
var expected = 'body { font-size: 16px; } .class-body { font-size: 5vw; } .simple-class { font-size: 5vw; }';
188-
var options = {
189-
selectorBlackList: [/^body$/]
190-
};
191-
var processed = postcss(pxToViewport(options)).process(rules).css;
193+
var rules = 'body { font-size: 16px; } .class-body { font-size: 16px; } .simple-class { font-size: 16px; }';
194+
var expected = 'body { font-size: 16px; } .class-body { font-size: 5vw; } .simple-class { font-size: 5vw; }';
195+
var options = {
196+
selectorBlackList: [/^body$/]
197+
};
198+
var processed = postcss(pxToViewport(options)).process(rules).css;
192199

193-
expect(processed).toBe(expected);
200+
expect(processed).toBe(expected);
194201
});
195202
});
196203

197204
describe('mediaQuery', function () {
198-
it('should replace px in media queries', function () {
199-
var options = {
200-
mediaQuery: true
201-
};
202-
var processed = postcss(pxToViewport(options)).process('@media (min-width: 500px) { .rule { font-size: 16px } }').css;
203-
var expected = '@media (min-width: 156.25vw) { .rule { font-size: 5vw } }';
205+
it('should replace px inside media queries if opts.mediaQuery', function() {
206+
var options = {
207+
mediaQuery: true
208+
};
209+
var processed = postcss(pxToViewport(options)).process('@media (min-width: 500px) { .rule { font-size: 16px } }').css;
210+
var expected = '@media (min-width: 500px) { .rule { font-size: 5vw } }';
204211

205-
expect(processed).toBe(expected);
212+
expect(processed).toBe(expected);
213+
});
214+
215+
it('should not replace px inside media queries if not opts.mediaQuery', function() {
216+
var options = {
217+
mediaQuery: false
218+
};
219+
var processed = postcss(pxToViewport(options)).process('@media (min-width: 500px) { .rule { font-size: 16px } }').css;
220+
var expected = '@media (min-width: 500px) { .rule { font-size: 16px } }';
221+
222+
expect(processed).toBe(expected);
206223
});
207224
});
208225

209226
describe('propList', function () {
210227
it('should only replace properties in the prop list', function () {
211-
var css = '.rule { font-size: 16px; margin: 16px; margin-left: 5px; padding: 5px; padding-right: 16px }';
212-
var expected = '.rule { font-size: 5vw; margin: 5vw; margin-left: 5px; padding: 5px; padding-right: 5vw }';
213-
var options = {
214-
propList: ['*font*', 'margin*', '!margin-left', '*-right', 'pad']
215-
};
216-
var processed = postcss(pxToViewport(options)).process(css).css;
228+
var css = '.rule { font-size: 16px; margin: 16px; margin-left: 5px; padding: 5px; padding-right: 16px }';
229+
var expected = '.rule { font-size: 5vw; margin: 5vw; margin-left: 5px; padding: 5px; padding-right: 5vw }';
230+
var options = {
231+
propList: ['*font*', 'margin*', '!margin-left', '*-right', 'pad']
232+
};
233+
var processed = postcss(pxToViewport(options)).process(css).css;
217234

218-
expect(processed).toBe(expected);
235+
expect(processed).toBe(expected);
219236
});
220237

221238
it('should only replace properties in the prop list with wildcard', function () {
222-
var css = '.rule { font-size: 16px; margin: 16px; margin-left: 5px; padding: 5px; padding-right: 16px }';
223-
var expected = '.rule { font-size: 16px; margin: 5vw; margin-left: 5px; padding: 5px; padding-right: 16px }';
224-
var options = {
225-
propList: ['*', '!margin-left', '!*padding*', '!font*']
226-
};
227-
var processed = postcss(pxToViewport(options)).process(css).css;
239+
var css = '.rule { font-size: 16px; margin: 16px; margin-left: 5px; padding: 5px; padding-right: 16px }';
240+
var expected = '.rule { font-size: 16px; margin: 5vw; margin-left: 5px; padding: 5px; padding-right: 16px }';
241+
var options = {
242+
propList: ['*', '!margin-left', '!*padding*', '!font*']
243+
};
244+
var processed = postcss(pxToViewport(options)).process(css).css;
228245

229-
expect(processed).toBe(expected);
246+
expect(processed).toBe(expected);
230247
});
231248

232249
it('should replace all properties when prop list is not given', function () {
233-
var rules = '.rule { margin: 16px; font-size: 15px }';
234-
var expected = '.rule { margin: 5vw; font-size: 4.6875vw }';
235-
var processed = postcss(pxToViewport()).process(rules).css;
250+
var rules = '.rule { margin: 16px; font-size: 15px }';
251+
var expected = '.rule { margin: 5vw; font-size: 4.6875vw }';
252+
var processed = postcss(pxToViewport()).process(rules).css;
236253

237-
expect(processed).toBe(expected);
254+
expect(processed).toBe(expected);
238255
});
239256
});
240257

241258
describe('minPixelValue', function () {
242259
it('should not replace values below minPixelValue', function () {
243-
var options = {
244-
propWhiteList: [],
245-
minPixelValue: 2
246-
};
247-
var rules = '.rule { border: 1px solid #000; font-size: 16px; margin: 1px 10px; }';
248-
var expected = '.rule { border: 1px solid #000; font-size: 5vw; margin: 1px 3.125vw; }';
249-
var processed = postcss(pxToViewport(options)).process(rules).css;
260+
var options = {
261+
propWhiteList: [],
262+
minPixelValue: 2
263+
};
264+
var rules = '.rule { border: 1px solid #000; font-size: 16px; margin: 1px 10px; }';
265+
var expected = '.rule { border: 1px solid #000; font-size: 5vw; margin: 1px 3.125vw; }';
266+
var processed = postcss(pxToViewport(options)).process(rules).css;
250267

251-
expect(processed).toBe(expected);
268+
expect(processed).toBe(expected);
252269
});
253270
});
254271

255272
describe('exclude', function () {
256273
var rules = '.rule { border: 1px solid #000; font-size: 16px; margin: 1px 10px; }';
257-
var covered = '.rule { border: 1px solid #000; font-size: 5vw; margin: 1px 3.125vw; }'
274+
var covered = '.rule { border: 1px solid #000; font-size: 5vw; margin: 1px 3.125vw; }';
258275
it('when using regex at the time, the style should not be overwritten.', function () {
259276
var options = {
260277
exclude: /node_modules/
261-
}
278+
};
262279
var processed = postcss(pxToViewport(options)).process(rules, {
263280
from: '/node_modules/main.css'
264281
}).css;
@@ -269,7 +286,7 @@ describe('exclude', function () {
269286
it('when using regex at the time, the style should be overwritten.', function () {
270287
var options = {
271288
exclude: /node_modules/
272-
}
289+
};
273290
var processed = postcss(pxToViewport(options)).process(rules, {
274291
from: '/example/main.css'
275292
}).css;
@@ -280,7 +297,7 @@ describe('exclude', function () {
280297
it('when using array at the time, the style should not be overwritten.', function () {
281298
var options = {
282299
exclude: [/node_modules/, /exclude/]
283-
}
300+
};
284301
var processed = postcss(pxToViewport(options)).process(rules, {
285302
from: '/exclude/main.css'
286303
}).css;
@@ -291,7 +308,7 @@ describe('exclude', function () {
291308
it('when using array at the time, the style should be overwritten.', function () {
292309
var options = {
293310
exclude: [/node_modules/, /exclude/]
294-
}
311+
};
295312
var processed = postcss(pxToViewport(options)).process(rules, {
296313
from: '/example/main.css'
297314
}).css;

0 commit comments

Comments
 (0)