vibe-design-system 2.5.50 → 2.6.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.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "vibe-design-system",
3
- "version": "2.5.50",
3
+ "version": "2.6.0",
4
4
  "description": "Auto-generate design systems for vibe coding projects",
5
5
  "type": "module",
6
6
  "bin": {
@@ -621,7 +621,77 @@ function extractComponentSuggestions() {
621
621
  reason: `Visual section candidate: same className cluster ${count}×, ${directChildren} child elements`,
622
622
  });
623
623
  }
624
- return suggestions;
624
+
625
+ // Ek: Tekil büyük bloklar (single large blocks) — tekrar etmese bile component adayı
626
+ const LARGE_BLOCK_MIN_CHILDREN = 5; // en az 5 direkt child
627
+ const LARGE_BLOCK_MIN_CLASS_TOKENS = 4; // className’de en az 4 token
628
+ const MAX_SINGLE_BLOCKS_PER_FILE = 3; // her dosyadan en fazla 3 aday
629
+
630
+ const singleBlockCandidates = [];
631
+
632
+ for (const { fullPath, srcRel } of allPageFiles) {
633
+ let content;
634
+ try {
635
+ content = fs.readFileSync(fullPath, "utf-8");
636
+ } catch {
637
+ continue;
638
+ }
639
+ const fileCandidates = [];
640
+ const reSingle = /className\s*=\s*["']([^"']+)["']|className\s*=\s*\{\s*["']([^"']+)["']\s*\}/g;
641
+ let m;
642
+ while ((m = reSingle.exec(content)) !== null) {
643
+ const raw = (m[1] ?? m[2] ?? "").trim().replace(/\s+/g, " ").trim();
644
+ if (!raw) continue;
645
+ const classCount = raw.split(/\s+/).filter(Boolean).length;
646
+ if (classCount < LARGE_BLOCK_MIN_CLASS_TOKENS) continue;
647
+
648
+ const before = content.substring(0, m.index);
649
+ const lastOpen = before.lastIndexOf("<");
650
+ const tagMatch = lastOpen >= 0 ? content.slice(lastOpen).match(/<(\w+)/) : null;
651
+ const tagName = tagMatch ? tagMatch[1] : "div";
652
+
653
+ let fullJsx = null;
654
+ let innerContent = "";
655
+ const extracted = extractFullElement(content, m.index, tagName);
656
+ if (extracted) {
657
+ fullJsx = extracted.fullJsx;
658
+ innerContent = extracted.innerContent || "";
659
+ }
660
+ const directChildren = countDirectChildren(innerContent);
661
+ if (directChildren < LARGE_BLOCK_MIN_CHILDREN) continue;
662
+
663
+ fileCandidates.push({
664
+ tagName,
665
+ pattern: raw,
666
+ fullJsx,
667
+ innerContent,
668
+ directChildren,
669
+ srcRel,
670
+ });
671
+ }
672
+
673
+ fileCandidates
674
+ .sort((a, b) => b.directChildren - a.directChildren)
675
+ .slice(0, MAX_SINGLE_BLOCKS_PER_FILE)
676
+ .forEach((c) => {
677
+ singleBlockCandidates.push({
678
+ suggestedName: sanitizeComponentName(
679
+ (suggestNameFromContent(c.innerContent) ||
680
+ suggestNameFromPattern(c.pattern) ||
681
+ "Section").replace(/\s+/g, "")
682
+ ),
683
+ tagName: c.tagName,
684
+ pattern: c.pattern,
685
+ fullJsx: c.fullJsx,
686
+ occurrences: 1,
687
+ foundIn: [c.srcRel],
688
+ snippet: `<${c.tagName} className="${c.pattern}">...</${c.tagName}>`,
689
+ reason: `Large visual block candidate: ${c.directChildren} direct children, rich className`,
690
+ });
691
+ });
692
+ }
693
+
694
+ return suggestions.concat(singleBlockCandidates);
625
695
  }
626
696
 
627
697
  /** src/pages/ içinde tanımlı ama src/components'a çıkarılmamış visual section'ları listele (component adayı raporu). */