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

@bemedev/dev-utils

v0.7.0

Published

A collection of utilities for Node.js development, including build tools, testing utilities, and configuration management.

Readme

@bemedev/dev-utils

A collection of utilities for Node.js development, including build tools, testing utilities, and configuration management.

Modules

| Module | Description | | ----------------------------------- | --------------------------------------------- | | vitestAlias | Vitest plugin to inject tsconfig path aliases | | vitestExclude | Vitest plugin for glob-based include/exclude | | vitestExtended | Extended test helpers for Vitest | | rolldownConfig | Rolldown bundler configuration factory | | buildTests | CLI tooling to build and test packages |

Installation

pnpm add @bemedev/dev-utils
# or
npm install @bemedev/dev-utils
# or
yarn add @bemedev/dev-utils

Peer dependencies: typescript ^5 || ^6

Usage

Each module is available as a dedicated sub-path export — there is no root barrel export:

import { createAlias, aliasTs } from '@bemedev/dev-utils/vitest-alias';
import { exclude } from '@bemedev/dev-utils/vitest-exclude';
import {
  createTests,
  createFakeWaiter,
} from '@bemedev/dev-utils/vitest-extended';
import { defineConfig } from '@bemedev/dev-utils/rolldown';
import { addTarball, cleanup } from '@bemedev/dev-utils/build-tests';

vitestAlias

Vitest plugin that reads your tsconfig.json path mappings and injects them as Vitest/Vite aliases — no manual duplication needed.

createAlias(tsconfig?)

Converts compilerOptions.paths (and optional baseUrl) from a tsconfig object into a Vite-compatible alias map.

import tsconfig from './tsconfig.json';
import { createAlias } from '@bemedev/dev-utils/vitest-alias';

// vitest.config.ts
export default defineConfig({
  test: {
    alias: createAlias(tsconfig),
  },
});

Parameters

| Name | Type | Description | | ---------- | --------------------- | --------------------------- | | tsconfig | TsConf \| undefined | Parsed tsconfig JSON object |

Returns Record<string, string> — alias map ready for test.alias.


aliasTs(tsconfig?)

A Vitest/Vite plugin that automatically calls createAlias and merges the result into test.alias.

Note: Make sure "resolveJsonModule": true is set in your compilerOptions, or pass the parsed JSON directly.

import tsconfig from './tsconfig.json';
import { aliasTs } from '@bemedev/dev-utils/vitest-alias';

// vitest.config.ts
export default defineConfig({
  plugins: [aliasTs(tsconfig)],
});

Parameters

| Name | Type | Description | | ---------- | --------------------- | --------------------------- | | tsconfig | TsConf \| undefined | Parsed tsconfig JSON object |

Returns a Vitest Plugin.


vitestExclude

Vitest plugin that uses glob patterns to dynamically build test.include and coverage.include lists — no need to maintain test.exclude manually.

exclude(args?)

Uses default patterns (src/**/*.ts for coverage, src/**/*.{test,spec}.{ts,js,tsx,jsx} for tests) and applies optional ignore lists.

import { exclude } from '@bemedev/dev-utils/vitest-exclude';

// vitest.config.ts
export default defineConfig({
  plugins: [
    exclude({
      ignoreTestFiles: ['src/fixtures/**'],
      ignoreCoverageFiles: ['src/**/*.types.ts'],
    }),
  ],
});

Parameters (args)

| Property | Type | Description | | --------------------- | ----------------------- | -------------------------------------------- | | ignoreTestFiles | string[] \| undefined | Glob patterns to exclude from test discovery | | ignoreCoverageFiles | string[] \| undefined | Glob patterns to exclude from coverage |

Returns a Vitest Plugin.


exclude.withPattern(patterns, args)

Same as exclude, but lets you provide custom glob patterns instead of the defaults.

exclude.withPattern(
  {
    patternTest: 'tests/**/*.test.ts',
    patternCov: 'src/**/*.ts',
  },
  { ignoreTestFiles: ['tests/fixtures/**'] },
);

Parameters

| Name | Type | Description | | ------------- | -------------------- | ----------------------------------- | | patternTest | string \| string[] | Glob(s) for test file discovery | | patternCov | string \| string[] | Glob(s) for coverage file discovery | | args | same as exclude | Optional ignore lists |

Returns a Vitest Plugin.


create(args?)

Plain async function (not a plugin) that resolves glob patterns and returns { files, coverage } string arrays using the default patterns.

import { create } from '@bemedev/dev-utils/vitest-exclude';

const { files, coverage } = await create({
  ignoreTestFiles: ['src/fixtures/**'],
  ignoreCoverageFiles: ['src/**/*.types.ts'],
});

Parameters (args)

| Property | Type | Description | | --------------------- | ----------------------- | -------------------------------------------- | | ignoreTestFiles | string[] \| undefined | Glob patterns to exclude from test discovery | | ignoreCoverageFiles | string[] \| undefined | Glob patterns to exclude from coverage |

Returns Promise<{ files: string[]; coverage: string[] }>.


create.withPattern(patterns, args)

Same as create, but accepts custom glob patterns for both test and coverage discovery.

import { create } from '@bemedev/dev-utils/vitest-exclude';

const { files, coverage } = await create.withPattern(
  {
    patternTest: 'tests/**/*.test.ts',
    patternCov: 'src/**/*.ts',
  },
  { ignoreTestFiles: ['tests/fixtures/**'] },
);

Parameters

| Name | Type | Description | | ------------- | -------------------- | ----------------------------------- | | patternTest | string \| string[] | Glob(s) for test file discovery | | patternCov | string \| string[] | Glob(s) for coverage file discovery | | args | same as create | Optional ignore lists |

Returns Promise<{ files: string[]; coverage: string[] }>.


vitestExtended

Extended helpers for writing structured, type-safe Vitest tests.

createTests(func, args?)

Creates a reusable test suite for a function with acceptation, success, and fails runners.

import { createTests } from '@bemedev/dev-utils/vitest-extended';

// add.ts
export const add = (a: number, b: number) => a + b;

// add.test.ts
const { acceptation, success, fails } = createTests(add);

describe('add', () => {
  describe('acceptation', acceptation());

  describe(
    'success',
    success(
      { invite: '1 + 2 = 3', parameters: [1, 2], expected: 3 },
      { invite: '0 + 0 = 0', parameters: [0, 0], expected: 0 },
    ),
  );
});

Note: When the first parameter is an array, wrap it in another array: parameters: [[1, 2, 3]].

Parameters

| Name | Type | Description | | ---------------- | --------------------------- | --------------------------------------------------------------- | | func | Fn | The function under test | | args.transform | NextFn<F> \| undefined | Optional transformer applied to the return value | | args.toError | ToError_F<F> \| undefined | Optional function that derives an expected error from the input |

Returns { acceptation, success, fails }:

| Method | Signature | Description | | ------------------- | ------------ | ------------------------------------------------------ | | acceptation() | () => void | Runs two checks: function is defined and is a function | | success(...cases) | () => void | Runs test.concurrent.each for passing cases | | fails(...cases) | () => void | Runs test.concurrent.each and expects thrown errors |


createTests.withImplementation(f, opts)

Same as createTests but replaces the implementation with a vi.fn() mock before the test suite runs.

const { acceptation, success } = createTests.withImplementation(myFn, {
  name: 'myFn',
  instanciation: async () => realImpl,
});

opts properties

| Property | Type | Description | | --------------- | --------------------------- | -------------------------------------------------------- | | instanciation | () => Promise<F> \| F | Factory called in beforeAll to set mock implementation | | name | string | Display name used in acceptation tests | | transform | NextFn<F> \| undefined | Optional return-value transformer | | toError | ToError_F<F> \| undefined | Optional error deriver |


doneTest(invite, fn, options?)

Wraps a callback-style (done-based) test into a Vitest test. The test passes only when done() is called within the timeout. Supports both sync and async test functions.

import { doneTest } from '@bemedev/dev-utils/vitest-extended';

// Async example with await
doneTest('async callback', async done => {
  await service.start();
  await service.send('event');
});

// Sync example
doneTest('fires callback', done => {
  emitter.once('event', done);
  emitter.emit('event');
});

Parameters

| Name | Type | Default | Description | | --------- | --------------------------------------------- | ------- | ------------------------------------------ | | invite | string | — | Test description | | fn | (done: () => void) => void \| Promise<void> | — | Test body (sync or async, receives done) | | options | number \| TestOptions | 100 | Timeout in ms or Vitest TestOptions |

Variants

| Variant | Description | | ------------------------------------------- | -------------------------- | | doneTest.fails(invite, fn, options?) | Expects the test to fail | | doneTest.concurrent(invite, fn, options?) | Runs the test concurrently |


createFakeWaiter(vi)

Creates a fake-timer-aware async waiter. If fake timers are active it advances them; otherwise it uses a real sleep.

import { createFakeWaiter } from '@bemedev/dev-utils/vitest-extended';

const wait = createFakeWaiter(vi);

test('advances time', async () => {
  vi.useFakeTimers();
  await wait(500); // advances fake timers by 500 ms
});

Parameters

| Name | Type | Description | | ---- | ------------- | ------------------ | | vi | VitestUtils | Vitest vi object |

Returns (ms?: number, times?: number) => Promise<void>

Variants

| Variant | Signature | Description | | -------------------------------------------- | ------------------------------------------------------- | ----------------------------------------------------------------- | | createFakeWaiter.withDefaultDelay(vi, ms?) | (index, times?) => [string, () => Promise<void>] | Returns a labelled waiter with a fixed delay | | createFakeWaiter.all(vi) | (index, ms?, times?) => [string, () => Promise<void>] | Returns a labelled waiter with configurable delay and repetitions |


useEach(func, transform?)

A typed wrapper around test.concurrent.each for synchronous functions.

import { useEach } from '@bemedev/dev-utils/vitest-extended';

const run = useEach(add);

run(['1+2', [1, 2], 3], ['0+0', [0, 0], 0]);

Parameters

| Name | Type | Description | | ----------- | ------------------------ | --------------------------------- | | func | Fn | Function under test | | transform | NextFn<F> \| undefined | Optional return-value transformer |

Returns (...cases: TestArgs2<F>) => void


useEachAsync(func, transform?)

Same as useEach but awaits the function result.


useErrorAsyncEach(func, transform?, toError?)

Runs async error cases using expect(fn).rejects.toThrowError(error).

const runErrors = vitestExtended.useErrorAsyncEach(
  divide,
  undefined,
  ([_, b]) => (b === 0 ? 'Division by zero' : undefined),
);

runErrors(['divide by 0', [1, 0], undefined]);

useTestFunctionAcceptation(f, name?) / useTFA

Runs two acceptation checks: the function is defined and is actually a function.

vitestExtended.useTFA(myFunction, 'myFunction');

Utility helpers

| Export | Signature | Description | | ---------------------------------- | ----------------------------------- | ------------------------------------------------- | | isDefined(value?) | (value?: T \| null) => value is T | Type guard — not undefined or null | | isFunction(arg) | (arg: any) => boolean | Type guard — checks if arg is a callable function | | identity(value) | <T>(value: T) => T | Returns the value unchanged | | defaultEquality(value, expected) | (a, b) => void | Strict equality; sorts arrays before comparing |


rolldownConfig

Rolldown bundler configuration factory with built-in plugins for TypeScript declarations, path aliasing, circular dependency detection, and tree-shaking externals.

defineConfig(additionals?)

Shorthand for defineConfig.default.

defineConfig.default(params?)

Produces a full Rolldown config with the default plugin pipeline:

  1. alias — resolves tsconfig path aliases (rollup-plugin-tsc-alias)
  2. tsPaths — resolves tsconfig path imports at bundle time (rollup-plugin-tsconfig-paths)
  3. circulars — warns on circular dependencies (rollup-plugin-circular-dependency)
  4. externals — marks dependencies and peerDependencies as external (rollup-plugin-node-externals)
  5. typescript — emits .d.ts declarations via the TypeScript compiler API
  6. clean — removes JS outputs for files that produce empty chunks
// rolldown.config.ts
import { defineConfig } from '@bemedev/dev-utils/rolldown';

export default defineConfig.default({
  dir: 'lib',
  sourcemap: true,
  excludesTS: ['src/fixtures/**/*.ts'],
});

Params properties

| Property | Type | Default | Description | | ---------------- | --------------------------------------- | ------------- | ------------------------------------------------------- | | dir | string | 'lib' | Output directory | | sourcemap | boolean | false | Emit sourcemaps | | declarationMap | boolean | undefined | Emit declaration maps | | excludesTS | string \| string[] | [] | Extra TS files to exclude from declaration emit | | circularDeps | string \| string[] | [] | Extra patterns exempt from circular-dep warnings | | ignoresJS | string \| string[] | [] | Patterns whose empty-bundle warnings are suppressed | | externals | string \| string[] | [] | Additional packages to mark as external | | plugins | (RolldownPluginOption \| PluginKey)[] | default order | Custom plugin list; string keys select built-in plugins |

Default excluded files (always applied):

**/node_modules/**/*
**/__tests__/**/*
**/*.test.ts  /  **/*.test-d.ts
**/*.fixtures.ts  /  **/fixtures.ts
src/fixtures/**/*.ts

Output format: both esm (.js) and cjs (.cjs), with preserveModules: true.


defineConfig.bemedev(params?)

Opinionated preset that extends defineConfig.default with:

  • Sourcemaps enabled by default
  • DEFAULT_CIRCULAR_DEPS merged into circularDeps (**/types.ts, **/*.types.ts, …)
  • DEFAULT_EXCLUDE merged into excludesTS
  • DEFAULT_CIRCULAR_DEPS merged into ignoresJS
export default defineConfig.bemedev({
  excludesTS: ['src/my-fixtures/**'],
});

Plugin builders (PLUGIN_BUILDERS)

Individual plugin factories are available for custom pipeline assembly:

| Key | Function | Wraps | | ------------ | ---------------------- | ------------------------------------- | | alias | alias(options?) | rollup-plugin-tsc-alias | | tsPaths | tsPaths(options?) | rollup-plugin-tsconfig-paths | | circulars | circulars(options?) | rollup-plugin-circular-dependency | | externals | externals(options?) | rollup-plugin-node-externals | | typescript | typescript(options?) | TypeScript compiler API + tsc-alias | | clean | clean(options?) | Custom post-build JS cleanup |

Pass plugin keys as strings in the plugins array to reorder or subset them:

defineConfig.default({
  plugins: ['alias', 'tsPaths', 'externals', 'typescript'],
});

buildTests

CLI tooling that packs your built library as a local tarball, installs it under the alias this-gen-1, runs your test suite against the real distributable, then tears down.

Available as a sub-path export:

import {
  addTarball,
  cleanup,
  customImport,
  THIS1,
} from '@bemedev/dev-utils/build-tests';

CLI usage

The binary is build-tests. It exposes three subcommands:

# Install the tarball (pre-test hook)
build-tests pre

# Run tests with pre/post lifecycle
build-tests test [--pretest] [--posttest]

# Clean up tarball + uninstall (post-test hook)
build-tests post

package.json integration (auto-configured):

{
  "scripts": {
    "pretest": "build && build-tests pre",
    "posttest": "fmt && build-tests post"
  }
}

addTarball()

Programmatic API for the pre step:

  1. Builds the package.json for the outDir (strips scripts, devDependencies, files; fixes paths)
  2. Runs pnpm pack into .pack/
  3. Installs the resulting .tgz as this-gen-1 in devDependencies
import { addTarball } from '@bemedev/dev-utils/build-tests';

await addTarball();

cleanup()

Programmatic API for the post step:

  1. Removes the .pack/ folder
  2. Runs pnpm remove this-gen-1
import { cleanup } from '@bemedev/dev-utils/build-tests';

cleanup();

customImport(fn?)

Dynamically imports the installed package (this-gen-1) and optionally transforms its exports via a mapper function.

import { customImport } from '@bemedev/dev-utils/build-tests';

// Import the default export as-is
const out = await customImport();

// Import and pick a specific export
const myFn = await customImport(mod => mod.myFn);

Parameters

| Name | Type | Default | Description | | ---- | ------------------------- | ---------- | -------------------------------------------------------- | | fn | (out: IndexImport) => T | identity | Mapper applied to the imported module; defaults to no-op |

Returns Promise<T> — the mapped module output.


THIS1

Constant string 'this-gen-1' — the package alias used by addTarball and cleanup when installing/removing the local tarball.

import { THIS1 } from '@bemedev/dev-utils/build-tests';

console.log(THIS1); // 'this-gen-1'

Types

| Name | Description | | ------------- | --------------------------------------------------------------------- | | IndexImport | Type of the module returned by a dynamic import(THIS1) call (any) |


Licence

MIT

CHANGELOG

Read CHANGELOG.md for details about all changes and versions.

Author

chlbri ([email protected])

My github

Links