skillui 1.1.2 → 1.1.4
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/README.md +20 -15
- package/dist/cli.js +105073 -194
- package/package.json +15 -6
- package/dist/cli.d.ts +0 -3
- package/dist/extractors/components.d.ts +0 -11
- package/dist/extractors/components.js +0 -455
- package/dist/extractors/framework.d.ts +0 -4
- package/dist/extractors/framework.js +0 -126
- package/dist/extractors/tokens/computed.d.ts +0 -7
- package/dist/extractors/tokens/computed.js +0 -249
- package/dist/extractors/tokens/css.d.ts +0 -3
- package/dist/extractors/tokens/css.js +0 -510
- package/dist/extractors/tokens/http-css.d.ts +0 -14
- package/dist/extractors/tokens/http-css.js +0 -1689
- package/dist/extractors/tokens/tailwind.d.ts +0 -3
- package/dist/extractors/tokens/tailwind.js +0 -353
- package/dist/extractors/tokens/tokens-file.d.ts +0 -3
- package/dist/extractors/tokens/tokens-file.js +0 -229
- package/dist/extractors/ultra/animations.d.ts +0 -21
- package/dist/extractors/ultra/animations.js +0 -527
- package/dist/extractors/ultra/components-dom.d.ts +0 -13
- package/dist/extractors/ultra/components-dom.js +0 -149
- package/dist/extractors/ultra/interactions.d.ts +0 -14
- package/dist/extractors/ultra/interactions.js +0 -222
- package/dist/extractors/ultra/layout.d.ts +0 -14
- package/dist/extractors/ultra/layout.js +0 -123
- package/dist/extractors/ultra/pages.d.ts +0 -16
- package/dist/extractors/ultra/pages.js +0 -228
- package/dist/font-resolver.d.ts +0 -10
- package/dist/font-resolver.js +0 -280
- package/dist/modes/dir.d.ts +0 -6
- package/dist/modes/dir.js +0 -213
- package/dist/modes/repo.d.ts +0 -6
- package/dist/modes/repo.js +0 -76
- package/dist/modes/ultra.d.ts +0 -22
- package/dist/modes/ultra.js +0 -281
- package/dist/modes/url.d.ts +0 -14
- package/dist/modes/url.js +0 -161
- package/dist/normalizer.d.ts +0 -11
- package/dist/normalizer.js +0 -867
- package/dist/playwright-loader.d.ts +0 -10
- package/dist/playwright-loader.js +0 -71
- package/dist/screenshot.d.ts +0 -9
- package/dist/screenshot.js +0 -94
- package/dist/types-ultra.d.ts +0 -157
- package/dist/types-ultra.js +0 -4
- package/dist/types.d.ts +0 -182
- package/dist/types.js +0 -4
- package/dist/writers/animations-md.d.ts +0 -17
- package/dist/writers/animations-md.js +0 -313
- package/dist/writers/components-md.d.ts +0 -8
- package/dist/writers/components-md.js +0 -151
- package/dist/writers/design-md.d.ts +0 -7
- package/dist/writers/design-md.js +0 -704
- package/dist/writers/interactions-md.d.ts +0 -8
- package/dist/writers/interactions-md.js +0 -146
- package/dist/writers/layout-md.d.ts +0 -8
- package/dist/writers/layout-md.js +0 -120
- package/dist/writers/skill.d.ts +0 -12
- package/dist/writers/skill.js +0 -1006
- package/dist/writers/tokens-json.d.ts +0 -11
- package/dist/writers/tokens-json.js +0 -164
|
@@ -1,510 +0,0 @@
|
|
|
1
|
-
"use strict";
|
|
2
|
-
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
|
3
|
-
if (k2 === undefined) k2 = k;
|
|
4
|
-
var desc = Object.getOwnPropertyDescriptor(m, k);
|
|
5
|
-
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
|
|
6
|
-
desc = { enumerable: true, get: function() { return m[k]; } };
|
|
7
|
-
}
|
|
8
|
-
Object.defineProperty(o, k2, desc);
|
|
9
|
-
}) : (function(o, m, k, k2) {
|
|
10
|
-
if (k2 === undefined) k2 = k;
|
|
11
|
-
o[k2] = m[k];
|
|
12
|
-
}));
|
|
13
|
-
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
|
|
14
|
-
Object.defineProperty(o, "default", { enumerable: true, value: v });
|
|
15
|
-
}) : function(o, v) {
|
|
16
|
-
o["default"] = v;
|
|
17
|
-
});
|
|
18
|
-
var __importStar = (this && this.__importStar) || (function () {
|
|
19
|
-
var ownKeys = function(o) {
|
|
20
|
-
ownKeys = Object.getOwnPropertyNames || function (o) {
|
|
21
|
-
var ar = [];
|
|
22
|
-
for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
|
|
23
|
-
return ar;
|
|
24
|
-
};
|
|
25
|
-
return ownKeys(o);
|
|
26
|
-
};
|
|
27
|
-
return function (mod) {
|
|
28
|
-
if (mod && mod.__esModule) return mod;
|
|
29
|
-
var result = {};
|
|
30
|
-
if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
|
|
31
|
-
__setModuleDefault(result, mod);
|
|
32
|
-
return result;
|
|
33
|
-
};
|
|
34
|
-
})();
|
|
35
|
-
Object.defineProperty(exports, "__esModule", { value: true });
|
|
36
|
-
exports.extractCSSTokens = extractCSSTokens;
|
|
37
|
-
const fs = __importStar(require("fs"));
|
|
38
|
-
const path = __importStar(require("path"));
|
|
39
|
-
const csstree = __importStar(require("css-tree"));
|
|
40
|
-
const CSS_EXTENSIONS = ['.css', '.scss', '.less'];
|
|
41
|
-
const IGNORE_DIRS = ['node_modules', '.git', 'dist', 'build', '.next', '.nuxt'];
|
|
42
|
-
function extractCSSTokens(projectDir) {
|
|
43
|
-
const tokens = {
|
|
44
|
-
colors: [],
|
|
45
|
-
fonts: [],
|
|
46
|
-
spacingValues: [],
|
|
47
|
-
shadows: [],
|
|
48
|
-
cssVariables: [],
|
|
49
|
-
breakpoints: [],
|
|
50
|
-
borderRadii: [],
|
|
51
|
-
gradients: [],
|
|
52
|
-
fontVarMap: {},
|
|
53
|
-
animations: [],
|
|
54
|
-
darkModeVars: [],
|
|
55
|
-
zIndexValues: [],
|
|
56
|
-
containerMaxWidth: null,
|
|
57
|
-
fontSources: [],
|
|
58
|
-
pageSections: [],
|
|
59
|
-
transitionDurations: [],
|
|
60
|
-
transitionEasings: [],
|
|
61
|
-
};
|
|
62
|
-
const cssFiles = findCSSFiles(projectDir);
|
|
63
|
-
for (const file of cssFiles) {
|
|
64
|
-
try {
|
|
65
|
-
const content = fs.readFileSync(file, 'utf-8');
|
|
66
|
-
extractFromCSS(content, tokens);
|
|
67
|
-
}
|
|
68
|
-
catch {
|
|
69
|
-
// Skip files that can't be read/parsed
|
|
70
|
-
}
|
|
71
|
-
}
|
|
72
|
-
// Extract dark mode variable pairs
|
|
73
|
-
extractDarkModeVars(tokens);
|
|
74
|
-
return tokens;
|
|
75
|
-
}
|
|
76
|
-
function findCSSFiles(dir, depth = 0) {
|
|
77
|
-
const files = [];
|
|
78
|
-
if (depth > 6)
|
|
79
|
-
return files;
|
|
80
|
-
try {
|
|
81
|
-
const entries = fs.readdirSync(dir, { withFileTypes: true });
|
|
82
|
-
for (const entry of entries) {
|
|
83
|
-
if (IGNORE_DIRS.includes(entry.name))
|
|
84
|
-
continue;
|
|
85
|
-
const fullPath = path.join(dir, entry.name);
|
|
86
|
-
if (entry.isFile() && CSS_EXTENSIONS.some(ext => entry.name.endsWith(ext))) {
|
|
87
|
-
files.push(fullPath);
|
|
88
|
-
}
|
|
89
|
-
else if (entry.isDirectory()) {
|
|
90
|
-
files.push(...findCSSFiles(fullPath, depth + 1));
|
|
91
|
-
}
|
|
92
|
-
}
|
|
93
|
-
}
|
|
94
|
-
catch {
|
|
95
|
-
// Permission errors
|
|
96
|
-
}
|
|
97
|
-
return files;
|
|
98
|
-
}
|
|
99
|
-
function extractFromCSS(content, tokens) {
|
|
100
|
-
// Extract dark mode block variables (regex, works across all CSS flavors)
|
|
101
|
-
extractDarkModeBlocks(content, tokens);
|
|
102
|
-
// Extract CSS keyframe animations
|
|
103
|
-
extractKeyframeAnimations(content, tokens);
|
|
104
|
-
// Extract z-index values
|
|
105
|
-
extractZIndexValues(content, tokens);
|
|
106
|
-
// Extract container max-width
|
|
107
|
-
extractContainerMaxWidth(content, tokens);
|
|
108
|
-
// Use css-tree for AST-based extraction
|
|
109
|
-
try {
|
|
110
|
-
const ast = csstree.parse(content, {
|
|
111
|
-
parseCustomProperty: true,
|
|
112
|
-
parseAtrulePrelude: true,
|
|
113
|
-
});
|
|
114
|
-
csstree.walk(ast, {
|
|
115
|
-
visit: 'Declaration',
|
|
116
|
-
enter(node) {
|
|
117
|
-
const prop = node.property;
|
|
118
|
-
const rawValue = csstree.generate(node.value);
|
|
119
|
-
// CSS custom properties
|
|
120
|
-
if (prop.startsWith('--')) {
|
|
121
|
-
const trimmedValue = rawValue.trim();
|
|
122
|
-
tokens.cssVariables.push({
|
|
123
|
-
name: prop,
|
|
124
|
-
value: trimmedValue,
|
|
125
|
-
property: guessPropertyType(prop),
|
|
126
|
-
});
|
|
127
|
-
if (isColorVarName(prop)) {
|
|
128
|
-
const hex = tryParseColorValue(trimmedValue);
|
|
129
|
-
if (hex) {
|
|
130
|
-
const name = prop.replace(/^--/, '').replace(/-/g, '-');
|
|
131
|
-
tokens.colors.push({ value: hex, frequency: 1, source: 'css', name });
|
|
132
|
-
}
|
|
133
|
-
}
|
|
134
|
-
}
|
|
135
|
-
// Colors
|
|
136
|
-
if (isColorProperty(prop)) {
|
|
137
|
-
extractColorsFromValue(rawValue, tokens);
|
|
138
|
-
}
|
|
139
|
-
// Font family
|
|
140
|
-
if (prop === 'font-family') {
|
|
141
|
-
const family = rawValue.replace(/["']/g, '').split(',')[0].trim();
|
|
142
|
-
if (family) {
|
|
143
|
-
tokens.fonts.push({ family, source: 'css' });
|
|
144
|
-
}
|
|
145
|
-
}
|
|
146
|
-
// Font size
|
|
147
|
-
if (prop === 'font-size') {
|
|
148
|
-
const existing = tokens.fonts.find(f => !f.size);
|
|
149
|
-
if (existing) {
|
|
150
|
-
existing.size = rawValue.trim();
|
|
151
|
-
}
|
|
152
|
-
else {
|
|
153
|
-
tokens.fonts.push({ family: '', size: rawValue.trim(), source: 'css' });
|
|
154
|
-
}
|
|
155
|
-
}
|
|
156
|
-
// Font weight
|
|
157
|
-
if (prop === 'font-weight') {
|
|
158
|
-
const existing = tokens.fonts.find(f => !f.weight);
|
|
159
|
-
if (existing) {
|
|
160
|
-
existing.weight = rawValue.trim();
|
|
161
|
-
}
|
|
162
|
-
}
|
|
163
|
-
// Spacing-related properties
|
|
164
|
-
if (isSpacingProperty(prop)) {
|
|
165
|
-
extractSpacingValues(rawValue, tokens);
|
|
166
|
-
}
|
|
167
|
-
// Box shadow
|
|
168
|
-
if (prop === 'box-shadow') {
|
|
169
|
-
tokens.shadows.push({ value: rawValue.trim() });
|
|
170
|
-
}
|
|
171
|
-
// Border radius
|
|
172
|
-
if (prop === 'border-radius' || prop.startsWith('border-') && prop.endsWith('-radius')) {
|
|
173
|
-
tokens.borderRadii.push(rawValue.trim());
|
|
174
|
-
}
|
|
175
|
-
// Gradients
|
|
176
|
-
if (rawValue.includes('gradient(')) {
|
|
177
|
-
tokens.gradients.push(rawValue.trim());
|
|
178
|
-
}
|
|
179
|
-
// CSS transitions
|
|
180
|
-
if (prop === 'transition') {
|
|
181
|
-
tokens.animations.push({
|
|
182
|
-
name: 'css-transition',
|
|
183
|
-
type: 'css-transition',
|
|
184
|
-
value: rawValue.trim(),
|
|
185
|
-
source: 'css',
|
|
186
|
-
});
|
|
187
|
-
}
|
|
188
|
-
},
|
|
189
|
-
});
|
|
190
|
-
// Extract @media breakpoints
|
|
191
|
-
csstree.walk(ast, {
|
|
192
|
-
visit: 'Atrule',
|
|
193
|
-
enter(node) {
|
|
194
|
-
if (node.name === 'media' && node.prelude) {
|
|
195
|
-
const mediaQuery = csstree.generate(node.prelude);
|
|
196
|
-
const minWidthMatch = mediaQuery.match(/min-width:\s*([\d.]+(?:px|em|rem))/);
|
|
197
|
-
if (minWidthMatch) {
|
|
198
|
-
const existing = tokens.breakpoints.find(bp => bp.value === minWidthMatch[1]);
|
|
199
|
-
if (!existing) {
|
|
200
|
-
tokens.breakpoints.push({
|
|
201
|
-
name: `breakpoint-${minWidthMatch[1]}`,
|
|
202
|
-
value: minWidthMatch[1],
|
|
203
|
-
source: 'css',
|
|
204
|
-
});
|
|
205
|
-
}
|
|
206
|
-
}
|
|
207
|
-
}
|
|
208
|
-
},
|
|
209
|
-
});
|
|
210
|
-
}
|
|
211
|
-
catch {
|
|
212
|
-
// Fallback: regex-based extraction
|
|
213
|
-
extractWithRegex(content, tokens);
|
|
214
|
-
}
|
|
215
|
-
}
|
|
216
|
-
/**
|
|
217
|
-
* Extract :root and .dark CSS variable blocks to detect light/dark mode pairs.
|
|
218
|
-
*/
|
|
219
|
-
function extractDarkModeBlocks(content, tokens) {
|
|
220
|
-
// Collect :root variables
|
|
221
|
-
const rootVars = new Map();
|
|
222
|
-
const darkVars = new Map();
|
|
223
|
-
// Match :root { ... } blocks
|
|
224
|
-
const rootBlocks = content.matchAll(/:root\s*\{([^}]+)\}/g);
|
|
225
|
-
for (const m of rootBlocks) {
|
|
226
|
-
const vars = m[1].matchAll(/(--[\w-]+)\s*:\s*([^;}\n]+)/g);
|
|
227
|
-
for (const v of vars) {
|
|
228
|
-
rootVars.set(v[1], v[2].trim());
|
|
229
|
-
}
|
|
230
|
-
}
|
|
231
|
-
// Match .dark { ... } or [data-theme="dark"] { ... } or @media (prefers-color-scheme: dark) blocks
|
|
232
|
-
const darkPatterns = [
|
|
233
|
-
/\.dark\s*\{([^}]+)\}/g,
|
|
234
|
-
/\[data-theme\s*=\s*["']dark["']\]\s*\{([^}]+)\}/g,
|
|
235
|
-
/\.dark\s+:root\s*\{([^}]+)\}/g,
|
|
236
|
-
/:root\.dark\s*\{([^}]+)\}/g,
|
|
237
|
-
/@media\s*\(\s*prefers-color-scheme\s*:\s*dark\s*\)\s*\{[^{]*:root\s*\{([^}]+)\}/g,
|
|
238
|
-
];
|
|
239
|
-
for (const pattern of darkPatterns) {
|
|
240
|
-
const matches = content.matchAll(pattern);
|
|
241
|
-
for (const m of matches) {
|
|
242
|
-
const vars = m[1].matchAll(/(--[\w-]+)\s*:\s*([^;}\n]+)/g);
|
|
243
|
-
for (const v of vars) {
|
|
244
|
-
darkVars.set(v[1], v[2].trim());
|
|
245
|
-
}
|
|
246
|
-
}
|
|
247
|
-
}
|
|
248
|
-
// Build dark mode var pairs
|
|
249
|
-
for (const [name, lightVal] of rootVars) {
|
|
250
|
-
const darkVal = darkVars.get(name);
|
|
251
|
-
if (darkVal && darkVal !== lightVal) {
|
|
252
|
-
tokens.darkModeVars.push({
|
|
253
|
-
variable: name,
|
|
254
|
-
lightValue: lightVal,
|
|
255
|
-
darkValue: darkVal,
|
|
256
|
-
});
|
|
257
|
-
}
|
|
258
|
-
}
|
|
259
|
-
}
|
|
260
|
-
/**
|
|
261
|
-
* Extract @keyframes animations from CSS.
|
|
262
|
-
*/
|
|
263
|
-
function extractKeyframeAnimations(content, tokens) {
|
|
264
|
-
const keyframeMatches = content.matchAll(/@keyframes\s+([\w-]+)\s*\{([^}]*(?:\{[^}]*\}[^}]*)*)\}/g);
|
|
265
|
-
for (const m of keyframeMatches) {
|
|
266
|
-
tokens.animations.push({
|
|
267
|
-
name: m[1],
|
|
268
|
-
type: 'css-keyframe',
|
|
269
|
-
value: m[2].trim().slice(0, 200),
|
|
270
|
-
source: 'css',
|
|
271
|
-
});
|
|
272
|
-
}
|
|
273
|
-
}
|
|
274
|
-
/**
|
|
275
|
-
* Extract z-index values used in the CSS.
|
|
276
|
-
*/
|
|
277
|
-
function extractZIndexValues(content, tokens) {
|
|
278
|
-
const zMatches = content.matchAll(/z-index\s*:\s*(\d+)/g);
|
|
279
|
-
for (const m of zMatches) {
|
|
280
|
-
const val = parseInt(m[1]);
|
|
281
|
-
if (!tokens.zIndexValues.includes(val)) {
|
|
282
|
-
tokens.zIndexValues.push(val);
|
|
283
|
-
}
|
|
284
|
-
}
|
|
285
|
-
}
|
|
286
|
-
/**
|
|
287
|
-
* Extract container / max-width patterns.
|
|
288
|
-
*/
|
|
289
|
-
function extractContainerMaxWidth(content, tokens) {
|
|
290
|
-
const maxWidthMatches = content.matchAll(/max-width\s*:\s*([\d.]+(?:px|rem|em|%))/g);
|
|
291
|
-
for (const m of maxWidthMatches) {
|
|
292
|
-
const val = m[1];
|
|
293
|
-
// Prefer larger container-level values
|
|
294
|
-
if (parseFloat(val) >= 960 || val.includes('%')) {
|
|
295
|
-
tokens.containerMaxWidth = val;
|
|
296
|
-
}
|
|
297
|
-
}
|
|
298
|
-
// Also check CSS variables
|
|
299
|
-
const containerVarMatch = content.match(/--(container|content|max-width|page-width)[\w-]*\s*:\s*([^;}\n]+)/);
|
|
300
|
-
if (containerVarMatch) {
|
|
301
|
-
tokens.containerMaxWidth = containerVarMatch[2].trim();
|
|
302
|
-
}
|
|
303
|
-
}
|
|
304
|
-
function extractWithRegex(content, tokens) {
|
|
305
|
-
// Hex colors
|
|
306
|
-
const hexMatches = content.matchAll(/#([0-9a-fA-F]{3,8})\b/g);
|
|
307
|
-
for (const m of hexMatches) {
|
|
308
|
-
const hex = normalizeHex(m[0]);
|
|
309
|
-
const existing = tokens.colors.find(c => c.value === hex);
|
|
310
|
-
if (existing) {
|
|
311
|
-
existing.frequency++;
|
|
312
|
-
}
|
|
313
|
-
else {
|
|
314
|
-
tokens.colors.push({ value: hex, frequency: 1, source: 'css' });
|
|
315
|
-
}
|
|
316
|
-
}
|
|
317
|
-
// RGB/RGBA colors
|
|
318
|
-
const rgbMatches = content.matchAll(/rgba?\(\s*(\d+)\s*,\s*(\d+)\s*,\s*(\d+)/g);
|
|
319
|
-
for (const m of rgbMatches) {
|
|
320
|
-
const hex = rgbToHex(parseInt(m[1]), parseInt(m[2]), parseInt(m[3]));
|
|
321
|
-
const existing = tokens.colors.find(c => c.value === hex);
|
|
322
|
-
if (existing) {
|
|
323
|
-
existing.frequency++;
|
|
324
|
-
}
|
|
325
|
-
else {
|
|
326
|
-
tokens.colors.push({ value: hex, frequency: 1, source: 'css' });
|
|
327
|
-
}
|
|
328
|
-
}
|
|
329
|
-
// CSS variables
|
|
330
|
-
const varMatches = content.matchAll(/(--[\w-]+)\s*:\s*([^;}\n]+)/g);
|
|
331
|
-
for (const m of varMatches) {
|
|
332
|
-
const varName = m[1];
|
|
333
|
-
const varValue = m[2].trim();
|
|
334
|
-
tokens.cssVariables.push({
|
|
335
|
-
name: varName,
|
|
336
|
-
value: varValue,
|
|
337
|
-
property: guessPropertyType(varName),
|
|
338
|
-
});
|
|
339
|
-
if (isColorVarName(varName)) {
|
|
340
|
-
const hex = tryParseColorValue(varValue);
|
|
341
|
-
if (hex) {
|
|
342
|
-
const name = varName.replace(/^--/, '');
|
|
343
|
-
const existing = tokens.colors.find(c => c.value === hex);
|
|
344
|
-
if (existing) {
|
|
345
|
-
existing.frequency++;
|
|
346
|
-
if (!existing.name)
|
|
347
|
-
existing.name = name;
|
|
348
|
-
}
|
|
349
|
-
else {
|
|
350
|
-
tokens.colors.push({ value: hex, frequency: 1, source: 'css', name });
|
|
351
|
-
}
|
|
352
|
-
}
|
|
353
|
-
}
|
|
354
|
-
}
|
|
355
|
-
// Font families
|
|
356
|
-
const fontMatches = content.matchAll(/font-family\s*:\s*([^;}\n]+)/g);
|
|
357
|
-
for (const m of fontMatches) {
|
|
358
|
-
const family = m[1].replace(/["']/g, '').split(',')[0].trim();
|
|
359
|
-
if (family) {
|
|
360
|
-
tokens.fonts.push({ family, source: 'css' });
|
|
361
|
-
}
|
|
362
|
-
}
|
|
363
|
-
// Media queries
|
|
364
|
-
const mediaMatches = content.matchAll(/@media[^{]*min-width:\s*([\d.]+(?:px|em|rem))/g);
|
|
365
|
-
for (const m of mediaMatches) {
|
|
366
|
-
if (!tokens.breakpoints.find(bp => bp.value === m[1])) {
|
|
367
|
-
tokens.breakpoints.push({
|
|
368
|
-
name: `breakpoint-${m[1]}`,
|
|
369
|
-
value: m[1],
|
|
370
|
-
source: 'css',
|
|
371
|
-
});
|
|
372
|
-
}
|
|
373
|
-
}
|
|
374
|
-
// Box shadows
|
|
375
|
-
const shadowMatches = content.matchAll(/box-shadow\s*:\s*([^;}\n]+)/g);
|
|
376
|
-
for (const m of shadowMatches) {
|
|
377
|
-
tokens.shadows.push({ value: m[1].trim() });
|
|
378
|
-
}
|
|
379
|
-
}
|
|
380
|
-
/**
|
|
381
|
-
* Build dark mode variable pairs from collected CSS variables.
|
|
382
|
-
* Detects patterns like --background (in :root) vs --background (in .dark).
|
|
383
|
-
*/
|
|
384
|
-
function extractDarkModeVars(tokens) {
|
|
385
|
-
// Already extracted in extractDarkModeBlocks, this is a post-processing step
|
|
386
|
-
// Deduplicate
|
|
387
|
-
const seen = new Set();
|
|
388
|
-
tokens.darkModeVars = tokens.darkModeVars.filter(v => {
|
|
389
|
-
if (seen.has(v.variable))
|
|
390
|
-
return false;
|
|
391
|
-
seen.add(v.variable);
|
|
392
|
-
return true;
|
|
393
|
-
});
|
|
394
|
-
}
|
|
395
|
-
function extractColorsFromValue(value, tokens) {
|
|
396
|
-
const hexMatches = value.matchAll(/#([0-9a-fA-F]{3,8})\b/g);
|
|
397
|
-
for (const m of hexMatches) {
|
|
398
|
-
const hex = normalizeHex(m[0]);
|
|
399
|
-
const existing = tokens.colors.find(c => c.value === hex);
|
|
400
|
-
if (existing) {
|
|
401
|
-
existing.frequency++;
|
|
402
|
-
}
|
|
403
|
-
else {
|
|
404
|
-
tokens.colors.push({ value: hex, frequency: 1, source: 'css' });
|
|
405
|
-
}
|
|
406
|
-
}
|
|
407
|
-
const rgbMatches = value.matchAll(/rgba?\(\s*(\d+)\s*,\s*(\d+)\s*,\s*(\d+)/g);
|
|
408
|
-
for (const m of rgbMatches) {
|
|
409
|
-
const hex = rgbToHex(parseInt(m[1]), parseInt(m[2]), parseInt(m[3]));
|
|
410
|
-
const existing = tokens.colors.find(c => c.value === hex);
|
|
411
|
-
if (existing) {
|
|
412
|
-
existing.frequency++;
|
|
413
|
-
}
|
|
414
|
-
else {
|
|
415
|
-
tokens.colors.push({ value: hex, frequency: 1, source: 'css' });
|
|
416
|
-
}
|
|
417
|
-
}
|
|
418
|
-
}
|
|
419
|
-
function extractSpacingValues(value, tokens) {
|
|
420
|
-
const nums = value.matchAll(/([\d.]+)(px|rem|em)/g);
|
|
421
|
-
for (const m of nums) {
|
|
422
|
-
let px = parseFloat(m[1]);
|
|
423
|
-
if (m[2] === 'rem' || m[2] === 'em')
|
|
424
|
-
px *= 16;
|
|
425
|
-
if (px > 0 && px <= 200) {
|
|
426
|
-
tokens.spacingValues.push(Math.round(px));
|
|
427
|
-
}
|
|
428
|
-
}
|
|
429
|
-
}
|
|
430
|
-
function isColorProperty(prop) {
|
|
431
|
-
return /^(color|background-color|background|border-color|outline-color|fill|stroke|--[\w-]*color[\w-]*)$/i.test(prop);
|
|
432
|
-
}
|
|
433
|
-
function isSpacingProperty(prop) {
|
|
434
|
-
return /^(margin|padding|gap|row-gap|column-gap|margin-top|margin-right|margin-bottom|margin-left|padding-top|padding-right|padding-bottom|padding-left|top|right|bottom|left|width|height|max-width|min-width)$/i.test(prop);
|
|
435
|
-
}
|
|
436
|
-
function guessPropertyType(varName) {
|
|
437
|
-
if (/color|bg|background|foreground/i.test(varName))
|
|
438
|
-
return 'color';
|
|
439
|
-
if (/font|family|typeface/i.test(varName))
|
|
440
|
-
return 'font';
|
|
441
|
-
if (/size|spacing|gap|padding|margin|radius/i.test(varName))
|
|
442
|
-
return 'spacing';
|
|
443
|
-
if (/shadow|elevation/i.test(varName))
|
|
444
|
-
return 'shadow';
|
|
445
|
-
return 'unknown';
|
|
446
|
-
}
|
|
447
|
-
function normalizeHex(v) {
|
|
448
|
-
const match = v.match(/^#([0-9a-fA-F]{3})$/);
|
|
449
|
-
if (match) {
|
|
450
|
-
const [r, g, b] = match[1].split('');
|
|
451
|
-
return `#${r}${r}${g}${g}${b}${b}`.toLowerCase();
|
|
452
|
-
}
|
|
453
|
-
return v.toLowerCase().slice(0, 7);
|
|
454
|
-
}
|
|
455
|
-
function rgbToHex(r, g, b) {
|
|
456
|
-
return '#' + [r, g, b].map(c => c.toString(16).padStart(2, '0')).join('').toLowerCase();
|
|
457
|
-
}
|
|
458
|
-
function isColorVarName(name) {
|
|
459
|
-
return /color|background|foreground|primary|secondary|accent|muted|destructive|border|card|popover|ring|input|chart/i.test(name) &&
|
|
460
|
-
!/font|size|spacing|radius|shadow|width|height|duration|delay/i.test(name);
|
|
461
|
-
}
|
|
462
|
-
function tryParseColorValue(value) {
|
|
463
|
-
const hexMatch = value.match(/^#([0-9a-fA-F]{3,8})$/);
|
|
464
|
-
if (hexMatch)
|
|
465
|
-
return normalizeHex(value);
|
|
466
|
-
const rgbMatch = value.match(/^rgba?\(\s*(\d+)\s*,\s*(\d+)\s*,\s*(\d+)/);
|
|
467
|
-
if (rgbMatch)
|
|
468
|
-
return rgbToHex(parseInt(rgbMatch[1]), parseInt(rgbMatch[2]), parseInt(rgbMatch[3]));
|
|
469
|
-
const hslMatch = value.match(/^hsla?\(\s*([\d.]+)\s*[,\s]\s*([\d.]+)%\s*[,\s]\s*([\d.]+)%/);
|
|
470
|
-
if (hslMatch)
|
|
471
|
-
return hslToHex(parseFloat(hslMatch[1]), parseFloat(hslMatch[2]), parseFloat(hslMatch[3]));
|
|
472
|
-
const bareHslMatch = value.match(/^\s*([\d.]+)\s+([\d.]+)%\s+([\d.]+)%\s*$/);
|
|
473
|
-
if (bareHslMatch)
|
|
474
|
-
return hslToHex(parseFloat(bareHslMatch[1]), parseFloat(bareHslMatch[2]), parseFloat(bareHslMatch[3]));
|
|
475
|
-
return null;
|
|
476
|
-
}
|
|
477
|
-
function hslToHex(h, s, l) {
|
|
478
|
-
s /= 100;
|
|
479
|
-
l /= 100;
|
|
480
|
-
const c = (1 - Math.abs(2 * l - 1)) * s;
|
|
481
|
-
const x = c * (1 - Math.abs(((h / 60) % 2) - 1));
|
|
482
|
-
const m = l - c / 2;
|
|
483
|
-
let r = 0, g = 0, b = 0;
|
|
484
|
-
if (h < 60) {
|
|
485
|
-
r = c;
|
|
486
|
-
g = x;
|
|
487
|
-
}
|
|
488
|
-
else if (h < 120) {
|
|
489
|
-
r = x;
|
|
490
|
-
g = c;
|
|
491
|
-
}
|
|
492
|
-
else if (h < 180) {
|
|
493
|
-
g = c;
|
|
494
|
-
b = x;
|
|
495
|
-
}
|
|
496
|
-
else if (h < 240) {
|
|
497
|
-
g = x;
|
|
498
|
-
b = c;
|
|
499
|
-
}
|
|
500
|
-
else if (h < 300) {
|
|
501
|
-
r = x;
|
|
502
|
-
b = c;
|
|
503
|
-
}
|
|
504
|
-
else {
|
|
505
|
-
r = c;
|
|
506
|
-
b = x;
|
|
507
|
-
}
|
|
508
|
-
return rgbToHex(Math.round((r + m) * 255), Math.round((g + m) * 255), Math.round((b + m) * 255));
|
|
509
|
-
}
|
|
510
|
-
//# sourceMappingURL=css.js.map
|
|
@@ -1,14 +0,0 @@
|
|
|
1
|
-
import { RawTokens, ComponentInfo } from '../../types';
|
|
2
|
-
/**
|
|
3
|
-
* HTTP-based extraction: fetch a URL, download its HTML + linked CSS,
|
|
4
|
-
* parse CSS for design tokens. Works WITHOUT Playwright.
|
|
5
|
-
*
|
|
6
|
-
* This is the fallback for URL mode when Playwright is not installed.
|
|
7
|
-
* It also serves as a baseline even when Playwright IS available.
|
|
8
|
-
*/
|
|
9
|
-
export interface HttpExtractionResult {
|
|
10
|
-
tokens: RawTokens;
|
|
11
|
-
components: ComponentInfo[];
|
|
12
|
-
}
|
|
13
|
-
export declare function extractHttpCSSTokens(url: string, maxPages?: number): Promise<HttpExtractionResult>;
|
|
14
|
-
//# sourceMappingURL=http-css.d.ts.map
|