{"_id":"@cognirail/eslint-config","name":"@cognirail/eslint-config","dist-tags":{"latest":"2.1.3"},"versions":{"2.1.3":{"name":"@cognirail/eslint-config","version":"2.1.3","description":"Opinionated ESLint flat config + Prettier for TypeScript — AI coding guardrails","type":"module","exports":{".":{"types":"./src/index.d.mts","import":"./src/index.mjs","default":"./src/index.mjs"},"./cspell":{"types":"./src/configs/cspell.d.mts","import":"./src/configs/cspell.mjs","default":"./src/configs/cspell.mjs"},"./barrel":{"types":"./src/configs/barrel.d.mts","import":"./src/configs/barrel.mjs","default":"./src/configs/barrel.mjs"},"./role-naming":{"types":"./src/configs/role-naming.d.mts","import":"./src/configs/role-naming.mjs","default":"./src/configs/role-naming.mjs"},"./nest-naming":{"types":"./src/configs/nest-naming.d.mts","import":"./src/configs/nest-naming.mjs","default":"./src/configs/nest-naming.mjs"},"./agent":{"types":"./src/agent.d.mts","import":"./src/agent.mjs","default":"./src/agent.mjs"},"./prettier":{"import":{"types":"./src/prettier.d.mts","default":"./src/prettier.mjs"},"require":{"types":"./src/prettier.d.cts","default":"./src/prettier.cjs"}}},"scripts":{"smoke":"node scripts/smoke.mjs","test":"node scripts/smoke.mjs"},"engines":{"node":"^20.19.0 || ^22.13.0 || >=24"},"author":{"name":"halo xie"},"license":"ISC","homepage":"https://github.com/cognirail/eslint-config#readme","bugs":{"url":"https://github.com/cognirail/eslint-config/issues"},"repository":{"type":"git","url":"git+https://github.com/cognirail/eslint-config.git"},"publishConfig":{"access":"public","registry":"https://registry.npmjs.org/"},"keywords":["eslint","eslintconfig","prettier","typescript","flat-config","ai-coding"],"dependencies":{"@eslint/js":"^10.0.1","eslint-config-prettier":"^10.1.8","eslint-import-resolver-typescript":"^4.4.5","eslint-plugin-import-x":"^4.16.2","eslint-plugin-n":"^18.0.1","eslint-plugin-sonarjs":"^4.0.3","eslint-plugin-unicorn":"^64.0.0","globals":"^17.6.0","typescript-eslint":"^8.60.1"},"devDependencies":{"@cspell/eslint-plugin":"^10.0.1"},"peerDependencies":{"@cspell/eslint-plugin":">=10.0.1","eslint":">=10.4.1","prettier":">=3.8.3","typescript":">=6.0.3"},"peerDependenciesMeta":{"@cspell/eslint-plugin":{"optional":true},"prettier":{"optional":true},"typescript":{"optional":true}},"gitHead":"f02f7e647857454a582e109ec54a1568a28b9c3d","_id":"@cognirail/eslint-config@2.1.3","_nodeVersion":"24.13.0","_npmVersion":"11.6.2","dist":{"integrity":"sha512-Nv3iYPIMUgkxTlT00EYmHnWLHa8U4vU1sq+15tfZRgCF9KM7CYTVu3dFH9rQ1KZxZYsVzFbh4KPi7k4nfNkGOw==","shasum":"cd6aa040ba3b4a353687f18ca31b360567c1019d","tarball":"https://registry.npmjs.org/@cognirail/eslint-config/-/eslint-config-2.1.3.tgz","fileCount":26,"unpackedSize":99184,"signatures":[{"keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U","sig":"MEQCIB7yeYnmbR+Q4cQRv5VDUI3O+Lchj3amEfTvJS976CI6AiA94qRevYs743/ALm8o+8gK5yllE4pEF5cVuPkAKexXRw=="}]},"_npmUser":{"name":"haloxie","email":"minghao.xie@foxmail.com"},"directories":{},"maintainers":[{"name":"haloxie","email":"minghao.xie@foxmail.com"}],"_npmOperationalInternal":{"host":"s3://npm-registry-packages-npm-production","tmp":"tmp/eslint-config_2.1.3_1782807378817_0.7256826155187215"},"_hasShrinkwrap":false}},"time":{"created":"2026-06-30T08:16:18.671Z","2.1.3":"2026-06-30T08:16:18.944Z","modified":"2026-06-30T08:16:19.179Z"},"maintainers":[{"name":"haloxie","email":"minghao.xie@foxmail.com"}],"description":"Opinionated ESLint flat config + Prettier for TypeScript — AI coding guardrails","homepage":"https://github.com/cognirail/eslint-config#readme","keywords":["eslint","eslintconfig","prettier","typescript","flat-config","ai-coding"],"repository":{"type":"git","url":"git+https://github.com/cognirail/eslint-config.git"},"author":{"name":"halo xie"},"bugs":{"url":"https://github.com/cognirail/eslint-config/issues"},"license":"ISC","readme":"# @cognirail/eslint-config\n\nOpinionated ESLint flat config + Prettier for TypeScript projects.\n\nDesigned as **AI coding guardrails** — strict type checks, complexity detection, modern JS enforcement, and no inline escape hatches. One package, zero config hassle.\n\n## Included Plugins\n\n| Plugin                                | Purpose                                                           |\n| ------------------------------------- | ----------------------------------------------------------------- |\n| `typescript-eslint` strictTypeChecked | Strict TS rules + type-aware analysis                             |\n| `eslint-plugin-unicorn`               | Modern JS idioms enforcement                                      |\n| `eslint-plugin-sonarjs`               | Code smell + bug detection                                        |\n| `eslint-plugin-import-x`              | Import organization + TS resolver                                 |\n| `eslint-plugin-n`                     | Node.js best practices                                            |\n| `eslint-config-prettier`              | Disable formatting rules (let Prettier handle it)                 |\n| `eslint-import-resolver-typescript`   | TypeScript-aware import resolution for import-x                   |\n| `@cspell/eslint-plugin`               | Spell checking for identifiers, comments, and JSX text (optional) |\n\n## Requirements\n\n- **Node.js** ^20.19.0 || ^22.13.0 || >=24\n- **ESLint** >= 10.4.1\n- **TypeScript** >= 6.0.3 (optional — works without it when `disableTypeChecked: true`)\n- **Prettier** >= 3.8.3 (optional — only needed if using `./prettier` export)\n\n## Quick Start\n\n### 1. Install\n\n```bash\npnpm add -D @cognirail/eslint-config eslint typescript prettier\n```\n\n### 2. ESLint — create `eslint.config.mjs`\n\n```js\nimport { defineConfig } from '@cognirail/eslint-config';\n\nexport default defineConfig();\n```\n\n> Also supports `eslint.config.ts` with typescript-eslint v8+.\n\n### 3. Prettier — add to `package.json`\n\n```json\n{\n  \"prettier\": \"@cognirail/eslint-config/prettier\"\n}\n```\n\n### 4. Add lint scripts\n\n```json\n{\n  \"scripts\": {\n    \"lint\": \"eslint .\",\n    \"lint:fix\": \"eslint --fix . && prettier --write .\",\n    \"format:check\": \"prettier --check .\"\n  }\n}\n```\n\nDone. Run `pnpm lint` to check, `pnpm lint:fix` to auto-fix.\n\n> **Note:** Your project must have a `tsconfig.json` for type-aware rules to work. If you don't have one, set `disableTypeChecked: true` in the options.\n\n### 5. (Optional) Spell Checking\n\nRequires **Node.js** >= 22.18.0 because `@cspell/eslint-plugin` v10 uses that runtime baseline.\n\n```bash\npnpm add -D @cspell/eslint-plugin\n```\n\n```js\n// eslint.config.mjs\nimport { defineConfig } from '@cognirail/eslint-config';\nimport { cspell } from '@cognirail/eslint-config/cspell';\n\nexport default [...defineConfig(), ...cspell()];\n```\n\nThe CSpell config includes a built-in word list for common tech ecosystem terms (AI/DB/tooling). To add project-specific words, pass them via the `words` option:\n\n```js\nexport default [...defineConfig(), ...cspell({ words: ['myapp', 'myterm'] })];\n```\n\nAlternatively, create a `cspell.json` at project root — CSpell auto-discovers it.\n\n### 6. (Optional) Barrel Import Enforcement\n\nEnforce barrel imports at architecture boundaries — prevent deep path imports like `@agent/runtime/internal/executor` and force consumers to use `@agent/runtime`.\n\n```js\n// eslint.config.mjs\nimport { defineConfig } from '@cognirail/eslint-config';\nimport { barrel } from '@cognirail/eslint-config/barrel';\n\nexport default [\n  ...defineConfig({ tsconfigRootDir: import.meta.dirname }),\n  ...barrel({\n    boundaries: [\n      {\n        publicAlias: '@agent/runtime',\n        internalGlobs: ['src/agent/runtime/**'],\n        consumers: ['src/agent/**', 'src/tools/**', 'test/**'],\n      },\n    ],\n  }),\n];\n```\n\n| Option                              | Type       | Description                                                                                  |\n| ----------------------------------- | ---------- | -------------------------------------------------------------------------------------------- |\n| `boundaries[].publicAlias`          | `string`   | Public alias to import from. Blocks imports below this alias.                                |\n| `boundaries[].internalGlobs`        | `string[]` | Files inside the implementation boundary; ignored so internals can import each other.        |\n| `boundaries[].consumers`            | `string[]` | Files where deep imports from the public alias are forbidden.                                |\n| `boundaries[].allowInternalFrom`    | `string[]` | Additional globs allowed to import internals.                                                |\n| `boundaries[].ignores`              | `string[]` | Extra ignores for this boundary.                                                             |\n| `layers` / `enforcedIn` / `ignores` | —          | Legacy API kept for existing configs; prefer `boundaries` for new architecture declarations. |\n\nThe rule only applies to boundary `consumers`; files matching `internalGlobs`, `allowInternalFrom`, or `ignores` are not restricted.\n\n### 7. (Optional) Agent Project Preset\n\nUse `./agent` when the project contains agent runtime/tool/prompt/eval code and should enforce role-based file naming. This is the core agent preset; spell checking remains opt-in through `./cspell`.\n\n```js\n// eslint.config.mjs\nimport { defineAgentConfig } from '@cognirail/eslint-config/agent';\n\nexport default defineAgentConfig({\n  tsconfigRootDir: import.meta.dirname,\n  boundaries: [\n    {\n      publicAlias: '@agent/runtime',\n      internalGlobs: ['src/agent/runtime/**'],\n      consumers: ['src/agent/**', 'src/tools/**', 'test/**'],\n    },\n  ],\n});\n```\n\nDefault agent role suffixes:\n\n| Suffix      | Expected shape       |\n| ----------- | -------------------- |\n| `runtime`   | any                  |\n| `executor`  | class or function    |\n| `planner`   | class or function    |\n| `tool`      | schema or function   |\n| `prompt`    | text or factory      |\n| `eval`      | any                  |\n| `adapter`   | class or function    |\n| `schema`    | any                  |\n| `memory`    | class or function    |\n| `type`      | interface/type alias |\n| `interface` | interface/type alias |\n\n### 8. (Optional) Role-Based File Naming\n\nUse `./role-naming` directly for non-Nest, non-agent projects with their own role suffix table.\n\n```js\nimport { defineConfig } from '@cognirail/eslint-config';\nimport { roleNaming } from '@cognirail/eslint-config/role-naming';\n\nexport default [\n  ...defineConfig({ tsconfigRootDir: import.meta.dirname }),\n  ...roleNaming({\n    suffixes: {\n      service: { kind: 'class-or-function' },\n      schema: { kind: 'any' },\n      type: { kind: 'types' },\n    },\n  }),\n];\n```\n\n### 9. (Optional) NestJS File Naming\n\nEnforce the NestJS file-naming convention: role-suffix whitelist, content↔suffix binding, ambient declaration placement, and a single test-file convention. Self-contained — adds **no** external ESLint plugin dependency.\n\nGeneral form:\n\n```txt\n<kebab-base>.<role>.ts\n```\n\nThe role suffix describes the dominant symbol's role, not merely its technical shape. One file should have one role: if a `*.service.ts` grows DTOs, interfaces, or exported utility types, split them into the role-specific files. Narrow private utility types that are not externally imported may stay close to the implementation.\n\n```js\n// eslint.config.mjs\nimport { defineConfig } from '@cognirail/eslint-config';\nimport { nestNaming } from '@cognirail/eslint-config/nest-naming';\n\nexport default [\n  ...defineConfig({ tsconfigRootDir: import.meta.dirname }),\n  ...nestNaming({ files: ['src/**/*.ts'] }),\n];\n```\n\nRules:\n\n| Rule                                 | Catches                                                                                                                                                                                   |\n| ------------------------------------ | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |\n| `nest-naming/allowed-suffix`         | Filename suffix not in the role whitelist (e.g. `*.widget.ts`); non-kebab base (`CreateUser.dto.ts`)                                                                                      |\n| `nest-naming/suffix-kind`            | Content doesn't match suffix: `*.dto.ts` written as `interface`/`type`; a class inside `*.interface.ts` / `*.type.ts`; exported interfaces/types left in the wrong role file              |\n| `nest-naming/suffix-decorator`       | A `*.controller.ts` / `*.service.ts` / `*.module.ts` / `*.guard.ts` class missing its `@Controller` / `@Injectable` / `@Module` decorator (severity = `enforceDecorator`, default `warn`) |\n| `nest-naming/test-suffix`            | Wrong test convention: `*.test.ts` when Nest's default jest `testRegex` only matches `*.spec.ts` (silent skip)                                                                            |\n| `nest-naming/declaration-file`       | Ambient `declare ...` declarations hidden in normal implementation files, or project domain types placed in `*.d.ts`                                                                      |\n| `nest-naming/no-global-types-folder` | Project types placed in a global `types/` or `src/types/` folder instead of being co-located with the owning module                                                                       |\n\nSuffixes are graded by runtime shape. `class` files emit JS and participate in DI/decorators/new; `interface`/`type` files disappear after compilation; `any` files are allowed because they may be functions, constants, or mixed framework forms.\n\nClass suffixes with enforced decorators:\n\n| Suffix        | Role                                                   | Decorator           |\n| ------------- | ------------------------------------------------------ | ------------------- |\n| `controller`  | HTTP/RPC entrypoint; orchestration, not business logic | `@Controller`       |\n| `service`     | Injectable application/domain logic                    | `@Injectable`       |\n| `module`      | DI organization unit                                   | `@Module`           |\n| `guard`       | `CanActivate` access control                           | `@Injectable`       |\n| `pipe`        | `PipeTransform` validation/transformation              | `@Injectable`       |\n| `interceptor` | `NestInterceptor` around advice                        | `@Injectable`       |\n| `filter`      | `ExceptionFilter` handling                             | `@Catch`            |\n| `resolver`    | GraphQL resolver                                       | `@Resolver`         |\n| `gateway`     | WebSocket gateway                                      | `@WebSocketGateway` |\n\nClass suffixes without fixed decorator enforcement:\n\n| Suffix       | Role                                                                 |\n| ------------ | -------------------------------------------------------------------- |\n| `dto`        | Boundary data contract with runtime validation; DTOs must be classes |\n| `entity`     | Persistence mapping / domain entity                                  |\n| `repository` | Custom repository                                                    |\n| `strategy`   | Passport strategy                                                    |\n| `subscriber` | TypeORM event subscriber                                             |\n\nCompile-time suffixes:\n\n| Suffix      | Must contain            | Forbidden |\n| ----------- | ----------------------- | --------- |\n| `interface` | `interface` declaration | class     |\n| `type`      | `type` alias            | class     |\n\nContent-free suffixes:\n\n| Suffixes                                | Typical content                                      |\n| --------------------------------------- | ---------------------------------------------------- |\n| `decorator`                             | Custom decorator functions / factories               |\n| `middleware`                            | Function middleware or injectable class              |\n| `constant` / `constants`                | Exported constants                                   |\n| `enum`                                  | Enum declarations                                    |\n| `config`                                | `registerAs()` functions or config objects           |\n| `schema` / `model`                      | Mongoose / GraphQL mixed forms                       |\n| `validator`                             | `@ValidatorConstraint` class or validation functions |\n| `util` / `utils` / `helper` / `helpers` | Pure helper functions                                |\n| `mock` / `fixture`                      | Test helpers                                         |\n\nContent binding decisions:\n\n- DTOs must be classes. `class-validator` relies on runtime objects; `interface`/`type` DTOs compile away and can silently bypass `ValidationPipe`.\n- `*.interface.ts` and `*.type.ts` must not contain classes.\n- Use `*.interface.ts` for `implements`, declaration merging, `extends`, and ordinary object shapes.\n- Use `*.type.ts` for union, intersection, mapped, conditional, tuple, and utility types.\n- Do not use `*.d.ts` for project domain types. Reserve `*.d.ts` for ambient declarations such as third-party typings, `declare global`, and `declare module`.\n- Do not centralize project types in a global `types/` folder; co-locate them with the owning module.\n- Base names must be kebab-case: `create-user.dto.ts`, not `CreateUser.dto.ts`.\n\nTest suffixes:\n\n| Type      | Suffix                     | Reason                                   |\n| --------- | -------------------------- | ---------------------------------------- |\n| Unit test | `*.spec.ts`                | Matches Nest's default Jest `testRegex`  |\n| E2E test  | `*.e2e-spec.ts`            | Matches Nest's e2e Jest config           |\n| Forbidden | `*.test.ts` / `*.tests.ts` | Can be silently skipped in Nest projects |\n\n| Option             | Type                                   | Default           | Description                                                                                                      |\n| ------------------ | -------------------------------------- | ----------------- | ---------------------------------------------------------------------------------------------------------------- |\n| `files`            | `string[]`                             | `['src/**/*.ts']` | Globs the rules apply to.                                                                                        |\n| `ignores`          | `string[]`                             | `[]`              | Globs to exclude.                                                                                                |\n| `suffixes`         | `Record<string, { kind; decorator? }>` | —                 | Merge on top of the default suffix table (add project suffixes / relax decorators).                              |\n| `testSuffix`       | `'spec' \\| 'test' \\| false`            | `'spec'`          | Which single test convention to enforce; `false` disables.                                                       |\n| `kebabCase`        | `boolean`                              | `true`            | Require kebab-case base names.                                                                                   |\n| `enforceDecorator` | `boolean \\| 'warn'`                    | `'warn'`          | `true` => error, `false` => off. Start at `warn` to surface noise from abstract bases before promoting to error. |\n\n> Test files (`*.spec.ts`, `*.e2e-spec.ts`) and suffix-less files (`index.ts`, `main.ts`) are exempt from `allowed-suffix` and `suffix-kind`. Identifier naming is handled separately by the base config: classes, interfaces, type aliases, enums, enum members, and type parameters use `PascalCase`; interfaces cannot use Hungarian `I` prefixes.\n\n## Options\n\n```js\nimport { defineConfig } from '@cognirail/eslint-config';\n\nexport default defineConfig({\n  // Path to tsconfig.json directory (default: process.cwd())\n  tsconfigRootDir: import.meta.dirname,\n\n  // Additional ignore patterns (extends defaults, doesn't replace)\n  ignores: ['**/generated/**', '**/proto/**'],\n\n  // Additional abbreviations for unicorn/prevent-abbreviations (merged with defaults)\n  abbreviations: { src: true, dest: true },\n\n  // Additional prevent-abbreviations ignore patterns (merged with defaults)\n  abbreviationIgnore: ['(^|[._-])api($|[._-])'],\n\n  // Additional file globs where devDependency imports are allowed (merged with defaults)\n  testFiles: ['**/__tests__/**', '**/e2e/**'],\n\n  // Rule overrides (applied last). Keep these for explicit project exceptions,\n  // not for lowering the guardrail baseline.\n  overrides: {\n    'sonarjs/cognitive-complexity': ['error', 20],\n  },\n\n  // Falls back to strict + stylistic (non-type-aware variants),\n  // still provides substantial linting without a tsconfig.json.\n  disableTypeChecked: false,\n});\n```\n\n### Default Ignores\n\nThese glob patterns are always ignored: `dist/**`, `build/**`, `output/**`, `node_modules/**`, `coverage/**`, `.next/**`, `.nuxt/**`, `.output/**`.\n\n### JS/CJS File Handling\n\nJS files (`*.js`, `*.mjs`, `*.cjs`) automatically have type-checked rules and return-type requirements disabled. CommonJS files (`*.cjs`, `*.cts`) parse with `sourceType: 'commonjs'`, so the config works in mixed TS/JS projects out of the box.\n\n### Inline Config Policy\n\nInline ESLint config comments are disabled via `linterOptions.noInlineConfig`, and `ai-guardrails/no-inline-eslint-config` reports ESLint directive comments as errors. AI-generated code should not be able to silence guardrails with `eslint-disable` comments. Use `ignores` for generated output and explicit top-level `overrides` for rare project-level exceptions.\n\n## Prettier Config\n\nThe bundled Prettier config uses these settings:\n\n```json\n{\n  \"semi\": true,\n  \"singleQuote\": true,\n  \"jsxSingleQuote\": true,\n  \"tabWidth\": 2,\n  \"trailingComma\": \"all\",\n  \"printWidth\": 100,\n  \"arrowParens\": \"always\",\n  \"bracketSpacing\": true,\n  \"bracketSameLine\": true,\n  \"endOfLine\": \"lf\",\n  \"htmlWhitespaceSensitivity\": \"ignore\",\n  \"vueIndentScriptAndStyle\": true\n}\n```\n\n## AI Guardrail Rules\n\nKey rules that catch common AI-generated code issues:\n\n| Rule                                               | AI Problem                                             | Effect                                         |\n| -------------------------------------------------- | ------------------------------------------------------ | ---------------------------------------------- |\n| `@typescript-eslint/no-floating-promises`          | AI writes `someAsync()` without `await`                | Forces promise handling                        |\n| `@typescript-eslint/no-misused-promises`           | AI passes async to non-promise-expecting APIs          | Catches async misuse                           |\n| `@typescript-eslint/explicit-function-return-type` | AI omits return types                                  | Forces explicit declarations                   |\n| `@typescript-eslint/no-explicit-any`               | AI falls back to `any`                                 | Enforces proper typing                         |\n| `@typescript-eslint/consistent-type-imports`       | AI mixes value/type imports                            | Forces `import type {}`                        |\n| `@typescript-eslint/prefer-nullish-coalescing`     | AI writes `x \\|\\| fallback` instead of `x ?? fallback` | Prevents falsy-value bugs                      |\n| `@typescript-eslint/prefer-optional-chain`         | AI writes manual `if (a && a.b)` chains                | Enforces `a?.b`                                |\n| `@typescript-eslint/strict-boolean-expressions`    | AI relies on truthy/falsy coercion                     | Forces explicit boolean intent                 |\n| `@typescript-eslint/switch-exhaustiveness-check`   | AI misses union cases                                  | Forces exhaustive discriminated-union handling |\n| `ai-guardrails/no-inline-eslint-config`            | AI tries to silence lint with comments                 | Forces exceptions into reviewed config         |\n| `sonarjs/cognitive-complexity` (<=15)              | AI writes deeply nested logic                          | Limits function complexity                     |\n| `unicorn/prefer-node-protocol`                     | AI writes `import fs from 'fs'`                        | Forces `node:fs` prefix                        |\n| `unicorn/no-array-for-each`                        | AI uses `.forEach()`                                   | Enforces `for...of`                            |\n| `curly` / `eqeqeq`                                 | AI writes terse or coercive conditionals               | Forces explicit blocks and equality            |\n| `no-console` / `no-debugger`                       | AI leaves ad-hoc diagnostics in production paths       | Blocks stray debugging artifacts               |\n| `prefer-const` / `no-var`                          | AI uses `let` or `var` unnecessarily                   | Forces immutable bindings                      |\n\n### Notable Unicorn Customizations\n\n- **`prevent-abbreviations`**: Allows common short names: `args`, `ctx`, `db`, `e2e`, `Env`, `env`, `err`, `fn`, `params`, `Prod`, `prod`, `props`, `ref`, `req`, `res`, `util`, `utils`; ignores conventional `*.e2e.*` filename segments\n- **`no-null`**: Disabled — Node.js/TS ecosystem uses `null` pervasively\n- **`no-array-reduce`**: Disabled — `reduce` is idiomatic for data aggregation\n- **`prefer-module`**: Disabled — supports mixed CJS/ESM codebases\n- **`prefer-top-level-await`**: Disabled for `main.ts` — CommonJS entry files cannot use top-level await\n- **`filename-case`**: Allows kebab-case, camelCase, and PascalCase\n\n### Notable TypeScript Customizations\n\n- **`no-extraneous-class`**: Allows classes with decorators — required by NestJS (`@Module`), Angular (`@NgModule`), and similar frameworks\n- **`restrict-template-expressions`**: Allows `number` in template literals — safe and ubiquitous in practice\n- **`strict-boolean-expressions`**: Disallows truthy/falsy shortcuts for strings, numbers, nullable values, and objects; write the actual condition\n- **`switch-exhaustiveness-check`**: Requires discriminated-union switches to handle every case; redundant `default` cases do not hide missing variants\n- **`naming-convention`**: Enforces `PascalCase` for interfaces and type aliases; forbids Hungarian notation prefixes (`IUser` → `User`, `TProps` → `Props`)\n\n### Notable Node.js Plugin Customizations\n\n- **`no-missing-import`**: Disabled — `eslint-plugin-import-x` with TypeScript resolver already covers this\n- **`no-process-exit`**: Disabled — `process.exit()` is valid in CLI tools and application entry points\n- **`no-unpublished-import`** / **`no-unpublished-require`**: Disabled for test, spec, and config files — devDependencies imports are expected there\n\n### Notable Import-x Customizations\n\n- **`named`**: Disabled for TypeScript files — TypeScript compiler already validates named exports\n\n### Notable SonarJS Customizations\n\n- **`cognitive-complexity`**: Set to 15 (default is 10)\n- **`no-nested-functions`**: Disabled — closures and callbacks are core JavaScript/TypeScript patterns\n- **`todo-tag`** / **`fixme-tag`**: Set to `warn` — allows TODO markers during development without blocking CI\n- **Cross-plugin dedup**: 9 rules disabled where `typescript-eslint` already provides equivalent checks: `no-array-delete`, `prefer-regexp-exec`, `deprecation`, `argument-type`, `different-types-comparison`, `no-try-promise`, `no-async-constructor`, `function-return-type`, `redundant-type-aliases`\n\n## Environment\n\nTargets modern Node.js runtimes (`^20.19.0 || ^22.13.0 || >=24`) with `ecmaVersion: 'latest'` and Node + ES2025 globals by default. Uses `eslint-plugin-n`'s `flat/recommended-module` preset (ESM-first), with `*.cjs` and `*.cts` parsed as CommonJS.\n\n## VSCode Setup\n\n```jsonc\n// .vscode/settings.json\n{\n  \"eslint.useFlatConfig\": true,\n  \"editor.formatOnSave\": true,\n  \"editor.defaultFormatter\": \"esbenp.prettier-vscode\",\n  \"editor.codeActionsOnSave\": {\n    \"source.fixAll.eslint\": \"explicit\",\n  },\n}\n```\n\nRecommended extensions: [ESLint](https://marketplace.visualstudio.com/items?itemName=dbaeumer.vscode-eslint), [Prettier](https://marketplace.visualstudio.com/items?itemName=esbenp.prettier-vscode), [Error Lens](https://marketplace.visualstudio.com/items?itemName=usernamehw.errorlens).\n\n## Migration from `@me-tool`\n\n`@cognirail/eslint-config` is the new package name for `@me-tool/eslint-prettier-ts-config`.\n\n```bash\npnpm remove @me-tool/eslint-prettier-ts-config\npnpm add -D @cognirail/eslint-config\n```\n\nThen replace imports and Prettier references:\n\n```diff\n- import { defineConfig } from '@me-tool/eslint-prettier-ts-config';\n+ import { defineConfig } from '@cognirail/eslint-config';\n\n- \"prettier\": \"@me-tool/eslint-prettier-ts-config/prettier\"\n+ \"prettier\": \"@cognirail/eslint-config/prettier\"\n```\n\n## Migration from v1\n\nv2 is a breaking change:\n\n1. **Update the package**\n\n   ```bash\n   pnpm add -D @cognirail/eslint-config@2 eslint@latest\n   pnpm remove @me-tool/eslint-prettier-config  # remove old base\n   ```\n\n2. **Replace config file**: Delete `.eslintrc.js` / `.eslintrc.json`, create `eslint.config.mjs` as shown in Quick Start.\n\n3. **Update Prettier**:\n\n   ```diff\n   - \"prettier\": \"@me-tool/eslint-prettier-ts-config/.prettierrc.js\"\n   + \"prettier\": \"@cognirail/eslint-config/prettier\"\n   ```\n\n4. **Update lint-staged**: Remove `git add` from commands (auto-staged since lint-staged v10).\n   ```json\n   {\n     \"lint-staged\": {\n       \"*.{ts,mts}\": [\"eslint --fix\", \"prettier --write\"],\n       \"*.{js,mjs,cjs}\": [\"eslint --fix\", \"prettier --write\"],\n       \"*.{json,md,yml,css}\": [\"prettier --write\"]\n     }\n   }\n   ```\n\n### New rules in v2\n\nv2 adds significantly more rules than v1. Expect new lint errors on existing code, particularly from:\n\n- `eslint-plugin-unicorn` (modern JS patterns)\n- `eslint-plugin-sonarjs` (cognitive complexity)\n- `@typescript-eslint` strict type checks (`no-floating-promises`, `explicit-function-return-type`, etc.)\n\nRun `eslint --fix .` to auto-fix what's possible, then address remaining issues manually.\n\n## License\n\nISC\n","readmeFilename":"README.md","_rev":"1-88c9b24f36deb9735b35c15778314c89"}