diff --git a/.gitignore b/.gitignore index 9e79e27a6..047355489 100644 --- a/.gitignore +++ b/.gitignore @@ -9,3 +9,4 @@ website/.vitepress/.temp website/.vitepress/dist website/.vitepress/cache legacy +project/ diff --git a/eslint.config.js b/eslint.config.js index 66f676e68..f3ad42f05 100644 --- a/eslint.config.js +++ b/eslint.config.js @@ -3,6 +3,7 @@ import tsEslint from 'typescript-eslint' export default tsEslint.config({ ignores: [ + 'project/**/*', 'examples/35_custom-scalar/custom-scalar.ts', 'eslint.config.js', 'vite.config.ts', diff --git a/examples/__outputs__/20_output/output_envelope.output.test.txt b/examples/__outputs__/20_output/output_envelope.output.test.txt index b09812228..01267213e 100644 --- a/examples/__outputs__/20_output/output_envelope.output.test.txt +++ b/examples/__outputs__/20_output/output_envelope.output.test.txt @@ -10,8 +10,6 @@ { name: 'Weedle' } ] }, - errors: undefined, - extensions: undefined, response: Response { status: 200, statusText: 'OK', diff --git a/examples/__outputs__/20_output/output_return-error_return-error-execution__return-error-execution.output.txt b/examples/__outputs__/20_output/output_return-error_return-error-execution__return-error-execution.output.txt index 1ca6a0f70..5beb7aad6 100644 --- a/examples/__outputs__/20_output/output_return-error_return-error-execution__return-error-execution.output.txt +++ b/examples/__outputs__/20_output/output_return-error_return-error-execution__return-error-execution.output.txt @@ -8,7 +8,7 @@ ContextualAggregateError: One or more errors in the execution result. context: {}, cause: undefined, errors: [ - GraphQLError: [ + ContextualError: [ { "code": "too_small", "minimum": 1, @@ -21,15 +21,15 @@ ContextualAggregateError: One or more errors in the execution result. ] } ] - at (/some/path/to/http.ts:XX:XX:47) + at (/some/path/to/handleOutput.ts:XX:XX:16) at Array.map () - at parseExecutionResult (/some/path/to/http.ts:XX:XX:28) - at Object.unpack (/some/path/to/core.ts:XX:XX:26) + at handleOutput (/some/path/to/handleOutput.ts:XX:XX:21) + at executeDocument (/some/path/to/requestMethods.ts:XX:XX:10) at process.processTicksAndRejections (node:internal/process/task_queues:XX:XX) - at async runHook (/some/path/to/runHook.ts:XX:XX:16) { - path: [ 'addPokemon' ], - locations: undefined, - extensions: [Object: null prototype] {} + at async executeRootField (/some/path/to/requestMethods.ts:XX:XX:18) + at async (/some/path/to/output_return-error_return-error-execution__return-error-execution.ts:XX:XX:16) { + context: { locations: [ { line: 2, column: 3 } ], path: [ 'addPokemon' ] }, + cause: undefined } ] } diff --git a/package.json b/package.json index 4a562cb9d..684dda113 100644 --- a/package.json +++ b/package.json @@ -84,6 +84,7 @@ "check:publint": "publint run --strict", "prepublishOnly": "pnpm build", "build:docs": "doctoc README.md --notitle && dprint fmt README.md", + "build:emit": "pnpm clean && pnpm tsc --noCheck --project tsconfig.build.json && chmod +x ./build/generator/cli/generate.js", "build": "pnpm clean && pnpm tsc --project tsconfig.build.json && chmod +x ./build/generator/cli/generate.js", "clean": "tsc --build --clean && rm -rf build", "test:unit": "vitest --exclude tests/examples", diff --git a/src/documentBuilder/Select/document.ts b/src/documentBuilder/Select/document.ts index dc13ec7c5..0b5c52f4d 100644 --- a/src/documentBuilder/Select/document.ts +++ b/src/documentBuilder/Select/document.ts @@ -80,7 +80,7 @@ export const createDocumentNormalizedFromRootTypeSelection = ( operations: { [operationName ?? defaultOperationName]: { name: operationName ?? null, - type: Grafaid.RootTypeNameToOperationName[rootTypeName], + type: Grafaid.Document.RootTypeToOperationType[rootTypeName], rootType: rootTypeName, selectionSet, }, @@ -100,7 +100,7 @@ export const normalizeOrThrow = (document: DocumentObject): DocumentNormalized = [name, selectionSet], ): [name: string, OperationNormalized] => [name, { name, - type: Grafaid.RootTypeNameToOperationName[Grafaid.Schema.RootTypeName.Query], + type: Grafaid.Document.RootTypeToOperationType[Grafaid.Schema.RootTypeName.Query], rootType: Grafaid.Schema.RootTypeName.Query, selectionSet, }]) @@ -108,7 +108,7 @@ export const normalizeOrThrow = (document: DocumentObject): DocumentNormalized = [name, selectionSet], ): [name: string, OperationNormalized] => [name, { name, - type: Grafaid.RootTypeNameToOperationName[Grafaid.Schema.RootTypeName.Mutation], + type: Grafaid.Document.RootTypeToOperationType[Grafaid.Schema.RootTypeName.Mutation], rootType: Grafaid.Schema.RootTypeName.Mutation, selectionSet, }]) diff --git a/src/generator/generators/MethodsRoot.ts b/src/generator/generators/MethodsRoot.ts index c29cc1733..9d5dadb28 100644 --- a/src/generator/generators/MethodsRoot.ts +++ b/src/generator/generators/MethodsRoot.ts @@ -30,8 +30,8 @@ export const ModuleGeneratorMethodsRoot = createModuleGenerator( export interface BuilderMethodsRoot<$Context extends ${identifiers.$$Utilities}.ClientContext> { ${ config.schema.kindMap.Root.map(node => { - const operationName = - Grafaid.RootTypeNameToOperationName[node.name as keyof typeof Grafaid.RootTypeNameToOperationName] + const operationName = Grafaid.Document + .RootTypeToOperationType[node.name as keyof typeof Grafaid.Document.RootTypeToOperationType] return `${operationName}: ${node.name}Methods<$Context>` }).join(`\n`) } diff --git a/src/layers/5_request/core.ts b/src/layers/5_request/core.ts index 5d1afca1c..448767fa4 100644 --- a/src/layers/5_request/core.ts +++ b/src/layers/5_request/core.ts @@ -1,10 +1,8 @@ -import { type ExecutionResult } from 'graphql' import { SelectionSetGraphqlMapper } from '../../documentBuilder/SelectGraphQLMapper/__.js' import { Anyware } from '../../lib/anyware/__.js' -import type { Grafaid } from '../../lib/grafaid/__.js' +import { Grafaid } from '../../lib/grafaid/__.js' import { getOperationDefinition, OperationTypeToAccessKind, print } from '../../lib/grafaid/document.js' -import { execute } from '../../lib/grafaid/execute.js' -import { operationTypeToRootType } from '../../lib/grafaid/graphql.js' +import { execute } from '../../lib/grafaid/execute.js' // todo import { getRequestEncodeSearchParameters, getRequestHeadersRec, @@ -44,7 +42,7 @@ export const graffleMappedResultToRequest = ( if (!operation_) throw new Error(`Unknown operation named "${String(operationName)}".`) return { - rootType: operationTypeToRootType[operation_.operation], + rootType: Grafaid.Document.OperationTypeToRootType[operation_.operation], operationName, operation: operation_, query: document, @@ -52,7 +50,8 @@ export const graffleMappedResultToRequest = ( } } -export const anyware = Anyware.create({ +// todo execution result only if transport is memory +export const anyware = Anyware.create({ // If core errors caused by an abort error then raise it as a direct error. // This is an expected possible error. Possible when user cancels a request. passthroughErrorWith: (signal) => { diff --git a/src/layers/5_request/hooks.ts b/src/layers/5_request/hooks.ts index 20a87cce6..60417a2be 100644 --- a/src/layers/5_request/hooks.ts +++ b/src/layers/5_request/hooks.ts @@ -1,4 +1,4 @@ -import type { ExecutionResult, GraphQLSchema } from 'graphql' +import type { FormattedExecutionResult, GraphQLSchema } from 'graphql' import type { Select } from '../../documentBuilder/Select/__.js' import type { Grafaid } from '../../lib/grafaid/__.js' import type { getRequestEncodeSearchParameters, postRequestEncodeBody } from '../../lib/grafaid/http/http.js' @@ -96,7 +96,7 @@ export type HookDefUnpack<$Config extends Config> = { & TransportInput< $Config, { response: Response }, - { result: ExecutionResult } + { result: FormattedExecutionResult } > } @@ -108,7 +108,7 @@ export type HookDefDecode<$Config extends Config> = { $Config, { response: Response } > - & { result: ExecutionResult } + & { result: FormattedExecutionResult } } export type HookMap<$Config extends Config = Config> = { diff --git a/src/layers/6_client/client.ts b/src/layers/6_client/client.ts index 74aff5993..0642acf54 100644 --- a/src/layers/6_client/client.ts +++ b/src/layers/6_client/client.ts @@ -1,4 +1,4 @@ -import { CustomScalars } from '../../extensions/CustomScalars/CustomScalars.js' +import { CustomScalars } from '../../extensions/CustomScalars/CustomScalars.js' // todo import type { ConfigManager } from '../../lib/config-manager/__.js' import type { Fluent } from '../../lib/fluent/__.js' import { proxyGet } from '../../lib/prelude.js' @@ -11,7 +11,7 @@ import type { FnInternal } from './properties/internal.js' import { type FnRetry, retryProperties } from './properties/retry.js' import { type ScalarFn, scalarProperties } from './properties/scalar.js' import { type FnWith, withProperties } from './properties/with.js' -import { type FnRequestMethods, requestMethodsProperties } from './requestMethods/requestMethods.js' +import { type FnRequestMethods, requestMethodsProperties } from './requestMethods/requestMethods.js' // todo import { type InputStatic } from './Settings/Input.js' import { type NormalizeInput } from './Settings/InputToConfig.js' diff --git a/src/layers/6_client/gql/gql.ts b/src/layers/6_client/gql/gql.ts index 086457009..51fbe87f3 100644 --- a/src/layers/6_client/gql/gql.ts +++ b/src/layers/6_client/gql/gql.ts @@ -1,13 +1,12 @@ import type { Fluent } from '../../../lib/fluent/__.js' import type { Grafaid } from '../../../lib/grafaid/__.js' -import { getOperationType } from '../../../lib/grafaid/document.js' -import { operationTypeToRootType } from '../../../lib/grafaid/graphql.js' +import { getOperationType, OperationTypeToRootType } from '../../../lib/grafaid/document.js' import { isTemplateStringArguments, joinTemplateStringArrayAndArgs, type TemplateStringsArguments, } from '../../../lib/template-string.js' -import { RequestCore } from '../../5_request/__.js' +import { RequestCore } from '../../5_request/__.js' // todo import type { InterfaceRaw } from '../../5_request/types.js' import { type ClientContext, defineTerminus } from '../fluent.js' import { handleOutput } from '../handleOutput.js' @@ -55,7 +54,7 @@ export const gqlProperties = defineTerminus((state) => { if (!operationType) throw new Error(`Could not get operation type`) const analyzedRequest = { - rootType: operationTypeToRootType[operationType], + rootType: OperationTypeToRootType[operationType], operation: operationType, query, variables, diff --git a/src/layers/6_client/handleOutput.ts b/src/layers/6_client/handleOutput.ts index 14de62715..17b2ffafc 100644 --- a/src/layers/6_client/handleOutput.ts +++ b/src/layers/6_client/handleOutput.ts @@ -1,5 +1,6 @@ import type { GraphQLError } from 'graphql' import { Errors } from '../../lib/errors/__.js' +import type { Grafaid } from '../../lib/grafaid/__.js' import type { SomeObjectData } from '../../lib/grafaid/graphql.js' import type { GraphQLExecutionResultError } from '../../lib/grafaid/graphql.js' import { @@ -32,7 +33,12 @@ export type ErrorsOther = export type GraffleExecutionResultEnvelope<$Config extends Config = Config> = // & ExecutionResult & { - errors?: ReadonlyArray + errors?: ReadonlyArray< + // formatted comes from http transport + | Grafaid.FormattedExecutionResultError + // unformatted comes from memory transport + | Grafaid.GraphQLError + > data?: SomeObjectData | null extensions?: ObjMap } @@ -91,7 +97,11 @@ export const handleOutput = ( const error = new Errors.ContextualAggregateError( `One or more errors in the execution result.`, {}, - result.errors, + result.errors.map(e => { + if (e instanceof Error) return e + const { message, ...context } = e + return new Errors.ContextualError(message, context) + }), ) if (isThrowExecution) throw error if (isReturnExecution) return error diff --git a/src/lib/grafaid/document.ts b/src/lib/grafaid/document.ts index 575d9ba37..97a4f37de 100644 --- a/src/lib/grafaid/document.ts +++ b/src/lib/grafaid/document.ts @@ -9,7 +9,6 @@ import { type FragmentSpreadNode, type InlineFragmentNode, type IntValueNode, - Kind, type ListValueNode, type NamedTypeNode, type NameNode, @@ -17,7 +16,6 @@ import { type ObjectFieldNode, type ObjectValueNode, type OperationDefinitionNode, - OperationTypeNode, parse, print as graphqlPrint, type SelectionSetNode, @@ -29,7 +27,10 @@ import { } from 'graphql' import type { HasRequiredKeys } from 'type-fest' import { isString } from '../prelude.js' +import { Kind } from './document/kind.js' +import { OperationTypeNode } from './document/OperationTypeNode.js' import type { RequestDocumentNodeInput, RequestInput } from './graphql.js' +import { RootTypeName } from './schema/schema.js' import { TypedDocument } from './typed-document/__.js' export type { @@ -50,7 +51,6 @@ export type { ObjectValueNode, OperationDefinitionNode, OperationTypeDefinitionNode, - OperationTypeNode, SelectionNode, SelectionSetNode, StringValueNode, @@ -59,7 +59,9 @@ export type { VariableNode, } from 'graphql' -export { Kind } from 'graphql' +export { OperationTypeNode } from './document/OperationTypeNode.js' + +export { Kind } from './document/kind.js' export * as Typed from './typed-document/TypedDocument.js' @@ -253,12 +255,25 @@ export const ObjectField: Constructor = (objectField) => { } } +export const RootTypeToOperationType = { + Query: OperationTypeNode.QUERY, + Mutation: OperationTypeNode.MUTATION, + Subscription: OperationTypeNode.SUBSCRIPTION, +} as const +export type RootTypeNameToOperationName = typeof RootTypeToOperationType + export const OperationTypeToAccessKind = { query: `read`, mutation: `write`, subscription: `read`, } as const +export const OperationTypeToRootType = { + query: RootTypeName.Query, + mutation: RootTypeName.Mutation, + subscription: RootTypeName.Subscription, +} as const + export const print = (document: TypedDocument.TypedDocumentLike): string => { const documentUntyped = TypedDocument.unType(document) return isString(documentUntyped) ? documentUntyped : graphqlPrint(documentUntyped) @@ -291,6 +306,7 @@ const definedOperationPattern = new RegExp(`^\\b(${Object.values(OperationTypeNo * to avoid document encode/decode performance costs. */ export const getOperationType = (request: RequestInput): OperationTypeNode | null => { + // return null const { operationName, query: document } = request const documentUntyped = TypedDocument.unType(document) diff --git a/src/lib/grafaid/document/OperationTypeNode.ts b/src/lib/grafaid/document/OperationTypeNode.ts new file mode 100644 index 000000000..dc4f49280 --- /dev/null +++ b/src/lib/grafaid/document/OperationTypeNode.ts @@ -0,0 +1,8 @@ +/** + * This is a tree-shakable version of https://github.com/graphql/graphql-js/blob/16.x.x/src/language/kinds.ts + */ + +import type { OperationTypeNode as GraphQLOperationTypeNode } from 'graphql' + +export type OperationTypeNode = GraphQLOperationTypeNode +export * as OperationTypeNode from './OperationTypeNodes.js' diff --git a/src/lib/grafaid/document/OperationTypeNodes.ts b/src/lib/grafaid/document/OperationTypeNodes.ts new file mode 100644 index 000000000..3362b1a04 --- /dev/null +++ b/src/lib/grafaid/document/OperationTypeNodes.ts @@ -0,0 +1,9 @@ +/** + * This is a tree-shakable version of https://github.com/graphql/graphql-js/blob/16.x.x/src/language/ast.ts#L326-L331 + */ + +import type { OperationTypeNode as GraphQLOperationTypeNode } from 'graphql' + +export const QUERY = `query` as GraphQLOperationTypeNode.QUERY +export const MUTATION = `mutation` as GraphQLOperationTypeNode.MUTATION +export const SUBSCRIPTION = `subscription` as GraphQLOperationTypeNode.SUBSCRIPTION diff --git a/src/lib/grafaid/document/kind.ts b/src/lib/grafaid/document/kind.ts new file mode 100644 index 000000000..c4b539471 --- /dev/null +++ b/src/lib/grafaid/document/kind.ts @@ -0,0 +1,9 @@ +/** + * This is a tree-shakable version of https://github.com/graphql/graphql-js/blob/16.x.x/src/language/kinds.ts + */ + +import type { Kind as GraphQLKind } from 'graphql' + +export * as Kind from './kinds.js' + +export type Kind = GraphQLKind diff --git a/src/lib/grafaid/document/kinds.ts b/src/lib/grafaid/document/kinds.ts new file mode 100644 index 000000000..22f0b06cd --- /dev/null +++ b/src/lib/grafaid/document/kinds.ts @@ -0,0 +1,63 @@ +import type { Kind as GraphQLKind } from 'graphql' + +export const NAME = `Name` as GraphQLKind.NAME +export const DOCUMENT = `Document` as GraphQLKind.DOCUMENT +export const OPERATION_DEFINITION = `OperationDefinition` as GraphQLKind.OPERATION_DEFINITION +export const VARIABLE_DEFINITION = `VariableDefinition` as GraphQLKind.VARIABLE_DEFINITION +export const SELECTION_SET = `SelectionSet` as GraphQLKind.SELECTION_SET +export const FIELD = `Field` as GraphQLKind.FIELD +export const ARGUMENT = `Argument` as GraphQLKind.ARGUMENT + +/** Fragments */ +export const FRAGMENT_SPREAD = `FragmentSpread` as GraphQLKind.FRAGMENT_SPREAD +export const INLINE_FRAGMENT = `InlineFragment` as GraphQLKind.INLINE_FRAGMENT +export const FRAGMENT_DEFINITION = `FragmentDefinition` as GraphQLKind.FRAGMENT_DEFINITION + +/** Values */ +export const VARIABLE = `Variable` as GraphQLKind.VARIABLE +export const INT = `IntValue` as GraphQLKind.INT +export const FLOAT = `FloatValue` as GraphQLKind.FLOAT +export const STRING = `StringValue` as GraphQLKind.STRING +export const BOOLEAN = `BooleanValue` as GraphQLKind.BOOLEAN +export const NULL = `NullValue` as GraphQLKind.NULL +export const ENUM = `EnumValue` as GraphQLKind.ENUM +export const LIST = `ListValue` as GraphQLKind.LIST +export const OBJECT = `ObjectValue` as GraphQLKind.OBJECT +export const OBJECT_FIELD = `ObjectField` as GraphQLKind.OBJECT_FIELD + +/** Directives */ +export const DIRECTIVE = `Directive` as GraphQLKind.DIRECTIVE + +/** Types */ +export const NAMED_TYPE = `NamedType` as GraphQLKind.NAMED_TYPE +export const LIST_TYPE = `ListType` as GraphQLKind.LIST_TYPE +export const NON_NULL_TYPE = `NonNullType` as GraphQLKind.NON_NULL_TYPE + +/** Type System Definitions */ +export const SCHEMA_DEFINITION = `SchemaDefinition` as GraphQLKind.SCHEMA_DEFINITION +export const OPERATION_TYPE_DEFINITION = `OperationTypeDefinition` as GraphQLKind.OPERATION_TYPE_DEFINITION + +/** Type Definitions */ +export const SCALAR_TYPE_DEFINITION = `ScalarTypeDefinition` as GraphQLKind.SCALAR_TYPE_DEFINITION +export const OBJECT_TYPE_DEFINITION = `ObjectTypeDefinition` as GraphQLKind.OBJECT_TYPE_DEFINITION +export const FIELD_DEFINITION = `FieldDefinition` as GraphQLKind.FIELD_DEFINITION +export const INPUT_VALUE_DEFINITION = `InputValueDefinition` as GraphQLKind.INPUT_VALUE_DEFINITION +export const INTERFACE_TYPE_DEFINITION = `InterfaceTypeDefinition` as GraphQLKind.INTERFACE_TYPE_DEFINITION +export const UNION_TYPE_DEFINITION = `UnionTypeDefinition` as GraphQLKind.UNION_TYPE_DEFINITION +export const ENUM_TYPE_DEFINITION = `EnumTypeDefinition` as GraphQLKind.ENUM_TYPE_DEFINITION +export const ENUM_VALUE_DEFINITION = `EnumValueDefinition` as GraphQLKind.ENUM_VALUE_DEFINITION +export const INPUT_OBJECT_TYPE_DEFINITION = `InputObjectTypeDefinition` as GraphQLKind.INPUT_OBJECT_TYPE_DEFINITION + +/** Directive Definitions */ +export const DIRECTIVE_DEFINITION = `DirectiveDefinition` as GraphQLKind.DIRECTIVE_DEFINITION + +/** Type System Extensions */ +export const SCHEMA_EXTENSION = `SchemaExtension` as GraphQLKind.SCHEMA_EXTENSION + +/** Type Extensions */ +export const SCALAR_TYPE_EXTENSION = `ScalarTypeExtension` as GraphQLKind.SCALAR_TYPE_EXTENSION +export const OBJECT_TYPE_EXTENSION = `ObjectTypeExtension` as GraphQLKind.OBJECT_TYPE_EXTENSION +export const INTERFACE_TYPE_EXTENSION = `InterfaceTypeExtension` as GraphQLKind.INTERFACE_TYPE_EXTENSION +export const UNION_TYPE_EXTENSION = `UnionTypeExtension` as GraphQLKind.UNION_TYPE_EXTENSION +export const ENUM_TYPE_EXTENSION = `EnumTypeExtension` as GraphQLKind.ENUM_TYPE_EXTENSION +export const INPUT_OBJECT_TYPE_EXTENSION = `InputObjectTypeExtension` as GraphQLKind.INPUT_OBJECT_TYPE_EXTENSION diff --git a/src/lib/grafaid/graphql.ts b/src/lib/grafaid/graphql.ts index 6a4d2c63b..90703c057 100644 --- a/src/lib/grafaid/graphql.ts +++ b/src/lib/grafaid/graphql.ts @@ -1,18 +1,18 @@ import type { GraphQLNamedType, GraphQLScalarType } from 'graphql' -import { - isEnumType, - isInputObjectType, - isInterfaceType, - isObjectType, - isScalarType, - isUnionType, - OperationTypeNode, -} from 'graphql' +import { isEnumType, isInputObjectType, isInterfaceType, isObjectType, isScalarType, isUnionType } from 'graphql' import { casesExhausted } from '../prelude.js' import type { KindMap } from './schema/schema.js' import { isRootType, isScalarTypeCustom } from './schema/schema.js' +export { + type ExecutionResult, + type FormattedExecutionResult, + GraphQLError, + type GraphQLFormattedError as FormattedExecutionResultError, +} from 'graphql' + export * from './_Nodes.js' + export * from './request.js' export const StandardScalarTypeNames = { @@ -43,20 +43,6 @@ export const StandardScalarTypeTypeScriptMapping = { TypeScriptPrimitiveTypeNames > -export const operationTypeToRootType = { - query: `Query`, - mutation: `Mutation`, - subscription: `Subscription`, -} as const - -export const RootTypeNameToOperationName = { - Query: OperationTypeNode.QUERY, - Mutation: OperationTypeNode.MUTATION, - Subscription: OperationTypeNode.SUBSCRIPTION, -} as const - -export type RootTypeNameToOperationName = typeof RootTypeNameToOperationName - export const isStandardScalarType = (type: GraphQLScalarType) => { return type.name in StandardScalarTypeNames } diff --git a/src/lib/grafaid/http/http.ts b/src/lib/grafaid/http/http.ts index 9efdb84c4..94d0b6ac2 100644 --- a/src/lib/grafaid/http/http.ts +++ b/src/lib/grafaid/http/http.ts @@ -1,5 +1,4 @@ -import type { GraphQLFormattedError } from 'graphql' -import { type ExecutionResult, GraphQLError } from 'graphql' +import type { FormattedExecutionResult, GraphQLFormattedError } from 'graphql' import { CONTENT_TYPE_GQL, CONTENT_TYPE_JSON } from '../../http.js' import { isRecordLikeObject } from '../../prelude.js' import type { Variables } from '../graphql.js' @@ -10,15 +9,11 @@ export interface RequestConfig { operationName?: string } -export const parseExecutionResult = (result: unknown): ExecutionResult => { +export const parseExecutionResult = (result: unknown): FormattedExecutionResult => { if (typeof result !== `object` || result === null) { throw new Error(`Invalid execution result: result is not object`) } - let errors = undefined - let data = undefined - let extensions = undefined - if (`errors` in result) { if ( !Array.isArray(result.errors) @@ -28,9 +23,11 @@ export const parseExecutionResult = (result: unknown): ExecutionResult => { ) { throw new Error(`Invalid execution result: errors is not array of formatted errors`) // prettier-ignore } - errors = result.errors.map((error: GraphQLFormattedError) => - error instanceof GraphQLError ? error : new GraphQLError(error.message, error) - ) + result.errors.forEach(maybeError => { + if (!isFormattedError(maybeError)) { + throw new Error(`Invalid value in errors array.`) // prettier-ignore + } + }) } // todo add test coverage for case of null. @see https://github.com/graffle-js/graffle/issues/739 @@ -38,21 +35,15 @@ export const parseExecutionResult = (result: unknown): ExecutionResult => { if (!isRecordLikeObject(result.data) && result.data !== null) { throw new Error(`Invalid execution result: data is not plain object`) // prettier-ignore } - data = result.data } if (`extensions` in result) { if (!isRecordLikeObject(result.extensions)) { throw new Error(`Invalid execution result: extensions is not plain object`) // prettier-ignore } - extensions = result.extensions } - return { - data, - errors, - extensions, - } + return result } /** @@ -93,3 +84,8 @@ export const postRequestEncodeBody = (input: RequestConfig): BodyInit => { } export type postRequestEncodeBody = typeof postRequestEncodeBody + +// todo make this more robust +export const isFormattedError = (error: unknown): error is GraphQLFormattedError => { + return isRecordLikeObject(error) && `message` in error && typeof error[`message`] === `string` +} diff --git a/tests/e2e/tests.txt b/tests/e2e/tests.txt new file mode 100644 index 000000000..6d92cf078 --- /dev/null +++ b/tests/e2e/tests.txt @@ -0,0 +1,16 @@ +- new project no generation + - type error if try give name to constructor + +- new project with 1 client generation + - type error if try give name to constructor + - can use static client + - can use generated client import + +- new project with 2 client generation + - type error if give wrong name to constructor + - can give right name to constructor + - can use static client + - can use generated clients import + + +...?