caseflip: Fix camelCase ↔ snake_case Without Leaving the Browser
Freelance API integration needed batch field renames. Built a 90-line case converter that handles edge cases like HTTPHeader and iOS-style acronyms.
Context: Client's REST API returned user_id but frontend types used userId. Needed a quick converter during a call — not another npm package.
Full tool
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Case Converter</title>
<style>
body { font-family: system-ui; max-width: 720px; margin: 2rem auto; padding: 0 1rem; }
textarea { width: 100%; min-height: 140px; font-family: monospace; }
.btns { display: flex; flex-wrap: wrap; gap: .5rem; margin: .75rem 0; }
button { padding: .4rem .8rem; cursor: pointer; }
</style>
</head>
<body>
<h1>Case Converter</h1>
<textarea id="in" placeholder="user_id or userId"></textarea>
<div class="btns">
<button data-mode="camel">camelCase</button>
<button data-mode="pascal">PascalCase</button>
<button data-mode="snake">snake_case</button>
<button data-mode="kebab">kebab-case</button>
<button data-mode="constant">CONSTANT_CASE</button>
<button data-mode="title">Title Case</button>
</div>
<textarea id="out" readonly></textarea>
<script>
const words = (s) =>
s.replace(/([a-z])([A-Z])/g, '$1 $2')
.replace(/([A-Z]+)([A-Z][a-z])/g, '$1 $2')
.split(/[\s_\-.]+/)
.filter(Boolean)
.map(w => w.toLowerCase());
const convert = {
camel: (w) => w.map((x, i) => i ? x[0].toUpperCase() + x.slice(1) : x).join(''),
pascal: (w) => w.map(x => x[0].toUpperCase() + x.slice(1)).join(''),
snake: (w) => w.join('_'),
kebab: (w) => w.join('-'),
constant: (w) => w.join('_').toUpperCase(),
title: (w) => w.map(x => x[0].toUpperCase() + x.slice(1)).join(' '),
};
const input = document.getElementById('in');
const output = document.getElementById('out');
document.querySelectorAll('[data-mode]').forEach(btn => {
btn.addEventListener('click', () => {
const mode = btn.dataset.mode;
const lines = input.value.split('\n');
output.value = lines.map(line => {
const t = line.trim();
if (!t) return '';
return convert[mode](words(t));
}).join('\n');
});
});
</script>
</body>
</html>
Bug I shipped first
HTTPResponse became h t t p response because I split on every capital letter.
Fix: the regex ([A-Z]+)([A-Z][a-z]) keeps acronyms together before splitting.
Batch mode
One identifier per line. Pasting 200 GraphQL field names → click snake_case → copy for OpenAPI spec.
Real output
Input: getUserProfileURL
snake: get_user_profile_url
kebab: get-user-profile-url
Verify
user_id→ camel →userIdXMLHttpRequest→ snake →xml_http_request(acceptable tradeoff)- Empty lines preserved in batch output
Host as static HTML. No dependencies. Works offline after first load.