{"_id":"@7ka/eslint-config","_rev":"6-c17330f072dd9094f3e6f2a5aed34da9","name":"@7ka/eslint-config","dist-tags":{"latest":"0.1.5"},"versions":{"0.1.0":{"name":"@7ka/eslint-config","version":"0.1.0","keywords":["eslint","eslint-config","typescript","react","fsd","feature-sliced"],"license":"MIT","_id":"@7ka/eslint-config@0.1.0","maintainers":[{"name":"npm7ka","email":"npm@7ka.dev"}],"homepage":"https://github.com/7ka-dev/tooling/tree/master/packages/eslint-config","bugs":{"url":"https://github.com/7ka-dev/tooling/issues"},"dist":{"shasum":"8beacf79b5cb54b62f8a6b72936591b667d4dc92","tarball":"https://registry.npmjs.org/@7ka/eslint-config/-/eslint-config-0.1.0.tgz","fileCount":5,"integrity":"sha512-iBhWIixev0Fj8R1ejiKk5x8dRm+PQO5/6vNUA85IlzU9swR/HMbG0huD3liNy/78VwBuOEU2kmmFcN5ceZxXkw==","signatures":[{"sig":"MEUCIQDBZp+0JcCyLzbzS8x3edXJfbB7QTqjpxiEdCj0KQwnuwIgT60vejx20pdBvDiBJ27qQTAk80RmnF0ErtBtsPqjZeI=","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"unpackedSize":15341},"main":"index.js","type":"module","exports":{".":"./index.js","./fsd-light":"./fsd-light.js","./fsd-strict":"./fsd-strict.js"},"gitHead":"bef7767c7929a9d3950702c2646bf0c448e06c7b","_npmUser":{"name":"npm7ka","email":"npm@7ka.dev"},"repository":{"url":"git+https://github.com/7ka-dev/tooling.git","type":"git","directory":"packages/eslint-config"},"_npmVersion":"10.8.3","description":"Strict ESLint flat config for TypeScript + React + FSD projects","directories":{},"_nodeVersion":"24.11.1","publishConfig":{"access":"public"},"_hasShrinkwrap":false,"peerDependencies":{"eslint":">=9.0.0","typescript-eslint":">=8.0.0","eslint-plugin-import":">=2.0.0","eslint-plugin-unicorn":">=55.0.0","eslint-plugin-boundaries":">=4.0.0","eslint-plugin-react-hooks":">=5.0.0","eslint-plugin-react-refresh":">=0.4.0"},"_npmOperationalInternal":{"tmp":"tmp/eslint-config_0.1.0_1773211189157_0.4435471260412127","host":"s3://npm-registry-packages-npm-production"}},"0.1.1":{"name":"@7ka/eslint-config","version":"0.1.1","keywords":["eslint","eslint-config","typescript","react","fsd","feature-sliced"],"license":"MIT","_id":"@7ka/eslint-config@0.1.1","maintainers":[{"name":"npm7ka","email":"npm@7ka.dev"}],"homepage":"https://github.com/7ka-dev/tooling/tree/master/packages/eslint-config","bugs":{"url":"https://github.com/7ka-dev/tooling/issues"},"dist":{"shasum":"0dcda980cc9b887b3516922fcc6b1f1546db6bc0","tarball":"https://registry.npmjs.org/@7ka/eslint-config/-/eslint-config-0.1.1.tgz","fileCount":5,"integrity":"sha512-ESuK/EUAPmHH1m/XkE0pziuVu6Q7baKaYQCrH7cuSkbW1C/pVjycsLMdrWNLST6lK2T0pOyPlZY21ZDqXAl9WQ==","signatures":[{"sig":"MEUCIQCa1CC2lRGaPI/1bXm1PwDHWz84qCDNjoxQNiMmWlKqagIgUf/9oWDKvNROsiTM45QQW+qa+CSTAmK1ZTJ2KA4h4NI=","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"unpackedSize":15294},"main":"index.js","type":"module","exports":{".":"./index.js","./fsd-light":"./fsd-light.js","./fsd-strict":"./fsd-strict.js"},"gitHead":"03ef3b981f41b560e8255023e10e19b1ac09e67b","_npmUser":{"name":"npm7ka","email":"npm@7ka.dev"},"repository":{"url":"git+https://github.com/7ka-dev/tooling.git","type":"git","directory":"packages/eslint-config"},"_npmVersion":"10.8.3","description":"Strict ESLint flat config for TypeScript + React + FSD projects","directories":{},"_nodeVersion":"24.11.1","publishConfig":{"access":"public"},"_hasShrinkwrap":false,"peerDependencies":{"eslint":">=9.0.0","typescript-eslint":">=8.0.0","eslint-plugin-import":">=2.0.0","eslint-plugin-unicorn":">=55.0.0","eslint-plugin-boundaries":">=4.0.0","eslint-plugin-react-hooks":">=5.0.0","eslint-plugin-react-refresh":">=0.4.0"},"_npmOperationalInternal":{"tmp":"tmp/eslint-config_0.1.1_1773213566858_0.056280640621281464","host":"s3://npm-registry-packages-npm-production"}},"0.1.2":{"name":"@7ka/eslint-config","version":"0.1.2","keywords":["eslint","eslint-config","typescript","react","fsd","feature-sliced"],"license":"MIT","_id":"@7ka/eslint-config@0.1.2","maintainers":[{"name":"npm7ka","email":"npm@7ka.dev"}],"homepage":"https://github.com/7ka-dev/tooling/tree/master/packages/eslint-config","bugs":{"url":"https://github.com/7ka-dev/tooling/issues"},"dist":{"shasum":"79fc8a9a4a4739275ebf25c5115f09dd99c2373e","tarball":"https://registry.npmjs.org/@7ka/eslint-config/-/eslint-config-0.1.2.tgz","fileCount":6,"integrity":"sha512-Zcgtcy5472dsQlI3gYu+DoFJYgNljquWNeKRe4fOQPEyYCW8gSJF3kRLp1ZakhhVaSiCjRyiDMXegqJMcAuulQ==","signatures":[{"sig":"MEUCIQC5Q5vWkhkTY6X10xQuaFiYHopv3PtYdzGnDWIMCbAWEgIgDxmrh7Wd8qlrVVieopTTSx7N+/QiNF6IsA3RaLJM7vo=","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"unpackedSize":15339},"main":"index.js","type":"module","types":"index.d.ts","exports":{".":"./index.js","./fsd-light":"./fsd-light.js","./fsd-strict":"./fsd-strict.js"},"gitHead":"78bf7139b702b4914b1ea5fad26a980b1363ea99","_npmUser":{"name":"npm7ka","email":"npm@7ka.dev"},"repository":{"url":"git+https://github.com/7ka-dev/tooling.git","type":"git","directory":"packages/eslint-config"},"_npmVersion":"10.8.3","description":"Strict ESLint flat config for TypeScript + React + FSD projects","directories":{},"_nodeVersion":"24.11.1","publishConfig":{"access":"public"},"_hasShrinkwrap":false,"peerDependencies":{"eslint":">=9.0.0","typescript-eslint":">=8.0.0","eslint-plugin-import":">=2.0.0","eslint-plugin-unicorn":">=55.0.0","eslint-plugin-boundaries":">=4.0.0","eslint-plugin-react-hooks":">=5.0.0","eslint-plugin-react-refresh":">=0.4.0"},"_npmOperationalInternal":{"tmp":"tmp/eslint-config_0.1.2_1773223285905_0.4834399050235396","host":"s3://npm-registry-packages-npm-production"}},"0.1.3":{"name":"@7ka/eslint-config","version":"0.1.3","keywords":["eslint","eslint-config","typescript","react","fsd","feature-sliced"],"license":"MIT","_id":"@7ka/eslint-config@0.1.3","maintainers":[{"name":"npm7ka","email":"npm@7ka.dev"}],"homepage":"https://github.com/7ka-dev/tooling/tree/master/packages/eslint-config","bugs":{"url":"https://github.com/7ka-dev/tooling/issues"},"dist":{"shasum":"ac57845b9e786b9052ed3dc5dab3957509d9da9f","tarball":"https://registry.npmjs.org/@7ka/eslint-config/-/eslint-config-0.1.3.tgz","fileCount":6,"integrity":"sha512-5VxNarG09wAxsB+bjGhMl6wgqtrjneucrB6XErMNOCD/e+ebLGXvwE5ZuaSvj1Q6Cgxaf1u4Y6HQ6CW5yd1PvA==","signatures":[{"sig":"MEYCIQCmpEvIyJeJHdrTbjPoDNcKM9PJVCjDiL+JMJlhcstDEAIhAKqL+7hZgPtEUbJI1KGaznXqzgtd4PSVJDlEJflsNHzN","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"unpackedSize":15439},"main":"index.js","type":"module","types":"index.d.ts","exports":{".":"./index.js","./fsd-light":"./fsd-light.js","./fsd-strict":"./fsd-strict.js"},"gitHead":"ba6d7c25c2079492ee095976905631fd36a3f5e0","_npmUser":{"name":"npm7ka","email":"npm@7ka.dev"},"repository":{"url":"git+https://github.com/7ka-dev/tooling.git","type":"git","directory":"packages/eslint-config"},"_npmVersion":"10.8.3","description":"Strict ESLint flat config for TypeScript + React + FSD projects","directories":{},"_nodeVersion":"24.11.1","publishConfig":{"access":"public"},"_hasShrinkwrap":false,"peerDependencies":{"eslint":">=9.0.0","typescript-eslint":">=8.0.0","eslint-plugin-import":">=2.0.0","eslint-plugin-unicorn":">=55.0.0","eslint-plugin-boundaries":">=4.0.0","eslint-plugin-react-hooks":">=5.0.0","eslint-plugin-react-refresh":">=0.4.0"},"_npmOperationalInternal":{"tmp":"tmp/eslint-config_0.1.3_1773224194091_0.49076750956208093","host":"s3://npm-registry-packages-npm-production"}},"0.1.4":{"name":"@7ka/eslint-config","version":"0.1.4","keywords":["eslint","eslint-config","typescript","react","fsd","feature-sliced"],"license":"MIT","_id":"@7ka/eslint-config@0.1.4","maintainers":[{"name":"npm7ka","email":"npm@7ka.dev"}],"homepage":"https://github.com/7ka-dev/tooling/tree/master/packages/eslint-config","bugs":{"url":"https://github.com/7ka-dev/tooling/issues"},"dist":{"shasum":"67d18687c95524cb7ab984d0e8901d0c241ea1f9","tarball":"https://registry.npmjs.org/@7ka/eslint-config/-/eslint-config-0.1.4.tgz","fileCount":8,"integrity":"sha512-i1nAs1jUDmvZ7syh9OoVf/FxrPkqrVSSiC5xzZuUTYEktmtoboTPz+c5pMD6RIhYeQhBkB4pq+JqkFSj9CrCMw==","signatures":[{"sig":"MEUCIQCayfqFRn/DvF3aDUF3tDCCTCigIqeXY4bwKtDE2Hf99wIgQqAEG+CToRHxIyN8UUVa8hBmTW9qVR2jbzbW+vYZoKA=","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"unpackedSize":15872},"main":"index.js","type":"module","types":"index.d.ts","exports":{".":{"types":"./index.d.ts","default":"./index.js"},"./fsd-light":{"types":"./fsd-light.d.ts","default":"./fsd-light.js"},"./fsd-strict":{"types":"./fsd-strict.d.ts","default":"./fsd-strict.js"}},"gitHead":"36de36f53936ef6ed0ea4d115c4cd80c7ae8e598","_npmUser":{"name":"npm7ka","email":"npm@7ka.dev"},"repository":{"url":"git+https://github.com/7ka-dev/tooling.git","type":"git","directory":"packages/eslint-config"},"_npmVersion":"10.8.3","description":"Strict ESLint flat config for TypeScript + React + FSD projects","directories":{},"_nodeVersion":"24.11.1","publishConfig":{"access":"public"},"_hasShrinkwrap":false,"peerDependencies":{"eslint":">=9.0.0","typescript-eslint":">=8.0.0","eslint-plugin-import":">=2.0.0","eslint-plugin-unicorn":">=55.0.0","eslint-plugin-boundaries":">=4.0.0","eslint-plugin-react-hooks":">=5.0.0","eslint-plugin-react-refresh":">=0.4.0"},"_npmOperationalInternal":{"tmp":"tmp/eslint-config_0.1.4_1773226028182_0.4817846875279723","host":"s3://npm-registry-packages-npm-production"}},"0.1.5":{"name":"@7ka/eslint-config","version":"0.1.5","description":"Strict ESLint flat config for TypeScript + React + FSD projects","type":"module","main":"index.js","exports":{".":{"types":"./index.d.ts","default":"./index.js"},"./fsd-strict":{"types":"./fsd-strict.d.ts","default":"./fsd-strict.js"},"./fsd-light":{"types":"./fsd-light.d.ts","default":"./fsd-light.js"}},"types":"index.d.ts","publishConfig":{"access":"public"},"license":"MIT","keywords":["eslint","eslint-config","typescript","react","fsd","feature-sliced"],"repository":{"type":"git","url":"git+https://github.com/7ka-dev/tooling.git","directory":"packages/eslint-config"},"homepage":"https://github.com/7ka-dev/tooling/tree/master/packages/eslint-config","peerDependencies":{"eslint":">=9.0.0","typescript-eslint":">=8.0.0","eslint-plugin-react-hooks":">=5.0.0","eslint-plugin-react-refresh":">=0.4.0","eslint-plugin-import":">=2.0.0","eslint-plugin-unicorn":">=55.0.0","eslint-plugin-boundaries":">=4.0.0"},"_id":"@7ka/eslint-config@0.1.5","gitHead":"6e35e728cc4428bca1bf7f424bbd77f5364f3b70","bugs":{"url":"https://github.com/7ka-dev/tooling/issues"},"_nodeVersion":"24.11.1","_npmVersion":"10.8.3","dist":{"integrity":"sha512-yv0kN4PxMio1HnEcr34IgQop1nOfL7AQDklwJEgjionKm/7LFg6Ou6P/T3aGS+OnC2/Ltv/O/7VxbSZ9eN8HVw==","shasum":"76a91aa96085ec1d4adcd879e74a42c5d0f1aa9a","tarball":"https://registry.npmjs.org/@7ka/eslint-config/-/eslint-config-0.1.5.tgz","fileCount":8,"unpackedSize":16089,"signatures":[{"keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U","sig":"MEYCIQCtr+kHc+ztPfEu01mAjC6bSWmQZm4Wh16bgMqABH52egIhAJzqkl46YlTDNyRuZ3B+896qOtlMGi2PgE3EzFucaovE"}]},"_npmUser":{"name":"npm7ka","email":"npm@7ka.dev"},"directories":{},"maintainers":[{"name":"npm7ka","email":"npm@7ka.dev"}],"_npmOperationalInternal":{"host":"s3://npm-registry-packages-npm-production","tmp":"tmp/eslint-config_0.1.5_1773226947230_0.17466052798922993"},"_hasShrinkwrap":false}},"time":{"created":"2026-03-11T06:39:49.097Z","modified":"2026-03-11T11:02:27.503Z","0.1.0":"2026-03-11T06:39:49.380Z","0.1.1":"2026-03-11T07:19:27.014Z","0.1.2":"2026-03-11T10:01:26.059Z","0.1.3":"2026-03-11T10:16:34.263Z","0.1.4":"2026-03-11T10:47:08.302Z","0.1.5":"2026-03-11T11:02:27.367Z"},"bugs":{"url":"https://github.com/7ka-dev/tooling/issues"},"license":"MIT","homepage":"https://github.com/7ka-dev/tooling/tree/master/packages/eslint-config","keywords":["eslint","eslint-config","typescript","react","fsd","feature-sliced"],"repository":{"type":"git","url":"git+https://github.com/7ka-dev/tooling.git","directory":"packages/eslint-config"},"description":"Strict ESLint flat config for TypeScript + React + FSD projects","maintainers":[{"name":"npm7ka","email":"npm@7ka.dev"}],"readme":"# @7ka/eslint-config\r\n\r\nShared ESLint flat config for 7ka collective projects. Built for strict TypeScript + React + FSD codebases.\r\n\r\n---\r\n\r\n## Install\r\n\r\n```bash\r\nnpm install -D @7ka/eslint-config \\\r\n  eslint \\\r\n  typescript-eslint \\\r\n  eslint-plugin-react-hooks \\\r\n  eslint-plugin-react-refresh \\\r\n  eslint-plugin-import \\\r\n  eslint-plugin-unicorn \\\r\n  @feature-sliced/eslint-config\r\n```\r\n\r\n---\r\n\r\n## Usage\r\n\r\n### Base (no FSD)\r\n```ts\r\n// eslint.config.ts\r\nimport config from '@7ka/eslint-config'\r\nexport default config\r\n```\r\n\r\n### Strict FSD\r\n```ts\r\nimport config from '@7ka/eslint-config/fsd-strict'\r\nexport default config\r\n```\r\n\r\n### Light FSD\r\n```ts\r\nimport config from '@7ka/eslint-config/fsd-light'\r\nexport default config\r\n```\r\n\r\n---\r\n\r\n## Rules\r\n\r\n### TypeScript\r\n\r\n---\r\n\r\n#### `consistent-type-imports`\r\nForces `import type` when importing only a type. Type-only imports are stripped at compile time — faster builds, cleaner output, signals to readers that the import disappears at runtime.\r\n\r\n```ts\r\n// bad\r\nimport { User } from './types'\r\n\r\n// good\r\nimport type { User } from './types'\r\n```\r\n\r\n---\r\n\r\n#### `no-explicit-any`\r\nBans `any` as a type. Forces you to properly type values or use `unknown` when the shape is genuinely unknown.\r\n\r\n```ts\r\n// bad\r\nfunction parse(data: any): any {\r\n  return data.value\r\n}\r\n\r\n// good\r\nfunction parse(data: unknown): string {\r\n  if (typeof data === 'object' && data !== null && 'value' in data) {\r\n    return String(data.value)\r\n  }\r\n  throw new Error('Invalid data shape')\r\n}\r\n```\r\n\r\n---\r\n\r\n#### `no-unused-vars`\r\nErrors on variables, imports, or arguments that are declared but never used. Prefix with `_` to explicitly mark something as intentionally unused.\r\n\r\n```ts\r\n// bad\r\nimport { useEffect, useState } from 'react'\r\n// useState imported but never used\r\n\r\n// good — remove unused import\r\nimport { useEffect } from 'react'\r\n\r\n// good — underscore prefix for intentionally unused args\r\nconst handler = (_event: MouseEvent, value: string): void => {\r\n  console.warn(value)\r\n}\r\n```\r\n\r\n---\r\n\r\n#### `no-floating-promises`\r\nErrors when a Promise is not awaited or handled with `.catch()`. Unhandled promises fail silently.\r\n\r\n```ts\r\n// bad\r\nfunction loadData(): void {\r\n  fetchUser() // promise result ignored, errors swallowed\r\n}\r\n\r\n// good\r\nasync function loadData(): Promise<void> {\r\n  await fetchUser()\r\n}\r\n\r\n// also good\r\nvoid fetchUser().catch(console.error)\r\n```\r\n\r\n---\r\n\r\n#### `no-unsafe-assignment`\r\nErrors when a value typed as `any` is assigned to a variable. Prevents `any` from spreading through the codebase from third-party boundaries.\r\n\r\n```ts\r\n// bad\r\nconst data = JSON.parse(response) // JSON.parse returns any\r\nconst name = data.name            // name is now silently any\r\n\r\n// good\r\nconst raw: unknown = JSON.parse(response)\r\n// TypeScript now forces you to validate before using\r\n```\r\n\r\n---\r\n\r\n#### `no-misused-promises`\r\nErrors when a Promise is used where a non-Promise is expected — most commonly async callbacks passed to event handlers that don't await them.\r\n\r\n```ts\r\n// bad\r\n<button onClick={async () => {\r\n  await saveData() // onClick doesn't await — errors are swallowed\r\n}} />\r\n\r\n// good\r\nconst handleClick = (): void => {\r\n  void saveData().catch(console.error)\r\n}\r\n<button onClick={handleClick} />\r\n```\r\n\r\n---\r\n\r\n#### `explicit-function-return-type`\r\nForces explicit return type annotations on all functions. No accidental `any` returns, and readers know immediately what a function produces.\r\n\r\n```ts\r\n// bad\r\nfunction getUser(id: string) {\r\n  return users.find(u => u.id === id)\r\n}\r\n\r\n// good\r\nfunction getUser(id: string): User | undefined {\r\n  return users.find(u => u.id === id)\r\n}\r\n```\r\n\r\n---\r\n\r\n#### `naming-convention`\r\nEnforces consistent naming patterns across the codebase.\r\n\r\n| Selector | Format | Example |\r\n|---|---|---|\r\n| Types / Interfaces | `PascalCase` | `UserProfile`, `ApiResponse` |\r\n| Variables | `camelCase` or `UPPER_CASE` | `userName`, `MAX_RETRIES` |\r\n| Functions | `camelCase` or `PascalCase` | `getUser`, `UserCard` |\r\n| React components | `PascalCase` | `ProfilePage`, `AuthButton` |\r\n\r\n```ts\r\n// bad\r\ninterface user_profile { name: string }\r\nconst Max_Retries = 3\r\nfunction get_user(): User { ... }\r\n\r\n// good\r\ninterface UserProfile { name: string }\r\nconst MAX_RETRIES = 3\r\nfunction getUser(): User { ... }\r\n```\r\n\r\n---\r\n\r\n### General JavaScript\r\n\r\n---\r\n\r\n#### `no-console`\r\nWarns on `console.log`. Allows `console.warn` and `console.error` since those are intentional. Prevents debug leftovers reaching production.\r\n\r\n```ts\r\n// warned\r\nconsole.log('user loaded', user)\r\n\r\n// allowed\r\nconsole.warn('Deprecated method called')\r\nconsole.error('Failed to fetch user', error)\r\n```\r\n\r\n---\r\n\r\n#### `no-magic-numbers`\r\nBans raw numbers in logic. Forces named constants so intent is clear. `0`, `1`, and `-1` are allowed as common neutral values.\r\n\r\n```ts\r\n// bad\r\nif (response.status === 403) { ... }\r\nsetTimeout(sync, 86400000)\r\n\r\n// good\r\nconst FORBIDDEN = 403\r\nconst ONE_DAY_MS = 86_400_000\r\n\r\nif (response.status === FORBIDDEN) { ... }\r\nsetTimeout(sync, ONE_DAY_MS)\r\n```\r\n\r\n---\r\n\r\n#### `eqeqeq`\r\nForces `===` instead of `==`. Prevents silent type coercion bugs.\r\n\r\n```ts\r\n// bad — all of these are true with ==\r\n0 == false\r\n'' == false\r\nnull == undefined\r\n'1' == 1\r\n\r\n// good\r\nvalue === null\r\ncount === 0\r\n```\r\n\r\n---\r\n\r\n#### `prefer-const`\r\nForces `const` when a variable is never reassigned. Signals intent — `let` implies mutation is coming.\r\n\r\n```ts\r\n// bad\r\nlet userId = getUserId() // never reassigned below\r\n\r\n// good\r\nconst userId = getUserId()\r\n```\r\n\r\n---\r\n\r\n#### `no-var`\r\nBans `var` entirely. `var` is function-scoped and hoisted — a source of subtle bugs. `let` and `const` are block-scoped and predictable.\r\n\r\n```ts\r\n// bad\r\nvar count = 0\r\n\r\n// good\r\nlet count = 0\r\nconst MAX = 10\r\n```\r\n\r\n---\r\n\r\n### React Hooks\r\n\r\n---\r\n\r\n#### `react-hooks/rules-of-hooks`\r\nEnforces the Rules of Hooks. Hooks must be called at the top level — never inside conditions, loops, or nested functions. React relies on hook call order being stable between renders.\r\n\r\n```tsx\r\n// bad\r\nfunction Component({ isAdmin }: Props): JSX.Element {\r\n  if (isAdmin) {\r\n    const [data, setData] = useState(null) // conditional hook\r\n  }\r\n}\r\n\r\n// good\r\nfunction Component({ isAdmin }: Props): JSX.Element {\r\n  const [data, setData] = useState(null)\r\n  if (!isAdmin) return <AccessDenied />\r\n  ...\r\n}\r\n```\r\n\r\n---\r\n\r\n#### `react-hooks/exhaustive-deps`\r\nWarns when `useEffect`, `useCallback`, or `useMemo` has missing dependencies. Missing deps cause stale closures — the effect runs but sees old values.\r\n\r\n```tsx\r\n// bad — userId missing from deps, effect uses stale value\r\nuseEffect(() => {\r\n  fetchUser(userId)\r\n}, [])\r\n\r\n// good\r\nuseEffect(() => {\r\n  void fetchUser(userId)\r\n}, [userId])\r\n```\r\n\r\n---\r\n\r\n### Imports\r\n\r\n---\r\n\r\n#### `import/order`\r\nEnforces consistent import ordering. Groups are separated by a blank line.\r\n\r\nOrder:\r\n1. Node built-ins (`path`, `fs`)\r\n2. External packages (`react`, `effector`)\r\n3. Internal / FSD layers (`@/shared`, `@/entities`)\r\n4. Parent imports (`../foo`)\r\n5. Sibling imports (`./bar`)\r\n6. Index imports (`./`)\r\n\r\n```ts\r\n// bad\r\nimport { useState } from 'react'\r\nimport path from 'path'\r\nimport { UserCard } from './UserCard'\r\nimport type { User } from '@/entities/user'\r\n\r\n// good\r\nimport path from 'path'\r\nimport { useState } from 'react'\r\nimport type { User } from '@/entities/user'\r\nimport { UserCard } from './UserCard'\r\n```\r\n\r\n---\r\n\r\n### Unicorn\r\n\r\n---\r\n\r\n#### `unicorn/prefer-early-return`\r\nForces early returns instead of deeply nested `if` blocks. Flatter code is easier to read and reason about.\r\n\r\n```ts\r\n// bad\r\nfunction processUser(user: User | undefined): string {\r\n  if (user) {\r\n    if (user.isActive) {\r\n      return user.name\r\n    }\r\n  }\r\n  return 'unknown'\r\n}\r\n\r\n// good\r\nfunction processUser(user: User | undefined): string {\r\n  if (!user) return 'unknown'\r\n  if (!user.isActive) return 'unknown'\r\n  return user.name\r\n}\r\n```\r\n\r\n---\r\n\r\n#### `unicorn/no-array-for-each`\r\nForces `for...of` instead of `.forEach()`. `for...of` supports `break`, `continue`, and `await` — `.forEach` does not.\r\n\r\n```ts\r\n// bad\r\nusers.forEach(user => {\r\n  processUser(user)\r\n})\r\n\r\n// good\r\nfor (const user of users) {\r\n  processUser(user)\r\n}\r\n```\r\n\r\n---\r\n\r\n#### `unicorn/prefer-query-selector`\r\nForces `querySelector` / `querySelectorAll` over older DOM methods. Consistent, composable, works with any CSS selector.\r\n\r\n```ts\r\n// bad\r\ndocument.getElementById('app')\r\ndocument.getElementsByClassName('card')\r\n\r\n// good\r\ndocument.querySelector('#app')\r\ndocument.querySelectorAll('.card')\r\n```\r\n\r\n---\r\n\r\n### FSD Layer Boundaries\r\n\r\nEnforced in `fsd-strict` and `fsd-light` variants only.\r\n\r\nLayers can only import from layers **below** them. Cross-layer upward imports are banned.\r\n\r\n```\r\napp → pages → widgets → features → entities → shared\r\n```\r\n\r\n```ts\r\n// bad — features importing from pages (upward)\r\n// src/features/auth/model.ts\r\nimport { HomePage } from '@/pages/home'\r\n\r\n// bad — entities importing from features (upward)\r\n// src/entities/user/model.ts\r\nimport { loginFeature } from '@/features/auth'\r\n\r\n// good — features importing from entities (downward)\r\n// src/features/auth/model.ts\r\nimport type { User } from '@/entities/user'\r\n```\r\n\r\n**Light FSD** omits `widgets` and `entities` — suitable for smaller projects:\r\n```\r\napp → pages → features → shared\r\n```","readmeFilename":"README.md"}