@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,12 +1,22 @@
|
|
|
1
1
|
/**
|
|
2
|
-
*
|
|
2
|
+
* pace-core Compliance Rules (Standard 1)
|
|
3
3
|
* @package @jmruthers/pace-core
|
|
4
|
-
* @module ESLintRules/rules/compliance
|
|
4
|
+
* @module ESLintRules/rules/pace-core-compliance
|
|
5
|
+
*
|
|
6
|
+
* Enforces pace-core usage patterns from Standard 1:
|
|
7
|
+
* - Use pace-core components instead of native HTML or custom implementations
|
|
8
|
+
* - Use pace-core hooks instead of custom hooks
|
|
9
|
+
* - Use pace-core utilities instead of custom utilities
|
|
10
|
+
* - Block restricted imports (libraries wrapped by pace-core)
|
|
11
|
+
* - Prefer pace-core Form component
|
|
12
|
+
* - Prevent component duplication
|
|
13
|
+
*
|
|
14
|
+
* Reference: packages/core/docs/standards/1-pace-core-compliance-standards.md
|
|
5
15
|
*/
|
|
6
16
|
|
|
7
17
|
const path = require('path');
|
|
8
|
-
const { getPaceCoreComponents, getPaceCoreHooks, getPaceCoreUtils } = require('../utils/manifest-loader.cjs');
|
|
9
|
-
const { isPaceCoreSourceFile } = require('../utils/helpers.cjs');
|
|
18
|
+
const { getPaceCoreComponents, getPaceCoreHooks, getPaceCoreUtils, getRestrictedImports } = require('../utils/manifest-loader.cjs');
|
|
19
|
+
const { getPaceCoreAlternative, isPaceCoreSourceFile } = require('../utils/helpers.cjs');
|
|
10
20
|
|
|
11
21
|
module.exports = {
|
|
12
22
|
rules: {
|
|
@@ -19,7 +29,8 @@ module.exports = {
|
|
|
19
29
|
docs: {
|
|
20
30
|
description: 'Suggest using pace-core components instead of native HTML elements',
|
|
21
31
|
category: 'Best Practices',
|
|
22
|
-
recommended: true
|
|
32
|
+
recommended: true,
|
|
33
|
+
url: 'https://github.com/jmruthers/pace-core/blob/main/packages/core/docs/standards/1-pace-core-compliance-standards.md'
|
|
23
34
|
},
|
|
24
35
|
hasSuggestions: true,
|
|
25
36
|
messages: {
|
|
@@ -94,7 +105,8 @@ module.exports = {
|
|
|
94
105
|
docs: {
|
|
95
106
|
description: 'Suggest using pace-core hooks instead of custom implementations',
|
|
96
107
|
category: 'Best Practices',
|
|
97
|
-
recommended: true
|
|
108
|
+
recommended: true,
|
|
109
|
+
url: 'https://github.com/jmruthers/pace-core/blob/main/packages/core/docs/standards/1-pace-core-compliance-standards.md'
|
|
98
110
|
},
|
|
99
111
|
messages: {
|
|
100
112
|
preferPaceCoreHook: "Consider using '{{hook}}' from '@jmruthers/pace-core' instead of custom hook '{{customHook}}'"
|
|
@@ -155,7 +167,8 @@ module.exports = {
|
|
|
155
167
|
docs: {
|
|
156
168
|
description: 'Suggest using pace-core utilities instead of custom implementations',
|
|
157
169
|
category: 'Best Practices',
|
|
158
|
-
recommended: true
|
|
170
|
+
recommended: true,
|
|
171
|
+
url: 'https://github.com/jmruthers/pace-core/blob/main/packages/core/docs/standards/1-pace-core-compliance-standards.md'
|
|
159
172
|
},
|
|
160
173
|
messages: {
|
|
161
174
|
preferPaceCoreUtil: "Consider using '{{util}}' from '@jmruthers/pace-core' instead of custom function '{{customUtil}}'"
|
|
@@ -243,7 +256,8 @@ module.exports = {
|
|
|
243
256
|
docs: {
|
|
244
257
|
description: 'Disallow local components with names matching pace-core components',
|
|
245
258
|
category: 'Best Practices',
|
|
246
|
-
recommended: true
|
|
259
|
+
recommended: true,
|
|
260
|
+
url: 'https://github.com/jmruthers/pace-core/blob/main/packages/core/docs/standards/1-pace-core-compliance-standards.md'
|
|
247
261
|
},
|
|
248
262
|
messages: {
|
|
249
263
|
duplicateComponent: "Component '{{componentName}}' conflicts with pace-core component. Use '@jmruthers/pace-core' instead of creating a local version."
|
|
@@ -301,20 +315,23 @@ module.exports = {
|
|
|
301
315
|
},
|
|
302
316
|
|
|
303
317
|
/**
|
|
304
|
-
*
|
|
318
|
+
* Block direct imports of libraries wrapped by pace-core
|
|
305
319
|
*/
|
|
306
|
-
'no-
|
|
320
|
+
'no-restricted-imports': {
|
|
307
321
|
meta: {
|
|
308
322
|
type: 'problem',
|
|
309
323
|
docs: {
|
|
310
|
-
description: 'Disallow
|
|
324
|
+
description: 'Disallow direct imports of libraries that pace-core wraps',
|
|
311
325
|
category: 'Best Practices',
|
|
312
|
-
recommended: true
|
|
326
|
+
recommended: true,
|
|
327
|
+
url: 'https://github.com/jmruthers/pace-core/blob/main/packages/core/docs/standards/1-pace-core-compliance-standards.md'
|
|
313
328
|
},
|
|
329
|
+
fixable: 'code',
|
|
330
|
+
hasSuggestions: true,
|
|
314
331
|
messages: {
|
|
315
|
-
|
|
316
|
-
|
|
317
|
-
|
|
332
|
+
restrictedImport: '{{message}} Import from {{alternative}} instead.',
|
|
333
|
+
restrictedImportWithReason: '{{message}} {{reason}}'
|
|
334
|
+
}
|
|
318
335
|
},
|
|
319
336
|
create(context) {
|
|
320
337
|
const filename = context.getFilename();
|
|
@@ -324,20 +341,165 @@ module.exports = {
|
|
|
324
341
|
return {};
|
|
325
342
|
}
|
|
326
343
|
|
|
344
|
+
const restrictedImports = getRestrictedImports();
|
|
345
|
+
const restrictedModules = restrictedImports.map(imp => imp.module);
|
|
346
|
+
|
|
347
|
+
// Also catch @radix-ui/* patterns
|
|
348
|
+
const radixPattern = /^@radix-ui\//;
|
|
349
|
+
|
|
327
350
|
return {
|
|
328
|
-
|
|
329
|
-
|
|
351
|
+
ImportDeclaration(node) {
|
|
352
|
+
const importSource = node.source.value;
|
|
353
|
+
|
|
354
|
+
// Check exact matches
|
|
355
|
+
const restricted = restrictedImports.find(imp => imp.module === importSource);
|
|
356
|
+
if (restricted) {
|
|
330
357
|
context.report({
|
|
331
|
-
node,
|
|
332
|
-
messageId: '
|
|
358
|
+
node: node.source,
|
|
359
|
+
messageId: 'restrictedImportWithReason',
|
|
360
|
+
data: {
|
|
361
|
+
message: `Direct import of '${importSource}' is not allowed.`,
|
|
362
|
+
reason: restricted.reason
|
|
363
|
+
},
|
|
333
364
|
suggest: [{
|
|
334
|
-
desc:
|
|
365
|
+
desc: `Use pace-core alternative: ${restricted.reason}`,
|
|
335
366
|
fix(fixer) {
|
|
336
|
-
//
|
|
337
|
-
|
|
367
|
+
// Suggest importing from pace-core instead
|
|
368
|
+
const paceCoreAlternative = getPaceCoreAlternative(importSource);
|
|
369
|
+
if (paceCoreAlternative) {
|
|
370
|
+
return fixer.replaceText(
|
|
371
|
+
node.source,
|
|
372
|
+
`'@jmruthers/pace-core${paceCoreAlternative}'`
|
|
373
|
+
);
|
|
374
|
+
}
|
|
375
|
+
return null;
|
|
338
376
|
}
|
|
339
377
|
}]
|
|
340
378
|
});
|
|
379
|
+
return;
|
|
380
|
+
}
|
|
381
|
+
|
|
382
|
+
// Check @radix-ui/* pattern
|
|
383
|
+
if (radixPattern.test(importSource) && !restrictedModules.includes(importSource)) {
|
|
384
|
+
context.report({
|
|
385
|
+
node: node.source,
|
|
386
|
+
messageId: 'restrictedImport',
|
|
387
|
+
data: {
|
|
388
|
+
message: `Direct import of '${importSource}' is not allowed.`,
|
|
389
|
+
alternative: '@jmruthers/pace-core'
|
|
390
|
+
},
|
|
391
|
+
suggest: [{
|
|
392
|
+
desc: 'Use pace-core component instead',
|
|
393
|
+
fix(fixer) {
|
|
394
|
+
return fixer.replaceText(
|
|
395
|
+
node.source,
|
|
396
|
+
"'@jmruthers/pace-core'"
|
|
397
|
+
);
|
|
398
|
+
}
|
|
399
|
+
}]
|
|
400
|
+
});
|
|
401
|
+
}
|
|
402
|
+
}
|
|
403
|
+
};
|
|
404
|
+
}
|
|
405
|
+
},
|
|
406
|
+
|
|
407
|
+
/**
|
|
408
|
+
* Prefer pace-core Form component over plain form tags and direct react-hook-form usage
|
|
409
|
+
*/
|
|
410
|
+
'prefer-pace-core-form': {
|
|
411
|
+
meta: {
|
|
412
|
+
type: 'problem',
|
|
413
|
+
docs: {
|
|
414
|
+
description: 'Disallow plain <form> tags and direct react-hook-form imports. Use pace-core Form component instead.',
|
|
415
|
+
category: 'Best Practices',
|
|
416
|
+
recommended: true,
|
|
417
|
+
url: 'https://github.com/jmruthers/pace-core/blob/main/packages/core/docs/standards/1-pace-core-compliance-standards.md'
|
|
418
|
+
},
|
|
419
|
+
messages: {
|
|
420
|
+
plainFormTag: "Plain <form> tag detected. Use pace-core Form component instead.",
|
|
421
|
+
reactHookFormImport: "Direct import from 'react-hook-form' detected: {{imports}}. Use pace-core Form component instead. useFormContext is allowed when Form is imported from pace-core."
|
|
422
|
+
},
|
|
423
|
+
hasSuggestions: true
|
|
424
|
+
},
|
|
425
|
+
create(context) {
|
|
426
|
+
const filename = context.getFilename();
|
|
427
|
+
|
|
428
|
+
// Exclude pace-core source files - these rules are for consuming apps
|
|
429
|
+
if (isPaceCoreSourceFile(filename)) {
|
|
430
|
+
return {};
|
|
431
|
+
}
|
|
432
|
+
|
|
433
|
+
let hasPaceCoreForm = false;
|
|
434
|
+
const problematicImports = ['useForm', 'FormProvider', 'Controller', 'useWatch', 'useFieldArray', 'useController'];
|
|
435
|
+
|
|
436
|
+
return {
|
|
437
|
+
ImportDeclaration(node) {
|
|
438
|
+
const importSource = node.source.value;
|
|
439
|
+
|
|
440
|
+
// Check if Form is imported from pace-core
|
|
441
|
+
if (importSource === '@jmruthers/pace-core' ||
|
|
442
|
+
importSource === '@jmruthers/pace-core/components') {
|
|
443
|
+
const hasForm = node.specifiers.some(spec => {
|
|
444
|
+
if (spec.type === 'ImportSpecifier') {
|
|
445
|
+
return spec.imported.name === 'Form';
|
|
446
|
+
}
|
|
447
|
+
return false;
|
|
448
|
+
});
|
|
449
|
+
if (hasForm) {
|
|
450
|
+
hasPaceCoreForm = true;
|
|
451
|
+
}
|
|
452
|
+
}
|
|
453
|
+
|
|
454
|
+
// Check for react-hook-form imports
|
|
455
|
+
if (importSource === 'react-hook-form') {
|
|
456
|
+
const importedItems = node.specifiers
|
|
457
|
+
.filter(spec => spec.type === 'ImportSpecifier')
|
|
458
|
+
.map(spec => spec.imported.name);
|
|
459
|
+
|
|
460
|
+
const foundProblematic = importedItems.filter(item => problematicImports.includes(item));
|
|
461
|
+
|
|
462
|
+
// Allow useFormContext when Form is imported from pace-core
|
|
463
|
+
const isAcceptable = hasPaceCoreForm &&
|
|
464
|
+
foundProblematic.length === 1 &&
|
|
465
|
+
foundProblematic[0] === 'useFormContext';
|
|
466
|
+
|
|
467
|
+
if (foundProblematic.length > 0 && !isAcceptable) {
|
|
468
|
+
context.report({
|
|
469
|
+
node: node.source,
|
|
470
|
+
messageId: 'reactHookFormImport',
|
|
471
|
+
data: {
|
|
472
|
+
imports: foundProblematic.join(', ')
|
|
473
|
+
},
|
|
474
|
+
suggest: [{
|
|
475
|
+
desc: 'Use pace-core Form component instead',
|
|
476
|
+
fix(fixer) {
|
|
477
|
+
return fixer.remove(node);
|
|
478
|
+
}
|
|
479
|
+
}]
|
|
480
|
+
});
|
|
481
|
+
}
|
|
482
|
+
}
|
|
483
|
+
},
|
|
484
|
+
|
|
485
|
+
JSXOpeningElement(node) {
|
|
486
|
+
// Check for plain <form> tags (lowercase, not Form component)
|
|
487
|
+
if (node.name.type === 'JSXIdentifier') {
|
|
488
|
+
const elementName = node.name.name;
|
|
489
|
+
// Check if it's lowercase 'form' (not 'Form' component)
|
|
490
|
+
if (elementName === 'form') {
|
|
491
|
+
context.report({
|
|
492
|
+
node,
|
|
493
|
+
messageId: 'plainFormTag',
|
|
494
|
+
suggest: [{
|
|
495
|
+
desc: 'Replace with pace-core Form component',
|
|
496
|
+
fix(fixer) {
|
|
497
|
+
// This is complex to auto-fix, so we'll just report
|
|
498
|
+
return null;
|
|
499
|
+
}
|
|
500
|
+
}]
|
|
501
|
+
});
|
|
502
|
+
}
|
|
341
503
|
}
|
|
342
504
|
}
|
|
343
505
|
};
|
|
@@ -345,4 +507,3 @@ module.exports = {
|
|
|
345
507
|
}
|
|
346
508
|
}
|
|
347
509
|
};
|
|
348
|
-
|
|
@@ -0,0 +1,290 @@
|
|
|
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
|
+
// Check for hooks (functions that use React hooks)
|
|
51
|
+
const sourceCode = context.getSourceCode();
|
|
52
|
+
const functionText = sourceCode.getText(node.body);
|
|
53
|
+
const usesReactHooks = /use(State|Effect|Callback|Memo|Ref|Context|Reducer|LayoutEffect|ImperativeHandle|DebugValue)/.test(functionText);
|
|
54
|
+
|
|
55
|
+
// Check if function is a hook (starts with 'use' or uses React hooks)
|
|
56
|
+
if (usesReactHooks || functionName.startsWith('use')) {
|
|
57
|
+
if (!functionName.startsWith('use')) {
|
|
58
|
+
context.report({
|
|
59
|
+
node: node.id,
|
|
60
|
+
messageId: 'hookNaming',
|
|
61
|
+
data: { name: functionName },
|
|
62
|
+
suggest: [{
|
|
63
|
+
desc: `Rename to use${functionName.charAt(0).toUpperCase() + functionName.slice(1)}`,
|
|
64
|
+
fix(fixer) {
|
|
65
|
+
return null; // Complex rename
|
|
66
|
+
}
|
|
67
|
+
}]
|
|
68
|
+
});
|
|
69
|
+
}
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
// Check for providers (components that return JSX and have Provider in name or return Provider-like structure)
|
|
73
|
+
const returnsJSX = functionText.includes('return') && (functionText.includes('<') || functionText.includes('createElement'));
|
|
74
|
+
const hasProviderPattern = functionName.includes('Provider') ||
|
|
75
|
+
functionText.includes('Provider') ||
|
|
76
|
+
functionText.includes('Context.Provider');
|
|
77
|
+
|
|
78
|
+
if (returnsJSX && hasProviderPattern && !functionName.endsWith('Provider')) {
|
|
79
|
+
context.report({
|
|
80
|
+
node: node.id,
|
|
81
|
+
messageId: 'providerNaming',
|
|
82
|
+
data: { name: functionName },
|
|
83
|
+
suggest: [{
|
|
84
|
+
desc: `Rename to ${functionName}Provider`,
|
|
85
|
+
fix(fixer) {
|
|
86
|
+
return null; // Complex rename
|
|
87
|
+
}
|
|
88
|
+
}]
|
|
89
|
+
});
|
|
90
|
+
}
|
|
91
|
+
},
|
|
92
|
+
|
|
93
|
+
VariableDeclarator(node) {
|
|
94
|
+
if (!node.id || node.id.type !== 'Identifier') return;
|
|
95
|
+
if (!node.init) return;
|
|
96
|
+
|
|
97
|
+
const varName = node.id.name;
|
|
98
|
+
if (!varName) return;
|
|
99
|
+
|
|
100
|
+
// Check for hook variables (arrow functions that use React hooks)
|
|
101
|
+
if (node.init.type === 'ArrowFunctionExpression' || node.init.type === 'FunctionExpression') {
|
|
102
|
+
const sourceCode = context.getSourceCode();
|
|
103
|
+
const functionText = sourceCode.getText(node.init);
|
|
104
|
+
const usesReactHooks = /use(State|Effect|Callback|Memo|Ref|Context|Reducer|LayoutEffect|ImperativeHandle|DebugValue)/.test(functionText);
|
|
105
|
+
|
|
106
|
+
if (usesReactHooks && !varName.startsWith('use')) {
|
|
107
|
+
context.report({
|
|
108
|
+
node: node.id,
|
|
109
|
+
messageId: 'hookNaming',
|
|
110
|
+
data: { name: varName },
|
|
111
|
+
suggest: [{
|
|
112
|
+
desc: `Rename to use${varName.charAt(0).toUpperCase() + varName.slice(1)}`,
|
|
113
|
+
fix(fixer) {
|
|
114
|
+
return null; // Complex rename
|
|
115
|
+
}
|
|
116
|
+
}]
|
|
117
|
+
});
|
|
118
|
+
}
|
|
119
|
+
}
|
|
120
|
+
}
|
|
121
|
+
};
|
|
122
|
+
}
|
|
123
|
+
},
|
|
124
|
+
|
|
125
|
+
/**
|
|
126
|
+
* Enforce component naming: PascalCase
|
|
127
|
+
*/
|
|
128
|
+
'component-naming': {
|
|
129
|
+
meta: {
|
|
130
|
+
type: 'suggestion',
|
|
131
|
+
docs: {
|
|
132
|
+
description: 'Enforce component naming: components must use PascalCase',
|
|
133
|
+
category: 'Best Practices',
|
|
134
|
+
recommended: true,
|
|
135
|
+
url: 'https://github.com/jmruthers/pace-core/blob/main/packages/core/docs/standards/4-code-quality-standards.md'
|
|
136
|
+
},
|
|
137
|
+
messages: {
|
|
138
|
+
componentNaming: "Component '{{name}}' must use PascalCase (e.g., EventCard, UserProfile)"
|
|
139
|
+
},
|
|
140
|
+
hasSuggestions: true
|
|
141
|
+
},
|
|
142
|
+
create(context) {
|
|
143
|
+
const filename = context.getFilename();
|
|
144
|
+
|
|
145
|
+
// Exclude pace-core source files - these rules are for consuming apps
|
|
146
|
+
if (isPaceCoreSourceFile(filename)) {
|
|
147
|
+
return {};
|
|
148
|
+
}
|
|
149
|
+
|
|
150
|
+
const isComponentFile = filename.match(/(components|Components)\//);
|
|
151
|
+
if (!isComponentFile) {
|
|
152
|
+
return {};
|
|
153
|
+
}
|
|
154
|
+
|
|
155
|
+
return {
|
|
156
|
+
FunctionDeclaration(node) {
|
|
157
|
+
if (!node.id) return;
|
|
158
|
+
|
|
159
|
+
const functionName = node.id.name;
|
|
160
|
+
if (!functionName) return;
|
|
161
|
+
|
|
162
|
+
// Check if it's a component (returns JSX)
|
|
163
|
+
const sourceCode = context.getSourceCode();
|
|
164
|
+
const functionText = sourceCode.getText(node.body);
|
|
165
|
+
const returnsJSX = functionText.includes('return') && (functionText.includes('<') || functionText.includes('createElement'));
|
|
166
|
+
|
|
167
|
+
if (returnsJSX) {
|
|
168
|
+
// Check if it's PascalCase
|
|
169
|
+
const isPascalCase = /^[A-Z][a-zA-Z0-9]*$/.test(functionName);
|
|
170
|
+
if (!isPascalCase) {
|
|
171
|
+
context.report({
|
|
172
|
+
node: node.id,
|
|
173
|
+
messageId: 'componentNaming',
|
|
174
|
+
data: { name: functionName },
|
|
175
|
+
suggest: [{
|
|
176
|
+
desc: `Rename to ${functionName.charAt(0).toUpperCase() + functionName.slice(1).replace(/[^a-zA-Z0-9]/g, '')}`,
|
|
177
|
+
fix(fixer) {
|
|
178
|
+
return null; // Complex rename
|
|
179
|
+
}
|
|
180
|
+
}]
|
|
181
|
+
});
|
|
182
|
+
}
|
|
183
|
+
}
|
|
184
|
+
},
|
|
185
|
+
|
|
186
|
+
VariableDeclarator(node) {
|
|
187
|
+
if (!node.id || node.id.type !== 'Identifier') return;
|
|
188
|
+
if (!node.init) return;
|
|
189
|
+
|
|
190
|
+
const varName = node.id.name;
|
|
191
|
+
if (!varName) return;
|
|
192
|
+
|
|
193
|
+
// Check for component variables (arrow functions that return JSX)
|
|
194
|
+
if (node.init.type === 'ArrowFunctionExpression' || node.init.type === 'FunctionExpression') {
|
|
195
|
+
const sourceCode = context.getSourceCode();
|
|
196
|
+
const functionText = sourceCode.getText(node.init);
|
|
197
|
+
const returnsJSX = functionText.includes('return') && (functionText.includes('<') || functionText.includes('createElement'));
|
|
198
|
+
|
|
199
|
+
if (returnsJSX) {
|
|
200
|
+
const isPascalCase = /^[A-Z][a-zA-Z0-9]*$/.test(varName);
|
|
201
|
+
if (!isPascalCase) {
|
|
202
|
+
context.report({
|
|
203
|
+
node: node.id,
|
|
204
|
+
messageId: 'componentNaming',
|
|
205
|
+
data: { name: varName },
|
|
206
|
+
suggest: [{
|
|
207
|
+
desc: `Rename to ${varName.charAt(0).toUpperCase() + varName.slice(1).replace(/[^a-zA-Z0-9]/g, '')}`,
|
|
208
|
+
fix(fixer) {
|
|
209
|
+
return null; // Complex rename
|
|
210
|
+
}
|
|
211
|
+
}]
|
|
212
|
+
});
|
|
213
|
+
}
|
|
214
|
+
}
|
|
215
|
+
}
|
|
216
|
+
}
|
|
217
|
+
};
|
|
218
|
+
}
|
|
219
|
+
},
|
|
220
|
+
|
|
221
|
+
/**
|
|
222
|
+
* Enforce type/interface naming: PascalCase
|
|
223
|
+
*/
|
|
224
|
+
'type-naming': {
|
|
225
|
+
meta: {
|
|
226
|
+
type: 'suggestion',
|
|
227
|
+
docs: {
|
|
228
|
+
description: 'Enforce type/interface naming: types and interfaces must use PascalCase',
|
|
229
|
+
category: 'Best Practices',
|
|
230
|
+
recommended: true,
|
|
231
|
+
url: 'https://github.com/jmruthers/pace-core/blob/main/packages/core/docs/standards/4-code-quality-standards.md'
|
|
232
|
+
},
|
|
233
|
+
messages: {
|
|
234
|
+
typeNaming: "Type/interface '{{name}}' must use PascalCase (e.g., EventStatus, UserProfile)"
|
|
235
|
+
},
|
|
236
|
+
hasSuggestions: true
|
|
237
|
+
},
|
|
238
|
+
create(context) {
|
|
239
|
+
const filename = context.getFilename();
|
|
240
|
+
|
|
241
|
+
// Exclude pace-core source files - these rules are for consuming apps
|
|
242
|
+
if (isPaceCoreSourceFile(filename)) {
|
|
243
|
+
return {};
|
|
244
|
+
}
|
|
245
|
+
|
|
246
|
+
return {
|
|
247
|
+
TSInterfaceDeclaration(node) {
|
|
248
|
+
const interfaceName = node.id.name;
|
|
249
|
+
if (!interfaceName) return;
|
|
250
|
+
|
|
251
|
+
const isPascalCase = /^[A-Z][a-zA-Z0-9]*$/.test(interfaceName);
|
|
252
|
+
if (!isPascalCase) {
|
|
253
|
+
context.report({
|
|
254
|
+
node: node.id,
|
|
255
|
+
messageId: 'typeNaming',
|
|
256
|
+
data: { name: interfaceName },
|
|
257
|
+
suggest: [{
|
|
258
|
+
desc: `Rename to ${interfaceName.charAt(0).toUpperCase() + interfaceName.slice(1).replace(/[^a-zA-Z0-9]/g, '')}`,
|
|
259
|
+
fix(fixer) {
|
|
260
|
+
return null; // Complex rename
|
|
261
|
+
}
|
|
262
|
+
}]
|
|
263
|
+
});
|
|
264
|
+
}
|
|
265
|
+
},
|
|
266
|
+
|
|
267
|
+
TSTypeAliasDeclaration(node) {
|
|
268
|
+
const typeName = node.id.name;
|
|
269
|
+
if (!typeName) return;
|
|
270
|
+
|
|
271
|
+
const isPascalCase = /^[A-Z][a-zA-Z0-9]*$/.test(typeName);
|
|
272
|
+
if (!isPascalCase) {
|
|
273
|
+
context.report({
|
|
274
|
+
node: node.id,
|
|
275
|
+
messageId: 'typeNaming',
|
|
276
|
+
data: { name: typeName },
|
|
277
|
+
suggest: [{
|
|
278
|
+
desc: `Rename to ${typeName.charAt(0).toUpperCase() + typeName.slice(1).replace(/[^a-zA-Z0-9]/g, '')}`,
|
|
279
|
+
fix(fixer) {
|
|
280
|
+
return null; // Complex rename
|
|
281
|
+
}
|
|
282
|
+
}]
|
|
283
|
+
});
|
|
284
|
+
}
|
|
285
|
+
}
|
|
286
|
+
};
|
|
287
|
+
}
|
|
288
|
+
}
|
|
289
|
+
}
|
|
290
|
+
};
|
|
@@ -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
|
+
};
|