caseforge 0.2.2 → 0.4.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/LICENSE CHANGED
@@ -1,6 +1,6 @@
1
1
  MIT License
2
2
 
3
- Copyright (c) 2025 Chikada Hiroki
3
+ Copyright (c) 2026 Chikada Hiroki
4
4
 
5
5
  Permission is hereby granted, free of charge, to any person obtaining a copy
6
6
  of this software and associated documentation files (the "Software"), to deal
package/README.md CHANGED
@@ -2,6 +2,7 @@
2
2
 
3
3
  [![npm version](https://badge.fury.io/js/caseforge.svg)](https://www.npmjs.com/package/caseforge)
4
4
  [![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](https://opensource.org/licenses/MIT)
5
+ [![Coverage: 100%](https://img.shields.io/badge/coverage-100%25-brightgreen.svg)](https://github.com/chikadahiroki/caseforge)
5
6
 
6
7
  > Type-safe and lightweight case conversion library for TypeScript.
7
8
 
@@ -9,7 +10,8 @@
9
10
 
10
11
  - ðŸŽŊ Type-safe conversions with full TypeScript support
11
12
  - ðŸŠķ Zero dependencies
12
- - 🔄 Supports camelCase, snake_case, kebab-case, and PascalCase
13
+ - 🔄 Supports camelCase, snake_case, kebab-case, PascalCase, and UPPER_CASE
14
+ - 🔍 Case format detection functions
13
15
  - ðŸŒģ Deep object and array transformation
14
16
  - ðŸ“Ķ Works with Bun, Node.js, and browsers
15
17
 
@@ -20,7 +22,18 @@ npm install caseforge
20
22
  ```
21
23
 
22
24
  ```ts
23
- import { toCamelCase, toSnakeCase, toKebabCase, toPascalCase, toUpperCase } from "caseforge";
25
+ import {
26
+ toCamelCase,
27
+ toSnakeCase,
28
+ toKebabCase,
29
+ toPascalCase,
30
+ toUpperCase,
31
+ isCamelCase,
32
+ isSnakeCase,
33
+ isKebabCase,
34
+ isPascalCase,
35
+ isUpperCase
36
+ } from "caseforge";
24
37
 
25
38
  // String conversion
26
39
  toCamelCase("user_name"); // => "userName"
@@ -29,6 +42,13 @@ toKebabCase("userName"); // => "user-name"
29
42
  toPascalCase("user_name"); // => "UserName"
30
43
  toUpperCase("userName"); // => "USER_NAME"
31
44
 
45
+ // Case format detection
46
+ isCamelCase("userName"); // => true
47
+ isSnakeCase("user_name"); // => true
48
+ isKebabCase("user-name"); // => true
49
+ isPascalCase("UserName"); // => true
50
+ isUpperCase("USER_NAME"); // => true
51
+
32
52
  // Object conversion with type inference
33
53
  const apiResponse = {
34
54
  user_id: 123,
@@ -41,10 +61,34 @@ const apiResponse = {
41
61
  const result = toCamelCase(apiResponse);
42
62
  // result.userId (typed!)
43
63
  // result.userName (typed!)
44
- // result.userSettings.notificationEnabled (typed!)## API
64
+ // result.userSettings.notificationEnabled (typed!)
45
65
 
66
+ // Detect API response format and convert accordingly
67
+ const sampleKey = Object.keys(apiResponse)[0];
68
+ if (isSnakeCase(sampleKey)) {
69
+ const converted = toCamelCase(apiResponse);
70
+ // Use converted data
71
+ }
46
72
  ```
47
73
 
74
+ ## API
75
+
76
+ ### Conversion Functions
77
+
78
+ - `toCamelCase(input)` - Converts to camelCase
79
+ - `toSnakeCase(input)` - Converts to snake_case
80
+ - `toKebabCase(input)` - Converts to kebab-case
81
+ - `toPascalCase(input)` - Converts to PascalCase
82
+ - `toUpperCase(input)` - Converts to UPPER_SNAKE_CASE
83
+
84
+ ### Detection Functions
85
+
86
+ - `isCamelCase(value)` - Checks if a string is in camelCase format
87
+ - `isSnakeCase(value)` - Checks if a string is in snake_case format
88
+ - `isKebabCase(value)` - Checks if a string is in kebab-case format
89
+ - `isPascalCase(value)` - Checks if a string is in PascalCase format
90
+ - `isUpperCase(value)` - Checks if a string is in UPPER_SNAKE_CASE format
91
+
48
92
  ## License
49
93
 
50
94
  MIT ÂĐ Chikada Hiroki
@@ -2,12 +2,12 @@
2
2
  * Converts a string to camelCase format at the type level.
3
3
  * @example "user_name" -> "userName"
4
4
  */
5
- type CamelCase<S extends string> = S extends `${infer A}_${infer B}` ? `${Lowercase<A>}${Capitalize<CamelCase<B>>}` : S extends `${infer A}-${infer B}` ? `${Lowercase<A>}${Capitalize<CamelCase<B>>}` : Uncapitalize<S>;
5
+ export type CamelCase<S extends string> = S extends `${infer A}_${infer B}` ? `${Lowercase<A>}${Capitalize<CamelCase<B>>}` : S extends `${infer A}-${infer B}` ? `${Lowercase<A>}${Capitalize<CamelCase<B>>}` : Uncapitalize<S>;
6
6
  /**
7
7
  * Converts all object keys to camelCase format at the type level.
8
8
  * @example { user_name: "John Doe" } -> { userName: "John Doe" }
9
9
  */
10
- type CamelCaseKeys<T> = {
10
+ export type CamelCaseKeys<T> = {
11
11
  [K in keyof T as CamelCase<K & string>]: T[K] extends readonly (infer U)[] ? U extends object ? readonly CamelCaseKeys<U>[] : T[K] : T[K] extends object ? CamelCaseKeys<T[K]> : T[K];
12
12
  };
13
13
  /**
@@ -17,4 +17,3 @@ type CamelCaseKeys<T> = {
17
17
  */
18
18
  export declare function toCamelCase<T extends string>(input: T): CamelCase<T>;
19
19
  export declare function toCamelCase<T extends object>(input: T): CamelCaseKeys<T>;
20
- export {};
@@ -2,12 +2,12 @@
2
2
  * Converts a string to kebab-case format at the type level.
3
3
  * @example "userName" -> "user-name"
4
4
  */
5
- type KebabCase<S extends string, First extends boolean = true> = S extends `${infer C}${infer R}` ? C extends "_" ? `-${KebabCase<R, false>}` : C extends Uppercase<C> ? First extends true ? `${Lowercase<C>}${KebabCase<R, false>}` : `-${Lowercase<C>}${KebabCase<R, false>}` : `${C}${KebabCase<R, false>}` : S;
5
+ export type KebabCase<S extends string, First extends boolean = true> = S extends `${infer C}${infer R}` ? C extends "_" ? `-${KebabCase<R, false>}` : C extends Uppercase<C> ? First extends true ? `${Lowercase<C>}${KebabCase<R, false>}` : `-${Lowercase<C>}${KebabCase<R, false>}` : `${C}${KebabCase<R, false>}` : S;
6
6
  /**
7
7
  * Converts all object keys to kebab-case format at the type level.
8
8
  * @example { userName: "John Doe" } -> { "user-name": "John Doe" }
9
9
  */
10
- type KebabCaseKeys<T> = {
10
+ export type KebabCaseKeys<T> = {
11
11
  [K in keyof T as KebabCase<K & string>]: T[K] extends readonly (infer U)[] ? U extends object ? readonly KebabCaseKeys<U>[] : T[K] : T[K] extends object ? KebabCaseKeys<T[K]> : T[K];
12
12
  };
13
13
  /**
@@ -17,4 +17,3 @@ type KebabCaseKeys<T> = {
17
17
  */
18
18
  export declare function toKebabCase<T extends string>(input: T): KebabCase<T>;
19
19
  export declare function toKebabCase<T extends object>(input: T): KebabCaseKeys<T>;
20
- export {};
@@ -2,12 +2,12 @@
2
2
  * Converts a string to PascalCase format at the type level.
3
3
  * @example "user_name" -> "UserName"
4
4
  */
5
- type PascalCase<S extends string> = S extends `${infer Head}_${infer Tail}` ? `${Capitalize<Lowercase<Head>>}${PascalCase<Tail>}` : S extends `${infer Head}-${infer Tail}` ? `${Capitalize<Lowercase<Head>>}${PascalCase<Tail>}` : S extends `${infer First}${infer Rest}` ? `${Capitalize<First>}${Rest}` : S;
5
+ export type PascalCase<S extends string> = S extends `${infer Head}_${infer Tail}` ? `${Capitalize<Lowercase<Head>>}${PascalCase<Tail>}` : S extends `${infer Head}-${infer Tail}` ? `${Capitalize<Lowercase<Head>>}${PascalCase<Tail>}` : S extends `${infer First}${infer Rest}` ? `${Capitalize<First>}${Rest}` : S;
6
6
  /**
7
7
  * Converts all object keys to PascalCase format at the type level.
8
8
  * @example { user_name: "John Doe" } -> { UserName: "John Doe" }
9
9
  */
10
- type PascalCaseKeys<T> = {
10
+ export type PascalCaseKeys<T> = {
11
11
  [K in keyof T as PascalCase<K & string>]: T[K] extends readonly (infer U)[] ? U extends object ? readonly PascalCaseKeys<U>[] : T[K] : T[K] extends object ? PascalCaseKeys<T[K]> : T[K];
12
12
  };
13
13
  /**
@@ -17,4 +17,3 @@ type PascalCaseKeys<T> = {
17
17
  */
18
18
  export declare function toPascalCase<T extends string>(input: T): PascalCase<T>;
19
19
  export declare function toPascalCase<T extends object>(input: T): PascalCaseKeys<T>;
20
- export {};
@@ -2,12 +2,12 @@
2
2
  * Converts a string to snake_case format at the type level.
3
3
  * @example "userName" -> "user_name"
4
4
  */
5
- type SnakeCase<S extends string, First extends boolean = true> = S extends `${infer C}${infer R}` ? C extends "_" | "-" ? `_${SnakeCase<R, false>}` : C extends Uppercase<C> ? First extends true ? `${Lowercase<C>}${SnakeCase<R, false>}` : `_${Lowercase<C>}${SnakeCase<R, false>}` : `${C}${SnakeCase<R, false>}` : S;
5
+ export type SnakeCase<S extends string, First extends boolean = true> = S extends `${infer C}${infer R}` ? C extends "_" | "-" ? `_${SnakeCase<R, false>}` : C extends Uppercase<C> ? First extends true ? `${Lowercase<C>}${SnakeCase<R, false>}` : `_${Lowercase<C>}${SnakeCase<R, false>}` : `${C}${SnakeCase<R, false>}` : S;
6
6
  /**
7
7
  * Converts all object keys to snake_case format at the type level.
8
8
  * @example { userName: "John Doe" } -> { user_name: "John Doe" }
9
9
  */
10
- type SnakeCaseKeys<T> = {
10
+ export type SnakeCaseKeys<T> = {
11
11
  [K in keyof T as SnakeCase<K & string>]: T[K] extends readonly (infer U)[] ? U extends object ? readonly SnakeCaseKeys<U>[] : T[K] : T[K] extends object ? SnakeCaseKeys<T[K]> : T[K];
12
12
  };
13
13
  /**
@@ -17,4 +17,3 @@ type SnakeCaseKeys<T> = {
17
17
  */
18
18
  export declare function toSnakeCase<T extends string>(input: T): SnakeCase<T>;
19
19
  export declare function toSnakeCase<T extends object>(input: T): SnakeCaseKeys<T>;
20
- export {};
@@ -2,12 +2,12 @@
2
2
  * Converts a string to UPPER_SNAKE_CASE format at the type level.
3
3
  * @example "userName" -> "USER_NAME"
4
4
  */
5
- type UpperCase<S extends string, First extends boolean = true> = S extends `${infer C}${infer R}` ? C extends "_" | "-" ? `_${UpperCase<R, false>}` : C extends Uppercase<C> ? First extends true ? `${Uppercase<C>}${UpperCase<R, false>}` : `_${Uppercase<C>}${UpperCase<R, false>}` : `${Uppercase<C>}${UpperCase<R, false>}` : Uppercase<S>;
5
+ export type UpperCase<S extends string, First extends boolean = true> = S extends `${infer C}${infer R}` ? C extends "_" | "-" ? `_${UpperCase<R, false>}` : C extends Uppercase<C> ? First extends true ? `${Uppercase<C>}${UpperCase<R, false>}` : `_${Uppercase<C>}${UpperCase<R, false>}` : `${Uppercase<C>}${UpperCase<R, false>}` : Uppercase<S>;
6
6
  /**
7
7
  * Converts all object keys to UPPER_SNAKE_CASE format at the type level.
8
8
  * @example { userName: "John Doe" } -> { USER_NAME: "John Doe" }
9
9
  */
10
- type UpperCaseKeys<T> = {
10
+ export type UpperCaseKeys<T> = {
11
11
  [K in keyof T as UpperCase<K & string>]: T[K] extends readonly (infer U)[] ? U extends object ? readonly UpperCaseKeys<U>[] : T[K] : T[K] extends object ? UpperCaseKeys<T[K]> : T[K];
12
12
  };
13
13
  /**
@@ -17,4 +17,3 @@ type UpperCaseKeys<T> = {
17
17
  */
18
18
  export declare function toUpperCase<T extends string>(input: T): UpperCase<T>;
19
19
  export declare function toUpperCase<T extends object>(input: T): UpperCaseKeys<T>;
20
- export {};
package/dist/index.d.ts CHANGED
@@ -1,5 +1,6 @@
1
- export { toCamelCase } from "./core/toCamelCase";
2
- export { toKebabCase } from "./core/toKebabCase";
3
- export { toPascalCase } from "./core/toPascalCase";
4
- export { toSnakeCase } from "./core/toSnakeCase";
5
- export { toUpperCase } from "./core/toUpperCase";
1
+ export { type CamelCase, type CamelCaseKeys, toCamelCase, } from "./core/toCamelCase";
2
+ export { type KebabCase, type KebabCaseKeys, toKebabCase, } from "./core/toKebabCase";
3
+ export { type PascalCase, type PascalCaseKeys, toPascalCase, } from "./core/toPascalCase";
4
+ export { type SnakeCase, type SnakeCaseKeys, toSnakeCase, } from "./core/toSnakeCase";
5
+ export { toUpperCase, type UpperCase, type UpperCaseKeys, } from "./core/toUpperCase";
6
+ export { isCamelCase, isKebabCase, isPascalCase, isSnakeCase, isUpperCase, } from "./utils/caseGuards";
package/dist/index.js CHANGED
@@ -1 +1 @@
1
- var q={LEADING_UPPER:/^[A-Z]/,UPPERCASE:/[A-Z]/g,LEADING_LOWER:/^[a-z]/,SEPARATOR_WITH_CHAR:/[_-]+(.)/g,EDGE_SEPARATORS:/^[_-]+|[_-]+$/g,CONSECUTIVE_SEPARATORS:/[_-]+/g};function J(x){return typeof x==="string"}function X(x){return Array.isArray(x)}function D(x){return typeof x==="object"&&x!==null&&!X(x)}function Y(x){return x instanceof Date||x instanceof RegExp||typeof x==="function"}function H(x,z){let L={};for(let[M,Q]of Object.entries(x)){let V=z(M);if(Y(Q))L[V]=Q;else if(X(Q))L[V]=Q.map((W)=>D(W)&&!X(W)?H(W,z):W);else if(D(Q))L[V]=H(Q,z);else L[V]=Q}return L}function Z(x){return x.replace(q.LEADING_UPPER,(z)=>z.toLowerCase()).replace(q.SEPARATOR_WITH_CHAR,(z,L)=>L.toUpperCase()).replace(q.EDGE_SEPARATORS,"")}function U(x){if(J(x))return Z(x);if(D(x))return H(x,Z);return x}function $(x){return x.replace(q.UPPERCASE,(z)=>`-${z.toLowerCase()}`).replace(q.CONSECUTIVE_SEPARATORS,"-").replace(q.EDGE_SEPARATORS,"")}function w(x){if(J(x))return $(x);if(D(x))return H(x,$);return x}function B(x){return x.replace(q.SEPARATOR_WITH_CHAR,(z,L)=>L.toUpperCase()).replace(q.EDGE_SEPARATORS,"").replace(q.LEADING_LOWER,(z)=>z.toUpperCase())}function _(x){if(J(x))return B(x);if(D(x))return H(x,B);return x}function F(x){return x.replace(q.UPPERCASE,(z)=>`_${z.toLowerCase()}`).replace(q.CONSECUTIVE_SEPARATORS,"_").replace(q.EDGE_SEPARATORS,"")}function d(x){if(J(x))return F(x);if(D(x))return H(x,F);return x}function I(x){return x.replace(q.UPPERCASE,(z)=>`_${z.toLowerCase()}`).replace(q.CONSECUTIVE_SEPARATORS,"_").replace(q.EDGE_SEPARATORS,"").toUpperCase()}function G(x){if(J(x))return I(x);if(D(x))return H(x,I);return x}export{G as toUpperCase,d as toSnakeCase,_ as toPascalCase,w as toKebabCase,U as toCamelCase};
1
+ var q={LEADING_UPPER:/^[A-Z]/,UPPERCASE:/[A-Z]/g,LEADING_LOWER:/^[a-z]/,SEPARATOR_WITH_CHAR:/[_-]+(.)/g,EDGE_SEPARATORS:/^[_-]+|[_-]+$/g,CONSECUTIVE_SEPARATORS:/[_-]+/g,CAMEL_CASE:/^[a-z][a-zA-Z0-9]*$/,KEBAB_CASE:/^[a-z][a-z0-9-]*$/,PASCAL_CASE:/^[A-Z][a-zA-Z0-9]*$/,SNAKE_CASE:/^[a-z][a-z0-9_]*$/,UPPER_SNAKE_CASE:/^[A-Z][A-Z0-9_]*$/};function z(x){return typeof x==="string"}function X(x){return Array.isArray(x)}function H(x){return typeof x==="object"&&x!==null&&!X(x)}function Y(x){return x instanceof Date||x instanceof RegExp||typeof x==="function"}function J(x,D){let L={};for(let[M,Q]of Object.entries(x)){let V=D(M);if(Y(Q))L[V]=Q;else if(X(Q))L[V]=Q.map((W)=>H(W)&&!X(W)?J(W,D):W);else if(H(Q))L[V]=J(Q,D);else L[V]=Q}return L}function Z(x){return x.replace(q.LEADING_UPPER,(D)=>D.toLowerCase()).replace(q.SEPARATOR_WITH_CHAR,(D,L)=>L.toUpperCase()).replace(q.EDGE_SEPARATORS,"")}function U(x){if(z(x))return Z(x);if(H(x))return J(x,Z);return x}function $(x){return x.replace(q.UPPERCASE,(D)=>`-${D.toLowerCase()}`).replace(q.CONSECUTIVE_SEPARATORS,"-").replace(q.EDGE_SEPARATORS,"")}function C(x){if(z(x))return $(x);if(H(x))return J(x,$);return x}function B(x){return x.replace(q.SEPARATOR_WITH_CHAR,(D,L)=>L.toUpperCase()).replace(q.EDGE_SEPARATORS,"").replace(q.LEADING_LOWER,(D)=>D.toUpperCase())}function w(x){if(z(x))return B(x);if(H(x))return J(x,B);return x}function F(x){return x.replace(q.UPPERCASE,(D)=>`_${D.toLowerCase()}`).replace(q.CONSECUTIVE_SEPARATORS,"_").replace(q.EDGE_SEPARATORS,"")}function K(x){if(z(x))return F(x);if(H(x))return J(x,F);return x}function I(x){return x.replace(q.UPPERCASE,(D)=>`_${D.toLowerCase()}`).replace(q.CONSECUTIVE_SEPARATORS,"_").replace(q.EDGE_SEPARATORS,"").toUpperCase()}function d(x){if(z(x))return I(x);if(H(x))return J(x,I);return x}function G(x){if(!z(x))return!1;return q.CAMEL_CASE.test(x)&&!x.includes("_")&&!x.includes("-")}function _(x){if(!z(x))return!1;return q.SNAKE_CASE.test(x)&&!x.includes("-")&&!q.UPPERCASE.test(x)}function y(x){if(!z(x))return!1;return q.KEBAB_CASE.test(x)&&!x.includes("_")&&!q.UPPERCASE.test(x)}function O(x){if(!z(x))return!1;return q.PASCAL_CASE.test(x)&&!x.includes("_")&&!x.includes("-")}function k(x){if(!z(x))return!1;return q.UPPER_SNAKE_CASE.test(x)&&!x.includes("-")}export{d as toUpperCase,K as toSnakeCase,w as toPascalCase,C as toKebabCase,U as toCamelCase,k as isUpperCase,_ as isSnakeCase,O as isPascalCase,y as isKebabCase,G as isCamelCase};
@@ -0,0 +1,30 @@
1
+ /**
2
+ * Checks if a string is in camelCase format.
3
+ * @param value - The value to check.
4
+ * @returns `true` if the value is in camelCase format, `false` otherwise.
5
+ */
6
+ export declare function isCamelCase(value: unknown): boolean;
7
+ /**
8
+ * Checks if a string is in snake_case format.
9
+ * @param value - The value to check.
10
+ * @returns `true` if the value is in snake_case format, `false` otherwise.
11
+ */
12
+ export declare function isSnakeCase(value: unknown): boolean;
13
+ /**
14
+ * Checks if a string is in kebab-case format.
15
+ * @param value - The value to check.
16
+ * @returns `true` if the value is in kebab-case format, `false` otherwise.
17
+ */
18
+ export declare function isKebabCase(value: unknown): boolean;
19
+ /**
20
+ * Checks if a string is in PascalCase format.
21
+ * @param value - The value to check.
22
+ * @returns `true` if the value is in PascalCase format, `false` otherwise.
23
+ */
24
+ export declare function isPascalCase(value: unknown): boolean;
25
+ /**
26
+ * Checks if a string is in UPPER_SNAKE_CASE format.
27
+ * @param value - The value to check.
28
+ * @returns `true` if the value is in UPPER_SNAKE_CASE format, `false` otherwise.
29
+ */
30
+ export declare function isUpperCase(value: unknown): boolean;
@@ -14,4 +14,14 @@ export declare const PATTERNS: {
14
14
  readonly EDGE_SEPARATORS: RegExp;
15
15
  /** Matches consecutive separators */
16
16
  readonly CONSECUTIVE_SEPARATORS: RegExp;
17
+ /** Matches a complete camelCase string */
18
+ readonly CAMEL_CASE: RegExp;
19
+ /** Matches a complete kebab-case string */
20
+ readonly KEBAB_CASE: RegExp;
21
+ /** Matches a complete PascalCase string */
22
+ readonly PASCAL_CASE: RegExp;
23
+ /** Matches a complete snake_case string */
24
+ readonly SNAKE_CASE: RegExp;
25
+ /** Matches a complete UPPER_SNAKE_CASE string */
26
+ readonly UPPER_SNAKE_CASE: RegExp;
17
27
  };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "caseforge",
3
- "version": "0.2.2",
3
+ "version": "0.4.0",
4
4
  "description": "caseforge - Effortlessly convert between snake_case, camelCase, and more in TypeScript. Zero dependencies, type-safe, and easy to use for any project.",
5
5
  "main": "./dist/index.js",
6
6
  "types": "./dist/index.d.ts",