@gqlts/cli
Version:
Generate a client sdk from your GraphQl API
116 lines (107 loc) • 3.75 kB
text/typescript
import { RenderContext } from '../common/RenderContext';
import { excludedTypes } from '../common/excludedTypes';
import { objectType } from './objectType';
import { unionType } from './unionType';
import { ArgMap, CompressedField, CompressedFieldMap, CompressedTypeMap, TypeMap } from '@gqlts/runtime/dist/types';
import {
GraphQLSchema,
isEnumType,
isInputObjectType,
isInterfaceType,
isObjectType,
isScalarType,
isUnionType,
} from 'graphql';
export function renderTypeMap(schema: GraphQLSchema, ctx: RenderContext) {
// remove fields key,
// remove the Type.type and Type.args, replace with [type, args]
// reverse args.{name}
// Args type is deduced and added only when the concrete type is different from type name, remove the scalar field and replace with a top level scalars array field.
const result: TypeMap<string> = {
scalars: [],
types: {},
};
Object.keys(schema.getTypeMap())
.filter((t) => !excludedTypes.includes(t))
.map((t) => schema.getTypeMap()[t])
.map((t) => {
if (isObjectType(t) || isInterfaceType(t) || isInputObjectType(t)) result.types[t.name] = objectType(t, ctx);
else if (isUnionType(t)) result.types[t.name] = unionType(t, ctx);
else if (isScalarType(t) || isEnumType(t)) {
result.scalars.push(t.name);
result.types[t.name] = {};
}
});
// change names of query, mutation on schemas that chose different names (hasura)
const q = schema.getQueryType();
if (q?.name && q?.name !== 'Query') {
delete result.types[q.name];
result.types.Query = objectType(q, ctx);
// result.Query.name = 'Query'
}
const m = schema.getMutationType();
if (m?.name && m.name !== 'Mutation') {
delete result.types[m.name];
result.types.Mutation = objectType(m, ctx);
// result.Mutation.name = 'Mutation'
}
const s = schema.getSubscriptionType();
if (s?.name && s.name !== 'Subscription') {
delete result.types[s.name];
result.types.Subscription = objectType(s, ctx);
// result.Subscription.name = 'Subscription'
}
ctx.addCodeBlock(JSON.stringify(replaceTypeNamesWithIndexes(result), null, 4));
}
export function replaceTypeNamesWithIndexes(typeMap: TypeMap<string>): CompressedTypeMap<number> {
const nameToIndex: Record<string, number> = Object.assign(
{},
...Object.keys(typeMap.types).map((k, i) => ({ [k]: i })),
);
const scalars = typeMap.scalars.map((x) => nameToIndex[x]);
const types = Object.assign(
{},
...Object.keys(typeMap.types || {}).map((k) => {
const type = typeMap.types[k];
const fieldsMap = type || {};
// processFields(fields, indexToName)
const fields = Object.assign(
{},
...Object.keys(fieldsMap).map((f): CompressedFieldMap<number> => {
const content = fieldsMap[f] as any;
if (!content) {
throw new Error('no content in field ' + f);
}
const [typeName, args] = [content.type, content.args];
const res: CompressedField<number> = [typeName ? nameToIndex[typeName] : -1];
if (args) {
res[1] = Object.assign(
{},
...Object.keys(args || {}).map((k) => {
const arg = args?.[k];
if (!arg) {
throw new Error('replaceTypeNamesWithIndexes: no arg for ' + k);
}
return {
[k]: [nameToIndex[arg[0]], ...arg.slice(1)],
} as ArgMap<number>;
}),
);
}
return {
[f]: res,
};
}),
);
return {
[k]: {
...fields,
},
};
}),
);
return {
scalars,
types,
};
}