From 68b45d7fc30c7cbb3f4c4bb89ab7f58de9967b96 Mon Sep 17 00:00:00 2001 From: Jason Kuhrt Date: Thu, 11 Apr 2024 22:23:32 -0400 Subject: [PATCH 01/10] refactor(ts-client): schema module --- src/Schema/Field/Field.ts | 39 +++-- src/Schema/Field/Type.ts | 133 ------------------ src/Schema/Field/_.ts | 1 - src/Schema/Field/__.ts | 3 +- src/Schema/{NamedType => Hybrid}/Enum.ts | 0 .../{NamedType => Hybrid}/Scalar/Scalar.ts | 0 src/Schema/{NamedType => Hybrid}/Scalar/_.ts | 0 .../{NamedType => Hybrid}/Scalar/codec.ts | 0 .../Scalar/nativeScalarCodecs.ts | 0 src/Schema/Hybrid/_.ts | 2 + src/Schema/Hybrid/__.ts | 1 + src/Schema/Index.ts | 11 -- src/Schema/Input/Input.ts | 24 ++++ src/Schema/Input/__.ts | 1 + src/Schema/Input/typeGroups.ts | 6 + .../{NamedType => Input/types}/InputObjet.ts | 0 src/Schema/Input/types/List.ts | 9 ++ src/Schema/Input/types/Nullable.ts | 10 ++ src/Schema/NamedType/_.ts | 7 - src/Schema/Output/Output.ts | 35 +++++ src/Schema/Output/__.ts | 1 + src/Schema/Output/typeGroups.ts | 14 ++ .../{NamedType => Output/types}/Interface.ts | 6 +- src/Schema/Output/types/List.ts | 9 ++ src/Schema/Output/types/Nullable.ts | 13 ++ .../{NamedType => Output/types}/Object.ts | 30 ++-- .../{NamedType => Output/types}/Union.ts | 0 src/Schema/Output/types/__typename.ts | 6 + src/Schema/_.ts | 8 +- src/Schema/__.ts | 4 +- src/Schema/core/Index.ts | 12 ++ .../{ => core}/NamedType/NamedType.test-d.ts | 0 src/Schema/{ => core}/NamedType/NamedType.ts | 12 +- src/Schema/core/NamedType/_.ts | 1 + src/Schema/{ => core}/NamedType/__.ts | 0 src/Schema/core/helpers.ts | 20 +++ src/entrypoints/alpha/scalars.ts | 2 +- tests/ts/_/schema/customScalarCodecs.ts | 2 +- tests/ts/_/schema/generated/Scalar.ts | 2 +- 39 files changed, 218 insertions(+), 206 deletions(-) delete mode 100644 src/Schema/Field/Type.ts delete mode 100644 src/Schema/Field/_.ts rename src/Schema/{NamedType => Hybrid}/Enum.ts (100%) rename src/Schema/{NamedType => Hybrid}/Scalar/Scalar.ts (100%) rename src/Schema/{NamedType => Hybrid}/Scalar/_.ts (100%) rename src/Schema/{NamedType => Hybrid}/Scalar/codec.ts (100%) rename src/Schema/{NamedType => Hybrid}/Scalar/nativeScalarCodecs.ts (100%) create mode 100644 src/Schema/Hybrid/_.ts create mode 100644 src/Schema/Hybrid/__.ts delete mode 100644 src/Schema/Index.ts create mode 100644 src/Schema/Input/Input.ts create mode 100644 src/Schema/Input/__.ts create mode 100644 src/Schema/Input/typeGroups.ts rename src/Schema/{NamedType => Input/types}/InputObjet.ts (100%) create mode 100644 src/Schema/Input/types/List.ts create mode 100644 src/Schema/Input/types/Nullable.ts delete mode 100644 src/Schema/NamedType/_.ts create mode 100644 src/Schema/Output/Output.ts create mode 100644 src/Schema/Output/__.ts create mode 100644 src/Schema/Output/typeGroups.ts rename src/Schema/{NamedType => Output/types}/Interface.ts (75%) create mode 100644 src/Schema/Output/types/List.ts create mode 100644 src/Schema/Output/types/Nullable.ts rename src/Schema/{NamedType => Output/types}/Object.ts (50%) rename src/Schema/{NamedType => Output/types}/Union.ts (100%) create mode 100644 src/Schema/Output/types/__typename.ts create mode 100644 src/Schema/core/Index.ts rename src/Schema/{ => core}/NamedType/NamedType.test-d.ts (100%) rename src/Schema/{ => core}/NamedType/NamedType.ts (52%) create mode 100644 src/Schema/core/NamedType/_.ts rename src/Schema/{ => core}/NamedType/__.ts (100%) create mode 100644 src/Schema/core/helpers.ts diff --git a/src/Schema/Field/Field.ts b/src/Schema/Field/Field.ts index 5414227d6..266cb1443 100644 --- a/src/Schema/Field/Field.ts +++ b/src/Schema/Field/Field.ts @@ -1,38 +1,49 @@ -import type { NamedType } from '../NamedType/__.js' -import type { Scalar } from '../NamedType/Scalar/_.js' - -import type * as Type from './Type.js' - -export type * as Type from './Type.js' +import type { MaybeThunk } from '../core/helpers.js' +import { buildTimeOnly } from '../core/helpers.js' +import type * as TypesHybrid from '../Hybrid/_.js' +import type { Nullable } from '../Input/types/Nullable.js' +import type { Output } from '../Output/__.js' export type As = T extends Field ? T : never -export type Enum<$Args extends Args | null = null> = Field +export type Enum<$Args extends Args | null = null> = Field -export type Scalar<$Args extends Args | null = Args | null> = Field +export type Scalar<$Args extends Args | null = Args | null> = Field -export type String<$Args extends Args | null = null> = Field +export type String<$Args extends Args | null = null> = Field -export type Number<$Args extends Args | null = null> = Field +export type Number<$Args extends Args | null = null> = Field -export type Boolean<$Args extends Args | null = null> = Field +export type Boolean<$Args extends Args | null = null> = Field // export interface Args<$Fields extends Record = Record> { export interface Args<$Fields extends any = any> { - allOptional: Exclude<$Fields[keyof $Fields], Type.Output.Nullable> extends never ? true : false + allOptional: Exclude<$Fields[keyof $Fields], Nullable> extends never ? true : false fields: $Fields } export const Args = (fields: F): Args => { return { - // @ts-expect-error todo................................... + // @ts-expect-error allOptional: false, fields, } } export type Field<$Type extends any = any, $Args extends Args | null = Args | null> = { - typeUnwrapped: Type.Output.Unwrap<$Type> + typeUnwrapped: Output.Unwrap<$Type> type: $Type args: $Args } + +export const field = <$Type extends Output.Any, $Args extends null | Args = null>( + type: MaybeThunk<$Type>, + args: $Args = null as $Args, +): Field<$Type, $Args> => { + return { + typeUnwrapped: buildTimeOnly, // eslint-disable-line + // At type level "type" is not a thunk + type: type as any, // eslint-disable-line + args, + } +} diff --git a/src/Schema/Field/Type.ts b/src/Schema/Field/Type.ts deleted file mode 100644 index 96ca9b28f..000000000 --- a/src/Schema/Field/Type.ts +++ /dev/null @@ -1,133 +0,0 @@ -import type { TSError } from '../../lib/TSError.js' -import type { NamedType } from '../NamedType/__.js' -import type { Args } from './Field.js' - -const buildTimeOnly: any = undefined -export namespace Base { - export interface Nullable<$Type> { - kind: 'nullable' - type: $Type - } - export interface List<$Type> { - kind: 'list' - type: $Type - } -} - -export namespace Output { - export interface __typename<$Type extends string = string> { - kind: 'typename' - type: $Type - } - - export type Named = NamedType.AnyOutput - - export type Nullable<$Type extends Output.List | __typename | NamedType.AnyOutput> = Base.Nullable<$Type> - - export type List<$Type extends Any> = Base.List<$Type> - - export type Any = Output.List | __typename | Base.Nullable | NamedType.AnyOutput - - export const __typename = <$Type extends string>(type: $Type): __typename<$Type> => ({ kind: `typename`, type }) - - export const Nullable = <$Type extends __typename | List | NamedType.AnyOutput>( - type: MaybeThunk<$Type>, - ): Nullable<$Type> => ({ - kind: `nullable`, - // at type level "type" is not a thunk - type: type as any, // eslint-disable-line - }) - - export const List = <$Type extends Any>(type: $Type): List<$Type> => ({ - kind: `list`, - type, - }) - - // todo extends any because of infinite depth issue in generated schema types - // dprint-ignore - export type Unwrap<$Type extends any> = - $Type extends List ? Unwrap<$innerType> : - $Type extends Nullable ? Unwrap<$innerType> : - $Type extends __typename ? $Type['type'] : - $Type extends NamedType.AnyOutput ? $Type : - TSError<'Unwrap', 'Unknown $Type', { $Type: $Type }> - // dprint-ignore - export type UnwrapNonNull<$Type> = - $Type extends Nullable ? UnwrapNonNull<$innerType> - : $Type - - export const unwrapNonNull = <$Type extends Any>(type: $Type): UnwrapNonNull<$Type> => { - if (type.kind === `nullable`) return type.type - return type as UnwrapNonNull<$Type> - } - - export const unwrap = <$Type extends Any>(type: $Type): Unwrap<$Type> => { - // @ts-expect-error fixme - return type.kind === `named` ? type.type : unwrap(type.type) - } - - export const field = <$Type extends Any, $Args extends null | Args = null>( - type: MaybeThunk<$Type>, - args: $Args = null as $Args, - ): Field<$Type, $Args> => { - return { - typeUnwrapped: buildTimeOnly, // eslint-disable-line - // At type level "type" is not a thunk - type: type as any, // eslint-disable-line - args, - } - } - - export type Field<$Type extends any = any, $Args extends Args | null = Args | null> = { - typeUnwrapped: Unwrap<$Type> - type: $Type - args: $Args - } -} - -export namespace Input { - export type Nullable<$InnerType extends Any = Any> = Base.Nullable<$InnerType> - export type List<$InnerType extends Any = Any> = Base.List<$InnerType> - export type Any = List | Nullable | NamedType.AnyInput - - export const Nullable = <$InnerType extends Any>(type: MaybeThunk<$InnerType>): Nullable<$InnerType> => ({ - kind: `nullable`, - // at type level "type" is not a thunk - type: type as any, // eslint-disable-line - }) - - export const List = <$InnerType extends Any>(type: $InnerType): List<$InnerType> => ({ - kind: `list`, - type, - }) - - export const field = <$Type extends Any>(type: $Type): Field<$Type> => { - return { - type: type, - } - } - - // dprint-ignore - type UnwrapNonNull<$Type> = - $Type extends Nullable ? UnwrapNonNull<$innerType> - : $Type - - export const unwrapNullable = <$Type extends Any>(type: $Type): UnwrapNonNull<$Type> => { - if (type.kind === `nullable`) return type.type - // @ts-expect-error fixme - return type - } - - export type Field<$Type extends any = any> = { - // typeUnwrapped: Type.Output.Unwrap<$Type> - type: $Type - } -} - -type MaybeThunk<$Type> = $Type | Thunk<$Type> - -type Thunk<$Type> = () => $Type - -export const readMaybeThunk = (maybeThunk: MaybeThunk): T => - // @ts-expect-error fixme - typeof maybeThunk === `function` ? maybeThunk() : maybeThunk diff --git a/src/Schema/Field/_.ts b/src/Schema/Field/_.ts deleted file mode 100644 index f9956dd53..000000000 --- a/src/Schema/Field/_.ts +++ /dev/null @@ -1 +0,0 @@ -export * as Field from './__.js' diff --git a/src/Schema/Field/__.ts b/src/Schema/Field/__.ts index 3292e0087..581873b2c 100644 --- a/src/Schema/Field/__.ts +++ b/src/Schema/Field/__.ts @@ -1,2 +1 @@ -export * from './Field.js' -export * from './Type.js' +export * as Field from './Field.js' diff --git a/src/Schema/NamedType/Enum.ts b/src/Schema/Hybrid/Enum.ts similarity index 100% rename from src/Schema/NamedType/Enum.ts rename to src/Schema/Hybrid/Enum.ts diff --git a/src/Schema/NamedType/Scalar/Scalar.ts b/src/Schema/Hybrid/Scalar/Scalar.ts similarity index 100% rename from src/Schema/NamedType/Scalar/Scalar.ts rename to src/Schema/Hybrid/Scalar/Scalar.ts diff --git a/src/Schema/NamedType/Scalar/_.ts b/src/Schema/Hybrid/Scalar/_.ts similarity index 100% rename from src/Schema/NamedType/Scalar/_.ts rename to src/Schema/Hybrid/Scalar/_.ts diff --git a/src/Schema/NamedType/Scalar/codec.ts b/src/Schema/Hybrid/Scalar/codec.ts similarity index 100% rename from src/Schema/NamedType/Scalar/codec.ts rename to src/Schema/Hybrid/Scalar/codec.ts diff --git a/src/Schema/NamedType/Scalar/nativeScalarCodecs.ts b/src/Schema/Hybrid/Scalar/nativeScalarCodecs.ts similarity index 100% rename from src/Schema/NamedType/Scalar/nativeScalarCodecs.ts rename to src/Schema/Hybrid/Scalar/nativeScalarCodecs.ts diff --git a/src/Schema/Hybrid/_.ts b/src/Schema/Hybrid/_.ts new file mode 100644 index 000000000..80a6c0668 --- /dev/null +++ b/src/Schema/Hybrid/_.ts @@ -0,0 +1,2 @@ +export * from './Enum.js' +export * from './Scalar/_.js' diff --git a/src/Schema/Hybrid/__.ts b/src/Schema/Hybrid/__.ts new file mode 100644 index 000000000..780cae1e4 --- /dev/null +++ b/src/Schema/Hybrid/__.ts @@ -0,0 +1 @@ +export * as Hybrid from './_.js' diff --git a/src/Schema/Index.ts b/src/Schema/Index.ts deleted file mode 100644 index ef89e8be5..000000000 --- a/src/Schema/Index.ts +++ /dev/null @@ -1,11 +0,0 @@ -import type { Object$2, Union } from './__.js' - -export interface Index { - Root: { - Query: null | Object$2 - Mutation: null | Object$2 - Subscription: null | Object$2 - } - objects: Record - unions: Record -} diff --git a/src/Schema/Input/Input.ts b/src/Schema/Input/Input.ts new file mode 100644 index 000000000..ef341a8b9 --- /dev/null +++ b/src/Schema/Input/Input.ts @@ -0,0 +1,24 @@ +import type { Any } from './typeGroups.js' +import type { Nullable } from './types/Nullable.js' + +export const field = <$Type extends Any>(type: $Type): Field<$Type> => { + return { + type: type, + } +} + +// dprint-ignore +type UnwrapNonNull<$Type> = + $Type extends Nullable ? UnwrapNonNull<$innerType> + : $Type + +export const unwrapNullable = <$Type extends Any>(type: $Type): UnwrapNonNull<$Type> => { + if (type.kind === `nullable`) return type.type + // @ts-expect-error fixme + return type +} + +export type Field<$Type extends any = any> = { + // typeUnwrapped: Type.Output.Unwrap<$Type> + type: $Type +} diff --git a/src/Schema/Input/__.ts b/src/Schema/Input/__.ts new file mode 100644 index 000000000..31e74e92c --- /dev/null +++ b/src/Schema/Input/__.ts @@ -0,0 +1 @@ +export * as Input from './Input.js' diff --git a/src/Schema/Input/typeGroups.ts b/src/Schema/Input/typeGroups.ts new file mode 100644 index 000000000..deb0a1b76 --- /dev/null +++ b/src/Schema/Input/typeGroups.ts @@ -0,0 +1,6 @@ +import type { Enum, Scalar } from '../__.js' +import type { InputObject } from './types/InputObjet.js' +import type { List } from './types/List.js' +import type { Nullable } from './types/Nullable.js' + +export type Any = List | Nullable | Enum | Scalar.Any | InputObject diff --git a/src/Schema/NamedType/InputObjet.ts b/src/Schema/Input/types/InputObjet.ts similarity index 100% rename from src/Schema/NamedType/InputObjet.ts rename to src/Schema/Input/types/InputObjet.ts diff --git a/src/Schema/Input/types/List.ts b/src/Schema/Input/types/List.ts new file mode 100644 index 000000000..5f8faa012 --- /dev/null +++ b/src/Schema/Input/types/List.ts @@ -0,0 +1,9 @@ +import type { Base } from '../../core/helpers.js' +import type { Any } from '../typeGroups.js' + +export type List<$InnerType extends Any = Any> = Base.List<$InnerType> + +export const List = <$InnerType extends Any>(type: $InnerType): List<$InnerType> => ({ + kind: `list`, + type, +}) diff --git a/src/Schema/Input/types/Nullable.ts b/src/Schema/Input/types/Nullable.ts new file mode 100644 index 000000000..9e3433d79 --- /dev/null +++ b/src/Schema/Input/types/Nullable.ts @@ -0,0 +1,10 @@ +import type { Base, MaybeThunk } from '../../core/helpers.js' +import type { Any } from '../typeGroups.js' + +export type Nullable<$InnerType extends Any = Any> = Base.Nullable<$InnerType> + +export const Nullable = <$InnerType extends Any>(type: MaybeThunk<$InnerType>): Nullable<$InnerType> => ({ + kind: `nullable`, + // at type level "type" is not a thunk + type: type as any, // eslint-disable-line +}) diff --git a/src/Schema/NamedType/_.ts b/src/Schema/NamedType/_.ts deleted file mode 100644 index 40e0b6247..000000000 --- a/src/Schema/NamedType/_.ts +++ /dev/null @@ -1,7 +0,0 @@ -export * from './Enum.js' -export * from './InputObjet.js' -export * from './Interface.js' -export * from './NamedType.js' -export * from './Object.js' -export * from './Scalar/_.js' -export * from './Union.js' diff --git a/src/Schema/Output/Output.ts b/src/Schema/Output/Output.ts new file mode 100644 index 000000000..a8c780f74 --- /dev/null +++ b/src/Schema/Output/Output.ts @@ -0,0 +1,35 @@ +import type { TSError } from '../../lib/TSError.js' +import type { Any, Named } from './typeGroups.js' +import type { __typename } from './types/__typename.js' +import type { List } from './types/List.js' +import type { Nullable } from './types/Nullable.js' + +export * from './typeGroups.js' +export * from './types/Interface.js' +export * from './types/List.js' +export * from './types/Nullable.js' +export * from './types/Object.js' +export * from './types/Union.js' + +// todo extends any because of infinite depth issue in generated schema types +// dprint-ignore +export type Unwrap<$Type extends any> = + $Type extends List ? Unwrap<$innerType> : + $Type extends Nullable ? Unwrap<$innerType> : + $Type extends __typename ? $Type['type'] : + $Type extends Named ? $Type : + TSError<'Unwrap', 'Unknown $Type', { $Type: $Type }> +// dprint-ignore +export type UnwrapNonNull<$Type> = + $Type extends Nullable ? UnwrapNonNull<$innerType> + : $Type + +export const unwrapNonNull = <$Type extends Any>(type: $Type): UnwrapNonNull<$Type> => { + if (type.kind === `nullable`) return type.type + return type as UnwrapNonNull<$Type> +} + +export const unwrap = <$Type extends Any>(type: $Type): Unwrap<$Type> => { + // @ts-expect-error fixme + return type.kind === `named` ? type.type : unwrap(type.type) +} diff --git a/src/Schema/Output/__.ts b/src/Schema/Output/__.ts new file mode 100644 index 000000000..6df548327 --- /dev/null +++ b/src/Schema/Output/__.ts @@ -0,0 +1 @@ +export * as Output from './Output.js' diff --git a/src/Schema/Output/typeGroups.ts b/src/Schema/Output/typeGroups.ts new file mode 100644 index 000000000..35f28f709 --- /dev/null +++ b/src/Schema/Output/typeGroups.ts @@ -0,0 +1,14 @@ +import type { Hybrid } from '../Hybrid/__.js' +import type { Enum } from '../Hybrid/Enum.js' +import type { __typename } from './types/__typename.js' +import type { Interface } from './types/Interface.js' +import type { List } from './types/List.js' +import type { Nullable } from './types/Nullable.js' +import type { Object$2 } from './types/Object.js' +import type { Union } from './types/Union.js' + +export type Named = Interface | Enum | Object$2 | Union | Hybrid.Scalar.Any + +export type Unnamed = List | __typename | Nullable + +export type Any = Unnamed | Named diff --git a/src/Schema/NamedType/Interface.ts b/src/Schema/Output/types/Interface.ts similarity index 75% rename from src/Schema/NamedType/Interface.ts rename to src/Schema/Output/types/Interface.ts index 492bb7a70..681eec168 100644 --- a/src/Schema/NamedType/Interface.ts +++ b/src/Schema/Output/types/Interface.ts @@ -1,9 +1,9 @@ -import type { Output } from '../__.js' +import type { Field } from '../../Field/__.js' import type { Object$2 } from './Object.js' export type Interface< $Name extends string = string, - $Fields extends Record = Record, + $Fields extends Record = Record, $Implementors extends [Object$2, ...Object$2[]] = [Object$2, ...Object$2[]], > = { kind: 'Interface' @@ -14,7 +14,7 @@ export type Interface< export const Interface = < $Name extends string, - $Fields extends Record, + $Fields extends Record, $Implementors extends [Object$2, ...Object$2[]], >( name: $Name, diff --git a/src/Schema/Output/types/List.ts b/src/Schema/Output/types/List.ts new file mode 100644 index 000000000..46e373324 --- /dev/null +++ b/src/Schema/Output/types/List.ts @@ -0,0 +1,9 @@ +import type { Base } from '../../core/helpers.js' +import type { Any } from '../typeGroups.js' + +export type List<$Type extends Any> = Base.List<$Type> + +export const List = <$Type extends Any>(type: $Type): List<$Type> => ({ + kind: `list`, + type, +}) diff --git a/src/Schema/Output/types/Nullable.ts b/src/Schema/Output/types/Nullable.ts new file mode 100644 index 000000000..d5708ae7d --- /dev/null +++ b/src/Schema/Output/types/Nullable.ts @@ -0,0 +1,13 @@ +import type { Base, MaybeThunk } from '../../core/helpers.js' +import type { Any } from '../typeGroups.js' +import type { __typename } from './__typename.js' + +export type Nullable<$Type extends Exclude>> = Base.Nullable<$Type> + +export const Nullable = <$Type extends Exclude>>( + type: MaybeThunk<$Type>, +): Nullable<$Type> => ({ + kind: `nullable`, + // at type level "type" is not a thunk + type: type as any, // eslint-disable-line +}) diff --git a/src/Schema/NamedType/Object.ts b/src/Schema/Output/types/Object.ts similarity index 50% rename from src/Schema/NamedType/Object.ts rename to src/Schema/Output/types/Object.ts index 3ccec0ead..599e15529 100644 --- a/src/Schema/NamedType/Object.ts +++ b/src/Schema/Output/types/Object.ts @@ -1,15 +1,9 @@ -import { Output } from '../Field/Type.js' -import type { Scalar } from './_.js' -import type { Enum } from './Enum.js' - -export type Fields = Record< - string, - Output.Field | Output.Nullable | Object$2 | Enum | Scalar.Any> -> - -export type ObjectFields = { - __typename: Output.Field -} & Fields +import type { Field } from '../../_.js' +import { field } from '../../Field/Field.js' +import type { Hybrid } from '../../Hybrid/__.js' +import { __typename } from './__typename.js' +import type { List } from './List.js' +import type { Nullable } from './Nullable.js' export interface Object$2< $Name extends string = string, @@ -17,12 +11,12 @@ export interface Object$2< > { kind: 'Object' fields: { - __typename: Output.Field> + __typename: Field.Field<__typename<$Name>> } & $Fields } // Naming this "Object" breaks Vitest: https://github.com/vitest-dev/vitest/issues/5463 -export const Object$ = <$Name extends string, $Fields extends Record>( +export const Object$ = <$Name extends string, $Fields extends Record>( name: $Name, fields: $Fields, // eslint-disable-next-line @@ -30,9 +24,15 @@ export const Object$ = <$Name extends string, $Fields extends Record => ({ kind: `Object`, fields: { - __typename: Output.field(Output.__typename(name)), + __typename: field(__typename(name)), ...fields, }, }) export { Object$ as Object } + +type Fields = Record< + string, + // eslint-disable-next-line + Field.Field | Nullable | Object$2 | Hybrid.Enum | Hybrid.Scalar.Any> +> diff --git a/src/Schema/NamedType/Union.ts b/src/Schema/Output/types/Union.ts similarity index 100% rename from src/Schema/NamedType/Union.ts rename to src/Schema/Output/types/Union.ts diff --git a/src/Schema/Output/types/__typename.ts b/src/Schema/Output/types/__typename.ts new file mode 100644 index 000000000..3a7dc3428 --- /dev/null +++ b/src/Schema/Output/types/__typename.ts @@ -0,0 +1,6 @@ +export interface __typename<$Type extends string = string> { + kind: 'typename' + type: $Type +} + +export const __typename = <$Type extends string>(type: $Type): __typename<$Type> => ({ kind: `typename`, type }) diff --git a/src/Schema/_.ts b/src/Schema/_.ts index d8ec79685..fb193821b 100644 --- a/src/Schema/_.ts +++ b/src/Schema/_.ts @@ -1,3 +1,5 @@ -export * from './Field/_.js' -export { Index } from './Index.js' -export * as Named from './NamedType/_.js' +export { Index } from './core/Index.js' +export * as Named from './core/NamedType/_.js' +export * from './Field/__.js' +export * from './Input/__.js' +export * from './Output/__.js' diff --git a/src/Schema/__.ts b/src/Schema/__.ts index a346e7390..ae38428c6 100644 --- a/src/Schema/__.ts +++ b/src/Schema/__.ts @@ -1,4 +1,2 @@ export * as Schema from './_.js' -export { Args, As, Field, Input, Output } from './Field/__.js' -export { Index } from './Index.js' -export * from './NamedType/_.js' +export * from './_.js' diff --git a/src/Schema/core/Index.ts b/src/Schema/core/Index.ts new file mode 100644 index 000000000..dc166a149 --- /dev/null +++ b/src/Schema/core/Index.ts @@ -0,0 +1,12 @@ +import type { Output } from '../Output/__.js' + +export interface Index { + Root: { + Query: null | Output.Object$2 + Mutation: null | Output.Object$2 + Subscription: null | Output.Object$2 + } + objects: Record + // todo unused? + unions: Record +} diff --git a/src/Schema/NamedType/NamedType.test-d.ts b/src/Schema/core/NamedType/NamedType.test-d.ts similarity index 100% rename from src/Schema/NamedType/NamedType.test-d.ts rename to src/Schema/core/NamedType/NamedType.test-d.ts diff --git a/src/Schema/NamedType/NamedType.ts b/src/Schema/core/NamedType/NamedType.ts similarity index 52% rename from src/Schema/NamedType/NamedType.ts rename to src/Schema/core/NamedType/NamedType.ts index f8337a736..09a761869 100644 --- a/src/Schema/NamedType/NamedType.ts +++ b/src/Schema/core/NamedType/NamedType.ts @@ -1,14 +1,4 @@ -import type { Digit, Letter } from '../../lib/prelude.js' -import type { Enum } from './Enum.js' -import type { InputObject } from './InputObjet.js' -import type { Interface } from './Interface.js' -import type { Object$2 } from './Object.js' -import type { Scalar } from './Scalar/_.js' -import type { Union } from './Union.js' - -export type AnyOutput = Interface | Enum | Object$2 | Scalar.Any | Union -export type AnyInput = Enum | Scalar.Any | InputObject -export type Any = AnyOutput | AnyInput +import type { Digit, Letter } from '../../../lib/prelude.js' /** * @see http://spec.graphql.org/draft/#sec-Names diff --git a/src/Schema/core/NamedType/_.ts b/src/Schema/core/NamedType/_.ts new file mode 100644 index 000000000..a5943c577 --- /dev/null +++ b/src/Schema/core/NamedType/_.ts @@ -0,0 +1 @@ +export * from './NamedType.js' diff --git a/src/Schema/NamedType/__.ts b/src/Schema/core/NamedType/__.ts similarity index 100% rename from src/Schema/NamedType/__.ts rename to src/Schema/core/NamedType/__.ts diff --git a/src/Schema/core/helpers.ts b/src/Schema/core/helpers.ts new file mode 100644 index 000000000..9b6e7bd26 --- /dev/null +++ b/src/Schema/core/helpers.ts @@ -0,0 +1,20 @@ +export type MaybeThunk<$Type> = $Type | Thunk<$Type> + +export type Thunk<$Type> = () => $Type + +export const readMaybeThunk = (maybeThunk: MaybeThunk): T => + // @ts-expect-error fixme + typeof maybeThunk === `function` ? maybeThunk() : maybeThunk + +export const buildTimeOnly: any = undefined + +export namespace Base { + export interface Nullable<$Type> { + kind: 'nullable' + type: $Type + } + export interface List<$Type> { + kind: 'list' + type: $Type + } +} diff --git a/src/entrypoints/alpha/scalars.ts b/src/entrypoints/alpha/scalars.ts index 554b6a894..237e44a57 100644 --- a/src/entrypoints/alpha/scalars.ts +++ b/src/entrypoints/alpha/scalars.ts @@ -1 +1 @@ -export * from '../../Schema/NamedType/Scalar/Scalar.js' +export * from '../../Schema/Hybrid/Scalar/Scalar.js' diff --git a/tests/ts/_/schema/customScalarCodecs.ts b/tests/ts/_/schema/customScalarCodecs.ts index 037fc63eb..3d5f817a9 100644 --- a/tests/ts/_/schema/customScalarCodecs.ts +++ b/tests/ts/_/schema/customScalarCodecs.ts @@ -1,5 +1,5 @@ import { Scalar } from '../../../../src/Schema/__.js' -import type { Codec } from '../../../../src/Schema/NamedType/Scalar/codec.js' +import type { Codec } from '../../../../src/Schema/Hybrid/Scalar/codec.js' export const Date = Scalar.scalar<'Date', Codec>(`Date`, { encode: value => value.getTime(), diff --git a/tests/ts/_/schema/generated/Scalar.ts b/tests/ts/_/schema/generated/Scalar.ts index 77463f759..1649339d4 100644 --- a/tests/ts/_/schema/generated/Scalar.ts +++ b/tests/ts/_/schema/generated/Scalar.ts @@ -6,5 +6,5 @@ declare global { } } -export * from '../../../../../src/Schema/NamedType/Scalar/Scalar.js' +export * from '../../../../../src/Schema/Hybrid/Scalar/Scalar.js' export * from '../customScalarCodecs.js' From 06d80d35e04c51cb86d9fe4b9a2ceb7e9b87d504 Mon Sep 17 00:00:00 2001 From: Jason Kuhrt Date: Thu, 11 Apr 2024 23:37:27 -0400 Subject: [PATCH 02/10] work --- src/ResultSet/ResultSet.ts | 34 +++++------ src/Schema/Args.ts | 14 +++++ src/Schema/Field.ts | 35 ++++++++++++ src/Schema/Field/Field.ts | 49 ---------------- src/Schema/Field/__.ts | 1 - src/Schema/Hybrid/_.ts | 4 +- src/Schema/Hybrid/{ => types}/Enum.ts | 0 .../Hybrid/{ => types}/Scalar/Scalar.ts | 0 src/Schema/Hybrid/{ => types}/Scalar/_.ts | 0 src/Schema/Hybrid/{ => types}/Scalar/codec.ts | 0 .../{ => types}/Scalar/nativeScalarCodecs.ts | 0 src/Schema/Input/Input.ts | 17 ++---- src/Schema/Input/typeGroups.ts | 2 +- .../types/{InputObjet.ts => InputObject.ts} | 0 src/Schema/Input/types/Nullable.ts | 11 ++++ src/Schema/Output/Output.ts | 1 + src/Schema/Output/typeGroups.ts | 2 +- src/Schema/Output/types/Interface.ts | 6 +- src/Schema/Output/types/Object.ts | 11 ++-- src/Schema/_.ts | 14 ++++- .../{NamedType => Named}/NamedType.test-d.ts | 0 .../core/{NamedType => Named}/NamedType.ts | 0 src/Schema/core/{NamedType => Named}/_.ts | 0 src/Schema/core/Named/__.ts | 1 + src/Schema/core/NamedType/__.ts | 1 - src/SelectionSet/SelectionSet.ts | 56 +++++++++---------- src/client.ts | 12 ++-- src/entrypoints/alpha/scalars.ts | 2 +- src/lib/prelude.ts | 2 + tests/ts/_/schema/customScalarCodecs.ts | 2 +- tests/ts/_/schema/generated/Scalar.ts | 2 +- 31 files changed, 144 insertions(+), 135 deletions(-) create mode 100644 src/Schema/Args.ts create mode 100644 src/Schema/Field.ts delete mode 100644 src/Schema/Field/Field.ts delete mode 100644 src/Schema/Field/__.ts rename src/Schema/Hybrid/{ => types}/Enum.ts (100%) rename src/Schema/Hybrid/{ => types}/Scalar/Scalar.ts (100%) rename src/Schema/Hybrid/{ => types}/Scalar/_.ts (100%) rename src/Schema/Hybrid/{ => types}/Scalar/codec.ts (100%) rename src/Schema/Hybrid/{ => types}/Scalar/nativeScalarCodecs.ts (100%) rename src/Schema/Input/types/{InputObjet.ts => InputObject.ts} (100%) rename src/Schema/core/{NamedType => Named}/NamedType.test-d.ts (100%) rename src/Schema/core/{NamedType => Named}/NamedType.ts (100%) rename src/Schema/core/{NamedType => Named}/_.ts (100%) create mode 100644 src/Schema/core/Named/__.ts delete mode 100644 src/Schema/core/NamedType/__.ts diff --git a/src/ResultSet/ResultSet.ts b/src/ResultSet/ResultSet.ts index 23a290d76..1e647bd87 100644 --- a/src/ResultSet/ResultSet.ts +++ b/src/ResultSet/ResultSet.ts @@ -19,7 +19,7 @@ export type Subscription<$SelectionSetSubscription extends object, $Index extend SimplifyDeep, $Index>> // dprint-ignore -export type Object$<$SelectionSet, $Node extends Schema.Named.Object$2, $Index extends Schema.Index> = +export type Object$<$SelectionSet, $Node extends Schema.Output.Object$2, $Index extends Schema.Index> = SelectionSet.IsSelectScalarsWildcard<$SelectionSet> extends true /** @@ -27,7 +27,7 @@ export type Object$<$SelectionSet, $Node extends Schema.Named.Object$2, $Index e */ ? { - [$Key in keyof $Node['fields'] as $Node['fields'][$Key] extends Schema.Field.Field | {'typeUnwrapped':{kind:'Scalar'}} ? $Key : never]: + [$Key in keyof $Node['fields'] as $Node['fields'][$Key] extends Schema.Field | {'typeUnwrapped':{kind:'Scalar'}} ? $Key : never]: // eslint-disable-next-line // @ts-ignore infinite depth issue, can this be fixed? Field<$SelectionSet, Schema.Field.As<$Node['fields'][$Key]>, $Index> @@ -44,15 +44,15 @@ export type Object$<$SelectionSet, $Node extends Schema.Named.Object$2, $Index e }> // dprint-ignore -type Union<$SelectionSet, $Node extends Schema.Named.Union, $Index extends Schema.Index> = +type Union<$SelectionSet, $Node extends Schema.Output.Union, $Index extends Schema.Index> = OnTypeFragment<$SelectionSet,$Node['members'][number], $Index> // dprint-ignore -type Interface<$SelectionSet, $Node extends Schema.Named.Interface, $Index extends Schema.Index> = +type Interface<$SelectionSet, $Node extends Schema.Output.Interface, $Index extends Schema.Index> = OnTypeFragment<$SelectionSet, $Node['implementors'][number], $Index> // dprint-ignore -type OnTypeFragment<$SelectionSet, $Node extends Schema.Named.Object$2, $Index extends Schema.Index> = +type OnTypeFragment<$SelectionSet, $Node extends Schema.Output.Object$2, $Index extends Schema.Index> = $Node extends any // force distribution ? Object$< GetKeyOr<$SelectionSet, `on${Capitalize<$Node['fields']['__typename']['type']['type']>}`, {}> & SelectionSet.OmitOnTypeFragments<$SelectionSet>, @@ -62,7 +62,7 @@ type OnTypeFragment<$SelectionSet, $Node extends Schema.Named.Object$2, $Index e : never // dprint-ignore -type Field<$SelectionSet, $Field extends Schema.Field.Field, $Index extends Schema.Index> = +type Field<$SelectionSet, $Field extends Schema.Field, $Index extends Schema.Index> = $SelectionSet extends SelectionSet.Directive.Include.Negative | SelectionSet.Directive.Skip.Positive ? null : ( @@ -74,18 +74,18 @@ type Field<$SelectionSet, $Field extends Schema.Field.Field, $Index extends Sche // dprint-ignore type FieldType< $SelectionSet, - $Type extends Schema.Field.Type.Output.Any, + $Type extends Schema.Output.Any, $Index extends Schema.Index > =Simplify< - $Type extends Schema.Field.Type.Output.__typename ? $Value : - $Type extends Schema.Field.Type.Output.Nullable ? null | FieldType<$SelectionSet, $InnerType, $Index> : - $Type extends Schema.Field.Type.Output.List ? Array> : - $Type extends Schema.Named.Enum ? $Members[number] : - $Type extends Schema.Named.Scalar.Any ? ReturnType<$Type['codec']['decode']> : - $Type extends Schema.Named.Object$2 ? Object$<$SelectionSet,$Type,$Index> : - $Type extends Schema.Named.Interface ? Interface<$SelectionSet,$Type,$Index> : - $Type extends Schema.Named.Union ? Union<$SelectionSet,$Type,$Index> : - TSError<'FieldType', `Unknown type`, { $Type: $Type }> + $Type extends Schema.__typename ? $Value : + $Type extends Schema.Output.Nullable ? null | FieldType<$SelectionSet, $InnerType, $Index> : + $Type extends Schema.Output.List ? Array> : + $Type extends Schema.Enum ? $Members[number] : + $Type extends Schema.Scalar.Any ? ReturnType<$Type['codec']['decode']> : + $Type extends Schema.Object$2 ? Object$<$SelectionSet,$Type,$Index> : + $Type extends Schema.Interface ? Interface<$SelectionSet,$Type,$Index> : + $Type extends Schema.Union ? Union<$SelectionSet,$Type,$Index> : + TSError<'FieldType', `Unknown type`, { $Type: $Type }> > // dprint-ignore @@ -104,5 +104,5 @@ type FieldDirectiveSkip<$SelectionSet> = // dprint-ignore export namespace Errors { - export type UnknownFieldName<$FieldName extends string, $Object extends Schema.Named.Object$2> = TSError<'Object', `field "${$FieldName}" does not exist on object "${$Object['fields']['__typename']['type']['type']}"`> + export type UnknownFieldName<$FieldName extends string, $Object extends Schema.Object$2> = TSError<'Object', `field "${$FieldName}" does not exist on object "${$Object['fields']['__typename']['type']['type']}"`> } diff --git a/src/Schema/Args.ts b/src/Schema/Args.ts new file mode 100644 index 000000000..aaa8db9e3 --- /dev/null +++ b/src/Schema/Args.ts @@ -0,0 +1,14 @@ +import type { Nullable } from './Input/types/Nullable.js' + +export interface Args<$Fields extends any = any> { + allOptional: Exclude<$Fields[keyof $Fields], Nullable> extends never ? true : false + fields: $Fields +} + +export const Args = (fields: F): Args => { + return { + // @ts-expect-error + allOptional: false, + fields, + } +} diff --git a/src/Schema/Field.ts b/src/Schema/Field.ts new file mode 100644 index 000000000..7343e4912 --- /dev/null +++ b/src/Schema/Field.ts @@ -0,0 +1,35 @@ +import type { Args } from './Args.js' +import type { MaybeThunk } from './core/helpers.js' +import { buildTimeOnly } from './core/helpers.js' +// import type * as TypesHybrid from '../Hybrid/_.js' +import type { Output } from './Output/__.js' + +// export type Enum<$Args extends Args | null = null> = Field + +// export type Scalar<$Args extends Args | null = Args | null> = Field + +// export type String<$Args extends Args | null = null> = Field + +// export type Number<$Args extends Args | null = null> = Field + +// export type Boolean<$Args extends Args | null = null> = Field + +// export interface Args<$Fields extends Record = Record> { + +export type Field<$Type extends any = any, $Args extends Args | null = Args | null> = { + typeUnwrapped: Output.Unwrap<$Type> + type: $Type + args: $Args +} + +export const field = <$Type extends Output.Any, $Args extends null | Args = null>( + type: MaybeThunk<$Type>, + args: $Args = null as $Args, +): Field<$Type, $Args> => { + return { + typeUnwrapped: buildTimeOnly, // eslint-disable-line + // At type level "type" is not a thunk + type: type as any, // eslint-disable-line + args, + } +} diff --git a/src/Schema/Field/Field.ts b/src/Schema/Field/Field.ts deleted file mode 100644 index 266cb1443..000000000 --- a/src/Schema/Field/Field.ts +++ /dev/null @@ -1,49 +0,0 @@ -import type { MaybeThunk } from '../core/helpers.js' -import { buildTimeOnly } from '../core/helpers.js' -import type * as TypesHybrid from '../Hybrid/_.js' -import type { Nullable } from '../Input/types/Nullable.js' -import type { Output } from '../Output/__.js' - -export type As = T extends Field ? T : never - -export type Enum<$Args extends Args | null = null> = Field - -export type Scalar<$Args extends Args | null = Args | null> = Field - -export type String<$Args extends Args | null = null> = Field - -export type Number<$Args extends Args | null = null> = Field - -export type Boolean<$Args extends Args | null = null> = Field - -// export interface Args<$Fields extends Record = Record> { -export interface Args<$Fields extends any = any> { - allOptional: Exclude<$Fields[keyof $Fields], Nullable> extends never ? true : false - fields: $Fields -} - -export const Args = (fields: F): Args => { - return { - // @ts-expect-error - allOptional: false, - fields, - } -} - -export type Field<$Type extends any = any, $Args extends Args | null = Args | null> = { - typeUnwrapped: Output.Unwrap<$Type> - type: $Type - args: $Args -} - -export const field = <$Type extends Output.Any, $Args extends null | Args = null>( - type: MaybeThunk<$Type>, - args: $Args = null as $Args, -): Field<$Type, $Args> => { - return { - typeUnwrapped: buildTimeOnly, // eslint-disable-line - // At type level "type" is not a thunk - type: type as any, // eslint-disable-line - args, - } -} diff --git a/src/Schema/Field/__.ts b/src/Schema/Field/__.ts deleted file mode 100644 index 581873b2c..000000000 --- a/src/Schema/Field/__.ts +++ /dev/null @@ -1 +0,0 @@ -export * as Field from './Field.js' diff --git a/src/Schema/Hybrid/_.ts b/src/Schema/Hybrid/_.ts index 80a6c0668..ff6c57fe2 100644 --- a/src/Schema/Hybrid/_.ts +++ b/src/Schema/Hybrid/_.ts @@ -1,2 +1,2 @@ -export * from './Enum.js' -export * from './Scalar/_.js' +export * from './types/Enum.js' +export * from './types/Scalar/_.js' diff --git a/src/Schema/Hybrid/Enum.ts b/src/Schema/Hybrid/types/Enum.ts similarity index 100% rename from src/Schema/Hybrid/Enum.ts rename to src/Schema/Hybrid/types/Enum.ts diff --git a/src/Schema/Hybrid/Scalar/Scalar.ts b/src/Schema/Hybrid/types/Scalar/Scalar.ts similarity index 100% rename from src/Schema/Hybrid/Scalar/Scalar.ts rename to src/Schema/Hybrid/types/Scalar/Scalar.ts diff --git a/src/Schema/Hybrid/Scalar/_.ts b/src/Schema/Hybrid/types/Scalar/_.ts similarity index 100% rename from src/Schema/Hybrid/Scalar/_.ts rename to src/Schema/Hybrid/types/Scalar/_.ts diff --git a/src/Schema/Hybrid/Scalar/codec.ts b/src/Schema/Hybrid/types/Scalar/codec.ts similarity index 100% rename from src/Schema/Hybrid/Scalar/codec.ts rename to src/Schema/Hybrid/types/Scalar/codec.ts diff --git a/src/Schema/Hybrid/Scalar/nativeScalarCodecs.ts b/src/Schema/Hybrid/types/Scalar/nativeScalarCodecs.ts similarity index 100% rename from src/Schema/Hybrid/Scalar/nativeScalarCodecs.ts rename to src/Schema/Hybrid/types/Scalar/nativeScalarCodecs.ts diff --git a/src/Schema/Input/Input.ts b/src/Schema/Input/Input.ts index ef341a8b9..78d7f59a2 100644 --- a/src/Schema/Input/Input.ts +++ b/src/Schema/Input/Input.ts @@ -1,5 +1,9 @@ import type { Any } from './typeGroups.js' -import type { Nullable } from './types/Nullable.js' + +export * from './typeGroups.js' +export * from './types/InputObject.js' +export * from './types/List.js' +export * from './types/Nullable.js' export const field = <$Type extends Any>(type: $Type): Field<$Type> => { return { @@ -7,17 +11,6 @@ export const field = <$Type extends Any>(type: $Type): Field<$Type> => { } } -// dprint-ignore -type UnwrapNonNull<$Type> = - $Type extends Nullable ? UnwrapNonNull<$innerType> - : $Type - -export const unwrapNullable = <$Type extends Any>(type: $Type): UnwrapNonNull<$Type> => { - if (type.kind === `nullable`) return type.type - // @ts-expect-error fixme - return type -} - export type Field<$Type extends any = any> = { // typeUnwrapped: Type.Output.Unwrap<$Type> type: $Type diff --git a/src/Schema/Input/typeGroups.ts b/src/Schema/Input/typeGroups.ts index deb0a1b76..074dc55df 100644 --- a/src/Schema/Input/typeGroups.ts +++ b/src/Schema/Input/typeGroups.ts @@ -1,5 +1,5 @@ import type { Enum, Scalar } from '../__.js' -import type { InputObject } from './types/InputObjet.js' +import type { InputObject } from './types/InputObject.js' import type { List } from './types/List.js' import type { Nullable } from './types/Nullable.js' diff --git a/src/Schema/Input/types/InputObjet.ts b/src/Schema/Input/types/InputObject.ts similarity index 100% rename from src/Schema/Input/types/InputObjet.ts rename to src/Schema/Input/types/InputObject.ts diff --git a/src/Schema/Input/types/Nullable.ts b/src/Schema/Input/types/Nullable.ts index 9e3433d79..224afb64b 100644 --- a/src/Schema/Input/types/Nullable.ts +++ b/src/Schema/Input/types/Nullable.ts @@ -8,3 +8,14 @@ export const Nullable = <$InnerType extends Any>(type: MaybeThunk<$InnerType>): // at type level "type" is not a thunk type: type as any, // eslint-disable-line }) + +// dprint-ignore +type UnwrapNullable<$Type> = + $Type extends Nullable ? UnwrapNullable<$innerType> + : $Type + +export const unwrapNullable = <$Type extends Any>(type: $Type): UnwrapNullable<$Type> => { + if (type.kind === `nullable`) return type.type + // @ts-expect-error fixme + return type +} diff --git a/src/Schema/Output/Output.ts b/src/Schema/Output/Output.ts index a8c780f74..379486a54 100644 --- a/src/Schema/Output/Output.ts +++ b/src/Schema/Output/Output.ts @@ -5,6 +5,7 @@ import type { List } from './types/List.js' import type { Nullable } from './types/Nullable.js' export * from './typeGroups.js' +export * from './types/__typename.js' export * from './types/Interface.js' export * from './types/List.js' export * from './types/Nullable.js' diff --git a/src/Schema/Output/typeGroups.ts b/src/Schema/Output/typeGroups.ts index 35f28f709..40f0366b1 100644 --- a/src/Schema/Output/typeGroups.ts +++ b/src/Schema/Output/typeGroups.ts @@ -1,5 +1,5 @@ import type { Hybrid } from '../Hybrid/__.js' -import type { Enum } from '../Hybrid/Enum.js' +import type { Enum } from '../Hybrid/types/Enum.js' import type { __typename } from './types/__typename.js' import type { Interface } from './types/Interface.js' import type { List } from './types/List.js' diff --git a/src/Schema/Output/types/Interface.ts b/src/Schema/Output/types/Interface.ts index 681eec168..b4899db3d 100644 --- a/src/Schema/Output/types/Interface.ts +++ b/src/Schema/Output/types/Interface.ts @@ -1,9 +1,9 @@ -import type { Field } from '../../Field/__.js' +import type { Field } from '../../Field.js' import type { Object$2 } from './Object.js' export type Interface< $Name extends string = string, - $Fields extends Record = Record, + $Fields extends Record = Record, $Implementors extends [Object$2, ...Object$2[]] = [Object$2, ...Object$2[]], > = { kind: 'Interface' @@ -14,7 +14,7 @@ export type Interface< export const Interface = < $Name extends string, - $Fields extends Record, + $Fields extends Record, $Implementors extends [Object$2, ...Object$2[]], >( name: $Name, diff --git a/src/Schema/Output/types/Object.ts b/src/Schema/Output/types/Object.ts index 599e15529..276ad01fd 100644 --- a/src/Schema/Output/types/Object.ts +++ b/src/Schema/Output/types/Object.ts @@ -1,5 +1,5 @@ -import type { Field } from '../../_.js' -import { field } from '../../Field/Field.js' +import type { Field } from '../../Field.js' +import { field } from '../../Field.js' import type { Hybrid } from '../../Hybrid/__.js' import { __typename } from './__typename.js' import type { List } from './List.js' @@ -11,12 +11,12 @@ export interface Object$2< > { kind: 'Object' fields: { - __typename: Field.Field<__typename<$Name>> + __typename: Field<__typename<$Name>> } & $Fields } // Naming this "Object" breaks Vitest: https://github.com/vitest-dev/vitest/issues/5463 -export const Object$ = <$Name extends string, $Fields extends Record>( +export const Object$ = <$Name extends string, $Fields extends Record>( name: $Name, fields: $Fields, // eslint-disable-next-line @@ -33,6 +33,5 @@ export { Object$ as Object } type Fields = Record< string, - // eslint-disable-next-line - Field.Field | Nullable | Object$2 | Hybrid.Enum | Hybrid.Scalar.Any> + Field | Nullable | Object$2 | Hybrid.Enum | Hybrid.Scalar.Any> > diff --git a/src/Schema/_.ts b/src/Schema/_.ts index fb193821b..cb459e602 100644 --- a/src/Schema/_.ts +++ b/src/Schema/_.ts @@ -1,5 +1,13 @@ -export { Index } from './core/Index.js' -export * as Named from './core/NamedType/_.js' -export * from './Field/__.js' +export * from './Args.js' +export * from './core/Index.js' +export * from './core/Named/__.js' +export * from './Field.js' +export * from './Hybrid/types/Enum.js' +export * from './Hybrid/types/Scalar/_.js' export * from './Input/__.js' +export * from './Input/types/InputObject.js' export * from './Output/__.js' +export * from './Output/types/__typename.js' +export * from './Output/types/Interface.js' +export { Object$2 } from './Output/types/Object.js' +export * from './Output/types/Union.js' diff --git a/src/Schema/core/NamedType/NamedType.test-d.ts b/src/Schema/core/Named/NamedType.test-d.ts similarity index 100% rename from src/Schema/core/NamedType/NamedType.test-d.ts rename to src/Schema/core/Named/NamedType.test-d.ts diff --git a/src/Schema/core/NamedType/NamedType.ts b/src/Schema/core/Named/NamedType.ts similarity index 100% rename from src/Schema/core/NamedType/NamedType.ts rename to src/Schema/core/Named/NamedType.ts diff --git a/src/Schema/core/NamedType/_.ts b/src/Schema/core/Named/_.ts similarity index 100% rename from src/Schema/core/NamedType/_.ts rename to src/Schema/core/Named/_.ts diff --git a/src/Schema/core/Named/__.ts b/src/Schema/core/Named/__.ts new file mode 100644 index 000000000..07fafba48 --- /dev/null +++ b/src/Schema/core/Named/__.ts @@ -0,0 +1 @@ +export * as Named from './_.js' diff --git a/src/Schema/core/NamedType/__.ts b/src/Schema/core/NamedType/__.ts deleted file mode 100644 index 974d0f166..000000000 --- a/src/Schema/core/NamedType/__.ts +++ /dev/null @@ -1 +0,0 @@ -export * as NamedType from './_.js' diff --git a/src/SelectionSet/SelectionSet.ts b/src/SelectionSet/SelectionSet.ts index 8e7cf20a4..c4582c34a 100644 --- a/src/SelectionSet/SelectionSet.ts +++ b/src/SelectionSet/SelectionSet.ts @@ -1,30 +1,30 @@ /* eslint-disable @typescript-eslint/ban-types */ -import type { MaybeList, StringNonEmpty, Values } from '../lib/prelude.js' +import type { As, MaybeList, StringNonEmpty, Values } from '../lib/prelude.js' import type { TSError } from '../lib/TSError.js' import type { Schema } from '../Schema/__.js' -export type Query<$Index extends Schema.Index> = $Index['Root']['Query'] extends Schema.Named.Object$2 +export type Query<$Index extends Schema.Index> = $Index['Root']['Query'] extends Schema.Object$2 ? Object<$Index['Root']['Query'], $Index> : never -export type Mutation<$Index extends Schema.Index> = $Index['Root']['Mutation'] extends Schema.Named.Object$2 +export type Mutation<$Index extends Schema.Index> = $Index['Root']['Mutation'] extends Schema.Object$2 ? Object<$Index['Root']['Mutation'], $Index> : never -export type Subscription<$Index extends Schema.Index> = $Index['Root']['Subscription'] extends Schema.Named.Object$2 +export type Subscription<$Index extends Schema.Index> = $Index['Root']['Subscription'] extends Schema.Object$2 ? Object<$Index['Root']['Subscription'], $Index> : never // dprint-ignore type Object< - $Fields extends Schema.Named.Object$2, + $Fields extends Schema.Object$2, $Index extends Schema.Index, > = Fields<$Fields['fields'], $Index> // dprint-ignore type Fields< - $Fields extends Schema.Named.Fields, + $Fields extends Schema.Fields, $Index extends Schema.Index, > = & @@ -32,7 +32,7 @@ type Fields< [Key in keyof $Fields]?: // eslint-disable-next-line // @ts-ignore excessive deep error, fixme? - Field, $Index> + Field, $Index> } & /** @@ -43,7 +43,7 @@ type Fields< [ Key in keyof $Fields as `${keyof $Fields & string}_as_${StringNonEmpty}` ]?: - Field, $Index> + Field, $Index> } & /** @@ -65,7 +65,7 @@ export type IsSelectScalarsWildcard = SS extends { $scalars: ClientIndicator // dprint-ignore export type Field< - $Field extends Schema.Field.Field, + $Field extends Schema.Field, $Index extends Schema.Index, > = $Field['type']['kind'] extends 'typename' ? NoArgsIndicator : @@ -78,13 +78,13 @@ export type Field< $Field['typeUnwrapped']['kind'] extends 'Interface' ? Interface<$Field['typeUnwrapped'], $Index> : TSError<'SelectionSetField', '$Field case not handled', { $Field: $Field }> // dprint-ignore -type Arguments<$Field extends Schema.Field.Field> = -$Field['args'] extends Schema.Field.Args ? $Field['args']['allOptional'] extends true ? { $?: Args<$Field['args']> } : +type Arguments<$Field extends Schema.Field> = +$Field['args'] extends Schema.Args ? $Field['args']['allOptional'] extends true ? { $?: Args<$Field['args']> } : { $: Args<$Field['args']> } : {} // dprint-ignore -type Interface<$Node extends Schema.Named.Interface, $Index extends Schema.Index> = +type Interface<$Node extends Schema.Interface, $Index extends Schema.Index> = & InterfaceDistributed<$Node['implementors'][number], $Index> & Fields< & $Node['fields'] @@ -95,7 +95,7 @@ type Interface<$Node extends Schema.Named.Interface, $Index extends Schema.Index > // dprint-ignore -type InterfaceDistributed<$Node extends Schema.Named.Object$2, $Index extends Schema.Index> = +type InterfaceDistributed<$Node extends Schema.Object$2, $Index extends Schema.Index> = $Node extends any ? { [$typename in $Node['fields']['__typename']['type']['type'] as `on${Capitalize<$typename>}`]?: @@ -104,12 +104,12 @@ type InterfaceDistributed<$Node extends Schema.Named.Object$2, $Index extends Sc : never // dprint-ignore -type Union<$Node extends Schema.Named.Union, $Index extends Schema.Index> = +type Union<$Node extends Schema.Union, $Index extends Schema.Index> = & UnionDistributed<$Node['members'][number], $Index> & { __typename?: NoArgsIndicator } // dprint-ignore -type UnionDistributed<$Object extends Schema.Named.Object$2,$Index extends Schema.Index> = +type UnionDistributed<$Object extends Schema.Object$2,$Index extends Schema.Index> = $Object extends any ? { [$typename in $Object['fields']['__typename']['type']['type'] as `on${Capitalize<$typename>}`]?: @@ -217,36 +217,36 @@ export type OmitNegativeIndicators<$SelectionSet> = { export type NoArgsIndicator = ClientIndicator | FieldDirectives // dprint-ignore -export type Indicator<$Field extends Schema.Field.Field = Schema.Field.Field> = +export type Indicator<$Field extends Schema.Field = Schema.Field> = // $Field['args']['allOptional'] -$Field['args'] extends Schema.Field.Args ? $Field['args']['allOptional'] extends true +$Field['args'] extends Schema.Args ? $Field['args']['allOptional'] extends true ? ({ $?: Args<$Field['args']> } & FieldDirectives) | ClientIndicator : { $: Args<$Field['args']> } & FieldDirectives : NoArgsIndicator // dprint-ignore -export type Args<$Args extends Schema.Field.Args> = ArgFields<$Args['fields']> +export type Args<$Args extends Schema.Args> = ArgFields<$Args['fields']> -export type ArgFields<$ArgFields extends Schema.Named.InputObject['fields']> = +export type ArgFields<$ArgFields extends Schema.InputObject['fields']> = & { [ - Key in keyof $ArgFields as $ArgFields[Key] extends Schema.Field.Input.Nullable ? never : Key + Key in keyof $ArgFields as $ArgFields[Key] extends Schema.Input.Nullable ? never : Key ]: InferTypeInput<$ArgFields[Key]> } & { [ - Key in keyof $ArgFields as $ArgFields[Key] extends Schema.Field.Input.Nullable ? Key : never + Key in keyof $ArgFields as $ArgFields[Key] extends Schema.Input.Nullable ? Key : never ]?: null | InferTypeInput<$ArgFields[Key]> } // dprint-ignore -type InferTypeInput<$InputType extends Schema.Field.Input.Any> = - $InputType extends Schema.Field.Input.Nullable ? InferTypeInput<$InnerType> | null : - $InputType extends Schema.Field.Input.List ? InferTypeInput<$InnerType>[] : - $InputType extends Schema.Named.InputObject ? ArgFields<$Fields> : - $InputType extends Schema.Named.Enum ? $Members[number] : - $InputType extends Schema.Named.Scalar.Any ? ReturnType<$InputType['codec']['decode']> : - TSError<'InferTypeInput', 'Unknown $InputType', { $InputType: $InputType }> // never +type InferTypeInput<$InputType extends Schema.Input.Any> = + $InputType extends Schema.Input.Nullable ? InferTypeInput<$InnerType> | null : + $InputType extends Schema.Input.List ? InferTypeInput<$InnerType>[] : + $InputType extends Schema.InputObject ? ArgFields<$Fields> : + $InputType extends Schema.Enum ? $Members[number] : + $InputType extends Schema.Scalar.Any ? ReturnType<$InputType['codec']['decode']> : + TSError<'InferTypeInput', 'Unknown $InputType', { $InputType: $InputType }> // never /** * @see https://spec.graphql.org/draft/#sec-Type-System.Directives.Built-in-Directives diff --git a/src/client.ts b/src/client.ts index 005dba7e0..685334acd 100644 --- a/src/client.ts +++ b/src/client.ts @@ -5,8 +5,7 @@ import type { Exact } from './lib/prelude.js' import type { ResultSet } from './ResultSet/__.js' import type { Object$2, Schema } from './Schema/__.js' import { Output } from './Schema/__.js' -import type { Input } from './Schema/Field/Type.js' -import { readMaybeThunk } from './Schema/Field/Type.js' +import { readMaybeThunk } from './Schema/core/helpers.js' import { SelectionSet } from './SelectionSet/__.js' import type { Args } from './SelectionSet/SelectionSet.js' import type { GraphQLDocumentObject } from './SelectionSet/toGraphQLDocumentString.js' @@ -112,7 +111,7 @@ const encodeCustomScalars = ( if (typeof fieldValue === `object` && `$` in fieldValue) { const field = input.index.fields[fieldName] if (!field?.args) throw new Error(`Field has no args: ${fieldName}`) - if (!field) throw new Error(`Field not found: ${fieldName}`) // eslint-disable-line + if (!field) throw new Error(`Field not found: ${fieldName}`) // @ts-expect-error fixme fieldValue.$ = encodeCustomScalarsArgs(field.args, fieldValue.$) return [fieldName, fieldValue] @@ -133,7 +132,7 @@ const encodeCustomScalarsArgs = (indexArgs: Args, valueArgs: SSValue.Args2) ) } -const encodeCustomScalarsArgValue = (indexArg: Input.Any, argValue: null | SSValue.Arg): any => { +const encodeCustomScalarsArgValue = (indexArg: Schema.Input.Any, argValue: null | SSValue.Arg): any => { if (argValue === null) return null // todo could check if index agrees is nullable. if (indexArg.kind === `nullable`) { return encodeCustomScalarsArgValue(indexArg.type, argValue) @@ -175,10 +174,7 @@ const decodeCustomScalarValue = ( if (fieldValue === null) return null const indexTypeDethunked = readMaybeThunk(indexType) - const typeWithoutNonNull = Output.unwrapNonNull(indexTypeDethunked) as - | Output.Named - | Output.List - | Output.__typename + const typeWithoutNonNull = Output.unwrapNonNull(indexTypeDethunked) if (typeWithoutNonNull.kind === `list`) { assertArray(fieldValue) diff --git a/src/entrypoints/alpha/scalars.ts b/src/entrypoints/alpha/scalars.ts index 237e44a57..c4eda2861 100644 --- a/src/entrypoints/alpha/scalars.ts +++ b/src/entrypoints/alpha/scalars.ts @@ -1 +1 @@ -export * from '../../Schema/Hybrid/Scalar/Scalar.js' +export * from '../../Schema/Hybrid/types/Scalar/Scalar.js' diff --git a/src/lib/prelude.ts b/src/lib/prelude.ts index c9a92ed0f..cd1a05bfd 100644 --- a/src/lib/prelude.ts +++ b/src/lib/prelude.ts @@ -186,3 +186,5 @@ export const fileExists = async (path: string) => { }), ) } + +export type As = U extends T ? U : never diff --git a/tests/ts/_/schema/customScalarCodecs.ts b/tests/ts/_/schema/customScalarCodecs.ts index 3d5f817a9..cda91956c 100644 --- a/tests/ts/_/schema/customScalarCodecs.ts +++ b/tests/ts/_/schema/customScalarCodecs.ts @@ -1,5 +1,5 @@ import { Scalar } from '../../../../src/Schema/__.js' -import type { Codec } from '../../../../src/Schema/Hybrid/Scalar/codec.js' +import type { Codec } from '../../../../src/Schema/Hybrid/types/Scalar/codec.js' export const Date = Scalar.scalar<'Date', Codec>(`Date`, { encode: value => value.getTime(), diff --git a/tests/ts/_/schema/generated/Scalar.ts b/tests/ts/_/schema/generated/Scalar.ts index 1649339d4..e0ae1e408 100644 --- a/tests/ts/_/schema/generated/Scalar.ts +++ b/tests/ts/_/schema/generated/Scalar.ts @@ -6,5 +6,5 @@ declare global { } } -export * from '../../../../../src/Schema/Hybrid/Scalar/Scalar.js' +export * from '../../../../../src/Schema/Hybrid/types/Scalar/Scalar.js' export * from '../customScalarCodecs.js' From 3832ad4efe2f973b55b85caa149ea9e802b7d1bd Mon Sep 17 00:00:00 2001 From: Jason Kuhrt Date: Thu, 11 Apr 2024 23:54:15 -0400 Subject: [PATCH 03/10] work --- src/Schema/Field.ts | 13 -- src/Schema/Hybrid/_.ts | 2 +- .../Hybrid/types/Scalar/{_.ts => __.ts} | 0 src/Schema/_.ts | 4 +- src/SelectionSet/SelectionSet.ts | 5 +- .../__snapshots__/files.test.ts.snap | 211 +++++++++--------- src/generator/code/schemaRuntime.ts | 30 +-- src/generator/files.test.ts | 2 +- tests/ts/_/schema/generated/SchemaRuntime.ts | 209 +++++++++-------- 9 files changed, 225 insertions(+), 251 deletions(-) rename src/Schema/Hybrid/types/Scalar/{_.ts => __.ts} (100%) diff --git a/src/Schema/Field.ts b/src/Schema/Field.ts index 7343e4912..292069c68 100644 --- a/src/Schema/Field.ts +++ b/src/Schema/Field.ts @@ -1,21 +1,8 @@ import type { Args } from './Args.js' import type { MaybeThunk } from './core/helpers.js' import { buildTimeOnly } from './core/helpers.js' -// import type * as TypesHybrid from '../Hybrid/_.js' import type { Output } from './Output/__.js' -// export type Enum<$Args extends Args | null = null> = Field - -// export type Scalar<$Args extends Args | null = Args | null> = Field - -// export type String<$Args extends Args | null = null> = Field - -// export type Number<$Args extends Args | null = null> = Field - -// export type Boolean<$Args extends Args | null = null> = Field - -// export interface Args<$Fields extends Record = Record> { - export type Field<$Type extends any = any, $Args extends Args | null = Args | null> = { typeUnwrapped: Output.Unwrap<$Type> type: $Type diff --git a/src/Schema/Hybrid/_.ts b/src/Schema/Hybrid/_.ts index ff6c57fe2..d2818dc2b 100644 --- a/src/Schema/Hybrid/_.ts +++ b/src/Schema/Hybrid/_.ts @@ -1,2 +1,2 @@ export * from './types/Enum.js' -export * from './types/Scalar/_.js' +export * from './types/Scalar/__.js' diff --git a/src/Schema/Hybrid/types/Scalar/_.ts b/src/Schema/Hybrid/types/Scalar/__.ts similarity index 100% rename from src/Schema/Hybrid/types/Scalar/_.ts rename to src/Schema/Hybrid/types/Scalar/__.ts diff --git a/src/Schema/_.ts b/src/Schema/_.ts index cb459e602..d8751cdd3 100644 --- a/src/Schema/_.ts +++ b/src/Schema/_.ts @@ -3,11 +3,11 @@ export * from './core/Index.js' export * from './core/Named/__.js' export * from './Field.js' export * from './Hybrid/types/Enum.js' -export * from './Hybrid/types/Scalar/_.js' +export * from './Hybrid/types/Scalar/__.js' export * from './Input/__.js' export * from './Input/types/InputObject.js' export * from './Output/__.js' export * from './Output/types/__typename.js' export * from './Output/types/Interface.js' -export { Object$2 } from './Output/types/Object.js' +export { Object$, Object$2 } from './Output/types/Object.js' export * from './Output/types/Union.js' diff --git a/src/SelectionSet/SelectionSet.ts b/src/SelectionSet/SelectionSet.ts index c4582c34a..6cf93daad 100644 --- a/src/SelectionSet/SelectionSet.ts +++ b/src/SelectionSet/SelectionSet.ts @@ -23,10 +23,7 @@ type Object< > = Fields<$Fields['fields'], $Index> // dprint-ignore -type Fields< - $Fields extends Schema.Fields, - $Index extends Schema.Index, -> = +type Fields<$Fields extends Record>, $Index extends Schema.Index> = & { [Key in keyof $Fields]?: diff --git a/src/generator/__snapshots__/files.test.ts.snap b/src/generator/__snapshots__/files.test.ts.snap index 8b5ae4edb..dec2ebe3f 100644 --- a/src/generator/__snapshots__/files.test.ts.snap +++ b/src/generator/__snapshots__/files.test.ts.snap @@ -261,161 +261,156 @@ declare global { } } -export * from '../../../../../src/Schema/NamedType/Scalar/Scalar.js' +export * from '../../../../../src/Schema/Hybrid/types/Scalar/Scalar.js' export * from '../customScalarCodecs.js' " `; exports[`generates types from GraphQL SDL file 3`] = ` -"import * as _ from '../../../../../src/Schema/__.js' +"import * as $ from '../../../../../src/Schema/__.js' import * as $Scalar from './Scalar.js' -export const ABCEnum = _.Enum(\`ABCEnum\`, [\`A\`, \`B\`, \`C\`]) +export const ABCEnum = $.Enum(\`ABCEnum\`, [\`A\`, \`B\`, \`C\`]) -export const InputObject = _.InputObject(\`InputObject\`, { - id: _.Input.field(_.Input.Nullable($Scalar.ID)), - idRequired: _.Input.field($Scalar.ID), - date: _.Input.field(_.Input.Nullable($Scalar.Date)), - dateRequired: _.Input.field($Scalar.Date), +export const InputObject = $.InputObject(\`InputObject\`, { + id: $.Input.field($.Input.Nullable($Scalar.ID)), + idRequired: $.Input.field($Scalar.ID), + date: $.Input.field($.Input.Nullable($Scalar.Date)), + dateRequired: $.Input.field($Scalar.Date), }) -export const DateObject1 = _.Object$(\`DateObject1\`, { - date1: _.Output.field(_.Output.Nullable($Scalar.Date)), +export const DateObject1 = $.Object$(\`DateObject1\`, { + date1: $.field($.Output.Nullable($Scalar.Date)), }) -export const DateObject2 = _.Object$(\`DateObject2\`, { - date2: _.Output.field(_.Output.Nullable($Scalar.Date)), +export const DateObject2 = $.Object$(\`DateObject2\`, { + date2: $.field($.Output.Nullable($Scalar.Date)), }) -export const Foo = _.Object$(\`Foo\`, { - id: _.Output.field(_.Output.Nullable($Scalar.ID)), +export const Foo = $.Object$(\`Foo\`, { + id: $.field($.Output.Nullable($Scalar.ID)), }) -export const Bar = _.Object$(\`Bar\`, { - int: _.Output.field(_.Output.Nullable($Scalar.Int)), +export const Bar = $.Object$(\`Bar\`, { + int: $.field($.Output.Nullable($Scalar.Int)), }) -export const ObjectNested = _.Object$(\`ObjectNested\`, { - id: _.Output.field(_.Output.Nullable($Scalar.ID)), - object: _.Output.field(_.Output.Nullable(() => Object1)), +export const ObjectNested = $.Object$(\`ObjectNested\`, { + id: $.field($.Output.Nullable($Scalar.ID)), + object: $.field($.Output.Nullable(() => Object1)), }) -export const lowerCaseObject = _.Object$(\`lowerCaseObject\`, { - id: _.Output.field(_.Output.Nullable($Scalar.ID)), +export const lowerCaseObject = $.Object$(\`lowerCaseObject\`, { + id: $.field($.Output.Nullable($Scalar.ID)), }) -export const lowerCaseObject2 = _.Object$(\`lowerCaseObject2\`, { - int: _.Output.field(_.Output.Nullable($Scalar.Int)), +export const lowerCaseObject2 = $.Object$(\`lowerCaseObject2\`, { + int: $.field($.Output.Nullable($Scalar.Int)), }) -export const Object1 = _.Object$(\`Object1\`, { - string: _.Output.field(_.Output.Nullable($Scalar.String)), - int: _.Output.field(_.Output.Nullable($Scalar.Int)), - float: _.Output.field(_.Output.Nullable($Scalar.Float)), - boolean: _.Output.field(_.Output.Nullable($Scalar.Boolean)), - id: _.Output.field(_.Output.Nullable($Scalar.ID)), +export const Object1 = $.Object$(\`Object1\`, { + string: $.field($.Output.Nullable($Scalar.String)), + int: $.field($.Output.Nullable($Scalar.Int)), + float: $.field($.Output.Nullable($Scalar.Float)), + boolean: $.field($.Output.Nullable($Scalar.Boolean)), + id: $.field($.Output.Nullable($Scalar.ID)), }) -export const Object1ImplementingInterface = _.Object$(\`Object1ImplementingInterface\`, { - id: _.Output.field(_.Output.Nullable($Scalar.ID)), - int: _.Output.field(_.Output.Nullable($Scalar.Int)), +export const Object1ImplementingInterface = $.Object$(\`Object1ImplementingInterface\`, { + id: $.field($.Output.Nullable($Scalar.ID)), + int: $.field($.Output.Nullable($Scalar.Int)), }) -export const Object2ImplementingInterface = _.Object$(\`Object2ImplementingInterface\`, { - id: _.Output.field(_.Output.Nullable($Scalar.ID)), - boolean: _.Output.field(_.Output.Nullable($Scalar.Boolean)), +export const Object2ImplementingInterface = $.Object$(\`Object2ImplementingInterface\`, { + id: $.field($.Output.Nullable($Scalar.ID)), + boolean: $.field($.Output.Nullable($Scalar.Boolean)), }) -export const DateUnion = _.Union(\`DateUnion\`, [DateObject1, DateObject2]) +export const DateUnion = $.Union(\`DateUnion\`, [DateObject1, DateObject2]) -export const FooBarUnion = _.Union(\`FooBarUnion\`, [Foo, Bar]) +export const FooBarUnion = $.Union(\`FooBarUnion\`, [Foo, Bar]) -export const lowerCaseUnion = _.Union(\`lowerCaseUnion\`, [lowerCaseObject, lowerCaseObject2]) +export const lowerCaseUnion = $.Union(\`lowerCaseUnion\`, [lowerCaseObject, lowerCaseObject2]) -export const DateInterface1 = _.Interface( - \`DateInterface1\`, - { date1: _.Output.field(_.Output.Nullable($Scalar.Date)) }, - [DateObject1], -) -export const Interface = _.Interface(\`Interface\`, { id: _.Output.field(_.Output.Nullable($Scalar.ID)) }, [ +export const DateInterface1 = $.Interface(\`DateInterface1\`, { date1: $.field($.Output.Nullable($Scalar.Date)) }, [ + DateObject1, +]) +export const Interface = $.Interface(\`Interface\`, { id: $.field($.Output.Nullable($Scalar.ID)) }, [ Object1ImplementingInterface, Object2ImplementingInterface, ]) -export const Query = _.Object$(\`Query\`, { - date: _.Output.field(_.Output.Nullable($Scalar.Date)), - dateNonNull: _.Output.field($Scalar.Date), - dateList: _.Output.field(_.Output.Nullable(_.Output.List(_.Output.Nullable($Scalar.Date)))), - dateObject1: _.Output.field(_.Output.Nullable(() => DateObject1)), - dateUnion: _.Output.field(_.Output.Nullable(() => DateUnion)), - dateInterface1: _.Output.field(_.Output.Nullable(() => DateInterface1)), - dateListNonNull: _.Output.field(_.Output.List($Scalar.Date)), - dateArg: _.Output.field(_.Output.Nullable($Scalar.Date), _.Args({ date: _.Input.Nullable($Scalar.Date) })), - dateArgNonNull: _.Output.field(_.Output.Nullable($Scalar.Date), _.Args({ date: $Scalar.Date })), - dateArgList: _.Output.field( - _.Output.Nullable($Scalar.Date), - _.Args({ date: _.Input.Nullable(_.Input.List(_.Input.Nullable($Scalar.Date))) }), - ), - dateArgNonNullList: _.Output.field( - _.Output.Nullable($Scalar.Date), - _.Args({ date: _.Input.List(_.Input.Nullable($Scalar.Date)) }), +export const Query = $.Object$(\`Query\`, { + date: $.field($.Output.Nullable($Scalar.Date)), + dateNonNull: $.field($Scalar.Date), + dateList: $.field($.Output.Nullable($.Output.List($.Output.Nullable($Scalar.Date)))), + dateObject1: $.field($.Output.Nullable(() => DateObject1)), + dateUnion: $.field($.Output.Nullable(() => DateUnion)), + dateInterface1: $.field($.Output.Nullable(() => DateInterface1)), + dateListNonNull: $.field($.Output.List($Scalar.Date)), + dateArg: $.field($.Output.Nullable($Scalar.Date), $.Args({ date: $.Input.Nullable($Scalar.Date) })), + dateArgNonNull: $.field($.Output.Nullable($Scalar.Date), $.Args({ date: $Scalar.Date })), + dateArgList: $.field( + $.Output.Nullable($Scalar.Date), + $.Args({ date: $.Input.Nullable($.Input.List($.Input.Nullable($Scalar.Date))) }), ), - dateArgNonNullListNonNull: _.Output.field( - _.Output.Nullable($Scalar.Date), - _.Args({ date: _.Input.List($Scalar.Date) }), + dateArgNonNullList: $.field( + $.Output.Nullable($Scalar.Date), + $.Args({ date: $.Input.List($.Input.Nullable($Scalar.Date)) }), ), - dateArgInputObject: _.Output.field(_.Output.Nullable($Scalar.Date), _.Args({ input: _.Input.Nullable(InputObject) })), - interface: _.Output.field(_.Output.Nullable(() => Interface)), - id: _.Output.field(_.Output.Nullable($Scalar.ID)), - idNonNull: _.Output.field($Scalar.ID), - string: _.Output.field(_.Output.Nullable($Scalar.String)), - stringWithRequiredArg: _.Output.field(_.Output.Nullable($Scalar.String), _.Args({ string: $Scalar.String })), - stringWithArgs: _.Output.field( - _.Output.Nullable($Scalar.String), - _.Args({ - string: _.Input.Nullable($Scalar.String), - int: _.Input.Nullable($Scalar.Int), - float: _.Input.Nullable($Scalar.Float), - boolean: _.Input.Nullable($Scalar.Boolean), - id: _.Input.Nullable($Scalar.ID), + dateArgNonNullListNonNull: $.field($.Output.Nullable($Scalar.Date), $.Args({ date: $.Input.List($Scalar.Date) })), + dateArgInputObject: $.field($.Output.Nullable($Scalar.Date), $.Args({ input: $.Input.Nullable(InputObject) })), + interface: $.field($.Output.Nullable(() => Interface)), + id: $.field($.Output.Nullable($Scalar.ID)), + idNonNull: $.field($Scalar.ID), + string: $.field($.Output.Nullable($Scalar.String)), + stringWithRequiredArg: $.field($.Output.Nullable($Scalar.String), $.Args({ string: $Scalar.String })), + stringWithArgs: $.field( + $.Output.Nullable($Scalar.String), + $.Args({ + string: $.Input.Nullable($Scalar.String), + int: $.Input.Nullable($Scalar.Int), + float: $.Input.Nullable($Scalar.Float), + boolean: $.Input.Nullable($Scalar.Boolean), + id: $.Input.Nullable($Scalar.ID), }), ), - stringWithArgEnum: _.Output.field(_.Output.Nullable($Scalar.String), _.Args({ ABCEnum: _.Input.Nullable(ABCEnum) })), - stringWithListArg: _.Output.field( - _.Output.Nullable($Scalar.String), - _.Args({ ints: _.Input.Nullable(_.Input.List(_.Input.Nullable($Scalar.Int))) }), + stringWithArgEnum: $.field($.Output.Nullable($Scalar.String), $.Args({ ABCEnum: $.Input.Nullable(ABCEnum) })), + stringWithListArg: $.field( + $.Output.Nullable($Scalar.String), + $.Args({ ints: $.Input.Nullable($.Input.List($.Input.Nullable($Scalar.Int))) }), ), - stringWithListArgRequired: _.Output.field( - _.Output.Nullable($Scalar.String), - _.Args({ ints: _.Input.List(_.Input.Nullable($Scalar.Int)) }), + stringWithListArgRequired: $.field( + $.Output.Nullable($Scalar.String), + $.Args({ ints: $.Input.List($.Input.Nullable($Scalar.Int)) }), ), - stringWithArgInputObject: _.Output.field( - _.Output.Nullable($Scalar.String), - _.Args({ input: _.Input.Nullable(InputObject) }), + stringWithArgInputObject: $.field( + $.Output.Nullable($Scalar.String), + $.Args({ input: $.Input.Nullable(InputObject) }), ), - stringWithArgInputObjectRequired: _.Output.field(_.Output.Nullable($Scalar.String), _.Args({ input: InputObject })), - listListIntNonNull: _.Output.field(_.Output.List(_.Output.List($Scalar.Int))), - listListInt: _.Output.field( - _.Output.Nullable(_.Output.List(_.Output.Nullable(_.Output.List(_.Output.Nullable($Scalar.Int))))), + stringWithArgInputObjectRequired: $.field($.Output.Nullable($Scalar.String), $.Args({ input: InputObject })), + listListIntNonNull: $.field($.Output.List($.Output.List($Scalar.Int))), + listListInt: $.field( + $.Output.Nullable($.Output.List($.Output.Nullable($.Output.List($.Output.Nullable($Scalar.Int))))), ), - listInt: _.Output.field(_.Output.Nullable(_.Output.List(_.Output.Nullable($Scalar.Int)))), - listIntNonNull: _.Output.field(_.Output.List($Scalar.Int)), - object: _.Output.field(_.Output.Nullable(() => Object1)), - objectNonNull: _.Output.field(() => Object1), - objectNested: _.Output.field(_.Output.Nullable(() => ObjectNested)), - objectWithArgs: _.Output.field( - _.Output.Nullable(() => Object1), - _.Args({ - string: _.Input.Nullable($Scalar.String), - int: _.Input.Nullable($Scalar.Int), - float: _.Input.Nullable($Scalar.Float), - boolean: _.Input.Nullable($Scalar.Boolean), - id: _.Input.Nullable($Scalar.ID), + listInt: $.field($.Output.Nullable($.Output.List($.Output.Nullable($Scalar.Int)))), + listIntNonNull: $.field($.Output.List($Scalar.Int)), + object: $.field($.Output.Nullable(() => Object1)), + objectNonNull: $.field(() => Object1), + objectNested: $.field($.Output.Nullable(() => ObjectNested)), + objectWithArgs: $.field( + $.Output.Nullable(() => Object1), + $.Args({ + string: $.Input.Nullable($Scalar.String), + int: $.Input.Nullable($Scalar.Int), + float: $.Input.Nullable($Scalar.Float), + boolean: $.Input.Nullable($Scalar.Boolean), + id: $.Input.Nullable($Scalar.ID), }), ), - fooBarUnion: _.Output.field(_.Output.Nullable(() => FooBarUnion)), - abcEnum: _.Output.field(_.Output.Nullable(ABCEnum)), - lowerCaseUnion: _.Output.field(_.Output.Nullable(() => lowerCaseUnion)), + fooBarUnion: $.field($.Output.Nullable(() => FooBarUnion)), + abcEnum: $.field($.Output.Nullable(ABCEnum)), + lowerCaseUnion: $.field($.Output.Nullable(() => lowerCaseUnion)), }) export const $Index = { diff --git a/src/generator/code/schemaRuntime.ts b/src/generator/code/schemaRuntime.ts index 9dc92c873..1e4d364f5 100644 --- a/src/generator/code/schemaRuntime.ts +++ b/src/generator/code/schemaRuntime.ts @@ -29,7 +29,7 @@ export const generateRuntimeSchema = ( code.push( ` - import * as _ from '${config.libraryPaths.schema}' + import * as $ from '${config.libraryPaths.schema}' import * as $Scalar from './Scalar.js' `, ) @@ -60,10 +60,10 @@ const index = (config: Config) => { Subscription ${hasSubscription(config.typeMapByKind) ? `` : `:null`} }, objects: { - ${config.typeMapByKind.GraphQLObjectType.map(_ => _.name).join(`,\n`)}, + ${config.typeMapByKind.GraphQLObjectType.map(type => type.name).join(`,\n`)}, }, unions: { - ${config.typeMapByKind.GraphQLUnionType.map(_ => _.name).join(`,\n`)}, + ${config.typeMapByKind.GraphQLUnionType.map(type => type.name).join(`,\n`)}, } } ` @@ -72,7 +72,7 @@ const index = (config: Config) => { const union = (config: Config, type: GraphQLUnionType) => { // todo probably need thunks here const members = type.getTypes().map(t => t.name).join(`, `) - return `export const ${type.name} = _.Union(\`${type.name}\`, [${members}])\n` + return `export const ${type.name} = $.Union(\`${type.name}\`, [${members}])\n` } const interface$ = (config: Config, type: GraphQLInterfaceType) => { @@ -83,14 +83,14 @@ const interface$ = (config: Config, type: GraphQLInterfaceType) => { const fields = Object.values(type.getFields()).map((field) => { return `${field.name}: ${outputField(config, field)}` }).join(`,\n`) - return `export const ${type.name} = _.Interface(\`${type.name}\`, {${fields}}, [${implementors}])` + return `export const ${type.name} = $.Interface(\`${type.name}\`, {${fields}}, [${implementors}])` } const enum$ = (config: Config, type: GraphQLEnumType) => { const members = type.getValues().map((value) => { return `\`${value.name}\`` }).join(`, `) - return `export const ${type.name} = _.Enum(\`${type.name}\`, [${members}])` + return `export const ${type.name} = $.Enum(\`${type.name}\`, [${members}])` } const object = (config: Config, type: GraphQLObjectType) => { @@ -98,7 +98,7 @@ const object = (config: Config, type: GraphQLObjectType) => { return `${field.name}: ${outputField(config, field)}` }).join(`,\n`) return ` - export const ${type.name} = _.Object$(\`${type.name}\`, { + export const ${type.name} = $.Object$(\`${type.name}\`, { ${fields} }) ` @@ -109,7 +109,7 @@ const inputObject = (config: Config, type: GraphQLInputObjectType) => { `,\n`, ) return ` - export const ${type.name} = _.InputObject(\`${type.name}\`, { + export const ${type.name} = $.InputObject(\`${type.name}\`, { ${fields} }) ` @@ -117,18 +117,18 @@ const inputObject = (config: Config, type: GraphQLInputObjectType) => { const inputField = (config: Config, field: GraphQLInputField): string => { const type = buildType(`input`, config, field.type) - return `_.Input.field(${type})` + return `$.Input.field(${type})` } const outputField = (config: Config, field: AnyGraphQLOutputField): string => { const type = buildType(`output`, config, field.type) return field.args.length > 0 - ? `_.Output.field(${type}, ${renderArgs(config, field.args)})` - : `_.Output.field(${type})` + ? `$.field(${type}, ${renderArgs(config, field.args)})` + : `$.field(${type})` } const renderArgs = (config: Config, args: readonly GraphQLArgument[]) => { - return `_.Args({${args.map(arg => renderArg(config, arg)).join(`, `)}})` + return `$.Args({${args.map(arg => renderArg(config, arg)).join(`, `)}})` } const renderArg = (config: Config, arg: GraphQLArgument) => { @@ -161,14 +161,14 @@ const buildType = (direction: 'input' | 'output', config: Config, node: AnyClass const namedTypeReference = dispatchNamedType(config, nodeInner) const namedTypeCode = namedTypeReference return nullable - ? `_.${ns}.Nullable(${namedTypeCode})` + ? `$.${ns}.Nullable(${namedTypeCode})` : namedTypeCode } if (isListType(nodeInner)) { - const fieldType = `_.${ns}.List(${buildType(direction, config, nodeInner.ofType)})` as any as string + const fieldType = `$.${ns}.List(${buildType(direction, config, nodeInner.ofType)})` as any as string return nullable - ? `_.${ns}.Nullable(${fieldType})` + ? `$.${ns}.Nullable(${fieldType})` : fieldType } diff --git a/src/generator/files.test.ts b/src/generator/files.test.ts index 22d101a7e..7e81dfbfe 100644 --- a/src/generator/files.test.ts +++ b/src/generator/files.test.ts @@ -9,7 +9,7 @@ test(`generates types from GraphQL SDL file`, async () => { code: { libraryPaths: { schema: `../../../../../src/Schema/__.js`, - scalars: `../../../../../src/Schema/NamedType/Scalar/Scalar.js`, + scalars: `../../../../../src/Schema/Hybrid/types/Scalar/Scalar.js`, }, }, }) diff --git a/tests/ts/_/schema/generated/SchemaRuntime.ts b/tests/ts/_/schema/generated/SchemaRuntime.ts index 5d1a6e914..25a605712 100644 --- a/tests/ts/_/schema/generated/SchemaRuntime.ts +++ b/tests/ts/_/schema/generated/SchemaRuntime.ts @@ -1,152 +1,147 @@ -import * as _ from '../../../../../src/Schema/__.js' +import * as $ from '../../../../../src/Schema/__.js' import * as $Scalar from './Scalar.js' -export const ABCEnum = _.Enum(`ABCEnum`, [`A`, `B`, `C`]) +export const ABCEnum = $.Enum(`ABCEnum`, [`A`, `B`, `C`]) -export const InputObject = _.InputObject(`InputObject`, { - id: _.Input.field(_.Input.Nullable($Scalar.ID)), - idRequired: _.Input.field($Scalar.ID), - date: _.Input.field(_.Input.Nullable($Scalar.Date)), - dateRequired: _.Input.field($Scalar.Date), +export const InputObject = $.InputObject(`InputObject`, { + id: $.Input.field($.Input.Nullable($Scalar.ID)), + idRequired: $.Input.field($Scalar.ID), + date: $.Input.field($.Input.Nullable($Scalar.Date)), + dateRequired: $.Input.field($Scalar.Date), }) -export const DateObject1 = _.Object$(`DateObject1`, { - date1: _.Output.field(_.Output.Nullable($Scalar.Date)), +export const DateObject1 = $.Object$(`DateObject1`, { + date1: $.field($.Output.Nullable($Scalar.Date)), }) -export const DateObject2 = _.Object$(`DateObject2`, { - date2: _.Output.field(_.Output.Nullable($Scalar.Date)), +export const DateObject2 = $.Object$(`DateObject2`, { + date2: $.field($.Output.Nullable($Scalar.Date)), }) -export const Foo = _.Object$(`Foo`, { - id: _.Output.field(_.Output.Nullable($Scalar.ID)), +export const Foo = $.Object$(`Foo`, { + id: $.field($.Output.Nullable($Scalar.ID)), }) -export const Bar = _.Object$(`Bar`, { - int: _.Output.field(_.Output.Nullable($Scalar.Int)), +export const Bar = $.Object$(`Bar`, { + int: $.field($.Output.Nullable($Scalar.Int)), }) -export const ObjectNested = _.Object$(`ObjectNested`, { - id: _.Output.field(_.Output.Nullable($Scalar.ID)), - object: _.Output.field(_.Output.Nullable(() => Object1)), +export const ObjectNested = $.Object$(`ObjectNested`, { + id: $.field($.Output.Nullable($Scalar.ID)), + object: $.field($.Output.Nullable(() => Object1)), }) -export const lowerCaseObject = _.Object$(`lowerCaseObject`, { - id: _.Output.field(_.Output.Nullable($Scalar.ID)), +export const lowerCaseObject = $.Object$(`lowerCaseObject`, { + id: $.field($.Output.Nullable($Scalar.ID)), }) -export const lowerCaseObject2 = _.Object$(`lowerCaseObject2`, { - int: _.Output.field(_.Output.Nullable($Scalar.Int)), +export const lowerCaseObject2 = $.Object$(`lowerCaseObject2`, { + int: $.field($.Output.Nullable($Scalar.Int)), }) -export const Object1 = _.Object$(`Object1`, { - string: _.Output.field(_.Output.Nullable($Scalar.String)), - int: _.Output.field(_.Output.Nullable($Scalar.Int)), - float: _.Output.field(_.Output.Nullable($Scalar.Float)), - boolean: _.Output.field(_.Output.Nullable($Scalar.Boolean)), - id: _.Output.field(_.Output.Nullable($Scalar.ID)), +export const Object1 = $.Object$(`Object1`, { + string: $.field($.Output.Nullable($Scalar.String)), + int: $.field($.Output.Nullable($Scalar.Int)), + float: $.field($.Output.Nullable($Scalar.Float)), + boolean: $.field($.Output.Nullable($Scalar.Boolean)), + id: $.field($.Output.Nullable($Scalar.ID)), }) -export const Object1ImplementingInterface = _.Object$(`Object1ImplementingInterface`, { - id: _.Output.field(_.Output.Nullable($Scalar.ID)), - int: _.Output.field(_.Output.Nullable($Scalar.Int)), +export const Object1ImplementingInterface = $.Object$(`Object1ImplementingInterface`, { + id: $.field($.Output.Nullable($Scalar.ID)), + int: $.field($.Output.Nullable($Scalar.Int)), }) -export const Object2ImplementingInterface = _.Object$(`Object2ImplementingInterface`, { - id: _.Output.field(_.Output.Nullable($Scalar.ID)), - boolean: _.Output.field(_.Output.Nullable($Scalar.Boolean)), +export const Object2ImplementingInterface = $.Object$(`Object2ImplementingInterface`, { + id: $.field($.Output.Nullable($Scalar.ID)), + boolean: $.field($.Output.Nullable($Scalar.Boolean)), }) -export const DateUnion = _.Union(`DateUnion`, [DateObject1, DateObject2]) +export const DateUnion = $.Union(`DateUnion`, [DateObject1, DateObject2]) -export const FooBarUnion = _.Union(`FooBarUnion`, [Foo, Bar]) +export const FooBarUnion = $.Union(`FooBarUnion`, [Foo, Bar]) -export const lowerCaseUnion = _.Union(`lowerCaseUnion`, [lowerCaseObject, lowerCaseObject2]) +export const lowerCaseUnion = $.Union(`lowerCaseUnion`, [lowerCaseObject, lowerCaseObject2]) -export const DateInterface1 = _.Interface( - `DateInterface1`, - { date1: _.Output.field(_.Output.Nullable($Scalar.Date)) }, - [DateObject1], -) -export const Interface = _.Interface(`Interface`, { id: _.Output.field(_.Output.Nullable($Scalar.ID)) }, [ +export const DateInterface1 = $.Interface(`DateInterface1`, { date1: $.field($.Output.Nullable($Scalar.Date)) }, [ + DateObject1, +]) +export const Interface = $.Interface(`Interface`, { id: $.field($.Output.Nullable($Scalar.ID)) }, [ Object1ImplementingInterface, Object2ImplementingInterface, ]) -export const Query = _.Object$(`Query`, { - date: _.Output.field(_.Output.Nullable($Scalar.Date)), - dateNonNull: _.Output.field($Scalar.Date), - dateList: _.Output.field(_.Output.Nullable(_.Output.List(_.Output.Nullable($Scalar.Date)))), - dateObject1: _.Output.field(_.Output.Nullable(() => DateObject1)), - dateUnion: _.Output.field(_.Output.Nullable(() => DateUnion)), - dateInterface1: _.Output.field(_.Output.Nullable(() => DateInterface1)), - dateListNonNull: _.Output.field(_.Output.List($Scalar.Date)), - dateArg: _.Output.field(_.Output.Nullable($Scalar.Date), _.Args({ date: _.Input.Nullable($Scalar.Date) })), - dateArgNonNull: _.Output.field(_.Output.Nullable($Scalar.Date), _.Args({ date: $Scalar.Date })), - dateArgList: _.Output.field( - _.Output.Nullable($Scalar.Date), - _.Args({ date: _.Input.Nullable(_.Input.List(_.Input.Nullable($Scalar.Date))) }), - ), - dateArgNonNullList: _.Output.field( - _.Output.Nullable($Scalar.Date), - _.Args({ date: _.Input.List(_.Input.Nullable($Scalar.Date)) }), +export const Query = $.Object$(`Query`, { + date: $.field($.Output.Nullable($Scalar.Date)), + dateNonNull: $.field($Scalar.Date), + dateList: $.field($.Output.Nullable($.Output.List($.Output.Nullable($Scalar.Date)))), + dateObject1: $.field($.Output.Nullable(() => DateObject1)), + dateUnion: $.field($.Output.Nullable(() => DateUnion)), + dateInterface1: $.field($.Output.Nullable(() => DateInterface1)), + dateListNonNull: $.field($.Output.List($Scalar.Date)), + dateArg: $.field($.Output.Nullable($Scalar.Date), $.Args({ date: $.Input.Nullable($Scalar.Date) })), + dateArgNonNull: $.field($.Output.Nullable($Scalar.Date), $.Args({ date: $Scalar.Date })), + dateArgList: $.field( + $.Output.Nullable($Scalar.Date), + $.Args({ date: $.Input.Nullable($.Input.List($.Input.Nullable($Scalar.Date))) }), ), - dateArgNonNullListNonNull: _.Output.field( - _.Output.Nullable($Scalar.Date), - _.Args({ date: _.Input.List($Scalar.Date) }), + dateArgNonNullList: $.field( + $.Output.Nullable($Scalar.Date), + $.Args({ date: $.Input.List($.Input.Nullable($Scalar.Date)) }), ), - dateArgInputObject: _.Output.field(_.Output.Nullable($Scalar.Date), _.Args({ input: _.Input.Nullable(InputObject) })), - interface: _.Output.field(_.Output.Nullable(() => Interface)), - id: _.Output.field(_.Output.Nullable($Scalar.ID)), - idNonNull: _.Output.field($Scalar.ID), - string: _.Output.field(_.Output.Nullable($Scalar.String)), - stringWithRequiredArg: _.Output.field(_.Output.Nullable($Scalar.String), _.Args({ string: $Scalar.String })), - stringWithArgs: _.Output.field( - _.Output.Nullable($Scalar.String), - _.Args({ - string: _.Input.Nullable($Scalar.String), - int: _.Input.Nullable($Scalar.Int), - float: _.Input.Nullable($Scalar.Float), - boolean: _.Input.Nullable($Scalar.Boolean), - id: _.Input.Nullable($Scalar.ID), + dateArgNonNullListNonNull: $.field($.Output.Nullable($Scalar.Date), $.Args({ date: $.Input.List($Scalar.Date) })), + dateArgInputObject: $.field($.Output.Nullable($Scalar.Date), $.Args({ input: $.Input.Nullable(InputObject) })), + interface: $.field($.Output.Nullable(() => Interface)), + id: $.field($.Output.Nullable($Scalar.ID)), + idNonNull: $.field($Scalar.ID), + string: $.field($.Output.Nullable($Scalar.String)), + stringWithRequiredArg: $.field($.Output.Nullable($Scalar.String), $.Args({ string: $Scalar.String })), + stringWithArgs: $.field( + $.Output.Nullable($Scalar.String), + $.Args({ + string: $.Input.Nullable($Scalar.String), + int: $.Input.Nullable($Scalar.Int), + float: $.Input.Nullable($Scalar.Float), + boolean: $.Input.Nullable($Scalar.Boolean), + id: $.Input.Nullable($Scalar.ID), }), ), - stringWithArgEnum: _.Output.field(_.Output.Nullable($Scalar.String), _.Args({ ABCEnum: _.Input.Nullable(ABCEnum) })), - stringWithListArg: _.Output.field( - _.Output.Nullable($Scalar.String), - _.Args({ ints: _.Input.Nullable(_.Input.List(_.Input.Nullable($Scalar.Int))) }), + stringWithArgEnum: $.field($.Output.Nullable($Scalar.String), $.Args({ ABCEnum: $.Input.Nullable(ABCEnum) })), + stringWithListArg: $.field( + $.Output.Nullable($Scalar.String), + $.Args({ ints: $.Input.Nullable($.Input.List($.Input.Nullable($Scalar.Int))) }), ), - stringWithListArgRequired: _.Output.field( - _.Output.Nullable($Scalar.String), - _.Args({ ints: _.Input.List(_.Input.Nullable($Scalar.Int)) }), + stringWithListArgRequired: $.field( + $.Output.Nullable($Scalar.String), + $.Args({ ints: $.Input.List($.Input.Nullable($Scalar.Int)) }), ), - stringWithArgInputObject: _.Output.field( - _.Output.Nullable($Scalar.String), - _.Args({ input: _.Input.Nullable(InputObject) }), + stringWithArgInputObject: $.field( + $.Output.Nullable($Scalar.String), + $.Args({ input: $.Input.Nullable(InputObject) }), ), - stringWithArgInputObjectRequired: _.Output.field(_.Output.Nullable($Scalar.String), _.Args({ input: InputObject })), - listListIntNonNull: _.Output.field(_.Output.List(_.Output.List($Scalar.Int))), - listListInt: _.Output.field( - _.Output.Nullable(_.Output.List(_.Output.Nullable(_.Output.List(_.Output.Nullable($Scalar.Int))))), + stringWithArgInputObjectRequired: $.field($.Output.Nullable($Scalar.String), $.Args({ input: InputObject })), + listListIntNonNull: $.field($.Output.List($.Output.List($Scalar.Int))), + listListInt: $.field( + $.Output.Nullable($.Output.List($.Output.Nullable($.Output.List($.Output.Nullable($Scalar.Int))))), ), - listInt: _.Output.field(_.Output.Nullable(_.Output.List(_.Output.Nullable($Scalar.Int)))), - listIntNonNull: _.Output.field(_.Output.List($Scalar.Int)), - object: _.Output.field(_.Output.Nullable(() => Object1)), - objectNonNull: _.Output.field(() => Object1), - objectNested: _.Output.field(_.Output.Nullable(() => ObjectNested)), - objectWithArgs: _.Output.field( - _.Output.Nullable(() => Object1), - _.Args({ - string: _.Input.Nullable($Scalar.String), - int: _.Input.Nullable($Scalar.Int), - float: _.Input.Nullable($Scalar.Float), - boolean: _.Input.Nullable($Scalar.Boolean), - id: _.Input.Nullable($Scalar.ID), + listInt: $.field($.Output.Nullable($.Output.List($.Output.Nullable($Scalar.Int)))), + listIntNonNull: $.field($.Output.List($Scalar.Int)), + object: $.field($.Output.Nullable(() => Object1)), + objectNonNull: $.field(() => Object1), + objectNested: $.field($.Output.Nullable(() => ObjectNested)), + objectWithArgs: $.field( + $.Output.Nullable(() => Object1), + $.Args({ + string: $.Input.Nullable($Scalar.String), + int: $.Input.Nullable($Scalar.Int), + float: $.Input.Nullable($Scalar.Float), + boolean: $.Input.Nullable($Scalar.Boolean), + id: $.Input.Nullable($Scalar.ID), }), ), - fooBarUnion: _.Output.field(_.Output.Nullable(() => FooBarUnion)), - abcEnum: _.Output.field(_.Output.Nullable(ABCEnum)), - lowerCaseUnion: _.Output.field(_.Output.Nullable(() => lowerCaseUnion)), + fooBarUnion: $.field($.Output.Nullable(() => FooBarUnion)), + abcEnum: $.field($.Output.Nullable(ABCEnum)), + lowerCaseUnion: $.field($.Output.Nullable(() => lowerCaseUnion)), }) export const $Index = { From 226e5106fcec29ea838aae352403811dfbbfa794 Mon Sep 17 00:00:00 2001 From: Jason Kuhrt Date: Fri, 12 Apr 2024 07:41:30 -0400 Subject: [PATCH 04/10] work --- src/Schema/Output/Output.ts | 9 +++++---- src/Schema/Output/typeGroups.ts | 4 ++-- src/Schema/Output/types/List.ts | 9 ++++++--- src/Schema/Output/types/Nullable.ts | 9 ++++++--- src/client.ts | 6 +++--- 5 files changed, 22 insertions(+), 15 deletions(-) diff --git a/src/Schema/Output/Output.ts b/src/Schema/Output/Output.ts index 379486a54..8a91cf3ea 100644 --- a/src/Schema/Output/Output.ts +++ b/src/Schema/Output/Output.ts @@ -20,14 +20,15 @@ export type Unwrap<$Type extends any> = $Type extends __typename ? $Type['type'] : $Type extends Named ? $Type : TSError<'Unwrap', 'Unknown $Type', { $Type: $Type }> + // dprint-ignore -export type UnwrapNonNull<$Type> = - $Type extends Nullable ? UnwrapNonNull<$innerType> +export type UnwrapNullable<$Type> = + $Type extends Nullable ? UnwrapNullable<$innerType> : $Type -export const unwrapNonNull = <$Type extends Any>(type: $Type): UnwrapNonNull<$Type> => { +export const unwrapNullable = <$Type extends Any>(type: $Type): UnwrapNullable<$Type> => { if (type.kind === `nullable`) return type.type - return type as UnwrapNonNull<$Type> + return type as UnwrapNullable<$Type> } export const unwrap = <$Type extends Any>(type: $Type): Unwrap<$Type> => { diff --git a/src/Schema/Output/typeGroups.ts b/src/Schema/Output/typeGroups.ts index 40f0366b1..395251f18 100644 --- a/src/Schema/Output/typeGroups.ts +++ b/src/Schema/Output/typeGroups.ts @@ -9,6 +9,6 @@ import type { Union } from './types/Union.js' export type Named = Interface | Enum | Object$2 | Union | Hybrid.Scalar.Any -export type Unnamed = List | __typename | Nullable +export type Unnamed = List | Nullable -export type Any = Unnamed | Named +export type Any = Unnamed | Named | __typename diff --git a/src/Schema/Output/types/List.ts b/src/Schema/Output/types/List.ts index 46e373324..8606db9c1 100644 --- a/src/Schema/Output/types/List.ts +++ b/src/Schema/Output/types/List.ts @@ -1,9 +1,12 @@ import type { Base } from '../../core/helpers.js' -import type { Any } from '../typeGroups.js' +import type { Named } from '../typeGroups.js' +import type { Nullable } from './Nullable.js' -export type List<$Type extends Any> = Base.List<$Type> +type InnerType = Named | Nullable | List -export const List = <$Type extends Any>(type: $Type): List<$Type> => ({ +export type List<$Type extends InnerType> = Base.List<$Type> + +export const List = <$Type extends InnerType>(type: $Type): List<$Type> => ({ kind: `list`, type, }) diff --git a/src/Schema/Output/types/Nullable.ts b/src/Schema/Output/types/Nullable.ts index d5708ae7d..86815f8df 100644 --- a/src/Schema/Output/types/Nullable.ts +++ b/src/Schema/Output/types/Nullable.ts @@ -1,10 +1,13 @@ import type { Base, MaybeThunk } from '../../core/helpers.js' -import type { Any } from '../typeGroups.js' +import type { Named } from '../typeGroups.js' import type { __typename } from './__typename.js' +import type { List } from './List.js' -export type Nullable<$Type extends Exclude>> = Base.Nullable<$Type> +type InnerType = Named | List -export const Nullable = <$Type extends Exclude>>( +export type Nullable<$Type extends InnerType> = Base.Nullable<$Type> + +export const Nullable = <$Type extends InnerType>( type: MaybeThunk<$Type>, ): Nullable<$Type> => ({ kind: `nullable`, diff --git a/src/client.ts b/src/client.ts index 685334acd..93b87bca2 100644 --- a/src/client.ts +++ b/src/client.ts @@ -111,7 +111,7 @@ const encodeCustomScalars = ( if (typeof fieldValue === `object` && `$` in fieldValue) { const field = input.index.fields[fieldName] if (!field?.args) throw new Error(`Field has no args: ${fieldName}`) - if (!field) throw new Error(`Field not found: ${fieldName}`) + if (!field) throw new Error(`Field not found: ${fieldName}`) // eslint-disable-line // @ts-expect-error fixme fieldValue.$ = encodeCustomScalarsArgs(field.args, fieldValue.$) return [fieldName, fieldValue] @@ -159,7 +159,7 @@ const decodeCustomScalars = (index: Object$2, documentQueryObject: object): obje if (!indexField) throw new Error(`Field not found: ${fieldName}`) const type = readMaybeThunk(indexField.type) - const typeWithoutNonNull = Output.unwrapNonNull(type) as Output.Named | Output.List + const typeWithoutNonNull = Output.unwrapNullable(type) as Output.Named | Output.List const v2 = decodeCustomScalarValue(typeWithoutNonNull, v) // eslint-disable-line return [fieldName, v2] }), @@ -174,7 +174,7 @@ const decodeCustomScalarValue = ( if (fieldValue === null) return null const indexTypeDethunked = readMaybeThunk(indexType) - const typeWithoutNonNull = Output.unwrapNonNull(indexTypeDethunked) + const typeWithoutNonNull = Output.unwrapNullable(indexTypeDethunked) as Exclude> if (typeWithoutNonNull.kind === `list`) { assertArray(fieldValue) From 401f484664ee1a0e3a8fd876a0bc56e42ff3d1b1 Mon Sep 17 00:00:00 2001 From: Jason Kuhrt Date: Fri, 12 Apr 2024 08:44:14 -0400 Subject: [PATCH 05/10] work --- src/ResultSet/ResultSet.ts | 1 + src/Schema/Field.ts | 3 -- src/Schema/Input/Input.ts | 1 - src/Schema/Input/typeGroups.ts | 6 ++- src/Schema/Input/types/List.ts | 2 +- src/Schema/Input/types/Nullable.ts | 9 ++-- src/Schema/core/helpers.ts | 2 - src/SelectionSet/SelectionSet.test-d.ts | 1 + src/SelectionSet/SelectionSet.ts | 67 +++++++++++++++---------- 9 files changed, 53 insertions(+), 39 deletions(-) diff --git a/src/ResultSet/ResultSet.ts b/src/ResultSet/ResultSet.ts index 1e647bd87..7b093f648 100644 --- a/src/ResultSet/ResultSet.ts +++ b/src/ResultSet/ResultSet.ts @@ -27,6 +27,7 @@ export type Object$<$SelectionSet, $Node extends Schema.Output.Object$2, $Index */ ? { + // TODO no more type unwrapped field [$Key in keyof $Node['fields'] as $Node['fields'][$Key] extends Schema.Field | {'typeUnwrapped':{kind:'Scalar'}} ? $Key : never]: // eslint-disable-next-line // @ts-ignore infinite depth issue, can this be fixed? diff --git a/src/Schema/Field.ts b/src/Schema/Field.ts index 292069c68..0e702f447 100644 --- a/src/Schema/Field.ts +++ b/src/Schema/Field.ts @@ -1,10 +1,8 @@ import type { Args } from './Args.js' import type { MaybeThunk } from './core/helpers.js' -import { buildTimeOnly } from './core/helpers.js' import type { Output } from './Output/__.js' export type Field<$Type extends any = any, $Args extends Args | null = Args | null> = { - typeUnwrapped: Output.Unwrap<$Type> type: $Type args: $Args } @@ -14,7 +12,6 @@ export const field = <$Type extends Output.Any, $Args extends null | Args = null args: $Args = null as $Args, ): Field<$Type, $Args> => { return { - typeUnwrapped: buildTimeOnly, // eslint-disable-line // At type level "type" is not a thunk type: type as any, // eslint-disable-line args, diff --git a/src/Schema/Input/Input.ts b/src/Schema/Input/Input.ts index 78d7f59a2..fb2765b10 100644 --- a/src/Schema/Input/Input.ts +++ b/src/Schema/Input/Input.ts @@ -12,6 +12,5 @@ export const field = <$Type extends Any>(type: $Type): Field<$Type> => { } export type Field<$Type extends any = any> = { - // typeUnwrapped: Type.Output.Unwrap<$Type> type: $Type } diff --git a/src/Schema/Input/typeGroups.ts b/src/Schema/Input/typeGroups.ts index 074dc55df..ce8aa897e 100644 --- a/src/Schema/Input/typeGroups.ts +++ b/src/Schema/Input/typeGroups.ts @@ -1,6 +1,8 @@ -import type { Enum, Scalar } from '../__.js' +import type { Hybrid } from '../Hybrid/__.js' import type { InputObject } from './types/InputObject.js' import type { List } from './types/List.js' import type { Nullable } from './types/Nullable.js' -export type Any = List | Nullable | Enum | Scalar.Any | InputObject +export type Named = Hybrid.Enum | Hybrid.Scalar.Any | InputObject + +export type Any = List | Nullable | Named diff --git a/src/Schema/Input/types/List.ts b/src/Schema/Input/types/List.ts index 5f8faa012..8d70d4e34 100644 --- a/src/Schema/Input/types/List.ts +++ b/src/Schema/Input/types/List.ts @@ -1,7 +1,7 @@ import type { Base } from '../../core/helpers.js' import type { Any } from '../typeGroups.js' -export type List<$InnerType extends Any = Any> = Base.List<$InnerType> +export type List<$InnerType extends Any> = Base.List<$InnerType> export const List = <$InnerType extends Any>(type: $InnerType): List<$InnerType> => ({ kind: `list`, diff --git a/src/Schema/Input/types/Nullable.ts b/src/Schema/Input/types/Nullable.ts index 224afb64b..89b296582 100644 --- a/src/Schema/Input/types/Nullable.ts +++ b/src/Schema/Input/types/Nullable.ts @@ -1,9 +1,12 @@ import type { Base, MaybeThunk } from '../../core/helpers.js' -import type { Any } from '../typeGroups.js' +import type { Any, Named } from '../typeGroups.js' +import type { List } from './List.js' -export type Nullable<$InnerType extends Any = Any> = Base.Nullable<$InnerType> +type InnerType = Named | List -export const Nullable = <$InnerType extends Any>(type: MaybeThunk<$InnerType>): Nullable<$InnerType> => ({ +export type Nullable<$InnerType extends InnerType> = Base.Nullable<$InnerType> + +export const Nullable = <$InnerType extends InnerType>(type: MaybeThunk<$InnerType>): Nullable<$InnerType> => ({ kind: `nullable`, // at type level "type" is not a thunk type: type as any, // eslint-disable-line diff --git a/src/Schema/core/helpers.ts b/src/Schema/core/helpers.ts index 9b6e7bd26..35680921e 100644 --- a/src/Schema/core/helpers.ts +++ b/src/Schema/core/helpers.ts @@ -6,8 +6,6 @@ export const readMaybeThunk = (maybeThunk: MaybeThunk): T => // @ts-expect-error fixme typeof maybeThunk === `function` ? maybeThunk() : maybeThunk -export const buildTimeOnly: any = undefined - export namespace Base { export interface Nullable<$Type> { kind: 'nullable' diff --git a/src/SelectionSet/SelectionSet.test-d.ts b/src/SelectionSet/SelectionSet.test-d.ts index 11168df24..34cd5118f 100644 --- a/src/SelectionSet/SelectionSet.test-d.ts +++ b/src/SelectionSet/SelectionSet.test-d.ts @@ -204,6 +204,7 @@ test(`Query`, () => { assertType({ stringWithArgInputObjectRequired: { $: { input: { idRequired: ``, dateRequired: new Date(0) } } } }) // @ts-expect-error missing "idRequired" field assertType({ stringWithArgInputObjectRequired: { $: { input: {} } } }) + // type x = Exclude['$']['input'] // all-optional + scalar + directive assertType({ stringWithArgs: { $: { boolean: true }, $skip: true } }) diff --git a/src/SelectionSet/SelectionSet.ts b/src/SelectionSet/SelectionSet.ts index 6cf93daad..27bb0d3c4 100644 --- a/src/SelectionSet/SelectionSet.ts +++ b/src/SelectionSet/SelectionSet.ts @@ -16,20 +16,22 @@ export type Subscription<$Index extends Schema.Index> = $Index['Root']['Subscrip ? Object<$Index['Root']['Subscription'], $Index> : never +type OutputField = Schema.Field + +type OutputFields = Record + // dprint-ignore -type Object< - $Fields extends Schema.Object$2, - $Index extends Schema.Index, -> = Fields<$Fields['fields'], $Index> +type Object<$Object extends Schema.Object$2, $Index extends Schema.Index> = + Fields<$Object['fields'], $Index> // dprint-ignore -type Fields<$Fields extends Record>, $Index extends Schema.Index> = +type Fields<$Fields extends OutputFields, $Index extends Schema.Index> = & { [Key in keyof $Fields]?: // eslint-disable-next-line // @ts-ignore excessive deep error, fixme? - Field, $Index> + Field, $Index> } & /** @@ -40,7 +42,7 @@ type Fields<$Fields extends Record>, $In [ Key in keyof $Fields as `${keyof $Fields & string}_as_${StringNonEmpty}` ]?: - Field, $Index> + Field, $Index> } & /** @@ -64,16 +66,23 @@ export type IsSelectScalarsWildcard = SS extends { $scalars: ClientIndicator export type Field< $Field extends Schema.Field, $Index extends Schema.Index, +> = Field_<$Field['type'], $Field, $Index> + +// dprint-ignore +export type Field_< + $type extends Schema.Output.Any, + $Field extends Schema.Field, + $Index extends Schema.Index, > = - $Field['type']['kind'] extends 'typename' ? NoArgsIndicator : - // eslint-disable-next-line - // @ts-ignore infinite depth issue, can this be fixed? - $Field['typeUnwrapped']['kind'] extends 'Scalar' ? Indicator<$Field> : - $Field['typeUnwrapped']['kind'] extends 'Enum' ? Indicator<$Field> : - $Field['typeUnwrapped']['kind'] extends 'Object' ? Object<$Field['typeUnwrapped'], $Index> & FieldDirectives & Arguments<$Field> : - $Field['typeUnwrapped']['kind'] extends 'Union' ? Union<$Field['typeUnwrapped'], $Index> : - $Field['typeUnwrapped']['kind'] extends 'Interface' ? Interface<$Field['typeUnwrapped'], $Index> : - TSError<'SelectionSetField', '$Field case not handled', { $Field: $Field }> + $type extends Schema.__typename ? NoArgsIndicator : + $type extends Schema.Scalar.Any ? Indicator<$Field> : + $type extends Schema.Enum ? Indicator<$Field> : + $type extends Schema.Output.Nullable ? Field_<$typeInner, $Field, $Index> : + $type extends Schema.Output.List ? Field_<$typeInner, $Field, $Index> : + $type extends Schema.Object$2 ? Object<$type, $Index> & FieldDirectives & Arguments<$Field> : + $type extends Schema.Union ? Union<$type, $Index> : + $type extends Schema.Interface ? Interface<$type, $Index> : + TSError<'Field', '$Field case not handled', { $Field: $Field }> // dprint-ignore type Arguments<$Field extends Schema.Field> = $Field['args'] extends Schema.Args ? $Field['args']['allOptional'] extends true ? { $?: Args<$Field['args']> } : @@ -224,26 +233,30 @@ $Field['args'] extends Schema.Args ? $Field['args']['allOptional'] extend // dprint-ignore export type Args<$Args extends Schema.Args> = ArgFields<$Args['fields']> +// dprint-ignore export type ArgFields<$ArgFields extends Schema.InputObject['fields']> = & { - [ - Key in keyof $ArgFields as $ArgFields[Key] extends Schema.Input.Nullable ? never : Key - ]: InferTypeInput<$ArgFields[Key]> - } + [Key in keyof OmitNullableFields<$ArgFields>]: InputField<$ArgFields[Key]> + } & { - [ - Key in keyof $ArgFields as $ArgFields[Key] extends Schema.Input.Nullable ? Key : never - ]?: null | InferTypeInput<$ArgFields[Key]> - } + [Key in keyof PickNullableFields<$ArgFields>]?: InputField<$ArgFields[Key]> | null + } // dprint-ignore -type InferTypeInput<$InputType extends Schema.Input.Any> = - $InputType extends Schema.Input.Nullable ? InferTypeInput<$InnerType> | null : - $InputType extends Schema.Input.List ? InferTypeInput<$InnerType>[] : +type InputField<$InputType extends Schema.Input.Any> = + $InputType extends Schema.Input.Nullable ? InputField<$InnerType> | null : + $InputType extends Schema.Input.List ? InputField<$InnerType>[] : $InputType extends Schema.InputObject ? ArgFields<$Fields> : $InputType extends Schema.Enum ? $Members[number] : $InputType extends Schema.Scalar.Any ? ReturnType<$InputType['codec']['decode']> : TSError<'InferTypeInput', 'Unknown $InputType', { $InputType: $InputType }> // never +type OmitNullableFields<$Fields extends Schema.InputObject['fields']> = { + [Key in keyof $Fields as $Fields[Key] extends Schema.Input.Nullable ? never : Key]: $Fields[Key] +} + +type PickNullableFields<$Fields extends Schema.InputObject['fields']> = { + [Key in keyof $Fields as $Fields[Key] extends Schema.Input.Nullable ? Key : never]: $Fields[Key] +} /** * @see https://spec.graphql.org/draft/#sec-Type-System.Directives.Built-in-Directives From 91fdebafab25a9612c91a13ac2654f2b1ea56d6d Mon Sep 17 00:00:00 2001 From: Jason Kuhrt Date: Fri, 12 Apr 2024 08:45:47 -0400 Subject: [PATCH 06/10] work --- src/SelectionSet/SelectionSet.ts | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/SelectionSet/SelectionSet.ts b/src/SelectionSet/SelectionSet.ts index 27bb0d3c4..f6272ec3b 100644 --- a/src/SelectionSet/SelectionSet.ts +++ b/src/SelectionSet/SelectionSet.ts @@ -222,8 +222,10 @@ export type OmitNegativeIndicators<$SelectionSet> = { */ export type NoArgsIndicator = ClientIndicator | FieldDirectives +// todo something is wrong here, resulting types are `any`. // dprint-ignore export type Indicator<$Field extends Schema.Field = Schema.Field> = + // $Field['args']['allOptional'] $Field['args'] extends Schema.Args ? $Field['args']['allOptional'] extends true ? ({ $?: Args<$Field['args']> } & FieldDirectives) | ClientIndicator : From 411e423c8b6cb57c771c746819ff95bb8be295f8 Mon Sep 17 00:00:00 2001 From: Jason Kuhrt Date: Fri, 12 Apr 2024 13:18:03 -0400 Subject: [PATCH 07/10] work --- src/ResultSet/ResultSet.ts | 6 +- src/Schema/Args.ts | 12 ++- src/Schema/Field.ts | 16 +++- src/Schema/Output/types/Interface.ts | 6 +- src/Schema/Output/types/Object.ts | 16 +--- src/SelectionSet/SelectionSet.ts | 39 ++++----- .../__snapshots__/files.test.ts.snap | 81 ++++++++++--------- src/generator/code/schemaBuildtime.ts | 2 +- src/generator/files.ts | 4 +- .../ts/_/schema/generated/SchemaBuildtime.ts | 81 ++++++++++--------- 10 files changed, 134 insertions(+), 129 deletions(-) diff --git a/src/ResultSet/ResultSet.ts b/src/ResultSet/ResultSet.ts index 7b093f648..406274c58 100644 --- a/src/ResultSet/ResultSet.ts +++ b/src/ResultSet/ResultSet.ts @@ -3,7 +3,7 @@ import type { Simplify } from 'type-fest' import type { GetKeyOr, SimplifyDeep } from '../lib/prelude.js' import type { TSError } from '../lib/TSError.js' -import type { Schema } from '../Schema/__.js' +import type { Schema, SomeField } from '../Schema/__.js' import type { SelectionSet } from '../SelectionSet/__.js' // dprint-ignore @@ -28,7 +28,7 @@ export type Object$<$SelectionSet, $Node extends Schema.Output.Object$2, $Index ? { // TODO no more type unwrapped field - [$Key in keyof $Node['fields'] as $Node['fields'][$Key] extends Schema.Field | {'typeUnwrapped':{kind:'Scalar'}} ? $Key : never]: + [$Key in keyof $Node['fields'] as $Node['fields'][$Key] extends Schema.Field | {'typeUnwrapped':{kind:'Scalar'}} ? $Key : never]: // eslint-disable-next-line // @ts-ignore infinite depth issue, can this be fixed? Field<$SelectionSet, Schema.Field.As<$Node['fields'][$Key]>, $Index> @@ -63,7 +63,7 @@ type OnTypeFragment<$SelectionSet, $Node extends Schema.Output.Object$2, $Index : never // dprint-ignore -type Field<$SelectionSet, $Field extends Schema.Field, $Index extends Schema.Index> = +type Field<$SelectionSet, $Field extends SomeField, $Index extends Schema.Index> = $SelectionSet extends SelectionSet.Directive.Include.Negative | SelectionSet.Directive.Skip.Positive ? null : ( diff --git a/src/Schema/Args.ts b/src/Schema/Args.ts index aaa8db9e3..b42bdc429 100644 --- a/src/Schema/Args.ts +++ b/src/Schema/Args.ts @@ -1,11 +1,17 @@ import type { Nullable } from './Input/types/Nullable.js' -export interface Args<$Fields extends any = any> { - allOptional: Exclude<$Fields[keyof $Fields], Nullable> extends never ? true : false +type InputFields = Record + +// dprint-ignore +export type InputFieldsAllNullable<$Fields extends InputFields> = + Exclude<$Fields[keyof $Fields], Nullable> extends never ? true : false + +export interface Args<$Fields extends InputFields> { + allOptional: InputFieldsAllNullable<$Fields> fields: $Fields } -export const Args = (fields: F): Args => { +export const Args = (fields: F): Args => { return { // @ts-expect-error allOptional: false, diff --git a/src/Schema/Field.ts b/src/Schema/Field.ts index 0e702f447..1a39f3208 100644 --- a/src/Schema/Field.ts +++ b/src/Schema/Field.ts @@ -1,13 +1,14 @@ import type { Args } from './Args.js' import type { MaybeThunk } from './core/helpers.js' +import type { Hybrid } from './Hybrid/__.js' import type { Output } from './Output/__.js' -export type Field<$Type extends any = any, $Args extends Args | null = Args | null> = { +export type Field<$Type extends Output.Any, $Args extends Args | null> = { type: $Type args: $Args } -export const field = <$Type extends Output.Any, $Args extends null | Args = null>( +export const field = <$Type extends Output.Any, $Args extends null | Args = null>( type: MaybeThunk<$Type>, args: $Args = null as $Args, ): Field<$Type, $Args> => { @@ -17,3 +18,14 @@ export const field = <$Type extends Output.Any, $Args extends null | Args = null args, } } + +// todo test non null union and non null interface fields +export type SomeField = Field< + Hybrid.Enum | Hybrid.Scalar.Any | Output.List | Output.Nullable | Output.Object$2, + Args | null +> + +export type SomeFields<$Keys extends string | number | symbol = string | number | symbol> = Record< + $Keys, + SomeField +> diff --git a/src/Schema/Output/types/Interface.ts b/src/Schema/Output/types/Interface.ts index b4899db3d..47c5c875c 100644 --- a/src/Schema/Output/types/Interface.ts +++ b/src/Schema/Output/types/Interface.ts @@ -1,9 +1,9 @@ -import type { Field } from '../../Field.js' +import type { SomeFields } from '../../Field.js' import type { Object$2 } from './Object.js' export type Interface< $Name extends string = string, - $Fields extends Record = Record, + $Fields extends SomeFields = SomeFields, $Implementors extends [Object$2, ...Object$2[]] = [Object$2, ...Object$2[]], > = { kind: 'Interface' @@ -14,7 +14,7 @@ export type Interface< export const Interface = < $Name extends string, - $Fields extends Record, + $Fields extends SomeFields, $Implementors extends [Object$2, ...Object$2[]], >( name: $Name, diff --git a/src/Schema/Output/types/Object.ts b/src/Schema/Output/types/Object.ts index 276ad01fd..515d5ada2 100644 --- a/src/Schema/Output/types/Object.ts +++ b/src/Schema/Output/types/Object.ts @@ -1,22 +1,19 @@ -import type { Field } from '../../Field.js' +import type { Field, SomeFields } from '../../Field.js' import { field } from '../../Field.js' -import type { Hybrid } from '../../Hybrid/__.js' import { __typename } from './__typename.js' -import type { List } from './List.js' -import type { Nullable } from './Nullable.js' export interface Object$2< $Name extends string = string, - $Fields extends Fields = Fields, + $Fields extends SomeFields = SomeFields, > { kind: 'Object' fields: { - __typename: Field<__typename<$Name>> + __typename: Field<__typename<$Name>, null> } & $Fields } // Naming this "Object" breaks Vitest: https://github.com/vitest-dev/vitest/issues/5463 -export const Object$ = <$Name extends string, $Fields extends Record>( +export const Object$ = <$Name extends string, $Fields extends Record>>( name: $Name, fields: $Fields, // eslint-disable-next-line @@ -30,8 +27,3 @@ export const Object$ = <$Name extends string, $Fields extends Record | Nullable | Object$2 | Hybrid.Enum | Hybrid.Scalar.Any> -> diff --git a/src/SelectionSet/SelectionSet.ts b/src/SelectionSet/SelectionSet.ts index f6272ec3b..2622435e1 100644 --- a/src/SelectionSet/SelectionSet.ts +++ b/src/SelectionSet/SelectionSet.ts @@ -1,8 +1,8 @@ /* eslint-disable @typescript-eslint/ban-types */ -import type { As, MaybeList, StringNonEmpty, Values } from '../lib/prelude.js' +import type { MaybeList, StringNonEmpty, Values } from '../lib/prelude.js' import type { TSError } from '../lib/TSError.js' -import type { Schema } from '../Schema/__.js' +import type { Schema, SomeField, SomeFields } from '../Schema/__.js' export type Query<$Index extends Schema.Index> = $Index['Root']['Query'] extends Schema.Object$2 ? Object<$Index['Root']['Query'], $Index> @@ -16,22 +16,18 @@ export type Subscription<$Index extends Schema.Index> = $Index['Root']['Subscrip ? Object<$Index['Root']['Subscription'], $Index> : never -type OutputField = Schema.Field - -type OutputFields = Record - // dprint-ignore type Object<$Object extends Schema.Object$2, $Index extends Schema.Index> = Fields<$Object['fields'], $Index> // dprint-ignore -type Fields<$Fields extends OutputFields, $Index extends Schema.Index> = +type Fields<$Fields extends SomeFields, $Index extends Schema.Index> = & { [Key in keyof $Fields]?: // eslint-disable-next-line // @ts-ignore excessive deep error, fixme? - Field, $Index> + Field<$Fields[Key], $Index> } & /** @@ -42,7 +38,7 @@ type Fields<$Fields extends OutputFields, $Index extends Schema.Index> = [ Key in keyof $Fields as `${keyof $Fields & string}_as_${StringNonEmpty}` ]?: - Field, $Index> + Field<$Fields[Key], $Index> } & /** @@ -63,31 +59,28 @@ type Fields<$Fields extends OutputFields, $Index extends Schema.Index> = export type IsSelectScalarsWildcard = SS extends { $scalars: ClientIndicatorPositive } ? true : false // dprint-ignore -export type Field< - $Field extends Schema.Field, - $Index extends Schema.Index, -> = Field_<$Field['type'], $Field, $Index> +export type Field<$Field extends SomeField, $Index extends Schema.Index> = Field_<$Field['type'], $Field, $Index> // dprint-ignore export type Field_< $type extends Schema.Output.Any, - $Field extends Schema.Field, + $Field extends SomeField, $Index extends Schema.Index, > = + $type extends Schema.Output.Nullable ? Field_<$typeInner, $Field, $Index> : + $type extends Schema.Output.List ? Field_<$typeInner, $Field, $Index> : $type extends Schema.__typename ? NoArgsIndicator : $type extends Schema.Scalar.Any ? Indicator<$Field> : $type extends Schema.Enum ? Indicator<$Field> : - $type extends Schema.Output.Nullable ? Field_<$typeInner, $Field, $Index> : - $type extends Schema.Output.List ? Field_<$typeInner, $Field, $Index> : $type extends Schema.Object$2 ? Object<$type, $Index> & FieldDirectives & Arguments<$Field> : $type extends Schema.Union ? Union<$type, $Index> : $type extends Schema.Interface ? Interface<$type, $Index> : TSError<'Field', '$Field case not handled', { $Field: $Field }> // dprint-ignore -type Arguments<$Field extends Schema.Field> = -$Field['args'] extends Schema.Args ? $Field['args']['allOptional'] extends true ? { $?: Args<$Field['args']> } : - { $: Args<$Field['args']> } : - {} +type Arguments<$Field extends SomeField> = + $Field['args'] extends Schema.Args ? $Field['args']['allOptional'] extends true ? { $?: Args<$Field['args']> } : + { $: Args<$Field['args']> } : + {} // dprint-ignore type Interface<$Node extends Schema.Interface, $Index extends Schema.Index> = @@ -224,16 +217,16 @@ export type NoArgsIndicator = ClientIndicator | FieldDirectives // todo something is wrong here, resulting types are `any`. // dprint-ignore -export type Indicator<$Field extends Schema.Field = Schema.Field> = +export type Indicator<$Field extends SomeField> = // $Field['args']['allOptional'] -$Field['args'] extends Schema.Args ? $Field['args']['allOptional'] extends true +$Field['args'] extends Schema.Args ? $Field['args']['allOptional'] extends true ? ({ $?: Args<$Field['args']> } & FieldDirectives) | ClientIndicator : { $: Args<$Field['args']> } & FieldDirectives : NoArgsIndicator // dprint-ignore -export type Args<$Args extends Schema.Args> = ArgFields<$Args['fields']> +export type Args<$Args extends Schema.Args> = ArgFields<$Args['fields']> // dprint-ignore export type ArgFields<$ArgFields extends Schema.InputObject['fields']> = diff --git a/src/generator/__snapshots__/files.test.ts.snap b/src/generator/__snapshots__/files.test.ts.snap index dec2ebe3f..430d40a65 100644 --- a/src/generator/__snapshots__/files.test.ts.snap +++ b/src/generator/__snapshots__/files.test.ts.snap @@ -10,13 +10,13 @@ import type * as $Scalar from './Scalar.ts' export namespace Root { export type Query = $.Object$2<'Query', { - date: $.Field<$.Output.Nullable<$Scalar.Date>> - dateNonNull: $.Field<$Scalar.Date> - dateList: $.Field<$.Output.Nullable<$.Output.List<$.Output.Nullable<$Scalar.Date>>>> - dateObject1: $.Field<$.Output.Nullable> - dateUnion: $.Field<$.Output.Nullable> - dateInterface1: $.Field<$.Output.Nullable> - dateListNonNull: $.Field<$.Output.List<$Scalar.Date>> + date: $.Field<$.Output.Nullable<$Scalar.Date>, null> + dateNonNull: $.Field<$Scalar.Date, null> + dateList: $.Field<$.Output.Nullable<$.Output.List<$.Output.Nullable<$Scalar.Date>>>, null> + dateObject1: $.Field<$.Output.Nullable, null> + dateUnion: $.Field<$.Output.Nullable, null> + dateInterface1: $.Field<$.Output.Nullable, null> + dateListNonNull: $.Field<$.Output.List<$Scalar.Date>, null> dateArg: $.Field< $.Output.Nullable<$Scalar.Date>, $.Args<{ @@ -53,10 +53,10 @@ export namespace Root { input: $.Input.Nullable }> > - interface: $.Field<$.Output.Nullable> - id: $.Field<$.Output.Nullable<$Scalar.ID>> - idNonNull: $.Field<$Scalar.ID> - string: $.Field<$.Output.Nullable<$Scalar.String>> + interface: $.Field<$.Output.Nullable, null> + id: $.Field<$.Output.Nullable<$Scalar.ID>, null> + idNonNull: $.Field<$Scalar.ID, null> + string: $.Field<$.Output.Nullable<$Scalar.String>, null> stringWithRequiredArg: $.Field< $.Output.Nullable<$Scalar.String>, $.Args<{ @@ -103,15 +103,16 @@ export namespace Root { input: InputObject.InputObject }> > - listListIntNonNull: $.Field<$.Output.List<$.Output.List<$Scalar.Int>>> + listListIntNonNull: $.Field<$.Output.List<$.Output.List<$Scalar.Int>>, null> listListInt: $.Field< - $.Output.Nullable<$.Output.List<$.Output.Nullable<$.Output.List<$.Output.Nullable<$Scalar.Int>>>>> + $.Output.Nullable<$.Output.List<$.Output.Nullable<$.Output.List<$.Output.Nullable<$Scalar.Int>>>>>, + null > - listInt: $.Field<$.Output.Nullable<$.Output.List<$.Output.Nullable<$Scalar.Int>>>> - listIntNonNull: $.Field<$.Output.List<$Scalar.Int>> - object: $.Field<$.Output.Nullable> - objectNonNull: $.Field - objectNested: $.Field<$.Output.Nullable> + listInt: $.Field<$.Output.Nullable<$.Output.List<$.Output.Nullable<$Scalar.Int>>>, null> + listIntNonNull: $.Field<$.Output.List<$Scalar.Int>, null> + object: $.Field<$.Output.Nullable, null> + objectNonNull: $.Field + objectNested: $.Field<$.Output.Nullable, null> objectWithArgs: $.Field< $.Output.Nullable, $.Args<{ @@ -122,12 +123,12 @@ export namespace Root { id: $.Input.Nullable<$Scalar.ID> }> > - fooBarUnion: $.Field<$.Output.Nullable> + fooBarUnion: $.Field<$.Output.Nullable, null> /** * Query enum field documentation. */ - abcEnum: $.Field<$.Output.Nullable> - lowerCaseUnion: $.Field<$.Output.Nullable> + abcEnum: $.Field<$.Output.Nullable, null> + lowerCaseUnion: $.Field<$.Output.Nullable, null> }> } @@ -166,11 +167,11 @@ export namespace InputObject { export namespace Interface { export type DateInterface1 = $.Interface<'DateInterface1', { - date1: $.Field<$.Output.Nullable<$Scalar.Date>> + date1: $.Field<$.Output.Nullable<$Scalar.Date>, null> }, [Object.DateObject1]> export type Interface = $.Interface<'Interface', { - id: $.Field<$.Output.Nullable<$Scalar.ID>> + id: $.Field<$.Output.Nullable<$Scalar.ID>, null> }, [Object.Object1ImplementingInterface, Object.Object2ImplementingInterface]> } @@ -180,11 +181,11 @@ export namespace Interface { export namespace Object { export type DateObject1 = $.Object$2<'DateObject1', { - date1: $.Field<$.Output.Nullable<$Scalar.Date>> + date1: $.Field<$.Output.Nullable<$Scalar.Date>, null> }> export type DateObject2 = $.Object$2<'DateObject2', { - date2: $.Field<$.Output.Nullable<$Scalar.Date>> + date2: $.Field<$.Output.Nullable<$Scalar.Date>, null> }> /** @@ -196,42 +197,42 @@ export namespace Object { * * @deprecated Field a is deprecated. */ - id: $.Field<$.Output.Nullable<$Scalar.ID>> + id: $.Field<$.Output.Nullable<$Scalar.ID>, null> }> export type Bar = $.Object$2<'Bar', { - int: $.Field<$.Output.Nullable<$Scalar.Int>> + int: $.Field<$.Output.Nullable<$Scalar.Int>, null> }> export type ObjectNested = $.Object$2<'ObjectNested', { - id: $.Field<$.Output.Nullable<$Scalar.ID>> - object: $.Field<$.Output.Nullable> + id: $.Field<$.Output.Nullable<$Scalar.ID>, null> + object: $.Field<$.Output.Nullable, null> }> export type lowerCaseObject = $.Object$2<'lowerCaseObject', { - id: $.Field<$.Output.Nullable<$Scalar.ID>> + id: $.Field<$.Output.Nullable<$Scalar.ID>, null> }> export type lowerCaseObject2 = $.Object$2<'lowerCaseObject2', { - int: $.Field<$.Output.Nullable<$Scalar.Int>> + int: $.Field<$.Output.Nullable<$Scalar.Int>, null> }> export type Object1 = $.Object$2<'Object1', { - string: $.Field<$.Output.Nullable<$Scalar.String>> - int: $.Field<$.Output.Nullable<$Scalar.Int>> - float: $.Field<$.Output.Nullable<$Scalar.Float>> - boolean: $.Field<$.Output.Nullable<$Scalar.Boolean>> - id: $.Field<$.Output.Nullable<$Scalar.ID>> + string: $.Field<$.Output.Nullable<$Scalar.String>, null> + int: $.Field<$.Output.Nullable<$Scalar.Int>, null> + float: $.Field<$.Output.Nullable<$Scalar.Float>, null> + boolean: $.Field<$.Output.Nullable<$Scalar.Boolean>, null> + id: $.Field<$.Output.Nullable<$Scalar.ID>, null> }> export type Object1ImplementingInterface = $.Object$2<'Object1ImplementingInterface', { - id: $.Field<$.Output.Nullable<$Scalar.ID>> - int: $.Field<$.Output.Nullable<$Scalar.Int>> + id: $.Field<$.Output.Nullable<$Scalar.ID>, null> + int: $.Field<$.Output.Nullable<$Scalar.Int>, null> }> export type Object2ImplementingInterface = $.Object$2<'Object2ImplementingInterface', { - id: $.Field<$.Output.Nullable<$Scalar.ID>> - boolean: $.Field<$.Output.Nullable<$Scalar.Boolean>> + id: $.Field<$.Output.Nullable<$Scalar.ID>, null> + boolean: $.Field<$.Output.Nullable<$Scalar.Boolean>, null> }> } diff --git a/src/generator/code/schemaBuildtime.ts b/src/generator/code/schemaBuildtime.ts index a2d1e7ac3..60ec1c7f4 100644 --- a/src/generator/code/schemaBuildtime.ts +++ b/src/generator/code/schemaBuildtime.ts @@ -253,7 +253,7 @@ const renderOutputField = (config: Config, field: AnyField): string => { ? renderArgs(config, field.args) : null - return `$.Field<${type}${args ? `, ${args}` : ``}>` + return `$.Field<${type}${args ? `, ${args}` : `, null`}>` } const renderInputField = (config: Config, field: AnyField): string => { diff --git a/src/generator/files.ts b/src/generator/files.ts index 1c33a13fd..e5bf2d063 100644 --- a/src/generator/files.ts +++ b/src/generator/files.ts @@ -26,7 +26,7 @@ export const generateFiles = async (input: Input) => { customScalarCodecsFilePath.replace(/\.ts$/, `.js`), ) const customScalarCodecsPathExists = await fileExists(customScalarCodecsFilePath) - const formatter = (input.format ?? true) ? createFromBuffer(await fs.readFile(getPath())) : undefined + const typeScriptFormatter = (input.format ?? true) ? createFromBuffer(await fs.readFile(getPath())) : undefined const code = generateCode({ schemaSource, @@ -35,7 +35,7 @@ export const generateFiles = async (input: Input) => { }, ...input.code, options: { - formatter, + formatter: typeScriptFormatter, customScalars: customScalarCodecsPathExists, }, }) diff --git a/tests/ts/_/schema/generated/SchemaBuildtime.ts b/tests/ts/_/schema/generated/SchemaBuildtime.ts index c45b2d9ff..7e635b216 100644 --- a/tests/ts/_/schema/generated/SchemaBuildtime.ts +++ b/tests/ts/_/schema/generated/SchemaBuildtime.ts @@ -7,13 +7,13 @@ import type * as $Scalar from './Scalar.ts' export namespace Root { export type Query = $.Object$2<'Query', { - date: $.Field<$.Output.Nullable<$Scalar.Date>> - dateNonNull: $.Field<$Scalar.Date> - dateList: $.Field<$.Output.Nullable<$.Output.List<$.Output.Nullable<$Scalar.Date>>>> - dateObject1: $.Field<$.Output.Nullable> - dateUnion: $.Field<$.Output.Nullable> - dateInterface1: $.Field<$.Output.Nullable> - dateListNonNull: $.Field<$.Output.List<$Scalar.Date>> + date: $.Field<$.Output.Nullable<$Scalar.Date>, null> + dateNonNull: $.Field<$Scalar.Date, null> + dateList: $.Field<$.Output.Nullable<$.Output.List<$.Output.Nullable<$Scalar.Date>>>, null> + dateObject1: $.Field<$.Output.Nullable, null> + dateUnion: $.Field<$.Output.Nullable, null> + dateInterface1: $.Field<$.Output.Nullable, null> + dateListNonNull: $.Field<$.Output.List<$Scalar.Date>, null> dateArg: $.Field< $.Output.Nullable<$Scalar.Date>, $.Args<{ @@ -50,10 +50,10 @@ export namespace Root { input: $.Input.Nullable }> > - interface: $.Field<$.Output.Nullable> - id: $.Field<$.Output.Nullable<$Scalar.ID>> - idNonNull: $.Field<$Scalar.ID> - string: $.Field<$.Output.Nullable<$Scalar.String>> + interface: $.Field<$.Output.Nullable, null> + id: $.Field<$.Output.Nullable<$Scalar.ID>, null> + idNonNull: $.Field<$Scalar.ID, null> + string: $.Field<$.Output.Nullable<$Scalar.String>, null> stringWithRequiredArg: $.Field< $.Output.Nullable<$Scalar.String>, $.Args<{ @@ -100,15 +100,16 @@ export namespace Root { input: InputObject.InputObject }> > - listListIntNonNull: $.Field<$.Output.List<$.Output.List<$Scalar.Int>>> + listListIntNonNull: $.Field<$.Output.List<$.Output.List<$Scalar.Int>>, null> listListInt: $.Field< - $.Output.Nullable<$.Output.List<$.Output.Nullable<$.Output.List<$.Output.Nullable<$Scalar.Int>>>>> + $.Output.Nullable<$.Output.List<$.Output.Nullable<$.Output.List<$.Output.Nullable<$Scalar.Int>>>>>, + null > - listInt: $.Field<$.Output.Nullable<$.Output.List<$.Output.Nullable<$Scalar.Int>>>> - listIntNonNull: $.Field<$.Output.List<$Scalar.Int>> - object: $.Field<$.Output.Nullable> - objectNonNull: $.Field - objectNested: $.Field<$.Output.Nullable> + listInt: $.Field<$.Output.Nullable<$.Output.List<$.Output.Nullable<$Scalar.Int>>>, null> + listIntNonNull: $.Field<$.Output.List<$Scalar.Int>, null> + object: $.Field<$.Output.Nullable, null> + objectNonNull: $.Field + objectNested: $.Field<$.Output.Nullable, null> objectWithArgs: $.Field< $.Output.Nullable, $.Args<{ @@ -119,12 +120,12 @@ export namespace Root { id: $.Input.Nullable<$Scalar.ID> }> > - fooBarUnion: $.Field<$.Output.Nullable> + fooBarUnion: $.Field<$.Output.Nullable, null> /** * Query enum field documentation. */ - abcEnum: $.Field<$.Output.Nullable> - lowerCaseUnion: $.Field<$.Output.Nullable> + abcEnum: $.Field<$.Output.Nullable, null> + lowerCaseUnion: $.Field<$.Output.Nullable, null> }> } @@ -163,11 +164,11 @@ export namespace InputObject { export namespace Interface { export type DateInterface1 = $.Interface<'DateInterface1', { - date1: $.Field<$.Output.Nullable<$Scalar.Date>> + date1: $.Field<$.Output.Nullable<$Scalar.Date>, null> }, [Object.DateObject1]> export type Interface = $.Interface<'Interface', { - id: $.Field<$.Output.Nullable<$Scalar.ID>> + id: $.Field<$.Output.Nullable<$Scalar.ID>, null> }, [Object.Object1ImplementingInterface, Object.Object2ImplementingInterface]> } @@ -177,11 +178,11 @@ export namespace Interface { export namespace Object { export type DateObject1 = $.Object$2<'DateObject1', { - date1: $.Field<$.Output.Nullable<$Scalar.Date>> + date1: $.Field<$.Output.Nullable<$Scalar.Date>, null> }> export type DateObject2 = $.Object$2<'DateObject2', { - date2: $.Field<$.Output.Nullable<$Scalar.Date>> + date2: $.Field<$.Output.Nullable<$Scalar.Date>, null> }> /** @@ -193,42 +194,42 @@ export namespace Object { * * @deprecated Field a is deprecated. */ - id: $.Field<$.Output.Nullable<$Scalar.ID>> + id: $.Field<$.Output.Nullable<$Scalar.ID>, null> }> export type Bar = $.Object$2<'Bar', { - int: $.Field<$.Output.Nullable<$Scalar.Int>> + int: $.Field<$.Output.Nullable<$Scalar.Int>, null> }> export type ObjectNested = $.Object$2<'ObjectNested', { - id: $.Field<$.Output.Nullable<$Scalar.ID>> - object: $.Field<$.Output.Nullable> + id: $.Field<$.Output.Nullable<$Scalar.ID>, null> + object: $.Field<$.Output.Nullable, null> }> export type lowerCaseObject = $.Object$2<'lowerCaseObject', { - id: $.Field<$.Output.Nullable<$Scalar.ID>> + id: $.Field<$.Output.Nullable<$Scalar.ID>, null> }> export type lowerCaseObject2 = $.Object$2<'lowerCaseObject2', { - int: $.Field<$.Output.Nullable<$Scalar.Int>> + int: $.Field<$.Output.Nullable<$Scalar.Int>, null> }> export type Object1 = $.Object$2<'Object1', { - string: $.Field<$.Output.Nullable<$Scalar.String>> - int: $.Field<$.Output.Nullable<$Scalar.Int>> - float: $.Field<$.Output.Nullable<$Scalar.Float>> - boolean: $.Field<$.Output.Nullable<$Scalar.Boolean>> - id: $.Field<$.Output.Nullable<$Scalar.ID>> + string: $.Field<$.Output.Nullable<$Scalar.String>, null> + int: $.Field<$.Output.Nullable<$Scalar.Int>, null> + float: $.Field<$.Output.Nullable<$Scalar.Float>, null> + boolean: $.Field<$.Output.Nullable<$Scalar.Boolean>, null> + id: $.Field<$.Output.Nullable<$Scalar.ID>, null> }> export type Object1ImplementingInterface = $.Object$2<'Object1ImplementingInterface', { - id: $.Field<$.Output.Nullable<$Scalar.ID>> - int: $.Field<$.Output.Nullable<$Scalar.Int>> + id: $.Field<$.Output.Nullable<$Scalar.ID>, null> + int: $.Field<$.Output.Nullable<$Scalar.Int>, null> }> export type Object2ImplementingInterface = $.Object$2<'Object2ImplementingInterface', { - id: $.Field<$.Output.Nullable<$Scalar.ID>> - boolean: $.Field<$.Output.Nullable<$Scalar.Boolean>> + id: $.Field<$.Output.Nullable<$Scalar.ID>, null> + boolean: $.Field<$.Output.Nullable<$Scalar.Boolean>, null> }> } From 7e67daefcb27f492545d5cc403a4042622a5ebd2 Mon Sep 17 00:00:00 2001 From: Jason Kuhrt Date: Fri, 12 Apr 2024 15:28:25 -0400 Subject: [PATCH 08/10] work --- src/Schema/Args.ts | 3 --- src/SelectionSet/SelectionSet.ts | 17 +++++++---------- 2 files changed, 7 insertions(+), 13 deletions(-) diff --git a/src/Schema/Args.ts b/src/Schema/Args.ts index b42bdc429..92554baa4 100644 --- a/src/Schema/Args.ts +++ b/src/Schema/Args.ts @@ -7,14 +7,11 @@ export type InputFieldsAllNullable<$Fields extends InputFields> = Exclude<$Fields[keyof $Fields], Nullable> extends never ? true : false export interface Args<$Fields extends InputFields> { - allOptional: InputFieldsAllNullable<$Fields> fields: $Fields } export const Args = (fields: F): Args => { return { - // @ts-expect-error - allOptional: false, fields, } } diff --git a/src/SelectionSet/SelectionSet.ts b/src/SelectionSet/SelectionSet.ts index 2622435e1..ffc27e865 100644 --- a/src/SelectionSet/SelectionSet.ts +++ b/src/SelectionSet/SelectionSet.ts @@ -2,7 +2,7 @@ import type { MaybeList, StringNonEmpty, Values } from '../lib/prelude.js' import type { TSError } from '../lib/TSError.js' -import type { Schema, SomeField, SomeFields } from '../Schema/__.js' +import type { InputFieldsAllNullable, Schema, SomeField, SomeFields } from '../Schema/__.js' export type Query<$Index extends Schema.Index> = $Index['Root']['Query'] extends Schema.Object$2 ? Object<$Index['Root']['Query'], $Index> @@ -78,8 +78,8 @@ export type Field_< TSError<'Field', '$Field case not handled', { $Field: $Field }> // dprint-ignore type Arguments<$Field extends SomeField> = - $Field['args'] extends Schema.Args ? $Field['args']['allOptional'] extends true ? { $?: Args<$Field['args']> } : - { $: Args<$Field['args']> } : + $Field['args'] extends Schema.Args ? InputFieldsAllNullable<$Field['args']['fields']> extends true ? { $?: Args<$Field['args']> } : + { $: Args<$Field['args']> } : {} // dprint-ignore @@ -215,15 +215,12 @@ export type OmitNegativeIndicators<$SelectionSet> = { */ export type NoArgsIndicator = ClientIndicator | FieldDirectives -// todo something is wrong here, resulting types are `any`. // dprint-ignore export type Indicator<$Field extends SomeField> = - -// $Field['args']['allOptional'] -$Field['args'] extends Schema.Args ? $Field['args']['allOptional'] extends true - ? ({ $?: Args<$Field['args']> } & FieldDirectives) | ClientIndicator : - { $: Args<$Field['args']> } & FieldDirectives : - NoArgsIndicator +$Field['args'] extends Schema.Args ? InputFieldsAllNullable<$Field['args']['fields']> extends true + ? ({ $?: Args<$Field['args']> } & FieldDirectives) | ClientIndicator : + { $: Args<$Field['args']> } & FieldDirectives : + NoArgsIndicator // dprint-ignore export type Args<$Args extends Schema.Args> = ArgFields<$Args['fields']> From af98246043d3c24a5807f8eccf07f449b356cc73 Mon Sep 17 00:00:00 2001 From: Jason Kuhrt Date: Fri, 12 Apr 2024 15:32:50 -0400 Subject: [PATCH 09/10] work --- src/ResultSet/ResultSet.test-d.ts | 1 + src/Schema/Args.ts | 9 +++++++++ src/Schema/Input/types/InputObject.ts | 4 ++-- src/SelectionSet/SelectionSet.ts | 16 ++++++++-------- 4 files changed, 20 insertions(+), 10 deletions(-) diff --git a/src/ResultSet/ResultSet.test-d.ts b/src/ResultSet/ResultSet.test-d.ts index deb179b65..0da7a2fa4 100644 --- a/src/ResultSet/ResultSet.test-d.ts +++ b/src/ResultSet/ResultSet.test-d.ts @@ -41,6 +41,7 @@ test(`general`, () => { // non-nullable expectTypeOf>().toEqualTypeOf<{ objectNonNull: { id: string | null } }>() + type x= RS<{ objectNonNull: { $scalars: true } }> // scalars-wildcard expectTypeOf>().toEqualTypeOf<{ objectNonNull: { __typename: "Object1"; string: null|string; int: null|number; float: null|number; boolean: null|boolean; id: null|string } }>() // scalars-wildcard with nested object diff --git a/src/Schema/Args.ts b/src/Schema/Args.ts index 92554baa4..37ff38842 100644 --- a/src/Schema/Args.ts +++ b/src/Schema/Args.ts @@ -1,3 +1,4 @@ +import type { Input } from './_.js' import type { Nullable } from './Input/types/Nullable.js' type InputFields = Record @@ -15,3 +16,11 @@ export const Args = (fields: F): Args => { fields, } } + +export type OmitNullableFields<$Fields extends InputFields> = { + [Key in keyof $Fields as $Fields[Key] extends Input.Nullable ? never : Key]: $Fields[Key] +} + +export type PickNullableFields<$Fields extends InputFields> = { + [Key in keyof $Fields as $Fields[Key] extends Input.Nullable ? Key : never]: $Fields[Key] +} diff --git a/src/Schema/Input/types/InputObject.ts b/src/Schema/Input/types/InputObject.ts index 416b016ae..c7db110ff 100644 --- a/src/Schema/Input/types/InputObject.ts +++ b/src/Schema/Input/types/InputObject.ts @@ -1,8 +1,8 @@ -type Fields = Record +export type InputFields = Record export interface InputObject< $Name extends string = string, - $Fields extends Fields = Fields, + $Fields extends InputFields = InputFields, > { kind: 'InputObject' name: $Name diff --git a/src/SelectionSet/SelectionSet.ts b/src/SelectionSet/SelectionSet.ts index ffc27e865..d4ada60b4 100644 --- a/src/SelectionSet/SelectionSet.ts +++ b/src/SelectionSet/SelectionSet.ts @@ -2,7 +2,14 @@ import type { MaybeList, StringNonEmpty, Values } from '../lib/prelude.js' import type { TSError } from '../lib/TSError.js' -import type { InputFieldsAllNullable, Schema, SomeField, SomeFields } from '../Schema/__.js' +import type { + InputFieldsAllNullable, + OmitNullableFields, + PickNullableFields, + Schema, + SomeField, + SomeFields, +} from '../Schema/__.js' export type Query<$Index extends Schema.Index> = $Index['Root']['Query'] extends Schema.Object$2 ? Object<$Index['Root']['Query'], $Index> @@ -242,13 +249,6 @@ type InputField<$InputType extends Schema.Input.Any> = $InputType extends Schema.Enum ? $Members[number] : $InputType extends Schema.Scalar.Any ? ReturnType<$InputType['codec']['decode']> : TSError<'InferTypeInput', 'Unknown $InputType', { $InputType: $InputType }> // never -type OmitNullableFields<$Fields extends Schema.InputObject['fields']> = { - [Key in keyof $Fields as $Fields[Key] extends Schema.Input.Nullable ? never : Key]: $Fields[Key] -} - -type PickNullableFields<$Fields extends Schema.InputObject['fields']> = { - [Key in keyof $Fields as $Fields[Key] extends Schema.Input.Nullable ? Key : never]: $Fields[Key] -} /** * @see https://spec.graphql.org/draft/#sec-Type-System.Directives.Built-in-Directives From f1951437ff107847d4a026a18b97dc00194387f6 Mon Sep 17 00:00:00 2001 From: Jason Kuhrt Date: Fri, 12 Apr 2024 15:42:15 -0400 Subject: [PATCH 10/10] work --- src/ResultSet/ResultSet.test-d.ts | 1 - src/ResultSet/ResultSet.ts | 7 ++----- src/Schema/Output/typeGroups.ts | 6 ++++++ src/Schema/Output/types/Object.ts | 9 +++++++++ 4 files changed, 17 insertions(+), 6 deletions(-) diff --git a/src/ResultSet/ResultSet.test-d.ts b/src/ResultSet/ResultSet.test-d.ts index 0da7a2fa4..deb179b65 100644 --- a/src/ResultSet/ResultSet.test-d.ts +++ b/src/ResultSet/ResultSet.test-d.ts @@ -41,7 +41,6 @@ test(`general`, () => { // non-nullable expectTypeOf>().toEqualTypeOf<{ objectNonNull: { id: string | null } }>() - type x= RS<{ objectNonNull: { $scalars: true } }> // scalars-wildcard expectTypeOf>().toEqualTypeOf<{ objectNonNull: { __typename: "Object1"; string: null|string; int: null|number; float: null|number; boolean: null|boolean; id: null|string } }>() // scalars-wildcard with nested object diff --git a/src/ResultSet/ResultSet.ts b/src/ResultSet/ResultSet.ts index 406274c58..2ba4e823c 100644 --- a/src/ResultSet/ResultSet.ts +++ b/src/ResultSet/ResultSet.ts @@ -4,6 +4,7 @@ import type { Simplify } from 'type-fest' import type { GetKeyOr, SimplifyDeep } from '../lib/prelude.js' import type { TSError } from '../lib/TSError.js' import type { Schema, SomeField } from '../Schema/__.js' +import type { PickScalarFields } from '../Schema/Output/Output.js' import type { SelectionSet } from '../SelectionSet/__.js' // dprint-ignore @@ -27,11 +28,7 @@ export type Object$<$SelectionSet, $Node extends Schema.Output.Object$2, $Index */ ? { - // TODO no more type unwrapped field - [$Key in keyof $Node['fields'] as $Node['fields'][$Key] extends Schema.Field | {'typeUnwrapped':{kind:'Scalar'}} ? $Key : never]: - // eslint-disable-next-line - // @ts-ignore infinite depth issue, can this be fixed? - Field<$SelectionSet, Schema.Field.As<$Node['fields'][$Key]>, $Index> + [$Key in keyof PickScalarFields<$Node>]: Field<$SelectionSet, $Node['fields'][$Key], $Index> } /** * Handle fields in regular way. diff --git a/src/Schema/Output/typeGroups.ts b/src/Schema/Output/typeGroups.ts index 395251f18..0531a5e05 100644 --- a/src/Schema/Output/typeGroups.ts +++ b/src/Schema/Output/typeGroups.ts @@ -12,3 +12,9 @@ export type Named = Interface | Enum | Object$2 | Union | Hybrid.Scalar.Any export type Unnamed = List | Nullable export type Any = Unnamed | Named | __typename + +// dprint-ignore +export type UnwrapToNamed<$Type extends Any> = + $Type extends List ? UnwrapToNamed<$Inner> : + $Type extends Nullable ? UnwrapToNamed<$Inner> : + $Type diff --git a/src/Schema/Output/types/Object.ts b/src/Schema/Output/types/Object.ts index 515d5ada2..3b21d8a9c 100644 --- a/src/Schema/Output/types/Object.ts +++ b/src/Schema/Output/types/Object.ts @@ -1,5 +1,7 @@ import type { Field, SomeFields } from '../../Field.js' import { field } from '../../Field.js' +import type { Hybrid } from '../../Hybrid/__.js' +import type { UnwrapToNamed } from '../typeGroups.js' import { __typename } from './__typename.js' export interface Object$2< @@ -27,3 +29,10 @@ export const Object$ = <$Name extends string, $Fields extends Record = { + [ + $Key in keyof $Object['fields'] as UnwrapToNamed<$Object['fields'][$Key]['type']> extends Hybrid.Scalar.Any | __typename ? $Key : never + ]: $Object['fields'][$Key] +}