custom-formatting

skill

How to use ESLint v9 Flat Config with @stylistic/eslint-plugin to enforce custom padding (like 3 blank lines after imports) instead of Prettier. Use when configuring or fixing formatting rules in this workspace.

v1.0.0development
eslintstylisticprettierformattingast
Install this skill
$npx @ivannikov-pro/ai-agent-kit@latest add custom-formatting

ESLint v9 & Stylistic Padding Enforcement

This repository strictly rejects default Prettier formatting in favor of highly customized structural spacing rules powered by ESLint v9 Flat Config and the @stylistic/eslint-plugin.

When to Use

  • Generating new code and needing to understand the spacing format.
  • Troubleshooting linting errors related to empty lines.
  • Adding a new package to the monorepo and setting up its formatting rules.
  • Whenever an AI agent or developer tries to install or format code with Prettier.

⚠️ Gotchas & Critical Rules

  • NEVER use Prettier: Prettier forcibly collapses multiple empty lines into a maximum of 1 empty line. This violates our strict project requirement of 3 blank lines after imports and 2 blank lines between blocks.
  • ESLint Handles Everything: We rely entirely on eslint with the --fix flag to resolve spacing.
  • AI Formatting Requirements: All code generated by AI agents must natively respect these custom line spacings. Do not rely on ESLint to fix generated code if you can write it correctly in the first place.

Core Setup: @stylistic/padding-line-between-statements

The spacing enforcement relies on this specific configuration inside packages/config-eslint:

"@stylistic/padding-line-between-statements": [
  "error",
  // Always 3 lines after imports
  { blankLine: "always", prev: "import", next: "*" },
  { blankLine: "always", prev: "import", next: "*" },
  { blankLine: "always", prev: "import", next: "*" },

  // Always 2 lines before logical blocks (functions, types, classes)
  { blankLine: "always", prev: "*", next: "function" },
  { blankLine: "always", prev: "*", next: "function" },
  
  { blankLine: "always", prev: "*", next: "type" },
  { blankLine: "always", prev: "*", next: "type" },

  { blankLine: "always", prev: "*", next: "interface" },
  { blankLine: "always", prev: "*", next: "interface" },
]

Note: In ESLint, repeating the blankLine: "always" target multiple times tells the linter to expect multiple consecutive lines. We complement this with "@stylistic/no-multiple-empty-lines": ["error", { "max": 4 }] to avoid conflicting limits.

Bootstrap Formatting Script

Because ESLint's --fix isn't always perfect at inserting missing multi-line padding across dense legacy codebases, we have a Node script that structurally injects the gaps using Regex before linting.

# Run the rough structural insertion
node .agents/skills/custom-formatting/scripts/force-spacing.mjs ./apps/web-app/src/components

# Polish and finish with exact ESLint AST resolution
pnpm turbo run lint -- --fix

AI Native Code Generation

When producing code snippets or updating existing code in your context window, insert literal newline characters (\n\n\n) correctly! E.g.

import React from 'react';
import { Button } from '@ivannikov-pro/ui';



export function MyComponent() {
  return <Button />;
}



export type MyComponentProps = {
  active: boolean;
};

Markdown Table Formatting

While the primary focus of this skill is TS/JS spacing, the same philosophy of human-readable formatting applies to all markdown files in the repo.

Aligned Tables

Tables in .md files (skills, workflows, docs, playbooks) must have padded, aligned columns. The separator row (---) must span the widest content in each column.

<!-- ❌ Wrong — compressed, hard to scan in raw markdown -->
| Tool          | Purpose             |
| ------------- | ------------------- |
| **pnpm**      | Package manager     |
| **Turborepo** | Build orchestration |

<!-- ✅ Correct — aligned, easy to read -->
| Tool          | Purpose             |
| ------------- | ------------------- |
| **pnpm**      | Package manager     |
| **Turborepo** | Build orchestration |

Mermaid Diagram Labels

Never use \n or <br/> for multi-line labels in Mermaid graph nodes — they render inconsistently or literally. Use short node labels and add a legend table below the diagram.

Verification & Automation

Unlike TS/JS formatting (which ESLint enforces automatically), markdown table alignment is enforced via a custom script. When creating or editing .md files, or if you spot compressed tables (|---|), you can run the following script to automatically pad and align them:

# Format tables in a specific file or directory
node .agents/skills/custom-formatting/scripts/format-tables.mjs ./docs/ARCHITECTURE.md

To quickly find compressed tables in the repo:

grep -rn '|---|' .agents/ docs/ packages/ --include="*.md"