@tpitre/story-ui 4.5.2 → 4.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/dist/cli/index.js +5 -0
- package/dist/mcp-server/routes/generateStory.d.ts.map +1 -1
- package/dist/mcp-server/routes/generateStory.js +19 -5
- package/dist/mcp-server/routes/generateStoryStream.d.ts.map +1 -1
- package/dist/mcp-server/routes/generateStoryStream.js +19 -5
- package/dist/story-generator/promptGenerator.d.ts.map +1 -1
- package/dist/story-generator/promptGenerator.js +182 -24
- package/dist/story-generator/selfHealingLoop.d.ts.map +1 -1
- package/dist/story-generator/selfHealingLoop.js +48 -17
- package/dist/story-generator/storyTracker.d.ts +12 -0
- package/dist/story-generator/storyTracker.d.ts.map +1 -1
- package/dist/story-generator/storyTracker.js +42 -0
- package/dist/story-generator/storyValidator.d.ts.map +1 -1
- package/dist/story-generator/storyValidator.js +0 -4
- package/dist/story-generator/validateStory.d.ts.map +1 -1
- package/dist/story-generator/validateStory.js +128 -0
- package/dist/templates/StoryUI/StoryUIPanel.css +1623 -0
- package/dist/templates/StoryUI/StoryUIPanel.d.ts.map +1 -1
- package/dist/templates/StoryUI/StoryUIPanel.js +46 -69
- package/dist/templates/StoryUI/StoryUIPanel.mdx +84 -0
- package/package.json +3 -2
- package/templates/StoryUI/StoryUIPanel.css +152 -54
- package/templates/StoryUI/StoryUIPanel.tsx +51 -75
package/dist/cli/index.js
CHANGED
|
@@ -58,6 +58,11 @@ program
|
|
|
58
58
|
console.log(`⚠️ Port ${requestedPort} is in use. Using ${finalPort} instead.`);
|
|
59
59
|
}
|
|
60
60
|
const env = { ...process.env, PORT: String(finalPort) };
|
|
61
|
+
// Set memory limit to prevent heap exhaustion during vision/image processing
|
|
62
|
+
// Default to 8GB for handling large images and self-healing retry loops
|
|
63
|
+
if (!env.NODE_OPTIONS?.includes('--max-old-space-size')) {
|
|
64
|
+
env.NODE_OPTIONS = `${env.NODE_OPTIONS || ''} --max-old-space-size=8192`.trim();
|
|
65
|
+
}
|
|
61
66
|
if (options.config) {
|
|
62
67
|
env.STORY_UI_CONFIG_PATH = options.config;
|
|
63
68
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"generateStory.d.ts","sourceRoot":"","sources":["../../../mcp-server/routes/generateStory.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,OAAO,EAAE,QAAQ,EAAE,MAAM,SAAS,CAAC;AAmd5C,wBAAsB,uBAAuB,CAAC,GAAG,EAAE,OAAO,EAAE,GAAG,EAAE,QAAQ,
|
|
1
|
+
{"version":3,"file":"generateStory.d.ts","sourceRoot":"","sources":["../../../mcp-server/routes/generateStory.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,OAAO,EAAE,QAAQ,EAAE,MAAM,SAAS,CAAC;AAmd5C,wBAAsB,uBAAuB,CAAC,GAAG,EAAE,OAAO,EAAE,GAAG,EAAE,QAAQ,2DA8lBxE"}
|
|
@@ -710,10 +710,23 @@ export async function generateStoryFromPrompt(req, res) {
|
|
|
710
710
|
}
|
|
711
711
|
// Create title for the story (clean, without hash - hash goes in id for uniqueness)
|
|
712
712
|
const prettyPrompt = escapeTitleForTS(aiTitle);
|
|
713
|
-
//
|
|
714
|
-
|
|
713
|
+
// For NEW stories, check if title already exists and add version if needed
|
|
714
|
+
// This prevents multiple stories from stacking under the same navigation group
|
|
715
|
+
// e.g., "Navigation Bar" → "Navigation Bar v2" → "Navigation Bar v3"
|
|
716
|
+
let cleanTitle;
|
|
717
|
+
if (isActualUpdate) {
|
|
718
|
+
// For updates, keep the original title (don't version)
|
|
719
|
+
cleanTitle = prettyPrompt;
|
|
720
|
+
}
|
|
721
|
+
else {
|
|
722
|
+
// For new stories, check for duplicates and version if needed
|
|
723
|
+
cleanTitle = storyTracker.getNextVersionTitle(prettyPrompt);
|
|
724
|
+
if (cleanTitle !== prettyPrompt) {
|
|
725
|
+
logger.log(`📋 Title "${prettyPrompt}" already exists, using "${cleanTitle}" instead`);
|
|
726
|
+
}
|
|
727
|
+
}
|
|
715
728
|
// Generate Storybook-compatible ID with hash for uniqueness (prevents duplicate story errors)
|
|
716
|
-
const storyIdSlug = `${
|
|
729
|
+
const storyIdSlug = `${cleanTitle.toLowerCase().replace(/[^a-z0-9]+/g, '-').replace(/^-|-$/g, '')}-${hash}`;
|
|
717
730
|
// Fix title with storyPrefix - handle multiple story formats
|
|
718
731
|
// Note: (?::\s*\w+(?:<[^>]+>)?)? handles TypeScript type annotations including generics
|
|
719
732
|
// e.g., "const meta: Meta = {" or "const meta: Meta<typeof Button> = {"
|
|
@@ -793,8 +806,9 @@ export async function generateStoryFromPrompt(req, res) {
|
|
|
793
806
|
config: config
|
|
794
807
|
});
|
|
795
808
|
// Register with story tracker
|
|
809
|
+
// Use cleanTitle (which may include version suffix) for proper deduplication tracking
|
|
796
810
|
const mapping = {
|
|
797
|
-
title:
|
|
811
|
+
title: cleanTitle,
|
|
798
812
|
fileName: finalFileName,
|
|
799
813
|
storyId,
|
|
800
814
|
hash,
|
|
@@ -855,7 +869,7 @@ export async function generateStoryFromPrompt(req, res) {
|
|
|
855
869
|
fileName: finalFileName,
|
|
856
870
|
storyId,
|
|
857
871
|
outPath,
|
|
858
|
-
title:
|
|
872
|
+
title: cleanTitle, // Use versioned title (e.g., "Navigation Bar v2")
|
|
859
873
|
story: fileContents,
|
|
860
874
|
storage: 'file-system',
|
|
861
875
|
isUpdate: isActualUpdate,
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"generateStoryStream.d.ts","sourceRoot":"","sources":["../../../mcp-server/routes/generateStoryStream.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AAEH,OAAO,EAAE,OAAO,EAAE,QAAQ,EAAE,MAAM,SAAS,CAAC;AA0c5C,wBAAsB,6BAA6B,CAAC,GAAG,EAAE,OAAO,EAAE,GAAG,EAAE,QAAQ,
|
|
1
|
+
{"version":3,"file":"generateStoryStream.d.ts","sourceRoot":"","sources":["../../../mcp-server/routes/generateStoryStream.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AAEH,OAAO,EAAE,OAAO,EAAE,QAAQ,EAAE,MAAM,SAAS,CAAC;AA0c5C,wBAAsB,6BAA6B,CAAC,GAAG,EAAE,OAAO,EAAE,GAAG,EAAE,QAAQ,iBA2qB9E"}
|
|
@@ -816,10 +816,23 @@ export async function generateStoryFromPromptStream(req, res) {
|
|
|
816
816
|
}
|
|
817
817
|
// Create title for the story (clean, without hash - hash goes in id for uniqueness)
|
|
818
818
|
const prettyPrompt = escapeTitleForTS(aiTitle);
|
|
819
|
-
//
|
|
820
|
-
|
|
819
|
+
// For NEW stories, check if title already exists and add version if needed
|
|
820
|
+
// This prevents multiple stories from stacking under the same navigation group
|
|
821
|
+
// e.g., "Navigation Bar" → "Navigation Bar v2" → "Navigation Bar v3"
|
|
822
|
+
let cleanTitle;
|
|
823
|
+
if (isActualUpdate) {
|
|
824
|
+
// For updates, keep the original title (don't version)
|
|
825
|
+
cleanTitle = prettyPrompt;
|
|
826
|
+
}
|
|
827
|
+
else {
|
|
828
|
+
// For new stories, check for duplicates and version if needed
|
|
829
|
+
cleanTitle = storyTracker.getNextVersionTitle(prettyPrompt);
|
|
830
|
+
if (cleanTitle !== prettyPrompt) {
|
|
831
|
+
logger.log(`📋 Title "${prettyPrompt}" already exists, using "${cleanTitle}" instead`);
|
|
832
|
+
}
|
|
833
|
+
}
|
|
821
834
|
// Generate Storybook-compatible ID with hash for uniqueness (prevents duplicate story errors)
|
|
822
|
-
const storyIdSlug = `${
|
|
835
|
+
const storyIdSlug = `${cleanTitle.toLowerCase().replace(/[^a-z0-9]+/g, '-').replace(/^-|-$/g, '')}-${hash}`;
|
|
823
836
|
// Fix title with storyPrefix - handle multiple story formats
|
|
824
837
|
// Note: (?::\s*\w+(?:<[^>]+>)?)? handles TypeScript type annotations including generics
|
|
825
838
|
// e.g., "const meta: Meta = {" or "const meta: Meta<typeof Button> = {"
|
|
@@ -873,8 +886,9 @@ export async function generateStoryFromPromptStream(req, res) {
|
|
|
873
886
|
config: config
|
|
874
887
|
});
|
|
875
888
|
// Register with story tracker
|
|
889
|
+
// Use cleanTitle (which may include version suffix) for proper deduplication tracking
|
|
876
890
|
const mapping = {
|
|
877
|
-
title:
|
|
891
|
+
title: cleanTitle,
|
|
878
892
|
fileName: finalFileName,
|
|
879
893
|
storyId,
|
|
880
894
|
hash,
|
|
@@ -902,7 +916,7 @@ export async function generateStoryFromPromptStream(req, res) {
|
|
|
902
916
|
// IMPORTANT: success is FALSE when we had to create a fallback error story
|
|
903
917
|
stream.sendCompletion({
|
|
904
918
|
success: !isFallbackStory,
|
|
905
|
-
title:
|
|
919
|
+
title: cleanTitle, // Use versioned title (e.g., "Navigation Bar v2")
|
|
906
920
|
fileName: finalFileName,
|
|
907
921
|
storyId,
|
|
908
922
|
summary: {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"promptGenerator.d.ts","sourceRoot":"","sources":["../../story-generator/promptGenerator.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,aAAa,EAAE,MAAM,uBAAuB,CAAC;AACtD,OAAO,EAAE,mBAAmB,EAAE,MAAM,yBAAyB,CAAC;AAI9D,OAAO,EAEL,eAAe,EACf,sBAAsB,EACtB,aAAa,EACb,gBAAgB,EACjB,MAAM,+BAA+B,CAAC;
|
|
1
|
+
{"version":3,"file":"promptGenerator.d.ts","sourceRoot":"","sources":["../../story-generator/promptGenerator.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,aAAa,EAAE,MAAM,uBAAuB,CAAC;AACtD,OAAO,EAAE,mBAAmB,EAAE,MAAM,yBAAyB,CAAC;AAI9D,OAAO,EAEL,eAAe,EACf,sBAAsB,EACtB,aAAa,EACb,gBAAgB,EACjB,MAAM,+BAA+B,CAAC;AAyOvC;;;GAGG;AACH,MAAM,WAAW,oBAAqB,SAAQ,IAAI,CAAC,eAAe,EAAE,oBAAoB,CAAC;IACvF,kBAAkB,EAAE,MAAM,EAAE,CAAC;CAC9B;AAED,MAAM,WAAW,eAAe;IAC9B,YAAY,EAAE,MAAM,CAAC;IACrB,kBAAkB,EAAE,MAAM,CAAC;IAC3B,kBAAkB,EAAE,MAAM,EAAE,CAAC;IAC7B,QAAQ,EAAE,MAAM,EAAE,CAAC;IACnB,WAAW,EAAE,MAAM,CAAC;CACrB;AAED;;GAEG;AACH,wBAAgB,cAAc,CAAC,MAAM,EAAE,aAAa,EAAE,UAAU,EAAE,mBAAmB,EAAE,GAAG,eAAe,CAcxG;AA2hBD;;GAEG;AACH,wBAAsB,iBAAiB,CACrC,UAAU,EAAE,MAAM,EAClB,MAAM,EAAE,aAAa,EACrB,UAAU,EAAE,mBAAmB,EAAE,GAChC,OAAO,CAAC,MAAM,CAAC,CA8JjB;AAED;;;GAGG;AACH,wBAAsB,4BAA4B,CAChD,MAAM,EAAE,aAAa,EACrB,UAAU,EAAE,mBAAmB,EAAE,EACjC,OAAO,CAAC,EAAE,sBAAsB,GAC/B,OAAO,CAAC,oBAAoB,CAAC,CAqB/B;AAED;;;GAGG;AACH,wBAAsB,yBAAyB,CAC7C,UAAU,EAAE,MAAM,EAClB,MAAM,EAAE,aAAa,EACrB,UAAU,EAAE,mBAAmB,EAAE,EACjC,OAAO,CAAC,EAAE,sBAAsB,GAC/B,OAAO,CAAC,MAAM,CAAC,CAiHjB;AA4ED;;GAEG;AACH,wBAAsB,sBAAsB,CAAC,WAAW,CAAC,EAAE,MAAM,GAAG,OAAO,CAAC,aAAa,CAAC,CAIzF;AAED;;GAEG;AACH,wBAAgB,mBAAmB,CAAC,SAAS,EAAE,aAAa,GAAG,gBAAgB,CAG9E;AAED;;GAEG;AACH,wBAAgB,sBAAsB,IAAI,aAAa,EAAE,CAGxD"}
|
|
@@ -1,6 +1,165 @@
|
|
|
1
1
|
import { loadConsiderations, considerationsToPrompt } from './considerationsLoader.js';
|
|
2
2
|
import { DocumentationLoader } from './documentationLoader.js';
|
|
3
3
|
import { getAdapterRegistry, } from './framework-adapters/index.js';
|
|
4
|
+
import * as fs from 'fs';
|
|
5
|
+
import * as path from 'path';
|
|
6
|
+
/**
|
|
7
|
+
* Known icon packages and their common icons
|
|
8
|
+
* Used for smart detection when icon packages are installed
|
|
9
|
+
*/
|
|
10
|
+
const KNOWN_ICON_PACKAGES = [
|
|
11
|
+
{
|
|
12
|
+
name: '@tabler/icons-react',
|
|
13
|
+
importPath: '@tabler/icons-react',
|
|
14
|
+
commonIcons: [
|
|
15
|
+
'IconHome', 'IconSettings', 'IconUser', 'IconSearch', 'IconMenu2',
|
|
16
|
+
'IconBell', 'IconMail', 'IconCalendar', 'IconClock', 'IconStar',
|
|
17
|
+
'IconHeart', 'IconPlus', 'IconMinus', 'IconX', 'IconCheck',
|
|
18
|
+
'IconChevronRight', 'IconChevronLeft', 'IconChevronDown', 'IconChevronUp',
|
|
19
|
+
'IconArrowRight', 'IconArrowLeft', 'IconArrowUp', 'IconArrowDown',
|
|
20
|
+
'IconEdit', 'IconTrash', 'IconDownload', 'IconUpload', 'IconShare',
|
|
21
|
+
'IconFilter', 'IconSort', 'IconRefresh', 'IconEye', 'IconEyeOff',
|
|
22
|
+
'IconLock', 'IconUnlock', 'IconCopy', 'IconClipboard', 'IconFolder',
|
|
23
|
+
'IconFile', 'IconImage', 'IconVideo', 'IconMusic', 'IconLink',
|
|
24
|
+
'IconExternalLink', 'IconDots', 'IconDotsVertical', 'IconGripVertical',
|
|
25
|
+
'IconSun', 'IconMoon', 'IconCloud', 'IconBolt', 'IconDroplet',
|
|
26
|
+
'IconMapPin', 'IconPhone', 'IconMessage', 'IconSend', 'IconInbox',
|
|
27
|
+
'IconArchive', 'IconTag', 'IconBookmark', 'IconFlag', 'IconAward',
|
|
28
|
+
'IconTrendingUp', 'IconTrendingDown', 'IconActivity', 'IconPieChart',
|
|
29
|
+
'IconBarChart', 'IconLineChart', 'IconDatabase', 'IconServer', 'IconCode',
|
|
30
|
+
'IconTerminal', 'IconBrandGithub', 'IconBrandTwitter', 'IconBrandLinkedin',
|
|
31
|
+
'IconWorld', 'IconGlobe', 'IconWifi', 'IconBluetooth', 'IconCpu',
|
|
32
|
+
'IconDeviceDesktop', 'IconDeviceMobile', 'IconPrinter', 'IconCamera',
|
|
33
|
+
'IconMicrophone', 'IconVolume', 'IconPlayerPlay', 'IconPlayerPause',
|
|
34
|
+
],
|
|
35
|
+
importStyle: 'named',
|
|
36
|
+
description: 'Tabler Icons - Free and open source icons (Mantine recommended)',
|
|
37
|
+
},
|
|
38
|
+
{
|
|
39
|
+
name: 'lucide-react',
|
|
40
|
+
importPath: 'lucide-react',
|
|
41
|
+
commonIcons: [
|
|
42
|
+
'Home', 'Settings', 'User', 'Search', 'Menu',
|
|
43
|
+
'Bell', 'Mail', 'Calendar', 'Clock', 'Star',
|
|
44
|
+
'Heart', 'Plus', 'Minus', 'X', 'Check',
|
|
45
|
+
'ChevronRight', 'ChevronLeft', 'ChevronDown', 'ChevronUp',
|
|
46
|
+
'ArrowRight', 'ArrowLeft', 'ArrowUp', 'ArrowDown',
|
|
47
|
+
'Edit', 'Trash', 'Download', 'Upload', 'Share',
|
|
48
|
+
'Filter', 'RefreshCw', 'Eye', 'EyeOff',
|
|
49
|
+
'Lock', 'Unlock', 'Copy', 'Clipboard', 'Folder',
|
|
50
|
+
'File', 'Image', 'Video', 'Music', 'Link',
|
|
51
|
+
'ExternalLink', 'MoreHorizontal', 'MoreVertical', 'GripVertical',
|
|
52
|
+
'Sun', 'Moon', 'Cloud', 'Zap', 'Droplet',
|
|
53
|
+
'MapPin', 'Phone', 'MessageSquare', 'Send', 'Inbox',
|
|
54
|
+
],
|
|
55
|
+
importStyle: 'named',
|
|
56
|
+
description: 'Lucide Icons - Beautiful & consistent icons',
|
|
57
|
+
},
|
|
58
|
+
{
|
|
59
|
+
name: '@heroicons/react',
|
|
60
|
+
importPath: '@heroicons/react/24/outline',
|
|
61
|
+
commonIcons: [
|
|
62
|
+
'HomeIcon', 'Cog6ToothIcon', 'UserIcon', 'MagnifyingGlassIcon', 'Bars3Icon',
|
|
63
|
+
'BellIcon', 'EnvelopeIcon', 'CalendarIcon', 'ClockIcon', 'StarIcon',
|
|
64
|
+
'HeartIcon', 'PlusIcon', 'MinusIcon', 'XMarkIcon', 'CheckIcon',
|
|
65
|
+
'ChevronRightIcon', 'ChevronLeftIcon', 'ChevronDownIcon', 'ChevronUpIcon',
|
|
66
|
+
'ArrowRightIcon', 'ArrowLeftIcon', 'ArrowUpIcon', 'ArrowDownIcon',
|
|
67
|
+
'PencilIcon', 'TrashIcon', 'ArrowDownTrayIcon', 'ArrowUpTrayIcon', 'ShareIcon',
|
|
68
|
+
'FunnelIcon', 'ArrowPathIcon', 'EyeIcon', 'EyeSlashIcon',
|
|
69
|
+
'LockClosedIcon', 'LockOpenIcon', 'ClipboardIcon', 'FolderIcon',
|
|
70
|
+
'DocumentIcon', 'PhotoIcon', 'VideoCameraIcon', 'MusicalNoteIcon', 'LinkIcon',
|
|
71
|
+
],
|
|
72
|
+
importStyle: 'named',
|
|
73
|
+
description: 'Heroicons - Beautiful hand-crafted SVG icons by Tailwind',
|
|
74
|
+
},
|
|
75
|
+
{
|
|
76
|
+
name: 'react-icons',
|
|
77
|
+
importPath: 'react-icons/fi', // Feather icons subset - most common
|
|
78
|
+
commonIcons: [
|
|
79
|
+
'FiHome', 'FiSettings', 'FiUser', 'FiSearch', 'FiMenu',
|
|
80
|
+
'FiBell', 'FiMail', 'FiCalendar', 'FiClock', 'FiStar',
|
|
81
|
+
'FiHeart', 'FiPlus', 'FiMinus', 'FiX', 'FiCheck',
|
|
82
|
+
'FiChevronRight', 'FiChevronLeft', 'FiChevronDown', 'FiChevronUp',
|
|
83
|
+
'FiArrowRight', 'FiArrowLeft', 'FiArrowUp', 'FiArrowDown',
|
|
84
|
+
'FiEdit', 'FiTrash', 'FiDownload', 'FiUpload', 'FiShare',
|
|
85
|
+
'FiFilter', 'FiRefreshCw', 'FiEye', 'FiEyeOff',
|
|
86
|
+
],
|
|
87
|
+
importStyle: 'named',
|
|
88
|
+
description: 'React Icons - Popular icon packs as React components',
|
|
89
|
+
},
|
|
90
|
+
{
|
|
91
|
+
name: '@phosphor-icons/react',
|
|
92
|
+
importPath: '@phosphor-icons/react',
|
|
93
|
+
commonIcons: [
|
|
94
|
+
'House', 'Gear', 'User', 'MagnifyingGlass', 'List',
|
|
95
|
+
'Bell', 'Envelope', 'Calendar', 'Clock', 'Star',
|
|
96
|
+
'Heart', 'Plus', 'Minus', 'X', 'Check',
|
|
97
|
+
'CaretRight', 'CaretLeft', 'CaretDown', 'CaretUp',
|
|
98
|
+
'ArrowRight', 'ArrowLeft', 'ArrowUp', 'ArrowDown',
|
|
99
|
+
'PencilSimple', 'Trash', 'DownloadSimple', 'UploadSimple', 'ShareNetwork',
|
|
100
|
+
'Funnel', 'ArrowsClockwise', 'Eye', 'EyeSlash',
|
|
101
|
+
],
|
|
102
|
+
importStyle: 'named',
|
|
103
|
+
description: 'Phosphor Icons - Flexible icon family',
|
|
104
|
+
},
|
|
105
|
+
];
|
|
106
|
+
/**
|
|
107
|
+
* Detects installed icon packages by checking package.json
|
|
108
|
+
* Returns the first detected icon package info, or null if none found
|
|
109
|
+
*/
|
|
110
|
+
function detectInstalledIconPackage(projectPath) {
|
|
111
|
+
const cwd = projectPath || process.cwd();
|
|
112
|
+
const packageJsonPath = path.join(cwd, 'package.json');
|
|
113
|
+
try {
|
|
114
|
+
if (!fs.existsSync(packageJsonPath)) {
|
|
115
|
+
return null;
|
|
116
|
+
}
|
|
117
|
+
const packageJson = JSON.parse(fs.readFileSync(packageJsonPath, 'utf-8'));
|
|
118
|
+
const allDeps = {
|
|
119
|
+
...packageJson.dependencies,
|
|
120
|
+
...packageJson.devDependencies,
|
|
121
|
+
};
|
|
122
|
+
// Check each known icon package
|
|
123
|
+
for (const iconPackage of KNOWN_ICON_PACKAGES) {
|
|
124
|
+
if (allDeps[iconPackage.name]) {
|
|
125
|
+
return iconPackage;
|
|
126
|
+
}
|
|
127
|
+
}
|
|
128
|
+
return null;
|
|
129
|
+
}
|
|
130
|
+
catch (error) {
|
|
131
|
+
// If we can't read package.json, assume no icon package
|
|
132
|
+
return null;
|
|
133
|
+
}
|
|
134
|
+
}
|
|
135
|
+
/**
|
|
136
|
+
* Generates icon usage instructions for the prompt
|
|
137
|
+
* Uses smart detection to enable real icons when a supported icon package is installed
|
|
138
|
+
*/
|
|
139
|
+
function generateIconInstructions(components, projectPath) {
|
|
140
|
+
const instructions = [];
|
|
141
|
+
// First, check if an icon package is installed in the project
|
|
142
|
+
const installedIconPackage = detectInstalledIconPackage(projectPath);
|
|
143
|
+
if (installedIconPackage) {
|
|
144
|
+
// Icon package detected - enable icon usage with the installed package
|
|
145
|
+
const sampleIcons = installedIconPackage.commonIcons.slice(0, 20).join(', ');
|
|
146
|
+
instructions.push('', '✅ ICON LIBRARY AVAILABLE ✅', `You have ${installedIconPackage.name} installed in this project.`, `${installedIconPackage.description}`, '', '📦 How to use icons:', ` Import path: import { IconName } from '${installedIconPackage.importPath}';`, ` Example icons: ${sampleIcons}`, '', '🎯 ICON BEST PRACTICES:', ' - Use icons to enhance visual clarity and user experience', ' - Common use cases: navigation, actions, status indicators, decorative elements', ' - Icons should complement text, not replace it entirely for accessibility', ' - Use consistent icon sizing (typically 16-24px for inline, 24-48px for prominent)', '', '⚠️ IMPORTANT:', ` - ONLY import icons from '${installedIconPackage.importPath}'`, ' - Do NOT import from other icon libraries not installed in the project', ' - If you need an icon that may not exist, use a similar common icon from the list above', '');
|
|
147
|
+
return instructions;
|
|
148
|
+
}
|
|
149
|
+
// No icon package installed - check if design system has icon components
|
|
150
|
+
const iconComponents = components.filter(c => c.name && typeof c.name === 'string' &&
|
|
151
|
+
(c.name.toLowerCase().includes('icon') || c.name === 'Icon' || c.name === 'v-icon' || c.name === 'mat-icon' || c.name === 'sl-icon'));
|
|
152
|
+
if (iconComponents.length > 0) {
|
|
153
|
+
// Design system has icon support - allow those, prohibit external libraries
|
|
154
|
+
const allowedIconNames = iconComponents.map(c => c.name).join(', ');
|
|
155
|
+
instructions.push('', '🔶 ICON USAGE RULES 🔶', `Your design system includes icon components: ${allowedIconNames}`, '✅ You MAY use these icon components from the Available components list', '🚫 Do NOT import from external icon libraries:', ' - @tabler/icons-react, @tabler/icons', ' - react-icons, lucide-react, @heroicons/react', ' - @fortawesome/react-fontawesome, @phosphor-icons/react', ' - Any other external icon package', 'If you need icons beyond what the design system provides, use Unicode symbols (→ ✓ + ×) or text labels instead.', '');
|
|
156
|
+
}
|
|
157
|
+
else {
|
|
158
|
+
// No icon components discovered - prohibit all icon imports
|
|
159
|
+
instructions.push('', '🔴 ICON IMPORT RESTRICTION 🔴', 'This design system does not include icon components in the available components list.', '🚫 Do NOT import from ANY icon library:', ' - @tabler/icons-react, @tabler/icons', ' - react-icons, lucide-react, @heroicons/react', ' - @fortawesome/react-fontawesome, @phosphor-icons/react', ' - @mui/icons-material, @chakra-ui/icons', ' - Any other icon package', '✅ Instead, use:', ' - Unicode symbols: → ✓ ✗ + − × ÷ • ★ ♦ ▶ ◀ ▲ ▼', ' - Text labels: "Add", "Remove", "Edit", "Delete"', ' - Badge or Button components with text content', 'Icons are NOT in the available components list and WILL cause import errors.', '');
|
|
160
|
+
}
|
|
161
|
+
return instructions;
|
|
162
|
+
}
|
|
4
163
|
/**
|
|
5
164
|
* Generates a comprehensive AI prompt based on the configuration and discovered components
|
|
6
165
|
*/
|
|
@@ -177,6 +336,23 @@ ANY component not in that list DOES NOT EXIST and will cause import errors.
|
|
|
177
336
|
Before importing any component, verify it exists in the Available components list.
|
|
178
337
|
If a component is not listed, DO NOT use it - choose an alternative from the available list.
|
|
179
338
|
|
|
339
|
+
🎨 CREATIVE APPROXIMATION - WHEN COMPONENTS DON'T EXIST 🎨
|
|
340
|
+
If the user asks for a UI that requires components NOT in your available list (like Calendar, Chart, Map, etc.):
|
|
341
|
+
**DO NOT fail or refuse** - instead, CREATIVELY APPROXIMATE the UI using available components!
|
|
342
|
+
|
|
343
|
+
Common approximation strategies:
|
|
344
|
+
• Calendar/DatePicker → Use Grid/SimpleGrid with Text for days, Badge for selected dates
|
|
345
|
+
• Charts/Graphs → Use Progress bars, RingProgress, or Stack of colored Box components
|
|
346
|
+
• Timeline → Use Stack with Card/Paper for each event, connecting lines with Divider
|
|
347
|
+
• Carousel/Slider → Use Group with Image components and Button for navigation
|
|
348
|
+
• Data Tables → Use Table components, or Stack of Card/Paper rows
|
|
349
|
+
• Tree View → Use nested Stack/Accordion with List or NavLink components
|
|
350
|
+
• Star Ratings → Use Group of ThemeIcon or inline SVG stars
|
|
351
|
+
• Maps → Use Image with a static map placeholder
|
|
352
|
+
|
|
353
|
+
The goal is VISUAL SIMILARITY, not exact functionality. Users are exploring design possibilities.
|
|
354
|
+
They want to see what a UI COULD look like - be creative with basic layout components!
|
|
355
|
+
|
|
180
356
|
🔴 IMPORT PATH RULE - MANDATORY 🔴
|
|
181
357
|
ALWAYS use the EXACT import path shown in parentheses after each component name.
|
|
182
358
|
For example: If the Available components list shows "Button (import from 'antd')",
|
|
@@ -562,18 +738,9 @@ export async function buildClaudePrompt(userPrompt, config, components) {
|
|
|
562
738
|
});
|
|
563
739
|
});
|
|
564
740
|
}
|
|
565
|
-
// Smart icon handling -
|
|
566
|
-
const
|
|
567
|
-
|
|
568
|
-
if (iconComponents.length > 0) {
|
|
569
|
-
// Design system has icon support - allow those, prohibit external libraries
|
|
570
|
-
const allowedIconNames = iconComponents.map(c => c.name).join(', ');
|
|
571
|
-
promptParts.push('', '🔶 ICON USAGE RULES 🔶', `Your design system includes icon components: ${allowedIconNames}`, '✅ You MAY use these icon components from the Available components list', '🚫 Do NOT import from external icon libraries:', ' - @tabler/icons-react, @tabler/icons', ' - react-icons, lucide-react, @heroicons/react', ' - @fortawesome/react-fontawesome, @phosphor-icons/react', ' - Any other external icon package', 'If you need icons beyond what the design system provides, use Unicode symbols (→ ✓ + ×) or text labels instead.', '');
|
|
572
|
-
}
|
|
573
|
-
else {
|
|
574
|
-
// No icon components discovered - prohibit all icon imports
|
|
575
|
-
promptParts.push('', '🔴 ICON IMPORT RESTRICTION 🔴', 'This design system does not include icon components in the available components list.', '🚫 Do NOT import from ANY icon library:', ' - @tabler/icons-react, @tabler/icons', ' - react-icons, lucide-react, @heroicons/react', ' - @fortawesome/react-fontawesome, @phosphor-icons/react', ' - @mui/icons-material, @chakra-ui/icons', ' - Any other icon package', '✅ Instead, use:', ' - Unicode symbols: → ✓ ✗ + − × ÷ • ★ ♦ ▶ ◀ ▲ ▼', ' - Text labels: "Add", "Remove", "Edit", "Delete"', ' - Badge or Button components with text content', 'Icons are NOT in the available components list and WILL cause import errors.', '');
|
|
576
|
-
}
|
|
741
|
+
// Smart icon handling - detect installed icon packages or fall back to design system icons
|
|
742
|
+
const iconInstructions = generateIconInstructions(components);
|
|
743
|
+
promptParts.push(...iconInstructions);
|
|
577
744
|
// Reinforce NO children in args rule
|
|
578
745
|
promptParts.push('', '🔴 CRITICAL REMINDER: NEVER use children in args 🔴', 'Always use render functions for any layout or component composition.', '');
|
|
579
746
|
// Determine framework from config for rules section
|
|
@@ -698,18 +865,9 @@ export async function buildFrameworkAwarePrompt(userPrompt, config, components,
|
|
|
698
865
|
});
|
|
699
866
|
});
|
|
700
867
|
}
|
|
701
|
-
// Smart icon handling -
|
|
702
|
-
const
|
|
703
|
-
|
|
704
|
-
if (iconComponents.length > 0) {
|
|
705
|
-
// Design system has icon support - allow those, prohibit external libraries
|
|
706
|
-
const allowedIconNames = iconComponents.map(c => c.name).join(', ');
|
|
707
|
-
promptParts.push('', '🔶 ICON USAGE RULES 🔶', `Your design system includes icon components: ${allowedIconNames}`, '✅ You MAY use these icon components from the Available components list', '🚫 Do NOT import from external icon libraries:', ' - @tabler/icons-react, @tabler/icons', ' - react-icons, lucide-react, @heroicons/react', ' - @fortawesome/react-fontawesome, @phosphor-icons/react', ' - Any other external icon package', 'If you need icons beyond what the design system provides, use Unicode symbols (→ ✓ + ×) or text labels instead.', '');
|
|
708
|
-
}
|
|
709
|
-
else {
|
|
710
|
-
// No icon components discovered - prohibit all icon imports
|
|
711
|
-
promptParts.push('', '🔴 ICON IMPORT RESTRICTION 🔴', 'This design system does not include icon components in the available components list.', '🚫 Do NOT import from ANY icon library:', ' - @tabler/icons-react, @tabler/icons', ' - react-icons, lucide-react, @heroicons/react', ' - @fortawesome/react-fontawesome, @phosphor-icons/react', ' - @mui/icons-material, @chakra-ui/icons', ' - Any other icon package', '✅ Instead, use:', ' - Unicode symbols: → ✓ ✗ + − × ÷ • ★ ♦ ▶ ◀ ▲ ▼', ' - Text labels: "Add", "Remove", "Edit", "Delete"', ' - Badge or Button components with text content', 'Icons are NOT in the available components list and WILL cause import errors.', '');
|
|
712
|
-
}
|
|
868
|
+
// Smart icon handling - detect installed icon packages or fall back to design system icons
|
|
869
|
+
const iconInstructions2 = generateIconInstructions(components);
|
|
870
|
+
promptParts.push(...iconInstructions2);
|
|
713
871
|
// Add framework-specific rules
|
|
714
872
|
const frameworkType = generated.framework.componentFramework;
|
|
715
873
|
const frameworkRules = getFrameworkSpecificRules(frameworkType);
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"selfHealingLoop.d.ts","sourceRoot":"","sources":["../../story-generator/selfHealingLoop.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AAEH,OAAO,EAAE,gBAAgB,EAAE,MAAM,oBAAoB,CAAC;AACtD,OAAO,EAAE,eAAe,EAAE,MAAM,qBAAqB,CAAC;AAEtD;;GAEG;AACH,MAAM,WAAW,gBAAgB;IAC/B,mCAAmC;IACnC,YAAY,EAAE,MAAM,EAAE,CAAC;IACvB,wDAAwD;IACxD,aAAa,EAAE,MAAM,EAAE,CAAC;IACxB,sCAAsC;IACtC,YAAY,EAAE,MAAM,EAAE,CAAC;CACxB;AAED;;GAEG;AACH,MAAM,WAAW,kBAAkB;IACjC,6BAA6B;IAC7B,WAAW,EAAE,MAAM,CAAC;IACpB,uDAAuD;IACvD,mBAAmB,EAAE,MAAM,EAAE,CAAC;IAC9B,uDAAuD;IACvD,SAAS,EAAE,MAAM,CAAC;IAClB,4CAA4C;IAC5C,UAAU,EAAE,MAAM,CAAC;CACpB;AAED;;GAEG;AACH,MAAM,WAAW,iBAAiB;IAChC,+CAA+C;IAC/C,OAAO,EAAE,OAAO,CAAC;IACjB,8CAA8C;IAC9C,IAAI,EAAE,MAAM,CAAC;IACb,8BAA8B;IAC9B,QAAQ,EAAE,MAAM,CAAC;IACjB,0CAA0C;IAC1C,YAAY,EAAE,gBAAgB,EAAE,CAAC;IACjC,sCAAsC;IACtC,WAAW,EAAE,gBAAgB,CAAC;IAC9B,6CAA6C;IAC7C,eAAe,EAAE,OAAO,CAAC;CAC1B;AAED;;GAEG;AACH,MAAM,WAAW,iBAAiB;IAChC,QAAQ,EAAE,MAAM,CAAC;IACjB,eAAe,EAAE,OAAO,CAAC;IACzB,iBAAiB,EAAE,KAAK,CAAC;QACvB,OAAO,EAAE,MAAM,CAAC;QAChB,YAAY,EAAE,MAAM,CAAC;QACrB,aAAa,EAAE,MAAM,CAAC;QACtB,YAAY,EAAE,MAAM,CAAC;QACrB,cAAc,EAAE,OAAO,CAAC;KACzB,CAAC,CAAC;CACJ;AAED;;GAEG;AACH,wBAAgB,WAAW,CAAC,MAAM,EAAE,gBAAgB,GAAG,OAAO,CAM7D;AAED;;GAEG;AACH,wBAAgB,kBAAkB,CAAC,MAAM,EAAE,gBAAgB,GAAG,MAAM,CAMnE;AAED;;GAEG;AACH,wBAAgB,iBAAiB,IAAI,gBAAgB,CAMpD;AAED;;GAEG;AACH,wBAAgB,yBAAyB,CACvC,SAAS,EAAE,gBAAgB,GAAG,IAAI,EAClC,aAAa,EAAE,eAAe,EAAE,GAAG,IAAI,EACvC,YAAY,EAAE,MAAM,EAAE,GAAG,IAAI,GAC5B,gBAAgB,CAqBlB;AAED;;GAEG;AACH,wBAAgB,sBAAsB,CACpC,QAAQ,EAAE,MAAM,EAChB,WAAW,EAAE,MAAM,EACnB,YAAY,EAAE,gBAAgB,EAAE,GAC/B;IAAE,WAAW,EAAE,OAAO,CAAC;IAAC,MAAM,EAAE,MAAM,CAAA;CAAE,CA2C1C;AAuED;;;;GAIG;AACH,wBAAgB,sBAAsB,CACpC,YAAY,EAAE,MAAM,EACpB,MAAM,EAAE,gBAAgB,EACxB,OAAO,EAAE,MAAM,EACf,OAAO,EAAE,kBAAkB,GAC1B,MAAM,
|
|
1
|
+
{"version":3,"file":"selfHealingLoop.d.ts","sourceRoot":"","sources":["../../story-generator/selfHealingLoop.ts"],"names":[],"mappings":"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"}
|
|
@@ -196,19 +196,47 @@ export function buildSelfHealingPrompt(originalCode, errors, attempt, options) {
|
|
|
196
196
|
errors.patternErrors.forEach((e) => sections.push(`- ${e}`));
|
|
197
197
|
sections.push('');
|
|
198
198
|
}
|
|
199
|
-
// Import errors section
|
|
199
|
+
// Import errors section - with approximation guidance
|
|
200
200
|
if (errors.importErrors.length > 0) {
|
|
201
|
-
sections.push('### Import Errors');
|
|
202
|
-
sections.push(
|
|
201
|
+
sections.push('### Import Errors - MUST USE AVAILABLE COMPONENTS');
|
|
202
|
+
sections.push('');
|
|
203
|
+
sections.push('🚨 **CRITICAL: DO NOT try to import these components again - they DO NOT EXIST:**');
|
|
203
204
|
errors.importErrors.forEach((e) => sections.push(`- ${e}`));
|
|
204
205
|
sections.push('');
|
|
206
|
+
sections.push('### HOW TO FIX: Approximate the UI with Available Components');
|
|
207
|
+
sections.push('');
|
|
208
|
+
sections.push('You MUST recreate the same visual appearance using ONLY the available components listed below.');
|
|
209
|
+
sections.push('Think creatively - almost any UI can be approximated with basic layout and display components.');
|
|
210
|
+
sections.push('');
|
|
211
|
+
sections.push('**Common approximation strategies:**');
|
|
212
|
+
sections.push('- **Calendar/DatePicker** → Use Grid/SimpleGrid with Text components to create a calendar-like grid layout');
|
|
213
|
+
sections.push('- **Chart/Graph** → Use Progress, RingProgress, or Stack with colored Box components');
|
|
214
|
+
sections.push('- **Timeline** → Use Stack/Timeline with Card or Paper components for each event');
|
|
215
|
+
sections.push('- **Carousel/Slider** → Use Grid or Group with Image and navigation Button components');
|
|
216
|
+
sections.push('- **DataTable** → Use Table components or Stack of Card/Paper rows');
|
|
217
|
+
sections.push('- **TreeView** → Use nested Stack/Accordion with NavLink or List components');
|
|
218
|
+
sections.push('- **Rating/Stars** → Use Group of ActionIcon or ThemeIcon components');
|
|
219
|
+
sections.push('- **Map** → Use Image with a placeholder map image and overlaid markers using Box');
|
|
220
|
+
sections.push('');
|
|
221
|
+
sections.push('**The goal is visual similarity, not exact functionality.**');
|
|
222
|
+
sections.push('Users want to see what a UI could look like - use basic components creatively!');
|
|
223
|
+
sections.push('');
|
|
205
224
|
// Show available components (design-system agnostic)
|
|
206
225
|
if (options.availableComponents.length > 0) {
|
|
207
|
-
sections.push('**Available components
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
226
|
+
sections.push('**Available components you MUST use instead:**');
|
|
227
|
+
// Group by likely use case for easier reference
|
|
228
|
+
const layoutComponents = options.availableComponents.filter(c => /^(Box|Stack|Group|Grid|SimpleGrid|Flex|Container|Center|Space|Paper|Card|Divider)$/i.test(c));
|
|
229
|
+
const displayComponents = options.availableComponents.filter(c => /^(Text|Title|Badge|Avatar|Image|ThemeIcon|ActionIcon|Button|Anchor)$/i.test(c));
|
|
230
|
+
const otherComponents = options.availableComponents.filter(c => !layoutComponents.includes(c) && !displayComponents.includes(c));
|
|
231
|
+
if (layoutComponents.length > 0) {
|
|
232
|
+
sections.push(`- **Layout:** ${layoutComponents.join(', ')}`);
|
|
233
|
+
}
|
|
234
|
+
if (displayComponents.length > 0) {
|
|
235
|
+
sections.push(`- **Display:** ${displayComponents.join(', ')}`);
|
|
236
|
+
}
|
|
237
|
+
if (otherComponents.length > 0) {
|
|
238
|
+
const displayOthers = otherComponents.slice(0, 30);
|
|
239
|
+
sections.push(`- **Other:** ${displayOthers.join(', ')}${otherComponents.length > 30 ? ` ... and ${otherComponents.length - 30} more` : ''}`);
|
|
212
240
|
}
|
|
213
241
|
sections.push('');
|
|
214
242
|
}
|
|
@@ -224,18 +252,21 @@ export function buildSelfHealingPrompt(originalCode, errors, attempt, options) {
|
|
|
224
252
|
sections.push('1. Fix ALL errors listed above');
|
|
225
253
|
sections.push('2. Keep the same component structure and layout');
|
|
226
254
|
sections.push('3. Do NOT add new features - only fix the errors');
|
|
255
|
+
sections.push('4. **CRITICAL: Escape apostrophes in title strings** - Use `\\\'` not `\'`');
|
|
256
|
+
sections.push(' Example: `title: \'Women\\\'s Athletic Dashboard\'` NOT `title: \'Women\'s Athletic Dashboard\'`');
|
|
257
|
+
sections.push('5. Do NOT duplicate title segments - "Dashboard Dashboard" is WRONG');
|
|
227
258
|
if (options.framework === 'svelte') {
|
|
228
|
-
sections.push('
|
|
229
|
-
sections.push('
|
|
230
|
-
sections.push(`
|
|
231
|
-
sections.push(`
|
|
232
|
-
sections.push('
|
|
259
|
+
sections.push('6. Use proper Svelte 5 syntax (class=, onclick=, NOT on:click=)');
|
|
260
|
+
sections.push('7. NEVER nest a component inside itself: <Comp><Comp>X</Comp></Comp> is WRONG! Use <Comp>X</Comp>');
|
|
261
|
+
sections.push(`8. Only import from ROOT: import { Comp } from "${options.importPath}" - NEVER use deep paths like "${options.importPath}/dist/..." or "${options.importPath}/components/..."`);
|
|
262
|
+
sections.push(`9. Return the COMPLETE corrected code in a \`\`\`svelte code block`);
|
|
263
|
+
sections.push('10. Do NOT include any explanation - just the corrected code block');
|
|
233
264
|
}
|
|
234
265
|
else {
|
|
235
|
-
sections.push('
|
|
236
|
-
sections.push(`
|
|
237
|
-
sections.push(`
|
|
238
|
-
sections.push('
|
|
266
|
+
sections.push('6. Ensure all JSX elements are properly opened and closed');
|
|
267
|
+
sections.push(`7. Only import components that exist in "${options.importPath}"`);
|
|
268
|
+
sections.push(`8. Return the COMPLETE corrected code in a \`\`\`${codeBlockLang} code block`);
|
|
269
|
+
sections.push('9. Do NOT include any explanation - just the corrected code block');
|
|
239
270
|
}
|
|
240
271
|
return sections.join('\n');
|
|
241
272
|
}
|
|
@@ -44,5 +44,17 @@ export declare class StoryTracker {
|
|
|
44
44
|
* Clean up orphaned mappings (stories that no longer exist)
|
|
45
45
|
*/
|
|
46
46
|
cleanupOrphaned(generatedStoriesPath: string): number;
|
|
47
|
+
/**
|
|
48
|
+
* Get the next available version for a title
|
|
49
|
+
* If "Navigation Bar" exists, returns "Navigation Bar v2"
|
|
50
|
+
* If "Navigation Bar v2" exists, returns "Navigation Bar v3", etc.
|
|
51
|
+
*
|
|
52
|
+
* This is only used for NEW stories (not updates to existing stories)
|
|
53
|
+
*/
|
|
54
|
+
getNextVersionTitle(baseTitle: string): string;
|
|
55
|
+
/**
|
|
56
|
+
* Escape special regex characters in a string
|
|
57
|
+
*/
|
|
58
|
+
private escapeRegex;
|
|
47
59
|
}
|
|
48
60
|
//# sourceMappingURL=storyTracker.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"storyTracker.d.ts","sourceRoot":"","sources":["../../story-generator/storyTracker.ts"],"names":[],"mappings":"AAEA,OAAO,EAAE,aAAa,EAAE,MAAM,uBAAuB,CAAC;AAEtD,MAAM,WAAW,YAAY;IAC3B,KAAK,EAAE,MAAM,CAAC;IACd,QAAQ,EAAE,MAAM,CAAC;IACjB,OAAO,EAAE,MAAM,CAAC;IAChB,IAAI,EAAE,MAAM,CAAC;IACb,SAAS,EAAE,MAAM,CAAC;IAClB,SAAS,EAAE,MAAM,CAAC;IAClB,MAAM,EAAE,MAAM,CAAC;CAChB;AAED,qBAAa,YAAY;IACvB,OAAO,CAAC,WAAW,CAAS;IAC5B,OAAO,CAAC,QAAQ,CAA4B;gBAEhC,MAAM,EAAE,aAAa;IAMjC;;OAEG;IACH,OAAO,CAAC,YAAY;IAgBpB;;OAEG;IACH,OAAO,CAAC,YAAY;IASpB;;OAEG;IACH,WAAW,CAAC,KAAK,EAAE,MAAM,GAAG,YAAY,GAAG,SAAS;IAkBpD;;OAEG;IACH,YAAY,CAAC,MAAM,EAAE,MAAM,GAAG,YAAY,GAAG,SAAS;IA4CtD;;OAEG;IACH,aAAa,CAAC,OAAO,EAAE,YAAY,GAAG,IAAI;IAwB1C;;OAEG;IACH,WAAW,CAAC,eAAe,EAAE,MAAM,GAAG,OAAO;IAqB7C;;OAEG;IACH,cAAc,IAAI,YAAY,EAAE;IAIhC;;OAEG;IACH,eAAe,CAAC,oBAAoB,EAAE,MAAM,GAAG,MAAM;
|
|
1
|
+
{"version":3,"file":"storyTracker.d.ts","sourceRoot":"","sources":["../../story-generator/storyTracker.ts"],"names":[],"mappings":"AAEA,OAAO,EAAE,aAAa,EAAE,MAAM,uBAAuB,CAAC;AAEtD,MAAM,WAAW,YAAY;IAC3B,KAAK,EAAE,MAAM,CAAC;IACd,QAAQ,EAAE,MAAM,CAAC;IACjB,OAAO,EAAE,MAAM,CAAC;IAChB,IAAI,EAAE,MAAM,CAAC;IACb,SAAS,EAAE,MAAM,CAAC;IAClB,SAAS,EAAE,MAAM,CAAC;IAClB,MAAM,EAAE,MAAM,CAAC;CAChB;AAED,qBAAa,YAAY;IACvB,OAAO,CAAC,WAAW,CAAS;IAC5B,OAAO,CAAC,QAAQ,CAA4B;gBAEhC,MAAM,EAAE,aAAa;IAMjC;;OAEG;IACH,OAAO,CAAC,YAAY;IAgBpB;;OAEG;IACH,OAAO,CAAC,YAAY;IASpB;;OAEG;IACH,WAAW,CAAC,KAAK,EAAE,MAAM,GAAG,YAAY,GAAG,SAAS;IAkBpD;;OAEG;IACH,YAAY,CAAC,MAAM,EAAE,MAAM,GAAG,YAAY,GAAG,SAAS;IA4CtD;;OAEG;IACH,aAAa,CAAC,OAAO,EAAE,YAAY,GAAG,IAAI;IAwB1C;;OAEG;IACH,WAAW,CAAC,eAAe,EAAE,MAAM,GAAG,OAAO;IAqB7C;;OAEG;IACH,cAAc,IAAI,YAAY,EAAE;IAIhC;;OAEG;IACH,eAAe,CAAC,oBAAoB,EAAE,MAAM,GAAG,MAAM;IAkBrD;;;;;;OAMG;IACH,mBAAmB,CAAC,SAAS,EAAE,MAAM,GAAG,MAAM;IAoC9C;;OAEG;IACH,OAAO,CAAC,WAAW;CAGpB"}
|
|
@@ -163,4 +163,46 @@ export class StoryTracker {
|
|
|
163
163
|
}
|
|
164
164
|
return removed;
|
|
165
165
|
}
|
|
166
|
+
/**
|
|
167
|
+
* Get the next available version for a title
|
|
168
|
+
* If "Navigation Bar" exists, returns "Navigation Bar v2"
|
|
169
|
+
* If "Navigation Bar v2" exists, returns "Navigation Bar v3", etc.
|
|
170
|
+
*
|
|
171
|
+
* This is only used for NEW stories (not updates to existing stories)
|
|
172
|
+
*/
|
|
173
|
+
getNextVersionTitle(baseTitle) {
|
|
174
|
+
if (!baseTitle || typeof baseTitle !== 'string') {
|
|
175
|
+
return baseTitle;
|
|
176
|
+
}
|
|
177
|
+
const normalizedBase = baseTitle.toLowerCase().trim();
|
|
178
|
+
// Check if the exact title already exists
|
|
179
|
+
if (!this.mappings.has(normalizedBase)) {
|
|
180
|
+
return baseTitle; // No conflict, use as-is
|
|
181
|
+
}
|
|
182
|
+
// Find the highest existing version
|
|
183
|
+
let highestVersion = 1;
|
|
184
|
+
// Check for base title (v1 implicitly)
|
|
185
|
+
if (this.mappings.has(normalizedBase)) {
|
|
186
|
+
highestVersion = 1;
|
|
187
|
+
}
|
|
188
|
+
// Check for versioned titles (v2, v3, etc.)
|
|
189
|
+
for (const existingTitle of this.mappings.keys()) {
|
|
190
|
+
// Match patterns like "title v2", "title v3", etc.
|
|
191
|
+
const versionMatch = existingTitle.match(new RegExp(`^${this.escapeRegex(normalizedBase)}\\s+v(\\d+)$`, 'i'));
|
|
192
|
+
if (versionMatch) {
|
|
193
|
+
const version = parseInt(versionMatch[1], 10);
|
|
194
|
+
if (version > highestVersion) {
|
|
195
|
+
highestVersion = version;
|
|
196
|
+
}
|
|
197
|
+
}
|
|
198
|
+
}
|
|
199
|
+
// Return the next version
|
|
200
|
+
return `${baseTitle} v${highestVersion + 1}`;
|
|
201
|
+
}
|
|
202
|
+
/**
|
|
203
|
+
* Escape special regex characters in a string
|
|
204
|
+
*/
|
|
205
|
+
escapeRegex(str) {
|
|
206
|
+
return str.replace(/[.*+?^${}()|[\]\\]/g, '\\$&');
|
|
207
|
+
}
|
|
166
208
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"storyValidator.d.ts","sourceRoot":"","sources":["../../story-generator/storyValidator.ts"],"names":[],"mappings":"AAAA,MAAM,WAAW,eAAe;IAC9B,OAAO,EAAE,MAAM,CAAC;IAChB,IAAI,EAAE,MAAM,CAAC;CACd;AAED,wBAAgB,aAAa,CAAC,YAAY,EAAE,MAAM,GAAG,eAAe,EAAE,
|
|
1
|
+
{"version":3,"file":"storyValidator.d.ts","sourceRoot":"","sources":["../../story-generator/storyValidator.ts"],"names":[],"mappings":"AAAA,MAAM,WAAW,eAAe;IAC9B,OAAO,EAAE,MAAM,CAAC;IAChB,IAAI,EAAE,MAAM,CAAC;CACd;AAED,wBAAgB,aAAa,CAAC,YAAY,EAAE,MAAM,GAAG,eAAe,EAAE,CA6DrE"}
|
|
@@ -11,14 +11,10 @@ export function validateStory(storyContent) {
|
|
|
11
11
|
{ pattern: /from\s+['"]@storybook\/addon-actions['"]/i, message: 'Do not import from @storybook/addon-actions. Use argTypes with action property instead: argTypes: { onClick: { action: "clicked" } }' },
|
|
12
12
|
// Catch Svelte slot property which doesn't work in modern Storybook
|
|
13
13
|
{ pattern: /slot:\s*['"][^'"]+['"]/i, message: 'The slot property in render functions does not work in Svelte Storybook. Use simple args-based stories instead.' },
|
|
14
|
-
// Catch abbreviated Material icon names that will render as text instead of icons
|
|
15
|
-
{ pattern: /<mat-icon>\s*(fav|ho|de|se|sta|che|add|rem|edi|sav|can|men|clo|sea)\s*<\/mat-icon>/i, message: 'Material icon name appears to be abbreviated. Use full icon names: "favorite" (not "fav"), "home" (not "ho"), "delete" (not "de"), "settings" (not "se"), etc.' },
|
|
16
14
|
// Catch Angular TS4111 patterns - "this.property" state management in render functions
|
|
17
15
|
{ pattern: /this\.\w+\s*=\s*\$?event\./i, message: 'Do not use "this.property = event.value" in Angular stories. This causes TS4111 errors. Use argTypes with action property for events and create separate stories for different states.' },
|
|
18
16
|
{ pattern: /this\.\w+\+\+/i, message: 'Do not use "this.property++" in Angular stories. This causes TS4111 errors. Use argTypes with action property for events instead of managing state.' },
|
|
19
17
|
{ pattern: /this\.\w+--/i, message: 'Do not use "this.property--" in Angular stories. This causes TS4111 errors. Use argTypes with action property for events instead of managing state.' },
|
|
20
|
-
// Catch flowbite-svelte deep path imports that break in production
|
|
21
|
-
{ pattern: /from\s+['"]flowbite-svelte\/[^'"]+['"]/i, message: 'Do not use deep path imports for flowbite-svelte. Use named exports from root: import { Component } from "flowbite-svelte"' },
|
|
22
18
|
];
|
|
23
19
|
lines.forEach((line, index) => {
|
|
24
20
|
for (const { pattern, message } of forbiddenPatterns) {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"validateStory.d.ts","sourceRoot":"","sources":["../../story-generator/validateStory.ts"],"names":[],"mappings":"AAKA,MAAM,WAAW,gBAAgB;IAC/B,OAAO,EAAE,OAAO,CAAC;IACjB,MAAM,EAAE,MAAM,EAAE,CAAC;IACjB,QAAQ,EAAE,MAAM,EAAE,CAAC;IACnB,SAAS,CAAC,EAAE,MAAM,CAAC;CACpB;AAED;;GAEG;AACH,wBAAgB,iBAAiB,CAAC,IAAI,EAAE,MAAM,EAAE,QAAQ,GAAE,MAAoB,EAAE,MAAM,CAAC,EAAE,GAAG,GAAG,gBAAgB,CAsH9G;
|
|
1
|
+
{"version":3,"file":"validateStory.d.ts","sourceRoot":"","sources":["../../story-generator/validateStory.ts"],"names":[],"mappings":"AAKA,MAAM,WAAW,gBAAgB;IAC/B,OAAO,EAAE,OAAO,CAAC;IACjB,MAAM,EAAE,MAAM,EAAE,CAAC;IACjB,QAAQ,EAAE,MAAM,EAAE,CAAC;IACnB,SAAS,CAAC,EAAE,MAAM,CAAC;CACpB;AAED;;GAEG;AACH,wBAAgB,iBAAiB,CAAC,IAAI,EAAE,MAAM,EAAE,QAAQ,GAAE,MAAoB,EAAE,MAAM,CAAC,EAAE,GAAG,GAAG,gBAAgB,CAsH9G;AAgrBD;;;GAGG;AACH,wBAAgB,2BAA2B,CAAC,UAAU,EAAE,MAAM,EAAE,MAAM,CAAC,EAAE,GAAG,EAAE,QAAQ,CAAC,EAAE,MAAM,GAAG,gBAAgB,CAoFjH;AAED;;GAEG;AACH,wBAAgB,mBAAmB,CAAC,MAAM,EAAE,MAAM,EAAE,MAAM,EAAE,GAAG,GAAG,MAAM,CA+BvE"}
|