@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.
Files changed (473) hide show
  1. package/CHANGELOG.md +104 -0
  2. package/README.md +5 -403
  3. package/audit-tool/00-dependencies.cjs +394 -0
  4. package/audit-tool/audits/01-pace-core-compliance.cjs +556 -0
  5. package/audit-tool/audits/02-project-structure.cjs +255 -0
  6. package/audit-tool/audits/03-architecture.cjs +196 -0
  7. package/audit-tool/audits/04-code-quality.cjs +149 -0
  8. package/audit-tool/audits/05-styling.cjs +224 -0
  9. package/audit-tool/audits/06-security-rbac.cjs +544 -0
  10. package/audit-tool/audits/07-api-tech-stack.cjs +301 -0
  11. package/audit-tool/audits/08-testing-documentation.cjs +202 -0
  12. package/audit-tool/audits/09-operations.cjs +208 -0
  13. package/audit-tool/index.cjs +291 -0
  14. package/audit-tool/utils/code-utils.cjs +218 -0
  15. package/audit-tool/utils/file-utils.cjs +230 -0
  16. package/audit-tool/utils/report-utils.cjs +241 -0
  17. package/core-usage-manifest.json +93 -0
  18. package/cursor-rules/00-standards-overview.mdc +156 -0
  19. package/cursor-rules/01-pace-core-compliance.mdc +586 -0
  20. package/cursor-rules/02-project-structure.mdc +42 -4
  21. package/cursor-rules/{03-solid-principles.mdc → 03-architecture.mdc} +126 -10
  22. package/cursor-rules/04-code-quality.mdc +419 -0
  23. package/cursor-rules/{08-markup-quality.mdc → 05-styling.mdc} +104 -34
  24. package/cursor-rules/06-security-rbac.mdc +518 -0
  25. package/cursor-rules/07-api-tech-stack.mdc +377 -0
  26. package/cursor-rules/08-testing-documentation.mdc +324 -0
  27. package/cursor-rules/09-operations.mdc +365 -0
  28. package/dist/{AuthService-Cb34EQs3.d.ts → AuthService-DmfO5rGS.d.ts} +10 -0
  29. package/dist/DataTable-7PMH7XN7.js +15 -0
  30. package/dist/{DataTable-BMRU8a1j.d.ts → DataTable-DRUIgtUH.d.ts} +1 -1
  31. package/dist/{PublicPageProvider-QTFVrL-Z.d.ts → PublicPageProvider-DlsCaR5v.d.ts} +33 -72
  32. package/dist/UnifiedAuthProvider-ZT6TIGM7.js +7 -0
  33. package/dist/api-Y4MQWOFW.js +4 -0
  34. package/dist/audit-MYQXYZFU.js +3 -0
  35. package/dist/{chunk-DGUM43GV.js → chunk-3RG5ZIWI.js} +1 -4
  36. package/dist/{chunk-QXHPKYJV.js → chunk-4SXLQIZO.js} +1 -26
  37. package/dist/{chunk-UPPMRMYG.js → chunk-5X4QLXRG.js} +73 -151
  38. package/dist/chunk-6F3IILHI.js +62 -0
  39. package/dist/{chunk-E66EQZE6.js → chunk-6GLLNA6U.js} +3 -9
  40. package/dist/{chunk-ZSAAAMVR.js → chunk-6QYDGKQY.js} +1 -4
  41. package/dist/{chunk-FMUCXFII.js → chunk-7ILTDCL2.js} +9 -5
  42. package/dist/{chunk-M43Y4SSO.js → chunk-A3W6LW53.js} +15 -13
  43. package/dist/{chunk-63FOKYGO.js → chunk-AHU7G2R5.js} +2 -11
  44. package/dist/{chunk-HU2C6SSC.js → chunk-BM4CQ5P3.js} +606 -559
  45. package/dist/chunk-C7NSAPTL.js +1 -0
  46. package/dist/{chunk-J36DSWQK.js → chunk-FEJLJNWA.js} +7 -41
  47. package/dist/{chunk-IHB5DR3H.js → chunk-FTCRZOG2.js} +188 -387
  48. package/dist/{chunk-G37KK66H.js → chunk-FYHN4DD5.js} +60 -19
  49. package/dist/chunk-GHYHJTYV.js +994 -0
  50. package/dist/{chunk-VBXEHIUJ.js → chunk-HF6O3O37.js} +6 -88
  51. package/dist/{chunk-FFQEQTNW.js → chunk-IUBRCBSY.js} +134 -45
  52. package/dist/{chunk-6COVEUS7.js → chunk-JGWDVX64.js} +983 -1034
  53. package/dist/{chunk-RGAWHO7N.js → chunk-L4XMVJKY.js} +77 -222
  54. package/dist/chunk-MBADTM7L.js +64 -0
  55. package/dist/{chunk-M7MPQISP.js → chunk-OJ4SKRSV.js} +3 -16
  56. package/dist/{chunk-IVOFDYWT.js → chunk-Q7Q7V5NV.js} +2109 -1604
  57. package/dist/{chunk-JGRYX5UX.js → chunk-S7DKJPLT.js} +29 -58
  58. package/dist/{chunk-PWLANIRT.js → chunk-TTRFSOKR.js} +1 -7
  59. package/dist/{chunk-5DRSZLL2.js → chunk-UH3NTO3F.js} +1 -6
  60. package/dist/{chunk-NTM7ZSB6.js → chunk-VBCS3DUA.js} +261 -168
  61. package/dist/{chunk-EFN2EIMK.js → chunk-ZFYPMX46.js} +271 -87
  62. package/dist/{chunk-L4OXEN46.js → chunk-ZKAWKYT4.js} +10 -24
  63. package/dist/components.d.ts +7 -5
  64. package/dist/components.js +46 -257
  65. package/dist/{database.generated-CzIvgcPu.d.ts → database.generated-CcnC_DRc.d.ts} +4795 -3691
  66. package/dist/eslint-rules/index.cjs +35 -0
  67. package/{src/eslint-rules/pace-core-compliance.cjs → dist/eslint-rules/rules/01-pace-core-compliance.cjs} +234 -235
  68. package/dist/eslint-rules/rules/04-code-quality.cjs +290 -0
  69. package/dist/eslint-rules/rules/05-styling.cjs +61 -0
  70. package/dist/eslint-rules/rules/06-security-rbac.cjs +806 -0
  71. package/dist/eslint-rules/rules/07-api-tech-stack.cjs +263 -0
  72. package/dist/eslint-rules/rules/08-testing.cjs +94 -0
  73. package/dist/eslint-rules/utils/helpers.cjs +42 -0
  74. package/dist/eslint-rules/utils/manifest-loader.cjs +75 -0
  75. package/dist/hooks.d.ts +6 -6
  76. package/dist/hooks.js +62 -172
  77. package/dist/icons/index.d.ts +1 -0
  78. package/dist/icons/index.js +1 -0
  79. package/dist/index.d.ts +12 -11
  80. package/dist/index.js +67 -660
  81. package/dist/providers.d.ts +2 -2
  82. package/dist/providers.js +8 -35
  83. package/dist/rbac/eslint-rules.d.ts +46 -44
  84. package/dist/rbac/eslint-rules.js +7 -4
  85. package/dist/rbac/index.d.ts +109 -586
  86. package/dist/rbac/index.js +14 -207
  87. package/dist/styles/index.js +2 -12
  88. package/dist/theming/runtime.d.ts +14 -1
  89. package/dist/theming/runtime.js +3 -19
  90. package/dist/{timezone-CHhWg6b4.d.ts → timezone-BZe_eUxx.d.ts} +175 -1
  91. package/dist/{types-CkbwOr4Y.d.ts → types-DXstZpNI.d.ts} +4 -17
  92. package/dist/types-t9H8qKRw.d.ts +55 -0
  93. package/dist/types.d.ts +1 -1
  94. package/dist/types.js +7 -94
  95. package/dist/{usePublicRouteParams-ClnV4tnv.d.ts → usePublicRouteParams-MamNgwqe.d.ts} +20 -20
  96. package/dist/utils.d.ts +24 -117
  97. package/dist/utils.js +54 -392
  98. package/docs/README.md +17 -7
  99. package/docs/api/README.md +4 -402
  100. package/docs/api/modules.md +301 -871
  101. package/docs/api-reference/components.md +21 -21
  102. package/docs/api-reference/deprecated.md +31 -6
  103. package/docs/api-reference/hooks.md +80 -80
  104. package/docs/api-reference/rpc-functions.md +78 -3
  105. package/docs/api-reference/types.md +1 -1
  106. package/docs/api-reference/utilities.md +1 -1
  107. package/docs/architecture/README.md +1 -1
  108. package/docs/core-concepts/events.md +3 -3
  109. package/docs/core-concepts/organisations.md +6 -6
  110. package/docs/core-concepts/permissions.md +6 -6
  111. package/docs/documentation-index.md +12 -18
  112. package/docs/getting-started/cursor-rules.md +3 -23
  113. package/docs/getting-started/dependencies.md +650 -0
  114. package/docs/getting-started/documentation-index.md +1 -1
  115. package/docs/getting-started/examples/README.md +4 -4
  116. package/docs/getting-started/examples/full-featured-app.md +1 -1
  117. package/docs/getting-started/faq.md +2 -2
  118. package/docs/getting-started/installation-guide.md +20 -7
  119. package/docs/getting-started/quick-reference.md +4 -4
  120. package/docs/getting-started/quick-start.md +23 -12
  121. package/docs/implementation-guides/authentication.md +15 -15
  122. package/docs/implementation-guides/component-styling.md +1 -1
  123. package/docs/implementation-guides/data-tables.md +126 -33
  124. package/docs/implementation-guides/datatable-rbac-usage.md +1 -1
  125. package/docs/implementation-guides/dynamic-colors.md +3 -3
  126. package/docs/implementation-guides/file-upload-storage.md +2 -2
  127. package/docs/implementation-guides/hierarchical-datatable.md +40 -60
  128. package/docs/implementation-guides/inactivity-tracking.md +3 -3
  129. package/docs/implementation-guides/large-datasets.md +3 -2
  130. package/docs/implementation-guides/organisation-security.md +2 -2
  131. package/docs/implementation-guides/performance.md +2 -2
  132. package/docs/implementation-guides/permission-enforcement.md +5 -1
  133. package/docs/migration/V0.3.44_organisation-context-timing-fix.md +1 -1
  134. package/docs/migration/V0.4.0_rbac-migration.md +6 -6
  135. package/docs/rbac/MIGRATION_GUIDE.md +819 -0
  136. package/docs/rbac/RBAC_CONTRACT.md +724 -0
  137. package/docs/rbac/README.md +17 -8
  138. package/docs/rbac/advanced-patterns.md +6 -6
  139. package/docs/rbac/api-reference.md +20 -20
  140. package/docs/rbac/edge-functions-guide.md +376 -0
  141. package/docs/rbac/event-based-apps.md +3 -3
  142. package/docs/rbac/examples.md +41 -41
  143. package/docs/rbac/getting-started.md +37 -37
  144. package/docs/rbac/performance.md +1 -1
  145. package/docs/rbac/quick-start.md +52 -52
  146. package/docs/rbac/secure-client-protection.md +1 -35
  147. package/docs/rbac/troubleshooting.md +1 -1
  148. package/docs/security/README.md +5 -5
  149. package/docs/standards/0-standards-overview.md +220 -0
  150. package/docs/standards/1-pace-core-compliance-standards.md +986 -0
  151. package/docs/standards/2-project-structure-standards.md +949 -0
  152. package/docs/standards/3-architecture-standards.md +606 -0
  153. package/docs/standards/4-code-quality-standards.md +728 -0
  154. package/docs/standards/5-styling-standards.md +348 -0
  155. package/docs/standards/{07-rbac-and-rls-standard.md → 6-security-rbac-standards.md} +269 -66
  156. package/docs/standards/7-api-tech-stack-standards.md +662 -0
  157. package/docs/standards/8-testing-documentation-standards.md +401 -0
  158. package/docs/standards/9-operations-standards.md +1102 -0
  159. package/docs/standards/README.md +185 -57
  160. package/docs/troubleshooting/README.md +4 -4
  161. package/docs/troubleshooting/common-issues.md +2 -2
  162. package/docs/troubleshooting/debugging.md +9 -9
  163. package/docs/troubleshooting/migration.md +4 -4
  164. package/docs/troubleshooting/organisation-context-setup.md +42 -19
  165. package/eslint-config-pace-core.cjs +33 -6
  166. package/package.json +35 -23
  167. package/scripts/install-cursor-rules.cjs +25 -6
  168. package/scripts/install-eslint-config.cjs +284 -0
  169. package/src/__tests__/fixtures/supabase.ts +1 -1
  170. package/src/__tests__/helpers/__tests__/component-test-utils.test.tsx +3 -3
  171. package/src/__tests__/helpers/__tests__/optimized-test-setup.test.ts +1 -1
  172. package/src/__tests__/helpers/__tests__/supabaseMock.test.ts +1 -1
  173. package/src/__tests__/helpers/__tests__/test-providers.test.tsx +2 -2
  174. package/src/__tests__/helpers/__tests__/test-utils.test.tsx +13 -13
  175. package/src/__tests__/helpers/component-test-utils.tsx +1 -1
  176. package/src/__tests__/helpers/supabaseMock.ts +2 -2
  177. package/src/__tests__/integration/UserProfile.test.tsx +14 -14
  178. package/src/__tests__/public-recipe-view.test.ts +38 -9
  179. package/src/__tests__/rbac/PagePermissionGuard.test.tsx +6 -6
  180. package/src/__tests__/templates/accessibility.test.template.tsx +9 -9
  181. package/src/__tests__/templates/component.test.template.tsx +18 -15
  182. package/src/components/Button/Button.tsx +5 -1
  183. package/src/components/Calendar/Calendar.tsx +201 -47
  184. package/src/components/ContextSelector/ContextSelector.tsx +106 -119
  185. package/src/components/DataTable/AUDIT_REPORT.md +293 -0
  186. package/src/components/DataTable/__tests__/DataTableCore.test.tsx +10 -2
  187. package/src/components/DataTable/__tests__/a11y.basic.test.tsx +10 -4
  188. package/src/components/DataTable/__tests__/test-utils/sharedTestUtils.tsx +9 -9
  189. package/src/components/DataTable/components/ColumnFilter.tsx +63 -74
  190. package/src/components/DataTable/components/ColumnVisibilityDropdown.tsx +43 -41
  191. package/src/components/DataTable/components/DataTableCore.tsx +186 -13
  192. package/src/components/DataTable/components/DataTableErrorBoundary.tsx +9 -11
  193. package/src/components/DataTable/components/DataTableLayout.tsx +35 -21
  194. package/src/components/DataTable/components/EditFields.tsx +23 -3
  195. package/src/components/DataTable/components/EditableRow.tsx +12 -9
  196. package/src/components/DataTable/components/EmptyState.tsx +10 -9
  197. package/src/components/DataTable/components/FilterRow.tsx +2 -4
  198. package/src/components/DataTable/components/ImportModal.tsx +124 -126
  199. package/src/components/DataTable/components/LoadingState.tsx +5 -6
  200. package/src/components/DataTable/components/RowComponent.tsx +12 -0
  201. package/src/components/DataTable/components/SortIndicator.tsx +50 -0
  202. package/src/components/DataTable/components/__tests__/COVERAGE_NOTE.md +4 -4
  203. package/src/components/DataTable/components/__tests__/ColumnFilter.test.tsx +23 -82
  204. package/src/components/DataTable/components/__tests__/DataTableErrorBoundary.test.tsx +37 -9
  205. package/src/components/DataTable/components/__tests__/EmptyState.test.tsx +7 -4
  206. package/src/components/DataTable/components/__tests__/FilterRow.test.tsx +12 -4
  207. package/src/components/DataTable/components/__tests__/LoadingState.test.tsx +41 -27
  208. package/src/components/DataTable/components/hooks/usePermissionTracking.ts +0 -4
  209. package/src/components/DataTable/components/index.ts +2 -1
  210. package/src/components/DataTable/hooks/__tests__/useDataTableState.test.ts +51 -47
  211. package/src/components/DataTable/hooks/useDataTablePermissions.ts +24 -21
  212. package/src/components/DataTable/hooks/useDataTableState.ts +125 -9
  213. package/src/components/DataTable/hooks/useTableColumns.ts +40 -2
  214. package/src/components/DataTable/hooks/useTableHandlers.ts +11 -0
  215. package/src/components/DataTable/types.ts +5 -18
  216. package/src/components/DataTable/utils/a11yUtils.ts +17 -0
  217. package/src/components/DatePickerWithTimezone/DatePickerWithTimezone.test.tsx +2 -1
  218. package/src/components/DatePickerWithTimezone/DatePickerWithTimezone.tsx +11 -15
  219. package/src/components/DateTimeField/DateTimeField.tsx +10 -9
  220. package/src/components/Dialog/Dialog.test.tsx +128 -104
  221. package/src/components/Dialog/Dialog.tsx +742 -24
  222. package/src/components/ErrorBoundary/ErrorBoundary.tsx +77 -79
  223. package/src/components/FileDisplay/FileDisplay.test.tsx +4 -2
  224. package/src/components/FileDisplay/FileDisplay.tsx +23 -17
  225. package/src/components/FileUpload/FileUpload.test.tsx +52 -14
  226. package/src/components/FileUpload/FileUpload.tsx +112 -130
  227. package/src/components/Form/Form.test.tsx +6 -8
  228. package/src/components/Form/Form.tsx +365 -4
  229. package/src/components/NavigationMenu/NavigationMenu.test.tsx +14 -13
  230. package/src/components/NavigationMenu/useNavigationFiltering.ts +11 -21
  231. package/src/components/PaceAppLayout/PaceAppLayout.test.tsx +6 -4
  232. package/src/components/PaceAppLayout/PaceAppLayout.tsx +11 -15
  233. package/src/components/PaceLoginPage/PaceLoginPage.test.tsx +108 -61
  234. package/src/components/PaceLoginPage/PaceLoginPage.tsx +27 -3
  235. package/src/components/Progress/Progress.tsx +2 -4
  236. package/src/components/ProtectedRoute/ProtectedRoute.tsx +8 -8
  237. package/src/components/Select/Select.tsx +109 -98
  238. package/src/components/Select/types.ts +4 -1
  239. package/src/components/UserMenu/UserMenu.tsx +9 -6
  240. package/src/hooks/__tests__/ServiceHooks.test.tsx +16 -16
  241. package/src/hooks/__tests__/hooks.integration.test.tsx +55 -57
  242. package/src/hooks/__tests__/useAppConfig.unit.test.ts +129 -67
  243. package/src/hooks/__tests__/useFocusTrap.unit.test.tsx +97 -97
  244. package/src/hooks/__tests__/usePublicEvent.simple.test.ts +149 -67
  245. package/src/hooks/__tests__/usePublicEvent.test.ts +149 -79
  246. package/src/hooks/__tests__/usePublicEvent.unit.test.ts +158 -109
  247. package/src/hooks/__tests__/useSessionDraft.test.ts +163 -0
  248. package/src/hooks/__tests__/useSessionRestoration.unit.test.tsx +10 -5
  249. package/src/hooks/public/usePublicEvent.ts +67 -195
  250. package/src/hooks/public/usePublicEventLogo.test.ts +70 -17
  251. package/src/hooks/public/usePublicEventLogo.ts +24 -14
  252. package/src/hooks/public/usePublicFileDisplay.ts +2 -2
  253. package/src/hooks/public/usePublicRouteParams.ts +5 -5
  254. package/src/hooks/useAppConfig.ts +28 -26
  255. package/src/hooks/useEventTheme.test.ts +217 -239
  256. package/src/hooks/useEventTheme.ts +16 -28
  257. package/src/hooks/useFileDisplay.ts +2 -2
  258. package/src/hooks/useOrganisationPermissions.ts +5 -7
  259. package/src/hooks/useQueryCache.ts +0 -1
  260. package/src/hooks/useSessionDraft.ts +380 -0
  261. package/src/hooks/useSessionRestoration.ts +3 -1
  262. package/src/icons/index.ts +27 -0
  263. package/src/index.ts +5 -0
  264. package/src/providers/OrganisationProvider.tsx +23 -14
  265. package/src/providers/UnifiedAuthProvider.smoke.test.tsx +21 -21
  266. package/src/providers/__tests__/AuthProvider.test.tsx +21 -21
  267. package/src/providers/__tests__/EventProvider.test.tsx +61 -61
  268. package/src/providers/__tests__/InactivityProvider.test.tsx +56 -56
  269. package/src/providers/__tests__/OrganisationProvider.test.tsx +75 -75
  270. package/src/providers/__tests__/ProviderLifecycle.test.tsx +37 -37
  271. package/src/providers/__tests__/UnifiedAuthProvider.test.tsx +103 -103
  272. package/src/providers/services/EventServiceProvider.tsx +1 -24
  273. package/src/providers/services/UnifiedAuthProvider.tsx +5 -48
  274. package/src/providers/services/__tests__/AuthServiceProvider.integration.test.tsx +7 -7
  275. package/src/providers/services/__tests__/UnifiedAuthProvider.integration.test.tsx +13 -10
  276. package/src/rbac/__tests__/adapters.comprehensive.test.tsx +7 -457
  277. package/src/rbac/__tests__/auth-rbac.e2e.test.tsx +33 -7
  278. package/src/rbac/adapters.tsx +7 -295
  279. package/src/rbac/api.test.ts +44 -56
  280. package/src/rbac/api.ts +10 -17
  281. package/src/rbac/cache-invalidation.ts +0 -1
  282. package/src/rbac/compliance/index.ts +10 -0
  283. package/src/rbac/compliance/pattern-detector.ts +553 -0
  284. package/src/rbac/compliance/runtime-compliance.ts +22 -0
  285. package/src/rbac/components/AccessDenied.tsx +150 -0
  286. package/src/rbac/components/NavigationGuard.tsx +12 -20
  287. package/src/rbac/components/PagePermissionGuard.tsx +4 -24
  288. package/src/rbac/components/__tests__/NavigationGuard.test.tsx +21 -8
  289. package/src/rbac/components/index.ts +3 -41
  290. package/src/rbac/eslint-rules.js +1 -1
  291. package/src/rbac/hooks/index.ts +0 -3
  292. package/src/rbac/hooks/permissions/index.ts +0 -3
  293. package/src/rbac/hooks/permissions/useAccessLevel.ts +4 -8
  294. package/src/rbac/hooks/usePermissions.ts +0 -3
  295. package/src/rbac/hooks/useResolvedScope.test.ts +57 -47
  296. package/src/rbac/hooks/useResolvedScope.ts +58 -140
  297. package/src/rbac/hooks/useResourcePermissions.test.ts +124 -38
  298. package/src/rbac/hooks/useResourcePermissions.ts +139 -48
  299. package/src/rbac/hooks/useRoleManagement.test.ts +65 -22
  300. package/src/rbac/hooks/useRoleManagement.ts +147 -19
  301. package/src/rbac/hooks/useSecureSupabase.ts +4 -8
  302. package/src/rbac/index.ts +7 -9
  303. package/src/rbac/utils/contextValidator.ts +9 -7
  304. package/src/services/AuthService.ts +130 -18
  305. package/src/services/EventService.ts +4 -97
  306. package/src/services/InactivityService.ts +16 -0
  307. package/src/services/OrganisationService.ts +7 -44
  308. package/src/services/__tests__/OrganisationService.test.ts +26 -8
  309. package/src/services/base/BaseService.ts +0 -3
  310. package/src/styles/core.css +7 -0
  311. package/src/theming/__tests__/parseEventColours.test.ts +9 -3
  312. package/src/theming/parseEventColours.ts +22 -10
  313. package/src/types/database.generated.ts +4733 -3809
  314. package/src/utils/__tests__/lazyLoad.unit.test.tsx +42 -39
  315. package/src/utils/__tests__/organisationContext.unit.test.ts +9 -10
  316. package/src/utils/context/organisationContext.test.ts +13 -28
  317. package/src/utils/context/organisationContext.ts +21 -52
  318. package/src/utils/dynamic/dynamicUtils.ts +1 -1
  319. package/src/utils/file-reference/index.ts +39 -15
  320. package/src/utils/formatting/formatDateTime.test.ts +3 -2
  321. package/src/utils/google-places/loadGoogleMapsScript.ts +29 -4
  322. package/src/utils/index.ts +4 -1
  323. package/src/utils/persistence/__tests__/keyDerivation.test.ts +135 -0
  324. package/src/utils/persistence/__tests__/sensitiveFieldDetection.test.ts +123 -0
  325. package/src/utils/persistence/keyDerivation.ts +304 -0
  326. package/src/utils/persistence/sensitiveFieldDetection.ts +212 -0
  327. package/src/utils/security/secureStorage.ts +5 -5
  328. package/src/utils/storage/README.md +1 -1
  329. package/src/utils/storage/helpers.ts +3 -3
  330. package/src/utils/supabase/createBaseClient.ts +147 -0
  331. package/src/utils/timezone/timezone.test.ts +1 -2
  332. package/src/utils/timezone/timezone.ts +1 -1
  333. package/src/utils/validation/csrf.ts +4 -4
  334. package/cursor-rules/00-pace-core-compliance.mdc +0 -331
  335. package/cursor-rules/01-standards-compliance.mdc +0 -244
  336. package/cursor-rules/04-testing-standards.mdc +0 -268
  337. package/cursor-rules/05-bug-reports-and-features.mdc +0 -246
  338. package/cursor-rules/06-code-quality.mdc +0 -309
  339. package/cursor-rules/07-tech-stack-compliance.mdc +0 -214
  340. package/cursor-rules/CHANGELOG.md +0 -119
  341. package/cursor-rules/README.md +0 -192
  342. package/dist/DataTable-AOVNCPTX.js +0 -175
  343. package/dist/DataTable-AOVNCPTX.js.map +0 -1
  344. package/dist/UnifiedAuthProvider-4SBX4LU5.js +0 -18
  345. package/dist/UnifiedAuthProvider-4SBX4LU5.js.map +0 -1
  346. package/dist/api-O6HTBX5Y.js +0 -52
  347. package/dist/api-O6HTBX5Y.js.map +0 -1
  348. package/dist/audit-V53FV5AG.js +0 -17
  349. package/dist/audit-V53FV5AG.js.map +0 -1
  350. package/dist/chunk-5DRSZLL2.js.map +0 -1
  351. package/dist/chunk-63FOKYGO.js.map +0 -1
  352. package/dist/chunk-6COVEUS7.js.map +0 -1
  353. package/dist/chunk-AFVQODI2.js +0 -263
  354. package/dist/chunk-AFVQODI2.js.map +0 -1
  355. package/dist/chunk-DGUM43GV.js.map +0 -1
  356. package/dist/chunk-E66EQZE6.js.map +0 -1
  357. package/dist/chunk-EFN2EIMK.js.map +0 -1
  358. package/dist/chunk-FFQEQTNW.js.map +0 -1
  359. package/dist/chunk-FMUCXFII.js.map +0 -1
  360. package/dist/chunk-G37KK66H.js.map +0 -1
  361. package/dist/chunk-G7QEZTYQ.js +0 -2053
  362. package/dist/chunk-G7QEZTYQ.js.map +0 -1
  363. package/dist/chunk-HU2C6SSC.js.map +0 -1
  364. package/dist/chunk-IHB5DR3H.js.map +0 -1
  365. package/dist/chunk-IVOFDYWT.js.map +0 -1
  366. package/dist/chunk-J36DSWQK.js.map +0 -1
  367. package/dist/chunk-JGRYX5UX.js.map +0 -1
  368. package/dist/chunk-KQCRWDSA.js +0 -1
  369. package/dist/chunk-KQCRWDSA.js.map +0 -1
  370. package/dist/chunk-L4OXEN46.js.map +0 -1
  371. package/dist/chunk-LMC26NLJ.js +0 -84
  372. package/dist/chunk-LMC26NLJ.js.map +0 -1
  373. package/dist/chunk-M43Y4SSO.js.map +0 -1
  374. package/dist/chunk-M7MPQISP.js.map +0 -1
  375. package/dist/chunk-NTM7ZSB6.js.map +0 -1
  376. package/dist/chunk-PWLANIRT.js.map +0 -1
  377. package/dist/chunk-QXHPKYJV.js.map +0 -1
  378. package/dist/chunk-RGAWHO7N.js.map +0 -1
  379. package/dist/chunk-UPPMRMYG.js.map +0 -1
  380. package/dist/chunk-VBXEHIUJ.js.map +0 -1
  381. package/dist/chunk-ZSAAAMVR.js.map +0 -1
  382. package/dist/components.js.map +0 -1
  383. package/dist/contextValidator-5OGXSPKS.js +0 -9
  384. package/dist/contextValidator-5OGXSPKS.js.map +0 -1
  385. package/dist/eslint-rules/pace-core-compliance.cjs +0 -510
  386. package/dist/hooks.js.map +0 -1
  387. package/dist/index.js.map +0 -1
  388. package/dist/providers.js.map +0 -1
  389. package/dist/rbac/eslint-rules.js.map +0 -1
  390. package/dist/rbac/index.js.map +0 -1
  391. package/dist/styles/index.js.map +0 -1
  392. package/dist/theming/runtime.js.map +0 -1
  393. package/dist/types.js.map +0 -1
  394. package/dist/utils.js.map +0 -1
  395. package/docs/best-practices/README.md +0 -472
  396. package/docs/best-practices/accessibility.md +0 -601
  397. package/docs/best-practices/common-patterns.md +0 -516
  398. package/docs/best-practices/deployment.md +0 -1103
  399. package/docs/best-practices/performance.md +0 -1328
  400. package/docs/best-practices/security.md +0 -940
  401. package/docs/best-practices/testing.md +0 -1034
  402. package/docs/rbac/compliance/compliance-guide.md +0 -544
  403. package/docs/standards/01-architecture-standard.md +0 -44
  404. package/docs/standards/02-api-and-rpc-standard.md +0 -39
  405. package/docs/standards/03-component-standard.md +0 -32
  406. package/docs/standards/04-code-style-standard.md +0 -32
  407. package/docs/standards/05-security-standard.md +0 -44
  408. package/docs/standards/06-testing-and-docs-standard.md +0 -29
  409. package/docs/standards/pace-core-compliance.md +0 -432
  410. package/scripts/audit/core/checks/accessibility.cjs +0 -197
  411. package/scripts/audit/core/checks/api-usage.cjs +0 -191
  412. package/scripts/audit/core/checks/bundle.cjs +0 -142
  413. package/scripts/audit/core/checks/compliance.cjs +0 -2706
  414. package/scripts/audit/core/checks/config.cjs +0 -54
  415. package/scripts/audit/core/checks/coverage.cjs +0 -84
  416. package/scripts/audit/core/checks/dependencies.cjs +0 -994
  417. package/scripts/audit/core/checks/documentation.cjs +0 -268
  418. package/scripts/audit/core/checks/environment.cjs +0 -116
  419. package/scripts/audit/core/checks/error-handling.cjs +0 -340
  420. package/scripts/audit/core/checks/forms.cjs +0 -172
  421. package/scripts/audit/core/checks/heuristics.cjs +0 -68
  422. package/scripts/audit/core/checks/hooks.cjs +0 -334
  423. package/scripts/audit/core/checks/imports.cjs +0 -244
  424. package/scripts/audit/core/checks/performance.cjs +0 -325
  425. package/scripts/audit/core/checks/routes.cjs +0 -117
  426. package/scripts/audit/core/checks/state.cjs +0 -130
  427. package/scripts/audit/core/checks/structure.cjs +0 -65
  428. package/scripts/audit/core/checks/style.cjs +0 -584
  429. package/scripts/audit/core/checks/testing.cjs +0 -122
  430. package/scripts/audit/core/checks/typescript.cjs +0 -61
  431. package/scripts/audit/core/scanner.cjs +0 -199
  432. package/scripts/audit/core/utils.cjs +0 -137
  433. package/scripts/audit/index.cjs +0 -223
  434. package/scripts/audit/reporters/console.cjs +0 -151
  435. package/scripts/audit/reporters/json.cjs +0 -54
  436. package/scripts/audit/reporters/markdown.cjs +0 -124
  437. package/scripts/audit-consuming-app.cjs +0 -86
  438. package/src/components/DataTable/components/DataTableBody.tsx +0 -454
  439. package/src/components/DataTable/components/DraggableColumnHeader.tsx +0 -156
  440. package/src/components/DataTable/components/ExpandButton.tsx +0 -113
  441. package/src/components/DataTable/components/GroupHeader.tsx +0 -54
  442. package/src/components/DataTable/components/ViewRowModal.tsx +0 -68
  443. package/src/components/DataTable/components/VirtualizedDataTable.tsx +0 -525
  444. package/src/components/DataTable/components/__tests__/ExpandButton.test.tsx +0 -462
  445. package/src/components/DataTable/components/__tests__/GroupHeader.test.tsx +0 -393
  446. package/src/components/DataTable/components/__tests__/ViewRowModal.test.tsx +0 -476
  447. package/src/components/DataTable/components/__tests__/VirtualizedDataTable.test.tsx +0 -128
  448. package/src/components/DataTable/core/DataTableContext.tsx +0 -216
  449. package/src/components/DataTable/core/__tests__/DataTableContext.test.tsx +0 -136
  450. package/src/components/DataTable/hooks/__tests__/useColumnReordering.test.ts +0 -570
  451. package/src/components/DataTable/hooks/useColumnReordering.ts +0 -123
  452. package/src/components/DataTable/utils/debugTools.ts +0 -514
  453. package/src/eslint-rules/pace-core-compliance.js +0 -638
  454. package/src/rbac/components/EnhancedNavigationMenu.test.tsx +0 -555
  455. package/src/rbac/components/EnhancedNavigationMenu.tsx +0 -293
  456. package/src/rbac/components/NavigationProvider.test.tsx +0 -481
  457. package/src/rbac/components/NavigationProvider.tsx +0 -345
  458. package/src/rbac/components/PagePermissionProvider.test.tsx +0 -476
  459. package/src/rbac/components/PagePermissionProvider.tsx +0 -279
  460. package/src/rbac/components/PermissionEnforcer.tsx +0 -312
  461. package/src/rbac/components/RoleBasedRouter.tsx +0 -440
  462. package/src/rbac/components/SecureDataProvider.test.tsx +0 -543
  463. package/src/rbac/components/SecureDataProvider.tsx +0 -339
  464. package/src/rbac/components/__tests__/EnhancedNavigationMenu.test.tsx +0 -620
  465. package/src/rbac/components/__tests__/NavigationProvider.test.tsx +0 -726
  466. package/src/rbac/components/__tests__/PagePermissionProvider.test.tsx +0 -661
  467. package/src/rbac/components/__tests__/PermissionEnforcer.test.tsx +0 -881
  468. package/src/rbac/components/__tests__/RoleBasedRouter.test.tsx +0 -783
  469. package/src/rbac/components/__tests__/SecureDataProvider.fixed.test.tsx +0 -645
  470. package/src/rbac/components/__tests__/SecureDataProvider.test.tsx +0 -659
  471. package/src/rbac/hooks/permissions/useCachedPermissions.ts +0 -79
  472. package/src/rbac/hooks/permissions/useHasAllPermissions.ts +0 -90
  473. 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;