diff --git a/src/documentBuilder/InferResult/OutputField.ts b/src/documentBuilder/InferResult/OutputField.ts index 6f856570b..0f9749144 100644 --- a/src/documentBuilder/InferResult/OutputField.ts +++ b/src/documentBuilder/InferResult/OutputField.ts @@ -42,8 +42,8 @@ type GetCodecForCodecless< $Schema extends Schema, $Node extends Schema.Scalar.ScalarCodecless > = - $Node['name'] extends keyof $Schema['scalars']['map'] - ? $Schema['scalars']['map'][$Node['name']] + $Node['name'] extends keyof $Schema['scalarRegistry']['map'] + ? $Schema['scalarRegistry']['map'][$Node['name']] : Schema.Scalar.String // dprint-ignore diff --git a/src/extensions/SchemaErrors/tests/fixture/graffle/modules/schema.ts b/src/extensions/SchemaErrors/tests/fixture/graffle/modules/schema.ts index 2fb50a6b2..a66aca603 100644 --- a/src/extensions/SchemaErrors/tests/fixture/graffle/modules/schema.ts +++ b/src/extensions/SchemaErrors/tests/fixture/graffle/modules/schema.ts @@ -1732,7 +1732,22 @@ export interface Schema<$Scalars extends $$Utilities.Schema.Scalar.Registry = $$ Error: Schema.Error Interface: Schema.Interface } - scalars: $Scalars + scalarNamesUnion: + | 'Date' + | 'Boolean' + | 'Float' + | 'ID' + | 'Int' + | 'String' + scalars: { + Date: Schema.Date + Boolean: Schema.Boolean + Float: Schema.Float + ID: Schema.ID + Int: Schema.Int + String: Schema.String + } + scalarRegistry: $Scalars extensions: { SchemaErrors: { objectNames: 'ErrorOne' | 'ErrorTwo' diff --git a/src/generator/generator/__snapshots__/generate.test.ts.snap b/src/generator/generator/__snapshots__/generate.test.ts.snap index 2deb8706a..56297309a 100644 --- a/src/generator/generator/__snapshots__/generate.test.ts.snap +++ b/src/generator/generator/__snapshots__/generate.test.ts.snap @@ -2893,7 +2893,22 @@ export interface Schema<$Scalars extends $$Utilities.Schema.Scalar.Registry = $$ Error: Schema.Error Interface: Schema.Interface } - scalars: $Scalars + scalarNamesUnion: + | 'Date' + | 'Boolean' + | 'Float' + | 'ID' + | 'Int' + | 'String' + scalars: { + Date: Schema.Date + Boolean: Schema.Boolean + Float: Schema.Float + ID: Schema.ID + Int: Schema.Int + String: Schema.String + } + scalarRegistry: $Scalars extensions: $$Utilities.GlobalRegistry.TypeExtensions } " @@ -7688,7 +7703,13 @@ export interface Schema< objects: {}; unions: {}; interfaces: {}; - scalars: $Scalars; + scalarNamesUnion: "ID" | "Boolean" | "String"; + scalars: { + ID: Schema.ID; + Boolean: Schema.Boolean; + String: Schema.String; + }; + scalarRegistry: $Scalars; extensions: $$Utilities.GlobalRegistry.TypeExtensions; } " diff --git a/src/generator/generators/Schema.ts b/src/generator/generators/Schema.ts index 3807a40c8..34441b5da 100644 --- a/src/generator/generators/Schema.ts +++ b/src/generator/generators/Schema.ts @@ -262,11 +262,15 @@ export const SchemaGenerator = createCodeGenerator( ({ config, code }) => { const kindMap = config.schema.kindMap // dprint-ignore - const root = kindMap.list.Root.map(_ => [_.name, `${identifiers.Schema}.${_.name}`]) - const objects = kindMap.list.OutputObject.map(_ => [_.name, `${identifiers.Schema}.${_.name}`]) - const unions = kindMap.list.Union.map(_ => [_.name, `${identifiers.Schema}.${_.name}`]) - const interfaces = kindMap.list.Interface.map(_ => [_.name, `${identifiers.Schema}.${_.name}`]) - const enums = kindMap.list.Enum.map(_ => [_.name, `${identifiers.Schema}.${_.name}`]) + const root = kindMap.list.Root.map(_ => [_.name, `${identifiers.Schema}.${_.name}`] as const) + const objects = kindMap.list.OutputObject.map(_ => [_.name, `${identifiers.Schema}.${_.name}`] as const) + const unions = kindMap.list.Union.map(_ => [_.name, `${identifiers.Schema}.${_.name}`] as const) + const interfaces = kindMap.list.Interface.map(_ => [_.name, `${identifiers.Schema}.${_.name}`] as const) + const enums = kindMap.list.Enum.map(_ => [_.name, `${identifiers.Schema}.${_.name}`] as const) + const scalars = [ + ...kindMap.list.ScalarCustom.map(_ => [_.name, `${identifiers.Schema}.${_.name}`] as const), + ...kindMap.list.ScalarStandard.map(_ => [_.name, `${identifiers.Schema}.${_.name}`] as const), + ] const operationsAvailable = entries(kindMap.index.Root).filter(_ => _[1] !== null).map(_ => _[0]) const schema: Code.TermObject = { name: `$$Data.Name`, @@ -290,10 +294,12 @@ export const SchemaGenerator = createCodeGenerator( ...unions, ...interfaces, ]), - objects: Object.fromEntries(objects), - unions: Object.fromEntries(unions), - interfaces: Object.fromEntries(interfaces), - scalars: `$Scalars`, + objects, + unions, + interfaces, + scalarNamesUnion: Code.tsUnionItems(scalars.map(_ => _[0]).map(Code.string)), + scalars, + scalarRegistry: `$Scalars`, extensions: `${identifiers.$$Utilities}.GlobalRegistry.TypeExtensions`, } diff --git a/src/layers/6_client/chainExtensions/scalar.test-d.ts b/src/layers/6_client/chainExtensions/scalar.test-d.ts index 892070510..586f832e5 100644 --- a/src/layers/6_client/chainExtensions/scalar.test-d.ts +++ b/src/layers/6_client/chainExtensions/scalar.test-d.ts @@ -1,7 +1,8 @@ +import { DateScalar, FooScalar } from '../../../../tests/_/fixtures/scalars.js' import { schemaMap } from '../../../../tests/_/schemas/kitchen-sink/graffle/__.js' import { Graffle } from '../../../entrypoints/__Graffle.js' import { assertEqual } from '../../../lib/assert-equal.js' -import type { SomeFunction } from '../../../lib/prelude.js' +import { any, type SomeFunction } from '../../../lib/prelude.js' import type { TypeErrorMissingSchemaMap } from './scalar.js' const g1 = Graffle.create({ schema: `foo` }) @@ -9,3 +10,11 @@ assertEqual() const g2 = Graffle.create({ schema: `foo`, schemaMap }) assertEqual() + +// @ts-expect-error "Foo" is not a scalar name in the schema. +Graffle.create({ schema: `foo`, schemaMap }).scalar(`Foo`, any) +// @ts-expect-error "Foo" is not a scalar name in the schema. +Graffle.create({ schema: `foo`, schemaMap }).scalar(FooScalar) +Graffle.create({ schema: `foo`, schemaMap }).scalar(`Date`, any) +Graffle.create({ schema: `foo`, schemaMap }).scalar(DateScalar) +Graffle.create({ schema: `foo`, schemaMap }).scalar(`Int`, any) diff --git a/src/layers/6_client/chainExtensions/scalar.ts b/src/layers/6_client/chainExtensions/scalar.ts index 1fe3448c4..4ca0cb368 100644 --- a/src/layers/6_client/chainExtensions/scalar.ts +++ b/src/layers/6_client/chainExtensions/scalar.ts @@ -1,6 +1,7 @@ import type { Simplify } from 'type-fest' import { Chain } from '../../../lib/chain/__.js' import type { ConfigManager } from '../../../lib/config-manager/__.js' +import type { GlobalRegistry } from '../../../types/GlobalRegistry/GlobalRegistry.js' import { Schema } from '../../../types/Schema/__.js' import { type Context } from '../context.js' @@ -24,11 +25,16 @@ type ScalarMethod<$Args extends Chain.Extension.Parameters> = { /** * TODO Docs. */ - // TODO limit $Name to what is in the schema. - <$Name extends string, $Decoded>(name: $Name, $Codec: { - decode: (value: string) => $Decoded - encode: (value: $Decoded) => string - }): Chain.Definition.MaterializeWithNewContext< + < + $Name extends GlobalRegistry.GetOrGeneric<$Args['context']['name']>['schema']['scalarNamesUnion'], + $Decoded, + >( + name: $Name, + $Codec: { + decode: (value: string) => $Decoded + encode: (value: $Decoded) => string + }, + ): Chain.Definition.MaterializeWithNewContext< $Args['chain'], ConfigManager.SetAtPath< $Args['context'], @@ -42,7 +48,9 @@ type ScalarMethod<$Args extends Chain.Extension.Parameters> = { /* * TODO Docs. */ - <$Scalar extends Schema.Scalar>(scalar: $Scalar): Chain.Definition.MaterializeWithNewContext< + <$Scalar extends Schema.Scalar['schema']['scalarNamesUnion']>>( + scalar: $Scalar, + ): Chain.Definition.MaterializeWithNewContext< $Args['chain'], ConfigManager.SetAtPath< $Args['context'], diff --git a/src/lib/prelude.ts b/src/lib/prelude.ts index 47177d057..c76bd2071 100644 --- a/src/lib/prelude.ts +++ b/src/lib/prelude.ts @@ -636,3 +636,5 @@ export type SimplifyExcept<$ExcludeType, $Type> = : $Type extends $ExcludeType ? $Type : {[TypeKey in keyof $Type]: $Type[TypeKey]} + +export const any = undefined as any diff --git a/src/types/Schema/__.ts b/src/types/Schema/__.ts index e0bfbfb72..70736d592 100644 --- a/src/types/Schema/__.ts +++ b/src/types/Schema/__.ts @@ -6,6 +6,7 @@ import type { Enum } from './nodes/Enum.js' import type { Interface } from './nodes/Interface.js' import type { OutputObject } from './nodes/OutputObject.js' import type { Scalar } from './nodes/Scalar/Scalar.js' +import type { ScalarCodecless } from './nodes/ScalarCodecless.js' import type { Union } from './nodes/Union.js' // import type { Mutation, Query, RootType, Subscription } from './StandardTypes/object.js' @@ -35,9 +36,11 @@ export interface Schema< objects: Record unions: Record interfaces: Record + scalars: Record + scalarNamesUnion: string /** - * A map of scalar definitions. Useful for custom scalars. + * A registry of scalar definitions. Useful for custom scalars. */ - scalars: $Scalars + scalarRegistry: $Scalars extensions: $Extensions } diff --git a/tests/_/fixtures/scalars.ts b/tests/_/fixtures/scalars.ts index 7426e0933..ddc9575c2 100644 --- a/tests/_/fixtures/scalars.ts +++ b/tests/_/fixtures/scalars.ts @@ -4,3 +4,8 @@ export const DateScalar = Graffle.Scalars.create(`Date`, { encode: (value: globalThis.Date) => value.toISOString(), decode: (value: string) => new globalThis.Date(value), }) + +export const FooScalar = Graffle.Scalars.create(`Foo`, { + encode: (value) => String(value), + decode: (value) => value, +}) diff --git a/tests/_/schemas/kitchen-sink/graffle/modules/schema.ts b/tests/_/schemas/kitchen-sink/graffle/modules/schema.ts index de0c1e5c4..d5ce42788 100644 --- a/tests/_/schemas/kitchen-sink/graffle/modules/schema.ts +++ b/tests/_/schemas/kitchen-sink/graffle/modules/schema.ts @@ -1732,6 +1732,21 @@ export interface Schema<$Scalars extends $$Utilities.Schema.Scalar.Registry = $$ Error: Schema.Error Interface: Schema.Interface } - scalars: $Scalars + scalarNamesUnion: + | 'Date' + | 'Boolean' + | 'Float' + | 'ID' + | 'Int' + | 'String' + scalars: { + Date: Schema.Date + Boolean: Schema.Boolean + Float: Schema.Float + ID: Schema.ID + Int: Schema.Int + String: Schema.String + } + scalarRegistry: $Scalars extensions: $$Utilities.GlobalRegistry.TypeExtensions } diff --git a/tests/_/schemas/mutation-only/graffle/modules/schema.ts b/tests/_/schemas/mutation-only/graffle/modules/schema.ts index f69de24e5..cd8e37878 100644 --- a/tests/_/schemas/mutation-only/graffle/modules/schema.ts +++ b/tests/_/schemas/mutation-only/graffle/modules/schema.ts @@ -266,6 +266,19 @@ export interface Schema<$Scalars extends $$Utilities.Schema.Scalar.Registry = $$ objects: {} unions: {} interfaces: {} - scalars: $Scalars + scalarNamesUnion: + | 'Boolean' + | 'Float' + | 'ID' + | 'Int' + | 'String' + scalars: { + Boolean: Schema.Boolean + Float: Schema.Float + ID: Schema.ID + Int: Schema.Int + String: Schema.String + } + scalarRegistry: $Scalars extensions: $$Utilities.GlobalRegistry.TypeExtensions } diff --git a/tests/_/schemas/pokemon/graffle/modules/schema.ts b/tests/_/schemas/pokemon/graffle/modules/schema.ts index f93a82215..4c4cd66ff 100644 --- a/tests/_/schemas/pokemon/graffle/modules/schema.ts +++ b/tests/_/schemas/pokemon/graffle/modules/schema.ts @@ -1088,6 +1088,21 @@ export interface Schema<$Scalars extends $$Utilities.Schema.Scalar.Registry = $$ interfaces: { Being: Schema.Being } - scalars: $Scalars + scalarNamesUnion: + | 'Date' + | 'Boolean' + | 'Float' + | 'ID' + | 'Int' + | 'String' + scalars: { + Date: Schema.Date + Boolean: Schema.Boolean + Float: Schema.Float + ID: Schema.ID + Int: Schema.Int + String: Schema.String + } + scalarRegistry: $Scalars extensions: $$Utilities.GlobalRegistry.TypeExtensions } diff --git a/tests/_/schemas/query-only/graffle/modules/schema.ts b/tests/_/schemas/query-only/graffle/modules/schema.ts index f78380d35..86b4bf0ca 100644 --- a/tests/_/schemas/query-only/graffle/modules/schema.ts +++ b/tests/_/schemas/query-only/graffle/modules/schema.ts @@ -266,6 +266,19 @@ export interface Schema<$Scalars extends $$Utilities.Schema.Scalar.Registry = $$ objects: {} unions: {} interfaces: {} - scalars: $Scalars + scalarNamesUnion: + | 'Boolean' + | 'Float' + | 'ID' + | 'Int' + | 'String' + scalars: { + Boolean: Schema.Boolean + Float: Schema.Float + ID: Schema.ID + Int: Schema.Int + String: Schema.String + } + scalarRegistry: $Scalars extensions: $$Utilities.GlobalRegistry.TypeExtensions } diff --git a/website/graffle/modules/Schema.ts b/website/graffle/modules/Schema.ts index ab2520e95..1b71ae7e1 100644 --- a/website/graffle/modules/Schema.ts +++ b/website/graffle/modules/Schema.ts @@ -1088,6 +1088,21 @@ export interface Schema<$Scalars extends $$Utilities.Schema.Scalar.Registry = $$ interfaces: { Being: Schema.Being; }; - scalars: $Scalars; + scalarNamesUnion: + | "Date" + | "Float" + | "ID" + | "String" + | "Int" + | "Boolean"; + scalars: { + Date: Schema.Date; + Float: Schema.Float; + ID: Schema.ID; + String: Schema.String; + Int: Schema.Int; + Boolean: Schema.Boolean; + }; + scalarRegistry: $Scalars; extensions: $$Utilities.GlobalRegistry.TypeExtensions; }