@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,346 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Code Quality Rules (Standard 4)
|
|
3
|
+
* @package @jmruthers/pace-core
|
|
4
|
+
* @module ESLintRules/rules/code-quality
|
|
5
|
+
*
|
|
6
|
+
* Enforces code quality patterns from Standard 4:
|
|
7
|
+
* - Naming conventions (hooks: use*, providers: *Provider)
|
|
8
|
+
* - TypeScript best practices
|
|
9
|
+
*
|
|
10
|
+
* Reference: packages/core/docs/standards/4-code-quality-standards.md
|
|
11
|
+
*/
|
|
12
|
+
|
|
13
|
+
const { isPaceCoreSourceFile } = require('../utils/helpers.cjs');
|
|
14
|
+
|
|
15
|
+
module.exports = {
|
|
16
|
+
rules: {
|
|
17
|
+
/**
|
|
18
|
+
* Enforce naming conventions for hooks and providers
|
|
19
|
+
*/
|
|
20
|
+
'naming-convention': {
|
|
21
|
+
meta: {
|
|
22
|
+
type: 'suggestion',
|
|
23
|
+
docs: {
|
|
24
|
+
description: 'Enforce naming conventions: hooks must start with "use", providers must end with "Provider"',
|
|
25
|
+
category: 'Best Practices',
|
|
26
|
+
recommended: true,
|
|
27
|
+
url: 'https://github.com/jmruthers/pace-core/blob/main/packages/core/docs/standards/4-code-quality-standards.md'
|
|
28
|
+
},
|
|
29
|
+
messages: {
|
|
30
|
+
hookNaming: "Hook '{{name}}' must start with 'use' (e.g., useEventData, useUserProfile)",
|
|
31
|
+
providerNaming: "Provider '{{name}}' must end with 'Provider' (e.g., AuthProvider, OrganisationProvider)"
|
|
32
|
+
},
|
|
33
|
+
hasSuggestions: true
|
|
34
|
+
},
|
|
35
|
+
create(context) {
|
|
36
|
+
const filename = context.getFilename();
|
|
37
|
+
|
|
38
|
+
// Exclude pace-core source files - these rules are for consuming apps
|
|
39
|
+
if (isPaceCoreSourceFile(filename)) {
|
|
40
|
+
return {};
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
return {
|
|
44
|
+
FunctionDeclaration(node) {
|
|
45
|
+
if (!node.id) return;
|
|
46
|
+
|
|
47
|
+
const functionName = node.id.name;
|
|
48
|
+
if (!functionName) return;
|
|
49
|
+
|
|
50
|
+
const sourceCode = context.getSourceCode();
|
|
51
|
+
const functionText = sourceCode.getText(node.body);
|
|
52
|
+
|
|
53
|
+
// Check if function returns JSX (is a component)
|
|
54
|
+
const returnsJSX = functionText.includes('return') && (functionText.includes('<') || functionText.includes('createElement'));
|
|
55
|
+
|
|
56
|
+
// Check for hooks (functions that use React hooks but are NOT components)
|
|
57
|
+
const usesReactHooks = /use(State|Effect|Callback|Memo|Ref|Context|Reducer|LayoutEffect|ImperativeHandle|DebugValue)/.test(functionText);
|
|
58
|
+
|
|
59
|
+
// Only flag as hook if:
|
|
60
|
+
// 1. It uses React hooks AND doesn't return JSX (not a component)
|
|
61
|
+
// 2. OR it starts with 'use' but doesn't return JSX (likely a hook)
|
|
62
|
+
// Components that use hooks are NOT hooks themselves
|
|
63
|
+
if (usesReactHooks && !returnsJSX) {
|
|
64
|
+
if (!functionName.startsWith('use')) {
|
|
65
|
+
context.report({
|
|
66
|
+
node: node.id,
|
|
67
|
+
messageId: 'hookNaming',
|
|
68
|
+
data: { name: functionName },
|
|
69
|
+
suggest: [{
|
|
70
|
+
desc: `Rename to use${functionName.charAt(0).toUpperCase() + functionName.slice(1)}`,
|
|
71
|
+
fix(fixer) {
|
|
72
|
+
return null; // Complex rename
|
|
73
|
+
}
|
|
74
|
+
}]
|
|
75
|
+
});
|
|
76
|
+
}
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
// Check for providers (components that CREATE a Context.Provider, not just use/wrap one)
|
|
80
|
+
// A provider component must:
|
|
81
|
+
// 1. Use createContext (creates a context)
|
|
82
|
+
// 2. Return <ContextName.Provider> (provides the context)
|
|
83
|
+
// We don't flag components that just wrap other providers (like AppProviders wrapping QueryClientProvider)
|
|
84
|
+
const createsContext = /createContext\s*\(/.test(functionText);
|
|
85
|
+
const returnsContextProvider = /<[A-Z][a-zA-Z0-9]*\.Provider/.test(functionText) ||
|
|
86
|
+
/\.Provider\s*>/.test(functionText);
|
|
87
|
+
|
|
88
|
+
// Only flag if it actually creates a context AND returns a Context.Provider
|
|
89
|
+
// AND doesn't already end with 'Provider'
|
|
90
|
+
if (returnsJSX && createsContext && returnsContextProvider && !functionName.endsWith('Provider')) {
|
|
91
|
+
context.report({
|
|
92
|
+
node: node.id,
|
|
93
|
+
messageId: 'providerNaming',
|
|
94
|
+
data: { name: functionName },
|
|
95
|
+
suggest: [{
|
|
96
|
+
desc: `Rename to ${functionName}Provider`,
|
|
97
|
+
fix(fixer) {
|
|
98
|
+
return null; // Complex rename
|
|
99
|
+
}
|
|
100
|
+
}]
|
|
101
|
+
});
|
|
102
|
+
}
|
|
103
|
+
},
|
|
104
|
+
|
|
105
|
+
VariableDeclarator(node) {
|
|
106
|
+
if (!node.id || node.id.type !== 'Identifier') return;
|
|
107
|
+
if (!node.init) return;
|
|
108
|
+
|
|
109
|
+
const varName = node.id.name;
|
|
110
|
+
if (!varName) return;
|
|
111
|
+
|
|
112
|
+
// Check for hook variables (arrow functions that use React hooks)
|
|
113
|
+
if (node.init.type === 'ArrowFunctionExpression' || node.init.type === 'FunctionExpression') {
|
|
114
|
+
const sourceCode = context.getSourceCode();
|
|
115
|
+
const functionText = sourceCode.getText(node.init);
|
|
116
|
+
|
|
117
|
+
// Check if it returns JSX (is a component)
|
|
118
|
+
const returnsJSX = functionText.includes('return') && (functionText.includes('<') || functionText.includes('createElement'));
|
|
119
|
+
const usesReactHooks = /use(State|Effect|Callback|Memo|Ref|Context|Reducer|LayoutEffect|ImperativeHandle|DebugValue)/.test(functionText);
|
|
120
|
+
|
|
121
|
+
// Only flag as hook if it uses React hooks but doesn't return JSX (not a component)
|
|
122
|
+
// Components that use hooks are NOT hooks themselves
|
|
123
|
+
if (usesReactHooks && !returnsJSX && !varName.startsWith('use')) {
|
|
124
|
+
context.report({
|
|
125
|
+
node: node.id,
|
|
126
|
+
messageId: 'hookNaming',
|
|
127
|
+
data: { name: varName },
|
|
128
|
+
suggest: [{
|
|
129
|
+
desc: `Rename to use${varName.charAt(0).toUpperCase() + varName.slice(1)}`,
|
|
130
|
+
fix(fixer) {
|
|
131
|
+
return null; // Complex rename
|
|
132
|
+
}
|
|
133
|
+
}]
|
|
134
|
+
});
|
|
135
|
+
}
|
|
136
|
+
}
|
|
137
|
+
}
|
|
138
|
+
};
|
|
139
|
+
}
|
|
140
|
+
},
|
|
141
|
+
|
|
142
|
+
/**
|
|
143
|
+
* Enforce component naming: PascalCase
|
|
144
|
+
*/
|
|
145
|
+
'component-naming': {
|
|
146
|
+
meta: {
|
|
147
|
+
type: 'suggestion',
|
|
148
|
+
docs: {
|
|
149
|
+
description: 'Enforce component naming: components must use PascalCase',
|
|
150
|
+
category: 'Best Practices',
|
|
151
|
+
recommended: true,
|
|
152
|
+
url: 'https://github.com/jmruthers/pace-core/blob/main/packages/core/docs/standards/4-code-quality-standards.md'
|
|
153
|
+
},
|
|
154
|
+
messages: {
|
|
155
|
+
componentNaming: "Component '{{name}}' must use PascalCase (e.g., EventCard, UserProfile)"
|
|
156
|
+
},
|
|
157
|
+
hasSuggestions: true
|
|
158
|
+
},
|
|
159
|
+
create(context) {
|
|
160
|
+
const filename = context.getFilename();
|
|
161
|
+
|
|
162
|
+
// Exclude pace-core source files - these rules are for consuming apps
|
|
163
|
+
if (isPaceCoreSourceFile(filename)) {
|
|
164
|
+
return {};
|
|
165
|
+
}
|
|
166
|
+
|
|
167
|
+
const isComponentFile = filename.match(/(components|Components)\//);
|
|
168
|
+
if (!isComponentFile) {
|
|
169
|
+
return {};
|
|
170
|
+
}
|
|
171
|
+
|
|
172
|
+
return {
|
|
173
|
+
FunctionDeclaration(node) {
|
|
174
|
+
if (!node.id) return;
|
|
175
|
+
|
|
176
|
+
const functionName = node.id.name;
|
|
177
|
+
if (!functionName) return;
|
|
178
|
+
|
|
179
|
+
// Skip event handlers and utility functions (these are not components)
|
|
180
|
+
const isEventHandler = functionName.startsWith('handle') ||
|
|
181
|
+
functionName.startsWith('on') ||
|
|
182
|
+
functionName.startsWith('get') ||
|
|
183
|
+
functionName.startsWith('set') ||
|
|
184
|
+
functionName.startsWith('load') ||
|
|
185
|
+
functionName.startsWith('read') ||
|
|
186
|
+
functionName.startsWith('create') ||
|
|
187
|
+
functionName.startsWith('update') ||
|
|
188
|
+
functionName.startsWith('delete');
|
|
189
|
+
|
|
190
|
+
if (isEventHandler) return;
|
|
191
|
+
|
|
192
|
+
// Only check exported components (not internal functions)
|
|
193
|
+
const isExported = node.parent?.type === 'ExportNamedDeclaration' ||
|
|
194
|
+
node.parent?.type === 'ExportDefaultDeclaration' ||
|
|
195
|
+
(node.parent?.parent?.type === 'ExportNamedDeclaration');
|
|
196
|
+
|
|
197
|
+
if (!isExported) return;
|
|
198
|
+
|
|
199
|
+
// Check if it's a component (returns JSX)
|
|
200
|
+
const sourceCode = context.getSourceCode();
|
|
201
|
+
const functionText = sourceCode.getText(node.body);
|
|
202
|
+
const returnsJSX = functionText.includes('return') && (functionText.includes('<') || functionText.includes('createElement'));
|
|
203
|
+
|
|
204
|
+
if (returnsJSX) {
|
|
205
|
+
// Check if it's PascalCase
|
|
206
|
+
const isPascalCase = /^[A-Z][a-zA-Z0-9]*$/.test(functionName);
|
|
207
|
+
if (!isPascalCase) {
|
|
208
|
+
context.report({
|
|
209
|
+
node: node.id,
|
|
210
|
+
messageId: 'componentNaming',
|
|
211
|
+
data: { name: functionName },
|
|
212
|
+
suggest: [{
|
|
213
|
+
desc: `Rename to ${functionName.charAt(0).toUpperCase() + functionName.slice(1).replace(/[^a-zA-Z0-9]/g, '')}`,
|
|
214
|
+
fix(fixer) {
|
|
215
|
+
return null; // Complex rename
|
|
216
|
+
}
|
|
217
|
+
}]
|
|
218
|
+
});
|
|
219
|
+
}
|
|
220
|
+
}
|
|
221
|
+
},
|
|
222
|
+
|
|
223
|
+
VariableDeclarator(node) {
|
|
224
|
+
if (!node.id || node.id.type !== 'Identifier') return;
|
|
225
|
+
if (!node.init) return;
|
|
226
|
+
|
|
227
|
+
const varName = node.id.name;
|
|
228
|
+
if (!varName) return;
|
|
229
|
+
|
|
230
|
+
// Skip event handlers and utility functions (these are not components)
|
|
231
|
+
const isEventHandler = varName.startsWith('handle') ||
|
|
232
|
+
varName.startsWith('on') ||
|
|
233
|
+
varName.startsWith('get') ||
|
|
234
|
+
varName.startsWith('set') ||
|
|
235
|
+
varName.startsWith('load') ||
|
|
236
|
+
varName.startsWith('read') ||
|
|
237
|
+
varName.startsWith('create') ||
|
|
238
|
+
varName.startsWith('update') ||
|
|
239
|
+
varName.startsWith('delete');
|
|
240
|
+
|
|
241
|
+
if (isEventHandler) return;
|
|
242
|
+
|
|
243
|
+
// Only check exported components (not internal functions)
|
|
244
|
+
const isExported = node.parent?.parent?.type === 'ExportNamedDeclaration' ||
|
|
245
|
+
node.parent?.parent?.type === 'ExportDefaultDeclaration';
|
|
246
|
+
|
|
247
|
+
if (!isExported) return;
|
|
248
|
+
|
|
249
|
+
// Check for component variables (arrow functions that return JSX)
|
|
250
|
+
if (node.init.type === 'ArrowFunctionExpression' || node.init.type === 'FunctionExpression') {
|
|
251
|
+
const sourceCode = context.getSourceCode();
|
|
252
|
+
const functionText = sourceCode.getText(node.init);
|
|
253
|
+
const returnsJSX = functionText.includes('return') && (functionText.includes('<') || functionText.includes('createElement'));
|
|
254
|
+
|
|
255
|
+
if (returnsJSX) {
|
|
256
|
+
const isPascalCase = /^[A-Z][a-zA-Z0-9]*$/.test(varName);
|
|
257
|
+
if (!isPascalCase) {
|
|
258
|
+
context.report({
|
|
259
|
+
node: node.id,
|
|
260
|
+
messageId: 'componentNaming',
|
|
261
|
+
data: { name: varName },
|
|
262
|
+
suggest: [{
|
|
263
|
+
desc: `Rename to ${varName.charAt(0).toUpperCase() + varName.slice(1).replace(/[^a-zA-Z0-9]/g, '')}`,
|
|
264
|
+
fix(fixer) {
|
|
265
|
+
return null; // Complex rename
|
|
266
|
+
}
|
|
267
|
+
}]
|
|
268
|
+
});
|
|
269
|
+
}
|
|
270
|
+
}
|
|
271
|
+
}
|
|
272
|
+
}
|
|
273
|
+
};
|
|
274
|
+
}
|
|
275
|
+
},
|
|
276
|
+
|
|
277
|
+
/**
|
|
278
|
+
* Enforce type/interface naming: PascalCase
|
|
279
|
+
*/
|
|
280
|
+
'type-naming': {
|
|
281
|
+
meta: {
|
|
282
|
+
type: 'suggestion',
|
|
283
|
+
docs: {
|
|
284
|
+
description: 'Enforce type/interface naming: types and interfaces must use PascalCase',
|
|
285
|
+
category: 'Best Practices',
|
|
286
|
+
recommended: true,
|
|
287
|
+
url: 'https://github.com/jmruthers/pace-core/blob/main/packages/core/docs/standards/4-code-quality-standards.md'
|
|
288
|
+
},
|
|
289
|
+
messages: {
|
|
290
|
+
typeNaming: "Type/interface '{{name}}' must use PascalCase (e.g., EventStatus, UserProfile)"
|
|
291
|
+
},
|
|
292
|
+
hasSuggestions: true
|
|
293
|
+
},
|
|
294
|
+
create(context) {
|
|
295
|
+
const filename = context.getFilename();
|
|
296
|
+
|
|
297
|
+
// Exclude pace-core source files - these rules are for consuming apps
|
|
298
|
+
if (isPaceCoreSourceFile(filename)) {
|
|
299
|
+
return {};
|
|
300
|
+
}
|
|
301
|
+
|
|
302
|
+
return {
|
|
303
|
+
TSInterfaceDeclaration(node) {
|
|
304
|
+
const interfaceName = node.id.name;
|
|
305
|
+
if (!interfaceName) return;
|
|
306
|
+
|
|
307
|
+
const isPascalCase = /^[A-Z][a-zA-Z0-9]*$/.test(interfaceName);
|
|
308
|
+
if (!isPascalCase) {
|
|
309
|
+
context.report({
|
|
310
|
+
node: node.id,
|
|
311
|
+
messageId: 'typeNaming',
|
|
312
|
+
data: { name: interfaceName },
|
|
313
|
+
suggest: [{
|
|
314
|
+
desc: `Rename to ${interfaceName.charAt(0).toUpperCase() + interfaceName.slice(1).replace(/[^a-zA-Z0-9]/g, '')}`,
|
|
315
|
+
fix(fixer) {
|
|
316
|
+
return null; // Complex rename
|
|
317
|
+
}
|
|
318
|
+
}]
|
|
319
|
+
});
|
|
320
|
+
}
|
|
321
|
+
},
|
|
322
|
+
|
|
323
|
+
TSTypeAliasDeclaration(node) {
|
|
324
|
+
const typeName = node.id.name;
|
|
325
|
+
if (!typeName) return;
|
|
326
|
+
|
|
327
|
+
const isPascalCase = /^[A-Z][a-zA-Z0-9]*$/.test(typeName);
|
|
328
|
+
if (!isPascalCase) {
|
|
329
|
+
context.report({
|
|
330
|
+
node: node.id,
|
|
331
|
+
messageId: 'typeNaming',
|
|
332
|
+
data: { name: typeName },
|
|
333
|
+
suggest: [{
|
|
334
|
+
desc: `Rename to ${typeName.charAt(0).toUpperCase() + typeName.slice(1).replace(/[^a-zA-Z0-9]/g, '')}`,
|
|
335
|
+
fix(fixer) {
|
|
336
|
+
return null; // Complex rename
|
|
337
|
+
}
|
|
338
|
+
}]
|
|
339
|
+
});
|
|
340
|
+
}
|
|
341
|
+
}
|
|
342
|
+
};
|
|
343
|
+
}
|
|
344
|
+
}
|
|
345
|
+
}
|
|
346
|
+
};
|
|
@@ -0,0 +1,61 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Styling Rules (Standard 5)
|
|
3
|
+
* @package @jmruthers/pace-core
|
|
4
|
+
* @module ESLintRules/rules/styling
|
|
5
|
+
*
|
|
6
|
+
* Enforces styling patterns from Standard 5:
|
|
7
|
+
* - No inline styles (use pace-core components or Tailwind classes)
|
|
8
|
+
*
|
|
9
|
+
* Reference: packages/core/docs/standards/5-styling-standards.md
|
|
10
|
+
*/
|
|
11
|
+
|
|
12
|
+
const { isPaceCoreSourceFile } = require('../utils/helpers.cjs');
|
|
13
|
+
|
|
14
|
+
module.exports = {
|
|
15
|
+
rules: {
|
|
16
|
+
/**
|
|
17
|
+
* Disallow inline styles
|
|
18
|
+
*/
|
|
19
|
+
'no-inline-styles': {
|
|
20
|
+
meta: {
|
|
21
|
+
type: 'problem',
|
|
22
|
+
docs: {
|
|
23
|
+
description: 'Disallow inline styles. Use pace-core components or Tailwind classes instead.',
|
|
24
|
+
category: 'Best Practices',
|
|
25
|
+
recommended: true,
|
|
26
|
+
url: 'https://github.com/jmruthers/pace-core/blob/main/packages/core/docs/standards/5-styling-standards.md'
|
|
27
|
+
},
|
|
28
|
+
messages: {
|
|
29
|
+
inlineStyle: 'Inline style detected. Use pace-core components or Tailwind classes instead.'
|
|
30
|
+
},
|
|
31
|
+
hasSuggestions: true
|
|
32
|
+
},
|
|
33
|
+
create(context) {
|
|
34
|
+
const filename = context.getFilename();
|
|
35
|
+
|
|
36
|
+
// Exclude pace-core source files - these rules are for consuming apps
|
|
37
|
+
if (isPaceCoreSourceFile(filename)) {
|
|
38
|
+
return {};
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
return {
|
|
42
|
+
JSXAttribute(node) {
|
|
43
|
+
if (node.name && node.name.name === 'style') {
|
|
44
|
+
context.report({
|
|
45
|
+
node,
|
|
46
|
+
messageId: 'inlineStyle',
|
|
47
|
+
suggest: [{
|
|
48
|
+
desc: 'Remove inline style and use pace-core component styling or Tailwind utility classes',
|
|
49
|
+
fix(fixer) {
|
|
50
|
+
// Remove the style attribute
|
|
51
|
+
return fixer.remove(node);
|
|
52
|
+
}
|
|
53
|
+
}]
|
|
54
|
+
});
|
|
55
|
+
}
|
|
56
|
+
}
|
|
57
|
+
};
|
|
58
|
+
}
|
|
59
|
+
}
|
|
60
|
+
}
|
|
61
|
+
};
|
|
@@ -1,7 +1,15 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* RBAC
|
|
2
|
+
* Security & RBAC Rules (Standard 6)
|
|
3
3
|
* @package @jmruthers/pace-core
|
|
4
|
-
* @module ESLintRules/rules/rbac
|
|
4
|
+
* @module ESLintRules/rules/security-rbac
|
|
5
|
+
*
|
|
6
|
+
* Enforces security and RBAC patterns from Standard 6:
|
|
7
|
+
* - Use secure Supabase client (useSecureSupabase)
|
|
8
|
+
* - Use RESOURCE_NAMES constants
|
|
9
|
+
* - No wrapper components/functions around RBAC hooks
|
|
10
|
+
* - Proper permission loading state handling
|
|
11
|
+
*
|
|
12
|
+
* Reference: packages/core/docs/standards/6-security-rbac-standards.md
|
|
5
13
|
*/
|
|
6
14
|
|
|
7
15
|
const { isPaceCoreSourceFile } = require('../utils/helpers.cjs');
|
|
@@ -17,7 +25,8 @@ module.exports = {
|
|
|
17
25
|
docs: {
|
|
18
26
|
description: 'Disallow direct createClient calls from @supabase/supabase-js. Use useSecureSupabase() from pace-core instead to ensure organisation context and RLS policies are enforced.',
|
|
19
27
|
category: 'Security',
|
|
20
|
-
recommended: true
|
|
28
|
+
recommended: true,
|
|
29
|
+
url: 'https://github.com/jmruthers/pace-core/blob/main/packages/core/docs/standards/6-security-rbac-standards.md'
|
|
21
30
|
},
|
|
22
31
|
messages: {
|
|
23
32
|
directClientCreation: "Direct Supabase client creation detected. You MUST use useSecureSupabase() from '@jmruthers/pace-core/rbac' instead to ensure organisation context and RLS policies are enforced. This prevents cross-organisation data access.",
|
|
@@ -33,6 +42,11 @@ module.exports = {
|
|
|
33
42
|
return {};
|
|
34
43
|
}
|
|
35
44
|
|
|
45
|
+
// Exclude Edge Functions - they run in Deno and cannot use React hooks
|
|
46
|
+
// Edge Functions must use createClient() directly with service role keys
|
|
47
|
+
const isEdgeFunction = filename.includes('supabase/functions/') ||
|
|
48
|
+
filename.includes('supabase\\functions\\');
|
|
49
|
+
|
|
36
50
|
// Allow createClient in specific config files (supabaseClient.ts/js, etc.)
|
|
37
51
|
const isConfigFile = /(supabase|client)\.(ts|js|tsx|jsx)$/i.test(filename) &&
|
|
38
52
|
(filename.includes('supabase') || filename.includes('client'));
|
|
@@ -54,7 +68,7 @@ module.exports = {
|
|
|
54
68
|
return false;
|
|
55
69
|
});
|
|
56
70
|
|
|
57
|
-
if (hasCreateClient && !isConfigFile) {
|
|
71
|
+
if (hasCreateClient && !isConfigFile && !isEdgeFunction) {
|
|
58
72
|
context.report({
|
|
59
73
|
node: node.source,
|
|
60
74
|
messageId: 'directClientImport',
|
|
@@ -72,7 +86,7 @@ module.exports = {
|
|
|
72
86
|
CallExpression(node) {
|
|
73
87
|
// Check for createClient() calls
|
|
74
88
|
if (node.callee.type === 'Identifier' && node.callee.name === 'createClient') {
|
|
75
|
-
if (!isConfigFile) {
|
|
89
|
+
if (!isConfigFile && !isEdgeFunction) {
|
|
76
90
|
context.report({
|
|
77
91
|
node,
|
|
78
92
|
messageId: 'directClientCreation',
|
|
@@ -89,7 +103,7 @@ module.exports = {
|
|
|
89
103
|
// Check for supabase.createClient() or similar patterns
|
|
90
104
|
if (node.callee.type === 'MemberExpression' &&
|
|
91
105
|
node.callee.property?.name === 'createClient') {
|
|
92
|
-
if (!isConfigFile) {
|
|
106
|
+
if (!isConfigFile && !isEdgeFunction) {
|
|
93
107
|
context.report({
|
|
94
108
|
node,
|
|
95
109
|
messageId: 'directClientCreation',
|
|
@@ -116,7 +130,8 @@ module.exports = {
|
|
|
116
130
|
docs: {
|
|
117
131
|
description: 'Require isLoading extraction from useResourcePermissions and check it before permission calls in mutations.',
|
|
118
132
|
category: 'Security',
|
|
119
|
-
recommended: true
|
|
133
|
+
recommended: true,
|
|
134
|
+
url: 'https://github.com/jmruthers/pace-core/blob/main/packages/core/docs/standards/6-security-rbac-standards.md'
|
|
120
135
|
},
|
|
121
136
|
messages: {
|
|
122
137
|
missingIsLoading: "useResourcePermissions is used but 'isLoading' is not extracted. Permission checks may fail if scope resolution is still in progress.",
|
|
@@ -237,7 +252,8 @@ module.exports = {
|
|
|
237
252
|
docs: {
|
|
238
253
|
description: 'Disallow direct calls to RBAC RPC functions. Use pace-core RBAC hooks instead.',
|
|
239
254
|
category: 'Security',
|
|
240
|
-
recommended: true
|
|
255
|
+
recommended: true,
|
|
256
|
+
url: 'https://github.com/jmruthers/pace-core/blob/main/packages/core/docs/standards/6-security-rbac-standards.md'
|
|
241
257
|
},
|
|
242
258
|
messages: {
|
|
243
259
|
directRbacRpc: "Direct RPC call to '{{rpcName}}' detected. Use pace-core RBAC hooks from '@jmruthers/pace-core/rbac' instead."
|
|
@@ -296,7 +312,8 @@ module.exports = {
|
|
|
296
312
|
docs: {
|
|
297
313
|
description: 'Disallow direct queries to RBAC tables. Use pace-core RBAC API functions or useSecureSupabase instead.',
|
|
298
314
|
category: 'Security',
|
|
299
|
-
recommended: true
|
|
315
|
+
recommended: true,
|
|
316
|
+
url: 'https://github.com/jmruthers/pace-core/blob/main/packages/core/docs/standards/6-security-rbac-standards.md'
|
|
300
317
|
},
|
|
301
318
|
messages: {
|
|
302
319
|
directRbacTable: "Direct query to RBAC table '{{tableName}}' detected. Use pace-core RBAC API functions from '@jmruthers/pace-core/rbac' or useSecureSupabase hook instead."
|
|
@@ -402,7 +419,8 @@ module.exports = {
|
|
|
402
419
|
docs: {
|
|
403
420
|
description: 'Disallow hardcoded role checks. Use useAccessLevel hook or getRoleContext API from pace-core instead.',
|
|
404
421
|
category: 'Security',
|
|
405
|
-
recommended: true
|
|
422
|
+
recommended: true,
|
|
423
|
+
url: 'https://github.com/jmruthers/pace-core/blob/main/packages/core/docs/standards/6-security-rbac-standards.md'
|
|
406
424
|
},
|
|
407
425
|
messages: {
|
|
408
426
|
hardcodedRoleCheck: "Hardcoded role check detected. Use useAccessLevel hook or getRoleContext API from '@jmruthers/pace-core/rbac' instead."
|
|
@@ -471,7 +489,8 @@ module.exports = {
|
|
|
471
489
|
docs: {
|
|
472
490
|
description: 'Require RESOURCE_NAMES constants instead of string literals in useResourcePermissions calls.',
|
|
473
491
|
category: 'Best Practices',
|
|
474
|
-
recommended: true
|
|
492
|
+
recommended: true,
|
|
493
|
+
url: 'https://github.com/jmruthers/pace-core/blob/main/packages/core/docs/standards/6-security-rbac-standards.md'
|
|
475
494
|
},
|
|
476
495
|
messages: {
|
|
477
496
|
resourcePermissionStringLiteral: "Resource permission string literal detected. Use RESOURCE_NAMES constant object instead (e.g., RESOURCE_NAMES.ORGANISATIONS, RESOURCE_NAMES.EVENTS)."
|
|
@@ -536,7 +555,8 @@ module.exports = {
|
|
|
536
555
|
docs: {
|
|
537
556
|
description: 'Disallow wrapper components around PagePermissionGuard. Use PagePermissionGuard directly.',
|
|
538
557
|
category: 'Security',
|
|
539
|
-
recommended: true
|
|
558
|
+
recommended: true,
|
|
559
|
+
url: 'https://github.com/jmruthers/pace-core/blob/main/packages/core/docs/standards/6-security-rbac-standards.md'
|
|
540
560
|
},
|
|
541
561
|
messages: {
|
|
542
562
|
wrapperComponent: "Wrapper component '{{componentName}}' detected around PagePermissionGuard. Must use PagePermissionGuard directly, not through wrappers."
|
|
@@ -643,7 +663,8 @@ module.exports = {
|
|
|
643
663
|
docs: {
|
|
644
664
|
description: 'Disallow wrapper functions around pace-core permission hooks. Use hooks directly in components.',
|
|
645
665
|
category: 'Security',
|
|
646
|
-
recommended: true
|
|
666
|
+
recommended: true,
|
|
667
|
+
url: 'https://github.com/jmruthers/pace-core/blob/main/packages/core/docs/standards/6-security-rbac-standards.md'
|
|
647
668
|
},
|
|
648
669
|
messages: {
|
|
649
670
|
wrapperFunction: "Permission wrapper function '{{functionName}}' detected. Use pace-core hooks (useCan, useResourcePermissions) directly in components instead of wrapping them."
|