@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,994 +0,0 @@
|
|
|
1
|
-
#!/usr/bin/env node
|
|
2
|
-
|
|
3
|
-
/**
|
|
4
|
-
* Dependencies Check Module
|
|
5
|
-
* @package @jmruthers/pace-core
|
|
6
|
-
* @module Audit/Checks/Dependencies
|
|
7
|
-
*
|
|
8
|
-
* Checks for:
|
|
9
|
-
* - Outdated pace-core version
|
|
10
|
-
* - Security vulnerabilities
|
|
11
|
-
* - Unused dependencies
|
|
12
|
-
* - Missing peer dependencies
|
|
13
|
-
* - Version mismatches
|
|
14
|
-
* - Redundant dependencies (duplicates of pace-core deps)
|
|
15
|
-
* - Missing dependencies (used but not declared)
|
|
16
|
-
* - Misclassified dependencies (wrong section)
|
|
17
|
-
* - Version mismatches across workspace
|
|
18
|
-
* - Optional dependencies build configuration
|
|
19
|
-
*/
|
|
20
|
-
|
|
21
|
-
const fs = require('fs');
|
|
22
|
-
const path = require('path');
|
|
23
|
-
const { getPackageInfo, findSourceFiles } = require('../utils.cjs');
|
|
24
|
-
|
|
25
|
-
/**
|
|
26
|
-
* Extract package name from import/require path
|
|
27
|
-
*/
|
|
28
|
-
function extractPackageName(modulePath) {
|
|
29
|
-
if (modulePath.startsWith('@')) {
|
|
30
|
-
const parts = modulePath.split('/');
|
|
31
|
-
if (parts.length >= 2) {
|
|
32
|
-
return `${parts[0]}/${parts[1]}`;
|
|
33
|
-
}
|
|
34
|
-
} else {
|
|
35
|
-
return modulePath.split('/')[0];
|
|
36
|
-
}
|
|
37
|
-
return null;
|
|
38
|
-
}
|
|
39
|
-
|
|
40
|
-
/**
|
|
41
|
-
* Find all config files in the project
|
|
42
|
-
*/
|
|
43
|
-
function findConfigFiles(projectRoot) {
|
|
44
|
-
const configFiles = [];
|
|
45
|
-
const configPatterns = [
|
|
46
|
-
'vite.config.{ts,js,mjs,cjs}',
|
|
47
|
-
'vitest.config.{ts,js,mjs,cjs}',
|
|
48
|
-
'tsconfig.json',
|
|
49
|
-
'.eslintrc.{js,json,cjs}',
|
|
50
|
-
'eslint.config.{js,mjs,cjs}',
|
|
51
|
-
'tailwind.config.{ts,js}',
|
|
52
|
-
'postcss.config.{js,cjs}',
|
|
53
|
-
'babel.config.{js,json}',
|
|
54
|
-
'jest.config.{js,ts}',
|
|
55
|
-
'webpack.config.{js,ts}',
|
|
56
|
-
'rollup.config.{js,ts}',
|
|
57
|
-
'next.config.{js,mjs}',
|
|
58
|
-
'remix.config.{js,ts}',
|
|
59
|
-
];
|
|
60
|
-
|
|
61
|
-
// Check root directory
|
|
62
|
-
const rootFiles = fs.readdirSync(projectRoot);
|
|
63
|
-
rootFiles.forEach(file => {
|
|
64
|
-
configPatterns.forEach(pattern => {
|
|
65
|
-
const regex = new RegExp('^' + pattern.replace(/\{.*?\}/g, '.*') + '$');
|
|
66
|
-
if (regex.test(file)) {
|
|
67
|
-
const fullPath = path.join(projectRoot, file);
|
|
68
|
-
if (fs.existsSync(fullPath)) {
|
|
69
|
-
configFiles.push(fullPath);
|
|
70
|
-
}
|
|
71
|
-
}
|
|
72
|
-
});
|
|
73
|
-
});
|
|
74
|
-
|
|
75
|
-
return configFiles;
|
|
76
|
-
}
|
|
77
|
-
|
|
78
|
-
/**
|
|
79
|
-
* Get pace-core peer dependencies
|
|
80
|
-
*/
|
|
81
|
-
function getPaceCorePeerDeps(projectRoot) {
|
|
82
|
-
try {
|
|
83
|
-
// Try to find pace-core in node_modules
|
|
84
|
-
const paceCorePath = path.join(projectRoot, 'node_modules', '@jmruthers', 'pace-core', 'package.json');
|
|
85
|
-
if (fs.existsSync(paceCorePath)) {
|
|
86
|
-
const paceCorePkg = JSON.parse(fs.readFileSync(paceCorePath, 'utf8'));
|
|
87
|
-
return paceCorePkg.peerDependencies || {};
|
|
88
|
-
}
|
|
89
|
-
} catch (error) {
|
|
90
|
-
// If we can't find it, return empty object
|
|
91
|
-
}
|
|
92
|
-
return {};
|
|
93
|
-
}
|
|
94
|
-
|
|
95
|
-
/**
|
|
96
|
-
* Get pace-core dependencies (runtime dependencies provided by pace-core)
|
|
97
|
-
*/
|
|
98
|
-
function getPaceCoreDeps(projectRoot) {
|
|
99
|
-
try {
|
|
100
|
-
// Try to find pace-core in node_modules
|
|
101
|
-
const paceCorePath = path.join(projectRoot, 'node_modules', '@jmruthers', 'pace-core', 'package.json');
|
|
102
|
-
if (fs.existsSync(paceCorePath)) {
|
|
103
|
-
const paceCorePkg = JSON.parse(fs.readFileSync(paceCorePath, 'utf8'));
|
|
104
|
-
return paceCorePkg.dependencies || {};
|
|
105
|
-
}
|
|
106
|
-
} catch (error) {
|
|
107
|
-
// If we can't find it, return empty object
|
|
108
|
-
}
|
|
109
|
-
return {};
|
|
110
|
-
}
|
|
111
|
-
|
|
112
|
-
/**
|
|
113
|
-
* Get pace-core package.json (for workspace checks)
|
|
114
|
-
*/
|
|
115
|
-
function getPaceCorePackageJson(projectRoot) {
|
|
116
|
-
try {
|
|
117
|
-
// Try to find pace-core in node_modules
|
|
118
|
-
const paceCorePath = path.join(projectRoot, 'node_modules', '@jmruthers', 'pace-core', 'package.json');
|
|
119
|
-
if (fs.existsSync(paceCorePath)) {
|
|
120
|
-
return JSON.parse(fs.readFileSync(paceCorePath, 'utf8'));
|
|
121
|
-
}
|
|
122
|
-
// Also try packages/core if we're in the workspace
|
|
123
|
-
const packagesCorePath = path.join(projectRoot, 'packages', 'core', 'package.json');
|
|
124
|
-
if (fs.existsSync(packagesCorePath)) {
|
|
125
|
-
return JSON.parse(fs.readFileSync(packagesCorePath, 'utf8'));
|
|
126
|
-
}
|
|
127
|
-
} catch (error) {
|
|
128
|
-
// If we can't find it, return null
|
|
129
|
-
}
|
|
130
|
-
return null;
|
|
131
|
-
}
|
|
132
|
-
|
|
133
|
-
/**
|
|
134
|
-
* Get workspace root package.json (for monorepo checks)
|
|
135
|
-
*/
|
|
136
|
-
function getWorkspaceRootPackageJson(projectRoot) {
|
|
137
|
-
try {
|
|
138
|
-
const rootPath = path.join(projectRoot, 'package.json');
|
|
139
|
-
if (fs.existsSync(rootPath)) {
|
|
140
|
-
return JSON.parse(fs.readFileSync(rootPath, 'utf8'));
|
|
141
|
-
}
|
|
142
|
-
} catch (error) {
|
|
143
|
-
// If we can't find it, return null
|
|
144
|
-
}
|
|
145
|
-
return null;
|
|
146
|
-
}
|
|
147
|
-
|
|
148
|
-
/**
|
|
149
|
-
* Check if a dependency is used in config files
|
|
150
|
-
*/
|
|
151
|
-
function checkConfigFiles(configFiles, depName) {
|
|
152
|
-
for (const configFile of configFiles) {
|
|
153
|
-
try {
|
|
154
|
-
const content = fs.readFileSync(configFile, 'utf8');
|
|
155
|
-
|
|
156
|
-
// Check for direct imports/requires
|
|
157
|
-
const importPatterns = [
|
|
158
|
-
/from\s+['"]([^'"]+)['"]/g,
|
|
159
|
-
/require\(['"]([^'"]+)['"]\)/g,
|
|
160
|
-
/import\(['"]([^'"]+)['"]\)/g,
|
|
161
|
-
];
|
|
162
|
-
|
|
163
|
-
for (const pattern of importPatterns) {
|
|
164
|
-
let match;
|
|
165
|
-
while ((match = pattern.exec(content)) !== null) {
|
|
166
|
-
const modulePath = match[1];
|
|
167
|
-
const pkgName = extractPackageName(modulePath);
|
|
168
|
-
if (pkgName === depName) {
|
|
169
|
-
return true;
|
|
170
|
-
}
|
|
171
|
-
}
|
|
172
|
-
}
|
|
173
|
-
|
|
174
|
-
// Check for string references (e.g., in optimizeDeps, plugins, etc.)
|
|
175
|
-
// This is a heuristic - check if the package name appears as a string
|
|
176
|
-
const depNameEscaped = depName.replace(/[.*+?^${}()|[\]\\]/g, '\\$&');
|
|
177
|
-
const stringRefPattern = new RegExp(`['"]${depNameEscaped}['"]`, 'g');
|
|
178
|
-
if (stringRefPattern.test(content)) {
|
|
179
|
-
return true;
|
|
180
|
-
}
|
|
181
|
-
} catch (error) {
|
|
182
|
-
// Skip files we can't read
|
|
183
|
-
}
|
|
184
|
-
}
|
|
185
|
-
return false;
|
|
186
|
-
}
|
|
187
|
-
|
|
188
|
-
/**
|
|
189
|
-
* Check if a dependency is used in CSS or other non-JS files
|
|
190
|
-
*/
|
|
191
|
-
function checkNonJsFiles(projectRoot, depName) {
|
|
192
|
-
const cssFiles = [];
|
|
193
|
-
const cssExtensions = ['.css', '.scss', '.sass', '.less', '.styl'];
|
|
194
|
-
|
|
195
|
-
try {
|
|
196
|
-
const srcPath = path.join(projectRoot, 'src');
|
|
197
|
-
if (fs.existsSync(srcPath)) {
|
|
198
|
-
const walkDir = (dir) => {
|
|
199
|
-
const files = fs.readdirSync(dir);
|
|
200
|
-
files.forEach(file => {
|
|
201
|
-
const fullPath = path.join(dir, file);
|
|
202
|
-
const stat = fs.statSync(fullPath);
|
|
203
|
-
if (stat.isDirectory() && !file.startsWith('.') && file !== 'node_modules') {
|
|
204
|
-
walkDir(fullPath);
|
|
205
|
-
} else if (stat.isFile()) {
|
|
206
|
-
const ext = path.extname(file);
|
|
207
|
-
if (cssExtensions.includes(ext)) {
|
|
208
|
-
cssFiles.push(fullPath);
|
|
209
|
-
}
|
|
210
|
-
}
|
|
211
|
-
});
|
|
212
|
-
};
|
|
213
|
-
walkDir(srcPath);
|
|
214
|
-
}
|
|
215
|
-
} catch (error) {
|
|
216
|
-
// Skip if can't read
|
|
217
|
-
}
|
|
218
|
-
|
|
219
|
-
// Check CSS files for @import statements
|
|
220
|
-
for (const cssFile of cssFiles) {
|
|
221
|
-
try {
|
|
222
|
-
const content = fs.readFileSync(cssFile, 'utf8');
|
|
223
|
-
// Check for @import statements that might reference packages
|
|
224
|
-
const importPattern = /@import\s+['"]([^'"]+)['"]/g;
|
|
225
|
-
let match;
|
|
226
|
-
while ((match = importPattern.exec(content)) !== null) {
|
|
227
|
-
const modulePath = match[1];
|
|
228
|
-
const pkgName = extractPackageName(modulePath);
|
|
229
|
-
if (pkgName === depName) {
|
|
230
|
-
return true;
|
|
231
|
-
}
|
|
232
|
-
}
|
|
233
|
-
} catch (error) {
|
|
234
|
-
// Skip files we can't read
|
|
235
|
-
}
|
|
236
|
-
}
|
|
237
|
-
|
|
238
|
-
return false;
|
|
239
|
-
}
|
|
240
|
-
|
|
241
|
-
/**
|
|
242
|
-
* Find all test files in the project
|
|
243
|
-
*/
|
|
244
|
-
function findTestFiles(projectRoot) {
|
|
245
|
-
const testFiles = [];
|
|
246
|
-
const testPattern = /\.(test|spec)\.(ts|tsx|js|jsx)$/;
|
|
247
|
-
const ignoreDirs = ['node_modules', 'dist', 'build', '.next', 'coverage'];
|
|
248
|
-
|
|
249
|
-
const walkDir = (dir) => {
|
|
250
|
-
try {
|
|
251
|
-
const items = fs.readdirSync(dir);
|
|
252
|
-
items.forEach(item => {
|
|
253
|
-
const fullPath = path.join(dir, item);
|
|
254
|
-
const stat = fs.statSync(fullPath);
|
|
255
|
-
|
|
256
|
-
if (stat.isDirectory()) {
|
|
257
|
-
if (!ignoreDirs.includes(item) && !item.startsWith('.')) {
|
|
258
|
-
walkDir(fullPath);
|
|
259
|
-
}
|
|
260
|
-
} else if (stat.isFile() && testPattern.test(item)) {
|
|
261
|
-
testFiles.push(fullPath);
|
|
262
|
-
}
|
|
263
|
-
});
|
|
264
|
-
} catch (error) {
|
|
265
|
-
// Skip directories we can't read
|
|
266
|
-
}
|
|
267
|
-
};
|
|
268
|
-
|
|
269
|
-
try {
|
|
270
|
-
const srcPath = path.join(projectRoot, 'src');
|
|
271
|
-
if (fs.existsSync(srcPath)) {
|
|
272
|
-
walkDir(srcPath);
|
|
273
|
-
}
|
|
274
|
-
} catch (error) {
|
|
275
|
-
// Skip if can't read
|
|
276
|
-
}
|
|
277
|
-
|
|
278
|
-
return testFiles;
|
|
279
|
-
}
|
|
280
|
-
|
|
281
|
-
/**
|
|
282
|
-
* Check if a dependency is used in package.json scripts
|
|
283
|
-
*/
|
|
284
|
-
function checkPackageScripts(packageJson, depName) {
|
|
285
|
-
if (!packageJson || !packageJson.scripts) {
|
|
286
|
-
return false;
|
|
287
|
-
}
|
|
288
|
-
|
|
289
|
-
const scripts = packageJson.scripts;
|
|
290
|
-
const scriptContent = Object.values(scripts).join(' ');
|
|
291
|
-
|
|
292
|
-
// Check if the package name appears in any script
|
|
293
|
-
// This is a simple check - package names in scripts are usually the command name
|
|
294
|
-
const depNameEscaped = depName.replace(/[.*+?^${}()|[\]\\]/g, '\\$&');
|
|
295
|
-
const scriptPattern = new RegExp(`\\b${depNameEscaped}\\b`, 'i');
|
|
296
|
-
|
|
297
|
-
return scriptPattern.test(scriptContent);
|
|
298
|
-
}
|
|
299
|
-
|
|
300
|
-
/**
|
|
301
|
-
* Check if a dependency is only used in test files
|
|
302
|
-
*/
|
|
303
|
-
function isOnlyUsedInTests(projectRoot, depName, testFiles) {
|
|
304
|
-
if (testFiles.length === 0) {
|
|
305
|
-
return false;
|
|
306
|
-
}
|
|
307
|
-
|
|
308
|
-
// Check if it's used in any test file
|
|
309
|
-
let foundInTests = false;
|
|
310
|
-
for (const testFile of testFiles) {
|
|
311
|
-
try {
|
|
312
|
-
const content = fs.readFileSync(testFile, 'utf8');
|
|
313
|
-
const depNameEscaped = depName.replace(/[.*+?^${}()|[\]\\]/g, '\\$&');
|
|
314
|
-
|
|
315
|
-
// Check for imports
|
|
316
|
-
const importPattern = new RegExp(`from\\s+['"]${depNameEscaped}`, 'g');
|
|
317
|
-
const requirePattern = new RegExp(`require\\(['"]${depNameEscaped}`, 'g');
|
|
318
|
-
|
|
319
|
-
if (importPattern.test(content) || requirePattern.test(content)) {
|
|
320
|
-
foundInTests = true;
|
|
321
|
-
break;
|
|
322
|
-
}
|
|
323
|
-
} catch (error) {
|
|
324
|
-
// Skip files we can't read
|
|
325
|
-
}
|
|
326
|
-
}
|
|
327
|
-
|
|
328
|
-
return foundInTests;
|
|
329
|
-
}
|
|
330
|
-
|
|
331
|
-
const dependenciesCheck = {
|
|
332
|
-
name: 'dependencies',
|
|
333
|
-
description: 'Dependency analysis (outdated versions, security, unused deps, redundant deps, misclassified deps, version mismatches)',
|
|
334
|
-
severity: 'warning',
|
|
335
|
-
|
|
336
|
-
async run(context) {
|
|
337
|
-
const { projectRoot } = context;
|
|
338
|
-
const issues = [];
|
|
339
|
-
const warnings = [];
|
|
340
|
-
const suggestions = [];
|
|
341
|
-
|
|
342
|
-
const packageJson = getPackageInfo(projectRoot);
|
|
343
|
-
if (!packageJson) {
|
|
344
|
-
return { issues, warnings, suggestions };
|
|
345
|
-
}
|
|
346
|
-
|
|
347
|
-
// Skip dependency checks if this is the pace-core repository itself
|
|
348
|
-
// Detect pace-core repository by checking if packages/core exists
|
|
349
|
-
const packagesCorePath = path.join(projectRoot, 'packages', 'core');
|
|
350
|
-
const isPaceCoreRepository = fs.existsSync(packagesCorePath);
|
|
351
|
-
|
|
352
|
-
const allDeps = { ...packageJson.dependencies, ...packageJson.devDependencies };
|
|
353
|
-
const devDeps = packageJson.devDependencies || {};
|
|
354
|
-
|
|
355
|
-
// Get pace-core peer dependencies
|
|
356
|
-
const paceCorePeerDeps = getPaceCorePeerDeps(projectRoot);
|
|
357
|
-
|
|
358
|
-
// Get pace-core version (used in multiple checks)
|
|
359
|
-
const paceCoreVersion = !isPaceCoreRepository ? allDeps['@jmruthers/pace-core'] : null;
|
|
360
|
-
|
|
361
|
-
// Check for required React version (19.2.3) - do this early to ensure it always runs
|
|
362
|
-
// This check MUST run for all consuming apps (not pace-core repository itself)
|
|
363
|
-
if (!isPaceCoreRepository) {
|
|
364
|
-
const requiredReactVersion = '19.2.3';
|
|
365
|
-
|
|
366
|
-
// Read React versions from package.json - check both dependencies and devDependencies
|
|
367
|
-
const reactVersion = (packageJson.dependencies && packageJson.dependencies.react) ||
|
|
368
|
-
(packageJson.devDependencies && packageJson.devDependencies.react) ||
|
|
369
|
-
null;
|
|
370
|
-
const reactDomVersion = (packageJson.dependencies && packageJson.dependencies['react-dom']) ||
|
|
371
|
-
(packageJson.devDependencies && packageJson.devDependencies['react-dom']) ||
|
|
372
|
-
null;
|
|
373
|
-
|
|
374
|
-
// Normalize version for comparison (remove ^, ~, >=, <=, etc.)
|
|
375
|
-
const normalizeVersion = (v) => {
|
|
376
|
-
if (!v || typeof v !== 'string') {
|
|
377
|
-
return null;
|
|
378
|
-
}
|
|
379
|
-
// Remove range prefixes (^, ~, >=, <=, >, <, =)
|
|
380
|
-
let normalized = v.replace(/^[\^~>=<]/, '');
|
|
381
|
-
// Remove any whitespace
|
|
382
|
-
normalized = normalized.trim();
|
|
383
|
-
// Extract base version (e.g., "19.2.3" from "19.2.3" or "19.2.3-alpha.1")
|
|
384
|
-
const match = normalized.match(/^(\d+\.\d+\.\d+)/);
|
|
385
|
-
if (match && match[1]) {
|
|
386
|
-
return match[1];
|
|
387
|
-
}
|
|
388
|
-
// Fallback: try to extract any version pattern
|
|
389
|
-
const fallbackMatch = normalized.match(/(\d+\.\d+\.\d+)/);
|
|
390
|
-
return fallbackMatch ? fallbackMatch[1] : null;
|
|
391
|
-
};
|
|
392
|
-
|
|
393
|
-
// Check React version
|
|
394
|
-
if (reactVersion) {
|
|
395
|
-
const normalizedReactVersion = normalizeVersion(reactVersion);
|
|
396
|
-
const normalizedRequiredVersion = normalizeVersion(requiredReactVersion);
|
|
397
|
-
|
|
398
|
-
// Check if versions match - always add issue if they don't match
|
|
399
|
-
let versionMismatch = false;
|
|
400
|
-
|
|
401
|
-
if (normalizedReactVersion && normalizedRequiredVersion) {
|
|
402
|
-
// Both normalized successfully - compare normalized versions
|
|
403
|
-
versionMismatch = normalizedReactVersion !== normalizedRequiredVersion;
|
|
404
|
-
} else {
|
|
405
|
-
// Normalization failed - do a simple string check
|
|
406
|
-
const cleanReactVersion = reactVersion.replace(/^[\^~>=<]/, '').trim();
|
|
407
|
-
const cleanRequiredVersion = requiredReactVersion.replace(/^[\^~>=<]/, '').trim();
|
|
408
|
-
versionMismatch = cleanReactVersion !== cleanRequiredVersion && !cleanReactVersion.startsWith(requiredReactVersion);
|
|
409
|
-
}
|
|
410
|
-
|
|
411
|
-
if (versionMismatch) {
|
|
412
|
-
issues.push({
|
|
413
|
-
type: 'incorrect-react-version',
|
|
414
|
-
file: 'package.json',
|
|
415
|
-
message: `React version ${reactVersion} does not match required version ${requiredReactVersion}`,
|
|
416
|
-
recommendation: `Install React ${requiredReactVersion}. Run: npm install react@${requiredReactVersion} react-dom@${requiredReactVersion}`
|
|
417
|
-
});
|
|
418
|
-
}
|
|
419
|
-
} else {
|
|
420
|
-
issues.push({
|
|
421
|
-
type: 'missing-react',
|
|
422
|
-
file: 'package.json',
|
|
423
|
-
message: 'React is not installed but is required',
|
|
424
|
-
recommendation: `Install React ${requiredReactVersion}. Run: npm install react@${requiredReactVersion} react-dom@${requiredReactVersion}`
|
|
425
|
-
});
|
|
426
|
-
}
|
|
427
|
-
|
|
428
|
-
// Check react-dom version matches
|
|
429
|
-
if (reactDomVersion) {
|
|
430
|
-
const normalizedReactDomVersion = normalizeVersion(reactDomVersion);
|
|
431
|
-
const normalizedRequiredVersion = normalizeVersion(requiredReactVersion);
|
|
432
|
-
|
|
433
|
-
// Check if versions match - always add issue if they don't match
|
|
434
|
-
let versionMismatch = false;
|
|
435
|
-
|
|
436
|
-
if (normalizedReactDomVersion && normalizedRequiredVersion) {
|
|
437
|
-
// Both normalized successfully - compare normalized versions
|
|
438
|
-
versionMismatch = normalizedReactDomVersion !== normalizedRequiredVersion;
|
|
439
|
-
} else {
|
|
440
|
-
// Normalization failed - do a simple string check
|
|
441
|
-
const cleanReactDomVersion = reactDomVersion.replace(/^[\^~>=<]/, '').trim();
|
|
442
|
-
const cleanRequiredVersion = requiredReactVersion.replace(/^[\^~>=<]/, '').trim();
|
|
443
|
-
versionMismatch = cleanReactDomVersion !== cleanRequiredVersion && !cleanReactDomVersion.startsWith(requiredReactVersion);
|
|
444
|
-
}
|
|
445
|
-
|
|
446
|
-
if (versionMismatch) {
|
|
447
|
-
issues.push({
|
|
448
|
-
type: 'incorrect-react-dom-version',
|
|
449
|
-
file: 'package.json',
|
|
450
|
-
message: `react-dom version ${reactDomVersion} does not match required version ${requiredReactVersion}`,
|
|
451
|
-
recommendation: `Install react-dom ${requiredReactVersion}. Run: npm install react-dom@${requiredReactVersion}`
|
|
452
|
-
});
|
|
453
|
-
}
|
|
454
|
-
} else if (reactVersion) {
|
|
455
|
-
// If react is installed but react-dom is not, that's also an issue
|
|
456
|
-
issues.push({
|
|
457
|
-
type: 'missing-react-dom',
|
|
458
|
-
file: 'package.json',
|
|
459
|
-
message: 'react-dom is not installed but is required',
|
|
460
|
-
recommendation: `Install react-dom ${requiredReactVersion}. Run: npm install react-dom@${requiredReactVersion}`
|
|
461
|
-
});
|
|
462
|
-
}
|
|
463
|
-
}
|
|
464
|
-
|
|
465
|
-
// Check pace-core version (skip if this is the pace-core repository itself)
|
|
466
|
-
if (!isPaceCoreRepository) {
|
|
467
|
-
if (paceCoreVersion) {
|
|
468
|
-
// Check if version is outdated (simplified - would need to check npm registry)
|
|
469
|
-
if (paceCoreVersion.startsWith('^') || paceCoreVersion.startsWith('~')) {
|
|
470
|
-
// Version range - this is fine
|
|
471
|
-
} else if (paceCoreVersion.match(/^\d+\.\d+\.\d+$/)) {
|
|
472
|
-
// Exact version - suggest using range
|
|
473
|
-
suggestions.push({
|
|
474
|
-
type: 'exact-version',
|
|
475
|
-
file: 'package.json',
|
|
476
|
-
message: `pace-core is pinned to exact version ${paceCoreVersion}`,
|
|
477
|
-
recommendation: 'Consider using a version range (^ or ~) to receive patch/minor updates automatically'
|
|
478
|
-
});
|
|
479
|
-
}
|
|
480
|
-
} else {
|
|
481
|
-
issues.push({
|
|
482
|
-
type: 'missing-pace-core',
|
|
483
|
-
file: 'package.json',
|
|
484
|
-
message: '@jmruthers/pace-core is not in dependencies',
|
|
485
|
-
recommendation: 'Add @jmruthers/pace-core to your dependencies'
|
|
486
|
-
});
|
|
487
|
-
}
|
|
488
|
-
}
|
|
489
|
-
|
|
490
|
-
// Collect all files to scan
|
|
491
|
-
// Skip unused dependency checks if this is the pace-core repository itself
|
|
492
|
-
// The library's dependencies are used in packages/core/src/, not in the root src/
|
|
493
|
-
const sourceFiles = [];
|
|
494
|
-
if (!isPaceCoreRepository) {
|
|
495
|
-
try {
|
|
496
|
-
const srcPath = path.join(projectRoot, 'src');
|
|
497
|
-
if (fs.existsSync(srcPath)) {
|
|
498
|
-
sourceFiles.push(...findSourceFiles(srcPath));
|
|
499
|
-
}
|
|
500
|
-
} catch (error) {
|
|
501
|
-
// Skip if can't read source files
|
|
502
|
-
}
|
|
503
|
-
}
|
|
504
|
-
|
|
505
|
-
// Also scan config files
|
|
506
|
-
const configFiles = findConfigFiles(projectRoot);
|
|
507
|
-
|
|
508
|
-
// Find test files separately for better analysis
|
|
509
|
-
const testFiles = !isPaceCoreRepository ? findTestFiles(projectRoot) : [];
|
|
510
|
-
|
|
511
|
-
// Build set of imported packages from source files (runtime)
|
|
512
|
-
const importedPackages = new Set();
|
|
513
|
-
// Build set of packages used only in tests
|
|
514
|
-
const testOnlyPackages = new Set();
|
|
515
|
-
|
|
516
|
-
// Scan source files (runtime code)
|
|
517
|
-
sourceFiles.forEach(filePath => {
|
|
518
|
-
try {
|
|
519
|
-
const content = fs.readFileSync(filePath, 'utf8');
|
|
520
|
-
// Check for ES6 imports
|
|
521
|
-
const importPattern = /from\s+['"]([^'"]+)['"]/g;
|
|
522
|
-
let match;
|
|
523
|
-
while ((match = importPattern.exec(content)) !== null) {
|
|
524
|
-
const modulePath = match[1];
|
|
525
|
-
const pkgName = extractPackageName(modulePath);
|
|
526
|
-
if (pkgName) {
|
|
527
|
-
importedPackages.add(pkgName);
|
|
528
|
-
}
|
|
529
|
-
}
|
|
530
|
-
// Check for require() statements
|
|
531
|
-
const requirePattern = /require\(['"]([^'"]+)['"]\)/g;
|
|
532
|
-
while ((match = requirePattern.exec(content)) !== null) {
|
|
533
|
-
const modulePath = match[1];
|
|
534
|
-
const pkgName = extractPackageName(modulePath);
|
|
535
|
-
if (pkgName) {
|
|
536
|
-
importedPackages.add(pkgName);
|
|
537
|
-
}
|
|
538
|
-
}
|
|
539
|
-
// Check for dynamic imports
|
|
540
|
-
const dynamicImportPattern = /import\(['"]([^'"]+)['"]\)/g;
|
|
541
|
-
while ((match = dynamicImportPattern.exec(content)) !== null) {
|
|
542
|
-
const modulePath = match[1];
|
|
543
|
-
const pkgName = extractPackageName(modulePath);
|
|
544
|
-
if (pkgName) {
|
|
545
|
-
importedPackages.add(pkgName);
|
|
546
|
-
}
|
|
547
|
-
}
|
|
548
|
-
} catch (error) {
|
|
549
|
-
// Skip files with errors
|
|
550
|
-
}
|
|
551
|
-
});
|
|
552
|
-
|
|
553
|
-
// Scan test files separately
|
|
554
|
-
testFiles.forEach(filePath => {
|
|
555
|
-
try {
|
|
556
|
-
const content = fs.readFileSync(filePath, 'utf8');
|
|
557
|
-
const importPattern = /from\s+['"]([^'"]+)['"]/g;
|
|
558
|
-
let match;
|
|
559
|
-
while ((match = importPattern.exec(content)) !== null) {
|
|
560
|
-
const modulePath = match[1];
|
|
561
|
-
const pkgName = extractPackageName(modulePath);
|
|
562
|
-
if (pkgName && !importedPackages.has(pkgName)) {
|
|
563
|
-
// Only add to test-only if not already used in runtime code
|
|
564
|
-
testOnlyPackages.add(pkgName);
|
|
565
|
-
}
|
|
566
|
-
}
|
|
567
|
-
const requirePattern = /require\(['"]([^'"]+)['"]\)/g;
|
|
568
|
-
while ((match = requirePattern.exec(content)) !== null) {
|
|
569
|
-
const modulePath = match[1];
|
|
570
|
-
const pkgName = extractPackageName(modulePath);
|
|
571
|
-
if (pkgName && !importedPackages.has(pkgName)) {
|
|
572
|
-
testOnlyPackages.add(pkgName);
|
|
573
|
-
}
|
|
574
|
-
}
|
|
575
|
-
} catch (error) {
|
|
576
|
-
// Skip files with errors
|
|
577
|
-
}
|
|
578
|
-
});
|
|
579
|
-
|
|
580
|
-
// Scan config files for imports
|
|
581
|
-
configFiles.forEach(filePath => {
|
|
582
|
-
try {
|
|
583
|
-
const content = fs.readFileSync(filePath, 'utf8');
|
|
584
|
-
const importPattern = /from\s+['"]([^'"]+)['"]/g;
|
|
585
|
-
let match;
|
|
586
|
-
while ((match = importPattern.exec(content)) !== null) {
|
|
587
|
-
const modulePath = match[1];
|
|
588
|
-
const pkgName = extractPackageName(modulePath);
|
|
589
|
-
if (pkgName) {
|
|
590
|
-
importedPackages.add(pkgName);
|
|
591
|
-
}
|
|
592
|
-
}
|
|
593
|
-
const requirePattern = /require\(['"]([^'"]+)['"]\)/g;
|
|
594
|
-
while ((match = requirePattern.exec(content)) !== null) {
|
|
595
|
-
const modulePath = match[1];
|
|
596
|
-
const pkgName = extractPackageName(modulePath);
|
|
597
|
-
if (pkgName) {
|
|
598
|
-
importedPackages.add(pkgName);
|
|
599
|
-
}
|
|
600
|
-
}
|
|
601
|
-
} catch (error) {
|
|
602
|
-
// Skip files with errors
|
|
603
|
-
}
|
|
604
|
-
});
|
|
605
|
-
|
|
606
|
-
// Known build tools and dev dependencies that are commonly used but not directly imported
|
|
607
|
-
const knownBuildTools = [
|
|
608
|
-
'vite',
|
|
609
|
-
'typescript',
|
|
610
|
-
'eslint',
|
|
611
|
-
'prettier',
|
|
612
|
-
'vitest',
|
|
613
|
-
'@types',
|
|
614
|
-
'@vitejs',
|
|
615
|
-
'@testing-library',
|
|
616
|
-
'jsdom',
|
|
617
|
-
'globals',
|
|
618
|
-
'tailwindcss',
|
|
619
|
-
'@tailwindcss',
|
|
620
|
-
'postcss',
|
|
621
|
-
'autoprefixer',
|
|
622
|
-
'babel',
|
|
623
|
-
'webpack',
|
|
624
|
-
'rollup',
|
|
625
|
-
'tsup',
|
|
626
|
-
'esbuild',
|
|
627
|
-
'lovable-tagger',
|
|
628
|
-
'babel-plugin-react-compiler',
|
|
629
|
-
];
|
|
630
|
-
|
|
631
|
-
// Check for potentially unused dependencies
|
|
632
|
-
// Skip this check if running on the pace-core repository itself
|
|
633
|
-
// The library's dependencies are used in packages/core/src/, not in the root src/ (demo app)
|
|
634
|
-
if (!isPaceCoreRepository) {
|
|
635
|
-
Object.keys(allDeps).forEach(dep => {
|
|
636
|
-
// Skip if it's a known build tool
|
|
637
|
-
if (knownBuildTools.some(tool => dep.includes(tool) || dep.startsWith(tool))) {
|
|
638
|
-
return;
|
|
639
|
-
}
|
|
640
|
-
|
|
641
|
-
// Skip if it's a peer dependency of pace-core
|
|
642
|
-
if (paceCorePeerDeps[dep]) {
|
|
643
|
-
return;
|
|
644
|
-
}
|
|
645
|
-
|
|
646
|
-
// Skip if it's pace-core itself
|
|
647
|
-
if (dep === '@jmruthers/pace-core') {
|
|
648
|
-
return;
|
|
649
|
-
}
|
|
650
|
-
|
|
651
|
-
// Skip if it's a dependency of pace-core (required by pace-core's bundled code)
|
|
652
|
-
if (!isPaceCoreRepository) {
|
|
653
|
-
const paceCoreDeps = getPaceCoreDeps(projectRoot);
|
|
654
|
-
if (paceCoreDeps[dep]) {
|
|
655
|
-
// This dependency is required by pace-core, so it's not unused
|
|
656
|
-
return;
|
|
657
|
-
}
|
|
658
|
-
}
|
|
659
|
-
|
|
660
|
-
// Check if package is imported in source files (runtime)
|
|
661
|
-
if (importedPackages.has(dep)) {
|
|
662
|
-
// Package is used in runtime code, so it's needed
|
|
663
|
-
return;
|
|
664
|
-
}
|
|
665
|
-
|
|
666
|
-
// Check if it's used in package.json scripts
|
|
667
|
-
if (checkPackageScripts(packageJson, dep)) {
|
|
668
|
-
return;
|
|
669
|
-
}
|
|
670
|
-
|
|
671
|
-
// Check if it's used in config files
|
|
672
|
-
if (checkConfigFiles(configFiles, dep)) {
|
|
673
|
-
return;
|
|
674
|
-
}
|
|
675
|
-
|
|
676
|
-
// Check if it's used in CSS or other non-JS files
|
|
677
|
-
if (checkNonJsFiles(projectRoot, dep)) {
|
|
678
|
-
return;
|
|
679
|
-
}
|
|
680
|
-
|
|
681
|
-
// Check if it's used in test files
|
|
682
|
-
const isUsedInTests = testOnlyPackages.has(dep) || isOnlyUsedInTests(projectRoot, dep, testFiles);
|
|
683
|
-
const isOnlyInTests = isUsedInTests && !importedPackages.has(dep);
|
|
684
|
-
|
|
685
|
-
// For dev dependencies, provide more context
|
|
686
|
-
const isDevDep = dep in devDeps;
|
|
687
|
-
const context = [];
|
|
688
|
-
|
|
689
|
-
if (isDevDep) {
|
|
690
|
-
context.push('This is a dev dependency and may be used by build tools or test frameworks');
|
|
691
|
-
}
|
|
692
|
-
|
|
693
|
-
// Check if it might be a transitive dependency needed by pace-core
|
|
694
|
-
if (paceCoreVersion) {
|
|
695
|
-
context.push('This may be required by @jmruthers/pace-core as a transitive dependency');
|
|
696
|
-
}
|
|
697
|
-
|
|
698
|
-
// Check if it's in vite.config.ts optimizeDeps (common for pace-core peer deps)
|
|
699
|
-
const viteConfigPath = path.join(projectRoot, 'vite.config.ts');
|
|
700
|
-
const viteConfigJsPath = path.join(projectRoot, 'vite.config.js');
|
|
701
|
-
let isInViteConfig = false;
|
|
702
|
-
|
|
703
|
-
for (const configPath of [viteConfigPath, viteConfigJsPath]) {
|
|
704
|
-
if (fs.existsSync(configPath)) {
|
|
705
|
-
try {
|
|
706
|
-
const viteContent = fs.readFileSync(configPath, 'utf8');
|
|
707
|
-
if (viteContent.includes(dep)) {
|
|
708
|
-
isInViteConfig = true;
|
|
709
|
-
break;
|
|
710
|
-
}
|
|
711
|
-
} catch (error) {
|
|
712
|
-
// Skip if can't read
|
|
713
|
-
}
|
|
714
|
-
}
|
|
715
|
-
}
|
|
716
|
-
|
|
717
|
-
// Only warn if we're reasonably sure it's unused
|
|
718
|
-
// For runtime dependencies, be more strict
|
|
719
|
-
if (!isDevDep) {
|
|
720
|
-
// If it's only used in tests, suggest moving to devDependencies
|
|
721
|
-
if (isOnlyInTests) {
|
|
722
|
-
warnings.push({
|
|
723
|
-
type: 'test-only-runtime-dependency',
|
|
724
|
-
file: 'package.json',
|
|
725
|
-
message: `Runtime dependency '${dep}' is only used in test files`,
|
|
726
|
-
recommendation: `Move '${dep}' from dependencies to devDependencies since it's only used in tests. This will reduce your production bundle size.`
|
|
727
|
-
});
|
|
728
|
-
return;
|
|
729
|
-
}
|
|
730
|
-
|
|
731
|
-
const recommendation = `Verify if '${dep}' is actually used. ${context.length > 0 ? context.join(' ') : ''}${isInViteConfig ? 'This dependency is referenced in vite.config.ts, which suggests it may be required by pace-core components. ' : ''}If it's a peer dependency of @jmruthers/pace-core (check pace-core's package.json), it's required even if not directly imported. If confirmed unused, remove it to reduce bundle size.`;
|
|
732
|
-
|
|
733
|
-
warnings.push({
|
|
734
|
-
type: 'unused-dependency',
|
|
735
|
-
file: 'package.json',
|
|
736
|
-
message: `Runtime dependency '${dep}' may be unused`,
|
|
737
|
-
recommendation: recommendation
|
|
738
|
-
});
|
|
739
|
-
} else {
|
|
740
|
-
// For dev dependencies, only suggest (lower severity)
|
|
741
|
-
suggestions.push({
|
|
742
|
-
type: 'potentially-unused-dev-dependency',
|
|
743
|
-
file: 'package.json',
|
|
744
|
-
message: `Dev dependency '${dep}' may be unused`,
|
|
745
|
-
recommendation: `Check if '${dep}' is used in build configs, test files, or by pace-core. ${context.join(' ')}${isInViteConfig ? 'This dependency is referenced in vite.config.ts. ' : ''}If confirmed unused, you can remove it.`
|
|
746
|
-
});
|
|
747
|
-
}
|
|
748
|
-
});
|
|
749
|
-
}
|
|
750
|
-
|
|
751
|
-
// Check for missing peer dependencies from pace-core
|
|
752
|
-
Object.keys(paceCorePeerDeps).forEach(peerDep => {
|
|
753
|
-
if (!allDeps[peerDep]) {
|
|
754
|
-
warnings.push({
|
|
755
|
-
type: 'missing-peer-dependency',
|
|
756
|
-
file: 'package.json',
|
|
757
|
-
message: `Peer dependency '${peerDep}' is missing but required by @jmruthers/pace-core`,
|
|
758
|
-
recommendation: `Install '${peerDep}' as it's required by pace-core. Run: npm install ${peerDep}`
|
|
759
|
-
});
|
|
760
|
-
}
|
|
761
|
-
});
|
|
762
|
-
|
|
763
|
-
// Check for version mismatches between react and react-dom
|
|
764
|
-
// (The required version check is done earlier in the function)
|
|
765
|
-
const reactVersionForMismatch = packageJson.dependencies?.react || packageJson.devDependencies?.react;
|
|
766
|
-
const reactDomVersionForMismatch = packageJson.dependencies?.['react-dom'] || packageJson.devDependencies?.['react-dom'];
|
|
767
|
-
|
|
768
|
-
if (reactVersionForMismatch && reactDomVersionForMismatch && reactVersionForMismatch !== reactDomVersionForMismatch) {
|
|
769
|
-
issues.push({
|
|
770
|
-
type: 'version-mismatch',
|
|
771
|
-
file: 'package.json',
|
|
772
|
-
message: `React version mismatch: react@${reactVersionForMismatch} vs react-dom@${reactDomVersionForMismatch}`,
|
|
773
|
-
recommendation: 'React and react-dom versions must match exactly'
|
|
774
|
-
});
|
|
775
|
-
}
|
|
776
|
-
|
|
777
|
-
// ============================================
|
|
778
|
-
// NEW CHECKS: Future-proofing dependency management
|
|
779
|
-
// ============================================
|
|
780
|
-
|
|
781
|
-
// 1. Check for redundant dependencies in consuming apps
|
|
782
|
-
// (packages already provided by pace-core)
|
|
783
|
-
if (!isPaceCoreRepository) {
|
|
784
|
-
const paceCoreDeps = getPaceCoreDeps(projectRoot);
|
|
785
|
-
const paceCorePeerDeps = getPaceCorePeerDeps(projectRoot);
|
|
786
|
-
|
|
787
|
-
// Packages that pace-core provides as dependencies (should not be duplicated)
|
|
788
|
-
const redundantDeps = [];
|
|
789
|
-
Object.keys(packageJson.dependencies || {}).forEach(dep => {
|
|
790
|
-
// Skip pace-core itself
|
|
791
|
-
if (dep === '@jmruthers/pace-core') {
|
|
792
|
-
return;
|
|
793
|
-
}
|
|
794
|
-
|
|
795
|
-
// Check if it's provided by pace-core as a dependency
|
|
796
|
-
if (paceCoreDeps[dep]) {
|
|
797
|
-
redundantDeps.push({
|
|
798
|
-
dep,
|
|
799
|
-
reason: 'provided by pace-core as a dependency',
|
|
800
|
-
paceCoreVersion: paceCoreDeps[dep]
|
|
801
|
-
});
|
|
802
|
-
}
|
|
803
|
-
});
|
|
804
|
-
|
|
805
|
-
redundantDeps.forEach(({ dep, reason, paceCoreVersion }) => {
|
|
806
|
-
warnings.push({
|
|
807
|
-
type: 'redundant-dependency',
|
|
808
|
-
file: 'package.json',
|
|
809
|
-
message: `Dependency '${dep}' is redundant - ${reason}`,
|
|
810
|
-
recommendation: `Remove '${dep}' from dependencies. It's already provided by @jmruthers/pace-core@${paceCoreVersion}. Exception: If you need a different version or direct control, keep it but document why.`
|
|
811
|
-
});
|
|
812
|
-
});
|
|
813
|
-
}
|
|
814
|
-
|
|
815
|
-
// 2. Check for missing dependencies (used but not declared)
|
|
816
|
-
if (!isPaceCoreRepository) {
|
|
817
|
-
// Check for dynamic imports that might need to be declared
|
|
818
|
-
const optionalDeps = ['recharts', 'papaparse', 'lodash.debounce', 'lodash.throttle'];
|
|
819
|
-
const dynamicImportPattern = /import\(['"]([^'"]+)['"]\)/g;
|
|
820
|
-
|
|
821
|
-
sourceFiles.forEach(filePath => {
|
|
822
|
-
try {
|
|
823
|
-
const content = fs.readFileSync(filePath, 'utf8');
|
|
824
|
-
let match;
|
|
825
|
-
while ((match = dynamicImportPattern.exec(content)) !== null) {
|
|
826
|
-
const modulePath = match[1];
|
|
827
|
-
const pkgName = extractPackageName(modulePath);
|
|
828
|
-
if (pkgName && optionalDeps.includes(pkgName)) {
|
|
829
|
-
// Check if it's declared
|
|
830
|
-
if (!allDeps[pkgName]) {
|
|
831
|
-
suggestions.push({
|
|
832
|
-
type: 'missing-optional-dependency',
|
|
833
|
-
file: path.relative(projectRoot, filePath),
|
|
834
|
-
message: `Optional dependency '${pkgName}' is dynamically imported but not declared`,
|
|
835
|
-
recommendation: `Add '${pkgName}' to dependencies if you use this feature, or ensure it's marked as external in your build config`
|
|
836
|
-
});
|
|
837
|
-
}
|
|
838
|
-
}
|
|
839
|
-
}
|
|
840
|
-
} catch (error) {
|
|
841
|
-
// Skip files with errors
|
|
842
|
-
}
|
|
843
|
-
});
|
|
844
|
-
}
|
|
845
|
-
|
|
846
|
-
// 3. Check for misclassified dependencies
|
|
847
|
-
// Runtime deps in devDependencies, peer deps in dependencies, etc.
|
|
848
|
-
if (isPaceCoreRepository) {
|
|
849
|
-
// Check pace-core's own package.json
|
|
850
|
-
const packagesCorePath = path.join(projectRoot, 'packages', 'core', 'package.json');
|
|
851
|
-
if (fs.existsSync(packagesCorePath)) {
|
|
852
|
-
const corePkg = JSON.parse(fs.readFileSync(packagesCorePath, 'utf8'));
|
|
853
|
-
const coreDeps = corePkg.dependencies || {};
|
|
854
|
-
const coreDevDeps = corePkg.devDependencies || {};
|
|
855
|
-
const corePeerDeps = corePkg.peerDependencies || {};
|
|
856
|
-
|
|
857
|
-
// Check if peer dependencies are incorrectly in dependencies
|
|
858
|
-
Object.keys(coreDeps).forEach(dep => {
|
|
859
|
-
if (corePeerDeps[dep]) {
|
|
860
|
-
issues.push({
|
|
861
|
-
type: 'misclassified-dependency',
|
|
862
|
-
file: 'packages/core/package.json',
|
|
863
|
-
message: `'${dep}' is declared as both dependency and peerDependency`,
|
|
864
|
-
recommendation: `Remove '${dep}' from dependencies. Peer dependencies should only be in peerDependencies.`
|
|
865
|
-
});
|
|
866
|
-
}
|
|
867
|
-
});
|
|
868
|
-
|
|
869
|
-
// Check if runtime dependencies are in devDependencies
|
|
870
|
-
// This is harder to detect automatically, but we can check for common patterns
|
|
871
|
-
const runtimeDepsInDev = ['@hookform/resolvers', '@supabase/supabase-js', '@tanstack/react-query'];
|
|
872
|
-
runtimeDepsInDev.forEach(dep => {
|
|
873
|
-
if (coreDevDeps[dep] && !coreDeps[dep]) {
|
|
874
|
-
// Check if it's used in source code
|
|
875
|
-
const coreSrcPath = path.join(projectRoot, 'packages', 'core', 'src');
|
|
876
|
-
if (fs.existsSync(coreSrcPath)) {
|
|
877
|
-
const coreSourceFiles = findSourceFiles(coreSrcPath);
|
|
878
|
-
let isUsed = false;
|
|
879
|
-
coreSourceFiles.forEach(filePath => {
|
|
880
|
-
try {
|
|
881
|
-
const content = fs.readFileSync(filePath, 'utf8');
|
|
882
|
-
if (content.includes(dep) || content.includes(extractPackageName(dep))) {
|
|
883
|
-
isUsed = true;
|
|
884
|
-
}
|
|
885
|
-
} catch (error) {
|
|
886
|
-
// Skip
|
|
887
|
-
}
|
|
888
|
-
});
|
|
889
|
-
|
|
890
|
-
if (isUsed) {
|
|
891
|
-
warnings.push({
|
|
892
|
-
type: 'misclassified-dependency',
|
|
893
|
-
file: 'packages/core/package.json',
|
|
894
|
-
message: `'${dep}' is in devDependencies but appears to be used in source code`,
|
|
895
|
-
recommendation: `Move '${dep}' from devDependencies to dependencies if it's used at runtime`
|
|
896
|
-
});
|
|
897
|
-
}
|
|
898
|
-
}
|
|
899
|
-
}
|
|
900
|
-
});
|
|
901
|
-
}
|
|
902
|
-
}
|
|
903
|
-
|
|
904
|
-
// 4. Check for version mismatches across workspace (monorepo)
|
|
905
|
-
if (isPaceCoreRepository) {
|
|
906
|
-
const rootPkg = getWorkspaceRootPackageJson(projectRoot);
|
|
907
|
-
const corePkg = getPaceCorePackageJson(projectRoot);
|
|
908
|
-
|
|
909
|
-
if (rootPkg && corePkg) {
|
|
910
|
-
const rootDeps = { ...rootPkg.dependencies, ...rootPkg.devDependencies };
|
|
911
|
-
const coreDeps = { ...corePkg.dependencies, ...corePkg.devDependencies };
|
|
912
|
-
|
|
913
|
-
// Check for version mismatches in common dependencies
|
|
914
|
-
const commonDeps = Object.keys(rootDeps).filter(dep => coreDeps[dep]);
|
|
915
|
-
commonDeps.forEach(dep => {
|
|
916
|
-
const rootVersion = rootDeps[dep];
|
|
917
|
-
const coreVersion = coreDeps[dep];
|
|
918
|
-
|
|
919
|
-
// Normalize versions for comparison (remove ^, ~, etc.)
|
|
920
|
-
const normalizeVersion = (v) => v.replace(/^[\^~]/, '');
|
|
921
|
-
const rootNormalized = normalizeVersion(rootVersion);
|
|
922
|
-
const coreNormalized = normalizeVersion(coreVersion);
|
|
923
|
-
|
|
924
|
-
if (rootNormalized !== coreNormalized) {
|
|
925
|
-
warnings.push({
|
|
926
|
-
type: 'workspace-version-mismatch',
|
|
927
|
-
file: 'package.json',
|
|
928
|
-
message: `Version mismatch for '${dep}': root@${rootVersion} vs packages/core@${coreVersion}`,
|
|
929
|
-
recommendation: `Align versions across workspace. Consider using the same version in both root and packages/core package.json files.`
|
|
930
|
-
});
|
|
931
|
-
}
|
|
932
|
-
});
|
|
933
|
-
}
|
|
934
|
-
}
|
|
935
|
-
|
|
936
|
-
// 5. Check for missing peer dependencies in consuming apps
|
|
937
|
-
if (!isPaceCoreRepository) {
|
|
938
|
-
const paceCorePkg = getPaceCorePackageJson(projectRoot);
|
|
939
|
-
if (paceCorePkg) {
|
|
940
|
-
const peerDeps = paceCorePkg.peerDependencies || {};
|
|
941
|
-
const allDeps = { ...packageJson.dependencies, ...packageJson.devDependencies };
|
|
942
|
-
|
|
943
|
-
Object.keys(peerDeps).forEach(peerDep => {
|
|
944
|
-
if (!allDeps[peerDep]) {
|
|
945
|
-
issues.push({
|
|
946
|
-
type: 'missing-peer-dependency',
|
|
947
|
-
file: 'package.json',
|
|
948
|
-
message: `Missing peer dependency '${peerDep}' required by @jmruthers/pace-core`,
|
|
949
|
-
recommendation: `Install '${peerDep}@${peerDeps[peerDep]}' as a dependency. Run: npm install ${peerDep}@${peerDeps[peerDep]}`
|
|
950
|
-
});
|
|
951
|
-
}
|
|
952
|
-
});
|
|
953
|
-
}
|
|
954
|
-
}
|
|
955
|
-
|
|
956
|
-
// 6. Check for optional dependencies handling in vite.config
|
|
957
|
-
if (!isPaceCoreRepository) {
|
|
958
|
-
const viteConfigPath = path.join(projectRoot, 'vite.config.ts');
|
|
959
|
-
const viteConfigJsPath = path.join(projectRoot, 'vite.config.js');
|
|
960
|
-
const optionalDeps = ['recharts', 'papaparse'];
|
|
961
|
-
|
|
962
|
-
for (const configPath of [viteConfigPath, viteConfigJsPath]) {
|
|
963
|
-
if (fs.existsSync(configPath)) {
|
|
964
|
-
try {
|
|
965
|
-
const viteContent = fs.readFileSync(configPath, 'utf8');
|
|
966
|
-
optionalDeps.forEach(dep => {
|
|
967
|
-
// Check if it's marked as external
|
|
968
|
-
const isExternal = viteContent.includes(`external`) &&
|
|
969
|
-
(viteContent.includes(`'${dep}'`) || viteContent.includes(`"${dep}"`));
|
|
970
|
-
|
|
971
|
-
// Check if it's in dependencies
|
|
972
|
-
const isInDeps = allDeps[dep];
|
|
973
|
-
|
|
974
|
-
if (!isExternal && !isInDeps) {
|
|
975
|
-
suggestions.push({
|
|
976
|
-
type: 'optional-dependency-config',
|
|
977
|
-
file: path.relative(projectRoot, configPath),
|
|
978
|
-
message: `Optional dependency '${dep}' should be handled in build config`,
|
|
979
|
-
recommendation: `Add '${dep}' to build.rollupOptions.external if you want it resolved at runtime, or install it as a dependency if you want it bundled`
|
|
980
|
-
});
|
|
981
|
-
}
|
|
982
|
-
});
|
|
983
|
-
} catch (error) {
|
|
984
|
-
// Skip if can't read
|
|
985
|
-
}
|
|
986
|
-
}
|
|
987
|
-
}
|
|
988
|
-
}
|
|
989
|
-
|
|
990
|
-
return { issues, warnings, suggestions };
|
|
991
|
-
}
|
|
992
|
-
};
|
|
993
|
-
|
|
994
|
-
module.exports = dependenciesCheck;
|