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.
- package/CHANGELOG.md +27 -0
- package/README.md +235 -1173
- package/lib/core/interfaces.d.ts +17 -1
- package/lib/core/interfaces.d.ts.map +1 -1
- package/lib/core/types.d.ts +1 -23
- package/lib/core/types.d.ts.map +1 -1
- package/lib/extractors/BaseExtractor.d.ts +10 -4
- package/lib/extractors/BaseExtractor.d.ts.map +1 -1
- package/lib/extractors/BaseExtractor.js +31 -41
- package/lib/extractors/BaseExtractor.js.map +1 -1
- package/lib/extractors/BaseExtractor.spec.js +23 -23
- package/lib/extractors/BaseExtractor.spec.js.map +1 -1
- package/lib/extractors/CvaExtractor.js +1 -1
- package/lib/extractors/CvaExtractor.js.map +1 -1
- package/lib/extractors/CvaExtractor.spec.js +4 -4
- package/lib/extractors/CvaExtractor.spec.js.map +1 -1
- package/lib/extractors/ExpressionExtractor.js +1 -1
- package/lib/extractors/ExpressionExtractor.js.map +1 -1
- package/lib/extractors/ExpressionExtractor.spec.js +4 -4
- package/lib/extractors/ExpressionExtractor.spec.js.map +1 -1
- package/lib/extractors/JsxAttributeExtractor.d.ts +5 -0
- package/lib/extractors/JsxAttributeExtractor.d.ts.map +1 -1
- package/lib/extractors/JsxAttributeExtractor.js +7 -1
- package/lib/extractors/JsxAttributeExtractor.js.map +1 -1
- package/lib/extractors/JsxAttributeExtractor.spec.js +6 -6
- package/lib/extractors/JsxAttributeExtractor.spec.js.map +1 -1
- package/lib/extractors/TailwindVariantsExtractor.js +1 -1
- package/lib/extractors/TailwindVariantsExtractor.js.map +1 -1
- package/lib/extractors/TailwindVariantsExtractor.spec.js +4 -4
- package/lib/extractors/TailwindVariantsExtractor.spec.js.map +1 -1
- package/lib/extractors/TemplateExpressionExtractor.spec.js +1 -1
- package/lib/extractors/TemplateExpressionExtractor.spec.js.map +1 -1
- package/lib/extractors/VariableReferenceExtractor.spec.js +1 -1
- package/lib/extractors/VariableReferenceExtractor.spec.js.map +1 -1
- package/lib/extractors/VueAttributeExtractor.d.ts +8 -2
- package/lib/extractors/VueAttributeExtractor.d.ts.map +1 -1
- package/lib/extractors/VueAttributeExtractor.js +26 -31
- package/lib/extractors/VueAttributeExtractor.js.map +1 -1
- package/lib/extractors/VueExpressionExtractor.d.ts +2 -2
- package/lib/extractors/VueExpressionExtractor.d.ts.map +1 -1
- package/lib/extractors/VueExpressionExtractor.js +18 -30
- package/lib/extractors/VueExpressionExtractor.js.map +1 -1
- package/lib/plugin/TailwindTypescriptPlugin.d.ts +9 -0
- package/lib/plugin/TailwindTypescriptPlugin.d.ts.map +1 -1
- package/lib/plugin/TailwindTypescriptPlugin.js +57 -20
- package/lib/plugin/TailwindTypescriptPlugin.js.map +1 -1
- package/lib/services/ClassNameExtractionService.d.ts +9 -10
- package/lib/services/ClassNameExtractionService.d.ts.map +1 -1
- package/lib/services/ClassNameExtractionService.js +28 -34
- package/lib/services/ClassNameExtractionService.js.map +1 -1
- package/lib/services/ClassNameExtractionService.spec.js +16 -16
- package/lib/services/CompletionService.d.ts +2 -2
- package/lib/services/CompletionService.d.ts.map +1 -1
- package/lib/services/CompletionService.js +3 -1
- package/lib/services/CompletionService.js.map +1 -1
- package/lib/services/CompletionService.spec.js +10 -10
- package/lib/services/CompletionService.spec.js.map +1 -1
- package/lib/services/ConflictClassDetection.spec.js +84 -36
- package/lib/services/ConflictClassDetection.spec.js.map +1 -1
- package/lib/services/DuplicateClassDetection.spec.js +32 -32
- package/lib/services/DuplicateClassDetection.spec.js.map +1 -1
- package/lib/services/PluginConfigService.d.ts +1 -11
- package/lib/services/PluginConfigService.d.ts.map +1 -1
- package/lib/services/PluginConfigService.js +0 -27
- package/lib/services/PluginConfigService.js.map +1 -1
- package/lib/services/PluginConfigService.spec.js +9 -3
- package/lib/services/PluginConfigService.spec.js.map +1 -1
- package/lib/services/ValidationService.d.ts +2 -2
- package/lib/services/ValidationService.d.ts.map +1 -1
- package/lib/services/ValidationService.js +2 -2
- package/lib/services/ValidationService.js.map +1 -1
- package/lib/services/ValidationService.spec.js +24 -24
- package/lib/utils/CssAutoDetector.d.ts +10 -0
- package/lib/utils/CssAutoDetector.d.ts.map +1 -0
- package/lib/utils/CssAutoDetector.js +93 -0
- package/lib/utils/CssAutoDetector.js.map +1 -0
- package/lib/utils/CssAutoDetector.spec.d.ts +2 -0
- package/lib/utils/CssAutoDetector.spec.d.ts.map +1 -0
- package/lib/utils/CssAutoDetector.spec.js +223 -0
- package/lib/utils/CssAutoDetector.spec.js.map +1 -0
- 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 @@
|
|
|
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.
|
|
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
|
-
"
|
|
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
|
}
|