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 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
@@ -0,0 +1,11 @@
1
+ #!/usr/bin/env node
2
+
3
+ const path = require('path');
4
+
5
+ // Determine which build to use
6
+ const distPath = path.join(__dirname, '..', 'dist');
7
+
8
+ // Try to load the compiled CLI
9
+ const cliPath = path.join(distPath, 'cli.js');
10
+
11
+ require(cliPath);
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
+ }