@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,325 +0,0 @@
1
- #!/usr/bin/env node
2
-
3
- /**
4
- * Performance Check Module
5
- * @package @jmruthers/pace-core
6
- * @module Audit/Checks/Performance
7
- *
8
- * Checks for:
9
- * - Missing React.memo on expensive components
10
- * - Missing useMemo/useCallback for expensive computations
11
- * - Unnecessary re-renders
12
- * - Large inline objects/functions in JSX props
13
- * - Missing key props in lists
14
- */
15
-
16
- const fs = require('fs');
17
- const { getRelativePath, getLineNumber } = require('../utils.cjs');
18
-
19
- const performanceCheck = {
20
- name: 'performance',
21
- description: 'Performance anti-patterns (missing memoization, unnecessary re-renders)',
22
- severity: 'warning',
23
-
24
- async run(context) {
25
- const { projectRoot, files } = context;
26
- const issues = [];
27
- const warnings = [];
28
- const suggestions = [];
29
-
30
- if (!files || files.length === 0) {
31
- return { issues, warnings, suggestions };
32
- }
33
-
34
- for (const filePath of files) {
35
- try {
36
- // Only check React component files
37
- if (!filePath.match(/\.(tsx|jsx)$/)) {
38
- continue;
39
- }
40
-
41
- const content = fs.readFileSync(filePath, 'utf8');
42
- const relativePath = getRelativePath(filePath, projectRoot);
43
- const normalizedPath = relativePath.replace(/\\/g, '/');
44
-
45
- // Skip root-level src directory - in pace-core repository, this is a demo/showcase app
46
- // Note: We DO check packages/core/ files because performance issues (like missing key props) are real issues that should be fixed
47
- const isRootSrc = normalizedPath.startsWith('src/') && !normalizedPath.includes('packages/');
48
- if (isRootSrc) {
49
- continue; // Skip demo app files
50
- }
51
-
52
- // Skip scripts directory - utility scripts don't need performance validation
53
- const isScript = normalizedPath.startsWith('scripts/') || normalizedPath.includes('/scripts/');
54
- if (isScript) {
55
- continue; // Skip script files
56
- }
57
-
58
- // Skip examples directory - these are demo/example files, not production code
59
- // Examples are meant to show usage patterns, not be optimized for performance
60
- const isExample = normalizedPath.includes('/examples/') || normalizedPath.startsWith('examples/');
61
- if (isExample) {
62
- continue; // Skip example files
63
- }
64
-
65
- // Skip test files - test code doesn't need performance optimization
66
- const isTestFile = normalizedPath.includes('.test.') ||
67
- normalizedPath.includes('.spec.') ||
68
- normalizedPath.includes('test-setup') ||
69
- normalizedPath.includes('__tests__');
70
- if (isTestFile) {
71
- continue; // Skip test files
72
- }
73
-
74
- // For library code (packages/core/src), be more lenient with performance suggestions
75
- // Library components often use inline functions which are acceptable patterns
76
- const isLibraryCode = normalizedPath.includes('packages/core/src/');
77
-
78
- // Check for components that could benefit from React.memo
79
- // Note: For library components, React.memo should be used judiciously
80
- // We only suggest it for components that are likely to render frequently
81
- const componentPattern = /export\s+(default\s+)?(function|const)\s+(\w+)\s*[=\(]/g;
82
- let match;
83
- while ((match = componentPattern.exec(content)) !== null) {
84
- const componentName = match[3];
85
- const isMemoized = content.includes(`React.memo(${componentName})`) ||
86
- content.includes(`memo(${componentName})`) ||
87
- content.includes(`export default memo(${componentName})`);
88
-
89
- // Check if component receives props and is not memoized
90
- if (match[0].includes('props') || match[0].includes('{') || content.includes(`${componentName}({`)) {
91
- // Check if component has significant JSX (heuristic: more than 5 lines of JSX)
92
- const componentStart = match.index;
93
- const afterMatch = content.substring(componentStart);
94
- const jsxLines = (afterMatch.match(/<[A-Z]/g) || []).length;
95
-
96
- // Skip if component uses forwardRef (memoization handled differently)
97
- // Skip if component is a hook (starts with 'use')
98
- // Skip if component is very simple (less than 5 JSX elements)
99
- // Skip if component is already memoized
100
- if (jsxLines > 5 && !isMemoized && !content.includes('forwardRef') && !componentName.startsWith('use')) {
101
- // For library components, be more conservative - only suggest for components
102
- // that are likely to be in lists or render frequently
103
- // Skip if it's a page-level component (like *Page, *Layout, *Route)
104
- const isPageComponent = /Page|Layout|Route|Modal|Dialog/.test(componentName);
105
-
106
- // Only suggest memo for components that are likely to render frequently
107
- // (not page-level components, which typically render once per route)
108
- // For library code, skip React.memo suggestions entirely - memoization decisions
109
- // should be made by the consuming application based on their specific use case
110
- if (!isPageComponent && !isLibraryCode) {
111
- suggestions.push({
112
- type: 'missing-memo',
113
- file: relativePath,
114
- line: getLineNumber(content, match.index),
115
- message: `Component '${componentName}' receives props but is not memoized`,
116
- recommendation: `Consider wrapping with React.memo if the component renders frequently: export default React.memo(${componentName})`
117
- });
118
- }
119
- // For library code, skip React.memo suggestions - library components are often
120
- // controlled by parent components, and memoization should be decided by consumers
121
- }
122
- }
123
- }
124
-
125
- // Check for large inline objects/functions in JSX props
126
- // But exclude JSX children (which is standard React pattern)
127
- const jsxPropPattern = /<[A-Z]\w+\s+[^>]*\{[^}]{100,}[^>]*>/g;
128
- let jsxMatch;
129
- while ((jsxMatch = jsxPropPattern.exec(content)) !== null) {
130
- const matchText = jsxMatch[0];
131
-
132
- // Check if this is JSX children (element prop) or guard component props
133
- // Patterns to exclude (these are valid React patterns):
134
- // 1. <Route element={<Component />} /> - React Router pattern
135
- // 2. <GuardComponent fallback={<Component />} /> - Guard component pattern
136
- // 3. <Component>{children}</Component> - JSX children (but this won't match our pattern)
137
- // 4. Any prop that contains JSX elements (starts with <)
138
-
139
- const isRouteElement = /element\s*=\s*\{/.test(matchText);
140
- const isGuardProp = /(fallback|loading|error|children)\s*=\s*\{/.test(matchText);
141
- const hasJSXElement = /<[A-Z]\w+/.test(matchText);
142
-
143
- // Also check if it's a className utility call (like cn()) - not a performance issue
144
- const isUtilityCall = /cn\s*\(|clsx\s*\(|classnames\s*\(/.test(matchText);
145
-
146
- // Only flag if it's an actual inline object/function, not JSX children
147
- if (!isRouteElement && !isGuardProp && !hasJSXElement && !isUtilityCall) {
148
- warnings.push({
149
- type: 'inline-object-in-jsx',
150
- file: relativePath,
151
- line: getLineNumber(content, jsxMatch.index),
152
- message: 'Large inline object or function in JSX props detected',
153
- recommendation: 'Extract inline objects/functions to variables or useMemo/useCallback to prevent unnecessary re-renders. JSX children in props (like React Router element prop or guard component fallback prop) are standard React patterns and not performance issues.'
154
- });
155
- }
156
- }
157
-
158
- // Check for missing key props in lists
159
- // Only flag if JSX is returned, not data arrays
160
- const mapPattern = /\.map\s*\(\s*\([^)]+\)\s*=>/g;
161
- while ((match = mapPattern.exec(content)) !== null) {
162
- const afterMap = content.substring(match.index, match.index + 500);
163
- // Check if JSX is returned without key
164
- // Also check if it's actually returning JSX (not just data objects)
165
- const returnsJSX = afterMap.includes('return') && afterMap.includes('<');
166
-
167
- // Check for key in various formats: key=, key:, or inside React.cloneElement
168
- const hasKey = afterMap.includes('key=') ||
169
- /key\s*:/.test(afterMap) ||
170
- /React\.cloneElement\s*\([^,]+,\s*\{[^}]*key\s*:/.test(afterMap);
171
-
172
- // Check if it's a data transformation (returns object/array/primitive, not JSX)
173
- // Pattern 1: Returns a simple value like .map(([key, _]) => key)
174
- const returnsSimpleValue = /=>\s*[a-zA-Z_$][a-zA-Z0-9_$]*\s*;/.test(afterMap) && !afterMap.includes('<');
175
- // Pattern 2: Returns a data object without JSX
176
- const returnsDataObject = /return\s*\{[^<]*\}/.test(afterMap) && !afterMap.match(/return\s*\{[^<]*<[A-Z]/);
177
- // Pattern 3: Returns array element access like .map((subRow) => subRow.original)
178
- const returnsDataProperty = /=>\s*[a-zA-Z_$][a-zA-Z0-9_$]*\.[a-zA-Z_$][a-zA-Z0-9_$]*\s*[;}]/.test(afterMap) && !afterMap.includes('<');
179
-
180
- // Skip pace-core files for this check - library code has complex patterns that are hard to detect accurately
181
- const isPaceCorePackage = normalizedPath.includes('packages/core/') || normalizedPath.startsWith('packages/core/');
182
-
183
- if (returnsJSX && !hasKey && !returnsDataObject && !returnsSimpleValue && !returnsDataProperty && !isPaceCorePackage) {
184
- warnings.push({
185
- type: 'missing-key',
186
- file: relativePath,
187
- line: getLineNumber(content, match.index),
188
- message: 'Array map returns JSX without key prop',
189
- recommendation: 'Add a unique key prop to list items: {items.map(item => <Item key={item.id} ... />)}. Data array transformations (not JSX) do not need keys.'
190
- });
191
- }
192
- }
193
-
194
- // Check for expensive computations that could use useMemo
195
- const expensivePatterns = [
196
- /\.filter\([^)]*\)\.map\(/g, // filter().map() chains
197
- /\.sort\([^)]*\)\.map\(/g, // sort().map() chains
198
- /\.reduce\([^)]*\)/g // reduce operations
199
- ];
200
-
201
- expensivePatterns.forEach(pattern => {
202
- let expMatch;
203
- while ((expMatch = pattern.exec(content)) !== null) {
204
- // Check a larger context to see if it's already in useMemo or useCallback
205
- const beforeMatch = content.substring(Math.max(0, expMatch.index - 500), expMatch.index);
206
- const afterMatch = content.substring(expMatch.index, Math.min(content.length, expMatch.index + 200));
207
-
208
- // Check if it's already in useMemo or useCallback
209
- if (beforeMatch.includes('useMemo') || beforeMatch.includes('useCallback')) {
210
- continue;
211
- }
212
-
213
- // Check if it's inside a function definition that's static (like aggregateFn, cell renderer, etc.)
214
- // These are function definitions that are called by the library, not recalculated on every render
215
- const isStaticFunctionDefinition = /(aggregateFn|cell|header|footer|render|format|transform)\s*[:=]\s*\(/.test(beforeMatch);
216
- if (isStaticFunctionDefinition) {
217
- continue; // Skip static function definitions
218
- }
219
-
220
- // Check if it's inside a const/let declaration that's likely already memoized
221
- // Pattern: const x = useMemo(() => ... or const x = useCallback(() => ...
222
- const isInMemoizedConst = /const\s+\w+\s*=\s*(useMemo|useCallback)\s*\(/.test(beforeMatch);
223
- if (isInMemoizedConst) {
224
- continue;
225
- }
226
-
227
- // Check if it's part of a column definition (static, not recalculated)
228
- const isColumnDefinition = /(accessorKey|header|cell|aggregateFn|aggregateCell)\s*:/.test(beforeMatch);
229
- if (isColumnDefinition) {
230
- continue; // Skip column definitions - these are static
231
- }
232
-
233
- suggestions.push({
234
- type: 'expensive-computation',
235
- file: relativePath,
236
- line: getLineNumber(content, expMatch.index),
237
- message: 'Expensive computation detected that could benefit from useMemo',
238
- recommendation: 'Wrap expensive computations in useMemo to prevent recalculation on every render'
239
- });
240
- }
241
- });
242
-
243
- // Check for functions passed as props that could use useCallback
244
- // Only flag complex inline functions, not simple event handlers
245
- // For library code, be very lenient - inline functions are often acceptable patterns
246
- if (!isLibraryCode) {
247
- // Only check for consuming applications, not library code
248
- const functionPropPattern = /(onClick|onChange|onSubmit|onFocus|onBlur|onMouseEnter|onMouseLeave|onValueChange)\s*=\s*\{[^}]*=>/g;
249
- let funcMatch;
250
- while ((funcMatch = functionPropPattern.exec(content)) !== null) {
251
- const beforeMatch = content.substring(Math.max(0, funcMatch.index - 150), funcMatch.index);
252
- const afterMatch = content.substring(funcMatch.index, Math.min(content.length, funcMatch.index + 300));
253
-
254
- // Skip if already using useCallback or defined as const
255
- if (beforeMatch.includes('useCallback') || beforeMatch.includes('const ')) {
256
- continue;
257
- }
258
-
259
- // Extract the function body to check complexity
260
- // Handle both arrow functions with and without braces
261
- let funcBody = '';
262
- const arrowMatch = afterMatch.match(/=>\s*(\{?)([^}]*?)(\}?)/);
263
- if (arrowMatch) {
264
- if (arrowMatch[1] === '{') {
265
- // Multi-line function with braces - extract content between braces
266
- const braceMatch = afterMatch.match(/=>\s*\{([^}]+)\}/);
267
- if (braceMatch) {
268
- funcBody = braceMatch[1];
269
- }
270
- } else {
271
- // Single expression arrow function
272
- funcBody = arrowMatch[2];
273
- }
274
- }
275
-
276
- if (funcBody) {
277
- const trimmedBody = funcBody.trim();
278
-
279
- // Very short handlers are usually simple
280
- if (trimmedBody.length < 50) {
281
- continue;
282
- }
283
-
284
- // Check for simple setState patterns (even with object spread)
285
- const isSimpleSetState = /^\s*set\w+\s*\([^)]*\)\s*;?\s*$/.test(trimmedBody) ||
286
- /^\s*set\w+\s*\([^)]*prev\s*=>\s*\(\{[^}]*\}\)[^}]*\)\s*;?\s*$/.test(trimmedBody);
287
-
288
- // Check for simple function calls
289
- const isSimpleFunctionCall = /^\s*(handle\w+|on\w+|navigate|window\.|document\.)\s*\([^)]*\)\s*;?\s*$/.test(trimmedBody);
290
-
291
- // Check for simple conditional (single if/ternary)
292
- const isSimpleConditional = /^\s*(if\s*\([^)]+\)\s*\{[^}]{0,50}\}|[^?]+\?[^:]+:[^;]+;?)\s*$/.test(trimmedBody);
293
-
294
- // Check for simple value transformations (common in library components)
295
- // Pattern: (e) => handleFunc(e.target.value || undefined)
296
- // Pattern: (e) => handleFunc(e.target.value ? transform(e.target.value) : undefined)
297
- const isSimpleValueTransform = /^\s*\w+\s*\([^)]*\.(target|value|checked|selected)[^)]*\)\s*;?\s*$/.test(trimmedBody) ||
298
- /^\s*\w+\s*\([^)]*\?[^:]+:[^;]+\)\s*;?\s*$/.test(trimmedBody);
299
-
300
- // Skip simple handlers - they're fine as inline functions
301
- if (isSimpleSetState || isSimpleFunctionCall || isSimpleConditional || isSimpleValueTransform) {
302
- continue;
303
- }
304
- }
305
-
306
- suggestions.push({
307
- type: 'inline-function-prop',
308
- file: relativePath,
309
- line: getLineNumber(content, funcMatch.index),
310
- message: 'Complex inline function passed as prop',
311
- recommendation: 'Use useCallback to memoize complex functions passed as props to prevent child re-renders. Simple event handlers (single setState call or function invocation) are fine as inline functions.'
312
- });
313
- }
314
- }
315
- // For library code, skip this check entirely - inline functions are acceptable patterns
316
- } catch (error) {
317
- // Skip files with errors
318
- }
319
- }
320
-
321
- return { issues, warnings, suggestions };
322
- }
323
- };
324
-
325
- module.exports = performanceCheck;
@@ -1,117 +0,0 @@
1
- #!/usr/bin/env node
2
-
3
- /**
4
- * Route Protection Check Module
5
- * @package @jmruthers/pace-core
6
- * @module Audit/Checks/Routes
7
- *
8
- * Checks for:
9
- * - Routes without PagePermissionGuard
10
- * - Incorrect route nesting
11
- * - Missing route error boundaries
12
- */
13
-
14
- const fs = require('fs');
15
- const { getRelativePath, getLineNumber } = require('../utils.cjs');
16
-
17
- const routesCheck = {
18
- name: 'routes',
19
- description: 'Route protection (PagePermissionGuard, route nesting)',
20
- severity: 'error',
21
-
22
- async run(context) {
23
- const { projectRoot, files } = context;
24
- const issues = [];
25
- const warnings = [];
26
- const suggestions = [];
27
-
28
- if (!files || files.length === 0) {
29
- return { issues, warnings, suggestions };
30
- }
31
-
32
- for (const filePath of files) {
33
- try {
34
- const content = fs.readFileSync(filePath, 'utf8');
35
- const relativePath = getRelativePath(filePath, projectRoot);
36
- const normalizedPath = relativePath.replace(/\\/g, '/');
37
-
38
- // Skip pace-core package files - routes check is for consuming applications, not the library itself
39
- // Note: Library components (like ProtectedRoute, PaceAppLayout) ARE the route protection components
40
- // They don't need to use PagePermissionGuard - they provide the protection functionality
41
- const isPaceCorePackage = normalizedPath.includes('packages/core/') || normalizedPath.startsWith('packages/core/');
42
- if (isPaceCorePackage) {
43
- continue; // Skip library files (including examples)
44
- }
45
-
46
- // Skip root-level src directory - in pace-core repository, this is a demo/showcase app
47
- const isRootSrc = normalizedPath.startsWith('src/') && !normalizedPath.includes('packages/');
48
- if (isRootSrc) {
49
- continue; // Skip demo app files
50
- }
51
-
52
- // Skip scripts directory - utility scripts don't need route protection validation
53
- const isScript = normalizedPath.startsWith('scripts/') || normalizedPath.includes('/scripts/');
54
- if (isScript) {
55
- continue; // Skip script files
56
- }
57
-
58
- // Check for route definitions
59
- const routePatterns = [
60
- /<Route\s+path=["'][^"']+["']/g,
61
- /<Route\s+element\s*=/g,
62
- /createBrowserRouter\s*\(/g,
63
- /createRoutesFromElements/g
64
- ];
65
-
66
- const hasRoutes = routePatterns.some(pattern => pattern.test(content));
67
-
68
- if (hasRoutes) {
69
- // Check for PagePermissionGuard
70
- const hasPagePermissionGuard = content.includes('PagePermissionGuard') ||
71
- content.includes('from \'@jmruthers/pace-core/rbac\'');
72
-
73
- if (!hasPagePermissionGuard && !relativePath.includes('test') && !relativePath.includes('spec')) {
74
- issues.push({
75
- type: 'unprotected-route',
76
- file: relativePath,
77
- message: 'Route file found without PagePermissionGuard',
78
- recommendation: 'Wrap routes with PagePermissionGuard from @jmruthers/pace-core/rbac to enforce permissions'
79
- });
80
- }
81
-
82
- // Check for route nesting issues
83
- const routeCount = (content.match(/<Route/g) || []).length;
84
- if (routeCount > 0) {
85
- // Check if routes are properly nested
86
- const hasRoutesWrapper = content.includes('<Routes') || content.includes('<BrowserRouter');
87
- if (!hasRoutesWrapper) {
88
- warnings.push({
89
- type: 'route-nesting',
90
- file: relativePath,
91
- message: 'Route elements found but may not be wrapped in <Routes>',
92
- recommendation: 'Ensure all Route elements are wrapped in <Routes> component'
93
- });
94
- }
95
- }
96
- }
97
-
98
- // Check for error boundaries around routes
99
- if (hasRoutes && !content.includes('ErrorBoundary') && !content.includes('error-boundary')) {
100
- suggestions.push({
101
- type: 'missing-route-error-boundary',
102
- file: relativePath,
103
- message: 'Routes without error boundary',
104
- recommendation: 'Wrap routes with ErrorBoundary to catch and handle route errors gracefully'
105
- });
106
- }
107
-
108
- } catch (error) {
109
- // Skip files with errors
110
- }
111
- }
112
-
113
- return { issues, warnings, suggestions };
114
- }
115
- };
116
-
117
- module.exports = routesCheck;
@@ -1,130 +0,0 @@
1
- #!/usr/bin/env node
2
-
3
- /**
4
- * State Management Check Module
5
- * @package @jmruthers/pace-core
6
- * @module Audit/Checks/State
7
- *
8
- * Checks for:
9
- * - Improper state lifting
10
- * - Prop drilling (too many levels)
11
- * - Missing state normalization
12
- * - Unnecessary global state
13
- */
14
-
15
- const fs = require('fs');
16
- const { getRelativePath, getLineNumber } = require('../utils.cjs');
17
-
18
- const stateCheck = {
19
- name: 'state',
20
- description: 'State management patterns (prop drilling, state lifting)',
21
- severity: 'suggestion',
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
- for (const filePath of files) {
34
- try {
35
- // Only check React component files
36
- if (!filePath.match(/\.(tsx|jsx)$/)) {
37
- continue;
38
- }
39
-
40
- const content = fs.readFileSync(filePath, 'utf8');
41
- const relativePath = getRelativePath(filePath, projectRoot);
42
- const normalizedPath = relativePath.replace(/\\/g, '/');
43
-
44
- // Skip pace-core package files - state check is for consuming applications, not the library itself
45
- // Note: Library components are designed to have many props for configurability - this is not prop drilling
46
- const isPaceCorePackage = normalizedPath.includes('packages/core/') || normalizedPath.startsWith('packages/core/');
47
- if (isPaceCorePackage) {
48
- continue; // Skip library files
49
- }
50
-
51
- // Skip root-level src directory - in pace-core repository, this is a demo/showcase app
52
- const isRootSrc = normalizedPath.startsWith('src/') && !normalizedPath.includes('packages/');
53
- if (isRootSrc) {
54
- continue; // Skip demo app files
55
- }
56
-
57
- // Skip scripts directory - utility scripts don't need state management validation
58
- const isScript = normalizedPath.startsWith('scripts/') || normalizedPath.includes('/scripts/');
59
- if (isScript) {
60
- continue; // Skip script files
61
- }
62
-
63
- // Check for prop drilling (component with many props that are just passed through)
64
- const componentPattern = /(?:function|const)\s+(\w+)\s*[=\(]\s*\([^)]*\)/g;
65
- let match;
66
- while ((match = componentPattern.exec(content)) !== null) {
67
- const propsMatch = match[0].match(/\(([^)]+)\)/);
68
- if (propsMatch) {
69
- const props = propsMatch[1].split(',').map(p => p.trim()).filter(p => p);
70
-
71
- // Check if component has many props (potential prop drilling)
72
- if (props.length > 8) {
73
- suggestions.push({
74
- type: 'many-props',
75
- file: relativePath,
76
- line: getLineNumber(content, match.index),
77
- message: `Component has ${props.length} props - may indicate prop drilling`,
78
- recommendation: 'Consider using context or state management library if props are passed through multiple levels'
79
- });
80
- }
81
-
82
- // Check if props are just passed through to children
83
- const componentBody = content.substring(match.index, Math.min(content.length, match.index + 1000));
84
- const passThroughProps = props.filter(prop => {
85
- const propName = prop.split(':')[0].trim();
86
- return new RegExp(`<\\w+\\s+[^>]*${propName}=`, 'g').test(componentBody);
87
- });
88
-
89
- if (passThroughProps.length > props.length * 0.7 && props.length > 3) {
90
- suggestions.push({
91
- type: 'prop-drilling',
92
- file: relativePath,
93
- line: getLineNumber(content, match.index),
94
- message: 'Component appears to be passing most props through to children',
95
- recommendation: 'Consider lifting state up or using React Context to avoid prop drilling'
96
- });
97
- }
98
- }
99
- }
100
-
101
- // Check for unnecessary useState when data comes from props
102
- const useStatePattern = /const\s+\[(\w+),\s*set\w+\]\s*=\s*useState/g;
103
- let stateMatch;
104
- while ((stateMatch = useStatePattern.exec(content)) !== null) {
105
- const stateVar = stateMatch[1];
106
- const beforeState = content.substring(Math.max(0, stateMatch.index - 200), stateMatch.index);
107
-
108
- // Check if there's a prop with the same name
109
- const propPattern = new RegExp(`(?:props\\.|\\{\\s*${stateVar}\\s*\\})`, 'g');
110
- if (propPattern.test(beforeState)) {
111
- suggestions.push({
112
- type: 'unnecessary-state',
113
- file: relativePath,
114
- line: getLineNumber(content, stateMatch.index),
115
- message: `State variable '${stateVar}' may duplicate a prop`,
116
- recommendation: 'If state comes from props, consider using the prop directly or use derived state pattern'
117
- });
118
- }
119
- }
120
-
121
- } catch (error) {
122
- // Skip files with errors
123
- }
124
- }
125
-
126
- return { issues, warnings, suggestions };
127
- }
128
- };
129
-
130
- module.exports = stateCheck;
@@ -1,65 +0,0 @@
1
- #!/usr/bin/env node
2
-
3
- /**
4
- * File Structure Check Module
5
- * @package @jmruthers/pace-core
6
- * @module Audit/Checks/Structure
7
- */
8
-
9
- const fs = require('fs');
10
- const path = require('path');
11
-
12
- const structureCheck = {
13
- name: 'structure',
14
- description: 'File structure checks (required/recommended directories)',
15
- severity: 'error',
16
-
17
- async run(context) {
18
- const { projectRoot } = context;
19
- const issues = [];
20
- const warnings = [];
21
-
22
- // Skip structure checks if this is the pace-core repository itself
23
- // Structure checks are for consuming applications, not the library repository
24
- // Detect pace-core repository by checking if packages/core exists
25
- const packagesCorePath = path.join(projectRoot, 'packages', 'core');
26
- const isPaceCoreRepository = fs.existsSync(packagesCorePath);
27
-
28
- if (isPaceCoreRepository) {
29
- // This is the pace-core library repository, not a consuming app
30
- // Skip structure checks - the library has its own structure
31
- return { issues: [], warnings: [], suggestions: [] };
32
- }
33
-
34
- const requiredDirs = ['src'];
35
- const recommendedDirs = ['src/components', 'src/hooks', 'src/utils', 'src/pages'];
36
-
37
- requiredDirs.forEach(dir => {
38
- const dirPath = path.join(projectRoot, dir);
39
- if (!fs.existsSync(dirPath)) {
40
- issues.push({
41
- type: 'missing-directory',
42
- file: dir,
43
- message: `Required directory '${dir}' is missing`,
44
- recommendation: `Create the '${dir}' directory`
45
- });
46
- }
47
- });
48
-
49
- recommendedDirs.forEach(dir => {
50
- const dirPath = path.join(projectRoot, dir);
51
- if (!fs.existsSync(dirPath)) {
52
- warnings.push({
53
- type: 'missing-directory',
54
- file: dir,
55
- message: `Recommended directory '${dir}' is missing`,
56
- recommendation: `Consider creating the '${dir}' directory for better organization`
57
- });
58
- }
59
- });
60
-
61
- return { issues, warnings, suggestions: [] };
62
- }
63
- };
64
-
65
- module.exports = structureCheck;