From bf27474e635fca25dbd794ea1af3df4e3b3d05a6 Mon Sep 17 00:00:00 2001 From: Jordan Eldredge Date: Sat, 11 Oct 2025 10:33:15 -0700 Subject: [PATCH 1/2] Prefer branded types to symbols in permissions guide --- website/docs/05-guides/09-permissions.mdx | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/website/docs/05-guides/09-permissions.mdx b/website/docs/05-guides/09-permissions.mdx index a1ff1156..3bda43c0 100644 --- a/website/docs/05-guides/09-permissions.mdx +++ b/website/docs/05-guides/09-permissions.mdx @@ -158,11 +158,11 @@ type Ctx = { isAdmin: true; }; -const AdminToken = Symbol("AdminToken"); +// Use "branded types" to ensure nobody else can construct an AdminToken. +// https://egghead.io/blog/using-branded-types-in-typescript +type AdminToken = "AdminToken" & { __brand: "AdminToken" }; -// Maybe we could use branded types to make this type impossible to -// construct generally? -type AssertAdminToken = typeof AdminToken; +type AssertAdminToken = AdminToken; /** * @gqlContext @@ -171,7 +171,7 @@ export function adminCheck(ctx: Ctx): AssertAdminToken { if (!ctx.isAdmin) { throw new Error("You do not have permission to access this field"); } - return AdminToken; + return "AdminToken" as AdminToken; } ``` @@ -184,14 +184,14 @@ In this case, you can define a "maybe" derived context type which is either the These two token approaches can also be combined! ```ts -type MaybeAdminToken = typeof AdminToken | null; +type MaybeAdminToken = AdminToken | null; /** * @gqlContext */ export function maybeAdminToken(ctx: Ctx): MaybeAdminToken { if (ctx.isAdmin) { - return AdminToken; + return "AdminToken" as AdminToken; } return null; } @@ -206,7 +206,7 @@ export function someField(admin: MaybeAdminToken): string { return someDataLayerFunction(admin); } -function someDataLayerFunction(admin: typeof AdminToken) { +function someDataLayerFunction(admin: AdminToken) { return "Here is your data"; } ``` From 19d5f073efaff0df21a2e87cd6a76da027fd10f3 Mon Sep 17 00:00:00 2001 From: Jordan Eldredge Date: Wed, 29 Oct 2025 16:12:30 -0700 Subject: [PATCH 2/2] Pothos interop init --- examples/pothos-interop/README.md | 8 + examples/pothos-interop/Subscription.ts | 9 + examples/pothos-interop/interfaces/IPerson.ts | 12 ++ examples/pothos-interop/models/Group.ts | 20 +++ examples/pothos-interop/models/User.ts | 22 +++ examples/pothos-interop/package.json | 40 +++++ examples/pothos-interop/pothosTypes.ts | 17 ++ examples/pothos-interop/schema.graphql | 27 +++ examples/pothos-interop/schema.ts | 135 +++++++++++++++ examples/pothos-interop/server.ts | 36 ++++ examples/pothos-interop/tsconfig.json | 15 ++ pnpm-lock.yaml | 74 ++++++++- scripts/TGratsConfig.ts | 97 ----------- scripts/buildConfigTypes.ts | 2 +- src/Errors.ts | 4 + src/Extractor.ts | 141 ++++++++++------ src/GraphQLAstExtensions.ts | 6 + src/GraphQLConstructor.ts | 6 + src/TGratsConfig.ts | 23 ++- src/cli.ts | 11 ++ src/codegen/TSAstBuilder.ts | 13 +- src/codegen/enumCodegen.ts | 7 +- src/codegen/pothosTypeCodegen.ts | 156 ++++++++++++++++++ src/codegen/resolverCodegen.ts | 28 +--- src/codegen/schemaCodegen.ts | 24 ++- src/configSpecRaw.json | 13 ++ src/metadata.ts | 11 +- src/printSchema.ts | 8 + .../configParserFixtures/empty.json.expected | 2 + .../experimentalField.json.expected | 2 + .../multiLineHeader.json.expected | 2 + .../ArgumentWithDescription.ts.expected | 3 +- .../CustomScalarArgument.ts.expected | 3 +- .../arguments/DeprecatedArgument.ts.expected | 3 +- .../GqlTypeUsedAsPositionalArg.ts.expected | 3 +- .../arguments/NullableArguments.ts.expected | 3 +- .../arguments/OptionalArgument.ts.expected | 3 +- ...NonNullableArgumentWithDefault.ts.expected | 3 +- ...ositionalArgDeprecatedOptional.ts.expected | 3 +- ...tionalArgDeprecatedWithDefault.ts.expected | 3 +- .../PositionalArgOptional.ts.expected | 3 +- .../PositionalArgWithDefault.ts.expected | 3 +- .../PositionalArgWithDescription.ts.expected | 3 +- .../arguments/StringArgument.ts.expected | 3 +- .../built_in_scalars/FloatField.ts.expected | 3 +- .../FloatFieldAliasedImport.ts.expected | 3 +- .../built_in_scalars/IdField.ts.expected | 3 +- .../built_in_scalars/IntField.ts.expected | 3 +- .../importModuleSpecifierEnding.ts.expected | 3 +- .../DefaultArgumentArray.ts.expected | 3 +- .../DefaultArgumentBooleanLiteral.ts.expected | 3 +- .../DefaultArgumentNullLiteral.ts.expected | 3 +- .../DefaultArgumentNumberLiteral.ts.expected | 3 +- .../DefaultArgumentObjectLiteral.ts.expected | 3 +- .../DefaultArgumentPropertyName.ts.expected | 3 +- .../DefaultArgumentStringLiteral.ts.expected | 3 +- ...ArgumentStringLiteralBackticks.ts.expected | 3 +- .../fixtures/examples/playground.ts.expected | 3 +- .../DeprecatedMethodField.ts.expected | 3 +- .../DeprecatedPropertyField.ts.expected | 3 +- .../FieldAsStaticClassMethod.ts.expected | 4 +- ...MethodWithClassAsDefaultExport.ts.expected | 3 +- .../GetAcessorField.ts.expected | 3 +- ...ipleFieldsAsStaticClassMethods.ts.expected | 4 +- .../ParameterPropertyField.ts.expected | 3 +- ...rameterPropertyFieldDeprecated.ts.expected | 3 +- ...ParameterPropertyFieldReadOnly.ts.expected | 3 +- .../ParameterPropertyFieldRenamed.ts.expected | 3 +- ...erPropertyFieldWithDescription.ts.expected | 3 +- .../PublicFieldMethod.ts.expected | 3 +- .../RenamedFieldWithArgs.ts.expected | 3 +- .../StringFieldWithDescription.ts.expected | 3 +- .../field_values/ArrayField.ts.expected | 3 +- .../field_values/ArrayOfPromises.ts.expected | 3 +- .../ArrayShorthandField.ts.expected | 3 +- .../ArrayWithNullableItems.ts.expected | 3 +- .../AsyncPromiseField.ts.expected | 3 +- .../field_values/BooleanField.ts.expected | 3 +- .../field_values/CustomScalar.ts.expected | 3 +- .../field_values/KitchenSink.ts.expected | 3 +- .../field_values/MaybePromise.ts.expected | 3 +- .../field_values/OptionalFields.ts.expected | 3 +- .../field_values/OptionalProperty.ts.expected | 3 +- .../ParenthesizedType.ts.expected | 3 +- .../field_values/PromiseOfPromise.ts.expected | 3 +- .../ReadonlyArrayField.ts.expected | 3 +- .../field_values/StringField.ts.expected | 3 +- ...ingFieldKillsParentOnException.ts.expected | 3 +- .../field_values/UnionField.ts.expected | 3 +- .../NonNullablePromise.ts.expected | 3 +- .../NullablePromise.ts.expected | 3 +- .../generics/genericOverArg.ts.expected | 4 +- .../genericTypeUsingClass.ts.expected | 4 +- .../headers/customHeaders.ts.expected | 3 +- .../headers/multilineHeader.ts.expected | 3 +- .../InputTypeWithDeprecatedField.ts.expected | 3 +- .../InputTypeWithFieldDescription.ts.expected | 3 +- .../FieldReturnsInterface.ts.expected | 3 +- .../IgnoresExtendsClause.ts.expected | 3 +- .../ImplementsInterface.ts.expected | 3 +- ...plementsInterfaceWithTypeParam.ts.expected | 3 +- .../ImplementsMultipleInterfaces.ts.expected | 3 +- .../InterfaceFieldWithDescription.ts.expected | 3 +- ...DescriptionThatDiffersFromType.ts.expected | 3 +- .../InterfaceWithCustomName.ts.expected | 3 +- .../InterfaceWithDeprecatedField.ts.expected | 3 +- .../InterfaceWithDescription.ts.expected | 3 +- .../pothos_integration/customScalar.ts | 4 + .../customScalar.ts.expected | 44 +++++ .../defaultNullabilityOff.ts | 7 + .../defaultNullabilityOff.ts.expected | 47 ++++++ .../pothos_integration/simplePothosExample.ts | 13 ++ .../simplePothosExample.ts.expected | 72 ++++++++ .../ClassMethodWithContextValue.ts.expected | 3 +- ...MethodWithContextValueExported.ts.expected | 3 +- .../ContextValueBeforeArgs.ts.expected | 3 +- .../ContextValueOptional.ts.expected | 3 +- .../ContextValueReadTwice.ts.expected | 3 +- .../FunctionWithContextValue.ts.expected | 4 +- ...MethodsReferencingContextValue.ts.expected | 3 +- .../ClassMethodWithInfoValue.ts.expected | 3 +- .../StaticMethodWithInfoValue.ts.expected | 4 +- .../semanticNonNull.ts.expected | 3 +- ...emanticNonNullMatchesInterface.ts.expected | 3 +- .../semanticNull.ts.expected | 3 +- ...criptionClassWithAsyncIterable.ts.expected | 3 +- ...TypeWithVariantWithDescription.ts.expected | 3 +- ...ClassImplementsNonGqlInterface.ts.expected | 3 +- .../ClassWithDescription.ts.expected | 3 +- ...ssWithDescriptionAndCustomName.ts.expected | 3 +- ...sDefinitionImplementsInterface.ts.expected | 3 +- ...onImplementsMultipleInterfaces.ts.expected | 3 +- .../PropertySignatureTypename.ts.expected | 3 +- .../typename/PropertyTypename.ts.expected | 3 +- .../unions/DefineUnionType.ts.expected | 3 +- .../DefineUnionTypeWithInterfaces.ts.expected | 3 +- ...efineUnionTypeWithTypeLiterals.ts.expected | 3 +- .../unions/UnionWithDescription.ts.expected | 3 +- .../resolveTypeViaClass/schema.ts | 11 +- src/tests/test.ts | 29 +++- src/transforms/makeResolverSignature.ts | 18 +- src/tsPlugin/initTsPlugin.ts | 2 + 142 files changed, 1205 insertions(+), 322 deletions(-) create mode 100644 examples/pothos-interop/README.md create mode 100644 examples/pothos-interop/Subscription.ts create mode 100644 examples/pothos-interop/interfaces/IPerson.ts create mode 100644 examples/pothos-interop/models/Group.ts create mode 100644 examples/pothos-interop/models/User.ts create mode 100644 examples/pothos-interop/package.json create mode 100644 examples/pothos-interop/pothosTypes.ts create mode 100644 examples/pothos-interop/schema.graphql create mode 100644 examples/pothos-interop/schema.ts create mode 100644 examples/pothos-interop/server.ts create mode 100644 examples/pothos-interop/tsconfig.json delete mode 100644 scripts/TGratsConfig.ts create mode 100644 src/codegen/pothosTypeCodegen.ts create mode 100644 src/tests/fixtures/pothos_integration/customScalar.ts create mode 100644 src/tests/fixtures/pothos_integration/customScalar.ts.expected create mode 100644 src/tests/fixtures/pothos_integration/defaultNullabilityOff.ts create mode 100644 src/tests/fixtures/pothos_integration/defaultNullabilityOff.ts.expected create mode 100644 src/tests/fixtures/pothos_integration/simplePothosExample.ts create mode 100644 src/tests/fixtures/pothos_integration/simplePothosExample.ts.expected diff --git a/examples/pothos-interop/README.md b/examples/pothos-interop/README.md new file mode 100644 index 00000000..ba9d5800 --- /dev/null +++ b/examples/pothos-interop/README.md @@ -0,0 +1,8 @@ +# Grats + Yoga + node:http + +Simple demo project integrating [Grats](https://grats.capt.dev/) and [Yoga](https://github.com/dotansimha/graphql-yoga) with Node's built-in HTTP server. This example also includes an working example of GraphQL subscriptions. + +## Running the demo + +- `$ pnpm install` +- `$ pnpm run start` diff --git a/examples/pothos-interop/Subscription.ts b/examples/pothos-interop/Subscription.ts new file mode 100644 index 00000000..4cf48bdc --- /dev/null +++ b/examples/pothos-interop/Subscription.ts @@ -0,0 +1,9 @@ +import { Int } from "grats"; + +/** @gqlSubscriptionField */ +export async function* countdown(args: { from: Int }): AsyncIterable { + for (let i = args.from; i >= 0; i--) { + await new Promise((resolve) => setTimeout(resolve, 1000)); + yield i; + } +} diff --git a/examples/pothos-interop/interfaces/IPerson.ts b/examples/pothos-interop/interfaces/IPerson.ts new file mode 100644 index 00000000..21cbc43c --- /dev/null +++ b/examples/pothos-interop/interfaces/IPerson.ts @@ -0,0 +1,12 @@ +import User from "../models/User"; + +/** @gqlInterface */ +export default interface IPerson { + /** @gqlField */ + name(): string; +} + +/** @gqlQueryField */ +export function person(): IPerson { + return new User(); +} diff --git a/examples/pothos-interop/models/Group.ts b/examples/pothos-interop/models/Group.ts new file mode 100644 index 00000000..9e672ad3 --- /dev/null +++ b/examples/pothos-interop/models/Group.ts @@ -0,0 +1,20 @@ +import User from "./User"; + +/** @gqlType */ +export default class Group { + /** @gqlField */ + description: string; + + constructor() { + this.description = "A group of people"; + } + + /** @gqlField */ + name(): string { + return "Pal's Club"; + } + /** @gqlField */ + async members(): Promise { + return [new User()]; + } +} diff --git a/examples/pothos-interop/models/User.ts b/examples/pothos-interop/models/User.ts new file mode 100644 index 00000000..6b1d0fa8 --- /dev/null +++ b/examples/pothos-interop/models/User.ts @@ -0,0 +1,22 @@ +import IPerson from "../interfaces/IPerson"; +import Group from "./Group"; + +/** @gqlType User */ +export default class User implements IPerson { + /** @gqlField */ + name(): string { + return "Alice"; + } + /** @gqlField */ + groups(): Group[] { + return [new Group()]; + } + /** @gqlQueryField */ + static me(): User { + return new User(); + } + /** @gqlQueryField */ + static allUsers(): User[] { + return [new User(), new User()]; + } +} diff --git a/examples/pothos-interop/package.json b/examples/pothos-interop/package.json new file mode 100644 index 00000000..c767dfba --- /dev/null +++ b/examples/pothos-interop/package.json @@ -0,0 +1,40 @@ +{ + "name": "grats-example-yoga", + "version": "0.0.0", + "description": "Example server showcasing Grats used with Yoga", + "main": "index.js", + "scripts": { + "start": "tsc && node dist/server.js", + "grats": "grats", + "build": "tsc" + }, + "repository": { + "type": "git", + "url": "git+https://github.com/captbaritone/grats.git" + }, + "keywords": [ + "graphql", + "grats", + "yoga", + "javascript", + "typescript", + "subscriptions" + ], + "author": "", + "license": "ISC", + "bugs": { + "url": "https://github.com/captbaritone/grats/issues" + }, + "homepage": "https://github.com/captbaritone/grats#readme", + "dependencies": { + "@pothos/core": "^3.41.1", + "@pothos/plugin-add-graphql": "^4.2.4", + "graphql": "16.8.1", + "graphql-yoga": "^5.0.0", + "typescript": "^5.5.4" + }, + "devDependencies": { + "@types/node": "^20.8.10", + "grats": "workspace:*" + } +} diff --git a/examples/pothos-interop/pothosTypes.ts b/examples/pothos-interop/pothosTypes.ts new file mode 100644 index 00000000..928dcc3b --- /dev/null +++ b/examples/pothos-interop/pothosTypes.ts @@ -0,0 +1,17 @@ +import IPersonInternal from "./interfaces/IPerson"; +import GroupInternal from "./models/Group"; +import UserInternal from "./models/User"; + +type EnsureSubtype> = T; + +export type PothosUserSchemaTypes = EnsureSubtype<{ + Defaults: "v4"; + Objects: { + Group: GroupInternal; + User: UserInternal; + }; + Interface: { + IPerson: IPersonInternal; + }; + DefaultFieldNullability: true; +}>; diff --git a/examples/pothos-interop/schema.graphql b/examples/pothos-interop/schema.graphql new file mode 100644 index 00000000..bc728c21 --- /dev/null +++ b/examples/pothos-interop/schema.graphql @@ -0,0 +1,27 @@ +# Schema generated by Grats (https://grats.capt.dev) +# Do not manually edit. Regenerate by running `npx grats`. + +interface IPerson { + name: String +} + +type Group { + description: String + members: [User!] + name: String +} + +type Query { + allUsers: [User!] + me: User + person: IPerson +} + +type Subscription { + countdown(from: Int!): Int +} + +type User implements IPerson { + groups: [Group!] + name: String +} diff --git a/examples/pothos-interop/schema.ts b/examples/pothos-interop/schema.ts new file mode 100644 index 00000000..185239ac --- /dev/null +++ b/examples/pothos-interop/schema.ts @@ -0,0 +1,135 @@ +/** + * Executable schema generated by Grats (https://grats.capt.dev) + * Do not manually edit. Regenerate by running `npx grats`. + */ + +import type TUser from "./models/User"; +import type TGroup from "./models/Group"; +import UserClass from "./models/User"; +import queryAllUsersResolver from "./models/User"; +import queryMeResolver from "./models/User"; +import { GraphQLSchema, GraphQLObjectType, GraphQLList, GraphQLNonNull, GraphQLString, GraphQLInterfaceType, GraphQLInt } from "graphql"; +import { person as queryPersonResolver } from "./interfaces/IPerson"; +import { countdown as subscriptionCountdownResolver } from "./Subscription"; +export function getSchema(): GraphQLSchema { + const GroupType: GraphQLObjectType = new GraphQLObjectType({ + name: "Group", + fields() { + return { + description: { + name: "description", + type: GraphQLString + }, + members: { + name: "members", + type: new GraphQLList(new GraphQLNonNull(UserType)) + }, + name: { + name: "name", + type: GraphQLString + } + }; + } + }); + const IPersonType: GraphQLInterfaceType = new GraphQLInterfaceType({ + name: "IPerson", + fields() { + return { + name: { + name: "name", + type: GraphQLString + } + }; + }, + resolveType + }); + const UserType: GraphQLObjectType = new GraphQLObjectType({ + name: "User", + fields() { + return { + groups: { + name: "groups", + type: new GraphQLList(new GraphQLNonNull(GroupType)) + }, + name: { + name: "name", + type: GraphQLString + } + }; + }, + interfaces() { + return [IPersonType]; + } + }); + const QueryType: GraphQLObjectType = new GraphQLObjectType({ + name: "Query", + fields() { + return { + allUsers: { + name: "allUsers", + type: new GraphQLList(new GraphQLNonNull(UserType)), + resolve() { + return queryAllUsersResolver.allUsers(); + } + }, + me: { + name: "me", + type: UserType, + resolve() { + return queryMeResolver.me(); + } + }, + person: { + name: "person", + type: IPersonType, + resolve() { + return queryPersonResolver(); + } + } + }; + } + }); + const SubscriptionType: GraphQLObjectType = new GraphQLObjectType({ + name: "Subscription", + fields() { + return { + countdown: { + name: "countdown", + type: GraphQLInt, + args: { + from: { + type: new GraphQLNonNull(GraphQLInt) + } + }, + subscribe(_source, args) { + return subscriptionCountdownResolver(args); + }, + resolve(payload) { + return payload; + } + } + }; + } + }); + return new GraphQLSchema({ + query: QueryType, + subscription: SubscriptionType, + types: [IPersonType, GroupType, QueryType, SubscriptionType, UserType] + }); +} +const typeNameMap = new Map(); +typeNameMap.set(UserClass, "User"); +function resolveType(obj: any): string { + if (typeof obj.__typename === "string") { + return obj.__typename; + } + let prototype = Object.getPrototypeOf(obj); + while (prototype) { + const name = typeNameMap.get(prototype.constructor); + if (name != null) { + return name; + } + prototype = Object.getPrototypeOf(prototype); + } + throw new Error("Cannot find type name."); +} diff --git a/examples/pothos-interop/server.ts b/examples/pothos-interop/server.ts new file mode 100644 index 00000000..ded65898 --- /dev/null +++ b/examples/pothos-interop/server.ts @@ -0,0 +1,36 @@ +import { createServer } from "node:http"; +import { createYoga } from "graphql-yoga"; +import { getSchema } from "./schema"; +import SchemaBuilder from "@pothos/core"; +import AddGraphQLPlugin from "@pothos/plugin-add-graphql"; +import { PothosUserSchemaTypes } from "./pothosTypes"; +import User from "./models/User"; + +const builder = new SchemaBuilder({ + plugins: [AddGraphQLPlugin], + add: { schema: getSchema() }, + // Pothos + Grats' generated PothosUserSchemaTypes ensure this matches + // the value in Grats config. + defaultFieldNullability: true, +}); + +builder.queryType({ + fields: (t) => ({ + pothosAllUsers: t.field({ + type: ["User"], + resolve: () => { + return User.allUsers(); + }, + }), + }), +}); + +const yoga = createYoga({ + schema: builder.toSchema(), +}); + +const server = createServer(yoga); + +server.listen(4000, () => { + console.log("Running a GraphQL API server at http://localhost:4000/graphql"); +}); diff --git a/examples/pothos-interop/tsconfig.json b/examples/pothos-interop/tsconfig.json new file mode 100644 index 00000000..35efce61 --- /dev/null +++ b/examples/pothos-interop/tsconfig.json @@ -0,0 +1,15 @@ +{ + "grats": { + "requireExportedTypes": true, + "EXPERIMENTAL__emitPothos": "./pothosTypes.ts" + }, + "compilerOptions": { + "outDir": "dist", + "module": "NodeNext", + "moduleResolution": "NodeNext", + "target": "esnext", + "lib": ["esnext"], + "strict": true, + "skipLibCheck": true + } +} diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index aa72a797..7b7f2996 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -170,6 +170,31 @@ importers: specifier: ^5.5.4 version: 5.5.4 + examples/pothos-interop: + dependencies: + '@pothos/core': + specifier: ^3.41.1 + version: 3.41.1(graphql@16.8.1) + '@pothos/plugin-add-graphql': + specifier: ^4.2.4 + version: 4.2.4(@pothos/core@3.41.1(graphql@16.8.1))(graphql@16.8.1) + graphql: + specifier: 16.8.1 + version: 16.8.1 + graphql-yoga: + specifier: ^5.0.0 + version: 5.16.0(graphql@16.8.1) + typescript: + specifier: ^5.5.4 + version: 5.9.2 + devDependencies: + '@types/node': + specifier: ^20.8.10 + version: 20.8.10 + grats: + specifier: workspace:* + version: link:../.. + examples/production-app: dependencies: '@graphql-tools/utils': @@ -2513,6 +2538,12 @@ packages: peerDependencies: graphql: '>=15.1.0' + '@pothos/plugin-add-graphql@4.2.4': + resolution: {integrity: sha512-gRQLLD98Z/OsJv5FUytaWrtf0vI4KS1TRXfrKYMWx8LElMYxjdOQWQl3Oa92czgQBJpY1tSBIB2Ow2qFfwl/iQ==} + peerDependencies: + '@pothos/core': '*' + graphql: ^16.10.0 + '@protobufjs/aspromise@1.1.2': resolution: {integrity: sha512-j+gKExEuLmKwvz3OgROXtrJ2UG2x8Ch2YZUxahh+s1F2HZ+wAceUNLkvy6zKCPVRkU++ZWQrdxsUeQXmcg4uoQ==} @@ -10414,6 +10445,16 @@ snapshots: graphql: 16.11.0 tslib: 2.8.1 + '@graphql-tools/executor@1.4.9(graphql@16.8.1)': + dependencies: + '@graphql-tools/utils': 10.9.1(graphql@16.8.1) + '@graphql-typed-document-node/core': 3.2.0(graphql@16.8.1) + '@repeaterjs/repeater': 3.0.5 + '@whatwg-node/disposablestack': 0.0.6 + '@whatwg-node/promise-helpers': 1.3.2 + graphql: 16.8.1 + tslib: 2.8.1 + '@graphql-tools/merge@9.0.12(graphql@16.11.0)': dependencies: '@graphql-tools/utils': 10.6.2(graphql@16.11.0) @@ -10481,6 +10522,15 @@ snapshots: graphql: 16.11.0 tslib: 2.8.1 + '@graphql-tools/utils@10.9.1(graphql@16.8.1)': + dependencies: + '@graphql-typed-document-node/core': 3.2.0(graphql@16.8.1) + '@whatwg-node/promise-helpers': 1.3.2 + cross-inspect: 1.0.1 + dset: 3.1.4 + graphql: 16.8.1 + tslib: 2.8.1 + '@graphql-tools/utils@9.2.1(graphql@16.11.0)': dependencies: '@graphql-typed-document-node/core': 3.1.2(graphql@16.11.0) @@ -10718,6 +10768,11 @@ snapshots: dependencies: graphql: 16.8.1 + '@pothos/plugin-add-graphql@4.2.4(@pothos/core@3.41.1(graphql@16.8.1))(graphql@16.8.1)': + dependencies: + '@pothos/core': 3.41.1(graphql@16.8.1) + graphql: 16.8.1 + '@protobufjs/aspromise@1.1.2': {} '@protobufjs/base64@1.1.2': {} @@ -13172,6 +13227,23 @@ snapshots: lru-cache: 10.0.2 tslib: 2.8.1 + graphql-yoga@5.16.0(graphql@16.8.1): + dependencies: + '@envelop/core': 5.3.2 + '@envelop/instrumentation': 1.0.0 + '@graphql-tools/executor': 1.4.9(graphql@16.8.1) + '@graphql-tools/schema': 10.0.11(graphql@16.8.1) + '@graphql-tools/utils': 10.6.2(graphql@16.8.1) + '@graphql-yoga/logger': 2.0.1 + '@graphql-yoga/subscription': 5.0.5 + '@whatwg-node/fetch': 0.10.11 + '@whatwg-node/promise-helpers': 1.3.2 + '@whatwg-node/server': 0.10.12 + dset: 3.1.4 + graphql: 16.8.1 + lru-cache: 10.0.2 + tslib: 2.8.1 + graphql@16.11.0: {} graphql@16.8.1: {} @@ -13180,7 +13252,7 @@ snapshots: dependencies: commander: 10.0.1 graphql: 16.11.0 - typescript: 5.5.4 + typescript: 5.9.2 gray-matter@4.0.3: dependencies: diff --git a/scripts/TGratsConfig.ts b/scripts/TGratsConfig.ts deleted file mode 100644 index d6efa30f..00000000 --- a/scripts/TGratsConfig.ts +++ /dev/null @@ -1,97 +0,0 @@ -/** - * This file is generated by src/gratsConfigBeta.ts. Do not edit directly. - * Run `pnpm run test` to regenerate. - */ - -/** - * Describes the shape of the Grats config after parsing, validation, and - * defaults. - */ -export type GratsConfig = { - /** - * Where Grats should write your schema file. Path is relative to the - * `tsconfig.json` file. - */ - graphqlSchema: string; - /** - * Where Grats should write your executable TypeScript schema file. Path - * is relative to the `tsconfig.json` file. - */ - tsSchema: string; - /** - * Where Grats should write your TypeScript enums file. Path is relative - * to the `tsconfig.json` file. - * If enabled, Grats will require that all GraphQL enums be defined using - * exported TypeScript enums. Set to `null` to disable emitting this file. - */ - tsClientEnums: string | null; - /** - * Should all fields be typed as nullable in accordance with GraphQL best - * practices? - * https://graphql.org/learn/best-practices/#nullability - * Individual fields can declare themselves as non-nullable by adding the - * docblock tag `@killsParentOnException`. - */ - nullableByDefault: boolean; - /** - * Experimental feature to add `@semanticNonNull` to all fields which have - * non-null TypeScript return types, but which are made nullable by the - * `nullableByDefault` option. - * This feature allows clients which handle errors out of band, for - * example by discarding responses with errors, to know which fields are - * expected to be non-null in the absence of errors. - * See https://grats.capt.dev/docs/guides/strict-semantic-nullability - * It is an error to enable `strictSemanticNullability` if - * `nullableByDefault` is false. - */ - strictSemanticNullability: boolean; - /** - * Should Grats error if it encounters a TypeScript type error? - * Note that Grats will always error if it encounters a TypeScript syntax - * error. - */ - reportTypeScriptTypeErrors: boolean; - /** - * A string to prepend to the generated schema text. Useful for copyright - * headers or instructions for how to regenerate the file. Set to `null` - * to omit the default header. - */ - schemaHeader: string | null; - /** - * A string to prepend to the generated TypeScript schema file. Useful for - * copyright headers or instructions for how to regenerate the file. Set - * to `null` to omit the default header. - */ - tsSchemaHeader: string | null; - /** - * A string to prepend to the TypeScript enums file generated when the - * `tsClientEnums` configuration options is set. Useful for copyright - * headers or instructions for how to regenerate the file. Set to `null` - * to omit the default header. - */ - tsClientEnumsHeader: string | null; - /** - * This option allows you configure an extension that will be appended to - * the end of all import paths in the generated TypeScript schema file. - * When building a package that uses ES modules, import paths must not - * omit the file extension. In TypeScript code this generally means import - * paths must end with `.js`. If set to null, no ending will be appended. - */ - importModuleSpecifierEnding: string; - /** - * EXPERIMENTAL: THIS OPTION WILL BE RENAMED OR REMOVED IN A FUTURE - * RELEASE - * Emit a JSON file alongside the generated schema file which contains the - * metadata containing information about the resolvers. - */ - EXPERIMENTAL__emitMetadata: boolean; - /** - * EXPERIMENTAL: THIS OPTION WILL BE RENAMED OR REMOVED IN A FUTURE - * RELEASE - * Instead of emitting a TypeScript file which creates a GraphQLSchema, - * emit a TypeScript file which creates a GraphQL Tools style Resolver - * Map. - * https://the-guild.dev/graphql/tools/docs/resolvers#resolver-map - */ - EXPERIMENTAL__emitResolverMap: boolean; -}; diff --git a/scripts/buildConfigTypes.ts b/scripts/buildConfigTypes.ts index 52184e4e..eb5ce0d7 100644 --- a/scripts/buildConfigTypes.ts +++ b/scripts/buildConfigTypes.ts @@ -15,6 +15,6 @@ export function writeTypeScriptTypeToDisk(): void { */ ${makeTypeScriptType(GratsConfigSpec)} `; - const outPath = path.join(__dirname, "TGratsConfig.ts"); + const outPath = path.join(__dirname, "../src/TGratsConfig.ts"); fs.writeFileSync(outPath, doc, "utf8"); } diff --git a/src/Errors.ts b/src/Errors.ts index 02365ba4..5f2ae145 100644 --- a/src/Errors.ts +++ b/src/Errors.ts @@ -646,6 +646,10 @@ export function enumNotExported(): string { return "Expected enum to be exported when `tsClientEnums` is configured. Grats needs to import enum types to build the enums module."; } +export function definitionNotExported(): string { + return "Expected GraphQL definition to be exported. Grats needs to import this definitions type into its generated TypeScript schema."; +} + export function typeAliasEnumNotSupportedWithEmitEnums(): string { return 'Type alias enums are not supported when `tsClientEnums` is configured. Use `enum` declarations instead. For example: `export enum Status { PENDING = "pending" }`.'; } diff --git a/src/Extractor.ts b/src/Extractor.ts index e6bdbd32..748bf318 100644 --- a/src/Extractor.ts +++ b/src/Extractor.ts @@ -138,7 +138,7 @@ type FieldTypeContext = { */ export function extract( sourceFile: ts.SourceFile, - config?: { tsClientEnums?: string | null }, + config: { tsClientEnums?: string | null; requireExportedTypes: boolean }, ): DiagnosticsResult { const extractor = new Extractor(config); return extractor.extract(sourceFile); @@ -157,9 +157,12 @@ class Extractor { errors: ts.DiagnosticWithLocation[] = []; gql: GraphQLConstructor; - config?: { tsClientEnums?: string | null }; + config: { tsClientEnums?: string | null; requireExportedTypes: boolean }; - constructor(config?: { tsClientEnums?: string | null }) { + constructor(config: { + tsClientEnums?: string | null; + requireExportedTypes: boolean; + }) { this.gql = new GraphQLConstructor(); this.config = config; } @@ -689,8 +692,17 @@ class Extractor { const directives = this.collectDirectives(node); + const exported = this.maybeExported(node); + this.definitions.push( - this.gql.unionTypeDefinition(node, name, types, description, directives), + this.gql.unionTypeDefinition( + node, + name, + types, + description, + directives, + exported, + ), ); } @@ -1077,31 +1089,83 @@ class Extractor { const directives = this.collectDirectives(node); + const exported = this.assertExported(node); + if (exported == null) return null; + + this.definitions.push( + this.gql.scalarTypeDefinition( + node, + name, + directives, + description, + exported, + ), + ); + } + + assertExported(node: ts.TypeAliasDeclaration): ExportDefinition | null { const isExported = node.modifiers?.find( (modifier) => modifier.kind === ts.SyntaxKind.ExportKeyword, ); if (!isExported) { + // TODO: Make this error generic this.report(node.name, E.scalarNotExported(), [], { fixName: "add-export-keyword-to-scalar", description: "Add export keyword to type alias with @gqlScalar", changes: [Act.prefixNode(node, "export ")], }); + return null; } - const exported: ExportDefinition = { + return { tsModulePath: relativePath(node.getSourceFile().fileName), exportName: node.name.text, }; + } - this.definitions.push( - this.gql.scalarTypeDefinition( - node, - name, - directives, - description, - exported, - ), + maybeExported( + node: + | ts.TypeAliasDeclaration + | ts.ClassDeclaration + | ts.TypeAliasDeclaration + | ts.InterfaceDeclaration + | ts.EnumDeclaration, + ): ExportDefinition | null { + const isExported = node.modifiers?.find( + (modifier) => modifier.kind === ts.SyntaxKind.ExportKeyword, + ); + if (!isExported) { + if (this.config.requireExportedTypes) { + return this.report(node, E.enumNotExported(), [], { + fixName: "add-export-keyword-to-definition", + description: "Add export keyword definition", + changes: [Act.prefixNode(node, "export ")], + }); + } else { + return null; + } + } + + const isDefault = node.modifiers?.find( + (modifier) => modifier.kind === ts.SyntaxKind.DefaultKeyword, ); + + const tsModulePath = relativePath(node.getSourceFile().fileName); + + // Special case for ClassDeclarations since in some cases they may be missing a name. + if (ts.isClassDeclaration(node)) { + if (isDefault) return { exportName: null, tsModulePath }; + if (node.name == null) { + // This is invalid TypeScript, but we should still handle it gracefully. + return this.report( + node, + "Expected non-default exported class to have a name.", + ); + } + return { exportName: node.name.text, tsModulePath }; + } + + return { tsModulePath, exportName: isDefault ? null : node.name.text }; } inputTypeAliasDeclaration(node: ts.TypeAliasDeclaration, tag: ts.JSDocTag) { @@ -1126,6 +1190,8 @@ class Extractor { if (fields == null) return; + const exported = this.maybeExported(node); + this.definitions.push( this.gql.inputObjectTypeDefinition( node, @@ -1133,6 +1199,7 @@ class Extractor { fields, directives, description, + exported, ), ); } @@ -1163,6 +1230,8 @@ class Extractor { const directives = this.collectDirectives(node); + const exported = this.maybeExported(node); + this.definitions.push( this.gql.inputObjectTypeDefinition( node, @@ -1170,6 +1239,7 @@ class Extractor { fields, directives, description, + exported, ), ); } @@ -1220,6 +1290,7 @@ class Extractor { // All fields must be nullable since only one will be present at a time. const type = this.gql.nullableType(inner); + return this.gql.inputValueDefinition( node, this.gql.name(name, name.text), @@ -1308,22 +1379,7 @@ class Extractor { const hasTypeName = this.checkForTypenameProperty(node, name.value); - let exported: { tsModulePath: string; exportName: string | null } | null = - null; - if (!hasTypeName) { - const isExported = node.modifiers?.find( - (modifier) => modifier.kind === ts.SyntaxKind.ExportKeyword, - ); - const isDefault = node.modifiers?.find( - (modifier) => modifier.kind === ts.SyntaxKind.DefaultKeyword, - ); - if (isExported) { - exported = { - tsModulePath: relativePath(node.getSourceFile().fileName), - exportName: isDefault ? null : node.name.text, - }; - } - } + const exported = this.maybeExported(node); const directives = this.collectDirectives(node); @@ -1691,6 +1747,8 @@ class Extractor { const directives = this.collectDirectives(node); + const exported = this.maybeExported(node); + this.definitions.push( this.gql.interfaceTypeDefinition( node, @@ -1699,6 +1757,7 @@ class Extractor { interfaces, description, directives, + exported, ), ); } @@ -2029,13 +2088,8 @@ class Extractor { } // Check if enum must be exported when tsClientEnums is configured - let exported: { tsModulePath: string; exportName: string | null } | null = - null; - const isExported = node.modifiers?.some((modifier) => { - return modifier.kind === ts.SyntaxKind.ExportKeyword; - }); - - if (this.config?.tsClientEnums != null && !isExported) { + const exported = this.maybeExported(node); + if (this.config?.tsClientEnums != null && !exported) { this.report(node, E.enumNotExported(), [], { fixName: "add-export-keyword-to-enum", description: "Add export keyword to enum with @gqlEnum", @@ -2044,16 +2098,6 @@ class Extractor { return; } - if (isExported) { - const isDefault = node.modifiers?.find( - (modifier) => modifier.kind === ts.SyntaxKind.DefaultKeyword, - ); - exported = { - tsModulePath: relativePath(node.getSourceFile().fileName), - exportName: isDefault ? null : (node.name?.text ?? null), - }; - } - const description = this.collectDescription(node); const values = this.collectEnumValues(node); @@ -2084,7 +2128,7 @@ class Extractor { } // Prohibit type alias enums when tsClientEnums is configured - if (this.config?.tsClientEnums != null) { + if (this.config.tsClientEnums != null) { this.report(node, E.typeAliasEnumNotSupportedWithEmitEnums()); return; } @@ -2096,6 +2140,7 @@ class Extractor { this.recordTypeName(node, name, "ENUM"); const directives = this.collectDirectives(node); + const exported = this.maybeExported(node); this.definitions.push( this.gql.enumTypeDefinition( @@ -2104,7 +2149,7 @@ class Extractor { values, description, directives, - null, + exported, ), ); } diff --git a/src/GraphQLAstExtensions.ts b/src/GraphQLAstExtensions.ts index b6107242..32c67c6c 100644 --- a/src/GraphQLAstExtensions.ts +++ b/src/GraphQLAstExtensions.ts @@ -40,12 +40,17 @@ declare module "graphql" { hasTypeNameField: boolean; exported?: ExportDefinition; } + + export interface InputObjectTypeDefinitionNode { + exported?: ExportDefinition; + } export interface UnionTypeDefinitionNode { /** * Grats metadata: Indicates that the type was materialized as part of * generic type resolution. */ wasSynthesized?: boolean; + exported?: ExportDefinition; } export interface InterfaceTypeDefinitionNode { /** @@ -53,6 +58,7 @@ declare module "graphql" { * generic type resolution. */ wasSynthesized?: boolean; + exported?: ExportDefinition; } export interface ObjectTypeExtensionNode { /** diff --git a/src/GraphQLConstructor.ts b/src/GraphQLConstructor.ts index 40b77690..eb0a0ead 100644 --- a/src/GraphQLConstructor.ts +++ b/src/GraphQLConstructor.ts @@ -72,6 +72,7 @@ export class GraphQLConstructor { types: NamedTypeNode[], description: StringValueNode | null, directives: readonly ConstDirectiveNode[] | null, + exported: ExportDefinition | null, ): UnionTypeDefinitionNode { return { kind: Kind.UNION_TYPE_DEFINITION, @@ -80,6 +81,7 @@ export class GraphQLConstructor { name, types, directives: this._optionalList(directives), + exported: exported ?? undefined, }; } @@ -113,6 +115,7 @@ export class GraphQLConstructor { interfaces: NamedTypeNode[] | null, description: StringValueNode | null, directives: readonly ConstDirectiveNode[] | null, + exported: ExportDefinition | null, ): InterfaceTypeDefinitionNode { return { kind: Kind.INTERFACE_TYPE_DEFINITION, @@ -122,6 +125,7 @@ export class GraphQLConstructor { fields, interfaces: interfaces ?? undefined, directives: this._optionalList(directives), + exported: exported ?? undefined, }; } @@ -271,6 +275,7 @@ export class GraphQLConstructor { fields: InputValueDefinitionNode[] | null, directives: readonly ConstDirectiveNode[] | null, description: StringValueNode | null, + exported: ExportDefinition | null, ): InputObjectTypeDefinitionNode { return { kind: Kind.INPUT_OBJECT_TYPE_DEFINITION, @@ -279,6 +284,7 @@ export class GraphQLConstructor { name, fields: fields ?? undefined, directives: this._optionalList(directives), + exported: exported ?? undefined, }; } diff --git a/src/TGratsConfig.ts b/src/TGratsConfig.ts index 55056871..78b56c9f 100644 --- a/src/TGratsConfig.ts +++ b/src/TGratsConfig.ts @@ -53,16 +53,24 @@ export type GratsConfig = { reportTypeScriptTypeErrors: boolean; /** * A string to prepend to the generated schema text. Useful for copyright - * headers or other information to the generated file. Set to `null` to - * omit the default header. + * headers or instructions for how to regenerate the file. Set to `null` + * to omit the default header. */ schemaHeader: string | null; /** * A string to prepend to the generated TypeScript schema file. Useful for - * copyright headers or other information to the generated file. Set to - * `null` to omit the default header. + * copyright headers or instructions for how to regenerate the file. Set + * to `null` to omit the default header. */ tsSchemaHeader: string | null; + /** + * Should Grats require that all GraphQL types (objects, interfaces, + * unions, enums, input objects) be defined using exported TypeScript + * types? + * This allows Grats's generated TypeScript executable schema to be more + * explicitly typed. + */ + requireExportedTypes: boolean; /** * A string to prepend to the TypeScript enums file generated when the * `tsClientEnums` configuration options is set. Useful for copyright @@ -78,6 +86,13 @@ export type GratsConfig = { * paths must end with `.js`. If set to null, no ending will be appended. */ importModuleSpecifierEnding: string; + /** + * EXPERIMENTAL: THIS OPTION WILL BE RENAMED OR REMOVED IN A FUTURE + * RELEASE + * Emit a TypeScript file which creates a Pothos module to enable + * interoperability with Pothos GraphQL schema builders. + */ + EXPERIMENTAL__emitPothos: string; /** * EXPERIMENTAL: THIS OPTION WILL BE RENAMED OR REMOVED IN A FUTURE * RELEASE diff --git a/src/cli.ts b/src/cli.ts index 8783e2bd..54e5a5ae 100644 --- a/src/cli.ts +++ b/src/cli.ts @@ -17,6 +17,7 @@ import { printGratsSDL, printExecutableSchema, printEnumsModule, + printPothosTypesModule, } from "./printSchema"; import * as ts from "typescript"; import { @@ -190,6 +191,16 @@ function writeSchemaFilesAndReport( writeFileSync(absOutput, schemaStr); console.error(`Grats: Wrote schema to \`${absOutput}\`.`); + if (config.raw.grats.EXPERIMENTAL__emitPothos) { + const pothosOutput = resolve( + dirname(configPath), + config.raw.grats.EXPERIMENTAL__emitPothos, + ); + const pothosTypesCode = printPothosTypesModule(schema, gratsConfig); + writeFileSync(pothosOutput, pothosTypesCode); + console.error(`Grats: Wrote Pothos types to \`${pothosOutput}\`.`); + } + if (config.raw.grats.EXPERIMENTAL__emitMetadata) { const absOutput = resolve( dirname(configPath), diff --git a/src/codegen/TSAstBuilder.ts b/src/codegen/TSAstBuilder.ts index b0c16858..417232fd 100644 --- a/src/codegen/TSAstBuilder.ts +++ b/src/codegen/TSAstBuilder.ts @@ -2,6 +2,7 @@ import * as ts from "typescript"; import { isNonNull } from "../utils/helpers"; import * as path from "path"; import { resolveRelativePath } from "../gratsRoot"; +import { ExportDefinition } from "../GraphQLAstExtensions"; type JsonObject = { [key: string]: JsonValue }; type JsonArray = JsonValue[]; @@ -119,7 +120,7 @@ export default class TSAstBuilder { return F.createObjectLiteralExpression(properties.filter(isNonNull), true); } - boolean(value: boolean): ts.BooleanLiteral { + boolean(value: boolean): ts.TrueLiteral | ts.FalseLiteral { return value ? F.createTrue() : F.createFalse(); } @@ -200,22 +201,22 @@ export default class TSAstBuilder { } } - importDefault(from: string, as: string) { + importDefault(from: string, as: string, isTypeOnly: boolean) { this._imports.push( F.createImportDeclaration( undefined, - F.createImportClause(false, F.createIdentifier(as), undefined), + F.createImportClause(isTypeOnly, F.createIdentifier(as), undefined), F.createStringLiteral(from), ), ); } importUserConstruct( - tsModulePath: string, - exportName: string | null, + exported: ExportDefinition, localName: string, isTypeOnly: boolean, ): void { + const { exportName, tsModulePath } = exported; const abs = resolveRelativePath(tsModulePath); const relative = replaceExt( path.relative(path.dirname(this._destination), abs), @@ -223,7 +224,7 @@ export default class TSAstBuilder { ); const modulePath = `./${normalizeRelativePathToPosix(relative)}`; if (exportName == null) { - this.importDefault(modulePath, localName); + this.importDefault(modulePath, localName, isTypeOnly); } else { this.import(modulePath, [ { name: exportName, as: localName, isTypeOnly }, diff --git a/src/codegen/enumCodegen.ts b/src/codegen/enumCodegen.ts index 1fd2953f..d8efcb72 100644 --- a/src/codegen/enumCodegen.ts +++ b/src/codegen/enumCodegen.ts @@ -63,12 +63,7 @@ class EnumCodegen { }); // Import the enum - this.ts.importUserConstruct( - exported.tsModulePath, - exported.exportName, - localName, - false, - ); + this.ts.importUserConstruct(exported, localName, false); } private generateEnumsObject(enumTypes: GraphQLEnumType[]): void { diff --git a/src/codegen/pothosTypeCodegen.ts b/src/codegen/pothosTypeCodegen.ts new file mode 100644 index 00000000..a01f63de --- /dev/null +++ b/src/codegen/pothosTypeCodegen.ts @@ -0,0 +1,156 @@ +import { + GraphQLEnumType, + GraphQLInputObjectType, + GraphQLInterfaceType, + GraphQLObjectType, + GraphQLScalarType, + GraphQLSchema, + GraphQLUnionType, +} from "graphql"; +import * as ts from "typescript"; +import TSAstBuilder from "./TSAstBuilder"; +import { GratsConfig } from "../TGratsConfig"; +import { nullThrows } from "../utils/helpers"; +import { ExportDefinition } from "../GraphQLAstExtensions"; + +const BUILT_IN_SCALARS = new Set(["String", "Int", "Float", "Boolean", "ID"]); + +/** + * Codegen file for generating Pothos UserSchemaTypes type definitions. + */ + +const F = ts.factory; + +// Given a GraphQL schema, returns TypeScript code that exports all enums +// as a single object mapping enum names to their TypeScript values. +export function codegenPothosUserSchemaTypes( + schema: GraphQLSchema, + config: GratsConfig, +): string { + const astBuilder = new TSAstBuilder( + config.EXPERIMENTAL__emitPothos!, + config.importModuleSpecifierEnding, + ); + const codegen = new PothosCodegen(schema, config, astBuilder); + codegen.generate(); + return astBuilder.print(); +} + +class PothosCodegen { + constructor( + private schema: GraphQLSchema, + private config: GratsConfig, + private ts: TSAstBuilder, + ) {} + + generate() { + this.generatePothosUserSchemaTypes(); + } + + private generatePothosUserSchemaTypes(): void { + const objects: ts.TypeElement[] = []; + const inputs: ts.TypeElement[] = []; + const enums: ts.TypeElement[] = []; + const interfaces: ts.TypeElement[] = []; + const scalars: ts.TypeElement[] = []; + const unions: ts.TypeElement[] = []; + for (const [name, type] of Object.entries(this.schema.getTypeMap())) { + if (name.startsWith("__") || BUILT_IN_SCALARS.has(name)) continue; + + // Ensure we have an AST node; preserve original behavior of throwing if absent + const ast = nullThrows(type.astNode); + const exported = ast.exported; + if (exported == null) continue; + + // Handle scalars specially because they map to a small type literal (Input/Output) + if (type instanceof GraphQLScalarType) { + const localName = `${name}Internal`; + this.ts.importUserConstruct(exported, localName, false); + scalars.push( + F.createPropertySignature( + undefined, + name, + undefined, + F.createTypeLiteralNode([ + F.createPropertySignature( + undefined, + "Output", + undefined, + F.createTypeReferenceNode(localName, undefined), + ), + F.createPropertySignature( + undefined, + "Input", + undefined, + F.createTypeReferenceNode(localName, undefined), + ), + ]), + ), + ); + continue; + } + + // For all other named types we delegate to typeProperty and add to the + // correct collection based on runtime class. + const prop = this.typeProperty(name, exported); + if (type instanceof GraphQLObjectType) objects.push(prop); + else if (type instanceof GraphQLInputObjectType) inputs.push(prop); + else if (type instanceof GraphQLEnumType) enums.push(prop); + else if (type instanceof GraphQLInterfaceType) interfaces.push(prop); + else if (type instanceof GraphQLUnionType) unions.push(prop); + } + + const maybeProperties: Array = [ + F.createPropertySignature( + undefined, + "Defaults", + undefined, + F.createLiteralTypeNode(F.createStringLiteral("v4")), + ), + this.property("Objects", objects), + this.property("Inputs", inputs), + this.property("Interface", interfaces), + this.property("Unions", unions), + this.property("Scalars", scalars), + this.property("Enums", enums), + F.createPropertySignature( + undefined, + "DefaultFieldNullability", + undefined, + F.createLiteralTypeNode(this.ts.boolean(this.config.nullableByDefault)), + ), + ]; + + this.ts.addStatement( + F.createTypeAliasDeclaration( + [F.createModifier(ts.SyntaxKind.ExportKeyword)], + "PothosUserSchemaTypes", + undefined, + F.createTypeLiteralNode(maybeProperties.filter((p) => p != null)), + ), + ); + } + + typeProperty(name: string, exported: ExportDefinition): ts.PropertySignature { + const localName = `${name}Internal`; + this.ts.importUserConstruct(exported, localName, false); + return F.createPropertySignature( + undefined, + name, + undefined, + F.createTypeReferenceNode(localName, undefined), + ); + } + + property(name: string, members: ts.TypeElement[]) { + if (members.length === 0) { + return undefined; + } + return F.createPropertySignature( + undefined, + name, + undefined, + F.createTypeLiteralNode(members), + ); + } +} diff --git a/src/codegen/resolverCodegen.ts b/src/codegen/resolverCodegen.ts index 07d26525..0c4968ad 100644 --- a/src/codegen/resolverCodegen.ts +++ b/src/codegen/resolverCodegen.ts @@ -43,12 +43,7 @@ export default class ResolverCodegen { return undefined; } const sourceTypeName = `${parentTypeName}SourceType`; - this.ts.importUserConstruct( - sourceExport.tsModulePath, - sourceExport.exportName, - sourceTypeName, - true, - ); + this.ts.importUserConstruct(sourceExport, sourceTypeName, true); return F.createTypeReferenceNode(sourceTypeName); }; switch (resolver.kind) { @@ -95,12 +90,7 @@ export default class ResolverCodegen { parentTypeName, fieldName, ); - this.ts.importUserConstruct( - resolver.path, - resolver.exportName, - resolverName, - false, - ); + this.ts.importUserConstruct(resolver.exported, resolverName, false); return this.ts.method( methodName, extractUsedParams(resolver.arguments ?? []).map((name) => { @@ -129,12 +119,7 @@ export default class ResolverCodegen { parentTypeName, fieldName, ); - this.ts.importUserConstruct( - resolver.path, - resolver.exportName, - resolverName, - false, - ); + this.ts.importUserConstruct(resolver.exported, resolverName, false); return this.ts.method( methodName, extractUsedParams(resolver.arguments ?? []).map((name) => { @@ -211,8 +196,8 @@ export default class ResolverCodegen { F.createIdentifier(arg.name), ); case "derivedContext": { - const localName = this.getDerivedContextName(arg.path, arg.exportName); - this.ts.importUserConstruct(arg.path, arg.exportName, localName, false); + const localName = this.getDerivedContextName(arg.exported); + this.ts.importUserConstruct(arg.exported, localName, false); return F.createCallExpression( F.createIdentifier(localName), undefined, @@ -230,7 +215,8 @@ export default class ResolverCodegen { // globally unique, like GraphQL type names, so must ensure this name is // unique within our module. However, we want to avoid generating a new // name for the same derived context more than once. - getDerivedContextName(path: string, exportName: string | null): string { + getDerivedContextName(exported: ExportDefinition): string { + const { tsModulePath: path, exportName } = exported; const key = `${path}:${exportName ?? ""}`; let name = this._derivedContextNames.get(key); if (name == null) { diff --git a/src/codegen/schemaCodegen.ts b/src/codegen/schemaCodegen.ts index d451dcc3..3e23cf29 100644 --- a/src/codegen/schemaCodegen.ts +++ b/src/codegen/schemaCodegen.ts @@ -106,12 +106,7 @@ class Codegen { const localName = `${type.name}Internal`; - this.ts.importUserConstruct( - exported.tsModulePath, - exported.exportName, - localName, - true, - ); + this.ts.importUserConstruct(exported, localName, true); return F.createPropertySignature( undefined, @@ -307,11 +302,19 @@ class Codegen { const ast = nullThrows(obj.astNode); + let typeArguments: ts.TypeNode[] = []; + if (ast.exported != null) { + const localType = `T${obj.name}`; + this.ts.importUserConstruct(ast.exported, localType, true); + + typeArguments = [F.createTypeReferenceNode(localType)]; + } + this.ts.constDeclaration( varName, F.createNewExpression( this.graphQLImport("GraphQLObjectType"), - [], + typeArguments, [this.objectTypeConfig(obj, ast.exported || null)], ), // We need to explicitly specify the type due to circular references in @@ -439,12 +442,7 @@ class Codegen { if (exportedMetadata != null) { if (!this._typeNameMappings.has(t.name)) { const localName = `${t.name}Class`; - this.ts.importUserConstruct( - exportedMetadata.tsModulePath, - exportedMetadata.exportName, - localName, - false, - ); + this.ts.importUserConstruct(exportedMetadata, localName, false); this._typeNameMappings.set(t.name, localName); } diff --git a/src/configSpecRaw.json b/src/configSpecRaw.json index f1d2fdc0..e9b16bd7 100644 --- a/src/configSpecRaw.json +++ b/src/configSpecRaw.json @@ -49,6 +49,12 @@ "nullable": true, "default": "/**\n * Executable schema generated by Grats (https://grats.capt.dev)\n * Do not manually edit. Regenerate by running `npx grats`.\n */" }, + "requireExportedTypes": { + "description": "Should Grats require that all GraphQL types (objects, interfaces, unions, enums, input objects) be defined using exported TypeScript types?\nThis allows Grats's generated TypeScript executable schema to be more explicitly typed.", + "type": { "kind": "boolean" }, + "nullable": false, + "default": false + }, "tsClientEnumsHeader": { "description": "A string to prepend to the TypeScript enums file generated when the `tsClientEnums` configuration options is set. Useful for copyright headers or instructions for how to regenerate the file. Set to `null` to omit the default header.", "type": { "kind": "longString" }, @@ -61,6 +67,13 @@ "nullable": false, "default": "" }, + "EXPERIMENTAL__emitPothos": { + "description": "EXPERIMENTAL: THIS OPTION WILL BE RENAMED OR REMOVED IN A FUTURE RELEASE\nEmit a TypeScript file which creates a Pothos module to enable interoperability with Pothos GraphQL schema builders.", + "type": { "kind": "string" }, + "nullable": false, + "default": false, + "experimental": true + }, "EXPERIMENTAL__emitMetadata": { "description": "EXPERIMENTAL: THIS OPTION WILL BE RENAMED OR REMOVED IN A FUTURE RELEASE\nEmit a JSON file alongside the generated schema file which contains the metadata containing information about the resolvers.", "type": { "kind": "boolean" }, diff --git a/src/metadata.ts b/src/metadata.ts index 0faae6ef..52fc3237 100644 --- a/src/metadata.ts +++ b/src/metadata.ts @@ -11,6 +11,8 @@ * for now we are just using TypeScript types. */ +import { ExportDefinition } from "./GraphQLAstExtensions"; + // Note: An example of replacing codegen with a dynamic default resolve powered // by this JSON schema: // https://gist.github.com/captbaritone/f66d0355645a32494da368d0448b9d7a @@ -57,8 +59,7 @@ export type PropertyResolver = { */ export type FunctionResolver = { kind: "function"; - path: string; // Path to the module - exportName: string | null; // Name of the export. If omitted the function is the default export. + exported: ExportDefinition; arguments: ResolverArgument[] | null; }; @@ -76,8 +77,7 @@ export type MethodResolver = { */ export type StaticMethodResolver = { kind: "staticMethod"; - path: string; // Path to the module - exportName: string | null; // Export name. If omitted, the class is the default export + exported: ExportDefinition; name: string; // Method name arguments: ResolverArgument[] | null; }; @@ -111,8 +111,7 @@ export type ContextArgument = { /** A context value which is expressed as a function of the global context */ export type DerivedContextArgument = { kind: "derivedContext"; - path: string; // Path to the module - exportName: string | null; // Export name. If omitted, the class is the default export + exported: ExportDefinition; args: Array; }; diff --git a/src/printSchema.ts b/src/printSchema.ts index 98ee268e..6bacb853 100644 --- a/src/printSchema.ts +++ b/src/printSchema.ts @@ -10,6 +10,7 @@ import { Metadata } from "./metadata"; import { resolverMapCodegen } from "./codegen/resolverMapCodegen"; import { codegenEnums } from "./codegen/enumCodegen"; import { mapDefinitions } from "./utils/visitor"; +import { codegenPothosUserSchemaTypes } from "./codegen/pothosTypeCodegen"; /** * Prints code for a TypeScript module that exports a GraphQLSchema. @@ -78,6 +79,13 @@ export function printSDLWithoutMetadata(doc: DocumentNode): string { return print(trimmed); } +export function printPothosTypesModule( + schema: GraphQLSchema, + config: GratsConfig, +): string { + return codegenPothosUserSchemaTypes(schema, config); +} + function formatHeader(header: string | null, code: string): string { if (header !== null) { return `${header}\n\n${code}`; diff --git a/src/tests/configParserFixtures/empty.json.expected b/src/tests/configParserFixtures/empty.json.expected index cbed7d58..09cb096c 100644 --- a/src/tests/configParserFixtures/empty.json.expected +++ b/src/tests/configParserFixtures/empty.json.expected @@ -16,8 +16,10 @@ OUTPUT "reportTypeScriptTypeErrors": false, "schemaHeader": "# Schema generated by Grats (https://grats.capt.dev)\n# Do not manually edit. Regenerate by running `npx grats`.", "tsSchemaHeader": "/**\n * Executable schema generated by Grats (https://grats.capt.dev)\n * Do not manually edit. Regenerate by running `npx grats`.\n */", + "requireExportedTypes": false, "tsClientEnumsHeader": "/**\n * TypeScript enum definitions generated by Grats (https://grats.capt.dev)\n * Do not manually edit. Regenerate by running `npx grats`.\n */", "importModuleSpecifierEnding": "", + "EXPERIMENTAL__emitPothos": false, "EXPERIMENTAL__emitMetadata": false, "EXPERIMENTAL__emitResolverMap": false } \ No newline at end of file diff --git a/src/tests/configParserFixtures/experimentalField.json.expected b/src/tests/configParserFixtures/experimentalField.json.expected index 9c915af4..9fc82de1 100644 --- a/src/tests/configParserFixtures/experimentalField.json.expected +++ b/src/tests/configParserFixtures/experimentalField.json.expected @@ -18,8 +18,10 @@ OUTPUT "reportTypeScriptTypeErrors": false, "schemaHeader": "# Schema generated by Grats (https://grats.capt.dev)\n# Do not manually edit. Regenerate by running `npx grats`.", "tsSchemaHeader": "/**\n * Executable schema generated by Grats (https://grats.capt.dev)\n * Do not manually edit. Regenerate by running `npx grats`.\n */", + "requireExportedTypes": false, "tsClientEnumsHeader": "/**\n * TypeScript enum definitions generated by Grats (https://grats.capt.dev)\n * Do not manually edit. Regenerate by running `npx grats`.\n */", "importModuleSpecifierEnding": "", + "EXPERIMENTAL__emitPothos": false, "EXPERIMENTAL__emitMetadata": true, "EXPERIMENTAL__emitResolverMap": false } diff --git a/src/tests/configParserFixtures/multiLineHeader.json.expected b/src/tests/configParserFixtures/multiLineHeader.json.expected index b8f64bb6..bd0a2513 100644 --- a/src/tests/configParserFixtures/multiLineHeader.json.expected +++ b/src/tests/configParserFixtures/multiLineHeader.json.expected @@ -18,8 +18,10 @@ OUTPUT "reportTypeScriptTypeErrors": false, "schemaHeader": "/**\n * An amazing GraphQL schema\n */", "tsSchemaHeader": "/**\n * Executable schema generated by Grats (https://grats.capt.dev)\n * Do not manually edit. Regenerate by running `npx grats`.\n */", + "requireExportedTypes": false, "tsClientEnumsHeader": "/**\n * TypeScript enum definitions generated by Grats (https://grats.capt.dev)\n * Do not manually edit. Regenerate by running `npx grats`.\n */", "importModuleSpecifierEnding": "", + "EXPERIMENTAL__emitPothos": false, "EXPERIMENTAL__emitMetadata": false, "EXPERIMENTAL__emitResolverMap": false } \ No newline at end of file diff --git a/src/tests/fixtures/arguments/ArgumentWithDescription.ts.expected b/src/tests/fixtures/arguments/ArgumentWithDescription.ts.expected index bd158c52..226f5440 100644 --- a/src/tests/fixtures/arguments/ArgumentWithDescription.ts.expected +++ b/src/tests/fixtures/arguments/ArgumentWithDescription.ts.expected @@ -23,9 +23,10 @@ type SomeType { ): String } -- TypeScript -- +import type TSomeType from "./ArgumentWithDescription"; import { GraphQLSchema, GraphQLObjectType, GraphQLString, GraphQLNonNull } from "graphql"; export function getSchema(): GraphQLSchema { - const SomeTypeType: GraphQLObjectType = new GraphQLObjectType({ + const SomeTypeType: GraphQLObjectType = new GraphQLObjectType({ name: "SomeType", fields() { return { diff --git a/src/tests/fixtures/arguments/CustomScalarArgument.ts.expected b/src/tests/fixtures/arguments/CustomScalarArgument.ts.expected index f1bcebdd..c4c9792a 100644 --- a/src/tests/fixtures/arguments/CustomScalarArgument.ts.expected +++ b/src/tests/fixtures/arguments/CustomScalarArgument.ts.expected @@ -22,6 +22,7 @@ type SomeType { hello(greeting: MyString!): String } -- TypeScript -- +import type TSomeType from "./CustomScalarArgument"; import type { GqlScalar } from "grats"; import type { MyString as MyStringInternal } from "./CustomScalarArgument"; import { GraphQLSchema, GraphQLScalarType, GraphQLObjectType, GraphQLString, GraphQLNonNull } from "graphql"; @@ -35,7 +36,7 @@ export function getSchema(config: SchemaConfig): GraphQLSchema { name: "MyString", ...config.scalars.MyString }); - const SomeTypeType: GraphQLObjectType = new GraphQLObjectType({ + const SomeTypeType: GraphQLObjectType = new GraphQLObjectType({ name: "SomeType", fields() { return { diff --git a/src/tests/fixtures/arguments/DeprecatedArgument.ts.expected b/src/tests/fixtures/arguments/DeprecatedArgument.ts.expected index 88aba529..5e8780fe 100644 --- a/src/tests/fixtures/arguments/DeprecatedArgument.ts.expected +++ b/src/tests/fixtures/arguments/DeprecatedArgument.ts.expected @@ -22,9 +22,10 @@ type SomeType { hello(greeting: String @deprecated(reason: "Not used anymore")): String } -- TypeScript -- +import type TSomeType from "./DeprecatedArgument"; import { GraphQLSchema, GraphQLObjectType, GraphQLString } from "graphql"; export function getSchema(): GraphQLSchema { - const SomeTypeType: GraphQLObjectType = new GraphQLObjectType({ + const SomeTypeType: GraphQLObjectType = new GraphQLObjectType({ name: "SomeType", fields() { return { diff --git a/src/tests/fixtures/arguments/GqlTypeUsedAsPositionalArg.ts.expected b/src/tests/fixtures/arguments/GqlTypeUsedAsPositionalArg.ts.expected index 2999df3b..d5f1361b 100644 --- a/src/tests/fixtures/arguments/GqlTypeUsedAsPositionalArg.ts.expected +++ b/src/tests/fixtures/arguments/GqlTypeUsedAsPositionalArg.ts.expected @@ -28,6 +28,7 @@ type SomeType { hello(greeting: Greeting!): String } -- TypeScript -- +import type TSomeType from "./GqlTypeUsedAsPositionalArg"; import { GraphQLSchema, GraphQLInputObjectType, GraphQLNonNull, GraphQLString, GraphQLObjectType } from "graphql"; export function getSchema(): GraphQLSchema { const GreetingType: GraphQLInputObjectType = new GraphQLInputObjectType({ @@ -45,7 +46,7 @@ export function getSchema(): GraphQLSchema { }; } }); - const SomeTypeType: GraphQLObjectType = new GraphQLObjectType({ + const SomeTypeType: GraphQLObjectType = new GraphQLObjectType({ name: "SomeType", fields() { return { diff --git a/src/tests/fixtures/arguments/NullableArguments.ts.expected b/src/tests/fixtures/arguments/NullableArguments.ts.expected index 64cbca40..661f4b7d 100644 --- a/src/tests/fixtures/arguments/NullableArguments.ts.expected +++ b/src/tests/fixtures/arguments/NullableArguments.ts.expected @@ -26,9 +26,10 @@ type SomeType { hello2(greeting: String): String } -- TypeScript -- +import type TSomeType from "./NullableArguments"; import { GraphQLSchema, GraphQLObjectType, GraphQLString } from "graphql"; export function getSchema(): GraphQLSchema { - const SomeTypeType: GraphQLObjectType = new GraphQLObjectType({ + const SomeTypeType: GraphQLObjectType = new GraphQLObjectType({ name: "SomeType", fields() { return { diff --git a/src/tests/fixtures/arguments/OptionalArgument.ts.expected b/src/tests/fixtures/arguments/OptionalArgument.ts.expected index fdbe2165..7eab7458 100644 --- a/src/tests/fixtures/arguments/OptionalArgument.ts.expected +++ b/src/tests/fixtures/arguments/OptionalArgument.ts.expected @@ -17,9 +17,10 @@ type SomeType { hello(greeting: String): String } -- TypeScript -- +import type TSomeType from "./OptionalArgument"; import { GraphQLSchema, GraphQLObjectType, GraphQLString } from "graphql"; export function getSchema(): GraphQLSchema { - const SomeTypeType: GraphQLObjectType = new GraphQLObjectType({ + const SomeTypeType: GraphQLObjectType = new GraphQLObjectType({ name: "SomeType", fields() { return { diff --git a/src/tests/fixtures/arguments/OptionalNonNullableArgumentWithDefault.ts.expected b/src/tests/fixtures/arguments/OptionalNonNullableArgumentWithDefault.ts.expected index aba02ae1..3612e5e2 100644 --- a/src/tests/fixtures/arguments/OptionalNonNullableArgumentWithDefault.ts.expected +++ b/src/tests/fixtures/arguments/OptionalNonNullableArgumentWithDefault.ts.expected @@ -17,9 +17,10 @@ type SomeType { hello(greeting: String! = "Hello"): String } -- TypeScript -- +import type TSomeType from "./OptionalNonNullableArgumentWithDefault"; import { GraphQLSchema, GraphQLObjectType, GraphQLString, GraphQLNonNull } from "graphql"; export function getSchema(): GraphQLSchema { - const SomeTypeType: GraphQLObjectType = new GraphQLObjectType({ + const SomeTypeType: GraphQLObjectType = new GraphQLObjectType({ name: "SomeType", fields() { return { diff --git a/src/tests/fixtures/arguments/PositionalArgDeprecatedOptional.ts.expected b/src/tests/fixtures/arguments/PositionalArgDeprecatedOptional.ts.expected index b127fda2..e83da5ee 100644 --- a/src/tests/fixtures/arguments/PositionalArgDeprecatedOptional.ts.expected +++ b/src/tests/fixtures/arguments/PositionalArgDeprecatedOptional.ts.expected @@ -31,6 +31,7 @@ type SomeType { hello(greeting: Greeting @deprecated(reason: "Unused!")): String } -- TypeScript -- +import type TSomeType from "./PositionalArgDeprecatedOptional"; import { GraphQLSchema, GraphQLInputObjectType, GraphQLNonNull, GraphQLString, GraphQLObjectType } from "graphql"; export function getSchema(): GraphQLSchema { const GreetingType: GraphQLInputObjectType = new GraphQLInputObjectType({ @@ -48,7 +49,7 @@ export function getSchema(): GraphQLSchema { }; } }); - const SomeTypeType: GraphQLObjectType = new GraphQLObjectType({ + const SomeTypeType: GraphQLObjectType = new GraphQLObjectType({ name: "SomeType", fields() { return { diff --git a/src/tests/fixtures/arguments/PositionalArgDeprecatedWithDefault.ts.expected b/src/tests/fixtures/arguments/PositionalArgDeprecatedWithDefault.ts.expected index b0c058c1..4a968da6 100644 --- a/src/tests/fixtures/arguments/PositionalArgDeprecatedWithDefault.ts.expected +++ b/src/tests/fixtures/arguments/PositionalArgDeprecatedWithDefault.ts.expected @@ -31,6 +31,7 @@ type SomeType { hello(greeting: Greeting! = {name: "Alice", salutation: "Hullo"} @deprecated(reason: "Unused!")): String } -- TypeScript -- +import type TSomeType from "./PositionalArgDeprecatedWithDefault"; import { GraphQLSchema, GraphQLInputObjectType, GraphQLNonNull, GraphQLString, GraphQLObjectType } from "graphql"; export function getSchema(): GraphQLSchema { const GreetingType: GraphQLInputObjectType = new GraphQLInputObjectType({ @@ -48,7 +49,7 @@ export function getSchema(): GraphQLSchema { }; } }); - const SomeTypeType: GraphQLObjectType = new GraphQLObjectType({ + const SomeTypeType: GraphQLObjectType = new GraphQLObjectType({ name: "SomeType", fields() { return { diff --git a/src/tests/fixtures/arguments/PositionalArgOptional.ts.expected b/src/tests/fixtures/arguments/PositionalArgOptional.ts.expected index 59c0b855..177698a4 100644 --- a/src/tests/fixtures/arguments/PositionalArgOptional.ts.expected +++ b/src/tests/fixtures/arguments/PositionalArgOptional.ts.expected @@ -28,6 +28,7 @@ type SomeType { hello(greeting: String): String } -- TypeScript -- +import type TSomeType from "./PositionalArgOptional"; import { GraphQLSchema, GraphQLInputObjectType, GraphQLNonNull, GraphQLString, GraphQLObjectType } from "graphql"; export function getSchema(): GraphQLSchema { const GreetingType: GraphQLInputObjectType = new GraphQLInputObjectType({ @@ -45,7 +46,7 @@ export function getSchema(): GraphQLSchema { }; } }); - const SomeTypeType: GraphQLObjectType = new GraphQLObjectType({ + const SomeTypeType: GraphQLObjectType = new GraphQLObjectType({ name: "SomeType", fields() { return { diff --git a/src/tests/fixtures/arguments/PositionalArgWithDefault.ts.expected b/src/tests/fixtures/arguments/PositionalArgWithDefault.ts.expected index e1009fd7..05f2c977 100644 --- a/src/tests/fixtures/arguments/PositionalArgWithDefault.ts.expected +++ b/src/tests/fixtures/arguments/PositionalArgWithDefault.ts.expected @@ -17,9 +17,10 @@ type SomeType { hello(greeting: String! = "Hello"): String } -- TypeScript -- +import type TSomeType from "./PositionalArgWithDefault"; import { GraphQLSchema, GraphQLObjectType, GraphQLString, GraphQLNonNull } from "graphql"; export function getSchema(): GraphQLSchema { - const SomeTypeType: GraphQLObjectType = new GraphQLObjectType({ + const SomeTypeType: GraphQLObjectType = new GraphQLObjectType({ name: "SomeType", fields() { return { diff --git a/src/tests/fixtures/arguments/PositionalArgWithDescription.ts.expected b/src/tests/fixtures/arguments/PositionalArgWithDescription.ts.expected index 44182b83..c50d4af1 100644 --- a/src/tests/fixtures/arguments/PositionalArgWithDescription.ts.expected +++ b/src/tests/fixtures/arguments/PositionalArgWithDescription.ts.expected @@ -34,6 +34,7 @@ type SomeType { ): String } -- TypeScript -- +import type TSomeType from "./PositionalArgWithDescription"; import { GraphQLSchema, GraphQLInputObjectType, GraphQLNonNull, GraphQLString, GraphQLObjectType } from "graphql"; export function getSchema(): GraphQLSchema { const GreetingType: GraphQLInputObjectType = new GraphQLInputObjectType({ @@ -51,7 +52,7 @@ export function getSchema(): GraphQLSchema { }; } }); - const SomeTypeType: GraphQLObjectType = new GraphQLObjectType({ + const SomeTypeType: GraphQLObjectType = new GraphQLObjectType({ name: "SomeType", fields() { return { diff --git a/src/tests/fixtures/arguments/StringArgument.ts.expected b/src/tests/fixtures/arguments/StringArgument.ts.expected index 72e3b046..0fc12ccb 100644 --- a/src/tests/fixtures/arguments/StringArgument.ts.expected +++ b/src/tests/fixtures/arguments/StringArgument.ts.expected @@ -17,9 +17,10 @@ type SomeType { hello(greeting: String!): String } -- TypeScript -- +import type TSomeType from "./StringArgument"; import { GraphQLSchema, GraphQLObjectType, GraphQLString, GraphQLNonNull } from "graphql"; export function getSchema(): GraphQLSchema { - const SomeTypeType: GraphQLObjectType = new GraphQLObjectType({ + const SomeTypeType: GraphQLObjectType = new GraphQLObjectType({ name: "SomeType", fields() { return { diff --git a/src/tests/fixtures/built_in_scalars/FloatField.ts.expected b/src/tests/fixtures/built_in_scalars/FloatField.ts.expected index dc6e8769..8ed2ea3b 100644 --- a/src/tests/fixtures/built_in_scalars/FloatField.ts.expected +++ b/src/tests/fixtures/built_in_scalars/FloatField.ts.expected @@ -19,9 +19,10 @@ type SomeType { ratio: Float } -- TypeScript -- +import type TSomeType from "./FloatField"; import { GraphQLSchema, GraphQLObjectType, GraphQLFloat } from "graphql"; export function getSchema(): GraphQLSchema { - const SomeTypeType: GraphQLObjectType = new GraphQLObjectType({ + const SomeTypeType: GraphQLObjectType = new GraphQLObjectType({ name: "SomeType", fields() { return { diff --git a/src/tests/fixtures/built_in_scalars/FloatFieldAliasedImport.ts.expected b/src/tests/fixtures/built_in_scalars/FloatFieldAliasedImport.ts.expected index de2d5463..f04a01a3 100644 --- a/src/tests/fixtures/built_in_scalars/FloatFieldAliasedImport.ts.expected +++ b/src/tests/fixtures/built_in_scalars/FloatFieldAliasedImport.ts.expected @@ -19,9 +19,10 @@ type SomeType { ratio: Float } -- TypeScript -- +import type TSomeType from "./FloatFieldAliasedImport"; import { GraphQLSchema, GraphQLObjectType, GraphQLFloat } from "graphql"; export function getSchema(): GraphQLSchema { - const SomeTypeType: GraphQLObjectType = new GraphQLObjectType({ + const SomeTypeType: GraphQLObjectType = new GraphQLObjectType({ name: "SomeType", fields() { return { diff --git a/src/tests/fixtures/built_in_scalars/IdField.ts.expected b/src/tests/fixtures/built_in_scalars/IdField.ts.expected index 7ea3ec8c..ca6179ad 100644 --- a/src/tests/fixtures/built_in_scalars/IdField.ts.expected +++ b/src/tests/fixtures/built_in_scalars/IdField.ts.expected @@ -19,9 +19,10 @@ type SomeType { id: ID } -- TypeScript -- +import type TSomeType from "./IdField"; import { GraphQLSchema, GraphQLObjectType, GraphQLID } from "graphql"; export function getSchema(): GraphQLSchema { - const SomeTypeType: GraphQLObjectType = new GraphQLObjectType({ + const SomeTypeType: GraphQLObjectType = new GraphQLObjectType({ name: "SomeType", fields() { return { diff --git a/src/tests/fixtures/built_in_scalars/IntField.ts.expected b/src/tests/fixtures/built_in_scalars/IntField.ts.expected index aa597960..fca86d53 100644 --- a/src/tests/fixtures/built_in_scalars/IntField.ts.expected +++ b/src/tests/fixtures/built_in_scalars/IntField.ts.expected @@ -19,9 +19,10 @@ type SomeType { age: Int } -- TypeScript -- +import type TSomeType from "./IntField"; import { GraphQLSchema, GraphQLObjectType, GraphQLInt } from "graphql"; export function getSchema(): GraphQLSchema { - const SomeTypeType: GraphQLObjectType = new GraphQLObjectType({ + const SomeTypeType: GraphQLObjectType = new GraphQLObjectType({ name: "SomeType", fields() { return { diff --git a/src/tests/fixtures/configOptions/importModuleSpecifierEnding.ts.expected b/src/tests/fixtures/configOptions/importModuleSpecifierEnding.ts.expected index 791f133a..cdf9c975 100644 --- a/src/tests/fixtures/configOptions/importModuleSpecifierEnding.ts.expected +++ b/src/tests/fixtures/configOptions/importModuleSpecifierEnding.ts.expected @@ -23,10 +23,11 @@ type SomeType { hello: String } -- TypeScript -- +import type TSomeType from "./importModuleSpecifierEnding.js"; import { GraphQLSchema, GraphQLObjectType, GraphQLString } from "graphql"; import { greeting as someTypeGreetingResolver } from "./importModuleSpecifierEnding.js"; export function getSchema(): GraphQLSchema { - const SomeTypeType: GraphQLObjectType = new GraphQLObjectType({ + const SomeTypeType: GraphQLObjectType = new GraphQLObjectType({ name: "SomeType", fields() { return { diff --git a/src/tests/fixtures/default_values/DefaultArgumentArray.ts.expected b/src/tests/fixtures/default_values/DefaultArgumentArray.ts.expected index 68064910..651cbd83 100644 --- a/src/tests/fixtures/default_values/DefaultArgumentArray.ts.expected +++ b/src/tests/fixtures/default_values/DefaultArgumentArray.ts.expected @@ -24,9 +24,10 @@ type SomeType { someField1(inputs: [String!] = ["hello", "there"]): String } -- TypeScript -- +import type TSomeType from "./DefaultArgumentArray"; import { GraphQLSchema, GraphQLObjectType, GraphQLString, GraphQLList, GraphQLNonNull } from "graphql"; export function getSchema(): GraphQLSchema { - const SomeTypeType: GraphQLObjectType = new GraphQLObjectType({ + const SomeTypeType: GraphQLObjectType = new GraphQLObjectType({ name: "SomeType", fields() { return { diff --git a/src/tests/fixtures/default_values/DefaultArgumentBooleanLiteral.ts.expected b/src/tests/fixtures/default_values/DefaultArgumentBooleanLiteral.ts.expected index 11d274c0..4cf07585 100644 --- a/src/tests/fixtures/default_values/DefaultArgumentBooleanLiteral.ts.expected +++ b/src/tests/fixtures/default_values/DefaultArgumentBooleanLiteral.ts.expected @@ -25,9 +25,10 @@ type SomeType { someField2(greet: Boolean = true): String } -- TypeScript -- +import type TSomeType from "./DefaultArgumentBooleanLiteral"; import { GraphQLSchema, GraphQLObjectType, GraphQLString, GraphQLBoolean } from "graphql"; export function getSchema(): GraphQLSchema { - const SomeTypeType: GraphQLObjectType = new GraphQLObjectType({ + const SomeTypeType: GraphQLObjectType = new GraphQLObjectType({ name: "SomeType", fields() { return { diff --git a/src/tests/fixtures/default_values/DefaultArgumentNullLiteral.ts.expected b/src/tests/fixtures/default_values/DefaultArgumentNullLiteral.ts.expected index 8a9192f7..ba202ce1 100644 --- a/src/tests/fixtures/default_values/DefaultArgumentNullLiteral.ts.expected +++ b/src/tests/fixtures/default_values/DefaultArgumentNullLiteral.ts.expected @@ -24,9 +24,10 @@ type SomeType { someField2(hello: String = null): String } -- TypeScript -- +import type TSomeType from "./DefaultArgumentNullLiteral"; import { GraphQLSchema, GraphQLObjectType, GraphQLString } from "graphql"; export function getSchema(): GraphQLSchema { - const SomeTypeType: GraphQLObjectType = new GraphQLObjectType({ + const SomeTypeType: GraphQLObjectType = new GraphQLObjectType({ name: "SomeType", fields() { return { diff --git a/src/tests/fixtures/default_values/DefaultArgumentNumberLiteral.ts.expected b/src/tests/fixtures/default_values/DefaultArgumentNumberLiteral.ts.expected index 30387b80..7d40bd56 100644 --- a/src/tests/fixtures/default_values/DefaultArgumentNumberLiteral.ts.expected +++ b/src/tests/fixtures/default_values/DefaultArgumentNumberLiteral.ts.expected @@ -24,9 +24,10 @@ type SomeType { intField(count: Int! = 10): String } -- TypeScript -- +import type TSomeType from "./DefaultArgumentNumberLiteral"; import { GraphQLSchema, GraphQLObjectType, GraphQLString, GraphQLNonNull, GraphQLFloat, GraphQLInt } from "graphql"; export function getSchema(): GraphQLSchema { - const SomeTypeType: GraphQLObjectType = new GraphQLObjectType({ + const SomeTypeType: GraphQLObjectType = new GraphQLObjectType({ name: "SomeType", fields() { return { diff --git a/src/tests/fixtures/default_values/DefaultArgumentObjectLiteral.ts.expected b/src/tests/fixtures/default_values/DefaultArgumentObjectLiteral.ts.expected index f99e6834..0ae1fc45 100644 --- a/src/tests/fixtures/default_values/DefaultArgumentObjectLiteral.ts.expected +++ b/src/tests/fixtures/default_values/DefaultArgumentObjectLiteral.ts.expected @@ -34,6 +34,7 @@ type SomeType { someField1(input: ConnectionInput = {first: 10, offset: 100}): String } -- TypeScript -- +import type TSomeType from "./DefaultArgumentObjectLiteral"; import { GraphQLSchema, GraphQLInputObjectType, GraphQLNonNull, GraphQLInt, GraphQLObjectType, GraphQLString } from "graphql"; export function getSchema(): GraphQLSchema { const ConnectionInputType: GraphQLInputObjectType = new GraphQLInputObjectType({ @@ -51,7 +52,7 @@ export function getSchema(): GraphQLSchema { }; } }); - const SomeTypeType: GraphQLObjectType = new GraphQLObjectType({ + const SomeTypeType: GraphQLObjectType = new GraphQLObjectType({ name: "SomeType", fields() { return { diff --git a/src/tests/fixtures/default_values/DefaultArgumentPropertyName.ts.expected b/src/tests/fixtures/default_values/DefaultArgumentPropertyName.ts.expected index 9be72092..2c292078 100644 --- a/src/tests/fixtures/default_values/DefaultArgumentPropertyName.ts.expected +++ b/src/tests/fixtures/default_values/DefaultArgumentPropertyName.ts.expected @@ -17,9 +17,10 @@ type SomeType { hello(if: Boolean! = false): String } -- TypeScript -- +import type TSomeType from "./DefaultArgumentPropertyName"; import { GraphQLSchema, GraphQLObjectType, GraphQLString, GraphQLNonNull, GraphQLBoolean } from "graphql"; export function getSchema(): GraphQLSchema { - const SomeTypeType: GraphQLObjectType = new GraphQLObjectType({ + const SomeTypeType: GraphQLObjectType = new GraphQLObjectType({ name: "SomeType", fields() { return { diff --git a/src/tests/fixtures/default_values/DefaultArgumentStringLiteral.ts.expected b/src/tests/fixtures/default_values/DefaultArgumentStringLiteral.ts.expected index e40fa82c..a41cb5f5 100644 --- a/src/tests/fixtures/default_values/DefaultArgumentStringLiteral.ts.expected +++ b/src/tests/fixtures/default_values/DefaultArgumentStringLiteral.ts.expected @@ -17,9 +17,10 @@ type SomeType { hello(greeting: String! = "hello"): String } -- TypeScript -- +import type TSomeType from "./DefaultArgumentStringLiteral"; import { GraphQLSchema, GraphQLObjectType, GraphQLString, GraphQLNonNull } from "graphql"; export function getSchema(): GraphQLSchema { - const SomeTypeType: GraphQLObjectType = new GraphQLObjectType({ + const SomeTypeType: GraphQLObjectType = new GraphQLObjectType({ name: "SomeType", fields() { return { diff --git a/src/tests/fixtures/default_values/DefaultArgumentStringLiteralBackticks.ts.expected b/src/tests/fixtures/default_values/DefaultArgumentStringLiteralBackticks.ts.expected index 2980e922..39b4f464 100644 --- a/src/tests/fixtures/default_values/DefaultArgumentStringLiteralBackticks.ts.expected +++ b/src/tests/fixtures/default_values/DefaultArgumentStringLiteralBackticks.ts.expected @@ -17,9 +17,10 @@ type SomeType { hello(greeting: String! = "hello"): String } -- TypeScript -- +import type TSomeType from "./DefaultArgumentStringLiteralBackticks"; import { GraphQLSchema, GraphQLObjectType, GraphQLString, GraphQLNonNull } from "graphql"; export function getSchema(): GraphQLSchema { - const SomeTypeType: GraphQLObjectType = new GraphQLObjectType({ + const SomeTypeType: GraphQLObjectType = new GraphQLObjectType({ name: "SomeType", fields() { return { diff --git a/src/tests/fixtures/examples/playground.ts.expected b/src/tests/fixtures/examples/playground.ts.expected index b5601591..be2583ed 100644 --- a/src/tests/fixtures/examples/playground.ts.expected +++ b/src/tests/fixtures/examples/playground.ts.expected @@ -51,6 +51,7 @@ type User { name: String } -- TypeScript -- +import type TSomeType from "./playground"; import { GraphQLSchema, GraphQLObjectType, GraphQLString, GraphQLNonNull } from "graphql"; import { getUser as someTypeGetUserResolver } from "./playground"; export function getSchema(): GraphQLSchema { @@ -75,7 +76,7 @@ export function getSchema(): GraphQLSchema { }; } }); - const SomeTypeType: GraphQLObjectType = new GraphQLObjectType({ + const SomeTypeType: GraphQLObjectType = new GraphQLObjectType({ name: "SomeType", fields() { return { diff --git a/src/tests/fixtures/field_definitions/DeprecatedMethodField.ts.expected b/src/tests/fixtures/field_definitions/DeprecatedMethodField.ts.expected index 71c4c7bc..c2957a0e 100644 --- a/src/tests/fixtures/field_definitions/DeprecatedMethodField.ts.expected +++ b/src/tests/fixtures/field_definitions/DeprecatedMethodField.ts.expected @@ -20,9 +20,10 @@ type SomeType { hello: String @deprecated(reason: "Use something else.") } -- TypeScript -- +import type TSomeType from "./DeprecatedMethodField"; import { GraphQLSchema, GraphQLObjectType, GraphQLString } from "graphql"; export function getSchema(): GraphQLSchema { - const SomeTypeType: GraphQLObjectType = new GraphQLObjectType({ + const SomeTypeType: GraphQLObjectType = new GraphQLObjectType({ name: "SomeType", fields() { return { diff --git a/src/tests/fixtures/field_definitions/DeprecatedPropertyField.ts.expected b/src/tests/fixtures/field_definitions/DeprecatedPropertyField.ts.expected index 944c38f4..b828c0bb 100644 --- a/src/tests/fixtures/field_definitions/DeprecatedPropertyField.ts.expected +++ b/src/tests/fixtures/field_definitions/DeprecatedPropertyField.ts.expected @@ -18,9 +18,10 @@ type SomeType { hello: String @deprecated(reason: "Use something else.") } -- TypeScript -- +import type TSomeType from "./DeprecatedPropertyField"; import { GraphQLSchema, GraphQLObjectType, GraphQLString } from "graphql"; export function getSchema(): GraphQLSchema { - const SomeTypeType: GraphQLObjectType = new GraphQLObjectType({ + const SomeTypeType: GraphQLObjectType = new GraphQLObjectType({ name: "SomeType", fields() { return { diff --git a/src/tests/fixtures/field_definitions/FieldAsStaticClassMethod.ts.expected b/src/tests/fixtures/field_definitions/FieldAsStaticClassMethod.ts.expected index 8899d648..fede906e 100644 --- a/src/tests/fixtures/field_definitions/FieldAsStaticClassMethod.ts.expected +++ b/src/tests/fixtures/field_definitions/FieldAsStaticClassMethod.ts.expected @@ -28,9 +28,9 @@ type User { } -- TypeScript -- import { GraphQLSchema, GraphQLObjectType, GraphQLString } from "graphql"; -import { User as queryGetUserResolver } from "./FieldAsStaticClassMethod"; +import { type User as TUser, User as queryGetUserResolver } from "./FieldAsStaticClassMethod"; export function getSchema(): GraphQLSchema { - const UserType: GraphQLObjectType = new GraphQLObjectType({ + const UserType: GraphQLObjectType = new GraphQLObjectType({ name: "User", fields() { return { diff --git a/src/tests/fixtures/field_definitions/FieldAsStaticClassMethodWithClassAsDefaultExport.ts.expected b/src/tests/fixtures/field_definitions/FieldAsStaticClassMethodWithClassAsDefaultExport.ts.expected index 16364980..1fbf6aeb 100644 --- a/src/tests/fixtures/field_definitions/FieldAsStaticClassMethodWithClassAsDefaultExport.ts.expected +++ b/src/tests/fixtures/field_definitions/FieldAsStaticClassMethodWithClassAsDefaultExport.ts.expected @@ -27,10 +27,11 @@ type User { name: String } -- TypeScript -- +import type TUser from "./FieldAsStaticClassMethodWithClassAsDefaultExport"; import queryGetUserResolver from "./FieldAsStaticClassMethodWithClassAsDefaultExport"; import { GraphQLSchema, GraphQLObjectType, GraphQLString } from "graphql"; export function getSchema(): GraphQLSchema { - const UserType: GraphQLObjectType = new GraphQLObjectType({ + const UserType: GraphQLObjectType = new GraphQLObjectType({ name: "User", fields() { return { diff --git a/src/tests/fixtures/field_definitions/GetAcessorField.ts.expected b/src/tests/fixtures/field_definitions/GetAcessorField.ts.expected index d7377ce5..32993919 100644 --- a/src/tests/fixtures/field_definitions/GetAcessorField.ts.expected +++ b/src/tests/fixtures/field_definitions/GetAcessorField.ts.expected @@ -17,9 +17,10 @@ type SomeType { hello: String } -- TypeScript -- +import type TSomeType from "./GetAcessorField"; import { GraphQLSchema, GraphQLObjectType, GraphQLString } from "graphql"; export function getSchema(): GraphQLSchema { - const SomeTypeType: GraphQLObjectType = new GraphQLObjectType({ + const SomeTypeType: GraphQLObjectType = new GraphQLObjectType({ name: "SomeType", fields() { return { diff --git a/src/tests/fixtures/field_definitions/MultipleFieldsAsStaticClassMethods.ts.expected b/src/tests/fixtures/field_definitions/MultipleFieldsAsStaticClassMethods.ts.expected index c31e50c7..19725dcf 100644 --- a/src/tests/fixtures/field_definitions/MultipleFieldsAsStaticClassMethods.ts.expected +++ b/src/tests/fixtures/field_definitions/MultipleFieldsAsStaticClassMethods.ts.expected @@ -34,9 +34,9 @@ type User { } -- TypeScript -- import { GraphQLSchema, GraphQLObjectType, GraphQLString, GraphQLList, GraphQLNonNull } from "graphql"; -import { User as queryGetUserResolver, User as queryGetUsersResolver } from "./MultipleFieldsAsStaticClassMethods"; +import { type User as TUser, User as queryGetUserResolver, User as queryGetUsersResolver } from "./MultipleFieldsAsStaticClassMethods"; export function getSchema(): GraphQLSchema { - const UserType: GraphQLObjectType = new GraphQLObjectType({ + const UserType: GraphQLObjectType = new GraphQLObjectType({ name: "User", fields() { return { diff --git a/src/tests/fixtures/field_definitions/ParameterPropertyField.ts.expected b/src/tests/fixtures/field_definitions/ParameterPropertyField.ts.expected index 13ddc8d2..6b6fe145 100644 --- a/src/tests/fixtures/field_definitions/ParameterPropertyField.ts.expected +++ b/src/tests/fixtures/field_definitions/ParameterPropertyField.ts.expected @@ -17,9 +17,10 @@ type SomeType { hello: String } -- TypeScript -- +import type TSomeType from "./ParameterPropertyField"; import { GraphQLSchema, GraphQLObjectType, GraphQLString } from "graphql"; export function getSchema(): GraphQLSchema { - const SomeTypeType: GraphQLObjectType = new GraphQLObjectType({ + const SomeTypeType: GraphQLObjectType = new GraphQLObjectType({ name: "SomeType", fields() { return { diff --git a/src/tests/fixtures/field_definitions/ParameterPropertyFieldDeprecated.ts.expected b/src/tests/fixtures/field_definitions/ParameterPropertyFieldDeprecated.ts.expected index 3ef64623..379516cf 100644 --- a/src/tests/fixtures/field_definitions/ParameterPropertyFieldDeprecated.ts.expected +++ b/src/tests/fixtures/field_definitions/ParameterPropertyFieldDeprecated.ts.expected @@ -20,9 +20,10 @@ type SomeType { hello: String @deprecated(reason: "Don't use this") } -- TypeScript -- +import type TSomeType from "./ParameterPropertyFieldDeprecated"; import { GraphQLSchema, GraphQLObjectType, GraphQLString } from "graphql"; export function getSchema(): GraphQLSchema { - const SomeTypeType: GraphQLObjectType = new GraphQLObjectType({ + const SomeTypeType: GraphQLObjectType = new GraphQLObjectType({ name: "SomeType", fields() { return { diff --git a/src/tests/fixtures/field_definitions/ParameterPropertyFieldReadOnly.ts.expected b/src/tests/fixtures/field_definitions/ParameterPropertyFieldReadOnly.ts.expected index 8ad67d2a..921ae5ad 100644 --- a/src/tests/fixtures/field_definitions/ParameterPropertyFieldReadOnly.ts.expected +++ b/src/tests/fixtures/field_definitions/ParameterPropertyFieldReadOnly.ts.expected @@ -17,9 +17,10 @@ type SomeType { hello: String } -- TypeScript -- +import type TSomeType from "./ParameterPropertyFieldReadOnly"; import { GraphQLSchema, GraphQLObjectType, GraphQLString } from "graphql"; export function getSchema(): GraphQLSchema { - const SomeTypeType: GraphQLObjectType = new GraphQLObjectType({ + const SomeTypeType: GraphQLObjectType = new GraphQLObjectType({ name: "SomeType", fields() { return { diff --git a/src/tests/fixtures/field_definitions/ParameterPropertyFieldRenamed.ts.expected b/src/tests/fixtures/field_definitions/ParameterPropertyFieldRenamed.ts.expected index 4d7af756..628feb61 100644 --- a/src/tests/fixtures/field_definitions/ParameterPropertyFieldRenamed.ts.expected +++ b/src/tests/fixtures/field_definitions/ParameterPropertyFieldRenamed.ts.expected @@ -17,9 +17,10 @@ type SomeType { hello: String } -- TypeScript -- +import type TSomeType from "./ParameterPropertyFieldRenamed"; import { GraphQLSchema, GraphQLObjectType, GraphQLString } from "graphql"; export function getSchema(): GraphQLSchema { - const SomeTypeType: GraphQLObjectType = new GraphQLObjectType({ + const SomeTypeType: GraphQLObjectType = new GraphQLObjectType({ name: "SomeType", fields() { return { diff --git a/src/tests/fixtures/field_definitions/ParameterPropertyFieldWithDescription.ts.expected b/src/tests/fixtures/field_definitions/ParameterPropertyFieldWithDescription.ts.expected index af7c8620..1ea34ee6 100644 --- a/src/tests/fixtures/field_definitions/ParameterPropertyFieldWithDescription.ts.expected +++ b/src/tests/fixtures/field_definitions/ParameterPropertyFieldWithDescription.ts.expected @@ -21,9 +21,10 @@ type SomeType { hello: String } -- TypeScript -- +import type TSomeType from "./ParameterPropertyFieldWithDescription"; import { GraphQLSchema, GraphQLObjectType, GraphQLString } from "graphql"; export function getSchema(): GraphQLSchema { - const SomeTypeType: GraphQLObjectType = new GraphQLObjectType({ + const SomeTypeType: GraphQLObjectType = new GraphQLObjectType({ name: "SomeType", fields() { return { diff --git a/src/tests/fixtures/field_definitions/PublicFieldMethod.ts.expected b/src/tests/fixtures/field_definitions/PublicFieldMethod.ts.expected index a1bc6d96..f1f5b660 100644 --- a/src/tests/fixtures/field_definitions/PublicFieldMethod.ts.expected +++ b/src/tests/fixtures/field_definitions/PublicFieldMethod.ts.expected @@ -18,8 +18,9 @@ type User { } -- TypeScript -- import { GraphQLSchema, GraphQLObjectType, GraphQLString } from "graphql"; +import type { User as TUser } from "./PublicFieldMethod"; export function getSchema(): GraphQLSchema { - const UserType: GraphQLObjectType = new GraphQLObjectType({ + const UserType: GraphQLObjectType = new GraphQLObjectType({ name: "User", fields() { return { diff --git a/src/tests/fixtures/field_definitions/RenamedFieldWithArgs.ts.expected b/src/tests/fixtures/field_definitions/RenamedFieldWithArgs.ts.expected index 9657cca3..6a720b24 100644 --- a/src/tests/fixtures/field_definitions/RenamedFieldWithArgs.ts.expected +++ b/src/tests/fixtures/field_definitions/RenamedFieldWithArgs.ts.expected @@ -17,9 +17,10 @@ type SomeType { greetz(greeting: String!): String } -- TypeScript -- +import type TSomeType from "./RenamedFieldWithArgs"; import { GraphQLSchema, GraphQLObjectType, GraphQLString, GraphQLNonNull } from "graphql"; export function getSchema(): GraphQLSchema { - const SomeTypeType: GraphQLObjectType = new GraphQLObjectType({ + const SomeTypeType: GraphQLObjectType = new GraphQLObjectType({ name: "SomeType", fields() { return { diff --git a/src/tests/fixtures/field_definitions/StringFieldWithDescription.ts.expected b/src/tests/fixtures/field_definitions/StringFieldWithDescription.ts.expected index 956c1052..66c5a9be 100644 --- a/src/tests/fixtures/field_definitions/StringFieldWithDescription.ts.expected +++ b/src/tests/fixtures/field_definitions/StringFieldWithDescription.ts.expected @@ -21,9 +21,10 @@ type SomeType { hello: String } -- TypeScript -- +import type TSomeType from "./StringFieldWithDescription"; import { GraphQLSchema, GraphQLObjectType, GraphQLString } from "graphql"; export function getSchema(): GraphQLSchema { - const SomeTypeType: GraphQLObjectType = new GraphQLObjectType({ + const SomeTypeType: GraphQLObjectType = new GraphQLObjectType({ name: "SomeType", fields() { return { diff --git a/src/tests/fixtures/field_values/ArrayField.ts.expected b/src/tests/fixtures/field_values/ArrayField.ts.expected index 3ba4d47d..69a9f742 100644 --- a/src/tests/fixtures/field_values/ArrayField.ts.expected +++ b/src/tests/fixtures/field_values/ArrayField.ts.expected @@ -17,9 +17,10 @@ type SomeType { hello: [String!] } -- TypeScript -- +import type TSomeType from "./ArrayField"; import { GraphQLSchema, GraphQLObjectType, GraphQLList, GraphQLNonNull, GraphQLString } from "graphql"; export function getSchema(): GraphQLSchema { - const SomeTypeType: GraphQLObjectType = new GraphQLObjectType({ + const SomeTypeType: GraphQLObjectType = new GraphQLObjectType({ name: "SomeType", fields() { return { diff --git a/src/tests/fixtures/field_values/ArrayOfPromises.ts.expected b/src/tests/fixtures/field_values/ArrayOfPromises.ts.expected index b930798b..add7fbfc 100644 --- a/src/tests/fixtures/field_values/ArrayOfPromises.ts.expected +++ b/src/tests/fixtures/field_values/ArrayOfPromises.ts.expected @@ -18,9 +18,10 @@ type SomeType { c: [String!] } -- TypeScript -- +import type TSomeType from "./ArrayOfPromises"; import { GraphQLSchema, GraphQLObjectType, GraphQLList, GraphQLNonNull, GraphQLString } from "graphql"; export function getSchema(): GraphQLSchema { - const SomeTypeType: GraphQLObjectType = new GraphQLObjectType({ + const SomeTypeType: GraphQLObjectType = new GraphQLObjectType({ name: "SomeType", fields() { return { diff --git a/src/tests/fixtures/field_values/ArrayShorthandField.ts.expected b/src/tests/fixtures/field_values/ArrayShorthandField.ts.expected index 6b611ee5..ab5a6045 100644 --- a/src/tests/fixtures/field_values/ArrayShorthandField.ts.expected +++ b/src/tests/fixtures/field_values/ArrayShorthandField.ts.expected @@ -17,9 +17,10 @@ type SomeType { hello: [String!] } -- TypeScript -- +import type TSomeType from "./ArrayShorthandField"; import { GraphQLSchema, GraphQLObjectType, GraphQLList, GraphQLNonNull, GraphQLString } from "graphql"; export function getSchema(): GraphQLSchema { - const SomeTypeType: GraphQLObjectType = new GraphQLObjectType({ + const SomeTypeType: GraphQLObjectType = new GraphQLObjectType({ name: "SomeType", fields() { return { diff --git a/src/tests/fixtures/field_values/ArrayWithNullableItems.ts.expected b/src/tests/fixtures/field_values/ArrayWithNullableItems.ts.expected index 015a63d5..e9225d2a 100644 --- a/src/tests/fixtures/field_values/ArrayWithNullableItems.ts.expected +++ b/src/tests/fixtures/field_values/ArrayWithNullableItems.ts.expected @@ -17,9 +17,10 @@ type SomeType { hello: [String] } -- TypeScript -- +import type TSomeType from "./ArrayWithNullableItems"; import { GraphQLSchema, GraphQLObjectType, GraphQLList, GraphQLString } from "graphql"; export function getSchema(): GraphQLSchema { - const SomeTypeType: GraphQLObjectType = new GraphQLObjectType({ + const SomeTypeType: GraphQLObjectType = new GraphQLObjectType({ name: "SomeType", fields() { return { diff --git a/src/tests/fixtures/field_values/AsyncPromiseField.ts.expected b/src/tests/fixtures/field_values/AsyncPromiseField.ts.expected index e20460f1..7e0e90ac 100644 --- a/src/tests/fixtures/field_values/AsyncPromiseField.ts.expected +++ b/src/tests/fixtures/field_values/AsyncPromiseField.ts.expected @@ -17,9 +17,10 @@ type SomeType { hello: String } -- TypeScript -- +import type TSomeType from "./AsyncPromiseField"; import { GraphQLSchema, GraphQLObjectType, GraphQLString } from "graphql"; export function getSchema(): GraphQLSchema { - const SomeTypeType: GraphQLObjectType = new GraphQLObjectType({ + const SomeTypeType: GraphQLObjectType = new GraphQLObjectType({ name: "SomeType", fields() { return { diff --git a/src/tests/fixtures/field_values/BooleanField.ts.expected b/src/tests/fixtures/field_values/BooleanField.ts.expected index 95d13592..aeb5bdbc 100644 --- a/src/tests/fixtures/field_values/BooleanField.ts.expected +++ b/src/tests/fixtures/field_values/BooleanField.ts.expected @@ -17,9 +17,10 @@ type SomeType { haveBeenGreeted: Boolean } -- TypeScript -- +import type TSomeType from "./BooleanField"; import { GraphQLSchema, GraphQLObjectType, GraphQLBoolean } from "graphql"; export function getSchema(): GraphQLSchema { - const SomeTypeType: GraphQLObjectType = new GraphQLObjectType({ + const SomeTypeType: GraphQLObjectType = new GraphQLObjectType({ name: "SomeType", fields() { return { diff --git a/src/tests/fixtures/field_values/CustomScalar.ts.expected b/src/tests/fixtures/field_values/CustomScalar.ts.expected index b64b8459..4d62375a 100644 --- a/src/tests/fixtures/field_values/CustomScalar.ts.expected +++ b/src/tests/fixtures/field_values/CustomScalar.ts.expected @@ -22,6 +22,7 @@ type SomeType { hello: MyString } -- TypeScript -- +import type TSomeType from "./CustomScalar"; import type { GqlScalar } from "grats"; import type { MyString as MyStringInternal } from "./CustomScalar"; import { GraphQLSchema, GraphQLScalarType, GraphQLObjectType } from "graphql"; @@ -35,7 +36,7 @@ export function getSchema(config: SchemaConfig): GraphQLSchema { name: "MyString", ...config.scalars.MyString }); - const SomeTypeType: GraphQLObjectType = new GraphQLObjectType({ + const SomeTypeType: GraphQLObjectType = new GraphQLObjectType({ name: "SomeType", fields() { return { diff --git a/src/tests/fixtures/field_values/KitchenSink.ts.expected b/src/tests/fixtures/field_values/KitchenSink.ts.expected index b20d679e..7bcb6e5e 100644 --- a/src/tests/fixtures/field_values/KitchenSink.ts.expected +++ b/src/tests/fixtures/field_values/KitchenSink.ts.expected @@ -81,6 +81,7 @@ type User { name: String } -- TypeScript -- +import type TSomeType from "./KitchenSink"; import { GraphQLSchema, GraphQLObjectType, GraphQLString, GraphQLList, GraphQLNonNull } from "graphql"; export function getSchema(): GraphQLSchema { const UserType: GraphQLObjectType = new GraphQLObjectType({ @@ -117,7 +118,7 @@ export function getSchema(): GraphQLSchema { }; } }); - const SomeTypeType: GraphQLObjectType = new GraphQLObjectType({ + const SomeTypeType: GraphQLObjectType = new GraphQLObjectType({ name: "SomeType", fields() { return { diff --git a/src/tests/fixtures/field_values/MaybePromise.ts.expected b/src/tests/fixtures/field_values/MaybePromise.ts.expected index 4e01479f..3e45c594 100644 --- a/src/tests/fixtures/field_values/MaybePromise.ts.expected +++ b/src/tests/fixtures/field_values/MaybePromise.ts.expected @@ -15,9 +15,10 @@ type SomeType { b: String } -- TypeScript -- +import type TSomeType from "./MaybePromise"; import { GraphQLSchema, GraphQLObjectType, GraphQLString } from "graphql"; export function getSchema(): GraphQLSchema { - const SomeTypeType: GraphQLObjectType = new GraphQLObjectType({ + const SomeTypeType: GraphQLObjectType = new GraphQLObjectType({ name: "SomeType", fields() { return { diff --git a/src/tests/fixtures/field_values/OptionalFields.ts.expected b/src/tests/fixtures/field_values/OptionalFields.ts.expected index c1439640..681cd98e 100644 --- a/src/tests/fixtures/field_values/OptionalFields.ts.expected +++ b/src/tests/fixtures/field_values/OptionalFields.ts.expected @@ -32,9 +32,10 @@ type SomeType { hello: String } -- TypeScript -- +import type TSomeType from "./OptionalFields"; import { GraphQLSchema, GraphQLObjectType, GraphQLString } from "graphql"; export function getSchema(): GraphQLSchema { - const SomeTypeType: GraphQLObjectType = new GraphQLObjectType({ + const SomeTypeType: GraphQLObjectType = new GraphQLObjectType({ name: "SomeType", fields() { return { diff --git a/src/tests/fixtures/field_values/OptionalProperty.ts.expected b/src/tests/fixtures/field_values/OptionalProperty.ts.expected index 1ec2c7dd..2e1efb9d 100644 --- a/src/tests/fixtures/field_values/OptionalProperty.ts.expected +++ b/src/tests/fixtures/field_values/OptionalProperty.ts.expected @@ -15,9 +15,10 @@ type SomeType { hello: String } -- TypeScript -- +import type TSomeType from "./OptionalProperty"; import { GraphQLSchema, GraphQLObjectType, GraphQLString } from "graphql"; export function getSchema(): GraphQLSchema { - const SomeTypeType: GraphQLObjectType = new GraphQLObjectType({ + const SomeTypeType: GraphQLObjectType = new GraphQLObjectType({ name: "SomeType", fields() { return { diff --git a/src/tests/fixtures/field_values/ParenthesizedType.ts.expected b/src/tests/fixtures/field_values/ParenthesizedType.ts.expected index acf67fac..85058c3e 100644 --- a/src/tests/fixtures/field_values/ParenthesizedType.ts.expected +++ b/src/tests/fixtures/field_values/ParenthesizedType.ts.expected @@ -17,9 +17,10 @@ type SomeType { hello: [String] } -- TypeScript -- +import type TSomeType from "./ParenthesizedType"; import { GraphQLSchema, GraphQLObjectType, GraphQLList, GraphQLString } from "graphql"; export function getSchema(): GraphQLSchema { - const SomeTypeType: GraphQLObjectType = new GraphQLObjectType({ + const SomeTypeType: GraphQLObjectType = new GraphQLObjectType({ name: "SomeType", fields() { return { diff --git a/src/tests/fixtures/field_values/PromiseOfPromise.ts.expected b/src/tests/fixtures/field_values/PromiseOfPromise.ts.expected index e84ff807..935beaa3 100644 --- a/src/tests/fixtures/field_values/PromiseOfPromise.ts.expected +++ b/src/tests/fixtures/field_values/PromiseOfPromise.ts.expected @@ -15,9 +15,10 @@ type SomeType { b: String } -- TypeScript -- +import type TSomeType from "./PromiseOfPromise"; import { GraphQLSchema, GraphQLObjectType, GraphQLString } from "graphql"; export function getSchema(): GraphQLSchema { - const SomeTypeType: GraphQLObjectType = new GraphQLObjectType({ + const SomeTypeType: GraphQLObjectType = new GraphQLObjectType({ name: "SomeType", fields() { return { diff --git a/src/tests/fixtures/field_values/ReadonlyArrayField.ts.expected b/src/tests/fixtures/field_values/ReadonlyArrayField.ts.expected index f07eadc5..626803bd 100644 --- a/src/tests/fixtures/field_values/ReadonlyArrayField.ts.expected +++ b/src/tests/fixtures/field_values/ReadonlyArrayField.ts.expected @@ -17,9 +17,10 @@ type SomeType { hello: [String!] } -- TypeScript -- +import type TSomeType from "./ReadonlyArrayField"; import { GraphQLSchema, GraphQLObjectType, GraphQLList, GraphQLNonNull, GraphQLString } from "graphql"; export function getSchema(): GraphQLSchema { - const SomeTypeType: GraphQLObjectType = new GraphQLObjectType({ + const SomeTypeType: GraphQLObjectType = new GraphQLObjectType({ name: "SomeType", fields() { return { diff --git a/src/tests/fixtures/field_values/StringField.ts.expected b/src/tests/fixtures/field_values/StringField.ts.expected index c4a78eab..115bbec9 100644 --- a/src/tests/fixtures/field_values/StringField.ts.expected +++ b/src/tests/fixtures/field_values/StringField.ts.expected @@ -17,9 +17,10 @@ type SomeType { hello: String } -- TypeScript -- +import type TSomeType from "./StringField"; import { GraphQLSchema, GraphQLObjectType, GraphQLString } from "graphql"; export function getSchema(): GraphQLSchema { - const SomeTypeType: GraphQLObjectType = new GraphQLObjectType({ + const SomeTypeType: GraphQLObjectType = new GraphQLObjectType({ name: "SomeType", fields() { return { diff --git a/src/tests/fixtures/field_values/StringFieldKillsParentOnException.ts.expected b/src/tests/fixtures/field_values/StringFieldKillsParentOnException.ts.expected index 69b3feb7..37048026 100644 --- a/src/tests/fixtures/field_values/StringFieldKillsParentOnException.ts.expected +++ b/src/tests/fixtures/field_values/StringFieldKillsParentOnException.ts.expected @@ -20,9 +20,10 @@ type SomeType { hello: String! } -- TypeScript -- +import type TSomeType from "./StringFieldKillsParentOnException"; import { GraphQLSchema, GraphQLObjectType, GraphQLNonNull, GraphQLString } from "graphql"; export function getSchema(): GraphQLSchema { - const SomeTypeType: GraphQLObjectType = new GraphQLObjectType({ + const SomeTypeType: GraphQLObjectType = new GraphQLObjectType({ name: "SomeType", fields() { return { diff --git a/src/tests/fixtures/field_values/UnionField.ts.expected b/src/tests/fixtures/field_values/UnionField.ts.expected index 5e6dd3c9..ce356b22 100644 --- a/src/tests/fixtures/field_values/UnionField.ts.expected +++ b/src/tests/fixtures/field_values/UnionField.ts.expected @@ -44,6 +44,7 @@ type User { name: String } -- TypeScript -- +import type TSomeType from "./UnionField"; import { GraphQLSchema, GraphQLUnionType, GraphQLObjectType, GraphQLString } from "graphql"; export function getSchema(): GraphQLSchema { const EntityType: GraphQLObjectType = new GraphQLObjectType({ @@ -74,7 +75,7 @@ export function getSchema(): GraphQLSchema { return [EntityType, UserType]; } }); - const SomeTypeType: GraphQLObjectType = new GraphQLObjectType({ + const SomeTypeType: GraphQLObjectType = new GraphQLObjectType({ name: "SomeType", fields() { return { diff --git a/src/tests/fixtures/field_values/non_default_nullable/NonNullablePromise.ts.expected b/src/tests/fixtures/field_values/non_default_nullable/NonNullablePromise.ts.expected index 67a6e38b..ffabe565 100644 --- a/src/tests/fixtures/field_values/non_default_nullable/NonNullablePromise.ts.expected +++ b/src/tests/fixtures/field_values/non_default_nullable/NonNullablePromise.ts.expected @@ -18,9 +18,10 @@ type SomeType { hello: String! } -- TypeScript -- +import type TSomeType from "./NonNullablePromise"; import { GraphQLSchema, GraphQLObjectType, GraphQLNonNull, GraphQLString } from "graphql"; export function getSchema(): GraphQLSchema { - const SomeTypeType: GraphQLObjectType = new GraphQLObjectType({ + const SomeTypeType: GraphQLObjectType = new GraphQLObjectType({ name: "SomeType", fields() { return { diff --git a/src/tests/fixtures/field_values/non_default_nullable/NullablePromise.ts.expected b/src/tests/fixtures/field_values/non_default_nullable/NullablePromise.ts.expected index 05c16424..3d922572 100644 --- a/src/tests/fixtures/field_values/non_default_nullable/NullablePromise.ts.expected +++ b/src/tests/fixtures/field_values/non_default_nullable/NullablePromise.ts.expected @@ -18,9 +18,10 @@ type SomeType { hello: String } -- TypeScript -- +import type TSomeType from "./NullablePromise"; import { GraphQLSchema, GraphQLObjectType, GraphQLString } from "graphql"; export function getSchema(): GraphQLSchema { - const SomeTypeType: GraphQLObjectType = new GraphQLObjectType({ + const SomeTypeType: GraphQLObjectType = new GraphQLObjectType({ name: "SomeType", fields() { return { diff --git a/src/tests/fixtures/generics/genericOverArg.ts.expected b/src/tests/fixtures/generics/genericOverArg.ts.expected index 4b83be89..ca1089cf 100644 --- a/src/tests/fixtures/generics/genericOverArg.ts.expected +++ b/src/tests/fixtures/generics/genericOverArg.ts.expected @@ -39,7 +39,7 @@ type SomeInputSomeClass { } -- TypeScript -- import { GraphQLSchema, GraphQLObjectType, GraphQLString, GraphQLInputObjectType, GraphQLNonNull } from "graphql"; -import { someField as querySomeFieldResolver } from "./genericOverArg"; +import { type SomeClass as TSomeInputSomeClass, someField as querySomeFieldResolver } from "./genericOverArg"; export function getSchema(): GraphQLSchema { const SomeInputType: GraphQLInputObjectType = new GraphQLInputObjectType({ name: "SomeInput", @@ -52,7 +52,7 @@ export function getSchema(): GraphQLSchema { }; } }); - const SomeInputSomeClassType: GraphQLObjectType = new GraphQLObjectType({ + const SomeInputSomeClassType: GraphQLObjectType = new GraphQLObjectType({ name: "SomeInputSomeClass", fields() { return { diff --git a/src/tests/fixtures/generics/genericTypeUsingClass.ts.expected b/src/tests/fixtures/generics/genericTypeUsingClass.ts.expected index e458848d..23daa6f9 100644 --- a/src/tests/fixtures/generics/genericTypeUsingClass.ts.expected +++ b/src/tests/fixtures/generics/genericTypeUsingClass.ts.expected @@ -41,7 +41,7 @@ type Query { } -- TypeScript -- import { GraphQLSchema, GraphQLObjectType, GraphQLString } from "graphql"; -import { createEdge as queryCreateEdgeResolver } from "./genericTypeUsingClass"; +import { type Edge as TPageEdge, createEdge as queryCreateEdgeResolver } from "./genericTypeUsingClass"; export function getSchema(): GraphQLSchema { const PageType: GraphQLObjectType = new GraphQLObjectType({ name: "Page", @@ -54,7 +54,7 @@ export function getSchema(): GraphQLSchema { }; } }); - const PageEdgeType: GraphQLObjectType = new GraphQLObjectType({ + const PageEdgeType: GraphQLObjectType = new GraphQLObjectType({ name: "PageEdge", fields() { return { diff --git a/src/tests/fixtures/headers/customHeaders.ts.expected b/src/tests/fixtures/headers/customHeaders.ts.expected index 40b9c3bf..505f581d 100644 --- a/src/tests/fixtures/headers/customHeaders.ts.expected +++ b/src/tests/fixtures/headers/customHeaders.ts.expected @@ -20,9 +20,10 @@ type SomeType { -- TypeScript -- // Generated TS +import type TSomeType from "./customHeaders"; import { GraphQLSchema, GraphQLObjectType, GraphQLString } from "graphql"; export function getSchema(): GraphQLSchema { - const SomeTypeType: GraphQLObjectType = new GraphQLObjectType({ + const SomeTypeType: GraphQLObjectType = new GraphQLObjectType({ name: "SomeType", fields() { return { diff --git a/src/tests/fixtures/headers/multilineHeader.ts.expected b/src/tests/fixtures/headers/multilineHeader.ts.expected index cd5be9e5..c72e420a 100644 --- a/src/tests/fixtures/headers/multilineHeader.ts.expected +++ b/src/tests/fixtures/headers/multilineHeader.ts.expected @@ -24,9 +24,10 @@ type SomeType { // multi-line +import type TSomeType from "./multilineHeader"; import { GraphQLSchema, GraphQLObjectType, GraphQLString } from "graphql"; export function getSchema(): GraphQLSchema { - const SomeTypeType: GraphQLObjectType = new GraphQLObjectType({ + const SomeTypeType: GraphQLObjectType = new GraphQLObjectType({ name: "SomeType", fields() { return { diff --git a/src/tests/fixtures/input_types/InputTypeWithDeprecatedField.ts.expected b/src/tests/fixtures/input_types/InputTypeWithDeprecatedField.ts.expected index fe6a8533..0cf6a9ba 100644 --- a/src/tests/fixtures/input_types/InputTypeWithDeprecatedField.ts.expected +++ b/src/tests/fixtures/input_types/InputTypeWithDeprecatedField.ts.expected @@ -28,6 +28,7 @@ type SomeType { hello: String } -- TypeScript -- +import type TSomeType from "./InputTypeWithDeprecatedField"; import { GraphQLSchema, GraphQLInputObjectType, GraphQLString, GraphQLObjectType } from "graphql"; export function getSchema(): GraphQLSchema { const MyInputTypeType: GraphQLInputObjectType = new GraphQLInputObjectType({ @@ -43,7 +44,7 @@ export function getSchema(): GraphQLSchema { }; } }); - const SomeTypeType: GraphQLObjectType = new GraphQLObjectType({ + const SomeTypeType: GraphQLObjectType = new GraphQLObjectType({ name: "SomeType", fields() { return { diff --git a/src/tests/fixtures/input_types/InputTypeWithFieldDescription.ts.expected b/src/tests/fixtures/input_types/InputTypeWithFieldDescription.ts.expected index 92bd92cd..a57f653a 100644 --- a/src/tests/fixtures/input_types/InputTypeWithFieldDescription.ts.expected +++ b/src/tests/fixtures/input_types/InputTypeWithFieldDescription.ts.expected @@ -26,6 +26,7 @@ type SomeType { hello: String } -- TypeScript -- +import type TSomeType from "./InputTypeWithFieldDescription"; import { GraphQLSchema, GraphQLInputObjectType, GraphQLNonNull, GraphQLString, GraphQLObjectType } from "graphql"; export function getSchema(): GraphQLSchema { const MyInputTypeType: GraphQLInputObjectType = new GraphQLInputObjectType({ @@ -40,7 +41,7 @@ export function getSchema(): GraphQLSchema { }; } }); - const SomeTypeType: GraphQLObjectType = new GraphQLObjectType({ + const SomeTypeType: GraphQLObjectType = new GraphQLObjectType({ name: "SomeType", fields() { return { diff --git a/src/tests/fixtures/interfaces/FieldReturnsInterface.ts.expected b/src/tests/fixtures/interfaces/FieldReturnsInterface.ts.expected index c4a86aa5..7ae5959f 100644 --- a/src/tests/fixtures/interfaces/FieldReturnsInterface.ts.expected +++ b/src/tests/fixtures/interfaces/FieldReturnsInterface.ts.expected @@ -38,6 +38,7 @@ type User implements Person { name: String } -- TypeScript -- +import type TSomeType from "./FieldReturnsInterface"; import { GraphQLSchema, GraphQLInterfaceType, GraphQLString, GraphQLObjectType } from "graphql"; export function getSchema(): GraphQLSchema { const PersonType: GraphQLInterfaceType = new GraphQLInterfaceType({ @@ -51,7 +52,7 @@ export function getSchema(): GraphQLSchema { }; } }); - const SomeTypeType: GraphQLObjectType = new GraphQLObjectType({ + const SomeTypeType: GraphQLObjectType = new GraphQLObjectType({ name: "SomeType", fields() { return { diff --git a/src/tests/fixtures/interfaces/IgnoresExtendsClause.ts.expected b/src/tests/fixtures/interfaces/IgnoresExtendsClause.ts.expected index 97e93528..8151ce6d 100644 --- a/src/tests/fixtures/interfaces/IgnoresExtendsClause.ts.expected +++ b/src/tests/fixtures/interfaces/IgnoresExtendsClause.ts.expected @@ -42,6 +42,7 @@ type User implements Actor { name: String } -- TypeScript -- +import type TSomeType from "./IgnoresExtendsClause"; import { GraphQLSchema, GraphQLInterfaceType, GraphQLString, GraphQLObjectType } from "graphql"; export function getSchema(): GraphQLSchema { const ActorType: GraphQLInterfaceType = new GraphQLInterfaceType({ @@ -69,7 +70,7 @@ export function getSchema(): GraphQLSchema { return [ActorType]; } }); - const SomeTypeType: GraphQLObjectType = new GraphQLObjectType({ + const SomeTypeType: GraphQLObjectType = new GraphQLObjectType({ name: "SomeType", fields() { return { diff --git a/src/tests/fixtures/interfaces/ImplementsInterface.ts.expected b/src/tests/fixtures/interfaces/ImplementsInterface.ts.expected index ac482c20..25169144 100644 --- a/src/tests/fixtures/interfaces/ImplementsInterface.ts.expected +++ b/src/tests/fixtures/interfaces/ImplementsInterface.ts.expected @@ -38,6 +38,7 @@ type User implements Person { name: String } -- TypeScript -- +import type TSomeType from "./ImplementsInterface"; import { GraphQLSchema, GraphQLInterfaceType, GraphQLString, GraphQLObjectType } from "graphql"; export function getSchema(): GraphQLSchema { const PersonType: GraphQLInterfaceType = new GraphQLInterfaceType({ @@ -65,7 +66,7 @@ export function getSchema(): GraphQLSchema { return [PersonType]; } }); - const SomeTypeType: GraphQLObjectType = new GraphQLObjectType({ + const SomeTypeType: GraphQLObjectType = new GraphQLObjectType({ name: "SomeType", fields() { return { diff --git a/src/tests/fixtures/interfaces/ImplementsInterfaceWithTypeParam.ts.expected b/src/tests/fixtures/interfaces/ImplementsInterfaceWithTypeParam.ts.expected index 0c0fbc18..21c22a2d 100644 --- a/src/tests/fixtures/interfaces/ImplementsInterfaceWithTypeParam.ts.expected +++ b/src/tests/fixtures/interfaces/ImplementsInterfaceWithTypeParam.ts.expected @@ -42,6 +42,7 @@ type User implements Person { name: String } -- TypeScript -- +import type TSomeType from "./ImplementsInterfaceWithTypeParam"; import { GraphQLSchema, GraphQLInterfaceType, GraphQLString, GraphQLObjectType } from "graphql"; export function getSchema(): GraphQLSchema { const PersonType: GraphQLInterfaceType = new GraphQLInterfaceType({ @@ -69,7 +70,7 @@ export function getSchema(): GraphQLSchema { return [PersonType]; } }); - const SomeTypeType: GraphQLObjectType = new GraphQLObjectType({ + const SomeTypeType: GraphQLObjectType = new GraphQLObjectType({ name: "SomeType", fields() { return { diff --git a/src/tests/fixtures/interfaces/ImplementsMultipleInterfaces.ts.expected b/src/tests/fixtures/interfaces/ImplementsMultipleInterfaces.ts.expected index 272807f7..a84e5085 100644 --- a/src/tests/fixtures/interfaces/ImplementsMultipleInterfaces.ts.expected +++ b/src/tests/fixtures/interfaces/ImplementsMultipleInterfaces.ts.expected @@ -48,6 +48,7 @@ type User implements Actor & Person { name: String } -- TypeScript -- +import type TSomeType from "./ImplementsMultipleInterfaces"; import { GraphQLSchema, GraphQLInterfaceType, GraphQLString, GraphQLObjectType } from "graphql"; export function getSchema(): GraphQLSchema { const ActorType: GraphQLInterfaceType = new GraphQLInterfaceType({ @@ -86,7 +87,7 @@ export function getSchema(): GraphQLSchema { return [ActorType, PersonType]; } }); - const SomeTypeType: GraphQLObjectType = new GraphQLObjectType({ + const SomeTypeType: GraphQLObjectType = new GraphQLObjectType({ name: "SomeType", fields() { return { diff --git a/src/tests/fixtures/interfaces/InterfaceFieldWithDescription.ts.expected b/src/tests/fixtures/interfaces/InterfaceFieldWithDescription.ts.expected index 483159d3..f042ab61 100644 --- a/src/tests/fixtures/interfaces/InterfaceFieldWithDescription.ts.expected +++ b/src/tests/fixtures/interfaces/InterfaceFieldWithDescription.ts.expected @@ -42,6 +42,7 @@ type User implements IPerson { name: String } -- TypeScript -- +import type TSomeType from "./InterfaceFieldWithDescription"; import { GraphQLSchema, GraphQLInterfaceType, GraphQLString, GraphQLObjectType } from "graphql"; export function getSchema(): GraphQLSchema { const IPersonType: GraphQLInterfaceType = new GraphQLInterfaceType({ @@ -70,7 +71,7 @@ export function getSchema(): GraphQLSchema { return [IPersonType]; } }); - const SomeTypeType: GraphQLObjectType = new GraphQLObjectType({ + const SomeTypeType: GraphQLObjectType = new GraphQLObjectType({ name: "SomeType", fields() { return { diff --git a/src/tests/fixtures/interfaces/InterfaceFieldWithDescriptionThatDiffersFromType.ts.expected b/src/tests/fixtures/interfaces/InterfaceFieldWithDescriptionThatDiffersFromType.ts.expected index 69795873..ffce57b9 100644 --- a/src/tests/fixtures/interfaces/InterfaceFieldWithDescriptionThatDiffersFromType.ts.expected +++ b/src/tests/fixtures/interfaces/InterfaceFieldWithDescriptionThatDiffersFromType.ts.expected @@ -46,6 +46,7 @@ type User implements IPerson { name: String } -- TypeScript -- +import type TSomeType from "./InterfaceFieldWithDescriptionThatDiffersFromType"; import { GraphQLSchema, GraphQLInterfaceType, GraphQLString, GraphQLObjectType } from "graphql"; export function getSchema(): GraphQLSchema { const IPersonType: GraphQLInterfaceType = new GraphQLInterfaceType({ @@ -75,7 +76,7 @@ export function getSchema(): GraphQLSchema { return [IPersonType]; } }); - const SomeTypeType: GraphQLObjectType = new GraphQLObjectType({ + const SomeTypeType: GraphQLObjectType = new GraphQLObjectType({ name: "SomeType", fields() { return { diff --git a/src/tests/fixtures/interfaces/InterfaceWithCustomName.ts.expected b/src/tests/fixtures/interfaces/InterfaceWithCustomName.ts.expected index 8ad54388..69bc99ec 100644 --- a/src/tests/fixtures/interfaces/InterfaceWithCustomName.ts.expected +++ b/src/tests/fixtures/interfaces/InterfaceWithCustomName.ts.expected @@ -38,6 +38,7 @@ type User implements Person { name: String } -- TypeScript -- +import type TSomeType from "./InterfaceWithCustomName"; import { GraphQLSchema, GraphQLInterfaceType, GraphQLString, GraphQLObjectType } from "graphql"; export function getSchema(): GraphQLSchema { const PersonType: GraphQLInterfaceType = new GraphQLInterfaceType({ @@ -65,7 +66,7 @@ export function getSchema(): GraphQLSchema { return [PersonType]; } }); - const SomeTypeType: GraphQLObjectType = new GraphQLObjectType({ + const SomeTypeType: GraphQLObjectType = new GraphQLObjectType({ name: "SomeType", fields() { return { diff --git a/src/tests/fixtures/interfaces/InterfaceWithDeprecatedField.ts.expected b/src/tests/fixtures/interfaces/InterfaceWithDeprecatedField.ts.expected index 57112ef7..c0697162 100644 --- a/src/tests/fixtures/interfaces/InterfaceWithDeprecatedField.ts.expected +++ b/src/tests/fixtures/interfaces/InterfaceWithDeprecatedField.ts.expected @@ -40,6 +40,7 @@ type User implements IPerson { name: String } -- TypeScript -- +import type TSomeType from "./InterfaceWithDeprecatedField"; import { GraphQLSchema, GraphQLInterfaceType, GraphQLString, GraphQLObjectType } from "graphql"; export function getSchema(): GraphQLSchema { const IPersonType: GraphQLInterfaceType = new GraphQLInterfaceType({ @@ -68,7 +69,7 @@ export function getSchema(): GraphQLSchema { return [IPersonType]; } }); - const SomeTypeType: GraphQLObjectType = new GraphQLObjectType({ + const SomeTypeType: GraphQLObjectType = new GraphQLObjectType({ name: "SomeType", fields() { return { diff --git a/src/tests/fixtures/interfaces/InterfaceWithDescription.ts.expected b/src/tests/fixtures/interfaces/InterfaceWithDescription.ts.expected index 722d6717..3c9bc401 100644 --- a/src/tests/fixtures/interfaces/InterfaceWithDescription.ts.expected +++ b/src/tests/fixtures/interfaces/InterfaceWithDescription.ts.expected @@ -43,6 +43,7 @@ type User implements IPerson { name: String } -- TypeScript -- +import type TSomeType from "./InterfaceWithDescription"; import { GraphQLSchema, GraphQLInterfaceType, GraphQLString, GraphQLObjectType } from "graphql"; export function getSchema(): GraphQLSchema { const IPersonType: GraphQLInterfaceType = new GraphQLInterfaceType({ @@ -71,7 +72,7 @@ export function getSchema(): GraphQLSchema { return [IPersonType]; } }); - const SomeTypeType: GraphQLObjectType = new GraphQLObjectType({ + const SomeTypeType: GraphQLObjectType = new GraphQLObjectType({ name: "SomeType", fields() { return { diff --git a/src/tests/fixtures/pothos_integration/customScalar.ts b/src/tests/fixtures/pothos_integration/customScalar.ts new file mode 100644 index 00000000..d8cf99b4 --- /dev/null +++ b/src/tests/fixtures/pothos_integration/customScalar.ts @@ -0,0 +1,4 @@ +// {"EXPERIMENTAL__emitPothos": "./pothosGrats.ts"} + +/** @gqlScalar */ +export type MyType = Date; diff --git a/src/tests/fixtures/pothos_integration/customScalar.ts.expected b/src/tests/fixtures/pothos_integration/customScalar.ts.expected new file mode 100644 index 00000000..53a12f48 --- /dev/null +++ b/src/tests/fixtures/pothos_integration/customScalar.ts.expected @@ -0,0 +1,44 @@ +----------------- +INPUT +----------------- +// {"EXPERIMENTAL__emitPothos": "./pothosGrats.ts"} + +/** @gqlScalar */ +export type MyType = Date; + +----------------- +OUTPUT +----------------- +-- SDL -- +scalar MyType +-- TypeScript -- +import type { GqlScalar } from "grats"; +import type { MyType as MyTypeInternal } from "./customScalar"; +import { GraphQLSchema, GraphQLScalarType } from "graphql"; +export type SchemaConfig = { + scalars: { + MyType: GqlScalar; + }; +}; +export function getSchema(config: SchemaConfig): GraphQLSchema { + const MyTypeType: GraphQLScalarType = new GraphQLScalarType({ + name: "MyType", + ...config.scalars.MyType + }); + return new GraphQLSchema({ + types: [MyTypeType] + }); +} + +-- Pothos Types -- +import { MyType as MyTypeInternal } from "./customScalar"; +export type PothosUserSchemaTypes = { + Defaults: "v4"; + Scalars: { + MyType: { + Output: MyTypeInternal; + Input: MyTypeInternal; + }; + }; + DefaultFieldNullability: true; +}; diff --git a/src/tests/fixtures/pothos_integration/defaultNullabilityOff.ts b/src/tests/fixtures/pothos_integration/defaultNullabilityOff.ts new file mode 100644 index 00000000..0aa4f1f2 --- /dev/null +++ b/src/tests/fixtures/pothos_integration/defaultNullabilityOff.ts @@ -0,0 +1,7 @@ +// {"EXPERIMENTAL__emitPothos": "./pothosGrats.ts", "nullableByDefault": false } + +/** @gqlType */ +export class MyType { + /** @gqlField */ + name: string = "Example"; +} diff --git a/src/tests/fixtures/pothos_integration/defaultNullabilityOff.ts.expected b/src/tests/fixtures/pothos_integration/defaultNullabilityOff.ts.expected new file mode 100644 index 00000000..c3543fe7 --- /dev/null +++ b/src/tests/fixtures/pothos_integration/defaultNullabilityOff.ts.expected @@ -0,0 +1,47 @@ +----------------- +INPUT +----------------- +// {"EXPERIMENTAL__emitPothos": "./pothosGrats.ts", "nullableByDefault": false } + +/** @gqlType */ +export class MyType { + /** @gqlField */ + name: string = "Example"; +} + +----------------- +OUTPUT +----------------- +-- SDL -- +type MyType { + name: String! +} +-- TypeScript -- +import { GraphQLSchema, GraphQLObjectType, GraphQLNonNull, GraphQLString } from "graphql"; +import type { MyType as TMyType } from "./defaultNullabilityOff"; +export function getSchema(): GraphQLSchema { + const MyTypeType: GraphQLObjectType = new GraphQLObjectType({ + name: "MyType", + fields() { + return { + name: { + name: "name", + type: new GraphQLNonNull(GraphQLString) + } + }; + } + }); + return new GraphQLSchema({ + types: [MyTypeType] + }); +} + +-- Pothos Types -- +import { MyType as MyTypeInternal } from "./defaultNullabilityOff"; +export type PothosUserSchemaTypes = { + Defaults: "v4"; + Objects: { + MyType: MyTypeInternal; + }; + DefaultFieldNullability: false; +}; diff --git a/src/tests/fixtures/pothos_integration/simplePothosExample.ts b/src/tests/fixtures/pothos_integration/simplePothosExample.ts new file mode 100644 index 00000000..0afe3d7c --- /dev/null +++ b/src/tests/fixtures/pothos_integration/simplePothosExample.ts @@ -0,0 +1,13 @@ +// {"EXPERIMENTAL__emitPothos": "./pothosGrats.ts"} + +/** @gqlType */ +export class MyType { + /** @gqlField */ + name: string = "Example"; +} + +/** @gqlEnum */ +export enum MyEnum { + VALUE_ONE = "VALUE_ONE", + VALUE_TWO = "VALUE_TWO", +} diff --git a/src/tests/fixtures/pothos_integration/simplePothosExample.ts.expected b/src/tests/fixtures/pothos_integration/simplePothosExample.ts.expected new file mode 100644 index 00000000..78fff205 --- /dev/null +++ b/src/tests/fixtures/pothos_integration/simplePothosExample.ts.expected @@ -0,0 +1,72 @@ +----------------- +INPUT +----------------- +// {"EXPERIMENTAL__emitPothos": "./pothosGrats.ts"} + +/** @gqlType */ +export class MyType { + /** @gqlField */ + name: string = "Example"; +} + +/** @gqlEnum */ +export enum MyEnum { + VALUE_ONE = "VALUE_ONE", + VALUE_TWO = "VALUE_TWO", +} + +----------------- +OUTPUT +----------------- +-- SDL -- +enum MyEnum { + VALUE_ONE + VALUE_TWO +} + +type MyType { + name: String +} +-- TypeScript -- +import { GraphQLSchema, GraphQLEnumType, GraphQLObjectType, GraphQLString } from "graphql"; +import type { MyType as TMyType } from "./simplePothosExample"; +export function getSchema(): GraphQLSchema { + const MyEnumType: GraphQLEnumType = new GraphQLEnumType({ + name: "MyEnum", + values: { + VALUE_ONE: { + value: "VALUE_ONE" + }, + VALUE_TWO: { + value: "VALUE_TWO" + } + } + }); + const MyTypeType: GraphQLObjectType = new GraphQLObjectType({ + name: "MyType", + fields() { + return { + name: { + name: "name", + type: GraphQLString + } + }; + } + }); + return new GraphQLSchema({ + types: [MyEnumType, MyTypeType] + }); +} + +-- Pothos Types -- +import { MyEnum as MyEnumInternal, MyType as MyTypeInternal } from "./simplePothosExample"; +export type PothosUserSchemaTypes = { + Defaults: "v4"; + Objects: { + MyType: MyTypeInternal; + }; + Enums: { + MyEnum: MyEnumInternal; + }; + DefaultFieldNullability: true; +}; diff --git a/src/tests/fixtures/resolver_context/ClassMethodWithContextValue.ts.expected b/src/tests/fixtures/resolver_context/ClassMethodWithContextValue.ts.expected index 4ead0dc6..9abdda71 100644 --- a/src/tests/fixtures/resolver_context/ClassMethodWithContextValue.ts.expected +++ b/src/tests/fixtures/resolver_context/ClassMethodWithContextValue.ts.expected @@ -23,8 +23,9 @@ type SomeType { } -- TypeScript -- import { GraphQLSchema, GraphQLObjectType, GraphQLString } from "graphql"; +import type { SomeType as TSomeType } from "./ClassMethodWithContextValue"; export function getSchema(): GraphQLSchema { - const SomeTypeType: GraphQLObjectType = new GraphQLObjectType({ + const SomeTypeType: GraphQLObjectType = new GraphQLObjectType({ name: "SomeType", fields() { return { diff --git a/src/tests/fixtures/resolver_context/ClassMethodWithContextValueExported.ts.expected b/src/tests/fixtures/resolver_context/ClassMethodWithContextValueExported.ts.expected index 985135e1..ee0adf70 100644 --- a/src/tests/fixtures/resolver_context/ClassMethodWithContextValueExported.ts.expected +++ b/src/tests/fixtures/resolver_context/ClassMethodWithContextValueExported.ts.expected @@ -23,8 +23,9 @@ type SomeType { } -- TypeScript -- import { GraphQLSchema, GraphQLObjectType, GraphQLString } from "graphql"; +import type { SomeType as TSomeType } from "./ClassMethodWithContextValueExported"; export function getSchema(): GraphQLSchema { - const SomeTypeType: GraphQLObjectType = new GraphQLObjectType({ + const SomeTypeType: GraphQLObjectType = new GraphQLObjectType({ name: "SomeType", fields() { return { diff --git a/src/tests/fixtures/resolver_context/ContextValueBeforeArgs.ts.expected b/src/tests/fixtures/resolver_context/ContextValueBeforeArgs.ts.expected index 29263371..80337669 100644 --- a/src/tests/fixtures/resolver_context/ContextValueBeforeArgs.ts.expected +++ b/src/tests/fixtures/resolver_context/ContextValueBeforeArgs.ts.expected @@ -21,8 +21,9 @@ type SomeType { } -- TypeScript -- import { GraphQLSchema, GraphQLObjectType, GraphQLString, GraphQLNonNull } from "graphql"; +import type { SomeType as TSomeType } from "./ContextValueBeforeArgs"; export function getSchema(): GraphQLSchema { - const SomeTypeType: GraphQLObjectType = new GraphQLObjectType({ + const SomeTypeType: GraphQLObjectType = new GraphQLObjectType({ name: "SomeType", fields() { return { diff --git a/src/tests/fixtures/resolver_context/ContextValueOptional.ts.expected b/src/tests/fixtures/resolver_context/ContextValueOptional.ts.expected index c3e90748..5a9af115 100644 --- a/src/tests/fixtures/resolver_context/ContextValueOptional.ts.expected +++ b/src/tests/fixtures/resolver_context/ContextValueOptional.ts.expected @@ -24,8 +24,9 @@ type SomeType { } -- TypeScript -- import { GraphQLSchema, GraphQLObjectType, GraphQLString } from "graphql"; +import type { SomeType as TSomeType } from "./ContextValueOptional"; export function getSchema(): GraphQLSchema { - const SomeTypeType: GraphQLObjectType = new GraphQLObjectType({ + const SomeTypeType: GraphQLObjectType = new GraphQLObjectType({ name: "SomeType", fields() { return { diff --git a/src/tests/fixtures/resolver_context/ContextValueReadTwice.ts.expected b/src/tests/fixtures/resolver_context/ContextValueReadTwice.ts.expected index 45b9d893..69c56862 100644 --- a/src/tests/fixtures/resolver_context/ContextValueReadTwice.ts.expected +++ b/src/tests/fixtures/resolver_context/ContextValueReadTwice.ts.expected @@ -23,8 +23,9 @@ type SomeType { } -- TypeScript -- import { GraphQLSchema, GraphQLObjectType, GraphQLString } from "graphql"; +import type { SomeType as TSomeType } from "./ContextValueReadTwice"; export function getSchema(): GraphQLSchema { - const SomeTypeType: GraphQLObjectType = new GraphQLObjectType({ + const SomeTypeType: GraphQLObjectType = new GraphQLObjectType({ name: "SomeType", fields() { return { diff --git a/src/tests/fixtures/resolver_context/FunctionWithContextValue.ts.expected b/src/tests/fixtures/resolver_context/FunctionWithContextValue.ts.expected index acbb3ed9..d228588a 100644 --- a/src/tests/fixtures/resolver_context/FunctionWithContextValue.ts.expected +++ b/src/tests/fixtures/resolver_context/FunctionWithContextValue.ts.expected @@ -23,9 +23,9 @@ type User { } -- TypeScript -- import { GraphQLSchema, GraphQLObjectType, GraphQLString } from "graphql"; -import { greeting as userGreetingResolver } from "./FunctionWithContextValue"; +import { type User as TUser, greeting as userGreetingResolver } from "./FunctionWithContextValue"; export function getSchema(): GraphQLSchema { - const UserType: GraphQLObjectType = new GraphQLObjectType({ + const UserType: GraphQLObjectType = new GraphQLObjectType({ name: "User", fields() { return { diff --git a/src/tests/fixtures/resolver_context/MultipleClassMethodsReferencingContextValue.ts.expected b/src/tests/fixtures/resolver_context/MultipleClassMethodsReferencingContextValue.ts.expected index 7feaa158..3a57917e 100644 --- a/src/tests/fixtures/resolver_context/MultipleClassMethodsReferencingContextValue.ts.expected +++ b/src/tests/fixtures/resolver_context/MultipleClassMethodsReferencingContextValue.ts.expected @@ -29,8 +29,9 @@ type SomeType { } -- TypeScript -- import { GraphQLSchema, GraphQLObjectType, GraphQLString } from "graphql"; +import type { SomeType as TSomeType } from "./MultipleClassMethodsReferencingContextValue"; export function getSchema(): GraphQLSchema { - const SomeTypeType: GraphQLObjectType = new GraphQLObjectType({ + const SomeTypeType: GraphQLObjectType = new GraphQLObjectType({ name: "SomeType", fields() { return { diff --git a/src/tests/fixtures/resolver_info/ClassMethodWithInfoValue.ts.expected b/src/tests/fixtures/resolver_info/ClassMethodWithInfoValue.ts.expected index 985c2d9f..78112e41 100644 --- a/src/tests/fixtures/resolver_info/ClassMethodWithInfoValue.ts.expected +++ b/src/tests/fixtures/resolver_info/ClassMethodWithInfoValue.ts.expected @@ -20,8 +20,9 @@ type SomeType { } -- TypeScript -- import { GraphQLSchema, GraphQLObjectType, GraphQLString } from "graphql"; +import type { SomeType as TSomeType } from "./ClassMethodWithInfoValue"; export function getSchema(): GraphQLSchema { - const SomeTypeType: GraphQLObjectType = new GraphQLObjectType({ + const SomeTypeType: GraphQLObjectType = new GraphQLObjectType({ name: "SomeType", fields() { return { diff --git a/src/tests/fixtures/resolver_info/StaticMethodWithInfoValue.ts.expected b/src/tests/fixtures/resolver_info/StaticMethodWithInfoValue.ts.expected index 79f78ae6..f48d4be6 100644 --- a/src/tests/fixtures/resolver_info/StaticMethodWithInfoValue.ts.expected +++ b/src/tests/fixtures/resolver_info/StaticMethodWithInfoValue.ts.expected @@ -30,7 +30,7 @@ type SomeType { } -- TypeScript -- import { GraphQLSchema, GraphQLObjectType, GraphQLString } from "graphql"; -import { SomeType as queryGreetingResolver } from "./StaticMethodWithInfoValue"; +import { SomeType as queryGreetingResolver, type SomeType as TSomeType } from "./StaticMethodWithInfoValue"; export function getSchema(): GraphQLSchema { const QueryType: GraphQLObjectType = new GraphQLObjectType({ name: "Query", @@ -46,7 +46,7 @@ export function getSchema(): GraphQLSchema { }; } }); - const SomeTypeType: GraphQLObjectType = new GraphQLObjectType({ + const SomeTypeType: GraphQLObjectType = new GraphQLObjectType({ name: "SomeType", fields() { return { diff --git a/src/tests/fixtures/semantic_nullability/semanticNonNull.ts.expected b/src/tests/fixtures/semantic_nullability/semanticNonNull.ts.expected index 0a5b0fa2..1d487be4 100644 --- a/src/tests/fixtures/semantic_nullability/semanticNonNull.ts.expected +++ b/src/tests/fixtures/semantic_nullability/semanticNonNull.ts.expected @@ -56,6 +56,7 @@ type User { } -- TypeScript -- import { GraphQLSchema, GraphQLDirective, DirectiveLocation, GraphQLList, GraphQLInt, specifiedDirectives, GraphQLObjectType, GraphQLString, defaultFieldResolver } from "graphql"; +import type { User as TUser } from "./semanticNonNull"; async function assertNonNull(value: T | Promise): Promise { const awaited = await value; if (awaited == null) @@ -63,7 +64,7 @@ async function assertNonNull(value: T | Promise): Promise { return awaited; } export function getSchema(): GraphQLSchema { - const UserType: GraphQLObjectType = new GraphQLObjectType({ + const UserType: GraphQLObjectType = new GraphQLObjectType({ name: "User", fields() { return { diff --git a/src/tests/fixtures/semantic_nullability/semanticNonNullMatchesInterface.ts.expected b/src/tests/fixtures/semantic_nullability/semanticNonNullMatchesInterface.ts.expected index 0fa9407e..86843bc9 100644 --- a/src/tests/fixtures/semantic_nullability/semanticNonNullMatchesInterface.ts.expected +++ b/src/tests/fixtures/semantic_nullability/semanticNonNullMatchesInterface.ts.expected @@ -67,6 +67,7 @@ type User implements IPerson { } -- TypeScript -- import { GraphQLSchema, GraphQLDirective, DirectiveLocation, GraphQLList, GraphQLInt, specifiedDirectives, GraphQLInterfaceType, GraphQLString, GraphQLObjectType, defaultFieldResolver } from "graphql"; +import type { User as TUser } from "./semanticNonNullMatchesInterface"; async function assertNonNull(value: T | Promise): Promise { const awaited = await value; if (awaited == null) @@ -85,7 +86,7 @@ export function getSchema(): GraphQLSchema { }; } }); - const UserType: GraphQLObjectType = new GraphQLObjectType({ + const UserType: GraphQLObjectType = new GraphQLObjectType({ name: "User", fields() { return { diff --git a/src/tests/fixtures/semantic_nullability/semanticNull.ts.expected b/src/tests/fixtures/semantic_nullability/semanticNull.ts.expected index 9e02461f..b1c1bd0e 100644 --- a/src/tests/fixtures/semantic_nullability/semanticNull.ts.expected +++ b/src/tests/fixtures/semantic_nullability/semanticNull.ts.expected @@ -59,8 +59,9 @@ type User { } -- TypeScript -- import { GraphQLSchema, GraphQLDirective, DirectiveLocation, GraphQLList, GraphQLInt, specifiedDirectives, GraphQLObjectType, GraphQLString } from "graphql"; +import type { User as TUser } from "./semanticNull"; export function getSchema(): GraphQLSchema { - const UserType: GraphQLObjectType = new GraphQLObjectType({ + const UserType: GraphQLObjectType = new GraphQLObjectType({ name: "User", fields() { return { diff --git a/src/tests/fixtures/subscriptions/NonSubscriptionClassWithAsyncIterable.ts.expected b/src/tests/fixtures/subscriptions/NonSubscriptionClassWithAsyncIterable.ts.expected index 01b29426..1592e50b 100644 --- a/src/tests/fixtures/subscriptions/NonSubscriptionClassWithAsyncIterable.ts.expected +++ b/src/tests/fixtures/subscriptions/NonSubscriptionClassWithAsyncIterable.ts.expected @@ -37,8 +37,9 @@ type User { } -- TypeScript -- import { GraphQLSchema, GraphQLObjectType, GraphQLNonNull, GraphQLList, GraphQLString } from "graphql"; +import type { User as TUser } from "./NonSubscriptionClassWithAsyncIterable"; export function getSchema(): GraphQLSchema { - const UserType: GraphQLObjectType = new GraphQLObjectType({ + const UserType: GraphQLObjectType = new GraphQLObjectType({ name: "User", fields() { return { diff --git a/src/tests/fixtures/todo/EnumFromUnionTypeWithVariantWithDescription.ts.expected b/src/tests/fixtures/todo/EnumFromUnionTypeWithVariantWithDescription.ts.expected index b6dd02ea..d046adf6 100644 --- a/src/tests/fixtures/todo/EnumFromUnionTypeWithVariantWithDescription.ts.expected +++ b/src/tests/fixtures/todo/EnumFromUnionTypeWithVariantWithDescription.ts.expected @@ -27,6 +27,7 @@ type SomeType { hello: MyEnum } -- TypeScript -- +import type TSomeType from "./EnumFromUnionTypeWithVariantWithDescription"; import { GraphQLSchema, GraphQLEnumType, GraphQLObjectType } from "graphql"; export function getSchema(): GraphQLSchema { const MyEnumType: GraphQLEnumType = new GraphQLEnumType({ @@ -40,7 +41,7 @@ export function getSchema(): GraphQLSchema { } } }); - const SomeTypeType: GraphQLObjectType = new GraphQLObjectType({ + const SomeTypeType: GraphQLObjectType = new GraphQLObjectType({ name: "SomeType", fields() { return { diff --git a/src/tests/fixtures/type_definitions/ClassImplementsNonGqlInterface.ts.expected b/src/tests/fixtures/type_definitions/ClassImplementsNonGqlInterface.ts.expected index d1726422..54370a5f 100644 --- a/src/tests/fixtures/type_definitions/ClassImplementsNonGqlInterface.ts.expected +++ b/src/tests/fixtures/type_definitions/ClassImplementsNonGqlInterface.ts.expected @@ -23,9 +23,10 @@ type User { hello: String } -- TypeScript -- +import type TUser from "./ClassImplementsNonGqlInterface"; import { GraphQLSchema, GraphQLObjectType, GraphQLString } from "graphql"; export function getSchema(): GraphQLSchema { - const UserType: GraphQLObjectType = new GraphQLObjectType({ + const UserType: GraphQLObjectType = new GraphQLObjectType({ name: "User", description: "The root of all evil.", fields() { diff --git a/src/tests/fixtures/type_definitions/ClassWithDescription.ts.expected b/src/tests/fixtures/type_definitions/ClassWithDescription.ts.expected index 16b161f1..de5346e8 100644 --- a/src/tests/fixtures/type_definitions/ClassWithDescription.ts.expected +++ b/src/tests/fixtures/type_definitions/ClassWithDescription.ts.expected @@ -20,9 +20,10 @@ type SomeType { hello: String } -- TypeScript -- +import type TSomeType from "./ClassWithDescription"; import { GraphQLSchema, GraphQLObjectType, GraphQLString } from "graphql"; export function getSchema(): GraphQLSchema { - const SomeTypeType: GraphQLObjectType = new GraphQLObjectType({ + const SomeTypeType: GraphQLObjectType = new GraphQLObjectType({ name: "SomeType", description: "The root of all evil.", fields() { diff --git a/src/tests/fixtures/type_definitions/ClassWithDescriptionAndCustomName.ts.expected b/src/tests/fixtures/type_definitions/ClassWithDescriptionAndCustomName.ts.expected index ee9aed25..49517be2 100644 --- a/src/tests/fixtures/type_definitions/ClassWithDescriptionAndCustomName.ts.expected +++ b/src/tests/fixtures/type_definitions/ClassWithDescriptionAndCustomName.ts.expected @@ -20,9 +20,10 @@ type SomeType { hello: String } -- TypeScript -- +import type TSomeType from "./ClassWithDescriptionAndCustomName"; import { GraphQLSchema, GraphQLObjectType, GraphQLString } from "graphql"; export function getSchema(): GraphQLSchema { - const SomeTypeType: GraphQLObjectType = new GraphQLObjectType({ + const SomeTypeType: GraphQLObjectType = new GraphQLObjectType({ name: "SomeType", description: "The root of all evil.", fields() { diff --git a/src/tests/fixtures/type_definitions/TypeFromClassDefinitionImplementsInterface.ts.expected b/src/tests/fixtures/type_definitions/TypeFromClassDefinitionImplementsInterface.ts.expected index 70e7c4ae..792499ca 100644 --- a/src/tests/fixtures/type_definitions/TypeFromClassDefinitionImplementsInterface.ts.expected +++ b/src/tests/fixtures/type_definitions/TypeFromClassDefinitionImplementsInterface.ts.expected @@ -26,6 +26,7 @@ type User implements Person { hello: String } -- TypeScript -- +import type TUser from "./TypeFromClassDefinitionImplementsInterface"; import { GraphQLSchema, GraphQLInterfaceType, GraphQLString, GraphQLObjectType } from "graphql"; export function getSchema(): GraphQLSchema { const PersonType: GraphQLInterfaceType = new GraphQLInterfaceType({ @@ -39,7 +40,7 @@ export function getSchema(): GraphQLSchema { }; } }); - const UserType: GraphQLObjectType = new GraphQLObjectType({ + const UserType: GraphQLObjectType = new GraphQLObjectType({ name: "User", fields() { return { diff --git a/src/tests/fixtures/type_definitions/TypeFromClassDefinitionImplementsMultipleInterfaces.ts.expected b/src/tests/fixtures/type_definitions/TypeFromClassDefinitionImplementsMultipleInterfaces.ts.expected index ea4a8914..920b91fc 100644 --- a/src/tests/fixtures/type_definitions/TypeFromClassDefinitionImplementsMultipleInterfaces.ts.expected +++ b/src/tests/fixtures/type_definitions/TypeFromClassDefinitionImplementsMultipleInterfaces.ts.expected @@ -40,6 +40,7 @@ type User implements Node & Person { id: String } -- TypeScript -- +import type TUser from "./TypeFromClassDefinitionImplementsMultipleInterfaces"; import { GraphQLSchema, GraphQLInterfaceType, GraphQLString, GraphQLObjectType } from "graphql"; export function getSchema(): GraphQLSchema { const NodeType: GraphQLInterfaceType = new GraphQLInterfaceType({ @@ -64,7 +65,7 @@ export function getSchema(): GraphQLSchema { }; } }); - const UserType: GraphQLObjectType = new GraphQLObjectType({ + const UserType: GraphQLObjectType = new GraphQLObjectType({ name: "User", fields() { return { diff --git a/src/tests/fixtures/typename/PropertySignatureTypename.ts.expected b/src/tests/fixtures/typename/PropertySignatureTypename.ts.expected index 09932219..91c737a7 100644 --- a/src/tests/fixtures/typename/PropertySignatureTypename.ts.expected +++ b/src/tests/fixtures/typename/PropertySignatureTypename.ts.expected @@ -27,6 +27,7 @@ type User implements IPerson { } -- TypeScript -- import { GraphQLSchema, GraphQLInterfaceType, GraphQLString, GraphQLObjectType } from "graphql"; +import type { User as TUser } from "./PropertySignatureTypename"; export function getSchema(): GraphQLSchema { const IPersonType: GraphQLInterfaceType = new GraphQLInterfaceType({ name: "IPerson", @@ -39,7 +40,7 @@ export function getSchema(): GraphQLSchema { }; } }); - const UserType: GraphQLObjectType = new GraphQLObjectType({ + const UserType: GraphQLObjectType = new GraphQLObjectType({ name: "User", fields() { return { diff --git a/src/tests/fixtures/typename/PropertyTypename.ts.expected b/src/tests/fixtures/typename/PropertyTypename.ts.expected index 3ebd0ce8..2b83d44f 100644 --- a/src/tests/fixtures/typename/PropertyTypename.ts.expected +++ b/src/tests/fixtures/typename/PropertyTypename.ts.expected @@ -17,8 +17,9 @@ type User { } -- TypeScript -- import { GraphQLSchema, GraphQLObjectType, GraphQLString } from "graphql"; +import type { User as TUser } from "./PropertyTypename"; export function getSchema(): GraphQLSchema { - const UserType: GraphQLObjectType = new GraphQLObjectType({ + const UserType: GraphQLObjectType = new GraphQLObjectType({ name: "User", fields() { return { diff --git a/src/tests/fixtures/unions/DefineUnionType.ts.expected b/src/tests/fixtures/unions/DefineUnionType.ts.expected index 47b5ed1f..408efb7d 100644 --- a/src/tests/fixtures/unions/DefineUnionType.ts.expected +++ b/src/tests/fixtures/unions/DefineUnionType.ts.expected @@ -42,6 +42,7 @@ type User { name: String } -- TypeScript -- +import type TSomeType from "./DefineUnionType"; import { GraphQLSchema, GraphQLUnionType, GraphQLObjectType, GraphQLString } from "graphql"; export function getSchema(): GraphQLSchema { const EntityType: GraphQLObjectType = new GraphQLObjectType({ @@ -72,7 +73,7 @@ export function getSchema(): GraphQLSchema { return [EntityType, UserType]; } }); - const SomeTypeType: GraphQLObjectType = new GraphQLObjectType({ + const SomeTypeType: GraphQLObjectType = new GraphQLObjectType({ name: "SomeType", fields() { return { diff --git a/src/tests/fixtures/unions/DefineUnionTypeWithInterfaces.ts.expected b/src/tests/fixtures/unions/DefineUnionTypeWithInterfaces.ts.expected index 7fecbbb1..d074f589 100644 --- a/src/tests/fixtures/unions/DefineUnionTypeWithInterfaces.ts.expected +++ b/src/tests/fixtures/unions/DefineUnionTypeWithInterfaces.ts.expected @@ -42,6 +42,7 @@ type User { name: String } -- TypeScript -- +import type TSomeType from "./DefineUnionTypeWithInterfaces"; import { GraphQLSchema, GraphQLUnionType, GraphQLObjectType, GraphQLString } from "graphql"; export function getSchema(): GraphQLSchema { const EntityType: GraphQLObjectType = new GraphQLObjectType({ @@ -72,7 +73,7 @@ export function getSchema(): GraphQLSchema { return [EntityType, UserType]; } }); - const SomeTypeType: GraphQLObjectType = new GraphQLObjectType({ + const SomeTypeType: GraphQLObjectType = new GraphQLObjectType({ name: "SomeType", fields() { return { diff --git a/src/tests/fixtures/unions/DefineUnionTypeWithTypeLiterals.ts.expected b/src/tests/fixtures/unions/DefineUnionTypeWithTypeLiterals.ts.expected index 4c1f4dfb..ca9458c9 100644 --- a/src/tests/fixtures/unions/DefineUnionTypeWithTypeLiterals.ts.expected +++ b/src/tests/fixtures/unions/DefineUnionTypeWithTypeLiterals.ts.expected @@ -42,6 +42,7 @@ type User { name: String } -- TypeScript -- +import type TSomeType from "./DefineUnionTypeWithTypeLiterals"; import { GraphQLSchema, GraphQLUnionType, GraphQLObjectType, GraphQLString } from "graphql"; export function getSchema(): GraphQLSchema { const EntityType: GraphQLObjectType = new GraphQLObjectType({ @@ -72,7 +73,7 @@ export function getSchema(): GraphQLSchema { return [EntityType, UserType]; } }); - const SomeTypeType: GraphQLObjectType = new GraphQLObjectType({ + const SomeTypeType: GraphQLObjectType = new GraphQLObjectType({ name: "SomeType", fields() { return { diff --git a/src/tests/fixtures/unions/UnionWithDescription.ts.expected b/src/tests/fixtures/unions/UnionWithDescription.ts.expected index 863344b7..e155c4fc 100644 --- a/src/tests/fixtures/unions/UnionWithDescription.ts.expected +++ b/src/tests/fixtures/unions/UnionWithDescription.ts.expected @@ -46,6 +46,7 @@ type User { name: String } -- TypeScript -- +import type TSomeType from "./UnionWithDescription"; import { GraphQLSchema, GraphQLUnionType, GraphQLObjectType, GraphQLString } from "graphql"; export function getSchema(): GraphQLSchema { const EntityType: GraphQLObjectType = new GraphQLObjectType({ @@ -77,7 +78,7 @@ export function getSchema(): GraphQLSchema { return [EntityType, UserType]; } }); - const SomeTypeType: GraphQLObjectType = new GraphQLObjectType({ + const SomeTypeType: GraphQLObjectType = new GraphQLObjectType({ name: "SomeType", fields() { return { diff --git a/src/tests/integrationFixtures/resolveTypeViaClass/schema.ts b/src/tests/integrationFixtures/resolveTypeViaClass/schema.ts index 745b0fe0..8e83158f 100644 --- a/src/tests/integrationFixtures/resolveTypeViaClass/schema.ts +++ b/src/tests/integrationFixtures/resolveTypeViaClass/schema.ts @@ -1,6 +1,7 @@ import DefaultNodeClass from "./index"; +import type TDefaultNode from "./index"; import { GraphQLSchema, GraphQLObjectType, GraphQLInterfaceType, GraphQLID, GraphQLNonNull } from "graphql"; -import { Guest as GuestClass, ThisNameGetsIgnored as RenamedNodeClass, User as UserClass, node as queryNodeResolver } from "./index"; +import { Guest as GuestClass, ThisNameGetsIgnored as RenamedNodeClass, User as UserClass, node as queryNodeResolver, type Guest as TGuest, type ThisNameGetsIgnored as TRenamedNode, type User as TUser } from "./index"; export function getSchema(): GraphQLSchema { const GqlNodeType: GraphQLInterfaceType = new GraphQLInterfaceType({ name: "GqlNode", @@ -33,7 +34,7 @@ export function getSchema(): GraphQLSchema { }; } }); - const DefaultNodeType: GraphQLObjectType = new GraphQLObjectType({ + const DefaultNodeType: GraphQLObjectType = new GraphQLObjectType({ name: "DefaultNode", fields() { return { @@ -47,7 +48,7 @@ export function getSchema(): GraphQLSchema { return [GqlNodeType]; } }); - const GuestType: GraphQLObjectType = new GraphQLObjectType({ + const GuestType: GraphQLObjectType = new GraphQLObjectType({ name: "Guest", fields() { return { @@ -61,7 +62,7 @@ export function getSchema(): GraphQLSchema { return [GqlNodeType]; } }); - const RenamedNodeType: GraphQLObjectType = new GraphQLObjectType({ + const RenamedNodeType: GraphQLObjectType = new GraphQLObjectType({ name: "RenamedNode", fields() { return { @@ -75,7 +76,7 @@ export function getSchema(): GraphQLSchema { return [GqlNodeType]; } }); - const UserType: GraphQLObjectType = new GraphQLObjectType({ + const UserType: GraphQLObjectType = new GraphQLObjectType({ name: "User", fields() { return { diff --git a/src/tests/test.ts b/src/tests/test.ts index 8b42c4a1..145c08c2 100644 --- a/src/tests/test.ts +++ b/src/tests/test.ts @@ -32,6 +32,8 @@ import { extend } from "../utils/helpers"; import { Result, ok, err } from "../utils/Result"; import { applyFixes } from "../fixFixable"; import { writeTypeScriptTypeToDisk } from "../../scripts/buildConfigTypes"; +import { codegenPothosUserSchemaTypes } from "../codegen/pothosTypeCodegen"; +import TSAstBuilder from "../codegen/TSAstBuilder"; writeTypeScriptTypeToDisk(); @@ -245,7 +247,19 @@ const testDirs = [ print(docSansDirectives), ); - return ok(`-- SDL --\n${sdl}\n-- TypeScript --\n${executableSchema}`); + let pothosTypesCode: string | null = null; + if (parsedOptions.raw.grats.EXPERIMENTAL__emitPothos != null) { + pothosTypesCode = codegenPothosUserSchemaTypes( + schema, + parsedOptions.raw.grats, + ); + } + + let output = `-- SDL --\n${sdl}\n-- TypeScript --\n${executableSchema}`; + if (pothosTypesCode != null) { + output += `\n-- Pothos Types --\n${pothosTypesCode}`; + } + return ok(output); } }, }, @@ -325,6 +339,19 @@ const testDirs = [ writeFileSync(enumsPath, enumsCode); } + // Generate the pothos types file if EXPERIMENTAL__emitPothos is configured + if (parsedOptions.raw.grats.EXPERIMENTAL__emitPothos != null) { + const pothosTypesPath = path.join( + path.dirname(filePath), + "pothosTypes.ts", + ); + const pothosTypesCode = codegenPothosUserSchemaTypes( + schema, + parsedOptions.raw.grats, + ); + writeFileSync(pothosTypesPath, pothosTypesCode); + } + const server = await import(filePath); if (server.query == null || typeof server.query !== "string") { diff --git a/src/transforms/makeResolverSignature.ts b/src/transforms/makeResolverSignature.ts index 1770cbaa..9d86ce5a 100644 --- a/src/transforms/makeResolverSignature.ts +++ b/src/transforms/makeResolverSignature.ts @@ -38,8 +38,10 @@ export function makeResolverSignature(documentAst: DocumentNode): Metadata { case "function": resolver = { kind: "function", - path: fieldResolver.path, - exportName: fieldResolver.exportName, + exported: { + tsModulePath: fieldResolver.path, + exportName: fieldResolver.exportName, + }, arguments: transformArgs(fieldResolver.arguments), }; break; @@ -53,8 +55,10 @@ export function makeResolverSignature(documentAst: DocumentNode): Metadata { case "staticMethod": resolver = { kind: "staticMethod", - path: fieldResolver.path, - exportName: fieldResolver.exportName, + exported: { + tsModulePath: fieldResolver.path, + exportName: fieldResolver.exportName, + }, name: fieldResolver.name, arguments: transformArgs(fieldResolver.arguments), }; @@ -97,8 +101,10 @@ function transformArg(arg: DirectiveResolverArgument): ResolverArgument { case "derivedContext": return { kind: "derivedContext", - path: arg.path, - exportName: arg.exportName, + exported: { + tsModulePath: arg.path, + exportName: arg.exportName, + }, args: arg.args.map((arg): ContextArgs => { const newArg = transformArg(arg); invariant( diff --git a/src/tsPlugin/initTsPlugin.ts b/src/tsPlugin/initTsPlugin.ts index a691f6a4..a4c76939 100644 --- a/src/tsPlugin/initTsPlugin.ts +++ b/src/tsPlugin/initTsPlugin.ts @@ -50,6 +50,7 @@ export function initTsPlugin(modules: { typescript: typeof TS }) { const doc = info.languageService.getProgram()?.getSourceFile(filename); if (doc == null) return prior; + // @ts-ignore const result = extract(doc, undefined); if (result.kind === "OK") return prior; @@ -89,6 +90,7 @@ export function initTsPlugin(modules: { typescript: typeof TS }) { const doc = info.languageService.getProgram()?.getSourceFile(fileName); if (doc == null) return prior; + // @ts-ignore const result = extract(doc, undefined); if (result.kind === "OK") return prior;