From 61b6f509eed2e5b9c1108de46f1246cbedd2e589 Mon Sep 17 00:00:00 2001 From: Jason Kuhrt Date: Sun, 13 Oct 2024 18:18:25 -0400 Subject: [PATCH] feat(gql): encode custom scalars (#1178) --- ...ware_slot_slot-body__slot-search-params.ts | 12 +- ...tension_headers__dynamicHeaders.output.txt | 2 +- .../transport-http_method-get.output.txt | 8 +- .../20_output/output_envelope.output.txt | 2 +- ..._envelope-error__envelope-error.output.txt | 2 +- ...ror-throw__envelope-error-throw.output.txt | 2 +- ...output_preset__standard-graphql.output.txt | 8 +- .../20_output/output_return-error.output.txt | 2 +- ...ecution__return-error-execution.output.txt | 4 +- ...gql-typed-graphql-document-node.output.txt | 20 - ...DocumentNode__raw-document-node.output.txt | 20 - ...wTyped__raw-document-node-typed.output.txt | 20 - .../raw_rawString__rawString.output.txt | 20 - ...tring_rawTyped__rawString-typed.output.txt | 20 - ...t_slot-body__slot-search-params.output.txt | 33 +- ...on_opentelemetry__opentelemetry.output.txt | 58 +- src/entrypoints/_Print.ts | 2 +- src/entrypoints/utilities-for-generated.ts | 1 + .../1_Schema/Hybrid/types/Scalar/Scalar.ts | 27 +- .../1_Schema/Hybrid/types/Scalar/codec.ts | 6 +- src/layers/2_Select/$parseSelection.ts | 134 +- src/layers/2_Select/SelectAlias.ts | 2 +- src/layers/2_Select/document.ts | 14 +- src/layers/3_SelectGraphQLMapper/_.ts | 3 +- .../__snapshots__/toGraphQL.test.ts.snap | 2463 +++++++++++++++++ src/layers/3_SelectGraphQLMapper/context.ts | 64 + src/layers/3_SelectGraphQLMapper/helpers.ts | 22 - .../inferVariableType.ts | 36 + src/layers/3_SelectGraphQLMapper/mapper.ts | 26 + .../3_SelectGraphQLMapper/nodes/1_Document.ts | 43 + .../nodes/2_OperationDefinition.ts | 54 + .../nodes/3_GraffleSelectionSetRoot.ts | 24 + .../nodes/4_GraffleSelectionObjectLevel.ts | 62 + .../3_SelectGraphQLMapper/nodes/5_Field.ts | 87 + .../nodes/5_InlineFragments.ts | 65 + .../3_SelectGraphQLMapper/nodes/Argument.ts | 21 +- .../3_SelectGraphQLMapper/nodes/Directive.ts | 62 +- .../nodes/Document.test.ts | 143 - .../3_SelectGraphQLMapper/nodes/Document.ts | 22 - .../3_SelectGraphQLMapper/nodes/Field.ts | 45 - .../nodes/InlineFragment.ts | 41 - .../nodes/OperationDefinition.ts | 29 - .../nodes/SelectionSet.ts | 115 - .../3_SelectGraphQLMapper/nodes/Value.ts | 48 +- .../nodes/__snapshots__/Document.test.ts.snap | 847 ------ .../3_SelectGraphQLMapper/nodes/_collect.ts | 34 + .../3_SelectGraphQLMapper/toGraphQL.test.ts | 114 + src/layers/3_SelectGraphQLMapper/types.ts | 94 - .../__snapshots__/generate.test.ts.snap | 1861 ++++++++++--- src/layers/4_generator/config.ts | 14 +- src/layers/4_generator/generate.test.ts | 12 +- src/layers/4_generator/generate.ts | 6 +- src/layers/4_generator/generators/Client.ts | 10 +- src/layers/4_generator/generators/Data.ts | 8 +- .../4_generator/generators/MethodsRoot.ts | 32 +- .../4_generator/generators/SchemaBuildtime.ts | 74 +- .../4_generator/generators/SchemaIndex.ts | 28 +- .../4_generator/generators/SchemaRuntime.ts | 277 -- .../4_generator/generators/SelectionSets.ts | 87 +- src/layers/4_generator/globalRegistry.ts | 2 +- src/layers/4_generator/helpers/render.ts | 43 +- src/layers/5_request/core.ts | 94 +- src/layers/5_request/hooks.ts | 12 +- src/layers/5_request/schemaErrors.test.ts | 50 - src/layers/5_request/schemaErrors.ts | 34 +- src/layers/6_client/Settings/Config.ts | 5 +- src/layers/6_client/Settings/Input.ts | 16 +- src/layers/6_client/Settings/InputToConfig.ts | 16 +- .../client.create.config.output.test-d.ts | 15 +- .../inputIncrementable/inputIncrementable.ts | 4 +- .../6_client/client.transport-http.test.ts | 4 +- src/layers/6_client/client.ts | 23 +- src/layers/6_client/fluent.ts | 3 +- src/layers/6_client/gql/gql.test-d.ts | 58 +- src/layers/6_client/gql/gql.test.ts | 4 +- src/layers/6_client/gql/gql.ts | 69 +- src/layers/6_client/gql/send.test-d.ts | 14 +- src/layers/6_client/gql/send.ts | 20 +- src/layers/6_client/handleOutput.ts | 25 +- src/layers/6_client/prefilled.ts | 13 +- .../client.rootMethods.test-d.ts | 16 +- .../requestMethods/client.rootMethods.test.ts | 6 +- .../6_client/requestMethods/document.test.ts | 10 +- .../6_client/requestMethods/requestMethods.ts | 63 +- .../RuntimeIndexCustomScalars.ts | 177 -- src/layers/7_customScalars/decode.ts | 102 - src/layers/7_customScalars/encode.ts | 17 - src/layers/7_customScalars/extension.ts | 27 - .../CustomScalars/CustomScalars.ts | 41 + .../CustomScalars}/decode.test.ts | 26 +- .../7_extensions/CustomScalars/decode.ts | 86 + .../7_extensions/CustomScalars/encode.test.ts | 46 + .../7_extensions/CustomScalars/encode.ts | 61 + .../schemaDrivenDataMap/generator.ts | 390 +++ .../schemaDrivenDataMap/types.ts | 166 ++ .../SchemaErrors/SchemaErrors.test.ts | 100 + .../7_extensions/SchemaErrors/SchemaErrors.ts | 26 + src/layers/7_extensions/Throws/Throws.test.ts | 12 - src/layers/7_extensions/Upload/Upload.test.ts | 3 +- src/lib/Code.ts | 96 +- src/lib/anyware/__.test-d.ts | 1 - src/lib/grafaid/_.ts | 4 +- src/lib/grafaid/document.ts | 105 +- src/lib/grafaid/graphql.test.ts | 4 +- src/lib/grafaid/graphql.ts | 165 +- src/lib/grafaid/request.ts | 62 + src/lib/grafaid/schema/customScalars.ts | 4 +- src/lib/grafaid/schema/schema.ts | 116 +- .../grafaid/typed-document/TypedDocument.ts | 16 +- src/lib/prelude.ts | 15 + src/lib/template-string.ts | 17 + tests/_/SpyExtension.ts | 42 +- .../kitchen-sink/graffle/modules/Client.ts | 5 +- .../kitchen-sink/graffle/modules/Data.ts | 2 + .../graffle/modules/MethodsRoot.ts | 140 +- .../graffle/modules/RuntimeCustomScalars.ts | 217 -- .../graffle/modules/SchemaBuildtime.ts | 12 + .../graffle/modules/SchemaDrivenDataMap.ts | 735 +++++ .../graffle/modules/SchemaRuntime.ts | 370 --- .../graffle/modules/SelectionSets.ts | 36 + tests/_/schemas/kitchen-sink/schema.graphql | 6 + tests/_/schemas/kitchen-sink/schema.ts | 12 + .../mutation-only/graffle/modules/Client.ts | 5 +- .../mutation-only/graffle/modules/Data.ts | 2 + .../graffle/modules/MethodsRoot.ts | 8 +- .../graffle/modules/RuntimeCustomScalars.ts | 49 +- .../graffle/modules/SchemaDrivenDataMap.ts | 204 ++ .../graffle/modules/SchemaRuntime.ts | 42 - .../schemas/pokemon/graffle/modules/Client.ts | 5 +- .../_/schemas/pokemon/graffle/modules/Data.ts | 2 + .../graffle/modules/RuntimeCustomScalars.ts | 285 +- .../graffle/modules/SchemaDrivenDataMap.ts | 459 +++ .../pokemon/graffle/modules/SchemaRuntime.ts | 228 -- .../query-only/graffle/modules/Client.ts | 5 +- .../query-only/graffle/modules/Data.ts | 2 + .../query-only/graffle/modules/MethodsRoot.ts | 8 +- .../graffle/modules/RuntimeCustomScalars.ts | 49 +- .../graffle/modules/SchemaDrivenDataMap.ts | 102 +- .../graffle/modules/SchemaRuntime.ts | 41 - website/.vitepress/config.ts | 2 +- .../anyware/slot-search-params.detail.md | 42 +- .../examples/anyware/slot-search-params.md | 42 +- .../extension/opentelemetry.detail.md | 58 +- .../examples/extension/opentelemetry.md | 58 +- .../output/envelope-error-throw.detail.md | 2 +- .../examples/output/envelope-error-throw.md | 2 +- .../examples/output/envelope-error.detail.md | 2 +- .../examples/output/envelope-error.md | 2 +- .../examples/output/envelope.detail.md | 2 +- .../_snippets/examples/output/envelope.md | 2 +- .../output/return-error-execution.detail.md | 8 +- .../examples/output/return-error-execution.md | 8 +- .../examples/output/return-error.detail.md | 2 +- .../_snippets/examples/output/return-error.md | 2 +- .../output/standard-graphql.detail.md | 14 +- .../examples/output/standard-graphql.md | 14 +- .../transport-http/dynamic-headers.detail.md | 2 +- .../transport-http/dynamic-headers.md | 2 +- .../transport-http/method-get.detail.md | 8 +- .../examples/transport-http/method-get.md | 8 +- .../10_transport-http/dynamic-headers.md | 2 +- .../examples/10_transport-http/method-get.md | 8 +- .../20_output/envelope-error-throw.md | 2 +- .../examples/20_output/envelope-error.md | 2 +- .../content/examples/20_output/envelope.md | 2 +- .../20_output/return-error-execution.md | 8 +- .../examples/20_output/return-error.md | 2 +- .../examples/20_output/standard-graphql.md | 14 +- .../examples/50_anyware/slot-search-params.md | 42 +- .../examples/60_extension/opentelemetry.md | 58 +- website/graffle/modules/Client.ts | 5 +- website/graffle/modules/Data.ts | 2 + .../modules/SchemaCustomScalarIndex.ts | 0 .../graffle/modules/SchemaDrivenDataMap.ts | 379 +++ website/graffle/modules/SchemaRuntime.ts | 2 +- website/pokemon/modules/Client.ts | 5 +- website/pokemon/modules/Data.ts | 2 + .../pokemon/modules/SchemaDrivenDataMap.ts | 459 +++ website/pokemon/modules/SchemaRuntime.ts | 2 +- 179 files changed, 9660 insertions(+), 4587 deletions(-) delete mode 100644 examples/__outputs__/30_gql/gql_gql-document-node_gql-typed_gql-typed-graphql-document-node__gql-typed-graphql-document-node.output.txt delete mode 100644 examples/__outputs__/30_raw 11-54-53-229/raw_rawDocumentNode__raw-document-node.output.txt delete mode 100644 examples/__outputs__/30_raw 11-54-53-229/raw_rawDocumentNode_rawTyped__raw-document-node-typed.output.txt delete mode 100644 examples/__outputs__/30_raw 11-54-53-229/raw_rawString__rawString.output.txt delete mode 100644 examples/__outputs__/30_raw 11-54-53-229/raw_rawString_rawTyped__rawString-typed.output.txt create mode 100644 src/layers/3_SelectGraphQLMapper/__snapshots__/toGraphQL.test.ts.snap create mode 100644 src/layers/3_SelectGraphQLMapper/context.ts delete mode 100644 src/layers/3_SelectGraphQLMapper/helpers.ts create mode 100644 src/layers/3_SelectGraphQLMapper/inferVariableType.ts create mode 100644 src/layers/3_SelectGraphQLMapper/mapper.ts create mode 100644 src/layers/3_SelectGraphQLMapper/nodes/1_Document.ts create mode 100644 src/layers/3_SelectGraphQLMapper/nodes/2_OperationDefinition.ts create mode 100644 src/layers/3_SelectGraphQLMapper/nodes/3_GraffleSelectionSetRoot.ts create mode 100644 src/layers/3_SelectGraphQLMapper/nodes/4_GraffleSelectionObjectLevel.ts create mode 100644 src/layers/3_SelectGraphQLMapper/nodes/5_Field.ts create mode 100644 src/layers/3_SelectGraphQLMapper/nodes/5_InlineFragments.ts delete mode 100644 src/layers/3_SelectGraphQLMapper/nodes/Document.test.ts delete mode 100644 src/layers/3_SelectGraphQLMapper/nodes/Document.ts delete mode 100644 src/layers/3_SelectGraphQLMapper/nodes/Field.ts delete mode 100644 src/layers/3_SelectGraphQLMapper/nodes/InlineFragment.ts delete mode 100644 src/layers/3_SelectGraphQLMapper/nodes/OperationDefinition.ts delete mode 100644 src/layers/3_SelectGraphQLMapper/nodes/SelectionSet.ts delete mode 100644 src/layers/3_SelectGraphQLMapper/nodes/__snapshots__/Document.test.ts.snap create mode 100644 src/layers/3_SelectGraphQLMapper/nodes/_collect.ts create mode 100644 src/layers/3_SelectGraphQLMapper/toGraphQL.test.ts delete mode 100644 src/layers/3_SelectGraphQLMapper/types.ts delete mode 100644 src/layers/4_generator/generators/SchemaRuntime.ts delete mode 100644 src/layers/5_request/schemaErrors.test.ts delete mode 100644 src/layers/7_customScalars/RuntimeIndexCustomScalars.ts delete mode 100644 src/layers/7_customScalars/decode.ts delete mode 100644 src/layers/7_customScalars/encode.ts delete mode 100644 src/layers/7_customScalars/extension.ts create mode 100644 src/layers/7_extensions/CustomScalars/CustomScalars.ts rename src/layers/{7_customScalars => 7_extensions/CustomScalars}/decode.test.ts (89%) create mode 100644 src/layers/7_extensions/CustomScalars/decode.ts create mode 100644 src/layers/7_extensions/CustomScalars/encode.test.ts create mode 100644 src/layers/7_extensions/CustomScalars/encode.ts create mode 100644 src/layers/7_extensions/CustomScalars/schemaDrivenDataMap/generator.ts create mode 100644 src/layers/7_extensions/CustomScalars/schemaDrivenDataMap/types.ts create mode 100644 src/layers/7_extensions/SchemaErrors/SchemaErrors.test.ts create mode 100644 src/layers/7_extensions/SchemaErrors/SchemaErrors.ts create mode 100644 src/lib/grafaid/request.ts create mode 100644 src/lib/template-string.ts delete mode 100644 tests/_/schemas/kitchen-sink/graffle/modules/RuntimeCustomScalars.ts create mode 100644 tests/_/schemas/kitchen-sink/graffle/modules/SchemaDrivenDataMap.ts delete mode 100644 tests/_/schemas/kitchen-sink/graffle/modules/SchemaRuntime.ts create mode 100644 tests/_/schemas/mutation-only/graffle/modules/SchemaDrivenDataMap.ts delete mode 100644 tests/_/schemas/mutation-only/graffle/modules/SchemaRuntime.ts create mode 100644 tests/_/schemas/pokemon/graffle/modules/SchemaDrivenDataMap.ts delete mode 100644 tests/_/schemas/pokemon/graffle/modules/SchemaRuntime.ts rename website/graffle/modules/RuntimeCustomScalars.ts => tests/_/schemas/query-only/graffle/modules/SchemaDrivenDataMap.ts (50%) delete mode 100644 tests/_/schemas/query-only/graffle/modules/SchemaRuntime.ts delete mode 100644 website/graffle/modules/SchemaCustomScalarIndex.ts create mode 100644 website/graffle/modules/SchemaDrivenDataMap.ts create mode 100644 website/pokemon/modules/SchemaDrivenDataMap.ts diff --git a/examples/50_anyware/anyware_slot_slot-body__slot-search-params.ts b/examples/50_anyware/anyware_slot_slot-body__slot-search-params.ts index 1b77d35e1..d7ed955fe 100644 --- a/examples/50_anyware/anyware_slot_slot-body__slot-search-params.ts +++ b/examples/50_anyware/anyware_slot_slot-body__slot-search-params.ts @@ -12,7 +12,7 @@ const graffle = Graffle searchParams: (graphqlRequest) => { return { query: graphqlRequest.query, - operationName: `queryContinents`, + operationName: `getPokemon`, } }, }, @@ -20,13 +20,13 @@ const graffle = Graffle }) const result = await graffle.gql` - query trainers { - pokemon { name } - } - query pokemon { + query getTrainers { trainers { name } } + query getPokemon { + pokemon { name } + } ` - .send(`queryCountries`) + .send(`getTrainers`) show(result) diff --git a/examples/__outputs__/10_transport-http/transport-http_extension_headers__dynamicHeaders.output.txt b/examples/__outputs__/10_transport-http/transport-http_extension_headers__dynamicHeaders.output.txt index 830b8b5cb..a7a7e7fb8 100644 --- a/examples/__outputs__/10_transport-http/transport-http_extension_headers__dynamicHeaders.output.txt +++ b/examples/__outputs__/10_transport-http/transport-http_extension_headers__dynamicHeaders.output.txt @@ -4,7 +4,7 @@ headers: Headers { accept: 'application/graphql-response+json; charset=utf-8, application/json; charset=utf-8', 'content-type': 'application/json', - 'x-sent-at-time': '1728323381286' + 'x-sent-at-time': '1728856241218' }, signal: undefined, method: 'post', diff --git a/examples/__outputs__/10_transport-http/transport-http_method-get.output.txt b/examples/__outputs__/10_transport-http/transport-http_method-get.output.txt index 27f796aa8..3c50e3c13 100644 --- a/examples/__outputs__/10_transport-http/transport-http_method-get.output.txt +++ b/examples/__outputs__/10_transport-http/transport-http_method-get.output.txt @@ -22,7 +22,7 @@ searchParams: URLSearchParams {}, hash: '' }, - body: '{"query":"mutation { addPokemon(attack:0, defense:0, hp:1, name:\\"Nano\\", type: grass) { name } }"}' + body: '{"query":"mutation {\\n addPokemon(attack: 0, defense: 0, hp: 1, name: \\"Nano\\", type: grass) {\\n name\\n }\\n}"}' } ---------------------------------------- SHOW ---------------------------------------- { @@ -34,7 +34,7 @@ signal: undefined, method: 'get', url: URL { - href: 'http://localhost:3000/graphql?query=query+%7B+pokemonByName%28name%3A+%22Nano%22%29+%7B+hp+%7D+%7D', + href: 'http://localhost:3000/graphql?query=%7B%0A++pokemonByName%28name%3A+%22Nano%22%29+%7B%0A++++hp%0A++%7D%0A%7D', origin: 'http://localhost:3000', protocol: 'http:', username: '', @@ -43,8 +43,8 @@ hostname: 'localhost', port: '3000', pathname: '/graphql', - search: '?query=query+%7B+pokemonByName%28name%3A+%22Nano%22%29+%7B+hp+%7D+%7D', - searchParams: URLSearchParams { 'query' => 'query { pokemonByName(name: "Nano") { hp } }' }, + search: '?query=%7B%0A++pokemonByName%28name%3A+%22Nano%22%29+%7B%0A++++hp%0A++%7D%0A%7D', + searchParams: URLSearchParams { 'query' => '{\n pokemonByName(name: "Nano") {\n hp\n }\n}' }, hash: '' } } \ No newline at end of file diff --git a/examples/__outputs__/20_output/output_envelope.output.txt b/examples/__outputs__/20_output/output_envelope.output.txt index fc3b79159..6e46d7646 100644 --- a/examples/__outputs__/20_output/output_envelope.output.txt +++ b/examples/__outputs__/20_output/output_envelope.output.txt @@ -18,7 +18,7 @@ headers: Headers { 'content-type': 'application/graphql-response+json; charset=utf-8', 'content-length': '142', - date: 'Mon, 07 Oct 2024 17:49:41 GMT', + date: 'Sun, 13 Oct 2024 21:50:41 GMT', connection: 'keep-alive', 'keep-alive': 'timeout=5' }, diff --git a/examples/__outputs__/20_output/output_envelope_envelope-error__envelope-error.output.txt b/examples/__outputs__/20_output/output_envelope_envelope-error__envelope-error.output.txt index 143379dff..0fb468557 100644 --- a/examples/__outputs__/20_output/output_envelope_envelope-error__envelope-error.output.txt +++ b/examples/__outputs__/20_output/output_envelope_envelope-error__envelope-error.output.txt @@ -5,7 +5,7 @@ at runPipeline (/some/path/to/runPipeline.ts:XX:XX:18) at async Object.run (/some/path/to/main.ts:XX:XX:22) at async executeDocument (/some/path/to/requestMethods.ts:XX:XX:18) - at async executeRootTypeField (/some/path/to/requestMethods.ts:XX:XX:18) + at async executeRootField (/some/path/to/requestMethods.ts:XX:XX:18) at async (/some/path/to/output_envelope_envelope-error__envelope-error.ts:XX:XX:16) { context: { hookName: 'encode', diff --git a/examples/__outputs__/20_output/output_envelope_envelope_error-throw__envelope-error-throw.output.txt b/examples/__outputs__/20_output/output_envelope_envelope_error-throw__envelope-error-throw.output.txt index cc41ef40f..fe7e4f5dd 100644 --- a/examples/__outputs__/20_output/output_envelope_envelope_error-throw__envelope-error-throw.output.txt +++ b/examples/__outputs__/20_output/output_envelope_envelope_error-throw__envelope-error-throw.output.txt @@ -7,7 +7,7 @@ ContextualError: There was an error in the extension "anonymous" (use named func at runPipeline (/some/path/to/runPipeline.ts:XX:XX:18) at async Object.run (/some/path/to/main.ts:XX:XX:22) at async executeDocument (/some/path/to/requestMethods.ts:XX:XX:18) - at async executeRootTypeField (/some/path/to/requestMethods.ts:XX:XX:18) + at async executeRootField (/some/path/to/requestMethods.ts:XX:XX:18) at async (/some/path/to/output_envelope_envelope_error-throw__envelope-error-throw.ts:XX:XX:1) { context: { hookName: 'encode', diff --git a/examples/__outputs__/20_output/output_preset__standard-graphql.output.txt b/examples/__outputs__/20_output/output_preset__standard-graphql.output.txt index badaa3d05..d4feb07a3 100644 --- a/examples/__outputs__/20_output/output_preset__standard-graphql.output.txt +++ b/examples/__outputs__/20_output/output_preset__standard-graphql.output.txt @@ -14,16 +14,14 @@ ContextualError: There was an error in the core implementation of hook "exchange [cause]: TypeError: Failed to parse URL from ... at new Request (node:internal/deps/undici/undici:XX:XX) at Object.run (/some/path/to/core.ts:XX:XX:29) - ... 3 lines matching cause stack trace ... - at async applyBody (/some/path/to/main.ts:XX:XX:22) { + at runHook (/some/path/to/runHook.ts:XX:XX:37) + at runHook (/some/path/to/runHook.ts:XX:XX:16) { [cause]: TypeError: Invalid URL at new URL (node:internal/url:XX:XX) at new Request (node:internal/deps/undici/undici:XX:XX) at Object.run (/some/path/to/core.ts:XX:XX:29) at runHook (/some/path/to/runHook.ts:XX:XX:37) - at (/some/path/to/runHook.ts:XX:XX:14) - at onRequest (/some/path/to/extension.ts:XX:XX:32) - at async applyBody (/some/path/to/main.ts:XX:XX:22) { + at runHook (/some/path/to/runHook.ts:XX:XX:16) { code: 'ERR_INVALID_URL', input: '...' } diff --git a/examples/__outputs__/20_output/output_return-error.output.txt b/examples/__outputs__/20_output/output_return-error.output.txt index ff2c67ae4..dae3a1f41 100644 --- a/examples/__outputs__/20_output/output_return-error.output.txt +++ b/examples/__outputs__/20_output/output_return-error.output.txt @@ -3,7 +3,7 @@ ContextualError: There was an error in the extension "anonymous" (use named func at runPipeline (/some/path/to/runPipeline.ts:XX:XX:18) at async Object.run (/some/path/to/main.ts:XX:XX:22) at async executeDocument (/some/path/to/requestMethods.ts:XX:XX:18) - at async executeRootTypeField (/some/path/to/requestMethods.ts:XX:XX:18) + at async executeRootField (/some/path/to/requestMethods.ts:XX:XX:18) at async (/some/path/to/output_return-error.ts:XX:XX:18) { context: { hookName: 'encode', 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 881f9db89..1ca6a0f70 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 @@ -3,7 +3,7 @@ ContextualAggregateError: One or more errors in the execution result. at handleOutput (/some/path/to/handleOutput.ts:XX:XX:19) at executeDocument (/some/path/to/requestMethods.ts:XX:XX:10) at process.processTicksAndRejections (node:internal/process/task_queues:XX:XX) - at async executeRootTypeField (/some/path/to/requestMethods.ts:XX:XX:18) + 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: {}, cause: undefined, @@ -39,7 +39,7 @@ ContextualError: There was an error in the extension "anonymous" (use named func at process.processTicksAndRejections (node:internal/process/task_queues:XX:XX) at async Object.run (/some/path/to/main.ts:XX:XX:22) at async executeDocument (/some/path/to/requestMethods.ts:XX:XX:18) - at async executeRootTypeField (/some/path/to/requestMethods.ts:XX:XX:18) + 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:3) { context: { hookName: 'encode', diff --git a/examples/__outputs__/30_gql/gql_gql-document-node_gql-typed_gql-typed-graphql-document-node__gql-typed-graphql-document-node.output.txt b/examples/__outputs__/30_gql/gql_gql-document-node_gql-typed_gql-typed-graphql-document-node__gql-typed-graphql-document-node.output.txt deleted file mode 100644 index 04ee07503..000000000 --- a/examples/__outputs__/30_gql/gql_gql-document-node_gql-typed_gql-typed-graphql-document-node__gql-typed-graphql-document-node.output.txt +++ /dev/null @@ -1,20 +0,0 @@ - -node:internal/modules/run_main:123 - triggerUncaughtException( - ^ -Error [ERR_MODULE_NOT_FOUND]: Cannot find module '/some/path/to/gql_gql-document-node_gql-typed_gql-typed-graphql-document-node__gql-typed-graphql-document-node.ts:XX:XX' imported from /Users/jasonkuhrt/projects/jasonkuhrt/graffle/ - at finalizeResolution (node:internal/modules/esm/resolve:XX:XX) - at moduleResolve (node:internal/modules/esm/resolve:XX:XX) - at defaultResolve (node:internal/modules/esm/resolve:XX:XX) - at nextResolve (node:internal/modules/esm/hooks:XX:XX) - at resolveBase (file:///Users/jasonkuhrt/projects/jasonkuhrt/graffle/node_modules/.pnpm/tsx@4.19.1/node_modules/tsx/dist/esm/index.mjs?1728404771051:XX:XX) - at resolveDirectory (file:///Users/jasonkuhrt/projects/jasonkuhrt/graffle/node_modules/.pnpm/tsx@4.19.1/node_modules/tsx/dist/esm/index.mjs?1728404771051:XX:XX) - at resolveTsPaths (file:///Users/jasonkuhrt/projects/jasonkuhrt/graffle/node_modules/.pnpm/tsx@4.19.1/node_modules/tsx/dist/esm/index.mjs?1728404771051:XX:XX) - at resolve (file:///Users/jasonkuhrt/projects/jasonkuhrt/graffle/node_modules/.pnpm/tsx@4.19.1/node_modules/tsx/dist/esm/index.mjs?1728404771051:XX:XX) - at nextResolve (node:internal/modules/esm/hooks:XX:XX) - at Hooks.resolve (node:internal/modules/esm/hooks:XX:XX) { - code: 'ERR_MODULE_NOT_FOUND', - url: 'file:/some/path/to/gql_gql-document-node_gql-typed_gql-typed-graphql-document-node__gql-typed-graphql-document-node.ts:XX:XX' -} - -Node.js vXX.XX.XX \ No newline at end of file diff --git a/examples/__outputs__/30_raw 11-54-53-229/raw_rawDocumentNode__raw-document-node.output.txt b/examples/__outputs__/30_raw 11-54-53-229/raw_rawDocumentNode__raw-document-node.output.txt deleted file mode 100644 index 6191da0e2..000000000 --- a/examples/__outputs__/30_raw 11-54-53-229/raw_rawDocumentNode__raw-document-node.output.txt +++ /dev/null @@ -1,20 +0,0 @@ - -node:internal/modules/run_main:123 - triggerUncaughtException( - ^ -Error [ERR_MODULE_NOT_FOUND]: Cannot find module '/some/path/to/raw_rawDocumentNode__raw-document-node.ts:XX:XX' imported from /Users/jasonkuhrt/projects/jasonkuhrt/graffle/ - at finalizeResolution (node:internal/modules/esm/resolve:XX:XX) - at moduleResolve (node:internal/modules/esm/resolve:XX:XX) - at defaultResolve (node:internal/modules/esm/resolve:XX:XX) - at nextResolve (node:internal/modules/esm/hooks:XX:XX) - at resolveBase (file:///Users/jasonkuhrt/projects/jasonkuhrt/graffle/node_modules/.pnpm/tsx@4.19.1/node_modules/tsx/dist/esm/index.mjs?1728316475175:XX:XX) - at resolveDirectory (file:///Users/jasonkuhrt/projects/jasonkuhrt/graffle/node_modules/.pnpm/tsx@4.19.1/node_modules/tsx/dist/esm/index.mjs?1728316475175:XX:XX) - at resolveTsPaths (file:///Users/jasonkuhrt/projects/jasonkuhrt/graffle/node_modules/.pnpm/tsx@4.19.1/node_modules/tsx/dist/esm/index.mjs?1728316475175:XX:XX) - at resolve (file:///Users/jasonkuhrt/projects/jasonkuhrt/graffle/node_modules/.pnpm/tsx@4.19.1/node_modules/tsx/dist/esm/index.mjs?1728316475175:XX:XX) - at nextResolve (node:internal/modules/esm/hooks:XX:XX) - at Hooks.resolve (node:internal/modules/esm/hooks:XX:XX) { - code: 'ERR_MODULE_NOT_FOUND', - url: 'file:/some/path/to/raw_rawDocumentNode__raw-document-node.ts:XX:XX' -} - -Node.js vXX.XX.XX \ No newline at end of file diff --git a/examples/__outputs__/30_raw 11-54-53-229/raw_rawDocumentNode_rawTyped__raw-document-node-typed.output.txt b/examples/__outputs__/30_raw 11-54-53-229/raw_rawDocumentNode_rawTyped__raw-document-node-typed.output.txt deleted file mode 100644 index ff4983017..000000000 --- a/examples/__outputs__/30_raw 11-54-53-229/raw_rawDocumentNode_rawTyped__raw-document-node-typed.output.txt +++ /dev/null @@ -1,20 +0,0 @@ - -node:internal/modules/run_main:123 - triggerUncaughtException( - ^ -Error [ERR_MODULE_NOT_FOUND]: Cannot find module '/some/path/to/raw_rawDocumentNode_rawTyped__raw-document-node-typed.ts:XX:XX' imported from /Users/jasonkuhrt/projects/jasonkuhrt/graffle/ - at finalizeResolution (node:internal/modules/esm/resolve:XX:XX) - at moduleResolve (node:internal/modules/esm/resolve:XX:XX) - at defaultResolve (node:internal/modules/esm/resolve:XX:XX) - at nextResolve (node:internal/modules/esm/hooks:XX:XX) - at resolveBase (file:///Users/jasonkuhrt/projects/jasonkuhrt/graffle/node_modules/.pnpm/tsx@4.19.1/node_modules/tsx/dist/esm/index.mjs?1728316472737:XX:XX) - at resolveDirectory (file:///Users/jasonkuhrt/projects/jasonkuhrt/graffle/node_modules/.pnpm/tsx@4.19.1/node_modules/tsx/dist/esm/index.mjs?1728316472737:XX:XX) - at resolveTsPaths (file:///Users/jasonkuhrt/projects/jasonkuhrt/graffle/node_modules/.pnpm/tsx@4.19.1/node_modules/tsx/dist/esm/index.mjs?1728316472737:XX:XX) - at resolve (file:///Users/jasonkuhrt/projects/jasonkuhrt/graffle/node_modules/.pnpm/tsx@4.19.1/node_modules/tsx/dist/esm/index.mjs?1728316472737:XX:XX) - at nextResolve (node:internal/modules/esm/hooks:XX:XX) - at Hooks.resolve (node:internal/modules/esm/hooks:XX:XX) { - code: 'ERR_MODULE_NOT_FOUND', - url: 'file:/some/path/to/raw_rawDocumentNode_rawTyped__raw-document-node-typed.ts:XX:XX' -} - -Node.js vXX.XX.XX \ No newline at end of file diff --git a/examples/__outputs__/30_raw 11-54-53-229/raw_rawString__rawString.output.txt b/examples/__outputs__/30_raw 11-54-53-229/raw_rawString__rawString.output.txt deleted file mode 100644 index 9cfdad843..000000000 --- a/examples/__outputs__/30_raw 11-54-53-229/raw_rawString__rawString.output.txt +++ /dev/null @@ -1,20 +0,0 @@ - -node:internal/modules/run_main:123 - triggerUncaughtException( - ^ -Error [ERR_MODULE_NOT_FOUND]: Cannot find module '/some/path/to/raw_rawString__rawString.ts:XX:XX' imported from /Users/jasonkuhrt/projects/jasonkuhrt/graffle/ - at finalizeResolution (node:internal/modules/esm/resolve:XX:XX) - at moduleResolve (node:internal/modules/esm/resolve:XX:XX) - at defaultResolve (node:internal/modules/esm/resolve:XX:XX) - at nextResolve (node:internal/modules/esm/hooks:XX:XX) - at resolveBase (file:///Users/jasonkuhrt/projects/jasonkuhrt/graffle/node_modules/.pnpm/tsx@4.19.1/node_modules/tsx/dist/esm/index.mjs?1728316478033:XX:XX) - at resolveDirectory (file:///Users/jasonkuhrt/projects/jasonkuhrt/graffle/node_modules/.pnpm/tsx@4.19.1/node_modules/tsx/dist/esm/index.mjs?1728316478033:XX:XX) - at resolveTsPaths (file:///Users/jasonkuhrt/projects/jasonkuhrt/graffle/node_modules/.pnpm/tsx@4.19.1/node_modules/tsx/dist/esm/index.mjs?1728316478033:XX:XX) - at resolve (file:///Users/jasonkuhrt/projects/jasonkuhrt/graffle/node_modules/.pnpm/tsx@4.19.1/node_modules/tsx/dist/esm/index.mjs?1728316478033:XX:XX) - at nextResolve (node:internal/modules/esm/hooks:XX:XX) - at Hooks.resolve (node:internal/modules/esm/hooks:XX:XX) { - code: 'ERR_MODULE_NOT_FOUND', - url: 'file:/some/path/to/raw_rawString__rawString.ts:XX:XX' -} - -Node.js vXX.XX.XX \ No newline at end of file diff --git a/examples/__outputs__/30_raw 11-54-53-229/raw_rawString_rawTyped__rawString-typed.output.txt b/examples/__outputs__/30_raw 11-54-53-229/raw_rawString_rawTyped__rawString-typed.output.txt deleted file mode 100644 index 7b3dd2767..000000000 --- a/examples/__outputs__/30_raw 11-54-53-229/raw_rawString_rawTyped__rawString-typed.output.txt +++ /dev/null @@ -1,20 +0,0 @@ - -node:internal/modules/run_main:123 - triggerUncaughtException( - ^ -Error [ERR_MODULE_NOT_FOUND]: Cannot find module '/some/path/to/raw_rawString_rawTyped__rawString-typed.ts:XX:XX' imported from /Users/jasonkuhrt/projects/jasonkuhrt/graffle/ - at finalizeResolution (node:internal/modules/esm/resolve:XX:XX) - at moduleResolve (node:internal/modules/esm/resolve:XX:XX) - at defaultResolve (node:internal/modules/esm/resolve:XX:XX) - at nextResolve (node:internal/modules/esm/hooks:XX:XX) - at resolveBase (file:///Users/jasonkuhrt/projects/jasonkuhrt/graffle/node_modules/.pnpm/tsx@4.19.1/node_modules/tsx/dist/esm/index.mjs?1728316474983:XX:XX) - at resolveDirectory (file:///Users/jasonkuhrt/projects/jasonkuhrt/graffle/node_modules/.pnpm/tsx@4.19.1/node_modules/tsx/dist/esm/index.mjs?1728316474983:XX:XX) - at resolveTsPaths (file:///Users/jasonkuhrt/projects/jasonkuhrt/graffle/node_modules/.pnpm/tsx@4.19.1/node_modules/tsx/dist/esm/index.mjs?1728316474983:XX:XX) - at resolve (file:///Users/jasonkuhrt/projects/jasonkuhrt/graffle/node_modules/.pnpm/tsx@4.19.1/node_modules/tsx/dist/esm/index.mjs?1728316474983:XX:XX) - at nextResolve (node:internal/modules/esm/hooks:XX:XX) - at Hooks.resolve (node:internal/modules/esm/hooks:XX:XX) { - code: 'ERR_MODULE_NOT_FOUND', - url: 'file:/some/path/to/raw_rawString_rawTyped__rawString-typed.ts:XX:XX' -} - -Node.js vXX.XX.XX \ No newline at end of file diff --git a/examples/__outputs__/50_anyware/anyware_slot_slot-body__slot-search-params.output.txt b/examples/__outputs__/50_anyware/anyware_slot_slot-body__slot-search-params.output.txt index 102c598a6..77d7ecb45 100644 --- a/examples/__outputs__/50_anyware/anyware_slot_slot-body__slot-search-params.output.txt +++ b/examples/__outputs__/50_anyware/anyware_slot_slot-body__slot-search-params.output.txt @@ -1,22 +1,11 @@ -/some/path/to/runPipeline.ts:XX:XX - return new ContextualError(message, { hookName: signal.hookName, source: signal.source }, signal.error) - ^ - - -ContextualError: There was an error in the core implementation of hook "pack". - at runPipeline (/some/path/to/runPipeline.ts:XX:XX:18) - at async runPipeline (/some/path/to/runPipeline.ts:XX:XX:14) - at async Object.run (/some/path/to/main.ts:XX:XX:22) - at async Object.send (/some/path/to/gql.ts:XX:XX:26) - at async (/some/path/to/anyware_slot_slot-body__slot-search-params.ts:XX:XX:16) { - context: { hookName: 'pack', source: 'implementation' }, - cause: Error: Unexpected null value. - at throwNull (/some/path/to/prelude.ts:XX:XX:29) - at Object.run (/some/path/to/core.ts:XX:XX:35) - at runHook (/some/path/to/runHook.ts:XX:XX:37) - at (/some/path/to/runHook.ts:XX:XX:14) - at (/some/path/to/anyware_slot_slot-body__slot-search-params.ts:XX:XX:18) - at applyBody (/some/path/to/main.ts:XX:XX:28) -} - -Node.js vXX.XX.XX \ No newline at end of file +---------------------------------------- SHOW ---------------------------------------- +{ + pokemon: [ + { name: 'Pikachu' }, + { name: 'Charizard' }, + { name: 'Squirtle' }, + { name: 'Bulbasaur' }, + { name: 'Caterpie' }, + { name: 'Weedle' } + ] +} \ No newline at end of file diff --git a/examples/__outputs__/60_extension/extension_opentelemetry__opentelemetry.output.txt b/examples/__outputs__/60_extension/extension_opentelemetry__opentelemetry.output.txt index 563c2c241..93a93cc37 100644 --- a/examples/__outputs__/60_extension/extension_opentelemetry__opentelemetry.output.txt +++ b/examples/__outputs__/60_extension/extension_opentelemetry__opentelemetry.output.txt @@ -9,14 +9,14 @@ } }, instrumentationScope: { name: 'graffle', version: undefined, schemaUrl: undefined }, - traceId: 'ac014dada983f302716deae963031d77', - parentId: 'fe33e3cb84b589ed', + traceId: '0d775d0099c7910506a0772440555fbe', + parentId: '9b0787a81673ace4', traceState: undefined, name: 'encode', - id: '87f70f2b478a9946', + id: 'e6fbdb4081ec6e4e', kind: 0, - timestamp: 1728323381984000, - duration: 620.917, + timestamp: 1728856242273000, + duration: 1418.125, attributes: {}, status: { code: 0 }, events: [], @@ -33,14 +33,14 @@ } }, instrumentationScope: { name: 'graffle', version: undefined, schemaUrl: undefined }, - traceId: 'ac014dada983f302716deae963031d77', - parentId: 'fe33e3cb84b589ed', + traceId: '0d775d0099c7910506a0772440555fbe', + parentId: '9b0787a81673ace4', traceState: undefined, name: 'pack', - id: '4223bd045e4f82b7', + id: 'c20c4b4a0bb60890', kind: 0, - timestamp: 1728323381987000, - duration: 17090.167, + timestamp: 1728856242277000, + duration: 11234.958, attributes: {}, status: { code: 0 }, events: [], @@ -57,14 +57,14 @@ } }, instrumentationScope: { name: 'graffle', version: undefined, schemaUrl: undefined }, - traceId: 'ac014dada983f302716deae963031d77', - parentId: 'fe33e3cb84b589ed', + traceId: '0d775d0099c7910506a0772440555fbe', + parentId: '9b0787a81673ace4', traceState: undefined, name: 'exchange', - id: '1acd0a0de0d5eb48', + id: 'b37626f52b507127', kind: 0, - timestamp: 1728323382005000, - duration: 28187.833, + timestamp: 1728856242288000, + duration: 106411.25, attributes: {}, status: { code: 0 }, events: [], @@ -81,14 +81,14 @@ } }, instrumentationScope: { name: 'graffle', version: undefined, schemaUrl: undefined }, - traceId: 'ac014dada983f302716deae963031d77', - parentId: 'fe33e3cb84b589ed', + traceId: '0d775d0099c7910506a0772440555fbe', + parentId: '9b0787a81673ace4', traceState: undefined, name: 'unpack', - id: '5190c757f52e1c88', + id: '7cdde5c9f15d334d', kind: 0, - timestamp: 1728323382033000, - duration: 1180.667, + timestamp: 1728856242395000, + duration: 1244.125, attributes: {}, status: { code: 0 }, events: [], @@ -105,14 +105,14 @@ } }, instrumentationScope: { name: 'graffle', version: undefined, schemaUrl: undefined }, - traceId: 'ac014dada983f302716deae963031d77', - parentId: 'fe33e3cb84b589ed', + traceId: '0d775d0099c7910506a0772440555fbe', + parentId: '9b0787a81673ace4', traceState: undefined, name: 'decode', - id: '88685659d9725d48', + id: 'b048da7b0a82b097', kind: 0, - timestamp: 1728323382035000, - duration: 196.375, + timestamp: 1728856242396000, + duration: 181.792, attributes: {}, status: { code: 0 }, events: [], @@ -129,14 +129,14 @@ } }, instrumentationScope: { name: 'graffle', version: undefined, schemaUrl: undefined }, - traceId: 'ac014dada983f302716deae963031d77', + traceId: '0d775d0099c7910506a0772440555fbe', parentId: undefined, traceState: undefined, name: 'request', - id: 'fe33e3cb84b589ed', + id: '9b0787a81673ace4', kind: 0, - timestamp: 1728323381982000, - duration: 53359.417, + timestamp: 1728856242273000, + duration: 123962.916, attributes: {}, status: { code: 0 }, events: [], diff --git a/src/entrypoints/_Print.ts b/src/entrypoints/_Print.ts index f7d98ae9a..7e7dd9356 100644 --- a/src/entrypoints/_Print.ts +++ b/src/entrypoints/_Print.ts @@ -1 +1 @@ -export { toGraphQLDocument as document } from '../layers/3_SelectGraphQLMapper/nodes/Document.js' +export { toGraphQLDocument as document } from '../layers/3_SelectGraphQLMapper/nodes/1_Document.js' diff --git a/src/entrypoints/utilities-for-generated.ts b/src/entrypoints/utilities-for-generated.ts index f15efbb54..c289dd4f2 100644 --- a/src/entrypoints/utilities-for-generated.ts +++ b/src/entrypoints/utilities-for-generated.ts @@ -9,5 +9,6 @@ export type { export { type DocumentRunner } from '../layers/6_client/requestMethods/document.js' export type { Config } from '../layers/6_client/Settings/Config.js' export { type AddTypenameToSelectedRootTypeResultFields } from '../layers/6_client/Settings/Config.js' +export { type SchemaDrivenDataMap } from '../layers/7_extensions/CustomScalars/schemaDrivenDataMap/types.js' export { HKT } from '../lib/hkt/__.js' export { type Exact, type ExactNonEmpty, type UnionExpanded } from '../lib/prelude.js' diff --git a/src/layers/1_Schema/Hybrid/types/Scalar/Scalar.ts b/src/layers/1_Schema/Hybrid/types/Scalar/Scalar.ts index ef56d5170..775261cb9 100644 --- a/src/layers/1_Schema/Hybrid/types/Scalar/Scalar.ts +++ b/src/layers/1_Schema/Hybrid/types/Scalar/Scalar.ts @@ -1,5 +1,5 @@ import type { GlobalRegistry } from '../../../../4_generator/globalRegistry.js' -import type { Codec } from './codec.js' +import type { Codec, Mapper } from './codec.js' import { JavaScriptScalarCodecs } from './nativeScalarCodecs.js' export { JavaScriptScalarCodecs } from './nativeScalarCodecs.js' @@ -46,6 +46,31 @@ export interface Scalar< codec: Codec<$Decoded, $Encoded> } +/** + * Apply a codec's mapper function (decode or encode) to a GraphQL value. + * + * If value is an array then its members are traversed recursively. + * + * Null values are returned as is. + */ +export const applyCodec = <$Mapper extends Mapper>( + mapper: $Mapper, + value: any, +): null | ReturnType<$Mapper> | ReturnType<$Mapper>[] => { + if (value === null) { + return null + } + + if (Array.isArray(value)) { + return value.map(item => applyCodec(mapper, item)) as ReturnType<$Mapper> + } + + return mapper(value) as ReturnType<$Mapper> +} + +export const isScalar = (value: unknown): value is Scalar => + typeof value === `object` && value !== null && `codec` in value && typeof value.codec === `object` + export const String = create(`String`, JavaScriptScalarCodecs.String) export const ID = create(`ID`, JavaScriptScalarCodecs.String) diff --git a/src/layers/1_Schema/Hybrid/types/Scalar/codec.ts b/src/layers/1_Schema/Hybrid/types/Scalar/codec.ts index 448c6637e..12f0af5dc 100644 --- a/src/layers/1_Schema/Hybrid/types/Scalar/codec.ts +++ b/src/layers/1_Schema/Hybrid/types/Scalar/codec.ts @@ -1,11 +1,13 @@ import type { StandardScalarRuntimeTypes } from './Scalar.js' export type Codec<$Decoded = any, $Encoded extends StandardScalarRuntimeTypes = StandardScalarRuntimeTypes> = { - encode: (value: $Decoded) => $Encoded - decode: (value: $Encoded) => $Decoded + encode: <$$Decoded extends $Decoded>(value: $$Decoded) => $Encoded + decode: <$$Encoded extends $Encoded>(value: $$Encoded) => $Decoded } export const createCodec = <$Decoded, $Encoded extends StandardScalarRuntimeTypes>(codec: { encode: (value: $Decoded) => $Encoded decode: (value: $Encoded) => $Decoded }): Codec<$Decoded, $Encoded> => codec + +export type Mapper = (value: any) => any diff --git a/src/layers/2_Select/$parseSelection.ts b/src/layers/2_Select/$parseSelection.ts index 105fd21d5..0d9c974a1 100644 --- a/src/layers/2_Select/$parseSelection.ts +++ b/src/layers/2_Select/$parseSelection.ts @@ -1,46 +1,90 @@ import type { SelectionSet } from './_.js' import { Arguments, Directive, Indicator, InlineFragment, SelectAlias, SelectScalarsWildcard } from './_.js' -export type ParsedSelection = - | { - type: 'Arguments' - arguments: Record - } - | { - /** - * When undefined is passed to a directive. - */ - type: 'DirectiveNoop' - } - | { - type: 'Directive' - name: string - argumentsInput: unknown - arguments: Record - } - | { - type: 'InlineFragment' - typeCondition: string | null - selectionSets: SelectionSet.AnySelectionSet[] - } - | { - type: 'ScalarsWildcard' - } - | { - type: 'SelectionSet' - name: string - selectionSet: SelectionSet.AnySelectionSet - } - | { - type: 'Indicator' - name: string - select: boolean - } - | { - type: 'Alias' - name: string - aliases: SelectAlias.SelectAliasMultiple +export interface ParsedSelectionArguments { + type: 'Arguments' + arguments: Record +} + +export interface ParsedSelectionDirective { + type: 'Directive' + name: string + /** + * `null` when undefined is passed to a directive. + */ + + arguments: null | { + input: unknown + parsed: Record } +} + +export interface ParsedSelectionInlineFragments { + type: 'InlineFragment' + typeCondition: string | null + selectionSets: SelectionSet.AnySelectionSet[] +} + +export interface ParsedSelectionScalarsWildcard { + type: 'ScalarsWildcard' +} + +export interface ParsedSelectionSelectionSet { + type: 'SelectionSet' + name: string + selectionSet: SelectionSet.AnySelectionSet +} + +export interface ParsedSelectionIndicator { + type: 'Indicator' + name: string + select: boolean +} + +export interface ParsedSelectionAlias { + type: 'Alias' + name: string + aliases: SelectAlias.SelectAliasMultiple +} + +export type ParsedFieldSelection = + | ParsedSelectionSelectionSet + | ParsedSelectionIndicator + +export type ParsedSelection = + | ParsedSelectionArguments + | ParsedSelectionDirective + | ParsedSelectionInlineFragments + | ParsedSelectionScalarsWildcard + | ParsedSelectionSelectionSet + | ParsedSelectionIndicator + | ParsedSelectionAlias + +export type ParsedFieldLevelSelection = + | ParsedSelectionArguments + | ParsedSelectionDirective + +export type ParsedInlineFragmentLevelSelection = + | ParsedSelectionDirective + | ParsedSelectionObjectLevel + +export type ParsedSelectionObjectLevel = + | ParsedSelectionInlineFragments + | ParsedSelectionScalarsWildcard + | ParsedSelectionSelectionSet + | ParsedSelectionIndicator + | ParsedSelectionAlias + +export const parseSelectionField = (key: string, value: any): ParsedFieldSelection => { + return parseSelection(key, value) as any +} +export const parseSelectionRoot = (key: string, value: any): ParsedSelectionObjectLevel => { + return parseSelection(key, value) as any +} + +export const parseSelectionInlineFragment = (key: string, value: any): ParsedInlineFragmentLevelSelection => { + return parseSelection(key, value) as any +} export const parseSelection = (key: string, value: any): ParsedSelection => { if (key === Arguments.key) { @@ -57,16 +101,14 @@ export const parseSelection = (key: string, value: any): ParsedSelection => { if (!directiveDef) { throw new Error(`Unknown directive ${key}.`) } - if (value === undefined) { - return { - type: `DirectiveNoop`, - } - } + return { type: `Directive`, name: directiveName, - argumentsInput: value, - arguments: directiveDef.normalizeArguments(value), + arguments: value === undefined ? null : { + input: value, + parsed: directiveDef.normalizeArguments(value), + }, } } diff --git a/src/layers/2_Select/SelectAlias.ts b/src/layers/2_Select/SelectAlias.ts index 32c69ba69..71197e841 100644 --- a/src/layers/2_Select/SelectAlias.ts +++ b/src/layers/2_Select/SelectAlias.ts @@ -11,7 +11,7 @@ export type SelectAliasMultiple<$SelectionSet = AnyExceptAlias> = [ ] export const isSelectAlias = (value: unknown): value is SelectAlias => { - return Array.isArray(value) && (value.length === 2 || isSelectAlias(value[1])) + return Array.isArray(value) && ((value.length === 2 && typeof value[0] === `string`) || isSelectAlias(value[0])) } export const isSelectAliasOne = (selectAlias: SelectAlias): selectAlias is SelectAliasOne => { diff --git a/src/layers/2_Select/document.ts b/src/layers/2_Select/document.ts index 4ac519b45..f67d3c495 100644 --- a/src/layers/2_Select/document.ts +++ b/src/layers/2_Select/document.ts @@ -66,16 +66,20 @@ export interface DocumentNormalized { } } -export const createDocumentNormalized = (document: DocumentNormalized) => document +export const createDocumentNormalizedFromQuerySelection = ( + selectionSet: Select.SelectionSet.AnySelectionSet, + operationName?: string, +): DocumentNormalized => createDocumentNormalizedFromRootTypeSelection(`Query`, selectionSet, operationName) export const createDocumentNormalizedFromRootTypeSelection = ( rootTypeName: Grafaid.Schema.RootTypeName, selectionSet: Select.SelectionSet.AnySelectionSet, -) => + operationName?: string, +): DocumentNormalized => createDocumentNormalized({ operations: { - [defaultOperationName]: { - name: null, + [operationName ?? defaultOperationName]: { + name: operationName ?? null, type: Grafaid.RootTypeNameToOperationName[rootTypeName], rootType: rootTypeName, selectionSet, @@ -169,3 +173,5 @@ export const getOperationOrThrow = ( } return document.operations[operationName]! } + +const createDocumentNormalized = (document: DocumentNormalized) => document diff --git a/src/layers/3_SelectGraphQLMapper/_.ts b/src/layers/3_SelectGraphQLMapper/_.ts index e5941eae2..1cd963abb 100644 --- a/src/layers/3_SelectGraphQLMapper/_.ts +++ b/src/layers/3_SelectGraphQLMapper/_.ts @@ -1 +1,2 @@ -export { toGraphQL } from './helpers.js' +export { type Encoded } from './nodes/1_Document.js' +export { toGraphQLDocument as toGraphQL } from './nodes/1_Document.js' diff --git a/src/layers/3_SelectGraphQLMapper/__snapshots__/toGraphQL.test.ts.snap b/src/layers/3_SelectGraphQLMapper/__snapshots__/toGraphQL.test.ts.snap new file mode 100644 index 000000000..b1785168b --- /dev/null +++ b/src/layers/3_SelectGraphQLMapper/__snapshots__/toGraphQL.test.ts.snap @@ -0,0 +1,2463 @@ +// Vitest Snapshot v1, https://vitest.dev/guide/snapshot.html + +exports[`( variables: false ) - Query - $include (empty object) > $include (empty object) 1`] = ` +" + +--------------GRAFFLE QUERY------------- +{ + "object": { + "$include": {}, + "id": true + } +} +--------GRAPHQL DOCUMENT & VARIABLES-------- +{ + object @include(if: true) { + id + } +} +---------------- +{ + "$default": {} +} +" +`; + +exports[`( variables: false ) - Query - $include (false) > $include (false) 1`] = ` +" + +--------------GRAFFLE QUERY------------- +{ + "object": { + "$include": false, + "id": true + } +} +--------GRAPHQL DOCUMENT & VARIABLES-------- +{ + object @include(if: false) { + id + } +} +---------------- +{ + "$default": {} +} +" +`; + +exports[`( variables: false ) - Query - $include (if false) > $include (if false) 1`] = ` +" + +--------------GRAFFLE QUERY------------- +{ + "object": { + "$include": { + "if": false + }, + "id": true + } +} +--------GRAPHQL DOCUMENT & VARIABLES-------- +{ + object @include(if: false) { + id + } +} +---------------- +{ + "$default": {} +} +" +`; + +exports[`( variables: false ) - Query - $include (if true) > $include (if true) 1`] = ` +" + +--------------GRAFFLE QUERY------------- +{ + "object": { + "$include": { + "if": true + }, + "id": true + } +} +--------GRAPHQL DOCUMENT & VARIABLES-------- +{ + object @include(if: true) { + id + } +} +---------------- +{ + "$default": {} +} +" +`; + +exports[`( variables: false ) - Query - $include (if undefined) > $include (if undefined) 1`] = ` +" + +--------------GRAFFLE QUERY------------- +{ + "object": { + "$include": {}, + "id": true + } +} +--------GRAPHQL DOCUMENT & VARIABLES-------- +{ + object @include(if: true) { + id + } +} +---------------- +{ + "$default": {} +} +" +`; + +exports[`( variables: false ) - Query - $include (undefined) > $include (undefined) 1`] = ` +" + +--------------GRAFFLE QUERY------------- +{ + "object": { + "id": true + } +} +--------GRAPHQL DOCUMENT & VARIABLES-------- +{ + object { + id + } +} +---------------- +{ + "$default": {} +} +" +`; + +exports[`( variables: false ) - Query - $include > $include 1`] = ` +" + +--------------GRAFFLE QUERY------------- +{ + "object": { + "$include": true, + "id": true + } +} +--------GRAPHQL DOCUMENT & VARIABLES-------- +{ + object @include(if: true) { + id + } +} +---------------- +{ + "$default": {} +} +" +`; + +exports[`( variables: false ) - Query - $skip (empty object) > $skip (empty object) 1`] = ` +" + +--------------GRAFFLE QUERY------------- +{ + "object": { + "$skip": {}, + "id": true + } +} +--------GRAPHQL DOCUMENT & VARIABLES-------- +{ + object @skip(if: true) { + id + } +} +---------------- +{ + "$default": {} +} +" +`; + +exports[`( variables: false ) - Query - $skip (false) > $skip (false) 1`] = ` +" + +--------------GRAFFLE QUERY------------- +{ + "object": { + "$skip": false, + "id": true + } +} +--------GRAPHQL DOCUMENT & VARIABLES-------- +{ + object @skip(if: false) { + id + } +} +---------------- +{ + "$default": {} +} +" +`; + +exports[`( variables: false ) - Query - $skip (if false) > $skip (if false) 1`] = ` +" + +--------------GRAFFLE QUERY------------- +{ + "object": { + "$skip": { + "if": false + }, + "id": true + } +} +--------GRAPHQL DOCUMENT & VARIABLES-------- +{ + object @skip(if: false) { + id + } +} +---------------- +{ + "$default": {} +} +" +`; + +exports[`( variables: false ) - Query - $skip (if true) > $skip (if true) 1`] = ` +" + +--------------GRAFFLE QUERY------------- +{ + "object": { + "$skip": { + "if": true + }, + "id": true + } +} +--------GRAPHQL DOCUMENT & VARIABLES-------- +{ + object @skip(if: true) { + id + } +} +---------------- +{ + "$default": {} +} +" +`; + +exports[`( variables: false ) - Query - $skip (if undefined) > $skip (if undefined) 1`] = ` +" + +--------------GRAFFLE QUERY------------- +{ + "object": { + "$skip": {}, + "id": true + } +} +--------GRAPHQL DOCUMENT & VARIABLES-------- +{ + object @skip(if: true) { + id + } +} +---------------- +{ + "$default": {} +} +" +`; + +exports[`( variables: false ) - Query - $skip (true) > $skip (true) 1`] = ` +" + +--------------GRAFFLE QUERY------------- +{ + "object": { + "$skip": true, + "id": true + } +} +--------GRAPHQL DOCUMENT & VARIABLES-------- +{ + object @skip(if: true) { + id + } +} +---------------- +{ + "$default": {} +} +" +`; + +exports[`( variables: false ) - Query - $skip (undefined) > $skip (undefined) 1`] = ` +" + +--------------GRAFFLE QUERY------------- +{ + "object": { + "id": true + } +} +--------GRAPHQL DOCUMENT & VARIABLES-------- +{ + object { + id + } +} +---------------- +{ + "$default": {} +} +" +`; + +exports[`( variables: false ) - Query - alias - scalar > alias - scalar 1`] = ` +" + +--------------GRAFFLE QUERY------------- +{ + "id": [ + "x", + true + ] +} +--------GRAPHQL DOCUMENT & VARIABLES-------- +{ + x: id +} +---------------- +{ + "$default": {} +} +" +`; + +exports[`( variables: false ) - Query - alias - scalar directive > alias - scalar directive 1`] = ` +" + +--------------GRAFFLE QUERY------------- +{ + "id": [ + "x", + { + "$skip": true + } + ] +} +--------GRAPHQL DOCUMENT & VARIABLES-------- +{ + x: id @skip(if: true) +} +---------------- +{ + "$default": {} +} +" +`; + +exports[`( variables: false ) - Query - alias - scalar directive+select > alias - scalar directive+select 1`] = ` +" + +--------------GRAFFLE QUERY------------- +{ + "object": [ + "x", + { + "$skip": true, + "id": true + } + ] +} +--------GRAPHQL DOCUMENT & VARIABLES-------- +{ + x: object @skip(if: true) { + id + } +} +---------------- +{ + "$default": {} +} +" +`; + +exports[`( variables: false ) - Query - alias - scalar x2 > alias - scalar x2 1`] = ` +" + +--------------GRAFFLE QUERY------------- +{ + "id": [ + [ + "x", + true + ], + [ + "id2", + true + ] + ] +} +--------GRAPHQL DOCUMENT & VARIABLES-------- +{ + x: id + id2: id +} +---------------- +{ + "$default": {} +} +" +`; + +exports[`( variables: false ) - Query - args - alias > args - alias 1`] = ` +" + +--------------GRAFFLE QUERY------------- +{ + "stringWithArgs": [ + [ + "a", + { + "$": { + "id": "" + } + } + ] + ] +} +--------GRAPHQL DOCUMENT & VARIABLES-------- +{ + a: stringWithArgs(id: "") +} +---------------- +{ + "$default": {} +} +" +`; + +exports[`( variables: false ) - Query - args - custom scalar - arg field > args - custom scalar - arg field 1`] = ` +" + +--------------GRAFFLE QUERY------------- +{ + "dateArg": { + "$": { + "date": "1970-01-01T00:00:00.000Z" + } + } +} +--------GRAPHQL DOCUMENT & VARIABLES-------- +{ + dateArg(date: "1970-01-01T00:00:00.000Z") +} +---------------- +{ + "$default": {} +} +" +`; + +exports[`( variables: false ) - Query - args - custom scalar - arg field in list (null) > args - custom scalar - arg field in list (null) 1`] = ` +" + +--------------GRAFFLE QUERY------------- +{ + "dateArgList": { + "$": { + "date": null + } + } +} +--------GRAPHQL DOCUMENT & VARIABLES-------- +{ + dateArgList(date: null) +} +---------------- +{ + "$default": {} +} +" +`; + +exports[`( variables: false ) - Query - args - custom scalar - arg field in list > args - custom scalar - arg field in list 1`] = ` +" + +--------------GRAFFLE QUERY------------- +{ + "dateArgList": { + "$": { + "date": [ + "1970-01-01T00:00:00.000Z", + "1970-01-01T00:00:00.001Z" + ] + } + } +} +--------GRAPHQL DOCUMENT & VARIABLES-------- +{ + dateArgList(date: ["1970-01-01T00:00:00.000Z", "1970-01-01T00:00:00.001Z"]) +} +---------------- +{ + "$default": {} +} +" +`; + +exports[`( variables: false ) - Query - args - custom scalar - arg field in non-null > args - custom scalar - arg field in non-null 1`] = ` +" + +--------------GRAFFLE QUERY------------- +{ + "dateArgNonNull": { + "$": { + "date": "1970-01-01T00:00:00.000Z" + } + } +} +--------GRAPHQL DOCUMENT & VARIABLES-------- +{ + dateArgNonNull(date: "1970-01-01T00:00:00.000Z") +} +---------------- +{ + "$default": {} +} +" +`; + +exports[`( variables: false ) - Query - args - custom scalar - arg field in non-null list (with list) > args - custom scalar - arg field in non-null list (with list) 1`] = ` +" + +--------------GRAFFLE QUERY------------- +{ + "dateArgNonNullList": { + "$": { + "date": [ + "1970-01-01T00:00:00.000Z", + "1970-01-01T00:00:00.001Z" + ] + } + } +} +--------GRAPHQL DOCUMENT & VARIABLES-------- +{ + dateArgNonNullList( + date: ["1970-01-01T00:00:00.000Z", "1970-01-01T00:00:00.001Z"] + ) +} +---------------- +{ + "$default": {} +} +" +`; + +exports[`( variables: false ) - Query - args - custom scalar - arg field in non-null list (with null) > args - custom scalar - arg field in non-null list (with null) 1`] = ` +" + +--------------GRAFFLE QUERY------------- +{ + "dateArgNonNullList": { + "$": { + "date": [ + null, + "1970-01-01T00:00:00.000Z" + ] + } + } +} +--------GRAPHQL DOCUMENT & VARIABLES-------- +{ + dateArgNonNullList(date: [null, "1970-01-01T00:00:00.000Z"]) +} +---------------- +{ + "$default": {} +} +" +`; + +exports[`( variables: false ) - Query - args - custom scalar - arg field in non-null list non-null > args - custom scalar - arg field in non-null list non-null 1`] = ` +" + +--------------GRAFFLE QUERY------------- +{ + "dateArgNonNullListNonNull": { + "$": { + "date": [ + "1970-01-01T00:00:00.000Z", + "1970-01-01T00:00:00.001Z" + ] + } + } +} +--------GRAPHQL DOCUMENT & VARIABLES-------- +{ + dateArgNonNullListNonNull( + date: ["1970-01-01T00:00:00.000Z", "1970-01-01T00:00:00.001Z"] + ) +} +---------------- +{ + "$default": {} +} +" +`; + +exports[`( variables: false ) - Query - args - custom scalar - input object field > args - custom scalar - input object field 1`] = ` +" + +--------------GRAFFLE QUERY------------- +{ + "dateArgInputObject": { + "$": { + "input": { + "idRequired": "", + "dateRequired": "1970-01-01T00:00:00.000Z", + "date": "1970-01-01T00:00:00.001Z" + } + } + } +} +--------GRAPHQL DOCUMENT & VARIABLES-------- +{ + dateArgInputObject( + input: {idRequired: "", dateRequired: "1970-01-01T00:00:00.000Z", date: "1970-01-01T00:00:00.001Z"} + ) +} +---------------- +{ + "$default": {} +} +" +`; + +exports[`( variables: false ) - Query - args - custom scalar - nested input object field > args - custom scalar - nested input object field 1`] = ` +" + +--------------GRAFFLE QUERY------------- +{ + "InputObjectNested": { + "$": { + "input": { + "InputObject": { + "idRequired": "", + "dateRequired": "1970-01-01T00:00:00.000Z", + "date": "1970-01-01T00:00:00.001Z" + } + } + } + } +} +--------GRAPHQL DOCUMENT & VARIABLES-------- +{ + InputObjectNested( + input: {InputObject: {idRequired: "", dateRequired: "1970-01-01T00:00:00.000Z", date: "1970-01-01T00:00:00.001Z"}} + ) +} +---------------- +{ + "$default": {} +} +" +`; + +exports[`( variables: false ) - Query - args - object with args (empty object) > args - object with args (empty object) 1`] = ` +" + +--------------GRAFFLE QUERY------------- +{ + "objectWithArgs": { + "$": {}, + "id": true + } +} +--------GRAPHQL DOCUMENT & VARIABLES-------- +{ + objectWithArgs { + id + } +} +---------------- +{ + "$default": {} +} +" +`; + +exports[`( variables: false ) - Query - args - object with args > args - object with args 1`] = ` +" + +--------------GRAFFLE QUERY------------- +{ + "objectWithArgs": { + "$": { + "id": "" + }, + "id": true + } +} +--------GRAPHQL DOCUMENT & VARIABLES-------- +{ + objectWithArgs(id: "") { + id + } +} +---------------- +{ + "$default": {} +} +" +`; + +exports[`( variables: false ) - Query - args - on union > args - on union 1`] = ` +" + +--------------GRAFFLE QUERY------------- +{ + "result": { + "$": { + "$case": "Object1" + }, + "__typename": true + } +} +--------GRAPHQL DOCUMENT & VARIABLES-------- +{ + result(case: Object1) { + __typename + } +} +---------------- +{ + "$default": {} +} +" +`; + +exports[`( variables: false ) - Query - args - string with args (empty object) > args - string with args (empty object) 1`] = ` +" + +--------------GRAFFLE QUERY------------- +{ + "stringWithArgs": { + "$": {} + } +} +--------GRAPHQL DOCUMENT & VARIABLES-------- +{ + stringWithArgs +} +---------------- +{ + "$default": {} +} +" +`; + +exports[`( variables: false ) - Query - args - string with args > args - string with args 1`] = ` +" + +--------------GRAFFLE QUERY------------- +{ + "stringWithArgs": { + "$": { + "boolean": true, + "float": 1 + } + } +} +--------GRAPHQL DOCUMENT & VARIABLES-------- +{ + stringWithArgs(boolean: true, float: 1) +} +---------------- +{ + "$default": {} +} +" +`; + +exports[`( variables: false ) - Query - args - x2 same > args - x2 same 1`] = ` +" + +--------------GRAFFLE QUERY------------- +{ + "stringWithArgs": [ + [ + "a", + { + "$": { + "id": "" + } + } + ], + [ + "b", + { + "$": { + "id": "" + } + } + ] + ] +} +--------GRAPHQL DOCUMENT & VARIABLES-------- +{ + a: stringWithArgs(id: "") + b: stringWithArgs(id: "") +} +---------------- +{ + "$default": {} +} +" +`; + +exports[`( variables: false ) - Query - custom operation name > custom operation name 1`] = ` +" + +--------------GRAFFLE QUERY------------- +{ + "id": true +} +--------GRAPHQL DOCUMENT & VARIABLES-------- +query foobar { + id +} +---------------- +{ + "foobar": {} +} +" +`; + +exports[`( variables: false ) - Query - fg - directive > fg - directive 1`] = ` +" + +--------------GRAFFLE QUERY------------- +{ + "___": { + "__typename": true, + "$include": true + } +} +--------GRAPHQL DOCUMENT & VARIABLES-------- +{ + ... @include(if: true) { + __typename + } +} +---------------- +{ + "$default": {} +} +" +`; + +exports[`( variables: false ) - Query - fg - in union > fg - in union 1`] = ` +" + +--------------GRAFFLE QUERY------------- +{ + "unionFooBar": { + "___": { + "__typename": true + } + } +} +--------GRAPHQL DOCUMENT & VARIABLES-------- +{ + unionFooBar { + ... { + __typename + } + } +} +---------------- +{ + "$default": {} +} +" +`; + +exports[`( variables: false ) - Query - fg - interface > fg - interface 1`] = ` +" + +--------------GRAFFLE QUERY------------- +{ + "interface": { + "___": { + "__typename": true + } + } +} +--------GRAPHQL DOCUMENT & VARIABLES-------- +{ + interface { + ... { + __typename + } + } +} +---------------- +{ + "$default": {} +} +" +`; + +exports[`( variables: false ) - Query - fg - multiple > fg - multiple 1`] = ` +" + +--------------GRAFFLE QUERY------------- +{ + "___": [ + { + "__typename": true + }, + { + "abcEnum": true + } + ] +} +--------GRAPHQL DOCUMENT & VARIABLES-------- +{ + ... { + __typename + } + ... { + abcEnum + } +} +---------------- +{ + "$default": {} +} +" +`; + +exports[`( variables: false ) - Query - fg - one > fg - one 1`] = ` +" + +--------------GRAFFLE QUERY------------- +{ + "___": { + "__typename": true + } +} +--------GRAPHQL DOCUMENT & VARIABLES-------- +{ + ... { + __typename + } +} +---------------- +{ + "$default": {} +} +" +`; + +exports[`( variables: false ) - Query - id string false > id string false 1`] = ` +" + +--------------GRAFFLE QUERY------------- +{ + "id": true, + "string": false +} +--------GRAPHQL DOCUMENT & VARIABLES-------- +{ + id +} +---------------- +{ + "$default": {} +} +" +`; + +exports[`( variables: false ) - Query - id string undefined > id string undefined 1`] = ` +" + +--------------GRAFFLE QUERY------------- +{ + "id": true +} +--------GRAPHQL DOCUMENT & VARIABLES-------- +{ + id +} +---------------- +{ + "$default": {} +} +" +`; + +exports[`( variables: false ) - Query - object nested > object nested 1`] = ` +" + +--------------GRAFFLE QUERY------------- +{ + "objectNested": { + "object": { + "string": true, + "id": true, + "int": false + } + } +} +--------GRAPHQL DOCUMENT & VARIABLES-------- +{ + objectNested { + object { + string + id + } + } +} +---------------- +{ + "$default": {} +} +" +`; + +exports[`( variables: false ) - Query - object nested scalar $skip > object nested scalar $skip 1`] = ` +" + +--------------GRAFFLE QUERY------------- +{ + "objectNested": { + "object": { + "string": true, + "id": true, + "int": { + "$skip": true + } + } + } +} +--------GRAPHQL DOCUMENT & VARIABLES-------- +{ + objectNested { + object { + string + id + int @skip(if: true) + } + } +} +---------------- +{ + "$default": {} +} +" +`; + +exports[`( variables: false ) - Query - object scalar > object scalar 1`] = ` +" + +--------------GRAFFLE QUERY------------- +{ + "object": { + "id": true + } +} +--------GRAPHQL DOCUMENT & VARIABLES-------- +{ + object { + id + } +} +---------------- +{ + "$default": {} +} +" +`; + +exports[`( variables: false ) - Query - other > other 1`] = ` +" + +--------------GRAFFLE QUERY------------- +{ + "__typename": true +} +--------GRAPHQL DOCUMENT & VARIABLES-------- +{ + __typename +} +---------------- +{ + "$default": {} +} +" +`; + +exports[`( variables: false ) - Query - string > string 1`] = ` +" + +--------------GRAFFLE QUERY------------- +{ + "string": true +} +--------GRAPHQL DOCUMENT & VARIABLES-------- +{ + string +} +---------------- +{ + "$default": {} +} +" +`; + +exports[`( variables: false ) - Query - union - __typename (no fragment) > union - __typename (no fragment) 1`] = ` +" + +--------------GRAFFLE QUERY------------- +{ + "unionFooBar": { + "__typename": true + } +} +--------GRAPHQL DOCUMENT & VARIABLES-------- +{ + unionFooBar { + __typename + } +} +---------------- +{ + "$default": {} +} +" +`; + +exports[`( variables: false ) - Query - union - directive > union - directive 1`] = ` +" + +--------------GRAFFLE QUERY------------- +{ + "unionFooBar": { + "___on_Bar": { + "$skip": true, + "int": true + } + } +} +--------GRAPHQL DOCUMENT & VARIABLES-------- +{ + unionFooBar { + ... on Bar @skip(if: true) { + int + } + } +} +---------------- +{ + "$default": {} +} +" +`; + +exports[`( variables: false ) - Query - union - scalar > union - scalar 1`] = ` +" + +--------------GRAFFLE QUERY------------- +{ + "unionFooBar": { + "___on_Bar": { + "int": true + } + } +} +--------GRAPHQL DOCUMENT & VARIABLES-------- +{ + unionFooBar { + ... on Bar { + int + } + } +} +---------------- +{ + "$default": {} +} +" +`; + +exports[`( variables: true ) - Query - $include (empty object) > $include (empty object) 1`] = ` +" + +--------------GRAFFLE QUERY------------- +{ + "object": { + "$include": {}, + "id": true + } +} +--------GRAPHQL DOCUMENT & VARIABLES-------- +{ + object @include(if: true) { + id + } +} +---------------- +{ + "$default": {} +} +" +`; + +exports[`( variables: true ) - Query - $include (false) > $include (false) 1`] = ` +" + +--------------GRAFFLE QUERY------------- +{ + "object": { + "$include": false, + "id": true + } +} +--------GRAPHQL DOCUMENT & VARIABLES-------- +{ + object @include(if: false) { + id + } +} +---------------- +{ + "$default": {} +} +" +`; + +exports[`( variables: true ) - Query - $include (if false) > $include (if false) 1`] = ` +" + +--------------GRAFFLE QUERY------------- +{ + "object": { + "$include": { + "if": false + }, + "id": true + } +} +--------GRAPHQL DOCUMENT & VARIABLES-------- +{ + object @include(if: false) { + id + } +} +---------------- +{ + "$default": {} +} +" +`; + +exports[`( variables: true ) - Query - $include (if true) > $include (if true) 1`] = ` +" + +--------------GRAFFLE QUERY------------- +{ + "object": { + "$include": { + "if": true + }, + "id": true + } +} +--------GRAPHQL DOCUMENT & VARIABLES-------- +{ + object @include(if: true) { + id + } +} +---------------- +{ + "$default": {} +} +" +`; + +exports[`( variables: true ) - Query - $include (if undefined) > $include (if undefined) 1`] = ` +" + +--------------GRAFFLE QUERY------------- +{ + "object": { + "$include": {}, + "id": true + } +} +--------GRAPHQL DOCUMENT & VARIABLES-------- +{ + object @include(if: true) { + id + } +} +---------------- +{ + "$default": {} +} +" +`; + +exports[`( variables: true ) - Query - $include (undefined) > $include (undefined) 1`] = ` +" + +--------------GRAFFLE QUERY------------- +{ + "object": { + "id": true + } +} +--------GRAPHQL DOCUMENT & VARIABLES-------- +{ + object { + id + } +} +---------------- +{ + "$default": {} +} +" +`; + +exports[`( variables: true ) - Query - $include > $include 1`] = ` +" + +--------------GRAFFLE QUERY------------- +{ + "object": { + "$include": true, + "id": true + } +} +--------GRAPHQL DOCUMENT & VARIABLES-------- +{ + object @include(if: true) { + id + } +} +---------------- +{ + "$default": {} +} +" +`; + +exports[`( variables: true ) - Query - $skip (empty object) > $skip (empty object) 1`] = ` +" + +--------------GRAFFLE QUERY------------- +{ + "object": { + "$skip": {}, + "id": true + } +} +--------GRAPHQL DOCUMENT & VARIABLES-------- +{ + object @skip(if: true) { + id + } +} +---------------- +{ + "$default": {} +} +" +`; + +exports[`( variables: true ) - Query - $skip (false) > $skip (false) 1`] = ` +" + +--------------GRAFFLE QUERY------------- +{ + "object": { + "$skip": false, + "id": true + } +} +--------GRAPHQL DOCUMENT & VARIABLES-------- +{ + object @skip(if: false) { + id + } +} +---------------- +{ + "$default": {} +} +" +`; + +exports[`( variables: true ) - Query - $skip (if false) > $skip (if false) 1`] = ` +" + +--------------GRAFFLE QUERY------------- +{ + "object": { + "$skip": { + "if": false + }, + "id": true + } +} +--------GRAPHQL DOCUMENT & VARIABLES-------- +{ + object @skip(if: false) { + id + } +} +---------------- +{ + "$default": {} +} +" +`; + +exports[`( variables: true ) - Query - $skip (if true) > $skip (if true) 1`] = ` +" + +--------------GRAFFLE QUERY------------- +{ + "object": { + "$skip": { + "if": true + }, + "id": true + } +} +--------GRAPHQL DOCUMENT & VARIABLES-------- +{ + object @skip(if: true) { + id + } +} +---------------- +{ + "$default": {} +} +" +`; + +exports[`( variables: true ) - Query - $skip (if undefined) > $skip (if undefined) 1`] = ` +" + +--------------GRAFFLE QUERY------------- +{ + "object": { + "$skip": {}, + "id": true + } +} +--------GRAPHQL DOCUMENT & VARIABLES-------- +{ + object @skip(if: true) { + id + } +} +---------------- +{ + "$default": {} +} +" +`; + +exports[`( variables: true ) - Query - $skip (true) > $skip (true) 1`] = ` +" + +--------------GRAFFLE QUERY------------- +{ + "object": { + "$skip": true, + "id": true + } +} +--------GRAPHQL DOCUMENT & VARIABLES-------- +{ + object @skip(if: true) { + id + } +} +---------------- +{ + "$default": {} +} +" +`; + +exports[`( variables: true ) - Query - $skip (undefined) > $skip (undefined) 1`] = ` +" + +--------------GRAFFLE QUERY------------- +{ + "object": { + "id": true + } +} +--------GRAPHQL DOCUMENT & VARIABLES-------- +{ + object { + id + } +} +---------------- +{ + "$default": {} +} +" +`; + +exports[`( variables: true ) - Query - alias - scalar > alias - scalar 1`] = ` +" + +--------------GRAFFLE QUERY------------- +{ + "id": [ + "x", + true + ] +} +--------GRAPHQL DOCUMENT & VARIABLES-------- +{ + x: id +} +---------------- +{ + "$default": {} +} +" +`; + +exports[`( variables: true ) - Query - alias - scalar directive > alias - scalar directive 1`] = ` +" + +--------------GRAFFLE QUERY------------- +{ + "id": [ + "x", + { + "$skip": true + } + ] +} +--------GRAPHQL DOCUMENT & VARIABLES-------- +{ + x: id @skip(if: true) +} +---------------- +{ + "$default": {} +} +" +`; + +exports[`( variables: true ) - Query - alias - scalar directive+select > alias - scalar directive+select 1`] = ` +" + +--------------GRAFFLE QUERY------------- +{ + "object": [ + "x", + { + "$skip": true, + "id": true + } + ] +} +--------GRAPHQL DOCUMENT & VARIABLES-------- +{ + x: object @skip(if: true) { + id + } +} +---------------- +{ + "$default": {} +} +" +`; + +exports[`( variables: true ) - Query - alias - scalar x2 > alias - scalar x2 1`] = ` +" + +--------------GRAFFLE QUERY------------- +{ + "id": [ + [ + "x", + true + ], + [ + "id2", + true + ] + ] +} +--------GRAPHQL DOCUMENT & VARIABLES-------- +{ + x: id + id2: id +} +---------------- +{ + "$default": {} +} +" +`; + +exports[`( variables: true ) - Query - args - alias > args - alias 1`] = ` +" + +--------------GRAFFLE QUERY------------- +{ + "stringWithArgs": [ + [ + "a", + { + "$": { + "id": "" + } + } + ] + ] +} +--------GRAPHQL DOCUMENT & VARIABLES-------- +query ($id: ID) { + a: stringWithArgs(id: $id) +} +---------------- +{ + "$default": { + "id": "" + } +} +" +`; + +exports[`( variables: true ) - Query - args - custom scalar - arg field > args - custom scalar - arg field 1`] = ` +" + +--------------GRAFFLE QUERY------------- +{ + "dateArg": { + "$": { + "date": "1970-01-01T00:00:00.000Z" + } + } +} +--------GRAPHQL DOCUMENT & VARIABLES-------- +query ($date: Date) { + dateArg(date: $date) +} +---------------- +{ + "$default": { + "date": "1970-01-01T00:00:00.000Z" + } +} +" +`; + +exports[`( variables: true ) - Query - args - custom scalar - arg field in list (null) > args - custom scalar - arg field in list (null) 1`] = ` +" + +--------------GRAFFLE QUERY------------- +{ + "dateArgList": { + "$": { + "date": null + } + } +} +--------GRAPHQL DOCUMENT & VARIABLES-------- +query ($date: [Date!]) { + dateArgList(date: $date) +} +---------------- +{ + "$default": { + "date": null + } +} +" +`; + +exports[`( variables: true ) - Query - args - custom scalar - arg field in list > args - custom scalar - arg field in list 1`] = ` +" + +--------------GRAFFLE QUERY------------- +{ + "dateArgList": { + "$": { + "date": [ + "1970-01-01T00:00:00.000Z", + "1970-01-01T00:00:00.001Z" + ] + } + } +} +--------GRAPHQL DOCUMENT & VARIABLES-------- +query ($date: [Date!]) { + dateArgList(date: $date) +} +---------------- +{ + "$default": { + "date": [ + "1970-01-01T00:00:00.000Z", + "1970-01-01T00:00:00.001Z" + ] + } +} +" +`; + +exports[`( variables: true ) - Query - args - custom scalar - arg field in non-null > args - custom scalar - arg field in non-null 1`] = ` +" + +--------------GRAFFLE QUERY------------- +{ + "dateArgNonNull": { + "$": { + "date": "1970-01-01T00:00:00.000Z" + } + } +} +--------GRAPHQL DOCUMENT & VARIABLES-------- +query ($date: Date!) { + dateArgNonNull(date: $date) +} +---------------- +{ + "$default": { + "date": "1970-01-01T00:00:00.000Z" + } +} +" +`; + +exports[`( variables: true ) - Query - args - custom scalar - arg field in non-null list (with list) > args - custom scalar - arg field in non-null list (with list) 1`] = ` +" + +--------------GRAFFLE QUERY------------- +{ + "dateArgNonNullList": { + "$": { + "date": [ + "1970-01-01T00:00:00.000Z", + "1970-01-01T00:00:00.001Z" + ] + } + } +} +--------GRAPHQL DOCUMENT & VARIABLES-------- +query ($date: [Date]!) { + dateArgNonNullList(date: $date) +} +---------------- +{ + "$default": { + "date": [ + "1970-01-01T00:00:00.000Z", + "1970-01-01T00:00:00.001Z" + ] + } +} +" +`; + +exports[`( variables: true ) - Query - args - custom scalar - arg field in non-null list (with null) > args - custom scalar - arg field in non-null list (with null) 1`] = ` +" + +--------------GRAFFLE QUERY------------- +{ + "dateArgNonNullList": { + "$": { + "date": [ + null, + "1970-01-01T00:00:00.000Z" + ] + } + } +} +--------GRAPHQL DOCUMENT & VARIABLES-------- +query ($date: [Date]!) { + dateArgNonNullList(date: $date) +} +---------------- +{ + "$default": { + "date": [ + null, + "1970-01-01T00:00:00.000Z" + ] + } +} +" +`; + +exports[`( variables: true ) - Query - args - custom scalar - arg field in non-null list non-null > args - custom scalar - arg field in non-null list non-null 1`] = ` +" + +--------------GRAFFLE QUERY------------- +{ + "dateArgNonNullListNonNull": { + "$": { + "date": [ + "1970-01-01T00:00:00.000Z", + "1970-01-01T00:00:00.001Z" + ] + } + } +} +--------GRAPHQL DOCUMENT & VARIABLES-------- +query ($date: [Date!]!) { + dateArgNonNullListNonNull(date: $date) +} +---------------- +{ + "$default": { + "date": [ + "1970-01-01T00:00:00.000Z", + "1970-01-01T00:00:00.001Z" + ] + } +} +" +`; + +exports[`( variables: true ) - Query - args - custom scalar - input object field > args - custom scalar - input object field 1`] = ` +" + +--------------GRAFFLE QUERY------------- +{ + "dateArgInputObject": { + "$": { + "input": { + "idRequired": "", + "dateRequired": "1970-01-01T00:00:00.000Z", + "date": "1970-01-01T00:00:00.001Z" + } + } + } +} +--------GRAPHQL DOCUMENT & VARIABLES-------- +query ($input: InputObject) { + dateArgInputObject(input: $input) +} +---------------- +{ + "$default": { + "input": { + "idRequired": "", + "dateRequired": "1970-01-01T00:00:00.000Z", + "date": "1970-01-01T00:00:00.001Z" + } + } +} +" +`; + +exports[`( variables: true ) - Query - args - custom scalar - nested input object field > args - custom scalar - nested input object field 1`] = ` +" + +--------------GRAFFLE QUERY------------- +{ + "InputObjectNested": { + "$": { + "input": { + "InputObject": { + "idRequired": "", + "dateRequired": "1970-01-01T00:00:00.000Z", + "date": "1970-01-01T00:00:00.001Z" + } + } + } + } +} +--------GRAPHQL DOCUMENT & VARIABLES-------- +query ($input: InputObjectNested) { + InputObjectNested(input: $input) +} +---------------- +{ + "$default": { + "input": { + "InputObject": { + "idRequired": "", + "dateRequired": "1970-01-01T00:00:00.000Z", + "date": "1970-01-01T00:00:00.001Z" + } + } + } +} +" +`; + +exports[`( variables: true ) - Query - args - object with args (empty object) > args - object with args (empty object) 1`] = ` +" + +--------------GRAFFLE QUERY------------- +{ + "objectWithArgs": { + "$": {}, + "id": true + } +} +--------GRAPHQL DOCUMENT & VARIABLES-------- +{ + objectWithArgs { + id + } +} +---------------- +{ + "$default": {} +} +" +`; + +exports[`( variables: true ) - Query - args - object with args > args - object with args 1`] = ` +" + +--------------GRAFFLE QUERY------------- +{ + "objectWithArgs": { + "$": { + "id": "" + }, + "id": true + } +} +--------GRAPHQL DOCUMENT & VARIABLES-------- +query ($id: ID) { + objectWithArgs(id: $id) { + id + } +} +---------------- +{ + "$default": { + "id": "" + } +} +" +`; + +exports[`( variables: true ) - Query - args - on union > args - on union 1`] = ` +" + +--------------GRAFFLE QUERY------------- +{ + "result": { + "$": { + "$case": "Object1" + }, + "__typename": true + } +} +--------GRAPHQL DOCUMENT & VARIABLES-------- +query ($case: Case!) { + result(case: $case) { + __typename + } +} +---------------- +{ + "$default": { + "case": "Object1" + } +} +" +`; + +exports[`( variables: true ) - Query - args - string with args (empty object) > args - string with args (empty object) 1`] = ` +" + +--------------GRAFFLE QUERY------------- +{ + "stringWithArgs": { + "$": {} + } +} +--------GRAPHQL DOCUMENT & VARIABLES-------- +{ + stringWithArgs +} +---------------- +{ + "$default": {} +} +" +`; + +exports[`( variables: true ) - Query - args - string with args > args - string with args 1`] = ` +" + +--------------GRAFFLE QUERY------------- +{ + "stringWithArgs": { + "$": { + "boolean": true, + "float": 1 + } + } +} +--------GRAPHQL DOCUMENT & VARIABLES-------- +query ($boolean: Boolean, $float: Float) { + stringWithArgs(boolean: $boolean, float: $float) +} +---------------- +{ + "$default": { + "boolean": true, + "float": 1 + } +} +" +`; + +exports[`( variables: true ) - Query - args - x2 same > args - x2 same 1`] = ` +" + +--------------GRAFFLE QUERY------------- +{ + "stringWithArgs": [ + [ + "a", + { + "$": { + "id": "" + } + } + ], + [ + "b", + { + "$": { + "id": "" + } + } + ] + ] +} +--------GRAPHQL DOCUMENT & VARIABLES-------- +query ($id: ID, $id_2: ID) { + a: stringWithArgs(id: $id) + b: stringWithArgs(id: $id_2) +} +---------------- +{ + "$default": { + "id": "", + "id_2": "" + } +} +" +`; + +exports[`( variables: true ) - Query - custom operation name > custom operation name 1`] = ` +" + +--------------GRAFFLE QUERY------------- +{ + "id": true +} +--------GRAPHQL DOCUMENT & VARIABLES-------- +query foobar { + id +} +---------------- +{ + "foobar": {} +} +" +`; + +exports[`( variables: true ) - Query - fg - directive > fg - directive 1`] = ` +" + +--------------GRAFFLE QUERY------------- +{ + "___": { + "__typename": true, + "$include": true + } +} +--------GRAPHQL DOCUMENT & VARIABLES-------- +{ + ... @include(if: true) { + __typename + } +} +---------------- +{ + "$default": {} +} +" +`; + +exports[`( variables: true ) - Query - fg - in union > fg - in union 1`] = ` +" + +--------------GRAFFLE QUERY------------- +{ + "unionFooBar": { + "___": { + "__typename": true + } + } +} +--------GRAPHQL DOCUMENT & VARIABLES-------- +{ + unionFooBar { + ... { + __typename + } + } +} +---------------- +{ + "$default": {} +} +" +`; + +exports[`( variables: true ) - Query - fg - interface > fg - interface 1`] = ` +" + +--------------GRAFFLE QUERY------------- +{ + "interface": { + "___": { + "__typename": true + } + } +} +--------GRAPHQL DOCUMENT & VARIABLES-------- +{ + interface { + ... { + __typename + } + } +} +---------------- +{ + "$default": {} +} +" +`; + +exports[`( variables: true ) - Query - fg - multiple > fg - multiple 1`] = ` +" + +--------------GRAFFLE QUERY------------- +{ + "___": [ + { + "__typename": true + }, + { + "abcEnum": true + } + ] +} +--------GRAPHQL DOCUMENT & VARIABLES-------- +{ + ... { + __typename + } + ... { + abcEnum + } +} +---------------- +{ + "$default": {} +} +" +`; + +exports[`( variables: true ) - Query - fg - one > fg - one 1`] = ` +" + +--------------GRAFFLE QUERY------------- +{ + "___": { + "__typename": true + } +} +--------GRAPHQL DOCUMENT & VARIABLES-------- +{ + ... { + __typename + } +} +---------------- +{ + "$default": {} +} +" +`; + +exports[`( variables: true ) - Query - id string false > id string false 1`] = ` +" + +--------------GRAFFLE QUERY------------- +{ + "id": true, + "string": false +} +--------GRAPHQL DOCUMENT & VARIABLES-------- +{ + id +} +---------------- +{ + "$default": {} +} +" +`; + +exports[`( variables: true ) - Query - id string undefined > id string undefined 1`] = ` +" + +--------------GRAFFLE QUERY------------- +{ + "id": true +} +--------GRAPHQL DOCUMENT & VARIABLES-------- +{ + id +} +---------------- +{ + "$default": {} +} +" +`; + +exports[`( variables: true ) - Query - object nested > object nested 1`] = ` +" + +--------------GRAFFLE QUERY------------- +{ + "objectNested": { + "object": { + "string": true, + "id": true, + "int": false + } + } +} +--------GRAPHQL DOCUMENT & VARIABLES-------- +{ + objectNested { + object { + string + id + } + } +} +---------------- +{ + "$default": {} +} +" +`; + +exports[`( variables: true ) - Query - object nested scalar $skip > object nested scalar $skip 1`] = ` +" + +--------------GRAFFLE QUERY------------- +{ + "objectNested": { + "object": { + "string": true, + "id": true, + "int": { + "$skip": true + } + } + } +} +--------GRAPHQL DOCUMENT & VARIABLES-------- +{ + objectNested { + object { + string + id + int @skip(if: true) + } + } +} +---------------- +{ + "$default": {} +} +" +`; + +exports[`( variables: true ) - Query - object scalar > object scalar 1`] = ` +" + +--------------GRAFFLE QUERY------------- +{ + "object": { + "id": true + } +} +--------GRAPHQL DOCUMENT & VARIABLES-------- +{ + object { + id + } +} +---------------- +{ + "$default": {} +} +" +`; + +exports[`( variables: true ) - Query - other > other 1`] = ` +" + +--------------GRAFFLE QUERY------------- +{ + "__typename": true +} +--------GRAPHQL DOCUMENT & VARIABLES-------- +{ + __typename +} +---------------- +{ + "$default": {} +} +" +`; + +exports[`( variables: true ) - Query - string > string 1`] = ` +" + +--------------GRAFFLE QUERY------------- +{ + "string": true +} +--------GRAPHQL DOCUMENT & VARIABLES-------- +{ + string +} +---------------- +{ + "$default": {} +} +" +`; + +exports[`( variables: true ) - Query - union - __typename (no fragment) > union - __typename (no fragment) 1`] = ` +" + +--------------GRAFFLE QUERY------------- +{ + "unionFooBar": { + "__typename": true + } +} +--------GRAPHQL DOCUMENT & VARIABLES-------- +{ + unionFooBar { + __typename + } +} +---------------- +{ + "$default": {} +} +" +`; + +exports[`( variables: true ) - Query - union - directive > union - directive 1`] = ` +" + +--------------GRAFFLE QUERY------------- +{ + "unionFooBar": { + "___on_Bar": { + "$skip": true, + "int": true + } + } +} +--------GRAPHQL DOCUMENT & VARIABLES-------- +{ + unionFooBar { + ... on Bar @skip(if: true) { + int + } + } +} +---------------- +{ + "$default": {} +} +" +`; + +exports[`( variables: true ) - Query - union - scalar > union - scalar 1`] = ` +" + +--------------GRAFFLE QUERY------------- +{ + "unionFooBar": { + "___on_Bar": { + "int": true + } + } +} +--------GRAPHQL DOCUMENT & VARIABLES-------- +{ + unionFooBar { + ... on Bar { + int + } + } +} +---------------- +{ + "$default": {} +} +" +`; diff --git a/src/layers/3_SelectGraphQLMapper/context.ts b/src/layers/3_SelectGraphQLMapper/context.ts new file mode 100644 index 000000000..61e9bed05 --- /dev/null +++ b/src/layers/3_SelectGraphQLMapper/context.ts @@ -0,0 +1,64 @@ +import type { Grafaid } from '../../lib/grafaid/__.js' +import { Nodes } from '../../lib/grafaid/_Nodes.js' +import type { SchemaDrivenDataMap } from '../7_extensions/CustomScalars/schemaDrivenDataMap/types.js' +import { inferVariableType } from './inferVariableType.js' +import type { Options } from './nodes/1_Document.js' + +export interface OperationContext { + sddm?: SchemaDrivenDataMap + variables: { + /** + * Should variables be used for arguments? + */ + enabled: boolean + capture: (input: { + name: string + value: any + sddmArgument: SchemaDrivenDataMap.ArgumentOrInputField + }) => Grafaid.Document.ArgumentNode + data: CapturedVariable[] + } +} + +export interface CapturedVariable { + name: string + typeName: string + value: unknown +} + +export interface Captures { + variables: CapturedVariable[] +} + +export const createOperationContext = (options?: Options): OperationContext => { + const context: OperationContext = { + sddm: options?.sddm ?? undefined, + variables: { + enabled: options?.operationVariables ?? true, + capture: (input) => { + let potentialVariableName = input.name + let nameIndex = 2 + while (context.variables.data.find(_ => _.name === potentialVariableName)) { + potentialVariableName = `${input.name}_${String(nameIndex)}` + nameIndex++ + } + + context.variables.data.push({ + name: potentialVariableName, + typeName: inferVariableType(input.sddmArgument), + value: input.value, + }) + + return Nodes.Argument({ + name: Nodes.Name({ value: input.name }), + value: Nodes.Variable({ + name: Nodes.Name({ value: potentialVariableName }), + }), + }) + }, + data: [], + }, + } + + return context +} diff --git a/src/layers/3_SelectGraphQLMapper/helpers.ts b/src/layers/3_SelectGraphQLMapper/helpers.ts deleted file mode 100644 index 264a5489b..000000000 --- a/src/layers/3_SelectGraphQLMapper/helpers.ts +++ /dev/null @@ -1,22 +0,0 @@ -import type { Select } from '../2_Select/__.js' -import type { CustomScalarsIndex } from '../4_generator/generators/SchemaIndex.js' -import { toGraphQLDocument } from './nodes/Document.js' - -export const toGraphQL = (input: { - document: Select.Document.DocumentNormalized - customScalarsIndex?: CustomScalarsIndex - // we can probably remove this. was an idea that was aborted. Do we need scalar hook? - // hooks?: Context['hooks'] -}) => { - const context = { - captures: { - customScalarOutputs: [], - variables: [], - }, - // hooks: input.hooks, - } - - const customScalarsIndex: CustomScalarsIndex = input.customScalarsIndex ?? {} - - return toGraphQLDocument(context, customScalarsIndex, input.document) -} diff --git a/src/layers/3_SelectGraphQLMapper/inferVariableType.ts b/src/layers/3_SelectGraphQLMapper/inferVariableType.ts new file mode 100644 index 000000000..4b097e34c --- /dev/null +++ b/src/layers/3_SelectGraphQLMapper/inferVariableType.ts @@ -0,0 +1,36 @@ +import { isScalar } from '../1_Schema/Hybrid/types/Scalar/Scalar.js' +import type { SchemaDrivenDataMap } from '../7_extensions/CustomScalars/schemaDrivenDataMap/types.js' + +/** + * Infer the type of a variable for the given argument. + * This basically just transfers the inline type from the argument to the variable. + * The argument's inline type is known from the SDDM. + * + * Aside: Interestingly its representation in a GraphQL operation variable is as a string, not any kind of node. + */ +export const inferVariableType = (sddmArgLike: SchemaDrivenDataMap.ArgumentOrInputField): string => { + if (sddmArgLike.it) { + const isRequiredIndicator = sddmArgLike.it[0] === 1 ? `!` : `` + const namedType = inferNamedType(sddmArgLike) + return inferTypeInline(sddmArgLike.it[1], namedType) + isRequiredIndicator + } + return inferNamedType(sddmArgLike) +} + +const inferTypeInline = (sddmInlineType: undefined | SchemaDrivenDataMap.InlineType, typeName: string): string => { + if (!sddmInlineType) return typeName + const isRequiredIndicator = sddmInlineType[0] === 1 ? `!` : `` + return `[${inferTypeInline(sddmInlineType[1], typeName)}${isRequiredIndicator}]` +} + +const inferNamedType = (sddmNode: SchemaDrivenDataMap.ArgumentOrInputField): string => { + if (isScalar(sddmNode.nt)) { + return sddmNode.nt.name + } + + if (sddmNode.nt?.n) { + return sddmNode.nt.n + } + + throw new Error(`Unknown sddm node: ${String(sddmNode)}`) +} diff --git a/src/layers/3_SelectGraphQLMapper/mapper.ts b/src/layers/3_SelectGraphQLMapper/mapper.ts new file mode 100644 index 000000000..37987a2a7 --- /dev/null +++ b/src/layers/3_SelectGraphQLMapper/mapper.ts @@ -0,0 +1,26 @@ +import type { SchemaDrivenDataMap } from '../7_extensions/CustomScalars/schemaDrivenDataMap/types.js' +import type { OperationContext } from './context.js' + +export type GraphQLPreOperationMapper< + $SDDMNode extends SchemaDrivenDataMap.Node, + $Return, + $Args extends [...any[]] = [], +> = ( + ...args: [ + sddmNode: undefined | $SDDMNode, + ...$Args, + ] +) => $Return + +export type GraphQLPostOperationMapper< + $SDDMNode extends SchemaDrivenDataMap.Node, + $Return, + $Args extends [...any[]] = [], + $ContextExtension extends object = {}, +> = ( + ...args: [ + context: OperationContext & $ContextExtension, + sddmNode: undefined | $SDDMNode, + ...$Args, + ] +) => $Return diff --git a/src/layers/3_SelectGraphQLMapper/nodes/1_Document.ts b/src/layers/3_SelectGraphQLMapper/nodes/1_Document.ts new file mode 100644 index 000000000..9e42f0f0f --- /dev/null +++ b/src/layers/3_SelectGraphQLMapper/nodes/1_Document.ts @@ -0,0 +1,43 @@ +import type { SchemaDrivenDataMap } from '../../../entrypoints/utilities-for-generated.js' +import type { Grafaid } from '../../../lib/grafaid/__.js' +import { Nodes } from '../../../lib/grafaid/_Nodes.js' +import type { Select } from '../../2_Select/__.js' +import { toGraphQLOperationDefinition } from './2_OperationDefinition.js' + +const defaultOperationName = `$default` + +export const toGraphQLDocument = ( + graffleDocument: Select.Document.DocumentNormalized, + options?: Options, +): Encoded => { + const operationsAndVariables = Object + .values(graffleDocument.operations) + .map(graffleOperation => { + const sddm = options?.sddm?.roots[graffleOperation.rootType] + return toGraphQLOperationDefinition(sddm, graffleOperation, options) + }) + + const graphqlDocument = Nodes.Document({ + definitions: operationsAndVariables.map(_ => _.operation), + }) + + const operationsVariables = Object.fromEntries(operationsAndVariables.map((_): [string, Grafaid.Variables] => { + const name = _.operation.name?.value ?? defaultOperationName + return [name, _.variables] + })) + + return { + document: graphqlDocument, + operationsVariables, + } +} + +export interface Options { + sddm?: SchemaDrivenDataMap | null + operationVariables?: boolean +} + +export interface Encoded { + document: Grafaid.Document.DocumentNode + operationsVariables: Record +} diff --git a/src/layers/3_SelectGraphQLMapper/nodes/2_OperationDefinition.ts b/src/layers/3_SelectGraphQLMapper/nodes/2_OperationDefinition.ts new file mode 100644 index 000000000..21e9c4a90 --- /dev/null +++ b/src/layers/3_SelectGraphQLMapper/nodes/2_OperationDefinition.ts @@ -0,0 +1,54 @@ +import type { Grafaid } from '../../../lib/grafaid/__.js' +import { Nodes } from '../../../lib/grafaid/_Nodes.js' +import type { Select } from '../../2_Select/__.js' +import type { SchemaDrivenDataMap } from '../../7_extensions/CustomScalars/schemaDrivenDataMap/types.js' +import { createOperationContext } from '../context.js' +import { type GraphQLPreOperationMapper } from '../mapper.js' +import type { Options } from './1_Document.js' +import { toGraphQLSelectionSetRoot } from './3_GraffleSelectionSetRoot.js' + +export const toGraphQLOperationDefinition: GraphQLPreOperationMapper< + SchemaDrivenDataMap.OutputObject, + { operation: Nodes.OperationDefinitionNode; variables: Grafaid.Variables }, + [ + operation: Select.Document.OperationNormalized, + options?: Options, + ] +> = ( + sddmNode, + operation, + options, +) => { + const context = createOperationContext(options) + + const name = operation.name + ? Nodes.Name({ value: operation.name }) + : undefined + + const selectionSet = toGraphQLSelectionSetRoot(context, sddmNode, operation.selectionSet) + + const variableDefinitions = context.variables.data.map((captured) => { + return Nodes.VariableDefinition({ + variable: Nodes.Variable({ name: Nodes.Name({ value: captured.name }) }), + type: Nodes.NamedType({ name: Nodes.Name({ value: captured.typeName }) }), + }) + }) + + const graphqlOperation = Nodes.OperationDefinition({ + operation: operation.type, + name, + selectionSet, + variableDefinitions, + // todo support directives on operations ??? Check what this feature/capability is about + // directives + }) + + const variables: Grafaid.Variables = Object.fromEntries(context.variables.data.map(_ => { + return [_.name, _.value as any] + })) + + return { + operation: graphqlOperation, + variables, + } +} diff --git a/src/layers/3_SelectGraphQLMapper/nodes/3_GraffleSelectionSetRoot.ts b/src/layers/3_SelectGraphQLMapper/nodes/3_GraffleSelectionSetRoot.ts new file mode 100644 index 000000000..4d23d8510 --- /dev/null +++ b/src/layers/3_SelectGraphQLMapper/nodes/3_GraffleSelectionSetRoot.ts @@ -0,0 +1,24 @@ +import { Nodes } from '../../../lib/grafaid/_Nodes.js' +import { Select } from '../../2_Select/__.js' +import type { SchemaDrivenDataMap } from '../../7_extensions/CustomScalars/schemaDrivenDataMap/types.js' +import { type GraphQLPostOperationMapper } from '../mapper.js' +import { fromGraffleSelectionObjectLevel } from './4_GraffleSelectionObjectLevel.js' + +export const toGraphQLSelectionSetRoot: GraphQLPostOperationMapper< + SchemaDrivenDataMap.OutputObject, + Nodes.SelectionSetNode, + [ + selectionSet: Select.SelectionSet.AnySelectionSet, + ] +> = ( + context, + sddm, + selectionSet, +) => { + return Nodes.SelectionSet({ + selections: Object + .entries(selectionSet) + .map(([key, value]) => Select.parseSelectionRoot(key, value)) + .flatMap(keyParsed => fromGraffleSelectionObjectLevel(context, sddm, keyParsed)), + }) +} diff --git a/src/layers/3_SelectGraphQLMapper/nodes/4_GraffleSelectionObjectLevel.ts b/src/layers/3_SelectGraphQLMapper/nodes/4_GraffleSelectionObjectLevel.ts new file mode 100644 index 000000000..90d80c143 --- /dev/null +++ b/src/layers/3_SelectGraphQLMapper/nodes/4_GraffleSelectionObjectLevel.ts @@ -0,0 +1,62 @@ +import type { Grafaid } from '../../../lib/grafaid/__.js' +import { Nodes } from '../../../lib/grafaid/_Nodes.js' +import { casesExhausted, isNonNull } from '../../../lib/prelude.js' +import type { ParsedSelectionObjectLevel } from '../../2_Select/_.js' +import type { SchemaDrivenDataMap } from '../../7_extensions/CustomScalars/schemaDrivenDataMap/types.js' +import type { GraphQLPostOperationMapper } from '../mapper.js' +import { toGraphQLField } from './5_Field.js' +import { toGraphQLInlineFragments } from './5_InlineFragments.js' + +export const fromGraffleSelectionObjectLevel: GraphQLPostOperationMapper< + SchemaDrivenDataMap.OutputObject, + Grafaid.Document.SelectionNode[], + [ + keyParsed: ParsedSelectionObjectLevel, + ] +> = ( + context, + sddm, + selection, +) => { + switch (selection.type) { + case `Indicator`: { + if (!selection.select) return [] + + return [Nodes.Field({ + name: Nodes.Name({ value: selection.name }), + })] + } + case `InlineFragment`: { + return toGraphQLInlineFragments(context, sddm, selection) + } + case `Alias`: { + const sddmOutputField = sddm?.f[selection.name] + return selection.aliases.map(alias => { + return toGraphQLField(context, sddmOutputField, { + name: selection.name, + alias: alias[0], + value: alias[1], + }) + }).filter(isNonNull) + } + case `SelectionSet`: { + const sddmOutputField = sddm?.f[selection.name] + const outputField = { + alias: null, + name: selection.name, + value: selection.selectionSet, + } + return [toGraphQLField(context, sddmOutputField, outputField)].filter(isNonNull) + } + // todo make this an extension that requires the schema. + case `ScalarsWildcard`: { + // todo get scalar fields from the schema + throw new Error(`todo`) + } + // todo + // case 'FragmentSpread' + default: { + throw casesExhausted(selection) + } + } +} diff --git a/src/layers/3_SelectGraphQLMapper/nodes/5_Field.ts b/src/layers/3_SelectGraphQLMapper/nodes/5_Field.ts new file mode 100644 index 000000000..ece3afbf4 --- /dev/null +++ b/src/layers/3_SelectGraphQLMapper/nodes/5_Field.ts @@ -0,0 +1,87 @@ +import { Nodes } from '../../../lib/grafaid/_Nodes.js' +import { Select } from '../../2_Select/__.js' +import { SchemaDrivenDataMap } from '../../7_extensions/CustomScalars/schemaDrivenDataMap/types.js' +import type { GraphQLPostOperationMapper } from '../mapper.js' +import { collectForInlineFragmentLike } from './_collect.js' +import { toGraphQLArgument } from './Argument.js' + +export const toGraphQLField: GraphQLPostOperationMapper< + SchemaDrivenDataMap.OutputField, + Nodes.FieldNode | null, + [field: Field] +> = ( + context, + sddm, + field, +) => { + const fieldSelection = Select.parseSelectionField(field.name, field.value) + + const alias = field.alias + ? Nodes.Name({ value: field.alias }) + : undefined + + if (fieldSelection.type === `Indicator`) { + if (!fieldSelection.select) return null + return Nodes.Field({ + name: Nodes.Name({ value: field.name }), + alias, + }) + } + + const arguments_: Nodes.ArgumentNode[] = [] + const directives: Nodes.DirectiveNode[] = [] + const selections: Nodes.SelectionNode[] = [] + + for (const key in fieldSelection.selectionSet) { + const keyParsed = Select.parseSelection(key, fieldSelection.selectionSet[key]) + switch (keyParsed.type) { + case `Arguments`: { + const sddmArguments = sddm?.a + for (const argName in keyParsed.arguments) { + const argNameSchema = argName.replace(/^\$/, ``) + const sddmArgument = sddmArguments?.[argNameSchema] + const argValue = keyParsed.arguments[argName] + + if (context.variables.enabled && sddmArgument) { + const argument = context.variables.capture({ + name: argNameSchema, + value: argValue, + sddmArgument, + }) + arguments_.push(argument) + } else { + const argument = toGraphQLArgument(context, sddmArgument, { name: argName, value: argValue }) + arguments_.push(argument) + } + } + continue + } + default: { + // dprint-ignore + if (SchemaDrivenDataMap.isScalar(sddm?.nt) || SchemaDrivenDataMap.isOutputField(sddm?.nt) || SchemaDrivenDataMap.isEnum(sddm?.nt)) throw new Error(`schema map scalar on non-scalar graffle selection.`) + collectForInlineFragmentLike(context, sddm?.nt, keyParsed, { + directives, + selections, + }) + } + } + } + + return Nodes.Field({ + name: Nodes.Name({ + value: field.name, + }), + alias, + arguments: arguments_, + directives, + selectionSet: Nodes.SelectionSet({ + selections, + }), + }) +} + +export interface Field { + name: string + alias: string | null + value: Select.SelectionSet.Any +} diff --git a/src/layers/3_SelectGraphQLMapper/nodes/5_InlineFragments.ts b/src/layers/3_SelectGraphQLMapper/nodes/5_InlineFragments.ts new file mode 100644 index 000000000..e3879c43c --- /dev/null +++ b/src/layers/3_SelectGraphQLMapper/nodes/5_InlineFragments.ts @@ -0,0 +1,65 @@ +import type { Grafaid } from '../../../lib/grafaid/__.js' +import { Nodes } from '../../../lib/grafaid/_Nodes.js' +import { Select } from '../../2_Select/__.js' +import type { SchemaDrivenDataMap } from '../../7_extensions/CustomScalars/schemaDrivenDataMap/types.js' +import type { GraphQLPostOperationMapper } from '../mapper.js' +import { collectForInlineFragmentLike } from './_collect.js' + +export const toGraphQLInlineFragments: GraphQLPostOperationMapper< + SchemaDrivenDataMap.OutputObject, + Grafaid.Document.InlineFragmentNode[], + [inlineFragments: Select.ParsedSelectionInlineFragments] +> = ( + context, + sddm, + inlineFragments, +) => { + return inlineFragments.selectionSets.map(selectionSet => { + return toGraphQLInlineFragment(context, sddm, { + selectionSet, + typeCondition: inlineFragments.typeCondition, + }) + }) +} + +const toGraphQLInlineFragment: GraphQLPostOperationMapper< + SchemaDrivenDataMap.OutputObject, + Grafaid.Document.InlineFragmentNode, + [inlineFragment: InlineFragment] +> = ( + context, + sddm, + inlineFragment, +) => { + const typeCondition = inlineFragment.typeCondition + ? Nodes.NamedType({ + name: Nodes.Name({ + value: inlineFragment.typeCondition, + }), + }) + : undefined + + const directives: Nodes.DirectiveNode[] = [] + const selections: Nodes.SelectionNode[] = [] + + for (const key in inlineFragment.selectionSet) { + const keyParsed = Select.parseSelectionInlineFragment(key, inlineFragment.selectionSet[key]) + collectForInlineFragmentLike(context, sddm, keyParsed, { + directives, + selections, + }) + } + + return Nodes.InlineFragment({ + typeCondition, + directives, + selectionSet: Nodes.SelectionSet({ + selections, + }), + }) +} + +interface InlineFragment { + typeCondition: Select.ParsedSelectionInlineFragments['typeCondition'] + selectionSet: Select.ParsedSelectionInlineFragments['selectionSets'][number] +} diff --git a/src/layers/3_SelectGraphQLMapper/nodes/Argument.ts b/src/layers/3_SelectGraphQLMapper/nodes/Argument.ts index 57812e7bb..64779e9ec 100644 --- a/src/layers/3_SelectGraphQLMapper/nodes/Argument.ts +++ b/src/layers/3_SelectGraphQLMapper/nodes/Argument.ts @@ -1,6 +1,7 @@ import { Nodes } from '../../../lib/grafaid/_Nodes.js' import { Select } from '../../2_Select/__.js' -import { advanceIndex, type GraphQLNodeMapper } from '../types.js' +import type { SchemaDrivenDataMap } from '../../7_extensions/CustomScalars/schemaDrivenDataMap/types.js' +import { type GraphQLPostOperationMapper } from '../mapper.js' import { toGraphQLValue } from './Value.js' export interface Argument { @@ -8,21 +9,23 @@ export interface Argument { value: Select.Arguments.ArgValue } -export const toGraphQLArgument: GraphQLNodeMapper< +export const toGraphQLArgument: GraphQLPostOperationMapper< + SchemaDrivenDataMap.ArgumentOrInputField, Nodes.ArgumentNode, [arg: Argument] > = ( context, - index, + sddm, arg, ) => { - const value = toGraphQLValue( - { ...context, value: { isEnum: Select.Arguments.isEnumKey(arg.name) } }, - advanceIndex(index, arg.name), - arg.value, - ) + // return Nodes.Variable({ name: Nodes.Name({ value: `abc` }) }) + const valueContext = { ...context, value: { isEnum: Select.Arguments.isEnumKey(arg.name) } } + const value = toGraphQLValue(valueContext, sddm, arg.value) const name = Nodes.Name({ value: arg.name.replace(Select.Arguments.enumKeyPrefixPattern, ``) }) - return Nodes.Argument({ name, value }) + return Nodes.Argument({ + name, + value, + }) } diff --git a/src/layers/3_SelectGraphQLMapper/nodes/Directive.ts b/src/layers/3_SelectGraphQLMapper/nodes/Directive.ts index 3ad8e6663..55c300e6c 100644 --- a/src/layers/3_SelectGraphQLMapper/nodes/Directive.ts +++ b/src/layers/3_SelectGraphQLMapper/nodes/Directive.ts @@ -1,41 +1,49 @@ +import type { SchemaDrivenDataMap } from '../../../entrypoints/utilities-for-generated.js' import { Nodes } from '../../../lib/grafaid/_Nodes.js' -import { getFromEnumLooselyOrThrow } from '../../../lib/prelude.js' -import { Select } from '../../2_Select/__.js' -import type { GraphQLNodeMapper } from '../types.js' +import type { Select } from '../../2_Select/__.js' +import type { GraphQLPostOperationMapper } from '../mapper.js' import { toGraphQLValue } from './Value.js' -export const toGraphQLDirective: GraphQLNodeMapper< - Nodes.DirectiveNode, - [directive: Select.Directive.DirectiveLike] +export const toGraphQLDirective: GraphQLPostOperationMapper< + SchemaDrivenDataMap.ArgumentsOrInputObjectFields, + Nodes.DirectiveNode | null, + [graffleExpressions: Select.ParsedSelectionDirective] > = ( context, - location, + sddmArguments, directive, ) => { - const definition = getFromEnumLooselyOrThrow(Select.Directive.definitionsByName, directive.name) + if (directive.arguments === null) return null - const graphqlArguments = Object.entries(directive.arguments).map( - ([argumentName, argumentValue]) => { - const argumentType = definition.type.arguments[argumentName]?.type - if (argumentType === undefined) { - throw new Error(`Argument ${argumentName} is required`) - } + const arguments_: Nodes.ArgumentNode[] = [] - // todo lift directive arguments to document variables - const value = toGraphQLValue({ ...context, value: { isEnum: false } }, location, argumentValue) - return Nodes.Argument({ - name: Nodes.Name({ - value: argumentName, - }), - value, + for (const argumentName in directive.arguments.parsed) { + const argumentValue = directive.arguments.parsed[argumentName] + + const sddmArgument = sddmArguments?.[argumentName] + let argument: Nodes.ArgumentNode + + if (context.variables.enabled && sddmArgument) { + argument = context.variables.capture({ + name: argumentName, + value: argumentValue, + sddmArgument, }) - }, - ) + } else { + const name = Nodes.Name({ value: argumentName }) + const value = toGraphQLValue( + { ...context, value: { isEnum: false } }, + sddmArgument, + argumentValue, + ) + argument = Nodes.Argument({ name, value }) + } - const graphqlDirective = Nodes.Directive({ + arguments_.push(argument) + } + + return Nodes.Directive({ name: Nodes.Name({ value: directive.name }), - arguments: graphqlArguments, + arguments: arguments_, }) - - return graphqlDirective } diff --git a/src/layers/3_SelectGraphQLMapper/nodes/Document.test.ts b/src/layers/3_SelectGraphQLMapper/nodes/Document.test.ts deleted file mode 100644 index 099aa56a4..000000000 --- a/src/layers/3_SelectGraphQLMapper/nodes/Document.test.ts +++ /dev/null @@ -1,143 +0,0 @@ -import { print } from 'graphql' -import { describe, expect, test } from 'vitest' -import { db } from '../../../../tests/_/schemas/db.js' -import { $index as customScalarsIndex } from '../../../../tests/_/schemas/kitchen-sink/graffle/modules/RuntimeCustomScalars.js' -import type * as SelectionSets from '../../../../tests/_/schemas/kitchen-sink/graffle/modules/SelectionSets.js' -import { Select } from '../../2_Select/__.js' -import type { Context } from '../types.js' -import { toGraphQLDocument } from './Document.js' - -type CasesQuery = [selectionSet: SelectionSets.Query] - -type CasesDescriptiveQuery = [description: string, selectionSet: SelectionSets.Query] - -const testEachArguments = [ - `Query - %s`, - (...args: CasesQuery | CasesDescriptiveQuery) => { - const [description, selectionSet] = args.length === 1 ? [undefined, args[0]] : args - - const context: Context = { - captures: { - variables: [], - customScalarOutputs: [], - }, - } - const documentNormalized = Select.Document.createDocumentNormalizedFromRootTypeSelection( - `Query`, - selectionSet as any, - ) - - const graphqlDocument = toGraphQLDocument(context, customScalarsIndex as any, documentNormalized) - const graphqlDocumentStringFormatted = print(graphqlDocument) - - const beforeAfter = `\n` - + JSON.stringify(selectionSet, null, 2) - + `\n--------------\n` - + graphqlDocumentStringFormatted - + `\n` - expect(beforeAfter).toMatchSnapshot(description) - }, -] as const - -describe(`inline fragment`, () => { - describe(`field group`, () => { - test.each([ - [`one`, { ___: { __typename: true } }], - [`multiple`, { ___: [{ __typename: true }, { abcEnum: true }] }], - [`interface`, { interface: { ___: { __typename: true } } }], - [`union`, { unionFooBar: { ___: { __typename: true } } }], - [`directive`, { ___: { __typename: true, $include: true } }], - ])(...testEachArguments) - }) - - describe(`type condition union`, () => { - test.each([ - [`__typename (no fragment)`, { unionFooBar: { __typename: true } }], - [`scalar`, { unionFooBar: { ___on_Bar: { int: true } } }], - [`directive`, { unionFooBar: { ___on_Bar: { $skip: true, int: true } } }], - // s({ unionFooBar: { __on_Bar: {} } }), // todo should be static type error - ])(...testEachArguments) - }) -}) - -describe(`enum`, () => { - test.each([ - [{ result: { $: { $case: `Object1` }, __typename: true } }], - ])(...testEachArguments) -}) - -describe(`alias`, () => { - test.each([ - [{ id: [`x`, true] }], - [{ id: [[`x`, true], [`id2`, true]] }], - [{ id: [`x`, { $skip: true }] }], - [{ object: [`x`, { $skip: true, id: true }] }], - ])(...testEachArguments) -}) - -describe(`arguments`, () => { - test.each([ - [{ stringWithArgs: { $: { boolean: true, float: 1 } } }], - [{ stringWithArgs: { $: {} } }], - // s({ objectWithArgs: { $: { id: `` } } }), // todo should be static error - // s({ objectWithArgs: { $: {} } }), // todo should be static error - [{ objectWithArgs: { $: { id: `` }, id: true } }], - [{ objectWithArgs: { $: {}, id: true } }], - ])(...testEachArguments) - - // dprint-ignore - describe(`custom scalars`, () => { - test.each([ - [`arg field`, { dateArg: { $: { date: db.date0 } } }], - [`arg field in non-null`, { dateArgNonNull: { $: { date: db.date0 } } }], - [`arg field in list`, { dateArgList: { $: { date: [db.date0, new Date(1)] } } }], - [`arg field in list (null)`, { dateArgList: { $: { date: null } } }], - [`arg field in non-null list (with list)`, { dateArgNonNullList: { $: { date: [db.date0, new Date(1)] } } }], - [`arg field in non-null list (with null)`, { dateArgNonNullList: { $: { date: [null, db.date0] } } }], - [`arg field in non-null list non-null`, { dateArgNonNullListNonNull: { $: { date: [db.date0, new Date(1)] } } }], - [`input object field`, { dateArgInputObject: { $: { input: { idRequired: ``, dateRequired: db.date0, date: new Date(1) } } } }], - [`nested input object field`, { InputObjectNested: { $: { input: { InputObject: { idRequired: ``, dateRequired: db.date0, date: new Date(1) } } } } }] - ])(...testEachArguments) - }) -}) - -describe(`directive`, () => { - describe(`$include`, () => { - test.each([ - [{ object: { $include: true, id: true } }], - [{ object: { $include: false, id: true } }], - [{ object: { $include: undefined, id: true } }], - [{ object: { $include: { if: true }, id: true } }], - [{ object: { $include: { if: false }, id: true } }], - [{ object: { $include: { if: undefined }, id: true } }], - [{ object: { $include: {}, id: true } }], - ])(...testEachArguments) - }) - - describe(`$skip`, () => { - test.each([ - [{ object: { $skip: true, id: true } }], - [{ object: { $skip: false, id: true } }], - [{ object: { $skip: undefined, id: true } }], - [{ object: { $skip: { if: true }, id: true } }], - [{ object: { $skip: { if: false }, id: true } }], - [{ object: { $skip: { if: undefined }, id: true } }], - [{ object: { $skip: {}, id: true } }], - ])(...testEachArguments) - }) -}) - -describe(`other`, () => { - test.each([ - [{ __typename: true }], - [{ string: true }], - // [{ string: 1 }], - // s({ string: false }), // todo should be static error - [{ id: true, string: false }], - // [{ id: true, string: 0 }], - [{ id: true, string: undefined }], - [{ object: { id: true } }], - [{ objectNested: { object: { string: true, id: true, int: false } } }], - [{ objectNested: { object: { string: true, id: true, int: { $skip: true } } } }], - ])(...testEachArguments) -}) diff --git a/src/layers/3_SelectGraphQLMapper/nodes/Document.ts b/src/layers/3_SelectGraphQLMapper/nodes/Document.ts deleted file mode 100644 index beaee9a64..000000000 --- a/src/layers/3_SelectGraphQLMapper/nodes/Document.ts +++ /dev/null @@ -1,22 +0,0 @@ -import { Nodes } from '../../../lib/grafaid/_Nodes.js' -import type { Select } from '../../2_Select/__.js' -import { advanceIndex, type GraphQLNodeMapper } from '../types.js' -import { toGraphQLOperationDefinition } from './OperationDefinition.js' - -export const toGraphQLDocument: GraphQLNodeMapper< - Nodes.DocumentNode, - [document: Select.Document.DocumentNormalized] -> = ( - context, - index, - document, -) => { - const operations = Object.values(document.operations) - const definitions = operations.map(operation => { - return toGraphQLOperationDefinition(context, advanceIndex(index, operation.rootType), operation) - }) - - return Nodes.Document({ - definitions, - }) -} diff --git a/src/layers/3_SelectGraphQLMapper/nodes/Field.ts b/src/layers/3_SelectGraphQLMapper/nodes/Field.ts deleted file mode 100644 index 5963b570e..000000000 --- a/src/layers/3_SelectGraphQLMapper/nodes/Field.ts +++ /dev/null @@ -1,45 +0,0 @@ -import { Nodes } from '../../../lib/grafaid/_Nodes.js' -import { Select } from '../../2_Select/__.js' -import { advanceIndex, type Field } from '../types.js' -import type { GraphQLNodeMapper } from '../types.js' -import { type SelectionSetContext, toGraphQLSelectionSet } from './SelectionSet.js' - -export const toGraphQLField: GraphQLNodeMapper = ( - context, - index, - field, -) => { - const alias = field.alias - ? Nodes.Name({ value: field.alias }) - : undefined - - if (Select.Indicator.isPositiveIndicator(field.value)) { - return Nodes.Field({ - name: Nodes.Name({ value: field.name }), - alias, - }) - } - - const selectionSetContext: SelectionSetContext = { - kind: `Field`, - arguments: [], - directives: [], - } - - const selectionSet = toGraphQLSelectionSet( - context, - advanceIndex(index, field.name), - field.value as any, // todo fix any - selectionSetContext, - ) - - return Nodes.Field({ - name: Nodes.Name({ - value: field.name, - }), - arguments: selectionSetContext.arguments, - directives: selectionSetContext.directives, - alias, - selectionSet, - }) -} diff --git a/src/layers/3_SelectGraphQLMapper/nodes/InlineFragment.ts b/src/layers/3_SelectGraphQLMapper/nodes/InlineFragment.ts deleted file mode 100644 index 823ca1f8d..000000000 --- a/src/layers/3_SelectGraphQLMapper/nodes/InlineFragment.ts +++ /dev/null @@ -1,41 +0,0 @@ -import { Nodes } from '../../../lib/grafaid/_Nodes.js' -import type { Select } from '../../2_Select/__.js' -import type { GraphQLNodeMapper } from '../types.js' -import { type SelectionSetContext, toGraphQLSelectionSet } from './SelectionSet.js' - -export const toGraphQLInlineFragment: GraphQLNodeMapper< - Nodes.InlineFragmentNode, - [inlineFragment: InlineFragmentNormalized] -> = ( - context, - location, - inlineFragment, -) => { - const typeCondition = inlineFragment.typeCondition - ? Nodes.NamedType({ - name: Nodes.Name({ - value: inlineFragment.typeCondition, - }), - }) - : undefined - - const graphqlDirectives: Nodes.DirectiveNode[] = [] - - const selectionSetContext: SelectionSetContext = { - kind: `InlineFragment`, - directives: graphqlDirectives, - } - - const selectionSet = toGraphQLSelectionSet(context, location, inlineFragment.selectionSet, selectionSetContext) - - return Nodes.InlineFragment({ - typeCondition, - directives: graphqlDirectives, - selectionSet, - }) -} - -export interface InlineFragmentNormalized { - selectionSet: Select.SelectionSet.AnySelectionSet - typeCondition: null | string -} diff --git a/src/layers/3_SelectGraphQLMapper/nodes/OperationDefinition.ts b/src/layers/3_SelectGraphQLMapper/nodes/OperationDefinition.ts deleted file mode 100644 index 6ee196105..000000000 --- a/src/layers/3_SelectGraphQLMapper/nodes/OperationDefinition.ts +++ /dev/null @@ -1,29 +0,0 @@ -import { Nodes } from '../../../lib/grafaid/_Nodes.js' -import type { Select } from '../../2_Select/__.js' -import type { GraphQLNodeMapper } from '../types.js' -import { toGraphQLSelectionSet } from './SelectionSet.js' - -export const toGraphQLOperationDefinition: GraphQLNodeMapper< - Nodes.OperationDefinitionNode, - [operation: Select.Document.OperationNormalized] -> = ( - context, - index, - operation, -) => { - const selectionSet = toGraphQLSelectionSet(context, index, operation.selectionSet, undefined) - - const name = operation.name - ? Nodes.Name({ value: operation.name }) - : undefined - - return Nodes.OperationDefinition({ - operation: operation.type, - name, - selectionSet, - // todo support directives on operations ??? Check what this feature/capability is about - // directives - // todo, we have to extract variables from the context after traversal. - // variableDefinitions: [], - }) -} diff --git a/src/layers/3_SelectGraphQLMapper/nodes/SelectionSet.ts b/src/layers/3_SelectGraphQLMapper/nodes/SelectionSet.ts deleted file mode 100644 index b550c6c1a..000000000 --- a/src/layers/3_SelectGraphQLMapper/nodes/SelectionSet.ts +++ /dev/null @@ -1,115 +0,0 @@ -import { Nodes } from '../../../lib/grafaid/_Nodes.js' -import { casesExhausted } from '../../../lib/prelude.js' -import { Select } from '../../2_Select/__.js' -import { advanceIndex, type GraphQLNodeMapper } from '../types.js' -import { toGraphQLArgument } from './Argument.js' -import { toGraphQLDirective } from './Directive.js' -import { toGraphQLField } from './Field.js' -import { toGraphQLInlineFragment } from './InlineFragment.js' - -export type SelectionSetContext = { - kind: `Field` - arguments: Nodes.ArgumentNode[] - directives: Nodes.DirectiveNode[] -} | { - kind: `InlineFragment` - directives: Nodes.DirectiveNode[] -} - -export const toGraphQLSelectionSet: GraphQLNodeMapper< - Nodes.SelectionSetNode, - [ - selectionSet: Select.SelectionSet.AnySelectionSet, - graphqlFieldProperties: SelectionSetContext | undefined, - ] -> = ( - context, - index, - selectionSet, - selectionSetContext, -) => { - const selections: Nodes.SelectionNode[] = [] - - for (const key in selectionSet) { - const keyParsed = Select.parseSelection(key, selectionSet[key]) - - switch (keyParsed.type) { - case `Arguments`: - if (!selectionSetContext) { - throw new Error(`No selection set context to push arguments to.`) - } - if (selectionSetContext.kind === `InlineFragment`) { - throw new Error(`Cannot have arguments on an inline fragment.`) - } - // todo import constant from generator for "i" - // ... do NOT use namespace since that would drag generator code into tree-shake output. - const index_ = advanceIndex(index, `i`) - for (const argName in keyParsed.arguments) { - const argValue = keyParsed.arguments[argName] - // We don't do client side validation, let server handle schema errors. - const arg = { - name: argName, - value: argValue, - } - selectionSetContext.arguments.push(toGraphQLArgument(context, index_, arg)) - } - continue - case `DirectiveNoop`: { - continue // drop from selection set - } - case `Directive`: - if (!selectionSetContext) { - throw new Error(`No selection set context to push directives to.`) - } - selectionSetContext.directives.push(toGraphQLDirective(context, index, keyParsed)) - continue - case `Indicator`: { - if (!keyParsed.select) continue - selections.push(Nodes.Field({ - name: Nodes.Name({ - value: keyParsed.name, - }), - })) - continue - } - case `InlineFragment`: { - for (const selectionSet of keyParsed.selectionSets) { - selections.push( - toGraphQLInlineFragment(context, index, { typeCondition: keyParsed.typeCondition, selectionSet }), - ) - } - continue - } - case `Alias`: { - for (const alias of keyParsed.aliases) { - selections.push(toGraphQLField(context, index, { - name: key, - alias: alias[0], - value: alias[1], - })) - } - continue - } - case `SelectionSet`: { - selections.push( - toGraphQLField(context, index, { alias: null, name: keyParsed.name, value: keyParsed.selectionSet }), - ) - continue - } - // todo make this an extension that requires the schema. - case `ScalarsWildcard`: { - // todo get scalar fields from the schema - throw new Error(`todo`) - } - // todo - // case 'FragmentSpread' - default: { - casesExhausted(keyParsed) - } - } - } - - return Nodes.SelectionSet({ - selections, - }) -} diff --git a/src/layers/3_SelectGraphQLMapper/nodes/Value.ts b/src/layers/3_SelectGraphQLMapper/nodes/Value.ts index f33ee151b..79b045ed6 100644 --- a/src/layers/3_SelectGraphQLMapper/nodes/Value.ts +++ b/src/layers/3_SelectGraphQLMapper/nodes/Value.ts @@ -1,14 +1,21 @@ -import type { ValueNode } from 'graphql' +import type { Grafaid } from '../../../lib/grafaid/__.js' import { Nodes } from '../../../lib/grafaid/_Nodes.js' -import { advanceIndex, type CodecString, type GraphQLNodeMapper, isCodec } from '../types.js' +import type { Scalar } from '../../1_Schema/_.js' +import { SchemaDrivenDataMap } from '../../7_extensions/CustomScalars/schemaDrivenDataMap/types.js' +import type { OperationContext } from '../context.js' +import { type GraphQLPostOperationMapper } from '../mapper.js' -export const toGraphQLValue: ValueMapper = (context, index, value) => { +export const toGraphQLValue: ValueMapper = (context, sddm, value) => { // todo remove? unused. // const hookResult = context.hooks?.value?.(context, index, value) // if (hookResult) return hookResult - if (isCodec(index)) { - return applyCodec(index, value) + if (SchemaDrivenDataMap.isScalar(sddm?.nt)) { + return applyScalar(context, sddm.nt, value) + } + + if (SchemaDrivenDataMap.isEnum(sddm?.nt)) { + return Nodes.EnumValue({ value: String(value) }) } if (value === null) { @@ -20,7 +27,7 @@ export const toGraphQLValue: ValueMapper = (context, index, value) => { values: value.map(oneValue => toGraphQLValue( context, - index, + sddm, oneValue, ) ), @@ -28,11 +35,12 @@ export const toGraphQLValue: ValueMapper = (context, index, value) => { } if (typeof value === `object`) { + const sddmInputObject = sddm?.nt return Nodes.ObjectValue({ fields: Object.entries(value).map(([fieldName, fieldValue]) => { return Nodes.ObjectField({ name: Nodes.Name({ value: fieldName }), - value: toGraphQLValue(context, advanceIndex(index, fieldName), fieldValue), + value: toGraphQLValue(context, sddmInputObject?.f?.[fieldName], fieldValue), }) }), }) @@ -56,27 +64,33 @@ export const toGraphQLValue: ValueMapper = (context, index, value) => { throw new Error(`Unsupported value: ${String(value)}`) } -export type ValueMapper = GraphQLNodeMapper< - ValueNode, +export type ValueMapper = GraphQLPostOperationMapper< + SchemaDrivenDataMap.ArgumentOrInputField, + Grafaid.Document.ValueNode, [value: unknown], - { value: ValueContext } + AdditionalContext > -type ValueContext = { - isEnum: boolean +interface AdditionalContext { + value: { + isEnum: boolean + } } -const applyCodec = ( - codec: CodecString, +const applyScalar = ( + context: OperationContext & AdditionalContext, + scalar: Scalar.Scalar, value: unknown, -): Nodes.ListValueNode | Nodes.StringValueNode | Nodes.NullValueNode => { +): Grafaid.Document.ValueNode => { if (value === null) return Nodes.NullValue() if (Array.isArray(value)) { return Nodes.ListValue({ - values: value.map(oneValue => applyCodec(codec, oneValue)), + values: value.map(oneValue => applyScalar(context, scalar, oneValue)), }) } - return Nodes.StringValue({ value: codec.encode(value) }) + const valueEncoded = scalar.codec.encode(value) + + return toGraphQLValue(context, undefined, valueEncoded) } diff --git a/src/layers/3_SelectGraphQLMapper/nodes/__snapshots__/Document.test.ts.snap b/src/layers/3_SelectGraphQLMapper/nodes/__snapshots__/Document.test.ts.snap deleted file mode 100644 index f1e5c24fc..000000000 --- a/src/layers/3_SelectGraphQLMapper/nodes/__snapshots__/Document.test.ts.snap +++ /dev/null @@ -1,847 +0,0 @@ -// Vitest Snapshot v1, https://vitest.dev/guide/snapshot.html - -exports[`alias > Query - { id: [ 'x', { 'undefined': true } ] } 1`] = ` -" -{ - "id": [ - "x", - { - "$skip": true - } - ] -} --------------- -{ - x: id @skip(if: true) -} -" -`; - -exports[`alias > Query - { id: [ 'x', true ] } 1`] = ` -" -{ - "id": [ - "x", - true - ] -} --------------- -{ - x: id -} -" -`; - -exports[`alias > Query - { id: [ [ 'x', true ], [ 'id2', true ] ] } 1`] = ` -" -{ - "id": [ - [ - "x", - true - ], - [ - "id2", - true - ] - ] -} --------------- -{ - x: id - id2: id -} -" -`; - -exports[`alias > Query - { object: [ 'x', { 'undefined': true, id: true } ] } 1`] = ` -" -{ - "object": [ - "x", - { - "$skip": true, - "id": true - } - ] -} --------------- -{ - x: object @skip(if: true) { - id - } -} -" -`; - -exports[`arguments > Query - { objectWithArgs: { '$': { id: '' }, id: true } } 1`] = ` -" -{ - "objectWithArgs": { - "$": { - "id": "" - }, - "id": true - } -} --------------- -{ - objectWithArgs(id: "") { - id - } -} -" -`; - -exports[`arguments > Query - { objectWithArgs: { '$': {}, id: true } } 1`] = ` -" -{ - "objectWithArgs": { - "$": {}, - "id": true - } -} --------------- -{ - objectWithArgs { - id - } -} -" -`; - -exports[`arguments > Query - { stringWithArgs: { '$': { boolean: true, float: 1 } } } 1`] = ` -" -{ - "stringWithArgs": { - "$": { - "boolean": true, - "float": 1 - } - } -} --------------- -{ - stringWithArgs(boolean: true, float: 1) -} -" -`; - -exports[`arguments > Query - { stringWithArgs: { '$': {} } } 1`] = ` -" -{ - "stringWithArgs": { - "$": {} - } -} --------------- -{ - stringWithArgs -} -" -`; - -exports[`arguments > custom scalars > Query - arg field > arg field 1`] = ` -" -{ - "dateArg": { - "$": { - "date": "1970-01-01T00:00:00.000Z" - } - } -} --------------- -{ - dateArg(date: "1970-01-01T00:00:00.000Z") -} -" -`; - -exports[`arguments > custom scalars > Query - arg field in list (null) > arg field in list (null) 1`] = ` -" -{ - "dateArgList": { - "$": { - "date": null - } - } -} --------------- -{ - dateArgList(date: null) -} -" -`; - -exports[`arguments > custom scalars > Query - arg field in list > arg field in list 1`] = ` -" -{ - "dateArgList": { - "$": { - "date": [ - "1970-01-01T00:00:00.000Z", - "1970-01-01T00:00:00.001Z" - ] - } - } -} --------------- -{ - dateArgList(date: ["1970-01-01T00:00:00.000Z", "1970-01-01T00:00:00.001Z"]) -} -" -`; - -exports[`arguments > custom scalars > Query - arg field in non-null > arg field in non-null 1`] = ` -" -{ - "dateArgNonNull": { - "$": { - "date": "1970-01-01T00:00:00.000Z" - } - } -} --------------- -{ - dateArgNonNull(date: "1970-01-01T00:00:00.000Z") -} -" -`; - -exports[`arguments > custom scalars > Query - arg field in non-null list (with list) > arg field in non-null list (with list) 1`] = ` -" -{ - "dateArgNonNullList": { - "$": { - "date": [ - "1970-01-01T00:00:00.000Z", - "1970-01-01T00:00:00.001Z" - ] - } - } -} --------------- -{ - dateArgNonNullList( - date: ["1970-01-01T00:00:00.000Z", "1970-01-01T00:00:00.001Z"] - ) -} -" -`; - -exports[`arguments > custom scalars > Query - arg field in non-null list (with null) > arg field in non-null list (with null) 1`] = ` -" -{ - "dateArgNonNullList": { - "$": { - "date": [ - null, - "1970-01-01T00:00:00.000Z" - ] - } - } -} --------------- -{ - dateArgNonNullList(date: [null, "1970-01-01T00:00:00.000Z"]) -} -" -`; - -exports[`arguments > custom scalars > Query - arg field in non-null list non-null > arg field in non-null list non-null 1`] = ` -" -{ - "dateArgNonNullListNonNull": { - "$": { - "date": [ - "1970-01-01T00:00:00.000Z", - "1970-01-01T00:00:00.001Z" - ] - } - } -} --------------- -{ - dateArgNonNullListNonNull( - date: ["1970-01-01T00:00:00.000Z", "1970-01-01T00:00:00.001Z"] - ) -} -" -`; - -exports[`arguments > custom scalars > Query - input object field > input object field 1`] = ` -" -{ - "dateArgInputObject": { - "$": { - "input": { - "idRequired": "", - "dateRequired": "1970-01-01T00:00:00.000Z", - "date": "1970-01-01T00:00:00.001Z" - } - } - } -} --------------- -{ - dateArgInputObject( - input: {idRequired: "", dateRequired: "1970-01-01T00:00:00.000Z", date: "1970-01-01T00:00:00.001Z"} - ) -} -" -`; - -exports[`arguments > custom scalars > Query - nested input object field > nested input object field 1`] = ` -" -{ - "InputObjectNested": { - "$": { - "input": { - "InputObject": { - "idRequired": "", - "dateRequired": "1970-01-01T00:00:00.000Z", - "date": "1970-01-01T00:00:00.001Z" - } - } - } - } -} --------------- -{ - InputObjectNested( - input: {InputObject: {idRequired: "", dateRequired: "1970-01-01T00:00:00.000Z", date: "1970-01-01T00:00:00.001Z"}} - ) -} -" -`; - -exports[`directive > $include > Query - { object: { 'undefined': { if: false }, id: true } } 1`] = ` -" -{ - "object": { - "$include": { - "if": false - }, - "id": true - } -} --------------- -{ - object @include(if: false) { - id - } -} -" -`; - -exports[`directive > $include > Query - { object: { 'undefined': { if: true }, id: true } } 1`] = ` -" -{ - "object": { - "$include": { - "if": true - }, - "id": true - } -} --------------- -{ - object @include(if: true) { - id - } -} -" -`; - -exports[`directive > $include > Query - { object: { 'undefined': { if: undefined }, id: true } } 1`] = ` -" -{ - "object": { - "$include": {}, - "id": true - } -} --------------- -{ - object @include(if: true) { - id - } -} -" -`; - -exports[`directive > $include > Query - { object: { 'undefined': {}, id: true } } 1`] = ` -" -{ - "object": { - "$include": {}, - "id": true - } -} --------------- -{ - object @include(if: true) { - id - } -} -" -`; - -exports[`directive > $include > Query - { object: { 'undefined': false, id: true } } 1`] = ` -" -{ - "object": { - "$include": false, - "id": true - } -} --------------- -{ - object @include(if: false) { - id - } -} -" -`; - -exports[`directive > $include > Query - { object: { 'undefined': true, id: true } } 1`] = ` -" -{ - "object": { - "$include": true, - "id": true - } -} --------------- -{ - object @include(if: true) { - id - } -} -" -`; - -exports[`directive > $include > Query - { object: { 'undefined': undefined, id: true } } 1`] = ` -" -{ - "object": { - "id": true - } -} --------------- -{ - object { - id - } -} -" -`; - -exports[`directive > $skip > Query - { object: { 'undefined': { if: false }, id: true } } 1`] = ` -" -{ - "object": { - "$skip": { - "if": false - }, - "id": true - } -} --------------- -{ - object @skip(if: false) { - id - } -} -" -`; - -exports[`directive > $skip > Query - { object: { 'undefined': { if: true }, id: true } } 1`] = ` -" -{ - "object": { - "$skip": { - "if": true - }, - "id": true - } -} --------------- -{ - object @skip(if: true) { - id - } -} -" -`; - -exports[`directive > $skip > Query - { object: { 'undefined': { if: undefined }, id: true } } 1`] = ` -" -{ - "object": { - "$skip": {}, - "id": true - } -} --------------- -{ - object @skip(if: true) { - id - } -} -" -`; - -exports[`directive > $skip > Query - { object: { 'undefined': {}, id: true } } 1`] = ` -" -{ - "object": { - "$skip": {}, - "id": true - } -} --------------- -{ - object @skip(if: true) { - id - } -} -" -`; - -exports[`directive > $skip > Query - { object: { 'undefined': false, id: true } } 1`] = ` -" -{ - "object": { - "$skip": false, - "id": true - } -} --------------- -{ - object @skip(if: false) { - id - } -} -" -`; - -exports[`directive > $skip > Query - { object: { 'undefined': true, id: true } } 1`] = ` -" -{ - "object": { - "$skip": true, - "id": true - } -} --------------- -{ - object @skip(if: true) { - id - } -} -" -`; - -exports[`directive > $skip > Query - { object: { 'undefined': undefined, id: true } } 1`] = ` -" -{ - "object": { - "id": true - } -} --------------- -{ - object { - id - } -} -" -`; - -exports[`enum > Query - { result: { '$': { 'undefined': 'Object1' }, __typename: true } } 1`] = ` -" -{ - "result": { - "$": { - "$case": "Object1" - }, - "__typename": true - } -} --------------- -{ - result(case: Object1) { - __typename - } -} -" -`; - -exports[`inline fragment > field group > Query - directive > directive 1`] = ` -" -{ - "___": { - "__typename": true, - "$include": true - } -} --------------- -{ - ... @include(if: true) { - __typename - } -} -" -`; - -exports[`inline fragment > field group > Query - interface > interface 1`] = ` -" -{ - "interface": { - "___": { - "__typename": true - } - } -} --------------- -{ - interface { - ... { - __typename - } - } -} -" -`; - -exports[`inline fragment > field group > Query - multiple > multiple 1`] = ` -" -{ - "___": [ - { - "__typename": true - }, - { - "abcEnum": true - } - ] -} --------------- -{ - ... { - __typename - } - ... { - abcEnum - } -} -" -`; - -exports[`inline fragment > field group > Query - one > one 1`] = ` -" -{ - "___": { - "__typename": true - } -} --------------- -{ - ... { - __typename - } -} -" -`; - -exports[`inline fragment > field group > Query - union > union 1`] = ` -" -{ - "unionFooBar": { - "___": { - "__typename": true - } - } -} --------------- -{ - unionFooBar { - ... { - __typename - } - } -} -" -`; - -exports[`inline fragment > type condition union > Query - __typename (no fragment) > __typename (no fragment) 1`] = ` -" -{ - "unionFooBar": { - "__typename": true - } -} --------------- -{ - unionFooBar { - __typename - } -} -" -`; - -exports[`inline fragment > type condition union > Query - directive > directive 1`] = ` -" -{ - "unionFooBar": { - "___on_Bar": { - "$skip": true, - "int": true - } - } -} --------------- -{ - unionFooBar { - ... on Bar @skip(if: true) { - int - } - } -} -" -`; - -exports[`inline fragment > type condition union > Query - scalar > scalar 1`] = ` -" -{ - "unionFooBar": { - "___on_Bar": { - "int": true - } - } -} --------------- -{ - unionFooBar { - ... on Bar { - int - } - } -} -" -`; - -exports[`other > Query - { __typename: true } 1`] = ` -" -{ - "__typename": true -} --------------- -{ - __typename -} -" -`; - -exports[`other > Query - { id: true, string: false } 1`] = ` -" -{ - "id": true, - "string": false -} --------------- -{ - id -} -" -`; - -exports[`other > Query - { id: true, string: undefined } 1`] = ` -" -{ - "id": true -} --------------- -{ - id -} -" -`; - -exports[`other > Query - { object: { id: true } } 1`] = ` -" -{ - "object": { - "id": true - } -} --------------- -{ - object { - id - } -} -" -`; - -exports[`other > Query - { objectNested: { object: { string: true, id: true, int: { 'undefined': true } } } } 1`] = ` -" -{ - "objectNested": { - "object": { - "string": true, - "id": true, - "int": { - "$skip": true - } - } - } -} --------------- -{ - objectNested { - object { - string - id - int @skip(if: true) - } - } -} -" -`; - -exports[`other > Query - { objectNested: { object: { string: true, id: true, int: false } } } 1`] = ` -" -{ - "objectNested": { - "object": { - "string": true, - "id": true, - "int": false - } - } -} --------------- -{ - objectNested { - object { - string - id - } - } -} -" -`; - -exports[`other > Query - { string: true } 1`] = ` -" -{ - "string": true -} --------------- -{ - string -} -" -`; diff --git a/src/layers/3_SelectGraphQLMapper/nodes/_collect.ts b/src/layers/3_SelectGraphQLMapper/nodes/_collect.ts new file mode 100644 index 000000000..81afa78d9 --- /dev/null +++ b/src/layers/3_SelectGraphQLMapper/nodes/_collect.ts @@ -0,0 +1,34 @@ +import type { Grafaid } from '../../../lib/grafaid/__.js' +import type { Select } from '../../2_Select/__.js' +import type { SchemaDrivenDataMap } from '../../7_extensions/CustomScalars/schemaDrivenDataMap/types.js' +import type { GraphQLPostOperationMapper } from '../mapper.js' +import { fromGraffleSelectionObjectLevel } from './4_GraffleSelectionObjectLevel.js' +import { toGraphQLDirective } from './Directive.js' + +export const collectForInlineFragmentLike: GraphQLPostOperationMapper< + SchemaDrivenDataMap.OutputObject, + void, + [ + keyParsed: Select.ParsedInlineFragmentLevelSelection, + basket: { + directives: Grafaid.Document.DirectiveNode[] + selections: Grafaid.Document.SelectionNode[] + }, + ] +> = ( + context, + sddm, + keyParsed, + basket, +) => { + switch (keyParsed.type) { + case `Directive`: { + const directive = toGraphQLDirective(context, context.sddm?.directives[keyParsed.name], keyParsed) + if (directive) basket.directives.push(directive) + break + } + default: { + basket.selections.push(...fromGraffleSelectionObjectLevel(context, sddm, keyParsed)) + } + } +} diff --git a/src/layers/3_SelectGraphQLMapper/toGraphQL.test.ts b/src/layers/3_SelectGraphQLMapper/toGraphQL.test.ts new file mode 100644 index 000000000..829355e27 --- /dev/null +++ b/src/layers/3_SelectGraphQLMapper/toGraphQL.test.ts @@ -0,0 +1,114 @@ +import { expect, test } from 'vitest' +import { db } from '../../../tests/_/schemas/db.js' +import { schemaDrivenDataMap } from '../../../tests/_/schemas/kitchen-sink/graffle/modules/SchemaDrivenDataMap.js' +import type * as SelectionSets from '../../../tests/_/schemas/kitchen-sink/graffle/modules/SelectionSets.js' +import { Grafaid } from '../../lib/grafaid/__.js' +import { Select } from '../2_Select/__.js' +import { toGraphQLDocument } from './nodes/1_Document.js' + +type CasesDescriptiveQuery = [ + description: string, + selectionSet: SelectionSets.Query, + options?: { operationName?: string }, +] +const testEachQueryWithDescription = test.for.bind(test) + +const tester = (input: { variables: boolean }) => + [ + `( variables: ${String(input.variables)} ) - Query - %s`, + (args: CasesDescriptiveQuery) => { + const [description, graffleQuery, options] = args + + const { document, operationsVariables } = toGraphQLDocument( + Select.Document.createDocumentNormalizedFromQuerySelection( + graffleQuery as any, + options?.operationName, + ), + { + sddm: schemaDrivenDataMap, + operationVariables: input.variables, + }, + ) + + const beforeAndAfter = `\n` + + `\n--------------GRAFFLE QUERY-------------\n` + + JSON.stringify(graffleQuery, null, 2) + + `\n--------GRAPHQL DOCUMENT & VARIABLES--------\n` + + Grafaid.Document.print(document) + + `\n----------------\n` + + JSON.stringify(operationsVariables, null, 2) + + `\n` + + expect(beforeAndAfter).toMatchSnapshot(description) + }, + ] as const + +// todo test a case where we provide an operation name +// dprint-ignore +const cases = testEachQueryWithDescription([ + [`fg - one` , { ___: { __typename: true } }], + [`fg - multiple` , { ___: [{ __typename: true }, { abcEnum: true }] }], + [`fg - interface` , { interface: { ___: { __typename: true } } }], + [`fg - in union` , { unionFooBar: { ___: { __typename: true } } }], + [`fg - directive` , { ___: { __typename: true, $include: true } }], + // union + [`union - __typename (no fragment)` , { unionFooBar: { __typename: true } }], + [`union - scalar` , { unionFooBar: { ___on_Bar: { int: true } } }], + [`union - directive` , { unionFooBar: { ___on_Bar: { $skip: true, int: true } } }], + // s({ unionFooBar: { __on_Bar: {} } }), // todo should be static type error + // alias + [`alias - scalar` , { id: [`x`, true] }], + [`alias - scalar x2` , { id: [[`x`, true], [`id2`, true]] }], + [`alias - scalar directive` , { id: [`x`, { $skip: true }] }], + [`alias - scalar directive+select` , { object: [`x`, { $skip: true, id: true }] }], + // arguments + [`args - on union` , { result: { $: { $case: `Object1` }, __typename: true } }], + [`args - string with args` , { stringWithArgs: { $: { boolean: true, float: 1 } } }], + [`args - alias` , { stringWithArgs: [[`a`, { $: { id: `` }}]] }], + [`args - x2 same` , { stringWithArgs: [[`a`, { $: { id: `` }}], [`b`,{$:{id:``}}]] }], + [`args - string with args (empty object)` , { stringWithArgs: { $: {} } }], + // arguments custom scalars + [`args - custom scalar - arg field` , { dateArg: { $: { date: db.date0 } } }], + [`args - custom scalar - arg field in non-null` , { dateArgNonNull: { $: { date: db.date0 } } }], + [`args - custom scalar - arg field in list` , { dateArgList: { $: { date: [db.date0, new Date(1)] } } }], + [`args - custom scalar - arg field in list (null)` , { dateArgList: { $: { date: null } } }], + [`args - custom scalar - arg field in non-null list (with list)` , { dateArgNonNullList: { $: { date: [db.date0, new Date(1)] } } }], + [`args - custom scalar - arg field in non-null list (with null)` , { dateArgNonNullList: { $: { date: [null, db.date0] } } }], + [`args - custom scalar - arg field in non-null list non-null` , { dateArgNonNullListNonNull: { $: { date: [db.date0, new Date(1)] } } }], + [`args - custom scalar - input object field` , { dateArgInputObject: { $: { input: { idRequired: ``, dateRequired: db.date0, date: new Date(1) } } } }], + [`args - custom scalar - nested input object field` , { InputObjectNested: { $: { input: { InputObject: { idRequired: ``, dateRequired: db.date0, date: new Date(1) } } } } }], + // s({ objectWithArgs: { $: { id: `` } } }), // todo should be static error + // s({ objectWithArgs: { $: {} } }), // todo should be static error + [`args - object with args`, { objectWithArgs: { $: { id: `` }, id: true } }], + [`args - object with args (empty object)` , { objectWithArgs: { $: {}, id: true } }], + // $include + [`$include` , { object: { $include: true, id: true } }], + [`$include (false)` , { object: { $include: false, id: true } }], + [`$include (undefined)` , { object: { $include: undefined, id: true } }], + [`$include (if true)` , { object: { $include: { if: true }, id: true } }], + [`$include (if false)` , { object: { $include: { if: false }, id: true } }], + [`$include (if undefined)` , { object: { $include: { if: undefined }, id: true } }], + [`$include (empty object)` , { object: { $include: {}, id: true } }], + // skip + [`$skip (true)` , { object: { $skip: true, id: true } }], + [`$skip (false)` , { object: { $skip: false, id: true } }], + [`$skip (undefined)` , { object: { $skip: undefined, id: true } }], + [`$skip (if true)` , { object: { $skip: { if: true }, id: true } }], + [`$skip (if false)` , { object: { $skip: { if: false }, id: true } }], + [`$skip (if undefined)` , { object: { $skip: { if: undefined }, id: true } }], + [`$skip (empty object)` , { object: { $skip: {}, id: true } }], + [`object nested scalar $skip` , { objectNested: { object: { string: true, id: true, int: { $skip: true } } } }], + // other + [`custom operation name` , { id: true }, {operationName: `foobar` }], + [`other` , { __typename: true }], + [`string` , { string: true }], + // [{ string: 1 }], + // s({ string: false }), // todo should be static error + [`id string false` , { id: true, string: false }], + // [{ id: true, string: 0 }], + [`id string undefined` , { id: true, string: undefined }], + [`object scalar` , { object: { id: true } }], + [`object nested` , { objectNested: { object: { string: true, id: true, int: false } } }], +]) +cases(...tester({ variables: true })) +cases(...tester({ variables: false })) diff --git a/src/layers/3_SelectGraphQLMapper/types.ts b/src/layers/3_SelectGraphQLMapper/types.ts deleted file mode 100644 index 0f4db0811..000000000 --- a/src/layers/3_SelectGraphQLMapper/types.ts +++ /dev/null @@ -1,94 +0,0 @@ -import type { Nodes } from '../../lib/grafaid/_Nodes.js' -import type { Codec } from '../1_Schema/Hybrid/types/Scalar/codec.js' -import type { Select } from '../2_Select/__.js' -import type { CustomScalarsIndex } from '../4_generator/generators/SchemaIndex.js' -import type { ValueMapper } from './nodes/Value.js' - -export interface Context { - captures: Captures - hooks?: { - value?: ValueMapper - } -} - -export interface Parsed { - document: string - captures: Captures -} - -export interface Captures { - variables: CapturedVariable[] - customScalarOutputs: CapturedCustomScalarOutput[] -} - -export interface CapturedVariable { - name: string - type: unknown - value: unknown - location: VariableLocation -} - -export interface CapturedCustomScalarOutput { - type: unknown - location: OutputLocation -} - -export type LocationDirectiveArgument = { - type: 'directiveArgument' - argumentName: string - directiveName: string -} - -export type VariableLocation = Location - -export type OutputLocation = LocationStepField[] - -export type Location = LocationStep[] - -export type LocationStep = LocationStepRootType | LocationDirectiveArgument | LocationStepField | LocationStepArgument - -export type LocationStepRootType = { type: 'rootType'; name: string } - -export type LocationStepField = { type: 'field'; name: string } - -export type LocationStepArgument = { type: 'argument'; name: string } - -export type CodecString = Codec - -export const isCodec = (value: unknown): value is CodecString => - typeof value === `object` && value !== null && `encode` in value && typeof value.encode === `function` - -type RootIndexPointer = - | CustomScalarsIndex - | IndexPointer - -type IndexPointer = - | CustomScalarsIndex - | CustomScalarsIndex.OutputObject - | CustomScalarsIndex.InputObject - | CustomScalarsIndex.InputField - | null - -export const advanceIndex = (pointer: RootIndexPointer, rootTypeOrSomeKey: string): IndexPointer => { - if (pointer === null) return pointer - if (isCodec(pointer)) return pointer - return (pointer as any)[rootTypeOrSomeKey] ?? null -} - -export type GraphQLNodeMapper< - $Return extends Nodes.$Any, - $Args extends [...any[]] = [], - $ContextExtension extends object = {}, -> = ( - ...args: [ - context: Context & $ContextExtension, - customScalarsIndexPointer: IndexPointer, - ...$Args, - ] -) => $Return - -export interface Field { - name: string - alias: string | null - value: Select.SelectionSet.Any -} diff --git a/src/layers/4_generator/__snapshots__/generate.test.ts.snap b/src/layers/4_generator/__snapshots__/generate.test.ts.snap index 33376c329..f2962f229 100644 --- a/src/layers/4_generator/__snapshots__/generate.test.ts.snap +++ b/src/layers/4_generator/__snapshots__/generate.test.ts.snap @@ -2,9 +2,10 @@ exports[`schema2 1`] = ` "import { createPrefilled } from '../../../../../../src/entrypoints/client.js' -import { $defaultSchemaUrl, $Index } from './SchemaRuntime.js' +import { defaultSchemaUrl } from './Data.js' +import { schemaDrivenDataMap } from './SchemaDrivenDataMap.js' -export const create = createPrefilled(\`default\`, $Index, $defaultSchemaUrl) +export const create = createPrefilled(\`default\`, schemaDrivenDataMap, defaultSchemaUrl) " `; @@ -321,6 +322,13 @@ export namespace Root { * Query enum field documentation. */ abcEnum: $.Field<'abcEnum', $.Output.Nullable, null> + argInputObjectCircular: $.Field< + 'argInputObjectCircular', + $.Output.Nullable<$Scalar.String>, + $.Args<{ + input: $.Input.Field<$.Input.Nullable> + }, true> + > date: $.Field<'date', $.Output.Nullable<$Scalar.Date>, null> dateArg: $.Field< 'dateArg', @@ -525,6 +533,11 @@ export namespace InputObject { idRequired: $.Input.Field<$Scalar.ID> }, true> + export type InputObjectCircular = $.InputObject<'InputObjectCircular', { + circular: $.Input.Field<$.Input.Nullable> + date: $.Input.Field<$.Input.Nullable<$Scalar.Date>> + }, true> + export type InputObjectNested = $.InputObject<'InputObjectNested', { InputObject: $.Input.Field<$.Input.Nullable> }, true> @@ -670,375 +683,1503 @@ export type DateEncoded = Schema.Scalar.GetEncoded `; exports[`schema2 9`] = ` -"/* eslint-disable */ -import * as $ from '../../../../../../src/entrypoints/schema.js' -import * as Data from './Data.js' -import { $index as $customScalarsIndex } from './RuntimeCustomScalars.js' +"import type * as $Utilities from '../../../../../../src/entrypoints/utilities-for-generated.js' import * as $Scalar from './Scalar.js' -import type { Index } from './SchemaIndex.js' -export const $defaultSchemaUrl = undefined -export const ABCEnum = $.Enum(\`ABCEnum\`, [\`A\`, \`B\`, \`C\`]) -export const Case = $.Enum(\`Case\`, [\`ErrorOne\`, \`ErrorTwo\`, \`Object1\`]) -export const InputObject = $.InputObject(\`InputObject\`, { - date: $.Input.Field($.Input.Nullable($Scalar.Date)), - dateRequired: $.Input.Field($Scalar.Date), - id: $.Input.Field($.Input.Nullable($Scalar.ID)), - idRequired: $.Input.Field($Scalar.ID), -}, true) - -export const InputObjectNested = $.InputObject(\`InputObjectNested\`, { - InputObject: $.Input.Field(() => $.Input.Nullable(InputObject)), -}, true) - -export const InputObjectNestedNonNull = $.InputObject(\`InputObjectNestedNonNull\`, { - InputObject: $.Input.Field(() => InputObject), -}, false) -// @ts-ignore - circular types cannot infer. Ignore in case there are any. This comment is always added, it does not indicate if this particular type could infer or not. -export const Bar = $.Object$(\`Bar\`, { - int: $.field('int', $.Output.Nullable($Scalar.Int)), -}) - -// @ts-ignore - circular types cannot infer. Ignore in case there are any. This comment is always added, it does not indicate if this particular type could infer or not. -export const DateObject1 = $.Object$(\`DateObject1\`, { - date1: $.field('date1', $.Output.Nullable($Scalar.Date)), -}) - -// @ts-ignore - circular types cannot infer. Ignore in case there are any. This comment is always added, it does not indicate if this particular type could infer or not. -export const DateObject2 = $.Object$(\`DateObject2\`, { - date2: $.field('date2', $.Output.Nullable($Scalar.Date)), -}) - -// @ts-ignore - circular types cannot infer. Ignore in case there are any. This comment is always added, it does not indicate if this particular type could infer or not. -export const ErrorOne = $.Object$(\`ErrorOne\`, { - infoId: $.field('infoId', $.Output.Nullable($Scalar.ID)), - message: $.field('message', $Scalar.String), -}) - -// @ts-ignore - circular types cannot infer. Ignore in case there are any. This comment is always added, it does not indicate if this particular type could infer or not. -export const ErrorTwo = $.Object$(\`ErrorTwo\`, { - infoInt: $.field('infoInt', $.Output.Nullable($Scalar.Int)), - message: $.field('message', $Scalar.String), -}) - -// @ts-ignore - circular types cannot infer. Ignore in case there are any. This comment is always added, it does not indicate if this particular type could infer or not. -export const Foo = $.Object$(\`Foo\`, { - id: $.field('id', $.Output.Nullable($Scalar.ID)), -}) - -// @ts-ignore - circular types cannot infer. Ignore in case there are any. This comment is always added, it does not indicate if this particular type could infer or not. -export const Object1 = $.Object$(\`Object1\`, { - boolean: $.field('boolean', $.Output.Nullable($Scalar.Boolean)), - float: $.field('float', $.Output.Nullable($Scalar.Float)), - id: $.field('id', $.Output.Nullable($Scalar.ID)), - int: $.field('int', $.Output.Nullable($Scalar.Int)), - string: $.field('string', $.Output.Nullable($Scalar.String)), -}) - -// @ts-ignore - circular types cannot infer. Ignore in case there are any. This comment is always added, it does not indicate if this particular type could infer or not. -export const Object1ImplementingInterface = $.Object$(\`Object1ImplementingInterface\`, { - id: $.field('id', $.Output.Nullable($Scalar.ID)), - int: $.field('int', $.Output.Nullable($Scalar.Int)), -}) - -// @ts-ignore - circular types cannot infer. Ignore in case there are any. This comment is always added, it does not indicate if this particular type could infer or not. -export const Object2ImplementingInterface = $.Object$(\`Object2ImplementingInterface\`, { - boolean: $.field('boolean', $.Output.Nullable($Scalar.Boolean)), - id: $.field('id', $.Output.Nullable($Scalar.ID)), -}) - -// @ts-ignore - circular types cannot infer. Ignore in case there are any. This comment is always added, it does not indicate if this particular type could infer or not. -export const ObjectNested = $.Object$(\`ObjectNested\`, { - id: $.field('id', $.Output.Nullable($Scalar.ID)), - // @ts-ignore - circular types cannot infer. Ignore in case there are any. This comment is always added, it does not indicate if this particular type could infer or not. - object: $.field('object', $.Output.Nullable(() => Object1)), -}) - -// @ts-ignore - circular types cannot infer. Ignore in case there are any. This comment is always added, it does not indicate if this particular type could infer or not. -export const ObjectUnion = $.Object$(\`ObjectUnion\`, { - // @ts-ignore - circular types cannot infer. Ignore in case there are any. This comment is always added, it does not indicate if this particular type could infer or not. - fooBarUnion: $.field('fooBarUnion', $.Output.Nullable(() => FooBarUnion)), -}) - -// @ts-ignore - circular types cannot infer. Ignore in case there are any. This comment is always added, it does not indicate if this particular type could infer or not. -export const lowerCaseObject = $.Object$(\`lowerCaseObject\`, { - id: $.field('id', $.Output.Nullable($Scalar.ID)), -}) - -// @ts-ignore - circular types cannot infer. Ignore in case there are any. This comment is always added, it does not indicate if this particular type could infer or not. -export const lowerCaseObject2 = $.Object$(\`lowerCaseObject2\`, { - int: $.field('int', $.Output.Nullable($Scalar.Int)), -}) -// @ts-ignore - circular types cannot infer. Ignore in case there are any. This comment is always added, it does not indicate if this particular type could infer or not. -export const DateUnion = $.Union(\`DateUnion\`, [DateObject1, DateObject2]) - -// @ts-ignore - circular types cannot infer. Ignore in case there are any. This comment is always added, it does not indicate if this particular type could infer or not. -export const FooBarUnion = $.Union(\`FooBarUnion\`, [Bar, Foo]) - -// @ts-ignore - circular types cannot infer. Ignore in case there are any. This comment is always added, it does not indicate if this particular type could infer or not. -export const Result = $.Union(\`Result\`, [ErrorOne, ErrorTwo, Object1]) - -// @ts-ignore - circular types cannot infer. Ignore in case there are any. This comment is always added, it does not indicate if this particular type could infer or not. -export const lowerCaseUnion = $.Union(\`lowerCaseUnion\`, [lowerCaseObject, lowerCaseObject2]) -export const DateInterface1 = $.Interface(\`DateInterface1\`, { - date1: $.field('date1', $.Output.Nullable($Scalar.Date)), -}, [DateObject1]) -export const Error = $.Interface(\`Error\`, { message: $.field('message', $Scalar.String) }, [ErrorOne, ErrorTwo]) -export const Interface = $.Interface(\`Interface\`, { id: $.field('id', $.Output.Nullable($Scalar.ID)) }, [ - Object1ImplementingInterface, - Object2ImplementingInterface, -]) -// @ts-ignore - circular types cannot infer. Ignore in case there are any. This comment is always added, it does not indicate if this particular type could infer or not. -export const Mutation = $.Object$(\`Mutation\`, { - id: $.field('id', $.Output.Nullable($Scalar.ID)), - idNonNull: $.field('idNonNull', $Scalar.ID), -}) - -// @ts-ignore - circular types cannot infer. Ignore in case there are any. This comment is always added, it does not indicate if this particular type could infer or not. -export const Query = $.Object$(\`Query\`, { - InputObjectNested: $.field( - 'InputObjectNested', - $.Output.Nullable($Scalar.ID), - $.Args({ input: $.Input.Field($.Input.Nullable(InputObjectNested)) }, true), - ), - InputObjectNestedNonNull: $.field( - 'InputObjectNestedNonNull', - $.Output.Nullable($Scalar.ID), - $.Args({ input: $.Input.Field(InputObjectNestedNonNull) }, false), - ), - // @ts-ignore - circular types cannot infer. Ignore in case there are any. This comment is always added, it does not indicate if this particular type could infer or not. - abcEnum: $.field('abcEnum', $.Output.Nullable(ABCEnum)), - date: $.field('date', $.Output.Nullable($Scalar.Date)), - dateArg: $.field( - 'dateArg', - $.Output.Nullable($Scalar.Date), - $.Args({ date: $.Input.Field($.Input.Nullable($Scalar.Date)) }, true), - ), - dateArgInputObject: $.field( - 'dateArgInputObject', - $.Output.Nullable($Scalar.Date), - $.Args({ input: $.Input.Field($.Input.Nullable(InputObject)) }, true), - ), - dateArgList: $.field( - 'dateArgList', - $.Output.Nullable($Scalar.Date), - $.Args({ date: $.Input.Field($.Input.Nullable($.Input.List($Scalar.Date))) }, true), - ), - dateArgNonNull: $.field( - 'dateArgNonNull', - $.Output.Nullable($Scalar.Date), - $.Args({ date: $.Input.Field($Scalar.Date) }, false), - ), - dateArgNonNullList: $.field( - 'dateArgNonNullList', - $.Output.Nullable($Scalar.Date), - $.Args({ date: $.Input.Field($.Input.List($.Input.Nullable($Scalar.Date))) }, false), - ), - dateArgNonNullListNonNull: $.field( - 'dateArgNonNullListNonNull', - $.Output.Nullable($Scalar.Date), - $.Args({ date: $.Input.Field($.Input.List($Scalar.Date)) }, false), - ), - // @ts-ignore - circular types cannot infer. Ignore in case there are any. This comment is always added, it does not indicate if this particular type could infer or not. - dateInterface1: $.field('dateInterface1', $.Output.Nullable(() => DateInterface1)), - dateList: $.field('dateList', $.Output.Nullable($.Output.List($Scalar.Date))), - dateListList: $.field('dateListList', $.Output.Nullable($.Output.List($.Output.List($Scalar.Date)))), - dateListNonNull: $.field('dateListNonNull', $.Output.List($Scalar.Date)), - dateNonNull: $.field('dateNonNull', $Scalar.Date), - // @ts-ignore - circular types cannot infer. Ignore in case there are any. This comment is always added, it does not indicate if this particular type could infer or not. - dateObject1: $.field('dateObject1', $.Output.Nullable(() => DateObject1)), - // @ts-ignore - circular types cannot infer. Ignore in case there are any. This comment is always added, it does not indicate if this particular type could infer or not. - dateUnion: $.field('dateUnion', $.Output.Nullable(() => DateUnion)), - error: $.field( - 'error', - $.Output.Nullable($Scalar.String), - $.Args({ case: $.Input.Field($.Input.Nullable($Scalar.String)) }, true), - ), - id: $.field('id', $.Output.Nullable($Scalar.ID)), - idNonNull: $.field('idNonNull', $Scalar.ID), - // @ts-ignore - circular types cannot infer. Ignore in case there are any. This comment is always added, it does not indicate if this particular type could infer or not. - interface: $.field('interface', $.Output.Nullable(() => Interface)), - // @ts-ignore - circular types cannot infer. Ignore in case there are any. This comment is always added, it does not indicate if this particular type could infer or not. - interfaceNonNull: $.field('interfaceNonNull', () => Interface), - // @ts-ignore - circular types cannot infer. Ignore in case there are any. This comment is always added, it does not indicate if this particular type could infer or not. - interfaceWithArgs: $.field( - 'interfaceWithArgs', - $.Output.Nullable(() => Interface), - $.Args({ id: $.Input.Field($Scalar.ID) }, false), - ), - listInt: $.field('listInt', $.Output.Nullable($.Output.List($.Output.Nullable($Scalar.Int)))), - listIntNonNull: $.field('listIntNonNull', $.Output.List($Scalar.Int)), - listListInt: $.field( - 'listListInt', - $.Output.Nullable($.Output.List($.Output.Nullable($.Output.List($.Output.Nullable($Scalar.Int))))), - ), - listListIntNonNull: $.field('listListIntNonNull', $.Output.List($.Output.List($Scalar.Int))), - // @ts-ignore - circular types cannot infer. Ignore in case there are any. This comment is always added, it does not indicate if this particular type could infer or not. - lowerCaseUnion: $.field('lowerCaseUnion', $.Output.Nullable(() => lowerCaseUnion)), - // @ts-ignore - circular types cannot infer. Ignore in case there are any. This comment is always added, it does not indicate if this particular type could infer or not. - object: $.field('object', $.Output.Nullable(() => Object1)), - // @ts-ignore - circular types cannot infer. Ignore in case there are any. This comment is always added, it does not indicate if this particular type could infer or not. - objectList: $.field('objectList', $.Output.Nullable($.Output.List(() => Object1))), - // @ts-ignore - circular types cannot infer. Ignore in case there are any. This comment is always added, it does not indicate if this particular type could infer or not. - objectListNonNull: $.field('objectListNonNull', $.Output.List(() => Object1)), - // @ts-ignore - circular types cannot infer. Ignore in case there are any. This comment is always added, it does not indicate if this particular type could infer or not. - objectNested: $.field('objectNested', $.Output.Nullable(() => ObjectNested)), - // @ts-ignore - circular types cannot infer. Ignore in case there are any. This comment is always added, it does not indicate if this particular type could infer or not. - objectNonNull: $.field('objectNonNull', () => Object1), - // @ts-ignore - circular types cannot infer. Ignore in case there are any. This comment is always added, it does not indicate if this particular type could infer or not. - objectWithArgs: $.field( - 'objectWithArgs', - $.Output.Nullable(() => Object1), - $.Args({ - boolean: $.Input.Field($.Input.Nullable($Scalar.Boolean)), - float: $.Input.Field($.Input.Nullable($Scalar.Float)), - id: $.Input.Field($.Input.Nullable($Scalar.ID)), - int: $.Input.Field($.Input.Nullable($Scalar.Int)), - string: $.Input.Field($.Input.Nullable($Scalar.String)), - }, true), - ), - // @ts-ignore - circular types cannot infer. Ignore in case there are any. This comment is always added, it does not indicate if this particular type could infer or not. - result: $.field('result', $.Output.Nullable(() => Result), $.Args({ case: $.Input.Field(Case) }, false)), - // @ts-ignore - circular types cannot infer. Ignore in case there are any. This comment is always added, it does not indicate if this particular type could infer or not. - resultNonNull: $.field('resultNonNull', () => Result, $.Args({ case: $.Input.Field($.Input.Nullable(Case)) }, true)), - string: $.field('string', $.Output.Nullable($Scalar.String)), - stringWithArgEnum: $.field( - 'stringWithArgEnum', - $.Output.Nullable($Scalar.String), - $.Args({ ABCEnum: $.Input.Field($.Input.Nullable(ABCEnum)) }, true), - ), - stringWithArgInputObject: $.field( - 'stringWithArgInputObject', - $.Output.Nullable($Scalar.String), - $.Args({ input: $.Input.Field($.Input.Nullable(InputObject)) }, true), - ), - stringWithArgInputObjectRequired: $.field( - 'stringWithArgInputObjectRequired', - $.Output.Nullable($Scalar.String), - $.Args({ input: $.Input.Field(InputObject) }, false), - ), - stringWithArgs: $.field( - 'stringWithArgs', - $.Output.Nullable($Scalar.String), - $.Args({ - boolean: $.Input.Field($.Input.Nullable($Scalar.Boolean)), - float: $.Input.Field($.Input.Nullable($Scalar.Float)), - id: $.Input.Field($.Input.Nullable($Scalar.ID)), - int: $.Input.Field($.Input.Nullable($Scalar.Int)), - string: $.Input.Field($.Input.Nullable($Scalar.String)), - }, true), - ), - stringWithListArg: $.field( - 'stringWithListArg', - $.Output.Nullable($Scalar.String), - $.Args({ ints: $.Input.Field($.Input.Nullable($.Input.List($.Input.Nullable($Scalar.Int)))) }, true), - ), - stringWithListArgRequired: $.field( - 'stringWithListArgRequired', - $.Output.Nullable($Scalar.String), - $.Args({ ints: $.Input.Field($.Input.List($Scalar.Int)) }, false), - ), - stringWithRequiredArg: $.field( - 'stringWithRequiredArg', - $.Output.Nullable($Scalar.String), - $.Args({ string: $.Input.Field($Scalar.String) }, false), - ), - // @ts-ignore - circular types cannot infer. Ignore in case there are any. This comment is always added, it does not indicate if this particular type could infer or not. - unionFooBar: $.field('unionFooBar', $.Output.Nullable(() => FooBarUnion)), - // @ts-ignore - circular types cannot infer. Ignore in case there are any. This comment is always added, it does not indicate if this particular type could infer or not. - unionFooBarNonNull: $.field('unionFooBarNonNull', () => FooBarUnion), - // @ts-ignore - circular types cannot infer. Ignore in case there are any. This comment is always added, it does not indicate if this particular type could infer or not. - unionFooBarWithArgs: $.field( - 'unionFooBarWithArgs', - $.Output.Nullable(() => FooBarUnion), - $.Args({ id: $.Input.Field($.Input.Nullable($Scalar.ID)) }, true), - ), - // @ts-ignore - circular types cannot infer. Ignore in case there are any. This comment is always added, it does not indicate if this particular type could infer or not. - unionObject: $.field('unionObject', $.Output.Nullable(() => ObjectUnion)), - // @ts-ignore - circular types cannot infer. Ignore in case there are any. This comment is always added, it does not indicate if this particular type could infer or not. - unionObjectNonNull: $.field('unionObjectNonNull', () => ObjectUnion), -}) -export const $Index: Index = { - name: Data.Name, - RootTypesPresent: ['Mutation', 'Query'] as const, - RootUnion: undefined as any, // Type level only. - Root: { - Query, - Mutation, - Subscription: null, +// +// +// +// +// +// +// ================================================================================================== +// GraphQLScalarType +// ================================================================================================== +// +// +// +// +// +// + +const Int = $Scalar.Int + +const String = $Scalar.String + +const ID = $Scalar.ID + +const Boolean = $Scalar.Boolean + +const Float = $Scalar.Float + +// +// +// +// +// +// +// ================================================================================================== +// GraphQLScalarTypeCustom +// ================================================================================================== +// +// +// +// +// +// + +const Date = $Scalar.Date + +// +// +// +// +// +// +// ================================================================================================== +// GraphQLEnumType +// ================================================================================================== +// +// +// +// +// +// + +const ABCEnum: $Utilities.SchemaDrivenDataMap.Enum = { + k: 'enum', + n: 'ABCEnum', +} + +const Case: $Utilities.SchemaDrivenDataMap.Enum = { + k: 'enum', + n: 'Case', +} + +// +// +// +// +// +// +// ================================================================================================== +// GraphQLInputObjectType +// ================================================================================================== +// +// +// +// +// +// + +const InputObject: $Utilities.SchemaDrivenDataMap.InputObject = { + n: 'InputObject', + fcs: ['date', 'dateRequired'], + f: { + date: { + nt: Date, + }, + dateRequired: { + nt: Date, + }, + id: {}, + idRequired: {}, }, - allTypes: { - Mutation, - Query, - DateUnion, - FooBarUnion, - Result, - lowerCaseUnion, - Bar, - DateObject1, - DateObject2, - ErrorOne, - ErrorTwo, - Foo, - Object1, - Object1ImplementingInterface, - Object2ImplementingInterface, - ObjectNested, - ObjectUnion, - lowerCaseObject, - lowerCaseObject2, - DateInterface1, - Error, - Interface, - ABCEnum, - Case, +} + +const InputObjectCircular: $Utilities.SchemaDrivenDataMap.InputObject = { + n: 'InputObjectCircular', + fcs: ['circular', 'date'], + f: { + circular: { + // nt: InputObjectCircular, <-- Assigned later to avoid potential circular dependency. + }, + date: { + nt: Date, + }, }, - objects: { - Bar, - DateObject1, - DateObject2, - ErrorOne, - ErrorTwo, - Foo, - Object1, - Object1ImplementingInterface, - Object2ImplementingInterface, - ObjectNested, - ObjectUnion, - lowerCaseObject, - lowerCaseObject2, +} + +const InputObjectNested: $Utilities.SchemaDrivenDataMap.InputObject = { + n: 'InputObjectNested', + fcs: ['InputObject'], + f: { + InputObject: { + // nt: InputObject, <-- Assigned later to avoid potential circular dependency. + }, }, - unions: { - DateUnion, - FooBarUnion, - Result, - lowerCaseUnion, +} + +const InputObjectNestedNonNull: $Utilities.SchemaDrivenDataMap.InputObject = { + n: 'InputObjectNestedNonNull', + fcs: ['InputObject'], + f: { + InputObject: { + // nt: InputObject, <-- Assigned later to avoid potential circular dependency. + }, }, - interfaces: { - DateInterface1, - Error, - Interface, +} + +// +// +// +// +// +// +// ================================================================================================== +// GraphQLObjectType +// ================================================================================================== +// +// +// +// +// +// + +const Bar: $Utilities.SchemaDrivenDataMap.OutputObject = { + f: { + int: {}, }, - customScalars: { - input: $customScalarsIndex, +} + +const DateObject1: $Utilities.SchemaDrivenDataMap.OutputObject = { + f: { + date1: { + nt: Date, + }, }, - error: { - objects: { - ErrorOne, - ErrorTwo, +} + +const DateObject2: $Utilities.SchemaDrivenDataMap.OutputObject = { + f: { + date2: { + nt: Date, }, - objectsTypename: { - ErrorOne: { __typename: 'ErrorOne' }, - ErrorTwo: { __typename: 'ErrorTwo' }, + }, +} + +const ErrorOne: $Utilities.SchemaDrivenDataMap.OutputObject = { + e: 1, + f: { + infoId: {}, + message: {}, + }, +} + +const ErrorTwo: $Utilities.SchemaDrivenDataMap.OutputObject = { + e: 1, + f: { + infoInt: {}, + message: {}, + }, +} + +const Foo: $Utilities.SchemaDrivenDataMap.OutputObject = { + f: { + id: {}, + }, +} + +const Object1: $Utilities.SchemaDrivenDataMap.OutputObject = { + f: { + boolean: {}, + float: {}, + id: {}, + int: {}, + string: {}, + }, +} + +const Object1ImplementingInterface: $Utilities.SchemaDrivenDataMap.OutputObject = { + f: { + id: {}, + int: {}, + }, +} + +const Object2ImplementingInterface: $Utilities.SchemaDrivenDataMap.OutputObject = { + f: { + boolean: {}, + id: {}, + }, +} + +const ObjectNested: $Utilities.SchemaDrivenDataMap.OutputObject = { + f: { + id: {}, + object: { + // nt: Object1, <-- Assigned later to avoid potential circular dependency. }, - rootResultFields: { - Subscription: {}, - Mutation: {}, - Query: { - result: 'result' as const, - resultNonNull: 'resultNonNull' as const, - }, + }, +} + +const ObjectUnion: $Utilities.SchemaDrivenDataMap.OutputObject = { + f: { + fooBarUnion: { + // nt: FooBarUnion, <-- Assigned later to avoid potential circular dependency. }, }, } + +const lowerCaseObject: $Utilities.SchemaDrivenDataMap.OutputObject = { + f: { + id: {}, + }, +} + +const lowerCaseObject2: $Utilities.SchemaDrivenDataMap.OutputObject = { + f: { + int: {}, + }, +} + +// +// +// +// +// +// +// ================================================================================================== +// GraphQLInterfaceType +// ================================================================================================== +// +// +// +// +// +// + +const DateInterface1: $Utilities.SchemaDrivenDataMap.OutputObject = { + f: { + ...DateObject1.f, + }, +} + +const Error: $Utilities.SchemaDrivenDataMap.OutputObject = { + f: {}, +} + +const Interface: $Utilities.SchemaDrivenDataMap.OutputObject = { + f: {}, +} + +// +// +// +// +// +// +// ================================================================================================== +// GraphQLUnionType +// ================================================================================================== +// +// +// +// +// +// + +const DateUnion: $Utilities.SchemaDrivenDataMap.OutputObject = { + f: { + ...DateObject1.f, + ...DateObject2.f, + }, +} + +const FooBarUnion: $Utilities.SchemaDrivenDataMap.OutputObject = { + f: {}, +} + +const Result: $Utilities.SchemaDrivenDataMap.OutputObject = { + f: {}, +} + +const lowerCaseUnion: $Utilities.SchemaDrivenDataMap.OutputObject = { + f: {}, +} + +// +// +// +// +// +// +// ================================================================================================== +// GraphQLRootType +// ================================================================================================== +// +// +// +// +// +// + +const Mutation: $Utilities.SchemaDrivenDataMap.OutputObject = { + f: { + id: {}, + idNonNull: {}, + }, +} + +const Query: $Utilities.SchemaDrivenDataMap.OutputObject = { + f: { + InputObjectNested: { + a: { + input: { + nt: InputObjectNested, + it: [0], + }, + }, + }, + InputObjectNestedNonNull: { + a: { + input: { + nt: InputObjectNestedNonNull, + it: [1], + }, + }, + }, + abcEnum: {}, + argInputObjectCircular: { + a: { + input: { + nt: InputObjectCircular, + it: [0], + }, + }, + }, + date: { + nt: Date, + }, + dateArg: { + a: { + date: { + nt: Date, + it: [0], + }, + }, + nt: Date, + }, + dateArgInputObject: { + a: { + input: { + nt: InputObject, + it: [0], + }, + }, + nt: Date, + }, + dateArgList: { + a: { + date: { + nt: Date, + it: [0, [1]], + }, + }, + nt: Date, + }, + dateArgNonNull: { + a: { + date: { + nt: Date, + it: [1], + }, + }, + nt: Date, + }, + dateArgNonNullList: { + a: { + date: { + nt: Date, + it: [1, [0]], + }, + }, + nt: Date, + }, + dateArgNonNullListNonNull: { + a: { + date: { + nt: Date, + it: [1, [1]], + }, + }, + nt: Date, + }, + dateInterface1: { + // nt: DateInterface1, <-- Assigned later to avoid potential circular dependency. + }, + dateList: { + nt: Date, + }, + dateListList: { + nt: Date, + }, + dateListNonNull: { + nt: Date, + }, + dateNonNull: { + nt: Date, + }, + dateObject1: { + // nt: DateObject1, <-- Assigned later to avoid potential circular dependency. + }, + dateUnion: { + // nt: DateUnion, <-- Assigned later to avoid potential circular dependency. + }, + error: { + a: { + case: { + nt: String, + it: [0], + }, + }, + }, + id: {}, + idNonNull: {}, + interface: { + // nt: Interface, <-- Assigned later to avoid potential circular dependency. + }, + interfaceNonNull: { + // nt: Interface, <-- Assigned later to avoid potential circular dependency. + }, + interfaceWithArgs: { + a: { + id: { + nt: ID, + it: [1], + }, + }, + // nt: Interface, <-- Assigned later to avoid potential circular dependency. + }, + listInt: {}, + listIntNonNull: {}, + listListInt: {}, + listListIntNonNull: {}, + lowerCaseUnion: { + // nt: lowerCaseUnion, <-- Assigned later to avoid potential circular dependency. + }, + object: { + // nt: Object1, <-- Assigned later to avoid potential circular dependency. + }, + objectList: { + // nt: Object1, <-- Assigned later to avoid potential circular dependency. + }, + objectListNonNull: { + // nt: Object1, <-- Assigned later to avoid potential circular dependency. + }, + objectNested: { + // nt: ObjectNested, <-- Assigned later to avoid potential circular dependency. + }, + objectNonNull: { + // nt: Object1, <-- Assigned later to avoid potential circular dependency. + }, + objectWithArgs: { + a: { + boolean: { + nt: Boolean, + it: [0], + }, + float: { + nt: Float, + it: [0], + }, + id: { + nt: ID, + it: [0], + }, + int: { + nt: Int, + it: [0], + }, + string: { + nt: String, + it: [0], + }, + }, + // nt: Object1, <-- Assigned later to avoid potential circular dependency. + }, + result: { + a: { + case: { + nt: Case, + it: [1], + }, + }, + r: 1, + // nt: Result, <-- Assigned later to avoid potential circular dependency. + }, + resultNonNull: { + a: { + case: { + nt: Case, + it: [0], + }, + }, + r: 1, + // nt: Result, <-- Assigned later to avoid potential circular dependency. + }, + string: {}, + stringWithArgEnum: { + a: { + ABCEnum: { + nt: ABCEnum, + it: [0], + }, + }, + }, + stringWithArgInputObject: { + a: { + input: { + nt: InputObject, + it: [0], + }, + }, + }, + stringWithArgInputObjectRequired: { + a: { + input: { + nt: InputObject, + it: [1], + }, + }, + }, + stringWithArgs: { + a: { + boolean: { + nt: Boolean, + it: [0], + }, + float: { + nt: Float, + it: [0], + }, + id: { + nt: ID, + it: [0], + }, + int: { + nt: Int, + it: [0], + }, + string: { + nt: String, + it: [0], + }, + }, + }, + stringWithListArg: { + a: { + ints: { + nt: Int, + it: [0, [0]], + }, + }, + }, + stringWithListArgRequired: { + a: { + ints: { + nt: Int, + it: [1, [1]], + }, + }, + }, + stringWithRequiredArg: { + a: { + string: { + nt: String, + it: [1], + }, + }, + }, + unionFooBar: { + // nt: FooBarUnion, <-- Assigned later to avoid potential circular dependency. + }, + unionFooBarNonNull: { + // nt: FooBarUnion, <-- Assigned later to avoid potential circular dependency. + }, + unionFooBarWithArgs: { + a: { + id: { + nt: ID, + it: [0], + }, + }, + // nt: FooBarUnion, <-- Assigned later to avoid potential circular dependency. + }, + unionObject: { + // nt: ObjectUnion, <-- Assigned later to avoid potential circular dependency. + }, + unionObjectNonNull: { + // nt: ObjectUnion, <-- Assigned later to avoid potential circular dependency. + }, + }, +} + +// +// +// +// +// +// +// ================================================================================================== +// Reference Assignments +// (avoids circular assignment issues) +// ================================================================================================== +// +// +// +// +// +// + +InputObjectCircular.f!['circular']!.nt = InputObjectCircular +InputObjectNested.f!['InputObject']!.nt = InputObject +InputObjectNestedNonNull.f!['InputObject']!.nt = InputObject +ObjectNested.f['object']!.nt = Object1 +ObjectUnion.f['fooBarUnion']!.nt = FooBarUnion +Query.f['dateInterface1']!.nt = DateInterface1 +Query.f['dateObject1']!.nt = DateObject1 +Query.f['dateUnion']!.nt = DateUnion +Query.f['interface']!.nt = Interface +Query.f['interfaceNonNull']!.nt = Interface +Query.f['interfaceWithArgs']!.nt = Interface +Query.f['lowerCaseUnion']!.nt = lowerCaseUnion +Query.f['object']!.nt = Object1 +Query.f['objectList']!.nt = Object1 +Query.f['objectListNonNull']!.nt = Object1 +Query.f['objectNested']!.nt = ObjectNested +Query.f['objectNonNull']!.nt = Object1 +Query.f['objectWithArgs']!.nt = Object1 +Query.f['result']!.nt = Result +Query.f['resultNonNull']!.nt = Result +Query.f['unionFooBar']!.nt = FooBarUnion +Query.f['unionFooBarNonNull']!.nt = FooBarUnion +Query.f['unionFooBarWithArgs']!.nt = FooBarUnion +Query.f['unionObject']!.nt = ObjectUnion +Query.f['unionObjectNonNull']!.nt = ObjectUnion + +// +// +// +// +// +// +// ================================================================================================== +// Index +// ================================================================================================== +// +// +// +// +// +// + +const $schemaDrivenDataMap: $Utilities.SchemaDrivenDataMap = { + roots: { + Mutation, + Query, + }, + directives: {}, + types: { + Int, + String, + ID, + Boolean, + Float, + Date, + ABCEnum, + Case, + InputObject, + InputObjectCircular, + InputObjectNested, + InputObjectNestedNonNull, + Bar, + DateObject1, + DateObject2, + ErrorOne, + ErrorTwo, + Foo, + Object1, + Object1ImplementingInterface, + Object2ImplementingInterface, + ObjectNested, + ObjectUnion, + lowerCaseObject, + lowerCaseObject2, + DateInterface1, + Error, + Interface, + DateUnion, + FooBarUnion, + Result, + lowerCaseUnion, + Mutation, + Query, + }, +} + +export { $schemaDrivenDataMap as schemaDrivenDataMap } +" +`; + +exports[`schema2 10`] = ` +"import type * as Utilities from '../../../../../../src/entrypoints/utilities-for-generated.js' +import type { Index } from './SchemaIndex.js' +import type * as SelectionSets from './SelectionSets.js' + +export interface Document<$Config extends Utilities.Config> { + <$Document>(document: Utilities.ExactNonEmpty<$Document, SelectionSets.$Document>): Utilities.DocumentRunner< + $Config, + Index, + // @ts-expect-error We use Exact instead of constraint on this function. TypeScript does not see that as + // Satisfying the constraint on the DocumentRunner type. + $Document + > +} + +export interface BuilderMethodsDocumentFn extends Utilities.HKT.Fn { + // @ts-expect-error parameter is Untyped. + return: Document +} +" +`; + +exports[`schema2 11`] = ` +"import type { InferResult } from '../../../../../../src/entrypoints/schema.js' +import type * as Utils from '../../../../../../src/entrypoints/utilities-for-generated.js' +import type { Index } from './SchemaIndex.js' +import type * as SelectionSet from './SelectionSets.js' + +export interface MutationMethods<$Config extends Utils.Config> { + // todo Use a static type here? + $batch: <$SelectionSet>(selectionSet: Utils.Exact<$SelectionSet, SelectionSet.Mutation>) => Promise< + Utils.ResolveOutputReturnRootType< + $Config, + Index, + InferResult.Mutation< + Utils.AddTypenameToSelectedRootTypeResultFields<$Config, Index, 'Mutation', $SelectionSet>, + Index + > + > + > + // todo Use a static type here? + __typename: () => Promise< + Utils.ResolveOutputReturnRootField< + $Config, + Index, + '__typename', + 'Mutation' + > + > + id: <$SelectionSet>(selectionSet?: Utils.Exact<$SelectionSet, SelectionSet.Mutation.id>) => Promise< + Utils.ResolveOutputReturnRootField< + $Config, + Index, + 'id', + InferResult.Field<$SelectionSet, Index['Root']['Mutation']['fields']['id'], Index> + > + > + idNonNull: <$SelectionSet>(selectionSet?: Utils.Exact<$SelectionSet, SelectionSet.Mutation.idNonNull>) => Promise< + Utils.ResolveOutputReturnRootField< + $Config, + Index, + 'idNonNull', + InferResult.Field<$SelectionSet, Index['Root']['Mutation']['fields']['idNonNull'], Index> + > + > +} + +export interface QueryMethods<$Config extends Utils.Config> { + // todo Use a static type here? + $batch: <$SelectionSet>(selectionSet: Utils.Exact<$SelectionSet, SelectionSet.Query>) => Promise< + Utils.ResolveOutputReturnRootType< + $Config, + Index, + InferResult.Query< + Utils.AddTypenameToSelectedRootTypeResultFields<$Config, Index, 'Query', $SelectionSet>, + Index + > + > + > + // todo Use a static type here? + __typename: () => Promise< + Utils.ResolveOutputReturnRootField< + $Config, + Index, + '__typename', + 'Query' + > + > + InputObjectNested: <$SelectionSet>( + selectionSet?: Utils.Exact<$SelectionSet, SelectionSet.Query.InputObjectNested>, + ) => Promise< + Utils.ResolveOutputReturnRootField< + $Config, + Index, + 'InputObjectNested', + InferResult.Field<$SelectionSet, Index['Root']['Query']['fields']['InputObjectNested'], Index> + > + > + InputObjectNestedNonNull: <$SelectionSet>( + selectionSet: Utils.Exact<$SelectionSet, SelectionSet.Query.InputObjectNestedNonNull>, + ) => Promise< + Utils.ResolveOutputReturnRootField< + $Config, + Index, + 'InputObjectNestedNonNull', + InferResult.Field<$SelectionSet, Index['Root']['Query']['fields']['InputObjectNestedNonNull'], Index> + > + > + /** + * Query enum field documentation. + */ + abcEnum: <$SelectionSet>(selectionSet: Utils.Exact<$SelectionSet, SelectionSet.Query.abcEnum>) => Promise< + Utils.ResolveOutputReturnRootField< + $Config, + Index, + 'abcEnum', + InferResult.Field<$SelectionSet, Index['Root']['Query']['fields']['abcEnum'], Index> + > + > + argInputObjectCircular: <$SelectionSet>( + selectionSet?: Utils.Exact<$SelectionSet, SelectionSet.Query.argInputObjectCircular>, + ) => Promise< + Utils.ResolveOutputReturnRootField< + $Config, + Index, + 'argInputObjectCircular', + InferResult.Field<$SelectionSet, Index['Root']['Query']['fields']['argInputObjectCircular'], Index> + > + > + date: <$SelectionSet>(selectionSet?: Utils.Exact<$SelectionSet, SelectionSet.Query.date>) => Promise< + Utils.ResolveOutputReturnRootField< + $Config, + Index, + 'date', + InferResult.Field<$SelectionSet, Index['Root']['Query']['fields']['date'], Index> + > + > + dateArg: <$SelectionSet>(selectionSet?: Utils.Exact<$SelectionSet, SelectionSet.Query.dateArg>) => Promise< + Utils.ResolveOutputReturnRootField< + $Config, + Index, + 'dateArg', + InferResult.Field<$SelectionSet, Index['Root']['Query']['fields']['dateArg'], Index> + > + > + dateArgInputObject: <$SelectionSet>( + selectionSet?: Utils.Exact<$SelectionSet, SelectionSet.Query.dateArgInputObject>, + ) => Promise< + Utils.ResolveOutputReturnRootField< + $Config, + Index, + 'dateArgInputObject', + InferResult.Field<$SelectionSet, Index['Root']['Query']['fields']['dateArgInputObject'], Index> + > + > + dateArgList: <$SelectionSet>(selectionSet?: Utils.Exact<$SelectionSet, SelectionSet.Query.dateArgList>) => Promise< + Utils.ResolveOutputReturnRootField< + $Config, + Index, + 'dateArgList', + InferResult.Field<$SelectionSet, Index['Root']['Query']['fields']['dateArgList'], Index> + > + > + dateArgNonNull: <$SelectionSet>( + selectionSet: Utils.Exact<$SelectionSet, SelectionSet.Query.dateArgNonNull>, + ) => Promise< + Utils.ResolveOutputReturnRootField< + $Config, + Index, + 'dateArgNonNull', + InferResult.Field<$SelectionSet, Index['Root']['Query']['fields']['dateArgNonNull'], Index> + > + > + dateArgNonNullList: <$SelectionSet>( + selectionSet: Utils.Exact<$SelectionSet, SelectionSet.Query.dateArgNonNullList>, + ) => Promise< + Utils.ResolveOutputReturnRootField< + $Config, + Index, + 'dateArgNonNullList', + InferResult.Field<$SelectionSet, Index['Root']['Query']['fields']['dateArgNonNullList'], Index> + > + > + dateArgNonNullListNonNull: <$SelectionSet>( + selectionSet: Utils.Exact<$SelectionSet, SelectionSet.Query.dateArgNonNullListNonNull>, + ) => Promise< + Utils.ResolveOutputReturnRootField< + $Config, + Index, + 'dateArgNonNullListNonNull', + InferResult.Field<$SelectionSet, Index['Root']['Query']['fields']['dateArgNonNullListNonNull'], Index> + > + > + dateInterface1: <$SelectionSet>( + selectionSet: Utils.Exact<$SelectionSet, SelectionSet.Query.dateInterface1>, + ) => Promise< + Utils.ResolveOutputReturnRootField< + $Config, + Index, + 'dateInterface1', + InferResult.Field<$SelectionSet, Index['Root']['Query']['fields']['dateInterface1'], Index> + > + > + dateList: <$SelectionSet>(selectionSet?: Utils.Exact<$SelectionSet, SelectionSet.Query.dateList>) => Promise< + Utils.ResolveOutputReturnRootField< + $Config, + Index, + 'dateList', + InferResult.Field<$SelectionSet, Index['Root']['Query']['fields']['dateList'], Index> + > + > + dateListList: <$SelectionSet>(selectionSet?: Utils.Exact<$SelectionSet, SelectionSet.Query.dateListList>) => Promise< + Utils.ResolveOutputReturnRootField< + $Config, + Index, + 'dateListList', + InferResult.Field<$SelectionSet, Index['Root']['Query']['fields']['dateListList'], Index> + > + > + dateListNonNull: <$SelectionSet>( + selectionSet?: Utils.Exact<$SelectionSet, SelectionSet.Query.dateListNonNull>, + ) => Promise< + Utils.ResolveOutputReturnRootField< + $Config, + Index, + 'dateListNonNull', + InferResult.Field<$SelectionSet, Index['Root']['Query']['fields']['dateListNonNull'], Index> + > + > + dateNonNull: <$SelectionSet>(selectionSet?: Utils.Exact<$SelectionSet, SelectionSet.Query.dateNonNull>) => Promise< + Utils.ResolveOutputReturnRootField< + $Config, + Index, + 'dateNonNull', + InferResult.Field<$SelectionSet, Index['Root']['Query']['fields']['dateNonNull'], Index> + > + > + dateObject1: <$SelectionSet>(selectionSet: Utils.Exact<$SelectionSet, SelectionSet.Query.dateObject1>) => Promise< + Utils.ResolveOutputReturnRootField< + $Config, + Index, + 'dateObject1', + InferResult.Field<$SelectionSet, Index['Root']['Query']['fields']['dateObject1'], Index> + > + > + dateUnion: <$SelectionSet>(selectionSet: Utils.Exact<$SelectionSet, SelectionSet.Query.dateUnion>) => Promise< + Utils.ResolveOutputReturnRootField< + $Config, + Index, + 'dateUnion', + InferResult.Field<$SelectionSet, Index['Root']['Query']['fields']['dateUnion'], Index> + > + > + error: <$SelectionSet>(selectionSet?: Utils.Exact<$SelectionSet, SelectionSet.Query.error>) => Promise< + Utils.ResolveOutputReturnRootField< + $Config, + Index, + 'error', + InferResult.Field<$SelectionSet, Index['Root']['Query']['fields']['error'], Index> + > + > + id: <$SelectionSet>(selectionSet?: Utils.Exact<$SelectionSet, SelectionSet.Query.id>) => Promise< + Utils.ResolveOutputReturnRootField< + $Config, + Index, + 'id', + InferResult.Field<$SelectionSet, Index['Root']['Query']['fields']['id'], Index> + > + > + idNonNull: <$SelectionSet>(selectionSet?: Utils.Exact<$SelectionSet, SelectionSet.Query.idNonNull>) => Promise< + Utils.ResolveOutputReturnRootField< + $Config, + Index, + 'idNonNull', + InferResult.Field<$SelectionSet, Index['Root']['Query']['fields']['idNonNull'], Index> + > + > + interface: <$SelectionSet>(selectionSet: Utils.Exact<$SelectionSet, SelectionSet.Query.$interface>) => Promise< + Utils.ResolveOutputReturnRootField< + $Config, + Index, + 'interface', + InferResult.Field<$SelectionSet, Index['Root']['Query']['fields']['interface'], Index> + > + > + interfaceNonNull: <$SelectionSet>( + selectionSet: Utils.Exact<$SelectionSet, SelectionSet.Query.interfaceNonNull>, + ) => Promise< + Utils.ResolveOutputReturnRootField< + $Config, + Index, + 'interfaceNonNull', + InferResult.Field<$SelectionSet, Index['Root']['Query']['fields']['interfaceNonNull'], Index> + > + > + interfaceWithArgs: <$SelectionSet>( + selectionSet: Utils.Exact<$SelectionSet, SelectionSet.Query.interfaceWithArgs>, + ) => Promise< + Utils.ResolveOutputReturnRootField< + $Config, + Index, + 'interfaceWithArgs', + InferResult.Field<$SelectionSet, Index['Root']['Query']['fields']['interfaceWithArgs'], Index> + > + > + listInt: <$SelectionSet>(selectionSet?: Utils.Exact<$SelectionSet, SelectionSet.Query.listInt>) => Promise< + Utils.ResolveOutputReturnRootField< + $Config, + Index, + 'listInt', + InferResult.Field<$SelectionSet, Index['Root']['Query']['fields']['listInt'], Index> + > + > + listIntNonNull: <$SelectionSet>( + selectionSet?: Utils.Exact<$SelectionSet, SelectionSet.Query.listIntNonNull>, + ) => Promise< + Utils.ResolveOutputReturnRootField< + $Config, + Index, + 'listIntNonNull', + InferResult.Field<$SelectionSet, Index['Root']['Query']['fields']['listIntNonNull'], Index> + > + > + listListInt: <$SelectionSet>(selectionSet?: Utils.Exact<$SelectionSet, SelectionSet.Query.listListInt>) => Promise< + Utils.ResolveOutputReturnRootField< + $Config, + Index, + 'listListInt', + InferResult.Field<$SelectionSet, Index['Root']['Query']['fields']['listListInt'], Index> + > + > + listListIntNonNull: <$SelectionSet>( + selectionSet?: Utils.Exact<$SelectionSet, SelectionSet.Query.listListIntNonNull>, + ) => Promise< + Utils.ResolveOutputReturnRootField< + $Config, + Index, + 'listListIntNonNull', + InferResult.Field<$SelectionSet, Index['Root']['Query']['fields']['listListIntNonNull'], Index> + > + > + lowerCaseUnion: <$SelectionSet>( + selectionSet: Utils.Exact<$SelectionSet, SelectionSet.Query.lowerCaseUnion>, + ) => Promise< + Utils.ResolveOutputReturnRootField< + $Config, + Index, + 'lowerCaseUnion', + InferResult.Field<$SelectionSet, Index['Root']['Query']['fields']['lowerCaseUnion'], Index> + > + > + object: <$SelectionSet>(selectionSet: Utils.Exact<$SelectionSet, SelectionSet.Query.$object>) => Promise< + Utils.ResolveOutputReturnRootField< + $Config, + Index, + 'object', + InferResult.Field<$SelectionSet, Index['Root']['Query']['fields']['object'], Index> + > + > + objectList: <$SelectionSet>(selectionSet: Utils.Exact<$SelectionSet, SelectionSet.Query.objectList>) => Promise< + Utils.ResolveOutputReturnRootField< + $Config, + Index, + 'objectList', + InferResult.Field<$SelectionSet, Index['Root']['Query']['fields']['objectList'], Index> + > + > + objectListNonNull: <$SelectionSet>( + selectionSet: Utils.Exact<$SelectionSet, SelectionSet.Query.objectListNonNull>, + ) => Promise< + Utils.ResolveOutputReturnRootField< + $Config, + Index, + 'objectListNonNull', + InferResult.Field<$SelectionSet, Index['Root']['Query']['fields']['objectListNonNull'], Index> + > + > + objectNested: <$SelectionSet>(selectionSet: Utils.Exact<$SelectionSet, SelectionSet.Query.objectNested>) => Promise< + Utils.ResolveOutputReturnRootField< + $Config, + Index, + 'objectNested', + InferResult.Field<$SelectionSet, Index['Root']['Query']['fields']['objectNested'], Index> + > + > + objectNonNull: <$SelectionSet>(selectionSet: Utils.Exact<$SelectionSet, SelectionSet.Query.objectNonNull>) => Promise< + Utils.ResolveOutputReturnRootField< + $Config, + Index, + 'objectNonNull', + InferResult.Field<$SelectionSet, Index['Root']['Query']['fields']['objectNonNull'], Index> + > + > + objectWithArgs: <$SelectionSet>( + selectionSet: Utils.Exact<$SelectionSet, SelectionSet.Query.objectWithArgs>, + ) => Promise< + Utils.ResolveOutputReturnRootField< + $Config, + Index, + 'objectWithArgs', + InferResult.Field<$SelectionSet, Index['Root']['Query']['fields']['objectWithArgs'], Index> + > + > + result: <$SelectionSet>(selectionSet: Utils.Exact<$SelectionSet, SelectionSet.Query.result>) => Promise< + Utils.ResolveOutputReturnRootField< + $Config, + Index, + 'result', + InferResult.Field<$SelectionSet, Index['Root']['Query']['fields']['result'], Index> + > + > + resultNonNull: <$SelectionSet>(selectionSet: Utils.Exact<$SelectionSet, SelectionSet.Query.resultNonNull>) => Promise< + Utils.ResolveOutputReturnRootField< + $Config, + Index, + 'resultNonNull', + InferResult.Field<$SelectionSet, Index['Root']['Query']['fields']['resultNonNull'], Index> + > + > + string: <$SelectionSet>(selectionSet?: Utils.Exact<$SelectionSet, SelectionSet.Query.$string>) => Promise< + Utils.ResolveOutputReturnRootField< + $Config, + Index, + 'string', + InferResult.Field<$SelectionSet, Index['Root']['Query']['fields']['string'], Index> + > + > + stringWithArgEnum: <$SelectionSet>( + selectionSet?: Utils.Exact<$SelectionSet, SelectionSet.Query.stringWithArgEnum>, + ) => Promise< + Utils.ResolveOutputReturnRootField< + $Config, + Index, + 'stringWithArgEnum', + InferResult.Field<$SelectionSet, Index['Root']['Query']['fields']['stringWithArgEnum'], Index> + > + > + stringWithArgInputObject: <$SelectionSet>( + selectionSet?: Utils.Exact<$SelectionSet, SelectionSet.Query.stringWithArgInputObject>, + ) => Promise< + Utils.ResolveOutputReturnRootField< + $Config, + Index, + 'stringWithArgInputObject', + InferResult.Field<$SelectionSet, Index['Root']['Query']['fields']['stringWithArgInputObject'], Index> + > + > + stringWithArgInputObjectRequired: <$SelectionSet>( + selectionSet: Utils.Exact<$SelectionSet, SelectionSet.Query.stringWithArgInputObjectRequired>, + ) => Promise< + Utils.ResolveOutputReturnRootField< + $Config, + Index, + 'stringWithArgInputObjectRequired', + InferResult.Field<$SelectionSet, Index['Root']['Query']['fields']['stringWithArgInputObjectRequired'], Index> + > + > + /** + * The given arguments are reflected back as a JSON string. + */ + stringWithArgs: <$SelectionSet>( + selectionSet?: Utils.Exact<$SelectionSet, SelectionSet.Query.stringWithArgs>, + ) => Promise< + Utils.ResolveOutputReturnRootField< + $Config, + Index, + 'stringWithArgs', + InferResult.Field<$SelectionSet, Index['Root']['Query']['fields']['stringWithArgs'], Index> + > + > + stringWithListArg: <$SelectionSet>( + selectionSet?: Utils.Exact<$SelectionSet, SelectionSet.Query.stringWithListArg>, + ) => Promise< + Utils.ResolveOutputReturnRootField< + $Config, + Index, + 'stringWithListArg', + InferResult.Field<$SelectionSet, Index['Root']['Query']['fields']['stringWithListArg'], Index> + > + > + stringWithListArgRequired: <$SelectionSet>( + selectionSet: Utils.Exact<$SelectionSet, SelectionSet.Query.stringWithListArgRequired>, + ) => Promise< + Utils.ResolveOutputReturnRootField< + $Config, + Index, + 'stringWithListArgRequired', + InferResult.Field<$SelectionSet, Index['Root']['Query']['fields']['stringWithListArgRequired'], Index> + > + > + stringWithRequiredArg: <$SelectionSet>( + selectionSet: Utils.Exact<$SelectionSet, SelectionSet.Query.stringWithRequiredArg>, + ) => Promise< + Utils.ResolveOutputReturnRootField< + $Config, + Index, + 'stringWithRequiredArg', + InferResult.Field<$SelectionSet, Index['Root']['Query']['fields']['stringWithRequiredArg'], Index> + > + > + unionFooBar: <$SelectionSet>(selectionSet: Utils.Exact<$SelectionSet, SelectionSet.Query.unionFooBar>) => Promise< + Utils.ResolveOutputReturnRootField< + $Config, + Index, + 'unionFooBar', + InferResult.Field<$SelectionSet, Index['Root']['Query']['fields']['unionFooBar'], Index> + > + > + unionFooBarNonNull: <$SelectionSet>( + selectionSet: Utils.Exact<$SelectionSet, SelectionSet.Query.unionFooBarNonNull>, + ) => Promise< + Utils.ResolveOutputReturnRootField< + $Config, + Index, + 'unionFooBarNonNull', + InferResult.Field<$SelectionSet, Index['Root']['Query']['fields']['unionFooBarNonNull'], Index> + > + > + unionFooBarWithArgs: <$SelectionSet>( + selectionSet: Utils.Exact<$SelectionSet, SelectionSet.Query.unionFooBarWithArgs>, + ) => Promise< + Utils.ResolveOutputReturnRootField< + $Config, + Index, + 'unionFooBarWithArgs', + InferResult.Field<$SelectionSet, Index['Root']['Query']['fields']['unionFooBarWithArgs'], Index> + > + > + unionObject: <$SelectionSet>(selectionSet: Utils.Exact<$SelectionSet, SelectionSet.Query.unionObject>) => Promise< + Utils.ResolveOutputReturnRootField< + $Config, + Index, + 'unionObject', + InferResult.Field<$SelectionSet, Index['Root']['Query']['fields']['unionObject'], Index> + > + > + unionObjectNonNull: <$SelectionSet>( + selectionSet: Utils.Exact<$SelectionSet, SelectionSet.Query.unionObjectNonNull>, + ) => Promise< + Utils.ResolveOutputReturnRootField< + $Config, + Index, + 'unionObjectNonNull', + InferResult.Field<$SelectionSet, Index['Root']['Query']['fields']['unionObjectNonNull'], Index> + > + > +} + +export interface BuilderMethodsRoot<$Config extends Utils.Config> { + mutation: MutationMethods<$Config> + query: QueryMethods<$Config> +} + +export interface BuilderMethodsRootFn extends Utils.HKT.Fn { + // @ts-expect-error parameter is Untyped. + return: BuilderMethodsRoot +} +" +`; + +exports[`schema2 12`] = ` +"import type * as $Utilities from '../../../../../../src/entrypoints/utilities-for-generated.js' +import type * as $SelectionSets from './SelectionSets.js' + +// +// +// +// +// +// +// ================================================================================================== +// Select Methods Interface +// ================================================================================================== +// +// +// +// +// +// + +export interface $MethodsSelect { + Mutation: Mutation + Query: Query + Bar: Bar + DateObject1: DateObject1 + DateObject2: DateObject2 + ErrorOne: ErrorOne + ErrorTwo: ErrorTwo + Foo: Foo + Object1: Object1 + Object1ImplementingInterface: Object1ImplementingInterface + Object2ImplementingInterface: Object2ImplementingInterface + ObjectNested: ObjectNested + ObjectUnion: ObjectUnion + lowerCaseObject: lowerCaseObject + lowerCaseObject2: lowerCaseObject2 + DateUnion: DateUnion + FooBarUnion: FooBarUnion + Result: Result + lowerCaseUnion: lowerCaseUnion + DateInterface1: DateInterface1 + Error: Error + Interface: Interface +} + +// +// +// +// +// +// +// ================================================================================================== +// Root +// ================================================================================================== +// +// +// +// +// +// + +export interface Mutation { + <$SelectionSet>(selectionSet: $Utilities.Exact<$SelectionSet, $SelectionSets.Mutation>): $SelectionSet +} + +export interface Query { + <$SelectionSet>(selectionSet: $Utilities.Exact<$SelectionSet, $SelectionSets.Query>): $SelectionSet +} + +// +// +// +// +// +// +// ================================================================================================== +// Object +// ================================================================================================== +// +// +// +// +// +// + +export interface Bar { + <$SelectionSet>(selectionSet: $Utilities.Exact<$SelectionSet, $SelectionSets.Bar>): $SelectionSet +} + +export interface DateObject1 { + <$SelectionSet>(selectionSet: $Utilities.Exact<$SelectionSet, $SelectionSets.DateObject1>): $SelectionSet +} + +export interface DateObject2 { + <$SelectionSet>(selectionSet: $Utilities.Exact<$SelectionSet, $SelectionSets.DateObject2>): $SelectionSet +} + +export interface ErrorOne { + <$SelectionSet>(selectionSet: $Utilities.Exact<$SelectionSet, $SelectionSets.ErrorOne>): $SelectionSet +} + +export interface ErrorTwo { + <$SelectionSet>(selectionSet: $Utilities.Exact<$SelectionSet, $SelectionSets.ErrorTwo>): $SelectionSet +} + +export interface Foo { + <$SelectionSet>(selectionSet: $Utilities.Exact<$SelectionSet, $SelectionSets.Foo>): $SelectionSet +} + +export interface Object1 { + <$SelectionSet>(selectionSet: $Utilities.Exact<$SelectionSet, $SelectionSets.Object1>): $SelectionSet +} + +export interface Object1ImplementingInterface { + <$SelectionSet>( + selectionSet: $Utilities.Exact<$SelectionSet, $SelectionSets.Object1ImplementingInterface>, + ): $SelectionSet +} + +export interface Object2ImplementingInterface { + <$SelectionSet>( + selectionSet: $Utilities.Exact<$SelectionSet, $SelectionSets.Object2ImplementingInterface>, + ): $SelectionSet +} + +export interface ObjectNested { + <$SelectionSet>(selectionSet: $Utilities.Exact<$SelectionSet, $SelectionSets.ObjectNested>): $SelectionSet +} + +export interface ObjectUnion { + <$SelectionSet>(selectionSet: $Utilities.Exact<$SelectionSet, $SelectionSets.ObjectUnion>): $SelectionSet +} + +export interface lowerCaseObject { + <$SelectionSet>(selectionSet: $Utilities.Exact<$SelectionSet, $SelectionSets.lowerCaseObject>): $SelectionSet +} + +export interface lowerCaseObject2 { + <$SelectionSet>(selectionSet: $Utilities.Exact<$SelectionSet, $SelectionSets.lowerCaseObject2>): $SelectionSet +} + +// +// +// +// +// +// +// ================================================================================================== +// Union +// ================================================================================================== +// +// +// +// +// +// + +export interface DateUnion { + <$SelectionSet>(selectionSet: $Utilities.Exact<$SelectionSet, $SelectionSets.DateUnion>): $SelectionSet +} + +export interface FooBarUnion { + <$SelectionSet>(selectionSet: $Utilities.Exact<$SelectionSet, $SelectionSets.FooBarUnion>): $SelectionSet +} + +export interface Result { + <$SelectionSet>(selectionSet: $Utilities.Exact<$SelectionSet, $SelectionSets.Result>): $SelectionSet +} + +export interface lowerCaseUnion { + <$SelectionSet>(selectionSet: $Utilities.Exact<$SelectionSet, $SelectionSets.lowerCaseUnion>): $SelectionSet +} + +// +// +// +// +// +// +// ================================================================================================== +// Interface +// ================================================================================================== +// +// +// +// +// +// + +export interface DateInterface1 { + <$SelectionSet>(selectionSet: $Utilities.Exact<$SelectionSet, $SelectionSets.DateInterface1>): $SelectionSet +} + +export interface Error { + <$SelectionSet>(selectionSet: $Utilities.Exact<$SelectionSet, $SelectionSets.Error>): $SelectionSet +} + +export interface Interface { + <$SelectionSet>(selectionSet: $Utilities.Exact<$SelectionSet, $SelectionSets.Interface>): $SelectionSet +} " `; diff --git a/src/layers/4_generator/config.ts b/src/layers/4_generator/config.ts index b1b18d72d..a3a60dfda 100644 --- a/src/layers/4_generator/config.ts +++ b/src/layers/4_generator/config.ts @@ -4,7 +4,7 @@ import fs from 'node:fs/promises' import * as Path from 'node:path' import { Graffle } from '../../entrypoints/__Graffle.js' import { Introspection } from '../../entrypoints/extensions.js' -import { Nodes } from '../../lib/grafaid/_Nodes.js' +import { Grafaid } from '../../lib/grafaid/__.js' import { omitUndefinedKeys } from '../../lib/prelude.js' import { fileExists, isPathToADirectory } from './helpers/fs.js' @@ -74,12 +74,16 @@ export interface Config { schema: { sdl: string instance: GraphQLSchema - typeMapByKind: Nodes.$Schema.KindMap.KindMap + typeMapByKind: Grafaid.Schema.KindMap.KindMap error: { objects: GraphQLObjectType[] enabled: boolean } } + runtimeFeatures: { + customScalars: boolean + operationVariables: boolean + } options: { defaultSchemaUrl: URL | null format: boolean @@ -132,12 +136,16 @@ export const createConfig = async (input: Input): Promise => { const sourceSchema = await resolveSourceSchema(input) const schema = buildSchema(sourceSchema.content) - const typeMapByKind = Nodes.$Schema.KindMap.getKindMap(schema) + const typeMapByKind = Grafaid.Schema.KindMap.getKindMap(schema) const errorObjects = errorTypeNamePattern ? Object.values(typeMapByKind.GraphQLObjectType).filter(_ => _.name.match(errorTypeNamePattern)) : [] return { + runtimeFeatures: { + customScalars: true, // todo do not assume true + operationVariables: true, // todo do not assume true + }, name: input.name ?? defaultName, paths: { project: { diff --git a/src/layers/4_generator/generate.test.ts b/src/layers/4_generator/generate.test.ts index c3f01511e..ea70a6a6e 100644 --- a/src/layers/4_generator/generate.test.ts +++ b/src/layers/4_generator/generate.test.ts @@ -1,6 +1,7 @@ import { readFile } from 'fs/promises' import { expect, test } from 'vitest' +// todo replace with snapshot via glob test(`schema2`, async () => { expect( await readFile(`./tests/_/schemas/kitchen-sink/graffle/modules/Client.ts`, `utf8`), @@ -27,6 +28,15 @@ test(`schema2`, async () => { await readFile(`./tests/_/schemas/kitchen-sink/graffle/modules/Scalar.ts`, `utf8`), ).toMatchSnapshot() expect( - await readFile(`./tests/_/schemas/kitchen-sink/graffle/modules/SchemaRuntime.ts`, `utf8`), + await readFile(`./tests/_/schemas/kitchen-sink/graffle/modules/SchemaDrivenDataMap.ts`, `utf8`), + ).toMatchSnapshot() + expect( + await readFile(`./tests/_/schemas/kitchen-sink/graffle/modules/MethodsDocument.ts`, `utf8`), + ).toMatchSnapshot() + expect( + await readFile(`./tests/_/schemas/kitchen-sink/graffle/modules/MethodsRoot.ts`, `utf8`), + ).toMatchSnapshot() + expect( + await readFile(`./tests/_/schemas/kitchen-sink/graffle/modules/MethodsSelect.ts`, `utf8`), ).toMatchSnapshot() }) diff --git a/src/layers/4_generator/generate.ts b/src/layers/4_generator/generate.ts index e15068e7a..6da5dfb0c 100644 --- a/src/layers/4_generator/generate.ts +++ b/src/layers/4_generator/generate.ts @@ -1,5 +1,5 @@ import fs from 'node:fs/promises' -import { ModuleGeneratorRuntimeCustomScalars } from '../7_customScalars/RuntimeIndexCustomScalars.js' +import { ModuleGeneratorSchemaDrivenDataMap } from '../7_extensions/CustomScalars/schemaDrivenDataMap/generator.js' import { type Config, createConfig, type Input } from './config.js' import { ModuleGenerator_ } from './generators/_.js' import { ModuleGenerator__ } from './generators/__.js' @@ -13,7 +13,6 @@ import { ModuleGeneratorMethodsSelect } from './generators/MethodsSelect.js' import { ModuleGeneratorScalar } from './generators/Scalar.js' import { ModuleGeneratorSchemaBuildtime } from './generators/SchemaBuildtime.js' import { ModuleGeneratorSchemaIndex } from './generators/SchemaIndex.js' -import { ModuleGeneratorSchemaRuntime } from './generators/SchemaRuntime.js' import { ModuleGeneratorSelect } from './generators/Select.js' import { ModuleGeneratorSelectionSets } from './generators/SelectionSets.js' import type { GeneratedModule } from './helpers/moduleGenerator.js' @@ -55,8 +54,7 @@ const generateCode = async (config: Config): Promise => { // Schema Stuff ModuleGeneratorSchemaIndex, ModuleGeneratorSchemaBuildtime, - ModuleGeneratorSchemaRuntime, - ModuleGeneratorRuntimeCustomScalars, + ModuleGeneratorSchemaDrivenDataMap, // Interface Stuff ModuleGeneratorSelectionSets, ModuleGeneratorSelect, diff --git a/src/layers/4_generator/generators/Client.ts b/src/layers/4_generator/generators/Client.ts index 358585626..3f35ae55e 100644 --- a/src/layers/4_generator/generators/Client.ts +++ b/src/layers/4_generator/generators/Client.ts @@ -1,16 +1,16 @@ +import { ModuleGeneratorSchemaDrivenDataMap } from '../../7_extensions/CustomScalars/schemaDrivenDataMap/generator.js' import { createModuleGenerator } from '../helpers/moduleGenerator.js' -import { ModuleGeneratorSchemaRuntime } from './SchemaRuntime.js' +import { ModuleGeneratorData } from './Data.js' export const ModuleGeneratorClient = createModuleGenerator( `Client`, ({ config, code }) => { code( `import { createPrefilled } from '${config.paths.imports.grafflePackage.client}'`, - `import { $defaultSchemaUrl, $Index } from './${ModuleGeneratorSchemaRuntime.name}.js'`, + `import { defaultSchemaUrl } from './${ModuleGeneratorData.name}.js'`, + `import { schemaDrivenDataMap } from './${ModuleGeneratorSchemaDrivenDataMap.name}.js'`, ``, - `export const create = createPrefilled(\`${config.name}\`, $Index, $defaultSchemaUrl)`, + `export const create = createPrefilled(\`${config.name}\`, schemaDrivenDataMap, defaultSchemaUrl)`, ) - - return code }, ) diff --git a/src/layers/4_generator/generators/Data.ts b/src/layers/4_generator/generators/Data.ts index 0c0512d64..39b85902c 100644 --- a/src/layers/4_generator/generators/Data.ts +++ b/src/layers/4_generator/generators/Data.ts @@ -7,7 +7,11 @@ export const ModuleGeneratorData = createModuleGenerator( `export const Name = \`${config.name}\``, `export type Name = '${config.name}'`, ) - - return code + code() + code( + `export const defaultSchemaUrl = ${ + config.options.defaultSchemaUrl ? `new URL("${config.options.defaultSchemaUrl.href}")` : `undefined` + }`, + ) }, ) diff --git a/src/layers/4_generator/generators/MethodsRoot.ts b/src/layers/4_generator/generators/MethodsRoot.ts index 0abfb64bf..a49ec1e99 100644 --- a/src/layers/4_generator/generators/MethodsRoot.ts +++ b/src/layers/4_generator/generators/MethodsRoot.ts @@ -1,5 +1,4 @@ // todo remove use of Utils.Aug when schema errors not in use -import { getNamedType, type GraphQLObjectType, isScalarType } from 'graphql' import { Grafaid } from '../../../lib/grafaid/__.js' import { createModuleGenerator } from '../helpers/moduleGenerator.js' import { createCodeGenerator } from '../helpers/moduleGeneratorRunner.js' @@ -47,7 +46,7 @@ export const ModuleGeneratorMethodsRoot = createModuleGenerator( }, ) -const renderRootType = createCodeGenerator<{ node: GraphQLObjectType }>(({ node, config, code }) => { +const renderRootType = createCodeGenerator<{ node: Grafaid.Schema.ObjectType }>(({ node, config, code }) => { const fieldMethods = renderFieldMethods({ config, node }) code(` @@ -78,32 +77,21 @@ const renderRootType = createCodeGenerator<{ node: GraphQLObjectType }>(({ node, }`) }) -const renderFieldMethods = createCodeGenerator<{ node: GraphQLObjectType }>(({ node, config, code }) => { +const renderFieldMethods = createCodeGenerator<{ node: Grafaid.Schema.ObjectType }>(({ node, config, code }) => { for (const field of Object.values(node.getFields())) { const doc = renderDocumentation(config, field) code(doc) - const fieldTypeUnwrapped = getNamedType(field.type) + const fieldTypeUnwrapped = Grafaid.Schema.getNamedType(field.type) - if (isScalarType(fieldTypeUnwrapped)) { - const isArgsAllNullable_ = Grafaid.Schema.Args.isAllArgsNullable(field.args) - const parametersCode = field.args.length > 0 - ? `<$SelectionSet>(args${isArgsAllNullable_ ? `?` : ``}: Utils.Exact<$SelectionSet, SelectionSet.${ - renderName(node) - }.${renderName(field)}$SelectionSetArguments>)` - : `()` + const isOptional = Grafaid.Schema.isScalarType(fieldTypeUnwrapped) + && Grafaid.Schema.Args.isAllArgsNullable(field.args) - code(` - ${field.name}: ${parametersCode} => - ${Helpers.returnType(node.name, field.name, `true`)} - `) - } else { - code(` - ${field.name}: <$SelectionSet> - (selectionSet: Utils.Exact<$SelectionSet, SelectionSet.${renderName(node)}.${renderName(field)}>) => - ${Helpers.returnType(node.name, field.name, `$SelectionSet`)} - `) - } + // dprint-ignore + code(` + ${field.name}: <$SelectionSet>(selectionSet${isOptional ? `?` : ``}: Utils.Exact<$SelectionSet, SelectionSet.${renderName(node)}.${renderName(field)}>) => + ${Helpers.returnType(node.name, field.name, `$SelectionSet`)} + `) } }) diff --git a/src/layers/4_generator/generators/SchemaBuildtime.ts b/src/layers/4_generator/generators/SchemaBuildtime.ts index 911a08667..b537369b4 100644 --- a/src/layers/4_generator/generators/SchemaBuildtime.ts +++ b/src/layers/4_generator/generators/SchemaBuildtime.ts @@ -1,21 +1,5 @@ -import type { - GraphQLArgument, - GraphQLInputObjectType, - GraphQLInterfaceType, - GraphQLNamedType, - GraphQLObjectType, -} from 'graphql' -import { getNullableType, isListType, isNamedType, isNullableType } from 'graphql' import { Code } from '../../../lib/Code.js' import { Grafaid } from '../../../lib/grafaid/__.js' -import type { Nodes } from '../../../lib/grafaid/graphql.js' -import { - type AnyClass, - type AnyField, - type AnyNamedClassName, - type ClassToName, - type NamedNameToClass, -} from '../../../lib/grafaid/graphql.js' import { entries, values } from '../../../lib/prelude.js' import type { Config } from '../config.js' import { createModuleGenerator } from '../helpers/moduleGenerator.js' @@ -29,39 +13,41 @@ const namespaceNames = { GraphQLObjectType: `Object`, GraphQLScalarType: `Scalar`, GraphQLUnionType: `Union`, -} satisfies Record +} satisfies Record type AnyGraphQLFieldsType = - | GraphQLObjectType - | GraphQLInterfaceType - | GraphQLInputObjectType + | Grafaid.Schema.ObjectType + | Grafaid.Schema.InterfaceType + | Grafaid.Schema.InputObjectType const defineReferenceRenderers = < - $Renderers extends { [ClassName in keyof NamedNameToClass]: any }, + $Renderers extends { [ClassName in keyof Grafaid.Schema.NamedNameToClass]: any }, >( renderers: { [ClassName in keyof $Renderers]: ( config: Config, - node: ClassName extends keyof NamedNameToClass ? InstanceType + node: ClassName extends keyof Grafaid.Schema.NamedNameToClass + ? InstanceType : never, ) => string }, ) => renderers const defineConcreteRenderers = < - $Renderers extends { [ClassName in keyof Nodes.$Schema.NameToClassNamedType]: any }, + $Renderers extends { [ClassName in keyof Grafaid.Schema.NameToClassNamedType]: any }, >( renderers: { [ClassName in keyof $Renderers]: ( config: Config, - node: ClassName extends keyof Nodes.$Schema.NameToClassNamedType - ? InstanceType + node: ClassName extends keyof Grafaid.Schema.NameToClassNamedType + ? InstanceType : never, ) => string }, ): { [ClassName in keyof $Renderers]: ( - node: ClassName extends keyof Grafaid.NameToClass ? InstanceType | null | undefined + node: ClassName extends keyof Grafaid.Schema.NameToClass + ? InstanceType | null | undefined : never, ) => string } => { @@ -78,18 +64,10 @@ const defineConcreteRenderers = < ) as any } -const dispatchToReferenceRenderer = (config: Config, node: AnyClass): string => - // @ts-expect-error fixme - getReferenceRenderer(node)(config, node as any) - -// @ts-expect-error fixme -const getReferenceRenderer = (node: N): (typeof referenceRenderers)[ClassToName] => { - // @ts-expect-error lookup - const renderer = referenceRenderers[node.constructor.name] - if (!renderer) { - throw new Error(`No renderer found for class: ${node.constructor.name}`) - } - return renderer +const dispatchToReferenceRenderer = (config: Config, type: Grafaid.Schema.Types): string => { + const renderer = (referenceRenderers as any)[type.constructor.name] + if (!renderer) throw new Error(`No renderer found for class: ${type.constructor.name}`) + return renderer(config, type as any) } const referenceRenderers = defineReferenceRenderers({ @@ -105,7 +83,7 @@ const referenceRenderers = defineReferenceRenderers({ const dispatchToConcreteRenderer = ( config: Config, - node: GraphQLNamedType, + node: Grafaid.Schema.NamedTypes, ): string => { // @ts-expect-error lookup const renderer = concreteRenderers[node.constructor.name] @@ -203,7 +181,7 @@ const renderInputFields = (config: Config, node: AnyGraphQLFieldsType): string = ])) } -const renderOutputField = (config: Config, field: AnyField): string => { +const renderOutputField = (config: Config, field: Grafaid.Schema.InputOrOutputField): string => { const type = buildType(`output`, config, field.type) const args = Grafaid.Schema.isGraphQLOutputField(field) && field.args.length > 0 @@ -213,16 +191,16 @@ const renderOutputField = (config: Config, field: AnyField): string => { return `$.Field<'${field.name}', ${type}${args ? `, ${args}` : `, null`}>` } -const renderInputField = (config: Config, field: AnyField): string => { +const renderInputField = (config: Config, field: Grafaid.Schema.InputOrOutputField): string => { return `$.Input.Field<${buildType(`input`, config, field.type)}>` } -const buildType = (direction: 'input' | 'output', config: Config, node: AnyClass) => { +const buildType = (direction: 'input' | 'output', config: Config, node: Grafaid.Schema.Types) => { const ns = direction === `input` ? `Input` : `Output` - const nullable = isNullableType(node) - const nodeInner = getNullableType(node) + const nullable = Grafaid.Schema.isNullableType(node) + const nodeInner = Grafaid.Schema.getNullableType(node) - if (isNamedType(nodeInner)) { + if (Grafaid.Schema.isNamedType(nodeInner)) { const namedTypeReference = dispatchToReferenceRenderer(config, nodeInner) // const namedTypeCode = `_.Named<${namedTypeReference}>` const namedTypeCode = namedTypeReference @@ -231,7 +209,7 @@ const buildType = (direction: 'input' | 'output', config: Config, node: AnyClass : namedTypeCode } - if (isListType(nodeInner)) { + if (Grafaid.Schema.isListType(nodeInner)) { const fieldType = `$.${ns}.List<${buildType(direction, config, nodeInner.ofType)}>` as any as string return nullable ? `$.${ns}.Nullable<${fieldType}>` @@ -241,7 +219,7 @@ const buildType = (direction: 'input' | 'output', config: Config, node: AnyClass throw new Error(`Unhandled type: ${String(node)}`) } -const renderArgs = (config: Config, args: readonly GraphQLArgument[]) => { +const renderArgs = (config: Config, args: readonly Grafaid.Schema.Argument[]) => { const code = `$.Args<${ Code.object( Code.fields( @@ -252,7 +230,7 @@ const renderArgs = (config: Config, args: readonly GraphQLArgument[]) => { return code } -const renderArg = (config: Config, arg: GraphQLArgument) => { +const renderArg = (config: Config, arg: Grafaid.Schema.Argument) => { // const { nullable } = unwrapToNonNull(arg.type) // hasRequiredArgs = hasRequiredArgs || !nullable const type = buildType(`input`, config, arg.type) diff --git a/src/layers/4_generator/generators/SchemaIndex.ts b/src/layers/4_generator/generators/SchemaIndex.ts index 9e9952a86..5431e4ff0 100644 --- a/src/layers/4_generator/generators/SchemaIndex.ts +++ b/src/layers/4_generator/generators/SchemaIndex.ts @@ -2,37 +2,13 @@ import { getNamedType, isUnionType } from 'graphql' import { Code } from '../../../lib/Code.js' import { Grafaid } from '../../../lib/grafaid/__.js' import type { Schema } from '../../1_Schema/__.js' -import type { CodecString } from '../../3_SelectGraphQLMapper/types.js' +import type { SchemaDrivenDataMap } from '../../7_extensions/CustomScalars/schemaDrivenDataMap/types.js' import type { GlobalRegistry } from '../globalRegistry.js' import { createModuleGenerator } from '../helpers/moduleGenerator.js' import { ModuleGeneratorData } from './Data.js' import { ModuleGeneratorMethodsRoot } from './MethodsRoot.js' import { ModuleGeneratorSchemaBuildtime } from './SchemaBuildtime.js' -export interface CustomScalarsIndex { - [Grafaid.Schema.RootTypeName.Mutation]?: CustomScalarsIndex.OutputObject - [Grafaid.Schema.RootTypeName.Query]?: CustomScalarsIndex.OutputObject - [Grafaid.Schema.RootTypeName.Subscription]?: CustomScalarsIndex.OutputObject -} - -export namespace CustomScalarsIndex { - export interface OutputObject { - [key: string]: OutputField - } - - export interface OutputField { - o?: CodecString - i?: InputObject - r?: OutputObject - } - - export interface InputObject { - [key: string]: InputField - } - - export type InputField = CodecString | InputObject -} - /** * A generic schema index type. Any particular schema index will be a subtype of this, with * additional specificity such as on objects where here `Record` is used. @@ -60,7 +36,7 @@ export interface SchemaIndex { unions: Record interfaces: Record customScalars: { - input: CustomScalarsIndex + input: SchemaDrivenDataMap } error: { objects: Record diff --git a/src/layers/4_generator/generators/SchemaRuntime.ts b/src/layers/4_generator/generators/SchemaRuntime.ts deleted file mode 100644 index 60e436170..000000000 --- a/src/layers/4_generator/generators/SchemaRuntime.ts +++ /dev/null @@ -1,277 +0,0 @@ -import { - getNamedType, - getNullableType, - type GraphQLArgument, - type GraphQLEnumType, - type GraphQLInputField, - type GraphQLInputObjectType, - type GraphQLInterfaceType, - GraphQLList, - GraphQLNonNull, - type GraphQLOutputType, - GraphQLScalarType, - type GraphQLUnionType, - isNullableType, -} from 'graphql' -import { - type GraphQLObjectType, - isEnumType, - isInputObjectType, - isInterfaceType, - isListType, - isNamedType, - isObjectType, - isScalarType, - isUnionType, -} from 'graphql' -import { Code } from '../../../lib/Code.js' -import { Grafaid } from '../../../lib/grafaid/__.js' -import type { AnyClass, AnyGraphQLOutputField } from '../../../lib/grafaid/graphql.js' -import { ModuleGeneratorRuntimeCustomScalars } from '../../7_customScalars/RuntimeIndexCustomScalars.js' -import type { Config } from '../config.js' -import { createModuleGenerator } from '../helpers/moduleGenerator.js' -import { ModuleGeneratorData } from './Data.js' -import { ModuleGeneratorScalar } from './Scalar.js' -import { ModuleGeneratorSchemaIndex } from './SchemaIndex.js' - -const identifiers = { - $customScalarsIndex: `$customScalarsIndex`, -} - -export const ModuleGeneratorSchemaRuntime = createModuleGenerator( - `SchemaRuntime`, - ({ config, code }) => { - code(`/* eslint-disable */\n`) - code( - ` - import * as $ from '${config.paths.imports.grafflePackage.schema}' - import * as Data from './${ModuleGeneratorData.name}.js' - import * as $Scalar from './${ModuleGeneratorScalar.name}.js' - import type { Index } from './${ModuleGeneratorSchemaIndex.name}.js' - import { $index as ${identifiers.$customScalarsIndex} } from './${ModuleGeneratorRuntimeCustomScalars.name}.js' - `, - ) - - code( - `export const $defaultSchemaUrl = ${ - config.options.defaultSchemaUrl ? `new URL("${config.options.defaultSchemaUrl.href}")` : `undefined` - }`, - ) - - code( - config.schema.typeMapByKind.GraphQLEnumType.map(type => enum$(config, type)).join(`\n`), - config.schema.typeMapByKind.GraphQLInputObjectType.map(type => inputObject(config, type)).join(`\n`), - config.schema.typeMapByKind.GraphQLObjectType.map(type => object(config, type)).join(`\n`), - config.schema.typeMapByKind.GraphQLUnionType.map(type => union(config, type)).join(`\n`), - config.schema.typeMapByKind.GraphQLInterfaceType.map(type => interface$(config, type)).join(`\n`), - config.schema.typeMapByKind.GraphQLRootType.map(type => object(config, type)).join(`\n`), - ) - - code( - index(config), - ) - - return code - }, -) - -const index = (config: Config) => { - const rootTypesPresence = { - Query: Grafaid.Schema.KindMap.hasQuery(config.schema.typeMapByKind), - Mutation: Grafaid.Schema.KindMap.hasMutation(config.schema.typeMapByKind), - Subscription: Grafaid.Schema.KindMap.hasSubscription(config.schema.typeMapByKind), - } - // todo input objects for decode/encode input object fields - const unions = config.schema.typeMapByKind.GraphQLUnionType.map(type => type.name).join(`,\n`) - const objects = config.schema.typeMapByKind.GraphQLObjectType.map(type => type.name).join(`,\n`) - const interfaces = config.schema.typeMapByKind.GraphQLInterfaceType.map(type => type.name).join(`,\n`) - const roots = config.schema.typeMapByKind.GraphQLRootType.map(type => type.name).join(`,\n`) - const enums = config.schema.typeMapByKind.GraphQLEnumType.map(type => type.name).join(`,\n`) - const allTypes = [ - roots, - unions, - objects, - interfaces, - enums, - ].filter(_ => _).join(`,\n`) - - return ` - export const $Index: Index = { - name: Data.Name, - RootTypesPresent: [${ - config.schema.typeMapByKind.GraphQLRootType.map((_) => Code.string(_.name)).join(`, `) - }] as const, - RootUnion: undefined as any, // Type level only. - Root: { - Query ${rootTypesPresence.Query ? `` : `:null`} , - Mutation ${rootTypesPresence.Mutation ? `` : `:null`}, - Subscription ${rootTypesPresence.Subscription ? `` : `:null`} - }, - allTypes: { - ${allTypes} - }, - objects: { - ${objects} - }, - unions: { - ${unions} - }, - interfaces: { - ${interfaces} - }, - customScalars: { - input: ${identifiers.$customScalarsIndex}, - }, - error: { - objects: { - ${config.schema.error.objects.map(type => type.name).join(`,\n`)} - }, - objectsTypename: { - ${config.schema.error.objects.map(_ => `${_.name}: { __typename: "${_.name}" }`).join(`,\n`)} - }, - rootResultFields: { - ${!Grafaid.Schema.KindMap.hasQuery(config.schema.typeMapByKind) ? `Query: {},` : ``} - ${!Grafaid.Schema.KindMap.hasMutation(config.schema.typeMapByKind) ? `Mutation: {},` : ``} - ${!Grafaid.Schema.KindMap.hasSubscription(config.schema.typeMapByKind) ? `Subscription: {},` : ``} - ${ - Object.values(config.schema.typeMapByKind.GraphQLRootType).map((rootType) => { - const resultFields = Object.values(rootType.getFields()).filter((field) => { - const type = getNamedType(field.type) - return isUnionType(type) - && type.getTypes().some(_ => config.schema.error.objects.some(__ => __.name === _.name)) - }).map((field) => field.name) - - return `${rootType.name}: {\n${resultFields.map(_ => `${_}: "${_}" as const`).join(`,\n`)} }` - }).join(`,\n`) - } - } - } - } - ` -} - -const commentTsIgnoreCircDep = - `// @ts-ignore - circular types cannot infer. Ignore in case there are any. This comment is always added, it does not indicate if this particular type could infer or not.` - -const union = (_config: Config, type: GraphQLUnionType) => { - // todo probably need thunks here - const members = type.getTypes().map(t => t.name).join(`, `) - return ` - ${commentTsIgnoreCircDep} - export const ${type.name} = $.Union(\`${type.name}\`, [${members}])\n` -} - -const interface$ = (config: Config, type: GraphQLInterfaceType) => { - // todo probably need thunks here - const implementors = config.schema.typeMapByKind.GraphQLObjectType.filter(_ => - _.getInterfaces().filter(_ => _.name === type.name).length > 0 - ).map(_ => _.name).join(`,`) - const fields = Object.values(type.getFields()).map((field) => { - // todo test case for this directive being present - const maybeCommentTsIgnoreCircDep = isScalarTypeDirectOrNested(field.type) ? `` : commentTsIgnoreCircDep + `\n` - return `${maybeCommentTsIgnoreCircDep}${field.name}: ${outputField(config, field)}` - }).join(`,\n`) - 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}])` -} - -const object = (config: Config, type: GraphQLObjectType) => { - const fields = Object.values(type.getFields()).map((field) => { - // todo test case for this directive being present - const maybeCommentTsIgnoreCircDep = isScalarTypeDirectOrNested(field.type) ? `` : commentTsIgnoreCircDep + `\n` - return `${maybeCommentTsIgnoreCircDep}${field.name}: ${outputField(config, field)}` - }).join(`,\n`) - return ` - ${commentTsIgnoreCircDep} - export const ${type.name} = $.Object$(\`${type.name}\`, { - ${fields} - }) - ` -} - -const inputObject = (config: Config, type: GraphQLInputObjectType) => { - const isFieldsAllNullable = Grafaid.Schema.isAllInputObjectFieldsNullable(type) - const fields = Object.values(type.getFields()).map((field) => `${field.name}: ${inputField(config, field)}`).join( - `,\n`, - ) - return ` - export const ${type.name} = $.InputObject(\`${type.name}\`, { - ${fields} - }, ${Code.boolean(isFieldsAllNullable)}) - ` -} - -const inputField = (config: Config, field: GraphQLInputField): string => { - const type = buildType(`input`, config, field.type) - const isNeedThunk = isInputObjectType(getNamedType(field.type)) - return `$.Input.Field(${isNeedThunk ? `() => ${type}` : type})` -} - -const outputField = (config: Config, field: AnyGraphQLOutputField): string => { - const type = buildType(`output`, config, field.type) - return field.args.length > 0 - ? `$.field(${Code.string(field.name)}, ${type}, ${renderArgs(config, field.args)})` - : `$.field(${Code.string(field.name)}, ${type})` -} - -const renderArgs = (config: Config, args: readonly GraphQLArgument[]) => { - const isFieldsAllNullable = Grafaid.Schema.Args.isAllArgsNullable(args) - return `$.Args({${args.map(arg => renderArg(config, arg)).join(`, `)}}, ${Code.boolean(isFieldsAllNullable)})` -} - -const renderArg = (config: Config, arg: GraphQLArgument) => { - const type = buildType(`input`, config, arg.type) - return `${arg.name}: $.Input.Field(${type})` -} - -const scalar = (_config: Config, type: GraphQLScalarType) => { - return `$Scalar.${type.name}` -} - -const dispatchNamedType = (config: Config, type: AnyClass) => { - if (isScalarType(type)) return scalar(config, type) - if (isEnumType(type)) return type.name - if (isObjectType(type)) return thunk(type.name) - if (isInterfaceType(type)) return thunk(type.name) - if (isUnionType(type)) return thunk(type.name) - if (isInputObjectType(type)) return type.name - - throw new Error(`Unhandled type: ${String(type)}`) -} - -const thunk = (code: string) => `() => ${code}` - -const buildType = (direction: 'input' | 'output', config: Config, node: AnyClass) => { - const ns = direction === `input` ? `Input` : `Output` - const nullable = isNullableType(node) - const nodeInner = getNullableType(node) - - if (isNamedType(nodeInner)) { - const namedTypeReference = dispatchNamedType(config, nodeInner) - const namedTypeCode = namedTypeReference - return nullable - ? `$.${ns}.Nullable(${namedTypeCode})` - : namedTypeCode - } - - if (isListType(nodeInner)) { - const fieldType = `$.${ns}.List(${buildType(direction, config, nodeInner.ofType)})` as any as string - return nullable - ? `$.${ns}.Nullable(${fieldType})` - : fieldType - } - - throw new Error(`Unhandled type: ${String(node)}`) -} - -const isScalarTypeDirectOrNested = (type: GraphQLOutputType): boolean => { - return type instanceof GraphQLScalarType - || type instanceof GraphQLNonNull && isScalarTypeDirectOrNested(type.ofType) - || type instanceof GraphQLList && isScalarTypeDirectOrNested(type.ofType) -} diff --git a/src/layers/4_generator/generators/SelectionSets.ts b/src/layers/4_generator/generators/SelectionSets.ts index c1ace451f..427749de2 100644 --- a/src/layers/4_generator/generators/SelectionSets.ts +++ b/src/layers/4_generator/generators/SelectionSets.ts @@ -1,31 +1,8 @@ // todo: generate in JSDoc how the feature maps to GQL syntax. // todo: on union fields, JSDoc that mentions the syntax `on*` -import type { - GraphQLEnumType, - GraphQLInputObjectType, - GraphQLInterfaceType, - GraphQLNamedType, - GraphQLUnionType, -} from 'graphql' -import { - getNullableType, - type GraphQLArgument, - type GraphQLField, - type GraphQLInputField, - type GraphQLObjectType, - type GraphQLType, - isEnumType, -} from 'graphql' -import { getNamedType, isNullableType, isScalarType } from 'graphql' import { Code } from '../../../lib/Code.js' import { Grafaid } from '../../../lib/grafaid/__.js' -import { - getTypeNameAndKind, - Nodes, - type StandardScalarTypeNames, - StandardScalarTypeTypeScriptMapping, -} from '../../../lib/grafaid/graphql.js' import { analyzeArgsNullability } from '../../../lib/grafaid/schema/args.js' import { RootTypeName } from '../../../lib/grafaid/schema/schema.js' import { Select } from '../../2_Select/__.js' @@ -69,7 +46,7 @@ export const ModuleGeneratorSelectionSets = createModuleGenerator( ].filter(_ => _.length > 0) typesToRender.forEach((nodes) => { - const kind = Grafaid.getTypeKind(nodes[0]!) + const kind = Grafaid.Schema.getTypeKind(nodes[0]!) code(title1(`${kind} Types`)) code() @@ -93,7 +70,7 @@ export const ModuleGeneratorSelectionSets = createModuleGenerator( }, ) -const renderRefDefs = createCodeGenerator<{ nodes: GraphQLNamedType[] }>( +const renderRefDefs = createCodeGenerator<{ nodes: Grafaid.Schema.NamedTypes[] }>( ({ nodes, code }) => { const refDefsRendered = nodes.map(node => `export type _${renderName(node)} = ${renderName(node)}`).join(`\n`) const namespaceRendered = ` @@ -106,7 +83,7 @@ const renderRefDefs = createCodeGenerator<{ nodes: GraphQLNamedType[] }>( }, ) -const renderUnion = createCodeGenerator<{ node: GraphQLUnionType }>( +const renderUnion = createCodeGenerator<{ node: Grafaid.Schema.UnionType }>( ({ config, node, code }) => { const doc = renderDocumentation(config, node) code(doc) @@ -130,7 +107,7 @@ const renderUnion = createCodeGenerator<{ node: GraphQLUnionType }>( }, ) -const renderEnum = createCodeGenerator<{ node: GraphQLEnumType }>( +const renderEnum = createCodeGenerator<{ node: Grafaid.Schema.EnumType }>( ({ config, node, code }) => { const doc = renderDocumentation(config, node) code(doc) @@ -140,7 +117,7 @@ const renderEnum = createCodeGenerator<{ node: GraphQLEnumType }>( }, ) -const renderInputObject = createCodeGenerator<{ node: GraphQLInputObjectType }>( +const renderInputObject = createCodeGenerator<{ node: Grafaid.Schema.InputObjectType }>( ({ config, node, code }) => { const doc = renderDocumentation(config, node) code(doc) @@ -154,13 +131,13 @@ const renderInputObject = createCodeGenerator<{ node: GraphQLInputObjectType }>( }, ) -const renderInterface = createCodeGenerator<{ node: GraphQLInterfaceType }>( +const renderInterface = createCodeGenerator<{ node: Grafaid.Schema.InterfaceType }>( ({ config, node, code }) => { const fields = Object.values(node.getFields()) const fieldsRendered = fields.map(field => { return Helpers.outputField(field.name, `${renderName(node)}.${renderName(field)}`) }).join(`\n`) - const implementorTypes = Nodes.$Schema.KindMap.getInterfaceImplementors(config.schema.typeMapByKind, node) + const implementorTypes = Grafaid.Schema.KindMap.getInterfaceImplementors(config.schema.typeMapByKind, node) const onTypesRendered = implementorTypes.map(type => Helpers.outputField(`${Select.InlineFragment.typeConditionPRefix}${type.name}`, renderName(type)) ).join( @@ -198,7 +175,7 @@ const renderInterface = createCodeGenerator<{ node: GraphQLInterfaceType }>( }, ) -const renderObject = createCodeGenerator<{ node: GraphQLObjectType }>( +const renderObject = createCodeGenerator<{ node: Grafaid.Schema.ObjectType }>( ({ config, node, code }) => { const fields = Object.values(node.getFields()) @@ -209,7 +186,7 @@ const renderObject = createCodeGenerator<{ node: GraphQLObjectType }>( code() const propertiesRendered = fields.map(field => { - const nodeWhat = getTypeNameAndKind(getNamedType(field.type)) + const nodeWhat = Grafaid.getTypeNameAndKind(Grafaid.Schema.getNamedType(field.type)) const type = nodeWhat.kind === `Scalar` ? `\`${nodeWhat.name}\` (a \`Scalar\`)` : nodeWhat.kind const doc = Code.TSDoc(` Select the \`${field.name}\` field on the \`${node.name}\` object. Its type is ${type}. @@ -262,16 +239,16 @@ const kindRenderLookup = { GraphQLUnionType: renderUnion, } -const renderField = createCodeGenerator<{ field: GraphQLField }>( +const renderField = createCodeGenerator<{ field: Grafaid.Schema.Field }>( ({ config, field, code }) => { - const namedType = getNamedType(field.type) + const namedType = Grafaid.Schema.getNamedType(field.type) const nameRendered = renderName(field) // code() // code(`// -- .${nameRendered} --`) // code() - if (isScalarType(namedType) || isEnumType(namedType)) { + if (Grafaid.Schema.isScalarType(namedType) || Grafaid.Schema.isEnumType(namedType)) { const argsAnalysis = analyzeArgsNullability(field.args) const argFieldsRendered = renderArguments({ config, field }) const argsRendered = renderArgumentsKey({ @@ -322,7 +299,7 @@ const renderField = createCodeGenerator<{ field: GraphQLField }>( }, ) -const renderArgumentsKey = createCodeGenerator<{ field: GraphQLField; argFieldsRendered: string }>( +const renderArgumentsKey = createCodeGenerator<{ field: Grafaid.Schema.Field; argFieldsRendered: string }>( ({ field, code, argFieldsRendered }) => { const argsAnalysis = analyzeArgsNullability(field.args) @@ -346,7 +323,7 @@ const renderArgumentsKey = createCodeGenerator<{ field: GraphQLField; }, ) -const renderArguments = createCodeGenerator<{ field: GraphQLField }>(({ config, field, code }) => { +const renderArguments = createCodeGenerator<{ field: Grafaid.Schema.Field }>(({ config, field, code }) => { const argFieldsRendered = field.args.map(arg => renderArgumentLike({ config, arg })).join(`\n`) if (argFieldsRendered) { code(`{\n${argFieldsRendered}\n}`) @@ -354,9 +331,12 @@ const renderArguments = createCodeGenerator<{ field: GraphQLField }>(( } }) -const renderArgumentLike = createCodeGenerator<{ arg: GraphQLArgument | GraphQLInputField }>( +const renderArgumentLike = createCodeGenerator<{ arg: Grafaid.Schema.Argument | Grafaid.Schema.InputField }>( ({ config, arg, code }) => { - const enumKeyPrefix = isEnumType(Nodes.getNamedType(arg.type)) ? Select.Arguments.enumKeyPrefix : `` + // todo do not import whole of graphql package here. Just import getNamedType. + const enumKeyPrefix = Grafaid.Schema.isEnumType(Grafaid.Schema.getNamedType(arg.type)) + ? Select.Arguments.enumKeyPrefix + : `` const typeRendered = renderArgType(arg.type) const doc = getDocumentation(config, arg) code(doc) @@ -364,22 +344,23 @@ const renderArgumentLike = createCodeGenerator<{ arg: GraphQLArgument | GraphQLI }, ) -const renderArgType = (type: Nodes.$Schema.GraphQLType): string => { - const sansNullabilityType = Nodes.$Schema.getNullableType(type) +const renderArgType = (type: Grafaid.Schema.InputTypes): string => { + const sansNullabilityType = Grafaid.Schema.getNullableType(type) - const nullableRendered = Nodes.$Schema.isNullableType(type) ? `| undefined | null` : `` + const nullableRendered = Grafaid.Schema.isNullableType(type) ? `| undefined | null` : `` - if (Nodes.$Schema.isListType(sansNullabilityType)) { - const innerType = getNullableType(sansNullabilityType.ofType) + if (Grafaid.Schema.isListType(sansNullabilityType)) { + const innerType = Grafaid.Schema.getNullableType(sansNullabilityType.ofType) return `Array<${renderArgType(innerType)}> ${nullableRendered}` } - if (Nodes.$Schema.isScalarType(sansNullabilityType)) { - if (Nodes.$Schema.isScalarTypeCustom(sansNullabilityType)) { + if (Grafaid.Schema.isScalarType(sansNullabilityType)) { + if (Grafaid.Schema.isScalarTypeCustom(sansNullabilityType)) { const scalarTypeRendered = `$Scalar.${sansNullabilityType.name}Decoded` return `${scalarTypeRendered} ${nullableRendered}` } - const scalarTypeRendered = StandardScalarTypeTypeScriptMapping[sansNullabilityType.name as StandardScalarTypeNames] + const scalarTypeRendered = + Grafaid.StandardScalarTypeTypeScriptMapping[sansNullabilityType.name as Grafaid.StandardScalarTypeNames] return `${scalarTypeRendered} ${nullableRendered}` } @@ -387,8 +368,8 @@ const renderArgType = (type: Nodes.$Schema.GraphQLType): string => { } namespace Helpers { - export const propOpt = (type: GraphQLType) => { - return isNullableType(type) ? `?` : `` + export const propOpt = (type: Grafaid.Schema.Types) => { + return Grafaid.Schema.isNullableType(type) ? `?` : `` } export const maybeList = (type: string) => { return `${type} | Array<${type}>` @@ -437,12 +418,16 @@ namespace Helpers { const fragmentInlineNameSuffix = `$FragmentInline` - export const fragmentInlineInterface = (node: GraphQLObjectType | GraphQLUnionType | GraphQLInterfaceType) => { + export const fragmentInlineInterface = ( + node: Grafaid.Schema.ObjectType | Grafaid.Schema.UnionType | Grafaid.Schema.InterfaceType, + ) => { const name = `${renderName(node)}${fragmentInlineNameSuffix}` return `export interface ${name} extends ${renderName(node)}, $Select.Directive.$Groups.InlineFragment.Fields {}` } - export const fragmentInlineField = (node: GraphQLObjectType | GraphQLUnionType | GraphQLInterfaceType) => { + export const fragmentInlineField = ( + node: Grafaid.Schema.ObjectType | Grafaid.Schema.UnionType | Grafaid.Schema.InterfaceType, + ) => { const doc = Code.TSDoc(` Inline fragments for field groups. diff --git a/src/layers/4_generator/globalRegistry.ts b/src/layers/4_generator/globalRegistry.ts index 49439c445..cf52573bb 100644 --- a/src/layers/4_generator/globalRegistry.ts +++ b/src/layers/4_generator/globalRegistry.ts @@ -7,7 +7,7 @@ declare global { export namespace GraffleGlobalTypes { interface Schemas {} // Use this is for manual internal type testing. - // interface SchemasAlwaysEmpty {} + interface SchemasAlwaysEmpty {} } } diff --git a/src/layers/4_generator/helpers/render.ts b/src/layers/4_generator/helpers/render.ts index a16516200..441e96cac 100644 --- a/src/layers/4_generator/helpers/render.ts +++ b/src/layers/4_generator/helpers/render.ts @@ -1,16 +1,10 @@ -import { type GraphQLEnumValue, type GraphQLField, type GraphQLNamedType, isEnumType } from 'graphql' import { Code } from '../../../lib/Code.js' -import { - type Describable, - getNodeDisplayName, - getTypeNameAndKind, - isDeprecatableNode, - type TypeMapKind, -} from '../../../lib/grafaid/graphql.js' +import { Grafaid } from '../../../lib/grafaid/__.js' +import { getNodeDisplayName } from '../../../lib/grafaid/graphql.js' import { borderThickFullWidth, borderThinFullWidth, centerTo } from '../../../lib/text.js' import type { Config } from '../config.js' -export const title1 = (title: string) => { +export const title1 = (title: string, subTitle?: string) => { const titleDecorated = ` // // @@ -19,7 +13,7 @@ export const title1 = (title: string) => { // // // ${borderThickFullWidth} - // ${centerTo(borderThickFullWidth, title)} + // ${centerTo(borderThickFullWidth, title)}${subTitle ? `\n// ${centerTo(borderThickFullWidth, subTitle)}` : ``} // ${borderThickFullWidth} // // @@ -31,9 +25,9 @@ export const title1 = (title: string) => { return titleDecorated } -export const typeTitle2 = (category: string) => (node: GraphQLNamedType) => { - const nameKind = getTypeNameAndKind(node) - const nameOrKind = nameKind.kind === `Scalar` ? nameKind.name : nameKind.kind +export const typeTitle2 = (category: string) => (type: Grafaid.Schema.NamedTypes) => { + const typeKind = Grafaid.getTypeNameAndKind(type) + const nameOrKind = typeKind.kind === `Scalar` ? typeKind.name : typeKind.kind const typeLabel = nameOrKind const title = ` // @@ -43,7 +37,7 @@ export const typeTitle2 = (category: string) => (node: GraphQLNamedType) => { // ${category.toUpperCase()} // ${typeLabel.toUpperCase()} // ${borderThinFullWidth} - // ${centerTo(borderThinFullWidth, node.name)} + // ${centerTo(borderThinFullWidth, type.name)} // ${borderThinFullWidth} // // @@ -54,9 +48,9 @@ export const typeTitle2 = (category: string) => (node: GraphQLNamedType) => { export const typeTitle2SelectionSet = typeTitle2(`GRAPHQL SELECTION SET`) -export const typeTitle = (config: Config, typeName: TypeMapKind) => { - const hasItems = config.schema.typeMapByKind[`GraphQL${typeName}Type`].length > 0 - const title = `${typeName} Types` +export const typeTitle = (config: Config, typeKind: Grafaid.Schema.NamedTypeKind) => { + const hasItems = config.schema.typeMapByKind[`GraphQL${typeKind}Type`].length > 0 + const title = `${typeKind} Types` const titleDecorated = `// ${title}\n// ${`-`.repeat(title.length)}\n` if (hasItems) { return titleDecorated @@ -65,20 +59,21 @@ export const typeTitle = (config: Config, typeName: TypeMapKind) => { } } -const defaultDescription = (node: Describable) => `There is no documentation for this ${getNodeDisplayName(node)}.` +const defaultDescription = (node: Grafaid.Schema.DescribableTypes) => + `There is no documentation for this ${getNodeDisplayName(node)}.` -export const renderDocumentation = (config: Config, node: Describable) => { +export const renderDocumentation = (config: Config, node: Grafaid.Schema.DescribableTypes) => { return Code.TSDoc(getDocumentation(config, node)) } -export const getDocumentation = (config: Config, node: Describable) => { +export const getDocumentation = (config: Config, node: Grafaid.Schema.DescribableTypes) => { const generalDescription = node.description ?? (config.options.TSDoc.noDocPolicy === `message` ? defaultDescription(node) : null) - const deprecationDescription = isDeprecatableNode(node) && node.deprecationReason + const deprecationDescription = Grafaid.Schema.isDeprecatableNode(node) && node.deprecationReason ? `@deprecated ${node.deprecationReason}` : null - const enumMemberDescriptions: string[] = isEnumType(node) + const enumMemberDescriptions: string[] = Grafaid.Schema.isEnumType(node) ? node .getValues() .map((_) => { @@ -96,7 +91,7 @@ export const getDocumentation = (config: Config, node: Describable) => { .join(` `) return [_, content] as const }) - .filter((_): _ is [GraphQLEnumValue, string] => _ !== null) + .filter((_): _ is [Grafaid.Schema.EnumValue, string] => _ !== null) .map(([node, description]) => { const content = `"${node.name}" - ${description}` return content @@ -123,7 +118,7 @@ export const getDocumentation = (config: Config, node: Describable) => { * this guards against GraphQL type or property names that * would be illegal in TypeScript such as `namespace` or `interface`. */ -export const renderName = (type: GraphQLNamedType | GraphQLField) => { +export const renderName = (type: Grafaid.Schema.NamedTypes | Grafaid.Schema.Field) => { if (Code.reservedTypeScriptInterfaceNames.includes(type.name as any)) { return `$${type.name}` } diff --git a/src/layers/5_request/core.ts b/src/layers/5_request/core.ts index d2c733b48..03ce88e88 100644 --- a/src/layers/5_request/core.ts +++ b/src/layers/5_request/core.ts @@ -1,10 +1,9 @@ -import { type ExecutionResult, parse } from 'graphql' +import { type ExecutionResult } from 'graphql' import { Anyware } from '../../lib/anyware/__.js' import type { Grafaid } from '../../lib/grafaid/__.js' -import { OperationTypeToAccessKind, print } from '../../lib/grafaid/document.js' +import { getOperationDefinition, OperationTypeToAccessKind, print } from '../../lib/grafaid/document.js' import { execute } from '../../lib/grafaid/execute.js' -import type { Nodes } from '../../lib/grafaid/graphql.js' -import { parseOperationType, type Variables } from '../../lib/grafaid/graphql.js' +import { operationTypeToRootType } from '../../lib/grafaid/graphql.js' import { getRequestEncodeSearchParameters, getRequestHeadersRec, @@ -12,9 +11,8 @@ import { postRequestEncodeBody, postRequestHeadersRec, } from '../../lib/grafaid/http/http.js' -import type { TypedDocument } from '../../lib/grafaid/typed-document/__.js' import { mergeRequestInit, searchParamsAppendAll } from '../../lib/http.js' -import { casesExhausted, isString, throwNull } from '../../lib/prelude.js' +import { casesExhausted, isString } from '../../lib/prelude.js' import { SelectionSetGraphqlMapper } from '../3_SelectGraphQLMapper/__.js' import type { GraffleExecutionResultVar } from '../6_client/handleOutput.js' import type { Config } from '../6_client/Settings/Config.js' @@ -26,9 +24,34 @@ import { hookNamesOrderedBySequence, type HookSequence, } from './hooks.js' -import { injectTypenameOnRootResultFields } from './schemaErrors.js' import { Transport } from './types.js' +export const graffleMappedToRequest = ( + { document, operationsVariables }: SelectionSetGraphqlMapper.Encoded, + operationName?: string, +): Grafaid.RequestAnalyzedDocumentNodeInput => { + // We get back variables for every operation in the Graffle document. + // However, we only need the variables for the operation that was selected to be executed. + // If there was NO operation name provided then we assume that the first operation in the document is the one that should be executed. + // If there are MULTIPLE operations in the Graffle document AND the user has supplied an invalid operation name (either none or given matches none) + // then what happens here is the variables from one operation can be mixed into another operation. + // This shouldn't matter because such a state would be rejected by the server since it wouldn't know what operation to execute. + const variables_ = operationName + ? operationsVariables[operationName] + : Object.values(operationsVariables)[0] + + const operation_ = getOperationDefinition({ query: document, operationName }) + if (!operation_) throw new Error(`Impossible.`) + + return { + rootType: operationTypeToRootType[operation_.operation], + operationName, + operation: operation_, + query: document, + variables: variables_, + } +} + 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. @@ -41,48 +64,22 @@ export const anyware = Anyware.create({ hookNamesOrderedBySequence, hooks: { encode: ({ input }) => { - let document: string | TypedDocument.TypedDocument - - // todo: the other case where we're going to need to parse document is for custom scalar support of raw - const isWillInjectTypename = input.state.config.output.errors.schema && input.schemaIndex + let request: Grafaid.RequestAnalyzedInput - if (isWillInjectTypename) { - document = input.interfaceType === `raw` - ? isString(input.request.query) - ? parse(input.request.query) - : input.request.query as Nodes.DocumentNode - : SelectionSetGraphqlMapper.toGraphQL({ - document: input.request.document, - customScalarsIndex: input.schemaIndex!.customScalars.input, - }) - - injectTypenameOnRootResultFields({ - document, - operationName: input.request.operationName, - schema: input.schemaIndex!, - }) + if (input.interfaceType === `raw`) { + request = input.request } else { - document = input.interfaceType === `raw` - ? input.request.query - : SelectionSetGraphqlMapper.toGraphQL({ - // schema: input.schemaIndex!, - document: input.request.document, - customScalarsIndex: input.schemaIndex!.customScalars.input, - }) + request = graffleMappedToRequest( + SelectionSetGraphqlMapper.toGraphQL(input.request.document, { + sddm: input.state.config.schemaMap, + }), + input.request.operationName, + ) } - const variables: Variables | undefined = input.interfaceType === `raw` - ? input.request.variables - // todo turn inputs into variables - : undefined - return { ...input, - request: { - query: document, - variables, - operationName: input.request.operationName, - }, + request, } }, pack: { @@ -92,7 +89,8 @@ export const anyware = Anyware.create({ }, run: ({ input, slots }) => { const graphqlRequest: Grafaid.HTTP.RequestConfig = { - ...input.request, + operationName: input.request.operationName, + variables: input.request.variables, query: print(input.request.query), } @@ -107,12 +105,10 @@ export const anyware = Anyware.create({ case `http`: { if (input.state.config.transport.type !== Transport.http) throw new Error(`transport type is not http`) + const operationType = isString(input.request.operation) + ? input.request.operation + : input.request.operation.operation const methodMode = input.state.config.transport.config.methodMode - // todo parsing here can be optimized. - // 1. If using TS interface then work with initially submitted structured data to already know the operation type - // 2. Maybe: Memoize over request.{ operationName, query } - // 3. Maybe: Keep a cache of parsed request.{ query } - const operationType = throwNull(parseOperationType(input.request)) // todo better feedback here than throwNull const requestMethod = methodMode === MethodMode.post ? `post` : methodMode === MethodMode.getReads // eslint-disable-line diff --git a/src/layers/5_request/hooks.ts b/src/layers/5_request/hooks.ts index 48fd85eb2..f14f9f368 100644 --- a/src/layers/5_request/hooks.ts +++ b/src/layers/5_request/hooks.ts @@ -3,18 +3,13 @@ import type { Grafaid } from '../../lib/grafaid/__.js' import type { getRequestEncodeSearchParameters, postRequestEncodeBody } from '../../lib/grafaid/http/http.js' import type { httpMethodGet, httpMethodPost } from '../../lib/http.js' import type { Select } from '../2_Select/__.js' -import type { SchemaIndex } from '../4_generator/generators/SchemaIndex.js' import type { State } from '../6_client/fluent.js' import type { Config } from '../6_client/Settings/Config.js' import type { MethodModeGetReads, MethodModePost } from '../6_client/transportHttp/request.js' import type { InterfaceRaw, InterfaceTyped, TransportHttp, TransportMemory } from './types.js' interface HookInputBase { - schemaIndex: SchemaIndex | null state: State - // todo remove these - document?: Select.Document.DocumentNormalized - operationName?: string } type InterfaceInput = @@ -45,12 +40,15 @@ type TransportInput<$Config extends Config, $HttpProperties = {}, $MemoryPropert : never ) +// --------------------------- + export type HookDefEncode<$Config extends Config> = { input: & HookInputBase & InterfaceInput< { request: { document: Select.Document.DocumentNormalized; operationName?: string } }, - { request: Grafaid.RequestInput } + // { request: Grafaid.RequestInput } + { request: Grafaid.RequestAnalyzedInput } > & TransportInput<$Config> } @@ -64,7 +62,7 @@ export type HookDefPack<$Config extends Config> = { // todo why is headers here but not other http request properties? { headers?: HeadersInit } > - & { request: Grafaid.RequestInput } + & { request: Grafaid.RequestAnalyzedInput } slots: { /** * When request will be sent using GET this slot is called to create the value that will be used for the HTTP Search Parameters. diff --git a/src/layers/5_request/schemaErrors.test.ts b/src/layers/5_request/schemaErrors.test.ts deleted file mode 100644 index b43d6cec1..000000000 --- a/src/layers/5_request/schemaErrors.test.ts +++ /dev/null @@ -1,50 +0,0 @@ -import { parse } from 'graphql' -import { expect } from 'vitest' -import { test } from '../../../tests/_/helpers.js' -import { $Index as schema } from '../../../tests/_/schemas/kitchen-sink/graffle/modules/SchemaRuntime.js' -import type { Query } from '../../../tests/_/schemas/kitchen-sink/graffle/modules/SelectionSets.js' -import { Select } from '../2_Select/__.js' -import { SelectionSetGraphqlMapper } from '../3_SelectGraphQLMapper/__.js' -import { Throws } from '../7_extensions/Throws/Throws.js' -import { injectTypenameOnRootResultFields } from './schemaErrors.js' - -type CasesQuery = [description: string, queryWithoutTypename: Query, queryWithTypename: Query] - -// todo symmetrical type tests for these cases -// dprint-ignore -test.each([ - [`one result field`, { resultNonNull: { } }, { resultNonNull: { __typename: true } }], - [`two result fields`, { resultNonNull: { }, result: { $: { $case: `ErrorOne` }}}, { resultNonNull: { __typename: true }, result: { $: { $case: `ErrorOne` }, __typename: true } }], - [`no result fields`, { id: true, object: { id: true } }, { id: true, object: { id: true }}], - [`__typename in fragment`, { resultNonNull: { ___: { __typename: true }}}, { resultNonNull: { ___: { __typename: true }, __typename: true } }], - [`root field in fragment`, { ___: { resultNonNull: {} } }, { ___: { resultNonNull: { __typename: true }}}], - [`root field in fragment in alias`, { ___: { resultNonNull: [`x`, {}] } }, { ___: { resultNonNull: [`x`, { __typename: true }] }}], - [`root field alias `, { resultNonNull: [`x`, {}] }, { resultNonNull: [`x`, { __typename: true }] }], -])(`Query %s`, (_, queryWithoutTypenameInput, queryWithTypenameInput) => { - const documentWithTypename = SelectionSetGraphqlMapper.toGraphQL({ - document: Select.Document.normalizeOrThrow({ query: { x: queryWithTypenameInput as any } }) - }) - const documentWithoutTypename = SelectionSetGraphqlMapper.toGraphQL({ - document: Select.Document.normalizeOrThrow({ query: { x: queryWithoutTypenameInput as any } }) - }) - injectTypenameOnRootResultFields({ - document: documentWithoutTypename, - schema, - }) - expect(documentWithoutTypename).toMatchObject(documentWithTypename) -}) - -// dprint-ignore -test(`type name field injection works for raw string requests`, async ({ kitchenSink }) => { - // todo it would be nicer to move the extension use to the fixture but how would we get the static type for that? - // This makes me think of a feature we need to have. Make it easy to get static types of the client in its various configured states. - const result = await kitchenSink.use(Throws()).throws().gql`query { resultNonNull (case: Object1) { ... on Object1 { id } } }`.send() - expect(result).toMatchObject({ resultNonNull: { __typename: `Object1`, id: `abc` } }) -}) - -test(`type name field injection works for raw document requests`, async ({ kitchenSink }) => { - const result = await kitchenSink.use(Throws()).throws().gql( - parse(`query { resultNonNull (case: Object1) { ... on Object1 { id } } }`), - ).send() - expect(result).toMatchObject({ resultNonNull: { __typename: `Object1`, id: `abc` } }) -}) diff --git a/src/layers/5_request/schemaErrors.ts b/src/layers/5_request/schemaErrors.ts index d73c0dbcd..132534799 100644 --- a/src/layers/5_request/schemaErrors.ts +++ b/src/layers/5_request/schemaErrors.ts @@ -1,32 +1,23 @@ import type { Grafaid } from '../../lib/grafaid/__.js' -import { Nodes, operationTypeNameToRootTypeName } from '../../lib/grafaid/graphql.js' -import type { SchemaIndex } from '../4_generator/generators/SchemaIndex.js' +import { Nodes } from '../../lib/grafaid/graphql.js' +import type { SchemaDrivenDataMap } from '../7_extensions/CustomScalars/schemaDrivenDataMap/types.js' export const injectTypenameOnRootResultFields = ( - { document, operationName, schema }: { - operationName?: string | undefined - schema: SchemaIndex - document: Nodes.DocumentNode + { request, sddm }: { + sddm: SchemaDrivenDataMap + request: Grafaid.RequestAnalyzedDocumentNodeInput }, ): void => { - const operationDefinition = document.definitions.find(_ => - _.kind === Nodes.Kind.OPERATION_DEFINITION && (operationName ? _.name?.value === operationName : true) - ) as Nodes.OperationDefinitionNode | undefined - - if (!operationDefinition) { - throw new Error(`Operation not found`) - } - injectTypenameOnRootResultFields_({ - rootTypeName: operationTypeNameToRootTypeName[operationDefinition.operation], - schema, - selectionSet: operationDefinition.selectionSet, + sddm, + rootTypeName: request.rootType, + selectionSet: request.operation.selectionSet, }) } const injectTypenameOnRootResultFields_ = ( - { selectionSet, schema, rootTypeName }: { - schema: SchemaIndex + { selectionSet, sddm, rootTypeName }: { + sddm: SchemaDrivenDataMap rootTypeName: Grafaid.Schema.RootTypeName selectionSet: Nodes.SelectionSetNode }, @@ -34,7 +25,8 @@ const injectTypenameOnRootResultFields_ = ( for (const selection of selectionSet.selections) { switch (selection.kind) { case Nodes.Kind.FIELD: { - if (schema.error.rootResultFields[rootTypeName][selection.name.value]) { + const isResultField = Boolean(sddm.roots[rootTypeName]?.f[selection.name.value]?.r) + if (isResultField) { // @ts-expect-error selections is typed as readonly // @see https://github.com/graphql/graphql-js/discussions/4212 selection.selectionSet?.selections.push(Nodes.Field({ name: Nodes.Name({ value: `__typename` }) })) @@ -44,7 +36,7 @@ const injectTypenameOnRootResultFields_ = ( case Nodes.Kind.INLINE_FRAGMENT: { injectTypenameOnRootResultFields_({ rootTypeName, - schema, + sddm, selectionSet: selection.selectionSet, }) } diff --git a/src/layers/6_client/Settings/Config.ts b/src/layers/6_client/Settings/Config.ts index 420786c28..ea6fa3b85 100644 --- a/src/layers/6_client/Settings/Config.ts +++ b/src/layers/6_client/Settings/Config.ts @@ -5,6 +5,7 @@ import type { Select } from '../../2_Select/__.js' import type { SchemaIndex } from '../../4_generator/generators/SchemaIndex.js' import type { GlobalRegistry } from '../../4_generator/globalRegistry.js' import type { TransportHttp, TransportMemory } from '../../5_request/types.js' +import type { SchemaDrivenDataMap } from '../../7_extensions/CustomScalars/schemaDrivenDataMap/types.js' import type { ConfigGetOutputError } from '../handleOutput.js' import type { TransportHttpInput } from '../transportHttp/request.js' import type { InputStatic } from './Input.js' @@ -119,10 +120,10 @@ export type Config = { /** * The initial input that was given to derive this config. */ - initialInput: InputStatic // InputStatic + initialInput: InputStatic name: GlobalRegistry.SchemaNames output: OutputConfig - schemaIndex: SchemaIndex | null + schemaMap: SchemaDrivenDataMap | null transport: TransportConfigHttp | TransportConfigMemory } diff --git a/src/layers/6_client/Settings/Input.ts b/src/layers/6_client/Settings/Input.ts index 27ddaca12..73055289f 100644 --- a/src/layers/6_client/Settings/Input.ts +++ b/src/layers/6_client/Settings/Input.ts @@ -1,6 +1,6 @@ import type { GraphQLSchema } from 'graphql' -import type { SchemaIndex } from '../../4_generator/generators/SchemaIndex.js' import type { GlobalRegistry } from '../../4_generator/globalRegistry.js' +import type { SchemaDrivenDataMap } from '../../7_extensions/CustomScalars/schemaDrivenDataMap/types.js' import type { WithInput } from './inputIncrementable/inputIncrementable.js' export type URLInput = URL | string @@ -19,7 +19,7 @@ export type InputOutputEnvelopeLonghand = { /** * @remarks This input extends base with properties that can be filled with exports from the generated client. */ -export type InputStatic<$Schema extends GlobalRegistry.SchemaUnion> = +export type InputStatic<$Schema extends GlobalRegistry.SchemaUnion = GlobalRegistry.SchemaUnion> = & InputBase<$Schema> & { /** @@ -31,17 +31,9 @@ export type InputStatic<$Schema extends GlobalRegistry.SchemaUnion> = */ name?: $Schema['index']['name'] /** - * Used internally. - * - * When custom scalars are being used, this runtime schema is used to - * encode/decode them before/after your application sends/receives them. - * - * When using root type field methods, this runtime schema is used to assist how arguments on scalars versus objects - * are constructed into the sent GraphQL document. + * todo */ - readonly schemaIndex?: SchemaIndex | null - // todo way to hide Relay input pattern of nested input - // elideInputKey: true, + readonly schemaMap?: SchemaDrivenDataMap | null } // TODO use code generation to display diff --git a/src/layers/6_client/Settings/InputToConfig.ts b/src/layers/6_client/Settings/InputToConfig.ts index 18bad66c0..d7601871c 100644 --- a/src/layers/6_client/Settings/InputToConfig.ts +++ b/src/layers/6_client/Settings/InputToConfig.ts @@ -7,10 +7,10 @@ import { outputConfigDefault, type TransportConfigHttp, type TransportConfigMemo import type { InputOutputEnvelopeLonghand, InputStatic, URLInput } from './Input.js' // dprint-ignore -export type InputToConfig<$Input extends InputStatic> = { +export type NormalizeInput<$Input extends InputStatic> = { initialInput: $Input name: HandleName<$Input> - schemaIndex: ConfigManager.OrDefault<$Input['schemaIndex'], null> + schemaMap: ConfigManager.OrDefault<$Input['schemaMap'], null> transport: HandleTransport<$Input> output: { defaults: { @@ -38,9 +38,9 @@ export type InputToConfig<$Input extends InputStatic export const defaultSchemaName: GlobalRegistry.DefaultSchemaName = `default` -export const inputToConfig = <$Input extends InputStatic>( +export const inputToConfig = <$Input extends InputStatic>( input: $Input, -): InputToConfig<$Input> => { +): NormalizeInput<$Input> => { const outputEnvelopeLonghand: InputOutputEnvelopeLonghand | undefined = typeof input.output?.envelope === `object` ? { enabled: true, ...input.output.envelope } : typeof input.output?.envelope === `boolean` @@ -54,7 +54,7 @@ export const inputToConfig = <$Input extends InputStatic> = $Input['name'] extends string ? $Input['name'] +type HandleName<$Input extends InputStatic> = $Input['name'] extends string ? $Input['name'] : GlobalRegistry.DefaultSchemaName // dprint-ignore -type HandleTransport<$Input extends InputStatic> = +type HandleTransport<$Input extends InputStatic> = $Input['schema'] extends URLInput ? TransportConfigHttp : // When the client is generated via introspection of a URL then the schema defaults to that URL. // This is the only case when schema can be unknown from so we can assume that transport is HTTP. IsUnknown<$Input['schema']> extends true ? TransportConfigHttp : TransportConfigMemory -const handleTransport = >(input: T): HandleTransport => { +const handleTransport = (input: T): HandleTransport => { if (input.schema instanceof URL || typeof input.schema === `string`) { return { type: Transport.http, diff --git a/src/layers/6_client/Settings/client.create.config.output.test-d.ts b/src/layers/6_client/Settings/client.create.config.output.test-d.ts index 57dde711b..129016542 100644 --- a/src/layers/6_client/Settings/client.create.config.output.test-d.ts +++ b/src/layers/6_client/Settings/client.create.config.output.test-d.ts @@ -182,12 +182,13 @@ describe('.errors.schema', () => { }) describe('envelope.schema', () => { const g = G({ schema, output: { envelope: { errors: { schema: true } }, errors: { schema: 'return' } } }) - type Config = typeof g._.config - test('query.', async () => { - // todo: once we have execution result with type variable errors, then enhance this test to assert that the result errors come through in the errors field. - expectTypeOf(g.query.resultNonNull(resultFieldSelect)).resolves.toEqualTypeOf< - Envelope - >() - }) + // todo bring back: + // type Config = typeof g._.config + // test('query.', async () => { + // // todo: once we have execution result with type variable errors, then enhance this test to assert that the result errors come through in the errors field. + // expectTypeOf(g.query.resultNonNull(resultFieldSelect)).resolves.toEqualTypeOf< + // Envelope + // >() + // }) }) }) diff --git a/src/layers/6_client/Settings/inputIncrementable/inputIncrementable.ts b/src/layers/6_client/Settings/inputIncrementable/inputIncrementable.ts index 8eba5c845..ce784aceb 100644 --- a/src/layers/6_client/Settings/inputIncrementable/inputIncrementable.ts +++ b/src/layers/6_client/Settings/inputIncrementable/inputIncrementable.ts @@ -2,7 +2,7 @@ import type { GlobalRegistry } from '../../../4_generator/globalRegistry.js' import type { Transport, TransportMemory } from '../../../5_request/types.js' import type { TransportHttpInput } from '../../transportHttp/request.js' import type { Config } from '../Config.js' -import type { InputToConfig } from '../InputToConfig.js' +import type { NormalizeInput } from '../InputToConfig.js' import type { OutputInput } from './output.js' // dprint-ignore @@ -28,4 +28,4 @@ export type IncrementableInputContext = { // dprint-ignore export type AddIncrementalInput<$Config extends Config, $Input extends WithInput> = - InputToConfig<$Config['initialInput'] & $Input> + NormalizeInput<$Config['initialInput'] & $Input> diff --git a/src/layers/6_client/client.transport-http.test.ts b/src/layers/6_client/client.transport-http.test.ts index 668cff6c9..e09caa054 100644 --- a/src/layers/6_client/client.transport-http.test.ts +++ b/src/layers/6_client/client.transport-http.test.ts @@ -36,8 +36,8 @@ import type { CoreExchangeGetRequest, CoreExchangePostRequest } from '../5_reque test(`when envelope is used then response property is present even if relying on schema url default`, async () => { const service = await serveSchema({ schema: schemaPokemon }) - const atlas = Pokemon.create({ output: { envelope: true } }) - const result = await atlas.query.pokemons({ name: true }) + const pokemon = Pokemon.create({ output: { envelope: true } }) + const result = await pokemon.query.pokemons({ name: true }) await service.stop() expectTypeOf(result.response).toEqualTypeOf() }) diff --git a/src/layers/6_client/client.ts b/src/layers/6_client/client.ts index 5204bebd4..b8d13726e 100644 --- a/src/layers/6_client/client.ts +++ b/src/layers/6_client/client.ts @@ -1,8 +1,7 @@ import type { Fluent } from '../../lib/fluent/__.js' import { proxyGet } from '../../lib/prelude.js' -import type { SchemaIndex } from '../4_generator/generators/SchemaIndex.js' -import type { GlobalRegistry } from '../4_generator/globalRegistry.js' -import { CustomScalars } from '../7_customScalars/extension.js' +import { CustomScalars } from '../7_extensions/CustomScalars/CustomScalars.js' +import { SchemaErrors } from '../7_extensions/SchemaErrors/SchemaErrors.js' import { type UseFn, useProperties } from './extension/use.js' import { type ClientContext, createState, type FnParametersProperty, type StateWithoutConfig } from './fluent.js' import { type FnGql, gqlProperties } from './gql/gql.js' @@ -12,7 +11,7 @@ import { type FnRetry, retryProperties } from './properties/retry.js' import { type FnWith, withProperties } from './properties/with.js' import { type FnRequestMethods, requestMethodsProperties } from './requestMethods/requestMethods.js' import { type InputStatic } from './Settings/Input.js' -import { type InputToConfig } from './Settings/InputToConfig.js' +import { type NormalizeInput } from './Settings/InputToConfig.js' export type Client<$Context extends ClientContext> = Fluent.Materialize< Fluent.AddMany< @@ -40,19 +39,15 @@ export type IncrementWthNewConfig< > // dprint-ignore -type Create = <$Input extends InputStatic>(input: $Input) => +type Create = <$Input extends InputStatic>(input: $Input) => + // todo fixme // eslint-disable-next-line - // @ts-ignore fixme - Client<{ - config: InputToConfig<$Input>, - schemaIndex: $Input['schemaIndex'] extends SchemaIndex - ? GlobalRegistry.GetSchemaIndexOrDefault<$Input['name']> - : null - }> + // @ts-ignore + Client<{ config: NormalizeInput<$Input> }> export const create: Create = (input) => { const initialState = createState({ - extensions: [CustomScalars()], + extensions: [CustomScalars(), SchemaErrors()], retry: null, input, }) @@ -78,7 +73,7 @@ const createWithState = ( // The schema index nullability will affect more granular features within.. // So, we are going to need a different check than this one. - if (state.input.schemaIndex) { + if (state.input.schemaMap) { Object.assign(clientDirect, { ...requestMethodsProperties(state), }) diff --git a/src/layers/6_client/fluent.ts b/src/layers/6_client/fluent.ts index 377d5f291..d4a03e0e0 100644 --- a/src/layers/6_client/fluent.ts +++ b/src/layers/6_client/fluent.ts @@ -1,6 +1,5 @@ import type { Anyware } from '../../lib/anyware/__.js' import type { Fluent } from '../../lib/fluent/__.js' -import type { GlobalRegistry } from '../4_generator/globalRegistry.js' import type { RequestCore } from '../5_request/__.js' import type { Extension } from './extension/extension.js' import type { Config } from './Settings/Config.js' @@ -48,7 +47,7 @@ export const defineTerminus = (property: (state: State) => TerminusDefinitions) } export interface State { - input: InputStatic + input: InputStatic config: Config retry: Anyware.Extension2 | null extensions: Extension[] diff --git a/src/layers/6_client/gql/gql.test-d.ts b/src/layers/6_client/gql/gql.test-d.ts index a6d96077d..80ad4613a 100644 --- a/src/layers/6_client/gql/gql.test-d.ts +++ b/src/layers/6_client/gql/gql.test-d.ts @@ -4,7 +4,7 @@ import type { Grafaid } from '../../../lib/grafaid/__.js' type D = { id: 0 } -const d1 = 0 as any as Grafaid.Nodes.Typed.Node<{ id: 0 }, {}> +const d1 = 0 as any as Grafaid.Document.Typed.Node<{ id: 0 }, {}> AssertTypeOf(await g.gql(d1).send()) // @ts-expect-error - variables not allowed. @@ -14,7 +14,7 @@ await g.gql(d1).send({}) // // -const d2 = 0 as any as Grafaid.Nodes.Typed.Node<{ id: 0 }, { x?: 0 }> +const d2 = 0 as any as Grafaid.Document.Typed.Node<{ id: 0 }, { x?: 0 }> AssertTypeOf(await g.gql(d2).send()) AssertTypeOf(await g.gql(d2).send({})) @@ -27,7 +27,7 @@ await g.gql(d2).send({ filter: `wrong type` }) // // -const d3 = 0 as any as Grafaid.Nodes.Typed.Node<{ id: 0 }, { x: 0 }> +const d3 = 0 as any as Grafaid.Document.Typed.Node<{ id: 0 }, { x: 0 }> AssertTypeOf(await g.gql(d3).send({ x: 0 })) // @ts-expect-error - missing argument @@ -39,34 +39,40 @@ AssertTypeOf(await g.gql(d3).send({})) // dprint-ignore { - AssertTypeOf(await g.gql >``.send({ x: 1 })) - AssertTypeOf(await g.gql >``.send()) - AssertTypeOf(await g.gql >``.send({ x: 1 })) - AssertTypeOf(await g.gql >``.send()) - AssertTypeOf(await g.gql>``.send()) - AssertTypeOf(await g.gql>``.send({ x: 1 })) - AssertTypeOf(await g.gql>``.send(`abc`, { x: 1 })) + AssertTypeOf(await g.gql >``.send({ x: 1 })) + AssertTypeOf(await g.gql >``.send()) + AssertTypeOf(await g.gql >``.send({ x: 1 })) + AssertTypeOf(await g.gql >``.send()) + AssertTypeOf(await g.gql>``.send()) + AssertTypeOf(await g.gql>``.send({ x: 1 })) + AssertTypeOf(await g.gql>``.send(`abc`, { x: 1 })) // @ts-expect-error - wrong argument type - await g.gql >``.send({ x: 2 }) + await g.gql >``.send({ x: 2 }) - AssertTypeOf(await g.gql >``.send({ x: 1 })) - AssertTypeOf(await g.gql >``.send()) - AssertTypeOf(await g.gql >``.send({ x: 1 })) - AssertTypeOf(await g.gql >``.send()) - AssertTypeOf(await g.gql>``.send()) // eslint-disable-line - AssertTypeOf(await g.gql>``.send({ x: 1 })) // eslint-disable-line - AssertTypeOf(await g.gql>``.send(`abc`, { x: 1 })) // eslint-disable-line + AssertTypeOf(await g.gql >``.send({ x: 1 })) + AssertTypeOf(await g.gql >``.send()) + AssertTypeOf(await g.gql >``.send({ x: 1 })) + AssertTypeOf(await g.gql >``.send()) + AssertTypeOf(await g.gql>``.send()) // eslint-disable-line + AssertTypeOf(await g.gql>``.send({ x: 1 })) // eslint-disable-line + AssertTypeOf(await g.gql>``.send(`abc`, { x: 1 })) // eslint-disable-line // @ts-expect-error - wrong argument type await g.gql >``.send({ x: 2 }) - AssertTypeOf(await g.gql >``.send({ x: 1 })) - AssertTypeOf(await g.gql >``.send()) - AssertTypeOf(await g.gql >``.send({ x: 1 })) - AssertTypeOf(await g.gql >``.send()) - AssertTypeOf(await g.gql>``.send()) // eslint-disable-line - AssertTypeOf(await g.gql>``.send({ x: 1 })) // eslint-disable-line - AssertTypeOf(await g.gql>``.send(`abc`, { x: 1 })) // eslint-disable-line + AssertTypeOf(await g.gql >``.send({ x: 1 })) + AssertTypeOf(await g.gql >``.send()) + AssertTypeOf(await g.gql >``.send({ x: 1 })) + AssertTypeOf(await g.gql >``.send()) + AssertTypeOf(await g.gql>``.send()) // eslint-disable-line + AssertTypeOf(await g.gql>``.send({ x: 1 })) // eslint-disable-line + AssertTypeOf(await g.gql>``.send(`abc`, { x: 1 })) // eslint-disable-line // @ts-expect-error - wrong argument type - await g.gql >``.send({ x: 2 }) + await g.gql >``.send({ x: 2 }) + + + AssertTypeOf(await g.gql``.send()) + AssertTypeOf(await g.gql``.send(`foo`)) + AssertTypeOf(await g.gql``.send(`foo`, { x: 1 })) + AssertTypeOf(await g.gql``.send({ x: 1 })) } diff --git a/src/layers/6_client/gql/gql.test.ts b/src/layers/6_client/gql/gql.test.ts index d3bb4aaca..7b798a622 100644 --- a/src/layers/6_client/gql/gql.test.ts +++ b/src/layers/6_client/gql/gql.test.ts @@ -8,11 +8,11 @@ describe(`memory transport`, () => { describe(`operationName`, () => { test(`undefined by default`, async ({ kitchenSink }) => { await kitchenSink.use(Spy()).gql`query { id }`.send() - expect(Spy.input).toMatchObject({ request: { operationName: undefined } }) + expect(Spy.data.exchange.input).toMatchObject({ request: { operationName: undefined } }) }) test(`reflects explicit value`, async ({ kitchenSink }) => { await kitchenSink.use(Spy()).gql`query foo { id }`.send(`foo`) - expect(Spy.input).toMatchObject({ request: { operationName: `foo` } }) + expect(Spy.data.exchange.input).toMatchObject({ request: { operationName: `foo` } }) }) }) }) diff --git a/src/layers/6_client/gql/gql.ts b/src/layers/6_client/gql/gql.ts index f7fa4a485..e414e9075 100644 --- a/src/layers/6_client/gql/gql.ts +++ b/src/layers/6_client/gql/gql.ts @@ -1,5 +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 { + isTemplateStringArguments, + joinTemplateStringArrayAndArgs, + type TemplateStringsArguments, +} from '../../../lib/template-string.js' import { RequestCore } from '../../5_request/__.js' import type { InterfaceRaw } from '../../5_request/types.js' import { defineTerminus } from '../fluent.js' @@ -9,13 +16,11 @@ import { type DocumentController, resolveSendArguments, type sendArgumentsImplem // dprint-ignore export interface gql<$Config extends Config = Config> { - <$Document extends Grafaid.Nodes.Typed.TypedDocument>(document: $Document ): DocumentController<$Config, $Document> - <$Document extends Grafaid.Nodes.Typed.TypedDocument>(parts: TemplateStringsArray, ...args: unknown[]): DocumentController<$Config, $Document> + <$Document extends Grafaid.Document.Typed.TypedDocumentLike>(document: $Document ): DocumentController<$Config, $Document> + <$Document extends Grafaid.Document.Typed.TypedDocumentLike>(parts: TemplateStringsArray, ...args: unknown[]): DocumentController<$Config, $Document> } -type TemplateStringsArguments = [TemplateStringsArray, ...unknown[]] - -type gqlArguments = [Grafaid.Nodes.Typed.TypedDocument] | TemplateStringsArguments +type gqlArguments = [Grafaid.Document.Typed.TypedDocumentLike] | TemplateStringsArguments const resolveGqlArguments = (args: gqlArguments) => { const document = isTemplateStringArguments(args) ? joinTemplateStringArrayAndArgs(args) : args[0] @@ -32,52 +37,50 @@ export interface FnGql extends Fluent.FnProperty<'gql'> { export const gqlProperties = defineTerminus((state) => { return { gql: (...args: gqlArguments) => { - const { document } = resolveGqlArguments(args) + const { document: query } = resolveGqlArguments(args) + const interfaceType: InterfaceRaw = `raw` + const transportType = state.config.transport.type + const url = state.config.transport.type === `http` ? state.config.transport.url : undefined + const schema = state.config.transport.type === `http` ? undefined : state.config.transport.schema return { send: async (...args: sendArgumentsImplementation) => { const { operationName, variables } = resolveSendArguments(args) - const interfaceType: InterfaceRaw = `raw` - const transportType = state.config.transport.type - const url = state.config.transport.type === `http` ? state.config.transport.url : undefined - const schema = state.config.transport.type === `http` ? undefined : state.config.transport.schema + const request = { + query, + variables, + operationName, + } + const operationType = getOperationType(request) + if (!operationType) throw new Error(`Could not get operation type`) + + const analyzedRequest = { + rootType: operationTypeToRootType[operationType], + operation: operationType, + query, + variables, + operationName, + } + const initialInput = { interfaceType, transportType, state, url, schema, - schemaIndex: state.config.schemaIndex, - request: { - query: document, - variables, - operationName, - }, + // request, + request: analyzedRequest, } as RequestCore.Hooks.HookDefEncode['input'] + const result = await RequestCore.anyware.run({ initialInput, retryingExtension: state.retry as any, extensions: state.extensions.filter(_ => _.onRequest !== undefined).map(_ => _.onRequest!) as any, }) - return handleOutput(state, result) + + return handleOutput(state, analyzedRequest.rootType, result) }, } as any }, } }) - -const isTemplateStringArguments = (args: [...unknown[]]): args is TemplateStringsArguments => { - return isTemplateStringArray(args[0]) -} - -const isTemplateStringArray = (arg: any): arg is TemplateStringsArray => { - return Array.isArray(arg) && `raw` in arg && arg.raw !== undefined -} - -const joinTemplateStringArrayAndArgs = (args: TemplateStringsArguments): string => { - const [templateParts, ...templateArgs] = args - return templateParts.reduce( - (string, part, index) => `${string}${part}${index in templateArgs ? String(templateArgs[index]) : ``}`, - ``, - ) -} diff --git a/src/layers/6_client/gql/send.test-d.ts b/src/layers/6_client/gql/send.test-d.ts index 0361834e5..9cbde3e59 100644 --- a/src/layers/6_client/gql/send.test-d.ts +++ b/src/layers/6_client/gql/send.test-d.ts @@ -3,18 +3,22 @@ import type { Grafaid } from '../../../lib/grafaid/__.js' import type { SendArguments } from './send.js' AssertEqual< - SendArguments>, + SendArguments>, [string, { x: 1 }] | [{ x: 1 }] >() AssertEqual< - SendArguments>, + SendArguments>, [x?: string] | [x?: string, x?: { x?: 1 }] | [x?: { x?: 1 }] >() AssertEqual< - SendArguments>, + SendArguments>, [x?: string] >() AssertEqual< - SendArguments>, - [x?: string] | [x?: string, x?: Grafaid.Nodes.Typed.Variables] | [x?: Grafaid.Nodes.Typed.Variables] + SendArguments>, + [x?: string] | [x?: string, x?: Grafaid.Document.Typed.Variables] | [x?: Grafaid.Document.Typed.Variables] +>() +AssertEqual< + SendArguments, + [x?: string] | [x?: string, x?: Grafaid.Document.Typed.Variables] | [x?: Grafaid.Document.Typed.Variables] >() diff --git a/src/layers/6_client/gql/send.ts b/src/layers/6_client/gql/send.ts index 46481f561..e788a2173 100644 --- a/src/layers/6_client/gql/send.ts +++ b/src/layers/6_client/gql/send.ts @@ -4,32 +4,34 @@ import type { ResolveOutputGql } from '../handleOutput.js' import type { Config } from '../Settings/Config.js' // dprint-ignore -export type SendArguments<$TypedDocument extends Grafaid.Nodes.Typed.TypedDocument> = - SendArguments_> +export type SendArguments<$TypedDocument extends string | Grafaid.Document.Typed.TypedDocumentLike> = + $TypedDocument extends string + ? ([operationName?: string] | [operationName?: string, variables?: Grafaid.Document.Typed.Variables] | [variables?: Grafaid.Document.Typed.Variables]) + : SendArguments_> // dprint-ignore -type SendArguments_<$Variables extends Grafaid.Nodes.Typed.Variables> = - SendArguments__<$Variables, Grafaid.Nodes.Typed.GetVariablesInputKind<$Variables>> +type SendArguments_<$Variables extends Grafaid.Document.Typed.Variables> = + SendArguments__<$Variables, Grafaid.Document.Typed.GetVariablesInputKind<$Variables>> // dprint-ignore -type SendArguments__<$Variables extends Grafaid.Nodes.Typed.Variables, $VariablesKind extends Grafaid.Nodes.Typed.VariablesInputKind> = +type SendArguments__<$Variables extends Grafaid.Document.Typed.Variables, $VariablesKind extends Grafaid.Document.Typed.VariablesInputKind> = $VariablesKind extends 'none' ? ([operationName?: string]) : $VariablesKind extends 'optional' ? ([operationName?: string] | [operationName?: string, variables?: $Variables] | [variables?: $Variables]) : $VariablesKind extends 'required' ? ([operationName: string, variables: $Variables] | [variables: $Variables]) : never // dprint-ignore -export interface DocumentController<$Config extends Config, $TypedDocument extends Grafaid.Nodes.Typed.TypedDocument> { - send(...args: SendArguments<$TypedDocument>): Promise>> +export interface DocumentController<$Config extends Config, $TypedDocument extends Grafaid.Document.Typed.TypedDocumentLike> { + send(...args: SendArguments<$TypedDocument>): Promise>> } export type sendArgumentsImplementation = | [] | [string] - | [Grafaid.Nodes.Typed.Variables] + | [Grafaid.Document.Typed.Variables] | [ string, - Grafaid.Nodes.Typed.Variables, + Grafaid.Document.Typed.Variables, ] export const resolveSendArguments = (args: sendArgumentsImplementation) => { diff --git a/src/layers/6_client/handleOutput.ts b/src/layers/6_client/handleOutput.ts index 298499f7b..d2b3b097f 100644 --- a/src/layers/6_client/handleOutput.ts +++ b/src/layers/6_client/handleOutput.ts @@ -1,8 +1,10 @@ import type { ExecutionResult, GraphQLError } from 'graphql' import type { Simplify } from 'type-fest' +import { SchemaDrivenDataMap } from '../../layers/7_extensions/CustomScalars/schemaDrivenDataMap/types.js' import { Errors } from '../../lib/errors/__.js' +import type { Grafaid } from '../../lib/grafaid/__.js' import type { GraphQLExecutionResultError } from '../../lib/grafaid/graphql.js' -import { isRecordLikeObject, type SimplifyExceptError, type Values } from '../../lib/prelude.js' +import { isRecordLikeObject, isString, type SimplifyExceptError, type Values } from '../../lib/prelude.js' import type { SchemaIndex } from '../4_generator/generators/SchemaIndex.js' import type { TransportHttp } from '../5_request/types.js' import type { State } from './fluent.js' @@ -43,7 +45,7 @@ export type GraffleExecutionResultVar<$Config extends Config = Config> = export const handleOutput = ( state: State, - // context: RequestContext, + rootTypeName: Grafaid.Schema.RootTypeName, result: GraffleExecutionResultVar, ) => { if (isContextConfigTraditionalGraphQLOutput(state.config)) { @@ -90,27 +92,26 @@ export const handleOutput = ( return isEnvelope ? { ...result, errors: [...result.errors ?? [], error] } : error } - if (state.input.schemaIndex) { + if (state.input.schemaMap) { if (c.errors.schema !== false) { if (!isRecordLikeObject(result.data)) throw new Error(`Expected data to be an object.`) const schemaErrors = Object.entries(result.data).map(([rootFieldName, rootFieldValue]) => { // todo this check would be nice but it doesn't account for aliases right now. To achieve this we would // need to have the selection set available to use and then do a costly analysis for all fields that were aliases. // So costly that we would probably instead want to create an index of them on the initial encoding step and - // then make available down stream. Also, note, here, the hardcoding of Query, needs to be any root type. - // const isResultField = Boolean(schemaIndex.error.rootResultFields.Query[rootFieldName]) - // if (!isResultField) return null + // then make available down stream. + // const sddmNodeField = state.input.schemaMap?.roots[rootTypeName]?.f[rootFieldName] + // if (!sddmNodeField) return null // if (!isPlainObject(rootFieldValue)) return new Error(`Expected result field to be an object.`) if (!isRecordLikeObject(rootFieldValue)) return null + // If __typename is not selected we assume that this is not a result field. + // The extension makes sure that the __typename would have been selected if it were a result field. const __typename = rootFieldValue[`__typename`] - if (typeof __typename !== `string`) { - return new Error(`Expected __typename to be selected and a string.`) - } + if (!isString(__typename)) return null - const isErrorObject = Boolean( - state.input.schemaIndex?.error.objectsTypename[__typename], - ) + const sddmNode = state.input.schemaMap?.types[__typename] + const isErrorObject = SchemaDrivenDataMap.isOutputObject(sddmNode) && Boolean(sddmNode.e) if (!isErrorObject) return null // todo extract message // todo allow mapping error instances to schema errors diff --git a/src/layers/6_client/prefilled.ts b/src/layers/6_client/prefilled.ts index bab7a1108..d553dabc7 100644 --- a/src/layers/6_client/prefilled.ts +++ b/src/layers/6_client/prefilled.ts @@ -1,10 +1,10 @@ import type { HasRequiredKeys } from 'type-fest' import type { Exact } from '../../lib/prelude.js' -import type { SchemaIndex } from '../4_generator/generators/SchemaIndex.js' import type { GlobalRegistry } from '../4_generator/globalRegistry.js' +import type { SchemaDrivenDataMap } from '../7_extensions/CustomScalars/schemaDrivenDataMap/types.js' import { type Client, create } from './client.js' import type { InputBase } from './Settings/Input.js' -import type { InputToConfig } from './Settings/InputToConfig.js' +import type { NormalizeInput } from './Settings/InputToConfig.js' /** * Create a constructor with some fields prefilled. Fields that can be prefilled are: @@ -12,15 +12,15 @@ import type { InputToConfig } from './Settings/InputToConfig.js' * - `schemaIndex` * - `schema` (If introspection was used for code generation, then is prefilled to the URL that was used.) */ -export const createPrefilled: CreatePrefilled = (name, schemaIndex, schemaUrl) => { +export const createPrefilled: CreatePrefilled = (name, schemaMap, schemaUrl) => { // eslint-disable-next-line // @ts-ignore passes after generation - return ((input) => create({ schema: schemaUrl, ...input, name, schemaIndex })) as any + return ((input) => create({ schema: schemaUrl, ...input, name, schemaMap })) as any } // dprint-ignore export type CreatePrefilled = -(name: $Name, schemaIndex: SchemaIndex, schemaUrl?: URL) => +(name: $Name, sddm: SchemaDrivenDataMap, schemaUrl?: URL) => < // eslint-disable-next-line // @ts-ignore passes after generation @@ -41,8 +41,7 @@ export type CreatePrefilled = // @ts-ignore passes after generation Client<{ // @ts-expect-error fixme - TS cannot figure out that name input meets constraint - config: InputToConfig<$Input & { name: $Name; schemaIndex: GlobalRegistry.GetSchemaIndexOrDefault<$Name> }>, - schemaIndex: GlobalRegistry.GetSchemaIndexOrDefault<$Name> + config: NormalizeInput<$Input & { name: $Name, schemaMap: SchemaDrivenDataMap }>, }> // dprint-ignore diff --git a/src/layers/6_client/requestMethods/client.rootMethods.test-d.ts b/src/layers/6_client/requestMethods/client.rootMethods.test-d.ts index 70333ad8a..7538f741e 100644 --- a/src/layers/6_client/requestMethods/client.rootMethods.test-d.ts +++ b/src/layers/6_client/requestMethods/client.rootMethods.test-d.ts @@ -7,14 +7,14 @@ const graffle = Graffle.create({ schema: Schema.schema }) // dprint-ignore test(`query`, async () => { - // scalar - expectTypeOf(graffle.query.id).toEqualTypeOf<() => Promise>() - expectTypeOf(graffle.query.idNonNull).toEqualTypeOf<() => Promise>() - // custom scalar - expectTypeOf(graffle.query.date).toEqualTypeOf<() => Promise>() - expectTypeOf(graffle.query.dateNonNull).toEqualTypeOf<() => Promise>() - expectTypeOf(graffle.query.dateArg).toMatchTypeOf<(args?: { date?: Date | null | undefined }) => Promise>() - expectTypeOf(graffle.query.dateArgNonNull).toMatchTypeOf<(args: { date: Date }) => Promise>() + // scalar input + expectTypeOf(graffle.query.id).toMatchTypeOf<(input?: Graffle.SelectionSets.Query.id) => Promise>() + expectTypeOf(graffle.query.idNonNull).toMatchTypeOf<(input?: Graffle.SelectionSets.Query.idNonNull) => Promise>() + // custom scalar input + expectTypeOf(graffle.query.date).toMatchTypeOf<(input?: Graffle.SelectionSets.Query.date) => Promise>() + expectTypeOf(graffle.query.dateNonNull).toMatchTypeOf<(input?: Graffle.SelectionSets.Query.dateNonNull) => Promise>() + expectTypeOf(graffle.query.dateArg).toMatchTypeOf<(input?: Graffle.SelectionSets.Query.dateArg) => Promise>() + expectTypeOf(graffle.query.dateArgNonNull).toMatchTypeOf<(input: Graffle.SelectionSets.Query.dateArgNonNull) => Promise>() // object expectTypeOf(graffle.query.dateObject1({ date1: true })).resolves.toEqualTypeOf<{ date1: Date | null } | null>() expectTypeOf(graffle.query.dateObject1({ $scalars: true })).resolves.toEqualTypeOf<{ __typename: "DateObject1"; date1: Date | null } | null>() diff --git a/src/layers/6_client/requestMethods/client.rootMethods.test.ts b/src/layers/6_client/requestMethods/client.rootMethods.test.ts index 60fe50cc0..ea2ee43e3 100644 --- a/src/layers/6_client/requestMethods/client.rootMethods.test.ts +++ b/src/layers/6_client/requestMethods/client.rootMethods.test.ts @@ -7,12 +7,12 @@ describe(`query`, () => { await expect(kitchenSink.query.id()).resolves.toEqual(db.id1) }) test(`argument`, async ({ kitchenSink }) => { - await expect(kitchenSink.query.stringWithArgs({ id: `x` })).resolves.toEqual(`{"id":"x"}`) + await expect(kitchenSink.query.stringWithArgs({ $: { id: `x` } })).resolves.toEqual(`{"id":"x"}`) }) test(`argument custom scalar`, async ({ kitchenSink, kitchenSinkData:db }) => { await expect(kitchenSink.query.dateArg()).resolves.toEqual(db.date0) - await expect(kitchenSink.query.dateArg({ date: db.date1 })).resolves.toEqual(db.date1) - await expect(kitchenSink.query.dateArgNonNull({ date: db.date1 })).resolves.toEqual(db.date1) + await expect(kitchenSink.query.dateArg({ $: { date: db.date1 }})).resolves.toEqual(db.date1) + await expect(kitchenSink.query.dateArgNonNull({ $: { date: db.date1 }})).resolves.toEqual(db.date1) }) test(`object`, async ({ kitchenSink, kitchenSinkData:db }) => { await expect(kitchenSink.query.dateObject1({ date1: true })).resolves.toEqual({ date1: db.date0 }) diff --git a/src/layers/6_client/requestMethods/document.test.ts b/src/layers/6_client/requestMethods/document.test.ts index 31fb9ae78..a4293a9d1 100644 --- a/src/layers/6_client/requestMethods/document.test.ts +++ b/src/layers/6_client/requestMethods/document.test.ts @@ -41,19 +41,13 @@ describe(`document with two queries`, () => { const { run } = withTwo // @ts-expect-error const error = await run().catch((e: unknown) => e) as Errors.ContextualAggregateError - expect(error.message).toEqual(`One or more errors in the execution result.`) - expect(error.errors[0]?.message).toEqual( - `Must provide operation name if query contains multiple operations.`, - ) + expect(error.message).toEqual(`Must provide operation name if query contains multiple operations.`) }) test(`error if wrong operation name is provided`, async () => { const { run } = withTwo // @ts-expect-error const error = await run(`boo`).catch((e: unknown) => e) as Errors.ContextualAggregateError - expect(error.message).toEqual(`One or more errors in the execution result.`) - expect(error.errors[0]?.message).toEqual( - `Unknown operation named "boo".`, - ) + expect(error.message).toEqual(`Unknown operation named "boo".`) }) test(`error if no operations provided`, () => { expect(() => { diff --git a/src/layers/6_client/requestMethods/requestMethods.ts b/src/layers/6_client/requestMethods/requestMethods.ts index 2b103495e..02ca83ba6 100644 --- a/src/layers/6_client/requestMethods/requestMethods.ts +++ b/src/layers/6_client/requestMethods/requestMethods.ts @@ -1,9 +1,9 @@ import type { HKT } from '../../../entrypoints/utilities-for-generated.js' import type { Fluent } from '../../../lib/fluent/__.js' import type { Grafaid } from '../../../lib/grafaid/__.js' -import { readMaybeThunk } from '../../1_Schema/_.js' -import { Schema } from '../../1_Schema/__.js' +import { isSymbol } from '../../../lib/prelude.js' import { Select } from '../../2_Select/__.js' +import { getOperationOrThrow } from '../../2_Select/document.js' import type { GlobalRegistry } from '../../4_generator/globalRegistry.js' import { RequestCore } from '../../5_request/__.js' import { type ClientContext, defineTerminus, type State } from '../fluent.js' @@ -18,7 +18,7 @@ export interface FnRequestMethods extends Fluent.FnMerge { // dprint-ignore export type BuilderRequestMethods<$Context extends ClientContext>= & ( - $Context['config']['schemaIndex'] extends null + $Context['config']['schemaMap'] extends null ? {} : ( @@ -55,60 +55,36 @@ export const createMethodDocument = (state: State) => (document: Select.Document const createMethodRootType = (state: State, rootTypeName: Grafaid.Schema.RootTypeName) => { return new Proxy({}, { get: (_, key) => { - if (typeof key === `symbol`) throw new Error(`Symbols not supported.`) + if (isSymbol(key)) throw new Error(`Symbols not supported.`) if (key.startsWith(`$batch`)) { - return async (selectionSetOrIndicator: Select.SelectionSet.FieldValue) => - executeRootType(state, rootTypeName, selectionSetOrIndicator as Select.SelectionSet.AnySelectionSet) + return async (selectionSetOrIndicator: Select.SelectionSet.AnySelectionSet) => + executeRootType(state, rootTypeName, selectionSetOrIndicator) } else { const fieldName = key - return (selectionSetOrArgs: Select.SelectionSet.AnySelectionSet | Select.Arguments.ArgsObject) => - executeRootTypeField(state, rootTypeName, fieldName, selectionSetOrArgs) + return (selectionSetOrArgs: Select.SelectionSet.AnySelectionSet) => + executeRootField(state, rootTypeName, fieldName, selectionSetOrArgs) } }, }) } -const executeRootTypeField = async ( +const executeRootField = async ( state: State, rootTypeName: Grafaid.Schema.RootTypeName, - rootTypeFieldName: string, - argsOrSelectionSet?: Select.SelectionSet.AnySelectionSet | Select.Arguments.ArgsObject, + rootFieldName: string, + rootFieldSelectionSet?: Select.SelectionSet.AnySelectionSet, ) => { - if (!state.input.schemaIndex) throw new Error(`Schema not loaded`) - - const selectedType = readMaybeThunk(state.input.schemaIndex.Root[rootTypeName]?.fields[rootTypeFieldName]?.type) - const selectedNamedType = readMaybeThunk( - // eslint-disable-next-line - // @ts-ignore excess depth error - Schema.Output.unwrapToNamed(selectedType), - ) as Schema.Output.Named - // eslint-disable-next-line - if (!selectedNamedType) throw new Error(`${rootTypeName} field not found: ${String(rootTypeFieldName)}`) - // @ts-expect-error fixme - const isSelectedTypeScalarOrTypeName = selectedNamedType.kind === `Scalar` || selectedNamedType.kind === `typename` // todo fix type here, its valid - const isFieldHasArgs = Boolean(state.input.schemaIndex.Root[rootTypeName]?.fields[rootTypeFieldName]?.args) - // We should only need to add __typename for result type fields, but the return handler doesn't yet know how to look beyond a plain object type so we have to add all those cases here. - // todo we could look at the root type fields that have result types and compare to the incoming query for match? - const isHasSchemaErrors = Object.values(state.input.schemaIndex.error.objects).length > 0 - const needsTypenameAdded = isHasSchemaErrors && state.config.output.errors.schema !== false - && (selectedNamedType.kind === `Object` || selectedNamedType.kind === `Interface` - || selectedNamedType.kind === `Union`) - const rootTypeFieldSelectionSet = isSelectedTypeScalarOrTypeName - ? isFieldHasArgs && argsOrSelectionSet ? { $: argsOrSelectionSet } : true - : needsTypenameAdded - ? { ...argsOrSelectionSet, __typename: true } - : argsOrSelectionSet - const result = await executeRootType(state, rootTypeName, { - [rootTypeFieldName]: rootTypeFieldSelectionSet, - } as Select.SelectionSet.AnySelectionSet) + [rootFieldName]: rootFieldSelectionSet ?? {}, + }) + if (result instanceof Error) return result return state.config.output.envelope.enabled ? result // @ts-expect-error - : result[rootTypeFieldName] + : result[rootFieldName] } const executeRootType = async ( @@ -135,16 +111,15 @@ export const executeDocument = async ( const interfaceType = `typed` const url = state.config.transport.type === `http` ? state.config.transport.url : undefined const schema = state.config.transport.type === `http` ? undefined : state.config.transport.schema + + const { rootType } = getOperationOrThrow(document, operationName) + const initialInput = { - document, - operationName, - // todo, remove the above state, interfaceType, transportType, url, schema, - schemaIndex: state.config.schemaIndex, request: { document, operationName, @@ -158,5 +133,5 @@ export const executeDocument = async ( extensions: state.extensions.filter(_ => _.onRequest !== undefined).map(_ => _.onRequest!) as any, }) - return handleOutput(state, result) + return handleOutput(state, rootType, result) } diff --git a/src/layers/7_customScalars/RuntimeIndexCustomScalars.ts b/src/layers/7_customScalars/RuntimeIndexCustomScalars.ts deleted file mode 100644 index eb6250ef2..000000000 --- a/src/layers/7_customScalars/RuntimeIndexCustomScalars.ts +++ /dev/null @@ -1,177 +0,0 @@ -// todo we are going to run into recursion with input types such as two input -// objects each having their own custom scalars and also referencing one another. -// to solve this we'll need to either use thunks or some kind of indirect look up table? -import { Code } from '../../lib/Code.js' -import { Grafaid } from '../../lib/grafaid/__.js' -import { entries } from '../../lib/prelude.js' -import { ModuleGeneratorScalar } from '../4_generator/generators/Scalar.js' -import { createModuleGenerator } from '../4_generator/helpers/moduleGenerator.js' -import { createCodeGenerator } from '../4_generator/helpers/moduleGeneratorRunner.js' -import { title1 } from '../4_generator/helpers/render.js' - -const identifiers = { - $CustomScalars: `CustomScalars`, -} - -export const ModuleGeneratorRuntimeCustomScalars = createModuleGenerator( - `RuntimeCustomScalars`, - ({ config, code }) => { - code(`import * as ${identifiers.$CustomScalars} from './${ModuleGeneratorScalar.name}.js'`) - - // dprint-ignore - const kindsFiltered = { - GraphQLInputObjectType: config.schema.typeMapByKind.GraphQLInputObjectType.filter(Grafaid.Nodes.$Schema.CustomScalars.isHasCustomScalars), - GraphQLObjectType: config.schema.typeMapByKind.GraphQLObjectType.filter(Grafaid.Nodes.$Schema.CustomScalars.isHasCustomScalars), - GraphQLInterfaceType: config.schema.typeMapByKind.GraphQLInterfaceType.filter(Grafaid.Nodes.$Schema.CustomScalars.isHasCustomScalars), - GraphQLUnionType: config.schema.typeMapByKind.GraphQLUnionType.filter(Grafaid.Nodes.$Schema.CustomScalars.isHasCustomScalars), - GraphQLRootType: config.schema.typeMapByKind.GraphQLRootType.filter(Grafaid.Nodes.$Schema.CustomScalars.isHasCustomScalars), - } - - for (const [kindName, nodes] of entries(kindsFiltered)) { - code(title1(kindName)) - code() - if (nodes.length === 0) { - code(`// None of your ${kindName}s have custom scalars.`) - } - for (const type of nodes) { - const codeGenerator = kindRenders[kindName] as any - code(codeGenerator({ config, type: type as any })) - code() - } - - code() - } - - code(title1(`Index`)) - code() - code(`export const $index = {`) - kindsFiltered.GraphQLRootType.forEach(type => { - code(type.name + `,`) - }) - code(`}`) - }, -) - -// -// -// -// Code Generators -// --------------- -// -// -// - -const UnionType = createCodeGenerator< - { type: Grafaid.Nodes.$Schema.GraphQLUnionType } ->( - ({ code, type }) => { - // This takes advantage of the fact that in GraphQL, in a union type, all members that happen - // to have fields of the same name, those fields MUST be the same type. - // See: - // - https://github.com/graphql/graphql-js/issues/1361 - // - https://stackoverflow.com/questions/44170603/graphql-using-same-field-names-in-different-types-within-union - // - // So what we do is inline all the custom scalar paths of all union members knowing - // that they could never conflict. - code(`const ${type.name} = {`) - for (const memberType of type.getTypes()) { - if (Grafaid.Nodes.$Schema.CustomScalars.isHasCustomScalars(memberType)) { - code(`...${memberType.name},`) - } - } - code(`}`) - }, -) - -const InterfaceType = createCodeGenerator< - { type: Grafaid.Nodes.$Schema.GraphQLInterfaceType } ->( - ({ code, type, config }) => { - const implementorTypes = Grafaid.Nodes.$Schema.KindMap.getInterfaceImplementors(config.schema.typeMapByKind, type) - code(`const ${type.name} = {`) - for (const implementorType of implementorTypes) { - if (Grafaid.Nodes.$Schema.CustomScalars.isHasCustomScalars(implementorType)) { - code(`...${implementorType.name},`) - } - } - code(`}`) - }, -) - -const ObjectType = createCodeGenerator<{ type: Grafaid.Nodes.$Schema.GraphQLObjectType }>( - ({ code, type }) => { - code(`const ${type.name} = {`) - - const fields = Object.values(type.getFields()).filter(Grafaid.Nodes.$Schema.CustomScalars.isHasCustomScalars) - for (const field of fields) { - code(Code.termField(field.name, `{`, { comma: false })) - - // Field Arguments - const args = field.args.filter(Grafaid.Nodes.$Schema.CustomScalars.isHasCustomScalarInputs) - if (args.length > 0) { - code(Code.termField(`i`, `{`, { comma: false })) - for (const arg of args) { - const argType = Grafaid.Nodes.getNamedType(arg.type) - if (Grafaid.Nodes.$Schema.isScalarTypeAndCustom(argType)) { - code(Code.termField(arg.name, `${identifiers.$CustomScalars}.${argType.name}.codec`)) - } else if (Grafaid.Nodes.$Schema.isInputObjectType(argType)) { - code(Code.termField(arg.name, argType.name)) - } else { - throw new Error(`Failed to complete index for argument ${arg.name} of ${argType.toString()}`) - } - } - code(`},`) - } - - const fieldType = Grafaid.Nodes.getNamedType(field.type) - - if (Grafaid.Nodes.$Schema.CustomScalars.isHasCustomScalars(fieldType)) { - if (Grafaid.Nodes.$Schema.isScalarTypeAndCustom(fieldType)) { - code(Code.termField(`o`, `${identifiers.$CustomScalars}.${fieldType.name}.codec`)) - } else if ( - Grafaid.Nodes.$Schema.isUnionType(fieldType) || Grafaid.Nodes.$Schema.isObjectType(fieldType) - || Grafaid.Nodes.$Schema.isInterfaceType(fieldType) - ) { - code(Code.termField(`r`, fieldType.name)) - // // todo make kitchen sink schema have a pattern where this code path will be traversed. - // // We just need to have arguments on a field on a nested object. - // // Nested objects that in turn have custom scalar arguments - // if (Nodes.$Schema.isObjectType(fieldType) && Nodes.$Schema.isHasCustomScalars(fieldType)) { - // code(Code.termField(field.name, fieldType.name)) - // } - } - } - - code(`},`) - } - code(`}`) - }, -) - -const InputObjectType = createCodeGenerator<{ type: Grafaid.Nodes.$Schema.GraphQLInputObjectType }>( - ({ code, type }) => { - code(`const ${type.name} = {`) - - for (const field of Object.values(type.getFields())) { - const type = Grafaid.Nodes.getNamedType(field.type) - if (Grafaid.Nodes.$Schema.isScalarTypeAndCustom(type)) { - code(Code.termField(field.name, `${identifiers.$CustomScalars}.${type.name}.codec`)) - } else if ( - Grafaid.Nodes.$Schema.isInputObjectType(type) - && Grafaid.Nodes.$Schema.CustomScalars.isHasCustomScalarInputs(type) - ) { - code(Code.termField(field.name, type.name)) - } - } - - code(`}`) - }, -) - -const kindRenders = { - GraphQLUnionType: UnionType, - GraphQLInterfaceType: InterfaceType, - GraphQLInputObjectType: InputObjectType, - GraphQLObjectType: ObjectType, - GraphQLRootType: ObjectType, -} diff --git a/src/layers/7_customScalars/decode.ts b/src/layers/7_customScalars/decode.ts deleted file mode 100644 index e3fbf1394..000000000 --- a/src/layers/7_customScalars/decode.ts +++ /dev/null @@ -1,102 +0,0 @@ -import { Kind, parse } from 'graphql' -import type { Grafaid } from '../../lib/grafaid/__.js' -import { operationTypeNameToRootTypeName, parseOperationType } from '../../lib/grafaid/graphql.js' -import { unType } from '../../lib/grafaid/typed-document/TypedDocument.js' -import { isString } from '../../lib/prelude.js' -import type { CodecString } from '../3_SelectGraphQLMapper/types.js' -import type { CustomScalarsIndex } from '../4_generator/generators/SchemaIndex.js' - -/** - * If a document is given then aliases will be decoded as well. - */ -export const decodeCustomScalars = (input: { - data: Grafaid.SomeData | null | undefined - customScalarsIndex: CustomScalarsIndex - request: Grafaid.RequestInput -}) => { - const rootType = parseOperationType(input.request) - if (!rootType) return - - const customScalarsIndex = input.customScalarsIndex[operationTypeNameToRootTypeName[rootType]] - if (!customScalarsIndex) return - - const queryUntyped = unType(input.request.query) - // todo expose an option to optimize string interface by not parsing it. Explain the caveat of losing support for custom scalars in aliased positions. - // const document = isString(queryUntyped) ? null : queryUntyped - const document = (isString(queryUntyped) ? parse(queryUntyped) : queryUntyped) as Grafaid.Nodes.DocumentNode | null - const documentOperations = document?.definitions.filter(d => d.kind === Kind.OPERATION_DEFINITION) - const selectionSet = (documentOperations?.length === 1 ? documentOperations[0] : documentOperations?.find(d => { - return d.name?.value === input.request.operationName - }))?.selectionSet ?? null - - decode_({ - data: input.data, - customScalarsIndex, - documentPart: selectionSet, - }) -} - -const decode_ = (input: { - data: Grafaid.SomeData | null | undefined - customScalarsIndex: CustomScalarsIndex.OutputObject - documentPart: null | Grafaid.Nodes.SelectionSetNode -}): void => { - const { data, customScalarsIndex, documentPart } = input - if (!data) return - - for (const [k, v] of Object.entries(data)) { - // todo: test case of a custom scalar whose encoded value would be falsy in JS, like 0 or empty string - if (v === null) continue - - const documentField = findDocumentField(documentPart, k) - - const kSchema = documentField?.name.value ?? k - - const indexField = customScalarsIndex[kSchema] - if (!indexField) continue - - const codec = indexField.o - if (codec) { - data[k] = decodeValue(v, codec) - continue - } - - const indexFieldType = indexField.r - if (indexFieldType) { - decode_({ - data: v, - customScalarsIndex: indexFieldType, - documentPart: documentField?.selectionSet ?? null, - }) - continue - } - - throw new Error(`Unknown index item: ${String(indexField)}`) - } -} - -const decodeValue = (value: any, codec: CodecString): any => { - if (Array.isArray(value)) { - return value.map(item => decodeValue(item, codec)) - } - return codec.decode(value) -} - -const findDocumentField = ( - selectionSet: null | Grafaid.Nodes.SelectionSetNode, - k: string, -): Grafaid.Nodes.FieldNode | null => { - if (!selectionSet) return null - - for (const selection of selectionSet.selections) { - if (selection.kind === Kind.FIELD && (selection.alias?.value ?? selection.name.value) === k) { - return selection - } - if (selection.kind === Kind.INLINE_FRAGMENT) { - const result = findDocumentField(selection.selectionSet, k) - if (result !== null) return result - } - } - - return null -} diff --git a/src/layers/7_customScalars/encode.ts b/src/layers/7_customScalars/encode.ts deleted file mode 100644 index 419f1df76..000000000 --- a/src/layers/7_customScalars/encode.ts +++ /dev/null @@ -1,17 +0,0 @@ -// import { describe, test } from 'vitest' -// import { db } from '../../../../tests/_/schemas/db.js' - -// // dprint-ignore -// describe(`custom scalars`, () => { -// test.each([ -// [`arg field`, { dateArg: { $: { date: db.date0 } } }], -// [`arg field in non-null`, { dateArgNonNull: { $: { date: db.date0 } } }], -// [`arg field in list`, { dateArgList: { $: { date: [db.date0, new Date(1)] } } }], -// [`arg field in list (null)`, { dateArgList: { $: { date: null } } }], -// [`arg field in non-null list (with list)`, { dateArgNonNullList: { $: { date: [db.date0, new Date(1)] } } }], -// [`arg field in non-null list (with null)`, { dateArgNonNullList: { $: { date: [null, db.date0] } } }], -// [`arg field in non-null list non-null`, { dateArgNonNullListNonNull: { $: { date: [db.date0, new Date(1)] } } }], -// [`input object field`, { dateArgInputObject: { $: { input: { idRequired: ``, dateRequired: db.date0, date: new Date(1) } } } }], -// [`nested input object field`, { InputObjectNested: { $: { input: { InputObject: { idRequired: ``, dateRequired: db.date0, date: new Date(1) } } } } }] -// ])(...testEachArguments) -// }) diff --git a/src/layers/7_customScalars/extension.ts b/src/layers/7_customScalars/extension.ts deleted file mode 100644 index 18f55f7fd..000000000 --- a/src/layers/7_customScalars/extension.ts +++ /dev/null @@ -1,27 +0,0 @@ -import { createExtension } from '../6_client/extension/extension.js' -import { decodeCustomScalars } from './decode.js' - -export const CustomScalars = () => - createExtension({ - name: `CustomScalars`, - onRequest: (async ({ pack }) => { - const { exchange } = await pack() - const { unpack } = await exchange() - const { decode } = await unpack() - - // If there has been an error and we definitely don't have any data, such as when - // giving an operation name that doesn't match any in the document, - // then don't attempt to decode. - const isError = !decode.input.result.data && (decode.input.result.errors?.length ?? 0) > 0 - - if (decode.input.schemaIndex && !isError) { - decodeCustomScalars({ - data: decode.input.result.data, - customScalarsIndex: decode.input.schemaIndex.customScalars.input, // todo drop input/output separation - request: pack.input.request, - }) - } - - return await decode() - }), - }) diff --git a/src/layers/7_extensions/CustomScalars/CustomScalars.ts b/src/layers/7_extensions/CustomScalars/CustomScalars.ts new file mode 100644 index 000000000..69952851e --- /dev/null +++ b/src/layers/7_extensions/CustomScalars/CustomScalars.ts @@ -0,0 +1,41 @@ +import { normalizeRequestToNode } from '../../../lib/grafaid/request.js' +import { createExtension } from '../../6_client/extension/extension.js' +import { decodeResultData } from './decode.js' +import { encodeRequestVariables } from './encode.js' + +export const CustomScalars = () => + createExtension({ + name: `CustomScalars`, + // todo: can we make it easier to remove the string interface case? + // documentNode: true, + onRequest: (async ({ pack }) => { + const sddm = pack.input.state.config.schemaMap + if (!sddm) return pack() + + const request = normalizeRequestToNode(pack.input.request) + + // We will mutate query. Assign it back to input for it to be carried forward. + pack.input.request.query = request.query + + encodeRequestVariables({ sddm, request }) + + const { exchange } = await pack() + const { unpack } = await exchange() + const { decode } = await unpack() + + // If there has been an error and we definitely don't have any data, such as when + // giving an operation name that doesn't match any in the document, + // then don't attempt to decode. + const isError = !decode.input.result.data && (decode.input.result.errors?.length ?? 0) > 0 + + if (!isError) { + decodeResultData({ + sddm, + request, + data: decode.input.result.data, + }) + } + + return await decode() + }), + }) diff --git a/src/layers/7_customScalars/decode.test.ts b/src/layers/7_extensions/CustomScalars/decode.test.ts similarity index 89% rename from src/layers/7_customScalars/decode.test.ts rename to src/layers/7_extensions/CustomScalars/decode.test.ts index 501adb937..23228eb86 100644 --- a/src/layers/7_customScalars/decode.test.ts +++ b/src/layers/7_extensions/CustomScalars/decode.test.ts @@ -1,10 +1,10 @@ -import { print } from 'graphql' import { describe, expect } from 'vitest' -import { createResponse, test } from '../../../tests/_/helpers.js' -import { db } from '../../../tests/_/schemas/db.js' -import type { Graffle } from '../../../tests/_/schemas/kitchen-sink/graffle/__.js' -import { Select } from '../2_Select/__.js' -import { SelectionSetGraphqlMapper } from '../3_SelectGraphQLMapper/__.js' +import { createResponse, test } from '../../../../tests/_/helpers.js' +import { db } from '../../../../tests/_/schemas/db.js' +import type { Graffle } from '../../../../tests/_/schemas/kitchen-sink/graffle/__.js' +import { Grafaid } from '../../../lib/grafaid/__.js' +import { Select } from '../../2_Select/__.js' +import { SelectionSetGraphqlMapper } from '../../3_SelectGraphQLMapper/__.js' const date0Encoded = db.date0.toISOString() @@ -31,9 +31,9 @@ const withGqlDocument: TestCaseWith = [ {}, async ([_, query, responseData, expectedData], { fetch, kitchenSinkHttp: kitchenSink }) => { fetch.mockResolvedValueOnce(createResponse({ data: responseData })) - const document = SelectionSetGraphqlMapper.toGraphQL({ - document: Select.Document.normalizeOrThrow({ query: { foo: query as any } }), - }) + const { document } = SelectionSetGraphqlMapper.toGraphQL( + Select.Document.createDocumentNormalizedFromQuerySelection(query as any), + ) expect(await kitchenSink.gql(document).send()).toEqual(expectedData) }, ] @@ -43,10 +43,10 @@ const withGqlString: TestCaseWith = [ {}, async ([_, query, responseData, expectedData], { fetch, kitchenSinkHttp: kitchenSink }) => { fetch.mockResolvedValueOnce(createResponse({ data: responseData })) - const document = SelectionSetGraphqlMapper.toGraphQL({ - document: Select.Document.normalizeOrThrow({ query: { foo: query as any } }), - }) - expect(await kitchenSink.gql(print(document)).send()).toEqual(expectedData) + const { document } = SelectionSetGraphqlMapper.toGraphQL( + Select.Document.normalizeOrThrow({ query: { foo: query as any } }), + ) + expect(await kitchenSink.gql(Grafaid.Document.print(document)).send()).toEqual(expectedData) }, ] diff --git a/src/layers/7_extensions/CustomScalars/decode.ts b/src/layers/7_extensions/CustomScalars/decode.ts new file mode 100644 index 000000000..f45c552ed --- /dev/null +++ b/src/layers/7_extensions/CustomScalars/decode.ts @@ -0,0 +1,86 @@ +import { Kind } from 'graphql' +import type { Grafaid } from '../../../lib/grafaid/__.js' +import { applyCodec } from '../../1_Schema/Hybrid/types/Scalar/Scalar.js' +import { SchemaDrivenDataMap } from './schemaDrivenDataMap/types.js' + +/** + * If a document is given then aliases will be decoded as well. + */ +export const decodeResultData = ({ request, data, sddm }: { + /** + * Result data to decode. + */ + data: Grafaid.SomeData | null | undefined + /** + * Schema Driven Data Map that contains codecs for custom scalars. + */ + sddm: SchemaDrivenDataMap + /** + * Request is used to traverse aliases if any were used. + */ + request: Grafaid.RequestAnalyzedDocumentNodeInput +}) => { + const sddmOutputObject = sddm.roots[request.rootType] + if (!sddmOutputObject) return + + decodeResultData_({ + data, + sddmOutputObject, + documentPart: request.operation.selectionSet, + }) +} + +const decodeResultData_ = (input: { + data: Grafaid.SomeData | null | undefined + sddmOutputObject: SchemaDrivenDataMap.OutputObject + documentPart: null | Grafaid.Document.SelectionSetNode +}): void => { + const { data, sddmOutputObject, documentPart } = input + if (!data) return + + for (const [k, v] of Object.entries(data)) { + // todo: test case of a custom scalar whose encoded value would be falsy in JS, like 0 or empty string + if (v === null) continue + + const documentField = findDocumentField(documentPart, k) + + const kSchema = documentField?.name.value ?? k + + const sddmOutputField = sddmOutputObject.f[kSchema] + if (!sddmOutputField) continue + + const sddmNode = sddmOutputField.nt + + // console.log(sddmNode) + if (SchemaDrivenDataMap.isScalar(sddmNode)) { + data[k] = applyCodec(sddmNode.codec.decode, v) + } else if (SchemaDrivenDataMap.isOutputObject(sddmNode)) { + decodeResultData_({ + data: v, + sddmOutputObject: sddmNode, + documentPart: documentField?.selectionSet ?? null, + }) + } else { + // enums not decoded. + } + } +} + +const findDocumentField = ( + selectionSet: null | Grafaid.Document.SelectionSetNode, + k: string, +): Grafaid.Document.FieldNode | null => { + if (!selectionSet) return null + + for (const selection of selectionSet.selections) { + if (selection.kind === Kind.FIELD && (selection.alias?.value ?? selection.name.value) === k) { + return selection + } + if (selection.kind === Kind.INLINE_FRAGMENT) { + const result = findDocumentField(selection.selectionSet, k) + if (result !== null) return result + } + } + + return null +} diff --git a/src/layers/7_extensions/CustomScalars/encode.test.ts b/src/layers/7_extensions/CustomScalars/encode.test.ts new file mode 100644 index 000000000..204391db1 --- /dev/null +++ b/src/layers/7_extensions/CustomScalars/encode.test.ts @@ -0,0 +1,46 @@ +import { expect } from 'vitest' +import { test } from '../../../../tests/_/helpers.js' +import { db } from '../../../../tests/_/schemas/db.js' +import type { Graffle } from '../../../../tests/_/schemas/kitchen-sink/graffle/__.js' +import { schemaDrivenDataMap } from '../../../../tests/_/schemas/kitchen-sink/graffle/modules/SchemaDrivenDataMap.js' +import { Spy } from '../../../../tests/_/SpyExtension.js' +import { Grafaid } from '../../../lib/grafaid/__.js' +import { Select } from '../../2_Select/__.js' +import { SelectionSetGraphqlMapper } from '../../3_SelectGraphQLMapper/__.js' + +const date0Encoded = db.date0.toISOString() +const date1Encoded = db.date1.toISOString() + +type TestCase = [ + description: string, + query: Graffle.SelectionSets.Query, + expectedVariables: object, +] + +// todo test variable to a directive. +// dprint-ignore +const testCases = test.for([ + [`arg enum` , { stringWithArgEnum: { $: { $ABCEnum: `A` } } } , { ABCEnum: `A` }], + [`arg field` , { dateArg: { $: { date: db.date0 } } } , { date: date0Encoded }], + [`arg field in non-null` , { dateArgNonNull: { $: { date: db.date0 } } } , { date: date0Encoded }], + [`arg field in list` , { dateArgList: { $: { date: [db.date0, db.date1] } } } , { date: [date0Encoded, date1Encoded] }], + [`arg field in list (null)` , { dateArgList: { $: { date: null } } } , { date: null } ], + [`arg field in non-null list (with list)` , { dateArgNonNullList: { $: { date: [db.date0, db.date1] } } } , { date: [date0Encoded, date1Encoded] }], + [`arg field in non-null list (with null)` , { dateArgNonNullList: { $: { date: [null, db.date0] } } } , { date: [null, date0Encoded] }], + [`arg field in non-null list non-null` , { dateArgNonNullListNonNull: { $: { date: [db.date0, db.date1] } } } , { date: [date0Encoded, date1Encoded] }], + [`input object field` , { dateArgInputObject: { $: { input: { idRequired: ``, dateRequired: db.date0, date: db.date1 } } } } , { input: { idRequired: ``, dateRequired: date0Encoded, date: date1Encoded } }], + [`nested input object field` , { InputObjectNested: { $: { input: { InputObject: { idRequired: ``, dateRequired: db.date0, date: db.date1 }}}}} , { input: { InputObject: { idRequired: ``, dateRequired: date0Encoded, date: date1Encoded } } }], +]) + +testCases(`%s`, async ([_, query, expectedVariables], { kitchenSink }) => { + const { document, operationsVariables } = SelectionSetGraphqlMapper.toGraphQL( + Select.Document.createDocumentNormalizedFromQuerySelection(query as any), + { + sddm: schemaDrivenDataMap, + operationVariables: true, + }, + ) + const documentString = Grafaid.Document.print(document) + await kitchenSink.use(Spy()).gql(documentString).send(operationsVariables[`$default`]) + expect(Spy.data.pack.input?.request.variables).toEqual(expectedVariables) +}) diff --git a/src/layers/7_extensions/CustomScalars/encode.ts b/src/layers/7_extensions/CustomScalars/encode.ts new file mode 100644 index 000000000..6d98be03a --- /dev/null +++ b/src/layers/7_extensions/CustomScalars/encode.ts @@ -0,0 +1,61 @@ +import { Grafaid } from '../../../lib/grafaid/__.js' +import { applyCodec } from '../../1_Schema/Hybrid/types/Scalar/Scalar.js' +import { SchemaDrivenDataMap } from './schemaDrivenDataMap/types.js' + +export const encodeRequestVariables = ({ sddm, request }: { + sddm: SchemaDrivenDataMap + request: Grafaid.RequestAnalyzedDocumentNodeInput +}): void => { + const variableDefinitions = request.operation.variableDefinitions + if (!variableDefinitions) return + + const variableDefinitionsMap = new Map(variableDefinitions.map(v => [v.variable.name.value, v])) + + const variables = request.variables ?? {} + + // todo align the iteration strategy with other func. + for (const variableName in variables) { + const definition = variableDefinitionsMap.get(variableName) + if (!definition) continue // todo in a strict mode could be error. + + const value = variables[variableName] + if (value === undefined) continue + + const namedType = Grafaid.Document.getNamedType(definition.type) + const sddmNamedType = sddm.types[namedType.name.value] + if (!sddmNamedType) continue // todo in a strict mode could be error. + + encodeInputFieldLike(variables, variableName, value, sddmNamedType) + } +} + +const encodeInputFieldLike = ( + object: Record, + name: any, + value: any, + sddmNode: SchemaDrivenDataMap.InputLike, +) => { + if (SchemaDrivenDataMap.isScalar(sddmNode)) { + object[name] = applyCodec(sddmNode.codec.encode, value) + return + } + + if (SchemaDrivenDataMap.isInputObject(sddmNode)) { + // We could iterate here by two strategies: + // 1. The number of fields in the variables object given to execute against the document operation. + // 2. The number of custom scalar fields (direct or transient) on this schema object. + // The optimal choice is about which is smaller. + // TODO let users supply an algorithm choice. + for (const nameOfFieldIsOrContainingCustomScalar of sddmNode.fcs ?? []) { + if (!(typeof value === `object` && value !== null)) continue + + const variableValue2 = value[nameOfFieldIsOrContainingCustomScalar] + if (variableValue2 === undefined) continue + + const sddmNode2 = sddmNode.f?.[nameOfFieldIsOrContainingCustomScalar] + if (!sddmNode2?.nt) continue + + encodeInputFieldLike(value, nameOfFieldIsOrContainingCustomScalar, variableValue2, sddmNode2.nt) + } + } +} diff --git a/src/layers/7_extensions/CustomScalars/schemaDrivenDataMap/generator.ts b/src/layers/7_extensions/CustomScalars/schemaDrivenDataMap/generator.ts new file mode 100644 index 000000000..891246f85 --- /dev/null +++ b/src/layers/7_extensions/CustomScalars/schemaDrivenDataMap/generator.ts @@ -0,0 +1,390 @@ +import { Code } from '../../../../lib/Code.js' +import { Grafaid } from '../../../../lib/grafaid/__.js' +import { entries } from '../../../../lib/prelude.js' +import type { Config } from '../../../4_generator/config.js' +import { ModuleGeneratorScalar } from '../../../4_generator/generators/Scalar.js' +import { createModuleGenerator } from '../../../4_generator/helpers/moduleGenerator.js' +import { createCodeGenerator } from '../../../4_generator/helpers/moduleGeneratorRunner.js' +import { title1 } from '../../../4_generator/helpers/render.js' +import { propertyNames, SchemaDrivenDataMap } from './types.js' + +const identifiers = { + $Scalar: `$Scalar`, +} + +type ReferenceAssignments = string[] + +export const ModuleGeneratorSchemaDrivenDataMap = createModuleGenerator( + `SchemaDrivenDataMap`, + ({ config, code }) => { + code(` + import * as ${identifiers.$Scalar} from './${ModuleGeneratorScalar.name}.js' + import type * as $Utilities from '${config.paths.imports.grafflePackage.utilitiesForGenerated}' + `) + + const kinds = getKinds(config) + const kindsList = entries(kinds) + + const referenceAssignments: ReferenceAssignments = [] + + for (const [kindName, nodes] of kindsList) { + code(title1(kindName)) + code() + if (nodes.length === 0) { + code(`// None of your ${kindName}s have custom scalars.`) + } + for (const type of nodes) { + const codeGenerator = kindRenders[kindName] as any + code(codeGenerator({ config, type: type as any, referenceAssignments })) + code() + } + code() + } + + code(title1(`Reference Assignments`, `(avoids circular assignment issues)`)) + code() + if (referenceAssignments.length === 0) { + code(`// None of your types have references to other non-scalar/enum types.`) + } + for (const referenceAssignment of referenceAssignments) { + code(referenceAssignment) + } + code() + + code(title1(`Index`)) + code() + code(`const $schemaDrivenDataMap: $Utilities.SchemaDrivenDataMap =`) + code(Code.termObject({ + roots: Code.termObjectWith({ + $literal: kinds.GraphQLRootType.map(type => type.name + `,`).join(`\n`), + }), + directives: `{}`, + types: Code.termObjectWith({ + $literal: [ + ...kindsList.map(([, _]) => _).flat().map((_) => _.name), + // We also include the custom scalars here to facilitate encoding. Encoding has names of variables and + // that need to be looked up to determine which are/have custom scalars. + // ...config.schema.typeMapByKind.GraphQLScalarTypeCustom.map(_ => { + // return `${_.name}: ${identifiers.$CustomScalars}.${_.name},` + // }), + ].join(`,\n`), + }), + })) + code() + code(`export { $schemaDrivenDataMap as schemaDrivenDataMap }`) + }, +) + +// +// +// +// Helpers +// ------- +// +// +// + +/** + * Get minimal kind set for SDDM + * + * If feature operationVariables is enabled then we need to emit all paths to inputs. + * If feature customScalars is enabled then we need to emit all paths to customs scalar inputs AND outputs. + * If both are enabled the merged requirement is: all paths to inputs AND custom scalar outputs. + */ +const getKinds = (config: Config) => { + const { schema: { typeMapByKind } } = config + const condition = typeCondition(config) + return { + // When "variables" enabled, we need to know all named types to be able to write them out. + GraphQLScalarType: typeMapByKind.GraphQLScalarType.filter((n) => + config.runtimeFeatures.operationVariables && !Grafaid.Schema.isScalarTypeCustom(n) + ), + GraphQLScalarTypeCustom: typeMapByKind.GraphQLScalarTypeCustom.filter(() => config.runtimeFeatures.customScalars), + GraphQLEnumType: typeMapByKind.GraphQLEnumType.filter(() => config.runtimeFeatures.operationVariables), + GraphQLInputObjectType: typeMapByKind.GraphQLInputObjectType.filter(condition), + GraphQLObjectType: typeMapByKind.GraphQLObjectType.filter(condition), + GraphQLInterfaceType: typeMapByKind.GraphQLInterfaceType.filter(condition), + GraphQLUnionType: typeMapByKind.GraphQLUnionType.filter(condition), + GraphQLRootType: typeMapByKind.GraphQLRootType.filter(condition), + } +} + +const typeCondition = (config: Config) => { + if (config.runtimeFeatures.customScalars) { + if (config.runtimeFeatures.operationVariables) { + const isHasInputOrOutputCustomScalar = () => true // todo + return isHasInputOrOutputCustomScalar + } + return Grafaid.Schema.CustomScalars.isHasCustomScalars + } + + if (config.runtimeFeatures.operationVariables) { + const isHasInput = () => true // todo + return isHasInput + } + + return falseFilter +} + +const falseFilter = () => false +const trueFilter = () => true + +const inputTypeCondition = (config: Config) => { + if (config.runtimeFeatures.operationVariables) return trueFilter + + if (config.runtimeFeatures.customScalars) { + return Grafaid.Schema.CustomScalars.isHasCustomScalars + } + + return falseFilter +} + +// +// +// +// Code Generators +// --------------- +// +// +// +const ScalarType = createCodeGenerator< + { type: Grafaid.Schema.ScalarType } +>( + ({ code, type }) => { + code(Code.termConst(type.name, `${identifiers.$Scalar}.${type.name}`)) + }, +) + +const UnionType = createCodeGenerator< + { type: Grafaid.Schema.UnionType; referenceAssignments: ReferenceAssignments } +>( + ({ code, type }) => { + // This takes advantage of the fact that in GraphQL, in a union type, all members that happen + // to have fields of the same name, those fields MUST be the same type. + // See: + // - https://github.com/graphql/graphql-js/issues/1361 + // - https://stackoverflow.com/questions/44170603/graphql-using-same-field-names-in-different-types-within-union + // + // So what we do is inline all the custom scalar paths of all union members knowing + // that they could never conflict. + code(Code.termConstTyped( + type.name, + `$Utilities.SchemaDrivenDataMap.OutputObject`, + Code.termObject({ + [propertyNames.f]: Code.termObjectWith({ + $spread: type.getTypes().filter(Grafaid.Schema.CustomScalars.isHasCustomScalars).map(memberType => + memberType.name + `.${propertyNames.f}` + ), + }), + }), + )) + }, +) + +const InterfaceType = createCodeGenerator< + { type: Grafaid.Schema.InterfaceType; referenceAssignments: ReferenceAssignments } +>( + ({ code, type, config }) => { + const implementorTypes = Grafaid.Schema.KindMap.getInterfaceImplementors(config.schema.typeMapByKind, type) + code(Code.termConstTyped( + type.name, + `$Utilities.SchemaDrivenDataMap.OutputObject`, + Code.termObject({ + [propertyNames.f]: Code.termObjectWith({ + $spread: implementorTypes.filter(Grafaid.Schema.CustomScalars.isHasCustomScalars).map(memberType => + memberType.name + `.${propertyNames.f}` + ), + }), + }), + )) + }, +) + +const ObjectType = createCodeGenerator< + { type: Grafaid.Schema.ObjectType; referenceAssignments: ReferenceAssignments } +>( + ({ config, code, type, referenceAssignments }) => { + const o: Code.TermObject = {} + + // Indicate if this is an error type. + // ---------------------------------- + if (config.schema.error.objects.find(_ => _.name === type.name)) { + o[propertyNames.e] = 1 + } + + // Fields of this object. + // --------------------- + const of: Code.TermObject = {} + o[propertyNames.f] = of + + const condition = typeCondition(config) + + const outputFields = Object.values(type.getFields()).filter(condition) + for (const outputField of outputFields) { + const outputFieldNamedType = Grafaid.Schema.getNamedType(outputField.type) + const ofItem: Code.TermObjectWithLike = { + $fields: {}, + } + of[outputField.name] = ofItem + + // Field Arguments + const inputCondition = inputTypeCondition(config) + const args = outputField.args.filter(inputCondition) + if (args.length > 0) { + const ofItemAs: Code.TermObject = {} + ofItem.$fields[propertyNames.a] = ofItemAs + + for (const arg of args) { + const ofItemA: Code.TermObject = {} + ofItemAs[arg.name] = ofItemA + + const argType = Grafaid.Schema.getNamedType(arg.type) + // dprint-ignore + if ( + (config.runtimeFeatures.customScalars && Grafaid.Schema.isScalarTypeAndCustom(argType)) || + // For variables, we need to know the variable type to write it out, so we always need the named type. + (config.runtimeFeatures.operationVariables) + ) { + ofItemA[propertyNames.nt] = argType.name + // For variables, we need to know the variable type to write it out, so we always need the inline type. + if (config.runtimeFeatures.operationVariables) { + ofItemA[propertyNames.it] = inlineType(arg.type) + } + } + } + } + + // Indicate if the field is a "result field" + // ------------------------------------------ + const memberTypes = Grafaid.Schema.isUnionType(outputFieldNamedType) ? outputFieldNamedType.getTypes() : null + if ( + config.schema.error.enabled + && memberTypes + && config.schema.error.objects.find(_ => memberTypes.find(__ => __.name === _.name)) + ) { + ofItem.$fields[propertyNames.r] = 1 + } + + if (condition(outputFieldNamedType)) { + if (Grafaid.Schema.isScalarTypeAndCustom(outputFieldNamedType)) { + if (config.runtimeFeatures.customScalars) { + ofItem.$fields[propertyNames.nt] = outputFieldNamedType.name + } + } else if ( + Grafaid.Schema.isUnionType(outputFieldNamedType) || Grafaid.Schema.isObjectType(outputFieldNamedType) + || Grafaid.Schema.isInterfaceType(outputFieldNamedType) + ) { + referenceAssignments.push(`${type.name}.f['${outputField.name}']!.nt = ${outputFieldNamedType.name}`) + // dprint-ignore + ofItem.$literal = `// ${Code.termField(propertyNames.nt, outputFieldNamedType.name)} <-- Assigned later to avoid potential circular dependency.` + // // todo make kitchen sink schema have a pattern where this code path will be traversed. + // // We just need to have arguments on a field on a nested object. + // // Nested objects that in turn have custom scalar arguments + // if (Schema.isObjectType(fieldType) && Schema.isHasCustomScalars(fieldType)) { + // code(Code.termField(field.name, fieldType.name)) + // } + } + } + } + + code(Code.termConstTyped(type.name, `$Utilities.SchemaDrivenDataMap.OutputObject`, Code.termObject(o))) + }, +) + +const EnumType = createCodeGenerator< + { type: Grafaid.Schema.EnumType; referenceAssignments: ReferenceAssignments } +>( + ({ code, type }) => { + code(Code.termConstTyped( + type.name, + `$Utilities.SchemaDrivenDataMap.Enum`, + Code.termObject({ + [propertyNames.k]: Code.string(`enum`), + [propertyNames.n]: Code.string(type.name), + }), + )) + }, +) + +const InputObjectType = createCodeGenerator< + { type: Grafaid.Schema.ObjectType; referenceAssignments: ReferenceAssignments } +>( + ({ config, code, type, referenceAssignments }) => { + const o: Code.TermObject = {} + + const inputFields = Object.values(type.getFields()) + + if (config.runtimeFeatures.operationVariables) { + o[propertyNames.n] = Code.string(type.name) + const customScalarFields = inputFields + .filter(Grafaid.Schema.CustomScalars.isHasCustomScalarInputs) + .map(inputField => inputField.name) + .map(Code.string) + if (customScalarFields.length) { + o[propertyNames.fcs] = Code.termList(customScalarFields) + } + } + const f: Code.TermObjectOf> = {} + o[propertyNames.f] = f + + for (const inputField of inputFields) { + const inputFieldType = Grafaid.Schema.getNamedType(inputField.type) + + // dprint-ignore + const isPresent = + config.runtimeFeatures.operationVariables || + (config.runtimeFeatures.customScalars && + (Grafaid.Schema.isScalarTypeAndCustom(inputFieldType) || + (Grafaid.Schema.isInputObjectType(inputFieldType) && Grafaid.Schema.CustomScalars.isHasCustomScalarInputs(inputFieldType)))) + + if (!isPresent) continue + + f[inputField.name] = { + $fields: {}, + } + + if (Grafaid.Schema.isScalarTypeAndCustom(inputFieldType)) { + f[inputField.name]!.$fields[propertyNames.nt] = inputFieldType.name + } else if ( + Grafaid.Schema.isInputObjectType(inputFieldType) + && Grafaid.Schema.CustomScalars.isHasCustomScalarInputs(inputFieldType) + ) { + referenceAssignments.push( + `${type.name}.${propertyNames.f}!['${inputField.name}']!.${propertyNames.nt} = ${inputFieldType.name}`, + ) + f[inputField.name]!.$literal = `// ${ + Code.termField(propertyNames.nt, inputFieldType.name) + } <-- Assigned later to avoid potential circular dependency.` + } + } + + code(Code.termConstTyped(type.name, `$Utilities.SchemaDrivenDataMap.InputObject`, Code.termObject(o))) + }, +) + +const kindRenders = { + GraphQLScalarType: ScalarType, + GraphQLScalarTypeCustom: ScalarType, + GraphQLEnumType: EnumType, + GraphQLUnionType: UnionType, + GraphQLInterfaceType: InterfaceType, + GraphQLInputObjectType: InputObjectType, + GraphQLObjectType: ObjectType, + GraphQLRootType: ObjectType, +} + +const inlineType = (type: Grafaid.Schema.InputTypes): string => { + const [ofType, nonNull] = Grafaid.Schema.isNonNullType(type) + ? [type.ofType, true] + : [type, false] + + const nullFlag = nonNull + ? SchemaDrivenDataMap.nullabilityFlags.nonNull + : SchemaDrivenDataMap.nullabilityFlags.nullable + + const rest = Grafaid.Schema.isListType(ofType) + ? inlineType(ofType.ofType) + : `` + + return `[${nullFlag.toString()}, ${rest}]` +} diff --git a/src/layers/7_extensions/CustomScalars/schemaDrivenDataMap/types.ts b/src/layers/7_extensions/CustomScalars/schemaDrivenDataMap/types.ts new file mode 100644 index 000000000..a6e692e7e --- /dev/null +++ b/src/layers/7_extensions/CustomScalars/schemaDrivenDataMap/types.ts @@ -0,0 +1,166 @@ +import type { Grafaid } from '../../../../lib/grafaid/__.js' +import { Scalar, type Scalar as SchemaScalar } from '../../../1_Schema/_.js' + +export const propertyNames = { + k: `k`, + n: `n`, + it: `it`, + fcs: `fcs`, + f: `f`, + a: `a`, + nt: `nt`, + // schema errors + r: `r`, + e: `e`, +} as const + +export interface SchemaDrivenDataMap { + roots: { + [Grafaid.Schema.RootTypeName.Mutation]?: SchemaDrivenDataMap.OutputObject + [Grafaid.Schema.RootTypeName.Query]?: SchemaDrivenDataMap.OutputObject + [Grafaid.Schema.RootTypeName.Subscription]?: SchemaDrivenDataMap.OutputObject + } + types: Record + directives: Record + // todo, actually generate this + // schemaErrors?: { + // [Grafaid.Schema.RootTypeName.Mutation]?: Record + // [Grafaid.Schema.RootTypeName.Query]?: Record + // [Grafaid.Schema.RootTypeName.Subscription]?: Record + // } +} + +export namespace SchemaDrivenDataMap { + export type NamedLike = SchemaScalar.Scalar | OutputObject | Enum | InputObject + + export type OutputLike = SchemaScalar.Scalar | OutputObject | Enum + + export type InputLike = SchemaScalar.Scalar | InputObject | Enum + + export type Enum = { + k: `enum` + n: string + } + export const isEnum = (node?: Node): node is Enum => { + return node ? `k` in node && node.k === `enum` : false + } + + export type Node = + | OutputObject + | InputObject + | ArgumentsOrInputObjectFields + | ArgumentOrInputField + | InlineType + | SchemaDrivenDataMap + | Scalar + | Enum + + export interface OutputObject { + /** + * Indicates that this object represents an error type. + */ + e?: 1 + /** + * Fields of this output object. + */ + f: { + [key: string]: OutputField + } + } + + export const isScalar = Scalar.isScalar + + export const isOutputObject = (node?: Node): node is OutputObject => { + return node ? propertyNames.f in node : false + } + + export interface OutputField { + /** + * Indicates that this is a "result field". + */ + r?: 1 + /** + * The field's arguments, if any. + * + * Present when one of: + * - operationVariables is enabled and field has arguments. + * - customScalars is enabled and field has arguments that contain custom scalars. + */ + a?: ArgumentsOrInputObjectFields + /** + * The field's output type. + * + * Present when/as one of: + * - `CodecString` when customScalars enabled and this field's named type is a custom scalar. + * - `OutputObject` when customScalars enabled and this field's type contains custom scalars. + */ + nt?: OutputLike + } + export const isOutputField = (node?: Node): node is OutputField => { + return node ? `a` in node : false + } + + export interface ArgumentsOrInputObjectFields { + [key: string]: ArgumentOrInputField + } + + export interface ArgumentOrInputField { + /** + * Inline types (nullable/non-nullable, list) of this argument or input field. Only present when operationVariables is enabled. + */ + it?: InlineType + /** + * Named type of this argument or input field. Only present when customScalars is enabled. + */ + nt?: InputLike + } + + /** + * Inline types for a field-like (directive argument, field argument, input/output field) type. + * + * Nested tuple. Each nesting represents a list. First tuple member represents nullability of the list. + * + * The outer most tuple represents not a list but the nullability for the named type itself. E.g. `[0]` would indicate + * that a scalar field is nullable while `[1]` would indicate that it is non-nullable. + */ + export type InlineType = [Nullable | NonNull, InlineType?] + + export type Nullable = 0 + + export const nullabilityFlags = { + 'nullable': 0, + 'nonNull': 1, + } as const + + export type NonNull = 1 + + export interface InputObject { + /** + * Field names within this input object that are or transitively contain custom scalars. + * + * This is only present when operationVariables is enabled, because that feature requires + * all input object fields to be mapped, thus requiring a meta field to identify the custom scalar ones. + */ + fcs?: string[] + /** + * Name of the input object. Only present when "variables" is enabled. + */ + n?: string + /** + * Fields of the input object. + */ + f?: { + [key: string]: ArgumentOrInputField + } + } + + // todo not the best check, type has to limit to input like nodes since the check cannot tell input and output apart + // so it would be unsafe to rely on it if output objects could also be passed in. + // fixing this 1) means branding the data which means more bytes in the sddm + // or 2) means using a different key hint like `if` for "input field". + export const isInputObject = (node?: InputLike): node is InputObject => { + return node ? propertyNames.f in node : false + } + + export type Scalar = SchemaScalar.Scalar +} diff --git a/src/layers/7_extensions/SchemaErrors/SchemaErrors.test.ts b/src/layers/7_extensions/SchemaErrors/SchemaErrors.test.ts new file mode 100644 index 000000000..e40f94484 --- /dev/null +++ b/src/layers/7_extensions/SchemaErrors/SchemaErrors.test.ts @@ -0,0 +1,100 @@ +import { parse } from 'graphql' +import { describe, expect } from 'vitest' +import { test } from '../../../../tests/_/helpers.js' +import { db } from '../../../../tests/_/schemas/db.js' +import { Graffle } from '../../../../tests/_/schemas/kitchen-sink/graffle/__.js' +import { schemaDrivenDataMap } from '../../../../tests/_/schemas/kitchen-sink/graffle/modules/SchemaDrivenDataMap.js' +import type { Query } from '../../../../tests/_/schemas/kitchen-sink/graffle/modules/SelectionSets.js' +import { schema } from '../../../../tests/_/schemas/kitchen-sink/schema.js' +import { Select } from '../../2_Select/__.js' +import { SelectionSetGraphqlMapper } from '../../3_SelectGraphQLMapper/__.js' +import { graffleMappedToRequest } from '../../5_request/core.js' +import { injectTypenameOnRootResultFields } from '../../5_request/schemaErrors.js' +import { Throws } from '../Throws/Throws.js' + +const graffle = Graffle.create({ schema }).use(Throws()) + +describe(`document`, () => { + describe(`query result field`, () => { + test(`with __typename`, async () => { + const result = graffle.throws().document({ + query: { x: { resultNonNull: { $: { $case: `ErrorOne` }, __typename: true } } }, + }) + .run() + await expect(result).rejects.toMatchInlineSnapshot(`[Error: Failure on field resultNonNull: ErrorOne]`) + }) + test(`without __typename still works, __typename is dynamically added at runtime`, async () => { + const result = graffle.throws().document({ query: { x: { resultNonNull: { $: { $case: `ErrorOne` } } } } }).run() + await expect(result).rejects.toMatchInlineSnapshot( + `[Error: Failure on field resultNonNull: ErrorOne]`, + ) + }) + test(`multiple via alias`, async () => { + const result = graffle.throws().document({ + query: { + x: { + resultNonNull: [ + [`resultNonNull`, { $: { $case: `ErrorOne` } }], + [`x`, { $: { $case: `ErrorOne` } }], + ], + }, + }, + }).run() + await expect(result).rejects.toMatchInlineSnapshot( + `[ContextualAggregateError: Two or more schema errors in the execution result.]`, + ) + }) + }) +}) + +describe(`query non-result field`, () => { + test(`without error`, async () => { + await expect(graffle.throws().query.objectWithArgs({ $: { id: `x` }, id: true })).resolves.toEqual({ + id: `x`, + }) + }) + test(`with error`, async () => { + await expect(graffle.throws().query.error()).rejects.toMatchObject(db.errorAggregate) + }) +}) + +type CasesQuery = [description: string, queryWithoutTypename: Query, queryWithTypename: Query] + +// todo symmetrical type tests for these cases +// dprint-ignore +test.each([ + [`one result field`, { resultNonNull: { } }, { resultNonNull: { __typename: true } }], + [`two result fields`, { resultNonNull: { }, result: { $: { $case: `ErrorOne` }}}, { resultNonNull: { __typename: true }, result: { $: { $case: `ErrorOne` }, __typename: true } }], + [`no result fields`, { id: true, object: { id: true } }, { id: true, object: { id: true }}], + [`__typename in fragment`, { resultNonNull: { ___: { __typename: true }}}, { resultNonNull: { ___: { __typename: true }, __typename: true } }], + [`root field in fragment`, { ___: { resultNonNull: {} } }, { ___: { resultNonNull: { __typename: true }}}], + [`root field in fragment in alias`, { ___: { resultNonNull: [`x`, {}] } }, { ___: { resultNonNull: [`x`, { __typename: true }] }}], + [`root field alias `, { resultNonNull: [`x`, {}] }, { resultNonNull: [`x`, { __typename: true }] }], +])(`Query %s`, (_, queryWithoutTypenameInput, queryWithTypenameInput) => { + const mappedResultWithTypename = SelectionSetGraphqlMapper.toGraphQL( + Select.Document.normalizeOrThrow({ query: { x: queryWithTypenameInput as any } }) + ) + const mappedResultWithoutTypename = SelectionSetGraphqlMapper.toGraphQL( + Select.Document.normalizeOrThrow({ query: { x: queryWithoutTypenameInput as any } }) + ) + injectTypenameOnRootResultFields({ + request: graffleMappedToRequest(mappedResultWithoutTypename), + sddm: schemaDrivenDataMap, + }) + expect(mappedResultWithTypename.document).toMatchObject(mappedResultWithoutTypename.document) +}) + +// dprint-ignore +test(`gql string request`, async ({ kitchenSink }) => { + // todo it would be nicer to move the extension use to the fixture but how would we get the static type for that? + // This makes me think of a feature we need to have. Make it easy to get static types of the client in its various configured states. + const result = await kitchenSink.use(Throws()).throws().gql`query { resultNonNull (case: Object1) { ... on Object1 { id } } }`.send() + expect(result).toMatchObject({ resultNonNull: { __typename: `Object1`, id: `abc` } }) +}) + +test(`gql document request`, async ({ kitchenSink }) => { + const result = await kitchenSink.use(Throws()).throws().gql( + parse(`query { resultNonNull (case: Object1) { ... on Object1 { id } } }`), + ).send() + expect(result).toMatchObject({ resultNonNull: { __typename: `Object1`, id: `abc` } }) +}) diff --git a/src/layers/7_extensions/SchemaErrors/SchemaErrors.ts b/src/layers/7_extensions/SchemaErrors/SchemaErrors.ts new file mode 100644 index 000000000..50e04dd0b --- /dev/null +++ b/src/layers/7_extensions/SchemaErrors/SchemaErrors.ts @@ -0,0 +1,26 @@ +import { normalizeRequestToNode } from '../../../lib/grafaid/request.js' +import { injectTypenameOnRootResultFields } from '../../5_request/schemaErrors.js' +import { createExtension } from '../../6_client/extension/extension.js' + +// todo?: augment config to include how schema errors should be handled in the output +// todo: manipulate results: 1) schema errors should be thrown or returned (outside envelope) depending on config. +// todo: manipulate the types + +export const SchemaErrors = () => { + return createExtension({ + name: `SchemaErrors`, + onRequest: async ({ pack }) => { + const sddm = pack.input.state.config.schemaMap + if (!sddm) return pack() + + const request = normalizeRequestToNode(pack.input.request) + + // We will mutate query. Assign it back to input for it to be carried forward. + pack.input.request.query = request.query + + injectTypenameOnRootResultFields({ sddm, request }) + + return pack() + }, + }) +} diff --git a/src/layers/7_extensions/Throws/Throws.test.ts b/src/layers/7_extensions/Throws/Throws.test.ts index 4bb86a673..422111b80 100644 --- a/src/layers/7_extensions/Throws/Throws.test.ts +++ b/src/layers/7_extensions/Throws/Throws.test.ts @@ -53,15 +53,3 @@ describe(`$batch`, () => { await expect(graffle.throws().query.$batch({ error: true })).rejects.toMatchObject(db.errorAggregate) }) }) - -describe(`root field`, () => { - test(`without error`, async () => { - await expect(graffle.throws().query.objectWithArgs({ $: { id: `x` }, id: true })).resolves.toEqual({ - id: `x`, - __typename: `Object1`, - }) - }) - test(`with error`, async () => { - await expect(graffle.throws().query.error()).rejects.toMatchObject(db.errorAggregate) - }) -}) diff --git a/src/layers/7_extensions/Upload/Upload.test.ts b/src/layers/7_extensions/Upload/Upload.test.ts index 8a1dc3cb5..4d700f0fc 100644 --- a/src/layers/7_extensions/Upload/Upload.test.ts +++ b/src/layers/7_extensions/Upload/Upload.test.ts @@ -13,13 +13,12 @@ import type { OutputConfigDefault, TransportConfigHttp } from '../../6_client/Se let schemaServer: SchemaService let graffle: Client<{ config: { - schemaIndex: null + schemaMap: null transport: TransportConfigHttp output: OutputConfigDefault initialInput: { schema: URL } name: 'default' } - schemaIndex: null }> beforeAll(async () => { diff --git a/src/lib/Code.ts b/src/lib/Code.ts index b8c4d5057..73ce8a9f2 100644 --- a/src/lib/Code.ts +++ b/src/lib/Code.ts @@ -1,24 +1,92 @@ +import { entries, isString } from './prelude.js' import { linesPrepend, linesTrim } from './text.js' +type FieldTuple = [k: string, v: string] + export namespace Code { - export const propertyAccess = (object: string, name: string) => `${object}.${name}` - export const string = (str: string) => `"${str}"` - export const nullable = (type: string) => `${type} | null` - export const union = (name: string, types: string[]) => `type ${name} =\n| ${Code.unionItems(types)}` - export const unionItems = (types: string[]) => types.join(`\n| `) - export const tuple = (types: string[]) => `[${types.join(`, `)}]` - export const list = (type: string) => `Array<${type}>` - export const termField = (name: string, type: string, options?: { comma?: boolean }) => { - return `${name}: ${type}${(options?.comma ?? true) ? `,` : ``}` - } export const field = (name: string, type: string, options?: { optional?: boolean }) => { if (options?.optional) return `${name}?: ${type}` return `${name}: ${type}` } + export interface TermObjectWith { + $spread?: string[] + $fields?: TermObject | TermObjectWith + $literal?: string + } + + export type TermPrimitive = string | number | boolean + + export type TermObjectWithLike<$Fields extends null | TermObject | TermObjectWith = null> = { + $spread?: string[] + $literal?: string + } & ($Fields extends null ? { $fields?: TermObject | TermObjectWith } : { $fields: $Fields }) + + const isTermObjectWith = (value: unknown): value is TermObjectWith => { + if (typeof value !== `object` || value === null) return false + return Object.keys(value).some(key => key === `$spread` || key === `$fields` || key === `$fieldsMerge`) + } + + export interface TermObject { + [key: string]: TermPrimitive | TermObjectWith | TermObject + } + + export type TermObjectOf = { + [key: string]: T + } + + export const termObjectWith = (objectWith: TermObjectWith): string => { + // const object = [...(objectWith.$fields ? [objectWith.$fields] : []), ...(objectWith.$fieldsMerge ?? [])].reduce( + // (finalO, o) => { + // if (isTermObjectWith(o)) { + // return { ...finalO, ...o } + // } + // return { ...finalO, ...o } + // }, + // {}, + // ) + const spreads = (objectWith.$spread ?? []).map(spread => `...${spread},`) + return block( + spreads.join(`\n`) + `\n` + termObjectFields(objectWith.$fields ?? {}) + + (objectWith.$literal ? `\n${objectWith.$literal}` : ``), + ) + } + // terms + export const termObject = (object: TermObject): string => { + return block(termObjectFields(object)) + } + export const termObjectFields = (object: TermObject | TermObjectWith): string => + termFieldsFromTuples( + entries(object).map(([key, value]): FieldTuple => { + const valueNormalized = isTermObjectWith(value) + ? termObjectWith(value) + : isString(value) || typeof value === `number` || typeof value === `boolean` + ? String(value) + : termObject(value as any) + return [key, valueNormalized] + }), + ) + + export const termFieldsFromTuples = (fields: FieldTuple[]) => fields.map(termFieldFromTuple).join(`\n`) + export const termList = (value: string[]) => `[${value.join(`, `)}]` + export const termFieldFromTuple = (tuple: FieldTuple) => Code.termField(tuple[0], tuple[1]) + export const termField = (name: string, type: string, options?: { comma?: boolean }) => { + return `${name}: ${type}${(options?.comma ?? true) ? `,` : ``}` + } + export const termConst = (name: string, value?: string) => termConstTyped(name, null, value) + export const termConstTyped = (name: string, type: string | null, value?: string) => + `const ${name} ${type ? `:${type}` : ``} = ${value ?? ``}` + + // type + export const nullable = (type: string) => `${type} | null` + export const union = (name: string, types: string[]) => `type ${name} =\n| ${Code.unionItems(types)}` + export const unionItems = (types: string[]) => types.join(`\n| `) + export const tuple = (types: string[]) => termList(types) + export const list = (type: string) => `Array<${type}>` export const optionalField = (name: string, type: string) => Code.field(name, type, { optional: true }) export const fields = (fieldTypes: string[]) => fieldTypes.join(`\n`) export const intersection = (a: string, b: string) => `${a} & ${b}` export const object = (fields: string) => `{\n${fields}\n}` + export const objectFromEntries = (entries: readonly (readonly [string, string])[]) => Code.objectFrom(Object.fromEntries(entries.map(([name, type]) => [name, { type }]))) export const objectFrom = ( @@ -38,10 +106,15 @@ export namespace Code { ), ) } - export const boolean = (value: boolean) => value ? `true` : `false` export const type = (name: string, type: string) => `type ${name} = ${type}` export const interface$ = (name: string, object: string) => `interface ${name} ${object}` export const export$ = (thing: string) => `export ${thing}` + export const namespace = (name: string, content: string) => `namespace ${name} ${Code.object(content)}` + // term or type + export const propertyAccess = (object: string, name: string) => `${object}.${name}` + export const string = (str: string) => `"${str}"` + export const block = (content: string) => `{\n${content}\n}` + export const boolean = (value: boolean) => value ? `true` : `false` export const TSDoc = <$Content extends string | null>(content: $Content): $Content => { return (content === null ? null : `/**\n${linesPrepend(`* `, linesTrim(content)) || `*`}\n*/`) as $Content } @@ -50,7 +123,6 @@ export namespace Code { return tsDoc === null ? block : `${tsDoc}\n${block}` } - export const namespace = (name: string, content: string) => `namespace ${name} ${Code.object(content)}` export const group = (...content: string[]) => content.join(`\n`) export const commentSectionTitle = (title: string) => { const lineSize = 60 diff --git a/src/lib/anyware/__.test-d.ts b/src/lib/anyware/__.test-d.ts index b29047dc0..c1fa1b1e0 100644 --- a/src/lib/anyware/__.test-d.ts +++ b/src/lib/anyware/__.test-d.ts @@ -1,7 +1,6 @@ /* eslint-disable */ import { describe, expectTypeOf, test } from 'vitest' -import { Result } from '../../../tests/_/schemas/kitchen-sink/graffle/modules/SchemaRuntime.js' import { ContextualError } from '../errors/ContextualError.js' import { type MaybePromise } from '../prelude.js' import { Anyware } from './__.js' diff --git a/src/lib/grafaid/_.ts b/src/lib/grafaid/_.ts index 971fcc91e..57229b68c 100644 --- a/src/lib/grafaid/_.ts +++ b/src/lib/grafaid/_.ts @@ -1,4 +1,4 @@ -export { $Schema as Schema } from './document.js' -export * as Nodes from './document.js' +export * as Document from './document.js' export * from './graphql.js' export * as HTTP from './http/http.js' +export * as Schema from './schema/schema.js' diff --git a/src/lib/grafaid/document.ts b/src/lib/grafaid/document.ts index 58a2e015d..575d9ba37 100644 --- a/src/lib/grafaid/document.ts +++ b/src/lib/grafaid/document.ts @@ -6,6 +6,7 @@ import { type EnumValueNode, type FieldNode, type FloatValueNode, + type FragmentSpreadNode, type InlineFragmentNode, type IntValueNode, Kind, @@ -16,15 +17,19 @@ import { type ObjectFieldNode, type ObjectValueNode, type OperationDefinitionNode, + OperationTypeNode, + parse, print as graphqlPrint, type SelectionSetNode, type StringValueNode, + type TypeNode, type ValueNode, type VariableDefinitionNode, type VariableNode, } from 'graphql' import type { HasRequiredKeys } from 'type-fest' import { isString } from '../prelude.js' +import type { RequestDocumentNodeInput, RequestInput } from './graphql.js' import { TypedDocument } from './typed-document/__.js' export type { @@ -35,6 +40,7 @@ export type { DocumentNode, FieldNode, FloatValueNode, + FragmentSpreadNode, InlineFragmentNode, IntValueNode, ListValueNode, @@ -43,10 +49,13 @@ export type { ObjectFieldNode, ObjectValueNode, OperationDefinitionNode, + OperationTypeDefinitionNode, + OperationTypeNode, SelectionNode, SelectionSetNode, StringValueNode, ValueNode, + VariableDefinitionNode, VariableNode, } from 'graphql' @@ -54,10 +63,6 @@ export { Kind } from 'graphql' export * as Typed from './typed-document/TypedDocument.js' -export { getNamedType } from 'graphql' - -export * as $Schema from './schema/schema.js' - export type $Any = | DirectiveNode | NameNode @@ -68,6 +73,7 @@ export type $Any = | OperationDefinitionNode | NamedTypeNode | FieldNode + | FragmentSpreadNode | DocumentNode | ArgumentNode | EnumValueNode @@ -126,7 +132,7 @@ export const Document: Constructor = (document) => { } export const isDocumentNode = (value: unknown): value is DocumentNode => { - return typeof value === `object` && value !== null && `kind` in value && value.kind === `Document` + return typeof value === `object` && value !== null && `kind` in value && value.kind === Kind.DOCUMENT } export const OperationDefinition: Constructor = (operationDefinition) => { @@ -135,6 +141,9 @@ export const OperationDefinition: Constructor = (operat ...operationDefinition, } } +export const isOperationDefinitionNode = (value: unknown): value is OperationDefinitionNode => { + return typeof value === `object` && value !== null && `kind` in value && value.kind === Kind.OPERATION_DEFINITION +} export const SelectionSet: Constructor = (selectionSet) => { return { @@ -164,6 +173,10 @@ export const NamedType: Constructor = (namedType) => { } } +export const isNamedType = (value: unknown): value is NamedTypeNode => { + return typeof value === `object` && value !== null && `kind` in value && value.kind === Kind.NAMED_TYPE +} + export const Field: Constructor = (field) => { return { kind: Kind.FIELD, @@ -246,7 +259,87 @@ export const OperationTypeToAccessKind = { subscription: `read`, } as const -export const print = (document: TypedDocument.TypedDocument): string => { +export const print = (document: TypedDocument.TypedDocumentLike): string => { const documentUntyped = TypedDocument.unType(document) return isString(documentUntyped) ? documentUntyped : graphqlPrint(documentUntyped) } + +export const getNamedType = (type: TypeNode): NamedTypeNode => { + if (type.kind === Kind.NAMED_TYPE) return type + return getNamedType(type.type) +} + +export const getOperationDefinition = ( + request: RequestDocumentNodeInput, +): OperationDefinitionNode | null => { + for (const node of request.query.definitions) { + const opDefNode = isOperationDefinitionNode(node) ? node : null + if (!request.operationName) return opDefNode + if (opDefNode?.name?.value === request.operationName) return opDefNode + } + return null +} + +const definedOperationPattern = new RegExp(`^\\b(${Object.values(OperationTypeNode).join(`|`)})\\b`) + +/** + * Get the _type_ (query, mutation, subscription) of operation a request will execute as. + * + * Compares the given operation name with document contents. + * + * If document is string then regular expressions are used to extract the operation type + * to avoid document encode/decode performance costs. + */ +export const getOperationType = (request: RequestInput): OperationTypeNode | null => { + const { operationName, query: document } = request + + const documentUntyped = TypedDocument.unType(document) + + if (!isString(documentUntyped)) { + const operationDefinition = getOperationDefinition({ query: documentUntyped, operationName }) + if (operationDefinition) return operationDefinition.operation + throw new Error(`Could not parse operation type from document.`) + } + + const definedOperations = documentUntyped.split(/[{}\n]+/).map(s => s.trim()).map(line => { + const match = line.match(definedOperationPattern) + if (!match) return null + return { + line, + operationType: match[0] as OperationTypeNode, + } + }).filter(_ => _ !== null) + + // Handle obviously invalid cases that are zero cost to compute. + + // The given operation name will not match to anything. + if (definedOperations.length > 1 && !request.operationName) return null + + // An operation name is required but was not given. + if (definedOperations.length === 0 && request.operationName) return null + + // Handle optimistically assumed valid case short circuits. + + if (definedOperations.length === 0) { + // Assume that the implicit query syntax is being used. + // This is a non-validated optimistic approach for performance, not aimed at correctness. + // For example its not checked if the document is actually of the syntactic form `{ ... }` + return OperationTypeNode.QUERY + } + + // Continue to the full search. + + const definedOperationToAnalyze = operationName + ? definedOperations.find(o => o.line.includes(operationName)) + : definedOperations[0] + + // Invalid: The given operation name does not show up in the document. + if (!definedOperationToAnalyze) return null + + return definedOperationToAnalyze.operationType +} + +export const normalizeDocumentToNode = (document: TypedDocument.TypedDocumentLike): DocumentNode => { + const d = TypedDocument.unType(document) + return isString(d) ? parse(d) : d +} diff --git a/src/lib/grafaid/graphql.test.ts b/src/lib/grafaid/graphql.test.ts index 5f14dd877..abe089d67 100644 --- a/src/lib/grafaid/graphql.test.ts +++ b/src/lib/grafaid/graphql.test.ts @@ -15,7 +15,7 @@ type CaseParameters = [ result: null | OperationTypeNode, ] -describe(`parseGraphQLOperationType`, () => { +describe(`getOperationType`, () => { // dprint-ignore test.each([ @@ -30,6 +30,6 @@ describe(`parseGraphQLOperationType`, () => { [ `mutation if only operation without name and no operation given `, { query: `mutation { user { name } }` }, OperationTypeNode.MUTATION ], [ `overloaded terms do not confuse parser`, { query: docOverloadedTerms }, OperationTypeNode.QUERY ], ])(`%s`, (_, request, result) => { - expect(Grafaid.parseOperationType(request)).toEqual(result) + expect(Grafaid.Document.getOperationType(request)).toEqual(result) }) }) diff --git a/src/lib/grafaid/graphql.ts b/src/lib/grafaid/graphql.ts index f795073e5..e2613d10b 100644 --- a/src/lib/grafaid/graphql.ts +++ b/src/lib/grafaid/graphql.ts @@ -1,13 +1,5 @@ -import type { GraphQLEnumValue, GraphQLError, GraphQLField, GraphQLInputField, GraphQLNamedType } from 'graphql' +import type { GraphQLNamedType, GraphQLScalarType } from 'graphql' import { - GraphQLEnumType, - GraphQLInputObjectType, - GraphQLInterfaceType, - GraphQLList, - GraphQLNonNull, - GraphQLObjectType, - GraphQLScalarType, - GraphQLUnionType, isEnumType, isInputObjectType, isInterfaceType, @@ -16,12 +8,10 @@ import { isUnionType, OperationTypeNode, } from 'graphql' -import type { Errors } from '../errors/__.js' -import { isString } from '../prelude.js' -import { Nodes } from './_Nodes.js' -import { TypedDocument } from './typed-document/__.js' +import type { DescribableTypes, NodeNamePlus } from './schema/schema.js' export * from './_Nodes.js' +export * from './request.js' export const StandardScalarTypeNames = { String: `String`, @@ -51,11 +41,7 @@ export const StandardScalarTypeTypeScriptMapping = { TypeScriptPrimitiveTypeNames > -export type TypeNamedKind = `Enum` | `InputObject` | `Interface` | `Object` | `Scalar` | `Union` - -export type TypeMapKind = TypeNamedKind | `Root` - -export const operationTypeNameToRootTypeName = { +export const operationTypeToRootType = { query: `Query`, mutation: `Mutation`, subscription: `Subscription`, @@ -73,55 +59,10 @@ export const isStandardScalarType = (type: GraphQLScalarType) => { return type.name in StandardScalarTypeNames } -export type ClassToName = C extends GraphQLScalarType ? `GraphQLScalarType` - : C extends GraphQLObjectType ? `GraphQLObjectType` - : C extends GraphQLInterfaceType ? `GraphQLInterfaceType` - : C extends GraphQLUnionType ? `GraphQLUnionType` - : C extends GraphQLEnumType ? `GraphQLEnumType` - : C extends GraphQLInputObjectType ? `GraphQLInputObjectType` - : C extends GraphQLList ? `GraphQLList` - : C extends GraphQLNonNull ? `GraphQLNonNull` - : never - -export const NamedNameToClass = { - GraphQLScalarType: GraphQLScalarType, - GraphQLObjectType: GraphQLObjectType, - GraphQLInterfaceType: GraphQLInterfaceType, - GraphQLUnionType: GraphQLUnionType, - GraphQLEnumType: GraphQLEnumType, - GraphQLInputObjectType: GraphQLInputObjectType, -} as const - -export type NamedNameToClass = typeof NamedNameToClass - -export const NameToClass = { - GraphQLNonNull: GraphQLNonNull, - GraphQLList: GraphQLList, - ...NamedNameToClass, -} as const - -export type AnyGraphQLOutputField = GraphQLField - -export type AnyField = AnyGraphQLOutputField | GraphQLInputField - -export type NameToClass = typeof NameToClass - -export type NodeName = keyof NameToClass - -export type NodeNamePlus = NodeName | 'GraphQLField' - -export type AnyNamedClassName = keyof NamedNameToClass - -export type AnyClass = InstanceType - /** * Groups */ -export type Describable = - | GraphQLNamedType - | AnyField - export const getTypeNameAndKind = ( node: GraphQLNamedType, ): { name: string; kind: 'Object' | 'Interface' | 'Union' | 'Enum' | 'Scalar' } => { @@ -135,26 +76,7 @@ export const getTypeNameAndKind = ( return { name, kind } } -export const getTypeKind = <$Node extends GraphQLNamedType>(node: $Node): ClassToName<$Node> => { - switch (true) { - case isObjectType(node): - return `GraphQLObjectType` as ClassToName<$Node> - case isInputObjectType(node): - return `GraphQLInputObjectType` as ClassToName<$Node> - case isUnionType(node): - return `GraphQLUnionType` as ClassToName<$Node> - case isInterfaceType(node): - return `GraphQLInterfaceType` as ClassToName<$Node> - case isEnumType(node): - return `GraphQLEnumType` as ClassToName<$Node> - case isScalarType(node): - return `GraphQLScalarType` as ClassToName<$Node> - default: - throw new Error(`Unknown node kind: ${String(node)}`) - } -} - -export const getNodeKindOld = (node: Describable): NodeNamePlus => { +export const getNodeKindOld = (node: DescribableTypes): NodeNamePlus => { switch (true) { case isObjectType(node): return `GraphQLObjectType` @@ -173,85 +95,10 @@ export const getNodeKindOld = (node: Describable): NodeNamePlus => { } } -export const getNodeDisplayName = (node: Describable) => { +export const getNodeDisplayName = (node: DescribableTypes) => { return toDisplayName(getNodeKindOld(node)) } const toDisplayName = (nodeName: NodeNamePlus) => { return nodeName.replace(/^GraphQL/, ``).replace(/Type$/, ``) } - -export const isDeprecatableNode = (node: object): node is GraphQLEnumValue | AnyField => { - return `deprecationReason` in node -} - -export interface RequestInput { - query: string | TypedDocument.TypedDocument - variables?: Variables - operationName?: string -} - -export type Variables = { - [key: string]: string | boolean | null | number | Variables -} - -export type SomeData = Record - -export type GraphQLExecutionResultError = Errors.ContextualAggregateError - -const definedOperationPattern = new RegExp(`^\\b(${Object.values(OperationTypeNode).join(`|`)})\\b`) - -export const parseOperationType = (request: RequestInput): OperationTypeNode | null => { - const { operationName, query: document } = request - - const documentUntyped = TypedDocument.unType(document) - - if (!isString(documentUntyped)) { - for (const node of documentUntyped.definitions) { - if (node.kind === Nodes.Kind.OPERATION_DEFINITION) { - if (operationName ? node.name?.value === operationName : true) { - return node.operation - } - } - } - throw new Error(`Could not parse operation type from document.`) - } - - const definedOperations = documentUntyped.split(/[{}\n]+/).map(s => s.trim()).map(line => { - const match = line.match(definedOperationPattern) - if (!match) return null - return { - line, - operationType: match[0] as OperationTypeNode, - } - }).filter(_ => _ !== null) - // console.log(definedOperations) - - // Handle obviously invalid cases that are zero cost to compute. - - // The given operation name will not match to anything. - if (definedOperations.length > 1 && !request.operationName) return null - - // An operation name is required but was not given. - if (definedOperations.length === 0 && request.operationName) return null - - // Handle optimistically assumed valid case short circuits. - - if (definedOperations.length === 0) { - // Assume that the implicit query syntax is being used. - // This is a non-validated optimistic approach for performance, not aimed at correctness. - // For example its not checked if the document is actually of the syntactic form `{ ... }` - return OperationTypeNode.QUERY - } - - // Continue to the full search. - - const definedOperationToAnalyze = operationName - ? definedOperations.find(o => o.line.includes(operationName)) - : definedOperations[0] - - // Invalid: The given operation name does not show up in the document. - if (!definedOperationToAnalyze) return null - - return definedOperationToAnalyze.operationType -} diff --git a/src/lib/grafaid/request.ts b/src/lib/grafaid/request.ts new file mode 100644 index 000000000..21b4d3574 --- /dev/null +++ b/src/lib/grafaid/request.ts @@ -0,0 +1,62 @@ +import type { GraphQLError, OperationDefinitionNode, OperationTypeNode } from 'graphql' +import type { Errors } from '../errors/__.js' +import { getOperationDefinition, normalizeDocumentToNode } from './document.js' +import type { RootTypeName } from './schema/schema.js' +import type { TypedDocument } from './typed-document/__.js' + +export interface RequestInput { + query: string | TypedDocument.TypedDocumentLike + variables?: Variables + operationName?: string +} + +export interface RequestDocumentNodeInput { + query: TypedDocument.TypedDocumentNodeLike + variables?: Variables + operationName?: string +} + +export interface RequestAnalyzedInput extends RequestInput { + operation: OperationTypeNode | OperationDefinitionNode + rootType: RootTypeName +} + +export interface RequestAnalyzedDocumentNodeInput extends RequestDocumentNodeInput { + operation: OperationDefinitionNode + rootType: RootTypeName +} + +export type Variables = { + [key: string]: string | boolean | null | number | Variables +} + +export type SomeData = Record + +export type GraphQLExecutionResultError = Errors.ContextualAggregateError + +// dprint-ignore +export const normalizeRequestToNode = <$R extends RequestInput | RequestAnalyzedInput>(request: $R): + $R extends RequestAnalyzedInput ? RequestAnalyzedDocumentNodeInput : + $R extends RequestInput ? RequestDocumentNodeInput : + never => { + + const query = normalizeDocumentToNode(request.query) + + if (`operation` in request) { + const operation = getOperationDefinition({ + ...request, + query: normalizeDocumentToNode(request.query), + }) + + return { + ...request, + operation, + query, + } as any + } + + return { + ...request, + query, + } as any +} diff --git a/src/lib/grafaid/schema/customScalars.ts b/src/lib/grafaid/schema/customScalars.ts index 6121841a5..a2c51e91a 100644 --- a/src/lib/grafaid/schema/customScalars.ts +++ b/src/lib/grafaid/schema/customScalars.ts @@ -15,9 +15,9 @@ import { casesExhausted } from '../../prelude.js' import { isGraphQLArgumentOrInputField, isGraphQLField, isScalarTypeAndCustom } from './schema.js' export const isHasCustomScalars = ( - node: GraphQLNamedOutputType | GraphQLField | GraphQLInputObjectType, + node: GraphQLNamedOutputType | GraphQLField | GraphQLInputObjectType | GraphQLInputField | GraphQLArgument, ): boolean => { - if (isInputObjectType(node)) { + if (isInputObjectType(node) || isGraphQLArgumentOrInputField(node)) { return isHasCustomScalarInputs(node) } diff --git a/src/lib/grafaid/schema/schema.ts b/src/lib/grafaid/schema/schema.ts index c5542dc1d..3d396823f 100644 --- a/src/lib/grafaid/schema/schema.ts +++ b/src/lib/grafaid/schema/schema.ts @@ -1,34 +1,54 @@ import { type GraphQLArgument, GraphQLEnumType, + type GraphQLEnumValue, type GraphQLField, type GraphQLInputField, GraphQLInterfaceType, + GraphQLList, + type GraphQLNamedType, + GraphQLNonNull, GraphQLObjectType, GraphQLScalarType, GraphQLUnionType, + isEnumType, + isInputObjectType, + isInterfaceType, isNonNullType, isObjectType, + isUnionType, } from 'graphql' import { GraphQLInputObjectType, isScalarType } from 'graphql' -import type { AnyGraphQLOutputField } from '../graphql.js' export { + getNamedType, getNullableType, - GraphQLInputObjectType, - GraphQLInterfaceType, - GraphQLList, - GraphQLNonNull, - GraphQLObjectType, - GraphQLScalarType, - GraphQLSchema, - type GraphQLType, - GraphQLUnionType, + type GraphQLArgument as Argument, + GraphQLEnumType as EnumType, + type GraphQLEnumValue as EnumValue, + type GraphQLField as Field, + type GraphQLInputField as InputField, + GraphQLInputObjectType as InputObjectType, + type GraphQLInputType as InputTypes, + GraphQLInterfaceType as InterfaceType, + GraphQLList as ListType, + type GraphQLNamedType as NamedTypes, + GraphQLNonNull as NonNullType, + GraphQLObjectType as ObjectType, + GraphQLScalarType as ScalarType, + GraphQLSchema as Schema, + type GraphQLType as Types, + GraphQLUnionType as UnionType, + isEnumType, isInputObjectType, isInterfaceType, isListType, + isNamedType, + isNonNullType, isNullableType, isObjectType, + isRequiredArgument, + isRequiredInputField, isScalarType, isUnionType, } from 'graphql' @@ -37,7 +57,40 @@ export * as Args from './args.js' export * as CustomScalars from './customScalars.js' export * as KindMap from './kindMap.js' -export const isGraphQLOutputField = (object: object): object is AnyGraphQLOutputField => { +export type DeprecatableNodes = GraphQLEnumValue | InputOrOutputField + +export const isDeprecatableNode = (node: object): node is DeprecatableNodes => { + return `deprecationReason` in node +} + +export type InputOrOutputField = GraphQLField | GraphQLInputField + +export type AnyNamedClassName = keyof NamedNameToClass + +export type NamedNameToClass = typeof NamedNameToClass + +export type NameToClass = typeof NameToClass + +export const NamedNameToClass = { + GraphQLScalarType: GraphQLScalarType, + GraphQLObjectType: GraphQLObjectType, + GraphQLInterfaceType: GraphQLInterfaceType, + GraphQLUnionType: GraphQLUnionType, + GraphQLEnumType: GraphQLEnumType, + GraphQLInputObjectType: GraphQLInputObjectType, +} as const + +export const NameToClass = { + GraphQLNonNull: GraphQLNonNull, + GraphQLList: GraphQLList, + ...NamedNameToClass, +} as const + +export type DescribableTypes = + | GraphQLNamedType + | InputOrOutputField + +export const isGraphQLOutputField = (object: object): object is GraphQLField => { return `args` in object } @@ -89,3 +142,44 @@ export type RootTypeNameSubscription = typeof RootTypeName['Subscription'] export const isRootType = (value: unknown): value is GraphQLObjectType => { return isObjectType(value) && value.name in RootTypeName } + +export type NodeName = keyof NameToClass + +export type NodeNamePlus = NodeName | 'GraphQLField' + +// export type AnyClass = InstanceType + +// dprint-ignore +export type ClassToName = + C extends GraphQLScalarType ? `GraphQLScalarType` + : C extends GraphQLObjectType ? `GraphQLObjectType` + : C extends GraphQLInterfaceType ? `GraphQLInterfaceType` + : C extends GraphQLUnionType ? `GraphQLUnionType` + : C extends GraphQLEnumType ? `GraphQLEnumType` + : C extends GraphQLInputObjectType ? `GraphQLInputObjectType` + : C extends GraphQLList ? `GraphQLList` + : C extends GraphQLNonNull ? `GraphQLNonNull` + : never + +export const getTypeKind = <$Node extends GraphQLNamedType>(node: $Node): ClassToName<$Node> => { + switch (true) { + case isObjectType(node): + return `GraphQLObjectType` as ClassToName<$Node> + case isInputObjectType(node): + return `GraphQLInputObjectType` as ClassToName<$Node> + case isUnionType(node): + return `GraphQLUnionType` as ClassToName<$Node> + case isInterfaceType(node): + return `GraphQLInterfaceType` as ClassToName<$Node> + case isEnumType(node): + return `GraphQLEnumType` as ClassToName<$Node> + case isScalarType(node): + return `GraphQLScalarType` as ClassToName<$Node> + default: + throw new Error(`Unknown node kind: ${String(node)}`) + } +} + +export type TypeNamedKind = `Enum` | `InputObject` | `Interface` | `Object` | `Scalar` | `Union` + +export type NamedTypeKind = TypeNamedKind | `Root` diff --git a/src/lib/grafaid/typed-document/TypedDocument.ts b/src/lib/grafaid/typed-document/TypedDocument.ts index 21b00755c..c816243db 100644 --- a/src/lib/grafaid/typed-document/TypedDocument.ts +++ b/src/lib/grafaid/typed-document/TypedDocument.ts @@ -1,5 +1,5 @@ import type { DocumentTypeDecoration } from '@graphql-typed-document-node/core' -import type { DocumentNode, TypedQueryDocumentNode } from 'graphql' +import { type DocumentNode, type TypedQueryDocumentNode } from 'graphql' import type { HasRequiredKeys, IsNever, IsUnknown } from 'type-fest' import { type HasKeys, type IsHasIndexType } from '../../prelude.js' import type { SomeData, Variables } from '../graphql.js' @@ -14,11 +14,15 @@ export { type TypedQueryDocumentNode as Query } from 'graphql' // types are allowed. // dprint-ignore -export type TypedDocument<$Result extends SomeData = SomeData, $Variables extends Variables = any> = +export type TypedDocumentLike<$Result extends SomeData = SomeData, $Variables extends Variables = any> = | TypedQueryDocumentNode<$Result, $Variables> | TypedDocumentString <$Result, $Variables> | TypedDocumentNode <$Result, $Variables> +export type TypedDocumentNodeLike<$Result extends SomeData = SomeData, $Variables extends Variables = any> = + | TypedQueryDocumentNode<$Result, $Variables> + | TypedDocumentNode<$Result, $Variables> + /** * @remarks From package \@graphql-typed-document-node/core in theory but not exported * @see https://github.com/dotansimha/graphql-typed-document-node/issues/163 @@ -73,21 +77,21 @@ export type VariablesInputKindOptional = 'optional' // // Document Helpers -export const isString = <$TypedDocument extends TypedDocument>( +export const isString = <$TypedDocument extends TypedDocumentLike>( document: $TypedDocument, ): document is Exclude<$TypedDocument, TypedDocumentNode | TypedQueryDocumentNode> => typeof document === `string` -export const unType = (document: TypedDocument): string | DocumentNode => document as any +export const unType = (document: TypedDocumentLike): string | DocumentNode => document as any // dprint-ignore -export type ResultOf<$Document extends TypedDocument> = +export type ResultOf<$Document extends TypedDocumentLike> = $Document extends TypedQueryDocumentNode ? $R : $Document extends TypedDocumentNode ? $R : $Document extends TypedDocumentString ? $R : never // dprint-ignore -export type VariablesOf<$Document extends TypedDocument> = +export type VariablesOf<$Document extends TypedDocumentLike> = $Document extends TypedDocumentString ? $V : $Document extends TypedQueryDocumentNode ? $V : $Document extends TypedDocumentNode ? IsUnknown<$V> extends true diff --git a/src/lib/prelude.ts b/src/lib/prelude.ts index e3b0b7dcb..9f8e082a1 100644 --- a/src/lib/prelude.ts +++ b/src/lib/prelude.ts @@ -625,3 +625,18 @@ export type IsHasIndexType = string extends keyof T ? true : false export const isString = (value: unknown): value is string => { return typeof value === 'string' } + +export const isSymbol = (value: unknown): value is symbol => { + return typeof value === 'symbol' +} + +export const isNonNull = <$Value>(value: $Value): value is ExcludeNull<$Value> => { + return value !== null +} + +export const findTyped = <$Value, $Result>( + values: readonly $Value[], + looker: (value: $Value) => null | $Result, +): undefined | $Result => { + return values.find((value) => Boolean(looker(value))) as undefined | $Result +} diff --git a/src/lib/template-string.ts b/src/lib/template-string.ts new file mode 100644 index 000000000..fe357fa24 --- /dev/null +++ b/src/lib/template-string.ts @@ -0,0 +1,17 @@ +export type TemplateStringsArguments = [TemplateStringsArray, ...unknown[]] + +export const isTemplateStringArguments = (args: [...unknown[]]): args is TemplateStringsArguments => { + return isTemplateStringArray(args[0]) +} + +export const isTemplateStringArray = (arg: any): arg is TemplateStringsArray => { + return Array.isArray(arg) && `raw` in arg && arg.raw !== undefined +} + +export const joinTemplateStringArrayAndArgs = (args: TemplateStringsArguments): string => { + const [templateParts, ...templateArgs] = args + return templateParts.reduce( + (string, part, index) => `${string}${part}${index in templateArgs ? String(templateArgs[index]) : ``}`, + ``, + ) +} diff --git a/tests/_/SpyExtension.ts b/tests/_/SpyExtension.ts index 584f5d1f4..8a37f2020 100644 --- a/tests/_/SpyExtension.ts +++ b/tests/_/SpyExtension.ts @@ -1,19 +1,47 @@ import { beforeEach } from 'vitest' import { createExtension } from '../../src/entrypoints/main.js' +import type { Config } from '../../src/entrypoints/utilities-for-generated.js' +import type { HookDefEncode, HookDefExchange, HookDefPack } from '../../src/layers/5_request/hooks.js' export const Spy = () => createExtension({ - name: `spy`, - onRequest: ({ exchange }) => { - if (exchange.input.transportType === `memory`) { - Spy.input = exchange.input - } + name: `Spy`, + onRequest: async ({ encode }) => { + Spy.data.encode.input = encode.input + const { pack } = await encode() + Spy.data.pack.input = pack.input + const { exchange } = await pack() + Spy.data.exchange.input = exchange.input return exchange() }, }) -Spy.input = undefined as object | undefined +interface SpyData { + encode: { + input: HookDefEncode['input'] | null + } + pack: { + input: HookDefPack['input'] | null + } + exchange: { + input: HookDefExchange['input'] | null + } +} + +const emptySpyData: SpyData = { + encode: { + input: null, + }, + pack: { + input: null, + }, + exchange: { + input: null, + }, +} + +Spy.data = emptySpyData beforeEach(() => { - Spy.input = undefined + Spy.data = emptySpyData }) diff --git a/tests/_/schemas/kitchen-sink/graffle/modules/Client.ts b/tests/_/schemas/kitchen-sink/graffle/modules/Client.ts index 44d3c2d07..bd2e48835 100644 --- a/tests/_/schemas/kitchen-sink/graffle/modules/Client.ts +++ b/tests/_/schemas/kitchen-sink/graffle/modules/Client.ts @@ -1,4 +1,5 @@ import { createPrefilled } from '../../../../../../src/entrypoints/client.js' -import { $defaultSchemaUrl, $Index } from './SchemaRuntime.js' +import { defaultSchemaUrl } from './Data.js' +import { schemaDrivenDataMap } from './SchemaDrivenDataMap.js' -export const create = createPrefilled(`default`, $Index, $defaultSchemaUrl) +export const create = createPrefilled(`default`, schemaDrivenDataMap, defaultSchemaUrl) diff --git a/tests/_/schemas/kitchen-sink/graffle/modules/Data.ts b/tests/_/schemas/kitchen-sink/graffle/modules/Data.ts index dd4ec32fe..ef2ad4cf6 100644 --- a/tests/_/schemas/kitchen-sink/graffle/modules/Data.ts +++ b/tests/_/schemas/kitchen-sink/graffle/modules/Data.ts @@ -1,2 +1,4 @@ export const Name = `default` export type Name = 'default' + +export const defaultSchemaUrl = undefined diff --git a/tests/_/schemas/kitchen-sink/graffle/modules/MethodsRoot.ts b/tests/_/schemas/kitchen-sink/graffle/modules/MethodsRoot.ts index a563c1007..38dca2462 100644 --- a/tests/_/schemas/kitchen-sink/graffle/modules/MethodsRoot.ts +++ b/tests/_/schemas/kitchen-sink/graffle/modules/MethodsRoot.ts @@ -24,20 +24,20 @@ export interface MutationMethods<$Config extends Utils.Config> { 'Mutation' > > - id: () => Promise< + id: <$SelectionSet>(selectionSet?: Utils.Exact<$SelectionSet, SelectionSet.Mutation.id>) => Promise< Utils.ResolveOutputReturnRootField< $Config, Index, 'id', - InferResult.Field + InferResult.Field<$SelectionSet, Index['Root']['Mutation']['fields']['id'], Index> > > - idNonNull: () => Promise< + idNonNull: <$SelectionSet>(selectionSet?: Utils.Exact<$SelectionSet, SelectionSet.Mutation.idNonNull>) => Promise< Utils.ResolveOutputReturnRootField< $Config, Index, 'idNonNull', - InferResult.Field + InferResult.Field<$SelectionSet, Index['Root']['Mutation']['fields']['idNonNull'], Index> > > } @@ -64,23 +64,23 @@ export interface QueryMethods<$Config extends Utils.Config> { > > InputObjectNested: <$SelectionSet>( - args?: Utils.Exact<$SelectionSet, SelectionSet.Query.InputObjectNested$SelectionSetArguments>, + selectionSet?: Utils.Exact<$SelectionSet, SelectionSet.Query.InputObjectNested>, ) => Promise< Utils.ResolveOutputReturnRootField< $Config, Index, 'InputObjectNested', - InferResult.Field + InferResult.Field<$SelectionSet, Index['Root']['Query']['fields']['InputObjectNested'], Index> > > InputObjectNestedNonNull: <$SelectionSet>( - args: Utils.Exact<$SelectionSet, SelectionSet.Query.InputObjectNestedNonNull$SelectionSetArguments>, + selectionSet: Utils.Exact<$SelectionSet, SelectionSet.Query.InputObjectNestedNonNull>, ) => Promise< Utils.ResolveOutputReturnRootField< $Config, Index, 'InputObjectNestedNonNull', - InferResult.Field + InferResult.Field<$SelectionSet, Index['Root']['Query']['fields']['InputObjectNestedNonNull'], Index> > > /** @@ -94,72 +94,78 @@ export interface QueryMethods<$Config extends Utils.Config> { InferResult.Field<$SelectionSet, Index['Root']['Query']['fields']['abcEnum'], Index> > > - date: () => Promise< + argInputObjectCircular: <$SelectionSet>( + selectionSet?: Utils.Exact<$SelectionSet, SelectionSet.Query.argInputObjectCircular>, + ) => Promise< + Utils.ResolveOutputReturnRootField< + $Config, + Index, + 'argInputObjectCircular', + InferResult.Field<$SelectionSet, Index['Root']['Query']['fields']['argInputObjectCircular'], Index> + > + > + date: <$SelectionSet>(selectionSet?: Utils.Exact<$SelectionSet, SelectionSet.Query.date>) => Promise< Utils.ResolveOutputReturnRootField< $Config, Index, 'date', - InferResult.Field + InferResult.Field<$SelectionSet, Index['Root']['Query']['fields']['date'], Index> > > - dateArg: <$SelectionSet>( - args?: Utils.Exact<$SelectionSet, SelectionSet.Query.dateArg$SelectionSetArguments>, - ) => Promise< + dateArg: <$SelectionSet>(selectionSet?: Utils.Exact<$SelectionSet, SelectionSet.Query.dateArg>) => Promise< Utils.ResolveOutputReturnRootField< $Config, Index, 'dateArg', - InferResult.Field + InferResult.Field<$SelectionSet, Index['Root']['Query']['fields']['dateArg'], Index> > > dateArgInputObject: <$SelectionSet>( - args?: Utils.Exact<$SelectionSet, SelectionSet.Query.dateArgInputObject$SelectionSetArguments>, + selectionSet?: Utils.Exact<$SelectionSet, SelectionSet.Query.dateArgInputObject>, ) => Promise< Utils.ResolveOutputReturnRootField< $Config, Index, 'dateArgInputObject', - InferResult.Field + InferResult.Field<$SelectionSet, Index['Root']['Query']['fields']['dateArgInputObject'], Index> > > - dateArgList: <$SelectionSet>( - args?: Utils.Exact<$SelectionSet, SelectionSet.Query.dateArgList$SelectionSetArguments>, - ) => Promise< + dateArgList: <$SelectionSet>(selectionSet?: Utils.Exact<$SelectionSet, SelectionSet.Query.dateArgList>) => Promise< Utils.ResolveOutputReturnRootField< $Config, Index, 'dateArgList', - InferResult.Field + InferResult.Field<$SelectionSet, Index['Root']['Query']['fields']['dateArgList'], Index> > > dateArgNonNull: <$SelectionSet>( - args: Utils.Exact<$SelectionSet, SelectionSet.Query.dateArgNonNull$SelectionSetArguments>, + selectionSet: Utils.Exact<$SelectionSet, SelectionSet.Query.dateArgNonNull>, ) => Promise< Utils.ResolveOutputReturnRootField< $Config, Index, 'dateArgNonNull', - InferResult.Field + InferResult.Field<$SelectionSet, Index['Root']['Query']['fields']['dateArgNonNull'], Index> > > dateArgNonNullList: <$SelectionSet>( - args: Utils.Exact<$SelectionSet, SelectionSet.Query.dateArgNonNullList$SelectionSetArguments>, + selectionSet: Utils.Exact<$SelectionSet, SelectionSet.Query.dateArgNonNullList>, ) => Promise< Utils.ResolveOutputReturnRootField< $Config, Index, 'dateArgNonNullList', - InferResult.Field + InferResult.Field<$SelectionSet, Index['Root']['Query']['fields']['dateArgNonNullList'], Index> > > dateArgNonNullListNonNull: <$SelectionSet>( - args: Utils.Exact<$SelectionSet, SelectionSet.Query.dateArgNonNullListNonNull$SelectionSetArguments>, + selectionSet: Utils.Exact<$SelectionSet, SelectionSet.Query.dateArgNonNullListNonNull>, ) => Promise< Utils.ResolveOutputReturnRootField< $Config, Index, 'dateArgNonNullListNonNull', - InferResult.Field + InferResult.Field<$SelectionSet, Index['Root']['Query']['fields']['dateArgNonNullListNonNull'], Index> > > dateInterface1: <$SelectionSet>( @@ -172,36 +178,38 @@ export interface QueryMethods<$Config extends Utils.Config> { InferResult.Field<$SelectionSet, Index['Root']['Query']['fields']['dateInterface1'], Index> > > - dateList: () => Promise< + dateList: <$SelectionSet>(selectionSet?: Utils.Exact<$SelectionSet, SelectionSet.Query.dateList>) => Promise< Utils.ResolveOutputReturnRootField< $Config, Index, 'dateList', - InferResult.Field + InferResult.Field<$SelectionSet, Index['Root']['Query']['fields']['dateList'], Index> > > - dateListList: () => Promise< + dateListList: <$SelectionSet>(selectionSet?: Utils.Exact<$SelectionSet, SelectionSet.Query.dateListList>) => Promise< Utils.ResolveOutputReturnRootField< $Config, Index, 'dateListList', - InferResult.Field + InferResult.Field<$SelectionSet, Index['Root']['Query']['fields']['dateListList'], Index> > > - dateListNonNull: () => Promise< + dateListNonNull: <$SelectionSet>( + selectionSet?: Utils.Exact<$SelectionSet, SelectionSet.Query.dateListNonNull>, + ) => Promise< Utils.ResolveOutputReturnRootField< $Config, Index, 'dateListNonNull', - InferResult.Field + InferResult.Field<$SelectionSet, Index['Root']['Query']['fields']['dateListNonNull'], Index> > > - dateNonNull: () => Promise< + dateNonNull: <$SelectionSet>(selectionSet?: Utils.Exact<$SelectionSet, SelectionSet.Query.dateNonNull>) => Promise< Utils.ResolveOutputReturnRootField< $Config, Index, 'dateNonNull', - InferResult.Field + InferResult.Field<$SelectionSet, Index['Root']['Query']['fields']['dateNonNull'], Index> > > dateObject1: <$SelectionSet>(selectionSet: Utils.Exact<$SelectionSet, SelectionSet.Query.dateObject1>) => Promise< @@ -220,28 +228,28 @@ export interface QueryMethods<$Config extends Utils.Config> { InferResult.Field<$SelectionSet, Index['Root']['Query']['fields']['dateUnion'], Index> > > - error: <$SelectionSet>(args?: Utils.Exact<$SelectionSet, SelectionSet.Query.error$SelectionSetArguments>) => Promise< + error: <$SelectionSet>(selectionSet?: Utils.Exact<$SelectionSet, SelectionSet.Query.error>) => Promise< Utils.ResolveOutputReturnRootField< $Config, Index, 'error', - InferResult.Field + InferResult.Field<$SelectionSet, Index['Root']['Query']['fields']['error'], Index> > > - id: () => Promise< + id: <$SelectionSet>(selectionSet?: Utils.Exact<$SelectionSet, SelectionSet.Query.id>) => Promise< Utils.ResolveOutputReturnRootField< $Config, Index, 'id', - InferResult.Field + InferResult.Field<$SelectionSet, Index['Root']['Query']['fields']['id'], Index> > > - idNonNull: () => Promise< + idNonNull: <$SelectionSet>(selectionSet?: Utils.Exact<$SelectionSet, SelectionSet.Query.idNonNull>) => Promise< Utils.ResolveOutputReturnRootField< $Config, Index, 'idNonNull', - InferResult.Field + InferResult.Field<$SelectionSet, Index['Root']['Query']['fields']['idNonNull'], Index> > > interface: <$SelectionSet>(selectionSet: Utils.Exact<$SelectionSet, SelectionSet.Query.$interface>) => Promise< @@ -272,36 +280,40 @@ export interface QueryMethods<$Config extends Utils.Config> { InferResult.Field<$SelectionSet, Index['Root']['Query']['fields']['interfaceWithArgs'], Index> > > - listInt: () => Promise< + listInt: <$SelectionSet>(selectionSet?: Utils.Exact<$SelectionSet, SelectionSet.Query.listInt>) => Promise< Utils.ResolveOutputReturnRootField< $Config, Index, 'listInt', - InferResult.Field + InferResult.Field<$SelectionSet, Index['Root']['Query']['fields']['listInt'], Index> > > - listIntNonNull: () => Promise< + listIntNonNull: <$SelectionSet>( + selectionSet?: Utils.Exact<$SelectionSet, SelectionSet.Query.listIntNonNull>, + ) => Promise< Utils.ResolveOutputReturnRootField< $Config, Index, 'listIntNonNull', - InferResult.Field + InferResult.Field<$SelectionSet, Index['Root']['Query']['fields']['listIntNonNull'], Index> > > - listListInt: () => Promise< + listListInt: <$SelectionSet>(selectionSet?: Utils.Exact<$SelectionSet, SelectionSet.Query.listListInt>) => Promise< Utils.ResolveOutputReturnRootField< $Config, Index, 'listListInt', - InferResult.Field + InferResult.Field<$SelectionSet, Index['Root']['Query']['fields']['listListInt'], Index> > > - listListIntNonNull: () => Promise< + listListIntNonNull: <$SelectionSet>( + selectionSet?: Utils.Exact<$SelectionSet, SelectionSet.Query.listListIntNonNull>, + ) => Promise< Utils.ResolveOutputReturnRootField< $Config, Index, 'listListIntNonNull', - InferResult.Field + InferResult.Field<$SelectionSet, Index['Root']['Query']['fields']['listListIntNonNull'], Index> > > lowerCaseUnion: <$SelectionSet>( @@ -382,85 +394,85 @@ export interface QueryMethods<$Config extends Utils.Config> { InferResult.Field<$SelectionSet, Index['Root']['Query']['fields']['resultNonNull'], Index> > > - string: () => Promise< + string: <$SelectionSet>(selectionSet?: Utils.Exact<$SelectionSet, SelectionSet.Query.$string>) => Promise< Utils.ResolveOutputReturnRootField< $Config, Index, 'string', - InferResult.Field + InferResult.Field<$SelectionSet, Index['Root']['Query']['fields']['string'], Index> > > stringWithArgEnum: <$SelectionSet>( - args?: Utils.Exact<$SelectionSet, SelectionSet.Query.stringWithArgEnum$SelectionSetArguments>, + selectionSet?: Utils.Exact<$SelectionSet, SelectionSet.Query.stringWithArgEnum>, ) => Promise< Utils.ResolveOutputReturnRootField< $Config, Index, 'stringWithArgEnum', - InferResult.Field + InferResult.Field<$SelectionSet, Index['Root']['Query']['fields']['stringWithArgEnum'], Index> > > stringWithArgInputObject: <$SelectionSet>( - args?: Utils.Exact<$SelectionSet, SelectionSet.Query.stringWithArgInputObject$SelectionSetArguments>, + selectionSet?: Utils.Exact<$SelectionSet, SelectionSet.Query.stringWithArgInputObject>, ) => Promise< Utils.ResolveOutputReturnRootField< $Config, Index, 'stringWithArgInputObject', - InferResult.Field + InferResult.Field<$SelectionSet, Index['Root']['Query']['fields']['stringWithArgInputObject'], Index> > > stringWithArgInputObjectRequired: <$SelectionSet>( - args: Utils.Exact<$SelectionSet, SelectionSet.Query.stringWithArgInputObjectRequired$SelectionSetArguments>, + selectionSet: Utils.Exact<$SelectionSet, SelectionSet.Query.stringWithArgInputObjectRequired>, ) => Promise< Utils.ResolveOutputReturnRootField< $Config, Index, 'stringWithArgInputObjectRequired', - InferResult.Field + InferResult.Field<$SelectionSet, Index['Root']['Query']['fields']['stringWithArgInputObjectRequired'], Index> > > /** * The given arguments are reflected back as a JSON string. */ stringWithArgs: <$SelectionSet>( - args?: Utils.Exact<$SelectionSet, SelectionSet.Query.stringWithArgs$SelectionSetArguments>, + selectionSet?: Utils.Exact<$SelectionSet, SelectionSet.Query.stringWithArgs>, ) => Promise< Utils.ResolveOutputReturnRootField< $Config, Index, 'stringWithArgs', - InferResult.Field + InferResult.Field<$SelectionSet, Index['Root']['Query']['fields']['stringWithArgs'], Index> > > stringWithListArg: <$SelectionSet>( - args?: Utils.Exact<$SelectionSet, SelectionSet.Query.stringWithListArg$SelectionSetArguments>, + selectionSet?: Utils.Exact<$SelectionSet, SelectionSet.Query.stringWithListArg>, ) => Promise< Utils.ResolveOutputReturnRootField< $Config, Index, 'stringWithListArg', - InferResult.Field + InferResult.Field<$SelectionSet, Index['Root']['Query']['fields']['stringWithListArg'], Index> > > stringWithListArgRequired: <$SelectionSet>( - args: Utils.Exact<$SelectionSet, SelectionSet.Query.stringWithListArgRequired$SelectionSetArguments>, + selectionSet: Utils.Exact<$SelectionSet, SelectionSet.Query.stringWithListArgRequired>, ) => Promise< Utils.ResolveOutputReturnRootField< $Config, Index, 'stringWithListArgRequired', - InferResult.Field + InferResult.Field<$SelectionSet, Index['Root']['Query']['fields']['stringWithListArgRequired'], Index> > > stringWithRequiredArg: <$SelectionSet>( - args: Utils.Exact<$SelectionSet, SelectionSet.Query.stringWithRequiredArg$SelectionSetArguments>, + selectionSet: Utils.Exact<$SelectionSet, SelectionSet.Query.stringWithRequiredArg>, ) => Promise< Utils.ResolveOutputReturnRootField< $Config, Index, 'stringWithRequiredArg', - InferResult.Field + InferResult.Field<$SelectionSet, Index['Root']['Query']['fields']['stringWithRequiredArg'], Index> > > unionFooBar: <$SelectionSet>(selectionSet: Utils.Exact<$SelectionSet, SelectionSet.Query.unionFooBar>) => Promise< diff --git a/tests/_/schemas/kitchen-sink/graffle/modules/RuntimeCustomScalars.ts b/tests/_/schemas/kitchen-sink/graffle/modules/RuntimeCustomScalars.ts deleted file mode 100644 index ba01287a5..000000000 --- a/tests/_/schemas/kitchen-sink/graffle/modules/RuntimeCustomScalars.ts +++ /dev/null @@ -1,217 +0,0 @@ -import * as CustomScalars from './Scalar.js' -// -// -// -// -// -// -// ================================================================================================== -// GraphQLInputObjectType -// ================================================================================================== -// -// -// -// -// -// - -const InputObject = { - date: CustomScalars.Date.codec, - dateRequired: CustomScalars.Date.codec, -} - -const InputObjectNested = { - InputObject: InputObject, -} - -const InputObjectNestedNonNull = { - InputObject: InputObject, -} - -// -// -// -// -// -// -// ================================================================================================== -// GraphQLObjectType -// ================================================================================================== -// -// -// -// -// -// - -const DateObject1 = { - date1: { - o: CustomScalars.Date.codec, - }, -} - -const DateObject2 = { - date2: { - o: CustomScalars.Date.codec, - }, -} - -// -// -// -// -// -// -// ================================================================================================== -// GraphQLInterfaceType -// ================================================================================================== -// -// -// -// -// -// - -const DateInterface1 = { - ...DateObject1, -} - -// -// -// -// -// -// -// ================================================================================================== -// GraphQLUnionType -// ================================================================================================== -// -// -// -// -// -// - -const DateUnion = { - ...DateObject1, - ...DateObject2, -} - -// -// -// -// -// -// -// ================================================================================================== -// GraphQLRootType -// ================================================================================================== -// -// -// -// -// -// - -const Query = { - InputObjectNested: { - i: { - input: InputObjectNested, - }, - }, - InputObjectNestedNonNull: { - i: { - input: InputObjectNestedNonNull, - }, - }, - date: { - o: CustomScalars.Date.codec, - }, - dateArg: { - i: { - date: CustomScalars.Date.codec, - }, - o: CustomScalars.Date.codec, - }, - dateArgInputObject: { - i: { - input: InputObject, - }, - o: CustomScalars.Date.codec, - }, - dateArgList: { - i: { - date: CustomScalars.Date.codec, - }, - o: CustomScalars.Date.codec, - }, - dateArgNonNull: { - i: { - date: CustomScalars.Date.codec, - }, - o: CustomScalars.Date.codec, - }, - dateArgNonNullList: { - i: { - date: CustomScalars.Date.codec, - }, - o: CustomScalars.Date.codec, - }, - dateArgNonNullListNonNull: { - i: { - date: CustomScalars.Date.codec, - }, - o: CustomScalars.Date.codec, - }, - dateInterface1: { - r: DateInterface1, - }, - dateList: { - o: CustomScalars.Date.codec, - }, - dateListList: { - o: CustomScalars.Date.codec, - }, - dateListNonNull: { - o: CustomScalars.Date.codec, - }, - dateNonNull: { - o: CustomScalars.Date.codec, - }, - dateObject1: { - r: DateObject1, - }, - dateUnion: { - r: DateUnion, - }, - stringWithArgInputObject: { - i: { - input: InputObject, - }, - }, - stringWithArgInputObjectRequired: { - i: { - input: InputObject, - }, - }, -} - -// -// -// -// -// -// -// ================================================================================================== -// Index -// ================================================================================================== -// -// -// -// -// -// - -export const $index = { - Query, -} diff --git a/tests/_/schemas/kitchen-sink/graffle/modules/SchemaBuildtime.ts b/tests/_/schemas/kitchen-sink/graffle/modules/SchemaBuildtime.ts index 36a8c72f7..9afdbf2ae 100644 --- a/tests/_/schemas/kitchen-sink/graffle/modules/SchemaBuildtime.ts +++ b/tests/_/schemas/kitchen-sink/graffle/modules/SchemaBuildtime.ts @@ -29,6 +29,13 @@ export namespace Root { * Query enum field documentation. */ abcEnum: $.Field<'abcEnum', $.Output.Nullable, null> + argInputObjectCircular: $.Field< + 'argInputObjectCircular', + $.Output.Nullable<$Scalar.String>, + $.Args<{ + input: $.Input.Field<$.Input.Nullable> + }, true> + > date: $.Field<'date', $.Output.Nullable<$Scalar.Date>, null> dateArg: $.Field< 'dateArg', @@ -233,6 +240,11 @@ export namespace InputObject { idRequired: $.Input.Field<$Scalar.ID> }, true> + export type InputObjectCircular = $.InputObject<'InputObjectCircular', { + circular: $.Input.Field<$.Input.Nullable> + date: $.Input.Field<$.Input.Nullable<$Scalar.Date>> + }, true> + export type InputObjectNested = $.InputObject<'InputObjectNested', { InputObject: $.Input.Field<$.Input.Nullable> }, true> diff --git a/tests/_/schemas/kitchen-sink/graffle/modules/SchemaDrivenDataMap.ts b/tests/_/schemas/kitchen-sink/graffle/modules/SchemaDrivenDataMap.ts new file mode 100644 index 000000000..db510e87f --- /dev/null +++ b/tests/_/schemas/kitchen-sink/graffle/modules/SchemaDrivenDataMap.ts @@ -0,0 +1,735 @@ +import type * as $Utilities from '../../../../../../src/entrypoints/utilities-for-generated.js' +import * as $Scalar from './Scalar.js' +// +// +// +// +// +// +// ================================================================================================== +// GraphQLScalarType +// ================================================================================================== +// +// +// +// +// +// + +const Int = $Scalar.Int + +const String = $Scalar.String + +const ID = $Scalar.ID + +const Boolean = $Scalar.Boolean + +const Float = $Scalar.Float + +// +// +// +// +// +// +// ================================================================================================== +// GraphQLScalarTypeCustom +// ================================================================================================== +// +// +// +// +// +// + +const Date = $Scalar.Date + +// +// +// +// +// +// +// ================================================================================================== +// GraphQLEnumType +// ================================================================================================== +// +// +// +// +// +// + +const ABCEnum: $Utilities.SchemaDrivenDataMap.Enum = { + k: 'enum', + n: 'ABCEnum', +} + +const Case: $Utilities.SchemaDrivenDataMap.Enum = { + k: 'enum', + n: 'Case', +} + +// +// +// +// +// +// +// ================================================================================================== +// GraphQLInputObjectType +// ================================================================================================== +// +// +// +// +// +// + +const InputObject: $Utilities.SchemaDrivenDataMap.InputObject = { + n: 'InputObject', + fcs: ['date', 'dateRequired'], + f: { + date: { + nt: Date, + }, + dateRequired: { + nt: Date, + }, + id: {}, + idRequired: {}, + }, +} + +const InputObjectCircular: $Utilities.SchemaDrivenDataMap.InputObject = { + n: 'InputObjectCircular', + fcs: ['circular', 'date'], + f: { + circular: { + // nt: InputObjectCircular, <-- Assigned later to avoid potential circular dependency. + }, + date: { + nt: Date, + }, + }, +} + +const InputObjectNested: $Utilities.SchemaDrivenDataMap.InputObject = { + n: 'InputObjectNested', + fcs: ['InputObject'], + f: { + InputObject: { + // nt: InputObject, <-- Assigned later to avoid potential circular dependency. + }, + }, +} + +const InputObjectNestedNonNull: $Utilities.SchemaDrivenDataMap.InputObject = { + n: 'InputObjectNestedNonNull', + fcs: ['InputObject'], + f: { + InputObject: { + // nt: InputObject, <-- Assigned later to avoid potential circular dependency. + }, + }, +} + +// +// +// +// +// +// +// ================================================================================================== +// GraphQLObjectType +// ================================================================================================== +// +// +// +// +// +// + +const Bar: $Utilities.SchemaDrivenDataMap.OutputObject = { + f: { + int: {}, + }, +} + +const DateObject1: $Utilities.SchemaDrivenDataMap.OutputObject = { + f: { + date1: { + nt: Date, + }, + }, +} + +const DateObject2: $Utilities.SchemaDrivenDataMap.OutputObject = { + f: { + date2: { + nt: Date, + }, + }, +} + +const ErrorOne: $Utilities.SchemaDrivenDataMap.OutputObject = { + e: 1, + f: { + infoId: {}, + message: {}, + }, +} + +const ErrorTwo: $Utilities.SchemaDrivenDataMap.OutputObject = { + e: 1, + f: { + infoInt: {}, + message: {}, + }, +} + +const Foo: $Utilities.SchemaDrivenDataMap.OutputObject = { + f: { + id: {}, + }, +} + +const Object1: $Utilities.SchemaDrivenDataMap.OutputObject = { + f: { + boolean: {}, + float: {}, + id: {}, + int: {}, + string: {}, + }, +} + +const Object1ImplementingInterface: $Utilities.SchemaDrivenDataMap.OutputObject = { + f: { + id: {}, + int: {}, + }, +} + +const Object2ImplementingInterface: $Utilities.SchemaDrivenDataMap.OutputObject = { + f: { + boolean: {}, + id: {}, + }, +} + +const ObjectNested: $Utilities.SchemaDrivenDataMap.OutputObject = { + f: { + id: {}, + object: { + // nt: Object1, <-- Assigned later to avoid potential circular dependency. + }, + }, +} + +const ObjectUnion: $Utilities.SchemaDrivenDataMap.OutputObject = { + f: { + fooBarUnion: { + // nt: FooBarUnion, <-- Assigned later to avoid potential circular dependency. + }, + }, +} + +const lowerCaseObject: $Utilities.SchemaDrivenDataMap.OutputObject = { + f: { + id: {}, + }, +} + +const lowerCaseObject2: $Utilities.SchemaDrivenDataMap.OutputObject = { + f: { + int: {}, + }, +} + +// +// +// +// +// +// +// ================================================================================================== +// GraphQLInterfaceType +// ================================================================================================== +// +// +// +// +// +// + +const DateInterface1: $Utilities.SchemaDrivenDataMap.OutputObject = { + f: { + ...DateObject1.f, + }, +} + +const Error: $Utilities.SchemaDrivenDataMap.OutputObject = { + f: {}, +} + +const Interface: $Utilities.SchemaDrivenDataMap.OutputObject = { + f: {}, +} + +// +// +// +// +// +// +// ================================================================================================== +// GraphQLUnionType +// ================================================================================================== +// +// +// +// +// +// + +const DateUnion: $Utilities.SchemaDrivenDataMap.OutputObject = { + f: { + ...DateObject1.f, + ...DateObject2.f, + }, +} + +const FooBarUnion: $Utilities.SchemaDrivenDataMap.OutputObject = { + f: {}, +} + +const Result: $Utilities.SchemaDrivenDataMap.OutputObject = { + f: {}, +} + +const lowerCaseUnion: $Utilities.SchemaDrivenDataMap.OutputObject = { + f: {}, +} + +// +// +// +// +// +// +// ================================================================================================== +// GraphQLRootType +// ================================================================================================== +// +// +// +// +// +// + +const Mutation: $Utilities.SchemaDrivenDataMap.OutputObject = { + f: { + id: {}, + idNonNull: {}, + }, +} + +const Query: $Utilities.SchemaDrivenDataMap.OutputObject = { + f: { + InputObjectNested: { + a: { + input: { + nt: InputObjectNested, + it: [0], + }, + }, + }, + InputObjectNestedNonNull: { + a: { + input: { + nt: InputObjectNestedNonNull, + it: [1], + }, + }, + }, + abcEnum: {}, + argInputObjectCircular: { + a: { + input: { + nt: InputObjectCircular, + it: [0], + }, + }, + }, + date: { + nt: Date, + }, + dateArg: { + a: { + date: { + nt: Date, + it: [0], + }, + }, + nt: Date, + }, + dateArgInputObject: { + a: { + input: { + nt: InputObject, + it: [0], + }, + }, + nt: Date, + }, + dateArgList: { + a: { + date: { + nt: Date, + it: [0, [1]], + }, + }, + nt: Date, + }, + dateArgNonNull: { + a: { + date: { + nt: Date, + it: [1], + }, + }, + nt: Date, + }, + dateArgNonNullList: { + a: { + date: { + nt: Date, + it: [1, [0]], + }, + }, + nt: Date, + }, + dateArgNonNullListNonNull: { + a: { + date: { + nt: Date, + it: [1, [1]], + }, + }, + nt: Date, + }, + dateInterface1: { + // nt: DateInterface1, <-- Assigned later to avoid potential circular dependency. + }, + dateList: { + nt: Date, + }, + dateListList: { + nt: Date, + }, + dateListNonNull: { + nt: Date, + }, + dateNonNull: { + nt: Date, + }, + dateObject1: { + // nt: DateObject1, <-- Assigned later to avoid potential circular dependency. + }, + dateUnion: { + // nt: DateUnion, <-- Assigned later to avoid potential circular dependency. + }, + error: { + a: { + case: { + nt: String, + it: [0], + }, + }, + }, + id: {}, + idNonNull: {}, + interface: { + // nt: Interface, <-- Assigned later to avoid potential circular dependency. + }, + interfaceNonNull: { + // nt: Interface, <-- Assigned later to avoid potential circular dependency. + }, + interfaceWithArgs: { + a: { + id: { + nt: ID, + it: [1], + }, + }, + // nt: Interface, <-- Assigned later to avoid potential circular dependency. + }, + listInt: {}, + listIntNonNull: {}, + listListInt: {}, + listListIntNonNull: {}, + lowerCaseUnion: { + // nt: lowerCaseUnion, <-- Assigned later to avoid potential circular dependency. + }, + object: { + // nt: Object1, <-- Assigned later to avoid potential circular dependency. + }, + objectList: { + // nt: Object1, <-- Assigned later to avoid potential circular dependency. + }, + objectListNonNull: { + // nt: Object1, <-- Assigned later to avoid potential circular dependency. + }, + objectNested: { + // nt: ObjectNested, <-- Assigned later to avoid potential circular dependency. + }, + objectNonNull: { + // nt: Object1, <-- Assigned later to avoid potential circular dependency. + }, + objectWithArgs: { + a: { + boolean: { + nt: Boolean, + it: [0], + }, + float: { + nt: Float, + it: [0], + }, + id: { + nt: ID, + it: [0], + }, + int: { + nt: Int, + it: [0], + }, + string: { + nt: String, + it: [0], + }, + }, + // nt: Object1, <-- Assigned later to avoid potential circular dependency. + }, + result: { + a: { + case: { + nt: Case, + it: [1], + }, + }, + r: 1, + // nt: Result, <-- Assigned later to avoid potential circular dependency. + }, + resultNonNull: { + a: { + case: { + nt: Case, + it: [0], + }, + }, + r: 1, + // nt: Result, <-- Assigned later to avoid potential circular dependency. + }, + string: {}, + stringWithArgEnum: { + a: { + ABCEnum: { + nt: ABCEnum, + it: [0], + }, + }, + }, + stringWithArgInputObject: { + a: { + input: { + nt: InputObject, + it: [0], + }, + }, + }, + stringWithArgInputObjectRequired: { + a: { + input: { + nt: InputObject, + it: [1], + }, + }, + }, + stringWithArgs: { + a: { + boolean: { + nt: Boolean, + it: [0], + }, + float: { + nt: Float, + it: [0], + }, + id: { + nt: ID, + it: [0], + }, + int: { + nt: Int, + it: [0], + }, + string: { + nt: String, + it: [0], + }, + }, + }, + stringWithListArg: { + a: { + ints: { + nt: Int, + it: [0, [0]], + }, + }, + }, + stringWithListArgRequired: { + a: { + ints: { + nt: Int, + it: [1, [1]], + }, + }, + }, + stringWithRequiredArg: { + a: { + string: { + nt: String, + it: [1], + }, + }, + }, + unionFooBar: { + // nt: FooBarUnion, <-- Assigned later to avoid potential circular dependency. + }, + unionFooBarNonNull: { + // nt: FooBarUnion, <-- Assigned later to avoid potential circular dependency. + }, + unionFooBarWithArgs: { + a: { + id: { + nt: ID, + it: [0], + }, + }, + // nt: FooBarUnion, <-- Assigned later to avoid potential circular dependency. + }, + unionObject: { + // nt: ObjectUnion, <-- Assigned later to avoid potential circular dependency. + }, + unionObjectNonNull: { + // nt: ObjectUnion, <-- Assigned later to avoid potential circular dependency. + }, + }, +} + +// +// +// +// +// +// +// ================================================================================================== +// Reference Assignments +// (avoids circular assignment issues) +// ================================================================================================== +// +// +// +// +// +// + +InputObjectCircular.f!['circular']!.nt = InputObjectCircular +InputObjectNested.f!['InputObject']!.nt = InputObject +InputObjectNestedNonNull.f!['InputObject']!.nt = InputObject +ObjectNested.f['object']!.nt = Object1 +ObjectUnion.f['fooBarUnion']!.nt = FooBarUnion +Query.f['dateInterface1']!.nt = DateInterface1 +Query.f['dateObject1']!.nt = DateObject1 +Query.f['dateUnion']!.nt = DateUnion +Query.f['interface']!.nt = Interface +Query.f['interfaceNonNull']!.nt = Interface +Query.f['interfaceWithArgs']!.nt = Interface +Query.f['lowerCaseUnion']!.nt = lowerCaseUnion +Query.f['object']!.nt = Object1 +Query.f['objectList']!.nt = Object1 +Query.f['objectListNonNull']!.nt = Object1 +Query.f['objectNested']!.nt = ObjectNested +Query.f['objectNonNull']!.nt = Object1 +Query.f['objectWithArgs']!.nt = Object1 +Query.f['result']!.nt = Result +Query.f['resultNonNull']!.nt = Result +Query.f['unionFooBar']!.nt = FooBarUnion +Query.f['unionFooBarNonNull']!.nt = FooBarUnion +Query.f['unionFooBarWithArgs']!.nt = FooBarUnion +Query.f['unionObject']!.nt = ObjectUnion +Query.f['unionObjectNonNull']!.nt = ObjectUnion + +// +// +// +// +// +// +// ================================================================================================== +// Index +// ================================================================================================== +// +// +// +// +// +// + +const $schemaDrivenDataMap: $Utilities.SchemaDrivenDataMap = { + roots: { + Mutation, + Query, + }, + directives: {}, + types: { + Int, + String, + ID, + Boolean, + Float, + Date, + ABCEnum, + Case, + InputObject, + InputObjectCircular, + InputObjectNested, + InputObjectNestedNonNull, + Bar, + DateObject1, + DateObject2, + ErrorOne, + ErrorTwo, + Foo, + Object1, + Object1ImplementingInterface, + Object2ImplementingInterface, + ObjectNested, + ObjectUnion, + lowerCaseObject, + lowerCaseObject2, + DateInterface1, + Error, + Interface, + DateUnion, + FooBarUnion, + Result, + lowerCaseUnion, + Mutation, + Query, + }, +} + +export { $schemaDrivenDataMap as schemaDrivenDataMap } diff --git a/tests/_/schemas/kitchen-sink/graffle/modules/SchemaRuntime.ts b/tests/_/schemas/kitchen-sink/graffle/modules/SchemaRuntime.ts deleted file mode 100644 index b525726cc..000000000 --- a/tests/_/schemas/kitchen-sink/graffle/modules/SchemaRuntime.ts +++ /dev/null @@ -1,370 +0,0 @@ -/* eslint-disable */ -import * as $ from '../../../../../../src/entrypoints/schema.js' -import * as Data from './Data.js' -import { $index as $customScalarsIndex } from './RuntimeCustomScalars.js' -import * as $Scalar from './Scalar.js' -import type { Index } from './SchemaIndex.js' -export const $defaultSchemaUrl = undefined -export const ABCEnum = $.Enum(`ABCEnum`, [`A`, `B`, `C`]) -export const Case = $.Enum(`Case`, [`ErrorOne`, `ErrorTwo`, `Object1`]) -export const InputObject = $.InputObject(`InputObject`, { - date: $.Input.Field($.Input.Nullable($Scalar.Date)), - dateRequired: $.Input.Field($Scalar.Date), - id: $.Input.Field($.Input.Nullable($Scalar.ID)), - idRequired: $.Input.Field($Scalar.ID), -}, true) - -export const InputObjectNested = $.InputObject(`InputObjectNested`, { - InputObject: $.Input.Field(() => $.Input.Nullable(InputObject)), -}, true) - -export const InputObjectNestedNonNull = $.InputObject(`InputObjectNestedNonNull`, { - InputObject: $.Input.Field(() => InputObject), -}, false) -// @ts-ignore - circular types cannot infer. Ignore in case there are any. This comment is always added, it does not indicate if this particular type could infer or not. -export const Bar = $.Object$(`Bar`, { - int: $.field('int', $.Output.Nullable($Scalar.Int)), -}) - -// @ts-ignore - circular types cannot infer. Ignore in case there are any. This comment is always added, it does not indicate if this particular type could infer or not. -export const DateObject1 = $.Object$(`DateObject1`, { - date1: $.field('date1', $.Output.Nullable($Scalar.Date)), -}) - -// @ts-ignore - circular types cannot infer. Ignore in case there are any. This comment is always added, it does not indicate if this particular type could infer or not. -export const DateObject2 = $.Object$(`DateObject2`, { - date2: $.field('date2', $.Output.Nullable($Scalar.Date)), -}) - -// @ts-ignore - circular types cannot infer. Ignore in case there are any. This comment is always added, it does not indicate if this particular type could infer or not. -export const ErrorOne = $.Object$(`ErrorOne`, { - infoId: $.field('infoId', $.Output.Nullable($Scalar.ID)), - message: $.field('message', $Scalar.String), -}) - -// @ts-ignore - circular types cannot infer. Ignore in case there are any. This comment is always added, it does not indicate if this particular type could infer or not. -export const ErrorTwo = $.Object$(`ErrorTwo`, { - infoInt: $.field('infoInt', $.Output.Nullable($Scalar.Int)), - message: $.field('message', $Scalar.String), -}) - -// @ts-ignore - circular types cannot infer. Ignore in case there are any. This comment is always added, it does not indicate if this particular type could infer or not. -export const Foo = $.Object$(`Foo`, { - id: $.field('id', $.Output.Nullable($Scalar.ID)), -}) - -// @ts-ignore - circular types cannot infer. Ignore in case there are any. This comment is always added, it does not indicate if this particular type could infer or not. -export const Object1 = $.Object$(`Object1`, { - boolean: $.field('boolean', $.Output.Nullable($Scalar.Boolean)), - float: $.field('float', $.Output.Nullable($Scalar.Float)), - id: $.field('id', $.Output.Nullable($Scalar.ID)), - int: $.field('int', $.Output.Nullable($Scalar.Int)), - string: $.field('string', $.Output.Nullable($Scalar.String)), -}) - -// @ts-ignore - circular types cannot infer. Ignore in case there are any. This comment is always added, it does not indicate if this particular type could infer or not. -export const Object1ImplementingInterface = $.Object$(`Object1ImplementingInterface`, { - id: $.field('id', $.Output.Nullable($Scalar.ID)), - int: $.field('int', $.Output.Nullable($Scalar.Int)), -}) - -// @ts-ignore - circular types cannot infer. Ignore in case there are any. This comment is always added, it does not indicate if this particular type could infer or not. -export const Object2ImplementingInterface = $.Object$(`Object2ImplementingInterface`, { - boolean: $.field('boolean', $.Output.Nullable($Scalar.Boolean)), - id: $.field('id', $.Output.Nullable($Scalar.ID)), -}) - -// @ts-ignore - circular types cannot infer. Ignore in case there are any. This comment is always added, it does not indicate if this particular type could infer or not. -export const ObjectNested = $.Object$(`ObjectNested`, { - id: $.field('id', $.Output.Nullable($Scalar.ID)), - // @ts-ignore - circular types cannot infer. Ignore in case there are any. This comment is always added, it does not indicate if this particular type could infer or not. - object: $.field('object', $.Output.Nullable(() => Object1)), -}) - -// @ts-ignore - circular types cannot infer. Ignore in case there are any. This comment is always added, it does not indicate if this particular type could infer or not. -export const ObjectUnion = $.Object$(`ObjectUnion`, { - // @ts-ignore - circular types cannot infer. Ignore in case there are any. This comment is always added, it does not indicate if this particular type could infer or not. - fooBarUnion: $.field('fooBarUnion', $.Output.Nullable(() => FooBarUnion)), -}) - -// @ts-ignore - circular types cannot infer. Ignore in case there are any. This comment is always added, it does not indicate if this particular type could infer or not. -export const lowerCaseObject = $.Object$(`lowerCaseObject`, { - id: $.field('id', $.Output.Nullable($Scalar.ID)), -}) - -// @ts-ignore - circular types cannot infer. Ignore in case there are any. This comment is always added, it does not indicate if this particular type could infer or not. -export const lowerCaseObject2 = $.Object$(`lowerCaseObject2`, { - int: $.field('int', $.Output.Nullable($Scalar.Int)), -}) -// @ts-ignore - circular types cannot infer. Ignore in case there are any. This comment is always added, it does not indicate if this particular type could infer or not. -export const DateUnion = $.Union(`DateUnion`, [DateObject1, DateObject2]) - -// @ts-ignore - circular types cannot infer. Ignore in case there are any. This comment is always added, it does not indicate if this particular type could infer or not. -export const FooBarUnion = $.Union(`FooBarUnion`, [Bar, Foo]) - -// @ts-ignore - circular types cannot infer. Ignore in case there are any. This comment is always added, it does not indicate if this particular type could infer or not. -export const Result = $.Union(`Result`, [ErrorOne, ErrorTwo, Object1]) - -// @ts-ignore - circular types cannot infer. Ignore in case there are any. This comment is always added, it does not indicate if this particular type could infer or not. -export const lowerCaseUnion = $.Union(`lowerCaseUnion`, [lowerCaseObject, lowerCaseObject2]) -export const DateInterface1 = $.Interface(`DateInterface1`, { - date1: $.field('date1', $.Output.Nullable($Scalar.Date)), -}, [DateObject1]) -export const Error = $.Interface(`Error`, { message: $.field('message', $Scalar.String) }, [ErrorOne, ErrorTwo]) -export const Interface = $.Interface(`Interface`, { id: $.field('id', $.Output.Nullable($Scalar.ID)) }, [ - Object1ImplementingInterface, - Object2ImplementingInterface, -]) -// @ts-ignore - circular types cannot infer. Ignore in case there are any. This comment is always added, it does not indicate if this particular type could infer or not. -export const Mutation = $.Object$(`Mutation`, { - id: $.field('id', $.Output.Nullable($Scalar.ID)), - idNonNull: $.field('idNonNull', $Scalar.ID), -}) - -// @ts-ignore - circular types cannot infer. Ignore in case there are any. This comment is always added, it does not indicate if this particular type could infer or not. -export const Query = $.Object$(`Query`, { - InputObjectNested: $.field( - 'InputObjectNested', - $.Output.Nullable($Scalar.ID), - $.Args({ input: $.Input.Field($.Input.Nullable(InputObjectNested)) }, true), - ), - InputObjectNestedNonNull: $.field( - 'InputObjectNestedNonNull', - $.Output.Nullable($Scalar.ID), - $.Args({ input: $.Input.Field(InputObjectNestedNonNull) }, false), - ), - // @ts-ignore - circular types cannot infer. Ignore in case there are any. This comment is always added, it does not indicate if this particular type could infer or not. - abcEnum: $.field('abcEnum', $.Output.Nullable(ABCEnum)), - date: $.field('date', $.Output.Nullable($Scalar.Date)), - dateArg: $.field( - 'dateArg', - $.Output.Nullable($Scalar.Date), - $.Args({ date: $.Input.Field($.Input.Nullable($Scalar.Date)) }, true), - ), - dateArgInputObject: $.field( - 'dateArgInputObject', - $.Output.Nullable($Scalar.Date), - $.Args({ input: $.Input.Field($.Input.Nullable(InputObject)) }, true), - ), - dateArgList: $.field( - 'dateArgList', - $.Output.Nullable($Scalar.Date), - $.Args({ date: $.Input.Field($.Input.Nullable($.Input.List($Scalar.Date))) }, true), - ), - dateArgNonNull: $.field( - 'dateArgNonNull', - $.Output.Nullable($Scalar.Date), - $.Args({ date: $.Input.Field($Scalar.Date) }, false), - ), - dateArgNonNullList: $.field( - 'dateArgNonNullList', - $.Output.Nullable($Scalar.Date), - $.Args({ date: $.Input.Field($.Input.List($.Input.Nullable($Scalar.Date))) }, false), - ), - dateArgNonNullListNonNull: $.field( - 'dateArgNonNullListNonNull', - $.Output.Nullable($Scalar.Date), - $.Args({ date: $.Input.Field($.Input.List($Scalar.Date)) }, false), - ), - // @ts-ignore - circular types cannot infer. Ignore in case there are any. This comment is always added, it does not indicate if this particular type could infer or not. - dateInterface1: $.field('dateInterface1', $.Output.Nullable(() => DateInterface1)), - dateList: $.field('dateList', $.Output.Nullable($.Output.List($Scalar.Date))), - dateListList: $.field('dateListList', $.Output.Nullable($.Output.List($.Output.List($Scalar.Date)))), - dateListNonNull: $.field('dateListNonNull', $.Output.List($Scalar.Date)), - dateNonNull: $.field('dateNonNull', $Scalar.Date), - // @ts-ignore - circular types cannot infer. Ignore in case there are any. This comment is always added, it does not indicate if this particular type could infer or not. - dateObject1: $.field('dateObject1', $.Output.Nullable(() => DateObject1)), - // @ts-ignore - circular types cannot infer. Ignore in case there are any. This comment is always added, it does not indicate if this particular type could infer or not. - dateUnion: $.field('dateUnion', $.Output.Nullable(() => DateUnion)), - error: $.field( - 'error', - $.Output.Nullable($Scalar.String), - $.Args({ case: $.Input.Field($.Input.Nullable($Scalar.String)) }, true), - ), - id: $.field('id', $.Output.Nullable($Scalar.ID)), - idNonNull: $.field('idNonNull', $Scalar.ID), - // @ts-ignore - circular types cannot infer. Ignore in case there are any. This comment is always added, it does not indicate if this particular type could infer or not. - interface: $.field('interface', $.Output.Nullable(() => Interface)), - // @ts-ignore - circular types cannot infer. Ignore in case there are any. This comment is always added, it does not indicate if this particular type could infer or not. - interfaceNonNull: $.field('interfaceNonNull', () => Interface), - // @ts-ignore - circular types cannot infer. Ignore in case there are any. This comment is always added, it does not indicate if this particular type could infer or not. - interfaceWithArgs: $.field( - 'interfaceWithArgs', - $.Output.Nullable(() => Interface), - $.Args({ id: $.Input.Field($Scalar.ID) }, false), - ), - listInt: $.field('listInt', $.Output.Nullable($.Output.List($.Output.Nullable($Scalar.Int)))), - listIntNonNull: $.field('listIntNonNull', $.Output.List($Scalar.Int)), - listListInt: $.field( - 'listListInt', - $.Output.Nullable($.Output.List($.Output.Nullable($.Output.List($.Output.Nullable($Scalar.Int))))), - ), - listListIntNonNull: $.field('listListIntNonNull', $.Output.List($.Output.List($Scalar.Int))), - // @ts-ignore - circular types cannot infer. Ignore in case there are any. This comment is always added, it does not indicate if this particular type could infer or not. - lowerCaseUnion: $.field('lowerCaseUnion', $.Output.Nullable(() => lowerCaseUnion)), - // @ts-ignore - circular types cannot infer. Ignore in case there are any. This comment is always added, it does not indicate if this particular type could infer or not. - object: $.field('object', $.Output.Nullable(() => Object1)), - // @ts-ignore - circular types cannot infer. Ignore in case there are any. This comment is always added, it does not indicate if this particular type could infer or not. - objectList: $.field('objectList', $.Output.Nullable($.Output.List(() => Object1))), - // @ts-ignore - circular types cannot infer. Ignore in case there are any. This comment is always added, it does not indicate if this particular type could infer or not. - objectListNonNull: $.field('objectListNonNull', $.Output.List(() => Object1)), - // @ts-ignore - circular types cannot infer. Ignore in case there are any. This comment is always added, it does not indicate if this particular type could infer or not. - objectNested: $.field('objectNested', $.Output.Nullable(() => ObjectNested)), - // @ts-ignore - circular types cannot infer. Ignore in case there are any. This comment is always added, it does not indicate if this particular type could infer or not. - objectNonNull: $.field('objectNonNull', () => Object1), - // @ts-ignore - circular types cannot infer. Ignore in case there are any. This comment is always added, it does not indicate if this particular type could infer or not. - objectWithArgs: $.field( - 'objectWithArgs', - $.Output.Nullable(() => Object1), - $.Args({ - boolean: $.Input.Field($.Input.Nullable($Scalar.Boolean)), - float: $.Input.Field($.Input.Nullable($Scalar.Float)), - id: $.Input.Field($.Input.Nullable($Scalar.ID)), - int: $.Input.Field($.Input.Nullable($Scalar.Int)), - string: $.Input.Field($.Input.Nullable($Scalar.String)), - }, true), - ), - // @ts-ignore - circular types cannot infer. Ignore in case there are any. This comment is always added, it does not indicate if this particular type could infer or not. - result: $.field('result', $.Output.Nullable(() => Result), $.Args({ case: $.Input.Field(Case) }, false)), - // @ts-ignore - circular types cannot infer. Ignore in case there are any. This comment is always added, it does not indicate if this particular type could infer or not. - resultNonNull: $.field('resultNonNull', () => Result, $.Args({ case: $.Input.Field($.Input.Nullable(Case)) }, true)), - string: $.field('string', $.Output.Nullable($Scalar.String)), - stringWithArgEnum: $.field( - 'stringWithArgEnum', - $.Output.Nullable($Scalar.String), - $.Args({ ABCEnum: $.Input.Field($.Input.Nullable(ABCEnum)) }, true), - ), - stringWithArgInputObject: $.field( - 'stringWithArgInputObject', - $.Output.Nullable($Scalar.String), - $.Args({ input: $.Input.Field($.Input.Nullable(InputObject)) }, true), - ), - stringWithArgInputObjectRequired: $.field( - 'stringWithArgInputObjectRequired', - $.Output.Nullable($Scalar.String), - $.Args({ input: $.Input.Field(InputObject) }, false), - ), - stringWithArgs: $.field( - 'stringWithArgs', - $.Output.Nullable($Scalar.String), - $.Args({ - boolean: $.Input.Field($.Input.Nullable($Scalar.Boolean)), - float: $.Input.Field($.Input.Nullable($Scalar.Float)), - id: $.Input.Field($.Input.Nullable($Scalar.ID)), - int: $.Input.Field($.Input.Nullable($Scalar.Int)), - string: $.Input.Field($.Input.Nullable($Scalar.String)), - }, true), - ), - stringWithListArg: $.field( - 'stringWithListArg', - $.Output.Nullable($Scalar.String), - $.Args({ ints: $.Input.Field($.Input.Nullable($.Input.List($.Input.Nullable($Scalar.Int)))) }, true), - ), - stringWithListArgRequired: $.field( - 'stringWithListArgRequired', - $.Output.Nullable($Scalar.String), - $.Args({ ints: $.Input.Field($.Input.List($Scalar.Int)) }, false), - ), - stringWithRequiredArg: $.field( - 'stringWithRequiredArg', - $.Output.Nullable($Scalar.String), - $.Args({ string: $.Input.Field($Scalar.String) }, false), - ), - // @ts-ignore - circular types cannot infer. Ignore in case there are any. This comment is always added, it does not indicate if this particular type could infer or not. - unionFooBar: $.field('unionFooBar', $.Output.Nullable(() => FooBarUnion)), - // @ts-ignore - circular types cannot infer. Ignore in case there are any. This comment is always added, it does not indicate if this particular type could infer or not. - unionFooBarNonNull: $.field('unionFooBarNonNull', () => FooBarUnion), - // @ts-ignore - circular types cannot infer. Ignore in case there are any. This comment is always added, it does not indicate if this particular type could infer or not. - unionFooBarWithArgs: $.field( - 'unionFooBarWithArgs', - $.Output.Nullable(() => FooBarUnion), - $.Args({ id: $.Input.Field($.Input.Nullable($Scalar.ID)) }, true), - ), - // @ts-ignore - circular types cannot infer. Ignore in case there are any. This comment is always added, it does not indicate if this particular type could infer or not. - unionObject: $.field('unionObject', $.Output.Nullable(() => ObjectUnion)), - // @ts-ignore - circular types cannot infer. Ignore in case there are any. This comment is always added, it does not indicate if this particular type could infer or not. - unionObjectNonNull: $.field('unionObjectNonNull', () => ObjectUnion), -}) -export const $Index: Index = { - name: Data.Name, - RootTypesPresent: ['Mutation', 'Query'] as const, - RootUnion: undefined as any, // Type level only. - Root: { - Query, - Mutation, - Subscription: null, - }, - allTypes: { - Mutation, - Query, - DateUnion, - FooBarUnion, - Result, - lowerCaseUnion, - Bar, - DateObject1, - DateObject2, - ErrorOne, - ErrorTwo, - Foo, - Object1, - Object1ImplementingInterface, - Object2ImplementingInterface, - ObjectNested, - ObjectUnion, - lowerCaseObject, - lowerCaseObject2, - DateInterface1, - Error, - Interface, - ABCEnum, - Case, - }, - objects: { - Bar, - DateObject1, - DateObject2, - ErrorOne, - ErrorTwo, - Foo, - Object1, - Object1ImplementingInterface, - Object2ImplementingInterface, - ObjectNested, - ObjectUnion, - lowerCaseObject, - lowerCaseObject2, - }, - unions: { - DateUnion, - FooBarUnion, - Result, - lowerCaseUnion, - }, - interfaces: { - DateInterface1, - Error, - Interface, - }, - customScalars: { - input: $customScalarsIndex, - }, - error: { - objects: { - ErrorOne, - ErrorTwo, - }, - objectsTypename: { - ErrorOne: { __typename: 'ErrorOne' }, - ErrorTwo: { __typename: 'ErrorTwo' }, - }, - rootResultFields: { - Subscription: {}, - Mutation: {}, - Query: { - result: 'result' as const, - resultNonNull: 'resultNonNull' as const, - }, - }, - }, -} diff --git a/tests/_/schemas/kitchen-sink/graffle/modules/SelectionSets.ts b/tests/_/schemas/kitchen-sink/graffle/modules/SelectionSets.ts index 3f0c4bd21..4632a1147 100644 --- a/tests/_/schemas/kitchen-sink/graffle/modules/SelectionSets.ts +++ b/tests/_/schemas/kitchen-sink/graffle/modules/SelectionSets.ts @@ -137,6 +137,12 @@ export interface Query { * Select the `abcEnum` field on the `Query` object. Its type is Enum. */ abcEnum?: Query.abcEnum$Expanded | $Select.SelectAlias.SelectAlias + /** + * Select the `argInputObjectCircular` field on the `Query` object. Its type is `String` (a `Scalar`). + */ + argInputObjectCircular?: + | Query.argInputObjectCircular$Expanded + | $Select.SelectAlias.SelectAlias /** * Select the `date` field on the `Query` object. Its type is `Date` (a `Scalar`). */ @@ -399,6 +405,30 @@ export namespace Query { export type abcEnum = $Select.Indicator.NoArgsIndicator + export type argInputObjectCircular$SelectionSetArguments = { + input?: _RefDefs._InputObjectCircular | undefined | null + } + export type argInputObjectCircular$SelectionSet = $Utilities.Simplify< + $Select.Bases.Base & { + /** + * Arguments for `argInputObjectCircular` field. + * No arguments are required so you may omit this. + */ + $?: argInputObjectCircular$SelectionSetArguments + } + > + + /** + * This is the "expanded" version of the `argInputObjectCircular` type. It is identical except for the fact + * that IDEs will display its contents (a union type) directly, rather than the name of this type. + * In some cases, this is a preferable DX, making the types easier to read for users. + */ + export type argInputObjectCircular$Expanded = $Utilities.UnionExpanded< + $Select.Indicator.Indicator | argInputObjectCircular$SelectionSet + > + + export type argInputObjectCircular = $Select.Indicator.Indicator | argInputObjectCircular$SelectionSet + /** * This is the "expanded" version of the `date` type. It is identical except for the fact * that IDEs will display its contents (a union type) directly, rather than the name of this type. @@ -900,6 +930,11 @@ export interface InputObject { idRequired: string } +export interface InputObjectCircular { + circular?: _RefDefs._InputObjectCircular | undefined | null + date?: $Scalar.DateDecoded | undefined | null +} + export interface InputObjectNested { InputObject?: _RefDefs._InputObject | undefined | null } @@ -2042,6 +2077,7 @@ export namespace _RefDefs { export type _ABCEnum = ABCEnum export type _Case = Case export type _InputObject = InputObject + export type _InputObjectCircular = InputObjectCircular export type _InputObjectNested = InputObjectNested export type _InputObjectNestedNonNull = InputObjectNestedNonNull export type _DateInterface1 = DateInterface1 diff --git a/tests/_/schemas/kitchen-sink/schema.graphql b/tests/_/schemas/kitchen-sink/schema.graphql index 91c8d86fb..9bfc1c357 100644 --- a/tests/_/schemas/kitchen-sink/schema.graphql +++ b/tests/_/schemas/kitchen-sink/schema.graphql @@ -66,6 +66,11 @@ input InputObject { idRequired: ID! } +input InputObjectCircular { + circular: InputObjectCircular + date: Date +} + input InputObjectNested { InputObject: InputObject } @@ -116,6 +121,7 @@ type Query { """Query enum field documentation.""" abcEnum: ABCEnum + argInputObjectCircular(input: InputObjectCircular): String date: Date dateArg(date: Date): Date dateArgInputObject(input: InputObject): Date diff --git a/tests/_/schemas/kitchen-sink/schema.ts b/tests/_/schemas/kitchen-sink/schema.ts index c6e9b71d7..eeb573486 100644 --- a/tests/_/schemas/kitchen-sink/schema.ts +++ b/tests/_/schemas/kitchen-sink/schema.ts @@ -152,6 +152,13 @@ const InputObjectNested = builder.inputType(`InputObjectNested`, { }), }) +const InputObjectCircular = builder.inputRef(`InputObjectCircular`).implement({ + fields: t => ({ + date: t.field({ type: `Date` }), + circular: t.field({ type: InputObjectCircular }), + }), +}) + const InputObjectNestedNonNull = builder.inputType(`InputObjectNestedNonNull`, { fields: t => ({ InputObject: t.field({ type: InputObject, required: true }), @@ -233,6 +240,11 @@ builder.queryType({ type: t.listRef(`Date`, { nullable: false }), resolve: () => [db.date0, db.date1], }), + argInputObjectCircular: t.field({ + type: `String`, + args: { input: t.arg({ type: InputObjectCircular }) }, + resolve: (_, args) => JSON.stringify(args), + }), dateArg: t.field({ type: `Date`, args: { date: t.arg({ type: `Date` }) }, diff --git a/tests/_/schemas/mutation-only/graffle/modules/Client.ts b/tests/_/schemas/mutation-only/graffle/modules/Client.ts index 1041a03ed..cbf44a758 100644 --- a/tests/_/schemas/mutation-only/graffle/modules/Client.ts +++ b/tests/_/schemas/mutation-only/graffle/modules/Client.ts @@ -1,4 +1,5 @@ import { createPrefilled } from '../../../../../../src/entrypoints/client.js' -import { $defaultSchemaUrl, $Index } from './SchemaRuntime.js' +import { defaultSchemaUrl } from './Data.js' +import { schemaDrivenDataMap } from './SchemaDrivenDataMap.js' -export const create = createPrefilled(`MutationOnly`, $Index, $defaultSchemaUrl) +export const create = createPrefilled(`MutationOnly`, schemaDrivenDataMap, defaultSchemaUrl) diff --git a/tests/_/schemas/mutation-only/graffle/modules/Data.ts b/tests/_/schemas/mutation-only/graffle/modules/Data.ts index 76bc6ab22..9d6d8a207 100644 --- a/tests/_/schemas/mutation-only/graffle/modules/Data.ts +++ b/tests/_/schemas/mutation-only/graffle/modules/Data.ts @@ -1,2 +1,4 @@ export const Name = `MutationOnly` export type Name = 'MutationOnly' + +export const defaultSchemaUrl = undefined diff --git a/tests/_/schemas/mutation-only/graffle/modules/MethodsRoot.ts b/tests/_/schemas/mutation-only/graffle/modules/MethodsRoot.ts index 97c8c775b..72ea4f2c9 100644 --- a/tests/_/schemas/mutation-only/graffle/modules/MethodsRoot.ts +++ b/tests/_/schemas/mutation-only/graffle/modules/MethodsRoot.ts @@ -24,20 +24,20 @@ export interface MutationMethods<$Config extends Utils.Config> { 'Mutation' > > - id: () => Promise< + id: <$SelectionSet>(selectionSet?: Utils.Exact<$SelectionSet, SelectionSet.Mutation.id>) => Promise< Utils.ResolveOutputReturnRootField< $Config, Index, 'id', - InferResult.Field + InferResult.Field<$SelectionSet, Index['Root']['Mutation']['fields']['id'], Index> > > - idNonNull: () => Promise< + idNonNull: <$SelectionSet>(selectionSet?: Utils.Exact<$SelectionSet, SelectionSet.Mutation.idNonNull>) => Promise< Utils.ResolveOutputReturnRootField< $Config, Index, 'idNonNull', - InferResult.Field + InferResult.Field<$SelectionSet, Index['Root']['Mutation']['fields']['idNonNull'], Index> > > } diff --git a/tests/_/schemas/mutation-only/graffle/modules/RuntimeCustomScalars.ts b/tests/_/schemas/mutation-only/graffle/modules/RuntimeCustomScalars.ts index 13aee9e4b..56dc44044 100644 --- a/tests/_/schemas/mutation-only/graffle/modules/RuntimeCustomScalars.ts +++ b/tests/_/schemas/mutation-only/graffle/modules/RuntimeCustomScalars.ts @@ -1,4 +1,23 @@ +import type * as $Utilities from '../../../../../../src/entrypoints/utilities-for-generated.js' import * as CustomScalars from './Scalar.js' +// +// +// +// +// +// +// ================================================================================================== +// GraphQLEnumType +// ================================================================================================== +// +// +// +// +// +// + +// None of your GraphQLEnumTypes have custom scalars. + // // // @@ -87,7 +106,31 @@ import * as CustomScalars from './Scalar.js' // // -// None of your GraphQLRootTypes have custom scalars. +const Mutation: $Utilities.SchemaDrivenDataMap.OutputObject = { + f: { + id: {}, + idNonNull: {}, + }, +} + +// +// +// +// +// +// +// ================================================================================================== +// Reference Assignments +// (avoids circular assignment issues) +// ================================================================================================== +// +// +// +// +// +// + +// None of your types have references to other non-scalar/enum types. // // @@ -105,4 +148,6 @@ import * as CustomScalars from './Scalar.js' // // -export const $index = {} +export const $index = { + Mutation, +} diff --git a/tests/_/schemas/mutation-only/graffle/modules/SchemaDrivenDataMap.ts b/tests/_/schemas/mutation-only/graffle/modules/SchemaDrivenDataMap.ts new file mode 100644 index 000000000..39fabd26d --- /dev/null +++ b/tests/_/schemas/mutation-only/graffle/modules/SchemaDrivenDataMap.ts @@ -0,0 +1,204 @@ +import type * as $Utilities from '../../../../../../src/entrypoints/utilities-for-generated.js' +import * as $Scalar from './Scalar.js' +// +// +// +// +// +// +// ================================================================================================== +// GraphQLScalarType +// ================================================================================================== +// +// +// +// +// +// + +const ID = $Scalar.ID + +const Boolean = $Scalar.Boolean + +const String = $Scalar.String + +// +// +// +// +// +// +// ================================================================================================== +// GraphQLScalarTypeCustom +// ================================================================================================== +// +// +// +// +// +// + +// None of your GraphQLScalarTypeCustoms have custom scalars. + +// +// +// +// +// +// +// ================================================================================================== +// GraphQLEnumType +// ================================================================================================== +// +// +// +// +// +// + +// None of your GraphQLEnumTypes have custom scalars. + +// +// +// +// +// +// +// ================================================================================================== +// GraphQLInputObjectType +// ================================================================================================== +// +// +// +// +// +// + +// None of your GraphQLInputObjectTypes have custom scalars. + +// +// +// +// +// +// +// ================================================================================================== +// GraphQLObjectType +// ================================================================================================== +// +// +// +// +// +// + +// None of your GraphQLObjectTypes have custom scalars. + +// +// +// +// +// +// +// ================================================================================================== +// GraphQLInterfaceType +// ================================================================================================== +// +// +// +// +// +// + +// None of your GraphQLInterfaceTypes have custom scalars. + +// +// +// +// +// +// +// ================================================================================================== +// GraphQLUnionType +// ================================================================================================== +// +// +// +// +// +// + +// None of your GraphQLUnionTypes have custom scalars. + +// +// +// +// +// +// +// ================================================================================================== +// GraphQLRootType +// ================================================================================================== +// +// +// +// +// +// + +const Mutation: $Utilities.SchemaDrivenDataMap.OutputObject = { + f: { + id: {}, + idNonNull: {}, + }, +} + +// +// +// +// +// +// +// ================================================================================================== +// Reference Assignments +// (avoids circular assignment issues) +// ================================================================================================== +// +// +// +// +// +// + +// None of your types have references to other non-scalar/enum types. + +// +// +// +// +// +// +// ================================================================================================== +// Index +// ================================================================================================== +// +// +// +// +// +// + +const $schemaDrivenDataMap: $Utilities.SchemaDrivenDataMap = { + roots: { + Mutation, + }, + directives: {}, + types: { + ID, + Boolean, + String, + Mutation, + }, +} + +export { $schemaDrivenDataMap as schemaDrivenDataMap } diff --git a/tests/_/schemas/mutation-only/graffle/modules/SchemaRuntime.ts b/tests/_/schemas/mutation-only/graffle/modules/SchemaRuntime.ts deleted file mode 100644 index 5e32c0a8c..000000000 --- a/tests/_/schemas/mutation-only/graffle/modules/SchemaRuntime.ts +++ /dev/null @@ -1,42 +0,0 @@ -/* eslint-disable */ -import * as $ from '../../../../../../src/entrypoints/schema.js' -import * as Data from './Data.js' -import { $index as $customScalarsIndex } from './RuntimeCustomScalars.js' -import * as $Scalar from './Scalar.js' -import type { Index } from './SchemaIndex.js' -export const $defaultSchemaUrl = undefined - -// @ts-ignore - circular types cannot infer. Ignore in case there are any. This comment is always added, it does not indicate if this particular type could infer or not. -export const Mutation = $.Object$(`Mutation`, { - id: $.field('id', $.Output.Nullable($Scalar.ID)), - idNonNull: $.field('idNonNull', $Scalar.ID), -}) -export const $Index: Index = { - name: Data.Name, - RootTypesPresent: ['Mutation'] as const, - RootUnion: undefined as any, // Type level only. - Root: { - Query: null, - Mutation, - Subscription: null, - }, - allTypes: { - Mutation, - }, - objects: {}, - unions: {}, - interfaces: {}, - customScalars: { - input: $customScalarsIndex, - }, - error: { - objects: {}, - objectsTypename: {}, - rootResultFields: { - Query: {}, - - Subscription: {}, - Mutation: {}, - }, - }, -} diff --git a/tests/_/schemas/pokemon/graffle/modules/Client.ts b/tests/_/schemas/pokemon/graffle/modules/Client.ts index 67d31a6e2..28a57b572 100644 --- a/tests/_/schemas/pokemon/graffle/modules/Client.ts +++ b/tests/_/schemas/pokemon/graffle/modules/Client.ts @@ -1,4 +1,5 @@ import { createPrefilled } from '../../../../../../src/entrypoints/client.js' -import { $defaultSchemaUrl, $Index } from './SchemaRuntime.js' +import { defaultSchemaUrl } from './Data.js' +import { schemaDrivenDataMap } from './SchemaDrivenDataMap.js' -export const create = createPrefilled(`Pokemon`, $Index, $defaultSchemaUrl) +export const create = createPrefilled(`Pokemon`, schemaDrivenDataMap, defaultSchemaUrl) diff --git a/tests/_/schemas/pokemon/graffle/modules/Data.ts b/tests/_/schemas/pokemon/graffle/modules/Data.ts index c5ba8a7d0..2f19c3ff4 100644 --- a/tests/_/schemas/pokemon/graffle/modules/Data.ts +++ b/tests/_/schemas/pokemon/graffle/modules/Data.ts @@ -1,2 +1,4 @@ export const Name = `Pokemon` export type Name = 'Pokemon' + +export const defaultSchemaUrl = new URL('http://localhost:3000/graphql') diff --git a/tests/_/schemas/pokemon/graffle/modules/RuntimeCustomScalars.ts b/tests/_/schemas/pokemon/graffle/modules/RuntimeCustomScalars.ts index 13aee9e4b..bfbe140ce 100644 --- a/tests/_/schemas/pokemon/graffle/modules/RuntimeCustomScalars.ts +++ b/tests/_/schemas/pokemon/graffle/modules/RuntimeCustomScalars.ts @@ -1,4 +1,36 @@ +import type * as $Utilities from '../../../../../../src/entrypoints/utilities-for-generated.js' import * as CustomScalars from './Scalar.js' +// +// +// +// +// +// +// ================================================================================================== +// GraphQLEnumType +// ================================================================================================== +// +// +// +// +// +// + +const BattleWildResult: $Utilities.SchemaDrivenDataMap.Enum = { + k: 'enum', + n: 'BattleWildResult', +} + +const PokemonType: $Utilities.SchemaDrivenDataMap.Enum = { + k: 'enum', + n: 'PokemonType', +} + +const TrainerClass: $Utilities.SchemaDrivenDataMap.Enum = { + k: 'enum', + n: 'TrainerClass', +} + // // // @@ -15,7 +47,29 @@ import * as CustomScalars from './Scalar.js' // // -// None of your GraphQLInputObjectTypes have custom scalars. +const DateFilter: $Utilities.SchemaDrivenDataMap.InputObject = { + n: 'DateFilter', + f: { + gte: {}, + lte: {}, + }, +} + +const PokemonFilter: $Utilities.SchemaDrivenDataMap.InputObject = { + n: 'PokemonFilter', + f: { + birthday: {}, + name: {}, + }, +} + +const StringFilter: $Utilities.SchemaDrivenDataMap.InputObject = { + n: 'StringFilter', + f: { + contains: {}, + in: {}, + }, +} // // @@ -33,7 +87,110 @@ import * as CustomScalars from './Scalar.js' // // -// None of your GraphQLObjectTypes have custom scalars. +const BattleRoyale: $Utilities.SchemaDrivenDataMap.OutputObject = { + f: { + combatants: { + // nt: CombatantMultiPokemon, <-- Assigned later to avoid potential circular dependency. + }, + date: {}, + id: {}, + winner: { + // nt: Trainer, <-- Assigned later to avoid potential circular dependency. + }, + }, +} + +const BattleTrainer: $Utilities.SchemaDrivenDataMap.OutputObject = { + f: { + combatant1: { + // nt: CombatantSinglePokemon, <-- Assigned later to avoid potential circular dependency. + }, + combatant2: { + // nt: CombatantSinglePokemon, <-- Assigned later to avoid potential circular dependency. + }, + date: {}, + id: {}, + winner: { + // nt: Trainer, <-- Assigned later to avoid potential circular dependency. + }, + }, +} + +const BattleWild: $Utilities.SchemaDrivenDataMap.OutputObject = { + f: { + date: {}, + id: {}, + pokemon: { + // nt: Pokemon, <-- Assigned later to avoid potential circular dependency. + }, + result: {}, + trainer: { + // nt: Trainer, <-- Assigned later to avoid potential circular dependency. + }, + wildPokemons: { + // nt: Pokemon, <-- Assigned later to avoid potential circular dependency. + }, + }, +} + +const CombatantMultiPokemon: $Utilities.SchemaDrivenDataMap.OutputObject = { + f: { + pokemons: { + // nt: Pokemon, <-- Assigned later to avoid potential circular dependency. + }, + trainer: { + // nt: Trainer, <-- Assigned later to avoid potential circular dependency. + }, + }, +} + +const CombatantSinglePokemon: $Utilities.SchemaDrivenDataMap.OutputObject = { + f: { + pokemon: { + // nt: Pokemon, <-- Assigned later to avoid potential circular dependency. + }, + trainer: { + // nt: Trainer, <-- Assigned later to avoid potential circular dependency. + }, + }, +} + +const Patron: $Utilities.SchemaDrivenDataMap.OutputObject = { + f: { + id: {}, + money: {}, + name: {}, + }, +} + +const Pokemon: $Utilities.SchemaDrivenDataMap.OutputObject = { + f: { + attack: {}, + birthday: {}, + defense: {}, + hp: {}, + id: {}, + name: {}, + trainer: { + // nt: Trainer, <-- Assigned later to avoid potential circular dependency. + }, + type: {}, + }, +} + +const Trainer: $Utilities.SchemaDrivenDataMap.OutputObject = { + f: { + class: {}, + fans: { + // nt: Patron, <-- Assigned later to avoid potential circular dependency. + }, + id: {}, + name: {}, + pokemon: { + // nt: Pokemon, <-- Assigned later to avoid potential circular dependency. + }, + }, +} // // @@ -51,7 +208,7 @@ import * as CustomScalars from './Scalar.js' // // -// None of your GraphQLInterfaceTypes have custom scalars. +const Being = { f: {} } // // @@ -69,7 +226,7 @@ import * as CustomScalars from './Scalar.js' // // -// None of your GraphQLUnionTypes have custom scalars. +const Battle = { f: {} } // // @@ -87,7 +244,120 @@ import * as CustomScalars from './Scalar.js' // // -// None of your GraphQLRootTypes have custom scalars. +const Mutation: $Utilities.SchemaDrivenDataMap.OutputObject = { + f: { + addPokemon: { + a: { + attack: { + it: [0], + nt: CustomScalars.Int, + }, + defense: { + it: [0], + nt: CustomScalars.Int, + }, + hp: { + it: [0], + nt: CustomScalars.Int, + }, + name: { + it: [1], + nt: CustomScalars.String, + }, + type: { + it: [1], + nt: PokemonType, + }, + }, + // nt: Pokemon, <-- Assigned later to avoid potential circular dependency. + }, + }, +} + +const Query: $Utilities.SchemaDrivenDataMap.OutputObject = { + f: { + battles: { + // nt: Battle, <-- Assigned later to avoid potential circular dependency. + }, + beings: { + // nt: Being, <-- Assigned later to avoid potential circular dependency. + }, + pokemon: { + // nt: Pokemon, <-- Assigned later to avoid potential circular dependency. + }, + pokemonByName: { + a: { + name: { + it: [1], + nt: CustomScalars.String, + }, + }, + // nt: Pokemon, <-- Assigned later to avoid potential circular dependency. + }, + pokemons: { + a: { + filter: { + it: [0], + nt: PokemonFilter, + }, + }, + // nt: Pokemon, <-- Assigned later to avoid potential circular dependency. + }, + trainerByName: { + a: { + name: { + it: [1], + nt: CustomScalars.String, + }, + }, + // nt: Trainer, <-- Assigned later to avoid potential circular dependency. + }, + trainers: { + // nt: Trainer, <-- Assigned later to avoid potential circular dependency. + }, + }, +} + +// +// +// +// +// +// +// ================================================================================================== +// Reference Assignments +// (avoids circular assignment issues) +// ================================================================================================== +// +// +// +// +// +// + +BattleRoyale.f['combatants']!.nt = CombatantMultiPokemon +BattleRoyale.f['winner']!.nt = Trainer +BattleTrainer.f['combatant1']!.nt = CombatantSinglePokemon +BattleTrainer.f['combatant2']!.nt = CombatantSinglePokemon +BattleTrainer.f['winner']!.nt = Trainer +BattleWild.f['pokemon']!.nt = Pokemon +BattleWild.f['trainer']!.nt = Trainer +BattleWild.f['wildPokemons']!.nt = Pokemon +CombatantMultiPokemon.f['pokemons']!.nt = Pokemon +CombatantMultiPokemon.f['trainer']!.nt = Trainer +CombatantSinglePokemon.f['pokemon']!.nt = Pokemon +CombatantSinglePokemon.f['trainer']!.nt = Trainer +Pokemon.f['trainer']!.nt = Trainer +Trainer.f['fans']!.nt = Patron +Trainer.f['pokemon']!.nt = Pokemon +Mutation.f['addPokemon']!.nt = Pokemon +Query.f['battles']!.nt = Battle +Query.f['beings']!.nt = Being +Query.f['pokemon']!.nt = Pokemon +Query.f['pokemonByName']!.nt = Pokemon +Query.f['pokemons']!.nt = Pokemon +Query.f['trainerByName']!.nt = Trainer +Query.f['trainers']!.nt = Trainer // // @@ -105,4 +375,7 @@ import * as CustomScalars from './Scalar.js' // // -export const $index = {} +export const $index = { + Mutation, + Query, +} diff --git a/tests/_/schemas/pokemon/graffle/modules/SchemaDrivenDataMap.ts b/tests/_/schemas/pokemon/graffle/modules/SchemaDrivenDataMap.ts new file mode 100644 index 000000000..07177dd10 --- /dev/null +++ b/tests/_/schemas/pokemon/graffle/modules/SchemaDrivenDataMap.ts @@ -0,0 +1,459 @@ +import type * as $Utilities from '../../../../../../src/entrypoints/utilities-for-generated.js' +import * as $Scalar from './Scalar.js' +// +// +// +// +// +// +// ================================================================================================== +// GraphQLScalarType +// ================================================================================================== +// +// +// +// +// +// + +const Float = $Scalar.Float + +const ID = $Scalar.ID + +const String = $Scalar.String + +const Int = $Scalar.Int + +const Boolean = $Scalar.Boolean + +// +// +// +// +// +// +// ================================================================================================== +// GraphQLScalarTypeCustom +// ================================================================================================== +// +// +// +// +// +// + +// None of your GraphQLScalarTypeCustoms have custom scalars. + +// +// +// +// +// +// +// ================================================================================================== +// GraphQLEnumType +// ================================================================================================== +// +// +// +// +// +// + +const BattleWildResult: $Utilities.SchemaDrivenDataMap.Enum = { + k: 'enum', + n: 'BattleWildResult', +} + +const PokemonType: $Utilities.SchemaDrivenDataMap.Enum = { + k: 'enum', + n: 'PokemonType', +} + +const TrainerClass: $Utilities.SchemaDrivenDataMap.Enum = { + k: 'enum', + n: 'TrainerClass', +} + +// +// +// +// +// +// +// ================================================================================================== +// GraphQLInputObjectType +// ================================================================================================== +// +// +// +// +// +// + +const DateFilter: $Utilities.SchemaDrivenDataMap.InputObject = { + n: 'DateFilter', + f: { + gte: {}, + lte: {}, + }, +} + +const PokemonFilter: $Utilities.SchemaDrivenDataMap.InputObject = { + n: 'PokemonFilter', + f: { + birthday: {}, + name: {}, + }, +} + +const StringFilter: $Utilities.SchemaDrivenDataMap.InputObject = { + n: 'StringFilter', + f: { + contains: {}, + in: {}, + }, +} + +// +// +// +// +// +// +// ================================================================================================== +// GraphQLObjectType +// ================================================================================================== +// +// +// +// +// +// + +const BattleRoyale: $Utilities.SchemaDrivenDataMap.OutputObject = { + f: { + combatants: { + // nt: CombatantMultiPokemon, <-- Assigned later to avoid potential circular dependency. + }, + date: {}, + id: {}, + winner: { + // nt: Trainer, <-- Assigned later to avoid potential circular dependency. + }, + }, +} + +const BattleTrainer: $Utilities.SchemaDrivenDataMap.OutputObject = { + f: { + combatant1: { + // nt: CombatantSinglePokemon, <-- Assigned later to avoid potential circular dependency. + }, + combatant2: { + // nt: CombatantSinglePokemon, <-- Assigned later to avoid potential circular dependency. + }, + date: {}, + id: {}, + winner: { + // nt: Trainer, <-- Assigned later to avoid potential circular dependency. + }, + }, +} + +const BattleWild: $Utilities.SchemaDrivenDataMap.OutputObject = { + f: { + date: {}, + id: {}, + pokemon: { + // nt: Pokemon, <-- Assigned later to avoid potential circular dependency. + }, + result: {}, + trainer: { + // nt: Trainer, <-- Assigned later to avoid potential circular dependency. + }, + wildPokemons: { + // nt: Pokemon, <-- Assigned later to avoid potential circular dependency. + }, + }, +} + +const CombatantMultiPokemon: $Utilities.SchemaDrivenDataMap.OutputObject = { + f: { + pokemons: { + // nt: Pokemon, <-- Assigned later to avoid potential circular dependency. + }, + trainer: { + // nt: Trainer, <-- Assigned later to avoid potential circular dependency. + }, + }, +} + +const CombatantSinglePokemon: $Utilities.SchemaDrivenDataMap.OutputObject = { + f: { + pokemon: { + // nt: Pokemon, <-- Assigned later to avoid potential circular dependency. + }, + trainer: { + // nt: Trainer, <-- Assigned later to avoid potential circular dependency. + }, + }, +} + +const Patron: $Utilities.SchemaDrivenDataMap.OutputObject = { + f: { + id: {}, + money: {}, + name: {}, + }, +} + +const Pokemon: $Utilities.SchemaDrivenDataMap.OutputObject = { + f: { + attack: {}, + birthday: {}, + defense: {}, + hp: {}, + id: {}, + name: {}, + trainer: { + // nt: Trainer, <-- Assigned later to avoid potential circular dependency. + }, + type: {}, + }, +} + +const Trainer: $Utilities.SchemaDrivenDataMap.OutputObject = { + f: { + class: {}, + fans: { + // nt: Patron, <-- Assigned later to avoid potential circular dependency. + }, + id: {}, + name: {}, + pokemon: { + // nt: Pokemon, <-- Assigned later to avoid potential circular dependency. + }, + }, +} + +// +// +// +// +// +// +// ================================================================================================== +// GraphQLInterfaceType +// ================================================================================================== +// +// +// +// +// +// + +const Being: $Utilities.SchemaDrivenDataMap.OutputObject = { + f: {}, +} + +// +// +// +// +// +// +// ================================================================================================== +// GraphQLUnionType +// ================================================================================================== +// +// +// +// +// +// + +const Battle: $Utilities.SchemaDrivenDataMap.OutputObject = { + f: {}, +} + +// +// +// +// +// +// +// ================================================================================================== +// GraphQLRootType +// ================================================================================================== +// +// +// +// +// +// + +const Mutation: $Utilities.SchemaDrivenDataMap.OutputObject = { + f: { + addPokemon: { + a: { + attack: { + nt: Int, + it: [0], + }, + defense: { + nt: Int, + it: [0], + }, + hp: { + nt: Int, + it: [0], + }, + name: { + nt: String, + it: [1], + }, + type: { + nt: PokemonType, + it: [1], + }, + }, + // nt: Pokemon, <-- Assigned later to avoid potential circular dependency. + }, + }, +} + +const Query: $Utilities.SchemaDrivenDataMap.OutputObject = { + f: { + battles: { + // nt: Battle, <-- Assigned later to avoid potential circular dependency. + }, + beings: { + // nt: Being, <-- Assigned later to avoid potential circular dependency. + }, + pokemon: { + // nt: Pokemon, <-- Assigned later to avoid potential circular dependency. + }, + pokemonByName: { + a: { + name: { + nt: String, + it: [1], + }, + }, + // nt: Pokemon, <-- Assigned later to avoid potential circular dependency. + }, + pokemons: { + a: { + filter: { + nt: PokemonFilter, + it: [0], + }, + }, + // nt: Pokemon, <-- Assigned later to avoid potential circular dependency. + }, + trainerByName: { + a: { + name: { + nt: String, + it: [1], + }, + }, + // nt: Trainer, <-- Assigned later to avoid potential circular dependency. + }, + trainers: { + // nt: Trainer, <-- Assigned later to avoid potential circular dependency. + }, + }, +} + +// +// +// +// +// +// +// ================================================================================================== +// Reference Assignments +// (avoids circular assignment issues) +// ================================================================================================== +// +// +// +// +// +// + +BattleRoyale.f['combatants']!.nt = CombatantMultiPokemon +BattleRoyale.f['winner']!.nt = Trainer +BattleTrainer.f['combatant1']!.nt = CombatantSinglePokemon +BattleTrainer.f['combatant2']!.nt = CombatantSinglePokemon +BattleTrainer.f['winner']!.nt = Trainer +BattleWild.f['pokemon']!.nt = Pokemon +BattleWild.f['trainer']!.nt = Trainer +BattleWild.f['wildPokemons']!.nt = Pokemon +CombatantMultiPokemon.f['pokemons']!.nt = Pokemon +CombatantMultiPokemon.f['trainer']!.nt = Trainer +CombatantSinglePokemon.f['pokemon']!.nt = Pokemon +CombatantSinglePokemon.f['trainer']!.nt = Trainer +Pokemon.f['trainer']!.nt = Trainer +Trainer.f['fans']!.nt = Patron +Trainer.f['pokemon']!.nt = Pokemon +Mutation.f['addPokemon']!.nt = Pokemon +Query.f['battles']!.nt = Battle +Query.f['beings']!.nt = Being +Query.f['pokemon']!.nt = Pokemon +Query.f['pokemonByName']!.nt = Pokemon +Query.f['pokemons']!.nt = Pokemon +Query.f['trainerByName']!.nt = Trainer +Query.f['trainers']!.nt = Trainer + +// +// +// +// +// +// +// ================================================================================================== +// Index +// ================================================================================================== +// +// +// +// +// +// + +const $schemaDrivenDataMap: $Utilities.SchemaDrivenDataMap = { + roots: { + Mutation, + Query, + }, + directives: {}, + types: { + Float, + ID, + String, + Int, + Boolean, + BattleWildResult, + PokemonType, + TrainerClass, + DateFilter, + PokemonFilter, + StringFilter, + BattleRoyale, + BattleTrainer, + BattleWild, + CombatantMultiPokemon, + CombatantSinglePokemon, + Patron, + Pokemon, + Trainer, + Being, + Battle, + Mutation, + Query, + }, +} + +export { $schemaDrivenDataMap as schemaDrivenDataMap } diff --git a/tests/_/schemas/pokemon/graffle/modules/SchemaRuntime.ts b/tests/_/schemas/pokemon/graffle/modules/SchemaRuntime.ts deleted file mode 100644 index 4f3e0af01..000000000 --- a/tests/_/schemas/pokemon/graffle/modules/SchemaRuntime.ts +++ /dev/null @@ -1,228 +0,0 @@ -/* eslint-disable */ -import * as $ from '../../../../../../src/entrypoints/schema.js' -import * as Data from './Data.js' -import { $index as $customScalarsIndex } from './RuntimeCustomScalars.js' -import * as $Scalar from './Scalar.js' -import type { Index } from './SchemaIndex.js' -export const $defaultSchemaUrl = new URL('http://localhost:3000/graphql') -export const BattleWildResult = $.Enum(`BattleWildResult`, [`pokemonsCaptured`, `pokemonsDefeated`, `trainerDefeated`]) -export const PokemonType = $.Enum(`PokemonType`, [`bug`, `electric`, `fire`, `grass`, `water`]) -export const TrainerClass = $.Enum(`TrainerClass`, [ - `bugCatcher`, - `camper`, - `picnicker`, - `psychic`, - `psychicMedium`, - `psychicYoungster`, - `sailor`, - `superNerd`, - `tamer`, - `teamRocketGrunt`, - `triathlete`, - `youngster`, - `youth`, -]) -export const DateFilter = $.InputObject(`DateFilter`, { - gte: $.Input.Field($.Input.Nullable($Scalar.Float)), - lte: $.Input.Field($.Input.Nullable($Scalar.Float)), -}, true) - -export const PokemonFilter = $.InputObject(`PokemonFilter`, { - birthday: $.Input.Field(() => $.Input.Nullable(DateFilter)), - name: $.Input.Field(() => $.Input.Nullable(StringFilter)), -}, true) - -export const StringFilter = $.InputObject(`StringFilter`, { - contains: $.Input.Field($.Input.Nullable($Scalar.String)), - in: $.Input.Field($.Input.Nullable($.Input.List($Scalar.String))), -}, true) -// @ts-ignore - circular types cannot infer. Ignore in case there are any. This comment is always added, it does not indicate if this particular type could infer or not. -export const BattleRoyale = $.Object$(`BattleRoyale`, { - // @ts-ignore - circular types cannot infer. Ignore in case there are any. This comment is always added, it does not indicate if this particular type could infer or not. - combatants: $.field('combatants', $.Output.Nullable($.Output.List(() => CombatantMultiPokemon))), - date: $.field('date', $.Output.Nullable($Scalar.Float)), - id: $.field('id', $.Output.Nullable($Scalar.ID)), - // @ts-ignore - circular types cannot infer. Ignore in case there are any. This comment is always added, it does not indicate if this particular type could infer or not. - winner: $.field('winner', $.Output.Nullable(() => Trainer)), -}) - -// @ts-ignore - circular types cannot infer. Ignore in case there are any. This comment is always added, it does not indicate if this particular type could infer or not. -export const BattleTrainer = $.Object$(`BattleTrainer`, { - // @ts-ignore - circular types cannot infer. Ignore in case there are any. This comment is always added, it does not indicate if this particular type could infer or not. - combatant1: $.field('combatant1', $.Output.Nullable(() => CombatantSinglePokemon)), - // @ts-ignore - circular types cannot infer. Ignore in case there are any. This comment is always added, it does not indicate if this particular type could infer or not. - combatant2: $.field('combatant2', $.Output.Nullable(() => CombatantSinglePokemon)), - date: $.field('date', $.Output.Nullable($Scalar.Float)), - id: $.field('id', $.Output.Nullable($Scalar.ID)), - // @ts-ignore - circular types cannot infer. Ignore in case there are any. This comment is always added, it does not indicate if this particular type could infer or not. - winner: $.field('winner', $.Output.Nullable(() => Trainer)), -}) - -// @ts-ignore - circular types cannot infer. Ignore in case there are any. This comment is always added, it does not indicate if this particular type could infer or not. -export const BattleWild = $.Object$(`BattleWild`, { - date: $.field('date', $.Output.Nullable($Scalar.Float)), - id: $.field('id', $.Output.Nullable($Scalar.ID)), - // @ts-ignore - circular types cannot infer. Ignore in case there are any. This comment is always added, it does not indicate if this particular type could infer or not. - pokemon: $.field('pokemon', $.Output.Nullable(() => Pokemon)), - // @ts-ignore - circular types cannot infer. Ignore in case there are any. This comment is always added, it does not indicate if this particular type could infer or not. - result: $.field('result', $.Output.Nullable(BattleWildResult)), - // @ts-ignore - circular types cannot infer. Ignore in case there are any. This comment is always added, it does not indicate if this particular type could infer or not. - trainer: $.field('trainer', $.Output.Nullable(() => Trainer)), - // @ts-ignore - circular types cannot infer. Ignore in case there are any. This comment is always added, it does not indicate if this particular type could infer or not. - wildPokemons: $.field('wildPokemons', $.Output.Nullable($.Output.List(() => Pokemon))), -}) - -// @ts-ignore - circular types cannot infer. Ignore in case there are any. This comment is always added, it does not indicate if this particular type could infer or not. -export const CombatantMultiPokemon = $.Object$(`CombatantMultiPokemon`, { - // @ts-ignore - circular types cannot infer. Ignore in case there are any. This comment is always added, it does not indicate if this particular type could infer or not. - pokemons: $.field('pokemons', $.Output.Nullable($.Output.List(() => Pokemon))), - // @ts-ignore - circular types cannot infer. Ignore in case there are any. This comment is always added, it does not indicate if this particular type could infer or not. - trainer: $.field('trainer', $.Output.Nullable(() => Trainer)), -}) - -// @ts-ignore - circular types cannot infer. Ignore in case there are any. This comment is always added, it does not indicate if this particular type could infer or not. -export const CombatantSinglePokemon = $.Object$(`CombatantSinglePokemon`, { - // @ts-ignore - circular types cannot infer. Ignore in case there are any. This comment is always added, it does not indicate if this particular type could infer or not. - pokemon: $.field('pokemon', $.Output.Nullable(() => Pokemon)), - // @ts-ignore - circular types cannot infer. Ignore in case there are any. This comment is always added, it does not indicate if this particular type could infer or not. - trainer: $.field('trainer', $.Output.Nullable(() => Trainer)), -}) - -// @ts-ignore - circular types cannot infer. Ignore in case there are any. This comment is always added, it does not indicate if this particular type could infer or not. -export const Patron = $.Object$(`Patron`, { - id: $.field('id', $.Output.Nullable($Scalar.ID)), - money: $.field('money', $.Output.Nullable($Scalar.Int)), - name: $.field('name', $.Output.Nullable($Scalar.String)), -}) - -// @ts-ignore - circular types cannot infer. Ignore in case there are any. This comment is always added, it does not indicate if this particular type could infer or not. -export const Pokemon = $.Object$(`Pokemon`, { - attack: $.field('attack', $.Output.Nullable($Scalar.Int)), - birthday: $.field('birthday', $.Output.Nullable($Scalar.Int)), - defense: $.field('defense', $.Output.Nullable($Scalar.Int)), - hp: $.field('hp', $.Output.Nullable($Scalar.Int)), - id: $.field('id', $.Output.Nullable($Scalar.ID)), - name: $.field('name', $.Output.Nullable($Scalar.String)), - // @ts-ignore - circular types cannot infer. Ignore in case there are any. This comment is always added, it does not indicate if this particular type could infer or not. - trainer: $.field('trainer', $.Output.Nullable(() => Trainer)), - // @ts-ignore - circular types cannot infer. Ignore in case there are any. This comment is always added, it does not indicate if this particular type could infer or not. - type: $.field('type', $.Output.Nullable(PokemonType)), -}) - -// @ts-ignore - circular types cannot infer. Ignore in case there are any. This comment is always added, it does not indicate if this particular type could infer or not. -export const Trainer = $.Object$(`Trainer`, { - // @ts-ignore - circular types cannot infer. Ignore in case there are any. This comment is always added, it does not indicate if this particular type could infer or not. - class: $.field('class', $.Output.Nullable(TrainerClass)), - // @ts-ignore - circular types cannot infer. Ignore in case there are any. This comment is always added, it does not indicate if this particular type could infer or not. - fans: $.field('fans', $.Output.Nullable($.Output.List(() => Patron))), - id: $.field('id', $.Output.Nullable($Scalar.ID)), - name: $.field('name', $.Output.Nullable($Scalar.String)), - // @ts-ignore - circular types cannot infer. Ignore in case there are any. This comment is always added, it does not indicate if this particular type could infer or not. - pokemon: $.field('pokemon', $.Output.Nullable($.Output.List(() => Pokemon))), -}) -// @ts-ignore - circular types cannot infer. Ignore in case there are any. This comment is always added, it does not indicate if this particular type could infer or not. -export const Battle = $.Union(`Battle`, [BattleRoyale, BattleTrainer, BattleWild]) -export const Being = $.Interface(`Being`, { - id: $.field('id', $.Output.Nullable($Scalar.ID)), - name: $.field('name', $.Output.Nullable($Scalar.String)), -}, [Patron, Pokemon, Trainer]) -// @ts-ignore - circular types cannot infer. Ignore in case there are any. This comment is always added, it does not indicate if this particular type could infer or not. -export const Mutation = $.Object$(`Mutation`, { - // @ts-ignore - circular types cannot infer. Ignore in case there are any. This comment is always added, it does not indicate if this particular type could infer or not. - addPokemon: $.field( - 'addPokemon', - $.Output.Nullable(() => Pokemon), - $.Args({ - attack: $.Input.Field($.Input.Nullable($Scalar.Int)), - defense: $.Input.Field($.Input.Nullable($Scalar.Int)), - hp: $.Input.Field($.Input.Nullable($Scalar.Int)), - name: $.Input.Field($Scalar.String), - type: $.Input.Field(PokemonType), - }, false), - ), -}) - -// @ts-ignore - circular types cannot infer. Ignore in case there are any. This comment is always added, it does not indicate if this particular type could infer or not. -export const Query = $.Object$(`Query`, { - // @ts-ignore - circular types cannot infer. Ignore in case there are any. This comment is always added, it does not indicate if this particular type could infer or not. - battles: $.field('battles', $.Output.List(() => Battle)), - // @ts-ignore - circular types cannot infer. Ignore in case there are any. This comment is always added, it does not indicate if this particular type could infer or not. - beings: $.field('beings', $.Output.List(() => Being)), - // @ts-ignore - circular types cannot infer. Ignore in case there are any. This comment is always added, it does not indicate if this particular type could infer or not. - pokemon: $.field('pokemon', $.Output.Nullable($.Output.List(() => Pokemon))), - // @ts-ignore - circular types cannot infer. Ignore in case there are any. This comment is always added, it does not indicate if this particular type could infer or not. - pokemonByName: $.field( - 'pokemonByName', - $.Output.Nullable($.Output.List(() => Pokemon)), - $.Args({ name: $.Input.Field($Scalar.String) }, false), - ), - // @ts-ignore - circular types cannot infer. Ignore in case there are any. This comment is always added, it does not indicate if this particular type could infer or not. - pokemons: $.field( - 'pokemons', - $.Output.Nullable($.Output.List(() => Pokemon)), - $.Args({ filter: $.Input.Field($.Input.Nullable(PokemonFilter)) }, true), - ), - // @ts-ignore - circular types cannot infer. Ignore in case there are any. This comment is always added, it does not indicate if this particular type could infer or not. - trainerByName: $.field( - 'trainerByName', - $.Output.Nullable(() => Trainer), - $.Args({ name: $.Input.Field($Scalar.String) }, false), - ), - // @ts-ignore - circular types cannot infer. Ignore in case there are any. This comment is always added, it does not indicate if this particular type could infer or not. - trainers: $.field('trainers', $.Output.Nullable($.Output.List(() => Trainer))), -}) -export const $Index: Index = { - name: Data.Name, - RootTypesPresent: ['Mutation', 'Query'] as const, - RootUnion: undefined as any, // Type level only. - Root: { - Query, - Mutation, - Subscription: null, - }, - allTypes: { - Mutation, - Query, - Battle, - BattleRoyale, - BattleTrainer, - BattleWild, - CombatantMultiPokemon, - CombatantSinglePokemon, - Patron, - Pokemon, - Trainer, - Being, - BattleWildResult, - PokemonType, - TrainerClass, - }, - objects: { - BattleRoyale, - BattleTrainer, - BattleWild, - CombatantMultiPokemon, - CombatantSinglePokemon, - Patron, - Pokemon, - Trainer, - }, - unions: { - Battle, - }, - interfaces: { - Being, - }, - customScalars: { - input: $customScalarsIndex, - }, - error: { - objects: {}, - objectsTypename: {}, - rootResultFields: { - Subscription: {}, - Mutation: {}, - Query: {}, - }, - }, -} diff --git a/tests/_/schemas/query-only/graffle/modules/Client.ts b/tests/_/schemas/query-only/graffle/modules/Client.ts index 4ef12a6a1..a8861e0fc 100644 --- a/tests/_/schemas/query-only/graffle/modules/Client.ts +++ b/tests/_/schemas/query-only/graffle/modules/Client.ts @@ -1,4 +1,5 @@ import { createPrefilled } from '../../../../../../src/entrypoints/client.js' -import { $defaultSchemaUrl, $Index } from './SchemaRuntime.js' +import { defaultSchemaUrl } from './Data.js' +import { schemaDrivenDataMap } from './SchemaDrivenDataMap.js' -export const create = createPrefilled(`QueryOnly`, $Index, $defaultSchemaUrl) +export const create = createPrefilled(`QueryOnly`, schemaDrivenDataMap, defaultSchemaUrl) diff --git a/tests/_/schemas/query-only/graffle/modules/Data.ts b/tests/_/schemas/query-only/graffle/modules/Data.ts index 93955893b..f54d171f4 100644 --- a/tests/_/schemas/query-only/graffle/modules/Data.ts +++ b/tests/_/schemas/query-only/graffle/modules/Data.ts @@ -1,2 +1,4 @@ export const Name = `QueryOnly` export type Name = 'QueryOnly' + +export const defaultSchemaUrl = undefined diff --git a/tests/_/schemas/query-only/graffle/modules/MethodsRoot.ts b/tests/_/schemas/query-only/graffle/modules/MethodsRoot.ts index 3474eef2b..fcb1f4e40 100644 --- a/tests/_/schemas/query-only/graffle/modules/MethodsRoot.ts +++ b/tests/_/schemas/query-only/graffle/modules/MethodsRoot.ts @@ -24,20 +24,20 @@ export interface QueryMethods<$Config extends Utils.Config> { 'Query' > > - id: () => Promise< + id: <$SelectionSet>(selectionSet?: Utils.Exact<$SelectionSet, SelectionSet.Query.id>) => Promise< Utils.ResolveOutputReturnRootField< $Config, Index, 'id', - InferResult.Field + InferResult.Field<$SelectionSet, Index['Root']['Query']['fields']['id'], Index> > > - idNonNull: () => Promise< + idNonNull: <$SelectionSet>(selectionSet?: Utils.Exact<$SelectionSet, SelectionSet.Query.idNonNull>) => Promise< Utils.ResolveOutputReturnRootField< $Config, Index, 'idNonNull', - InferResult.Field + InferResult.Field<$SelectionSet, Index['Root']['Query']['fields']['idNonNull'], Index> > > } diff --git a/tests/_/schemas/query-only/graffle/modules/RuntimeCustomScalars.ts b/tests/_/schemas/query-only/graffle/modules/RuntimeCustomScalars.ts index 13aee9e4b..18a509fa7 100644 --- a/tests/_/schemas/query-only/graffle/modules/RuntimeCustomScalars.ts +++ b/tests/_/schemas/query-only/graffle/modules/RuntimeCustomScalars.ts @@ -1,4 +1,23 @@ +import type * as $Utilities from '../../../../../../src/entrypoints/utilities-for-generated.js' import * as CustomScalars from './Scalar.js' +// +// +// +// +// +// +// ================================================================================================== +// GraphQLEnumType +// ================================================================================================== +// +// +// +// +// +// + +// None of your GraphQLEnumTypes have custom scalars. + // // // @@ -87,7 +106,31 @@ import * as CustomScalars from './Scalar.js' // // -// None of your GraphQLRootTypes have custom scalars. +const Query: $Utilities.SchemaDrivenDataMap.OutputObject = { + f: { + id: {}, + idNonNull: {}, + }, +} + +// +// +// +// +// +// +// ================================================================================================== +// Reference Assignments +// (avoids circular assignment issues) +// ================================================================================================== +// +// +// +// +// +// + +// None of your types have references to other non-scalar/enum types. // // @@ -105,4 +148,6 @@ import * as CustomScalars from './Scalar.js' // // -export const $index = {} +export const $index = { + Query, +} diff --git a/website/graffle/modules/RuntimeCustomScalars.ts b/tests/_/schemas/query-only/graffle/modules/SchemaDrivenDataMap.ts similarity index 50% rename from website/graffle/modules/RuntimeCustomScalars.ts rename to tests/_/schemas/query-only/graffle/modules/SchemaDrivenDataMap.ts index 13aee9e4b..3561596d6 100644 --- a/website/graffle/modules/RuntimeCustomScalars.ts +++ b/tests/_/schemas/query-only/graffle/modules/SchemaDrivenDataMap.ts @@ -1,4 +1,63 @@ -import * as CustomScalars from './Scalar.js' +import type * as $Utilities from '../../../../../../src/entrypoints/utilities-for-generated.js' +import * as $Scalar from './Scalar.js' +// +// +// +// +// +// +// ================================================================================================== +// GraphQLScalarType +// ================================================================================================== +// +// +// +// +// +// + +const ID = $Scalar.ID + +const Boolean = $Scalar.Boolean + +const String = $Scalar.String + +// +// +// +// +// +// +// ================================================================================================== +// GraphQLScalarTypeCustom +// ================================================================================================== +// +// +// +// +// +// + +// None of your GraphQLScalarTypeCustoms have custom scalars. + +// +// +// +// +// +// +// ================================================================================================== +// GraphQLEnumType +// ================================================================================================== +// +// +// +// +// +// + +// None of your GraphQLEnumTypes have custom scalars. + // // // @@ -87,7 +146,31 @@ import * as CustomScalars from './Scalar.js' // // -// None of your GraphQLRootTypes have custom scalars. +const Query: $Utilities.SchemaDrivenDataMap.OutputObject = { + f: { + id: {}, + idNonNull: {}, + }, +} + +// +// +// +// +// +// +// ================================================================================================== +// Reference Assignments +// (avoids circular assignment issues) +// ================================================================================================== +// +// +// +// +// +// + +// None of your types have references to other non-scalar/enum types. // // @@ -105,4 +188,17 @@ import * as CustomScalars from './Scalar.js' // // -export const $index = {} +const $schemaDrivenDataMap: $Utilities.SchemaDrivenDataMap = { + roots: { + Query, + }, + directives: {}, + types: { + ID, + Boolean, + String, + Query, + }, +} + +export { $schemaDrivenDataMap as schemaDrivenDataMap } diff --git a/tests/_/schemas/query-only/graffle/modules/SchemaRuntime.ts b/tests/_/schemas/query-only/graffle/modules/SchemaRuntime.ts deleted file mode 100644 index 1c3f8a9fb..000000000 --- a/tests/_/schemas/query-only/graffle/modules/SchemaRuntime.ts +++ /dev/null @@ -1,41 +0,0 @@ -/* eslint-disable */ -import * as $ from '../../../../../../src/entrypoints/schema.js' -import * as Data from './Data.js' -import { $index as $customScalarsIndex } from './RuntimeCustomScalars.js' -import * as $Scalar from './Scalar.js' -import type { Index } from './SchemaIndex.js' -export const $defaultSchemaUrl = undefined - -// @ts-ignore - circular types cannot infer. Ignore in case there are any. This comment is always added, it does not indicate if this particular type could infer or not. -export const Query = $.Object$(`Query`, { - id: $.field('id', $.Output.Nullable($Scalar.ID)), - idNonNull: $.field('idNonNull', $Scalar.ID), -}) -export const $Index: Index = { - name: Data.Name, - RootTypesPresent: ['Query'] as const, - RootUnion: undefined as any, // Type level only. - Root: { - Query, - Mutation: null, - Subscription: null, - }, - allTypes: { - Query, - }, - objects: {}, - unions: {}, - interfaces: {}, - customScalars: { - input: $customScalarsIndex, - }, - error: { - objects: {}, - objectsTypename: {}, - rootResultFields: { - Mutation: {}, - Subscription: {}, - Query: {}, - }, - }, -} diff --git a/website/.vitepress/config.ts b/website/.vitepress/config.ts index 5842dfa8d..cc78958de 100644 --- a/website/.vitepress/config.ts +++ b/website/.vitepress/config.ts @@ -67,7 +67,7 @@ export default defineConfig({ rewrites: { ':section/{:_(\\d+_)}?:one/{:_(\\d+_)}?:two/{:_(\\d+_)}?:three' : ':section/:one/:two/:three', ':section/{:_(\\d+_)}?:one/{:_(\\d+_)}?:two' : ':section/:one/:two', - ':section/{:prefixOne(\\d+_)}?:one' : ':section/:one' + ':section/{:_(\\d+_)}?:one' : ':section/:one' }, title: 'Graffle', description: 'Minimalist Progressively Type Safe GraphQL Client For JavaScript.', diff --git a/website/content/_snippets/examples/anyware/slot-search-params.detail.md b/website/content/_snippets/examples/anyware/slot-search-params.detail.md index 190a55949..a0690dd7a 100644 --- a/website/content/_snippets/examples/anyware/slot-search-params.detail.md +++ b/website/content/_snippets/examples/anyware/slot-search-params.detail.md @@ -15,7 +15,7 @@ const graffle = Graffle searchParams: (graphqlRequest) => { return { query: graphqlRequest.query, - operationName: `queryContinents`, + operationName: `getPokemon`, } }, }, @@ -23,14 +23,14 @@ const graffle = Graffle }) const result = await graffle.gql` - query trainers { - pokemon { name } - } - query pokemon { + query getTrainers { trainers { name } } + query getPokemon { + pokemon { name } + } ` - .send(`queryCountries`) + .send(`getTrainers`) console.log(result) ``` @@ -38,28 +38,16 @@ console.log(result) ```txt -/some/path/to/runPipeline.ts:XX:XX - return new ContextualError(message, { hookName: signal.hookName, source: signal.source }, signal.error) - ^ - - -ContextualError: There was an error in the core implementation of hook "pack". - at runPipeline (/some/path/to/runPipeline.ts:XX:XX:18) - at async runPipeline (/some/path/to/runPipeline.ts:XX:XX:14) - at async Object.run (/some/path/to/main.ts:XX:XX:22) - at async Object.send (/some/path/to/gql.ts:XX:XX:26) - at async (/some/path/to/anyware_slot_slot-body__slot-search-params.ts:XX:XX:16) { - context: { hookName: 'pack', source: 'implementation' }, - cause: Error: Unexpected null value. - at throwNull (/some/path/to/prelude.ts:XX:XX:29) - at Object.run (/some/path/to/core.ts:XX:XX:35) - at runHook (/some/path/to/runHook.ts:XX:XX:37) - at (/some/path/to/runHook.ts:XX:XX:14) - at (/some/path/to/anyware_slot_slot-body__slot-search-params.ts:XX:XX:18) - at applyBody (/some/path/to/main.ts:XX:XX:28) +{ + pokemon: [ + { name: 'Pikachu' }, + { name: 'Charizard' }, + { name: 'Squirtle' }, + { name: 'Bulbasaur' }, + { name: 'Caterpie' }, + { name: 'Weedle' } + ] } - -Node.js vXX.XX.XX ``` diff --git a/website/content/_snippets/examples/anyware/slot-search-params.md b/website/content/_snippets/examples/anyware/slot-search-params.md index bc6f9c224..7707f403e 100644 --- a/website/content/_snippets/examples/anyware/slot-search-params.md +++ b/website/content/_snippets/examples/anyware/slot-search-params.md @@ -13,7 +13,7 @@ const graffle = Graffle searchParams: (graphqlRequest) => { return { query: graphqlRequest.query, - operationName: `queryContinents`, + operationName: `getPokemon`, } }, }, @@ -21,14 +21,14 @@ const graffle = Graffle }) const result = await graffle.gql` - query trainers { - pokemon { name } - } - query pokemon { + query getTrainers { trainers { name } } + query getPokemon { + pokemon { name } + } ` - .send(`queryCountries`) + .send(`getTrainers`) console.log(result) ``` @@ -36,28 +36,16 @@ console.log(result) ```txt -/some/path/to/runPipeline.ts:XX:XX - return new ContextualError(message, { hookName: signal.hookName, source: signal.source }, signal.error) - ^ - - -ContextualError: There was an error in the core implementation of hook "pack". - at runPipeline (/some/path/to/runPipeline.ts:XX:XX:18) - at async runPipeline (/some/path/to/runPipeline.ts:XX:XX:14) - at async Object.run (/some/path/to/main.ts:XX:XX:22) - at async Object.send (/some/path/to/gql.ts:XX:XX:26) - at async (/some/path/to/anyware_slot_slot-body__slot-search-params.ts:XX:XX:16) { - context: { hookName: 'pack', source: 'implementation' }, - cause: Error: Unexpected null value. - at throwNull (/some/path/to/prelude.ts:XX:XX:29) - at Object.run (/some/path/to/core.ts:XX:XX:35) - at runHook (/some/path/to/runHook.ts:XX:XX:37) - at (/some/path/to/runHook.ts:XX:XX:14) - at (/some/path/to/anyware_slot_slot-body__slot-search-params.ts:XX:XX:18) - at applyBody (/some/path/to/main.ts:XX:XX:28) +{ + pokemon: [ + { name: 'Pikachu' }, + { name: 'Charizard' }, + { name: 'Squirtle' }, + { name: 'Bulbasaur' }, + { name: 'Caterpie' }, + { name: 'Weedle' } + ] } - -Node.js vXX.XX.XX ``` diff --git a/website/content/_snippets/examples/extension/opentelemetry.detail.md b/website/content/_snippets/examples/extension/opentelemetry.detail.md index 79a7203c2..e4871e96b 100644 --- a/website/content/_snippets/examples/extension/opentelemetry.detail.md +++ b/website/content/_snippets/examples/extension/opentelemetry.detail.md @@ -37,14 +37,14 @@ console.log(data) } }, instrumentationScope: { name: 'graffle', version: undefined, schemaUrl: undefined }, - traceId: 'ac014dada983f302716deae963031d77', - parentId: 'fe33e3cb84b589ed', + traceId: '0d775d0099c7910506a0772440555fbe', + parentId: '9b0787a81673ace4', traceState: undefined, name: 'encode', - id: '87f70f2b478a9946', + id: 'e6fbdb4081ec6e4e', kind: 0, - timestamp: 1728323381984000, - duration: 620.917, + timestamp: 1728856242273000, + duration: 1418.125, attributes: {}, status: { code: 0 }, events: [], @@ -64,14 +64,14 @@ console.log(data) } }, instrumentationScope: { name: 'graffle', version: undefined, schemaUrl: undefined }, - traceId: 'ac014dada983f302716deae963031d77', - parentId: 'fe33e3cb84b589ed', + traceId: '0d775d0099c7910506a0772440555fbe', + parentId: '9b0787a81673ace4', traceState: undefined, name: 'pack', - id: '4223bd045e4f82b7', + id: 'c20c4b4a0bb60890', kind: 0, - timestamp: 1728323381987000, - duration: 17090.167, + timestamp: 1728856242277000, + duration: 11234.958, attributes: {}, status: { code: 0 }, events: [], @@ -91,14 +91,14 @@ console.log(data) } }, instrumentationScope: { name: 'graffle', version: undefined, schemaUrl: undefined }, - traceId: 'ac014dada983f302716deae963031d77', - parentId: 'fe33e3cb84b589ed', + traceId: '0d775d0099c7910506a0772440555fbe', + parentId: '9b0787a81673ace4', traceState: undefined, name: 'exchange', - id: '1acd0a0de0d5eb48', + id: 'b37626f52b507127', kind: 0, - timestamp: 1728323382005000, - duration: 28187.833, + timestamp: 1728856242288000, + duration: 106411.25, attributes: {}, status: { code: 0 }, events: [], @@ -118,14 +118,14 @@ console.log(data) } }, instrumentationScope: { name: 'graffle', version: undefined, schemaUrl: undefined }, - traceId: 'ac014dada983f302716deae963031d77', - parentId: 'fe33e3cb84b589ed', + traceId: '0d775d0099c7910506a0772440555fbe', + parentId: '9b0787a81673ace4', traceState: undefined, name: 'unpack', - id: '5190c757f52e1c88', + id: '7cdde5c9f15d334d', kind: 0, - timestamp: 1728323382033000, - duration: 1180.667, + timestamp: 1728856242395000, + duration: 1244.125, attributes: {}, status: { code: 0 }, events: [], @@ -145,14 +145,14 @@ console.log(data) } }, instrumentationScope: { name: 'graffle', version: undefined, schemaUrl: undefined }, - traceId: 'ac014dada983f302716deae963031d77', - parentId: 'fe33e3cb84b589ed', + traceId: '0d775d0099c7910506a0772440555fbe', + parentId: '9b0787a81673ace4', traceState: undefined, name: 'decode', - id: '88685659d9725d48', + id: 'b048da7b0a82b097', kind: 0, - timestamp: 1728323382035000, - duration: 196.375, + timestamp: 1728856242396000, + duration: 181.792, attributes: {}, status: { code: 0 }, events: [], @@ -172,14 +172,14 @@ console.log(data) } }, instrumentationScope: { name: 'graffle', version: undefined, schemaUrl: undefined }, - traceId: 'ac014dada983f302716deae963031d77', + traceId: '0d775d0099c7910506a0772440555fbe', parentId: undefined, traceState: undefined, name: 'request', - id: 'fe33e3cb84b589ed', + id: '9b0787a81673ace4', kind: 0, - timestamp: 1728323381982000, - duration: 53359.417, + timestamp: 1728856242273000, + duration: 123962.916, attributes: {}, status: { code: 0 }, events: [], diff --git a/website/content/_snippets/examples/extension/opentelemetry.md b/website/content/_snippets/examples/extension/opentelemetry.md index 7094855df..ab5c7f55f 100644 --- a/website/content/_snippets/examples/extension/opentelemetry.md +++ b/website/content/_snippets/examples/extension/opentelemetry.md @@ -35,14 +35,14 @@ console.log(data) } }, instrumentationScope: { name: 'graffle', version: undefined, schemaUrl: undefined }, - traceId: 'ac014dada983f302716deae963031d77', - parentId: 'fe33e3cb84b589ed', + traceId: '0d775d0099c7910506a0772440555fbe', + parentId: '9b0787a81673ace4', traceState: undefined, name: 'encode', - id: '87f70f2b478a9946', + id: 'e6fbdb4081ec6e4e', kind: 0, - timestamp: 1728323381984000, - duration: 620.917, + timestamp: 1728856242273000, + duration: 1418.125, attributes: {}, status: { code: 0 }, events: [], @@ -62,14 +62,14 @@ console.log(data) } }, instrumentationScope: { name: 'graffle', version: undefined, schemaUrl: undefined }, - traceId: 'ac014dada983f302716deae963031d77', - parentId: 'fe33e3cb84b589ed', + traceId: '0d775d0099c7910506a0772440555fbe', + parentId: '9b0787a81673ace4', traceState: undefined, name: 'pack', - id: '4223bd045e4f82b7', + id: 'c20c4b4a0bb60890', kind: 0, - timestamp: 1728323381987000, - duration: 17090.167, + timestamp: 1728856242277000, + duration: 11234.958, attributes: {}, status: { code: 0 }, events: [], @@ -89,14 +89,14 @@ console.log(data) } }, instrumentationScope: { name: 'graffle', version: undefined, schemaUrl: undefined }, - traceId: 'ac014dada983f302716deae963031d77', - parentId: 'fe33e3cb84b589ed', + traceId: '0d775d0099c7910506a0772440555fbe', + parentId: '9b0787a81673ace4', traceState: undefined, name: 'exchange', - id: '1acd0a0de0d5eb48', + id: 'b37626f52b507127', kind: 0, - timestamp: 1728323382005000, - duration: 28187.833, + timestamp: 1728856242288000, + duration: 106411.25, attributes: {}, status: { code: 0 }, events: [], @@ -116,14 +116,14 @@ console.log(data) } }, instrumentationScope: { name: 'graffle', version: undefined, schemaUrl: undefined }, - traceId: 'ac014dada983f302716deae963031d77', - parentId: 'fe33e3cb84b589ed', + traceId: '0d775d0099c7910506a0772440555fbe', + parentId: '9b0787a81673ace4', traceState: undefined, name: 'unpack', - id: '5190c757f52e1c88', + id: '7cdde5c9f15d334d', kind: 0, - timestamp: 1728323382033000, - duration: 1180.667, + timestamp: 1728856242395000, + duration: 1244.125, attributes: {}, status: { code: 0 }, events: [], @@ -143,14 +143,14 @@ console.log(data) } }, instrumentationScope: { name: 'graffle', version: undefined, schemaUrl: undefined }, - traceId: 'ac014dada983f302716deae963031d77', - parentId: 'fe33e3cb84b589ed', + traceId: '0d775d0099c7910506a0772440555fbe', + parentId: '9b0787a81673ace4', traceState: undefined, name: 'decode', - id: '88685659d9725d48', + id: 'b048da7b0a82b097', kind: 0, - timestamp: 1728323382035000, - duration: 196.375, + timestamp: 1728856242396000, + duration: 181.792, attributes: {}, status: { code: 0 }, events: [], @@ -170,14 +170,14 @@ console.log(data) } }, instrumentationScope: { name: 'graffle', version: undefined, schemaUrl: undefined }, - traceId: 'ac014dada983f302716deae963031d77', + traceId: '0d775d0099c7910506a0772440555fbe', parentId: undefined, traceState: undefined, name: 'request', - id: 'fe33e3cb84b589ed', + id: '9b0787a81673ace4', kind: 0, - timestamp: 1728323381982000, - duration: 53359.417, + timestamp: 1728856242273000, + duration: 123962.916, attributes: {}, status: { code: 0 }, events: [], diff --git a/website/content/_snippets/examples/output/envelope-error-throw.detail.md b/website/content/_snippets/examples/output/envelope-error-throw.detail.md index 00d4cdabf..a7a02df96 100644 --- a/website/content/_snippets/examples/output/envelope-error-throw.detail.md +++ b/website/content/_snippets/examples/output/envelope-error-throw.detail.md @@ -38,7 +38,7 @@ ContextualError: There was an error in the extension "anonymous" (use named func at runPipeline (/some/path/to/runPipeline.ts:XX:XX:18) at async Object.run (/some/path/to/main.ts:XX:XX:22) at async executeDocument (/some/path/to/requestMethods.ts:XX:XX:18) - at async executeRootTypeField (/some/path/to/requestMethods.ts:XX:XX:18) + at async executeRootField (/some/path/to/requestMethods.ts:XX:XX:18) at async (/some/path/to/output_envelope_envelope_error-throw__envelope-error-throw.ts:XX:XX:1) { context: { hookName: 'encode', diff --git a/website/content/_snippets/examples/output/envelope-error-throw.md b/website/content/_snippets/examples/output/envelope-error-throw.md index 7227ff820..503466392 100644 --- a/website/content/_snippets/examples/output/envelope-error-throw.md +++ b/website/content/_snippets/examples/output/envelope-error-throw.md @@ -36,7 +36,7 @@ ContextualError: There was an error in the extension "anonymous" (use named func at runPipeline (/some/path/to/runPipeline.ts:XX:XX:18) at async Object.run (/some/path/to/main.ts:XX:XX:22) at async executeDocument (/some/path/to/requestMethods.ts:XX:XX:18) - at async executeRootTypeField (/some/path/to/requestMethods.ts:XX:XX:18) + at async executeRootField (/some/path/to/requestMethods.ts:XX:XX:18) at async (/some/path/to/output_envelope_envelope_error-throw__envelope-error-throw.ts:XX:XX:1) { context: { hookName: 'encode', diff --git a/website/content/_snippets/examples/output/envelope-error.detail.md b/website/content/_snippets/examples/output/envelope-error.detail.md index eaf7007a7..84e5335a5 100644 --- a/website/content/_snippets/examples/output/envelope-error.detail.md +++ b/website/content/_snippets/examples/output/envelope-error.detail.md @@ -38,7 +38,7 @@ console.log(result) at runPipeline (/some/path/to/runPipeline.ts:XX:XX:18) at async Object.run (/some/path/to/main.ts:XX:XX:22) at async executeDocument (/some/path/to/requestMethods.ts:XX:XX:18) - at async executeRootTypeField (/some/path/to/requestMethods.ts:XX:XX:18) + at async executeRootField (/some/path/to/requestMethods.ts:XX:XX:18) at async (/some/path/to/output_envelope_envelope-error__envelope-error.ts:XX:XX:16) { context: { hookName: 'encode', diff --git a/website/content/_snippets/examples/output/envelope-error.md b/website/content/_snippets/examples/output/envelope-error.md index 19c73782d..52dfa1ab5 100644 --- a/website/content/_snippets/examples/output/envelope-error.md +++ b/website/content/_snippets/examples/output/envelope-error.md @@ -36,7 +36,7 @@ console.log(result) at runPipeline (/some/path/to/runPipeline.ts:XX:XX:18) at async Object.run (/some/path/to/main.ts:XX:XX:22) at async executeDocument (/some/path/to/requestMethods.ts:XX:XX:18) - at async executeRootTypeField (/some/path/to/requestMethods.ts:XX:XX:18) + at async executeRootField (/some/path/to/requestMethods.ts:XX:XX:18) at async (/some/path/to/output_envelope_envelope-error__envelope-error.ts:XX:XX:16) { context: { hookName: 'encode', diff --git a/website/content/_snippets/examples/output/envelope.detail.md b/website/content/_snippets/examples/output/envelope.detail.md index ec1f81c99..6cc5ce543 100644 --- a/website/content/_snippets/examples/output/envelope.detail.md +++ b/website/content/_snippets/examples/output/envelope.detail.md @@ -40,7 +40,7 @@ console.log(result) headers: Headers { 'content-type': 'application/graphql-response+json; charset=utf-8', 'content-length': '142', - date: 'Mon, 07 Oct 2024 17:49:41 GMT', + date: 'Sun, 13 Oct 2024 21:50:41 GMT', connection: 'keep-alive', 'keep-alive': 'timeout=5' }, diff --git a/website/content/_snippets/examples/output/envelope.md b/website/content/_snippets/examples/output/envelope.md index 6b85d5763..fba64ca77 100644 --- a/website/content/_snippets/examples/output/envelope.md +++ b/website/content/_snippets/examples/output/envelope.md @@ -38,7 +38,7 @@ console.log(result) headers: Headers { 'content-type': 'application/graphql-response+json; charset=utf-8', 'content-length': '142', - date: 'Mon, 07 Oct 2024 17:49:41 GMT', + date: 'Sun, 13 Oct 2024 21:50:41 GMT', connection: 'keep-alive', 'keep-alive': 'timeout=5' }, diff --git a/website/content/_snippets/examples/output/return-error-execution.detail.md b/website/content/_snippets/examples/output/return-error-execution.detail.md index d4b35c7ca..e7dd5d3ea 100644 --- a/website/content/_snippets/examples/output/return-error-execution.detail.md +++ b/website/content/_snippets/examples/output/return-error-execution.detail.md @@ -49,7 +49,7 @@ ContextualAggregateError: One or more errors in the execution result. at handleOutput (/some/path/to/handleOutput.ts:XX:XX:19) at executeDocument (/some/path/to/requestMethods.ts:XX:XX:10) at process.processTicksAndRejections (node:internal/process/task_queues:XX:XX) - at async executeRootTypeField (/some/path/to/requestMethods.ts:XX:XX:18) + 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: {}, cause: undefined, @@ -67,9 +67,9 @@ ContextualAggregateError: One or more errors in the execution result. ] } ] - at (/some/path/to/graphqlHTTP.ts:XX:XX:47) + at (/some/path/to/http.ts:XX:XX:47) at Array.map () - at parseExecutionResult (/some/path/to/graphqlHTTP.ts:XX:XX:28) + at parseExecutionResult (/some/path/to/http.ts:XX:XX:28) at Object.unpack (/some/path/to/core.ts:XX:XX:26) at process.processTicksAndRejections (node:internal/process/task_queues:XX:XX) at async runHook (/some/path/to/runHook.ts:XX:XX:16) { @@ -88,7 +88,7 @@ ContextualError: There was an error in the extension "anonymous" (use named func at process.processTicksAndRejections (node:internal/process/task_queues:XX:XX) at async Object.run (/some/path/to/main.ts:XX:XX:22) at async executeDocument (/some/path/to/requestMethods.ts:XX:XX:18) - at async executeRootTypeField (/some/path/to/requestMethods.ts:XX:XX:18) + 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:3) { context: { hookName: 'encode', diff --git a/website/content/_snippets/examples/output/return-error-execution.md b/website/content/_snippets/examples/output/return-error-execution.md index bf1c8e2cf..2951c10f8 100644 --- a/website/content/_snippets/examples/output/return-error-execution.md +++ b/website/content/_snippets/examples/output/return-error-execution.md @@ -47,7 +47,7 @@ ContextualAggregateError: One or more errors in the execution result. at handleOutput (/some/path/to/handleOutput.ts:XX:XX:19) at executeDocument (/some/path/to/requestMethods.ts:XX:XX:10) at process.processTicksAndRejections (node:internal/process/task_queues:XX:XX) - at async executeRootTypeField (/some/path/to/requestMethods.ts:XX:XX:18) + 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: {}, cause: undefined, @@ -65,9 +65,9 @@ ContextualAggregateError: One or more errors in the execution result. ] } ] - at (/some/path/to/graphqlHTTP.ts:XX:XX:47) + at (/some/path/to/http.ts:XX:XX:47) at Array.map () - at parseExecutionResult (/some/path/to/graphqlHTTP.ts:XX:XX:28) + at parseExecutionResult (/some/path/to/http.ts:XX:XX:28) at Object.unpack (/some/path/to/core.ts:XX:XX:26) at process.processTicksAndRejections (node:internal/process/task_queues:XX:XX) at async runHook (/some/path/to/runHook.ts:XX:XX:16) { @@ -86,7 +86,7 @@ ContextualError: There was an error in the extension "anonymous" (use named func at process.processTicksAndRejections (node:internal/process/task_queues:XX:XX) at async Object.run (/some/path/to/main.ts:XX:XX:22) at async executeDocument (/some/path/to/requestMethods.ts:XX:XX:18) - at async executeRootTypeField (/some/path/to/requestMethods.ts:XX:XX:18) + 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:3) { context: { hookName: 'encode', diff --git a/website/content/_snippets/examples/output/return-error.detail.md b/website/content/_snippets/examples/output/return-error.detail.md index ad10679b8..a99e36611 100644 --- a/website/content/_snippets/examples/output/return-error.detail.md +++ b/website/content/_snippets/examples/output/return-error.detail.md @@ -35,7 +35,7 @@ ContextualError: There was an error in the extension "anonymous" (use named func at runPipeline (/some/path/to/runPipeline.ts:XX:XX:18) at async Object.run (/some/path/to/main.ts:XX:XX:22) at async executeDocument (/some/path/to/requestMethods.ts:XX:XX:18) - at async executeRootTypeField (/some/path/to/requestMethods.ts:XX:XX:18) + at async executeRootField (/some/path/to/requestMethods.ts:XX:XX:18) at async (/some/path/to/output_return-error.ts:XX:XX:18) { context: { hookName: 'encode', diff --git a/website/content/_snippets/examples/output/return-error.md b/website/content/_snippets/examples/output/return-error.md index 9f0f0f1f2..52be3de7a 100644 --- a/website/content/_snippets/examples/output/return-error.md +++ b/website/content/_snippets/examples/output/return-error.md @@ -33,7 +33,7 @@ ContextualError: There was an error in the extension "anonymous" (use named func at runPipeline (/some/path/to/runPipeline.ts:XX:XX:18) at async Object.run (/some/path/to/main.ts:XX:XX:22) at async executeDocument (/some/path/to/requestMethods.ts:XX:XX:18) - at async executeRootTypeField (/some/path/to/requestMethods.ts:XX:XX:18) + at async executeRootField (/some/path/to/requestMethods.ts:XX:XX:18) at async (/some/path/to/output_return-error.ts:XX:XX:18) { context: { hookName: 'encode', diff --git a/website/content/_snippets/examples/output/standard-graphql.detail.md b/website/content/_snippets/examples/output/standard-graphql.detail.md index d4f12f683..2e3429b84 100644 --- a/website/content/_snippets/examples/output/standard-graphql.detail.md +++ b/website/content/_snippets/examples/output/standard-graphql.detail.md @@ -29,25 +29,21 @@ ContextualError: There was an error in the core implementation of hook "exchange at runPipeline (/some/path/to/runPipeline.ts:XX:XX:18) at async runPipeline (/some/path/to/runPipeline.ts:XX:XX:14) at async runPipeline (/some/path/to/runPipeline.ts:XX:XX:14) - ... 2 lines matching cause stack trace ... + at async Object.run (/some/path/to/main.ts:XX:XX:22) + at async Object.send (/some/path/to/gql.ts:XX:XX:26) at async (/some/path/to/output_preset__standard-graphql.ts:XX:XX:16) { context: { hookName: 'exchange', source: 'implementation' }, [cause]: TypeError: Failed to parse URL from ... at new Request (node:internal/deps/undici/undici:XX:XX) at Object.run (/some/path/to/core.ts:XX:XX:29) - ... 6 lines matching cause stack trace ... - at async (/some/path/to/output_preset__standard-graphql.ts:XX:XX:16) { + at runHook (/some/path/to/runHook.ts:XX:XX:37) + at runHook (/some/path/to/runHook.ts:XX:XX:16) { [cause]: TypeError: Invalid URL at new URL (node:internal/url:XX:XX) at new Request (node:internal/deps/undici/undici:XX:XX) at Object.run (/some/path/to/core.ts:XX:XX:29) at runHook (/some/path/to/runHook.ts:XX:XX:37) - at runPipeline (/some/path/to/runPipeline.ts:XX:XX:8) - at runPipeline (/some/path/to/runPipeline.ts:XX:XX:20) - at async runPipeline (/some/path/to/runPipeline.ts:XX:XX:14) - at async Object.run (/some/path/to/main.ts:XX:XX:22) - at async Object.send (/some/path/to/gql.ts:XX:XX:26) - at async (/some/path/to/output_preset__standard-graphql.ts:XX:XX:16) { + at runHook (/some/path/to/runHook.ts:XX:XX:16) { code: 'ERR_INVALID_URL', input: '...' } diff --git a/website/content/_snippets/examples/output/standard-graphql.md b/website/content/_snippets/examples/output/standard-graphql.md index 0ec75a9dc..48104a756 100644 --- a/website/content/_snippets/examples/output/standard-graphql.md +++ b/website/content/_snippets/examples/output/standard-graphql.md @@ -27,25 +27,21 @@ ContextualError: There was an error in the core implementation of hook "exchange at runPipeline (/some/path/to/runPipeline.ts:XX:XX:18) at async runPipeline (/some/path/to/runPipeline.ts:XX:XX:14) at async runPipeline (/some/path/to/runPipeline.ts:XX:XX:14) - ... 2 lines matching cause stack trace ... + at async Object.run (/some/path/to/main.ts:XX:XX:22) + at async Object.send (/some/path/to/gql.ts:XX:XX:26) at async (/some/path/to/output_preset__standard-graphql.ts:XX:XX:16) { context: { hookName: 'exchange', source: 'implementation' }, [cause]: TypeError: Failed to parse URL from ... at new Request (node:internal/deps/undici/undici:XX:XX) at Object.run (/some/path/to/core.ts:XX:XX:29) - ... 6 lines matching cause stack trace ... - at async (/some/path/to/output_preset__standard-graphql.ts:XX:XX:16) { + at runHook (/some/path/to/runHook.ts:XX:XX:37) + at runHook (/some/path/to/runHook.ts:XX:XX:16) { [cause]: TypeError: Invalid URL at new URL (node:internal/url:XX:XX) at new Request (node:internal/deps/undici/undici:XX:XX) at Object.run (/some/path/to/core.ts:XX:XX:29) at runHook (/some/path/to/runHook.ts:XX:XX:37) - at runPipeline (/some/path/to/runPipeline.ts:XX:XX:8) - at runPipeline (/some/path/to/runPipeline.ts:XX:XX:20) - at async runPipeline (/some/path/to/runPipeline.ts:XX:XX:14) - at async Object.run (/some/path/to/main.ts:XX:XX:22) - at async Object.send (/some/path/to/gql.ts:XX:XX:26) - at async (/some/path/to/output_preset__standard-graphql.ts:XX:XX:16) { + at runHook (/some/path/to/runHook.ts:XX:XX:16) { code: 'ERR_INVALID_URL', input: '...' } diff --git a/website/content/_snippets/examples/transport-http/dynamic-headers.detail.md b/website/content/_snippets/examples/transport-http/dynamic-headers.detail.md index 6e03525d8..949906a9b 100644 --- a/website/content/_snippets/examples/transport-http/dynamic-headers.detail.md +++ b/website/content/_snippets/examples/transport-http/dynamic-headers.detail.md @@ -38,7 +38,7 @@ await graffle.gql`{ pokemons { name } }`.send() headers: Headers { accept: 'application/graphql-response+json; charset=utf-8, application/json; charset=utf-8', 'content-type': 'application/json', - 'x-sent-at-time': '1728323381286' + 'x-sent-at-time': '1728856241218' }, signal: undefined, method: 'post', diff --git a/website/content/_snippets/examples/transport-http/dynamic-headers.md b/website/content/_snippets/examples/transport-http/dynamic-headers.md index a2118fdb3..63efbd6fa 100644 --- a/website/content/_snippets/examples/transport-http/dynamic-headers.md +++ b/website/content/_snippets/examples/transport-http/dynamic-headers.md @@ -36,7 +36,7 @@ await graffle.gql`{ pokemons { name } }`.send() headers: Headers { accept: 'application/graphql-response+json; charset=utf-8, application/json; charset=utf-8', 'content-type': 'application/json', - 'x-sent-at-time': '1728323381286' + 'x-sent-at-time': '1728856241218' }, signal: undefined, method: 'post', diff --git a/website/content/_snippets/examples/transport-http/method-get.detail.md b/website/content/_snippets/examples/transport-http/method-get.detail.md index 064e3a370..2e7b80cdc 100644 --- a/website/content/_snippets/examples/transport-http/method-get.detail.md +++ b/website/content/_snippets/examples/transport-http/method-get.detail.md @@ -54,7 +54,7 @@ await graffle.gql`query { pokemonByName(name: "Nano") { hp } }`.send() searchParams: URLSearchParams {}, hash: '' }, - body: '{"query":"mutation { addPokemon(attack:0, defense:0, hp:1, name:\\"Nano\\", type: grass) { name } }"}' + body: '{"query":"mutation {\\n addPokemon(attack: 0, defense: 0, hp: 1, name: \\"Nano\\", type: grass) {\\n name\\n }\\n}"}' } ``` @@ -69,7 +69,7 @@ await graffle.gql`query { pokemonByName(name: "Nano") { hp } }`.send() signal: undefined, method: 'get', url: URL { - href: 'http://localhost:3000/graphql?query=query+%7B+pokemonByName%28name%3A+%22Nano%22%29+%7B+hp+%7D+%7D', + href: 'http://localhost:3000/graphql?query=%7B%0A++pokemonByName%28name%3A+%22Nano%22%29+%7B%0A++++hp%0A++%7D%0A%7D', origin: 'http://localhost:3000', protocol: 'http:', username: '', @@ -78,8 +78,8 @@ await graffle.gql`query { pokemonByName(name: "Nano") { hp } }`.send() hostname: 'localhost', port: '3000', pathname: '/graphql', - search: '?query=query+%7B+pokemonByName%28name%3A+%22Nano%22%29+%7B+hp+%7D+%7D', - searchParams: URLSearchParams { 'query' => 'query { pokemonByName(name: "Nano") { hp } }' }, + search: '?query=%7B%0A++pokemonByName%28name%3A+%22Nano%22%29+%7B%0A++++hp%0A++%7D%0A%7D', + searchParams: URLSearchParams { 'query' => '{\n pokemonByName(name: "Nano") {\n hp\n }\n}' }, hash: '' } } diff --git a/website/content/_snippets/examples/transport-http/method-get.md b/website/content/_snippets/examples/transport-http/method-get.md index 1f82038af..8cb557ea3 100644 --- a/website/content/_snippets/examples/transport-http/method-get.md +++ b/website/content/_snippets/examples/transport-http/method-get.md @@ -52,7 +52,7 @@ await graffle.gql`query { pokemonByName(name: "Nano") { hp } }`.send() searchParams: URLSearchParams {}, hash: '' }, - body: '{"query":"mutation { addPokemon(attack:0, defense:0, hp:1, name:\\"Nano\\", type: grass) { name } }"}' + body: '{"query":"mutation {\\n addPokemon(attack: 0, defense: 0, hp: 1, name: \\"Nano\\", type: grass) {\\n name\\n }\\n}"}' } ``` @@ -67,7 +67,7 @@ await graffle.gql`query { pokemonByName(name: "Nano") { hp } }`.send() signal: undefined, method: 'get', url: URL { - href: 'http://localhost:3000/graphql?query=query+%7B+pokemonByName%28name%3A+%22Nano%22%29+%7B+hp+%7D+%7D', + href: 'http://localhost:3000/graphql?query=%7B%0A++pokemonByName%28name%3A+%22Nano%22%29+%7B%0A++++hp%0A++%7D%0A%7D', origin: 'http://localhost:3000', protocol: 'http:', username: '', @@ -76,8 +76,8 @@ await graffle.gql`query { pokemonByName(name: "Nano") { hp } }`.send() hostname: 'localhost', port: '3000', pathname: '/graphql', - search: '?query=query+%7B+pokemonByName%28name%3A+%22Nano%22%29+%7B+hp+%7D+%7D', - searchParams: URLSearchParams { 'query' => 'query { pokemonByName(name: "Nano") { hp } }' }, + search: '?query=%7B%0A++pokemonByName%28name%3A+%22Nano%22%29+%7B%0A++++hp%0A++%7D%0A%7D', + searchParams: URLSearchParams { 'query' => '{\n pokemonByName(name: "Nano") {\n hp\n }\n}' }, hash: '' } } diff --git a/website/content/examples/10_transport-http/dynamic-headers.md b/website/content/examples/10_transport-http/dynamic-headers.md index fa4f67fb7..ba23979ed 100644 --- a/website/content/examples/10_transport-http/dynamic-headers.md +++ b/website/content/examples/10_transport-http/dynamic-headers.md @@ -43,7 +43,7 @@ await graffle.gql`{ pokemons { name } }`.send() headers: Headers { accept: 'application/graphql-response+json; charset=utf-8, application/json; charset=utf-8', 'content-type': 'application/json', - 'x-sent-at-time': '1728323381286' + 'x-sent-at-time': '1728856241218' }, signal: undefined, method: 'post', diff --git a/website/content/examples/10_transport-http/method-get.md b/website/content/examples/10_transport-http/method-get.md index 2b6861a2f..5f6ca4aa0 100644 --- a/website/content/examples/10_transport-http/method-get.md +++ b/website/content/examples/10_transport-http/method-get.md @@ -60,7 +60,7 @@ await graffle.gql`query { pokemonByName(name: "Nano") { hp } }`.send() searchParams: URLSearchParams {}, hash: '' }, - body: '{"query":"mutation { addPokemon(attack:0, defense:0, hp:1, name:\\"Nano\\", type: grass) { name } }"}' + body: '{"query":"mutation {\\n addPokemon(attack: 0, defense: 0, hp: 1, name: \\"Nano\\", type: grass) {\\n name\\n }\\n}"}' } ``` @@ -75,7 +75,7 @@ await graffle.gql`query { pokemonByName(name: "Nano") { hp } }`.send() signal: undefined, method: 'get', url: URL { - href: 'http://localhost:3000/graphql?query=query+%7B+pokemonByName%28name%3A+%22Nano%22%29+%7B+hp+%7D+%7D', + href: 'http://localhost:3000/graphql?query=%7B%0A++pokemonByName%28name%3A+%22Nano%22%29+%7B%0A++++hp%0A++%7D%0A%7D', origin: 'http://localhost:3000', protocol: 'http:', username: '', @@ -84,8 +84,8 @@ await graffle.gql`query { pokemonByName(name: "Nano") { hp } }`.send() hostname: 'localhost', port: '3000', pathname: '/graphql', - search: '?query=query+%7B+pokemonByName%28name%3A+%22Nano%22%29+%7B+hp+%7D+%7D', - searchParams: URLSearchParams { 'query' => 'query { pokemonByName(name: "Nano") { hp } }' }, + search: '?query=%7B%0A++pokemonByName%28name%3A+%22Nano%22%29+%7B%0A++++hp%0A++%7D%0A%7D', + searchParams: URLSearchParams { 'query' => '{\n pokemonByName(name: "Nano") {\n hp\n }\n}' }, hash: '' } } diff --git a/website/content/examples/20_output/envelope-error-throw.md b/website/content/examples/20_output/envelope-error-throw.md index 87b99d276..2cb706232 100644 --- a/website/content/examples/20_output/envelope-error-throw.md +++ b/website/content/examples/20_output/envelope-error-throw.md @@ -43,7 +43,7 @@ ContextualError: There was an error in the extension "anonymous" (use named func at runPipeline (/some/path/to/runPipeline.ts:XX:XX:18) at async Object.run (/some/path/to/main.ts:XX:XX:22) at async executeDocument (/some/path/to/requestMethods.ts:XX:XX:18) - at async executeRootTypeField (/some/path/to/requestMethods.ts:XX:XX:18) + at async executeRootField (/some/path/to/requestMethods.ts:XX:XX:18) at async (/some/path/to/output_envelope_envelope_error-throw__envelope-error-throw.ts:XX:XX:1) { context: { hookName: 'encode', diff --git a/website/content/examples/20_output/envelope-error.md b/website/content/examples/20_output/envelope-error.md index 3495b1ca2..474d3bc16 100644 --- a/website/content/examples/20_output/envelope-error.md +++ b/website/content/examples/20_output/envelope-error.md @@ -43,7 +43,7 @@ console.log(result) at runPipeline (/some/path/to/runPipeline.ts:XX:XX:18) at async Object.run (/some/path/to/main.ts:XX:XX:22) at async executeDocument (/some/path/to/requestMethods.ts:XX:XX:18) - at async executeRootTypeField (/some/path/to/requestMethods.ts:XX:XX:18) + at async executeRootField (/some/path/to/requestMethods.ts:XX:XX:18) at async (/some/path/to/output_envelope_envelope-error__envelope-error.ts:XX:XX:16) { context: { hookName: 'encode', diff --git a/website/content/examples/20_output/envelope.md b/website/content/examples/20_output/envelope.md index 1e3f92d07..2e21c0f68 100644 --- a/website/content/examples/20_output/envelope.md +++ b/website/content/examples/20_output/envelope.md @@ -45,7 +45,7 @@ console.log(result) headers: Headers { 'content-type': 'application/graphql-response+json; charset=utf-8', 'content-length': '142', - date: 'Mon, 07 Oct 2024 17:49:41 GMT', + date: 'Sun, 13 Oct 2024 21:50:41 GMT', connection: 'keep-alive', 'keep-alive': 'timeout=5' }, diff --git a/website/content/examples/20_output/return-error-execution.md b/website/content/examples/20_output/return-error-execution.md index 8f9154823..01a177a92 100644 --- a/website/content/examples/20_output/return-error-execution.md +++ b/website/content/examples/20_output/return-error-execution.md @@ -54,7 +54,7 @@ ContextualAggregateError: One or more errors in the execution result. at handleOutput (/some/path/to/handleOutput.ts:XX:XX:19) at executeDocument (/some/path/to/requestMethods.ts:XX:XX:10) at process.processTicksAndRejections (node:internal/process/task_queues:XX:XX) - at async executeRootTypeField (/some/path/to/requestMethods.ts:XX:XX:18) + 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: {}, cause: undefined, @@ -72,9 +72,9 @@ ContextualAggregateError: One or more errors in the execution result. ] } ] - at (/some/path/to/graphqlHTTP.ts:XX:XX:47) + at (/some/path/to/http.ts:XX:XX:47) at Array.map () - at parseExecutionResult (/some/path/to/graphqlHTTP.ts:XX:XX:28) + at parseExecutionResult (/some/path/to/http.ts:XX:XX:28) at Object.unpack (/some/path/to/core.ts:XX:XX:26) at process.processTicksAndRejections (node:internal/process/task_queues:XX:XX) at async runHook (/some/path/to/runHook.ts:XX:XX:16) { @@ -93,7 +93,7 @@ ContextualError: There was an error in the extension "anonymous" (use named func at process.processTicksAndRejections (node:internal/process/task_queues:XX:XX) at async Object.run (/some/path/to/main.ts:XX:XX:22) at async executeDocument (/some/path/to/requestMethods.ts:XX:XX:18) - at async executeRootTypeField (/some/path/to/requestMethods.ts:XX:XX:18) + 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:3) { context: { hookName: 'encode', diff --git a/website/content/examples/20_output/return-error.md b/website/content/examples/20_output/return-error.md index c2494cb89..4ba13d8b0 100644 --- a/website/content/examples/20_output/return-error.md +++ b/website/content/examples/20_output/return-error.md @@ -40,7 +40,7 @@ ContextualError: There was an error in the extension "anonymous" (use named func at runPipeline (/some/path/to/runPipeline.ts:XX:XX:18) at async Object.run (/some/path/to/main.ts:XX:XX:22) at async executeDocument (/some/path/to/requestMethods.ts:XX:XX:18) - at async executeRootTypeField (/some/path/to/requestMethods.ts:XX:XX:18) + at async executeRootField (/some/path/to/requestMethods.ts:XX:XX:18) at async (/some/path/to/output_return-error.ts:XX:XX:18) { context: { hookName: 'encode', diff --git a/website/content/examples/20_output/standard-graphql.md b/website/content/examples/20_output/standard-graphql.md index a1c81ef75..fec728e1b 100644 --- a/website/content/examples/20_output/standard-graphql.md +++ b/website/content/examples/20_output/standard-graphql.md @@ -34,25 +34,21 @@ ContextualError: There was an error in the core implementation of hook "exchange at runPipeline (/some/path/to/runPipeline.ts:XX:XX:18) at async runPipeline (/some/path/to/runPipeline.ts:XX:XX:14) at async runPipeline (/some/path/to/runPipeline.ts:XX:XX:14) - ... 2 lines matching cause stack trace ... + at async Object.run (/some/path/to/main.ts:XX:XX:22) + at async Object.send (/some/path/to/gql.ts:XX:XX:26) at async (/some/path/to/output_preset__standard-graphql.ts:XX:XX:16) { context: { hookName: 'exchange', source: 'implementation' }, [cause]: TypeError: Failed to parse URL from ... at new Request (node:internal/deps/undici/undici:XX:XX) at Object.run (/some/path/to/core.ts:XX:XX:29) - ... 6 lines matching cause stack trace ... - at async (/some/path/to/output_preset__standard-graphql.ts:XX:XX:16) { + at runHook (/some/path/to/runHook.ts:XX:XX:37) + at runHook (/some/path/to/runHook.ts:XX:XX:16) { [cause]: TypeError: Invalid URL at new URL (node:internal/url:XX:XX) at new Request (node:internal/deps/undici/undici:XX:XX) at Object.run (/some/path/to/core.ts:XX:XX:29) at runHook (/some/path/to/runHook.ts:XX:XX:37) - at runPipeline (/some/path/to/runPipeline.ts:XX:XX:8) - at runPipeline (/some/path/to/runPipeline.ts:XX:XX:20) - at async runPipeline (/some/path/to/runPipeline.ts:XX:XX:14) - at async Object.run (/some/path/to/main.ts:XX:XX:22) - at async Object.send (/some/path/to/gql.ts:XX:XX:26) - at async (/some/path/to/output_preset__standard-graphql.ts:XX:XX:16) { + at runHook (/some/path/to/runHook.ts:XX:XX:16) { code: 'ERR_INVALID_URL', input: '...' } diff --git a/website/content/examples/50_anyware/slot-search-params.md b/website/content/examples/50_anyware/slot-search-params.md index c943fcef9..75daad3d0 100644 --- a/website/content/examples/50_anyware/slot-search-params.md +++ b/website/content/examples/50_anyware/slot-search-params.md @@ -18,7 +18,7 @@ const graffle = Graffle searchParams: (graphqlRequest) => { return { query: graphqlRequest.query, - operationName: `queryContinents`, + operationName: `getPokemon`, } }, }, @@ -26,14 +26,14 @@ const graffle = Graffle }) const result = await graffle.gql` - query trainers { - pokemon { name } - } - query pokemon { + query getTrainers { trainers { name } } + query getPokemon { + pokemon { name } + } ` - .send(`queryCountries`) + .send(`getTrainers`) console.log(result) ``` @@ -43,27 +43,15 @@ console.log(result) ```txt -/some/path/to/runPipeline.ts:XX:XX - return new ContextualError(message, { hookName: signal.hookName, source: signal.source }, signal.error) - ^ - - -ContextualError: There was an error in the core implementation of hook "pack". - at runPipeline (/some/path/to/runPipeline.ts:XX:XX:18) - at async runPipeline (/some/path/to/runPipeline.ts:XX:XX:14) - at async Object.run (/some/path/to/main.ts:XX:XX:22) - at async Object.send (/some/path/to/gql.ts:XX:XX:26) - at async (/some/path/to/anyware_slot_slot-body__slot-search-params.ts:XX:XX:16) { - context: { hookName: 'pack', source: 'implementation' }, - cause: Error: Unexpected null value. - at throwNull (/some/path/to/prelude.ts:XX:XX:29) - at Object.run (/some/path/to/core.ts:XX:XX:35) - at runHook (/some/path/to/runHook.ts:XX:XX:37) - at (/some/path/to/runHook.ts:XX:XX:14) - at (/some/path/to/anyware_slot_slot-body__slot-search-params.ts:XX:XX:18) - at applyBody (/some/path/to/main.ts:XX:XX:28) +{ + pokemon: [ + { name: 'Pikachu' }, + { name: 'Charizard' }, + { name: 'Squirtle' }, + { name: 'Bulbasaur' }, + { name: 'Caterpie' }, + { name: 'Weedle' } + ] } - -Node.js vXX.XX.XX ``` diff --git a/website/content/examples/60_extension/opentelemetry.md b/website/content/examples/60_extension/opentelemetry.md index 1a2a11208..eb0e29675 100644 --- a/website/content/examples/60_extension/opentelemetry.md +++ b/website/content/examples/60_extension/opentelemetry.md @@ -40,14 +40,14 @@ console.log(data) } }, instrumentationScope: { name: 'graffle', version: undefined, schemaUrl: undefined }, - traceId: 'ac014dada983f302716deae963031d77', - parentId: 'fe33e3cb84b589ed', + traceId: '0d775d0099c7910506a0772440555fbe', + parentId: '9b0787a81673ace4', traceState: undefined, name: 'encode', - id: '87f70f2b478a9946', + id: 'e6fbdb4081ec6e4e', kind: 0, - timestamp: 1728323381984000, - duration: 620.917, + timestamp: 1728856242273000, + duration: 1418.125, attributes: {}, status: { code: 0 }, events: [], @@ -67,14 +67,14 @@ console.log(data) } }, instrumentationScope: { name: 'graffle', version: undefined, schemaUrl: undefined }, - traceId: 'ac014dada983f302716deae963031d77', - parentId: 'fe33e3cb84b589ed', + traceId: '0d775d0099c7910506a0772440555fbe', + parentId: '9b0787a81673ace4', traceState: undefined, name: 'pack', - id: '4223bd045e4f82b7', + id: 'c20c4b4a0bb60890', kind: 0, - timestamp: 1728323381987000, - duration: 17090.167, + timestamp: 1728856242277000, + duration: 11234.958, attributes: {}, status: { code: 0 }, events: [], @@ -94,14 +94,14 @@ console.log(data) } }, instrumentationScope: { name: 'graffle', version: undefined, schemaUrl: undefined }, - traceId: 'ac014dada983f302716deae963031d77', - parentId: 'fe33e3cb84b589ed', + traceId: '0d775d0099c7910506a0772440555fbe', + parentId: '9b0787a81673ace4', traceState: undefined, name: 'exchange', - id: '1acd0a0de0d5eb48', + id: 'b37626f52b507127', kind: 0, - timestamp: 1728323382005000, - duration: 28187.833, + timestamp: 1728856242288000, + duration: 106411.25, attributes: {}, status: { code: 0 }, events: [], @@ -121,14 +121,14 @@ console.log(data) } }, instrumentationScope: { name: 'graffle', version: undefined, schemaUrl: undefined }, - traceId: 'ac014dada983f302716deae963031d77', - parentId: 'fe33e3cb84b589ed', + traceId: '0d775d0099c7910506a0772440555fbe', + parentId: '9b0787a81673ace4', traceState: undefined, name: 'unpack', - id: '5190c757f52e1c88', + id: '7cdde5c9f15d334d', kind: 0, - timestamp: 1728323382033000, - duration: 1180.667, + timestamp: 1728856242395000, + duration: 1244.125, attributes: {}, status: { code: 0 }, events: [], @@ -148,14 +148,14 @@ console.log(data) } }, instrumentationScope: { name: 'graffle', version: undefined, schemaUrl: undefined }, - traceId: 'ac014dada983f302716deae963031d77', - parentId: 'fe33e3cb84b589ed', + traceId: '0d775d0099c7910506a0772440555fbe', + parentId: '9b0787a81673ace4', traceState: undefined, name: 'decode', - id: '88685659d9725d48', + id: 'b048da7b0a82b097', kind: 0, - timestamp: 1728323382035000, - duration: 196.375, + timestamp: 1728856242396000, + duration: 181.792, attributes: {}, status: { code: 0 }, events: [], @@ -175,14 +175,14 @@ console.log(data) } }, instrumentationScope: { name: 'graffle', version: undefined, schemaUrl: undefined }, - traceId: 'ac014dada983f302716deae963031d77', + traceId: '0d775d0099c7910506a0772440555fbe', parentId: undefined, traceState: undefined, name: 'request', - id: 'fe33e3cb84b589ed', + id: '9b0787a81673ace4', kind: 0, - timestamp: 1728323381982000, - duration: 53359.417, + timestamp: 1728856242273000, + duration: 123962.916, attributes: {}, status: { code: 0 }, events: [], diff --git a/website/graffle/modules/Client.ts b/website/graffle/modules/Client.ts index fc58fc94a..f3787e620 100644 --- a/website/graffle/modules/Client.ts +++ b/website/graffle/modules/Client.ts @@ -1,4 +1,5 @@ import { createPrefilled } from 'graffle/client' -import { $defaultSchemaUrl, $Index } from './SchemaRuntime.js' +import { defaultSchemaUrl } from './Data.js' +import { schemaDrivenDataMap } from './SchemaDrivenDataMap.js' -export const create = createPrefilled(`default`, $Index, $defaultSchemaUrl) +export const create = createPrefilled(`default`, schemaDrivenDataMap, defaultSchemaUrl) diff --git a/website/graffle/modules/Data.ts b/website/graffle/modules/Data.ts index dd4ec32fe..b5ecc3ae6 100644 --- a/website/graffle/modules/Data.ts +++ b/website/graffle/modules/Data.ts @@ -1,2 +1,4 @@ export const Name = `default` export type Name = 'default' + +export const defaultSchemaUrl = new URL('https://countries.trevorblades.com/graphql') diff --git a/website/graffle/modules/SchemaCustomScalarIndex.ts b/website/graffle/modules/SchemaCustomScalarIndex.ts deleted file mode 100644 index e69de29bb..000000000 diff --git a/website/graffle/modules/SchemaDrivenDataMap.ts b/website/graffle/modules/SchemaDrivenDataMap.ts new file mode 100644 index 000000000..e74ea7a38 --- /dev/null +++ b/website/graffle/modules/SchemaDrivenDataMap.ts @@ -0,0 +1,379 @@ +import type * as $Utilities from 'graffle/utilities-for-generated' +import * as $Scalar from './Scalar.js' +// +// +// +// +// +// +// ================================================================================================== +// GraphQLScalarType +// ================================================================================================== +// +// +// +// +// +// + +const ID = $Scalar.ID + +const String = $Scalar.String + +const Boolean = $Scalar.Boolean + +// +// +// +// +// +// +// ================================================================================================== +// GraphQLScalarTypeCustom +// ================================================================================================== +// +// +// +// +// +// + +// None of your GraphQLScalarTypeCustoms have custom scalars. + +// +// +// +// +// +// +// ================================================================================================== +// GraphQLEnumType +// ================================================================================================== +// +// +// +// +// +// + +// None of your GraphQLEnumTypes have custom scalars. + +// +// +// +// +// +// +// ================================================================================================== +// GraphQLInputObjectType +// ================================================================================================== +// +// +// +// +// +// + +const ContinentFilterInput: $Utilities.SchemaDrivenDataMap.InputObject = { + n: 'ContinentFilterInput', + f: { + code: {}, + }, +} + +const CountryFilterInput: $Utilities.SchemaDrivenDataMap.InputObject = { + n: 'CountryFilterInput', + f: { + code: {}, + continent: {}, + currency: {}, + name: {}, + }, +} + +const LanguageFilterInput: $Utilities.SchemaDrivenDataMap.InputObject = { + n: 'LanguageFilterInput', + f: { + code: {}, + }, +} + +const StringQueryOperatorInput: $Utilities.SchemaDrivenDataMap.InputObject = { + n: 'StringQueryOperatorInput', + f: { + eq: {}, + in: {}, + ne: {}, + nin: {}, + regex: {}, + }, +} + +// +// +// +// +// +// +// ================================================================================================== +// GraphQLObjectType +// ================================================================================================== +// +// +// +// +// +// + +const Continent: $Utilities.SchemaDrivenDataMap.OutputObject = { + f: { + code: {}, + countries: { + // nt: Country, <-- Assigned later to avoid potential circular dependency. + }, + name: {}, + }, +} + +const Country: $Utilities.SchemaDrivenDataMap.OutputObject = { + f: { + awsRegion: {}, + capital: {}, + code: {}, + continent: { + // nt: Continent, <-- Assigned later to avoid potential circular dependency. + }, + currencies: {}, + currency: {}, + emoji: {}, + emojiU: {}, + languages: { + // nt: Language, <-- Assigned later to avoid potential circular dependency. + }, + name: { + a: { + lang: { + nt: String, + it: [0], + }, + }, + }, + native: {}, + phone: {}, + phones: {}, + states: { + // nt: State, <-- Assigned later to avoid potential circular dependency. + }, + subdivisions: { + // nt: Subdivision, <-- Assigned later to avoid potential circular dependency. + }, + }, +} + +const Language: $Utilities.SchemaDrivenDataMap.OutputObject = { + f: { + code: {}, + name: {}, + native: {}, + rtl: {}, + }, +} + +const State: $Utilities.SchemaDrivenDataMap.OutputObject = { + f: { + code: {}, + country: { + // nt: Country, <-- Assigned later to avoid potential circular dependency. + }, + name: {}, + }, +} + +const Subdivision: $Utilities.SchemaDrivenDataMap.OutputObject = { + f: { + code: {}, + emoji: {}, + name: {}, + }, +} + +// +// +// +// +// +// +// ================================================================================================== +// GraphQLInterfaceType +// ================================================================================================== +// +// +// +// +// +// + +// None of your GraphQLInterfaceTypes have custom scalars. + +// +// +// +// +// +// +// ================================================================================================== +// GraphQLUnionType +// ================================================================================================== +// +// +// +// +// +// + +// None of your GraphQLUnionTypes have custom scalars. + +// +// +// +// +// +// +// ================================================================================================== +// GraphQLRootType +// ================================================================================================== +// +// +// +// +// +// + +const Query: $Utilities.SchemaDrivenDataMap.OutputObject = { + f: { + continent: { + a: { + code: { + nt: ID, + it: [1], + }, + }, + // nt: Continent, <-- Assigned later to avoid potential circular dependency. + }, + continents: { + a: { + filter: { + nt: ContinentFilterInput, + it: [0], + }, + }, + // nt: Continent, <-- Assigned later to avoid potential circular dependency. + }, + countries: { + a: { + filter: { + nt: CountryFilterInput, + it: [0], + }, + }, + // nt: Country, <-- Assigned later to avoid potential circular dependency. + }, + country: { + a: { + code: { + nt: ID, + it: [1], + }, + }, + // nt: Country, <-- Assigned later to avoid potential circular dependency. + }, + language: { + a: { + code: { + nt: ID, + it: [1], + }, + }, + // nt: Language, <-- Assigned later to avoid potential circular dependency. + }, + languages: { + a: { + filter: { + nt: LanguageFilterInput, + it: [0], + }, + }, + // nt: Language, <-- Assigned later to avoid potential circular dependency. + }, + }, +} + +// +// +// +// +// +// +// ================================================================================================== +// Reference Assignments +// (avoids circular assignment issues) +// ================================================================================================== +// +// +// +// +// +// + +Continent.f['countries']!.nt = Country +Country.f['continent']!.nt = Continent +Country.f['languages']!.nt = Language +Country.f['states']!.nt = State +Country.f['subdivisions']!.nt = Subdivision +State.f['country']!.nt = Country +Query.f['continent']!.nt = Continent +Query.f['continents']!.nt = Continent +Query.f['countries']!.nt = Country +Query.f['country']!.nt = Country +Query.f['language']!.nt = Language +Query.f['languages']!.nt = Language + +// +// +// +// +// +// +// ================================================================================================== +// Index +// ================================================================================================== +// +// +// +// +// +// + +const $schemaDrivenDataMap: $Utilities.SchemaDrivenDataMap = { + roots: { + Query, + }, + directives: {}, + types: { + ID, + String, + Boolean, + ContinentFilterInput, + CountryFilterInput, + LanguageFilterInput, + StringQueryOperatorInput, + Continent, + Country, + Language, + State, + Subdivision, + Query, + }, +} + +export { $schemaDrivenDataMap as schemaDrivenDataMap } diff --git a/website/graffle/modules/SchemaRuntime.ts b/website/graffle/modules/SchemaRuntime.ts index 8675d92bf..d6c840408 100644 --- a/website/graffle/modules/SchemaRuntime.ts +++ b/website/graffle/modules/SchemaRuntime.ts @@ -1,8 +1,8 @@ /* eslint-disable */ import * as $ from 'graffle/schema' import * as Data from './Data.js' -import { $index as $customScalarsIndex } from './RuntimeCustomScalars.js' import * as $Scalar from './Scalar.js' +import { $index as $customScalarsIndex } from './SchemaDrivenDataMa' import type { Index } from './SchemaIndex.js' export const $defaultSchemaUrl = new URL('https://countries.trevorblades.com/graphql') diff --git a/website/pokemon/modules/Client.ts b/website/pokemon/modules/Client.ts index 530140079..f7ddfba99 100644 --- a/website/pokemon/modules/Client.ts +++ b/website/pokemon/modules/Client.ts @@ -1,4 +1,5 @@ import { createPrefilled } from 'graffle/client' -import { $defaultSchemaUrl, $Index } from './SchemaRuntime.js' +import { defaultSchemaUrl } from './Data.js' +import { schemaDrivenDataMap } from './SchemaDrivenDataMap.js' -export const create = createPrefilled(`Pokemon`, $Index, $defaultSchemaUrl) +export const create = createPrefilled(`Pokemon`, schemaDrivenDataMap, defaultSchemaUrl) diff --git a/website/pokemon/modules/Data.ts b/website/pokemon/modules/Data.ts index c5ba8a7d0..2f19c3ff4 100644 --- a/website/pokemon/modules/Data.ts +++ b/website/pokemon/modules/Data.ts @@ -1,2 +1,4 @@ export const Name = `Pokemon` export type Name = 'Pokemon' + +export const defaultSchemaUrl = new URL('http://localhost:3000/graphql') diff --git a/website/pokemon/modules/SchemaDrivenDataMap.ts b/website/pokemon/modules/SchemaDrivenDataMap.ts new file mode 100644 index 000000000..68e3ac4ae --- /dev/null +++ b/website/pokemon/modules/SchemaDrivenDataMap.ts @@ -0,0 +1,459 @@ +import type * as $Utilities from 'graffle/utilities-for-generated' +import * as $Scalar from './Scalar.js' +// +// +// +// +// +// +// ================================================================================================== +// GraphQLScalarType +// ================================================================================================== +// +// +// +// +// +// + +const Float = $Scalar.Float + +const ID = $Scalar.ID + +const String = $Scalar.String + +const Int = $Scalar.Int + +const Boolean = $Scalar.Boolean + +// +// +// +// +// +// +// ================================================================================================== +// GraphQLScalarTypeCustom +// ================================================================================================== +// +// +// +// +// +// + +// None of your GraphQLScalarTypeCustoms have custom scalars. + +// +// +// +// +// +// +// ================================================================================================== +// GraphQLEnumType +// ================================================================================================== +// +// +// +// +// +// + +const BattleWildResult: $Utilities.SchemaDrivenDataMap.Enum = { + k: 'enum', + n: 'BattleWildResult', +} + +const PokemonType: $Utilities.SchemaDrivenDataMap.Enum = { + k: 'enum', + n: 'PokemonType', +} + +const TrainerClass: $Utilities.SchemaDrivenDataMap.Enum = { + k: 'enum', + n: 'TrainerClass', +} + +// +// +// +// +// +// +// ================================================================================================== +// GraphQLInputObjectType +// ================================================================================================== +// +// +// +// +// +// + +const DateFilter: $Utilities.SchemaDrivenDataMap.InputObject = { + n: 'DateFilter', + f: { + gte: {}, + lte: {}, + }, +} + +const PokemonFilter: $Utilities.SchemaDrivenDataMap.InputObject = { + n: 'PokemonFilter', + f: { + birthday: {}, + name: {}, + }, +} + +const StringFilter: $Utilities.SchemaDrivenDataMap.InputObject = { + n: 'StringFilter', + f: { + contains: {}, + in: {}, + }, +} + +// +// +// +// +// +// +// ================================================================================================== +// GraphQLObjectType +// ================================================================================================== +// +// +// +// +// +// + +const BattleRoyale: $Utilities.SchemaDrivenDataMap.OutputObject = { + f: { + combatants: { + // nt: CombatantMultiPokemon, <-- Assigned later to avoid potential circular dependency. + }, + date: {}, + id: {}, + winner: { + // nt: Trainer, <-- Assigned later to avoid potential circular dependency. + }, + }, +} + +const BattleTrainer: $Utilities.SchemaDrivenDataMap.OutputObject = { + f: { + combatant1: { + // nt: CombatantSinglePokemon, <-- Assigned later to avoid potential circular dependency. + }, + combatant2: { + // nt: CombatantSinglePokemon, <-- Assigned later to avoid potential circular dependency. + }, + date: {}, + id: {}, + winner: { + // nt: Trainer, <-- Assigned later to avoid potential circular dependency. + }, + }, +} + +const BattleWild: $Utilities.SchemaDrivenDataMap.OutputObject = { + f: { + date: {}, + id: {}, + pokemon: { + // nt: Pokemon, <-- Assigned later to avoid potential circular dependency. + }, + result: {}, + trainer: { + // nt: Trainer, <-- Assigned later to avoid potential circular dependency. + }, + wildPokemons: { + // nt: Pokemon, <-- Assigned later to avoid potential circular dependency. + }, + }, +} + +const CombatantMultiPokemon: $Utilities.SchemaDrivenDataMap.OutputObject = { + f: { + pokemons: { + // nt: Pokemon, <-- Assigned later to avoid potential circular dependency. + }, + trainer: { + // nt: Trainer, <-- Assigned later to avoid potential circular dependency. + }, + }, +} + +const CombatantSinglePokemon: $Utilities.SchemaDrivenDataMap.OutputObject = { + f: { + pokemon: { + // nt: Pokemon, <-- Assigned later to avoid potential circular dependency. + }, + trainer: { + // nt: Trainer, <-- Assigned later to avoid potential circular dependency. + }, + }, +} + +const Patron: $Utilities.SchemaDrivenDataMap.OutputObject = { + f: { + id: {}, + money: {}, + name: {}, + }, +} + +const Pokemon: $Utilities.SchemaDrivenDataMap.OutputObject = { + f: { + attack: {}, + birthday: {}, + defense: {}, + hp: {}, + id: {}, + name: {}, + trainer: { + // nt: Trainer, <-- Assigned later to avoid potential circular dependency. + }, + type: {}, + }, +} + +const Trainer: $Utilities.SchemaDrivenDataMap.OutputObject = { + f: { + class: {}, + fans: { + // nt: Patron, <-- Assigned later to avoid potential circular dependency. + }, + id: {}, + name: {}, + pokemon: { + // nt: Pokemon, <-- Assigned later to avoid potential circular dependency. + }, + }, +} + +// +// +// +// +// +// +// ================================================================================================== +// GraphQLInterfaceType +// ================================================================================================== +// +// +// +// +// +// + +const Being: $Utilities.SchemaDrivenDataMap.OutputObject = { + f: {}, +} + +// +// +// +// +// +// +// ================================================================================================== +// GraphQLUnionType +// ================================================================================================== +// +// +// +// +// +// + +const Battle: $Utilities.SchemaDrivenDataMap.OutputObject = { + f: {}, +} + +// +// +// +// +// +// +// ================================================================================================== +// GraphQLRootType +// ================================================================================================== +// +// +// +// +// +// + +const Mutation: $Utilities.SchemaDrivenDataMap.OutputObject = { + f: { + addPokemon: { + a: { + attack: { + nt: Int, + it: [0], + }, + defense: { + nt: Int, + it: [0], + }, + hp: { + nt: Int, + it: [0], + }, + name: { + nt: String, + it: [1], + }, + type: { + nt: PokemonType, + it: [1], + }, + }, + // nt: Pokemon, <-- Assigned later to avoid potential circular dependency. + }, + }, +} + +const Query: $Utilities.SchemaDrivenDataMap.OutputObject = { + f: { + battles: { + // nt: Battle, <-- Assigned later to avoid potential circular dependency. + }, + beings: { + // nt: Being, <-- Assigned later to avoid potential circular dependency. + }, + pokemon: { + // nt: Pokemon, <-- Assigned later to avoid potential circular dependency. + }, + pokemonByName: { + a: { + name: { + nt: String, + it: [1], + }, + }, + // nt: Pokemon, <-- Assigned later to avoid potential circular dependency. + }, + pokemons: { + a: { + filter: { + nt: PokemonFilter, + it: [0], + }, + }, + // nt: Pokemon, <-- Assigned later to avoid potential circular dependency. + }, + trainerByName: { + a: { + name: { + nt: String, + it: [1], + }, + }, + // nt: Trainer, <-- Assigned later to avoid potential circular dependency. + }, + trainers: { + // nt: Trainer, <-- Assigned later to avoid potential circular dependency. + }, + }, +} + +// +// +// +// +// +// +// ================================================================================================== +// Reference Assignments +// (avoids circular assignment issues) +// ================================================================================================== +// +// +// +// +// +// + +BattleRoyale.f['combatants']!.nt = CombatantMultiPokemon +BattleRoyale.f['winner']!.nt = Trainer +BattleTrainer.f['combatant1']!.nt = CombatantSinglePokemon +BattleTrainer.f['combatant2']!.nt = CombatantSinglePokemon +BattleTrainer.f['winner']!.nt = Trainer +BattleWild.f['pokemon']!.nt = Pokemon +BattleWild.f['trainer']!.nt = Trainer +BattleWild.f['wildPokemons']!.nt = Pokemon +CombatantMultiPokemon.f['pokemons']!.nt = Pokemon +CombatantMultiPokemon.f['trainer']!.nt = Trainer +CombatantSinglePokemon.f['pokemon']!.nt = Pokemon +CombatantSinglePokemon.f['trainer']!.nt = Trainer +Pokemon.f['trainer']!.nt = Trainer +Trainer.f['fans']!.nt = Patron +Trainer.f['pokemon']!.nt = Pokemon +Mutation.f['addPokemon']!.nt = Pokemon +Query.f['battles']!.nt = Battle +Query.f['beings']!.nt = Being +Query.f['pokemon']!.nt = Pokemon +Query.f['pokemonByName']!.nt = Pokemon +Query.f['pokemons']!.nt = Pokemon +Query.f['trainerByName']!.nt = Trainer +Query.f['trainers']!.nt = Trainer + +// +// +// +// +// +// +// ================================================================================================== +// Index +// ================================================================================================== +// +// +// +// +// +// + +const $schemaDrivenDataMap: $Utilities.SchemaDrivenDataMap = { + roots: { + Mutation, + Query, + }, + directives: {}, + types: { + Float, + ID, + String, + Int, + Boolean, + BattleWildResult, + PokemonType, + TrainerClass, + DateFilter, + PokemonFilter, + StringFilter, + BattleRoyale, + BattleTrainer, + BattleWild, + CombatantMultiPokemon, + CombatantSinglePokemon, + Patron, + Pokemon, + Trainer, + Being, + Battle, + Mutation, + Query, + }, +} + +export { $schemaDrivenDataMap as schemaDrivenDataMap } diff --git a/website/pokemon/modules/SchemaRuntime.ts b/website/pokemon/modules/SchemaRuntime.ts index 04db7fb1c..72d27156b 100644 --- a/website/pokemon/modules/SchemaRuntime.ts +++ b/website/pokemon/modules/SchemaRuntime.ts @@ -1,8 +1,8 @@ /* eslint-disable */ import * as $ from 'graffle/schema' import * as Data from './Data.js' -import { $index as $customScalarsIndex } from './RuntimeCustomScalars.js' import * as $Scalar from './Scalar.js' +import { $index as $customScalarsIndex } from './SchemaDrivenDataMap.js' import type { Index } from './SchemaIndex.js' export const $defaultSchemaUrl = new URL('http://localhost:3000/graphql') export const BattleWildResult = $.Enum(`BattleWildResult`, [`pokemonsCaptured`, `pokemonsDefeated`, `trainerDefeated`])