npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2026 – Pkg Stats / Ryan Hefner

@7ka/eslint-config

v0.1.5

Published

Strict ESLint flat config for TypeScript + React + FSD projects

Readme

@7ka/eslint-config

Shared ESLint flat config for 7ka collective projects. Built for strict TypeScript + React + FSD codebases.


Install

npm install -D @7ka/eslint-config \
  eslint \
  typescript-eslint \
  eslint-plugin-react-hooks \
  eslint-plugin-react-refresh \
  eslint-plugin-import \
  eslint-plugin-unicorn \
  @feature-sliced/eslint-config

Usage

Base (no FSD)

// eslint.config.ts
import config from '@7ka/eslint-config'
export default config

Strict FSD

import config from '@7ka/eslint-config/fsd-strict'
export default config

Light FSD

import config from '@7ka/eslint-config/fsd-light'
export default config

Rules

TypeScript


consistent-type-imports

Forces 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.

// bad
import { User } from './types'

// good
import type { User } from './types'

no-explicit-any

Bans any as a type. Forces you to properly type values or use unknown when the shape is genuinely unknown.

// bad
function parse(data: any): any {
  return data.value
}

// good
function parse(data: unknown): string {
  if (typeof data === 'object' && data !== null && 'value' in data) {
    return String(data.value)
  }
  throw new Error('Invalid data shape')
}

no-unused-vars

Errors on variables, imports, or arguments that are declared but never used. Prefix with _ to explicitly mark something as intentionally unused.

// bad
import { useEffect, useState } from 'react'
// useState imported but never used

// good — remove unused import
import { useEffect } from 'react'

// good — underscore prefix for intentionally unused args
const handler = (_event: MouseEvent, value: string): void => {
  console.warn(value)
}

no-floating-promises

Errors when a Promise is not awaited or handled with .catch(). Unhandled promises fail silently.

// bad
function loadData(): void {
  fetchUser() // promise result ignored, errors swallowed
}

// good
async function loadData(): Promise<void> {
  await fetchUser()
}

// also good
void fetchUser().catch(console.error)

no-unsafe-assignment

Errors when a value typed as any is assigned to a variable. Prevents any from spreading through the codebase from third-party boundaries.

// bad
const data = JSON.parse(response) // JSON.parse returns any
const name = data.name            // name is now silently any

// good
const raw: unknown = JSON.parse(response)
// TypeScript now forces you to validate before using

no-misused-promises

Errors when a Promise is used where a non-Promise is expected — most commonly async callbacks passed to event handlers that don't await them.

// bad
<button onClick={async () => {
  await saveData() // onClick doesn't await — errors are swallowed
}} />

// good
const handleClick = (): void => {
  void saveData().catch(console.error)
}
<button onClick={handleClick} />

explicit-function-return-type

Forces explicit return type annotations on all functions. No accidental any returns, and readers know immediately what a function produces.

// bad
function getUser(id: string) {
  return users.find(u => u.id === id)
}

// good
function getUser(id: string): User | undefined {
  return users.find(u => u.id === id)
}

naming-convention

Enforces consistent naming patterns across the codebase.

| Selector | Format | Example | |---|---|---| | Types / Interfaces | PascalCase | UserProfile, ApiResponse | | Variables | camelCase or UPPER_CASE | userName, MAX_RETRIES | | Functions | camelCase or PascalCase | getUser, UserCard | | React components | PascalCase | ProfilePage, AuthButton |

// bad
interface user_profile { name: string }
const Max_Retries = 3
function get_user(): User { ... }

// good
interface UserProfile { name: string }
const MAX_RETRIES = 3
function getUser(): User { ... }

General JavaScript


no-console

Warns on console.log. Allows console.warn and console.error since those are intentional. Prevents debug leftovers reaching production.

// warned
console.log('user loaded', user)

// allowed
console.warn('Deprecated method called')
console.error('Failed to fetch user', error)

no-magic-numbers

Bans raw numbers in logic. Forces named constants so intent is clear. 0, 1, and -1 are allowed as common neutral values.

// bad
if (response.status === 403) { ... }
setTimeout(sync, 86400000)

// good
const FORBIDDEN = 403
const ONE_DAY_MS = 86_400_000

if (response.status === FORBIDDEN) { ... }
setTimeout(sync, ONE_DAY_MS)

eqeqeq

Forces === instead of ==. Prevents silent type coercion bugs.

// bad — all of these are true with ==
0 == false
'' == false
null == undefined
'1' == 1

// good
value === null
count === 0

prefer-const

Forces const when a variable is never reassigned. Signals intent — let implies mutation is coming.

// bad
let userId = getUserId() // never reassigned below

// good
const userId = getUserId()

no-var

Bans var entirely. var is function-scoped and hoisted — a source of subtle bugs. let and const are block-scoped and predictable.

// bad
var count = 0

// good
let count = 0
const MAX = 10

React Hooks


react-hooks/rules-of-hooks

Enforces 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.

// bad
function Component({ isAdmin }: Props): JSX.Element {
  if (isAdmin) {
    const [data, setData] = useState(null) // conditional hook
  }
}

// good
function Component({ isAdmin }: Props): JSX.Element {
  const [data, setData] = useState(null)
  if (!isAdmin) return <AccessDenied />
  ...
}

react-hooks/exhaustive-deps

Warns when useEffect, useCallback, or useMemo has missing dependencies. Missing deps cause stale closures — the effect runs but sees old values.

// bad — userId missing from deps, effect uses stale value
useEffect(() => {
  fetchUser(userId)
}, [])

// good
useEffect(() => {
  void fetchUser(userId)
}, [userId])

Imports


import/order

Enforces consistent import ordering. Groups are separated by a blank line.

Order:

  1. Node built-ins (path, fs)
  2. External packages (react, effector)
  3. Internal / FSD layers (@/shared, @/entities)
  4. Parent imports (../foo)
  5. Sibling imports (./bar)
  6. Index imports (./)
// bad
import { useState } from 'react'
import path from 'path'
import { UserCard } from './UserCard'
import type { User } from '@/entities/user'

// good
import path from 'path'
import { useState } from 'react'
import type { User } from '@/entities/user'
import { UserCard } from './UserCard'

Unicorn


unicorn/prefer-early-return

Forces early returns instead of deeply nested if blocks. Flatter code is easier to read and reason about.

// bad
function processUser(user: User | undefined): string {
  if (user) {
    if (user.isActive) {
      return user.name
    }
  }
  return 'unknown'
}

// good
function processUser(user: User | undefined): string {
  if (!user) return 'unknown'
  if (!user.isActive) return 'unknown'
  return user.name
}

unicorn/no-array-for-each

Forces for...of instead of .forEach(). for...of supports break, continue, and await.forEach does not.

// bad
users.forEach(user => {
  processUser(user)
})

// good
for (const user of users) {
  processUser(user)
}

unicorn/prefer-query-selector

Forces querySelector / querySelectorAll over older DOM methods. Consistent, composable, works with any CSS selector.

// bad
document.getElementById('app')
document.getElementsByClassName('card')

// good
document.querySelector('#app')
document.querySelectorAll('.card')

FSD Layer Boundaries

Enforced in fsd-strict and fsd-light variants only.

Layers can only import from layers below them. Cross-layer upward imports are banned.

app → pages → widgets → features → entities → shared
// bad — features importing from pages (upward)
// src/features/auth/model.ts
import { HomePage } from '@/pages/home'

// bad — entities importing from features (upward)
// src/entities/user/model.ts
import { loginFeature } from '@/features/auth'

// good — features importing from entities (downward)
// src/features/auth/model.ts
import type { User } from '@/entities/user'

Light FSD omits widgets and entities — suitable for smaller projects:

app → pages → features → shared