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

eslint-plugin-flexium

v0.17.2

Published

ESLint plugin for Flexium with rules for best practices

Readme

eslint-plugin-flexium

ESLint plugin for Flexium with rules for best practices and common pitfalls.

Installation

npm install eslint-plugin-flexium --save-dev

Usage

Add flexium to the plugins section of your .eslintrc configuration file:

{
  "plugins": ["flexium"],
  "extends": ["plugin:flexium/recommended"]
}

Or configure rules individually:

{
  "plugins": ["flexium"],
  "rules": {
    "flexium/no-signal-outside-reactive": "warn",
    "flexium/effect-cleanup": "warn",
    "flexium/no-side-effect-in-computed": "error",
    "flexium/prefer-sync": "off",
    "flexium/no-signal-mutation": "warn",
    "flexium/no-effect-in-render": "error",
    "flexium/no-circular-dependency": "error",
    "flexium/component-naming": "warn",
    "flexium/no-signal-reassignment": "error",
    "flexium/no-state-comparison": "error"
  }
}

Configurations

| Configuration | Description | |--------------|-------------| | recommended | Balanced rules for most projects | | strict | Stricter rules for production code | | all | Enable all rules as errors |

Rules

flexium/no-signal-outside-reactive

Disallow reading state values outside of reactive contexts.

Why? State reads outside of use() or JSX will not be tracked and won't trigger re-renders.

// ❌ Bad - state read outside reactive context
const [count, setCount] = use(0)
if (count > 5) {
  doSomething()
}

// ✅ Good - state read inside effect
use(({ onCleanup }) => {
  if (count > 5) {
    doSomething()
  }
}, [count])

// ✅ Good - state read inside JSX
const App = () => <div>{count}</div>

flexium/effect-cleanup

Enforce cleanup functions in effects that add event listeners or timers.

Why? Effects that add event listeners or timers without cleanup can cause memory leaks.

// ❌ Bad - no cleanup for event listener
use(({ onCleanup }) => {
  window.addEventListener('resize', handleResize)
}, [])

// ✅ Good - uses onCleanup
use(({ onCleanup }) => {
  window.addEventListener('resize', handleResize)
  onCleanup(() => window.removeEventListener('resize', handleResize))
}, [])

flexium/no-side-effect-in-computed

Disallow side effects in computed state functions.

Why? Computed values should be pure functions. Side effects belong in use().

const [count, setCount] = use(0)

// ❌ Bad - side effect in computed
const [doubled] = use(() => {
  console.log('Computing...')  // Side effect!
  return count * 2
}, [count])

// ✅ Good - pure computed
const [doubled] = use(() => count * 2, [count])

// ✅ Good - side effect in effect
use(({ onCleanup }) => {
  console.log('Count changed:', count)
}, [count])

flexium/prefer-sync

Suggest using sync() when multiple state updates occur consecutively.

Why? Multiple state updates are auto-batched via microtask, but sync() provides explicit synchronous batching when needed.

import { use, sync } from 'flexium/core'

const [count, setCount] = use(0)
const [name, setName] = use('')
const [active, setActive] = use(false)

// ⚠️ Auto-batched (microtask), but may want explicit control
setCount(1)
setName('test')
setActive(true)

// ✅ Good - explicit synchronous batching
sync(() => {
  setCount(1)
  setName('test')
  setActive(true)
})

flexium/no-signal-mutation

Warn about direct object/array mutations in state.

Why? State containing objects or arrays should be updated immutably. Direct mutations won't trigger reactivity updates.

const [items, setItems] = use([1, 2, 3])

// ❌ Bad - direct mutation (won't trigger updates)
items.push(4)
items[0] = 10

// ✅ Good - immutable updates via setter
setItems(prev => [...prev, 4])
setItems(prev => prev.map((item, i) => i === 0 ? 10 : item))

// For objects
const [user, setUser] = use({ name: 'John', age: 30 })

// ❌ Bad
user.age = 31

// ✅ Good
setUser(prev => ({ ...prev, age: 31 }))

flexium/no-effect-in-render

Prevent calling use() in component render body without proper scoping.

Why? Effects created during every render can cause performance issues and unexpected behavior.

// ❌ Bad - effect created on every render without deps
const MyComponent = () => {
  use(({ onCleanup }) => {
    console.log('This runs on every render!')
  })

  return <div>Hello</div>
}

// ✅ Good - effect with empty deps (runs once)
const MyComponent = () => {
  use(({ onCleanup }) => {
    console.log('This runs once on mount')
  }, [])

  return <div>Hello</div>
}

flexium/no-circular-dependency

Detect circular dependencies between computed states.

Why? Circular dependencies create infinite loops and will crash your application.

// ❌ Bad - circular dependency
const [a] = use(() => b + 1, [b])
const [b] = use(() => a + 1, [a]) // Creates infinite loop!

// ✅ Good - no circular dependencies
const [count, setCount] = use(0)
const [doubled] = use(() => count * 2, [count])
const [quadrupled] = use(() => doubled * 2, [doubled])

flexium/component-naming

Enforce PascalCase naming convention for components.

Why? JSX conventions expect components to use PascalCase to distinguish them from HTML elements.

// ❌ Bad - component names should be PascalCase
const myComponent = () => <div>Hello</div>
const user_profile = () => <div>Profile</div>

// ✅ Good - PascalCase component names
const MyComponent = () => <div>Hello</div>
const UserProfile = () => <div>Profile</div>

flexium/no-signal-reassignment

Prevent reassigning state variables.

Why? State variables should be updated via their setter function, not reassigned.

const [count, setCount] = use(0)

// ❌ Bad - reassigning state variable
count = 5

// ✅ Good - use setter
setCount(5)

flexium/no-state-comparison

Warn about comparing state values with === or !==.

Why? State values are Proxy-wrapped and may not compare as expected with strict equality.

const [count, setCount] = use(0)

// ⚠️ Warning - comparing proxied state
if (count === 0) { }

// ✅ Good - use Number() or compare with primitives
if (Number(count) === 0) { }
if (count == 0) { }  // loose equality works

flexium/no-missing-dependencies

Warn when computed state or effects reference reactive values not in deps array.

const [a, setA] = use(1)
const [b, setB] = use(2)

// ⚠️ Warning - b is used but not in deps
const [sum] = use(() => a + b, [a])

// ✅ Good - all dependencies listed
const [sum] = use(() => a + b, [a, b])

flexium/effect-dependencies-complete

Enforce complete dependency arrays in effects.

const [count, setCount] = use(0)
const [name, setName] = use('')

// ⚠️ Warning - name is used but not in deps
use(({ onCleanup }) => {
  console.log(count, name)
}, [count])

// ✅ Good - all dependencies listed
use(({ onCleanup }) => {
  console.log(count, name)
}, [count, name])

flexium/prefer-computed

Suggest using computed state instead of effect for derived values.

const [count, setCount] = use(0)
const [doubled, setDoubled] = use(0)

// ⚠️ Warning - prefer computed for derived values
use(({ onCleanup }) => {
  setDoubled(count * 2)
}, [count])

// ✅ Good - use computed state
const [doubled] = use(() => count * 2, [count])

Rule Severity by Configuration

| Rule | recommended | strict | all | |------|-------------|--------|-----| | no-signal-outside-reactive | warn | error | error | | effect-cleanup | warn | error | error | | no-side-effect-in-computed | error | error | error | | prefer-sync | off | warn | error | | no-missing-dependencies | warn | error | error | | effect-dependencies-complete | warn | error | error | | no-signal-mutation | warn | error | error | | no-effect-in-render | error | error | error | | prefer-computed | off | warn | error | | no-circular-dependency | error | error | error | | component-naming | warn | error | error | | no-signal-reassignment | error | error | error | | no-state-comparison | error | error | error |

License

MIT