@jmruthers/pace-core 0.6.4 → 0.6.6

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 (387) hide show
  1. package/CHANGELOG.md +104 -0
  2. package/README.md +5 -403
  3. package/core-usage-manifest.json +93 -0
  4. package/cursor-rules/00-pace-core-compliance.mdc +128 -26
  5. package/cursor-rules/01-standards-compliance.mdc +49 -8
  6. package/cursor-rules/02-project-structure.mdc +6 -0
  7. package/cursor-rules/03-solid-principles.mdc +2 -0
  8. package/cursor-rules/04-testing-standards.mdc +2 -0
  9. package/cursor-rules/05-bug-reports-and-features.mdc +2 -0
  10. package/cursor-rules/06-code-quality.mdc +2 -0
  11. package/cursor-rules/07-tech-stack-compliance.mdc +2 -0
  12. package/cursor-rules/08-markup-quality.mdc +52 -27
  13. package/cursor-rules/09-rbac-compliance.mdc +462 -0
  14. package/cursor-rules/10-error-handling-patterns.mdc +179 -0
  15. package/cursor-rules/11-performance-optimization.mdc +169 -0
  16. package/cursor-rules/12-ci-cd-integration.mdc +150 -0
  17. package/dist/{AuthService-Cb34EQs3.d.ts → AuthService-DmfO5rGS.d.ts} +10 -0
  18. package/dist/{DataTable-BMRU8a1j.d.ts → DataTable-2N_tqbfq.d.ts} +1 -1
  19. package/dist/DataTable-LRJL4IRV.js +15 -0
  20. package/dist/{PublicPageProvider-DEMpysFR.d.ts → PublicPageProvider-BBH6Vqg7.d.ts} +72 -139
  21. package/dist/UnifiedAuthProvider-ZT6TIGM7.js +7 -0
  22. package/dist/api-Y4MQWOFW.js +4 -0
  23. package/dist/audit-MYQXYZFU.js +3 -0
  24. package/dist/{chunk-J36DSWQK.js → chunk-2HGJFNAH.js} +8 -28
  25. package/dist/{chunk-OEWDTMG7.js → chunk-3O3WHILE.js} +38 -121
  26. package/dist/{chunk-M43Y4SSO.js → chunk-3QC3KRHK.js} +1 -14
  27. package/dist/{chunk-DGUM43GV.js → chunk-3RG5ZIWI.js} +1 -4
  28. package/dist/{chunk-QXHPKYJV.js → chunk-4SXLQIZO.js} +1 -26
  29. package/dist/chunk-4T7OBVTU.js +62 -0
  30. package/dist/{chunk-E66EQZE6.js → chunk-6GLLNA6U.js} +3 -9
  31. package/dist/{chunk-ZSAAAMVR.js → chunk-6QYDGKQY.js} +1 -4
  32. package/dist/{chunk-NN6WWZ5U.js → chunk-7TYHROIV.js} +579 -563
  33. package/dist/{chunk-M7MPQISP.js → chunk-A55DK444.js} +9 -16
  34. package/dist/{chunk-63FOKYGO.js → chunk-AHU7G2R5.js} +2 -11
  35. package/dist/{chunk-L4OXEN46.js → chunk-BVP2BCJF.js} +2 -16
  36. package/dist/chunk-C7NSAPTL.js +1 -0
  37. package/dist/{chunk-YKRAFF5K.js → chunk-FENMYN2U.js} +73 -149
  38. package/dist/{chunk-AVMLPIM7.js → chunk-FTCRZOG2.js} +284 -432
  39. package/dist/{chunk-G37KK66H.js → chunk-FYHN4DD5.js} +60 -19
  40. package/dist/{chunk-VBXEHIUJ.js → chunk-HF6O3O37.js} +6 -88
  41. package/dist/{chunk-I6DAQMWX.js → chunk-LAZMKTTF.js} +930 -891
  42. package/dist/{chunk-5EC5MEWX.js → chunk-MAGBIDNS.js} +77 -222
  43. package/dist/chunk-MBADTM7L.js +64 -0
  44. package/dist/chunk-OHIK3MIO.js +994 -0
  45. package/dist/{chunk-6SOIHG6Z.js → chunk-S7DKJPLT.js} +115 -44
  46. package/dist/{chunk-FMUCXFII.js → chunk-SD6WQY43.js} +1 -5
  47. package/dist/{chunk-PWLANIRT.js → chunk-TTRFSOKR.js} +1 -7
  48. package/dist/{chunk-5DRSZLL2.js → chunk-UH3NTO3F.js} +1 -6
  49. package/dist/{chunk-FFQEQTNW.js → chunk-UIYSCEV7.js} +134 -45
  50. package/dist/{chunk-3LPHPB62.js → chunk-ZFYPMX46.js} +271 -87
  51. package/dist/{chunk-7JPAB3T5.js → chunk-ZS5VO5JB.js} +1989 -1283
  52. package/dist/components.d.ts +6 -6
  53. package/dist/components.js +57 -267
  54. package/dist/{database.generated-CzIvgcPu.d.ts → database.generated-CcnC_DRc.d.ts} +4795 -3691
  55. package/dist/eslint-rules/index.cjs +22 -0
  56. package/dist/eslint-rules/rules/compliance.cjs +348 -0
  57. package/dist/eslint-rules/rules/components.cjs +113 -0
  58. package/dist/eslint-rules/rules/imports.cjs +102 -0
  59. package/dist/eslint-rules/rules/rbac.cjs +790 -0
  60. package/dist/eslint-rules/utils/helpers.cjs +42 -0
  61. package/dist/eslint-rules/utils/manifest-loader.cjs +75 -0
  62. package/dist/hooks.d.ts +5 -5
  63. package/dist/hooks.js +62 -270
  64. package/dist/icons/index.d.ts +1 -0
  65. package/dist/icons/index.js +1 -0
  66. package/dist/index.d.ts +36 -26
  67. package/dist/index.js +87 -690
  68. package/dist/providers.d.ts +2 -2
  69. package/dist/providers.js +8 -35
  70. package/dist/rbac/eslint-rules.d.ts +46 -44
  71. package/dist/rbac/eslint-rules.js +7 -4
  72. package/dist/rbac/index.d.ts +124 -594
  73. package/dist/rbac/index.js +14 -207
  74. package/dist/styles/index.js +2 -12
  75. package/dist/theming/runtime.js +3 -19
  76. package/dist/{timezone-CHhWg6b4.d.ts → timezone-BZe_eUxx.d.ts} +175 -1
  77. package/dist/{types-CkbwOr4Y.d.ts → types-B-K_5VnO.d.ts} +4 -0
  78. package/dist/types-t9H8qKRw.d.ts +55 -0
  79. package/dist/types.d.ts +1 -1
  80. package/dist/types.js +7 -94
  81. package/dist/{usePublicRouteParams-i3qtoBgg.d.ts → usePublicRouteParams-COZ28Mvq.d.ts} +9 -9
  82. package/dist/utils.d.ts +24 -117
  83. package/dist/utils.js +54 -392
  84. package/docs/README.md +16 -6
  85. package/docs/api/README.md +4 -402
  86. package/docs/api/modules.md +454 -930
  87. package/docs/api-reference/components.md +3 -1
  88. package/docs/api-reference/deprecated.md +31 -6
  89. package/docs/api-reference/rpc-functions.md +78 -3
  90. package/docs/best-practices/accessibility.md +6 -3
  91. package/docs/getting-started/cursor-rules.md +3 -23
  92. package/docs/getting-started/dependencies.md +650 -0
  93. package/docs/getting-started/installation-guide.md +20 -7
  94. package/docs/getting-started/quick-start.md +23 -12
  95. package/docs/implementation-guides/permission-enforcement.md +4 -0
  96. package/docs/rbac/MIGRATION_GUIDE.md +819 -0
  97. package/docs/rbac/RBAC_CONTRACT.md +724 -0
  98. package/docs/rbac/README.md +12 -3
  99. package/docs/rbac/edge-functions-guide.md +376 -0
  100. package/docs/rbac/secure-client-protection.md +0 -34
  101. package/docs/standards/00-pace-core-compliance.md +967 -0
  102. package/docs/standards/01-standards-compliance.md +188 -0
  103. package/docs/standards/02-project-structure.md +985 -0
  104. package/docs/standards/03-solid-principles.md +39 -0
  105. package/docs/standards/04-testing-standards.md +36 -0
  106. package/docs/standards/05-bug-reports-and-features.md +27 -0
  107. package/docs/standards/{04-code-style-standard.md → 06-code-quality.md} +2 -0
  108. package/docs/standards/07-tech-stack-compliance.md +30 -0
  109. package/docs/standards/08-markup-quality.md +345 -0
  110. package/docs/standards/{07-rbac-and-rls-standard.md → 09-rbac-compliance.md} +149 -54
  111. package/docs/standards/10-error-handling-patterns.md +401 -0
  112. package/docs/standards/11-performance-optimization.md +348 -0
  113. package/docs/standards/12-ci-cd-integration.md +370 -0
  114. package/docs/standards/ALIGNMENT_REVIEW_SUMMARY.md +192 -0
  115. package/docs/standards/README.md +62 -33
  116. package/docs/troubleshooting/organisation-context-setup.md +42 -19
  117. package/eslint-config-pace-core.cjs +20 -4
  118. package/package.json +31 -21
  119. package/scripts/audit/audit-compliance.cjs +1295 -0
  120. package/scripts/audit/audit-components.cjs +260 -0
  121. package/scripts/audit/audit-dependencies.cjs +395 -0
  122. package/scripts/audit/audit-rbac.cjs +954 -0
  123. package/scripts/audit/audit-standards.cjs +1268 -0
  124. package/scripts/audit/index.cjs +1898 -194
  125. package/scripts/install-cursor-rules.cjs +259 -8
  126. package/scripts/validate-master.js +1 -1
  127. package/src/__tests__/fixtures/supabase.ts +1 -1
  128. package/src/__tests__/helpers/__tests__/component-test-utils.test.tsx +1 -1
  129. package/src/__tests__/helpers/__tests__/optimized-test-setup.test.ts +1 -1
  130. package/src/__tests__/helpers/__tests__/supabaseMock.test.ts +1 -1
  131. package/src/__tests__/helpers/__tests__/test-utils.test.tsx +3 -3
  132. package/src/__tests__/helpers/component-test-utils.tsx +1 -1
  133. package/src/__tests__/helpers/supabaseMock.ts +2 -2
  134. package/src/__tests__/public-recipe-view.test.ts +38 -9
  135. package/src/components/Button/Button.tsx +5 -1
  136. package/src/components/ContextSelector/ContextSelector.tsx +42 -39
  137. package/src/components/DataTable/__tests__/keyboard.test.tsx +15 -2
  138. package/src/components/DataTable/components/DataTableBody.tsx +55 -31
  139. package/src/components/DataTable/components/DataTableCore.tsx +186 -13
  140. package/src/components/DataTable/components/DataTableLayout.tsx +30 -5
  141. package/src/components/DataTable/components/EditFields.tsx +23 -3
  142. package/src/components/DataTable/components/EditableRow.tsx +7 -2
  143. package/src/components/DataTable/components/ImportModal.tsx +4 -6
  144. package/src/components/DataTable/components/RowComponent.tsx +12 -0
  145. package/src/components/DataTable/components/ViewRowModal.tsx +4 -4
  146. package/src/components/DataTable/components/__tests__/ImportModal.test.tsx +455 -96
  147. package/src/components/DataTable/components/__tests__/ViewRowModal.test.tsx +122 -58
  148. package/src/components/DataTable/components/hooks/usePermissionTracking.ts +0 -4
  149. package/src/components/DataTable/core/DataTableContext.tsx +1 -1
  150. package/src/components/DataTable/hooks/__tests__/useDataTableState.test.ts +51 -47
  151. package/src/components/DataTable/hooks/useDataTablePermissions.ts +24 -21
  152. package/src/components/DataTable/hooks/useDataTableState.ts +125 -9
  153. package/src/components/DataTable/hooks/useTableColumns.ts +40 -2
  154. package/src/components/DataTable/hooks/useTableHandlers.ts +11 -0
  155. package/src/components/DataTable/types.ts +5 -0
  156. package/src/components/DateTimeField/DateTimeField.tsx +20 -20
  157. package/src/components/DateTimeField/README.md +5 -2
  158. package/src/components/Dialog/Dialog.test.tsx +361 -318
  159. package/src/components/Dialog/Dialog.tsx +1154 -323
  160. package/src/components/Dialog/index.ts +3 -3
  161. package/src/components/FileDisplay/FileDisplay.test.tsx +45 -2
  162. package/src/components/FileDisplay/FileDisplay.tsx +28 -22
  163. package/src/components/Form/Form.test.tsx +9 -10
  164. package/src/components/Form/Form.tsx +369 -9
  165. package/src/components/InactivityWarningModal/InactivityWarningModal.test.tsx +28 -28
  166. package/src/components/InactivityWarningModal/InactivityWarningModal.tsx +40 -54
  167. package/src/components/LoginForm/LoginForm.tsx +2 -2
  168. package/src/components/NavigationMenu/NavigationMenu.test.tsx +14 -13
  169. package/src/components/NavigationMenu/NavigationMenu.tsx +2 -2
  170. package/src/components/NavigationMenu/useNavigationFiltering.ts +11 -21
  171. package/src/components/PaceAppLayout/PaceAppLayout.test.tsx +6 -4
  172. package/src/components/PaceAppLayout/PaceAppLayout.tsx +30 -41
  173. package/src/components/PaceAppLayout/README.md +10 -9
  174. package/src/components/PaceAppLayout/test-setup.tsx +40 -31
  175. package/src/components/PaceLoginPage/PaceLoginPage.test.tsx +108 -61
  176. package/src/components/PaceLoginPage/PaceLoginPage.tsx +27 -3
  177. package/src/components/PasswordChange/PasswordChangeForm.test.tsx +61 -0
  178. package/src/components/PasswordChange/PasswordChangeForm.tsx +20 -13
  179. package/src/components/PublicLayout/PublicLayout.test.tsx +7 -3
  180. package/src/components/PublicLayout/PublicPageLayout.tsx +5 -8
  181. package/src/components/Select/Select.tsx +23 -21
  182. package/src/components/Select/types.ts +1 -1
  183. package/src/components/UserMenu/UserMenu.test.tsx +38 -6
  184. package/src/components/UserMenu/UserMenu.tsx +39 -34
  185. package/src/components/index.ts +3 -4
  186. package/src/eslint-rules/index.cjs +22 -0
  187. package/src/eslint-rules/rules/compliance.cjs +348 -0
  188. package/src/eslint-rules/rules/components.cjs +113 -0
  189. package/src/eslint-rules/rules/imports.cjs +102 -0
  190. package/src/eslint-rules/rules/rbac.cjs +790 -0
  191. package/src/eslint-rules/utils/helpers.cjs +42 -0
  192. package/src/eslint-rules/utils/manifest-loader.cjs +75 -0
  193. package/src/hooks/__tests__/hooks.integration.test.tsx +6 -8
  194. package/src/hooks/__tests__/useAppConfig.unit.test.ts +129 -67
  195. package/src/hooks/__tests__/usePublicEvent.simple.test.ts +149 -67
  196. package/src/hooks/__tests__/usePublicEvent.test.ts +149 -79
  197. package/src/hooks/__tests__/usePublicEvent.unit.test.ts +158 -109
  198. package/src/hooks/__tests__/useSessionDraft.test.ts +163 -0
  199. package/src/hooks/__tests__/useSessionRestoration.unit.test.tsx +10 -5
  200. package/src/hooks/public/usePublicEvent.ts +62 -190
  201. package/src/hooks/public/usePublicEventLogo.test.ts +70 -17
  202. package/src/hooks/public/usePublicEventLogo.ts +19 -9
  203. package/src/hooks/useAppConfig.ts +26 -24
  204. package/src/hooks/useEventTheme.test.ts +211 -233
  205. package/src/hooks/useEventTheme.ts +19 -28
  206. package/src/hooks/useEvents.ts +11 -7
  207. package/src/hooks/useKeyboardShortcuts.ts +1 -1
  208. package/src/hooks/useOrganisationPermissions.ts +9 -11
  209. package/src/hooks/useOrganisations.ts +13 -7
  210. package/src/hooks/useQueryCache.ts +0 -1
  211. package/src/hooks/useSessionDraft.ts +380 -0
  212. package/src/hooks/useSessionRestoration.ts +3 -1
  213. package/src/icons/index.ts +27 -0
  214. package/src/index.ts +16 -1
  215. package/src/providers/OrganisationProvider.tsx +23 -14
  216. package/src/providers/services/EventServiceProvider.tsx +1 -24
  217. package/src/providers/services/UnifiedAuthProvider.tsx +5 -48
  218. package/src/providers/services/__tests__/UnifiedAuthProvider.integration.test.tsx +3 -0
  219. package/src/rbac/README.md +20 -20
  220. package/src/rbac/__tests__/adapters.comprehensive.test.tsx +7 -457
  221. package/src/rbac/__tests__/auth-rbac.e2e.test.tsx +33 -7
  222. package/src/rbac/adapters.tsx +7 -295
  223. package/src/rbac/api.test.ts +44 -56
  224. package/src/rbac/api.ts +10 -17
  225. package/src/rbac/cache-invalidation.ts +0 -1
  226. package/src/rbac/compliance/index.ts +10 -0
  227. package/src/rbac/compliance/pattern-detector.ts +553 -0
  228. package/src/rbac/compliance/runtime-compliance.ts +22 -0
  229. package/src/rbac/components/AccessDenied.tsx +150 -0
  230. package/src/rbac/components/NavigationGuard.tsx +12 -20
  231. package/src/rbac/components/PagePermissionGuard.tsx +4 -24
  232. package/src/rbac/components/__tests__/NavigationGuard.test.tsx +21 -8
  233. package/src/rbac/components/index.ts +3 -41
  234. package/src/rbac/eslint-rules.js +1 -1
  235. package/src/rbac/hooks/index.ts +0 -3
  236. package/src/rbac/hooks/permissions/index.ts +0 -3
  237. package/src/rbac/hooks/permissions/useAccessLevel.ts +4 -8
  238. package/src/rbac/hooks/usePermissions.ts +0 -3
  239. package/src/rbac/hooks/useRBAC.test.ts +21 -3
  240. package/src/rbac/hooks/useRBAC.ts +4 -3
  241. package/src/rbac/hooks/useResolvedScope.test.ts +57 -47
  242. package/src/rbac/hooks/useResolvedScope.ts +58 -140
  243. package/src/rbac/hooks/useResourcePermissions.test.ts +241 -60
  244. package/src/rbac/hooks/useResourcePermissions.ts +182 -63
  245. package/src/rbac/hooks/useRoleManagement.test.ts +65 -22
  246. package/src/rbac/hooks/useRoleManagement.ts +147 -19
  247. package/src/rbac/hooks/useSecureSupabase.ts +4 -8
  248. package/src/rbac/index.ts +7 -9
  249. package/src/rbac/permissions.ts +17 -17
  250. package/src/rbac/utils/contextValidator.ts +45 -7
  251. package/src/services/AuthService.ts +132 -23
  252. package/src/services/EventService.ts +4 -97
  253. package/src/services/InactivityService.ts +155 -58
  254. package/src/services/OrganisationService.ts +7 -44
  255. package/src/services/__tests__/OrganisationService.test.ts +26 -8
  256. package/src/services/base/BaseService.ts +0 -3
  257. package/src/styles/core.css +4 -0
  258. package/src/types/database.generated.ts +4733 -3809
  259. package/src/utils/__tests__/organisationContext.unit.test.ts +9 -10
  260. package/src/utils/context/organisationContext.test.ts +13 -28
  261. package/src/utils/context/organisationContext.ts +21 -52
  262. package/src/utils/dynamic/dynamicUtils.ts +1 -1
  263. package/src/utils/file-reference/index.ts +39 -15
  264. package/src/utils/formatting/formatDateTime.test.ts +3 -2
  265. package/src/utils/formatting/formatTime.test.ts +3 -2
  266. package/src/utils/google-places/loadGoogleMapsScript.ts +29 -4
  267. package/src/utils/index.ts +4 -1
  268. package/src/utils/persistence/__tests__/keyDerivation.test.ts +135 -0
  269. package/src/utils/persistence/__tests__/sensitiveFieldDetection.test.ts +123 -0
  270. package/src/utils/persistence/keyDerivation.ts +304 -0
  271. package/src/utils/persistence/sensitiveFieldDetection.ts +212 -0
  272. package/src/utils/security/secureStorage.ts +5 -5
  273. package/src/utils/storage/helpers.ts +3 -3
  274. package/src/utils/supabase/createBaseClient.ts +147 -0
  275. package/src/utils/timezone/timezone.test.ts +1 -2
  276. package/src/utils/timezone/timezone.ts +1 -1
  277. package/src/utils/validation/csrf.ts +4 -4
  278. package/cursor-rules/CHANGELOG.md +0 -119
  279. package/cursor-rules/README.md +0 -192
  280. package/dist/DataTable-E7YQZD7D.js +0 -175
  281. package/dist/DataTable-E7YQZD7D.js.map +0 -1
  282. package/dist/UnifiedAuthProvider-QPXO24B4.js +0 -18
  283. package/dist/UnifiedAuthProvider-QPXO24B4.js.map +0 -1
  284. package/dist/api-6LVZTHDS.js +0 -52
  285. package/dist/api-6LVZTHDS.js.map +0 -1
  286. package/dist/audit-V53FV5AG.js +0 -17
  287. package/dist/audit-V53FV5AG.js.map +0 -1
  288. package/dist/chunk-36LVWXB2.js +0 -227
  289. package/dist/chunk-36LVWXB2.js.map +0 -1
  290. package/dist/chunk-3LPHPB62.js.map +0 -1
  291. package/dist/chunk-5DRSZLL2.js.map +0 -1
  292. package/dist/chunk-5EC5MEWX.js.map +0 -1
  293. package/dist/chunk-63FOKYGO.js.map +0 -1
  294. package/dist/chunk-6SOIHG6Z.js.map +0 -1
  295. package/dist/chunk-7JPAB3T5.js.map +0 -1
  296. package/dist/chunk-ATKZM7RX.js +0 -2053
  297. package/dist/chunk-ATKZM7RX.js.map +0 -1
  298. package/dist/chunk-AVMLPIM7.js.map +0 -1
  299. package/dist/chunk-DGUM43GV.js.map +0 -1
  300. package/dist/chunk-E66EQZE6.js.map +0 -1
  301. package/dist/chunk-FFQEQTNW.js.map +0 -1
  302. package/dist/chunk-FMUCXFII.js.map +0 -1
  303. package/dist/chunk-G37KK66H.js.map +0 -1
  304. package/dist/chunk-I6DAQMWX.js.map +0 -1
  305. package/dist/chunk-J36DSWQK.js.map +0 -1
  306. package/dist/chunk-KQCRWDSA.js +0 -1
  307. package/dist/chunk-KQCRWDSA.js.map +0 -1
  308. package/dist/chunk-L4OXEN46.js.map +0 -1
  309. package/dist/chunk-LMC26NLJ.js +0 -84
  310. package/dist/chunk-LMC26NLJ.js.map +0 -1
  311. package/dist/chunk-M43Y4SSO.js.map +0 -1
  312. package/dist/chunk-M7MPQISP.js.map +0 -1
  313. package/dist/chunk-NN6WWZ5U.js.map +0 -1
  314. package/dist/chunk-OEWDTMG7.js.map +0 -1
  315. package/dist/chunk-PWLANIRT.js.map +0 -1
  316. package/dist/chunk-QXHPKYJV.js.map +0 -1
  317. package/dist/chunk-VBXEHIUJ.js.map +0 -1
  318. package/dist/chunk-YKRAFF5K.js.map +0 -1
  319. package/dist/chunk-ZSAAAMVR.js.map +0 -1
  320. package/dist/components.js.map +0 -1
  321. package/dist/contextValidator-OOPCLPZW.js +0 -9
  322. package/dist/contextValidator-OOPCLPZW.js.map +0 -1
  323. package/dist/eslint-rules/pace-core-compliance.cjs +0 -510
  324. package/dist/hooks.js.map +0 -1
  325. package/dist/index.js.map +0 -1
  326. package/dist/providers.js.map +0 -1
  327. package/dist/rbac/eslint-rules.js.map +0 -1
  328. package/dist/rbac/index.js.map +0 -1
  329. package/dist/styles/index.js.map +0 -1
  330. package/dist/theming/runtime.js.map +0 -1
  331. package/dist/types.js.map +0 -1
  332. package/dist/utils.js.map +0 -1
  333. package/docs/standards/01-architecture-standard.md +0 -44
  334. package/docs/standards/02-api-and-rpc-standard.md +0 -39
  335. package/docs/standards/03-component-standard.md +0 -32
  336. package/docs/standards/05-security-standard.md +0 -44
  337. package/docs/standards/06-testing-and-docs-standard.md +0 -29
  338. package/docs/standards/pace-core-compliance.md +0 -432
  339. package/scripts/audit/core/checks/accessibility.cjs +0 -197
  340. package/scripts/audit/core/checks/api-usage.cjs +0 -191
  341. package/scripts/audit/core/checks/bundle.cjs +0 -142
  342. package/scripts/audit/core/checks/compliance.cjs +0 -2706
  343. package/scripts/audit/core/checks/config.cjs +0 -54
  344. package/scripts/audit/core/checks/coverage.cjs +0 -84
  345. package/scripts/audit/core/checks/dependencies.cjs +0 -994
  346. package/scripts/audit/core/checks/documentation.cjs +0 -268
  347. package/scripts/audit/core/checks/environment.cjs +0 -116
  348. package/scripts/audit/core/checks/error-handling.cjs +0 -340
  349. package/scripts/audit/core/checks/forms.cjs +0 -172
  350. package/scripts/audit/core/checks/heuristics.cjs +0 -68
  351. package/scripts/audit/core/checks/hooks.cjs +0 -334
  352. package/scripts/audit/core/checks/imports.cjs +0 -244
  353. package/scripts/audit/core/checks/performance.cjs +0 -325
  354. package/scripts/audit/core/checks/routes.cjs +0 -117
  355. package/scripts/audit/core/checks/state.cjs +0 -130
  356. package/scripts/audit/core/checks/structure.cjs +0 -65
  357. package/scripts/audit/core/checks/style.cjs +0 -584
  358. package/scripts/audit/core/checks/testing.cjs +0 -122
  359. package/scripts/audit/core/checks/typescript.cjs +0 -61
  360. package/scripts/audit/core/scanner.cjs +0 -199
  361. package/scripts/audit/core/utils.cjs +0 -137
  362. package/scripts/audit/reporters/console.cjs +0 -151
  363. package/scripts/audit/reporters/json.cjs +0 -54
  364. package/scripts/audit/reporters/markdown.cjs +0 -124
  365. package/scripts/audit-consuming-app.cjs +0 -86
  366. package/src/eslint-rules/pace-core-compliance.cjs +0 -510
  367. package/src/eslint-rules/pace-core-compliance.js +0 -638
  368. package/src/rbac/components/EnhancedNavigationMenu.test.tsx +0 -555
  369. package/src/rbac/components/EnhancedNavigationMenu.tsx +0 -293
  370. package/src/rbac/components/NavigationProvider.test.tsx +0 -481
  371. package/src/rbac/components/NavigationProvider.tsx +0 -345
  372. package/src/rbac/components/PagePermissionProvider.test.tsx +0 -476
  373. package/src/rbac/components/PagePermissionProvider.tsx +0 -279
  374. package/src/rbac/components/PermissionEnforcer.tsx +0 -312
  375. package/src/rbac/components/RoleBasedRouter.tsx +0 -440
  376. package/src/rbac/components/SecureDataProvider.test.tsx +0 -543
  377. package/src/rbac/components/SecureDataProvider.tsx +0 -339
  378. package/src/rbac/components/__tests__/EnhancedNavigationMenu.test.tsx +0 -620
  379. package/src/rbac/components/__tests__/NavigationProvider.test.tsx +0 -726
  380. package/src/rbac/components/__tests__/PagePermissionProvider.test.tsx +0 -661
  381. package/src/rbac/components/__tests__/PermissionEnforcer.test.tsx +0 -881
  382. package/src/rbac/components/__tests__/RoleBasedRouter.test.tsx +0 -783
  383. package/src/rbac/components/__tests__/SecureDataProvider.fixed.test.tsx +0 -645
  384. package/src/rbac/components/__tests__/SecureDataProvider.test.tsx +0 -659
  385. package/src/rbac/hooks/permissions/useCachedPermissions.ts +0 -79
  386. package/src/rbac/hooks/permissions/useHasAllPermissions.ts +0 -90
  387. package/src/rbac/hooks/permissions/useHasAnyPermission.ts +0 -90
@@ -1,29 +0,0 @@
1
- # Testing & Documentation Standard
2
-
3
- ## Testing Strategy
4
- - Unit tests for utils & hooks
5
- - Integration tests for components
6
- - Few meaningful E2E tests (in consuming apps)
7
- - Coverage: ≥90% utils, ≥70% components
8
-
9
- ## Test Structure
10
- - Colocated tests (*.test.ts/tsx)
11
- - Use RTL + userEvent
12
- - Avoid unnecessary mocks
13
-
14
- ## Documentation Requirements
15
- - Component READMEs
16
- - API docs
17
- - Standards directory
18
-
19
- ## Required Sections
20
- - Overview
21
- - API/Props
22
- - Examples
23
- - A11y notes
24
- - Edge cases
25
-
26
- ## Cursor Checklist
27
- - Update docs after API changes
28
- - Ensure tests cover critical paths
29
- - Use RTL patterns only
@@ -1,432 +0,0 @@
1
- # pace-core Compliance Enforcement
2
-
3
- This guide explains how to enforce pace-core usage patterns in consuming apps to ensure consistent design, reduce duplication, and maintain high code quality.
4
-
5
- ## Overview
6
-
7
- pace-core provides a comprehensive enforcement system that includes:
8
-
9
- 1. **ESLint Rules** - Real-time linting during development
10
- 2. **Static Analysis Script** - Comprehensive codebase scanning
11
- 3. **ESLint Config Preset** - Easy setup for consuming apps
12
-
13
- ## Quick Start
14
-
15
- ### Option 1: ESLint Config Preset (Recommended)
16
-
17
- The easiest way to enable compliance checking is to use the shareable ESLint config. The config is CommonJS but works with both ES module and CommonJS ESLint configs:
18
-
19
- **For ES Module ESLint Config (eslint.config.js):**
20
- ```javascript
21
- // eslint.config.js (ES modules)
22
- import paceCoreConfig from '@jmruthers/pace-core/eslint-config';
23
-
24
- export default [
25
- ...paceCoreConfig,
26
- // your other config
27
- ];
28
- ```
29
-
30
- **For CommonJS ESLint Config (.eslintrc.js or eslint.config.cjs):**
31
- ```javascript
32
- // eslint.config.cjs (CommonJS)
33
- const paceCoreConfig = require('@jmruthers/pace-core/eslint-config');
34
-
35
- module.exports = [
36
- ...paceCoreConfig,
37
- // your other config
38
- ];
39
- ```
40
-
41
- ### Option 2: Manual ESLint Rules Setup
42
-
43
- If you prefer more control, you can import the rules directly. Note: The rules are CommonJS, so use `createRequire` in ES modules:
44
-
45
- **For ES Module ESLint Config:**
46
- ```javascript
47
- // eslint.config.js
48
- import { createRequire } from 'module';
49
- const require = createRequire(import.meta.url);
50
- const paceCoreRules = require('@jmruthers/pace-core/eslint-rules').rules;
51
-
52
- export default [
53
- {
54
- plugins: {
55
- 'pace-core-compliance': {
56
- rules: paceCoreRules
57
- }
58
- },
59
- rules: {
60
- 'pace-core-compliance/no-restricted-imports': 'error',
61
- 'pace-core-compliance/prefer-pace-core-components': 'warn',
62
- 'pace-core-compliance/prefer-pace-core-hooks': 'warn',
63
- 'pace-core-compliance/prefer-pace-core-utils': 'warn',
64
- 'pace-core-compliance/no-local-component-duplication': 'error'
65
- }
66
- }
67
- ];
68
- ```
69
-
70
- **For CommonJS ESLint Config:**
71
- ```javascript
72
- // eslint.config.cjs
73
- const paceCoreRules = require('@jmruthers/pace-core/eslint-rules').rules;
74
-
75
- module.exports = [
76
- {
77
- plugins: {
78
- 'pace-core-compliance': {
79
- rules: paceCoreRules
80
- }
81
- },
82
- rules: {
83
- 'pace-core-compliance/no-restricted-imports': 'error',
84
- 'pace-core-compliance/prefer-pace-core-components': 'warn',
85
- 'pace-core-compliance/prefer-pace-core-hooks': 'warn',
86
- 'pace-core-compliance/prefer-pace-core-utils': 'warn',
87
- 'pace-core-compliance/no-local-component-duplication': 'error'
88
- }
89
- }
90
- ];
91
- ```
92
-
93
- ## ESLint Rules
94
-
95
- ### no-restricted-imports
96
-
97
- **Severity**: Error
98
-
99
- Blocks direct imports of libraries that pace-core wraps and standardizes.
100
-
101
- **Restricted Libraries**:
102
- - `@radix-ui/*` - All Radix UI packages (use pace-core components instead)
103
- - `lucide-react` - Icons (use pace-core components that include icons)
104
- - `react-day-picker` - Use `Calendar` from pace-core
105
- - `@tanstack/react-table` - Use `DataTable` from pace-core
106
- - `react-hook-form` - Use `Form` and `useZodForm` from pace-core
107
- - `zod` - Use validation utilities from pace-core
108
-
109
- **Example Violation**:
110
- ```typescript
111
- // ❌ Bad
112
- import { Dialog } from '@radix-ui/react-dialog';
113
- import { Button } from 'lucide-react';
114
-
115
- // ✅ Good
116
- import { Dialog } from '@jmruthers/pace-core';
117
- import { Button } from '@jmruthers/pace-core';
118
- ```
119
-
120
- ### prefer-pace-core-components
121
-
122
- **Severity**: Warning
123
-
124
- Suggests using pace-core components instead of native HTML elements.
125
-
126
- **Detected Patterns**:
127
- - `<button>` → Use `Button` from pace-core
128
- - `<input>` → Use `Input` from pace-core
129
- - `<textarea>` → Use `Textarea` from pace-core
130
- - `<label>` → Use `Label` from pace-core
131
-
132
- **Example**:
133
- ```tsx
134
- // ⚠️ Warning
135
- <button onClick={handleClick}>Click me</button>
136
-
137
- // ✅ Recommended
138
- import { Button } from '@jmruthers/pace-core';
139
- <Button onClick={handleClick}>Click me</Button>
140
- ```
141
-
142
- ### prefer-pace-core-hooks
143
-
144
- **Severity**: Warning
145
-
146
- Detects custom hooks that duplicate pace-core functionality.
147
-
148
- **Common Patterns Detected**:
149
- - `useToast`, `useNotification` → Use `useToast` from pace-core
150
- - `useDebounce`, `useDebounced` → Use `useDebounce` from pace-core
151
- - `useAuth`, `useAuthentication` → Use `useUnifiedAuth` from pace-core
152
- - `useForm`, `useZodForm` → Use `useZodForm` from pace-core
153
-
154
- **Example**:
155
- ```typescript
156
- // ⚠️ Warning
157
- function useToast() {
158
- // custom implementation
159
- }
160
-
161
- // ✅ Recommended
162
- import { useToast } from '@jmruthers/pace-core';
163
- ```
164
-
165
- ### prefer-pace-core-utils
166
-
167
- **Severity**: Warning
168
-
169
- Detects utility functions that duplicate pace-core functionality.
170
-
171
- **Common Patterns Detected**:
172
- - `formatDate`, `dateFormat` → Use `formatDate` from pace-core
173
- - `formatCurrency`, `formatMoney` → Use `formatCurrency` from pace-core
174
- - `cn`, `classNames`, `clsx` → Use `cn` from pace-core
175
- - `validate`, `validateInput` → Use `validateUserInput` from pace-core
176
-
177
- **Example**:
178
- ```typescript
179
- // ⚠️ Warning
180
- function formatDate(date: Date): string {
181
- // custom implementation
182
- }
183
-
184
- // ✅ Recommended
185
- import { formatDate } from '@jmruthers/pace-core';
186
- ```
187
-
188
- ### no-local-component-duplication
189
-
190
- **Severity**: Error
191
-
192
- Prevents creating local components with names matching pace-core components.
193
-
194
- **Example Violation**:
195
- ```
196
- // ❌ Error: components/Button.tsx
197
- export function Button() { ... }
198
-
199
- // pace-core already provides Button component
200
- ```
201
-
202
- **Fix**: Remove the local component and import from pace-core:
203
- ```typescript
204
- import { Button } from '@jmruthers/pace-core';
205
- ```
206
-
207
- ## Static Analysis Script
208
-
209
- The static analysis script provides a comprehensive scan of your codebase and generates a detailed compliance report.
210
-
211
- ### Running the Script
212
-
213
- ```bash
214
- # From your consuming app root
215
- node node_modules/@jmruthers/pace-core/scripts/check-pace-core-compliance.cjs
216
- ```
217
-
218
- Or add it to your `package.json`:
219
-
220
- ```json
221
- {
222
- "scripts": {
223
- "check:pace-core": "node node_modules/@jmruthers/pace-core/scripts/check-pace-core-compliance.cjs"
224
- }
225
- }
226
- ```
227
-
228
- ### What It Checks
229
-
230
- 1. **Restricted Imports** - Scans for direct imports of wrapped libraries
231
- 2. **Duplicate Components** - Finds local components matching pace-core names
232
- 3. **Duplicate Hooks** - Finds local hooks matching pace-core hooks
233
- 4. **Duplicate Utils** - Finds local utils matching pace-core utils
234
- 5. **Suggestions** - Recommends pace-core alternatives for native HTML elements
235
-
236
- ### Report Output
237
-
238
- The script generates a color-coded terminal report showing:
239
-
240
- - ❌ **Errors** - Critical violations that must be fixed
241
- - ⚠️ **Warnings** - Issues that should be addressed
242
- - 💡 **Suggestions** - Recommendations for improvement
243
- - ✅ **Summary** - Overall compliance status
244
-
245
- Example output:
246
- ```
247
- ═══════════════════════════════════════════════════════════
248
- pace-core Compliance Report
249
- ═══════════════════════════════════════════════════════════
250
-
251
- ❌ Restricted Imports Found: 3
252
-
253
- • src/components/CustomDialog.tsx:5
254
- Import: @radix-ui/react-dialog
255
- Reason: Use Dialog component from pace-core instead
256
-
257
- Summary:
258
- Total Issues: 3
259
- - Restricted Imports: 3
260
- - Duplicate Components/Hooks/Utils: 0
261
- - Suggestions: 0
262
- ```
263
-
264
- ## Best Practices
265
-
266
- ### 1. Always Import from pace-core
267
-
268
- ```typescript
269
- // ✅ Good
270
- import { Button, Card, Dialog } from '@jmruthers/pace-core';
271
- import { useToast, useDebounce } from '@jmruthers/pace-core';
272
- import { formatDate, formatCurrency } from '@jmruthers/pace-core';
273
- ```
274
-
275
- ### 2. Use pace-core Components for UI
276
-
277
- Avoid native HTML elements when pace-core provides a component:
278
-
279
- ```tsx
280
- // ❌ Avoid
281
- <button className="btn">Click</button>
282
-
283
- // ✅ Use pace-core
284
- <Button>Click</Button>
285
- ```
286
-
287
- ### 3. Leverage pace-core Hooks
288
-
289
- Don't recreate hooks that pace-core already provides:
290
-
291
- ```typescript
292
- // ❌ Avoid
293
- const [debouncedValue, setDebouncedValue] = useState(value);
294
- useEffect(() => {
295
- const timer = setTimeout(() => setDebouncedValue(value), 500);
296
- return () => clearTimeout(timer);
297
- }, [value]);
298
-
299
- // ✅ Use pace-core
300
- import { useDebounce } from '@jmruthers/pace-core';
301
- const debouncedValue = useDebounce(value, 500);
302
- ```
303
-
304
- ### 4. Use pace-core Utilities
305
-
306
- Leverage formatting, validation, and other utilities from pace-core:
307
-
308
- ```typescript
309
- // ❌ Avoid
310
- const formatted = new Intl.DateTimeFormat('en-US').format(date);
311
-
312
- // ✅ Use pace-core
313
- import { formatDate } from '@jmruthers/pace-core';
314
- const formatted = formatDate(date);
315
- ```
316
-
317
- ### 5. Check Before Creating New Components
318
-
319
- Before creating a new component, check if pace-core already provides it:
320
-
321
- 1. Review the [pace-core documentation](https://github.com/your-org/pace-core)
322
- 2. Check `core-usage-manifest.json` for available components
323
- 3. Search pace-core exports
324
-
325
- ## Troubleshooting
326
-
327
- ### ESLint Rules Not Working
328
-
329
- 1. **Verify plugin is loaded**: Check that the config is imported correctly:
330
- ```javascript
331
- // In your eslint.config.js, add temporarily:
332
- import paceCoreConfig from '@jmruthers/pace-core/eslint-config';
333
- console.log('Config:', paceCoreConfig);
334
- console.log('Has plugins:', paceCoreConfig[0]?.plugins);
335
- ```
336
-
337
- 2. **Check rule names**: Rules must be prefixed with `pace-core-compliance/`
338
-
339
- 3. **Verify manifest exists**: Rules load from `core-usage-manifest.json` in the pace-core package
340
-
341
- 4. **CommonJS/ES Module issues**: If you're using ES modules and rules aren't loading:
342
- - Ensure you're using the config preset (Option 1) which handles this automatically
343
- - Or use `createRequire` when importing rules directly (Option 2)
344
-
345
- 5. **Verify rules are available**: Check that the rules file exists:
346
- ```bash
347
- ls node_modules/@jmruthers/pace-core/dist/eslint-rules/pace-core-compliance.cjs
348
- ```
349
-
350
- ### Static Analysis Script Errors
351
-
352
- 1. **Manifest not found**: Ensure `core-usage-manifest.json` exists in pace-core package
353
- 2. **No files scanned**: Check that you're running from the project root
354
- 3. **Permission errors**: Ensure script has read access to source files
355
-
356
- ### False Positives
357
-
358
- If you encounter false positives:
359
-
360
- 1. **Component name conflicts**: If you have a legitimate reason to create a local component with a pace-core name, consider:
361
- - Renaming your component
362
- - Using a namespace/prefix
363
- - Documenting why pace-core doesn't meet your needs
364
-
365
- 2. **Hook/Util patterns**: The pattern matching may flag similar names. Review the suggestion and decide if migration makes sense.
366
-
367
- ## Integration with CI/CD
368
-
369
- While CI/CD integration is not included in the initial release, you can easily add it:
370
-
371
- ```yaml
372
- # .github/workflows/pace-core-compliance.yml
373
- name: pace-core Compliance
374
-
375
- on: [push, pull_request]
376
-
377
- jobs:
378
- compliance:
379
- runs-on: ubuntu-latest
380
- steps:
381
- - uses: actions/checkout@v3
382
- - uses: actions/setup-node@v3
383
- - run: npm ci
384
- - run: npm run check:pace-core
385
- - run: npm run lint
386
- ```
387
-
388
- ## Verification
389
-
390
- After setting up the ESLint config, verify it's working:
391
-
392
- 1. **Check ESLint can load the config**:
393
- ```bash
394
- npx eslint --print-config src/App.tsx
395
- ```
396
- Look for `pace-core-compliance` in the plugins section.
397
-
398
- 2. **Test with a violation**: Create a test file that imports a restricted library:
399
- ```typescript
400
- // test-violation.ts
401
- import { Dialog } from '@radix-ui/react-dialog'; // Should trigger error
402
- ```
403
- Run ESLint and verify it reports the violation.
404
-
405
- 3. **Run static analysis**: Use the compliance script to get a full report:
406
- ```bash
407
- npm run check:pace-core
408
- ```
409
-
410
- ## Getting Help
411
-
412
- - **Documentation**: See [pace-core docs](../README.md)
413
- - **Issues**: Report false positives or rule issues
414
- - **Manifest**: Check `core-usage-manifest.json` for available exports
415
- - **ESLint Config**: The config file is at `@jmruthers/pace-core/eslint-config` (CommonJS)
416
- - **ESLint Rules**: The rules are at `@jmruthers/pace-core/eslint-rules` (CommonJS)
417
-
418
- ## File Locations
419
-
420
- When installed in a consuming app, the compliance tools are available at:
421
-
422
- - **ESLint Config**: `node_modules/@jmruthers/pace-core/eslint-config-pace-core.cjs`
423
- - **ESLint Rules**: `node_modules/@jmruthers/pace-core/dist/eslint-rules/pace-core-compliance.cjs`
424
- - **Static Analysis Script**: `node_modules/@jmruthers/pace-core/scripts/check-pace-core-compliance.cjs`
425
- - **Manifest**: `node_modules/@jmruthers/pace-core/core-usage-manifest.json`
426
-
427
- ## Related Documentation
428
-
429
- - [Component Standards](./03-component-standard.md)
430
- - [API & RPC Standards](./02-api-and-rpc-standard.md)
431
- - [Getting Started Guide](../getting-started/README.md)
432
-
@@ -1,197 +0,0 @@
1
- #!/usr/bin/env node
2
-
3
- /**
4
- * Accessibility Check Module
5
- * @package @jmruthers/pace-core
6
- * @module Audit/Checks/Accessibility
7
- *
8
- * Checks for:
9
- * - Missing aria-* attributes
10
- * - Missing keyboard navigation
11
- * - Missing focus management
12
- * - Missing alt text on images
13
- */
14
-
15
- const fs = require('fs');
16
- const { getRelativePath, getLineNumber } = require('../utils.cjs');
17
-
18
- const accessibilityCheck = {
19
- name: 'accessibility',
20
- description: 'Accessibility checks (aria attributes, keyboard navigation, alt text)',
21
- severity: 'warning',
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 root-level src directory - in pace-core repository, this is a demo/showcase app
45
- // Note: We DO check packages/core/ files because accessibility issues (missing alt attributes, missing form labels) are real issues that should be fixed
46
- const isRootSrc = normalizedPath.startsWith('src/') && !normalizedPath.includes('packages/');
47
- if (isRootSrc) {
48
- continue; // Skip demo app files
49
- }
50
-
51
- // Skip scripts directory - utility scripts don't need accessibility validation
52
- const isScript = normalizedPath.startsWith('scripts/') || normalizedPath.includes('/scripts/');
53
- if (isScript) {
54
- continue; // Skip script files
55
- }
56
-
57
- // Skip pace-core library components and examples - these are designed to accept accessibility props
58
- // Library components accept id, aria-label, etc. via props spread
59
- // Examples are demonstration code, not production code
60
- const isPaceCorePackage = normalizedPath.includes('packages/core/') || normalizedPath.startsWith('packages/core/');
61
- const isExample = normalizedPath.includes('/examples/');
62
- const isLibraryComponent = isPaceCorePackage && !isExample;
63
-
64
- // Check for images without alt text
65
- // Skip library components - they accept alt as a prop
66
- if (!isLibraryComponent) {
67
- const imgPattern = /<img[^>]*>/g;
68
- let imgMatch;
69
- while ((imgMatch = imgPattern.exec(content)) !== null) {
70
- const imgTag = imgMatch[0];
71
- // Check for alt attribute, including React props (alt=, alt =, alt={)
72
- const hasAlt = imgTag.includes('alt=') || imgTag.includes('alt =') || imgTag.includes('alt={');
73
- if (!hasAlt) {
74
- warnings.push({
75
- type: 'missing-alt-text',
76
- file: relativePath,
77
- line: getLineNumber(content, imgMatch.index),
78
- message: 'Image element missing alt attribute',
79
- recommendation: 'Add alt text to all images for accessibility: <img alt="description" ... />'
80
- });
81
- }
82
- }
83
- }
84
-
85
- // Check for buttons/clickable elements without aria-label or accessible text
86
- const buttonPattern = /<(button|a|div)\s+[^>]*(onClick|role=["']button["'])[^>]*>/g;
87
- let buttonMatch;
88
- while ((buttonMatch = buttonPattern.exec(content)) !== null) {
89
- const buttonTag = buttonMatch[0];
90
- const hasAriaLabel = buttonTag.includes('aria-label=') || buttonTag.includes('ariaLabel=');
91
- const hasAccessibleText = buttonTag.includes('>') && content.substring(buttonMatch.index).match(/<[^>]*>([^<]+)</);
92
-
93
- if (!hasAriaLabel && !hasAccessibleText) {
94
- warnings.push({
95
- type: 'missing-aria-label',
96
- file: relativePath,
97
- line: getLineNumber(content, buttonMatch.index),
98
- message: 'Interactive element missing accessible label',
99
- recommendation: 'Add aria-label or ensure element contains accessible text content'
100
- });
101
- }
102
- }
103
-
104
- // Check for form inputs without labels
105
- // Skip library components - they accept id, aria-label, etc. via props spread
106
- // Skip examples - they're demonstration code
107
- if (!isLibraryComponent && !isExample) {
108
- const inputPattern = /<input[^>]*>/g;
109
- let inputMatch;
110
- while ((inputMatch = inputPattern.exec(content)) !== null) {
111
- // Get the full input tag including multi-line attributes
112
- const inputStart = inputMatch.index;
113
- const afterInput = content.substring(inputStart, Math.min(content.length, inputStart + 500));
114
- const inputTagEnd = afterInput.indexOf('>');
115
- const fullInputTag = inputTagEnd !== -1 ? afterInput.substring(0, inputTagEnd + 1) : inputMatch[0];
116
-
117
- // Check for id (including React props)
118
- const hasId = /id=["']([^"']+)["']|id=\{/.test(fullInputTag);
119
- // Check for aria-label (including React props)
120
- const hasAriaLabel = /aria-label=["']|ariaLabel=|aria-label=\{/.test(fullInputTag);
121
-
122
- if (hasId) {
123
- const idMatch = fullInputTag.match(/id=["']([^"']+)["']/);
124
- if (idMatch) {
125
- const id = idMatch[1];
126
- // Check if there's a corresponding label
127
- const beforeInput = content.substring(Math.max(0, inputMatch.index - 200), inputMatch.index);
128
- const hasLabel = new RegExp(`<label[^>]*for=["']${id}["']`, 'i').test(beforeInput);
129
-
130
- if (!hasLabel && !hasAriaLabel) {
131
- warnings.push({
132
- type: 'missing-input-label',
133
- file: relativePath,
134
- line: getLineNumber(content, inputMatch.index),
135
- message: 'Form input missing associated label',
136
- recommendation: 'Add a <label> element with for attribute matching input id, or use aria-label'
137
- });
138
- }
139
- }
140
- } else if (!hasAriaLabel) {
141
- warnings.push({
142
- type: 'missing-input-label',
143
- file: relativePath,
144
- line: getLineNumber(content, inputMatch.index),
145
- message: 'Form input missing id and label',
146
- recommendation: 'Add id to input and corresponding label, or use aria-label'
147
- });
148
- }
149
- }
150
- }
151
-
152
- // Check for missing focus management in modals/dialogs
153
- const dialogPattern = /<Dialog|<dialog/gi;
154
- if (dialogPattern.test(content)) {
155
- // Skip Dialog.tsx itself - it IS the Dialog component
156
- if (normalizedPath.includes('/Dialog/Dialog.tsx') || normalizedPath.includes('/Dialog/Dialog.jsx')) {
157
- continue; // Skip the Dialog component file itself
158
- }
159
-
160
- // Check if Dialog from pace-core is used (which handles focus automatically)
161
- // Check for both published package import and relative imports (within pace-core repo)
162
- const usesPaceCoreDialog = content.includes('from \'@jmruthers/pace-core\'') ||
163
- content.includes('from "@jmruthers/pace-core"') ||
164
- content.includes('from \'../Dialog') ||
165
- content.includes('from "../Dialog') ||
166
- content.includes('from \'../../Dialog') ||
167
- content.includes('from "../../Dialog') ||
168
- content.includes('from \'../../../Dialog') ||
169
- content.includes('from "../../../Dialog') ||
170
- content.includes('from \'./Dialog') ||
171
- content.includes('from "./Dialog');
172
-
173
- if (!usesPaceCoreDialog) {
174
- suggestions.push({
175
- type: 'dialog-focus-management',
176
- file: relativePath,
177
- message: 'Custom dialog implementation detected',
178
- recommendation: 'Use Dialog component from @jmruthers/pace-core which handles focus management automatically'
179
- });
180
- }
181
- }
182
-
183
- // Check for color contrast issues (heuristic - check for color props without sufficient contrast)
184
- const colorPattern = /(?:color|bg-|text-)=["']([^"']+)["']/g;
185
- // This is a simplified check - full implementation would need color contrast calculation
186
- // For now, just suggest using pace-core components which handle contrast
187
-
188
- } catch (error) {
189
- // Skip files with errors
190
- }
191
- }
192
-
193
- return { issues, warnings, suggestions };
194
- }
195
- };
196
-
197
- module.exports = accessibilityCheck;