css-to-tailwind-react 0.1.0
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 +303 -0
- package/bin/index.js +11 -0
- package/dist/cli.d.ts +1 -0
- package/dist/cli.js +80 -0
- package/dist/cssParser.d.ts +41 -0
- package/dist/cssParser.js +215 -0
- package/dist/fileWriter.d.ts +14 -0
- package/dist/fileWriter.js +128 -0
- package/dist/index.d.ts +8 -0
- package/dist/index.js +21 -0
- package/dist/jsxParser.d.ts +26 -0
- package/dist/jsxParser.js +273 -0
- package/dist/scanner.d.ts +5 -0
- package/dist/scanner.js +55 -0
- package/dist/tailwindMapper.d.ts +35 -0
- package/dist/tailwindMapper.js +428 -0
- package/dist/transformer.d.ts +19 -0
- package/dist/transformer.js +259 -0
- package/dist/utils/config.d.ts +14 -0
- package/dist/utils/config.js +139 -0
- package/dist/utils/logger.d.ts +14 -0
- package/dist/utils/logger.js +56 -0
- package/package.json +73 -0
package/README.md
ADDED
|
@@ -0,0 +1,303 @@
|
|
|
1
|
+
# CSS to Tailwind React
|
|
2
|
+
|
|
3
|
+
Convert traditional CSS (inline, internal, and external) into Tailwind CSS utility classes for React-based frameworks.
|
|
4
|
+
|
|
5
|
+
## Features
|
|
6
|
+
|
|
7
|
+
✨ **Multi-source CSS support**: Handles inline styles, internal `<style>` blocks, and external CSS files
|
|
8
|
+
🎯 **AST-based parsing**: Uses Babel for JSX/TSX and PostCSS for CSS - no regex hacks
|
|
9
|
+
🔄 **Smart merging**: Safely merges Tailwind classes with existing className attributes
|
|
10
|
+
⚠️ **Safety first**: Creates backups before modifications, supports dry-run mode
|
|
11
|
+
🎨 **Tailwind config aware**: Reads your `tailwind.config.js` for custom scales
|
|
12
|
+
📊 **Detailed reporting**: Shows exactly what changed and what was skipped
|
|
13
|
+
|
|
14
|
+
## Installation
|
|
15
|
+
|
|
16
|
+
```bash
|
|
17
|
+
npm install -g css-to-tailwind-react
|
|
18
|
+
```
|
|
19
|
+
|
|
20
|
+
Or use directly with npx:
|
|
21
|
+
|
|
22
|
+
```bash
|
|
23
|
+
npx css-to-tailwind-react ./src
|
|
24
|
+
```
|
|
25
|
+
|
|
26
|
+
## Usage
|
|
27
|
+
|
|
28
|
+
### Basic Usage
|
|
29
|
+
|
|
30
|
+
```bash
|
|
31
|
+
npx css-to-tailwind-react ./src
|
|
32
|
+
```
|
|
33
|
+
|
|
34
|
+
### CLI Options
|
|
35
|
+
|
|
36
|
+
```bash
|
|
37
|
+
npx css-to-tailwind-react <directory> [options]
|
|
38
|
+
|
|
39
|
+
Options:
|
|
40
|
+
--dry-run Show changes without modifying files
|
|
41
|
+
--verbose Show detailed output
|
|
42
|
+
--delete-css Delete CSS files when all rules are converted
|
|
43
|
+
--skip-external Skip external CSS files (imports)
|
|
44
|
+
--skip-inline Skip inline styles
|
|
45
|
+
--skip-internal Skip internal <style> blocks
|
|
46
|
+
```
|
|
47
|
+
|
|
48
|
+
### Examples
|
|
49
|
+
|
|
50
|
+
**Preview changes (dry-run):**
|
|
51
|
+
```bash
|
|
52
|
+
npx css-to-tailwind-react ./src --dry-run --verbose
|
|
53
|
+
```
|
|
54
|
+
|
|
55
|
+
**Only inline styles:**
|
|
56
|
+
```bash
|
|
57
|
+
npx css-to-tailwind-react ./src --skip-external --skip-internal
|
|
58
|
+
```
|
|
59
|
+
|
|
60
|
+
**Full conversion with CSS cleanup:**
|
|
61
|
+
```bash
|
|
62
|
+
npx css-to-tailwind-react ./src --delete-css
|
|
63
|
+
```
|
|
64
|
+
|
|
65
|
+
## Supported Conversions
|
|
66
|
+
|
|
67
|
+
### Inline Styles
|
|
68
|
+
|
|
69
|
+
Input:
|
|
70
|
+
```jsx
|
|
71
|
+
<div style={{ display: "flex", justifyContent: "center", padding: "16px" }}>
|
|
72
|
+
Content
|
|
73
|
+
</div>
|
|
74
|
+
```
|
|
75
|
+
|
|
76
|
+
Output:
|
|
77
|
+
```jsx
|
|
78
|
+
<div className="flex justify-center p-4">
|
|
79
|
+
Content
|
|
80
|
+
</div>
|
|
81
|
+
```
|
|
82
|
+
|
|
83
|
+
### External CSS
|
|
84
|
+
|
|
85
|
+
Input (`styles.css`):
|
|
86
|
+
```css
|
|
87
|
+
.main-head {
|
|
88
|
+
font-weight: bold;
|
|
89
|
+
text-align: center;
|
|
90
|
+
margin-bottom: 20px;
|
|
91
|
+
}
|
|
92
|
+
```
|
|
93
|
+
|
|
94
|
+
Component:
|
|
95
|
+
```jsx
|
|
96
|
+
import "./styles.css";
|
|
97
|
+
|
|
98
|
+
function Header() {
|
|
99
|
+
return <h1 className="main-head">Title</h1>;
|
|
100
|
+
}
|
|
101
|
+
```
|
|
102
|
+
|
|
103
|
+
Output:
|
|
104
|
+
```jsx
|
|
105
|
+
import "./styles.css";
|
|
106
|
+
|
|
107
|
+
function Header() {
|
|
108
|
+
return <h1 className="font-bold text-center mb-5">Title</h1>;
|
|
109
|
+
}
|
|
110
|
+
```
|
|
111
|
+
|
|
112
|
+
### ClassName Merging
|
|
113
|
+
|
|
114
|
+
Input:
|
|
115
|
+
```jsx
|
|
116
|
+
<div className="container" style={{ display: "flex" }}>
|
|
117
|
+
Content
|
|
118
|
+
</div>
|
|
119
|
+
```
|
|
120
|
+
|
|
121
|
+
Output:
|
|
122
|
+
```jsx
|
|
123
|
+
<div className="container flex">
|
|
124
|
+
Content
|
|
125
|
+
</div>
|
|
126
|
+
```
|
|
127
|
+
|
|
128
|
+
## Supported CSS Properties
|
|
129
|
+
|
|
130
|
+
The following properties are supported in v1:
|
|
131
|
+
|
|
132
|
+
- **Display**: `display: flex`, `display: block`, etc.
|
|
133
|
+
- **Position**: `position: relative`, `absolute`, etc.
|
|
134
|
+
- **Spacing**: `margin`, `padding` (with px to Tailwind scale conversion)
|
|
135
|
+
- **Typography**: `font-weight`, `font-size`, `text-align`
|
|
136
|
+
- **Flexbox**: `flex-direction`, `flex-wrap`, `justify-content`, `align-items`
|
|
137
|
+
- **Gap**: `gap` (with spacing scale)
|
|
138
|
+
- **Dimensions**: `width`, `height` (basic values and percentages)
|
|
139
|
+
- **Colors**: `background-color`, `color` (named, hex, rgb)
|
|
140
|
+
- **Border**: `border-radius`
|
|
141
|
+
|
|
142
|
+
## What Gets Skipped
|
|
143
|
+
|
|
144
|
+
The following are intentionally skipped with warnings:
|
|
145
|
+
|
|
146
|
+
- Pseudo-selectors (`:hover`, `:focus`, etc.)
|
|
147
|
+
- Media queries
|
|
148
|
+
- Nested selectors
|
|
149
|
+
- CSS animations and keyframes
|
|
150
|
+
- CSS variables (`--*`)
|
|
151
|
+
- `calc()` expressions
|
|
152
|
+
- Dynamic styles (conditional expressions)
|
|
153
|
+
- Complex className expressions
|
|
154
|
+
|
|
155
|
+
## Safety Features
|
|
156
|
+
|
|
157
|
+
### Backups
|
|
158
|
+
|
|
159
|
+
All original files are backed up to `.css-to-tailwind-backups/` before modification. To restore:
|
|
160
|
+
|
|
161
|
+
```bash
|
|
162
|
+
# Manual restore
|
|
163
|
+
cp -r .css-to-tailwind-backups/* ./
|
|
164
|
+
```
|
|
165
|
+
|
|
166
|
+
### Dry Run
|
|
167
|
+
|
|
168
|
+
Always preview changes first:
|
|
169
|
+
|
|
170
|
+
```bash
|
|
171
|
+
npx css-to-tailwind-react ./src --dry-run --verbose
|
|
172
|
+
```
|
|
173
|
+
|
|
174
|
+
### Dynamic Content Detection
|
|
175
|
+
|
|
176
|
+
The tool safely skips dynamic expressions:
|
|
177
|
+
|
|
178
|
+
```jsx
|
|
179
|
+
// These are skipped with warnings
|
|
180
|
+
<div style={dynamicStyle} />
|
|
181
|
+
<div className={condition ? "a" : "b"} style={{ display: "flex" }} />
|
|
182
|
+
```
|
|
183
|
+
|
|
184
|
+
## Configuration
|
|
185
|
+
|
|
186
|
+
The tool automatically detects and uses your `tailwind.config.js` if present. It supports:
|
|
187
|
+
|
|
188
|
+
- Custom spacing scales
|
|
189
|
+
- Extended colors
|
|
190
|
+
- Custom font sizes
|
|
191
|
+
- Border radius values
|
|
192
|
+
|
|
193
|
+
Example config support:
|
|
194
|
+
|
|
195
|
+
```javascript
|
|
196
|
+
// tailwind.config.js
|
|
197
|
+
module.exports = {
|
|
198
|
+
theme: {
|
|
199
|
+
extend: {
|
|
200
|
+
spacing: {
|
|
201
|
+
'18': '4.5rem',
|
|
202
|
+
'88': '22rem',
|
|
203
|
+
}
|
|
204
|
+
}
|
|
205
|
+
}
|
|
206
|
+
}
|
|
207
|
+
```
|
|
208
|
+
|
|
209
|
+
## Programmatic API
|
|
210
|
+
|
|
211
|
+
```typescript
|
|
212
|
+
import { scanProject, transformFiles } from 'css-to-tailwind-react';
|
|
213
|
+
|
|
214
|
+
const files = await scanProject('./src');
|
|
215
|
+
const results = await transformFiles(files, {
|
|
216
|
+
dryRun: false,
|
|
217
|
+
deleteCss: true,
|
|
218
|
+
skipExternal: false,
|
|
219
|
+
skipInline: false,
|
|
220
|
+
skipInternal: false,
|
|
221
|
+
tailwindConfig: null,
|
|
222
|
+
projectRoot: './src'
|
|
223
|
+
});
|
|
224
|
+
|
|
225
|
+
console.log(`Modified ${results.filesModified} files`);
|
|
226
|
+
```
|
|
227
|
+
|
|
228
|
+
## Architecture
|
|
229
|
+
|
|
230
|
+
```
|
|
231
|
+
src/
|
|
232
|
+
├── cli.ts # Commander CLI entry
|
|
233
|
+
├── scanner.ts # File detection with fast-glob
|
|
234
|
+
├── jsxParser.ts # Babel AST transformations
|
|
235
|
+
├── cssParser.ts # PostCSS CSS parsing
|
|
236
|
+
├── tailwindMapper.ts # CSS to Tailwind conversion engine
|
|
237
|
+
├── transformer.ts # Main transformation coordinator
|
|
238
|
+
├── fileWriter.ts # Safe file operations with backups
|
|
239
|
+
└── utils/
|
|
240
|
+
├── logger.ts # Structured logging
|
|
241
|
+
└── config.ts # Tailwind config loading
|
|
242
|
+
```
|
|
243
|
+
|
|
244
|
+
## Limitations
|
|
245
|
+
|
|
246
|
+
### v1 Limitations
|
|
247
|
+
|
|
248
|
+
1. **No pseudo-selectors**: `:hover`, `:focus`, etc. are skipped
|
|
249
|
+
2. **No media queries**: Responsive styles are not converted
|
|
250
|
+
3. **No SCSS/Sass**: Plain CSS only
|
|
251
|
+
4. **Limited value formats**: Pixel values and standard units work best
|
|
252
|
+
5. **No complex selectors**: Only simple class selectors (`.classname`)
|
|
253
|
+
6. **No CSS-in-JS**: Styled-components, emotion, etc. not supported
|
|
254
|
+
|
|
255
|
+
### Best Practices
|
|
256
|
+
|
|
257
|
+
1. **Commit your code** before running
|
|
258
|
+
2. **Use `--dry-run`** first to preview changes
|
|
259
|
+
3. **Review warnings** - some styles may need manual conversion
|
|
260
|
+
4. **Test thoroughly** after conversion
|
|
261
|
+
5. **Keep backups** until you're confident
|
|
262
|
+
|
|
263
|
+
## Troubleshooting
|
|
264
|
+
|
|
265
|
+
### "No supported files found"
|
|
266
|
+
|
|
267
|
+
Ensure your target directory contains `.js`, `.jsx`, `.ts`, `.tsx`, or `.css` files. The tool automatically ignores `node_modules`, `.next`, `dist`, and `build` directories.
|
|
268
|
+
|
|
269
|
+
### "Failed to parse"
|
|
270
|
+
|
|
271
|
+
Some JavaScript/TypeScript syntax may not be supported. Ensure your code is valid and doesn't use experimental features.
|
|
272
|
+
|
|
273
|
+
### Missing Tailwind classes
|
|
274
|
+
|
|
275
|
+
The tool uses a default Tailwind config if none is found. Create a `tailwind.config.js` for custom scales.
|
|
276
|
+
|
|
277
|
+
### Too many warnings
|
|
278
|
+
|
|
279
|
+
Use `--verbose` to see detailed output about what's being skipped and why.
|
|
280
|
+
|
|
281
|
+
## Contributing
|
|
282
|
+
|
|
283
|
+
Contributions welcome! Please ensure:
|
|
284
|
+
|
|
285
|
+
1. Code follows TypeScript strict mode
|
|
286
|
+
2. All tests pass
|
|
287
|
+
3. New features include tests
|
|
288
|
+
4. Documentation is updated
|
|
289
|
+
|
|
290
|
+
## License
|
|
291
|
+
|
|
292
|
+
MIT
|
|
293
|
+
|
|
294
|
+
## Changelog
|
|
295
|
+
|
|
296
|
+
### 1.0.0
|
|
297
|
+
|
|
298
|
+
- Initial release
|
|
299
|
+
- Inline style conversion
|
|
300
|
+
- External CSS support
|
|
301
|
+
- Internal style support
|
|
302
|
+
- Backup and dry-run modes
|
|
303
|
+
- Tailwind config detection
|
package/bin/index.js
ADDED
package/dist/cli.d.ts
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
package/dist/cli.js
ADDED
|
@@ -0,0 +1,80 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
3
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
4
|
+
};
|
|
5
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
|
+
const commander_1 = require("commander");
|
|
7
|
+
const scanner_1 = require("./scanner");
|
|
8
|
+
const transformer_1 = require("./transformer");
|
|
9
|
+
const logger_1 = require("./utils/logger");
|
|
10
|
+
const config_1 = require("./utils/config");
|
|
11
|
+
const path_1 = __importDefault(require("path"));
|
|
12
|
+
const program = new commander_1.Command();
|
|
13
|
+
program
|
|
14
|
+
.name('css-to-tailwind-react')
|
|
15
|
+
.description('Convert traditional CSS into Tailwind CSS utility classes for React')
|
|
16
|
+
.version('1.0.0')
|
|
17
|
+
.argument('<directory>', 'Target directory to scan and transform')
|
|
18
|
+
.option('--dry-run', 'Show changes without modifying files')
|
|
19
|
+
.option('--verbose', 'Show detailed output')
|
|
20
|
+
.option('--delete-css', 'Delete CSS files when all rules are converted')
|
|
21
|
+
.option('--skip-external', 'Skip external CSS files (imports)')
|
|
22
|
+
.option('--skip-inline', 'Skip inline styles')
|
|
23
|
+
.option('--skip-internal', 'Skip internal <style> blocks')
|
|
24
|
+
.action(async (directory, options) => {
|
|
25
|
+
const startTime = Date.now();
|
|
26
|
+
try {
|
|
27
|
+
// Set verbose mode for logger
|
|
28
|
+
logger_1.logger.setVerbose(options.verbose || false);
|
|
29
|
+
logger_1.logger.info('🚀 CSS to Tailwind React Converter');
|
|
30
|
+
logger_1.logger.info(`📁 Target directory: ${path_1.default.resolve(directory)}`);
|
|
31
|
+
if (options.dryRun) {
|
|
32
|
+
logger_1.logger.info('🔍 Dry run mode - no files will be modified');
|
|
33
|
+
}
|
|
34
|
+
// Load Tailwind config
|
|
35
|
+
logger_1.logger.info('⚙️ Loading Tailwind configuration...');
|
|
36
|
+
const tailwindConfig = await (0, config_1.loadTailwindConfig)(directory);
|
|
37
|
+
// Scan project files
|
|
38
|
+
logger_1.logger.info('🔎 Scanning project files...');
|
|
39
|
+
const files = await (0, scanner_1.scanProject)(directory);
|
|
40
|
+
logger_1.logger.success(`Found ${files.length} files to process`);
|
|
41
|
+
if (files.length === 0) {
|
|
42
|
+
logger_1.logger.warn('No supported files found in the target directory');
|
|
43
|
+
process.exit(0);
|
|
44
|
+
}
|
|
45
|
+
// Transform files
|
|
46
|
+
const results = await (0, transformer_1.transformFiles)(files, {
|
|
47
|
+
dryRun: options.dryRun || false,
|
|
48
|
+
deleteCss: options.deleteCss || false,
|
|
49
|
+
skipExternal: options.skipExternal || false,
|
|
50
|
+
skipInline: options.skipInline || false,
|
|
51
|
+
skipInternal: options.skipInternal || false,
|
|
52
|
+
tailwindConfig,
|
|
53
|
+
projectRoot: path_1.default.resolve(directory)
|
|
54
|
+
});
|
|
55
|
+
// Print summary
|
|
56
|
+
const duration = ((Date.now() - startTime) / 1000).toFixed(2);
|
|
57
|
+
console.log('\n' + '='.repeat(50));
|
|
58
|
+
logger_1.logger.success('✨ Transformation Complete!');
|
|
59
|
+
console.log('='.repeat(50));
|
|
60
|
+
console.log(`📊 Summary:`);
|
|
61
|
+
console.log(` Files scanned: ${results.filesScanned}`);
|
|
62
|
+
console.log(` Files modified: ${results.filesModified}`);
|
|
63
|
+
console.log(` Styles converted: ${results.stylesConverted}`);
|
|
64
|
+
console.log(` Classes replaced: ${results.classesReplaced}`);
|
|
65
|
+
console.log(` Warnings: ${results.warnings}`);
|
|
66
|
+
console.log(` Duration: ${duration}s`);
|
|
67
|
+
console.log('='.repeat(50));
|
|
68
|
+
if (results.warnings > 0) {
|
|
69
|
+
logger_1.logger.warn('Some styles could not be converted. Run with --verbose for details.');
|
|
70
|
+
process.exit(0);
|
|
71
|
+
}
|
|
72
|
+
process.exit(0);
|
|
73
|
+
}
|
|
74
|
+
catch (error) {
|
|
75
|
+
logger_1.logger.error('❌ Transformation failed:', error);
|
|
76
|
+
process.exit(1);
|
|
77
|
+
}
|
|
78
|
+
});
|
|
79
|
+
program.parse();
|
|
80
|
+
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiY2xpLmpzIiwic291cmNlUm9vdCI6IiIsInNvdXJjZXMiOlsiLi4vc3JjL2NsaS50cyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiOzs7OztBQUFBLHlDQUFvQztBQUNwQyx1Q0FBd0M7QUFDeEMsK0NBQStDO0FBQy9DLDJDQUF3QztBQUN4QywyQ0FBb0Q7QUFDcEQsZ0RBQXdCO0FBV3hCLE1BQU0sT0FBTyxHQUFHLElBQUksbUJBQU8sRUFBRSxDQUFDO0FBRTlCLE9BQU87S0FDSixJQUFJLENBQUMsdUJBQXVCLENBQUM7S0FDN0IsV0FBVyxDQUFDLHFFQUFxRSxDQUFDO0tBQ2xGLE9BQU8sQ0FBQyxPQUFPLENBQUM7S0FDaEIsUUFBUSxDQUFDLGFBQWEsRUFBRSx3Q0FBd0MsQ0FBQztLQUNqRSxNQUFNLENBQUMsV0FBVyxFQUFFLHNDQUFzQyxDQUFDO0tBQzNELE1BQU0sQ0FBQyxXQUFXLEVBQUUsc0JBQXNCLENBQUM7S0FDM0MsTUFBTSxDQUFDLGNBQWMsRUFBRSwrQ0FBK0MsQ0FBQztLQUN2RSxNQUFNLENBQUMsaUJBQWlCLEVBQUUsbUNBQW1DLENBQUM7S0FDOUQsTUFBTSxDQUFDLGVBQWUsRUFBRSxvQkFBb0IsQ0FBQztLQUM3QyxNQUFNLENBQUMsaUJBQWlCLEVBQUUsOEJBQThCLENBQUM7S0FDekQsTUFBTSxDQUFDLEtBQUssRUFBRSxTQUFpQixFQUFFLE9BQW1CLEVBQUUsRUFBRTtJQUN2RCxNQUFNLFNBQVMsR0FBRyxJQUFJLENBQUMsR0FBRyxFQUFFLENBQUM7SUFFN0IsSUFBSSxDQUFDO1FBQ0gsOEJBQThCO1FBQzlCLGVBQU0sQ0FBQyxVQUFVLENBQUMsT0FBTyxDQUFDLE9BQU8sSUFBSSxLQUFLLENBQUMsQ0FBQztRQUU1QyxlQUFNLENBQUMsSUFBSSxDQUFDLG9DQUFvQyxDQUFDLENBQUM7UUFDbEQsZUFBTSxDQUFDLElBQUksQ0FBQyx3QkFBd0IsY0FBSSxDQUFDLE9BQU8sQ0FBQyxTQUFTLENBQUMsRUFBRSxDQUFDLENBQUM7UUFFL0QsSUFB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LENBQUMsQ0FBQyxDQUFDO0lBQ2xCLENBQUM7SUFBQyxPQUFPLEtBQUssRUFBRSxDQUFDO1FBQ2YsZUFBTSxDQUFDLEtBQUssQ0FBQywwQkFBMEIsRUFBRSxLQUFLLENBQUMsQ0FBQztRQUNoRCxPQUFPLENBQUMsSUFBSSxDQUFDLENBQUMsQ0FBQyxDQUFDO0lBQ2xCLENBQUM7QUFDSCxDQUFDLENBQUMsQ0FBQztBQUVMLE9BQU8sQ0FBQyxLQUFLLEVBQUUsQ0FBQyIsInNvdXJjZXNDb250ZW50IjpbImltcG9ydCB7IENvbW1hbmQgfSBmcm9tICdjb21tYW5kZXInO1xuaW1wb3J0IHsgc2NhblByb2plY3QgfSBmcm9tICcuL3NjYW5uZXInO1xuaW1wb3J0IHsgdHJhbnNmb3JtRmlsZXMgfSBmcm9tICcuL3RyYW5zZm9ybWVyJztcbmltcG9ydCB7IGxvZ2dlciB9IGZyb20gJy4vdXRpbHMvbG9nZ2VyJztcbmltcG9ydCB7IGxvYWRUYWlsd2luZENvbmZpZyB9IGZyb20gJy4vdXRpbHMvY29uZmlnJztcbmltcG9ydCBwYXRoIGZyb20gJ3BhdGgnO1xuXG5pbnRlcmZhY2UgQ0xJT3B0aW9ucyB7XG4gIGRyeVJ1bj86IGJvb2xlYW47XG4gIHZlcmJvc2U/OiBib29sZWFuO1xuICBkZWxldGVDc3M/OiBib29sZWFuO1xuICBza2lwRXh0ZXJuYWw/OiBib29sZWFuO1xuICBza2lwSW5saW5lPzogYm9vbGVhbjtcbiAgc2tpcEludGVybmFsPzogYm9vbGVhbjtcbn1cblxuY29uc3QgcHJvZ3JhbSA9IG5ldyBDb21tYW5kKCk7XG5cbnByb2dyYW1cbiAgLm5hbWUoJ2Nzcy10by10YWlsd2luZC1yZWFjdCcpXG4gIC5kZXNjcmlwdGlvbignQ29udmVydCB0cmFkaXRpb25hbCBDU1MgaW50byBUYWlsd2luZCBDU1MgdXRpbGl0eSBjbGFzc2VzIGZvciBSZWFjdCcpXG4gIC52ZXJzaW9uKCcxLjAuMCcpXG4gIC5hcmd1bWVudCgnPGRpcmVjdG9yeT4nLCAnVGFyZ2V0IGRpcmVjdG9yeSB0byBzY2FuIGFuZCB0cmFuc2Zvcm0nKVxuICAub3B0aW9uKCctLWRyeS1ydW4nLCAnU2hvdyBjaGFuZ2VzIHdpdGhvdXQgbW9kaWZ5aW5nIGZpbGVzJylcbiAgLm9wdGlvbignLS12ZXJib3NlJywgJ1Nob3cgZGV0YWlsZWQgb3V0cHV0JylcbiAgLm9wdGlvbignLS1kZWxldGUtY3NzJywgJ0RlbGV0ZSBDU1MgZmlsZXMgd2hlbiBhbGwgcnVsZXMgYXJlIGNvbnZlcnRlZCcpXG4gIC5vcHRpb24oJy0tc2tpcC1leHRlcm5hbCcsICdTa2lwIGV4dGVybmFsIENTUyBmaWxlcyAoaW1wb3J0cyknKVxuICAub3B0aW9uKCctLXNraXAtaW5saW5lJywgJ1NraXAgaW5saW5lIHN0eWxlcycpXG4gIC5vcHRpb24oJy0tc2tpcC1pbnRlcm5hbCcsICdTa2lwIGludGVybmFsIDxzdHlsZT4gYmxvY2tzJylcbiAgLmFjdGlvbihhc3luYyAoZGlyZWN0b3J5OiBzdHJpbmcsIG9wdGlvbnM6IENMSU9wdGlvbnMpID0+IHtcbiAgICBjb25zdCBzdGFydFRpbWUgPSBEYXRlLm5vdygpO1xuICAgIFxuICAgIHRyeSB7XG4gICAgICAvLyBTZXQgdmVyYm9zZSBtb2RlIGZvciBsb2dnZXJcbiAgICAgIGxvZ2dlci5zZXRWZXJib3NlKG9wdGlvbnMudmVyYm9zZSB8fCBmYWxzZSk7XG4gICAgICBcbiAgICAgIGxvZ2dlci5pbmZvKCfwn5qAIENTUyB0byBUYWlsd2luZCBSZWFjdCBDb252ZXJ0ZXInKTtcbiAgICAgIGxvZ2dlci5pbmZvKGDwn5OBIFRhcmdldCBkaXJlY3Rvcnk6ICR7cGF0aC5yZXNvbHZlKGRpcmVjdG9yeSl9YCk7XG4gICAgICBcbiAgICAgIGlmIChvcHRpb25zLmRyeVJ1bikge1xuICAgICAgICBsb2dnZXIuaW5mbygn8J+UjSBEcnkgcnVuIG1vZGUgLSBubyBmaWxlcyB3aWxsIGJlIG1vZGlmaWVkJyk7XG4gICAgICB9XG5cbiAgICAgIC8vIExvYWQgVGFpbHdpbmQgY29uZmlnXG4gICAgICBsb2dnZXIuaW5mbygn4pqZ77iPICBMb2FkaW5nIFRhaWx3aW5kIGNvbmZpZ3VyYXRpb24uLi4nKTtcbiAgICAgIGNvbnN0IHRhaWx3aW5kQ29uZmlnID0gYXdhaXQgbG9hZFRhaWx3aW5kQ29uZmlnKGRpcmVjdG9yeSk7XG4gICAgICBcbiAgICAgIC8vIFNjYW4gcHJvamVjdCBmaWxlc1xuICAgICAgbG9nZ2VyLmluZm8oJ/CflI4gU2Nhbm5pbmcgcHJvamVjdCBmaWxlcy4uLicpO1xuICAgICAgY29uc3QgZmlsZXMgPSBhd2FpdCBzY2FuUHJvamVjdChkaXJlY3RvcnkpO1xuICAgICAgXG4gICAgICBsb2dnZXIuc3VjY2VzcyhgRm91bmQgJHtmaWxlcy5sZW5ndGh9IGZpbGVzIHRvIHByb2Nlc3NgKTtcbiAgICAgIFxuICAgICAgaWYgKGZpbGVzLmxlbmd0aCA9PT0gMCkge1xuICAgICAgICBsb2dnZXIud2FybignTm8gc3VwcG9ydGVkIGZpbGVzIGZvdW5kIGluIHRoZSB0YXJnZXQgZGlyZWN0b3J5Jyk7XG4gICAgICAgIHByb2Nlc3MuZXhpdCgwKTtcbiAgICAgIH1cblxuICAgICAgLy8gVHJhbnNmb3JtIGZpbGVzXG4gICAgICBjb25zdCByZXN1bHRzID0gYXdhaXQgdHJhbnNmb3JtRmlsZXMoZmlsZXMsIHtcbiAgICAgICAgZHJ5UnVuOiBvcHRpb25zLmRyeVJ1biB8fCBmYWxzZSxcbiAgICAgICAgZGVsZXRlQ3NzOiBvcHRpb25zLmRlbGV0ZUNzcyB8fCBmYWxzZSxcbiAgICAgICAgc2tpcEV4dGVybmFsOiBvcHRpb25zLnNraXBFeHRlcm5hbCB8fCBmYWxzZSxcbiAgICAgICAgc2tpcElubGluZTogb3B0aW9ucy5za2lwSW5saW5lIHx8IGZhbHNlLFxuICAgICAgICBza2lwSW50ZXJuYWw6IG9wdGlvbnMuc2tpcEludGVybmFsIHx8IGZhbHNlLFxuICAgICAgICB0YWlsd2luZENvbmZpZyxcbiAgICAgICAgcHJvamVjdFJvb3Q6IHBhdGgucmVzb2x2ZShkaXJlY3RvcnkpXG4gICAgICB9KTtcblxuICAgICAgLy8gUHJpbnQgc3VtbWFyeVxuICAgICAgY29uc3QgZHVyYXRpb24gPSAoKERhdGUubm93KCkgLSBzdGFydFRpbWUpIC8gMTAwMCkudG9GaXhlZCgyKTtcbiAgICAgIFxuICAgICAgY29uc29sZS5sb2coJ1xcbicgKyAnPScucmVwZWF0KDUwKSk7XG4gICAgICBsb2dnZXIuc3VjY2Vzcygn4pyoIFRyYW5zZm9ybWF0aW9uIENvbXBsZXRlIScpO1xuICAgICAgY29uc29sZS5sb2coJz0nLnJlcGVhdCg1MCkpO1xuICAgICAgY29uc29sZS5sb2coYPCfk4ogU3VtbWFyeTpgKTtcbiAgICAgIGNvbnNvbGUubG9nKGAgICBGaWxlcyBzY2FubmVkOiAgICAgICR7cmVzdWx0cy5maWxlc1NjYW5uZWR9YCk7XG4gICAgICBjb25zb2xlLmxvZyhgICAgRmlsZXMgbW9kaWZpZWQ6ICAgICAke3Jlc3VsdHMuZmlsZXNNb2RpZmllZH1gKTtcbiAgICAgIGNvbnNvbGUubG9nKGAgICBTdHlsZXMgY29udmVydGVkOiAgICR7cmVzdWx0cy5zdHlsZXNDb252ZXJ0ZWR9YCk7XG4gICAgICBjb25zb2xlLmxvZyhgICAgQ2xhc3NlcyByZXBsYWNlZDogICAke3Jlc3VsdHMuY2xhc3Nlc1JlcGxhY2VkfWApO1xuICAgICAgY29uc29sZS5sb2coYCAgIFdhcm5pbmdzOiAgICAgICAgICAgJHtyZXN1bHRzLndhcm5pbmdzfWApO1xuICAgICAgY29uc29sZS5sb2coYCAgIER1cmF0aW9uOiAgICAgICAgICAgJHtkdXJhdGlvbn1zYCk7XG4gICAgICBjb25zb2xlLmxvZygnPScucmVwZWF0KDUwKSk7XG5cbiAgICAgIGlmIChyZXN1bHRzLndhcm5pbmdzID4gMCkge1xuICAgICAgICBsb2dnZXIud2FybignU29tZSBzdHlsZXMgY291bGQgbm90IGJlIGNvbnZlcnRlZC4gUnVuIHdpdGggLS12ZXJib3NlIGZvciBkZXRhaWxzLicpO1xuICAgICAgICBwcm9jZXNzLmV4aXQoMCk7XG4gICAgICB9XG5cbiAgICAgIHByb2Nlc3MuZXhpdCgwKTtcbiAgICB9IGNhdGNoIChlcnJvcikge1xuICAgICAgbG9nZ2VyLmVycm9yKCfinYwgVHJhbnNmb3JtYXRpb24gZmFpbGVkOicsIGVycm9yKTtcbiAgICAgIHByb2Nlc3MuZXhpdCgxKTtcbiAgICB9XG4gIH0pO1xuXG5wcm9ncmFtLnBhcnNlKCk7XG4iXX0=
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
import { TailwindMapper, CSSProperty } from './tailwindMapper';
|
|
2
|
+
export interface CSSRule {
|
|
3
|
+
selector: string;
|
|
4
|
+
className: string;
|
|
5
|
+
declarations: CSSProperty[];
|
|
6
|
+
convertedClasses: string[];
|
|
7
|
+
skipped: boolean;
|
|
8
|
+
fullyConverted: boolean;
|
|
9
|
+
partialConversion: boolean;
|
|
10
|
+
reason?: string;
|
|
11
|
+
}
|
|
12
|
+
export interface CSSParseResult {
|
|
13
|
+
css: string;
|
|
14
|
+
rules: CSSRule[];
|
|
15
|
+
hasChanges: boolean;
|
|
16
|
+
canDelete: boolean;
|
|
17
|
+
warnings: string[];
|
|
18
|
+
}
|
|
19
|
+
export interface CSSUsageMap {
|
|
20
|
+
[className: string]: string[];
|
|
21
|
+
}
|
|
22
|
+
export declare class CSSParser {
|
|
23
|
+
private mapper;
|
|
24
|
+
constructor(mapper: TailwindMapper);
|
|
25
|
+
parse(css: string, filePath: string): Promise<CSSParseResult>;
|
|
26
|
+
parseInternalStyle(html: string): {
|
|
27
|
+
styles: Array<{
|
|
28
|
+
content: string;
|
|
29
|
+
start: number;
|
|
30
|
+
end: number;
|
|
31
|
+
}>;
|
|
32
|
+
warnings: string[];
|
|
33
|
+
};
|
|
34
|
+
parseInternalCSS(html: string, filePath: string): Promise<{
|
|
35
|
+
html: string;
|
|
36
|
+
rules: CSSRule[];
|
|
37
|
+
hasChanges: boolean;
|
|
38
|
+
warnings: string[];
|
|
39
|
+
}>;
|
|
40
|
+
extractImportPaths(code: string): string[];
|
|
41
|
+
}
|