vibe-design-system 2.5.18 → 2.5.20

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.5.18",
3
+ "version": "2.5.20",
4
4
  "description": "Auto-generate design systems for vibe coding projects",
5
5
  "type": "module",
6
6
  "bin": {
@@ -445,7 +445,7 @@ function parsePropsFromSource(source) {
445
445
  /** Default icon for LucideIcon prop when name is generic (icon, leftIcon, etc.). */
446
446
  const LUCIDE_ICON_DEFAULT = "Star";
447
447
 
448
- /** Yaygın required string prop isimleri için anlamlı varsayılan metin (component'in boş/Example yerine görünür render etmesi için). */
448
+ /** Yaygın required string prop isimleri için fallback (sayfada kullanım bulunamazsa). */
449
449
  const DEFAULT_STRINGS_BY_PROP_NAME = {
450
450
  eyebrow: "Label",
451
451
  title: "Section title",
@@ -456,29 +456,107 @@ const DEFAULT_STRINGS_BY_PROP_NAME = {
456
456
  subtitle: "Subtitle text",
457
457
  text: "Sample text",
458
458
  label: "Label",
459
+ status: "Active",
460
+ sector: "Technology",
461
+ step: "01",
462
+ role: "Team Member",
459
463
  };
460
464
 
461
- /** Build default args lines and lucide-react imports for required props (LucideIcon icon component, X[] → example item). */
462
- function buildDefaultArgsForRequiredProps(props) {
465
+ /** Recursive list of .tsx file paths under dir (relative to dir). */
466
+ function getAllTsxUnderDir(dir) {
467
+ if (!fs.existsSync(dir)) return [];
468
+ const out = [];
469
+ const entries = fs.readdirSync(dir, { withFileTypes: true });
470
+ for (const e of entries) {
471
+ const full = path.join(dir, e.name);
472
+ if (e.isDirectory()) {
473
+ out.push(...getAllTsxUnderDir(full).map((r) => path.join(e.name, r)));
474
+ } else if (e.isFile() && e.name.endsWith(".tsx")) {
475
+ out.push(e.name);
476
+ }
477
+ }
478
+ return out;
479
+ }
480
+
481
+ /** Extract prop="value" and prop='value' and prop={"value"} from JSX tag content. Returns { propName: "value", ... }. */
482
+ function extractPropsFromJsxTagContent(tagContent) {
483
+ const props = {};
484
+ let m;
485
+ const doubleQuoted = /\b(\w+)=["]([^"]*)["]/g;
486
+ while ((m = doubleQuoted.exec(tagContent)) !== null) props[m[1]] = m[2];
487
+ const singleQuoted = /\b(\w+)=[']([^']*)[']/g;
488
+ while ((m = singleQuoted.exec(tagContent)) !== null) if (props[m[1]] === undefined) props[m[1]] = m[2];
489
+ const jsxDouble = /\b(\w+)=\{"([^"]*)"\}/g;
490
+ while ((m = jsxDouble.exec(tagContent)) !== null) if (props[m[1]] === undefined) props[m[1]] = m[2];
491
+ const jsxSingle = /\b(\w+)=\{'([^']*)'\}/g;
492
+ while ((m = jsxSingle.exec(tagContent)) !== null) if (props[m[1]] === undefined) props[m[1]] = m[2];
493
+ return props;
494
+ }
495
+
496
+ /** Find first real usage of component in src/pages or src/app; return { propName: "literalValue", ... } or null. */
497
+ function findComponentUsageInPages(componentName, projectRoot) {
498
+ const srcDir = path.join(projectRoot, "src");
499
+ const pagesDir = path.join(srcDir, "pages");
500
+ const appDir = path.join(srcDir, "app");
501
+ const dirs = [];
502
+ if (fs.existsSync(pagesDir)) dirs.push(pagesDir);
503
+ if (fs.existsSync(appDir)) dirs.push(appDir);
504
+ const escapedName = componentName.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
505
+ const tagOpenRe = new RegExp(`<${escapedName}\\s+([\\s\\S]*?)\\s*\\/?>`, "m");
506
+ for (const dir of dirs) {
507
+ const files = getAllTsxUnderDir(dir);
508
+ for (const rel of files) {
509
+ const fullPath = path.join(dir, rel);
510
+ try {
511
+ const content = fs.readFileSync(fullPath, "utf-8");
512
+ const match = content.match(tagOpenRe);
513
+ if (match) {
514
+ const props = extractPropsFromJsxTagContent(match[1]);
515
+ if (Object.keys(props).length > 0) return props;
516
+ }
517
+ } catch (_) {}
518
+ }
519
+ }
520
+ return null;
521
+ }
522
+
523
+ /** Build default args lines and lucide-react imports. usageFromPages: sayfadan çıkarılan gerçek prop değerleri (yoksa fallback). */
524
+ function buildDefaultArgsForRequiredProps(props, usageFromPages = null) {
463
525
  const argLines = [];
464
526
  const lucideImports = new Set();
465
- if (!Array.isArray(props) || props.length === 0) return { argLines, lucideImports: [] };
466
- for (const p of props) {
467
- if (p.required !== true) continue;
468
- const type = String(p.type || "").trim();
469
- const name = p.name;
470
- if (/LucideIcon|lucide-react/.test(type)) {
471
- const iconName = LUCIDE_ICON_DEFAULT;
472
- lucideImports.add(iconName);
473
- argLines.push(` ${name}: ${iconName},`);
474
- } else if (/\[\]/.test(type)) {
475
- if (/string\s*\[\]/.test(type)) {
476
- argLines.push(` ${name}: ["Example"],`);
477
- } else {
478
- argLines.push(` ${name}: [],`);
527
+ const fromPages = usageFromPages && typeof usageFromPages === "object" ? usageFromPages : {};
528
+ const added = new Set();
529
+ if (Array.isArray(props) && props.length > 0) {
530
+ for (const p of props) {
531
+ if (p.required !== true) continue;
532
+ const type = String(p.type || "").trim();
533
+ const name = p.name;
534
+ if (/LucideIcon|lucide-react/.test(type)) {
535
+ const iconName = LUCIDE_ICON_DEFAULT;
536
+ lucideImports.add(iconName);
537
+ argLines.push(` ${name}: ${iconName},`);
538
+ added.add(name);
539
+ } else if (/\[\]/.test(type)) {
540
+ if (/string\s*\[\]/.test(type)) {
541
+ argLines.push(` ${name}: ["Example"],`);
542
+ } else {
543
+ argLines.push(` ${name}: [],`);
544
+ }
545
+ added.add(name);
546
+ } else if (fromPages[name] !== undefined && fromPages[name] !== null) {
547
+ argLines.push(` ${name}: ${JSON.stringify(String(fromPages[name]))},`);
548
+ added.add(name);
549
+ } else if (/string/.test(type) && DEFAULT_STRINGS_BY_PROP_NAME[name] !== undefined) {
550
+ argLines.push(` ${name}: ${JSON.stringify(DEFAULT_STRINGS_BY_PROP_NAME[name])},`);
551
+ added.add(name);
479
552
  }
480
- } else if (/string/.test(type) && DEFAULT_STRINGS_BY_PROP_NAME[name] !== undefined) {
481
- argLines.push(` ${name}: ${JSON.stringify(DEFAULT_STRINGS_BY_PROP_NAME[name])},`);
553
+ }
554
+ }
555
+ for (const name of Object.keys(fromPages)) {
556
+ if (added.has(name)) continue;
557
+ const val = fromPages[name];
558
+ if (val !== undefined && val !== null && typeof val === "string") {
559
+ argLines.push(` ${name}: ${JSON.stringify(val)},`);
482
560
  }
483
561
  }
484
562
  return { argLines, lucideImports: [...lucideImports] };
@@ -723,7 +801,8 @@ function buildStoryFileContent(comp) {
723
801
 
724
802
  // Props: manifest or parse from source for default args (LucideIcon, array types)
725
803
  const effectiveProps = Array.isArray(comp.props) && comp.props.length > 0 ? comp.props : parsePropsFromSource(source);
726
- const { argLines: defaultArgLines, lucideImports } = buildDefaultArgsForRequiredProps(effectiveProps);
804
+ const usageFromPages = findComponentUsageInPages(componentName, PROJECT_ROOT);
805
+ const { argLines: defaultArgLines, lucideImports } = buildDefaultArgsForRequiredProps(effectiveProps, usageFromPages);
727
806
  const useReactNodeChildrenRender = !omitChildren && hasChildrenPropReactNode(effectiveProps);
728
807
 
729
808
  // Skip story only if not a page and no export found