@jmruthers/pace-core 0.6.5 → 0.6.7

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 (473) hide show
  1. package/CHANGELOG.md +104 -0
  2. package/README.md +5 -403
  3. package/audit-tool/00-dependencies.cjs +394 -0
  4. package/audit-tool/audits/01-pace-core-compliance.cjs +556 -0
  5. package/audit-tool/audits/02-project-structure.cjs +255 -0
  6. package/audit-tool/audits/03-architecture.cjs +196 -0
  7. package/audit-tool/audits/04-code-quality.cjs +149 -0
  8. package/audit-tool/audits/05-styling.cjs +224 -0
  9. package/audit-tool/audits/06-security-rbac.cjs +544 -0
  10. package/audit-tool/audits/07-api-tech-stack.cjs +301 -0
  11. package/audit-tool/audits/08-testing-documentation.cjs +202 -0
  12. package/audit-tool/audits/09-operations.cjs +208 -0
  13. package/audit-tool/index.cjs +291 -0
  14. package/audit-tool/utils/code-utils.cjs +218 -0
  15. package/audit-tool/utils/file-utils.cjs +230 -0
  16. package/audit-tool/utils/report-utils.cjs +241 -0
  17. package/core-usage-manifest.json +93 -0
  18. package/cursor-rules/00-standards-overview.mdc +156 -0
  19. package/cursor-rules/01-pace-core-compliance.mdc +586 -0
  20. package/cursor-rules/02-project-structure.mdc +42 -4
  21. package/cursor-rules/{03-solid-principles.mdc → 03-architecture.mdc} +126 -10
  22. package/cursor-rules/04-code-quality.mdc +419 -0
  23. package/cursor-rules/{08-markup-quality.mdc → 05-styling.mdc} +104 -34
  24. package/cursor-rules/06-security-rbac.mdc +518 -0
  25. package/cursor-rules/07-api-tech-stack.mdc +377 -0
  26. package/cursor-rules/08-testing-documentation.mdc +324 -0
  27. package/cursor-rules/09-operations.mdc +365 -0
  28. package/dist/{AuthService-Cb34EQs3.d.ts → AuthService-DmfO5rGS.d.ts} +10 -0
  29. package/dist/DataTable-7PMH7XN7.js +15 -0
  30. package/dist/{DataTable-BMRU8a1j.d.ts → DataTable-DRUIgtUH.d.ts} +1 -1
  31. package/dist/{PublicPageProvider-QTFVrL-Z.d.ts → PublicPageProvider-DlsCaR5v.d.ts} +33 -72
  32. package/dist/UnifiedAuthProvider-ZT6TIGM7.js +7 -0
  33. package/dist/api-Y4MQWOFW.js +4 -0
  34. package/dist/audit-MYQXYZFU.js +3 -0
  35. package/dist/{chunk-DGUM43GV.js → chunk-3RG5ZIWI.js} +1 -4
  36. package/dist/{chunk-QXHPKYJV.js → chunk-4SXLQIZO.js} +1 -26
  37. package/dist/{chunk-UPPMRMYG.js → chunk-5X4QLXRG.js} +73 -151
  38. package/dist/chunk-6F3IILHI.js +62 -0
  39. package/dist/{chunk-E66EQZE6.js → chunk-6GLLNA6U.js} +3 -9
  40. package/dist/{chunk-ZSAAAMVR.js → chunk-6QYDGKQY.js} +1 -4
  41. package/dist/{chunk-FMUCXFII.js → chunk-7ILTDCL2.js} +9 -5
  42. package/dist/{chunk-M43Y4SSO.js → chunk-A3W6LW53.js} +15 -13
  43. package/dist/{chunk-63FOKYGO.js → chunk-AHU7G2R5.js} +2 -11
  44. package/dist/{chunk-HU2C6SSC.js → chunk-BM4CQ5P3.js} +606 -559
  45. package/dist/chunk-C7NSAPTL.js +1 -0
  46. package/dist/{chunk-J36DSWQK.js → chunk-FEJLJNWA.js} +7 -41
  47. package/dist/{chunk-IHB5DR3H.js → chunk-FTCRZOG2.js} +188 -387
  48. package/dist/{chunk-G37KK66H.js → chunk-FYHN4DD5.js} +60 -19
  49. package/dist/chunk-GHYHJTYV.js +994 -0
  50. package/dist/{chunk-VBXEHIUJ.js → chunk-HF6O3O37.js} +6 -88
  51. package/dist/{chunk-FFQEQTNW.js → chunk-IUBRCBSY.js} +134 -45
  52. package/dist/{chunk-6COVEUS7.js → chunk-JGWDVX64.js} +983 -1034
  53. package/dist/{chunk-RGAWHO7N.js → chunk-L4XMVJKY.js} +77 -222
  54. package/dist/chunk-MBADTM7L.js +64 -0
  55. package/dist/{chunk-M7MPQISP.js → chunk-OJ4SKRSV.js} +3 -16
  56. package/dist/{chunk-IVOFDYWT.js → chunk-Q7Q7V5NV.js} +2109 -1604
  57. package/dist/{chunk-JGRYX5UX.js → chunk-S7DKJPLT.js} +29 -58
  58. package/dist/{chunk-PWLANIRT.js → chunk-TTRFSOKR.js} +1 -7
  59. package/dist/{chunk-5DRSZLL2.js → chunk-UH3NTO3F.js} +1 -6
  60. package/dist/{chunk-NTM7ZSB6.js → chunk-VBCS3DUA.js} +261 -168
  61. package/dist/{chunk-EFN2EIMK.js → chunk-ZFYPMX46.js} +271 -87
  62. package/dist/{chunk-L4OXEN46.js → chunk-ZKAWKYT4.js} +10 -24
  63. package/dist/components.d.ts +7 -5
  64. package/dist/components.js +46 -257
  65. package/dist/{database.generated-CzIvgcPu.d.ts → database.generated-CcnC_DRc.d.ts} +4795 -3691
  66. package/dist/eslint-rules/index.cjs +35 -0
  67. package/{src/eslint-rules/pace-core-compliance.cjs → dist/eslint-rules/rules/01-pace-core-compliance.cjs} +234 -235
  68. package/dist/eslint-rules/rules/04-code-quality.cjs +290 -0
  69. package/dist/eslint-rules/rules/05-styling.cjs +61 -0
  70. package/dist/eslint-rules/rules/06-security-rbac.cjs +806 -0
  71. package/dist/eslint-rules/rules/07-api-tech-stack.cjs +263 -0
  72. package/dist/eslint-rules/rules/08-testing.cjs +94 -0
  73. package/dist/eslint-rules/utils/helpers.cjs +42 -0
  74. package/dist/eslint-rules/utils/manifest-loader.cjs +75 -0
  75. package/dist/hooks.d.ts +6 -6
  76. package/dist/hooks.js +62 -172
  77. package/dist/icons/index.d.ts +1 -0
  78. package/dist/icons/index.js +1 -0
  79. package/dist/index.d.ts +12 -11
  80. package/dist/index.js +67 -660
  81. package/dist/providers.d.ts +2 -2
  82. package/dist/providers.js +8 -35
  83. package/dist/rbac/eslint-rules.d.ts +46 -44
  84. package/dist/rbac/eslint-rules.js +7 -4
  85. package/dist/rbac/index.d.ts +109 -586
  86. package/dist/rbac/index.js +14 -207
  87. package/dist/styles/index.js +2 -12
  88. package/dist/theming/runtime.d.ts +14 -1
  89. package/dist/theming/runtime.js +3 -19
  90. package/dist/{timezone-CHhWg6b4.d.ts → timezone-BZe_eUxx.d.ts} +175 -1
  91. package/dist/{types-CkbwOr4Y.d.ts → types-DXstZpNI.d.ts} +4 -17
  92. package/dist/types-t9H8qKRw.d.ts +55 -0
  93. package/dist/types.d.ts +1 -1
  94. package/dist/types.js +7 -94
  95. package/dist/{usePublicRouteParams-ClnV4tnv.d.ts → usePublicRouteParams-MamNgwqe.d.ts} +20 -20
  96. package/dist/utils.d.ts +24 -117
  97. package/dist/utils.js +54 -392
  98. package/docs/README.md +17 -7
  99. package/docs/api/README.md +4 -402
  100. package/docs/api/modules.md +301 -871
  101. package/docs/api-reference/components.md +21 -21
  102. package/docs/api-reference/deprecated.md +31 -6
  103. package/docs/api-reference/hooks.md +80 -80
  104. package/docs/api-reference/rpc-functions.md +78 -3
  105. package/docs/api-reference/types.md +1 -1
  106. package/docs/api-reference/utilities.md +1 -1
  107. package/docs/architecture/README.md +1 -1
  108. package/docs/core-concepts/events.md +3 -3
  109. package/docs/core-concepts/organisations.md +6 -6
  110. package/docs/core-concepts/permissions.md +6 -6
  111. package/docs/documentation-index.md +12 -18
  112. package/docs/getting-started/cursor-rules.md +3 -23
  113. package/docs/getting-started/dependencies.md +650 -0
  114. package/docs/getting-started/documentation-index.md +1 -1
  115. package/docs/getting-started/examples/README.md +4 -4
  116. package/docs/getting-started/examples/full-featured-app.md +1 -1
  117. package/docs/getting-started/faq.md +2 -2
  118. package/docs/getting-started/installation-guide.md +20 -7
  119. package/docs/getting-started/quick-reference.md +4 -4
  120. package/docs/getting-started/quick-start.md +23 -12
  121. package/docs/implementation-guides/authentication.md +15 -15
  122. package/docs/implementation-guides/component-styling.md +1 -1
  123. package/docs/implementation-guides/data-tables.md +126 -33
  124. package/docs/implementation-guides/datatable-rbac-usage.md +1 -1
  125. package/docs/implementation-guides/dynamic-colors.md +3 -3
  126. package/docs/implementation-guides/file-upload-storage.md +2 -2
  127. package/docs/implementation-guides/hierarchical-datatable.md +40 -60
  128. package/docs/implementation-guides/inactivity-tracking.md +3 -3
  129. package/docs/implementation-guides/large-datasets.md +3 -2
  130. package/docs/implementation-guides/organisation-security.md +2 -2
  131. package/docs/implementation-guides/performance.md +2 -2
  132. package/docs/implementation-guides/permission-enforcement.md +5 -1
  133. package/docs/migration/V0.3.44_organisation-context-timing-fix.md +1 -1
  134. package/docs/migration/V0.4.0_rbac-migration.md +6 -6
  135. package/docs/rbac/MIGRATION_GUIDE.md +819 -0
  136. package/docs/rbac/RBAC_CONTRACT.md +724 -0
  137. package/docs/rbac/README.md +17 -8
  138. package/docs/rbac/advanced-patterns.md +6 -6
  139. package/docs/rbac/api-reference.md +20 -20
  140. package/docs/rbac/edge-functions-guide.md +376 -0
  141. package/docs/rbac/event-based-apps.md +3 -3
  142. package/docs/rbac/examples.md +41 -41
  143. package/docs/rbac/getting-started.md +37 -37
  144. package/docs/rbac/performance.md +1 -1
  145. package/docs/rbac/quick-start.md +52 -52
  146. package/docs/rbac/secure-client-protection.md +1 -35
  147. package/docs/rbac/troubleshooting.md +1 -1
  148. package/docs/security/README.md +5 -5
  149. package/docs/standards/0-standards-overview.md +220 -0
  150. package/docs/standards/1-pace-core-compliance-standards.md +986 -0
  151. package/docs/standards/2-project-structure-standards.md +949 -0
  152. package/docs/standards/3-architecture-standards.md +606 -0
  153. package/docs/standards/4-code-quality-standards.md +728 -0
  154. package/docs/standards/5-styling-standards.md +348 -0
  155. package/docs/standards/{07-rbac-and-rls-standard.md → 6-security-rbac-standards.md} +269 -66
  156. package/docs/standards/7-api-tech-stack-standards.md +662 -0
  157. package/docs/standards/8-testing-documentation-standards.md +401 -0
  158. package/docs/standards/9-operations-standards.md +1102 -0
  159. package/docs/standards/README.md +185 -57
  160. package/docs/troubleshooting/README.md +4 -4
  161. package/docs/troubleshooting/common-issues.md +2 -2
  162. package/docs/troubleshooting/debugging.md +9 -9
  163. package/docs/troubleshooting/migration.md +4 -4
  164. package/docs/troubleshooting/organisation-context-setup.md +42 -19
  165. package/eslint-config-pace-core.cjs +33 -6
  166. package/package.json +35 -23
  167. package/scripts/install-cursor-rules.cjs +25 -6
  168. package/scripts/install-eslint-config.cjs +284 -0
  169. package/src/__tests__/fixtures/supabase.ts +1 -1
  170. package/src/__tests__/helpers/__tests__/component-test-utils.test.tsx +3 -3
  171. package/src/__tests__/helpers/__tests__/optimized-test-setup.test.ts +1 -1
  172. package/src/__tests__/helpers/__tests__/supabaseMock.test.ts +1 -1
  173. package/src/__tests__/helpers/__tests__/test-providers.test.tsx +2 -2
  174. package/src/__tests__/helpers/__tests__/test-utils.test.tsx +13 -13
  175. package/src/__tests__/helpers/component-test-utils.tsx +1 -1
  176. package/src/__tests__/helpers/supabaseMock.ts +2 -2
  177. package/src/__tests__/integration/UserProfile.test.tsx +14 -14
  178. package/src/__tests__/public-recipe-view.test.ts +38 -9
  179. package/src/__tests__/rbac/PagePermissionGuard.test.tsx +6 -6
  180. package/src/__tests__/templates/accessibility.test.template.tsx +9 -9
  181. package/src/__tests__/templates/component.test.template.tsx +18 -15
  182. package/src/components/Button/Button.tsx +5 -1
  183. package/src/components/Calendar/Calendar.tsx +201 -47
  184. package/src/components/ContextSelector/ContextSelector.tsx +106 -119
  185. package/src/components/DataTable/AUDIT_REPORT.md +293 -0
  186. package/src/components/DataTable/__tests__/DataTableCore.test.tsx +10 -2
  187. package/src/components/DataTable/__tests__/a11y.basic.test.tsx +10 -4
  188. package/src/components/DataTable/__tests__/test-utils/sharedTestUtils.tsx +9 -9
  189. package/src/components/DataTable/components/ColumnFilter.tsx +63 -74
  190. package/src/components/DataTable/components/ColumnVisibilityDropdown.tsx +43 -41
  191. package/src/components/DataTable/components/DataTableCore.tsx +186 -13
  192. package/src/components/DataTable/components/DataTableErrorBoundary.tsx +9 -11
  193. package/src/components/DataTable/components/DataTableLayout.tsx +35 -21
  194. package/src/components/DataTable/components/EditFields.tsx +23 -3
  195. package/src/components/DataTable/components/EditableRow.tsx +12 -9
  196. package/src/components/DataTable/components/EmptyState.tsx +10 -9
  197. package/src/components/DataTable/components/FilterRow.tsx +2 -4
  198. package/src/components/DataTable/components/ImportModal.tsx +124 -126
  199. package/src/components/DataTable/components/LoadingState.tsx +5 -6
  200. package/src/components/DataTable/components/RowComponent.tsx +12 -0
  201. package/src/components/DataTable/components/SortIndicator.tsx +50 -0
  202. package/src/components/DataTable/components/__tests__/COVERAGE_NOTE.md +4 -4
  203. package/src/components/DataTable/components/__tests__/ColumnFilter.test.tsx +23 -82
  204. package/src/components/DataTable/components/__tests__/DataTableErrorBoundary.test.tsx +37 -9
  205. package/src/components/DataTable/components/__tests__/EmptyState.test.tsx +7 -4
  206. package/src/components/DataTable/components/__tests__/FilterRow.test.tsx +12 -4
  207. package/src/components/DataTable/components/__tests__/LoadingState.test.tsx +41 -27
  208. package/src/components/DataTable/components/hooks/usePermissionTracking.ts +0 -4
  209. package/src/components/DataTable/components/index.ts +2 -1
  210. package/src/components/DataTable/hooks/__tests__/useDataTableState.test.ts +51 -47
  211. package/src/components/DataTable/hooks/useDataTablePermissions.ts +24 -21
  212. package/src/components/DataTable/hooks/useDataTableState.ts +125 -9
  213. package/src/components/DataTable/hooks/useTableColumns.ts +40 -2
  214. package/src/components/DataTable/hooks/useTableHandlers.ts +11 -0
  215. package/src/components/DataTable/types.ts +5 -18
  216. package/src/components/DataTable/utils/a11yUtils.ts +17 -0
  217. package/src/components/DatePickerWithTimezone/DatePickerWithTimezone.test.tsx +2 -1
  218. package/src/components/DatePickerWithTimezone/DatePickerWithTimezone.tsx +11 -15
  219. package/src/components/DateTimeField/DateTimeField.tsx +10 -9
  220. package/src/components/Dialog/Dialog.test.tsx +128 -104
  221. package/src/components/Dialog/Dialog.tsx +742 -24
  222. package/src/components/ErrorBoundary/ErrorBoundary.tsx +77 -79
  223. package/src/components/FileDisplay/FileDisplay.test.tsx +4 -2
  224. package/src/components/FileDisplay/FileDisplay.tsx +23 -17
  225. package/src/components/FileUpload/FileUpload.test.tsx +52 -14
  226. package/src/components/FileUpload/FileUpload.tsx +112 -130
  227. package/src/components/Form/Form.test.tsx +6 -8
  228. package/src/components/Form/Form.tsx +365 -4
  229. package/src/components/NavigationMenu/NavigationMenu.test.tsx +14 -13
  230. package/src/components/NavigationMenu/useNavigationFiltering.ts +11 -21
  231. package/src/components/PaceAppLayout/PaceAppLayout.test.tsx +6 -4
  232. package/src/components/PaceAppLayout/PaceAppLayout.tsx +11 -15
  233. package/src/components/PaceLoginPage/PaceLoginPage.test.tsx +108 -61
  234. package/src/components/PaceLoginPage/PaceLoginPage.tsx +27 -3
  235. package/src/components/Progress/Progress.tsx +2 -4
  236. package/src/components/ProtectedRoute/ProtectedRoute.tsx +8 -8
  237. package/src/components/Select/Select.tsx +109 -98
  238. package/src/components/Select/types.ts +4 -1
  239. package/src/components/UserMenu/UserMenu.tsx +9 -6
  240. package/src/hooks/__tests__/ServiceHooks.test.tsx +16 -16
  241. package/src/hooks/__tests__/hooks.integration.test.tsx +55 -57
  242. package/src/hooks/__tests__/useAppConfig.unit.test.ts +129 -67
  243. package/src/hooks/__tests__/useFocusTrap.unit.test.tsx +97 -97
  244. package/src/hooks/__tests__/usePublicEvent.simple.test.ts +149 -67
  245. package/src/hooks/__tests__/usePublicEvent.test.ts +149 -79
  246. package/src/hooks/__tests__/usePublicEvent.unit.test.ts +158 -109
  247. package/src/hooks/__tests__/useSessionDraft.test.ts +163 -0
  248. package/src/hooks/__tests__/useSessionRestoration.unit.test.tsx +10 -5
  249. package/src/hooks/public/usePublicEvent.ts +67 -195
  250. package/src/hooks/public/usePublicEventLogo.test.ts +70 -17
  251. package/src/hooks/public/usePublicEventLogo.ts +24 -14
  252. package/src/hooks/public/usePublicFileDisplay.ts +2 -2
  253. package/src/hooks/public/usePublicRouteParams.ts +5 -5
  254. package/src/hooks/useAppConfig.ts +28 -26
  255. package/src/hooks/useEventTheme.test.ts +217 -239
  256. package/src/hooks/useEventTheme.ts +16 -28
  257. package/src/hooks/useFileDisplay.ts +2 -2
  258. package/src/hooks/useOrganisationPermissions.ts +5 -7
  259. package/src/hooks/useQueryCache.ts +0 -1
  260. package/src/hooks/useSessionDraft.ts +380 -0
  261. package/src/hooks/useSessionRestoration.ts +3 -1
  262. package/src/icons/index.ts +27 -0
  263. package/src/index.ts +5 -0
  264. package/src/providers/OrganisationProvider.tsx +23 -14
  265. package/src/providers/UnifiedAuthProvider.smoke.test.tsx +21 -21
  266. package/src/providers/__tests__/AuthProvider.test.tsx +21 -21
  267. package/src/providers/__tests__/EventProvider.test.tsx +61 -61
  268. package/src/providers/__tests__/InactivityProvider.test.tsx +56 -56
  269. package/src/providers/__tests__/OrganisationProvider.test.tsx +75 -75
  270. package/src/providers/__tests__/ProviderLifecycle.test.tsx +37 -37
  271. package/src/providers/__tests__/UnifiedAuthProvider.test.tsx +103 -103
  272. package/src/providers/services/EventServiceProvider.tsx +1 -24
  273. package/src/providers/services/UnifiedAuthProvider.tsx +5 -48
  274. package/src/providers/services/__tests__/AuthServiceProvider.integration.test.tsx +7 -7
  275. package/src/providers/services/__tests__/UnifiedAuthProvider.integration.test.tsx +13 -10
  276. package/src/rbac/__tests__/adapters.comprehensive.test.tsx +7 -457
  277. package/src/rbac/__tests__/auth-rbac.e2e.test.tsx +33 -7
  278. package/src/rbac/adapters.tsx +7 -295
  279. package/src/rbac/api.test.ts +44 -56
  280. package/src/rbac/api.ts +10 -17
  281. package/src/rbac/cache-invalidation.ts +0 -1
  282. package/src/rbac/compliance/index.ts +10 -0
  283. package/src/rbac/compliance/pattern-detector.ts +553 -0
  284. package/src/rbac/compliance/runtime-compliance.ts +22 -0
  285. package/src/rbac/components/AccessDenied.tsx +150 -0
  286. package/src/rbac/components/NavigationGuard.tsx +12 -20
  287. package/src/rbac/components/PagePermissionGuard.tsx +4 -24
  288. package/src/rbac/components/__tests__/NavigationGuard.test.tsx +21 -8
  289. package/src/rbac/components/index.ts +3 -41
  290. package/src/rbac/eslint-rules.js +1 -1
  291. package/src/rbac/hooks/index.ts +0 -3
  292. package/src/rbac/hooks/permissions/index.ts +0 -3
  293. package/src/rbac/hooks/permissions/useAccessLevel.ts +4 -8
  294. package/src/rbac/hooks/usePermissions.ts +0 -3
  295. package/src/rbac/hooks/useResolvedScope.test.ts +57 -47
  296. package/src/rbac/hooks/useResolvedScope.ts +58 -140
  297. package/src/rbac/hooks/useResourcePermissions.test.ts +124 -38
  298. package/src/rbac/hooks/useResourcePermissions.ts +139 -48
  299. package/src/rbac/hooks/useRoleManagement.test.ts +65 -22
  300. package/src/rbac/hooks/useRoleManagement.ts +147 -19
  301. package/src/rbac/hooks/useSecureSupabase.ts +4 -8
  302. package/src/rbac/index.ts +7 -9
  303. package/src/rbac/utils/contextValidator.ts +9 -7
  304. package/src/services/AuthService.ts +130 -18
  305. package/src/services/EventService.ts +4 -97
  306. package/src/services/InactivityService.ts +16 -0
  307. package/src/services/OrganisationService.ts +7 -44
  308. package/src/services/__tests__/OrganisationService.test.ts +26 -8
  309. package/src/services/base/BaseService.ts +0 -3
  310. package/src/styles/core.css +7 -0
  311. package/src/theming/__tests__/parseEventColours.test.ts +9 -3
  312. package/src/theming/parseEventColours.ts +22 -10
  313. package/src/types/database.generated.ts +4733 -3809
  314. package/src/utils/__tests__/lazyLoad.unit.test.tsx +42 -39
  315. package/src/utils/__tests__/organisationContext.unit.test.ts +9 -10
  316. package/src/utils/context/organisationContext.test.ts +13 -28
  317. package/src/utils/context/organisationContext.ts +21 -52
  318. package/src/utils/dynamic/dynamicUtils.ts +1 -1
  319. package/src/utils/file-reference/index.ts +39 -15
  320. package/src/utils/formatting/formatDateTime.test.ts +3 -2
  321. package/src/utils/google-places/loadGoogleMapsScript.ts +29 -4
  322. package/src/utils/index.ts +4 -1
  323. package/src/utils/persistence/__tests__/keyDerivation.test.ts +135 -0
  324. package/src/utils/persistence/__tests__/sensitiveFieldDetection.test.ts +123 -0
  325. package/src/utils/persistence/keyDerivation.ts +304 -0
  326. package/src/utils/persistence/sensitiveFieldDetection.ts +212 -0
  327. package/src/utils/security/secureStorage.ts +5 -5
  328. package/src/utils/storage/README.md +1 -1
  329. package/src/utils/storage/helpers.ts +3 -3
  330. package/src/utils/supabase/createBaseClient.ts +147 -0
  331. package/src/utils/timezone/timezone.test.ts +1 -2
  332. package/src/utils/timezone/timezone.ts +1 -1
  333. package/src/utils/validation/csrf.ts +4 -4
  334. package/cursor-rules/00-pace-core-compliance.mdc +0 -331
  335. package/cursor-rules/01-standards-compliance.mdc +0 -244
  336. package/cursor-rules/04-testing-standards.mdc +0 -268
  337. package/cursor-rules/05-bug-reports-and-features.mdc +0 -246
  338. package/cursor-rules/06-code-quality.mdc +0 -309
  339. package/cursor-rules/07-tech-stack-compliance.mdc +0 -214
  340. package/cursor-rules/CHANGELOG.md +0 -119
  341. package/cursor-rules/README.md +0 -192
  342. package/dist/DataTable-AOVNCPTX.js +0 -175
  343. package/dist/DataTable-AOVNCPTX.js.map +0 -1
  344. package/dist/UnifiedAuthProvider-4SBX4LU5.js +0 -18
  345. package/dist/UnifiedAuthProvider-4SBX4LU5.js.map +0 -1
  346. package/dist/api-O6HTBX5Y.js +0 -52
  347. package/dist/api-O6HTBX5Y.js.map +0 -1
  348. package/dist/audit-V53FV5AG.js +0 -17
  349. package/dist/audit-V53FV5AG.js.map +0 -1
  350. package/dist/chunk-5DRSZLL2.js.map +0 -1
  351. package/dist/chunk-63FOKYGO.js.map +0 -1
  352. package/dist/chunk-6COVEUS7.js.map +0 -1
  353. package/dist/chunk-AFVQODI2.js +0 -263
  354. package/dist/chunk-AFVQODI2.js.map +0 -1
  355. package/dist/chunk-DGUM43GV.js.map +0 -1
  356. package/dist/chunk-E66EQZE6.js.map +0 -1
  357. package/dist/chunk-EFN2EIMK.js.map +0 -1
  358. package/dist/chunk-FFQEQTNW.js.map +0 -1
  359. package/dist/chunk-FMUCXFII.js.map +0 -1
  360. package/dist/chunk-G37KK66H.js.map +0 -1
  361. package/dist/chunk-G7QEZTYQ.js +0 -2053
  362. package/dist/chunk-G7QEZTYQ.js.map +0 -1
  363. package/dist/chunk-HU2C6SSC.js.map +0 -1
  364. package/dist/chunk-IHB5DR3H.js.map +0 -1
  365. package/dist/chunk-IVOFDYWT.js.map +0 -1
  366. package/dist/chunk-J36DSWQK.js.map +0 -1
  367. package/dist/chunk-JGRYX5UX.js.map +0 -1
  368. package/dist/chunk-KQCRWDSA.js +0 -1
  369. package/dist/chunk-KQCRWDSA.js.map +0 -1
  370. package/dist/chunk-L4OXEN46.js.map +0 -1
  371. package/dist/chunk-LMC26NLJ.js +0 -84
  372. package/dist/chunk-LMC26NLJ.js.map +0 -1
  373. package/dist/chunk-M43Y4SSO.js.map +0 -1
  374. package/dist/chunk-M7MPQISP.js.map +0 -1
  375. package/dist/chunk-NTM7ZSB6.js.map +0 -1
  376. package/dist/chunk-PWLANIRT.js.map +0 -1
  377. package/dist/chunk-QXHPKYJV.js.map +0 -1
  378. package/dist/chunk-RGAWHO7N.js.map +0 -1
  379. package/dist/chunk-UPPMRMYG.js.map +0 -1
  380. package/dist/chunk-VBXEHIUJ.js.map +0 -1
  381. package/dist/chunk-ZSAAAMVR.js.map +0 -1
  382. package/dist/components.js.map +0 -1
  383. package/dist/contextValidator-5OGXSPKS.js +0 -9
  384. package/dist/contextValidator-5OGXSPKS.js.map +0 -1
  385. package/dist/eslint-rules/pace-core-compliance.cjs +0 -510
  386. package/dist/hooks.js.map +0 -1
  387. package/dist/index.js.map +0 -1
  388. package/dist/providers.js.map +0 -1
  389. package/dist/rbac/eslint-rules.js.map +0 -1
  390. package/dist/rbac/index.js.map +0 -1
  391. package/dist/styles/index.js.map +0 -1
  392. package/dist/theming/runtime.js.map +0 -1
  393. package/dist/types.js.map +0 -1
  394. package/dist/utils.js.map +0 -1
  395. package/docs/best-practices/README.md +0 -472
  396. package/docs/best-practices/accessibility.md +0 -601
  397. package/docs/best-practices/common-patterns.md +0 -516
  398. package/docs/best-practices/deployment.md +0 -1103
  399. package/docs/best-practices/performance.md +0 -1328
  400. package/docs/best-practices/security.md +0 -940
  401. package/docs/best-practices/testing.md +0 -1034
  402. package/docs/rbac/compliance/compliance-guide.md +0 -544
  403. package/docs/standards/01-architecture-standard.md +0 -44
  404. package/docs/standards/02-api-and-rpc-standard.md +0 -39
  405. package/docs/standards/03-component-standard.md +0 -32
  406. package/docs/standards/04-code-style-standard.md +0 -32
  407. package/docs/standards/05-security-standard.md +0 -44
  408. package/docs/standards/06-testing-and-docs-standard.md +0 -29
  409. package/docs/standards/pace-core-compliance.md +0 -432
  410. package/scripts/audit/core/checks/accessibility.cjs +0 -197
  411. package/scripts/audit/core/checks/api-usage.cjs +0 -191
  412. package/scripts/audit/core/checks/bundle.cjs +0 -142
  413. package/scripts/audit/core/checks/compliance.cjs +0 -2706
  414. package/scripts/audit/core/checks/config.cjs +0 -54
  415. package/scripts/audit/core/checks/coverage.cjs +0 -84
  416. package/scripts/audit/core/checks/dependencies.cjs +0 -994
  417. package/scripts/audit/core/checks/documentation.cjs +0 -268
  418. package/scripts/audit/core/checks/environment.cjs +0 -116
  419. package/scripts/audit/core/checks/error-handling.cjs +0 -340
  420. package/scripts/audit/core/checks/forms.cjs +0 -172
  421. package/scripts/audit/core/checks/heuristics.cjs +0 -68
  422. package/scripts/audit/core/checks/hooks.cjs +0 -334
  423. package/scripts/audit/core/checks/imports.cjs +0 -244
  424. package/scripts/audit/core/checks/performance.cjs +0 -325
  425. package/scripts/audit/core/checks/routes.cjs +0 -117
  426. package/scripts/audit/core/checks/state.cjs +0 -130
  427. package/scripts/audit/core/checks/structure.cjs +0 -65
  428. package/scripts/audit/core/checks/style.cjs +0 -584
  429. package/scripts/audit/core/checks/testing.cjs +0 -122
  430. package/scripts/audit/core/checks/typescript.cjs +0 -61
  431. package/scripts/audit/core/scanner.cjs +0 -199
  432. package/scripts/audit/core/utils.cjs +0 -137
  433. package/scripts/audit/index.cjs +0 -223
  434. package/scripts/audit/reporters/console.cjs +0 -151
  435. package/scripts/audit/reporters/json.cjs +0 -54
  436. package/scripts/audit/reporters/markdown.cjs +0 -124
  437. package/scripts/audit-consuming-app.cjs +0 -86
  438. package/src/components/DataTable/components/DataTableBody.tsx +0 -454
  439. package/src/components/DataTable/components/DraggableColumnHeader.tsx +0 -156
  440. package/src/components/DataTable/components/ExpandButton.tsx +0 -113
  441. package/src/components/DataTable/components/GroupHeader.tsx +0 -54
  442. package/src/components/DataTable/components/ViewRowModal.tsx +0 -68
  443. package/src/components/DataTable/components/VirtualizedDataTable.tsx +0 -525
  444. package/src/components/DataTable/components/__tests__/ExpandButton.test.tsx +0 -462
  445. package/src/components/DataTable/components/__tests__/GroupHeader.test.tsx +0 -393
  446. package/src/components/DataTable/components/__tests__/ViewRowModal.test.tsx +0 -476
  447. package/src/components/DataTable/components/__tests__/VirtualizedDataTable.test.tsx +0 -128
  448. package/src/components/DataTable/core/DataTableContext.tsx +0 -216
  449. package/src/components/DataTable/core/__tests__/DataTableContext.test.tsx +0 -136
  450. package/src/components/DataTable/hooks/__tests__/useColumnReordering.test.ts +0 -570
  451. package/src/components/DataTable/hooks/useColumnReordering.ts +0 -123
  452. package/src/components/DataTable/utils/debugTools.ts +0 -514
  453. package/src/eslint-rules/pace-core-compliance.js +0 -638
  454. package/src/rbac/components/EnhancedNavigationMenu.test.tsx +0 -555
  455. package/src/rbac/components/EnhancedNavigationMenu.tsx +0 -293
  456. package/src/rbac/components/NavigationProvider.test.tsx +0 -481
  457. package/src/rbac/components/NavigationProvider.tsx +0 -345
  458. package/src/rbac/components/PagePermissionProvider.test.tsx +0 -476
  459. package/src/rbac/components/PagePermissionProvider.tsx +0 -279
  460. package/src/rbac/components/PermissionEnforcer.tsx +0 -312
  461. package/src/rbac/components/RoleBasedRouter.tsx +0 -440
  462. package/src/rbac/components/SecureDataProvider.test.tsx +0 -543
  463. package/src/rbac/components/SecureDataProvider.tsx +0 -339
  464. package/src/rbac/components/__tests__/EnhancedNavigationMenu.test.tsx +0 -620
  465. package/src/rbac/components/__tests__/NavigationProvider.test.tsx +0 -726
  466. package/src/rbac/components/__tests__/PagePermissionProvider.test.tsx +0 -661
  467. package/src/rbac/components/__tests__/PermissionEnforcer.test.tsx +0 -881
  468. package/src/rbac/components/__tests__/RoleBasedRouter.test.tsx +0 -783
  469. package/src/rbac/components/__tests__/SecureDataProvider.fixed.test.tsx +0 -645
  470. package/src/rbac/components/__tests__/SecureDataProvider.test.tsx +0 -659
  471. package/src/rbac/hooks/permissions/useCachedPermissions.ts +0 -79
  472. package/src/rbac/hooks/permissions/useHasAllPermissions.ts +0 -90
  473. package/src/rbac/hooks/permissions/useHasAnyPermission.ts +0 -90
@@ -1,334 +0,0 @@
1
- #!/usr/bin/env node
2
-
3
- /**
4
- * React Hooks Compliance Check Module
5
- * @package @jmruthers/pace-core
6
- * @module Audit/Checks/Hooks
7
- *
8
- * Checks for:
9
- * - Hooks called conditionally or after early returns
10
- * - Hooks called in loops
11
- * - Missing dependencies in useEffect/useMemo/useCallback
12
- * - Hooks called in wrong order
13
- */
14
-
15
- const fs = require('fs');
16
- const { getRelativePath, getLineNumber } = require('../utils.cjs');
17
-
18
- const hooksCheck = {
19
- name: 'hooks',
20
- description: 'React hooks compliance (conditional calls, missing dependencies, etc.)',
21
- severity: 'error',
22
-
23
- async run(context) {
24
- const { projectRoot, files } = context;
25
- const issues = [];
26
- const warnings = [];
27
- const suggestions = [];
28
-
29
- if (!files || files.length === 0) {
30
- return { issues, warnings, suggestions };
31
- }
32
-
33
- // React hooks that must follow rules
34
- // Separate actual React hooks from custom hooks
35
- const actualReactHooks = [
36
- 'useState', 'useEffect', 'useContext', 'useReducer', 'useCallback',
37
- 'useMemo', 'useRef', 'useImperativeHandle', 'useLayoutEffect',
38
- 'useDebugValue'
39
- ];
40
-
41
- const customHooks = [
42
- 'useUnifiedAuth', 'useOrganisations', 'useEvents',
43
- 'usePermissions', 'useCan', 'useSecureSupabase', 'useToast',
44
- 'useDebounce', 'useZodForm', 'useFileReference', 'useRBAC'
45
- ];
46
-
47
- // Combined list for pattern matching
48
- const hookNames = [...actualReactHooks, ...customHooks];
49
-
50
- const hookPattern = new RegExp(`\\b(${hookNames.join('|')})\\s*\\(`, 'g');
51
-
52
- for (const filePath of files) {
53
- try {
54
- // Only check React component files
55
- if (!filePath.match(/\.(tsx|jsx)$/)) {
56
- continue;
57
- }
58
-
59
- const content = fs.readFileSync(filePath, 'utf8');
60
- const relativePath = getRelativePath(filePath, projectRoot);
61
- const normalizedPath = relativePath.replace(/\\/g, '/');
62
-
63
- // Skip root-level src directory - in pace-core repository, this is a demo/showcase app
64
- const isRootSrc = normalizedPath.startsWith('src/') && !normalizedPath.includes('packages/');
65
- if (isRootSrc) {
66
- continue; // Skip demo app files
67
- }
68
-
69
- // Skip scripts directory - utility scripts don't need hooks validation
70
- const isScript = normalizedPath.startsWith('scripts/') || normalizedPath.includes('/scripts/');
71
- if (isScript) {
72
- continue; // Skip script files
73
- }
74
-
75
- // Check if this is a pace-core package file
76
- // Skip "hook-after-return" check for pace-core files - these are false positives.
77
- // The detection logic has issues with complex nested structures in library code.
78
- // Other hook checks (conditional calls, missing dependencies) still apply to pace-core.
79
- const isPaceCorePackage = normalizedPath.includes('packages/core/') || normalizedPath.startsWith('packages/core/');
80
-
81
- // Check for hooks
82
- if (!hookPattern.test(content)) {
83
- continue; // No hooks in this file
84
- }
85
-
86
- // Find all hook calls
87
- const hookCalls = [];
88
- let match;
89
- const regex = new RegExp(`\\b(${hookNames.join('|')})\\s*\\(`, 'g');
90
- while ((match = regex.exec(content)) !== null) {
91
- hookCalls.push({
92
- name: match[1],
93
- index: match.index,
94
- line: getLineNumber(content, match.index)
95
- });
96
- }
97
-
98
- if (hookCalls.length === 0) {
99
- continue;
100
- }
101
-
102
- // Check for hooks called conditionally
103
- for (const hookCall of hookCalls) {
104
- const beforeHook = content.substring(0, hookCall.index);
105
- const linesBefore = beforeHook.split('\n');
106
- const currentLine = linesBefore[linesBefore.length - 1];
107
-
108
- // Check if hook is in a conditional
109
- const isInConditional = /if\s*\(|else\s*\{|switch\s*\(|case\s+.*:|for\s*\(|while\s*\(|\.map\s*\(/.test(currentLine);
110
-
111
- if (isInConditional) {
112
- issues.push({
113
- type: 'hook-in-conditional',
114
- file: relativePath,
115
- line: hookCall.line,
116
- message: `Hook '${hookCall.name}' is called conditionally or in a loop`,
117
- recommendation: 'Hooks must be called at the top level of the component, not conditionally or in loops'
118
- });
119
- }
120
-
121
- // Check if there's an early return before this hook at the component level
122
- // Only flag returns at the component function level, not inside nested functions
123
- const functionStart = beforeHook.lastIndexOf('function') > beforeHook.lastIndexOf('=>') ?
124
- beforeHook.lastIndexOf('function') : beforeHook.lastIndexOf('=>');
125
-
126
- if (functionStart !== -1) {
127
- const functionBody = content.substring(functionStart, hookCall.index);
128
-
129
- // Find all return statements and check if they're at component level (not in nested functions)
130
- // Only flag CONDITIONAL early returns (guard clauses), not the final return statement
131
- const returnPattern = /\breturn\s+[^;]+;|\breturn\s*;|\breturn\s+\(/g;
132
- let returnMatch;
133
- let hasComponentLevelReturn = false;
134
-
135
- while ((returnMatch = returnPattern.exec(functionBody)) !== null) {
136
- const returnIndex = returnMatch.index;
137
- const beforeReturn = functionBody.substring(Math.max(0, returnIndex - 200), returnIndex);
138
- const afterReturn = functionBody.substring(returnIndex, Math.min(functionBody.length, returnIndex + 100));
139
-
140
- // Check if this is a CONDITIONAL early return (guard clause)
141
- // Pattern: if (...) return ...; or if (...) { return ...; }
142
- // NOT the final return statement of the component
143
- const isConditionalReturn = /\bif\s*\([^)]+\)\s*(return|{[\s\S]*?return)/.test(beforeReturn) ||
144
- /\belse\s+if\s*\([^)]+\)\s*(return|{[\s\S]*?return)/.test(beforeReturn) ||
145
- /\belse\s*{\s*return/.test(beforeReturn) ||
146
- /\?\s*\([^)]*\)\s*=>\s*{?\s*return/.test(beforeReturn); // Ternary operator
147
-
148
- // If it's not a conditional return, it's likely the final return - skip it
149
- if (!isConditionalReturn) {
150
- continue;
151
- }
152
-
153
- // Check if return is inside a nested function by looking for patterns
154
- const isInHookInitializer = /useState\s*\(\s*\([^)]*\)\s*=>/.test(beforeReturn);
155
- const isInEffectCallback = /useEffect\s*\(\s*\([^)]*\)\s*=>/.test(beforeReturn);
156
- const isInQueryFn = /queryFn\s*:\s*\([^)]*\)\s*=>|useQuery\s*\(\s*\{[^}]*queryFn/.test(beforeReturn);
157
- const isInArrayMethod = /\.(map|filter|find|reduce|forEach|some|every)\s*\(\s*\([^)]*\)\s*=>/.test(beforeReturn);
158
- const isInIIFE = /\(\s*\([^)]*\)\s*=>/.test(beforeReturn);
159
- const isInFunctionExpr = /\bfunction\s*\([^)]*\)\s*\{/.test(beforeReturn);
160
- const isInUseMemo = /useMemo\s*\(\s*\([^)]*\)\s*=>/.test(beforeReturn);
161
- const isInUseCallback = /useCallback\s*\(\s*\([^)]*\)\s*=>/.test(beforeReturn);
162
-
163
- // Check if return is inside a switch case (also nested)
164
- const isInSwitchCase = /\bcase\s+[^:]+:\s*[\s\S]*?return/.test(beforeReturn);
165
-
166
- // If return is NOT in any nested function pattern, it's a component-level conditional return
167
- if (!isInHookInitializer && !isInEffectCallback && !isInQueryFn &&
168
- !isInArrayMethod && !isInIIFE && !isInFunctionExpr &&
169
- !isInUseMemo && !isInUseCallback && !isInSwitchCase) {
170
- hasComponentLevelReturn = true;
171
- break;
172
- }
173
- }
174
-
175
- if (hasComponentLevelReturn && !isPaceCorePackage) {
176
- // Skip this check for pace-core files - false positives due to complex nested structures
177
- issues.push({
178
- type: 'hook-after-return',
179
- file: relativePath,
180
- line: hookCall.line,
181
- message: `Hook '${hookCall.name}' is called after an early return`,
182
- recommendation: 'All hooks must be called before any conditional returns at the component level. Move hooks to the top of the component, before any component-level conditional returns. Returns inside nested functions (useState initializers, useEffect callbacks, etc.) are fine. If you have guard clauses (if (loading) return <Loading />), move all hooks above these guard clauses.'
183
- });
184
- }
185
- }
186
- }
187
-
188
- // Check for missing dependencies in useEffect, useMemo, useCallback
189
- const dependencyHooks = ['useEffect', 'useMemo', 'useCallback', 'useLayoutEffect'];
190
- dependencyHooks.forEach(hookName => {
191
- // Match hook with dependency array - handle multiline and various formats
192
- const hookRegex = new RegExp(`${hookName}\\s*\\(([^)]*)\\)\\s*,\\s*\\[([^\\]]*)\\]`, 'gs');
193
- let depMatch;
194
- while ((depMatch = hookRegex.exec(content)) !== null) {
195
- const hookBody = depMatch[1]; // The function body or callback
196
- const deps = depMatch[2].trim();
197
-
198
- // If dependency array is empty, check if hook only uses stable globals
199
- if (deps === '') {
200
- // Extract the actual callback body (handle arrow functions and regular functions)
201
- let callbackBody = hookBody;
202
-
203
- // Check if it's an arrow function: () => { ... } or () => ...
204
- if (hookBody.includes('=>')) {
205
- const arrowMatch = hookBody.match(/=>\s*\{?([^}]*)\}?$/);
206
- if (arrowMatch) {
207
- callbackBody = arrowMatch[1];
208
- }
209
- }
210
-
211
- // Check if callback only uses stable global APIs or imported module-level constants
212
- // Stable globals that don't need dependencies:
213
- const stableGlobals = [
214
- /window\.(location|document|localStorage|sessionStorage|navigator)/,
215
- /document\.(documentElement|body|getElementById|querySelector)/,
216
- /localStorage\.(getItem|setItem|removeItem|clear)/,
217
- /sessionStorage\.(getItem|setItem|removeItem|clear)/,
218
- /console\.(log|error|warn|info|debug)/,
219
- /Math\./,
220
- /Date\./,
221
- /JSON\./,
222
- /Object\./,
223
- /Array\./,
224
- /String\./,
225
- /Number\./,
226
- /Boolean\./,
227
- /RegExp\./,
228
- /Error\./,
229
- /Promise\./,
230
- /Symbol\./,
231
- /Reflect\./,
232
- /Proxy\./
233
- ];
234
-
235
- // Check for imported module-level constants (classes, functions, constants)
236
- // Pattern: ImportedClass.method() or importedFunction() or importedConstant
237
- const importedModulePattern = /[A-Z]\w+\.\w+\(|^[A-Z]\w+\(|\b[A-Z][A-Z_]+/;
238
-
239
- // Check if callback body only contains stable globals or simple operations
240
- const hasOnlyStableGlobals = stableGlobals.some(pattern => pattern.test(callbackBody));
241
- const hasImportedModule = importedModulePattern.test(callbackBody);
242
-
243
- // Check if callback uses reactive values (props, state, context) that would need deps
244
- const hasReactiveValues = /\b(props|state|context|use[A-Z]\w+\(\))/.test(callbackBody);
245
-
246
- // Check for variable references that might be reactive
247
- // Simple heuristic: if callback references variables that aren't stable globals
248
- const variablePattern = /\b[a-z][a-zA-Z0-9_]*\b/g;
249
- const variables = callbackBody.match(variablePattern) || [];
250
- const hasNonGlobalVariables = variables.some(v => {
251
- // Skip common stable globals and built-ins
252
- const stableVars = ['window', 'document', 'localStorage', 'sessionStorage', 'console',
253
- 'Math', 'Date', 'JSON', 'Object', 'Array', 'String', 'Number',
254
- 'Boolean', 'RegExp', 'Error', 'Promise', 'Symbol', 'Reflect', 'Proxy',
255
- 'true', 'false', 'null', 'undefined', 'this', 'return', 'if', 'else',
256
- 'const', 'let', 'var', 'function', 'async', 'await', 'for', 'while',
257
- 'switch', 'case', 'default', 'break', 'continue', 'try', 'catch', 'finally'];
258
- return !stableVars.includes(v) && !v.match(/^[A-Z]/); // Lowercase vars that aren't stable
259
- });
260
-
261
- // Only warn if callback uses reactive values or non-global variables
262
- if (hasReactiveValues || (hasNonGlobalVariables && !hasOnlyStableGlobals && !hasImportedModule)) {
263
- warnings.push({
264
- type: 'missing-dependencies',
265
- file: relativePath,
266
- line: getLineNumber(content, depMatch.index),
267
- message: `${hookName} has empty dependency array but may need dependencies`,
268
- recommendation: 'Review the hook body and add all dependencies to the dependency array. If the callback only uses stable global APIs (window, document, localStorage, etc.) or imported module-level constants, an empty dependency array is correct.'
269
- });
270
- }
271
- }
272
- }
273
- });
274
-
275
- // Check hook order (hooks should be called in consistent order)
276
- // This is a simplified check - full implementation would track hook order across renders
277
-
278
- // SKIP hook grouping suggestions for pace-core library files
279
- // Library components often have complex hook usage organized by feature/concern,
280
- // and strict grouping is less critical than in consuming applications.
281
- // The grouping suggestions are primarily for consuming apps, not library code.
282
- if (isPaceCorePackage) {
283
- continue; // Skip grouping suggestions for pace-core library files
284
- }
285
-
286
- // Filter to only actual React hooks (not custom hooks) for grouping suggestions
287
- // Files with only custom hooks (like useToast()) don't need grouping suggestions
288
- const actualReactHookCalls = hookCalls.filter(h => actualReactHooks.includes(h.name));
289
-
290
- // Skip files that only have custom hooks (no actual React hooks)
291
- // Custom hooks are typically called once and don't need grouping
292
- // This also filters out files like Toast.tsx that only have forwardRef components
293
- // (forwardRef components don't use React hooks, so actualReactHookCalls will be empty)
294
- if (actualReactHookCalls.length === 0) {
295
- continue; // No actual React hooks, skip grouping suggestion
296
- }
297
-
298
- // Check if hooks are already grouped (look for grouping comments)
299
- // Accept more flexible patterns:
300
- // - Specific keywords: // ============================================================================ // REFS / STATE HOOKS / etc.
301
- // - Section dividers: // ============================================================================ (any text)
302
- // - Comment blocks near hooks: // HOOKS or // State management or similar
303
- const hasGroupingComments =
304
- /\/\/\s*=+\s*(REFS|STATE HOOKS|CUSTOM HOOKS|MEMOIZATION HOOKS|EFFECT HOOKS|HOOKS|STATE|EFFECTS|MEMOIZATION|CALLBACKS)/i.test(content) ||
305
- /\/\/\s*=+\s*[A-Z].*HOOK/i.test(content) ||
306
- /\/\/\s*=+\s*[A-Z].*STATE/i.test(content) ||
307
- /\/\/\s*=+\s*[A-Z].*EFFECT/i.test(content);
308
-
309
- // Only suggest grouping if:
310
- // 1. File has actual React hooks (not just custom hooks)
311
- // 2. Hooks are called multiple times (duplicate hook names)
312
- // 3. Hooks are not already grouped (no grouping comments found)
313
- const hookOrder = actualReactHookCalls.map(h => h.name);
314
- const uniqueHooks = [...new Set(hookOrder)];
315
-
316
- if (uniqueHooks.length !== hookOrder.length && !hasGroupingComments) {
317
- // Hooks are called multiple times and not grouped
318
- suggestions.push({
319
- type: 'hook-order',
320
- file: relativePath,
321
- message: 'Consider grouping related hooks together for better readability',
322
- recommendation: 'Group hooks by purpose (state hooks, effect hooks, custom hooks)'
323
- });
324
- }
325
- } catch (error) {
326
- // Skip files with errors
327
- }
328
- }
329
-
330
- return { issues, warnings, suggestions };
331
- }
332
- };
333
-
334
- module.exports = hooksCheck;
@@ -1,244 +0,0 @@
1
- #!/usr/bin/env node
2
-
3
- /**
4
- * Import Patterns Check Module
5
- * @package @jmruthers/pace-core
6
- * @module Audit/Checks/Imports
7
- *
8
- * Checks for:
9
- * - Unused imports from pace-core
10
- * - Missing default imports
11
- * - Circular dependencies
12
- * - Wrong import paths
13
- * - Barrel import anti-patterns
14
- */
15
-
16
- const fs = require('fs');
17
- const path = require('path');
18
- const { findSourceFiles, getRelativePath } = require('../utils.cjs');
19
-
20
- const importsCheck = {
21
- name: 'imports',
22
- description: 'Import pattern analysis (unused imports, circular dependencies, wrong paths)',
23
- severity: 'warning',
24
-
25
- async run(context) {
26
- const { projectRoot, files } = context;
27
- const issues = [];
28
- const warnings = [];
29
- const suggestions = [];
30
-
31
- if (!files || files.length === 0) {
32
- return { issues, warnings, suggestions };
33
- }
34
-
35
- // Track imports and usage
36
- const importMap = new Map(); // file -> { imports: [], exports: [] }
37
- const usageMap = new Map(); // file -> Set of used identifiers
38
-
39
- // First pass: collect imports and exports
40
- for (const filePath of files) {
41
- try {
42
- const content = fs.readFileSync(filePath, 'utf8');
43
- const relativePath = getRelativePath(filePath, projectRoot);
44
-
45
- const imports = [];
46
- const exports = [];
47
- const used = new Set();
48
-
49
- // Find all imports
50
- const importPattern = /import\s+(?:(?:\*\s+as\s+(\w+))|(?:{([^}]+)})|(\w+))\s+from\s+['"]([^'"]+)['"]/g;
51
- let match;
52
- while ((match = importPattern.exec(content)) !== null) {
53
- const namespace = match[1];
54
- const namedImports = match[2];
55
- const defaultImport = match[3];
56
- const modulePath = match[4];
57
-
58
- imports.push({
59
- namespace,
60
- namedImports: namedImports ? namedImports.split(',').map(s => s.trim().replace(/\s+as\s+\w+/, '')) : [],
61
- defaultImport,
62
- modulePath,
63
- line: content.substring(0, match.index).split('\n').length
64
- });
65
- }
66
-
67
- // Find all exports
68
- const exportPattern = /export\s+(?:(?:default\s+)?(?:function|const|class|interface|type)\s+(\w+)|(?:{([^}]+)})|(\w+))/g;
69
- while ((match = exportPattern.exec(content)) !== null) {
70
- const namedExport = match[1] || match[3];
71
- const namedExports = match[2];
72
-
73
- if (namedExport) {
74
- exports.push(namedExport);
75
- }
76
- if (namedExports) {
77
- exports.push(...namedExports.split(',').map(s => s.trim()));
78
- }
79
- }
80
-
81
- // Find usage of imported identifiers (simplified heuristic)
82
- imports.forEach(imp => {
83
- if (imp.defaultImport) {
84
- // Check if default import is used
85
- const usagePattern = new RegExp(`\\b${imp.defaultImport}\\b`, 'g');
86
- if (usagePattern.test(content)) {
87
- used.add(imp.defaultImport);
88
- }
89
- }
90
- if (imp.namespace) {
91
- const usagePattern = new RegExp(`\\b${imp.namespace}\\.`, 'g');
92
- if (usagePattern.test(content)) {
93
- used.add(imp.namespace);
94
- }
95
- }
96
- imp.namedImports.forEach(name => {
97
- const cleanName = name.trim();
98
- const usagePattern = new RegExp(`\\b${cleanName}\\b`, 'g');
99
- // Count occurrences - if more than 1, it's likely used (1 is the import itself)
100
- const matches = content.match(usagePattern);
101
- if (matches && matches.length > 1) {
102
- used.add(cleanName);
103
- }
104
- });
105
- });
106
-
107
- importMap.set(relativePath, { imports, exports, content });
108
- usageMap.set(relativePath, used);
109
- } catch (error) {
110
- // Skip files with errors
111
- }
112
- }
113
-
114
- // Second pass: analyze imports
115
- for (const [filePath, { imports, content }] of importMap.entries()) {
116
- const relativePath = filePath;
117
- const normalizedPath = relativePath.replace(/\\/g, '/');
118
-
119
- // Skip pace-core package files - imports check is for consuming applications, not the library itself
120
- // The library must use internal import paths and may have unused imports in examples/config files
121
- const isPaceCorePackage = normalizedPath.includes('packages/core/') || normalizedPath.startsWith('packages/core/');
122
- if (isPaceCorePackage) {
123
- continue; // Skip library files
124
- }
125
-
126
- // Skip root-level src directory - in pace-core repository, this is a demo/showcase app
127
- const isRootSrc = normalizedPath.startsWith('src/') && !normalizedPath.includes('packages/');
128
- if (isRootSrc) {
129
- continue; // Skip demo app files
130
- }
131
-
132
- // Skip scripts directory - utility scripts don't need import validation
133
- const isScript = normalizedPath.startsWith('scripts/') || normalizedPath.includes('/scripts/');
134
- if (isScript) {
135
- continue; // Skip script files
136
- }
137
-
138
- const used = usageMap.get(filePath) || new Set();
139
-
140
- imports.forEach(imp => {
141
- // Check for unused imports from pace-core
142
- if (imp.modulePath === '@jmruthers/pace-core' || imp.modulePath.startsWith('@jmruthers/pace-core/')) {
143
- const unused = [];
144
-
145
- if (imp.defaultImport && !used.has(imp.defaultImport)) {
146
- unused.push(imp.defaultImport);
147
- }
148
-
149
- imp.namedImports.forEach(name => {
150
- if (!used.has(name.trim())) {
151
- unused.push(name.trim());
152
- }
153
- });
154
-
155
- if (imp.namespace && !used.has(imp.namespace)) {
156
- unused.push(`${imp.namespace} (namespace)`);
157
- }
158
-
159
- if (unused.length > 0) {
160
- warnings.push({
161
- type: 'unused-import',
162
- file: relativePath,
163
- line: imp.line,
164
- message: `Unused imports from pace-core: ${unused.join(', ')}`,
165
- recommendation: `Remove unused imports to reduce bundle size`
166
- });
167
- }
168
- }
169
-
170
- // Check for wrong import paths
171
- if (imp.modulePath.startsWith('@jmruthers/pace-core/')) {
172
- const validPaths = [
173
- '@jmruthers/pace-core',
174
- '@jmruthers/pace-core/components',
175
- '@jmruthers/pace-core/hooks',
176
- '@jmruthers/pace-core/utils',
177
- '@jmruthers/pace-core/providers',
178
- '@jmruthers/pace-core/rbac',
179
- '@jmruthers/pace-core/types'
180
- ];
181
-
182
- if (!validPaths.includes(imp.modulePath)) {
183
- warnings.push({
184
- type: 'wrong-import-path',
185
- file: relativePath,
186
- line: imp.line,
187
- message: `Invalid import path: ${imp.modulePath}`,
188
- recommendation: `Use one of the valid paths: ${validPaths.join(', ')}`
189
- });
190
- }
191
- }
192
-
193
- // Check for barrel import anti-patterns (importing entire modules)
194
- if (imp.namespace && (imp.modulePath === '@jmruthers/pace-core' || imp.modulePath.startsWith('@jmruthers/pace-core/'))) {
195
- warnings.push({
196
- type: 'barrel-import',
197
- file: relativePath,
198
- line: imp.line,
199
- message: `Namespace import from pace-core: import * as ${imp.namespace}`,
200
- recommendation: `Import specific exports instead to enable tree-shaking: import { Component1, Component2 } from '@jmruthers/pace-core'`
201
- });
202
- }
203
- });
204
- }
205
-
206
- // Check for circular dependencies (simplified - check if file A imports B and B imports A)
207
- const filePaths = Array.from(importMap.keys());
208
- for (let i = 0; i < filePaths.length; i++) {
209
- for (let j = i + 1; j < filePaths.length; j++) {
210
- const fileA = filePaths[i];
211
- const fileB = filePaths[j];
212
- const importsA = importMap.get(fileA)?.imports || [];
213
- const importsB = importMap.get(fileB)?.imports || [];
214
-
215
- // Check if A imports B
216
- const aImportsB = importsA.some(imp => {
217
- const importPath = imp.modulePath;
218
- return importPath.startsWith('./') || importPath.startsWith('../') ?
219
- path.resolve(path.dirname(fileA), importPath) === fileB : false;
220
- });
221
-
222
- // Check if B imports A
223
- const bImportsA = importsB.some(imp => {
224
- const importPath = imp.modulePath;
225
- return importPath.startsWith('./') || importPath.startsWith('../') ?
226
- path.resolve(path.dirname(fileB), importPath) === fileA : false;
227
- });
228
-
229
- if (aImportsB && bImportsA) {
230
- issues.push({
231
- type: 'circular-dependency',
232
- file: fileA,
233
- message: `Circular dependency detected between ${fileA} and ${fileB}`,
234
- recommendation: `Refactor to break the circular dependency by extracting shared code to a third module`
235
- });
236
- }
237
- }
238
- }
239
-
240
- return { issues, warnings, suggestions };
241
- }
242
- };
243
-
244
- module.exports = importsCheck;