@vadenai/mcp-server 0.2.1 → 0.3.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/dist/api-client.d.ts +3 -0
- package/dist/api-client.js +13 -3
- package/dist/index.js +235 -3
- package/dist/tools/components.js +149 -0
- package/dist/tools/concept.d.ts +12 -0
- package/dist/tools/concept.js +147 -1
- package/dist/tools/wireframes.d.ts +26 -0
- package/dist/tools/wireframes.js +39 -1
- package/dist/tools/write-components.d.ts +18 -0
- package/dist/tools/write-components.js +17 -0
- package/dist/tools/write-tokens.d.ts +17 -0
- package/dist/tools/write-tokens.js +16 -0
- package/dist/utils/tailwind-resolver.d.ts +35 -0
- package/dist/utils/tailwind-resolver.js +632 -0
- package/dist/validation.d.ts +42 -0
- package/dist/validation.js +83 -0
- package/package.json +1 -1
|
@@ -0,0 +1,632 @@
|
|
|
1
|
+
const SIZE_MAP = {
|
|
2
|
+
"0": "0px",
|
|
3
|
+
"0.5": "2px",
|
|
4
|
+
"1": "4px",
|
|
5
|
+
"1.5": "6px",
|
|
6
|
+
"2": "8px",
|
|
7
|
+
"2.5": "10px",
|
|
8
|
+
"3": "12px",
|
|
9
|
+
"3.5": "14px",
|
|
10
|
+
"4": "16px",
|
|
11
|
+
"5": "20px",
|
|
12
|
+
"6": "24px",
|
|
13
|
+
"7": "28px",
|
|
14
|
+
"8": "32px",
|
|
15
|
+
"9": "36px",
|
|
16
|
+
"10": "40px",
|
|
17
|
+
"11": "44px",
|
|
18
|
+
"12": "48px",
|
|
19
|
+
"14": "56px",
|
|
20
|
+
"16": "64px",
|
|
21
|
+
"20": "80px",
|
|
22
|
+
"24": "96px",
|
|
23
|
+
full: "100%",
|
|
24
|
+
};
|
|
25
|
+
const RADIUS_MAP = {
|
|
26
|
+
none: "0px",
|
|
27
|
+
sm: "0.125rem",
|
|
28
|
+
"": "0.25rem",
|
|
29
|
+
md: "0.375rem",
|
|
30
|
+
lg: "0.5rem",
|
|
31
|
+
xl: "0.75rem",
|
|
32
|
+
"2xl": "1rem",
|
|
33
|
+
"3xl": "1.5rem",
|
|
34
|
+
full: "9999px",
|
|
35
|
+
};
|
|
36
|
+
const FONT_WEIGHT_MAP = {
|
|
37
|
+
thin: "100",
|
|
38
|
+
extralight: "200",
|
|
39
|
+
light: "300",
|
|
40
|
+
normal: "400",
|
|
41
|
+
medium: "500",
|
|
42
|
+
semibold: "600",
|
|
43
|
+
bold: "700",
|
|
44
|
+
extrabold: "800",
|
|
45
|
+
black: "900",
|
|
46
|
+
};
|
|
47
|
+
const FONT_SIZE_MAP = {
|
|
48
|
+
xs: "0.75rem",
|
|
49
|
+
sm: "0.875rem",
|
|
50
|
+
base: "1rem",
|
|
51
|
+
lg: "1.125rem",
|
|
52
|
+
xl: "1.25rem",
|
|
53
|
+
"2xl": "1.5rem",
|
|
54
|
+
"3xl": "1.875rem",
|
|
55
|
+
};
|
|
56
|
+
const STATIC_COLORS = {
|
|
57
|
+
white: "#ffffff",
|
|
58
|
+
black: "#000000",
|
|
59
|
+
transparent: "transparent",
|
|
60
|
+
};
|
|
61
|
+
const TAILWIND_PALETTE = {
|
|
62
|
+
// Gray
|
|
63
|
+
"gray-50": "#f9fafb",
|
|
64
|
+
"gray-100": "#f3f4f6",
|
|
65
|
+
"gray-200": "#e5e7eb",
|
|
66
|
+
"gray-300": "#d1d5db",
|
|
67
|
+
"gray-400": "#9ca3af",
|
|
68
|
+
"gray-500": "#6b7280",
|
|
69
|
+
"gray-600": "#4b5563",
|
|
70
|
+
"gray-700": "#374151",
|
|
71
|
+
"gray-800": "#1f2937",
|
|
72
|
+
"gray-900": "#111827",
|
|
73
|
+
// Pink
|
|
74
|
+
"pink-50": "#fdf2f8",
|
|
75
|
+
"pink-100": "#fce7f3",
|
|
76
|
+
"pink-200": "#fbcfe8",
|
|
77
|
+
"pink-300": "#f9a8d4",
|
|
78
|
+
"pink-400": "#f472b6",
|
|
79
|
+
"pink-500": "#ec4899",
|
|
80
|
+
"pink-600": "#db2777",
|
|
81
|
+
"pink-700": "#be185d",
|
|
82
|
+
"pink-800": "#9d174d",
|
|
83
|
+
"pink-900": "#831843",
|
|
84
|
+
// Purple
|
|
85
|
+
"purple-400": "#a78bfa",
|
|
86
|
+
"purple-500": "#8b5cf6",
|
|
87
|
+
"purple-600": "#7c3aed",
|
|
88
|
+
"purple-900": "#4c1d95",
|
|
89
|
+
// Cyan
|
|
90
|
+
"cyan-400": "#22d3ee",
|
|
91
|
+
"cyan-500": "#06b6d4",
|
|
92
|
+
// Yellow
|
|
93
|
+
"yellow-200": "#fef08a",
|
|
94
|
+
"yellow-400": "#facc15",
|
|
95
|
+
// Red
|
|
96
|
+
"red-500": "#ef4444",
|
|
97
|
+
"red-600": "#dc2626",
|
|
98
|
+
// Green
|
|
99
|
+
"green-500": "#22c55e",
|
|
100
|
+
// Blue
|
|
101
|
+
"blue-500": "#3b82f6",
|
|
102
|
+
"blue-600": "#2563eb",
|
|
103
|
+
};
|
|
104
|
+
const SHADOW_MAP = {
|
|
105
|
+
sm: "0 1px 2px 0 rgb(0 0 0 / 0.05)",
|
|
106
|
+
"": "0 1px 3px 0 rgb(0 0 0 / 0.1), 0 1px 2px -1px rgb(0 0 0 / 0.1)",
|
|
107
|
+
md: "0 4px 6px -1px rgb(0 0 0 / 0.1), 0 2px 4px -2px rgb(0 0 0 / 0.1)",
|
|
108
|
+
lg: "0 10px 15px -3px rgb(0 0 0 / 0.1), 0 4px 6px -4px rgb(0 0 0 / 0.1)",
|
|
109
|
+
xl: "0 20px 25px -5px rgb(0 0 0 / 0.1), 0 10px 10px -5px rgb(0 0 0 / 0.1)",
|
|
110
|
+
"2xl": "0 25px 50px -12px rgb(0 0 0 / 0.25)",
|
|
111
|
+
none: "none",
|
|
112
|
+
};
|
|
113
|
+
const TRACKING_MAP = {
|
|
114
|
+
tighter: "-0.05em",
|
|
115
|
+
tight: "-0.025em",
|
|
116
|
+
normal: "0em",
|
|
117
|
+
wide: "0.025em",
|
|
118
|
+
wider: "0.05em",
|
|
119
|
+
widest: "0.1em",
|
|
120
|
+
};
|
|
121
|
+
const FONT_FAMILY_MAP = {
|
|
122
|
+
sans: "sans-serif",
|
|
123
|
+
serif: "serif",
|
|
124
|
+
mono: "monospace",
|
|
125
|
+
body: "var(--font-body)",
|
|
126
|
+
heading: "var(--font-heading)",
|
|
127
|
+
};
|
|
128
|
+
const GRADIENT_DIR_MAP = {
|
|
129
|
+
r: "right",
|
|
130
|
+
l: "left",
|
|
131
|
+
t: "top",
|
|
132
|
+
b: "bottom",
|
|
133
|
+
tr: "top right",
|
|
134
|
+
tl: "top left",
|
|
135
|
+
br: "bottom right",
|
|
136
|
+
bl: "bottom left",
|
|
137
|
+
};
|
|
138
|
+
const FONT_SIZE_KEYS = new Set(Object.keys(FONT_SIZE_MAP));
|
|
139
|
+
function normalizeHex(hex) {
|
|
140
|
+
const h = hex.replace("#", "");
|
|
141
|
+
if (h.length === 3) {
|
|
142
|
+
return `#${h[0]}${h[0]}${h[1]}${h[1]}${h[2]}${h[2]}`;
|
|
143
|
+
}
|
|
144
|
+
if (h.length === 4) {
|
|
145
|
+
const r = parseInt(`${h[0]}${h[0]}`, 16);
|
|
146
|
+
const g = parseInt(`${h[1]}${h[1]}`, 16);
|
|
147
|
+
const b = parseInt(`${h[2]}${h[2]}`, 16);
|
|
148
|
+
const a = parseInt(`${h[3]}${h[3]}`, 16) / 255;
|
|
149
|
+
return `rgba(${r},${g},${b},${Number(a.toFixed(3))})`;
|
|
150
|
+
}
|
|
151
|
+
if (h.length === 8) {
|
|
152
|
+
const r = parseInt(h.slice(0, 2), 16);
|
|
153
|
+
const g = parseInt(h.slice(2, 4), 16);
|
|
154
|
+
const b = parseInt(h.slice(4, 6), 16);
|
|
155
|
+
const a = parseInt(h.slice(6, 8), 16) / 255;
|
|
156
|
+
return `rgba(${r},${g},${b},${Number(a.toFixed(3))})`;
|
|
157
|
+
}
|
|
158
|
+
return `#${h.slice(0, 6)}`;
|
|
159
|
+
}
|
|
160
|
+
function parseArbitraryValue(val) {
|
|
161
|
+
const m = val.match(/^\[(.+)\]$/);
|
|
162
|
+
// Tailwind の arbitrary value では _ はスペースとして扱われる
|
|
163
|
+
// e.g. w-[calc(100%_-_1rem)] → calc(100% - 1rem)
|
|
164
|
+
return m ? m[1].replace(/_/g, " ") : null;
|
|
165
|
+
}
|
|
166
|
+
function resolveColorValue(value, resolvedColors) {
|
|
167
|
+
// 0. Arbitrary bracket color: [#hex], [rgba(...)], [hsl(...)], [oklch(...)]
|
|
168
|
+
const arbitrary = parseArbitraryValue(value);
|
|
169
|
+
if (arbitrary) {
|
|
170
|
+
// raw hex
|
|
171
|
+
if (/^#([0-9a-fA-F]{3,8})$/.test(arbitrary)) {
|
|
172
|
+
return normalizeHex(arbitrary);
|
|
173
|
+
}
|
|
174
|
+
// css function: rgba(...), hsl(...), oklch(...)
|
|
175
|
+
if (/^(rgba?|hsla?|oklch)\(.+\)$/i.test(arbitrary)) {
|
|
176
|
+
return arbitrary;
|
|
177
|
+
}
|
|
178
|
+
return null;
|
|
179
|
+
}
|
|
180
|
+
// 0.5. Raw hex without brackets (used in gradient stops like from-#hex)
|
|
181
|
+
if (/^#([0-9a-fA-F]{3,8})$/.test(value)) {
|
|
182
|
+
return normalizeHex(value);
|
|
183
|
+
}
|
|
184
|
+
// 1a. Bracket opacity: {name}/[0.05]
|
|
185
|
+
const bracketOpacityMatch = value.match(/^(.+)\/\[([0-9.]+)\]$/);
|
|
186
|
+
if (bracketOpacityMatch) {
|
|
187
|
+
const [, colorName, opacityStr] = bracketOpacityMatch;
|
|
188
|
+
const opacity = Number(opacityStr);
|
|
189
|
+
if (colorName === "white")
|
|
190
|
+
return `rgba(255,255,255,${opacity})`;
|
|
191
|
+
if (colorName === "black")
|
|
192
|
+
return `rgba(0,0,0,${opacity})`;
|
|
193
|
+
const baseColor = resolveColorValue(colorName, resolvedColors);
|
|
194
|
+
if (baseColor?.startsWith("#")) {
|
|
195
|
+
const r = parseInt(baseColor.slice(1, 3), 16);
|
|
196
|
+
const g = parseInt(baseColor.slice(3, 5), 16);
|
|
197
|
+
const b = parseInt(baseColor.slice(5, 7), 16);
|
|
198
|
+
return `rgba(${r},${g},${b},${opacity})`;
|
|
199
|
+
}
|
|
200
|
+
}
|
|
201
|
+
// 1b. Opacity-suffixed colors: white/10, black/50, primary/10
|
|
202
|
+
const opacityMatch = value.match(/^(.+)\/(\d+)$/);
|
|
203
|
+
if (opacityMatch) {
|
|
204
|
+
const [, colorName, opacityStr] = opacityMatch;
|
|
205
|
+
const opacity = Number(opacityStr) / 100;
|
|
206
|
+
if (colorName === "white")
|
|
207
|
+
return `rgba(255,255,255,${opacity})`;
|
|
208
|
+
if (colorName === "black")
|
|
209
|
+
return `rgba(0,0,0,${opacity})`;
|
|
210
|
+
// Try resolving semantic color
|
|
211
|
+
const baseColor = resolveColorValue(colorName, resolvedColors);
|
|
212
|
+
if (baseColor?.startsWith("#")) {
|
|
213
|
+
const r = parseInt(baseColor.slice(1, 3), 16);
|
|
214
|
+
const g = parseInt(baseColor.slice(3, 5), 16);
|
|
215
|
+
const b = parseInt(baseColor.slice(5, 7), 16);
|
|
216
|
+
return `rgba(${r},${g},${b},${opacity})`;
|
|
217
|
+
}
|
|
218
|
+
}
|
|
219
|
+
// 2. Static colors
|
|
220
|
+
if (value in STATIC_COLORS) {
|
|
221
|
+
return STATIC_COLORS[value];
|
|
222
|
+
}
|
|
223
|
+
// 2.5 Tailwind palette colors (e.g. gray-300, pink-400)
|
|
224
|
+
if (value in TAILWIND_PALETTE) {
|
|
225
|
+
return TAILWIND_PALETTE[value];
|
|
226
|
+
}
|
|
227
|
+
// 3. Semantic tokens from resolvedColors
|
|
228
|
+
// muted-foreground → resolvedColors.muted.foreground
|
|
229
|
+
// foreground → resolvedColors.base.foreground
|
|
230
|
+
// muted → resolvedColors.muted.background
|
|
231
|
+
// primary → resolvedColors.primary.background
|
|
232
|
+
// destructive → resolvedColors.destructive (if string)
|
|
233
|
+
// Handle compound tokens like "muted-foreground", "primary-foreground"
|
|
234
|
+
const dashIndex = value.indexOf("-");
|
|
235
|
+
if (dashIndex !== -1) {
|
|
236
|
+
const prefix = value.substring(0, dashIndex);
|
|
237
|
+
const suffix = value.substring(dashIndex + 1);
|
|
238
|
+
const group = resolvedColors[prefix];
|
|
239
|
+
if (group && typeof group === "object" && group !== null) {
|
|
240
|
+
const resolved = group[suffix];
|
|
241
|
+
if (typeof resolved === "string") {
|
|
242
|
+
return resolved;
|
|
243
|
+
}
|
|
244
|
+
}
|
|
245
|
+
return null;
|
|
246
|
+
}
|
|
247
|
+
// Handle simple tokens
|
|
248
|
+
if (value === "foreground") {
|
|
249
|
+
const base = resolvedColors.base;
|
|
250
|
+
if (base && typeof base === "object" && base !== null) {
|
|
251
|
+
const fg = base.foreground;
|
|
252
|
+
if (typeof fg === "string")
|
|
253
|
+
return fg;
|
|
254
|
+
}
|
|
255
|
+
return null;
|
|
256
|
+
}
|
|
257
|
+
if (value === "background") {
|
|
258
|
+
const base = resolvedColors.base;
|
|
259
|
+
if (base && typeof base === "object" && base !== null) {
|
|
260
|
+
const bg = base.background;
|
|
261
|
+
if (typeof bg === "string")
|
|
262
|
+
return bg;
|
|
263
|
+
}
|
|
264
|
+
return null;
|
|
265
|
+
}
|
|
266
|
+
// For tokens like "muted", "primary" → look up .background
|
|
267
|
+
const group = resolvedColors[value];
|
|
268
|
+
if (typeof group === "string") {
|
|
269
|
+
return group;
|
|
270
|
+
}
|
|
271
|
+
if (group && typeof group === "object" && group !== null) {
|
|
272
|
+
const bg = group.background;
|
|
273
|
+
if (typeof bg === "string")
|
|
274
|
+
return bg;
|
|
275
|
+
}
|
|
276
|
+
return null;
|
|
277
|
+
}
|
|
278
|
+
export function resolveVisualProperties(classes, resolvedColors) {
|
|
279
|
+
const result = {};
|
|
280
|
+
const tokens = classes.split(/\s+/).filter(Boolean);
|
|
281
|
+
for (const token of tokens) {
|
|
282
|
+
// Height
|
|
283
|
+
if (token.startsWith("h-")) {
|
|
284
|
+
const val = token.slice(2);
|
|
285
|
+
if (val === "screen") {
|
|
286
|
+
result.height = "100vh";
|
|
287
|
+
}
|
|
288
|
+
else if (val in SIZE_MAP) {
|
|
289
|
+
result.height = SIZE_MAP[val];
|
|
290
|
+
}
|
|
291
|
+
else {
|
|
292
|
+
const arb = parseArbitraryValue(val);
|
|
293
|
+
if (arb)
|
|
294
|
+
result.height = arb;
|
|
295
|
+
}
|
|
296
|
+
continue;
|
|
297
|
+
}
|
|
298
|
+
// Width
|
|
299
|
+
if (token.startsWith("w-")) {
|
|
300
|
+
const val = token.slice(2);
|
|
301
|
+
if (val === "screen") {
|
|
302
|
+
result.width = "100vw";
|
|
303
|
+
}
|
|
304
|
+
else if (val in SIZE_MAP) {
|
|
305
|
+
result.width = SIZE_MAP[val];
|
|
306
|
+
}
|
|
307
|
+
else {
|
|
308
|
+
const arb = parseArbitraryValue(val);
|
|
309
|
+
if (arb)
|
|
310
|
+
result.width = arb;
|
|
311
|
+
}
|
|
312
|
+
continue;
|
|
313
|
+
}
|
|
314
|
+
// Padding (check px-/py-/pt-/pb-/pl-/pr- before p- to avoid false match)
|
|
315
|
+
if (token.startsWith("px-")) {
|
|
316
|
+
const val = token.slice(3);
|
|
317
|
+
if (val in SIZE_MAP)
|
|
318
|
+
result.paddingX = SIZE_MAP[val];
|
|
319
|
+
else {
|
|
320
|
+
const arb = parseArbitraryValue(val);
|
|
321
|
+
if (arb)
|
|
322
|
+
result.paddingX = arb;
|
|
323
|
+
}
|
|
324
|
+
continue;
|
|
325
|
+
}
|
|
326
|
+
if (token.startsWith("py-")) {
|
|
327
|
+
const val = token.slice(3);
|
|
328
|
+
if (val in SIZE_MAP)
|
|
329
|
+
result.paddingY = SIZE_MAP[val];
|
|
330
|
+
else {
|
|
331
|
+
const arb = parseArbitraryValue(val);
|
|
332
|
+
if (arb)
|
|
333
|
+
result.paddingY = arb;
|
|
334
|
+
}
|
|
335
|
+
continue;
|
|
336
|
+
}
|
|
337
|
+
if (token.startsWith("pt-")) {
|
|
338
|
+
const val = token.slice(3);
|
|
339
|
+
if (val in SIZE_MAP)
|
|
340
|
+
result.paddingTop = SIZE_MAP[val];
|
|
341
|
+
else {
|
|
342
|
+
const arb = parseArbitraryValue(val);
|
|
343
|
+
if (arb)
|
|
344
|
+
result.paddingTop = arb;
|
|
345
|
+
}
|
|
346
|
+
continue;
|
|
347
|
+
}
|
|
348
|
+
if (token.startsWith("pb-")) {
|
|
349
|
+
const val = token.slice(3);
|
|
350
|
+
if (val in SIZE_MAP)
|
|
351
|
+
result.paddingBottom = SIZE_MAP[val];
|
|
352
|
+
else {
|
|
353
|
+
const arb = parseArbitraryValue(val);
|
|
354
|
+
if (arb)
|
|
355
|
+
result.paddingBottom = arb;
|
|
356
|
+
}
|
|
357
|
+
continue;
|
|
358
|
+
}
|
|
359
|
+
if (token.startsWith("pl-")) {
|
|
360
|
+
const val = token.slice(3);
|
|
361
|
+
if (val in SIZE_MAP)
|
|
362
|
+
result.paddingLeft = SIZE_MAP[val];
|
|
363
|
+
else {
|
|
364
|
+
const arb = parseArbitraryValue(val);
|
|
365
|
+
if (arb)
|
|
366
|
+
result.paddingLeft = arb;
|
|
367
|
+
}
|
|
368
|
+
continue;
|
|
369
|
+
}
|
|
370
|
+
if (token.startsWith("pr-")) {
|
|
371
|
+
const val = token.slice(3);
|
|
372
|
+
if (val in SIZE_MAP)
|
|
373
|
+
result.paddingRight = SIZE_MAP[val];
|
|
374
|
+
else {
|
|
375
|
+
const arb = parseArbitraryValue(val);
|
|
376
|
+
if (arb)
|
|
377
|
+
result.paddingRight = arb;
|
|
378
|
+
}
|
|
379
|
+
continue;
|
|
380
|
+
}
|
|
381
|
+
if (token.startsWith("p-")) {
|
|
382
|
+
const val = token.slice(2);
|
|
383
|
+
if (val in SIZE_MAP)
|
|
384
|
+
result.padding = SIZE_MAP[val];
|
|
385
|
+
else {
|
|
386
|
+
const arb = parseArbitraryValue(val);
|
|
387
|
+
if (arb)
|
|
388
|
+
result.padding = arb;
|
|
389
|
+
}
|
|
390
|
+
continue;
|
|
391
|
+
}
|
|
392
|
+
// Gap
|
|
393
|
+
if (token.startsWith("gap-")) {
|
|
394
|
+
const val = token.slice(4);
|
|
395
|
+
if (val in SIZE_MAP)
|
|
396
|
+
result.gap = SIZE_MAP[val];
|
|
397
|
+
else {
|
|
398
|
+
const arb = parseArbitraryValue(val);
|
|
399
|
+
if (arb)
|
|
400
|
+
result.gap = arb;
|
|
401
|
+
}
|
|
402
|
+
continue;
|
|
403
|
+
}
|
|
404
|
+
// Letter-spacing (tracking)
|
|
405
|
+
if (token.startsWith("tracking-")) {
|
|
406
|
+
const val = token.slice(9);
|
|
407
|
+
if (val in TRACKING_MAP)
|
|
408
|
+
result.letterSpacing = TRACKING_MAP[val];
|
|
409
|
+
continue;
|
|
410
|
+
}
|
|
411
|
+
// Flex-shrink
|
|
412
|
+
if (token === "shrink-0") {
|
|
413
|
+
result.flexShrink = "0";
|
|
414
|
+
continue;
|
|
415
|
+
}
|
|
416
|
+
if (token === "shrink") {
|
|
417
|
+
result.flexShrink = "1";
|
|
418
|
+
continue;
|
|
419
|
+
}
|
|
420
|
+
// Border radius
|
|
421
|
+
if (token === "rounded") {
|
|
422
|
+
result.borderRadius = "0.25rem";
|
|
423
|
+
continue;
|
|
424
|
+
}
|
|
425
|
+
if (token.startsWith("rounded-")) {
|
|
426
|
+
const val = token.slice(8);
|
|
427
|
+
if (val in RADIUS_MAP) {
|
|
428
|
+
result.borderRadius = RADIUS_MAP[val];
|
|
429
|
+
}
|
|
430
|
+
continue;
|
|
431
|
+
}
|
|
432
|
+
// Display
|
|
433
|
+
if (token === "flex") {
|
|
434
|
+
result.display = "flex";
|
|
435
|
+
continue;
|
|
436
|
+
}
|
|
437
|
+
if (token === "inline-flex") {
|
|
438
|
+
result.display = "inline-flex";
|
|
439
|
+
continue;
|
|
440
|
+
}
|
|
441
|
+
if (token === "grid") {
|
|
442
|
+
result.display = "grid";
|
|
443
|
+
continue;
|
|
444
|
+
}
|
|
445
|
+
// Align items
|
|
446
|
+
if (token === "items-center") {
|
|
447
|
+
result.alignItems = "center";
|
|
448
|
+
continue;
|
|
449
|
+
}
|
|
450
|
+
if (token === "items-start") {
|
|
451
|
+
result.alignItems = "flex-start";
|
|
452
|
+
continue;
|
|
453
|
+
}
|
|
454
|
+
if (token === "items-end") {
|
|
455
|
+
result.alignItems = "flex-end";
|
|
456
|
+
continue;
|
|
457
|
+
}
|
|
458
|
+
// Justify content
|
|
459
|
+
if (token === "justify-center") {
|
|
460
|
+
result.justifyContent = "center";
|
|
461
|
+
continue;
|
|
462
|
+
}
|
|
463
|
+
if (token === "justify-between") {
|
|
464
|
+
result.justifyContent = "space-between";
|
|
465
|
+
continue;
|
|
466
|
+
}
|
|
467
|
+
// Overflow
|
|
468
|
+
if (token === "overflow-hidden") {
|
|
469
|
+
result.overflow = "hidden";
|
|
470
|
+
continue;
|
|
471
|
+
}
|
|
472
|
+
// Aspect ratio
|
|
473
|
+
if (token === "aspect-square") {
|
|
474
|
+
result.aspectRatio = "1/1";
|
|
475
|
+
continue;
|
|
476
|
+
}
|
|
477
|
+
if (token === "aspect-video") {
|
|
478
|
+
result.aspectRatio = "16/9";
|
|
479
|
+
continue;
|
|
480
|
+
}
|
|
481
|
+
// Object fit
|
|
482
|
+
if (token === "object-cover") {
|
|
483
|
+
result.objectFit = "cover";
|
|
484
|
+
continue;
|
|
485
|
+
}
|
|
486
|
+
if (token === "object-contain") {
|
|
487
|
+
result.objectFit = "contain";
|
|
488
|
+
continue;
|
|
489
|
+
}
|
|
490
|
+
// Font family / weight
|
|
491
|
+
if (token.startsWith("font-")) {
|
|
492
|
+
const val = token.slice(5);
|
|
493
|
+
if (val in FONT_FAMILY_MAP) {
|
|
494
|
+
result.fontFamily = FONT_FAMILY_MAP[val];
|
|
495
|
+
continue;
|
|
496
|
+
}
|
|
497
|
+
if (val in FONT_WEIGHT_MAP) {
|
|
498
|
+
result.fontWeight = FONT_WEIGHT_MAP[val];
|
|
499
|
+
}
|
|
500
|
+
continue;
|
|
501
|
+
}
|
|
502
|
+
// Opacity
|
|
503
|
+
if (token.startsWith("opacity-")) {
|
|
504
|
+
const val = token.slice(8);
|
|
505
|
+
const num = Number(val);
|
|
506
|
+
if (!Number.isNaN(num)) {
|
|
507
|
+
result.opacity = String(num / 100);
|
|
508
|
+
}
|
|
509
|
+
continue;
|
|
510
|
+
}
|
|
511
|
+
// Shadow: semantic values first, then arbitrary
|
|
512
|
+
if (token === "shadow") {
|
|
513
|
+
result.boxShadow = SHADOW_MAP[""];
|
|
514
|
+
continue;
|
|
515
|
+
}
|
|
516
|
+
if (token.startsWith("shadow-[")) {
|
|
517
|
+
const inner = token.slice(8, -1);
|
|
518
|
+
result.boxShadow = inner.replace(/_/g, " ");
|
|
519
|
+
continue;
|
|
520
|
+
}
|
|
521
|
+
if (token.startsWith("shadow-")) {
|
|
522
|
+
const val = token.slice(7);
|
|
523
|
+
if (val in SHADOW_MAP) {
|
|
524
|
+
result.boxShadow = SHADOW_MAP[val];
|
|
525
|
+
}
|
|
526
|
+
continue;
|
|
527
|
+
}
|
|
528
|
+
// Border: must check before bg-/text- color resolution
|
|
529
|
+
if (token === "border") {
|
|
530
|
+
result.border = {
|
|
531
|
+
width: "1px",
|
|
532
|
+
color: result.border?.color ?? "",
|
|
533
|
+
};
|
|
534
|
+
continue;
|
|
535
|
+
}
|
|
536
|
+
// border-{n} where n is a single digit
|
|
537
|
+
if (token.startsWith("border-")) {
|
|
538
|
+
const val = token.slice(7);
|
|
539
|
+
// border-style: dashed, dotted, solid (must check before color resolution)
|
|
540
|
+
if (val === "dashed" || val === "dotted" || val === "solid") {
|
|
541
|
+
result.borderStyle = val;
|
|
542
|
+
continue;
|
|
543
|
+
}
|
|
544
|
+
// border-[{n}px] arbitrary value
|
|
545
|
+
const arbitraryMatch = val.match(/^\[(\d+)px\]$/);
|
|
546
|
+
if (arbitraryMatch) {
|
|
547
|
+
result.border = {
|
|
548
|
+
width: `${arbitraryMatch[1]}px`,
|
|
549
|
+
color: result.border?.color ?? "",
|
|
550
|
+
};
|
|
551
|
+
continue;
|
|
552
|
+
}
|
|
553
|
+
// border-{n} numeric
|
|
554
|
+
if (/^\d+$/.test(val)) {
|
|
555
|
+
result.border = {
|
|
556
|
+
width: `${val}px`,
|
|
557
|
+
color: result.border?.color ?? "",
|
|
558
|
+
};
|
|
559
|
+
continue;
|
|
560
|
+
}
|
|
561
|
+
// border-{colorValue}
|
|
562
|
+
const color = resolveColorValue(val, resolvedColors);
|
|
563
|
+
if (color) {
|
|
564
|
+
result.border = {
|
|
565
|
+
width: result.border?.width ?? "1px",
|
|
566
|
+
color,
|
|
567
|
+
};
|
|
568
|
+
}
|
|
569
|
+
continue;
|
|
570
|
+
}
|
|
571
|
+
// text-{size} MUST come before text-{color}
|
|
572
|
+
if (token.startsWith("text-")) {
|
|
573
|
+
const val = token.slice(5);
|
|
574
|
+
if (FONT_SIZE_KEYS.has(val)) {
|
|
575
|
+
result.fontSize = FONT_SIZE_MAP[val];
|
|
576
|
+
continue;
|
|
577
|
+
}
|
|
578
|
+
// text-{color}
|
|
579
|
+
const color = resolveColorValue(val, resolvedColors);
|
|
580
|
+
if (color) {
|
|
581
|
+
result.color = color;
|
|
582
|
+
}
|
|
583
|
+
continue;
|
|
584
|
+
}
|
|
585
|
+
// bg-gradient-to-{direction} (must check before bg-{color})
|
|
586
|
+
if (token.startsWith("bg-gradient-to-")) {
|
|
587
|
+
const dir = token.slice(15);
|
|
588
|
+
result.gradient = `linear-gradient(to ${GRADIENT_DIR_MAP[dir] ?? dir}`;
|
|
589
|
+
continue;
|
|
590
|
+
}
|
|
591
|
+
// bg-{color}
|
|
592
|
+
if (token.startsWith("bg-")) {
|
|
593
|
+
const val = token.slice(3);
|
|
594
|
+
const color = resolveColorValue(val, resolvedColors);
|
|
595
|
+
if (color) {
|
|
596
|
+
result.backgroundColor = color;
|
|
597
|
+
}
|
|
598
|
+
continue;
|
|
599
|
+
}
|
|
600
|
+
// from-{color} (gradient)
|
|
601
|
+
if (token.startsWith("from-")) {
|
|
602
|
+
const val = token.slice(5);
|
|
603
|
+
const color = resolveColorValue(val, resolvedColors);
|
|
604
|
+
if (color) {
|
|
605
|
+
result.gradient = `${result.gradient ?? "linear-gradient("}, ${color}`;
|
|
606
|
+
}
|
|
607
|
+
continue;
|
|
608
|
+
}
|
|
609
|
+
// via-{color} (gradient middle stop)
|
|
610
|
+
if (token.startsWith("via-")) {
|
|
611
|
+
const val = token.slice(4);
|
|
612
|
+
const color = resolveColorValue(val, resolvedColors);
|
|
613
|
+
if (color) {
|
|
614
|
+
result.gradient = `${result.gradient ?? "linear-gradient("}, ${color}`;
|
|
615
|
+
}
|
|
616
|
+
continue;
|
|
617
|
+
}
|
|
618
|
+
// to-{color} (gradient stop)
|
|
619
|
+
if (token.startsWith("to-")) {
|
|
620
|
+
const val = token.slice(3);
|
|
621
|
+
const color = resolveColorValue(val, resolvedColors);
|
|
622
|
+
if (color) {
|
|
623
|
+
result.gradient = `${result.gradient ?? "linear-gradient("}, ${color})`;
|
|
624
|
+
}
|
|
625
|
+
}
|
|
626
|
+
}
|
|
627
|
+
// グラデーションが閉じ括弧なしで終わっている場合は追加
|
|
628
|
+
if (result.gradient && !result.gradient.endsWith(")")) {
|
|
629
|
+
result.gradient = `${result.gradient})`;
|
|
630
|
+
}
|
|
631
|
+
return result;
|
|
632
|
+
}
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* MCP ツール引数のバリデーションユーティリティ
|
|
3
|
+
*/
|
|
4
|
+
/**
|
|
5
|
+
* update_concept / update_wireframe 用のフィールド更新引数を検証・抽出する
|
|
6
|
+
*
|
|
7
|
+
* @returns { fieldPath, value } — 検証済みの値
|
|
8
|
+
* @throws {Error} 引数が不正な場合
|
|
9
|
+
*/
|
|
10
|
+
export declare function validateFieldUpdateArgs(args: Record<string, unknown>): {
|
|
11
|
+
fieldPath: string;
|
|
12
|
+
value: string | number | boolean | null;
|
|
13
|
+
};
|
|
14
|
+
/**
|
|
15
|
+
* add_wireframe_element / add_concept_element 用の引数を検証・抽出する
|
|
16
|
+
*
|
|
17
|
+
* @returns { fieldPath, value } — 検証済みの値
|
|
18
|
+
* @throws {Error} 引数が不正な場合
|
|
19
|
+
*/
|
|
20
|
+
export declare function validateArrayAddArgs(args: Record<string, unknown>): {
|
|
21
|
+
fieldPath: string;
|
|
22
|
+
value: unknown;
|
|
23
|
+
};
|
|
24
|
+
/**
|
|
25
|
+
* remove_wireframe_element / remove_concept_element 用の引数を検証・抽出する
|
|
26
|
+
*
|
|
27
|
+
* @returns { fieldPath } — 検証済みの値
|
|
28
|
+
* @throws {Error} 引数が不正な場合
|
|
29
|
+
*/
|
|
30
|
+
export declare function validateArrayRemoveArgs(args: Record<string, unknown>): {
|
|
31
|
+
fieldPath: string;
|
|
32
|
+
};
|
|
33
|
+
/**
|
|
34
|
+
* push_wireframes 用の files 引数を検証する
|
|
35
|
+
*
|
|
36
|
+
* @returns 検証済みの files 配列
|
|
37
|
+
* @throws {Error} 引数が不正な場合
|
|
38
|
+
*/
|
|
39
|
+
export declare function validatePushWireframesArgs(args: Record<string, unknown>): Array<{
|
|
40
|
+
filename: string;
|
|
41
|
+
content: string;
|
|
42
|
+
}>;
|