From 04d98c6bbc3848516bd6187808e27e683177a3da Mon Sep 17 00:00:00 2001 From: Jason Kuhrt Date: Sun, 22 Dec 2024 09:32:23 -0500 Subject: [PATCH] fix(document-builder): strip $ on enum-typed variables (#1288) --- examples/70_type_level/selection-sets.ts | 121 ++++++++++++++ ...tension_headers__dynamicHeaders.output.txt | 2 +- .../20_output/output_envelope.output.txt | 2 +- ...on_opentelemetry__opentelemetry.output.txt | 58 +++---- .../70_type_level/selection-sets.output.txt | 7 + examples/pnpm-lock.yaml | 16 +- package.json | 2 + src/lib/grafaid/request.ts | 25 +++ src/requestPipeline/RequestPipeline.ts | 4 +- .../70_type_level/selection-sets.test.ts | 19 +++ ....timestamp-1734877293576-49f423770518b.mjs | 148 ++++++++++++++++++ .../_snippets/example-links/selection-sets.md | 1 + .../extension/opentelemetry.detail.md | 58 +++---- .../examples/extension/opentelemetry.md | 58 +++---- .../examples/output/envelope.detail.md | 2 +- .../_snippets/examples/output/envelope.md | 2 +- .../transport-http/dynamic-headers.detail.md | 2 +- .../transport-http/dynamic-headers.md | 2 +- .../type_level/selection-sets.detail.md | 145 +++++++++++++++++ .../examples/type_level/selection-sets.md | 142 +++++++++++++++++ .../10_transport-http/dynamic-headers.md | 2 +- .../content/examples/20_output/envelope.md | 2 +- .../examples/60_extension/opentelemetry.md | 58 +++---- .../examples/70_type_level/selection-sets.md | 147 +++++++++++++++++ 24 files changed, 892 insertions(+), 133 deletions(-) create mode 100644 examples/70_type_level/selection-sets.ts create mode 100644 examples/__outputs__/70_type_level/selection-sets.output.txt create mode 100644 tests/examples/70_type_level/selection-sets.test.ts create mode 100644 website/.vitepress/config.ts.timestamp-1734877293576-49f423770518b.mjs create mode 100644 website/content/_snippets/example-links/selection-sets.md create mode 100644 website/content/_snippets/examples/type_level/selection-sets.detail.md create mode 100644 website/content/_snippets/examples/type_level/selection-sets.md create mode 100644 website/content/examples/70_type_level/selection-sets.md diff --git a/examples/70_type_level/selection-sets.ts b/examples/70_type_level/selection-sets.ts new file mode 100644 index 000000000..4f8b116ee --- /dev/null +++ b/examples/70_type_level/selection-sets.ts @@ -0,0 +1,121 @@ +/** + * This example shows how to work with the selection set types generated by Graffle. Selection set types reflect your GraphQL schema. + */ + +import { Graffle } from '../$/graffle/__.js' +import { showJson } from '../$/helpers.js' + +type _ = [ + // + // ======================== + // Primary TypeScript Types + // ======================== + // + // + // 1. GraphQL Types + // -------------- + // The SelectionSets namespace contains a TypeScript type for each GraphQL type. + // + Graffle.SelectionSets.Query, + Graffle.SelectionSets.Mutation, + Graffle.SelectionSets.Battle, + // ... + // + // Each type contains the selection set for that type. + // + Graffle.SelectionSets.Query['pokemons'], + Graffle.SelectionSets.Query['trainers'], + Graffle.SelectionSets.Mutation['addPokemon'], + Graffle.SelectionSets.Battle['___on_BattleRoyale'], + + // 2. GraphQL Type Fields + // ------------------- + // Each name is also overloaded with a namespace. Within it, you will find more TypeScript types. + // One per selection set field in the respective GraphQL type. + // + Graffle.SelectionSets.Query.pokemons, + Graffle.SelectionSets.Query.trainers, + Graffle.SelectionSets.Mutation.addPokemon, + // ... + // + // Each GraphQL type field type has properties about the selection set set for that field. + // + Graffle.SelectionSets.Query.pokemons['$'], + Graffle.SelectionSets.Query.trainers['$skip'], + Graffle.SelectionSets.Mutation.addPokemon['id'], + // ... + // + // You may have already noticed but there is a relationship between these two things: + // - The GraphQL Type type properties + // - The GraphQL Type Field types. + // + // Use the kind of type that suites your use case. + // + Graffle.SelectionSets.Query['pokemons'], + Graffle.SelectionSets.Query.pokemons, + // + // 3. TypeScript Types for Arguments + // ------------------------------ + // There are type definitions for GraphQL Type Field Arguments + // + Graffle.SelectionSets.Query.pokemons$Arguments, + Graffle.SelectionSets.Query.trainerByName$Arguments, + Graffle.SelectionSets.Mutation.addPokemon$Arguments, + // ... + // + // + // ====================== + // Niche TypeScript Types + // ====================== + // + // + // 4. "Expanded" Variants + // ------------------- + // You will find various type definitions with the suffix `$Expanded`. + // From a type-checking point of view they are identical to their non-expanded form. + // They differ in how they will be displayed in tooling, namely IDEs. + // You can leverage them to improve DX in your use-cases. + // For more details, refer to their JSDoc. + // + Graffle.SelectionSets.Query.pokemons$Expanded, + Graffle.SelectionSets.Mutation.addPokemon$Expanded, + // ... + // + // 5. Inline Fragments + // ---------------- + // + Graffle.SelectionSets.Query$FragmentInline, + Graffle.SelectionSets.Battle$FragmentInline, + // ... + // + // 6. Selection Sets Sans Union with Indicators + // ----------------------------------------- + // If the GraphQL field is a non-scalar OR scalar-with-arguments, then its type will be synonymous + // with its explicit selection set type. For example: + // + Graffle.SelectionSets.Query.beings, + Graffle.SelectionSets.Query.beings$SelectionSet, + // However, if the GraphQL field IS a scalar-without-arguments, then its type will become an + // indicator unioned with the "meta" selection set (meaning stuff like field directives). + // + // Meanwhile, the explicit selection set type will _only_ have those meta things, not the + // indicator. For example: + // + Graffle.SelectionSets.Pokemon.name, + Graffle.SelectionSets.Pokemon.name$SelectionSet, +] + +const graffle = Graffle.create() + +const getPokemonsLike = async (filter: Graffle.SelectionSets.Query.pokemons$Arguments['filter']) => + graffle.query.pokemons({ + $: { filter }, + hp: true, + name: true, + }) + +// todo add test coverage for $ stripping on arguments. +const pokemons = await getPokemonsLike({ $type: `water` }) + +// We don't lose any type safety. :) +showJson(pokemons) 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 c0e9b3fcd..df8a3be32 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': '1734835236654' + 'x-sent-at-time': '1734877667965' }, method: 'post', url: 'http://localhost:3000/graphql', diff --git a/examples/__outputs__/20_output/output_envelope.output.txt b/examples/__outputs__/20_output/output_envelope.output.txt index dd1d94477..c171e75d8 100644 --- a/examples/__outputs__/20_output/output_envelope.output.txt +++ b/examples/__outputs__/20_output/output_envelope.output.txt @@ -16,7 +16,7 @@ headers: Headers { 'content-type': 'application/graphql-response+json; charset=utf-8', 'content-length': '142', - date: 'Sun, 22 Dec 2024 02:40:37 GMT', + date: 'Sun, 22 Dec 2024 14:27:48 GMT', connection: 'keep-alive', 'keep-alive': 'timeout=5' }, diff --git a/examples/__outputs__/60_extension/extension_opentelemetry__opentelemetry.output.txt b/examples/__outputs__/60_extension/extension_opentelemetry__opentelemetry.output.txt index cad31421c..9a03999da 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: 'e8d5df13d914fbbd4ccbdcfacd957ab0', - parentId: '8e35291fef6405ac', + traceId: '0e52a2a1fb3ccb88d38cd44dded63dec', + parentId: '6fcf4ddd316eb7dd', traceState: undefined, name: 'encode', - id: '57064bac33995f52', + id: 'e30897dc9cb51142', kind: 0, - timestamp: 1734835237807000, - duration: 985.375, + timestamp: 1734877668621000, + duration: 1060.917, attributes: {}, status: { code: 0 }, events: [], @@ -33,14 +33,14 @@ } }, instrumentationScope: { name: 'graffle', version: undefined, schemaUrl: undefined }, - traceId: 'e8d5df13d914fbbd4ccbdcfacd957ab0', - parentId: '8e35291fef6405ac', + traceId: '0e52a2a1fb3ccb88d38cd44dded63dec', + parentId: '6fcf4ddd316eb7dd', traceState: undefined, name: 'pack', - id: '4160ec4bd017e345', + id: '893c1fed7b2256dd', kind: 0, - timestamp: 1734835237808000, - duration: 12389.166, + timestamp: 1734877668623000, + duration: 18450.083, attributes: {}, status: { code: 0 }, events: [], @@ -57,14 +57,14 @@ } }, instrumentationScope: { name: 'graffle', version: undefined, schemaUrl: undefined }, - traceId: 'e8d5df13d914fbbd4ccbdcfacd957ab0', - parentId: '8e35291fef6405ac', + traceId: '0e52a2a1fb3ccb88d38cd44dded63dec', + parentId: '6fcf4ddd316eb7dd', traceState: undefined, name: 'exchange', - id: 'b605384e7351522a', + id: 'b0c30685f178d075', kind: 0, - timestamp: 1734835237821000, - duration: 21988.041, + timestamp: 1734877668642000, + duration: 25750.5, attributes: {}, status: { code: 0 }, events: [], @@ -81,14 +81,14 @@ } }, instrumentationScope: { name: 'graffle', version: undefined, schemaUrl: undefined }, - traceId: 'e8d5df13d914fbbd4ccbdcfacd957ab0', - parentId: '8e35291fef6405ac', + traceId: '0e52a2a1fb3ccb88d38cd44dded63dec', + parentId: '6fcf4ddd316eb7dd', traceState: undefined, name: 'unpack', - id: '3dc693f1496eb20f', + id: 'c148fb01cd7693fa', kind: 0, - timestamp: 1734835237844000, - duration: 1031.333, + timestamp: 1734877668668000, + duration: 1080.291, attributes: {}, status: { code: 0 }, events: [], @@ -105,14 +105,14 @@ } }, instrumentationScope: { name: 'graffle', version: undefined, schemaUrl: undefined }, - traceId: 'e8d5df13d914fbbd4ccbdcfacd957ab0', - parentId: '8e35291fef6405ac', + traceId: '0e52a2a1fb3ccb88d38cd44dded63dec', + parentId: '6fcf4ddd316eb7dd', traceState: undefined, name: 'decode', - id: '41886c6abbbe3566', + id: '634824deddb746e7', kind: 0, - timestamp: 1734835237845000, - duration: 457.25, + timestamp: 1734877668670000, + duration: 516.708, attributes: {}, status: { code: 0 }, events: [], @@ -129,14 +129,14 @@ } }, instrumentationScope: { name: 'graffle', version: undefined, schemaUrl: undefined }, - traceId: 'e8d5df13d914fbbd4ccbdcfacd957ab0', + traceId: '0e52a2a1fb3ccb88d38cd44dded63dec', parentId: undefined, traceState: undefined, name: 'request', - id: '8e35291fef6405ac', + id: '6fcf4ddd316eb7dd', kind: 0, - timestamp: 1734835237806000, - duration: 39409.5, + timestamp: 1734877668621000, + duration: 49549.459, attributes: {}, status: { code: 0 }, events: [], diff --git a/examples/__outputs__/70_type_level/selection-sets.output.txt b/examples/__outputs__/70_type_level/selection-sets.output.txt new file mode 100644 index 000000000..626bdadcd --- /dev/null +++ b/examples/__outputs__/70_type_level/selection-sets.output.txt @@ -0,0 +1,7 @@ +---------------------------------------- SHOW ---------------------------------------- +[ + { + "hp": 44, + "name": "Squirtle" + } +] \ No newline at end of file diff --git a/examples/pnpm-lock.yaml b/examples/pnpm-lock.yaml index ead9521d3..1a64070c1 100644 --- a/examples/pnpm-lock.yaml +++ b/examples/pnpm-lock.yaml @@ -115,8 +115,8 @@ packages: resolution: {integrity: sha512-7HSX4QQb4CspciLpVFwyRe79O3xsIZDDLER21kERQ71oaPodF8jL725AgJMFAYbooIqolJoRLuM81SpeUkpkvA==} engines: {node: '>=12'} - chalk@5.3.0: - resolution: {integrity: sha512-dLitG79d+GV1Nb/VYcCDFivJeK1hiukt9QjRNVOsUtTy1rR1YJsmpGGTZ3qJos+uw7WmWF4wUwBd9jxjocFC2w==} + chalk@5.4.1: + resolution: {integrity: sha512-zgVZuo2WcZgfUEmsn6eO3kINexW8RAE4maiQ8QNs8CtpPCSyMiYsULR3HQYkm3w8FIA3SberyMJMSldGsW+U3w==} engines: {node: ^12.17.0 || ^14.13 || >=16.0.0} es-toolkit@1.30.1: @@ -181,8 +181,8 @@ packages: ts-toolbelt@9.6.0: resolution: {integrity: sha512-nsZd8ZeNUzukXPlJmTBwUAuABDe/9qtVDelJeT/qW0ow3ZS3BsQJtNkan1802aM9Uf68/Y8ljw86Hu0h5IUW3w==} - type-fest@4.30.1: - resolution: {integrity: sha512-ojFL7eDMX2NF0xMbDwPZJ8sb7ckqtlAi1GsmgsFXvErT9kFTk1r0DuQKvrCh73M6D4nngeHJmvogF9OluXs7Hw==} + type-fest@4.30.2: + resolution: {integrity: sha512-UJShLPYi1aWqCdq9HycOL/gwsuqda1OISdBO3t8RlXQC4QvtuIz4b5FCfe2dQIWEpmlRExKmcTBfP1r9bhY7ig==} engines: {node: '>=16'} typescript@5.7.2: @@ -207,14 +207,14 @@ snapshots: dependencies: '@molt/types': 0.2.0 alge: 0.8.1 - chalk: 5.3.0 + chalk: 5.4.1 lodash.camelcase: 4.3.0 lodash.snakecase: 4.1.1 readline-sync: 1.4.10 string-length: 6.0.0 strip-ansi: 7.1.0 ts-toolbelt: 9.6.0 - type-fest: 4.30.1 + type-fest: 4.30.2 zod: 3.24.1 '@molt/types@0.2.0': @@ -280,7 +280,7 @@ snapshots: ansi-regex@6.1.0: {} - chalk@5.3.0: {} + chalk@5.4.1: {} es-toolkit@1.30.1: {} @@ -321,7 +321,7 @@ snapshots: ts-toolbelt@9.6.0: {} - type-fest@4.30.1: {} + type-fest@4.30.2: {} typescript@5.7.2: {} diff --git a/package.json b/package.json index 4f6992bca..edbc55c97 100644 --- a/package.json +++ b/package.json @@ -92,6 +92,8 @@ "serve:pokemon": "tsx tests/_/services/pokemonManual.ts", "gen:graffle": "pnpm gen:graffle:tests && pnpm build && cd website && pnpm gen:graffle", "gen:graffle:tests": "tsx tests/_/schemas/generate.ts && pnpm graffle --project src/extensions/SchemaErrors/tests/fixture", + "gen:graffle:examples": "pnpm build && cd examples && pnpm i && pnpm gen:graffle", + "examples:link-mode": "cd examples && pnpm add ..", "graffle": "tsx ./src/generator/cli/generate.ts", "gen:examples": "tsx scripts/generate-examples-derivatives/generate.ts && pnpm format", "gen:examples:outputs": "tsx scripts/generate-examples-derivatives/generate.ts --outputs", diff --git a/src/lib/grafaid/request.ts b/src/lib/grafaid/request.ts index c1d1efa5e..d6aa23b26 100644 --- a/src/lib/grafaid/request.ts +++ b/src/lib/grafaid/request.ts @@ -1,3 +1,4 @@ +import { isPlainObject } from 'es-toolkit' import type { GraphQLError, OperationDefinitionNode, OperationTypeNode } from 'graphql' import type { Errors } from '../errors/__.js' import type { Grafaid } from './__.js' @@ -49,6 +50,7 @@ export const normalizeRequestToNode = <$R extends RequestInput | RequestAnalyzed never => { const query = normalizeDocumentToNode(request.query) + // we have to strip the $ from the variables keys (enum types) if (`operation` in request) { const operation = getOperationDefinition({ @@ -68,3 +70,26 @@ export const normalizeRequestToNode = <$R extends RequestInput | RequestAnalyzed query, } as any } + +// todo: refactor into concise visitor pattern. +export const normalizeVariables = (variables?: Variables): Variables => { + return normalizeVariables_(variables) +} + +const normalizeVariables_ = (value: unknown): any => { + if (value === undefined) return undefined + if (value === null) return null + if (typeof value !== `object`) return value + if (Array.isArray(value)) return value.map(normalizeVariables_) + if (!isPlainObject(value)) return value // todo: optimize + + const normalized: Variables = {} + + for (const key in value) { + const normalizedKey = key.replace(/^\$/, ``) + const normalizedValue = normalizeVariables_(value[key]) + normalized[normalizedKey] = normalizedValue + } + + return normalized +} diff --git a/src/requestPipeline/RequestPipeline.ts b/src/requestPipeline/RequestPipeline.ts index 3203caa5a..4d224ae34 100644 --- a/src/requestPipeline/RequestPipeline.ts +++ b/src/requestPipeline/RequestPipeline.ts @@ -3,7 +3,7 @@ import type { GraffleExecutionResultEnvelope } from '../client/handleOutput.js' import { Anyware } from '../lib/anyware/__.js' import type { Config } from '../lib/anyware/PipelineDef/Config.js' import type { Grafaid } from '../lib/grafaid/__.js' -import { normalizeRequestToNode } from '../lib/grafaid/request.js' +import { normalizeRequestToNode, normalizeVariables } from '../lib/grafaid/request.js' import { isAbortError } from '../lib/prelude.js' import type { Context } from '../types/context.js' import { decodeResultData } from './CustomScalars/decode.js' @@ -90,8 +90,10 @@ export const requestPipelineBaseDefinition: RequestPipelineBaseDefinition = Anyw input.request.query = request.query encodeRequestVariables({ sddm, scalars, request }) + // input.request.variables = request.variables // enum $ stripping } + input.request.variables = normalizeVariables(input.request.variables) return input }, }) diff --git a/tests/examples/70_type_level/selection-sets.test.ts b/tests/examples/70_type_level/selection-sets.test.ts new file mode 100644 index 000000000..8309ff38c --- /dev/null +++ b/tests/examples/70_type_level/selection-sets.test.ts @@ -0,0 +1,19 @@ +// @vitest-environment node + +// WARNING: +// This test is generated by scripts/generate-example-derivatives/generate.ts +// Do not modify this file directly. + +import { expect, test } from 'vitest' +import { runExample } from '../../../scripts/generate-examples-derivatives/helpers.js' + +test(`selection-sets`, async () => { + const exampleResult = await runExample(`./examples/70_type_level/selection-sets.ts`) + // Examples should output their data results. + const exampleResultMaybeEncoded = exampleResult + // If ever outputs vary by Node version, you can use this to snapshot by Node version. + // const nodeMajor = process.version.match(/v(\d+)/)?.[1] ?? `unknown` + await expect(exampleResultMaybeEncoded).toMatchFileSnapshot( + `../../../examples/__outputs__/70_type_level/selection-sets.output.txt`, + ) +}) diff --git a/website/.vitepress/config.ts.timestamp-1734877293576-49f423770518b.mjs b/website/.vitepress/config.ts.timestamp-1734877293576-49f423770518b.mjs new file mode 100644 index 000000000..de33e77c0 --- /dev/null +++ b/website/.vitepress/config.ts.timestamp-1734877293576-49f423770518b.mjs @@ -0,0 +1,148 @@ +// .vitepress/config.ts +import { createFileSystemTypesCache } from 'file:///Users/jasonkuhrt/projects/jasonkuhrt/graffle/website/node_modules/.pnpm/@shikijs+vitepress-twoslash@1.24.4_typescript@5.7.2/node_modules/@shikijs/vitepress-twoslash/dist/cache-fs.mjs' +import { transformerTwoslash } from 'file:///Users/jasonkuhrt/projects/jasonkuhrt/graffle/website/node_modules/.pnpm/@shikijs+vitepress-twoslash@1.24.4_typescript@5.7.2/node_modules/@shikijs/vitepress-twoslash/dist/index.mjs' +import { + ModuleKind, + ModuleResolutionKind, +} from 'file:///Users/jasonkuhrt/projects/jasonkuhrt/graffle/website/node_modules/.pnpm/typescript@5.7.2/node_modules/typescript/lib/typescript.js' +import { tabsMarkdownPlugin } from 'file:///Users/jasonkuhrt/projects/jasonkuhrt/graffle/website/node_modules/.pnpm/vitepress-plugin-tabs@0.5.0_vitepress@1.5.0_@algolia+client-search@5.18.0_postcss@8.4.49_sear_sjxfchr23nu2ftbpbwru3ytjyy/node_modules/vitepress-plugin-tabs/dist/index.js' +import { generateSidebar } from 'file:///Users/jasonkuhrt/projects/jasonkuhrt/graffle/website/node_modules/.pnpm/vitepress-sidebar@1.30.2/node_modules/vitepress-sidebar/dist/index.js' +import { defineConfig } from 'file:///Users/jasonkuhrt/projects/jasonkuhrt/graffle/website/node_modules/.pnpm/vitepress@1.5.0_@algolia+client-search@5.18.0_postcss@8.4.49_search-insights@2.17.3_typescript@5.7.2/node_modules/vitepress/dist/node/index.js' +var prefixPattern = /\d+_/g +var sidebarMultiVisitItems = (sidebarMulti, visitor) => { + Object.values(sidebarMulti).forEach((sidebar) => sidebar.items.forEach((_) => sidebarItemVisitItems(_, visitor))) + return sidebarMulti +} +var sidebarItemVisitItems = (sidebarItem, visitor) => { + visitor(sidebarItem) + sidebarItem.items?.forEach((_) => sidebarItemVisitItems(_, visitor)) +} +var fixLinks = (sidebarMulti) => { + return sidebarMultiVisitItems(sidebarMulti, (sidebarItem) => { + sidebarItem.link = sidebarItem.link?.replaceAll(prefixPattern, '') + }) +} +var sidebars = fixLinks(generateSidebar([ + { + scanStartPath: 'content/guides', + resolvePath: '/guides/', + prefixSeparator: '_', + removePrefixAfterOrdering: true, + useTitleFromFrontmatter: true, + useTitleFromFileHeading: true, + hyphenToSpace: true, + capitalizeEachWords: true, + keepMarkdownSyntaxFromTitle: true, + }, + { + hyphenToSpace: true, + capitalizeEachWords: true, + scanStartPath: 'content/examples', + resolvePath: '/examples/', + prefixSeparator: '_', + removePrefixAfterOrdering: true, + useTitleFromFrontmatter: true, + useTitleFromFileHeading: true, + keepMarkdownSyntaxFromTitle: true, + }, + { + hyphenToSpace: true, + capitalizeEachWords: true, + scanStartPath: 'content/extensions', + resolvePath: '/extensions/', + prefixSeparator: '_', + removePrefixAfterOrdering: true, + useTitleFromFrontmatter: true, + useTitleFromFileHeading: true, + keepMarkdownSyntaxFromTitle: true, + }, +])) +sidebars['/examples/'].items.find((_) => _.text === 'About').items.unshift({ text: 'Introduction', link: '/' }) +sidebars['/guides/'].items.unshift({ text: 'Introduction', link: '/' }) +var rootItems = sidebars['/guides/'].items.filter((_) => !_.items) +sidebars['/guides/'].items = sidebars['/guides/'].items.filter((_) => _.items && _.items.length > 0) +sidebars['/guides/'].items.unshift(...rootItems) +var config_default = defineConfig({ + rewrites: (path) => { + const newPath = path.replaceAll(prefixPattern, '') + return newPath + }, + title: 'Graffle', + description: 'Minimalist Progressively Type Safe GraphQL Client For JavaScript.', + cleanUrls: true, + // TODO, remove before going live. + ignoreDeadLinks: true, + sitemap: { + hostname: 'https://graffle.js.org', + }, + head: [ + // + ['script', { + defer: 'true', + 'data-domain': 'graffle.js.org', + src: 'https://plausible.io/js/script.js', + }], + ], + markdown: { + config(md) { + md.use(tabsMarkdownPlugin) + }, + codeTransformers: [ + ...process.env.disable_twoslash ? [] : [ + transformerTwoslash({ + typesCache: createFileSystemTypesCache({ + dir: './.vitepress/cache/types', + }), + twoslashOptions: { + handbookOptions: { + // noErrors: true, + // noErrorValidation: process.env.NODE_ENV !== 'development', + }, + compilerOptions: { + moduleResolution: ModuleResolutionKind.Bundler, + module: ModuleKind.ESNext, + // noErrorTruncation: true, + }, + shouldGetHoverInfo: (x, b, c) => { + const ignoreIdentifiers = ['console', 'log'] + return !ignoreIdentifiers.includes(x) + }, + }, + }), + ], + ], + }, + srcDir: './content', + themeConfig: { + footer: { + message: 'Released under the MIT License.', + copyright: 'Copyright \xA9 2024-present Jason Kuhrt', + }, + // @see https://github.com/vuejs/vitepress/issues/4141 + logo: { + light: '/_assets/logo-dark.svg', + dark: '/_assets/logo-light.svg', + }, + search: { + provider: 'local', + }, + docFooter: { + next: false, + prev: false, + }, + aside: 'left', + nav: [ + { text: 'Guides', link: '/guides' }, + { text: 'Examples', link: '/examples' }, + { text: 'Extensions', link: '/extensions' }, + ], + sidebar: { + ...sidebars, + }, + socialLinks: [ + { icon: 'github', link: 'https://github.com/graffle-js/graffle' }, + ], + }, +}) +export { config_default as default } +// # sourceMappingURL=data:application/json;base64,ewogICJ2ZXJzaW9uIjogMywKICAic291cmNlcyI6IFsiLnZpdGVwcmVzcy9jb25maWcudHMiXSwKICAic291cmNlc0NvbnRlbnQiOiBbImNvbnN0IF9fdml0ZV9pbmplY3RlZF9vcmlnaW5hbF9kaXJuYW1lID0gXCIvVXNlcnMvamFzb25rdWhydC9wcm9qZWN0cy9qYXNvbmt1aHJ0L2dyYWZmbGUvd2Vic2l0ZS8udml0ZXByZXNzXCI7Y29uc3QgX192aXRlX2luamVjdGVkX29yaWdpbmFsX2ZpbGVuYW1lID0gXCIvVXNlcnMvamFzb25rdWhydC9wcm9qZWN0cy9qYXNvbmt1aHJ0L2dyYWZmbGUvd2Vic2l0ZS8udml0ZXByZXNzL2NvbmZpZy50c1wiO2NvbnN0IF9fdml0ZV9pbmplY3RlZF9vcmlnaW5hbF9pbXBvcnRfbWV0YV91cmwgPSBcImZpbGU6Ly8vVXNlcnMvamFzb25rdWhydC9wcm9qZWN0cy9qYXNvbmt1aHJ0L2dyYWZmbGUvd2Vic2l0ZS8udml0ZXByZXNzL2NvbmZpZy50c1wiO2ltcG9ydCB7IHRyYW5zZm9ybWVyVHdvc2xhc2ggfSBmcm9tICdAc2hpa2lqcy92aXRlcHJlc3MtdHdvc2xhc2gnXG5pbXBvcnQgeyBjcmVhdGVGaWxlU3lzdGVtVHlwZXNDYWNoZSB9IGZyb20gJ0BzaGlraWpzL3ZpdGVwcmVzcy10d29zbGFzaC9jYWNoZS1mcydcbmltcG9ydCB7IE1vZHVsZUtpbmQsIE1vZHVsZVJlc29sdXRpb25LaW5kIH0gZnJvbSAndHlwZXNjcmlwdCdcbmltcG9ydCB7IGRlZmluZUNvbmZpZyB9IGZyb20gJ3ZpdGVwcmVzcydcbmltcG9ydCB7IHRhYnNNYXJrZG93blBsdWdpbiB9IGZyb20gJ3ZpdGVwcmVzcy1wbHVnaW4tdGFicydcbmltcG9ydCB7IGdlbmVyYXRlU2lkZWJhciB9IGZyb20gJ3ZpdGVwcmVzcy1zaWRlYmFyJ1xuaW1wb3J0IHsgU2lkZWJhckl0ZW0sIFNpZGViYXJNdWx0aSB9IGZyb20gJ3ZpdGVwcmVzcy1zaWRlYmFyL3R5cGVzJ1xuXG5jb25zdCBwcmVmaXhQYXR0ZXJuID0gL1xcZCtfL2dcblxuY29uc3Qgc2lkZWJhck11bHRpVmlzaXRJdGVtcyA9IChzaWRlYmFyTXVsdGk6IFNpZGViYXJNdWx0aSwgdmlzaXRvcjogKHNpZGViYXJJdGVtOiBTaWRlYmFySXRlbSkgPT4gdm9pZCkgPT4ge1xuICBPYmplY3QudmFsdWVzKHNpZGViYXJNdWx0aSkuZm9yRWFjaChzaWRlYmFyID0+IHNpZGViYXIuaXRlbXMuZm9yRWFjaChfID0+IHNpZGViYXJJdGVtVmlzaXRJdGVtcyhfLCB2aXNpdG9yKSkpXG4gIHJldHVybiBzaWRlYmFyTXVsdGlcbn1cblxuY29uc3Qgc2lkZWJhckl0ZW1WaXNpdEl0ZW1zID0gKHNpZGViYXJJdGVtOiBTaWRlYmFySXRlbSwgdmlzaXRvcjogKHNpZGViYXJJdGVtOiBTaWRlYmFySXRlbSkgPT4gdm9pZCkgPT4ge1xuICB2aXNpdG9yKHNpZGViYXJJdGVtKVxuICBzaWRlYmFySXRlbS5pdGVtcz8uZm9yRWFjaChfID0+IHNpZGViYXJJdGVtVmlzaXRJdGVtcyhfLCB2aXNpdG9yKSlcbn1cblxuY29uc3QgZml4TGlua3MgPSAoc2lkZWJhck11bHRpOiBTaWRlYmFyTXVsdGkpID0+IHtcbiAgcmV0dXJuIHNpZGViYXJNdWx0aVZpc2l0SXRlbXMoc2lkZWJhck11bHRpLCAoc2lkZWJhckl0ZW0pID0+IHtcbiAgICBzaWRlYmFySXRlbS5saW5rID0gc2lkZWJhckl0ZW0ubGluaz8ucmVwbGFjZUFsbChwcmVmaXhQYXR0ZXJuLCAnJylcbiAgfSlcbn1cblxuLyoqXG4gKiBAc2VlIGh0dHBzOi8vdml0ZXByZXNzLXNpZGViYXIuY2RnZXQuY29tL2d1aWRlL2FwaVxuICovXG5jb25zdCBzaWRlYmFycyA9IGZpeExpbmtzKGdlbmVyYXRlU2lkZWJhcihbXG4gIHtcbiAgICBzY2FuU3RhcnRQYXRoOiAnY29udGVudC9ndWlkZXMnLFxuICAgIHJlc29sdmVQYXRoOiAnL2d1aWRlcy8nLFxuICAgIHByZWZpeFNlcGFyYXRvcjogJ18nLFxuICAgIHJlbW92ZVByZWZpeEFmdGVyT3JkZXJpbmc6IHRydWUsXG4gICAgdXNlVGl0bGVGcm9tRnJvbnRtYXR0ZXI6IHRydWUsXG4gICAgdXNlVGl0bGVGcm9tRmlsZUhlYWRpbmc6IHRydWUsXG4gICAgaHlwaGVuVG9TcGFjZTogdHJ1ZSxcbiAgICBjYXBpdGFsaXplRWFjaFdvcmRzOiB0cnVlLFxuICAgIGtlZXBNYXJrZG93blN5bnRheEZyb21UaXRsZTogdHJ1ZSxcbiAgfSxcbiAge1xuICAgIGh5cGhlblRvU3BhY2U6IHRydWUsXG4gICAgY2FwaXRhbGl6ZUVhY2hXb3JkczogdHJ1ZSxcbiAgICBzY2FuU3RhcnRQYXRoOiAnY29udGVudC9leGFtcGxlcycsXG4gICAgcmVzb2x2ZVBhdGg6ICcvZXhhbXBsZXMvJyxcbiAgICBwcmVmaXhTZXBhcmF0b3I6ICdfJyxcbiAgICByZW1vdmVQcmVmaXhBZnRlck9yZGVyaW5nOiB0cnVlLFxuICAgIHVzZVRpdGxlRnJvbUZyb250bWF0dGVyOiB0cnVlLFxuICAgIHVzZVRpdGxlRnJvbUZpbGVIZWFkaW5nOiB0cnVlLFxuICAgIGtlZXBNYXJrZG93blN5bnRheEZyb21UaXRsZTogdHJ1ZSxcbiAgfSxcbiAge1xuICAgIGh5cGhlblRvU3BhY2U6IHRydWUsXG4gICAgY2FwaXRhbGl6ZUVhY2hXb3JkczogdHJ1ZSxcbiAgICBzY2FuU3RhcnRQYXRoOiAnY29udGVudC9leHRlbnNpb25zJyxcbiAgICByZXNvbHZlUGF0aDogJy9leHRlbnNpb25zLycsXG4gICAgcHJlZml4U2VwYXJhdG9yOiAnXycsXG4gICAgcmVtb3ZlUHJlZml4QWZ0ZXJPcmRlcmluZzogdHJ1ZSxcbiAgICB1c2VUaXRsZUZyb21Gcm9udG1hdHRlcjogdHJ1ZSxcbiAgICB1c2VUaXRsZUZyb21GaWxlSGVhZGluZzogdHJ1ZSxcbiAgICBrZWVwTWFya2Rvd25TeW50YXhGcm9tVGl0bGU6IHRydWUsXG4gIH0sXG5dKSBhcyBTaWRlYmFyTXVsdGkpXG5cbnNpZGViYXJzWycvZXhhbXBsZXMvJ10uaXRlbXMuZmluZChfID0+IF8udGV4dCA9PT0gJ0Fib3V0JykhLml0ZW1zIS51bnNoaWZ0KHsgdGV4dDogJ0ludHJvZHVjdGlvbicsIGxpbms6ICcvJyB9KVxuc2lkZWJhcnNbJy9ndWlkZXMvJ10uaXRlbXMudW5zaGlmdCh7IHRleHQ6ICdJbnRyb2R1Y3Rpb24nLCBsaW5rOiAnLycgfSlcblxuY29uc3Qgcm9vdEl0ZW1zID0gc2lkZWJhcnNbJy9ndWlkZXMvJ10uaXRlbXMuZmlsdGVyKF8gPT4gIV8uaXRlbXMpXG5cbnNpZGViYXJzWycvZ3VpZGVzLyddLml0ZW1zID0gc2lkZWJhcnNbJy9ndWlkZXMvJ10uaXRlbXMuZmlsdGVyKF8gPT4gXy5pdGVtcyAmJiBfLml0ZW1zLmxlbmd0aCA+IDApXG5zaWRlYmFyc1snL2d1aWRlcy8nXS5pdGVtcy51bnNoaWZ0KC4uLnJvb3RJdGVtcylcblxuLy8gaHR0cHM6Ly92aXRlcHJlc3MuZGV2L3JlZmVyZW5jZS9zaXRlLWNvbmZpZ1xuZXhwb3J0IGRlZmF1bHQgZGVmaW5lQ29uZmlnKHtcbiAgcmV3cml0ZXM6IChwYXRoKSA9PiB7XG4gICAgY29uc3QgbmV3UGF0aCA9IHBhdGgucmVwbGFjZUFsbChwcmVmaXhQYXR0ZXJuLCAnJylcbiAgICByZXR1cm4gbmV3UGF0aFxuICB9LFxuICB0aXRsZTogJ0dyYWZmbGUnLFxuICBkZXNjcmlwdGlvbjogJ01pbmltYWxpc3QgUHJvZ3Jlc3NpdmVseSBUeXBlIFNhZmUgR3JhcGhRTCBDbGllbnQgRm9yIEphdmFTY3JpcHQuJyxcbiAgY2xlYW5VcmxzOiB0cnVlLFxuICAvLyBUT0RPLCByZW1vdmUgYmVmb3JlIGdvaW5nIGxpdmUuXG4gIGlnbm9yZURlYWRMaW5rczogdHJ1ZSxcbiAgc2l0ZW1hcDoge1xuICAgIGhvc3RuYW1lOiAnaHR0cHM6Ly9ncmFmZmxlLmpzLm9yZycsXG4gIH0sXG4gIGhlYWQ6IFtcbiAgICAvLyA8c2NyaXB0IGRlZmVyIGRhdGEtZG9tYWluPVwiZ3JhZmZsZS5qcy5vcmdcIiBzcmM9XCJodHRwczovL3BsYXVzaWJsZS5pby9qcy9zY3JpcHQuanNcIj48L3NjcmlwdD5cbiAgICBbJ3NjcmlwdCcsIHtcbiAgICAgIGRlZmVyOiAndHJ1ZScsXG4gICAgICAnZGF0YS1kb21haW4nOiAnZ3JhZmZsZS5qcy5vcmcnLFxuICAgICAgc3JjOiAnaHR0cHM6Ly9wbGF1c2libGUuaW8vanMvc2NyaXB0LmpzJyxcbiAgICB9XSxcbiAgXSxcbiAgbWFya2Rvd246IHtcbiAgICBjb25maWcobWQpIHtcbiAgICAgIG1kLnVzZSh0YWJzTWFya2Rvd25QbHVnaW4pXG4gICAgfSxcbiAgICBjb2RlVHJhbnNmb3JtZXJzOiBbXG4gICAgICAuLi4ocHJvY2Vzcy5lbnYuZGlzYWJsZV90d29zbGFzaCA/IFtdIDogW1xuICAgICAgICB0cmFuc2Zvcm1lclR3b3NsYXNoKHtcbiAgICAgICAgICB0eXBlc0NhY2hlOiBjcmVhdGVGaWxlU3lzdGVtVHlwZXNDYWNoZSh7XG4gICAgICAgICAgICBkaXI6ICcuLy52aXRlcHJlc3MvY2FjaGUvdHlwZXMnLFxuICAgICAgICAgIH0pLFxuICAgICAgICAgIHR3b3NsYXNoT3B0aW9uczoge1xuICAgICAgICAgICAgaGFuZGJvb2tPcHRpb25zOiB7XG4gICAgICAgICAgICAgIC8vIG5vRXJyb3JzOiB0cnVlLFxuICAgICAgICAgICAgICAvLyBub0Vycm9yVmFsaWRhdGlvbjogcHJvY2Vzcy5lbnYuTk9ERV9FTlYgIT09ICdkZXZlbG9wbWVudCcsXG4gICAgICAgICAgICB9LFxuICAgICAgICAgICAgY29tcGlsZXJPcHRpb25zOiB7XG4gICAgICAgICAgICAgIG1vZHVsZVJlc29sdXRpb246IE1vZHVsZVJlc29sdXRpb25LaW5kLkJ1bmRsZXIsXG4gICAgICAgICAgICAgIG1vZHVsZTogTW9kdWxlS2luZC5FU05leHQsXG4gICAgICAgICAgICAgIC8vIG5vRXJyb3JUcnVuY2F0aW9uOiB0cnVlLFxuICAgICAgICAgICAgfSxcbiAgICAgICAgICAgIHNob3VsZEdldEhvdmVySW5mbzogKHgsIGIsIGMpID0+IHtcbiAgICAgICAgICAgICAgY29uc3QgaWdub3JlSWRlbnRpZmllcnMgPSBbJ2NvbnNvbGUnLCAnbG9nJ11cbiAgICAgICAgICAgICAgcmV0dXJuICFpZ25vcmVJZGVudGlmaWVycy5pbmNsdWRlcyh4KVxuICAgICAgICAgICAgfSxcbiAgICAgICAgICB9LFxuICAgICAgICB9KSxcbiAgICAgIF0pIGFzIGFueSxcbiAgICBdLFxuICB9LFxuICBzcmNEaXI6ICcuL2NvbnRlbnQnLFxuICB0aGVtZUNvbmZpZzoge1xuICAgIGZvb3Rlcjoge1xuICAgICAgbWVzc2FnZTogJ1JlbGVhc2VkIHVuZGVyIHRoZSBNSVQgTGljZW5zZS4nLFxuICAgICAgY29weXJpZ2h0OiAnQ29weXJpZ2h0IFx1MDBBOSAyMDI0LXByZXNlbnQgSmFzb24gS3VocnQnLFxuICAgIH0sXG4gICAgLy8gQHNlZSBodHRwczovL2dpdGh1Yi5jb20vdnVlanMvdml0ZXByZXNzL2lzc3Vlcy80MTQxXG4gICAgbG9nbzoge1xuICAgICAgbGlnaHQ6ICcvX2Fzc2V0cy9sb2dvLWRhcmsuc3ZnJyxcbiAgICAgIGRhcms6ICcvX2Fzc2V0cy9sb2dvLWxpZ2h0LnN2ZycsXG4gICAgfSxcbiAgICBzZWFyY2g6IHtcbiAgICAgIHByb3ZpZGVyOiAnbG9jYWwnLFxuICAgIH0sXG4gICAgZG9jRm9vdGVyOiB7XG4gICAgICBuZXh0OiBmYWxzZSxcbiAgICAgIHByZXY6IGZhbHNlLFxuICAgIH0sXG4gICAgYXNpZGU6ICdsZWZ0JyxcbiAgICBuYXY6IFtcbiAgICAgIHsgdGV4dDogJ0d1aWRlcycsIGxpbms6ICcvZ3VpZGVzJyB9LFxuICAgICAgeyB0ZXh0OiAnRXhhbXBsZXMnLCBsaW5rOiAnL2V4YW1wbGVzJyB9LFxuICAgICAgeyB0ZXh0OiAnRXh0ZW5zaW9ucycsIGxpbms6ICcvZXh0ZW5zaW9ucycgfSxcbiAgICBdLFxuICAgIHNpZGViYXI6IHtcbiAgICAgIC4uLnNpZGViYXJzLFxuICAgIH0sXG4gICAgc29jaWFsTGlua3M6IFtcbiAgICAgIHsgaWNvbjogJ2dpdGh1YicsIGxpbms6ICdodHRwczovL2dpdGh1Yi5jb20vZ3JhZmZsZS1qcy9ncmFmZmxlJyB9LFxuICAgIF0sXG4gIH0sXG59KVxuIl0sCiAgIm1hcHBpbmdzIjogIjtBQUF3VyxTQUFTLDJCQUEyQjtBQUM1WSxTQUFTLGtDQUFrQztBQUMzQyxTQUFTLFlBQVksNEJBQTRCO0FBQ2pELFNBQVMsb0JBQW9CO0FBQzdCLFNBQVMsMEJBQTBCO0FBQ25DLFNBQVMsdUJBQXVCO0FBR2hDLElBQU0sZ0JBQWdCO0FBRXRCLElBQU0seUJBQXlCLENBQUMsY0FBNEIsWUFBZ0Q7QUFDMUcsU0FBTyxPQUFPLFlBQVksRUFBRSxRQUFRLGFBQVcsUUFBUSxNQUFNLFFBQVEsT0FBSyxzQkFBc0IsR0FBRyxPQUFPLENBQUMsQ0FBQztBQUM1RyxTQUFPO0FBQ1Q7QUFFQSxJQUFNLHdCQUF3QixDQUFDLGFBQTBCLFlBQWdEO0FBQ3ZHLFVBQVEsV0FBVztBQUNuQixjQUFZLE9BQU8sUUFBUSxPQUFLLHNCQUFzQixHQUFHLE9BQU8sQ0FBQztBQUNuRTtBQUVBLElBQU0sV0FBVyxDQUFDLGlCQUErQjtBQUMvQyxTQUFPLHVCQUF1QixjQUFjLENBQUMsZ0JBQWdCO0FBQzNELGdCQUFZLE9BQU8sWUFBWSxNQUFNLFdBQVcsZUFBZSxFQUFFO0FBQUEsRUFDbkUsQ0FBQztBQUNIO0FBS0EsSUFBTSxXQUFXLFNBQVMsZ0JBQWdCO0FBQUEsRUFDeEM7QUFBQSxJQUNFLGVBQWU7QUFBQSxJQUNmLGFBQWE7QUFBQSxJQUNiLGlCQUFpQjtBQUFBLElBQ2pCLDJCQUEyQjtBQUFBLElBQzNCLHlCQUF5QjtBQUFBLElBQ3pCLHlCQUF5QjtBQUFBLElBQ3pCLGVBQWU7QUFBQSxJQUNmLHFCQUFxQjtBQUFBLElBQ3JCLDZCQUE2QjtBQUFBLEVBQy9CO0FBQUEsRUFDQTtBQUFBLElBQ0UsZUFBZTtBQUFBLElBQ2YscUJBQXFCO0FBQUEsSUFDckIsZUFBZTtBQUFBLElBQ2YsYUFBYTtBQUFBLElBQ2IsaUJBQWlCO0FBQUEsSUFDakIsMkJBQTJCO0FBQUEsSUFDM0IseUJBQXlCO0FBQUEsSUFDekIseUJBQXlCO0FBQUEsSUFDekIsNkJBQTZCO0FBQUEsRUFDL0I7QUFBQSxFQUNBO0FBQUEsSUFDRSxlQUFlO0FBQUEsSUFDZixxQkFBcUI7QUFBQSxJQUNyQixlQUFlO0FBQUEsSUFDZixhQUFhO0FBQUEsSUFDYixpQkFBaUI7QUFBQSxJQUNqQiwyQkFBMkI7QUFBQSxJQUMzQix5QkFBeUI7QUFBQSxJQUN6Qix5QkFBeUI7QUFBQSxJQUN6Qiw2QkFBNkI7QUFBQSxFQUMvQjtBQUNGLENBQUMsQ0FBaUI7QUFFbEIsU0FBUyxZQUFZLEVBQUUsTUFBTSxLQUFLLE9BQUssRUFBRSxTQUFTLE9BQU8sRUFBRyxNQUFPLFFBQVEsRUFBRSxNQUFNLGdCQUFnQixNQUFNLElBQUksQ0FBQztBQUM5RyxTQUFTLFVBQVUsRUFBRSxNQUFNLFFBQVEsRUFBRSxNQUFNLGdCQUFnQixNQUFNLElBQUksQ0FBQztBQUV0RSxJQUFNLFlBQVksU0FBUyxVQUFVLEVBQUUsTUFBTSxPQUFPLE9BQUssQ0FBQyxFQUFFLEtBQUs7QUFFakUsU0FBUyxVQUFVLEVBQUUsUUFBUSxTQUFTLFVBQVUsRUFBRSxNQUFNLE9BQU8sT0FBSyxFQUFFLFNBQVMsRUFBRSxNQUFNLFNBQVMsQ0FBQztBQUNqRyxTQUFTLFVBQVUsRUFBRSxNQUFNLFFBQVEsR0FBRyxTQUFTO0FBRy9DLElBQU8saUJBQVEsYUFBYTtBQUFBLEVBQzFCLFVBQVUsQ0FBQyxTQUFTO0FBQ2xCLFVBQU0sVUFBVSxLQUFLLFdBQVcsZUFBZSxFQUFFO0FBQ2pELFdBQU87QUFBQSxFQUNUO0FBQUEsRUFDQSxPQUFPO0FBQUEsRUFDUCxhQUFhO0FBQUEsRUFDYixXQUFXO0FBQUE7QUFBQSxFQUVYLGlCQUFpQjtBQUFBLEVBQ2pCLFNBQVM7QUFBQSxJQUNQLFVBQVU7QUFBQSxFQUNaO0FBQUEsRUFDQSxNQUFNO0FBQUE7QUFBQSxJQUVKLENBQUMsVUFBVTtBQUFBLE1BQ1QsT0FBTztBQUFBLE1BQ1AsZUFBZTtBQUFBLE1BQ2YsS0FBSztBQUFBLElBQ1AsQ0FBQztBQUFBLEVBQ0g7QUFBQSxFQUNBLFVBQVU7QUFBQSxJQUNSLE9BQU8sSUFBSTtBQUNULFNBQUcsSUFBSSxrQkFBa0I7QUFBQSxJQUMzQjtBQUFBLElBQ0Esa0JBQWtCO0FBQUEsTUFDaEIsR0FBSSxRQUFRLElBQUksbUJBQW1CLENBQUMsSUFBSTtBQUFBLFFBQ3RDLG9CQUFvQjtBQUFBLFVBQ2xCLFlBQVksMkJBQTJCO0FBQUEsWUFDckMsS0FBSztBQUFBLFVBQ1AsQ0FBQztBQUFBLFVBQ0QsaUJBQWlCO0FBQUEsWUFDZixpQkFBaUI7QUFBQTtBQUFBO0FBQUEsWUFHakI7QUFBQSxZQUNBLGlCQUFpQjtBQUFBLGNBQ2Ysa0JBQWtCLHFCQUFxQjtBQUFBLGNBQ3ZDLFFBQVEsV0FBVztBQUFBO0FBQUEsWUFFckI7QUFBQSxZQUNBLG9CQUFvQixDQUFDLEdBQUcsR0FBRyxNQUFNO0FBQy9CLG9CQUFNLG9CQUFvQixDQUFDLFdBQVcsS0FBSztBQUMzQyxxQkFBTyxDQUFDLGtCQUFrQixTQUFTLENBQUM7QUFBQSxZQUN0QztBQUFBLFVBQ0Y7QUFBQSxRQUNGLENBQUM7QUFBQSxNQUNIO0FBQUEsSUFDRjtBQUFBLEVBQ0Y7QUFBQSxFQUNBLFFBQVE7QUFBQSxFQUNSLGFBQWE7QUFBQSxJQUNYLFFBQVE7QUFBQSxNQUNOLFNBQVM7QUFBQSxNQUNULFdBQVc7QUFBQSxJQUNiO0FBQUE7QUFBQSxJQUVBLE1BQU07QUFBQSxNQUNKLE9BQU87QUFBQSxNQUNQLE1BQU07QUFBQSxJQUNSO0FBQUEsSUFDQSxRQUFRO0FBQUEsTUFDTixVQUFVO0FBQUEsSUFDWjtBQUFBLElBQ0EsV0FBVztBQUFBLE1BQ1QsTUFBTTtBQUFBLE1BQ04sTUFBTTtBQUFBLElBQ1I7QUFBQSxJQUNBLE9BQU87QUFBQSxJQUNQLEtBQUs7QUFBQSxNQUNILEVBQUUsTUFBTSxVQUFVLE1BQU0sVUFBVTtBQUFBLE1BQ2xDLEVBQUUsTUFBTSxZQUFZLE1BQU0sWUFBWTtBQUFBLE1BQ3RDLEVBQUUsTUFBTSxjQUFjLE1BQU0sY0FBYztBQUFBLElBQzVDO0FBQUEsSUFDQSxTQUFTO0FBQUEsTUFDUCxHQUFHO0FBQUEsSUFDTDtBQUFBLElBQ0EsYUFBYTtBQUFBLE1BQ1gsRUFBRSxNQUFNLFVBQVUsTUFBTSx3Q0FBd0M7QUFBQSxJQUNsRTtBQUFBLEVBQ0Y7QUFDRixDQUFDOyIsCiAgIm5hbWVzIjogW10KfQo= diff --git a/website/content/_snippets/example-links/selection-sets.md b/website/content/_snippets/example-links/selection-sets.md new file mode 100644 index 000000000..8b80ca4b6 --- /dev/null +++ b/website/content/_snippets/example-links/selection-sets.md @@ -0,0 +1 @@ + diff --git a/website/content/_snippets/examples/extension/opentelemetry.detail.md b/website/content/_snippets/examples/extension/opentelemetry.detail.md index 008f20a8d..ec3b28770 100644 --- a/website/content/_snippets/examples/extension/opentelemetry.detail.md +++ b/website/content/_snippets/examples/extension/opentelemetry.detail.md @@ -43,14 +43,14 @@ console.log(data) } }, instrumentationScope: { name: 'graffle', version: undefined, schemaUrl: undefined }, - traceId: 'e8d5df13d914fbbd4ccbdcfacd957ab0', - parentId: '8e35291fef6405ac', + traceId: '0e52a2a1fb3ccb88d38cd44dded63dec', + parentId: '6fcf4ddd316eb7dd', traceState: undefined, name: 'encode', - id: '57064bac33995f52', + id: 'e30897dc9cb51142', kind: 0, - timestamp: 1734835237807000, - duration: 985.375, + timestamp: 1734877668621000, + duration: 1060.917, attributes: {}, status: { code: 0 }, events: [], @@ -70,14 +70,14 @@ console.log(data) } }, instrumentationScope: { name: 'graffle', version: undefined, schemaUrl: undefined }, - traceId: 'e8d5df13d914fbbd4ccbdcfacd957ab0', - parentId: '8e35291fef6405ac', + traceId: '0e52a2a1fb3ccb88d38cd44dded63dec', + parentId: '6fcf4ddd316eb7dd', traceState: undefined, name: 'pack', - id: '4160ec4bd017e345', + id: '893c1fed7b2256dd', kind: 0, - timestamp: 1734835237808000, - duration: 12389.166, + timestamp: 1734877668623000, + duration: 18450.083, attributes: {}, status: { code: 0 }, events: [], @@ -97,14 +97,14 @@ console.log(data) } }, instrumentationScope: { name: 'graffle', version: undefined, schemaUrl: undefined }, - traceId: 'e8d5df13d914fbbd4ccbdcfacd957ab0', - parentId: '8e35291fef6405ac', + traceId: '0e52a2a1fb3ccb88d38cd44dded63dec', + parentId: '6fcf4ddd316eb7dd', traceState: undefined, name: 'exchange', - id: 'b605384e7351522a', + id: 'b0c30685f178d075', kind: 0, - timestamp: 1734835237821000, - duration: 21988.041, + timestamp: 1734877668642000, + duration: 25750.5, attributes: {}, status: { code: 0 }, events: [], @@ -124,14 +124,14 @@ console.log(data) } }, instrumentationScope: { name: 'graffle', version: undefined, schemaUrl: undefined }, - traceId: 'e8d5df13d914fbbd4ccbdcfacd957ab0', - parentId: '8e35291fef6405ac', + traceId: '0e52a2a1fb3ccb88d38cd44dded63dec', + parentId: '6fcf4ddd316eb7dd', traceState: undefined, name: 'unpack', - id: '3dc693f1496eb20f', + id: 'c148fb01cd7693fa', kind: 0, - timestamp: 1734835237844000, - duration: 1031.333, + timestamp: 1734877668668000, + duration: 1080.291, attributes: {}, status: { code: 0 }, events: [], @@ -151,14 +151,14 @@ console.log(data) } }, instrumentationScope: { name: 'graffle', version: undefined, schemaUrl: undefined }, - traceId: 'e8d5df13d914fbbd4ccbdcfacd957ab0', - parentId: '8e35291fef6405ac', + traceId: '0e52a2a1fb3ccb88d38cd44dded63dec', + parentId: '6fcf4ddd316eb7dd', traceState: undefined, name: 'decode', - id: '41886c6abbbe3566', + id: '634824deddb746e7', kind: 0, - timestamp: 1734835237845000, - duration: 457.25, + timestamp: 1734877668670000, + duration: 516.708, attributes: {}, status: { code: 0 }, events: [], @@ -178,14 +178,14 @@ console.log(data) } }, instrumentationScope: { name: 'graffle', version: undefined, schemaUrl: undefined }, - traceId: 'e8d5df13d914fbbd4ccbdcfacd957ab0', + traceId: '0e52a2a1fb3ccb88d38cd44dded63dec', parentId: undefined, traceState: undefined, name: 'request', - id: '8e35291fef6405ac', + id: '6fcf4ddd316eb7dd', kind: 0, - timestamp: 1734835237806000, - duration: 39409.5, + timestamp: 1734877668621000, + duration: 49549.459, attributes: {}, status: { code: 0 }, events: [], diff --git a/website/content/_snippets/examples/extension/opentelemetry.md b/website/content/_snippets/examples/extension/opentelemetry.md index 9da3ea31d..834df7c2f 100644 --- a/website/content/_snippets/examples/extension/opentelemetry.md +++ b/website/content/_snippets/examples/extension/opentelemetry.md @@ -41,14 +41,14 @@ console.log(data) } }, instrumentationScope: { name: 'graffle', version: undefined, schemaUrl: undefined }, - traceId: 'e8d5df13d914fbbd4ccbdcfacd957ab0', - parentId: '8e35291fef6405ac', + traceId: '0e52a2a1fb3ccb88d38cd44dded63dec', + parentId: '6fcf4ddd316eb7dd', traceState: undefined, name: 'encode', - id: '57064bac33995f52', + id: 'e30897dc9cb51142', kind: 0, - timestamp: 1734835237807000, - duration: 985.375, + timestamp: 1734877668621000, + duration: 1060.917, attributes: {}, status: { code: 0 }, events: [], @@ -68,14 +68,14 @@ console.log(data) } }, instrumentationScope: { name: 'graffle', version: undefined, schemaUrl: undefined }, - traceId: 'e8d5df13d914fbbd4ccbdcfacd957ab0', - parentId: '8e35291fef6405ac', + traceId: '0e52a2a1fb3ccb88d38cd44dded63dec', + parentId: '6fcf4ddd316eb7dd', traceState: undefined, name: 'pack', - id: '4160ec4bd017e345', + id: '893c1fed7b2256dd', kind: 0, - timestamp: 1734835237808000, - duration: 12389.166, + timestamp: 1734877668623000, + duration: 18450.083, attributes: {}, status: { code: 0 }, events: [], @@ -95,14 +95,14 @@ console.log(data) } }, instrumentationScope: { name: 'graffle', version: undefined, schemaUrl: undefined }, - traceId: 'e8d5df13d914fbbd4ccbdcfacd957ab0', - parentId: '8e35291fef6405ac', + traceId: '0e52a2a1fb3ccb88d38cd44dded63dec', + parentId: '6fcf4ddd316eb7dd', traceState: undefined, name: 'exchange', - id: 'b605384e7351522a', + id: 'b0c30685f178d075', kind: 0, - timestamp: 1734835237821000, - duration: 21988.041, + timestamp: 1734877668642000, + duration: 25750.5, attributes: {}, status: { code: 0 }, events: [], @@ -122,14 +122,14 @@ console.log(data) } }, instrumentationScope: { name: 'graffle', version: undefined, schemaUrl: undefined }, - traceId: 'e8d5df13d914fbbd4ccbdcfacd957ab0', - parentId: '8e35291fef6405ac', + traceId: '0e52a2a1fb3ccb88d38cd44dded63dec', + parentId: '6fcf4ddd316eb7dd', traceState: undefined, name: 'unpack', - id: '3dc693f1496eb20f', + id: 'c148fb01cd7693fa', kind: 0, - timestamp: 1734835237844000, - duration: 1031.333, + timestamp: 1734877668668000, + duration: 1080.291, attributes: {}, status: { code: 0 }, events: [], @@ -149,14 +149,14 @@ console.log(data) } }, instrumentationScope: { name: 'graffle', version: undefined, schemaUrl: undefined }, - traceId: 'e8d5df13d914fbbd4ccbdcfacd957ab0', - parentId: '8e35291fef6405ac', + traceId: '0e52a2a1fb3ccb88d38cd44dded63dec', + parentId: '6fcf4ddd316eb7dd', traceState: undefined, name: 'decode', - id: '41886c6abbbe3566', + id: '634824deddb746e7', kind: 0, - timestamp: 1734835237845000, - duration: 457.25, + timestamp: 1734877668670000, + duration: 516.708, attributes: {}, status: { code: 0 }, events: [], @@ -176,14 +176,14 @@ console.log(data) } }, instrumentationScope: { name: 'graffle', version: undefined, schemaUrl: undefined }, - traceId: 'e8d5df13d914fbbd4ccbdcfacd957ab0', + traceId: '0e52a2a1fb3ccb88d38cd44dded63dec', parentId: undefined, traceState: undefined, name: 'request', - id: '8e35291fef6405ac', + id: '6fcf4ddd316eb7dd', kind: 0, - timestamp: 1734835237806000, - duration: 39409.5, + timestamp: 1734877668621000, + duration: 49549.459, attributes: {}, status: { code: 0 }, events: [], diff --git a/website/content/_snippets/examples/output/envelope.detail.md b/website/content/_snippets/examples/output/envelope.detail.md index f5074eecf..413819c8e 100644 --- a/website/content/_snippets/examples/output/envelope.detail.md +++ b/website/content/_snippets/examples/output/envelope.detail.md @@ -44,7 +44,7 @@ console.log(result) headers: Headers { 'content-type': 'application/graphql-response+json; charset=utf-8', 'content-length': '142', - date: 'Sun, 22 Dec 2024 02:40:37 GMT', + date: 'Sun, 22 Dec 2024 14:27:48 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 4f1fe975c..2e05163a5 100644 --- a/website/content/_snippets/examples/output/envelope.md +++ b/website/content/_snippets/examples/output/envelope.md @@ -42,7 +42,7 @@ console.log(result) headers: Headers { 'content-type': 'application/graphql-response+json; charset=utf-8', 'content-length': '142', - date: 'Sun, 22 Dec 2024 02:40:37 GMT', + date: 'Sun, 22 Dec 2024 14:27:48 GMT', connection: 'keep-alive', 'keep-alive': 'timeout=5' }, 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 d968a1d24..45c189ed8 100644 --- a/website/content/_snippets/examples/transport-http/dynamic-headers.detail.md +++ b/website/content/_snippets/examples/transport-http/dynamic-headers.detail.md @@ -46,7 +46,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': '1734835236654' + 'x-sent-at-time': '1734877667965' }, method: 'post', url: 'http://localhost:3000/graphql', diff --git a/website/content/_snippets/examples/transport-http/dynamic-headers.md b/website/content/_snippets/examples/transport-http/dynamic-headers.md index 97b773d14..77cbf4c39 100644 --- a/website/content/_snippets/examples/transport-http/dynamic-headers.md +++ b/website/content/_snippets/examples/transport-http/dynamic-headers.md @@ -44,7 +44,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': '1734835236654' + 'x-sent-at-time': '1734877667965' }, method: 'post', url: 'http://localhost:3000/graphql', diff --git a/website/content/_snippets/examples/type_level/selection-sets.detail.md b/website/content/_snippets/examples/type_level/selection-sets.detail.md new file mode 100644 index 000000000..ed6ba6d8f --- /dev/null +++ b/website/content/_snippets/examples/type_level/selection-sets.detail.md @@ -0,0 +1,145 @@ +::: details Example + +
+Selection Sets + + +```ts twoslash +// Our website uses Vitepress+Twoslash. Twoslash does not discover the generated Graffle modules. +// Perhaps we can configure Twoslash to include them. Until we figure that out, we have to +// explicitly import them like this. +import './graffle/modules/global.js' +// ---cut--- + +import { Graffle } from './graffle/__.js' + +type _ = [ + // + // ======================== + // Primary TypeScript Types + // ======================== + // + // + // 1. GraphQL Types + // -------------- + // The SelectionSets namespace contains a TypeScript type for each GraphQL type. + // + Graffle.SelectionSets.Query, + Graffle.SelectionSets.Mutation, + Graffle.SelectionSets.Battle, + // ... + // + // Each type contains the selection set for that type. + // + Graffle.SelectionSets.Query['pokemons'], + Graffle.SelectionSets.Query['trainers'], + Graffle.SelectionSets.Mutation['addPokemon'], + Graffle.SelectionSets.Battle['___on_BattleRoyale'], + + // 2. GraphQL Type Fields + // ------------------- + // Each name is also overloaded with a namespace. Within it, you will find more TypeScript types. + // One per selection set field in the respective GraphQL type. + // + Graffle.SelectionSets.Query.pokemons, + Graffle.SelectionSets.Query.trainers, + Graffle.SelectionSets.Mutation.addPokemon, + // ... + // + // Each GraphQL type field type has properties about the selection set set for that field. + // + Graffle.SelectionSets.Query.pokemons['$'], + Graffle.SelectionSets.Query.trainers['$skip'], + Graffle.SelectionSets.Mutation.addPokemon['id'], + // ... + // + // You may have already noticed but there is a relationship between these two things: + // - The GraphQL Type type properties + // - The GraphQL Type Field types. + // + // Use the kind of type that suites your use case. + // + Graffle.SelectionSets.Query['pokemons'], + Graffle.SelectionSets.Query.pokemons, + // + // 3. TypeScript Types for Arguments + // ------------------------------ + // There are type definitions for GraphQL Type Field Arguments + // + Graffle.SelectionSets.Query.pokemons$Arguments, + Graffle.SelectionSets.Query.trainerByName$Arguments, + Graffle.SelectionSets.Mutation.addPokemon$Arguments, + // ... + // + // + // ====================== + // Niche TypeScript Types + // ====================== + // + // + // 4. "Expanded" Variants + // ------------------- + // You will find various type definitions with the suffix `$Expanded`. + // From a type-checking point of view they are identical to their non-expanded form. + // They differ in how they will be displayed in tooling, namely IDEs. + // You can leverage them to improve DX in your use-cases. + // For more details, refer to their JSDoc. + // + Graffle.SelectionSets.Query.pokemons$Expanded, + Graffle.SelectionSets.Mutation.addPokemon$Expanded, + // ... + // + // 5. Inline Fragments + // ---------------- + // + Graffle.SelectionSets.Query$FragmentInline, + Graffle.SelectionSets.Battle$FragmentInline, + // ... + // + // 6. Selection Sets Sans Union with Indicators + // ----------------------------------------- + // If the GraphQL field is a non-scalar OR scalar-with-arguments, then its type will be synonymous + // with its explicit selection set type. For example: + // + Graffle.SelectionSets.Query.beings, + Graffle.SelectionSets.Query.beings$SelectionSet, + // However, if the GraphQL field IS a scalar-without-arguments, then its type will become an + // indicator unioned with the "meta" selection set (meaning stuff like field directives). + // + // Meanwhile, the explicit selection set type will _only_ have those meta things, not the + // indicator. For example: + // + Graffle.SelectionSets.Pokemon.name, + Graffle.SelectionSets.Pokemon.name$SelectionSet, +] + +const graffle = Graffle.create() + +const getPokemonsLike = async (filter: Graffle.SelectionSets.Query.pokemons$Arguments['filter']) => + graffle.query.pokemons({ + $: { filter }, + hp: true, + name: true, + }) + +// todo add test coverage for $ stripping on arguments. +const pokemons = await getPokemonsLike({ $type: `water` }) + +// We don't lose any type safety. :) +console.log(pokemons) +``` + + + +```json +[ + { + "hp": 44, + "name": "Squirtle" + } +] +``` + + +
+::: diff --git a/website/content/_snippets/examples/type_level/selection-sets.md b/website/content/_snippets/examples/type_level/selection-sets.md new file mode 100644 index 000000000..d19a5c2e2 --- /dev/null +++ b/website/content/_snippets/examples/type_level/selection-sets.md @@ -0,0 +1,142 @@ +
+Selection Sets + + +```ts twoslash +// Our website uses Vitepress+Twoslash. Twoslash does not discover the generated Graffle modules. +// Perhaps we can configure Twoslash to include them. Until we figure that out, we have to +// explicitly import them like this. +import './graffle/modules/global.js' +// ---cut--- + +import { Graffle } from './graffle/__.js' + +type _ = [ + // + // ======================== + // Primary TypeScript Types + // ======================== + // + // + // 1. GraphQL Types + // -------------- + // The SelectionSets namespace contains a TypeScript type for each GraphQL type. + // + Graffle.SelectionSets.Query, + Graffle.SelectionSets.Mutation, + Graffle.SelectionSets.Battle, + // ... + // + // Each type contains the selection set for that type. + // + Graffle.SelectionSets.Query['pokemons'], + Graffle.SelectionSets.Query['trainers'], + Graffle.SelectionSets.Mutation['addPokemon'], + Graffle.SelectionSets.Battle['___on_BattleRoyale'], + + // 2. GraphQL Type Fields + // ------------------- + // Each name is also overloaded with a namespace. Within it, you will find more TypeScript types. + // One per selection set field in the respective GraphQL type. + // + Graffle.SelectionSets.Query.pokemons, + Graffle.SelectionSets.Query.trainers, + Graffle.SelectionSets.Mutation.addPokemon, + // ... + // + // Each GraphQL type field type has properties about the selection set set for that field. + // + Graffle.SelectionSets.Query.pokemons['$'], + Graffle.SelectionSets.Query.trainers['$skip'], + Graffle.SelectionSets.Mutation.addPokemon['id'], + // ... + // + // You may have already noticed but there is a relationship between these two things: + // - The GraphQL Type type properties + // - The GraphQL Type Field types. + // + // Use the kind of type that suites your use case. + // + Graffle.SelectionSets.Query['pokemons'], + Graffle.SelectionSets.Query.pokemons, + // + // 3. TypeScript Types for Arguments + // ------------------------------ + // There are type definitions for GraphQL Type Field Arguments + // + Graffle.SelectionSets.Query.pokemons$Arguments, + Graffle.SelectionSets.Query.trainerByName$Arguments, + Graffle.SelectionSets.Mutation.addPokemon$Arguments, + // ... + // + // + // ====================== + // Niche TypeScript Types + // ====================== + // + // + // 4. "Expanded" Variants + // ------------------- + // You will find various type definitions with the suffix `$Expanded`. + // From a type-checking point of view they are identical to their non-expanded form. + // They differ in how they will be displayed in tooling, namely IDEs. + // You can leverage them to improve DX in your use-cases. + // For more details, refer to their JSDoc. + // + Graffle.SelectionSets.Query.pokemons$Expanded, + Graffle.SelectionSets.Mutation.addPokemon$Expanded, + // ... + // + // 5. Inline Fragments + // ---------------- + // + Graffle.SelectionSets.Query$FragmentInline, + Graffle.SelectionSets.Battle$FragmentInline, + // ... + // + // 6. Selection Sets Sans Union with Indicators + // ----------------------------------------- + // If the GraphQL field is a non-scalar OR scalar-with-arguments, then its type will be synonymous + // with its explicit selection set type. For example: + // + Graffle.SelectionSets.Query.beings, + Graffle.SelectionSets.Query.beings$SelectionSet, + // However, if the GraphQL field IS a scalar-without-arguments, then its type will become an + // indicator unioned with the "meta" selection set (meaning stuff like field directives). + // + // Meanwhile, the explicit selection set type will _only_ have those meta things, not the + // indicator. For example: + // + Graffle.SelectionSets.Pokemon.name, + Graffle.SelectionSets.Pokemon.name$SelectionSet, +] + +const graffle = Graffle.create() + +const getPokemonsLike = async (filter: Graffle.SelectionSets.Query.pokemons$Arguments['filter']) => + graffle.query.pokemons({ + $: { filter }, + hp: true, + name: true, + }) + +// todo add test coverage for $ stripping on arguments. +const pokemons = await getPokemonsLike({ $type: `water` }) + +// We don't lose any type safety. :) +console.log(pokemons) +``` + + + +```json +[ + { + "hp": 44, + "name": "Squirtle" + } +] +``` + + +
diff --git a/website/content/examples/10_transport-http/dynamic-headers.md b/website/content/examples/10_transport-http/dynamic-headers.md index bfdb6aaf6..2defe7d32 100644 --- a/website/content/examples/10_transport-http/dynamic-headers.md +++ b/website/content/examples/10_transport-http/dynamic-headers.md @@ -51,7 +51,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': '1734835236654' + 'x-sent-at-time': '1734877667965' }, method: 'post', url: 'http://localhost:3000/graphql', diff --git a/website/content/examples/20_output/envelope.md b/website/content/examples/20_output/envelope.md index a210d1a63..73c21f661 100644 --- a/website/content/examples/20_output/envelope.md +++ b/website/content/examples/20_output/envelope.md @@ -49,7 +49,7 @@ console.log(result) headers: Headers { 'content-type': 'application/graphql-response+json; charset=utf-8', 'content-length': '142', - date: 'Sun, 22 Dec 2024 02:40:37 GMT', + date: 'Sun, 22 Dec 2024 14:27:48 GMT', connection: 'keep-alive', 'keep-alive': 'timeout=5' }, diff --git a/website/content/examples/60_extension/opentelemetry.md b/website/content/examples/60_extension/opentelemetry.md index 662a221be..b4ee1a116 100644 --- a/website/content/examples/60_extension/opentelemetry.md +++ b/website/content/examples/60_extension/opentelemetry.md @@ -46,14 +46,14 @@ console.log(data) } }, instrumentationScope: { name: 'graffle', version: undefined, schemaUrl: undefined }, - traceId: 'e8d5df13d914fbbd4ccbdcfacd957ab0', - parentId: '8e35291fef6405ac', + traceId: '0e52a2a1fb3ccb88d38cd44dded63dec', + parentId: '6fcf4ddd316eb7dd', traceState: undefined, name: 'encode', - id: '57064bac33995f52', + id: 'e30897dc9cb51142', kind: 0, - timestamp: 1734835237807000, - duration: 985.375, + timestamp: 1734877668621000, + duration: 1060.917, attributes: {}, status: { code: 0 }, events: [], @@ -73,14 +73,14 @@ console.log(data) } }, instrumentationScope: { name: 'graffle', version: undefined, schemaUrl: undefined }, - traceId: 'e8d5df13d914fbbd4ccbdcfacd957ab0', - parentId: '8e35291fef6405ac', + traceId: '0e52a2a1fb3ccb88d38cd44dded63dec', + parentId: '6fcf4ddd316eb7dd', traceState: undefined, name: 'pack', - id: '4160ec4bd017e345', + id: '893c1fed7b2256dd', kind: 0, - timestamp: 1734835237808000, - duration: 12389.166, + timestamp: 1734877668623000, + duration: 18450.083, attributes: {}, status: { code: 0 }, events: [], @@ -100,14 +100,14 @@ console.log(data) } }, instrumentationScope: { name: 'graffle', version: undefined, schemaUrl: undefined }, - traceId: 'e8d5df13d914fbbd4ccbdcfacd957ab0', - parentId: '8e35291fef6405ac', + traceId: '0e52a2a1fb3ccb88d38cd44dded63dec', + parentId: '6fcf4ddd316eb7dd', traceState: undefined, name: 'exchange', - id: 'b605384e7351522a', + id: 'b0c30685f178d075', kind: 0, - timestamp: 1734835237821000, - duration: 21988.041, + timestamp: 1734877668642000, + duration: 25750.5, attributes: {}, status: { code: 0 }, events: [], @@ -127,14 +127,14 @@ console.log(data) } }, instrumentationScope: { name: 'graffle', version: undefined, schemaUrl: undefined }, - traceId: 'e8d5df13d914fbbd4ccbdcfacd957ab0', - parentId: '8e35291fef6405ac', + traceId: '0e52a2a1fb3ccb88d38cd44dded63dec', + parentId: '6fcf4ddd316eb7dd', traceState: undefined, name: 'unpack', - id: '3dc693f1496eb20f', + id: 'c148fb01cd7693fa', kind: 0, - timestamp: 1734835237844000, - duration: 1031.333, + timestamp: 1734877668668000, + duration: 1080.291, attributes: {}, status: { code: 0 }, events: [], @@ -154,14 +154,14 @@ console.log(data) } }, instrumentationScope: { name: 'graffle', version: undefined, schemaUrl: undefined }, - traceId: 'e8d5df13d914fbbd4ccbdcfacd957ab0', - parentId: '8e35291fef6405ac', + traceId: '0e52a2a1fb3ccb88d38cd44dded63dec', + parentId: '6fcf4ddd316eb7dd', traceState: undefined, name: 'decode', - id: '41886c6abbbe3566', + id: '634824deddb746e7', kind: 0, - timestamp: 1734835237845000, - duration: 457.25, + timestamp: 1734877668670000, + duration: 516.708, attributes: {}, status: { code: 0 }, events: [], @@ -181,14 +181,14 @@ console.log(data) } }, instrumentationScope: { name: 'graffle', version: undefined, schemaUrl: undefined }, - traceId: 'e8d5df13d914fbbd4ccbdcfacd957ab0', + traceId: '0e52a2a1fb3ccb88d38cd44dded63dec', parentId: undefined, traceState: undefined, name: 'request', - id: '8e35291fef6405ac', + id: '6fcf4ddd316eb7dd', kind: 0, - timestamp: 1734835237806000, - duration: 39409.5, + timestamp: 1734877668621000, + duration: 49549.459, attributes: {}, status: { code: 0 }, events: [], diff --git a/website/content/examples/70_type_level/selection-sets.md b/website/content/examples/70_type_level/selection-sets.md new file mode 100644 index 000000000..d7c5f0a84 --- /dev/null +++ b/website/content/examples/70_type_level/selection-sets.md @@ -0,0 +1,147 @@ +--- +aside: false +--- + +# Selection Sets + +This example shows how to work with the selection set types generated by Graffle. Selection set types reflect your GraphQL schema. + + +```ts twoslash +// Our website uses Vitepress+Twoslash. Twoslash does not discover the generated Graffle modules. +// Perhaps we can configure Twoslash to include them. Until we figure that out, we have to +// explicitly import them like this. +import './graffle/modules/global.js' +// ---cut--- + +import { Graffle } from './graffle/__.js' + +type _ = [ + // + // ======================== + // Primary TypeScript Types + // ======================== + // + // + // 1. GraphQL Types + // -------------- + // The SelectionSets namespace contains a TypeScript type for each GraphQL type. + // + Graffle.SelectionSets.Query, + Graffle.SelectionSets.Mutation, + Graffle.SelectionSets.Battle, + // ... + // + // Each type contains the selection set for that type. + // + Graffle.SelectionSets.Query['pokemons'], + Graffle.SelectionSets.Query['trainers'], + Graffle.SelectionSets.Mutation['addPokemon'], + Graffle.SelectionSets.Battle['___on_BattleRoyale'], + + // 2. GraphQL Type Fields + // ------------------- + // Each name is also overloaded with a namespace. Within it, you will find more TypeScript types. + // One per selection set field in the respective GraphQL type. + // + Graffle.SelectionSets.Query.pokemons, + Graffle.SelectionSets.Query.trainers, + Graffle.SelectionSets.Mutation.addPokemon, + // ... + // + // Each GraphQL type field type has properties about the selection set set for that field. + // + Graffle.SelectionSets.Query.pokemons['$'], + Graffle.SelectionSets.Query.trainers['$skip'], + Graffle.SelectionSets.Mutation.addPokemon['id'], + // ... + // + // You may have already noticed but there is a relationship between these two things: + // - The GraphQL Type type properties + // - The GraphQL Type Field types. + // + // Use the kind of type that suites your use case. + // + Graffle.SelectionSets.Query['pokemons'], + Graffle.SelectionSets.Query.pokemons, + // + // 3. TypeScript Types for Arguments + // ------------------------------ + // There are type definitions for GraphQL Type Field Arguments + // + Graffle.SelectionSets.Query.pokemons$Arguments, + Graffle.SelectionSets.Query.trainerByName$Arguments, + Graffle.SelectionSets.Mutation.addPokemon$Arguments, + // ... + // + // + // ====================== + // Niche TypeScript Types + // ====================== + // + // + // 4. "Expanded" Variants + // ------------------- + // You will find various type definitions with the suffix `$Expanded`. + // From a type-checking point of view they are identical to their non-expanded form. + // They differ in how they will be displayed in tooling, namely IDEs. + // You can leverage them to improve DX in your use-cases. + // For more details, refer to their JSDoc. + // + Graffle.SelectionSets.Query.pokemons$Expanded, + Graffle.SelectionSets.Mutation.addPokemon$Expanded, + // ... + // + // 5. Inline Fragments + // ---------------- + // + Graffle.SelectionSets.Query$FragmentInline, + Graffle.SelectionSets.Battle$FragmentInline, + // ... + // + // 6. Selection Sets Sans Union with Indicators + // ----------------------------------------- + // If the GraphQL field is a non-scalar OR scalar-with-arguments, then its type will be synonymous + // with its explicit selection set type. For example: + // + Graffle.SelectionSets.Query.beings, + Graffle.SelectionSets.Query.beings$SelectionSet, + // However, if the GraphQL field IS a scalar-without-arguments, then its type will become an + // indicator unioned with the "meta" selection set (meaning stuff like field directives). + // + // Meanwhile, the explicit selection set type will _only_ have those meta things, not the + // indicator. For example: + // + Graffle.SelectionSets.Pokemon.name, + Graffle.SelectionSets.Pokemon.name$SelectionSet, +] + +const graffle = Graffle.create() + +const getPokemonsLike = async (filter: Graffle.SelectionSets.Query.pokemons$Arguments['filter']) => + graffle.query.pokemons({ + $: { filter }, + hp: true, + name: true, + }) + +// todo add test coverage for $ stripping on arguments. +const pokemons = await getPokemonsLike({ $type: `water` }) + +// We don't lose any type safety. :) +console.log(pokemons) +``` + + +#### Outputs + + +```json +[ + { + "hp": 44, + "name": "Squirtle" + } +] +``` +