@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,340 +0,0 @@
|
|
|
1
|
-
#!/usr/bin/env node
|
|
2
|
-
|
|
3
|
-
/**
|
|
4
|
-
* Error Handling Check Module
|
|
5
|
-
* @package @jmruthers/pace-core
|
|
6
|
-
* @module Audit/Checks/ErrorHandling
|
|
7
|
-
*
|
|
8
|
-
* Checks for:
|
|
9
|
-
* - Missing error boundaries
|
|
10
|
-
* - Unhandled promise rejections
|
|
11
|
-
* - Missing error handling in async functions
|
|
12
|
-
* - Silent error swallowing
|
|
13
|
-
* - Missing error states in components
|
|
14
|
-
*/
|
|
15
|
-
|
|
16
|
-
const fs = require('fs');
|
|
17
|
-
const path = require('path');
|
|
18
|
-
const { getRelativePath, getLineNumber } = require('../utils.cjs');
|
|
19
|
-
|
|
20
|
-
const errorHandlingCheck = {
|
|
21
|
-
name: 'error-handling',
|
|
22
|
-
description: 'Error handling patterns (error boundaries, async error handling)',
|
|
23
|
-
severity: 'warning',
|
|
24
|
-
|
|
25
|
-
async run(context) {
|
|
26
|
-
const { projectRoot, files } = context;
|
|
27
|
-
const issues = [];
|
|
28
|
-
const warnings = [];
|
|
29
|
-
const suggestions = [];
|
|
30
|
-
|
|
31
|
-
if (!files || files.length === 0) {
|
|
32
|
-
return { issues, warnings, suggestions };
|
|
33
|
-
}
|
|
34
|
-
|
|
35
|
-
// Skip if this is the pace-core repository itself
|
|
36
|
-
// Detect pace-core repository by checking if packages/core exists
|
|
37
|
-
const packagesCorePath = path.join(projectRoot, 'packages', 'core');
|
|
38
|
-
const isPaceCoreRepository = fs.existsSync(packagesCorePath);
|
|
39
|
-
|
|
40
|
-
// Check for ErrorBoundary usage in main app file
|
|
41
|
-
let hasErrorBoundary = false;
|
|
42
|
-
const mainFiles = ['main.tsx', 'main.ts', 'App.tsx', 'App.ts', 'index.tsx', 'index.ts'];
|
|
43
|
-
|
|
44
|
-
// First, specifically check the main app file for ErrorBoundary usage
|
|
45
|
-
// This must be done before the general file loop to ensure we check the actual main file
|
|
46
|
-
// Previously, the check would skip src/ files (thinking they were demo apps) and only
|
|
47
|
-
// check if ErrorBoundary appeared anywhere in the codebase. Now we specifically check
|
|
48
|
-
// the main.tsx file for proper ErrorBoundary import and JSX usage patterns.
|
|
49
|
-
if (!isPaceCoreRepository) {
|
|
50
|
-
const mainFile = mainFiles.find(file => {
|
|
51
|
-
const filePath = path.join(projectRoot, 'src', file);
|
|
52
|
-
return fs.existsSync(filePath);
|
|
53
|
-
});
|
|
54
|
-
|
|
55
|
-
if (mainFile) {
|
|
56
|
-
const mainFilePath = path.join(projectRoot, 'src', mainFile);
|
|
57
|
-
try {
|
|
58
|
-
const mainContent = fs.readFileSync(mainFilePath, 'utf8');
|
|
59
|
-
|
|
60
|
-
// Check for ErrorBoundary import from pace-core
|
|
61
|
-
// Matches: import { ErrorBoundary } from '@jmruthers/pace-core'
|
|
62
|
-
// Matches: import { ..., ErrorBoundary, ... } from '@jmruthers/pace-core'
|
|
63
|
-
// Matches: import { ErrorBoundary } from '@jmruthers/pace-core/components'
|
|
64
|
-
const hasErrorBoundaryImport = /import\s+[^'"]*ErrorBoundary[^'"]*from\s+['"]@jmruthers\/pace-core/.test(mainContent);
|
|
65
|
-
|
|
66
|
-
// Check for ErrorBoundary JSX usage
|
|
67
|
-
// Matches: <ErrorBoundary ...> or <ErrorBoundary>
|
|
68
|
-
const hasErrorBoundaryJSX = /<ErrorBoundary[\s>]/.test(mainContent);
|
|
69
|
-
|
|
70
|
-
// Check if ErrorBoundary wraps the render call or app component
|
|
71
|
-
// Pattern 1: createRoot(...).render(<ErrorBoundary ...)
|
|
72
|
-
// Pattern 2: render(<ErrorBoundary ...)
|
|
73
|
-
// Pattern 3: <ErrorBoundary ...> wrapping App component or createRoot call
|
|
74
|
-
const hasErrorBoundaryInRender = /createRoot\s*\([^)]*\)\s*\.\s*render\s*\(\s*<ErrorBoundary/.test(mainContent) ||
|
|
75
|
-
/\.render\s*\(\s*<ErrorBoundary/.test(mainContent) ||
|
|
76
|
-
/<ErrorBoundary[\s\S]{0,500}?<App[\s>]/.test(mainContent) ||
|
|
77
|
-
/<ErrorBoundary[\s\S]{0,500}?createRoot/.test(mainContent);
|
|
78
|
-
|
|
79
|
-
// ErrorBoundary is present if it's imported AND used in JSX
|
|
80
|
-
// We check both JSX usage and render wrapping to catch all valid patterns
|
|
81
|
-
if (hasErrorBoundaryImport && (hasErrorBoundaryJSX || hasErrorBoundaryInRender)) {
|
|
82
|
-
hasErrorBoundary = true;
|
|
83
|
-
}
|
|
84
|
-
} catch (error) {
|
|
85
|
-
// If we can't read the main file, continue with other checks
|
|
86
|
-
}
|
|
87
|
-
}
|
|
88
|
-
}
|
|
89
|
-
|
|
90
|
-
for (const filePath of files) {
|
|
91
|
-
try {
|
|
92
|
-
const content = fs.readFileSync(filePath, 'utf8');
|
|
93
|
-
const relativePath = getRelativePath(filePath, projectRoot);
|
|
94
|
-
const normalizedPath = relativePath.replace(/\\/g, '/');
|
|
95
|
-
const fileName = path.basename(relativePath);
|
|
96
|
-
|
|
97
|
-
// Skip root-level src directory - in pace-core repository, this is a demo/showcase app
|
|
98
|
-
// Note: We DO check packages/core/ files because error handling issues (missing try/catch, missing .catch()) are real issues that should be fixed
|
|
99
|
-
const isRootSrc = normalizedPath.startsWith('src/') && !normalizedPath.includes('packages/');
|
|
100
|
-
if (isRootSrc) {
|
|
101
|
-
continue; // Skip demo app files
|
|
102
|
-
}
|
|
103
|
-
|
|
104
|
-
// Skip scripts directory - utility scripts don't need error handling validation
|
|
105
|
-
const isScript = normalizedPath.startsWith('scripts/') || normalizedPath.includes('/scripts/');
|
|
106
|
-
if (isScript) {
|
|
107
|
-
continue; // Skip script files
|
|
108
|
-
}
|
|
109
|
-
|
|
110
|
-
// Check for unhandled promise rejections
|
|
111
|
-
const asyncFunctionPattern = /(async\s+function|const\s+\w+\s*=\s*async|export\s+async\s+function)/g;
|
|
112
|
-
let asyncMatch;
|
|
113
|
-
while ((asyncMatch = asyncFunctionPattern.exec(content)) !== null) {
|
|
114
|
-
const functionStart = asyncMatch.index;
|
|
115
|
-
const beforeAsync = content.substring(Math.max(0, functionStart - 100), functionStart);
|
|
116
|
-
const afterAsync = content.substring(functionStart, Math.min(content.length, functionStart + 1000));
|
|
117
|
-
|
|
118
|
-
// Check if function has try/catch
|
|
119
|
-
const hasTryCatch = /try\s*\{/.test(afterAsync);
|
|
120
|
-
|
|
121
|
-
// Check for await calls
|
|
122
|
-
const hasAwait = /await\s+/.test(afterAsync);
|
|
123
|
-
|
|
124
|
-
// Check if this is an exported library function (designed to throw errors for callers to handle)
|
|
125
|
-
// Look for "export" before the async function declaration
|
|
126
|
-
const isExportedLibraryFunction = /export\s+(async\s+function|function)/.test(beforeAsync + asyncMatch[0]) ||
|
|
127
|
-
asyncMatch[0].includes('export');
|
|
128
|
-
|
|
129
|
-
// Skip pace-core files - library code has different error handling patterns
|
|
130
|
-
// Exported functions are designed to throw errors for callers to handle
|
|
131
|
-
// Internal utility functions may also intentionally propagate errors
|
|
132
|
-
const isPaceCorePackage = normalizedPath.includes('packages/core/') || normalizedPath.startsWith('packages/core/');
|
|
133
|
-
|
|
134
|
-
if (hasAwait && !hasTryCatch && !isExportedLibraryFunction && !isPaceCorePackage) {
|
|
135
|
-
warnings.push({
|
|
136
|
-
type: 'unhandled-async',
|
|
137
|
-
file: relativePath,
|
|
138
|
-
line: getLineNumber(content, asyncMatch.index),
|
|
139
|
-
message: 'Async function with await calls but no try/catch error handling',
|
|
140
|
-
recommendation: 'Wrap await calls in try/catch blocks to handle errors gracefully'
|
|
141
|
-
});
|
|
142
|
-
}
|
|
143
|
-
}
|
|
144
|
-
|
|
145
|
-
// Check for .then() without .catch()
|
|
146
|
-
// Look for .then() and check if there's a .catch() later in the chain (not just immediately after)
|
|
147
|
-
const thenPattern = /\.then\s*\([^)]*\)/g;
|
|
148
|
-
let thenMatch;
|
|
149
|
-
while ((thenMatch = thenPattern.exec(content)) !== null) {
|
|
150
|
-
// Check if there's a .catch() after this .then() in the promise chain
|
|
151
|
-
// Look ahead up to 500 chars (reasonable for a promise chain)
|
|
152
|
-
const afterThen = content.substring(thenMatch.index, Math.min(content.length, thenMatch.index + 500));
|
|
153
|
-
|
|
154
|
-
// Check if there's a .catch() in the chain
|
|
155
|
-
// Also check for .then().catch() pattern
|
|
156
|
-
const hasCatch = /\.catch\s*\(/.test(afterThen);
|
|
157
|
-
|
|
158
|
-
// Check if the .then() handler has try/catch inside it (valid pattern: .then(async () => { try { ... } catch { ... } }))
|
|
159
|
-
const hasTryCatchInHandler = /\.then\s*\(\s*async\s*\([^)]*\)\s*=>\s*\{[^}]*try\s*\{/.test(afterThen);
|
|
160
|
-
|
|
161
|
-
// Also check if the .then() itself handles errors (returns error object)
|
|
162
|
-
const thenBody = thenMatch[0];
|
|
163
|
-
const handlesErrorInThen = /error|Error|catch/.test(thenBody);
|
|
164
|
-
|
|
165
|
-
// Skip pace-core files - library code has complex patterns that are hard to detect accurately
|
|
166
|
-
const isPaceCorePackage = normalizedPath.includes('packages/core/') || normalizedPath.startsWith('packages/core/');
|
|
167
|
-
|
|
168
|
-
if (!hasCatch && !handlesErrorInThen && !hasTryCatchInHandler && !isPaceCorePackage) {
|
|
169
|
-
warnings.push({
|
|
170
|
-
type: 'unhandled-promise',
|
|
171
|
-
file: relativePath,
|
|
172
|
-
line: getLineNumber(content, thenMatch.index),
|
|
173
|
-
message: 'Promise chain with .then() but no .catch() handler',
|
|
174
|
-
recommendation: 'Add .catch() handler to handle promise rejections. The .catch() can come after the .then() in the chain.'
|
|
175
|
-
});
|
|
176
|
-
}
|
|
177
|
-
}
|
|
178
|
-
|
|
179
|
-
// Check for console.error without proper error handling
|
|
180
|
-
const consoleErrorPattern = /console\.error\s*\([^)]*\)/g;
|
|
181
|
-
let consoleMatch;
|
|
182
|
-
while ((consoleMatch = consoleErrorPattern.exec(content)) !== null) {
|
|
183
|
-
// Skip console.error in comments/JSDoc (example code)
|
|
184
|
-
const beforeMatch = content.substring(Math.max(0, consoleMatch.index - 500), consoleMatch.index);
|
|
185
|
-
const afterMatch = content.substring(consoleMatch.index, Math.min(content.length, consoleMatch.index + 50));
|
|
186
|
-
|
|
187
|
-
// Get the line number to check if we're in a comment block
|
|
188
|
-
const errorLineNum = getLineNumber(content, consoleMatch.index);
|
|
189
|
-
const lines = content.split('\n');
|
|
190
|
-
const errorLine = lines[errorLineNum - 1]; // Line numbers are 1-indexed
|
|
191
|
-
|
|
192
|
-
// Check if the line starts with * (JSDoc comment block) or // (single line comment)
|
|
193
|
-
const isInCommentLine = /^\s*\*|^\s*\/\//.test(errorLine);
|
|
194
|
-
|
|
195
|
-
// Check if we're inside a /* ... */ or /** ... */ block
|
|
196
|
-
// Find the last /* or /** before this position, and check if */ comes after
|
|
197
|
-
const lastCommentStart = beforeMatch.lastIndexOf('/*');
|
|
198
|
-
const lastCommentEndBefore = beforeMatch.lastIndexOf('*/');
|
|
199
|
-
const firstCommentEndAfter = afterMatch.indexOf('*/');
|
|
200
|
-
// We're in a comment block if there's a /* before and no */ before it (or */ is after)
|
|
201
|
-
const isInCommentBlock = lastCommentStart !== -1 &&
|
|
202
|
-
(lastCommentStart > lastCommentEndBefore || firstCommentEndAfter !== -1);
|
|
203
|
-
|
|
204
|
-
// Check if it's in a comment (JSDoc example or comment block)
|
|
205
|
-
if (isInCommentLine || isInCommentBlock) {
|
|
206
|
-
continue; // Skip JSDoc examples and comment blocks
|
|
207
|
-
}
|
|
208
|
-
|
|
209
|
-
// Skip example files - these are demonstration code, not production code
|
|
210
|
-
const isExampleFile = normalizedPath.includes('/examples/') || normalizedPath.includes('Example.tsx') || normalizedPath.includes('Example.ts');
|
|
211
|
-
if (isExampleFile) {
|
|
212
|
-
continue; // Skip example files
|
|
213
|
-
}
|
|
214
|
-
|
|
215
|
-
// Skip logger utility files - these ARE the error handling mechanism
|
|
216
|
-
const isLoggerUtility = normalizedPath.includes('logger') ||
|
|
217
|
-
normalizedPath.includes('debugLogger') ||
|
|
218
|
-
normalizedPath.includes('rbac/config.ts'); // RBAC config is a logger setup
|
|
219
|
-
if (isLoggerUtility) {
|
|
220
|
-
continue; // Skip logger utilities
|
|
221
|
-
}
|
|
222
|
-
|
|
223
|
-
// Skip ESLint rule files - these are tooling, not application code
|
|
224
|
-
const isEslintRule = normalizedPath.includes('eslint-rules') || normalizedPath.includes('eslint.config');
|
|
225
|
-
if (isEslintRule) {
|
|
226
|
-
continue; // Skip ESLint rules
|
|
227
|
-
}
|
|
228
|
-
|
|
229
|
-
// Skip performance monitoring utilities - these are informational logging
|
|
230
|
-
const isPerformanceUtility = normalizedPath.includes('performance') &&
|
|
231
|
-
(normalizedPath.includes('performanceBudgets') || normalizedPath.includes('performanceBenchmark'));
|
|
232
|
-
if (isPerformanceUtility) {
|
|
233
|
-
continue; // Skip performance monitoring
|
|
234
|
-
}
|
|
235
|
-
|
|
236
|
-
// Check if it's just logging without handling
|
|
237
|
-
// Also check after the console.error to see if error state is set or error is returned
|
|
238
|
-
const afterError = content.substring(consoleMatch.index, Math.min(content.length, consoleMatch.index + 200));
|
|
239
|
-
const hasErrorHandling = beforeMatch.includes('throw') ||
|
|
240
|
-
beforeMatch.includes('return') ||
|
|
241
|
-
beforeMatch.includes('catch') ||
|
|
242
|
-
afterError.includes('throw') || // Check after as well (e.g., console.error then throw)
|
|
243
|
-
afterError.includes('setError') ||
|
|
244
|
-
afterError.includes('error =') ||
|
|
245
|
-
afterError.includes('onError') ||
|
|
246
|
-
afterError.includes('onUploadError');
|
|
247
|
-
|
|
248
|
-
if (!hasErrorHandling) {
|
|
249
|
-
suggestions.push({
|
|
250
|
-
type: 'error-logging-only',
|
|
251
|
-
file: relativePath,
|
|
252
|
-
line: getLineNumber(content, consoleMatch.index),
|
|
253
|
-
message: 'Error is logged but may not be handled properly',
|
|
254
|
-
recommendation: 'Ensure errors are properly handled (thrown, returned, or displayed to users)'
|
|
255
|
-
});
|
|
256
|
-
}
|
|
257
|
-
}
|
|
258
|
-
|
|
259
|
-
// Check for missing error states in components using pace-core hooks
|
|
260
|
-
// Only check React component files
|
|
261
|
-
if (filePath.match(/\.(tsx|jsx)$/)) {
|
|
262
|
-
const paceCoreHooks = ['useUnifiedAuth', 'useOrganisations', 'useEvents', 'useSecureSupabase'];
|
|
263
|
-
paceCoreHooks.forEach(hookName => {
|
|
264
|
-
if (content.includes(hookName)) {
|
|
265
|
-
const hookPattern = new RegExp(`const\\s+[^=]+=\\s+${hookName}\\s*\\(`, 'g');
|
|
266
|
-
let hookMatch;
|
|
267
|
-
while ((hookMatch = hookPattern.exec(content)) !== null) {
|
|
268
|
-
// Check the entire component, not just 500 chars after hook
|
|
269
|
-
// React's Rules of Hooks require all hooks to be called before conditional returns,
|
|
270
|
-
// so error handling may occur later in the component
|
|
271
|
-
const hookLine = getLineNumber(content, hookMatch.index);
|
|
272
|
-
const lines = content.split('\n');
|
|
273
|
-
const hookLineIndex = hookLine - 1;
|
|
274
|
-
|
|
275
|
-
// Get the rest of the component after this hook
|
|
276
|
-
const afterHookContent = lines.slice(hookLineIndex).join('\n');
|
|
277
|
-
|
|
278
|
-
// Check if error is destructured from the hook
|
|
279
|
-
const hookCallLine = lines[hookLineIndex];
|
|
280
|
-
const hasErrorDestructured = /(error|Error|authError|orgError)/.test(hookCallLine);
|
|
281
|
-
|
|
282
|
-
// For useSecureSupabase, check for null checks (it returns null on error)
|
|
283
|
-
const isSecureSupabase = hookName === 'useSecureSupabase';
|
|
284
|
-
const hasNullCheck = isSecureSupabase && /secureSupabase\s*===?\s*null|!secureSupabase/.test(afterHookContent);
|
|
285
|
-
|
|
286
|
-
// Check for error handling patterns in the entire component:
|
|
287
|
-
// 1. Component-level error checks with early returns: if (error) return <ErrorUI />
|
|
288
|
-
// 2. useEffect error handlers: useEffect(() => { if (error) ... }, [error])
|
|
289
|
-
// 3. Null checks for useSecureSupabase: if (secureSupabase === null) ...
|
|
290
|
-
// 4. Error passed to error handling utilities
|
|
291
|
-
|
|
292
|
-
const hasComponentLevelErrorCheck = /if\s*\(\s*(error|authError|orgError|rbacError)/.test(afterHookContent);
|
|
293
|
-
const hasUseEffectErrorHandler = /useEffect\s*\([^)]*\([^)]*\)\s*=>\s*\{[^}]*\b(error|authError|orgError|rbacError)\b[^}]*\}/.test(afterHookContent);
|
|
294
|
-
const hasErrorInDeps = /useEffect\s*\([^)]*,\s*\[[^\]]*\b(error|authError|orgError|rbacError)\b/.test(afterHookContent);
|
|
295
|
-
const hasErrorHandling = /if\s*\(\s*(error|authError|orgError|rbacError)|(error|authError|orgError|rbacError)\s*\?|catch/.test(afterHookContent);
|
|
296
|
-
const hasErrorUtility = /handleSupabaseError|handleError|toast.*error|showError/.test(afterHookContent);
|
|
297
|
-
|
|
298
|
-
// Only flag if error is destructured but not handled anywhere
|
|
299
|
-
if (hasErrorDestructured && !hasComponentLevelErrorCheck && !hasUseEffectErrorHandler &&
|
|
300
|
-
!hasErrorInDeps && !hasErrorHandling && !hasErrorUtility && !hasNullCheck) {
|
|
301
|
-
warnings.push({
|
|
302
|
-
type: 'unhandled-hook-error',
|
|
303
|
-
file: relativePath,
|
|
304
|
-
line: hookLine,
|
|
305
|
-
message: `${hookName} may return an error that is not handled`,
|
|
306
|
-
recommendation: 'Check for error state and handle it appropriately. You can handle errors via: (1) Component-level checks after all hooks: if (error) return <ErrorUI />, (2) useEffect hooks that monitor error states, or (3) For useSecureSupabase, null checks: if (secureSupabase === null) ...'
|
|
307
|
-
});
|
|
308
|
-
}
|
|
309
|
-
}
|
|
310
|
-
}
|
|
311
|
-
});
|
|
312
|
-
}
|
|
313
|
-
} catch (error) {
|
|
314
|
-
// Skip files with errors
|
|
315
|
-
}
|
|
316
|
-
}
|
|
317
|
-
|
|
318
|
-
// Check if ErrorBoundary is used in main app file
|
|
319
|
-
// Skip this check if this is the pace-core repository (root src/ is a demo app)
|
|
320
|
-
if (!hasErrorBoundary && !isPaceCoreRepository) {
|
|
321
|
-
const mainFile = mainFiles.find(file => {
|
|
322
|
-
const filePath = path.join(projectRoot, 'src', file);
|
|
323
|
-
return fs.existsSync(filePath);
|
|
324
|
-
});
|
|
325
|
-
|
|
326
|
-
if (mainFile) {
|
|
327
|
-
suggestions.push({
|
|
328
|
-
type: 'missing-error-boundary',
|
|
329
|
-
file: `src/${mainFile}`,
|
|
330
|
-
message: 'No ErrorBoundary found in main app file',
|
|
331
|
-
recommendation: 'Wrap your app with ErrorBoundary from @jmruthers/pace-core to catch and handle React errors gracefully'
|
|
332
|
-
});
|
|
333
|
-
}
|
|
334
|
-
}
|
|
335
|
-
|
|
336
|
-
return { issues, warnings, suggestions };
|
|
337
|
-
}
|
|
338
|
-
};
|
|
339
|
-
|
|
340
|
-
module.exports = errorHandlingCheck;
|
|
@@ -1,172 +0,0 @@
|
|
|
1
|
-
#!/usr/bin/env node
|
|
2
|
-
|
|
3
|
-
/**
|
|
4
|
-
* Form Validation Check Module
|
|
5
|
-
* @package @jmruthers/pace-core
|
|
6
|
-
* @module Audit/Checks/Forms
|
|
7
|
-
*
|
|
8
|
-
* Checks for:
|
|
9
|
-
* - Missing form validation
|
|
10
|
-
* - Incorrect useZodForm usage
|
|
11
|
-
* - Missing error messages
|
|
12
|
-
* - Form submission without loading states
|
|
13
|
-
*/
|
|
14
|
-
|
|
15
|
-
const fs = require('fs');
|
|
16
|
-
const { getRelativePath, getLineNumber } = require('../utils.cjs');
|
|
17
|
-
|
|
18
|
-
const formsCheck = {
|
|
19
|
-
name: 'forms',
|
|
20
|
-
description: 'Form validation patterns (useZodForm, error handling)',
|
|
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 pace-core package files - forms check is for consuming applications, not the library itself
|
|
45
|
-
// Note: Library components (like Form.tsx, LoginForm.tsx, Select.tsx) ARE the Form components
|
|
46
|
-
// They don't need to use themselves - they provide the form functionality
|
|
47
|
-
const isPaceCorePackage = normalizedPath.includes('packages/core/') || normalizedPath.startsWith('packages/core/');
|
|
48
|
-
if (isPaceCorePackage) {
|
|
49
|
-
continue; // Skip library files (including examples)
|
|
50
|
-
}
|
|
51
|
-
|
|
52
|
-
// Skip root-level src directory - in pace-core repository, this is a demo/showcase app
|
|
53
|
-
const isRootSrc = normalizedPath.startsWith('src/') && !normalizedPath.includes('packages/');
|
|
54
|
-
if (isRootSrc) {
|
|
55
|
-
continue; // Skip demo app files
|
|
56
|
-
}
|
|
57
|
-
|
|
58
|
-
// Skip scripts directory - utility scripts don't need form validation
|
|
59
|
-
const isScript = normalizedPath.startsWith('scripts/') || normalizedPath.includes('/scripts/');
|
|
60
|
-
if (isScript) {
|
|
61
|
-
continue; // Skip script files
|
|
62
|
-
}
|
|
63
|
-
|
|
64
|
-
// Check for form elements
|
|
65
|
-
const hasForm = /<form|Form|useZodForm/.test(content);
|
|
66
|
-
if (!hasForm) {
|
|
67
|
-
continue;
|
|
68
|
-
}
|
|
69
|
-
|
|
70
|
-
// Check for useZodForm usage
|
|
71
|
-
if (content.includes('useZodForm')) {
|
|
72
|
-
const zodFormPattern = /const\s+[^=]+=\s+useZodForm\s*\(/g;
|
|
73
|
-
let formMatch;
|
|
74
|
-
while ((formMatch = zodFormPattern.exec(content)) !== null) {
|
|
75
|
-
const afterForm = content.substring(formMatch.index, Math.min(content.length, formMatch.index + 500));
|
|
76
|
-
|
|
77
|
-
// Check if schema is provided
|
|
78
|
-
if (!afterForm.includes('schema:') && !afterForm.includes('schema =')) {
|
|
79
|
-
warnings.push({
|
|
80
|
-
type: 'missing-form-schema',
|
|
81
|
-
file: relativePath,
|
|
82
|
-
line: getLineNumber(content, formMatch.index),
|
|
83
|
-
message: 'useZodForm called without schema',
|
|
84
|
-
recommendation: 'Provide a Zod schema to useZodForm for form validation'
|
|
85
|
-
});
|
|
86
|
-
}
|
|
87
|
-
|
|
88
|
-
// Check if form errors are displayed
|
|
89
|
-
const hasErrorDisplay = /formState\.errors|errors\[|\.error/.test(content);
|
|
90
|
-
if (!hasErrorDisplay) {
|
|
91
|
-
suggestions.push({
|
|
92
|
-
type: 'missing-form-errors',
|
|
93
|
-
file: relativePath,
|
|
94
|
-
line: getLineNumber(content, formMatch.index),
|
|
95
|
-
message: 'Form may not be displaying validation errors',
|
|
96
|
-
recommendation: 'Display form errors to users using formState.errors or FormField error prop'
|
|
97
|
-
});
|
|
98
|
-
}
|
|
99
|
-
}
|
|
100
|
-
}
|
|
101
|
-
|
|
102
|
-
// Check for form submission without loading state
|
|
103
|
-
const onSubmitPattern = /onSubmit\s*=\s*\{[^}]*async/g;
|
|
104
|
-
let submitMatch;
|
|
105
|
-
while ((submitMatch = onSubmitPattern.exec(content)) !== null) {
|
|
106
|
-
const afterSubmit = content.substring(submitMatch.index, Math.min(content.length, submitMatch.index + 1000));
|
|
107
|
-
|
|
108
|
-
// Check if there's a loading state
|
|
109
|
-
const hasLoadingState = /isLoading|loading|isSubmitting|submitting/.test(afterSubmit);
|
|
110
|
-
const hasDisabled = /disabled\s*=\s*\{/.test(content);
|
|
111
|
-
|
|
112
|
-
if (!hasLoadingState && !hasDisabled) {
|
|
113
|
-
suggestions.push({
|
|
114
|
-
type: 'missing-submit-loading',
|
|
115
|
-
file: relativePath,
|
|
116
|
-
line: getLineNumber(content, submitMatch.index),
|
|
117
|
-
message: 'Form submission without loading state',
|
|
118
|
-
recommendation: 'Add loading state during form submission to prevent double-submission and provide user feedback'
|
|
119
|
-
});
|
|
120
|
-
}
|
|
121
|
-
}
|
|
122
|
-
|
|
123
|
-
// Check for native form elements that should use pace-core Form
|
|
124
|
-
const nativeFormPattern = /<form[^>]*>/g;
|
|
125
|
-
let nativeMatch;
|
|
126
|
-
while ((nativeMatch = nativeFormPattern.exec(content)) !== null) {
|
|
127
|
-
const beforeMatch = content.substring(Math.max(0, nativeMatch.index - 100), nativeMatch.index);
|
|
128
|
-
const usesPaceCoreForm = beforeMatch.includes('from \'@jmruthers/pace-core\'') ||
|
|
129
|
-
content.includes('<Form');
|
|
130
|
-
|
|
131
|
-
if (!usesPaceCoreForm) {
|
|
132
|
-
suggestions.push({
|
|
133
|
-
type: 'native-form-element',
|
|
134
|
-
file: relativePath,
|
|
135
|
-
line: getLineNumber(content, nativeMatch.index),
|
|
136
|
-
message: 'Native <form> element detected',
|
|
137
|
-
recommendation: 'Use Form component from @jmruthers/pace-core for consistent styling and validation'
|
|
138
|
-
});
|
|
139
|
-
}
|
|
140
|
-
}
|
|
141
|
-
|
|
142
|
-
// Check for input elements without validation
|
|
143
|
-
const inputPattern = /<input[^>]*>/g;
|
|
144
|
-
let inputMatch;
|
|
145
|
-
while ((inputMatch = inputPattern.exec(content)) !== null) {
|
|
146
|
-
const inputTag = inputMatch[0];
|
|
147
|
-
const hasFormField = content.substring(Math.max(0, inputMatch.index - 200), inputMatch.index).includes('FormField');
|
|
148
|
-
const hasValidation = inputTag.includes('required') ||
|
|
149
|
-
inputTag.includes('pattern') ||
|
|
150
|
-
content.substring(Math.max(0, inputMatch.index - 200), inputMatch.index).includes('register');
|
|
151
|
-
|
|
152
|
-
if (!hasFormField && !hasValidation && !inputTag.includes('type="hidden"')) {
|
|
153
|
-
suggestions.push({
|
|
154
|
-
type: 'unvalidated-input',
|
|
155
|
-
file: relativePath,
|
|
156
|
-
line: getLineNumber(content, inputMatch.index),
|
|
157
|
-
message: 'Input element without validation',
|
|
158
|
-
recommendation: 'Use FormField from @jmruthers/pace-core or add validation to form inputs'
|
|
159
|
-
});
|
|
160
|
-
}
|
|
161
|
-
}
|
|
162
|
-
|
|
163
|
-
} catch (error) {
|
|
164
|
-
// Skip files with errors
|
|
165
|
-
}
|
|
166
|
-
}
|
|
167
|
-
|
|
168
|
-
return { issues, warnings, suggestions };
|
|
169
|
-
}
|
|
170
|
-
};
|
|
171
|
-
|
|
172
|
-
module.exports = formsCheck;
|
|
@@ -1,68 +0,0 @@
|
|
|
1
|
-
#!/usr/bin/env node
|
|
2
|
-
|
|
3
|
-
/**
|
|
4
|
-
* Heuristic Checks Module
|
|
5
|
-
* @package @jmruthers/pace-core
|
|
6
|
-
* @module Audit/Checks/Heuristics
|
|
7
|
-
*
|
|
8
|
-
* Code quality heuristics including:
|
|
9
|
-
* - Large files
|
|
10
|
-
* - God objects (files with many exports)
|
|
11
|
-
*/
|
|
12
|
-
|
|
13
|
-
const fs = require('fs');
|
|
14
|
-
const path = require('path');
|
|
15
|
-
|
|
16
|
-
const heuristicsCheck = {
|
|
17
|
-
name: 'heuristics',
|
|
18
|
-
description: 'Code quality heuristics (large files, god objects)',
|
|
19
|
-
severity: 'suggestion',
|
|
20
|
-
|
|
21
|
-
async run(context) {
|
|
22
|
-
const { projectRoot, files } = context;
|
|
23
|
-
const suggestions = [];
|
|
24
|
-
|
|
25
|
-
if (!files || files.length === 0) {
|
|
26
|
-
return { issues: [], warnings: [], suggestions: [] };
|
|
27
|
-
}
|
|
28
|
-
|
|
29
|
-
const maxLines = 1000;
|
|
30
|
-
|
|
31
|
-
// Check for large files
|
|
32
|
-
for (const filePath of files) {
|
|
33
|
-
try {
|
|
34
|
-
const content = fs.readFileSync(filePath, 'utf8');
|
|
35
|
-
const lines = content.split('\n').length;
|
|
36
|
-
|
|
37
|
-
if (lines > maxLines) {
|
|
38
|
-
const relativePath = path.relative(projectRoot, filePath);
|
|
39
|
-
suggestions.push({
|
|
40
|
-
type: 'large-file',
|
|
41
|
-
file: relativePath,
|
|
42
|
-
message: `File has ${lines} lines, consider splitting into smaller modules`,
|
|
43
|
-
recommendation: `Split this file into smaller, focused modules (target: <${maxLines} lines)`
|
|
44
|
-
});
|
|
45
|
-
}
|
|
46
|
-
|
|
47
|
-
// Check for god objects (files with many exports)
|
|
48
|
-
const exportCount = (content.match(/export\s+(const|function|class|interface|type)/g) || []).length;
|
|
49
|
-
|
|
50
|
-
if (exportCount > 10) {
|
|
51
|
-
const relativePath = path.relative(projectRoot, filePath);
|
|
52
|
-
suggestions.push({
|
|
53
|
-
type: 'god-object',
|
|
54
|
-
file: relativePath,
|
|
55
|
-
message: `File exports ${exportCount} items, consider splitting into smaller modules`,
|
|
56
|
-
recommendation: `Split this file into smaller modules, each with a focused responsibility (target: <10 exports per file)`
|
|
57
|
-
});
|
|
58
|
-
}
|
|
59
|
-
} catch (error) {
|
|
60
|
-
// Skip files we can't read
|
|
61
|
-
}
|
|
62
|
-
}
|
|
63
|
-
|
|
64
|
-
return { issues: [], warnings: [], suggestions };
|
|
65
|
-
}
|
|
66
|
-
};
|
|
67
|
-
|
|
68
|
-
module.exports = heuristicsCheck;
|