tailwind-typescript-plugin 1.4.1-beta.1 → 1.4.1-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 +206 -34
- package/lib/core/interfaces.d.ts +2 -2
- package/lib/core/interfaces.d.ts.map +1 -1
- package/lib/core/types.d.ts +19 -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.js +1 -1
- 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.map +1 -1
- package/lib/extractors/TailwindVariantsExtractor.js +1 -5
- 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 +28 -18
- package/lib/infrastructure/TailwindConflictDetector.d.ts.map +1 -1
- package/lib/infrastructure/TailwindConflictDetector.js +216 -486
- package/lib/infrastructure/TailwindConflictDetector.js.map +1 -1
- 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 +185 -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 +113 -0
- package/lib/services/CompletionService.d.ts.map +1 -0
- package/lib/services/CompletionService.js +488 -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 +1039 -0
- package/lib/services/CompletionService.spec.js.map +1 -0
- package/lib/services/ConflictClassDetection.spec.js +24 -19
- package/lib/services/ConflictClassDetection.spec.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 +4 -2
- package/lib/services/ValidationService.d.ts.map +1 -1
- package/lib/services/ValidationService.js +10 -7
- 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
|
@@ -82,15 +82,27 @@ Add the plugin to the `compilerOptions.plugins` array in your `tsconfig.json`:
|
|
|
82
82
|
|
|
83
83
|
- `globalCss` (required): Path to your global CSS file that imports Tailwind CSS. This can be relative to your project root.
|
|
84
84
|
|
|
85
|
-
- `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.
|
|
86
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` |
|
|
87
94
|
- **Example**:
|
|
88
95
|
```json
|
|
89
96
|
{
|
|
90
|
-
"allowedClasses": [
|
|
97
|
+
"allowedClasses": [
|
|
98
|
+
"custom-*",
|
|
99
|
+
"*-icon",
|
|
100
|
+
"*-component-*",
|
|
101
|
+
"exact-class"
|
|
102
|
+
]
|
|
91
103
|
}
|
|
92
104
|
```
|
|
93
|
-
- Classes
|
|
105
|
+
- Classes matching any pattern will be considered valid and won't trigger validation errors
|
|
94
106
|
- Works with all extraction patterns (literals, expressions, functions, arrays, etc.)
|
|
95
107
|
- Combines with Tailwind classes - both are validated independently
|
|
96
108
|
|
|
@@ -128,34 +140,99 @@ Add the plugin to the `compilerOptions.plugins` array in your `tsconfig.json`:
|
|
|
128
140
|
```
|
|
129
141
|
- **Performance impact**: Disabling unused extractors skips TypeChecker operations and symbol resolution for that library, providing faster validation
|
|
130
142
|
|
|
131
|
-
- `utilityFunctions` (optional): Array of
|
|
132
|
-
- **Defaults (always included)**: `['clsx', 'cn', 'classnames', 'classNames', 'cx', 'cva', 'twMerge', 'tv']`
|
|
133
|
-
- **Add your own**: Provide custom function names that will be added to the defaults
|
|
134
|
-
- **Example config**:
|
|
135
|
-
```json
|
|
136
|
-
{
|
|
137
|
-
"utilityFunctions": ["myCustomFn", "buildClasses"]
|
|
138
|
-
}
|
|
139
|
-
```
|
|
140
|
-
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:
|
|
141
144
|
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
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
|
+
```
|
|
147
171
|
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
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'`
|
|
151
175
|
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
176
|
+
**Example configurations**:
|
|
177
|
+
```json
|
|
178
|
+
// Simple: just add function names
|
|
179
|
+
{
|
|
180
|
+
"utilityFunctions": ["myCustomFn", "buildClasses"]
|
|
181
|
+
}
|
|
155
182
|
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
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
|
+
```
|
|
159
236
|
|
|
160
237
|
### 2. Ensure your CSS file imports Tailwind
|
|
161
238
|
|
|
@@ -245,6 +322,18 @@ const validClass = 'flex items-center';
|
|
|
245
322
|
const baseClass = 'flex';
|
|
246
323
|
<div className={[baseClass, 'items-center']}>Array with variable</div>
|
|
247
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
|
+
|
|
248
337
|
// ✅ Variables in tv() and cva()
|
|
249
338
|
const buttonBase = 'font-semibold text-white';
|
|
250
339
|
const button = tv({ base: buttonBase });
|
|
@@ -275,6 +364,14 @@ const badClass = 'invalid-array-class';
|
|
|
275
364
|
// Error: The class "invalid-array-class" is not a valid Tailwind class.
|
|
276
365
|
// This value is used as className via variable "badClass" on line 8
|
|
277
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>
|
|
278
375
|
```
|
|
279
376
|
|
|
280
377
|
**Custom allowed classes**:
|
|
@@ -326,6 +423,18 @@ The plugin detects duplicate classes within the same `className` attribute and s
|
|
|
326
423
|
<div className={cn(['flex', 'flex', 'items-center'])}>In array</div>
|
|
327
424
|
// Warning: Duplicate class "flex"
|
|
328
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
|
+
|
|
329
438
|
// ✅ Valid: Same class in DIFFERENT elements (not duplicates)
|
|
330
439
|
<div className="flex items-center">
|
|
331
440
|
<span className="flex justify-center">Different elements</span>
|
|
@@ -479,6 +588,22 @@ The plugin intelligently handles ternary expressions - conflicts are NOT flagged
|
|
|
479
588
|
// Warning: Both classes affect text-align
|
|
480
589
|
```
|
|
481
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
|
+
|
|
482
607
|
**Conflicts in tv() and cva()**:
|
|
483
608
|
|
|
484
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:
|
|
@@ -834,6 +959,15 @@ const card2 = tv({ base: 'flex justify-center' });
|
|
|
834
959
|
Validates variables used in computed object property keys
|
|
835
960
|
Example: `const myClass = 'invalid-class'; <div className={{ [myClass]: true }}>Object</div>`
|
|
836
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
|
+
|
|
837
971
|
- [X] **TV Variable** → [`tv-variable.tsx`](./example/src/tv-variable.tsx)
|
|
838
972
|
Validates variables in tailwind-variants tv() definitions
|
|
839
973
|
Example: `const baseClasses = 'invalid-class'; const button = tv({ base: baseClasses })`
|
|
@@ -842,19 +976,19 @@ const card2 = tv({ base: 'flex justify-center' });
|
|
|
842
976
|
Validates variables in class-variance-authority cva() definitions
|
|
843
977
|
Example: `const baseClasses = 'invalid-class'; const button = cva(baseClasses)`
|
|
844
978
|
|
|
845
|
-
- [X] **Duplicate Classes** → [`duplicate-classes
|
|
979
|
+
- [X] **Duplicate Classes** → [`duplicate-classes/`](./example/src/duplicate-classes/)
|
|
846
980
|
Detects duplicate classes within the same className attribute
|
|
847
|
-
Example: `className="flex flex items-center"` shows warning on
|
|
981
|
+
Example: `className="flex flex items-center"` shows warning on both `flex` occurrences
|
|
848
982
|
|
|
849
|
-
- [X] **Duplicate Classes in Ternary** → [`duplicate-classes
|
|
983
|
+
- [X] **Duplicate Classes in Ternary** → [`duplicate-classes/`](./example/src/duplicate-classes/)
|
|
850
984
|
Smart detection of duplicates in ternary expressions:
|
|
851
|
-
- Root + branch duplicate: `clsx('flex', isActive ? 'flex' : 'flex')` → Warning
|
|
985
|
+
- Root + branch duplicate: `clsx('flex', isActive ? 'flex' : 'flex')` → Warning on all occurrences
|
|
852
986
|
- Both branches same class: `clsx('mt-4', isActive ? 'flex' : 'flex')` → Warning (consider extracting)
|
|
853
987
|
- Single branch only: `clsx('mt-4', isActive ? 'flex' : '')` → No warning (valid pattern)
|
|
854
988
|
|
|
855
|
-
- [X] **Duplicate Classes in Variables with Conditionals** → [`duplicate-classes
|
|
989
|
+
- [X] **Duplicate Classes in Variables with Conditionals** → [`duplicate-classes/`](./example/src/duplicate-classes/)
|
|
856
990
|
Resolves variables containing ternary expressions and detects duplicates:
|
|
857
|
-
- `const x = isActive ? 'flex' : 'flex'; clsx('flex', x)` → Warning
|
|
991
|
+
- `const x = isActive ? 'flex' : 'flex'; clsx('flex', x)` → Warning on all occurrences
|
|
858
992
|
- `const x = isActive ? 'flex' : 'flex'; clsx('mt-4', x)` → Warning (consider extracting from variable)
|
|
859
993
|
- `const x = isActive ? 'flex' : ''; clsx('mt-4', x)` → No warning (single branch)
|
|
860
994
|
|
|
@@ -879,6 +1013,16 @@ const card2 = tv({ base: 'flex justify-center' });
|
|
|
879
1013
|
- Works with clsx, cn, tv(), cva() and other utility functions
|
|
880
1014
|
- tv()/cva() base vs variant: NO conflict (variants are designed to override base)
|
|
881
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
|
+
|
|
882
1026
|
## How It Works
|
|
883
1027
|
|
|
884
1028
|
The plugin hooks into the TypeScript Language Service and:
|
|
@@ -902,6 +1046,34 @@ The plugin is designed for minimal performance impact:
|
|
|
902
1046
|
|
|
903
1047
|
**Typical overhead**: <1ms per file for most files, ~2-3ms for files with many tv()/cva() calls
|
|
904
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
|
+
|
|
905
1077
|
## Development
|
|
906
1078
|
|
|
907
1079
|
This is a monorepo using Yarn workspaces:
|
|
@@ -944,7 +1116,7 @@ Commit to main → Auto-publishes 1.0.33-beta.3
|
|
|
944
1116
|
|
|
945
1117
|
Users can install beta versions:
|
|
946
1118
|
```bash
|
|
947
|
-
npm install typescript-
|
|
1119
|
+
npm install tailwind-typescript-plugin@beta
|
|
948
1120
|
```
|
|
949
1121
|
|
|
950
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
|
*/
|
|
@@ -45,7 +63,7 @@ export interface ClassNameInfo {
|
|
|
45
63
|
export interface ExtractionContext {
|
|
46
64
|
readonly typescript: typeof ts;
|
|
47
65
|
readonly sourceFile: ts.SourceFile;
|
|
48
|
-
readonly utilityFunctions:
|
|
66
|
+
readonly utilityFunctions: UtilityFunction[];
|
|
49
67
|
readonly typeChecker?: ts.TypeChecker;
|
|
50
68
|
}
|
|
51
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;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,
|
|
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"}
|
|
@@ -1,11 +1,21 @@
|
|
|
1
1
|
import * as ts from 'typescript/lib/tsserverlibrary';
|
|
2
2
|
import { IClassNameExtractor } from '../core/interfaces';
|
|
3
|
-
import { ClassNameInfo, ExtractionContext } from '../core/types';
|
|
3
|
+
import { ClassNameInfo, ExtractionContext, UtilityFunction } from '../core/types';
|
|
4
4
|
/**
|
|
5
5
|
* Abstract base class for all extractors
|
|
6
6
|
* Provides common functionality and enforces the contract
|
|
7
7
|
*/
|
|
8
8
|
export declare abstract class BaseExtractor implements IClassNameExtractor {
|
|
9
|
+
/**
|
|
10
|
+
* Cache for import mappings per file
|
|
11
|
+
* Maps filename -> (local identifier name -> module specifier)
|
|
12
|
+
*/
|
|
13
|
+
private importCache;
|
|
14
|
+
/**
|
|
15
|
+
* Cache for namespace import mappings per file
|
|
16
|
+
* Maps filename -> (namespace identifier -> module specifier)
|
|
17
|
+
*/
|
|
18
|
+
private namespaceImportCache;
|
|
9
19
|
abstract canHandle(node: ts.Node, context: ExtractionContext): boolean;
|
|
10
20
|
abstract extract(node: ts.Node, context: ExtractionContext): ClassNameInfo[];
|
|
11
21
|
/**
|
|
@@ -15,7 +25,44 @@ export declare abstract class BaseExtractor implements IClassNameExtractor {
|
|
|
15
25
|
protected extractFromStringLiteral(literal: ts.StringLiteral | ts.NoSubstitutionTemplateLiteral, context: ExtractionContext): ClassNameInfo[];
|
|
16
26
|
/**
|
|
17
27
|
* Helper method to check if a function call should be validated
|
|
28
|
+
* Supports both simple string matching and precise import verification
|
|
29
|
+
*/
|
|
30
|
+
protected shouldValidateFunctionCall(callExpression: ts.CallExpression, utilityFunctions: UtilityFunction[], context?: ExtractionContext): boolean;
|
|
31
|
+
/**
|
|
32
|
+
* Check if a function name is imported from a specific module
|
|
33
|
+
* Supports:
|
|
34
|
+
* - Named imports: import { clsx } from 'clsx'
|
|
35
|
+
* - Aliased imports: import { clsx as cx } from 'clsx'
|
|
36
|
+
* - Default imports: import clsx from 'clsx'
|
|
37
|
+
*/
|
|
38
|
+
protected isImportedFrom(functionName: string, expectedModule: string, context: ExtractionContext): boolean;
|
|
39
|
+
/**
|
|
40
|
+
* Check if an object name is a namespace import from a specific module
|
|
41
|
+
* For: import * as utils from 'clsx' -> utils.clsx('flex')
|
|
42
|
+
*/
|
|
43
|
+
protected isNamespaceImportedFrom(objectName: string, expectedModule: string, context: ExtractionContext): boolean;
|
|
44
|
+
/**
|
|
45
|
+
* Get the import map for the current file
|
|
46
|
+
* Caches the result for performance
|
|
47
|
+
*/
|
|
48
|
+
private getImportMap;
|
|
49
|
+
/**
|
|
50
|
+
* Get the namespace import map for the current file
|
|
51
|
+
* Caches the result for performance
|
|
52
|
+
*/
|
|
53
|
+
private getNamespaceImportMap;
|
|
54
|
+
/**
|
|
55
|
+
* Build both import maps (regular and namespace) for the current file
|
|
56
|
+
*/
|
|
57
|
+
private buildImportMaps;
|
|
58
|
+
/**
|
|
59
|
+
* Clear the import cache (useful for testing or when files change)
|
|
60
|
+
*/
|
|
61
|
+
clearImportCache(): void;
|
|
62
|
+
/**
|
|
63
|
+
* Check if a function name matches any utility function (by name only)
|
|
64
|
+
* Used for quick exclusion checks without import verification
|
|
18
65
|
*/
|
|
19
|
-
protected
|
|
66
|
+
protected isUtilityFunctionName(functionName: string, utilityFunctions: UtilityFunction[]): boolean;
|
|
20
67
|
}
|
|
21
68
|
//# sourceMappingURL=BaseExtractor.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"BaseExtractor.d.ts","sourceRoot":"","sources":["../../src/extractors/BaseExtractor.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,MAAM,gCAAgC,CAAC;AAErD,OAAO,EAAE,mBAAmB,EAAE,MAAM,oBAAoB,CAAC;AACzD,OAAO,EAAE,aAAa,EAAE,iBAAiB,EAAE,MAAM,eAAe,CAAC;
|
|
1
|
+
{"version":3,"file":"BaseExtractor.d.ts","sourceRoot":"","sources":["../../src/extractors/BaseExtractor.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,MAAM,gCAAgC,CAAC;AAErD,OAAO,EAAE,mBAAmB,EAAE,MAAM,oBAAoB,CAAC;AACzD,OAAO,EAAE,aAAa,EAAE,iBAAiB,EAAE,eAAe,EAAE,MAAM,eAAe,CAAC;AAclF;;;GAGG;AACH,8BAAsB,aAAc,YAAW,mBAAmB;IACjE;;;OAGG;IACH,OAAO,CAAC,WAAW,CAAgC;IAEnD;;;OAGG;IACH,OAAO,CAAC,oBAAoB,CAAyC;IAErE,QAAQ,CAAC,SAAS,CAAC,IAAI,EAAE,EAAE,CAAC,IAAI,EAAE,OAAO,EAAE,iBAAiB,GAAG,OAAO;IACtE,QAAQ,CAAC,OAAO,CAAC,IAAI,EAAE,EAAE,CAAC,IAAI,EAAE,OAAO,EAAE,iBAAiB,GAAG,aAAa,EAAE;IAE5E;;;OAGG;IACH,SAAS,CAAC,wBAAwB,CACjC,OAAO,EAAE,EAAE,CAAC,aAAa,GAAG,EAAE,CAAC,6BAA6B,EAC5D,OAAO,EAAE,iBAAiB,GACxB,aAAa,EAAE;IA0BlB;;;OAGG;IACH,SAAS,CAAC,0BAA0B,CACnC,cAAc,EAAE,EAAE,CAAC,cAAc,EACjC,gBAAgB,EAAE,eAAe,EAAE,EACnC,OAAO,CAAC,EAAE,iBAAiB,GACzB,OAAO;IAyDV;;;;;;OAMG;IACH,SAAS,CAAC,cAAc,CACvB,YAAY,EAAE,MAAM,EACpB,cAAc,EAAE,MAAM,EACtB,OAAO,EAAE,iBAAiB,GACxB,OAAO;IAYV;;;OAGG;IACH,SAAS,CAAC,uBAAuB,CAChC,UAAU,EAAE,MAAM,EAClB,cAAc,EAAE,MAAM,EACtB,OAAO,EAAE,iBAAiB,GACxB,OAAO;IAYV;;;OAGG;IACH,OAAO,CAAC,YAAY;IAcpB;;;OAGG;IACH,OAAO,CAAC,qBAAqB;IAc7B;;OAEG;IACH,OAAO,CAAC,eAAe;IAsDvB;;OAEG;IACH,gBAAgB,IAAI,IAAI;IAKxB;;;OAGG;IACH,SAAS,CAAC,qBAAqB,CAC9B,YAAY,EAAE,MAAM,EACpB,gBAAgB,EAAE,eAAe,EAAE,GACjC,OAAO;CASV"}
|