From 03b5ffd24a5a57fa13600d52d5fc9f9e26ab4f0b Mon Sep 17 00:00:00 2001 From: Tim Griesser Date: Wed, 4 Aug 2021 10:59:50 -0400 Subject: [PATCH 01/10] fix: #921 wrong typegen for nullable values w/ default (#965) * fix: #921 wrong typegen for nullable values w/ default * refactor: make the conditional easier to follow --- patches/prettier-plugin-jsdoc+0.2.5.patch | 13 ------------- src/typegenPrinter.ts | 9 +++++---- tests/__snapshots__/typegenPrinter.spec.ts.snap | 4 ++-- tests/integrations/kitchenSink/__typegen.ts | 2 +- tests/typegen/types.gen.ts | 2 +- 5 files changed, 9 insertions(+), 21 deletions(-) delete mode 100644 patches/prettier-plugin-jsdoc+0.2.5.patch diff --git a/patches/prettier-plugin-jsdoc+0.2.5.patch b/patches/prettier-plugin-jsdoc+0.2.5.patch deleted file mode 100644 index 0b2d5ec5..00000000 --- a/patches/prettier-plugin-jsdoc+0.2.5.patch +++ /dev/null @@ -1,13 +0,0 @@ -diff --git a/node_modules/prettier-plugin-jsdoc/lib/parser.js b/node_modules/prettier-plugin-jsdoc/lib/parser.js -index 85b9e5d..3b98730 100644 ---- a/node_modules/prettier-plugin-jsdoc/lib/parser.js -+++ b/node_modules/prettier-plugin-jsdoc/lib/parser.js -@@ -12,7 +12,7 @@ const stringify_1 = require("./stringify"); - /** @link https://prettier.io/docs/en/api.html#custom-parser-api} */ - exports.getParser = (parser) => function jsdocParser(text, parsers, options) { - const ast = parser(text, parsers, options); -- if (!options.jsdocParser) { -+ if (!options || !options.jsdocParser) { - return ast; - } - /** diff --git a/src/typegenPrinter.ts b/src/typegenPrinter.ts index 1016f49d..948c1d0f 100644 --- a/src/typegenPrinter.ts +++ b/src/typegenPrinter.ts @@ -16,6 +16,7 @@ import { isInterfaceType, isListType, isNonNullType, + isNullableType, isObjectType, isScalarType, isSpecifiedScalarType, @@ -715,15 +716,15 @@ export class TypegenPrinter { } normalizeArg(arg: GraphQLInputField | GraphQLArgument): [string, string] { - return [this.argSeparator(arg.type, Boolean(arg.defaultValue)), this.argTypeRepresentation(arg.type)] + return [this.argSeparator(arg.type, arg.defaultValue !== undefined), this.argTypeRepresentation(arg.type)] } argSeparator(type: GraphQLInputType, hasDefaultValue: boolean) { - if (hasDefaultValue || isNonNullType(type)) { - return ':' + if (hasDefaultValue || isNullableType(type)) { + return '?:' } - return '?:' + return ':' } argTypeRepresentation(arg: GraphQLInputType): string { diff --git a/tests/__snapshots__/typegenPrinter.spec.ts.snap b/tests/__snapshots__/typegenPrinter.spec.ts.snap index 127b2394..038fb5f8 100644 --- a/tests/__snapshots__/typegenPrinter.spec.ts.snap +++ b/tests/__snapshots__/typegenPrinter.spec.ts.snap @@ -16,7 +16,7 @@ exports[`typegenPrinter builds the input object type defs 1`] = ` } PostFilters: { // input type order: NexusGenEnums['OrderEnum']; // OrderEnum! - search: string | null; // String + search?: string | null; // String } }" `; @@ -167,7 +167,7 @@ export interface NexusGenInputs { } PostFilters: { // input type order: NexusGenEnums['OrderEnum']; // OrderEnum! - search: string | null; // String + search?: string | null; // String } } diff --git a/tests/integrations/kitchenSink/__typegen.ts b/tests/integrations/kitchenSink/__typegen.ts index b250dfcb..f7fc99d8 100644 --- a/tests/integrations/kitchenSink/__typegen.ts +++ b/tests/integrations/kitchenSink/__typegen.ts @@ -279,7 +279,7 @@ export interface NexusGenArgTypes { user: { // args id?: string | null // ID - status: NexusGenEnums['UserStatus'] | null // UserStatus + status?: NexusGenEnums['UserStatus'] | null // UserStatus } } User: { diff --git a/tests/typegen/types.gen.ts b/tests/typegen/types.gen.ts index bdca6f81..c6a0b800 100644 --- a/tests/typegen/types.gen.ts +++ b/tests/typegen/types.gen.ts @@ -16,7 +16,7 @@ export interface NexusGenInputs { PostFilters: { // input type order: NexusGenEnums['OrderEnum'] // OrderEnum! - search: string | null // String + search?: string | null // String } } From a914cc33d1a933eebfc57d8c6dc7af7dcf613427 Mon Sep 17 00:00:00 2001 From: Tim Griesser Date: Tue, 17 Aug 2021 13:50:36 -0400 Subject: [PATCH 02/10] Revert "fix: #921 wrong typegen for nullable values w/ default (#965)" (#966) This reverts commit 03b5ffd24a5a57fa13600d52d5fc9f9e26ab4f0b. --- patches/prettier-plugin-jsdoc+0.2.5.patch | 13 +++++++++++++ src/typegenPrinter.ts | 9 ++++----- tests/__snapshots__/typegenPrinter.spec.ts.snap | 4 ++-- tests/integrations/kitchenSink/__typegen.ts | 2 +- tests/typegen/types.gen.ts | 2 +- 5 files changed, 21 insertions(+), 9 deletions(-) create mode 100644 patches/prettier-plugin-jsdoc+0.2.5.patch diff --git a/patches/prettier-plugin-jsdoc+0.2.5.patch b/patches/prettier-plugin-jsdoc+0.2.5.patch new file mode 100644 index 00000000..0b2d5ec5 --- /dev/null +++ b/patches/prettier-plugin-jsdoc+0.2.5.patch @@ -0,0 +1,13 @@ +diff --git a/node_modules/prettier-plugin-jsdoc/lib/parser.js b/node_modules/prettier-plugin-jsdoc/lib/parser.js +index 85b9e5d..3b98730 100644 +--- a/node_modules/prettier-plugin-jsdoc/lib/parser.js ++++ b/node_modules/prettier-plugin-jsdoc/lib/parser.js +@@ -12,7 +12,7 @@ const stringify_1 = require("./stringify"); + /** @link https://prettier.io/docs/en/api.html#custom-parser-api} */ + exports.getParser = (parser) => function jsdocParser(text, parsers, options) { + const ast = parser(text, parsers, options); +- if (!options.jsdocParser) { ++ if (!options || !options.jsdocParser) { + return ast; + } + /** diff --git a/src/typegenPrinter.ts b/src/typegenPrinter.ts index 948c1d0f..1016f49d 100644 --- a/src/typegenPrinter.ts +++ b/src/typegenPrinter.ts @@ -16,7 +16,6 @@ import { isInterfaceType, isListType, isNonNullType, - isNullableType, isObjectType, isScalarType, isSpecifiedScalarType, @@ -716,15 +715,15 @@ export class TypegenPrinter { } normalizeArg(arg: GraphQLInputField | GraphQLArgument): [string, string] { - return [this.argSeparator(arg.type, arg.defaultValue !== undefined), this.argTypeRepresentation(arg.type)] + return [this.argSeparator(arg.type, Boolean(arg.defaultValue)), this.argTypeRepresentation(arg.type)] } argSeparator(type: GraphQLInputType, hasDefaultValue: boolean) { - if (hasDefaultValue || isNullableType(type)) { - return '?:' + if (hasDefaultValue || isNonNullType(type)) { + return ':' } - return ':' + return '?:' } argTypeRepresentation(arg: GraphQLInputType): string { diff --git a/tests/__snapshots__/typegenPrinter.spec.ts.snap b/tests/__snapshots__/typegenPrinter.spec.ts.snap index 038fb5f8..127b2394 100644 --- a/tests/__snapshots__/typegenPrinter.spec.ts.snap +++ b/tests/__snapshots__/typegenPrinter.spec.ts.snap @@ -16,7 +16,7 @@ exports[`typegenPrinter builds the input object type defs 1`] = ` } PostFilters: { // input type order: NexusGenEnums['OrderEnum']; // OrderEnum! - search?: string | null; // String + search: string | null; // String } }" `; @@ -167,7 +167,7 @@ export interface NexusGenInputs { } PostFilters: { // input type order: NexusGenEnums['OrderEnum']; // OrderEnum! - search?: string | null; // String + search: string | null; // String } } diff --git a/tests/integrations/kitchenSink/__typegen.ts b/tests/integrations/kitchenSink/__typegen.ts index f7fc99d8..b250dfcb 100644 --- a/tests/integrations/kitchenSink/__typegen.ts +++ b/tests/integrations/kitchenSink/__typegen.ts @@ -279,7 +279,7 @@ export interface NexusGenArgTypes { user: { // args id?: string | null // ID - status?: NexusGenEnums['UserStatus'] | null // UserStatus + status: NexusGenEnums['UserStatus'] | null // UserStatus } } User: { diff --git a/tests/typegen/types.gen.ts b/tests/typegen/types.gen.ts index c6a0b800..bdca6f81 100644 --- a/tests/typegen/types.gen.ts +++ b/tests/typegen/types.gen.ts @@ -16,7 +16,7 @@ export interface NexusGenInputs { PostFilters: { // input type order: NexusGenEnums['OrderEnum'] // OrderEnum! - search?: string | null // String + search: string | null // String } } From 5984ee122ef4d2a5f34e5e689a2cddb0102d2d73 Mon Sep 17 00:00:00 2001 From: Tim Griesser Date: Tue, 17 Aug 2021 15:49:47 -0400 Subject: [PATCH 03/10] feat: ConfiguredTypegen for splitting global types & configuring input type emission (#967) * feat: ConfiguredTypegen for splitting globals from other types * default the declareInputs to true --- src/builder.ts | 23 +- src/makeSchema.ts | 14 +- src/typegenMetadata.ts | 65 ++- src/typegenPrinter.ts | 143 ++++- src/typegenUtils.ts | 14 +- .../typegenPrinterGlobals.spec.ts.snap | 513 ++++++++++++++++++ .../declarativeWrappingPlugin/__typegen.ts | 27 +- tests/integrations/kitchenSink/__typegen.ts | 79 +-- tests/typegen-globals/global-types.gen.ts | 16 + tests/typegen-globals/schema.gen.graphql | 75 +++ tests/typegen-globals/types.gen.ts | 232 ++++++++ tests/typegen/types.gen.ts | 88 +-- tests/typegenPrinterGlobals.spec.ts | 118 ++++ 13 files changed, 1280 insertions(+), 127 deletions(-) create mode 100644 tests/__snapshots__/typegenPrinterGlobals.spec.ts.snap create mode 100644 tests/typegen-globals/global-types.gen.ts create mode 100644 tests/typegen-globals/schema.gen.graphql create mode 100644 tests/typegen-globals/types.gen.ts create mode 100644 tests/typegenPrinterGlobals.spec.ts diff --git a/src/builder.ts b/src/builder.ts index f771ead2..21cf5721 100644 --- a/src/builder.ts +++ b/src/builder.ts @@ -176,6 +176,27 @@ type PossibleOutputType = type PossibleInputType = string | AllNexusNamedInputTypeDefs | GraphQLType +export interface ConfiguredTypegen { + /** Path for the generated type defs */ + outputPath: string + /** + * Determine the path the "globals" are output, useful when you have a monorepo setup and need to isolate + * the globals from the rest of the types in order to have multiple schemas/ts projects + */ + globalsPath?: string + /** + * If globalsPath is defined, these headers are added to the "globals" generated file, rather than the + * typegen generated file + */ + globalsHeaders?: string[] + /** + * If "true", declares dedicated interfaces for any inputs / args + * + * @default true + */ + declareInputs?: boolean +} + export interface BuilderConfigInput { /** * Generated artifact settings. Set to false to disable all. Set to true to enable all and use default @@ -195,7 +216,7 @@ export interface BuilderConfigInput { * will pick it up without any configuration needed by you. For more details about the @types system * refer to https://www.typescriptlang.org/docs/handbook/tsconfig-json.html#types-typeroots-and-types */ - typegen?: boolean | string + typegen?: boolean | string | ConfiguredTypegen /** * GraphQL SDL file generation toggle and location. * diff --git a/src/makeSchema.ts b/src/makeSchema.ts index c8aad994..a61c420a 100644 --- a/src/makeSchema.ts +++ b/src/makeSchema.ts @@ -1,4 +1,4 @@ -import { makeSchemaInternal, SchemaConfig } from './builder' +import { ConfiguredTypegen, makeSchemaInternal, SchemaConfig } from './builder' import type { NexusGraphQLSchema } from './definitions/_types' import { TypegenMetadata } from './typegenMetadata' import { resolveTypegenConfig } from './typegenUtils' @@ -58,19 +58,19 @@ export async function generateSchema(config: SchemaConfig): Promise => { const { schema, missingTypes, finalConfig } = makeSchemaInternal(config) const typegenConfig = resolveTypegenConfig(finalConfig) - const { schemaTypes, tsTypes } = await new TypegenMetadata(typegenConfig).generateArtifactContents( - schema, - typeFilePath - ) + const { schemaTypes, tsTypes, globalTypes } = await new TypegenMetadata( + typegenConfig + ).generateArtifactContents(schema, typegen) assertNoMissingTypes(schema, missingTypes) runAbstractTypeRuntimeChecks(schema, finalConfig.features) - return { schema, schemaTypes, tsTypes } + return { schema, schemaTypes, tsTypes, globalTypes } } diff --git a/src/typegenMetadata.ts b/src/typegenMetadata.ts index b57efb8f..7c0af58c 100644 --- a/src/typegenMetadata.ts +++ b/src/typegenMetadata.ts @@ -1,6 +1,7 @@ import { GraphQLSchema, lexicographicSortSchema, printSchema } from 'graphql' import * as path from 'path' import type { BuilderConfigInput, TypegenInfo } from './builder' +import type { ConfiguredTypegen } from './core' import type { NexusGraphQLSchema } from './definitions/_types' import { SDL_HEADER, TYPEGEN_HEADER } from './lang' import { typegenAutoConfig } from './typegenAutoConfig' @@ -12,7 +13,7 @@ export interface TypegenMetadataConfig nexusSchemaImportId?: string outputs: { schema: null | string - typegen: null | string + typegen: null | string | ConfiguredTypegen } } @@ -26,26 +27,42 @@ export class TypegenMetadata { /** Generates the artifacts of the build based on what we know about the schema and how it was defined. */ async generateArtifacts(schema: NexusGraphQLSchema) { const sortedSchema = this.sortSchema(schema) - if (this.config.outputs.schema || this.config.outputs.typegen) { - const { schemaTypes, tsTypes } = await this.generateArtifactContents( - sortedSchema, - this.config.outputs.typegen - ) + const { typegen } = this.config.outputs + if (this.config.outputs.schema || typegen) { + const { schemaTypes, tsTypes, globalTypes } = await this.generateArtifactContents(sortedSchema, typegen) if (this.config.outputs.schema) { await this.writeFile('schema', schemaTypes, this.config.outputs.schema) } - if (this.config.outputs.typegen) { - await this.writeFile('types', tsTypes, this.config.outputs.typegen) + if (typegen) { + if (typeof typegen === 'string') { + await this.writeFile('types', tsTypes, typegen) + } else { + await this.writeFile('types', tsTypes, typegen.outputPath) + if (typeof typegen.globalsPath === 'string') { + await this.writeFile('types', globalTypes ?? '', typegen.globalsPath) + } + } } } } - async generateArtifactContents(schema: NexusGraphQLSchema, typeFilePath: string | null) { - const [schemaTypes, tsTypes] = await Promise.all([ - this.generateSchemaFile(schema), - typeFilePath ? this.generateTypesFile(schema, typeFilePath) : '', - ]) - return { schemaTypes, tsTypes } + async generateArtifactContents(schema: NexusGraphQLSchema, typegen: string | null | ConfiguredTypegen) { + const result = { + schemaTypes: this.generateSchemaFile(schema), + tsTypes: '', + globalTypes: null as null | string, + } + if (!typegen) { + return result + } + if (typeof typegen === 'string') { + result.tsTypes = await this.generateTypesFile(schema, typegen) + } else { + const generateResult = await this.generateConfiguredTypes(schema, typegen) + result.tsTypes = generateResult.tsTypes + result.globalTypes = generateResult.globalTypes + } + return result } sortSchema(schema: NexusGraphQLSchema) { @@ -115,11 +132,25 @@ export class TypegenMetadata { const typegenInfo = await this.getTypegenInfo(schema, typegenPath) return new TypegenPrinter(schema, { + declareInputs: true, ...typegenInfo, typegenPath, }).print() } + /** Generates the type definitions */ + async generateConfiguredTypes(schema: NexusGraphQLSchema, typegen: ConfiguredTypegen) { + const { outputPath: typegenPath, globalsPath, declareInputs = true } = typegen + const typegenInfo = await this.getTypegenInfo(schema, typegenPath) + + return new TypegenPrinter(schema, { + ...typegenInfo, + typegenPath, + globalsPath, + declareInputs, + }).printConfigured() + } + async getTypegenInfo(schema: GraphQLSchema, typegenPath?: string): Promise { if ('typegenConfig' in this.config) { throw new Error( @@ -130,7 +161,7 @@ export class TypegenMetadata { if (this.config.sourceTypes) { return typegenAutoConfig(this.config.sourceTypes, this.config.contextType)( schema, - typegenPath || this.config.outputs.typegen || '' + typegenPath || this.normalizeTypegenPath(this.config.outputs.typegen) || '' ) } @@ -142,4 +173,8 @@ export class TypegenMetadata { sourceTypeMap: {}, } } + + private normalizeTypegenPath(typegen: string | ConfiguredTypegen | null) { + return typeof typegen === 'string' ? typegen : typegen ? typegen.outputPath : null + } } diff --git a/src/typegenPrinter.ts b/src/typegenPrinter.ts index 1016f49d..8e602d7f 100644 --- a/src/typegenPrinter.ts +++ b/src/typegenPrinter.ts @@ -24,6 +24,7 @@ import { import type { TypegenInfo } from './builder' import { isNexusPrintedGenTyping, isNexusPrintedGenTypingImport } from './definitions/wrapping' import type { NexusGraphQLSchema } from './definitions/_types' +import { TYPEGEN_HEADER } from './lang' import type { StringLike } from './plugin' import { eachObj, @@ -34,6 +35,7 @@ import { mapObj, mapValues, PrintedGenTypingImport, + relativePathTo, resolveImportPath, } from './utils' @@ -52,6 +54,9 @@ type RootTypeMapping = Record> interface TypegenInfoWithFile extends TypegenInfo { typegenPath: string + globalsPath?: string + globalsHeaders?: string + declareInputs?: boolean } /** @@ -77,7 +82,28 @@ export class TypegenPrinter { } print() { - const body = [ + const body = [this.printCommon(), this.printPlugins()].join('\n\n') + return [this.printHeaders(), body].join('\n\n') + } + + printConfigured() { + if (this.typegenInfo.globalsPath) { + const common = this.printCommon() + const tsTypes = [this.printHeadersCommon(), common].join('\n\n') + const globalTypes = [this.printHeadersGlobal(), this.printPlugins()].join('\n\n') + return { + tsTypes, + globalTypes, + } + } + return { + tsTypes: this.print(), + globalTypes: null, + } + } + + private printCommon() { + return [ this.printInputTypeMap(), this.printEnumTypeMap(), this.printScalarTypeMap(), @@ -101,26 +127,42 @@ export class TypegenPrinter { this.printResolveTypeAbstractTypes('NexusGenAbstractsUsingStrategyResolveType'), this.printFeaturesConfig('NexusGenFeaturesConfig'), this.printGenTypeMap(), - this.printPlugins(), ].join('\n\n') - return [this.printHeaders(), body].join('\n\n') } printHeaders() { - const fieldDefs = [ - this.printDynamicInputFieldDefinitions(), - this.printDynamicOutputFieldDefinitions(), - this.printDynamicOutputPropertyDefinitions(), - ] + return [this.printHeadersCommon(), this.printHeadersGlobal()].join('\n') + } + + private printHeadersCommon() { return [ this.typegenInfo.headers.join('\n'), this.typegenInfo.imports.join('\n'), this.printDynamicImport(), - ...fieldDefs, - GLOBAL_DECLARATION, ].join('\n') } + private printHeadersGlobal() { + const headers = [ + this.printDynamicInputFieldDefinitions(), + this.printDynamicOutputFieldDefinitions(), + this.printDynamicOutputPropertyDefinitions(), + GLOBAL_DECLARATION, + ] + + if (this.typegenInfo.globalsPath) { + headers.unshift( + `import { NexusGenTypes } from '${relativePathTo( + this.typegenInfo.typegenPath, + this.typegenInfo.globalsPath ?? '' + )}'` + ) + headers.unshift(this.typegenInfo.globalsHeaders ?? TYPEGEN_HEADER) + } + + return headers.join('\n') + } + printGenTypeMap() { return [`export interface NexusGenTypes {`] .concat([ @@ -467,11 +509,29 @@ export class TypegenPrinter { } printInputTypeMap() { - return this.printTypeFieldInterface('NexusGenInputs', this.buildInputTypeMap(), 'input type') + const inputTypeMap = this.buildInputTypeMap() + + if (this.typegenInfo.declareInputs) { + const declaredInputs: string[] = mapObj(inputTypeMap, (fields, inputName) => + this.printNamedObj(inputName, fields) + ) + return [...declaredInputs, this.printNamedMap('NexusGenInputs', inputTypeMap)].join('\n\n') + } + + return this.printTypeFieldInterface('NexusGenInputs', inputTypeMap, 'input type') } printEnumTypeMap() { - return this.printTypeInterface('NexusGenEnums', this.buildEnumTypeMap()) + const enumTypeMap = this.buildEnumTypeMap() + + if (this.typegenInfo.declareInputs) { + return [ + ...mapObj(enumTypeMap, (val, name) => `export type ${name} = ${val}`), + this.printNamedMap('NexusGenEnums', enumTypeMap), + ].join('\n\n') + } + + return this.printTypeInterface('NexusGenEnums', enumTypeMap) } printScalarTypeMap() { @@ -631,7 +691,34 @@ export class TypegenPrinter { } printArgTypeMap() { - return this.printArgTypeFieldInterface(this.buildArgTypeMap()) + const argTypeMap = this.buildArgTypeMap() + if (this.typegenInfo.declareInputs) { + const declaredArgs: string[] = [] + eachObj(argTypeMap, (fields, typeName) => { + eachObj(fields, (args, fieldName) => { + declaredArgs.push(this.printNamedObj(this.getArgsName(typeName, fieldName), args)) + }) + }) + return [...declaredArgs, this.printArgTypeFieldInterface(argTypeMap)].join('\n\n') + } + + return this.printArgTypeFieldInterface(argTypeMap) + } + + private getArgsName(typeName: string, fieldName: string) { + return `${typeName}${fieldName.slice(0, 1).toUpperCase().concat(fieldName.slice(1))}Args` + } + + printNamedObj(name: string, obj: Record) { + return [ + `export interface ${name} {`, + ...mapObj(obj, (val, key) => ` ${key}${val[0]} ${val[1]}`), + `}`, + ].join('\n') + } + + printNamedMap(name: string, obj: Record) { + return [`export interface ${name} {`, ...mapObj(obj, (val, key) => ` ${key}: ${key}`), `}`].join('\n') } buildReturnTypeMap() { @@ -695,7 +782,11 @@ export class TypegenPrinter { } else if (isScalarType(type)) { typing.push(this.printScalar(type)) } else if (isEnumType(type)) { - typing.push(`NexusGenEnums['${type.name}']`) + if (this.typegenInfo.declareInputs) { + typing.push(type.name) + } else { + typing.push(`NexusGenEnums['${type.name}']`) + } } else if (isObjectType(type) || isInterfaceType(type) || isUnionType(type)) { typing.push(`NexusGenRootTypes['${type.name}']`) } @@ -757,9 +848,17 @@ export class TypegenPrinter { } else if (isScalarType(arg)) { typing.push(this.printScalar(arg)) } else if (isEnumType(arg)) { - typing.push(`NexusGenEnums['${arg.name}']`) + if (this.typegenInfo.declareInputs) { + typing.push(arg.name) + } else { + typing.push(`NexusGenEnums['${arg.name}']`) + } } else if (isInputObjectType(arg)) { - typing.push(`NexusGenInputs['${arg.name}']`) + if (this.typegenInfo.declareInputs) { + typing.push(arg.name) + } else { + typing.push(`NexusGenInputs['${arg.name}']`) + } } return typing } @@ -798,8 +897,16 @@ export class TypegenPrinter { printArgTypeFieldInterface(typeMapping: Record) { return [`export interface NexusGenArgTypes {`] .concat( - mapObj(typeMapping, (val, key) => { - return [` ${key}: {`] + mapObj(typeMapping, (val, typeName) => { + if (this.typegenInfo.declareInputs) { + return [` ${typeName}: {`] + .concat( + mapObj(val, (_, fieldName) => ` ${fieldName}: ${this.getArgsName(typeName, fieldName)}`) + ) + .concat(' }') + .join('\n') + } + return [` ${typeName}: {`] .concat(mapObj(val, this.printObj(' ', 'args'))) .concat(' }') .join('\n') diff --git a/src/typegenUtils.ts b/src/typegenUtils.ts index 977656d0..77017b44 100644 --- a/src/typegenUtils.ts +++ b/src/typegenUtils.ts @@ -1,5 +1,6 @@ import * as path from 'path' import type { BuilderConfigInput } from './builder' +import type { ConfiguredTypegen } from './core' import type { TypegenMetadataConfig } from './typegenMetadata' import { assertAbsolutePath, getOwnPackage, isProductionStage } from './utils' @@ -13,7 +14,7 @@ export function resolveTypegenConfig(config: BuilderConfigInput): TypegenMetadat const defaultSDLFilePath = path.join(process.cwd(), 'schema.graphql') - let typegenFilePath: string | null = null + let typegenFilePath: string | ConfiguredTypegen | null = null let sdlFilePath: string | null = null if (outputs === undefined) { @@ -32,6 +33,17 @@ export function resolveTypegenConfig(config: BuilderConfigInput): TypegenMetadat // handle typegen configuration if (typeof outputs.typegen === 'string') { typegenFilePath = assertAbsolutePath(outputs.typegen, 'outputs.typegen') + } else if (typeof outputs.typegen === 'object') { + typegenFilePath = { + ...outputs.typegen, + outputPath: assertAbsolutePath(outputs.typegen.outputPath, 'outputs.typegen.outputPath'), + } as ConfiguredTypegen + if (outputs.typegen.globalsPath) { + typegenFilePath.globalsPath = assertAbsolutePath( + outputs.typegen.globalsPath, + 'outputs.typegen.globalsPath' + ) + } } } else if (outputs !== false) { console.warn( diff --git a/tests/__snapshots__/typegenPrinterGlobals.spec.ts.snap b/tests/__snapshots__/typegenPrinterGlobals.spec.ts.snap new file mode 100644 index 00000000..0b68547d --- /dev/null +++ b/tests/__snapshots__/typegenPrinterGlobals.spec.ts.snap @@ -0,0 +1,513 @@ +// Jest Snapshot v1, https://goo.gl/fbAQLP + +exports[`typegenPrinter: globals should print the full output 1`] = ` +Object { + "globalTypes": "/** + * This file was generated by Nexus Schema + * Do not make changes to this file directly + */ + +import { NexusGenTypes } from './types.gen' + + + + +declare global { + interface NexusGen extends NexusGenTypes {} +} + + +declare global { + interface NexusGenPluginTypeConfig { + } + interface NexusGenPluginInputTypeConfig { + } + interface NexusGenPluginFieldConfig { + } + interface NexusGenPluginInputFieldConfig { + } + interface NexusGenPluginSchemaConfig { + } + interface NexusGenPluginArgConfig { + } +}", + "tsTypes": "/** + * This file was generated by Nexus Schema + * Do not make changes to this file directly + */ + + +import type { TestContext } from \\"./../__helpers/index\\" +import type { core } from \\"nexus\\" + +export interface CreatePostInput { + author: string; // ID! + geo: Array>; // [[Float]!]! + name: string; // String! +} + +export interface PostFilters { + order: OrderEnum; // OrderEnum! + search: string | null; // String +} + +export interface NexusGenInputs { + CreatePostInput: CreatePostInput + PostFilters: PostFilters +} + +export type OrderEnum = \\"ASC\\" | \\"DESC\\" + +export type SomeEnum = \\"A\\" | \\"B\\" + +export interface NexusGenEnums { + OrderEnum: OrderEnum + SomeEnum: SomeEnum +} + +export interface NexusGenScalars { + String: string + Int: number + Float: number + Boolean: boolean + ID: string + UUID: string +} + +export interface NexusGenObjects { + Mutation: {}; + Post: {}; + Query: {}; + User: {}; +} + +export interface NexusGenInterfaces { + Node: core.Discriminate<'Post', 'required'> | core.Discriminate<'User', 'required'>; +} + +export interface NexusGenUnions { + ExampleUnion: core.Discriminate<'Post', 'required'> | core.Discriminate<'User', 'required'>; +} + +export type NexusGenRootTypes = NexusGenInterfaces & NexusGenObjects & NexusGenUnions + +export type NexusGenAllTypes = NexusGenRootTypes & NexusGenScalars & NexusGenEnums + +export interface NexusGenFieldTypes { + Mutation: { // field return type + createPost: NexusGenRootTypes['Post']; // Post! + registerClick: NexusGenRootTypes['Query']; // Query! + someList: Array; // [String]! + } + Post: { // field return type + author: NexusGenRootTypes['User']; // User! + geo: number[][]; // [[Float!]!]! + id: string; // ID! + messyGeo: Array | null; // [[Float!]] + uuid: NexusGenScalars['UUID']; // UUID! + } + Query: { // field return type + posts: NexusGenRootTypes['Post'][]; // [Post!]! + unionField: NexusGenRootTypes['ExampleUnion']; // ExampleUnion! + user: NexusGenRootTypes['User']; // User! + } + User: { // field return type + email: string; // String! + id: string; // ID! + name: string; // String! + outEnum: SomeEnum | null; // SomeEnum + phone: string | null; // String + posts: NexusGenRootTypes['Post'][]; // [Post!]! + } + Node: { // field return type + id: string; // ID! + } +} + +export interface NexusGenFieldTypeNames { + Mutation: { // field return type name + createPost: 'Post' + registerClick: 'Query' + someList: 'String' + } + Post: { // field return type name + author: 'User' + geo: 'Float' + id: 'ID' + messyGeo: 'Float' + uuid: 'UUID' + } + Query: { // field return type name + posts: 'Post' + unionField: 'ExampleUnion' + user: 'User' + } + User: { // field return type name + email: 'String' + id: 'ID' + name: 'String' + outEnum: 'SomeEnum' + phone: 'String' + posts: 'Post' + } + Node: { // field return type name + id: 'ID' + } +} + +export interface MutationCreatePostArgs { + input: CreatePostInput; // CreatePostInput! +} + +export interface MutationRegisterClickArgs { + uuid?: NexusGenScalars['UUID'] | null; // UUID +} + +export interface MutationSomeListArgs { + items: Array; // [String]! +} + +export interface QueryPostsArgs { + filters: PostFilters; // PostFilters! +} + +export interface UserNameArgs { + prefix?: string | null; // String +} + +export interface UserPostsArgs { + filters?: PostFilters | null; // PostFilters +} + +export interface NexusGenArgTypes { + Mutation: { + createPost: MutationCreatePostArgs + registerClick: MutationRegisterClickArgs + someList: MutationSomeListArgs + } + Query: { + posts: QueryPostsArgs + } + User: { + name: UserNameArgs + posts: UserPostsArgs + } +} + +export interface NexusGenAbstractTypeMembers { + ExampleUnion: \\"Post\\" | \\"User\\" + Node: \\"Post\\" | \\"User\\" +} + +export interface NexusGenTypeInterfaces { + Post: \\"Node\\" + User: \\"Node\\" +} + +export type NexusGenObjectNames = keyof NexusGenObjects; + +export type NexusGenInputNames = keyof NexusGenInputs; + +export type NexusGenEnumNames = keyof NexusGenEnums; + +export type NexusGenInterfaceNames = keyof NexusGenInterfaces; + +export type NexusGenScalarNames = keyof NexusGenScalars; + +export type NexusGenUnionNames = keyof NexusGenUnions; + +export type NexusGenObjectsUsingAbstractStrategyIsTypeOf = never; + +export type NexusGenAbstractsUsingStrategyResolveType = never; + +export type NexusGenFeaturesConfig = { + abstractTypeStrategies: { + __typename: true + isTypeOf: false + resolveType: false + } +} + +export interface NexusGenTypes { + context: TestContext; + inputTypes: NexusGenInputs; + rootTypes: NexusGenRootTypes; + inputTypeShapes: NexusGenInputs & NexusGenEnums & NexusGenScalars; + argTypes: NexusGenArgTypes; + fieldTypes: NexusGenFieldTypes; + fieldTypeNames: NexusGenFieldTypeNames; + allTypes: NexusGenAllTypes; + typeInterfaces: NexusGenTypeInterfaces; + objectNames: NexusGenObjectNames; + inputNames: NexusGenInputNames; + enumNames: NexusGenEnumNames; + interfaceNames: NexusGenInterfaceNames; + scalarNames: NexusGenScalarNames; + unionNames: NexusGenUnionNames; + allInputTypes: NexusGenTypes['inputNames'] | NexusGenTypes['enumNames'] | NexusGenTypes['scalarNames']; + allOutputTypes: NexusGenTypes['objectNames'] | NexusGenTypes['enumNames'] | NexusGenTypes['unionNames'] | NexusGenTypes['interfaceNames'] | NexusGenTypes['scalarNames']; + allNamedTypes: NexusGenTypes['allInputTypes'] | NexusGenTypes['allOutputTypes'] + abstractTypes: NexusGenTypes['interfaceNames'] | NexusGenTypes['unionNames']; + abstractTypeMembers: NexusGenAbstractTypeMembers; + objectsUsingAbstractStrategyIsTypeOf: NexusGenObjectsUsingAbstractStrategyIsTypeOf; + abstractsUsingStrategyResolveType: NexusGenAbstractsUsingStrategyResolveType; + features: NexusGenFeaturesConfig; +}", +} +`; + +exports[`typegenPrinter: no input changes should print the full output, with inputs 1`] = ` +"/** + * This file was generated by Nexus Schema + * Do not make changes to this file directly + */ + + +import type { core } from \\"nexus\\" + +export interface CreatePostInput { + name: string; // String! + author: string; // ID! + geo: Array>; // [[Float]!]! +} + +export interface PostFilters { + order: OrderEnum; // OrderEnum! + search: string | null; // String +} + +export interface NexusGenInputs { + CreatePostInput: CreatePostInput + PostFilters: PostFilters +} + +export type OrderEnum = \\"ASC\\" | \\"DESC\\" + +export type SomeEnum = \\"A\\" | \\"B\\" + +export interface NexusGenEnums { + OrderEnum: OrderEnum + SomeEnum: SomeEnum +} + +export interface NexusGenScalars { + String: string + Int: number + Float: number + Boolean: boolean + ID: string + UUID: any +} + +export interface NexusGenObjects { + Mutation: {}; + Post: {}; + Query: {}; + User: {}; +} + +export interface NexusGenInterfaces { + Node: core.Discriminate<'User', 'required'> | core.Discriminate<'Post', 'required'>; +} + +export interface NexusGenUnions { + ExampleUnion: core.Discriminate<'Post', 'required'> | core.Discriminate<'User', 'required'>; +} + +export type NexusGenRootTypes = NexusGenInterfaces & NexusGenObjects & NexusGenUnions + +export type NexusGenAllTypes = NexusGenRootTypes & NexusGenScalars & NexusGenEnums + +export interface NexusGenFieldTypes { + Mutation: { // field return type + someList: Array; // [String]! + createPost: NexusGenRootTypes['Post']; // Post! + registerClick: NexusGenRootTypes['Query']; // Query! + } + Post: { // field return type + id: string; // ID! + uuid: NexusGenScalars['UUID']; // UUID! + author: NexusGenRootTypes['User']; // User! + geo: number[][]; // [[Float!]!]! + messyGeo: Array | null; // [[Float!]] + } + Query: { // field return type + user: NexusGenRootTypes['User']; // User! + posts: NexusGenRootTypes['Post'][]; // [Post!]! + unionField: NexusGenRootTypes['ExampleUnion']; // ExampleUnion! + } + User: { // field return type + id: string; // ID! + name: string; // String! + email: string; // String! + phone: string | null; // String + posts: NexusGenRootTypes['Post'][]; // [Post!]! + outEnum: SomeEnum | null; // SomeEnum + } + Node: { // field return type + id: string; // ID! + } +} + +export interface NexusGenFieldTypeNames { + Mutation: { // field return type name + someList: 'String' + createPost: 'Post' + registerClick: 'Query' + } + Post: { // field return type name + id: 'ID' + uuid: 'UUID' + author: 'User' + geo: 'Float' + messyGeo: 'Float' + } + Query: { // field return type name + user: 'User' + posts: 'Post' + unionField: 'ExampleUnion' + } + User: { // field return type name + id: 'ID' + name: 'String' + email: 'String' + phone: 'String' + posts: 'Post' + outEnum: 'SomeEnum' + } + Node: { // field return type name + id: 'ID' + } +} + +export interface MutationSomeListArgs { + items: Array; // [String]! +} + +export interface MutationCreatePostArgs { + input: CreatePostInput; // CreatePostInput! +} + +export interface MutationRegisterClickArgs { + uuid?: NexusGenScalars['UUID'] | null; // UUID +} + +export interface QueryPostsArgs { + filters: PostFilters; // PostFilters! +} + +export interface UserNameArgs { + prefix?: string | null; // String +} + +export interface UserPostsArgs { + filters?: PostFilters | null; // PostFilters +} + +export interface NexusGenArgTypes { + Mutation: { + someList: MutationSomeListArgs + createPost: MutationCreatePostArgs + registerClick: MutationRegisterClickArgs + } + Query: { + posts: QueryPostsArgs + } + User: { + name: UserNameArgs + posts: UserPostsArgs + } +} + +export interface NexusGenAbstractTypeMembers { + ExampleUnion: \\"Post\\" | \\"User\\" + Node: \\"User\\" | \\"Post\\" +} + +export interface NexusGenTypeInterfaces { + Post: \\"Node\\" + User: \\"Node\\" +} + +export type NexusGenObjectNames = keyof NexusGenObjects; + +export type NexusGenInputNames = keyof NexusGenInputs; + +export type NexusGenEnumNames = keyof NexusGenEnums; + +export type NexusGenInterfaceNames = keyof NexusGenInterfaces; + +export type NexusGenScalarNames = keyof NexusGenScalars; + +export type NexusGenUnionNames = keyof NexusGenUnions; + +export type NexusGenObjectsUsingAbstractStrategyIsTypeOf = never; + +export type NexusGenAbstractsUsingStrategyResolveType = never; + +export type NexusGenFeaturesConfig = { + abstractTypeStrategies: { + __typename: true + isTypeOf: false + resolveType: false + } +} + +export interface NexusGenTypes { + context: any; + inputTypes: NexusGenInputs; + rootTypes: NexusGenRootTypes; + inputTypeShapes: NexusGenInputs & NexusGenEnums & NexusGenScalars; + argTypes: NexusGenArgTypes; + fieldTypes: NexusGenFieldTypes; + fieldTypeNames: NexusGenFieldTypeNames; + allTypes: NexusGenAllTypes; + typeInterfaces: NexusGenTypeInterfaces; + objectNames: NexusGenObjectNames; + inputNames: NexusGenInputNames; + enumNames: NexusGenEnumNames; + interfaceNames: NexusGenInterfaceNames; + scalarNames: NexusGenScalarNames; + unionNames: NexusGenUnionNames; + allInputTypes: NexusGenTypes['inputNames'] | NexusGenTypes['enumNames'] | NexusGenTypes['scalarNames']; + allOutputTypes: NexusGenTypes['objectNames'] | NexusGenTypes['enumNames'] | NexusGenTypes['unionNames'] | NexusGenTypes['interfaceNames'] | NexusGenTypes['scalarNames']; + allNamedTypes: NexusGenTypes['allInputTypes'] | NexusGenTypes['allOutputTypes'] + abstractTypes: NexusGenTypes['interfaceNames'] | NexusGenTypes['unionNames']; + abstractTypeMembers: NexusGenAbstractTypeMembers; + objectsUsingAbstractStrategyIsTypeOf: NexusGenObjectsUsingAbstractStrategyIsTypeOf; + abstractsUsingStrategyResolveType: NexusGenAbstractsUsingStrategyResolveType; + features: NexusGenFeaturesConfig; +}" +`; + +exports[`typegenPrinter: no input changes should print the full output, with inputs 2`] = ` +"/** + * This file was generated by Nexus Schema + * Do not make changes to this file directly + */ + +import { NexusGenTypes } from './types.gen' + + + + +declare global { + interface NexusGen extends NexusGenTypes {} +} + + +declare global { + interface NexusGenPluginTypeConfig { + } + interface NexusGenPluginInputTypeConfig { + } + interface NexusGenPluginFieldConfig { + } + interface NexusGenPluginInputFieldConfig { + } + interface NexusGenPluginSchemaConfig { + } + interface NexusGenPluginArgConfig { + } +}" +`; diff --git a/tests/integrations/declarativeWrappingPlugin/__typegen.ts b/tests/integrations/declarativeWrappingPlugin/__typegen.ts index ffd15fd6..fa540661 100644 --- a/tests/integrations/declarativeWrappingPlugin/__typegen.ts +++ b/tests/integrations/declarativeWrappingPlugin/__typegen.ts @@ -4,11 +4,12 @@ declare global { interface NexusGen extends NexusGenTypes {} } +export interface InlineInputType { + abc: number // Int! +} + export interface NexusGenInputs { - InlineInputType: { - // input type - abc: number // Int! - } + InlineInputType: InlineInputType } export interface NexusGenEnums {} @@ -62,16 +63,18 @@ export interface NexusGenFieldTypeNames { } } +export interface DeclarativeWrappingOutputSomeListOfListsArgs { + int: number // Int! +} + +export interface DeclarativeWrappingOutputSomeNullFieldArgs { + input?: InlineInputType | null // InlineInputType +} + export interface NexusGenArgTypes { DeclarativeWrappingOutput: { - someListOfLists: { - // args - int: number // Int! - } - someNullField: { - // args - input?: NexusGenInputs['InlineInputType'] | null // InlineInputType - } + someListOfLists: DeclarativeWrappingOutputSomeListOfListsArgs + someNullField: DeclarativeWrappingOutputSomeNullFieldArgs } } diff --git a/tests/integrations/kitchenSink/__typegen.ts b/tests/integrations/kitchenSink/__typegen.ts index b250dfcb..463fb191 100644 --- a/tests/integrations/kitchenSink/__typegen.ts +++ b/tests/integrations/kitchenSink/__typegen.ts @@ -45,20 +45,24 @@ declare global { interface NexusGen extends NexusGenTypes {} } +export interface PostSearchInput { + body?: string | null // String + title?: string | null // String +} + +export interface Something { + id: number // Int! +} + export interface NexusGenInputs { - PostSearchInput: { - // input type - body?: string | null // String - title?: string | null // String - } - Something: { - // input type - id: number // Int! - } + PostSearchInput: PostSearchInput + Something: Something } +export type UserStatus = 'active' | 'pending' + export interface NexusGenEnums { - UserStatus: 'active' | 'pending' + UserStatus: UserStatus } export interface NexusGenScalars { @@ -257,39 +261,44 @@ export interface NexusGenFieldTypeNames { } } +export interface MutationCreateUserArgs { + firstName?: string | null // String + lastName?: string | null // String +} + +export interface PostEdgeDeltaArgs { + format?: string | null // String +} + +export interface QuerySearchPostsArgs { + input?: PostSearchInput | null // PostSearchInput +} + +export interface QueryUserArgs { + id?: string | null // ID + status: UserStatus | null // UserStatus +} + +export interface UserPostsArgs { + after?: string | null // String + before?: string | null // String + first?: number | null // Int + last?: number | null // Int +} + export interface NexusGenArgTypes { Mutation: { - createUser: { - // args - firstName?: string | null // String - lastName?: string | null // String - } + createUser: MutationCreateUserArgs } PostEdge: { - delta: { - // args - format?: string | null // String - } + delta: PostEdgeDeltaArgs } Query: { - searchPosts: { - // args - input?: NexusGenInputs['PostSearchInput'] | null // PostSearchInput - } - user: { - // args - id?: string | null // ID - status: NexusGenEnums['UserStatus'] | null // UserStatus - } + searchPosts: QuerySearchPostsArgs + user: QueryUserArgs } User: { - posts: { - // args - after?: string | null // String - before?: string | null // String - first?: number | null // Int - last?: number | null // Int - } + posts: UserPostsArgs } } diff --git a/tests/typegen-globals/global-types.gen.ts b/tests/typegen-globals/global-types.gen.ts new file mode 100644 index 00000000..72e3bab8 --- /dev/null +++ b/tests/typegen-globals/global-types.gen.ts @@ -0,0 +1,16 @@ +/** This file was generated by Nexus Schema Do not make changes to this file directly */ + +import { NexusGenTypes } from './types.gen' + +declare global { + interface NexusGen extends NexusGenTypes {} +} + +declare global { + interface NexusGenPluginTypeConfig {} + interface NexusGenPluginInputTypeConfig {} + interface NexusGenPluginFieldConfig {} + interface NexusGenPluginInputFieldConfig {} + interface NexusGenPluginSchemaConfig {} + interface NexusGenPluginArgConfig {} +} diff --git a/tests/typegen-globals/schema.gen.graphql b/tests/typegen-globals/schema.gen.graphql new file mode 100644 index 00000000..c61a8dd1 --- /dev/null +++ b/tests/typegen-globals/schema.gen.graphql @@ -0,0 +1,75 @@ +### This file was generated by Nexus Schema +### Do not make changes to this file directly + +input CreatePostInput { + author: ID! + geo: [[Float]!]! + name: String! +} + +union ExampleUnion = Post | User + +type Mutation { + createPost(input: CreatePostInput!): Post! + registerClick(uuid: UUID): Query! + someList(items: [String]!): [String]! +} + +""" +This is a description of a Node +""" +interface Node { + id: ID! +} + +enum OrderEnum { + ASC + DESC +} + +""" +This is a description of a Post +""" +type Post implements Node { + author: User! + geo: [[Float!]!]! + id: ID! + messyGeo: [[Float!]] + uuid: UUID! +} + +input PostFilters { + order: OrderEnum! + search: String = "nexus" +} + +type Query { + posts(filters: PostFilters!): [Post!]! + unionField: ExampleUnion! + user: User! +} + +enum SomeEnum { + A + B @deprecated(reason: "This is a deprecation reason for B") +} + +type User implements Node { + email: String! + id: ID! + + """ + This is a description of a name + """ + name( + """ + And a description of an arg + """ + prefix: String + ): String! + outEnum: SomeEnum + phone: String + posts(filters: PostFilters): [Post!]! +} + +scalar UUID diff --git a/tests/typegen-globals/types.gen.ts b/tests/typegen-globals/types.gen.ts new file mode 100644 index 00000000..855a40f4 --- /dev/null +++ b/tests/typegen-globals/types.gen.ts @@ -0,0 +1,232 @@ +/** This file was generated by Nexus Schema Do not make changes to this file directly */ + +import type { core } from '../../src' + +export interface CreatePostInput { + author: string // ID! + geo: Array> // [[Float]!]! + name: string // String! +} + +export interface PostFilters { + order: OrderEnum // OrderEnum! + search: string | null // String +} + +export interface NexusGenInputs { + CreatePostInput: CreatePostInput + PostFilters: PostFilters +} + +export type OrderEnum = 'ASC' | 'DESC' + +export type SomeEnum = 'A' | 'B' + +export interface NexusGenEnums { + OrderEnum: OrderEnum + SomeEnum: SomeEnum +} + +export interface NexusGenScalars { + String: string + Int: number + Float: number + Boolean: boolean + ID: string + UUID: any +} + +export interface NexusGenObjects { + Mutation: {} + Post: {} + Query: {} + User: {} +} + +export interface NexusGenInterfaces { + Node: core.Discriminate<'Post', 'required'> | core.Discriminate<'User', 'required'> +} + +export interface NexusGenUnions { + ExampleUnion: core.Discriminate<'Post', 'required'> | core.Discriminate<'User', 'required'> +} + +export type NexusGenRootTypes = NexusGenInterfaces & NexusGenObjects & NexusGenUnions + +export type NexusGenAllTypes = NexusGenRootTypes & NexusGenScalars & NexusGenEnums + +export interface NexusGenFieldTypes { + Mutation: { + // field return type + createPost: NexusGenRootTypes['Post'] // Post! + registerClick: NexusGenRootTypes['Query'] // Query! + someList: Array // [String]! + } + Post: { + // field return type + author: NexusGenRootTypes['User'] // User! + geo: number[][] // [[Float!]!]! + id: string // ID! + messyGeo: Array | null // [[Float!]] + uuid: NexusGenScalars['UUID'] // UUID! + } + Query: { + // field return type + posts: NexusGenRootTypes['Post'][] // [Post!]! + unionField: NexusGenRootTypes['ExampleUnion'] // ExampleUnion! + user: NexusGenRootTypes['User'] // User! + } + User: { + // field return type + email: string // String! + id: string // ID! + name: string // String! + outEnum: SomeEnum | null // SomeEnum + phone: string | null // String + posts: NexusGenRootTypes['Post'][] // [Post!]! + } + Node: { + // field return type + id: string // ID! + } +} + +export interface NexusGenFieldTypeNames { + Mutation: { + // field return type name + createPost: 'Post' + registerClick: 'Query' + someList: 'String' + } + Post: { + // field return type name + author: 'User' + geo: 'Float' + id: 'ID' + messyGeo: 'Float' + uuid: 'UUID' + } + Query: { + // field return type name + posts: 'Post' + unionField: 'ExampleUnion' + user: 'User' + } + User: { + // field return type name + email: 'String' + id: 'ID' + name: 'String' + outEnum: 'SomeEnum' + phone: 'String' + posts: 'Post' + } + Node: { + // field return type name + id: 'ID' + } +} + +export interface MutationCreatePostArgs { + input: CreatePostInput // CreatePostInput! +} + +export interface MutationRegisterClickArgs { + uuid?: NexusGenScalars['UUID'] | null // UUID +} + +export interface MutationSomeListArgs { + items: Array // [String]! +} + +export interface QueryPostsArgs { + filters: PostFilters // PostFilters! +} + +export interface UserNameArgs { + prefix?: string | null // String +} + +export interface UserPostsArgs { + filters?: PostFilters | null // PostFilters +} + +export interface NexusGenArgTypes { + Mutation: { + createPost: MutationCreatePostArgs + registerClick: MutationRegisterClickArgs + someList: MutationSomeListArgs + } + Query: { + posts: QueryPostsArgs + } + User: { + name: UserNameArgs + posts: UserPostsArgs + } +} + +export interface NexusGenAbstractTypeMembers { + ExampleUnion: 'Post' | 'User' + Node: 'Post' | 'User' +} + +export interface NexusGenTypeInterfaces { + Post: 'Node' + User: 'Node' +} + +export type NexusGenObjectNames = keyof NexusGenObjects + +export type NexusGenInputNames = keyof NexusGenInputs + +export type NexusGenEnumNames = keyof NexusGenEnums + +export type NexusGenInterfaceNames = keyof NexusGenInterfaces + +export type NexusGenScalarNames = keyof NexusGenScalars + +export type NexusGenUnionNames = keyof NexusGenUnions + +export type NexusGenObjectsUsingAbstractStrategyIsTypeOf = never + +export type NexusGenAbstractsUsingStrategyResolveType = never + +export type NexusGenFeaturesConfig = { + abstractTypeStrategies: { + __typename: true + isTypeOf: false + resolveType: false + } +} + +export interface NexusGenTypes { + context: any + inputTypes: NexusGenInputs + rootTypes: NexusGenRootTypes + inputTypeShapes: NexusGenInputs & NexusGenEnums & NexusGenScalars + argTypes: NexusGenArgTypes + fieldTypes: NexusGenFieldTypes + fieldTypeNames: NexusGenFieldTypeNames + allTypes: NexusGenAllTypes + typeInterfaces: NexusGenTypeInterfaces + objectNames: NexusGenObjectNames + inputNames: NexusGenInputNames + enumNames: NexusGenEnumNames + interfaceNames: NexusGenInterfaceNames + scalarNames: NexusGenScalarNames + unionNames: NexusGenUnionNames + allInputTypes: NexusGenTypes['inputNames'] | NexusGenTypes['enumNames'] | NexusGenTypes['scalarNames'] + allOutputTypes: + | NexusGenTypes['objectNames'] + | NexusGenTypes['enumNames'] + | NexusGenTypes['unionNames'] + | NexusGenTypes['interfaceNames'] + | NexusGenTypes['scalarNames'] + allNamedTypes: NexusGenTypes['allInputTypes'] | NexusGenTypes['allOutputTypes'] + abstractTypes: NexusGenTypes['interfaceNames'] | NexusGenTypes['unionNames'] + abstractTypeMembers: NexusGenAbstractTypeMembers + objectsUsingAbstractStrategyIsTypeOf: NexusGenObjectsUsingAbstractStrategyIsTypeOf + abstractsUsingStrategyResolveType: NexusGenAbstractsUsingStrategyResolveType + features: NexusGenFeaturesConfig +} diff --git a/tests/typegen/types.gen.ts b/tests/typegen/types.gen.ts index bdca6f81..f1665802 100644 --- a/tests/typegen/types.gen.ts +++ b/tests/typegen/types.gen.ts @@ -6,23 +6,29 @@ declare global { interface NexusGen extends NexusGenTypes {} } +export interface CreatePostInput { + author: string // ID! + geo: Array> // [[Float]!]! + name: string // String! +} + +export interface PostFilters { + order: OrderEnum // OrderEnum! + search: string | null // String +} + export interface NexusGenInputs { - CreatePostInput: { - // input type - author: string // ID! - geo: Array> // [[Float]!]! - name: string // String! - } - PostFilters: { - // input type - order: NexusGenEnums['OrderEnum'] // OrderEnum! - search: string | null // String - } + CreatePostInput: CreatePostInput + PostFilters: PostFilters } +export type OrderEnum = 'ASC' | 'DESC' + +export type SomeEnum = 'A' | 'B' + export interface NexusGenEnums { - OrderEnum: 'ASC' | 'DESC' - SomeEnum: 'A' | 'B' + OrderEnum: OrderEnum + SomeEnum: SomeEnum } export interface NexusGenScalars { @@ -79,7 +85,7 @@ export interface NexusGenFieldTypes { email: string // String! id: string // ID! name: string // String! - outEnum: NexusGenEnums['SomeEnum'] | null // SomeEnum + outEnum: SomeEnum | null // SomeEnum phone: string | null // String posts: NexusGenRootTypes['Post'][] // [Post!]! } @@ -125,36 +131,42 @@ export interface NexusGenFieldTypeNames { } } +export interface MutationCreatePostArgs { + input: CreatePostInput // CreatePostInput! +} + +export interface MutationRegisterClickArgs { + uuid?: NexusGenScalars['UUID'] | null // UUID +} + +export interface MutationSomeListArgs { + items: Array // [String]! +} + +export interface QueryPostsArgs { + filters: PostFilters // PostFilters! +} + +export interface UserNameArgs { + prefix?: string | null // String +} + +export interface UserPostsArgs { + filters?: PostFilters | null // PostFilters +} + export interface NexusGenArgTypes { Mutation: { - createPost: { - // args - input: NexusGenInputs['CreatePostInput'] // CreatePostInput! - } - registerClick: { - // args - uuid?: NexusGenScalars['UUID'] | null // UUID - } - someList: { - // args - items: Array // [String]! - } + createPost: MutationCreatePostArgs + registerClick: MutationRegisterClickArgs + someList: MutationSomeListArgs } Query: { - posts: { - // args - filters: NexusGenInputs['PostFilters'] // PostFilters! - } + posts: QueryPostsArgs } User: { - name: { - // args - prefix?: string | null // String - } - posts: { - // args - filters?: NexusGenInputs['PostFilters'] | null // PostFilters - } + name: UserNameArgs + posts: UserPostsArgs } } diff --git a/tests/typegenPrinterGlobals.spec.ts b/tests/typegenPrinterGlobals.spec.ts new file mode 100644 index 00000000..f86b7e94 --- /dev/null +++ b/tests/typegenPrinterGlobals.spec.ts @@ -0,0 +1,118 @@ +import { buildSchema } from 'graphql' +import * as path from 'path' +import { core } from '../src' +import { generateSchema, NexusGraphQLSchema, typegenFormatPrettier } from '../src/core' +import { EXAMPLE_SDL } from './_sdl' + +const { TypegenPrinter, TypegenMetadata } = core + +describe('typegenPrinter: globals', () => { + let typegen: core.TypegenPrinter + let metadata: core.TypegenMetadata + beforeEach(async () => { + const outputs = { + typegen: { + outputPath: path.join(__dirname, 'typegen-globals/types.gen.ts'), + globalsPath: path.join(__dirname, 'typegen-globals/global-types.gen.ts'), + declareInputs: true, + }, + schema: path.join(__dirname, 'typegen-globals/schema.gen.graphql'), + } as const + + const schema = (await generateSchema({ + outputs, + shouldGenerateArtifacts: true, + types: [buildSchema(EXAMPLE_SDL)], + // __typename put to true to prevent from erroring because of missing resolveType + features: { + abstractTypeStrategies: { + __typename: true, + }, + }, + async formatTypegen(source, type) { + const prettierConfigPath = require.resolve('../.prettierrc') + const content = await typegenFormatPrettier(prettierConfigPath)(source, type) + + return content.replace("'nexus'", `'../../src'`) + }, + })) as core.NexusGraphQLSchema + + metadata = new TypegenMetadata({ + outputs, + sourceTypes: { + modules: [ + { + module: path.join(__dirname, '__helpers/index.ts'), + alias: 't', + }, + ], + mapping: { + UUID: 'string', + }, + }, + contextType: { + module: path.join(__dirname, '__helpers/index.ts'), + export: 'TestContext', + }, + }) + + const typegenInfo = await metadata.getTypegenInfo(schema) + + const { outputPath, ...rest } = outputs.typegen + + typegen = new TypegenPrinter(metadata.sortSchema(schema), { + ...typegenInfo, + ...rest, + typegenPath: outputPath, + }) + }) + + afterEach(() => { + jest.clearAllMocks() + }) + + it('should print the full output', () => { + expect(typegen.printConfigured()).toMatchSnapshot() + }) +}) + +describe('typegenPrinter: no input changes', () => { + let out: { + schema: NexusGraphQLSchema + schemaTypes: string + tsTypes: string + globalTypes: string | null + } + beforeEach(async () => { + const typegen = { + outputPath: path.join(__dirname, 'typegen-globals/types.gen.ts'), + globalsPath: path.join(__dirname, 'typegen-globals/global-types.gen.ts'), + } as const + out = await generateSchema.withArtifacts( + { + outputs: { + typegen, + schema: path.join(__dirname, 'typegen-globals/schema.gen.graphql'), + }, + shouldGenerateArtifacts: true, + types: [buildSchema(EXAMPLE_SDL)], + // __typename put to true to prevent from erroring because of missing resolveType + features: { + abstractTypeStrategies: { + __typename: true, + }, + }, + }, + typegen + ) + }) + + afterEach(() => { + jest.clearAllMocks() + }) + + it('should print the full output, with inputs', () => { + expect(out.tsTypes).toMatchSnapshot() + expect(out.globalTypes).toMatchSnapshot() + }) +}) From 380ed9d4ca1089b3cc76660cd43fc637e43d367d Mon Sep 17 00:00:00 2001 From: Tim Griesser Date: Tue, 17 Aug 2021 19:35:56 -0400 Subject: [PATCH 04/10] fix: correct imports for changes in #967 (#968) * fix: correct imports for changes in #967 --- examples/kitchen-sink/src/index.ts | 5 +- .../src/kitchen-sink-globals.gen.ts | 65 ++++ examples/kitchen-sink/src/kitchen-sink.gen.ts | 360 ++++++------------ patches/prettier-plugin-jsdoc+0.2.5.patch | 13 - src/typegenPrinter.ts | 185 +++++---- .../typegenPrinterGlobals.spec.ts.snap | 8 +- tests/backingTypes.spec.ts | 2 + tests/typegen-globals/global-types.gen.ts | 2 +- tests/typegenPrinter.spec.ts | 14 + 9 files changed, 305 insertions(+), 349 deletions(-) create mode 100644 examples/kitchen-sink/src/kitchen-sink-globals.gen.ts delete mode 100644 patches/prettier-plugin-jsdoc+0.2.5.patch diff --git a/examples/kitchen-sink/src/index.ts b/examples/kitchen-sink/src/index.ts index b40611db..4ba4b6b1 100644 --- a/examples/kitchen-sink/src/index.ts +++ b/examples/kitchen-sink/src/index.ts @@ -21,7 +21,10 @@ const schema = makeSchema({ types, outputs: { schema: path.join(__dirname, '../kitchen-sink-schema.graphql'), - typegen: path.join(__dirname, './kitchen-sink.gen.ts'), + typegen: { + outputPath: path.join(__dirname, './kitchen-sink.gen.ts'), + globalsPath: path.join(__dirname, './kitchen-sink-globals.gen.ts'), + }, }, plugins: [ NodePlugin, diff --git a/examples/kitchen-sink/src/kitchen-sink-globals.gen.ts b/examples/kitchen-sink/src/kitchen-sink-globals.gen.ts new file mode 100644 index 00000000..d929771e --- /dev/null +++ b/examples/kitchen-sink/src/kitchen-sink-globals.gen.ts @@ -0,0 +1,65 @@ +/** This file was generated by Nexus Schema Do not make changes to this file directly */ + +import type { NexusGenTypes } from './kitchen-sink.gen' +declare global { + interface NexusGenCustomInputMethods { + date( + fieldName: FieldName, + opts?: core.CommonInputFieldConfig + ): void // "Date"; + } +} +declare global { + interface NexusGenCustomOutputMethods { + date( + fieldName: FieldName, + ...opts: core.ScalarOutSpread + ): void // "Date"; + /** + * Adds a Relay-style connection to the type, with numerous options for configuration + * + * @see https://nexusjs.org/docs/plugins/connection + */ + connectionField( + fieldName: FieldName, + config: connectionPluginCore.ConnectionFieldConfig + ): void + } +} + +declare global { + interface NexusGen extends NexusGenTypes {} +} + +import type { core, connectionPluginCore } from 'nexus' +import type { QueryComplexity } from 'nexus/dist/plugins/queryComplexityPlugin' +import type { FieldAuthorizeResolver } from 'nexus/dist/plugins/fieldAuthorizePlugin' + +declare global { + interface NexusGenPluginTypeConfig { + node?: string | core.FieldResolver + } + interface NexusGenPluginInputTypeConfig {} + interface NexusGenPluginFieldConfig { + /** + * The complexity for an individual field. Return a number or a function that returns a number to specify + * the complexity for this field. + */ + complexity?: QueryComplexity + /** + * Authorization for an individual field. Returning "true" or "Promise" means the field can be + * accessed. Returning "false" or "Promise" will respond with a "Not Authorized" error for the + * field. Returning or throwing an error will also prevent the resolver from executing. + */ + authorize?: FieldAuthorizeResolver + /** + * The nullability guard can be helpful, but is also a potentially expensive operation for lists. We need + * to iterate the entire list to check for null items to guard against. Set this to true to skip the null + * guard on a specific field if you know there's no potential for unsafe types. + */ + skipNullGuard?: boolean + } + interface NexusGenPluginInputFieldConfig {} + interface NexusGenPluginSchemaConfig {} + interface NexusGenPluginArgConfig {} +} diff --git a/examples/kitchen-sink/src/kitchen-sink.gen.ts b/examples/kitchen-sink/src/kitchen-sink.gen.ts index 9634b164..7a91ff18 100644 --- a/examples/kitchen-sink/src/kitchen-sink.gen.ts +++ b/examples/kitchen-sink/src/kitchen-sink.gen.ts @@ -1,61 +1,34 @@ /** This file was generated by Nexus Schema Do not make changes to this file directly */ -import { UnusedInterfaceTypeDef } from './kitchen-sink-definitions' -import { core, connectionPluginCore } from 'nexus' -import { QueryComplexity } from 'nexus/dist/plugins/queryComplexityPlugin' -import { FieldAuthorizeResolver } from 'nexus/dist/plugins/fieldAuthorizePlugin' -declare global { - interface NexusGenCustomInputMethods { - date( - fieldName: FieldName, - opts?: core.CommonInputFieldConfig - ): void // "Date"; - } -} -declare global { - interface NexusGenCustomOutputMethods { - date( - fieldName: FieldName, - ...opts: core.ScalarOutSpread - ): void // "Date"; - /** - * Adds a Relay-style connection to the type, with numerous options for configuration - * - * @see https://nexusjs.org/docs/plugins/connection - */ - connectionField( - fieldName: FieldName, - config: connectionPluginCore.ConnectionFieldConfig - ): void - } -} - -declare global { - interface NexusGen extends NexusGenTypes {} +import type { UnusedInterfaceTypeDef } from './kitchen-sink-definitions' +import type { core } from 'nexus' + +export interface InputType { + answer?: number | null // Int + key: string // String! + nestedInput?: InputType2 | null // InputType2 +} + +export interface InputType2 { + answer?: number | null // Int + key: string // String! + someDate: NexusGenScalars['Date'] // Date! +} + +export interface NestedType { + veryNested?: string | null // String +} + +export interface SomeArg { + arg?: NestedType | null // NestedType + someField?: string | null // String } export interface NexusGenInputs { - InputType: { - // input type - answer?: number | null // Int - key: string // String! - nestedInput?: NexusGenInputs['InputType2'] | null // InputType2 - } - InputType2: { - // input type - answer?: number | null // Int - key: string // String! - someDate: NexusGenScalars['Date'] // Date! - } - NestedType: { - // input type - veryNested?: string | null // String - } - SomeArg: { - // input type - arg?: NexusGenInputs['NestedType'] | null // NestedType - someField?: string | null // String - } + InputType: InputType + InputType2: InputType2 + NestedType: NestedType + SomeArg: SomeArg } export interface NexusGenEnums {} @@ -390,100 +363,117 @@ export interface NexusGenFieldTypeNames { } } +export interface FooArgsTestArgs { + a: InputType | null // InputType +} + +export interface MutationSomeMutationFieldArgs { + id: string // ID! +} + +export interface QueryAsArgExampleArgs { + testAsArg: InputType // InputType! +} + +export interface QueryBooleanConnectionArgs { + after?: string | null // String + first: number // Int! +} + +export interface QueryComplexQueryArgs { + count: number // Int! +} + +export interface QueryDeprecatedConnectionArgs { + after?: string | null // String + before?: string | null // String + first?: number | null // Int + last?: number | null // Int +} + +export interface QueryGetNumberOrNullArgs { + a: number // Int! +} + +export interface QueryGuardedConnectionArgs { + after?: string | null // String + first: number // Int! +} + +export interface QueryInlineArgsArgs { + someArg?: SomeArg | null // SomeArg +} + +export interface QueryInputAsArgExampleArgs { + testInput?: InputType | null // InputType + testScalar?: string | null // String +} + +export interface QueryUserConnectionAdditionalArgsArgs { + after?: string | null // String + first: number // Int! + isEven?: boolean | null // Boolean +} + +export interface QueryUserConnectionBackwardOnlyArgs { + before?: string | null // String + last: number // Int! +} + +export interface QueryUserConnectionForwardOnlyArgs { + after?: string | null // String + first: number // Int! +} + +export interface QueryUsersConnectionNodesArgs { + after?: string | null // String + before?: string | null // String + first?: number | null // Int + last?: number | null // Int +} + +export interface QueryUsersConnectionResolveArgs { + after?: string | null // String + before?: string | null // String + first?: number | null // Int + last?: number | null // Int +} + +export interface TestObjArgsTestArgs { + a: InputType | null // InputType +} + +export interface BarArgsTestArgs { + a: InputType | null // InputType +} + export interface NexusGenArgTypes { Foo: { - argsTest: { - // args - a: NexusGenInputs['InputType'] | null // InputType - } + argsTest: FooArgsTestArgs } Mutation: { - someMutationField: { - // args - id: string // ID! - } + someMutationField: MutationSomeMutationFieldArgs } Query: { - asArgExample: { - // args - testAsArg: NexusGenInputs['InputType'] // InputType! - } - booleanConnection: { - // args - after?: string | null // String - first: number // Int! - } - complexQuery: { - // args - count: number // Int! - } - deprecatedConnection: { - // args - after?: string | null // String - before?: string | null // String - first?: number | null // Int - last?: number | null // Int - } - getNumberOrNull: { - // args - a: number // Int! - } - guardedConnection: { - // args - after?: string | null // String - first: number // Int! - } - inlineArgs: { - // args - someArg?: NexusGenInputs['SomeArg'] | null // SomeArg - } - inputAsArgExample: { - // args - testInput?: NexusGenInputs['InputType'] | null // InputType - testScalar?: string | null // String - } - userConnectionAdditionalArgs: { - // args - after?: string | null // String - first: number // Int! - isEven?: boolean | null // Boolean - } - userConnectionBackwardOnly: { - // args - before?: string | null // String - last: number // Int! - } - userConnectionForwardOnly: { - // args - after?: string | null // String - first: number // Int! - } - usersConnectionNodes: { - // args - after?: string | null // String - before?: string | null // String - first?: number | null // Int - last?: number | null // Int - } - usersConnectionResolve: { - // args - after?: string | null // String - before?: string | null // String - first?: number | null // Int - last?: number | null // Int - } + asArgExample: QueryAsArgExampleArgs + booleanConnection: QueryBooleanConnectionArgs + complexQuery: QueryComplexQueryArgs + deprecatedConnection: QueryDeprecatedConnectionArgs + getNumberOrNull: QueryGetNumberOrNullArgs + guardedConnection: QueryGuardedConnectionArgs + inlineArgs: QueryInlineArgsArgs + inputAsArgExample: QueryInputAsArgExampleArgs + userConnectionAdditionalArgs: QueryUserConnectionAdditionalArgsArgs + userConnectionBackwardOnly: QueryUserConnectionBackwardOnlyArgs + userConnectionForwardOnly: QueryUserConnectionForwardOnlyArgs + usersConnectionNodes: QueryUsersConnectionNodesArgs + usersConnectionResolve: QueryUsersConnectionResolveArgs } TestObj: { - argsTest: { - // args - a: NexusGenInputs['InputType'] | null // InputType - } + argsTest: TestObjArgsTestArgs } Bar: { - argsTest: { - // args - a: NexusGenInputs['InputType'] | null // InputType - } + argsTest: BarArgsTestArgs } } @@ -554,99 +544,3 @@ export interface NexusGenTypes { abstractsUsingStrategyResolveType: NexusGenAbstractsUsingStrategyResolveType features: NexusGenFeaturesConfig } - -declare global { - interface NexusGenPluginTypeConfig { - node?: string | core.FieldResolver - } - interface NexusGenPluginFieldConfig { - /** - * The complexity for an individual field. Return a number or a function that returns a number to specify - * the complexity for this field. - */ - complexity?: QueryComplexity - /** - * Authorization for an individual field. Returning "true" or "Promise" means the field can be - * accessed. Returning "false" or "Promise" will respond with a "Not Authorized" error for the - * field. Returning or throwing an error will also prevent the resolver from executing. - */ - authorize?: FieldAuthorizeResolver - /** - * The nullability guard can be helpful, but is also a potentially expensive operation for lists. We need - * to iterate the entire list to check for null items to guard against. Set this to true to skip the null - * guard on a specific field if you know there's no potential for unsafe types. - */ - skipNullGuard?: boolean - /** - * Whether the type can be null - * - * @default (depends on whether nullability is configured in type or schema) - * @see declarativeWrappingPlugin - */ - nullable?: boolean - /** - * Whether the type is list of values, or just a single value. If list is true, we assume the type is a - * list. If list is an array, we'll assume that it's a list with the depth. The boolean indicates whether - * the type is required (non-null), where true = nonNull, false = nullable. - * - * @see declarativeWrappingPlugin - */ - list?: true | boolean[] - /** - * Whether the type should be non null, `required: true` = `nullable: false` - * - * @default (depends on whether nullability is configured in type or schema) - * @see declarativeWrappingPlugin - */ - required?: boolean - } - interface NexusGenPluginInputFieldConfig { - /** - * Whether the type can be null - * - * @default (depends on whether nullability is configured in type or schema) - * @see declarativeWrappingPlugin - */ - nullable?: boolean - /** - * Whether the type is list of values, or just a single value. If list is true, we assume the type is a - * list. If list is an array, we'll assume that it's a list with the depth. The boolean indicates whether - * the type is required (non-null), where true = nonNull, false = nullable. - * - * @see declarativeWrappingPlugin - */ - list?: true | boolean[] - /** - * Whether the type should be non null, `required: true` = `nullable: false` - * - * @default (depends on whether nullability is configured in type or schema) - * @see declarativeWrappingPlugin - */ - required?: boolean - } - interface NexusGenPluginSchemaConfig {} - interface NexusGenPluginArgConfig { - /** - * Whether the type can be null - * - * @default (depends on whether nullability is configured in type or schema) - * @see declarativeWrappingPlugin - */ - nullable?: boolean - /** - * Whether the type is list of values, or just a single value. If list is true, we assume the type is a - * list. If list is an array, we'll assume that it's a list with the depth. The boolean indicates whether - * the type is required (non-null), where true = nonNull, false = nullable. - * - * @see declarativeWrappingPlugin - */ - list?: true | boolean[] - /** - * Whether the type should be non null, `required: true` = `nullable: false` - * - * @default (depends on whether nullability is configured in type or schema) - * @see declarativeWrappingPlugin - */ - required?: boolean - } -} diff --git a/patches/prettier-plugin-jsdoc+0.2.5.patch b/patches/prettier-plugin-jsdoc+0.2.5.patch deleted file mode 100644 index 0b2d5ec5..00000000 --- a/patches/prettier-plugin-jsdoc+0.2.5.patch +++ /dev/null @@ -1,13 +0,0 @@ -diff --git a/node_modules/prettier-plugin-jsdoc/lib/parser.js b/node_modules/prettier-plugin-jsdoc/lib/parser.js -index 85b9e5d..3b98730 100644 ---- a/node_modules/prettier-plugin-jsdoc/lib/parser.js -+++ b/node_modules/prettier-plugin-jsdoc/lib/parser.js -@@ -12,7 +12,7 @@ const stringify_1 = require("./stringify"); - /** @link https://prettier.io/docs/en/api.html#custom-parser-api} */ - exports.getParser = (parser) => function jsdocParser(text, parsers, options) { - const ast = parser(text, parsers, options); -- if (!options.jsdocParser) { -+ if (!options || !options.jsdocParser) { - return ast; - } - /** diff --git a/src/typegenPrinter.ts b/src/typegenPrinter.ts index 8e602d7f..1795ca69 100644 --- a/src/typegenPrinter.ts +++ b/src/typegenPrinter.ts @@ -71,9 +71,9 @@ interface TypegenInfoWithFile extends TypegenInfo { * - Non-scalar types will get a dedicated "Root" type associated with it */ export class TypegenPrinter { - groupedTypes: GroupedTypes - printImports: Record> - hasDiscriminatedTypes: boolean + private groupedTypes: GroupedTypes + private printImports: Record> + private hasDiscriminatedTypes: boolean constructor(protected schema: NexusGraphQLSchema, protected typegenInfo: TypegenInfoWithFile) { this.groupedTypes = groupTypes(schema) @@ -88,9 +88,14 @@ export class TypegenPrinter { printConfigured() { if (this.typegenInfo.globalsPath) { + const plugins = this.printPlugins() + const globalTypes = [this.printHeadersGlobal(), this.printDynamicImport(true), plugins].join('\n\n') + + // Reset printImports for the imports needed in the types + this.printImports = {} + const common = this.printCommon() const tsTypes = [this.printHeadersCommon(), common].join('\n\n') - const globalTypes = [this.printHeadersGlobal(), this.printPlugins()].join('\n\n') return { tsTypes, globalTypes, @@ -130,7 +135,7 @@ export class TypegenPrinter { ].join('\n\n') } - printHeaders() { + private printHeaders() { return [this.printHeadersCommon(), this.printHeadersGlobal()].join('\n') } @@ -152,7 +157,7 @@ export class TypegenPrinter { if (this.typegenInfo.globalsPath) { headers.unshift( - `import { NexusGenTypes } from '${relativePathTo( + `import type { NexusGenTypes } from '${relativePathTo( this.typegenInfo.typegenPath, this.typegenInfo.globalsPath ?? '' )}'` @@ -163,7 +168,7 @@ export class TypegenPrinter { return headers.join('\n') } - printGenTypeMap() { + private printGenTypeMap() { return [`export interface NexusGenTypes {`] .concat([ ` context: ${this.printContext()};`, @@ -194,7 +199,7 @@ export class TypegenPrinter { .join('\n') } - printDynamicImport() { + private printDynamicImport(forGlobal = false) { const { rootTypings, dynamicFields: { dynamicInputFields, dynamicOutputFields }, @@ -226,15 +231,18 @@ export class TypegenPrinter { ) } - eachObj(rootTypings, (rootType, typeName) => { - if (typeof rootType !== 'string') { - const importPath = resolveImportPath(rootType, typeName, outputPath) - importMap[importPath] = importMap[importPath] || new Set() - importMap[importPath].add( - rootType.alias ? `${rootType.export} as ${rootType.alias}` : rootType.export - ) - } - }) + if (!forGlobal) { + eachObj(rootTypings, (rootType, typeName) => { + if (typeof rootType !== 'string') { + const importPath = resolveImportPath(rootType, typeName, outputPath) + importMap[importPath] = importMap[importPath] || new Set() + importMap[importPath].add( + rootType.alias ? `${rootType.export} as ${rootType.alias}` : rootType.export + ) + } + }) + } + eachObj(importMap, (val, key) => { imports.push(`import type { ${Array.from(val).join(', ')} } from ${JSON.stringify(key)}`) }) @@ -256,7 +264,7 @@ export class TypegenPrinter { return imports.join('\n') } - printDynamicInputFieldDefinitions() { + private printDynamicInputFieldDefinitions() { const { dynamicInputFields } = this.schema.extensions.nexus.config.dynamicFields // If there is nothing custom... exit if (!Object.keys(dynamicInputFields).length) { @@ -284,7 +292,7 @@ export class TypegenPrinter { .join('\n') } - printDynamicOutputFieldDefinitions() { + private printDynamicOutputFieldDefinitions() { const { dynamicOutputFields } = this.schema.extensions.nexus.config.dynamicFields // If there is nothing custom... exit if (!Object.keys(dynamicOutputFields).length) { @@ -312,7 +320,7 @@ export class TypegenPrinter { .join('\n') } - prependDoc(typeDef: string, typeDescription?: string | null) { + private prependDoc(typeDef: string, typeDescription?: string | null) { let outStr = '' if (typeDescription) { let parts = typeDescription.split('\n').map((f) => f.trimLeft()) @@ -327,7 +335,7 @@ export class TypegenPrinter { return `${outStr}${typeDef}` } - printDynamicOutputPropertyDefinitions() { + private printDynamicOutputPropertyDefinitions() { const { dynamicOutputProperties } = this.schema.extensions.nexus.config.dynamicFields // If there is nothing custom... exit if (!Object.keys(dynamicOutputProperties).length) { @@ -346,7 +354,7 @@ export class TypegenPrinter { .join('\n') } - printInheritedFieldMap() { + private printInheritedFieldMap() { const hasInterfaces: ( | (GraphQLInterfaceType & { getInterfaces(): GraphQLInterfaceType[] }) | GraphQLObjectType @@ -371,37 +379,15 @@ export class TypegenPrinter { .join('\n') } - printContext() { + private printContext() { return this.typegenInfo.contextTypeImport?.alias || this.typegenInfo.contextTypeImport?.export || 'any' } - buildResolveSourceTypeMap() { - const sourceMap: TypeMapping = {} - const abstractTypes: (GraphQLInterfaceType | GraphQLUnionType)[] = [] - abstractTypes - .concat(this.groupedTypes.union) - .concat(this.groupedTypes.interface) - .forEach((type) => { - if (isInterfaceType(type)) { - const possibleNames = this.schema.getPossibleTypes(type).map((t) => t.name) - if (possibleNames.length > 0) { - sourceMap[type.name] = possibleNames.map((val) => `NexusGenRootTypes['${val}']`).join(' | ') - } - } else { - sourceMap[type.name] = type - .getTypes() - .map((t) => `NexusGenRootTypes['${t.name}']`) - .join(' | ') - } - }) - return sourceMap - } - - printAbstractTypeMembers() { + private printAbstractTypeMembers() { return this.printTypeInterface('NexusGenAbstractTypeMembers', this.buildAbstractTypeMembers()) } - buildAbstractTypeMembers() { + private buildAbstractTypeMembers() { const sourceMap: TypeMapping = {} const abstractTypes: (GraphQLInterfaceType | GraphQLUnionType)[] = [] abstractTypes @@ -423,13 +409,13 @@ export class TypegenPrinter { return sourceMap } - printTypeNames(name: keyof GroupedTypes, exportName: string, source: string) { + private printTypeNames(name: keyof GroupedTypes, exportName: string, source: string) { const obj = this.groupedTypes[name] as GraphQLNamedType[] const typeDef = obj.length === 0 ? 'never' : `keyof ${source}` return `export type ${exportName} = ${typeDef};` } - printIsTypeOfObjectTypeNames(exportName: string) { + private printIsTypeOfObjectTypeNames(exportName: string) { const objectTypes = this.groupedTypes.object.filter((o) => o.isTypeOf !== undefined) const typeDef = objectTypes.length === 0 @@ -441,7 +427,7 @@ export class TypegenPrinter { return `export type ${exportName} = ${typeDef};` } - printResolveTypeAbstractTypes(exportName: string) { + private printResolveTypeAbstractTypes(exportName: string) { const abstractTypes = [...this.groupedTypes.interface, ...this.groupedTypes.union].filter( (o) => o.resolveType !== undefined ) @@ -456,7 +442,7 @@ export class TypegenPrinter { return `export type ${exportName} = ${typeDef};` } - printFeaturesConfig(exportName: string) { + private printFeaturesConfig(exportName: string) { const abstractTypes = this.schema.extensions.nexus.config.features?.abstractTypeStrategies ?? {} const unionProps = renderObject(mapValues(abstractTypes, (val) => val ?? false)) @@ -466,7 +452,7 @@ export class TypegenPrinter { .join('\n') } - buildEnumTypeMap() { + private buildEnumTypeMap() { const enumMap: TypeMapping = {} this.groupedTypes.enum.forEach((e) => { const sourceType = this.resolveSourceType(e.name) @@ -480,7 +466,7 @@ export class TypegenPrinter { return enumMap } - buildInputTypeMap() { + private buildInputTypeMap() { const inputObjMap: TypeFieldMapping = {} this.groupedTypes.input.forEach((input) => { eachObj(input.getFields(), (field) => { @@ -491,7 +477,7 @@ export class TypegenPrinter { return inputObjMap } - buildScalarTypeMap() { + private buildScalarTypeMap() { const scalarMap: TypeMapping = {} this.groupedTypes.scalar.forEach((e) => { if (isSpecifiedScalarType(e)) { @@ -508,7 +494,7 @@ export class TypegenPrinter { return scalarMap } - printInputTypeMap() { + private printInputTypeMap() { const inputTypeMap = this.buildInputTypeMap() if (this.typegenInfo.declareInputs) { @@ -521,7 +507,7 @@ export class TypegenPrinter { return this.printTypeFieldInterface('NexusGenInputs', inputTypeMap, 'input type') } - printEnumTypeMap() { + private printEnumTypeMap() { const enumTypeMap = this.buildEnumTypeMap() if (this.typegenInfo.declareInputs) { @@ -534,11 +520,11 @@ export class TypegenPrinter { return this.printTypeInterface('NexusGenEnums', enumTypeMap) } - printScalarTypeMap() { + private printScalarTypeMap() { return this.printTypeInterface('NexusGenScalars', this.buildScalarTypeMap()) } - shouldDiscriminateType( + private shouldDiscriminateType( abstractType: GraphQLAbstractType, objectType: GraphQLObjectType ): 'required' | 'optional' | false { @@ -557,7 +543,7 @@ export class TypegenPrinter { return 'required' } - maybeDiscriminate(abstractType: GraphQLAbstractType, objectType: GraphQLObjectType) { + private maybeDiscriminate(abstractType: GraphQLAbstractType, objectType: GraphQLObjectType) { const requiredOrOptional = this.shouldDiscriminateType(abstractType, objectType) if (requiredOrOptional === false) { @@ -569,7 +555,7 @@ export class TypegenPrinter { return `core.Discriminate<'${objectType.name}', '${requiredOrOptional}'>` } - buildRootTypeMap(hasFields: Array) { + private buildRootTypeMap(hasFields: Array) { const rootTypeMap: RootTypeMapping = {} hasFields.forEach((type) => { const rootTyping = this.resolveSourceType(type.name) @@ -608,7 +594,7 @@ export class TypegenPrinter { return rootTypeMap } - resolveSourceType(typeName: string): string | undefined { + private resolveSourceType(typeName: string): string | undefined { const rootTyping = this.schema.extensions.nexus.config.rootTypings[typeName] if (rootTyping) { return typeof rootTyping === 'string' ? rootTyping : rootTyping.export @@ -616,7 +602,7 @@ export class TypegenPrinter { return (this.typegenInfo.sourceTypeMap as any)[typeName] } - hasResolver( + private hasResolver( field: GraphQLField, // Used in test mocking _type: GraphQLObjectType @@ -627,25 +613,25 @@ export class TypegenPrinter { return Boolean(field.resolve) } - printObjectTypeMap() { + private printObjectTypeMap() { return this.printRootTypeFieldInterface( 'NexusGenObjects', this.buildRootTypeMap(this.groupedTypes.object) ) } - printInterfaceTypeMap() { + private printInterfaceTypeMap() { return this.printRootTypeFieldInterface( 'NexusGenInterfaces', this.buildRootTypeMap(this.groupedTypes.interface) ) } - printUnionTypeMap() { + private printUnionTypeMap() { return this.printRootTypeFieldInterface('NexusGenUnions', this.buildRootTypeMap(this.groupedTypes.union)) } - printRootTypeDef() { + private printRootTypeDef() { const toJoin: string[] = [] if (this.groupedTypes.interface.length) { toJoin.push('NexusGenInterfaces') @@ -659,7 +645,7 @@ export class TypegenPrinter { return `export type NexusGenRootTypes = ${toJoin.join(' & ')}` } - printAllTypesMap() { + private printAllTypesMap() { const toJoin: string[] = ['NexusGenRootTypes'] if (this.groupedTypes.scalar.length) { toJoin.push('NexusGenScalars') @@ -670,7 +656,7 @@ export class TypegenPrinter { return `export type NexusGenAllTypes = ${toJoin.join(' & ')}` } - buildArgTypeMap() { + private buildArgTypeMap() { const argTypeMap: Record = {} const hasFields: (GraphQLInterfaceType | GraphQLObjectType)[] = [] hasFields @@ -690,7 +676,7 @@ export class TypegenPrinter { return argTypeMap } - printArgTypeMap() { + private printArgTypeMap() { const argTypeMap = this.buildArgTypeMap() if (this.typegenInfo.declareInputs) { const declaredArgs: string[] = [] @@ -709,7 +695,7 @@ export class TypegenPrinter { return `${typeName}${fieldName.slice(0, 1).toUpperCase().concat(fieldName.slice(1))}Args` } - printNamedObj(name: string, obj: Record) { + private printNamedObj(name: string, obj: Record) { return [ `export interface ${name} {`, ...mapObj(obj, (val, key) => ` ${key}${val[0]} ${val[1]}`), @@ -717,11 +703,11 @@ export class TypegenPrinter { ].join('\n') } - printNamedMap(name: string, obj: Record) { + private printNamedMap(name: string, obj: Record) { return [`export interface ${name} {`, ...mapObj(obj, (val, key) => ` ${key}: ${key}`), `}`].join('\n') } - buildReturnTypeMap() { + private buildReturnTypeMap() { const returnTypeMap: TypeFieldMapping = {} const hasFields: (GraphQLInterfaceType | GraphQLObjectType)[] = [] hasFields @@ -736,7 +722,7 @@ export class TypegenPrinter { return returnTypeMap } - buildReturnTypeNamesMap() { + private buildReturnTypeNamesMap() { const returnTypeMap: TypeFieldMapping = {} const hasFields: (GraphQLInterfaceType | GraphQLObjectType)[] = [] hasFields @@ -751,7 +737,7 @@ export class TypegenPrinter { return returnTypeMap } - printOutputType(type: GraphQLOutputType) { + private printOutputType(type: GraphQLOutputType) { const returnType = this.typeToArr(type) function combine(item: any[]): string { if (item.length === 1) { @@ -770,7 +756,7 @@ export class TypegenPrinter { return `${combine(returnType)}; // ${type}` } - typeToArr(type: GraphQLOutputType): any[] { + private typeToArr(type: GraphQLOutputType): any[] { const typing = [] if (isNonNullType(type)) { type = type.ofType @@ -793,11 +779,11 @@ export class TypegenPrinter { return typing } - printFieldTypesMap() { + private printFieldTypesMap() { return this.printTypeFieldInterface('NexusGenFieldTypes', this.buildReturnTypeMap(), 'field return type') } - printFieldTypeNamesMap() { + private printFieldTypeNamesMap() { return this.printTypeFieldInterface( 'NexusGenFieldTypeNames', this.buildReturnTypeNamesMap(), @@ -805,11 +791,11 @@ export class TypegenPrinter { ) } - normalizeArg(arg: GraphQLInputField | GraphQLArgument): [string, string] { + private normalizeArg(arg: GraphQLInputField | GraphQLArgument): [string, string] { return [this.argSeparator(arg.type, Boolean(arg.defaultValue)), this.argTypeRepresentation(arg.type)] } - argSeparator(type: GraphQLInputType, hasDefaultValue: boolean) { + private argSeparator(type: GraphQLInputType, hasDefaultValue: boolean) { if (hasDefaultValue || isNonNullType(type)) { return ':' } @@ -817,7 +803,7 @@ export class TypegenPrinter { return '?:' } - argTypeRepresentation(arg: GraphQLInputType): string { + private argTypeRepresentation(arg: GraphQLInputType): string { const argType = this.argTypeArr(arg) function combine(item: any[]): string { if (item.length === 1) { @@ -836,7 +822,7 @@ export class TypegenPrinter { return `${combine(argType)}; // ${arg}` } - argTypeArr(arg: GraphQLInputType): any[] { + private argTypeArr(arg: GraphQLInputType): any[] { const typing = [] if (isNonNullType(arg)) { arg = arg.ofType @@ -863,14 +849,14 @@ export class TypegenPrinter { return typing } - printTypeInterface(interfaceName: string, typeMapping: TypeMapping) { + private printTypeInterface(interfaceName: string, typeMapping: TypeMapping) { return [`export interface ${interfaceName} {`] .concat(mapObj(typeMapping, (val, key) => ` ${key}: ${val}`)) .concat('}') .join('\n') } - printRootTypeFieldInterface(interfaceName: string, typeMapping: RootTypeMapping) { + private printRootTypeFieldInterface(interfaceName: string, typeMapping: RootTypeMapping) { return [`export interface ${interfaceName} {`] .concat( mapObj(typeMapping, (val, key) => { @@ -887,14 +873,14 @@ export class TypegenPrinter { .join('\n') } - printTypeFieldInterface(interfaceName: string, typeMapping: TypeFieldMapping, source: string) { + private printTypeFieldInterface(interfaceName: string, typeMapping: TypeFieldMapping, source: string) { return [`export interface ${interfaceName} {`] .concat(mapObj(typeMapping, this.printObj(' ', source))) .concat('}') .join('\n') } - printArgTypeFieldInterface(typeMapping: Record) { + private printArgTypeFieldInterface(typeMapping: Record) { return [`export interface NexusGenArgTypes {`] .concat( mapObj(typeMapping, (val, typeName) => { @@ -916,25 +902,26 @@ export class TypegenPrinter { .join('\n') } - printObj = (space: string, source: string) => (val: Record, key: string) => { - return [`${space}${key}: { // ${source}`] - .concat( - mapObj(val, (v2, k2) => { - return `${space} ${k2}${v2[0]} ${v2[1]}` - }) - ) - .concat(`${space}}`) - .join('\n') - } + private printObj = + (space: string, source: string) => (val: Record, key: string) => { + return [`${space}${key}: { // ${source}`] + .concat( + mapObj(val, (v2, k2) => { + return `${space} ${k2}${v2[0]} ${v2[1]}` + }) + ) + .concat(`${space}}`) + .join('\n') + } - printScalar(type: GraphQLScalarType) { + private printScalar(type: GraphQLScalarType) { if (isSpecifiedScalarType(type)) { return this.resolveSourceType(type.name) ?? SpecifiedScalars[type.name as SpecifiedScalarNames] } return `NexusGenScalars['${type.name}']` } - printPlugins() { + private printPlugins() { const pluginFieldExt: string[] = [ ` interface NexusGenPluginFieldConfig {`, ] @@ -983,7 +970,7 @@ export class TypegenPrinter { ].join('\n') } - printType(strLike: StringLike | StringLike[]): string { + private printType(strLike: StringLike | StringLike[]): string { if (Array.isArray(strLike)) { return strLike.map((s) => this.printType(s)).join('\n') } @@ -1000,7 +987,7 @@ export class TypegenPrinter { return strLike } - addImport(i: PrintedGenTypingImport) { + private addImport(i: PrintedGenTypingImport) { /* istanbul ignore if */ if (!isNexusPrintedGenTypingImport(i)) { console.warn(`Expected printedGenTypingImport, saw ${i}`) diff --git a/tests/__snapshots__/typegenPrinterGlobals.spec.ts.snap b/tests/__snapshots__/typegenPrinterGlobals.spec.ts.snap index 0b68547d..13163eec 100644 --- a/tests/__snapshots__/typegenPrinterGlobals.spec.ts.snap +++ b/tests/__snapshots__/typegenPrinterGlobals.spec.ts.snap @@ -7,7 +7,7 @@ Object { * Do not make changes to this file directly */ -import { NexusGenTypes } from './types.gen' +import type { NexusGenTypes } from './types.gen' @@ -16,6 +16,8 @@ declare global { interface NexusGen extends NexusGenTypes {} } +import type { TestContext } from \\"./../__helpers/index\\" + declare global { interface NexusGenPluginTypeConfig { @@ -486,7 +488,7 @@ exports[`typegenPrinter: no input changes should print the full output, with inp * Do not make changes to this file directly */ -import { NexusGenTypes } from './types.gen' +import type { NexusGenTypes } from './types.gen' @@ -496,6 +498,8 @@ declare global { } + + declare global { interface NexusGenPluginTypeConfig { } diff --git a/tests/backingTypes.spec.ts b/tests/backingTypes.spec.ts index ea75ac09..93a32111 100644 --- a/tests/backingTypes.spec.ts +++ b/tests/backingTypes.spec.ts @@ -75,6 +75,7 @@ describe('sourceTypes', () => { typegenPath: '', }) + // @ts-expect-error expect(typegen.printEnumTypeMap()).toMatchSnapshot() }) @@ -86,6 +87,7 @@ describe('sourceTypes', () => { typegenPath: '', }) + // @ts-expect-error expect(typegen.printEnumTypeMap()).toMatchSnapshot() }) }) diff --git a/tests/typegen-globals/global-types.gen.ts b/tests/typegen-globals/global-types.gen.ts index 72e3bab8..c8abab6b 100644 --- a/tests/typegen-globals/global-types.gen.ts +++ b/tests/typegen-globals/global-types.gen.ts @@ -1,6 +1,6 @@ /** This file was generated by Nexus Schema Do not make changes to this file directly */ -import { NexusGenTypes } from './types.gen' +import type { NexusGenTypes } from './types.gen' declare global { interface NexusGen extends NexusGenTypes {} diff --git a/tests/typegenPrinter.spec.ts b/tests/typegenPrinter.spec.ts index 086793ed..6dedfccf 100644 --- a/tests/typegenPrinter.spec.ts +++ b/tests/typegenPrinter.spec.ts @@ -68,7 +68,9 @@ describe('typegenPrinter', () => { typegenPath: '', }) jest + // @ts-expect-error .spyOn(typegen, 'hasResolver') + // @ts-expect-error .mockImplementation((field: GraphQLField, type: GraphQLObjectType | GraphQLInterfaceType) => { if (type.name === 'Query' || type.name === 'Mutation') { return true @@ -82,30 +84,37 @@ describe('typegenPrinter', () => { }) it('builds the enum object type defs', () => { + // @ts-expect-error expect(typegen.printEnumTypeMap()).toMatchSnapshot() }) it('builds the input object type defs', () => { + // @ts-expect-error expect(typegen.printInputTypeMap()).toMatchSnapshot() }) it('should build an argument type map', () => { + // @ts-expect-error expect(typegen.printArgTypeMap()).toMatchSnapshot() }) it('should print a object type map', () => { + // @ts-expect-error expect(typegen.printObjectTypeMap()).toMatchSnapshot() }) it('should print a interface type map', () => { + // @ts-expect-error expect(typegen.printInterfaceTypeMap()).toMatchSnapshot() }) it('should print a union type map', () => { + // @ts-expect-error expect(typegen.printUnionTypeMap()).toMatchSnapshot() }) it('should print a root type map', () => { + // @ts-expect-error expect(typegen.printRootTypeDef()).toMatchSnapshot() }) @@ -115,7 +124,9 @@ describe('typegenPrinter', () => { // If the field has a resolver, we assume it's derived, otherwise // you'll need to supply a backing root type with more information. jest + // @ts-expect-error .spyOn(typegen, 'hasResolver') + // @ts-expect-error .mockImplementation((field: GraphQLField, type: GraphQLObjectType | GraphQLInterfaceType) => { if (type.name === 'Query' || type.name === 'Mutation') { return true @@ -125,11 +136,14 @@ describe('typegenPrinter', () => { } return false }) + // @ts-expect-error expect(typegen.printObjectTypeMap()).toMatchSnapshot() + // @ts-expect-error expect(typegen.printRootTypeDef()).toMatchSnapshot() }) it('should print a return type map', () => { + // @ts-expect-error expect(typegen.printFieldTypesMap()).toMatchSnapshot() }) From 266f1a82ce0c1565e03481f1f84fa1cdb8349b9d Mon Sep 17 00:00:00 2001 From: Tim Griesser Date: Tue, 17 Aug 2021 20:15:49 -0400 Subject: [PATCH 05/10] fix: add globalHeaders to imports for global def file (#969) --- src/typegenMetadata.ts | 3 ++- src/typegenPrinter.ts | 5 +++-- 2 files changed, 5 insertions(+), 3 deletions(-) diff --git a/src/typegenMetadata.ts b/src/typegenMetadata.ts index 7c0af58c..a5955dff 100644 --- a/src/typegenMetadata.ts +++ b/src/typegenMetadata.ts @@ -140,13 +140,14 @@ export class TypegenMetadata { /** Generates the type definitions */ async generateConfiguredTypes(schema: NexusGraphQLSchema, typegen: ConfiguredTypegen) { - const { outputPath: typegenPath, globalsPath, declareInputs = true } = typegen + const { outputPath: typegenPath, globalsPath, globalsHeaders, declareInputs = true } = typegen const typegenInfo = await this.getTypegenInfo(schema, typegenPath) return new TypegenPrinter(schema, { ...typegenInfo, typegenPath, globalsPath, + globalsHeaders, declareInputs, }).printConfigured() } diff --git a/src/typegenPrinter.ts b/src/typegenPrinter.ts index 1795ca69..68cba083 100644 --- a/src/typegenPrinter.ts +++ b/src/typegenPrinter.ts @@ -55,7 +55,7 @@ type RootTypeMapping = Record> interface TypegenInfoWithFile extends TypegenInfo { typegenPath: string globalsPath?: string - globalsHeaders?: string + globalsHeaders?: string[] declareInputs?: boolean } @@ -162,7 +162,8 @@ export class TypegenPrinter { this.typegenInfo.globalsPath ?? '' )}'` ) - headers.unshift(this.typegenInfo.globalsHeaders ?? TYPEGEN_HEADER) + headers.unshift(...(this.typegenInfo.globalsHeaders ?? [])) + headers.unshift(TYPEGEN_HEADER) } return headers.join('\n') From 855a482c54213fd904f3b641bd8095ca2f188560 Mon Sep 17 00:00:00 2001 From: Johannes Choo Date: Thu, 19 Aug 2021 02:50:09 +0800 Subject: [PATCH 06/10] fix: plugin inputFieldDefTypes (#919) --- src/definitions/definitionBlocks.ts | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/definitions/definitionBlocks.ts b/src/definitions/definitionBlocks.ts index 4435e579..e9a24847 100644 --- a/src/definitions/definitionBlocks.ts +++ b/src/definitions/definitionBlocks.ts @@ -116,7 +116,8 @@ export type CommonInputFieldConfig +} & NexusGenPluginFieldConfig & + NexusGenPluginInputFieldConfig export interface OutputScalarConfig extends CommonOutputFieldConfig { /** From a003ff074fdc1d86abaa6fad87f7376823c37418 Mon Sep 17 00:00:00 2001 From: Tim Griesser Date: Thu, 19 Aug 2021 10:56:35 -0400 Subject: [PATCH 07/10] fix: printer imports, follow up from #967 (#970) --- src/makeSchema.ts | 9 ++- src/typegenMetadata.ts | 8 +-- src/typegenPrinter.ts | 61 +++++++++++-------- src/typegenUtils.ts | 6 +- .../typegenPrinterGlobals.spec.ts.snap | 2 +- tests/backingTypes.spec.ts | 4 +- tests/typegenPrinter.spec.ts | 4 +- 7 files changed, 57 insertions(+), 37 deletions(-) diff --git a/src/makeSchema.ts b/src/makeSchema.ts index a61c420a..06d1a17c 100644 --- a/src/makeSchema.ts +++ b/src/makeSchema.ts @@ -20,10 +20,17 @@ export function makeSchema(config: SchemaConfig): NexusGraphQLSchema { // in the optional thunk for the typegen config const typegenPromise = new TypegenMetadata(typegenConfig).generateArtifacts(schema) if (config.shouldExitAfterGenerateArtifacts) { + let typegenPath = '(not enabled)' + if (typegenConfig.outputs.typegen) { + typegenPath = typegenConfig.outputs.typegen.outputPath + if (typegenConfig.outputs.typegen.globalsPath) { + typegenPath += ` / ${typegenConfig.outputs.typegen.globalsPath}` + } + } typegenPromise .then(() => { console.log(`Generated Artifacts: - TypeScript Types ==> ${typegenConfig.outputs.typegen || '(not enabled)'} + TypeScript Types ==> ${typegenPath} GraphQL Schema ==> ${typegenConfig.outputs.schema || '(not enabled)'}`) process.exit(0) }) diff --git a/src/typegenMetadata.ts b/src/typegenMetadata.ts index a5955dff..95023323 100644 --- a/src/typegenMetadata.ts +++ b/src/typegenMetadata.ts @@ -13,7 +13,7 @@ export interface TypegenMetadataConfig nexusSchemaImportId?: string outputs: { schema: null | string - typegen: null | string | ConfiguredTypegen + typegen: null | ConfiguredTypegen } } @@ -162,7 +162,7 @@ export class TypegenMetadata { if (this.config.sourceTypes) { return typegenAutoConfig(this.config.sourceTypes, this.config.contextType)( schema, - typegenPath || this.normalizeTypegenPath(this.config.outputs.typegen) || '' + typegenPath || this.config.outputs.typegen?.outputPath || '' ) } @@ -174,8 +174,4 @@ export class TypegenMetadata { sourceTypeMap: {}, } } - - private normalizeTypegenPath(typegen: string | ConfiguredTypegen | null) { - return typeof typegen === 'string' ? typegen : typegen ? typegen.outputPath : null - } } diff --git a/src/typegenPrinter.ts b/src/typegenPrinter.ts index 68cba083..7a1a3616 100644 --- a/src/typegenPrinter.ts +++ b/src/typegenPrinter.ts @@ -201,10 +201,7 @@ export class TypegenPrinter { } private printDynamicImport(forGlobal = false) { - const { - rootTypings, - dynamicFields: { dynamicInputFields, dynamicOutputFields }, - } = this.schema.extensions.nexus.config + const { rootTypings } = this.schema.extensions.nexus.config const { contextTypeImport } = this.typegenInfo const imports: string[] = [] const importMap: Record> = {} @@ -212,27 +209,19 @@ export class TypegenPrinter { const nexusSchemaImportId = this.typegenInfo.nexusSchemaImportId ?? getOwnPackage().name if (!this.printImports[nexusSchemaImportId]) { - if ( - [dynamicInputFields, dynamicOutputFields].some((o) => Object.keys(o).length > 0) || - this.hasDiscriminatedTypes === true - ) { - this.printImports[nexusSchemaImportId] = { - core: true, - } - } - } - - if (contextTypeImport) { - const importPath = resolveImportPath(contextTypeImport, 'context', outputPath) - importMap[importPath] = importMap[importPath] || new Set() - importMap[importPath].add( - contextTypeImport.alias - ? `${contextTypeImport.export} as ${contextTypeImport.alias}` - : contextTypeImport.export - ) + this.maybeAddCoreImport(forGlobal) } if (!forGlobal) { + if (contextTypeImport) { + const importPath = resolveImportPath(contextTypeImport, 'context', outputPath) + importMap[importPath] = importMap[importPath] || new Set() + importMap[importPath].add( + contextTypeImport.alias + ? `${contextTypeImport.export} as ${contextTypeImport.alias}` + : contextTypeImport.export + ) + } eachObj(rootTypings, (rootType, typeName) => { if (typeof rootType !== 'string') { const importPath = resolveImportPath(rootType, typeName, outputPath) @@ -242,11 +231,11 @@ export class TypegenPrinter { ) } }) + eachObj(importMap, (val, key) => { + imports.push(`import type { ${Array.from(val).join(', ')} } from ${JSON.stringify(key)}`) + }) } - eachObj(importMap, (val, key) => { - imports.push(`import type { ${Array.from(val).join(', ')} } from ${JSON.stringify(key)}`) - }) eachObj(this.printImports, (val, key) => { const { default: def, ...rest } = val const idents = [] @@ -265,6 +254,28 @@ export class TypegenPrinter { return imports.join('\n') } + private maybeAddCoreImport(forGlobal = false) { + const nexusSchemaImportId = this.typegenInfo.nexusSchemaImportId ?? getOwnPackage().name + const { + dynamicFields: { dynamicInputFields, dynamicOutputFields }, + } = this.schema.extensions.nexus.config + + let shouldAdd = false + const hasDynamicFields = [dynamicInputFields, dynamicOutputFields].some((o) => Object.keys(o).length > 0) + + if (!this.typegenInfo.globalsPath) { + shouldAdd = hasDynamicFields || this.hasDiscriminatedTypes + } else { + shouldAdd = forGlobal ? hasDynamicFields : this.hasDiscriminatedTypes + } + + if (shouldAdd) { + this.printImports[nexusSchemaImportId] = { + core: true, + } + } + } + private printDynamicInputFieldDefinitions() { const { dynamicInputFields } = this.schema.extensions.nexus.config.dynamicFields // If there is nothing custom... exit diff --git a/src/typegenUtils.ts b/src/typegenUtils.ts index 77017b44..364c1122 100644 --- a/src/typegenUtils.ts +++ b/src/typegenUtils.ts @@ -14,7 +14,7 @@ export function resolveTypegenConfig(config: BuilderConfigInput): TypegenMetadat const defaultSDLFilePath = path.join(process.cwd(), 'schema.graphql') - let typegenFilePath: string | ConfiguredTypegen | null = null + let typegenFilePath: ConfiguredTypegen | null = null let sdlFilePath: string | null = null if (outputs === undefined) { @@ -32,7 +32,9 @@ export function resolveTypegenConfig(config: BuilderConfigInput): TypegenMetadat } // handle typegen configuration if (typeof outputs.typegen === 'string') { - typegenFilePath = assertAbsolutePath(outputs.typegen, 'outputs.typegen') + typegenFilePath = { + outputPath: assertAbsolutePath(outputs.typegen, 'outputs.typegen'), + } } else if (typeof outputs.typegen === 'object') { typegenFilePath = { ...outputs.typegen, diff --git a/tests/__snapshots__/typegenPrinterGlobals.spec.ts.snap b/tests/__snapshots__/typegenPrinterGlobals.spec.ts.snap index 13163eec..884df8a7 100644 --- a/tests/__snapshots__/typegenPrinterGlobals.spec.ts.snap +++ b/tests/__snapshots__/typegenPrinterGlobals.spec.ts.snap @@ -16,7 +16,7 @@ declare global { interface NexusGen extends NexusGenTypes {} } -import type { TestContext } from \\"./../__helpers/index\\" + declare global { diff --git a/tests/backingTypes.spec.ts b/tests/backingTypes.spec.ts index 93a32111..8ecaf0e8 100644 --- a/tests/backingTypes.spec.ts +++ b/tests/backingTypes.spec.ts @@ -49,7 +49,9 @@ describe('sourceTypes', () => { beforeEach(async () => { metadata = new TypegenMetadata({ outputs: { - typegen: path.join(__dirname, 'test-gen.ts'), + typegen: { + outputPath: path.join(__dirname, 'test-gen.ts'), + }, schema: path.join(__dirname, 'test-gen.graphql'), }, sourceTypes: { diff --git a/tests/typegenPrinter.spec.ts b/tests/typegenPrinter.spec.ts index 6dedfccf..a4ba835b 100644 --- a/tests/typegenPrinter.spec.ts +++ b/tests/typegenPrinter.spec.ts @@ -35,7 +35,9 @@ describe('typegenPrinter', () => { metadata = new TypegenMetadata({ outputs: { - typegen: path.join(__dirname, 'test-gen.ts'), + typegen: { + outputPath: path.join(__dirname, 'test-gen.ts'), + }, schema: path.join(__dirname, 'test-gen.graphql'), }, sourceTypes: { From 555ae79ded1a4c65d446cba10d72d077561a8515 Mon Sep 17 00:00:00 2001 From: Tim Griesser Date: Thu, 2 Sep 2021 09:18:47 -0400 Subject: [PATCH 08/10] fix: revert declareInputs default to false (#975) --- examples/kitchen-sink/src/index.ts | 1 + src/builder.ts | 2 +- src/typegenMetadata.ts | 4 +- .../typegenPrinterGlobals.spec.ts.snap | 80 +++++++---------- .../declarativeWrappingPlugin/__typegen.ts | 27 +++--- tests/integrations/kitchenSink/__typegen.ts | 79 ++++++++--------- tests/typegen/types.gen.ts | 88 ++++++++----------- 7 files changed, 119 insertions(+), 162 deletions(-) diff --git a/examples/kitchen-sink/src/index.ts b/examples/kitchen-sink/src/index.ts index 4ba4b6b1..d4285715 100644 --- a/examples/kitchen-sink/src/index.ts +++ b/examples/kitchen-sink/src/index.ts @@ -24,6 +24,7 @@ const schema = makeSchema({ typegen: { outputPath: path.join(__dirname, './kitchen-sink.gen.ts'), globalsPath: path.join(__dirname, './kitchen-sink-globals.gen.ts'), + declareInputs: true, }, }, plugins: [ diff --git a/src/builder.ts b/src/builder.ts index 21cf5721..077d8ee6 100644 --- a/src/builder.ts +++ b/src/builder.ts @@ -192,7 +192,7 @@ export interface ConfiguredTypegen { /** * If "true", declares dedicated interfaces for any inputs / args * - * @default true + * @default false */ declareInputs?: boolean } diff --git a/src/typegenMetadata.ts b/src/typegenMetadata.ts index 95023323..9bd63b41 100644 --- a/src/typegenMetadata.ts +++ b/src/typegenMetadata.ts @@ -132,7 +132,7 @@ export class TypegenMetadata { const typegenInfo = await this.getTypegenInfo(schema, typegenPath) return new TypegenPrinter(schema, { - declareInputs: true, + declareInputs: false, ...typegenInfo, typegenPath, }).print() @@ -140,7 +140,7 @@ export class TypegenMetadata { /** Generates the type definitions */ async generateConfiguredTypes(schema: NexusGraphQLSchema, typegen: ConfiguredTypegen) { - const { outputPath: typegenPath, globalsPath, globalsHeaders, declareInputs = true } = typegen + const { outputPath: typegenPath, globalsPath, globalsHeaders, declareInputs = false } = typegen const typegenInfo = await this.getTypegenInfo(schema, typegenPath) return new TypegenPrinter(schema, { diff --git a/tests/__snapshots__/typegenPrinterGlobals.spec.ts.snap b/tests/__snapshots__/typegenPrinterGlobals.spec.ts.snap index 884df8a7..bb966d73 100644 --- a/tests/__snapshots__/typegenPrinterGlobals.spec.ts.snap +++ b/tests/__snapshots__/typegenPrinterGlobals.spec.ts.snap @@ -267,29 +267,21 @@ exports[`typegenPrinter: no input changes should print the full output, with inp import type { core } from \\"nexus\\" -export interface CreatePostInput { - name: string; // String! - author: string; // ID! - geo: Array>; // [[Float]!]! -} - -export interface PostFilters { - order: OrderEnum; // OrderEnum! - search: string | null; // String -} - export interface NexusGenInputs { - CreatePostInput: CreatePostInput - PostFilters: PostFilters + CreatePostInput: { // input type + name: string; // String! + author: string; // ID! + geo: Array>; // [[Float]!]! + } + PostFilters: { // input type + order: NexusGenEnums['OrderEnum']; // OrderEnum! + search: string | null; // String + } } -export type OrderEnum = \\"ASC\\" | \\"DESC\\" - -export type SomeEnum = \\"A\\" | \\"B\\" - export interface NexusGenEnums { - OrderEnum: OrderEnum - SomeEnum: SomeEnum + OrderEnum: \\"ASC\\" | \\"DESC\\" + SomeEnum: \\"A\\" | \\"B\\" } export interface NexusGenScalars { @@ -344,7 +336,7 @@ export interface NexusGenFieldTypes { email: string; // String! phone: string | null; // String posts: NexusGenRootTypes['Post'][]; // [Post!]! - outEnum: SomeEnum | null; // SomeEnum + outEnum: NexusGenEnums['SomeEnum'] | null; // SomeEnum } Node: { // field return type id: string; // ID! @@ -382,42 +374,30 @@ export interface NexusGenFieldTypeNames { } } -export interface MutationSomeListArgs { - items: Array; // [String]! -} - -export interface MutationCreatePostArgs { - input: CreatePostInput; // CreatePostInput! -} - -export interface MutationRegisterClickArgs { - uuid?: NexusGenScalars['UUID'] | null; // UUID -} - -export interface QueryPostsArgs { - filters: PostFilters; // PostFilters! -} - -export interface UserNameArgs { - prefix?: string | null; // String -} - -export interface UserPostsArgs { - filters?: PostFilters | null; // PostFilters -} - export interface NexusGenArgTypes { Mutation: { - someList: MutationSomeListArgs - createPost: MutationCreatePostArgs - registerClick: MutationRegisterClickArgs + someList: { // args + items: Array; // [String]! + } + createPost: { // args + input: NexusGenInputs['CreatePostInput']; // CreatePostInput! + } + registerClick: { // args + uuid?: NexusGenScalars['UUID'] | null; // UUID + } } Query: { - posts: QueryPostsArgs + posts: { // args + filters: NexusGenInputs['PostFilters']; // PostFilters! + } } User: { - name: UserNameArgs - posts: UserPostsArgs + name: { // args + prefix?: string | null; // String + } + posts: { // args + filters?: NexusGenInputs['PostFilters'] | null; // PostFilters + } } } diff --git a/tests/integrations/declarativeWrappingPlugin/__typegen.ts b/tests/integrations/declarativeWrappingPlugin/__typegen.ts index fa540661..ffd15fd6 100644 --- a/tests/integrations/declarativeWrappingPlugin/__typegen.ts +++ b/tests/integrations/declarativeWrappingPlugin/__typegen.ts @@ -4,12 +4,11 @@ declare global { interface NexusGen extends NexusGenTypes {} } -export interface InlineInputType { - abc: number // Int! -} - export interface NexusGenInputs { - InlineInputType: InlineInputType + InlineInputType: { + // input type + abc: number // Int! + } } export interface NexusGenEnums {} @@ -63,18 +62,16 @@ export interface NexusGenFieldTypeNames { } } -export interface DeclarativeWrappingOutputSomeListOfListsArgs { - int: number // Int! -} - -export interface DeclarativeWrappingOutputSomeNullFieldArgs { - input?: InlineInputType | null // InlineInputType -} - export interface NexusGenArgTypes { DeclarativeWrappingOutput: { - someListOfLists: DeclarativeWrappingOutputSomeListOfListsArgs - someNullField: DeclarativeWrappingOutputSomeNullFieldArgs + someListOfLists: { + // args + int: number // Int! + } + someNullField: { + // args + input?: NexusGenInputs['InlineInputType'] | null // InlineInputType + } } } diff --git a/tests/integrations/kitchenSink/__typegen.ts b/tests/integrations/kitchenSink/__typegen.ts index 463fb191..b250dfcb 100644 --- a/tests/integrations/kitchenSink/__typegen.ts +++ b/tests/integrations/kitchenSink/__typegen.ts @@ -45,24 +45,20 @@ declare global { interface NexusGen extends NexusGenTypes {} } -export interface PostSearchInput { - body?: string | null // String - title?: string | null // String -} - -export interface Something { - id: number // Int! -} - export interface NexusGenInputs { - PostSearchInput: PostSearchInput - Something: Something + PostSearchInput: { + // input type + body?: string | null // String + title?: string | null // String + } + Something: { + // input type + id: number // Int! + } } -export type UserStatus = 'active' | 'pending' - export interface NexusGenEnums { - UserStatus: UserStatus + UserStatus: 'active' | 'pending' } export interface NexusGenScalars { @@ -261,44 +257,39 @@ export interface NexusGenFieldTypeNames { } } -export interface MutationCreateUserArgs { - firstName?: string | null // String - lastName?: string | null // String -} - -export interface PostEdgeDeltaArgs { - format?: string | null // String -} - -export interface QuerySearchPostsArgs { - input?: PostSearchInput | null // PostSearchInput -} - -export interface QueryUserArgs { - id?: string | null // ID - status: UserStatus | null // UserStatus -} - -export interface UserPostsArgs { - after?: string | null // String - before?: string | null // String - first?: number | null // Int - last?: number | null // Int -} - export interface NexusGenArgTypes { Mutation: { - createUser: MutationCreateUserArgs + createUser: { + // args + firstName?: string | null // String + lastName?: string | null // String + } } PostEdge: { - delta: PostEdgeDeltaArgs + delta: { + // args + format?: string | null // String + } } Query: { - searchPosts: QuerySearchPostsArgs - user: QueryUserArgs + searchPosts: { + // args + input?: NexusGenInputs['PostSearchInput'] | null // PostSearchInput + } + user: { + // args + id?: string | null // ID + status: NexusGenEnums['UserStatus'] | null // UserStatus + } } User: { - posts: UserPostsArgs + posts: { + // args + after?: string | null // String + before?: string | null // String + first?: number | null // Int + last?: number | null // Int + } } } diff --git a/tests/typegen/types.gen.ts b/tests/typegen/types.gen.ts index f1665802..bdca6f81 100644 --- a/tests/typegen/types.gen.ts +++ b/tests/typegen/types.gen.ts @@ -6,29 +6,23 @@ declare global { interface NexusGen extends NexusGenTypes {} } -export interface CreatePostInput { - author: string // ID! - geo: Array> // [[Float]!]! - name: string // String! -} - -export interface PostFilters { - order: OrderEnum // OrderEnum! - search: string | null // String -} - export interface NexusGenInputs { - CreatePostInput: CreatePostInput - PostFilters: PostFilters + CreatePostInput: { + // input type + author: string // ID! + geo: Array> // [[Float]!]! + name: string // String! + } + PostFilters: { + // input type + order: NexusGenEnums['OrderEnum'] // OrderEnum! + search: string | null // String + } } -export type OrderEnum = 'ASC' | 'DESC' - -export type SomeEnum = 'A' | 'B' - export interface NexusGenEnums { - OrderEnum: OrderEnum - SomeEnum: SomeEnum + OrderEnum: 'ASC' | 'DESC' + SomeEnum: 'A' | 'B' } export interface NexusGenScalars { @@ -85,7 +79,7 @@ export interface NexusGenFieldTypes { email: string // String! id: string // ID! name: string // String! - outEnum: SomeEnum | null // SomeEnum + outEnum: NexusGenEnums['SomeEnum'] | null // SomeEnum phone: string | null // String posts: NexusGenRootTypes['Post'][] // [Post!]! } @@ -131,42 +125,36 @@ export interface NexusGenFieldTypeNames { } } -export interface MutationCreatePostArgs { - input: CreatePostInput // CreatePostInput! -} - -export interface MutationRegisterClickArgs { - uuid?: NexusGenScalars['UUID'] | null // UUID -} - -export interface MutationSomeListArgs { - items: Array // [String]! -} - -export interface QueryPostsArgs { - filters: PostFilters // PostFilters! -} - -export interface UserNameArgs { - prefix?: string | null // String -} - -export interface UserPostsArgs { - filters?: PostFilters | null // PostFilters -} - export interface NexusGenArgTypes { Mutation: { - createPost: MutationCreatePostArgs - registerClick: MutationRegisterClickArgs - someList: MutationSomeListArgs + createPost: { + // args + input: NexusGenInputs['CreatePostInput'] // CreatePostInput! + } + registerClick: { + // args + uuid?: NexusGenScalars['UUID'] | null // UUID + } + someList: { + // args + items: Array // [String]! + } } Query: { - posts: QueryPostsArgs + posts: { + // args + filters: NexusGenInputs['PostFilters'] // PostFilters! + } } User: { - name: UserNameArgs - posts: UserPostsArgs + name: { + // args + prefix?: string | null // String + } + posts: { + // args + filters?: NexusGenInputs['PostFilters'] | null // PostFilters + } } } From 6de1cb691766c0f5d8a7db4aafe8523bea9eb539 Mon Sep 17 00:00:00 2001 From: Gary Lamp Date: Thu, 2 Sep 2021 20:20:54 +0700 Subject: [PATCH 09/10] docs: Remove `.ts` extension from import statement (#974) --- .../03-tutorial/02-chapter-1-setup-and-first-query.mdx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/content/010-getting-started/03-tutorial/02-chapter-1-setup-and-first-query.mdx b/docs/content/010-getting-started/03-tutorial/02-chapter-1-setup-and-first-query.mdx index e71d369d..9c484eee 100644 --- a/docs/content/010-getting-started/03-tutorial/02-chapter-1-setup-and-first-query.mdx +++ b/docs/content/010-getting-started/03-tutorial/02-chapter-1-setup-and-first-query.mdx @@ -118,7 +118,7 @@ export const server = new ApolloServer({ schema }) ```ts copy // api/index.ts -import { server } from './server.ts' +import { server } from './server' server.listen().then(({ url }) => { console.log(`🚀 Server ready at ${url}`) From d4c626077465bd012a22840d1a14d47c9a0eb5c0 Mon Sep 17 00:00:00 2001 From: Tim Griesser Date: Thu, 2 Sep 2021 09:38:16 -0400 Subject: [PATCH 10/10] feat: ability to rename root types (#976) Closes #867 --- src/builder.ts | 37 +++++++++++- tests/__snapshots__/builder.spec.ts.snap | 56 +++++++++++++++++ tests/builder.spec.ts | 76 ++++++++++++++++++++++++ 3 files changed, 166 insertions(+), 3 deletions(-) create mode 100644 tests/__snapshots__/builder.spec.ts.snap create mode 100644 tests/builder.spec.ts diff --git a/src/builder.ts b/src/builder.ts index 077d8ee6..56e64ce6 100644 --- a/src/builder.ts +++ b/src/builder.ts @@ -69,6 +69,7 @@ import { AllNexusNamedInputTypeDefs, AllNexusNamedOutputTypeDefs, AllNexusNamedTypeDefs, + AllNexusOutputTypeDefs, finalizeWrapping, isNexusDynamicInputMethod, isNexusDynamicOutputMethod, @@ -283,6 +284,15 @@ export type SchemaConfig = BuilderConfigInput & { * the values, if it's an array we flatten out the valid types, ignoring invalid ones. */ types: any + /** + * If we wish to override the "Root" type for the schema, we can do so by specifying the rootTypes option, + * which will replace the default roots of Query / Mutation / Subscription + */ + schemaRoots?: { + query?: GetGen<'allOutputTypes', string> | AllNexusOutputTypeDefs + mutation?: GetGen<'allOutputTypes', string> | AllNexusOutputTypeDefs + subscription?: GetGen<'allOutputTypes', string> | AllNexusOutputTypeDefs + } /** * Whether we should process.exit after the artifacts are generated. Useful if you wish to explicitly * generate the test artifacts at a certain stage in a startup or build process. @@ -1702,9 +1712,30 @@ export interface BuildTypes export function makeSchemaInternal(config: SchemaConfig) { const builder = new SchemaBuilder(config) builder.addTypes(config.types) + if (config.schemaRoots) { + builder.addTypes(config.schemaRoots) + } const { finalConfig, typeMap, missingTypes, schemaExtension, onAfterBuildFns } = builder.getFinalTypeMap() const { Query, Mutation, Subscription } = typeMap + function getRootType(rootType: 'query' | 'mutation' | 'subscription', defaultType: string) { + const rootTypeVal = config.schemaRoots?.[rootType] ?? defaultType + let returnVal: null | GraphQLNamedType = null + if (typeof rootTypeVal === 'string') { + returnVal = typeMap[rootTypeVal] + } else if (rootTypeVal) { + if (isNexusObjectTypeDef(rootTypeVal)) { + returnVal = typeMap[rootTypeVal.name] + } else if (isObjectType(rootTypeVal)) { + returnVal = typeMap[rootTypeVal.name] + } + } + if (returnVal && !isObjectType(returnVal)) { + throw new Error(`Expected ${rootType} to be a objectType, saw ${returnVal.constructor.name}`) + } + return returnVal + } + /* istanbul ignore next */ if (!isObjectType(Query)) { throw new Error(`Expected Query to be a objectType, saw ${Query.constructor.name}`) @@ -1719,9 +1750,9 @@ export function makeSchemaInternal(config: SchemaConfig) { } const schema = new GraphQLSchema({ - query: Query, - mutation: Mutation, - subscription: Subscription, + query: getRootType('query', 'Query'), + mutation: getRootType('mutation', 'Mutation'), + subscription: getRootType('subscription', 'Subscription'), types: objValues(typeMap), extensions: { ...config.extensions, diff --git a/tests/__snapshots__/builder.spec.ts.snap b/tests/__snapshots__/builder.spec.ts.snap new file mode 100644 index 00000000..a098d609 --- /dev/null +++ b/tests/__snapshots__/builder.spec.ts.snap @@ -0,0 +1,56 @@ +// Jest Snapshot v1, https://goo.gl/fbAQLP + +exports[`builder can replace the Mutation root type with an alternate type 1`] = ` +"schema { + query: Query + mutation: RootMutation +} + +type Mutation { + ok: String +} + +type Query { + ok: Boolean! +} + +type RootMutation { + name: String +} +" +`; + +exports[`builder can replace the Query root type with an alternate type 1`] = ` +"schema { + query: RootQuery +} + +type Query { + ok: String +} + +type RootQuery { + name: String +} +" +`; + +exports[`builder can replace the Subscription root type with an alternate type 1`] = ` +"schema { + query: Query + subscription: RootSubscription +} + +type Query { + ok: Boolean! +} + +type RootSubscription { + name: String +} + +type Subscription { + ok: String +} +" +`; diff --git a/tests/builder.spec.ts b/tests/builder.spec.ts new file mode 100644 index 00000000..837375ef --- /dev/null +++ b/tests/builder.spec.ts @@ -0,0 +1,76 @@ +import { lexicographicSortSchema, printSchema } from 'graphql' +import { makeSchema, objectType } from '../src' + +describe('builder', () => { + it('can replace the Query root type with an alternate type', () => { + const OtherQuery = objectType({ + name: 'RootQuery', + definition(t) { + t.string('name') + }, + }) + + const Query = objectType({ + name: 'Query', + definition(t) { + t.string('ok') + }, + }) + + const schema = makeSchema({ + types: [OtherQuery, Query], + schemaRoots: { + query: OtherQuery, + }, + }) + expect(printSchema(lexicographicSortSchema(schema))).toMatchSnapshot() + }) + + it('can replace the Mutation root type with an alternate type', () => { + const OtherMutation = objectType({ + name: 'RootMutation', + definition(t) { + t.string('name') + }, + }) + + const Mutation = objectType({ + name: 'Mutation', + definition(t) { + t.string('ok') + }, + }) + + const schema = makeSchema({ + types: [OtherMutation, Mutation], + schemaRoots: { + mutation: OtherMutation, + }, + }) + expect(printSchema(lexicographicSortSchema(schema))).toMatchSnapshot() + }) + + it('can replace the Subscription root type with an alternate type', () => { + const OtherSubscription = objectType({ + name: 'RootSubscription', + definition(t) { + t.string('name') + }, + }) + + const Subscription = objectType({ + name: 'Subscription', + definition(t) { + t.string('ok') + }, + }) + + const schema = makeSchema({ + types: [OtherSubscription, Subscription], + schemaRoots: { + subscription: OtherSubscription, + }, + }) + expect(printSchema(lexicographicSortSchema(schema))).toMatchSnapshot() + }) +})