@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.
- package/{scripts/audit/audit-dependencies.cjs → audit-tool/00-dependencies.cjs} +227 -22
- package/audit-tool/audits/01-pace-core-compliance.cjs +556 -0
- package/audit-tool/audits/02-project-structure.cjs +240 -0
- package/audit-tool/audits/03-architecture.cjs +224 -0
- package/audit-tool/audits/04-code-quality.cjs +149 -0
- package/audit-tool/audits/05-styling.cjs +224 -0
- package/audit-tool/audits/06-security-rbac.cjs +554 -0
- package/audit-tool/audits/07-api-tech-stack.cjs +355 -0
- package/audit-tool/audits/08-testing-documentation.cjs +202 -0
- package/audit-tool/audits/09-operations.cjs +208 -0
- package/audit-tool/index.cjs +295 -0
- package/audit-tool/utils/code-utils.cjs +218 -0
- package/audit-tool/utils/file-utils.cjs +230 -0
- package/audit-tool/utils/report-utils.cjs +380 -0
- package/cursor-rules/00-standards-overview.mdc +156 -0
- package/cursor-rules/{00-pace-core-compliance.mdc → 01-pace-core-compliance.mdc} +187 -34
- package/cursor-rules/02-project-structure.mdc +37 -5
- package/cursor-rules/{03-solid-principles.mdc → 03-architecture.mdc} +125 -11
- package/cursor-rules/04-code-quality.mdc +419 -0
- package/cursor-rules/{08-markup-quality.mdc → 05-styling.mdc} +55 -10
- package/cursor-rules/{09-rbac-compliance.mdc → 06-security-rbac.mdc} +62 -6
- package/cursor-rules/07-api-tech-stack.mdc +377 -0
- package/cursor-rules/08-testing-documentation.mdc +324 -0
- package/cursor-rules/09-operations.mdc +365 -0
- package/dist/DataTable-6RMSCQJ6.js +15 -0
- package/dist/{DataTable-2N_tqbfq.d.ts → DataTable-DRUIgtUH.d.ts} +1 -1
- package/dist/{PublicPageProvider-BBH6Vqg7.d.ts → PublicPageProvider-CIGSujI2.d.ts} +40 -24
- package/dist/{UnifiedAuthProvider-ZT6TIGM7.js → UnifiedAuthProvider-7SNDOWYD.js} +2 -2
- package/dist/{api-Y4MQWOFW.js → api-7P7DI652.js} +1 -1
- package/dist/{chunk-MAGBIDNS.js → chunk-4DDCYDQ3.js} +8 -7
- package/dist/{chunk-BVP2BCJF.js → chunk-5W2A3DRC.js} +10 -9
- package/dist/{chunk-SD6WQY43.js → chunk-7ILTDCL2.js} +9 -1
- package/dist/{chunk-3QC3KRHK.js → chunk-A3W6LW53.js} +16 -1
- package/dist/{chunk-3O3WHILE.js → chunk-EF2UGZWY.js} +239 -63
- package/dist/{chunk-LAZMKTTF.js → chunk-EURB7QFZ.js} +341 -337
- package/dist/{chunk-2HGJFNAH.js → chunk-FEJLJNWA.js} +1 -15
- package/dist/{chunk-7TYHROIV.js → chunk-GS5672WG.js} +55 -13
- package/dist/{chunk-UIYSCEV7.js → chunk-IUBRCBSY.js} +1 -1
- package/dist/{chunk-ZFYPMX46.js → chunk-LX6U42O3.js} +1 -1
- package/dist/{chunk-FENMYN2U.js → chunk-MPBLMWVR.js} +3 -3
- package/dist/{chunk-ZS5VO5JB.js → chunk-NKHKXPI4.js} +408 -453
- package/dist/{chunk-A55DK444.js → chunk-OJ4SKRSV.js} +1 -7
- package/dist/{chunk-4T7OBVTU.js → chunk-S6ZQKDY6.js} +1 -1
- package/dist/{chunk-FTCRZOG2.js → chunk-T5CVK4R3.js} +5 -5
- package/dist/{chunk-OHIK3MIO.js → chunk-Z2FNRKF3.js} +13 -13
- package/dist/components.d.ts +5 -4
- package/dist/components.js +29 -34
- package/dist/eslint-rules/index.cjs +22 -9
- package/{src/eslint-rules/rules/compliance.cjs → dist/eslint-rules/rules/01-pace-core-compliance.cjs} +184 -23
- package/dist/eslint-rules/rules/04-code-quality.cjs +346 -0
- package/dist/eslint-rules/rules/05-styling.cjs +61 -0
- package/dist/eslint-rules/rules/{rbac.cjs → 06-security-rbac.cjs} +34 -13
- package/dist/eslint-rules/rules/07-api-tech-stack.cjs +385 -0
- package/dist/eslint-rules/rules/08-testing.cjs +94 -0
- package/dist/{functions-DHebl8-F.d.ts → functions-lBy5L2ry.d.ts} +1 -1
- package/dist/hooks.d.ts +5 -5
- package/dist/hooks.js +8 -8
- package/dist/index.d.ts +7 -7
- package/dist/index.js +21 -20
- package/dist/providers.js +2 -2
- package/dist/rbac/index.d.ts +1 -1
- package/dist/rbac/index.js +8 -8
- package/dist/theming/runtime.d.ts +61 -1
- package/dist/theming/runtime.js +1 -1
- package/dist/{types-B-K_5VnO.d.ts → types-DXstZpNI.d.ts} +0 -17
- package/dist/types.d.ts +2 -2
- package/dist/{usePublicRouteParams-COZ28Mvq.d.ts → usePublicRouteParams-MamNgwqe.d.ts} +19 -19
- package/dist/utils.d.ts +2 -2
- package/dist/utils.js +8 -8
- package/docs/README.md +1 -1
- package/docs/api/modules.md +106 -41
- package/docs/api-reference/components.md +18 -20
- package/docs/api-reference/hooks.md +80 -80
- package/docs/api-reference/types.md +1 -1
- package/docs/api-reference/utilities.md +1 -1
- package/docs/architecture/README.md +1 -1
- package/docs/core-concepts/events.md +3 -3
- package/docs/core-concepts/organisations.md +6 -6
- package/docs/core-concepts/permissions.md +6 -6
- package/docs/documentation-index.md +12 -18
- package/docs/getting-started/dependencies.md +23 -0
- package/docs/getting-started/documentation-index.md +1 -1
- package/docs/getting-started/examples/README.md +4 -4
- package/docs/getting-started/examples/full-featured-app.md +1 -1
- package/docs/getting-started/faq.md +2 -2
- package/docs/getting-started/quick-reference.md +4 -4
- package/docs/implementation-guides/app-layout.md +1 -1
- package/docs/implementation-guides/authentication.md +15 -15
- package/docs/implementation-guides/component-styling.md +1 -1
- package/docs/implementation-guides/data-tables.md +127 -34
- package/docs/implementation-guides/datatable-rbac-usage.md +1 -1
- package/docs/implementation-guides/dynamic-colors.md +3 -3
- package/docs/implementation-guides/file-upload-storage.md +2 -2
- package/docs/implementation-guides/hierarchical-datatable.md +40 -60
- package/docs/implementation-guides/inactivity-tracking.md +3 -3
- package/docs/implementation-guides/large-datasets.md +3 -2
- package/docs/implementation-guides/organisation-security.md +2 -2
- package/docs/implementation-guides/performance.md +2 -2
- package/docs/implementation-guides/permission-enforcement.md +1 -1
- package/docs/migration/V0.3.44_organisation-context-timing-fix.md +1 -1
- package/docs/migration/V0.4.0_rbac-migration.md +6 -6
- package/docs/rbac/README.md +5 -5
- package/docs/rbac/advanced-patterns.md +6 -6
- package/docs/rbac/api-reference.md +20 -20
- package/docs/rbac/event-based-apps.md +3 -3
- package/docs/rbac/examples.md +41 -41
- package/docs/rbac/getting-started.md +37 -37
- package/docs/rbac/performance.md +1 -1
- package/docs/rbac/quick-start.md +52 -52
- package/docs/rbac/secure-client-protection.md +1 -1
- package/docs/rbac/troubleshooting.md +1 -1
- package/docs/security/README.md +5 -5
- package/docs/standards/0-standards-overview.md +220 -0
- package/docs/standards/{00-pace-core-compliance.md → 1-pace-core-compliance-standards.md} +241 -185
- package/docs/standards/{02-project-structure.md → 2-project-structure-standards.md} +11 -47
- package/docs/standards/3-architecture-standards.md +606 -0
- package/docs/standards/4-code-quality-standards.md +728 -0
- package/docs/standards/{08-markup-quality.md → 5-styling-standards.md} +12 -9
- package/docs/standards/{09-rbac-compliance.md → 6-security-rbac-standards.md} +126 -18
- package/docs/standards/7-api-tech-stack-standards.md +662 -0
- package/docs/standards/8-testing-documentation-standards.md +401 -0
- package/docs/standards/9-operations-standards.md +1102 -0
- package/docs/standards/README.md +203 -104
- package/docs/troubleshooting/README.md +4 -4
- package/docs/troubleshooting/common-issues.md +2 -2
- package/docs/troubleshooting/debugging.md +9 -9
- package/docs/troubleshooting/migration.md +4 -4
- package/eslint-config-pace-core.cjs +50 -20
- package/package.json +50 -19
- package/scripts/eslint-audit.cjs +123 -0
- package/scripts/install-cursor-rules.cjs +11 -243
- package/scripts/install-eslint-config.cjs +349 -0
- package/scripts/validate-dependencies.cjs +248 -0
- package/src/__tests__/helpers/__tests__/component-test-utils.test.tsx +2 -2
- package/src/__tests__/helpers/__tests__/test-providers.test.tsx +2 -2
- package/src/__tests__/helpers/__tests__/test-utils.test.tsx +30 -18
- package/src/__tests__/integration/UserProfile.test.tsx +14 -14
- package/src/__tests__/rbac/PagePermissionGuard.test.tsx +6 -6
- package/src/__tests__/templates/accessibility.test.template.tsx +10 -9
- package/src/__tests__/templates/component.test.template.tsx +18 -15
- package/src/components/AddressField/AddressField.tsx +26 -1
- package/src/components/Alert/Alert.test.tsx +86 -22
- package/src/components/Alert/Alert.tsx +19 -11
- package/src/components/Badge/Badge.tsx +1 -1
- package/src/components/Calendar/Calendar.tsx +201 -47
- package/src/components/Checkbox/Checkbox.test.tsx +2 -1
- package/src/components/ContextSelector/ContextSelector.tsx +108 -126
- package/src/components/DataTable/AUDIT_REPORT.md +293 -0
- package/src/components/DataTable/DataTable.tsx +1 -19
- package/src/components/DataTable/__tests__/DataTableCore.test.tsx +6 -2
- package/src/components/DataTable/__tests__/a11y.basic.test.tsx +21 -6
- package/src/components/DataTable/__tests__/pagination.modes.test.tsx +3 -2
- package/src/components/DataTable/__tests__/test-utils/sharedTestUtils.tsx +9 -9
- package/src/components/DataTable/components/ColumnFilter.tsx +63 -74
- package/src/components/DataTable/components/ColumnVisibilityDropdown.tsx +43 -41
- package/src/components/DataTable/components/DataTableErrorBoundary.tsx +9 -11
- package/src/components/DataTable/components/DataTableLayout.tsx +5 -16
- package/src/components/DataTable/components/EditableRow.tsx +5 -7
- package/src/components/DataTable/components/EmptyState.tsx +11 -10
- package/src/components/DataTable/components/FilterRow.tsx +2 -4
- package/src/components/DataTable/components/ImportModal.tsx +124 -126
- package/src/components/DataTable/components/LoadingState.tsx +5 -6
- package/src/components/DataTable/components/SortIndicator.tsx +50 -0
- package/src/components/DataTable/components/__tests__/COVERAGE_NOTE.md +4 -4
- package/src/components/DataTable/components/__tests__/ColumnFilter.test.tsx +23 -82
- package/src/components/DataTable/components/__tests__/DataTableErrorBoundary.test.tsx +37 -9
- package/src/components/DataTable/components/__tests__/EmptyState.test.tsx +7 -4
- package/src/components/DataTable/components/__tests__/FilterRow.test.tsx +12 -4
- package/src/components/DataTable/components/__tests__/LoadingState.test.tsx +45 -27
- package/src/components/DataTable/components/index.ts +2 -1
- package/src/components/DataTable/types.ts +0 -18
- package/src/components/DataTable/utils/a11yUtils.ts +17 -0
- package/src/components/DatePickerWithTimezone/DatePickerWithTimezone.test.tsx +1 -1
- package/src/components/DatePickerWithTimezone/DatePickerWithTimezone.tsx +11 -15
- package/src/components/DateTimeField/DateTimeField.tsx +7 -8
- package/src/components/Dialog/Dialog.test.tsx +1 -0
- package/src/components/Dialog/Dialog.tsx +25 -8
- package/src/components/ErrorBoundary/ErrorBoundary.tsx +77 -79
- package/src/components/FileUpload/FileUpload.test.tsx +45 -16
- package/src/components/FileUpload/FileUpload.tsx +141 -130
- package/src/components/NavigationMenu/NavigationMenu.test.tsx +48 -12
- package/src/components/PaceAppLayout/PaceAppLayout.performance.test.tsx +9 -9
- package/src/components/PaceAppLayout/PaceAppLayout.security.test.tsx +30 -30
- package/src/components/PaceAppLayout/PaceAppLayout.test.tsx +4 -4
- package/src/components/PaceLoginPage/PaceLoginPage.test.tsx +7 -1
- package/src/components/Progress/Progress.tsx +2 -4
- package/src/components/ProtectedRoute/ProtectedRoute.tsx +8 -8
- package/src/components/Select/Select.tsx +86 -77
- package/src/components/Select/types.ts +3 -0
- package/src/hooks/__tests__/ServiceHooks.test.tsx +16 -16
- package/src/hooks/__tests__/hooks.integration.test.tsx +49 -49
- package/src/hooks/__tests__/useDataTablePerformance.unit.test.ts +8 -5
- package/src/hooks/__tests__/useFileUrl.unit.test.ts +4 -0
- package/src/hooks/__tests__/useFocusTrap.unit.test.tsx +99 -99
- package/src/hooks/__tests__/useInactivityTracker.unit.test.ts +45 -8
- package/src/hooks/__tests__/usePerformanceMonitor.unit.test.ts +22 -2
- package/src/hooks/public/usePublicEvent.ts +5 -5
- package/src/hooks/public/usePublicEventLogo.ts +5 -5
- package/src/hooks/public/usePublicFileDisplay.ts +2 -2
- package/src/hooks/public/usePublicRouteParams.ts +13 -9
- package/src/hooks/useAddressAutocomplete.test.ts +18 -18
- package/src/hooks/useAppConfig.ts +2 -2
- package/src/hooks/useEventTheme.test.ts +7 -7
- package/src/hooks/useEventTheme.ts +2 -1
- package/src/hooks/useFileDisplay.ts +2 -2
- package/src/hooks/useFileUrl.ts +52 -8
- package/src/hooks/useOrganisationSecurity.test.ts +2 -1
- package/src/providers/UnifiedAuthProvider.smoke.test.tsx +21 -21
- package/src/providers/__tests__/AuthProvider.test.tsx +21 -21
- package/src/providers/__tests__/EventProvider.test.tsx +61 -61
- package/src/providers/__tests__/InactivityProvider.test.tsx +56 -56
- package/src/providers/__tests__/OrganisationProvider.test.tsx +75 -75
- package/src/providers/__tests__/ProviderLifecycle.test.tsx +38 -38
- package/src/providers/__tests__/UnifiedAuthProvider.test.tsx +103 -103
- package/src/providers/services/__tests__/AuthServiceProvider.integration.test.tsx +7 -7
- package/src/providers/services/__tests__/UnifiedAuthProvider.integration.test.tsx +10 -10
- package/src/rbac/__tests__/auth-rbac.e2e.test.tsx +15 -6
- package/src/rbac/__tests__/rbac-functions.test.ts +3 -3
- package/src/rbac/api.test.ts +104 -0
- package/src/rbac/engine.ts +1 -1
- package/src/rbac/hooks/useCan.test.ts +2 -2
- package/src/rbac/secureClient.ts +1 -1
- package/src/rbac/types/functions.ts +1 -1
- package/src/styles/core.css +7 -0
- package/src/theming/__tests__/parseEventColours.test.ts +118 -3
- package/src/theming/parseEventColours.ts +77 -11
- package/src/types/supabase.ts +2 -3
- package/src/utils/__tests__/bundleAnalysis.unit.test.ts +9 -9
- package/src/utils/__tests__/lazyLoad.unit.test.tsx +42 -39
- package/src/utils/file-reference/__tests__/file-reference.test.ts +4 -0
- package/src/utils/formatting/formatDate.test.ts +3 -2
- package/src/utils/formatting/formatDateTime.test.ts +2 -2
- package/src/utils/google-places/googlePlacesUtils.test.ts +36 -24
- package/src/utils/storage/README.md +1 -1
- package/src/utils/storage/__tests__/helpers.unit.test.ts +19 -12
- package/src/utils/storage/helpers.test.ts +69 -3
- package/cursor-rules/01-standards-compliance.mdc +0 -285
- package/cursor-rules/04-testing-standards.mdc +0 -270
- package/cursor-rules/05-bug-reports-and-features.mdc +0 -248
- package/cursor-rules/06-code-quality.mdc +0 -311
- package/cursor-rules/07-tech-stack-compliance.mdc +0 -216
- package/cursor-rules/10-error-handling-patterns.mdc +0 -179
- package/cursor-rules/11-performance-optimization.mdc +0 -169
- package/cursor-rules/12-ci-cd-integration.mdc +0 -150
- package/dist/DataTable-LRJL4IRV.js +0 -15
- package/dist/eslint-rules/rules/compliance.cjs +0 -348
- package/dist/eslint-rules/rules/components.cjs +0 -113
- package/dist/eslint-rules/rules/imports.cjs +0 -102
- package/docs/best-practices/README.md +0 -472
- package/docs/best-practices/accessibility.md +0 -604
- package/docs/best-practices/common-patterns.md +0 -516
- package/docs/best-practices/deployment.md +0 -1103
- package/docs/best-practices/performance.md +0 -1328
- package/docs/best-practices/security.md +0 -940
- package/docs/best-practices/testing.md +0 -1034
- package/docs/rbac/compliance/compliance-guide.md +0 -544
- package/docs/standards/01-standards-compliance.md +0 -188
- package/docs/standards/03-solid-principles.md +0 -39
- package/docs/standards/04-testing-standards.md +0 -36
- package/docs/standards/05-bug-reports-and-features.md +0 -27
- package/docs/standards/06-code-quality.md +0 -34
- package/docs/standards/07-tech-stack-compliance.md +0 -30
- package/docs/standards/10-error-handling-patterns.md +0 -401
- package/docs/standards/11-performance-optimization.md +0 -348
- package/docs/standards/12-ci-cd-integration.md +0 -370
- package/docs/standards/ALIGNMENT_REVIEW_SUMMARY.md +0 -192
- package/scripts/audit/audit-compliance.cjs +0 -1295
- package/scripts/audit/audit-components.cjs +0 -260
- package/scripts/audit/audit-rbac.cjs +0 -954
- package/scripts/audit/audit-standards.cjs +0 -1268
- package/scripts/audit/index.cjs +0 -1927
- package/src/components/DataTable/components/DataTableBody.tsx +0 -478
- package/src/components/DataTable/components/DraggableColumnHeader.tsx +0 -156
- package/src/components/DataTable/components/ExpandButton.tsx +0 -113
- package/src/components/DataTable/components/GroupHeader.tsx +0 -54
- package/src/components/DataTable/components/ViewRowModal.tsx +0 -68
- package/src/components/DataTable/components/VirtualizedDataTable.tsx +0 -525
- package/src/components/DataTable/components/__tests__/ExpandButton.test.tsx +0 -462
- package/src/components/DataTable/components/__tests__/GroupHeader.test.tsx +0 -393
- package/src/components/DataTable/components/__tests__/ViewRowModal.test.tsx +0 -476
- package/src/components/DataTable/components/__tests__/VirtualizedDataTable.test.tsx +0 -128
- package/src/components/DataTable/core/DataTableContext.tsx +0 -216
- package/src/components/DataTable/core/__tests__/DataTableContext.test.tsx +0 -136
- package/src/components/DataTable/hooks/__tests__/useColumnReordering.test.ts +0 -570
- package/src/components/DataTable/hooks/useColumnReordering.ts +0 -123
- package/src/components/DataTable/utils/debugTools.ts +0 -514
- package/src/eslint-rules/index.cjs +0 -22
- package/src/eslint-rules/rules/components.cjs +0 -113
- package/src/eslint-rules/rules/imports.cjs +0 -102
- package/src/eslint-rules/rules/rbac.cjs +0 -790
- package/src/eslint-rules/utils/helpers.cjs +0 -42
- 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
|
+
};
|