@pattern-stack/frontend-patterns 0.1.3 → 0.2.0-alpha.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/CHANGELOG.md +69 -74
- package/README.md +17 -2
- package/cli/commands/generate-hooks.ts +2 -2
- package/cli/commands/scaffold.ts +1 -1
- package/cli/index.ts +1 -3
- package/cli/src/codegen/openapi/client-generator.js +4 -17
- package/cli/src/codegen/openapi/hook-generator.js +181 -513
- package/cli/src/codegen/openapi/parser.js +9 -14
- package/cli/src/codegen/openapi/type-generator.js +6 -16
- package/dist/atoms/components/core/Avatar/Avatar.d.ts +6 -6
- package/dist/atoms/components/core/Avatar/Avatar.d.ts.map +1 -1
- package/dist/atoms/components/core/Avatar/index.d.ts +1 -1
- package/dist/atoms/components/core/Badge/Badge.d.ts +6 -6
- package/dist/atoms/components/core/Badge/Badge.d.ts.map +1 -1
- package/dist/atoms/components/core/Badge/index.d.ts +1 -1
- package/dist/atoms/components/core/Button/Button.d.ts +3 -3
- package/dist/atoms/components/core/Button/Button.d.ts.map +1 -1
- package/dist/atoms/components/core/Button/index.d.ts +2 -2
- package/dist/atoms/components/core/Card/Card.d.ts +2 -2
- package/dist/atoms/components/core/Card/Card.d.ts.map +1 -1
- package/dist/atoms/components/core/Card/index.d.ts +2 -2
- package/dist/atoms/components/core/Card/index.d.ts.map +1 -1
- package/dist/atoms/components/core/Checkbox/Checkbox.d.ts +4 -4
- package/dist/atoms/components/core/Checkbox/Checkbox.d.ts.map +1 -1
- package/dist/atoms/components/core/Checkbox/index.d.ts +2 -2
- package/dist/atoms/components/core/Input/Input.d.ts +2 -2
- package/dist/atoms/components/core/Input/Input.d.ts.map +1 -1
- package/dist/atoms/components/core/Input/index.d.ts +2 -2
- package/dist/atoms/components/core/Label/Label.d.ts +3 -4
- package/dist/atoms/components/core/Label/Label.d.ts.map +1 -1
- package/dist/atoms/components/core/Label/index.d.ts +2 -2
- package/dist/atoms/components/core/Select/Select.d.ts +5 -5
- package/dist/atoms/components/core/Select/Select.d.ts.map +1 -1
- package/dist/atoms/components/core/Select/index.d.ts +2 -2
- package/dist/atoms/components/core/Select/index.d.ts.map +1 -1
- package/dist/atoms/components/core/Spinner/Spinner.d.ts +4 -4
- package/dist/atoms/components/core/Spinner/Spinner.d.ts.map +1 -1
- package/dist/atoms/components/core/Spinner/index.d.ts +2 -2
- package/dist/atoms/components/core/Switch/Switch.d.ts +4 -4
- package/dist/atoms/components/core/Switch/Switch.d.ts.map +1 -1
- package/dist/atoms/components/core/Switch/index.d.ts +1 -1
- package/dist/atoms/components/core/index.d.ts +10 -10
- package/dist/atoms/components/core/index.d.ts.map +1 -1
- package/dist/atoms/components/data/ActivityFeed/ActivityFeed.d.ts +2 -2
- package/dist/atoms/components/data/ActivityFeed/ActivityFeed.d.ts.map +1 -1
- package/dist/atoms/components/data/ActivityFeed/ActivityFeedItem.d.ts +3 -3
- package/dist/atoms/components/data/ActivityFeed/ActivityFeedItem.d.ts.map +1 -1
- package/dist/atoms/components/data/ActivityFeed/index.d.ts +3 -3
- package/dist/atoms/components/data/ActivityFeed/index.d.ts.map +1 -1
- package/dist/atoms/components/data/ActivityFeed/types.d.ts +3 -3
- package/dist/atoms/components/data/ActivityFeed/types.d.ts.map +1 -1
- package/dist/atoms/components/data/ActivityFeed/utils.d.ts +2 -2
- package/dist/atoms/components/data/ActivityFeed/utils.d.ts.map +1 -1
- package/dist/atoms/components/data/Chart/Chart.d.ts +52 -5
- package/dist/atoms/components/data/Chart/Chart.d.ts.map +1 -1
- package/dist/atoms/components/data/Chart/index.d.ts +2 -2
- package/dist/atoms/components/data/Chart/index.d.ts.map +1 -1
- package/dist/atoms/components/data/DataBadge/DataBadge.d.ts +6 -6
- package/dist/atoms/components/data/DataBadge/DataBadge.d.ts.map +1 -1
- package/dist/atoms/components/data/DataBadge/index.d.ts +1 -1
- package/dist/atoms/components/data/DataTable/DataTable.d.ts +4 -4
- package/dist/atoms/components/data/DataTable/DataTable.d.ts.map +1 -1
- package/dist/atoms/components/data/DataTable/DataTable.types.d.ts +4 -4
- package/dist/atoms/components/data/DataTable/DataTable.types.d.ts.map +1 -1
- package/dist/atoms/components/data/DataTable/TableCellWithTooltip.d.ts +1 -1
- package/dist/atoms/components/data/DataTable/index.d.ts +2 -2
- package/dist/atoms/components/data/DetailedCard/DetailedCard.d.ts +4 -4
- package/dist/atoms/components/data/DetailedCard/DetailedCard.d.ts.map +1 -1
- package/dist/atoms/components/data/DetailedCard/index.d.ts +2 -2
- package/dist/atoms/components/data/EntityIcon/EntityIcon.d.ts +3 -3
- package/dist/atoms/components/data/EntityIcon/EntityIcon.d.ts.map +1 -1
- package/dist/atoms/components/data/EntityIcon/index.d.ts +1 -1
- package/dist/atoms/components/data/IconBadge/IconBadge.d.ts +6 -6
- package/dist/atoms/components/data/IconBadge/IconBadge.d.ts.map +1 -1
- package/dist/atoms/components/data/IconBadge/index.d.ts +2 -2
- package/dist/atoms/components/data/ListCard/ListCard.d.ts +9 -9
- package/dist/atoms/components/data/ListCard/ListCard.d.ts.map +1 -1
- package/dist/atoms/components/data/ListCard/index.d.ts +1 -1
- package/dist/atoms/components/data/ProgressBar/ProgressBar.d.ts +5 -5
- package/dist/atoms/components/data/ProgressBar/ProgressBar.d.ts.map +1 -1
- package/dist/atoms/components/data/ProgressBar/index.d.ts +1 -1
- package/dist/atoms/components/data/StatCard/StatCard.d.ts +3 -3
- package/dist/atoms/components/data/StatCard/StatCard.d.ts.map +1 -1
- package/dist/atoms/components/data/StatCard/index.d.ts +1 -1
- package/dist/atoms/components/data/Table/Table.d.ts +2 -2
- package/dist/atoms/components/data/Table/Table.d.ts.map +1 -1
- package/dist/atoms/components/data/Table/index.d.ts +1 -1
- package/dist/atoms/components/data/TruncatedText/TruncatedText.d.ts +2 -2
- package/dist/atoms/components/data/TruncatedText/TruncatedText.d.ts.map +1 -1
- package/dist/atoms/components/data/TruncatedText/index.d.ts +1 -1
- package/dist/atoms/components/data/index.d.ts +12 -12
- package/dist/atoms/components/data/index.d.ts.map +1 -1
- package/dist/atoms/components/domain/SalesPanel/SalesPanel.d.ts +15 -15
- package/dist/atoms/components/domain/SalesPanel/SalesPanel.d.ts.map +1 -1
- package/dist/atoms/components/domain/SalesPanel/index.d.ts +1 -1
- package/dist/atoms/components/domain/SalesPanel/index.d.ts.map +1 -1
- package/dist/atoms/components/domain/index.d.ts +1 -1
- package/dist/atoms/components/feedback/Alert/Alert.d.ts +4 -4
- package/dist/atoms/components/feedback/Alert/Alert.d.ts.map +1 -1
- package/dist/atoms/components/feedback/Alert/index.d.ts +1 -1
- package/dist/atoms/components/feedback/EmptyState/EmptyState.d.ts +3 -3
- package/dist/atoms/components/feedback/EmptyState/EmptyState.d.ts.map +1 -1
- package/dist/atoms/components/feedback/EmptyState/index.d.ts +1 -1
- package/dist/atoms/components/feedback/ErrorBoundary/ErrorBoundary.d.ts +1 -1
- package/dist/atoms/components/feedback/ErrorBoundary/ErrorBoundary.d.ts.map +1 -1
- package/dist/atoms/components/feedback/ErrorBoundary/index.d.ts +1 -1
- package/dist/atoms/components/feedback/Skeleton/Skeleton.d.ts +30 -4
- package/dist/atoms/components/feedback/Skeleton/Skeleton.d.ts.map +1 -1
- package/dist/atoms/components/feedback/Skeleton/index.d.ts +1 -1
- package/dist/atoms/components/feedback/Toast/Toast.d.ts +4 -4
- package/dist/atoms/components/feedback/Toast/Toast.d.ts.map +1 -1
- package/dist/atoms/components/feedback/Toast/index.d.ts +1 -1
- package/dist/atoms/components/feedback/Toast/index.d.ts.map +1 -1
- package/dist/atoms/components/feedback/index.d.ts +5 -5
- package/dist/atoms/components/feedback/index.d.ts.map +1 -1
- package/dist/atoms/components/forms/DateTimePicker/DateTimePicker.d.ts +6 -6
- package/dist/atoms/components/forms/DateTimePicker/DateTimePicker.d.ts.map +1 -1
- package/dist/atoms/components/forms/DateTimePicker/index.d.ts +2 -2
- package/dist/atoms/components/forms/FileUpload/FileUpload.d.ts +3 -3
- package/dist/atoms/components/forms/FileUpload/FileUpload.d.ts.map +1 -1
- package/dist/atoms/components/forms/FileUpload/index.d.ts +2 -2
- package/dist/atoms/components/forms/FormField/FormField.d.ts +2 -2
- package/dist/atoms/components/forms/FormField/FormField.d.ts.map +1 -1
- package/dist/atoms/components/forms/FormField/index.d.ts +1 -1
- package/dist/atoms/components/forms/index.d.ts +3 -3
- package/dist/atoms/components/index.d.ts +9 -9
- package/dist/atoms/components/layout/Accordion/Accordion.d.ts +3 -3
- package/dist/atoms/components/layout/Accordion/Accordion.d.ts.map +1 -1
- package/dist/atoms/components/layout/Accordion/index.d.ts +1 -1
- package/dist/atoms/components/layout/Accordion/index.d.ts.map +1 -1
- package/dist/atoms/components/layout/Breadcrumb/Breadcrumb.d.ts +2 -3
- package/dist/atoms/components/layout/Breadcrumb/Breadcrumb.d.ts.map +1 -1
- package/dist/atoms/components/layout/Breadcrumb/index.d.ts +1 -1
- package/dist/atoms/components/layout/Breadcrumb/index.d.ts.map +1 -1
- package/dist/atoms/components/layout/Dialog/Dialog.d.ts +45 -0
- package/dist/atoms/components/layout/Dialog/Dialog.d.ts.map +1 -0
- package/dist/atoms/components/layout/Dialog/index.d.ts +2 -2
- package/dist/atoms/components/layout/Dialog/index.d.ts.map +1 -1
- package/dist/atoms/components/layout/Dropdown/Dropdown.d.ts +9 -9
- package/dist/atoms/components/layout/Dropdown/Dropdown.d.ts.map +1 -1
- package/dist/atoms/components/layout/Dropdown/index.d.ts +2 -2
- package/dist/atoms/components/layout/Dropdown/index.d.ts.map +1 -1
- package/dist/atoms/components/layout/Modal/Modal.d.ts +6 -6
- package/dist/atoms/components/layout/Modal/Modal.d.ts.map +1 -1
- package/dist/atoms/components/layout/Modal/index.d.ts +2 -2
- package/dist/atoms/components/layout/Tabs/Tabs.d.ts +46 -0
- package/dist/atoms/components/layout/Tabs/Tabs.d.ts.map +1 -0
- package/dist/atoms/components/layout/Tabs/index.d.ts +1 -1
- package/dist/atoms/components/layout/Tooltip/Tooltip.d.ts +6 -6
- package/dist/atoms/components/layout/Tooltip/Tooltip.d.ts.map +1 -1
- package/dist/atoms/components/layout/Tooltip/index.d.ts +1 -1
- package/dist/atoms/components/layout/index.d.ts +7 -7
- package/dist/atoms/components/layout/index.d.ts.map +1 -1
- package/dist/atoms/components/navigation/GlobalSearch/GlobalSearch.d.ts +2 -3
- package/dist/atoms/components/navigation/GlobalSearch/GlobalSearch.d.ts.map +1 -1
- package/dist/atoms/components/navigation/GlobalSearch/index.d.ts +1 -1
- package/dist/atoms/components/navigation/GlobalSearch/index.d.ts.map +1 -1
- package/dist/atoms/components/navigation/index.d.ts +1 -1
- package/dist/atoms/components/theme/ColorSwatch/ColorSwatch.d.ts +2 -2
- package/dist/atoms/components/theme/ColorSwatch/ColorSwatch.d.ts.map +1 -1
- package/dist/atoms/components/theme/ColorSwatch/index.d.ts +1 -1
- package/dist/atoms/components/theme/DarkModeToggle.d.ts.map +1 -1
- package/dist/atoms/components/theme/PaletteSwitcher.d.ts +1 -1
- package/dist/atoms/components/theme/PaletteSwitcher.d.ts.map +1 -1
- package/dist/atoms/components/theme/StyleGuide.d.ts +1 -1
- package/dist/atoms/components/theme/StyleGuide.d.ts.map +1 -1
- package/dist/atoms/components/theme/index.d.ts +4 -4
- package/dist/atoms/components/user/UserAvatar/UserAvatar.d.ts +2 -3
- package/dist/atoms/components/user/UserAvatar/UserAvatar.d.ts.map +1 -1
- package/dist/atoms/components/user/UserAvatar/index.d.ts +1 -1
- package/dist/atoms/components/user/UserAvatar/index.d.ts.map +1 -1
- package/dist/atoms/components/user/UserMenu/UserMenu.d.ts +2 -3
- package/dist/atoms/components/user/UserMenu/UserMenu.d.ts.map +1 -1
- package/dist/atoms/components/user/UserMenu/index.d.ts +1 -1
- package/dist/atoms/components/user/UserMenu/index.d.ts.map +1 -1
- package/dist/atoms/components/user/index.d.ts +2 -2
- package/dist/atoms/config/responsive.d.ts +16 -16
- package/dist/atoms/config/responsive.d.ts.map +1 -1
- package/dist/atoms/hooks/index.d.ts +4 -4
- package/dist/atoms/hooks/use-toast.d.ts +1 -1
- package/dist/atoms/hooks/use-toast.d.ts.map +1 -1
- package/dist/atoms/hooks/useApi.d.ts +2 -2
- package/dist/atoms/hooks/useApi.d.ts.map +1 -1
- package/dist/atoms/hooks/useResponsive.d.ts +1 -1
- package/dist/atoms/hooks/useResponsive.d.ts.map +1 -1
- package/dist/atoms/index.d.ts +6 -7
- package/dist/atoms/index.d.ts.map +1 -1
- package/dist/atoms/primitives/Badge.d.ts +6 -6
- package/dist/atoms/primitives/Badge.d.ts.map +1 -1
- package/dist/atoms/primitives/ErrorBoundary.d.ts +3 -3
- package/dist/atoms/primitives/ErrorBoundary.d.ts.map +1 -1
- package/dist/atoms/primitives/Select.d.ts +9 -7
- package/dist/atoms/primitives/Select.d.ts.map +1 -1
- package/dist/atoms/primitives/Switch.d.ts +4 -3
- package/dist/atoms/primitives/Switch.d.ts.map +1 -1
- package/dist/atoms/primitives/Tabs.d.ts +10 -10
- package/dist/atoms/primitives/Tabs.d.ts.map +1 -1
- package/dist/atoms/primitives/avatar.d.ts.map +1 -1
- package/dist/atoms/primitives/button.d.ts +2 -5
- package/dist/atoms/primitives/button.d.ts.map +1 -1
- package/dist/atoms/primitives/button.variants.d.ts +7 -0
- package/dist/atoms/primitives/button.variants.d.ts.map +1 -0
- package/dist/atoms/primitives/card.d.ts +3 -2
- package/dist/atoms/primitives/card.d.ts.map +1 -1
- package/dist/atoms/primitives/checkbox.d.ts +3 -3
- package/dist/atoms/primitives/checkbox.d.ts.map +1 -1
- package/dist/atoms/primitives/dialog.d.ts +4 -4
- package/dist/atoms/primitives/dialog.d.ts.map +1 -1
- package/dist/atoms/primitives/dropdown-menu.d.ts.map +1 -1
- package/dist/atoms/primitives/index.d.ts +16 -16
- package/dist/atoms/primitives/index.d.ts.map +1 -1
- package/dist/atoms/primitives/input.d.ts.map +1 -1
- package/dist/atoms/primitives/label.d.ts +4 -3
- package/dist/atoms/primitives/label.d.ts.map +1 -1
- package/dist/atoms/primitives/skeleton.d.ts.map +1 -1
- package/dist/atoms/primitives/spinner.d.ts +5 -5
- package/dist/atoms/primitives/spinner.d.ts.map +1 -1
- package/dist/atoms/primitives/table.d.ts.map +1 -1
- package/dist/atoms/services/api/client.d.ts +11 -2
- package/dist/atoms/services/api/client.d.ts.map +1 -1
- package/dist/atoms/services/auth-service.d.ts +1 -1
- package/dist/atoms/services/auth-service.d.ts.map +1 -1
- package/dist/atoms/services/health.d.ts +2 -2
- package/dist/atoms/services/index.d.ts +3 -3
- package/dist/atoms/shared/config/dashboard-sizes.d.ts +17 -17
- package/dist/atoms/shared/config/dashboard-sizes.d.ts.map +1 -1
- package/dist/atoms/shared/config/environment.d.ts.map +1 -1
- package/dist/atoms/shared/index.d.ts +4 -4
- package/dist/atoms/shared/index.d.ts.map +1 -1
- package/dist/atoms/types/auth.d.ts +11 -1
- package/dist/atoms/types/auth.d.ts.map +1 -1
- package/dist/atoms/types/entity-config.d.ts +9 -9
- package/dist/atoms/types/entity-config.d.ts.map +1 -1
- package/dist/atoms/types/generated.d.ts.map +1 -1
- package/dist/atoms/types/index.d.ts +6 -6
- package/dist/atoms/types/loading.d.ts +1 -1
- package/dist/atoms/types/navigation.d.ts +1 -1
- package/dist/atoms/types/navigation.d.ts.map +1 -1
- package/dist/atoms/types/ui-config.d.ts +8 -8
- package/dist/atoms/types/ui-config.d.ts.map +1 -1
- package/dist/atoms/utils/animations.d.ts +7 -7
- package/dist/atoms/utils/animations.d.ts.map +1 -1
- package/dist/atoms/utils/color-manager.d.ts +1 -1
- package/dist/atoms/utils/debounce.d.ts +1 -1
- package/dist/atoms/utils/debounce.d.ts.map +1 -1
- package/dist/atoms/utils/field-detection.d.ts +2 -2
- package/dist/atoms/utils/field-detection.d.ts.map +1 -1
- package/dist/atoms/utils/icon-map.d.ts +68 -0
- package/dist/atoms/utils/icon-map.d.ts.map +1 -0
- package/dist/atoms/utils/icon-resolver.d.ts +7 -67
- package/dist/atoms/utils/icon-resolver.d.ts.map +1 -1
- package/dist/atoms/utils/index.d.ts +4 -4
- package/dist/atoms/utils/metric-engine.d.ts +2 -10
- package/dist/atoms/utils/metric-engine.d.ts.map +1 -1
- package/dist/atoms/utils/tooltip-helpers.d.ts +1 -1
- package/dist/atoms/utils/tooltip-helpers.d.ts.map +1 -1
- package/dist/atoms/utils/ui-mapping.d.ts +6 -4
- package/dist/atoms/utils/ui-mapping.d.ts.map +1 -1
- package/dist/atoms/utils/utils.d.ts +7 -6
- package/dist/atoms/utils/utils.d.ts.map +1 -1
- package/dist/codegen/openapi/bulk-types.d.ts +4 -4
- package/dist/codegen/openapi/bulk-types.d.ts.map +1 -1
- package/dist/features/auth/components/LoginForm.d.ts.map +1 -1
- package/dist/features/auth/components/LogoutButton.d.ts.map +1 -1
- package/dist/features/auth/components/ProtectedRoute.d.ts +2 -2
- package/dist/features/auth/components/ProtectedRoute.d.ts.map +1 -1
- package/dist/features/auth/components/index.d.ts +3 -3
- package/dist/features/auth/hooks/auth-context.d.ts +3 -0
- package/dist/features/auth/hooks/auth-context.d.ts.map +1 -0
- package/dist/features/auth/hooks/index.d.ts +4 -3
- package/dist/features/auth/hooks/index.d.ts.map +1 -1
- package/dist/features/auth/hooks/use-auth.d.ts +3 -0
- package/dist/features/auth/hooks/use-auth.d.ts.map +1 -0
- package/dist/features/auth/hooks/useAuth.d.ts +3 -4
- package/dist/features/auth/hooks/useAuth.d.ts.map +1 -1
- package/dist/features/auth/hooks/useAuthContext.d.ts +1 -1
- package/dist/features/auth/hooks/useAuthContext.d.ts.map +1 -1
- package/dist/features/auth/hooks/usePermissions.d.ts +3 -3
- package/dist/features/auth/index.d.ts +3 -3
- package/dist/features/auth/providers/MockAuthProvider.d.ts +3 -4
- package/dist/features/auth/providers/MockAuthProvider.d.ts.map +1 -1
- package/dist/features/auth/providers/index.d.ts +2 -1
- package/dist/features/auth/providers/index.d.ts.map +1 -1
- package/dist/features/auth/providers/mock-auth-context.d.ts +3 -0
- package/dist/features/auth/providers/mock-auth-context.d.ts.map +1 -0
- package/dist/features/auth/providers/use-mock-auth.d.ts +3 -0
- package/dist/features/auth/providers/use-mock-auth.d.ts.map +1 -0
- package/dist/features/auth/services/mock-auth-service.d.ts +3 -3
- package/dist/features/auth/services/mock-auth-service.d.ts.map +1 -1
- package/dist/features/index.d.ts +1 -1
- package/dist/frontend-patterns.css +713 -576
- package/dist/index.d.ts +17 -17
- package/dist/index.d.ts.map +1 -1
- package/dist/index.es.js +21400 -21788
- package/dist/index.es.js.map +1 -1
- package/dist/index.js +21404 -21792
- package/dist/index.js.map +1 -1
- package/dist/molecules/forms/FormGroup.d.ts +2 -2
- package/dist/molecules/forms/FormGroup.d.ts.map +1 -1
- package/dist/molecules/forms/SearchInput.d.ts +1 -1
- package/dist/molecules/forms/SearchInput.d.ts.map +1 -1
- package/dist/molecules/forms/index.d.ts +2 -2
- package/dist/molecules/forms/index.d.ts.map +1 -1
- package/dist/molecules/index.d.ts +3 -3
- package/dist/molecules/layout/AppHeader/AppHeader.d.ts +1 -1
- package/dist/molecules/layout/AppHeader/AppHeader.d.ts.map +1 -1
- package/dist/molecules/layout/AppHeader/index.d.ts +1 -1
- package/dist/molecules/layout/BulkSelectionBar.d.ts +2 -2
- package/dist/molecules/layout/BulkSelectionBar.d.ts.map +1 -1
- package/dist/molecules/layout/DashboardWithSidePanel/DashboardWithSidePanel.d.ts +1 -1
- package/dist/molecules/layout/DashboardWithSidePanel/index.d.ts +1 -1
- package/dist/molecules/layout/NavigationContext.d.ts +3 -9
- package/dist/molecules/layout/NavigationContext.d.ts.map +1 -1
- package/dist/molecules/layout/PageTemplate.d.ts +1 -1
- package/dist/molecules/layout/PageTemplate.d.ts.map +1 -1
- package/dist/molecules/layout/SectionHeader/SectionHeader.d.ts +4 -4
- package/dist/molecules/layout/SectionHeader/SectionHeader.d.ts.map +1 -1
- package/dist/molecules/layout/SectionHeader/index.d.ts +1 -1
- package/dist/molecules/layout/ShowcaseSection.d.ts +4 -4
- package/dist/molecules/layout/ShowcaseSection.d.ts.map +1 -1
- package/dist/molecules/layout/Sidebar.d.ts.map +1 -1
- package/dist/molecules/layout/SidebarButton/SidebarButton.d.ts +1 -1
- package/dist/molecules/layout/SidebarButton/SidebarButton.d.ts.map +1 -1
- package/dist/molecules/layout/SidebarButton/index.d.ts +1 -1
- package/dist/molecules/layout/SidebarContext.d.ts +1 -8
- package/dist/molecules/layout/SidebarContext.d.ts.map +1 -1
- package/dist/molecules/layout/index.d.ts +14 -11
- package/dist/molecules/layout/index.d.ts.map +1 -1
- package/dist/molecules/layout/navigation-context.d.ts +9 -0
- package/dist/molecules/layout/navigation-context.d.ts.map +1 -0
- package/dist/molecules/layout/sidebar-context.d.ts +7 -0
- package/dist/molecules/layout/sidebar-context.d.ts.map +1 -0
- package/dist/molecules/layout/use-navigation.d.ts +2 -0
- package/dist/molecules/layout/use-navigation.d.ts.map +1 -0
- package/dist/molecules/layout/use-sidebar.d.ts +2 -0
- package/dist/molecules/layout/use-sidebar.d.ts.map +1 -0
- package/dist/molecules/navigation/NavMenu.d.ts +2 -2
- package/dist/molecules/navigation/NavMenu.d.ts.map +1 -1
- package/dist/molecules/navigation/Pagination.d.ts +2 -2
- package/dist/molecules/navigation/index.d.ts +2 -2
- package/dist/organisms/index.d.ts +1 -1
- package/dist/organisms/showcase/ComponentShowcasePage.d.ts +1 -1
- package/dist/organisms/showcase/ComponentShowcasePage.d.ts.map +1 -1
- package/dist/templates/AuthTemplate.d.ts +4 -4
- package/dist/templates/AuthTemplate.d.ts.map +1 -1
- package/dist/templates/ComponentShowcaseTemplate.d.ts +7 -7
- package/dist/templates/ComponentShowcaseTemplate.d.ts.map +1 -1
- package/dist/templates/DashboardTemplate.d.ts +3 -3
- package/dist/templates/DashboardTemplate.d.ts.map +1 -1
- package/dist/templates/DataTemplate.d.ts +3 -3
- package/dist/templates/DataTemplate.d.ts.map +1 -1
- package/dist/templates/EnhancedDataTemplate.d.ts +11 -11
- package/dist/templates/EnhancedDataTemplate.d.ts.map +1 -1
- package/dist/templates/EnhancedDataTemplate.hooks.bulk.d.ts +2 -2
- package/dist/templates/EnhancedDataTemplate.hooks.bulk.d.ts.map +1 -1
- package/dist/templates/EnhancedDataTemplate.hooks.d.ts +4 -4
- package/dist/templates/EnhancedDataTemplate.hooks.d.ts.map +1 -1
- package/dist/templates/admin/AdminCRUDTemplate.d.ts +4 -4
- package/dist/templates/admin/AdminCRUDTemplate.d.ts.map +1 -1
- package/dist/templates/admin/AdminDashboardTemplate.d.ts +7 -7
- package/dist/templates/admin/AdminDashboardTemplate.d.ts.map +1 -1
- package/dist/templates/admin/AdminDetailTemplate.d.ts +4 -4
- package/dist/templates/admin/AdminDetailTemplate.d.ts.map +1 -1
- package/dist/templates/admin/index.d.ts +3 -3
- package/dist/templates/admin/index.d.ts.map +1 -1
- package/dist/templates/api/APIDataTemplate.d.ts +14 -9
- package/dist/templates/api/APIDataTemplate.d.ts.map +1 -1
- package/dist/templates/api/create-api-data-template.d.ts +4 -0
- package/dist/templates/api/create-api-data-template.d.ts.map +1 -0
- package/dist/templates/api/index.d.ts +3 -2
- package/dist/templates/api/index.d.ts.map +1 -1
- package/dist/templates/factory.d.ts +3 -3
- package/dist/templates/factory.d.ts.map +1 -1
- package/dist/templates/index.d.ts +8 -8
- package/dist/templates/index.d.ts.map +1 -1
- package/package.json +10 -7
- package/LICENSE +0 -19
- package/cli/cli/commands/generate-hooks.js +0 -291
- package/cli/cli/commands/init.js +0 -25
- package/cli/cli/commands/scaffold.js +0 -201
- package/cli/cli/index.js +0 -113
- package/cli/commands/generate-hooks.js +0 -291
- package/cli/commands/init.js +0 -25
- package/cli/commands/scaffold.js +0 -201
- package/cli/index.js +0 -6665
- package/cli/src/codegen/openapi/bulk-hook-generator.js +0 -252
- package/cli/src/codegen/openapi/bulk-types.js +0 -89
- package/cli/src/codegen/openapi/confidence-scorer.js +0 -204
- package/cli/src/codegen/openapi/hook-config.js +0 -66
- package/dist/atoms/components/data/ActivityFeed/ActivityFeed.stories.d.ts +0 -38
- package/dist/atoms/components/data/ActivityFeed/ActivityFeed.stories.d.ts.map +0 -1
- package/dist/codegen/index.d.ts +0 -7
- package/dist/codegen/index.d.ts.map +0 -1
- package/dist/codegen/openapi/bulk-hook-generator.d.ts +0 -40
- package/dist/codegen/openapi/bulk-hook-generator.d.ts.map +0 -1
- package/dist/codegen/openapi/client-generator.d.ts +0 -52
- package/dist/codegen/openapi/client-generator.d.ts.map +0 -1
- package/dist/codegen/openapi/confidence-scorer.d.ts +0 -30
- package/dist/codegen/openapi/confidence-scorer.d.ts.map +0 -1
- package/dist/codegen/openapi/hook-config.d.ts +0 -50
- package/dist/codegen/openapi/hook-config.d.ts.map +0 -1
- package/dist/codegen/openapi/hook-generator.d.ts +0 -108
- package/dist/codegen/openapi/hook-generator.d.ts.map +0 -1
- package/dist/codegen/openapi/index.d.ts +0 -27
- package/dist/codegen/openapi/index.d.ts.map +0 -1
- package/dist/codegen/openapi/parser.d.ts +0 -107
- package/dist/codegen/openapi/parser.d.ts.map +0 -1
- package/dist/codegen/openapi/type-generator.d.ts +0 -53
- package/dist/codegen/openapi/type-generator.d.ts.map +0 -1
- package/dist/generated/client/client.d.ts +0 -23
- package/dist/generated/client/client.d.ts.map +0 -1
- package/dist/generated/client/config.d.ts +0 -10
- package/dist/generated/client/config.d.ts.map +0 -1
- package/dist/generated/client/index.d.ts +0 -12
- package/dist/generated/client/index.d.ts.map +0 -1
- package/dist/generated/client/methods.d.ts +0 -591
- package/dist/generated/client/methods.d.ts.map +0 -1
- package/dist/generated/client/types.d.ts +0 -37
- package/dist/generated/client/types.d.ts.map +0 -1
- package/dist/generated/example.d.ts +0 -8
- package/dist/generated/example.d.ts.map +0 -1
- package/dist/generated/hooks/index.d.ts +0 -11
- package/dist/generated/hooks/index.d.ts.map +0 -1
- package/dist/generated/hooks/keys.d.ts +0 -59
- package/dist/generated/hooks/keys.d.ts.map +0 -1
- package/dist/generated/hooks/mutations.d.ts +0 -551
- package/dist/generated/hooks/mutations.d.ts.map +0 -1
- package/dist/generated/hooks/queries.d.ts +0 -426
- package/dist/generated/hooks/queries.d.ts.map +0 -1
- package/dist/generated/hooks/types.d.ts +0 -318
- package/dist/generated/hooks/types.d.ts.map +0 -1
- package/dist/generated/index.d.ts +0 -13
- package/dist/generated/index.d.ts.map +0 -1
- package/dist/generated/types/endpoints.d.ts +0 -1364
- package/dist/generated/types/endpoints.d.ts.map +0 -1
- package/dist/generated/types/index.d.ts +0 -11
- package/dist/generated/types/index.d.ts.map +0 -1
- package/dist/generated/types/parameters.d.ts +0 -8
- package/dist/generated/types/parameters.d.ts.map +0 -1
- package/dist/generated/types/responses.d.ts +0 -8
- package/dist/generated/types/responses.d.ts.map +0 -1
- package/dist/generated/types/schemas.d.ts +0 -652
- package/dist/generated/types/schemas.d.ts.map +0 -1
|
@@ -1,4 +1,3 @@
|
|
|
1
|
-
"use strict";
|
|
2
1
|
/**
|
|
3
2
|
* React Hook Generator
|
|
4
3
|
*
|
|
@@ -7,17 +6,14 @@
|
|
|
7
6
|
*
|
|
8
7
|
* Part of FRO-3: React Hook Generator
|
|
9
8
|
*/
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
class ReactHookGenerator {
|
|
9
|
+
import { HookConfigManager } from './hook-config';
|
|
10
|
+
import { ConfidenceScorer } from './confidence-scorer';
|
|
11
|
+
export class ReactHookGenerator {
|
|
12
|
+
options;
|
|
13
|
+
configManager;
|
|
14
|
+
confidenceScorer;
|
|
15
|
+
scoredNames = [];
|
|
18
16
|
constructor(options = {}) {
|
|
19
|
-
this.scoredNames = [];
|
|
20
|
-
this.resourceConfigs = new Map();
|
|
21
17
|
this.options = {
|
|
22
18
|
queryKeyPrefix: options.queryKeyPrefix || 'api',
|
|
23
19
|
includeInfiniteQueries: options.includeInfiniteQueries !== false,
|
|
@@ -28,115 +24,13 @@ class ReactHookGenerator {
|
|
|
28
24
|
configPath: options.configPath || './hooks.config.json',
|
|
29
25
|
enableConfidenceScoring: options.enableConfidenceScoring ?? true
|
|
30
26
|
};
|
|
31
|
-
this.configManager = new
|
|
32
|
-
this.confidenceScorer = new
|
|
33
|
-
this.bulkHookGenerator = new bulk_hook_generator_1.BulkHookGenerator();
|
|
34
|
-
}
|
|
35
|
-
/**
|
|
36
|
-
* Detect resource operations from endpoints
|
|
37
|
-
*/
|
|
38
|
-
detectResourceOperations(endpoints) {
|
|
39
|
-
const resourceMap = new Map();
|
|
40
|
-
endpoints.forEach(endpoint => {
|
|
41
|
-
const resourceName = this.extractResourceName(endpoint.path);
|
|
42
|
-
if (!resourceName)
|
|
43
|
-
return;
|
|
44
|
-
const config = resourceMap.get(resourceName) || this.createDefaultConfig(resourceName);
|
|
45
|
-
// Check if this is a bulk operation
|
|
46
|
-
const requestBody = endpoint.requestBody;
|
|
47
|
-
if ((0, bulk_types_1.isBulkOperation)(endpoint.path, endpoint.method, requestBody)) {
|
|
48
|
-
const bulkType = detectBulkOperationType(endpoint.path, endpoint.method);
|
|
49
|
-
switch (bulkType) {
|
|
50
|
-
case 'delete':
|
|
51
|
-
config.operations.bulkDelete = {
|
|
52
|
-
path: endpoint.path,
|
|
53
|
-
method: endpoint.method
|
|
54
|
-
};
|
|
55
|
-
break;
|
|
56
|
-
case 'update':
|
|
57
|
-
config.operations.bulkUpdate = {
|
|
58
|
-
path: endpoint.path,
|
|
59
|
-
method: endpoint.method
|
|
60
|
-
};
|
|
61
|
-
break;
|
|
62
|
-
case 'create':
|
|
63
|
-
config.operations.bulkCreate = {
|
|
64
|
-
path: endpoint.path,
|
|
65
|
-
method: endpoint.method
|
|
66
|
-
};
|
|
67
|
-
break;
|
|
68
|
-
case 'mixed':
|
|
69
|
-
default:
|
|
70
|
-
if (!config.operations.customBulk) {
|
|
71
|
-
config.operations.customBulk = [];
|
|
72
|
-
}
|
|
73
|
-
config.operations.customBulk.push({
|
|
74
|
-
name: this.getOperationName(endpoint),
|
|
75
|
-
path: endpoint.path,
|
|
76
|
-
method: endpoint.method,
|
|
77
|
-
operationType: bulkType || 'mixed'
|
|
78
|
-
});
|
|
79
|
-
break;
|
|
80
|
-
}
|
|
81
|
-
}
|
|
82
|
-
else {
|
|
83
|
-
// Standard CRUD operations
|
|
84
|
-
switch (endpoint.method.toLowerCase()) {
|
|
85
|
-
case 'get':
|
|
86
|
-
if (endpoint.path.includes('{')) {
|
|
87
|
-
// Single resource fetch
|
|
88
|
-
}
|
|
89
|
-
else {
|
|
90
|
-
config.operations.list = { path: endpoint.path, method: endpoint.method };
|
|
91
|
-
}
|
|
92
|
-
break;
|
|
93
|
-
case 'post':
|
|
94
|
-
config.operations.create = { path: endpoint.path, method: endpoint.method };
|
|
95
|
-
break;
|
|
96
|
-
case 'put':
|
|
97
|
-
case 'patch':
|
|
98
|
-
config.operations.update = { path: endpoint.path, method: endpoint.method };
|
|
99
|
-
break;
|
|
100
|
-
case 'delete':
|
|
101
|
-
config.operations.delete = { path: endpoint.path, method: endpoint.method };
|
|
102
|
-
break;
|
|
103
|
-
}
|
|
104
|
-
}
|
|
105
|
-
resourceMap.set(resourceName, config);
|
|
106
|
-
});
|
|
107
|
-
return resourceMap;
|
|
108
|
-
}
|
|
109
|
-
/**
|
|
110
|
-
* Extract resource name from path
|
|
111
|
-
*/
|
|
112
|
-
extractResourceName(path) {
|
|
113
|
-
// Remove API version prefix
|
|
114
|
-
const cleanPath = path.replace(/^\/api\/v\d+\//, '/');
|
|
115
|
-
const segments = cleanPath.split('/').filter(Boolean);
|
|
116
|
-
// Find the first non-parameter segment
|
|
117
|
-
for (const segment of segments) {
|
|
118
|
-
if (!segment.startsWith('{')) {
|
|
119
|
-
return segment.replace(/-/g, '_');
|
|
120
|
-
}
|
|
121
|
-
}
|
|
122
|
-
return null;
|
|
123
|
-
}
|
|
124
|
-
/**
|
|
125
|
-
* Create default API config for a resource
|
|
126
|
-
*/
|
|
127
|
-
createDefaultConfig(resourceName) {
|
|
128
|
-
return {
|
|
129
|
-
baseURL: '',
|
|
130
|
-
resourceName,
|
|
131
|
-
operations: {}
|
|
132
|
-
};
|
|
27
|
+
this.configManager = new HookConfigManager(this.options.configPath);
|
|
28
|
+
this.confidenceScorer = new ConfidenceScorer();
|
|
133
29
|
}
|
|
134
30
|
async generate(parsedAPI) {
|
|
135
31
|
const endpoints = parsedAPI.endpoints;
|
|
136
32
|
// Load configuration
|
|
137
33
|
await this.configManager.load();
|
|
138
|
-
// Detect resource operations
|
|
139
|
-
this.resourceConfigs = this.detectResourceOperations(endpoints);
|
|
140
34
|
// Reset scored names for this generation
|
|
141
35
|
this.scoredNames = [];
|
|
142
36
|
const result = {
|
|
@@ -169,50 +63,15 @@ class ReactHookGenerator {
|
|
|
169
63
|
const hooks = [];
|
|
170
64
|
hooks.push(this.generateFileHeader('Query Hooks'));
|
|
171
65
|
hooks.push('');
|
|
172
|
-
hooks.push("import { useQuery, useInfiniteQuery,
|
|
66
|
+
hooks.push("import { useQuery, useInfiniteQuery, QueryOptions, InfiniteQueryOptions } from '@tanstack/react-query'");
|
|
173
67
|
hooks.push("import { apiClient } from '../client'");
|
|
174
68
|
hooks.push("import { queryKeys } from './keys'");
|
|
175
69
|
hooks.push("import * as Types from './types'");
|
|
176
70
|
hooks.push('');
|
|
177
71
|
// Filter GET endpoints for queries
|
|
178
72
|
const queryEndpoints = endpoints.filter(endpoint => endpoint.method === 'get');
|
|
179
|
-
// Track generated hook names to avoid duplicates
|
|
180
|
-
const generatedHooks = new Map();
|
|
181
73
|
for (const endpoint of queryEndpoints) {
|
|
182
|
-
|
|
183
|
-
// If we've already generated this hook, add suffix to differentiate
|
|
184
|
-
if (generatedHooks.has(hookName)) {
|
|
185
|
-
const existingEndpoint = generatedHooks.get(hookName);
|
|
186
|
-
// Determine which endpoint should get a suffix based on the path
|
|
187
|
-
const existingIsSimpler = existingEndpoint.path.split('/').filter(s => !s.startsWith('{')).length <
|
|
188
|
-
endpoint.path.split('/').filter(s => !s.startsWith('{')).length;
|
|
189
|
-
if (existingIsSimpler) {
|
|
190
|
-
// Current endpoint needs a suffix
|
|
191
|
-
const suffix = endpoint.path.includes('/{subcategory_id}') ? 'Single' : 'List';
|
|
192
|
-
hookName = `${hookName}${suffix}`;
|
|
193
|
-
}
|
|
194
|
-
else {
|
|
195
|
-
// Need to rename the existing hook that we already added
|
|
196
|
-
const existingSuffix = existingEndpoint.path.includes('/{subcategory_id}') ? 'Single' : 'List';
|
|
197
|
-
const existingHookName = hookName;
|
|
198
|
-
const newExistingHookName = `${existingHookName}${existingSuffix}`;
|
|
199
|
-
// Find and update the existing hook in our output
|
|
200
|
-
for (let i = hooks.length - 1; i >= 0; i--) {
|
|
201
|
-
if (hooks[i].includes(`function ${existingHookName}(`)) {
|
|
202
|
-
hooks[i] = hooks[i].replace(`function ${existingHookName}(`, `function ${newExistingHookName}(`);
|
|
203
|
-
// Also update the JSDoc if it references the hook name
|
|
204
|
-
if (i > 0 && hooks[i - 1].includes(`${existingHookName}`)) {
|
|
205
|
-
hooks[i - 1] = hooks[i - 1].replace(existingHookName, newExistingHookName);
|
|
206
|
-
}
|
|
207
|
-
break;
|
|
208
|
-
}
|
|
209
|
-
}
|
|
210
|
-
// Update our tracking map
|
|
211
|
-
generatedHooks.delete(existingHookName);
|
|
212
|
-
generatedHooks.set(newExistingHookName, existingEndpoint);
|
|
213
|
-
}
|
|
214
|
-
}
|
|
215
|
-
generatedHooks.set(hookName, endpoint);
|
|
74
|
+
const hookName = this.generateQueryHookName(endpoint);
|
|
216
75
|
const hook = this.generateQueryHook(endpoint, hookName);
|
|
217
76
|
hooks.push(hook);
|
|
218
77
|
hooks.push('');
|
|
@@ -241,24 +100,21 @@ class ReactHookGenerator {
|
|
|
241
100
|
lines.push(' */');
|
|
242
101
|
// Generate hook signature
|
|
243
102
|
const paramType = hasParams ? this.generateParamType(endpoint) : '';
|
|
244
|
-
const params = hasParams ? `params: ${paramType}, options?:
|
|
103
|
+
const params = hasParams ? `params: ${paramType}, options?: QueryOptions` : 'options?: QueryOptions = {}';
|
|
245
104
|
lines.push(`export function ${hookName}(${params}) {`);
|
|
246
105
|
// Generate hook body
|
|
247
|
-
// Extract the query key name from the hook name (remove 'use' prefix)
|
|
248
|
-
const queryKeyName = hookName.replace(/^use/, '');
|
|
249
|
-
const queryKeyNameCamelCase = queryKeyName.charAt(0).toLowerCase() + queryKeyName.slice(1);
|
|
250
106
|
const queryKeyCall = hasParams ?
|
|
251
|
-
`queryKeys.${
|
|
252
|
-
`queryKeys.${
|
|
107
|
+
`queryKeys.${this.camelCase(operationName)}(params)` :
|
|
108
|
+
`queryKeys.${this.camelCase(operationName)}()`;
|
|
253
109
|
const apiCall = hasParams ?
|
|
254
110
|
`() => apiClient.${this.camelCase(operationName)}(params)` :
|
|
255
111
|
`() => apiClient.${this.camelCase(operationName)}()`;
|
|
256
112
|
lines.push(' return useQuery({');
|
|
257
113
|
lines.push(` queryKey: ${queryKeyCall},`);
|
|
258
114
|
lines.push(` queryFn: ${apiCall},`);
|
|
259
|
-
|
|
260
|
-
|
|
261
|
-
|
|
115
|
+
if (this.options.authenticationRequired) {
|
|
116
|
+
lines.push(' enabled: !!authToken && (options?.enabled ?? true),');
|
|
117
|
+
}
|
|
262
118
|
lines.push(' ...options');
|
|
263
119
|
lines.push(' })');
|
|
264
120
|
lines.push('}');
|
|
@@ -272,18 +128,14 @@ class ReactHookGenerator {
|
|
|
272
128
|
lines.push(` * Infinite query version of ${baseHookName}`);
|
|
273
129
|
lines.push(' */');
|
|
274
130
|
const paramType = this.generateParamType(endpoint);
|
|
275
|
-
|
|
276
|
-
const queryKeyName = baseHookName.replace(/^use/, '');
|
|
277
|
-
const queryKeyNameCamelCase = queryKeyName.charAt(0).toLowerCase() + queryKeyName.slice(1);
|
|
278
|
-
lines.push(`export function ${hookName}(params: ${paramType}, options?: UseInfiniteQueryOptions<any, any, any, any, any>) {`);
|
|
131
|
+
lines.push(`export function ${hookName}(params: ${paramType}, options?: InfiniteQueryOptions) {`);
|
|
279
132
|
lines.push(' return useInfiniteQuery({');
|
|
280
|
-
lines.push(` queryKey:
|
|
133
|
+
lines.push(` queryKey: queryKeys.${this.camelCase(operationName)}(params),`);
|
|
281
134
|
lines.push(` queryFn: ({ pageParam = 1 }) => apiClient.${this.camelCase(operationName)}({ ...params, page: pageParam }),`);
|
|
282
135
|
lines.push(' getNextPageParam: (lastPage, allPages) => {');
|
|
283
136
|
lines.push(' // Implement pagination logic based on your API response structure');
|
|
284
137
|
lines.push(' return lastPage?.hasNextPage ? allPages.length + 1 : undefined');
|
|
285
138
|
lines.push(' },');
|
|
286
|
-
lines.push(' initialPageParam: 1,');
|
|
287
139
|
lines.push(' ...options');
|
|
288
140
|
lines.push(' })');
|
|
289
141
|
lines.push('}');
|
|
@@ -293,33 +145,16 @@ class ReactHookGenerator {
|
|
|
293
145
|
const hooks = [];
|
|
294
146
|
hooks.push(this.generateFileHeader('Mutation Hooks'));
|
|
295
147
|
hooks.push('');
|
|
296
|
-
hooks.push("import { useMutation, useQueryClient,
|
|
148
|
+
hooks.push("import { useMutation, useQueryClient, MutationOptions } from '@tanstack/react-query'");
|
|
297
149
|
hooks.push("import { apiClient } from '../client'");
|
|
298
150
|
hooks.push("import { queryKeys } from './keys'");
|
|
299
151
|
hooks.push("import * as Types from './types'");
|
|
300
|
-
hooks.push("import type { BulkOperationRequest, BulkOperationResponse, BulkOperationProgress, BulkMutationOptions } from '../bulk-types'");
|
|
301
152
|
hooks.push('');
|
|
302
153
|
// Filter non-GET endpoints for mutations
|
|
303
154
|
const mutationEndpoints = endpoints.filter(endpoint => endpoint.method !== 'get');
|
|
304
|
-
// Track generated hook names to avoid duplicates
|
|
305
|
-
const generatedHooks = new Map();
|
|
306
155
|
for (const endpoint of mutationEndpoints) {
|
|
307
|
-
|
|
308
|
-
const
|
|
309
|
-
const isBulk = (0, bulk_types_1.isBulkOperation)(endpoint.path, endpoint.method, requestBody);
|
|
310
|
-
let hookName = this.generateMutationHookName(endpoint);
|
|
311
|
-
// If we've already generated this hook, add suffix to differentiate
|
|
312
|
-
if (generatedHooks.has(hookName)) {
|
|
313
|
-
const existingEndpoint = generatedHooks.get(hookName);
|
|
314
|
-
// Add method suffix to differentiate
|
|
315
|
-
const methodSuffix = endpoint.method.charAt(0).toUpperCase() + endpoint.method.slice(1);
|
|
316
|
-
hookName = `${hookName}${methodSuffix}`;
|
|
317
|
-
}
|
|
318
|
-
generatedHooks.set(hookName, endpoint);
|
|
319
|
-
// Generate appropriate hook based on type
|
|
320
|
-
const hook = isBulk
|
|
321
|
-
? this.bulkHookGenerator.generateBulkMutationHook(endpoint, hookName, this.getOperationName(endpoint))
|
|
322
|
-
: this.generateMutationHook(endpoint, hookName);
|
|
156
|
+
const hookName = this.generateMutationHookName(endpoint);
|
|
157
|
+
const hook = this.generateMutationHook(endpoint, hookName);
|
|
323
158
|
hooks.push(hook);
|
|
324
159
|
hooks.push('');
|
|
325
160
|
}
|
|
@@ -339,7 +174,7 @@ class ReactHookGenerator {
|
|
|
339
174
|
lines.push(' */');
|
|
340
175
|
// Generate hook signature
|
|
341
176
|
const mutationType = this.generateMutationType(endpoint);
|
|
342
|
-
lines.push(`export function ${hookName}(options?:
|
|
177
|
+
lines.push(`export function ${hookName}(options?: MutationOptions<any, any, ${mutationType}>) {`);
|
|
343
178
|
lines.push(' const queryClient = useQueryClient()');
|
|
344
179
|
lines.push('');
|
|
345
180
|
lines.push(' return useMutation({');
|
|
@@ -363,97 +198,56 @@ class ReactHookGenerator {
|
|
|
363
198
|
}
|
|
364
199
|
generateOptimisticUpdate(endpoint) {
|
|
365
200
|
const method = endpoint.method.toLowerCase();
|
|
366
|
-
const resource = endpoint.tags?.[0] || 'default';
|
|
367
|
-
const hasPathParams = endpoint.parameters.some(p => p.in === 'path');
|
|
368
201
|
switch (method) {
|
|
369
202
|
case 'post':
|
|
370
|
-
return ` onMutate: async (
|
|
203
|
+
return ` onMutate: async (newData) => {
|
|
371
204
|
// Cancel outgoing refetches
|
|
372
|
-
await queryClient.cancelQueries({ queryKey: queryKeys
|
|
205
|
+
await queryClient.cancelQueries({ queryKey: queryKeys.all })
|
|
373
206
|
|
|
374
207
|
// Snapshot previous value
|
|
375
|
-
const previousData = queryClient.getQueryData(queryKeys
|
|
208
|
+
const previousData = queryClient.getQueryData(queryKeys.all)
|
|
376
209
|
|
|
377
210
|
// Optimistically update cache
|
|
378
|
-
queryClient.setQueryData(queryKeys
|
|
379
|
-
if (Array.isArray(old)) {
|
|
380
|
-
return [...old, data]
|
|
381
|
-
}
|
|
382
|
-
return old
|
|
383
|
-
})
|
|
211
|
+
queryClient.setQueryData(queryKeys.all, (old: any) => [...(old || []), newData])
|
|
384
212
|
|
|
385
213
|
return { previousData }
|
|
386
214
|
},
|
|
387
|
-
onError: (err
|
|
215
|
+
onError: (err, newData, context) => {
|
|
388
216
|
// Rollback on error
|
|
389
|
-
|
|
390
|
-
queryClient.setQueryData(queryKeys.${resource}(), context.previousData)
|
|
391
|
-
}
|
|
217
|
+
queryClient.setQueryData(queryKeys.all, context?.previousData)
|
|
392
218
|
},`;
|
|
393
219
|
case 'put':
|
|
394
220
|
case 'patch':
|
|
395
|
-
|
|
396
|
-
|
|
397
|
-
await queryClient.cancelQueries({ queryKey: queryKeys.${resource}() })
|
|
221
|
+
return ` onMutate: async (updatedData) => {
|
|
222
|
+
await queryClient.cancelQueries({ queryKey: queryKeys.all })
|
|
398
223
|
|
|
399
|
-
const previousData = queryClient.getQueryData(queryKeys
|
|
224
|
+
const previousData = queryClient.getQueryData(queryKeys.all)
|
|
400
225
|
|
|
401
226
|
// Update specific item in cache
|
|
402
|
-
queryClient.setQueryData(queryKeys
|
|
403
|
-
|
|
404
|
-
|
|
405
|
-
item.id === data.pathParams?.id || item.id === data.pathParams?.${resource.slice(0, -1)}_id
|
|
406
|
-
? { ...item, ...data }
|
|
407
|
-
: item
|
|
408
|
-
)
|
|
409
|
-
}
|
|
410
|
-
return old
|
|
411
|
-
})
|
|
412
|
-
|
|
413
|
-
return { previousData }
|
|
414
|
-
},
|
|
415
|
-
onError: (err: any, data: any, context: any) => {
|
|
416
|
-
if (context?.previousData !== undefined) {
|
|
417
|
-
queryClient.setQueryData(queryKeys.${resource}(), context.previousData)
|
|
418
|
-
}
|
|
419
|
-
},`;
|
|
420
|
-
}
|
|
421
|
-
return ` onMutate: async (data: any) => {
|
|
422
|
-
await queryClient.cancelQueries({ queryKey: queryKeys.${resource}() })
|
|
423
|
-
|
|
424
|
-
const previousData = queryClient.getQueryData(queryKeys.${resource}())
|
|
425
|
-
|
|
426
|
-
// Update cache with new data
|
|
427
|
-
queryClient.setQueryData(queryKeys.${resource}(), data)
|
|
227
|
+
queryClient.setQueryData(queryKeys.all, (old: any) =>
|
|
228
|
+
old?.map((item: any) => item.id === updatedData.id ? { ...item, ...updatedData } : item)
|
|
229
|
+
)
|
|
428
230
|
|
|
429
231
|
return { previousData }
|
|
430
232
|
},
|
|
431
|
-
onError: (err
|
|
432
|
-
|
|
433
|
-
queryClient.setQueryData(queryKeys.${resource}(), context.previousData)
|
|
434
|
-
}
|
|
233
|
+
onError: (err, updatedData, context) => {
|
|
234
|
+
queryClient.setQueryData(queryKeys.all, context?.previousData)
|
|
435
235
|
},`;
|
|
436
236
|
case 'delete':
|
|
437
|
-
return ` onMutate: async (
|
|
438
|
-
await queryClient.cancelQueries({ queryKey: queryKeys
|
|
237
|
+
return ` onMutate: async (id) => {
|
|
238
|
+
await queryClient.cancelQueries({ queryKey: queryKeys.all })
|
|
439
239
|
|
|
440
|
-
const previousData = queryClient.getQueryData(queryKeys
|
|
240
|
+
const previousData = queryClient.getQueryData(queryKeys.all)
|
|
441
241
|
|
|
442
242
|
// Remove item from cache
|
|
443
|
-
queryClient.setQueryData(queryKeys
|
|
444
|
-
|
|
445
|
-
|
|
446
|
-
return old.filter((item: any) => item.id !== idToDelete)
|
|
447
|
-
}
|
|
448
|
-
return old
|
|
449
|
-
})
|
|
243
|
+
queryClient.setQueryData(queryKeys.all, (old: any) =>
|
|
244
|
+
old?.filter((item: any) => item.id !== id)
|
|
245
|
+
)
|
|
450
246
|
|
|
451
247
|
return { previousData }
|
|
452
248
|
},
|
|
453
|
-
onError: (err
|
|
454
|
-
|
|
455
|
-
queryClient.setQueryData(queryKeys.${resource}(), context.previousData)
|
|
456
|
-
}
|
|
249
|
+
onError: (err, id, context) => {
|
|
250
|
+
queryClient.setQueryData(queryKeys.all, context?.previousData)
|
|
457
251
|
},`;
|
|
458
252
|
default:
|
|
459
253
|
return '';
|
|
@@ -463,7 +257,7 @@ class ReactHookGenerator {
|
|
|
463
257
|
const relatedTags = this.getRelatedQueryTags(endpoint);
|
|
464
258
|
return ` onSettled: () => {
|
|
465
259
|
// Invalidate related queries
|
|
466
|
-
${relatedTags.map(tag => `queryClient.invalidateQueries({ queryKey: queryKeys.${tag}
|
|
260
|
+
${relatedTags.map(tag => `queryClient.invalidateQueries({ queryKey: queryKeys.${tag} })`).join('\n ')}
|
|
467
261
|
},`;
|
|
468
262
|
}
|
|
469
263
|
generateQueryKeys(endpoints) {
|
|
@@ -483,46 +277,11 @@ class ReactHookGenerator {
|
|
|
483
277
|
for (const [resource, resourceEndpoints] of Object.entries(groupedEndpoints)) {
|
|
484
278
|
keys.push(` // ${resource} keys`);
|
|
485
279
|
keys.push(` ${resource}: () => [...queryKeys.all, '${resource}'] as const,`);
|
|
486
|
-
// Track generated key names to avoid duplicates
|
|
487
|
-
const generatedKeys = new Map();
|
|
488
280
|
for (const endpoint of resourceEndpoints) {
|
|
489
281
|
if (endpoint.method !== 'get')
|
|
490
282
|
continue;
|
|
491
283
|
const operationName = this.getOperationName(endpoint);
|
|
492
|
-
|
|
493
|
-
// If we've already generated this key, add suffix to differentiate
|
|
494
|
-
if (generatedKeys.has(keyName)) {
|
|
495
|
-
const existingEndpoint = generatedKeys.get(keyName);
|
|
496
|
-
// Determine which endpoint should get a suffix based on the path
|
|
497
|
-
// The one with a single resource gets the plain name, the one with sub-resources gets a suffix
|
|
498
|
-
const existingIsSimpler = existingEndpoint.path.split('/').filter(s => !s.startsWith('{')).length <
|
|
499
|
-
endpoint.path.split('/').filter(s => !s.startsWith('{')).length;
|
|
500
|
-
if (existingIsSimpler) {
|
|
501
|
-
// Current endpoint needs a suffix
|
|
502
|
-
const suffix = endpoint.path.includes('/{subcategory_id}') ? 'Single' : 'List';
|
|
503
|
-
keyName = `${keyName}${suffix}`;
|
|
504
|
-
}
|
|
505
|
-
else {
|
|
506
|
-
// Update the existing key with a suffix
|
|
507
|
-
const existingSuffix = existingEndpoint.path.includes('/{subcategory_id}') ? 'Single' : 'List';
|
|
508
|
-
const existingKeyName = keyName;
|
|
509
|
-
const newExistingKeyName = `${existingKeyName}${existingSuffix}`;
|
|
510
|
-
// Find and update the existing key in our output
|
|
511
|
-
for (let i = keys.length - 1; i >= 0; i--) {
|
|
512
|
-
if (keys[i].includes(`${existingKeyName}:`)) {
|
|
513
|
-
// Replace both the function name and the cache key string
|
|
514
|
-
keys[i] = keys[i]
|
|
515
|
-
.replace(`${existingKeyName}:`, `${newExistingKeyName}:`)
|
|
516
|
-
.replace(`'${existingKeyName}'`, `'${newExistingKeyName}'`);
|
|
517
|
-
break;
|
|
518
|
-
}
|
|
519
|
-
}
|
|
520
|
-
// Update our tracking map
|
|
521
|
-
generatedKeys.delete(existingKeyName);
|
|
522
|
-
generatedKeys.set(newExistingKeyName, existingEndpoint);
|
|
523
|
-
}
|
|
524
|
-
}
|
|
525
|
-
generatedKeys.set(keyName, endpoint);
|
|
284
|
+
const keyName = this.camelCase(operationName.replace(/^get/, ''));
|
|
526
285
|
if (this.hasRequiredParams(endpoint)) {
|
|
527
286
|
keys.push(` ${keyName}: (params: any) => [...queryKeys.${resource}(), '${keyName}', params] as const,`);
|
|
528
287
|
}
|
|
@@ -539,31 +298,20 @@ class ReactHookGenerator {
|
|
|
539
298
|
const types = [];
|
|
540
299
|
types.push(this.generateFileHeader('Hook Types'));
|
|
541
300
|
types.push('');
|
|
542
|
-
types.push(
|
|
543
|
-
types.push("export type { BulkOperationRequest, BulkOperationResponse, BulkOperationProgress, BulkMutationOptions } from '../bulk-types'");
|
|
301
|
+
types.push("import { QueryOptions, MutationOptions, InfiniteQueryOptions } from '@tanstack/react-query'");
|
|
544
302
|
types.push('');
|
|
545
|
-
// Track generated type names to avoid duplicates
|
|
546
|
-
const generatedTypes = new Set();
|
|
547
303
|
// Generate parameter and response types for hooks
|
|
548
304
|
for (const endpoint of endpoints) {
|
|
549
305
|
const operationName = this.getOperationName(endpoint);
|
|
550
306
|
if (this.hasRequiredParams(endpoint)) {
|
|
551
|
-
const
|
|
552
|
-
|
|
553
|
-
|
|
554
|
-
const paramType = this.generateParamType(endpoint);
|
|
555
|
-
types.push(`export interface ${typeName} ${paramType}`);
|
|
556
|
-
types.push('');
|
|
557
|
-
}
|
|
307
|
+
const paramType = this.generateParamType(endpoint);
|
|
308
|
+
types.push(`export interface ${this.capitalize(operationName)}Params ${paramType}`);
|
|
309
|
+
types.push('');
|
|
558
310
|
}
|
|
559
311
|
if (endpoint.method !== 'get') {
|
|
560
|
-
const
|
|
561
|
-
|
|
562
|
-
|
|
563
|
-
const mutationType = this.generateMutationType(endpoint);
|
|
564
|
-
types.push(`export interface ${typeName} ${mutationType}`);
|
|
565
|
-
types.push('');
|
|
566
|
-
}
|
|
312
|
+
const mutationType = this.generateMutationType(endpoint);
|
|
313
|
+
types.push(`export interface ${this.capitalize(operationName)}Data ${mutationType}`);
|
|
314
|
+
types.push('');
|
|
567
315
|
}
|
|
568
316
|
}
|
|
569
317
|
return types.join('\n');
|
|
@@ -599,14 +347,6 @@ class ReactHookGenerator {
|
|
|
599
347
|
}
|
|
600
348
|
generateMutationHookName(endpoint) {
|
|
601
349
|
const operationName = this.getOperationName(endpoint);
|
|
602
|
-
// Check if this is a bulk operation
|
|
603
|
-
const resourceName = this.extractResourceName(endpoint.path);
|
|
604
|
-
if (resourceName) {
|
|
605
|
-
const bulkHookName = this.bulkHookGenerator.generateBulkMutationHookName(endpoint, resourceName);
|
|
606
|
-
if (bulkHookName) {
|
|
607
|
-
return bulkHookName;
|
|
608
|
-
}
|
|
609
|
-
}
|
|
610
350
|
return `use${this.capitalize(operationName)}`;
|
|
611
351
|
}
|
|
612
352
|
getOperationName(endpoint) {
|
|
@@ -659,217 +399,164 @@ class ReactHookGenerator {
|
|
|
659
399
|
cleanOperationId(operationId, endpoint) {
|
|
660
400
|
// Parse the operation ID into components
|
|
661
401
|
const parsed = this.parseOperationId(operationId, endpoint);
|
|
662
|
-
//
|
|
663
|
-
|
|
402
|
+
// Check if it's a custom action endpoint
|
|
403
|
+
if (parsed.isCustomAction) {
|
|
404
|
+
return this.formatCustomActionName(parsed);
|
|
405
|
+
}
|
|
406
|
+
// Check if it's a special endpoint that should keep its verb
|
|
407
|
+
if (this.isSpecialEndpoint(parsed)) {
|
|
408
|
+
return this.formatSpecialEndpointName(parsed);
|
|
409
|
+
}
|
|
410
|
+
// Format standard CRUD operation
|
|
411
|
+
return this.formatStandardOperationName(parsed, endpoint);
|
|
664
412
|
}
|
|
665
413
|
/**
|
|
666
414
|
* Parse operation ID into structured components
|
|
667
415
|
*/
|
|
668
416
|
parseOperationId(operationId, endpoint) {
|
|
669
|
-
//
|
|
670
|
-
const
|
|
671
|
-
|
|
672
|
-
|
|
673
|
-
|
|
674
|
-
|
|
675
|
-
|
|
676
|
-
|
|
677
|
-
|
|
678
|
-
|
|
417
|
+
// Common patterns for operation IDs
|
|
418
|
+
const patterns = [
|
|
419
|
+
// Pattern: action_resource_api_v1_path_segments_method
|
|
420
|
+
/^(?<action>\w+?)_(?<resource>\w+?)_api_v\d+_(?<path>.+?)_(?<method>get|post|put|patch|delete)$/i,
|
|
421
|
+
// Pattern: action_api_v1_path_segments_method
|
|
422
|
+
/^(?<action>\w+?)_api_v\d+_(?<path>.+?)_(?<method>get|post|put|patch|delete)$/i,
|
|
423
|
+
// Pattern: action_resource_path_method
|
|
424
|
+
/^(?<action>\w+?)_(?<resource>\w+?)_(?<path>.+?)_(?<method>get|post|put|patch|delete)$/i,
|
|
425
|
+
// Pattern: simple action_resource
|
|
426
|
+
/^(?<action>\w+?)_(?<resource>\w+?)$/i,
|
|
427
|
+
];
|
|
428
|
+
let components = {};
|
|
429
|
+
for (const pattern of patterns) {
|
|
430
|
+
const match = operationId.match(pattern);
|
|
431
|
+
if (match && match.groups) {
|
|
432
|
+
components = match.groups;
|
|
433
|
+
break;
|
|
434
|
+
}
|
|
435
|
+
}
|
|
436
|
+
// Extract path information
|
|
437
|
+
const pathSegments = endpoint.path.split('/').filter(s => s && !s.startsWith('{'));
|
|
438
|
+
const lastPathSegment = pathSegments[pathSegments.length - 1]?.replace(/-/g, '_');
|
|
679
439
|
// Check if it's a custom action
|
|
680
|
-
const
|
|
681
|
-
const lastSegment =
|
|
682
|
-
const isCustomAction = !lastSegment.startsWith('{') &&
|
|
440
|
+
const urlSegments = endpoint.path.split('/');
|
|
441
|
+
const lastSegment = urlSegments[urlSegments.length - 1];
|
|
442
|
+
const isCustomAction = !lastSegment.startsWith('{') && urlSegments[urlSegments.length - 2]?.startsWith('{');
|
|
443
|
+
// Extract or infer the action verb
|
|
444
|
+
const actionVerb = this.extractActionVerb(components.action || operationId, endpoint.method);
|
|
445
|
+
// Extract or infer the resource
|
|
446
|
+
const resource = components.resource ||
|
|
447
|
+
this.extractResourceFromPath(endpoint.path) ||
|
|
448
|
+
lastPathSegment ||
|
|
449
|
+
'resource';
|
|
683
450
|
return {
|
|
684
|
-
action:
|
|
685
|
-
resource:
|
|
686
|
-
|
|
451
|
+
action: actionVerb,
|
|
452
|
+
resource: resource,
|
|
453
|
+
path: components.path || '',
|
|
687
454
|
method: endpoint.method,
|
|
688
455
|
isCustomAction,
|
|
689
456
|
customActionName: isCustomAction ? lastSegment.replace(/-/g, '_') : undefined,
|
|
690
|
-
originalId: operationId
|
|
691
|
-
prefix: prefix?.fullPrefix || '',
|
|
692
|
-
resources
|
|
457
|
+
originalId: operationId
|
|
693
458
|
};
|
|
694
459
|
}
|
|
695
460
|
/**
|
|
696
|
-
* Extract
|
|
461
|
+
* Extract the primary action verb from the operation ID
|
|
697
462
|
*/
|
|
698
|
-
|
|
699
|
-
|
|
700
|
-
|
|
701
|
-
// For extracting the prefix, use the original operation ID
|
|
702
|
-
const originalId = endpoint.operationId || '';
|
|
703
|
-
// Check if first part is a known action
|
|
704
|
-
const knownActions = [
|
|
463
|
+
extractActionVerb(actionPart, method) {
|
|
464
|
+
// Common action verbs to recognize
|
|
465
|
+
const actionVerbs = [
|
|
705
466
|
'login', 'logout', 'register', 'signup', 'signin',
|
|
706
|
-
'
|
|
707
|
-
'
|
|
467
|
+
'health', 'status', 'check',
|
|
468
|
+
'list', 'get', 'create', 'update', 'delete',
|
|
469
|
+
'reassign', 'assign', 'settle', 'reconcile',
|
|
470
|
+
'approve', 'reject', 'archive', 'restore',
|
|
471
|
+
'sync', 'refresh', 'reset', 'verify', 'validate'
|
|
708
472
|
];
|
|
709
|
-
|
|
710
|
-
|
|
711
|
-
|
|
712
|
-
if (
|
|
713
|
-
|
|
714
|
-
const match = originalId.match(/^get_(.+?)_api_v\d+/);
|
|
715
|
-
if (match) {
|
|
716
|
-
const compoundName = match[1];
|
|
717
|
-
if (compoundName === 'health_status' || compoundName === 'current_user_info') {
|
|
718
|
-
return {
|
|
719
|
-
action: firstPart,
|
|
720
|
-
fullPrefix: `${firstPart}_${compoundName}`
|
|
721
|
-
};
|
|
722
|
-
}
|
|
723
|
-
}
|
|
724
|
-
}
|
|
725
|
-
// Look for compound actions like "assign_roles" or "reassign_budget"
|
|
726
|
-
if (parts.length > 1 && ['assign', 'reassign'].includes(firstPart)) {
|
|
727
|
-
// Special case for reassign_transaction_budget
|
|
728
|
-
if (firstPart === 'reassign' && parts[1] === 'transaction' && parts[2] === 'budget') {
|
|
729
|
-
return {
|
|
730
|
-
action: 'reassign',
|
|
731
|
-
fullPrefix: 'reassign_budget'
|
|
732
|
-
};
|
|
733
|
-
}
|
|
734
|
-
return {
|
|
735
|
-
action: firstPart,
|
|
736
|
-
fullPrefix: `${parts[0]}_${parts[1]}`
|
|
737
|
-
};
|
|
738
|
-
}
|
|
739
|
-
return {
|
|
740
|
-
action: firstPart,
|
|
741
|
-
fullPrefix: parts[0]
|
|
742
|
-
};
|
|
743
|
-
}
|
|
744
|
-
return null;
|
|
745
|
-
}
|
|
746
|
-
/**
|
|
747
|
-
* Extract resources from API path
|
|
748
|
-
*/
|
|
749
|
-
extractResourcesFromPath(path) {
|
|
750
|
-
// Remove API version prefix
|
|
751
|
-
const cleanPath = path.replace(/^\/api\/v\d+\//, '/');
|
|
752
|
-
const segments = cleanPath.split('/').filter(Boolean);
|
|
753
|
-
const resources = [];
|
|
754
|
-
let lastHasParam = false;
|
|
755
|
-
for (let i = 0; i < segments.length; i++) {
|
|
756
|
-
if (!segments[i].startsWith('{')) {
|
|
757
|
-
resources.push(segments[i].replace(/-/g, '_'));
|
|
758
|
-
}
|
|
759
|
-
else if (i === segments.length - 1) {
|
|
760
|
-
lastHasParam = true;
|
|
473
|
+
// Check if the action part starts with any known verb
|
|
474
|
+
const lowerAction = actionPart.toLowerCase();
|
|
475
|
+
for (const verb of actionVerbs) {
|
|
476
|
+
if (lowerAction.startsWith(verb)) {
|
|
477
|
+
return verb;
|
|
761
478
|
}
|
|
762
479
|
}
|
|
763
|
-
|
|
764
|
-
|
|
765
|
-
|
|
766
|
-
|
|
480
|
+
// Default to HTTP method mapping
|
|
481
|
+
const methodMap = {
|
|
482
|
+
get: 'get',
|
|
483
|
+
post: 'create',
|
|
484
|
+
put: 'update',
|
|
485
|
+
patch: 'update',
|
|
486
|
+
delete: 'delete'
|
|
767
487
|
};
|
|
488
|
+
return methodMap[method] || method;
|
|
768
489
|
}
|
|
769
490
|
/**
|
|
770
|
-
*
|
|
491
|
+
* Extract resource name from the API path
|
|
771
492
|
*/
|
|
772
|
-
|
|
773
|
-
|
|
774
|
-
|
|
775
|
-
|
|
776
|
-
|
|
777
|
-
|
|
778
|
-
// Handle compound GET operations (e.g., get_health_status, get_current_user_info)
|
|
779
|
-
if (parsed.prefix && parsed.prefix.startsWith('get_') && parsed.prefix.includes('_')) {
|
|
780
|
-
const withoutGet = parsed.prefix.substring(4); // Remove "get_"
|
|
781
|
-
// Return the compound name without "get_" prefix
|
|
782
|
-
if (withoutGet === 'health_status' || withoutGet === 'current_user_info') {
|
|
783
|
-
return withoutGet;
|
|
784
|
-
}
|
|
785
|
-
}
|
|
786
|
-
// Handle custom actions with meaningful prefixes
|
|
787
|
-
if (parsed.prefix && this.isMeaningfulPrefix(parsed.prefix, parsed.resources)) {
|
|
788
|
-
return this.formatWithPrefix(parsed);
|
|
789
|
-
}
|
|
790
|
-
// Standard REST conventions
|
|
791
|
-
return this.formatStandardOperation(parsed, endpoint);
|
|
493
|
+
extractResourceFromPath(path) {
|
|
494
|
+
const segments = path.split('/').filter(s => s && !s.startsWith('{'));
|
|
495
|
+
// Skip common prefixes
|
|
496
|
+
const filtered = segments.filter(s => !['api', 'v1', 'v2'].includes(s));
|
|
497
|
+
// Return the last meaningful segment
|
|
498
|
+
return filtered[filtered.length - 1]?.replace(/-/g, '_') || null;
|
|
792
499
|
}
|
|
793
500
|
/**
|
|
794
|
-
* Check if
|
|
501
|
+
* Check if this is a special endpoint that should keep its action verb
|
|
795
502
|
*/
|
|
796
|
-
|
|
797
|
-
const
|
|
798
|
-
|
|
799
|
-
|
|
800
|
-
|
|
801
|
-
|
|
802
|
-
return false;
|
|
803
|
-
if (prefix === `list_${resources.primary}`)
|
|
804
|
-
return false;
|
|
805
|
-
// Meaningful if it's a custom action
|
|
806
|
-
return ['assign', 'reassign', 'verify', 'validate', 'sync', 'refresh'].includes(action);
|
|
503
|
+
isSpecialEndpoint(parsed) {
|
|
504
|
+
const specialActions = [
|
|
505
|
+
'login', 'logout', 'register', 'signup', 'signin',
|
|
506
|
+
'health', 'status', 'check', 'verify', 'validate'
|
|
507
|
+
];
|
|
508
|
+
return specialActions.includes(parsed.action);
|
|
807
509
|
}
|
|
808
510
|
/**
|
|
809
|
-
* Format name
|
|
511
|
+
* Format name for custom action endpoints
|
|
810
512
|
*/
|
|
811
|
-
|
|
812
|
-
const {
|
|
813
|
-
|
|
814
|
-
|
|
815
|
-
|
|
816
|
-
|
|
817
|
-
|
|
818
|
-
// For reassign_budget on transactions
|
|
819
|
-
if (action === 'reassign' && subject === 'budget') {
|
|
820
|
-
return `reassign_${this.singularize(resources.primary)}_budget`;
|
|
513
|
+
formatCustomActionName(parsed) {
|
|
514
|
+
const { action, resource, customActionName } = parsed;
|
|
515
|
+
// For custom actions like "reassign-budget", format as "reassign_budget"
|
|
516
|
+
if (customActionName) {
|
|
517
|
+
// Check if the action is already part of the custom action name
|
|
518
|
+
if (customActionName.startsWith(action)) {
|
|
519
|
+
return customActionName;
|
|
821
520
|
}
|
|
521
|
+
// Otherwise combine resource and action
|
|
522
|
+
return `${this.singularize(resource)}_${customActionName}`;
|
|
822
523
|
}
|
|
823
|
-
|
|
824
|
-
|
|
825
|
-
|
|
826
|
-
|
|
827
|
-
|
|
828
|
-
|
|
829
|
-
|
|
524
|
+
return `${action}_${this.singularize(resource)}`;
|
|
525
|
+
}
|
|
526
|
+
/**
|
|
527
|
+
* Format name for special endpoints (login, health, etc.)
|
|
528
|
+
*/
|
|
529
|
+
formatSpecialEndpointName(parsed) {
|
|
530
|
+
const { action, resource } = parsed;
|
|
531
|
+
// For endpoints like "login", "health", just return the action
|
|
532
|
+
if (['login', 'logout', 'health', 'status'].includes(action)) {
|
|
533
|
+
return action;
|
|
830
534
|
}
|
|
831
|
-
//
|
|
832
|
-
if (
|
|
833
|
-
return `${action}_${
|
|
535
|
+
// For other special endpoints, combine with resource if meaningful
|
|
536
|
+
if (resource && resource !== action) {
|
|
537
|
+
return `${action}_${resource}`;
|
|
834
538
|
}
|
|
835
|
-
return
|
|
539
|
+
return action;
|
|
836
540
|
}
|
|
837
541
|
/**
|
|
838
|
-
* Format standard
|
|
542
|
+
* Format name for standard CRUD operations
|
|
839
543
|
*/
|
|
840
|
-
|
|
841
|
-
const {
|
|
842
|
-
|
|
843
|
-
const
|
|
844
|
-
|
|
845
|
-
if (resources.sub.length > 0) {
|
|
846
|
-
const primary = this.singularize(resources.primary);
|
|
847
|
-
const sub = resources.sub[0];
|
|
848
|
-
switch (method) {
|
|
849
|
-
case 'get':
|
|
850
|
-
return isListOperation ? `${primary}_${this.pluralize(sub)}` : `${primary}_${sub}`;
|
|
851
|
-
case 'post':
|
|
852
|
-
return `create_${primary}_${this.singularize(sub)}`;
|
|
853
|
-
case 'put':
|
|
854
|
-
case 'patch':
|
|
855
|
-
return `set_${primary}_${sub}`;
|
|
856
|
-
case 'delete':
|
|
857
|
-
return `remove_${primary}_${sub}`;
|
|
858
|
-
}
|
|
859
|
-
}
|
|
860
|
-
// Handle primary resource only
|
|
861
|
-
switch (method) {
|
|
544
|
+
formatStandardOperationName(parsed, endpoint) {
|
|
545
|
+
const { resource } = parsed;
|
|
546
|
+
// Determine if it's a list or single resource operation
|
|
547
|
+
const isList = endpoint.method === 'get' && !endpoint.path.includes('{');
|
|
548
|
+
switch (endpoint.method) {
|
|
862
549
|
case 'get':
|
|
863
|
-
return
|
|
550
|
+
return isList ? this.pluralize(resource) : this.singularize(resource);
|
|
864
551
|
case 'post':
|
|
865
|
-
return `create_${this.singularize(
|
|
552
|
+
return `create_${this.singularize(resource)}`;
|
|
866
553
|
case 'put':
|
|
867
554
|
case 'patch':
|
|
868
|
-
return `update_${this.singularize(
|
|
555
|
+
return `update_${this.singularize(resource)}`;
|
|
869
556
|
case 'delete':
|
|
870
|
-
return `delete_${this.singularize(
|
|
557
|
+
return `delete_${this.singularize(resource)}`;
|
|
871
558
|
default:
|
|
872
|
-
return this.singularize(
|
|
559
|
+
return this.singularize(resource);
|
|
873
560
|
}
|
|
874
561
|
}
|
|
875
562
|
generateCleanName(endpoint) {
|
|
@@ -880,7 +567,7 @@ class ReactHookGenerator {
|
|
|
880
567
|
return endpoint.method;
|
|
881
568
|
// Get the main resource (usually the last non-parameter segment)
|
|
882
569
|
const resource = pathParts[pathParts.length - 1];
|
|
883
|
-
|
|
570
|
+
let cleanResource = resource.replace(/-/g, '_');
|
|
884
571
|
// Check if it's a custom action (last segment after a parameter)
|
|
885
572
|
const segments = endpoint.path.split('/');
|
|
886
573
|
const lastSegment = segments[segments.length - 1];
|
|
@@ -919,23 +606,13 @@ class ReactHookGenerator {
|
|
|
919
606
|
}
|
|
920
607
|
}
|
|
921
608
|
pluralize(word) {
|
|
922
|
-
// Don't pluralize if already plural
|
|
923
|
-
if (word.endsWith('s') && !word.endsWith('ss') && !word.endsWith('us') && !word.endsWith('is')) {
|
|
924
|
-
return word;
|
|
925
|
-
}
|
|
926
609
|
// Simple pluralization rules
|
|
927
610
|
if (word.endsWith('y') && !['ay', 'ey', 'iy', 'oy', 'uy'].includes(word.slice(-2))) {
|
|
928
611
|
return word.slice(0, -1) + 'ies';
|
|
929
612
|
}
|
|
930
|
-
if (word.endsWith('
|
|
613
|
+
if (word.endsWith('s') || word.endsWith('x') || word.endsWith('ch') || word.endsWith('sh')) {
|
|
931
614
|
return word + 'es';
|
|
932
615
|
}
|
|
933
|
-
if (word.endsWith('us')) {
|
|
934
|
-
return word.slice(0, -2) + 'i';
|
|
935
|
-
}
|
|
936
|
-
if (word.endsWith('is')) {
|
|
937
|
-
return word.slice(0, -2) + 'es';
|
|
938
|
-
}
|
|
939
616
|
return word + 's';
|
|
940
617
|
}
|
|
941
618
|
singularize(word) {
|
|
@@ -986,20 +663,10 @@ class ReactHookGenerator {
|
|
|
986
663
|
}
|
|
987
664
|
}
|
|
988
665
|
isListEndpoint(endpoint) {
|
|
989
|
-
|
|
990
|
-
|
|
991
|
-
|
|
992
|
-
|
|
993
|
-
if (endpoint.path.includes('{'))
|
|
994
|
-
return false;
|
|
995
|
-
// Check if the response is an array
|
|
996
|
-
if (endpoint.responses?.['200']?.schema?.type === 'array')
|
|
997
|
-
return true;
|
|
998
|
-
// Check if summary/description indicates it's a list
|
|
999
|
-
const description = `${endpoint.summary || ''} ${endpoint.description || ''}`.toLowerCase();
|
|
1000
|
-
return description.includes('list') ||
|
|
1001
|
-
description.includes('get all') ||
|
|
1002
|
-
description.includes('fetch all');
|
|
666
|
+
return endpoint.path.includes('list') ||
|
|
667
|
+
!endpoint.path.includes('{') ||
|
|
668
|
+
(endpoint.summary?.toLowerCase().includes('list') ?? false) ||
|
|
669
|
+
(endpoint.summary?.toLowerCase().includes('get all') ?? false);
|
|
1003
670
|
}
|
|
1004
671
|
groupEndpointsByResource(endpoints) {
|
|
1005
672
|
const groups = {};
|
|
@@ -1041,7 +708,9 @@ class ReactHookGenerator {
|
|
|
1041
708
|
const result = [];
|
|
1042
709
|
for (const part of parts) {
|
|
1043
710
|
const lower = part.toLowerCase();
|
|
1044
|
-
if (
|
|
711
|
+
// Keep important words even if duplicated (like verbs)
|
|
712
|
+
const importantWords = ['create', 'update', 'delete', 'get', 'list', 'reassign', 'assign'];
|
|
713
|
+
if (!seen.has(lower) || importantWords.includes(lower)) {
|
|
1045
714
|
seen.add(lower);
|
|
1046
715
|
result.push(part);
|
|
1047
716
|
}
|
|
@@ -1049,9 +718,8 @@ class ReactHookGenerator {
|
|
|
1049
718
|
return result.join('_');
|
|
1050
719
|
}
|
|
1051
720
|
}
|
|
1052
|
-
exports.ReactHookGenerator = ReactHookGenerator;
|
|
1053
721
|
// Factory function
|
|
1054
|
-
async function generateHooks(parsedAPI, options) {
|
|
722
|
+
export async function generateHooks(parsedAPI, options) {
|
|
1055
723
|
const generator = new ReactHookGenerator(options);
|
|
1056
724
|
return generator.generate(parsedAPI);
|
|
1057
725
|
}
|