@poupe/eslint-config
v0.10.0
Published
Sharable ESLint configuration preset for Poupe UI projects with TypeScript, Vue.js, and Tailwind CSS support
Maintainers
Readme
@poupe/eslint-config
Sharable ESLint configuration preset for Poupe UI projects with TypeScript, Vue.js, and Tailwind CSS support.
✅ Includes:
- eslint recommended rules
- stylistic recommended formatting rules
- typescript-eslint integration
- unicorn rules
- perfectionist rules for sorting imports, exports, types, and more
- vue recommended rules with TypeScript support
- tsdoc rules for TypeScript documentation
- markdownlint rules for Markdown files, including link and table-consistency checks
- jsonc rules for JSON and package.json files
- css rules for CSS files with Tailwind CSS support
- Poupe UI recommended rules
Getting started
[!NOTE] This preset uses the new ESLint flat config format and supports ESLint v9 or v10 on Node.js 20.19+, 22.13+, or 24+.
eslint and @eslint/js are peer dependencies — the preset does not
bundle them, so you must install them yourself alongside it:
pnpm install -D eslint @eslint/js typescript @poupe/eslint-configCreate eslint.config.mjs in your project root:
// @ts-check
import poupeConfig from '@poupe/eslint-config';
export default poupeConfig;For Nuxt.js applications (with @nuxt/eslint):
// @ts-check
import { withPoupe } from '@poupe/eslint-config';
import withNuxt from './.nuxt/eslint.config.mjs';
export default withPoupe(withNuxt(), {
rules: {
// custom rule overrides
},
});For Nuxt modules (with @nuxt/eslint-config):
// @ts-check
import { createConfigForNuxt } from '@nuxt/eslint-config/flat';
import { withPoupe } from '@poupe/eslint-config';
export default withPoupe(createConfigForNuxt({
features: {
tooling: true, // Enables rules for module authors
stylistic: true, // Enables formatting rules
},
}));Custom configuration:
// @ts-check
import { defineConfig } from '@poupe/eslint-config';
export default defineConfig({
rules: {
// rule overrides
},
});CSS Support
This configuration includes advanced CSS linting with Tailwind CSS v4 syntax support. The CSS configuration uses an intelligent filtering system that:
- Applies CSS-specific rules from
@eslint/css - Supports Tailwind CSS v4 syntax including theme functions and modifiers
- Automatically disables JavaScript-specific rules for CSS files
- Keeps relevant cross-language rules (like
filename-casefrom unicorn)
The filtering system categorizes plugins and rules to ensure only appropriate rules apply to CSS files. See AGENTS.md for implementation details.
Supported File Types
This configuration automatically lints the following file types:
- JavaScript:
.js,.mjs,.cjs - TypeScript:
.ts,.tsx - Vue.js:
.vue(Single File Components) - JSON/JSONC:
.json,.jsonc,package.json - Markdown:
.md - CSS:
.css,.postcss, Vue<style>blocks (with Tailwind CSS v4 syntax support)
Features
Self-Dogfooding
This package uses its own ESLint configuration for validation, ensuring quality and serving as a real-world test case.
Automatic Import/Export Sorting
This configuration includes eslint-plugin-perfectionist which automatically
organizes your imports and exports. The sorting happens automatically when you
run eslint --fix or save files with ESLint auto-fix enabled in your editor:
// Before
import { z } from 'zod';
import React from 'react';
import { useState, useEffect } from 'react';
import { Button } from './components/Button';
import axios from 'axios';
import type { User } from '../types';
import { config } from './config';
// After (automatically fixed by ESLint)
import type { User } from '../types';
import axios from 'axios';
import React from 'react';
import { z } from 'zod';
import { config } from './config';
import { Button } from './components/Button';
import { useEffect, useState } from 'react';Import Grouping with Empty Lines
The configuration respects empty lines as block separators, allowing you to organize imports into logical groups:
// Core React imports
import React from 'react';
import { useState, useEffect } from 'react';
// External libraries
import axios from 'axios';
import { z } from 'zod';
// Internal modules
import { config } from './config';
import { Button } from './components/Button';Each group separated by empty lines is sorted independently, preserving your intended organization while maintaining consistent ordering within each group.
Union and Intersection Type Sorting
Union and intersection types are sorted in natural order. Use comments to create logical groups:
// Before
type Status = 'error' | 'loading' | 'success' | 'idle';
// After (automatically fixed by ESLint)
type Status = 'error' | 'idle' | 'loading' | 'success';
// With comment-based grouping
type Status =
// Active states
| 'loading'
| 'processing'
// Inactive states
| 'error'
| 'idle'
| 'success';Additional Sorting Rules
The configuration also sorts these constructs in natural alphabetical order,
all auto-fixable via eslint --fix:
- Interfaces and object types — sorted by property name, with blank-line grouping support
- Enums — sorted by member name (numeric enums sorted by value)
- Classes — sorted by member type and visibility (static first, then instance, public before private), with blank-line grouping
- Heritage clauses —
extendsandimplementslists - Variable declarations — destructured bindings
- Import/export attributes —
import ... with { ... }keys
Advanced Configuration
Custom Rule Overrides
// @ts-check
import { defineConfig } from '@poupe/eslint-config';
export default defineConfig({
rules: {
// Disable specific rules
'unicorn/filename-case': 'off',
// Customize rule severity and options
'@typescript-eslint/no-unused-vars': ['warn', {
argsIgnorePattern: '^_',
varsIgnorePattern: '^_',
}],
},
});Selective Configuration Import
// @ts-check
import { configs, withConfig } from '@poupe/eslint-config';
// Import only specific configurations
export default withConfig(
configs.javascript,
configs.typescript,
configs.stylistic,
configs.vue,
// Add custom overrides
{
rules: {
'vue/multi-word-component-names': 'off',
},
},
);Combining Configs from Multiple Sources
When composing configs from different packages, use withPoupe to
layer Poupe configs on top of an upstream config. It handles async
resolution and deduplicates plugin instances automatically:
// @ts-check
import { withPoupe } from '@poupe/eslint-config';
import someOtherConfig from 'some-other-eslint-config';
export default withPoupe(someOtherConfig);For lower-level control, reconcilePlugins deduplicates plugin
instances in a flat config array using a first-wins strategy:
// @ts-check
import { defineConfig, reconcilePlugins } from '@poupe/eslint-config';
import someOtherConfig from 'some-other-eslint-config';
export default reconcilePlugins([
...someOtherConfig,
...defineConfig(),
]);Poupe UI Recommended Rules
In addition to the rules from included plugins, this configuration adds these custom rules:
TypeScript Rules
- Enforces explicit return types on exported functions
- Requires consistent type imports (
import type) - Disables
@ts-comment directives
Vue.js Rules
- Enforces multi-word component names
- Requires
defineEmitsanddefinePropstype declarations - Ensures proper
v-modelusage patterns
General JavaScript Rules
- Enforces camelCase naming convention
- Allows
i,j,kas loop counters and array indices - Requires explicit radix in
parseInt - Prevents console statements in production code
Stylistic Rules
- Single quotes for strings
- Semicolons required
- 1tbs (one true brace style)
- 2-space indentation for web files
- 80-character line limit for Markdown (tables exempt)
Migration Guide
From Legacy ESLint Config
If you're migrating from a legacy .eslintrc configuration:
Remove old config files: Delete
.eslintrc,.eslintrc.js,.eslintrc.json, etc.Update dependencies:
pnpm remove eslint-config-* eslint-plugin-* pnpm install -D eslint @eslint/js typescript @poupe/eslint-configCreate new config: Add
eslint.config.mjsas shown in Getting StartedUpdate scripts: ESLint automatically finds
eslint.config.mjs{ "scripts": { "lint": "eslint --fix .", "lint:check": "eslint ." } }Handle breaking changes:
- Some rules have been renamed or moved to different plugins
- The flat config uses different property names (
filesinstead ofoverrides) - Plugin names are now used as object keys instead of strings
Examples
The examples/ directory contains working examples demonstrating how to use
this ESLint configuration in different scenarios:
- playground-standard - Basic JavaScript/TypeScript projects (inherits the workspace ESLint, currently v10)
- playground-eslint9 - Basic JavaScript/TypeScript projects (pinned to ESLint 9)
- playground-nuxt - Nuxt.js applications
- playground-nuxt-module - Nuxt module development
Running Examples
This project uses pnpm workspaces. You can run commands on all examples:
# Install dependencies for all workspaces
pnpm install
# Check all examples without fixing
pnpm -r --filter "./examples/*" lint:check
# Lint and fix all examples
pnpm -r --filter "./examples/*" lint
# Run a specific example
pnpm --filter "playground-standard" lintTroubleshooting
Common Issues
"Cannot find module '@poupe/eslint-config'"
Ensure you've installed the package and are using the correct import path:
pnpm install -D @poupe/eslint-config"Plugin conflict" errors with Nuxt
For Nuxt applications, use withPoupe from the root entry point:
- Nuxt apps:
withPoupe(withNuxt()) - Nuxt modules:
withPoupe(createConfigForNuxt(...))
CSS rules applying to JavaScript files
This should not happen with the default configuration. If it does, ensure you're using the latest version and report an issue.
"Unknown rule" warnings
These warnings help the CSS filtering system learn about new rules. They're informational and don't affect functionality.
Debugging
To debug ESLint configuration issues:
# Show resolved configuration for a specific file
eslint --print-config path/to/file.js
# Verbose per-file linting trace
env DEBUG=eslint:linter pnpm lint:check
# Debug config resolution
env DEBUG=eslint:eslint pnpm lintDevelopment
For AI assistants working with this codebase, refer to AGENTS.md for detailed guidance and conventions.
Project Structure
src/
├── configs/ # Individual ESLint rule configurations
├── core/ # Core utilities and type definitions
├── config.ts # Main configuration builder
├── configs.ts # Configuration presets
└── index.ts # Main entry pointContributing
- Make changes to configuration files in
src/configs/ - Run
pnpm buildto compile the package - Test with
pnpm lint(self-linting) - Test in examples:
pnpm -r --filter "./examples/*" lint
