pxtorem-css 1.0.6 → 2.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 +21 -0
- package/Readme.md +314 -92
- package/dist/cli.js +40 -0
- package/dist/index.d.mts +157 -0
- package/dist/index.d.ts +159 -0
- package/dist/index.js +5 -0
- package/dist/index.mjs +4 -0
- package/package.json +72 -31
- package/app.js +0 -156
- package/bin/pxtorem +0 -199
package/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2024 Rashed Iqbal
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
package/Readme.md
CHANGED
|
@@ -1,92 +1,314 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
<
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
pxtorem-css
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
```bash
|
|
31
|
-
npm
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
1
|
+
|
|
2
|
+
<h1 align="center">pxtorem-css</h1>
|
|
3
|
+
|
|
4
|
+
<p align="center">
|
|
5
|
+
<strong>A modern PostCSS plugin & CLI to convert px → rem, em, vw, vh and more</strong>
|
|
6
|
+
</p>
|
|
7
|
+
<p align="center">
|
|
8
|
+
<img src="https://img.shields.io/npm/v/pxtorem-css?style=flat-square&color=blue" alt="npm version" />
|
|
9
|
+
<img src="https://img.shields.io/npm/dm/pxtorem-css?style=flat-square&color=green" alt="downloads" />
|
|
10
|
+
<img src="https://img.shields.io/npm/l/pxtorem-css?style=flat-square" alt="license" />
|
|
11
|
+
<img src="https://img.shields.io/badge/TypeScript-Ready-blue?style=flat-square&logo=typescript" alt="typescript" />
|
|
12
|
+
</p>
|
|
13
|
+
|
|
14
|
+
---
|
|
15
|
+
|
|
16
|
+
## ✨ Features
|
|
17
|
+
|
|
18
|
+
- 🎯 **Multiple Units** — Convert to `rem`, `em`, `vw`, `vh`, `vmin`, `vmax`, `%`
|
|
19
|
+
- ⚡ **Fast & Lightweight** — Zero dependencies (except postcss)
|
|
20
|
+
- 🔧 **Highly Configurable** — Per-property settings, custom transforms
|
|
21
|
+
- 💬 **Comment Control** — Disable conversion with inline comments
|
|
22
|
+
- 📊 **Conversion Reports** — Track what was converted
|
|
23
|
+
- 🖥️ **CLI Included** — Convert files from command line
|
|
24
|
+
- � **TypeScript** — Full type definitions included
|
|
25
|
+
|
|
26
|
+
---
|
|
27
|
+
|
|
28
|
+
## 📦 Installation
|
|
29
|
+
|
|
30
|
+
```bash
|
|
31
|
+
# npm
|
|
32
|
+
npm install pxtorem-css postcss --save-dev
|
|
33
|
+
|
|
34
|
+
# yarn
|
|
35
|
+
yarn add pxtorem-css postcss -D
|
|
36
|
+
|
|
37
|
+
# pnpm
|
|
38
|
+
pnpm add pxtorem-css postcss -D
|
|
39
|
+
```
|
|
40
|
+
|
|
41
|
+
---
|
|
42
|
+
|
|
43
|
+
## 🚀 Quick Start
|
|
44
|
+
|
|
45
|
+
### PostCSS Config
|
|
46
|
+
|
|
47
|
+
```js
|
|
48
|
+
// postcss.config.js
|
|
49
|
+
module.exports = {
|
|
50
|
+
plugins: [
|
|
51
|
+
require('pxtorem-css')({
|
|
52
|
+
baseSize: 16,
|
|
53
|
+
properties: ['*'],
|
|
54
|
+
}),
|
|
55
|
+
],
|
|
56
|
+
};
|
|
57
|
+
```
|
|
58
|
+
|
|
59
|
+
### CLI
|
|
60
|
+
|
|
61
|
+
```bash
|
|
62
|
+
# Convert a file
|
|
63
|
+
npx pxtorem style.css
|
|
64
|
+
|
|
65
|
+
# With options
|
|
66
|
+
npx pxtorem style.css -b 16 -u rem --min-value 2
|
|
67
|
+
```
|
|
68
|
+
|
|
69
|
+
---
|
|
70
|
+
|
|
71
|
+
## 📖 Usage Examples
|
|
72
|
+
|
|
73
|
+
<details>
|
|
74
|
+
<summary><strong>Vite</strong></summary>
|
|
75
|
+
|
|
76
|
+
```js
|
|
77
|
+
// vite.config.js
|
|
78
|
+
import { defineConfig } from 'vite';
|
|
79
|
+
import pxtorem from 'pxtorem-css';
|
|
80
|
+
|
|
81
|
+
export default defineConfig({
|
|
82
|
+
css: {
|
|
83
|
+
postcss: {
|
|
84
|
+
plugins: [
|
|
85
|
+
pxtorem({
|
|
86
|
+
baseSize: 16,
|
|
87
|
+
properties: ['*'],
|
|
88
|
+
}),
|
|
89
|
+
],
|
|
90
|
+
},
|
|
91
|
+
},
|
|
92
|
+
});
|
|
93
|
+
```
|
|
94
|
+
|
|
95
|
+
</details>
|
|
96
|
+
|
|
97
|
+
<details>
|
|
98
|
+
<summary><strong>Next.js</strong></summary>
|
|
99
|
+
|
|
100
|
+
```js
|
|
101
|
+
// postcss.config.js
|
|
102
|
+
module.exports = {
|
|
103
|
+
plugins: {
|
|
104
|
+
'pxtorem-css': {
|
|
105
|
+
baseSize: 16,
|
|
106
|
+
properties: ['*'],
|
|
107
|
+
},
|
|
108
|
+
},
|
|
109
|
+
};
|
|
110
|
+
```
|
|
111
|
+
|
|
112
|
+
</details>
|
|
113
|
+
|
|
114
|
+
<details>
|
|
115
|
+
<summary><strong>Webpack</strong></summary>
|
|
116
|
+
|
|
117
|
+
```js
|
|
118
|
+
// postcss.config.js
|
|
119
|
+
module.exports = {
|
|
120
|
+
plugins: [
|
|
121
|
+
require('pxtorem-css')({
|
|
122
|
+
baseSize: 16,
|
|
123
|
+
properties: ['*'],
|
|
124
|
+
minValue: 2,
|
|
125
|
+
}),
|
|
126
|
+
require('autoprefixer'),
|
|
127
|
+
],
|
|
128
|
+
};
|
|
129
|
+
```
|
|
130
|
+
|
|
131
|
+
</details>
|
|
132
|
+
|
|
133
|
+
<details>
|
|
134
|
+
<summary><strong>Node.js Script</strong></summary>
|
|
135
|
+
|
|
136
|
+
```js
|
|
137
|
+
const fs = require('fs');
|
|
138
|
+
const postcss = require('postcss');
|
|
139
|
+
const pxtorem = require('pxtorem-css');
|
|
140
|
+
|
|
141
|
+
const css = fs.readFileSync('input.css', 'utf8');
|
|
142
|
+
|
|
143
|
+
postcss([pxtorem({ baseSize: 16 })])
|
|
144
|
+
.process(css)
|
|
145
|
+
.then((result) => {
|
|
146
|
+
fs.writeFileSync('output.css', result.css);
|
|
147
|
+
});
|
|
148
|
+
```
|
|
149
|
+
|
|
150
|
+
</details>
|
|
151
|
+
|
|
152
|
+
---
|
|
153
|
+
|
|
154
|
+
## ⚙️ Options
|
|
155
|
+
|
|
156
|
+
| Option | Type | Default | Description |
|
|
157
|
+
| --------------------- | ---------------------- | ---------- | ---------------------------------------------------------- |
|
|
158
|
+
| `baseSize` | `number \| function` | `16` | Base font size for conversion |
|
|
159
|
+
| `toUnit` | `string` | `'rem'` | Target unit (`rem`, `em`, `vw`, `vh`, `vmin`, `vmax`, `%`) |
|
|
160
|
+
| `fromUnit` | `string` | `'px'` | Source unit to convert |
|
|
161
|
+
| `precision` | `number` | `5` | Decimal precision |
|
|
162
|
+
| `properties` | `string[]` | `['*']` | Properties to convert (supports wildcards) |
|
|
163
|
+
| `skipSelectors` | `(string \| RegExp)[]` | `[]` | Selectors to skip |
|
|
164
|
+
| `minValue` | `number` | `0` | Skip values below this |
|
|
165
|
+
| `maxValue` | `number` | `Infinity` | Skip values above this |
|
|
166
|
+
| `convertMediaQueries` | `boolean` | `false` | Convert in media queries |
|
|
167
|
+
| `replaceOriginal` | `boolean` | `true` | Replace vs add fallback |
|
|
168
|
+
| `propertyBaseSize` | `object` | `{}` | Per-property base sizes |
|
|
169
|
+
| `convert` | `function` | `null` | Custom conversion function |
|
|
170
|
+
| `verbose` | `boolean` | `false` | Log conversions |
|
|
171
|
+
|
|
172
|
+
---
|
|
173
|
+
|
|
174
|
+
## 🎨 Advanced Examples
|
|
175
|
+
|
|
176
|
+
### Property Wildcards
|
|
177
|
+
|
|
178
|
+
```js
|
|
179
|
+
pxtorem({
|
|
180
|
+
properties: ['font*', '*margin*', '!border*'],
|
|
181
|
+
// ✓ font-size, font-weight, margin, margin-top
|
|
182
|
+
// ✗ border, border-width
|
|
183
|
+
});
|
|
184
|
+
```
|
|
185
|
+
|
|
186
|
+
### Per-Property Base Size
|
|
187
|
+
|
|
188
|
+
```js
|
|
189
|
+
pxtorem({
|
|
190
|
+
baseSize: 16,
|
|
191
|
+
propertyBaseSize: {
|
|
192
|
+
'font-size': 14,
|
|
193
|
+
'line-height': 20,
|
|
194
|
+
},
|
|
195
|
+
});
|
|
196
|
+
```
|
|
197
|
+
|
|
198
|
+
### Custom Transform
|
|
199
|
+
|
|
200
|
+
```js
|
|
201
|
+
pxtorem({
|
|
202
|
+
convert: (px, property, selector) => {
|
|
203
|
+
// Skip small values
|
|
204
|
+
if (px < 4) return false;
|
|
205
|
+
|
|
206
|
+
// Use CSS variable
|
|
207
|
+
if (px === 16) return 'var(--base-size)';
|
|
208
|
+
|
|
209
|
+
// Round to 0.25rem
|
|
210
|
+
return Math.round((px / 16) * 4) / 4;
|
|
211
|
+
},
|
|
212
|
+
});
|
|
213
|
+
```
|
|
214
|
+
|
|
215
|
+
### Viewport Units (Mobile-First)
|
|
216
|
+
|
|
217
|
+
```js
|
|
218
|
+
pxtorem({
|
|
219
|
+
toUnit: 'vw',
|
|
220
|
+
baseSize: 3.75, // 375px / 100vw
|
|
221
|
+
properties: ['*'],
|
|
222
|
+
});
|
|
223
|
+
```
|
|
224
|
+
|
|
225
|
+
---
|
|
226
|
+
|
|
227
|
+
## 💬 Comment Control
|
|
228
|
+
|
|
229
|
+
Disable conversion with inline comments:
|
|
230
|
+
|
|
231
|
+
```css
|
|
232
|
+
.element {
|
|
233
|
+
font-size: 16px; /* → 1rem */
|
|
234
|
+
padding: 20px; /* pxtorem-disable-line */ /* → 20px (skipped) */
|
|
235
|
+
|
|
236
|
+
/* pxtorem-disable */
|
|
237
|
+
margin: 32px; /* → 32px (skipped) */
|
|
238
|
+
border: 1px solid; /* → 1px (skipped) */
|
|
239
|
+
/* pxtorem-enable */
|
|
240
|
+
|
|
241
|
+
width: 100px; /* → 6.25rem */
|
|
242
|
+
}
|
|
243
|
+
```
|
|
244
|
+
|
|
245
|
+
| Comment | Effect |
|
|
246
|
+
| --------------------------------- | -------------------- |
|
|
247
|
+
| `/* pxtorem-disable-line */` | Skip current line |
|
|
248
|
+
| `/* pxtorem-disable-next-line */` | Skip next line |
|
|
249
|
+
| `/* pxtorem-disable */` | Disable until enable |
|
|
250
|
+
| `/* pxtorem-enable */` | Re-enable |
|
|
251
|
+
|
|
252
|
+
---
|
|
253
|
+
|
|
254
|
+
## 🖥️ CLI Reference
|
|
255
|
+
|
|
256
|
+
```bash
|
|
257
|
+
pxtorem [options] <input>
|
|
258
|
+
```
|
|
259
|
+
|
|
260
|
+
| Option | Description |
|
|
261
|
+
| ------------------------- | --------------------------------- |
|
|
262
|
+
| `-o, --output <path>` | Output file/directory |
|
|
263
|
+
| `-b, --base-size <n>` | Base font size |
|
|
264
|
+
| `-u, --to-unit <unit>` | Target unit |
|
|
265
|
+
| `-p, --precision <n>` | Decimal precision |
|
|
266
|
+
| `--properties <list>` | Comma-separated properties |
|
|
267
|
+
| `--skip-selectors <list>` | Comma-separated selectors to skip |
|
|
268
|
+
| `--min-value <n>` | Min px value |
|
|
269
|
+
| `--max-value <n>` | Max px value |
|
|
270
|
+
| `--media-queries` | Convert in media queries |
|
|
271
|
+
| `--no-replace` | Add fallback instead of replacing |
|
|
272
|
+
| `-v, --verbose` | Verbose output |
|
|
273
|
+
| `-h, --help` | Show help |
|
|
274
|
+
|
|
275
|
+
### CLI Examples
|
|
276
|
+
|
|
277
|
+
```bash
|
|
278
|
+
# Basic conversion
|
|
279
|
+
pxtorem style.css
|
|
280
|
+
|
|
281
|
+
# Custom options
|
|
282
|
+
pxtorem style.css -b 16 -u rem -p 5 --min-value 2
|
|
283
|
+
|
|
284
|
+
# Different output
|
|
285
|
+
pxtorem -o dist/styles.css src/styles.css
|
|
286
|
+
|
|
287
|
+
# Directory conversion
|
|
288
|
+
pxtorem -o dist/css src/css
|
|
289
|
+
|
|
290
|
+
# Filter properties
|
|
291
|
+
pxtorem style.css --properties "font-size,margin,padding"
|
|
292
|
+
```
|
|
293
|
+
|
|
294
|
+
---
|
|
295
|
+
|
|
296
|
+
## 📘 TypeScript
|
|
297
|
+
|
|
298
|
+
```ts
|
|
299
|
+
import pxtorem, { Options, ConversionReport, TargetUnit } from 'pxtorem-css';
|
|
300
|
+
|
|
301
|
+
const options: Options = {
|
|
302
|
+
baseSize: 16,
|
|
303
|
+
toUnit: 'rem',
|
|
304
|
+
onConversionComplete: (report: ConversionReport) => {
|
|
305
|
+
console.log(`Converted: ${report.convertedDeclarations}`);
|
|
306
|
+
},
|
|
307
|
+
};
|
|
308
|
+
```
|
|
309
|
+
|
|
310
|
+
---
|
|
311
|
+
|
|
312
|
+
## 📄 License
|
|
313
|
+
|
|
314
|
+
MIT © [Rashed Iqbal](https://github.com/iqbal-rashed)
|
package/dist/cli.js
ADDED
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
"use strict";var z=Object.create;var y=Object.defineProperty;var M=Object.getOwnPropertyDescriptor;var B=Object.getOwnPropertyNames;var I=Object.getPrototypeOf,T=Object.prototype.hasOwnProperty;var A=(t,e,i,r)=>{if(e&&typeof e=="object"||typeof e=="function")for(let s of B(e))!T.call(t,s)&&s!==i&&y(t,s,{get:()=>e[s],enumerable:!(r=M(e,s))||r.enumerable});return t};var L=(t,e,i)=>(i=t!=null?z(I(t)):{},A(e||!t||!t.__esModule?y(i,"default",{value:t,enumerable:!0}):i,t));var f=require("fs"),m=require("path"),F=L(require("postcss"));function h(t){return new RegExp(`"[^"]+"|'[^']+'|url\\([^)]+\\)|var\\([^)]+\\)|(\\d*\\.?\\d+)${t}`,"g")}function Q(t){return t.filter(e=>e.match(/^[^*!]+$/))}function j(t){return t.filter(e=>e.match(/^\*.+\*$/)).map(e=>e.slice(1,-1))}function q(t){return t.filter(e=>e.match(/^[^*!]+\*$/)).map(e=>e.slice(0,-1))}function J(t){return t.filter(e=>e.match(/^\*[^*]+$/)).map(e=>e.slice(1))}function _(t){return t.filter(e=>e.match(/^![^*].*$/)).map(e=>e.slice(1))}function H(t){return t.filter(e=>e.match(/^!\*.+\*$/)).map(e=>e.slice(2,-1))}function X(t){return t.filter(e=>e.match(/^!\*[^*]+$/)).map(e=>e.slice(2))}function G(t){return t.filter(e=>e.match(/^![^*]+\*$/)).map(e=>e.slice(1,-1))}var g={exact:Q,contain:j,startWith:q,endWith:J,notExact:_,notContain:H,notStartWith:X,notEndWith:G};function $(t){let e=t.indexOf("*")>-1,i=e&&t.length===1,r={exact:g.exact(t),contain:g.contain(t),startWith:g.startWith(t),endWith:g.endWith(t),notExact:g.notExact(t),notContain:g.notContain(t),notStartWith:g.notStartWith(t),notEndWith:g.notEndWith(t)};return s=>i?!0:(e||r.exact.indexOf(s)>-1||r.contain.some(n=>s.indexOf(n)>-1)||r.startWith.some(n=>s.indexOf(n)===0)||r.endWith.some(n=>s.indexOf(n)===s.length-n.length))&&!(r.notExact.indexOf(s)>-1||r.notContain.some(n=>s.indexOf(n)>-1)||r.notStartWith.some(n=>s.indexOf(n)===0)||r.notEndWith.some(n=>s.indexOf(n)===s.length-n.length))}function E(t){return typeof t=="string"}function C(t){return typeof t=="function"}function k(t,e){return t.text.trim().toLowerCase().includes(e.toLowerCase())}function K(t){if(!t.parent)return;let e=t.parent.index(t);if(!(e<=0))return t.parent.nodes?.[e-1]}function V(t,e,i,r,s){let n=t.source;if(n?.input?.css){let c=n.input.css.split(`
|
|
3
|
+
`),l=(n.start?.line??1)-1;if(l>=0&&l<c.length){let p=c[l];if(p.includes("/*")&&p.toLowerCase().includes(i.toLowerCase()))return!0}}let a=K(t);if(a?.type==="comment"&&k(a,e))return!0;let o=t,u=!1;for(;o?.parent;){let c=o.parent,l=c.index(o);for(let p=l-1;p>=0;p--){let d=c.nodes?.[p];if(d?.type==="comment"){let x=d;if(k(x,s)){u=!1;break}if(k(x,r)){u=!0;break}}}if(u)return!0;o=c}return u}var Y={baseSize:16,precision:5,skipSelectors:[],properties:["*"],replaceOriginal:!0,convertMediaQueries:!1,minValue:0,maxValue:1/0,excludeFiles:null,includeFiles:null,fromUnit:"px",toUnit:"rem",propertyBaseSize:{},disableNextLineComment:"pxtorem-disable-next-line",disableLineComment:"pxtorem-disable-line",disableBlockComment:"pxtorem-disable",enableBlockComment:"pxtorem-enable",convert:null,onConversionComplete:null,verbose:!1};function w(t,e){let i=Math.pow(10,e+1),r=Math.floor(t*i);return Math.round(r/10)*10/i}function Z(t,e,i){return t.some(r=>r.prop===e&&r.value===i)}function ee(t,e){return typeof e!="string"?!1:t.some(i=>typeof i=="string"?e.indexOf(i)!==-1:i.test(e))}function N(t,e){return!e||!t?!1:C(e)?e(t):E(e)?t.indexOf(e)!==-1:e instanceof RegExp?e.test(t):!1}function U(t,e,i,r,s,n,a,o,u,c,l){let p=o[n]??t;return(d,x)=>{if(!x)return d;let b=parseFloat(x);if(b<i||b>r)return c.skipped++,d;if(u){let v=u(b,n,a);if(v===!1)return c.skipped++,d;if(typeof v=="string")return c.converted++,l&&console.log(`[pxtorem-css] ${n}: ${d} \u2192 ${v} (custom)`),v;if(typeof v=="number"){let O=w(v,e);return c.converted++,l&&console.log(`[pxtorem-css] ${n}: ${d} \u2192 ${O}${s} (custom)`),O+s}}let S=w(b/p,e);return c.converted++,l&&console.log(`[pxtorem-css] ${n}: ${d} \u2192 ${S}${s}`),S+s}}function D(t={}){let e={...Y,...t},i=$(e.properties),r=!1,s,n,a={totalDeclarations:0,convertedDeclarations:0,skippedDeclarations:0,filesProcessed:[],details:new Map};return{postcssPlugin:"pxtorem-css",Once(o){n=o.source?.input?.file,e.includeFiles&&n?r=!N(n,e.includeFiles):e.excludeFiles&&n?r=N(n,e.excludeFiles):r=!1,!r&&(n&&!a.filesProcessed.includes(n)&&(a.filesProcessed.push(n),a.details.set(n,{converted:0,skipped:0})),s=C(e.baseSize)?e.baseSize(o.source.input):e.baseSize)},Declaration(o){if(r)return;if(a.totalDeclarations++,o.value.indexOf(e.fromUnit)===-1){a.skippedDeclarations++;return}if(!i(o.prop)){a.skippedDeclarations++;return}let u=o.parent?.type==="rule"?o.parent.selector:void 0;if(ee(e.skipSelectors,u)){a.skippedDeclarations++;return}if(V(o,e.disableNextLineComment,e.disableLineComment,e.disableBlockComment,e.enableBlockComment)){a.skippedDeclarations++,e.verbose&&console.log(`[pxtorem-css] Skipped (disabled): ${o.prop}: ${o.value}`);return}let c=n?a.details.get(n)??{converted:0,skipped:0}:{converted:0,skipped:0},l=h(e.fromUnit),p=U(s,e.precision,e.minValue,e.maxValue,e.toUnit,o.prop,u??"",e.propertyBaseSize,e.convert,c,e.verbose),d=o.value.replace(l,p);n&&a.details.set(n,c),a.convertedDeclarations+=c.converted,a.skippedDeclarations+=c.skipped,d!==o.value&&(o.parent&&Z(o.parent.nodes?.filter(x=>x.type==="decl")||[],o.prop,d)||(e.replaceOriginal?o.value=d:o.cloneAfter({value:d})))},AtRule(o){if(!r&&e.convertMediaQueries&&o.name==="media"){if(o.params.indexOf(e.fromUnit)===-1)return;let u=n?a.details.get(n)??{converted:0,skipped:0}:{converted:0,skipped:0},c=h(e.fromUnit),l=U(s,e.precision,e.minValue,e.maxValue,e.toUnit,"@media","",e.propertyBaseSize,e.convert,u,e.verbose);o.params=o.params.replace(c,l),n&&a.details.set(n,u)}},OnceExit(){e.onConversionComplete&&e.onConversionComplete(a),e.verbose&&(console.log(`
|
|
4
|
+
[pxtorem-css] Conversion Report:`),console.log(` Files: ${a.filesProcessed.length}`),console.log(` Total: ${a.totalDeclarations}`),console.log(` Converted: ${a.convertedDeclarations}`),console.log(` Skipped: ${a.skippedDeclarations}
|
|
5
|
+
`))}}}D.postcss=!0;var R=D;var te="2.0.0",ne=`
|
|
6
|
+
pxtorem-css - Convert px to rem/em/vw/vh in CSS files
|
|
7
|
+
|
|
8
|
+
Usage:
|
|
9
|
+
pxtorem [options] <input>
|
|
10
|
+
|
|
11
|
+
Options:
|
|
12
|
+
-i, --input <path> Input CSS file or directory
|
|
13
|
+
-o, --output <path> Output file or directory (default: overwrite input)
|
|
14
|
+
-c, --config <path> Path to config file (JSON)
|
|
15
|
+
-b, --base-size <n> Base font size (default: 16)
|
|
16
|
+
-u, --to-unit <unit> Target unit: rem, em, vw, vh, vmin, vmax, % (default: rem)
|
|
17
|
+
-f, --from-unit <unit> Source unit (default: px)
|
|
18
|
+
-p, --precision <n> Decimal precision (default: 5)
|
|
19
|
+
--properties <list> Comma-separated properties to convert (default: *)
|
|
20
|
+
--skip-selectors <list> Comma-separated selectors to skip
|
|
21
|
+
--min-value <n> Minimum px value to convert (default: 0)
|
|
22
|
+
--max-value <n> Maximum px value to convert (default: Infinity)
|
|
23
|
+
--media-queries Convert px in media queries
|
|
24
|
+
--no-replace Add rem as fallback instead of replacing
|
|
25
|
+
-v, --verbose Show conversion details
|
|
26
|
+
-h, --help Show this help message
|
|
27
|
+
--version Show version number
|
|
28
|
+
|
|
29
|
+
Examples:
|
|
30
|
+
pxtorem style.css
|
|
31
|
+
pxtorem style.css -b 16 -u rem -p 5
|
|
32
|
+
pxtorem -i src/styles -o dist/styles
|
|
33
|
+
pxtorem style.css --properties "font-size,margin,padding"
|
|
34
|
+
pxtorem style.css --skip-selectors "body,.no-convert"
|
|
35
|
+
pxtorem style.css --min-value 2 --media-queries
|
|
36
|
+
`;function ie(t){let e={},i=0;for(;i<t.length;){let r=t[i];switch(r){case"-i":case"--input":e.input=t[++i];break;case"-o":case"--output":e.output=t[++i];break;case"-c":case"--config":e.config=t[++i];break;case"-b":case"--base-size":e.baseSize=parseFloat(t[++i]);break;case"-u":case"--to-unit":e.toUnit=t[++i];break;case"-p":case"--precision":e.precision=parseInt(t[++i],10);break;case"-f":case"--from-unit":e.fromUnit=t[++i];break;case"--properties":e.properties=t[++i].split(",").map(s=>s.trim());break;case"--skip-selectors":e.skipSelectors=t[++i].split(",").map(s=>s.trim());break;case"--min-value":e.minValue=parseFloat(t[++i]);break;case"--max-value":e.maxValue=parseFloat(t[++i]);break;case"--media-queries":e.convertMediaQueries=!0;break;case"--no-replace":e.replaceOriginal=!1;break;case"-v":case"--verbose":e.verbose=!0;break;case"-h":case"--help":e.help=!0;break;case"--version":e.version=!0;break;default:!r.startsWith("-")&&!e.input?e.input=r:r.startsWith("-")&&(console.error(`Error: Unknown option "${r}"`),console.log("Use --help to see available options."),process.exit(1));break}i++}return e}var W=["rem","em","vw","vh","vmin","vmax","%"];function re(t){let e=[];t.toUnit&&!W.includes(t.toUnit)&&e.push(`Invalid --to-unit "${t.toUnit}". Valid values: ${W.join(", ")}`),t.baseSize!==void 0&&(isNaN(t.baseSize)||t.baseSize<=0)&&e.push("--base-size must be a positive number"),t.precision!==void 0&&(isNaN(t.precision)||t.precision<0||!Number.isInteger(t.precision))&&e.push("--precision must be a non-negative integer"),t.minValue!==void 0&&isNaN(t.minValue)&&e.push("--min-value must be a number"),t.maxValue!==void 0&&isNaN(t.maxValue)&&e.push("--max-value must be a number"),t.minValue!==void 0&&t.maxValue!==void 0&&t.minValue>t.maxValue&&e.push("--min-value cannot be greater than --max-value"),t.config&&!(0,f.existsSync)(t.config)&&e.push(`Config file not found: ${t.config}`),e.length>0&&(console.error("Validation errors:"),e.forEach(i=>console.error(` \u2717 ${i}`)),process.exit(1))}function se(t){try{let e=(0,f.readFileSync)(t,"utf-8");return JSON.parse(e)}catch(e){console.error(`Error loading config file: ${t}`,e),process.exit(1)}}function oe(){let t=["pxtorem.config.json","pxtorem.json",".pxtoremrc.json"];for(let e of t){let i=(0,m.resolve)(process.cwd(),e);if((0,f.existsSync)(i))return i}return null}function P(t){let e=(0,m.resolve)(process.cwd(),t);(0,f.existsSync)(e)||(console.error(`Error: Path not found: ${t}`),process.exit(1));let i=(0,f.statSync)(e);if(i.isFile())return[e];if(i.isDirectory()){let r=[],s=(0,f.readdirSync)(e,{withFileTypes:!0});for(let n of s)n.isFile()&&/\.(css|scss|sass|less)$/.test(n.name)?r.push((0,m.join)(e,n.name)):n.isDirectory()&&r.push(...P((0,m.join)(e,n.name)));return r}return[]}async function ae(t,e,i){let r=(0,f.readFileSync)(t,"utf-8"),s={converted:0,skipped:0},n=await(0,F.default)([R({...i,onConversionComplete:a=>{s={converted:a.convertedDeclarations,skipped:a.skippedDeclarations}}})]).process(r,{from:t,to:e});return(0,f.writeFileSync)(e,n.css),s}async function le(){let t=process.argv.slice(2),e=ie(t);e.version&&(console.log(`pxtorem-css v${te}`),process.exit(0)),(e.help||!e.input)&&(console.log(ne),process.exit(e.help?0:1)),re(e);let i={},r=e.config||oe();r&&(i=se(r),e.verbose&&console.log(`Using config: ${r}`));let s={...i,...e.baseSize!==void 0&&{baseSize:e.baseSize},...e.toUnit!==void 0&&{toUnit:e.toUnit},...e.fromUnit!==void 0&&{fromUnit:e.fromUnit},...e.precision!==void 0&&{precision:e.precision},...e.properties!==void 0&&{properties:e.properties},...e.skipSelectors!==void 0&&{skipSelectors:e.skipSelectors},...e.minValue!==void 0&&{minValue:e.minValue},...e.maxValue!==void 0&&{maxValue:e.maxValue},...e.convertMediaQueries!==void 0&&{convertMediaQueries:e.convertMediaQueries},...e.replaceOriginal!==void 0&&{replaceOriginal:e.replaceOriginal},...e.verbose!==void 0&&{verbose:e.verbose}},n=P(e.input);n.length===0&&(console.error("No CSS files found."),process.exit(1)),console.log(`
|
|
37
|
+
Processing ${n.length} file(s)...
|
|
38
|
+
`);let a=0,o=0;for(let u of n){let c;if(e.output){let l=(0,m.resolve)(process.cwd(),e.output),p=(0,f.existsSync)(l)&&(0,f.statSync)(l);p&&p.isDirectory()?c=(0,m.join)(l,(0,m.basename)(u)):n.length===1?c=l:c=(0,m.join)(l,(0,m.basename)(u))}else c=u;try{let l=await ae(u,c,s);a+=l.converted,o+=l.skipped;let p=u.replace(process.cwd(),".");console.log(`\u2713 ${p} (${l.converted} converted, ${l.skipped} skipped)`)}catch(l){console.error(`\u2717 ${u}: ${l.message}`)}}console.log(`
|
|
39
|
+
Done! Converted: ${a}, Skipped: ${o}
|
|
40
|
+
`)}le().catch(t=>{console.error(t),process.exit(1)});
|
package/dist/index.d.mts
ADDED
|
@@ -0,0 +1,157 @@
|
|
|
1
|
+
import { Input, Plugin } from 'postcss';
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* Supported target units for conversion
|
|
5
|
+
*/
|
|
6
|
+
type TargetUnit = 'rem' | 'em' | 'vw' | 'vh' | 'vmin' | 'vmax' | '%';
|
|
7
|
+
/**
|
|
8
|
+
* Conversion report generated after processing
|
|
9
|
+
*/
|
|
10
|
+
interface ConversionReport {
|
|
11
|
+
/** Total number of declarations processed */
|
|
12
|
+
totalDeclarations: number;
|
|
13
|
+
/** Number of declarations converted */
|
|
14
|
+
convertedDeclarations: number;
|
|
15
|
+
/** Number of declarations skipped */
|
|
16
|
+
skippedDeclarations: number;
|
|
17
|
+
/** List of files processed */
|
|
18
|
+
filesProcessed: string[];
|
|
19
|
+
/** Conversion details per file */
|
|
20
|
+
details: Map<string, {
|
|
21
|
+
converted: number;
|
|
22
|
+
skipped: number;
|
|
23
|
+
}>;
|
|
24
|
+
}
|
|
25
|
+
/**
|
|
26
|
+
* Options for the pxtorem-css plugin
|
|
27
|
+
*/
|
|
28
|
+
interface Options {
|
|
29
|
+
/**
|
|
30
|
+
* Base font size for conversion calculation
|
|
31
|
+
* @default 16
|
|
32
|
+
*/
|
|
33
|
+
baseSize?: number | ((input: Input) => number);
|
|
34
|
+
/**
|
|
35
|
+
* Decimal precision for converted values
|
|
36
|
+
* @default 5
|
|
37
|
+
*/
|
|
38
|
+
precision?: number;
|
|
39
|
+
/**
|
|
40
|
+
* Properties to convert. Supports wildcards and negation.
|
|
41
|
+
* - `['*']` - all properties
|
|
42
|
+
* - `['font*']` - properties starting with font
|
|
43
|
+
* - `['*size']` - properties ending with size
|
|
44
|
+
* - `['!border*']` - exclude properties starting with border
|
|
45
|
+
* @default ['*']
|
|
46
|
+
*/
|
|
47
|
+
properties?: string[];
|
|
48
|
+
/**
|
|
49
|
+
* Selectors to skip. Strings check for containment, RegExp for matches.
|
|
50
|
+
* @default []
|
|
51
|
+
*/
|
|
52
|
+
skipSelectors?: (string | RegExp)[];
|
|
53
|
+
/**
|
|
54
|
+
* Replace values instead of adding fallbacks
|
|
55
|
+
* @default true
|
|
56
|
+
*/
|
|
57
|
+
replaceOriginal?: boolean;
|
|
58
|
+
/**
|
|
59
|
+
* Convert px in media queries
|
|
60
|
+
* @default false
|
|
61
|
+
*/
|
|
62
|
+
convertMediaQueries?: boolean;
|
|
63
|
+
/**
|
|
64
|
+
* Minimum px value to convert. Values below this are skipped.
|
|
65
|
+
* @default 0
|
|
66
|
+
*/
|
|
67
|
+
minValue?: number;
|
|
68
|
+
/**
|
|
69
|
+
* Maximum px value to convert. Values above this are skipped.
|
|
70
|
+
* @default Infinity
|
|
71
|
+
*/
|
|
72
|
+
maxValue?: number;
|
|
73
|
+
/**
|
|
74
|
+
* File paths to exclude from conversion
|
|
75
|
+
*/
|
|
76
|
+
excludeFiles?: string | RegExp | ((file: string) => boolean) | null;
|
|
77
|
+
/**
|
|
78
|
+
* File paths to include for conversion (overrides excludeFiles)
|
|
79
|
+
*/
|
|
80
|
+
includeFiles?: string | RegExp | ((file: string) => boolean) | null;
|
|
81
|
+
/**
|
|
82
|
+
* Source unit to convert from
|
|
83
|
+
* @default 'px'
|
|
84
|
+
*/
|
|
85
|
+
fromUnit?: string;
|
|
86
|
+
/**
|
|
87
|
+
* Target unit to convert to
|
|
88
|
+
* @default 'rem'
|
|
89
|
+
*/
|
|
90
|
+
toUnit?: TargetUnit;
|
|
91
|
+
/**
|
|
92
|
+
* Property-specific base sizes. Overrides baseSize for specified properties.
|
|
93
|
+
* @example { 'font-size': 14, 'line-height': 20 }
|
|
94
|
+
*/
|
|
95
|
+
propertyBaseSize?: Record<string, number>;
|
|
96
|
+
/**
|
|
97
|
+
* Comment pattern to disable conversion for next line
|
|
98
|
+
* @default 'pxtorem-disable-next-line'
|
|
99
|
+
*/
|
|
100
|
+
disableNextLineComment?: string;
|
|
101
|
+
/**
|
|
102
|
+
* Comment pattern to disable conversion for current line
|
|
103
|
+
* @default 'pxtorem-disable-line'
|
|
104
|
+
*/
|
|
105
|
+
disableLineComment?: string;
|
|
106
|
+
/**
|
|
107
|
+
* Comment pattern to disable conversion for block
|
|
108
|
+
* @default 'pxtorem-disable'
|
|
109
|
+
*/
|
|
110
|
+
disableBlockComment?: string;
|
|
111
|
+
/**
|
|
112
|
+
* Comment pattern to re-enable conversion after disable
|
|
113
|
+
* @default 'pxtorem-enable'
|
|
114
|
+
*/
|
|
115
|
+
enableBlockComment?: string;
|
|
116
|
+
/**
|
|
117
|
+
* Custom conversion function.
|
|
118
|
+
* Return a number for calculated value, string for custom output, or false to skip.
|
|
119
|
+
* @param pixelValue - The original pixel value
|
|
120
|
+
* @param property - The CSS property name
|
|
121
|
+
* @param selector - The CSS selector
|
|
122
|
+
* @returns Custom value or false to skip
|
|
123
|
+
*/
|
|
124
|
+
convert?: (pixelValue: number, property: string, selector: string) => number | string | false;
|
|
125
|
+
/**
|
|
126
|
+
* Callback when processing is complete with conversion report
|
|
127
|
+
*/
|
|
128
|
+
onConversionComplete?: (report: ConversionReport) => void;
|
|
129
|
+
/**
|
|
130
|
+
* Log conversion details to console
|
|
131
|
+
* @default false
|
|
132
|
+
*/
|
|
133
|
+
verbose?: boolean;
|
|
134
|
+
}
|
|
135
|
+
|
|
136
|
+
/**
|
|
137
|
+
* PostCSS plugin that converts px to rem/em/vw/vh units
|
|
138
|
+
*
|
|
139
|
+
* @example
|
|
140
|
+
* ```js
|
|
141
|
+
* import pxtorem from 'pxtorem-css';
|
|
142
|
+
*
|
|
143
|
+
* postcss([
|
|
144
|
+
* pxtorem({
|
|
145
|
+
* baseSize: 16,
|
|
146
|
+
* properties: ['*'],
|
|
147
|
+
* toUnit: 'rem'
|
|
148
|
+
* })
|
|
149
|
+
* ])
|
|
150
|
+
* ```
|
|
151
|
+
*/
|
|
152
|
+
declare function pxtorem(options?: Options): Plugin;
|
|
153
|
+
declare namespace pxtorem {
|
|
154
|
+
var postcss: boolean;
|
|
155
|
+
}
|
|
156
|
+
|
|
157
|
+
export { type ConversionReport, type Options, type TargetUnit, pxtorem as default, pxtorem };
|
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1,159 @@
|
|
|
1
|
+
import { Input, Plugin } from 'postcss';
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* Supported target units for conversion
|
|
5
|
+
*/
|
|
6
|
+
type TargetUnit = 'rem' | 'em' | 'vw' | 'vh' | 'vmin' | 'vmax' | '%';
|
|
7
|
+
/**
|
|
8
|
+
* Conversion report generated after processing
|
|
9
|
+
*/
|
|
10
|
+
interface ConversionReport {
|
|
11
|
+
/** Total number of declarations processed */
|
|
12
|
+
totalDeclarations: number;
|
|
13
|
+
/** Number of declarations converted */
|
|
14
|
+
convertedDeclarations: number;
|
|
15
|
+
/** Number of declarations skipped */
|
|
16
|
+
skippedDeclarations: number;
|
|
17
|
+
/** List of files processed */
|
|
18
|
+
filesProcessed: string[];
|
|
19
|
+
/** Conversion details per file */
|
|
20
|
+
details: Map<string, {
|
|
21
|
+
converted: number;
|
|
22
|
+
skipped: number;
|
|
23
|
+
}>;
|
|
24
|
+
}
|
|
25
|
+
/**
|
|
26
|
+
* Options for the pxtorem-css plugin
|
|
27
|
+
*/
|
|
28
|
+
interface Options {
|
|
29
|
+
/**
|
|
30
|
+
* Base font size for conversion calculation
|
|
31
|
+
* @default 16
|
|
32
|
+
*/
|
|
33
|
+
baseSize?: number | ((input: Input) => number);
|
|
34
|
+
/**
|
|
35
|
+
* Decimal precision for converted values
|
|
36
|
+
* @default 5
|
|
37
|
+
*/
|
|
38
|
+
precision?: number;
|
|
39
|
+
/**
|
|
40
|
+
* Properties to convert. Supports wildcards and negation.
|
|
41
|
+
* - `['*']` - all properties
|
|
42
|
+
* - `['font*']` - properties starting with font
|
|
43
|
+
* - `['*size']` - properties ending with size
|
|
44
|
+
* - `['!border*']` - exclude properties starting with border
|
|
45
|
+
* @default ['*']
|
|
46
|
+
*/
|
|
47
|
+
properties?: string[];
|
|
48
|
+
/**
|
|
49
|
+
* Selectors to skip. Strings check for containment, RegExp for matches.
|
|
50
|
+
* @default []
|
|
51
|
+
*/
|
|
52
|
+
skipSelectors?: (string | RegExp)[];
|
|
53
|
+
/**
|
|
54
|
+
* Replace values instead of adding fallbacks
|
|
55
|
+
* @default true
|
|
56
|
+
*/
|
|
57
|
+
replaceOriginal?: boolean;
|
|
58
|
+
/**
|
|
59
|
+
* Convert px in media queries
|
|
60
|
+
* @default false
|
|
61
|
+
*/
|
|
62
|
+
convertMediaQueries?: boolean;
|
|
63
|
+
/**
|
|
64
|
+
* Minimum px value to convert. Values below this are skipped.
|
|
65
|
+
* @default 0
|
|
66
|
+
*/
|
|
67
|
+
minValue?: number;
|
|
68
|
+
/**
|
|
69
|
+
* Maximum px value to convert. Values above this are skipped.
|
|
70
|
+
* @default Infinity
|
|
71
|
+
*/
|
|
72
|
+
maxValue?: number;
|
|
73
|
+
/**
|
|
74
|
+
* File paths to exclude from conversion
|
|
75
|
+
*/
|
|
76
|
+
excludeFiles?: string | RegExp | ((file: string) => boolean) | null;
|
|
77
|
+
/**
|
|
78
|
+
* File paths to include for conversion (overrides excludeFiles)
|
|
79
|
+
*/
|
|
80
|
+
includeFiles?: string | RegExp | ((file: string) => boolean) | null;
|
|
81
|
+
/**
|
|
82
|
+
* Source unit to convert from
|
|
83
|
+
* @default 'px'
|
|
84
|
+
*/
|
|
85
|
+
fromUnit?: string;
|
|
86
|
+
/**
|
|
87
|
+
* Target unit to convert to
|
|
88
|
+
* @default 'rem'
|
|
89
|
+
*/
|
|
90
|
+
toUnit?: TargetUnit;
|
|
91
|
+
/**
|
|
92
|
+
* Property-specific base sizes. Overrides baseSize for specified properties.
|
|
93
|
+
* @example { 'font-size': 14, 'line-height': 20 }
|
|
94
|
+
*/
|
|
95
|
+
propertyBaseSize?: Record<string, number>;
|
|
96
|
+
/**
|
|
97
|
+
* Comment pattern to disable conversion for next line
|
|
98
|
+
* @default 'pxtorem-disable-next-line'
|
|
99
|
+
*/
|
|
100
|
+
disableNextLineComment?: string;
|
|
101
|
+
/**
|
|
102
|
+
* Comment pattern to disable conversion for current line
|
|
103
|
+
* @default 'pxtorem-disable-line'
|
|
104
|
+
*/
|
|
105
|
+
disableLineComment?: string;
|
|
106
|
+
/**
|
|
107
|
+
* Comment pattern to disable conversion for block
|
|
108
|
+
* @default 'pxtorem-disable'
|
|
109
|
+
*/
|
|
110
|
+
disableBlockComment?: string;
|
|
111
|
+
/**
|
|
112
|
+
* Comment pattern to re-enable conversion after disable
|
|
113
|
+
* @default 'pxtorem-enable'
|
|
114
|
+
*/
|
|
115
|
+
enableBlockComment?: string;
|
|
116
|
+
/**
|
|
117
|
+
* Custom conversion function.
|
|
118
|
+
* Return a number for calculated value, string for custom output, or false to skip.
|
|
119
|
+
* @param pixelValue - The original pixel value
|
|
120
|
+
* @param property - The CSS property name
|
|
121
|
+
* @param selector - The CSS selector
|
|
122
|
+
* @returns Custom value or false to skip
|
|
123
|
+
*/
|
|
124
|
+
convert?: (pixelValue: number, property: string, selector: string) => number | string | false;
|
|
125
|
+
/**
|
|
126
|
+
* Callback when processing is complete with conversion report
|
|
127
|
+
*/
|
|
128
|
+
onConversionComplete?: (report: ConversionReport) => void;
|
|
129
|
+
/**
|
|
130
|
+
* Log conversion details to console
|
|
131
|
+
* @default false
|
|
132
|
+
*/
|
|
133
|
+
verbose?: boolean;
|
|
134
|
+
}
|
|
135
|
+
|
|
136
|
+
/**
|
|
137
|
+
* PostCSS plugin that converts px to rem/em/vw/vh units
|
|
138
|
+
*
|
|
139
|
+
* @example
|
|
140
|
+
* ```js
|
|
141
|
+
* import pxtorem from 'pxtorem-css';
|
|
142
|
+
*
|
|
143
|
+
* postcss([
|
|
144
|
+
* pxtorem({
|
|
145
|
+
* baseSize: 16,
|
|
146
|
+
* properties: ['*'],
|
|
147
|
+
* toUnit: 'rem'
|
|
148
|
+
* })
|
|
149
|
+
* ])
|
|
150
|
+
* ```
|
|
151
|
+
*/
|
|
152
|
+
declare function pxtorem(options?: Options): Plugin;
|
|
153
|
+
declare namespace pxtorem {
|
|
154
|
+
var postcss: boolean;
|
|
155
|
+
}
|
|
156
|
+
|
|
157
|
+
// @ts-ignore
|
|
158
|
+
export = pxtorem;
|
|
159
|
+
export { type ConversionReport, type Options, type TargetUnit, pxtorem };
|
package/dist/index.js
ADDED
|
@@ -0,0 +1,5 @@
|
|
|
1
|
+
"use strict";var h=Object.defineProperty;var N=Object.getOwnPropertyDescriptor;var P=Object.getOwnPropertyNames;var F=Object.prototype.hasOwnProperty;var w=(t,e)=>{for(var l in e)h(t,l,{get:e[l],enumerable:!0})},M=(t,e,l,r)=>{if(e&&typeof e=="object"||typeof e=="function")for(let o of P(e))!F.call(t,o)&&o!==l&&h(t,o,{get:()=>e[o],enumerable:!(r=N(e,o))||r.enumerable});return t};var U=t=>M(h({},"__esModule",{value:!0}),t);var K={};w(K,{default:()=>J,pxtorem:()=>k});module.exports=U(K);function v(t){return new RegExp(`"[^"]+"|'[^']+'|url\\([^)]+\\)|var\\([^)]+\\)|(\\d*\\.?\\d+)${t}`,"g")}function V(t){return t.filter(e=>e.match(/^[^*!]+$/))}function z(t){return t.filter(e=>e.match(/^\*.+\*$/)).map(e=>e.slice(1,-1))}function B(t){return t.filter(e=>e.match(/^[^*!]+\*$/)).map(e=>e.slice(0,-1))}function A(t){return t.filter(e=>e.match(/^\*[^*]+$/)).map(e=>e.slice(1))}function L(t){return t.filter(e=>e.match(/^![^*].*$/)).map(e=>e.slice(1))}function T(t){return t.filter(e=>e.match(/^!\*.+\*$/)).map(e=>e.slice(2,-1))}function I(t){return t.filter(e=>e.match(/^!\*[^*]+$/)).map(e=>e.slice(2))}function Q(t){return t.filter(e=>e.match(/^![^*]+\*$/)).map(e=>e.slice(1,-1))}var p={exact:V,contain:z,startWith:B,endWith:A,notExact:L,notContain:T,notStartWith:I,notEndWith:Q};function $(t){let e=t.indexOf("*")>-1,l=e&&t.length===1,r={exact:p.exact(t),contain:p.contain(t),startWith:p.startWith(t),endWith:p.endWith(t),notExact:p.notExact(t),notContain:p.notContain(t),notStartWith:p.notStartWith(t),notEndWith:p.notEndWith(t)};return o=>l?!0:(e||r.exact.indexOf(o)>-1||r.contain.some(n=>o.indexOf(n)>-1)||r.startWith.some(n=>o.indexOf(n)===0)||r.endWith.some(n=>o.indexOf(n)===o.length-n.length))&&!(r.notExact.indexOf(o)>-1||r.notContain.some(n=>o.indexOf(n)>-1)||r.notStartWith.some(n=>o.indexOf(n)===0)||r.notEndWith.some(n=>o.indexOf(n)===o.length-n.length))}function E(t){return typeof t=="string"}function b(t){return typeof t=="function"}function C(t,e){return t.text.trim().toLowerCase().includes(e.toLowerCase())}function j(t){if(!t.parent)return;let e=t.parent.index(t);if(!(e<=0))return t.parent.nodes?.[e-1]}function O(t,e,l,r,o){let n=t.source;if(n?.input?.css){let a=n.input.css.split(`
|
|
2
|
+
`),f=(n.start?.line??1)-1;if(f>=0&&f<a.length){let d=a[f];if(d.includes("/*")&&d.toLowerCase().includes(l.toLowerCase()))return!0}}let s=j(t);if(s?.type==="comment"&&C(s,e))return!0;let i=t,u=!1;for(;i?.parent;){let a=i.parent,f=a.index(i);for(let d=f-1;d>=0;d--){let c=a.nodes?.[d];if(c?.type==="comment"){let m=c;if(C(m,o)){u=!1;break}if(C(m,r)){u=!0;break}}}if(u)return!0;i=a}return u}var q={baseSize:16,precision:5,skipSelectors:[],properties:["*"],replaceOriginal:!0,convertMediaQueries:!1,minValue:0,maxValue:1/0,excludeFiles:null,includeFiles:null,fromUnit:"px",toUnit:"rem",propertyBaseSize:{},disableNextLineComment:"pxtorem-disable-next-line",disableLineComment:"pxtorem-disable-line",disableBlockComment:"pxtorem-disable",enableBlockComment:"pxtorem-enable",convert:null,onConversionComplete:null,verbose:!1};function W(t,e){let l=Math.pow(10,e+1),r=Math.floor(t*l);return Math.round(r/10)*10/l}function G(t,e,l){return t.some(r=>r.prop===e&&r.value===l)}function H(t,e){return typeof e!="string"?!1:t.some(l=>typeof l=="string"?e.indexOf(l)!==-1:l.test(e))}function D(t,e){return!e||!t?!1:b(e)?e(t):E(e)?t.indexOf(e)!==-1:e instanceof RegExp?e.test(t):!1}function y(t,e,l,r,o,n,s,i,u,a,f){let d=i[n]??t;return(c,m)=>{if(!m)return c;let x=parseFloat(m);if(x<l||x>r)return a.skipped++,c;if(u){let g=u(x,n,s);if(g===!1)return a.skipped++,c;if(typeof g=="string")return a.converted++,f&&console.log(`[pxtorem-css] ${n}: ${c} \u2192 ${g} (custom)`),g;if(typeof g=="number"){let R=W(g,e);return a.converted++,f&&console.log(`[pxtorem-css] ${n}: ${c} \u2192 ${R}${o} (custom)`),R+o}}let S=W(x/d,e);return a.converted++,f&&console.log(`[pxtorem-css] ${n}: ${c} \u2192 ${S}${o}`),S+o}}function k(t={}){let e={...q,...t},l=$(e.properties),r=!1,o,n,s={totalDeclarations:0,convertedDeclarations:0,skippedDeclarations:0,filesProcessed:[],details:new Map};return{postcssPlugin:"pxtorem-css",Once(i){n=i.source?.input?.file,e.includeFiles&&n?r=!D(n,e.includeFiles):e.excludeFiles&&n?r=D(n,e.excludeFiles):r=!1,!r&&(n&&!s.filesProcessed.includes(n)&&(s.filesProcessed.push(n),s.details.set(n,{converted:0,skipped:0})),o=b(e.baseSize)?e.baseSize(i.source.input):e.baseSize)},Declaration(i){if(r)return;if(s.totalDeclarations++,i.value.indexOf(e.fromUnit)===-1){s.skippedDeclarations++;return}if(!l(i.prop)){s.skippedDeclarations++;return}let u=i.parent?.type==="rule"?i.parent.selector:void 0;if(H(e.skipSelectors,u)){s.skippedDeclarations++;return}if(O(i,e.disableNextLineComment,e.disableLineComment,e.disableBlockComment,e.enableBlockComment)){s.skippedDeclarations++,e.verbose&&console.log(`[pxtorem-css] Skipped (disabled): ${i.prop}: ${i.value}`);return}let a=n?s.details.get(n)??{converted:0,skipped:0}:{converted:0,skipped:0},f=v(e.fromUnit),d=y(o,e.precision,e.minValue,e.maxValue,e.toUnit,i.prop,u??"",e.propertyBaseSize,e.convert,a,e.verbose),c=i.value.replace(f,d);n&&s.details.set(n,a),s.convertedDeclarations+=a.converted,s.skippedDeclarations+=a.skipped,c!==i.value&&(i.parent&&G(i.parent.nodes?.filter(m=>m.type==="decl")||[],i.prop,c)||(e.replaceOriginal?i.value=c:i.cloneAfter({value:c})))},AtRule(i){if(!r&&e.convertMediaQueries&&i.name==="media"){if(i.params.indexOf(e.fromUnit)===-1)return;let u=n?s.details.get(n)??{converted:0,skipped:0}:{converted:0,skipped:0},a=v(e.fromUnit),f=y(o,e.precision,e.minValue,e.maxValue,e.toUnit,"@media","",e.propertyBaseSize,e.convert,u,e.verbose);i.params=i.params.replace(a,f),n&&s.details.set(n,u)}},OnceExit(){e.onConversionComplete&&e.onConversionComplete(s),e.verbose&&(console.log(`
|
|
3
|
+
[pxtorem-css] Conversion Report:`),console.log(` Files: ${s.filesProcessed.length}`),console.log(` Total: ${s.totalDeclarations}`),console.log(` Converted: ${s.convertedDeclarations}`),console.log(` Skipped: ${s.skippedDeclarations}
|
|
4
|
+
`))}}}k.postcss=!0;var J=k;0&&(module.exports={pxtorem});
|
|
5
|
+
module.exports = module.exports.default;
|
package/dist/index.mjs
ADDED
|
@@ -0,0 +1,4 @@
|
|
|
1
|
+
function h(t){return new RegExp(`"[^"]+"|'[^']+'|url\\([^)]+\\)|var\\([^)]+\\)|(\\d*\\.?\\d+)${t}`,"g")}function y(t){return t.filter(e=>e.match(/^[^*!]+$/))}function N(t){return t.filter(e=>e.match(/^\*.+\*$/)).map(e=>e.slice(1,-1))}function P(t){return t.filter(e=>e.match(/^[^*!]+\*$/)).map(e=>e.slice(0,-1))}function F(t){return t.filter(e=>e.match(/^\*[^*]+$/)).map(e=>e.slice(1))}function w(t){return t.filter(e=>e.match(/^![^*].*$/)).map(e=>e.slice(1))}function M(t){return t.filter(e=>e.match(/^!\*.+\*$/)).map(e=>e.slice(2,-1))}function U(t){return t.filter(e=>e.match(/^!\*[^*]+$/)).map(e=>e.slice(2))}function V(t){return t.filter(e=>e.match(/^![^*]+\*$/)).map(e=>e.slice(1,-1))}var p={exact:y,contain:N,startWith:P,endWith:F,notExact:w,notContain:M,notStartWith:U,notEndWith:V};function S(t){let e=t.indexOf("*")>-1,a=e&&t.length===1,r={exact:p.exact(t),contain:p.contain(t),startWith:p.startWith(t),endWith:p.endWith(t),notExact:p.notExact(t),notContain:p.notContain(t),notStartWith:p.notStartWith(t),notEndWith:p.notEndWith(t)};return s=>a?!0:(e||r.exact.indexOf(s)>-1||r.contain.some(n=>s.indexOf(n)>-1)||r.startWith.some(n=>s.indexOf(n)===0)||r.endWith.some(n=>s.indexOf(n)===s.length-n.length))&&!(r.notExact.indexOf(s)>-1||r.notContain.some(n=>s.indexOf(n)>-1)||r.notStartWith.some(n=>s.indexOf(n)===0)||r.notEndWith.some(n=>s.indexOf(n)===s.length-n.length))}function R(t){return typeof t=="string"}function v(t){return typeof t=="function"}function b(t,e){return t.text.trim().toLowerCase().includes(e.toLowerCase())}function z(t){if(!t.parent)return;let e=t.parent.index(t);if(!(e<=0))return t.parent.nodes?.[e-1]}function $(t,e,a,r,s){let n=t.source;if(n?.input?.css){let l=n.input.css.split(`
|
|
2
|
+
`),f=(n.start?.line??1)-1;if(f>=0&&f<l.length){let d=l[f];if(d.includes("/*")&&d.toLowerCase().includes(a.toLowerCase()))return!0}}let o=z(t);if(o?.type==="comment"&&b(o,e))return!0;let i=t,u=!1;for(;i?.parent;){let l=i.parent,f=l.index(i);for(let d=f-1;d>=0;d--){let c=l.nodes?.[d];if(c?.type==="comment"){let m=c;if(b(m,s)){u=!1;break}if(b(m,r)){u=!0;break}}}if(u)return!0;i=l}return u}var B={baseSize:16,precision:5,skipSelectors:[],properties:["*"],replaceOriginal:!0,convertMediaQueries:!1,minValue:0,maxValue:1/0,excludeFiles:null,includeFiles:null,fromUnit:"px",toUnit:"rem",propertyBaseSize:{},disableNextLineComment:"pxtorem-disable-next-line",disableLineComment:"pxtorem-disable-line",disableBlockComment:"pxtorem-disable",enableBlockComment:"pxtorem-enable",convert:null,onConversionComplete:null,verbose:!1};function E(t,e){let a=Math.pow(10,e+1),r=Math.floor(t*a);return Math.round(r/10)*10/a}function A(t,e,a){return t.some(r=>r.prop===e&&r.value===a)}function L(t,e){return typeof e!="string"?!1:t.some(a=>typeof a=="string"?e.indexOf(a)!==-1:a.test(e))}function O(t,e){return!e||!t?!1:v(e)?e(t):R(e)?t.indexOf(e)!==-1:e instanceof RegExp?e.test(t):!1}function W(t,e,a,r,s,n,o,i,u,l,f){let d=i[n]??t;return(c,m)=>{if(!m)return c;let x=parseFloat(m);if(x<a||x>r)return l.skipped++,c;if(u){let g=u(x,n,o);if(g===!1)return l.skipped++,c;if(typeof g=="string")return l.converted++,f&&console.log(`[pxtorem-css] ${n}: ${c} \u2192 ${g} (custom)`),g;if(typeof g=="number"){let k=E(g,e);return l.converted++,f&&console.log(`[pxtorem-css] ${n}: ${c} \u2192 ${k}${s} (custom)`),k+s}}let C=E(x/d,e);return l.converted++,f&&console.log(`[pxtorem-css] ${n}: ${c} \u2192 ${C}${s}`),C+s}}function D(t={}){let e={...B,...t},a=S(e.properties),r=!1,s,n,o={totalDeclarations:0,convertedDeclarations:0,skippedDeclarations:0,filesProcessed:[],details:new Map};return{postcssPlugin:"pxtorem-css",Once(i){n=i.source?.input?.file,e.includeFiles&&n?r=!O(n,e.includeFiles):e.excludeFiles&&n?r=O(n,e.excludeFiles):r=!1,!r&&(n&&!o.filesProcessed.includes(n)&&(o.filesProcessed.push(n),o.details.set(n,{converted:0,skipped:0})),s=v(e.baseSize)?e.baseSize(i.source.input):e.baseSize)},Declaration(i){if(r)return;if(o.totalDeclarations++,i.value.indexOf(e.fromUnit)===-1){o.skippedDeclarations++;return}if(!a(i.prop)){o.skippedDeclarations++;return}let u=i.parent?.type==="rule"?i.parent.selector:void 0;if(L(e.skipSelectors,u)){o.skippedDeclarations++;return}if($(i,e.disableNextLineComment,e.disableLineComment,e.disableBlockComment,e.enableBlockComment)){o.skippedDeclarations++,e.verbose&&console.log(`[pxtorem-css] Skipped (disabled): ${i.prop}: ${i.value}`);return}let l=n?o.details.get(n)??{converted:0,skipped:0}:{converted:0,skipped:0},f=h(e.fromUnit),d=W(s,e.precision,e.minValue,e.maxValue,e.toUnit,i.prop,u??"",e.propertyBaseSize,e.convert,l,e.verbose),c=i.value.replace(f,d);n&&o.details.set(n,l),o.convertedDeclarations+=l.converted,o.skippedDeclarations+=l.skipped,c!==i.value&&(i.parent&&A(i.parent.nodes?.filter(m=>m.type==="decl")||[],i.prop,c)||(e.replaceOriginal?i.value=c:i.cloneAfter({value:c})))},AtRule(i){if(!r&&e.convertMediaQueries&&i.name==="media"){if(i.params.indexOf(e.fromUnit)===-1)return;let u=n?o.details.get(n)??{converted:0,skipped:0}:{converted:0,skipped:0},l=h(e.fromUnit),f=W(s,e.precision,e.minValue,e.maxValue,e.toUnit,"@media","",e.propertyBaseSize,e.convert,u,e.verbose);i.params=i.params.replace(l,f),n&&o.details.set(n,u)}},OnceExit(){e.onConversionComplete&&e.onConversionComplete(o),e.verbose&&(console.log(`
|
|
3
|
+
[pxtorem-css] Conversion Report:`),console.log(` Files: ${o.filesProcessed.length}`),console.log(` Total: ${o.totalDeclarations}`),console.log(` Converted: ${o.convertedDeclarations}`),console.log(` Skipped: ${o.skippedDeclarations}
|
|
4
|
+
`))}}}D.postcss=!0;var K=D;export{K as default,D as pxtorem};
|
package/package.json
CHANGED
|
@@ -1,31 +1,72 @@
|
|
|
1
|
-
{
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
}
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
"
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
1
|
+
{
|
|
2
|
+
"name": "pxtorem-css",
|
|
3
|
+
"version": "2.0.1",
|
|
4
|
+
"description": "A PostCSS plugin and CLI tool that converts px to rem/em/vw/vh units",
|
|
5
|
+
"main": "dist/index.js",
|
|
6
|
+
"module": "dist/index.mjs",
|
|
7
|
+
"types": "dist/index.d.ts",
|
|
8
|
+
"bin": {
|
|
9
|
+
"pxtorem": "./dist/cli.js"
|
|
10
|
+
},
|
|
11
|
+
"exports": {
|
|
12
|
+
".": {
|
|
13
|
+
"types": "./dist/index.d.ts",
|
|
14
|
+
"import": "./dist/index.mjs",
|
|
15
|
+
"require": "./dist/index.js",
|
|
16
|
+
"default": "./dist/index.js"
|
|
17
|
+
}
|
|
18
|
+
},
|
|
19
|
+
"files": [
|
|
20
|
+
"dist"
|
|
21
|
+
],
|
|
22
|
+
"scripts": {
|
|
23
|
+
"build": "tsup",
|
|
24
|
+
"dev": "tsup --watch",
|
|
25
|
+
"test": "vitest run",
|
|
26
|
+
"test:watch": "vitest",
|
|
27
|
+
"lint": "eslint .",
|
|
28
|
+
"lint:fix": "eslint . --fix",
|
|
29
|
+
"format": "prettier --write .",
|
|
30
|
+
"format:check": "prettier --check .",
|
|
31
|
+
"prepublishOnly": "npm run lint && npm run test && npm run build"
|
|
32
|
+
},
|
|
33
|
+
"keywords": [
|
|
34
|
+
"postcss",
|
|
35
|
+
"postcss-plugin",
|
|
36
|
+
"css",
|
|
37
|
+
"rem",
|
|
38
|
+
"em",
|
|
39
|
+
"vw",
|
|
40
|
+
"vh",
|
|
41
|
+
"pixel",
|
|
42
|
+
"px",
|
|
43
|
+
"pxtorem",
|
|
44
|
+
"converter",
|
|
45
|
+
"cli"
|
|
46
|
+
],
|
|
47
|
+
"author": "Rashed Iqbal",
|
|
48
|
+
"license": "MIT",
|
|
49
|
+
"repository": {
|
|
50
|
+
"type": "git",
|
|
51
|
+
"url": "https://github.com/iqbal-rashed/pxtorem-css"
|
|
52
|
+
},
|
|
53
|
+
"bugs": {
|
|
54
|
+
"url": "https://github.com/iqbal-rashed/pxtorem-css/issues"
|
|
55
|
+
},
|
|
56
|
+
"peerDependencies": {
|
|
57
|
+
"postcss": "^8.0.0"
|
|
58
|
+
},
|
|
59
|
+
"dependencies": {
|
|
60
|
+
"postcss": "^8.4.49"
|
|
61
|
+
},
|
|
62
|
+
"devDependencies": {
|
|
63
|
+
"@eslint/js": "^9.17.0",
|
|
64
|
+
"@types/node": "^22.10.2",
|
|
65
|
+
"eslint": "^9.17.0",
|
|
66
|
+
"prettier": "^3.4.2",
|
|
67
|
+
"tsup": "^8.3.5",
|
|
68
|
+
"typescript": "^5.7.2",
|
|
69
|
+
"typescript-eslint": "^8.18.2",
|
|
70
|
+
"vitest": "^2.1.8"
|
|
71
|
+
}
|
|
72
|
+
}
|
package/app.js
DELETED
|
@@ -1,156 +0,0 @@
|
|
|
1
|
-
const chalk = require("chalk");
|
|
2
|
-
const fs = require("fs");
|
|
3
|
-
const path = require("path");
|
|
4
|
-
|
|
5
|
-
function getListOfFile(dir, type, fileList) {
|
|
6
|
-
let files = fs.readdirSync(dir);
|
|
7
|
-
fileList = fileList || [];
|
|
8
|
-
files.forEach((f) => {
|
|
9
|
-
if (!f.startsWith(".")) {
|
|
10
|
-
let filePath = path.join(dir, f);
|
|
11
|
-
if (fs.statSync(filePath).isDirectory()) {
|
|
12
|
-
fileList = getListOfFile(filePath, type, fileList);
|
|
13
|
-
} else {
|
|
14
|
-
if (f.endsWith(type)) {
|
|
15
|
-
fileList.push(filePath);
|
|
16
|
-
}
|
|
17
|
-
}
|
|
18
|
-
}
|
|
19
|
-
});
|
|
20
|
-
return fileList;
|
|
21
|
-
}
|
|
22
|
-
|
|
23
|
-
function pxtorem(
|
|
24
|
-
{ size, dir, type, ignore, replace, output, include, exclude },
|
|
25
|
-
spinner
|
|
26
|
-
) {
|
|
27
|
-
let finalArr = [];
|
|
28
|
-
dir.forEach((v) => {
|
|
29
|
-
const finalDir = path.join(process.cwd(), v);
|
|
30
|
-
finalArr = finalArr.concat(getListOfFile(finalDir, type));
|
|
31
|
-
});
|
|
32
|
-
let finalPathArr = finalArr.map((v) => path.resolve(v)) || [];
|
|
33
|
-
|
|
34
|
-
if (include.length > 0) {
|
|
35
|
-
include.forEach((v) => {
|
|
36
|
-
if (finalPathArr.indexOf(v) === -1) {
|
|
37
|
-
finalPathArr.push(v);
|
|
38
|
-
}
|
|
39
|
-
});
|
|
40
|
-
}
|
|
41
|
-
|
|
42
|
-
if (exclude.length > 0) {
|
|
43
|
-
exclude.forEach((v) => {
|
|
44
|
-
if (finalPathArr.indexOf(v) !== -1) {
|
|
45
|
-
finalPathArr.splice(finalPathArr.indexOf(v), 1);
|
|
46
|
-
}
|
|
47
|
-
});
|
|
48
|
-
}
|
|
49
|
-
if (finalPathArr.length === 0) {
|
|
50
|
-
spinner.fail(chalk.red("At the end no css file found"));
|
|
51
|
-
process.exit(1);
|
|
52
|
-
}
|
|
53
|
-
finalPathArr.forEach((v) => {
|
|
54
|
-
try {
|
|
55
|
-
let fileName = path.basename(v);
|
|
56
|
-
if (replace) {
|
|
57
|
-
fileName = fileName.replace(
|
|
58
|
-
new RegExp(path.extname(v), "g"),
|
|
59
|
-
""
|
|
60
|
-
);
|
|
61
|
-
fileName = replace.replace(new RegExp("/name/", "g"), fileName);
|
|
62
|
-
|
|
63
|
-
fileName = fileName.replace(
|
|
64
|
-
new RegExp("/.ext", "g"),
|
|
65
|
-
path.extname(v)
|
|
66
|
-
);
|
|
67
|
-
console.log(fileName);
|
|
68
|
-
}
|
|
69
|
-
const readFileData = fs.readFileSync(v, "utf-8");
|
|
70
|
-
if (!readFileData) {
|
|
71
|
-
throw new Error("Css file empty");
|
|
72
|
-
}
|
|
73
|
-
if (!size) {
|
|
74
|
-
throw new Error("Html size not valid");
|
|
75
|
-
}
|
|
76
|
-
const changeData = changePxToRem(readFileData, size, ignore);
|
|
77
|
-
if (output) {
|
|
78
|
-
const destination = path.join(output, fileName);
|
|
79
|
-
|
|
80
|
-
fs.writeFileSync(destination, changeData, {
|
|
81
|
-
encoding: "utf-8",
|
|
82
|
-
flag: "w",
|
|
83
|
-
});
|
|
84
|
-
} else {
|
|
85
|
-
const destination = path.join(path.dirname(v), fileName);
|
|
86
|
-
fs.writeFileSync(destination, changeData, {
|
|
87
|
-
encoding: "utf-8",
|
|
88
|
-
flag: "w",
|
|
89
|
-
});
|
|
90
|
-
}
|
|
91
|
-
} catch (error) {
|
|
92
|
-
spinner.fail(chalk.red("Something went wrong", error.message));
|
|
93
|
-
}
|
|
94
|
-
});
|
|
95
|
-
}
|
|
96
|
-
|
|
97
|
-
function changePxToRem(data, size, ignore) {
|
|
98
|
-
const myRegex = /[-]?([a-z]*[-])?[a-z]*?\:.*?.*?px(;)?.*/g;
|
|
99
|
-
const finalRegex =
|
|
100
|
-
/[-]?([a-z]*[-])?[a-z]*?\:.*?([0-9]*[.])?[0-9]*?px+(\s+([0-9]*[.])?[0-9]*?px)*/g;
|
|
101
|
-
const attributeValueRegex =
|
|
102
|
-
/[-]?([a-z]*[-])?[a-z]*?\:.*?([0-9]*[.])?[0-9]*?px/g;
|
|
103
|
-
const valueRegex = /([0-9]*[.])?[0-9]*?px/g;
|
|
104
|
-
|
|
105
|
-
let result = data.match(finalRegex);
|
|
106
|
-
|
|
107
|
-
if (!result) {
|
|
108
|
-
console.log(chalk.red("Match result not found"));
|
|
109
|
-
process.exit(1);
|
|
110
|
-
}
|
|
111
|
-
let filterResult = [];
|
|
112
|
-
if (Array.isArray(ignore) && ignore.length > 0) {
|
|
113
|
-
filterResult = result.filter((res) => {
|
|
114
|
-
for (let i = 0; i < ignore.length; i++) {
|
|
115
|
-
const element = ignore[i];
|
|
116
|
-
if (res.includes(element + ":")) {
|
|
117
|
-
return res;
|
|
118
|
-
}
|
|
119
|
-
}
|
|
120
|
-
});
|
|
121
|
-
}
|
|
122
|
-
let finalResult = result.filter((v) => !filterResult.includes(v)) || [];
|
|
123
|
-
|
|
124
|
-
let valueResult = finalResult.map((v) => {
|
|
125
|
-
return v.match(valueRegex);
|
|
126
|
-
});
|
|
127
|
-
|
|
128
|
-
// result.forEach((v) => {
|
|
129
|
-
// const pxValue = v.slice(0, -2);
|
|
130
|
-
// const valueRegex = new RegExp(`${pxValue}px`, "g");
|
|
131
|
-
// finalData = finalData.replace(
|
|
132
|
-
// valueRegex,
|
|
133
|
-
// `${pxValue / parseFloat(size)}rem`
|
|
134
|
-
// );
|
|
135
|
-
// });
|
|
136
|
-
let finalData = data;
|
|
137
|
-
for (let i = 0; i < finalResult.length; i++) {
|
|
138
|
-
const element = finalResult[i];
|
|
139
|
-
const valueArr = valueResult[i];
|
|
140
|
-
let replaceElement = element;
|
|
141
|
-
for (let j = 0; j < valueArr.length; j++) {
|
|
142
|
-
const value = valueArr[j];
|
|
143
|
-
const pxValue = value.slice(0, -2);
|
|
144
|
-
replaceElement = replaceElement.replace(
|
|
145
|
-
value,
|
|
146
|
-
`${parseFloat(pxValue) / parseFloat(size)}rem`
|
|
147
|
-
);
|
|
148
|
-
}
|
|
149
|
-
|
|
150
|
-
// console.log(replaceElement);
|
|
151
|
-
finalData = finalData.replace(element, replaceElement);
|
|
152
|
-
}
|
|
153
|
-
return finalData;
|
|
154
|
-
}
|
|
155
|
-
|
|
156
|
-
module.exports = pxtorem;
|
package/bin/pxtorem
DELETED
|
@@ -1,199 +0,0 @@
|
|
|
1
|
-
#!/usr/bin/env node
|
|
2
|
-
|
|
3
|
-
const fs = require("fs");
|
|
4
|
-
const { program, Option } = require("commander");
|
|
5
|
-
const path = require("path");
|
|
6
|
-
const chalk = require("chalk");
|
|
7
|
-
const pxtorem = require("../app");
|
|
8
|
-
const ora = require("ora");
|
|
9
|
-
|
|
10
|
-
const spinner = ora({
|
|
11
|
-
text: chalk.yellow("Converting css px to rem..."),
|
|
12
|
-
color: "yellow",
|
|
13
|
-
});
|
|
14
|
-
|
|
15
|
-
const processDir = process.cwd();
|
|
16
|
-
|
|
17
|
-
program
|
|
18
|
-
.addOption(
|
|
19
|
-
new Option("-init,--init [type]", "Init pxtorem options json").preset(
|
|
20
|
-
"pxtorem.config.json"
|
|
21
|
-
)
|
|
22
|
-
)
|
|
23
|
-
.addOption(
|
|
24
|
-
new Option("-s, --size [type]", "Select html size")
|
|
25
|
-
.preset("16")
|
|
26
|
-
.default("16")
|
|
27
|
-
)
|
|
28
|
-
.addOption(
|
|
29
|
-
new Option("-d, --dir [type...]", "Select css directory")
|
|
30
|
-
.preset("/")
|
|
31
|
-
.default(["/"])
|
|
32
|
-
)
|
|
33
|
-
.addOption(
|
|
34
|
-
new Option("-t, --type [type]", "Select css ext type example: .scss")
|
|
35
|
-
.preset(".css")
|
|
36
|
-
.default(".css")
|
|
37
|
-
)
|
|
38
|
-
.addOption(
|
|
39
|
-
new Option("-i, --ignore [type...]", "Ignore css attribute")
|
|
40
|
-
.preset([])
|
|
41
|
-
.default([])
|
|
42
|
-
)
|
|
43
|
-
.addOption(
|
|
44
|
-
new Option("-r, --replace [type]", "For replace file name")
|
|
45
|
-
.preset(false)
|
|
46
|
-
.default(false)
|
|
47
|
-
)
|
|
48
|
-
.addOption(
|
|
49
|
-
new Option("-o, --output [type]", "Output directory")
|
|
50
|
-
.preset("")
|
|
51
|
-
.default("")
|
|
52
|
-
)
|
|
53
|
-
.addOption(
|
|
54
|
-
new Option("-in, --include [type...]", "For include css file path")
|
|
55
|
-
.preset([])
|
|
56
|
-
.default([])
|
|
57
|
-
)
|
|
58
|
-
.addOption(
|
|
59
|
-
new Option("-ex, --exclude [type...]", "For exclue css file path")
|
|
60
|
-
.preset([])
|
|
61
|
-
.default([])
|
|
62
|
-
)
|
|
63
|
-
.addOption(
|
|
64
|
-
new Option("-c, --config [type]", "For json config file")
|
|
65
|
-
.preset("")
|
|
66
|
-
.default("")
|
|
67
|
-
)
|
|
68
|
-
.parse();
|
|
69
|
-
|
|
70
|
-
let options = program.opts();
|
|
71
|
-
|
|
72
|
-
if (options.init) {
|
|
73
|
-
initFunction(options.init);
|
|
74
|
-
}
|
|
75
|
-
spinner.start();
|
|
76
|
-
|
|
77
|
-
let configObj;
|
|
78
|
-
const currentDir = fs.readdirSync(processDir);
|
|
79
|
-
|
|
80
|
-
if (options.config && options.config.endsWith(".json")) {
|
|
81
|
-
if (currentDir.indexOf(options.config) !== -1) {
|
|
82
|
-
configObj = readConfigFile(options.config);
|
|
83
|
-
}
|
|
84
|
-
} else {
|
|
85
|
-
if (currentDir.indexOf("pxtorem.json") !== -1) {
|
|
86
|
-
configObj = readConfigFile("pxtorem.json");
|
|
87
|
-
}
|
|
88
|
-
if (currentDir.indexOf("pxtorem.config.json") !== -1) {
|
|
89
|
-
configObj = readConfigFile("pxtorem.config.json");
|
|
90
|
-
}
|
|
91
|
-
}
|
|
92
|
-
|
|
93
|
-
function readConfigFile(fileName) {
|
|
94
|
-
try {
|
|
95
|
-
const configFilePath = path.join(processDir, fileName);
|
|
96
|
-
const configfile = fs.readFileSync(configFilePath, "utf-8");
|
|
97
|
-
const toObj = JSON.parse(`${configfile}`);
|
|
98
|
-
if (typeof toObj === "object") {
|
|
99
|
-
return toObj;
|
|
100
|
-
} else {
|
|
101
|
-
return false;
|
|
102
|
-
}
|
|
103
|
-
} catch (error) {
|
|
104
|
-
return false;
|
|
105
|
-
}
|
|
106
|
-
}
|
|
107
|
-
|
|
108
|
-
for (let key in options) {
|
|
109
|
-
if (configObj && configObj.hasOwnProperty(key)) {
|
|
110
|
-
const element = options[key];
|
|
111
|
-
options[key] = configObj[key];
|
|
112
|
-
// if (Array.isArray(element)) {
|
|
113
|
-
// let concatArr = element.concat(configObj[key]);
|
|
114
|
-
// let finalArr = [];
|
|
115
|
-
// concatArr.forEach((v) => {
|
|
116
|
-
// if (finalArr.length === 0) {
|
|
117
|
-
// finalArr.push(v);
|
|
118
|
-
// } else if (finalArr.indexOf(v) === -1) {
|
|
119
|
-
// finalArr.push(v);
|
|
120
|
-
// }
|
|
121
|
-
// });
|
|
122
|
-
// options[key] = finalArr;
|
|
123
|
-
// } else {
|
|
124
|
-
// options[key] = configObj[key];
|
|
125
|
-
// }
|
|
126
|
-
}
|
|
127
|
-
}
|
|
128
|
-
|
|
129
|
-
if (options.replace) {
|
|
130
|
-
const isMatch = options.replace.match(/.*\/name\/.*\/.ext/g);
|
|
131
|
-
|
|
132
|
-
if (!isMatch) {
|
|
133
|
-
spinner.fail(chalk.red("Replace name incorrect please fix this"));
|
|
134
|
-
process.exit(1);
|
|
135
|
-
}
|
|
136
|
-
}
|
|
137
|
-
|
|
138
|
-
options.dir.forEach((v) => {
|
|
139
|
-
const dirPath = path.join(processDir, v);
|
|
140
|
-
if (!fs.existsSync(dirPath)) {
|
|
141
|
-
spinner.fail(chalk.red("Css directories not exist!"));
|
|
142
|
-
process.exit(1);
|
|
143
|
-
}
|
|
144
|
-
});
|
|
145
|
-
|
|
146
|
-
if (options.include.length > 0) {
|
|
147
|
-
options.include.forEach((v) => checkFileExist(v, "Include"));
|
|
148
|
-
options.include = options.include.map((v) => path.resolve(v));
|
|
149
|
-
}
|
|
150
|
-
if (options.exclude.length > 0) {
|
|
151
|
-
options.exclude.forEach((v) => checkFileExist(v, "Exclude"));
|
|
152
|
-
options.exclude = options.exclude.map((v) => path.resolve(v));
|
|
153
|
-
}
|
|
154
|
-
|
|
155
|
-
function checkFileExist(filePath, type) {
|
|
156
|
-
filePath = path.join(processDir, filePath);
|
|
157
|
-
if (!fs.existsSync(filePath)) {
|
|
158
|
-
console.log(chalk.red(`${type} css file not exist`));
|
|
159
|
-
process.exit(1);
|
|
160
|
-
}
|
|
161
|
-
}
|
|
162
|
-
|
|
163
|
-
function checkOutputDir(dir) {
|
|
164
|
-
if (!fs.existsSync(path.join(processDir, dir))) {
|
|
165
|
-
console.log(chalk.red(`Output directory not exist`));
|
|
166
|
-
process.exit(1);
|
|
167
|
-
}
|
|
168
|
-
}
|
|
169
|
-
|
|
170
|
-
if (options.output) {
|
|
171
|
-
checkOutputDir(options.output);
|
|
172
|
-
options.output = path.resolve(options.output);
|
|
173
|
-
}
|
|
174
|
-
|
|
175
|
-
if (options.size && isNaN(options.size)) {
|
|
176
|
-
console.log(chalk.red(`Html size not valid`));
|
|
177
|
-
process.exit(1);
|
|
178
|
-
}
|
|
179
|
-
|
|
180
|
-
function initFunction(name) {
|
|
181
|
-
const initData = `{
|
|
182
|
-
"size": "16",
|
|
183
|
-
"dir": ["public/css"],
|
|
184
|
-
"type": ".css",
|
|
185
|
-
"ignore": ["margin", "padding", "box-shadow"],
|
|
186
|
-
"replace": "{your custom word}/name/{your custom word}/.ext",
|
|
187
|
-
"output": "",
|
|
188
|
-
"include": [],
|
|
189
|
-
"exclude": []
|
|
190
|
-
}`;
|
|
191
|
-
const filePath = path.join(processDir, name);
|
|
192
|
-
fs.writeFileSync(filePath, initData, { encoding: "utf-8", flag: "w" });
|
|
193
|
-
spinner.succeed(chalk.green(`${name} created!`));
|
|
194
|
-
process.exit(1);
|
|
195
|
-
}
|
|
196
|
-
|
|
197
|
-
pxtorem(options, spinner);
|
|
198
|
-
|
|
199
|
-
spinner.succeed(chalk.green("Convert completed. Enjoy (:"));
|