Transform strings between 19+ case formats with full TypeScript support
[Features](#-features) β’ [Installation](#-installation) β’ [Quick Start](#-quick-start) β’ [API Reference](#-available-methods) β’ [Examples](#-examples) β’ [Documentation](#-usage-guide) β’ [Live Demo](https://github.com/idimetrix/vue-case)β οΈ Version 2.0 - Complete rewrite for Vue 3 with full TypeScript support and 100% test coverage. For Vue 2, use version 1.x.
import { camelCase, pascalCase, snakeCase } from 'vue-case';
camelCase('hello world')    // β 'helloWorld'
pascalCase('hello world')   // β 'HelloWorld'
snakeCase('hello world')    // β 'hello_world'
| ### π― **Core Features** - β **19+ Case Transformations** - β **100% Test Coverage** - β **Full TypeScript Support** - β **Zero Configuration** - β **Tree Shakeable** | ### π **Vue 3 Integration** - β **Composition API** with `useCase()` - β **Options API** with global `$methods` - β **Direct Imports** for flexibility - β **Plugin System** for global access - β **CDN Support** for quick prototyping | 
| **npm** ```bash npm install vue-case ``` | **pnpm** ```bash pnpm add vue-case ``` | **yarn** ```bash yarn add vue-case ``` | 
<!-- Vue 3 -->
<script src="https://unpkg.com/vue@3"></script>
<!-- vue-case -->
<script src="https://unpkg.com/vue-case@2"></script>
<script>
  const { createApp } = Vue;
  const app = createApp({
    template: '<div></div>'
  });
  app.use(VueCase);
  app.mount('#app');
</script>
<template>
  <div class="converter">
    <input v-model="text" placeholder="Enter text..." />
    <div class="results">
      <p>camelCase: <code></code></p>
      <p>PascalCase: <code></code></p>
      <p>snake_case: <code></code></p>
      <p>kebab-case: <code></code></p>
    </div>
  </div>
</template>
<script setup lang="ts">
import { ref } from 'vue';
import { useCase } from 'vue-case';
const { camelCase, pascalCase, snakeCase, paramCase } = useCase();
const text = ref('Hello World');
</script>
<template>
  <div>
    <p></p>
    <p></p>
    <p></p>
  </div>
</template>
<script lang="ts">
import { defineComponent } from 'vue';
export default defineComponent({
  data() {
    return {
      username: 'John Doe',
      description: 'A very long description text...'
    };
  }
});
</script>
import { camelCase, pascalCase, snakeCase, constantCase } from 'vue-case';
// Use anywhere in your code
const apiEndpoint = camelCase('user profile');     // 'userProfile'
const className = pascalCase('my component');      // 'MyComponent'
const dbColumn = snakeCase('user name');          // 'user_name'
const envVar = constantCase('api key');           // 'API_KEY'
Setup in main.ts:
import { createApp } from 'vue';
import VueCase from 'vue-case';
import App from './App.vue';
const app = createApp(App);
// Install plugin globally
app.use(VueCase);
app.mount('#app');
Use in any component:
<template>
  <div>
    <!-- Available as $camelCase, $pascalCase, $snakeCase, etc. -->
    <h1></h1>
    <p></p>
  </div>
</template>
useCase()<script setup lang="ts">
import { useCase } from 'vue-case';
import { ref, computed } from 'vue';
// Get all transformation methods
const { camelCase, pascalCase, snakeCase, constantCase, truncate } = useCase();
const inputText = ref('user profile settings');
// Use in computed properties
const apiRoute = computed(() => camelCase(inputText.value));
const component = computed(() => pascalCase(inputText.value));
const database = computed(() => snakeCase(inputText.value));
const environment = computed(() => constantCase(inputText.value));
</script>
<template>
  <div>
    <input v-model="inputText" />
    <ul>
      <li>API: </li>
      <li>Component: </li>
      <li>Database: </li>
      <li>Environment: </li>
    </ul>
  </div>
</template>
import type { 
  CaseMethods, 
  CaseTransformFn,
  CaseCheckFn,
  TruncateFn,
  VueCaseOptions
} from 'vue-case';
import { camelCase, pascalCase, useCase } from 'vue-case';
// Type-safe function
const transformUserInput: CaseTransformFn = (input: string) => {
  return camelCase(input);
};
// Type-safe composable usage
const caseMethods: CaseMethods = useCase();
// Use in classes
class StringTransformer {
  private transform: CaseTransformFn;
  constructor() {
    this.transform = pascalCase;
  }
  process(input: string): string {
    return this.transform(input);
  }
}
| Method | Input | Output | Use Case | 
|---|---|---|---|
| camelCase | 'hello world' | 'helloWorld' | JavaScript variables, object keys | 
| pascalCase | 'hello world' | 'HelloWorld' | Component names, class names | 
| snakeCase | 'hello world' | 'hello_world' | Database columns, Python variables | 
| constantCase | 'hello world' | 'HELLO_WORLD' | Environment variables, constants | 
| paramCase | 'hello world' | 'hello-world' | URLs, CSS classes, file names | 
| dotCase | 'hello world' | 'hello.world' | Object paths, configuration keys | 
| pathCase | 'hello world' | 'hello/world' | File paths, routes | 
| headerCase | 'hello world' | 'Hello-World' | HTTP headers | 
| capitalCase | 'hello world' | 'Hello World' | Titles, display names | 
| titleCase | 'hello world' | 'Hello World' | Book titles, headings | 
| sentenceCase | 'HELLO WORLD' | 'Hello world' | Sentences, descriptions | 
| noCase | 'helloWorld' | 'hello world' | Remove formatting | 
| lowerCase | 'HELLO WORLD' | 'hello world' | Normalize to lowercase | 
| upperCase | 'hello world' | 'HELLO WORLD' | Normalize to uppercase | 
| lowerCaseFirst | 'Hello' | 'hello' | Lowercase first letter | 
| upperCaseFirst | 'hello' | 'Hello' | Capitalize first letter | 
| swapCase | 'Hello World' | 'hELLO wORLD' | Toggle case | 
| Method | Signature | Description | Example | 
|---|---|---|---|
| truncate | (text: string, length?: number) | Truncate text with ββ¦β | truncate('Hello World', 5)β'Hello...' | 
| isLowerCase | (text: string): boolean | Check if lowercase | isLowerCase('hello')βtrue | 
| isUpperCase | (text: string): boolean | Check if uppercase | isUpperCase('HELLO')βtrue | 
import { camelCase, snakeCase } from 'vue-case';
// Transform snake_case API responses to camelCase
function transformResponse<T extends Record<string, any>>(data: T): Record<string, any> {
  return Object.entries(data).reduce((acc, [key, value]) => {
    acc[camelCase(key)] = value;
    return acc;
  }, {} as Record<string, any>);
}
// Transform camelCase to snake_case for API requests
function transformRequest<T extends Record<string, any>>(data: T): Record<string, any> {
  return Object.entries(data).reduce((acc, [key, value]) => {
    acc[snakeCase(key)] = value;
    return acc;
  }, {} as Record<string, any>);
}
// Usage with Axios
import axios from 'axios';
const api = axios.create({
  baseURL: 'https://api.example.com',
  transformResponse: [(data) => {
    const parsed = JSON.parse(data);
    return transformResponse(parsed);
  }],
  transformRequest: [(data) => {
    return JSON.stringify(transformRequest(data));
  }]
});
// Now your API calls work seamlessly:
const response = await api.get('/user_profile'); // API returns user_name
console.log(response.data.userName); // Access as userName
<template>
  <component 
    :is="getComponent(type)" 
    :class="getClassName(type)"
  >
    <h1 id="changelog">Changelog</h1>
<p>All notable changes to this project will be documented in this file.</p>
<p>The format is based on <a href="https://keepachangelog.com/en/1.0.0/">Keep a Changelog</a>,
and this project adheres to <a href="https://semver.org/spec/v2.0.0.html">Semantic Versioning</a>.</p>
<h2 id="200---2024-01-01"><a href="https://github.com/idimetrix/vue-case/compare/v1.0.7...v2.0.0">2.0.0</a> - 2024-01-01</h2>
<h3 id="-major-release---vue-3--typescript-rewrite">π Major Release - Vue 3 + TypeScript Rewrite</h3>
<p>This is a complete rewrite of vue-case for Vue 3 with full TypeScript support.</p>
<h3 id="οΈ-breaking-changes">β οΈ Breaking Changes</h3>
<ul>
  <li><strong>Vue 3 Required</strong>: Now requires Vue 3.x (previously Vue 2.x)</li>
  <li><strong>Filter Syntax Removed</strong>: Vue 3 removed filters, use methods or composables instead
    <ul>
      <li>Old: ``</li>
      <li>New: <code class="language-plaintext highlighter-rouge">or</code> with <code class="language-plaintext highlighter-rouge">useCase()</code></li>
    </ul>
  </li>
  <li><strong>API Changes</strong>: Plugin now uses Vue 3βs <code class="language-plaintext highlighter-rouge">app.use()</code> instead of <code class="language-plaintext highlighter-rouge">Vue.use()</code></li>
</ul>
<h3 id="-added">β¨ Added</h3>
<ul>
  <li><strong>TypeScript Support</strong>: Full TypeScript rewrite with complete type definitions</li>
  <li><strong>Composition API</strong>: New <code class="language-plaintext highlighter-rouge">useCase()</code> composable for Composition API</li>
  <li><strong>Multiple Usage Patterns</strong>:
    <ul>
      <li>Plugin installation with global properties</li>
      <li>Composable with <code class="language-plaintext highlighter-rouge">useCase()</code></li>
      <li>Direct imports for tree-shaking</li>
    </ul>
  </li>
  <li><strong>Modern Build</strong>: Updated to Vue 3.5.x with latest tooling</li>
  <li><strong>Enhanced Demo</strong>: Interactive demo with both Options and Composition API examples</li>
  <li><strong>Type Exports</strong>: All types are now exported for TypeScript users</li>
  <li><strong>Better Documentation</strong>: Comprehensive README with examples for all use cases</li>
</ul>
<h3 id="-changed">π§ Changed</h3>
<ul>
  <li>Migrated from Vue 2 to Vue 3</li>
  <li>Converted all JavaScript to TypeScript</li>
  <li>Updated all dependencies to latest versions</li>
  <li>Improved error handling and edge cases</li>
  <li>Better test coverage with TypeScript tests</li>
  <li>Modern UI for demo application</li>
</ul>
<h3 id="-documentation">π Documentation</h3>
<ul>
  <li>Complete README rewrite with Vue 3 examples</li>
  <li>Added TypeScript usage examples</li>
  <li>Added CONTRIBUTING.md</li>
  <li>Added comprehensive API documentation</li>
  <li>Added multiple real-world examples</li>
</ul>
<h3 id="οΈ-development">π οΈ Development</h3>
<ul>
  <li>Added ESLint with TypeScript support</li>
  <li>Added Prettier configuration</li>
  <li>Added Jest configuration for TypeScript</li>
  <li>Added TypeScript compiler configuration</li>
  <li>Added proper type declarations</li>
</ul>
<h3 id="-dependencies">π¦ Dependencies</h3>
<ul>
  <li>Updated <code class="language-plaintext highlighter-rouge">vue</code> to ^3.5.22</li>
  <li>Updated <code class="language-plaintext highlighter-rouge">@vue/cli-service</code> to ^5.0.9</li>
  <li>Updated <code class="language-plaintext highlighter-rouge">@vue/test-utils</code> to ^2.4.6</li>
  <li>Added <code class="language-plaintext highlighter-rouge">typescript</code> ^5.7.2</li>
  <li>Added TypeScript ESLint plugins</li>
  <li>Removed deprecated Vue 2 dependencies</li>
</ul>
<hr />
<h2 id="107---2023-xx-xx"><a href="https://github.com/idimetrix/vue-case/compare/v1.0.0...v1.0.7">1.0.7</a> - 2023-xx-xx</h2>
<h3 id="fixed">Fixed</h3>
<ul>
  <li>Bug fixes and improvements for Vue 2</li>
</ul>
<h2 id="100---2020-xx-xx"><a href="https://github.com/idimetrix/vue-case/releases/tag/v1.0.0">1.0.0</a> - 2020-xx-xx</h2>
<h3 id="added">Added</h3>
<ul>
  <li>Initial release with Vue 2 support</li>
  <li>Filter-based API</li>
  <li>20+ case transformation methods</li>
</ul>
  </component>
</template>
<script setup lang="ts">
import { computed } from 'vue';
import { pascalCase, paramCase } from 'vue-case';
interface Props {
  type: string;
  content: string;
}
const props = defineProps<Props>();
// Convert 'user card' β 'UserCard' for component name
const getComponent = (type: string) => {
  return pascalCase(type);
};
// Convert 'user card' β 'user-card' for CSS class
const getClassName = (type: string) => {
  return `component-${paramCase(type)}`;
};
</script>
<template>
  <form @submit.prevent="handleSubmit">
    <div v-for="field in formFields" :key="field.name">
      <label :for="field.id"></label>
      <input 
        :id="field.id"
        :name="field.name"
        v-model="formData[field.name]"
      />
    </div>
    <button type="submit">Submit</button>
  </form>
</template>
<script setup lang="ts">
import { ref, computed } from 'vue';
import { camelCase, paramCase, capitalCase } from 'vue-case';
const fieldNames = ['user name', 'email address', 'phone number'];
const formFields = computed(() => 
  fieldNames.map(name => ({
    name: camelCase(name),        // 'userName' for v-model
    id: paramCase(name),           // 'user-name' for id/for
    label: capitalCase(name)       // 'User Name' for display
  }))
);
const formData = ref(
  fieldNames.reduce((acc, name) => {
    acc[camelCase(name)] = '';
    return acc;
  }, {} as Record<string, string>)
);
const handleSubmit = () => {
  console.log(formData.value);
  // { userName: '...', emailAddress: '...', phoneNumber: '...' }
};
</script>
<template>
  <div class="blog-editor">
    <input 
      v-model="title" 
      placeholder="Blog post title"
      @input="generateSlug"
    />
    <p class="slug-preview">
      URL: <code>/</code>
    </p>
    <button @click="copySlug">Copy URL</button>
  </div>
</template>
<script setup lang="ts">
import { ref, computed } from 'vue';
import { paramCase } from 'vue-case';
const title = ref('');
const baseUrl = 'https://myblog.com/posts';
const slug = computed(() => paramCase(title.value));
const generateSlug = () => {
  // Automatically updates via computed property
};
const copySlug = async () => {
  await navigator.clipboard.writeText(`${baseUrl}/${slug.value}`);
  alert('URL copied!');
};
</script>
import { constantCase, camelCase } from 'vue-case';
class EnvironmentConfig {
  private config: Record<string, string> = {};
  // Load from process.env
  loadFromEnv() {
    this.config = {
      [camelCase('API_KEY')]: process.env.API_KEY || '',
      [camelCase('DATABASE_URL')]: process.env.DATABASE_URL || '',
      [camelCase('APP_NAME')]: process.env.APP_NAME || '',
    };
    return this.config;
  }
  // Generate .env content
  generateEnvFile(config: Record<string, string>): string {
    return Object.entries(config)
      .map(([key, value]) => `${constantCase(key)}=${value}`)
      .join('\n');
  }
}
// Usage
const env = new EnvironmentConfig();
const config = {
  apiKey: 'secret123',
  databaseUrl: 'postgresql://...',
  appName: 'My App'
};
console.log(env.generateEnvFile(config));
// Output:
// API_KEY=secret123
// DATABASE_URL=postgresql://...
// APP_NAME=My App
<template>
  <div :class="bem('container')">
    <div :class="bem('header')">
      <h1 :class="bem('title', 'large')"></h1>
    </div>
    <div :class="bem('content', isActive && 'active')">
      <slot />
    </div>
  </div>
</template>
<script setup lang="ts">
import { paramCase } from 'vue-case';
import { ref } from 'vue';
const componentName = 'UserProfile';
const blockName = paramCase(componentName); // 'user-profile'
// BEM (Block Element Modifier) helper
const bem = (element: string, modifier?: string | boolean) => {
  const base = `${blockName}__${paramCase(element)}`;
  if (modifier && typeof modifier === 'string') {
    return `${base} ${base}--${paramCase(modifier)}`;
  }
  return base;
};
const title = ref('User Profile');
const isActive = ref(true);
// Generates classes like:
// user-profile__container
// user-profile__header
// user-profile__title user-profile__title--large
// user-profile__content user-profile__content--active
</script>
import { snakeCase } from 'vue-case';
interface QueryFilters {
  [key: string]: any;
}
class QueryBuilder {
  private tableName: string;
  private filters: Record<string, any> = {};
  constructor(tableName: string) {
    this.tableName = snakeCase(tableName);
  }
  where(filters: QueryFilters) {
    this.filters = Object.entries(filters).reduce((acc, [key, value]) => {
      acc[snakeCase(key)] = value;
      return acc;
    }, {} as Record<string, any>);
    return this;
  }
  build(): string {
    const conditions = Object.entries(this.filters)
      .map(([key, value]) => `${key} = '${value}'`)
      .join(' AND ');
    
    return `SELECT * FROM ${this.tableName} WHERE ${conditions}`;
  }
}
// Usage
const query = new QueryBuilder('UserProfile')
  .where({
    firstName: 'John',
    emailAddress: 'john@example.com'
  })
  .build();
console.log(query);
// SELECT * FROM user_profile WHERE first_name = 'John' AND email_address = 'john@example.com'
import { dotCase } from 'vue-case';
interface TranslationKeys {
  [key: string]: string | TranslationKeys;
}
function generateI18nKeys(prefix: string, keys: string[]): TranslationKeys {
  return keys.reduce((acc, key) => {
    const i18nKey = dotCase(`${prefix} ${key}`);
    acc[i18nKey] = `${prefix}.${key}`;
    return acc;
  }, {} as TranslationKeys);
}
// Generate translation keys
const userKeys = generateI18nKeys('user', [
  'profile settings',
  'account details',
  'privacy settings'
]);
console.log(userKeys);
// {
//   'user.profile.settings': 'user.profile settings',
//   'user.account.details': 'user.account details',
//   'user.privacy.settings': 'user.privacy settings'
// }
// Use in Vue components
import { useI18n } from 'vue-i18n';
const { t } = useI18n();
const title = t(userKeys['user.profile.settings']);
Full support for all major testing frameworks:
import { describe, it, expect } from 'vitest'; // or jest
import { camelCase, pascalCase, snakeCase } from 'vue-case';
describe('vue-case transformations', () => {
  it('transforms to camelCase', () => {
    expect(camelCase('hello world')).toBe('helloWorld');
    expect(camelCase('hello-world')).toBe('helloWorld');
    expect(camelCase('hello_world')).toBe('helloWorld');
  });
  it('transforms to PascalCase', () => {
    expect(pascalCase('hello world')).toBe('HelloWorld');
  });
  it('handles edge cases', () => {
    expect(camelCase('')).toBe('');
    expect(camelCase('a')).toBe('a');
    expect(camelCase('hello@world')).toBe('helloWorld');
  });
});
text-case library|  |  |  |  | 
|---|---|---|---|
| Latest β | Latest β | Latest β | Latest β | 
import { createApp } from 'vue';
import VueCase from 'vue-case';
import type { VueCaseOptions } from 'vue-case';
const app = createApp(App);
// Custom options (currently all methods are included by default)
const options: VueCaseOptions = {
  // Future: Configure which methods to include
};
app.use(VueCase, options);
import { camelCase, upperCaseFirst, lowerCase } from 'vue-case';
// Create custom transformations
const customTransform = (text: string) => {
  return upperCaseFirst(camelCase(lowerCase(text)));
};
customTransform('HELLO WORLD'); // 'HelloWorld'
// All available types exported
export type CaseTransformFn = (value: string) => string;
export type TruncateFn = (value: string, length?: number) => string;
export type CaseCheckFn = (value: string) => boolean;
export interface CaseMethods {
  camelCase: CaseTransformFn;
  pascalCase: CaseTransformFn;
  capitalCase: CaseTransformFn;
  headerCase: CaseTransformFn;
  titleCase: CaseTransformFn;
  pathCase: CaseTransformFn;
  paramCase: CaseTransformFn;
  dotCase: CaseTransformFn;
  snakeCase: CaseTransformFn;
  constantCase: CaseTransformFn;
  lowerCase: CaseTransformFn;
  lowerCaseFirst: CaseTransformFn;
  upperCase: CaseTransformFn;
  upperCaseFirst: CaseTransformFn;
  swapCase: CaseTransformFn;
  sentenceCase: CaseTransformFn;
  noCase: CaseTransformFn;
  isLowerCase: CaseCheckFn;
  isUpperCase: CaseCheckFn;
  truncate: TruncateFn;
}
export interface VueCaseOptions {
  // Plugin configuration options
}
// Global property types for Options API
declare module 'vue' {
  interface ComponentCustomProperties {
    $case: CaseMethods;
    $camelCase: CaseTransformFn;
    $pascalCase: CaseTransformFn;
    // ... all other methods
  }
}
We welcome contributions! Hereβs how you can help:
git checkout -b feature/AmazingFeature)pnpm test)git commit -m 'Add some AmazingFeature')git push origin feature/AmazingFeature)# Clone the repository
git clone https://github.com/idimetrix/vue-case.git
cd vue-case
# Install dependencies
pnpm install
# Run tests
pnpm test
# Run tests with coverage
pnpm test --coverage
# Build library
pnpm run build
# Type check
pnpm run typecheck
# Run dev server
pnpm serve
See CHANGELOG.md for detailed release notes.
| ### π¦ Package [npm](https://www.npmjs.com/package/vue-case) | ### π» Repository [GitHub](https://github.com/idimetrix/vue-case) | ### π Issues [Report Bug](https://github.com/idimetrix/vue-case/issues) | ### π‘ Discussions [Ideas & Questions](https://github.com/idimetrix/vue-case/discussions) | 
If you find vue-case helpful, please consider:
Built with β€οΈ using: