-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Signed-off-by: Chris Lahaye <mail@chrislahaye.com>
- Loading branch information
0 parents
commit 81d1f78
Showing
7 changed files
with
1,148 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,16 @@ | ||
{ | ||
"root": true, | ||
"parser": "@typescript-eslint/parser", | ||
"plugins": [ | ||
"@typescript-eslint" | ||
], | ||
"extends": [ | ||
"eslint:recommended", | ||
"plugin:@typescript-eslint/eslint-recommended", | ||
"plugin:@typescript-eslint/recommended" | ||
], | ||
"rules": { | ||
"@typescript-eslint/no-explicit-any": [0], | ||
"no-prototype-builtins": [0] | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,3 @@ | ||
lib/**/*.d.ts | ||
lib/**/*.js | ||
node_modules |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,100 @@ | ||
# type-graphql-utils | ||
[![npm version](https://img.shields.io/npm/v/type-graphql-utils)](https://www.npmjs.com/package/type-graphql-utils) | ||
[![npm downloads](https://img.shields.io/npm/dm/type-graphql-utils.svg)](https://www.npmjs.com/package/type-graphql-utils) | ||
[![Known Vulnerabilities](https://snyk.io/test/github/chrislahaye/type-graphql-utils/badge.svg)](https://snyk.io/test/github/chrislahaye/type-graphql-utils) | ||
|
||
This module provides utilities to transform [type-graphql](https://www.npmjs.com/package/type-graphql) types. | ||
|
||
## Install | ||
|
||
```shell | ||
yarn install type-graphql-utils | ||
``` | ||
|
||
## Usage | ||
|
||
```ts | ||
import { Field, InputType, ObjectType } from 'type-graphql'; | ||
import { Pick, Partial } from 'type-graphql-utils'; | ||
|
||
@ObjectType() | ||
class User { | ||
@Field() | ||
id!: number; | ||
|
||
@Field() | ||
name!: string; | ||
|
||
@Field() | ||
email!: string; | ||
} | ||
``` | ||
|
||
``` | ||
type User { | ||
id: String! | ||
name: String! | ||
email: String! | ||
} | ||
``` | ||
|
||
```ts | ||
@InputType() | ||
class UserInput1 extends Partial(User) { | ||
// extra fields | ||
} | ||
``` | ||
|
||
``` | ||
input UserInput1 { | ||
id: String | ||
name: String | ||
email: String | ||
} | ||
``` | ||
|
||
```ts | ||
@InputType() | ||
class UserInput2 extends Pick(User, { name: 1 }) { } | ||
``` | ||
|
||
``` | ||
input UserInput2 { | ||
name: String! | ||
} | ||
``` | ||
|
||
```ts | ||
@InputType() | ||
class UserInput3 extends Required(Partial(User), { id: 1 }) {} | ||
``` | ||
|
||
``` | ||
input UserInput3 { | ||
id: String! | ||
name: String | ||
email: String | ||
} | ||
``` | ||
|
||
## API | ||
|
||
**`BaseClass`**: The type to transform. A class decorated with `@InputType()` or `@ObjectType()`. | ||
|
||
**`names`**: The fields to transform. A potentially optional object containing the names of the fields as key, e.g. `{ id: 1, name: 1 }`. The TypeScript type enforces all values to be *1*, but the value isn't actually used. We just need the names as object to determine if a name is included in constant time. | ||
|
||
### `Pick(BaseClass, names)` | ||
|
||
Constructs a type by picking the keys of `names` from `BaseClass`. | ||
|
||
### `Omit(BaseClass, names)` | ||
|
||
Constructs a type by picking all fields from `BaseClass` and then removing the keys of `names`. | ||
|
||
### `Partial(BaseClass, [names])` | ||
|
||
Constructs a type by picking all fields from `BaseClass` and then setting the keys of `names` to optional. The opposite of Required. By default, `names` contains all names. | ||
|
||
### `Required(BaseClass, [names])` | ||
|
||
Constructs a type by picking all fields from `BaseClass` and then setting the keys of `names` to required. The opposite of Partial. By default, `names` contains all names. |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,65 @@ | ||
import { ClassType, getMetadataStorage, InputType, registerEnumType, ObjectType } from 'type-graphql'; | ||
import type { FieldMetadata } from 'type-graphql/dist/metadata/definitions'; | ||
|
||
type PartialBy<T, K extends keyof T> = Omit<T, K> & Partial<Pick<T, K>>; | ||
type RequiredBy<T, K extends keyof T> = Omit<T, K> & Required<Pick<T, K>>; | ||
|
||
const metadata = getMetadataStorage(); | ||
|
||
export function buildEnum<T extends ClassType>( | ||
Class: T, | ||
name: string, | ||
): Record<keyof InstanceType<T>, keyof InstanceType<T>> { | ||
const enumObj = {} as Record<keyof InstanceType<T>, keyof InstanceType<T>>; | ||
|
||
metadata.fields.forEach((f) => { | ||
if (f.target !== Class && !f.target.isPrototypeOf(Class)) return; | ||
|
||
enumObj[f.name as keyof InstanceType<T>] = f.name; | ||
}); | ||
|
||
registerEnumType(enumObj, { name }); | ||
|
||
return enumObj; | ||
} | ||
|
||
export function buildType( | ||
BaseClass: ClassType, | ||
buildFn: (f: FieldMetadata) => FieldMetadata | FieldMetadata[] | undefined, | ||
): any { | ||
@InputType({ isAbstract: true }) | ||
@ObjectType({ isAbstract: true }) | ||
class ChildClass { } | ||
|
||
metadata.fields.forEach((f) => { | ||
if (f.target !== BaseClass && !f.target.isPrototypeOf(BaseClass)) return; | ||
|
||
const field = buildFn(f); | ||
|
||
if (field instanceof Array) { | ||
field.forEach((field) => | ||
metadata.fields.push({ ...field, target: ChildClass }) | ||
); | ||
} else if (field) { | ||
metadata.fields.push({ ...field, target: ChildClass }) | ||
} | ||
}); | ||
|
||
return ChildClass; | ||
} | ||
|
||
export function Pick<T extends ClassType, K extends keyof InstanceType<T>>(BaseClass: T, names: Record<K, 1>): ClassType<Pick<InstanceType<T>, K>> { | ||
return buildType(BaseClass, (f) => f.name in names ? f : undefined); | ||
} | ||
|
||
export function Omit<T extends ClassType, K extends keyof InstanceType<T>>(BaseClass: T, names: Record<K, 1>): ClassType<Omit<InstanceType<T>, K>> { | ||
return buildType(BaseClass, (f) => f.name in names ? undefined : f); | ||
} | ||
|
||
export function Partial<T extends ClassType, K extends keyof InstanceType<T> = keyof InstanceType<T>>(BaseClass: T, names?: Record<K, 1>): ClassType<PartialBy<InstanceType<T>, K>> { | ||
return buildType(BaseClass, (f) => !names || f.name in names ? { ...f, typeOptions: { ...f.typeOptions, nullable: true } } : f); | ||
} | ||
|
||
export function Required<T extends ClassType, K extends keyof InstanceType<T> = keyof InstanceType<T>>(BaseClass: T, names?: Record<K, 1>): ClassType<RequiredBy<InstanceType<T>, K>> { | ||
return buildType(BaseClass, (f) => !names || f.name in names ? { ...f, typeOptions: { ...f.typeOptions, nullable: false } } : f); | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,38 @@ | ||
{ | ||
"name": "type-graphql-utils", | ||
"version": "1.0.0", | ||
"description": "utilities to transform type-graphql types", | ||
"main": "lib/index.js", | ||
"types": "lib/index.d.ts", | ||
"files": [ | ||
"lib/**/*" | ||
], | ||
"scripts": { | ||
"prepare": "install-peers && tsc", | ||
"build": "tsc", | ||
"watch": "tsc -w" | ||
}, | ||
"repository": { | ||
"type": "git", | ||
"url": "github:ChrisLahaye/type-graphql-utils" | ||
}, | ||
"keywords": [ | ||
"type-graphql" | ||
], | ||
"author": "Chris Lahaye <mail@chrislahaye.com>", | ||
"license": "MIT", | ||
"bugs": { | ||
"url": "https://github.com/ChrisLahaye/type-graphql-utils/issues" | ||
}, | ||
"devDependencies": { | ||
"@typescript-eslint/eslint-plugin": "^5.32.0", | ||
"@typescript-eslint/parser": "^5.32.0", | ||
"eslint": "^8.21.0", | ||
"install-peers-cli": "^2.2.0", | ||
"typescript": "^4.7.4" | ||
}, | ||
"peerDependencies": { | ||
"graphql": "^15", | ||
"type-graphql": "^1" | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,11 @@ | ||
{ | ||
"compilerOptions": { | ||
"declaration": true, | ||
"lib": ["ES2020"], | ||
"module": "commonjs", | ||
"target": "ES2020", | ||
"skipLibCheck": true, | ||
"strict": true, | ||
"experimentalDecorators": true | ||
} | ||
} |
Oops, something went wrong.