@nxgt/graphql-codegen-zod 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 (43) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +232 -2
  3. package/dist/collect-fields.d.ts +24 -0
  4. package/dist/collect-fields.d.ts.map +1 -0
  5. package/dist/config.d.ts +53 -0
  6. package/dist/config.d.ts.map +1 -0
  7. package/dist/cycles.d.ts +16 -0
  8. package/dist/cycles.d.ts.map +1 -0
  9. package/dist/defaults.d.ts +21 -0
  10. package/dist/defaults.d.ts.map +1 -0
  11. package/dist/imports.d.ts +14 -0
  12. package/dist/imports.d.ts.map +1 -0
  13. package/dist/index.d.ts +14 -0
  14. package/dist/index.d.ts.map +1 -0
  15. package/dist/index.js +1114 -0
  16. package/dist/index.js.map +25 -0
  17. package/dist/naming.d.ts +24 -0
  18. package/dist/naming.d.ts.map +1 -0
  19. package/dist/objects-output.d.ts +16 -0
  20. package/dist/objects-output.d.ts.map +1 -0
  21. package/dist/output-types.d.ts +15 -0
  22. package/dist/output-types.d.ts.map +1 -0
  23. package/dist/results-output.d.ts +16 -0
  24. package/dist/results-output.d.ts.map +1 -0
  25. package/dist/results-selections.d.ts +21 -0
  26. package/dist/results-selections.d.ts.map +1 -0
  27. package/dist/scalars.d.ts +21 -0
  28. package/dist/scalars.d.ts.map +1 -0
  29. package/dist/schema-output.d.ts +10 -0
  30. package/dist/schema-output.d.ts.map +1 -0
  31. package/dist/source.d.ts +9 -0
  32. package/dist/source.d.ts.map +1 -0
  33. package/dist/type-code.d.ts +12 -0
  34. package/dist/type-code.d.ts.map +1 -0
  35. package/dist/variables-output.d.ts +13 -0
  36. package/dist/variables-output.d.ts.map +1 -0
  37. package/dist/writer.d.ts +36 -0
  38. package/dist/writer.d.ts.map +1 -0
  39. package/docs/README.md +14 -0
  40. package/docs/guide/output.md +732 -0
  41. package/docs/roadmap.md +38 -0
  42. package/docs/troubleshooting.md +267 -0
  43. package/package.json +62 -5
@@ -0,0 +1,38 @@
1
+ # Roadmap
2
+
3
+ What `@nxgt/graphql-codegen-zod` is heading for, phrased as what you get.
4
+
5
+ ## Now
6
+
7
+ - **Output types.** Zod schemas and types for the SDL's object types,
8
+ interfaces and unions, and for each named operation's result and each
9
+ fragment, with `__typename` discriminating abstract types. Both parts are
10
+ written; they ship with the next release.
11
+
12
+ ## Next
13
+
14
+ Candidates, not commitments.
15
+
16
+ - **Emit only some parts**, an option to write just the arguments, or just
17
+ the variables, of a file.
18
+ - **Your own formats**, once `@nxgt/graphql-validation` supports custom
19
+ `@constraint(format: "...")` values; the plugin will carry them.
20
+
21
+ ## Later
22
+
23
+ Nothing yet.
24
+
25
+ ## Not planned
26
+
27
+ - **An `Int` for an `ID` on the client.** An id is a string in what the
28
+ client sends, as in what the resolver receives.
29
+
30
+ - **Zod 3.** The schemas use Zod 4's getters, `prefault`, `z.strictObject` and
31
+ `z.email()`; they have no Zod 3 form.
32
+
33
+ ## Shipped
34
+
35
+ - **The first release, 0.1.0.** Zod 4 schemas and types for enums, input
36
+ types, field arguments and operation variables, carrying every
37
+ `@constraint` of `@nxgt/graphql-validation`, so the client refuses what the
38
+ server refuses.
@@ -0,0 +1,267 @@
1
+ # Troubleshooting
2
+
3
+ One entry per error you can hit, headed by the message you will search for.
4
+ Configuration, Scalars, Operations and The schema happen while
5
+ `graphql-codegen` runs; The generated file is what `tsc` and the generated
6
+ schemas report.
7
+
8
+ - [Configuration](#configuration)
9
+ - [Scalars](#scalars)
10
+ - [Operations](#operations)
11
+ - [The generated file](#the-generated-file)
12
+ - [The schema](#the-schema)
13
+
14
+ ## Configuration
15
+
16
+ ### `@nxgt/graphql-codegen-zod: namingConvention "my-module#myCase" is not one this plugin reads. Use 'keep', a function, or 'change-case-all#<case>' with one of camelCase, capitalCase, constantCase, dotCase, headerCase, noCase, paramCase, pascalCase, pathCase, sentenceCase, snakeCase, lowerCase, upperCase, lowerCaseFirst, upperCaseFirst.`
17
+
18
+ **When:** running codegen with a `namingConvention` string that names another module, or a case not in the list. The string in the message is what you wrote.
19
+ **Why:** the plugin reads the forms the typescript plugins take for type names, but only `change-case-all` and `change-case` cases; it does not load a module.
20
+ **Fix:** use one of the forms, or pass a function.
21
+
22
+ ```ts
23
+ config: { namingConvention: 'change-case-all#pascalCase' }
24
+ // or
25
+ config: { namingConvention: (name) => name.toUpperCase() }
26
+ ```
27
+
28
+ ## Scalars
29
+
30
+ ### `@nxgt/graphql-codegen-zod: the scalar Money is not in zodScalars, and no scalarSchemas is set. Map it: zodScalars: { Money: './module#export' }, or set scalarSchemas: '@nxgt/graphql-scalars'.`
31
+
32
+ **When:** running codegen on a schema with a custom scalar (here `Money`),
33
+ on an input or, since 0.2.0, on an object type's field or in an operation's
34
+ result only (`createdAt: Money`). 0.1.0 did not read output fields, so such a
35
+ scalar used to need no schema.
36
+ **Why:** a scalar written as `z.unknown()` would check nothing, in silence, so
37
+ the plugin refuses instead.
38
+ **Fix:** map the scalar, or point `scalarSchemas` at a module that has it. If
39
+ the scalar is only on output fields and in operations' results, and you do not
40
+ need those types, `objects: false` and `operations: false` together skip them:
41
+ either alone still reads it, wherever an operation selects the scalar.
42
+
43
+ ```ts
44
+ config: { zodScalars: { Money: './money#moneySchema' } }
45
+ ```
46
+
47
+ ### `@nxgt/graphql-codegen-zod: the scalar Money is neither in zodScalars nor in @nxgt/graphql-scalars's scalarSchemas. Map it: zodScalars: { Money: './module#export' }, or set scalarSchemas: '@nxgt/graphql-scalars'.`
48
+
49
+ **When:** running codegen with `scalarSchemas` set, on a scalar the record has
50
+ no key for. The module path in the message is the one you configured.
51
+ **Why:** the plugin loaded the record and `Money` is not one of its keys.
52
+ **Fix:** map that one scalar next to the record; `zodScalars` wins over it.
53
+
54
+ ```ts
55
+ config: {
56
+ scalarSchemas: '@nxgt/graphql-scalars',
57
+ zodScalars: { Money: './money#moneySchema' },
58
+ }
59
+ ```
60
+
61
+ ### `@nxgt/graphql-codegen-zod: zodScalars.Money is "moneySchema"; write it '<module>#<export>', e.g. './money#moneySchema'.`
62
+
63
+ **When:** running codegen with a `zodScalars` entry that is not `module#export`.
64
+ **Why:** the entry needs a module and an export name on either side of the
65
+ last `#`; the one in the message has none, or an empty side.
66
+ **Fix:**
67
+
68
+ ```ts
69
+ config: { zodScalars: { Money: './money#moneySchema' } }
70
+ ```
71
+
72
+ ### `@nxgt/graphql-codegen-zod: @nxgt/graphql-scalars exports no scalarSchemas record.`
73
+
74
+ **When:** running codegen with `scalarSchemas` set.
75
+ **Why:** the module loaded, but exports no `scalarSchemas` object. The module
76
+ path in the message is the one you configured. For `@nxgt/graphql-scalars`,
77
+ the record is exported from 0.4.0; an older version has none.
78
+ **Fix:** upgrade the package, or export the record yourself.
79
+
80
+ ```ts
81
+ // scalars.ts
82
+ import { z } from 'zod';
83
+
84
+ export const scalarSchemas = {
85
+ DateTime: z.iso.datetime({ offset: true }),
86
+ };
87
+ ```
88
+
89
+ ## Operations
90
+
91
+ ### `@nxgt/graphql-codegen-zod: SignUp's $input has a type the schema does not define.`
92
+
93
+ **When:** running codegen on a document.
94
+ **Why:** the operation (`SignUp`) declares a variable (`$input`) of a type the
95
+ schema has no input type for, usually a typo, or a document written against
96
+ another schema.
97
+ **Fix:** declare the type in the schema, or correct the variable's type in the
98
+ document.
99
+
100
+ ```graphql
101
+ mutation SignUp($input: SignUpInput!) { signUp(input: $input) }
102
+ ```
103
+
104
+ ### `@nxgt/graphql-codegen-zod: Bare.search selects the abstract type SearchResult without __typename for User. Select __typename there, so the result tells its members apart.`
105
+
106
+ **When:** running codegen on a named operation or a fragment. The operation
107
+ (or `fragment <Name>`), the path, the type and the member in the message are
108
+ yours.
109
+ **Why:** when the possible types of an interface or a union select different
110
+ fields, the selection becomes a union discriminated on `__typename`, and
111
+ without it the result cannot tell the members apart. When they all select the
112
+ same fields, no `__typename` is needed. A `__typename` under `@skip` or
113
+ `@include` may be absent, so it counts as missing.
114
+ **Fix:** select `__typename` in that selection, or set `operations: false`.
115
+
116
+ ```graphql
117
+ # fails
118
+ query Bare { search(text: "a") { ... on User { id } } }
119
+ # generates
120
+ query Bare { search(text: "a") { __typename ... on User { id } } }
121
+ ```
122
+
123
+ ### `@nxgt/graphql-codegen-zod: Keys.search selects __typename under a different key for each member of SearchResult (t, k). Select it under one key for every member, so the result tells its members apart.`
124
+
125
+ **When:** running codegen on an operation or a fragment. The path, the type
126
+ and the keys in the message are yours.
127
+ **Why:** the union is discriminated on one key, and the members select
128
+ `__typename` under different aliases. When several keys select it,
129
+ `__typename` itself is preferred.
130
+ **Fix:** select `__typename` under one key for every member.
131
+
132
+ ```graphql
133
+ query Keys { search(text: "a") { ... on User { t: __typename id } ... on Post { k: __typename title } } }
134
+ ```
135
+
136
+ ### `@nxgt/graphql-codegen-zod: Both($v:) is passed to Query.e(v:) (format: "email") and to Query.u(v:) (format: "uuid"), whose schemas cannot both apply. Use one variable for each.`
137
+
138
+ **When:** running codegen on an operation that passes one variable to two
139
+ places whose `@constraint(format:)` differ. The operation, variable and places
140
+ in the message are yours.
141
+ **Why:** each `format` replaces the schema, so the variable cannot be both.
142
+ **Fix:** use one variable for each.
143
+
144
+ ```graphql
145
+ query Both($e: String, $u: String) { e(v: $e) u(v: $u) }
146
+ ```
147
+
148
+ ## The generated file
149
+
150
+ ### `Property 'Money' does not exist on type '{ DateTime: ... }'` (or `TS2339`)
151
+
152
+ **When:** type-checking the generated file, with `scalarSchemas` set.
153
+ **Why:** the plugin loads the record's module to check its keys, but cannot
154
+ when it is a `.ts` file under Node. It then trusts the record, and the file
155
+ reads `scalarSchemas.Money` which the record lacks.
156
+ **Fix:** add the key to the record, or map the scalar with `zodScalars`, or run
157
+ codegen under Bun so the module loads and the plugin refuses with the message
158
+ above.
159
+
160
+ ```ts
161
+ config: { zodScalars: { Money: './money#moneySchema' } }
162
+ ```
163
+
164
+ ### `TS2300: Duplicate identifier 'SignUpInput'`
165
+
166
+ **When:** type-checking, with the plugin and `@graphql-codegen/typescript`
167
+ writing to the same file.
168
+ **Why:** both write a type of the same name.
169
+ **Fix:** generate into a file of its own.
170
+
171
+ ```ts
172
+ generates: {
173
+ 'src/generated/zod.ts': { plugins: ['@nxgt/graphql-codegen-zod'] },
174
+ }
175
+ ```
176
+
177
+ ### A client request is refused for `{ id: 5 }`: `Invalid input: expected string, received number`
178
+
179
+ **When:** `safeParse` of a variables schema with a number where the schema has
180
+ an `ID`.
181
+ **Why:** `graphql` accepts an `Int` for an `ID`; the generated schema is
182
+ `z.string()`: an id is a string in what the client sends, as in what the
183
+ resolver receives.
184
+ **Fix:** send the id as a string.
185
+
186
+ ```ts
187
+ zUserQueryVariables.safeParse({ id: String(id) });
188
+ ```
189
+
190
+ ### A client request is refused: `Unrecognized key: "nickname"`
191
+
192
+ **When:** `safeParse` of a variables schema whose input object carries a field
193
+ the input type does not declare.
194
+ **Why:** input types are `z.strictObject`, as `graphql` refuses an unknown
195
+ field. The variables object itself ignores an extra variable, as `graphql` does.
196
+ **Fix:** remove the field, or add it to the input type in the schema.
197
+
198
+ ## The schema
199
+
200
+ ### `@nxgt/graphql-codegen-zod: the file would declare FilterInput twice: two GraphQL names, or a type in a cycle and its Input or Wire type, give the same name. Rename one of the GraphQL types or operations, set typesSuffix, or set objects: false or operations: false.`
201
+
202
+ **When:** running codegen on a schema where two declarations of the same kind
203
+ get one name:
204
+ - an input type in a cycle (`Filter`) declares `FilterInput`, or an object
205
+ type in a cycle (`User`) declares `UserWire`, and the schema also has a
206
+ type of that name;
207
+ - an object type is named like a type the plugin already writes, such as
208
+ `QueryFindArgs` beside a field `Query.find(...)`. With 0.1.0 this generated,
209
+ because object types were not written.
210
+
211
+ **Why:** the file cannot declare one name twice.
212
+ **Fix:** rename one of the GraphQL types, or set `typesSuffix`: `Filter`
213
+ then declares `FilterTInput`, apart from `FilterInputT`. A `typesPrefix`
214
+ does not part them. When the clash comes from an object type and you do not
215
+ need the output types, `objects: false` writes none of them. When it comes
216
+ from an operation's or a fragment's result (`SearchQuery`), `operations:
217
+ false` writes none of them.
218
+
219
+ ```graphql
220
+ input Filter { and: [Filter] }
221
+ input FilterFields { a: Int } # was FilterInput
222
+ ```
223
+
224
+ ### `@nxgt/graphql-codegen-zod: the default of Query.a(n:) holds 9007199254740993, which a JavaScript number cannot keep exact. Write it as a string, if its scalar takes one.`
225
+
226
+ **When:** running codegen on an argument, input field or variable whose
227
+ default is an integer past `Number.MAX_SAFE_INTEGER`, given to an `ID` or a
228
+ custom scalar (`Long`, `BigInt`). An `Int` or a `Float` rounds on the server
229
+ too, and is written as it is.
230
+ **Why:** the generated `.prefault(...)` would hold a rounded number, while the
231
+ server hands the scalar every digit.
232
+ **Fix:** write the default as a string, when the scalar parses one.
233
+
234
+ ```graphql
235
+ type Query { a(n: Long = "9007199254740993"): Int }
236
+ ```
237
+
238
+ ### `@nxgt/graphql-codegen-zod: the schema declares @constraint, but Query has no SDL to read it from (an introspected schema?). Point codegen's schema at the SDL files.`
239
+
240
+ **When:** running codegen on a schema that declares `@constraint` but was
241
+ introspected or loaded from a URL. The type in the message is the first found.
242
+ **Why:** an introspected schema carries no directives on its arguments, so
243
+ every constraint would be dropped in silence.
244
+ **Fix:** point codegen's `schema` at the SDL files. A schema without
245
+ `@constraint` can still be introspected; its defaults are read back.
246
+
247
+ ```ts
248
+ schema: 'src/schema/**/*.graphql',
249
+ ```
250
+
251
+ ### Errors of `@constraint`
252
+
253
+ The plugin refuses a schema `withValidation` would refuse, with the same
254
+ message, for example `@constraint(minLength) on Query.a(n:) needs a String or
255
+ an ID, not Int.`. Each is explained, with its fix, in
256
+ [`@nxgt/graphql-validation`'s troubleshooting](https://github.com/softistx/nxgt-graphql/blob/develop/packages/graphql-validation/docs/troubleshooting.md).
257
+
258
+ ### No error, and nothing is constrained
259
+
260
+ **When:** the generated schemas have no `.min()`, `.email()` and the like.
261
+ **Why:** the schema codegen reads does not declare `@constraint`, so the
262
+ plugin reads none; plain types are still generated, without a warning.
263
+ **Fix:** add the directive to the schema codegen loads.
264
+
265
+ ```ts
266
+ import { constraintTypeDefs } from '@nxgt/graphql-validation';
267
+ ```
package/package.json CHANGED
@@ -1,6 +1,63 @@
1
1
  {
2
- "name": "@nxgt/graphql-codegen-zod",
3
- "version": "0.0.0-stage",
4
- "stub": true,
5
- "description": "Temporary package placeholder for staged publishing"
6
- }
2
+ "name": "@nxgt/graphql-codegen-zod",
3
+ "version": "0.2.0",
4
+ "description": "A graphql-codegen plugin that writes Zod schemas from your SDL — inputs, enums, field arguments, operation variables, operation results and output types — with the @constraint rules of @nxgt/graphql-validation",
5
+ "license": "MIT",
6
+ "type": "module",
7
+ "main": "./dist/index.js",
8
+ "types": "./dist/index.d.ts",
9
+ "files": [
10
+ "dist",
11
+ "docs",
12
+ "README.md",
13
+ "package.json",
14
+ "LICENSE"
15
+ ],
16
+ "exports": {
17
+ ".": {
18
+ "types": "./dist/index.d.ts",
19
+ "import": "./dist/index.js",
20
+ "default": "./dist/index.js"
21
+ },
22
+ "./package.json": "./package.json"
23
+ },
24
+ "keywords": [
25
+ "graphql",
26
+ "codegen",
27
+ "graphql-codegen",
28
+ "zod",
29
+ "validation",
30
+ "constraint",
31
+ "typescript"
32
+ ],
33
+ "repository": {
34
+ "type": "git",
35
+ "url": "git+https://github.com/softistx/nxgt-graphql.git",
36
+ "directory": "packages/graphql-codegen-zod"
37
+ },
38
+ "publishConfig": {
39
+ "registry": "https://registry.npmjs.org",
40
+ "access": "public"
41
+ },
42
+ "scripts": {
43
+ "build": "bun run ../../build.ts",
44
+ "test": "bun test src",
45
+ "typecheck": "tsc --noEmit",
46
+ "generated:write": "bun run test/write-generated.ts"
47
+ },
48
+ "dependencies": {
49
+ "@nxgt/graphql-validation": "^0.2.0",
50
+ "change-case": "^5.4.4"
51
+ },
52
+ "devDependencies": {
53
+ "@nxgt/graphql-scalars": "^0.4.0",
54
+ "@types/bun": "^1.4.0",
55
+ "graphql": "16.11.0",
56
+ "zod": "4.6.5"
57
+ },
58
+ "peerDependencies": {
59
+ "graphql": "^16.11.0 || ^17.0.0",
60
+ "typescript": "^6.0.3",
61
+ "zod": ">=4.6.5 <5"
62
+ }
63
+ }