tailwind-typescript-plugin 1.4.0-beta.1 → 1.4.0-beta.11
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/CHANGELOG.md +73 -0
- package/README.md +373 -34
- package/lib/core/interfaces.d.ts +2 -2
- package/lib/core/interfaces.d.ts.map +1 -1
- package/lib/core/types.d.ts +27 -1
- package/lib/core/types.d.ts.map +1 -1
- package/lib/extractors/BaseExtractor.d.ts +49 -2
- package/lib/extractors/BaseExtractor.d.ts.map +1 -1
- package/lib/extractors/BaseExtractor.js +184 -5
- package/lib/extractors/BaseExtractor.js.map +1 -1
- package/lib/extractors/CvaExtractor.d.ts.map +1 -1
- package/lib/extractors/CvaExtractor.js +7 -3
- package/lib/extractors/CvaExtractor.js.map +1 -1
- package/lib/extractors/ExpressionExtractor.d.ts.map +1 -1
- package/lib/extractors/ExpressionExtractor.js +35 -5
- package/lib/extractors/ExpressionExtractor.js.map +1 -1
- package/lib/extractors/JsxAttributeExtractor.js +1 -1
- package/lib/extractors/JsxAttributeExtractor.js.map +1 -1
- package/lib/extractors/TailwindVariantsExtractor.d.ts +2 -0
- package/lib/extractors/TailwindVariantsExtractor.d.ts.map +1 -1
- package/lib/extractors/TailwindVariantsExtractor.js +12 -8
- package/lib/extractors/TailwindVariantsExtractor.js.map +1 -1
- package/lib/extractors/VariableReferenceExtractor.d.ts.map +1 -1
- package/lib/extractors/VariableReferenceExtractor.js +21 -0
- package/lib/extractors/VariableReferenceExtractor.js.map +1 -1
- package/lib/infrastructure/TailwindConflictDetector.d.ts +83 -0
- package/lib/infrastructure/TailwindConflictDetector.d.ts.map +1 -0
- package/lib/infrastructure/TailwindConflictDetector.js +342 -0
- package/lib/infrastructure/TailwindConflictDetector.js.map +1 -0
- package/lib/infrastructure/TailwindValidator.d.ts +15 -0
- package/lib/infrastructure/TailwindValidator.d.ts.map +1 -1
- package/lib/infrastructure/TailwindValidator.js +84 -5
- package/lib/infrastructure/TailwindValidator.js.map +1 -1
- package/lib/infrastructure/TailwindValidator.spec.js +194 -0
- package/lib/infrastructure/TailwindValidator.spec.js.map +1 -1
- package/lib/plugin/TailwindTypescriptPlugin.d.ts +26 -0
- package/lib/plugin/TailwindTypescriptPlugin.d.ts.map +1 -1
- package/lib/plugin/TailwindTypescriptPlugin.js +180 -1
- package/lib/plugin/TailwindTypescriptPlugin.js.map +1 -1
- package/lib/services/ClassNameExtractionService.d.ts +2 -2
- package/lib/services/ClassNameExtractionService.d.ts.map +1 -1
- package/lib/services/ClassNameExtractionService.js.map +1 -1
- package/lib/services/CompletionService.d.ts +98 -0
- package/lib/services/CompletionService.d.ts.map +1 -0
- package/lib/services/CompletionService.js +484 -0
- package/lib/services/CompletionService.js.map +1 -0
- package/lib/services/CompletionService.spec.d.ts +2 -0
- package/lib/services/CompletionService.spec.d.ts.map +1 -0
- package/lib/services/CompletionService.spec.js +334 -0
- package/lib/services/CompletionService.spec.js.map +1 -0
- package/lib/services/ConflictClassDetection.spec.d.ts +2 -0
- package/lib/services/ConflictClassDetection.spec.d.ts.map +1 -0
- package/lib/services/ConflictClassDetection.spec.js +477 -0
- package/lib/services/ConflictClassDetection.spec.js.map +1 -0
- package/lib/services/DiagnosticService.d.ts +14 -0
- package/lib/services/DiagnosticService.d.ts.map +1 -1
- package/lib/services/DiagnosticService.js +32 -1
- package/lib/services/DiagnosticService.js.map +1 -1
- package/lib/services/DuplicateClassDetection.spec.js +41 -60
- package/lib/services/DuplicateClassDetection.spec.js.map +1 -1
- package/lib/services/PluginConfigService.d.ts +2 -1
- package/lib/services/PluginConfigService.d.ts.map +1 -1
- package/lib/services/PluginConfigService.js +19 -12
- package/lib/services/PluginConfigService.js.map +1 -1
- package/lib/services/ValidationService.d.ts +5 -2
- package/lib/services/ValidationService.d.ts.map +1 -1
- package/lib/services/ValidationService.js +22 -9
- package/lib/services/ValidationService.js.map +1 -1
- package/package.json +4 -2
- package/lib/extractors/StringLiteralExtractor.d.ts +0 -12
- package/lib/extractors/StringLiteralExtractor.d.ts.map +0 -1
- package/lib/extractors/StringLiteralExtractor.js +0 -21
- package/lib/extractors/StringLiteralExtractor.js.map +0 -1
- package/lib/services/ClassNameExtractionService.original.d.ts +0 -20
- package/lib/services/ClassNameExtractionService.original.d.ts.map +0 -1
- package/lib/services/ClassNameExtractionService.original.js +0 -48
- package/lib/services/ClassNameExtractionService.original.js.map +0 -1
package/CHANGELOG.md
CHANGED
|
@@ -1,3 +1,76 @@
|
|
|
1
|
+
## [1.4.0-beta.11](https://github.com/IvanRodriCalleja/tailwind-typescript-plugin/compare/v1.4.0-beta.10...v1.4.0-beta.11) (2025-11-29)
|
|
2
|
+
|
|
3
|
+
### ✨ Features
|
|
4
|
+
|
|
5
|
+
* add Tailwind CSS class completion suggestions ([a6f20ff](https://github.com/IvanRodriCalleja/tailwind-typescript-plugin/commit/a6f20ff1c4fb97577e92ce7946ed1e6cd7d196a4))
|
|
6
|
+
|
|
7
|
+
## [1.4.0-beta.10](https://github.com/IvanRodriCalleja/tailwind-typescript-plugin/compare/v1.4.0-beta.9...v1.4.0-beta.10) (2025-11-29)
|
|
8
|
+
|
|
9
|
+
### ⚡ Performance
|
|
10
|
+
|
|
11
|
+
* optimize test execution with sharding and separated test commands ([0a89bdd](https://github.com/IvanRodriCalleja/tailwind-typescript-plugin/commit/0a89bddcd77ec96eba6a2c0ff579b1c8b4d46f2d))
|
|
12
|
+
|
|
13
|
+
## [1.4.0-beta.9](https://github.com/IvanRodriCalleja/tailwind-typescript-plugin/compare/v1.4.0-beta.8...v1.4.0-beta.9) (2025-11-29)
|
|
14
|
+
|
|
15
|
+
### ♻️ Code Refactoring
|
|
16
|
+
|
|
17
|
+
* restructure test cases into folder-based organization with JSDoc comments ([13cc790](https://github.com/IvanRodriCalleja/tailwind-typescript-plugin/commit/13cc7900545d35b215e12618c8e7b003cfc67d02))
|
|
18
|
+
|
|
19
|
+
## [1.4.0-beta.8](https://github.com/IvanRodriCalleja/tailwind-typescript-plugin/compare/v1.4.0-beta.7...v1.4.0-beta.8) (2025-11-28)
|
|
20
|
+
|
|
21
|
+
### ✨ Features
|
|
22
|
+
|
|
23
|
+
* add import verification for utility functions ([9d34a12](https://github.com/IvanRodriCalleja/tailwind-typescript-plugin/commit/9d34a129cdb05d5e74cba1510d89b9b6c6afeab6))
|
|
24
|
+
* add namespace import verification for member expressions ([eaacf9a](https://github.com/IvanRodriCalleja/tailwind-typescript-plugin/commit/eaacf9a808c7f63e1d2fa5a284c24e1426821aa6))
|
|
25
|
+
|
|
26
|
+
### ♻️ Code Refactoring
|
|
27
|
+
|
|
28
|
+
* add imports to test files and update default utility functions ([698fdc2](https://github.com/IvanRodriCalleja/tailwind-typescript-plugin/commit/698fdc2afcfbb59dcd1cf6b17c754ef4a0b9a542))
|
|
29
|
+
|
|
30
|
+
## [1.4.0-beta.7](https://github.com/IvanRodriCalleja/tailwind-typescript-plugin/compare/v1.4.0-beta.6...v1.4.0-beta.7) (2025-11-28)
|
|
31
|
+
|
|
32
|
+
### ✨ Features
|
|
33
|
+
|
|
34
|
+
* add wildcard pattern support for allowedClasses ([a490b68](https://github.com/IvanRodriCalleja/tailwind-typescript-plugin/commit/a490b68800b54bfde6eadef42ab97aaee51550fc))
|
|
35
|
+
|
|
36
|
+
## [1.4.0-beta.6](https://github.com/IvanRodriCalleja/tailwind-typescript-plugin/compare/v1.4.0-beta.5...v1.4.0-beta.6) (2025-11-28)
|
|
37
|
+
|
|
38
|
+
### ✨ Features
|
|
39
|
+
|
|
40
|
+
* add spread operator support for class name validation ([a4c4ad1](https://github.com/IvanRodriCalleja/tailwind-typescript-plugin/commit/a4c4ad1fc2ef42e7d4d87351af4fe464384c44b3))
|
|
41
|
+
|
|
42
|
+
### 🔧 Chores
|
|
43
|
+
|
|
44
|
+
* add utility libraries and cn helper ([2ac664d](https://github.com/IvanRodriCalleja/tailwind-typescript-plugin/commit/2ac664dc33ba4a5c52e3059ee5ec5c9257da1c78))
|
|
45
|
+
|
|
46
|
+
## [1.4.0-beta.5](https://github.com/IvanRodriCalleja/tailwind-typescript-plugin/compare/v1.4.0-beta.4...v1.4.0-beta.5) (2025-11-27)
|
|
47
|
+
|
|
48
|
+
### ♻️ Code Refactoring
|
|
49
|
+
|
|
50
|
+
* split test cases into folder structure for better organization ([fbe6774](https://github.com/IvanRodriCalleja/tailwind-typescript-plugin/commit/fbe67742147857fb7c01e6e925142ba26d9fe7bf))
|
|
51
|
+
|
|
52
|
+
## [1.4.0-beta.4](https://github.com/IvanRodriCalleja/tailwind-typescript-plugin/compare/v1.4.0-beta.3...v1.4.0-beta.4) (2025-11-27)
|
|
53
|
+
|
|
54
|
+
### ✨ Features
|
|
55
|
+
|
|
56
|
+
* warn on all duplicate class occurrences ([d01d878](https://github.com/IvanRodriCalleja/tailwind-typescript-plugin/commit/d01d87844da17e15d5608ddddb1e3fdc033c8d38))
|
|
57
|
+
|
|
58
|
+
### 🐛 Bug Fixes
|
|
59
|
+
|
|
60
|
+
* dispose plugin in benchmark to close file watchers ([9efdc6a](https://github.com/IvanRodriCalleja/tailwind-typescript-plugin/commit/9efdc6a8e24de4dd3000c44fc075bb765ddba1bb))
|
|
61
|
+
|
|
62
|
+
## [1.4.0-beta.3](https://github.com/IvanRodriCalleja/tailwind-typescript-plugin/compare/v1.4.0-beta.2...v1.4.0-beta.3) (2025-11-26)
|
|
63
|
+
|
|
64
|
+
### ✨ Features
|
|
65
|
+
|
|
66
|
+
* add hot reloading for global.css changes ([c215ae6](https://github.com/IvanRodriCalleja/tailwind-typescript-plugin/commit/c215ae68b71741b1909460df0d22606dbfd5c0f1)), closes [#ff0000](https://github.com/IvanRodriCalleja/tailwind-typescript-plugin/issues/ff0000)
|
|
67
|
+
|
|
68
|
+
## [1.4.0-beta.2](https://github.com/IvanRodriCalleja/tailwind-typescript-plugin/compare/v1.4.0-beta.1...v1.4.0-beta.2) (2025-11-26)
|
|
69
|
+
|
|
70
|
+
### ✨ Features
|
|
71
|
+
|
|
72
|
+
* add conflicting class detection ([a31c01a](https://github.com/IvanRodriCalleja/tailwind-typescript-plugin/commit/a31c01aa6e747e2949109273f7eec3f1b7ac4876))
|
|
73
|
+
|
|
1
74
|
## [1.4.0-beta.1](https://github.com/IvanRodriCalleja/tailwind-typescript-plugin/compare/v1.3.0...v1.4.0-beta.1) (2025-11-26)
|
|
2
75
|
|
|
3
76
|
### ✨ Features
|
package/README.md
CHANGED
|
@@ -33,6 +33,7 @@ Ever written `className="flex itms-center"` instead of `"flex items-center"`? Th
|
|
|
33
33
|
|
|
34
34
|
- **Real-time validation**: Get instant feedback on invalid Tailwind classes while you code
|
|
35
35
|
- **Duplicate class detection**: Warns when the same class appears multiple times in the same `className` attribute
|
|
36
|
+
- **Conflicting class detection**: Warns when Tailwind utilities that affect the same CSS property are used together (e.g., `text-left text-center`)
|
|
36
37
|
- **Editor integration**: Works with any editor that supports TypeScript Language Service (VS Code, WebStorm, etc.)
|
|
37
38
|
- **Supports Tailwind variants**: Validates responsive (`md:`, `lg:`), state (`hover:`, `focus:`), and other variants
|
|
38
39
|
- **Arbitrary values**: Correctly handles Tailwind arbitrary values like `h-[50vh]` or `bg-[#ff0000]`
|
|
@@ -81,15 +82,27 @@ Add the plugin to the `compilerOptions.plugins` array in your `tsconfig.json`:
|
|
|
81
82
|
|
|
82
83
|
- `globalCss` (required): Path to your global CSS file that imports Tailwind CSS. This can be relative to your project root.
|
|
83
84
|
|
|
84
|
-
- `allowedClasses` (optional): Array of custom class names that should be treated as valid alongside Tailwind classes. Useful for project-specific or third-party utility classes that aren't part of Tailwind.
|
|
85
|
+
- `allowedClasses` (optional): Array of custom class names or wildcard patterns that should be treated as valid alongside Tailwind classes. Useful for project-specific or third-party utility classes that aren't part of Tailwind.
|
|
85
86
|
- **Default**: `[]` (no custom classes allowed)
|
|
87
|
+
- **Supports wildcard patterns**:
|
|
88
|
+
| Pattern | Description | Example | Matches |
|
|
89
|
+
|---------|-------------|---------|---------|
|
|
90
|
+
| `prefix-*` | Matches classes starting with prefix | `custom-*` | `custom-button`, `custom-card` |
|
|
91
|
+
| `*-suffix` | Matches classes ending with suffix | `*-icon` | `arrow-icon`, `close-icon` |
|
|
92
|
+
| `*-contains-*` | Matches classes containing the string | `*-component-*` | `app-component-header` |
|
|
93
|
+
| `exact` | Exact match (no wildcards) | `my-class` | Only `my-class` |
|
|
86
94
|
- **Example**:
|
|
87
95
|
```json
|
|
88
96
|
{
|
|
89
|
-
"allowedClasses": [
|
|
97
|
+
"allowedClasses": [
|
|
98
|
+
"custom-*",
|
|
99
|
+
"*-icon",
|
|
100
|
+
"*-component-*",
|
|
101
|
+
"exact-class"
|
|
102
|
+
]
|
|
90
103
|
}
|
|
91
104
|
```
|
|
92
|
-
- Classes
|
|
105
|
+
- Classes matching any pattern will be considered valid and won't trigger validation errors
|
|
93
106
|
- Works with all extraction patterns (literals, expressions, functions, arrays, etc.)
|
|
94
107
|
- Combines with Tailwind classes - both are validated independently
|
|
95
108
|
|
|
@@ -127,34 +140,99 @@ Add the plugin to the `compilerOptions.plugins` array in your `tsconfig.json`:
|
|
|
127
140
|
```
|
|
128
141
|
- **Performance impact**: Disabling unused extractors skips TypeChecker operations and symbol resolution for that library, providing faster validation
|
|
129
142
|
|
|
130
|
-
- `utilityFunctions` (optional): Array of
|
|
131
|
-
- **Defaults (always included)**: `['clsx', 'cn', 'classnames', 'classNames', 'cx', 'cva', 'twMerge', 'tv']`
|
|
132
|
-
- **Add your own**: Provide custom function names that will be added to the defaults
|
|
133
|
-
- **Example config**:
|
|
134
|
-
```json
|
|
135
|
-
{
|
|
136
|
-
"utilityFunctions": ["myCustomFn", "buildClasses"]
|
|
137
|
-
}
|
|
138
|
-
```
|
|
139
|
-
This will validate: `clsx`, `cn`, `classnames`, `classNames`, `cx`, `cva`, `twMerge`, `tv`, **`myCustomFn`**, **`buildClasses`**
|
|
143
|
+
- `utilityFunctions` (optional): Array of utility functions to validate. These will be **merged with the defaults**, so you don't lose the common ones. Supports two formats:
|
|
140
144
|
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
145
|
+
**Simple string format** (matches by function name only):
|
|
146
|
+
```json
|
|
147
|
+
{
|
|
148
|
+
"utilityFunctions": ["myCustomFn", "buildClasses"]
|
|
149
|
+
}
|
|
150
|
+
```
|
|
151
|
+
|
|
152
|
+
**Object format with import verification** (matches by name AND verifies import source):
|
|
153
|
+
```json
|
|
154
|
+
{
|
|
155
|
+
"utilityFunctions": [
|
|
156
|
+
{ "name": "merge", "from": "@/lib/utils" },
|
|
157
|
+
{ "name": "cx", "from": "my-styling-package" }
|
|
158
|
+
]
|
|
159
|
+
}
|
|
160
|
+
```
|
|
161
|
+
|
|
162
|
+
**Mixed format** (combine both):
|
|
163
|
+
```json
|
|
164
|
+
{
|
|
165
|
+
"utilityFunctions": [
|
|
166
|
+
"anyFunctionNamedThis",
|
|
167
|
+
{ "name": "merge", "from": "@/lib/utils" }
|
|
168
|
+
]
|
|
169
|
+
}
|
|
170
|
+
```
|
|
146
171
|
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
172
|
+
- **Defaults (always included)**: `clsx` (from 'clsx'), `cn` (name-only), `classnames`/`classNames`/`cx` (from 'classnames'), `twMerge` (from 'tailwind-merge'). Note: `cva` and `tv` are variant functions handled by dedicated extractors.
|
|
173
|
+
- **Import verification**: When using the object format with `from`, the plugin verifies the function is actually imported from that package before validating. This prevents false positives when a function with the same name exists but isn't a className utility.
|
|
174
|
+
- **Subpath matching**: `{ "name": "fn", "from": "my-pkg" }` also matches `import { fn } from 'my-pkg/utils'`
|
|
150
175
|
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
176
|
+
**Example configurations**:
|
|
177
|
+
```json
|
|
178
|
+
// Simple: just add function names
|
|
179
|
+
{
|
|
180
|
+
"utilityFunctions": ["myCustomFn", "buildClasses"]
|
|
181
|
+
}
|
|
154
182
|
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
183
|
+
// Precise: verify import sources
|
|
184
|
+
{
|
|
185
|
+
"utilityFunctions": [
|
|
186
|
+
{ "name": "cn", "from": "@/lib/utils" },
|
|
187
|
+
{ "name": "merge", "from": "tailwind-merge" }
|
|
188
|
+
]
|
|
189
|
+
}
|
|
190
|
+
|
|
191
|
+
// Mixed: some with import verification, some without
|
|
192
|
+
{
|
|
193
|
+
"utilityFunctions": [
|
|
194
|
+
"anyFn",
|
|
195
|
+
{ "name": "preciseFn", "from": "@/utils" }
|
|
196
|
+
]
|
|
197
|
+
}
|
|
198
|
+
```
|
|
199
|
+
|
|
200
|
+
**Supported import patterns**:
|
|
201
|
+
```typescript
|
|
202
|
+
// Named import
|
|
203
|
+
import { merge } from '@/lib/utils';
|
|
204
|
+
className={merge('flex', 'items-center')} // ✅ Validated
|
|
205
|
+
|
|
206
|
+
// Default import
|
|
207
|
+
import merge from '@/lib/utils';
|
|
208
|
+
className={merge('flex', 'items-center')} // ✅ Validated
|
|
209
|
+
|
|
210
|
+
// Aliased import
|
|
211
|
+
import { something as merge } from '@/lib/utils';
|
|
212
|
+
className={merge('flex', 'items-center')} // ✅ Validated
|
|
213
|
+
|
|
214
|
+
// Wrong import source (not validated when using object format)
|
|
215
|
+
import { merge } from 'different-package';
|
|
216
|
+
className={merge('flex', 'invalid-class')} // ⏭️ Skipped (wrong import)
|
|
217
|
+
```
|
|
218
|
+
|
|
219
|
+
**Supported call patterns**:
|
|
220
|
+
```typescript
|
|
221
|
+
// Simple calls (validated by default):
|
|
222
|
+
className={clsx('flex', 'items-center')}
|
|
223
|
+
className={cn('flex', 'items-center')}
|
|
224
|
+
|
|
225
|
+
// Member expressions (nested property access):
|
|
226
|
+
className={utils.cn('flex', 'items-center')}
|
|
227
|
+
className={lib.clsx('flex', 'items-center')}
|
|
228
|
+
|
|
229
|
+
// Custom functions (add via config):
|
|
230
|
+
className={myCustomFn('flex', 'items-center')}
|
|
231
|
+
className={buildClasses('flex', 'items-center')}
|
|
232
|
+
|
|
233
|
+
// Dynamic calls (ignored, won't throw errors):
|
|
234
|
+
className={functions['cn']('flex', 'items-center')}
|
|
235
|
+
```
|
|
158
236
|
|
|
159
237
|
### 2. Ensure your CSS file imports Tailwind
|
|
160
238
|
|
|
@@ -244,6 +322,18 @@ const validClass = 'flex items-center';
|
|
|
244
322
|
const baseClass = 'flex';
|
|
245
323
|
<div className={[baseClass, 'items-center']}>Array with variable</div>
|
|
246
324
|
|
|
325
|
+
// ✅ Spread operator in arrays
|
|
326
|
+
const baseClasses = ['flex', 'items-center'];
|
|
327
|
+
<div className={[...baseClasses, 'p-4']}>Spread in array</div>
|
|
328
|
+
|
|
329
|
+
// ✅ Spread operator in function calls
|
|
330
|
+
<div className={cn(...baseClasses, 'p-4')}>Spread in function</div>
|
|
331
|
+
|
|
332
|
+
// ✅ Multiple spreads
|
|
333
|
+
const layoutClasses = ['flex', 'items-center'];
|
|
334
|
+
const spacingClasses = ['p-4', 'm-2'];
|
|
335
|
+
<div className={cn(...layoutClasses, ...spacingClasses)}>Multiple spreads</div>
|
|
336
|
+
|
|
247
337
|
// ✅ Variables in tv() and cva()
|
|
248
338
|
const buttonBase = 'font-semibold text-white';
|
|
249
339
|
const button = tv({ base: buttonBase });
|
|
@@ -274,6 +364,14 @@ const badClass = 'invalid-array-class';
|
|
|
274
364
|
// Error: The class "invalid-array-class" is not a valid Tailwind class.
|
|
275
365
|
// This value is used as className via variable "badClass" on line 8
|
|
276
366
|
<div className={['flex', badClass]}>Array with invalid variable</div>
|
|
367
|
+
|
|
368
|
+
// ❌ Invalid class in spread operator
|
|
369
|
+
const invalidClasses = ['flex', 'invalid-spread-class'];
|
|
370
|
+
// Error: The class "invalid-spread-class" is not a valid Tailwind class.
|
|
371
|
+
<div className={[...invalidClasses, 'items-center']}>Spread with invalid</div>
|
|
372
|
+
|
|
373
|
+
// ❌ Invalid class in spread within function call
|
|
374
|
+
<div className={cn(...invalidClasses, 'p-4')}>Function spread with invalid</div>
|
|
277
375
|
```
|
|
278
376
|
|
|
279
377
|
**Custom allowed classes**:
|
|
@@ -325,6 +423,18 @@ The plugin detects duplicate classes within the same `className` attribute and s
|
|
|
325
423
|
<div className={cn(['flex', 'flex', 'items-center'])}>In array</div>
|
|
326
424
|
// Warning: Duplicate class "flex"
|
|
327
425
|
|
|
426
|
+
// ⚠️ Warning: Duplicates with spread operators
|
|
427
|
+
const baseClasses = ['flex', 'items-center'];
|
|
428
|
+
<div className={cn(...baseClasses, 'flex', 'items-center', 'p-4')}>Spread duplicates</div>
|
|
429
|
+
// Warning: Duplicate class "flex"
|
|
430
|
+
// Warning: Duplicate class "items-center"
|
|
431
|
+
|
|
432
|
+
// ⚠️ Warning: Duplicates between multiple spreads
|
|
433
|
+
const layoutClasses = ['flex', 'items-center'];
|
|
434
|
+
const containerClasses = ['flex', 'justify-center'];
|
|
435
|
+
<div className={cn(...layoutClasses, ...containerClasses)}>Multiple spread duplicates</div>
|
|
436
|
+
// Warning: Duplicate class "flex"
|
|
437
|
+
|
|
328
438
|
// ✅ Valid: Same class in DIFFERENT elements (not duplicates)
|
|
329
439
|
<div className="flex items-center">
|
|
330
440
|
<span className="flex justify-center">Different elements</span>
|
|
@@ -387,6 +497,179 @@ const conditionalOneBranch = isActive ? 'flex bg-blue-500' : 'bg-gray-500';
|
|
|
387
497
|
// No warning - 'flex' only appears in the true branch of the variable
|
|
388
498
|
```
|
|
389
499
|
|
|
500
|
+
**Conflicting class detection**:
|
|
501
|
+
|
|
502
|
+
The plugin detects when you use multiple Tailwind utilities that affect the same CSS property. This catches common mistakes where conflicting styles cancel each other out.
|
|
503
|
+
|
|
504
|
+
```tsx
|
|
505
|
+
// ⚠️ Warning: Text alignment conflict (both affect text-align)
|
|
506
|
+
<div className="text-left text-center">Conflicting alignment</div>
|
|
507
|
+
// Warning: Class "text-left" conflicts with "text-center". Both affect the text-align property.
|
|
508
|
+
// Warning: Class "text-center" conflicts with "text-left". Both affect the text-align property.
|
|
509
|
+
|
|
510
|
+
// ⚠️ Warning: Display conflict (both affect display)
|
|
511
|
+
<div className="flex block">Conflicting display</div>
|
|
512
|
+
// Warning: Class "flex" conflicts with "block". Both affect the display property.
|
|
513
|
+
// Warning: Class "block" conflicts with "flex". Both affect the display property.
|
|
514
|
+
|
|
515
|
+
// ⚠️ Warning: Position conflict
|
|
516
|
+
<div className="absolute relative">Conflicting position</div>
|
|
517
|
+
// Warning: Class "absolute" conflicts with "relative". Both affect the position property.
|
|
518
|
+
|
|
519
|
+
// ⚠️ Warning: Flex direction conflict
|
|
520
|
+
<div className="flex-row flex-col">Conflicting direction</div>
|
|
521
|
+
// Warning: Class "flex-row" conflicts with "flex-col". Both affect the flex-direction property.
|
|
522
|
+
|
|
523
|
+
// ⚠️ Warning: Justify content conflict
|
|
524
|
+
<div className="justify-start justify-center">Conflicting justify</div>
|
|
525
|
+
// Warning: Class "justify-start" conflicts with "justify-center". Both affect the justify-content property.
|
|
526
|
+
|
|
527
|
+
// ⚠️ Warning: Align items conflict
|
|
528
|
+
<div className="items-start items-center">Conflicting alignment</div>
|
|
529
|
+
// Warning: Class "items-start" conflicts with "items-center". Both affect the align-items property.
|
|
530
|
+
|
|
531
|
+
// ✅ Valid: Different utilities (no conflict)
|
|
532
|
+
<div className="flex items-center justify-between">No conflict</div>
|
|
533
|
+
|
|
534
|
+
// ✅ Valid: Same class in different elements
|
|
535
|
+
<div className="text-left">
|
|
536
|
+
<span className="text-center">Different elements</span>
|
|
537
|
+
</div>
|
|
538
|
+
```
|
|
539
|
+
|
|
540
|
+
**Responsive and state variants**:
|
|
541
|
+
|
|
542
|
+
The plugin correctly handles responsive and state variants - conflicts are only flagged when the same variant prefix is used:
|
|
543
|
+
|
|
544
|
+
```tsx
|
|
545
|
+
// ⚠️ Warning: Same variant prefix = conflict
|
|
546
|
+
<div className="md:text-left md:text-center">Conflict at md breakpoint</div>
|
|
547
|
+
// Warning: Both classes affect text-align at the md: breakpoint
|
|
548
|
+
|
|
549
|
+
// ✅ Valid: Different breakpoints = no conflict
|
|
550
|
+
<div className="sm:text-left md:text-center lg:text-right">No conflict</div>
|
|
551
|
+
// Each breakpoint has its own text-align value
|
|
552
|
+
|
|
553
|
+
// ⚠️ Warning: Same state variant = conflict
|
|
554
|
+
<div className="hover:flex hover:block">Conflict on hover</div>
|
|
555
|
+
// Warning: Both classes affect display on hover
|
|
556
|
+
|
|
557
|
+
// ✅ Valid: Different state variants = no conflict
|
|
558
|
+
<div className="hover:flex focus:block">No conflict</div>
|
|
559
|
+
// Different states trigger different display values
|
|
560
|
+
```
|
|
561
|
+
|
|
562
|
+
**Ternary conditional expressions**:
|
|
563
|
+
|
|
564
|
+
The plugin intelligently handles ternary expressions - conflicts are NOT flagged between mutually exclusive branches:
|
|
565
|
+
|
|
566
|
+
```tsx
|
|
567
|
+
// ✅ Valid: Different ternary branches = no conflict
|
|
568
|
+
<div className={clsx(isActive ? 'text-left' : 'text-center')}>No conflict</div>
|
|
569
|
+
// Only one branch executes at runtime
|
|
570
|
+
|
|
571
|
+
// ⚠️ Warning: Root conflicts with branch
|
|
572
|
+
<div className={clsx('text-left', isActive ? 'text-center' : 'bg-gray-500')}>Conflict</div>
|
|
573
|
+
// Warning: 'text-left' at root conflicts with 'text-center' in true branch
|
|
574
|
+
|
|
575
|
+
// ⚠️ Warning: Conflict within same branch
|
|
576
|
+
<div className={clsx(isActive ? 'text-left text-center' : 'bg-gray-500')}>Conflict</div>
|
|
577
|
+
// Warning: Conflict within the true branch
|
|
578
|
+
```
|
|
579
|
+
|
|
580
|
+
**Conflicts in utility functions**:
|
|
581
|
+
|
|
582
|
+
```tsx
|
|
583
|
+
// ⚠️ Warning: Conflicts detected in clsx/cn arguments
|
|
584
|
+
<div className={clsx('flex', 'block', 'items-center')}>Conflict</div>
|
|
585
|
+
// Warning: Class "flex" conflicts with "block". Both affect the display property.
|
|
586
|
+
|
|
587
|
+
<div className={cn('text-left', 'text-right')}>Conflict</div>
|
|
588
|
+
// Warning: Both classes affect text-align
|
|
589
|
+
```
|
|
590
|
+
|
|
591
|
+
**Conflicts with spread operators**:
|
|
592
|
+
|
|
593
|
+
```tsx
|
|
594
|
+
// ⚠️ Warning: Conflicts with spread operator
|
|
595
|
+
const baseClasses = ['flex', 'p-4'];
|
|
596
|
+
<div className={cn(...baseClasses, 'p-2', 'items-center')}>Spread conflict</div>
|
|
597
|
+
// Warning: Class "p-4" conflicts with "p-2". Both affect the padding property.
|
|
598
|
+
|
|
599
|
+
// ⚠️ Warning: Conflicts between multiple spreads
|
|
600
|
+
const smallText = ['text-sm', 'font-medium'];
|
|
601
|
+
const largeText = ['text-lg', 'font-bold'];
|
|
602
|
+
<div className={cn(...smallText, ...largeText)}>Multiple spread conflicts</div>
|
|
603
|
+
// Warning: Class "text-sm" conflicts with "text-lg". Both affect the font-size property.
|
|
604
|
+
// Warning: Class "font-medium" conflicts with "font-bold". Both affect the font-weight property.
|
|
605
|
+
```
|
|
606
|
+
|
|
607
|
+
**Conflicts in tv() and cva()**:
|
|
608
|
+
|
|
609
|
+
The plugin detects conflicts within `tv()` and `cva()` base properties, but intelligently skips conflicts between base and variants since variants are designed to override base styles:
|
|
610
|
+
|
|
611
|
+
```tsx
|
|
612
|
+
import { tv } from 'tailwind-variants';
|
|
613
|
+
import { cva } from 'class-variance-authority';
|
|
614
|
+
|
|
615
|
+
// ⚠️ Warning: Conflict in tv() base
|
|
616
|
+
const button = tv({
|
|
617
|
+
base: 'flex block items-center'
|
|
618
|
+
// Warning: "flex" conflicts with "block"
|
|
619
|
+
});
|
|
620
|
+
|
|
621
|
+
// ✅ Valid: Base vs variant = NO conflict (intentional override)
|
|
622
|
+
const button2 = tv({
|
|
623
|
+
base: 'text-left items-center',
|
|
624
|
+
variants: {
|
|
625
|
+
align: {
|
|
626
|
+
center: 'text-center' // This is designed to override base
|
|
627
|
+
}
|
|
628
|
+
}
|
|
629
|
+
});
|
|
630
|
+
// No warning - variants intentionally override base styles
|
|
631
|
+
|
|
632
|
+
// ⚠️ Warning: Conflict in cva() base
|
|
633
|
+
const card = cva(['flex', 'grid', 'items-center']);
|
|
634
|
+
// Warning: "flex" conflicts with "grid"
|
|
635
|
+
|
|
636
|
+
// ✅ Valid: Base vs variant = NO conflict
|
|
637
|
+
const card2 = cva(['justify-start'], {
|
|
638
|
+
variants: {
|
|
639
|
+
centered: {
|
|
640
|
+
true: ['justify-center'] // Designed to override
|
|
641
|
+
}
|
|
642
|
+
}
|
|
643
|
+
});
|
|
644
|
+
// No warning - variant overrides base
|
|
645
|
+
|
|
646
|
+
// ✅ Valid: Different tv()/cva() calls = no conflict
|
|
647
|
+
const buttonA = tv({ base: 'text-left' });
|
|
648
|
+
const buttonB = tv({ base: 'text-center' });
|
|
649
|
+
// No warning - each call has its own scope
|
|
650
|
+
```
|
|
651
|
+
|
|
652
|
+
**Detected conflict groups**:
|
|
653
|
+
|
|
654
|
+
The plugin detects conflicts in these CSS property groups:
|
|
655
|
+
|
|
656
|
+
| CSS Property | Conflicting Classes |
|
|
657
|
+
|--------------|---------------------|
|
|
658
|
+
| `text-align` | `text-left`, `text-center`, `text-right`, `text-justify`, `text-start`, `text-end` |
|
|
659
|
+
| `display` | `block`, `inline-block`, `inline`, `flex`, `inline-flex`, `grid`, `inline-grid`, `hidden`, `table`, `contents`, `flow-root`, `list-item` |
|
|
660
|
+
| `position` | `static`, `relative`, `absolute`, `fixed`, `sticky` |
|
|
661
|
+
| `flex-direction` | `flex-row`, `flex-row-reverse`, `flex-col`, `flex-col-reverse` |
|
|
662
|
+
| `justify-content` | `justify-start`, `justify-end`, `justify-center`, `justify-between`, `justify-around`, `justify-evenly`, `justify-stretch`, `justify-normal` |
|
|
663
|
+
| `align-items` | `items-start`, `items-end`, `items-center`, `items-baseline`, `items-stretch` |
|
|
664
|
+
| `visibility` | `visible`, `invisible`, `collapse` |
|
|
665
|
+
| `overflow` | `overflow-auto`, `overflow-hidden`, `overflow-clip`, `overflow-visible`, `overflow-scroll` |
|
|
666
|
+
| `font-style` | `italic`, `not-italic` |
|
|
667
|
+
| `text-transform` | `uppercase`, `lowercase`, `capitalize`, `normal-case` |
|
|
668
|
+
| `whitespace` | `whitespace-normal`, `whitespace-nowrap`, `whitespace-pre`, `whitespace-pre-line`, `whitespace-pre-wrap`, `whitespace-break-spaces` |
|
|
669
|
+
| `text-wrap` | `text-wrap`, `text-nowrap`, `text-balance`, `text-pretty` |
|
|
670
|
+
| `cursor` | `cursor-auto`, `cursor-default`, `cursor-pointer`, `cursor-wait`, `cursor-text`, `cursor-move`, `cursor-help`, `cursor-not-allowed`, `cursor-none`, `cursor-context-menu`, `cursor-progress`, `cursor-cell`, `cursor-crosshair`, `cursor-vertical-text`, `cursor-alias`, `cursor-copy`, `cursor-no-drop`, `cursor-grab`, `cursor-grabbing`, `cursor-all-scroll`, `cursor-col-resize`, `cursor-row-resize`, `cursor-n-resize`, `cursor-e-resize`, `cursor-s-resize`, `cursor-w-resize`, `cursor-ne-resize`, `cursor-nw-resize`, `cursor-se-resize`, `cursor-sw-resize`, `cursor-ew-resize`, `cursor-ns-resize`, `cursor-nesw-resize`, `cursor-nwse-resize`, `cursor-zoom-in`, `cursor-zoom-out` |
|
|
671
|
+
| And more... | `flex-wrap`, `align-content`, `align-self`, `justify-items`, `justify-self`, `float`, `clear`, `box-sizing`, `isolation`, `object-fit`, `pointer-events`, `resize`, `user-select`, `table-layout`, `border-collapse`, `caption-side` |
|
|
672
|
+
|
|
390
673
|
**tailwind-variants validation**:
|
|
391
674
|
```tsx
|
|
392
675
|
import { tv } from 'tailwind-variants';
|
|
@@ -676,6 +959,15 @@ const card2 = tv({ base: 'flex justify-center' });
|
|
|
676
959
|
Validates variables used in computed object property keys
|
|
677
960
|
Example: `const myClass = 'invalid-class'; <div className={{ [myClass]: true }}>Object</div>`
|
|
678
961
|
|
|
962
|
+
- [X] **Spread Operator** → [`test-spread-operator/`](./example/src/test-spread-operator/)
|
|
963
|
+
Validates spread operators in arrays and function calls
|
|
964
|
+
Example: `const base = ['flex', 'invalid']; <div className={[...base, 'p-4']}>Spread</div>`
|
|
965
|
+
- Spread in arrays: `className={[...baseClasses, 'p-4']}`
|
|
966
|
+
- Spread in function calls: `className={cn(...baseClasses, 'p-4')}`
|
|
967
|
+
- Multiple spreads: `className={cn(...layoutClasses, ...spacingClasses)}`
|
|
968
|
+
- Nested spreads: Variables containing arrays with spreads are resolved
|
|
969
|
+
- Detects invalid classes, duplicates, and conflicts within spread expressions
|
|
970
|
+
|
|
679
971
|
- [X] **TV Variable** → [`tv-variable.tsx`](./example/src/tv-variable.tsx)
|
|
680
972
|
Validates variables in tailwind-variants tv() definitions
|
|
681
973
|
Example: `const baseClasses = 'invalid-class'; const button = tv({ base: baseClasses })`
|
|
@@ -684,19 +976,19 @@ const card2 = tv({ base: 'flex justify-center' });
|
|
|
684
976
|
Validates variables in class-variance-authority cva() definitions
|
|
685
977
|
Example: `const baseClasses = 'invalid-class'; const button = cva(baseClasses)`
|
|
686
978
|
|
|
687
|
-
- [X] **Duplicate Classes** → [`duplicate-classes
|
|
979
|
+
- [X] **Duplicate Classes** → [`duplicate-classes/`](./example/src/duplicate-classes/)
|
|
688
980
|
Detects duplicate classes within the same className attribute
|
|
689
|
-
Example: `className="flex flex items-center"` shows warning on
|
|
981
|
+
Example: `className="flex flex items-center"` shows warning on both `flex` occurrences
|
|
690
982
|
|
|
691
|
-
- [X] **Duplicate Classes in Ternary** → [`duplicate-classes
|
|
983
|
+
- [X] **Duplicate Classes in Ternary** → [`duplicate-classes/`](./example/src/duplicate-classes/)
|
|
692
984
|
Smart detection of duplicates in ternary expressions:
|
|
693
|
-
- Root + branch duplicate: `clsx('flex', isActive ? 'flex' : 'flex')` → Warning
|
|
985
|
+
- Root + branch duplicate: `clsx('flex', isActive ? 'flex' : 'flex')` → Warning on all occurrences
|
|
694
986
|
- Both branches same class: `clsx('mt-4', isActive ? 'flex' : 'flex')` → Warning (consider extracting)
|
|
695
987
|
- Single branch only: `clsx('mt-4', isActive ? 'flex' : '')` → No warning (valid pattern)
|
|
696
988
|
|
|
697
|
-
- [X] **Duplicate Classes in Variables with Conditionals** → [`duplicate-classes
|
|
989
|
+
- [X] **Duplicate Classes in Variables with Conditionals** → [`duplicate-classes/`](./example/src/duplicate-classes/)
|
|
698
990
|
Resolves variables containing ternary expressions and detects duplicates:
|
|
699
|
-
- `const x = isActive ? 'flex' : 'flex'; clsx('flex', x)` → Warning
|
|
991
|
+
- `const x = isActive ? 'flex' : 'flex'; clsx('flex', x)` → Warning on all occurrences
|
|
700
992
|
- `const x = isActive ? 'flex' : 'flex'; clsx('mt-4', x)` → Warning (consider extracting from variable)
|
|
701
993
|
- `const x = isActive ? 'flex' : ''; clsx('mt-4', x)` → No warning (single branch)
|
|
702
994
|
|
|
@@ -712,6 +1004,25 @@ const card2 = tv({ base: 'flex justify-center' });
|
|
|
712
1004
|
- Duplicates detected across base array/string, variants, and compoundVariants
|
|
713
1005
|
- Same class in different cva() calls is NOT a duplicate (scoped per call)
|
|
714
1006
|
|
|
1007
|
+
- [X] **Conflicting Classes** → [`conflicting-classes.tsx`](./example/src/conflicting-classes.tsx)
|
|
1008
|
+
Detects conflicting Tailwind utilities that affect the same CSS property
|
|
1009
|
+
Example: `className="text-left text-center"` → Warning on both classes
|
|
1010
|
+
- Detects conflicts in 50+ CSS property groups (display, position, text-align, flex-direction, etc.)
|
|
1011
|
+
- Handles responsive/state variants: `md:text-left md:text-center` = conflict, `sm:text-left md:text-center` = no conflict
|
|
1012
|
+
- Smart ternary handling: mutually exclusive branches don't conflict
|
|
1013
|
+
- Works with clsx, cn, tv(), cva() and other utility functions
|
|
1014
|
+
- tv()/cva() base vs variant: NO conflict (variants are designed to override base)
|
|
1015
|
+
|
|
1016
|
+
- [X] **Utility Function Import Verification** → [`utility-function-imports/`](./example/src/utility-function-imports/)
|
|
1017
|
+
Validates custom utility functions with optional import source verification
|
|
1018
|
+
Example: `{ "name": "merge", "from": "@/lib/utils" }` only validates `merge()` if imported from `@/lib/utils`
|
|
1019
|
+
- Supports simple string format (name-only matching) and object format (with import verification)
|
|
1020
|
+
- Named imports: `import { merge } from '@/lib/utils'`
|
|
1021
|
+
- Default imports: `import merge from '@/lib/utils'`
|
|
1022
|
+
- Aliased imports: `import { something as merge } from '@/lib/utils'`
|
|
1023
|
+
- Subpath matching: `{ "from": "my-pkg" }` matches `import from 'my-pkg/utils'`
|
|
1024
|
+
- Functions from wrong import sources are skipped (prevents false positives)
|
|
1025
|
+
|
|
715
1026
|
## How It Works
|
|
716
1027
|
|
|
717
1028
|
The plugin hooks into the TypeScript Language Service and:
|
|
@@ -735,6 +1046,34 @@ The plugin is designed for minimal performance impact:
|
|
|
735
1046
|
|
|
736
1047
|
**Typical overhead**: <1ms per file for most files, ~2-3ms for files with many tv()/cva() calls
|
|
737
1048
|
|
|
1049
|
+
## Hot Reloading
|
|
1050
|
+
|
|
1051
|
+
The plugin automatically watches your global CSS file for changes. When you modify your Tailwind configuration or add custom classes in your CSS file, the plugin will:
|
|
1052
|
+
|
|
1053
|
+
1. **Detect changes** - Watches the `globalCss` file specified in your `tsconfig.json`
|
|
1054
|
+
2. **Reload the design system** - Automatically re-parses your Tailwind configuration
|
|
1055
|
+
3. **Clear caches** - Invalidates all diagnostic caches
|
|
1056
|
+
4. **Refresh diagnostics** - Requests TypeScript to revalidate all open files
|
|
1057
|
+
|
|
1058
|
+
This means you can add new custom classes or modify your Tailwind theme, and the plugin will immediately recognize them without restarting your editor or TypeScript server.
|
|
1059
|
+
|
|
1060
|
+
```css
|
|
1061
|
+
/* global.css */
|
|
1062
|
+
@import "tailwindcss";
|
|
1063
|
+
|
|
1064
|
+
/* Add a custom utility - plugin will recognize it after save */
|
|
1065
|
+
@utility custom-gradient {
|
|
1066
|
+
background: linear-gradient(to right, #ff7e5f, #feb47b);
|
|
1067
|
+
}
|
|
1068
|
+
```
|
|
1069
|
+
|
|
1070
|
+
```tsx
|
|
1071
|
+
// This will be valid immediately after saving global.css
|
|
1072
|
+
<div className="custom-gradient">Hot reloaded!</div>
|
|
1073
|
+
```
|
|
1074
|
+
|
|
1075
|
+
**Note**: The file watcher uses debouncing (300ms) to avoid excessive reloads when making rapid changes.
|
|
1076
|
+
|
|
738
1077
|
## Development
|
|
739
1078
|
|
|
740
1079
|
This is a monorepo using Yarn workspaces:
|
|
@@ -777,7 +1116,7 @@ Commit to main → Auto-publishes 1.0.33-beta.3
|
|
|
777
1116
|
|
|
778
1117
|
Users can install beta versions:
|
|
779
1118
|
```bash
|
|
780
|
-
npm install typescript-
|
|
1119
|
+
npm install tailwind-typescript-plugin@beta
|
|
781
1120
|
```
|
|
782
1121
|
|
|
783
1122
|
### Stable Releases (Manual)
|
package/lib/core/interfaces.d.ts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import * as ts from 'typescript/lib/tsserverlibrary';
|
|
2
|
-
import { ClassNameInfo, ExtractionContext } from './types';
|
|
2
|
+
import { ClassNameInfo, ExtractionContext, UtilityFunction } from './types';
|
|
3
3
|
/**
|
|
4
4
|
* Base interface for class name extractors
|
|
5
5
|
* Follows the Strategy pattern for extensibility
|
|
@@ -34,7 +34,7 @@ export interface IVariantsConfig {
|
|
|
34
34
|
*/
|
|
35
35
|
export interface IPluginConfig {
|
|
36
36
|
globalCss?: string;
|
|
37
|
-
utilityFunctions?:
|
|
37
|
+
utilityFunctions?: UtilityFunction[];
|
|
38
38
|
variants?: IVariantsConfig;
|
|
39
39
|
allowedClasses?: string[];
|
|
40
40
|
enableLogging?: boolean;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"interfaces.d.ts","sourceRoot":"","sources":["../../src/core/interfaces.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,MAAM,gCAAgC,CAAC;AAErD,OAAO,EAAE,aAAa,EAAE,iBAAiB,EAAE,MAAM,SAAS,CAAC;
|
|
1
|
+
{"version":3,"file":"interfaces.d.ts","sourceRoot":"","sources":["../../src/core/interfaces.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,MAAM,gCAAgC,CAAC;AAErD,OAAO,EAAE,aAAa,EAAE,iBAAiB,EAAE,eAAe,EAAE,MAAM,SAAS,CAAC;AAE5E;;;GAGG;AACH,MAAM,WAAW,mBAAmB;IACnC;;OAEG;IACH,SAAS,CAAC,IAAI,EAAE,EAAE,CAAC,IAAI,EAAE,OAAO,EAAE,iBAAiB,GAAG,OAAO,CAAC;IAE9D;;OAEG;IACH,OAAO,CAAC,IAAI,EAAE,EAAE,CAAC,IAAI,EAAE,OAAO,EAAE,iBAAiB,GAAG,aAAa,EAAE,CAAC;CACpE;AAED;;GAEG;AACH,MAAM,WAAW,mBAAmB;IACnC,YAAY,CAAC,SAAS,EAAE,MAAM,GAAG,OAAO,CAAC;IACzC,aAAa,IAAI,OAAO,CAAC;IACzB,iBAAiB,CAAC,cAAc,EAAE,MAAM,EAAE,GAAG,IAAI,CAAC;CAClD;AAED;;GAEG;AACH,MAAM,WAAW,eAAe;IAC/B,gBAAgB,CAAC,EAAE,OAAO,CAAC;IAC3B,sBAAsB,CAAC,EAAE,OAAO,CAAC;CACjC;AAED;;GAEG;AACH,MAAM,WAAW,aAAa;IAC7B,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,gBAAgB,CAAC,EAAE,eAAe,EAAE,CAAC;IACrC,QAAQ,CAAC,EAAE,eAAe,CAAC;IAC3B,cAAc,CAAC,EAAE,MAAM,EAAE,CAAC;IAC1B,aAAa,CAAC,EAAE,OAAO,CAAC;CACxB;AAED;;GAEG;AACH,MAAM,WAAW,kBAAkB;IAClC,gBAAgB,CAAC,SAAS,EAAE,aAAa,EAAE,UAAU,EAAE,EAAE,CAAC,UAAU,GAAG,EAAE,CAAC,UAAU,CAAC;CACrF"}
|
package/lib/core/types.d.ts
CHANGED
|
@@ -1,4 +1,22 @@
|
|
|
1
1
|
import * as ts from 'typescript/lib/tsserverlibrary';
|
|
2
|
+
/**
|
|
3
|
+
* Represents a utility function configuration with optional import source
|
|
4
|
+
* When 'from' is specified, the import will be verified before matching
|
|
5
|
+
*
|
|
6
|
+
* Examples:
|
|
7
|
+
* - { name: 'clsx', from: 'clsx' } - matches `import { clsx } from 'clsx'` or `import clsx from 'clsx'`
|
|
8
|
+
* - { name: 'cn', from: '@/lib/utils' } - matches `import { cn } from '@/lib/utils'`
|
|
9
|
+
*/
|
|
10
|
+
export interface UtilityFunctionConfig {
|
|
11
|
+
name: string;
|
|
12
|
+
from: string;
|
|
13
|
+
}
|
|
14
|
+
/**
|
|
15
|
+
* A utility function can be either:
|
|
16
|
+
* - A simple string (matches by function name only, backwards compatible)
|
|
17
|
+
* - A UtilityFunctionConfig object (matches by name AND verifies import source)
|
|
18
|
+
*/
|
|
19
|
+
export type UtilityFunction = string | UtilityFunctionConfig;
|
|
2
20
|
/**
|
|
3
21
|
* Represents information about a class name found in source code
|
|
4
22
|
*/
|
|
@@ -30,6 +48,14 @@ export interface ClassNameInfo {
|
|
|
30
48
|
* Used to distinguish true duplicates from classes repeated in mutually exclusive branches.
|
|
31
49
|
*/
|
|
32
50
|
conditionalBranchId?: string;
|
|
51
|
+
/**
|
|
52
|
+
* Indicates if this class comes from a variant context in tv() or cva().
|
|
53
|
+
* - undefined or false: Class is from base/root (always applied)
|
|
54
|
+
* - true: Class is from a variant (only applied when variant is selected)
|
|
55
|
+
* Used to avoid flagging conflicts between base and variant classes,
|
|
56
|
+
* since variants are intentionally designed to override base styles.
|
|
57
|
+
*/
|
|
58
|
+
isVariant?: boolean;
|
|
33
59
|
}
|
|
34
60
|
/**
|
|
35
61
|
* Context provided to extractors for class name extraction
|
|
@@ -37,7 +63,7 @@ export interface ClassNameInfo {
|
|
|
37
63
|
export interface ExtractionContext {
|
|
38
64
|
readonly typescript: typeof ts;
|
|
39
65
|
readonly sourceFile: ts.SourceFile;
|
|
40
|
-
readonly utilityFunctions:
|
|
66
|
+
readonly utilityFunctions: UtilityFunction[];
|
|
41
67
|
readonly typeChecker?: ts.TypeChecker;
|
|
42
68
|
}
|
|
43
69
|
/**
|
package/lib/core/types.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../src/core/types.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,MAAM,gCAAgC,CAAC;AAErD;;GAEG;AACH,MAAM,WAAW,aAAa;IAC7B,SAAS,EAAE,MAAM,CAAC;IAClB,aAAa,EAAE,MAAM,CAAC;IACtB,MAAM,EAAE,MAAM,CAAC;IACf,IAAI,EAAE,MAAM,CAAC;IACb,IAAI,EAAE,MAAM,CAAC;IACb;;;OAGG;IACH,aAAa,CAAC,EAAE;QACf,YAAY,EAAE,MAAM,CAAC;QACrB,SAAS,EAAE,MAAM,CAAC;KAClB,CAAC;IACF;;;;OAIG;IACH,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB;;;;;;OAMG;IACH,mBAAmB,CAAC,EAAE,MAAM,CAAC;
|
|
1
|
+
{"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../src/core/types.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,MAAM,gCAAgC,CAAC;AAErD;;;;;;;GAOG;AACH,MAAM,WAAW,qBAAqB;IACrC,IAAI,EAAE,MAAM,CAAC;IACb,IAAI,EAAE,MAAM,CAAC;CACb;AAED;;;;GAIG;AACH,MAAM,MAAM,eAAe,GAAG,MAAM,GAAG,qBAAqB,CAAC;AAE7D;;GAEG;AACH,MAAM,WAAW,aAAa;IAC7B,SAAS,EAAE,MAAM,CAAC;IAClB,aAAa,EAAE,MAAM,CAAC;IACtB,MAAM,EAAE,MAAM,CAAC;IACf,IAAI,EAAE,MAAM,CAAC;IACb,IAAI,EAAE,MAAM,CAAC;IACb;;;OAGG;IACH,aAAa,CAAC,EAAE;QACf,YAAY,EAAE,MAAM,CAAC;QACrB,SAAS,EAAE,MAAM,CAAC;KAClB,CAAC;IACF;;;;OAIG;IACH,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB;;;;;;OAMG;IACH,mBAAmB,CAAC,EAAE,MAAM,CAAC;IAC7B;;;;;;OAMG;IACH,SAAS,CAAC,EAAE,OAAO,CAAC;CACpB;AAED;;GAEG;AACH,MAAM,WAAW,iBAAiB;IACjC,QAAQ,CAAC,UAAU,EAAE,OAAO,EAAE,CAAC;IAC/B,QAAQ,CAAC,UAAU,EAAE,EAAE,CAAC,UAAU,CAAC;IACnC,QAAQ,CAAC,gBAAgB,EAAE,eAAe,EAAE,CAAC;IAC7C,QAAQ,CAAC,WAAW,CAAC,EAAE,EAAE,CAAC,WAAW,CAAC;CACtC;AAED;;GAEG;AACH,MAAM,WAAW,gBAAgB;IAChC,UAAU,EAAE,aAAa,EAAE,CAAC;CAC5B"}
|