Skip to content

Commit 69acaa8

Browse files
committed
refactor(json-api-nestjs): move to project
use as separete package in next version
1 parent 57b6457 commit 69acaa8

File tree

90 files changed

+599
-77
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

90 files changed

+599
-77
lines changed
Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
export * from './lib/utils';
2+
export * from './lib/types';
Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
export type EntityField =
2+
| string
3+
| number
4+
| bigint
5+
| boolean
6+
| string[]
7+
| number[]
8+
| null
9+
| Date;
10+
11+
export type EntityProps<T> = {
12+
[P in keyof T]: T[P] extends EntityField ? P : never;
13+
}[keyof T];
14+
15+
export type EntityRelation<T> = {
16+
[P in keyof T]: T[P] extends EntityField ? never : P;
17+
}[keyof T];
Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
export * from './utils-string.type';
2+
export * from './query-type';
3+
export * from './entity-type';
4+
export * from './response-body';
Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,36 @@
1+
export enum QueryField {
2+
filter = 'filter',
3+
sort = 'sort',
4+
include = 'include',
5+
page = 'page',
6+
fields = 'fields',
7+
}
8+
9+
export enum FilterOperand {
10+
eq = 'eq',
11+
gt = 'gt',
12+
gte = 'gte',
13+
like = 'like',
14+
lt = 'lt',
15+
lte = 'lte',
16+
ne = 'ne',
17+
regexp = 'regexp',
18+
in = 'in',
19+
nin = 'nin',
20+
some = 'some',
21+
}
22+
23+
export enum FilterOperandOnlyInNin {
24+
in = 'in',
25+
nin = 'nin',
26+
}
27+
export enum FilterOperandOnlySimple {
28+
eq = 'eq',
29+
gt = 'gt',
30+
gte = 'gte',
31+
like = 'like',
32+
lt = 'lt',
33+
lte = 'lte',
34+
ne = 'ne',
35+
regexp = 'regexp',
36+
}
Lines changed: 76 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,76 @@
1+
import {
2+
EntityField,
3+
EntityProps,
4+
EntityRelation,
5+
TypeOfArray,
6+
ValueOf,
7+
} from '.';
8+
import { Collection } from '@mikro-orm/core';
9+
10+
export type PageProps = {
11+
totalItems: number;
12+
pageNumber: number;
13+
pageSize: number;
14+
};
15+
16+
export type DebugMetaProps = Partial<{
17+
time: number;
18+
}>;
19+
20+
export type MainData<T = string> = {
21+
type: T;
22+
id: string;
23+
};
24+
25+
export type Links = {
26+
self: string;
27+
related?: string;
28+
};
29+
30+
export type Attributes<D> = {
31+
[P in EntityProps<D>]?: D[P] extends EntityField ? D[P] : TypeOfArray<D[P]>;
32+
};
33+
34+
export type DataResult<E, S = string> = E extends unknown[]
35+
? MainData<S>[]
36+
: E extends Collection<any>
37+
? MainData<S>[]
38+
: MainData<S> | null;
39+
40+
export type Data<E, S = string> = {
41+
data?: DataResult<E, S>;
42+
};
43+
44+
export type Relationships<T> = {
45+
[P in EntityRelation<T>]?: {
46+
links: Links;
47+
} & Data<T[P], P>;
48+
};
49+
50+
export type Include<T> = ValueOf<{
51+
[P in EntityRelation<T>]: ResourceData<TypeOfArray<T[P]>>;
52+
}>;
53+
54+
export type ResourceData<T> = MainData & {
55+
attributes?: Attributes<T>;
56+
relationships?: Relationships<T>;
57+
links: Omit<Links, 'related'>;
58+
};
59+
60+
export type MetaProps<T, R = null> = R extends null ? T : T & R;
61+
62+
export type ResourceObject<
63+
T,
64+
R extends 'object' | 'array' = 'object',
65+
M = null
66+
> = {
67+
meta: R extends 'array'
68+
? MetaProps<PageProps & DebugMetaProps, M>
69+
: MetaProps<DebugMetaProps, M>;
70+
data: R extends 'array' ? ResourceData<T>[] : ResourceData<T>;
71+
included?: Include<T>[];
72+
};
73+
74+
export type ResourceObjectRelationships<E, K extends EntityRelation<E>> = {
75+
meta: DebugMetaProps;
76+
} & Required<Data<E[K], K>>;
Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
import type { Collection } from '@mikro-orm/core';
2+
3+
export type KebabCase<S> = S extends `${infer C}${infer T}`
4+
? KebabCase<T> extends infer U
5+
? U extends string
6+
? T extends Uncapitalize<T>
7+
? `${Uncapitalize<C>}${U}`
8+
: `${Uncapitalize<C>}-${U}`
9+
: never
10+
: never
11+
: S;
12+
13+
export type KebabToCamelCase<S extends string> =
14+
S extends `${infer T}-${infer U}-${infer V}`
15+
? `${T}${Capitalize<U>}${Capitalize<KebabToCamelCase<V>>}`
16+
: S extends `${infer T}-${infer U}`
17+
? `${Capitalize<T>}${Capitalize<KebabToCamelCase<U>>}`
18+
: S;
19+
20+
export type TypeOfArray<T> = T extends (infer U)[]
21+
? U
22+
: T extends Collection<infer U>
23+
? U
24+
: T;
25+
26+
export type ValueOf<T> = T[keyof T];
Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
export * from './string-utils';
2+
export * from './object-utils';
Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
import { kebabToCamel } from './string-utils';
2+
3+
export const ObjectTyped = {
4+
keys: Object.keys as <T extends {}>(yourObject: T) => Array<keyof T>,
5+
values: Object.values as <U extends {}>(yourObject: U) => Array<U[keyof U]>,
6+
entries: Object.entries as <O extends {}>(
7+
yourObject: O
8+
) => Array<[keyof O, O[keyof O]]>,
9+
fromEntries: Object.fromEntries as <K extends string, V>(
10+
yourObjectEntries: [K, V][]
11+
) => Record<K, V>,
12+
};
13+
14+
export function isObject(item: unknown): item is object {
15+
return typeof item === 'object' && !Array.isArray(item) && item !== null;
16+
}
17+
18+
export function createEntityInstance<E>(name: string): E {
19+
const entityName = kebabToCamel(name);
20+
return Function('return new class ' + entityName + '{}')();
21+
}
Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,42 @@
1+
import {
2+
camelToKebab,
3+
snakeToCamel,
4+
isString,
5+
kebabToCamel,
6+
} from './string-utils';
7+
8+
describe('Test utils', () => {
9+
it('camelToKebab', () => {
10+
const result = camelToKebab('ApproverGroups');
11+
const result1 = camelToKebab('Users');
12+
13+
expect(result).toBe('approver-groups');
14+
expect(result1).toBe('users');
15+
});
16+
17+
it('snakeToCamel', () => {
18+
const result = snakeToCamel('test_test');
19+
const result1 = snakeToCamel('test-test');
20+
const result2 = snakeToCamel('testTest');
21+
const result3 = snakeToCamel('event_incident_typeFK');
22+
expect(result).toBe('testTest');
23+
expect(result1).toBe('testTest');
24+
expect(result2).toBe('testTest');
25+
expect(result3).toBe('eventIncidentTypeFK');
26+
});
27+
28+
it('isString', () => {
29+
expect(isString('string')).toBe(true);
30+
expect(isString(String('string'))).toBe(true);
31+
expect(isString(new Date())).toBe(false);
32+
expect(isString(class {})).toBe(false);
33+
});
34+
35+
it('kebabToCamel', () => {
36+
const type = 'users-group';
37+
const type1 = 'users';
38+
39+
expect(kebabToCamel(type)).toBe('UsersGroup');
40+
expect(kebabToCamel(type1)).toBe('Users');
41+
});
42+
});
Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,38 @@
1+
import { KebabToCamelCase, KebabCase } from '../types';
2+
3+
export function isString<T, P extends T>(value: T): value is P {
4+
return typeof value === 'string' || value instanceof String;
5+
}
6+
7+
export function snakeToCamel(str: string): string {
8+
if (!str.match(/[\s_-]/g)) {
9+
return str;
10+
}
11+
return str.replace(/([-_][a-z])/g, (group) =>
12+
group.toUpperCase().replace('-', '').replace('_', '')
13+
);
14+
}
15+
16+
export function camelToKebab<S extends string>(string: S): KebabCase<S> {
17+
return string
18+
.replace(/((?<=[a-z\d])[A-Z]|(?<=[A-Z\d])[A-Z](?=[a-z]))/g, '-$1')
19+
.toLowerCase() as KebabCase<S>;
20+
}
21+
22+
export function upperFirstLetter<S extends string>(string: S): Capitalize<S> {
23+
return (string.charAt(0).toUpperCase() + string.slice(1)) as Capitalize<S>;
24+
}
25+
26+
export function kebabToCamel<S extends string>(str: S): KebabToCamelCase<S> {
27+
return str
28+
.split('-')
29+
.map((i) => i.charAt(0).toUpperCase() + i.substring(1))
30+
.join('') as KebabToCamelCase<S>;
31+
}
32+
33+
export function capitalizeFirstChar(str: string) {
34+
return str
35+
.split('-')
36+
.map((i) => i.charAt(0).toUpperCase() + i.substring(1))
37+
.join('');
38+
}

0 commit comments

Comments
 (0)