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-enforce-call

v0.4.0

Published

ESLint plugin to enforce function calls within specific function contexts

Readme

eslint-plugin-enforce-call

[!NOTE] This plugin was built using AI however everything has been tested and verified manually.

ESLint plugin to enforce specific function calls within callback arguments of designated context functions.

Installation

pnpm add -D eslint-plugin-enforce-call

Usage

ESLint Flat Config (ESLint 9+)

import enforceCall from 'eslint-plugin-enforce-call'

export default [
  {
    plugins: {
      'enforce-call': enforceCall
    },
    rules: {
      'enforce-call/require-call-in-context': ['error', {
        check: ['query', 'query.batch', 'command'],
        enforce: ['hasPermission', 'isAuthenticated'],
        requireAll: false
      }]
    }
  }
]

Rule: require-call-in-context

Enforces that specific functions are called within callback arguments of designated context functions or within exported named functions. Useful for ensuring security checks like hasPermission() or isAuthenticated() are present in API handlers, database queries, or other critical operations.

Options

  • check (array of strings, optional): Function names to monitor for callback arguments
  • checkFunctions (array of strings, optional): Exported function names to check directly
  • enforce (array of strings, required): Function names that must be called within those callbacks/functions
  • requireAll (boolean, optional, default: false):
    • false: At least one enforced function must be called
    • true: All enforced functions must be called

At least one of check or checkFunctions should be provided.

Examples

Valid ✓

// Callback with enforced call
query(() => {
  hasPermission()
})

// Member expression context
query.batch(() => {
  isAuthenticated()
})

// Multiple arguments
query(z.string(), () => {
  hasPermission('read')
})

// Empty callbacks are allowed
query(() => {})

// Expression-body arrow function
query(() => hasPermission())

Invalid ✗

// No enforced call
query(() => {
  console.log('test')
})

// Wrong function called
query.batch(() => {
  foo()
})

// Code present but no enforced call
query(z.string(), () => {
  const num = 2 + 2
})

// Commented out doesn't count
query(() => {
  // hasPermission()
})

// Function reference without invocation
query(() => {
  hasPermission
})

Checking Exported Functions

Use checkFunctions to enforce calls within exported named functions (useful for SvelteKit load functions, Next.js API routes, etc.):

// eslint.config.js
export default [
  {
    plugins: {
      'enforce-call': enforceCall
    },
    rules: {
      'enforce-call/require-call-in-context': ['error', {
        checkFunctions: ['load'],
        enforce: ['hasPermission']
      }]
    }
  }
]

Valid ✓

// Exported function with enforced call
export const load = () => {
  hasPermission()
}

// Function declaration
export function load() {
  hasPermission()
}

// Async function
export const load = async () => {
  await hasPermission()
}

// Namespace imports work too
import * as permissions from 'permissions'
export const load = () => {
  permissions.hasPermission()
}

// Empty functions are allowed
export const load = () => {}

// Non-exported functions are not checked
const load = () => {
  console.log('not checked')
}

Invalid ✗

// No enforced call
export const load = () => {
  console.log('test')
}

// Missing enforced call
export function load() {
  fetchData()
}

Checking Exported Objects with Functions

When checkFunctions matches an exported object, all function properties within that object are checked. This is useful for SvelteKit form actions:

// eslint.config.js
export default [
  {
    plugins: {
      'enforce-call': enforceCall
    },
    rules: {
      'enforce-call/require-call-in-context': ['error', {
        checkFunctions: ['actions'],
        enforce: ['hasPermission']
      }]
    }
  }
]

Valid ✓

// All functions in the object have enforced calls
export const actions = {
  default: async (event) => {
    hasPermission()
  },
  create: async () => {
    hasPermission()
  }
}

// Method shorthand syntax works too
export const actions = {
  async default() {
    hasPermission()
  }
}

// Empty functions are allowed
export const actions = {
  default: async () => {}
}

// Namespace imports work
import * as permissions from 'permissions'
export const actions = {
  default: async () => {
    permissions.hasPermission()
  }
}

Invalid ✗

// Missing enforced call
export const actions = {
  default: async (event) => {
    console.log('missing hasPermission')
  }
}

// One function missing enforced call (each is checked independently)
export const actions = {
  create: async () => { hasPermission() },  // OK
  update: async () => { console.log('bad') }  // Error
}

Multiple Rule Instances

You can configure multiple instances of the rule for different requirements:

export default [
  {
    plugins: {
      'enforce-call': enforceCall
    },
    rules: {
      // Basic queries need at least one auth check
      'enforce-call/require-call-in-context': ['error', {
        check: ['query', 'query.batch'],
        enforce: ['hasPermission', 'isAuthenticated'],
        requireAll: false
      }]
    }
  },
  {
    files: ['src/admin/**/*.js'],
    rules: {
      // Admin commands need both checks
      'enforce-call/require-call-in-context': ['error', {
        check: ['adminCommand'],
        enforce: ['hasPermission', 'isAuthenticated'],
        requireAll: true
      }]
    }
  }
]

Behavior

What Gets Checked

  • Callback arguments (arrow functions and function expressions) passed to functions in check
  • Exported functions with names matching checkFunctions
  • All function properties within exported objects matching checkFunctions
  • Member expressions like query.batch are treated as distinct from query

What Counts as Valid

  • Non-empty callbacks/functions that contain at least one direct call to an enforced function (when requireAll: false)
  • Non-empty callbacks/functions that contain direct calls to all enforced functions (when requireAll: true)
  • Empty callbacks/functions (no code = no violation)
  • Namespace import calls like permissions.hasPermission() satisfy an enforce: ["hasPermission"] requirement

What Gets Reported

  • Non-empty callbacks/functions without the required enforced function calls
  • Only direct calls within the callback/function body count (not nested in helper functions)

License

MIT