@graphql-ts/schema

Search for an npm package
'use strict';
var definition = require('graphql/type/definition');
var scalars = require('graphql/type/scalars');
/**
* An individual enum value in an {@link EnumType enum type} created using
* {@link enumType `graphql.enum`}. You can use the
* {@link enumValues `graphql.enumValues`} shorthand to create enum values more easily.
*
* Note the value property/generic here represents the deserialized form of the
* enum. It does not indicate the name of the enum value that is visible in the
* GraphQL schema. The value can be anything, not necessarily a string. Usually
* though, it will be a string which is equal to the key where the value is used.
*/
/**
* A shorthand to easily create {@link EnumValue enum values} to pass to
* {@link enumType `graphql.enum`}.
*
* If you need to set a `description` or `deprecationReason` for an enum
* variant, you should pass values directly to `graphql.enum` without using
* `graphql.enumValues`.
*
* ```ts
* const MyEnum = graphql.enum({
* name: "MyEnum",
* values: graphql.enumValues(["a", "b"]),
* });
* ```
*
* ```ts
* const values = graphql.enumValues(["a", "b"]);
*
* assertDeepEqual(values, {
* a: { value: "a" },
* b: { value: "b" },
* });
* ```
*/
function enumValues(values) {
return Object.fromEntries(values.map(value => [value, {
value
}]));
}
/**
* Creates an {@link EnumType enum type} with a number of {@link EnumValue enum values}.
*
* ```ts
* const MyEnum = graphql.enum({
* name: "MyEnum",
* values: graphql.enumValues(["a", "b"]),
* });
* // ==
* graphql`
* enum MyEnum {
* a
* b
* }
* `;
* ```
*
* ```ts
* const MyEnum = graphql.enum({
* name: "MyEnum",
* description: "My enum does things",
* values: {
* something: {
* description: "something something",
* value: "something",
* },
* thing: {
* description: "thing thing",
* deprecationReason: "something should be used instead of thing",
* value: "thing",
* },
* },
* });
* // ==
* graphql`
* """
* My enum does things
* """
* enum MyEnum {
* """
* something something
* """
* something
* """
* thing thing
* """
* thing @deprecated(reason: "something should be used instead of thing")
* }
* `;)
* ```
*/
function enumType(config) {
const graphQLType = new definition.GraphQLEnumType({
name: config.name,
description: config.description,
extensions: config.extensions,
values: config.values
});
return {
kind: "enum",
values: config.values,
graphQLType,
__context: undefined
};
}
/**
* Creates a {@link Arg GraphQL argument}.
*
* Args can can be used as arguments on output fields:
*
* ```ts
* graphql.field({
* type: graphql.String,
* args: {
* something: graphql.arg({ type: graphql.String }),
* },
* resolve(source, { something }) {
* return something || somethingElse;
* },
* });
* // ==
* graphql`(something: String): String`;
* ```
*
* Or as fields on input objects:
*
* ```ts
* const Something = graphql.inputObject({
* name: "Something",
* fields: {
* something: graphql.arg({ type: graphql.String }),
* },
* });
* // ==
* graphql`
* input Something {
* something: String
* }
* `;
* ```
*/
function arg(arg) {
if (!arg.type) {
throw new Error("A type must be passed to graphql.arg()");
}
return arg;
}
/**
* Creates an {@link InputObjectType}
*
* ```ts
* const Something = graphql.inputObject({
* name: "Something",
* fields: {
* something: graphql.arg({ type: graphql.String }),
* },
* });
* // ==
* graphql`
* input Something {
* something: String
* }
* `;
* ```
*
* ### Handling circular objects
*
* Circular input objects require explicitly specifying the fields on the object
* in the type because of TypeScript's limits with circularity.
*
* ```ts
* type SomethingInputType = graphql.InputObjectType<{
* something: graphql.Arg<SomethingInputType>;
* }>;
* const Something: SomethingInputType = graphql.inputObject({
* name: "Something",
* fields: () => ({
* something: graphql.arg({ type: Something }),
* }),
* });
* ```
*
* You can specify all of your non-circular fields outside of the fields object
* and then use `typeof` to get the type to avoid writing the non-circular
* fields as types again.
*
* ```ts
* const nonCircularFields = {
* thing: graphql.arg({ type: graphql.String }),
* };
* type SomethingInputType = graphql.InputObjectType<
* typeof nonCircularFields & {
* something: graphql.Arg<SomethingInputType>;
* }
* >;
* const Something: SomethingInputType = graphql.inputObject({
* name: "Something",
* fields: () => ({
* ...nonCircularFields,
* something: graphql.arg({ type: Something }),
* }),
* });
* ```
*/
function inputObject(config) {
const fields = config.fields;
const graphQLType = new definition.GraphQLInputObjectType({
name: config.name,
description: config.description,
fields: () => {
return Object.fromEntries(Object.entries(typeof fields === "function" ? fields() : fields).map(([key, value]) => [key, {
description: value.description,
type: value.type.graphQLType,
defaultValue: value.defaultValue,
deprecationReason: value.deprecationReason
}]));
}
});
return {
kind: "input",
__fields: undefined,
__context: undefined,
graphQLType
};
}
/**
* A GraphQL scalar type which wraps an underlying graphql-js
* `GraphQLScalarType` with a type representing the deserialized form of the
* scalar. These should be created used {@link scalar `graphql.scalar`}.
*
* ```ts
* const someScalar = graphql.scalar<string>(new GraphQLScalarType({}));
*
* // for fields on output types
* graphql.field({ type: someScalar });
*
* // for args on output fields or fields on input types
* graphql.arg({ type: someScalar });
* ```
*/
/**
* Creates a {@link ScalarType} from a graphql-js {@link GraphQLScalarType}.
*
* You should provide a type as a type parameter which is the type of the scalar
* value. Note, while graphql-js allows you to express scalar types like the
* `ID` type which accepts integers and strings as both input values and return
* values from resolvers which are transformed into strings before calling
* resolvers and returning the query respectively, the type you use should be
* `string` for `ID` since that is what it is transformed into.
* `@graphql-ts/schema` doesn't currently express the coercion of scalars, you
* should instead convert values to the canonical form yourself before returning
* from resolvers.
*
* ```ts
* const JSON = graphql.scalar<JSONValue>(GraphQLJSON);
* // for fields on output types
* graphql.field({ type: someScalar });
*
* // for args on output fields or fields on input types
* graphql.arg({ type: someScalar });
* ```
*/
function scalar(scalar) {
return {
kind: "scalar",
__type: undefined,
__context: undefined,
graphQLType: scalar
};
}
const ID = scalar(scalars.GraphQLID);
const String = scalar(scalars.GraphQLString);
const Float = scalar(scalars.GraphQLFloat);
const Int = scalar(scalars.GraphQLInt);
const Boolean = scalar(scalars.GraphQLBoolean);
/**
* Wraps any GraphQL type in a {@link ListType}.
*
* ```ts
* const stringListType = graphql.list(graphql.String);
* // ==
* graphql`[String]`;
* ```
*
* When used as an input type, you will recieve an array of the inner type.
*
* ```ts
* graphql.field({
* type: graphql.String,
* args: { thing: graphql.arg({ type: graphql.list(graphql.String) }) },
* resolve(source, { thing }) {
* const theThing: undefined | null | Array<string | null> = thing;
* return "";
* },
* });
* ```
*
* When used as an output type, you can return an iterable of the inner type
* that also matches `typeof val === 'object'` so for example, you'll probably
* return an Array most of the time but you could also return a Set you couldn't
* return a string though, even though a string is an iterable, it doesn't match
* `typeof val === 'object'`.
*
* ```ts
* graphql.field({
* type: graphql.list(graphql.String),
* resolve() {
* return [""];
* },
* });
* ```
*
* ```ts
* graphql.field({
* type: graphql.list(graphql.String),
* resolve() {
* return new Set([""]);
* },
* });
* ```
*
* ```ts
* graphql.field({
* type: graphql.list(graphql.String),
* resolve() {
* // this will not be allowed
* return "some things";
* },
* });
* ```
*/
function list(of) {
return {
kind: "list",
of,
__context: of["__context"],
graphQLType: new definition.GraphQLList(of.graphQLType)
};
}
/**
* Wraps a {@link NullableType} with a non-null type.
*
* See the documentation for {@link nonNull `graphql.nonNull`} for more information.
*/
/**
* Wraps a {@link NullableType} with a {@link NonNullType}.
*
* Types in GraphQL are always nullable by default so if you want to enforce
* that a type must always be there, you can use the non-null type.
*
* ```ts
* const nonNullableString = graphql.nonNull(graphql.String);
* // ==
* graphql`String!`;
* ```
*
* When using a non-null type as an input type, your resolver will never recieve
* null and consumers of your GraphQL API **must** provide a value for it unless
* you provide a default value.
*
* ```ts
* graphql.field({
* args: {
* someNonNullAndRequiredArg: graphql.arg({
* type: graphql.nonNull(graphql.String),
* }),
* someNonNullButOptionalArg: graphql.arg({
* type: graphql.nonNull(graphql.String),
* defaultValue: "some default",
* }),
* },
* type: graphql.String,
* resolve(source, args) {
* // both of these will always be a string
* args.someNonNullAndRequiredArg;
* args.someNonNullButOptionalArg;
*
* return "";
* },
* });
* // ==
* graphql`
* fieldName(
* someNonNullAndRequiredArg: String!
* someNonNullButOptionalArg: String! = "some default"
* ): String
* `;
* ```
*
* When using a non-null type as an output type, your resolver must never return
* null. If you do return null(which unless you do type-casting/ts-ignore/etc.
* `@graphql-ts/schema` will not let you do) graphql-js will return an error to
* consumers of your GraphQL API.
*
* Non-null types should be used very carefully on output types. If you have to
* do a fallible operation like a network request or etc. to get the value, it
* probably shouldn't be non-null. If you make a field non-null and doing the
* fallible operation fails, consumers of your GraphQL API will be unable to see
* any of the other fields on the object that the non-null field was on. For
* example, an id on some type is a good candidate for being non-null because if
* you have the item, you will already have the id so getting the id will never
* fail but fetching a related item from a database would be fallible so even if
* it will never be null in the success case, you should make it nullable.
*
* ```ts
* graphql.field({
* type: graphql.nonNull(graphql.String),
* resolve(source, args) {
* return "something";
* },
* });
* // ==
* graphql`
* fieldName: String!
* `;
* ```
*
* If you try to wrap another non-null type in a non-null type again, you will
* get a type error.
*
* ```ts
* // Argument of type 'NonNullType<ScalarType<string>>'
* // is not assignable to parameter of type 'TypesExcludingNonNull'.
* graphql.nonNull(graphql.nonNull(graphql.String));
* ```
*/
function nonNull(of) {
return {
kind: "non-null",
of,
__context: of["__context"],
graphQLType: new definition.GraphQLNonNull(of.graphQLType)
};
}
exports.Boolean = Boolean;
exports.Float = Float;
exports.ID = ID;
exports.Int = Int;
exports.String = String;
exports.arg = arg;
exports.enumType = enumType;
exports.enumValues = enumValues;
exports.inputObject = inputObject;
exports.list = list;
exports.nonNull = nonNull;
exports.scalar = scalar;