postcss-pxtransform 4.0.1-alpha.0 → 4.0.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/LICENSE CHANGED
@@ -154,8 +154,15 @@ See `/LICENSE` for details of the license.
154
154
 
155
155
  ==================
156
156
 
157
+ MIT (stencil-vue2-output-target):
158
+ The following files embed [stencil-vue2-output-target](https://github.com/diondree/stencil-vue2-output-target) MIT:
159
+ `/packages/taro-components-library-vue2/src/vue-component-lib/utils.ts`
160
+ See `/LICENSE` for details of the license.
161
+
162
+ ==================
163
+
157
164
  MIT (weui):
158
- The following files embed [weui](https://github.com/Tencent/weui) MIT:
165
+ The following files embed [stencil-vue2-output-target](https://github.com/Tencent/weui) MIT:
159
166
  `/packages/taro-components/src/components/*.scss`
160
167
  See `/LICENSE.txt` for details of the license.
161
168
 
@@ -165,10 +172,3 @@ Apache-2.0 (intersection-observer):
165
172
  The following files embed [intersection-observer](https://github.com/GoogleChromeLabs/intersection-observer) Apache-2.0:
166
173
  `/packages/taro-api/src/polyfill/intersection-observer.ts`
167
174
  See `/LICENSE.txt` for details of the license.
168
-
169
- ==================
170
-
171
- MIT (babel-plugin-jsx-dom-expressions):
172
- The following files embed [babel-plugin-jsx-dom-expressions](https://github.com/ryansolid/dom-expressions/blob/main/packages/babel-plugin-jsx-dom-expressions) MIT:
173
- `/packages/babel-plugin-transform-solid-jsx/src/*`
174
- See `/LICENSE` for details of the license.
@@ -0,0 +1,870 @@
1
+ 'use strict'
2
+ const postcss = require('postcss')
3
+ const px2rem = require('../index')
4
+
5
+ const basicCSS = '.rule { font-size: 15px }'
6
+ const filterPropList = require('../lib/filter-prop-list')
7
+
8
+ describe('px2rem', function () {
9
+ it('1 should work on the readme example', function () {
10
+ const input = 'h1 { margin: 0 0 20px; font-size: 32px; line-height: 1.2; letter-spacing: 1px; }'
11
+ const output = 'h1 { margin: 0 0 0.585rem; font-size: 0.936rem; line-height: 1.2; letter-spacing: 0.02925rem; }'
12
+ const processed = postcss(px2rem({ platform: 'h5', designWidth: 640 }))
13
+ .process(input).css
14
+
15
+ expect(processed).toBe(output)
16
+ })
17
+
18
+ it('2 should replace the px unit with rem', function () {
19
+ const processed = postcss(px2rem({ platform: 'h5', designWidth: 640 }))
20
+ .process(basicCSS).css
21
+ const expected = '.rule { font-size: 0.43875rem }'
22
+
23
+ expect(processed).toBe(expected)
24
+ })
25
+
26
+ it('3 should ignore non px properties', function () {
27
+ const expected = '.rule { font-size: 2em }'
28
+ const processed = postcss(px2rem({ platform: 'h5', designWidth: 640 }))
29
+ .process(expected).css
30
+
31
+ expect(processed).toBe(expected)
32
+ })
33
+
34
+ it('4 should handle < 1 values and values without a leading 0 - legacy',
35
+ function () {
36
+ const rules = '.rule { margin: 0.5rem .5px -0.2px -.2em }'
37
+ const expected = '.rule { margin: 0.5rem 0.01463rem -0.00585rem -.2em }'
38
+ const options = {
39
+ platform: 'h5',
40
+ designWidth: 640,
41
+ propWhiteList: ['margin']
42
+ }
43
+ const processed = postcss(px2rem(options)).process(rules).css
44
+
45
+ expect(processed).toBe(expected)
46
+ })
47
+
48
+ it('5 should handle < 1 values and values without a leading 0', function () {
49
+ const rules = '.rule { margin: 0.5rem .5px -0.2px -.2em }'
50
+ const expected = '.rule { margin: 0.5rem 0.01463rem -0.00585rem -.2em }'
51
+ const options = {
52
+ platform: 'h5',
53
+ designWidth: 640,
54
+ propList: ['margin']
55
+ }
56
+ const processed = postcss(px2rem(options)).process(rules).css
57
+
58
+ expect(processed).toBe(expected)
59
+ })
60
+
61
+ it('6 should not add properties that already exist', function () {
62
+ const expected = '.rule { font-size: 40px; font-size: 1rem; }'
63
+ const processed = postcss(px2rem({ platform: 'h5', designWidth: 750 }))
64
+ .process(expected).css
65
+
66
+ expect(processed).toBe(expected)
67
+ })
68
+
69
+ it('7 属性值为"0"时不处理,为"0px"时仍然单位转换', function () {
70
+ const rule = '.rule { font-size: 0px; font-size: 0; }'
71
+ const expected = '.rule { font-size: 0rpx; font-size: 0; }'
72
+ const processed = postcss(px2rem()).process(rule).css
73
+
74
+ expect(processed).toBe(expected)
75
+ })
76
+
77
+ it('8 should work on custom baseFontSize', function () {
78
+ const processed = postcss(px2rem({ platform: 'h5', baseFontSize: 15 })).process(basicCSS).css
79
+ const expected = '.rule { font-size: 0.5rem }'
80
+
81
+ expect(processed).toBe(expected)
82
+ })
83
+ })
84
+
85
+ describe('value parsing', function () {
86
+ it('1 should not replace values in double quotes or single quotes - legacy',
87
+ function () {
88
+ const options = {
89
+ platform: 'h5',
90
+ designWidth: 640
91
+ // propWhiteList: []
92
+ }
93
+ const rules = '.rule { content: \'16px\'; font-family: "16px"; font-size: 16px; }'
94
+ const expected = '.rule { content: \'16px\'; font-family: "16px"; font-size: 0.468rem; }'
95
+ const processed = postcss(px2rem(options)).process(rules).css
96
+
97
+ expect(processed).toBe(expected)
98
+ })
99
+
100
+ it('2 should not replace values in double quotes or single quotes',
101
+ function () {
102
+ const options = {
103
+ platform: 'h5',
104
+ designWidth: 640,
105
+ propList: ['*']
106
+ }
107
+ const rules = '.rule { content: \'16px\'; font-family: "16px"; font-size: 16px; }'
108
+ const expected = '.rule { content: \'16px\'; font-family: "16px"; font-size: 0.468rem; }'
109
+ const processed = postcss(px2rem(options)).process(rules).css
110
+
111
+ expect(processed).toBe(expected)
112
+ })
113
+
114
+ it('3 should not replace values in `url()` - legacy', function () {
115
+ const options = {
116
+ platform: 'h5',
117
+ designWidth: 640
118
+ // propWhiteList: []
119
+ }
120
+ const rules = '.rule { background: url(16px.jpg); font-size: 16px; }'
121
+ const expected = '.rule { background: url(16px.jpg); font-size: 0.468rem; }'
122
+ const processed = postcss(px2rem(options)).process(rules).css
123
+
124
+ expect(processed).toBe(expected)
125
+ })
126
+
127
+ it('4 should not replace values in `url()`', function () {
128
+ const options = {
129
+ platform: 'h5',
130
+ designWidth: 640,
131
+ propList: ['*']
132
+ }
133
+ const rules = '.rule { background: url(16px.jpg); font-size: 16px; }'
134
+ const expected = '.rule { background: url(16px.jpg); font-size: 0.468rem; }'
135
+ const processed = postcss(px2rem(options)).process(rules).css
136
+
137
+ expect(processed).toBe(expected)
138
+ })
139
+
140
+ it('5 should not replace values with an uppercase P or X', function () {
141
+ const options = {
142
+ platform: 'h5',
143
+ designWidth: 640,
144
+ propList: ['*']
145
+ }
146
+ const rules = '.rule { margin: 12px calc(100% - 14PX); height: calc(100% - 20px); font-size: 12Px; line-height: 16px; }'
147
+ const expected = '.rule { margin: 0.351rem calc(100% - 14PX); height: calc(100% - 0.585rem); font-size: 12Px; line-height: 0.468rem; }'
148
+ const processed = postcss(px2rem(options)).process(rules).css
149
+
150
+ expect(processed).toBe(expected)
151
+ })
152
+ })
153
+
154
+ describe('unitPrecision', function () {
155
+ // Deprecate
156
+ it('1 should replace using a decimal of 2 places - legacy', function () {
157
+ const expected = '.rule { font-size: 0.44rem }'
158
+ const options = {
159
+ platform: 'h5',
160
+ designWidth: 640,
161
+ unit_precision: 2
162
+ }
163
+ const processed = postcss(px2rem(options)).process(basicCSS).css
164
+
165
+ expect(processed).toBe(expected)
166
+ })
167
+
168
+ it('2 should replace using a decimal of 2 places', function () {
169
+ const expected = '.rule { font-size: 0.44rem }'
170
+ const options = {
171
+ platform: 'h5',
172
+ designWidth: 640,
173
+ unitPrecision: 2
174
+ }
175
+ const processed = postcss(px2rem(options)).process(basicCSS).css
176
+
177
+ expect(processed).toBe(expected)
178
+ })
179
+ })
180
+
181
+ describe('propWhiteList', function () {
182
+ // Deprecate
183
+ it('3 should only replace properties in the white list - legacy',
184
+ function () {
185
+ const expected = '.rule { font-size: 15px }'
186
+ const options = {
187
+ platform: 'h5',
188
+ designWidth: 640,
189
+ prop_white_list: ['font']
190
+ }
191
+ const processed = postcss(px2rem(options)).process(basicCSS).css
192
+
193
+ expect(processed).toBe(expected)
194
+ })
195
+
196
+ it('4 should only replace properties in the white list - legacy',
197
+ function () {
198
+ const expected = '.rule { font-size: 15px }'
199
+ const options = {
200
+ platform: 'h5',
201
+ designWidth: 640,
202
+ propWhiteList: ['font']
203
+ }
204
+ const processed = postcss(px2rem(options)).process(basicCSS).css
205
+
206
+ expect(processed).toBe(expected)
207
+ })
208
+
209
+ it('5 should only replace properties in the white list - legacy',
210
+ function () {
211
+ const css = '.rule { margin: 16px; margin-left: 10px }'
212
+ const expected = '.rule { margin: 0.468rem; margin-left: 10px }'
213
+ const options = {
214
+ platform: 'h5',
215
+ designWidth: 640,
216
+ propWhiteList: ['margin']
217
+ }
218
+ const processed = postcss(px2rem(options)).process(css).css
219
+
220
+ expect(processed).toBe(expected)
221
+ })
222
+
223
+ it('6 should only replace properties in the prop list', function () {
224
+ const css = '.rule { font-size: 16px; margin: 16px; margin-left: 5px; padding: 5px; padding-right: 16px }'
225
+ const expected = '.rule { font-size: 0.468rem; margin: 0.468rem; margin-left: 5px; padding: 5px; padding-right: 0.468rem }'
226
+ const options = {
227
+ platform: 'h5',
228
+ designWidth: 640,
229
+ propWhiteList: ['*font*', 'margin*', '!margin-left', '*-right', 'pad']
230
+ }
231
+ const processed = postcss(px2rem(options)).process(css).css
232
+
233
+ expect(processed).toBe(expected)
234
+ })
235
+
236
+ it('7 should only replace properties in the prop list with wildcard',
237
+ function () {
238
+ const css = '.rule { font-size: 16px; margin: 16px; margin-left: 5px; padding: 5px; padding-right: 16px }'
239
+ const expected = '.rule { font-size: 16px; margin: 0.468rem; margin-left: 5px; padding: 5px; padding-right: 16px }'
240
+ const options = {
241
+ platform: 'h5',
242
+ designWidth: 640,
243
+ propWhiteList: ['*', '!margin-left', '!*padding*', '!font*']
244
+ }
245
+ const processed = postcss(px2rem(options)).process(css).css
246
+
247
+ expect(processed).toBe(expected)
248
+ })
249
+
250
+ it('8 should replace all properties when white list is empty', function () {
251
+ const rules = '.rule { margin: 16px; font-size: 15px }'
252
+ const expected = '.rule { margin: 0.468rem; font-size: 0.43875rem }'
253
+ const options = {
254
+ platform: 'h5',
255
+ designWidth: 640
256
+ // propWhiteList: []
257
+ }
258
+ const processed = postcss(px2rem(options)).process(rules).css
259
+
260
+ expect(processed).toBe(expected)
261
+ })
262
+ })
263
+
264
+ describe('selectorBlackList', function () {
265
+ // Deprecate
266
+ it('1 should ignore selectors in the selector black list - legacy',
267
+ function () {
268
+ const rules = '.rule { font-size: 15px } .rule2 { font-size: 15px }'
269
+ const expected = '.rule { font-size: 0.43875rem } .rule2 { font-size: 15px }'
270
+ const options = {
271
+ platform: 'h5',
272
+ designWidth: 640,
273
+ selector_black_list: ['.rule2']
274
+ }
275
+ const processed = postcss(px2rem(options)).process(rules).css
276
+
277
+ expect(processed).toBe(expected)
278
+ })
279
+
280
+ it('2 should ignore selectors in the selector black list', function () {
281
+ const rules = '.rule { font-size: 15px } .rule2 { font-size: 15px }'
282
+ const expected = '.rule { font-size: 0.43875rem } .rule2 { font-size: 15px }'
283
+ const options = {
284
+ platform: 'h5',
285
+ designWidth: 640,
286
+ selectorBlackList: ['.rule2']
287
+ }
288
+ const processed = postcss(px2rem(options)).process(rules).css
289
+
290
+ expect(processed).toBe(expected)
291
+ })
292
+
293
+ it('3 should ignore every selector with `body$`', function () {
294
+ const rules = 'body { font-size: 16px; } .class-body$ { font-size: 16px; } .simple-class { font-size: 16px; }'
295
+ const expected = 'body { font-size: 0.468rem; } .class-body$ { font-size: 16px; } .simple-class { font-size: 0.468rem; }'
296
+ const options = {
297
+ platform: 'h5',
298
+ designWidth: 640,
299
+ selectorBlackList: ['body$']
300
+ }
301
+ const processed = postcss(px2rem(options)).process(rules).css
302
+
303
+ expect(processed).toBe(expected)
304
+ })
305
+
306
+ it('4 should only ignore exactly `body`', function () {
307
+ const rules = 'body { font-size: 16px; } .class-body { font-size: 16px; } .simple-class { font-size: 16px; }'
308
+ const expected = 'body { font-size: 16px; } .class-body { font-size: 0.468rem; } .simple-class { font-size: 0.468rem; }'
309
+ const options = {
310
+ platform: 'h5',
311
+ designWidth: 640,
312
+ selectorBlackList: [/^body$/]
313
+ }
314
+ const processed = postcss(px2rem(options)).process(rules).css
315
+
316
+ expect(processed).toBe(expected)
317
+ })
318
+ })
319
+
320
+ describe('replace', function () {
321
+ it('1 should leave fallback pixel unit with root em value', function () {
322
+ const options = {
323
+ platform: 'h5',
324
+ designWidth: 640,
325
+ replace: false
326
+ }
327
+ const processed = postcss(px2rem(options)).process(basicCSS).css
328
+ const expected = '.rule { font-size: 15px; font-size: 0.43875rem }'
329
+
330
+ expect(processed).toBe(expected)
331
+ })
332
+ })
333
+
334
+ describe('mediaQuery', function () {
335
+ // Deprecate
336
+ it('1 should replace px in media queries', function () {
337
+ const options = {
338
+ platform: 'h5',
339
+ designWidth: 640,
340
+ media_query: true
341
+ }
342
+ const processed = postcss(px2rem(options))
343
+ .process('@media (min-width: 500px) { .rule { font-size: 16px } }').css
344
+ const expected = '@media (min-width: 14.625rem) { .rule { font-size: 0.468rem } }'
345
+
346
+ expect(processed).toBe(expected)
347
+ })
348
+
349
+ it('2 should replace px in media queries', function () {
350
+ const options = {
351
+ platform: 'h5',
352
+ designWidth: 640,
353
+ mediaQuery: true
354
+ }
355
+ const processed = postcss(px2rem(options))
356
+ .process('@media (min-width: 500px) { .rule { font-size: 16px } }').css
357
+ const expected = '@media (min-width: 14.625rem) { .rule { font-size: 0.468rem } }'
358
+
359
+ expect(processed).toBe(expected)
360
+ })
361
+ })
362
+
363
+ describe('minPixelValue', function () {
364
+ it('1 should not replace values below minPixelValue', function () {
365
+ const options = {
366
+ platform: 'h5',
367
+ designWidth: 640,
368
+ // propWhiteList: [],
369
+ minPixelValue: 2
370
+ }
371
+ const rules = '.rule { border: 1px solid #000; font-size: 16px; margin: 1px 10px; }'
372
+ const expected = '.rule { border: 1px solid #000; font-size: 0.468rem; margin: 1px 0.2925rem; }'
373
+ const processed = postcss(px2rem(options)).process(rules).css
374
+
375
+ expect(processed).toBe(expected)
376
+ })
377
+ })
378
+
379
+ describe('filter-prop-list', function () {
380
+ it('1 should find "exact" matches from propList', function () {
381
+ const propList = [
382
+ 'font-size',
383
+ 'margin',
384
+ '!padding',
385
+ '*border*',
386
+ '*',
387
+ '*y',
388
+ '!*font*']
389
+ const expected = 'font-size,margin'
390
+ expect(filterPropList.exact(propList).join()).toBe(expected)
391
+ })
392
+
393
+ it('2 should find "contain" matches from propList and reduce to string',
394
+ function () {
395
+ const propList = [
396
+ 'font-size',
397
+ '*margin*',
398
+ '!padding',
399
+ '*border*',
400
+ '*',
401
+ '*y',
402
+ '!*font*']
403
+ const expected = 'margin,border'
404
+ expect(filterPropList.contain(propList).join()).toBe(expected)
405
+ })
406
+
407
+ it('3 should find "start" matches from propList and reduce to string',
408
+ function () {
409
+ const propList = [
410
+ 'font-size',
411
+ '*margin*',
412
+ '!padding',
413
+ 'border*',
414
+ '*',
415
+ '*y',
416
+ '!*font*']
417
+ const expected = 'border'
418
+ expect(filterPropList.startWith(propList).join()).toBe(expected)
419
+ })
420
+
421
+ it('4 should find "end" matches from propList and reduce to string',
422
+ function () {
423
+ const propList = [
424
+ 'font-size',
425
+ '*margin*',
426
+ '!padding',
427
+ 'border*',
428
+ '*',
429
+ '*y',
430
+ '!*font*']
431
+ const expected = 'y'
432
+ expect(filterPropList.endWith(propList).join()).toBe(expected)
433
+ })
434
+
435
+ it('5 should find "not" matches from propList and reduce to string',
436
+ function () {
437
+ const propList = [
438
+ 'font-size',
439
+ '*margin*',
440
+ '!padding',
441
+ 'border*',
442
+ '*',
443
+ '*y',
444
+ '!*font*']
445
+ const expected = 'padding'
446
+ expect(filterPropList.notExact(propList).join()).toBe(expected)
447
+ })
448
+
449
+ it('6 should find "not contain" matches from propList and reduce to string',
450
+ function () {
451
+ const propList = [
452
+ 'font-size',
453
+ '*margin*',
454
+ '!padding',
455
+ '!border*',
456
+ '*',
457
+ '*y',
458
+ '!*font*']
459
+ const expected = 'font'
460
+ expect(filterPropList.notContain(propList).join()).toBe(expected)
461
+ })
462
+
463
+ it('7 should find "not start" matches from propList and reduce to string',
464
+ function () {
465
+ const propList = [
466
+ 'font-size',
467
+ '*margin*',
468
+ '!padding',
469
+ '!border*',
470
+ '*',
471
+ '*y',
472
+ '!*font*']
473
+ const expected = 'border'
474
+ expect(filterPropList.notStartWith(propList).join()).toBe(expected)
475
+ })
476
+
477
+ it('8 should find "not end" matches from propList and reduce to string',
478
+ function () {
479
+ const propList = [
480
+ 'font-size',
481
+ '*margin*',
482
+ '!padding',
483
+ '!border*',
484
+ '*',
485
+ '!*y',
486
+ '!*font*']
487
+ const expected = 'y'
488
+ expect(filterPropList.notEndWith(propList).join()).toBe(expected)
489
+ })
490
+ })
491
+
492
+ // 补充的测试用例
493
+
494
+ describe('不传任何配置', () => {
495
+ it('不传任何配置', function () {
496
+ const rules = 'h1 {margin: 0 0 20px;font-size: 40px;line-height: 1.2;}'
497
+ const expected = 'h1 {margin: 0 0 20rpx;font-size: 40rpx;line-height: 1.2;}'
498
+ const processed = postcss(px2rem()).process(rules).css
499
+
500
+ expect(processed).toBe(expected)
501
+ })
502
+ })
503
+
504
+ describe('platform 为 weapp', () => {
505
+ it('{platform: \'weapp\', designWidth: 750} ', () => {
506
+ const rules = 'h1 {margin: 0 0 20px;font-size: 40Px;line-height: 1.2;}'
507
+ const expected = 'h1 {margin: 0 0 20rpx;font-size: 40Px;line-height: 1.2;}'
508
+ const options = {
509
+ platform: 'weapp',
510
+ designWidth: 750
511
+ }
512
+ const processed = postcss(px2rem(options)).process(rules).css
513
+ expect(processed).toBe(expected)
514
+ })
515
+
516
+ it('{platform: \'weapp\', designWidth: 640} ', () => {
517
+ const rules = 'h1 {margin: 0 0 20px;font-size: 40px;line-height: 1.2;}'
518
+ const expected = 'h1 {margin: 0 0 23.4rpx;font-size: 46.8rpx;line-height: 1.2;}'
519
+ const options = {
520
+ platform: 'weapp',
521
+ designWidth: 640
522
+ }
523
+ const processed = postcss(px2rem(options)).process(rules).css
524
+ expect(processed).toBe(expected)
525
+ })
526
+
527
+ it('{platform: \'weapp\', designWidth: 375} ', () => {
528
+ const rules = 'h1 {margin: 0 0 20px;font-size: 40px;line-height: 1.2;}'
529
+ const expected = 'h1 {margin: 0 0 40rpx;font-size: 80rpx;line-height: 1.2;}'
530
+ const options = {
531
+ platform: 'weapp',
532
+ designWidth: 375
533
+ }
534
+ const processed = postcss(px2rem(options)).process(rules).css
535
+ expect(processed).toBe(expected)
536
+ })
537
+ })
538
+
539
+ describe('platform 为 weapp, targetUnit 为 rem', () => {
540
+ it('{platform: \'weapp\', designWidth: 750, targetUnit: \'rem\'} ', () => {
541
+ const rules = 'h1 {margin: 0 0 20px;font-size: 40Px;line-height: 1.2;}'
542
+ const expected = 'h1 {margin: 0 0 0.5rem;font-size: 40Px;line-height: 1.2;}'
543
+ const options = {
544
+ platform: 'weapp',
545
+ designWidth: 750,
546
+ targetUnit: 'rem'
547
+ }
548
+ const processed = postcss(px2rem(options)).process(rules).css
549
+ expect(processed).toBe(expected)
550
+ })
551
+
552
+ it('{platform: \'weapp\', designWidth: 640, targetUnit: \'rem\'} ', () => {
553
+ const rules = 'h1 {margin: 0 0 20px;font-size: 40px;line-height: 1.2;}'
554
+ const expected = 'h1 {margin: 0 0 0.585rem;font-size: 1.17rem;line-height: 1.2;}'
555
+ const options = {
556
+ platform: 'weapp',
557
+ designWidth: 640,
558
+ targetUnit: 'rem'
559
+ }
560
+ const processed = postcss(px2rem(options)).process(rules).css
561
+ expect(processed).toBe(expected)
562
+ })
563
+
564
+ it('{platform: \'weapp\', designWidth: 375, targetUnit: \'rem\'} ', () => {
565
+ const rules = 'h1 {margin: 0 0 20px;font-size: 40px;line-height: 1.2;}'
566
+ const expected = 'h1 {margin: 0 0 1rem;font-size: 2rem;line-height: 1.2;}'
567
+ const options = {
568
+ platform: 'weapp',
569
+ designWidth: 375,
570
+ targetUnit: 'rem'
571
+ }
572
+ const processed = postcss(px2rem(options)).process(rules).css
573
+ expect(processed).toBe(expected)
574
+ })
575
+ })
576
+
577
+ describe('platform 为 weapp, targetUnit 为 px', () => {
578
+ it('{platform: \'weapp\', designWidth: 750, targetUnit: \'px\'} ', () => {
579
+ const rules = 'h1 {margin: 0 0 20px;font-size: 40Px;line-height: 1.2;}'
580
+ const expected = 'h1 {margin: 0 0 10px;font-size: 40Px;line-height: 1.2;}'
581
+ const options = {
582
+ platform: 'weapp',
583
+ designWidth: 750,
584
+ targetUnit: 'px'
585
+ }
586
+ const processed = postcss(px2rem(options)).process(rules).css
587
+ expect(processed).toBe(expected)
588
+ })
589
+
590
+ it('{platform: \'weapp\', designWidth: 640, targetUnit: \'px\'} ', () => {
591
+ const rules = 'h1 {margin: 0 0 20px;font-size: 40px;line-height: 1.2;}'
592
+ const expected = 'h1 {margin: 0 0 11.7px;font-size: 23.4px;line-height: 1.2;}'
593
+ const options = {
594
+ platform: 'weapp',
595
+ designWidth: 640,
596
+ targetUnit: 'px'
597
+ }
598
+ const processed = postcss(px2rem(options)).process(rules).css
599
+ expect(processed).toBe(expected)
600
+ })
601
+
602
+ it('{platform: \'weapp\', designWidth: 375, targetUnit: \'px\'} ', () => {
603
+ const rules = 'h1 {margin: 0 0 20px;font-size: 40px;line-height: 1.2;}'
604
+ const expected = 'h1 {margin: 0 0 20px;font-size: 40px;line-height: 1.2;}'
605
+ const options = {
606
+ platform: 'weapp',
607
+ designWidth: 375,
608
+ targetUnit: 'px'
609
+ }
610
+ const processed = postcss(px2rem(options)).process(rules).css
611
+ expect(processed).toBe(expected)
612
+ })
613
+ })
614
+
615
+ describe('platform 为 h5', () => {
616
+ it('{platform: \'h5\', designWidth: 750} ', () => {
617
+ const rules = 'h1 {margin: 0 0 20px;font-size: 40px;line-height: 1.2;}'
618
+ const expected = 'h1 {margin: 0 0 0.5rem;font-size: 1rem;line-height: 1.2;}'
619
+ const options = {
620
+ platform: 'h5',
621
+ designWidth: 750
622
+ }
623
+ const processed = postcss(px2rem(options)).process(rules).css
624
+ expect(processed).toBe(expected)
625
+ })
626
+
627
+ it('{platform: \'h5\', designWidth: 640} ', () => {
628
+ const rules = 'h1 {margin: 0 0 20px;font-size: 40Px;line-height: 1.2;}'
629
+ const expected = 'h1 {margin: 0 0 0.585rem;font-size: 40Px;line-height: 1.2;}'
630
+ const options = {
631
+ platform: 'h5',
632
+ designWidth: 640
633
+ }
634
+ const processed = postcss(px2rem(options)).process(rules).css
635
+ expect(processed).toBe(expected)
636
+ })
637
+
638
+ it('{platform: \'h5\', designWidth: 375} ', () => {
639
+ const rules = 'h1 {margin: 0 0 20px;font-size: 40Px;line-height: 1.2;}'
640
+ const expected = 'h1 {margin: 0 0 1rem;font-size: 40Px;line-height: 1.2;}'
641
+ const options = {
642
+ platform: 'h5',
643
+ designWidth: 375
644
+ }
645
+ const processed = postcss(px2rem(options)).process(rules).css
646
+ expect(processed).toBe(expected)
647
+ })
648
+ })
649
+
650
+ describe('platform 为 h5, targetUnit 为 px', () => {
651
+ it('{platform: \'h5\', designWidth: 750, targetUnit: \'px\'} ', () => {
652
+ const rules = 'h1 {margin: 0 0 20px;font-size: 40px;line-height: 1.2;}'
653
+ const expected = 'h1 {margin: 0 0 10px;font-size: 20px;line-height: 1.2;}'
654
+ const options = {
655
+ platform: 'h5',
656
+ designWidth: 750,
657
+ targetUnit: 'px'
658
+ }
659
+ const processed = postcss(px2rem(options)).process(rules).css
660
+ expect(processed).toBe(expected)
661
+ })
662
+
663
+ it('{platform: \'h5\', designWidth: 640, targetUnit: \'px\'} ', () => {
664
+ const rules = 'h1 {margin: 0 0 20px;font-size: 40Px;line-height: 1.2;}'
665
+ const expected = 'h1 {margin: 0 0 11.7px;font-size: 40Px;line-height: 1.2;}'
666
+ const options = {
667
+ platform: 'h5',
668
+ designWidth: 640,
669
+ targetUnit: 'px'
670
+ }
671
+ const processed = postcss(px2rem(options)).process(rules).css
672
+ expect(processed).toBe(expected)
673
+ })
674
+
675
+ it('{platform: \'h5\', designWidth: 375, targetUnit: \'px\'} ', () => {
676
+ const rules = 'h1 {margin: 0 0 20px;font-size: 40Px;line-height: 1.2;}'
677
+ const expected = 'h1 {margin: 0 0 20px;font-size: 40Px;line-height: 1.2;}'
678
+ const options = {
679
+ platform: 'h5',
680
+ designWidth: 375,
681
+ targetUnit: 'px'
682
+ }
683
+ const processed = postcss(px2rem(options)).process(rules).css
684
+ expect(processed).toBe(expected)
685
+ })
686
+ })
687
+
688
+ describe('platform 为 h5,文件头部带注释的不转换', () => {
689
+ it('{platform: \'h5\', designWidth: 640} ', () => {
690
+ const rules = '/*postcss-pxtransform disable*/ h1 {margin: 0 0 20px;font-size: 40Px;line-height: 1.2;}'
691
+ const options = {
692
+ platform: 'h5',
693
+ designWidth: 640
694
+ }
695
+ const processed = postcss(px2rem(options)).process(rules).css
696
+ expect(processed).toBe(rules)
697
+ })
698
+ })
699
+
700
+ describe('platform 为 h5,指定 h5 平台保留', () => {
701
+ it('{platform: \'h5\', designWidth: 640} ', () => {
702
+ const rules = '/* #ifdef h5 */ h1 {margin: 0 0 20Px;font-size: 40Px;line-height: 1.2;}/* #endif */'
703
+ const options = {
704
+ platform: 'h5',
705
+ designWidth: 640
706
+ }
707
+ const processed = postcss(px2rem(options)).process(rules).css
708
+ expect(processed).toBe(rules)
709
+ })
710
+ })
711
+
712
+ describe('platform 为 h5,指定平台 rn 平台保留', () => {
713
+ it('{platform: \'h5\', designWidth: 640} ', () => {
714
+ const rules = '/* #ifdef rn */ h1 {margin: 0 0 20px;font-size: 40Px;line-height: 1.2;}/* #endif */ .test{}'
715
+ const options = {
716
+ platform: 'h5',
717
+ designWidth: 640
718
+ }
719
+ const processed = postcss(px2rem(options)).process(rules).css
720
+ expect(processed).toBe('/* #ifdef rn *//* #endif */ .test{}')
721
+ })
722
+ })
723
+
724
+ describe('platform 为 rn,指定平台 h5 rn 平台保留', () => {
725
+ it('{platform: \'rn\', designWidth: 640} ', () => {
726
+ const rules = '/* #ifdef h5 rn */ h1 {margin: 0 0 20Px;font-size: 40Px;line-height: 1.2;}/* #endif */ .test{}'
727
+ const options = {
728
+ platform: 'rn',
729
+ designWidth: 640
730
+ }
731
+ const processed = postcss(px2rem(options)).process(rules).css
732
+ expect(processed).toBe(rules)
733
+ })
734
+ })
735
+
736
+ describe('platform 为 h5,指定平台 rn 平台剔除', () => {
737
+ it('{platform: \'h5\', designWidth: 640} ', () => {
738
+ const rules = '/* #ifndef rn */ h1 {margin: 0 0 20Px;font-size: 40Px;line-height: 1.2;}/* #endif */ .test{}'
739
+ const options = {
740
+ platform: 'h5',
741
+ designWidth: 640
742
+ }
743
+ const processed = postcss(px2rem(options)).process(rules).css
744
+ expect(processed).toBe(rules)
745
+ })
746
+ })
747
+
748
+ describe('platform 为 h5,指定平台 h5 平台剔除', () => {
749
+ it('{platform: \'h5\', designWidth: 640} ', () => {
750
+ const rules = '/* #ifndef h5 */ h1 {margin: 0 0 20px;font-size: 40Px;line-height: 1.2;}/* #endif */ .test{}'
751
+ const options = {
752
+ platform: 'h5',
753
+ designWidth: 640
754
+ }
755
+ const processed = postcss(px2rem(options)).process(rules).css
756
+ expect(processed).toBe('/* #ifndef h5 *//* #endif */ .test{}')
757
+ })
758
+ })
759
+
760
+ describe('rpx 单位转换', () => {
761
+ it('{platform: \'weapp\', designWidth: 640} ', () => {
762
+ const rules = 'h1 {margin: 0 0 20rpx;font-size: 40Px;line-height: 1.2;} .test{}'
763
+ const options = {
764
+ platform: 'weapp',
765
+ designWidth: 640
766
+ }
767
+ const processed = postcss(px2rem(options)).process(rules).css
768
+ expect(processed).toBe('h1 {margin: 0 0 20rpx;font-size: 40Px;line-height: 1.2;} .test{}')
769
+ })
770
+
771
+ it('{platform: \'h5\', designWidth: 640} ', () => {
772
+ const rules = 'h1 {margin: 0 0 20rpx;font-size: 40Px;line-height: 1.2;} .test{}'
773
+ const options = {
774
+ platform: 'h5',
775
+ designWidth: 640
776
+ }
777
+ const processed = postcss(px2rem(options)).process(rules).css
778
+ expect(processed).toBe('h1 {margin: 0 0 0.585rem;font-size: 40Px;line-height: 1.2;} .test{}')
779
+ })
780
+
781
+ it('{platform: \'weapp\', designWidth: 375} ', () => {
782
+ const rules = 'h1 {margin: 0 0 20rpx;font-size: 40Px;line-height: 1.2;} .test{}'
783
+ const options = {
784
+ platform: 'weapp',
785
+ designWidth: 375
786
+ }
787
+ const processed = postcss(px2rem(options)).process(rules).css
788
+ expect(processed).toBe('h1 {margin: 0 0 20rpx;font-size: 40Px;line-height: 1.2;} .test{}')
789
+ })
790
+ })
791
+
792
+ describe('vw 单位转换', () => {
793
+ it('{platform: \'h5\', designWidth: 640} ', () => {
794
+ const rules = 'h1 {margin: 0 0 640px;font-size: 40Px;line-height: 1.2;} .test{}'
795
+ const options = {
796
+ platform: 'h5',
797
+ designWidth: 750,
798
+ targetUnit: 'vw'
799
+ }
800
+ const processed = postcss(px2rem(options)).process(rules).css
801
+ expect(processed).toBe('h1 {margin: 0 0 85.33333vw;font-size: 40Px;line-height: 1.2;} .test{}')
802
+ })
803
+
804
+ it('{platform: \'h5\', designWidth: 750} ', () => {
805
+ const rules = 'h1 {margin: 0 0 375px;font-size: 40Px;line-height: 1.2;} .test{}'
806
+ const options = {
807
+ platform: 'h5',
808
+ designWidth: 750,
809
+ targetUnit: 'vw'
810
+ }
811
+ const processed = postcss(px2rem(options)).process(rules).css
812
+ expect(processed).toBe('h1 {margin: 0 0 50vw;font-size: 40Px;line-height: 1.2;} .test{}')
813
+ })
814
+
815
+ it('{platform: \'h5\', designWidth: 640} ', () => {
816
+ const rules = 'h1 {margin: 0 0 320px;font-size: 40Px;line-height: 1.2;} .test{}'
817
+ const options = {
818
+ platform: 'h5',
819
+ designWidth: 640,
820
+ targetUnit: 'vw'
821
+ }
822
+ const processed = postcss(px2rem(options)).process(rules).css
823
+ expect(processed).toBe('h1 {margin: 0 0 50vw;font-size: 40Px;line-height: 1.2;} .test{}')
824
+ })
825
+
826
+ it('{platform: \'h5\', designWidth: 375} ', () => {
827
+ const rules = 'h1 {margin: 0 0 320px;font-size: 40Px;line-height: 1.2;} .test{}'
828
+ const options = {
829
+ platform: 'h5',
830
+ designWidth: 375,
831
+ targetUnit: 'vw'
832
+ }
833
+ const processed = postcss(px2rem(options)).process(rules).css
834
+ expect(processed).toBe('h1 {margin: 0 0 85.33333vw;font-size: 40Px;line-height: 1.2;} .test{}')
835
+ })
836
+ })
837
+
838
+ describe('platform 为 rn,适配', () => {
839
+ it('{platform: \'rn\', designWidth: 750} ', () => {
840
+ const rules = 'view { width: 100px; }'
841
+ const options = {
842
+ platform: 'rn',
843
+ designWidth: 750,
844
+ deviceRatio: {
845
+ 640: 2.34 / 2,
846
+ 750: 1,
847
+ 828: 1.81 / 2
848
+ }
849
+ }
850
+ const processed = postcss(px2rem(options)).process(rules).css
851
+ expect(processed).toBe('view { width: 50px; }')
852
+ })
853
+ })
854
+
855
+ describe('platform 为 harmony,适配', () => {
856
+ it('{platform: \'harmony\', designWidth: 640} ', () => {
857
+ const rules = 'view { width: 100PX; }'
858
+ const options = {
859
+ platform: 'harmony',
860
+ designWidth: 640,
861
+ deviceRatio: {
862
+ 640: 2.34 / 2,
863
+ 750: 1,
864
+ 828: 1.81 / 2
865
+ }
866
+ }
867
+ const processed = postcss(px2rem(options)).process(rules).css
868
+ expect(processed).toBe('view { width: 100vp; }')
869
+ })
870
+ })
package/index.js CHANGED
@@ -1,8 +1,8 @@
1
1
  const pxRegex = require('./lib/pixel-unit-regex')
2
+ const PXRegex = require('./lib/pixel-upper-unit-regex')
2
3
  const filterPropList = require('./lib/filter-prop-list')
3
4
 
4
5
  const defaults = {
5
- methods: ['platform', 'size'],
6
6
  rootValue: 16,
7
7
  unitPrecision: 5,
8
8
  selectorBlackList: [],
@@ -36,41 +36,32 @@ const DEFAULT_WEAPP_OPTIONS = {
36
36
 
37
37
  const processed = Symbol('processed')
38
38
 
39
- let targetUnit
40
39
 
41
- const SPECIAL_PIXEL = ['Px', 'PX', 'pX']
42
- let unConvertTargetUnit
43
- let platform
40
+ let targetUnit
44
41
 
45
42
  module.exports = (options = {}) => {
46
43
  options = Object.assign({}, DEFAULT_WEAPP_OPTIONS, options)
47
- const exclude = options.exclude
44
+
48
45
  const transUnits = ['px']
49
46
  const baseFontSize = options.baseFontSize || (options.minRootSize >= 1 ? options.minRootSize : 20)
50
47
  const designWidth = (input) =>
51
48
  typeof options.designWidth === 'function' ? options.designWidth(input) : options.designWidth
52
49
 
53
- platform = options.platform
54
50
  switch (options.platform) {
55
51
  case 'h5': {
56
52
  targetUnit = options.targetUnit ?? 'rem'
57
53
 
58
- switch (targetUnit) {
59
- case 'vw':
60
- case 'vmin':
61
- options.rootValue = (input) => {
62
- return designWidth(input) / 100
63
- }
64
- break
65
- case 'px':
66
- options.rootValue = (input) => (1 / options.deviceRatio[designWidth(input)]) * 2
67
- break
68
- default:
69
- // rem
70
- options.rootValue = (input) => {
71
- return (baseFontSize / options.deviceRatio[designWidth(input)]) * 2
72
- }
73
- break
54
+ if (targetUnit === 'vw') {
55
+ options.rootValue = (input) => {
56
+ return designWidth(input) / 100
57
+ }
58
+ } else if (targetUnit === 'px') {
59
+ options.rootValue = (input) => (1 / options.deviceRatio[designWidth(input)]) * 2
60
+ } else {
61
+ // rem
62
+ options.rootValue = (input) => {
63
+ return (baseFontSize / options.deviceRatio[designWidth(input)]) * 2
64
+ }
74
65
  }
75
66
 
76
67
  transUnits.push('rpx')
@@ -89,8 +80,6 @@ module.exports = (options = {}) => {
89
80
  case 'harmony': {
90
81
  options.rootValue = (input) => 1 / options.deviceRatio[designWidth(input)]
91
82
  targetUnit = 'px'
92
- unConvertTargetUnit = 'ch' // harmony对于大小写的PX转换成其他单位,用于rust解析
93
- transUnits.push(...SPECIAL_PIXEL)
94
83
  break
95
84
  }
96
85
  default: {
@@ -129,10 +118,6 @@ module.exports = (options = {}) => {
129
118
  /** 是否跳过当前文件不处理 */
130
119
  let skip = false
131
120
 
132
- if (exclude && exclude?.(result.opts.from)) {
133
- return null
134
- }
135
-
136
121
  return {
137
122
  // 注意:钩子在节点变动时会重新执行,Once,OnceExit只执行一次,https://github.com/NervJS/taro/issues/13238
138
123
  Comment (comment) {
@@ -141,8 +126,6 @@ module.exports = (options = {}) => {
141
126
  return
142
127
  }
143
128
 
144
- if (!opts.methods.includes('platform')) return
145
-
146
129
  // delete code between comment in RN
147
130
  // 有死循环的问题
148
131
  if (options.platform === 'rn') {
@@ -200,46 +183,47 @@ module.exports = (options = {}) => {
200
183
  },
201
184
  Declaration (decl) {
202
185
  if (skip) return
203
- if (!opts.methods.includes('size')) return
204
186
 
205
187
  if (decl[processed]) return
206
188
 
207
189
  // 标记当前 node 已处理
208
190
  decl[processed] = true
209
191
 
210
- if (!/px/i.test(decl.value)) return
192
+ if (options.platform === 'harmony') {
193
+ if (decl.value.indexOf('PX') === -1) return
194
+ const value = decl.value.replace(PXRegex, function (m, _$1, $2) {
195
+ return m.replace($2, 'vp')
196
+ })
197
+ decl.value = value
198
+ } else {
199
+ if (decl.value.indexOf('px') === -1) return
211
200
 
212
- if (!satisfyPropList(decl.prop)) return
201
+ if (!satisfyPropList(decl.prop)) return
213
202
 
214
- const isBlacklisted = blacklistedSelector(opts.selectorBlackList, decl.parent.selector)
215
- if (isBlacklisted && platform !== 'harmony') return
216
- let value
217
- if (isBlacklisted) {
218
- // 如果是harmony平台,黑名单的样式单位做特殊处理
219
- if (platform === 'harmony') {
220
- value = decl.value.replace(pxRgx, (m, $1) => $1 ? $1 + unConvertTargetUnit : m)
203
+ if (blacklistedSelector(opts.selectorBlackList, decl.parent.selector)) return
204
+ const value = decl.value.replace(pxRgx, pxReplace)
205
+ // if rem unit already exists, do not add or replace
206
+ if (declarationExists(decl.parent, decl.prop, value)) return
207
+ if (opts.replace) {
208
+ decl.value = value
221
209
  } else {
222
- // 如果是其他平台,黑名单的样式单位不做处理
223
- return
210
+ decl.cloneAfter({ value: value })
224
211
  }
225
- } else {
226
- value = decl.value.replace(pxRgx, pxReplace)
227
- }
228
- // if rem unit already exists, do not add or replace
229
- if (declarationExists(decl.parent, decl.prop, value)) return
230
- if (opts.replace) {
231
- decl.value = value
232
- } else {
233
- decl.cloneAfter({ value: value })
234
212
  }
235
213
  },
236
214
  AtRule: {
237
215
  media: (rule) => {
238
216
  if (skip) return
239
- if (!opts.methods.includes('size')) return
240
-
241
- if (!/px/i.test(rule.params)) return
242
- rule.params = rule.params.replace(pxRgx, pxReplace)
217
+ if (options.platform === 'harmony') {
218
+ if (rule.params.indexOf('PX') === -1) return
219
+ const value = rule.params.replace(PXRegex, function (m, _$1, $2) {
220
+ return m.replace($2, 'vp')
221
+ })
222
+ rule.params = value
223
+ } else {
224
+ if (rule.params.indexOf('px') === -1) return
225
+ rule.params = rule.params.replace(pxRgx, pxReplace)
226
+ }
243
227
  },
244
228
  },
245
229
  }
@@ -271,28 +255,14 @@ function convertLegacyOptions (options) {
271
255
  }
272
256
 
273
257
  function createPxReplace (rootValue, unitPrecision, minPixelValue, onePxTransform) {
274
- const specialPxRgx = pxRegex(SPECIAL_PIXEL)
275
258
  return function (input) {
276
259
  return function (m, $1) {
277
260
  if (!$1) return m
278
-
279
- if (platform === 'harmony' && specialPxRgx.test(m)) {
280
- // harmony对大小写的PX转换成其他单位,用于rust解析
281
- return $1 + unConvertTargetUnit
282
- }
283
-
284
261
  if (!onePxTransform && parseInt($1, 10) === 1) {
285
- if (platform === 'harmony') { return $1 + unConvertTargetUnit }
286
262
  return m
287
263
  }
288
264
  const pixels = parseFloat($1)
289
- if (pixels < minPixelValue) {
290
- if (platform === 'harmony') { return $1 + unConvertTargetUnit }
291
- return m
292
- }
293
-
294
- // 转换工作,如果是harmony的话不转换
295
- if (platform === 'harmony') { return m }
265
+ if (pixels < minPixelValue) return m
296
266
  let val = pixels / rootValue(input, m, $1)
297
267
  if (unitPrecision >= 0 && unitPrecision <= 100) {
298
268
  val = toFixed(val, unitPrecision)
package/package.json CHANGED
@@ -1,9 +1,7 @@
1
1
  {
2
2
  "name": "postcss-pxtransform",
3
- "version": "4.0.1-alpha.0",
3
+ "version": "4.0.1",
4
4
  "description": "PostCSS plugin px 转小程序 rpx及h5 rem 单位",
5
- "author": "O2Team",
6
- "license": "MIT",
7
5
  "main": "index.js",
8
6
  "keywords": [
9
7
  "postcss",
@@ -11,10 +9,8 @@
11
9
  "postcss-plugin",
12
10
  "pxtransform"
13
11
  ],
14
- "files": [
15
- "lib",
16
- "index.js"
17
- ],
12
+ "author": "Pines-Cheng <spider.cs.nuc@gmail.com>",
13
+ "license": "MIT",
18
14
  "repository": {
19
15
  "type": "git",
20
16
  "url": "git+https://github.com/NervJS/taro.git"
@@ -22,16 +18,18 @@
22
18
  "bugs": {
23
19
  "url": "https://github.com/NervJS/taro/issues"
24
20
  },
25
- "homepage": "https://github.com/NervJS/taro/tree/main/packages/postcss-pxtransform#readme",
21
+ "homepage": "https://github.com/NervJS/taro/tree/next/packages/postcss-pxtransform#readme",
26
22
  "jest": {
27
23
  "testEnvironment": "node",
28
24
  "testEnvironmentOptions": {}
29
25
  },
30
- "engines": {
31
- "node": ">= 18"
26
+ "devDependencies": {
27
+ "jest": "^29.3.1",
28
+ "jest-cli": "^29.3.1",
29
+ "postcss": "^8.4.18"
32
30
  },
33
31
  "peerDependencies": {
34
- "postcss": "^8"
32
+ "postcss": "^8.4.18"
35
33
  },
36
34
  "scripts": {
37
35
  "test": "jest"