@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
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Main entry point for pace-core ESLint rules
|
|
3
|
+
* @package @jmruthers/pace-core
|
|
4
|
+
* @module ESLintRules
|
|
5
|
+
*
|
|
6
|
+
* This module exports all pace-core ESLint rules organized by standards.
|
|
7
|
+
* Rules are organized to match the 10-file standards structure.
|
|
8
|
+
*
|
|
9
|
+
* Reference: packages/core/docs/standards/README.md
|
|
10
|
+
*/
|
|
11
|
+
|
|
12
|
+
const paceCoreComplianceRules = require('./rules/01-pace-core-compliance.cjs');
|
|
13
|
+
const codeQualityRules = require('./rules/04-code-quality.cjs');
|
|
14
|
+
const stylingRules = require('./rules/05-styling.cjs');
|
|
15
|
+
const securityRbacRules = require('./rules/06-security-rbac.cjs');
|
|
16
|
+
const apiTechStackRules = require('./rules/07-api-tech-stack.cjs');
|
|
17
|
+
const testingRules = require('./rules/08-testing.cjs');
|
|
18
|
+
|
|
19
|
+
module.exports = {
|
|
20
|
+
rules: {
|
|
21
|
+
// Standard 1: pace-core Compliance
|
|
22
|
+
...paceCoreComplianceRules.rules,
|
|
23
|
+
// Standard 4: Code Quality
|
|
24
|
+
...codeQualityRules.rules,
|
|
25
|
+
// Standard 5: Styling
|
|
26
|
+
...stylingRules.rules,
|
|
27
|
+
// Standard 6: Security & RBAC
|
|
28
|
+
...securityRbacRules.rules,
|
|
29
|
+
// Standard 7: API & Tech Stack
|
|
30
|
+
...apiTechStackRules.rules,
|
|
31
|
+
// Standard 8: Testing
|
|
32
|
+
...testingRules.rules,
|
|
33
|
+
}
|
|
34
|
+
};
|
|
35
|
+
|
|
@@ -1,159 +1,25 @@
|
|
|
1
1
|
/**
|
|
2
|
-
*
|
|
2
|
+
* pace-core Compliance Rules (Standard 1)
|
|
3
3
|
* @package @jmruthers/pace-core
|
|
4
|
-
* @module ESLintRules/pace-core-compliance
|
|
5
|
-
* @since 1.0.0
|
|
4
|
+
* @module ESLintRules/rules/pace-core-compliance
|
|
6
5
|
*
|
|
7
|
-
*
|
|
8
|
-
*
|
|
6
|
+
* Enforces pace-core usage patterns from Standard 1:
|
|
7
|
+
* - Use pace-core components instead of native HTML or custom implementations
|
|
8
|
+
* - Use pace-core hooks instead of custom hooks
|
|
9
|
+
* - Use pace-core utilities instead of custom utilities
|
|
10
|
+
* - Block restricted imports (libraries wrapped by pace-core)
|
|
11
|
+
* - Prefer pace-core Form component
|
|
12
|
+
* - Prevent component duplication
|
|
13
|
+
*
|
|
14
|
+
* Reference: packages/core/docs/standards/1-pace-core-compliance-standards.md
|
|
9
15
|
*/
|
|
10
16
|
|
|
11
|
-
const fs = require('fs');
|
|
12
17
|
const path = require('path');
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
let manifestData = null;
|
|
16
|
-
try {
|
|
17
|
-
const manifestPath = path.join(__dirname, '../../core-usage-manifest.json');
|
|
18
|
-
if (fs.existsSync(manifestPath)) {
|
|
19
|
-
manifestData = JSON.parse(fs.readFileSync(manifestPath, 'utf8'));
|
|
20
|
-
}
|
|
21
|
-
} catch (error) {
|
|
22
|
-
// If manifest can't be loaded, rules will use hardcoded defaults
|
|
23
|
-
console.warn('Warning: Could not load core-usage-manifest.json, using defaults');
|
|
24
|
-
}
|
|
25
|
-
|
|
26
|
-
// Get restricted imports from manifest or use defaults
|
|
27
|
-
const getRestrictedImports = () => {
|
|
28
|
-
if (manifestData && manifestData.restrictedImports) {
|
|
29
|
-
return manifestData.restrictedImports;
|
|
30
|
-
}
|
|
31
|
-
// Fallback defaults
|
|
32
|
-
return [
|
|
33
|
-
{ module: '@radix-ui/react-avatar', reason: 'Use Avatar component from pace-core instead' },
|
|
34
|
-
{ module: '@radix-ui/react-checkbox', reason: 'Use Checkbox component from pace-core instead' },
|
|
35
|
-
{ module: '@radix-ui/react-dialog', reason: 'Use Dialog component from pace-core instead' },
|
|
36
|
-
{ module: '@radix-ui/react-label', reason: 'Use Label component from pace-core instead' },
|
|
37
|
-
{ module: '@radix-ui/react-slot', reason: 'Use Button component from pace-core which handles slot composition' },
|
|
38
|
-
{ module: '@radix-ui/react-switch', reason: 'Use Switch component from pace-core instead' },
|
|
39
|
-
{ module: '@radix-ui/react-tabs', reason: 'Use Tabs component from pace-core instead' },
|
|
40
|
-
{ module: '@radix-ui/react-toast', reason: 'Use Toast component and useToast hook from pace-core instead' },
|
|
41
|
-
{ module: '@radix-ui/react-tooltip', reason: 'Use Tooltip component from pace-core instead' },
|
|
42
|
-
{ module: 'react-day-picker', reason: 'Use Calendar component from pace-core instead' },
|
|
43
|
-
{ module: '@tanstack/react-table', reason: 'Use DataTable component and related hooks from pace-core instead. DataTable wraps and standardizes table functionality' },
|
|
44
|
-
{ module: 'react-hook-form', reason: 'Use Form component and useZodForm hook from pace-core instead' },
|
|
45
|
-
{ module: 'zod', reason: 'Use validation utilities and schemas from pace-core instead. pace-core provides standardized validation helpers' }
|
|
46
|
-
];
|
|
47
|
-
};
|
|
48
|
-
|
|
49
|
-
// Get pace-core components from manifest or use defaults
|
|
50
|
-
const getPaceCoreComponents = () => {
|
|
51
|
-
if (manifestData && manifestData.components) {
|
|
52
|
-
return manifestData.components;
|
|
53
|
-
}
|
|
54
|
-
return ['Button', 'Card', 'Dialog', 'Input', 'Form', 'Select', 'Alert', 'Badge', 'Checkbox', 'Switch', 'Textarea', 'Label', 'Table', 'DataTable', 'Toast', 'Tooltip', 'Tabs', 'Calendar', 'Avatar', 'Progress'];
|
|
55
|
-
};
|
|
56
|
-
|
|
57
|
-
// Get pace-core hooks from manifest or use defaults
|
|
58
|
-
const getPaceCoreHooks = () => {
|
|
59
|
-
if (manifestData && manifestData.hooks) {
|
|
60
|
-
return manifestData.hooks;
|
|
61
|
-
}
|
|
62
|
-
return ['useToast', 'useDebounce', 'useUnifiedAuth', 'useEvents', 'useOrganisations', 'useFileReference', 'useStorage', 'useZodForm', 'useRBAC', 'usePermissions'];
|
|
63
|
-
};
|
|
64
|
-
|
|
65
|
-
// Get pace-core utils from manifest or use defaults
|
|
66
|
-
const getPaceCoreUtils = () => {
|
|
67
|
-
if (manifestData && manifestData.utils) {
|
|
68
|
-
return manifestData.utils;
|
|
69
|
-
}
|
|
70
|
-
return ['formatDate', 'formatCurrency', 'formatNumber', 'formatTime', 'formatDateTime', 'cn', 'validateUserInput', 'sanitizeUserInput', 'hasPermission', 'getAppConfig'];
|
|
71
|
-
};
|
|
18
|
+
const { getPaceCoreComponents, getPaceCoreHooks, getPaceCoreUtils, getRestrictedImports } = require('../utils/manifest-loader.cjs');
|
|
19
|
+
const { getPaceCoreAlternative, isPaceCoreSourceFile } = require('../utils/helpers.cjs');
|
|
72
20
|
|
|
73
21
|
module.exports = {
|
|
74
22
|
rules: {
|
|
75
|
-
/**
|
|
76
|
-
* Block direct imports of libraries wrapped by pace-core
|
|
77
|
-
*/
|
|
78
|
-
'no-restricted-imports': {
|
|
79
|
-
meta: {
|
|
80
|
-
type: 'problem',
|
|
81
|
-
docs: {
|
|
82
|
-
description: 'Disallow direct imports of libraries that pace-core wraps',
|
|
83
|
-
category: 'Best Practices',
|
|
84
|
-
recommended: true
|
|
85
|
-
},
|
|
86
|
-
fixable: 'code',
|
|
87
|
-
hasSuggestions: true,
|
|
88
|
-
messages: {
|
|
89
|
-
restrictedImport: '{{message}} Import from {{alternative}} instead.',
|
|
90
|
-
restrictedImportWithReason: '{{message}} {{reason}}'
|
|
91
|
-
}
|
|
92
|
-
},
|
|
93
|
-
create(context) {
|
|
94
|
-
const restrictedImports = getRestrictedImports();
|
|
95
|
-
const restrictedModules = restrictedImports.map(imp => imp.module);
|
|
96
|
-
|
|
97
|
-
// Also catch @radix-ui/* patterns
|
|
98
|
-
const radixPattern = /^@radix-ui\//;
|
|
99
|
-
|
|
100
|
-
return {
|
|
101
|
-
ImportDeclaration(node) {
|
|
102
|
-
const importSource = node.source.value;
|
|
103
|
-
|
|
104
|
-
// Check exact matches
|
|
105
|
-
const restricted = restrictedImports.find(imp => imp.module === importSource);
|
|
106
|
-
if (restricted) {
|
|
107
|
-
context.report({
|
|
108
|
-
node: node.source,
|
|
109
|
-
messageId: 'restrictedImportWithReason',
|
|
110
|
-
data: {
|
|
111
|
-
message: `Direct import of '${importSource}' is not allowed.`,
|
|
112
|
-
reason: restricted.reason
|
|
113
|
-
},
|
|
114
|
-
suggest: [{
|
|
115
|
-
desc: `Use pace-core alternative: ${restricted.reason}`,
|
|
116
|
-
fix(fixer) {
|
|
117
|
-
// Suggest importing from pace-core instead
|
|
118
|
-
const paceCoreAlternative = getPaceCoreAlternative(importSource);
|
|
119
|
-
if (paceCoreAlternative) {
|
|
120
|
-
return fixer.replaceText(
|
|
121
|
-
node.source,
|
|
122
|
-
`'@jmruthers/pace-core${paceCoreAlternative}'`
|
|
123
|
-
);
|
|
124
|
-
}
|
|
125
|
-
return null;
|
|
126
|
-
}
|
|
127
|
-
}]
|
|
128
|
-
});
|
|
129
|
-
return;
|
|
130
|
-
}
|
|
131
|
-
|
|
132
|
-
// Check @radix-ui/* pattern
|
|
133
|
-
if (radixPattern.test(importSource) && !restrictedModules.includes(importSource)) {
|
|
134
|
-
context.report({
|
|
135
|
-
node: node.source,
|
|
136
|
-
messageId: 'restrictedImport',
|
|
137
|
-
data: {
|
|
138
|
-
message: `Direct import of '${importSource}' is not allowed.`,
|
|
139
|
-
alternative: '@jmruthers/pace-core'
|
|
140
|
-
},
|
|
141
|
-
suggest: [{
|
|
142
|
-
desc: 'Use pace-core component instead',
|
|
143
|
-
fix(fixer) {
|
|
144
|
-
return fixer.replaceText(
|
|
145
|
-
node.source,
|
|
146
|
-
"'@jmruthers/pace-core'"
|
|
147
|
-
);
|
|
148
|
-
}
|
|
149
|
-
}]
|
|
150
|
-
});
|
|
151
|
-
}
|
|
152
|
-
}
|
|
153
|
-
};
|
|
154
|
-
}
|
|
155
|
-
},
|
|
156
|
-
|
|
157
23
|
/**
|
|
158
24
|
* Prefer pace-core components over native HTML elements or custom implementations
|
|
159
25
|
*/
|
|
@@ -163,7 +29,8 @@ module.exports = {
|
|
|
163
29
|
docs: {
|
|
164
30
|
description: 'Suggest using pace-core components instead of native HTML elements',
|
|
165
31
|
category: 'Best Practices',
|
|
166
|
-
recommended: true
|
|
32
|
+
recommended: true,
|
|
33
|
+
url: 'https://github.com/jmruthers/pace-core/blob/main/packages/core/docs/standards/1-pace-core-compliance-standards.md'
|
|
167
34
|
},
|
|
168
35
|
hasSuggestions: true,
|
|
169
36
|
messages: {
|
|
@@ -175,6 +42,13 @@ module.exports = {
|
|
|
175
42
|
}
|
|
176
43
|
},
|
|
177
44
|
create(context) {
|
|
45
|
+
const filename = context.getFilename();
|
|
46
|
+
|
|
47
|
+
// Exclude pace-core source files - these rules are for consuming apps
|
|
48
|
+
if (isPaceCoreSourceFile(filename)) {
|
|
49
|
+
return {};
|
|
50
|
+
}
|
|
51
|
+
|
|
178
52
|
const paceCoreComponents = getPaceCoreComponents();
|
|
179
53
|
|
|
180
54
|
return {
|
|
@@ -183,6 +57,16 @@ module.exports = {
|
|
|
183
57
|
|
|
184
58
|
if (!elementName) return;
|
|
185
59
|
|
|
60
|
+
// Only flag lowercase native HTML elements, not capitalized components
|
|
61
|
+
// Native HTML: <button>, <input>, <label>, <textarea>
|
|
62
|
+
// Components: <Button>, <Input>, <Label>, <Textarea>
|
|
63
|
+
const isNativeHTMLElement = elementName === elementName.toLowerCase();
|
|
64
|
+
|
|
65
|
+
if (!isNativeHTMLElement) {
|
|
66
|
+
// This is a capitalized component, not a native HTML element
|
|
67
|
+
return;
|
|
68
|
+
}
|
|
69
|
+
|
|
186
70
|
// Check for native HTML elements that have pace-core alternatives
|
|
187
71
|
const nativeToPaceCore = {
|
|
188
72
|
'button': 'Button',
|
|
@@ -191,8 +75,8 @@ module.exports = {
|
|
|
191
75
|
'label': 'Label'
|
|
192
76
|
};
|
|
193
77
|
|
|
194
|
-
if (nativeToPaceCore[elementName
|
|
195
|
-
const paceCoreComponent = nativeToPaceCore[elementName
|
|
78
|
+
if (nativeToPaceCore[elementName]) {
|
|
79
|
+
const paceCoreComponent = nativeToPaceCore[elementName];
|
|
196
80
|
if (paceCoreComponents.includes(paceCoreComponent)) {
|
|
197
81
|
context.report({
|
|
198
82
|
node,
|
|
@@ -221,13 +105,21 @@ module.exports = {
|
|
|
221
105
|
docs: {
|
|
222
106
|
description: 'Suggest using pace-core hooks instead of custom implementations',
|
|
223
107
|
category: 'Best Practices',
|
|
224
|
-
recommended: true
|
|
108
|
+
recommended: true,
|
|
109
|
+
url: 'https://github.com/jmruthers/pace-core/blob/main/packages/core/docs/standards/1-pace-core-compliance-standards.md'
|
|
225
110
|
},
|
|
226
111
|
messages: {
|
|
227
112
|
preferPaceCoreHook: "Consider using '{{hook}}' from '@jmruthers/pace-core' instead of custom hook '{{customHook}}'"
|
|
228
113
|
}
|
|
229
114
|
},
|
|
230
115
|
create(context) {
|
|
116
|
+
const filename = context.getFilename();
|
|
117
|
+
|
|
118
|
+
// Exclude pace-core source files - these rules are for consuming apps
|
|
119
|
+
if (isPaceCoreSourceFile(filename)) {
|
|
120
|
+
return {};
|
|
121
|
+
}
|
|
122
|
+
|
|
231
123
|
const paceCoreHooks = getPaceCoreHooks();
|
|
232
124
|
const hookPatterns = {
|
|
233
125
|
'useToast': ['useToast', 'useNotification', 'useSnackbar'],
|
|
@@ -275,32 +167,67 @@ module.exports = {
|
|
|
275
167
|
docs: {
|
|
276
168
|
description: 'Suggest using pace-core utilities instead of custom implementations',
|
|
277
169
|
category: 'Best Practices',
|
|
278
|
-
recommended: true
|
|
170
|
+
recommended: true,
|
|
171
|
+
url: 'https://github.com/jmruthers/pace-core/blob/main/packages/core/docs/standards/1-pace-core-compliance-standards.md'
|
|
279
172
|
},
|
|
280
173
|
messages: {
|
|
281
174
|
preferPaceCoreUtil: "Consider using '{{util}}' from '@jmruthers/pace-core' instead of custom function '{{customUtil}}'"
|
|
282
175
|
}
|
|
283
176
|
},
|
|
284
177
|
create(context) {
|
|
178
|
+
const filename = context.getFilename();
|
|
179
|
+
|
|
180
|
+
// Exclude pace-core source files - these rules are for consuming apps
|
|
181
|
+
if (isPaceCoreSourceFile(filename)) {
|
|
182
|
+
return {};
|
|
183
|
+
}
|
|
184
|
+
|
|
285
185
|
const paceCoreUtils = getPaceCoreUtils();
|
|
286
186
|
const utilPatterns = {
|
|
287
187
|
'formatDate': ['formatDate', 'formatDateTime', 'dateFormat'],
|
|
288
188
|
'formatCurrency': ['formatCurrency', 'formatMoney', 'currencyFormat'],
|
|
289
189
|
'formatNumber': ['formatNumber', 'numberFormat'],
|
|
290
190
|
'cn': ['cn', 'classNames', 'clsx', 'mergeClasses'],
|
|
291
|
-
'validateUserInput': ['
|
|
191
|
+
'validateUserInput': ['validateInput', 'validateUser', 'validateUserInput'],
|
|
292
192
|
'sanitizeUserInput': ['sanitize', 'sanitizeInput', 'sanitizeUser']
|
|
293
193
|
};
|
|
294
194
|
|
|
195
|
+
// Patterns that should NOT trigger validateUserInput warnings
|
|
196
|
+
// These are for API/config validation, not user input validation
|
|
197
|
+
const excludePatterns = [
|
|
198
|
+
'validateApi',
|
|
199
|
+
'validateRequest',
|
|
200
|
+
'validateConfig',
|
|
201
|
+
'validateKey',
|
|
202
|
+
'validateToken',
|
|
203
|
+
'validateAuth',
|
|
204
|
+
'validateRateLimit',
|
|
205
|
+
'validatePermission',
|
|
206
|
+
'validateAccess'
|
|
207
|
+
];
|
|
208
|
+
|
|
295
209
|
return {
|
|
296
210
|
FunctionDeclaration(node) {
|
|
297
211
|
const functionName = node.id?.name;
|
|
298
212
|
if (!functionName) return;
|
|
299
213
|
|
|
214
|
+
// Skip if function name matches exclude patterns (API/config validation, not user input)
|
|
215
|
+
const lowerName = functionName.toLowerCase();
|
|
216
|
+
if (excludePatterns.some(pattern => lowerName.includes(pattern.toLowerCase()))) {
|
|
217
|
+
return;
|
|
218
|
+
}
|
|
219
|
+
|
|
300
220
|
// Check if this looks like a util that pace-core provides
|
|
301
221
|
for (const [paceCoreUtil, patterns] of Object.entries(utilPatterns)) {
|
|
302
222
|
if (paceCoreUtils.includes(paceCoreUtil)) {
|
|
303
223
|
for (const pattern of patterns) {
|
|
224
|
+
// Only match if the pattern is a significant part of the function name
|
|
225
|
+
// Don't match generic "validate" - it's too broad
|
|
226
|
+
if (paceCoreUtil === 'validateUserInput' && pattern === 'validate') {
|
|
227
|
+
// Skip generic "validate" - too many false positives
|
|
228
|
+
continue;
|
|
229
|
+
}
|
|
230
|
+
|
|
304
231
|
if (functionName.toLowerCase().includes(pattern.toLowerCase())) {
|
|
305
232
|
context.report({
|
|
306
233
|
node: node.id,
|
|
@@ -329,16 +256,23 @@ module.exports = {
|
|
|
329
256
|
docs: {
|
|
330
257
|
description: 'Disallow local components with names matching pace-core components',
|
|
331
258
|
category: 'Best Practices',
|
|
332
|
-
recommended: true
|
|
259
|
+
recommended: true,
|
|
260
|
+
url: 'https://github.com/jmruthers/pace-core/blob/main/packages/core/docs/standards/1-pace-core-compliance-standards.md'
|
|
333
261
|
},
|
|
334
262
|
messages: {
|
|
335
263
|
duplicateComponent: "Component '{{componentName}}' conflicts with pace-core component. Use '@jmruthers/pace-core' instead of creating a local version."
|
|
336
264
|
}
|
|
337
265
|
},
|
|
338
266
|
create(context) {
|
|
339
|
-
const paceCoreComponents = getPaceCoreComponents();
|
|
340
267
|
const filename = context.getFilename();
|
|
341
268
|
|
|
269
|
+
// Exclude pace-core source files - these rules are for consuming apps
|
|
270
|
+
if (isPaceCoreSourceFile(filename)) {
|
|
271
|
+
return {};
|
|
272
|
+
}
|
|
273
|
+
|
|
274
|
+
const paceCoreComponents = getPaceCoreComponents();
|
|
275
|
+
|
|
342
276
|
// Only check component files (components/, src/components/, etc.)
|
|
343
277
|
if (!filename.match(/(components|Components)\//)) {
|
|
344
278
|
return {};
|
|
@@ -381,100 +315,186 @@ module.exports = {
|
|
|
381
315
|
},
|
|
382
316
|
|
|
383
317
|
/**
|
|
384
|
-
*
|
|
318
|
+
* Block direct imports of libraries wrapped by pace-core
|
|
385
319
|
*/
|
|
386
|
-
'no-
|
|
320
|
+
'no-restricted-imports': {
|
|
387
321
|
meta: {
|
|
388
322
|
type: 'problem',
|
|
389
323
|
docs: {
|
|
390
|
-
description: 'Disallow direct
|
|
391
|
-
category: '
|
|
392
|
-
recommended: true
|
|
324
|
+
description: 'Disallow direct imports of libraries that pace-core wraps',
|
|
325
|
+
category: 'Best Practices',
|
|
326
|
+
recommended: true,
|
|
327
|
+
url: 'https://github.com/jmruthers/pace-core/blob/main/packages/core/docs/standards/1-pace-core-compliance-standards.md'
|
|
393
328
|
},
|
|
329
|
+
fixable: 'code',
|
|
330
|
+
hasSuggestions: true,
|
|
394
331
|
messages: {
|
|
395
|
-
|
|
396
|
-
|
|
332
|
+
restrictedImport: '{{message}} Import from {{alternative}} instead.',
|
|
333
|
+
restrictedImportWithReason: '{{message}} {{reason}}'
|
|
334
|
+
}
|
|
335
|
+
},
|
|
336
|
+
create(context) {
|
|
337
|
+
const filename = context.getFilename();
|
|
338
|
+
|
|
339
|
+
// Exclude pace-core source files - these rules are for consuming apps
|
|
340
|
+
if (isPaceCoreSourceFile(filename)) {
|
|
341
|
+
return {};
|
|
342
|
+
}
|
|
343
|
+
|
|
344
|
+
const restrictedImports = getRestrictedImports();
|
|
345
|
+
const restrictedModules = restrictedImports.map(imp => imp.module);
|
|
346
|
+
|
|
347
|
+
// Also catch @radix-ui/* patterns
|
|
348
|
+
const radixPattern = /^@radix-ui\//;
|
|
349
|
+
|
|
350
|
+
return {
|
|
351
|
+
ImportDeclaration(node) {
|
|
352
|
+
const importSource = node.source.value;
|
|
353
|
+
|
|
354
|
+
// Check exact matches
|
|
355
|
+
const restricted = restrictedImports.find(imp => imp.module === importSource);
|
|
356
|
+
if (restricted) {
|
|
357
|
+
context.report({
|
|
358
|
+
node: node.source,
|
|
359
|
+
messageId: 'restrictedImportWithReason',
|
|
360
|
+
data: {
|
|
361
|
+
message: `Direct import of '${importSource}' is not allowed.`,
|
|
362
|
+
reason: restricted.reason
|
|
363
|
+
},
|
|
364
|
+
suggest: [{
|
|
365
|
+
desc: `Use pace-core alternative: ${restricted.reason}`,
|
|
366
|
+
fix(fixer) {
|
|
367
|
+
// Suggest importing from pace-core instead
|
|
368
|
+
const paceCoreAlternative = getPaceCoreAlternative(importSource);
|
|
369
|
+
if (paceCoreAlternative) {
|
|
370
|
+
return fixer.replaceText(
|
|
371
|
+
node.source,
|
|
372
|
+
`'@jmruthers/pace-core${paceCoreAlternative}'`
|
|
373
|
+
);
|
|
374
|
+
}
|
|
375
|
+
return null;
|
|
376
|
+
}
|
|
377
|
+
}]
|
|
378
|
+
});
|
|
379
|
+
return;
|
|
380
|
+
}
|
|
381
|
+
|
|
382
|
+
// Check @radix-ui/* pattern
|
|
383
|
+
if (radixPattern.test(importSource) && !restrictedModules.includes(importSource)) {
|
|
384
|
+
context.report({
|
|
385
|
+
node: node.source,
|
|
386
|
+
messageId: 'restrictedImport',
|
|
387
|
+
data: {
|
|
388
|
+
message: `Direct import of '${importSource}' is not allowed.`,
|
|
389
|
+
alternative: '@jmruthers/pace-core'
|
|
390
|
+
},
|
|
391
|
+
suggest: [{
|
|
392
|
+
desc: 'Use pace-core component instead',
|
|
393
|
+
fix(fixer) {
|
|
394
|
+
return fixer.replaceText(
|
|
395
|
+
node.source,
|
|
396
|
+
"'@jmruthers/pace-core'"
|
|
397
|
+
);
|
|
398
|
+
}
|
|
399
|
+
}]
|
|
400
|
+
});
|
|
401
|
+
}
|
|
402
|
+
}
|
|
403
|
+
};
|
|
404
|
+
}
|
|
405
|
+
},
|
|
406
|
+
|
|
407
|
+
/**
|
|
408
|
+
* Prefer pace-core Form component over plain form tags and direct react-hook-form usage
|
|
409
|
+
*/
|
|
410
|
+
'prefer-pace-core-form': {
|
|
411
|
+
meta: {
|
|
412
|
+
type: 'problem',
|
|
413
|
+
docs: {
|
|
414
|
+
description: 'Disallow plain <form> tags and direct react-hook-form imports. Use pace-core Form component instead.',
|
|
415
|
+
category: 'Best Practices',
|
|
416
|
+
recommended: true,
|
|
417
|
+
url: 'https://github.com/jmruthers/pace-core/blob/main/packages/core/docs/standards/1-pace-core-compliance-standards.md'
|
|
418
|
+
},
|
|
419
|
+
messages: {
|
|
420
|
+
plainFormTag: "Plain <form> tag detected. Use pace-core Form component instead.",
|
|
421
|
+
reactHookFormImport: "Direct import from 'react-hook-form' detected: {{imports}}. Use pace-core Form component instead. useFormContext is allowed when Form is imported from pace-core."
|
|
397
422
|
},
|
|
398
423
|
hasSuggestions: true
|
|
399
424
|
},
|
|
400
425
|
create(context) {
|
|
401
|
-
let hasSupabaseImport = false;
|
|
402
|
-
let createClientImported = false;
|
|
403
426
|
const filename = context.getFilename();
|
|
404
427
|
|
|
405
|
-
//
|
|
406
|
-
|
|
407
|
-
|
|
428
|
+
// Exclude pace-core source files - these rules are for consuming apps
|
|
429
|
+
if (isPaceCoreSourceFile(filename)) {
|
|
430
|
+
return {};
|
|
431
|
+
}
|
|
432
|
+
|
|
433
|
+
let hasPaceCoreForm = false;
|
|
434
|
+
const problematicImports = ['useForm', 'FormProvider', 'Controller', 'useWatch', 'useFieldArray', 'useController'];
|
|
408
435
|
|
|
409
436
|
return {
|
|
410
437
|
ImportDeclaration(node) {
|
|
411
438
|
const importSource = node.source.value;
|
|
412
439
|
|
|
413
|
-
// Check
|
|
414
|
-
if (importSource === '@
|
|
415
|
-
|
|
416
|
-
|
|
417
|
-
// Check if createClient is imported
|
|
418
|
-
const hasCreateClient = node.specifiers.some(spec => {
|
|
440
|
+
// Check if Form is imported from pace-core
|
|
441
|
+
if (importSource === '@jmruthers/pace-core' ||
|
|
442
|
+
importSource === '@jmruthers/pace-core/components') {
|
|
443
|
+
const hasForm = node.specifiers.some(spec => {
|
|
419
444
|
if (spec.type === 'ImportSpecifier') {
|
|
420
|
-
return spec.imported.name === '
|
|
421
|
-
}
|
|
422
|
-
if (spec.type === 'ImportNamespaceSpecifier') {
|
|
423
|
-
return true; // import * as supabase
|
|
445
|
+
return spec.imported.name === 'Form';
|
|
424
446
|
}
|
|
425
447
|
return false;
|
|
426
448
|
});
|
|
427
|
-
|
|
428
|
-
|
|
429
|
-
createClientImported = true;
|
|
430
|
-
|
|
431
|
-
// Only report if not in a config file
|
|
432
|
-
if (!isConfigFile) {
|
|
433
|
-
context.report({
|
|
434
|
-
node: node.source,
|
|
435
|
-
messageId: 'directClientImport',
|
|
436
|
-
suggest: [{
|
|
437
|
-
desc: 'Replace with useSecureSupabase hook',
|
|
438
|
-
fix(fixer) {
|
|
439
|
-
// Remove the import
|
|
440
|
-
return fixer.remove(node);
|
|
441
|
-
}
|
|
442
|
-
}]
|
|
443
|
-
});
|
|
444
|
-
}
|
|
449
|
+
if (hasForm) {
|
|
450
|
+
hasPaceCoreForm = true;
|
|
445
451
|
}
|
|
446
452
|
}
|
|
447
|
-
|
|
448
|
-
|
|
449
|
-
|
|
450
|
-
|
|
451
|
-
|
|
452
|
-
|
|
453
|
-
|
|
453
|
+
|
|
454
|
+
// Check for react-hook-form imports
|
|
455
|
+
if (importSource === 'react-hook-form') {
|
|
456
|
+
const importedItems = node.specifiers
|
|
457
|
+
.filter(spec => spec.type === 'ImportSpecifier')
|
|
458
|
+
.map(spec => spec.imported.name);
|
|
459
|
+
|
|
460
|
+
const foundProblematic = importedItems.filter(item => problematicImports.includes(item));
|
|
461
|
+
|
|
462
|
+
// Allow useFormContext when Form is imported from pace-core
|
|
463
|
+
const isAcceptable = hasPaceCoreForm &&
|
|
464
|
+
foundProblematic.length === 1 &&
|
|
465
|
+
foundProblematic[0] === 'useFormContext';
|
|
466
|
+
|
|
467
|
+
if (foundProblematic.length > 0 && !isAcceptable) {
|
|
454
468
|
context.report({
|
|
455
|
-
node,
|
|
456
|
-
messageId: '
|
|
469
|
+
node: node.source,
|
|
470
|
+
messageId: 'reactHookFormImport',
|
|
471
|
+
data: {
|
|
472
|
+
imports: foundProblematic.join(', ')
|
|
473
|
+
},
|
|
457
474
|
suggest: [{
|
|
458
|
-
desc: 'Use
|
|
475
|
+
desc: 'Use pace-core Form component instead',
|
|
459
476
|
fix(fixer) {
|
|
460
|
-
|
|
461
|
-
return null;
|
|
477
|
+
return fixer.remove(node);
|
|
462
478
|
}
|
|
463
479
|
}]
|
|
464
480
|
});
|
|
465
481
|
}
|
|
466
482
|
}
|
|
467
|
-
|
|
468
|
-
|
|
469
|
-
|
|
470
|
-
|
|
471
|
-
|
|
483
|
+
},
|
|
484
|
+
|
|
485
|
+
JSXOpeningElement(node) {
|
|
486
|
+
// Check for plain <form> tags (lowercase, not Form component)
|
|
487
|
+
if (node.name.type === 'JSXIdentifier') {
|
|
488
|
+
const elementName = node.name.name;
|
|
489
|
+
// Check if it's lowercase 'form' (not 'Form' component)
|
|
490
|
+
if (elementName === 'form') {
|
|
472
491
|
context.report({
|
|
473
492
|
node,
|
|
474
|
-
messageId: '
|
|
493
|
+
messageId: 'plainFormTag',
|
|
475
494
|
suggest: [{
|
|
476
|
-
desc: '
|
|
495
|
+
desc: 'Replace with pace-core Form component',
|
|
477
496
|
fix(fixer) {
|
|
497
|
+
// This is complex to auto-fix, so we'll just report
|
|
478
498
|
return null;
|
|
479
499
|
}
|
|
480
500
|
}]
|
|
@@ -487,24 +507,3 @@ module.exports = {
|
|
|
487
507
|
}
|
|
488
508
|
}
|
|
489
509
|
};
|
|
490
|
-
|
|
491
|
-
// Helper function to get pace-core alternative for restricted imports
|
|
492
|
-
function getPaceCoreAlternative(importSource) {
|
|
493
|
-
const alternatives = {
|
|
494
|
-
'@radix-ui/react-avatar': '/components',
|
|
495
|
-
'@radix-ui/react-checkbox': '/components',
|
|
496
|
-
'@radix-ui/react-dialog': '/components',
|
|
497
|
-
'@radix-ui/react-label': '/components',
|
|
498
|
-
'@radix-ui/react-switch': '/components',
|
|
499
|
-
'@radix-ui/react-tabs': '/components',
|
|
500
|
-
'@radix-ui/react-toast': '/components',
|
|
501
|
-
'@radix-ui/react-tooltip': '/components',
|
|
502
|
-
'react-day-picker': '/components',
|
|
503
|
-
'@tanstack/react-table': '/components',
|
|
504
|
-
'react-hook-form': '/components',
|
|
505
|
-
'zod': '/utils'
|
|
506
|
-
};
|
|
507
|
-
|
|
508
|
-
return alternatives[importSource] || '';
|
|
509
|
-
}
|
|
510
|
-
|