Skip to main content

Linting Guidelines

Introduction

This repository uses a comprehensive ESLint configuration with custom rules to maintain code quality, enforce best practices, and catch potential issues early in development. Our modular ESLint setup includes both standard rules and custom rules tailored to our project's specific needs.

The ESLint configuration is located in eslint.config.js and uses modular configs from scripts/eslint/config/.

Custom ESLint Rules

prefer-crud-modal-template

This rule encourages the use of CRUDModalTemplate over BaseModal when building modals that contain CRUD (Create, Read, Update, Delete) functionality.

Rule Location: scripts/eslint/rules/prefer-crud-modal-template.ts

When This Rule Triggers

The rule flags BaseModal usage in these scenarios:

  1. CRUD Handler Props: When the modal has props that indicate CRUD operations:

    • onSubmit
    • onConfirm
    • onPrimary
    • onSave
  2. Form Elements: When the modal contains <form> or <Form> elements in its children.

Examples

Incorrect - Using BaseModal with CRUD props:

import { BaseModal } from 'shared-components/BaseModal';

function UserEditModal() {
return (
<BaseModal
isOpen={true}
onSubmit={handleSubmit} // CRUD handler prop
title="Edit User"
>
<form>
<input name="username" />
<button type="submit">Save</button>
</form>
</BaseModal>
);
}

Incorrect - Using BaseModal with form elements:

import { BaseModal } from 'shared-components/BaseModal';

function CreatePostModal() {
return (
<BaseModal isOpen={true} title="Create Post">
<Form onSubmit={handleSubmit}> {/* Form element detected */}
<input name="title" />
<textarea name="content" />
</Form>
</BaseModal>
);
}

Correct - Using CRUDModalTemplate:

import { CRUDModalTemplate } from 'shared-components/CRUDModalTemplate/CRUDModalTemplate';

function UserEditModal() {
return (
<CRUDModalTemplate
isOpen={true}
onSubmit={handleSubmit}
title="Edit User"
>
<form>
<input name="username" />
<button type="submit">Save</button>
</form>
</CRUDModalTemplate>
);
}

Configuration Options

The rule can be customized with these options:

// eslint.config.js
{
'custom-rules/prefer-crud-modal-template': ['error', {
keywords: ['onSubmit', 'onConfirm', 'onPrimary', 'onSave'], // Default
variants: ['BaseModal'], // Default
ignorePaths: ['src/test/**'], // Files to ignore
importPathPatterns: ['**/BaseModal'] // Custom import patterns
}]
}

Auto-fix Capability

This rule provides automatic fixes that:

  • Replace BaseModal imports with CRUDModalTemplate
  • Preserve other imports when multiple components are imported from the same module
  • Handle both default and named imports
  • Maintain import aliases

Benefits

  1. Consistency: Ensures CRUD modals use the standardized template
  2. Best Practices: Enforces proper component usage patterns
  3. Maintainability: Makes CRUD modal code more predictable and easier to maintain
  4. Developer Experience: Provides real-time feedback and automatic fixes in your IDE

Disabling ESLint Rules

While ESLint rules are designed to maintain code quality, there are rare cases where you may need to disable them. Use these guidelines responsibly and sparingly.

Inline Disabling

Disable a specific rule for the next line:

// es‌lint-disable-next-line custom-rules/prefer-crud-modal-template
<BaseModal onSubmit={handleSubmit}>

Disable multiple rules for the next line:

// es‌lint-disable-next-line custom-rules/prefer-crud-modal-template, no-restricted-imports
import { BaseModal } from 'shared-components/BaseModal';

Disable a rule for the current line:

<BaseModal onSubmit={handleSubmit}> {/* es‌lint-disable-line custom-rules/prefer-crud-modal-template */}

Block Disabling

Disable rules for a block of code:

/* es‌lint-disable custom-rules/prefer-crud-modal-template */
function LegacyModal() {
return (
<BaseModal onSubmit={handleSubmit}>
<form>...</form>
</BaseModal>
);
}
/* es‌lint-enable custom-rules/prefer-crud-modal-template */

File-level Disabling

Disable rules for an entire file (add at the top):

/* es‌lint-disable custom-rules/prefer-crud-modal-template */

// Rest of your file...

Disable all ESLint rules for a file:

/* es‌lint-disable */

// Rest of your file...

Best Practices for Disabling Rules

  1. Always include a comment explaining why you're disabling the rule:

    // Legacy component that will be refactored in next sprint  
    // es‌lint-disable-next-line custom-rules/prefer-crud-modal-template
    <BaseModal onSubmit={handleSubmit}>
  2. Use the most specific disable possible - prefer eslint-disable-next-line over broader disables

  3. Consider refactoring instead - if you find yourself disabling rules frequently, the code might need restructuring

  4. Document technical debt - create GitHub issues for code that needs future refactoring when rules are disabled

When Disabling is Acceptable

  • Legacy code during gradual migration
  • Third-party library compatibility issues
  • Test files with specific testing patterns

When NOT to Disable

  • Convenience - don't disable rules just because they're inconvenient
  • Security rules - never disable security-related rules without team approval
  • Style preferences - the linting rules represent agreed-upon team standards

Running Lint Checks

To run ESLint checks on your code:

# Check for linting issues
pnpm run lint:check

# Auto-fix issues where possible
pnpm run lint:fix