@youthfulhps/prettier-plugin-tailwindcss-normalizer 0.3.9 → 0.4.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/README.md +95 -7
- package/dist/index.d.ts +7 -3
- package/dist/index.js +36 -35
- package/dist/normalizer.d.ts +2 -0
- package/dist/normalizer.js +16 -1
- package/dist/types.d.ts +3 -0
- package/dist/utils/spacing-generator.d.ts +2 -0
- package/dist/utils/spacing-generator.js +116 -0
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -45,7 +45,7 @@ Add the plugin to your Prettier configuration:
|
|
|
45
45
|
|
|
46
46
|
```javascript
|
|
47
47
|
module.exports = {
|
|
48
|
-
plugins: [
|
|
48
|
+
plugins: ["@youthfulhps/prettier-plugin-tailwindcss-normalizer"],
|
|
49
49
|
};
|
|
50
50
|
```
|
|
51
51
|
|
|
@@ -59,15 +59,39 @@ npx prettier --write .
|
|
|
59
59
|
npx prettier --write src/**/*.{tsx,jsx,html,vue}
|
|
60
60
|
```
|
|
61
61
|
|
|
62
|
+
## 🔗 Using with Other Prettier Tailwind Plugins
|
|
63
|
+
|
|
64
|
+
To use this plugin alongside other prettier tailwind plugins, you need to install and configure `prettier-plugin-merge`.
|
|
65
|
+
|
|
66
|
+
### Installation
|
|
67
|
+
|
|
68
|
+
```bash
|
|
69
|
+
npm install --save-dev prettier-plugin-merge
|
|
70
|
+
```
|
|
71
|
+
|
|
72
|
+
### Configuration
|
|
73
|
+
|
|
74
|
+
In your `.prettierrc.js` file, add `prettier-plugin-merge` as the last item in the plugins array:
|
|
75
|
+
|
|
76
|
+
```javascript
|
|
77
|
+
module.exports = {
|
|
78
|
+
plugins: [
|
|
79
|
+
"@youthfulhps/prettier-plugin-tailwindcss-normalizer",
|
|
80
|
+
"prettier-plugin-tailwindcss",
|
|
81
|
+
"prettier-plugin-merge",
|
|
82
|
+
],
|
|
83
|
+
};
|
|
84
|
+
```
|
|
85
|
+
|
|
86
|
+
> **Note**: `prettier-plugin-merge` is a plugin that enables multiple prettier plugins to work together. When using with other tailwind-related plugins, it should always be placed last in the plugins array.
|
|
87
|
+
|
|
62
88
|
## 🎯 Examples
|
|
63
89
|
|
|
64
90
|
### Before
|
|
65
91
|
|
|
66
92
|
```jsx
|
|
67
93
|
<div className="p-[16px] m-[8px] bg-blue-500">
|
|
68
|
-
<span className="px-[24px] py-[12px] rounded-[6px]">
|
|
69
|
-
Button
|
|
70
|
-
</span>
|
|
94
|
+
<span className="px-[24px] py-[12px] rounded-[6px]">Button</span>
|
|
71
95
|
</div>
|
|
72
96
|
```
|
|
73
97
|
|
|
@@ -75,9 +99,7 @@ npx prettier --write src/**/*.{tsx,jsx,html,vue}
|
|
|
75
99
|
|
|
76
100
|
```jsx
|
|
77
101
|
<div className="p-4 m-2 bg-blue-500">
|
|
78
|
-
<span className="px-6 py-3 rounded-md">
|
|
79
|
-
Button
|
|
80
|
-
</span>
|
|
102
|
+
<span className="px-6 py-3 rounded-md">Button</span>
|
|
81
103
|
</div>
|
|
82
104
|
```
|
|
83
105
|
|
|
@@ -131,8 +153,74 @@ The plugin is designed to be safe and only transforms class-related attributes:
|
|
|
131
153
|
|
|
132
154
|
## 🔧 Configuration
|
|
133
155
|
|
|
156
|
+
### Basic Configuration
|
|
157
|
+
|
|
134
158
|
The plugin works out of the box with default settings. No additional configuration is required.
|
|
135
159
|
|
|
160
|
+
### Custom Spacing Unit
|
|
161
|
+
|
|
162
|
+
If you've customized your Tailwind CSS spacing scale, you can configure the plugin to match your custom spacing unit.
|
|
163
|
+
|
|
164
|
+
By default, Tailwind uses **4px** as the base spacing unit (e.g., `p-1` = 4px, `p-2` = 8px). If you've changed this in your Tailwind configuration, you should update the `customSpacingUnit` option.
|
|
165
|
+
|
|
166
|
+
**`.prettierrc.js`**
|
|
167
|
+
|
|
168
|
+
```javascript
|
|
169
|
+
module.exports = {
|
|
170
|
+
plugins: ["@youthfulhps/prettier-plugin-tailwindcss-normalizer"],
|
|
171
|
+
customSpacingUnit: 8, // Change to match your Tailwind spacing scale
|
|
172
|
+
};
|
|
173
|
+
```
|
|
174
|
+
|
|
175
|
+
**`tailwind.config.js` (Example with 8px base unit)**
|
|
176
|
+
|
|
177
|
+
```javascript
|
|
178
|
+
module.exports = {
|
|
179
|
+
theme: {
|
|
180
|
+
extend: {
|
|
181
|
+
spacing: {
|
|
182
|
+
1: "8px", // 8px * 1
|
|
183
|
+
2: "16px", // 8px * 2
|
|
184
|
+
3: "24px", // 8px * 3
|
|
185
|
+
4: "32px", // 8px * 4
|
|
186
|
+
// ... etc
|
|
187
|
+
},
|
|
188
|
+
},
|
|
189
|
+
},
|
|
190
|
+
};
|
|
191
|
+
```
|
|
192
|
+
|
|
193
|
+
**Tailwind CSS v4 (`global.css` or similar)**
|
|
194
|
+
|
|
195
|
+
```css
|
|
196
|
+
@theme {
|
|
197
|
+
--spacing: 1px;
|
|
198
|
+
/* ... etc */
|
|
199
|
+
}
|
|
200
|
+
```
|
|
201
|
+
|
|
202
|
+
**Example with `customSpacingUnit: 8`**
|
|
203
|
+
|
|
204
|
+
```jsx
|
|
205
|
+
// Before
|
|
206
|
+
<div className="p-[8px] m-[16px] gap-[24px]">Content</div>
|
|
207
|
+
|
|
208
|
+
// After (with customSpacingUnit: 8)
|
|
209
|
+
<div className="p-1 m-2 gap-3">Content</div>
|
|
210
|
+
```
|
|
211
|
+
|
|
212
|
+
**Example with default `customSpacingUnit: 4`**
|
|
213
|
+
|
|
214
|
+
```jsx
|
|
215
|
+
// Before
|
|
216
|
+
<div className="p-[4px] m-[8px] gap-[12px]">Content</div>
|
|
217
|
+
|
|
218
|
+
// After (with customSpacingUnit: 4)
|
|
219
|
+
<div className="p-1 m-2 gap-3">Content</div>
|
|
220
|
+
```
|
|
221
|
+
|
|
222
|
+
See the [examples/custom-spacing](./examples/custom-spacing) directory for a complete working example.
|
|
223
|
+
|
|
136
224
|
> **Note**: This plugin is optimized for Prettier v3+ and takes advantage of the new plugin architecture. If you're using Prettier v2, please upgrade to v3 or use an alternative solution.
|
|
137
225
|
|
|
138
226
|
## 🧪 Testing
|
package/dist/index.d.ts
CHANGED
|
@@ -1,3 +1,7 @@
|
|
|
1
|
-
import {
|
|
2
|
-
declare const
|
|
3
|
-
|
|
1
|
+
import { CompatParser } from "./types/prettier-compat";
|
|
2
|
+
declare const parsers: Record<string, CompatParser>, languages: {
|
|
3
|
+
name: string;
|
|
4
|
+
parsers: string[];
|
|
5
|
+
extensions: string[];
|
|
6
|
+
}[] | undefined, options: Record<string, any> | undefined;
|
|
7
|
+
export { parsers, languages, options };
|
package/dist/index.js
CHANGED
|
@@ -1,13 +1,18 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.options = exports.languages = exports.parsers = void 0;
|
|
3
4
|
const ast_transformer_1 = require("./ast-transformer");
|
|
4
5
|
const version_utils_1 = require("./utils/version-utils");
|
|
6
|
+
const normalizer_1 = require("./normalizer");
|
|
5
7
|
function createParser(parserName, fileType) {
|
|
6
8
|
const baseParser = (0, version_utils_1.safeLoadParser)(parserName, fileType);
|
|
7
9
|
return {
|
|
8
10
|
...baseParser,
|
|
9
|
-
astFormat: parserName,
|
|
10
11
|
preprocess: (text, options) => {
|
|
12
|
+
const pluginOptions = {
|
|
13
|
+
customSpacingUnit: options.customSpacingUnit,
|
|
14
|
+
};
|
|
15
|
+
(0, normalizer_1.setPluginOptions)(pluginOptions);
|
|
11
16
|
return (0, ast_transformer_1.transformByFileType)(text, options.filepath || `file.${fileType}`);
|
|
12
17
|
},
|
|
13
18
|
};
|
|
@@ -36,46 +41,42 @@ const plugin = {
|
|
|
36
41
|
},
|
|
37
42
|
{
|
|
38
43
|
name: "TypeScript",
|
|
39
|
-
parsers: ["
|
|
44
|
+
parsers: ["typescript"],
|
|
40
45
|
extensions: [".ts", ".tsx"],
|
|
41
46
|
},
|
|
42
47
|
],
|
|
43
48
|
parsers: {
|
|
44
|
-
html:
|
|
45
|
-
|
|
46
|
-
|
|
49
|
+
html: {
|
|
50
|
+
...createParser("html", "html"),
|
|
51
|
+
astFormat: "html",
|
|
52
|
+
},
|
|
53
|
+
vue: {
|
|
54
|
+
...createParser("html", "vue"),
|
|
55
|
+
astFormat: "vue",
|
|
56
|
+
},
|
|
57
|
+
angular: {
|
|
58
|
+
...createParser("angular", "html"),
|
|
59
|
+
astFormat: "html",
|
|
60
|
+
},
|
|
47
61
|
babel: {
|
|
48
|
-
...createParser("babel", "
|
|
49
|
-
|
|
50
|
-
const filepath = options.filepath || "";
|
|
51
|
-
if (filepath.endsWith(".jsx") || filepath.endsWith(".tsx")) {
|
|
52
|
-
const transformedText = (0, ast_transformer_1.transformByFileType)(text, filepath);
|
|
53
|
-
const baseParser = (0, version_utils_1.safeLoadParser)("babel");
|
|
54
|
-
return baseParser.parse
|
|
55
|
-
? baseParser.parse(transformedText, options)
|
|
56
|
-
: text;
|
|
57
|
-
}
|
|
58
|
-
const baseParser = (0, version_utils_1.safeLoadParser)("babel");
|
|
59
|
-
return baseParser.parse ? baseParser.parse(text, options) : text;
|
|
60
|
-
},
|
|
62
|
+
...createParser("babel", "babel"),
|
|
63
|
+
astFormat: "estree",
|
|
61
64
|
},
|
|
62
|
-
|
|
63
|
-
...createParser("
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
const baseParser = (0, version_utils_1.safeLoadParser)("babel", "babel-ts");
|
|
74
|
-
return baseParser.parse ? baseParser.parse(text, options) : text;
|
|
75
|
-
},
|
|
65
|
+
typescript: {
|
|
66
|
+
...createParser("typescript", "typescript"),
|
|
67
|
+
astFormat: "estree",
|
|
68
|
+
},
|
|
69
|
+
},
|
|
70
|
+
options: {
|
|
71
|
+
customSpacingUnit: {
|
|
72
|
+
type: "int",
|
|
73
|
+
category: "Tailwind",
|
|
74
|
+
default: 4,
|
|
75
|
+
description: "Custom spacing unit in pixels (default: 4). Tailwind uses 4px as the base unit (e.g., p-1 = 4px). Change this if you've customized Tailwind's spacing scale.",
|
|
76
76
|
},
|
|
77
77
|
},
|
|
78
|
-
printers: {},
|
|
79
78
|
};
|
|
80
|
-
|
|
81
|
-
exports.
|
|
79
|
+
const { parsers, languages, options } = plugin;
|
|
80
|
+
exports.parsers = parsers;
|
|
81
|
+
exports.languages = languages;
|
|
82
|
+
exports.options = options;
|
package/dist/normalizer.d.ts
CHANGED
|
@@ -1,3 +1,5 @@
|
|
|
1
|
+
import { PluginOptions } from "./types";
|
|
2
|
+
export declare function setPluginOptions(options?: PluginOptions): void;
|
|
1
3
|
export declare function normalizeClassAttribute(content: string): string;
|
|
2
4
|
export declare function normalizeClassNames(classNames: string): string;
|
|
3
5
|
export declare function normalizeClassName(className: string): string;
|
package/dist/normalizer.js
CHANGED
|
@@ -1,9 +1,24 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.setPluginOptions = setPluginOptions;
|
|
3
4
|
exports.normalizeClassAttribute = normalizeClassAttribute;
|
|
4
5
|
exports.normalizeClassNames = normalizeClassNames;
|
|
5
6
|
exports.normalizeClassName = normalizeClassName;
|
|
6
7
|
const mappings_1 = require("./mappings");
|
|
8
|
+
const spacing_generator_1 = require("./utils/spacing-generator");
|
|
9
|
+
let currentMappings = mappings_1.TAILWIND_MAPPINGS;
|
|
10
|
+
function setPluginOptions(options = {}) {
|
|
11
|
+
if (options.customSpacingUnit && options.customSpacingUnit !== 4) {
|
|
12
|
+
const customSpacingMappings = (0, spacing_generator_1.generateSpacingMappings)(options.customSpacingUnit);
|
|
13
|
+
currentMappings = {
|
|
14
|
+
...mappings_1.TAILWIND_MAPPINGS,
|
|
15
|
+
...customSpacingMappings,
|
|
16
|
+
};
|
|
17
|
+
}
|
|
18
|
+
else {
|
|
19
|
+
currentMappings = mappings_1.TAILWIND_MAPPINGS;
|
|
20
|
+
}
|
|
21
|
+
}
|
|
7
22
|
function normalizeClassAttribute(content) {
|
|
8
23
|
let result = content;
|
|
9
24
|
const classAttributeRegex = /class\s*=\s*["']([^"']*?)["']/g;
|
|
@@ -115,7 +130,7 @@ function normalizeClassName(className) {
|
|
|
115
130
|
return className;
|
|
116
131
|
}
|
|
117
132
|
function findStandardMapping(prefix, value) {
|
|
118
|
-
const mappings =
|
|
133
|
+
const mappings = currentMappings[prefix];
|
|
119
134
|
if (!mappings) {
|
|
120
135
|
return null;
|
|
121
136
|
}
|
package/dist/types.d.ts
CHANGED
|
@@ -0,0 +1,116 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.generateSpacingMappings = generateSpacingMappings;
|
|
4
|
+
function generateSpacingMappings(customUnit = 4) {
|
|
5
|
+
const spacingPrefixes = [
|
|
6
|
+
"p",
|
|
7
|
+
"px",
|
|
8
|
+
"py",
|
|
9
|
+
"pt",
|
|
10
|
+
"pr",
|
|
11
|
+
"pb",
|
|
12
|
+
"pl",
|
|
13
|
+
"ps",
|
|
14
|
+
"pe",
|
|
15
|
+
"m",
|
|
16
|
+
"mx",
|
|
17
|
+
"my",
|
|
18
|
+
"mt",
|
|
19
|
+
"mr",
|
|
20
|
+
"mb",
|
|
21
|
+
"ml",
|
|
22
|
+
"ms",
|
|
23
|
+
"me",
|
|
24
|
+
"gap",
|
|
25
|
+
"gap-x",
|
|
26
|
+
"gap-y",
|
|
27
|
+
"space-x",
|
|
28
|
+
"space-y",
|
|
29
|
+
"w",
|
|
30
|
+
"h",
|
|
31
|
+
"size",
|
|
32
|
+
"min-w",
|
|
33
|
+
"max-w",
|
|
34
|
+
"min-h",
|
|
35
|
+
"max-h",
|
|
36
|
+
"top",
|
|
37
|
+
"right",
|
|
38
|
+
"bottom",
|
|
39
|
+
"left",
|
|
40
|
+
"scroll-m",
|
|
41
|
+
"scroll-p",
|
|
42
|
+
];
|
|
43
|
+
const standardScales = [
|
|
44
|
+
{ scale: "0", multiplier: 0 },
|
|
45
|
+
{ scale: "0.5", multiplier: 0.5 },
|
|
46
|
+
{ scale: "1", multiplier: 1 },
|
|
47
|
+
{ scale: "1.5", multiplier: 1.5 },
|
|
48
|
+
{ scale: "2", multiplier: 2 },
|
|
49
|
+
{ scale: "2.5", multiplier: 2.5 },
|
|
50
|
+
{ scale: "3", multiplier: 3 },
|
|
51
|
+
{ scale: "3.5", multiplier: 3.5 },
|
|
52
|
+
{ scale: "4", multiplier: 4 },
|
|
53
|
+
{ scale: "5", multiplier: 5 },
|
|
54
|
+
{ scale: "6", multiplier: 6 },
|
|
55
|
+
{ scale: "7", multiplier: 7 },
|
|
56
|
+
{ scale: "8", multiplier: 8 },
|
|
57
|
+
{ scale: "9", multiplier: 9 },
|
|
58
|
+
{ scale: "10", multiplier: 10 },
|
|
59
|
+
{ scale: "11", multiplier: 11 },
|
|
60
|
+
{ scale: "12", multiplier: 12 },
|
|
61
|
+
{ scale: "14", multiplier: 14 },
|
|
62
|
+
{ scale: "16", multiplier: 16 },
|
|
63
|
+
{ scale: "20", multiplier: 20 },
|
|
64
|
+
{ scale: "24", multiplier: 24 },
|
|
65
|
+
{ scale: "28", multiplier: 28 },
|
|
66
|
+
{ scale: "32", multiplier: 32 },
|
|
67
|
+
{ scale: "36", multiplier: 36 },
|
|
68
|
+
{ scale: "40", multiplier: 40 },
|
|
69
|
+
{ scale: "44", multiplier: 44 },
|
|
70
|
+
{ scale: "48", multiplier: 48 },
|
|
71
|
+
{ scale: "52", multiplier: 52 },
|
|
72
|
+
{ scale: "56", multiplier: 56 },
|
|
73
|
+
{ scale: "60", multiplier: 60 },
|
|
74
|
+
{ scale: "64", multiplier: 64 },
|
|
75
|
+
{ scale: "72", multiplier: 72 },
|
|
76
|
+
{ scale: "80", multiplier: 80 },
|
|
77
|
+
{ scale: "96", multiplier: 96 },
|
|
78
|
+
];
|
|
79
|
+
const fractionalPrefixes = ["py", "my"];
|
|
80
|
+
const result = {};
|
|
81
|
+
spacingPrefixes.forEach((prefix) => {
|
|
82
|
+
const mapping = {};
|
|
83
|
+
const supportsFractional = fractionalPrefixes.includes(prefix);
|
|
84
|
+
const supportsNegative = [
|
|
85
|
+
"m",
|
|
86
|
+
"mx",
|
|
87
|
+
"my",
|
|
88
|
+
"mt",
|
|
89
|
+
"mr",
|
|
90
|
+
"mb",
|
|
91
|
+
"ml",
|
|
92
|
+
"ms",
|
|
93
|
+
"me",
|
|
94
|
+
"top",
|
|
95
|
+
"right",
|
|
96
|
+
"bottom",
|
|
97
|
+
"left",
|
|
98
|
+
].includes(prefix);
|
|
99
|
+
standardScales.forEach(({ scale, multiplier }) => {
|
|
100
|
+
if (!supportsFractional && scale.includes(".")) {
|
|
101
|
+
return;
|
|
102
|
+
}
|
|
103
|
+
const pixelValue = multiplier * customUnit;
|
|
104
|
+
const pixelKey = `${pixelValue}px`;
|
|
105
|
+
mapping[pixelKey] = `${prefix}-${scale}`;
|
|
106
|
+
if (supportsNegative && scale !== "0") {
|
|
107
|
+
const negativePixelValue = -pixelValue;
|
|
108
|
+
const negativePixelKey = `${negativePixelValue}px`;
|
|
109
|
+
mapping[negativePixelKey] = `-${prefix}-${scale}`;
|
|
110
|
+
}
|
|
111
|
+
});
|
|
112
|
+
mapping["1px"] = `${prefix}-px`;
|
|
113
|
+
result[prefix] = mapping;
|
|
114
|
+
});
|
|
115
|
+
return result;
|
|
116
|
+
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@youthfulhps/prettier-plugin-tailwindcss-normalizer",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.4.1",
|
|
4
4
|
"description": "A Prettier plugin that normalizes Tailwind CSS arbitrary values into standard utility classes.",
|
|
5
5
|
"main": "dist/index.js",
|
|
6
6
|
"types": "dist/index.d.ts",
|