@webergency-utils/typechecker 0.1.3 → 0.1.4

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/dist/index.d.ts CHANGED
@@ -18,3 +18,4 @@ export declare function validate<T>(input: unknown, options?: ValidationMode | V
18
18
  export declare function jsonSchema<T>(): any;
19
19
  export * from './runtime/validators.js';
20
20
  export * from './runtime/tags.js';
21
+ export * from './runtime/casing.js';
package/dist/index.js CHANGED
@@ -1,2 +1,3 @@
1
1
  export * from './runtime/validators.js';
2
2
  export * from './runtime/tags.js';
3
+ export * from './runtime/casing.js';
@@ -0,0 +1,29 @@
1
+ export type CasingFormat = 'snake_case' | 'SNAKE_CASE' | 'camelCase' | 'camelCaseID' | 'PascalCase' | 'PascalCaseID' | 'kebab-case' | 'dot.case';
2
+ export interface ConvertCasingOptions {
3
+ preserveEnds?: boolean;
4
+ }
5
+ type SplitCamel<S extends string> = S extends `${infer L}${infer R}` ? L extends Uppercase<L> ? L extends Lowercase<L> ? `${L}${SplitCamel<R>}` : `_${Lowercase<L>}${SplitCamel<R>}` : `${L}${SplitCamel<R>}` : S;
6
+ type NormalizeCamelKebabDot<S extends string> = S extends `${infer L}-${infer R}` ? `${NormalizeCamelKebabDot<L>}_${NormalizeCamelKebabDot<R>}` : S extends `${infer L}.${infer R}` ? `${NormalizeCamelKebabDot<L>}_${NormalizeCamelKebabDot<R>}` : SplitCamel<S> extends `_${infer T}` ? T : SplitCamel<S>;
7
+ type NormalizeString<S extends string> = S extends Uppercase<S> ? Lowercase<S> : NormalizeCamelKebabDot<S>;
8
+ type CleanUnderscores<S extends string> = S extends `${infer L}__${infer R}` ? CleanUnderscores<`${L}_${R}`> : S extends `_${infer R}` ? CleanUnderscores<R> : S extends `${infer L}_` ? CleanUnderscores<L> : S;
9
+ type Normalized<S extends string> = CleanUnderscores<NormalizeString<S>>;
10
+ type SnakeToCamel<S extends string> = S extends `${infer L}_${infer R}` ? `${L}${Capitalize<SnakeToCamel<R>>}` : S;
11
+ type SnakeToPascal<S extends string> = Capitalize<SnakeToCamel<S>>;
12
+ type SnakeToKebab<S extends string> = S extends `${infer L}_${infer R}` ? `${L}-${SnakeToKebab<R>}` : S;
13
+ type SnakeToDot<S extends string> = S extends `${infer L}_${infer R}` ? `${L}.${SnakeToDot<R>}` : S;
14
+ type SnakeToUpperSnake<S extends string> = Uppercase<S>;
15
+ type ReplaceId<S extends string> = S extends `${infer L}Id` ? `${L}ID` : S extends `id` ? `ID` : S extends `Id` ? `ID` : S;
16
+ type ToCamelCaseID<S extends string> = ReplaceId<SnakeToCamel<S>>;
17
+ type ToPascalCaseID<S extends string> = ReplaceId<SnakeToPascal<S>>;
18
+ type Leading<S extends string> = S extends `_${infer R}` ? `_${Leading<R>}` : S extends `-${infer R}` ? `-${Leading<R>}` : S extends `.${infer R}` ? `.${Leading<R>}` : S extends `$${infer R}` ? `$${Leading<R>}` : '';
19
+ type Trailing<S extends string> = S extends `${infer L}_` ? `${Trailing<L>}_` : S extends `${infer L}-` ? `${Trailing<L>}-` : S extends `${infer L}.` ? `${Trailing<L>}.` : S extends `${infer L}$` ? `${Trailing<L>}$` : '';
20
+ type StripLeading<S extends string> = S extends `_${infer R}` ? StripLeading<R> : S extends `-${infer R}` ? StripLeading<R> : S extends `.${infer R}` ? StripLeading<R> : S extends `$${infer R}` ? StripLeading<R> : S;
21
+ type StripTrailing<S extends string> = S extends `${infer L}_` ? StripTrailing<L> : S extends `${infer L}-` ? StripTrailing<L> : S extends `${infer L}.` ? StripTrailing<L> : S extends `${infer L}$` ? StripTrailing<L> : S;
22
+ type FormatCoreCasing<S extends string, Casing extends CasingFormat> = Casing extends 'snake_case' ? Normalized<S> : Casing extends 'SNAKE_CASE' ? SnakeToUpperSnake<Normalized<S>> : Casing extends 'camelCase' ? SnakeToCamel<Normalized<S>> : Casing extends 'PascalCase' ? SnakeToPascal<Normalized<S>> : Casing extends 'kebab-case' ? SnakeToKebab<Normalized<S>> : Casing extends 'dot.case' ? SnakeToDot<Normalized<S>> : Casing extends 'camelCaseID' ? ToCamelCaseID<Normalized<S>> : Casing extends 'PascalCaseID' ? ToPascalCaseID<Normalized<S>> : S;
23
+ export type FormatCasing<S extends string, Casing extends CasingFormat, Options extends ConvertCasingOptions = {}> = Options['preserveEnds'] extends false ? FormatCoreCasing<StripLeading<StripTrailing<S>>, Casing> : `${Leading<S>}${FormatCoreCasing<StripLeading<StripTrailing<S>>, Casing>}${Trailing<S>}`;
24
+ type ExtractArray<T> = T extends any[] ? T : never;
25
+ export type ConvertPropertyCasing<T, Casing extends CasingFormat, Options extends ConvertCasingOptions = {}> = T extends [infer F, ...infer R] ? [ConvertPropertyCasing<F, Casing, Options>, ...ExtractArray<ConvertPropertyCasing<R, Casing, Options>>] : T extends (infer E)[] ? ConvertPropertyCasing<E, Casing, Options>[] : T extends string | number | boolean | symbol | bigint | null | undefined ? T : T extends Date | RegExp | Function | Map<any, any> | Set<any> | Promise<any> ? T : T extends object ? {
26
+ [K in keyof T as K extends string ? FormatCasing<K, Casing, Options> : K]: ConvertPropertyCasing<T[K], Casing, Options>;
27
+ } : T;
28
+ export declare function convertPropertyCasing<T, C extends CasingFormat>(obj: T, casing: C, options?: ConvertCasingOptions): ConvertPropertyCasing<T, C>;
29
+ export {};
@@ -0,0 +1,78 @@
1
+ function normalizeString(str) {
2
+ if (/^[A-Z0-9_]+$/.test(str)) {
3
+ str = str.toLowerCase();
4
+ }
5
+ str = str.replace(/[-\.]/g, '_');
6
+ str = str.replace(/([a-z0-9])([A-Z])/g, '$1_$2').toLowerCase();
7
+ return str.replace(/_+/g, '_').replace(/^_|_$/g, '');
8
+ }
9
+ function formatCasing(str, casing, options = {}) {
10
+ const preserveEnds = options.preserveEnds !== false;
11
+ let leading = '';
12
+ let trailing = '';
13
+ let core = str;
14
+ if (preserveEnds) {
15
+ const match = str.match(/^([_\-\.\$]*)(.*?)([_\-\.\$]*)$/);
16
+ if (match) {
17
+ leading = match[1];
18
+ core = match[2];
19
+ trailing = match[3];
20
+ }
21
+ }
22
+ else {
23
+ core = str.replace(/^([_\-\.\$]*)/, '').replace(/([_\-\.\$]*)$/, '');
24
+ }
25
+ const normalized = normalizeString(core);
26
+ let formatted = '';
27
+ if (casing === 'snake_case') {
28
+ formatted = normalized;
29
+ }
30
+ else if (casing === 'SNAKE_CASE') {
31
+ formatted = normalized.toUpperCase();
32
+ }
33
+ else if (casing === 'kebab-case') {
34
+ formatted = normalized.replace(/_/g, '-');
35
+ }
36
+ else if (casing === 'dot.case') {
37
+ formatted = normalized.replace(/_/g, '.');
38
+ }
39
+ else {
40
+ const camel = normalized.replace(/_([a-z0-9])/g, (match, p1) => p1.toUpperCase());
41
+ if (casing === 'camelCase') {
42
+ formatted = camel;
43
+ }
44
+ else if (casing === 'camelCaseID') {
45
+ formatted = camel.replace(/Id$/, 'ID');
46
+ }
47
+ else {
48
+ const pascal = camel.charAt(0).toUpperCase() + camel.slice(1);
49
+ if (casing === 'PascalCase') {
50
+ formatted = pascal;
51
+ }
52
+ else if (casing === 'PascalCaseID') {
53
+ formatted = pascal.replace(/Id$/, 'ID');
54
+ }
55
+ else {
56
+ formatted = core;
57
+ }
58
+ }
59
+ }
60
+ return preserveEnds ? `${leading}${formatted}${trailing}` : formatted;
61
+ }
62
+ export function convertPropertyCasing(obj, casing, options) {
63
+ if (!obj || typeof obj !== 'object') {
64
+ return obj;
65
+ }
66
+ if (obj instanceof Date || obj instanceof RegExp || obj instanceof Map || obj instanceof Set || typeof obj === 'function') {
67
+ return obj;
68
+ }
69
+ if (Array.isArray(obj)) {
70
+ return obj.map((item) => convertPropertyCasing(item, casing, options));
71
+ }
72
+ const result = {};
73
+ for (const [key, value] of Object.entries(obj)) {
74
+ const newKey = formatCasing(key, casing, options);
75
+ result[newKey] = convertPropertyCasing(value, casing, options);
76
+ }
77
+ return result;
78
+ }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@webergency-utils/typechecker",
3
- "version": "0.1.3",
3
+ "version": "0.1.4",
4
4
  "type": "module",
5
5
  "description": "TypeScript compiler plugin for runtime validation",
6
6
  "author": "radixxko",