@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.
Files changed (443) hide show
  1. package/CHANGELOG.md +69 -74
  2. package/README.md +17 -2
  3. package/cli/commands/generate-hooks.ts +2 -2
  4. package/cli/commands/scaffold.ts +1 -1
  5. package/cli/index.ts +1 -3
  6. package/cli/src/codegen/openapi/client-generator.js +4 -17
  7. package/cli/src/codegen/openapi/hook-generator.js +181 -513
  8. package/cli/src/codegen/openapi/parser.js +9 -14
  9. package/cli/src/codegen/openapi/type-generator.js +6 -16
  10. package/dist/atoms/components/core/Avatar/Avatar.d.ts +6 -6
  11. package/dist/atoms/components/core/Avatar/Avatar.d.ts.map +1 -1
  12. package/dist/atoms/components/core/Avatar/index.d.ts +1 -1
  13. package/dist/atoms/components/core/Badge/Badge.d.ts +6 -6
  14. package/dist/atoms/components/core/Badge/Badge.d.ts.map +1 -1
  15. package/dist/atoms/components/core/Badge/index.d.ts +1 -1
  16. package/dist/atoms/components/core/Button/Button.d.ts +3 -3
  17. package/dist/atoms/components/core/Button/Button.d.ts.map +1 -1
  18. package/dist/atoms/components/core/Button/index.d.ts +2 -2
  19. package/dist/atoms/components/core/Card/Card.d.ts +2 -2
  20. package/dist/atoms/components/core/Card/Card.d.ts.map +1 -1
  21. package/dist/atoms/components/core/Card/index.d.ts +2 -2
  22. package/dist/atoms/components/core/Card/index.d.ts.map +1 -1
  23. package/dist/atoms/components/core/Checkbox/Checkbox.d.ts +4 -4
  24. package/dist/atoms/components/core/Checkbox/Checkbox.d.ts.map +1 -1
  25. package/dist/atoms/components/core/Checkbox/index.d.ts +2 -2
  26. package/dist/atoms/components/core/Input/Input.d.ts +2 -2
  27. package/dist/atoms/components/core/Input/Input.d.ts.map +1 -1
  28. package/dist/atoms/components/core/Input/index.d.ts +2 -2
  29. package/dist/atoms/components/core/Label/Label.d.ts +3 -4
  30. package/dist/atoms/components/core/Label/Label.d.ts.map +1 -1
  31. package/dist/atoms/components/core/Label/index.d.ts +2 -2
  32. package/dist/atoms/components/core/Select/Select.d.ts +5 -5
  33. package/dist/atoms/components/core/Select/Select.d.ts.map +1 -1
  34. package/dist/atoms/components/core/Select/index.d.ts +2 -2
  35. package/dist/atoms/components/core/Select/index.d.ts.map +1 -1
  36. package/dist/atoms/components/core/Spinner/Spinner.d.ts +4 -4
  37. package/dist/atoms/components/core/Spinner/Spinner.d.ts.map +1 -1
  38. package/dist/atoms/components/core/Spinner/index.d.ts +2 -2
  39. package/dist/atoms/components/core/Switch/Switch.d.ts +4 -4
  40. package/dist/atoms/components/core/Switch/Switch.d.ts.map +1 -1
  41. package/dist/atoms/components/core/Switch/index.d.ts +1 -1
  42. package/dist/atoms/components/core/index.d.ts +10 -10
  43. package/dist/atoms/components/core/index.d.ts.map +1 -1
  44. package/dist/atoms/components/data/ActivityFeed/ActivityFeed.d.ts +2 -2
  45. package/dist/atoms/components/data/ActivityFeed/ActivityFeed.d.ts.map +1 -1
  46. package/dist/atoms/components/data/ActivityFeed/ActivityFeedItem.d.ts +3 -3
  47. package/dist/atoms/components/data/ActivityFeed/ActivityFeedItem.d.ts.map +1 -1
  48. package/dist/atoms/components/data/ActivityFeed/index.d.ts +3 -3
  49. package/dist/atoms/components/data/ActivityFeed/index.d.ts.map +1 -1
  50. package/dist/atoms/components/data/ActivityFeed/types.d.ts +3 -3
  51. package/dist/atoms/components/data/ActivityFeed/types.d.ts.map +1 -1
  52. package/dist/atoms/components/data/ActivityFeed/utils.d.ts +2 -2
  53. package/dist/atoms/components/data/ActivityFeed/utils.d.ts.map +1 -1
  54. package/dist/atoms/components/data/Chart/Chart.d.ts +52 -5
  55. package/dist/atoms/components/data/Chart/Chart.d.ts.map +1 -1
  56. package/dist/atoms/components/data/Chart/index.d.ts +2 -2
  57. package/dist/atoms/components/data/Chart/index.d.ts.map +1 -1
  58. package/dist/atoms/components/data/DataBadge/DataBadge.d.ts +6 -6
  59. package/dist/atoms/components/data/DataBadge/DataBadge.d.ts.map +1 -1
  60. package/dist/atoms/components/data/DataBadge/index.d.ts +1 -1
  61. package/dist/atoms/components/data/DataTable/DataTable.d.ts +4 -4
  62. package/dist/atoms/components/data/DataTable/DataTable.d.ts.map +1 -1
  63. package/dist/atoms/components/data/DataTable/DataTable.types.d.ts +4 -4
  64. package/dist/atoms/components/data/DataTable/DataTable.types.d.ts.map +1 -1
  65. package/dist/atoms/components/data/DataTable/TableCellWithTooltip.d.ts +1 -1
  66. package/dist/atoms/components/data/DataTable/index.d.ts +2 -2
  67. package/dist/atoms/components/data/DetailedCard/DetailedCard.d.ts +4 -4
  68. package/dist/atoms/components/data/DetailedCard/DetailedCard.d.ts.map +1 -1
  69. package/dist/atoms/components/data/DetailedCard/index.d.ts +2 -2
  70. package/dist/atoms/components/data/EntityIcon/EntityIcon.d.ts +3 -3
  71. package/dist/atoms/components/data/EntityIcon/EntityIcon.d.ts.map +1 -1
  72. package/dist/atoms/components/data/EntityIcon/index.d.ts +1 -1
  73. package/dist/atoms/components/data/IconBadge/IconBadge.d.ts +6 -6
  74. package/dist/atoms/components/data/IconBadge/IconBadge.d.ts.map +1 -1
  75. package/dist/atoms/components/data/IconBadge/index.d.ts +2 -2
  76. package/dist/atoms/components/data/ListCard/ListCard.d.ts +9 -9
  77. package/dist/atoms/components/data/ListCard/ListCard.d.ts.map +1 -1
  78. package/dist/atoms/components/data/ListCard/index.d.ts +1 -1
  79. package/dist/atoms/components/data/ProgressBar/ProgressBar.d.ts +5 -5
  80. package/dist/atoms/components/data/ProgressBar/ProgressBar.d.ts.map +1 -1
  81. package/dist/atoms/components/data/ProgressBar/index.d.ts +1 -1
  82. package/dist/atoms/components/data/StatCard/StatCard.d.ts +3 -3
  83. package/dist/atoms/components/data/StatCard/StatCard.d.ts.map +1 -1
  84. package/dist/atoms/components/data/StatCard/index.d.ts +1 -1
  85. package/dist/atoms/components/data/Table/Table.d.ts +2 -2
  86. package/dist/atoms/components/data/Table/Table.d.ts.map +1 -1
  87. package/dist/atoms/components/data/Table/index.d.ts +1 -1
  88. package/dist/atoms/components/data/TruncatedText/TruncatedText.d.ts +2 -2
  89. package/dist/atoms/components/data/TruncatedText/TruncatedText.d.ts.map +1 -1
  90. package/dist/atoms/components/data/TruncatedText/index.d.ts +1 -1
  91. package/dist/atoms/components/data/index.d.ts +12 -12
  92. package/dist/atoms/components/data/index.d.ts.map +1 -1
  93. package/dist/atoms/components/domain/SalesPanel/SalesPanel.d.ts +15 -15
  94. package/dist/atoms/components/domain/SalesPanel/SalesPanel.d.ts.map +1 -1
  95. package/dist/atoms/components/domain/SalesPanel/index.d.ts +1 -1
  96. package/dist/atoms/components/domain/SalesPanel/index.d.ts.map +1 -1
  97. package/dist/atoms/components/domain/index.d.ts +1 -1
  98. package/dist/atoms/components/feedback/Alert/Alert.d.ts +4 -4
  99. package/dist/atoms/components/feedback/Alert/Alert.d.ts.map +1 -1
  100. package/dist/atoms/components/feedback/Alert/index.d.ts +1 -1
  101. package/dist/atoms/components/feedback/EmptyState/EmptyState.d.ts +3 -3
  102. package/dist/atoms/components/feedback/EmptyState/EmptyState.d.ts.map +1 -1
  103. package/dist/atoms/components/feedback/EmptyState/index.d.ts +1 -1
  104. package/dist/atoms/components/feedback/ErrorBoundary/ErrorBoundary.d.ts +1 -1
  105. package/dist/atoms/components/feedback/ErrorBoundary/ErrorBoundary.d.ts.map +1 -1
  106. package/dist/atoms/components/feedback/ErrorBoundary/index.d.ts +1 -1
  107. package/dist/atoms/components/feedback/Skeleton/Skeleton.d.ts +30 -4
  108. package/dist/atoms/components/feedback/Skeleton/Skeleton.d.ts.map +1 -1
  109. package/dist/atoms/components/feedback/Skeleton/index.d.ts +1 -1
  110. package/dist/atoms/components/feedback/Toast/Toast.d.ts +4 -4
  111. package/dist/atoms/components/feedback/Toast/Toast.d.ts.map +1 -1
  112. package/dist/atoms/components/feedback/Toast/index.d.ts +1 -1
  113. package/dist/atoms/components/feedback/Toast/index.d.ts.map +1 -1
  114. package/dist/atoms/components/feedback/index.d.ts +5 -5
  115. package/dist/atoms/components/feedback/index.d.ts.map +1 -1
  116. package/dist/atoms/components/forms/DateTimePicker/DateTimePicker.d.ts +6 -6
  117. package/dist/atoms/components/forms/DateTimePicker/DateTimePicker.d.ts.map +1 -1
  118. package/dist/atoms/components/forms/DateTimePicker/index.d.ts +2 -2
  119. package/dist/atoms/components/forms/FileUpload/FileUpload.d.ts +3 -3
  120. package/dist/atoms/components/forms/FileUpload/FileUpload.d.ts.map +1 -1
  121. package/dist/atoms/components/forms/FileUpload/index.d.ts +2 -2
  122. package/dist/atoms/components/forms/FormField/FormField.d.ts +2 -2
  123. package/dist/atoms/components/forms/FormField/FormField.d.ts.map +1 -1
  124. package/dist/atoms/components/forms/FormField/index.d.ts +1 -1
  125. package/dist/atoms/components/forms/index.d.ts +3 -3
  126. package/dist/atoms/components/index.d.ts +9 -9
  127. package/dist/atoms/components/layout/Accordion/Accordion.d.ts +3 -3
  128. package/dist/atoms/components/layout/Accordion/Accordion.d.ts.map +1 -1
  129. package/dist/atoms/components/layout/Accordion/index.d.ts +1 -1
  130. package/dist/atoms/components/layout/Accordion/index.d.ts.map +1 -1
  131. package/dist/atoms/components/layout/Breadcrumb/Breadcrumb.d.ts +2 -3
  132. package/dist/atoms/components/layout/Breadcrumb/Breadcrumb.d.ts.map +1 -1
  133. package/dist/atoms/components/layout/Breadcrumb/index.d.ts +1 -1
  134. package/dist/atoms/components/layout/Breadcrumb/index.d.ts.map +1 -1
  135. package/dist/atoms/components/layout/Dialog/Dialog.d.ts +45 -0
  136. package/dist/atoms/components/layout/Dialog/Dialog.d.ts.map +1 -0
  137. package/dist/atoms/components/layout/Dialog/index.d.ts +2 -2
  138. package/dist/atoms/components/layout/Dialog/index.d.ts.map +1 -1
  139. package/dist/atoms/components/layout/Dropdown/Dropdown.d.ts +9 -9
  140. package/dist/atoms/components/layout/Dropdown/Dropdown.d.ts.map +1 -1
  141. package/dist/atoms/components/layout/Dropdown/index.d.ts +2 -2
  142. package/dist/atoms/components/layout/Dropdown/index.d.ts.map +1 -1
  143. package/dist/atoms/components/layout/Modal/Modal.d.ts +6 -6
  144. package/dist/atoms/components/layout/Modal/Modal.d.ts.map +1 -1
  145. package/dist/atoms/components/layout/Modal/index.d.ts +2 -2
  146. package/dist/atoms/components/layout/Tabs/Tabs.d.ts +46 -0
  147. package/dist/atoms/components/layout/Tabs/Tabs.d.ts.map +1 -0
  148. package/dist/atoms/components/layout/Tabs/index.d.ts +1 -1
  149. package/dist/atoms/components/layout/Tooltip/Tooltip.d.ts +6 -6
  150. package/dist/atoms/components/layout/Tooltip/Tooltip.d.ts.map +1 -1
  151. package/dist/atoms/components/layout/Tooltip/index.d.ts +1 -1
  152. package/dist/atoms/components/layout/index.d.ts +7 -7
  153. package/dist/atoms/components/layout/index.d.ts.map +1 -1
  154. package/dist/atoms/components/navigation/GlobalSearch/GlobalSearch.d.ts +2 -3
  155. package/dist/atoms/components/navigation/GlobalSearch/GlobalSearch.d.ts.map +1 -1
  156. package/dist/atoms/components/navigation/GlobalSearch/index.d.ts +1 -1
  157. package/dist/atoms/components/navigation/GlobalSearch/index.d.ts.map +1 -1
  158. package/dist/atoms/components/navigation/index.d.ts +1 -1
  159. package/dist/atoms/components/theme/ColorSwatch/ColorSwatch.d.ts +2 -2
  160. package/dist/atoms/components/theme/ColorSwatch/ColorSwatch.d.ts.map +1 -1
  161. package/dist/atoms/components/theme/ColorSwatch/index.d.ts +1 -1
  162. package/dist/atoms/components/theme/DarkModeToggle.d.ts.map +1 -1
  163. package/dist/atoms/components/theme/PaletteSwitcher.d.ts +1 -1
  164. package/dist/atoms/components/theme/PaletteSwitcher.d.ts.map +1 -1
  165. package/dist/atoms/components/theme/StyleGuide.d.ts +1 -1
  166. package/dist/atoms/components/theme/StyleGuide.d.ts.map +1 -1
  167. package/dist/atoms/components/theme/index.d.ts +4 -4
  168. package/dist/atoms/components/user/UserAvatar/UserAvatar.d.ts +2 -3
  169. package/dist/atoms/components/user/UserAvatar/UserAvatar.d.ts.map +1 -1
  170. package/dist/atoms/components/user/UserAvatar/index.d.ts +1 -1
  171. package/dist/atoms/components/user/UserAvatar/index.d.ts.map +1 -1
  172. package/dist/atoms/components/user/UserMenu/UserMenu.d.ts +2 -3
  173. package/dist/atoms/components/user/UserMenu/UserMenu.d.ts.map +1 -1
  174. package/dist/atoms/components/user/UserMenu/index.d.ts +1 -1
  175. package/dist/atoms/components/user/UserMenu/index.d.ts.map +1 -1
  176. package/dist/atoms/components/user/index.d.ts +2 -2
  177. package/dist/atoms/config/responsive.d.ts +16 -16
  178. package/dist/atoms/config/responsive.d.ts.map +1 -1
  179. package/dist/atoms/hooks/index.d.ts +4 -4
  180. package/dist/atoms/hooks/use-toast.d.ts +1 -1
  181. package/dist/atoms/hooks/use-toast.d.ts.map +1 -1
  182. package/dist/atoms/hooks/useApi.d.ts +2 -2
  183. package/dist/atoms/hooks/useApi.d.ts.map +1 -1
  184. package/dist/atoms/hooks/useResponsive.d.ts +1 -1
  185. package/dist/atoms/hooks/useResponsive.d.ts.map +1 -1
  186. package/dist/atoms/index.d.ts +6 -7
  187. package/dist/atoms/index.d.ts.map +1 -1
  188. package/dist/atoms/primitives/Badge.d.ts +6 -6
  189. package/dist/atoms/primitives/Badge.d.ts.map +1 -1
  190. package/dist/atoms/primitives/ErrorBoundary.d.ts +3 -3
  191. package/dist/atoms/primitives/ErrorBoundary.d.ts.map +1 -1
  192. package/dist/atoms/primitives/Select.d.ts +9 -7
  193. package/dist/atoms/primitives/Select.d.ts.map +1 -1
  194. package/dist/atoms/primitives/Switch.d.ts +4 -3
  195. package/dist/atoms/primitives/Switch.d.ts.map +1 -1
  196. package/dist/atoms/primitives/Tabs.d.ts +10 -10
  197. package/dist/atoms/primitives/Tabs.d.ts.map +1 -1
  198. package/dist/atoms/primitives/avatar.d.ts.map +1 -1
  199. package/dist/atoms/primitives/button.d.ts +2 -5
  200. package/dist/atoms/primitives/button.d.ts.map +1 -1
  201. package/dist/atoms/primitives/button.variants.d.ts +7 -0
  202. package/dist/atoms/primitives/button.variants.d.ts.map +1 -0
  203. package/dist/atoms/primitives/card.d.ts +3 -2
  204. package/dist/atoms/primitives/card.d.ts.map +1 -1
  205. package/dist/atoms/primitives/checkbox.d.ts +3 -3
  206. package/dist/atoms/primitives/checkbox.d.ts.map +1 -1
  207. package/dist/atoms/primitives/dialog.d.ts +4 -4
  208. package/dist/atoms/primitives/dialog.d.ts.map +1 -1
  209. package/dist/atoms/primitives/dropdown-menu.d.ts.map +1 -1
  210. package/dist/atoms/primitives/index.d.ts +16 -16
  211. package/dist/atoms/primitives/index.d.ts.map +1 -1
  212. package/dist/atoms/primitives/input.d.ts.map +1 -1
  213. package/dist/atoms/primitives/label.d.ts +4 -3
  214. package/dist/atoms/primitives/label.d.ts.map +1 -1
  215. package/dist/atoms/primitives/skeleton.d.ts.map +1 -1
  216. package/dist/atoms/primitives/spinner.d.ts +5 -5
  217. package/dist/atoms/primitives/spinner.d.ts.map +1 -1
  218. package/dist/atoms/primitives/table.d.ts.map +1 -1
  219. package/dist/atoms/services/api/client.d.ts +11 -2
  220. package/dist/atoms/services/api/client.d.ts.map +1 -1
  221. package/dist/atoms/services/auth-service.d.ts +1 -1
  222. package/dist/atoms/services/auth-service.d.ts.map +1 -1
  223. package/dist/atoms/services/health.d.ts +2 -2
  224. package/dist/atoms/services/index.d.ts +3 -3
  225. package/dist/atoms/shared/config/dashboard-sizes.d.ts +17 -17
  226. package/dist/atoms/shared/config/dashboard-sizes.d.ts.map +1 -1
  227. package/dist/atoms/shared/config/environment.d.ts.map +1 -1
  228. package/dist/atoms/shared/index.d.ts +4 -4
  229. package/dist/atoms/shared/index.d.ts.map +1 -1
  230. package/dist/atoms/types/auth.d.ts +11 -1
  231. package/dist/atoms/types/auth.d.ts.map +1 -1
  232. package/dist/atoms/types/entity-config.d.ts +9 -9
  233. package/dist/atoms/types/entity-config.d.ts.map +1 -1
  234. package/dist/atoms/types/generated.d.ts.map +1 -1
  235. package/dist/atoms/types/index.d.ts +6 -6
  236. package/dist/atoms/types/loading.d.ts +1 -1
  237. package/dist/atoms/types/navigation.d.ts +1 -1
  238. package/dist/atoms/types/navigation.d.ts.map +1 -1
  239. package/dist/atoms/types/ui-config.d.ts +8 -8
  240. package/dist/atoms/types/ui-config.d.ts.map +1 -1
  241. package/dist/atoms/utils/animations.d.ts +7 -7
  242. package/dist/atoms/utils/animations.d.ts.map +1 -1
  243. package/dist/atoms/utils/color-manager.d.ts +1 -1
  244. package/dist/atoms/utils/debounce.d.ts +1 -1
  245. package/dist/atoms/utils/debounce.d.ts.map +1 -1
  246. package/dist/atoms/utils/field-detection.d.ts +2 -2
  247. package/dist/atoms/utils/field-detection.d.ts.map +1 -1
  248. package/dist/atoms/utils/icon-map.d.ts +68 -0
  249. package/dist/atoms/utils/icon-map.d.ts.map +1 -0
  250. package/dist/atoms/utils/icon-resolver.d.ts +7 -67
  251. package/dist/atoms/utils/icon-resolver.d.ts.map +1 -1
  252. package/dist/atoms/utils/index.d.ts +4 -4
  253. package/dist/atoms/utils/metric-engine.d.ts +2 -10
  254. package/dist/atoms/utils/metric-engine.d.ts.map +1 -1
  255. package/dist/atoms/utils/tooltip-helpers.d.ts +1 -1
  256. package/dist/atoms/utils/tooltip-helpers.d.ts.map +1 -1
  257. package/dist/atoms/utils/ui-mapping.d.ts +6 -4
  258. package/dist/atoms/utils/ui-mapping.d.ts.map +1 -1
  259. package/dist/atoms/utils/utils.d.ts +7 -6
  260. package/dist/atoms/utils/utils.d.ts.map +1 -1
  261. package/dist/codegen/openapi/bulk-types.d.ts +4 -4
  262. package/dist/codegen/openapi/bulk-types.d.ts.map +1 -1
  263. package/dist/features/auth/components/LoginForm.d.ts.map +1 -1
  264. package/dist/features/auth/components/LogoutButton.d.ts.map +1 -1
  265. package/dist/features/auth/components/ProtectedRoute.d.ts +2 -2
  266. package/dist/features/auth/components/ProtectedRoute.d.ts.map +1 -1
  267. package/dist/features/auth/components/index.d.ts +3 -3
  268. package/dist/features/auth/hooks/auth-context.d.ts +3 -0
  269. package/dist/features/auth/hooks/auth-context.d.ts.map +1 -0
  270. package/dist/features/auth/hooks/index.d.ts +4 -3
  271. package/dist/features/auth/hooks/index.d.ts.map +1 -1
  272. package/dist/features/auth/hooks/use-auth.d.ts +3 -0
  273. package/dist/features/auth/hooks/use-auth.d.ts.map +1 -0
  274. package/dist/features/auth/hooks/useAuth.d.ts +3 -4
  275. package/dist/features/auth/hooks/useAuth.d.ts.map +1 -1
  276. package/dist/features/auth/hooks/useAuthContext.d.ts +1 -1
  277. package/dist/features/auth/hooks/useAuthContext.d.ts.map +1 -1
  278. package/dist/features/auth/hooks/usePermissions.d.ts +3 -3
  279. package/dist/features/auth/index.d.ts +3 -3
  280. package/dist/features/auth/providers/MockAuthProvider.d.ts +3 -4
  281. package/dist/features/auth/providers/MockAuthProvider.d.ts.map +1 -1
  282. package/dist/features/auth/providers/index.d.ts +2 -1
  283. package/dist/features/auth/providers/index.d.ts.map +1 -1
  284. package/dist/features/auth/providers/mock-auth-context.d.ts +3 -0
  285. package/dist/features/auth/providers/mock-auth-context.d.ts.map +1 -0
  286. package/dist/features/auth/providers/use-mock-auth.d.ts +3 -0
  287. package/dist/features/auth/providers/use-mock-auth.d.ts.map +1 -0
  288. package/dist/features/auth/services/mock-auth-service.d.ts +3 -3
  289. package/dist/features/auth/services/mock-auth-service.d.ts.map +1 -1
  290. package/dist/features/index.d.ts +1 -1
  291. package/dist/frontend-patterns.css +713 -576
  292. package/dist/index.d.ts +17 -17
  293. package/dist/index.d.ts.map +1 -1
  294. package/dist/index.es.js +21400 -21788
  295. package/dist/index.es.js.map +1 -1
  296. package/dist/index.js +21404 -21792
  297. package/dist/index.js.map +1 -1
  298. package/dist/molecules/forms/FormGroup.d.ts +2 -2
  299. package/dist/molecules/forms/FormGroup.d.ts.map +1 -1
  300. package/dist/molecules/forms/SearchInput.d.ts +1 -1
  301. package/dist/molecules/forms/SearchInput.d.ts.map +1 -1
  302. package/dist/molecules/forms/index.d.ts +2 -2
  303. package/dist/molecules/forms/index.d.ts.map +1 -1
  304. package/dist/molecules/index.d.ts +3 -3
  305. package/dist/molecules/layout/AppHeader/AppHeader.d.ts +1 -1
  306. package/dist/molecules/layout/AppHeader/AppHeader.d.ts.map +1 -1
  307. package/dist/molecules/layout/AppHeader/index.d.ts +1 -1
  308. package/dist/molecules/layout/BulkSelectionBar.d.ts +2 -2
  309. package/dist/molecules/layout/BulkSelectionBar.d.ts.map +1 -1
  310. package/dist/molecules/layout/DashboardWithSidePanel/DashboardWithSidePanel.d.ts +1 -1
  311. package/dist/molecules/layout/DashboardWithSidePanel/index.d.ts +1 -1
  312. package/dist/molecules/layout/NavigationContext.d.ts +3 -9
  313. package/dist/molecules/layout/NavigationContext.d.ts.map +1 -1
  314. package/dist/molecules/layout/PageTemplate.d.ts +1 -1
  315. package/dist/molecules/layout/PageTemplate.d.ts.map +1 -1
  316. package/dist/molecules/layout/SectionHeader/SectionHeader.d.ts +4 -4
  317. package/dist/molecules/layout/SectionHeader/SectionHeader.d.ts.map +1 -1
  318. package/dist/molecules/layout/SectionHeader/index.d.ts +1 -1
  319. package/dist/molecules/layout/ShowcaseSection.d.ts +4 -4
  320. package/dist/molecules/layout/ShowcaseSection.d.ts.map +1 -1
  321. package/dist/molecules/layout/Sidebar.d.ts.map +1 -1
  322. package/dist/molecules/layout/SidebarButton/SidebarButton.d.ts +1 -1
  323. package/dist/molecules/layout/SidebarButton/SidebarButton.d.ts.map +1 -1
  324. package/dist/molecules/layout/SidebarButton/index.d.ts +1 -1
  325. package/dist/molecules/layout/SidebarContext.d.ts +1 -8
  326. package/dist/molecules/layout/SidebarContext.d.ts.map +1 -1
  327. package/dist/molecules/layout/index.d.ts +14 -11
  328. package/dist/molecules/layout/index.d.ts.map +1 -1
  329. package/dist/molecules/layout/navigation-context.d.ts +9 -0
  330. package/dist/molecules/layout/navigation-context.d.ts.map +1 -0
  331. package/dist/molecules/layout/sidebar-context.d.ts +7 -0
  332. package/dist/molecules/layout/sidebar-context.d.ts.map +1 -0
  333. package/dist/molecules/layout/use-navigation.d.ts +2 -0
  334. package/dist/molecules/layout/use-navigation.d.ts.map +1 -0
  335. package/dist/molecules/layout/use-sidebar.d.ts +2 -0
  336. package/dist/molecules/layout/use-sidebar.d.ts.map +1 -0
  337. package/dist/molecules/navigation/NavMenu.d.ts +2 -2
  338. package/dist/molecules/navigation/NavMenu.d.ts.map +1 -1
  339. package/dist/molecules/navigation/Pagination.d.ts +2 -2
  340. package/dist/molecules/navigation/index.d.ts +2 -2
  341. package/dist/organisms/index.d.ts +1 -1
  342. package/dist/organisms/showcase/ComponentShowcasePage.d.ts +1 -1
  343. package/dist/organisms/showcase/ComponentShowcasePage.d.ts.map +1 -1
  344. package/dist/templates/AuthTemplate.d.ts +4 -4
  345. package/dist/templates/AuthTemplate.d.ts.map +1 -1
  346. package/dist/templates/ComponentShowcaseTemplate.d.ts +7 -7
  347. package/dist/templates/ComponentShowcaseTemplate.d.ts.map +1 -1
  348. package/dist/templates/DashboardTemplate.d.ts +3 -3
  349. package/dist/templates/DashboardTemplate.d.ts.map +1 -1
  350. package/dist/templates/DataTemplate.d.ts +3 -3
  351. package/dist/templates/DataTemplate.d.ts.map +1 -1
  352. package/dist/templates/EnhancedDataTemplate.d.ts +11 -11
  353. package/dist/templates/EnhancedDataTemplate.d.ts.map +1 -1
  354. package/dist/templates/EnhancedDataTemplate.hooks.bulk.d.ts +2 -2
  355. package/dist/templates/EnhancedDataTemplate.hooks.bulk.d.ts.map +1 -1
  356. package/dist/templates/EnhancedDataTemplate.hooks.d.ts +4 -4
  357. package/dist/templates/EnhancedDataTemplate.hooks.d.ts.map +1 -1
  358. package/dist/templates/admin/AdminCRUDTemplate.d.ts +4 -4
  359. package/dist/templates/admin/AdminCRUDTemplate.d.ts.map +1 -1
  360. package/dist/templates/admin/AdminDashboardTemplate.d.ts +7 -7
  361. package/dist/templates/admin/AdminDashboardTemplate.d.ts.map +1 -1
  362. package/dist/templates/admin/AdminDetailTemplate.d.ts +4 -4
  363. package/dist/templates/admin/AdminDetailTemplate.d.ts.map +1 -1
  364. package/dist/templates/admin/index.d.ts +3 -3
  365. package/dist/templates/admin/index.d.ts.map +1 -1
  366. package/dist/templates/api/APIDataTemplate.d.ts +14 -9
  367. package/dist/templates/api/APIDataTemplate.d.ts.map +1 -1
  368. package/dist/templates/api/create-api-data-template.d.ts +4 -0
  369. package/dist/templates/api/create-api-data-template.d.ts.map +1 -0
  370. package/dist/templates/api/index.d.ts +3 -2
  371. package/dist/templates/api/index.d.ts.map +1 -1
  372. package/dist/templates/factory.d.ts +3 -3
  373. package/dist/templates/factory.d.ts.map +1 -1
  374. package/dist/templates/index.d.ts +8 -8
  375. package/dist/templates/index.d.ts.map +1 -1
  376. package/package.json +10 -7
  377. package/LICENSE +0 -19
  378. package/cli/cli/commands/generate-hooks.js +0 -291
  379. package/cli/cli/commands/init.js +0 -25
  380. package/cli/cli/commands/scaffold.js +0 -201
  381. package/cli/cli/index.js +0 -113
  382. package/cli/commands/generate-hooks.js +0 -291
  383. package/cli/commands/init.js +0 -25
  384. package/cli/commands/scaffold.js +0 -201
  385. package/cli/index.js +0 -6665
  386. package/cli/src/codegen/openapi/bulk-hook-generator.js +0 -252
  387. package/cli/src/codegen/openapi/bulk-types.js +0 -89
  388. package/cli/src/codegen/openapi/confidence-scorer.js +0 -204
  389. package/cli/src/codegen/openapi/hook-config.js +0 -66
  390. package/dist/atoms/components/data/ActivityFeed/ActivityFeed.stories.d.ts +0 -38
  391. package/dist/atoms/components/data/ActivityFeed/ActivityFeed.stories.d.ts.map +0 -1
  392. package/dist/codegen/index.d.ts +0 -7
  393. package/dist/codegen/index.d.ts.map +0 -1
  394. package/dist/codegen/openapi/bulk-hook-generator.d.ts +0 -40
  395. package/dist/codegen/openapi/bulk-hook-generator.d.ts.map +0 -1
  396. package/dist/codegen/openapi/client-generator.d.ts +0 -52
  397. package/dist/codegen/openapi/client-generator.d.ts.map +0 -1
  398. package/dist/codegen/openapi/confidence-scorer.d.ts +0 -30
  399. package/dist/codegen/openapi/confidence-scorer.d.ts.map +0 -1
  400. package/dist/codegen/openapi/hook-config.d.ts +0 -50
  401. package/dist/codegen/openapi/hook-config.d.ts.map +0 -1
  402. package/dist/codegen/openapi/hook-generator.d.ts +0 -108
  403. package/dist/codegen/openapi/hook-generator.d.ts.map +0 -1
  404. package/dist/codegen/openapi/index.d.ts +0 -27
  405. package/dist/codegen/openapi/index.d.ts.map +0 -1
  406. package/dist/codegen/openapi/parser.d.ts +0 -107
  407. package/dist/codegen/openapi/parser.d.ts.map +0 -1
  408. package/dist/codegen/openapi/type-generator.d.ts +0 -53
  409. package/dist/codegen/openapi/type-generator.d.ts.map +0 -1
  410. package/dist/generated/client/client.d.ts +0 -23
  411. package/dist/generated/client/client.d.ts.map +0 -1
  412. package/dist/generated/client/config.d.ts +0 -10
  413. package/dist/generated/client/config.d.ts.map +0 -1
  414. package/dist/generated/client/index.d.ts +0 -12
  415. package/dist/generated/client/index.d.ts.map +0 -1
  416. package/dist/generated/client/methods.d.ts +0 -591
  417. package/dist/generated/client/methods.d.ts.map +0 -1
  418. package/dist/generated/client/types.d.ts +0 -37
  419. package/dist/generated/client/types.d.ts.map +0 -1
  420. package/dist/generated/example.d.ts +0 -8
  421. package/dist/generated/example.d.ts.map +0 -1
  422. package/dist/generated/hooks/index.d.ts +0 -11
  423. package/dist/generated/hooks/index.d.ts.map +0 -1
  424. package/dist/generated/hooks/keys.d.ts +0 -59
  425. package/dist/generated/hooks/keys.d.ts.map +0 -1
  426. package/dist/generated/hooks/mutations.d.ts +0 -551
  427. package/dist/generated/hooks/mutations.d.ts.map +0 -1
  428. package/dist/generated/hooks/queries.d.ts +0 -426
  429. package/dist/generated/hooks/queries.d.ts.map +0 -1
  430. package/dist/generated/hooks/types.d.ts +0 -318
  431. package/dist/generated/hooks/types.d.ts.map +0 -1
  432. package/dist/generated/index.d.ts +0 -13
  433. package/dist/generated/index.d.ts.map +0 -1
  434. package/dist/generated/types/endpoints.d.ts +0 -1364
  435. package/dist/generated/types/endpoints.d.ts.map +0 -1
  436. package/dist/generated/types/index.d.ts +0 -11
  437. package/dist/generated/types/index.d.ts.map +0 -1
  438. package/dist/generated/types/parameters.d.ts +0 -8
  439. package/dist/generated/types/parameters.d.ts.map +0 -1
  440. package/dist/generated/types/responses.d.ts +0 -8
  441. package/dist/generated/types/responses.d.ts.map +0 -1
  442. package/dist/generated/types/schemas.d.ts +0 -652
  443. 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
- Object.defineProperty(exports, "__esModule", { value: true });
11
- exports.ReactHookGenerator = void 0;
12
- exports.generateHooks = generateHooks;
13
- const hook_config_1 = require("./hook-config");
14
- const confidence_scorer_1 = require("./confidence-scorer");
15
- const bulk_hook_generator_1 = require("./bulk-hook-generator");
16
- const bulk_types_1 = require("./bulk-types");
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 hook_config_1.HookConfigManager(this.options.configPath);
32
- this.confidenceScorer = new confidence_scorer_1.ConfidenceScorer();
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, type UseQueryOptions, type UseInfiniteQueryOptions } from '@tanstack/react-query'");
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
- let hookName = this.generateQueryHookName(endpoint);
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?: UseQueryOptions<any, any, any>` : 'options?: UseQueryOptions<any, any, any>';
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.${queryKeyNameCamelCase}(params)` :
252
- `queryKeys.${queryKeyNameCamelCase}()`;
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
- // Note: Authentication is handled by the API client interceptors
260
- // If you need to disable queries when not authenticated, use:
261
- // enabled: !!user && (options?.enabled ?? true) in your component
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
- // Extract the query key name from the hook name (remove 'use' prefix)
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: [...queryKeys.${queryKeyNameCamelCase}(), params],`);
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, type UseMutationOptions } from '@tanstack/react-query'");
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
- // Check if this is a bulk operation
308
- const requestBody = endpoint.requestBody;
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?: UseMutationOptions<any, any, ${mutationType}>) {`);
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 (data: any) => {
203
+ return ` onMutate: async (newData) => {
371
204
  // Cancel outgoing refetches
372
- await queryClient.cancelQueries({ queryKey: queryKeys.${resource}() })
205
+ await queryClient.cancelQueries({ queryKey: queryKeys.all })
373
206
 
374
207
  // Snapshot previous value
375
- const previousData = queryClient.getQueryData(queryKeys.${resource}())
208
+ const previousData = queryClient.getQueryData(queryKeys.all)
376
209
 
377
210
  // Optimistically update cache
378
- queryClient.setQueryData(queryKeys.${resource}(), (old: any) => {
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: any, data: any, context: any) => {
215
+ onError: (err, newData, context) => {
388
216
  // Rollback on error
389
- if (context?.previousData !== undefined) {
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
- if (hasPathParams) {
396
- return ` onMutate: async (data: any) => {
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.${resource}())
224
+ const previousData = queryClient.getQueryData(queryKeys.all)
400
225
 
401
226
  // Update specific item in cache
402
- queryClient.setQueryData(queryKeys.${resource}(), (old: any) => {
403
- if (Array.isArray(old)) {
404
- return old.map((item: any) =>
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: any, data: any, context: any) => {
432
- if (context?.previousData !== undefined) {
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 (data: any) => {
438
- await queryClient.cancelQueries({ queryKey: queryKeys.${resource}() })
237
+ return ` onMutate: async (id) => {
238
+ await queryClient.cancelQueries({ queryKey: queryKeys.all })
439
239
 
440
- const previousData = queryClient.getQueryData(queryKeys.${resource}())
240
+ const previousData = queryClient.getQueryData(queryKeys.all)
441
241
 
442
242
  // Remove item from cache
443
- queryClient.setQueryData(queryKeys.${resource}(), (old: any) => {
444
- if (Array.isArray(old)) {
445
- const idToDelete = data.pathParams?.id || data.pathParams?.${resource.slice(0, -1)}_id || data
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: any, data: any, context: any) => {
454
- if (context?.previousData !== undefined) {
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}() })`).join('\n ')}
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
- let keyName = this.camelCase(operationName.replace(/^get/, ''));
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('// Re-export bulk operation types for convenience');
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 typeName = `${this.capitalize(operationName)}Params`;
552
- if (!generatedTypes.has(typeName)) {
553
- generatedTypes.add(typeName);
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 typeName = `${this.capitalize(operationName)}Data`;
561
- if (!generatedTypes.has(typeName)) {
562
- generatedTypes.add(typeName);
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
- // Generate name based on parsed components
663
- return this.generateNameFromParsed(parsed, endpoint);
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
- // Clean common patterns
670
- const cleaned = operationId
671
- .replace(/_api_v\d+_/g, '_') // Remove API version
672
- .replace(/_(get|post|put|patch|delete)$/i, ''); // Remove HTTP suffix
673
- // Split into parts
674
- const parts = cleaned.split('_').filter(Boolean);
675
- // Extract prefix (action) if exists
676
- const prefix = this.extractPrefix(parts, { ...endpoint, operationId });
677
- // Extract resources from path
678
- const resources = this.extractResourcesFromPath(endpoint.path);
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 segments = endpoint.path.split('/');
681
- const lastSegment = segments[segments.length - 1];
682
- const isCustomAction = !lastSegment.startsWith('{') && segments[segments.length - 2]?.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: prefix?.action || '',
685
- resource: resources.primary || '',
686
- subResource: resources.sub?.[0] || '',
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 meaningful prefix from operation ID parts
461
+ * Extract the primary action verb from the operation ID
697
462
  */
698
- extractPrefix(parts, endpoint) {
699
- if (parts.length === 0)
700
- return null;
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
- 'assign', 'reassign', 'create', 'update', 'delete',
707
- 'get', 'list', 'health', 'status', 'verify', 'validate'
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
- const firstPart = parts[0].toLowerCase();
710
- if (knownActions.includes(firstPart)) {
711
- // Special handling for compound names like "get_health_status" or "get_current_user_info"
712
- if (firstPart === 'get' && originalId.startsWith('get_')) {
713
- // Extract everything between get_ and _api_v
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
- return {
764
- primary: resources[0] || '',
765
- sub: resources.slice(1),
766
- lastHasParam
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
- * Generate clean hook name from parsed components
491
+ * Extract resource name from the API path
771
492
  */
772
- generateNameFromParsed(parsed, endpoint) {
773
- // Special cases first
774
- if (parsed.prefix === 'login')
775
- return 'login';
776
- if (parsed.prefix === 'logout')
777
- return 'logout';
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 prefix adds meaningful context
501
+ * Check if this is a special endpoint that should keep its action verb
795
502
  */
796
- isMeaningfulPrefix(prefix, resources) {
797
- const action = prefix.split('_')[0];
798
- // Not meaningful if it just repeats the resource
799
- if (prefix === resources.primary)
800
- return false;
801
- if (prefix === `get_${resources.primary}`)
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 with meaningful prefix
511
+ * Format name for custom action endpoints
810
512
  */
811
- formatWithPrefix(parsed) {
812
- const { prefix, resources, originalId, isCustomAction, customActionName } = parsed;
813
- const prefixParts = prefix.split('_');
814
- const action = prefixParts[0];
815
- const subject = prefixParts.slice(1).join('_');
816
- // Special handling for custom actions
817
- if (isCustomAction && customActionName) {
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
- // Handle deduplication - don't repeat if subject matches sub-resource
824
- if (subject && resources.sub.length > 0) {
825
- const subResource = resources.sub[0];
826
- // If subject matches the sub-resource, don't duplicate
827
- if (subject === subResource || subject === this.pluralize(subResource)) {
828
- return `${action}_${this.singularize(resources.primary)}_${subResource}`;
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
- // Standard format: action_resource_subresource
832
- if (resources.sub.length > 0 && !isCustomAction) {
833
- return `${action}_${this.singularize(resources.primary)}_${resources.sub[0]}`;
535
+ // For other special endpoints, combine with resource if meaningful
536
+ if (resource && resource !== action) {
537
+ return `${action}_${resource}`;
834
538
  }
835
- return `${action}_${this.singularize(resources.primary)}`;
539
+ return action;
836
540
  }
837
541
  /**
838
- * Format standard REST operation
542
+ * Format name for standard CRUD operations
839
543
  */
840
- formatStandardOperation(parsed, endpoint) {
841
- const { resources, method } = parsed;
842
- const hasParams = endpoint.path.includes('{');
843
- const isListOperation = method === 'get' && !hasParams;
844
- // Handle sub-resources
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 isListOperation ? this.pluralize(resources.primary) : this.singularize(resources.primary);
550
+ return isList ? this.pluralize(resource) : this.singularize(resource);
864
551
  case 'post':
865
- return `create_${this.singularize(resources.primary)}`;
552
+ return `create_${this.singularize(resource)}`;
866
553
  case 'put':
867
554
  case 'patch':
868
- return `update_${this.singularize(resources.primary)}`;
555
+ return `update_${this.singularize(resource)}`;
869
556
  case 'delete':
870
- return `delete_${this.singularize(resources.primary)}`;
557
+ return `delete_${this.singularize(resource)}`;
871
558
  default:
872
- return this.singularize(resources.primary);
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
- const cleanResource = resource.replace(/-/g, '_');
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('ss') || word.endsWith('x') || word.endsWith('ch') || word.endsWith('sh')) {
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
- // Only GET requests can be list endpoints
990
- if (endpoint.method.toLowerCase() !== 'get')
991
- return false;
992
- // If it has path parameters, it's likely fetching a single resource
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 (!seen.has(lower)) {
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
  }