Comparing version 0.7.0-alpha.2 to 0.9.0
@@ -1,5 +0,134 @@ | ||
import { GraphQLDirective, GraphQLEnumType, GraphQLEnumValueConfigMap, GraphQLFieldConfig, GraphQLFieldConfigArgumentMap, GraphQLFieldConfigMap, GraphQLFieldResolver, GraphQLInputFieldConfig, GraphQLInputFieldConfigMap, GraphQLInputObjectType, GraphQLInputType, GraphQLInterfaceType, GraphQLNamedType, GraphQLObjectType, GraphQLOutputType, GraphQLScalarType, GraphQLUnionType, GraphQLSchema } from "graphql"; | ||
import { Metadata } from "./metadata"; | ||
import { DirectiveTypeDef, WrappedType } from "./core"; | ||
import * as Types from "./types"; | ||
import { | ||
GraphQLEnumType, | ||
GraphQLFieldConfig, | ||
GraphQLFieldConfigArgumentMap, | ||
GraphQLFieldConfigMap, | ||
GraphQLFieldResolver, | ||
GraphQLInputFieldConfig, | ||
GraphQLInputFieldConfigMap, | ||
GraphQLInputObjectType, | ||
GraphQLInputType, | ||
GraphQLInterfaceType, | ||
GraphQLNamedType, | ||
GraphQLObjectType, | ||
GraphQLOutputType, | ||
GraphQLScalarType, | ||
GraphQLSchema, | ||
GraphQLUnionType, | ||
} from "graphql"; | ||
import { NexusArgConfig, NexusArgDef } from "./definitions/args"; | ||
import { | ||
NexusInputFieldDef, | ||
NexusOutputFieldDef, | ||
} from "./definitions/definitionBlocks"; | ||
import { EnumTypeConfig } from "./definitions/enumType"; | ||
import { | ||
NexusExtendTypeConfig, | ||
NexusExtendTypeDef, | ||
} from "./definitions/extendType"; | ||
import { NexusInputObjectTypeConfig } from "./definitions/inputObjectType"; | ||
import { | ||
NexusInterfaceTypeConfig, | ||
NexusInterfaceTypeDef, | ||
} from "./definitions/interfaceType"; | ||
import { | ||
NexusObjectTypeConfig, | ||
NexusObjectTypeDef, | ||
} from "./definitions/objectType"; | ||
import { NexusScalarTypeConfig } from "./definitions/scalarType"; | ||
import { NexusUnionTypeConfig, UnionMembers } from "./definitions/unionType"; | ||
import { | ||
AllNexusInputTypeDefs, | ||
AllNexusNamedTypeDefs, | ||
} from "./definitions/wrapping"; | ||
import { | ||
GraphQLPossibleInputs, | ||
GraphQLPossibleOutputs, | ||
NonNullConfig, | ||
} from "./definitions/_types"; | ||
import { TypegenAutoConfigOptions } from "./typegenAutoConfig"; | ||
import { TypegenFormatFn } from "./typegenFormatPrettier"; | ||
import { GetGen } from "./typegenTypeHelpers"; | ||
export declare type Maybe<T> = T | null; | ||
export interface BuilderConfig { | ||
/** | ||
* When the schema starts and `process.env.NODE_ENV !== "production"`, | ||
* artifact files are auto-generated containing the .graphql definitions of | ||
* the schema | ||
*/ | ||
outputs: | ||
| { | ||
/** | ||
* Absolute path where the GraphQL IDL file should be written | ||
*/ | ||
schema: string | false; | ||
/** | ||
* File path where generated types should be saved | ||
*/ | ||
typegen: string | false; | ||
} | ||
| false; | ||
/** | ||
* Whether the schema & types are generated when the server | ||
* starts. Default is !process.env.NODE_ENV || process.env.NODE_ENV !== "development" | ||
*/ | ||
shouldGenerateArtifacts?: boolean; | ||
/** | ||
* Automatically configure type resolution for the TypeScript | ||
* representations of the associated types. | ||
* | ||
* Alias for typegenConfig: typegenAutoConfig(options) | ||
*/ | ||
typegenAutoConfig?: TypegenAutoConfigOptions; | ||
/** | ||
* A configuration function for advanced cases where | ||
* more control over the `TypegenInfo` is needed. | ||
*/ | ||
typegenConfig?: ( | ||
schema: GraphQLSchema, | ||
outputPath: string | ||
) => TypegenInfo | PromiseLike<TypegenInfo>; | ||
/** | ||
* Either an absolute path to a .prettierrc file, or an object | ||
* with relevant Prettier rules to be used on the generated output | ||
*/ | ||
prettierConfig?: string | object; | ||
/** | ||
* Manually apply a formatter to the generated content before saving, | ||
* see the `prettierConfig` option if you want to use Prettier. | ||
*/ | ||
formatTypegen?: TypegenFormatFn; | ||
/** | ||
* Configures the default "nonNullDefaults" for the entire schema the type. | ||
* Read more about how nexus handles nullability | ||
*/ | ||
nonNullDefaults?: NonNullConfig; | ||
} | ||
export interface TypegenInfo { | ||
/** | ||
* Headers attached to the generate type output | ||
*/ | ||
headers: string[]; | ||
/** | ||
* All imports for the backing types / context | ||
*/ | ||
imports: string[]; | ||
/** | ||
* A map of all GraphQL types and what TypeScript types they should | ||
* be represented by. | ||
*/ | ||
backingTypeMap: { [K in GetGen<"objectNames">]?: string }; | ||
/** | ||
* The type of the context for the resolvers | ||
*/ | ||
contextType?: string; | ||
} | ||
export interface SchemaConfig extends BuilderConfig { | ||
/** | ||
* All of the GraphQL types. This is an any for simplicity of developer experience, | ||
* if it's an object we get the values, if it's an array we flatten out the | ||
* valid types, ignoring invalid ones. | ||
*/ | ||
types: any; | ||
} | ||
/** | ||
@@ -11,66 +140,140 @@ * Builds all of the types, properly accounts for any using "mix". | ||
export declare class SchemaBuilder { | ||
protected metadata: Metadata; | ||
protected config: Types.BuilderConfig; | ||
/** | ||
* Used to check for circular references. | ||
*/ | ||
protected buildingTypes: Set<any>; | ||
/** | ||
* The "final type" map contains all types as they are built. | ||
*/ | ||
protected finalTypeMap: Record<string, GraphQLNamedType>; | ||
/** | ||
* The "defined type" map keeps track of all of the types that were | ||
* defined directly as `GraphQL*Type` objects, so we don't accidentally | ||
* overwrite any. | ||
*/ | ||
protected definedTypeMap: Record<string, GraphQLNamedType>; | ||
/** | ||
* The "pending type" map keeps track of all types that were defined w/ | ||
* GraphQL Nexus and haven't been processed into concrete types yet. | ||
*/ | ||
protected pendingTypeMap: Record<string, Types.NamedTypeDef>; | ||
protected pendingDirectiveMap: Record<string, DirectiveTypeDef<any>>; | ||
protected directiveMap: Record<string, GraphQLDirective>; | ||
protected nullability: Types.NullabilityConfig; | ||
constructor(metadata: Metadata, config: Types.BuilderConfig); | ||
getConfig(): Types.BuilderConfig; | ||
addType(typeDef: Types.NamedTypeDef | GraphQLNamedType): void; | ||
addDirective(directiveDef: DirectiveTypeDef<any> | GraphQLDirective): void; | ||
getFinalTypeMap(): Types.BuildTypes<any, any>; | ||
directiveType(config: Types.DirectiveTypeConfig): GraphQLDirective; | ||
inputObjectType(config: Types.InputTypeConfig): GraphQLInputObjectType; | ||
objectType(config: Types.ObjectTypeConfig): GraphQLObjectType; | ||
interfaceType(config: Types.InterfaceTypeConfig): GraphQLInterfaceType; | ||
enumType(config: Types.EnumTypeConfig): GraphQLEnumType; | ||
unionType(config: Types.UnionTypeConfig): GraphQLUnionType; | ||
protected missingType(typeName: string): GraphQLNamedType; | ||
protected buildEnumMembers(config: Types.EnumTypeConfig): GraphQLEnumValueConfigMap; | ||
protected buildUnionMembers(config: Types.UnionTypeConfig): GraphQLObjectType[]; | ||
protected buildObjectFields(typeConfig: Types.ObjectTypeConfig | Types.InterfaceTypeConfig): GraphQLFieldConfigMap<any, any>; | ||
protected buildInputObjectFields(typeConfig: Types.InputTypeConfig): GraphQLInputFieldConfigMap; | ||
protected buildObjectField(fieldConfig: Types.OutputFieldConfig, typeConfig: Types.ObjectTypeConfig | Types.InterfaceTypeConfig): GraphQLFieldConfig<any, any>; | ||
protected buildInputObjectField(field: Types.InputFieldConfig, typeConfig: Types.InputTypeConfig): GraphQLInputFieldConfig; | ||
protected buildArgs(args: Types.OutputFieldArgs, typeConfig: Types.InputTypeConfig): GraphQLFieldConfigArgumentMap; | ||
protected decorateInputType(type: GraphQLInputType, fieldConfig: Types.InputFieldConfig, typeConfig: Types.InputTypeConfig): GraphQLInputType; | ||
protected decorateOutputType(type: GraphQLOutputType, fieldConfig: Types.FieldConfig, typeConfig: Types.ObjectTypeConfig | Types.InterfaceTypeConfig): GraphQLOutputType; | ||
protected decorateArgType(type: GraphQLInputType, argOpts: Types.ArgDefinition & { | ||
name: string; | ||
}, typeConfig: Types.InputTypeConfig): GraphQLInputType; | ||
/** | ||
* Adds the null / list configuration to the type. | ||
*/ | ||
protected decorateType(type: GraphQLOutputType, fieldConfig: Types.Omit<Types.FieldConfig, "type" | "default">, typeConfig: Types.ObjectTypeConfig | Types.InterfaceTypeConfig, isInput: false): GraphQLOutputType; | ||
protected decorateType(type: GraphQLInputType, fieldConfig: Types.Omit<Types.FieldConfig, "type" | "default">, typeConfig: Types.InputTypeConfig, isInput: true): GraphQLInputType; | ||
protected getInterface(name: string): GraphQLInterfaceType; | ||
protected getEnum(name: string): GraphQLEnumType; | ||
protected getUnion(name: string): GraphQLUnionType; | ||
protected getInputType(name: string): GraphQLScalarType | GraphQLEnumType | GraphQLInputObjectType; | ||
protected getOutputType(name: string): GraphQLObjectType | GraphQLInterfaceType | GraphQLUnionType | GraphQLScalarType | GraphQLEnumType; | ||
protected getObjectType(name: string): GraphQLObjectType; | ||
protected getOrBuildType(name: string): GraphQLNamedType; | ||
protected getResolver(fieldOptions: Types.OutputFieldConfig, typeConfig: Types.ObjectTypeConfig | Types.InterfaceTypeConfig): GraphQLFieldResolver<any, any, { | ||
[argName: string]: any; | ||
}>; | ||
protected config: BuilderConfig; | ||
/** | ||
* Used to check for circular references. | ||
*/ | ||
protected buildingTypes: Set<any>; | ||
/** | ||
* The "final type" map contains all types as they are built. | ||
*/ | ||
protected finalTypeMap: Record<string, GraphQLNamedType>; | ||
/** | ||
* The "defined type" map keeps track of all of the types that were | ||
* defined directly as `GraphQL*Type` objects, so we don't accidentally | ||
* overwrite any. | ||
*/ | ||
protected definedTypeMap: Record<string, GraphQLNamedType>; | ||
/** | ||
* The "pending type" map keeps track of all types that were defined w/ | ||
* Nexus GraphQL and haven't been processed into concrete types yet. | ||
*/ | ||
protected pendingTypeMap: Record<string, AllNexusNamedTypeDefs>; | ||
/** | ||
* All "extensions" to types (adding fields on types from many locations) | ||
*/ | ||
protected typeExtensionMap: Record<string, NexusExtendTypeConfig<string>[]>; | ||
/** | ||
* Configures the root-level nonNullDefaults defaults | ||
*/ | ||
protected nonNullDefaults: NonNullConfig; | ||
/** | ||
* Adds custom dynamic scalar methods to the definition blocks | ||
* tuple: [FieldName, TypeName] | ||
*/ | ||
protected customScalarMethods: [string, string][]; | ||
constructor(config: BuilderConfig); | ||
getConfig(): BuilderConfig; | ||
addType( | ||
typeDef: | ||
| AllNexusNamedTypeDefs | ||
| NexusExtendTypeDef<string> | ||
| GraphQLNamedType | ||
): void; | ||
getFinalTypeMap(): BuildTypes<any>; | ||
inputObjectType( | ||
config: NexusInputObjectTypeConfig<any> | ||
): GraphQLInputObjectType; | ||
objectType(config: NexusObjectTypeConfig<any>): GraphQLObjectType; | ||
interfaceType(config: NexusInterfaceTypeConfig<any>): GraphQLInterfaceType; | ||
withScalarMethods<T extends NexusGenCustomScalarMethods<string>>( | ||
definitionBlock: T | ||
): T; | ||
enumType(config: EnumTypeConfig<any>): GraphQLEnumType; | ||
unionType(config: NexusUnionTypeConfig<any>): GraphQLUnionType; | ||
scalarType(config: NexusScalarTypeConfig<string>): GraphQLScalarType; | ||
protected missingType(typeName: string): GraphQLNamedType; | ||
protected buildUnionMembers( | ||
unionName: string, | ||
members: UnionMembers | undefined | ||
): GraphQLObjectType[]; | ||
protected buildObjectFields( | ||
fields: NexusOutputFieldDef[], | ||
typeConfig: NexusObjectTypeConfig<any> | NexusInterfaceTypeConfig<any>, | ||
intoObject: GraphQLFieldConfigMap<any, any>, | ||
forInterface?: boolean | ||
): GraphQLFieldConfigMap<any, any>; | ||
protected buildInputObjectFields( | ||
fields: NexusInputFieldDef[], | ||
typeConfig: NexusInputObjectTypeConfig<string> | ||
): GraphQLInputFieldConfigMap; | ||
protected buildObjectField( | ||
fieldConfig: NexusOutputFieldDef, | ||
typeConfig: | ||
| NexusObjectTypeConfig<string> | ||
| NexusInterfaceTypeConfig<string>, | ||
forInterface?: boolean | ||
): GraphQLFieldConfig<any, any>; | ||
protected buildInputObjectField( | ||
field: NexusInputFieldDef, | ||
typeConfig: NexusInputObjectTypeConfig<any> | ||
): GraphQLInputFieldConfig; | ||
protected buildArgs( | ||
args: Record<string, NexusArgDef<string>>, | ||
typeConfig: NexusObjectTypeConfig<string> | NexusInterfaceTypeConfig<string> | ||
): GraphQLFieldConfigArgumentMap; | ||
protected inputNonNull( | ||
typeDef: | ||
| NexusObjectTypeConfig<any> | ||
| NexusInterfaceTypeConfig<any> | ||
| NexusInputObjectTypeConfig<any>, | ||
field: NexusInputFieldDef | NexusArgConfig<any> | ||
): boolean; | ||
protected outputNonNull( | ||
typeDef: NexusObjectTypeConfig<any> | NexusInterfaceTypeConfig<any>, | ||
field: NexusOutputFieldDef | ||
): boolean; | ||
protected decorateType<T extends GraphQLNamedType>( | ||
type: T, | ||
list: null | undefined | true | boolean[], | ||
isNonNull: boolean | ||
): T; | ||
protected decorateList<T extends GraphQLOutputType | GraphQLInputType>( | ||
type: T, | ||
list: true | boolean[] | ||
): T; | ||
protected getInterface( | ||
name: string | NexusInterfaceTypeDef<string> | ||
): GraphQLInterfaceType; | ||
protected getEnum(name: string): GraphQLEnumType; | ||
protected getUnion(name: string): GraphQLUnionType; | ||
protected getInputObjectType(name: string): GraphQLInputObjectType; | ||
protected getInputType( | ||
name: string | AllNexusInputTypeDefs | ||
): GraphQLPossibleInputs; | ||
protected getOutputType(name: string): GraphQLPossibleOutputs; | ||
protected getObjectType( | ||
name: string | NexusObjectTypeDef<string> | ||
): GraphQLObjectType; | ||
protected getOrBuildType( | ||
name: string | AllNexusNamedTypeDefs | ||
): GraphQLNamedType; | ||
protected getResolver( | ||
fieldOptions: NexusOutputFieldDef, | ||
typeConfig: NexusObjectTypeConfig<any> | NexusInterfaceTypeConfig<any>, | ||
forInterface?: boolean | ||
): | ||
| GraphQLFieldResolver< | ||
any, | ||
any, | ||
{ | ||
[argName: string]: any; | ||
} | ||
> | ||
| undefined; | ||
} | ||
export interface BuildTypes< | ||
TypeMapDefs extends Record<string, GraphQLNamedType> | ||
> { | ||
typeMap: TypeMapDefs; | ||
} | ||
/** | ||
@@ -81,13 +284,22 @@ * Builds the types, normalizing the "types" passed into the schema for a | ||
*/ | ||
export declare function buildTypes<TypeMapDefs extends Record<string, GraphQLNamedType> = any, DirectiveDefs extends Record<string, GraphQLDirective> = any>(types: any, config?: Types.BuilderConfig, SchemaBuilderClass?: typeof SchemaBuilder, MetadataClass?: typeof Metadata): Types.BuildTypes<TypeMapDefs, DirectiveDefs>; | ||
export declare function buildTypes< | ||
TypeMapDefs extends Record<string, GraphQLNamedType> = any | ||
>( | ||
types: any, | ||
config?: BuilderConfig, | ||
SchemaBuilderClass?: typeof SchemaBuilder | ||
): BuildTypes<TypeMapDefs>; | ||
/** | ||
* Builds the schema, returning both the schema and metadata. | ||
* Builds the schema, we may return more than just the schema | ||
* from this one day. | ||
*/ | ||
export declare function makeSchemaWithMetadata(options: Types.SchemaConfig, SchemaBuilderClass?: typeof SchemaBuilder, MetadataClass?: typeof Metadata): { | ||
metadata: Metadata; | ||
schema: GraphQLSchema; | ||
export declare function makeSchemaInternal( | ||
options: SchemaConfig, | ||
SchemaBuilderClass?: typeof SchemaBuilder | ||
): { | ||
schema: GraphQLSchema; | ||
}; | ||
/** | ||
* Defines the GraphQL schema, by combining the GraphQL types defined | ||
* by the GraphQL Nexus layer or any manually defined GraphQLType objects. | ||
* by the Nexus GraphQL layer or any manually defined GraphQLType objects. | ||
* | ||
@@ -97,4 +309,2 @@ * Requires at least one type be named "Query", which will be used as the | ||
*/ | ||
export declare function makeSchema(options: Types.SchemaConfig): GraphQLSchema; | ||
export declare function isWrappedTypeDef(obj: any): obj is WrappedType; | ||
export declare function isNamedTypeDef(obj: any): obj is Types.NamedTypeDef; | ||
export declare function makeSchema(options: SchemaConfig): GraphQLSchema; |
@@ -5,18 +5,10 @@ "use strict"; | ||
var graphql_1 = require("graphql"); | ||
var metadata_1 = require("./metadata"); | ||
var core_1 = require("./core"); | ||
var Types = tslib_1.__importStar(require("./types")); | ||
var util_1 = require("util"); | ||
var definitionBlocks_1 = require("./definitions/definitionBlocks"); | ||
var interfaceType_1 = require("./definitions/interfaceType"); | ||
var objectType_1 = require("./definitions/objectType"); | ||
var unionType_1 = require("./definitions/unionType"); | ||
var wrapping_1 = require("./definitions/wrapping"); | ||
var typegenMetadata_1 = require("./typegenMetadata"); | ||
var utils_1 = require("./utils"); | ||
var util_1 = require("util"); | ||
var isPromise = function (val) { | ||
return Boolean(val && typeof val.then === "function"); | ||
}; | ||
var NULL_DEFAULTS = { | ||
output: false, | ||
outputList: false, | ||
outputListItem: false, | ||
input: true, | ||
inputList: true, | ||
inputListItem: false, | ||
}; | ||
var SCALARS = { | ||
@@ -35,4 +27,3 @@ String: graphql_1.GraphQLString, | ||
var SchemaBuilder = /** @class */ (function () { | ||
function SchemaBuilder(metadata, config) { | ||
this.metadata = metadata; | ||
function SchemaBuilder(config) { | ||
this.config = config; | ||
@@ -55,9 +46,18 @@ /** | ||
* The "pending type" map keeps track of all types that were defined w/ | ||
* GraphQL Nexus and haven't been processed into concrete types yet. | ||
* Nexus GraphQL and haven't been processed into concrete types yet. | ||
*/ | ||
this.pendingTypeMap = {}; | ||
this.pendingDirectiveMap = {}; | ||
this.directiveMap = {}; | ||
this.nullability = {}; | ||
this.nullability = config.nullability || {}; | ||
/** | ||
* All "extensions" to types (adding fields on types from many locations) | ||
*/ | ||
this.typeExtensionMap = {}; | ||
/** | ||
* Configures the root-level nonNullDefaults defaults | ||
*/ | ||
this.nonNullDefaults = {}; | ||
/** | ||
* Adds custom dynamic scalar methods to the definition blocks | ||
* tuple: [FieldName, TypeName] | ||
*/ | ||
this.customScalarMethods = []; | ||
} | ||
@@ -69,2 +69,8 @@ SchemaBuilder.prototype.getConfig = function () { | ||
var existingType = this.finalTypeMap[typeDef.name] || this.pendingTypeMap[typeDef.name]; | ||
if (wrapping_1.isNexusExtendTypeDef(typeDef)) { | ||
this.typeExtensionMap[typeDef.name] = | ||
this.typeExtensionMap[typeDef.name] || []; | ||
this.typeExtensionMap[typeDef.name].push(typeDef.value); | ||
return; | ||
} | ||
if (existingType) { | ||
@@ -77,4 +83,18 @@ // Allow importing the same exact type more than once. | ||
} | ||
if (wrapping_1.isNexusScalarTypeDef(typeDef) && typeDef.value.asNexusMethod) { | ||
this.customScalarMethods.push([ | ||
typeDef.value.asNexusMethod, | ||
typeDef.name, | ||
]); | ||
} | ||
else if (graphql_1.isScalarType(typeDef)) { | ||
var scalarDef = typeDef; | ||
if (scalarDef.asNexusMethod) { | ||
this.customScalarMethods.push([ | ||
scalarDef.asNexusMethod, | ||
scalarDef.name, | ||
]); | ||
} | ||
} | ||
if (graphql_1.isNamedType(typeDef)) { | ||
this.metadata.addExternalType(typeDef); | ||
this.finalTypeMap[typeDef.name] = typeDef; | ||
@@ -87,10 +107,2 @@ this.definedTypeMap[typeDef.name] = typeDef; | ||
}; | ||
SchemaBuilder.prototype.addDirective = function (directiveDef) { | ||
if (graphql_1.isDirective(directiveDef)) { | ||
this.directiveMap[directiveDef.name] = directiveDef; | ||
} | ||
else { | ||
this.pendingDirectiveMap[directiveDef.name] = directiveDef; | ||
} | ||
}; | ||
SchemaBuilder.prototype.getFinalTypeMap = function () { | ||
@@ -110,20 +122,16 @@ var _this = this; | ||
}); | ||
Object.keys(this.pendingDirectiveMap).forEach(function (key) { }); | ||
return { | ||
typeMap: this.finalTypeMap, | ||
metadata: this.metadata, | ||
directiveMap: this.directiveMap, | ||
}; | ||
}; | ||
SchemaBuilder.prototype.directiveType = function (config) { | ||
return new graphql_1.GraphQLDirective({ | ||
name: config.name, | ||
locations: [], | ||
}); | ||
}; | ||
SchemaBuilder.prototype.inputObjectType = function (config) { | ||
var _this = this; | ||
var fields = []; | ||
var definitionBlock = new definitionBlocks_1.InputDefinitionBlock({ | ||
addField: function (field) { return fields.push(field); }, | ||
}); | ||
config.definition(this.withScalarMethods(definitionBlock)); | ||
return new graphql_1.GraphQLInputObjectType({ | ||
name: config.name, | ||
fields: function () { return _this.buildInputObjectFields(config); }, | ||
fields: function () { return _this.buildInputObjectFields(fields, config); }, | ||
description: config.description, | ||
@@ -134,20 +142,35 @@ }); | ||
var _this = this; | ||
this.metadata.addObjectType(config); | ||
var fields = []; | ||
var interfaces = []; | ||
var modifications = {}; | ||
var definitionBlock = new objectType_1.ObjectDefinitionBlock({ | ||
addField: function (fieldDef) { return fields.push(fieldDef); }, | ||
addInterfaces: function (interfaceDefs) { return interfaces.push.apply(interfaces, interfaceDefs); }, | ||
addFieldModifications: function (mods) { | ||
modifications[mods.field] = modifications[mods.field] || []; | ||
modifications[mods.field].push(mods); | ||
}, | ||
}); | ||
config.definition(this.withScalarMethods(definitionBlock)); | ||
var extensions = this.typeExtensionMap[config.name]; | ||
if (extensions) { | ||
extensions.forEach(function (extension) { | ||
extension.definition(definitionBlock); | ||
}); | ||
} | ||
return new graphql_1.GraphQLObjectType({ | ||
name: config.name, | ||
interfaces: function () { return config.interfaces.map(function (i) { return _this.getInterface(i); }); }, | ||
interfaces: function () { return interfaces.map(function (i) { return _this.getInterface(i); }); }, | ||
description: config.description, | ||
fields: function () { | ||
var interfaceFields = {}; | ||
var allInterfaces = config.interfaces.map(function (i) { | ||
return _this.getInterface(i); | ||
}); | ||
var allFieldsMap = {}; | ||
var allInterfaces = interfaces.map(function (i) { return _this.getInterface(i); }); | ||
allInterfaces.forEach(function (i) { | ||
var iFields = i.getFields(); | ||
var interfaceFields = i.getFields(); | ||
// We need to take the interface fields and reconstruct them | ||
// this actually simplifies things becuase if we've modified | ||
// the field at all it needs to happen here. | ||
Object.keys(iFields).forEach(function (iFieldName) { | ||
var _a = iFields[iFieldName], isDeprecated = _a.isDeprecated, args = _a.args, rest = tslib_1.__rest(_a, ["isDeprecated", "args"]); | ||
interfaceFields[iFieldName] = tslib_1.__assign({}, rest, { args: args.reduce(function (result, arg) { | ||
Object.keys(interfaceFields).forEach(function (iFieldName) { | ||
var _a = interfaceFields[iFieldName], isDeprecated = _a.isDeprecated, args = _a.args, rest = tslib_1.__rest(_a, ["isDeprecated", "args"]); | ||
allFieldsMap[iFieldName] = tslib_1.__assign({}, rest, { args: args.reduce(function (result, arg) { | ||
var name = arg.name, argRest = tslib_1.__rest(arg, ["name"]); | ||
@@ -157,5 +180,16 @@ result[name] = argRest; | ||
}, {}) }); | ||
var mods = modifications[iFieldName]; | ||
if (mods) { | ||
mods.map(function (mod) { | ||
if (typeof mod.description !== "undefined") { | ||
allFieldsMap[iFieldName].description = mod.description; | ||
} | ||
if (typeof mod.resolve !== "undefined") { | ||
allFieldsMap[iFieldName].resolve = mod.resolve; | ||
} | ||
}); | ||
} | ||
}); | ||
}); | ||
return tslib_1.__assign({}, interfaceFields, _this.buildObjectFields(config)); | ||
return _this.buildObjectFields(fields, config, allFieldsMap); | ||
}, | ||
@@ -166,6 +200,23 @@ }); | ||
var _this = this; | ||
var name = config.name, resolveType = config.resolveType, description = config.description; | ||
var name = config.name, description = config.description; | ||
var resolveType; | ||
var fields = []; | ||
var definitionBlock = new interfaceType_1.InterfaceDefinitionBlock({ | ||
addField: function (field) { return fields.push(field); }, | ||
setResolveType: function (fn) { return (resolveType = fn); }, | ||
}); | ||
config.definition(this.withScalarMethods(definitionBlock)); | ||
var extensions = this.typeExtensionMap[config.name]; | ||
if (extensions) { | ||
extensions.forEach(function (extension) { | ||
extension.definition(definitionBlock); | ||
}); | ||
} | ||
if (!resolveType) { | ||
throw new Error("Missing resolveType for the " + name + " interface." + | ||
"Be sure to add one in the definition block for the type"); | ||
} | ||
return new graphql_1.GraphQLInterfaceType({ | ||
name: name, | ||
fields: function () { return _this.buildObjectFields(config); }, | ||
fields: function () { return _this.buildObjectFields(fields, config, {}, true); }, | ||
resolveType: resolveType, | ||
@@ -175,6 +226,48 @@ description: description, | ||
}; | ||
SchemaBuilder.prototype.withScalarMethods = function (definitionBlock) { | ||
this.customScalarMethods.forEach(function (_a) { | ||
var methodName = _a[0], typeName = _a[1]; | ||
// @ts-ignore - Yeah, yeah... we know | ||
definitionBlock[methodName] = function (fieldName) { | ||
var opts = []; | ||
for (var _i = 1; _i < arguments.length; _i++) { | ||
opts[_i - 1] = arguments[_i]; | ||
} | ||
// @ts-ignore | ||
this.addScalarField(fieldName, typeName, opts); | ||
}; | ||
}); | ||
return definitionBlock; | ||
}; | ||
SchemaBuilder.prototype.enumType = function (config) { | ||
var members = config.members; | ||
var values = {}; | ||
if (Array.isArray(members)) { | ||
members.forEach(function (m) { | ||
if (typeof m === "string") { | ||
values[m] = { value: m }; | ||
} | ||
else { | ||
values[m.name] = { | ||
value: typeof m.value === "undefined" ? m.name : m.value, | ||
deprecationReason: m.deprecation, | ||
description: m.description, | ||
}; | ||
} | ||
}); | ||
} | ||
else { | ||
Object.keys(members).forEach(function (key) { | ||
values[key] = { | ||
value: members[key], | ||
}; | ||
}); | ||
} | ||
if (!Object.keys(values).length) { | ||
throw new Error("Nexus GraphQL: Enum " + config.name + " must have at least one member"); | ||
} | ||
return new graphql_1.GraphQLEnumType({ | ||
name: config.name, | ||
values: this.buildEnumMembers(config), | ||
values: values, | ||
description: config.description, | ||
}); | ||
@@ -184,8 +277,27 @@ }; | ||
var _this = this; | ||
var members; | ||
var resolveType; | ||
config.definition(new unionType_1.UnionDefinitionBlock({ | ||
addField: function () { }, | ||
setResolveType: function (fn) { return (resolveType = fn); }, | ||
addUnionMembers: function (unionMembers) { return (members = unionMembers); }, | ||
})); | ||
if (!resolveType) { | ||
throw new Error("Missing resolveType for the " + config.name + " union." + | ||
"Be sure to add one in the definition block for the type"); | ||
} | ||
return new graphql_1.GraphQLUnionType({ | ||
name: config.name, | ||
types: function () { return _this.buildUnionMembers(config); }, | ||
resolveType: config.resolveType, | ||
resolveType: resolveType, | ||
description: config.description, | ||
types: function () { return _this.buildUnionMembers(config.name, members); }, | ||
}); | ||
}; | ||
SchemaBuilder.prototype.scalarType = function (config) { | ||
var scalar = new graphql_1.GraphQLScalarType(config); | ||
if (config.asNexusMethod) { | ||
scalar.asNexusMethod = config.asNexusMethod; | ||
} | ||
return scalar; | ||
}; | ||
SchemaBuilder.prototype.missingType = function (typeName) { | ||
@@ -199,101 +311,44 @@ var suggestions = utils_1.suggestionList(typeName, Object.keys(this.buildingTypes).concat(Object.keys(this.finalTypeMap))); | ||
}; | ||
SchemaBuilder.prototype.buildEnumMembers = function (config) { | ||
SchemaBuilder.prototype.buildUnionMembers = function (unionName, members) { | ||
var _this = this; | ||
var values = {}; | ||
config.members.forEach(function (member) { | ||
switch (member.item) { | ||
case Types.NodeType.ENUM_MEMBER: | ||
values[member.info.name] = { | ||
value: member.info.value, | ||
description: member.info.description, | ||
}; | ||
break; | ||
case Types.NodeType.MIX: | ||
var _a = member.mixOptions, pick_1 = _a.pick, omit_1 = _a.omit, typeName = member.typeName; | ||
var enumToMix = _this.getEnum(typeName); | ||
enumToMix.getValues().forEach(function (val) { | ||
if (pick_1 && pick_1.indexOf(val.name) === -1) { | ||
return; | ||
} | ||
if (omit_1 && omit_1.indexOf(val.name) !== -1) { | ||
return; | ||
} | ||
values[val.name] = { | ||
description: val.description, | ||
deprecationReason: val.deprecationReason, | ||
value: val.value, | ||
}; | ||
}); | ||
} | ||
}); | ||
if (!Object.keys(values).length) { | ||
throw new Error("GraphQL Nexus: Enum " + config.name + " must have at least one member"); | ||
var unionMembers = []; | ||
if (!members) { | ||
throw new Error("Missing Union members for " + unionName + "." + | ||
"Make sure to call the t.members(...) method in the union blocks"); | ||
} | ||
return values; | ||
}; | ||
SchemaBuilder.prototype.buildUnionMembers = function (config) { | ||
var _this = this; | ||
var unionMembers = []; | ||
config.members.forEach(function (member) { | ||
switch (member.item) { | ||
case Types.NodeType.UNION_MEMBER: | ||
unionMembers.push(_this.getObjectType(member.typeName)); | ||
break; | ||
case Types.NodeType.MIX: | ||
var _a = member.mixOptions, pick_2 = _a.pick, omit_2 = _a.omit, typeName = member.typeName; | ||
var unionToMix = _this.getUnion(typeName); | ||
unionToMix.getTypes().forEach(function (type) { | ||
if (pick_2 && pick_2.indexOf(type.name) === -1) { | ||
return; | ||
} | ||
if (omit_2 && omit_2.indexOf(type.name) !== -1) { | ||
return; | ||
} | ||
unionMembers.push(type); | ||
}); | ||
break; | ||
} | ||
members.forEach(function (member) { | ||
unionMembers.push(_this.getObjectType(member)); | ||
}); | ||
if (!Object.keys(unionMembers).length) { | ||
throw new Error("GraphQL Nexus: Union " + config.name + " must have at least one member type"); | ||
if (!unionMembers.length) { | ||
throw new Error("Nexus GraphQL: Union " + unionName + " must have at least one member type"); | ||
} | ||
return unionMembers; | ||
}; | ||
SchemaBuilder.prototype.buildObjectFields = function (typeConfig) { | ||
SchemaBuilder.prototype.buildObjectFields = function (fields, typeConfig, intoObject, forInterface) { | ||
var _this = this; | ||
var fieldMap = {}; | ||
typeConfig.fields.forEach(function (field) { | ||
switch (field.item) { | ||
case Types.NodeType.MIX: | ||
throw new Error("TODO"); | ||
break; | ||
case Types.NodeType.FIELD: | ||
fieldMap[field.config.name] = _this.buildObjectField(field.config, typeConfig); | ||
break; | ||
} | ||
if (forInterface === void 0) { forInterface = false; } | ||
fields.forEach(function (field) { | ||
intoObject[field.name] = _this.buildObjectField(field, typeConfig, forInterface); | ||
}); | ||
return fieldMap; | ||
return intoObject; | ||
}; | ||
SchemaBuilder.prototype.buildInputObjectFields = function (typeConfig) { | ||
SchemaBuilder.prototype.buildInputObjectFields = function (fields, typeConfig) { | ||
var _this = this; | ||
var fieldMap = {}; | ||
typeConfig.fields.forEach(function (field) { | ||
switch (field.item) { | ||
case Types.NodeType.MIX: | ||
throw new Error("TODO"); | ||
break; | ||
case Types.NodeType.FIELD: | ||
fieldMap[field.config.name] = _this.buildInputObjectField(field.config, typeConfig); | ||
break; | ||
} | ||
fields.forEach(function (field) { | ||
fieldMap[field.name] = _this.buildInputObjectField(field, typeConfig); | ||
}); | ||
return fieldMap; | ||
}; | ||
SchemaBuilder.prototype.buildObjectField = function (fieldConfig, typeConfig) { | ||
this.metadata.addField(typeConfig.name, fieldConfig); | ||
SchemaBuilder.prototype.buildObjectField = function (fieldConfig, typeConfig, forInterface) { | ||
if (forInterface === void 0) { forInterface = false; } | ||
if (!fieldConfig.type) { | ||
throw new Error("Missing required \"type\" field for " + typeConfig.name + "." + fieldConfig.name); | ||
} | ||
return { | ||
type: this.decorateOutputType(this.getOutputType(fieldConfig.type), fieldConfig, typeConfig), | ||
resolve: this.getResolver(fieldConfig, typeConfig), | ||
type: this.decorateType(this.getOutputType(fieldConfig.type), fieldConfig.list, this.outputNonNull(typeConfig, fieldConfig)), | ||
args: this.buildArgs(fieldConfig.args || {}, typeConfig), | ||
resolve: this.getResolver(fieldConfig, typeConfig, forInterface), | ||
description: fieldConfig.description, | ||
args: this.buildArgs(fieldConfig.args || {}, typeConfig), | ||
deprecationReason: fieldConfig.deprecation, | ||
}; | ||
@@ -303,3 +358,5 @@ }; | ||
return { | ||
type: this.decorateInputType(this.getInputType(field.type), field, typeConfig), | ||
type: this.decorateType(this.getInputType(field.type), field.list, this.inputNonNull(typeConfig, field)), | ||
defaultValue: field.default, | ||
description: field.description, | ||
}; | ||
@@ -311,6 +368,7 @@ }; | ||
Object.keys(args).forEach(function (argName) { | ||
var argDef = args[argName]; | ||
var argDef = args[argName].value; | ||
allArgs[argName] = { | ||
type: _this.decorateArgType(_this.getInputType(argDef.type), tslib_1.__assign({}, argDef, { name: argName }), typeConfig), | ||
type: _this.decorateType(_this.getInputType(argDef.type), argDef.list, _this.inputNonNull(typeConfig, argDef)), | ||
description: argDef.description, | ||
defaultValue: argDef.default, | ||
}; | ||
@@ -320,58 +378,40 @@ }); | ||
}; | ||
SchemaBuilder.prototype.decorateInputType = function (type, fieldConfig, typeConfig) { | ||
var _required = fieldConfig.required, requiredListItem = fieldConfig.requiredListItem, rest = tslib_1.__rest(fieldConfig, ["required", "requiredListItem"]); | ||
var newOpts = rest; | ||
if (typeof _required !== "undefined") { | ||
newOpts.nullable = !_required; | ||
SchemaBuilder.prototype.inputNonNull = function (typeDef, field) { | ||
var nullable = field.nullable, required = field.required; | ||
var name = typeDef.name, _a = typeDef.nonNullDefaults, nonNullDefaults = _a === void 0 ? {} : _a; | ||
if (typeof nullable !== "undefined" && typeof required !== "undefined") { | ||
throw new Error("Cannot set both nullable & required on " + name); | ||
} | ||
if (typeof requiredListItem !== "undefined") { | ||
if (rest.list) { | ||
newOpts.listItemNullable = !requiredListItem; | ||
} | ||
if (typeof nullable !== "undefined") { | ||
return !nullable; | ||
} | ||
return this.decorateType(type, newOpts, typeConfig, true); | ||
if (typeof required !== "undefined") { | ||
return required; | ||
} | ||
// Null by default | ||
return utils_1.firstDefined(nonNullDefaults.input, this.nonNullDefaults.input, false); | ||
}; | ||
SchemaBuilder.prototype.decorateOutputType = function (type, fieldConfig, typeConfig) { | ||
return this.decorateType(type, fieldConfig, typeConfig, false); | ||
SchemaBuilder.prototype.outputNonNull = function (typeDef, field) { | ||
var nullable = field.nullable; | ||
var _a = typeDef.nonNullDefaults, nonNullDefaults = _a === void 0 ? {} : _a; | ||
if (typeof nullable !== "undefined") { | ||
return !nullable; | ||
} | ||
// Non-Null by default | ||
return utils_1.firstDefined(nonNullDefaults.output, this.nonNullDefaults.output, true); | ||
}; | ||
SchemaBuilder.prototype.decorateArgType = function (type, argOpts, typeConfig) { | ||
var _required = argOpts.required, requiredListItem = argOpts.requiredListItem, rest = tslib_1.__rest(argOpts, ["required", "requiredListItem"]); | ||
var newOpts = rest; | ||
if (typeof _required !== "undefined") { | ||
newOpts.nullable = !_required; | ||
SchemaBuilder.prototype.decorateType = function (type, list, isNonNull) { | ||
if (list) { | ||
type = this.decorateList(type, list); | ||
} | ||
if (typeof requiredListItem !== "undefined") { | ||
if (rest.list) { | ||
newOpts.listItemNullable = !requiredListItem; | ||
} | ||
} | ||
return this.decorateType(type, newOpts, typeConfig, true); | ||
return (isNonNull ? graphql_1.GraphQLNonNull(type) : type); | ||
}; | ||
SchemaBuilder.prototype.decorateType = function (type, fieldConfig, typeConfig, isInput) { | ||
SchemaBuilder.prototype.decorateList = function (type, list) { | ||
var finalType = type; | ||
var nullConfig = tslib_1.__assign({}, NULL_DEFAULTS, this.nullability, typeConfig.nullability); | ||
var list = fieldConfig.list, nullable = fieldConfig.nullable, listDepth = fieldConfig.listDepth, listItemNullable = fieldConfig.listItemNullable; | ||
var isNullable = typeof nullable !== "undefined" | ||
? nullable | ||
: list | ||
? isInput | ||
? nullConfig.inputList | ||
: nullConfig.outputList | ||
: isInput | ||
? nullConfig.input | ||
: nullConfig.output; | ||
if (list) { | ||
var depth = listDepth || 1; | ||
var nullableItem = typeof listItemNullable !== "undefined" | ||
? listItemNullable | ||
: isInput | ||
? nullConfig.inputListItem | ||
: nullConfig.outputListItem; | ||
if (Array.isArray(nullableItem) && nullableItem.length !== depth) { | ||
throw new Error("Incorrect listItemNullable array length for " + typeConfig.name + fieldConfig.name + ", expected " + depth + " saw " + nullableItem.length); | ||
} | ||
for (var i = 0; i < depth; i++) { | ||
var isNull = Array.isArray(nullableItem) | ||
? nullableItem[i] | ||
: nullableItem; | ||
if (!Array.isArray(list)) { | ||
return graphql_1.GraphQLList(graphql_1.GraphQLNonNull(type)); | ||
} | ||
if (Array.isArray(list)) { | ||
for (var i = 0; i < list.length; i++) { | ||
var isNull = !list[0]; | ||
if (!isNull) { | ||
@@ -383,8 +423,2 @@ finalType = graphql_1.GraphQLNonNull(finalType); | ||
} | ||
else if (typeof listItemNullable !== "undefined") { | ||
console.log("listItemNullable should only be set with list: true, this option is ignored"); | ||
} | ||
if (!isNullable) { | ||
return graphql_1.GraphQLNonNull(finalType); | ||
} | ||
return finalType; | ||
@@ -413,5 +447,5 @@ }; | ||
}; | ||
SchemaBuilder.prototype.getInputType = function (name) { | ||
SchemaBuilder.prototype.getInputObjectType = function (name) { | ||
var type = this.getOrBuildType(name); | ||
if (!graphql_1.isInputType(type)) { | ||
if (!graphql_1.isInputObjectType(type)) { | ||
throw new Error("Expected " + name + " to be a valid input type, saw " + type.constructor.name); | ||
@@ -421,2 +455,9 @@ } | ||
}; | ||
SchemaBuilder.prototype.getInputType = function (name) { | ||
var type = this.getOrBuildType(name); | ||
if (!graphql_1.isInputObjectType(type) && !graphql_1.isLeafType(type)) { | ||
throw new Error("Expected " + name + " to be a possible input type, saw " + type.constructor.name); | ||
} | ||
return type; | ||
}; | ||
SchemaBuilder.prototype.getOutputType = function (name) { | ||
@@ -430,2 +471,5 @@ var type = this.getOrBuildType(name); | ||
SchemaBuilder.prototype.getObjectType = function (name) { | ||
if (wrapping_1.isNexusNamedTypeDef(name)) { | ||
return this.getObjectType(name.name); | ||
} | ||
var type = this.getOrBuildType(name); | ||
@@ -438,2 +482,6 @@ if (!graphql_1.isObjectType(type)) { | ||
SchemaBuilder.prototype.getOrBuildType = function (name) { | ||
invariantGuard(name); | ||
if (wrapping_1.isNexusNamedTypeDef(name)) { | ||
return this.getOrBuildType(name.name); | ||
} | ||
if (SCALARS[name]) { | ||
@@ -446,18 +494,36 @@ return SCALARS[name]; | ||
if (this.buildingTypes.has(name)) { | ||
throw new Error("GraphQL Nexus: Circular dependency detected, while building types " + Array.from(this.buildingTypes)); | ||
throw new Error("Nexus GraphQL: Circular dependency detected, while building types " + Array.from(this.buildingTypes)); | ||
} | ||
var pendingType = this.pendingTypeMap[name]; | ||
if (pendingType) { | ||
this.buildingTypes.add(name); | ||
return pendingType.buildType(this); | ||
if (wrapping_1.isNexusNamedTypeDef(pendingType)) { | ||
this.buildingTypes.add(pendingType.name); | ||
if (wrapping_1.isNexusObjectTypeDef(pendingType)) { | ||
return this.objectType(pendingType.value); | ||
} | ||
else if (wrapping_1.isNexusInterfaceTypeDef(pendingType)) { | ||
return this.interfaceType(pendingType.value); | ||
} | ||
else if (wrapping_1.isNexusEnumTypeDef(pendingType)) { | ||
return this.enumType(pendingType.value); | ||
} | ||
else if (wrapping_1.isNexusScalarTypeDef(pendingType)) { | ||
return this.scalarType(pendingType.value); | ||
} | ||
else if (wrapping_1.isNexusInputObjectTypeDef(pendingType)) { | ||
return this.inputObjectType(pendingType.value); | ||
} | ||
else if (wrapping_1.isNexusUnionTypeDef(pendingType)) { | ||
return this.unionType(pendingType.value); | ||
} | ||
} | ||
return this.missingType(name); | ||
}; | ||
SchemaBuilder.prototype.getResolver = function (fieldOptions, typeConfig) { | ||
var resolver = typeConfig.defaultResolver || graphql_1.defaultFieldResolver; | ||
SchemaBuilder.prototype.getResolver = function (fieldOptions, typeConfig, forInterface) { | ||
if (forInterface === void 0) { forInterface = false; } | ||
var resolver; | ||
if (fieldOptions.resolve) { | ||
resolver = fieldOptions.resolve; | ||
} | ||
if (typeof fieldOptions.default !== "undefined") { | ||
resolver = withDefaultValue(resolver, fieldOptions.default); | ||
if (!resolver && !forInterface) { | ||
resolver = typeConfig.defaultResolver; | ||
} | ||
@@ -469,23 +535,4 @@ return resolver; | ||
exports.SchemaBuilder = SchemaBuilder; | ||
function withDefaultValue(resolver, defaultValue) { | ||
return function (root, args, ctx, info) { | ||
var result = resolver(root, args, ctx, info); | ||
if (typeof result === "undefined" || result === null) { | ||
return typeof defaultValue === "function" ? defaultValue() : defaultValue; | ||
} | ||
if (isPromise(result)) { | ||
return result.then(function (val) { | ||
if (typeof val === "undefined" || val === null) { | ||
return typeof defaultValue === "function" | ||
? defaultValue() | ||
: defaultValue; | ||
} | ||
return val; | ||
}); | ||
} | ||
return result; | ||
}; | ||
} | ||
function extendError(name) { | ||
return new Error(name + " was already defined as a type, check the docs for extending"); | ||
return new Error(name + " was already defined and imported as a type, check the docs for extending types"); | ||
} | ||
@@ -497,8 +544,6 @@ /** | ||
*/ | ||
function buildTypes(types, config, SchemaBuilderClass, MetadataClass) { | ||
function buildTypes(types, config, SchemaBuilderClass) { | ||
if (config === void 0) { config = { outputs: false }; } | ||
if (SchemaBuilderClass === void 0) { SchemaBuilderClass = SchemaBuilder; } | ||
if (MetadataClass === void 0) { MetadataClass = metadata_1.Metadata; } | ||
var metadata = new MetadataClass(config); | ||
var builder = new SchemaBuilderClass(metadata, config); | ||
var builder = new SchemaBuilderClass(config); | ||
addTypes(builder, types); | ||
@@ -512,15 +557,11 @@ return builder.getFinalTypeMap(); | ||
} | ||
if (isWrappedTypeDef(types)) { | ||
types = types.type; | ||
if (typeof types === "function") { | ||
addTypes(builder, types(builder)); | ||
return; | ||
} | ||
if (wrapping_1.isNexusWrappedFn(types)) { | ||
addTypes(builder, types.fn(builder)); | ||
return; | ||
} | ||
if (isNamedTypeDef(types) || graphql_1.isNamedType(types)) { | ||
if (wrapping_1.isNexusNamedTypeDef(types) || | ||
wrapping_1.isNexusExtendTypeDef(types) || | ||
graphql_1.isNamedType(types)) { | ||
builder.addType(types); | ||
} | ||
else if (types instanceof core_1.DirectiveTypeDef || graphql_1.isDirective(types)) { | ||
builder.addDirective(types); | ||
} | ||
else if (Array.isArray(types)) { | ||
@@ -534,11 +575,11 @@ types.forEach(function (typeDef) { return addTypes(builder, typeDef); }); | ||
/** | ||
* Builds the schema, returning both the schema and metadata. | ||
* Builds the schema, we may return more than just the schema | ||
* from this one day. | ||
*/ | ||
function makeSchemaWithMetadata(options, SchemaBuilderClass, MetadataClass) { | ||
function makeSchemaInternal(options, SchemaBuilderClass) { | ||
if (SchemaBuilderClass === void 0) { SchemaBuilderClass = SchemaBuilder; } | ||
if (MetadataClass === void 0) { MetadataClass = metadata_1.Metadata; } | ||
var _a = buildTypes(options.types, options, SchemaBuilderClass, MetadataClass), typeMap = _a.typeMap, directiveMap = _a.directiveMap, metadata = _a.metadata; | ||
var typeMap = buildTypes(options.types, options, SchemaBuilderClass).typeMap; | ||
var Query = typeMap.Query, Mutation = typeMap.Mutation, Subscription = typeMap.Subscription; | ||
if (!Query) { | ||
console.warn("GraphQL Nexus: You should define a root `Query` type for your schema"); | ||
console.warn("Nexus: You should define a root `Query` type for your schema"); | ||
Query = new graphql_1.GraphQLObjectType({ | ||
@@ -567,12 +608,10 @@ name: "Query", | ||
subscription: Subscription, | ||
directives: graphql_1.specifiedDirectives.concat(utils_1.objValues(directiveMap)), | ||
types: utils_1.objValues(typeMap), | ||
}); | ||
metadata.finishConstruction(); | ||
return { schema: schema, metadata: metadata }; | ||
return { schema: schema }; | ||
} | ||
exports.makeSchemaWithMetadata = makeSchemaWithMetadata; | ||
exports.makeSchemaInternal = makeSchemaInternal; | ||
/** | ||
* Defines the GraphQL schema, by combining the GraphQL types defined | ||
* by the GraphQL Nexus layer or any manually defined GraphQLType objects. | ||
* by the Nexus GraphQL layer or any manually defined GraphQLType objects. | ||
* | ||
@@ -583,10 +622,12 @@ * Requires at least one type be named "Query", which will be used as the | ||
function makeSchema(options) { | ||
var _a = makeSchemaWithMetadata(options), schema = _a.schema, metadata = _a.metadata; | ||
var schema = makeSchemaInternal(options).schema; | ||
// Only in development envs do we want to worry about regenerating the | ||
// schema definition and/or generated types. | ||
var _b = options.shouldGenerateArtifacts, shouldGenerateArtifacts = _b === void 0 ? process.env.NODE_ENV !== "production" : _b; | ||
var _a = options.shouldGenerateArtifacts, shouldGenerateArtifacts = _a === void 0 ? Boolean(!process.env.NODE_ENV || process.env.NODE_ENV === "development") : _a; | ||
if (shouldGenerateArtifacts) { | ||
// Generating in the next tick allows us to use the schema | ||
// in the optional thunk for the typegen config | ||
metadata.generateArtifacts(schema); | ||
new typegenMetadata_1.TypegenMetadata(options).generateArtifacts(schema).catch(function (e) { | ||
console.error(e); | ||
}); | ||
} | ||
@@ -596,14 +637,8 @@ return schema; | ||
exports.makeSchema = makeSchema; | ||
function isWrappedTypeDef(obj) { | ||
return obj instanceof core_1.WrappedType; | ||
function invariantGuard(val) { | ||
if (!Boolean(val)) { | ||
throw new Error("Nexus Error: This should never happen, " + | ||
"please check your code or open a GitHub ticket if you believe this is an issue with Nexus"); | ||
} | ||
} | ||
exports.isWrappedTypeDef = isWrappedTypeDef; | ||
function isNamedTypeDef(obj) { | ||
return (obj instanceof core_1.ObjectTypeDef || | ||
obj instanceof core_1.InputObjectTypeDef || | ||
obj instanceof core_1.EnumTypeDef || | ||
obj instanceof core_1.UnionTypeDef || | ||
obj instanceof core_1.InterfaceTypeDef); | ||
} | ||
exports.isNamedTypeDef = isNamedTypeDef; | ||
//# sourceMappingURL=builder.js.map |
@@ -1,320 +0,19 @@ | ||
import * as Types from "./types"; | ||
import { GraphQLFieldResolver, GraphQLInputObjectType, GraphQLInterfaceType, GraphQLUnionType, GraphQLEnumType, GraphQLIsTypeOfFn, DirectiveLocationEnum, GraphQLObjectType, GraphQLDirective, GraphQLScalarType } from "graphql"; | ||
import { SchemaBuilder, isNamedTypeDef } from "./builder"; | ||
import { Metadata } from "./metadata"; | ||
export { SDLConverter } from "./sdlConverter"; | ||
export { Types }; | ||
export { SchemaBuilder, isNamedTypeDef, Metadata }; | ||
export { typegenAutoConfig } from "./autoConfig"; | ||
declare global { | ||
interface GraphQLNexusGen { | ||
} | ||
} | ||
/** | ||
* Provided to the [objectType](#objectType) function, this | ||
*/ | ||
export declare class ObjectTypeDef<GenTypes = GraphQLNexusGen, TypeName extends string = any> { | ||
readonly name: string; | ||
/** | ||
* All metadata about the object type | ||
*/ | ||
protected typeConfig: Types.ObjectTypeConfig; | ||
constructor(name: string); | ||
/** | ||
* Mixes in an existing field definition or object type | ||
* with the current type. | ||
*/ | ||
mix(typeName: string, options?: Types.MixOpts<any>): void; | ||
/** | ||
* Add an ID field type to the object schema. | ||
*/ | ||
id<FieldName extends string>(name: FieldName, ...opts: Types.ConditionalOutputFieldOpts<GenTypes, TypeName, FieldName>): void; | ||
/** | ||
* Add an Int field type to the object schema. | ||
*/ | ||
int<FieldName extends string>(name: FieldName, ...opts: Types.ConditionalOutputFieldOpts<GenTypes, TypeName, FieldName>): void; | ||
/** | ||
* Add a Float field type to the object schema. | ||
*/ | ||
float<FieldName extends string>(name: FieldName, ...opts: Types.ConditionalOutputFieldOpts<GenTypes, TypeName, FieldName>): void; | ||
/** | ||
* Add a String field type to the object schema. | ||
*/ | ||
string<FieldName extends string>(name: FieldName, ...opts: Types.ConditionalOutputFieldOpts<GenTypes, TypeName, FieldName>): void; | ||
/** | ||
* Add a Boolean field type to the object schema. | ||
*/ | ||
boolean<FieldName extends string>(name: FieldName, ...opts: Types.ConditionalOutputFieldOpts<GenTypes, TypeName, FieldName>): void; | ||
/** | ||
* Adds a new field to the object type | ||
*/ | ||
field<FieldName extends string>(name: FieldName, type: Types.AllOutputTypes<GenTypes> | Types.BaseScalars, ...opts: Types.ConditionalOutputFieldOpts<GenTypes, TypeName, FieldName>): void; | ||
/** | ||
* Declare that an object type implements a particular interface, | ||
* by providing the name of the interface | ||
*/ | ||
implements(...interfaceName: Types.AllInterfaces<GenTypes>[]): void; | ||
/** | ||
* Adds a description to the `GraphQLObjectType` | ||
* | ||
* Descriptions will be output as type annotations in the generated SDL | ||
*/ | ||
description(description: string): void; | ||
/** | ||
* Adds an "isTypeOf" check to the object type. | ||
*/ | ||
isTypeOf(fn: (value: GraphQLIsTypeOfFn<any, any>) => boolean): void; | ||
/** | ||
* Used to modify a field already defined on an interface or mixed-in | ||
* from another type. | ||
* | ||
* At this point the type will not change, but the resolver, | ||
* default, property, or description fields can. | ||
*/ | ||
modify<FieldName extends Types.ObjectTypeFields<GenTypes, TypeName>>(field: FieldName, options: Types.ModifyFieldOpts<GenTypes, TypeName, FieldName>): void; | ||
/** | ||
* Supply the default field resolver for all members of this type | ||
*/ | ||
defaultResolver(resolverFn: GraphQLFieldResolver<Types.RootValue<GenTypes, TypeName>, Types.ContextValue<GenTypes>>): void; | ||
/** | ||
* Adds a directive directly to the object definition | ||
* | ||
* > Should be used rarely, typically only for interpretation by other schema consumers. | ||
*/ | ||
directive(name: string, args?: Record<string, any>): void; | ||
/** | ||
* Configures the nullability for the type, check the | ||
* documentation's "Getting Started" section to learn | ||
* more about GraphQL Nexus's assumptions and configuration | ||
* on nullability. | ||
* | ||
* @param nullability | ||
*/ | ||
nullability(nullability: Types.NullabilityConfig): void; | ||
/** | ||
* @internal | ||
*/ | ||
buildType(builder: SchemaBuilder): GraphQLObjectType; | ||
} | ||
/** | ||
* Backing type for an enum member. | ||
*/ | ||
export declare class EnumTypeDef<GenTypes = GraphQLNexusGen> { | ||
readonly name: string; | ||
protected typeConfig: Types.EnumTypeConfig; | ||
constructor(name: string); | ||
mix<EnumName extends Types.EnumNames<GenTypes>>(typeName: EnumName, options?: Types.MixOpts<Types.EnumMembers<GenTypes, EnumName>>): void; | ||
member(name: string, config?: Types.EnumMemberConfig): void; | ||
/** | ||
* Sets the members of the enum | ||
*/ | ||
members(info: Array<Types.EnumMemberInfo | string>): void; | ||
/** | ||
* Adds a description to the `GraphQLEnumType` | ||
* | ||
* Descriptions will be output as type annotations in the generated SDL | ||
*/ | ||
description(description: string): void; | ||
/** | ||
* Should be used very rarely, adds a directive directly to the | ||
* enum definition - for interpretation by other schema consumers. | ||
*/ | ||
directive(name: string, args?: Record<string, any>): void; | ||
/** | ||
* @internal | ||
*/ | ||
buildType(builder: SchemaBuilder): GraphQLEnumType; | ||
} | ||
/** | ||
* Configure the `GraphQLUnionType` definition | ||
*/ | ||
export declare class UnionTypeDef<GenTypes = GraphQLNexusGen, TypeName extends string = any> { | ||
readonly name: string; | ||
protected typeConfig: Types.UnionTypeConfig; | ||
constructor(name: string); | ||
/** | ||
* Take an existing union and base the type off of that, using the `omit` | ||
* option to exclude members of the other union. | ||
* | ||
* > Note: Circular dependencies between unions are not allowed and will | ||
* trigger an error at build-time. | ||
*/ | ||
mix<UnionTypeName extends string>(type: UnionTypeName, options?: Types.MixOmitOpts<any>): void; | ||
/** | ||
* Add one or more members to the GraphQLUnion. Any types provided should be valid | ||
* object types available to the schema. | ||
*/ | ||
members(...types: Array<Types.ObjectNames<GenTypes>>): void; | ||
/** | ||
* Define a type resolver function for the union type. The Resolver should | ||
* return the type name of the union member that should be fulfilled. | ||
* | ||
* > Providing this is highly recommended. If one is not provided, the | ||
* default implementation will call `isTypeOf` on each implementing Object type. | ||
* | ||
* @see https://github.com/graphql/graphql-js/issues/876#issuecomment-304398882 | ||
*/ | ||
resolveType(typeResolver: Types.TypeResolver<GenTypes, TypeName>): void; | ||
/** | ||
* Should be used very rarely, adds a directive directly to the | ||
* union definition - for interpretation by other schema consumers. | ||
*/ | ||
directive(name: string, args?: Record<string, any>): void; | ||
/** | ||
* @internal | ||
*/ | ||
buildType(builder: SchemaBuilder): GraphQLUnionType; | ||
} | ||
export declare class InterfaceTypeDef<GenTypes = GraphQLNexusGen, TypeName extends string = any> { | ||
readonly name: string; | ||
/** | ||
* Metadata about the object type | ||
*/ | ||
protected typeConfig: Types.InterfaceTypeConfig; | ||
constructor(name: string); | ||
/** | ||
* Mixes in an existing field definition or object type | ||
* with the current type. | ||
*/ | ||
mix(typeName: string, options?: Types.MixOpts<any>): void; | ||
/** | ||
* Add an ID field type to the object schema. | ||
*/ | ||
id<FieldName extends string>(name: FieldName, ...opts: Types.ConditionalOutputFieldOpts<GenTypes, TypeName, FieldName>): void; | ||
/** | ||
* Add an Int field type to the object schema. | ||
*/ | ||
int<FieldName extends string>(name: FieldName, ...opts: Types.ConditionalOutputFieldOpts<GenTypes, TypeName, FieldName>): void; | ||
/** | ||
* Add a Float field type to the object schema. | ||
*/ | ||
float<FieldName extends string>(name: FieldName, ...opts: Types.ConditionalOutputFieldOpts<GenTypes, TypeName, FieldName>): void; | ||
/** | ||
* Add a String field type to the object schema. | ||
*/ | ||
string<FieldName extends string>(name: FieldName, ...opts: Types.ConditionalOutputFieldOpts<GenTypes, TypeName, FieldName>): void; | ||
/** | ||
* Add a Boolean field type to the object schema. | ||
*/ | ||
boolean<FieldName extends string>(name: FieldName, ...opts: Types.ConditionalOutputFieldOpts<GenTypes, TypeName, FieldName>): void; | ||
/** | ||
* Adds a new field to the object type | ||
*/ | ||
field<FieldName extends string>(name: FieldName, type: Types.AllOutputTypes<GenTypes> | Types.BaseScalars, ...opts: Types.ConditionalOutputFieldOpts<GenTypes, TypeName, FieldName>): void; | ||
/** | ||
* Adds a description to the `GraphQLInterfaceType` | ||
* | ||
* Descriptions will be output as type annotations in the generated SDL | ||
*/ | ||
description(description: string): void; | ||
/** | ||
* Optionally provide a custom type resolver function. If one is not provided, | ||
* the default implementation will call `isTypeOf` on each implementing | ||
* Object type. | ||
*/ | ||
resolveType(typeResolver: Types.TypeResolver<GenTypes, TypeName>): void; | ||
/** | ||
* Should be used very rarely, adds a directive directly to the | ||
* interface definition - for interpretation by other schema consumers. | ||
*/ | ||
directive(name: string, args?: Record<string, any>): void; | ||
/** | ||
* @internal | ||
*/ | ||
buildType(builder: SchemaBuilder): GraphQLInterfaceType; | ||
} | ||
export declare class InputObjectTypeDef<GenTypes = GraphQLNexusGen, TypeName extends string = any> { | ||
readonly name: string; | ||
protected typeConfig: Types.InputTypeConfig; | ||
constructor(name: string); | ||
/** | ||
* Add an ID field type to the object schema. | ||
*/ | ||
id(name: string, options?: Types.InputFieldOpts<GenTypes, "ID">): void; | ||
/** | ||
* Add an Int field type to the object schema. | ||
*/ | ||
int(name: string, options?: Types.InputFieldOpts<GenTypes, "Int">): void; | ||
/** | ||
* Add a Float field type to the object schema. | ||
*/ | ||
float(name: string, options?: Types.InputFieldOpts<GenTypes, "Float">): void; | ||
/** | ||
* Add a String field type to the object schema. | ||
*/ | ||
string(name: string, options?: Types.InputFieldOpts<GenTypes, "String">): void; | ||
/** | ||
* Add a Boolean field type to the object schema. | ||
*/ | ||
boolean(name: string, options?: Types.InputFieldOpts<GenTypes, "Boolean">): void; | ||
/** | ||
* Adds a new field to the input object type | ||
*/ | ||
field<FieldName extends string>(name: FieldName, type: Types.AllInputTypes<GenTypes> | Types.BaseScalars, options?: Types.InputFieldOpts<GenTypes, TypeName>): void; | ||
/** | ||
* Adds a description to the `GraphQLInputObjectType` | ||
* | ||
* Descriptions will be output as type annotations in the generated SDL | ||
*/ | ||
description(description: string): void; | ||
/** | ||
* Should be used very rarely, adds a directive directly to the | ||
* input object definition - for interpretation by other schema consumers. | ||
*/ | ||
directive(name: string, args?: Record<string, any>): void; | ||
/** | ||
* Configures the nullability for the type | ||
* | ||
* @see nullability | ||
*/ | ||
nullability(nullability: Types.NullabilityConfig): void; | ||
/** | ||
* @internal | ||
*/ | ||
buildType(builder: SchemaBuilder): GraphQLInputObjectType; | ||
} | ||
export declare class DirectiveTypeDef<GenTypes = GraphQLNexusGen> { | ||
readonly name: string; | ||
protected typeConfig: Types.DirectiveTypeConfig; | ||
constructor(name: string); | ||
description(description: string): void; | ||
locations(...location: DirectiveLocationEnum[]): void; | ||
/** | ||
* Add an ID field type to the object schema. | ||
*/ | ||
id(name: string, options?: Types.InputFieldOpts<GenTypes, "ID">): void; | ||
/** | ||
* Add an Int field type to the object schema. | ||
*/ | ||
int(name: string, options?: Types.InputFieldOpts<GenTypes, "Int">): void; | ||
/** | ||
* Add a Float field type to the object schema. | ||
*/ | ||
float(name: string, options?: Types.InputFieldOpts<GenTypes, "Float">): void; | ||
/** | ||
* Add a String field type to the object schema. | ||
*/ | ||
string(name: string, options?: Types.InputFieldOpts<GenTypes, "String">): void; | ||
/** | ||
* Add a Boolean field type to the object schema. | ||
*/ | ||
boolean(name: string, options?: Types.InputFieldOpts<GenTypes, "Boolean">): void; | ||
/** | ||
* Adds a new field to the input object type | ||
*/ | ||
field<TypeName extends Types.AllInputTypes<GenTypes> | Types.BaseScalars>(name: string, type: TypeName, options?: Types.InputFieldOpts<GenTypes, TypeName>): void; | ||
/** | ||
* @internal | ||
*/ | ||
buildType(builder: SchemaBuilder): GraphQLDirective; | ||
} | ||
/** | ||
* The `WrappedType` exists to signify that the value returned from | ||
* the type construction APIs should not be used externally outside of the | ||
* builder function. It also is useful if you need the SchemaBuilder, in that | ||
* it can take a function which is lazy-evaluated to build the type. | ||
*/ | ||
export declare class WrappedType { | ||
readonly type: Types.NamedTypeDef | DirectiveTypeDef | GraphQLScalarType | ((schema: SchemaBuilder) => WrappedType); | ||
constructor(type: Types.NamedTypeDef | DirectiveTypeDef | GraphQLScalarType | ((schema: SchemaBuilder) => WrappedType)); | ||
} | ||
export * from "./builder"; | ||
export * from "./sdlConverter"; | ||
export * from "./typegen"; | ||
export * from "./typegenAutoConfig"; | ||
export * from "./typegenFormatPrettier"; | ||
export * from "./typegenMetadata"; | ||
export * from "./typegenTypeHelpers"; | ||
export * from "./utils"; | ||
export * from "./definitions/_types"; | ||
export * from "./definitions/args"; | ||
export * from "./definitions/definitionBlocks"; | ||
export * from "./definitions/enumType"; | ||
export * from "./definitions/extendType"; | ||
export * from "./definitions/inputObjectType"; | ||
export * from "./definitions/interfaceType"; | ||
export * from "./definitions/objectType"; | ||
export * from "./definitions/scalarType"; | ||
export * from "./definitions/unionType"; | ||
export * from "./definitions/wrapping"; |
641
dist/core.js
"use strict"; | ||
Object.defineProperty(exports, "__esModule", { value: true }); | ||
var tslib_1 = require("tslib"); | ||
var Types = tslib_1.__importStar(require("./types")); | ||
exports.Types = Types; | ||
var utils_1 = require("./utils"); | ||
var builder_1 = require("./builder"); | ||
exports.SchemaBuilder = builder_1.SchemaBuilder; | ||
exports.isNamedTypeDef = builder_1.isNamedTypeDef; | ||
var metadata_1 = require("./metadata"); | ||
exports.Metadata = metadata_1.Metadata; | ||
var sdlConverter_1 = require("./sdlConverter"); | ||
exports.SDLConverter = sdlConverter_1.SDLConverter; | ||
// Keeping this in core since it shouldn't be needed directly | ||
var autoConfig_1 = require("./autoConfig"); | ||
exports.typegenAutoConfig = autoConfig_1.typegenAutoConfig; | ||
/** | ||
* Provided to the [objectType](#objectType) function, this | ||
*/ | ||
var ObjectTypeDef = /** @class */ (function () { | ||
function ObjectTypeDef(name) { | ||
this.name = name; | ||
this.typeConfig = { | ||
name: name, | ||
fields: [], | ||
interfaces: [], | ||
directives: [], | ||
fieldModifications: {}, | ||
}; | ||
} | ||
/** | ||
* Mixes in an existing field definition or object type | ||
* with the current type. | ||
*/ | ||
ObjectTypeDef.prototype.mix = function (typeName, options) { | ||
this.typeConfig.fields.push({ | ||
item: Types.NodeType.MIX, | ||
typeName: typeName, | ||
mixOptions: options || {}, | ||
}); | ||
}; | ||
/** | ||
* Add an ID field type to the object schema. | ||
*/ | ||
ObjectTypeDef.prototype.id = function (name) { | ||
var opts = []; | ||
for (var _i = 1; _i < arguments.length; _i++) { | ||
opts[_i - 1] = arguments[_i]; | ||
} | ||
this.field.apply(this, [name, "ID"].concat(opts)); | ||
}; | ||
/** | ||
* Add an Int field type to the object schema. | ||
*/ | ||
ObjectTypeDef.prototype.int = function (name) { | ||
var opts = []; | ||
for (var _i = 1; _i < arguments.length; _i++) { | ||
opts[_i - 1] = arguments[_i]; | ||
} | ||
this.field.apply(this, [name, "Int"].concat(opts)); | ||
}; | ||
/** | ||
* Add a Float field type to the object schema. | ||
*/ | ||
ObjectTypeDef.prototype.float = function (name) { | ||
var opts = []; | ||
for (var _i = 1; _i < arguments.length; _i++) { | ||
opts[_i - 1] = arguments[_i]; | ||
} | ||
this.field.apply(this, [name, "Float"].concat(opts)); | ||
}; | ||
/** | ||
* Add a String field type to the object schema. | ||
*/ | ||
ObjectTypeDef.prototype.string = function (name) { | ||
var opts = []; | ||
for (var _i = 1; _i < arguments.length; _i++) { | ||
opts[_i - 1] = arguments[_i]; | ||
} | ||
this.field.apply(this, [name, "String"].concat(opts)); | ||
}; | ||
/** | ||
* Add a Boolean field type to the object schema. | ||
*/ | ||
ObjectTypeDef.prototype.boolean = function (name) { | ||
var opts = []; | ||
for (var _i = 1; _i < arguments.length; _i++) { | ||
opts[_i - 1] = arguments[_i]; | ||
} | ||
this.field.apply(this, [name, "Boolean"].concat(opts)); | ||
}; | ||
/** | ||
* Adds a new field to the object type | ||
*/ | ||
ObjectTypeDef.prototype.field = function (name, type) { | ||
var opts = []; | ||
for (var _i = 2; _i < arguments.length; _i++) { | ||
opts[_i - 2] = arguments[_i]; | ||
} | ||
var options = {}; | ||
if (typeof opts[0] === "function") { | ||
options.resolve = opts[0]; | ||
} | ||
else { | ||
options = tslib_1.__assign({}, opts[0]); | ||
} | ||
this.typeConfig.fields.push({ | ||
item: Types.NodeType.FIELD, | ||
config: tslib_1.__assign({ name: name, | ||
type: type }, options), | ||
}); | ||
}; | ||
/** | ||
* Declare that an object type implements a particular interface, | ||
* by providing the name of the interface | ||
*/ | ||
ObjectTypeDef.prototype.implements = function () { | ||
var interfaceName = []; | ||
for (var _i = 0; _i < arguments.length; _i++) { | ||
interfaceName[_i] = arguments[_i]; | ||
} | ||
var _a; | ||
(_a = this.typeConfig.interfaces).push.apply(_a, interfaceName); | ||
}; | ||
/** | ||
* Adds a description to the `GraphQLObjectType` | ||
* | ||
* Descriptions will be output as type annotations in the generated SDL | ||
*/ | ||
ObjectTypeDef.prototype.description = function (description) { | ||
this.typeConfig.description = utils_1.dedent(description); | ||
}; | ||
/** | ||
* Adds an "isTypeOf" check to the object type. | ||
*/ | ||
ObjectTypeDef.prototype.isTypeOf = function (fn) { | ||
this.typeConfig.isTypeOf = fn; | ||
}; | ||
/** | ||
* Used to modify a field already defined on an interface or mixed-in | ||
* from another type. | ||
* | ||
* At this point the type will not change, but the resolver, | ||
* default, property, or description fields can. | ||
*/ | ||
ObjectTypeDef.prototype.modify = function (field, options) { | ||
this.typeConfig.fieldModifications[field] = options; | ||
}; | ||
/** | ||
* Supply the default field resolver for all members of this type | ||
*/ | ||
ObjectTypeDef.prototype.defaultResolver = function (resolverFn) { | ||
this.typeConfig.defaultResolver = resolverFn; | ||
}; | ||
/** | ||
* Adds a directive directly to the object definition | ||
* | ||
* > Should be used rarely, typically only for interpretation by other schema consumers. | ||
*/ | ||
ObjectTypeDef.prototype.directive = function (name, args) { | ||
this.typeConfig.directives.push({ | ||
name: name, | ||
args: args || {}, | ||
}); | ||
}; | ||
/** | ||
* Configures the nullability for the type, check the | ||
* documentation's "Getting Started" section to learn | ||
* more about GraphQL Nexus's assumptions and configuration | ||
* on nullability. | ||
* | ||
* @param nullability | ||
*/ | ||
ObjectTypeDef.prototype.nullability = function (nullability) { | ||
if (this.typeConfig.nullability) { | ||
console.warn("nullability has already been set for type " + this.typeConfig.name + ", the previous value will be replaced"); | ||
} | ||
this.typeConfig.nullability = nullability; | ||
}; | ||
/** | ||
* @internal | ||
*/ | ||
ObjectTypeDef.prototype.buildType = function (builder) { | ||
return builder.objectType(this.typeConfig); | ||
}; | ||
return ObjectTypeDef; | ||
}()); | ||
exports.ObjectTypeDef = ObjectTypeDef; | ||
/** | ||
* Backing type for an enum member. | ||
*/ | ||
var EnumTypeDef = /** @class */ (function () { | ||
function EnumTypeDef(name) { | ||
this.name = name; | ||
this.typeConfig = { | ||
name: name, | ||
members: [], | ||
directives: [], | ||
}; | ||
} | ||
EnumTypeDef.prototype.mix = function (typeName, options) { | ||
this.typeConfig.members.push({ | ||
item: Types.NodeType.MIX, | ||
typeName: typeName, | ||
mixOptions: options || {}, | ||
}); | ||
}; | ||
EnumTypeDef.prototype.member = function (name, config) { | ||
this.typeConfig.members.push({ | ||
item: Types.NodeType.ENUM_MEMBER, | ||
info: tslib_1.__assign({ name: name, value: name }, config), | ||
}); | ||
}; | ||
/** | ||
* Sets the members of the enum | ||
*/ | ||
EnumTypeDef.prototype.members = function (info) { | ||
var _this = this; | ||
info.forEach(function (member) { | ||
if (typeof member === "string") { | ||
return _this.typeConfig.members.push({ | ||
item: Types.NodeType.ENUM_MEMBER, | ||
info: { name: member, value: member }, | ||
}); | ||
} | ||
_this.typeConfig.members.push({ | ||
item: Types.NodeType.ENUM_MEMBER, | ||
info: member, | ||
}); | ||
}); | ||
}; | ||
/** | ||
* Adds a description to the `GraphQLEnumType` | ||
* | ||
* Descriptions will be output as type annotations in the generated SDL | ||
*/ | ||
EnumTypeDef.prototype.description = function (description) { | ||
this.typeConfig.description = utils_1.dedent(description); | ||
}; | ||
/** | ||
* Should be used very rarely, adds a directive directly to the | ||
* enum definition - for interpretation by other schema consumers. | ||
*/ | ||
EnumTypeDef.prototype.directive = function (name, args) { | ||
this.typeConfig.directives.push({ | ||
name: name, | ||
args: args || {}, | ||
}); | ||
}; | ||
/** | ||
* @internal | ||
*/ | ||
EnumTypeDef.prototype.buildType = function (builder) { | ||
return builder.enumType(this.typeConfig); | ||
}; | ||
return EnumTypeDef; | ||
}()); | ||
exports.EnumTypeDef = EnumTypeDef; | ||
/** | ||
* Configure the `GraphQLUnionType` definition | ||
*/ | ||
var UnionTypeDef = /** @class */ (function () { | ||
function UnionTypeDef(name) { | ||
this.name = name; | ||
this.typeConfig = { | ||
name: name, | ||
members: [], | ||
directives: [], | ||
}; | ||
} | ||
/** | ||
* Take an existing union and base the type off of that, using the `omit` | ||
* option to exclude members of the other union. | ||
* | ||
* > Note: Circular dependencies between unions are not allowed and will | ||
* trigger an error at build-time. | ||
*/ | ||
UnionTypeDef.prototype.mix = function (type, options) { | ||
this.typeConfig.members.push({ | ||
item: Types.NodeType.MIX, | ||
typeName: type, | ||
mixOptions: options || {}, | ||
}); | ||
}; | ||
/** | ||
* Add one or more members to the GraphQLUnion. Any types provided should be valid | ||
* object types available to the schema. | ||
*/ | ||
UnionTypeDef.prototype.members = function () { | ||
var _this = this; | ||
var types = []; | ||
for (var _i = 0; _i < arguments.length; _i++) { | ||
types[_i] = arguments[_i]; | ||
} | ||
types.forEach(function (typeName) { | ||
_this.typeConfig.members.push({ | ||
item: Types.NodeType.UNION_MEMBER, | ||
typeName: typeName, | ||
}); | ||
}); | ||
}; | ||
/** | ||
* Define a type resolver function for the union type. The Resolver should | ||
* return the type name of the union member that should be fulfilled. | ||
* | ||
* > Providing this is highly recommended. If one is not provided, the | ||
* default implementation will call `isTypeOf` on each implementing Object type. | ||
* | ||
* @see https://github.com/graphql/graphql-js/issues/876#issuecomment-304398882 | ||
*/ | ||
UnionTypeDef.prototype.resolveType = function (typeResolver) { | ||
this.typeConfig.resolveType = typeResolver; | ||
}; | ||
/** | ||
* Should be used very rarely, adds a directive directly to the | ||
* union definition - for interpretation by other schema consumers. | ||
*/ | ||
UnionTypeDef.prototype.directive = function (name, args) { | ||
this.typeConfig.directives.push({ | ||
name: name, | ||
args: args || {}, | ||
}); | ||
}; | ||
/** | ||
* @internal | ||
*/ | ||
UnionTypeDef.prototype.buildType = function (builder) { | ||
return builder.unionType(this.typeConfig); | ||
}; | ||
return UnionTypeDef; | ||
}()); | ||
exports.UnionTypeDef = UnionTypeDef; | ||
var InterfaceTypeDef = /** @class */ (function () { | ||
function InterfaceTypeDef(name) { | ||
this.name = name; | ||
this.typeConfig = { | ||
name: name, | ||
fields: [], | ||
directives: [], | ||
}; | ||
} | ||
/** | ||
* Mixes in an existing field definition or object type | ||
* with the current type. | ||
*/ | ||
InterfaceTypeDef.prototype.mix = function (typeName, options) { | ||
this.typeConfig.fields.push({ | ||
item: Types.NodeType.MIX, | ||
typeName: typeName, | ||
mixOptions: options || {}, | ||
}); | ||
}; | ||
/** | ||
* Add an ID field type to the object schema. | ||
*/ | ||
InterfaceTypeDef.prototype.id = function (name) { | ||
var opts = []; | ||
for (var _i = 1; _i < arguments.length; _i++) { | ||
opts[_i - 1] = arguments[_i]; | ||
} | ||
this.field.apply(this, [name, "ID"].concat(opts)); | ||
}; | ||
/** | ||
* Add an Int field type to the object schema. | ||
*/ | ||
InterfaceTypeDef.prototype.int = function (name) { | ||
var opts = []; | ||
for (var _i = 1; _i < arguments.length; _i++) { | ||
opts[_i - 1] = arguments[_i]; | ||
} | ||
this.field.apply(this, [name, "Int"].concat(opts)); | ||
}; | ||
/** | ||
* Add a Float field type to the object schema. | ||
*/ | ||
InterfaceTypeDef.prototype.float = function (name) { | ||
var opts = []; | ||
for (var _i = 1; _i < arguments.length; _i++) { | ||
opts[_i - 1] = arguments[_i]; | ||
} | ||
this.field.apply(this, [name, "Float"].concat(opts)); | ||
}; | ||
/** | ||
* Add a String field type to the object schema. | ||
*/ | ||
InterfaceTypeDef.prototype.string = function (name) { | ||
var opts = []; | ||
for (var _i = 1; _i < arguments.length; _i++) { | ||
opts[_i - 1] = arguments[_i]; | ||
} | ||
this.field.apply(this, [name, "String"].concat(opts)); | ||
}; | ||
/** | ||
* Add a Boolean field type to the object schema. | ||
*/ | ||
InterfaceTypeDef.prototype.boolean = function (name) { | ||
var opts = []; | ||
for (var _i = 1; _i < arguments.length; _i++) { | ||
opts[_i - 1] = arguments[_i]; | ||
} | ||
this.field.apply(this, [name, "Boolean"].concat(opts)); | ||
}; | ||
/** | ||
* Adds a new field to the object type | ||
*/ | ||
InterfaceTypeDef.prototype.field = function (name, type) { | ||
var opts = []; | ||
for (var _i = 2; _i < arguments.length; _i++) { | ||
opts[_i - 2] = arguments[_i]; | ||
} | ||
var options = {}; | ||
if (typeof opts[0] === "function") { | ||
options.resolve = opts[0]; | ||
} | ||
else { | ||
options = tslib_1.__assign({}, opts[0]); | ||
} | ||
this.typeConfig.fields.push({ | ||
item: Types.NodeType.FIELD, | ||
config: tslib_1.__assign({ name: name, | ||
type: type }, options), | ||
}); | ||
}; | ||
/** | ||
* Adds a description to the `GraphQLInterfaceType` | ||
* | ||
* Descriptions will be output as type annotations in the generated SDL | ||
*/ | ||
InterfaceTypeDef.prototype.description = function (description) { | ||
this.typeConfig.description = utils_1.dedent(description); | ||
}; | ||
/** | ||
* Optionally provide a custom type resolver function. If one is not provided, | ||
* the default implementation will call `isTypeOf` on each implementing | ||
* Object type. | ||
*/ | ||
InterfaceTypeDef.prototype.resolveType = function (typeResolver) { | ||
this.typeConfig.resolveType = typeResolver; | ||
}; | ||
/** | ||
* Should be used very rarely, adds a directive directly to the | ||
* interface definition - for interpretation by other schema consumers. | ||
*/ | ||
InterfaceTypeDef.prototype.directive = function (name, args) { | ||
this.typeConfig.directives.push({ | ||
name: name, | ||
args: args || {}, | ||
}); | ||
}; | ||
/** | ||
* @internal | ||
*/ | ||
InterfaceTypeDef.prototype.buildType = function (builder) { | ||
return builder.interfaceType(this.typeConfig); | ||
}; | ||
return InterfaceTypeDef; | ||
}()); | ||
exports.InterfaceTypeDef = InterfaceTypeDef; | ||
var InputObjectTypeDef = /** @class */ (function () { | ||
function InputObjectTypeDef(name) { | ||
this.name = name; | ||
this.typeConfig = { | ||
name: name, | ||
fields: [], | ||
directives: [], | ||
}; | ||
} | ||
/** | ||
* Add an ID field type to the object schema. | ||
*/ | ||
InputObjectTypeDef.prototype.id = function (name, options) { | ||
this.field(name, "ID", options); | ||
}; | ||
/** | ||
* Add an Int field type to the object schema. | ||
*/ | ||
InputObjectTypeDef.prototype.int = function (name, options) { | ||
this.field(name, "Int", options); | ||
}; | ||
/** | ||
* Add a Float field type to the object schema. | ||
*/ | ||
InputObjectTypeDef.prototype.float = function (name, options) { | ||
this.field(name, "Float", options); | ||
}; | ||
/** | ||
* Add a String field type to the object schema. | ||
*/ | ||
InputObjectTypeDef.prototype.string = function (name, options) { | ||
this.field(name, "String", options); | ||
}; | ||
/** | ||
* Add a Boolean field type to the object schema. | ||
*/ | ||
InputObjectTypeDef.prototype.boolean = function (name, options) { | ||
this.field(name, "Boolean", options); | ||
}; | ||
/** | ||
* Adds a new field to the input object type | ||
*/ | ||
InputObjectTypeDef.prototype.field = function (name, type, options) { | ||
this.typeConfig.fields.push({ | ||
item: Types.NodeType.FIELD, | ||
config: tslib_1.__assign({ name: name, | ||
type: type }, options), | ||
}); | ||
}; | ||
/** | ||
* Adds a description to the `GraphQLInputObjectType` | ||
* | ||
* Descriptions will be output as type annotations in the generated SDL | ||
*/ | ||
InputObjectTypeDef.prototype.description = function (description) { | ||
this.typeConfig.description = utils_1.dedent(description); | ||
}; | ||
/** | ||
* Should be used very rarely, adds a directive directly to the | ||
* input object definition - for interpretation by other schema consumers. | ||
*/ | ||
InputObjectTypeDef.prototype.directive = function (name, args) { | ||
this.typeConfig.directives.push({ | ||
name: name, | ||
args: args || {}, | ||
}); | ||
}; | ||
/** | ||
* Configures the nullability for the type | ||
* | ||
* @see nullability | ||
*/ | ||
InputObjectTypeDef.prototype.nullability = function (nullability) { | ||
if (this.typeConfig.nullability) { | ||
console.warn("nullability has already been set for type " + this.typeConfig.name + ", the previous value will be replaced"); | ||
} | ||
this.typeConfig.nullability = nullability; | ||
}; | ||
/** | ||
* @internal | ||
*/ | ||
InputObjectTypeDef.prototype.buildType = function (builder) { | ||
return builder.inputObjectType(this.typeConfig); | ||
}; | ||
return InputObjectTypeDef; | ||
}()); | ||
exports.InputObjectTypeDef = InputObjectTypeDef; | ||
var DirectiveTypeDef = /** @class */ (function () { | ||
function DirectiveTypeDef(name) { | ||
this.name = name; | ||
this.typeConfig = { | ||
name: name, | ||
locations: [], | ||
directiveArgs: [], | ||
}; | ||
} | ||
DirectiveTypeDef.prototype.description = function (description) { | ||
this.typeConfig.description = utils_1.dedent(description); | ||
}; | ||
DirectiveTypeDef.prototype.locations = function () { | ||
var location = []; | ||
for (var _i = 0; _i < arguments.length; _i++) { | ||
location[_i] = arguments[_i]; | ||
} | ||
var _a; | ||
(_a = this.typeConfig.locations).push.apply(_a, location); | ||
}; | ||
/** | ||
* Add an ID field type to the object schema. | ||
*/ | ||
DirectiveTypeDef.prototype.id = function (name, options) { | ||
this.field(name, "ID", options); | ||
}; | ||
/** | ||
* Add an Int field type to the object schema. | ||
*/ | ||
DirectiveTypeDef.prototype.int = function (name, options) { | ||
this.field(name, "Int", options); | ||
}; | ||
/** | ||
* Add a Float field type to the object schema. | ||
*/ | ||
DirectiveTypeDef.prototype.float = function (name, options) { | ||
this.field(name, "Float", options); | ||
}; | ||
/** | ||
* Add a String field type to the object schema. | ||
*/ | ||
DirectiveTypeDef.prototype.string = function (name, options) { | ||
this.field(name, "String", options); | ||
}; | ||
/** | ||
* Add a Boolean field type to the object schema. | ||
*/ | ||
DirectiveTypeDef.prototype.boolean = function (name, options) { | ||
this.field(name, "Boolean", options); | ||
}; | ||
/** | ||
* Adds a new field to the input object type | ||
*/ | ||
DirectiveTypeDef.prototype.field = function (name, type, options) { | ||
this.typeConfig.directiveArgs.push(tslib_1.__assign({ name: name, | ||
type: type }, options)); | ||
}; | ||
/** | ||
* @internal | ||
*/ | ||
DirectiveTypeDef.prototype.buildType = function (builder) { | ||
return builder.directiveType(this.typeConfig); | ||
}; | ||
return DirectiveTypeDef; | ||
}()); | ||
exports.DirectiveTypeDef = DirectiveTypeDef; | ||
/** | ||
* The `WrappedType` exists to signify that the value returned from | ||
* the type construction APIs should not be used externally outside of the | ||
* builder function. It also is useful if you need the SchemaBuilder, in that | ||
* it can take a function which is lazy-evaluated to build the type. | ||
*/ | ||
var WrappedType = /** @class */ (function () { | ||
function WrappedType(type) { | ||
this.type = type; | ||
} | ||
return WrappedType; | ||
}()); | ||
exports.WrappedType = WrappedType; | ||
// The "core" is used as a namespace to re-export everything, | ||
// For anyone who wants to use the internals | ||
tslib_1.__exportStar(require("./builder"), exports); | ||
tslib_1.__exportStar(require("./sdlConverter"), exports); | ||
tslib_1.__exportStar(require("./typegen"), exports); | ||
tslib_1.__exportStar(require("./typegenAutoConfig"), exports); | ||
tslib_1.__exportStar(require("./typegenFormatPrettier"), exports); | ||
tslib_1.__exportStar(require("./typegenMetadata"), exports); | ||
tslib_1.__exportStar(require("./utils"), exports); | ||
tslib_1.__exportStar(require("./definitions/_types"), exports); | ||
tslib_1.__exportStar(require("./definitions/args"), exports); | ||
tslib_1.__exportStar(require("./definitions/definitionBlocks"), exports); | ||
tslib_1.__exportStar(require("./definitions/enumType"), exports); | ||
tslib_1.__exportStar(require("./definitions/extendType"), exports); | ||
tslib_1.__exportStar(require("./definitions/inputObjectType"), exports); | ||
tslib_1.__exportStar(require("./definitions/interfaceType"), exports); | ||
tslib_1.__exportStar(require("./definitions/objectType"), exports); | ||
tslib_1.__exportStar(require("./definitions/scalarType"), exports); | ||
tslib_1.__exportStar(require("./definitions/unionType"), exports); | ||
tslib_1.__exportStar(require("./definitions/wrapping"), exports); | ||
//# sourceMappingURL=core.js.map |
@@ -1,5 +0,23 @@ | ||
export * from "./definitions"; | ||
export { buildTypes, makeSchema } from "./builder"; | ||
export { | ||
arg, | ||
booleanArg, | ||
floatArg, | ||
idArg, | ||
intArg, | ||
stringArg, | ||
} from "./definitions/args"; | ||
export { enumType } from "./definitions/enumType"; | ||
export { extendType } from "./definitions/extendType"; | ||
export { inputObjectType } from "./definitions/inputObjectType"; | ||
export { interfaceType } from "./definitions/interfaceType"; | ||
export { objectType } from "./definitions/objectType"; | ||
export { scalarType } from "./definitions/scalarType"; | ||
export { unionType } from "./definitions/unionType"; | ||
export { nexusWrappedFn } from "./definitions/wrapping"; | ||
export { convertSDL } from "./sdlConverter"; | ||
export { groupTypes } from "./utils"; | ||
export { FieldResolver } from "./typegenTypeHelpers"; | ||
export { core, blocks }; | ||
import * as core from "./core"; | ||
export { core }; | ||
export { makeSchema, buildTypes, makeSchemaWithMetadata } from "./builder"; | ||
export { convertSDL } from "./sdlConverter"; | ||
import * as blocks from "./blocks"; |
"use strict"; | ||
Object.defineProperty(exports, "__esModule", { value: true }); | ||
var tslib_1 = require("tslib"); | ||
tslib_1.__exportStar(require("./definitions"), exports); | ||
var core = tslib_1.__importStar(require("./core")); | ||
exports.core = core; | ||
// All of the Public API definitions | ||
var builder_1 = require("./builder"); | ||
exports.buildTypes = builder_1.buildTypes; | ||
exports.makeSchema = builder_1.makeSchema; | ||
exports.buildTypes = builder_1.buildTypes; | ||
exports.makeSchemaWithMetadata = builder_1.makeSchemaWithMetadata; | ||
var args_1 = require("./definitions/args"); | ||
exports.arg = args_1.arg; | ||
exports.booleanArg = args_1.booleanArg; | ||
exports.floatArg = args_1.floatArg; | ||
exports.idArg = args_1.idArg; | ||
exports.intArg = args_1.intArg; | ||
exports.stringArg = args_1.stringArg; | ||
var enumType_1 = require("./definitions/enumType"); | ||
exports.enumType = enumType_1.enumType; | ||
var extendType_1 = require("./definitions/extendType"); | ||
exports.extendType = extendType_1.extendType; | ||
var inputObjectType_1 = require("./definitions/inputObjectType"); | ||
exports.inputObjectType = inputObjectType_1.inputObjectType; | ||
var interfaceType_1 = require("./definitions/interfaceType"); | ||
exports.interfaceType = interfaceType_1.interfaceType; | ||
var objectType_1 = require("./definitions/objectType"); | ||
exports.objectType = objectType_1.objectType; | ||
var scalarType_1 = require("./definitions/scalarType"); | ||
exports.scalarType = scalarType_1.scalarType; | ||
var unionType_1 = require("./definitions/unionType"); | ||
exports.unionType = unionType_1.unionType; | ||
var wrapping_1 = require("./definitions/wrapping"); | ||
exports.nexusWrappedFn = wrapping_1.nexusWrappedFn; | ||
var sdlConverter_1 = require("./sdlConverter"); | ||
exports.convertSDL = sdlConverter_1.convertSDL; | ||
var utils_1 = require("./utils"); | ||
exports.groupTypes = utils_1.groupTypes; | ||
var core = tslib_1.__importStar(require("./core")); | ||
exports.core = core; | ||
var blocks = tslib_1.__importStar(require("./blocks")); | ||
exports.blocks = blocks; | ||
//# sourceMappingURL=index.js.map |
export declare const SDL_HEADER: string; | ||
export declare const TYPEGEN_HEADER: string; | ||
export declare const TYPEGEN_CONFIG_WARNING = | ||
'/**\n * For better typings, you should provide configuration for how to lookup \n * the types. See the documentation for "typegenAutoConfig"\n */\n'; |
"use strict"; | ||
Object.defineProperty(exports, "__esModule", { value: true }); | ||
var tslib_1 = require("tslib"); | ||
var utils_1 = require("./utils"); | ||
exports.SDL_HEADER = utils_1.dedent(templateObject_1 || (templateObject_1 = tslib_1.__makeTemplateObject(["\n ### This file was autogenerated by GraphQL Nexus\n ### Do not make changes to this file directly\n"], ["\n ### This file was autogenerated by GraphQL Nexus\n ### Do not make changes to this file directly\n"]))); | ||
exports.TYPEGEN_HEADER = utils_1.dedent(templateObject_2 || (templateObject_2 = tslib_1.__makeTemplateObject(["\n /**\n * This file is automatically generated by GraphQL Nexus\n * Do not make changes to this file directly\n * \n * For better typings, you should provide configuration for how to lookup \n * the types. See the documentation for \"typegenAutoConfig\"\n */\n"], ["\n /**\n * This file is automatically generated by GraphQL Nexus\n * Do not make changes to this file directly\n * \n * For better typings, you should provide configuration for how to lookup \n * the types. See the documentation for \"typegenAutoConfig\"\n */\n"]))); | ||
var templateObject_1, templateObject_2; | ||
var version = require("../package.json").version; | ||
exports.SDL_HEADER = "### This file was autogenerated by Nexus " + version + "\n### Do not make changes to this file directly\n"; | ||
exports.TYPEGEN_HEADER = "/**\n * This file was automatically generated by Nexus " + version + "\n * Do not make changes to this file directly\n */\n"; | ||
exports.TYPEGEN_CONFIG_WARNING = "/**\n * For better typings, you should provide configuration for how to lookup \n * the types. See the documentation for \"typegenAutoConfig\"\n */\n"; | ||
//# sourceMappingURL=lang.js.map |
@@ -1,16 +0,36 @@ | ||
import { GraphQLObjectType, GraphQLEnumType, GraphQLInterfaceType, GraphQLInputObjectType, GraphQLScalarType, GraphQLUnionType } from "graphql"; | ||
import { | ||
GraphQLObjectType, | ||
GraphQLEnumType, | ||
GraphQLInterfaceType, | ||
GraphQLInputObjectType, | ||
GraphQLScalarType, | ||
GraphQLUnionType, | ||
GraphQLSchema, | ||
GraphQLNamedType, | ||
} from "graphql"; | ||
import { GroupedTypes } from "./utils"; | ||
export declare function convertSDL(sdl: string, commonjs?: boolean): string; | ||
/** | ||
* Convert an existing SDL schema into a GraphQL Nexus format | ||
* Convert an existing SDL schema into a Nexus GraphQL format | ||
*/ | ||
export declare class SDLConverter { | ||
protected export: string; | ||
constructor(commonjs?: boolean); | ||
convert(sdl: string): string; | ||
makeObjectType(type: GraphQLObjectType): string; | ||
makeEnumType(type: GraphQLEnumType): string; | ||
makeInterfaceType(type: GraphQLInterfaceType): string; | ||
makeInputObjectType(type: GraphQLInputObjectType): string; | ||
makeUnionType(type: GraphQLUnionType): string; | ||
makeScalarType(type: GraphQLScalarType): string; | ||
protected export: string; | ||
protected schema: GraphQLSchema; | ||
protected groupedTypes: GroupedTypes; | ||
constructor(commonjs: boolean | undefined, sdl: string); | ||
print(): string; | ||
printObjectTypes(): string; | ||
printObjectType(type: GraphQLObjectType): string; | ||
printInterfaceTypes(): string; | ||
printInterfaceType(type: GraphQLInterfaceType): string; | ||
printEnumTypes(): string; | ||
printEnumType(type: GraphQLEnumType): string; | ||
printInputObjectTypes(): string[] | ""; | ||
printInputObjectType(type: GraphQLInputObjectType): string; | ||
printUnionTypes(): string; | ||
printUnionType(type: GraphQLUnionType): string; | ||
printScalarTypes(): string; | ||
printScalarType(type: GraphQLScalarType): string; | ||
maybeDescription(type: GraphQLNamedType): string | null; | ||
printBlock(block: (string | null)[]): string; | ||
} |
@@ -7,100 +7,163 @@ "use strict"; | ||
if (commonjs === void 0) { commonjs = false; } | ||
return new SDLConverter(commonjs).convert(sdl); | ||
return new SDLConverter(commonjs, sdl).print(); | ||
} | ||
exports.convertSDL = convertSDL; | ||
/** | ||
* Convert an existing SDL schema into a GraphQL Nexus format | ||
* Convert an existing SDL schema into a Nexus GraphQL format | ||
*/ | ||
var SDLConverter = /** @class */ (function () { | ||
function SDLConverter(commonjs) { | ||
function SDLConverter(commonjs, sdl) { | ||
if (commonjs === void 0) { commonjs = false; } | ||
this.export = commonjs ? "exports." : "export const "; | ||
this.schema = graphql_1.buildSchema(sdl); | ||
this.groupedTypes = utils_1.groupTypes(this.schema); | ||
} | ||
SDLConverter.prototype.convert = function (sdl) { | ||
SDLConverter.prototype.print = function () { | ||
return [ | ||
this.printObjectTypes(), | ||
this.printInterfaceTypes(), | ||
this.printInputObjectTypes(), | ||
this.printUnionTypes(), | ||
this.printEnumTypes(), | ||
this.printScalarTypes(), | ||
].join("\n\n"); | ||
}; | ||
SDLConverter.prototype.printObjectTypes = function () { | ||
var _this = this; | ||
var schema = graphql_1.buildSchema(sdl); | ||
if (typeof graphql_1.lexicographicSortSchema === "function") { | ||
schema = graphql_1.lexicographicSortSchema(schema); | ||
if (this.groupedTypes.object.length > 0) { | ||
return this.groupedTypes.object | ||
.map(function (t) { return _this.printObjectType(t); }) | ||
.join("\n"); | ||
} | ||
var typeMap = schema.getTypeMap(); | ||
var typeFragments = []; | ||
Object.keys(typeMap).forEach(function (typeName) { | ||
if (typeName.indexOf("__") === 0) { | ||
return; | ||
} | ||
var type = typeMap[typeName]; | ||
if (graphql_1.isObjectType(type)) { | ||
typeFragments.push(_this.makeObjectType(type)); | ||
} | ||
else if (graphql_1.isInterfaceType(type)) { | ||
typeFragments.push(_this.makeInterfaceType(type)); | ||
} | ||
else if (graphql_1.isUnionType(type)) { | ||
typeFragments.push(_this.makeUnionType(type)); | ||
} | ||
else if (graphql_1.isEnumType(type)) { | ||
typeFragments.push(_this.makeEnumType(type)); | ||
} | ||
else if (graphql_1.isScalarType(type)) { | ||
typeFragments.push(_this.makeScalarType(type)); | ||
} | ||
else if (graphql_1.isInputObjectType(type)) { | ||
typeFragments.push(_this.makeInputObjectType(type)); | ||
} | ||
}); | ||
return typeFragments.join("\n\n"); | ||
return ""; | ||
}; | ||
SDLConverter.prototype.makeObjectType = function (type) { | ||
var str = [ | ||
"" + this.export + type.name + " = objectType(\"" + type.name + "\", t => {", | ||
]; | ||
if (type.getInterfaces().length > 0) { | ||
str.push(" t.implements(\"" + type | ||
.getInterfaces() | ||
.map(function (i) { return i.name; }) | ||
.join('", "') + "\")"); | ||
SDLConverter.prototype.printObjectType = function (type) { | ||
return this.printBlock([ | ||
"" + this.export + type.name + " = objectType({", | ||
" name: \"" + type.name + "\"", | ||
"})", | ||
]); | ||
// if (type.getInterfaces().length > 0) { | ||
// const interfaceNames = type | ||
// .getInterfaces() | ||
// .map((i) => JSON.stringify(i.name)) | ||
// .join(", "); | ||
// str.push(` t.implements(${interfaceNames})`); | ||
// } | ||
// Object.keys(type.getFields()).forEach((fieldName) => { | ||
// if (isInterfaceField(type, fieldName)) { | ||
// return; | ||
// } | ||
// eachObj(type.getFields(), (field, key) => { | ||
// getFieldType(field); | ||
// }); | ||
// }); | ||
// return str.join("\n"); | ||
}; | ||
SDLConverter.prototype.printInterfaceTypes = function () { | ||
var _this = this; | ||
if (this.groupedTypes.interface.length) { | ||
return this.groupedTypes.interface | ||
.map(function (t) { return _this.printInterfaceType(t); }) | ||
.join("\n"); | ||
} | ||
Object.keys(type.getFields()).forEach(function (fieldName) { | ||
if (utils_1.isInterfaceField(type, fieldName)) { | ||
return; | ||
} | ||
utils_1.eachObj(type.getFields(), function (field, key) { | ||
getFieldType(field); | ||
}); | ||
}); | ||
return str.concat("});").join("\n"); | ||
return ""; | ||
}; | ||
SDLConverter.prototype.makeEnumType = function (type) { | ||
var str = [ | ||
"" + this.export + type.name + " = enumType(\"" + type.name + "\", t => {", | ||
]; | ||
return str.concat("});").join("\n"); | ||
SDLConverter.prototype.printInterfaceType = function (type) { | ||
return this.printBlock([ | ||
"" + this.export + type.name + " = interfaceType({", | ||
" name: \"" + type.name + "\",", | ||
this.maybeDescription(type), | ||
" definition(t) {", | ||
" }", | ||
"});", | ||
]); | ||
// eachObj(type.getFields(), (field, key) => { | ||
// getFieldType(field); | ||
// }); | ||
// return str.join("\n"); | ||
}; | ||
SDLConverter.prototype.makeInterfaceType = function (type) { | ||
var str = [ | ||
"" + this.export + type.name + " = interfaceType(\"" + type.name + "\", t => {", | ||
]; | ||
utils_1.eachObj(type.getFields(), function (field, key) { | ||
getFieldType(field); | ||
}); | ||
return str.concat("});").join("\n"); | ||
SDLConverter.prototype.printEnumTypes = function () { | ||
var _this = this; | ||
if (this.groupedTypes.enum.length) { | ||
return this.groupedTypes.enum | ||
.map(function (t) { return _this.printEnumType(t); }) | ||
.join("\n"); | ||
} | ||
return ""; | ||
}; | ||
SDLConverter.prototype.makeInputObjectType = function (type) { | ||
var str = [ | ||
"" + this.export + type.name + " = inputObjectType(\"" + type.name + "\", t => {", | ||
]; | ||
return str.concat("});").join("\n"); | ||
SDLConverter.prototype.printEnumType = function (type) { | ||
return this.printBlock([ | ||
"" + this.export + type.name + " = enumType({", | ||
" name: \"" + type.name + "\",", | ||
this.maybeDescription(type), | ||
" definition(t) {", | ||
" }", | ||
"});", | ||
]); | ||
}; | ||
SDLConverter.prototype.makeUnionType = function (type) { | ||
var str = [ | ||
"" + this.export + type.name + " = unionType(\"" + type.name + "\", t => {", | ||
]; | ||
return str.concat("});").join("\n"); | ||
SDLConverter.prototype.printInputObjectTypes = function () { | ||
var _this = this; | ||
if (this.groupedTypes.input.length) { | ||
return this.groupedTypes.input.map(function (t) { return _this.printInputObjectType(t); }); | ||
} | ||
return ""; | ||
}; | ||
SDLConverter.prototype.makeScalarType = function (type) { | ||
var str = [ | ||
"" + this.export + type.name + " = scalarType(\"" + type.name + "\", t => {", | ||
]; | ||
return str.concat("});").join("\n"); | ||
SDLConverter.prototype.printInputObjectType = function (type) { | ||
return this.printBlock([ | ||
"" + this.export + type.name + " = inputObjectType({", | ||
" name: \"" + type.name + "\",", | ||
this.maybeDescription(type), | ||
" definition(t) {", | ||
" }", | ||
"});", | ||
]); | ||
}; | ||
SDLConverter.prototype.printUnionTypes = function () { | ||
var _this = this; | ||
if (this.groupedTypes.union.length) { | ||
return this.groupedTypes.union | ||
.map(function (t) { return _this.printUnionType(t); }) | ||
.join("\n"); | ||
} | ||
return ""; | ||
}; | ||
SDLConverter.prototype.printUnionType = function (type) { | ||
return this.printBlock([ | ||
"" + this.export + type.name + " = unionType({", | ||
" name: \"" + type.name + "\",", | ||
this.maybeDescription(type), | ||
" definition(t) {", | ||
" }", | ||
"});", | ||
]); | ||
}; | ||
SDLConverter.prototype.printScalarTypes = function () { | ||
var _this = this; | ||
if (this.groupedTypes.scalar.length) { | ||
return this.groupedTypes.scalar | ||
.map(function (t) { return _this.printScalarType(t); }) | ||
.join("\n"); | ||
} | ||
return ""; | ||
}; | ||
SDLConverter.prototype.printScalarType = function (type) { | ||
return this.printBlock([ | ||
"" + this.export + type.name + " = scalarType({", | ||
" name: " + type.name + "\",", | ||
this.maybeDescription(type), | ||
" definition(t) {", | ||
" }", | ||
"});", | ||
]); | ||
}; | ||
SDLConverter.prototype.maybeDescription = function (type) { | ||
if (type.description) { | ||
return " description: " + JSON.stringify(type.description) + ","; | ||
} | ||
return null; | ||
}; | ||
SDLConverter.prototype.printBlock = function (block) { | ||
return block.filter(function (t) { return t !== null; }).join("\n"); | ||
}; | ||
return SDLConverter; | ||
@@ -107,0 +170,0 @@ }()); |
@@ -1,3 +0,99 @@ | ||
import { GraphQLSchema } from "graphql"; | ||
import { Metadata } from "./metadata"; | ||
export declare function buildTypeDefinitions(schema: GraphQLSchema, metadata: Metadata): Promise<string>; | ||
import { | ||
GraphQLArgument, | ||
GraphQLField, | ||
GraphQLInputField, | ||
GraphQLInputType as GraphQLType, | ||
GraphQLInterfaceType, | ||
GraphQLObjectType, | ||
GraphQLOutputType, | ||
GraphQLScalarType, | ||
GraphQLSchema, | ||
} from "graphql"; | ||
import { TypegenInfo } from "./builder"; | ||
import { GroupedTypes } from "./utils"; | ||
declare type TypeFieldMapping = Record< | ||
string, | ||
Record<string, [string, string]> | ||
>; | ||
declare type TypeMapping = Record<string, string>; | ||
declare type RootTypeMapping = Record< | ||
string, | ||
string | Record<string, [string, string]> | ||
>; | ||
/** | ||
* We track and output a few main things: | ||
* | ||
* 1. "root" types, or the values that fill the first | ||
* argument for a given object type | ||
* | ||
* 2. "arg" types, the values that are arguments to output fields. | ||
* | ||
* 3. "return" types, the values returned from the resolvers... usually | ||
* just list/nullable variations on the "root" types for other types | ||
* | ||
* 4. The names of all types, grouped by type. | ||
* | ||
* - Non-scalar types will get a dedicated "Root" type associated with it | ||
*/ | ||
export declare class Typegen { | ||
protected schema: GraphQLSchema; | ||
protected typegenInfo: TypegenInfo; | ||
groupedTypes: GroupedTypes; | ||
constructor(schema: GraphQLSchema, typegenInfo: TypegenInfo); | ||
print(): string; | ||
printHeaders(): string; | ||
printFooters(): string; | ||
printGenTypeMap(): string; | ||
printCustomScalarMethods(): string | never[]; | ||
buildCustomScalarMap(): Record<string, string>; | ||
printInheritedFieldMap(): string; | ||
printContext(): string; | ||
buildResolveSourceTypeMap(): Record<string, string>; | ||
printAbstractResolveReturnTypeMap(): string; | ||
buildResolveReturnTypesMap(): Record<string, string>; | ||
printTypeNames(name: keyof GroupedTypes, exportName: string): string; | ||
buildEnumTypeMap(): Record<string, string>; | ||
buildInputTypeMap(): Record<string, Record<string, [string, string]>>; | ||
printInputTypeMap(): string; | ||
printEnumTypeMap(): string; | ||
buildRootTypeMap(): Record<string, string | Record<string, [string, string]>>; | ||
buildAllTypesMap(): Record<string, string>; | ||
hasResolver( | ||
field: GraphQLField<any, any>, | ||
_type: GraphQLObjectType | GraphQLInterfaceType | ||
): boolean; | ||
printRootTypeMap(): string; | ||
printAllTypesMap(): string; | ||
buildArgTypeMap(): Record< | ||
string, | ||
Record<string, Record<string, [string, string]>> | ||
>; | ||
printArgTypeMap(): string; | ||
buildReturnTypeMap(): Record<string, Record<string, [string, string]>>; | ||
printOutputType(type: GraphQLOutputType): string; | ||
typeToArr(type: GraphQLOutputType): any[]; | ||
printReturnTypeMap(): string; | ||
normalizeArg(arg: GraphQLInputField | GraphQLArgument): [string, string]; | ||
argSeparator(type: GraphQLType): ":" | "?:"; | ||
argTypeRepresentation(arg: GraphQLType): string; | ||
argTypeArr(arg: GraphQLType): any[]; | ||
printTypeInterface(interfaceName: string, typeMapping: TypeMapping): string; | ||
printRootTypeFieldInterface( | ||
interfaceName: string, | ||
typeMapping: RootTypeMapping | ||
): string; | ||
printTypeFieldInterface( | ||
interfaceName: string, | ||
typeMapping: TypeFieldMapping, | ||
source: string | ||
): string; | ||
printArgTypeFieldInterface( | ||
typeMapping: Record<string, TypeFieldMapping> | ||
): string; | ||
printObj: ( | ||
space: string, | ||
source: string | ||
) => (val: Record<string, [string, string]>, key: string) => string; | ||
printScalar(type: GraphQLScalarType): string; | ||
} | ||
export {}; |
"use strict"; | ||
Object.defineProperty(exports, "__esModule", { value: true }); | ||
var tslib_1 = require("tslib"); | ||
var graphql_1 = require("graphql"); | ||
var utils_1 = require("./utils"); | ||
// This is intentionally concise and procedural. Didn't want to make this | ||
// unnecessarily abstracted and it should run only with only a single iteration | ||
// of the schema. The types created here are generally meant for internal use | ||
// by GraphQLNexus anyway. If there is a need, this could be factored out into | ||
// something nicer, but for now let's just make it work well, however ugly it is. | ||
// At least it's type safe™ | ||
function buildTypeDefinitions(schema, metadata) { | ||
return tslib_1.__awaiter(this, void 0, void 0, function () { | ||
var _a, headers, backingTypeMap, contextType, imports, schemaTypeMap, typeNames, allTypeStrings, interfaceRootTypes, returnTypeFields, argTypeFields, MP, MPL, MT, MTA, maybePromiseList, maybePromise, maybeThunk, maybeThunkWithArgs, suffixed, argFieldName, fieldReturnTypeName, typeReturnTypeName, typeRootTypeName, fieldResolverName, getReturnType, printInputType, printArgOrFieldMember, makeFieldArgs, processField, fieldRootType, fieldBackingName, makeRootType, makeReturnType, makeResolvers, objectNames, interfacesWithMembers, enums, unions, scalars, inputObjects; | ||
return tslib_1.__generator(this, function (_b) { | ||
switch (_b.label) { | ||
case 0: return [4 /*yield*/, metadata.getTypegenInfo(schema)]; | ||
case 1: | ||
_a = _b.sent(), headers = _a.headers, backingTypeMap = _a.backingTypeMap, contextType = _a.contextType, imports = _a.imports; | ||
schemaTypeMap = schema.getTypeMap(); | ||
typeNames = { | ||
enums: [], | ||
objects: [], | ||
inputObjects: [], | ||
interfaces: [], | ||
scalars: [], | ||
unions: [], | ||
}; | ||
allTypeStrings = []; | ||
interfaceRootTypes = {}; | ||
returnTypeFields = {}; | ||
argTypeFields = {}; | ||
MP = metadata.safeTypeName(schema, "MaybePromise"); | ||
MPL = metadata.safeTypeName(schema, "MaybePromiseList"); | ||
MT = metadata.safeTypeName(schema, "MaybeThunk"); | ||
MTA = metadata.safeTypeName(schema, "MaybeThunkArgs"); | ||
maybePromiseList = function (t) { return MPL + "<" + t + ">"; }; | ||
maybePromise = function (t) { return MP + "<" + t + ">"; }; | ||
maybeThunk = function (t) { return MT + "<" + t + ">"; }; | ||
maybeThunkWithArgs = function (t, a) { return MTA + "<" + t + ", " + a + ">"; }; | ||
suffixed = function () { | ||
var args = []; | ||
for (var _i = 0; _i < arguments.length; _i++) { | ||
args[_i] = arguments[_i]; | ||
var SpecifiedScalars = { | ||
ID: "string", | ||
String: "string", | ||
Float: "number", | ||
Int: "number", | ||
Boolean: "boolean", | ||
}; | ||
/** | ||
* We track and output a few main things: | ||
* | ||
* 1. "root" types, or the values that fill the first | ||
* argument for a given object type | ||
* | ||
* 2. "arg" types, the values that are arguments to output fields. | ||
* | ||
* 3. "return" types, the values returned from the resolvers... usually | ||
* just list/nullable variations on the "root" types for other types | ||
* | ||
* 4. The names of all types, grouped by type. | ||
* | ||
* - Non-scalar types will get a dedicated "Root" type associated with it | ||
*/ | ||
var Typegen = /** @class */ (function () { | ||
function Typegen(schema, typegenInfo) { | ||
this.schema = schema; | ||
this.typegenInfo = typegenInfo; | ||
this.printObj = function (space, source) { return function (val, key) { | ||
return ["" + space + key + ": { // " + source] | ||
.concat(utils_1.mapObj(val, function (v2, k2) { | ||
return space + " " + k2 + v2[0] + " " + v2[1]; | ||
})) | ||
.concat(space + "}") | ||
.join("\n"); | ||
}; }; | ||
this.groupedTypes = utils_1.groupTypes(schema); | ||
} | ||
Typegen.prototype.print = function () { | ||
return [ | ||
this.printHeaders(), | ||
this.printInputTypeMap(), | ||
this.printEnumTypeMap(), | ||
this.printRootTypeMap(), | ||
this.printAllTypesMap(), | ||
this.printReturnTypeMap(), | ||
this.printArgTypeMap(), | ||
this.printAbstractResolveReturnTypeMap(), | ||
this.printInheritedFieldMap(), | ||
this.printTypeNames("object", "NexusGenObjectNames"), | ||
this.printTypeNames("input", "NexusGenInputNames"), | ||
this.printTypeNames("enum", "NexusGenEnumNames"), | ||
this.printTypeNames("interface", "NexusGenInterfaceNames"), | ||
this.printTypeNames("scalar", "NexusGenScalarNames"), | ||
this.printTypeNames("union", "NexusGenUnionNames"), | ||
this.printGenTypeMap(), | ||
this.printFooters(), | ||
].join("\n\n"); | ||
}; | ||
Typegen.prototype.printHeaders = function () { | ||
return [ | ||
this.typegenInfo.headers.join("\n"), | ||
this.typegenInfo.imports.join("\n"), | ||
this.printCustomScalarMethods(), | ||
GLOBAL_DECLARATION, | ||
].join("\n"); | ||
}; | ||
Typegen.prototype.printFooters = function () { | ||
return "export type Gen = NexusGenTypes;"; | ||
}; | ||
Typegen.prototype.printGenTypeMap = function () { | ||
return ["export interface NexusGenTypes {"] | ||
.concat([ | ||
" context: " + this.printContext() + ";", | ||
" inputTypes: NexusGenInputs;", | ||
" rootTypes: NexusGenRootTypes;", | ||
" argTypes: NexusGenArgTypes;", | ||
" fieldTypes: NexusGenFieldTypes;", | ||
" allTypes: NexusGenAllTypes;", | ||
" inheritedFields: NexusGenInheritedFields;", | ||
" 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'];", | ||
" abstractResolveReturn: NexusGenAbstractResolveReturnTypes;", | ||
]) | ||
.concat("}") | ||
.join("\n"); | ||
}; | ||
Typegen.prototype.printCustomScalarMethods = function () { | ||
var customScalars = this.buildCustomScalarMap(); | ||
if (!Object.keys(customScalars).length) { | ||
return []; | ||
} | ||
return [ | ||
"import { core } from \"nexus\"", | ||
"declare global {", | ||
" interface NexusGenCustomScalarMethods<TypeName extends string> {", | ||
] | ||
.concat(utils_1.mapObj(customScalars, function (val, key) { | ||
return " " + val + "<FieldName extends string>(fieldName: FieldName, ...opts: core.ScalarOutSpread<TypeName, FieldName>): void // " + JSON.stringify(key) + ";"; | ||
})) | ||
.concat([" }", "}"]) | ||
.join("\n"); | ||
}; | ||
Typegen.prototype.buildCustomScalarMap = function () { | ||
var customScalars = {}; | ||
this.groupedTypes.scalar.forEach(function (type) { | ||
if (type.asNexusMethod) { | ||
customScalars[type.name] = type.asNexusMethod; | ||
} | ||
}); | ||
return customScalars; | ||
}; | ||
Typegen.prototype.printInheritedFieldMap = function () { | ||
return "export interface NexusGenInheritedFields {}"; | ||
}; | ||
Typegen.prototype.printContext = function () { | ||
return this.typegenInfo.contextType || "{}"; | ||
}; | ||
Typegen.prototype.buildResolveSourceTypeMap = function () { | ||
var _this = this; | ||
var sourceMap = {}; | ||
var abstractTypes = []; | ||
abstractTypes | ||
.concat(this.groupedTypes.union) | ||
.concat(this.groupedTypes.interface) | ||
.forEach(function (type) { | ||
if (graphql_1.isInterfaceType(type)) { | ||
var possibleNames = _this.schema | ||
.getPossibleTypes(type) | ||
.map(function (t) { return t.name; }); | ||
if (possibleNames.length > 0) { | ||
sourceMap[type.name] = possibleNames | ||
.map(function (val) { return "NexusGenRootTypes['" + val + "']"; }) | ||
.join(" | "); | ||
} | ||
} | ||
else { | ||
sourceMap[type.name] = type | ||
.getTypes() | ||
.map(function (t) { return "NexusGenRootTypes['" + t.name + "']"; }) | ||
.join(" | "); | ||
} | ||
}); | ||
return sourceMap; | ||
}; | ||
Typegen.prototype.printAbstractResolveReturnTypeMap = function () { | ||
return this.printTypeInterface("NexusGenAbstractResolveReturnTypes", this.buildResolveReturnTypesMap()); | ||
}; | ||
Typegen.prototype.buildResolveReturnTypesMap = function () { | ||
var _this = this; | ||
var sourceMap = {}; | ||
var abstractTypes = []; | ||
abstractTypes | ||
.concat(this.groupedTypes.union) | ||
.concat(this.groupedTypes.interface) | ||
.forEach(function (type) { | ||
if (graphql_1.isInterfaceType(type)) { | ||
var possibleNames = _this.schema | ||
.getPossibleTypes(type) | ||
.map(function (t) { return t.name; }); | ||
if (possibleNames.length > 0) { | ||
sourceMap[type.name] = possibleNames | ||
.map(function (val) { return JSON.stringify(val); }) | ||
.join(" | "); | ||
} | ||
else { | ||
console.warn("Nexus Warning: Interface " + type.name + " is not implemented by any object types"); | ||
} | ||
} | ||
else { | ||
sourceMap[type.name] = type | ||
.getTypes() | ||
.map(function (t) { return JSON.stringify(t.name); }) | ||
.join(" | "); | ||
} | ||
}); | ||
return sourceMap; | ||
}; | ||
Typegen.prototype.printTypeNames = function (name, exportName) { | ||
var obj = this.groupedTypes[name]; | ||
var typeDef = obj.length === 0 | ||
? "never" | ||
: obj | ||
.map(function (o) { return JSON.stringify(o.name); }) | ||
.sort() | ||
.join(" | "); | ||
return "export type " + exportName + " = " + typeDef + ";"; | ||
}; | ||
Typegen.prototype.buildEnumTypeMap = function () { | ||
var enumMap = {}; | ||
this.groupedTypes.enum.forEach(function (e) { | ||
var values = e.getValues().map(function (val) { return JSON.stringify(val.value); }); | ||
enumMap[e.name] = values.join(" | "); | ||
}); | ||
return enumMap; | ||
}; | ||
Typegen.prototype.buildInputTypeMap = function () { | ||
var _this = this; | ||
var inputObjMap = {}; | ||
this.groupedTypes.input.forEach(function (input) { | ||
utils_1.eachObj(input.getFields(), function (field) { | ||
inputObjMap[input.name] = inputObjMap[input.name] || {}; | ||
inputObjMap[input.name][field.name] = _this.normalizeArg(field); | ||
}); | ||
}); | ||
return inputObjMap; | ||
}; | ||
Typegen.prototype.printInputTypeMap = function () { | ||
return this.printTypeFieldInterface("NexusGenInputs", this.buildInputTypeMap(), "input type"); | ||
}; | ||
Typegen.prototype.printEnumTypeMap = function () { | ||
return this.printTypeInterface("NexusGenEnums", this.buildEnumTypeMap()); | ||
}; | ||
Typegen.prototype.buildRootTypeMap = function () { | ||
var _this = this; | ||
var rootTypeMap = {}; | ||
var hasFields = []; | ||
hasFields | ||
.concat(this.groupedTypes.object) | ||
.concat(this.groupedTypes.interface) | ||
.concat(this.groupedTypes.scalar) | ||
.concat(this.groupedTypes.union) | ||
.forEach(function (type) { | ||
var backingType = _this.typegenInfo.backingTypeMap[type.name]; | ||
if (typeof backingType === "string") { | ||
rootTypeMap[type.name] = backingType; | ||
} | ||
else if (graphql_1.isScalarType(type)) { | ||
if (graphql_1.isSpecifiedScalarType(type)) { | ||
rootTypeMap[type.name] = | ||
SpecifiedScalars[type.name]; | ||
} | ||
else { | ||
rootTypeMap[type.name] = "any"; | ||
} | ||
} | ||
else if (graphql_1.isUnionType(type)) { | ||
rootTypeMap[type.name] = type | ||
.getTypes() | ||
.map(function (t) { return "NexusGenRootTypes['" + t.name + "']"; }) | ||
.join(" | "); | ||
} | ||
else if (graphql_1.isInterfaceType(type)) { | ||
var possibleRoots = _this.schema | ||
.getPossibleTypes(type) | ||
.map(function (t) { return "NexusGenRootTypes['" + t.name + "']"; }); | ||
if (possibleRoots.length > 0) { | ||
rootTypeMap[type.name] = possibleRoots.join(" | "); | ||
} | ||
else { | ||
rootTypeMap[type.name] = "any"; | ||
} | ||
} | ||
else { | ||
utils_1.eachObj(type.getFields(), function (field) { | ||
var obj = (rootTypeMap[type.name] = rootTypeMap[type.name] || {}); | ||
if (!_this.hasResolver(field, type)) { | ||
if (typeof obj !== "string") { | ||
obj[field.name] = [ | ||
_this.argSeparator(field.type), | ||
_this.printOutputType(field.type), | ||
]; | ||
} | ||
var nameStr = ""; | ||
if (args.length === 3) { | ||
var typeName = args[0], fieldName = args[1], suffix = args[2]; | ||
var pascalField = pascalCase(fieldName); | ||
if (metadata.hasField(schema, typeName, pascalField)) { | ||
nameStr = "" + typeName + fieldName + suffix; | ||
} | ||
else { | ||
nameStr = "" + typeName + pascalField + suffix; | ||
} | ||
} | ||
else { | ||
nameStr = "" + args[0] + args[1]; | ||
} | ||
return metadata.safeTypeName(schema, nameStr); | ||
}; | ||
argFieldName = function (typeName, fieldName) { | ||
return suffixed(typeName, fieldName, "Args"); | ||
}; | ||
fieldReturnTypeName = function (typeName, fieldName) { | ||
return suffixed(typeName, fieldName, "ReturnType"); | ||
}; | ||
typeReturnTypeName = function (type) { | ||
if (graphql_1.isUnionType(type)) { | ||
return suffixed(type.name, "ReturnType"); | ||
} | ||
if (!utils_1.hasField(type, "ReturnType")) { | ||
return suffixed(type.name, "_ReturnType"); | ||
} | ||
return suffixed(type.name, "ReturnType"); | ||
}; | ||
typeRootTypeName = function (typeName) { | ||
if (isEntryType(typeName)) { | ||
return "{}"; | ||
} | ||
return suffixed(typeName, "RootType"); | ||
}; | ||
fieldResolverName = function (typeName, fieldName) { | ||
return suffixed(typeName, fieldName, "Resolver"); | ||
}; | ||
getReturnType = function (fieldType) { | ||
var _a = unwrapNull(fieldType), type = _a.type, typeStr = _a.typeStr; | ||
if (graphql_1.isListType(type)) { | ||
return "" + typeStr + maybePromiseList(getReturnType(type.ofType)); | ||
} | ||
if (graphql_1.isObjectType(type) || graphql_1.isInterfaceType(type) || graphql_1.isUnionType(type)) { | ||
typeStr += typeReturnTypeName(type); | ||
} | ||
else if (graphql_1.isEnumType(type)) { | ||
typeStr += type.name; | ||
} | ||
else if (graphql_1.isScalarType(type)) { | ||
typeStr += backingTypeMap[type.name] || "unknown"; | ||
} | ||
return typeStr; | ||
}; | ||
printInputType = function (fieldType) { | ||
var _a = unwrapNull(fieldType), type = _a.type, typeStr = _a.typeStr; | ||
if (graphql_1.isListType(type)) { | ||
var inputTypeStr = printInputType(type.ofType); | ||
return inputTypeStr.indexOf("null ") !== -1 | ||
? typeStr + "Array<" + inputTypeStr + ">" | ||
: "" + typeStr + inputTypeStr + "[]"; | ||
} | ||
if (graphql_1.isInputObjectType(type) || graphql_1.isEnumType(type)) { | ||
return "" + typeStr + type.name; | ||
} | ||
if (graphql_1.isScalarType(type)) { | ||
return "" + typeStr + (backingTypeMap[type.name] || "unknown"); | ||
} | ||
throw new Error("Unexpected type " + type); | ||
}; | ||
printArgOrFieldMember = function (_a) { | ||
var name = _a.name, type = _a.type; | ||
if (graphql_1.isNonNullType(type)) { | ||
return " " + name + ": " + printInputType(type) + ";"; | ||
} | ||
return " " + name + "?: " + printInputType(type) + ";"; | ||
}; | ||
makeFieldArgs = function (argTypeName, field) { | ||
allTypeStrings.push([ | ||
"export interface " + argTypeName + " {", | ||
map(field.args, function (arg) { return printArgOrFieldMember(arg); }), | ||
"}", | ||
].join("\n")); | ||
}; | ||
processField = function (type, field) { | ||
var returnTypeName = fieldReturnTypeName(type.name, field.name); | ||
utils_1.arrPush(returnTypeFields, type.name, [field.name, returnTypeName]); | ||
allTypeStrings.push("export type " + returnTypeName + " = " + getReturnType(field.type) + ";"); | ||
if (field.args.length) { | ||
var argTypeName = argFieldName(type.name, field.name); | ||
utils_1.arrPush(argTypeFields, type.name, [field.name, argTypeName]); | ||
if (graphql_1.isObjectType(type)) { | ||
var interfaces = type | ||
.getInterfaces() | ||
.filter(function (i) { return i.getFields()[field.name]; }) | ||
.map(function (i) { return argFieldName(i.name, field.name); }); | ||
if (interfaces.length) { | ||
allTypeStrings.push("export interface " + argTypeName + " extends " + interfaces.join(", ") + " {}"); | ||
} | ||
else { | ||
makeFieldArgs(argTypeName, field); | ||
} | ||
} | ||
else { | ||
makeFieldArgs(argTypeName, field); | ||
} | ||
} | ||
}; | ||
fieldRootType = function (fieldType) { | ||
var _a = unwrapNull(fieldType), type = _a.type, typeStr = _a.typeStr; | ||
if (graphql_1.isListType(type)) { | ||
var toWrap = fieldRootType(type.ofType); | ||
return toWrap.indexOf("null | ") === 0 | ||
? typeStr + "Array<" + toWrap + ">" | ||
: "" + typeStr + toWrap + "[]"; | ||
} | ||
if (graphql_1.isScalarType(type)) { | ||
return "" + typeStr + (backingTypeMap[type.name] || "any"); | ||
} | ||
if (graphql_1.isObjectType(type)) { | ||
// return field. | ||
} | ||
if (graphql_1.isEnumType(type)) { | ||
return "" + typeStr + type.name; | ||
} | ||
return typeStr + "any"; | ||
}; | ||
fieldBackingName = function (type, field) { | ||
var colon = metadata.hasDefaultValue(type, field.name) | ||
? "?:" | ||
: graphql_1.isNonNullType(field.type) | ||
? ":" | ||
: "?:"; | ||
return "" + field.name + colon; | ||
}; | ||
makeRootType = function (type) { | ||
if (isEntryType(type.name)) { | ||
return; | ||
} | ||
if (backingTypeMap[type.name]) { | ||
allTypeStrings.push("export type " + typeRootTypeName(type.name) + " = " + backingTypeMap[type.name] + ";"); | ||
} | ||
else { | ||
var rootMembers = utils_1.mapObj(type.getFields(), function (f) { | ||
if (metadata.hasResolver(type.name, f.name)) { | ||
return null; | ||
} | ||
return " " + fieldBackingName(type, f) + " " + fieldRootType(f.type) + ";"; | ||
}).filter(function (f) { return f; }); | ||
if (rootMembers.length === 0) { | ||
allTypeStrings.push("export type " + typeRootTypeName(type.name) + " = {};"); | ||
} | ||
else { | ||
allTypeStrings.push([ | ||
"export interface " + typeRootTypeName(type.name) + " {", | ||
rootMembers.join("\n"), | ||
"}", | ||
].join("\n")); | ||
} | ||
} | ||
}; | ||
makeReturnType = function (type) { | ||
if (backingTypeMap[type.name]) { | ||
allTypeStrings.push("export type " + typeReturnTypeName(type) + " = " + backingTypeMap[type.name]); | ||
} | ||
else { | ||
var returnMembers = utils_1.mapObj(type.getFields(), function (f) { | ||
var hasArgs = f.args.length > 0; | ||
if (metadata.hasResolver(type.name, f.name)) { | ||
return null; | ||
} | ||
var rootType = fieldRootType(f.type); | ||
return " " + fieldBackingName(type, f) + " " + (hasArgs | ||
? maybeThunkWithArgs(maybePromise(rootType), argFieldName(type.name, f.name)) | ||
: maybeThunk(maybePromise(rootType))) + ";"; | ||
}).filter(function (f) { return f; }); | ||
if (returnMembers.length === 0) { | ||
allTypeStrings.push("export type " + typeReturnTypeName(type) + " = {};"); | ||
} | ||
else { | ||
allTypeStrings.push([ | ||
"export type " + typeReturnTypeName(type) + " = {", | ||
returnMembers.join("\n"), | ||
"}", | ||
].join("\n")); | ||
} | ||
} | ||
}; | ||
makeResolvers = function (type) { | ||
// TODO | ||
}; | ||
Object.keys(schemaTypeMap).forEach(function (typeName) { | ||
if (typeName.indexOf("__") === 0) { | ||
return; | ||
} | ||
// All types will be "unused" until we say otherwise, | ||
// if we need to strip them. | ||
var type = schema.getType(typeName); | ||
// An object type has a "backing type", and fields | ||
// which may have an "arg type" and have a "return type" | ||
if (graphql_1.isObjectType(type)) { | ||
typeNames.objects.push(type.name); | ||
utils_1.eachObj(type.getFields(), function (field) { return processField(type, field); }); | ||
type | ||
.getInterfaces() | ||
.forEach(function (i) { return utils_1.arrPush(interfaceRootTypes, i.name, type); }); | ||
makeRootType(type); | ||
makeReturnType(type); | ||
makeResolvers(type); | ||
} | ||
else if (graphql_1.isInputObjectType(type)) { | ||
typeNames.inputObjects.push(type.name); | ||
allTypeStrings.push([ | ||
"export interface " + type.name + " {", | ||
utils_1.mapObj(type.getFields(), function (inputField) { | ||
return printArgOrFieldMember(inputField); | ||
}).join("\n"), | ||
"}", | ||
].join("\n")); | ||
} | ||
else if (graphql_1.isScalarType(type)) { | ||
typeNames.scalars.push(type.name); | ||
} | ||
else if (graphql_1.isUnionType(type)) { | ||
typeNames.unions.push(type.name); | ||
allTypeStrings.push("export type " + typeRootTypeName(type.name) + " = " + map(type.getTypes(), function (_a) { | ||
var name = _a.name; | ||
return typeRootTypeName(name); | ||
}, " | ") + ";"); | ||
allTypeStrings.push("export type " + typeReturnTypeName(type) + " = " + map(type.getTypes(), function (t) { return typeReturnTypeName(t); }, " | ") + ";"); | ||
} | ||
else if (graphql_1.isInterfaceType(type)) { | ||
typeNames.interfaces.push(type.name); | ||
utils_1.eachObj(type.getFields(), function (field) { return processField(type, field); }); | ||
} | ||
else if (graphql_1.isEnumType(type)) { | ||
typeNames.enums.push(type.name); | ||
allTypeStrings.push("export type " + type.name + " = " + map(type.getValues(), function (_a) { | ||
var value = _a.value; | ||
return JSON.stringify(value); | ||
}, " | ") + ";"); | ||
} | ||
}); | ||
utils_1.eachObj(interfaceRootTypes, function (members, interfaceName) { | ||
var i = schema.getType(interfaceName); | ||
if (!graphql_1.isInterfaceType(i)) { | ||
return; | ||
} | ||
if (backingTypeMap[interfaceName]) { | ||
allTypeStrings.push("export type " + typeRootTypeName(interfaceName) + " = " + backingTypeMap[interfaceName] + ";"); | ||
allTypeStrings.push("export type " + typeReturnTypeName(i) + " = " + backingTypeMap[interfaceName] + ";"); | ||
} | ||
else { | ||
allTypeStrings.push("export type " + typeRootTypeName(interfaceName) + " = " + members | ||
.map(function (_a) { | ||
var name = _a.name; | ||
return typeRootTypeName(name); | ||
}) | ||
.join(" | ") + ";"); | ||
allTypeStrings.push("export type " + typeReturnTypeName(i) + " = " + members | ||
.map(function (name) { return typeReturnTypeName(name); }) | ||
.join(" | ") + ";"); | ||
} | ||
}); | ||
objectNames = function () { | ||
return [ | ||
"{", | ||
map(typeNames.objects, function (n) { return " " + n + ": " + typeRootTypeName(n) + ";"; }), | ||
" }", | ||
].join("\n"); | ||
}; | ||
interfacesWithMembers = function () { | ||
if (typeNames.interfaces.length === 0) { | ||
return "{}"; | ||
} | ||
return [ | ||
"{", | ||
map(typeNames.interfaces, function (n) { | ||
return " " + n + ": " + (interfaceRootTypes[n] | ||
? interfaceRootTypes[n].map(stringify).join(" | ") | ||
: "never") + ";"; | ||
}), | ||
" }", | ||
].join("\n"); | ||
}; | ||
enums = function () { | ||
if (typeNames.enums.length === 0) { | ||
return "{}"; | ||
} | ||
return ["{", map(typeNames.enums, function (n) { return " " + n + ": " + n + ";"; }), " }"].join("\n"); | ||
}; | ||
unions = function () { | ||
if (typeNames.unions.length === 0) { | ||
return "{}"; | ||
} | ||
return ["{", map(typeNames.unions, function (n) { return " " + n + ": any;"; }), " }"].join("\n"); | ||
}; | ||
scalars = function () { | ||
return ["{", map(typeNames.scalars, function (n) { return " " + n + ": any;"; }), " }"].join("\n"); | ||
}; | ||
inputObjects = function () { | ||
if (typeNames.inputObjects.length === 0) { | ||
return "{}"; | ||
} | ||
return [ | ||
"{", | ||
map(typeNames.inputObjects, function (n) { return " " + n + ": " + n + ";"; }), | ||
" }", | ||
].join("\n"); | ||
}; | ||
return [2 /*return*/, headers.join("\n") + "\n" + imports.join("\n") + "\n\ndeclare global {\n interface GraphQLNexusGen extends GraphQLNexusGenTypes {}\n}\n\n// Maybe Promise\nexport type " + MP + "<T> = T | PromiseLike<T>;\n\n// Maybe Promise List\nexport type " + MPL + "<T> = Array<" + MP + "<T>>;\n\n// Maybe Thunk\nexport type " + MT + "<T> = T | (() => T);\n\n// Maybe Thunk, with args\nexport type " + MTA + "<T, A> = T | ((args?: A) => T);\n\n" + allTypeStrings.join("\n\n") + "\n\n" + stringifyTypeFieldMapping("GraphQLNexusGenArgTypes", argTypeFields) + "\n\nexport interface GraphQLNexusGenRootTypes {\n" + map(typeNames.interfaces.concat(typeNames.objects), function (name) { return " " + name + ": " + typeRootTypeName(name) + ";"; }) + "\n}\n\n" + stringifyTypeFieldMapping("GraphQLNexusGenReturnTypes", returnTypeFields) + "\n\nexport interface GraphQLNexusGenTypes {\n argTypes: GraphQLNexusGenArgTypes;\n backingTypes: GraphQLNexusGenRootTypes;\n returnTypes: GraphQLNexusGenReturnTypes;\n context: " + contextType + ";\n enums: " + enums() + ";\n objects: " + objectNames() + ";\n interfaces: " + interfacesWithMembers() + ";\n unions: " + unions() + ";\n scalars: " + scalars() + ";\n inputObjects: " + inputObjects() + ";\n allInputTypes: \n | Extract<keyof GraphQLNexusGenTypes['inputObjects'], string>\n | Extract<keyof GraphQLNexusGenTypes['enums'], string>\n | Extract<keyof GraphQLNexusGenTypes['scalars'], string>;\n allOutputTypes: \n | Extract<keyof GraphQLNexusGenTypes['objects'], string>\n | Extract<keyof GraphQLNexusGenTypes['enums'], string>\n | Extract<keyof GraphQLNexusGenTypes['unions'], string>\n | Extract<keyof GraphQLNexusGenTypes['interfaces'], string>\n | Extract<keyof GraphQLNexusGenTypes['scalars'], string>;\n}\n\nexport type Gen = GraphQLNexusGenTypes;\n"]; | ||
} | ||
}); | ||
} | ||
}); | ||
}); | ||
} | ||
exports.buildTypeDefinitions = buildTypeDefinitions; | ||
function isEntryType(typeName) { | ||
return (typeName === "Query" || | ||
typeName === "Mutation" || | ||
typeName === "Subscription"); | ||
} | ||
var stringify = function (v) { return JSON.stringify(v); }; | ||
function stringifyTypeFieldMapping(tsInterfaceName, obj) { | ||
var argTypeLines = Object.keys(obj).reduce(function (result, typeName) { | ||
return result | ||
.concat(" " + typeName + ": {") | ||
.concat(obj[typeName].reduce(function (fields, _a) { | ||
var fieldName = _a[0], mappingName = _a[1]; | ||
return fields.concat(" " + fieldName + ": " + mappingName + ";"); | ||
}, [])) | ||
.concat(" };"); | ||
}, []); | ||
var argTypes = ["export interface " + tsInterfaceName + " {"] | ||
.concat(argTypeLines) | ||
.concat("}") | ||
.join("\n"); | ||
return argTypes; | ||
} | ||
function map(nodes, iterator, join) { | ||
if (join === void 0) { join = "\n"; } | ||
return Array.from(nodes) | ||
.map(iterator) | ||
.join(join); | ||
} | ||
function ucFirst(str) { | ||
return str | ||
.slice(0, 1) | ||
.toUpperCase() | ||
.concat(str.slice(1)); | ||
} | ||
function camelize(str) { | ||
return str.replace(/^([A-Z])|[\s-_]+(\w)/g, function (match, p1, p2, offset) { | ||
if (p2) { | ||
return p2.toUpperCase(); | ||
return rootTypeMap; | ||
}; | ||
Typegen.prototype.buildAllTypesMap = function () { | ||
var typeMap = {}; | ||
var toCheck = []; | ||
toCheck | ||
.concat(this.groupedTypes.input) | ||
.concat(this.groupedTypes.enum) | ||
.forEach(function (type) { | ||
if (graphql_1.isInputObjectType(type)) { | ||
typeMap[type.name] = "NexusGenInputs['" + type.name + "']"; | ||
} | ||
else if (graphql_1.isEnumType(type)) { | ||
typeMap[type.name] = "NexusGenEnums['" + type.name + "']"; | ||
} | ||
}); | ||
return typeMap; | ||
}; | ||
Typegen.prototype.hasResolver = function (field, _type // Used in tests | ||
) { | ||
return Boolean(field.resolve); | ||
}; | ||
Typegen.prototype.printRootTypeMap = function () { | ||
return this.printRootTypeFieldInterface("NexusGenRootTypes", this.buildRootTypeMap()); | ||
}; | ||
Typegen.prototype.printAllTypesMap = function () { | ||
var typeMapping = this.buildAllTypesMap(); | ||
return ["export interface NexusGenAllTypes extends NexusGenRootTypes {"] | ||
.concat(utils_1.mapObj(typeMapping, function (val, key) { | ||
return " " + key + ": " + val + ";"; | ||
})) | ||
.concat("}") | ||
.join("\n"); | ||
}; | ||
Typegen.prototype.buildArgTypeMap = function () { | ||
var _this = this; | ||
var argTypeMap = {}; | ||
var hasFields = []; | ||
hasFields | ||
.concat(this.groupedTypes.object) | ||
.concat(this.groupedTypes.interface) | ||
.forEach(function (type) { | ||
utils_1.eachObj(type.getFields(), function (field) { | ||
if (field.args.length > 0) { | ||
argTypeMap[type.name] = argTypeMap[type.name] || {}; | ||
argTypeMap[type.name][field.name] = field.args.reduce(function (obj, arg) { | ||
obj[arg.name] = _this.normalizeArg(arg); | ||
return obj; | ||
}, {}); | ||
} | ||
}); | ||
}); | ||
return argTypeMap; | ||
}; | ||
Typegen.prototype.printArgTypeMap = function () { | ||
return this.printArgTypeFieldInterface(this.buildArgTypeMap()); | ||
}; | ||
Typegen.prototype.buildReturnTypeMap = function () { | ||
var _this = this; | ||
var returnTypeMap = {}; | ||
var hasFields = []; | ||
hasFields | ||
.concat(this.groupedTypes.object) | ||
.concat(this.groupedTypes.interface) | ||
.forEach(function (type) { | ||
utils_1.eachObj(type.getFields(), function (field) { | ||
returnTypeMap[type.name] = returnTypeMap[type.name] || {}; | ||
returnTypeMap[type.name][field.name] = [ | ||
":", | ||
_this.printOutputType(field.type), | ||
]; | ||
}); | ||
}); | ||
return returnTypeMap; | ||
}; | ||
Typegen.prototype.printOutputType = function (type) { | ||
var returnType = this.typeToArr(type); | ||
function combine(item) { | ||
if (item.length === 1) { | ||
if (Array.isArray(item[0])) { | ||
var toPrint = combine(item[0]); | ||
return toPrint.indexOf("null") === -1 | ||
? toPrint + "[]" | ||
: "Array<" + toPrint + ">"; | ||
} | ||
return item[0]; | ||
} | ||
if (Array.isArray(item[1])) { | ||
var toPrint = combine(item[1]); | ||
return toPrint.indexOf("null") === -1 | ||
? toPrint + "[] | null" | ||
: "Array<" + toPrint + "> | null"; | ||
} | ||
return item[1] + " | null"; | ||
} | ||
return p1.toLowerCase(); | ||
}); | ||
} | ||
function pascalCase(str) { | ||
return ucFirst(camelize(str)); | ||
} | ||
function unwrapNull(fieldType) { | ||
var type = fieldType; | ||
var typeStr = ""; | ||
if (graphql_1.isNonNullType(fieldType)) { | ||
type = fieldType.ofType; | ||
} | ||
else { | ||
typeStr += "null | "; | ||
} | ||
return { type: type, typeStr: typeStr }; | ||
} | ||
return combine(returnType) + "; // " + type; | ||
}; | ||
Typegen.prototype.typeToArr = function (type) { | ||
var typing = []; | ||
if (graphql_1.isNonNullType(type)) { | ||
type = type.ofType; | ||
} | ||
else { | ||
typing.push(null); | ||
} | ||
if (graphql_1.isListType(type)) { | ||
typing.push(this.typeToArr(type.ofType)); | ||
} | ||
else if (graphql_1.isScalarType(type)) { | ||
typing.push(this.printScalar(type)); | ||
} | ||
else if (graphql_1.isEnumType(type)) { | ||
typing.push("NexusGenEnums['" + type.name + "']"); | ||
} | ||
else if (graphql_1.isObjectType(type) || graphql_1.isInterfaceType(type)) { | ||
typing.push("NexusGenRootTypes['" + type.name + "']"); | ||
} | ||
return typing; | ||
}; | ||
Typegen.prototype.printReturnTypeMap = function () { | ||
return this.printTypeFieldInterface("NexusGenFieldTypes", this.buildReturnTypeMap(), "field return type"); | ||
}; | ||
Typegen.prototype.normalizeArg = function (arg) { | ||
return [this.argSeparator(arg.type), this.argTypeRepresentation(arg.type)]; | ||
}; | ||
Typegen.prototype.argSeparator = function (type) { | ||
if (graphql_1.isNonNullType(type)) { | ||
return ":"; | ||
} | ||
return "?:"; | ||
}; | ||
Typegen.prototype.argTypeRepresentation = function (arg) { | ||
var argType = this.argTypeArr(arg); | ||
function combine(item) { | ||
if (item.length === 1) { | ||
if (Array.isArray(item[0])) { | ||
var toPrint = combine(item[0]); | ||
return toPrint.indexOf("null") === -1 | ||
? toPrint + "[]" | ||
: "Array<" + toPrint + ">"; | ||
} | ||
return item[0]; | ||
} | ||
if (Array.isArray(item[1])) { | ||
var toPrint = combine(item[1]); | ||
return toPrint.indexOf("null") === -1 | ||
? toPrint + "[] | null" | ||
: "Array<" + toPrint + "> | null"; | ||
} | ||
return item[1] + " | null"; | ||
} | ||
return combine(argType) + "; // " + arg; | ||
}; | ||
Typegen.prototype.argTypeArr = function (arg) { | ||
var typing = []; | ||
if (graphql_1.isNonNullType(arg)) { | ||
arg = arg.ofType; | ||
} | ||
else { | ||
typing.push(null); | ||
} | ||
if (graphql_1.isListType(arg)) { | ||
typing.push(this.argTypeArr(arg.ofType)); | ||
} | ||
else if (graphql_1.isScalarType(arg)) { | ||
typing.push(this.printScalar(arg)); | ||
} | ||
else if (graphql_1.isEnumType(arg)) { | ||
typing.push("NexusGenEnums['" + arg.name + "']"); | ||
} | ||
else if (graphql_1.isInputObjectType(arg)) { | ||
typing.push("NexusGenInputs['" + arg.name + "']"); | ||
} | ||
return typing; | ||
}; | ||
Typegen.prototype.printTypeInterface = function (interfaceName, typeMapping) { | ||
return ["export interface " + interfaceName + " {"] | ||
.concat(utils_1.mapObj(typeMapping, function (val, key) { return " " + key + ": " + val; })) | ||
.concat("}") | ||
.join("\n"); | ||
}; | ||
Typegen.prototype.printRootTypeFieldInterface = function (interfaceName, typeMapping) { | ||
var _this = this; | ||
return ["export interface " + interfaceName + " {"] | ||
.concat(utils_1.mapObj(typeMapping, function (val, key) { | ||
if (typeof val === "string") { | ||
return " " + key + ": " + val + ";"; | ||
} | ||
if (Object.keys(val).length === 0) { | ||
return " " + key + ": {};"; | ||
} | ||
return _this.printObj(" ", "root type")(val, key); | ||
})) | ||
.concat("}") | ||
.join("\n"); | ||
}; | ||
Typegen.prototype.printTypeFieldInterface = function (interfaceName, typeMapping, source) { | ||
return ["export interface " + interfaceName + " {"] | ||
.concat(utils_1.mapObj(typeMapping, this.printObj(" ", source))) | ||
.concat("}") | ||
.join("\n"); | ||
}; | ||
Typegen.prototype.printArgTypeFieldInterface = function (typeMapping) { | ||
var _this = this; | ||
return ["export interface NexusGenArgTypes {"] | ||
.concat(utils_1.mapObj(typeMapping, function (val, key) { | ||
return [" " + key + ": {"] | ||
.concat(utils_1.mapObj(val, _this.printObj(" ", "args"))) | ||
.concat(" }") | ||
.join("\n"); | ||
})) | ||
.concat("}") | ||
.join("\n"); | ||
}; | ||
Typegen.prototype.printScalar = function (type) { | ||
if (graphql_1.isSpecifiedScalarType(type)) { | ||
return SpecifiedScalars[type.name]; | ||
} | ||
var backingType = this.typegenInfo.backingTypeMap[type.name]; | ||
if (typeof backingType === "string") { | ||
return backingType; | ||
} | ||
else { | ||
return "any"; | ||
} | ||
}; | ||
return Typegen; | ||
}()); | ||
exports.Typegen = Typegen; | ||
var GLOBAL_DECLARATION = "\ndeclare global {\n interface NexusGen extends NexusGenTypes {}\n}"; | ||
//# sourceMappingURL=typegen.js.map |
@@ -1,8 +0,18 @@ | ||
import { GraphQLObjectType, GraphQLInterfaceType } from "graphql"; | ||
import * as Types from "./types"; | ||
import { | ||
GraphQLObjectType, | ||
GraphQLInterfaceType, | ||
GraphQLSchema, | ||
GraphQLInputObjectType, | ||
GraphQLUnionType, | ||
GraphQLEnumType, | ||
GraphQLScalarType, | ||
} from "graphql"; | ||
export declare function log(msg: string): void; | ||
export declare function withDeprecationComment(description?: string | null): string | null | undefined; | ||
export declare const enumShorthandMembers: (arg: Record<string, string | number | boolean | object> | string[]) => Types.EnumMemberInfo[]; | ||
export declare const isInterfaceField: (type: GraphQLObjectType, fieldName: string) => boolean; | ||
export declare const hasField: (type: GraphQLObjectType | GraphQLInterfaceType, fieldName: string) => boolean; | ||
export declare function withDeprecationComment( | ||
description?: string | null | ||
): string | null | undefined; | ||
export declare const isInterfaceField: ( | ||
type: GraphQLObjectType, | ||
fieldName: string | ||
) => boolean; | ||
/** | ||
@@ -17,9 +27,33 @@ * | ||
*/ | ||
export declare function suggestionList(input: string, options: string[]): string[]; | ||
export declare function dedent(strings: string | TemplateStringsArray, ...values: Array<string>): string; | ||
export declare function arrPush<T, O extends Record<string, T[]>>(obj: O, property: string, value: T): void; | ||
export declare function suggestionList( | ||
input: string, | ||
options: string[] | ||
): string[]; | ||
export declare function objValues<T>(obj: Record<string, T>): T[]; | ||
export declare function mapObj<T, R>(obj: Record<string, T>, mapper: (val: T, key: string, index: number) => R): R[]; | ||
export declare function eachObj<T>(obj: Record<string, T>, iter: (val: T, key: string, index: number) => void): void; | ||
export declare function mapObj<T, R>( | ||
obj: Record<string, T>, | ||
mapper: (val: T, key: string, index: number) => R | ||
): R[]; | ||
export declare function eachObj<T>( | ||
obj: Record<string, T>, | ||
iter: (val: T, key: string, index: number) => void | ||
): void; | ||
export declare const isObject: (obj: any) => boolean; | ||
export declare const assertAbsolutePath: (pathName: string, property: string) => string; | ||
export declare const assertAbsolutePath: ( | ||
pathName: string, | ||
property: string | ||
) => string; | ||
export interface GroupedTypes { | ||
input: GraphQLInputObjectType[]; | ||
interface: GraphQLInterfaceType[]; | ||
object: GraphQLObjectType[]; | ||
union: GraphQLUnionType[]; | ||
enum: GraphQLEnumType[]; | ||
scalar: Array< | ||
GraphQLScalarType & { | ||
asNexusMethod?: string; | ||
} | ||
>; | ||
} | ||
export declare function groupTypes(schema: GraphQLSchema): GroupedTypes; | ||
export declare function firstDefined<T>(...args: Array<T | undefined>): T; |
"use strict"; | ||
Object.defineProperty(exports, "__esModule", { value: true }); | ||
var tslib_1 = require("tslib"); | ||
var graphql_1 = require("graphql"); | ||
var path_1 = tslib_1.__importDefault(require("path")); | ||
function log(msg) { | ||
console.log("GraphQL Nexus: " + msg); | ||
console.log("Nexus GraphQL: " + msg); | ||
} | ||
@@ -13,19 +14,5 @@ exports.log = log; | ||
exports.withDeprecationComment = withDeprecationComment; | ||
exports.enumShorthandMembers = function (arg) { | ||
if (Array.isArray(arg)) { | ||
return arg.map(function (name) { return ({ name: name, value: name }); }); | ||
} | ||
return Object.keys(arg).map(function (name) { | ||
return { | ||
name: name, | ||
value: arg[name], | ||
}; | ||
}); | ||
}; | ||
exports.isInterfaceField = function (type, fieldName) { | ||
return type.getInterfaces().some(function (i) { return Boolean(i.getFields()[fieldName]); }); | ||
}; | ||
exports.hasField = function (type, fieldName) { | ||
return Boolean(type.getFields()[fieldName]); | ||
}; | ||
// ---------------------------- | ||
@@ -103,55 +90,2 @@ /** | ||
// ---------------------------- | ||
// Borrowed from https://github.com/dmnd/dedent | ||
function dedent(strings) { | ||
var values = []; | ||
for (var _i = 1; _i < arguments.length; _i++) { | ||
values[_i - 1] = arguments[_i]; | ||
} | ||
var raw = typeof strings === "string" ? [strings] : strings.raw; | ||
// first, perform interpolation | ||
var result = ""; | ||
for (var i = 0; i < raw.length; i++) { | ||
result += raw[i] | ||
// join lines when there is a suppressed newline | ||
.replace(/\\\n[ \t]*/g, "") | ||
// handle escaped backticks | ||
.replace(/\\`/g, "`"); | ||
if (i < values.length) { | ||
result += values[i]; | ||
} | ||
} | ||
// now strip indentation | ||
var lines = result.split("\n"); | ||
var mindent = null; | ||
lines.forEach(function (l) { | ||
var m = l.match(/^(\s+)\S+/); | ||
if (m) { | ||
var indent = m[1].length; | ||
if (!mindent) { | ||
// this is the first indented line | ||
mindent = indent; | ||
} | ||
else { | ||
mindent = Math.min(mindent, indent); | ||
} | ||
} | ||
}); | ||
if (mindent !== null) { | ||
var m_1 = mindent; // appease Flow | ||
result = lines.map(function (l) { return (l[0] === " " ? l.slice(m_1) : l); }).join("\n"); | ||
} | ||
return (result | ||
// dedent eats leading and trailing whitespace too | ||
.trim() | ||
// handle escaped newlines at the end to ensure they don't get stripped too | ||
.replace(/\\n/g, "\n")); | ||
} | ||
exports.dedent = dedent; | ||
// ---------------------------- | ||
// Helper Fns | ||
function arrPush(obj, property, value) { | ||
obj[property] = obj[property] || []; | ||
obj[property].push(value); | ||
} | ||
exports.arrPush = arrPush; | ||
function objValues(obj) { | ||
@@ -181,2 +115,55 @@ return Object.keys(obj).reduce(function (result, key) { | ||
}; | ||
function groupTypes(schema) { | ||
var groupedTypes = { | ||
input: [], | ||
interface: [], | ||
object: [], | ||
union: [], | ||
enum: [], | ||
scalar: Array.from(graphql_1.specifiedScalarTypes), | ||
}; | ||
var schemaTypeMap = schema.getTypeMap(); | ||
Object.keys(schemaTypeMap) | ||
.sort() | ||
.forEach(function (typeName) { | ||
if (typeName.indexOf("__") === 0) { | ||
return; | ||
} | ||
var type = schema.getType(typeName); | ||
if (graphql_1.isObjectType(type)) { | ||
groupedTypes.object.push(type); | ||
} | ||
else if (graphql_1.isInputObjectType(type)) { | ||
groupedTypes.input.push(type); | ||
} | ||
else if (graphql_1.isScalarType(type) && !graphql_1.isSpecifiedScalarType(type)) { | ||
groupedTypes.scalar.push(type); | ||
} | ||
else if (graphql_1.isUnionType(type)) { | ||
groupedTypes.union.push(type); | ||
} | ||
else if (graphql_1.isInterfaceType(type)) { | ||
groupedTypes.interface.push(type); | ||
} | ||
else if (graphql_1.isEnumType(type)) { | ||
groupedTypes.enum.push(type); | ||
} | ||
}); | ||
return groupedTypes; | ||
} | ||
exports.groupTypes = groupTypes; | ||
function firstDefined() { | ||
var args = []; | ||
for (var _i = 0; _i < arguments.length; _i++) { | ||
args[_i] = arguments[_i]; | ||
} | ||
for (var i = 0; i < args.length; i++) { | ||
var arg = args[i]; | ||
if (typeof arg !== "undefined") { | ||
return arg; | ||
} | ||
} | ||
throw new Error("At least one of the values should be defined"); | ||
} | ||
exports.firstDefined = firstDefined; | ||
//# sourceMappingURL=utils.js.map |
{ | ||
"name": "nexus", | ||
"version": "0.7.0-alpha.2", | ||
"version": "0.9.0", | ||
"main": "dist", | ||
@@ -11,11 +11,13 @@ "types": "dist", | ||
"test": "jest", | ||
"build": "tsc", | ||
"build": "tsc && prettier --write 'dist/**/*.ts'", | ||
"lint": "tslint -p tsconfig.json", | ||
"clean": "rm -rf dist", | ||
"format": "prettier --write 'src/**/*.ts'", | ||
"prepublish": "yarn clean && yarn lint && yarn build", | ||
"website": "cd website && yarn && yarn start", | ||
"examples": "yarn link-examples && cd website && gulp run-examples", | ||
"link-examples": "cd website && yarn && gulp link-examples", | ||
"unlink-examples": "cd website && yarn && gulp unlink-examples", | ||
"upgrade-deps": "cd website && yarn && gulp upgrade-deps", | ||
"examples": "yarn link-examples && cd website && yarn gulp run-examples", | ||
"deploy-site": "cd website && yarn gulp link-website && yarn build", | ||
"link-examples": "cd website && yarn && yarn gulp link-examples", | ||
"unlink-examples": "cd website && yarn && yarn gulp unlink-examples", | ||
"upgrade-deps": "cd website && yarn && yarn gulp upgrade-deps", | ||
"ts-ast-reader": "cd examples/ts-ast-reader && yarn start" | ||
@@ -41,3 +43,5 @@ }, | ||
"@types/node": "^10.12.2", | ||
"@types/prettier": "^1.13.2", | ||
"@types/prettier": "^1.15.2", | ||
"@types/faker": "^4.1.5", | ||
"faker": "^4.1.0", | ||
"graphql": "^14.0.2", | ||
@@ -47,3 +51,3 @@ "husky": "^1.1.2", | ||
"lint-staged": "^7.3.0", | ||
"prettier": "^1.14.3", | ||
"prettier": "^1.16.0", | ||
"ts-jest": "^23.10.4", | ||
@@ -50,0 +54,0 @@ "ts-node": "^7.0.1", |
@@ -1,3 +0,5 @@ | ||
## GraphQL Nexus | ||
## Nexus GraphQL | ||
#### [nexus.js.org](https://nexus.js.org) | ||
``` | ||
@@ -19,3 +21,3 @@ yarn add nexus # or npm install nexus | ||
[graphql-nexus.com](https://graphql-nexus.com) | ||
[nexus.js.org](https://nexus.js.org) | ||
@@ -22,0 +24,0 @@ ### License |
import { | ||
defaultFieldResolver, | ||
GraphQLBoolean, | ||
GraphQLDirective, | ||
GraphQLEnumType, | ||
@@ -25,8 +23,9 @@ GraphQLEnumValueConfigMap, | ||
GraphQLScalarType, | ||
GraphQLSchema, | ||
GraphQLString, | ||
GraphQLUnionType, | ||
isDirective, | ||
isEnumType, | ||
isInputType, | ||
isInputObjectType, | ||
isInterfaceType, | ||
isLeafType, | ||
isNamedType, | ||
@@ -36,31 +35,61 @@ isObjectType, | ||
isUnionType, | ||
GraphQLSchema, | ||
specifiedDirectives, | ||
isScalarType, | ||
} from "graphql"; | ||
import { Metadata } from "./metadata"; | ||
import { isObject } from "util"; | ||
import { NexusArgConfig, NexusArgDef } from "./definitions/args"; | ||
import { | ||
DirectiveTypeDef, | ||
ObjectTypeDef, | ||
InputObjectTypeDef, | ||
EnumTypeDef, | ||
UnionTypeDef, | ||
InterfaceTypeDef, | ||
WrappedType, | ||
} from "./core"; | ||
import * as Types from "./types"; | ||
import { suggestionList, objValues } from "./utils"; | ||
import { isObject } from "util"; | ||
InputDefinitionBlock, | ||
NexusInputFieldDef, | ||
NexusOutputFieldDef, | ||
} from "./definitions/definitionBlocks"; | ||
import { EnumTypeConfig } from "./definitions/enumType"; | ||
import { | ||
NexusExtendTypeConfig, | ||
NexusExtendTypeDef, | ||
} from "./definitions/extendType"; | ||
import { NexusInputObjectTypeConfig } from "./definitions/inputObjectType"; | ||
import { | ||
InterfaceDefinitionBlock, | ||
NexusInterfaceTypeConfig, | ||
NexusInterfaceTypeDef, | ||
} from "./definitions/interfaceType"; | ||
import { | ||
FieldModificationDef, | ||
Implemented, | ||
NexusObjectTypeConfig, | ||
NexusObjectTypeDef, | ||
ObjectDefinitionBlock, | ||
} from "./definitions/objectType"; | ||
import { NexusScalarTypeConfig } from "./definitions/scalarType"; | ||
import { | ||
NexusUnionTypeConfig, | ||
UnionDefinitionBlock, | ||
UnionMembers, | ||
} from "./definitions/unionType"; | ||
import { | ||
AllNexusInputTypeDefs, | ||
AllNexusNamedTypeDefs, | ||
isNexusEnumTypeDef, | ||
isNexusExtendTypeDef, | ||
isNexusInputObjectTypeDef, | ||
isNexusInterfaceTypeDef, | ||
isNexusNamedTypeDef, | ||
isNexusObjectTypeDef, | ||
isNexusScalarTypeDef, | ||
isNexusUnionTypeDef, | ||
isNexusWrappedFn, | ||
} from "./definitions/wrapping"; | ||
import { | ||
GraphQLPossibleInputs, | ||
GraphQLPossibleOutputs, | ||
NonNullConfig, | ||
} from "./definitions/_types"; | ||
import { TypegenAutoConfigOptions } from "./typegenAutoConfig"; | ||
import { TypegenFormatFn } from "./typegenFormatPrettier"; | ||
import { TypegenMetadata } from "./typegenMetadata"; | ||
import { AbstractTypeResolver, GetGen } from "./typegenTypeHelpers"; | ||
import { firstDefined, objValues, suggestionList } from "./utils"; | ||
const isPromise = (val: any): val is Promise<any> => | ||
Boolean(val && typeof val.then === "function"); | ||
export type Maybe<T> = T | null; | ||
const NULL_DEFAULTS = { | ||
output: false, | ||
outputList: false, | ||
outputListItem: false, | ||
input: true, | ||
inputList: true, | ||
inputListItem: false, | ||
}; | ||
const SCALARS: Record<string, GraphQLScalarType> = { | ||
@@ -74,2 +103,86 @@ String: GraphQLString, | ||
export interface BuilderConfig { | ||
/** | ||
* When the schema starts and `process.env.NODE_ENV !== "production"`, | ||
* artifact files are auto-generated containing the .graphql definitions of | ||
* the schema | ||
*/ | ||
outputs: | ||
| { | ||
/** | ||
* Absolute path where the GraphQL IDL file should be written | ||
*/ | ||
schema: string | false; | ||
/** | ||
* File path where generated types should be saved | ||
*/ | ||
typegen: string | false; | ||
} | ||
| false; | ||
/** | ||
* Whether the schema & types are generated when the server | ||
* starts. Default is !process.env.NODE_ENV || process.env.NODE_ENV !== "development" | ||
*/ | ||
shouldGenerateArtifacts?: boolean; | ||
/** | ||
* Automatically configure type resolution for the TypeScript | ||
* representations of the associated types. | ||
* | ||
* Alias for typegenConfig: typegenAutoConfig(options) | ||
*/ | ||
typegenAutoConfig?: TypegenAutoConfigOptions; | ||
/** | ||
* A configuration function for advanced cases where | ||
* more control over the `TypegenInfo` is needed. | ||
*/ | ||
typegenConfig?: ( | ||
schema: GraphQLSchema, | ||
outputPath: string | ||
) => TypegenInfo | PromiseLike<TypegenInfo>; | ||
/** | ||
* Either an absolute path to a .prettierrc file, or an object | ||
* with relevant Prettier rules to be used on the generated output | ||
*/ | ||
prettierConfig?: string | object; | ||
/** | ||
* Manually apply a formatter to the generated content before saving, | ||
* see the `prettierConfig` option if you want to use Prettier. | ||
*/ | ||
formatTypegen?: TypegenFormatFn; | ||
/** | ||
* Configures the default "nonNullDefaults" for the entire schema the type. | ||
* Read more about how nexus handles nullability | ||
*/ | ||
nonNullDefaults?: NonNullConfig; | ||
} | ||
export interface TypegenInfo { | ||
/** | ||
* Headers attached to the generate type output | ||
*/ | ||
headers: string[]; | ||
/** | ||
* All imports for the backing types / context | ||
*/ | ||
imports: string[]; | ||
/** | ||
* A map of all GraphQL types and what TypeScript types they should | ||
* be represented by. | ||
*/ | ||
backingTypeMap: { [K in GetGen<"objectNames">]?: string }; | ||
/** | ||
* The type of the context for the resolvers | ||
*/ | ||
contextType?: string; | ||
} | ||
export interface SchemaConfig extends BuilderConfig { | ||
/** | ||
* All of the GraphQL types. This is an any for simplicity of developer experience, | ||
* if it's an object we get the values, if it's an array we flatten out the | ||
* valid types, ignoring invalid ones. | ||
*/ | ||
types: any; | ||
} | ||
/** | ||
@@ -97,25 +210,45 @@ * Builds all of the types, properly accounts for any using "mix". | ||
* The "pending type" map keeps track of all types that were defined w/ | ||
* GraphQL Nexus and haven't been processed into concrete types yet. | ||
* Nexus GraphQL and haven't been processed into concrete types yet. | ||
*/ | ||
protected pendingTypeMap: Record<string, Types.NamedTypeDef> = {}; | ||
protected pendingTypeMap: Record<string, AllNexusNamedTypeDefs> = {}; | ||
/** | ||
* All "extensions" to types (adding fields on types from many locations) | ||
*/ | ||
protected typeExtensionMap: Record< | ||
string, | ||
NexusExtendTypeConfig<string>[] | ||
> = {}; | ||
/** | ||
* Configures the root-level nonNullDefaults defaults | ||
*/ | ||
protected nonNullDefaults: NonNullConfig = {}; | ||
protected pendingDirectiveMap: Record<string, DirectiveTypeDef<any>> = {}; | ||
protected directiveMap: Record<string, GraphQLDirective> = {}; | ||
/** | ||
* Adds custom dynamic scalar methods to the definition blocks | ||
* tuple: [FieldName, TypeName] | ||
*/ | ||
protected customScalarMethods: [string, string][] = []; | ||
protected nullability: Types.NullabilityConfig = {}; | ||
constructor(protected config: BuilderConfig) {} | ||
constructor( | ||
protected metadata: Metadata, | ||
protected config: Types.BuilderConfig | ||
) { | ||
this.nullability = config.nullability || {}; | ||
} | ||
getConfig(): Types.BuilderConfig { | ||
getConfig(): BuilderConfig { | ||
return this.config; | ||
} | ||
addType(typeDef: Types.NamedTypeDef | GraphQLNamedType) { | ||
addType( | ||
typeDef: | ||
| AllNexusNamedTypeDefs | ||
| NexusExtendTypeDef<string> | ||
| GraphQLNamedType | ||
) { | ||
const existingType = | ||
this.finalTypeMap[typeDef.name] || this.pendingTypeMap[typeDef.name]; | ||
if (isNexusExtendTypeDef(typeDef)) { | ||
this.typeExtensionMap[typeDef.name] = | ||
this.typeExtensionMap[typeDef.name] || []; | ||
this.typeExtensionMap[typeDef.name].push(typeDef.value); | ||
return; | ||
} | ||
if (existingType) { | ||
@@ -128,4 +261,21 @@ // Allow importing the same exact type more than once. | ||
} | ||
if (isNexusScalarTypeDef(typeDef) && typeDef.value.asNexusMethod) { | ||
this.customScalarMethods.push([ | ||
typeDef.value.asNexusMethod, | ||
typeDef.name, | ||
]); | ||
} else if (isScalarType(typeDef)) { | ||
const scalarDef = typeDef as GraphQLScalarType & { | ||
asNexusMethod?: string; | ||
}; | ||
if (scalarDef.asNexusMethod) { | ||
this.customScalarMethods.push([ | ||
scalarDef.asNexusMethod, | ||
scalarDef.name, | ||
]); | ||
} | ||
} | ||
if (isNamedType(typeDef)) { | ||
this.metadata.addExternalType(typeDef); | ||
this.finalTypeMap[typeDef.name] = typeDef; | ||
@@ -138,11 +288,3 @@ this.definedTypeMap[typeDef.name] = typeDef; | ||
addDirective(directiveDef: DirectiveTypeDef<any> | GraphQLDirective) { | ||
if (isDirective(directiveDef)) { | ||
this.directiveMap[directiveDef.name] = directiveDef; | ||
} else { | ||
this.pendingDirectiveMap[directiveDef.name] = directiveDef; | ||
} | ||
} | ||
getFinalTypeMap(): Types.BuildTypes<any, any> { | ||
getFinalTypeMap(): BuildTypes<any> { | ||
Object.keys(this.pendingTypeMap).forEach((key) => { | ||
@@ -160,21 +302,18 @@ // If we've already constructed the type by this point, | ||
}); | ||
Object.keys(this.pendingDirectiveMap).forEach((key) => {}); | ||
return { | ||
typeMap: this.finalTypeMap, | ||
metadata: this.metadata, | ||
directiveMap: this.directiveMap, | ||
}; | ||
} | ||
directiveType(config: Types.DirectiveTypeConfig) { | ||
return new GraphQLDirective({ | ||
name: config.name, | ||
locations: [], | ||
inputObjectType( | ||
config: NexusInputObjectTypeConfig<any> | ||
): GraphQLInputObjectType { | ||
const fields: NexusInputFieldDef[] = []; | ||
const definitionBlock = new InputDefinitionBlock({ | ||
addField: (field) => fields.push(field), | ||
}); | ||
} | ||
inputObjectType(config: Types.InputTypeConfig): GraphQLInputObjectType { | ||
config.definition(this.withScalarMethods(definitionBlock)); | ||
return new GraphQLInputObjectType({ | ||
name: config.name, | ||
fields: () => this.buildInputObjectFields(config), | ||
fields: () => this.buildInputObjectFields(fields, config), | ||
description: config.description, | ||
@@ -184,21 +323,39 @@ }); | ||
objectType(config: Types.ObjectTypeConfig) { | ||
this.metadata.addObjectType(config); | ||
objectType(config: NexusObjectTypeConfig<any>) { | ||
const fields: NexusOutputFieldDef[] = []; | ||
const interfaces: Implemented[] = []; | ||
const modifications: Record< | ||
string, | ||
FieldModificationDef<string, string>[] | ||
> = {}; | ||
const definitionBlock = new ObjectDefinitionBlock({ | ||
addField: (fieldDef) => fields.push(fieldDef), | ||
addInterfaces: (interfaceDefs) => interfaces.push(...interfaceDefs), | ||
addFieldModifications(mods) { | ||
modifications[mods.field] = modifications[mods.field] || []; | ||
modifications[mods.field].push(mods); | ||
}, | ||
}); | ||
config.definition(this.withScalarMethods(definitionBlock)); | ||
const extensions = this.typeExtensionMap[config.name]; | ||
if (extensions) { | ||
extensions.forEach((extension) => { | ||
extension.definition(definitionBlock); | ||
}); | ||
} | ||
return new GraphQLObjectType({ | ||
name: config.name, | ||
interfaces: () => config.interfaces.map((i) => this.getInterface(i)), | ||
interfaces: () => interfaces.map((i) => this.getInterface(i)), | ||
description: config.description, | ||
fields: () => { | ||
const interfaceFields: GraphQLFieldConfigMap<any, any> = {}; | ||
const allInterfaces = config.interfaces.map((i) => | ||
this.getInterface(i) | ||
); | ||
const allFieldsMap: GraphQLFieldConfigMap<any, any> = {}; | ||
const allInterfaces = interfaces.map((i) => this.getInterface(i)); | ||
allInterfaces.forEach((i) => { | ||
const iFields = i.getFields(); | ||
const interfaceFields = i.getFields(); | ||
// We need to take the interface fields and reconstruct them | ||
// this actually simplifies things becuase if we've modified | ||
// the field at all it needs to happen here. | ||
Object.keys(iFields).forEach((iFieldName) => { | ||
const { isDeprecated, args, ...rest } = iFields[iFieldName]; | ||
interfaceFields[iFieldName] = { | ||
Object.keys(interfaceFields).forEach((iFieldName) => { | ||
const { isDeprecated, args, ...rest } = interfaceFields[iFieldName]; | ||
allFieldsMap[iFieldName] = { | ||
...rest, | ||
@@ -214,8 +371,16 @@ args: args.reduce( | ||
}; | ||
const mods = modifications[iFieldName]; | ||
if (mods) { | ||
mods.map((mod) => { | ||
if (typeof mod.description !== "undefined") { | ||
allFieldsMap[iFieldName].description = mod.description; | ||
} | ||
if (typeof mod.resolve !== "undefined") { | ||
allFieldsMap[iFieldName].resolve = mod.resolve; | ||
} | ||
}); | ||
} | ||
}); | ||
}); | ||
return { | ||
...interfaceFields, | ||
...this.buildObjectFields(config), | ||
}; | ||
return this.buildObjectFields(fields, config, allFieldsMap); | ||
}, | ||
@@ -225,7 +390,26 @@ }); | ||
interfaceType(config: Types.InterfaceTypeConfig) { | ||
const { name, resolveType, description } = config; | ||
interfaceType(config: NexusInterfaceTypeConfig<any>) { | ||
const { name, description } = config; | ||
let resolveType: AbstractTypeResolver<string> | undefined; | ||
const fields: NexusOutputFieldDef[] = []; | ||
const definitionBlock = new InterfaceDefinitionBlock({ | ||
addField: (field) => fields.push(field), | ||
setResolveType: (fn) => (resolveType = fn), | ||
}); | ||
config.definition(this.withScalarMethods(definitionBlock)); | ||
const extensions = this.typeExtensionMap[config.name]; | ||
if (extensions) { | ||
extensions.forEach((extension) => { | ||
extension.definition(definitionBlock); | ||
}); | ||
} | ||
if (!resolveType) { | ||
throw new Error( | ||
`Missing resolveType for the ${name} interface.` + | ||
`Be sure to add one in the definition block for the type` | ||
); | ||
} | ||
return new GraphQLInterfaceType({ | ||
name, | ||
fields: () => this.buildObjectFields(config), | ||
fields: () => this.buildObjectFields(fields, config, {}, true), | ||
resolveType, | ||
@@ -236,17 +420,83 @@ description, | ||
enumType(config: Types.EnumTypeConfig) { | ||
withScalarMethods<T extends NexusGenCustomScalarMethods<string>>( | ||
definitionBlock: T | ||
): T { | ||
this.customScalarMethods.forEach(([methodName, typeName]) => { | ||
// @ts-ignore - Yeah, yeah... we know | ||
definitionBlock[methodName] = function(fieldName, ...opts) { | ||
// @ts-ignore | ||
this.addScalarField(fieldName, typeName, opts); | ||
}; | ||
}); | ||
return definitionBlock; | ||
} | ||
enumType(config: EnumTypeConfig<any>) { | ||
const { members } = config; | ||
const values: GraphQLEnumValueConfigMap = {}; | ||
if (Array.isArray(members)) { | ||
members.forEach((m) => { | ||
if (typeof m === "string") { | ||
values[m] = { value: m }; | ||
} else { | ||
values[m.name] = { | ||
value: typeof m.value === "undefined" ? m.name : m.value, | ||
deprecationReason: m.deprecation, | ||
description: m.description, | ||
}; | ||
} | ||
}); | ||
} else { | ||
Object.keys(members).forEach((key) => { | ||
values[key] = { | ||
value: members[key], | ||
}; | ||
}); | ||
} | ||
if (!Object.keys(values).length) { | ||
throw new Error( | ||
`Nexus GraphQL: Enum ${config.name} must have at least one member` | ||
); | ||
} | ||
return new GraphQLEnumType({ | ||
name: config.name, | ||
values: this.buildEnumMembers(config), | ||
values: values, | ||
description: config.description, | ||
}); | ||
} | ||
unionType(config: Types.UnionTypeConfig) { | ||
unionType(config: NexusUnionTypeConfig<any>) { | ||
let members: UnionMembers | undefined; | ||
let resolveType: AbstractTypeResolver<string> | undefined; | ||
config.definition( | ||
new UnionDefinitionBlock({ | ||
addField() {}, | ||
setResolveType: (fn) => (resolveType = fn), | ||
addUnionMembers: (unionMembers) => (members = unionMembers), | ||
}) | ||
); | ||
if (!resolveType) { | ||
throw new Error( | ||
`Missing resolveType for the ${config.name} union.` + | ||
`Be sure to add one in the definition block for the type` | ||
); | ||
} | ||
return new GraphQLUnionType({ | ||
name: config.name, | ||
types: () => this.buildUnionMembers(config), | ||
resolveType: config.resolveType, | ||
resolveType, | ||
description: config.description, | ||
types: () => this.buildUnionMembers(config.name, members), | ||
}); | ||
} | ||
scalarType(config: NexusScalarTypeConfig<string>): GraphQLScalarType { | ||
const scalar: GraphQLScalarType & { | ||
asNexusMethod?: string; | ||
} = new GraphQLScalarType(config); | ||
if (config.asNexusMethod) { | ||
scalar.asNexusMethod = config.asNexusMethod; | ||
} | ||
return scalar; | ||
} | ||
protected missingType(typeName: string): GraphQLNamedType { | ||
@@ -266,70 +516,19 @@ const suggestions = suggestionList( | ||
protected buildEnumMembers(config: Types.EnumTypeConfig) { | ||
let values: GraphQLEnumValueConfigMap = {}; | ||
config.members.forEach((member) => { | ||
switch (member.item) { | ||
case Types.NodeType.ENUM_MEMBER: | ||
values[member.info.name] = { | ||
value: member.info.value, | ||
description: member.info.description, | ||
}; | ||
break; | ||
case Types.NodeType.MIX: | ||
const { | ||
mixOptions: { pick, omit }, | ||
typeName, | ||
} = member; | ||
const enumToMix = this.getEnum(typeName); | ||
enumToMix.getValues().forEach((val) => { | ||
if (pick && pick.indexOf(val.name) === -1) { | ||
return; | ||
} | ||
if (omit && omit.indexOf(val.name) !== -1) { | ||
return; | ||
} | ||
values[val.name] = { | ||
description: val.description, | ||
deprecationReason: val.deprecationReason, | ||
value: val.value, | ||
// astNode: val.astNode, | ||
}; | ||
}); | ||
} | ||
}); | ||
if (!Object.keys(values).length) { | ||
protected buildUnionMembers( | ||
unionName: string, | ||
members: UnionMembers | undefined | ||
) { | ||
const unionMembers: GraphQLObjectType[] = []; | ||
if (!members) { | ||
throw new Error( | ||
`GraphQL Nexus: Enum ${config.name} must have at least one member` | ||
`Missing Union members for ${unionName}.` + | ||
`Make sure to call the t.members(...) method in the union blocks` | ||
); | ||
} | ||
return values; | ||
} | ||
protected buildUnionMembers(config: Types.UnionTypeConfig) { | ||
const unionMembers: GraphQLObjectType[] = []; | ||
config.members.forEach((member) => { | ||
switch (member.item) { | ||
case Types.NodeType.UNION_MEMBER: | ||
unionMembers.push(this.getObjectType(member.typeName)); | ||
break; | ||
case Types.NodeType.MIX: | ||
const { | ||
mixOptions: { pick, omit }, | ||
typeName, | ||
} = member; | ||
const unionToMix = this.getUnion(typeName); | ||
unionToMix.getTypes().forEach((type) => { | ||
if (pick && pick.indexOf(type.name) === -1) { | ||
return; | ||
} | ||
if (omit && omit.indexOf(type.name) !== -1) { | ||
return; | ||
} | ||
unionMembers.push(type); | ||
}); | ||
break; | ||
} | ||
members.forEach((member) => { | ||
unionMembers.push(this.getObjectType(member)); | ||
}); | ||
if (!Object.keys(unionMembers).length) { | ||
if (!unionMembers.length) { | ||
throw new Error( | ||
`GraphQL Nexus: Union ${config.name} must have at least one member type` | ||
`Nexus GraphQL: Union ${unionName} must have at least one member type` | ||
); | ||
@@ -341,37 +540,24 @@ } | ||
protected buildObjectFields( | ||
typeConfig: Types.ObjectTypeConfig | Types.InterfaceTypeConfig | ||
fields: NexusOutputFieldDef[], | ||
typeConfig: NexusObjectTypeConfig<any> | NexusInterfaceTypeConfig<any>, | ||
intoObject: GraphQLFieldConfigMap<any, any>, | ||
forInterface: boolean = false | ||
): GraphQLFieldConfigMap<any, any> { | ||
const fieldMap: GraphQLFieldConfigMap<any, any> = {}; | ||
typeConfig.fields.forEach((field) => { | ||
switch (field.item) { | ||
case Types.NodeType.MIX: | ||
throw new Error("TODO"); | ||
break; | ||
case Types.NodeType.FIELD: | ||
fieldMap[field.config.name] = this.buildObjectField( | ||
field.config, | ||
typeConfig | ||
); | ||
break; | ||
} | ||
fields.forEach((field) => { | ||
intoObject[field.name] = this.buildObjectField( | ||
field, | ||
typeConfig, | ||
forInterface | ||
); | ||
}); | ||
return fieldMap; | ||
return intoObject; | ||
} | ||
protected buildInputObjectFields( | ||
typeConfig: Types.InputTypeConfig | ||
fields: NexusInputFieldDef[], | ||
typeConfig: NexusInputObjectTypeConfig<string> | ||
): GraphQLInputFieldConfigMap { | ||
const fieldMap: GraphQLInputFieldConfigMap = {}; | ||
typeConfig.fields.forEach((field) => { | ||
switch (field.item) { | ||
case Types.NodeType.MIX: | ||
throw new Error("TODO"); | ||
break; | ||
case Types.NodeType.FIELD: | ||
fieldMap[field.config.name] = this.buildInputObjectField( | ||
field.config, | ||
typeConfig | ||
); | ||
break; | ||
} | ||
fields.forEach((field) => { | ||
fieldMap[field.name] = this.buildInputObjectField(field, typeConfig); | ||
}); | ||
@@ -382,19 +568,28 @@ return fieldMap; | ||
protected buildObjectField( | ||
fieldConfig: Types.OutputFieldConfig, | ||
typeConfig: Types.ObjectTypeConfig | Types.InterfaceTypeConfig | ||
fieldConfig: NexusOutputFieldDef, | ||
typeConfig: | ||
| NexusObjectTypeConfig<string> | ||
| NexusInterfaceTypeConfig<string>, | ||
forInterface: boolean = false | ||
): GraphQLFieldConfig<any, any> { | ||
this.metadata.addField(typeConfig.name, fieldConfig); | ||
if (!fieldConfig.type) { | ||
throw new Error( | ||
`Missing required "type" field for ${typeConfig.name}.${ | ||
fieldConfig.name | ||
}` | ||
); | ||
} | ||
return { | ||
type: this.decorateOutputType( | ||
type: this.decorateType( | ||
this.getOutputType(fieldConfig.type), | ||
fieldConfig, | ||
typeConfig | ||
fieldConfig.list, | ||
this.outputNonNull(typeConfig, fieldConfig) | ||
), | ||
resolve: this.getResolver(fieldConfig, typeConfig), | ||
args: this.buildArgs(fieldConfig.args || {}, typeConfig), | ||
resolve: this.getResolver(fieldConfig, typeConfig, forInterface), | ||
description: fieldConfig.description, | ||
args: this.buildArgs(fieldConfig.args || {}, typeConfig), | ||
deprecationReason: fieldConfig.deprecation, | ||
// TODO: Need to look into subscription semantics and how | ||
// resolution works for them. | ||
// subscribe: fieldConfig.subscribe, | ||
// deprecationReason?: Maybe<string>; | ||
}; | ||
@@ -404,11 +599,13 @@ } | ||
protected buildInputObjectField( | ||
field: Types.InputFieldConfig, | ||
typeConfig: Types.InputTypeConfig | ||
field: NexusInputFieldDef, | ||
typeConfig: NexusInputObjectTypeConfig<any> | ||
): GraphQLInputFieldConfig { | ||
return { | ||
type: this.decorateInputType( | ||
type: this.decorateType( | ||
this.getInputType(field.type), | ||
field, | ||
typeConfig | ||
field.list, | ||
this.inputNonNull(typeConfig, field) | ||
), | ||
defaultValue: field.default, | ||
description: field.description, | ||
}; | ||
@@ -418,15 +615,16 @@ } | ||
protected buildArgs( | ||
args: Types.OutputFieldArgs, | ||
typeConfig: Types.InputTypeConfig | ||
args: Record<string, NexusArgDef<string>>, | ||
typeConfig: NexusObjectTypeConfig<string> | NexusInterfaceTypeConfig<string> | ||
): GraphQLFieldConfigArgumentMap { | ||
const allArgs: GraphQLFieldConfigArgumentMap = {}; | ||
Object.keys(args).forEach((argName) => { | ||
const argDef = args[argName]; | ||
const argDef = args[argName].value; | ||
allArgs[argName] = { | ||
type: this.decorateArgType( | ||
type: this.decorateType( | ||
this.getInputType(argDef.type), | ||
{ ...argDef, name: argName }, | ||
typeConfig | ||
argDef.list, | ||
this.inputNonNull(typeConfig, argDef) | ||
), | ||
description: argDef.description, | ||
defaultValue: argDef.default, | ||
}; | ||
@@ -437,124 +635,79 @@ }); | ||
protected decorateInputType( | ||
type: GraphQLInputType, | ||
fieldConfig: Types.InputFieldConfig, | ||
typeConfig: Types.InputTypeConfig | ||
) { | ||
const { required: _required, requiredListItem, ...rest } = fieldConfig; | ||
const newOpts = rest; | ||
if (typeof _required !== "undefined") { | ||
newOpts.nullable = !_required; | ||
protected inputNonNull( | ||
typeDef: | ||
| NexusObjectTypeConfig<any> | ||
| NexusInterfaceTypeConfig<any> | ||
| NexusInputObjectTypeConfig<any>, | ||
field: NexusInputFieldDef | NexusArgConfig<any> | ||
): boolean { | ||
const { nullable, required } = field; | ||
const { name, nonNullDefaults = {} } = typeDef; | ||
if (typeof nullable !== "undefined" && typeof required !== "undefined") { | ||
throw new Error(`Cannot set both nullable & required on ${name}`); | ||
} | ||
if (typeof requiredListItem !== "undefined") { | ||
if (rest.list) { | ||
newOpts.listItemNullable = !requiredListItem; | ||
} | ||
if (typeof nullable !== "undefined") { | ||
return !nullable; | ||
} | ||
return this.decorateType(type, newOpts, typeConfig, true); | ||
if (typeof required !== "undefined") { | ||
return required; | ||
} | ||
// Null by default | ||
return firstDefined( | ||
nonNullDefaults.input, | ||
this.nonNullDefaults.input, | ||
false | ||
); | ||
} | ||
protected decorateOutputType( | ||
type: GraphQLOutputType, | ||
fieldConfig: Types.FieldConfig, | ||
typeConfig: Types.ObjectTypeConfig | Types.InterfaceTypeConfig | ||
) { | ||
return this.decorateType(type, fieldConfig, typeConfig, false); | ||
protected outputNonNull( | ||
typeDef: NexusObjectTypeConfig<any> | NexusInterfaceTypeConfig<any>, | ||
field: NexusOutputFieldDef | ||
): boolean { | ||
const { nullable } = field; | ||
const { nonNullDefaults = {} } = typeDef; | ||
if (typeof nullable !== "undefined") { | ||
return !nullable; | ||
} | ||
// Non-Null by default | ||
return firstDefined( | ||
nonNullDefaults.output, | ||
this.nonNullDefaults.output, | ||
true | ||
); | ||
} | ||
protected decorateArgType( | ||
type: GraphQLInputType, | ||
argOpts: Types.ArgDefinition & { name: string }, | ||
typeConfig: Types.InputTypeConfig | ||
) { | ||
const { required: _required, requiredListItem, ...rest } = argOpts; | ||
const newOpts = rest; | ||
if (typeof _required !== "undefined") { | ||
newOpts.nullable = !_required; | ||
protected decorateType<T extends GraphQLNamedType>( | ||
type: T, | ||
list: null | undefined | true | boolean[], | ||
isNonNull: boolean | ||
): T { | ||
if (list) { | ||
type = this.decorateList(type, list); | ||
} | ||
if (typeof requiredListItem !== "undefined") { | ||
if (rest.list) { | ||
newOpts.listItemNullable = !requiredListItem; | ||
} | ||
} | ||
return this.decorateType(type, newOpts, typeConfig, true); | ||
return (isNonNull ? GraphQLNonNull(type) : type) as T; | ||
} | ||
/** | ||
* Adds the null / list configuration to the type. | ||
*/ | ||
protected decorateType( | ||
type: GraphQLOutputType, | ||
fieldConfig: Types.Omit<Types.FieldConfig, "type" | "default">, | ||
typeConfig: Types.ObjectTypeConfig | Types.InterfaceTypeConfig, | ||
isInput: false | ||
): GraphQLOutputType; | ||
protected decorateType( | ||
type: GraphQLInputType, | ||
fieldConfig: Types.Omit<Types.FieldConfig, "type" | "default">, | ||
typeConfig: Types.InputTypeConfig, | ||
isInput: true | ||
): GraphQLInputType; | ||
protected decorateType( | ||
type: any, | ||
fieldConfig: Types.Omit<Types.FieldConfig, "type" | "default">, | ||
typeConfig: | ||
| Types.ObjectTypeConfig | ||
| Types.InterfaceTypeConfig | ||
| Types.InputTypeConfig, | ||
isInput: boolean | ||
): any { | ||
protected decorateList<T extends GraphQLOutputType | GraphQLInputType>( | ||
type: T, | ||
list: true | boolean[] | ||
): T { | ||
let finalType = type; | ||
const nullConfig: typeof NULL_DEFAULTS = { | ||
...NULL_DEFAULTS, | ||
...this.nullability, | ||
...typeConfig.nullability, | ||
}; | ||
const { list, nullable, listDepth, listItemNullable } = fieldConfig; | ||
const isNullable = | ||
typeof nullable !== "undefined" | ||
? nullable | ||
: list | ||
? isInput | ||
? nullConfig.inputList | ||
: nullConfig.outputList | ||
: isInput | ||
? nullConfig.input | ||
: nullConfig.output; | ||
if (list) { | ||
const depth = listDepth || 1; | ||
const nullableItem = | ||
typeof listItemNullable !== "undefined" | ||
? listItemNullable | ||
: isInput | ||
? nullConfig.inputListItem | ||
: nullConfig.outputListItem; | ||
if (Array.isArray(nullableItem) && nullableItem.length !== depth) { | ||
throw new Error( | ||
`Incorrect listItemNullable array length for ${typeConfig.name}${ | ||
fieldConfig.name | ||
}, expected ${depth} saw ${nullableItem.length}` | ||
); | ||
} | ||
for (let i = 0; i < depth; i++) { | ||
const isNull = Array.isArray(nullableItem) | ||
? nullableItem[i] | ||
: nullableItem; | ||
if (!Array.isArray(list)) { | ||
return GraphQLList(GraphQLNonNull(type)) as T; | ||
} | ||
if (Array.isArray(list)) { | ||
for (let i = 0; i < list.length; i++) { | ||
const isNull = !list[0]; | ||
if (!isNull) { | ||
finalType = GraphQLNonNull(finalType); | ||
finalType = GraphQLNonNull(finalType) as T; | ||
} | ||
finalType = GraphQLList(finalType); | ||
finalType = GraphQLList(finalType) as T; | ||
} | ||
} else if (typeof listItemNullable !== "undefined") { | ||
console.log( | ||
"listItemNullable should only be set with list: true, this option is ignored" | ||
); | ||
} | ||
if (!isNullable) { | ||
return GraphQLNonNull(finalType); | ||
} | ||
return finalType; | ||
} | ||
protected getInterface(name: string): GraphQLInterfaceType { | ||
protected getInterface( | ||
name: string | NexusInterfaceTypeDef<string> | ||
): GraphQLInterfaceType { | ||
const type = this.getOrBuildType(name); | ||
@@ -589,5 +742,5 @@ if (!isInterfaceType(type)) { | ||
protected getInputType(name: string) { | ||
protected getInputObjectType(name: string): GraphQLInputObjectType { | ||
const type = this.getOrBuildType(name); | ||
if (!isInputType(type)) { | ||
if (!isInputObjectType(type)) { | ||
throw new Error( | ||
@@ -602,4 +755,18 @@ `Expected ${name} to be a valid input type, saw ${ | ||
protected getOutputType(name: string) { | ||
protected getInputType( | ||
name: string | AllNexusInputTypeDefs | ||
): GraphQLPossibleInputs { | ||
const type = this.getOrBuildType(name); | ||
if (!isInputObjectType(type) && !isLeafType(type)) { | ||
throw new Error( | ||
`Expected ${name} to be a possible input type, saw ${ | ||
type.constructor.name | ||
}` | ||
); | ||
} | ||
return type; | ||
} | ||
protected getOutputType(name: string): GraphQLPossibleOutputs { | ||
const type = this.getOrBuildType(name); | ||
if (!isOutputType(type)) { | ||
@@ -615,3 +782,8 @@ throw new Error( | ||
protected getObjectType(name: string) { | ||
protected getObjectType( | ||
name: string | NexusObjectTypeDef<string> | ||
): GraphQLObjectType { | ||
if (isNexusNamedTypeDef(name)) { | ||
return this.getObjectType(name.name); | ||
} | ||
const type = this.getOrBuildType(name); | ||
@@ -626,3 +798,9 @@ if (!isObjectType(type)) { | ||
protected getOrBuildType(name: string): GraphQLNamedType { | ||
protected getOrBuildType( | ||
name: string | AllNexusNamedTypeDefs | ||
): GraphQLNamedType { | ||
invariantGuard(name); | ||
if (isNexusNamedTypeDef(name)) { | ||
return this.getOrBuildType(name.name); | ||
} | ||
if (SCALARS[name]) { | ||
@@ -636,3 +814,3 @@ return SCALARS[name]; | ||
throw new Error( | ||
`GraphQL Nexus: Circular dependency detected, while building types ${Array.from( | ||
`Nexus GraphQL: Circular dependency detected, while building types ${Array.from( | ||
this.buildingTypes | ||
@@ -643,5 +821,17 @@ )}` | ||
const pendingType = this.pendingTypeMap[name]; | ||
if (pendingType) { | ||
this.buildingTypes.add(name); | ||
return pendingType.buildType(this); | ||
if (isNexusNamedTypeDef(pendingType)) { | ||
this.buildingTypes.add(pendingType.name); | ||
if (isNexusObjectTypeDef(pendingType)) { | ||
return this.objectType(pendingType.value); | ||
} else if (isNexusInterfaceTypeDef(pendingType)) { | ||
return this.interfaceType(pendingType.value); | ||
} else if (isNexusEnumTypeDef(pendingType)) { | ||
return this.enumType(pendingType.value); | ||
} else if (isNexusScalarTypeDef(pendingType)) { | ||
return this.scalarType(pendingType.value); | ||
} else if (isNexusInputObjectTypeDef(pendingType)) { | ||
return this.inputObjectType(pendingType.value); | ||
} else if (isNexusUnionTypeDef(pendingType)) { | ||
return this.unionType(pendingType.value); | ||
} | ||
} | ||
@@ -652,11 +842,12 @@ return this.missingType(name); | ||
protected getResolver( | ||
fieldOptions: Types.OutputFieldConfig, | ||
typeConfig: Types.ObjectTypeConfig | Types.InterfaceTypeConfig | ||
fieldOptions: NexusOutputFieldDef, | ||
typeConfig: NexusObjectTypeConfig<any> | NexusInterfaceTypeConfig<any>, | ||
forInterface: boolean = false | ||
) { | ||
let resolver = typeConfig.defaultResolver || defaultFieldResolver; | ||
let resolver: undefined | GraphQLFieldResolver<any, any>; | ||
if (fieldOptions.resolve) { | ||
resolver = fieldOptions.resolve; | ||
} | ||
if (typeof fieldOptions.default !== "undefined") { | ||
resolver = withDefaultValue(resolver, fieldOptions.default); | ||
if (!resolver && !forInterface) { | ||
resolver = (typeConfig as NexusObjectTypeConfig<any>).defaultResolver; | ||
} | ||
@@ -667,31 +858,14 @@ return resolver; | ||
function withDefaultValue( | ||
resolver: GraphQLFieldResolver<any, any>, | ||
defaultValue: any | ||
): GraphQLFieldResolver<any, any> { | ||
return (root, args, ctx, info) => { | ||
const result = resolver(root, args, ctx, info); | ||
if (typeof result === "undefined" || result === null) { | ||
return typeof defaultValue === "function" ? defaultValue() : defaultValue; | ||
} | ||
if (isPromise(result)) { | ||
return result.then((val: any) => { | ||
if (typeof val === "undefined" || val === null) { | ||
return typeof defaultValue === "function" | ||
? defaultValue() | ||
: defaultValue; | ||
} | ||
return val; | ||
}); | ||
} | ||
return result; | ||
}; | ||
} | ||
function extendError(name: string) { | ||
return new Error( | ||
`${name} was already defined as a type, check the docs for extending` | ||
`${name} was already defined and imported as a type, check the docs for extending types` | ||
); | ||
} | ||
export interface BuildTypes< | ||
TypeMapDefs extends Record<string, GraphQLNamedType> | ||
> { | ||
typeMap: TypeMapDefs; | ||
} | ||
/** | ||
@@ -703,12 +877,9 @@ * Builds the types, normalizing the "types" passed into the schema for a | ||
export function buildTypes< | ||
TypeMapDefs extends Record<string, GraphQLNamedType> = any, | ||
DirectiveDefs extends Record<string, GraphQLDirective> = any | ||
TypeMapDefs extends Record<string, GraphQLNamedType> = any | ||
>( | ||
types: any, | ||
config: Types.BuilderConfig = { outputs: false }, | ||
SchemaBuilderClass: typeof SchemaBuilder = SchemaBuilder, | ||
MetadataClass: typeof Metadata = Metadata | ||
): Types.BuildTypes<TypeMapDefs, DirectiveDefs> { | ||
const metadata = new MetadataClass(config); | ||
const builder = new SchemaBuilderClass(metadata, config); | ||
config: BuilderConfig = { outputs: false }, | ||
SchemaBuilderClass: typeof SchemaBuilder = SchemaBuilder | ||
): BuildTypes<TypeMapDefs> { | ||
const builder = new SchemaBuilderClass(config); | ||
addTypes(builder, types); | ||
@@ -722,13 +893,12 @@ return builder.getFinalTypeMap(); | ||
} | ||
if (isWrappedTypeDef(types)) { | ||
types = types.type; | ||
if (typeof types === "function") { | ||
addTypes(builder, types(builder)); | ||
return; | ||
} | ||
if (isNexusWrappedFn(types)) { | ||
addTypes(builder, types.fn(builder)); | ||
return; | ||
} | ||
if (isNamedTypeDef(types) || isNamedType(types)) { | ||
if ( | ||
isNexusNamedTypeDef(types) || | ||
isNexusExtendTypeDef(types) || | ||
isNamedType(types) | ||
) { | ||
builder.addType(types); | ||
} else if (types instanceof DirectiveTypeDef || isDirective(types)) { | ||
builder.addDirective(types); | ||
} else if (Array.isArray(types)) { | ||
@@ -742,15 +912,15 @@ types.forEach((typeDef) => addTypes(builder, typeDef)); | ||
/** | ||
* Builds the schema, returning both the schema and metadata. | ||
* Builds the schema, we may return more than just the schema | ||
* from this one day. | ||
*/ | ||
export function makeSchemaWithMetadata( | ||
options: Types.SchemaConfig, | ||
SchemaBuilderClass: typeof SchemaBuilder = SchemaBuilder, | ||
MetadataClass: typeof Metadata = Metadata | ||
): { metadata: Metadata; schema: GraphQLSchema } { | ||
const { typeMap: typeMap, directiveMap: directiveMap, metadata } = buildTypes( | ||
export function makeSchemaInternal( | ||
options: SchemaConfig, | ||
SchemaBuilderClass: typeof SchemaBuilder = SchemaBuilder | ||
): { schema: GraphQLSchema } { | ||
const { typeMap: typeMap } = buildTypes( | ||
options.types, | ||
options, | ||
SchemaBuilderClass, | ||
MetadataClass | ||
SchemaBuilderClass | ||
); | ||
let { Query, Mutation, Subscription } = typeMap; | ||
@@ -760,3 +930,3 @@ | ||
console.warn( | ||
"GraphQL Nexus: You should define a root `Query` type for your schema" | ||
"Nexus: You should define a root `Query` type for your schema" | ||
); | ||
@@ -796,9 +966,6 @@ Query = new GraphQLObjectType({ | ||
subscription: Subscription, | ||
directives: specifiedDirectives.concat(objValues(directiveMap)), | ||
types: objValues(typeMap), | ||
}); | ||
metadata.finishConstruction(); | ||
return { schema, metadata }; | ||
return { schema }; | ||
} | ||
@@ -808,3 +975,3 @@ | ||
* Defines the GraphQL schema, by combining the GraphQL types defined | ||
* by the GraphQL Nexus layer or any manually defined GraphQLType objects. | ||
* by the Nexus GraphQL layer or any manually defined GraphQLType objects. | ||
* | ||
@@ -814,4 +981,4 @@ * Requires at least one type be named "Query", which will be used as the | ||
*/ | ||
export function makeSchema(options: Types.SchemaConfig): GraphQLSchema { | ||
const { schema, metadata } = makeSchemaWithMetadata(options); | ||
export function makeSchema(options: SchemaConfig): GraphQLSchema { | ||
const { schema } = makeSchemaInternal(options); | ||
@@ -821,3 +988,5 @@ // Only in development envs do we want to worry about regenerating the | ||
const { | ||
shouldGenerateArtifacts = process.env.NODE_ENV !== "production", | ||
shouldGenerateArtifacts = Boolean( | ||
!process.env.NODE_ENV || process.env.NODE_ENV === "development" | ||
), | ||
} = options; | ||
@@ -828,3 +997,5 @@ | ||
// in the optional thunk for the typegen config | ||
metadata.generateArtifacts(schema); | ||
new TypegenMetadata(options).generateArtifacts(schema).catch((e) => { | ||
console.error(e); | ||
}); | ||
} | ||
@@ -835,14 +1006,9 @@ | ||
export function isWrappedTypeDef(obj: any): obj is WrappedType { | ||
return obj instanceof WrappedType; | ||
function invariantGuard(val: any) { | ||
if (!Boolean(val)) { | ||
throw new Error( | ||
"Nexus Error: This should never happen, " + | ||
"please check your code or open a GitHub ticket if you believe this is an issue with Nexus" | ||
); | ||
} | ||
} | ||
export function isNamedTypeDef(obj: any): obj is Types.NamedTypeDef { | ||
return ( | ||
obj instanceof ObjectTypeDef || | ||
obj instanceof InputObjectTypeDef || | ||
obj instanceof EnumTypeDef || | ||
obj instanceof UnionTypeDef || | ||
obj instanceof InterfaceTypeDef | ||
); | ||
} |
755
src/core.ts
@@ -1,734 +0,21 @@ | ||
import * as Types from "./types"; | ||
import { | ||
GraphQLFieldResolver, | ||
GraphQLInputObjectType, | ||
GraphQLInterfaceType, | ||
GraphQLUnionType, | ||
GraphQLEnumType, | ||
GraphQLIsTypeOfFn, | ||
DirectiveLocationEnum, | ||
GraphQLObjectType, | ||
GraphQLDirective, | ||
GraphQLScalarType, | ||
} from "graphql"; | ||
import { dedent } from "./utils"; | ||
import { SchemaBuilder, isNamedTypeDef } from "./builder"; | ||
import { Metadata } from "./metadata"; | ||
export { SDLConverter } from "./sdlConverter"; | ||
// Export the ts definitions so they can be used by library authors under `core.Types` | ||
export { Types }; | ||
// Same as above, export all core things under the "core" namespace | ||
export { SchemaBuilder, isNamedTypeDef, Metadata }; | ||
// Keeping this in core since it shouldn't be needed directly | ||
export { typegenAutoConfig } from "./autoConfig"; | ||
declare global { | ||
interface GraphQLNexusGen {} | ||
} | ||
/** | ||
* Provided to the [objectType](#objectType) function, this | ||
*/ | ||
export class ObjectTypeDef< | ||
GenTypes = GraphQLNexusGen, | ||
TypeName extends string = any | ||
> { | ||
/** | ||
* All metadata about the object type | ||
*/ | ||
protected typeConfig: Types.ObjectTypeConfig; | ||
constructor(readonly name: string) { | ||
this.typeConfig = { | ||
name, | ||
fields: [], | ||
interfaces: [], | ||
directives: [], | ||
fieldModifications: {}, | ||
}; | ||
} | ||
/** | ||
* Mixes in an existing field definition or object type | ||
* with the current type. | ||
*/ | ||
mix(typeName: string, options?: Types.MixOpts<any>) { | ||
this.typeConfig.fields.push({ | ||
item: Types.NodeType.MIX, | ||
typeName, | ||
mixOptions: options || {}, | ||
}); | ||
} | ||
/** | ||
* Add an ID field type to the object schema. | ||
*/ | ||
id<FieldName extends string>( | ||
name: FieldName, | ||
...opts: Types.ConditionalOutputFieldOpts<GenTypes, TypeName, FieldName> | ||
) { | ||
this.field(name, "ID", ...opts); | ||
} | ||
/** | ||
* Add an Int field type to the object schema. | ||
*/ | ||
int<FieldName extends string>( | ||
name: FieldName, | ||
...opts: Types.ConditionalOutputFieldOpts<GenTypes, TypeName, FieldName> | ||
) { | ||
this.field(name, "Int", ...opts); | ||
} | ||
/** | ||
* Add a Float field type to the object schema. | ||
*/ | ||
float<FieldName extends string>( | ||
name: FieldName, | ||
...opts: Types.ConditionalOutputFieldOpts<GenTypes, TypeName, FieldName> | ||
) { | ||
this.field(name, "Float", ...opts); | ||
} | ||
/** | ||
* Add a String field type to the object schema. | ||
*/ | ||
string<FieldName extends string>( | ||
name: FieldName, | ||
...opts: Types.ConditionalOutputFieldOpts<GenTypes, TypeName, FieldName> | ||
) { | ||
this.field(name, "String", ...opts); | ||
} | ||
/** | ||
* Add a Boolean field type to the object schema. | ||
*/ | ||
boolean<FieldName extends string>( | ||
name: FieldName, | ||
...opts: Types.ConditionalOutputFieldOpts<GenTypes, TypeName, FieldName> | ||
) { | ||
this.field(name, "Boolean", ...opts); | ||
} | ||
/** | ||
* Adds a new field to the object type | ||
*/ | ||
field<FieldName extends string>( | ||
name: FieldName, | ||
type: Types.AllOutputTypes<GenTypes> | Types.BaseScalars, | ||
...opts: Types.ConditionalOutputFieldOpts<GenTypes, TypeName, FieldName> | ||
) { | ||
let options: Types.OutputFieldOpts<GenTypes, TypeName, any> = {}; | ||
if (typeof opts[0] === "function") { | ||
options.resolve = opts[0]; | ||
} else { | ||
options = { ...opts[0] }; | ||
} | ||
this.typeConfig.fields.push({ | ||
item: Types.NodeType.FIELD, | ||
config: { | ||
name, | ||
type, | ||
...options, | ||
}, | ||
}); | ||
} | ||
/** | ||
* Declare that an object type implements a particular interface, | ||
* by providing the name of the interface | ||
*/ | ||
implements(...interfaceName: Types.AllInterfaces<GenTypes>[]) { | ||
this.typeConfig.interfaces.push(...interfaceName); | ||
} | ||
/** | ||
* Adds a description to the `GraphQLObjectType` | ||
* | ||
* Descriptions will be output as type annotations in the generated SDL | ||
*/ | ||
description(description: string) { | ||
this.typeConfig.description = dedent(description); | ||
} | ||
/** | ||
* Adds an "isTypeOf" check to the object type. | ||
*/ | ||
isTypeOf(fn: (value: GraphQLIsTypeOfFn<any, any>) => boolean): void { | ||
this.typeConfig.isTypeOf = fn; | ||
} | ||
/** | ||
* Used to modify a field already defined on an interface or mixed-in | ||
* from another type. | ||
* | ||
* At this point the type will not change, but the resolver, | ||
* default, property, or description fields can. | ||
*/ | ||
modify<FieldName extends Types.ObjectTypeFields<GenTypes, TypeName>>( | ||
field: FieldName, | ||
options: Types.ModifyFieldOpts<GenTypes, TypeName, FieldName> | ||
): void { | ||
this.typeConfig.fieldModifications[field as string] = options; | ||
} | ||
/** | ||
* Supply the default field resolver for all members of this type | ||
*/ | ||
defaultResolver( | ||
resolverFn: GraphQLFieldResolver< | ||
Types.RootValue<GenTypes, TypeName>, | ||
Types.ContextValue<GenTypes> | ||
> | ||
): void { | ||
this.typeConfig.defaultResolver = resolverFn; | ||
} | ||
/** | ||
* Adds a directive directly to the object definition | ||
* | ||
* > Should be used rarely, typically only for interpretation by other schema consumers. | ||
*/ | ||
directive(name: string, args?: Record<string, any>): void { | ||
this.typeConfig.directives.push({ | ||
name, | ||
args: args || {}, | ||
}); | ||
} | ||
/** | ||
* Configures the nullability for the type, check the | ||
* documentation's "Getting Started" section to learn | ||
* more about GraphQL Nexus's assumptions and configuration | ||
* on nullability. | ||
* | ||
* @param nullability | ||
*/ | ||
nullability(nullability: Types.NullabilityConfig): void { | ||
if (this.typeConfig.nullability) { | ||
console.warn( | ||
`nullability has already been set for type ${ | ||
this.typeConfig.name | ||
}, the previous value will be replaced` | ||
); | ||
} | ||
this.typeConfig.nullability = nullability; | ||
} | ||
/** | ||
* @internal | ||
*/ | ||
buildType(builder: SchemaBuilder): GraphQLObjectType { | ||
return builder.objectType(this.typeConfig); | ||
} | ||
} | ||
/** | ||
* Backing type for an enum member. | ||
*/ | ||
export class EnumTypeDef<GenTypes = GraphQLNexusGen> { | ||
protected typeConfig: Types.EnumTypeConfig; | ||
constructor(readonly name: string) { | ||
this.typeConfig = { | ||
name, | ||
members: [], | ||
directives: [], | ||
}; | ||
} | ||
mix<EnumName extends Types.EnumNames<GenTypes>>( | ||
typeName: EnumName, | ||
options?: Types.MixOpts<Types.EnumMembers<GenTypes, EnumName>> | ||
) { | ||
this.typeConfig.members.push({ | ||
item: Types.NodeType.MIX, | ||
typeName, | ||
mixOptions: options || {}, | ||
}); | ||
} | ||
member(name: string, config?: Types.EnumMemberConfig) { | ||
this.typeConfig.members.push({ | ||
item: Types.NodeType.ENUM_MEMBER, | ||
info: { | ||
name, | ||
value: name, | ||
...config, | ||
}, | ||
}); | ||
} | ||
/** | ||
* Sets the members of the enum | ||
*/ | ||
members(info: Array<Types.EnumMemberInfo | string>) { | ||
info.forEach((member) => { | ||
if (typeof member === "string") { | ||
return this.typeConfig.members.push({ | ||
item: Types.NodeType.ENUM_MEMBER, | ||
info: { name: member, value: member }, | ||
}); | ||
} | ||
this.typeConfig.members.push({ | ||
item: Types.NodeType.ENUM_MEMBER, | ||
info: member, | ||
}); | ||
}); | ||
} | ||
/** | ||
* Adds a description to the `GraphQLEnumType` | ||
* | ||
* Descriptions will be output as type annotations in the generated SDL | ||
*/ | ||
description(description: string) { | ||
this.typeConfig.description = dedent(description); | ||
} | ||
/** | ||
* Should be used very rarely, adds a directive directly to the | ||
* enum definition - for interpretation by other schema consumers. | ||
*/ | ||
directive(name: string, args?: Record<string, any>) { | ||
this.typeConfig.directives.push({ | ||
name, | ||
args: args || {}, | ||
}); | ||
} | ||
/** | ||
* @internal | ||
*/ | ||
buildType(builder: SchemaBuilder): GraphQLEnumType { | ||
return builder.enumType(this.typeConfig); | ||
} | ||
} | ||
/** | ||
* Configure the `GraphQLUnionType` definition | ||
*/ | ||
export class UnionTypeDef< | ||
GenTypes = GraphQLNexusGen, | ||
TypeName extends string = any | ||
> { | ||
protected typeConfig: Types.UnionTypeConfig; | ||
constructor(readonly name: string) { | ||
this.typeConfig = { | ||
name, | ||
members: [], | ||
directives: [], | ||
}; | ||
} | ||
/** | ||
* Take an existing union and base the type off of that, using the `omit` | ||
* option to exclude members of the other union. | ||
* | ||
* > Note: Circular dependencies between unions are not allowed and will | ||
* trigger an error at build-time. | ||
*/ | ||
mix<UnionTypeName extends string>( | ||
type: UnionTypeName, | ||
options?: Types.MixOmitOpts<any> | ||
) { | ||
this.typeConfig.members.push({ | ||
item: Types.NodeType.MIX, | ||
typeName: type, | ||
mixOptions: options || {}, | ||
}); | ||
} | ||
/** | ||
* Add one or more members to the GraphQLUnion. Any types provided should be valid | ||
* object types available to the schema. | ||
*/ | ||
members(...types: Array<Types.ObjectNames<GenTypes>>) { | ||
types.forEach((typeName) => { | ||
this.typeConfig.members.push({ | ||
item: Types.NodeType.UNION_MEMBER, | ||
typeName, | ||
}); | ||
}); | ||
} | ||
/** | ||
* Define a type resolver function for the union type. The Resolver should | ||
* return the type name of the union member that should be fulfilled. | ||
* | ||
* > Providing this is highly recommended. If one is not provided, the | ||
* default implementation will call `isTypeOf` on each implementing Object type. | ||
* | ||
* @see https://github.com/graphql/graphql-js/issues/876#issuecomment-304398882 | ||
*/ | ||
resolveType(typeResolver: Types.TypeResolver<GenTypes, TypeName>) { | ||
this.typeConfig.resolveType = typeResolver; | ||
} | ||
/** | ||
* Should be used very rarely, adds a directive directly to the | ||
* union definition - for interpretation by other schema consumers. | ||
*/ | ||
directive(name: string, args?: Record<string, any>) { | ||
this.typeConfig.directives.push({ | ||
name, | ||
args: args || {}, | ||
}); | ||
} | ||
/** | ||
* @internal | ||
*/ | ||
buildType(builder: SchemaBuilder): GraphQLUnionType { | ||
return builder.unionType(this.typeConfig); | ||
} | ||
} | ||
export class InterfaceTypeDef< | ||
GenTypes = GraphQLNexusGen, | ||
TypeName extends string = any | ||
> { | ||
/** | ||
* Metadata about the object type | ||
*/ | ||
protected typeConfig: Types.InterfaceTypeConfig; | ||
constructor(readonly name: string) { | ||
this.typeConfig = { | ||
name, | ||
fields: [], | ||
directives: [], | ||
}; | ||
} | ||
/** | ||
* Mixes in an existing field definition or object type | ||
* with the current type. | ||
*/ | ||
mix(typeName: string, options?: Types.MixOpts<any>) { | ||
this.typeConfig.fields.push({ | ||
item: Types.NodeType.MIX, | ||
typeName, | ||
mixOptions: options || {}, | ||
}); | ||
} | ||
/** | ||
* Add an ID field type to the object schema. | ||
*/ | ||
id<FieldName extends string>( | ||
name: FieldName, | ||
...opts: Types.ConditionalOutputFieldOpts<GenTypes, TypeName, FieldName> | ||
) { | ||
this.field(name, "ID", ...opts); | ||
} | ||
/** | ||
* Add an Int field type to the object schema. | ||
*/ | ||
int<FieldName extends string>( | ||
name: FieldName, | ||
...opts: Types.ConditionalOutputFieldOpts<GenTypes, TypeName, FieldName> | ||
) { | ||
this.field(name, "Int", ...opts); | ||
} | ||
/** | ||
* Add a Float field type to the object schema. | ||
*/ | ||
float<FieldName extends string>( | ||
name: FieldName, | ||
...opts: Types.ConditionalOutputFieldOpts<GenTypes, TypeName, FieldName> | ||
) { | ||
this.field(name, "Float", ...opts); | ||
} | ||
/** | ||
* Add a String field type to the object schema. | ||
*/ | ||
string<FieldName extends string>( | ||
name: FieldName, | ||
...opts: Types.ConditionalOutputFieldOpts<GenTypes, TypeName, FieldName> | ||
) { | ||
this.field(name, "String", ...opts); | ||
} | ||
/** | ||
* Add a Boolean field type to the object schema. | ||
*/ | ||
boolean<FieldName extends string>( | ||
name: FieldName, | ||
...opts: Types.ConditionalOutputFieldOpts<GenTypes, TypeName, FieldName> | ||
) { | ||
this.field(name, "Boolean", ...opts); | ||
} | ||
/** | ||
* Adds a new field to the object type | ||
*/ | ||
field<FieldName extends string>( | ||
name: FieldName, | ||
type: Types.AllOutputTypes<GenTypes> | Types.BaseScalars, | ||
...opts: Types.ConditionalOutputFieldOpts<GenTypes, TypeName, FieldName> | ||
) { | ||
let options: Types.OutputFieldOpts<GenTypes, TypeName, any> = {}; | ||
if (typeof opts[0] === "function") { | ||
options.resolve = opts[0]; | ||
} else { | ||
options = { ...opts[0] }; | ||
} | ||
this.typeConfig.fields.push({ | ||
item: Types.NodeType.FIELD, | ||
config: { | ||
name, | ||
type, | ||
...options, | ||
}, | ||
}); | ||
} | ||
/** | ||
* Adds a description to the `GraphQLInterfaceType` | ||
* | ||
* Descriptions will be output as type annotations in the generated SDL | ||
*/ | ||
description(description: string) { | ||
this.typeConfig.description = dedent(description); | ||
} | ||
/** | ||
* Optionally provide a custom type resolver function. If one is not provided, | ||
* the default implementation will call `isTypeOf` on each implementing | ||
* Object type. | ||
*/ | ||
resolveType(typeResolver: Types.TypeResolver<GenTypes, TypeName>) { | ||
this.typeConfig.resolveType = typeResolver; | ||
} | ||
/** | ||
* Should be used very rarely, adds a directive directly to the | ||
* interface definition - for interpretation by other schema consumers. | ||
*/ | ||
directive(name: string, args?: Record<string, any>) { | ||
this.typeConfig.directives.push({ | ||
name, | ||
args: args || {}, | ||
}); | ||
} | ||
/** | ||
* @internal | ||
*/ | ||
buildType(builder: SchemaBuilder): GraphQLInterfaceType { | ||
return builder.interfaceType(this.typeConfig); | ||
} | ||
} | ||
export class InputObjectTypeDef< | ||
GenTypes = GraphQLNexusGen, | ||
TypeName extends string = any | ||
> { | ||
protected typeConfig: Types.InputTypeConfig; | ||
constructor(readonly name: string) { | ||
this.typeConfig = { | ||
name, | ||
fields: [], | ||
directives: [], | ||
}; | ||
} | ||
/** | ||
* Add an ID field type to the object schema. | ||
*/ | ||
id(name: string, options?: Types.InputFieldOpts<GenTypes, "ID">) { | ||
this.field(name, "ID", options); | ||
} | ||
/** | ||
* Add an Int field type to the object schema. | ||
*/ | ||
int(name: string, options?: Types.InputFieldOpts<GenTypes, "Int">) { | ||
this.field(name, "Int", options); | ||
} | ||
/** | ||
* Add a Float field type to the object schema. | ||
*/ | ||
float(name: string, options?: Types.InputFieldOpts<GenTypes, "Float">) { | ||
this.field(name, "Float", options); | ||
} | ||
/** | ||
* Add a String field type to the object schema. | ||
*/ | ||
string(name: string, options?: Types.InputFieldOpts<GenTypes, "String">) { | ||
this.field(name, "String", options); | ||
} | ||
/** | ||
* Add a Boolean field type to the object schema. | ||
*/ | ||
boolean(name: string, options?: Types.InputFieldOpts<GenTypes, "Boolean">) { | ||
this.field(name, "Boolean", options); | ||
} | ||
/** | ||
* Adds a new field to the input object type | ||
*/ | ||
field<FieldName extends string>( | ||
name: FieldName, | ||
type: Types.AllInputTypes<GenTypes> | Types.BaseScalars, | ||
options?: Types.InputFieldOpts<GenTypes, TypeName> | ||
) { | ||
this.typeConfig.fields.push({ | ||
item: Types.NodeType.FIELD, | ||
config: { | ||
name, | ||
type, | ||
...options, | ||
}, | ||
}); | ||
} | ||
/** | ||
* Adds a description to the `GraphQLInputObjectType` | ||
* | ||
* Descriptions will be output as type annotations in the generated SDL | ||
*/ | ||
description(description: string) { | ||
this.typeConfig.description = dedent(description); | ||
} | ||
/** | ||
* Should be used very rarely, adds a directive directly to the | ||
* input object definition - for interpretation by other schema consumers. | ||
*/ | ||
directive(name: string, args?: Record<string, any>) { | ||
this.typeConfig.directives.push({ | ||
name, | ||
args: args || {}, | ||
}); | ||
} | ||
/** | ||
* Configures the nullability for the type | ||
* | ||
* @see nullability | ||
*/ | ||
nullability(nullability: Types.NullabilityConfig) { | ||
if (this.typeConfig.nullability) { | ||
console.warn( | ||
`nullability has already been set for type ${ | ||
this.typeConfig.name | ||
}, the previous value will be replaced` | ||
); | ||
} | ||
this.typeConfig.nullability = nullability; | ||
} | ||
/** | ||
* @internal | ||
*/ | ||
buildType(builder: SchemaBuilder): GraphQLInputObjectType { | ||
return builder.inputObjectType(this.typeConfig); | ||
} | ||
} | ||
export class DirectiveTypeDef<GenTypes = GraphQLNexusGen> { | ||
protected typeConfig: Types.DirectiveTypeConfig; | ||
constructor(readonly name: string) { | ||
this.typeConfig = { | ||
name, | ||
locations: [], | ||
directiveArgs: [], | ||
}; | ||
} | ||
description(description: string) { | ||
this.typeConfig.description = dedent(description); | ||
} | ||
locations(...location: DirectiveLocationEnum[]) { | ||
this.typeConfig.locations.push(...location); | ||
} | ||
/** | ||
* Add an ID field type to the object schema. | ||
*/ | ||
id(name: string, options?: Types.InputFieldOpts<GenTypes, "ID">) { | ||
this.field(name, "ID", options); | ||
} | ||
/** | ||
* Add an Int field type to the object schema. | ||
*/ | ||
int(name: string, options?: Types.InputFieldOpts<GenTypes, "Int">) { | ||
this.field(name, "Int", options); | ||
} | ||
/** | ||
* Add a Float field type to the object schema. | ||
*/ | ||
float(name: string, options?: Types.InputFieldOpts<GenTypes, "Float">) { | ||
this.field(name, "Float", options); | ||
} | ||
/** | ||
* Add a String field type to the object schema. | ||
*/ | ||
string(name: string, options?: Types.InputFieldOpts<GenTypes, "String">) { | ||
this.field(name, "String", options); | ||
} | ||
/** | ||
* Add a Boolean field type to the object schema. | ||
*/ | ||
boolean(name: string, options?: Types.InputFieldOpts<GenTypes, "Boolean">) { | ||
this.field(name, "Boolean", options); | ||
} | ||
/** | ||
* Adds a new field to the input object type | ||
*/ | ||
field<TypeName extends Types.AllInputTypes<GenTypes> | Types.BaseScalars>( | ||
name: string, | ||
type: TypeName, | ||
options?: Types.InputFieldOpts<GenTypes, TypeName> | ||
) { | ||
this.typeConfig.directiveArgs.push({ | ||
name, | ||
type, | ||
...options, | ||
}); | ||
} | ||
/** | ||
* @internal | ||
*/ | ||
buildType(builder: SchemaBuilder): GraphQLDirective { | ||
return builder.directiveType(this.typeConfig); | ||
} | ||
} | ||
/** | ||
* The `WrappedType` exists to signify that the value returned from | ||
* the type construction APIs should not be used externally outside of the | ||
* builder function. It also is useful if you need the SchemaBuilder, in that | ||
* it can take a function which is lazy-evaluated to build the type. | ||
*/ | ||
export class WrappedType { | ||
constructor( | ||
readonly type: | ||
| Types.NamedTypeDef | ||
| DirectiveTypeDef | ||
| GraphQLScalarType | ||
| ((schema: SchemaBuilder) => WrappedType) | ||
) {} | ||
} | ||
// The "core" is used as a namespace to re-export everything, | ||
// For anyone who wants to use the internals | ||
export * from "./builder"; | ||
export * from "./sdlConverter"; | ||
export * from "./typegen"; | ||
export * from "./typegenAutoConfig"; | ||
export * from "./typegenFormatPrettier"; | ||
export * from "./typegenMetadata"; | ||
export * from "./typegenTypeHelpers"; | ||
export * from "./utils"; | ||
export * from "./definitions/_types"; | ||
export * from "./definitions/args"; | ||
export * from "./definitions/definitionBlocks"; | ||
export * from "./definitions/enumType"; | ||
export * from "./definitions/extendType"; | ||
export * from "./definitions/inputObjectType"; | ||
export * from "./definitions/interfaceType"; | ||
export * from "./definitions/objectType"; | ||
export * from "./definitions/scalarType"; | ||
export * from "./definitions/unionType"; | ||
export * from "./definitions/wrapping"; |
@@ -1,5 +0,24 @@ | ||
export * from "./definitions"; | ||
// All of the Public API definitions | ||
export { buildTypes, makeSchema } from "./builder"; | ||
export { | ||
arg, | ||
booleanArg, | ||
floatArg, | ||
idArg, | ||
intArg, | ||
stringArg, | ||
} from "./definitions/args"; | ||
export { enumType } from "./definitions/enumType"; | ||
export { extendType } from "./definitions/extendType"; | ||
export { inputObjectType } from "./definitions/inputObjectType"; | ||
export { interfaceType } from "./definitions/interfaceType"; | ||
export { objectType } from "./definitions/objectType"; | ||
export { scalarType } from "./definitions/scalarType"; | ||
export { unionType } from "./definitions/unionType"; | ||
export { nexusWrappedFn } from "./definitions/wrapping"; | ||
export { convertSDL } from "./sdlConverter"; | ||
export { groupTypes } from "./utils"; | ||
export { FieldResolver } from "./typegenTypeHelpers"; | ||
export { core, blocks }; | ||
import * as core from "./core"; | ||
export { core }; | ||
export { makeSchema, buildTypes, makeSchemaWithMetadata } from "./builder"; | ||
export { convertSDL } from "./sdlConverter"; | ||
import * as blocks from "./blocks"; |
@@ -1,16 +0,17 @@ | ||
import { dedent } from "./utils"; | ||
const { version } = require("../package.json"); | ||
export const SDL_HEADER = dedent` | ||
### This file was autogenerated by GraphQL Nexus | ||
### Do not make changes to this file directly | ||
export const SDL_HEADER = `### This file was autogenerated by Nexus ${version} | ||
### Do not make changes to this file directly | ||
`; | ||
export const TYPEGEN_HEADER = dedent` | ||
/** | ||
* This file is automatically generated by GraphQL Nexus | ||
* Do not make changes to this file directly | ||
* | ||
* For better typings, you should provide configuration for how to lookup | ||
* the types. See the documentation for "typegenAutoConfig" | ||
*/ | ||
export const TYPEGEN_HEADER = `/** | ||
* This file was automatically generated by Nexus ${version} | ||
* Do not make changes to this file directly | ||
*/ | ||
`; | ||
export const TYPEGEN_CONFIG_WARNING = `/** | ||
* For better typings, you should provide configuration for how to lookup | ||
* the types. See the documentation for "typegenAutoConfig" | ||
*/ | ||
`; |
import { | ||
buildSchema, | ||
lexicographicSortSchema, | ||
isObjectType, | ||
isInterfaceType, | ||
isScalarType, | ||
isInputObjectType, | ||
GraphQLObjectType, | ||
@@ -14,116 +9,182 @@ GraphQLEnumType, | ||
GraphQLUnionType, | ||
isUnionType, | ||
isEnumType, | ||
GraphQLField, | ||
GraphQLSchema, | ||
GraphQLNamedType, | ||
GraphQLField, | ||
} from "graphql"; | ||
import { isInterfaceField, eachObj } from "./utils"; | ||
import { groupTypes, GroupedTypes } from "./utils"; | ||
export function convertSDL(sdl: string, commonjs: boolean = false) { | ||
return new SDLConverter(commonjs).convert(sdl); | ||
return new SDLConverter(commonjs, sdl).print(); | ||
} | ||
/** | ||
* Convert an existing SDL schema into a GraphQL Nexus format | ||
* Convert an existing SDL schema into a Nexus GraphQL format | ||
*/ | ||
export class SDLConverter { | ||
protected export: string; | ||
protected schema: GraphQLSchema; | ||
protected groupedTypes: GroupedTypes; | ||
constructor(commonjs: boolean = false) { | ||
constructor(commonjs: boolean = false, sdl: string) { | ||
this.export = commonjs ? "exports." : "export const "; | ||
this.schema = buildSchema(sdl); | ||
this.groupedTypes = groupTypes(this.schema); | ||
} | ||
convert(sdl: string) { | ||
let schema = buildSchema(sdl); | ||
if (typeof lexicographicSortSchema === "function") { | ||
schema = lexicographicSortSchema(schema); | ||
print() { | ||
return [ | ||
this.printObjectTypes(), | ||
this.printInterfaceTypes(), | ||
this.printInputObjectTypes(), | ||
this.printUnionTypes(), | ||
this.printEnumTypes(), | ||
this.printScalarTypes(), | ||
].join("\n\n"); | ||
} | ||
printObjectTypes() { | ||
if (this.groupedTypes.object.length > 0) { | ||
return this.groupedTypes.object | ||
.map((t) => this.printObjectType(t)) | ||
.join("\n"); | ||
} | ||
const typeMap = schema.getTypeMap(); | ||
const typeFragments: string[] = []; | ||
Object.keys(typeMap).forEach((typeName) => { | ||
if (typeName.indexOf("__") === 0) { | ||
return; | ||
} | ||
const type = typeMap[typeName]; | ||
if (isObjectType(type)) { | ||
typeFragments.push(this.makeObjectType(type)); | ||
} else if (isInterfaceType(type)) { | ||
typeFragments.push(this.makeInterfaceType(type)); | ||
} else if (isUnionType(type)) { | ||
typeFragments.push(this.makeUnionType(type)); | ||
} else if (isEnumType(type)) { | ||
typeFragments.push(this.makeEnumType(type)); | ||
} else if (isScalarType(type)) { | ||
typeFragments.push(this.makeScalarType(type)); | ||
} else if (isInputObjectType(type)) { | ||
typeFragments.push(this.makeInputObjectType(type)); | ||
} | ||
}); | ||
return typeFragments.join("\n\n"); | ||
return ""; | ||
} | ||
makeObjectType(type: GraphQLObjectType): string { | ||
const str = [ | ||
`${this.export}${type.name} = objectType("${type.name}", t => {`, | ||
]; | ||
if (type.getInterfaces().length > 0) { | ||
str.push( | ||
` t.implements("${type | ||
.getInterfaces() | ||
.map((i) => i.name) | ||
.join('", "')}")` | ||
); | ||
printObjectType(type: GraphQLObjectType): string { | ||
return this.printBlock([ | ||
`${this.export}${type.name} = objectType({`, | ||
` name: "${type.name}"`, | ||
`})`, | ||
]); | ||
// if (type.getInterfaces().length > 0) { | ||
// const interfaceNames = type | ||
// .getInterfaces() | ||
// .map((i) => JSON.stringify(i.name)) | ||
// .join(", "); | ||
// str.push(` t.implements(${interfaceNames})`); | ||
// } | ||
// Object.keys(type.getFields()).forEach((fieldName) => { | ||
// if (isInterfaceField(type, fieldName)) { | ||
// return; | ||
// } | ||
// eachObj(type.getFields(), (field, key) => { | ||
// getFieldType(field); | ||
// }); | ||
// }); | ||
// return str.join("\n"); | ||
} | ||
printInterfaceTypes() { | ||
if (this.groupedTypes.interface.length) { | ||
return this.groupedTypes.interface | ||
.map((t) => this.printInterfaceType(t)) | ||
.join("\n"); | ||
} | ||
Object.keys(type.getFields()).forEach((fieldName) => { | ||
if (isInterfaceField(type, fieldName)) { | ||
return; | ||
} | ||
eachObj(type.getFields(), (field, key) => { | ||
getFieldType(field); | ||
}); | ||
}); | ||
return str.concat("});").join("\n"); | ||
return ""; | ||
} | ||
makeEnumType(type: GraphQLEnumType): string { | ||
const str = [ | ||
`${this.export}${type.name} = enumType("${type.name}", t => {`, | ||
]; | ||
printInterfaceType(type: GraphQLInterfaceType): string { | ||
return this.printBlock([ | ||
`${this.export}${type.name} = interfaceType({`, | ||
` name: "${type.name}",`, | ||
this.maybeDescription(type), | ||
` definition(t) {`, | ||
` }`, | ||
`});`, | ||
]); | ||
// eachObj(type.getFields(), (field, key) => { | ||
// getFieldType(field); | ||
// }); | ||
// return str.join("\n"); | ||
} | ||
return str.concat("});").join("\n"); | ||
printEnumTypes() { | ||
if (this.groupedTypes.enum.length) { | ||
return this.groupedTypes.enum | ||
.map((t) => this.printEnumType(t)) | ||
.join("\n"); | ||
} | ||
return ""; | ||
} | ||
makeInterfaceType(type: GraphQLInterfaceType): string { | ||
const str = [ | ||
`${this.export}${type.name} = interfaceType("${type.name}", t => {`, | ||
]; | ||
eachObj(type.getFields(), (field, key) => { | ||
getFieldType(field); | ||
}); | ||
return str.concat("});").join("\n"); | ||
printEnumType(type: GraphQLEnumType): string { | ||
return this.printBlock([ | ||
`${this.export}${type.name} = enumType({`, | ||
` name: "${type.name}",`, | ||
this.maybeDescription(type), | ||
` definition(t) {`, | ||
` }`, | ||
`});`, | ||
]); | ||
} | ||
makeInputObjectType(type: GraphQLInputObjectType): string { | ||
const str = [ | ||
`${this.export}${type.name} = inputObjectType("${type.name}", t => {`, | ||
]; | ||
printInputObjectTypes() { | ||
if (this.groupedTypes.input.length) { | ||
return this.groupedTypes.input.map((t) => this.printInputObjectType(t)); | ||
} | ||
return ""; | ||
} | ||
return str.concat("});").join("\n"); | ||
printInputObjectType(type: GraphQLInputObjectType): string { | ||
return this.printBlock([ | ||
`${this.export}${type.name} = inputObjectType({`, | ||
` name: "${type.name}",`, | ||
this.maybeDescription(type), | ||
` definition(t) {`, | ||
` }`, | ||
`});`, | ||
]); | ||
} | ||
makeUnionType(type: GraphQLUnionType): string { | ||
const str = [ | ||
`${this.export}${type.name} = unionType("${type.name}", t => {`, | ||
]; | ||
printUnionTypes() { | ||
if (this.groupedTypes.union.length) { | ||
return this.groupedTypes.union | ||
.map((t) => this.printUnionType(t)) | ||
.join("\n"); | ||
} | ||
return ""; | ||
} | ||
return str.concat("});").join("\n"); | ||
printUnionType(type: GraphQLUnionType): string { | ||
return this.printBlock([ | ||
`${this.export}${type.name} = unionType({`, | ||
` name: "${type.name}",`, | ||
this.maybeDescription(type), | ||
` definition(t) {`, | ||
` }`, | ||
`});`, | ||
]); | ||
} | ||
makeScalarType(type: GraphQLScalarType): string { | ||
const str = [ | ||
`${this.export}${type.name} = scalarType("${type.name}", t => {`, | ||
]; | ||
printScalarTypes() { | ||
if (this.groupedTypes.scalar.length) { | ||
return this.groupedTypes.scalar | ||
.map((t) => this.printScalarType(t)) | ||
.join("\n"); | ||
} | ||
return ""; | ||
} | ||
return str.concat("});").join("\n"); | ||
printScalarType(type: GraphQLScalarType): string { | ||
return this.printBlock([ | ||
`${this.export}${type.name} = scalarType({`, | ||
` name: ${type.name}",`, | ||
this.maybeDescription(type), | ||
` definition(t) {`, | ||
` }`, | ||
`});`, | ||
]); | ||
} | ||
maybeDescription(type: GraphQLNamedType) { | ||
if (type.description) { | ||
return ` description: ${JSON.stringify(type.description)},`; | ||
} | ||
return null; | ||
} | ||
printBlock(block: (string | null)[]) { | ||
return block.filter((t) => t !== null).join("\n"); | ||
} | ||
} | ||
@@ -130,0 +191,0 @@ |
1077
src/typegen.ts
@@ -5,7 +5,10 @@ import { | ||
GraphQLInputField, | ||
GraphQLInputType, | ||
GraphQLInputType as GraphQLType, | ||
GraphQLInterfaceType, | ||
GraphQLNamedType, | ||
GraphQLObjectType, | ||
GraphQLOutputType, | ||
GraphQLScalarType, | ||
GraphQLSchema, | ||
GraphQLUnionType, | ||
isEnumType, | ||
@@ -18,596 +21,586 @@ isInputObjectType, | ||
isScalarType, | ||
isSpecifiedScalarType, | ||
isUnionType, | ||
GraphQLNamedType, | ||
GraphQLUnionType, | ||
GraphQLInputObjectType, | ||
GraphQLEnumType, | ||
} from "graphql"; | ||
import { Metadata } from "./metadata"; | ||
import { arrPush, eachObj, mapObj, hasField } from "./utils"; | ||
import { TypegenInfo } from "./builder"; | ||
import { eachObj, GroupedTypes, groupTypes, mapObj } from "./utils"; | ||
type AllTypes = | ||
| "enums" | ||
| "objects" | ||
| "inputObjects" | ||
| "interfaces" | ||
| "scalars" | ||
| "unions"; | ||
const SpecifiedScalars = { | ||
ID: "string", | ||
String: "string", | ||
Float: "number", | ||
Int: "number", | ||
Boolean: "boolean", | ||
}; | ||
type SpecifiedScalarNames = keyof typeof SpecifiedScalars; | ||
// This is intentionally concise and procedural. Didn't want to make this | ||
// unnecessarily abstracted and it should run only with only a single iteration | ||
// of the schema. The types created here are generally meant for internal use | ||
// by GraphQLNexus anyway. If there is a need, this could be factored out into | ||
// something nicer, but for now let's just make it work well, however ugly it is. | ||
// At least it's type safe™ | ||
export async function buildTypeDefinitions( | ||
schema: GraphQLSchema, | ||
metadata: Metadata | ||
) { | ||
const { | ||
headers, | ||
backingTypeMap, | ||
contextType, | ||
imports, | ||
} = await metadata.getTypegenInfo(schema); | ||
type TypeFieldMapping = Record<string, Record<string, [string, string]>>; | ||
type TypeMapping = Record<string, string>; | ||
type RootTypeMapping = Record< | ||
string, | ||
string | Record<string, [string, string]> | ||
>; | ||
const schemaTypeMap = schema.getTypeMap(); | ||
/** | ||
* We track and output a few main things: | ||
* | ||
* 1. "root" types, or the values that fill the first | ||
* argument for a given object type | ||
* | ||
* 2. "arg" types, the values that are arguments to output fields. | ||
* | ||
* 3. "return" types, the values returned from the resolvers... usually | ||
* just list/nullable variations on the "root" types for other types | ||
* | ||
* 4. The names of all types, grouped by type. | ||
* | ||
* - Non-scalar types will get a dedicated "Root" type associated with it | ||
*/ | ||
export class Typegen { | ||
groupedTypes: GroupedTypes; | ||
// Keeping track of all of the types we have for each | ||
// type in the schema. | ||
const typeNames: Record<AllTypes, string[]> = { | ||
enums: [], | ||
objects: [], | ||
inputObjects: [], | ||
interfaces: [], | ||
scalars: [], | ||
unions: [], | ||
}; | ||
const allTypeStrings: string[] = []; | ||
constructor( | ||
protected schema: GraphQLSchema, | ||
protected typegenInfo: TypegenInfo | ||
) { | ||
this.groupedTypes = groupTypes(schema); | ||
} | ||
const interfaceRootTypes: { | ||
[interfaceName: string]: GraphQLObjectType[]; // objectRootType | ||
} = {}; | ||
const returnTypeFields: { | ||
[typeName: string]: [string, string][]; // fieldName, returnTypeName | ||
} = {}; | ||
const argTypeFields: { | ||
[typeName: string]: [string, string][]; // fieldName, argTypeName | ||
} = {}; | ||
print() { | ||
return [ | ||
this.printHeaders(), | ||
this.printInputTypeMap(), | ||
this.printEnumTypeMap(), | ||
this.printRootTypeMap(), | ||
this.printAllTypesMap(), | ||
this.printReturnTypeMap(), | ||
this.printArgTypeMap(), | ||
this.printAbstractResolveReturnTypeMap(), | ||
this.printInheritedFieldMap(), | ||
this.printTypeNames("object", "NexusGenObjectNames"), | ||
this.printTypeNames("input", "NexusGenInputNames"), | ||
this.printTypeNames("enum", "NexusGenEnumNames"), | ||
this.printTypeNames("interface", "NexusGenInterfaceNames"), | ||
this.printTypeNames("scalar", "NexusGenScalarNames"), | ||
this.printTypeNames("union", "NexusGenUnionNames"), | ||
this.printGenTypeMap(), | ||
this.printFooters(), | ||
].join("\n\n"); | ||
} | ||
// If for some reason the user has types that conflict with these type names rename them. | ||
const MP = metadata.safeTypeName(schema, "MaybePromise"); | ||
const MPL = metadata.safeTypeName(schema, "MaybePromiseList"); | ||
const MT = metadata.safeTypeName(schema, "MaybeThunk"); | ||
const MTA = metadata.safeTypeName(schema, "MaybeThunkArgs"); | ||
printHeaders() { | ||
return [ | ||
this.typegenInfo.headers.join("\n"), | ||
this.typegenInfo.imports.join("\n"), | ||
this.printCustomScalarMethods(), | ||
GLOBAL_DECLARATION, | ||
].join("\n"); | ||
} | ||
const maybePromiseList = (t: string) => `${MPL}<${t}>`; | ||
const maybePromise = (t: string) => `${MP}<${t}>`; | ||
const maybeThunk = (t: string) => `${MT}<${t}>`; | ||
const maybeThunkWithArgs = (t: string, a: string) => `${MTA}<${t}, ${a}>`; | ||
printFooters() { | ||
return `export type Gen = NexusGenTypes;`; | ||
} | ||
type SuffixedArgs = | ||
| [string, string, string] // typeName, fieldName, suffix | ||
| [string, string]; // typeName, suffix | ||
printGenTypeMap() { | ||
return [`export interface NexusGenTypes {`] | ||
.concat([ | ||
` context: ${this.printContext()};`, | ||
` inputTypes: NexusGenInputs;`, | ||
` rootTypes: NexusGenRootTypes;`, | ||
` argTypes: NexusGenArgTypes;`, | ||
` fieldTypes: NexusGenFieldTypes;`, | ||
` allTypes: NexusGenAllTypes;`, | ||
` inheritedFields: NexusGenInheritedFields;`, | ||
` 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'];`, | ||
` abstractResolveReturn: NexusGenAbstractResolveReturnTypes;`, | ||
]) | ||
.concat("}") | ||
.join("\n"); | ||
} | ||
const suffixed = (...args: SuffixedArgs) => { | ||
let nameStr = ""; | ||
if (args.length === 3) { | ||
const [typeName, fieldName, suffix] = args; | ||
const pascalField = pascalCase(fieldName); | ||
if (metadata.hasField(schema, typeName, pascalField)) { | ||
nameStr = `${typeName}${fieldName}${suffix}`; | ||
} else { | ||
nameStr = `${typeName}${pascalField}${suffix}`; | ||
} | ||
} else { | ||
nameStr = `${args[0]}${args[1]}`; | ||
printCustomScalarMethods() { | ||
const customScalars = this.buildCustomScalarMap(); | ||
if (!Object.keys(customScalars).length) { | ||
return []; | ||
} | ||
return metadata.safeTypeName(schema, nameStr); | ||
}; | ||
return [ | ||
`import { core } from "nexus"`, | ||
`declare global {`, | ||
` interface NexusGenCustomScalarMethods<TypeName extends string> {`, | ||
] | ||
.concat( | ||
mapObj(customScalars, (val, key) => { | ||
return ` ${val}<FieldName extends string>(fieldName: FieldName, ...opts: core.ScalarOutSpread<TypeName, FieldName>): void // ${JSON.stringify( | ||
key | ||
)};`; | ||
}) | ||
) | ||
.concat([` }`, `}`]) | ||
.join("\n"); | ||
} | ||
const argFieldName = (typeName: string, fieldName: string) => | ||
suffixed(typeName, fieldName, "Args"); | ||
const fieldReturnTypeName = (typeName: string, fieldName: string) => | ||
suffixed(typeName, fieldName, "ReturnType"); | ||
const typeReturnTypeName = ( | ||
type: GraphQLObjectType | GraphQLInterfaceType | GraphQLUnionType | ||
) => { | ||
if (isUnionType(type)) { | ||
return suffixed(type.name, "ReturnType"); | ||
} | ||
if (!hasField(type, "ReturnType")) { | ||
return suffixed(type.name, "_ReturnType"); | ||
} | ||
return suffixed(type.name, "ReturnType"); | ||
}; | ||
const typeRootTypeName = (typeName: string) => { | ||
if (isEntryType(typeName)) { | ||
return "{}"; | ||
} | ||
return suffixed(typeName, "RootType"); | ||
}; | ||
const fieldResolverName = (typeName: string, fieldName: string) => | ||
suffixed(typeName, fieldName, "Resolver"); | ||
buildCustomScalarMap() { | ||
const customScalars: Record<string, string> = {}; | ||
this.groupedTypes.scalar.forEach((type) => { | ||
if (type.asNexusMethod) { | ||
customScalars[type.name] = type.asNexusMethod; | ||
} | ||
}); | ||
return customScalars; | ||
} | ||
// Takes a type and turns it into a "return type", based | ||
// on nullability and whether it's a list. | ||
const getReturnType = (fieldType: GraphQLOutputType): string => { | ||
let { type, typeStr } = unwrapNull(fieldType); | ||
if (isListType(type)) { | ||
return `${typeStr}${maybePromiseList(getReturnType(type.ofType))}`; | ||
} | ||
if (isObjectType(type) || isInterfaceType(type) || isUnionType(type)) { | ||
typeStr += typeReturnTypeName(type); | ||
} else if (isEnumType(type)) { | ||
typeStr += type.name; | ||
} else if (isScalarType(type)) { | ||
typeStr += backingTypeMap[type.name] || "unknown"; | ||
} | ||
return typeStr; | ||
}; | ||
printInheritedFieldMap() { | ||
return "export interface NexusGenInheritedFields {}"; | ||
} | ||
const printInputType = (fieldType: GraphQLInputType): string => { | ||
let { type, typeStr } = unwrapNull(fieldType); | ||
if (isListType(type)) { | ||
const inputTypeStr = printInputType(type.ofType); | ||
return inputTypeStr.indexOf("null ") !== -1 | ||
? `${typeStr}Array<${inputTypeStr}>` | ||
: `${typeStr}${inputTypeStr}[]`; | ||
} | ||
if (isInputObjectType(type) || isEnumType(type)) { | ||
return `${typeStr}${type.name}`; | ||
} | ||
if (isScalarType(type)) { | ||
return `${typeStr}${backingTypeMap[type.name] || "unknown"}`; | ||
} | ||
throw new Error(`Unexpected type ${type}`); | ||
}; | ||
printContext() { | ||
return this.typegenInfo.contextType || "{}"; | ||
} | ||
const printArgOrFieldMember = ({ | ||
name, | ||
type, | ||
}: GraphQLArgument | GraphQLInputField): string => { | ||
if (isNonNullType(type)) { | ||
return ` ${name}: ${printInputType(type)};`; | ||
} | ||
return ` ${name}?: ${printInputType(type)};`; | ||
}; | ||
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; | ||
} | ||
const makeFieldArgs = ( | ||
argTypeName: string, | ||
field: GraphQLField<any, any> | ||
) => { | ||
allTypeStrings.push( | ||
[ | ||
`export interface ${argTypeName} {`, | ||
map(field.args, (arg) => printArgOrFieldMember(arg)), | ||
"}", | ||
].join("\n") | ||
printAbstractResolveReturnTypeMap() { | ||
return this.printTypeInterface( | ||
"NexusGenAbstractResolveReturnTypes", | ||
this.buildResolveReturnTypesMap() | ||
); | ||
}; | ||
} | ||
const processField = ( | ||
type: GraphQLObjectType | GraphQLInterfaceType, | ||
field: GraphQLField<any, any> | ||
) => { | ||
const returnTypeName = fieldReturnTypeName(type.name, field.name); | ||
arrPush(returnTypeFields, type.name, [field.name, returnTypeName]); | ||
allTypeStrings.push( | ||
`export type ${returnTypeName} = ${getReturnType(field.type)};` | ||
buildResolveReturnTypesMap() { | ||
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) => JSON.stringify(val)) | ||
.join(" | "); | ||
} else { | ||
console.warn( | ||
`Nexus Warning: Interface ${ | ||
type.name | ||
} is not implemented by any object types` | ||
); | ||
} | ||
} else { | ||
sourceMap[type.name] = type | ||
.getTypes() | ||
.map((t) => JSON.stringify(t.name)) | ||
.join(" | "); | ||
} | ||
}); | ||
return sourceMap; | ||
} | ||
printTypeNames(name: keyof GroupedTypes, exportName: string) { | ||
const obj = this.groupedTypes[name] as GraphQLNamedType[]; | ||
const typeDef = | ||
obj.length === 0 | ||
? "never" | ||
: obj | ||
.map((o) => JSON.stringify(o.name)) | ||
.sort() | ||
.join(" | "); | ||
return `export type ${exportName} = ${typeDef};`; | ||
} | ||
buildEnumTypeMap() { | ||
const enumMap: TypeMapping = {}; | ||
this.groupedTypes.enum.forEach((e) => { | ||
const values = e.getValues().map((val) => JSON.stringify(val.value)); | ||
enumMap[e.name] = values.join(" | "); | ||
}); | ||
return enumMap; | ||
} | ||
buildInputTypeMap() { | ||
const inputObjMap: TypeFieldMapping = {}; | ||
this.groupedTypes.input.forEach((input) => { | ||
eachObj(input.getFields(), (field) => { | ||
inputObjMap[input.name] = inputObjMap[input.name] || {}; | ||
inputObjMap[input.name][field.name] = this.normalizeArg(field); | ||
}); | ||
}); | ||
return inputObjMap; | ||
} | ||
printInputTypeMap() { | ||
return this.printTypeFieldInterface( | ||
"NexusGenInputs", | ||
this.buildInputTypeMap(), | ||
"input type" | ||
); | ||
if (field.args.length) { | ||
const argTypeName = argFieldName(type.name, field.name); | ||
arrPush(argTypeFields, type.name, [field.name, argTypeName]); | ||
if (isObjectType(type)) { | ||
const interfaces = type | ||
.getInterfaces() | ||
.filter((i) => i.getFields()[field.name]) | ||
.map((i) => argFieldName(i.name, field.name)); | ||
if (interfaces.length) { | ||
allTypeStrings.push( | ||
`export interface ${argTypeName} extends ${interfaces.join( | ||
", " | ||
)} {}` | ||
); | ||
} | ||
printEnumTypeMap() { | ||
return this.printTypeInterface("NexusGenEnums", this.buildEnumTypeMap()); | ||
} | ||
buildRootTypeMap() { | ||
const rootTypeMap: RootTypeMapping = {}; | ||
const hasFields: ( | ||
| GraphQLInterfaceType | ||
| GraphQLObjectType | ||
| GraphQLScalarType | ||
| GraphQLUnionType)[] = []; | ||
hasFields | ||
.concat(this.groupedTypes.object) | ||
.concat(this.groupedTypes.interface) | ||
.concat(this.groupedTypes.scalar) | ||
.concat(this.groupedTypes.union) | ||
.forEach((type) => { | ||
const backingType = this.typegenInfo.backingTypeMap[type.name]; | ||
if (typeof backingType === "string") { | ||
rootTypeMap[type.name] = backingType; | ||
} else if (isScalarType(type)) { | ||
if (isSpecifiedScalarType(type)) { | ||
rootTypeMap[type.name] = | ||
SpecifiedScalars[type.name as SpecifiedScalarNames]; | ||
} else { | ||
rootTypeMap[type.name] = "any"; | ||
} | ||
} else if (isUnionType(type)) { | ||
rootTypeMap[type.name] = type | ||
.getTypes() | ||
.map((t) => `NexusGenRootTypes['${t.name}']`) | ||
.join(" | "); | ||
} else if (isInterfaceType(type)) { | ||
const possibleRoots = this.schema | ||
.getPossibleTypes(type) | ||
.map((t) => `NexusGenRootTypes['${t.name}']`); | ||
if (possibleRoots.length > 0) { | ||
rootTypeMap[type.name] = possibleRoots.join(" | "); | ||
} else { | ||
rootTypeMap[type.name] = "any"; | ||
} | ||
} else { | ||
makeFieldArgs(argTypeName, field); | ||
eachObj(type.getFields(), (field) => { | ||
const obj = (rootTypeMap[type.name] = rootTypeMap[type.name] || {}); | ||
if (!this.hasResolver(field, type)) { | ||
if (typeof obj !== "string") { | ||
obj[field.name] = [ | ||
this.argSeparator(field.type as GraphQLType), | ||
this.printOutputType(field.type), | ||
]; | ||
} | ||
} | ||
}); | ||
} | ||
} else { | ||
makeFieldArgs(argTypeName, field); | ||
} | ||
} | ||
}; | ||
}); | ||
return rootTypeMap; | ||
} | ||
const fieldRootType = (fieldType: GraphQLOutputType): string => { | ||
let { type, typeStr } = unwrapNull(fieldType); | ||
if (isListType(type)) { | ||
const toWrap = fieldRootType(type.ofType); | ||
return toWrap.indexOf("null | ") === 0 | ||
? `${typeStr}Array<${toWrap}>` | ||
: `${typeStr}${toWrap}[]`; | ||
} | ||
if (isScalarType(type)) { | ||
return `${typeStr}${backingTypeMap[type.name] || "any"}`; | ||
} | ||
if (isObjectType(type)) { | ||
// return field. | ||
} | ||
if (isEnumType(type)) { | ||
return `${typeStr}${type.name}`; | ||
} | ||
return `${typeStr}any`; | ||
}; | ||
buildAllTypesMap() { | ||
const typeMap: TypeMapping = {}; | ||
const toCheck: (GraphQLInputObjectType | GraphQLEnumType)[] = []; | ||
toCheck | ||
.concat(this.groupedTypes.input) | ||
.concat(this.groupedTypes.enum) | ||
.forEach((type) => { | ||
if (isInputObjectType(type)) { | ||
typeMap[type.name] = `NexusGenInputs['${type.name}']`; | ||
} else if (isEnumType(type)) { | ||
typeMap[type.name] = `NexusGenEnums['${type.name}']`; | ||
} | ||
}); | ||
return typeMap; | ||
} | ||
const fieldBackingName = ( | ||
type: GraphQLObjectType, | ||
field: GraphQLField<any, any> | ||
) => { | ||
const colon = metadata.hasDefaultValue(type, field.name) | ||
? "?:" | ||
: isNonNullType(field.type) | ||
? ":" | ||
: "?:"; | ||
return `${field.name}${colon}`; | ||
}; | ||
hasResolver( | ||
field: GraphQLField<any, any>, | ||
_type: GraphQLObjectType | GraphQLInterfaceType // Used in tests | ||
) { | ||
return Boolean(field.resolve); | ||
} | ||
const makeRootType = (type: GraphQLObjectType) => { | ||
if (isEntryType(type.name)) { | ||
return; | ||
} | ||
if (backingTypeMap[type.name]) { | ||
allTypeStrings.push( | ||
`export type ${typeRootTypeName(type.name)} = ${ | ||
backingTypeMap[type.name] | ||
};` | ||
); | ||
} else { | ||
const rootMembers = mapObj(type.getFields(), (f) => { | ||
if (metadata.hasResolver(type.name, f.name)) { | ||
return null; | ||
printRootTypeMap() { | ||
return this.printRootTypeFieldInterface( | ||
"NexusGenRootTypes", | ||
this.buildRootTypeMap() | ||
); | ||
} | ||
printAllTypesMap() { | ||
const typeMapping = this.buildAllTypesMap(); | ||
return [`export interface NexusGenAllTypes extends NexusGenRootTypes {`] | ||
.concat( | ||
mapObj(typeMapping, (val, key) => { | ||
return ` ${key}: ${val};`; | ||
}) | ||
) | ||
.concat("}") | ||
.join("\n"); | ||
} | ||
buildArgTypeMap() { | ||
const argTypeMap: Record<string, TypeFieldMapping> = {}; | ||
const hasFields: (GraphQLInterfaceType | GraphQLObjectType)[] = []; | ||
hasFields | ||
.concat(this.groupedTypes.object) | ||
.concat(this.groupedTypes.interface) | ||
.forEach((type) => { | ||
eachObj(type.getFields(), (field) => { | ||
if (field.args.length > 0) { | ||
argTypeMap[type.name] = argTypeMap[type.name] || {}; | ||
argTypeMap[type.name][field.name] = field.args.reduce( | ||
(obj: Record<string, string[]>, arg) => { | ||
obj[arg.name] = this.normalizeArg(arg); | ||
return obj; | ||
}, | ||
{} | ||
); | ||
} | ||
}); | ||
}); | ||
return argTypeMap; | ||
} | ||
printArgTypeMap() { | ||
return this.printArgTypeFieldInterface(this.buildArgTypeMap()); | ||
} | ||
buildReturnTypeMap() { | ||
const returnTypeMap: TypeFieldMapping = {}; | ||
const hasFields: (GraphQLInterfaceType | GraphQLObjectType)[] = []; | ||
hasFields | ||
.concat(this.groupedTypes.object) | ||
.concat(this.groupedTypes.interface) | ||
.forEach((type) => { | ||
eachObj(type.getFields(), (field) => { | ||
returnTypeMap[type.name] = returnTypeMap[type.name] || {}; | ||
returnTypeMap[type.name][field.name] = [ | ||
":", | ||
this.printOutputType(field.type), | ||
]; | ||
}); | ||
}); | ||
return returnTypeMap; | ||
} | ||
printOutputType(type: GraphQLOutputType) { | ||
const returnType = this.typeToArr(type); | ||
function combine(item: any[]): string { | ||
if (item.length === 1) { | ||
if (Array.isArray(item[0])) { | ||
const toPrint = combine(item[0]); | ||
return toPrint.indexOf("null") === -1 | ||
? `${toPrint}[]` | ||
: `Array<${toPrint}>`; | ||
} | ||
return ` ${fieldBackingName(type, f)} ${fieldRootType(f.type)};`; | ||
}).filter((f) => f); | ||
if (rootMembers.length === 0) { | ||
allTypeStrings.push(`export type ${typeRootTypeName(type.name)} = {};`); | ||
} else { | ||
allTypeStrings.push( | ||
[ | ||
`export interface ${typeRootTypeName(type.name)} {`, | ||
rootMembers.join("\n"), | ||
`}`, | ||
].join("\n") | ||
); | ||
return item[0]; | ||
} | ||
if (Array.isArray(item[1])) { | ||
const toPrint = combine(item[1]); | ||
return toPrint.indexOf("null") === -1 | ||
? `${toPrint}[] | null` | ||
: `Array<${toPrint}> | null`; | ||
} | ||
return `${item[1]} | null`; | ||
} | ||
}; | ||
return `${combine(returnType)}; // ${type}`; | ||
} | ||
// If we have a resolver, by default we assume we don't need to | ||
// return something (e.g. Query type) - specify the root type if this | ||
// is not the case. | ||
const makeReturnType = (type: GraphQLObjectType) => { | ||
if (backingTypeMap[type.name]) { | ||
allTypeStrings.push( | ||
`export type ${typeReturnTypeName(type)} = ${backingTypeMap[type.name]}` | ||
); | ||
typeToArr(type: GraphQLOutputType): any[] { | ||
const typing = []; | ||
if (isNonNullType(type)) { | ||
type = type.ofType; | ||
} else { | ||
const returnMembers = mapObj(type.getFields(), (f) => { | ||
const hasArgs = f.args.length > 0; | ||
if (metadata.hasResolver(type.name, f.name)) { | ||
return null; | ||
} | ||
const rootType = fieldRootType(f.type); | ||
return ` ${fieldBackingName(type, f)} ${ | ||
hasArgs | ||
? maybeThunkWithArgs( | ||
maybePromise(rootType), | ||
argFieldName(type.name, f.name) | ||
) | ||
: maybeThunk(maybePromise(rootType)) | ||
};`; | ||
}).filter((f) => f); | ||
if (returnMembers.length === 0) { | ||
allTypeStrings.push(`export type ${typeReturnTypeName(type)} = {};`); | ||
} else { | ||
allTypeStrings.push( | ||
[ | ||
`export type ${typeReturnTypeName(type)} = {`, | ||
returnMembers.join("\n"), | ||
`}`, | ||
].join("\n") | ||
); | ||
} | ||
typing.push(null); | ||
} | ||
}; | ||
const makeResolvers = (type: GraphQLObjectType) => { | ||
// TODO | ||
}; | ||
Object.keys(schemaTypeMap).forEach((typeName) => { | ||
if (typeName.indexOf("__") === 0) { | ||
return; | ||
} | ||
// All types will be "unused" until we say otherwise, | ||
// if we need to strip them. | ||
const type = schema.getType(typeName); | ||
// An object type has a "backing type", and fields | ||
// which may have an "arg type" and have a "return type" | ||
if (isObjectType(type)) { | ||
typeNames.objects.push(type.name); | ||
eachObj(type.getFields(), (field) => processField(type, field)); | ||
type | ||
.getInterfaces() | ||
.forEach((i) => arrPush(interfaceRootTypes, i.name, type)); | ||
makeRootType(type); | ||
makeReturnType(type); | ||
makeResolvers(type); | ||
} else if (isInputObjectType(type)) { | ||
typeNames.inputObjects.push(type.name); | ||
allTypeStrings.push( | ||
[ | ||
`export interface ${type.name} {`, | ||
mapObj(type.getFields(), (inputField) => | ||
printArgOrFieldMember(inputField) | ||
).join("\n"), | ||
`}`, | ||
].join("\n") | ||
); | ||
if (isListType(type)) { | ||
typing.push(this.typeToArr(type.ofType)); | ||
} else if (isScalarType(type)) { | ||
typeNames.scalars.push(type.name); | ||
} else if (isUnionType(type)) { | ||
typeNames.unions.push(type.name); | ||
allTypeStrings.push( | ||
`export type ${typeRootTypeName(type.name)} = ${map( | ||
type.getTypes(), | ||
({ name }) => typeRootTypeName(name), | ||
" | " | ||
)};` | ||
); | ||
allTypeStrings.push( | ||
`export type ${typeReturnTypeName(type)} = ${map( | ||
type.getTypes(), | ||
(t) => typeReturnTypeName(t), | ||
" | " | ||
)};` | ||
); | ||
} else if (isInterfaceType(type)) { | ||
typeNames.interfaces.push(type.name); | ||
eachObj(type.getFields(), (field) => processField(type, field)); | ||
typing.push(this.printScalar(type)); | ||
} else if (isEnumType(type)) { | ||
typeNames.enums.push(type.name); | ||
allTypeStrings.push( | ||
`export type ${type.name} = ${map( | ||
type.getValues(), | ||
({ value }) => JSON.stringify(value), | ||
" | " | ||
)};` | ||
); | ||
typing.push(`NexusGenEnums['${type.name}']`); | ||
} else if (isObjectType(type) || isInterfaceType(type)) { | ||
typing.push(`NexusGenRootTypes['${type.name}']`); | ||
} | ||
}); | ||
return typing; | ||
} | ||
eachObj(interfaceRootTypes, (members, interfaceName) => { | ||
const i = schema.getType(interfaceName); | ||
if (!isInterfaceType(i)) { | ||
return; | ||
} | ||
if (backingTypeMap[interfaceName]) { | ||
allTypeStrings.push( | ||
`export type ${typeRootTypeName(interfaceName)} = ${ | ||
backingTypeMap[interfaceName] | ||
};` | ||
); | ||
allTypeStrings.push( | ||
`export type ${typeReturnTypeName(i)} = ${ | ||
backingTypeMap[interfaceName] | ||
};` | ||
); | ||
} else { | ||
allTypeStrings.push( | ||
`export type ${typeRootTypeName(interfaceName)} = ${members | ||
.map(({ name }) => typeRootTypeName(name)) | ||
.join(" | ")};` | ||
); | ||
allTypeStrings.push( | ||
`export type ${typeReturnTypeName(i)} = ${members | ||
.map((name) => typeReturnTypeName(name)) | ||
.join(" | ")};` | ||
); | ||
} | ||
}); | ||
printReturnTypeMap() { | ||
return this.printTypeFieldInterface( | ||
"NexusGenFieldTypes", | ||
this.buildReturnTypeMap(), | ||
"field return type" | ||
); | ||
} | ||
// We're always guarenteed to have at least one of these | ||
const objectNames = () => { | ||
return [ | ||
`{`, | ||
map(typeNames.objects, (n) => ` ${n}: ${typeRootTypeName(n)};`), | ||
" }", | ||
].join("\n"); | ||
}; | ||
normalizeArg(arg: GraphQLInputField | GraphQLArgument): [string, string] { | ||
return [this.argSeparator(arg.type), this.argTypeRepresentation(arg.type)]; | ||
} | ||
// Each interface will always have at least one member, so the interface types | ||
// will just be a mapping to their members. | ||
const interfacesWithMembers = () => { | ||
if (typeNames.interfaces.length === 0) { | ||
return "{}"; | ||
argSeparator(type: GraphQLType) { | ||
if (isNonNullType(type)) { | ||
return ":"; | ||
} | ||
return [ | ||
`{`, | ||
map( | ||
typeNames.interfaces, | ||
(n) => | ||
` ${n}: ${ | ||
interfaceRootTypes[n] | ||
? interfaceRootTypes[n].map(stringify).join(" | ") | ||
: "never" | ||
};` | ||
), | ||
" }", | ||
].join("\n"); | ||
}; | ||
return "?:"; | ||
} | ||
const enums = () => { | ||
if (typeNames.enums.length === 0) { | ||
return "{}"; | ||
argTypeRepresentation(arg: GraphQLType): string { | ||
const argType = this.argTypeArr(arg); | ||
function combine(item: any[]): string { | ||
if (item.length === 1) { | ||
if (Array.isArray(item[0])) { | ||
const toPrint = combine(item[0]); | ||
return toPrint.indexOf("null") === -1 | ||
? `${toPrint}[]` | ||
: `Array<${toPrint}>`; | ||
} | ||
return item[0]; | ||
} | ||
if (Array.isArray(item[1])) { | ||
const toPrint = combine(item[1]); | ||
return toPrint.indexOf("null") === -1 | ||
? `${toPrint}[] | null` | ||
: `Array<${toPrint}> | null`; | ||
} | ||
return `${item[1]} | null`; | ||
} | ||
return [`{`, map(typeNames.enums, (n) => ` ${n}: ${n};`), " }"].join( | ||
"\n" | ||
); | ||
}; | ||
return `${combine(argType)}; // ${arg}`; | ||
} | ||
const unions = () => { | ||
if (typeNames.unions.length === 0) { | ||
return "{}"; | ||
argTypeArr(arg: GraphQLType): any[] { | ||
const typing = []; | ||
if (isNonNullType(arg)) { | ||
arg = arg.ofType; | ||
} else { | ||
typing.push(null); | ||
} | ||
return [`{`, map(typeNames.unions, (n) => ` ${n}: any;`), " }"].join( | ||
"\n" | ||
); | ||
}; | ||
const scalars = () => { | ||
return [`{`, map(typeNames.scalars, (n) => ` ${n}: any;`), " }"].join( | ||
"\n" | ||
); | ||
}; | ||
const inputObjects = () => { | ||
if (typeNames.inputObjects.length === 0) { | ||
return "{}"; | ||
if (isListType(arg)) { | ||
typing.push(this.argTypeArr(arg.ofType)); | ||
} else if (isScalarType(arg)) { | ||
typing.push(this.printScalar(arg)); | ||
} else if (isEnumType(arg)) { | ||
typing.push(`NexusGenEnums['${arg.name}']`); | ||
} else if (isInputObjectType(arg)) { | ||
typing.push(`NexusGenInputs['${arg.name}']`); | ||
} | ||
return [ | ||
`{`, | ||
map(typeNames.inputObjects, (n) => ` ${n}: ${n};`), | ||
" }", | ||
].join("\n"); | ||
}; | ||
return typing; | ||
} | ||
return `${headers.join("\n")} | ||
${imports.join("\n")} | ||
printTypeInterface(interfaceName: string, typeMapping: TypeMapping) { | ||
return [`export interface ${interfaceName} {`] | ||
.concat(mapObj(typeMapping, (val, key) => ` ${key}: ${val}`)) | ||
.concat("}") | ||
.join("\n"); | ||
} | ||
declare global { | ||
interface GraphQLNexusGen extends GraphQLNexusGenTypes {} | ||
} | ||
printRootTypeFieldInterface( | ||
interfaceName: string, | ||
typeMapping: RootTypeMapping | ||
) { | ||
return [`export interface ${interfaceName} {`] | ||
.concat( | ||
mapObj(typeMapping, (val, key) => { | ||
if (typeof val === "string") { | ||
return ` ${key}: ${val};`; | ||
} | ||
if (Object.keys(val).length === 0) { | ||
return ` ${key}: {};`; | ||
} | ||
return this.printObj(" ", "root type")(val, key); | ||
}) | ||
) | ||
.concat("}") | ||
.join("\n"); | ||
} | ||
// Maybe Promise | ||
export type ${MP}<T> = T | PromiseLike<T>; | ||
printTypeFieldInterface( | ||
interfaceName: string, | ||
typeMapping: TypeFieldMapping, | ||
source: string | ||
) { | ||
return [`export interface ${interfaceName} {`] | ||
.concat(mapObj(typeMapping, this.printObj(" ", source))) | ||
.concat("}") | ||
.join("\n"); | ||
} | ||
// Maybe Promise List | ||
export type ${MPL}<T> = Array<${MP}<T>>; | ||
printArgTypeFieldInterface(typeMapping: Record<string, TypeFieldMapping>) { | ||
return [`export interface NexusGenArgTypes {`] | ||
.concat( | ||
mapObj(typeMapping, (val, key) => { | ||
return [` ${key}: {`] | ||
.concat(mapObj(val, this.printObj(" ", "args"))) | ||
.concat(" }") | ||
.join("\n"); | ||
}) | ||
) | ||
.concat("}") | ||
.join("\n"); | ||
} | ||
// Maybe Thunk | ||
export type ${MT}<T> = T | (() => T); | ||
// Maybe Thunk, with args | ||
export type ${MTA}<T, A> = T | ((args?: A) => T); | ||
${allTypeStrings.join("\n\n")} | ||
${stringifyTypeFieldMapping("GraphQLNexusGenArgTypes", argTypeFields)} | ||
export interface GraphQLNexusGenRootTypes { | ||
${map( | ||
typeNames.interfaces.concat(typeNames.objects), | ||
(name) => ` ${name}: ${typeRootTypeName(name)};` | ||
)} | ||
} | ||
${stringifyTypeFieldMapping("GraphQLNexusGenReturnTypes", returnTypeFields)} | ||
export interface GraphQLNexusGenTypes { | ||
argTypes: GraphQLNexusGenArgTypes; | ||
backingTypes: GraphQLNexusGenRootTypes; | ||
returnTypes: GraphQLNexusGenReturnTypes; | ||
context: ${contextType}; | ||
enums: ${enums()}; | ||
objects: ${objectNames()}; | ||
interfaces: ${interfacesWithMembers()}; | ||
unions: ${unions()}; | ||
scalars: ${scalars()}; | ||
inputObjects: ${inputObjects()}; | ||
allInputTypes: | ||
| Extract<keyof GraphQLNexusGenTypes['inputObjects'], string> | ||
| Extract<keyof GraphQLNexusGenTypes['enums'], string> | ||
| Extract<keyof GraphQLNexusGenTypes['scalars'], string>; | ||
allOutputTypes: | ||
| Extract<keyof GraphQLNexusGenTypes['objects'], string> | ||
| Extract<keyof GraphQLNexusGenTypes['enums'], string> | ||
| Extract<keyof GraphQLNexusGenTypes['unions'], string> | ||
| Extract<keyof GraphQLNexusGenTypes['interfaces'], string> | ||
| Extract<keyof GraphQLNexusGenTypes['scalars'], string>; | ||
} | ||
export type Gen = GraphQLNexusGenTypes; | ||
`; | ||
} | ||
function isEntryType(typeName: string) { | ||
return ( | ||
typeName === "Query" || | ||
typeName === "Mutation" || | ||
typeName === "Subscription" | ||
); | ||
} | ||
const stringify = (v: any) => JSON.stringify(v); | ||
function stringifyTypeFieldMapping( | ||
tsInterfaceName: string, | ||
obj: Record<string, [string, string][]> | ||
) { | ||
const argTypeLines = Object.keys(obj).reduce((result: string[], typeName) => { | ||
return result | ||
.concat(` ${typeName}: {`) | ||
printObj = (space: string, source: string) => ( | ||
val: Record<string, [string, string]>, | ||
key: string | ||
) => { | ||
return [`${space}${key}: { // ${source}`] | ||
.concat( | ||
obj[typeName].reduce((fields: string[], [fieldName, mappingName]) => { | ||
return fields.concat(` ${fieldName}: ${mappingName};`); | ||
}, []) | ||
mapObj(val, (v2, k2) => { | ||
return `${space} ${k2}${v2[0]} ${v2[1]}`; | ||
}) | ||
) | ||
.concat(" };"); | ||
}, []); | ||
.concat(`${space}}`) | ||
.join("\n"); | ||
}; | ||
const argTypes = [`export interface ${tsInterfaceName} {`] | ||
.concat(argTypeLines) | ||
.concat("}") | ||
.join("\n"); | ||
return argTypes; | ||
} | ||
function map<T>( | ||
nodes: Set<T> | Array<T>, | ||
iterator: (item: T, index: number) => string, | ||
join = "\n" | ||
) { | ||
return Array.from(nodes) | ||
.map(iterator) | ||
.join(join); | ||
} | ||
function ucFirst(str: string) { | ||
return str | ||
.slice(0, 1) | ||
.toUpperCase() | ||
.concat(str.slice(1)); | ||
} | ||
function camelize(str: string) { | ||
return str.replace(/^([A-Z])|[\s-_]+(\w)/g, function(match, p1, p2, offset) { | ||
if (p2) { | ||
return p2.toUpperCase(); | ||
printScalar(type: GraphQLScalarType) { | ||
if (isSpecifiedScalarType(type)) { | ||
return SpecifiedScalars[type.name as SpecifiedScalarNames]; | ||
} | ||
return p1.toLowerCase(); | ||
}); | ||
const backingType = this.typegenInfo.backingTypeMap[type.name]; | ||
if (typeof backingType === "string") { | ||
return backingType; | ||
} else { | ||
return "any"; | ||
} | ||
} | ||
} | ||
function pascalCase(str: string) { | ||
return ucFirst(camelize(str)); | ||
} | ||
function unwrapNull(fieldType: GraphQLOutputType | GraphQLInputType) { | ||
let type = fieldType; | ||
let typeStr = ""; | ||
if (isNonNullType(fieldType)) { | ||
type = fieldType.ofType; | ||
} else { | ||
typeStr += "null | "; | ||
} | ||
return { type, typeStr }; | ||
} | ||
const GLOBAL_DECLARATION = ` | ||
declare global { | ||
interface NexusGen extends NexusGenTypes {} | ||
}`; |
160
src/utils.ts
@@ -1,7 +0,22 @@ | ||
import { GraphQLObjectType, GraphQLInterfaceType } from "graphql"; | ||
import { | ||
GraphQLObjectType, | ||
GraphQLInterfaceType, | ||
GraphQLSchema, | ||
GraphQLInputObjectType, | ||
GraphQLUnionType, | ||
GraphQLEnumType, | ||
GraphQLScalarType, | ||
isObjectType, | ||
isInputObjectType, | ||
isScalarType, | ||
isSpecifiedScalarType, | ||
isUnionType, | ||
isInterfaceType, | ||
isEnumType, | ||
specifiedScalarTypes, | ||
} from "graphql"; | ||
import path from "path"; | ||
import * as Types from "./types"; | ||
export function log(msg: string) { | ||
console.log(`GraphQL Nexus: ${msg}`); | ||
console.log(`Nexus GraphQL: ${msg}`); | ||
} | ||
@@ -13,16 +28,2 @@ | ||
export const enumShorthandMembers = ( | ||
arg: string[] | Record<string, string | number | object | boolean> | ||
): Types.EnumMemberInfo[] => { | ||
if (Array.isArray(arg)) { | ||
return arg.map((name) => ({ name, value: name })); | ||
} | ||
return Object.keys(arg).map((name) => { | ||
return { | ||
name, | ||
value: arg[name], | ||
}; | ||
}); | ||
}; | ||
export const isInterfaceField = ( | ||
@@ -35,9 +36,2 @@ type: GraphQLObjectType, | ||
export const hasField = ( | ||
type: GraphQLObjectType | GraphQLInterfaceType, | ||
fieldName: string | ||
) => { | ||
return Boolean(type.getFields()[fieldName]); | ||
}; | ||
// ---------------------------- | ||
@@ -132,67 +126,2 @@ | ||
// Borrowed from https://github.com/dmnd/dedent | ||
export function dedent( | ||
strings: string | TemplateStringsArray, | ||
...values: Array<string> | ||
) { | ||
const raw = typeof strings === "string" ? [strings] : strings.raw; | ||
// first, perform interpolation | ||
let result = ""; | ||
for (let i = 0; i < raw.length; i++) { | ||
result += raw[i] | ||
// join lines when there is a suppressed newline | ||
.replace(/\\\n[ \t]*/g, "") | ||
// handle escaped backticks | ||
.replace(/\\`/g, "`"); | ||
if (i < values.length) { | ||
result += values[i]; | ||
} | ||
} | ||
// now strip indentation | ||
const lines = result.split("\n"); | ||
let mindent: number | null = null; | ||
lines.forEach((l) => { | ||
let m = l.match(/^(\s+)\S+/); | ||
if (m) { | ||
let indent = m[1].length; | ||
if (!mindent) { | ||
// this is the first indented line | ||
mindent = indent; | ||
} else { | ||
mindent = Math.min(mindent, indent); | ||
} | ||
} | ||
}); | ||
if (mindent !== null) { | ||
const m = mindent; // appease Flow | ||
result = lines.map((l) => (l[0] === " " ? l.slice(m) : l)).join("\n"); | ||
} | ||
return ( | ||
result | ||
// dedent eats leading and trailing whitespace too | ||
.trim() | ||
// handle escaped newlines at the end to ensure they don't get stripped too | ||
.replace(/\\n/g, "\n") | ||
); | ||
} | ||
// ---------------------------- | ||
// Helper Fns | ||
export function arrPush<T, O extends Record<string, T[]>>( | ||
obj: O, | ||
property: string, | ||
value: T | ||
) { | ||
obj[property] = obj[property] || []; | ||
obj[property].push(value); | ||
} | ||
export function objValues<T>(obj: Record<string, T>): T[] { | ||
@@ -230,1 +159,54 @@ return Object.keys(obj).reduce((result: T[], key) => { | ||
}; | ||
export interface GroupedTypes { | ||
input: GraphQLInputObjectType[]; | ||
interface: GraphQLInterfaceType[]; | ||
object: GraphQLObjectType[]; | ||
union: GraphQLUnionType[]; | ||
enum: GraphQLEnumType[]; | ||
scalar: Array<GraphQLScalarType & { asNexusMethod?: string }>; | ||
} | ||
export function groupTypes(schema: GraphQLSchema) { | ||
const groupedTypes: GroupedTypes = { | ||
input: [], | ||
interface: [], | ||
object: [], | ||
union: [], | ||
enum: [], | ||
scalar: Array.from(specifiedScalarTypes), | ||
}; | ||
const schemaTypeMap = schema.getTypeMap(); | ||
Object.keys(schemaTypeMap) | ||
.sort() | ||
.forEach((typeName) => { | ||
if (typeName.indexOf("__") === 0) { | ||
return; | ||
} | ||
const type = schema.getType(typeName); | ||
if (isObjectType(type)) { | ||
groupedTypes.object.push(type); | ||
} else if (isInputObjectType(type)) { | ||
groupedTypes.input.push(type); | ||
} else if (isScalarType(type) && !isSpecifiedScalarType(type)) { | ||
groupedTypes.scalar.push(type); | ||
} else if (isUnionType(type)) { | ||
groupedTypes.union.push(type); | ||
} else if (isInterfaceType(type)) { | ||
groupedTypes.interface.push(type); | ||
} else if (isEnumType(type)) { | ||
groupedTypes.enum.push(type); | ||
} | ||
}); | ||
return groupedTypes; | ||
} | ||
export function firstDefined<T>(...args: Array<T | undefined>): T { | ||
for (let i = 0; i < args.length; i++) { | ||
const arg = args[i]; | ||
if (typeof arg !== "undefined") { | ||
return arg; | ||
} | ||
} | ||
throw new Error("At least one of the values should be defined"); | ||
} |
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
Deprecated
MaintenanceThe maintainer of the package marked it as deprecated. This could indicate that a single version should not be used, or that the package is no longer maintained and any new vulnerabilities will not be fixed.
Found 1 instance in 1 package
Major refactor
Supply chain riskPackage has recently undergone a major refactor. It may be unstable or indicate significant internal changes. Use caution when updating to versions that include significant changes.
Found 1 instance in 1 package
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
97
26
507085
16
7660
1
8
1