tailwind-typescript-plugin 0.0.2-beta.1
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 +42 -0
- package/LICENSE +21 -0
- package/README.md +538 -0
- package/lib/core/interfaces.d.ts +45 -0
- package/lib/core/interfaces.d.ts.map +1 -0
- package/lib/core/interfaces.js +3 -0
- package/lib/core/interfaces.js.map +1 -0
- package/lib/core/types.d.ts +27 -0
- package/lib/core/types.d.ts.map +1 -0
- package/lib/core/types.js +3 -0
- package/lib/core/types.js.map +1 -0
- package/lib/extractors/BaseExtractor.d.ts +20 -0
- package/lib/extractors/BaseExtractor.d.ts.map +1 -0
- package/lib/extractors/BaseExtractor.js +83 -0
- package/lib/extractors/BaseExtractor.js.map +1 -0
- package/lib/extractors/CvaExtractor.d.ts +88 -0
- package/lib/extractors/CvaExtractor.d.ts.map +1 -0
- package/lib/extractors/CvaExtractor.js +425 -0
- package/lib/extractors/CvaExtractor.js.map +1 -0
- package/lib/extractors/ExpressionExtractor.d.ts +16 -0
- package/lib/extractors/ExpressionExtractor.d.ts.map +1 -0
- package/lib/extractors/ExpressionExtractor.js +132 -0
- package/lib/extractors/ExpressionExtractor.js.map +1 -0
- package/lib/extractors/JsxAttributeExtractor.d.ts +20 -0
- package/lib/extractors/JsxAttributeExtractor.d.ts.map +1 -0
- package/lib/extractors/JsxAttributeExtractor.js +107 -0
- package/lib/extractors/JsxAttributeExtractor.js.map +1 -0
- package/lib/extractors/JsxAttributeExtractor.original.d.ts +15 -0
- package/lib/extractors/JsxAttributeExtractor.original.d.ts.map +1 -0
- package/lib/extractors/JsxAttributeExtractor.original.js +84 -0
- package/lib/extractors/JsxAttributeExtractor.original.js.map +1 -0
- package/lib/extractors/StringLiteralExtractor.d.ts +12 -0
- package/lib/extractors/StringLiteralExtractor.d.ts.map +1 -0
- package/lib/extractors/StringLiteralExtractor.js +21 -0
- package/lib/extractors/StringLiteralExtractor.js.map +1 -0
- package/lib/extractors/TailwindVariantsExtractor.d.ts +87 -0
- package/lib/extractors/TailwindVariantsExtractor.d.ts.map +1 -0
- package/lib/extractors/TailwindVariantsExtractor.js +447 -0
- package/lib/extractors/TailwindVariantsExtractor.js.map +1 -0
- package/lib/extractors/TemplateExpressionExtractor.d.ts +14 -0
- package/lib/extractors/TemplateExpressionExtractor.d.ts.map +1 -0
- package/lib/extractors/TemplateExpressionExtractor.js +66 -0
- package/lib/extractors/TemplateExpressionExtractor.js.map +1 -0
- package/lib/index.d.ts +65 -0
- package/lib/index.d.ts.map +1 -0
- package/lib/index.js +4 -0
- package/lib/index.js.map +1 -0
- package/lib/infrastructure/TailwindValidator.d.ts +42 -0
- package/lib/infrastructure/TailwindValidator.d.ts.map +1 -0
- package/lib/infrastructure/TailwindValidator.js +152 -0
- package/lib/infrastructure/TailwindValidator.js.map +1 -0
- package/lib/infrastructure/TailwindValidator.spec.d.ts +2 -0
- package/lib/infrastructure/TailwindValidator.spec.d.ts.map +1 -0
- package/lib/infrastructure/TailwindValidator.spec.js +219 -0
- package/lib/infrastructure/TailwindValidator.spec.js.map +1 -0
- package/lib/plugin/TailwindTypescriptPlugin.d.ts +52 -0
- package/lib/plugin/TailwindTypescriptPlugin.d.ts.map +1 -0
- package/lib/plugin/TailwindTypescriptPlugin.js +142 -0
- package/lib/plugin/TailwindTypescriptPlugin.js.map +1 -0
- package/lib/services/ClassNameExtractionService.d.ts +37 -0
- package/lib/services/ClassNameExtractionService.d.ts.map +1 -0
- package/lib/services/ClassNameExtractionService.js +98 -0
- package/lib/services/ClassNameExtractionService.js.map +1 -0
- package/lib/services/ClassNameExtractionService.original.d.ts +20 -0
- package/lib/services/ClassNameExtractionService.original.d.ts.map +1 -0
- package/lib/services/ClassNameExtractionService.original.js +48 -0
- package/lib/services/ClassNameExtractionService.original.js.map +1 -0
- package/lib/services/DiagnosticService.d.ts +14 -0
- package/lib/services/DiagnosticService.d.ts.map +1 -0
- package/lib/services/DiagnosticService.js +61 -0
- package/lib/services/DiagnosticService.js.map +1 -0
- package/lib/services/PerformanceCache.d.ts +15 -0
- package/lib/services/PerformanceCache.d.ts.map +1 -0
- package/lib/services/PerformanceCache.js +44 -0
- package/lib/services/PerformanceCache.js.map +1 -0
- package/lib/services/PluginConfigService.d.ts +22 -0
- package/lib/services/PluginConfigService.d.ts.map +1 -0
- package/lib/services/PluginConfigService.js +86 -0
- package/lib/services/PluginConfigService.js.map +1 -0
- package/lib/services/ValidationService.d.ts +25 -0
- package/lib/services/ValidationService.d.ts.map +1 -0
- package/lib/services/ValidationService.js +50 -0
- package/lib/services/ValidationService.js.map +1 -0
- package/lib/utils/Logger.d.ts +10 -0
- package/lib/utils/Logger.d.ts.map +1 -0
- package/lib/utils/Logger.js +13 -0
- package/lib/utils/Logger.js.map +1 -0
- package/package.json +84 -0
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
import { IClassNameValidator } from '../core/interfaces';
|
|
2
|
+
import { Logger } from '../utils/Logger';
|
|
3
|
+
/**
|
|
4
|
+
* Class validator for Tailwind CSS v4
|
|
5
|
+
* This loads the design system once and caches it for validation
|
|
6
|
+
* Implements IClassNameValidator for dependency inversion
|
|
7
|
+
*/
|
|
8
|
+
export declare class TailwindValidator implements IClassNameValidator {
|
|
9
|
+
private classSet;
|
|
10
|
+
private designSystem;
|
|
11
|
+
private cssFilePath;
|
|
12
|
+
private logger;
|
|
13
|
+
private validationCache;
|
|
14
|
+
constructor(cssFilePath: string, logger: Logger);
|
|
15
|
+
/**
|
|
16
|
+
* Load the design system and cache the class list
|
|
17
|
+
*/
|
|
18
|
+
initialize(): Promise<void>;
|
|
19
|
+
isInitialized(): boolean;
|
|
20
|
+
/**
|
|
21
|
+
* Check if a class name is valid
|
|
22
|
+
* This handles both static classes and arbitrary values (e.g., w-[100px])
|
|
23
|
+
* Performance optimized with LRU cache
|
|
24
|
+
*/
|
|
25
|
+
isValidClass(className: string): boolean;
|
|
26
|
+
/**
|
|
27
|
+
* Validate multiple class names and return invalid ones
|
|
28
|
+
*/
|
|
29
|
+
getInvalidClasses(classNames: string[]): string[];
|
|
30
|
+
/**
|
|
31
|
+
* Reload the design system (useful when CSS file changes)
|
|
32
|
+
*/
|
|
33
|
+
reload(): Promise<void>;
|
|
34
|
+
/**
|
|
35
|
+
* Get cache statistics (for performance monitoring)
|
|
36
|
+
*/
|
|
37
|
+
getCacheStats(): {
|
|
38
|
+
size: number;
|
|
39
|
+
maxSize: number;
|
|
40
|
+
};
|
|
41
|
+
}
|
|
42
|
+
//# sourceMappingURL=TailwindValidator.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"TailwindValidator.d.ts","sourceRoot":"","sources":["../../src/infrastructure/TailwindValidator.ts"],"names":[],"mappings":"AAGA,OAAO,EAAE,mBAAmB,EAAE,MAAM,oBAAoB,CAAC;AAEzD,OAAO,EAAE,MAAM,EAAE,MAAM,iBAAiB,CAAC;AAsBzC;;;;GAIG;AACH,qBAAa,iBAAkB,YAAW,mBAAmB;IAC5D,OAAO,CAAC,QAAQ,CAA4B;IAE5C,OAAO,CAAC,YAAY,CAAe;IACnC,OAAO,CAAC,WAAW,CAAS;IAC5B,OAAO,CAAC,MAAM,CAAS;IACvB,OAAO,CAAC,eAAe,CAAoC;gBAE/C,WAAW,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM;IAM/C;;OAEG;IACG,UAAU,IAAI,OAAO,CAAC,IAAI,CAAC;IAgEjC,aAAa,IAAI,OAAO;IAIxB;;;;OAIG;IACH,YAAY,CAAC,SAAS,EAAE,MAAM,GAAG,OAAO;IAiCxC;;OAEG;IACH,iBAAiB,CAAC,UAAU,EAAE,MAAM,EAAE,GAAG,MAAM,EAAE;IAQjD;;OAEG;IACG,MAAM,IAAI,OAAO,CAAC,IAAI,CAAC;IAM7B;;OAEG;IACH,aAAa,IAAI;QAAE,IAAI,EAAE,MAAM,CAAC;QAAC,OAAO,EAAE,MAAM,CAAA;KAAE;CAMlD"}
|
|
@@ -0,0 +1,152 @@
|
|
|
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.TailwindValidator = void 0;
|
|
7
|
+
const fs_1 = __importDefault(require("fs"));
|
|
8
|
+
const path_1 = __importDefault(require("path"));
|
|
9
|
+
const PerformanceCache_1 = require("../services/PerformanceCache");
|
|
10
|
+
/**
|
|
11
|
+
* Class validator for Tailwind CSS v4
|
|
12
|
+
* This loads the design system once and caches it for validation
|
|
13
|
+
* Implements IClassNameValidator for dependency inversion
|
|
14
|
+
*/
|
|
15
|
+
class TailwindValidator {
|
|
16
|
+
constructor(cssFilePath, logger) {
|
|
17
|
+
this.classSet = null;
|
|
18
|
+
this.cssFilePath = cssFilePath;
|
|
19
|
+
this.logger = logger;
|
|
20
|
+
this.validationCache = new PerformanceCache_1.PerformanceCache(2000);
|
|
21
|
+
}
|
|
22
|
+
/**
|
|
23
|
+
* Load the design system and cache the class list
|
|
24
|
+
*/
|
|
25
|
+
async initialize() {
|
|
26
|
+
if (this.classSet !== null) {
|
|
27
|
+
return; // Already initialized
|
|
28
|
+
}
|
|
29
|
+
this.logger.log(`[TailwindValidator] Loading design system from: ${this.cssFilePath}`);
|
|
30
|
+
try {
|
|
31
|
+
// Load the design system with full API access
|
|
32
|
+
const tailwindcss = require('tailwindcss');
|
|
33
|
+
if (!tailwindcss.__unstable__loadDesignSystem) {
|
|
34
|
+
throw new Error('Tailwind CSS v4 with __unstable__loadDesignSystem API is required');
|
|
35
|
+
}
|
|
36
|
+
const css = fs_1.default.readFileSync(this.cssFilePath, 'utf-8');
|
|
37
|
+
this.designSystem = await tailwindcss.__unstable__loadDesignSystem(css, {
|
|
38
|
+
base: path_1.default.dirname(this.cssFilePath),
|
|
39
|
+
loadStylesheet: async (id, base) => {
|
|
40
|
+
try {
|
|
41
|
+
if (id === 'tailwindcss' || id === 'tailwindcss/theme.css') {
|
|
42
|
+
const tailwindPackagePath = require.resolve('tailwindcss/package.json');
|
|
43
|
+
const tailwindDir = path_1.default.dirname(tailwindPackagePath);
|
|
44
|
+
const themePath = path_1.default.join(tailwindDir, 'theme.css');
|
|
45
|
+
return {
|
|
46
|
+
base: tailwindDir,
|
|
47
|
+
content: fs_1.default.readFileSync(themePath, 'utf-8')
|
|
48
|
+
};
|
|
49
|
+
}
|
|
50
|
+
const resolvedPath = path_1.default.resolve(base, id);
|
|
51
|
+
return {
|
|
52
|
+
base: path_1.default.dirname(resolvedPath),
|
|
53
|
+
content: fs_1.default.readFileSync(resolvedPath, 'utf-8')
|
|
54
|
+
};
|
|
55
|
+
}
|
|
56
|
+
catch (err) {
|
|
57
|
+
this.logger.log(`[TailwindValidator] Failed to load stylesheet: ${err}`);
|
|
58
|
+
return { base, content: '' };
|
|
59
|
+
}
|
|
60
|
+
},
|
|
61
|
+
loadModule: async (id, base, resourceType) => {
|
|
62
|
+
try {
|
|
63
|
+
const resolvedPath = require.resolve(id, { paths: [base] });
|
|
64
|
+
const module = require(resolvedPath);
|
|
65
|
+
return { base: path_1.default.dirname(resolvedPath), module };
|
|
66
|
+
}
|
|
67
|
+
catch (err) {
|
|
68
|
+
this.logger.log(`[TailwindValidator] Failed to load module: ${err}`);
|
|
69
|
+
if (resourceType === 'config') {
|
|
70
|
+
return { base, module: {} };
|
|
71
|
+
}
|
|
72
|
+
else if (resourceType === 'plugin') {
|
|
73
|
+
return { base, module: () => { } };
|
|
74
|
+
}
|
|
75
|
+
return { base, module: null };
|
|
76
|
+
}
|
|
77
|
+
}
|
|
78
|
+
});
|
|
79
|
+
this.classSet = new Set(this.designSystem.getClassList().map(([className]) => className));
|
|
80
|
+
}
|
|
81
|
+
catch (error) {
|
|
82
|
+
this.logger.log(`[TailwindValidator] Failed to load design system: ${error}`);
|
|
83
|
+
throw error;
|
|
84
|
+
}
|
|
85
|
+
}
|
|
86
|
+
isInitialized() {
|
|
87
|
+
return this.classSet !== null;
|
|
88
|
+
}
|
|
89
|
+
/**
|
|
90
|
+
* Check if a class name is valid
|
|
91
|
+
* This handles both static classes and arbitrary values (e.g., w-[100px])
|
|
92
|
+
* Performance optimized with LRU cache
|
|
93
|
+
*/
|
|
94
|
+
isValidClass(className) {
|
|
95
|
+
if (!this.classSet || !this.designSystem) {
|
|
96
|
+
this.logger.log('[TailwindValidator] Validator not initialized. Call initialize() first.');
|
|
97
|
+
return true; // Assume valid if not initialized
|
|
98
|
+
}
|
|
99
|
+
// Check cache first (performance optimization)
|
|
100
|
+
if (this.validationCache.has(className)) {
|
|
101
|
+
return this.validationCache.get(className);
|
|
102
|
+
}
|
|
103
|
+
// First, check if it's in the static class list (fast path)
|
|
104
|
+
if (this.classSet.has(className)) {
|
|
105
|
+
this.validationCache.set(className, true);
|
|
106
|
+
return true;
|
|
107
|
+
}
|
|
108
|
+
// If not in the static list, it might be an arbitrary value like w-[100px]
|
|
109
|
+
// Use the design system to check if it generates valid CSS
|
|
110
|
+
try {
|
|
111
|
+
const result = this.designSystem.candidatesToCss([className]);
|
|
112
|
+
// If candidatesToCss returns a non-null value, the class is valid
|
|
113
|
+
const isValid = result[0] !== null;
|
|
114
|
+
this.validationCache.set(className, isValid);
|
|
115
|
+
return isValid;
|
|
116
|
+
}
|
|
117
|
+
catch (err) {
|
|
118
|
+
this.logger.log(`[TailwindValidator] Failed to check class: ${err}`);
|
|
119
|
+
// If there's an error, consider it invalid
|
|
120
|
+
this.validationCache.set(className, false);
|
|
121
|
+
return false;
|
|
122
|
+
}
|
|
123
|
+
}
|
|
124
|
+
/**
|
|
125
|
+
* Validate multiple class names and return invalid ones
|
|
126
|
+
*/
|
|
127
|
+
getInvalidClasses(classNames) {
|
|
128
|
+
if (!this.classSet) {
|
|
129
|
+
return [];
|
|
130
|
+
}
|
|
131
|
+
return classNames.filter(className => !this.isValidClass(className));
|
|
132
|
+
}
|
|
133
|
+
/**
|
|
134
|
+
* Reload the design system (useful when CSS file changes)
|
|
135
|
+
*/
|
|
136
|
+
async reload() {
|
|
137
|
+
this.classSet = null;
|
|
138
|
+
this.validationCache.clear();
|
|
139
|
+
await this.initialize();
|
|
140
|
+
}
|
|
141
|
+
/**
|
|
142
|
+
* Get cache statistics (for performance monitoring)
|
|
143
|
+
*/
|
|
144
|
+
getCacheStats() {
|
|
145
|
+
return {
|
|
146
|
+
size: this.validationCache.size,
|
|
147
|
+
maxSize: 2000
|
|
148
|
+
};
|
|
149
|
+
}
|
|
150
|
+
}
|
|
151
|
+
exports.TailwindValidator = TailwindValidator;
|
|
152
|
+
//# sourceMappingURL=TailwindValidator.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"TailwindValidator.js","sourceRoot":"","sources":["../../src/infrastructure/TailwindValidator.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"TailwindValidator.spec.d.ts","sourceRoot":"","sources":["../../src/infrastructure/TailwindValidator.spec.ts"],"names":[],"mappings":""}
|
|
@@ -0,0 +1,219 @@
|
|
|
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 TailwindValidator_1 = require("./TailwindValidator");
|
|
10
|
+
// Mock logger for testing
|
|
11
|
+
class MockLogger {
|
|
12
|
+
// eslint-disable-next-line @typescript-eslint/no-unused-vars
|
|
13
|
+
log(_message) {
|
|
14
|
+
// Silent during tests
|
|
15
|
+
}
|
|
16
|
+
}
|
|
17
|
+
describe('TailwindValidator', () => {
|
|
18
|
+
let validator;
|
|
19
|
+
let tempCssFile;
|
|
20
|
+
beforeAll(async () => {
|
|
21
|
+
// Create a temporary CSS file for testing
|
|
22
|
+
const tempDir = fs_1.default.mkdtempSync(path_1.default.join(os_1.default.tmpdir(), 'tailwind-test-'));
|
|
23
|
+
tempCssFile = path_1.default.join(tempDir, 'global.css');
|
|
24
|
+
fs_1.default.writeFileSync(tempCssFile, '@import "tailwindcss";');
|
|
25
|
+
validator = new TailwindValidator_1.TailwindValidator(tempCssFile, new MockLogger());
|
|
26
|
+
await validator.initialize();
|
|
27
|
+
});
|
|
28
|
+
describe('initialization', () => {
|
|
29
|
+
it('should initialize successfully', () => {
|
|
30
|
+
expect(validator.isInitialized()).toBe(true);
|
|
31
|
+
});
|
|
32
|
+
it('should not re-initialize if already initialized', async () => {
|
|
33
|
+
const beforeInit = validator.isInitialized();
|
|
34
|
+
await validator.initialize();
|
|
35
|
+
const afterInit = validator.isInitialized();
|
|
36
|
+
expect(beforeInit).toBe(afterInit);
|
|
37
|
+
});
|
|
38
|
+
});
|
|
39
|
+
describe('isValidClass', () => {
|
|
40
|
+
describe('standard Tailwind classes', () => {
|
|
41
|
+
it('should validate basic utility classes', () => {
|
|
42
|
+
expect(validator.isValidClass('flex')).toBe(true);
|
|
43
|
+
expect(validator.isValidClass('block')).toBe(true);
|
|
44
|
+
expect(validator.isValidClass('hidden')).toBe(true);
|
|
45
|
+
expect(validator.isValidClass('container')).toBe(true);
|
|
46
|
+
});
|
|
47
|
+
it('should validate spacing utilities', () => {
|
|
48
|
+
expect(validator.isValidClass('p-4')).toBe(true);
|
|
49
|
+
expect(validator.isValidClass('m-8')).toBe(true);
|
|
50
|
+
expect(validator.isValidClass('mx-auto')).toBe(true);
|
|
51
|
+
expect(validator.isValidClass('py-2')).toBe(true);
|
|
52
|
+
});
|
|
53
|
+
it('should validate color utilities', () => {
|
|
54
|
+
expect(validator.isValidClass('bg-blue-500')).toBe(true);
|
|
55
|
+
expect(validator.isValidClass('text-red-600')).toBe(true);
|
|
56
|
+
expect(validator.isValidClass('border-gray-300')).toBe(true);
|
|
57
|
+
});
|
|
58
|
+
it('should validate typography utilities', () => {
|
|
59
|
+
expect(validator.isValidClass('text-lg')).toBe(true);
|
|
60
|
+
expect(validator.isValidClass('font-bold')).toBe(true);
|
|
61
|
+
expect(validator.isValidClass('text-center')).toBe(true);
|
|
62
|
+
});
|
|
63
|
+
it('should validate layout utilities', () => {
|
|
64
|
+
expect(validator.isValidClass('w-full')).toBe(true);
|
|
65
|
+
expect(validator.isValidClass('h-screen')).toBe(true);
|
|
66
|
+
expect(validator.isValidClass('grid')).toBe(true);
|
|
67
|
+
expect(validator.isValidClass('grid-cols-3')).toBe(true);
|
|
68
|
+
});
|
|
69
|
+
});
|
|
70
|
+
describe('variants', () => {
|
|
71
|
+
it('should validate hover variants', () => {
|
|
72
|
+
expect(validator.isValidClass('hover:bg-blue-500')).toBe(true);
|
|
73
|
+
expect(validator.isValidClass('hover:text-white')).toBe(true);
|
|
74
|
+
});
|
|
75
|
+
it('should validate responsive variants', () => {
|
|
76
|
+
expect(validator.isValidClass('md:flex')).toBe(true);
|
|
77
|
+
expect(validator.isValidClass('lg:grid')).toBe(true);
|
|
78
|
+
expect(validator.isValidClass('sm:hidden')).toBe(true);
|
|
79
|
+
});
|
|
80
|
+
it('should validate state variants', () => {
|
|
81
|
+
expect(validator.isValidClass('focus:outline-none')).toBe(true);
|
|
82
|
+
expect(validator.isValidClass('active:bg-blue-700')).toBe(true);
|
|
83
|
+
});
|
|
84
|
+
it('should validate dark mode variants', () => {
|
|
85
|
+
expect(validator.isValidClass('dark:bg-gray-900')).toBe(true);
|
|
86
|
+
expect(validator.isValidClass('dark:text-white')).toBe(true);
|
|
87
|
+
});
|
|
88
|
+
it('should validate combined variants', () => {
|
|
89
|
+
expect(validator.isValidClass('md:hover:bg-blue-500')).toBe(true);
|
|
90
|
+
expect(validator.isValidClass('dark:md:flex')).toBe(true);
|
|
91
|
+
});
|
|
92
|
+
});
|
|
93
|
+
describe('arbitrary values', () => {
|
|
94
|
+
it('should validate arbitrary width values', () => {
|
|
95
|
+
expect(validator.isValidClass('w-[100px]')).toBe(true);
|
|
96
|
+
expect(validator.isValidClass('w-[50%]')).toBe(true);
|
|
97
|
+
expect(validator.isValidClass('w-[calc(100%-2rem)]')).toBe(true);
|
|
98
|
+
});
|
|
99
|
+
it('should validate arbitrary height values', () => {
|
|
100
|
+
expect(validator.isValidClass('h-[50vh]')).toBe(true);
|
|
101
|
+
expect(validator.isValidClass('h-[200px]')).toBe(true);
|
|
102
|
+
});
|
|
103
|
+
it('should validate arbitrary color values', () => {
|
|
104
|
+
expect(validator.isValidClass('bg-[#ff0000]')).toBe(true);
|
|
105
|
+
expect(validator.isValidClass('text-[rgb(255,0,0)]')).toBe(true);
|
|
106
|
+
expect(validator.isValidClass('bg-[hsl(0,100%,50%)]')).toBe(true);
|
|
107
|
+
});
|
|
108
|
+
it('should validate arbitrary padding/margin values', () => {
|
|
109
|
+
expect(validator.isValidClass('p-[20px]')).toBe(true);
|
|
110
|
+
expect(validator.isValidClass('m-[1.5rem]')).toBe(true);
|
|
111
|
+
});
|
|
112
|
+
it('should validate arbitrary font size values', () => {
|
|
113
|
+
expect(validator.isValidClass('text-[14px]')).toBe(true);
|
|
114
|
+
expect(validator.isValidClass('text-[1.5rem]')).toBe(true);
|
|
115
|
+
});
|
|
116
|
+
});
|
|
117
|
+
describe('custom theme colors (Tailwind v4)', () => {
|
|
118
|
+
let customValidator;
|
|
119
|
+
let customTempDir;
|
|
120
|
+
beforeAll(async () => {
|
|
121
|
+
// Create a CSS file with custom colors defined using Tailwind v4 @theme
|
|
122
|
+
customTempDir = fs_1.default.mkdtempSync(path_1.default.join(os_1.default.tmpdir(), 'tailwind-custom-'));
|
|
123
|
+
const customCssFile = path_1.default.join(customTempDir, 'custom.css');
|
|
124
|
+
const cssContent = `@import "tailwindcss";
|
|
125
|
+
|
|
126
|
+
@theme {
|
|
127
|
+
--color-brand: #ff6b6b;
|
|
128
|
+
--color-accent: #4ecdc4;
|
|
129
|
+
--color-custom-blue: oklch(0.5 0.2 240);
|
|
130
|
+
}`;
|
|
131
|
+
fs_1.default.writeFileSync(customCssFile, cssContent);
|
|
132
|
+
customValidator = new TailwindValidator_1.TailwindValidator(customCssFile, new MockLogger());
|
|
133
|
+
await customValidator.initialize();
|
|
134
|
+
});
|
|
135
|
+
it('should validate custom background colors', () => {
|
|
136
|
+
expect(customValidator.isValidClass('bg-brand')).toBe(true);
|
|
137
|
+
expect(customValidator.isValidClass('bg-accent')).toBe(true);
|
|
138
|
+
expect(customValidator.isValidClass('bg-custom-blue')).toBe(true);
|
|
139
|
+
});
|
|
140
|
+
it('should validate custom text colors', () => {
|
|
141
|
+
expect(customValidator.isValidClass('text-brand')).toBe(true);
|
|
142
|
+
expect(customValidator.isValidClass('text-accent')).toBe(true);
|
|
143
|
+
expect(customValidator.isValidClass('text-custom-blue')).toBe(true);
|
|
144
|
+
});
|
|
145
|
+
it('should validate custom border colors', () => {
|
|
146
|
+
expect(customValidator.isValidClass('border-brand')).toBe(true);
|
|
147
|
+
expect(customValidator.isValidClass('border-accent')).toBe(true);
|
|
148
|
+
expect(customValidator.isValidClass('border-custom-blue')).toBe(true);
|
|
149
|
+
});
|
|
150
|
+
it('should validate custom colors with variants', () => {
|
|
151
|
+
expect(customValidator.isValidClass('hover:bg-brand')).toBe(true);
|
|
152
|
+
expect(customValidator.isValidClass('dark:text-accent')).toBe(true);
|
|
153
|
+
expect(customValidator.isValidClass('md:border-custom-blue')).toBe(true);
|
|
154
|
+
});
|
|
155
|
+
it('should still reject invalid custom color names', () => {
|
|
156
|
+
expect(customValidator.isValidClass('bg-nonexistent')).toBe(false);
|
|
157
|
+
expect(customValidator.isValidClass('text-fake-color')).toBe(false);
|
|
158
|
+
});
|
|
159
|
+
});
|
|
160
|
+
describe('invalid classes', () => {
|
|
161
|
+
it('should reject completely invalid class names', () => {
|
|
162
|
+
expect(validator.isValidClass('invalid-class')).toBe(false);
|
|
163
|
+
expect(validator.isValidClass('random-name')).toBe(false);
|
|
164
|
+
expect(validator.isValidClass('not-a-class')).toBe(false);
|
|
165
|
+
});
|
|
166
|
+
it('should reject typos in standard classes', () => {
|
|
167
|
+
expect(validator.isValidClass('flexs')).toBe(false);
|
|
168
|
+
expect(validator.isValidClass('itms-center')).toBe(false);
|
|
169
|
+
expect(validator.isValidClass('jusitfy-center')).toBe(false);
|
|
170
|
+
});
|
|
171
|
+
it('should reject invalid variants', () => {
|
|
172
|
+
expect(validator.isValidClass('invalid-variant:bg-blue-500')).toBe(false);
|
|
173
|
+
expect(validator.isValidClass('fake:text-white')).toBe(false);
|
|
174
|
+
});
|
|
175
|
+
it('should reject malformed arbitrary values', () => {
|
|
176
|
+
expect(validator.isValidClass('w-[')).toBe(false);
|
|
177
|
+
expect(validator.isValidClass('w-[]')).toBe(false);
|
|
178
|
+
});
|
|
179
|
+
});
|
|
180
|
+
});
|
|
181
|
+
describe('getInvalidClasses', () => {
|
|
182
|
+
it('should return empty array for all valid classes', () => {
|
|
183
|
+
const classes = ['flex', 'items-center', 'justify-center', 'bg-blue-500'];
|
|
184
|
+
const invalid = validator.getInvalidClasses(classes);
|
|
185
|
+
expect(invalid).toEqual([]);
|
|
186
|
+
});
|
|
187
|
+
it('should return array of invalid classes', () => {
|
|
188
|
+
const classes = ['flex', 'invalid-class', 'items-center', 'another-invalid'];
|
|
189
|
+
const invalid = validator.getInvalidClasses(classes);
|
|
190
|
+
expect(invalid).toEqual(['invalid-class', 'another-invalid']);
|
|
191
|
+
});
|
|
192
|
+
it('should handle mixed valid and invalid classes', () => {
|
|
193
|
+
const classes = [
|
|
194
|
+
'flex',
|
|
195
|
+
'invalid-one',
|
|
196
|
+
'bg-blue-500',
|
|
197
|
+
'hover:bg-blue-600',
|
|
198
|
+
'invalid-two',
|
|
199
|
+
'w-[100px]'
|
|
200
|
+
];
|
|
201
|
+
const invalid = validator.getInvalidClasses(classes);
|
|
202
|
+
expect(invalid).toEqual(['invalid-one', 'invalid-two']);
|
|
203
|
+
});
|
|
204
|
+
it('should handle empty array', () => {
|
|
205
|
+
const invalid = validator.getInvalidClasses([]);
|
|
206
|
+
expect(invalid).toEqual([]);
|
|
207
|
+
});
|
|
208
|
+
});
|
|
209
|
+
describe('reload', () => {
|
|
210
|
+
it('should reload the design system', async () => {
|
|
211
|
+
const wasBefore = validator.isInitialized();
|
|
212
|
+
await validator.reload();
|
|
213
|
+
const isAfter = validator.isInitialized();
|
|
214
|
+
expect(wasBefore).toBe(true);
|
|
215
|
+
expect(isAfter).toBe(true);
|
|
216
|
+
});
|
|
217
|
+
});
|
|
218
|
+
});
|
|
219
|
+
//# sourceMappingURL=TailwindValidator.spec.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"TailwindValidator.spec.js","sourceRoot":"","sources":["../../src/infrastructure/TailwindValidator.spec.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
import * as ts from 'typescript/lib/tsserverlibrary';
|
|
2
|
+
/**
|
|
3
|
+
* Main plugin class - Refactored with clean architecture and SOLID principles
|
|
4
|
+
*
|
|
5
|
+
* Architecture layers:
|
|
6
|
+
* 1. Core Domain - Types and interfaces (src/core)
|
|
7
|
+
* 2. Extractors - Strategy pattern for class extraction (src/extractors)
|
|
8
|
+
* 3. Services - Business logic orchestration (src/services)
|
|
9
|
+
* 4. Plugin - Thin adapter to TypeScript API (this file)
|
|
10
|
+
*
|
|
11
|
+
* Key improvements:
|
|
12
|
+
* - Single Responsibility: Each class has one clear purpose
|
|
13
|
+
* - Open/Closed: Easy to add new extractors without modifying existing code
|
|
14
|
+
* - Dependency Inversion: Depends on abstractions (interfaces) not concretions
|
|
15
|
+
* - Separation of Concerns: Clear boundaries between layers
|
|
16
|
+
* - Testability: All components can be tested in isolation
|
|
17
|
+
*/
|
|
18
|
+
export declare class TailwindTypescriptPlugin {
|
|
19
|
+
private readonly typescript;
|
|
20
|
+
private logger;
|
|
21
|
+
private validator;
|
|
22
|
+
private validationService;
|
|
23
|
+
private configService;
|
|
24
|
+
private initializationPromise;
|
|
25
|
+
constructor(typescript: typeof ts);
|
|
26
|
+
/**
|
|
27
|
+
* Create the plugin proxy for TypeScript Language Service
|
|
28
|
+
*/
|
|
29
|
+
create(info: ts.server.PluginCreateInfo): ts.LanguageService;
|
|
30
|
+
/**
|
|
31
|
+
* Initialize the Tailwind validator
|
|
32
|
+
*/
|
|
33
|
+
private initializeValidator;
|
|
34
|
+
/**
|
|
35
|
+
* Create a proxy for the TypeScript Language Service
|
|
36
|
+
* Intercepts semantic diagnostics to add Tailwind validation
|
|
37
|
+
*/
|
|
38
|
+
private createLanguageServiceProxy;
|
|
39
|
+
/**
|
|
40
|
+
* Create the getSemanticDiagnostics method with Tailwind validation
|
|
41
|
+
*/
|
|
42
|
+
private createGetSemanticDiagnostics;
|
|
43
|
+
/**
|
|
44
|
+
* Determine if a file should be validated
|
|
45
|
+
*/
|
|
46
|
+
private shouldValidateFile;
|
|
47
|
+
/**
|
|
48
|
+
* Get the initialization promise (for testing)
|
|
49
|
+
*/
|
|
50
|
+
getInitializationPromise(): Promise<void> | null;
|
|
51
|
+
}
|
|
52
|
+
//# sourceMappingURL=TailwindTypescriptPlugin.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"TailwindTypescriptPlugin.d.ts","sourceRoot":"","sources":["../../src/plugin/TailwindTypescriptPlugin.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,MAAM,gCAAgC,CAAC;AAWrD;;;;;;;;;;;;;;;GAeG;AACH,qBAAa,wBAAwB;IAOxB,OAAO,CAAC,QAAQ,CAAC,UAAU;IANvC,OAAO,CAAC,MAAM,CAAU;IACxB,OAAO,CAAC,SAAS,CAAqB;IACtC,OAAO,CAAC,iBAAiB,CAAqB;IAC9C,OAAO,CAAC,aAAa,CAAuB;IAC5C,OAAO,CAAC,qBAAqB,CAA8B;gBAE9B,UAAU,EAAE,OAAO,EAAE;IAElD;;OAEG;IACH,MAAM,CAAC,IAAI,EAAE,EAAE,CAAC,MAAM,CAAC,gBAAgB,GAAG,EAAE,CAAC,eAAe;IAc5D;;OAEG;IACH,OAAO,CAAC,mBAAmB;IA0C3B;;;OAGG;IACH,OAAO,CAAC,0BAA0B;IAgBlC;;OAEG;IACH,OAAO,CAAC,4BAA4B,CAiCjC;IAEH;;OAEG;IACH,OAAO,CAAC,kBAAkB;IAe1B;;OAEG;IACH,wBAAwB,IAAI,OAAO,CAAC,IAAI,CAAC,GAAG,IAAI;CAGhD"}
|
|
@@ -0,0 +1,142 @@
|
|
|
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.TailwindTypescriptPlugin = void 0;
|
|
7
|
+
const fs_1 = __importDefault(require("fs"));
|
|
8
|
+
const path_1 = __importDefault(require("path"));
|
|
9
|
+
const TailwindValidator_1 = require("../infrastructure/TailwindValidator");
|
|
10
|
+
const ClassNameExtractionService_1 = require("../services/ClassNameExtractionService");
|
|
11
|
+
const DiagnosticService_1 = require("../services/DiagnosticService");
|
|
12
|
+
const PluginConfigService_1 = require("../services/PluginConfigService");
|
|
13
|
+
const ValidationService_1 = require("../services/ValidationService");
|
|
14
|
+
const Logger_1 = require("../utils/Logger");
|
|
15
|
+
/**
|
|
16
|
+
* Main plugin class - Refactored with clean architecture and SOLID principles
|
|
17
|
+
*
|
|
18
|
+
* Architecture layers:
|
|
19
|
+
* 1. Core Domain - Types and interfaces (src/core)
|
|
20
|
+
* 2. Extractors - Strategy pattern for class extraction (src/extractors)
|
|
21
|
+
* 3. Services - Business logic orchestration (src/services)
|
|
22
|
+
* 4. Plugin - Thin adapter to TypeScript API (this file)
|
|
23
|
+
*
|
|
24
|
+
* Key improvements:
|
|
25
|
+
* - Single Responsibility: Each class has one clear purpose
|
|
26
|
+
* - Open/Closed: Easy to add new extractors without modifying existing code
|
|
27
|
+
* - Dependency Inversion: Depends on abstractions (interfaces) not concretions
|
|
28
|
+
* - Separation of Concerns: Clear boundaries between layers
|
|
29
|
+
* - Testability: All components can be tested in isolation
|
|
30
|
+
*/
|
|
31
|
+
class TailwindTypescriptPlugin {
|
|
32
|
+
constructor(typescript) {
|
|
33
|
+
this.typescript = typescript;
|
|
34
|
+
this.initializationPromise = null;
|
|
35
|
+
/**
|
|
36
|
+
* Create the getSemanticDiagnostics method with Tailwind validation
|
|
37
|
+
*/
|
|
38
|
+
this.createGetSemanticDiagnostics = (info) => (fileName) => {
|
|
39
|
+
this.logger.log(`[getSemanticDiagnostics] Getting semantic diagnostics for ${fileName}`);
|
|
40
|
+
// Get original TypeScript diagnostics
|
|
41
|
+
const prior = info.languageService.getSemanticDiagnostics(fileName);
|
|
42
|
+
// Skip if validator not initialized or not a JSX/TSX file
|
|
43
|
+
if (!this.shouldValidateFile(fileName)) {
|
|
44
|
+
return prior;
|
|
45
|
+
}
|
|
46
|
+
// Get source file and validate
|
|
47
|
+
const program = info.languageService.getProgram();
|
|
48
|
+
const sourceFile = program.getSourceFile(fileName);
|
|
49
|
+
if (!sourceFile) {
|
|
50
|
+
return prior;
|
|
51
|
+
}
|
|
52
|
+
// Get fresh type checker from current program (always up-to-date)
|
|
53
|
+
const typeChecker = program.getTypeChecker();
|
|
54
|
+
// Validate and get diagnostics
|
|
55
|
+
const tailwindDiagnostics = this.validationService.validateFile(this.typescript, sourceFile, this.configService.getUtilityFunctions(), typeChecker);
|
|
56
|
+
return [...prior, ...tailwindDiagnostics];
|
|
57
|
+
};
|
|
58
|
+
}
|
|
59
|
+
/**
|
|
60
|
+
* Create the plugin proxy for TypeScript Language Service
|
|
61
|
+
*/
|
|
62
|
+
create(info) {
|
|
63
|
+
this.logger = new Logger_1.LoggerImpl(info);
|
|
64
|
+
this.logger.log('============= Plugin Starting =============');
|
|
65
|
+
// Initialize configuration service
|
|
66
|
+
this.configService = new PluginConfigService_1.PluginConfigService(info.config || {}, this.logger);
|
|
67
|
+
// Initialize validator if CSS file is configured
|
|
68
|
+
this.initializeValidator(info);
|
|
69
|
+
// Create language service proxy
|
|
70
|
+
return this.createLanguageServiceProxy(info);
|
|
71
|
+
}
|
|
72
|
+
/**
|
|
73
|
+
* Initialize the Tailwind validator
|
|
74
|
+
*/
|
|
75
|
+
initializeValidator(info) {
|
|
76
|
+
if (!this.configService.hasValidCssPath()) {
|
|
77
|
+
this.logger.log('No CSS file configured');
|
|
78
|
+
return;
|
|
79
|
+
}
|
|
80
|
+
const projectRoot = info.project.getCurrentDirectory();
|
|
81
|
+
const relativeCssPath = this.configService.getCssFilePath();
|
|
82
|
+
const absoluteCssPath = path_1.default.resolve(projectRoot, relativeCssPath);
|
|
83
|
+
if (!fs_1.default.existsSync(absoluteCssPath)) {
|
|
84
|
+
this.logger.log(`CSS file not found at: ${absoluteCssPath}`);
|
|
85
|
+
return;
|
|
86
|
+
}
|
|
87
|
+
this.logger.log(`CSS file found, initializing Tailwind validator...`);
|
|
88
|
+
this.validator = new TailwindValidator_1.TailwindValidator(absoluteCssPath, this.logger);
|
|
89
|
+
// Initialize services with config flags
|
|
90
|
+
const extractionService = new ClassNameExtractionService_1.ClassNameExtractionService(this.configService.isTailwindVariantsEnabled(), this.configService.isClassVarianceAuthorityEnabled());
|
|
91
|
+
const diagnosticService = new DiagnosticService_1.DiagnosticService();
|
|
92
|
+
this.validationService = new ValidationService_1.ValidationService(extractionService, diagnosticService, this.validator, this.logger);
|
|
93
|
+
// Start async initialization
|
|
94
|
+
this.initializationPromise = this.validator
|
|
95
|
+
.initialize()
|
|
96
|
+
.then(() => {
|
|
97
|
+
this.logger.log('Tailwind validator initialized');
|
|
98
|
+
})
|
|
99
|
+
.catch(error => {
|
|
100
|
+
this.logger.log(`Failed to initialize Tailwind validator: ${error}`);
|
|
101
|
+
});
|
|
102
|
+
}
|
|
103
|
+
/**
|
|
104
|
+
* Create a proxy for the TypeScript Language Service
|
|
105
|
+
* Intercepts semantic diagnostics to add Tailwind validation
|
|
106
|
+
*/
|
|
107
|
+
createLanguageServiceProxy(info) {
|
|
108
|
+
const proxy = Object.create(null);
|
|
109
|
+
// Proxy all language service methods
|
|
110
|
+
for (const k of Object.keys(info.languageService)) {
|
|
111
|
+
const x = info.languageService[k];
|
|
112
|
+
// @ts-ignore - Dynamic proxy creation
|
|
113
|
+
proxy[k] = (...args) => x.apply(info.languageService, args);
|
|
114
|
+
}
|
|
115
|
+
// Override getSemanticDiagnostics to add Tailwind validation
|
|
116
|
+
proxy.getSemanticDiagnostics = this.createGetSemanticDiagnostics(info);
|
|
117
|
+
return proxy;
|
|
118
|
+
}
|
|
119
|
+
/**
|
|
120
|
+
* Determine if a file should be validated
|
|
121
|
+
*/
|
|
122
|
+
shouldValidateFile(fileName) {
|
|
123
|
+
if (!this.validator || !this.validator.isInitialized()) {
|
|
124
|
+
this.logger.log(`[shouldValidateFile] Validator not initialized yet for ${fileName}`);
|
|
125
|
+
return false;
|
|
126
|
+
}
|
|
127
|
+
// Only process .tsx and .jsx files
|
|
128
|
+
const isJsxFile = fileName.endsWith('.tsx') || fileName.endsWith('.jsx');
|
|
129
|
+
if (!isJsxFile) {
|
|
130
|
+
return false;
|
|
131
|
+
}
|
|
132
|
+
return true;
|
|
133
|
+
}
|
|
134
|
+
/**
|
|
135
|
+
* Get the initialization promise (for testing)
|
|
136
|
+
*/
|
|
137
|
+
getInitializationPromise() {
|
|
138
|
+
return this.initializationPromise;
|
|
139
|
+
}
|
|
140
|
+
}
|
|
141
|
+
exports.TailwindTypescriptPlugin = TailwindTypescriptPlugin;
|
|
142
|
+
//# sourceMappingURL=TailwindTypescriptPlugin.js.map
|