@znight/graphql 0.0.0-stage → 0.2.0

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 (62) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +1062 -2
  3. package/dist/compiler.d.mts +93 -0
  4. package/dist/compiler.mjs +2832 -0
  5. package/dist/compiler.mjs.map +1 -0
  6. package/dist/index.d.mts +542 -0
  7. package/dist/index.mjs +128 -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-BdBxr5NQ.mjs +3222 -0
  12. package/dist/plugin-BdBxr5NQ.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-CgbV9LjD.d.mts +234 -0
  17. package/package.json +95 -4
  18. package/src/compiler/analyze.ts +608 -0
  19. package/src/compiler/builder.ts +1640 -0
  20. package/src/compiler/constants.ts +74 -0
  21. package/src/compiler/data.ts +73 -0
  22. package/src/compiler/defaults.ts +92 -0
  23. package/src/compiler/discriminators.ts +53 -0
  24. package/src/compiler/docs.ts +55 -0
  25. package/src/compiler/generate.ts +405 -0
  26. package/src/compiler/ids.ts +128 -0
  27. package/src/compiler/index.ts +93 -0
  28. package/src/compiler/locate.ts +44 -0
  29. package/src/compiler/model.ts +122 -0
  30. package/src/compiler/options.ts +54 -0
  31. package/src/compiler/scalars.ts +138 -0
  32. package/src/compiler/sdl-view.ts +59 -0
  33. package/src/context.ts +181 -0
  34. package/src/decisions.ts +169 -0
  35. package/src/decorators.ts +196 -0
  36. package/src/errors.ts +89 -0
  37. package/src/execution.ts +1064 -0
  38. package/src/format.ts +285 -0
  39. package/src/index.ts +84 -0
  40. package/src/limits.ts +177 -0
  41. package/src/loaders.ts +149 -0
  42. package/src/memory-pubsub.ts +133 -0
  43. package/src/metadata.ts +195 -0
  44. package/src/names.ts +47 -0
  45. package/src/options.ts +309 -0
  46. package/src/pipeline.ts +277 -0
  47. package/src/plugin.ts +557 -0
  48. package/src/pubsub.ts +36 -0
  49. package/src/scalars.ts +131 -0
  50. package/src/schema-hash.ts +18 -0
  51. package/src/schema.ts +557 -0
  52. package/src/sdl.ts +515 -0
  53. package/src/testing.ts +454 -0
  54. package/src/tokens.ts +22 -0
  55. package/src/transport/abort.ts +80 -0
  56. package/src/transport/accept.ts +155 -0
  57. package/src/transport/graphiql.ts +106 -0
  58. package/src/transport/http.ts +373 -0
  59. package/src/transport/sse.ts +45 -0
  60. package/src/type-ref.ts +89 -0
  61. package/src/types.ts +190 -0
  62. package/src/validate-args.ts +48 -0
package/src/scalars.ts ADDED
@@ -0,0 +1,131 @@
1
+ /**
2
+ * Scalars of `@znight/graphql` (RFC 0005 §5.7): the built-in `DateTime`, `BigInt` and `JSON`, and
3
+ * the graphql-js 17 scalar built from a user `ScalarDefinition` (`scalar<T>(name, definition)`).
4
+ *
5
+ * Built-in scalars have no description and no `valueToLiteral`, with the `specifiedByURL` of
6
+ * `BUILTIN_SCALARS`, so that graphql-js `printSchema()` prints what `printSdl()` prints (§7.3).
7
+ */
8
+ import type { ConstValueNode } from 'graphql'
9
+ import type { ScalarDefinition } from './types.ts'
10
+
11
+ import { GraphQLScalarType, Kind, valueFromASTUntyped } from 'graphql'
12
+
13
+ import { BUILTIN_SCALARS } from './names.ts'
14
+
15
+ /** RFC 3339 date-time with a mandatory offset (`2026-11-02T10:00:00Z`, `...+01:00`). */
16
+ const DATE_TIME =
17
+ /^(\d{4})-(0[1-9]|1[0-2])-(0[1-9]|[12]\d|3[01])[Tt]([01]\d|2[0-3]):([0-5]\d):([0-5]\d|60)(\.\d+)?([Zz]|[+-]([01]\d|2[0-3]):[0-5]\d)$/
18
+
19
+ /** An integer in decimal notation (`BigInt` on the wire). */
20
+ const DECIMAL_INTEGER = /^-?\d+$/
21
+
22
+ function describe(value: unknown): string {
23
+ if (typeof value === 'string') return JSON.stringify(value)
24
+ if (typeof value === 'bigint') return `${value}n`
25
+ if (value === null || typeof value !== 'object') return String(value)
26
+ return Array.isArray(value) ? 'a list' : 'an object'
27
+ }
28
+
29
+ function parseDateTime(value: unknown): Date {
30
+ if (typeof value === 'string' && DATE_TIME.test(value)) {
31
+ const date = new Date(value)
32
+ if (!Number.isNaN(date.getTime())) return date
33
+ }
34
+ throw new TypeError(`DateTime cannot represent ${describe(value)}: expected an RFC 3339 date-time with an offset`)
35
+ }
36
+
37
+ function serializeDateTime(value: unknown): string {
38
+ if (value instanceof Date) {
39
+ if (Number.isNaN(value.getTime())) throw new TypeError('DateTime cannot represent an invalid Date')
40
+ return value.toISOString()
41
+ }
42
+ if (typeof value === 'string' && DATE_TIME.test(value) && !Number.isNaN(Date.parse(value))) return value
43
+ throw new TypeError(`DateTime cannot represent ${describe(value)}: expected a Date`)
44
+ }
45
+
46
+ function parseBigInt(value: unknown): bigint {
47
+ if (typeof value === 'string' && DECIMAL_INTEGER.test(value)) return BigInt(value)
48
+ if (typeof value === 'number' && Number.isSafeInteger(value)) return BigInt(value)
49
+ throw new TypeError(`BigInt cannot represent ${describe(value)}: expected an integer as a decimal string`)
50
+ }
51
+
52
+ function serializeBigInt(value: unknown): string {
53
+ if (typeof value === 'bigint') return value.toString()
54
+ if (typeof value === 'number' && Number.isSafeInteger(value)) return String(value)
55
+ if (typeof value === 'string' && DECIMAL_INTEGER.test(value)) return value
56
+ throw new TypeError(`BigInt cannot represent ${describe(value)}: expected a bigint`)
57
+ }
58
+
59
+ function identity(value: unknown): unknown {
60
+ return value
61
+ }
62
+
63
+ function specifiedBy(name: string): { specifiedByURL?: string } {
64
+ const url = BUILTIN_SCALARS.get(name)?.specifiedByURL
65
+ return url === undefined ? {} : { specifiedByURL: url }
66
+ }
67
+
68
+ function createBuiltin(name: string): GraphQLScalarType | undefined {
69
+ switch (name) {
70
+ case 'DateTime':
71
+ return new GraphQLScalarType<Date, string>({
72
+ name,
73
+ ...specifiedBy(name),
74
+ coerceOutputValue: serializeDateTime,
75
+ coerceInputValue: parseDateTime,
76
+ coerceInputLiteral: (node: ConstValueNode) => parseDateTime(node.kind === Kind.STRING ? node.value : node),
77
+ })
78
+ case 'BigInt':
79
+ return new GraphQLScalarType<bigint, string>({
80
+ name,
81
+ ...specifiedBy(name),
82
+ coerceOutputValue: serializeBigInt,
83
+ coerceInputValue: parseBigInt,
84
+ coerceInputLiteral: (node: ConstValueNode) =>
85
+ parseBigInt(node.kind === Kind.STRING || node.kind === Kind.INT ? node.value : node),
86
+ })
87
+ case 'JSON':
88
+ return new GraphQLScalarType<unknown, unknown>({
89
+ name,
90
+ ...specifiedBy(name),
91
+ coerceOutputValue: identity,
92
+ coerceInputValue: identity,
93
+ coerceInputLiteral: (node: ConstValueNode) => valueFromASTUntyped(node),
94
+ })
95
+ default:
96
+ return undefined
97
+ }
98
+ }
99
+
100
+ /** Built-in scalars, created on first use and shared by every schema (they hold no state). */
101
+ const builtins = new Map<string, GraphQLScalarType>()
102
+
103
+ /** The built-in scalar `name` (`DateTime`, `BigInt`, `JSON`), `undefined` for another name. */
104
+ export function builtinScalar(name: string): GraphQLScalarType | undefined {
105
+ let scalar = builtins.get(name)
106
+ if (scalar === undefined) {
107
+ scalar = createBuiltin(name)
108
+ if (scalar !== undefined) builtins.set(name, scalar)
109
+ }
110
+ return scalar
111
+ }
112
+
113
+ /**
114
+ * The graphql-js scalar of a {@link ScalarDefinition}: `serialize` → `coerceOutputValue`,
115
+ * `parseValue` → `coerceInputValue`, `parseLiteral` → `coerceInputLiteral` (default: `parseValue`
116
+ * of the literal's JSON value). The definition's methods are called on the definition.
117
+ */
118
+ export function definitionScalar(name: string, definition: ScalarDefinition<unknown>): GraphQLScalarType {
119
+ const parseLiteral = definition.parseLiteral
120
+ return new GraphQLScalarType({
121
+ name,
122
+ ...(definition.description === undefined ? {} : { description: definition.description }),
123
+ ...(definition.specifiedByURL === undefined ? {} : { specifiedByURL: definition.specifiedByURL }),
124
+ coerceOutputValue: (value: unknown) => definition.serialize(value),
125
+ coerceInputValue: (value: unknown) => definition.parseValue(value),
126
+ coerceInputLiteral:
127
+ parseLiteral === undefined
128
+ ? (node: ConstValueNode) => definition.parseValue(valueFromASTUntyped(node))
129
+ : (node: ConstValueNode) => parseLiteral.call(definition, node),
130
+ })
131
+ }
@@ -0,0 +1,18 @@
1
+ /**
2
+ * `schemaHash` of `metadata.extensions.graphql` (RFC 0005 §7.1): the first 16 hexadecimal
3
+ * characters of the SHA-256 of the SDL printed by `printSdl()`.
4
+ *
5
+ * Separate from the import-free `sdl.ts` because it needs `node:crypto`. That is fine on both sides:
6
+ * the compiler extension runs at build time on Node.js or Bun, and the runtime targets Node.js >= 24
7
+ * and Bun >= 1.3, which both provide `node:crypto`. The module reaches nothing else, so the
8
+ * `./compiler` boundaries hold (tests/boundaries.test.ts).
9
+ */
10
+ import { createHash } from 'node:crypto'
11
+
12
+ /** Length of a schema hash, in hexadecimal characters. */
13
+ export const SCHEMA_HASH_LENGTH = 16
14
+
15
+ /** First 16 hexadecimal characters of the SHA-256 of `sdl` (UTF-8). */
16
+ export function schemaHash(sdl: string): string {
17
+ return createHash('sha256').update(sdl, 'utf8').digest('hex').slice(0, SCHEMA_HASH_LENGTH)
18
+ }