@youthfulhps/prettier-plugin-tailwindcss-normalizer 0.3.4 → 0.3.7
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 +202 -1
- package/dist/index.js +30 -26
- package/dist/utils/version-utils.d.ts +0 -2
- package/dist/utils/version-utils.js +5 -43
- package/package.json +3 -3
package/README.md
CHANGED
|
@@ -1,3 +1,204 @@
|
|
|
1
1
|
# prettier-plugin-tailwindcss-normalizer
|
|
2
2
|
|
|
3
|
-
|
|
3
|
+
[](https://badge.fury.io/js/%40youthfulhps%2Fprettier-plugin-tailwindcss-normalizer)
|
|
4
|
+
[](https://opensource.org/licenses/MIT)
|
|
5
|
+
|
|
6
|
+
A Prettier plugin that automatically normalizes Tailwind CSS arbitrary values into standard utility classes, helping maintain consistent and optimized CSS across your project.
|
|
7
|
+
|
|
8
|
+
> **⚠️ Important**: This plugin requires **Prettier v3.0.0 or higher**. It does not support Prettier v2.
|
|
9
|
+
|
|
10
|
+
## ✨ Features
|
|
11
|
+
|
|
12
|
+
- **Automatic Normalization**: Converts arbitrary values like `p-[4px]` to standard classes like `p-1`
|
|
13
|
+
- **Multi-Framework Support**: Works with HTML, React/JSX, Vue.js, and Angular
|
|
14
|
+
- **Safe Transformation**: Only transforms class attributes, leaving comments, text, and other attributes untouched
|
|
15
|
+
- **Comprehensive Mapping**: Supports padding, margin, sizing, typography, borders, shadows, and more
|
|
16
|
+
- **Prettier v3+ Only**: Built specifically for Prettier v3.0.0 and above (v2 not supported)
|
|
17
|
+
|
|
18
|
+
## 🚀 Installation
|
|
19
|
+
|
|
20
|
+
**Prerequisites**: Make sure you have Prettier v3.0.0 or higher installed.
|
|
21
|
+
|
|
22
|
+
```bash
|
|
23
|
+
# Install Prettier v3+ (if not already installed)
|
|
24
|
+
npm install --save-dev prettier@^3.0.0
|
|
25
|
+
|
|
26
|
+
# Install the plugin
|
|
27
|
+
npm install --save-dev @youthfulhps/prettier-plugin-tailwindcss-normalizer
|
|
28
|
+
```
|
|
29
|
+
|
|
30
|
+
## 📖 Usage
|
|
31
|
+
|
|
32
|
+
### 1. Configure Prettier
|
|
33
|
+
|
|
34
|
+
Add the plugin to your Prettier configuration:
|
|
35
|
+
|
|
36
|
+
**`.prettierrc`**
|
|
37
|
+
|
|
38
|
+
```json
|
|
39
|
+
{
|
|
40
|
+
"plugins": ["@youthfulhps/prettier-plugin-tailwindcss-normalizer"]
|
|
41
|
+
}
|
|
42
|
+
```
|
|
43
|
+
|
|
44
|
+
**`prettier.config.js`**
|
|
45
|
+
|
|
46
|
+
```javascript
|
|
47
|
+
module.exports = {
|
|
48
|
+
plugins: ['@youthfulhps/prettier-plugin-tailwindcss-normalizer'],
|
|
49
|
+
};
|
|
50
|
+
```
|
|
51
|
+
|
|
52
|
+
### 2. Run Prettier
|
|
53
|
+
|
|
54
|
+
```bash
|
|
55
|
+
# Format all files
|
|
56
|
+
npx prettier --write .
|
|
57
|
+
|
|
58
|
+
# Format specific files
|
|
59
|
+
npx prettier --write src/**/*.{tsx,jsx,html,vue}
|
|
60
|
+
```
|
|
61
|
+
|
|
62
|
+
## 🎯 Examples
|
|
63
|
+
|
|
64
|
+
### Before
|
|
65
|
+
|
|
66
|
+
```jsx
|
|
67
|
+
<div className="p-[16px] m-[8px] bg-blue-500">
|
|
68
|
+
<span className="px-[24px] py-[12px] rounded-[6px]">
|
|
69
|
+
Button
|
|
70
|
+
</span>
|
|
71
|
+
</div>
|
|
72
|
+
```
|
|
73
|
+
|
|
74
|
+
### After
|
|
75
|
+
|
|
76
|
+
```jsx
|
|
77
|
+
<div className="p-4 m-2 bg-blue-500">
|
|
78
|
+
<span className="px-6 py-3 rounded-md">
|
|
79
|
+
Button
|
|
80
|
+
</span>
|
|
81
|
+
</div>
|
|
82
|
+
```
|
|
83
|
+
|
|
84
|
+
## 🛡️ Safety Features
|
|
85
|
+
|
|
86
|
+
The plugin is designed to be safe and only transforms class-related attributes:
|
|
87
|
+
|
|
88
|
+
### ✅ What Gets Transformed
|
|
89
|
+
|
|
90
|
+
- `className` attributes in JSX/TSX
|
|
91
|
+
- `class` attributes in HTML
|
|
92
|
+
- `:class` and `v-bind:class` in Vue
|
|
93
|
+
- `[class]` in Angular
|
|
94
|
+
- String literals in template literals
|
|
95
|
+
- Function calls like `clsx()`, `classnames()`, `cn()`
|
|
96
|
+
|
|
97
|
+
### ❌ What Stays Untouched
|
|
98
|
+
|
|
99
|
+
- Comments and documentation
|
|
100
|
+
- Regular text content
|
|
101
|
+
- Other HTML attributes (`title`, `data-*`, etc.)
|
|
102
|
+
- JavaScript strings and variables
|
|
103
|
+
- CSS in `<style>` tags
|
|
104
|
+
|
|
105
|
+
## 📋 Supported Mappings
|
|
106
|
+
|
|
107
|
+
### Spacing
|
|
108
|
+
|
|
109
|
+
- **Padding**: `p-[4px]` → `p-1`, `px-[16px]` → `px-4`
|
|
110
|
+
- **Margin**: `m-[8px]` → `m-2`, `my-[12px]` → `my-3`
|
|
111
|
+
- **Gap**: `gap-[8px]` → `gap-2`, `gap-x-[16px]` → `gap-x-4`
|
|
112
|
+
|
|
113
|
+
### Sizing
|
|
114
|
+
|
|
115
|
+
- **Width**: `w-[100px]` → `w-25`, `w-[200px]` → `w-50`
|
|
116
|
+
- **Height**: `h-[50px]` → `h-12.5`, `h-[100px]` → `h-25`
|
|
117
|
+
|
|
118
|
+
### Typography
|
|
119
|
+
|
|
120
|
+
- **Font Size**: `text-[14px]` → `text-sm`, `text-[18px]` → `text-lg`
|
|
121
|
+
|
|
122
|
+
### Layout
|
|
123
|
+
|
|
124
|
+
- **Border Radius**: `rounded-[4px]` → `rounded`, `rounded-[6px]` → `rounded-md`
|
|
125
|
+
- **Border Width**: `border-[1px]` → `border`, `border-[2px]` → `border-2`
|
|
126
|
+
|
|
127
|
+
### Effects
|
|
128
|
+
|
|
129
|
+
- **Box Shadow**: `shadow-[0_1px_3px_rgba(0,0,0,0.1)]` → `shadow-sm`
|
|
130
|
+
- **Opacity**: `opacity-[0.5]` → `opacity-50`
|
|
131
|
+
|
|
132
|
+
## 🔧 Configuration
|
|
133
|
+
|
|
134
|
+
The plugin works out of the box with default settings. No additional configuration is required.
|
|
135
|
+
|
|
136
|
+
> **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
|
+
|
|
138
|
+
## 🧪 Testing
|
|
139
|
+
|
|
140
|
+
The plugin includes comprehensive tests covering:
|
|
141
|
+
|
|
142
|
+
- Various file formats (HTML, JSX, TSX, Vue)
|
|
143
|
+
- Edge cases and complex scenarios
|
|
144
|
+
- Safety features and non-transformation cases
|
|
145
|
+
- Different Tailwind CSS patterns
|
|
146
|
+
|
|
147
|
+
Run tests:
|
|
148
|
+
|
|
149
|
+
```bash
|
|
150
|
+
npm test
|
|
151
|
+
```
|
|
152
|
+
|
|
153
|
+
## 📁 File Support
|
|
154
|
+
|
|
155
|
+
| Format | Extension | Support |
|
|
156
|
+
| --------- | ----------------- | ------- |
|
|
157
|
+
| HTML | `.html` | ✅ |
|
|
158
|
+
| React JSX | `.jsx` | ✅ |
|
|
159
|
+
| React TSX | `.tsx` | ✅ |
|
|
160
|
+
| Vue | `.vue` | ✅ |
|
|
161
|
+
| Angular | `.component.html` | ✅ |
|
|
162
|
+
|
|
163
|
+
## 🤝 Contributing
|
|
164
|
+
|
|
165
|
+
Contributions are welcome! Please feel free to submit a Pull Request.
|
|
166
|
+
|
|
167
|
+
1. Fork the repository
|
|
168
|
+
2. Create your feature branch (`git checkout -b feature/amazing-feature`)
|
|
169
|
+
3. Commit your changes (`git commit -m 'Add some amazing feature'`)
|
|
170
|
+
4. Push to the branch (`git push origin feature/amazing-feature`)
|
|
171
|
+
5. Open a Pull Request
|
|
172
|
+
|
|
173
|
+
## 📄 License
|
|
174
|
+
|
|
175
|
+
This project is licensed under the MIT License - see the [LICENSE](LICENSE) file for details.
|
|
176
|
+
|
|
177
|
+
## 🙏 Acknowledgments
|
|
178
|
+
|
|
179
|
+
- Built for the Prettier ecosystem
|
|
180
|
+
- Inspired by Tailwind CSS best practices
|
|
181
|
+
- Thanks to all contributors and users
|
|
182
|
+
|
|
183
|
+
## 📞 Support
|
|
184
|
+
|
|
185
|
+
If you encounter any issues or have questions:
|
|
186
|
+
|
|
187
|
+
1. Check the [Issues](https://github.com/youthfulhps/prettier-plugin-tailwindcss-normalizer/issues) page
|
|
188
|
+
2. Create a new issue with detailed information
|
|
189
|
+
3. Provide examples of your code and expected behavior
|
|
190
|
+
|
|
191
|
+
### Common Issues
|
|
192
|
+
|
|
193
|
+
**Q: The plugin doesn't work with Prettier v2**
|
|
194
|
+
A: This plugin requires Prettier v3.0.0 or higher. Please upgrade your Prettier version.
|
|
195
|
+
|
|
196
|
+
**Q: How do I check my Prettier version?**
|
|
197
|
+
A: Run `npx prettier --version` to check your current Prettier version.
|
|
198
|
+
|
|
199
|
+
**Q: Can I use this with Prettier v2?**
|
|
200
|
+
A: No, this plugin is built specifically for Prettier v3+ and will not work with v2.
|
|
201
|
+
|
|
202
|
+
---
|
|
203
|
+
|
|
204
|
+
**Made with ❤️ for the developer community**
|
package/dist/index.js
CHANGED
|
@@ -2,6 +2,15 @@
|
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
3
|
const ast_transformer_1 = require("./ast-transformer");
|
|
4
4
|
const version_utils_1 = require("./utils/version-utils");
|
|
5
|
+
function createParser(parserName, fileType) {
|
|
6
|
+
const baseParser = (0, version_utils_1.safeLoadParser)(parserName, fileType);
|
|
7
|
+
return {
|
|
8
|
+
...baseParser,
|
|
9
|
+
preprocess: (text, options) => {
|
|
10
|
+
return (0, ast_transformer_1.transformByFileType)(text, options.filepath || `file.${fileType}`);
|
|
11
|
+
},
|
|
12
|
+
};
|
|
13
|
+
}
|
|
5
14
|
const plugin = {
|
|
6
15
|
languages: [
|
|
7
16
|
{
|
|
@@ -31,42 +40,37 @@ const plugin = {
|
|
|
31
40
|
},
|
|
32
41
|
],
|
|
33
42
|
parsers: {
|
|
34
|
-
html:
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
return (0, ast_transformer_1.transformByFileType)(text, options.filepath || "file.html");
|
|
38
|
-
},
|
|
39
|
-
},
|
|
40
|
-
vue: {
|
|
41
|
-
...(0, version_utils_1.safeLoadParser)("html", "vue"),
|
|
42
|
-
preprocess: (text, options) => {
|
|
43
|
-
return (0, ast_transformer_1.transformByFileType)(text, options.filepath || "file.vue");
|
|
44
|
-
},
|
|
45
|
-
},
|
|
46
|
-
angular: {
|
|
47
|
-
...(0, version_utils_1.safeLoadParser)("angular"),
|
|
48
|
-
preprocess: (text, options) => {
|
|
49
|
-
return (0, ast_transformer_1.transformByFileType)(text, options.filepath || "file.html");
|
|
50
|
-
},
|
|
51
|
-
},
|
|
43
|
+
html: createParser("html", "html"),
|
|
44
|
+
vue: createParser("html", "vue"),
|
|
45
|
+
angular: createParser("angular", "html"),
|
|
52
46
|
babel: {
|
|
53
|
-
...(
|
|
54
|
-
|
|
47
|
+
...createParser("babel", "jsx"),
|
|
48
|
+
parse: (text, options) => {
|
|
55
49
|
const filepath = options.filepath || "";
|
|
56
50
|
if (filepath.endsWith(".jsx") || filepath.endsWith(".tsx")) {
|
|
57
|
-
|
|
51
|
+
const transformedText = (0, ast_transformer_1.transformByFileType)(text, filepath);
|
|
52
|
+
const baseParser = (0, version_utils_1.safeLoadParser)("babel");
|
|
53
|
+
return baseParser.parse
|
|
54
|
+
? baseParser.parse(transformedText, options)
|
|
55
|
+
: text;
|
|
58
56
|
}
|
|
59
|
-
|
|
57
|
+
const baseParser = (0, version_utils_1.safeLoadParser)("babel");
|
|
58
|
+
return baseParser.parse ? baseParser.parse(text, options) : text;
|
|
60
59
|
},
|
|
61
60
|
},
|
|
62
61
|
"babel-ts": {
|
|
63
|
-
...(
|
|
64
|
-
|
|
62
|
+
...createParser("babel", "tsx"),
|
|
63
|
+
parse: (text, options) => {
|
|
65
64
|
const filepath = options.filepath || "";
|
|
66
65
|
if (filepath.endsWith(".tsx")) {
|
|
67
|
-
|
|
66
|
+
const transformedText = (0, ast_transformer_1.transformByFileType)(text, filepath);
|
|
67
|
+
const baseParser = (0, version_utils_1.safeLoadParser)("babel", "babel-ts");
|
|
68
|
+
return baseParser.parse
|
|
69
|
+
? baseParser.parse(transformedText, options)
|
|
70
|
+
: text;
|
|
68
71
|
}
|
|
69
|
-
|
|
72
|
+
const baseParser = (0, version_utils_1.safeLoadParser)("babel", "babel-ts");
|
|
73
|
+
return baseParser.parse ? baseParser.parse(text, options) : text;
|
|
70
74
|
},
|
|
71
75
|
},
|
|
72
76
|
},
|
|
@@ -1,6 +1,4 @@
|
|
|
1
1
|
export declare function getPrettierMajorVersion(): number;
|
|
2
|
-
export declare function isPrettierV2(): boolean;
|
|
3
|
-
export declare function isPrettierV3Plus(): boolean;
|
|
4
2
|
export declare function loadParser(parserName: string): any;
|
|
5
3
|
export declare function getParserFromParsers(parsers: any, parserName: string): any;
|
|
6
4
|
export declare function safeLoadParser(parserName: string, specificParser?: string): any;
|
|
@@ -1,54 +1,17 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
3
|
exports.getPrettierMajorVersion = getPrettierMajorVersion;
|
|
4
|
-
exports.isPrettierV2 = isPrettierV2;
|
|
5
|
-
exports.isPrettierV3Plus = isPrettierV3Plus;
|
|
6
4
|
exports.loadParser = loadParser;
|
|
7
5
|
exports.getParserFromParsers = getParserFromParsers;
|
|
8
6
|
exports.safeLoadParser = safeLoadParser;
|
|
9
|
-
let prettierVersion = null;
|
|
10
7
|
function getPrettierMajorVersion() {
|
|
11
|
-
|
|
12
|
-
return prettierVersion;
|
|
13
|
-
}
|
|
14
|
-
try {
|
|
15
|
-
const prettier = require("prettier");
|
|
16
|
-
if (prettier.version) {
|
|
17
|
-
const majorVersion = parseInt(prettier.version.split(".")[0]);
|
|
18
|
-
prettierVersion = majorVersion;
|
|
19
|
-
return majorVersion;
|
|
20
|
-
}
|
|
21
|
-
const prettierPackageJson = require("prettier/package.json");
|
|
22
|
-
if (prettierPackageJson.version) {
|
|
23
|
-
const majorVersion = parseInt(prettierPackageJson.version.split(".")[0]);
|
|
24
|
-
prettierVersion = majorVersion;
|
|
25
|
-
return majorVersion;
|
|
26
|
-
}
|
|
27
|
-
prettierVersion = 3;
|
|
28
|
-
return 3;
|
|
29
|
-
}
|
|
30
|
-
catch (error) {
|
|
31
|
-
prettierVersion = 3;
|
|
32
|
-
return 3;
|
|
33
|
-
}
|
|
34
|
-
}
|
|
35
|
-
function isPrettierV2() {
|
|
36
|
-
return getPrettierMajorVersion() === 2;
|
|
37
|
-
}
|
|
38
|
-
function isPrettierV3Plus() {
|
|
39
|
-
return getPrettierMajorVersion() >= 3;
|
|
8
|
+
return 3;
|
|
40
9
|
}
|
|
41
10
|
function loadParser(parserName) {
|
|
42
|
-
const
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
pathsToTry.push(`prettier/parser-${parserName}`);
|
|
47
|
-
}
|
|
48
|
-
else {
|
|
49
|
-
pathsToTry.push(`prettier/parser-${parserName}`);
|
|
50
|
-
pathsToTry.push(`prettier/plugins/${parserName}`);
|
|
51
|
-
}
|
|
11
|
+
const pathsToTry = [
|
|
12
|
+
`prettier/plugins/${parserName}`,
|
|
13
|
+
`prettier/parser-${parserName}`,
|
|
14
|
+
];
|
|
52
15
|
let lastError = null;
|
|
53
16
|
for (const path of pathsToTry) {
|
|
54
17
|
try {
|
|
@@ -60,7 +23,6 @@ function loadParser(parserName) {
|
|
|
60
23
|
}
|
|
61
24
|
}
|
|
62
25
|
throw new Error(`Failed to load parser: ${parserName}. ` +
|
|
63
|
-
`Prettier version: ${majorVersion}. ` +
|
|
64
26
|
`Tried paths: ${pathsToTry.join(", ")}. ` +
|
|
65
27
|
`Last error: ${lastError?.message}`);
|
|
66
28
|
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@youthfulhps/prettier-plugin-tailwindcss-normalizer",
|
|
3
|
-
"version": "0.3.
|
|
3
|
+
"version": "0.3.7",
|
|
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",
|
|
@@ -39,7 +39,7 @@
|
|
|
39
39
|
"author": "Your Name",
|
|
40
40
|
"license": "MIT",
|
|
41
41
|
"peerDependencies": {
|
|
42
|
-
"prettier": ">=
|
|
42
|
+
"prettier": ">=3.0.0"
|
|
43
43
|
},
|
|
44
44
|
"devDependencies": {
|
|
45
45
|
"@types/jest": "^29.5.8",
|
|
@@ -48,7 +48,7 @@
|
|
|
48
48
|
"@typescript-eslint/parser": "^7.0.0",
|
|
49
49
|
"eslint": "^8.57.1",
|
|
50
50
|
"jest": "^29.7.0",
|
|
51
|
-
"prettier": "^3.
|
|
51
|
+
"prettier": "^3.0.0",
|
|
52
52
|
"ts-jest": "^29.1.1",
|
|
53
53
|
"typescript": "^5.2.2"
|
|
54
54
|
},
|