@jmruthers/pace-core 0.6.6 → 0.6.7
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/{scripts/audit/audit-dependencies.cjs → audit-tool/00-dependencies.cjs} +12 -13
- package/audit-tool/audits/01-pace-core-compliance.cjs +556 -0
- package/audit-tool/audits/02-project-structure.cjs +255 -0
- package/audit-tool/audits/03-architecture.cjs +196 -0
- package/audit-tool/audits/04-code-quality.cjs +149 -0
- package/audit-tool/audits/05-styling.cjs +224 -0
- package/audit-tool/audits/06-security-rbac.cjs +544 -0
- package/audit-tool/audits/07-api-tech-stack.cjs +301 -0
- package/audit-tool/audits/08-testing-documentation.cjs +202 -0
- package/audit-tool/audits/09-operations.cjs +208 -0
- package/audit-tool/index.cjs +291 -0
- package/audit-tool/utils/code-utils.cjs +218 -0
- package/audit-tool/utils/file-utils.cjs +230 -0
- package/audit-tool/utils/report-utils.cjs +241 -0
- package/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-7PMH7XN7.js +15 -0
- package/dist/{DataTable-2N_tqbfq.d.ts → DataTable-DRUIgtUH.d.ts} +1 -1
- package/dist/{PublicPageProvider-BBH6Vqg7.d.ts → PublicPageProvider-DlsCaR5v.d.ts} +26 -16
- package/dist/{chunk-FENMYN2U.js → chunk-5X4QLXRG.js} +1 -3
- package/dist/{chunk-4T7OBVTU.js → chunk-6F3IILHI.js} +1 -1
- package/dist/{chunk-SD6WQY43.js → chunk-7ILTDCL2.js} +9 -1
- package/dist/{chunk-3QC3KRHK.js → chunk-A3W6LW53.js} +16 -1
- package/dist/{chunk-7TYHROIV.js → chunk-BM4CQ5P3.js} +50 -8
- package/dist/{chunk-2HGJFNAH.js → chunk-FEJLJNWA.js} +1 -15
- package/dist/{chunk-OHIK3MIO.js → chunk-GHYHJTYV.js} +2 -2
- package/dist/{chunk-UIYSCEV7.js → chunk-IUBRCBSY.js} +1 -1
- package/dist/{chunk-LAZMKTTF.js → chunk-JGWDVX64.js} +281 -347
- package/dist/{chunk-MAGBIDNS.js → chunk-L4XMVJKY.js} +2 -2
- package/dist/{chunk-A55DK444.js → chunk-OJ4SKRSV.js} +1 -7
- package/dist/{chunk-ZS5VO5JB.js → chunk-Q7Q7V5NV.js} +406 -451
- package/dist/{chunk-3O3WHILE.js → chunk-VBCS3DUA.js} +236 -60
- package/dist/{chunk-BVP2BCJF.js → chunk-ZKAWKYT4.js} +8 -8
- package/dist/components.d.ts +5 -4
- package/dist/components.js +27 -32
- 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 +290 -0
- package/dist/eslint-rules/rules/05-styling.cjs +61 -0
- package/dist/eslint-rules/rules/{rbac.cjs → 06-security-rbac.cjs} +26 -10
- package/dist/eslint-rules/rules/07-api-tech-stack.cjs +263 -0
- package/dist/eslint-rules/rules/08-testing.cjs +94 -0
- package/dist/hooks.d.ts +5 -5
- package/dist/hooks.js +6 -6
- package/dist/index.d.ts +6 -6
- package/dist/index.js +18 -17
- package/dist/rbac/index.js +6 -6
- package/dist/theming/runtime.d.ts +14 -1
- package/dist/theming/runtime.js +1 -1
- package/dist/{types-B-K_5VnO.d.ts → types-DXstZpNI.d.ts} +0 -17
- 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 +47 -31
- 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/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/authentication.md +15 -15
- package/docs/implementation-guides/component-styling.md +1 -1
- package/docs/implementation-guides/data-tables.md +126 -33
- package/docs/implementation-guides/datatable-rbac-usage.md +1 -1
- package/docs/implementation-guides/dynamic-colors.md +3 -3
- package/docs/implementation-guides/file-upload-storage.md +2 -2
- package/docs/implementation-guides/hierarchical-datatable.md +40 -60
- package/docs/implementation-guides/inactivity-tracking.md +3 -3
- package/docs/implementation-guides/large-datasets.md +3 -2
- package/docs/implementation-guides/organisation-security.md +2 -2
- package/docs/implementation-guides/performance.md +2 -2
- package/docs/implementation-guides/permission-enforcement.md +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} +204 -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 +21 -10
- package/package.json +6 -5
- package/scripts/install-cursor-rules.cjs +11 -243
- package/scripts/install-eslint-config.cjs +284 -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 +10 -10
- 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 +9 -9
- package/src/__tests__/templates/component.test.template.tsx +18 -15
- package/src/components/Calendar/Calendar.tsx +201 -47
- package/src/components/ContextSelector/ContextSelector.tsx +137 -153
- package/src/components/DataTable/AUDIT_REPORT.md +293 -0
- package/src/components/DataTable/__tests__/DataTableCore.test.tsx +10 -2
- package/src/components/DataTable/__tests__/a11y.basic.test.tsx +10 -4
- package/src/components/DataTable/__tests__/test-utils/sharedTestUtils.tsx +9 -9
- package/src/components/DataTable/components/ColumnFilter.tsx +63 -74
- package/src/components/DataTable/components/ColumnVisibilityDropdown.tsx +43 -41
- package/src/components/DataTable/components/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 +10 -9
- package/src/components/DataTable/components/FilterRow.tsx +2 -4
- package/src/components/DataTable/components/ImportModal.tsx +124 -126
- package/src/components/DataTable/components/LoadingState.tsx +5 -6
- package/src/components/DataTable/components/SortIndicator.tsx +50 -0
- package/src/components/DataTable/components/__tests__/COVERAGE_NOTE.md +4 -4
- package/src/components/DataTable/components/__tests__/ColumnFilter.test.tsx +23 -82
- package/src/components/DataTable/components/__tests__/DataTableErrorBoundary.test.tsx +37 -9
- package/src/components/DataTable/components/__tests__/EmptyState.test.tsx +7 -4
- package/src/components/DataTable/components/__tests__/FilterRow.test.tsx +12 -4
- package/src/components/DataTable/components/__tests__/LoadingState.test.tsx +41 -27
- package/src/components/DataTable/components/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 +2 -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 +52 -14
- package/src/components/FileUpload/FileUpload.tsx +112 -130
- 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__/useFocusTrap.unit.test.tsx +97 -97
- 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 +5 -5
- package/src/hooks/useAppConfig.ts +2 -2
- package/src/hooks/useEventTheme.test.ts +7 -7
- package/src/hooks/useEventTheme.ts +1 -4
- package/src/hooks/useFileDisplay.ts +2 -2
- package/src/providers/UnifiedAuthProvider.smoke.test.tsx +21 -21
- package/src/providers/__tests__/AuthProvider.test.tsx +21 -21
- package/src/providers/__tests__/EventProvider.test.tsx +61 -61
- package/src/providers/__tests__/InactivityProvider.test.tsx +56 -56
- package/src/providers/__tests__/OrganisationProvider.test.tsx +75 -75
- package/src/providers/__tests__/ProviderLifecycle.test.tsx +37 -37
- package/src/providers/__tests__/UnifiedAuthProvider.test.tsx +103 -103
- package/src/providers/services/__tests__/AuthServiceProvider.integration.test.tsx +7 -7
- package/src/providers/services/__tests__/UnifiedAuthProvider.integration.test.tsx +10 -10
- package/src/styles/core.css +7 -0
- package/src/theming/__tests__/parseEventColours.test.ts +9 -3
- package/src/theming/parseEventColours.ts +22 -10
- package/src/utils/__tests__/lazyLoad.unit.test.tsx +42 -39
- package/src/utils/storage/README.md +1 -1
- 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
|
@@ -1,169 +0,0 @@
|
|
|
1
|
-
---
|
|
2
|
-
description: Enforce performance optimization patterns including React memoization, database query optimization, and caching strategies
|
|
3
|
-
globs: ["src/**/*.{ts,tsx,js,jsx}", "supabase/migrations/**/*.sql"]
|
|
4
|
-
alwaysApply: false
|
|
5
|
-
paceCoreVersion: "0.6.x"
|
|
6
|
-
rulesVersion: "2025-01-28"
|
|
7
|
-
---
|
|
8
|
-
# Performance Optimization Guide
|
|
9
|
-
|
|
10
|
-
**📚 Human-Readable Standard**: See [11-performance-optimization.md](../../packages/core/docs/standards/11-performance-optimization.md) for complete documentation.
|
|
11
|
-
|
|
12
|
-
This guide enforces performance optimization patterns to ensure fast, responsive applications.
|
|
13
|
-
|
|
14
|
-
**AI Agent Instructions**: When writing performance-sensitive code, ALWAYS apply these optimizations. Use the decision trees below to determine when to optimize.
|
|
15
|
-
|
|
16
|
-
## MUST: Optimize React Re-renders
|
|
17
|
-
|
|
18
|
-
**MUST use memoization for expensive computations and stable references:**
|
|
19
|
-
|
|
20
|
-
```tsx
|
|
21
|
-
// ✅ CORRECT - Memoize expensive computation
|
|
22
|
-
const expensiveValue = useMemo(() => computeExpensiveValue(data), [data]);
|
|
23
|
-
|
|
24
|
-
// ✅ CORRECT - Stable callback reference
|
|
25
|
-
const handleClick = useCallback(() => doSomething(id), [id]);
|
|
26
|
-
|
|
27
|
-
// ✅ CORRECT - Memoize component
|
|
28
|
-
const ExpensiveComponent = React.memo(({ data }) => <div>{/* ... */}</div>);
|
|
29
|
-
|
|
30
|
-
// ❌ WRONG - Recomputes on every render
|
|
31
|
-
const expensiveValue = computeExpensiveValue(data);
|
|
32
|
-
const handleClick = () => doSomething(id);
|
|
33
|
-
```
|
|
34
|
-
|
|
35
|
-
## MUST: Avoid Creating New Objects in Render
|
|
36
|
-
|
|
37
|
-
**MUST NOT create new objects/arrays in render:**
|
|
38
|
-
|
|
39
|
-
```tsx
|
|
40
|
-
// ❌ WRONG - New object on every render
|
|
41
|
-
function Component({ items }) {
|
|
42
|
-
const config = { items, enabled: true };
|
|
43
|
-
return <Child config={config} />;
|
|
44
|
-
}
|
|
45
|
-
|
|
46
|
-
// ✅ CORRECT - Memoize object
|
|
47
|
-
function Component({ items }) {
|
|
48
|
-
const config = useMemo(() => ({ items, enabled: true }), [items]);
|
|
49
|
-
return <Child config={config} />;
|
|
50
|
-
}
|
|
51
|
-
```
|
|
52
|
-
|
|
53
|
-
## MUST: Use Helper Functions in RLS Policies
|
|
54
|
-
|
|
55
|
-
**MUST use STABLE SECURITY DEFINER helper functions (never subqueries):**
|
|
56
|
-
|
|
57
|
-
```sql
|
|
58
|
-
-- ✅ CORRECT - Helper function (evaluated once)
|
|
59
|
-
CREATE POLICY "rbac_select_users" ON users FOR SELECT USING (
|
|
60
|
-
check_user_organisation_access(organisation_id)
|
|
61
|
-
);
|
|
62
|
-
|
|
63
|
-
-- ❌ WRONG - Subquery (N+1 performance issue)
|
|
64
|
-
CREATE POLICY "rbac_select_users" ON users FOR SELECT USING (
|
|
65
|
-
organisation_id IN (SELECT organisation_id FROM organisation_memberships WHERE user_id = auth.uid())
|
|
66
|
-
);
|
|
67
|
-
```
|
|
68
|
-
|
|
69
|
-
## SHOULD: Lazy Load Heavy Components
|
|
70
|
-
|
|
71
|
-
**SHOULD lazy load heavy components:**
|
|
72
|
-
|
|
73
|
-
```tsx
|
|
74
|
-
// ✅ CORRECT - Lazy load
|
|
75
|
-
import { lazy, Suspense } from 'react';
|
|
76
|
-
const HeavyComponent = lazy(() => import('./HeavyComponent'));
|
|
77
|
-
<Suspense fallback={<Loading />}><HeavyComponent /></Suspense>
|
|
78
|
-
```
|
|
79
|
-
|
|
80
|
-
## SHOULD: Configure TanStack Query Cache
|
|
81
|
-
|
|
82
|
-
**SHOULD configure appropriate cache times:**
|
|
83
|
-
|
|
84
|
-
```tsx
|
|
85
|
-
// ✅ CORRECT - Configure cache
|
|
86
|
-
const queryClient = new QueryClient({
|
|
87
|
-
defaultOptions: {
|
|
88
|
-
queries: {
|
|
89
|
-
staleTime: 5 * 60 * 1000,
|
|
90
|
-
cacheTime: 10 * 60 * 1000,
|
|
91
|
-
retry: 1,
|
|
92
|
-
refetchOnWindowFocus: false,
|
|
93
|
-
},
|
|
94
|
-
},
|
|
95
|
-
});
|
|
96
|
-
```
|
|
97
|
-
|
|
98
|
-
## SHOULD: Use RPC Functions for Complex Queries
|
|
99
|
-
|
|
100
|
-
**SHOULD use RPC functions instead of complex client-side queries:**
|
|
101
|
-
|
|
102
|
-
```tsx
|
|
103
|
-
// ✅ CORRECT - RPC for complex query
|
|
104
|
-
const { data } = await supabase.rpc('data_events_list', { organisation_id: orgId });
|
|
105
|
-
|
|
106
|
-
// ❌ AVOID - Complex client-side query
|
|
107
|
-
const { data } = await supabase.from('events').select('*, users(*), organisations(*)').eq('organisation_id', orgId);
|
|
108
|
-
```
|
|
109
|
-
|
|
110
|
-
## Decision Tree: Performance Optimization
|
|
111
|
-
|
|
112
|
-
**ALWAYS follow this decision tree:**
|
|
113
|
-
|
|
114
|
-
```
|
|
115
|
-
1. Is this expensive computation?
|
|
116
|
-
├─ YES → Use useMemo
|
|
117
|
-
└─ NO → Don't memoize (overhead not worth it)
|
|
118
|
-
|
|
119
|
-
2. Is this function passed as prop?
|
|
120
|
-
├─ YES → Use useCallback
|
|
121
|
-
└─ NO → Regular function is fine
|
|
122
|
-
|
|
123
|
-
3. Is this component expensive to render?
|
|
124
|
-
├─ YES → Use React.memo
|
|
125
|
-
└─ NO → Regular component is fine
|
|
126
|
-
|
|
127
|
-
4. Is this creating new object/array in render?
|
|
128
|
-
├─ YES → Memoize with useMemo
|
|
129
|
-
└─ NO → Continue
|
|
130
|
-
|
|
131
|
-
5. Is this RLS policy?
|
|
132
|
-
├─ YES → Use helper function (STABLE SECURITY DEFINER)
|
|
133
|
-
└─ NO → Continue
|
|
134
|
-
|
|
135
|
-
6. Is this complex query?
|
|
136
|
-
├─ YES → Use RPC function
|
|
137
|
-
└─ NO → Client-side query is fine
|
|
138
|
-
```
|
|
139
|
-
|
|
140
|
-
## Performance Checklist
|
|
141
|
-
|
|
142
|
-
Before committing performance-sensitive code, verify:
|
|
143
|
-
|
|
144
|
-
- [ ] Expensive computations memoized
|
|
145
|
-
- [ ] Callbacks stable with useCallback
|
|
146
|
-
- [ ] Components memoized when appropriate
|
|
147
|
-
- [ ] No new objects/arrays in render
|
|
148
|
-
- [ ] Heavy components lazy loaded
|
|
149
|
-
- [ ] RLS policies use helper functions
|
|
150
|
-
- [ ] Queries use indexes appropriately
|
|
151
|
-
- [ ] No N+1 query patterns
|
|
152
|
-
- [ ] TanStack Query configured properly
|
|
153
|
-
- [ ] Bundle size optimized
|
|
154
|
-
|
|
155
|
-
## Common Performance Pitfalls
|
|
156
|
-
|
|
157
|
-
1. **Creating new objects in render** - Memoize with useMemo
|
|
158
|
-
2. **Using inline functions** - Use useCallback
|
|
159
|
-
3. **Over-memoizing** - Only memoize expensive operations
|
|
160
|
-
4. **Subqueries in RLS** - Use helper functions
|
|
161
|
-
5. **N+1 queries** - Use joins or RPC functions
|
|
162
|
-
6. **Not lazy loading** - Lazy load heavy components
|
|
163
|
-
7. **Poor cache configuration** - Configure TanStack Query properly
|
|
164
|
-
|
|
165
|
-
## Reference
|
|
166
|
-
|
|
167
|
-
- **Standard**: `packages/core/docs/standards/11-performance-optimization.md`
|
|
168
|
-
- **RLS**: See `09-rbac-compliance.mdc` for RLS performance requirements
|
|
169
|
-
- **Code Quality**: See `06-code-quality.mdc` for React patterns
|
|
@@ -1,150 +0,0 @@
|
|
|
1
|
-
---
|
|
2
|
-
description: Enforce CI/CD integration patterns including automated quality checks, deployment processes, and security scanning
|
|
3
|
-
globs: [".github/workflows/**/*.yml", ".github/workflows/**/*.yaml", "package.json"]
|
|
4
|
-
alwaysApply: false
|
|
5
|
-
paceCoreVersion: "0.6.x"
|
|
6
|
-
rulesVersion: "2025-01-28"
|
|
7
|
-
---
|
|
8
|
-
# CI/CD Integration Guide
|
|
9
|
-
|
|
10
|
-
**📚 Human-Readable Standard**: See [12-ci-cd-integration.md](../../packages/core/docs/standards/12-ci-cd-integration.md) for complete documentation.
|
|
11
|
-
|
|
12
|
-
This guide enforces CI/CD integration patterns to ensure automated quality checks and consistent deployments.
|
|
13
|
-
|
|
14
|
-
**AI Agent Instructions**: When setting up CI/CD pipelines, ALWAYS include the required checks below. Use the decision tree to determine what checks are needed.
|
|
15
|
-
|
|
16
|
-
## MUST: Include Required CI Checks
|
|
17
|
-
|
|
18
|
-
**MUST run these checks in every CI pipeline:**
|
|
19
|
-
|
|
20
|
-
```yaml
|
|
21
|
-
# ✅ CORRECT - Required checks
|
|
22
|
-
jobs:
|
|
23
|
-
quality-checks:
|
|
24
|
-
steps:
|
|
25
|
-
- name: Lint
|
|
26
|
-
run: npm run lint
|
|
27
|
-
- name: Type check
|
|
28
|
-
run: npx tsc --noEmit
|
|
29
|
-
- name: Run tests
|
|
30
|
-
run: npm run test
|
|
31
|
-
- name: Build
|
|
32
|
-
run: npm run build
|
|
33
|
-
```
|
|
34
|
-
|
|
35
|
-
## MUST: Have Required Scripts
|
|
36
|
-
|
|
37
|
-
**MUST have these scripts in package.json:**
|
|
38
|
-
|
|
39
|
-
```json
|
|
40
|
-
// ✅ CORRECT - Required scripts
|
|
41
|
-
{
|
|
42
|
-
"scripts": {
|
|
43
|
-
"lint": "eslint .",
|
|
44
|
-
"type-check": "tsc --noEmit",
|
|
45
|
-
"test": "vitest run",
|
|
46
|
-
"build": "vite build"
|
|
47
|
-
}
|
|
48
|
-
}
|
|
49
|
-
```
|
|
50
|
-
|
|
51
|
-
## SHOULD: Include Additional Checks
|
|
52
|
-
|
|
53
|
-
**SHOULD include these checks:**
|
|
54
|
-
|
|
55
|
-
```yaml
|
|
56
|
-
# ✅ RECOMMENDED - Additional checks
|
|
57
|
-
- name: Format check
|
|
58
|
-
run: npm run format:check
|
|
59
|
-
- name: Security scan
|
|
60
|
-
run: npm audit --audit-level=moderate
|
|
61
|
-
- name: Coverage check
|
|
62
|
-
run: npm run test:coverage
|
|
63
|
-
```
|
|
64
|
-
|
|
65
|
-
## MUST: Use Secrets for Sensitive Data
|
|
66
|
-
|
|
67
|
-
**MUST NOT commit secrets to repository:**
|
|
68
|
-
|
|
69
|
-
```yaml
|
|
70
|
-
# ✅ CORRECT - Use secrets
|
|
71
|
-
env:
|
|
72
|
-
SUPABASE_URL: ${{ secrets.SUPABASE_URL }}
|
|
73
|
-
VITE_SUPABASE_ANON_KEY: ${{ secrets.VITE_SUPABASE_ANON_KEY }}
|
|
74
|
-
|
|
75
|
-
# ❌ WRONG - Hardcoded secrets
|
|
76
|
-
env:
|
|
77
|
-
SUPABASE_URL: "https://hardcoded-url.supabase.co"
|
|
78
|
-
```
|
|
79
|
-
|
|
80
|
-
## SHOULD: Deploy to Staging First
|
|
81
|
-
|
|
82
|
-
**SHOULD deploy to staging before production:**
|
|
83
|
-
|
|
84
|
-
```yaml
|
|
85
|
-
# ✅ CORRECT - Staging first
|
|
86
|
-
deploy-staging:
|
|
87
|
-
if: github.ref == 'refs/heads/develop'
|
|
88
|
-
environment: staging
|
|
89
|
-
|
|
90
|
-
deploy-production:
|
|
91
|
-
needs: deploy-staging
|
|
92
|
-
if: github.ref == 'refs/heads/main'
|
|
93
|
-
environment: production
|
|
94
|
-
```
|
|
95
|
-
|
|
96
|
-
## Decision Tree: CI/CD Setup
|
|
97
|
-
|
|
98
|
-
**ALWAYS follow this decision tree:**
|
|
99
|
-
|
|
100
|
-
```
|
|
101
|
-
1. What type of check is this?
|
|
102
|
-
├─ Lint → MUST include
|
|
103
|
-
├─ Type Check → MUST include
|
|
104
|
-
├─ Tests → MUST include
|
|
105
|
-
├─ Build → MUST include
|
|
106
|
-
├─ Compliance → MUST include
|
|
107
|
-
├─ Format → SHOULD include
|
|
108
|
-
├─ Security → SHOULD include
|
|
109
|
-
└─ Coverage → SHOULD include
|
|
110
|
-
|
|
111
|
-
2. Is this sensitive data?
|
|
112
|
-
├─ YES → Use secrets (never commit)
|
|
113
|
-
└─ NO → Can be in config
|
|
114
|
-
|
|
115
|
-
3. What environment?
|
|
116
|
-
├─ Staging → Deploy on develop branch
|
|
117
|
-
└─ Production → Deploy on main branch only
|
|
118
|
-
|
|
119
|
-
4. Are migrations needed?
|
|
120
|
-
├─ YES → Run in staging first, test in CI
|
|
121
|
-
└─ NO → Continue
|
|
122
|
-
```
|
|
123
|
-
|
|
124
|
-
## CI/CD Checklist
|
|
125
|
-
|
|
126
|
-
Before committing CI/CD configuration, verify:
|
|
127
|
-
|
|
128
|
-
- [ ] Lint check configured
|
|
129
|
-
- [ ] Type check configured
|
|
130
|
-
- [ ] Tests run in CI
|
|
131
|
-
- [ ] Build succeeds in CI
|
|
132
|
-
- [ ] Security scan configured (recommended)
|
|
133
|
-
- [ ] Environment variables set as secrets
|
|
134
|
-
- [ ] Staging deployment configured
|
|
135
|
-
- [ ] Production deployment configured
|
|
136
|
-
- [ ] Migration strategy defined
|
|
137
|
-
- [ ] Required scripts in package.json
|
|
138
|
-
|
|
139
|
-
## Common CI/CD Mistakes
|
|
140
|
-
|
|
141
|
-
1. **Missing required checks** - Include all MUST checks
|
|
142
|
-
2. **Hardcoded secrets** - Always use secrets
|
|
143
|
-
3. **No staging environment** - Deploy to staging first
|
|
144
|
-
4. **No rollback plan** - Document rollback process
|
|
145
|
-
|
|
146
|
-
## Reference
|
|
147
|
-
|
|
148
|
-
- **Standard**: `packages/core/docs/standards/12-ci-cd-integration.md`
|
|
149
|
-
- **Testing**: See `04-testing-standards.mdc` for test configuration
|
|
150
|
-
- **Code Quality**: See `06-code-quality.mdc` for linting
|
|
@@ -1,15 +0,0 @@
|
|
|
1
|
-
export { ActionButtons, BulkOperationsDropdown, ColumnFactory, ColumnVisibilityDropdown, DataTable, DataTableCore, DataTableErrorBoundary, DataTableModals, DataTableToolbar, EditableRow, EmptyState, EnhancedPaginationControls, GroupHeader, GroupingDropdown, ImportModal, LoadingState, PaginationControls, UnifiedTableBody, announce, announceBulkOperation, announceFilterChange, announceLoadingState, announcePaginationChange, announceSearchResults, announceSelectionChange, announceSortChange, average, calculateAllDepths, calculateAllIndentation, calculateIndentation, calculateOptimalPageSize, cleanupLiveRegion, count, createHierarchicalStructure, defaultDataTableFeatures, exportToCSV, exportToCSVWithTableRows, generateCSVContent, getAriaSortValue, getCellRenderer, getColumnHeaderText, getHierarchicalSortConfig, getPageSizeOptions, getPaginationBinding, getRowDepth, getRowDescription, getRowIdSafe, getSortButtonLabel, groupHierarchicalData, hasValidRowId, initializeLiveRegion, isHierarchicalSortableColumn, max, min, normalizeDataTableFeatures, shouldShowColumnForRow, sortHierarchicalDataByStructure, sortHierarchicalDataWithSorting, sum, validateHierarchicalData, validatePaginationConfig } from './chunk-ZS5VO5JB.js';
|
|
2
|
-
import './chunk-7TYHROIV.js';
|
|
3
|
-
export { CircuitBreaker, DEFAULT_FALLBACK_CONFIG, DataChunkManager, DataTableError, DataTableErrorType, ErrorRecoveryManager, MemoryMonitor, SearchIndex, VisibilityTracker, chunkData, debounce, determinePaginationMode, getOptimalPageSizeOptions, safeExecute, throttle, useDataTablePerformance } from './chunk-S7DKJPLT.js';
|
|
4
|
-
import './chunk-3O3WHILE.js';
|
|
5
|
-
import './chunk-C7NSAPTL.js';
|
|
6
|
-
import './chunk-FTCRZOG2.js';
|
|
7
|
-
import './chunk-ZFYPMX46.js';
|
|
8
|
-
import './chunk-AHU7G2R5.js';
|
|
9
|
-
import './chunk-4SXLQIZO.js';
|
|
10
|
-
import './chunk-3QC3KRHK.js';
|
|
11
|
-
import './chunk-A55DK444.js';
|
|
12
|
-
import './chunk-SD6WQY43.js';
|
|
13
|
-
import './chunk-HF6O3O37.js';
|
|
14
|
-
import './chunk-TTRFSOKR.js';
|
|
15
|
-
import './chunk-3RG5ZIWI.js';
|
|
@@ -1,348 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* General compliance rules
|
|
3
|
-
* @package @jmruthers/pace-core
|
|
4
|
-
* @module ESLintRules/rules/compliance
|
|
5
|
-
*/
|
|
6
|
-
|
|
7
|
-
const path = require('path');
|
|
8
|
-
const { getPaceCoreComponents, getPaceCoreHooks, getPaceCoreUtils } = require('../utils/manifest-loader.cjs');
|
|
9
|
-
const { isPaceCoreSourceFile } = require('../utils/helpers.cjs');
|
|
10
|
-
|
|
11
|
-
module.exports = {
|
|
12
|
-
rules: {
|
|
13
|
-
/**
|
|
14
|
-
* Prefer pace-core components over native HTML elements or custom implementations
|
|
15
|
-
*/
|
|
16
|
-
'prefer-pace-core-components': {
|
|
17
|
-
meta: {
|
|
18
|
-
type: 'suggestion',
|
|
19
|
-
docs: {
|
|
20
|
-
description: 'Suggest using pace-core components instead of native HTML elements',
|
|
21
|
-
category: 'Best Practices',
|
|
22
|
-
recommended: true
|
|
23
|
-
},
|
|
24
|
-
hasSuggestions: true,
|
|
25
|
-
messages: {
|
|
26
|
-
preferButton: "Use 'Button' component from '@jmruthers/pace-core' instead of <button>",
|
|
27
|
-
preferInput: "Use 'Input' component from '@jmruthers/pace-core' instead of <input>",
|
|
28
|
-
preferTextarea: "Use 'Textarea' component from '@jmruthers/pace-core' instead of <textarea>",
|
|
29
|
-
preferLabel: "Use 'Label' component from '@jmruthers/pace-core' instead of <label>",
|
|
30
|
-
preferForm: "Use 'Form' component from '@jmruthers/pace-core' instead of custom form implementation"
|
|
31
|
-
}
|
|
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
|
-
const paceCoreComponents = getPaceCoreComponents();
|
|
42
|
-
|
|
43
|
-
return {
|
|
44
|
-
JSXOpeningElement(node) {
|
|
45
|
-
const elementName = node.name.name;
|
|
46
|
-
|
|
47
|
-
if (!elementName) return;
|
|
48
|
-
|
|
49
|
-
// Only flag lowercase native HTML elements, not capitalized components
|
|
50
|
-
// Native HTML: <button>, <input>, <label>, <textarea>
|
|
51
|
-
// Components: <Button>, <Input>, <Label>, <Textarea>
|
|
52
|
-
const isNativeHTMLElement = elementName === elementName.toLowerCase();
|
|
53
|
-
|
|
54
|
-
if (!isNativeHTMLElement) {
|
|
55
|
-
// This is a capitalized component, not a native HTML element
|
|
56
|
-
return;
|
|
57
|
-
}
|
|
58
|
-
|
|
59
|
-
// Check for native HTML elements that have pace-core alternatives
|
|
60
|
-
const nativeToPaceCore = {
|
|
61
|
-
'button': 'Button',
|
|
62
|
-
'input': 'Input',
|
|
63
|
-
'textarea': 'Textarea',
|
|
64
|
-
'label': 'Label'
|
|
65
|
-
};
|
|
66
|
-
|
|
67
|
-
if (nativeToPaceCore[elementName]) {
|
|
68
|
-
const paceCoreComponent = nativeToPaceCore[elementName];
|
|
69
|
-
if (paceCoreComponents.includes(paceCoreComponent)) {
|
|
70
|
-
context.report({
|
|
71
|
-
node,
|
|
72
|
-
messageId: `prefer${paceCoreComponent}`,
|
|
73
|
-
suggest: [{
|
|
74
|
-
desc: `Import and use ${paceCoreComponent} from pace-core`,
|
|
75
|
-
fix(fixer) {
|
|
76
|
-
// This is a complex fix, so we'll just report
|
|
77
|
-
return null;
|
|
78
|
-
}
|
|
79
|
-
}]
|
|
80
|
-
});
|
|
81
|
-
}
|
|
82
|
-
}
|
|
83
|
-
}
|
|
84
|
-
};
|
|
85
|
-
}
|
|
86
|
-
},
|
|
87
|
-
|
|
88
|
-
/**
|
|
89
|
-
* Detect custom hooks that duplicate pace-core functionality
|
|
90
|
-
*/
|
|
91
|
-
'prefer-pace-core-hooks': {
|
|
92
|
-
meta: {
|
|
93
|
-
type: 'suggestion',
|
|
94
|
-
docs: {
|
|
95
|
-
description: 'Suggest using pace-core hooks instead of custom implementations',
|
|
96
|
-
category: 'Best Practices',
|
|
97
|
-
recommended: true
|
|
98
|
-
},
|
|
99
|
-
messages: {
|
|
100
|
-
preferPaceCoreHook: "Consider using '{{hook}}' from '@jmruthers/pace-core' instead of custom hook '{{customHook}}'"
|
|
101
|
-
}
|
|
102
|
-
},
|
|
103
|
-
create(context) {
|
|
104
|
-
const filename = context.getFilename();
|
|
105
|
-
|
|
106
|
-
// Exclude pace-core source files - these rules are for consuming apps
|
|
107
|
-
if (isPaceCoreSourceFile(filename)) {
|
|
108
|
-
return {};
|
|
109
|
-
}
|
|
110
|
-
|
|
111
|
-
const paceCoreHooks = getPaceCoreHooks();
|
|
112
|
-
const hookPatterns = {
|
|
113
|
-
'useToast': ['useToast', 'useNotification', 'useSnackbar'],
|
|
114
|
-
'useDebounce': ['useDebounce', 'useDebounced'],
|
|
115
|
-
'useAuth': ['useAuth', 'useAuthentication', 'useUser'],
|
|
116
|
-
'useFile': ['useFile', 'useFileUpload', 'useFileReference'],
|
|
117
|
-
'useForm': ['useForm', 'useZodForm'],
|
|
118
|
-
'useTable': ['useTable', 'useDataTable']
|
|
119
|
-
};
|
|
120
|
-
|
|
121
|
-
return {
|
|
122
|
-
FunctionDeclaration(node) {
|
|
123
|
-
const functionName = node.id?.name;
|
|
124
|
-
if (!functionName || !functionName.startsWith('use')) return;
|
|
125
|
-
|
|
126
|
-
// Check if this looks like a hook that pace-core provides
|
|
127
|
-
for (const [paceCoreHook, patterns] of Object.entries(hookPatterns)) {
|
|
128
|
-
if (paceCoreHooks.includes(paceCoreHook)) {
|
|
129
|
-
for (const pattern of patterns) {
|
|
130
|
-
if (functionName.toLowerCase().includes(pattern.toLowerCase().replace('use', ''))) {
|
|
131
|
-
context.report({
|
|
132
|
-
node: node.id,
|
|
133
|
-
messageId: 'preferPaceCoreHook',
|
|
134
|
-
data: {
|
|
135
|
-
hook: paceCoreHook,
|
|
136
|
-
customHook: functionName
|
|
137
|
-
}
|
|
138
|
-
});
|
|
139
|
-
return;
|
|
140
|
-
}
|
|
141
|
-
}
|
|
142
|
-
}
|
|
143
|
-
}
|
|
144
|
-
}
|
|
145
|
-
};
|
|
146
|
-
}
|
|
147
|
-
},
|
|
148
|
-
|
|
149
|
-
/**
|
|
150
|
-
* Detect utility functions that duplicate pace-core functionality
|
|
151
|
-
*/
|
|
152
|
-
'prefer-pace-core-utils': {
|
|
153
|
-
meta: {
|
|
154
|
-
type: 'suggestion',
|
|
155
|
-
docs: {
|
|
156
|
-
description: 'Suggest using pace-core utilities instead of custom implementations',
|
|
157
|
-
category: 'Best Practices',
|
|
158
|
-
recommended: true
|
|
159
|
-
},
|
|
160
|
-
messages: {
|
|
161
|
-
preferPaceCoreUtil: "Consider using '{{util}}' from '@jmruthers/pace-core' instead of custom function '{{customUtil}}'"
|
|
162
|
-
}
|
|
163
|
-
},
|
|
164
|
-
create(context) {
|
|
165
|
-
const filename = context.getFilename();
|
|
166
|
-
|
|
167
|
-
// Exclude pace-core source files - these rules are for consuming apps
|
|
168
|
-
if (isPaceCoreSourceFile(filename)) {
|
|
169
|
-
return {};
|
|
170
|
-
}
|
|
171
|
-
|
|
172
|
-
const paceCoreUtils = getPaceCoreUtils();
|
|
173
|
-
const utilPatterns = {
|
|
174
|
-
'formatDate': ['formatDate', 'formatDateTime', 'dateFormat'],
|
|
175
|
-
'formatCurrency': ['formatCurrency', 'formatMoney', 'currencyFormat'],
|
|
176
|
-
'formatNumber': ['formatNumber', 'numberFormat'],
|
|
177
|
-
'cn': ['cn', 'classNames', 'clsx', 'mergeClasses'],
|
|
178
|
-
'validateUserInput': ['validateInput', 'validateUser', 'validateUserInput'],
|
|
179
|
-
'sanitizeUserInput': ['sanitize', 'sanitizeInput', 'sanitizeUser']
|
|
180
|
-
};
|
|
181
|
-
|
|
182
|
-
// Patterns that should NOT trigger validateUserInput warnings
|
|
183
|
-
// These are for API/config validation, not user input validation
|
|
184
|
-
const excludePatterns = [
|
|
185
|
-
'validateApi',
|
|
186
|
-
'validateRequest',
|
|
187
|
-
'validateConfig',
|
|
188
|
-
'validateKey',
|
|
189
|
-
'validateToken',
|
|
190
|
-
'validateAuth',
|
|
191
|
-
'validateRateLimit',
|
|
192
|
-
'validatePermission',
|
|
193
|
-
'validateAccess'
|
|
194
|
-
];
|
|
195
|
-
|
|
196
|
-
return {
|
|
197
|
-
FunctionDeclaration(node) {
|
|
198
|
-
const functionName = node.id?.name;
|
|
199
|
-
if (!functionName) return;
|
|
200
|
-
|
|
201
|
-
// Skip if function name matches exclude patterns (API/config validation, not user input)
|
|
202
|
-
const lowerName = functionName.toLowerCase();
|
|
203
|
-
if (excludePatterns.some(pattern => lowerName.includes(pattern.toLowerCase()))) {
|
|
204
|
-
return;
|
|
205
|
-
}
|
|
206
|
-
|
|
207
|
-
// Check if this looks like a util that pace-core provides
|
|
208
|
-
for (const [paceCoreUtil, patterns] of Object.entries(utilPatterns)) {
|
|
209
|
-
if (paceCoreUtils.includes(paceCoreUtil)) {
|
|
210
|
-
for (const pattern of patterns) {
|
|
211
|
-
// Only match if the pattern is a significant part of the function name
|
|
212
|
-
// Don't match generic "validate" - it's too broad
|
|
213
|
-
if (paceCoreUtil === 'validateUserInput' && pattern === 'validate') {
|
|
214
|
-
// Skip generic "validate" - too many false positives
|
|
215
|
-
continue;
|
|
216
|
-
}
|
|
217
|
-
|
|
218
|
-
if (functionName.toLowerCase().includes(pattern.toLowerCase())) {
|
|
219
|
-
context.report({
|
|
220
|
-
node: node.id,
|
|
221
|
-
messageId: 'preferPaceCoreUtil',
|
|
222
|
-
data: {
|
|
223
|
-
util: paceCoreUtil,
|
|
224
|
-
customUtil: functionName
|
|
225
|
-
}
|
|
226
|
-
});
|
|
227
|
-
return;
|
|
228
|
-
}
|
|
229
|
-
}
|
|
230
|
-
}
|
|
231
|
-
}
|
|
232
|
-
}
|
|
233
|
-
};
|
|
234
|
-
}
|
|
235
|
-
},
|
|
236
|
-
|
|
237
|
-
/**
|
|
238
|
-
* Detect component files with names matching pace-core components
|
|
239
|
-
*/
|
|
240
|
-
'no-local-component-duplication': {
|
|
241
|
-
meta: {
|
|
242
|
-
type: 'problem',
|
|
243
|
-
docs: {
|
|
244
|
-
description: 'Disallow local components with names matching pace-core components',
|
|
245
|
-
category: 'Best Practices',
|
|
246
|
-
recommended: true
|
|
247
|
-
},
|
|
248
|
-
messages: {
|
|
249
|
-
duplicateComponent: "Component '{{componentName}}' conflicts with pace-core component. Use '@jmruthers/pace-core' instead of creating a local version."
|
|
250
|
-
}
|
|
251
|
-
},
|
|
252
|
-
create(context) {
|
|
253
|
-
const filename = context.getFilename();
|
|
254
|
-
|
|
255
|
-
// Exclude pace-core source files - these rules are for consuming apps
|
|
256
|
-
if (isPaceCoreSourceFile(filename)) {
|
|
257
|
-
return {};
|
|
258
|
-
}
|
|
259
|
-
|
|
260
|
-
const paceCoreComponents = getPaceCoreComponents();
|
|
261
|
-
|
|
262
|
-
// Only check component files (components/, src/components/, etc.)
|
|
263
|
-
if (!filename.match(/(components|Components)\//)) {
|
|
264
|
-
return {};
|
|
265
|
-
}
|
|
266
|
-
|
|
267
|
-
// Extract component name from filename
|
|
268
|
-
const basename = path.basename(filename, path.extname(filename));
|
|
269
|
-
const componentName = basename.replace(/\.(test|spec)$/, '');
|
|
270
|
-
|
|
271
|
-
return {
|
|
272
|
-
Program(node) {
|
|
273
|
-
// Check if this file exports a component with a name matching pace-core
|
|
274
|
-
if (paceCoreComponents.includes(componentName)) {
|
|
275
|
-
// Check if file exports this component
|
|
276
|
-
const hasExport = node.body.some(stmt => {
|
|
277
|
-
if (stmt.type === 'ExportNamedDeclaration') {
|
|
278
|
-
return stmt.declaration?.id?.name === componentName ||
|
|
279
|
-
stmt.specifiers?.some(spec => spec.exported.name === componentName);
|
|
280
|
-
}
|
|
281
|
-
if (stmt.type === 'ExportDefaultDeclaration') {
|
|
282
|
-
return stmt.declaration?.id?.name === componentName ||
|
|
283
|
-
stmt.declaration?.name === componentName;
|
|
284
|
-
}
|
|
285
|
-
return false;
|
|
286
|
-
});
|
|
287
|
-
|
|
288
|
-
if (hasExport) {
|
|
289
|
-
context.report({
|
|
290
|
-
node,
|
|
291
|
-
messageId: 'duplicateComponent',
|
|
292
|
-
data: {
|
|
293
|
-
componentName
|
|
294
|
-
}
|
|
295
|
-
});
|
|
296
|
-
}
|
|
297
|
-
}
|
|
298
|
-
}
|
|
299
|
-
};
|
|
300
|
-
}
|
|
301
|
-
},
|
|
302
|
-
|
|
303
|
-
/**
|
|
304
|
-
* Disallow inline styles
|
|
305
|
-
*/
|
|
306
|
-
'no-inline-styles': {
|
|
307
|
-
meta: {
|
|
308
|
-
type: 'problem',
|
|
309
|
-
docs: {
|
|
310
|
-
description: 'Disallow inline styles. Use pace-core components or Tailwind classes instead.',
|
|
311
|
-
category: 'Best Practices',
|
|
312
|
-
recommended: true
|
|
313
|
-
},
|
|
314
|
-
messages: {
|
|
315
|
-
inlineStyle: 'Inline style detected. Use pace-core components or Tailwind classes instead.'
|
|
316
|
-
},
|
|
317
|
-
hasSuggestions: true
|
|
318
|
-
},
|
|
319
|
-
create(context) {
|
|
320
|
-
const filename = context.getFilename();
|
|
321
|
-
|
|
322
|
-
// Exclude pace-core source files - these rules are for consuming apps
|
|
323
|
-
if (isPaceCoreSourceFile(filename)) {
|
|
324
|
-
return {};
|
|
325
|
-
}
|
|
326
|
-
|
|
327
|
-
return {
|
|
328
|
-
JSXAttribute(node) {
|
|
329
|
-
if (node.name && node.name.name === 'style') {
|
|
330
|
-
context.report({
|
|
331
|
-
node,
|
|
332
|
-
messageId: 'inlineStyle',
|
|
333
|
-
suggest: [{
|
|
334
|
-
desc: 'Remove inline style and use pace-core component styling or Tailwind utility classes',
|
|
335
|
-
fix(fixer) {
|
|
336
|
-
// Remove the style attribute
|
|
337
|
-
return fixer.remove(node);
|
|
338
|
-
}
|
|
339
|
-
}]
|
|
340
|
-
});
|
|
341
|
-
}
|
|
342
|
-
}
|
|
343
|
-
};
|
|
344
|
-
}
|
|
345
|
-
}
|
|
346
|
-
}
|
|
347
|
-
};
|
|
348
|
-
|