diff --git a/README.md b/README.md index 88ec4b9..ed34444 100644 --- a/README.md +++ b/README.md @@ -146,7 +146,7 @@ ts-gql isn't trying to be a GraphQL client, it's only trying to type GraphQL que ## Non-Goals -- ~~Improve the experience of creating GraphQL APIs, [Nexus](https://www.nexusjs.org/) does a really great job of this~~ (This may change! I'm experimenting with an API, it will be disconnected from the rest of ts-gql but will likely live in the same repo because it serves a similar goal of making GraphQL type-safe) +- Improve the experience of creating GraphQL APIs ## Thanks diff --git a/index.d.ts b/index.d.ts deleted file mode 100644 index d95c37f..0000000 --- a/index.d.ts +++ /dev/null @@ -1 +0,0 @@ -// this does nothing but tsd requires it diff --git a/index.test-d.ts b/index.test-d.ts deleted file mode 100644 index acfd29b..0000000 --- a/index.test-d.ts +++ /dev/null @@ -1,750 +0,0 @@ -import { expectType } from "tsd"; -import { - types, - bindTypesToContext, - Arg, - InferValueFromInputType, - InputObjectType, - ScalarType, - InferValueFromOutputType, -} from "./packages/schema"; -import * as typesWithContext from "./test-types-with-context"; - -typesWithContext.arg({ - type: typesWithContext.Boolean, -}); - -const someEnum = types.enum({ - name: "SomeEnum", - values: types.enumValues(["a", "b"]), -}); - -const enumArg = types.arg({ - type: someEnum, -}); - -const Something = types.inputObject({ - name: "Something", - fields: { - nullableString: types.arg({ type: types.String }), - nullableStringWithDefaultValue: types.arg({ - type: types.String, - defaultValue: "something", - }), - nonNullableString: types.arg({ - type: types.nonNull(types.String), - }), - nonNullableStringWithDefaultValue: types.arg({ - type: types.nonNull(types.String), - defaultValue: "something", - }), - enum: enumArg, - }, -}); - -{ - type SomethingType = InferValueFromInputType; - - const valOfSomethingType: SomethingType = undefined as any; - - expectType<{ - readonly nullableString: string | null | undefined; - readonly nullableStringWithDefaultValue: string | null; - readonly nonNullableString: string; - readonly nonNullableStringWithDefaultValue: string; - readonly enum: "a" | "b" | null | undefined; - } | null>(valOfSomethingType); -} - -{ - type RecursiveInput = InputObjectType<{ - nullableString: Arg, any>; - recursive: Arg; - }>; - - const Recursive: RecursiveInput = types.inputObject({ - name: "Recursive", - fields: () => ({ - nullableString: types.arg({ type: types.String }), - recursive: types.arg({ type: Recursive }), - }), - }); - - type RecursiveInputType = InferValueFromInputType; - - const valOfRecursiveInputType: RecursiveInputType = undefined as any; - - type RecursiveTypeExpect = { - readonly nullableString: string | null | undefined; - readonly recursive: RecursiveTypeExpect | null | undefined; - } | null; - - expectType(valOfRecursiveInputType); -} - -{ - const nonRecursiveFields = { - nullableString: types.arg({ type: types.String }), - }; - - type RecursiveInput = InputObjectType< - typeof nonRecursiveFields & { - recursive: Arg; - } - >; - - const Recursive: RecursiveInput = types.inputObject({ - name: "Recursive", - fields: () => ({ - ...nonRecursiveFields, - recursive: types.arg({ type: Recursive }), - }), - }); - - type RecursiveInputType = InferValueFromInputType; - - const valOfRecursiveInputType: RecursiveInputType = undefined as any; - - type RecursiveTypeExpect = { - readonly nullableString: string | null | undefined; - readonly recursive: RecursiveTypeExpect | null | undefined; - } | null; - - expectType(valOfRecursiveInputType); -} - -// TODO: if possible, this should error. not really a massive deal if it doesn't though tbh -// since if people forget to add something here, they will see an error when they try to read a field that doesn't exist -export const ExplicitDefinitionMissingFieldsThatAreSpecifiedInCalls: InputObjectType<{ - nullableString: Arg; -}> = types.inputObject({ - name: "ExplicitDefinitionMissingFieldsThatAreSpecifiedInCalls", - fields: () => ({ - nullableString: types.arg({ type: types.String }), - another: types.arg({ type: types.String }), - }), -}); - -types.object<{ id: string } | { id: "str" }>()({ - name: "Node", - fields: { - id: types.field({ - type: types.nonNull(types.ID), - }), - }, -}); - -types.object<{ id: string } | { id: boolean }>()({ - name: "Node", - fields: { - // @ts-expect-error - id: types.field({ - type: types.nonNull(types.ID), - }), - }, -}); - -{ - const types = { - ...typesWithContext, - ...bindTypesToContext<{ isAdminUIBuildProcess: true }>(), - }; - - const SomeOutput = types.object<{ thing: boolean }>()({ - name: "Something", - fields: { - thing: types.field({ type: types.nonNull(types.Boolean) }), - }, - }); - - const nonNullSomeOutput = types.nonNull(SomeOutput); - - type OutputTypeWithNull = InferValueFromOutputType; - - expectType({ thing: true }); - expectType(null); - - type OutputTypeWithoutNull = InferValueFromOutputType< - typeof nonNullSomeOutput - >; - - expectType({ thing: true }); - - types.field({ - type: SomeOutput, - resolve() { - if (Math.random() > 0.5) { - return null; - } - return { thing: false }; - }, - }); - - types.field({ - type: types.nonNull(types.list(nonNullSomeOutput)), - resolve() { - return [{ thing: false }]; - }, - }); - - type FieldIdentifier = { listKey: string; fieldPath: string }; - - types.fields<{ path: string; listKey: string }>()({ - thing: types.field({ - resolve(rootVal) { - return { fieldPath: rootVal.path, listKey: rootVal.listKey }; - }, - type: types.nonNull( - types.object()({ - name: "KeystoneAdminUIFieldMetaListView", - fields: { - fieldMode: types.field({ - type: types.nonNull( - types.enum({ - name: "KeystoneAdminUIFieldMetaListViewFieldMode", - values: types.enumValues(["read", "hidden"]), - }) - ), - async resolve(rootVal, args, context) { - return "read" as const; - }, - }), - }, - }) - ), - }), - }); -} - -// types.interface<{ kind: "one"; id: string } | { kind: "two"; id: boolean }>()({ -// name: "Node", -// fields: { -// id: types.field({ -// type: types.nonNull(types.ID), -// // args: {}, -// resolve({}, {}) { -// return true; -// }, -// }), -// }, -// }); - -{ - const sharedFields = types.fields<{ something: string }>()({ - something: types.field({ - type: types.nonNull(types.String), - }), - }); - - const sharedFieldsWithUnkownRootVal = types.fields()({ - other: types.field({ - type: types.nonNull(types.String), - resolve() { - return ""; - }, - }), - }); - - types.object<{ something: string; other: string }>()({ - name: "", - fields: { - ...sharedFields, - ...sharedFieldsWithUnkownRootVal, - }, - }); - - types.object<{ other: string }>()({ - name: "", - fields: sharedFieldsWithUnkownRootVal, - }); - - types.object<{ other: string }>()({ - name: "", - // @ts-expect-error - fields: sharedFields, - }); -} - -{ - const typesWithContextA = bindTypesToContext<{ something: boolean }>(); - - const typesWithContextB = - bindTypesToContext<{ something: boolean; other: string }>(); - - { - typesWithContextB.object<{ thing: string }>()({ - name: "", - fields: { - thing: typesWithContextA.field({ - type: types.String, - }), - }, - }); - typesWithContextA.object<{ thing: string }>()({ - name: "", - fields: { - // @ts-expect-error - thing: typesWithContextB.field({ - type: types.String, - }), - }, - }); - } - - { - const fromA = typesWithContextA.object<{}>()({ - name: "Something", - fields: { - a: typesWithContextA.field({ - type: types.String, - resolve(rootVal, args, context) { - expectType<{ something: boolean }>(context); - return ""; - }, - }), - }, - }); - const fromBWithA = typesWithContextB.object()({ - name: "Other", - fields: { - a: typesWithContextB.field({ - type: fromA, - resolve(rootVal, args, context) { - expectType<{ something: boolean; other: string }>(context); - return {}; - }, - }), - }, - }); - typesWithContextA.object<{}>()({ - name: "Something", - fields: { - a: typesWithContextA.field({ - // @ts-expect-error - type: fromBWithA, - resolve(rootVal, args, context) { - expectType<{ something: boolean }>(context); - }, - }), - }, - }); - typesWithContextA.object<{}>()({ - name: "Something", - fields: { - a: typesWithContextA.field({ - // @ts-expect-error - type: types.list(fromBWithA), - resolve(rootVal, args, context) { - expectType<{ something: boolean }>(context); - }, - }), - }, - }); - typesWithContextA.object<{}>()({ - name: "Something", - fields: { - a: typesWithContextA.field({ - // @ts-expect-error - type: types.list(types.list(fromBWithA)), - resolve(rootVal, args, context) { - expectType<{ something: boolean }>(context); - }, - }), - }, - }); - typesWithContextA.object<{}>()({ - name: "Something", - fields: { - a: typesWithContextA.field({ - // @ts-expect-error - type: types.nonNull(fromBWithA), - resolve(rootVal, args, context) { - expectType<{ something: boolean }>(context); - }, - }), - }, - }); - typesWithContextA.object<{}>()({ - name: "Something", - fields: { - a: typesWithContextA.field({ - // @ts-expect-error - type: types.list(types.nonNull(fromBWithA)), - resolve(rootVal, args, context) { - expectType<{ something: boolean }>(context); - }, - }), - }, - }); - } -} - -{ - const nonNullThing = types.nonNull(types.String); - types.nonNull( - // @ts-expect-error - nonNullThing - ); -} - -{ - const Node = types.interface()({ - name: "Node", - fields: { - id: types.interfaceField({ type: types.ID }), - }, - }); - - types.object<{ id: string }>()({ - name: "NodeImpl", - interfaces: [Node], - fields: { id: types.field({ type: types.ID }) }, - }); - - types.object<{ thing: string }>()({ - name: "NodeImpl", - interfaces: [Node], - // @ts-expect-error - fields: {}, - }); - - types.object<{ thing: string }>()({ - name: "NodeImpl", - interfaces: [Node], - // @ts-expect-error - fields: { - thing: types.field({ type: types.ID }), - }, - }); - types.object<{ id: number }>()({ - name: "NodeImpl", - interfaces: [Node], - fields: { - // @ts-expect-error - id: types.field({ type: types.Int }), - }, - }); - types.object<{ id: number }>()({ - name: "NodeImpl", - interfaces: [Node], - fields: { - // @ts-expect-error - id: types.field({ type: types.ID }), - }, - }); - - { - const NodeAnother = types.interface()({ - name: "Node", - fields: { - id: types.interfaceField({ type: types.Int }), - }, - }); - - types.object<{ id: string }>()({ - name: "NodeImpl", - interfaces: [Node, NodeAnother], - fields: { - // @ts-expect-error - id: types.field({ type: types.ID }), - }, - }); - } - - types.interface()({ - name: "Node", - interfaces: [Node], - // @ts-expect-error - fields: {}, - }); - - { - const Other = types.interface()({ - name: "Node", - fields: { something: types.interfaceField({ type: types.Int }) }, - }); - types.object<{ id: string; something: number }>()({ - name: "NodeImpl", - interfaces: [Node, Other], - fields: { - id: types.field({ type: types.ID }), - something: types.field({ type: types.Int }), - }, - }); - types.object<{ id: string }>()({ - name: "NodeImpl", - interfaces: [Node, Other], - // @ts-expect-error - fields: { - id: types.field({ type: types.ID }), - }, - }); - } -} - -types.object()({ - name: "Something", - fields: { - id: types.field({ - type: types.ID, - resolve(rootVal, args) { - // @ts-expect-error - args.something; - return ""; - }, - }), - }, -}); - -{ - type ImageMode = "local"; - - type ImageExtension = "jpg" | "png" | "webp" | "gif"; - - const SUPPORTED_IMAGE_EXTENSIONS = ["jpg", "png", "webp", "gif"] as const; - - const ImageExtensionEnum = types.enum({ - name: "ImageExtension", - values: types.enumValues(SUPPORTED_IMAGE_EXTENSIONS), - }); - - type ImageData = { - mode: ImageMode; - id: string; - extension: ImageExtension; - filesize: number; - width: number; - height: number; - }; - const imageOutputFields = types.fields()({ - id: types.field({ type: types.nonNull(types.ID) }), - filesize: types.field({ type: types.nonNull(types.Int) }), - height: types.field({ type: types.nonNull(types.Int) }), - width: types.field({ type: types.nonNull(types.Int) }), - extension: types.field({ type: types.nonNull(ImageExtensionEnum) }), - ref: types.field({ - type: types.nonNull(types.String), - resolve(data) { - return ""; - }, - }), - src: types.field({ - type: types.nonNull(types.String), - args: {}, - resolve(data, {}, context) { - return ""; - }, - }), - }); - - const ImageFieldOutput = types.interface()({ - name: "ImageFieldOutput", - fields: imageOutputFields, - }); - - const LocalImageFieldOutput = types.object()({ - name: "LocalImageFieldOutput", - interfaces: [ImageFieldOutput], - fields: { - id: types.field({ type: types.nonNull(types.ID) }), - filesize: types.field({ type: types.nonNull(types.Int) }), - height: types.field({ type: types.nonNull(types.Int) }), - width: types.field({ type: types.nonNull(types.Int) }), - extension: types.field({ type: types.nonNull(ImageExtensionEnum) }), - ref: types.field({ - type: types.nonNull(types.String), - resolve(data) { - return ""; - }, - }), - src: types.field({ - type: types.nonNull(types.String), - resolve(data, args, context) { - return ""; - }, - }), - }, - }); -} - -types.fields<{ thing: Promise[] }>()({ - thing: types.field({ - type: types.list(types.String), - }), -}); - -types.fields()({ - thing: types.field({ - type: types.list(types.String), - resolve() { - return [Promise.resolve("")]; - }, - }), -}); - -types.fields<{ thing: Promise }>()({ - thing: types.field({ - type: types.String, - }), -}); - -// note it's important that the type annotation is on another variable declaration -// since the type annotation can influence the return type and we don't want that here - -{ - const arg = types.arg({ - type: types.String, - }); - - const _assert: types.Arg = arg; -} - -{ - const arg = types.arg({ - type: types.String, - defaultValue: undefined, - }); - - const _assert: types.Arg = arg; -} - -{ - const arg = types.arg({ - type: types.String, - defaultValue: "", - }); - - const _assert: types.Arg = arg; -} - -{ - const arg = types.arg({ - type: types.String, - defaultValue: null, - }); - - const _assert: types.Arg = arg; -} - -{ - const arg = types.arg({ - type: types.String, - defaultValue: null, - }); - - const _assert: types.Arg = arg; -} - -{ - const arg = types.arg({ - type: types.String, - defaultValue: Math.random() > 0.5 ? "" : null, - }); - - const _assert: types.Arg = arg; - // @ts-expect-error - const _assert1: types.Arg = arg; - // @ts-expect-error - const _assert2: types.Arg = arg; -} - -{ - const x: - | { - defaultValue: string; - } - | { - defaultValue?: undefined; - } = - Math.random() > 0.5 - ? { - defaultValue: "", - } - : {}; - const arg = types.arg({ - type: types.String, - ...x, - }); - - const _assert: types.Arg = arg; - // @ts-expect-error - const _assert1: types.Arg = arg; - // @ts-expect-error - const _assert2: types.Arg = arg; - const _assert3: ( - x: types.Arg - ) => void = (x: typeof arg) => {}; -} - -{ - const x: - | {} - | { - defaultValue?: string; - } = - Math.random() > 0.5 - ? { - defaultValue: "", - } - : {}; - const arg = types.arg({ - type: types.String, - ...x, - }); - - const _assert: types.Arg = arg; - // @ts-expect-error - const _assert1: types.Arg = arg; - // @ts-expect-error - const _assert2: types.Arg = arg; -} - -{ - const x: - | {} - | { - defaultValue: string; - } = - Math.random() > 0.5 - ? { - defaultValue: "", - } - : {}; - // this is indicating a _kinda_ bug - // if this starts working, that would be good - // but i doubt this case would actually happen - // and it's being too strict rather than not strict enough so it's fine imo - // (it's a ts-expect-error rather than ts-ignore so that it's visible if it starts working) - // @ts-expect-error - const arg = types.arg({ - type: types.String, - ...x, - }); -} - -{ - const thing: { defaultValue: undefined } | { defaultValue: string } = - Math.random() > 0.5 ? { defaultValue: undefined } : { defaultValue: "" }; - const arg = types.arg({ - type: types.String, - ...thing, - }); - - const _assert: types.Arg = arg; - // @ts-expect-error - const _assert1: types.Arg = arg; - // @ts-expect-error - const _assert2: types.Arg = arg; -} - -types.arg({ - type: types.String, - // @ts-expect-error - defaultValue: 1, -}); - -types.arg({ - type: types.String, - // @ts-expect-error - bad: true, -}); diff --git a/output-types.d.ts b/output-types.d.ts deleted file mode 100644 index 48433fe..0000000 --- a/output-types.d.ts +++ /dev/null @@ -1,6 +0,0 @@ -import { TypesWithContext } from "./packages/schema"; -import { Context } from "./test-types-with-context"; - -declare const __types: TypesWithContext; - -export = __types; diff --git a/output-types.js b/output-types.js deleted file mode 100644 index 7311138..0000000 --- a/output-types.js +++ /dev/null @@ -1 +0,0 @@ -export * from "./packages/schema/types-with-context"; diff --git a/packages/schema/CHANGELOG.md b/packages/schema/CHANGELOG.md deleted file mode 100644 index 15b81fd..0000000 --- a/packages/schema/CHANGELOG.md +++ /dev/null @@ -1,135 +0,0 @@ -# @ts-gql/schema - -## 0.11.2 - -### Patch Changes - -- [`d687c4a`](https://github.com/Thinkmill/ts-gql/commit/d687c4ab02f04926d507733a90974a300285699d) Thanks [@mitchellhamilton](https://github.com/mitchellhamilton)! - `resolveType` in the arguments to `types.union` is now optional. - -## 0.11.1 - -### Patch Changes - -- [`1d9e5e5`](https://github.com/Thinkmill/ts-gql/commit/1d9e5e5f52d45c2a9d6eb8423f3a31ad58935d13) Thanks [@mitchellhamilton](https://github.com/mitchellhamilton)! - Fixed excess properties/default values that don't match the type being allowed to be passed to `types.arg()` - -## 0.11.0 - -### Minor Changes - -- [`64a74d3`](https://github.com/Thinkmill/ts-gql/commit/64a74d3fde71d3c214007546acc0686423c58af2) Thanks [@mitchellhamilton](https://github.com/mitchellhamilton)! - Fixed inference of `defaultValue` in `types.arg` to infer the `DefaultValue` to be `undefined` when `defaultValue` is not passed - -## 0.10.0 - -### Minor Changes - -- [`c664466`](https://github.com/Thinkmill/ts-gql/commit/c6644660d1a8de194872a9153e8e7d37a8bcfa41) Thanks [@mitchellhamilton](https://github.com/mitchellhamilton)! - Fixed `defaultValue` with `types.arg` being inferred incorrectly. - -## 0.9.0 - -### Minor Changes - -- [`80138fe`](https://github.com/Thinkmill/ts-gql/commit/80138fe1b12bab45017eb76b019579647b558f16) Thanks [@mitchellhamilton](https://github.com/mitchellhamilton)! - Added `types-with-context` entrypoint to allow for a different strategy of binding the `TypesWithContext` functions to a context type that will preserve JSDoc comments on the `TypesWithContext` functions - -## 0.8.0 - -### Minor Changes - -- [`5b10893`](https://github.com/Thinkmill/ts-gql/commit/5b108934c0aeccb4947b8d89798dab6ec9820d08) Thanks [@mitchellhamilton](https://github.com/mitchellhamilton)! - Lots of type renaming, type parameter adding re-ordering and the addition of TypeScript types available on the exported `types` object that are bound to the specific context type(which for the exported `types` object is `unknown`) and the removal of all non-context bound functions from `bindTypesToContext` - -## 0.7.3 - -### Patch Changes - -- [`0b9c783`](https://github.com/Thinkmill/ts-gql/commit/0b9c7838568b6837ad0c9cb43bac476f17e18f53) Thanks [@mitchellhamilton](https://github.com/mitchellhamilton)! - The types for resolvers now allow returning an array of promises for list types. - -## 0.7.2 - -### Patch Changes - -- [`4c2a7d1`](https://github.com/Thinkmill/ts-gql/commit/4c2a7d117cb9773d48f829a8562dc300c37cfd83) Thanks [@mitchellhamilton](https://github.com/mitchellhamilton)! - Added support for `deprecationReason` on GraphQL arguments/input fields - -## 0.7.1 - -### Patch Changes - -- [`45e1a24`](https://github.com/Thinkmill/ts-gql/commit/45e1a24511b810cd492a363c4ca85371944fb49e) Thanks [@mitchellhamilton](https://github.com/mitchellhamilton)! - Added checks to types.field and types.arg which throw if a type isn't passed so that it's easier to see why a type wasn't passed rather than getting an error when mapping the fields to graphql-js arguments - -## 0.7.0 - -### Minor Changes - -- [`af755ec`](https://github.com/Thinkmill/ts-gql/commit/af755ecb0e25f7c3e1f6c9f27f1104aa48fc9df9) Thanks [@mitchellhamilton](https://github.com/mitchellhamilton)! - Fixed various bugs with interfaces and bindTypesToContext - -## 0.6.0 - -### Minor Changes - -- [`1404564`](https://github.com/Thinkmill/ts-gql/commit/14045646b88dcd8e50ca1c21b43c0230d79b4726) [#70](https://github.com/Thinkmill/ts-gql/pull/70) Thanks [@mitchellhamilton](https://github.com/mitchellhamilton)! - Added `fields` function to share fields between multiple object types while inferring the `Key` of the fields correctly - -* [`1404564`](https://github.com/Thinkmill/ts-gql/commit/14045646b88dcd8e50ca1c21b43c0230d79b4726) [#70](https://github.com/Thinkmill/ts-gql/pull/70) Thanks [@mitchellhamilton](https://github.com/mitchellhamilton)! - Various correctness fixes around the typing of RootVal and Context - -- [`0b598b3`](https://github.com/Thinkmill/ts-gql/commit/0b598b3f489041f1d8e177b327d21c68b83bfe7b) [#72](https://github.com/Thinkmill/ts-gql/pull/72) Thanks [@mitchellhamilton](https://github.com/mitchellhamilton)! - First pass at an implementation of GraphQL interfaces. The API is quite likely to change. - -## 0.5.1 - -### Patch Changes - -- [`f39352d`](https://github.com/Thinkmill/ts-gql/commit/f39352dd0cc5324edabb722e717d3c7f027662d0) Thanks [@mitchellhamilton](https://github.com/mitchellhamilton)! - Fixed the value of enums being inferred to unknown rather than the actual values - -## 0.5.0 - -### Minor Changes - -- [`3c07b55`](https://github.com/Thinkmill/ts-gql/commit/3c07b552a250c23e3fdb56aa3587306a8189b25f) Thanks [@mitchellhamilton](https://github.com/mitchellhamilton)! - Moved exported TypeScript types from the `types` export to top-level exports create consistency with using the `types` export and `bindTypesToContext`. - -## 0.4.0 - -### Minor Changes - -- [`b2a88cf`](https://github.com/Thinkmill/ts-gql/commit/b2a88cf7a0e9e9875c54c40695f8a9ce324b4c0c) Thanks [@mitchellhamilton](https://github.com/mitchellhamilton)! - Removed `Context` type parameter to `ListType` type to be consistent with `NonNullType`. - -### Patch Changes - -- [`b2a88cf`](https://github.com/Thinkmill/ts-gql/commit/b2a88cf7a0e9e9875c54c40695f8a9ce324b4c0c) Thanks [@mitchellhamilton](https://github.com/mitchellhamilton)! - Fixed inference of input lists with non null inside them - -## 0.3.1 - -### Patch Changes - -- [`8d19a88`](https://github.com/Thinkmill/ts-gql/commit/8d19a886de62bfb9d5a6d9302d9f43500502b263) Thanks [@mitchellhamilton](https://github.com/mitchellhamilton)! - Fix types.arg returned from bindTypesToContext requiring a defaultValue - -## 0.3.0 - -### Minor Changes - -- [`d57bee5`](https://github.com/Thinkmill/ts-gql/commit/d57bee5a9c94c9937cc8308caa6e39a7a40f17eb) Thanks [@mitchellhamilton](https://github.com/mitchellhamilton)! - Export `bindTypesToContext` directly rather than in `types` - -## 0.2.0 - -### Minor Changes - -- [`2a7f889`](https://github.com/Thinkmill/ts-gql/commit/2a7f88954915834440a3e6c6178dba622435806a) Thanks [@mitchellhamilton](https://github.com/mitchellhamilton)! - Replace `bindObjectTypeToContext` with `bindTypesToContext` and rename `types.custom` to `types.scalar` - -## 0.1.0 - -### Minor Changes - -- [`7425f01`](https://github.com/Thinkmill/ts-gql/commit/7425f013822d5b302f8398a7b23008ae9f387df3) Thanks [@mitchellhamilton](https://github.com/mitchellhamilton)! - Various fixes - -## 0.0.3 - -### Patch Changes - -- [`f4c55aa`](https://github.com/Thinkmill/ts-gql/commit/f4c55aaaf0272f9e77e7f185dfc3b6d7d8f2c0e7) Thanks [@mitchellhamilton](https://github.com/mitchellhamilton)! - Add `GraphQLBoolean` - -## 0.0.2 - -### Patch Changes - -- [`f4b9909`](https://github.com/Thinkmill/ts-gql/commit/f4b99099e4b3fcfbd481ad19821703fd425f4390) Thanks [@mitchellhamilton](https://github.com/mitchellhamilton)! - Export object and union types - -## 0.0.1 - -### Patch Changes - -- [`b879c3b`](https://github.com/Thinkmill/ts-gql/commit/b879c3b453051d31c811df8e67c23faa954b07e1) Thanks [@mitchellhamilton](https://github.com/mitchellhamilton)! - Initial release diff --git a/packages/schema/README.md b/packages/schema/README.md index ffb6fd0..792cad4 100644 --- a/packages/schema/README.md +++ b/packages/schema/README.md @@ -1,3 +1,3 @@ # @ts-gql/schema -An experimental GraphQL schema definition API designed around type safety inspired by [Nexus](https://github.com/graphql-nexus/nexus/) and [gqtx](https://github.com/sikanhe/gqtx). +This package has been renamed to `@graphql-ts/schema` and moved to https://github.com/Thinkmill/graphql-ts diff --git a/packages/schema/package.json b/packages/schema/package.json deleted file mode 100644 index 9677ceb..0000000 --- a/packages/schema/package.json +++ /dev/null @@ -1,29 +0,0 @@ -{ - "name": "@ts-gql/schema", - "version": "0.11.2", - "main": "dist/schema.cjs.js", - "module": "dist/schema.esm.js", - "files": [ - "dist", - "types-without-context", - "types-with-context" - ], - "license": "MIT", - "dependencies": { - "@babel/runtime": "^7.9.2" - }, - "peerDependencies": { - "graphql": "^15.0.0" - }, - "devDependencies": { - "graphql": "^15.0.0" - }, - "repository": "https://github.com/Thinkmill/ts-gql/tree/master/packages/schema", - "preconstruct": { - "entrypoints": [ - "index.ts", - "types-without-context/index.ts", - "types-with-context/index.ts" - ] - } -} diff --git a/packages/schema/src/index.ts b/packages/schema/src/index.ts deleted file mode 100644 index f83dc5a..0000000 --- a/packages/schema/src/index.ts +++ /dev/null @@ -1,29 +0,0 @@ -export { bindTypesToContext } from "./output"; -export * as types from "./types"; -export type { - InferValueFromOutputType, - ObjectType, - Field, - FieldResolver, - NullableOutputType, - OutputType, - UnionType, - TypesWithContext, - InterfaceField, - InterfaceType, -} from "./output"; -export type { - Arg, - EnumType, - EnumValue, - InferValueFromArg, - InferValueFromArgs, - InferValueFromInputType, - InputObjectType, - InputType, - NullableInputType, - ListType, - NonNullType, - ScalarType, -} from "./types-without-context"; -export type { Type, NullableType } from "./type"; diff --git a/packages/schema/src/output.ts b/packages/schema/src/output.ts deleted file mode 100644 index 8aced42..0000000 --- a/packages/schema/src/output.ts +++ /dev/null @@ -1,526 +0,0 @@ -import { - GraphQLFieldConfigMap, - GraphQLFieldExtensions, - GraphQLInputType, - GraphQLInterfaceType, - GraphQLInterfaceTypeExtensions, - GraphQLIsTypeOfFn, - GraphQLList, - GraphQLNonNull, - GraphQLObjectType, - GraphQLObjectTypeExtensions, - GraphQLOutputType, - GraphQLResolveInfo, - GraphQLTypeResolver, - GraphQLUnionType, -} from "graphql/type/definition"; -import { - Arg, - InferValueFromArgs, - InputType, - ScalarType, - EnumType, -} from "./types-without-context"; - -type OutputListType> = { - kind: "list"; - of: Of; - graphQLType: GraphQLList; -}; - -type OutputNonNullType> = { - kind: "non-null"; - of: Of; - graphQLType: GraphQLNonNull; -}; - -type OutputListTypeWithContext = { - kind: "list"; - of: OutputType; - graphQLType: GraphQLList; -}; - -type OutputNonNullTypeWithContext = { - kind: "non-null"; - of: NullableOutputType; - graphQLType: GraphQLNonNull["graphQLType"]>; -}; - -export type NullableOutputType = - | ScalarType - | ObjectType - | UnionType - | InterfaceType - | EnumType - | OutputListTypeWithContext; - -export type OutputType = - | NullableOutputType - | OutputNonNullTypeWithContext; - -type InferValueFromOutputTypeWithoutAddingNull> = - Type extends ScalarType - ? Value - : Type extends EnumType - ? Values[keyof Values]["value"] - : Type extends OutputListType - ? InferValueFromOutputType[] - : Type extends ObjectType - ? RootVal - : Type extends UnionType - ? RootVal - : Type extends InterfaceType - ? RootVal - : never; - -export type InferValueFromOutputType> = - MaybePromise< - Type extends OutputNonNullType - ? InferValueFromOutputTypeWithoutAddingNull - : InferValueFromOutputTypeWithoutAddingNull | null - >; - -export type ObjectType = { - kind: "object"; - graphQLType: GraphQLObjectType; - __context: (context: Context) => void; - __rootVal: RootVal; -}; - -type MaybePromise = Promise | T; - -export type FieldResolver< - RootVal, - Args extends Record>, - TType extends OutputType, - Context -> = ( - rootVal: RootVal, - args: InferValueFromArgs, - context: Context, - info: GraphQLResolveInfo -) => InferValueFromOutputType; - -type SomeTypeThatIsntARecordOfArgs = string; - -export type Field< - RootVal, - Args extends Record>, - TType extends OutputType, - Key extends string, - Context -> = { - args?: Args; - type: TType; - __key: Key; - __rootVal: (rootVal: RootVal) => void; - __context: (context: Context) => void; - resolve?: FieldResolver; - deprecationReason?: string; - description?: string; - extensions?: Readonly< - GraphQLFieldExtensions> - >; -}; - -export type InterfaceField< - Args extends Record>, - Type extends OutputType, - Context -> = { - args?: Args; - type: Type; - deprecationReason?: string; - description?: string; - extensions?: Readonly< - GraphQLFieldExtensions> - >; -}; - -type FieldFuncResolve< - RootVal, - Args extends { [Key in keyof Args]: Arg }, - Type extends OutputType, - Key extends string, - Context -> = - // i think the solution below is kinda wrong and we actually want this whole thing to be wrapped in UnionToIntersection - - // the tuple is here because we _don't_ want this to be distributive - // if this was distributive then it would optional when it should be required e.g. - // types.object<{ id: string } | { id: boolean }>()({ - // name: "Node", - // fields: { - // id: types.field({ - // type: types.nonNull(types.ID), - // }), - // }, - // }); - // TODO: this check is incomplete, there are some more cases which graphql-js will handle like promises and functions - // though tbh, maybe it's fine to be a little more explicit like that - [RootVal] extends [ - { - [K in Key]: InferValueFromOutputType; - } - ] - ? { - resolve?: FieldResolver< - RootVal, - SomeTypeThatIsntARecordOfArgs extends Args ? {} : Args, - Type, - Context - >; - } - : { - resolve: FieldResolver< - RootVal, - SomeTypeThatIsntARecordOfArgs extends Args ? {} : Args, - Type, - Context - >; - }; - -type FieldFuncArgs< - RootVal, - Args extends { [Key in keyof Args]: Arg }, - Type extends OutputType, - Key extends string, - Context -> = { - args?: Args; - type: Type; - deprecationReason?: string; - description?: string; - extensions?: Readonly>; -} & FieldFuncResolve; - -export type FieldFunc = < - RootVal, - Type extends OutputType, - Key extends string, - Args extends { [Key in keyof Args]: Arg } = {} ->( - field: FieldFuncArgs -) => Field; - -function bindFieldToContext(): FieldFunc { - return function field(field) { - if (!field.type) { - throw new Error("A type must be passed to types.field()"); - } - return field as any; - }; -} - -export type InterfaceToInterfaceFields< - Interface extends InterfaceType -> = Interface extends InterfaceType ? Fields : never; - -type InterfaceFieldToOutputField< - RootVal, - Context, - TField extends InterfaceField, - Key extends string -> = TField extends InterfaceField - ? Field - : never; - -type InterfaceFieldsToOutputFields< - RootVal, - Context, - Fields extends { [Key in keyof Fields]: InterfaceField } -> = { - [Key in keyof Fields]: InterfaceFieldToOutputField< - RootVal, - Context, - Fields[Key], - Extract - >; -}; - -type UnionToIntersection = (T extends any ? (x: T) => any : never) extends ( - x: infer R -) => any - ? R - : never; - -export type InterfacesToOutputFields< - RootVal, - Context, - Interfaces extends readonly InterfaceType[] -> = UnionToIntersection< - InterfaceFieldsToOutputFields< - RootVal, - Context, - InterfaceToInterfaceFields - > ->; - -export type ObjectTypeFunc = < - RootVal ->(youOnlyNeedToPassATypeParameterToThisFunctionYouPassTheActualRuntimeArgsOnTheResultOfThisFunction?: { - youOnlyNeedToPassATypeParameterToThisFunctionYouPassTheActualRuntimeArgsOnTheResultOfThisFunction: true; -}) => < - Fields extends { - [Key in keyof Fields]: Field< - RootVal, - any, - any, - Extract, - Context - >; - } & - InterfacesToOutputFields, - Interfaces extends readonly InterfaceType[] = [] ->(config: { - name: string; - fields: MaybeFunc; - description?: string; - deprecationReason?: string; - interfaces?: [...Interfaces]; - isTypeOf?: GraphQLIsTypeOfFn; - extensions?: Readonly>; -}) => ObjectType; - -function bindObjectTypeToContext(): ObjectTypeFunc { - return function object() { - return function objectInner(config) { - return { - kind: "object", - name: config.name, - graphQLType: new GraphQLObjectType({ - name: config.name, - description: config.description, - isTypeOf: config.isTypeOf, - interfaces: config.interfaces?.map((x) => x.graphQLType), - fields: () => { - const fields = - typeof config.fields === "function" - ? config.fields() - : config.fields; - return buildFields(fields); - }, - extensions: config.extensions, - }), - __rootVal: undefined as any, - __context: undefined as any, - }; - }; - }; -} - -function buildFields( - fields: Record< - string, - Field< - any, - Record>, - OutputType, - string, - any - > - > -): GraphQLFieldConfigMap { - return Object.fromEntries( - Object.entries(fields).map(([key, val]) => [ - key, - { - type: val.type.graphQLType as GraphQLOutputType, - resolve: val.resolve, - deprecationReason: val.deprecationReason, - description: val.description, - args: Object.fromEntries( - Object.entries(val.args || {}).map(([key, val]) => [ - key, - { - type: val.type.graphQLType as GraphQLInputType, - description: val.description, - defaultValue: val.defaultValue, - deprecationReason: val.deprecationReason, - }, - ]) - ), - extensions: val.extensions, - }, - ]) - ); -} - -export type UnionType = { - kind: "union"; - __rootVal: RootVal; - __context: (context: Context) => void; - graphQLType: GraphQLUnionType; -}; - -export type UnionTypeFunc = < - TObjectType extends ObjectType ->(config: { - name: string; - description?: string; - types: TObjectType[]; - resolveType?: ( - type: TObjectType["__rootVal"], - context: Parameters[0], - info: GraphQLResolveInfo, - abstractType: GraphQLUnionType - ) => string; -}) => UnionType< - TObjectType["__rootVal"], - Parameters[0] ->; - -function bindUnionTypeToContext(): UnionTypeFunc { - return function union(config) { - return { - kind: "union", - graphQLType: new GraphQLUnionType({ - name: config.name, - description: config.description, - types: config.types.map((x) => x.graphQLType), - resolveType: config.resolveType as any, - }), - __rootVal: undefined as any, - __context: undefined as any, - }; - }; -} - -export type FieldsFunc = < - RootVal ->(youOnlyNeedToPassATypeParameterToThisFunctionYouPassTheActualRuntimeArgsOnTheResultOfThisFunction?: { - youOnlyNeedToPassATypeParameterToThisFunctionYouPassTheActualRuntimeArgsOnTheResultOfThisFunction: true; -}) => < - Fields extends { - [Key in keyof Fields]: Field< - RootVal, - any, - any, - Extract, - Context - >; - } ->( - fields: Fields -) => Fields; - -function bindFieldsToContext(): FieldsFunc { - return function fields() { - return function fieldsInner(fields) { - return fields; - }; - }; -} - -type InterfaceFieldFuncArgs< - RootVal, - Args extends { [Key in keyof Args]: Arg }, - Type extends OutputType, - Context -> = { - args?: Args; - type: Type; - deprecationReason?: string; - description?: string; - extensions?: Readonly>; -}; - -export type InterfaceFieldFunc = < - RootVal, - Type extends OutputType, - Args extends { [Key in keyof Args]: Arg } = {} ->( - field: InterfaceFieldFuncArgs -) => InterfaceField; - -function bindInterfaceFieldToContext(): InterfaceFieldFunc { - return function interfaceField(field) { - return field as any; - }; -} - -export type InterfaceType< - RootVal, - Fields extends Record< - string, - InterfaceField, Context> - >, - Context -> = { - kind: "interface"; - __rootVal: (rootVal: RootVal) => void; - __context: (context: Context) => void; - graphQLType: GraphQLInterfaceType; - fields: () => Fields; -}; - -export type MaybeFunc = T | (() => T); - -export type InterfaceTypeFunc = < - RootVal ->(youOnlyNeedToPassATypeParameterToThisFunctionYouPassTheActualRuntimeArgsOnTheResultOfThisFunction?: { - // eslint-disable-next-line @typescript-eslint/no-unused-vars - youOnlyNeedToPassATypeParameterToThisFunctionYouPassTheActualRuntimeArgsOnTheResultOfThisFunction: true; -}) => < - Fields extends { - [Key in keyof Fields]: InterfaceField, Context>; - } & - UnionToIntersection>, - Interfaces extends readonly InterfaceType[] = [] ->(config: { - name: string; - description?: string; - deprecationReason?: string; - interfaces?: [...Interfaces]; - resolveType?: GraphQLTypeResolver; - fields: MaybeFunc; - extensions?: Readonly; -}) => InterfaceType; - -function bindInterfaceTypeToContext(): InterfaceTypeFunc { - return function interfaceType() { - return function interfaceInner(config) { - return { - kind: "interface", - graphQLType: new GraphQLInterfaceType({ - name: config.name, - description: config.description, - resolveType: config.resolveType, - interfaces: config.interfaces?.map((x) => x.graphQLType), - extensions: config.extensions, - fields: () => { - const fields = - typeof config.fields === "function" - ? config.fields() - : config.fields; - return buildFields(fields as any); - }, - }), - __rootVal: undefined as any, - __context: undefined as any, - fields: () => - typeof config.fields === "function" ? config.fields() : config.fields, - }; - }; - }; -} - -export type TypesWithContext = { - object: ObjectTypeFunc; - union: UnionTypeFunc; - field: FieldFunc; - fields: FieldsFunc; - interfaceField: InterfaceFieldFunc; - interface: InterfaceTypeFunc; -}; - -export function bindTypesToContext(): TypesWithContext { - return { - object: bindObjectTypeToContext(), - union: bindUnionTypeToContext(), - field: bindFieldToContext(), - fields: bindFieldsToContext(), - interfaceField: bindInterfaceFieldToContext(), - interface: bindInterfaceTypeToContext(), - }; -} diff --git a/packages/schema/src/type.ts b/packages/schema/src/type.ts deleted file mode 100644 index ed0efd6..0000000 --- a/packages/schema/src/type.ts +++ /dev/null @@ -1,28 +0,0 @@ -import { GraphQLNullableType } from "graphql/type/definition"; -import { - ScalarType, - ListType, - InputObjectType, - ObjectType, - UnionType, - InterfaceType, - EnumType, -} from "."; - -export type NullableType = - | ScalarType - | ListType - | InputObjectType - | ObjectType - | UnionType - | InterfaceType - | EnumType; - -export type Type = - | NullableType - | { - kind: "non-null"; - of: NullableType; - graphQLType: GraphQLNullableType; - __context: unknown; - }; diff --git a/packages/schema/src/types-with-context/index.ts b/packages/schema/src/types-with-context/index.ts deleted file mode 100644 index c273b3e..0000000 --- a/packages/schema/src/types-with-context/index.ts +++ /dev/null @@ -1,11 +0,0 @@ -// Preconstruct doesn't currently correctly handle .js with .d.ts files directly at an entrypoint -// though it does correctly handle them as dependencies of an entrypoint so we need to have a .ts -// as the actual entrypoint and then Preconstruct will be okay with it -export { - field, - fields, - interface, - interfaceField, - object, - union, -} from "./types-with-context"; diff --git a/packages/schema/src/types-with-context/types-with-context.d.ts b/packages/schema/src/types-with-context/types-with-context.d.ts deleted file mode 100644 index 63b4bb6..0000000 --- a/packages/schema/src/types-with-context/types-with-context.d.ts +++ /dev/null @@ -1,5 +0,0 @@ -import { TypesWithContext } from "../output"; - -declare const __types: TypesWithContext; - -export = __types; diff --git a/packages/schema/src/types-with-context/types-with-context.js b/packages/schema/src/types-with-context/types-with-context.js deleted file mode 100644 index 19a3f4d..0000000 --- a/packages/schema/src/types-with-context/types-with-context.js +++ /dev/null @@ -1,9 +0,0 @@ -import { bindTypesToContext } from "../output"; - -const types = bindTypesToContext(); - -export const { field, fields, interfaceField, object, union } = types; - -const interfaceType = types.interface; - -export { interfaceType as interface }; diff --git a/packages/schema/src/types-without-context/enum.ts b/packages/schema/src/types-without-context/enum.ts deleted file mode 100644 index b3dd10d..0000000 --- a/packages/schema/src/types-without-context/enum.ts +++ /dev/null @@ -1,145 +0,0 @@ -import { - GraphQLEnumType, - GraphQLEnumTypeExtensions, -} from "graphql/type/definition"; - -/** - * An individual enum value - * - * Note the value property and generic here represents the deserialized form of - * the enum. It does not indicate the name of the enum value that is visible in - * the GraphQL schema. The value can be anything, not necessarily a string. - * Usually though, it will be a string which is equal to the key where the value is used. - */ -export type EnumValue = { - description?: string; - deprecationReason?: string; - value: Value; -}; - -/** - * An enum type for `@ts-gql/schema` which wraps an underlying graphql-js - * `GraphQLEnumType`. This should be created with `types.enum`. - * - * ```ts - * const MyEnum = types.enum({ - * name: "MyEnum", - * values: types.enumValues(["a", "b"]), - * }); - * // == - * graphql` - * enum MyEnum { - * a - * b - * } - * `; - * ``` - */ -export type EnumType>> = { - kind: "enum"; - values: Values; - graphQLType: GraphQLEnumType; - __context: unknown; -}; - -/** - * A shorthand to easily create enum values to pass to `types.enum`. - * - * If you need to set a `description` or `deprecationReason` for an enum - * variant, you should pass values directly to `types.enum` without using - * `types.enumValues`. - * - * ```ts - * const MyEnum = types.enum({ - * name: "MyEnum", - * values: types.enumValues(["a", "b"]), - * }); - * ``` - * --- - * ```ts - * const values = types.enumValues(["a", "b"]); - * - * assertDeepEqual(values, { - * a: { value: "a" }, - * b: { value: "b" }, - * }); - * ``` - */ -export function enumValues( - values: readonly [...Values] -): Record> { - return Object.fromEntries(values.map((value) => [value, { value }])); -} - -/** - * Creates a GraphQL enum to be used within a schema created within `@ts-gql/schema` - * - * ```ts - * const MyEnum = types.enum({ - * name: "MyEnum", - * values: types.enumValues(["a", "b"]), - * }); - * // == - * graphql` - * enum MyEnum { - * a - * b - * } - * `; - * ``` - * --- - * ```ts - * const MyEnum = types.enum({ - * name: "MyEnum", - * description: "My enum does things", - * values: { - * something: { - * description: "something something", - * value: "something", - * }, - * thing: { - * description: "thing thing", - * deprecationReason: "something should be used instead of thing", - * value: "thing", - * }, - * }, - * }); - * // == - * graphql` - * """ - * My enum does things - * """ - * enum MyEnum { - * """ - * something something - * """ - * something - * """ - * thing thing - * """ - * thing ​@deprecated(reason: "something should be used instead of thing") - * } - * `; - * ``` - */ -function enumType>>(config: { - name: string; - description?: string; - extensions?: Readonly; - values: Values; -}): EnumType { - const graphQLType = new GraphQLEnumType({ - name: config.name, - description: config.description, - extensions: config.extensions, - values: config.values, - }); - return { - kind: "enum", - values: config.values, - graphQLType, - __context: undefined as any, - }; -} - -export { enumType as enum }; diff --git a/packages/schema/src/types-without-context/index.ts b/packages/schema/src/types-without-context/index.ts deleted file mode 100644 index d4c0261..0000000 --- a/packages/schema/src/types-without-context/index.ts +++ /dev/null @@ -1,5 +0,0 @@ -export * from "./enum"; -export * from "./input"; -export * from "./scalars"; -export * from "./list-and-non-null"; -export type { InferValueFromOutputType } from "../output"; diff --git a/packages/schema/src/types-without-context/input.ts b/packages/schema/src/types-without-context/input.ts deleted file mode 100644 index f68a5b9..0000000 --- a/packages/schema/src/types-without-context/input.ts +++ /dev/null @@ -1,158 +0,0 @@ -import { - GraphQLInputObjectType, - GraphQLInputType, - GraphQLList, - GraphQLNonNull, -} from "graphql/type/definition"; -import { EnumType } from "./enum"; -import { ScalarType } from "./scalars"; - -type InputListType = { - kind: "list"; - of: Of; - graphQLType: GraphQLList; - __context: any; -}; - -type InputNonNullType = { - kind: "non-null"; - of: Of; - graphQLType: GraphQLNonNull; - __context: any; -}; - -export type NullableInputType = - | ScalarType - | InputObjectType - | InputListType - | EnumType; - -export type InputType = NullableInputType | InputNonNullType; - -type InferValueFromInputTypeWithoutAddingNull = - Type extends ScalarType - ? Value - : Type extends EnumType - ? Values[keyof Values]["value"] - : Type extends InputListType - ? InferValueFromInputType[] - : Type extends InputObjectType - ? { - readonly [Key in keyof Fields]: InferValueFromArg; - } - : never; - -export type InferValueFromArgs>> = { - readonly [Key in keyof Args]: InferValueFromArg; -}; - -export type InferValueFromArg> = - | InferValueFromInputType - | ("non-null" extends TArg["type"]["kind"] - ? never - : undefined extends TArg["defaultValue"] - ? undefined - : never); - -export type InferValueFromInputType = - Type extends InputNonNullType - ? InferValueFromInputTypeWithoutAddingNull - : InferValueFromInputTypeWithoutAddingNull | null; - -export type InputObjectType< - Fields extends { - [Key in keyof any]: Arg>; - } -> = { - kind: "input"; - __fields: Fields; - __context: (context: unknown) => void; - graphQLType: GraphQLInputObjectType; -}; - -export type Arg< - Type extends InputType, - DefaultValue extends InferValueFromInputType | undefined = - | InferValueFromInputType - | undefined -> = { - type: Type; - description?: string; - deprecationReason?: string; - defaultValue: DefaultValue; -}; - -export function arg< - Type extends InputType, - DefaultValue extends InferValueFromInputType | undefined = undefined ->( - arg: { - type: Type; - description?: string; - deprecationReason?: string; - } & (DefaultValue extends undefined - ? { defaultValue?: DefaultValue } - : { defaultValue: DefaultValue }) -): Arg { - if (!arg.type) { - throw new Error("A type must be passed to types.arg()"); - } - return arg as any; -} - -export function inputObject< - Fields extends { - [Key in keyof any]: Arg>; - } ->(config: { - name: string; - description?: string; - fields: (() => Fields) | Fields; -}): InputObjectType { - const fields = config.fields; - const graphQLType = new GraphQLInputObjectType({ - name: config.name, - description: config.description, - fields: () => { - return Object.fromEntries( - Object.entries(typeof fields === "function" ? fields() : fields).map( - ([key, value]) => - [ - key, - { - description: value.description, - type: value.type.graphQLType as GraphQLInputType, - defaultValue: value.defaultValue, - deprecationReason: value.deprecationReason, - }, - ] as const - ) - ); - }, - }); - return { - kind: "input", - __fields: undefined as any, - __context: undefined as any, - graphQLType, - }; -} - -// type Thing = { -// something?: string; -// theThing: T; -// }; - -// function thing( -// arg: { something: string,a: } & (T extends undefined -// ? { defaultValue?: undefined } -// : { defaultValue: B }) -// ): Thing { -// return undefined as any; -// } - -// const x = thing({ -// something: "", -// defaultValue: Math.random() > 0.5 ? "" : undefined, -// ...(Math.random() > 0.5 ? {} : { defaultValue: "" }), -// }); diff --git a/packages/schema/src/types-without-context/list-and-non-null.ts b/packages/schema/src/types-without-context/list-and-non-null.ts deleted file mode 100644 index e40d069..0000000 --- a/packages/schema/src/types-without-context/list-and-non-null.ts +++ /dev/null @@ -1,131 +0,0 @@ -import { GraphQLList, GraphQLNonNull } from "graphql/type/definition"; -import { NullableType, Type } from "../type"; - -export type ListType> = { - kind: "list"; - of: Of; - __context: Of["__context"]; - graphQLType: GraphQLList; -}; - -/** - * Wraps any `@ts-gql/schema` GraphQL type in a list. - * - * ```ts - * const stringListType = types.list(types.String); - * // == - * graphql`[String]`; - * ``` - */ -export function list>(of: Of): ListType { - return { - kind: "list", - of, - __context: of["__context"], - graphQLType: new GraphQLList(of.graphQLType), - }; -} - -/** - * Wraps any `@ts-gql/schema` GraphQL type with a non-null type except other - * non-null types. - * - * See the documentation for `types.nonNull` for more information. - */ -export type NonNullType> = { - kind: "non-null"; - of: Of; - __context: Of["__context"]; - graphQLType: GraphQLNonNull; -}; - -/** - * Wraps any `@ts-gql/schema` GraphQL type except other non-null types with a - * non-null type. - * - * ```ts - * const nonNullableString = types.nonNull(types.String); - * // == - * graphql`String!`; - * ``` - * - * When using a non-null type as an input type, your resolver will never recieve - * null and consumers of your GraphQL API **must** provide a value for it unless - * you provide a default value. - * - * ```ts - * types.field({ - * args: { - * someNonNullAndRequiredArg: types.arg({ - * type: types.nonNull(types.String), - * }), - * someNonNullButOptionalArg: types.arg({ - * type: types.nonNull(types.String), - * defaultValue: "some default", - * }), - * }, - * type: types.String, - * resolve(rootVal, args) { - * // both of these will always be a string - * args.someNonNullAndRequiredArg; - * args.someNonNullButOptionalArg; - * - * return ""; - * }, - * }); - * // == - * graphql` - * fieldName( - * someNonNullAndRequiredArg: String! - * someNonNullButOptionalArg: String! = "some default" - * ): String - * `; - * ``` - * - * When using a non-null type as an output type, your resolver must never return - * null. If you do return null(which unless you do type-casting/ts-ignore/etc. - * `@ts-gql/schema` will not let you do) graphql-js will return an error to - * consumers of your GraphQL API. - * - * Non-null types should be used very carefully on output types. If you have to - * do a fallible operation like a network request or etc. to get the value, it - * probably shouldn't be non-null. If you make a field non-null and doing the - * fallible operation fails, consumers of your GraphQL API will be unable to see - * any of the other fields on the object that the non-null field was on. For - * example, an id on some type is a good candidate for being non-null because if - * you have the entity, you will already have the id so getting the id will - * never fail but fetching a related entity from a database would be fallible so - * even if it will never be null in the success case, you should make it nullable. - * - * ```ts - * types.field({ - * type: types.nonNull(types.String), - * resolve(rootVal, args) { - * return "something"; - * }, - * }); - * // == - * graphql` - * fieldName: String! - * `; - * ``` - * - * If you try to wrap another non-null type in a non-null type again, you will - * get a type error. - * - * ```ts - * // Argument of type 'NonNullType>' - * // is not assignable to parameter of type 'TypesExcludingNonNull'. - * types.nonNull(types.nonNull(types.String)); - * ``` - */ -export function nonNull>(of: Of): NonNullType { - return { - kind: "non-null", - of, - __context: of["__context"], - graphQLType: new GraphQLNonNull(of.graphQLType) as GraphQLNonNull< - Of["graphQLType"] - >, - }; -} diff --git a/packages/schema/src/types-without-context/scalars.ts b/packages/schema/src/types-without-context/scalars.ts deleted file mode 100644 index dcfc95e..0000000 --- a/packages/schema/src/types-without-context/scalars.ts +++ /dev/null @@ -1,60 +0,0 @@ -import { GraphQLScalarType } from "graphql/type/definition"; -import { - GraphQLID, - GraphQLString, - GraphQLFloat, - GraphQLInt, - GraphQLBoolean, -} from "graphql/type/scalars"; - -/** - * A scalar type for `@ts-gql/schema` which wraps an underlying graphql-js - * `GraphQLScalarType` with an type representing the deserialized form of the scalar. - * - * @example - * declare const someScalar: ScalarType; - * - * // for fields on output types - * types.field({ type: someScalar }); - * - * // for args on output fields or fields on input types - * types.arg({ type: someScalar }); - * - * @template Type The type of a value of the scalar - */ -export type ScalarType = { - kind: "scalar"; - __type: Type; - __context: (context: unknown) => void; - graphQLType: GraphQLScalarType; -}; - -/** - * Creates a `@ts-gql/schema` scalar type from a graphql-js scalar. - * - * You should provide a type as a type parameter which is the type of the scalar - * value. Note, while graphql-js allows you to express scalar types like the - * `ID` type which accepts integers and strings as both input values and return - * values from resolvers which are transformed into strings before calling - * resolvers and returning the query respectively, the type you use should be - * `string` for `ID` since that is what it is transformed into. `@ts-gql/schema` - * doesn't currently express the coercion of scalars, you should instead convert - * values to the canonical form yourself before returning from resolvers. - * - * @example - * const JSON = types.scalar(GraphQLJSON); - */ -export function scalar(scalar: GraphQLScalarType): ScalarType { - return { - kind: "scalar", - __type: undefined as any, - __context: undefined as any, - graphQLType: scalar, - }; -} - -export const ID: ScalarType = scalar(GraphQLID); -export const String: ScalarType = scalar(GraphQLString); -export const Float: ScalarType = scalar(GraphQLFloat); -export const Int: ScalarType = scalar(GraphQLInt); -export const Boolean: ScalarType = scalar(GraphQLBoolean); diff --git a/packages/schema/src/types.ts b/packages/schema/src/types.ts deleted file mode 100644 index 6f688ba..0000000 --- a/packages/schema/src/types.ts +++ /dev/null @@ -1,41 +0,0 @@ -import * as tsgqlSchema from "."; -export * from "./types-without-context"; -export { - field, - fields, - interface, - interfaceField, - object, - union, -} from "./types-with-context"; - -export type Context = unknown; - -export type NullableType = tsgqlSchema.NullableType; -export type Type = tsgqlSchema.Type; -export type NullableOutputType = tsgqlSchema.NullableOutputType; -export type OutputType = tsgqlSchema.OutputType; -export type Field< - RootVal, - Args extends Record>, - TType extends OutputType, - Key extends string -> = tsgqlSchema.Field; -export type FieldResolver< - RootVal, - Args extends Record>, - TType extends OutputType -> = tsgqlSchema.FieldResolver; -export type ObjectType = tsgqlSchema.ObjectType; -export type UnionType = tsgqlSchema.UnionType; -export type InterfaceType< - RootVal, - Fields extends Record< - string, - tsgqlSchema.InterfaceField - > -> = tsgqlSchema.InterfaceType; -export type InterfaceField< - Args extends Record>, - TType extends OutputType -> = tsgqlSchema.InterfaceField; diff --git a/packages/schema/types-with-context/package.json b/packages/schema/types-with-context/package.json deleted file mode 100644 index 877ac9d..0000000 --- a/packages/schema/types-with-context/package.json +++ /dev/null @@ -1,4 +0,0 @@ -{ - "main": "dist/schema.cjs.js", - "module": "dist/schema.esm.js" -} diff --git a/packages/schema/types-without-context/package.json b/packages/schema/types-without-context/package.json deleted file mode 100644 index 877ac9d..0000000 --- a/packages/schema/types-without-context/package.json +++ /dev/null @@ -1,4 +0,0 @@ -{ - "main": "dist/schema.cjs.js", - "module": "dist/schema.esm.js" -} diff --git a/test-types-with-context.ts b/test-types-with-context.ts deleted file mode 100644 index 9cc6a68..0000000 --- a/test-types-with-context.ts +++ /dev/null @@ -1,41 +0,0 @@ -import * as tsgqlSchema from "./packages/schema"; -export * from "./packages/schema/types-without-context"; -export { - field, - fields, - interface, - interfaceField, - object, - union, -} from "./output-types"; - -export type Context = unknown; - -export type NullableType = tsgqlSchema.NullableType; -export type Type = tsgqlSchema.Type; -export type NullableOutputType = tsgqlSchema.NullableOutputType; -export type OutputType = tsgqlSchema.OutputType; -export type Field< - RootVal, - Args extends Record>, - TType extends OutputType, - Key extends string -> = tsgqlSchema.Field; -export type FieldResolver< - RootVal, - Args extends Record>, - TType extends OutputType -> = tsgqlSchema.FieldResolver; -export type ObjectType = tsgqlSchema.ObjectType; -export type UnionType = tsgqlSchema.UnionType; -export type InterfaceType< - RootVal, - Fields extends Record< - string, - tsgqlSchema.InterfaceField - > -> = tsgqlSchema.InterfaceType; -export type InterfaceField< - Args extends Record>, - TType extends OutputType -> = tsgqlSchema.InterfaceField;