@cran/lib.gql.core
Version:
GQL Core Functionality
93 lines (77 loc) • 2.23 kB
text/typescript
import type { Plugin } from "../plugins/Plugin";
import { type Derivative, parseError, parseLiteral } from "./parse";
import {
GraphQLScalarType, type GraphQLScalarValueParser, type ValueNode,
} from "graphql";
export namespace createScalar {
export interface Types {
string : string;
number : number;
boolean: boolean;
object : Record<string, Derivative>;
array : Array<Derivative>;
}
export type Invalid = ( reason?: string ) => string;
export type Casts = {
[Key in keyof Types]?: boolean | ((
value: Types[Key], invalid: Invalid
) => string);
};
export type Serializer = ( value: unknown ) => unknown;
}
function getTypeOf ( value: Derivative ) {
return (
value instanceof Array ? "array" : typeof value
) as keyof createScalar.Casts;
}
export function createScalar (
name: string, description: string,
casts: createScalar.Casts,
serialize?: createScalar.Serializer | undefined
) {
const asType = createScalarCast(name, casts);
return {
typeDefs : `scalar ${name}`,
resolvers: {
[name]: new GraphQLScalarType({
name,
description,
serialize : serialize!,
parseValue: asType,
parseLiteral ( ast, variables ) {
return asType(parseLiteral(name, ast, variables));
},
}),
},
} as const as Plugin;
}
export function createScalarCast (
name: string, casts: createScalar.Casts
) {
return function asType ( value: Derivative, ast?: ValueNode ) {
if (null === value) { return null; }
const type = getTypeOf(value);
let result: unknown = null;
try {
const cast = casts[type];
if (cast instanceof Function) {
result = cast(value as never, function invalid ( reason ) {
parseError(type, ast ?? value, reason);
});
} else if (cast) {
switch (type) {
case "object": case "array":
result = JSON.stringify(value);
break;
default:
result = String(value);
break;
}
}
} catch { /* ignored */ }
if (null === result) {
parseError(name, ast ?? value);
}
return result;
} as GraphQLScalarValueParser<unknown>;
}