@buoy-design/plugin-tailwind 0.1.0

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.
@@ -0,0 +1,26 @@
1
+ import type { DriftSignal } from '@buoy-design/core';
2
+ export interface ArbitraryValue {
3
+ type: 'color' | 'spacing' | 'size' | 'other';
4
+ value: string;
5
+ fullClass: string;
6
+ file: string;
7
+ line: number;
8
+ column: number;
9
+ }
10
+ export interface ArbitraryDetectorConfig {
11
+ projectRoot: string;
12
+ include?: string[];
13
+ exclude?: string[];
14
+ }
15
+ export declare class ArbitraryValueDetector {
16
+ private config;
17
+ constructor(config: ArbitraryDetectorConfig);
18
+ detect(): Promise<ArbitraryValue[]>;
19
+ detectAsDriftSignals(): Promise<DriftSignal[]>;
20
+ private findSourceFiles;
21
+ private scanFile;
22
+ private isHardcodedColor;
23
+ private valuesToDriftSignals;
24
+ private createDriftSignal;
25
+ }
26
+ //# sourceMappingURL=arbitrary-detector.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"arbitrary-detector.d.ts","sourceRoot":"","sources":["../src/arbitrary-detector.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAE,WAAW,EAAe,MAAM,mBAAmB,CAAC;AAElE,MAAM,WAAW,cAAc;IAC7B,IAAI,EAAE,OAAO,GAAG,SAAS,GAAG,MAAM,GAAG,OAAO,CAAC;IAC7C,KAAK,EAAE,MAAM,CAAC;IACd,SAAS,EAAE,MAAM,CAAC;IAClB,IAAI,EAAE,MAAM,CAAC;IACb,IAAI,EAAE,MAAM,CAAC;IACb,MAAM,EAAE,MAAM,CAAC;CAChB;AAED,MAAM,WAAW,uBAAuB;IACtC,WAAW,EAAE,MAAM,CAAC;IACpB,OAAO,CAAC,EAAE,MAAM,EAAE,CAAC;IACnB,OAAO,CAAC,EAAE,MAAM,EAAE,CAAC;CACpB;AAoBD,qBAAa,sBAAsB;IACjC,OAAO,CAAC,MAAM,CAA0B;gBAE5B,MAAM,EAAE,uBAAuB;IAIrC,MAAM,IAAI,OAAO,CAAC,cAAc,EAAE,CAAC;IAYnC,oBAAoB,IAAI,OAAO,CAAC,WAAW,EAAE,CAAC;YAKtC,eAAe;IAqC7B,OAAO,CAAC,QAAQ;IA+DhB,OAAO,CAAC,gBAAgB;IAmBxB,OAAO,CAAC,oBAAoB;IAgD5B,OAAO,CAAC,iBAAiB;CAsC1B"}
@@ -0,0 +1,194 @@
1
+ import { readFileSync } from 'fs';
2
+ import { glob } from 'glob';
3
+ import { relative } from 'path';
4
+ // Patterns for arbitrary values in Tailwind classes
5
+ const ARBITRARY_PATTERNS = {
6
+ // Colors: text-[#fff], bg-[#ff6b6b], border-[rgb(...)], etc.
7
+ color: /\b(?:text|bg|border|ring|fill|stroke|from|via|to|accent|caret|decoration|outline|shadow)-\[([#\w(),.%\s]+)\]/g,
8
+ // Spacing: p-[17px], m-[2rem], gap-[10px], etc.
9
+ spacing: /\b(?:p|px|py|pt|pr|pb|pl|m|mx|my|mt|mr|mb|ml|gap|gap-x|gap-y|space-x|space-y|inset|top|right|bottom|left)-\[([^\]]+)\]/g,
10
+ // Sizing: w-[100px], h-[50vh], min-w-[300px], etc.
11
+ size: /\b(?:w|h|min-w|max-w|min-h|max-h|size)-\[([^\]]+)\]/g,
12
+ // Font size: text-[14px], text-[1.5rem]
13
+ fontSize: /\btext-\[(\d+(?:\.\d+)?(?:px|rem|em))\]/g,
14
+ // Other arbitrary values
15
+ other: /\b[\w-]+-\[([^\]]+)\]/g,
16
+ };
17
+ export class ArbitraryValueDetector {
18
+ config;
19
+ constructor(config) {
20
+ this.config = config;
21
+ }
22
+ async detect() {
23
+ const files = await this.findSourceFiles();
24
+ const arbitraryValues = [];
25
+ for (const file of files) {
26
+ const values = this.scanFile(file);
27
+ arbitraryValues.push(...values);
28
+ }
29
+ return arbitraryValues;
30
+ }
31
+ async detectAsDriftSignals() {
32
+ const values = await this.detect();
33
+ return this.valuesToDriftSignals(values);
34
+ }
35
+ async findSourceFiles() {
36
+ const patterns = this.config.include || [
37
+ '**/*.html',
38
+ '**/*.jsx',
39
+ '**/*.tsx',
40
+ '**/*.vue',
41
+ '**/*.svelte',
42
+ '**/*.astro',
43
+ '**/*.php',
44
+ '**/*.blade.php',
45
+ '**/*.erb',
46
+ '**/*.twig',
47
+ '**/*.cshtml',
48
+ ];
49
+ const ignore = this.config.exclude || [
50
+ '**/node_modules/**',
51
+ '**/dist/**',
52
+ '**/build/**',
53
+ '**/.next/**',
54
+ '**/vendor/**',
55
+ ];
56
+ const allFiles = [];
57
+ for (const pattern of patterns) {
58
+ const matches = await glob(pattern, {
59
+ cwd: this.config.projectRoot,
60
+ ignore,
61
+ absolute: true,
62
+ });
63
+ allFiles.push(...matches);
64
+ }
65
+ return [...new Set(allFiles)];
66
+ }
67
+ scanFile(filePath) {
68
+ const content = readFileSync(filePath, 'utf-8');
69
+ const lines = content.split('\n');
70
+ const values = [];
71
+ const relativePath = relative(this.config.projectRoot, filePath);
72
+ for (let lineNum = 0; lineNum < lines.length; lineNum++) {
73
+ const line = lines[lineNum];
74
+ // Check for color arbitrary values
75
+ for (const match of line.matchAll(ARBITRARY_PATTERNS.color)) {
76
+ if (this.isHardcodedColor(match[1])) {
77
+ values.push({
78
+ type: 'color',
79
+ value: match[1],
80
+ fullClass: match[0],
81
+ file: relativePath,
82
+ line: lineNum + 1,
83
+ column: match.index + 1,
84
+ });
85
+ }
86
+ }
87
+ // Check for spacing arbitrary values
88
+ for (const match of line.matchAll(ARBITRARY_PATTERNS.spacing)) {
89
+ values.push({
90
+ type: 'spacing',
91
+ value: match[1],
92
+ fullClass: match[0],
93
+ file: relativePath,
94
+ line: lineNum + 1,
95
+ column: match.index + 1,
96
+ });
97
+ }
98
+ // Check for size arbitrary values
99
+ for (const match of line.matchAll(ARBITRARY_PATTERNS.size)) {
100
+ values.push({
101
+ type: 'size',
102
+ value: match[1],
103
+ fullClass: match[0],
104
+ file: relativePath,
105
+ line: lineNum + 1,
106
+ column: match.index + 1,
107
+ });
108
+ }
109
+ // Check for font size arbitrary values
110
+ for (const match of line.matchAll(ARBITRARY_PATTERNS.fontSize)) {
111
+ values.push({
112
+ type: 'size',
113
+ value: match[1],
114
+ fullClass: match[0],
115
+ file: relativePath,
116
+ line: lineNum + 1,
117
+ column: match.index + 1,
118
+ });
119
+ }
120
+ }
121
+ return values;
122
+ }
123
+ isHardcodedColor(value) {
124
+ // Check if it's a hex color
125
+ if (/^#[0-9a-fA-F]{3,8}$/.test(value)) {
126
+ return true;
127
+ }
128
+ // Check if it's rgb/rgba/hsl/hsla
129
+ if (/^(?:rgb|rgba|hsl|hsla)\s*\(/.test(value)) {
130
+ return true;
131
+ }
132
+ // CSS variable references are OK (var(--color-primary))
133
+ if (/^var\(/.test(value)) {
134
+ return false;
135
+ }
136
+ return false;
137
+ }
138
+ valuesToDriftSignals(values) {
139
+ // Group by file for better reporting
140
+ const byFile = new Map();
141
+ for (const value of values) {
142
+ const existing = byFile.get(value.file) || [];
143
+ existing.push(value);
144
+ byFile.set(value.file, existing);
145
+ }
146
+ const signals = [];
147
+ for (const [file, fileValues] of byFile) {
148
+ // Group by type within file
149
+ const colors = fileValues.filter(v => v.type === 'color');
150
+ const spacing = fileValues.filter(v => v.type === 'spacing');
151
+ const sizes = fileValues.filter(v => v.type === 'size');
152
+ if (colors.length > 0) {
153
+ signals.push(this.createDriftSignal('color', file, colors, `${colors.length} hardcoded color${colors.length > 1 ? 's' : ''} found. Use theme colors instead.`));
154
+ }
155
+ if (spacing.length > 0) {
156
+ signals.push(this.createDriftSignal('spacing', file, spacing, `${spacing.length} arbitrary spacing value${spacing.length > 1 ? 's' : ''} found. Use theme spacing instead.`));
157
+ }
158
+ if (sizes.length > 0) {
159
+ signals.push(this.createDriftSignal('size', file, sizes, `${sizes.length} arbitrary size value${sizes.length > 1 ? 's' : ''} found. Consider using theme values.`));
160
+ }
161
+ }
162
+ return signals;
163
+ }
164
+ createDriftSignal(valueType, file, values, message) {
165
+ const source = {
166
+ entityType: 'component', // Use component as closest match for file-level issues
167
+ entityId: `tailwind:${file}`,
168
+ entityName: file,
169
+ location: `${file}:${values[0].line}`,
170
+ };
171
+ const examples = values.slice(0, 5).map(v => `${v.fullClass} at line ${v.line}`);
172
+ return {
173
+ id: `drift:hardcoded-value:tailwind:${file}:${valueType}`,
174
+ type: 'hardcoded-value',
175
+ severity: valueType === 'color' ? 'warning' : 'info',
176
+ source,
177
+ message,
178
+ details: {
179
+ expected: 'Use Tailwind theme tokens',
180
+ actual: `${values.length} arbitrary ${valueType} values`,
181
+ affectedFiles: [file],
182
+ suggestions: [
183
+ valueType === 'color'
184
+ ? 'Replace arbitrary colors with theme colors: text-primary, bg-secondary, etc.'
185
+ : 'Replace arbitrary values with theme tokens: p-4, gap-2, w-full, etc.',
186
+ 'Add missing values to tailwind.config.js theme.extend if needed',
187
+ `Examples: ${examples.slice(0, 3).join(', ')}`,
188
+ ],
189
+ },
190
+ detectedAt: new Date(),
191
+ };
192
+ }
193
+ }
194
+ //# sourceMappingURL=arbitrary-detector.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"arbitrary-detector.js","sourceRoot":"","sources":["../src/arbitrary-detector.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,29 @@
1
+ import type { DesignToken } from '@buoy-design/core';
2
+ export interface TailwindTheme {
3
+ colors: Record<string, string | Record<string, string>>;
4
+ spacing: Record<string, string>;
5
+ fontSize: Record<string, string | [string, Record<string, string>]>;
6
+ fontFamily: Record<string, string[]>;
7
+ borderRadius: Record<string, string>;
8
+ boxShadow: Record<string, string>;
9
+ }
10
+ export interface ParsedTailwindConfig {
11
+ theme: Partial<TailwindTheme>;
12
+ tokens: DesignToken[];
13
+ configPath: string;
14
+ }
15
+ export declare class TailwindConfigParser {
16
+ private projectRoot;
17
+ constructor(projectRoot: string);
18
+ parse(): Promise<ParsedTailwindConfig | null>;
19
+ private findConfigFile;
20
+ private extractTheme;
21
+ private extractObjectFromConfig;
22
+ private parseObjectLiteral;
23
+ private themeToTokens;
24
+ private createColorToken;
25
+ private createSpacingToken;
26
+ private createShadowToken;
27
+ private createRawToken;
28
+ }
29
+ //# sourceMappingURL=config-parser.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"config-parser.d.ts","sourceRoot":"","sources":["../src/config-parser.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,WAAW,EAAe,MAAM,mBAAmB,CAAC;AAGlE,MAAM,WAAW,aAAa;IAC5B,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,GAAG,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC,CAAC;IACxD,OAAO,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IAChC,QAAQ,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,GAAG,CAAC,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC,CAAC,CAAC;IACpE,UAAU,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,EAAE,CAAC,CAAC;IACrC,YAAY,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IACrC,SAAS,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;CAEnC;AAED,MAAM,WAAW,oBAAoB;IACnC,KAAK,EAAE,OAAO,CAAC,aAAa,CAAC,CAAC;IAC9B,MAAM,EAAE,WAAW,EAAE,CAAC;IACtB,UAAU,EAAE,MAAM,CAAC;CACpB;AAED,qBAAa,oBAAoB;IAC/B,OAAO,CAAC,WAAW,CAAS;gBAEhB,WAAW,EAAE,MAAM;IAIzB,KAAK,IAAI,OAAO,CAAC,oBAAoB,GAAG,IAAI,CAAC;IAqBnD,OAAO,CAAC,cAAc;YAkBR,YAAY;IAqD1B,OAAO,CAAC,uBAAuB;IAiB/B,OAAO,CAAC,kBAAkB;IA8B1B,OAAO,CAAC,aAAa;IA+CrB,OAAO,CAAC,gBAAgB;IAcxB,OAAO,CAAC,kBAAkB;IAsB1B,OAAO,CAAC,iBAAiB;IAczB,OAAO,CAAC,cAAc;CAkBvB"}
@@ -0,0 +1,227 @@
1
+ import { readFileSync, existsSync } from 'fs';
2
+ import { resolve } from 'path';
3
+ import { createTokenId } from '@buoy-design/core';
4
+ export class TailwindConfigParser {
5
+ projectRoot;
6
+ constructor(projectRoot) {
7
+ this.projectRoot = projectRoot;
8
+ }
9
+ async parse() {
10
+ const configPath = this.findConfigFile();
11
+ if (!configPath) {
12
+ return null;
13
+ }
14
+ try {
15
+ const theme = await this.extractTheme(configPath);
16
+ const tokens = this.themeToTokens(theme, configPath);
17
+ return {
18
+ theme,
19
+ tokens,
20
+ configPath,
21
+ };
22
+ }
23
+ catch (err) {
24
+ console.error('Failed to parse Tailwind config:', err);
25
+ return null;
26
+ }
27
+ }
28
+ findConfigFile() {
29
+ const configNames = [
30
+ 'tailwind.config.js',
31
+ 'tailwind.config.ts',
32
+ 'tailwind.config.mjs',
33
+ 'tailwind.config.cjs',
34
+ ];
35
+ for (const name of configNames) {
36
+ const path = resolve(this.projectRoot, name);
37
+ if (existsSync(path)) {
38
+ return path;
39
+ }
40
+ }
41
+ return null;
42
+ }
43
+ async extractTheme(configPath) {
44
+ const content = readFileSync(configPath, 'utf-8');
45
+ // Try to extract theme object using regex (basic parsing)
46
+ // For full support, we'd need to actually evaluate the config
47
+ const theme = {
48
+ colors: {},
49
+ spacing: {},
50
+ fontSize: {},
51
+ fontFamily: {},
52
+ borderRadius: {},
53
+ boxShadow: {},
54
+ };
55
+ // Extract colors from theme.extend.colors or theme.colors
56
+ const colorMatches = this.extractObjectFromConfig(content, 'colors');
57
+ if (colorMatches) {
58
+ theme.colors = this.parseObjectLiteral(colorMatches);
59
+ }
60
+ // Extract spacing
61
+ const spacingMatches = this.extractObjectFromConfig(content, 'spacing');
62
+ if (spacingMatches) {
63
+ theme.spacing = this.parseObjectLiteral(spacingMatches);
64
+ }
65
+ // Extract fontSize
66
+ const fontSizeMatches = this.extractObjectFromConfig(content, 'fontSize');
67
+ if (fontSizeMatches) {
68
+ theme.fontSize = this.parseObjectLiteral(fontSizeMatches);
69
+ }
70
+ // Extract fontFamily
71
+ const fontFamilyMatches = this.extractObjectFromConfig(content, 'fontFamily');
72
+ if (fontFamilyMatches) {
73
+ theme.fontFamily = this.parseObjectLiteral(fontFamilyMatches);
74
+ }
75
+ // Extract borderRadius
76
+ const borderRadiusMatches = this.extractObjectFromConfig(content, 'borderRadius');
77
+ if (borderRadiusMatches) {
78
+ theme.borderRadius = this.parseObjectLiteral(borderRadiusMatches);
79
+ }
80
+ // Extract boxShadow
81
+ const boxShadowMatches = this.extractObjectFromConfig(content, 'boxShadow');
82
+ if (boxShadowMatches) {
83
+ theme.boxShadow = this.parseObjectLiteral(boxShadowMatches);
84
+ }
85
+ return theme;
86
+ }
87
+ extractObjectFromConfig(content, key) {
88
+ // Match patterns like: colors: { ... } or colors: { ... },
89
+ const patterns = [
90
+ new RegExp(`${key}:\\s*\\{([^{}]*(?:\\{[^{}]*\\}[^{}]*)*)\\}`, 's'),
91
+ new RegExp(`['"]${key}['"]:\\s*\\{([^{}]*(?:\\{[^{}]*\\}[^{}]*)*)\\}`, 's'),
92
+ ];
93
+ for (const pattern of patterns) {
94
+ const match = content.match(pattern);
95
+ if (match) {
96
+ return match[1] || null;
97
+ }
98
+ }
99
+ return null;
100
+ }
101
+ parseObjectLiteral(content) {
102
+ const result = {};
103
+ // Simple key-value extraction
104
+ // Matches: key: 'value' or key: "value" or 'key': 'value'
105
+ const kvPattern = /['"]?(\w+[-\w]*)['"]?\s*:\s*['"]([^'"]+)['"]/g;
106
+ let match;
107
+ while ((match = kvPattern.exec(content)) !== null) {
108
+ result[match[1]] = match[2];
109
+ }
110
+ // Also try to match nested objects for color scales
111
+ const nestedPattern = /['"]?(\w+[-\w]*)['"]?\s*:\s*\{([^{}]+)\}/g;
112
+ while ((match = nestedPattern.exec(content)) !== null) {
113
+ const nestedObj = {};
114
+ const nestedContent = match[2];
115
+ const nestedKv = /['"]?(\w+[-\w]*)['"]?\s*:\s*['"]([^'"]+)['"]/g;
116
+ let nestedMatch;
117
+ while ((nestedMatch = nestedKv.exec(nestedContent)) !== null) {
118
+ nestedObj[nestedMatch[1]] = nestedMatch[2];
119
+ }
120
+ if (Object.keys(nestedObj).length > 0) {
121
+ result[match[1]] = nestedObj;
122
+ }
123
+ }
124
+ return result;
125
+ }
126
+ themeToTokens(theme, configPath) {
127
+ const tokens = [];
128
+ const relativePath = configPath.replace(this.projectRoot + '/', '');
129
+ const source = {
130
+ type: 'json', // Closest match for config file
131
+ path: relativePath,
132
+ };
133
+ // Convert colors to tokens
134
+ if (theme.colors) {
135
+ for (const [name, value] of Object.entries(theme.colors)) {
136
+ if (typeof value === 'string') {
137
+ tokens.push(this.createColorToken(name, value, source));
138
+ }
139
+ else if (typeof value === 'object') {
140
+ // Color scale (e.g., gray: { 100: '#...', 200: '#...' })
141
+ for (const [shade, color] of Object.entries(value)) {
142
+ tokens.push(this.createColorToken(`${name}-${shade}`, color, source));
143
+ }
144
+ }
145
+ }
146
+ }
147
+ // Convert spacing to tokens
148
+ if (theme.spacing) {
149
+ for (const [name, value] of Object.entries(theme.spacing)) {
150
+ tokens.push(this.createSpacingToken(name, value, source));
151
+ }
152
+ }
153
+ // Convert boxShadow to tokens
154
+ if (theme.boxShadow) {
155
+ for (const [name, value] of Object.entries(theme.boxShadow)) {
156
+ tokens.push(this.createShadowToken(name, value, source));
157
+ }
158
+ }
159
+ // Convert borderRadius to tokens
160
+ if (theme.borderRadius) {
161
+ for (const [name, value] of Object.entries(theme.borderRadius)) {
162
+ tokens.push(this.createRawToken(`radius-${name}`, value, 'border', source));
163
+ }
164
+ }
165
+ return tokens;
166
+ }
167
+ createColorToken(name, hex, source) {
168
+ return {
169
+ id: createTokenId(source, `tw-${name}`),
170
+ name: `tw-${name}`,
171
+ category: 'color',
172
+ value: { type: 'color', hex },
173
+ source,
174
+ aliases: [name],
175
+ usedBy: [],
176
+ metadata: { tags: ['tailwind'] },
177
+ scannedAt: new Date(),
178
+ };
179
+ }
180
+ createSpacingToken(name, value, source) {
181
+ // Parse spacing value (e.g., '1rem', '4px')
182
+ const numMatch = value.match(/^([\d.]+)(rem|px|em)?$/);
183
+ if (numMatch) {
184
+ const num = parseFloat(numMatch[1]);
185
+ const unit = numMatch[2] || 'px';
186
+ return {
187
+ id: createTokenId(source, `tw-spacing-${name}`),
188
+ name: `tw-spacing-${name}`,
189
+ category: 'spacing',
190
+ value: { type: 'spacing', value: num, unit },
191
+ source,
192
+ aliases: [name],
193
+ usedBy: [],
194
+ metadata: { tags: ['tailwind'] },
195
+ scannedAt: new Date(),
196
+ };
197
+ }
198
+ return this.createRawToken(`spacing-${name}`, value, 'spacing', source);
199
+ }
200
+ createShadowToken(name, value, source) {
201
+ return {
202
+ id: createTokenId(source, `tw-shadow-${name}`),
203
+ name: `tw-shadow-${name}`,
204
+ category: 'shadow',
205
+ value: { type: 'raw', value },
206
+ source,
207
+ aliases: [name],
208
+ usedBy: [],
209
+ metadata: { tags: ['tailwind'] },
210
+ scannedAt: new Date(),
211
+ };
212
+ }
213
+ createRawToken(name, value, category, source) {
214
+ return {
215
+ id: createTokenId(source, `tw-${name}`),
216
+ name: `tw-${name}`,
217
+ category,
218
+ value: { type: 'raw', value },
219
+ source,
220
+ aliases: [],
221
+ usedBy: [],
222
+ metadata: { tags: ['tailwind'] },
223
+ scannedAt: new Date(),
224
+ };
225
+ }
226
+ }
227
+ //# sourceMappingURL=config-parser.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"config-parser.js","sourceRoot":"","sources":["../src/config-parser.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,4 @@
1
+ export { TailwindScanner, type TailwindScannerConfig } from './scanner.js';
2
+ export { TailwindConfigParser, type TailwindTheme } from './config-parser.js';
3
+ export { ArbitraryValueDetector, type ArbitraryValue } from './arbitrary-detector.js';
4
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,eAAe,EAAE,KAAK,qBAAqB,EAAE,MAAM,cAAc,CAAC;AAC3E,OAAO,EAAE,oBAAoB,EAAE,KAAK,aAAa,EAAE,MAAM,oBAAoB,CAAC;AAC9E,OAAO,EAAE,sBAAsB,EAAE,KAAK,cAAc,EAAE,MAAM,yBAAyB,CAAC"}
package/dist/index.js ADDED
@@ -0,0 +1,4 @@
1
+ export { TailwindScanner } from './scanner.js';
2
+ export { TailwindConfigParser } from './config-parser.js';
3
+ export { ArbitraryValueDetector } from './arbitrary-detector.js';
4
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,eAAe,EAA8B,MAAM,cAAc,CAAC;AAC3E,OAAO,EAAE,oBAAoB,EAAsB,MAAM,oBAAoB,CAAC;AAC9E,OAAO,EAAE,sBAAsB,EAAuB,MAAM,yBAAyB,CAAC"}
@@ -0,0 +1,26 @@
1
+ import type { DesignToken, DriftSignal } from '@buoy-design/core';
2
+ export interface TailwindScannerConfig {
3
+ projectRoot: string;
4
+ include?: string[];
5
+ exclude?: string[];
6
+ /** Whether to scan for arbitrary values (default: true) */
7
+ detectArbitraryValues?: boolean;
8
+ /** Whether to extract theme tokens from config (default: true) */
9
+ extractThemeTokens?: boolean;
10
+ }
11
+ export interface TailwindScanResult {
12
+ tokens: DesignToken[];
13
+ drifts: DriftSignal[];
14
+ configPath: string | null;
15
+ stats: {
16
+ filesScanned: number;
17
+ arbitraryValuesFound: number;
18
+ tokensExtracted: number;
19
+ };
20
+ }
21
+ export declare class TailwindScanner {
22
+ private config;
23
+ constructor(config: TailwindScannerConfig);
24
+ scan(): Promise<TailwindScanResult>;
25
+ }
26
+ //# sourceMappingURL=scanner.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"scanner.d.ts","sourceRoot":"","sources":["../src/scanner.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,WAAW,EAAE,WAAW,EAAE,MAAM,mBAAmB,CAAC;AAIlE,MAAM,WAAW,qBAAqB;IACpC,WAAW,EAAE,MAAM,CAAC;IACpB,OAAO,CAAC,EAAE,MAAM,EAAE,CAAC;IACnB,OAAO,CAAC,EAAE,MAAM,EAAE,CAAC;IACnB,2DAA2D;IAC3D,qBAAqB,CAAC,EAAE,OAAO,CAAC;IAChC,kEAAkE;IAClE,kBAAkB,CAAC,EAAE,OAAO,CAAC;CAC9B;AAED,MAAM,WAAW,kBAAkB;IACjC,MAAM,EAAE,WAAW,EAAE,CAAC;IACtB,MAAM,EAAE,WAAW,EAAE,CAAC;IACtB,UAAU,EAAE,MAAM,GAAG,IAAI,CAAC;IAC1B,KAAK,EAAE;QACL,YAAY,EAAE,MAAM,CAAC;QACrB,oBAAoB,EAAE,MAAM,CAAC;QAC7B,eAAe,EAAE,MAAM,CAAC;KACzB,CAAC;CACH;AAED,qBAAa,eAAe;IAC1B,OAAO,CAAC,MAAM,CAAwB;gBAE1B,MAAM,EAAE,qBAAqB;IAQnC,IAAI,IAAI,OAAO,CAAC,kBAAkB,CAAC;CA0C1C"}
@@ -0,0 +1,49 @@
1
+ import { TailwindConfigParser } from './config-parser.js';
2
+ import { ArbitraryValueDetector } from './arbitrary-detector.js';
3
+ export class TailwindScanner {
4
+ config;
5
+ constructor(config) {
6
+ this.config = {
7
+ detectArbitraryValues: true,
8
+ extractThemeTokens: true,
9
+ ...config,
10
+ };
11
+ }
12
+ async scan() {
13
+ const result = {
14
+ tokens: [],
15
+ drifts: [],
16
+ configPath: null,
17
+ stats: {
18
+ filesScanned: 0,
19
+ arbitraryValuesFound: 0,
20
+ tokensExtracted: 0,
21
+ },
22
+ };
23
+ // Extract theme tokens from tailwind.config.js
24
+ if (this.config.extractThemeTokens) {
25
+ const parser = new TailwindConfigParser(this.config.projectRoot);
26
+ const parsed = await parser.parse();
27
+ if (parsed) {
28
+ result.tokens = parsed.tokens;
29
+ result.configPath = parsed.configPath;
30
+ result.stats.tokensExtracted = parsed.tokens.length;
31
+ }
32
+ }
33
+ // Detect arbitrary values in source files
34
+ if (this.config.detectArbitraryValues) {
35
+ const detector = new ArbitraryValueDetector({
36
+ projectRoot: this.config.projectRoot,
37
+ include: this.config.include,
38
+ exclude: this.config.exclude,
39
+ });
40
+ const arbitraryValues = await detector.detect();
41
+ const driftSignals = await detector.detectAsDriftSignals();
42
+ result.drifts = driftSignals;
43
+ result.stats.arbitraryValuesFound = arbitraryValues.length;
44
+ result.stats.filesScanned = new Set(arbitraryValues.map(v => v.file)).size;
45
+ }
46
+ return result;
47
+ }
48
+ }
49
+ //# sourceMappingURL=scanner.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"scanner.js","sourceRoot":"","sources":["../src/scanner.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,oBAAoB,EAAE,MAAM,oBAAoB,CAAC;AAC1D,OAAO,EAAE,sBAAsB,EAAE,MAAM,yBAAyB,CAAC;AAuBjE,MAAM,OAAO,eAAe;IAClB,MAAM,CAAwB;IAEtC,YAAY,MAA6B;QACvC,IAAI,CAAC,MAAM,GAAG;YACZ,qBAAqB,EAAE,IAAI;YAC3B,kBAAkB,EAAE,IAAI;YACxB,GAAG,MAAM;SACV,CAAC;IACJ,CAAC;IAED,KAAK,CAAC,IAAI;QACR,MAAM,MAAM,GAAuB;YACjC,MAAM,EAAE,EAAE;YACV,MAAM,EAAE,EAAE;YACV,UAAU,EAAE,IAAI;YAChB,KAAK,EAAE;gBACL,YAAY,EAAE,CAAC;gBACf,oBAAoB,EAAE,CAAC;gBACvB,eAAe,EAAE,CAAC;aACnB;SACF,CAAC;QAEF,+CAA+C;QAC/C,IAAI,IAAI,CAAC,MAAM,CAAC,kBAAkB,EAAE,CAAC;YACnC,MAAM,MAAM,GAAG,IAAI,oBAAoB,CAAC,IAAI,CAAC,MAAM,CAAC,WAAW,CAAC,CAAC;YACjE,MAAM,MAAM,GAAG,MAAM,MAAM,CAAC,KAAK,EAAE,CAAC;YAEpC,IAAI,MAAM,EAAE,CAAC;gBACX,MAAM,CAAC,MAAM,GAAG,MAAM,CAAC,MAAM,CAAC;gBAC9B,MAAM,CAAC,UAAU,GAAG,MAAM,CAAC,UAAU,CAAC;gBACtC,MAAM,CAAC,KAAK,CAAC,eAAe,GAAG,MAAM,CAAC,MAAM,CAAC,MAAM,CAAC;YACtD,CAAC;QACH,CAAC;QAED,0CAA0C;QAC1C,IAAI,IAAI,CAAC,MAAM,CAAC,qBAAqB,EAAE,CAAC;YACtC,MAAM,QAAQ,GAAG,IAAI,sBAAsB,CAAC;gBAC1C,WAAW,EAAE,IAAI,CAAC,MAAM,CAAC,WAAW;gBACpC,OAAO,EAAE,IAAI,CAAC,MAAM,CAAC,OAAO;gBAC5B,OAAO,EAAE,IAAI,CAAC,MAAM,CAAC,OAAO;aAC7B,CAAC,CAAC;YAEH,MAAM,eAAe,GAAG,MAAM,QAAQ,CAAC,MAAM,EAAE,CAAC;YAChD,MAAM,YAAY,GAAG,MAAM,QAAQ,CAAC,oBAAoB,EAAE,CAAC;YAE3D,MAAM,CAAC,MAAM,GAAG,YAAY,CAAC;YAC7B,MAAM,CAAC,KAAK,CAAC,oBAAoB,GAAG,eAAe,CAAC,MAAM,CAAC;YAC3D,MAAM,CAAC,KAAK,CAAC,YAAY,GAAG,IAAI,GAAG,CAAC,eAAe,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,IAAI,CAAC;QAC7E,CAAC;QAED,OAAO,MAAM,CAAC;IAChB,CAAC;CACF"}
package/package.json ADDED
@@ -0,0 +1,51 @@
1
+ {
2
+ "name": "@buoy-design/plugin-tailwind",
3
+ "version": "0.1.0",
4
+ "description": "Buoy plugin for Tailwind CSS design drift detection",
5
+ "type": "module",
6
+ "license": "MIT",
7
+ "author": "Buoy <hello@buoy.design>",
8
+ "homepage": "https://buoy.design",
9
+ "repository": {
10
+ "type": "git",
11
+ "url": "git+https://github.com/dylantarre/buoy-design.git",
12
+ "directory": "packages/plugin-tailwind"
13
+ },
14
+ "bugs": {
15
+ "url": "https://github.com/dylantarre/buoy-design/issues"
16
+ },
17
+ "keywords": ["buoy", "tailwind", "tailwindcss", "design-system", "drift-detection", "arbitrary-values"],
18
+ "files": ["dist", "README.md"],
19
+ "main": "./dist/index.js",
20
+ "types": "./dist/index.d.ts",
21
+ "exports": {
22
+ ".": {
23
+ "types": "./dist/index.d.ts",
24
+ "import": "./dist/index.js"
25
+ }
26
+ },
27
+ "scripts": {
28
+ "build": "tsc",
29
+ "dev": "tsc --watch",
30
+ "typecheck": "tsc --noEmit",
31
+ "clean": "rm -rf dist",
32
+ "test": "vitest run",
33
+ "test:watch": "vitest"
34
+ },
35
+ "dependencies": {
36
+ "@buoy-design/core": "workspace:*",
37
+ "glob": "^10.3.10"
38
+ },
39
+ "devDependencies": {
40
+ "typescript": "^5.3.3",
41
+ "vitest": "^2.1.9"
42
+ },
43
+ "peerDependencies": {
44
+ "tailwindcss": ">=3.0.0"
45
+ },
46
+ "peerDependenciesMeta": {
47
+ "tailwindcss": {
48
+ "optional": true
49
+ }
50
+ }
51
+ }