tailwind-typescript-plugin 1.4.0-beta.24 → 1.4.0-beta.26

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.
Files changed (81) hide show
  1. package/CHANGELOG.md +27 -0
  2. package/README.md +235 -1173
  3. package/lib/core/interfaces.d.ts +17 -1
  4. package/lib/core/interfaces.d.ts.map +1 -1
  5. package/lib/core/types.d.ts +1 -23
  6. package/lib/core/types.d.ts.map +1 -1
  7. package/lib/extractors/BaseExtractor.d.ts +10 -4
  8. package/lib/extractors/BaseExtractor.d.ts.map +1 -1
  9. package/lib/extractors/BaseExtractor.js +31 -41
  10. package/lib/extractors/BaseExtractor.js.map +1 -1
  11. package/lib/extractors/BaseExtractor.spec.js +23 -23
  12. package/lib/extractors/BaseExtractor.spec.js.map +1 -1
  13. package/lib/extractors/CvaExtractor.js +1 -1
  14. package/lib/extractors/CvaExtractor.js.map +1 -1
  15. package/lib/extractors/CvaExtractor.spec.js +4 -4
  16. package/lib/extractors/CvaExtractor.spec.js.map +1 -1
  17. package/lib/extractors/ExpressionExtractor.js +1 -1
  18. package/lib/extractors/ExpressionExtractor.js.map +1 -1
  19. package/lib/extractors/ExpressionExtractor.spec.js +4 -4
  20. package/lib/extractors/ExpressionExtractor.spec.js.map +1 -1
  21. package/lib/extractors/JsxAttributeExtractor.d.ts +5 -0
  22. package/lib/extractors/JsxAttributeExtractor.d.ts.map +1 -1
  23. package/lib/extractors/JsxAttributeExtractor.js +7 -1
  24. package/lib/extractors/JsxAttributeExtractor.js.map +1 -1
  25. package/lib/extractors/JsxAttributeExtractor.spec.js +6 -6
  26. package/lib/extractors/JsxAttributeExtractor.spec.js.map +1 -1
  27. package/lib/extractors/TailwindVariantsExtractor.js +1 -1
  28. package/lib/extractors/TailwindVariantsExtractor.js.map +1 -1
  29. package/lib/extractors/TailwindVariantsExtractor.spec.js +4 -4
  30. package/lib/extractors/TailwindVariantsExtractor.spec.js.map +1 -1
  31. package/lib/extractors/TemplateExpressionExtractor.spec.js +1 -1
  32. package/lib/extractors/TemplateExpressionExtractor.spec.js.map +1 -1
  33. package/lib/extractors/VariableReferenceExtractor.spec.js +1 -1
  34. package/lib/extractors/VariableReferenceExtractor.spec.js.map +1 -1
  35. package/lib/extractors/VueAttributeExtractor.d.ts +8 -2
  36. package/lib/extractors/VueAttributeExtractor.d.ts.map +1 -1
  37. package/lib/extractors/VueAttributeExtractor.js +26 -31
  38. package/lib/extractors/VueAttributeExtractor.js.map +1 -1
  39. package/lib/extractors/VueExpressionExtractor.d.ts +2 -2
  40. package/lib/extractors/VueExpressionExtractor.d.ts.map +1 -1
  41. package/lib/extractors/VueExpressionExtractor.js +18 -30
  42. package/lib/extractors/VueExpressionExtractor.js.map +1 -1
  43. package/lib/plugin/TailwindTypescriptPlugin.d.ts +9 -0
  44. package/lib/plugin/TailwindTypescriptPlugin.d.ts.map +1 -1
  45. package/lib/plugin/TailwindTypescriptPlugin.js +57 -20
  46. package/lib/plugin/TailwindTypescriptPlugin.js.map +1 -1
  47. package/lib/services/ClassNameExtractionService.d.ts +9 -10
  48. package/lib/services/ClassNameExtractionService.d.ts.map +1 -1
  49. package/lib/services/ClassNameExtractionService.js +28 -34
  50. package/lib/services/ClassNameExtractionService.js.map +1 -1
  51. package/lib/services/ClassNameExtractionService.spec.js +16 -16
  52. package/lib/services/CompletionService.d.ts +2 -2
  53. package/lib/services/CompletionService.d.ts.map +1 -1
  54. package/lib/services/CompletionService.js +3 -1
  55. package/lib/services/CompletionService.js.map +1 -1
  56. package/lib/services/CompletionService.spec.js +10 -10
  57. package/lib/services/CompletionService.spec.js.map +1 -1
  58. package/lib/services/ConflictClassDetection.spec.js +84 -36
  59. package/lib/services/ConflictClassDetection.spec.js.map +1 -1
  60. package/lib/services/DuplicateClassDetection.spec.js +32 -32
  61. package/lib/services/DuplicateClassDetection.spec.js.map +1 -1
  62. package/lib/services/PluginConfigService.d.ts +1 -11
  63. package/lib/services/PluginConfigService.d.ts.map +1 -1
  64. package/lib/services/PluginConfigService.js +0 -27
  65. package/lib/services/PluginConfigService.js.map +1 -1
  66. package/lib/services/PluginConfigService.spec.js +9 -3
  67. package/lib/services/PluginConfigService.spec.js.map +1 -1
  68. package/lib/services/ValidationService.d.ts +2 -2
  69. package/lib/services/ValidationService.d.ts.map +1 -1
  70. package/lib/services/ValidationService.js +2 -2
  71. package/lib/services/ValidationService.js.map +1 -1
  72. package/lib/services/ValidationService.spec.js +24 -24
  73. package/lib/utils/CssAutoDetector.d.ts +10 -0
  74. package/lib/utils/CssAutoDetector.d.ts.map +1 -0
  75. package/lib/utils/CssAutoDetector.js +93 -0
  76. package/lib/utils/CssAutoDetector.js.map +1 -0
  77. package/lib/utils/CssAutoDetector.spec.d.ts +2 -0
  78. package/lib/utils/CssAutoDetector.spec.d.ts.map +1 -0
  79. package/lib/utils/CssAutoDetector.spec.js +223 -0
  80. package/lib/utils/CssAutoDetector.spec.js.map +1 -0
  81. package/package.json +10 -4
@@ -80,26 +80,26 @@ describe('ValidationService', () => {
80
80
  it('should return empty array when validator is not initialized', () => {
81
81
  mockValidator.isInitialized.mockReturnValue(false);
82
82
  const sourceFile = createSourceFile('<div className="flex">Hello</div>');
83
- const diagnostics = validationService.validateFile(ts, sourceFile, []);
83
+ const diagnostics = validationService.validateFile(ts, sourceFile, {});
84
84
  expect(diagnostics).toEqual([]);
85
85
  });
86
86
  it('should detect invalid Tailwind classes', () => {
87
87
  const sourceFile = createSourceFile('<div className="invalid-class">Hello</div>');
88
- const diagnostics = validationService.validateFile(ts, sourceFile, []);
88
+ const diagnostics = validationService.validateFile(ts, sourceFile, {});
89
89
  expect(diagnostics.length).toBeGreaterThan(0);
90
90
  expect(diagnostics[0].code).toBe(DiagnosticService_1.TAILWIND_DIAGNOSTIC_CODE);
91
91
  expect(diagnostics[0].messageText).toContain('invalid-class');
92
92
  });
93
93
  it('should not report valid Tailwind classes', () => {
94
94
  const sourceFile = createSourceFile('<div className="flex items-center">Hello</div>');
95
- const diagnostics = validationService.validateFile(ts, sourceFile, []);
95
+ const diagnostics = validationService.validateFile(ts, sourceFile, {});
96
96
  // Filter to only validation errors (not duplicate/conflict warnings)
97
97
  const validationErrors = diagnostics.filter(d => d.code === DiagnosticService_1.TAILWIND_DIAGNOSTIC_CODE);
98
98
  expect(validationErrors).toHaveLength(0);
99
99
  });
100
100
  it('should detect multiple invalid classes', () => {
101
101
  const sourceFile = createSourceFile('<div className="invalid1 flex invalid2">Hello</div>');
102
- const diagnostics = validationService.validateFile(ts, sourceFile, []);
102
+ const diagnostics = validationService.validateFile(ts, sourceFile, {});
103
103
  const validationErrors = diagnostics.filter(d => d.code === DiagnosticService_1.TAILWIND_DIAGNOSTIC_CODE);
104
104
  expect(validationErrors.length).toBe(2);
105
105
  });
@@ -107,7 +107,7 @@ describe('ValidationService', () => {
107
107
  describe('duplicate class detection', () => {
108
108
  it('should detect duplicate classes within same attribute', () => {
109
109
  const sourceFile = createSourceFile('<div className="flex flex">Hello</div>');
110
- const diagnostics = validationService.validateFile(ts, sourceFile, []);
110
+ const diagnostics = validationService.validateFile(ts, sourceFile, {});
111
111
  const duplicateWarnings = diagnostics.filter(d => d.code === DiagnosticService_1.TAILWIND_DUPLICATE_CODE);
112
112
  expect(duplicateWarnings.length).toBeGreaterThan(0);
113
113
  });
@@ -117,7 +117,7 @@ describe('ValidationService', () => {
117
117
  <span className="flex">Hello</span>
118
118
  </div>
119
119
  `);
120
- const diagnostics = validationService.validateFile(ts, sourceFile, []);
120
+ const diagnostics = validationService.validateFile(ts, sourceFile, {});
121
121
  const duplicateWarnings = diagnostics.filter(d => d.code === DiagnosticService_1.TAILWIND_DUPLICATE_CODE);
122
122
  expect(duplicateWarnings).toHaveLength(0);
123
123
  });
@@ -129,7 +129,7 @@ describe('ValidationService', () => {
129
129
  });
130
130
  const service = new ValidationService_1.ValidationService(extractionService, diagnosticService, mockValidator, disabledConfigService);
131
131
  const sourceFile = createSourceFile('<div className="invalid-class">Hello</div>');
132
- const diagnostics = service.validateFile(ts, sourceFile, []);
132
+ const diagnostics = service.validateFile(ts, sourceFile, {});
133
133
  const validationErrors = diagnostics.filter(d => d.code === DiagnosticService_1.TAILWIND_DIAGNOSTIC_CODE);
134
134
  expect(validationErrors).toHaveLength(0);
135
135
  });
@@ -139,7 +139,7 @@ describe('ValidationService', () => {
139
139
  });
140
140
  const service = new ValidationService_1.ValidationService(extractionService, diagnosticService, mockValidator, warningConfigService);
141
141
  const sourceFile = createSourceFile('<div className="invalid-class">Hello</div>');
142
- const diagnostics = service.validateFile(ts, sourceFile, []);
142
+ const diagnostics = service.validateFile(ts, sourceFile, {});
143
143
  const validationErrors = diagnostics.filter(d => d.code === DiagnosticService_1.TAILWIND_DIAGNOSTIC_CODE);
144
144
  expect(validationErrors.length).toBeGreaterThan(0);
145
145
  expect(validationErrors[0].category).toBe(ts.DiagnosticCategory.Warning);
@@ -150,7 +150,7 @@ describe('ValidationService', () => {
150
150
  });
151
151
  const service = new ValidationService_1.ValidationService(extractionService, diagnosticService, mockValidator, offConfigService);
152
152
  const sourceFile = createSourceFile('<div className="invalid-class">Hello</div>');
153
- const diagnostics = service.validateFile(ts, sourceFile, []);
153
+ const diagnostics = service.validateFile(ts, sourceFile, {});
154
154
  const validationErrors = diagnostics.filter(d => d.code === DiagnosticService_1.TAILWIND_DIAGNOSTIC_CODE);
155
155
  expect(validationErrors).toHaveLength(0);
156
156
  });
@@ -162,7 +162,7 @@ describe('ValidationService', () => {
162
162
  });
163
163
  const service = new ValidationService_1.ValidationService(extractionService, diagnosticService, mockValidator, disabledLintConfigService);
164
164
  const sourceFile = createSourceFile('<div className="flex flex">Hello</div>');
165
- const diagnostics = service.validateFile(ts, sourceFile, []);
165
+ const diagnostics = service.validateFile(ts, sourceFile, {});
166
166
  const duplicateWarnings = diagnostics.filter(d => d.code === DiagnosticService_1.TAILWIND_DUPLICATE_CODE);
167
167
  expect(duplicateWarnings).toHaveLength(0);
168
168
  });
@@ -175,7 +175,7 @@ describe('ValidationService', () => {
175
175
  });
176
176
  const service = new ValidationService_1.ValidationService(extractionService, diagnosticService, mockValidator, configService);
177
177
  const sourceFile = createSourceFile('<div className="flex flex">Hello</div>');
178
- const diagnostics = service.validateFile(ts, sourceFile, []);
178
+ const diagnostics = service.validateFile(ts, sourceFile, {});
179
179
  const duplicateWarnings = diagnostics.filter(d => d.code === DiagnosticService_1.TAILWIND_DUPLICATE_CODE);
180
180
  expect(duplicateWarnings).toHaveLength(0);
181
181
  });
@@ -187,7 +187,7 @@ describe('ValidationService', () => {
187
187
  });
188
188
  const service = new ValidationService_1.ValidationService(extractionService, diagnosticService, mockValidator, configService);
189
189
  const sourceFile = createSourceFile('<div className="flex flex">Hello</div>');
190
- const diagnostics = service.validateFile(ts, sourceFile, []);
190
+ const diagnostics = service.validateFile(ts, sourceFile, {});
191
191
  const duplicateWarnings = diagnostics.filter(d => d.code === DiagnosticService_1.TAILWIND_DUPLICATE_CODE);
192
192
  expect(duplicateWarnings.length).toBeGreaterThan(0);
193
193
  expect(duplicateWarnings[0].category).toBe(ts.DiagnosticCategory.Error);
@@ -200,7 +200,7 @@ describe('ValidationService', () => {
200
200
  });
201
201
  const service = new ValidationService_1.ValidationService(extractionService, diagnosticService, mockValidator, customConfigService);
202
202
  const sourceFile = createSourceFile('<View colorStyles="invalid-custom-class">Hello</View>');
203
- const diagnostics = service.validateFile(ts, sourceFile, []);
203
+ const diagnostics = service.validateFile(ts, sourceFile, {});
204
204
  const validationErrors = diagnostics.filter(d => d.code === DiagnosticService_1.TAILWIND_DIAGNOSTIC_CODE);
205
205
  expect(validationErrors.length).toBeGreaterThan(0);
206
206
  expect(validationErrors[0].messageText).toContain('invalid-custom-class');
@@ -211,7 +211,7 @@ describe('ValidationService', () => {
211
211
  });
212
212
  const service = new ValidationService_1.ValidationService(extractionService, diagnosticService, mockValidator, customConfigService);
213
213
  const sourceFile = createSourceFile('<div className="invalid-class">Hello</div>');
214
- const diagnostics = service.validateFile(ts, sourceFile, []);
214
+ const diagnostics = service.validateFile(ts, sourceFile, {});
215
215
  const validationErrors = diagnostics.filter(d => d.code === DiagnosticService_1.TAILWIND_DIAGNOSTIC_CODE);
216
216
  expect(validationErrors.length).toBeGreaterThan(0);
217
217
  });
@@ -219,20 +219,20 @@ describe('ValidationService', () => {
219
219
  describe('JSX expressions', () => {
220
220
  it('should validate classes in string literals', () => {
221
221
  const sourceFile = createSourceFile("<div className={'invalid-expr'}>Hello</div>");
222
- const diagnostics = validationService.validateFile(ts, sourceFile, []);
222
+ const diagnostics = validationService.validateFile(ts, sourceFile, {});
223
223
  const validationErrors = diagnostics.filter(d => d.code === DiagnosticService_1.TAILWIND_DIAGNOSTIC_CODE);
224
224
  expect(validationErrors.length).toBeGreaterThan(0);
225
225
  });
226
226
  it('should validate classes in template literals', () => {
227
227
  const sourceFile = createSourceFile('<div className={`flex invalid-template`}>Hello</div>');
228
- const diagnostics = validationService.validateFile(ts, sourceFile, []);
228
+ const diagnostics = validationService.validateFile(ts, sourceFile, {});
229
229
  const validationErrors = diagnostics.filter(d => d.code === DiagnosticService_1.TAILWIND_DIAGNOSTIC_CODE);
230
230
  expect(validationErrors.length).toBeGreaterThan(0);
231
231
  expect(validationErrors[0].messageText).toContain('invalid-template');
232
232
  });
233
233
  it('should validate classes in ternary expressions', () => {
234
234
  const sourceFile = createSourceFile("<div className={true ? 'flex' : 'invalid-ternary'}>Hello</div>");
235
- const diagnostics = validationService.validateFile(ts, sourceFile, []);
235
+ const diagnostics = validationService.validateFile(ts, sourceFile, {});
236
236
  const validationErrors = diagnostics.filter(d => d.code === DiagnosticService_1.TAILWIND_DIAGNOSTIC_CODE);
237
237
  expect(validationErrors.length).toBeGreaterThan(0);
238
238
  expect(validationErrors[0].messageText).toContain('invalid-ternary');
@@ -241,12 +241,12 @@ describe('ValidationService', () => {
241
241
  describe('empty and edge cases', () => {
242
242
  it('should handle empty className', () => {
243
243
  const sourceFile = createSourceFile('<div className="">Hello</div>');
244
- const diagnostics = validationService.validateFile(ts, sourceFile, []);
244
+ const diagnostics = validationService.validateFile(ts, sourceFile, {});
245
245
  expect(diagnostics).toHaveLength(0);
246
246
  });
247
247
  it('should handle elements without className', () => {
248
248
  const sourceFile = createSourceFile('<div>Hello</div>');
249
- const diagnostics = validationService.validateFile(ts, sourceFile, []);
249
+ const diagnostics = validationService.validateFile(ts, sourceFile, {});
250
250
  expect(diagnostics).toHaveLength(0);
251
251
  });
252
252
  it('should handle multiple elements', () => {
@@ -257,13 +257,13 @@ describe('ValidationService', () => {
257
257
  </span>
258
258
  </div>
259
259
  `);
260
- const diagnostics = validationService.validateFile(ts, sourceFile, []);
260
+ const diagnostics = validationService.validateFile(ts, sourceFile, {});
261
261
  const validationErrors = diagnostics.filter(d => d.code === DiagnosticService_1.TAILWIND_DIAGNOSTIC_CODE);
262
262
  expect(validationErrors.length).toBe(2);
263
263
  });
264
264
  it('should handle self-closing elements', () => {
265
265
  const sourceFile = createSourceFile('<img className="invalid-self-closing" />');
266
- const diagnostics = validationService.validateFile(ts, sourceFile, []);
266
+ const diagnostics = validationService.validateFile(ts, sourceFile, {});
267
267
  const validationErrors = diagnostics.filter(d => d.code === DiagnosticService_1.TAILWIND_DIAGNOSTIC_CODE);
268
268
  expect(validationErrors.length).toBeGreaterThan(0);
269
269
  });
@@ -271,17 +271,17 @@ describe('ValidationService', () => {
271
271
  describe('file type support', () => {
272
272
  it('should validate TSX files', () => {
273
273
  const sourceFile = createSourceFile('<div className="invalid-class">Hello</div>', 'Component.tsx');
274
- const diagnostics = validationService.validateFile(ts, sourceFile, []);
274
+ const diagnostics = validationService.validateFile(ts, sourceFile, {});
275
275
  expect(diagnostics.length).toBeGreaterThan(0);
276
276
  });
277
277
  it('should validate JSX files', () => {
278
278
  const sourceFile = ts.createSourceFile('Component.jsx', '<div className="invalid-class">Hello</div>', ts.ScriptTarget.Latest, true, ts.ScriptKind.JSX);
279
- const diagnostics = validationService.validateFile(ts, sourceFile, []);
279
+ const diagnostics = validationService.validateFile(ts, sourceFile, {});
280
280
  expect(diagnostics.length).toBeGreaterThan(0);
281
281
  });
282
282
  it('should return empty for unsupported file types', () => {
283
283
  const sourceFile = ts.createSourceFile('styles.css', '.class { color: red; }', ts.ScriptTarget.Latest, true);
284
- const diagnostics = validationService.validateFile(ts, sourceFile, []);
284
+ const diagnostics = validationService.validateFile(ts, sourceFile, {});
285
285
  expect(diagnostics).toHaveLength(0);
286
286
  });
287
287
  });
@@ -0,0 +1,10 @@
1
+ export interface CssAutoDetectResult {
2
+ cssFilePath: string | undefined;
3
+ status: 'found' | 'not-found' | 'multiple-found';
4
+ matchingFiles: string[];
5
+ }
6
+ export declare class CssAutoDetector {
7
+ detect(projectRoot: string): CssAutoDetectResult;
8
+ private scanDirectory;
9
+ }
10
+ //# sourceMappingURL=CssAutoDetector.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"CssAutoDetector.d.ts","sourceRoot":"","sources":["../../src/utils/CssAutoDetector.ts"],"names":[],"mappings":"AAGA,MAAM,WAAW,mBAAmB;IACnC,WAAW,EAAE,MAAM,GAAG,SAAS,CAAC;IAChC,MAAM,EAAE,OAAO,GAAG,WAAW,GAAG,gBAAgB,CAAC;IACjD,aAAa,EAAE,MAAM,EAAE,CAAC;CACxB;AAqBD,qBAAa,eAAe;IAC3B,MAAM,CAAC,WAAW,EAAE,MAAM,GAAG,mBAAmB;IAgChD,OAAO,CAAC,aAAa;CAyCrB"}
@@ -0,0 +1,93 @@
1
+ "use strict";
2
+ var __importDefault = (this && this.__importDefault) || function (mod) {
3
+ return (mod && mod.__esModule) ? mod : { "default": mod };
4
+ };
5
+ Object.defineProperty(exports, "__esModule", { value: true });
6
+ exports.CssAutoDetector = void 0;
7
+ const fs_1 = __importDefault(require("fs"));
8
+ const path_1 = __importDefault(require("path"));
9
+ const SKIPPED_DIRECTORIES = new Set([
10
+ 'node_modules',
11
+ 'dist',
12
+ '.git',
13
+ 'build',
14
+ 'out',
15
+ '.next',
16
+ '.nuxt',
17
+ '.output',
18
+ '.svelte-kit',
19
+ 'coverage',
20
+ '.turbo',
21
+ '.cache'
22
+ ]);
23
+ const MAX_DEPTH = 5;
24
+ const TAILWIND_IMPORT_REGEX = /^@import\s+["']tailwindcss(?:\/[^"']*)?["'];?\s*$/m;
25
+ class CssAutoDetector {
26
+ detect(projectRoot) {
27
+ const matchingFiles = [];
28
+ try {
29
+ this.scanDirectory(projectRoot, matchingFiles, 0);
30
+ }
31
+ catch {
32
+ // Silently handle unreadable root directory
33
+ }
34
+ if (matchingFiles.length === 1) {
35
+ return {
36
+ cssFilePath: matchingFiles[0],
37
+ status: 'found',
38
+ matchingFiles
39
+ };
40
+ }
41
+ if (matchingFiles.length > 1) {
42
+ return {
43
+ cssFilePath: undefined,
44
+ status: 'multiple-found',
45
+ matchingFiles
46
+ };
47
+ }
48
+ return {
49
+ cssFilePath: undefined,
50
+ status: 'not-found',
51
+ matchingFiles: []
52
+ };
53
+ }
54
+ scanDirectory(dirPath, matchingFiles, depth) {
55
+ if (depth > MAX_DEPTH) {
56
+ return;
57
+ }
58
+ let entries;
59
+ try {
60
+ entries = fs_1.default.readdirSync(dirPath, { withFileTypes: true });
61
+ }
62
+ catch {
63
+ return;
64
+ }
65
+ for (const entry of entries) {
66
+ const fullPath = path_1.default.join(dirPath, entry.name);
67
+ if (entry.isDirectory()) {
68
+ if (!SKIPPED_DIRECTORIES.has(entry.name)) {
69
+ this.scanDirectory(fullPath, matchingFiles, depth + 1);
70
+ }
71
+ continue;
72
+ }
73
+ if (!entry.isFile() || !entry.name.endsWith('.css')) {
74
+ continue;
75
+ }
76
+ try {
77
+ const fd = fs_1.default.openSync(fullPath, 'r');
78
+ const buffer = Buffer.alloc(1024);
79
+ const bytesRead = fs_1.default.readSync(fd, buffer, 0, 1024, 0);
80
+ fs_1.default.closeSync(fd);
81
+ const content = buffer.toString('utf-8', 0, bytesRead);
82
+ if (TAILWIND_IMPORT_REGEX.test(content)) {
83
+ matchingFiles.push(fullPath);
84
+ }
85
+ }
86
+ catch {
87
+ // Silently skip unreadable files
88
+ }
89
+ }
90
+ }
91
+ }
92
+ exports.CssAutoDetector = CssAutoDetector;
93
+ //# sourceMappingURL=CssAutoDetector.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"CssAutoDetector.js","sourceRoot":"","sources":["../../src/utils/CssAutoDetector.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,2 @@
1
+ export {};
2
+ //# sourceMappingURL=CssAutoDetector.spec.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"CssAutoDetector.spec.d.ts","sourceRoot":"","sources":["../../src/utils/CssAutoDetector.spec.ts"],"names":[],"mappings":""}
@@ -0,0 +1,223 @@
1
+ "use strict";
2
+ var __importDefault = (this && this.__importDefault) || function (mod) {
3
+ return (mod && mod.__esModule) ? mod : { "default": mod };
4
+ };
5
+ Object.defineProperty(exports, "__esModule", { value: true });
6
+ const fs_1 = __importDefault(require("fs"));
7
+ const os_1 = __importDefault(require("os"));
8
+ const path_1 = __importDefault(require("path"));
9
+ const CssAutoDetector_1 = require("./CssAutoDetector");
10
+ describe('CssAutoDetector', () => {
11
+ let detector;
12
+ let tempDir;
13
+ beforeEach(() => {
14
+ detector = new CssAutoDetector_1.CssAutoDetector();
15
+ tempDir = fs_1.default.mkdtempSync(path_1.default.join(os_1.default.tmpdir(), 'css-autodetect-'));
16
+ });
17
+ afterEach(() => {
18
+ fs_1.default.rmSync(tempDir, { recursive: true, force: true });
19
+ });
20
+ function createFile(relativePath, content) {
21
+ const fullPath = path_1.default.join(tempDir, relativePath);
22
+ fs_1.default.mkdirSync(path_1.default.dirname(fullPath), { recursive: true });
23
+ fs_1.default.writeFileSync(fullPath, content);
24
+ return fullPath;
25
+ }
26
+ function createDir(relativePath) {
27
+ const fullPath = path_1.default.join(tempDir, relativePath);
28
+ fs_1.default.mkdirSync(fullPath, { recursive: true });
29
+ return fullPath;
30
+ }
31
+ describe('single file detection', () => {
32
+ it('should find CSS file in project root', () => {
33
+ const cssPath = createFile('globals.css', '@import "tailwindcss";');
34
+ const result = detector.detect(tempDir);
35
+ expect(result.status).toBe('found');
36
+ expect(result.cssFilePath).toBe(cssPath);
37
+ expect(result.matchingFiles).toEqual([cssPath]);
38
+ });
39
+ it('should find CSS file in src/ subdirectory', () => {
40
+ const cssPath = createFile('src/globals.css', '@import "tailwindcss";');
41
+ const result = detector.detect(tempDir);
42
+ expect(result.status).toBe('found');
43
+ expect(result.cssFilePath).toBe(cssPath);
44
+ });
45
+ it('should find CSS file in deeply nested directory', () => {
46
+ const cssPath = createFile('src/styles/base/globals.css', '@import "tailwindcss";');
47
+ const result = detector.detect(tempDir);
48
+ expect(result.status).toBe('found');
49
+ expect(result.cssFilePath).toBe(cssPath);
50
+ });
51
+ });
52
+ describe('import syntax variations', () => {
53
+ it('should match double quotes: @import "tailwindcss"', () => {
54
+ createFile('style.css', '@import "tailwindcss";');
55
+ const result = detector.detect(tempDir);
56
+ expect(result.status).toBe('found');
57
+ });
58
+ it("should match single quotes: @import 'tailwindcss'", () => {
59
+ createFile('style.css', "@import 'tailwindcss';");
60
+ const result = detector.detect(tempDir);
61
+ expect(result.status).toBe('found');
62
+ });
63
+ it('should match without semicolon: @import "tailwindcss"', () => {
64
+ createFile('style.css', '@import "tailwindcss"');
65
+ const result = detector.detect(tempDir);
66
+ expect(result.status).toBe('found');
67
+ });
68
+ it('should match subpath: @import "tailwindcss/theme"', () => {
69
+ createFile('style.css', '@import "tailwindcss/theme";');
70
+ const result = detector.detect(tempDir);
71
+ expect(result.status).toBe('found');
72
+ });
73
+ it('should match subpath: @import "tailwindcss/preflight"', () => {
74
+ createFile('style.css', '@import "tailwindcss/preflight";');
75
+ const result = detector.detect(tempDir);
76
+ expect(result.status).toBe('found');
77
+ });
78
+ it('should match subpath with single quotes', () => {
79
+ createFile('style.css', "@import 'tailwindcss/theme';");
80
+ const result = detector.detect(tempDir);
81
+ expect(result.status).toBe('found');
82
+ });
83
+ it('should match with extra whitespace after @import', () => {
84
+ createFile('style.css', '@import "tailwindcss";');
85
+ const result = detector.detect(tempDir);
86
+ expect(result.status).toBe('found');
87
+ });
88
+ it('should match import preceded by comments and blank lines', () => {
89
+ createFile('style.css', `/* My stylesheet */
90
+
91
+ @import "tailwindcss";
92
+ `);
93
+ const result = detector.detect(tempDir);
94
+ expect(result.status).toBe('found');
95
+ });
96
+ });
97
+ describe('files that should NOT match', () => {
98
+ it('should not match CSS importing tailwindcss-animate (different package)', () => {
99
+ createFile('style.css', '@import "tailwindcss-animate";');
100
+ const result = detector.detect(tempDir);
101
+ expect(result.status).toBe('not-found');
102
+ });
103
+ it('should not match CSS without any Tailwind import', () => {
104
+ createFile('style.css', 'body { margin: 0; }');
105
+ const result = detector.detect(tempDir);
106
+ expect(result.status).toBe('not-found');
107
+ });
108
+ it('should not match non-CSS files containing the import text', () => {
109
+ createFile('config.js', 'const css = \'@import "tailwindcss";\';');
110
+ createFile('style.scss', '@import "tailwindcss";');
111
+ createFile('data.json', '{"import": "@import \\"tailwindcss\\""}');
112
+ const result = detector.detect(tempDir);
113
+ expect(result.status).toBe('not-found');
114
+ });
115
+ });
116
+ describe('directory skipping', () => {
117
+ const skippedDirs = [
118
+ 'node_modules',
119
+ 'dist',
120
+ '.git',
121
+ 'build',
122
+ 'out',
123
+ '.next',
124
+ '.nuxt',
125
+ '.output',
126
+ 'coverage',
127
+ '.cache'
128
+ ];
129
+ it.each(skippedDirs)('should skip %s directory', dirName => {
130
+ createFile(`${dirName}/style.css`, '@import "tailwindcss";');
131
+ const result = detector.detect(tempDir);
132
+ expect(result.status).toBe('not-found');
133
+ });
134
+ it('should find files in non-skipped directories alongside skipped ones', () => {
135
+ createFile('node_modules/style.css', '@import "tailwindcss";');
136
+ createFile('dist/style.css', '@import "tailwindcss";');
137
+ const cssPath = createFile('src/globals.css', '@import "tailwindcss";');
138
+ const result = detector.detect(tempDir);
139
+ expect(result.status).toBe('found');
140
+ expect(result.cssFilePath).toBe(cssPath);
141
+ });
142
+ });
143
+ describe('multiple matches', () => {
144
+ it('should return multiple-found when two CSS files match', () => {
145
+ createFile('src/globals.css', '@import "tailwindcss";');
146
+ createFile('packages/app/style.css', '@import "tailwindcss";');
147
+ const result = detector.detect(tempDir);
148
+ expect(result.status).toBe('multiple-found');
149
+ expect(result.cssFilePath).toBeUndefined();
150
+ });
151
+ it('should list all matching files', () => {
152
+ const file1 = createFile('src/globals.css', '@import "tailwindcss";');
153
+ const file2 = createFile('packages/app/style.css', '@import "tailwindcss";');
154
+ const result = detector.detect(tempDir);
155
+ expect(result.matchingFiles).toHaveLength(2);
156
+ expect(result.matchingFiles).toContain(file1);
157
+ expect(result.matchingFiles).toContain(file2);
158
+ });
159
+ it('should only count CSS files with Tailwind import, not all CSS files', () => {
160
+ createFile('src/globals.css', '@import "tailwindcss";');
161
+ createFile('src/reset.css', 'body { margin: 0; }');
162
+ createFile('src/utils.css', '.hidden { display: none; }');
163
+ const result = detector.detect(tempDir);
164
+ expect(result.status).toBe('found');
165
+ expect(result.matchingFiles).toHaveLength(1);
166
+ });
167
+ });
168
+ describe('no matches', () => {
169
+ it('should return not-found when no CSS files exist', () => {
170
+ createFile('index.ts', 'export default {}');
171
+ const result = detector.detect(tempDir);
172
+ expect(result.status).toBe('not-found');
173
+ expect(result.matchingFiles).toEqual([]);
174
+ });
175
+ it('should return not-found for empty project directory', () => {
176
+ const result = detector.detect(tempDir);
177
+ expect(result.status).toBe('not-found');
178
+ expect(result.matchingFiles).toEqual([]);
179
+ });
180
+ it('should return not-found with only empty subdirectories', () => {
181
+ createDir('src');
182
+ createDir('lib');
183
+ const result = detector.detect(tempDir);
184
+ expect(result.status).toBe('not-found');
185
+ });
186
+ });
187
+ describe('depth limit', () => {
188
+ it('should find files at depth 5', () => {
189
+ // depth 0 = project root, depth 5 = 5 levels deep
190
+ const cssPath = createFile('a/b/c/d/e/style.css', '@import "tailwindcss";');
191
+ const result = detector.detect(tempDir);
192
+ expect(result.status).toBe('found');
193
+ expect(result.cssFilePath).toBe(cssPath);
194
+ });
195
+ it('should NOT find files at depth 6', () => {
196
+ createFile('a/b/c/d/e/f/style.css', '@import "tailwindcss";');
197
+ const result = detector.detect(tempDir);
198
+ expect(result.status).toBe('not-found');
199
+ });
200
+ });
201
+ describe('error handling', () => {
202
+ it('should return not-found for non-existent project root', () => {
203
+ const result = detector.detect('/non/existent/path');
204
+ expect(result.status).toBe('not-found');
205
+ expect(result.matchingFiles).toEqual([]);
206
+ });
207
+ it('should still find valid files when some directories are unreadable', () => {
208
+ const cssPath = createFile('src/globals.css', '@import "tailwindcss";');
209
+ const unreadableDir = createDir('restricted');
210
+ try {
211
+ fs_1.default.chmodSync(unreadableDir, 0o000);
212
+ const result = detector.detect(tempDir);
213
+ expect(result.status).toBe('found');
214
+ expect(result.cssFilePath).toBe(cssPath);
215
+ }
216
+ finally {
217
+ // Restore permissions for cleanup
218
+ fs_1.default.chmodSync(unreadableDir, 0o755);
219
+ }
220
+ });
221
+ });
222
+ });
223
+ //# sourceMappingURL=CssAutoDetector.spec.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"CssAutoDetector.spec.js","sourceRoot":"","sources":["../../src/utils/CssAutoDetector.spec.ts"],"names":[],"mappings":"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"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "tailwind-typescript-plugin",
3
- "version": "1.4.0-beta.24",
3
+ "version": "1.4.0-beta.26",
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",
@@ -14,6 +14,10 @@
14
14
  "build": "tsc",
15
15
  "watch": "tsc --watch",
16
16
  "test": "jest --testPathPattern=src/",
17
+ "test:integration": "cd e2e && npm test",
18
+ "test:integration:ui": "cd e2e && npm run test:ui",
19
+ "test:integration:headed": "cd e2e && npm run test:headed",
20
+ "test:all": "npm test && npm run test:integration",
17
21
  "lint": "eslint src --ext .ts,.tsx,.json --quiet --cache",
18
22
  "tsc": "tsc --noEmit",
19
23
  "prepare": "npm run build",
@@ -73,18 +77,20 @@
73
77
  "eslint-plugin-react-hooks": "^5.2.0",
74
78
  "eslint-plugin-storybook": "^9.0.16",
75
79
  "jest": "^29.7.0",
80
+ "postcss": "^8.5.6",
76
81
  "prettier": "^3.5.3",
77
82
  "semantic-release": "^24.2.9",
83
+ "tailwindcss": "^4.1.17",
78
84
  "ts-jest": "^29.4.5",
79
85
  "ts-node": "^10.9.2",
80
86
  "typescript": "^5.7.2"
81
87
  },
82
88
  "peerDependencies": {
83
- "typescript": ">=4.0.0"
89
+ "postcss": "^8.0.0",
90
+ "tailwindcss": "^4.0.0",
91
+ "typescript": ">=5.0.0"
84
92
  },
85
93
  "dependencies": {
86
- "postcss": "^8.5.6",
87
- "tailwindcss": "^4.1.17",
88
94
  "zod": "^3.25.76"
89
95
  }
90
96
  }