@webergency-utils/typechecker 0.1.3 → 0.1.5
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 +1 -0
- package/dist/index.js +1 -0
- package/dist/runtime/casing.d.ts +29 -0
- package/dist/runtime/casing.js +78 -0
- package/dist/runtime/tags.d.ts +15 -0
- package/package.json +1 -1
package/dist/index.d.ts
CHANGED
package/dist/index.js
CHANGED
|
@@ -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/dist/runtime/tags.d.ts
CHANGED
|
@@ -42,3 +42,18 @@ type ApplyModifiers<T, EntriesList extends any[]> = EntriesList extends [[infer
|
|
|
42
42
|
* Utility type to decorate nested properties of a type with validation/transform modifiers without retyping the structure.
|
|
43
43
|
*/
|
|
44
44
|
export type WithModifiers<T, M> = ApplyModifiers<T, TuplifyUnion<Entries<M>>>;
|
|
45
|
+
/**
|
|
46
|
+
* Recursively resolves object properties, removing the optional `?` modifier
|
|
47
|
+
* from any properties that have a `tag.Default` applied.
|
|
48
|
+
*/
|
|
49
|
+
export type ResolveDefaults<T> = T extends Date | symbol | string | number | boolean | bigint | null | undefined | Function ? T : T extends Array<infer U> ? Array<ResolveDefaults<U>> : T extends object ? {
|
|
50
|
+
[K in keyof T as NonNullable<T[K]> extends {
|
|
51
|
+
readonly __default: any;
|
|
52
|
+
} ? K : never]-?: ResolveDefaults<Exclude<T[K], undefined>>;
|
|
53
|
+
} & {
|
|
54
|
+
[K in keyof T as NonNullable<T[K]> extends {
|
|
55
|
+
readonly __default: any;
|
|
56
|
+
} ? never : K]: ResolveDefaults<T[K]>;
|
|
57
|
+
} extends infer O ? {
|
|
58
|
+
[K in keyof O]: O[K];
|
|
59
|
+
} : never : T;
|