@homebound/graphql-typescript-simple-resolvers
Advanced tools
Comparing version 1.8.0 to 1.12.0
"use strict"; | ||
Object.defineProperty(exports, "__esModule", { value: true }); | ||
const graphql_1 = require("graphql"); | ||
const change_case_1 = require("change-case"); | ||
const upper_case_first_1 = require("upper-case-first"); | ||
const ts_poet_1 = require("ts-poet"); | ||
const types_1 = require("./types"); | ||
const builtInScalars = ["Int", "Boolean", "String", "ID", "Float"]; | ||
@@ -24,9 +24,19 @@ const GraphQLScalarTypeSymbol = ts_poet_1.imp("GraphQLScalarType@graphql"); | ||
const typesThatNeedResolvers = Object.values(schema.getTypeMap()) | ||
.filter(isObjectType) | ||
.filter(types_1.isObjectType) | ||
.filter(t => needsResolver(config, t)); | ||
const typesThatMayHaveResolvers = Object.values(schema.getTypeMap()) | ||
.filter(isObjectType) | ||
.filter(types_1.isObjectType) | ||
.filter(t => optionalResolver(config, t)); | ||
const scalars = Object.values(schema.getTypeMap()).filter(isScalarType); | ||
// Make the top-level Resolvers interface | ||
const allTypesWithResolvers = [...typesThatNeedResolvers, ...typesThatMayHaveResolvers]; | ||
const scalars = Object.values(schema.getTypeMap()).filter(types_1.isScalarType); | ||
generateTopLevelResolversType(chunks, typesThatMayHaveResolvers, typesThatNeedResolvers, scalars); | ||
generateEachResolverType(chunks, config, allTypesWithResolvers); | ||
generateDtosForNonMappedTypes(chunks, config, typesThatMayHaveResolvers); | ||
generateInputTypes(chunks, config, schema); | ||
generateEnums(chunks, config, schema); | ||
const content = await ts_poet_1.code `${chunks}`.toStringWithImports(); | ||
return { content }; | ||
}; | ||
// Make the top-level Resolvers interface | ||
function generateTopLevelResolversType(chunks, typesThatMayHaveResolvers, typesThatNeedResolvers, scalars) { | ||
const resolvers = ts_poet_1.code ` | ||
@@ -48,6 +58,8 @@ export interface Resolvers { | ||
chunks.push(resolvers); | ||
} | ||
function generateEachResolverType(chunks, config, allTypesWithResolvers) { | ||
// Make each resolver for any output type, whether its required or optional | ||
const ctx = toImp(config.contextType); | ||
const ctx = types_1.toImp(config.contextType); | ||
const argDefs = []; | ||
[...typesThatNeedResolvers, ...typesThatMayHaveResolvers].forEach(type => { | ||
allTypesWithResolvers.forEach(type => { | ||
chunks.push(ts_poet_1.code ` | ||
@@ -61,7 +73,7 @@ export interface ${type.name}Resolvers { | ||
export interface ${argsName} { | ||
${f.args.map(a => ts_poet_1.code `${a.name}: ${mapType(config, a.type)}; `)} | ||
${f.args.map(a => ts_poet_1.code `${a.name}: ${types_1.mapType(config, a.type)}; `)} | ||
}`); | ||
} | ||
const root = mapObjectType(config, type); | ||
const result = mapType(config, f.type); | ||
const root = types_1.mapObjectType(config, type); | ||
const result = types_1.mapType(config, f.type); | ||
return ts_poet_1.code `${f.name}: Resolver<${root}, ${args}, ${result}>;`; | ||
@@ -76,2 +88,4 @@ })} | ||
argDefs.forEach(a => chunks.push(a)); | ||
} | ||
function generateDtosForNonMappedTypes(chunks, config, typesThatMayHaveResolvers) { | ||
// For the output types with optional resolvers, make DTOs for them. Mapped types don't need DTOs. | ||
@@ -82,3 +96,3 @@ typesThatMayHaveResolvers.forEach(type => { | ||
${Object.values(type.getFields()).map(f => { | ||
return ts_poet_1.code `${f.name}: ${mapType(config, f.type)};`; | ||
return ts_poet_1.code `${f.name}: ${types_1.mapType(config, f.type)};`; | ||
})} | ||
@@ -88,5 +102,7 @@ } | ||
}); | ||
// Input types | ||
} | ||
// Input types | ||
function generateInputTypes(chunks, config, schema) { | ||
Object.values(schema.getTypeMap()) | ||
.filter(isInputObjectType) | ||
.filter(types_1.isInputObjectType) | ||
.forEach(type => { | ||
@@ -96,3 +112,3 @@ chunks.push(ts_poet_1.code ` | ||
${Object.values(type.getFields()).map(f => { | ||
return ts_poet_1.code `${f.name}: ${mapType(config, f.type)};`; | ||
return ts_poet_1.code `${f.name}: ${types_1.mapType(config, f.type)};`; | ||
})} | ||
@@ -102,6 +118,8 @@ } | ||
}); | ||
} | ||
function generateEnums(chunks, config, schema) { | ||
// Enums | ||
Object.values(schema.getTypeMap()) | ||
.filter(isEnumType) | ||
.filter(isNotMetadataType) | ||
.filter(types_1.isEnumType) | ||
.filter(types_1.isNotMetadataType) | ||
.forEach(type => { | ||
@@ -123,91 +141,8 @@ const mappedEnum = config.enumValues[type.name]; | ||
}); | ||
const content = await ts_poet_1.code `${chunks}`.toStringWithImports(); | ||
return { content }; | ||
}; | ||
/** Turns a generic `type` into a TS type, note that we detect non-nulls which means types are initially assumed nullable. */ | ||
function mapType(config, type) { | ||
if (type instanceof graphql_1.GraphQLNonNull) { | ||
const sub = mapType(config, type.ofType); | ||
return stripNullable(sub); | ||
} | ||
else if (type instanceof graphql_1.GraphQLList) { | ||
return nullableOf(ts_poet_1.code `${mapType(config, type.ofType)}[]`); | ||
} | ||
else if (type instanceof graphql_1.GraphQLObjectType) { | ||
return nullableOf(mapObjectType(config, type)); | ||
} | ||
else if (type instanceof graphql_1.GraphQLScalarType) { | ||
return nullableOf(mapScalarType(type)); | ||
} | ||
else if (type instanceof graphql_1.GraphQLEnumType) { | ||
return nullableOf(mapEnumType(config, type)); | ||
} | ||
else if (type instanceof graphql_1.GraphQLInputObjectType) { | ||
return nullableOf(type.name); | ||
} | ||
else { | ||
throw new Error(`Unsupported type ${type}`); | ||
} | ||
} | ||
function mapObjectType(config, type) { | ||
if (type.name === "Query" || type.name === "Mutation") { | ||
return "{}"; | ||
} | ||
return toImp(config.mappers[type.name]) || type.name; | ||
} | ||
function mapEnumType(config, type) { | ||
return toImp(config.enumValues[type.name]) || type.name; | ||
} | ||
function mapScalarType(type) { | ||
if (type.name === "String" || type.name === "ID") { | ||
return "string"; | ||
} | ||
else if (type.name === "Int" || type.name === "Float") { | ||
return "number"; | ||
} | ||
else { | ||
return type.name.toString(); | ||
} | ||
} | ||
/** Marks `type` as nullable in a way that both will be output correctly by ts-poet + can be undone. */ | ||
function nullableOf(type) { | ||
return [type, "| null"]; | ||
} | ||
/** Unmarks `type` as nullable, i.e. types are always nullable until unwrapped by a GraphQLNonNull parent. */ | ||
function stripNullable(type) { | ||
if (type instanceof Array && type.length == 2 && type[1] === "| null") { | ||
return type[0]; | ||
} | ||
else { | ||
return type; | ||
} | ||
} | ||
// Maps the graphql-code-generation convention of `@src/context#Context` to ts-poet's `Context@@src/context`. | ||
function toImp(spec) { | ||
if (!spec) { | ||
return undefined; | ||
} | ||
const [path, symbol] = spec.split("#"); | ||
return ts_poet_1.imp(`${symbol}@${path}`); | ||
} | ||
function isObjectType(t) { | ||
return t instanceof graphql_1.GraphQLObjectType; | ||
} | ||
function isInputObjectType(t) { | ||
return t instanceof graphql_1.GraphQLInputObjectType; | ||
} | ||
function isEnumType(t) { | ||
return t instanceof graphql_1.GraphQLEnumType; | ||
} | ||
function isScalarType(t) { | ||
return t instanceof graphql_1.GraphQLScalarType; | ||
} | ||
function needsResolver(config, t) { | ||
return isNotMetadataType(t) && (!!config.mappers[t.name] || t.name === "Query" || t.name === "Mutation"); | ||
return types_1.isNotMetadataType(t) && (types_1.isMappedType(t, config) || types_1.isQueryOrMutationType(t)); | ||
} | ||
function optionalResolver(config, t) { | ||
return isNotMetadataType(t) && !config.mappers[t.name] && t.name !== "Query" && t.name !== "Mutation"; | ||
return types_1.isNotMetadataType(t) && !types_1.isMappedType(t, config) && !types_1.isQueryOrMutationType(t); | ||
} | ||
function isNotMetadataType(t) { | ||
return !t.name.startsWith("__"); | ||
} |
{ | ||
"name": "@homebound/graphql-typescript-simple-resolvers", | ||
"version": "1.8.0", | ||
"version": "1.12.0", | ||
"main": "./build/index.js", | ||
@@ -5,0 +5,0 @@ "types": "./build/", |
14860
12
322