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,16 @@
|
|
|
1
|
+
import * as ts from 'typescript/lib/tsserverlibrary';
|
|
2
|
+
import { ClassNameInfo, ExtractionContext } from '../core/types';
|
|
3
|
+
import { BaseExtractor } from './BaseExtractor';
|
|
4
|
+
/**
|
|
5
|
+
* Extracts class names from various expression types
|
|
6
|
+
* This is a utility extractor used by other extractors to handle nested expressions
|
|
7
|
+
*/
|
|
8
|
+
export declare class ExpressionExtractor extends BaseExtractor {
|
|
9
|
+
canHandle(node: ts.Node, context: ExtractionContext): boolean;
|
|
10
|
+
extract(node: ts.Node, context: ExtractionContext): ClassNameInfo[];
|
|
11
|
+
/**
|
|
12
|
+
* Recursively extract class names from any expression type
|
|
13
|
+
*/
|
|
14
|
+
extractFromExpression(expression: ts.Expression, context: ExtractionContext): ClassNameInfo[];
|
|
15
|
+
}
|
|
16
|
+
//# sourceMappingURL=ExpressionExtractor.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"ExpressionExtractor.d.ts","sourceRoot":"","sources":["../../src/extractors/ExpressionExtractor.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,MAAM,gCAAgC,CAAC;AAErD,OAAO,EAAE,aAAa,EAAE,iBAAiB,EAAE,MAAM,eAAe,CAAC;AACjE,OAAO,EAAE,aAAa,EAAE,MAAM,iBAAiB,CAAC;AAEhD;;;GAGG;AACH,qBAAa,mBAAoB,SAAQ,aAAa;IACrD,SAAS,CAAC,IAAI,EAAE,EAAE,CAAC,IAAI,EAAE,OAAO,EAAE,iBAAiB,GAAG,OAAO;IAQ7D,OAAO,CAAC,IAAI,EAAE,EAAE,CAAC,IAAI,EAAE,OAAO,EAAE,iBAAiB,GAAG,aAAa,EAAE;IAOnE;;OAEG;IACH,qBAAqB,CAAC,UAAU,EAAE,EAAE,CAAC,UAAU,EAAE,OAAO,EAAE,iBAAiB,GAAG,aAAa,EAAE;CAmH7F"}
|
|
@@ -0,0 +1,132 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.ExpressionExtractor = void 0;
|
|
4
|
+
const BaseExtractor_1 = require("./BaseExtractor");
|
|
5
|
+
/**
|
|
6
|
+
* Extracts class names from various expression types
|
|
7
|
+
* This is a utility extractor used by other extractors to handle nested expressions
|
|
8
|
+
*/
|
|
9
|
+
class ExpressionExtractor extends BaseExtractor_1.BaseExtractor {
|
|
10
|
+
canHandle(node, context) {
|
|
11
|
+
return (context.typescript.isExpression(node) ||
|
|
12
|
+
context.typescript.isStringLiteral(node) ||
|
|
13
|
+
context.typescript.isNoSubstitutionTemplateLiteral(node));
|
|
14
|
+
}
|
|
15
|
+
extract(node, context) {
|
|
16
|
+
if (!context.typescript.isExpression(node)) {
|
|
17
|
+
return [];
|
|
18
|
+
}
|
|
19
|
+
return this.extractFromExpression(node, context);
|
|
20
|
+
}
|
|
21
|
+
/**
|
|
22
|
+
* Recursively extract class names from any expression type
|
|
23
|
+
*/
|
|
24
|
+
extractFromExpression(expression, context) {
|
|
25
|
+
const classNames = [];
|
|
26
|
+
const lineNumber = context.sourceFile.getLineAndCharacterOfPosition(expression.getStart()).line + 1;
|
|
27
|
+
// Handle string literals
|
|
28
|
+
if (context.typescript.isStringLiteral(expression)) {
|
|
29
|
+
return this.extractFromStringLiteral(expression, context);
|
|
30
|
+
}
|
|
31
|
+
// Handle conditional expressions: condition ? 'class1' : 'class2'
|
|
32
|
+
if (context.typescript.isConditionalExpression(expression)) {
|
|
33
|
+
classNames.push(...this.extractFromExpression(expression.whenTrue, context));
|
|
34
|
+
classNames.push(...this.extractFromExpression(expression.whenFalse, context));
|
|
35
|
+
}
|
|
36
|
+
// Handle binary expressions: condition && 'class-name'
|
|
37
|
+
else if (context.typescript.isBinaryExpression(expression)) {
|
|
38
|
+
if (expression.operatorToken.kind === context.typescript.SyntaxKind.AmpersandAmpersandToken ||
|
|
39
|
+
expression.operatorToken.kind === context.typescript.SyntaxKind.BarBarToken) {
|
|
40
|
+
classNames.push(...this.extractFromExpression(expression.right, context));
|
|
41
|
+
}
|
|
42
|
+
}
|
|
43
|
+
// Handle call expressions: clsx('class1', 'class2')
|
|
44
|
+
else if (context.typescript.isCallExpression(expression)) {
|
|
45
|
+
if (this.shouldValidateFunctionCall(expression, context.utilityFunctions)) {
|
|
46
|
+
expression.arguments.forEach(arg => {
|
|
47
|
+
classNames.push(...this.extractFromExpression(arg, context));
|
|
48
|
+
});
|
|
49
|
+
}
|
|
50
|
+
}
|
|
51
|
+
// Handle parenthesized expressions: ('class-name')
|
|
52
|
+
else if (context.typescript.isParenthesizedExpression(expression)) {
|
|
53
|
+
classNames.push(...this.extractFromExpression(expression.expression, context));
|
|
54
|
+
}
|
|
55
|
+
// Handle array literal expressions: ['class1', 'class2']
|
|
56
|
+
else if (context.typescript.isArrayLiteralExpression(expression)) {
|
|
57
|
+
expression.elements.forEach(element => {
|
|
58
|
+
classNames.push(...this.extractFromExpression(element, context));
|
|
59
|
+
});
|
|
60
|
+
}
|
|
61
|
+
// Handle object literal expressions: { 'class-name': true, 'another': condition }
|
|
62
|
+
else if (context.typescript.isObjectLiteralExpression(expression)) {
|
|
63
|
+
expression.properties.forEach(property => {
|
|
64
|
+
// Handle regular property assignments: { 'flex': true }
|
|
65
|
+
if (context.typescript.isPropertyAssignment(property)) {
|
|
66
|
+
const name = property.name;
|
|
67
|
+
// Handle string literal keys: { 'flex': true }
|
|
68
|
+
if (context.typescript.isStringLiteral(name)) {
|
|
69
|
+
const fullText = name.text;
|
|
70
|
+
const stringContentStart = name.getStart() + 1;
|
|
71
|
+
let offset = 0;
|
|
72
|
+
fullText.split(' ').forEach(className => {
|
|
73
|
+
if (className) {
|
|
74
|
+
classNames.push({
|
|
75
|
+
className: className,
|
|
76
|
+
absoluteStart: stringContentStart + offset,
|
|
77
|
+
length: className.length,
|
|
78
|
+
line: lineNumber,
|
|
79
|
+
file: context.sourceFile.fileName
|
|
80
|
+
});
|
|
81
|
+
}
|
|
82
|
+
offset += className.length + 1;
|
|
83
|
+
});
|
|
84
|
+
}
|
|
85
|
+
// Handle identifier keys: { flex: true }
|
|
86
|
+
else if (context.typescript.isIdentifier(name)) {
|
|
87
|
+
classNames.push({
|
|
88
|
+
className: name.text,
|
|
89
|
+
absoluteStart: name.getStart(),
|
|
90
|
+
length: name.text.length,
|
|
91
|
+
line: lineNumber,
|
|
92
|
+
file: context.sourceFile.fileName
|
|
93
|
+
});
|
|
94
|
+
}
|
|
95
|
+
// Handle computed property keys: { ['flex']: true }
|
|
96
|
+
else if (context.typescript.isComputedPropertyName(name)) {
|
|
97
|
+
classNames.push(...this.extractFromExpression(name.expression, context));
|
|
98
|
+
}
|
|
99
|
+
// Process the value - it might contain arrays, nested objects, etc.
|
|
100
|
+
classNames.push(...this.extractFromExpression(property.initializer, context));
|
|
101
|
+
}
|
|
102
|
+
// Handle shorthand property assignments: { flex }
|
|
103
|
+
else if (context.typescript.isShorthandPropertyAssignment(property)) {
|
|
104
|
+
const name = property.name;
|
|
105
|
+
if (context.typescript.isIdentifier(name)) {
|
|
106
|
+
classNames.push({
|
|
107
|
+
className: name.text,
|
|
108
|
+
absoluteStart: name.getStart(),
|
|
109
|
+
length: name.text.length,
|
|
110
|
+
line: lineNumber,
|
|
111
|
+
file: context.sourceFile.fileName
|
|
112
|
+
});
|
|
113
|
+
}
|
|
114
|
+
}
|
|
115
|
+
});
|
|
116
|
+
}
|
|
117
|
+
// Handle template expressions
|
|
118
|
+
else if (context.typescript.isTemplateExpression(expression)) {
|
|
119
|
+
// Import and use TemplateExpressionExtractor to avoid circular dependency
|
|
120
|
+
const { TemplateExpressionExtractor } = require('./TemplateExpressionExtractor');
|
|
121
|
+
const templateExtractor = new TemplateExpressionExtractor();
|
|
122
|
+
classNames.push(...templateExtractor.extract(expression, context));
|
|
123
|
+
}
|
|
124
|
+
// Handle no-substitution template literal
|
|
125
|
+
else if (context.typescript.isNoSubstitutionTemplateLiteral(expression)) {
|
|
126
|
+
return this.extractFromStringLiteral(expression, context);
|
|
127
|
+
}
|
|
128
|
+
return classNames;
|
|
129
|
+
}
|
|
130
|
+
}
|
|
131
|
+
exports.ExpressionExtractor = ExpressionExtractor;
|
|
132
|
+
//# sourceMappingURL=ExpressionExtractor.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"ExpressionExtractor.js","sourceRoot":"","sources":["../../src/extractors/ExpressionExtractor.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
import * as ts from 'typescript/lib/tsserverlibrary';
|
|
2
|
+
import { ClassNameInfo, ExtractionContext } from '../core/types';
|
|
3
|
+
import { BaseExtractor } from './BaseExtractor';
|
|
4
|
+
/**
|
|
5
|
+
* OPTIMIZED: Extracts class names from JSX className attributes
|
|
6
|
+
*
|
|
7
|
+
* Performance improvements:
|
|
8
|
+
* 1. Fast path for string literals (most common, ~70% of cases)
|
|
9
|
+
* 2. Inline hot paths to reduce function call overhead
|
|
10
|
+
* 3. Early returns to avoid unnecessary processing
|
|
11
|
+
* 4. Reuse extractor instances
|
|
12
|
+
*/
|
|
13
|
+
export declare class JsxAttributeExtractor extends BaseExtractor {
|
|
14
|
+
private expressionExtractor;
|
|
15
|
+
private templateExtractor;
|
|
16
|
+
constructor();
|
|
17
|
+
canHandle(node: ts.Node, context: ExtractionContext): boolean;
|
|
18
|
+
extract(node: ts.Node, context: ExtractionContext): ClassNameInfo[];
|
|
19
|
+
}
|
|
20
|
+
//# sourceMappingURL=JsxAttributeExtractor.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"JsxAttributeExtractor.d.ts","sourceRoot":"","sources":["../../src/extractors/JsxAttributeExtractor.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,MAAM,gCAAgC,CAAC;AAErD,OAAO,EAAE,aAAa,EAAE,iBAAiB,EAAE,MAAM,eAAe,CAAC;AACjE,OAAO,EAAE,aAAa,EAAE,MAAM,iBAAiB,CAAC;AAIhD;;;;;;;;GAQG;AACH,qBAAa,qBAAsB,SAAQ,aAAa;IACvD,OAAO,CAAC,mBAAmB,CAAsB;IACjD,OAAO,CAAC,iBAAiB,CAA8B;;IASvD,SAAS,CAAC,IAAI,EAAE,EAAE,CAAC,IAAI,EAAE,OAAO,EAAE,iBAAiB,GAAG,OAAO;IAO7D,OAAO,CAAC,IAAI,EAAE,EAAE,CAAC,IAAI,EAAE,OAAO,EAAE,iBAAiB,GAAG,aAAa,EAAE;CA+FnE"}
|
|
@@ -0,0 +1,107 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.JsxAttributeExtractor = void 0;
|
|
4
|
+
const BaseExtractor_1 = require("./BaseExtractor");
|
|
5
|
+
const ExpressionExtractor_1 = require("./ExpressionExtractor");
|
|
6
|
+
const TemplateExpressionExtractor_1 = require("./TemplateExpressionExtractor");
|
|
7
|
+
/**
|
|
8
|
+
* OPTIMIZED: Extracts class names from JSX className attributes
|
|
9
|
+
*
|
|
10
|
+
* Performance improvements:
|
|
11
|
+
* 1. Fast path for string literals (most common, ~70% of cases)
|
|
12
|
+
* 2. Inline hot paths to reduce function call overhead
|
|
13
|
+
* 3. Early returns to avoid unnecessary processing
|
|
14
|
+
* 4. Reuse extractor instances
|
|
15
|
+
*/
|
|
16
|
+
class JsxAttributeExtractor extends BaseExtractor_1.BaseExtractor {
|
|
17
|
+
constructor() {
|
|
18
|
+
super();
|
|
19
|
+
// Create once, reuse (avoid recreation overhead)
|
|
20
|
+
this.expressionExtractor = new ExpressionExtractor_1.ExpressionExtractor();
|
|
21
|
+
this.templateExtractor = new TemplateExpressionExtractor_1.TemplateExpressionExtractor();
|
|
22
|
+
}
|
|
23
|
+
canHandle(node, context) {
|
|
24
|
+
return (context.typescript.isJsxOpeningElement(node) ||
|
|
25
|
+
context.typescript.isJsxSelfClosingElement(node));
|
|
26
|
+
}
|
|
27
|
+
extract(node, context) {
|
|
28
|
+
const classNames = [];
|
|
29
|
+
// Type guard (already checked in service, but keep for safety)
|
|
30
|
+
if (!context.typescript.isJsxOpeningElement(node) &&
|
|
31
|
+
!context.typescript.isJsxSelfClosingElement(node)) {
|
|
32
|
+
return classNames;
|
|
33
|
+
}
|
|
34
|
+
const attributes = node.attributes.properties;
|
|
35
|
+
// OPTIMIZATION: Early exit if no attributes
|
|
36
|
+
if (attributes.length === 0) {
|
|
37
|
+
return classNames;
|
|
38
|
+
}
|
|
39
|
+
// Process attributes
|
|
40
|
+
for (const attr of attributes) {
|
|
41
|
+
// OPTIMIZATION: Check both conditions at once
|
|
42
|
+
if (!context.typescript.isJsxAttribute(attr) || attr.name.getText() !== 'className') {
|
|
43
|
+
continue;
|
|
44
|
+
}
|
|
45
|
+
const initializer = attr.initializer;
|
|
46
|
+
if (!initializer) {
|
|
47
|
+
continue;
|
|
48
|
+
}
|
|
49
|
+
// FAST PATH: String literal (most common case ~70%)
|
|
50
|
+
// Inline this hot path to avoid function call overhead
|
|
51
|
+
if (context.typescript.isStringLiteral(initializer)) {
|
|
52
|
+
const fullText = initializer.text;
|
|
53
|
+
// OPTIMIZATION: Early exit for empty strings
|
|
54
|
+
if (fullText.length === 0) {
|
|
55
|
+
continue;
|
|
56
|
+
}
|
|
57
|
+
const stringContentStart = initializer.getStart() + 1;
|
|
58
|
+
const lineNumber = context.sourceFile.getLineAndCharacterOfPosition(attr.getStart()).line + 1;
|
|
59
|
+
let offset = 0;
|
|
60
|
+
// OPTIMIZATION: Split and filter in one pass
|
|
61
|
+
const classes = fullText.split(' ');
|
|
62
|
+
for (let i = 0; i < classes.length; i++) {
|
|
63
|
+
const className = classes[i];
|
|
64
|
+
if (className) {
|
|
65
|
+
classNames.push({
|
|
66
|
+
className,
|
|
67
|
+
absoluteStart: stringContentStart + offset,
|
|
68
|
+
length: className.length,
|
|
69
|
+
line: lineNumber,
|
|
70
|
+
file: context.sourceFile.fileName
|
|
71
|
+
});
|
|
72
|
+
}
|
|
73
|
+
offset += className.length + 1;
|
|
74
|
+
}
|
|
75
|
+
continue; // Skip to next attribute
|
|
76
|
+
}
|
|
77
|
+
// JSX expression: className={'foo bar'} or className={clsx(...)}
|
|
78
|
+
if (context.typescript.isJsxExpression(initializer)) {
|
|
79
|
+
const expression = initializer.expression;
|
|
80
|
+
if (!expression) {
|
|
81
|
+
continue;
|
|
82
|
+
}
|
|
83
|
+
// OPTIMIZATION: Check type before delegating to extractor
|
|
84
|
+
if (context.typescript.isStringLiteral(expression)) {
|
|
85
|
+
classNames.push(...this.expressionExtractor.extract(expression, context));
|
|
86
|
+
}
|
|
87
|
+
else if (context.typescript.isTemplateExpression(expression) ||
|
|
88
|
+
context.typescript.isNoSubstitutionTemplateLiteral(expression)) {
|
|
89
|
+
classNames.push(...this.templateExtractor.extract(expression, context));
|
|
90
|
+
}
|
|
91
|
+
else if (context.typescript.isCallExpression(expression)) {
|
|
92
|
+
if (this.shouldValidateFunctionCall(expression, context.utilityFunctions)) {
|
|
93
|
+
classNames.push(...this.expressionExtractor.extract(expression, context));
|
|
94
|
+
}
|
|
95
|
+
}
|
|
96
|
+
else if (context.typescript.isBinaryExpression(expression) ||
|
|
97
|
+
context.typescript.isConditionalExpression(expression) ||
|
|
98
|
+
context.typescript.isParenthesizedExpression(expression)) {
|
|
99
|
+
classNames.push(...this.expressionExtractor.extract(expression, context));
|
|
100
|
+
}
|
|
101
|
+
}
|
|
102
|
+
}
|
|
103
|
+
return classNames;
|
|
104
|
+
}
|
|
105
|
+
}
|
|
106
|
+
exports.JsxAttributeExtractor = JsxAttributeExtractor;
|
|
107
|
+
//# sourceMappingURL=JsxAttributeExtractor.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"JsxAttributeExtractor.js","sourceRoot":"","sources":["../../src/extractors/JsxAttributeExtractor.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
import * as ts from 'typescript/lib/tsserverlibrary';
|
|
2
|
+
import { ClassNameInfo, ExtractionContext } from '../core/types';
|
|
3
|
+
import { BaseExtractor } from './BaseExtractor';
|
|
4
|
+
/**
|
|
5
|
+
* Extracts class names from JSX className attributes
|
|
6
|
+
* This is the main orchestrator for JSX elements
|
|
7
|
+
*/
|
|
8
|
+
export declare class JsxAttributeExtractor extends BaseExtractor {
|
|
9
|
+
private expressionExtractor;
|
|
10
|
+
private templateExtractor;
|
|
11
|
+
constructor();
|
|
12
|
+
canHandle(node: ts.Node, context: ExtractionContext): boolean;
|
|
13
|
+
extract(node: ts.Node, context: ExtractionContext): ClassNameInfo[];
|
|
14
|
+
}
|
|
15
|
+
//# sourceMappingURL=JsxAttributeExtractor.original.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"JsxAttributeExtractor.original.d.ts","sourceRoot":"","sources":["../../src/extractors/JsxAttributeExtractor.original.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,MAAM,gCAAgC,CAAC;AAErD,OAAO,EAAE,aAAa,EAAE,iBAAiB,EAAE,MAAM,eAAe,CAAC;AACjE,OAAO,EAAE,aAAa,EAAE,MAAM,iBAAiB,CAAC;AAIhD;;;GAGG;AACH,qBAAa,qBAAsB,SAAQ,aAAa;IACvD,OAAO,CAAC,mBAAmB,CAAsB;IACjD,OAAO,CAAC,iBAAiB,CAA8B;;IAQvD,SAAS,CAAC,IAAI,EAAE,EAAE,CAAC,IAAI,EAAE,OAAO,EAAE,iBAAiB,GAAG,OAAO;IAO7D,OAAO,CAAC,IAAI,EAAE,EAAE,CAAC,IAAI,EAAE,OAAO,EAAE,iBAAiB,GAAG,aAAa,EAAE;CA0EnE"}
|
|
@@ -0,0 +1,84 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.JsxAttributeExtractor = void 0;
|
|
4
|
+
const BaseExtractor_1 = require("./BaseExtractor");
|
|
5
|
+
const ExpressionExtractor_1 = require("./ExpressionExtractor");
|
|
6
|
+
const TemplateExpressionExtractor_1 = require("./TemplateExpressionExtractor");
|
|
7
|
+
/**
|
|
8
|
+
* Extracts class names from JSX className attributes
|
|
9
|
+
* This is the main orchestrator for JSX elements
|
|
10
|
+
*/
|
|
11
|
+
class JsxAttributeExtractor extends BaseExtractor_1.BaseExtractor {
|
|
12
|
+
constructor() {
|
|
13
|
+
super();
|
|
14
|
+
this.expressionExtractor = new ExpressionExtractor_1.ExpressionExtractor();
|
|
15
|
+
this.templateExtractor = new TemplateExpressionExtractor_1.TemplateExpressionExtractor();
|
|
16
|
+
}
|
|
17
|
+
canHandle(node, context) {
|
|
18
|
+
return (context.typescript.isJsxOpeningElement(node) ||
|
|
19
|
+
context.typescript.isJsxSelfClosingElement(node));
|
|
20
|
+
}
|
|
21
|
+
extract(node, context) {
|
|
22
|
+
const classNames = [];
|
|
23
|
+
if (!context.typescript.isJsxOpeningElement(node) &&
|
|
24
|
+
!context.typescript.isJsxSelfClosingElement(node)) {
|
|
25
|
+
return classNames;
|
|
26
|
+
}
|
|
27
|
+
const attributes = node.attributes.properties;
|
|
28
|
+
for (const attr of attributes) {
|
|
29
|
+
if (context.typescript.isJsxAttribute(attr) && attr.name.getText() === 'className') {
|
|
30
|
+
const initializer = attr.initializer;
|
|
31
|
+
if (!initializer) {
|
|
32
|
+
continue;
|
|
33
|
+
}
|
|
34
|
+
// Handle string literal: className="foo bar"
|
|
35
|
+
if (context.typescript.isStringLiteral(initializer)) {
|
|
36
|
+
const fullText = initializer.text;
|
|
37
|
+
const stringContentStart = initializer.getStart() + 1;
|
|
38
|
+
const lineNumber = context.sourceFile.getLineAndCharacterOfPosition(attr.getStart()).line + 1;
|
|
39
|
+
let offset = 0;
|
|
40
|
+
fullText.split(' ').forEach(className => {
|
|
41
|
+
if (className) {
|
|
42
|
+
classNames.push({
|
|
43
|
+
className: className,
|
|
44
|
+
absoluteStart: stringContentStart + offset,
|
|
45
|
+
length: className.length,
|
|
46
|
+
line: lineNumber,
|
|
47
|
+
file: context.sourceFile.fileName
|
|
48
|
+
});
|
|
49
|
+
}
|
|
50
|
+
offset += className.length + 1;
|
|
51
|
+
});
|
|
52
|
+
}
|
|
53
|
+
// Handle JSX expression: className={'foo bar'} or className={clsx(...)}
|
|
54
|
+
else if (context.typescript.isJsxExpression(initializer)) {
|
|
55
|
+
const expression = initializer.expression;
|
|
56
|
+
if (!expression) {
|
|
57
|
+
continue;
|
|
58
|
+
}
|
|
59
|
+
// Delegate to appropriate extractor based on expression type
|
|
60
|
+
if (context.typescript.isStringLiteral(expression)) {
|
|
61
|
+
classNames.push(...this.expressionExtractor.extract(expression, context));
|
|
62
|
+
}
|
|
63
|
+
else if (context.typescript.isTemplateExpression(expression) ||
|
|
64
|
+
context.typescript.isNoSubstitutionTemplateLiteral(expression)) {
|
|
65
|
+
classNames.push(...this.templateExtractor.extract(expression, context));
|
|
66
|
+
}
|
|
67
|
+
else if (context.typescript.isCallExpression(expression)) {
|
|
68
|
+
if (this.shouldValidateFunctionCall(expression, context.utilityFunctions)) {
|
|
69
|
+
classNames.push(...this.expressionExtractor.extract(expression, context));
|
|
70
|
+
}
|
|
71
|
+
}
|
|
72
|
+
else if (context.typescript.isBinaryExpression(expression) ||
|
|
73
|
+
context.typescript.isConditionalExpression(expression) ||
|
|
74
|
+
context.typescript.isParenthesizedExpression(expression)) {
|
|
75
|
+
classNames.push(...this.expressionExtractor.extract(expression, context));
|
|
76
|
+
}
|
|
77
|
+
}
|
|
78
|
+
}
|
|
79
|
+
}
|
|
80
|
+
return classNames;
|
|
81
|
+
}
|
|
82
|
+
}
|
|
83
|
+
exports.JsxAttributeExtractor = JsxAttributeExtractor;
|
|
84
|
+
//# sourceMappingURL=JsxAttributeExtractor.original.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"JsxAttributeExtractor.original.js","sourceRoot":"","sources":["../../src/extractors/JsxAttributeExtractor.original.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
import * as ts from 'typescript/lib/tsserverlibrary';
|
|
2
|
+
import { ClassNameInfo, ExtractionContext } from '../core/types';
|
|
3
|
+
import { BaseExtractor } from './BaseExtractor';
|
|
4
|
+
/**
|
|
5
|
+
* Extracts class names from string literals
|
|
6
|
+
* Example: 'flex items-center'
|
|
7
|
+
*/
|
|
8
|
+
export declare class StringLiteralExtractor extends BaseExtractor {
|
|
9
|
+
canHandle(node: ts.Node, context: ExtractionContext): boolean;
|
|
10
|
+
extract(node: ts.Node, context: ExtractionContext): ClassNameInfo[];
|
|
11
|
+
}
|
|
12
|
+
//# sourceMappingURL=StringLiteralExtractor.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"StringLiteralExtractor.d.ts","sourceRoot":"","sources":["../../src/extractors/StringLiteralExtractor.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,MAAM,gCAAgC,CAAC;AAErD,OAAO,EAAE,aAAa,EAAE,iBAAiB,EAAE,MAAM,eAAe,CAAC;AACjE,OAAO,EAAE,aAAa,EAAE,MAAM,iBAAiB,CAAC;AAEhD;;;GAGG;AACH,qBAAa,sBAAuB,SAAQ,aAAa;IACxD,SAAS,CAAC,IAAI,EAAE,EAAE,CAAC,IAAI,EAAE,OAAO,EAAE,iBAAiB,GAAG,OAAO;IAI7D,OAAO,CAAC,IAAI,EAAE,EAAE,CAAC,IAAI,EAAE,OAAO,EAAE,iBAAiB,GAAG,aAAa,EAAE;CAOnE"}
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.StringLiteralExtractor = void 0;
|
|
4
|
+
const BaseExtractor_1 = require("./BaseExtractor");
|
|
5
|
+
/**
|
|
6
|
+
* Extracts class names from string literals
|
|
7
|
+
* Example: 'flex items-center'
|
|
8
|
+
*/
|
|
9
|
+
class StringLiteralExtractor extends BaseExtractor_1.BaseExtractor {
|
|
10
|
+
canHandle(node, context) {
|
|
11
|
+
return context.typescript.isStringLiteral(node);
|
|
12
|
+
}
|
|
13
|
+
extract(node, context) {
|
|
14
|
+
if (!context.typescript.isStringLiteral(node)) {
|
|
15
|
+
return [];
|
|
16
|
+
}
|
|
17
|
+
return this.extractFromStringLiteral(node, context);
|
|
18
|
+
}
|
|
19
|
+
}
|
|
20
|
+
exports.StringLiteralExtractor = StringLiteralExtractor;
|
|
21
|
+
//# sourceMappingURL=StringLiteralExtractor.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"StringLiteralExtractor.js","sourceRoot":"","sources":["../../src/extractors/StringLiteralExtractor.ts"],"names":[],"mappings":";;;AAGA,mDAAgD;AAEhD;;;GAGG;AACH,MAAa,sBAAuB,SAAQ,6BAAa;IACxD,SAAS,CAAC,IAAa,EAAE,OAA0B;QAClD,OAAO,OAAO,CAAC,UAAU,CAAC,eAAe,CAAC,IAAI,CAAC,CAAC;IACjD,CAAC;IAED,OAAO,CAAC,IAAa,EAAE,OAA0B;QAChD,IAAI,CAAC,OAAO,CAAC,UAAU,CAAC,eAAe,CAAC,IAAI,CAAC,EAAE,CAAC;YAC/C,OAAO,EAAE,CAAC;QACX,CAAC;QAED,OAAO,IAAI,CAAC,wBAAwB,CAAC,IAAI,EAAE,OAAO,CAAC,CAAC;IACrD,CAAC;CACD;AAZD,wDAYC"}
|
|
@@ -0,0 +1,87 @@
|
|
|
1
|
+
import * as ts from 'typescript/lib/tsserverlibrary';
|
|
2
|
+
import { ClassNameInfo, ExtractionContext } from '../core/types';
|
|
3
|
+
import { BaseExtractor } from './BaseExtractor';
|
|
4
|
+
/**
|
|
5
|
+
* Extracts class names from tailwind-variants tv() function calls
|
|
6
|
+
*
|
|
7
|
+
* Supports:
|
|
8
|
+
* - base: string with classes or array of strings
|
|
9
|
+
* - variants: nested object with string values containing classes
|
|
10
|
+
* - compoundVariants: array of objects with class/className properties
|
|
11
|
+
* - slots: object where values contain classes
|
|
12
|
+
* - Import aliasing: import { tv as myTv } from 'tailwind-variants'
|
|
13
|
+
* - class property overrides: button({ color: 'primary', class: 'bg-pink-500' })
|
|
14
|
+
*
|
|
15
|
+
* PERFORMANCE OPTIMIZATIONS:
|
|
16
|
+
* - ✅ Import detection cached per file (one-time AST scan)
|
|
17
|
+
* - ✅ Early exits for non-tv calls (fast path)
|
|
18
|
+
* - ✅ Direct property access (no unnecessary traversal)
|
|
19
|
+
* - ✅ Inline hot paths (string literal extraction)
|
|
20
|
+
* - ✅ Short-circuit evaluation (skip work when possible)
|
|
21
|
+
* - ✅ TypeChecker-based origin tracking (cached per symbol)
|
|
22
|
+
*/
|
|
23
|
+
export declare class TailwindVariantsExtractor extends BaseExtractor {
|
|
24
|
+
private tvImportCache;
|
|
25
|
+
private tvVariableCache;
|
|
26
|
+
canHandle(node: ts.Node, context: ExtractionContext): boolean;
|
|
27
|
+
extract(node: ts.Node, context: ExtractionContext): ClassNameInfo[];
|
|
28
|
+
/**
|
|
29
|
+
* Check if this call expression is a tv() call from tailwind-variants
|
|
30
|
+
* Supports import aliasing: import { tv as myTv } from 'tailwind-variants'
|
|
31
|
+
*/
|
|
32
|
+
private isTvCall;
|
|
33
|
+
/**
|
|
34
|
+
* Get all local names for tv imports from tailwind-variants
|
|
35
|
+
* Supports aliasing: import { tv as myTv } -> returns Set(['myTv'])
|
|
36
|
+
* Caches result per file for performance
|
|
37
|
+
*/
|
|
38
|
+
private getTvImportNames;
|
|
39
|
+
/**
|
|
40
|
+
* Extract class names from tv() configuration object
|
|
41
|
+
*/
|
|
42
|
+
private extractFromTvConfig;
|
|
43
|
+
/**
|
|
44
|
+
* Extract class names from the variants object
|
|
45
|
+
* Structure: { variantName: { optionName: 'classes' } }
|
|
46
|
+
*/
|
|
47
|
+
private extractFromVariants;
|
|
48
|
+
/**
|
|
49
|
+
* Extract class names from compoundVariants array
|
|
50
|
+
* Structure: [{ condition: value, class: 'classes' or className: 'classes' }]
|
|
51
|
+
*/
|
|
52
|
+
private extractFromCompoundVariants;
|
|
53
|
+
/**
|
|
54
|
+
* Extract class names from slots object
|
|
55
|
+
* Structure: { slotName: 'classes' } or { slotName: { base: 'classes', variants: {...} } }
|
|
56
|
+
*/
|
|
57
|
+
private extractFromSlots;
|
|
58
|
+
/**
|
|
59
|
+
* Extract class names from any expression value
|
|
60
|
+
*/
|
|
61
|
+
private extractFromValue;
|
|
62
|
+
/**
|
|
63
|
+
* Get property name from a property assignment
|
|
64
|
+
*/
|
|
65
|
+
private getPropertyName;
|
|
66
|
+
/**
|
|
67
|
+
* Check if this call expression is calling a function created by tv()
|
|
68
|
+
* Uses TypeChecker for accurate origin tracking
|
|
69
|
+
* IMPORTANT: Returns false for utility functions
|
|
70
|
+
*/
|
|
71
|
+
private isTvCreatedFunctionCall;
|
|
72
|
+
/**
|
|
73
|
+
* Check if a symbol's declaration is from a tv() call
|
|
74
|
+
* Handles: const button = tv(...), export const button = tv(...), etc.
|
|
75
|
+
*/
|
|
76
|
+
private isSymbolFromTvCall;
|
|
77
|
+
/**
|
|
78
|
+
* Extract class names from a tv() function call
|
|
79
|
+
* Example: button({ color: 'primary', class: 'bg-pink-500' })
|
|
80
|
+
*/
|
|
81
|
+
private extractFromTvFunctionCall;
|
|
82
|
+
/**
|
|
83
|
+
* Clear the import cache (useful for testing or when files change)
|
|
84
|
+
*/
|
|
85
|
+
clearCache(): void;
|
|
86
|
+
}
|
|
87
|
+
//# sourceMappingURL=TailwindVariantsExtractor.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"TailwindVariantsExtractor.d.ts","sourceRoot":"","sources":["../../src/extractors/TailwindVariantsExtractor.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,MAAM,gCAAgC,CAAC;AAErD,OAAO,EAAE,aAAa,EAAE,iBAAiB,EAAE,MAAM,eAAe,CAAC;AACjE,OAAO,EAAE,aAAa,EAAE,MAAM,iBAAiB,CAAC;AAEhD;;;;;;;;;;;;;;;;;;GAkBG;AACH,qBAAa,yBAA0B,SAAQ,aAAa;IAC3D,OAAO,CAAC,aAAa,CAAkC;IACvD,OAAO,CAAC,eAAe,CAAiC;IAExD,SAAS,CAAC,IAAI,EAAE,EAAE,CAAC,IAAI,EAAE,OAAO,EAAE,iBAAiB,GAAG,OAAO;IAI7D,OAAO,CAAC,IAAI,EAAE,EAAE,CAAC,IAAI,EAAE,OAAO,EAAE,iBAAiB,GAAG,aAAa,EAAE;IAmCnE;;;OAGG;IACH,OAAO,CAAC,QAAQ;IAsBhB;;;;OAIG;IACH,OAAO,CAAC,gBAAgB;IAmDxB;;OAEG;IACH,OAAO,CAAC,mBAAmB;IAoD3B;;;OAGG;IACH,OAAO,CAAC,mBAAmB;IA8B3B;;;OAGG;IACH,OAAO,CAAC,2BAA2B;IAgCnC;;;OAGG;IACH,OAAO,CAAC,gBAAgB;IA+BxB;;OAEG;IACH,OAAO,CAAC,gBAAgB;IA2ExB;;OAEG;IACH,OAAO,CAAC,eAAe;IAiBvB;;;;OAIG;IACH,OAAO,CAAC,uBAAuB;IAsD/B;;;OAGG;IACH,OAAO,CAAC,kBAAkB;IA+B1B;;;OAGG;IACH,OAAO,CAAC,yBAAyB;IAkCjC;;OAEG;IACH,UAAU,IAAI,IAAI;CAIlB"}
|