@znight/graphql 0.0.0 → 0.2.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (69) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +1346 -0
  3. package/dist/compiler.d.mts +114 -0
  4. package/dist/compiler.mjs +4599 -0
  5. package/dist/compiler.mjs.map +1 -0
  6. package/dist/index.d.mts +583 -0
  7. package/dist/index.mjs +134 -0
  8. package/dist/index.mjs.map +1 -0
  9. package/dist/names-BlzDM5cF.mjs +111 -0
  10. package/dist/names-BlzDM5cF.mjs.map +1 -0
  11. package/dist/plugin-CR_wVfRU.mjs +3445 -0
  12. package/dist/plugin-CR_wVfRU.mjs.map +1 -0
  13. package/dist/testing.d.mts +101 -0
  14. package/dist/testing.mjs +306 -0
  15. package/dist/testing.mjs.map +1 -0
  16. package/dist/types-DQ713UgI.d.mts +266 -0
  17. package/package.json +97 -1
  18. package/src/compiler/analyze.ts +727 -0
  19. package/src/compiler/builder.ts +1561 -0
  20. package/src/compiler/checks.ts +105 -0
  21. package/src/compiler/conformance.ts +1068 -0
  22. package/src/compiler/constants.ts +80 -0
  23. package/src/compiler/data.ts +83 -0
  24. package/src/compiler/defaults.ts +92 -0
  25. package/src/compiler/discriminators.ts +53 -0
  26. package/src/compiler/docs.ts +55 -0
  27. package/src/compiler/generate.ts +419 -0
  28. package/src/compiler/graphql-js.ts +42 -0
  29. package/src/compiler/ids.ts +128 -0
  30. package/src/compiler/index.ts +98 -0
  31. package/src/compiler/locate.ts +82 -0
  32. package/src/compiler/model.ts +137 -0
  33. package/src/compiler/options.ts +85 -0
  34. package/src/compiler/scalars.ts +138 -0
  35. package/src/compiler/schema-first.ts +595 -0
  36. package/src/compiler/sdl-source.ts +529 -0
  37. package/src/compiler/sdl-view.ts +61 -0
  38. package/src/compiler/suggest.ts +39 -0
  39. package/src/context.ts +181 -0
  40. package/src/decisions.ts +169 -0
  41. package/src/decorators.ts +202 -0
  42. package/src/errors.ts +89 -0
  43. package/src/execution.ts +1064 -0
  44. package/src/format.ts +285 -0
  45. package/src/index.ts +89 -0
  46. package/src/limits.ts +177 -0
  47. package/src/loaders.ts +149 -0
  48. package/src/memory-pubsub.ts +133 -0
  49. package/src/metadata.ts +222 -0
  50. package/src/names.ts +47 -0
  51. package/src/options.ts +331 -0
  52. package/src/pipeline.ts +338 -0
  53. package/src/plugin.ts +579 -0
  54. package/src/pubsub.ts +36 -0
  55. package/src/results.ts +206 -0
  56. package/src/scalars.ts +138 -0
  57. package/src/schema-hash.ts +18 -0
  58. package/src/schema.ts +635 -0
  59. package/src/sdl.ts +530 -0
  60. package/src/testing.ts +454 -0
  61. package/src/tokens.ts +22 -0
  62. package/src/transport/abort.ts +80 -0
  63. package/src/transport/accept.ts +155 -0
  64. package/src/transport/graphiql.ts +106 -0
  65. package/src/transport/http.ts +373 -0
  66. package/src/transport/sse.ts +45 -0
  67. package/src/type-ref.ts +89 -0
  68. package/src/types.ts +225 -0
  69. package/src/validate-args.ts +48 -0
@@ -0,0 +1,105 @@
1
+ /**
2
+ * Checks shared by the code-first schema builder (`builder.ts`) and the schema-first one
3
+ * (`schema-first.ts`): loader providers (ZNIGHT065) and the route decisions of root fields
4
+ * (ZNIGHT023, RFC 0001).
5
+ */
6
+ import type { ClassInfo, Diagnostic, Location, ValidateContext } from '@znight/compiler'
7
+ import type { MetaEntry } from '@znight/http/compiler'
8
+ import type { GraphQLData, ResolverData } from './data.ts'
9
+
10
+ import { requiredRouteGroups } from '@znight/http/compiler'
11
+
12
+ import { ROOT_TYPE_NAMES } from '../names.ts'
13
+ import { Codes } from './constants.ts'
14
+ import { GraphQLIds } from './ids.ts'
15
+
16
+ type Context = ValidateContext<GraphQLData>
17
+ type Report = (diagnostic: Diagnostic) => void
18
+
19
+ /** `Loader<L>`: `L` must be a loader provider, implementing `BatchLoad<K, V>` (ZNIGHT065). */
20
+ export function checkLoaders(ctx: Context, resolvers: readonly ResolverData[], report: Report): void {
21
+ const seen = new Set<number>()
22
+ for (const resolver of resolvers) {
23
+ for (const field of resolver.fields) {
24
+ for (const param of field.params) {
25
+ if (param?.kind !== 'loader' || seen.has(param.binding.id)) continue
26
+ seen.add(param.binding.id)
27
+ const ref = ctx.binding(param.binding)
28
+ const token = tokenOfRef(ref)
29
+ const provider = token === undefined ? undefined : ctx.provider(token)
30
+ // an unbound loader is ZNIGHT001 (reported by the binding)
31
+ if (provider === undefined || provider.heritage.some(type => type.identity === GraphQLIds.BatchLoad)) continue
32
+ if (provider.kind !== 'class' || hasLoadMethod(ctx, provider.classIdentity)) continue
33
+ report({
34
+ code: Codes.InvalidLoader,
35
+ severity: 'error',
36
+ message: `${provider.displayName} is not a loader: Loader<${provider.displayName}> needs a provider implementing BatchLoad<K, V> (${resolver.host.displayName}.${field.method})`,
37
+ location: param.location,
38
+ hints: [
39
+ `export class ${provider.displayName} implements BatchLoad<ID, Value> { async load(keys: readonly ID[]): Promise<readonly (Value | Error)[]> { ... } }`,
40
+ ],
41
+ })
42
+ }
43
+ }
44
+ }
45
+ }
46
+
47
+ /**
48
+ * RFC 0001: every root field decides every required route decorator group (ZNIGHT023). `roots`
49
+ * names the root types (`schema { query: RootQuery }` in schema-first).
50
+ */
51
+ export function checkDecisions(
52
+ ctx: Context,
53
+ resolvers: readonly ResolverData[],
54
+ report: Report,
55
+ roots: { readonly query: string; readonly mutation?: string; readonly subscription?: string } = ROOT_TYPE_NAMES,
56
+ ): void {
57
+ const applied: MetaEntry[] = []
58
+ for (const resolver of resolvers) for (const field of resolver.fields) applied.push(...field.meta)
59
+ const required = requiredRouteGroups(ctx, applied)
60
+ if (required.length === 0) return
61
+ for (const resolver of resolvers) {
62
+ for (const field of resolver.fields) {
63
+ if (field.operation === 'field') continue
64
+ const decided = new Set(field.meta.map(entry => entry.group))
65
+ for (const group of required) {
66
+ if (decided.has(group.group)) continue
67
+ const root = roots[field.operation] ?? ROOT_TYPE_NAMES[field.operation]
68
+ report({
69
+ code: Codes.MissingRouteDecision,
70
+ severity: 'error',
71
+ message: `Root field ${root}.${field.name} (${resolver.host.displayName}.${field.method}) has no "${group.group}" decision`,
72
+ location: field.methodLocation,
73
+ hints: [`Add ${group.suggestion} to the method or to ${resolver.host.displayName}`],
74
+ related: [
75
+ {
76
+ message: `The "${group.group}" group is required`,
77
+ location: (group.decorators[0] as { definition: Location }).definition,
78
+ },
79
+ ],
80
+ })
81
+ }
82
+ }
83
+ }
84
+ }
85
+
86
+ /** The class (or one of its base classes) declares an instance `load` method. */
87
+ function hasLoadMethod(ctx: Context, identity: string): boolean {
88
+ const seen = new Set<string>()
89
+ let current: string | undefined = identity
90
+ while (current !== undefined && !seen.has(current)) {
91
+ seen.add(current)
92
+ const cls: ClassInfo | undefined = ctx.classInfo(current)
93
+ if (cls === undefined) return true // not analysable (a compiled class): trust the type checker
94
+ if (cls.methods.some(method => method.name === 'load' && method.kind === 'method' && !method.static)) return true
95
+ if (cls.properties.some(property => property.name === 'load' && !property.static)) return true
96
+ current = cls.superClass?.identity
97
+ }
98
+ return false
99
+ }
100
+
101
+ /** The token of a binding result (`undefined` when binding failed). */
102
+ function tokenOfRef(ref: ReturnType<Context['binding']>): string | undefined {
103
+ if (typeof ref === 'string') return ref
104
+ return ref !== undefined && 'token' in ref ? ref.token : undefined
105
+ }