tailwind-typescript-plugin 1.4.1-beta.16 → 1.4.1-beta.17
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 +6 -0
- package/README.md +49 -2
- package/lib/extractors/VueAttributeExtractor.d.ts +21 -6
- package/lib/extractors/VueAttributeExtractor.d.ts.map +1 -1
- package/lib/extractors/VueAttributeExtractor.js +194 -11
- package/lib/extractors/VueAttributeExtractor.js.map +1 -1
- package/lib/utils/FrameworkDetector.js +4 -4
- package/lib/utils/FrameworkDetector.js.map +1 -1
- package/package.json +1 -1
package/CHANGELOG.md
CHANGED
|
@@ -1,3 +1,9 @@
|
|
|
1
|
+
## [1.4.0-beta.17](https://github.com/IvanRodriCalleja/tailwind-typescript-plugin/compare/v1.4.0-beta.16...v1.4.0-beta.17) (2025-12-20)
|
|
2
|
+
|
|
3
|
+
### ✨ Features
|
|
4
|
+
|
|
5
|
+
* add configurable class attributes for custom JSX props ([701b133](https://github.com/IvanRodriCalleja/tailwind-typescript-plugin/commit/701b13369f943893f2cdf054b4a1c9a80640398e))
|
|
6
|
+
|
|
1
7
|
## [1.4.0-beta.16](https://github.com/IvanRodriCalleja/tailwind-typescript-plugin/compare/v1.4.0-beta.15...v1.4.0-beta.16) (2025-12-03)
|
|
2
8
|
|
|
3
9
|
### ✨ Features
|
package/README.md
CHANGED
|
@@ -6,11 +6,11 @@
|
|
|
6
6
|
[](https://www.typescriptlang.org/)
|
|
7
7
|
[](https://github.com/IvanRodriCalleja/tailwind-typescript-plugin/blob/main/CONTRIBUTING.md)
|
|
8
8
|
|
|
9
|
-
A TypeScript Language Service plugin that catches **typos and invalid Tailwind CSS class names** in your JSX/TSX files. When you write a class name that doesn't exist in Tailwind, it won't apply any styles—this plugin detects those mistakes and shows errors directly in your editor before you ship broken styles.
|
|
9
|
+
A TypeScript Language Service plugin that catches **typos and invalid Tailwind CSS class names** in your JSX/TSX and Vue files. When you write a class name that doesn't exist in Tailwind, it won't apply any styles—this plugin detects those mistakes and shows errors directly in your editor before you ship broken styles.
|
|
10
10
|
|
|
11
11
|
## What does this plugin do?
|
|
12
12
|
|
|
13
|
-
Ever written `className="flex itms-center"` instead of `"flex items-center"`? That typo silently fails—Tailwind ignores invalid classes and your component looks broken. This plugin prevents that by analyzing your JSX/TSX code
|
|
13
|
+
Ever written `className="flex itms-center"` instead of `"flex items-center"`? That typo silently fails—Tailwind ignores invalid classes and your component looks broken. This plugin prevents that by analyzing your JSX/TSX and Vue code, validating that all Tailwind classes used in `className`/`class` attributes actually exist in your Tailwind CSS configuration. It provides real-time feedback by showing TypeScript errors for invalid or misspelled Tailwind classes, catching styling mistakes before they reach production.
|
|
14
14
|
|
|
15
15
|
## Table of Contents
|
|
16
16
|
|
|
@@ -37,6 +37,10 @@ Ever written `className="flex itms-center"` instead of `"flex items-center"`? Th
|
|
|
37
37
|
- **Editor integration**: Works with any editor that supports TypeScript Language Service (VS Code, WebStorm, etc.)
|
|
38
38
|
- **Supports Tailwind variants**: Validates responsive (`md:`, `lg:`), state (`hover:`, `focus:`), and other variants
|
|
39
39
|
- **Arbitrary values**: Correctly handles Tailwind arbitrary values like `h-[50vh]` or `bg-[#ff0000]`
|
|
40
|
+
- **Vue support**: Validates classes in Vue Single File Components (`.vue` files) when used with `@vue/typescript-plugin`
|
|
41
|
+
- Static class attributes: `<div class="flex items-center">`
|
|
42
|
+
- Dynamic class bindings: `<div :class="{ 'bg-red-500': isActive }">`
|
|
43
|
+
- Object and array syntax support
|
|
40
44
|
- **Variant library support**:
|
|
41
45
|
- **tailwind-variants**: Validates classes in `tv()` function calls including `base`, `variants`, `compoundVariants`, `slots`, and `class`/`className` override properties
|
|
42
46
|
- **class-variance-authority**: Validates classes in `cva()` function calls including base classes, `variants`, `compoundVariants`, and `class`/`className` override properties
|
|
@@ -372,6 +376,49 @@ You may need to restart the TypeScript server:
|
|
|
372
376
|
- Open command palette
|
|
373
377
|
- Type "TypeScript: Restart TS Server"
|
|
374
378
|
|
|
379
|
+
#### Vue Projects
|
|
380
|
+
|
|
381
|
+
For Vue Single File Components (`.vue` files), you need to configure `@vue/typescript-plugin` alongside this plugin:
|
|
382
|
+
|
|
383
|
+
1. Install the Vue TypeScript plugin:
|
|
384
|
+
```bash
|
|
385
|
+
npm install -D @vue/typescript-plugin
|
|
386
|
+
```
|
|
387
|
+
|
|
388
|
+
2. Configure both plugins in your `tsconfig.json`:
|
|
389
|
+
```json
|
|
390
|
+
{
|
|
391
|
+
"compilerOptions": {
|
|
392
|
+
"plugins": [
|
|
393
|
+
{
|
|
394
|
+
"name": "@vue/typescript-plugin",
|
|
395
|
+
"languages": ["vue"]
|
|
396
|
+
},
|
|
397
|
+
{
|
|
398
|
+
"name": "tailwind-typescript-plugin",
|
|
399
|
+
"globalCss": "./src/global.css"
|
|
400
|
+
}
|
|
401
|
+
]
|
|
402
|
+
}
|
|
403
|
+
}
|
|
404
|
+
```
|
|
405
|
+
|
|
406
|
+
3. Ensure you have the [Vue - Official](https://marketplace.visualstudio.com/items?itemName=Vue.volar) extension installed in VS Code.
|
|
407
|
+
|
|
408
|
+
The plugin will then validate classes in your Vue templates:
|
|
409
|
+
```vue
|
|
410
|
+
<template>
|
|
411
|
+
<!-- ✅ Valid classes -->
|
|
412
|
+
<div class="flex items-center">Valid</div>
|
|
413
|
+
|
|
414
|
+
<!-- ❌ Invalid class detected -->
|
|
415
|
+
<div class="invalidclass">Error shown</div>
|
|
416
|
+
|
|
417
|
+
<!-- ✅ Dynamic class bindings -->
|
|
418
|
+
<div :class="{ 'bg-red-500': isActive }">Dynamic</div>
|
|
419
|
+
</template>
|
|
420
|
+
```
|
|
421
|
+
|
|
375
422
|
#### Other Editors
|
|
376
423
|
|
|
377
424
|
Most editors that support TypeScript Language Service plugins should work automatically. Refer to your editor's documentation for TypeScript plugin configuration.
|
|
@@ -3,16 +3,31 @@ import { ClassNameInfo, ExtractionContext } from '../core/types';
|
|
|
3
3
|
import { BaseExtractor } from './BaseExtractor';
|
|
4
4
|
/**
|
|
5
5
|
* Extracts class names from Vue template class attributes
|
|
6
|
-
* Assumes @vue/language-tools is configured and transforms Vue templates
|
|
7
6
|
*
|
|
8
|
-
*
|
|
9
|
-
*
|
|
10
|
-
*
|
|
11
|
-
*
|
|
12
|
-
*
|
|
7
|
+
* When @vue/language-tools (Volar) transforms Vue SFC templates, it generates
|
|
8
|
+
* TypeScript code using function calls with object spreads:
|
|
9
|
+
*
|
|
10
|
+
* ```typescript
|
|
11
|
+
* __VLS_asFunctionalElement(__VLS_intrinsicElements.div)({
|
|
12
|
+
* ...{ class: "flex items-center" },
|
|
13
|
+
* });
|
|
14
|
+
* ```
|
|
15
|
+
*
|
|
16
|
+
* For dynamic classes:
|
|
17
|
+
* ```typescript
|
|
18
|
+
* __VLS_asFunctionalElement(__VLS_intrinsicElements.div)({
|
|
19
|
+
* ...{ class: ({ 'bg-red-500': isActive }) },
|
|
20
|
+
* });
|
|
21
|
+
* ```
|
|
22
|
+
*
|
|
23
|
+
* This extractor handles these patterns to extract class names.
|
|
13
24
|
*/
|
|
14
25
|
export declare class VueAttributeExtractor extends BaseExtractor {
|
|
26
|
+
private expressionExtractor;
|
|
27
|
+
constructor();
|
|
15
28
|
canHandle(node: ts.Node, context: ExtractionContext): boolean;
|
|
29
|
+
private hasClassSpreadProperty;
|
|
16
30
|
extract(node: ts.Node, context: ExtractionContext): ClassNameInfo[];
|
|
31
|
+
private extractClassesFromValue;
|
|
17
32
|
}
|
|
18
33
|
//# sourceMappingURL=VueAttributeExtractor.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"VueAttributeExtractor.d.ts","sourceRoot":"","sources":["../../src/extractors/VueAttributeExtractor.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"VueAttributeExtractor.d.ts","sourceRoot":"","sources":["../../src/extractors/VueAttributeExtractor.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,MAAM,gCAAgC,CAAC;AAErD,OAAO,EAAE,aAAa,EAAE,iBAAiB,EAAE,MAAM,eAAe,CAAC;AACjE,OAAO,EAAE,aAAa,EAAE,MAAM,iBAAiB,CAAC;AAGhD;;;;;;;;;;;;;;;;;;;;GAoBG;AACH,qBAAa,qBAAsB,SAAQ,aAAa;IACvD,OAAO,CAAC,mBAAmB,CAAsB;;IAOjD,SAAS,CAAC,IAAI,EAAE,EAAE,CAAC,IAAI,EAAE,OAAO,EAAE,iBAAiB,GAAG,OAAO;IA4B7D,OAAO,CAAC,sBAAsB;IAsB9B,OAAO,CAAC,IAAI,EAAE,EAAE,CAAC,IAAI,EAAE,OAAO,EAAE,iBAAiB,GAAG,aAAa,EAAE;IA4CnE,OAAO,CAAC,uBAAuB;CA2H/B"}
|
|
@@ -2,26 +2,209 @@
|
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
3
|
exports.VueAttributeExtractor = void 0;
|
|
4
4
|
const BaseExtractor_1 = require("./BaseExtractor");
|
|
5
|
+
const ExpressionExtractor_1 = require("./ExpressionExtractor");
|
|
5
6
|
/**
|
|
6
7
|
* Extracts class names from Vue template class attributes
|
|
7
|
-
* Assumes @vue/language-tools is configured and transforms Vue templates
|
|
8
8
|
*
|
|
9
|
-
*
|
|
10
|
-
*
|
|
11
|
-
*
|
|
12
|
-
*
|
|
13
|
-
*
|
|
9
|
+
* When @vue/language-tools (Volar) transforms Vue SFC templates, it generates
|
|
10
|
+
* TypeScript code using function calls with object spreads:
|
|
11
|
+
*
|
|
12
|
+
* ```typescript
|
|
13
|
+
* __VLS_asFunctionalElement(__VLS_intrinsicElements.div)({
|
|
14
|
+
* ...{ class: "flex items-center" },
|
|
15
|
+
* });
|
|
16
|
+
* ```
|
|
17
|
+
*
|
|
18
|
+
* For dynamic classes:
|
|
19
|
+
* ```typescript
|
|
20
|
+
* __VLS_asFunctionalElement(__VLS_intrinsicElements.div)({
|
|
21
|
+
* ...{ class: ({ 'bg-red-500': isActive }) },
|
|
22
|
+
* });
|
|
23
|
+
* ```
|
|
24
|
+
*
|
|
25
|
+
* This extractor handles these patterns to extract class names.
|
|
14
26
|
*/
|
|
15
27
|
class VueAttributeExtractor extends BaseExtractor_1.BaseExtractor {
|
|
28
|
+
constructor() {
|
|
29
|
+
super();
|
|
30
|
+
this.expressionExtractor = new ExpressionExtractor_1.ExpressionExtractor();
|
|
31
|
+
}
|
|
16
32
|
canHandle(node, context) {
|
|
17
|
-
//
|
|
18
|
-
//
|
|
33
|
+
// We handle call expressions that look like Vue's generated element calls
|
|
34
|
+
// Pattern: __VLS_asFunctionalElement(...)({ ...{ class: ... } })
|
|
35
|
+
if (!context.typescript.isCallExpression(node)) {
|
|
36
|
+
return false;
|
|
37
|
+
}
|
|
38
|
+
// Check if this is a chained call (the outer call to the element function)
|
|
39
|
+
// The pattern is: func(...)({...}) where the result of func(...) is called again
|
|
40
|
+
const expression = node.expression;
|
|
41
|
+
if (!context.typescript.isCallExpression(expression)) {
|
|
42
|
+
return false;
|
|
43
|
+
}
|
|
44
|
+
// Check if the arguments contain an object with spread that has a 'class' property
|
|
45
|
+
if (node.arguments.length === 0) {
|
|
46
|
+
return false;
|
|
47
|
+
}
|
|
48
|
+
const firstArg = node.arguments[0];
|
|
49
|
+
if (!context.typescript.isObjectLiteralExpression(firstArg)) {
|
|
50
|
+
return false;
|
|
51
|
+
}
|
|
52
|
+
// Look for spread assignments with 'class' property
|
|
53
|
+
return this.hasClassSpreadProperty(firstArg, context);
|
|
54
|
+
}
|
|
55
|
+
hasClassSpreadProperty(obj, context) {
|
|
56
|
+
for (const prop of obj.properties) {
|
|
57
|
+
if (context.typescript.isSpreadAssignment(prop)) {
|
|
58
|
+
const spreadExpr = prop.expression;
|
|
59
|
+
if (context.typescript.isObjectLiteralExpression(spreadExpr)) {
|
|
60
|
+
for (const innerProp of spreadExpr.properties) {
|
|
61
|
+
if (context.typescript.isPropertyAssignment(innerProp)) {
|
|
62
|
+
const name = innerProp.name;
|
|
63
|
+
if (context.typescript.isIdentifier(name) && name.text === 'class') {
|
|
64
|
+
return true;
|
|
65
|
+
}
|
|
66
|
+
}
|
|
67
|
+
}
|
|
68
|
+
}
|
|
69
|
+
}
|
|
70
|
+
}
|
|
19
71
|
return false;
|
|
20
72
|
}
|
|
21
73
|
extract(node, context) {
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
74
|
+
const classNames = [];
|
|
75
|
+
if (!context.typescript.isCallExpression(node)) {
|
|
76
|
+
return classNames;
|
|
77
|
+
}
|
|
78
|
+
const firstArg = node.arguments[0];
|
|
79
|
+
if (!firstArg || !context.typescript.isObjectLiteralExpression(firstArg)) {
|
|
80
|
+
return classNames;
|
|
81
|
+
}
|
|
82
|
+
// Find spread assignments with 'class' property
|
|
83
|
+
for (const prop of firstArg.properties) {
|
|
84
|
+
if (!context.typescript.isSpreadAssignment(prop)) {
|
|
85
|
+
continue;
|
|
86
|
+
}
|
|
87
|
+
const spreadExpr = prop.expression;
|
|
88
|
+
if (!context.typescript.isObjectLiteralExpression(spreadExpr)) {
|
|
89
|
+
continue;
|
|
90
|
+
}
|
|
91
|
+
for (const innerProp of spreadExpr.properties) {
|
|
92
|
+
if (!context.typescript.isPropertyAssignment(innerProp)) {
|
|
93
|
+
continue;
|
|
94
|
+
}
|
|
95
|
+
const name = innerProp.name;
|
|
96
|
+
if (!context.typescript.isIdentifier(name) || name.text !== 'class') {
|
|
97
|
+
continue;
|
|
98
|
+
}
|
|
99
|
+
const value = innerProp.initializer;
|
|
100
|
+
const attributeId = `${innerProp.getStart()}-${innerProp.getEnd()}`;
|
|
101
|
+
// Handle different class value types
|
|
102
|
+
classNames.push(...this.extractClassesFromValue(value, context, attributeId));
|
|
103
|
+
}
|
|
104
|
+
}
|
|
105
|
+
return classNames;
|
|
106
|
+
}
|
|
107
|
+
extractClassesFromValue(value, context, attributeId) {
|
|
108
|
+
const classNames = [];
|
|
109
|
+
// Static string literal: class: "flex items-center"
|
|
110
|
+
if (context.typescript.isStringLiteral(value)) {
|
|
111
|
+
const fullText = value.text;
|
|
112
|
+
if (fullText.length === 0) {
|
|
113
|
+
return classNames;
|
|
114
|
+
}
|
|
115
|
+
const stringContentStart = value.getStart() + 1;
|
|
116
|
+
let offset = 0;
|
|
117
|
+
const parts = fullText.split(/(\s+)/);
|
|
118
|
+
for (const part of parts) {
|
|
119
|
+
if (part && !/^\s+$/.test(part)) {
|
|
120
|
+
classNames.push({
|
|
121
|
+
className: part,
|
|
122
|
+
absoluteStart: stringContentStart + offset,
|
|
123
|
+
length: part.length,
|
|
124
|
+
line: context.sourceFile.getLineAndCharacterOfPosition(stringContentStart + offset).line +
|
|
125
|
+
1,
|
|
126
|
+
file: context.sourceFile.fileName,
|
|
127
|
+
attributeId
|
|
128
|
+
});
|
|
129
|
+
}
|
|
130
|
+
offset += part.length;
|
|
131
|
+
}
|
|
132
|
+
return classNames;
|
|
133
|
+
}
|
|
134
|
+
// Object literal for dynamic classes: class: { 'bg-red-500': isActive }
|
|
135
|
+
// Or wrapped in parentheses: class: ({ 'bg-red-500': isActive })
|
|
136
|
+
let objectExpr;
|
|
137
|
+
if (context.typescript.isObjectLiteralExpression(value)) {
|
|
138
|
+
objectExpr = value;
|
|
139
|
+
}
|
|
140
|
+
else if (context.typescript.isParenthesizedExpression(value)) {
|
|
141
|
+
const inner = value.expression;
|
|
142
|
+
if (context.typescript.isObjectLiteralExpression(inner)) {
|
|
143
|
+
objectExpr = inner;
|
|
144
|
+
}
|
|
145
|
+
}
|
|
146
|
+
if (objectExpr) {
|
|
147
|
+
for (const prop of objectExpr.properties) {
|
|
148
|
+
if (context.typescript.isPropertyAssignment(prop)) {
|
|
149
|
+
const propName = prop.name;
|
|
150
|
+
let className;
|
|
151
|
+
let start;
|
|
152
|
+
// Handle string literal keys: { 'bg-red-500': true }
|
|
153
|
+
if (context.typescript.isStringLiteral(propName)) {
|
|
154
|
+
className = propName.text;
|
|
155
|
+
start = propName.getStart() + 1; // Skip opening quote
|
|
156
|
+
}
|
|
157
|
+
// Handle identifier keys: { flex: true }
|
|
158
|
+
else if (context.typescript.isIdentifier(propName)) {
|
|
159
|
+
className = propName.text;
|
|
160
|
+
start = propName.getStart();
|
|
161
|
+
}
|
|
162
|
+
if (className && start !== undefined) {
|
|
163
|
+
classNames.push({
|
|
164
|
+
className,
|
|
165
|
+
absoluteStart: start,
|
|
166
|
+
length: className.length,
|
|
167
|
+
line: context.sourceFile.getLineAndCharacterOfPosition(start).line + 1,
|
|
168
|
+
file: context.sourceFile.fileName,
|
|
169
|
+
attributeId
|
|
170
|
+
});
|
|
171
|
+
}
|
|
172
|
+
}
|
|
173
|
+
// Handle shorthand properties: { flex }
|
|
174
|
+
else if (context.typescript.isShorthandPropertyAssignment(prop)) {
|
|
175
|
+
const className = prop.name.text;
|
|
176
|
+
const start = prop.name.getStart();
|
|
177
|
+
classNames.push({
|
|
178
|
+
className,
|
|
179
|
+
absoluteStart: start,
|
|
180
|
+
length: className.length,
|
|
181
|
+
line: context.sourceFile.getLineAndCharacterOfPosition(start).line + 1,
|
|
182
|
+
file: context.sourceFile.fileName,
|
|
183
|
+
attributeId
|
|
184
|
+
});
|
|
185
|
+
}
|
|
186
|
+
}
|
|
187
|
+
return classNames;
|
|
188
|
+
}
|
|
189
|
+
// Array literal: class: ['flex', 'items-center']
|
|
190
|
+
if (context.typescript.isArrayLiteralExpression(value)) {
|
|
191
|
+
const addAttributeId = (classes) => classes.map(c => ({ ...c, attributeId }));
|
|
192
|
+
return addAttributeId(this.expressionExtractor.extract(value, context));
|
|
193
|
+
}
|
|
194
|
+
// Template literal or other expressions - delegate to expression extractor
|
|
195
|
+
if (context.typescript.isTemplateExpression(value) ||
|
|
196
|
+
context.typescript.isNoSubstitutionTemplateLiteral(value)) {
|
|
197
|
+
const addAttributeId = (classes) => classes.map(c => ({ ...c, attributeId }));
|
|
198
|
+
return addAttributeId(this.expressionExtractor.extract(value, context));
|
|
199
|
+
}
|
|
200
|
+
// Call expression (utility functions like cn, clsx)
|
|
201
|
+
if (context.typescript.isCallExpression(value)) {
|
|
202
|
+
if (this.shouldValidateFunctionCall(value, context.utilityFunctions, context)) {
|
|
203
|
+
const addAttributeId = (classes) => classes.map(c => ({ ...c, attributeId }));
|
|
204
|
+
return addAttributeId(this.expressionExtractor.extract(value, context));
|
|
205
|
+
}
|
|
206
|
+
}
|
|
207
|
+
return classNames;
|
|
25
208
|
}
|
|
26
209
|
}
|
|
27
210
|
exports.VueAttributeExtractor = VueAttributeExtractor;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"VueAttributeExtractor.js","sourceRoot":"","sources":["../../src/extractors/VueAttributeExtractor.ts"],"names":[],"mappings":";;;
|
|
1
|
+
{"version":3,"file":"VueAttributeExtractor.js","sourceRoot":"","sources":["../../src/extractors/VueAttributeExtractor.ts"],"names":[],"mappings":"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"}
|
|
@@ -20,12 +20,12 @@ var Framework;
|
|
|
20
20
|
* @returns The detected framework or null if not supported
|
|
21
21
|
*/
|
|
22
22
|
function detectFramework(fileName) {
|
|
23
|
-
// Vue Single File Components
|
|
24
|
-
if (fileName.endsWith('.vue')) {
|
|
23
|
+
// Vue Single File Components (including virtual .vue.ts files from Volar)
|
|
24
|
+
if (fileName.endsWith('.vue') || fileName.includes('.vue.')) {
|
|
25
25
|
return Framework.VUE;
|
|
26
26
|
}
|
|
27
|
-
// Svelte components
|
|
28
|
-
if (fileName.endsWith('.svelte')) {
|
|
27
|
+
// Svelte components (including virtual .svelte.ts files)
|
|
28
|
+
if (fileName.endsWith('.svelte') || fileName.includes('.svelte.')) {
|
|
29
29
|
return Framework.SVELTE;
|
|
30
30
|
}
|
|
31
31
|
// JSX/TSX files (React, Solid, etc.)
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"FrameworkDetector.js","sourceRoot":"","sources":["../../src/utils/FrameworkDetector.ts"],"names":[],"mappings":";;;AAgBA,0CAwBC;AAQD,0CAEC;AAlDD;;GAEG;AACH,IAAY,SAIX;AAJD,WAAY,SAAS;IACpB,wBAAW,CAAA;IACX,wBAAW,CAAA;IACX,8BAAiB,CAAA;AAClB,CAAC,EAJW,SAAS,yBAAT,SAAS,QAIpB;AAED;;;;;;GAMG;AACH,SAAgB,eAAe,CAAC,QAAgB;IAC/C,
|
|
1
|
+
{"version":3,"file":"FrameworkDetector.js","sourceRoot":"","sources":["../../src/utils/FrameworkDetector.ts"],"names":[],"mappings":";;;AAgBA,0CAwBC;AAQD,0CAEC;AAlDD;;GAEG;AACH,IAAY,SAIX;AAJD,WAAY,SAAS;IACpB,wBAAW,CAAA;IACX,wBAAW,CAAA;IACX,8BAAiB,CAAA;AAClB,CAAC,EAJW,SAAS,yBAAT,SAAS,QAIpB;AAED;;;;;;GAMG;AACH,SAAgB,eAAe,CAAC,QAAgB;IAC/C,0EAA0E;IAC1E,IAAI,QAAQ,CAAC,QAAQ,CAAC,MAAM,CAAC,IAAI,QAAQ,CAAC,QAAQ,CAAC,OAAO,CAAC,EAAE,CAAC;QAC7D,OAAO,SAAS,CAAC,GAAG,CAAC;IACtB,CAAC;IAED,yDAAyD;IACzD,IAAI,QAAQ,CAAC,QAAQ,CAAC,SAAS,CAAC,IAAI,QAAQ,CAAC,QAAQ,CAAC,UAAU,CAAC,EAAE,CAAC;QACnE,OAAO,SAAS,CAAC,MAAM,CAAC;IACzB,CAAC;IAED,qCAAqC;IACrC,IAAI,QAAQ,CAAC,QAAQ,CAAC,MAAM,CAAC,IAAI,QAAQ,CAAC,QAAQ,CAAC,MAAM,CAAC,EAAE,CAAC;QAC5D,OAAO,SAAS,CAAC,GAAG,CAAC;IACtB,CAAC;IAED,oDAAoD;IACpD,0CAA0C;IAC1C,IAAI,QAAQ,CAAC,QAAQ,CAAC,KAAK,CAAC,IAAI,QAAQ,CAAC,QAAQ,CAAC,KAAK,CAAC,EAAE,CAAC;QAC1D,OAAO,SAAS,CAAC,GAAG,CAAC;IACtB,CAAC;IAED,wBAAwB;IACxB,OAAO,IAAI,CAAC;AACb,CAAC;AAED;;;;;GAKG;AACH,SAAgB,eAAe,CAAC,QAAgB;IAC/C,OAAO,eAAe,CAAC,QAAQ,CAAC,KAAK,IAAI,CAAC;AAC3C,CAAC"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "tailwind-typescript-plugin",
|
|
3
|
-
"version": "1.4.1-beta.
|
|
3
|
+
"version": "1.4.1-beta.17",
|
|
4
4
|
"description": "TypeScript Language Service plugin that validates Tailwind CSS class names in JSX/TSX files. Catches typos and invalid classes in real-time with support for tailwind-variants and class-variance-authority.",
|
|
5
5
|
"main": "lib/index.js",
|
|
6
6
|
"types": "lib/index.d.ts",
|