@jmruthers/pace-core 0.6.6 → 0.6.8

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 (292) hide show
  1. package/{scripts/audit/audit-dependencies.cjs → audit-tool/00-dependencies.cjs} +227 -22
  2. package/audit-tool/audits/01-pace-core-compliance.cjs +556 -0
  3. package/audit-tool/audits/02-project-structure.cjs +240 -0
  4. package/audit-tool/audits/03-architecture.cjs +224 -0
  5. package/audit-tool/audits/04-code-quality.cjs +149 -0
  6. package/audit-tool/audits/05-styling.cjs +224 -0
  7. package/audit-tool/audits/06-security-rbac.cjs +554 -0
  8. package/audit-tool/audits/07-api-tech-stack.cjs +355 -0
  9. package/audit-tool/audits/08-testing-documentation.cjs +202 -0
  10. package/audit-tool/audits/09-operations.cjs +208 -0
  11. package/audit-tool/index.cjs +295 -0
  12. package/audit-tool/utils/code-utils.cjs +218 -0
  13. package/audit-tool/utils/file-utils.cjs +230 -0
  14. package/audit-tool/utils/report-utils.cjs +380 -0
  15. package/cursor-rules/00-standards-overview.mdc +156 -0
  16. package/cursor-rules/{00-pace-core-compliance.mdc → 01-pace-core-compliance.mdc} +187 -34
  17. package/cursor-rules/02-project-structure.mdc +37 -5
  18. package/cursor-rules/{03-solid-principles.mdc → 03-architecture.mdc} +125 -11
  19. package/cursor-rules/04-code-quality.mdc +419 -0
  20. package/cursor-rules/{08-markup-quality.mdc → 05-styling.mdc} +55 -10
  21. package/cursor-rules/{09-rbac-compliance.mdc → 06-security-rbac.mdc} +62 -6
  22. package/cursor-rules/07-api-tech-stack.mdc +377 -0
  23. package/cursor-rules/08-testing-documentation.mdc +324 -0
  24. package/cursor-rules/09-operations.mdc +365 -0
  25. package/dist/DataTable-6RMSCQJ6.js +15 -0
  26. package/dist/{DataTable-2N_tqbfq.d.ts → DataTable-DRUIgtUH.d.ts} +1 -1
  27. package/dist/{PublicPageProvider-BBH6Vqg7.d.ts → PublicPageProvider-CIGSujI2.d.ts} +40 -24
  28. package/dist/{UnifiedAuthProvider-ZT6TIGM7.js → UnifiedAuthProvider-7SNDOWYD.js} +2 -2
  29. package/dist/{api-Y4MQWOFW.js → api-7P7DI652.js} +1 -1
  30. package/dist/{chunk-MAGBIDNS.js → chunk-4DDCYDQ3.js} +8 -7
  31. package/dist/{chunk-BVP2BCJF.js → chunk-5W2A3DRC.js} +10 -9
  32. package/dist/{chunk-SD6WQY43.js → chunk-7ILTDCL2.js} +9 -1
  33. package/dist/{chunk-3QC3KRHK.js → chunk-A3W6LW53.js} +16 -1
  34. package/dist/{chunk-3O3WHILE.js → chunk-EF2UGZWY.js} +239 -63
  35. package/dist/{chunk-LAZMKTTF.js → chunk-EURB7QFZ.js} +341 -337
  36. package/dist/{chunk-2HGJFNAH.js → chunk-FEJLJNWA.js} +1 -15
  37. package/dist/{chunk-7TYHROIV.js → chunk-GS5672WG.js} +55 -13
  38. package/dist/{chunk-UIYSCEV7.js → chunk-IUBRCBSY.js} +1 -1
  39. package/dist/{chunk-ZFYPMX46.js → chunk-LX6U42O3.js} +1 -1
  40. package/dist/{chunk-FENMYN2U.js → chunk-MPBLMWVR.js} +3 -3
  41. package/dist/{chunk-ZS5VO5JB.js → chunk-NKHKXPI4.js} +408 -453
  42. package/dist/{chunk-A55DK444.js → chunk-OJ4SKRSV.js} +1 -7
  43. package/dist/{chunk-4T7OBVTU.js → chunk-S6ZQKDY6.js} +1 -1
  44. package/dist/{chunk-FTCRZOG2.js → chunk-T5CVK4R3.js} +5 -5
  45. package/dist/{chunk-OHIK3MIO.js → chunk-Z2FNRKF3.js} +13 -13
  46. package/dist/components.d.ts +5 -4
  47. package/dist/components.js +29 -34
  48. package/dist/eslint-rules/index.cjs +22 -9
  49. package/{src/eslint-rules/rules/compliance.cjs → dist/eslint-rules/rules/01-pace-core-compliance.cjs} +184 -23
  50. package/dist/eslint-rules/rules/04-code-quality.cjs +346 -0
  51. package/dist/eslint-rules/rules/05-styling.cjs +61 -0
  52. package/dist/eslint-rules/rules/{rbac.cjs → 06-security-rbac.cjs} +34 -13
  53. package/dist/eslint-rules/rules/07-api-tech-stack.cjs +385 -0
  54. package/dist/eslint-rules/rules/08-testing.cjs +94 -0
  55. package/dist/{functions-DHebl8-F.d.ts → functions-lBy5L2ry.d.ts} +1 -1
  56. package/dist/hooks.d.ts +5 -5
  57. package/dist/hooks.js +8 -8
  58. package/dist/index.d.ts +7 -7
  59. package/dist/index.js +21 -20
  60. package/dist/providers.js +2 -2
  61. package/dist/rbac/index.d.ts +1 -1
  62. package/dist/rbac/index.js +8 -8
  63. package/dist/theming/runtime.d.ts +61 -1
  64. package/dist/theming/runtime.js +1 -1
  65. package/dist/{types-B-K_5VnO.d.ts → types-DXstZpNI.d.ts} +0 -17
  66. package/dist/types.d.ts +2 -2
  67. package/dist/{usePublicRouteParams-COZ28Mvq.d.ts → usePublicRouteParams-MamNgwqe.d.ts} +19 -19
  68. package/dist/utils.d.ts +2 -2
  69. package/dist/utils.js +8 -8
  70. package/docs/README.md +1 -1
  71. package/docs/api/modules.md +106 -41
  72. package/docs/api-reference/components.md +18 -20
  73. package/docs/api-reference/hooks.md +80 -80
  74. package/docs/api-reference/types.md +1 -1
  75. package/docs/api-reference/utilities.md +1 -1
  76. package/docs/architecture/README.md +1 -1
  77. package/docs/core-concepts/events.md +3 -3
  78. package/docs/core-concepts/organisations.md +6 -6
  79. package/docs/core-concepts/permissions.md +6 -6
  80. package/docs/documentation-index.md +12 -18
  81. package/docs/getting-started/dependencies.md +23 -0
  82. package/docs/getting-started/documentation-index.md +1 -1
  83. package/docs/getting-started/examples/README.md +4 -4
  84. package/docs/getting-started/examples/full-featured-app.md +1 -1
  85. package/docs/getting-started/faq.md +2 -2
  86. package/docs/getting-started/quick-reference.md +4 -4
  87. package/docs/implementation-guides/app-layout.md +1 -1
  88. package/docs/implementation-guides/authentication.md +15 -15
  89. package/docs/implementation-guides/component-styling.md +1 -1
  90. package/docs/implementation-guides/data-tables.md +127 -34
  91. package/docs/implementation-guides/datatable-rbac-usage.md +1 -1
  92. package/docs/implementation-guides/dynamic-colors.md +3 -3
  93. package/docs/implementation-guides/file-upload-storage.md +2 -2
  94. package/docs/implementation-guides/hierarchical-datatable.md +40 -60
  95. package/docs/implementation-guides/inactivity-tracking.md +3 -3
  96. package/docs/implementation-guides/large-datasets.md +3 -2
  97. package/docs/implementation-guides/organisation-security.md +2 -2
  98. package/docs/implementation-guides/performance.md +2 -2
  99. package/docs/implementation-guides/permission-enforcement.md +1 -1
  100. package/docs/migration/V0.3.44_organisation-context-timing-fix.md +1 -1
  101. package/docs/migration/V0.4.0_rbac-migration.md +6 -6
  102. package/docs/rbac/README.md +5 -5
  103. package/docs/rbac/advanced-patterns.md +6 -6
  104. package/docs/rbac/api-reference.md +20 -20
  105. package/docs/rbac/event-based-apps.md +3 -3
  106. package/docs/rbac/examples.md +41 -41
  107. package/docs/rbac/getting-started.md +37 -37
  108. package/docs/rbac/performance.md +1 -1
  109. package/docs/rbac/quick-start.md +52 -52
  110. package/docs/rbac/secure-client-protection.md +1 -1
  111. package/docs/rbac/troubleshooting.md +1 -1
  112. package/docs/security/README.md +5 -5
  113. package/docs/standards/0-standards-overview.md +220 -0
  114. package/docs/standards/{00-pace-core-compliance.md → 1-pace-core-compliance-standards.md} +241 -185
  115. package/docs/standards/{02-project-structure.md → 2-project-structure-standards.md} +11 -47
  116. package/docs/standards/3-architecture-standards.md +606 -0
  117. package/docs/standards/4-code-quality-standards.md +728 -0
  118. package/docs/standards/{08-markup-quality.md → 5-styling-standards.md} +12 -9
  119. package/docs/standards/{09-rbac-compliance.md → 6-security-rbac-standards.md} +126 -18
  120. package/docs/standards/7-api-tech-stack-standards.md +662 -0
  121. package/docs/standards/8-testing-documentation-standards.md +401 -0
  122. package/docs/standards/9-operations-standards.md +1102 -0
  123. package/docs/standards/README.md +203 -104
  124. package/docs/troubleshooting/README.md +4 -4
  125. package/docs/troubleshooting/common-issues.md +2 -2
  126. package/docs/troubleshooting/debugging.md +9 -9
  127. package/docs/troubleshooting/migration.md +4 -4
  128. package/eslint-config-pace-core.cjs +50 -20
  129. package/package.json +50 -19
  130. package/scripts/eslint-audit.cjs +123 -0
  131. package/scripts/install-cursor-rules.cjs +11 -243
  132. package/scripts/install-eslint-config.cjs +349 -0
  133. package/scripts/validate-dependencies.cjs +248 -0
  134. package/src/__tests__/helpers/__tests__/component-test-utils.test.tsx +2 -2
  135. package/src/__tests__/helpers/__tests__/test-providers.test.tsx +2 -2
  136. package/src/__tests__/helpers/__tests__/test-utils.test.tsx +30 -18
  137. package/src/__tests__/integration/UserProfile.test.tsx +14 -14
  138. package/src/__tests__/rbac/PagePermissionGuard.test.tsx +6 -6
  139. package/src/__tests__/templates/accessibility.test.template.tsx +10 -9
  140. package/src/__tests__/templates/component.test.template.tsx +18 -15
  141. package/src/components/AddressField/AddressField.tsx +26 -1
  142. package/src/components/Alert/Alert.test.tsx +86 -22
  143. package/src/components/Alert/Alert.tsx +19 -11
  144. package/src/components/Badge/Badge.tsx +1 -1
  145. package/src/components/Calendar/Calendar.tsx +201 -47
  146. package/src/components/Checkbox/Checkbox.test.tsx +2 -1
  147. package/src/components/ContextSelector/ContextSelector.tsx +108 -126
  148. package/src/components/DataTable/AUDIT_REPORT.md +293 -0
  149. package/src/components/DataTable/DataTable.tsx +1 -19
  150. package/src/components/DataTable/__tests__/DataTableCore.test.tsx +6 -2
  151. package/src/components/DataTable/__tests__/a11y.basic.test.tsx +21 -6
  152. package/src/components/DataTable/__tests__/pagination.modes.test.tsx +3 -2
  153. package/src/components/DataTable/__tests__/test-utils/sharedTestUtils.tsx +9 -9
  154. package/src/components/DataTable/components/ColumnFilter.tsx +63 -74
  155. package/src/components/DataTable/components/ColumnVisibilityDropdown.tsx +43 -41
  156. package/src/components/DataTable/components/DataTableErrorBoundary.tsx +9 -11
  157. package/src/components/DataTable/components/DataTableLayout.tsx +5 -16
  158. package/src/components/DataTable/components/EditableRow.tsx +5 -7
  159. package/src/components/DataTable/components/EmptyState.tsx +11 -10
  160. package/src/components/DataTable/components/FilterRow.tsx +2 -4
  161. package/src/components/DataTable/components/ImportModal.tsx +124 -126
  162. package/src/components/DataTable/components/LoadingState.tsx +5 -6
  163. package/src/components/DataTable/components/SortIndicator.tsx +50 -0
  164. package/src/components/DataTable/components/__tests__/COVERAGE_NOTE.md +4 -4
  165. package/src/components/DataTable/components/__tests__/ColumnFilter.test.tsx +23 -82
  166. package/src/components/DataTable/components/__tests__/DataTableErrorBoundary.test.tsx +37 -9
  167. package/src/components/DataTable/components/__tests__/EmptyState.test.tsx +7 -4
  168. package/src/components/DataTable/components/__tests__/FilterRow.test.tsx +12 -4
  169. package/src/components/DataTable/components/__tests__/LoadingState.test.tsx +45 -27
  170. package/src/components/DataTable/components/index.ts +2 -1
  171. package/src/components/DataTable/types.ts +0 -18
  172. package/src/components/DataTable/utils/a11yUtils.ts +17 -0
  173. package/src/components/DatePickerWithTimezone/DatePickerWithTimezone.test.tsx +1 -1
  174. package/src/components/DatePickerWithTimezone/DatePickerWithTimezone.tsx +11 -15
  175. package/src/components/DateTimeField/DateTimeField.tsx +7 -8
  176. package/src/components/Dialog/Dialog.test.tsx +1 -0
  177. package/src/components/Dialog/Dialog.tsx +25 -8
  178. package/src/components/ErrorBoundary/ErrorBoundary.tsx +77 -79
  179. package/src/components/FileUpload/FileUpload.test.tsx +45 -16
  180. package/src/components/FileUpload/FileUpload.tsx +141 -130
  181. package/src/components/NavigationMenu/NavigationMenu.test.tsx +48 -12
  182. package/src/components/PaceAppLayout/PaceAppLayout.performance.test.tsx +9 -9
  183. package/src/components/PaceAppLayout/PaceAppLayout.security.test.tsx +30 -30
  184. package/src/components/PaceAppLayout/PaceAppLayout.test.tsx +4 -4
  185. package/src/components/PaceLoginPage/PaceLoginPage.test.tsx +7 -1
  186. package/src/components/Progress/Progress.tsx +2 -4
  187. package/src/components/ProtectedRoute/ProtectedRoute.tsx +8 -8
  188. package/src/components/Select/Select.tsx +86 -77
  189. package/src/components/Select/types.ts +3 -0
  190. package/src/hooks/__tests__/ServiceHooks.test.tsx +16 -16
  191. package/src/hooks/__tests__/hooks.integration.test.tsx +49 -49
  192. package/src/hooks/__tests__/useDataTablePerformance.unit.test.ts +8 -5
  193. package/src/hooks/__tests__/useFileUrl.unit.test.ts +4 -0
  194. package/src/hooks/__tests__/useFocusTrap.unit.test.tsx +99 -99
  195. package/src/hooks/__tests__/useInactivityTracker.unit.test.ts +45 -8
  196. package/src/hooks/__tests__/usePerformanceMonitor.unit.test.ts +22 -2
  197. package/src/hooks/public/usePublicEvent.ts +5 -5
  198. package/src/hooks/public/usePublicEventLogo.ts +5 -5
  199. package/src/hooks/public/usePublicFileDisplay.ts +2 -2
  200. package/src/hooks/public/usePublicRouteParams.ts +13 -9
  201. package/src/hooks/useAddressAutocomplete.test.ts +18 -18
  202. package/src/hooks/useAppConfig.ts +2 -2
  203. package/src/hooks/useEventTheme.test.ts +7 -7
  204. package/src/hooks/useEventTheme.ts +2 -1
  205. package/src/hooks/useFileDisplay.ts +2 -2
  206. package/src/hooks/useFileUrl.ts +52 -8
  207. package/src/hooks/useOrganisationSecurity.test.ts +2 -1
  208. package/src/providers/UnifiedAuthProvider.smoke.test.tsx +21 -21
  209. package/src/providers/__tests__/AuthProvider.test.tsx +21 -21
  210. package/src/providers/__tests__/EventProvider.test.tsx +61 -61
  211. package/src/providers/__tests__/InactivityProvider.test.tsx +56 -56
  212. package/src/providers/__tests__/OrganisationProvider.test.tsx +75 -75
  213. package/src/providers/__tests__/ProviderLifecycle.test.tsx +38 -38
  214. package/src/providers/__tests__/UnifiedAuthProvider.test.tsx +103 -103
  215. package/src/providers/services/__tests__/AuthServiceProvider.integration.test.tsx +7 -7
  216. package/src/providers/services/__tests__/UnifiedAuthProvider.integration.test.tsx +10 -10
  217. package/src/rbac/__tests__/auth-rbac.e2e.test.tsx +15 -6
  218. package/src/rbac/__tests__/rbac-functions.test.ts +3 -3
  219. package/src/rbac/api.test.ts +104 -0
  220. package/src/rbac/engine.ts +1 -1
  221. package/src/rbac/hooks/useCan.test.ts +2 -2
  222. package/src/rbac/secureClient.ts +1 -1
  223. package/src/rbac/types/functions.ts +1 -1
  224. package/src/styles/core.css +7 -0
  225. package/src/theming/__tests__/parseEventColours.test.ts +118 -3
  226. package/src/theming/parseEventColours.ts +77 -11
  227. package/src/types/supabase.ts +2 -3
  228. package/src/utils/__tests__/bundleAnalysis.unit.test.ts +9 -9
  229. package/src/utils/__tests__/lazyLoad.unit.test.tsx +42 -39
  230. package/src/utils/file-reference/__tests__/file-reference.test.ts +4 -0
  231. package/src/utils/formatting/formatDate.test.ts +3 -2
  232. package/src/utils/formatting/formatDateTime.test.ts +2 -2
  233. package/src/utils/google-places/googlePlacesUtils.test.ts +36 -24
  234. package/src/utils/storage/README.md +1 -1
  235. package/src/utils/storage/__tests__/helpers.unit.test.ts +19 -12
  236. package/src/utils/storage/helpers.test.ts +69 -3
  237. package/cursor-rules/01-standards-compliance.mdc +0 -285
  238. package/cursor-rules/04-testing-standards.mdc +0 -270
  239. package/cursor-rules/05-bug-reports-and-features.mdc +0 -248
  240. package/cursor-rules/06-code-quality.mdc +0 -311
  241. package/cursor-rules/07-tech-stack-compliance.mdc +0 -216
  242. package/cursor-rules/10-error-handling-patterns.mdc +0 -179
  243. package/cursor-rules/11-performance-optimization.mdc +0 -169
  244. package/cursor-rules/12-ci-cd-integration.mdc +0 -150
  245. package/dist/DataTable-LRJL4IRV.js +0 -15
  246. package/dist/eslint-rules/rules/compliance.cjs +0 -348
  247. package/dist/eslint-rules/rules/components.cjs +0 -113
  248. package/dist/eslint-rules/rules/imports.cjs +0 -102
  249. package/docs/best-practices/README.md +0 -472
  250. package/docs/best-practices/accessibility.md +0 -604
  251. package/docs/best-practices/common-patterns.md +0 -516
  252. package/docs/best-practices/deployment.md +0 -1103
  253. package/docs/best-practices/performance.md +0 -1328
  254. package/docs/best-practices/security.md +0 -940
  255. package/docs/best-practices/testing.md +0 -1034
  256. package/docs/rbac/compliance/compliance-guide.md +0 -544
  257. package/docs/standards/01-standards-compliance.md +0 -188
  258. package/docs/standards/03-solid-principles.md +0 -39
  259. package/docs/standards/04-testing-standards.md +0 -36
  260. package/docs/standards/05-bug-reports-and-features.md +0 -27
  261. package/docs/standards/06-code-quality.md +0 -34
  262. package/docs/standards/07-tech-stack-compliance.md +0 -30
  263. package/docs/standards/10-error-handling-patterns.md +0 -401
  264. package/docs/standards/11-performance-optimization.md +0 -348
  265. package/docs/standards/12-ci-cd-integration.md +0 -370
  266. package/docs/standards/ALIGNMENT_REVIEW_SUMMARY.md +0 -192
  267. package/scripts/audit/audit-compliance.cjs +0 -1295
  268. package/scripts/audit/audit-components.cjs +0 -260
  269. package/scripts/audit/audit-rbac.cjs +0 -954
  270. package/scripts/audit/audit-standards.cjs +0 -1268
  271. package/scripts/audit/index.cjs +0 -1927
  272. package/src/components/DataTable/components/DataTableBody.tsx +0 -478
  273. package/src/components/DataTable/components/DraggableColumnHeader.tsx +0 -156
  274. package/src/components/DataTable/components/ExpandButton.tsx +0 -113
  275. package/src/components/DataTable/components/GroupHeader.tsx +0 -54
  276. package/src/components/DataTable/components/ViewRowModal.tsx +0 -68
  277. package/src/components/DataTable/components/VirtualizedDataTable.tsx +0 -525
  278. package/src/components/DataTable/components/__tests__/ExpandButton.test.tsx +0 -462
  279. package/src/components/DataTable/components/__tests__/GroupHeader.test.tsx +0 -393
  280. package/src/components/DataTable/components/__tests__/ViewRowModal.test.tsx +0 -476
  281. package/src/components/DataTable/components/__tests__/VirtualizedDataTable.test.tsx +0 -128
  282. package/src/components/DataTable/core/DataTableContext.tsx +0 -216
  283. package/src/components/DataTable/core/__tests__/DataTableContext.test.tsx +0 -136
  284. package/src/components/DataTable/hooks/__tests__/useColumnReordering.test.ts +0 -570
  285. package/src/components/DataTable/hooks/useColumnReordering.ts +0 -123
  286. package/src/components/DataTable/utils/debugTools.ts +0 -514
  287. package/src/eslint-rules/index.cjs +0 -22
  288. package/src/eslint-rules/rules/components.cjs +0 -113
  289. package/src/eslint-rules/rules/imports.cjs +0 -102
  290. package/src/eslint-rules/rules/rbac.cjs +0 -790
  291. package/src/eslint-rules/utils/helpers.cjs +0 -42
  292. package/src/eslint-rules/utils/manifest-loader.cjs +0 -75
@@ -0,0 +1,218 @@
1
+ /**
2
+ * Code Analysis Utilities for Audit Tool
3
+ * @package @jmruthers/pace-core
4
+ * @module Audit/utils/code-utils
5
+ */
6
+
7
+ /**
8
+ * Get line number from index in content
9
+ * @param {string} content - File content
10
+ * @param {number} index - Character index
11
+ * @returns {number} - Line number (1-indexed)
12
+ */
13
+ function getLineNumber(content, index) {
14
+ return content.substring(0, index).split('\n').length;
15
+ }
16
+
17
+ /**
18
+ * Get code snippet around a match for context
19
+ * @param {string} content - File content
20
+ * @param {number} index - Character index
21
+ * @param {number} before - Characters before index
22
+ * @param {number} after - Characters after index
23
+ * @returns {string} - Code snippet
24
+ */
25
+ function getCodeSnippet(content, index, before = 30, after = 50) {
26
+ const start = Math.max(0, index - before);
27
+ const end = Math.min(content.length, index + after);
28
+ return content.substring(start, end).trim();
29
+ }
30
+
31
+ /**
32
+ * Check if content is in a comment or string (for TypeScript/JavaScript)
33
+ * @param {string} content - File content
34
+ * @param {number} index - Character index
35
+ * @returns {boolean} - True if in comment or string
36
+ */
37
+ function isInCommentOrString(content, index) {
38
+ const before = content.substring(0, index);
39
+
40
+ // Check for line comments
41
+ const lastLineComment = before.lastIndexOf('//');
42
+ const lastNewline = before.lastIndexOf('\n');
43
+ if (lastLineComment > lastNewline) {
44
+ return true;
45
+ }
46
+
47
+ // Check for block comments
48
+ const lastBlockCommentStart = before.lastIndexOf('/*');
49
+ const lastBlockCommentEnd = before.lastIndexOf('*/');
50
+ if (lastBlockCommentStart > lastBlockCommentEnd) {
51
+ return true;
52
+ }
53
+
54
+ // Check for string literals (simple check)
55
+ const singleQuoteMatches = [...before.matchAll(/'/g)];
56
+ const doubleQuoteMatches = [...before.matchAll(/"/g)];
57
+ const backtickMatches = [...before.matchAll(/`/g)];
58
+
59
+ // Simple heuristic: if odd number of quotes before, might be in string
60
+ const inSingleQuote = singleQuoteMatches.length % 2 === 1;
61
+ const inDoubleQuote = doubleQuoteMatches.length % 2 === 1;
62
+ const inBacktick = backtickMatches.length % 2 === 1;
63
+
64
+ return inSingleQuote || inDoubleQuote || inBacktick;
65
+ }
66
+
67
+ /**
68
+ * Check if content is in a comment or string (for SQL)
69
+ * @param {string} content - SQL content
70
+ * @param {number} index - Character index
71
+ * @returns {boolean} - True if in comment or string
72
+ */
73
+ function isInCommentOrStringSQL(content, index) {
74
+ const before = content.substring(0, index);
75
+
76
+ // Check for SQL line comments
77
+ const lastLineComment = before.lastIndexOf('--');
78
+ const lastNewline = before.lastIndexOf('\n');
79
+ if (lastLineComment > lastNewline && !before.substring(lastLineComment, index).includes('\n')) {
80
+ return true;
81
+ }
82
+
83
+ // Check for block comments
84
+ const lastBlockCommentStart = before.lastIndexOf('/*');
85
+ const lastBlockCommentEnd = before.lastIndexOf('*/');
86
+ if (lastBlockCommentStart > lastBlockCommentEnd) {
87
+ return true;
88
+ }
89
+
90
+ // Check for string literals (SQL uses single quotes)
91
+ const singleQuoteMatches = [...before.matchAll(/'/g)];
92
+ const inSingleQuote = singleQuoteMatches.length % 2 === 1;
93
+
94
+ return inSingleQuote;
95
+ }
96
+
97
+ /**
98
+ * Extract import statements from content
99
+ * @param {string} content - File content
100
+ * @returns {Array} - Array of import objects { source, specifiers, line }
101
+ */
102
+ function parseImports(content) {
103
+ const imports = [];
104
+ const lines = content.split('\n');
105
+
106
+ lines.forEach((line, index) => {
107
+ // Match various import patterns
108
+ const importPatterns = [
109
+ /^import\s+.*\s+from\s+['"]([^'"]+)['"]/,
110
+ /^import\s+['"]([^'"]+)['"]/,
111
+ ];
112
+
113
+ for (const pattern of importPatterns) {
114
+ const match = line.match(pattern);
115
+ if (match) {
116
+ const source = match[1];
117
+ const specifiers = [];
118
+
119
+ // Try to extract named imports
120
+ const namedMatch = line.match(/import\s+{([^}]+)}\s+from/);
121
+ if (namedMatch) {
122
+ namedMatch[1].split(',').forEach(spec => {
123
+ const trimmed = spec.trim();
124
+ if (trimmed) {
125
+ specifiers.push(trimmed);
126
+ }
127
+ });
128
+ }
129
+
130
+ // Check for default import
131
+ const defaultMatch = line.match(/import\s+(\w+)\s+from/);
132
+ if (defaultMatch && !line.includes('{')) {
133
+ specifiers.push('default');
134
+ }
135
+
136
+ imports.push({
137
+ source,
138
+ specifiers,
139
+ line: index + 1,
140
+ fullLine: line.trim(),
141
+ });
142
+ break;
143
+ }
144
+ }
145
+ });
146
+
147
+ return imports;
148
+ }
149
+
150
+ /**
151
+ * Extract export statements from content
152
+ * @param {string} content - File content
153
+ * @returns {Array} - Array of export objects { name, type, line }
154
+ */
155
+ function parseExports(content) {
156
+ const exports = [];
157
+ const lines = content.split('\n');
158
+
159
+ lines.forEach((line, index) => {
160
+ // Match export patterns
161
+ const exportPatterns = [
162
+ /^export\s+(?:function|const|class|interface|type)\s+(\w+)/,
163
+ /^export\s+default\s+(?:function\s+)?(\w+)?/,
164
+ /^export\s+{\s*(\w+)/,
165
+ ];
166
+
167
+ for (const pattern of exportPatterns) {
168
+ const match = line.match(pattern);
169
+ if (match) {
170
+ const name = match[1] || 'default';
171
+ const type = line.includes('function') ? 'function' :
172
+ line.includes('const') ? 'const' :
173
+ line.includes('class') ? 'class' :
174
+ line.includes('interface') ? 'interface' :
175
+ line.includes('type') ? 'type' :
176
+ 'other';
177
+
178
+ exports.push({
179
+ name,
180
+ type,
181
+ line: index + 1,
182
+ fullLine: line.trim(),
183
+ });
184
+ break;
185
+ }
186
+ }
187
+ });
188
+
189
+ return exports;
190
+ }
191
+
192
+ /**
193
+ * Check if file imports from pace-core
194
+ * @param {string} content - File content
195
+ * @param {string} name - Component/hook/util name to check
196
+ * @returns {boolean} - True if imports from pace-core
197
+ */
198
+ function importsFromPaceCore(content, name) {
199
+ const patterns = [
200
+ new RegExp(`import\\s+.*\\b${name}\\b.*from\\s+['"]@jmruthers/pace-core`),
201
+ new RegExp(`import\\s+.*\\b${name}\\b.*from\\s+['"]@jmruthers/pace-core/components`),
202
+ new RegExp(`import\\s+.*\\b${name}\\b.*from\\s+['"]@jmruthers/pace-core/hooks`),
203
+ new RegExp(`import\\s+.*\\b${name}\\b.*from\\s+['"]@jmruthers/pace-core/utils`),
204
+ new RegExp(`import\\s+.*\\b${name}\\b.*from\\s+['"]@jmruthers/pace-core/rbac`),
205
+ ];
206
+
207
+ return patterns.some(pattern => pattern.test(content));
208
+ }
209
+
210
+ module.exports = {
211
+ getLineNumber,
212
+ getCodeSnippet,
213
+ isInCommentOrString,
214
+ isInCommentOrStringSQL,
215
+ parseImports,
216
+ parseExports,
217
+ importsFromPaceCore,
218
+ };
@@ -0,0 +1,230 @@
1
+ /**
2
+ * File System Utilities for Audit Tool
3
+ * @package @jmruthers/pace-core
4
+ * @module Audit/utils/file-utils
5
+ */
6
+
7
+ const fs = require('fs');
8
+ const path = require('path');
9
+
10
+ /**
11
+ * Recursively find all source files matching extensions
12
+ * @param {string} dir - Directory to search
13
+ * @param {string[]} extensions - File extensions to match (e.g., ['.ts', '.tsx', '.js', '.jsx'])
14
+ * @param {string[]} fileList - Accumulator for found files
15
+ * @returns {string[]} - Array of file paths
16
+ */
17
+ function findSourceFiles(dir, extensions = ['.ts', '.tsx', '.js', '.jsx'], fileList = []) {
18
+ if (!fs.existsSync(dir)) {
19
+ return fileList;
20
+ }
21
+
22
+ const files = fs.readdirSync(dir);
23
+
24
+ files.forEach(file => {
25
+ const filePath = path.join(dir, file);
26
+ const stat = fs.statSync(filePath);
27
+
28
+ if (stat.isDirectory()) {
29
+ // Skip common build/dependency directories
30
+ if (!['node_modules', 'dist', 'build', '.git', '.next', '.vite', 'coverage', '.turbo', '.cursor'].includes(file)) {
31
+ findSourceFiles(filePath, extensions, fileList);
32
+ }
33
+ } else {
34
+ const ext = path.extname(file);
35
+ if (extensions.includes(ext)) {
36
+ fileList.push(filePath);
37
+ }
38
+ }
39
+ });
40
+
41
+ return fileList;
42
+ }
43
+
44
+ /**
45
+ * Recursively find all SQL files in a directory
46
+ * @param {string} dir - Directory to search
47
+ * @param {string[]} fileList - Accumulator for found files
48
+ * @returns {string[]} - Array of SQL file paths
49
+ */
50
+ function findSQLFiles(dir, fileList = []) {
51
+ if (!fs.existsSync(dir)) {
52
+ return fileList;
53
+ }
54
+
55
+ const files = fs.readdirSync(dir);
56
+
57
+ files.forEach(file => {
58
+ const filePath = path.join(dir, file);
59
+ const stat = fs.statSync(filePath);
60
+
61
+ if (stat.isDirectory()) {
62
+ // Skip common build/dependency directories
63
+ if (!['node_modules', 'dist', 'build', '.git', '.next', '.vite', 'coverage', '.turbo'].includes(file)) {
64
+ findSQLFiles(filePath, fileList);
65
+ }
66
+ } else if (/\.sql$/.test(file)) {
67
+ fileList.push(filePath);
68
+ }
69
+ });
70
+
71
+ return fileList;
72
+ }
73
+
74
+ /**
75
+ * Find configuration files by name
76
+ * @param {string} dir - Directory to search
77
+ * @param {string[]} configNames - Array of config file names to find
78
+ * @returns {Object} - Object mapping config names to paths (or null if not found)
79
+ */
80
+ function findConfigFiles(dir, configNames) {
81
+ const results = {};
82
+
83
+ for (const configName of configNames) {
84
+ const possiblePaths = [
85
+ path.join(dir, configName),
86
+ path.join(dir, `.${configName}`),
87
+ ];
88
+
89
+ // Also check common variations
90
+ if (configName.includes('.')) {
91
+ const [base, ext] = configName.split('.');
92
+ possiblePaths.push(
93
+ path.join(dir, `${base}.js`),
94
+ path.join(dir, `${base}.ts`),
95
+ path.join(dir, `${base}.cjs`),
96
+ path.join(dir, `${base}.mjs`),
97
+ path.join(dir, `.${base}.js`),
98
+ path.join(dir, `.${base}.ts`),
99
+ path.join(dir, `.${base}.cjs`),
100
+ path.join(dir, `.${base}.mjs`)
101
+ );
102
+ }
103
+
104
+ let found = null;
105
+ for (const configPath of possiblePaths) {
106
+ if (fs.existsSync(configPath)) {
107
+ found = configPath;
108
+ break;
109
+ }
110
+ }
111
+
112
+ results[configName] = found;
113
+ }
114
+
115
+ return results;
116
+ }
117
+
118
+ /**
119
+ * Safely read a file with error handling
120
+ * @param {string} filePath - Path to file
121
+ * @returns {string|null} - File content or null if error
122
+ */
123
+ function readFileSafe(filePath) {
124
+ try {
125
+ if (!fs.existsSync(filePath)) {
126
+ return null;
127
+ }
128
+ return fs.readFileSync(filePath, 'utf8');
129
+ } catch (error) {
130
+ return null;
131
+ }
132
+ }
133
+
134
+ /**
135
+ * Get relative path from base path
136
+ * @param {string} filePath - Absolute file path
137
+ * @param {string} basePath - Base path to make relative to
138
+ * @returns {string} - Relative path
139
+ */
140
+ function getRelativePath(filePath, basePath) {
141
+ try {
142
+ return path.relative(basePath, filePath);
143
+ } catch (error) {
144
+ return filePath;
145
+ }
146
+ }
147
+
148
+ /**
149
+ * Find pace-core package.json
150
+ * @param {string} consumingAppPath - Path to consuming app
151
+ * @returns {string|null} - Path to pace-core package.json or null
152
+ */
153
+ function findPaceCorePackageJson(consumingAppPath) {
154
+ const possiblePaths = [
155
+ path.resolve(__dirname, '../../package.json'), // From packages/core/audit-tool/utils
156
+ path.resolve(__dirname, '../../../package.json'), // Alternative location (from root)
157
+ path.join(consumingAppPath, 'node_modules', '@jmruthers', 'pace-core', 'package.json'),
158
+ ];
159
+
160
+ for (const packagePath of possiblePaths) {
161
+ if (fs.existsSync(packagePath)) {
162
+ return packagePath;
163
+ }
164
+ }
165
+
166
+ return null;
167
+ }
168
+
169
+ /**
170
+ * Load core-usage-manifest.json
171
+ * @param {string} consumingAppPath - Path to consuming app
172
+ * @returns {Object|null} - Manifest object or null
173
+ */
174
+ function loadManifest(consumingAppPath) {
175
+ const possiblePaths = [
176
+ path.resolve(__dirname, '../../../core-usage-manifest.json'),
177
+ path.resolve(__dirname, '../../../../core-usage-manifest.json'),
178
+ path.join(consumingAppPath, 'node_modules', '@jmruthers', 'pace-core', 'core-usage-manifest.json'),
179
+ ];
180
+
181
+ for (const manifestPath of possiblePaths) {
182
+ if (fs.existsSync(manifestPath)) {
183
+ try {
184
+ return JSON.parse(fs.readFileSync(manifestPath, 'utf8'));
185
+ } catch (e) {
186
+ // Continue to next path
187
+ }
188
+ }
189
+ }
190
+
191
+ return null;
192
+ }
193
+
194
+ /**
195
+ * Check if a directory exists
196
+ * @param {string} dirPath - Directory path
197
+ * @returns {boolean} - True if directory exists
198
+ */
199
+ function directoryExists(dirPath) {
200
+ try {
201
+ return fs.existsSync(dirPath) && fs.statSync(dirPath).isDirectory();
202
+ } catch (error) {
203
+ return false;
204
+ }
205
+ }
206
+
207
+ /**
208
+ * Check if a file exists
209
+ * @param {string} filePath - File path
210
+ * @returns {boolean} - True if file exists
211
+ */
212
+ function fileExists(filePath) {
213
+ try {
214
+ return fs.existsSync(filePath) && fs.statSync(filePath).isFile();
215
+ } catch (error) {
216
+ return false;
217
+ }
218
+ }
219
+
220
+ module.exports = {
221
+ findSourceFiles,
222
+ findSQLFiles,
223
+ findConfigFiles,
224
+ readFileSafe,
225
+ getRelativePath,
226
+ findPaceCorePackageJson,
227
+ loadManifest,
228
+ directoryExists,
229
+ fileExists,
230
+ };