@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.
- package/CHANGELOG.md +104 -0
- package/README.md +5 -403
- package/audit-tool/00-dependencies.cjs +394 -0
- package/audit-tool/audits/01-pace-core-compliance.cjs +556 -0
- package/audit-tool/audits/02-project-structure.cjs +255 -0
- package/audit-tool/audits/03-architecture.cjs +196 -0
- package/audit-tool/audits/04-code-quality.cjs +149 -0
- package/audit-tool/audits/05-styling.cjs +224 -0
- package/audit-tool/audits/06-security-rbac.cjs +544 -0
- package/audit-tool/audits/07-api-tech-stack.cjs +301 -0
- package/audit-tool/audits/08-testing-documentation.cjs +202 -0
- package/audit-tool/audits/09-operations.cjs +208 -0
- package/audit-tool/index.cjs +291 -0
- package/audit-tool/utils/code-utils.cjs +218 -0
- package/audit-tool/utils/file-utils.cjs +230 -0
- package/audit-tool/utils/report-utils.cjs +241 -0
- package/core-usage-manifest.json +93 -0
- package/cursor-rules/00-standards-overview.mdc +156 -0
- package/cursor-rules/01-pace-core-compliance.mdc +586 -0
- package/cursor-rules/02-project-structure.mdc +42 -4
- package/cursor-rules/{03-solid-principles.mdc → 03-architecture.mdc} +126 -10
- package/cursor-rules/04-code-quality.mdc +419 -0
- package/cursor-rules/{08-markup-quality.mdc → 05-styling.mdc} +104 -34
- package/cursor-rules/06-security-rbac.mdc +518 -0
- package/cursor-rules/07-api-tech-stack.mdc +377 -0
- package/cursor-rules/08-testing-documentation.mdc +324 -0
- package/cursor-rules/09-operations.mdc +365 -0
- package/dist/{AuthService-Cb34EQs3.d.ts → AuthService-DmfO5rGS.d.ts} +10 -0
- package/dist/DataTable-7PMH7XN7.js +15 -0
- package/dist/{DataTable-BMRU8a1j.d.ts → DataTable-DRUIgtUH.d.ts} +1 -1
- package/dist/{PublicPageProvider-QTFVrL-Z.d.ts → PublicPageProvider-DlsCaR5v.d.ts} +33 -72
- package/dist/UnifiedAuthProvider-ZT6TIGM7.js +7 -0
- package/dist/api-Y4MQWOFW.js +4 -0
- package/dist/audit-MYQXYZFU.js +3 -0
- package/dist/{chunk-DGUM43GV.js → chunk-3RG5ZIWI.js} +1 -4
- package/dist/{chunk-QXHPKYJV.js → chunk-4SXLQIZO.js} +1 -26
- package/dist/{chunk-UPPMRMYG.js → chunk-5X4QLXRG.js} +73 -151
- package/dist/chunk-6F3IILHI.js +62 -0
- package/dist/{chunk-E66EQZE6.js → chunk-6GLLNA6U.js} +3 -9
- package/dist/{chunk-ZSAAAMVR.js → chunk-6QYDGKQY.js} +1 -4
- package/dist/{chunk-FMUCXFII.js → chunk-7ILTDCL2.js} +9 -5
- package/dist/{chunk-M43Y4SSO.js → chunk-A3W6LW53.js} +15 -13
- package/dist/{chunk-63FOKYGO.js → chunk-AHU7G2R5.js} +2 -11
- package/dist/{chunk-HU2C6SSC.js → chunk-BM4CQ5P3.js} +606 -559
- package/dist/chunk-C7NSAPTL.js +1 -0
- package/dist/{chunk-J36DSWQK.js → chunk-FEJLJNWA.js} +7 -41
- package/dist/{chunk-IHB5DR3H.js → chunk-FTCRZOG2.js} +188 -387
- package/dist/{chunk-G37KK66H.js → chunk-FYHN4DD5.js} +60 -19
- package/dist/chunk-GHYHJTYV.js +994 -0
- package/dist/{chunk-VBXEHIUJ.js → chunk-HF6O3O37.js} +6 -88
- package/dist/{chunk-FFQEQTNW.js → chunk-IUBRCBSY.js} +134 -45
- package/dist/{chunk-6COVEUS7.js → chunk-JGWDVX64.js} +983 -1034
- package/dist/{chunk-RGAWHO7N.js → chunk-L4XMVJKY.js} +77 -222
- package/dist/chunk-MBADTM7L.js +64 -0
- package/dist/{chunk-M7MPQISP.js → chunk-OJ4SKRSV.js} +3 -16
- package/dist/{chunk-IVOFDYWT.js → chunk-Q7Q7V5NV.js} +2109 -1604
- package/dist/{chunk-JGRYX5UX.js → chunk-S7DKJPLT.js} +29 -58
- package/dist/{chunk-PWLANIRT.js → chunk-TTRFSOKR.js} +1 -7
- package/dist/{chunk-5DRSZLL2.js → chunk-UH3NTO3F.js} +1 -6
- package/dist/{chunk-NTM7ZSB6.js → chunk-VBCS3DUA.js} +261 -168
- package/dist/{chunk-EFN2EIMK.js → chunk-ZFYPMX46.js} +271 -87
- package/dist/{chunk-L4OXEN46.js → chunk-ZKAWKYT4.js} +10 -24
- package/dist/components.d.ts +7 -5
- package/dist/components.js +46 -257
- package/dist/{database.generated-CzIvgcPu.d.ts → database.generated-CcnC_DRc.d.ts} +4795 -3691
- package/dist/eslint-rules/index.cjs +35 -0
- package/{src/eslint-rules/pace-core-compliance.cjs → dist/eslint-rules/rules/01-pace-core-compliance.cjs} +234 -235
- package/dist/eslint-rules/rules/04-code-quality.cjs +290 -0
- package/dist/eslint-rules/rules/05-styling.cjs +61 -0
- package/dist/eslint-rules/rules/06-security-rbac.cjs +806 -0
- package/dist/eslint-rules/rules/07-api-tech-stack.cjs +263 -0
- package/dist/eslint-rules/rules/08-testing.cjs +94 -0
- package/dist/eslint-rules/utils/helpers.cjs +42 -0
- package/dist/eslint-rules/utils/manifest-loader.cjs +75 -0
- package/dist/hooks.d.ts +6 -6
- package/dist/hooks.js +62 -172
- package/dist/icons/index.d.ts +1 -0
- package/dist/icons/index.js +1 -0
- package/dist/index.d.ts +12 -11
- package/dist/index.js +67 -660
- package/dist/providers.d.ts +2 -2
- package/dist/providers.js +8 -35
- package/dist/rbac/eslint-rules.d.ts +46 -44
- package/dist/rbac/eslint-rules.js +7 -4
- package/dist/rbac/index.d.ts +109 -586
- package/dist/rbac/index.js +14 -207
- package/dist/styles/index.js +2 -12
- package/dist/theming/runtime.d.ts +14 -1
- package/dist/theming/runtime.js +3 -19
- package/dist/{timezone-CHhWg6b4.d.ts → timezone-BZe_eUxx.d.ts} +175 -1
- package/dist/{types-CkbwOr4Y.d.ts → types-DXstZpNI.d.ts} +4 -17
- package/dist/types-t9H8qKRw.d.ts +55 -0
- package/dist/types.d.ts +1 -1
- package/dist/types.js +7 -94
- package/dist/{usePublicRouteParams-ClnV4tnv.d.ts → usePublicRouteParams-MamNgwqe.d.ts} +20 -20
- package/dist/utils.d.ts +24 -117
- package/dist/utils.js +54 -392
- package/docs/README.md +17 -7
- package/docs/api/README.md +4 -402
- package/docs/api/modules.md +301 -871
- package/docs/api-reference/components.md +21 -21
- package/docs/api-reference/deprecated.md +31 -6
- package/docs/api-reference/hooks.md +80 -80
- package/docs/api-reference/rpc-functions.md +78 -3
- package/docs/api-reference/types.md +1 -1
- package/docs/api-reference/utilities.md +1 -1
- package/docs/architecture/README.md +1 -1
- package/docs/core-concepts/events.md +3 -3
- package/docs/core-concepts/organisations.md +6 -6
- package/docs/core-concepts/permissions.md +6 -6
- package/docs/documentation-index.md +12 -18
- package/docs/getting-started/cursor-rules.md +3 -23
- package/docs/getting-started/dependencies.md +650 -0
- package/docs/getting-started/documentation-index.md +1 -1
- package/docs/getting-started/examples/README.md +4 -4
- package/docs/getting-started/examples/full-featured-app.md +1 -1
- package/docs/getting-started/faq.md +2 -2
- package/docs/getting-started/installation-guide.md +20 -7
- package/docs/getting-started/quick-reference.md +4 -4
- package/docs/getting-started/quick-start.md +23 -12
- package/docs/implementation-guides/authentication.md +15 -15
- package/docs/implementation-guides/component-styling.md +1 -1
- package/docs/implementation-guides/data-tables.md +126 -33
- package/docs/implementation-guides/datatable-rbac-usage.md +1 -1
- package/docs/implementation-guides/dynamic-colors.md +3 -3
- package/docs/implementation-guides/file-upload-storage.md +2 -2
- package/docs/implementation-guides/hierarchical-datatable.md +40 -60
- package/docs/implementation-guides/inactivity-tracking.md +3 -3
- package/docs/implementation-guides/large-datasets.md +3 -2
- package/docs/implementation-guides/organisation-security.md +2 -2
- package/docs/implementation-guides/performance.md +2 -2
- package/docs/implementation-guides/permission-enforcement.md +5 -1
- package/docs/migration/V0.3.44_organisation-context-timing-fix.md +1 -1
- package/docs/migration/V0.4.0_rbac-migration.md +6 -6
- package/docs/rbac/MIGRATION_GUIDE.md +819 -0
- package/docs/rbac/RBAC_CONTRACT.md +724 -0
- package/docs/rbac/README.md +17 -8
- package/docs/rbac/advanced-patterns.md +6 -6
- package/docs/rbac/api-reference.md +20 -20
- package/docs/rbac/edge-functions-guide.md +376 -0
- package/docs/rbac/event-based-apps.md +3 -3
- package/docs/rbac/examples.md +41 -41
- package/docs/rbac/getting-started.md +37 -37
- package/docs/rbac/performance.md +1 -1
- package/docs/rbac/quick-start.md +52 -52
- package/docs/rbac/secure-client-protection.md +1 -35
- package/docs/rbac/troubleshooting.md +1 -1
- package/docs/security/README.md +5 -5
- package/docs/standards/0-standards-overview.md +220 -0
- package/docs/standards/1-pace-core-compliance-standards.md +986 -0
- package/docs/standards/2-project-structure-standards.md +949 -0
- package/docs/standards/3-architecture-standards.md +606 -0
- package/docs/standards/4-code-quality-standards.md +728 -0
- package/docs/standards/5-styling-standards.md +348 -0
- package/docs/standards/{07-rbac-and-rls-standard.md → 6-security-rbac-standards.md} +269 -66
- package/docs/standards/7-api-tech-stack-standards.md +662 -0
- package/docs/standards/8-testing-documentation-standards.md +401 -0
- package/docs/standards/9-operations-standards.md +1102 -0
- package/docs/standards/README.md +185 -57
- package/docs/troubleshooting/README.md +4 -4
- package/docs/troubleshooting/common-issues.md +2 -2
- package/docs/troubleshooting/debugging.md +9 -9
- package/docs/troubleshooting/migration.md +4 -4
- package/docs/troubleshooting/organisation-context-setup.md +42 -19
- package/eslint-config-pace-core.cjs +33 -6
- package/package.json +35 -23
- package/scripts/install-cursor-rules.cjs +25 -6
- package/scripts/install-eslint-config.cjs +284 -0
- package/src/__tests__/fixtures/supabase.ts +1 -1
- package/src/__tests__/helpers/__tests__/component-test-utils.test.tsx +3 -3
- package/src/__tests__/helpers/__tests__/optimized-test-setup.test.ts +1 -1
- package/src/__tests__/helpers/__tests__/supabaseMock.test.ts +1 -1
- package/src/__tests__/helpers/__tests__/test-providers.test.tsx +2 -2
- package/src/__tests__/helpers/__tests__/test-utils.test.tsx +13 -13
- package/src/__tests__/helpers/component-test-utils.tsx +1 -1
- package/src/__tests__/helpers/supabaseMock.ts +2 -2
- package/src/__tests__/integration/UserProfile.test.tsx +14 -14
- package/src/__tests__/public-recipe-view.test.ts +38 -9
- package/src/__tests__/rbac/PagePermissionGuard.test.tsx +6 -6
- package/src/__tests__/templates/accessibility.test.template.tsx +9 -9
- package/src/__tests__/templates/component.test.template.tsx +18 -15
- package/src/components/Button/Button.tsx +5 -1
- package/src/components/Calendar/Calendar.tsx +201 -47
- package/src/components/ContextSelector/ContextSelector.tsx +106 -119
- package/src/components/DataTable/AUDIT_REPORT.md +293 -0
- package/src/components/DataTable/__tests__/DataTableCore.test.tsx +10 -2
- package/src/components/DataTable/__tests__/a11y.basic.test.tsx +10 -4
- package/src/components/DataTable/__tests__/test-utils/sharedTestUtils.tsx +9 -9
- package/src/components/DataTable/components/ColumnFilter.tsx +63 -74
- package/src/components/DataTable/components/ColumnVisibilityDropdown.tsx +43 -41
- package/src/components/DataTable/components/DataTableCore.tsx +186 -13
- package/src/components/DataTable/components/DataTableErrorBoundary.tsx +9 -11
- package/src/components/DataTable/components/DataTableLayout.tsx +35 -21
- package/src/components/DataTable/components/EditFields.tsx +23 -3
- package/src/components/DataTable/components/EditableRow.tsx +12 -9
- package/src/components/DataTable/components/EmptyState.tsx +10 -9
- package/src/components/DataTable/components/FilterRow.tsx +2 -4
- package/src/components/DataTable/components/ImportModal.tsx +124 -126
- package/src/components/DataTable/components/LoadingState.tsx +5 -6
- package/src/components/DataTable/components/RowComponent.tsx +12 -0
- package/src/components/DataTable/components/SortIndicator.tsx +50 -0
- package/src/components/DataTable/components/__tests__/COVERAGE_NOTE.md +4 -4
- package/src/components/DataTable/components/__tests__/ColumnFilter.test.tsx +23 -82
- package/src/components/DataTable/components/__tests__/DataTableErrorBoundary.test.tsx +37 -9
- package/src/components/DataTable/components/__tests__/EmptyState.test.tsx +7 -4
- package/src/components/DataTable/components/__tests__/FilterRow.test.tsx +12 -4
- package/src/components/DataTable/components/__tests__/LoadingState.test.tsx +41 -27
- package/src/components/DataTable/components/hooks/usePermissionTracking.ts +0 -4
- package/src/components/DataTable/components/index.ts +2 -1
- package/src/components/DataTable/hooks/__tests__/useDataTableState.test.ts +51 -47
- package/src/components/DataTable/hooks/useDataTablePermissions.ts +24 -21
- package/src/components/DataTable/hooks/useDataTableState.ts +125 -9
- package/src/components/DataTable/hooks/useTableColumns.ts +40 -2
- package/src/components/DataTable/hooks/useTableHandlers.ts +11 -0
- package/src/components/DataTable/types.ts +5 -18
- package/src/components/DataTable/utils/a11yUtils.ts +17 -0
- package/src/components/DatePickerWithTimezone/DatePickerWithTimezone.test.tsx +2 -1
- package/src/components/DatePickerWithTimezone/DatePickerWithTimezone.tsx +11 -15
- package/src/components/DateTimeField/DateTimeField.tsx +10 -9
- package/src/components/Dialog/Dialog.test.tsx +128 -104
- package/src/components/Dialog/Dialog.tsx +742 -24
- package/src/components/ErrorBoundary/ErrorBoundary.tsx +77 -79
- package/src/components/FileDisplay/FileDisplay.test.tsx +4 -2
- package/src/components/FileDisplay/FileDisplay.tsx +23 -17
- package/src/components/FileUpload/FileUpload.test.tsx +52 -14
- package/src/components/FileUpload/FileUpload.tsx +112 -130
- package/src/components/Form/Form.test.tsx +6 -8
- package/src/components/Form/Form.tsx +365 -4
- package/src/components/NavigationMenu/NavigationMenu.test.tsx +14 -13
- package/src/components/NavigationMenu/useNavigationFiltering.ts +11 -21
- package/src/components/PaceAppLayout/PaceAppLayout.test.tsx +6 -4
- package/src/components/PaceAppLayout/PaceAppLayout.tsx +11 -15
- package/src/components/PaceLoginPage/PaceLoginPage.test.tsx +108 -61
- package/src/components/PaceLoginPage/PaceLoginPage.tsx +27 -3
- package/src/components/Progress/Progress.tsx +2 -4
- package/src/components/ProtectedRoute/ProtectedRoute.tsx +8 -8
- package/src/components/Select/Select.tsx +109 -98
- package/src/components/Select/types.ts +4 -1
- package/src/components/UserMenu/UserMenu.tsx +9 -6
- package/src/hooks/__tests__/ServiceHooks.test.tsx +16 -16
- package/src/hooks/__tests__/hooks.integration.test.tsx +55 -57
- package/src/hooks/__tests__/useAppConfig.unit.test.ts +129 -67
- package/src/hooks/__tests__/useFocusTrap.unit.test.tsx +97 -97
- package/src/hooks/__tests__/usePublicEvent.simple.test.ts +149 -67
- package/src/hooks/__tests__/usePublicEvent.test.ts +149 -79
- package/src/hooks/__tests__/usePublicEvent.unit.test.ts +158 -109
- package/src/hooks/__tests__/useSessionDraft.test.ts +163 -0
- package/src/hooks/__tests__/useSessionRestoration.unit.test.tsx +10 -5
- package/src/hooks/public/usePublicEvent.ts +67 -195
- package/src/hooks/public/usePublicEventLogo.test.ts +70 -17
- package/src/hooks/public/usePublicEventLogo.ts +24 -14
- package/src/hooks/public/usePublicFileDisplay.ts +2 -2
- package/src/hooks/public/usePublicRouteParams.ts +5 -5
- package/src/hooks/useAppConfig.ts +28 -26
- package/src/hooks/useEventTheme.test.ts +217 -239
- package/src/hooks/useEventTheme.ts +16 -28
- package/src/hooks/useFileDisplay.ts +2 -2
- package/src/hooks/useOrganisationPermissions.ts +5 -7
- package/src/hooks/useQueryCache.ts +0 -1
- package/src/hooks/useSessionDraft.ts +380 -0
- package/src/hooks/useSessionRestoration.ts +3 -1
- package/src/icons/index.ts +27 -0
- package/src/index.ts +5 -0
- package/src/providers/OrganisationProvider.tsx +23 -14
- package/src/providers/UnifiedAuthProvider.smoke.test.tsx +21 -21
- package/src/providers/__tests__/AuthProvider.test.tsx +21 -21
- package/src/providers/__tests__/EventProvider.test.tsx +61 -61
- package/src/providers/__tests__/InactivityProvider.test.tsx +56 -56
- package/src/providers/__tests__/OrganisationProvider.test.tsx +75 -75
- package/src/providers/__tests__/ProviderLifecycle.test.tsx +37 -37
- package/src/providers/__tests__/UnifiedAuthProvider.test.tsx +103 -103
- package/src/providers/services/EventServiceProvider.tsx +1 -24
- package/src/providers/services/UnifiedAuthProvider.tsx +5 -48
- package/src/providers/services/__tests__/AuthServiceProvider.integration.test.tsx +7 -7
- package/src/providers/services/__tests__/UnifiedAuthProvider.integration.test.tsx +13 -10
- package/src/rbac/__tests__/adapters.comprehensive.test.tsx +7 -457
- package/src/rbac/__tests__/auth-rbac.e2e.test.tsx +33 -7
- package/src/rbac/adapters.tsx +7 -295
- package/src/rbac/api.test.ts +44 -56
- package/src/rbac/api.ts +10 -17
- package/src/rbac/cache-invalidation.ts +0 -1
- package/src/rbac/compliance/index.ts +10 -0
- package/src/rbac/compliance/pattern-detector.ts +553 -0
- package/src/rbac/compliance/runtime-compliance.ts +22 -0
- package/src/rbac/components/AccessDenied.tsx +150 -0
- package/src/rbac/components/NavigationGuard.tsx +12 -20
- package/src/rbac/components/PagePermissionGuard.tsx +4 -24
- package/src/rbac/components/__tests__/NavigationGuard.test.tsx +21 -8
- package/src/rbac/components/index.ts +3 -41
- package/src/rbac/eslint-rules.js +1 -1
- package/src/rbac/hooks/index.ts +0 -3
- package/src/rbac/hooks/permissions/index.ts +0 -3
- package/src/rbac/hooks/permissions/useAccessLevel.ts +4 -8
- package/src/rbac/hooks/usePermissions.ts +0 -3
- package/src/rbac/hooks/useResolvedScope.test.ts +57 -47
- package/src/rbac/hooks/useResolvedScope.ts +58 -140
- package/src/rbac/hooks/useResourcePermissions.test.ts +124 -38
- package/src/rbac/hooks/useResourcePermissions.ts +139 -48
- package/src/rbac/hooks/useRoleManagement.test.ts +65 -22
- package/src/rbac/hooks/useRoleManagement.ts +147 -19
- package/src/rbac/hooks/useSecureSupabase.ts +4 -8
- package/src/rbac/index.ts +7 -9
- package/src/rbac/utils/contextValidator.ts +9 -7
- package/src/services/AuthService.ts +130 -18
- package/src/services/EventService.ts +4 -97
- package/src/services/InactivityService.ts +16 -0
- package/src/services/OrganisationService.ts +7 -44
- package/src/services/__tests__/OrganisationService.test.ts +26 -8
- package/src/services/base/BaseService.ts +0 -3
- package/src/styles/core.css +7 -0
- package/src/theming/__tests__/parseEventColours.test.ts +9 -3
- package/src/theming/parseEventColours.ts +22 -10
- package/src/types/database.generated.ts +4733 -3809
- package/src/utils/__tests__/lazyLoad.unit.test.tsx +42 -39
- package/src/utils/__tests__/organisationContext.unit.test.ts +9 -10
- package/src/utils/context/organisationContext.test.ts +13 -28
- package/src/utils/context/organisationContext.ts +21 -52
- package/src/utils/dynamic/dynamicUtils.ts +1 -1
- package/src/utils/file-reference/index.ts +39 -15
- package/src/utils/formatting/formatDateTime.test.ts +3 -2
- package/src/utils/google-places/loadGoogleMapsScript.ts +29 -4
- package/src/utils/index.ts +4 -1
- package/src/utils/persistence/__tests__/keyDerivation.test.ts +135 -0
- package/src/utils/persistence/__tests__/sensitiveFieldDetection.test.ts +123 -0
- package/src/utils/persistence/keyDerivation.ts +304 -0
- package/src/utils/persistence/sensitiveFieldDetection.ts +212 -0
- package/src/utils/security/secureStorage.ts +5 -5
- package/src/utils/storage/README.md +1 -1
- package/src/utils/storage/helpers.ts +3 -3
- package/src/utils/supabase/createBaseClient.ts +147 -0
- package/src/utils/timezone/timezone.test.ts +1 -2
- package/src/utils/timezone/timezone.ts +1 -1
- package/src/utils/validation/csrf.ts +4 -4
- package/cursor-rules/00-pace-core-compliance.mdc +0 -331
- package/cursor-rules/01-standards-compliance.mdc +0 -244
- package/cursor-rules/04-testing-standards.mdc +0 -268
- package/cursor-rules/05-bug-reports-and-features.mdc +0 -246
- package/cursor-rules/06-code-quality.mdc +0 -309
- package/cursor-rules/07-tech-stack-compliance.mdc +0 -214
- package/cursor-rules/CHANGELOG.md +0 -119
- package/cursor-rules/README.md +0 -192
- package/dist/DataTable-AOVNCPTX.js +0 -175
- package/dist/DataTable-AOVNCPTX.js.map +0 -1
- package/dist/UnifiedAuthProvider-4SBX4LU5.js +0 -18
- package/dist/UnifiedAuthProvider-4SBX4LU5.js.map +0 -1
- package/dist/api-O6HTBX5Y.js +0 -52
- package/dist/api-O6HTBX5Y.js.map +0 -1
- package/dist/audit-V53FV5AG.js +0 -17
- package/dist/audit-V53FV5AG.js.map +0 -1
- package/dist/chunk-5DRSZLL2.js.map +0 -1
- package/dist/chunk-63FOKYGO.js.map +0 -1
- package/dist/chunk-6COVEUS7.js.map +0 -1
- package/dist/chunk-AFVQODI2.js +0 -263
- package/dist/chunk-AFVQODI2.js.map +0 -1
- package/dist/chunk-DGUM43GV.js.map +0 -1
- package/dist/chunk-E66EQZE6.js.map +0 -1
- package/dist/chunk-EFN2EIMK.js.map +0 -1
- package/dist/chunk-FFQEQTNW.js.map +0 -1
- package/dist/chunk-FMUCXFII.js.map +0 -1
- package/dist/chunk-G37KK66H.js.map +0 -1
- package/dist/chunk-G7QEZTYQ.js +0 -2053
- package/dist/chunk-G7QEZTYQ.js.map +0 -1
- package/dist/chunk-HU2C6SSC.js.map +0 -1
- package/dist/chunk-IHB5DR3H.js.map +0 -1
- package/dist/chunk-IVOFDYWT.js.map +0 -1
- package/dist/chunk-J36DSWQK.js.map +0 -1
- package/dist/chunk-JGRYX5UX.js.map +0 -1
- package/dist/chunk-KQCRWDSA.js +0 -1
- package/dist/chunk-KQCRWDSA.js.map +0 -1
- package/dist/chunk-L4OXEN46.js.map +0 -1
- package/dist/chunk-LMC26NLJ.js +0 -84
- package/dist/chunk-LMC26NLJ.js.map +0 -1
- package/dist/chunk-M43Y4SSO.js.map +0 -1
- package/dist/chunk-M7MPQISP.js.map +0 -1
- package/dist/chunk-NTM7ZSB6.js.map +0 -1
- package/dist/chunk-PWLANIRT.js.map +0 -1
- package/dist/chunk-QXHPKYJV.js.map +0 -1
- package/dist/chunk-RGAWHO7N.js.map +0 -1
- package/dist/chunk-UPPMRMYG.js.map +0 -1
- package/dist/chunk-VBXEHIUJ.js.map +0 -1
- package/dist/chunk-ZSAAAMVR.js.map +0 -1
- package/dist/components.js.map +0 -1
- package/dist/contextValidator-5OGXSPKS.js +0 -9
- package/dist/contextValidator-5OGXSPKS.js.map +0 -1
- package/dist/eslint-rules/pace-core-compliance.cjs +0 -510
- package/dist/hooks.js.map +0 -1
- package/dist/index.js.map +0 -1
- package/dist/providers.js.map +0 -1
- package/dist/rbac/eslint-rules.js.map +0 -1
- package/dist/rbac/index.js.map +0 -1
- package/dist/styles/index.js.map +0 -1
- package/dist/theming/runtime.js.map +0 -1
- package/dist/types.js.map +0 -1
- package/dist/utils.js.map +0 -1
- package/docs/best-practices/README.md +0 -472
- package/docs/best-practices/accessibility.md +0 -601
- package/docs/best-practices/common-patterns.md +0 -516
- package/docs/best-practices/deployment.md +0 -1103
- package/docs/best-practices/performance.md +0 -1328
- package/docs/best-practices/security.md +0 -940
- package/docs/best-practices/testing.md +0 -1034
- package/docs/rbac/compliance/compliance-guide.md +0 -544
- package/docs/standards/01-architecture-standard.md +0 -44
- package/docs/standards/02-api-and-rpc-standard.md +0 -39
- package/docs/standards/03-component-standard.md +0 -32
- package/docs/standards/04-code-style-standard.md +0 -32
- package/docs/standards/05-security-standard.md +0 -44
- package/docs/standards/06-testing-and-docs-standard.md +0 -29
- package/docs/standards/pace-core-compliance.md +0 -432
- package/scripts/audit/core/checks/accessibility.cjs +0 -197
- package/scripts/audit/core/checks/api-usage.cjs +0 -191
- package/scripts/audit/core/checks/bundle.cjs +0 -142
- package/scripts/audit/core/checks/compliance.cjs +0 -2706
- package/scripts/audit/core/checks/config.cjs +0 -54
- package/scripts/audit/core/checks/coverage.cjs +0 -84
- package/scripts/audit/core/checks/dependencies.cjs +0 -994
- package/scripts/audit/core/checks/documentation.cjs +0 -268
- package/scripts/audit/core/checks/environment.cjs +0 -116
- package/scripts/audit/core/checks/error-handling.cjs +0 -340
- package/scripts/audit/core/checks/forms.cjs +0 -172
- package/scripts/audit/core/checks/heuristics.cjs +0 -68
- package/scripts/audit/core/checks/hooks.cjs +0 -334
- package/scripts/audit/core/checks/imports.cjs +0 -244
- package/scripts/audit/core/checks/performance.cjs +0 -325
- package/scripts/audit/core/checks/routes.cjs +0 -117
- package/scripts/audit/core/checks/state.cjs +0 -130
- package/scripts/audit/core/checks/structure.cjs +0 -65
- package/scripts/audit/core/checks/style.cjs +0 -584
- package/scripts/audit/core/checks/testing.cjs +0 -122
- package/scripts/audit/core/checks/typescript.cjs +0 -61
- package/scripts/audit/core/scanner.cjs +0 -199
- package/scripts/audit/core/utils.cjs +0 -137
- package/scripts/audit/index.cjs +0 -223
- package/scripts/audit/reporters/console.cjs +0 -151
- package/scripts/audit/reporters/json.cjs +0 -54
- package/scripts/audit/reporters/markdown.cjs +0 -124
- package/scripts/audit-consuming-app.cjs +0 -86
- package/src/components/DataTable/components/DataTableBody.tsx +0 -454
- package/src/components/DataTable/components/DraggableColumnHeader.tsx +0 -156
- package/src/components/DataTable/components/ExpandButton.tsx +0 -113
- package/src/components/DataTable/components/GroupHeader.tsx +0 -54
- package/src/components/DataTable/components/ViewRowModal.tsx +0 -68
- package/src/components/DataTable/components/VirtualizedDataTable.tsx +0 -525
- package/src/components/DataTable/components/__tests__/ExpandButton.test.tsx +0 -462
- package/src/components/DataTable/components/__tests__/GroupHeader.test.tsx +0 -393
- package/src/components/DataTable/components/__tests__/ViewRowModal.test.tsx +0 -476
- package/src/components/DataTable/components/__tests__/VirtualizedDataTable.test.tsx +0 -128
- package/src/components/DataTable/core/DataTableContext.tsx +0 -216
- package/src/components/DataTable/core/__tests__/DataTableContext.test.tsx +0 -136
- package/src/components/DataTable/hooks/__tests__/useColumnReordering.test.ts +0 -570
- package/src/components/DataTable/hooks/useColumnReordering.ts +0 -123
- package/src/components/DataTable/utils/debugTools.ts +0 -514
- package/src/eslint-rules/pace-core-compliance.js +0 -638
- package/src/rbac/components/EnhancedNavigationMenu.test.tsx +0 -555
- package/src/rbac/components/EnhancedNavigationMenu.tsx +0 -293
- package/src/rbac/components/NavigationProvider.test.tsx +0 -481
- package/src/rbac/components/NavigationProvider.tsx +0 -345
- package/src/rbac/components/PagePermissionProvider.test.tsx +0 -476
- package/src/rbac/components/PagePermissionProvider.tsx +0 -279
- package/src/rbac/components/PermissionEnforcer.tsx +0 -312
- package/src/rbac/components/RoleBasedRouter.tsx +0 -440
- package/src/rbac/components/SecureDataProvider.test.tsx +0 -543
- package/src/rbac/components/SecureDataProvider.tsx +0 -339
- package/src/rbac/components/__tests__/EnhancedNavigationMenu.test.tsx +0 -620
- package/src/rbac/components/__tests__/NavigationProvider.test.tsx +0 -726
- package/src/rbac/components/__tests__/PagePermissionProvider.test.tsx +0 -661
- package/src/rbac/components/__tests__/PermissionEnforcer.test.tsx +0 -881
- package/src/rbac/components/__tests__/RoleBasedRouter.test.tsx +0 -783
- package/src/rbac/components/__tests__/SecureDataProvider.fixed.test.tsx +0 -645
- package/src/rbac/components/__tests__/SecureDataProvider.test.tsx +0 -659
- package/src/rbac/hooks/permissions/useCachedPermissions.ts +0 -79
- package/src/rbac/hooks/permissions/useHasAllPermissions.ts +0 -90
- package/src/rbac/hooks/permissions/useHasAnyPermission.ts +0 -90
|
@@ -1,13 +1,43 @@
|
|
|
1
1
|
---
|
|
2
|
-
description: Enforce SOLID architecture principles
|
|
2
|
+
description: Enforce SOLID architecture principles, component design, and API design patterns
|
|
3
3
|
globs: ["src/**/*.{ts,tsx}"]
|
|
4
4
|
alwaysApply: false
|
|
5
5
|
paceCoreVersion: "0.6.x"
|
|
6
6
|
rulesVersion: "2025-01-28"
|
|
7
7
|
---
|
|
8
|
-
#
|
|
8
|
+
# Architecture Standards Guide
|
|
9
9
|
|
|
10
|
-
|
|
10
|
+
**📚 Human-Readable Standard**: See [3-architecture-standards.md](../../packages/core/docs/standards/3-architecture-standards.md) for complete documentation.
|
|
11
|
+
|
|
12
|
+
This guide enforces SOLID architecture principles, component design patterns, and API design patterns to ensure maintainable, extensible, and testable code.
|
|
13
|
+
|
|
14
|
+
## AI Agent Instructions
|
|
15
|
+
|
|
16
|
+
**When writing or modifying code, ALWAYS:**
|
|
17
|
+
1. **Extract complex logic** - Move business logic out of components into hooks, services, or utilities
|
|
18
|
+
2. **Use composition** - Extend functionality through composition, not modification of pace-core components
|
|
19
|
+
3. **Keep components simple** - Components should only handle UI rendering, not data fetching or business logic
|
|
20
|
+
4. **Use focused interfaces** - Create small, specific interfaces instead of large, generic ones
|
|
21
|
+
5. **Depend on abstractions** - Use interfaces/types, not concrete implementations
|
|
22
|
+
6. **Follow ApiResult pattern** - All RPCs must return ApiResult shape with proper error handling
|
|
23
|
+
|
|
24
|
+
**Decision Tree: Where should this logic live?**
|
|
25
|
+
```
|
|
26
|
+
1. What type of logic is this?
|
|
27
|
+
├─ UI rendering → Component
|
|
28
|
+
├─ Data fetching → Hook or service
|
|
29
|
+
├─ Business logic → Hook, service, or utility
|
|
30
|
+
├─ Formatting/transformation → Utility function
|
|
31
|
+
└─ Validation → Zod schema or utility
|
|
32
|
+
|
|
33
|
+
2. Is this logic complex?
|
|
34
|
+
├─ YES → Extract to hook/service/utility
|
|
35
|
+
└─ NO → Can stay in component if simple
|
|
36
|
+
|
|
37
|
+
3. Does this modify pace-core behavior?
|
|
38
|
+
├─ YES → Use composition (wrap pace-core component)
|
|
39
|
+
└─ NO → Continue
|
|
40
|
+
```
|
|
11
41
|
|
|
12
42
|
## Single Responsibility Principle (SRP)
|
|
13
43
|
|
|
@@ -204,17 +234,103 @@ Before committing code, verify:
|
|
|
204
234
|
- [ ] No god objects or bloated components
|
|
205
235
|
- [ ] Code is testable and maintainable
|
|
206
236
|
|
|
207
|
-
##
|
|
237
|
+
## Common Mistakes to Avoid
|
|
238
|
+
|
|
239
|
+
**When writing code, NEVER:**
|
|
240
|
+
1. **Create god objects** - Components/classes that do too much
|
|
241
|
+
```tsx
|
|
242
|
+
// ❌ WRONG: Component does everything
|
|
243
|
+
function UserDashboard({ userId }) {
|
|
244
|
+
const [user, setUser] = useState(null);
|
|
245
|
+
const [events, setEvents] = useState([]);
|
|
246
|
+
const [organisations, setOrganisations] = useState([]);
|
|
247
|
+
// 200+ lines of logic...
|
|
248
|
+
}
|
|
249
|
+
|
|
250
|
+
// ✅ CORRECT: Separated concerns
|
|
251
|
+
function UserDashboard({ userId }) {
|
|
252
|
+
const user = useUser(userId);
|
|
253
|
+
const events = useUserEvents(userId);
|
|
254
|
+
const organisations = useUserOrganisations(userId);
|
|
255
|
+
return <DashboardContent user={user} events={events} organisations={organisations} />;
|
|
256
|
+
}
|
|
257
|
+
```
|
|
258
|
+
|
|
259
|
+
2. **Put business logic in components** - Extract to hooks/services
|
|
260
|
+
3. **Create large interfaces** - Use focused, specific interfaces
|
|
261
|
+
4. **Depend on concrete implementations** - Use abstractions (interfaces/types)
|
|
262
|
+
5. **Modify pace-core components** - Use composition instead
|
|
263
|
+
6. **Use boolean flags for states** - Use discriminated unions
|
|
264
|
+
|
|
265
|
+
## API Design Patterns
|
|
266
|
+
|
|
267
|
+
### MUST: Follow API Design Principles
|
|
268
|
+
|
|
269
|
+
**APIs MUST be:**
|
|
270
|
+
- Intuitive and consistent
|
|
271
|
+
- Extensible without breaking changes
|
|
272
|
+
- Clear about errors and edge cases
|
|
273
|
+
|
|
274
|
+
### MUST: Use ApiResult Pattern
|
|
275
|
+
|
|
276
|
+
**All RPCs MUST return ApiResult shape:**
|
|
277
|
+
|
|
278
|
+
```typescript
|
|
279
|
+
type ApiResult<T> = { ok: true; data: T } | { ok: false; error: ApiError };
|
|
280
|
+
type ApiError = { code: string; message: string; details?: object };
|
|
281
|
+
```
|
|
282
|
+
|
|
283
|
+
```tsx
|
|
284
|
+
// ✅ CORRECT: RPC returns ApiResult
|
|
285
|
+
const result = await supabase.rpc('app_events_create', { name, date });
|
|
286
|
+
if (!result.ok) {
|
|
287
|
+
// Handle error
|
|
288
|
+
return { ok: false, error: result.error };
|
|
289
|
+
}
|
|
290
|
+
return { ok: true, data: result.data };
|
|
291
|
+
```
|
|
292
|
+
|
|
293
|
+
### SHOULD: Make Write RPCs Idempotent
|
|
294
|
+
|
|
295
|
+
**Write RPCs SHOULD be idempotent when possible:**
|
|
296
|
+
|
|
297
|
+
```sql
|
|
298
|
+
-- ✅ CORRECT: Idempotent create (ON CONFLICT DO NOTHING)
|
|
299
|
+
INSERT INTO events (id, name, date)
|
|
300
|
+
VALUES (p_event_id, p_name, p_date)
|
|
301
|
+
ON CONFLICT (id) DO NOTHING;
|
|
302
|
+
```
|
|
303
|
+
|
|
304
|
+
## Component Design Patterns
|
|
305
|
+
|
|
306
|
+
### MUST: Follow Component Principles
|
|
208
307
|
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
308
|
+
**Components MUST:**
|
|
309
|
+
- Be stateless when possible
|
|
310
|
+
- Use composable structure
|
|
311
|
+
- Be accessible by default
|
|
312
|
+
- Be fully typed
|
|
313
|
+
- Have small surface area
|
|
314
|
+
|
|
315
|
+
### MUST NOT: Add Domain Logic to Components
|
|
316
|
+
|
|
317
|
+
**Components MUST NOT:**
|
|
318
|
+
- Include domain-specific logic
|
|
319
|
+
- Fetch data directly (use hooks/services)
|
|
320
|
+
- Include business workflows
|
|
321
|
+
|
|
322
|
+
### MUST: Ensure Accessibility
|
|
323
|
+
|
|
324
|
+
**Components MUST:**
|
|
325
|
+
- Be keyboard operable
|
|
326
|
+
- Have correct ARIA roles
|
|
327
|
+
- Have visible focus states
|
|
328
|
+
- Avoid inaccessible interactions
|
|
215
329
|
|
|
216
330
|
## Reference
|
|
217
331
|
|
|
332
|
+
**Note**: RLS policy validation is handled by the audit tool. See [3-architecture-standards.md](../../packages/core/docs/standards/3-architecture-standards.md) for complete enforcement details.
|
|
333
|
+
|
|
218
334
|
- Single Responsibility: Each module has one reason to change
|
|
219
335
|
- Open/Closed: Open for extension, closed for modification
|
|
220
336
|
- Liskov Substitution: Subtypes must be substitutable
|
|
@@ -0,0 +1,419 @@
|
|
|
1
|
+
---
|
|
2
|
+
description: Enforce code quality standards including TypeScript, ESLint, formatting, performance, and accessibility
|
|
3
|
+
globs: ["src/**/*.{ts,tsx,js,jsx}"]
|
|
4
|
+
alwaysApply: false
|
|
5
|
+
paceCoreVersion: "0.6.x"
|
|
6
|
+
rulesVersion: "2025-01-28"
|
|
7
|
+
---
|
|
8
|
+
# Code Quality Guide
|
|
9
|
+
|
|
10
|
+
**📚 Human-Readable Standard**: See [4-code-quality-standards.md](../../packages/core/docs/standards/4-code-quality-standards.md) for complete documentation.
|
|
11
|
+
|
|
12
|
+
This guide enforces code quality standards to ensure maintainable, performant, and accessible code.
|
|
13
|
+
|
|
14
|
+
## AI Agent Instructions
|
|
15
|
+
|
|
16
|
+
**When writing or modifying code, ALWAYS:**
|
|
17
|
+
1. **Use strict TypeScript** - Never use `any`, always use proper types or `unknown` with type guards
|
|
18
|
+
2. **Use discriminated unions** - Replace boolean flags with discriminated unions for better type safety
|
|
19
|
+
3. **Use ReadonlyArray** - Use `ReadonlyArray` for immutable arrays
|
|
20
|
+
4. **Ensure accessibility** - All components must be keyboard accessible, have ARIA labels, and visible focus states
|
|
21
|
+
5. **Use semantic HTML** - Use semantic elements (`<main>`, `<section>`, `<article>`, etc.) instead of `<div>` wrappers
|
|
22
|
+
6. **Memoize appropriately** - Use `useMemo` and `useCallback` for expensive computations and stable references
|
|
23
|
+
7. **Early returns** - Use early returns to reduce nesting and improve readability
|
|
24
|
+
|
|
25
|
+
**Decision Tree: Type Safety**
|
|
26
|
+
```
|
|
27
|
+
1. What type should I use?
|
|
28
|
+
├─ Known structure → Interface or type
|
|
29
|
+
├─ Truly unknown → unknown (with type guard)
|
|
30
|
+
└─ Multiple variants → Discriminated union (not boolean flags)
|
|
31
|
+
|
|
32
|
+
2. Is this an array that shouldn't be mutated?
|
|
33
|
+
├─ YES → ReadonlyArray<T>
|
|
34
|
+
└─ NO → Array<T> or T[]
|
|
35
|
+
|
|
36
|
+
3. Do I need multiple states?
|
|
37
|
+
├─ YES → Discriminated union (type: 'loading' | 'success' | 'error')
|
|
38
|
+
└─ NO → Single type
|
|
39
|
+
```
|
|
40
|
+
|
|
41
|
+
## TypeScript Standards
|
|
42
|
+
|
|
43
|
+
### MUST: Use Strict Mode
|
|
44
|
+
|
|
45
|
+
**TypeScript MUST use strict mode:**
|
|
46
|
+
|
|
47
|
+
```json
|
|
48
|
+
// tsconfig.json
|
|
49
|
+
{
|
|
50
|
+
"compilerOptions": {
|
|
51
|
+
"strict": true,
|
|
52
|
+
"noImplicitAny": true,
|
|
53
|
+
"strictNullChecks": true,
|
|
54
|
+
"strictFunctionTypes": true,
|
|
55
|
+
"strictBindCallApply": true,
|
|
56
|
+
"strictPropertyInitialization": true,
|
|
57
|
+
"noImplicitThis": true,
|
|
58
|
+
"alwaysStrict": true
|
|
59
|
+
}
|
|
60
|
+
}
|
|
61
|
+
```
|
|
62
|
+
|
|
63
|
+
### MUST NOT: Use `any`
|
|
64
|
+
|
|
65
|
+
**MUST NOT use `any` type. Use `unknown` if type is truly unknown:**
|
|
66
|
+
|
|
67
|
+
```tsx
|
|
68
|
+
// ❌ WRONG: Using any
|
|
69
|
+
function processData(data: any) { return data.value; }
|
|
70
|
+
|
|
71
|
+
// ✅ CORRECT: Using unknown with type guard or proper types
|
|
72
|
+
function processData(data: unknown) {
|
|
73
|
+
if (typeof data === 'object' && data !== null && 'value' in data) {
|
|
74
|
+
return (data as { value: string }).value;
|
|
75
|
+
}
|
|
76
|
+
throw new Error('Invalid data');
|
|
77
|
+
}
|
|
78
|
+
// Or: interface Data { value: string; } function processData(data: Data) { return data.value; }
|
|
79
|
+
```
|
|
80
|
+
|
|
81
|
+
### MUST: Use Discriminated Unions
|
|
82
|
+
|
|
83
|
+
**MUST use discriminated unions instead of boolean flags:**
|
|
84
|
+
|
|
85
|
+
```tsx
|
|
86
|
+
// ❌ WRONG: Boolean flags (confusing: what if both are true?)
|
|
87
|
+
interface User { isAdmin: boolean; isGuest: boolean; }
|
|
88
|
+
|
|
89
|
+
// ✅ CORRECT: Discriminated union
|
|
90
|
+
type User = { type: 'admin'; permissions: Permission[] } | { type: 'guest'; limitedAccess: boolean } | { type: 'user'; role: UserRole };
|
|
91
|
+
```
|
|
92
|
+
|
|
93
|
+
### SHOULD: Use ReadonlyArray
|
|
94
|
+
|
|
95
|
+
**SHOULD use ReadonlyArray for immutable arrays:**
|
|
96
|
+
|
|
97
|
+
```tsx
|
|
98
|
+
// ✅ CORRECT - ReadonlyArray
|
|
99
|
+
function processItems(items: ReadonlyArray<Item>) {
|
|
100
|
+
// Can't mutate items
|
|
101
|
+
return items.map(item => transform(item));
|
|
102
|
+
}
|
|
103
|
+
```
|
|
104
|
+
|
|
105
|
+
## ESLint Configuration
|
|
106
|
+
|
|
107
|
+
**Note**: ESLint configuration and enforcement is handled by ESLint (Layer 3). See [4-code-quality-standards.md](../../packages/core/docs/standards/4-code-quality-standards.md) for complete ESLint setup instructions.
|
|
108
|
+
|
|
109
|
+
**MUST:**
|
|
110
|
+
- Use pace-core ESLint config
|
|
111
|
+
- Fix all ESLint errors before committing
|
|
112
|
+
- Run `npm run lint` before committing
|
|
113
|
+
|
|
114
|
+
## Code Formatting
|
|
115
|
+
|
|
116
|
+
### MUST: Use Consistent Formatting
|
|
117
|
+
|
|
118
|
+
**MUST use Prettier or equivalent for consistent formatting:**
|
|
119
|
+
|
|
120
|
+
```json
|
|
121
|
+
// .prettierrc
|
|
122
|
+
{
|
|
123
|
+
"semi": true,
|
|
124
|
+
"singleQuote": true,
|
|
125
|
+
"tabWidth": 2,
|
|
126
|
+
"trailingComma": "es5",
|
|
127
|
+
"printWidth": 100
|
|
128
|
+
}
|
|
129
|
+
```
|
|
130
|
+
|
|
131
|
+
### MUST: Format Before Committing
|
|
132
|
+
|
|
133
|
+
**MUST format code before committing:**
|
|
134
|
+
|
|
135
|
+
```bash
|
|
136
|
+
npm run format
|
|
137
|
+
# Or use pre-commit hook
|
|
138
|
+
```
|
|
139
|
+
|
|
140
|
+
## Performance Considerations
|
|
141
|
+
|
|
142
|
+
### SHOULD: Optimize Re-renders
|
|
143
|
+
|
|
144
|
+
**SHOULD use React.memo, useMemo, useCallback appropriately:**
|
|
145
|
+
|
|
146
|
+
```tsx
|
|
147
|
+
// ✅ CORRECT: Memoize expensive computations, callbacks, and components
|
|
148
|
+
const expensiveValue = useMemo(() => computeExpensiveValue(data), [data]);
|
|
149
|
+
const handleClick = useCallback(() => doSomething(id), [id]);
|
|
150
|
+
const ExpensiveComponent = React.memo(({ data }) => <div>{/* ... */}</div>);
|
|
151
|
+
```
|
|
152
|
+
|
|
153
|
+
### SHOULD: Avoid Unnecessary Re-renders
|
|
154
|
+
|
|
155
|
+
**SHOULD avoid causing unnecessary re-renders:**
|
|
156
|
+
|
|
157
|
+
```tsx
|
|
158
|
+
// ❌ WRONG: New object on every render (causes unnecessary re-renders)
|
|
159
|
+
function Component({ items }) { const config = { items, enabled: true }; return <Child config={config} />; }
|
|
160
|
+
|
|
161
|
+
// ✅ CORRECT: Memoize object
|
|
162
|
+
function Component({ items }) {
|
|
163
|
+
const config = useMemo(() => ({ items, enabled: true }), [items]);
|
|
164
|
+
return <Child config={config} />;
|
|
165
|
+
}
|
|
166
|
+
```
|
|
167
|
+
|
|
168
|
+
### SHOULD: Lazy Load Heavy Components
|
|
169
|
+
|
|
170
|
+
**SHOULD lazy load heavy components:**
|
|
171
|
+
|
|
172
|
+
```tsx
|
|
173
|
+
// ✅ CORRECT: Lazy load heavy components
|
|
174
|
+
import { lazy, Suspense } from 'react';
|
|
175
|
+
const HeavyComponent = lazy(() => import('./HeavyComponent'));
|
|
176
|
+
function App() {
|
|
177
|
+
return <Suspense fallback={<Loading />}><HeavyComponent /></Suspense>;
|
|
178
|
+
}
|
|
179
|
+
```
|
|
180
|
+
|
|
181
|
+
## Accessibility Requirements
|
|
182
|
+
|
|
183
|
+
**MUST** ensure all components and pages meet WCAG 2.1 Level AA standards.
|
|
184
|
+
|
|
185
|
+
### Core Principles
|
|
186
|
+
|
|
187
|
+
1. **Semantic HTML** - Use semantic elements (`<main>`, `<section>`, `<article>`, `<nav>`, etc.) instead of `<div>` wrappers
|
|
188
|
+
2. **Keyboard Navigation** - All interactive elements must be accessible via keyboard
|
|
189
|
+
3. **ARIA Labels** - Provide clear labels for screen readers when visible text isn't sufficient
|
|
190
|
+
4. **Focus Management** - Visible focus indicators on all interactive elements
|
|
191
|
+
5. **Color Contrast** - Text must meet 4.5:1 contrast ratio (WCAG AA)
|
|
192
|
+
|
|
193
|
+
### Implementation Requirements
|
|
194
|
+
|
|
195
|
+
```tsx
|
|
196
|
+
// ✅ CORRECT - Semantic HTML with ARIA
|
|
197
|
+
<main>
|
|
198
|
+
<h1>Page Title</h1>
|
|
199
|
+
<section aria-labelledby="section-title">
|
|
200
|
+
<h2 id="section-title">Section Title</h2>
|
|
201
|
+
<Button
|
|
202
|
+
aria-label="Delete user"
|
|
203
|
+
aria-describedby="delete-help"
|
|
204
|
+
>
|
|
205
|
+
Delete
|
|
206
|
+
</Button>
|
|
207
|
+
<span id="delete-help" className="sr-only">
|
|
208
|
+
Permanently removes the user account
|
|
209
|
+
</span>
|
|
210
|
+
</section>
|
|
211
|
+
</main>
|
|
212
|
+
|
|
213
|
+
// ❌ WRONG - Non-semantic structure
|
|
214
|
+
<div>
|
|
215
|
+
<div className="title">Page Title</div>
|
|
216
|
+
<div>
|
|
217
|
+
<button>Delete</button>
|
|
218
|
+
</div>
|
|
219
|
+
</div>
|
|
220
|
+
```
|
|
221
|
+
|
|
222
|
+
### Keyboard Navigation
|
|
223
|
+
|
|
224
|
+
**MUST** ensure all interactive elements are keyboard accessible:
|
|
225
|
+
|
|
226
|
+
```tsx
|
|
227
|
+
// ✅ CORRECT - pace-core components handle keyboard navigation automatically
|
|
228
|
+
import { Button, DataTable } from '@jmruthers/pace-core';
|
|
229
|
+
|
|
230
|
+
<Button onClick={handleClick}>Click me</Button>
|
|
231
|
+
<DataTable data={data} columns={columns} />
|
|
232
|
+
```
|
|
233
|
+
|
|
234
|
+
### Screen Reader Support
|
|
235
|
+
|
|
236
|
+
**MUST** provide appropriate ARIA attributes:
|
|
237
|
+
|
|
238
|
+
```tsx
|
|
239
|
+
// ✅ CORRECT - ARIA labels for icons
|
|
240
|
+
<Button aria-label="Close dialog">
|
|
241
|
+
<Icon name="x" aria-hidden="true" />
|
|
242
|
+
</Button>
|
|
243
|
+
|
|
244
|
+
// ✅ CORRECT - Error messages with role="alert"
|
|
245
|
+
{error && (
|
|
246
|
+
<div role="alert" aria-live="polite">
|
|
247
|
+
{error.message}
|
|
248
|
+
</div>
|
|
249
|
+
)}
|
|
250
|
+
|
|
251
|
+
// ✅ CORRECT - Loading states
|
|
252
|
+
<div role="status" aria-live="polite" aria-busy={loading}>
|
|
253
|
+
{loading && <span className="sr-only">Loading data...</span>}
|
|
254
|
+
{loading ? <Spinner /> : <Content />}
|
|
255
|
+
</div>
|
|
256
|
+
```
|
|
257
|
+
|
|
258
|
+
### Testing Accessibility
|
|
259
|
+
|
|
260
|
+
**MUST** test with:
|
|
261
|
+
- Keyboard navigation (Tab, Enter, Space, Arrow keys)
|
|
262
|
+
- Screen readers (NVDA, JAWS, VoiceOver)
|
|
263
|
+
- Automated tools (axe DevTools, WAVE, Lighthouse)
|
|
264
|
+
|
|
265
|
+
**Accessibility Checklist:**
|
|
266
|
+
- [ ] All interactive elements keyboard accessible
|
|
267
|
+
- [ ] Visible focus indicators on all interactive elements
|
|
268
|
+
- [ ] ARIA labels provided for icons and images
|
|
269
|
+
- [ ] Semantic HTML used appropriately
|
|
270
|
+
- [ ] Error messages properly associated with form fields
|
|
271
|
+
- [ ] Color contrast meets WCAG AA (4.5:1 for text)
|
|
272
|
+
- [ ] Screen reader announcements work correctly
|
|
273
|
+
- [ ] Focus management in modals and dynamic content
|
|
274
|
+
|
|
275
|
+
## Code Review Checklist
|
|
276
|
+
|
|
277
|
+
**Before submitting code for review, verify:**
|
|
278
|
+
|
|
279
|
+
- [ ] TypeScript strict mode enabled
|
|
280
|
+
- [ ] No `any` types used
|
|
281
|
+
- [ ] ESLint passes with no errors
|
|
282
|
+
- [ ] Code is formatted consistently
|
|
283
|
+
- [ ] Performance optimizations applied where needed
|
|
284
|
+
- [ ] Accessibility requirements met
|
|
285
|
+
- [ ] Semantic HTML used
|
|
286
|
+
- [ ] ARIA labels provided
|
|
287
|
+
- [ ] Keyboard navigation works
|
|
288
|
+
- [ ] Focus indicators visible
|
|
289
|
+
- [ ] Code is readable and maintainable
|
|
290
|
+
- [ ] Comments explain "why", not "what"
|
|
291
|
+
|
|
292
|
+
## Code Complexity
|
|
293
|
+
|
|
294
|
+
### SHOULD: Keep Functions Small
|
|
295
|
+
|
|
296
|
+
**Functions SHOULD be small and focused:**
|
|
297
|
+
|
|
298
|
+
```tsx
|
|
299
|
+
// ❌ WRONG: Large function (100+ lines, multiple responsibilities)
|
|
300
|
+
function processUserData(user) { /* 100+ lines of logic */ }
|
|
301
|
+
|
|
302
|
+
// ✅ CORRECT: Small, focused functions
|
|
303
|
+
function validateUser(user: User): ValidationResult { /* Validation logic */ }
|
|
304
|
+
function transformUser(user: User): TransformedUser { /* Transformation logic */ }
|
|
305
|
+
function processUserData(user: User) {
|
|
306
|
+
const validation = validateUser(user);
|
|
307
|
+
if (!validation.valid) return validation;
|
|
308
|
+
return transformUser(user);
|
|
309
|
+
}
|
|
310
|
+
```
|
|
311
|
+
|
|
312
|
+
### SHOULD: Limit Cyclomatic Complexity
|
|
313
|
+
|
|
314
|
+
**Functions SHOULD have low cyclomatic complexity (< 10):**
|
|
315
|
+
|
|
316
|
+
```tsx
|
|
317
|
+
// ❌ WRONG: High complexity (many nested conditions)
|
|
318
|
+
function processData(data) { if (condition1) { if (condition2) { if (condition3) { /* ... */ } } } }
|
|
319
|
+
|
|
320
|
+
// ✅ CORRECT: Lower complexity (early returns)
|
|
321
|
+
function processData(data) { if (!condition1) return; if (!condition2) return; if (!condition3) return; /* Process */ }
|
|
322
|
+
```
|
|
323
|
+
|
|
324
|
+
## Error Handling
|
|
325
|
+
|
|
326
|
+
### MUST: Handle Errors Gracefully
|
|
327
|
+
|
|
328
|
+
**MUST handle errors and provide user feedback:**
|
|
329
|
+
|
|
330
|
+
```tsx
|
|
331
|
+
// ✅ CORRECT: Handle errors gracefully with user feedback
|
|
332
|
+
try {
|
|
333
|
+
const data = await fetchData();
|
|
334
|
+
setData(data);
|
|
335
|
+
} catch (error) {
|
|
336
|
+
logger.error('Failed to fetch data', error);
|
|
337
|
+
toast.error('Failed to load data. Please try again.');
|
|
338
|
+
}
|
|
339
|
+
```
|
|
340
|
+
|
|
341
|
+
### MUST: Use Type-Safe Error Handling
|
|
342
|
+
|
|
343
|
+
**MUST use type-safe error handling:**
|
|
344
|
+
|
|
345
|
+
```tsx
|
|
346
|
+
// ✅ CORRECT: Type-safe error handling
|
|
347
|
+
function isApiError(error: unknown): error is ApiError {
|
|
348
|
+
return typeof error === 'object' && error !== null && 'code' in error && 'message' in error;
|
|
349
|
+
}
|
|
350
|
+
try {
|
|
351
|
+
await apiCall();
|
|
352
|
+
} catch (error) {
|
|
353
|
+
if (isApiError(error)) handleApiError(error);
|
|
354
|
+
else handleUnknownError(error);
|
|
355
|
+
}
|
|
356
|
+
```
|
|
357
|
+
|
|
358
|
+
## Common Mistakes to Avoid
|
|
359
|
+
|
|
360
|
+
**When writing code, NEVER:**
|
|
361
|
+
1. **Use `any` type** - Always use proper types or `unknown` with type guards
|
|
362
|
+
```tsx
|
|
363
|
+
// ❌ WRONG
|
|
364
|
+
function process(data: any) {
|
|
365
|
+
return data.value;
|
|
366
|
+
}
|
|
367
|
+
|
|
368
|
+
// ✅ CORRECT
|
|
369
|
+
function process(data: unknown) {
|
|
370
|
+
if (typeof data === 'object' && data !== null && 'value' in data) {
|
|
371
|
+
return (data as { value: string }).value;
|
|
372
|
+
}
|
|
373
|
+
throw new Error('Invalid data');
|
|
374
|
+
}
|
|
375
|
+
```
|
|
376
|
+
|
|
377
|
+
2. **Use boolean flags for multiple states** - Use discriminated unions
|
|
378
|
+
```tsx
|
|
379
|
+
// ❌ WRONG
|
|
380
|
+
interface User { isAdmin: boolean; isGuest: boolean; }
|
|
381
|
+
|
|
382
|
+
// ✅ CORRECT
|
|
383
|
+
type User =
|
|
384
|
+
| { type: 'admin'; permissions: Permission[] }
|
|
385
|
+
| { type: 'guest'; limitedAccess: boolean }
|
|
386
|
+
| { type: 'user'; role: UserRole };
|
|
387
|
+
```
|
|
388
|
+
|
|
389
|
+
3. **Forget accessibility** - Always ensure keyboard navigation, ARIA labels, and semantic HTML
|
|
390
|
+
4. **Create mutable arrays when they shouldn't change** - Use `ReadonlyArray`
|
|
391
|
+
5. **Skip memoization for expensive operations** - Use `useMemo` and `useCallback` appropriately
|
|
392
|
+
|
|
393
|
+
## Code Quality Checklist
|
|
394
|
+
|
|
395
|
+
Before committing, verify:
|
|
396
|
+
- [ ] TypeScript strict mode enabled
|
|
397
|
+
- [ ] No `any` types (use `unknown` with type guards)
|
|
398
|
+
- [ ] Discriminated unions used instead of boolean flags
|
|
399
|
+
- [ ] `ReadonlyArray` used for immutable arrays
|
|
400
|
+
- [ ] Naming conventions followed (hooks: `use*`, providers: `*Provider`, etc.)
|
|
401
|
+
- [ ] Pure functions preferred (no side effects)
|
|
402
|
+
- [ ] Early returns used to reduce nesting
|
|
403
|
+
- [ ] Complex logic extracted to helpers
|
|
404
|
+
- [ ] Components are small and focused
|
|
405
|
+
- [ ] Functional components only (no class components)
|
|
406
|
+
- [ ] Hook dependencies are complete
|
|
407
|
+
- [ ] Memoization used when appropriate
|
|
408
|
+
- [ ] Accessibility requirements met (WCAG 2.1 AA)
|
|
409
|
+
- [ ] Keyboard navigation supported
|
|
410
|
+
- [ ] ARIA labels provided where needed
|
|
411
|
+
- [ ] Semantic HTML used appropriately
|
|
412
|
+
|
|
413
|
+
## Reference
|
|
414
|
+
|
|
415
|
+
**Note**: ESLint configuration details and mechanical type checking are handled by ESLint (Layer 3). See [4-code-quality-standards.md](../../packages/core/docs/standards/4-code-quality-standards.md) for complete enforcement details.
|
|
416
|
+
|
|
417
|
+
- TypeScript Handbook: https://www.typescriptlang.org/docs/
|
|
418
|
+
- React Performance: https://react.dev/learn/render-and-commit
|
|
419
|
+
- Web Accessibility: https://www.w3.org/WAI/
|