tailwind-typescript-plugin 1.4.0-beta.17 → 1.4.0-beta.18

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 CHANGED
@@ -1,3 +1,9 @@
1
+ ## [1.4.0-beta.18](https://github.com/IvanRodriCalleja/tailwind-typescript-plugin/compare/v1.4.0-beta.17...v1.4.0-beta.18) (2025-12-20)
2
+
3
+ ### ✨ Features
4
+
5
+ * add Vue Single File Component support ([1d99210](https://github.com/IvanRodriCalleja/tailwind-typescript-plugin/commit/1d99210ce1d4b206fcf4461a904af7adee24ab53))
6
+
1
7
  ## [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
8
 
3
9
  ### ✨ Features
package/README.md CHANGED
@@ -6,11 +6,11 @@
6
6
  [![TypeScript](https://img.shields.io/github/package-json/dependency-version/IvanRodriCalleja/tailwind-typescript-plugin/dev/typescript?label=TypeScript)](https://www.typescriptlang.org/)
7
7
  [![PRs Welcome](https://img.shields.io/badge/PRs-welcome-brightgreen.svg)](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 and validating that all Tailwind classes used in `className` 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.
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
- * TODO: Implement Vue-specific extraction logic
9
- * - Handle :class (v-bind:class) dynamic bindings
10
- * - Handle class static attributes
11
- * - Handle object syntax: :class="{ 'active': isActive }"
12
- * - Handle array syntax: :class="['base', { 'active': isActive }]"
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":"AACA,OAAO,KAAK,EAAE,MAAM,gCAAgC,CAAC;AAErD,OAAO,EAAE,aAAa,EAAE,iBAAiB,EAAE,MAAM,eAAe,CAAC;AACjE,OAAO,EAAE,aAAa,EAAE,MAAM,iBAAiB,CAAC;AAEhD;;;;;;;;;GASG;AACH,qBAAa,qBAAsB,SAAQ,aAAa;IACvD,SAAS,CAAC,IAAI,EAAE,EAAE,CAAC,IAAI,EAAE,OAAO,EAAE,iBAAiB,GAAG,OAAO;IAM7D,OAAO,CAAC,IAAI,EAAE,EAAE,CAAC,IAAI,EAAE,OAAO,EAAE,iBAAiB,GAAG,aAAa,EAAE;CAKnE"}
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
- * TODO: Implement Vue-specific extraction logic
10
- * - Handle :class (v-bind:class) dynamic bindings
11
- * - Handle class static attributes
12
- * - Handle object syntax: :class="{ 'active': isActive }"
13
- * - Handle array syntax: :class="['base', { 'active': isActive }]"
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
- // TODO: Implement Vue node detection
18
- // For now, return false as this is a stub
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
- // TODO: Implement Vue class extraction
23
- // This is a placeholder that will be implemented in the next phase
24
- return [];
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":";;;AAIA,mDAAgD;AAEhD;;;;;;;;;GASG;AACH,MAAa,qBAAsB,SAAQ,6BAAa;IACvD,SAAS,CAAC,IAAa,EAAE,OAA0B;QAClD,qCAAqC;QACrC,0CAA0C;QAC1C,OAAO,KAAK,CAAC;IACd,CAAC;IAED,OAAO,CAAC,IAAa,EAAE,OAA0B;QAChD,uCAAuC;QACvC,mEAAmE;QACnE,OAAO,EAAE,CAAC;IACX,CAAC;CACD;AAZD,sDAYC"}
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,6BAA6B;IAC7B,IAAI,QAAQ,CAAC,QAAQ,CAAC,MAAM,CAAC,EAAE,CAAC;QAC/B,OAAO,SAAS,CAAC,GAAG,CAAC;IACtB,CAAC;IAED,oBAAoB;IACpB,IAAI,QAAQ,CAAC,QAAQ,CAAC,SAAS,CAAC,EAAE,CAAC;QAClC,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"}
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.0-beta.17",
3
+ "version": "1.4.0-beta.18",
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",