vibe-design-system 2.8.78 → 2.8.81

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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "vibe-design-system",
3
- "version": "2.8.78",
3
+ "version": "2.8.81",
4
4
  "description": "Auto-generate design systems for vibe coding projects",
5
5
  "homepage": "https://vibedesign.tech",
6
6
  "repository": {
@@ -2207,6 +2207,21 @@ function extractVariantUsage(componentResults) {
2207
2207
  }
2208
2208
  }
2209
2209
 
2210
+ /**
2211
+ * Heuristic: detect complex page-level components that should not get individual stories.
2212
+ * Criteria: 500+ lines AND 4+ internal capitalized component definitions AND no cva()/forwardRef.
2213
+ * Examples: a 900-line MethodologyMap.tsx with 8 inline sub-components.
2214
+ */
2215
+ function isComplexPageComponent(content) {
2216
+ const lines = content.split("\n").length;
2217
+ if (lines < 500) return false;
2218
+ const internalComps = (content.match(/\bconst\s+[A-Z][A-Za-z]+\s*[:=]\s*\(/g) || []).length;
2219
+ if (internalComps < 4) return false;
2220
+ // Don't flag UI primitives that use cva() or forwardRef — those are styled components
2221
+ if (content.includes("cva(") || content.includes("forwardRef")) return false;
2222
+ return true;
2223
+ }
2224
+
2210
2225
  function scan() {
2211
2226
  const relativeFiles = COMPONENTS_DIR ? getAllComponentFiles(COMPONENTS_DIR) : [];
2212
2227
  if (!COMPONENTS_DIR) {
@@ -2231,7 +2246,8 @@ function scan() {
2231
2246
  description = "";
2232
2247
  }
2233
2248
  const tokens = extractTailwindTokens(content);
2234
- results.push({ file: rel, name, group, category, description, tokens });
2249
+ const isPageComponent = isComplexPageComponent(content);
2250
+ results.push({ file: rel, name, group, category, description, tokens, ...(isPageComponent ? { isPageComponent: true } : {}) });
2235
2251
  }
2236
2252
  if (PAGES_DIR && fs.existsSync(PAGES_DIR)) {
2237
2253
  const pageFiles = getAllComponentFiles(PAGES_DIR);
@@ -2202,7 +2202,8 @@ function buildStoryFileContent(comp) {
2202
2202
  // Strip opacity modifier (e.g. "muted/20" → "muted") as a fallback
2203
2203
  const baseKey = key ? key.replace(/\/[\d.]+$/, "") : null;
2204
2204
  const entry = key ? (foundColors[key] || (baseKey !== key ? foundColors[baseKey] : null)) : null;
2205
- const hex = entry?.hex && /^#[0-9a-fA-F]{3,8}$/.test(entry.hex) ? entry.hex : null;
2205
+ const isValidCssColor = (v) => /^#[0-9a-fA-F]{3,8}$/.test(v) || /^(rgb|rgba|hsl|hsla|oklch|oklab|lch|lab|color)\s*\(/.test(v) || v === 'transparent';
2206
+ const hex = entry?.hex && isValidCssColor(entry.hex) ? entry.hex : null;
2206
2207
  return { token, hex, label: baseKey || key };
2207
2208
  });
2208
2209
 
@@ -4246,7 +4247,8 @@ function writeComponentInventoryStory(components, foundations) {
4246
4247
  let key = m ? m[1] : null;
4247
4248
  if (key) key = key.replace(/\/\d+$/, "");
4248
4249
  const entry = key ? foundColors[key] : null;
4249
- const hex = entry?.hex && /^#[0-9a-fA-F]{3,8}$/.test(entry.hex) ? entry.hex : null;
4250
+ const isValidCssColor = (v) => /^#[0-9a-fA-F]{3,8}$/.test(v) || /^(rgb|rgba|hsl|hsla|oklch|oklab|lch|lab|color)\s*\(/.test(v) || v === 'transparent';
4251
+ const hex = entry?.hex && isValidCssColor(entry.hex) ? entry.hex : null;
4250
4252
  return { token, hex };
4251
4253
  })
4252
4254
  .filter(s => s.hex);
@@ -4906,6 +4908,11 @@ function main() {
4906
4908
  const storyFileName = `${componentName}.stories.tsx`;
4907
4909
  const storyPath = path.join(STORIES_DIR, storyFileName);
4908
4910
  if (SKIP_LIST.includes(componentName)) continue;
4911
+ // Skip complex page-level components detected by scan (500+ lines, 4+ inline sub-components)
4912
+ if (comp.isPageComponent) {
4913
+ console.log(`[VDS] ${componentName} → skipped (complex page component — add to extraSkipList to suppress this message)`);
4914
+ continue;
4915
+ }
4909
4916
  const requiredCount = Array.isArray(comp.props) ? comp.props.filter((p) => p.required === true).length : 0;
4910
4917
  if (requiredCount > 3) {
4911
4918
  console.log(`[VDS] ${componentName} → skipped (${requiredCount} required props — too complex to auto-generate)`);
@@ -262,6 +262,89 @@ function injectViteConfigAliases(projectRoot) {
262
262
  console.log(`[VDS] Storybook adapt: injected vite aliases: ${missingAliases.map(([k]) => k).join(", ")}`);
263
263
  }
264
264
 
265
+ // ============================================================
266
+ // VERSION-PINNED IMPORT HANDLING (Bolt/Lovable/AI-generated)
267
+ // ============================================================
268
+
269
+ /** Detect if import specifier has a @version suffix (e.g. @radix-ui/react-slot@1.1.2) */
270
+ function isVersionPinned(spec) {
271
+ return /^(?:@[\w.-]+\/)?[\w.-]+@\d+\.\d+/.test(spec) && !spec.startsWith("@/");
272
+ }
273
+
274
+ /** Scan source files for any version-pinned imports */
275
+ function hasVersionPinnedImports() {
276
+ if (!fs.existsSync(SRC_DIR)) return false;
277
+ const files = getAllSourceFiles(SRC_DIR, SRC_DIR).map((r) => path.join(SRC_DIR, r));
278
+ for (const file of files) {
279
+ try {
280
+ const content = fs.readFileSync(file, "utf-8");
281
+ for (const spec of extractImports(content)) {
282
+ if (isVersionPinned(spec)) return true;
283
+ }
284
+ } catch (_) {}
285
+ }
286
+ return false;
287
+ }
288
+
289
+ /**
290
+ * Remove wrong version alias entries previously injected by a broken VDS run.
291
+ * These look like: "@radix-ui/react-slot@1.1.2": path.resolve(process.cwd(), "@radix-ui/react-slot"),
292
+ * They point to non-existent paths and must be replaced by the plugin approach.
293
+ */
294
+ function cleanupWrongVersionAliases(projectRoot) {
295
+ const mainPath = getMainPath(projectRoot);
296
+ if (!mainPath) return;
297
+ let content = fs.readFileSync(mainPath, "utf-8");
298
+ const before = content;
299
+ // Remove any alias line where key has @version suffix
300
+ content = content.replace(
301
+ /\n?\s*"(?:@[\w.-]+\/)?[\w.-]+@[\d.]+"\s*:\s*path\.resolve\(process\.cwd\(\),\s*"[^"]+"\),?/g,
302
+ ""
303
+ );
304
+ if (content !== before) {
305
+ fs.writeFileSync(mainPath, content, "utf-8");
306
+ console.log("[VDS] Storybook adapt: cleaned up incorrect version-pinned aliases from main.ts.");
307
+ }
308
+ }
309
+
310
+ /**
311
+ * Inject a Vite plugin that strips @version suffixes from package import specifiers.
312
+ * e.g. @radix-ui/react-slot@1.1.2 → @radix-ui/react-slot (resolved from node_modules normally).
313
+ * Only added to viteFinal-based configs (not Next.js @storybook/nextjs).
314
+ */
315
+ function injectVersionStripPlugin(projectRoot) {
316
+ const mainPath = getMainPath(projectRoot);
317
+ if (!mainPath) return;
318
+ let content = fs.readFileSync(mainPath, "utf-8");
319
+
320
+ if (content.includes("vds-version-pin-strip")) return; // already injected
321
+ if (!content.includes("viteFinal")) return; // only for Vite-based storybook
322
+
323
+ // The plugin block to inject. Double-escaped backslashes become single in the written file.
324
+ const pluginBlock = ` plugins: [
325
+ {
326
+ name: "vds-version-pin-strip",
327
+ enforce: "pre",
328
+ async resolveId(id) {
329
+ // Strip @version suffix: @radix-ui/react-slot@1.1.2 → @radix-ui/react-slot
330
+ const m = id.match(/^((?:@[\\w.-]+\\/)?[\\w.-]+)@[\\d]+\\.[\\d]/);
331
+ if (m) return this.resolve(m[1], undefined, { skipSelf: true });
332
+ },
333
+ },
334
+ ],
335
+ `;
336
+
337
+ // Insert before the resolve: { block inside viteFinal
338
+ const resolvePattern = /([ \t]+)(resolve\s*:\s*\{)/;
339
+ if (resolvePattern.test(content)) {
340
+ content = content.replace(resolvePattern, (_, indent, resolveKw) =>
341
+ `${indent}${pluginBlock}${resolveKw}`
342
+ );
343
+ fs.writeFileSync(mainPath, content, "utf-8");
344
+ console.log("[VDS] Storybook adapt: injected vds-version-pin-strip Vite plugin.");
345
+ }
346
+ }
347
+
265
348
  function main() {
266
349
  const projectRoot = PROJECT_ROOT;
267
350
  if (!fs.existsSync(path.join(projectRoot, ".storybook"))) {
@@ -272,10 +355,16 @@ function main() {
272
355
  injectViteConfigAliases(projectRoot);
273
356
  reportUnresolvedImports(projectRoot);
274
357
  const problematic = collectProblematicImports(projectRoot);
275
- if (problematic.size === 0) return;
276
- writeMocks(projectRoot, problematic);
277
- injectAliases(projectRoot, problematic);
278
- console.log("[VDS] Storybook adapt: mocked", [...problematic].join(", "));
358
+ if (problematic.size > 0) {
359
+ writeMocks(projectRoot, problematic);
360
+ injectAliases(projectRoot, problematic);
361
+ console.log("[VDS] Storybook adapt: mocked", [...problematic].join(", "));
362
+ }
363
+ // Handle version-pinned imports (AI/Bolt/Lovable-generated projects with @pkg@version syntax)
364
+ if (hasVersionPinnedImports()) {
365
+ cleanupWrongVersionAliases(projectRoot);
366
+ injectVersionStripPlugin(projectRoot);
367
+ }
279
368
  }
280
369
 
281
370
  main();