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

casebridge

v1.1.1

Published

Bidirectional camelCase ↔ snake_case key transformation for TypeScript/JavaScript — framework-agnostic core with adapters for Angular, Fetch, and Axios.

Readme

casebridge

Bidirectional camelCase ↔ snake_case key transformation for TypeScript/JavaScript.

  • O(n) single-pass iterative traversal — no recursive call-stack risk
  • Memoized key conversion — each unique key is transformed exactly once
  • Preserves Date, File, Blob, FormData, ArrayBuffer, and TypedArray references untouched
  • Full TypeScript types: ObjectToCamel<T>, ObjectToSnake<T> (compile-time key inference)
  • Framework-agnostic core with optional adapters for Angular, Fetch API, and Axios

Install

npm install casebridge

Core API

transformKeys(input, keyFn)

Recursively walks an object/array tree and applies keyFn to every key.

import { transformKeys, snakeToCamel, camelToSnake } from 'casebridge';

const camel = transformKeys(snakePayload, snakeToCamel);
const snake = transformKeys(camelPayload, camelToSnake);

toCamel<T>(input: T): ObjectToCamel<T>

Typed convenience wrapper — return type is fully inferred at compile time.

import { toCamel } from 'casebridge';

interface UserSnake {
  first_name: string;
  profile_id: number;
}

const user = toCamel(apiResponse as UserSnake);
user.firstName; // ✅ TypeScript knows this exists

toSnake<T>(input: T): ObjectToSnake<T>

import { toSnake } from 'casebridge';

const body = toSnake({ firstName: 'Jane', profileId: 42 });
// → { first_name: 'Jane', profile_id: 42 }

snakeToCamel(key) / camelToSnake(key)

Single-key converters with memoization cache.

import { snakeToCamel, camelToSnake } from 'casebridge';

snakeToCamel('member_profile_id'); // → 'memberProfileId'
snakeToCamel('member-profile-id'); // → 'memberProfileId'  (kebab supported)
camelToSnake('memberProfileId');   // → 'member_profile_id'
camelToSnake('MyKey');             // → 'my_key'            (PascalCase handled)

Adapters

All adapters accept the same configuration options:

| Option | Type | Default | Description | |--------|------|---------|-------------| | requestCase | 'snake' \| 'camel' | 'snake' | Global default for outgoing request payloads | | responseCase | 'snake' \| 'camel' | 'camel' | Global default for incoming response payloads | | avoidSnakeRequestConversion | (string \| RegExp)[] | [] | URLs that should receive camelCase request bodies (overrides requestCase) | | avoidCamelResponseConversion | (string \| RegExp)[] | [] | URLs whose responses should be left as-is (overrides responseCase) | | skipUrls | (string \| RegExp)[] | [] | URLs that bypass all transformation |

Fetch API

Works in any environment with native fetch (browser, Node 18+, Deno, Bun, Cloudflare Workers).

import { createCaseBridgeFetch } from 'casebridge/fetch';

const fetch = createCaseBridgeFetch({
  skipUrls: ['/exchange-router', /\/no-transform\//],
});

// Drop-in replacement for globalThis.fetch
const data = await fetch('/api/users', {
  method: 'POST',
  headers: { 'Content-Type': 'application/json' },
  body: JSON.stringify({ firstName: 'Jane', profileId: 42 }),
  // body sent as → { first_name: 'Jane', profile_id: 42 }
}).then(r => r.json());
// data keys are already camelCase

Mixed API example — most endpoints want snake_case, but some accept camelCase:

const fetch = createCaseBridgeFetch({
  // default: request bodies are converted to snake_case
  avoidSnakeRequestConversion: ['/v2/graphql', /\/camel-service\//],
  // default: responses are converted to camelCase
  avoidCamelResponseConversion: ['/legacy-api'],
});

All-camelCase API — no conversion at all on requests:

const fetch = createCaseBridgeFetch({ requestCase: 'camel' });

Axios

import axios from 'axios';
import { createCaseBridgeAxiosInterceptors } from 'casebridge/axios';

const { request, response } = createCaseBridgeAxiosInterceptors({
  skipUrls: ['/exchange-router'],
});

axios.interceptors.request.use(request.onFulfilled);
axios.interceptors.response.use(response.onFulfilled);

Or on a custom instance:

const api = axios.create({ baseURL: 'https://api.example.com' });
const { request, response } = createCaseBridgeAxiosInterceptors();
api.interceptors.request.use(request.onFulfilled);
api.interceptors.response.use(response.onFulfilled);

Mixed API example — some endpoints accept camelCase, others want snake_case:

const { request, response } = createCaseBridgeAxiosInterceptors({
  // default: camelCase → snake_case for all requests
  avoidSnakeRequestConversion: ['/v2/graphql', /\/camel-service\//],
  // skip camelCase conversion for responses from legacy services
  avoidCamelResponseConversion: ['/legacy-api'],
});

Angular

Add to your app.config.ts:

import { provideHttpClient, withInterceptors } from '@angular/common/http';
import { caseTransformInterceptor, provideCaseBridgeConfig } from 'casebridge/angular';

export const appConfig: ApplicationConfig = {
  providers: [
    provideHttpClient(withInterceptors([caseTransformInterceptor])),
    provideCaseBridgeConfig({
      skipUrls: ['/exchange-router', /\/no-transform\//],
    }),
  ],
};

Mixed API example:

provideCaseBridgeConfig({
  avoidSnakeRequestConversion: ['/v2/graphql'],
  avoidCamelResponseConversion: ['/legacy-api'],
})

Performance

| Approach | Time | Space | Notes | |---|---|---|---| | transformKeys (this lib) | O(n) | O(d) | Iterative stack, memoized keys | | JSON.stringify + parse | O(n) | O(n) | Two full traversals + string alloc | | Regex loop (non-global) | O(n²) | O(d) | Re-scans string per replacement |

Where n = total key-value pairs, d = max nesting depth.


TypeScript Types

Types adapted from ts-case-convert (Apache-2.0). Runtime implementation is original.

import type { ObjectToCamel, ObjectToSnake, ToCamel, ToSnake } from 'casebridge';

License

MIT © Kartik