@tpitre/story-ui 2.6.1 → 2.7.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/README.md +36 -37
- package/dist/cli/deploy.d.ts +4 -3
- package/dist/cli/deploy.d.ts.map +1 -1
- package/dist/cli/deploy.js +542 -46
- package/dist/cli/index.js +17 -14
- package/dist/cli/index.js.map +1 -0
- package/dist/cli/setup.d.ts.map +1 -1
- package/dist/cli/setup.js +4 -110
- package/dist/cli/setup.js.map +1 -0
- package/dist/cloudflare-edge/src/mcp-session.js +462 -0
- package/dist/cloudflare-edge/src/types.js +4 -0
- package/dist/cloudflare-edge/src/worker.js +106 -0
- package/dist/cloudflare-pages/vite.config.js +14 -0
- package/dist/index.d.ts +13 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +12 -0
- package/dist/index.js.map +1 -0
- package/dist/mcp-server/index.js.map +1 -0
- package/dist/mcp-server/mcp-stdio-server.js.map +1 -0
- package/dist/mcp-server/routes/claude.js.map +1 -0
- package/dist/mcp-server/routes/components.js.map +1 -0
- package/dist/mcp-server/routes/generateStory.js.map +1 -0
- package/dist/mcp-server/routes/hybridStories.js.map +1 -0
- package/dist/mcp-server/routes/memoryStories.js.map +1 -0
- package/dist/mcp-server/routes/storySync.js.map +1 -0
- package/dist/mcp-server/routes/updateStory.js +246 -0
- package/dist/mcp-server/sessionManager.js.map +1 -0
- package/dist/playground/components/AIAssistant/AIAssistant.d.ts +6 -0
- package/dist/playground/components/AIAssistant/AIAssistant.d.ts.map +1 -0
- package/dist/playground/components/AIAssistant/AIAssistant.js +109 -0
- package/dist/playground/components/AIAssistant/AIAssistant.js.map +1 -0
- package/dist/playground/components/AIAssistant/AIAssistant.module.css +166 -0
- package/dist/playground/components/Canvas/Canvas.d.ts +9 -0
- package/dist/playground/components/Canvas/Canvas.d.ts.map +1 -0
- package/dist/playground/components/Canvas/Canvas.js +58 -0
- package/dist/playground/components/Canvas/Canvas.js.map +1 -0
- package/dist/playground/components/Canvas/Canvas.module.css +189 -0
- package/dist/playground/components/Canvas/CanvasWithDnd.d.ts +9 -0
- package/dist/playground/components/Canvas/CanvasWithDnd.d.ts.map +1 -0
- package/dist/playground/components/Canvas/CanvasWithDnd.js +158 -0
- package/dist/playground/components/Canvas/CanvasWithDnd.js.map +1 -0
- package/dist/playground/components/Canvas/ComponentRenderer.d.ts +15 -0
- package/dist/playground/components/Canvas/ComponentRenderer.d.ts.map +1 -0
- package/dist/playground/components/Canvas/ComponentRenderer.js +177 -0
- package/dist/playground/components/Canvas/ComponentRenderer.js.map +1 -0
- package/dist/playground/components/Canvas/DraggableComponent.d.ts +15 -0
- package/dist/playground/components/Canvas/DraggableComponent.d.ts.map +1 -0
- package/dist/playground/components/Canvas/DraggableComponent.js +49 -0
- package/dist/playground/components/Canvas/DraggableComponent.js.map +1 -0
- package/dist/playground/components/Canvas/index.d.ts +9 -0
- package/dist/playground/components/Canvas/index.d.ts.map +1 -0
- package/dist/playground/components/Canvas/index.js +5 -0
- package/dist/playground/components/Canvas/index.js.map +1 -0
- package/dist/playground/components/CodeView/CodeView.d.ts +12 -0
- package/dist/playground/components/CodeView/CodeView.d.ts.map +1 -0
- package/dist/playground/components/CodeView/CodeView.js +77 -0
- package/dist/playground/components/CodeView/CodeView.js.map +1 -0
- package/dist/playground/components/CodeView/CodeView.module.css +178 -0
- package/dist/playground/components/ComponentPalette/ComponentPalette.d.ts +17 -0
- package/dist/playground/components/ComponentPalette/ComponentPalette.d.ts.map +1 -0
- package/dist/playground/components/ComponentPalette/ComponentPalette.js +138 -0
- package/dist/playground/components/ComponentPalette/ComponentPalette.js.map +1 -0
- package/dist/playground/components/ComponentPalette/ComponentPalette.module.css +217 -0
- package/dist/playground/components/ComponentPalette/index.d.ts +3 -0
- package/dist/playground/components/ComponentPalette/index.d.ts.map +1 -0
- package/dist/playground/components/ComponentPalette/index.js +2 -0
- package/dist/playground/components/ComponentPalette/index.js.map +1 -0
- package/dist/playground/components/DropZone/DropZone.d.ts +17 -0
- package/dist/playground/components/DropZone/DropZone.d.ts.map +1 -0
- package/dist/playground/components/DropZone/DropZone.js +73 -0
- package/dist/playground/components/DropZone/DropZone.js.map +1 -0
- package/dist/playground/components/DropZone/DropZone.module.css +86 -0
- package/dist/playground/components/ExportDialog/ExportDialog.d.ts +10 -0
- package/dist/playground/components/ExportDialog/ExportDialog.d.ts.map +1 -0
- package/dist/playground/components/ExportDialog/ExportDialog.js +57 -0
- package/dist/playground/components/ExportDialog/ExportDialog.js.map +1 -0
- package/dist/playground/components/ExportDialog/ExportDialog.module.css +328 -0
- package/dist/playground/components/LayoutHelpers/LayoutHelpers.d.ts +134 -0
- package/dist/playground/components/LayoutHelpers/LayoutHelpers.d.ts.map +1 -0
- package/dist/playground/components/LayoutHelpers/LayoutHelpers.js +254 -0
- package/dist/playground/components/LayoutHelpers/LayoutHelpers.js.map +1 -0
- package/dist/playground/components/LayoutHelpers/index.d.ts +3 -0
- package/dist/playground/components/LayoutHelpers/index.d.ts.map +1 -0
- package/dist/playground/components/LayoutHelpers/index.js +2 -0
- package/dist/playground/components/LayoutHelpers/index.js.map +1 -0
- package/dist/playground/components/Playground/Playground.d.ts +10 -0
- package/dist/playground/components/Playground/Playground.d.ts.map +1 -0
- package/dist/playground/components/Playground/Playground.js +128 -0
- package/dist/playground/components/Playground/Playground.js.map +1 -0
- package/dist/playground/components/Playground/Playground.module.css +308 -0
- package/dist/playground/components/PropertiesPanel/PropertiesPanel.d.ts +10 -0
- package/dist/playground/components/PropertiesPanel/PropertiesPanel.d.ts.map +1 -0
- package/dist/playground/components/PropertiesPanel/PropertiesPanel.js +150 -0
- package/dist/playground/components/PropertiesPanel/PropertiesPanel.js.map +1 -0
- package/dist/playground/components/PropertiesPanel/PropertiesPanel.module.css +155 -0
- package/dist/playground/components/PropertiesPanel/index.d.ts +3 -0
- package/dist/playground/components/PropertiesPanel/index.d.ts.map +1 -0
- package/dist/playground/components/PropertiesPanel/index.js +2 -0
- package/dist/playground/components/PropertiesPanel/index.js.map +1 -0
- package/dist/playground/components/PropertyEditors/BooleanEditor.d.ts +12 -0
- package/dist/playground/components/PropertyEditors/BooleanEditor.d.ts.map +1 -0
- package/dist/playground/components/PropertyEditors/BooleanEditor.js +14 -0
- package/dist/playground/components/PropertyEditors/BooleanEditor.js.map +1 -0
- package/dist/playground/components/PropertyEditors/ColorEditor.d.ts +12 -0
- package/dist/playground/components/PropertyEditors/ColorEditor.d.ts.map +1 -0
- package/dist/playground/components/PropertyEditors/ColorEditor.js +62 -0
- package/dist/playground/components/PropertyEditors/ColorEditor.js.map +1 -0
- package/dist/playground/components/PropertyEditors/IconEditor.d.ts +12 -0
- package/dist/playground/components/PropertyEditors/IconEditor.d.ts.map +1 -0
- package/dist/playground/components/PropertyEditors/IconEditor.js +123 -0
- package/dist/playground/components/PropertyEditors/IconEditor.js.map +1 -0
- package/dist/playground/components/PropertyEditors/NumberEditor.d.ts +15 -0
- package/dist/playground/components/PropertyEditors/NumberEditor.d.ts.map +1 -0
- package/dist/playground/components/PropertyEditors/NumberEditor.js +46 -0
- package/dist/playground/components/PropertyEditors/NumberEditor.js.map +1 -0
- package/dist/playground/components/PropertyEditors/PropertyEditors.module.css +432 -0
- package/dist/playground/components/PropertyEditors/SelectEditor.d.ts +19 -0
- package/dist/playground/components/PropertyEditors/SelectEditor.d.ts.map +1 -0
- package/dist/playground/components/PropertyEditors/SelectEditor.js +17 -0
- package/dist/playground/components/PropertyEditors/SelectEditor.js.map +1 -0
- package/dist/playground/components/PropertyEditors/SpacingEditor.d.ts +19 -0
- package/dist/playground/components/PropertyEditors/SpacingEditor.d.ts.map +1 -0
- package/dist/playground/components/PropertyEditors/SpacingEditor.js +162 -0
- package/dist/playground/components/PropertyEditors/SpacingEditor.js.map +1 -0
- package/dist/playground/components/PropertyEditors/SpacingEditor.module.css +214 -0
- package/dist/playground/components/PropertyEditors/TextEditor.d.ts +14 -0
- package/dist/playground/components/PropertyEditors/TextEditor.d.ts.map +1 -0
- package/dist/playground/components/PropertyEditors/TextEditor.js +38 -0
- package/dist/playground/components/PropertyEditors/TextEditor.js.map +1 -0
- package/dist/playground/components/PropertyEditors/TokenEditor.d.ts +23 -0
- package/dist/playground/components/PropertyEditors/TokenEditor.d.ts.map +1 -0
- package/dist/playground/components/PropertyEditors/TokenEditor.js +50 -0
- package/dist/playground/components/PropertyEditors/TokenEditor.js.map +1 -0
- package/dist/playground/components/PropertyEditors/index.d.ts +20 -0
- package/dist/playground/components/PropertyEditors/index.d.ts.map +1 -0
- package/dist/playground/components/PropertyEditors/index.js +12 -0
- package/dist/playground/components/PropertyEditors/index.js.map +1 -0
- package/dist/playground/components/TreeView/TreeView.d.ts +10 -0
- package/dist/playground/components/TreeView/TreeView.d.ts.map +1 -0
- package/dist/playground/components/TreeView/TreeView.js +146 -0
- package/dist/playground/components/TreeView/TreeView.js.map +1 -0
- package/dist/playground/components/TreeView/TreeView.module.css +214 -0
- package/dist/playground/components/TreeView/index.d.ts +3 -0
- package/dist/playground/components/TreeView/index.d.ts.map +1 -0
- package/dist/playground/components/TreeView/index.js +2 -0
- package/dist/playground/components/TreeView/index.js.map +1 -0
- package/dist/playground/config/propertyDefinitions.d.ts +73 -0
- package/dist/playground/config/propertyDefinitions.d.ts.map +1 -0
- package/dist/playground/config/propertyDefinitions.js +809 -0
- package/dist/playground/config/propertyDefinitions.js.map +1 -0
- package/dist/playground/hooks/useKeyboardShortcuts.d.ts +38 -0
- package/dist/playground/hooks/useKeyboardShortcuts.d.ts.map +1 -0
- package/dist/playground/hooks/useKeyboardShortcuts.js +191 -0
- package/dist/playground/hooks/useKeyboardShortcuts.js.map +1 -0
- package/dist/playground/index.d.ts +21 -0
- package/dist/playground/index.d.ts.map +1 -0
- package/dist/playground/index.js +23 -0
- package/dist/playground/index.js.map +1 -0
- package/dist/playground/services/CodeGenerator.d.ts +73 -0
- package/dist/playground/services/CodeGenerator.d.ts.map +1 -0
- package/dist/playground/services/CodeGenerator.js +359 -0
- package/dist/playground/services/CodeGenerator.js.map +1 -0
- package/dist/playground/services/DragDropManager.d.ts +95 -0
- package/dist/playground/services/DragDropManager.d.ts.map +1 -0
- package/dist/playground/services/DragDropManager.js +408 -0
- package/dist/playground/services/DragDropManager.js.map +1 -0
- package/dist/playground/services/StoryParser.d.ts +73 -0
- package/dist/playground/services/StoryParser.d.ts.map +1 -0
- package/dist/playground/services/StoryParser.js +419 -0
- package/dist/playground/services/StoryParser.js.map +1 -0
- package/dist/playground/store/playgroundStore.d.ts +86 -0
- package/dist/playground/store/playgroundStore.d.ts.map +1 -0
- package/dist/playground/store/playgroundStore.js +337 -0
- package/dist/playground/store/playgroundStore.js.map +1 -0
- package/dist/playground/stories/PlaygroundDragDrop.stories.d.ts +13 -0
- package/dist/playground/stories/PlaygroundDragDrop.stories.d.ts.map +1 -0
- package/dist/playground/stories/PlaygroundDragDrop.stories.js +227 -0
- package/dist/playground/stories/PlaygroundDragDrop.stories.js.map +1 -0
- package/dist/playground/stories/PlaygroundPhase4.stories.d.ts +13 -0
- package/dist/playground/stories/PlaygroundPhase4.stories.d.ts.map +1 -0
- package/dist/playground/stories/PlaygroundPhase4.stories.js +334 -0
- package/dist/playground/stories/PlaygroundPhase4.stories.js.map +1 -0
- package/dist/playground/stories/PlaygroundPhase5.stories.d.ts +14 -0
- package/dist/playground/stories/PlaygroundPhase5.stories.d.ts.map +1 -0
- package/dist/playground/stories/PlaygroundPhase5.stories.js +512 -0
- package/dist/playground/stories/PlaygroundPhase5.stories.js.map +1 -0
- package/dist/playground/stories/PlaygroundProperties.stories.d.ts +13 -0
- package/dist/playground/stories/PlaygroundProperties.stories.d.ts.map +1 -0
- package/dist/playground/stories/PlaygroundProperties.stories.js +342 -0
- package/dist/playground/stories/PlaygroundProperties.stories.js.map +1 -0
- package/dist/playground/types/index.d.ts +251 -0
- package/dist/playground/types/index.d.ts.map +1 -0
- package/dist/playground/types/index.js +5 -0
- package/dist/playground/types/index.js.map +1 -0
- package/dist/scripts/verify-framework-adapters.js +105 -0
- package/dist/story-generator/componentBlacklist.js.map +1 -0
- package/dist/story-generator/componentDiscovery.js.map +1 -0
- package/dist/story-generator/configLoader.js.map +1 -0
- package/dist/story-generator/considerationsLoader.js.map +1 -0
- package/dist/story-generator/documentation-sources.js.map +1 -0
- package/dist/story-generator/documentationLoader.js.map +1 -0
- package/dist/story-generator/dynamicPackageDiscovery.js.map +1 -0
- package/dist/story-generator/enhancedComponentDiscovery.d.ts.map +1 -1
- package/dist/story-generator/enhancedComponentDiscovery.js +4 -6
- package/dist/story-generator/enhancedComponentDiscovery.js.map +1 -0
- package/dist/story-generator/generateStory.js.map +1 -0
- package/dist/story-generator/gitignoreManager.js.map +1 -0
- package/dist/story-generator/inMemoryStoryService.js.map +1 -0
- package/dist/story-generator/llm-providers/settings-manager.js +4 -4
- package/dist/story-generator/logger.js.map +1 -0
- package/dist/story-generator/postProcessStory.js.map +1 -0
- package/dist/story-generator/productionGitignoreManager.d.ts.map +1 -1
- package/dist/story-generator/productionGitignoreManager.js +6 -0
- package/dist/story-generator/productionGitignoreManager.js.map +1 -0
- package/dist/story-generator/promptGenerator.js.map +1 -0
- package/dist/story-generator/providerPresets.d.ts +54 -0
- package/dist/story-generator/providerPresets.d.ts.map +1 -0
- package/dist/story-generator/providerPresets.js +214 -0
- package/dist/story-generator/storyHistory.js.map +1 -0
- package/dist/story-generator/storySync.js.map +1 -0
- package/dist/story-generator/storyTracker.js.map +1 -0
- package/dist/story-generator/storyValidator.js.map +1 -0
- package/dist/story-generator/test_validation.d.ts +2 -0
- package/dist/story-generator/test_validation.d.ts.map +1 -0
- package/dist/story-generator/test_validation.js +51 -0
- package/dist/story-generator/universalDesignSystemAdapter.js.map +1 -0
- package/dist/story-generator/urlRedirectService.js.map +1 -0
- package/dist/story-generator/validateStory.js.map +1 -0
- package/dist/story-ui.config.js.map +1 -0
- package/dist/story-ui.config.loader.d.ts +36 -0
- package/dist/story-ui.config.loader.d.ts.map +1 -0
- package/dist/story-ui.config.loader.js +205 -0
- package/dist/story-ui.config.loader.js.map +1 -0
- package/dist/temp/package/templates/StoryUI/StoryUIPanel.js +807 -0
- package/dist/temp/package/templates/StoryUI/StoryUIPanel.stories.js +37 -0
- package/dist/temp/package/templates/StoryUI/index.js +2 -0
- package/dist/templates/StoryUI/StoryUIPanel.js.map +1 -0
- package/dist/templates/StoryUI/StoryUIPanel.stories.js.map +1 -0
- package/dist/templates/StoryUI/index.js.map +1 -0
- package/dist/templates/StoryUI/manager.d.ts +14 -0
- package/dist/templates/StoryUI/manager.d.ts.map +1 -0
- package/dist/templates/production-app/src/App.d.ts +10 -0
- package/dist/templates/production-app/src/App.d.ts.map +1 -0
- package/dist/templates/production-app/src/App.js +653 -0
- package/dist/templates/production-app/src/LivePreviewRenderer.d.ts +24 -0
- package/dist/templates/production-app/src/LivePreviewRenderer.d.ts.map +1 -0
- package/dist/templates/production-app/src/LivePreviewRenderer.js +199 -0
- package/dist/templates/production-app/src/componentRegistry.d.ts +20 -0
- package/dist/templates/production-app/src/componentRegistry.d.ts.map +1 -0
- package/dist/templates/production-app/src/componentRegistry.js +316 -0
- package/dist/templates/production-app/src/main.d.ts +9 -0
- package/dist/templates/production-app/src/main.d.ts.map +1 -0
- package/dist/templates/production-app/src/main.js +18 -0
- package/dist/templates/production-app/vite.config.d.ts +3 -0
- package/dist/templates/production-app/vite.config.d.ts.map +1 -0
- package/dist/templates/production-app/vite.config.js +71 -0
- package/dist/test-storybooks/angular-material-storybook/src/main.js +66 -0
- package/dist/test-storybooks/chakra-storybook/vite.config.js +6 -0
- package/dist/test-storybooks/mantine-storybook/vite.config.js +93 -0
- package/dist/test-storybooks/web-components-shoelace/vite.config.js +9 -0
- package/dist/tsconfig.tsbuildinfo +1 -0
- package/dist/visual-builder/components/Canvas/Canvas.js +70 -0
- package/dist/visual-builder/components/Canvas/ComponentRenderer.js +545 -0
- package/dist/visual-builder/components/CodeExporter/CodeExporter.js +25 -0
- package/dist/visual-builder/components/CodeExporter/codeGenerator.js +99 -0
- package/dist/visual-builder/components/ComponentPalette/ComponentPalette.js +8 -0
- package/dist/visual-builder/components/ComponentPalette/ComponentPaletteItem.js +51 -0
- package/dist/visual-builder/components/EmbeddedVisualBuilder.js +107 -0
- package/dist/visual-builder/components/PropertyEditor/PropertyEditor.js +16 -0
- package/dist/visual-builder/components/PropertyEditor/PropertyForm.js +88 -0
- package/dist/visual-builder/components/PropertyEditor/SpacingControl.js +145 -0
- package/dist/visual-builder/components/PropertyEditor/SpacingEditor.js +32 -0
- package/dist/visual-builder/components/StoryManager/SaveOnlyManager.js +94 -0
- package/dist/visual-builder/components/StoryManager/StoryManager.js +68 -0
- package/dist/visual-builder/components/StoryManager/index.js +1 -0
- package/dist/visual-builder/components/VisualBuilder.js +256 -0
- package/dist/visual-builder/config/componentRegistry.js +1758 -0
- package/dist/visual-builder/decorators/VisualBuilderDecorator.js +184 -0
- package/dist/visual-builder/example-integration.js +59 -0
- package/dist/visual-builder/example.js +23 -0
- package/dist/visual-builder/hooks/useDragAndDrop.js +137 -0
- package/dist/visual-builder/hooks/useSelection.js +27 -0
- package/dist/visual-builder/index.js +7 -0
- package/dist/visual-builder/store/visualBuilderStore.js +305 -0
- package/dist/visual-builder/types/index.js +1 -0
- package/dist/visual-builder/utils/__tests__/storyFileUpdater.test.js +145 -0
- package/dist/visual-builder/utils/aiParser.js +336 -0
- package/dist/visual-builder/utils/componentTreeUtils.js +111 -0
- package/dist/visual-builder/utils/parserValidation.js +122 -0
- package/dist/visual-builder/utils/storyFileManager.js +73 -0
- package/dist/visual-builder/utils/storyFileUpdater.js +326 -0
- package/dist/visual-builder/utils/storyNameExtraction.test.js +211 -0
- package/dist/visual-builder/utils/storyPersistence.js +180 -0
- package/dist/visual-builder/utils/storyToBuilder.js +813 -0
- package/package.json +1 -1
|
@@ -0,0 +1,813 @@
|
|
|
1
|
+
// Component type mappings from JSX to Visual Builder format
|
|
2
|
+
const COMPONENT_TYPE_MAP = {
|
|
3
|
+
'Container': 'Container',
|
|
4
|
+
'Stack': 'Stack',
|
|
5
|
+
'SimpleGrid': 'SimpleGrid',
|
|
6
|
+
'Card': 'Card',
|
|
7
|
+
'Card.Section': 'CardSection',
|
|
8
|
+
'Image': 'Image',
|
|
9
|
+
'Text': 'Text',
|
|
10
|
+
'Title': 'Title',
|
|
11
|
+
'Badge': 'Badge',
|
|
12
|
+
'Button': 'Button',
|
|
13
|
+
'Group': 'Group',
|
|
14
|
+
'Avatar': 'Avatar',
|
|
15
|
+
'div': 'Box',
|
|
16
|
+
'span': 'Text',
|
|
17
|
+
// Add more mappings as needed
|
|
18
|
+
};
|
|
19
|
+
// Category mappings for Visual Builder
|
|
20
|
+
const COMPONENT_CATEGORIES = {
|
|
21
|
+
'Container': 'Layout',
|
|
22
|
+
'Stack': 'Layout',
|
|
23
|
+
'SimpleGrid': 'Layout',
|
|
24
|
+
'Group': 'Layout',
|
|
25
|
+
'Box': 'Layout',
|
|
26
|
+
'Card': 'Data Display',
|
|
27
|
+
'CardSection': 'Data Display',
|
|
28
|
+
'Image': 'Data Display',
|
|
29
|
+
'Avatar': 'Data Display',
|
|
30
|
+
'Text': 'Typography',
|
|
31
|
+
'Title': 'Typography',
|
|
32
|
+
'Badge': 'Feedback',
|
|
33
|
+
'Button': 'Inputs',
|
|
34
|
+
};
|
|
35
|
+
/**
|
|
36
|
+
* Extracts JSX from a React story component render function
|
|
37
|
+
*/
|
|
38
|
+
export function extractJSXFromStory(storyCode) {
|
|
39
|
+
try {
|
|
40
|
+
console.log('🔍 Extracting JSX from story code:', {
|
|
41
|
+
length: storyCode.length,
|
|
42
|
+
hasTransformed: storyCode.includes('__vite__') || storyCode.includes('_jsxDEV'),
|
|
43
|
+
preview: storyCode.substring(0, 300) + '...'
|
|
44
|
+
});
|
|
45
|
+
// Check for Vite-transformed code and reject it
|
|
46
|
+
if (storyCode.includes('__vite__cjsImport') || storyCode.includes('_jsxDEV') || storyCode.includes('import.meta.hot')) {
|
|
47
|
+
console.error('❌ Detected Vite-transformed code - cannot parse');
|
|
48
|
+
throw new Error('Received Vite-transformed code instead of source code. Cannot parse transformed JSX.');
|
|
49
|
+
}
|
|
50
|
+
// Check if this is the placeholder template
|
|
51
|
+
if (storyCode.includes('Component ready for editing in Visual Builder')) {
|
|
52
|
+
console.error('❌ Detected placeholder template - source code fetch failed');
|
|
53
|
+
throw new Error('Received placeholder template instead of actual story source. Please check if the Story UI server is running correctly.');
|
|
54
|
+
}
|
|
55
|
+
// Match the render function and extract its return JSX
|
|
56
|
+
const renderMatch = storyCode.match(/render:\s*\(\)\s*=>\s*\(([\s\S]*?)\)\s*[,}]/);
|
|
57
|
+
if (renderMatch) {
|
|
58
|
+
console.log('✅ Found JSX in render function');
|
|
59
|
+
return renderMatch[1].trim();
|
|
60
|
+
}
|
|
61
|
+
// Fallback: try to find JSX in return statement
|
|
62
|
+
const returnMatch = storyCode.match(/return\s*\(([\s\S]*?)\);?\s*}/);
|
|
63
|
+
if (returnMatch) {
|
|
64
|
+
console.log('✅ Found JSX in return statement');
|
|
65
|
+
return returnMatch[1].trim();
|
|
66
|
+
}
|
|
67
|
+
// Fallback: try to find JSX after => without parentheses
|
|
68
|
+
const arrowMatch = storyCode.match(/=>\s*([<][\s\S]*?)(?=;|\n|$)/);
|
|
69
|
+
if (arrowMatch) {
|
|
70
|
+
console.log('✅ Found JSX after arrow function');
|
|
71
|
+
return arrowMatch[1].trim();
|
|
72
|
+
}
|
|
73
|
+
// Fallback: try to find JSX in parentheses after =>
|
|
74
|
+
const arrowParenMatch = storyCode.match(/=>\s*\(([\s\S]*?)\)/);
|
|
75
|
+
if (arrowParenMatch) {
|
|
76
|
+
console.log('✅ Found JSX in parentheses after arrow');
|
|
77
|
+
return arrowParenMatch[1].trim();
|
|
78
|
+
}
|
|
79
|
+
console.warn('⚠️ No JSX pattern matched, returning original code');
|
|
80
|
+
return storyCode;
|
|
81
|
+
}
|
|
82
|
+
catch (error) {
|
|
83
|
+
console.error('❌ Error extracting JSX from story:', error);
|
|
84
|
+
throw error;
|
|
85
|
+
}
|
|
86
|
+
}
|
|
87
|
+
/**
|
|
88
|
+
* Parses JSX attributes into props object
|
|
89
|
+
*/
|
|
90
|
+
function parseAttributes(attributeString) {
|
|
91
|
+
const props = {};
|
|
92
|
+
if (!attributeString.trim()) {
|
|
93
|
+
return props;
|
|
94
|
+
}
|
|
95
|
+
try {
|
|
96
|
+
// Improved attribute parsing to handle nested braces in style objects
|
|
97
|
+
const parseAttributeString = (str) => {
|
|
98
|
+
const attrs = [];
|
|
99
|
+
let current = '';
|
|
100
|
+
let braceDepth = 0;
|
|
101
|
+
let inQuotes = false;
|
|
102
|
+
let quoteChar = '';
|
|
103
|
+
for (let i = 0; i < str.length; i++) {
|
|
104
|
+
const char = str[i];
|
|
105
|
+
if (!inQuotes) {
|
|
106
|
+
if (char === '"' || char === "'") {
|
|
107
|
+
inQuotes = true;
|
|
108
|
+
quoteChar = char;
|
|
109
|
+
}
|
|
110
|
+
else if (char === '{') {
|
|
111
|
+
braceDepth++;
|
|
112
|
+
}
|
|
113
|
+
else if (char === '}') {
|
|
114
|
+
braceDepth--;
|
|
115
|
+
}
|
|
116
|
+
else if (char === ' ' && braceDepth === 0 && current && current.includes('=')) {
|
|
117
|
+
attrs.push(current);
|
|
118
|
+
current = '';
|
|
119
|
+
continue;
|
|
120
|
+
}
|
|
121
|
+
}
|
|
122
|
+
else if (char === quoteChar && str[i - 1] !== '\\') {
|
|
123
|
+
inQuotes = false;
|
|
124
|
+
quoteChar = '';
|
|
125
|
+
}
|
|
126
|
+
current += char;
|
|
127
|
+
}
|
|
128
|
+
if (current) {
|
|
129
|
+
attrs.push(current);
|
|
130
|
+
}
|
|
131
|
+
return attrs;
|
|
132
|
+
};
|
|
133
|
+
const attributes = parseAttributeString(attributeString);
|
|
134
|
+
for (const attr of attributes) {
|
|
135
|
+
if (!attr.trim())
|
|
136
|
+
continue;
|
|
137
|
+
const eqIndex = attr.indexOf('=');
|
|
138
|
+
if (eqIndex === -1) {
|
|
139
|
+
// Boolean attribute
|
|
140
|
+
props[attr.trim()] = true;
|
|
141
|
+
continue;
|
|
142
|
+
}
|
|
143
|
+
const key = attr.substring(0, eqIndex).trim();
|
|
144
|
+
let value = attr.substring(eqIndex + 1).trim();
|
|
145
|
+
// Remove quotes
|
|
146
|
+
if ((value.startsWith('"') && value.endsWith('"')) ||
|
|
147
|
+
(value.startsWith("'") && value.endsWith("'"))) {
|
|
148
|
+
value = value.slice(1, -1);
|
|
149
|
+
props[key] = value;
|
|
150
|
+
}
|
|
151
|
+
else if (value.startsWith('{') && value.endsWith('}')) {
|
|
152
|
+
// Handle JSX expressions
|
|
153
|
+
const expression = value.slice(1, -1);
|
|
154
|
+
// Special handling for style prop - parse as object
|
|
155
|
+
if (key === 'style' && expression.startsWith('{') && expression.endsWith('}')) {
|
|
156
|
+
try {
|
|
157
|
+
// Parse style object - convert JS object syntax to JSON
|
|
158
|
+
const styleStr = expression.slice(1, -1); // Remove outer braces
|
|
159
|
+
const jsonStr = styleStr
|
|
160
|
+
.replace(/(['"])?([a-zA-Z0-9_]+)(['"])?:/g, '"$2":') // Quote keys
|
|
161
|
+
.replace(/'/g, '"'); // Single to double quotes
|
|
162
|
+
console.log('🎨 Parsing style:', { original: expression, converted: jsonStr });
|
|
163
|
+
// Try to parse as JSON
|
|
164
|
+
const parsedStyle = JSON.parse(`{${jsonStr}}`);
|
|
165
|
+
// Sanitize arrays in style properties
|
|
166
|
+
const sanitizedStyle = {};
|
|
167
|
+
for (const [styleProp, styleValue] of Object.entries(parsedStyle)) {
|
|
168
|
+
if (Array.isArray(styleValue)) {
|
|
169
|
+
// Convert array to string using first value
|
|
170
|
+
sanitizedStyle[styleProp] = String(styleValue[0]);
|
|
171
|
+
}
|
|
172
|
+
else {
|
|
173
|
+
sanitizedStyle[styleProp] = styleValue;
|
|
174
|
+
}
|
|
175
|
+
}
|
|
176
|
+
props[key] = sanitizedStyle;
|
|
177
|
+
console.log('✅ Successfully parsed style object:', props[key]);
|
|
178
|
+
}
|
|
179
|
+
catch (e) {
|
|
180
|
+
// If JSON parsing fails, try to parse manually
|
|
181
|
+
const styleObj = {};
|
|
182
|
+
const stylePairs = expression.slice(1, -1).split(',');
|
|
183
|
+
for (const pair of stylePairs) {
|
|
184
|
+
const colonIndex = pair.indexOf(':');
|
|
185
|
+
if (colonIndex > -1) {
|
|
186
|
+
const styleProp = pair.substring(0, colonIndex).trim().replace(/['"]/g, '');
|
|
187
|
+
let styleValue = pair.substring(colonIndex + 1).trim();
|
|
188
|
+
// Check if value looks like an array (e.g., "[14, 16, 18]")
|
|
189
|
+
if (styleValue.startsWith('[') && styleValue.endsWith(']')) {
|
|
190
|
+
// Extract first value from array
|
|
191
|
+
const arrayContent = styleValue.slice(1, -1).split(',')[0].trim();
|
|
192
|
+
styleValue = arrayContent;
|
|
193
|
+
}
|
|
194
|
+
// Remove quotes if present
|
|
195
|
+
if ((styleValue.startsWith('"') && styleValue.endsWith('"')) ||
|
|
196
|
+
(styleValue.startsWith("'") && styleValue.endsWith("'"))) {
|
|
197
|
+
styleValue = styleValue.slice(1, -1);
|
|
198
|
+
}
|
|
199
|
+
else if (/^\d+$/.test(styleValue)) {
|
|
200
|
+
// Preserve numeric values as numbers
|
|
201
|
+
styleValue = parseInt(styleValue, 10);
|
|
202
|
+
}
|
|
203
|
+
else if (/^\d*\.\d+$/.test(styleValue)) {
|
|
204
|
+
// Preserve decimal values as numbers
|
|
205
|
+
styleValue = parseFloat(styleValue);
|
|
206
|
+
}
|
|
207
|
+
else {
|
|
208
|
+
// Remove any remaining quotes
|
|
209
|
+
styleValue = styleValue.replace(/['"]/g, '');
|
|
210
|
+
}
|
|
211
|
+
// Convert camelCase to kebab-case for CSS properties if needed
|
|
212
|
+
// But keep camelCase for React style props
|
|
213
|
+
styleObj[styleProp] = styleValue;
|
|
214
|
+
}
|
|
215
|
+
}
|
|
216
|
+
props[key] = styleObj;
|
|
217
|
+
}
|
|
218
|
+
}
|
|
219
|
+
else if (expression === 'true' || expression === 'false') {
|
|
220
|
+
props[key] = expression === 'true';
|
|
221
|
+
}
|
|
222
|
+
else if (/^\d+$/.test(expression)) {
|
|
223
|
+
props[key] = parseInt(expression, 10);
|
|
224
|
+
}
|
|
225
|
+
else if (/^\d*\.\d+$/.test(expression)) {
|
|
226
|
+
props[key] = parseFloat(expression);
|
|
227
|
+
}
|
|
228
|
+
else if (expression.startsWith('"') && expression.endsWith('"')) {
|
|
229
|
+
props[key] = expression.slice(1, -1);
|
|
230
|
+
}
|
|
231
|
+
else {
|
|
232
|
+
// Keep as string for complex expressions
|
|
233
|
+
props[key] = expression;
|
|
234
|
+
}
|
|
235
|
+
}
|
|
236
|
+
else {
|
|
237
|
+
props[key] = value;
|
|
238
|
+
}
|
|
239
|
+
}
|
|
240
|
+
}
|
|
241
|
+
catch (error) {
|
|
242
|
+
console.error('Error parsing attributes:', error);
|
|
243
|
+
}
|
|
244
|
+
return props;
|
|
245
|
+
}
|
|
246
|
+
/**
|
|
247
|
+
* Advanced JSX tokenizer that properly handles nested structures
|
|
248
|
+
*/
|
|
249
|
+
function tokenizeJSX(jsx) {
|
|
250
|
+
const tokens = [];
|
|
251
|
+
let i = 0;
|
|
252
|
+
while (i < jsx.length) {
|
|
253
|
+
// Skip whitespace at the beginning
|
|
254
|
+
while (i < jsx.length && /\s/.test(jsx[i])) {
|
|
255
|
+
i++;
|
|
256
|
+
}
|
|
257
|
+
if (i >= jsx.length)
|
|
258
|
+
break;
|
|
259
|
+
// Handle JSX elements
|
|
260
|
+
if (jsx[i] === '<') {
|
|
261
|
+
const tokenStart = i;
|
|
262
|
+
i++; // skip '<'
|
|
263
|
+
// Check for comment
|
|
264
|
+
if (jsx.substring(i, i + 3) === '!--') {
|
|
265
|
+
// Skip comment
|
|
266
|
+
const commentEnd = jsx.indexOf('-->', i);
|
|
267
|
+
if (commentEnd !== -1) {
|
|
268
|
+
i = commentEnd + 3;
|
|
269
|
+
continue;
|
|
270
|
+
}
|
|
271
|
+
}
|
|
272
|
+
// Check for closing tag
|
|
273
|
+
const isClosingTag = jsx[i] === '/';
|
|
274
|
+
if (isClosingTag) {
|
|
275
|
+
i++; // skip '/'
|
|
276
|
+
}
|
|
277
|
+
// Extract tag name
|
|
278
|
+
let tagName = '';
|
|
279
|
+
while (i < jsx.length && /[a-zA-Z0-9._]/.test(jsx[i])) {
|
|
280
|
+
tagName += jsx[i];
|
|
281
|
+
i++;
|
|
282
|
+
}
|
|
283
|
+
if (!tagName) {
|
|
284
|
+
i++; // skip invalid character
|
|
285
|
+
continue;
|
|
286
|
+
}
|
|
287
|
+
// Handle closing tag
|
|
288
|
+
if (isClosingTag) {
|
|
289
|
+
// Skip to closing >
|
|
290
|
+
while (i < jsx.length && jsx[i] !== '>') {
|
|
291
|
+
i++;
|
|
292
|
+
}
|
|
293
|
+
if (jsx[i] === '>')
|
|
294
|
+
i++;
|
|
295
|
+
tokens.push({
|
|
296
|
+
type: 'tag_close',
|
|
297
|
+
content: jsx.substring(tokenStart, i),
|
|
298
|
+
tagName,
|
|
299
|
+
position: { start: tokenStart, end: i }
|
|
300
|
+
});
|
|
301
|
+
continue;
|
|
302
|
+
}
|
|
303
|
+
// Extract attributes for opening tag
|
|
304
|
+
let attributes = '';
|
|
305
|
+
let inString = false;
|
|
306
|
+
let stringChar = '';
|
|
307
|
+
let braceDepth = 0;
|
|
308
|
+
while (i < jsx.length) {
|
|
309
|
+
const char = jsx[i];
|
|
310
|
+
if (!inString) {
|
|
311
|
+
if (char === '"' || char === "'") {
|
|
312
|
+
inString = true;
|
|
313
|
+
stringChar = char;
|
|
314
|
+
}
|
|
315
|
+
else if (char === '{') {
|
|
316
|
+
braceDepth++;
|
|
317
|
+
}
|
|
318
|
+
else if (char === '}') {
|
|
319
|
+
braceDepth--;
|
|
320
|
+
}
|
|
321
|
+
else if (char === '>' && braceDepth === 0) {
|
|
322
|
+
break; // Found end of opening tag
|
|
323
|
+
}
|
|
324
|
+
else if (char === '/' && jsx[i + 1] === '>' && braceDepth === 0) {
|
|
325
|
+
// Self-closing tag
|
|
326
|
+
break;
|
|
327
|
+
}
|
|
328
|
+
}
|
|
329
|
+
else if (char === stringChar && jsx[i - 1] !== '\\') {
|
|
330
|
+
inString = false;
|
|
331
|
+
stringChar = '';
|
|
332
|
+
}
|
|
333
|
+
attributes += char;
|
|
334
|
+
i++;
|
|
335
|
+
}
|
|
336
|
+
// Check for self-closing tag
|
|
337
|
+
const isSelfClosing = jsx[i] === '/' && jsx[i + 1] === '>';
|
|
338
|
+
if (isSelfClosing) {
|
|
339
|
+
i += 2; // skip '/>'
|
|
340
|
+
tokens.push({
|
|
341
|
+
type: 'tag_self_close',
|
|
342
|
+
content: jsx.substring(tokenStart, i),
|
|
343
|
+
tagName,
|
|
344
|
+
attributes: attributes.trim(),
|
|
345
|
+
position: { start: tokenStart, end: i }
|
|
346
|
+
});
|
|
347
|
+
}
|
|
348
|
+
else if (jsx[i] === '>') {
|
|
349
|
+
i++; // skip '>'
|
|
350
|
+
tokens.push({
|
|
351
|
+
type: 'tag_open',
|
|
352
|
+
content: jsx.substring(tokenStart, i),
|
|
353
|
+
tagName,
|
|
354
|
+
attributes: attributes.trim(),
|
|
355
|
+
position: { start: tokenStart, end: i }
|
|
356
|
+
});
|
|
357
|
+
}
|
|
358
|
+
}
|
|
359
|
+
else {
|
|
360
|
+
// Handle text content
|
|
361
|
+
const textStart = i;
|
|
362
|
+
let textContent = '';
|
|
363
|
+
while (i < jsx.length && jsx[i] !== '<') {
|
|
364
|
+
textContent += jsx[i];
|
|
365
|
+
i++;
|
|
366
|
+
}
|
|
367
|
+
const trimmedText = textContent.trim();
|
|
368
|
+
if (trimmedText) {
|
|
369
|
+
tokens.push({
|
|
370
|
+
type: 'text',
|
|
371
|
+
content: trimmedText,
|
|
372
|
+
position: { start: textStart, end: i }
|
|
373
|
+
});
|
|
374
|
+
}
|
|
375
|
+
}
|
|
376
|
+
}
|
|
377
|
+
return tokens;
|
|
378
|
+
}
|
|
379
|
+
/**
|
|
380
|
+
* Recursively parses JSX tokens into ComponentDefinition tree using stack-based approach
|
|
381
|
+
*/
|
|
382
|
+
function parseJSXElement(jsx, idCounter) {
|
|
383
|
+
const components = [];
|
|
384
|
+
try {
|
|
385
|
+
jsx = jsx.trim();
|
|
386
|
+
if (!jsx)
|
|
387
|
+
return components;
|
|
388
|
+
// Handle pure text content
|
|
389
|
+
if (!jsx.startsWith('<')) {
|
|
390
|
+
const textContent = jsx.replace(/^\{|\}$/g, '').trim();
|
|
391
|
+
if (textContent && textContent !== '') {
|
|
392
|
+
components.push({
|
|
393
|
+
id: `text-${idCounter.value++}`,
|
|
394
|
+
type: 'Text',
|
|
395
|
+
displayName: 'Text',
|
|
396
|
+
category: 'Typography',
|
|
397
|
+
props: {
|
|
398
|
+
children: textContent.replace(/^["']|["']$/g, '')
|
|
399
|
+
}
|
|
400
|
+
});
|
|
401
|
+
}
|
|
402
|
+
return components;
|
|
403
|
+
}
|
|
404
|
+
// Tokenize the JSX
|
|
405
|
+
const tokens = tokenizeJSX(jsx);
|
|
406
|
+
console.log('🔍 Tokenized JSX:', tokens.map(t => `${t.type}:${t.tagName || t.content?.substring(0, 20)}`));
|
|
407
|
+
// Use corrected stack-based parsing to build component tree
|
|
408
|
+
const parseStack = [];
|
|
409
|
+
const childrenStack = [];
|
|
410
|
+
let currentChildren = [];
|
|
411
|
+
for (const token of tokens) {
|
|
412
|
+
console.log(`🔧 Processing token: ${token.type} - ${token.tagName || token.content?.substring(0, 30)}`);
|
|
413
|
+
switch (token.type) {
|
|
414
|
+
case 'tag_open': {
|
|
415
|
+
// Create new component
|
|
416
|
+
const tagName = token.tagName;
|
|
417
|
+
const componentType = COMPONENT_TYPE_MAP[tagName] || tagName;
|
|
418
|
+
const category = COMPONENT_CATEGORIES[componentType] || 'Other';
|
|
419
|
+
const props = parseAttributes(token.attributes || '');
|
|
420
|
+
const component = {
|
|
421
|
+
id: `${componentType.toLowerCase().replace('.', '-')}-${idCounter.value++}`,
|
|
422
|
+
type: componentType,
|
|
423
|
+
displayName: componentType,
|
|
424
|
+
category,
|
|
425
|
+
props
|
|
426
|
+
};
|
|
427
|
+
console.log(`📦 Created component: ${component.type} (${component.id})`);
|
|
428
|
+
// Push current state onto stack before processing this component
|
|
429
|
+
if (parseStack.length > 0 || currentChildren.length > 0) {
|
|
430
|
+
parseStack.push(component);
|
|
431
|
+
childrenStack.push(currentChildren);
|
|
432
|
+
currentChildren = [];
|
|
433
|
+
console.log(`📚 Pushed to stack. Stack depth: ${parseStack.length}`);
|
|
434
|
+
}
|
|
435
|
+
else {
|
|
436
|
+
// This is a potential root component
|
|
437
|
+
parseStack.push(component);
|
|
438
|
+
childrenStack.push([]);
|
|
439
|
+
currentChildren = [];
|
|
440
|
+
console.log(`🌳 Started root component: ${component.type}`);
|
|
441
|
+
}
|
|
442
|
+
break;
|
|
443
|
+
}
|
|
444
|
+
case 'tag_self_close': {
|
|
445
|
+
// Create self-closing component
|
|
446
|
+
const tagName = token.tagName;
|
|
447
|
+
const componentType = COMPONENT_TYPE_MAP[tagName] || tagName;
|
|
448
|
+
const category = COMPONENT_CATEGORIES[componentType] || 'Other';
|
|
449
|
+
const props = parseAttributes(token.attributes || '');
|
|
450
|
+
const component = {
|
|
451
|
+
id: `${componentType.toLowerCase().replace('.', '-')}-${idCounter.value++}`,
|
|
452
|
+
type: componentType,
|
|
453
|
+
displayName: componentType,
|
|
454
|
+
category,
|
|
455
|
+
props
|
|
456
|
+
};
|
|
457
|
+
console.log(`🏷️ Created self-closing: ${component.type} (${component.id})`);
|
|
458
|
+
// Add to current children
|
|
459
|
+
currentChildren.push(component);
|
|
460
|
+
console.log(`👶 Added to current children. Children count: ${currentChildren.length}`);
|
|
461
|
+
break;
|
|
462
|
+
}
|
|
463
|
+
case 'tag_close': {
|
|
464
|
+
// Complete current component and pop from stack
|
|
465
|
+
if (parseStack.length > 0) {
|
|
466
|
+
const completedComponent = parseStack.pop();
|
|
467
|
+
const parentChildren = childrenStack.pop();
|
|
468
|
+
// Assign accumulated children to the completed component
|
|
469
|
+
if (currentChildren.length > 0) {
|
|
470
|
+
completedComponent.children = [...currentChildren];
|
|
471
|
+
console.log(`✅ Assigned ${currentChildren.length} children to ${completedComponent.type}`);
|
|
472
|
+
}
|
|
473
|
+
console.log(`🔚 Completing component: ${completedComponent.type} with ${completedComponent.children?.length || 0} children`);
|
|
474
|
+
// Add completed component to parent's children or root
|
|
475
|
+
if (parseStack.length > 0) {
|
|
476
|
+
// Add to parent's children (which becomes new currentChildren)
|
|
477
|
+
currentChildren = parentChildren;
|
|
478
|
+
currentChildren.push(completedComponent);
|
|
479
|
+
console.log(`👨👩👧👦 Added ${completedComponent.type} to parent children. Parent children count: ${currentChildren.length}`);
|
|
480
|
+
}
|
|
481
|
+
else {
|
|
482
|
+
// This is a root component
|
|
483
|
+
components.push(completedComponent);
|
|
484
|
+
currentChildren = parentChildren;
|
|
485
|
+
console.log(`🌳 Added root component: ${completedComponent.type}`);
|
|
486
|
+
}
|
|
487
|
+
}
|
|
488
|
+
break;
|
|
489
|
+
}
|
|
490
|
+
case 'text': {
|
|
491
|
+
// Handle text content
|
|
492
|
+
const textContent = token.content.replace(/^\{|\}$/g, '').trim();
|
|
493
|
+
if (textContent && textContent.length > 0) {
|
|
494
|
+
// Check if this text should be inline content for the current component
|
|
495
|
+
if (parseStack.length > 0 && !parseStack[parseStack.length - 1].children) {
|
|
496
|
+
// Add as inline text content to the current component
|
|
497
|
+
parseStack[parseStack.length - 1].props.children = textContent.replace(/^["']|["']$/g, '');
|
|
498
|
+
console.log(`📝 Added inline text to ${parseStack[parseStack.length - 1].type}: "${textContent.substring(0, 30)}..."`);
|
|
499
|
+
}
|
|
500
|
+
else {
|
|
501
|
+
// Create a text component
|
|
502
|
+
const textComponent = {
|
|
503
|
+
id: `text-${idCounter.value++}`,
|
|
504
|
+
type: 'Text',
|
|
505
|
+
displayName: 'Text',
|
|
506
|
+
category: 'Typography',
|
|
507
|
+
props: {
|
|
508
|
+
children: textContent.replace(/^["']|["']$/g, '')
|
|
509
|
+
}
|
|
510
|
+
};
|
|
511
|
+
currentChildren.push(textComponent);
|
|
512
|
+
console.log(`📄 Created text component: "${textContent.substring(0, 30)}..."`);
|
|
513
|
+
}
|
|
514
|
+
}
|
|
515
|
+
break;
|
|
516
|
+
}
|
|
517
|
+
}
|
|
518
|
+
}
|
|
519
|
+
// Handle any remaining components on stack (error recovery)
|
|
520
|
+
while (parseStack.length > 0) {
|
|
521
|
+
const orphanComponent = parseStack.pop();
|
|
522
|
+
childrenStack.pop();
|
|
523
|
+
if (currentChildren.length > 0) {
|
|
524
|
+
orphanComponent.children = [...currentChildren];
|
|
525
|
+
currentChildren = [];
|
|
526
|
+
}
|
|
527
|
+
components.push(orphanComponent);
|
|
528
|
+
console.log(`🚨 Recovered orphan component: ${orphanComponent.type}`);
|
|
529
|
+
}
|
|
530
|
+
console.log(`✨ Parsing complete. Generated ${components.length} root components.`);
|
|
531
|
+
}
|
|
532
|
+
catch (error) {
|
|
533
|
+
console.error('❌ Error parsing JSX elements:', error);
|
|
534
|
+
}
|
|
535
|
+
return components;
|
|
536
|
+
}
|
|
537
|
+
/**
|
|
538
|
+
* Helper function to get original JSX tag name from component type
|
|
539
|
+
*/
|
|
540
|
+
function getOriginalTagName(componentType) {
|
|
541
|
+
// Handle the reverse mapping more reliably
|
|
542
|
+
const reverseMap = {
|
|
543
|
+
'Container': 'Container',
|
|
544
|
+
'Stack': 'Stack',
|
|
545
|
+
'SimpleGrid': 'SimpleGrid',
|
|
546
|
+
'Card': 'Card',
|
|
547
|
+
'CardSection': 'Card.Section',
|
|
548
|
+
'Image': 'Image',
|
|
549
|
+
'Text': 'Text',
|
|
550
|
+
'Title': 'Title',
|
|
551
|
+
'Badge': 'Badge',
|
|
552
|
+
'Button': 'Button',
|
|
553
|
+
'Group': 'Group',
|
|
554
|
+
'Avatar': 'Avatar',
|
|
555
|
+
'Box': 'div'
|
|
556
|
+
};
|
|
557
|
+
return reverseMap[componentType] || componentType;
|
|
558
|
+
}
|
|
559
|
+
/**
|
|
560
|
+
* Parses a single JSX element into ComponentDefinition - now handles proper nesting
|
|
561
|
+
*/
|
|
562
|
+
function parseSingleJSXElement(jsx, idCounter) {
|
|
563
|
+
try {
|
|
564
|
+
jsx = jsx.trim();
|
|
565
|
+
// Use the new tokenized approach for single elements too
|
|
566
|
+
const tokens = tokenizeJSX(jsx);
|
|
567
|
+
if (tokens.length === 0) {
|
|
568
|
+
return null;
|
|
569
|
+
}
|
|
570
|
+
// For single elements, we should have at most one opening tag and one closing tag
|
|
571
|
+
const firstToken = tokens[0];
|
|
572
|
+
if (firstToken.type === 'tag_self_close') {
|
|
573
|
+
// Self-closing tag
|
|
574
|
+
const tagName = firstToken.tagName;
|
|
575
|
+
const componentType = COMPONENT_TYPE_MAP[tagName] || tagName;
|
|
576
|
+
const category = COMPONENT_CATEGORIES[componentType] || 'Other';
|
|
577
|
+
const props = parseAttributes(firstToken.attributes || '');
|
|
578
|
+
return {
|
|
579
|
+
id: `${componentType.toLowerCase()}-${idCounter.value++}`,
|
|
580
|
+
type: componentType,
|
|
581
|
+
displayName: componentType,
|
|
582
|
+
category,
|
|
583
|
+
props
|
|
584
|
+
};
|
|
585
|
+
}
|
|
586
|
+
else if (firstToken.type === 'tag_open') {
|
|
587
|
+
// Opening tag - parse the full structure
|
|
588
|
+
const components = parseJSXElement(jsx, idCounter);
|
|
589
|
+
return components.length > 0 ? components[0] : null;
|
|
590
|
+
}
|
|
591
|
+
return null;
|
|
592
|
+
}
|
|
593
|
+
catch (error) {
|
|
594
|
+
console.error('Error parsing single JSX element:', error);
|
|
595
|
+
return null;
|
|
596
|
+
}
|
|
597
|
+
}
|
|
598
|
+
/**
|
|
599
|
+
* Main function to parse Story UI content into Visual Builder format
|
|
600
|
+
*/
|
|
601
|
+
export function parseStoryUIToBuilder(storyCode) {
|
|
602
|
+
const result = {
|
|
603
|
+
components: [],
|
|
604
|
+
errors: [],
|
|
605
|
+
warnings: []
|
|
606
|
+
};
|
|
607
|
+
try {
|
|
608
|
+
console.log('🚀 Starting to parse story code for Visual Builder', {
|
|
609
|
+
codeLength: storyCode.length,
|
|
610
|
+
hasCard: storyCode.includes('<Card'),
|
|
611
|
+
hasCardSection: storyCode.includes('Card.Section'),
|
|
612
|
+
hasBadge: storyCode.includes('<Badge'),
|
|
613
|
+
hasStack: storyCode.includes('<Stack'),
|
|
614
|
+
hasImage: storyCode.includes('<Image'),
|
|
615
|
+
firstLine: storyCode.split('\n')[0],
|
|
616
|
+
preview: storyCode.substring(0, 300)
|
|
617
|
+
});
|
|
618
|
+
// Check for placeholder template
|
|
619
|
+
if (storyCode.includes('Component ready for editing in Visual Builder')) {
|
|
620
|
+
const error = '⚠️ Received placeholder template instead of actual story source. The source code was not properly fetched from the server.';
|
|
621
|
+
console.error('❌ Placeholder template detected');
|
|
622
|
+
result.errors.push(error);
|
|
623
|
+
return result;
|
|
624
|
+
}
|
|
625
|
+
// Check for transformed code early and provide clear error
|
|
626
|
+
if (storyCode.includes('__vite__cjsImport') || storyCode.includes('_jsxDEV') || storyCode.includes('import.meta.hot')) {
|
|
627
|
+
const error = 'Visual Builder received Vite-transformed code instead of source code. Please ensure the raw source endpoint is working correctly.';
|
|
628
|
+
console.error('❌', error);
|
|
629
|
+
result.errors.push(error);
|
|
630
|
+
return result;
|
|
631
|
+
}
|
|
632
|
+
// Extract JSX from the story
|
|
633
|
+
const jsx = extractJSXFromStory(storyCode);
|
|
634
|
+
console.log('📝 Extracted JSX:', {
|
|
635
|
+
hasJSX: !!jsx,
|
|
636
|
+
jsxLength: jsx?.length || 0,
|
|
637
|
+
jsxPreview: jsx?.substring(0, 200)
|
|
638
|
+
});
|
|
639
|
+
if (!jsx) {
|
|
640
|
+
result.errors.push('No JSX content found in story');
|
|
641
|
+
return result;
|
|
642
|
+
}
|
|
643
|
+
console.log('📝 Extracted JSX:', jsx.substring(0, 200) + '...');
|
|
644
|
+
// Parse JSX into component tree
|
|
645
|
+
const idCounter = { value: 1 };
|
|
646
|
+
const components = parseJSXElement(jsx, idCounter);
|
|
647
|
+
if (components.length === 0) {
|
|
648
|
+
result.warnings.push('No components were parsed from the JSX');
|
|
649
|
+
}
|
|
650
|
+
else {
|
|
651
|
+
console.log(`✅ Successfully parsed ${components.length} components`);
|
|
652
|
+
// Log component structure for debugging
|
|
653
|
+
const logComponentStructure = (comps, depth = 0) => {
|
|
654
|
+
comps.forEach(comp => {
|
|
655
|
+
console.log(`${' '.repeat(depth)}📦 ${comp.type} (${comp.id}) - children: ${comp.children?.length || 0}`);
|
|
656
|
+
if (comp.children?.length) {
|
|
657
|
+
logComponentStructure(comp.children, depth + 1);
|
|
658
|
+
}
|
|
659
|
+
});
|
|
660
|
+
};
|
|
661
|
+
console.log('🌳 Component tree structure:');
|
|
662
|
+
logComponentStructure(components);
|
|
663
|
+
}
|
|
664
|
+
result.components = components;
|
|
665
|
+
// Add some warnings for unsupported features
|
|
666
|
+
if (jsx.includes('style={{')) {
|
|
667
|
+
result.warnings.push('Inline styles detected - these may not be fully preserved in Visual Builder');
|
|
668
|
+
}
|
|
669
|
+
if (jsx.includes('onClick') || jsx.includes('onHover') || jsx.includes('on[A-Z]')) {
|
|
670
|
+
result.warnings.push('Event handlers detected - these will need to be reconfigured in Visual Builder');
|
|
671
|
+
}
|
|
672
|
+
if (jsx.includes('import.meta') || jsx.includes('__vite__')) {
|
|
673
|
+
result.errors.push('Transformed code detected in JSX - parsing may be unreliable');
|
|
674
|
+
}
|
|
675
|
+
}
|
|
676
|
+
catch (error) {
|
|
677
|
+
const errorMessage = `Failed to parse story: ${error instanceof Error ? error.message : 'Unknown error'}`;
|
|
678
|
+
console.error('❌ Parse error:', errorMessage);
|
|
679
|
+
result.errors.push(errorMessage);
|
|
680
|
+
}
|
|
681
|
+
return result;
|
|
682
|
+
}
|
|
683
|
+
/**
|
|
684
|
+
* Utility function to validate parsed components
|
|
685
|
+
*/
|
|
686
|
+
export function validateParsedComponents(components) {
|
|
687
|
+
const issues = [];
|
|
688
|
+
function validateComponent(component, path) {
|
|
689
|
+
if (!component.id) {
|
|
690
|
+
issues.push(`Component at ${path} is missing an ID`);
|
|
691
|
+
}
|
|
692
|
+
if (!component.type) {
|
|
693
|
+
issues.push(`Component at ${path} is missing a type`);
|
|
694
|
+
}
|
|
695
|
+
if (!COMPONENT_CATEGORIES[component.type] && component.type !== 'Text') {
|
|
696
|
+
issues.push(`Component type "${component.type}" at ${path} is not recognized`);
|
|
697
|
+
}
|
|
698
|
+
if (component.children) {
|
|
699
|
+
component.children.forEach((child, index) => {
|
|
700
|
+
validateComponent(child, `${path}.children[${index}]`);
|
|
701
|
+
});
|
|
702
|
+
}
|
|
703
|
+
}
|
|
704
|
+
components.forEach((component, index) => {
|
|
705
|
+
validateComponent(component, `components[${index}]`);
|
|
706
|
+
});
|
|
707
|
+
console.log(`🔍 Validation complete: ${issues.length} issues found`, issues);
|
|
708
|
+
return issues;
|
|
709
|
+
}
|
|
710
|
+
/**
|
|
711
|
+
* Utility function to detect if code is Vite-transformed
|
|
712
|
+
*/
|
|
713
|
+
export function isViteTransformedCode(code) {
|
|
714
|
+
const transformedIndicators = [
|
|
715
|
+
'__vite__cjsImport',
|
|
716
|
+
'_jsxDEV',
|
|
717
|
+
'import.meta.hot',
|
|
718
|
+
'__vite__updateStyle',
|
|
719
|
+
'__vite_ssr_',
|
|
720
|
+
'createHotContext'
|
|
721
|
+
];
|
|
722
|
+
return transformedIndicators.some(indicator => code.includes(indicator));
|
|
723
|
+
}
|
|
724
|
+
/**
|
|
725
|
+
* Enhanced story name extraction that handles multiple story formats
|
|
726
|
+
*/
|
|
727
|
+
export function extractStoryName(storyCode) {
|
|
728
|
+
console.log('🔍 Extracting story name from code...');
|
|
729
|
+
// Method 1: Extract from story title property (title: "My Story") - HIGHEST PRIORITY
|
|
730
|
+
const titleMatch = storyCode.match(/title:\s*['"]([^'"]+)['"]/);
|
|
731
|
+
if (titleMatch && titleMatch[1]) {
|
|
732
|
+
console.log(`✅ Found title property: "${titleMatch[1]}"`);
|
|
733
|
+
return titleMatch[1];
|
|
734
|
+
}
|
|
735
|
+
// Method 2: Extract from meta title (export default { title: "My Story" })
|
|
736
|
+
const metaTitleMatch = storyCode.match(/export\s+default\s*{[^}]*title:\s*['"]([^'"]+)['"]/);
|
|
737
|
+
if (metaTitleMatch && metaTitleMatch[1]) {
|
|
738
|
+
console.log(`✅ Found meta title: "${metaTitleMatch[1]}"`);
|
|
739
|
+
return metaTitleMatch[1];
|
|
740
|
+
}
|
|
741
|
+
// Method 3: Extract from comment annotation (// @title My Story)
|
|
742
|
+
const commentMatch = storyCode.match(/\/\/\s*@title\s+(.+)/);
|
|
743
|
+
if (commentMatch && commentMatch[1]) {
|
|
744
|
+
const title = commentMatch[1].trim();
|
|
745
|
+
console.log(`✅ Found comment title: "${title}"`);
|
|
746
|
+
return title;
|
|
747
|
+
}
|
|
748
|
+
// Method 4: Extract from JSDoc comment (@title My Story)
|
|
749
|
+
const jsDocMatch = storyCode.match(/\*\s*@title\s+(.+)/);
|
|
750
|
+
if (jsDocMatch && jsDocMatch[1]) {
|
|
751
|
+
const title = jsDocMatch[1].trim();
|
|
752
|
+
console.log(`✅ Found JSDoc title: "${title}"`);
|
|
753
|
+
return title;
|
|
754
|
+
}
|
|
755
|
+
// Method 5: Extract from export const statement (e.g., export const MyStory = {...})
|
|
756
|
+
const exportMatch = storyCode.match(/export\s+const\s+(\w+)\s*=/);
|
|
757
|
+
if (exportMatch && exportMatch[1]) {
|
|
758
|
+
const rawName = exportMatch[1];
|
|
759
|
+
// Convert PascalCase or camelCase to readable format, but keep it clean
|
|
760
|
+
const readable = rawName
|
|
761
|
+
.replace(/([A-Z])/g, ' $1')
|
|
762
|
+
.replace(/^\s+/, '')
|
|
763
|
+
.trim();
|
|
764
|
+
console.log(`✅ Found export const name: "${rawName}" → "${readable}"`);
|
|
765
|
+
return readable;
|
|
766
|
+
}
|
|
767
|
+
// Method 6: Extract from component name in JSX (return <MyComponent />)
|
|
768
|
+
const componentMatch = storyCode.match(/return\s*\(?\s*<(\w+)/);
|
|
769
|
+
if (componentMatch && componentMatch[1]) {
|
|
770
|
+
const componentName = componentMatch[1];
|
|
771
|
+
// Only use this if it's not a generic HTML element
|
|
772
|
+
if (!['div', 'span', 'p', 'h1', 'h2', 'h3', 'h4', 'h5', 'h6'].includes(componentName.toLowerCase())) {
|
|
773
|
+
const readable = componentName
|
|
774
|
+
.replace(/([A-Z])/g, ' $1')
|
|
775
|
+
.replace(/^\s+/, '')
|
|
776
|
+
.trim();
|
|
777
|
+
console.log(`✅ Found component name: "${componentName}" → "${readable}"`);
|
|
778
|
+
return readable;
|
|
779
|
+
}
|
|
780
|
+
}
|
|
781
|
+
// Method 7: Extract from function name (export function MyStory())
|
|
782
|
+
const functionMatch = storyCode.match(/export\s+function\s+(\w+)/);
|
|
783
|
+
if (functionMatch && functionMatch[1]) {
|
|
784
|
+
const funcName = functionMatch[1];
|
|
785
|
+
const readable = funcName
|
|
786
|
+
.replace(/([A-Z])/g, ' $1')
|
|
787
|
+
.replace(/^\s+/, '')
|
|
788
|
+
.trim();
|
|
789
|
+
console.log(`✅ Found function name: "${funcName}" → "${readable}"`);
|
|
790
|
+
return readable;
|
|
791
|
+
}
|
|
792
|
+
console.log('❌ No story name found, using fallback');
|
|
793
|
+
return 'Imported Story';
|
|
794
|
+
}
|
|
795
|
+
/**
|
|
796
|
+
* Utility function to clean up code and provide helpful error messages
|
|
797
|
+
*/
|
|
798
|
+
export function preprocessStoryCode(code) {
|
|
799
|
+
const warnings = [];
|
|
800
|
+
const errors = [];
|
|
801
|
+
if (isViteTransformedCode(code)) {
|
|
802
|
+
errors.push('Detected Vite-transformed code. Visual Builder requires original source code, not transformed modules.');
|
|
803
|
+
return { code, warnings, errors };
|
|
804
|
+
}
|
|
805
|
+
// Check for common issues that might indicate problems
|
|
806
|
+
if (code.length < 50) {
|
|
807
|
+
warnings.push('Story code seems unusually short - this might indicate an incomplete source');
|
|
808
|
+
}
|
|
809
|
+
if (!code.includes('render:') && !code.includes('export')) {
|
|
810
|
+
warnings.push('No render function or exports found - this might not be a valid story file');
|
|
811
|
+
}
|
|
812
|
+
return { code, warnings, errors };
|
|
813
|
+
}
|