@nxgt/graphql-validation 0.2.1 → 0.3.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.
- package/README.md +64 -5
- package/dist/builder/check-constraints.d.ts +6 -1
- package/dist/builder/check-constraints.d.ts.map +1 -1
- package/dist/builder/input-code.d.ts +14 -1
- package/dist/builder/input-code.d.ts.map +1 -1
- package/dist/builder/input-schema.d.ts +3 -1
- package/dist/builder/input-schema.d.ts.map +1 -1
- package/dist/builder/leaf.d.ts +2 -2
- package/dist/builder/leaf.d.ts.map +1 -1
- package/dist/chunks/index-twevz7yc.js +527 -0
- package/dist/chunks/index-twevz7yc.js.map +26 -0
- package/dist/chunks/{index-rbxe5m3y.js → index-xcaf9kes.js} +24 -97
- package/dist/chunks/index-xcaf9kes.js.map +27 -0
- package/dist/cli.js +1 -1
- package/dist/codegen.d.ts +1 -0
- package/dist/codegen.d.ts.map +1 -1
- package/dist/codegen.js +19 -9
- package/dist/codegen.js.map +3 -3
- package/dist/formats/byte.d.ts +1 -1
- package/dist/formats/byte.d.ts.map +1 -1
- package/dist/formats/date-time.d.ts +1 -1
- package/dist/formats/date-time.d.ts.map +1 -1
- package/dist/formats/date.d.ts +1 -1
- package/dist/formats/date.d.ts.map +1 -1
- package/dist/formats/email.d.ts +1 -1
- package/dist/formats/email.d.ts.map +1 -1
- package/dist/formats/format.d.ts +17 -3
- package/dist/formats/format.d.ts.map +1 -1
- package/dist/formats/index.d.ts +6 -8
- package/dist/formats/index.d.ts.map +1 -1
- package/dist/formats/ipv4.d.ts +1 -1
- package/dist/formats/ipv4.d.ts.map +1 -1
- package/dist/formats/ipv6.d.ts +1 -1
- package/dist/formats/ipv6.d.ts.map +1 -1
- package/dist/formats/marked.d.ts +42 -0
- package/dist/formats/marked.d.ts.map +1 -0
- package/dist/formats/registry.d.ts +50 -0
- package/dist/formats/registry.d.ts.map +1 -0
- package/dist/formats/uri.d.ts +1 -1
- package/dist/formats/uri.d.ts.map +1 -1
- package/dist/formats/uuid.d.ts +1 -1
- package/dist/formats/uuid.d.ts.map +1 -1
- package/dist/index.d.ts +4 -1
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +18 -5
- package/dist/index.js.map +3 -3
- package/dist/rules/format.d.ts.map +1 -1
- package/dist/rules/index.d.ts +8 -3
- package/dist/rules/index.d.ts.map +1 -1
- package/dist/rules/rule.d.ts +19 -2
- package/dist/rules/rule.d.ts.map +1 -1
- package/dist/with-validation.d.ts +17 -1
- package/dist/with-validation.d.ts.map +1 -1
- package/docs/README.md +1 -1
- package/docs/guide/constraints.md +149 -4
- package/docs/guide/errors.md +4 -1
- package/docs/roadmap.md +19 -15
- package/docs/troubleshooting.md +157 -4
- package/package.json +2 -2
- package/dist/chunks/index-rbxe5m3y.js.map +0 -37
- package/dist/chunks/index-s1kkmg35.js +0 -266
- package/dist/chunks/index-s1kkmg35.js.map +0 -14
package/docs/troubleshooting.md
CHANGED
|
@@ -73,10 +73,148 @@ example with `@nxgt/graphql-scalars`), or on a field with [`validated`](guide/er
|
|
|
73
73
|
|
|
74
74
|
### `Unknown @constraint format "siret". Known formats: byte, date, date-time, email, ipv4, ipv6, uri, uuid.`
|
|
75
75
|
|
|
76
|
-
**When:** calling `withValidation
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
76
|
+
**When:** calling `withValidation` (or a code generator running
|
|
77
|
+
`checkConstraints`).
|
|
78
|
+
**Why:** `format` takes a built-in name or one of the formats handed to
|
|
79
|
+
`withValidation`; the message lists them all, yours after the built-in ones.
|
|
80
|
+
**Fix:** use a listed name, or declare the format and hand it over (see
|
|
81
|
+
[Your own formats](guide/constraints.md#your-own-formats)):
|
|
82
|
+
|
|
83
|
+
```ts
|
|
84
|
+
withValidation(schema, {
|
|
85
|
+
formats: { siret: z.string().regex(/^\d{14}$/) },
|
|
86
|
+
});
|
|
87
|
+
```
|
|
88
|
+
|
|
89
|
+
### `Invalid format name "Siret": write it in lowercase letters, digits and hyphens, starting with a letter.`
|
|
90
|
+
|
|
91
|
+
**When:** calling `withValidation` with `formats` (or `checkConstraints` /
|
|
92
|
+
`inputCode` with them).
|
|
93
|
+
**Why:** a format's name must match `/^[a-z][a-z0-9-]*$/`, as the built-in
|
|
94
|
+
ones do (`date-time`).
|
|
95
|
+
**Fix:** rename the key, and the `@constraint(format: "...")` that names it:
|
|
96
|
+
`siret`, `work-email`, `iso-6346`.
|
|
97
|
+
|
|
98
|
+
### `The format "email" is built in: give yours another name.`
|
|
99
|
+
|
|
100
|
+
**When:** calling `withValidation` with `formats` holding a built-in name
|
|
101
|
+
(`byte`, `date`, `date-time`, `email`, `ipv4`, `ipv6`, `uri`, `uuid`). A
|
|
102
|
+
record written in place is refused by the compiler first (its value is typed
|
|
103
|
+
`never`).
|
|
104
|
+
**Why:** a built-in format means the same everywhere; replacing it would
|
|
105
|
+
change every field that names it, in silence.
|
|
106
|
+
**Fix:** give yours its own name and use it where you need it:
|
|
107
|
+
|
|
108
|
+
```ts
|
|
109
|
+
const formatSchemas = { 'work-email': z.email().endsWith('@example.com') };
|
|
110
|
+
```
|
|
111
|
+
|
|
112
|
+
### `The format "code" is not a Zod string schema: write z.string() or a string format such as z.email(), narrowed with .regex() or .refine(), never transformed.`
|
|
113
|
+
|
|
114
|
+
**When:** calling `withValidation` with `formats` whose value is not a string
|
|
115
|
+
schema: `z.number()`, a `.transform()` or a codec (a pipe), `.optional()`, or
|
|
116
|
+
not a Zod schema at all. A record typed loosely (`as never`, `any`) gets past
|
|
117
|
+
the compiler; this check does not.
|
|
118
|
+
**Why:** a format checks a string and changes nothing, so the resolver
|
|
119
|
+
receives what the client sent; null and absence are the field's type's.
|
|
120
|
+
**Fix:** keep the string schema and its checks, and do any conversion in the
|
|
121
|
+
resolver:
|
|
122
|
+
|
|
123
|
+
```ts
|
|
124
|
+
const formatSchemas = { code: z.string().regex(/^[0-9]+$/) }; // not .transform(Number)
|
|
125
|
+
```
|
|
126
|
+
|
|
127
|
+
### `The format "code" cannot be run: its definition reads type: 'string' but it has no safeParseAsync, check, refine or catch, so it is not a schema of zod 4's classic API. Pass the schema z.string() or a string format returns, not an object shaped like one.`
|
|
128
|
+
|
|
129
|
+
**When:** calling `withValidation` (or generating with
|
|
130
|
+
`@nxgt/graphql-codegen-zod`) with `formats` whose value has a string
|
|
131
|
+
schema's definition (`_zod.def.type` is `'string'`) but not the methods of
|
|
132
|
+
Zod's classic API: an object built by hand, a test double shaped like a
|
|
133
|
+
schema, or a `zod/mini` schema. A record typed loosely (`as never`, `any`)
|
|
134
|
+
gets past the compiler; this check does not.
|
|
135
|
+
**Why:** every request runs the format through `safeParseAsync`, and reads
|
|
136
|
+
its abort and its result through `check`, `refine` and `catch`; without them,
|
|
137
|
+
each request would fail with `schema.safeParseAsync is not a function`, a message
|
|
138
|
+
that reaches the client. Startup refuses it instead.
|
|
139
|
+
**Fix:** pass the schema zod built, not an object shaped like one:
|
|
140
|
+
|
|
141
|
+
```ts
|
|
142
|
+
import { z } from 'zod';
|
|
143
|
+
|
|
144
|
+
const formatSchemas = { code: z.string().regex(/^[0-9]+$/) }; // not { _zod: { def: { type: 'string' } } }
|
|
145
|
+
```
|
|
146
|
+
|
|
147
|
+
### `The format "slug" rewrites the value (.trim(), .toLowerCase(), .toUpperCase(), .normalize(), .slugify(), .overwrite(), z.url(), z.httpUrl() or z.coerce.string()): refuse what is not canonical with .regex() or .refine() instead, so the server and the client check the value as it was sent.`
|
|
148
|
+
|
|
149
|
+
**When:** calling `withValidation` (or generating with
|
|
150
|
+
`@nxgt/graphql-codegen-zod`) with a format whose schema rewrites the value:
|
|
151
|
+
`.trim()`, `.toLowerCase()`, `.toUpperCase()`, `.normalize()`, `.slugify()`
|
|
152
|
+
or `.overwrite()`; `z.url()`, `z.httpUrl()` or `.url()`, which trim the value
|
|
153
|
+
and drop its tabs and newlines (`z.url({ normalize: true })` rewrites it
|
|
154
|
+
whole); or `z.coerce.string()`, which turns `12345` into `"12345"`. Each
|
|
155
|
+
keeps a string schema, so the type allows it; this check does not.
|
|
156
|
+
**Why:** the server checks the value as the client sent it, and the resolver
|
|
157
|
+
receives it unchanged, but a generated client chains the other rules on your
|
|
158
|
+
schema and would check the rewritten value: with `slug:
|
|
159
|
+
z.string().trim().toLowerCase()` and `@constraint(format: "slug", maxLength:
|
|
160
|
+
2)`, the server refuses `" AB "` and the client accepts it as `"ab"`.
|
|
161
|
+
**Fix:** refuse what is not canonical, and let the client normalise before it
|
|
162
|
+
sends:
|
|
163
|
+
|
|
164
|
+
```ts
|
|
165
|
+
const formatSchemas = {
|
|
166
|
+
slug: z.string().regex(/^[a-z0-9]+(?:-[a-z0-9]+)*$/, 'Invalid slug: lowercase words joined by hyphens'),
|
|
167
|
+
// not z.url(): a URL as sent, no white space to trim
|
|
168
|
+
link: z.string().refine((value) => value.trim() === value && URL.canParse(value), 'Invalid URL'),
|
|
169
|
+
code: z.string(), // not z.coerce.string()
|
|
170
|
+
};
|
|
171
|
+
```
|
|
172
|
+
|
|
173
|
+
### `The format "slug" rewrote the value it checked: a format checks the value and never changes it, so the server and the client check the value as it was sent. Refuse what is not canonical with .regex() or .refine() instead of setting payload.value in a .check().`
|
|
174
|
+
|
|
175
|
+
**When:** a request, not startup: a value reached a format whose schema
|
|
176
|
+
returned another value than the one it was handed — a `.check()` callback
|
|
177
|
+
that sets `ctx.value`, which no definition shows, so startup could not refuse
|
|
178
|
+
it. The operation fails with this error (no `BAD_USER_INPUT`: it is a bug in
|
|
179
|
+
the format, not in the input), and the resolver is not called.
|
|
180
|
+
**Why:** the resolver must receive what was sent, and a generated client
|
|
181
|
+
chaining rules on that schema would check the rewritten value.
|
|
182
|
+
**Fix:** refuse the value instead of changing it:
|
|
183
|
+
|
|
184
|
+
```ts
|
|
185
|
+
// not z.string().check((ctx) => { ctx.value = ctx.value.trim(); })
|
|
186
|
+
const slug = z.string().refine((value) => value.trim() === value, 'Invalid slug: no surrounding spaces');
|
|
187
|
+
```
|
|
188
|
+
|
|
189
|
+
### `withValidation: this schema is already wrapped with other formats. Call withValidation once, with every format.`
|
|
190
|
+
|
|
191
|
+
**When:** calling `withValidation` a second time on the same schema with a
|
|
192
|
+
record that is not the first call's: another name, another schema object for
|
|
193
|
+
a name (even one written the same, `z.string()` twice), formats where the first
|
|
194
|
+
call had none, or none where it had some.
|
|
195
|
+
**Why:** the first call already wrapped the fields, checked against its own
|
|
196
|
+
formats; a second set would be ignored in silence. With the same names, each
|
|
197
|
+
the very same schema object (the same record, or a copy of it), a second call
|
|
198
|
+
wraps nothing and does not throw.
|
|
199
|
+
**Fix:** call it once, last, with every format in one record.
|
|
200
|
+
|
|
201
|
+
### `@constraint(format: "siret") is one of the application's formats: its source is the code generator's to write, through inputCode's format option.`
|
|
202
|
+
|
|
203
|
+
**When:** a code generator calls `inputCode` from
|
|
204
|
+
`@nxgt/graphql-validation/codegen` on a field whose format is one of yours,
|
|
205
|
+
without `options.format`.
|
|
206
|
+
**Why:** your format exists as a schema, not as source this package can
|
|
207
|
+
write: only the generator knows where the generated file imports it from.
|
|
208
|
+
**Fix:** pass `format`, returning the source of your schema; the other rules
|
|
209
|
+
are chained on it. `@nxgt/graphql-codegen-zod` 0.3 does this for you
|
|
210
|
+
(`formatSchemas: './formats'`).
|
|
211
|
+
|
|
212
|
+
```ts
|
|
213
|
+
inputCode(type, constraints, where, named, {
|
|
214
|
+
format: (name) => `formatSchemas[${JSON.stringify(name)}]`,
|
|
215
|
+
}, formatSchemas);
|
|
216
|
+
// formatSchemas["siret"].max(14)
|
|
217
|
+
```
|
|
80
218
|
|
|
81
219
|
### `Invalid @constraint pattern "[a-":`
|
|
82
220
|
|
|
@@ -194,6 +332,21 @@ defaults.
|
|
|
194
332
|
type Query { a(name: String = "xy" @constraint(minLength: 2)): Int }
|
|
195
333
|
```
|
|
196
334
|
|
|
335
|
+
### `The default value of Query.a(s:) cannot be checked at startup: the format "free" checks asynchronously, and a default value is checked synchronously. Drop the default, or move the async check out of the format into validated().`
|
|
336
|
+
|
|
337
|
+
**When:** calling `withValidation` (or `checkConstraints`), on an argument or
|
|
338
|
+
input field with a default value whose format is one of yours with an async
|
|
339
|
+
check (`.refine(async …)`, an async `.superRefine()`, any check returning a
|
|
340
|
+
promise), from this package's zod or another copy, or whose check throws on
|
|
341
|
+
the default value: its error ends a run startup cannot wait for, so it reads
|
|
342
|
+
as async too.
|
|
343
|
+
**Why:** a default value is checked at startup, synchronously; Zod refuses
|
|
344
|
+
to run an async check there. In a request, the arguments are parsed
|
|
345
|
+
asynchronously and the check works.
|
|
346
|
+
**Fix:** drop the default, or keep the async check out of the format and run
|
|
347
|
+
it with [`validated`](guide/errors.md#validated); a check that throws is a
|
|
348
|
+
bug to fix in the format.
|
|
349
|
+
|
|
197
350
|
### `@constraint on @cached(ttl:) checks nothing: a directive's argument reaches no resolver. Remove it.`
|
|
198
351
|
|
|
199
352
|
**When:** calling `withValidation`, with `@constraint` written on an argument
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@nxgt/graphql-validation",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.3.1",
|
|
4
4
|
"description": "Validate GraphQL arguments and input fields with @constraint directives, checked by Zod schemas, for graphql 16 and 17",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"type": "module",
|
|
@@ -68,7 +68,7 @@
|
|
|
68
68
|
},
|
|
69
69
|
"peerDependencies": {
|
|
70
70
|
"graphql": "^16.11.0 || ^17.0.0",
|
|
71
|
-
"typescript": "^6.0.3",
|
|
71
|
+
"typescript": "^6.0.3 || ^7.0.0",
|
|
72
72
|
"zod": ">=4.6.5 <5"
|
|
73
73
|
}
|
|
74
74
|
}
|
|
@@ -1,37 +0,0 @@
|
|
|
1
|
-
{
|
|
2
|
-
"version": 3,
|
|
3
|
-
"sources": ["../src/constraint-directive.ts", "../src/rules/rule.ts", "../src/rules/contains.ts", "../src/rules/ends-with.ts", "../src/rules/exclusive-max.ts", "../src/rules/exclusive-min.ts", "../src/formats/byte.ts", "../src/formats/format.ts", "../src/formats/date.ts", "../src/formats/date-time.ts", "../src/formats/email.ts", "../src/formats/ipv4.ts", "../src/formats/ipv6.ts", "../src/formats/uri.ts", "../src/formats/uuid.ts", "../src/formats/index.ts", "../src/rules/format.ts", "../src/rules/max.ts", "../src/rules/max-items.ts", "../src/rules/max-length.ts", "../src/rules/min.ts", "../src/rules/min-items.ts", "../src/rules/min-length.ts", "../src/rules/multiple-of.ts", "../src/rules/not-contains.ts", "../src/rules/pattern.ts", "../src/rules/starts-with.ts", "../src/rules/index.ts"],
|
|
4
|
-
"sourcesContent": [
|
|
5
|
-
"import { DirectiveLocation, type GraphQLDirective } from 'graphql';\nimport { rules } from './rules';\n\n/**\n * The SDL of `@constraint`, to add to a schema-first server's `typeDefs`,\n * written from the rules: an argument is declared once its rule exists.\n *\n * Its arguments are graphql-constraint-directive's, minus `uniqueTypeName`\n * (a detail of that package's scalar wrapping). It is allowed on arguments\n * and input fields only, where that package also allows output fields: a\n * resolver's result is the output scalars' job, and a directive that checked\n * nothing there would be a promise broken in silence.\n */\nexport const constraintTypeDefs: string = `directive @constraint(\n${Object.values(rules)\n\t.map((rule) => `\\t${rule.argument}: ${rule.type}`)\n\t.join('\\n')}\n) on ARGUMENT_DEFINITION | INPUT_FIELD_DEFINITION\n`;\n\nconst allowed = new Set<string>([\n\tDirectiveLocation.ARGUMENT_DEFINITION,\n\tDirectiveLocation.INPUT_FIELD_DEFINITION,\n]);\n\n/**\n * Fails when the schema's `@constraint` is not the one\n * {@link constraintTypeDefs} declares — graphql-constraint-directive's, say,\n * kept from a migration. Its extra locations would be accepted and checked\n * by nothing, its extra arguments mean nothing here, and an argument of\n * another type would reach a rule as the wrong kind of value.\n */\nexport function assertOwnConstraint(directive: GraphQLDirective): void {\n\tconst problems = [\n\t\t...(directive.isRepeatable\n\t\t\t? ['repeatable, and only its first use is read']\n\t\t\t: []),\n\t\t...directive.locations\n\t\t\t.filter((location) => !allowed.has(location))\n\t\t\t.map((location) => `allowed on ${location}`),\n\t\t...directive.args.flatMap((arg) => {\n\t\t\tconst rule = (rules as Record<string, { type: string } | undefined>)[\n\t\t\t\targ.name\n\t\t\t];\n\t\t\tif (!rule) return [`declares ${arg.name}, which no rule reads`];\n\t\t\tconst type = String(arg.type);\n\t\t\treturn type === rule.type\n\t\t\t\t? []\n\t\t\t\t: [`declares ${arg.name}: ${type}, not ${rule.type}`];\n\t\t}),\n\t];\n\tif (problems.length > 0) {\n\t\tthrow new Error(\n\t\t\t`This schema's @constraint is not constraintTypeDefs': it is ${problems.join('; ')}. Declare it with constraintTypeDefs.`,\n\t\t);\n\t}\n}\n",
|
|
6
|
-
"import type { z } from 'zod';\nimport type { StringSchema } from '../formats/format';\n\n/** The schema each kind of rule narrows. */\nexport interface Targets {\n\tstring: StringSchema;\n\tnumber: z.ZodNumber;\n\tlist: z.ZodArray<z.ZodType>;\n}\n\nexport type Target = keyof Targets;\n\n/** What a `@constraint` argument's value can be. */\ninterface ValueOf {\n\tInt: number;\n\tFloat: number;\n\tString: string;\n}\n\n/**\n * One `@constraint` argument: its GraphQL type in the directive's SDL, the\n * kind of value it narrows, and the same narrowing twice — `toZod` applied to\n * a schema at startup, `toCode` written as source by a code generator. The\n * spec beside each rule proves the two accept and refuse the same values.\n *\n * A `base` rule (only `format`) replaces the schema instead of narrowing it,\n * so a builder applies it before every other rule of its target.\n */\nexport interface Rule<\n\tA extends string = string,\n\tT extends keyof ValueOf = keyof ValueOf,\n\tK extends Target = Target,\n> {\n\treadonly argument: A;\n\treadonly type: T;\n\treadonly target: K;\n\treadonly base?: true;\n\treadonly toZod: (schema: Targets[K], value: ValueOf[T]) => Targets[K];\n\t/**\n\t * `schema` is the source of the schema this rule narrows. The source names\n\t * zod as a free `z`: the generated file imports it.\n\t */\n\treadonly toCode: (schema: string, value: ValueOf[T]) => string;\n\t/**\n\t * Whether a Zod issue is this rule's refusal, so the error a client gets\n\t * names the rule (`constraint: 'minLength'`), which does not change with\n\t * Zod's own issue codes.\n\t */\n\treadonly owns: (issue: IssueFields) => boolean;\n}\n\n/** The fields of a Zod issue a rule recognises its refusal by. */\nexport interface IssueFields {\n\treadonly code: string;\n\treadonly origin?: string;\n\treadonly format?: string;\n\treadonly inclusive?: boolean;\n}\n\n/** Declares a rule, with its argument name kept literal. */\nexport function defineRule<\n\tconst A extends string,\n\tT extends keyof ValueOf,\n\tK extends Target,\n>(rule: Rule<A, T, K>): Rule<A, T, K> {\n\treturn rule;\n}\n\n/** A string literal as source: quotes and escapes included. */\nexport const literal = (value: string): string => JSON.stringify(value);\n",
|
|
7
|
-
"import { defineRule, literal } from './rule';\n\nexport const containsRule = defineRule({\n\targument: 'contains',\n\ttype: 'String',\n\ttarget: 'string',\n\ttoZod: (schema, value) => schema.includes(value),\n\ttoCode: (schema, value) => `${schema}.includes(${literal(value)})`,\n\towns: (issue) => issue.format === 'includes',\n});\n",
|
|
8
|
-
"import { defineRule, literal } from './rule';\n\nexport const endsWithRule = defineRule({\n\targument: 'endsWith',\n\ttype: 'String',\n\ttarget: 'string',\n\ttoZod: (schema, value) => schema.endsWith(value),\n\ttoCode: (schema, value) => `${schema}.endsWith(${literal(value)})`,\n\towns: (issue) => issue.format === 'ends_with',\n});\n",
|
|
9
|
-
"import { defineRule } from './rule';\n\nexport const exclusiveMaxRule = defineRule({\n\targument: 'exclusiveMax',\n\ttype: 'Float',\n\ttarget: 'number',\n\ttoZod: (schema, value) => schema.lt(value),\n\ttoCode: (schema, value) => `${schema}.lt(${value})`,\n\towns: (issue) =>\n\t\tissue.code === 'too_big' &&\n\t\tissue.origin === 'number' &&\n\t\tissue.inclusive === false,\n});\n",
|
|
10
|
-
"import { defineRule } from './rule';\n\nexport const exclusiveMinRule = defineRule({\n\targument: 'exclusiveMin',\n\ttype: 'Float',\n\ttarget: 'number',\n\ttoZod: (schema, value) => schema.gt(value),\n\ttoCode: (schema, value) => `${schema}.gt(${value})`,\n\towns: (issue) =>\n\t\tissue.code === 'too_small' &&\n\t\tissue.origin === 'number' &&\n\t\tissue.inclusive === false,\n});\n",
|
|
11
|
-
"import { z } from 'zod';\nimport { defineFormat } from './format';\n\nexport const byteFormat = defineFormat({\n\tname: 'byte',\n\ttoZod: () => z.base64(),\n\ttoCode: () => 'z.base64()',\n});\n",
|
|
12
|
-
"import type { z } from 'zod';\n\n/** A string schema, plain or a format (`z.email()` is not a `z.ZodString`). */\nexport type StringSchema = z.ZodString | z.ZodStringFormat;\n\n/**\n * One value of `@constraint(format: \"...\")`: the schema it stands for, as a\n * schema at startup and as source for a code generator.\n */\nexport interface Format<N extends string = string> {\n\treadonly name: N;\n\treadonly toZod: () => StringSchema;\n\treadonly toCode: () => string;\n}\n\n/** Declares a format, with its name kept literal. */\nexport function defineFormat<const N extends string>(\n\tformat: Format<N>,\n): Format<N> {\n\treturn format;\n}\n",
|
|
13
|
-
"import { z } from 'zod';\nimport { defineFormat } from './format';\n\nexport const dateFormat = defineFormat({\n\tname: 'date',\n\ttoZod: () => z.iso.date(),\n\ttoCode: () => 'z.iso.date()',\n});\n",
|
|
14
|
-
"import { z } from 'zod';\nimport { defineFormat } from './format';\n\n// RFC 3339 with an offset, in its canonical spelling only: an uppercase `T`\n// and `Z`, seconds present. graphql-constraint-directive (validator's\n// isRFC3339) also takes a lowercase `t`, `z` or a space.\nexport const dateTimeFormat = defineFormat({\n\tname: 'date-time',\n\ttoZod: () => z.iso.datetime({ offset: true }),\n\ttoCode: () => 'z.iso.datetime({ offset: true })',\n});\n",
|
|
15
|
-
"import { z } from 'zod';\nimport { defineFormat } from './format';\n\nexport const emailFormat = defineFormat({\n\tname: 'email',\n\ttoZod: () => z.email(),\n\ttoCode: () => 'z.email()',\n});\n",
|
|
16
|
-
"import { z } from 'zod';\nimport { defineFormat } from './format';\n\nexport const ipv4Format = defineFormat({\n\tname: 'ipv4',\n\ttoZod: () => z.ipv4(),\n\ttoCode: () => 'z.ipv4()',\n});\n",
|
|
17
|
-
"import { z } from 'zod';\nimport { defineFormat } from './format';\n\nexport const ipv6Format = defineFormat({\n\tname: 'ipv6',\n\ttoZod: () => z.ipv6(),\n\ttoCode: () => 'z.ipv6()',\n});\n",
|
|
18
|
-
"import { z } from 'zod';\nimport { defineFormat } from './format';\n\n// graphql-constraint-directive's `uri` is validator's isURL: http, https or\n// ftp. The scheme is required here, where isURL lets `example.com` through,\n// and nothing else gets in: no `javascript:`, no `mailto:`.\nexport const uriFormat = defineFormat({\n\tname: 'uri',\n\ttoZod: () => z.url({ protocol: /^(https?|ftp)$/ }),\n\ttoCode: () => 'z.url({ protocol: /^(https?|ftp)$/ })',\n});\n",
|
|
19
|
-
"import { z } from 'zod';\nimport { defineFormat } from './format';\n\nexport const uuidFormat = defineFormat({\n\tname: 'uuid',\n\ttoZod: () => z.uuid(),\n\ttoCode: () => 'z.uuid()',\n});\n",
|
|
20
|
-
"import * as all from './all';\nimport type { Format } from './format';\n\n/**\n * Every format, keyed by the value `@constraint(format: \"...\")` takes.\n * Derived from what `./all` exports, so a new format is one file and one\n * line there.\n */\nexport const formats = Object.fromEntries(\n\tObject.values(all).map((format) => [format.name, format]),\n) as { readonly [N in FormatName]: Format<N> };\n\n/** A value `@constraint(format: \"...\")` takes. */\nexport type FormatName = (typeof all)[keyof typeof all]['name'];\n\n/** The format named `name`, or an error that lists the known ones. */\nexport function formatNamed(name: string): Format {\n\tif (Object.hasOwn(formats, name)) return formats[name as FormatName];\n\tthrow new Error(\n\t\t`Unknown @constraint format \"${name}\". Known formats: ${Object.keys(formats).join(', ')}.`,\n\t);\n}\n",
|
|
21
|
-
"import { formatNamed } from '../formats';\nimport { defineRule } from './rule';\n\n// The string rules' own formats; every other invalid_format is a format's.\nconst NARROWING = new Set(['starts_with', 'ends_with', 'includes', 'regex']);\n\nexport const formatRule = defineRule({\n\targument: 'format',\n\ttype: 'String',\n\ttarget: 'string',\n\tbase: true,\n\ttoZod: (_schema, value) => formatNamed(value).toZod(),\n\ttoCode: (_schema, value) => formatNamed(value).toCode(),\n\towns: (issue) =>\n\t\tissue.code === 'invalid_format' && !NARROWING.has(issue.format ?? ''),\n});\n",
|
|
22
|
-
"import { defineRule } from './rule';\n\nexport const maxRule = defineRule({\n\targument: 'max',\n\ttype: 'Float',\n\ttarget: 'number',\n\ttoZod: (schema, value) => schema.lte(value),\n\ttoCode: (schema, value) => `${schema}.lte(${value})`,\n\towns: (issue) =>\n\t\tissue.code === 'too_big' &&\n\t\tissue.origin === 'number' &&\n\t\tissue.inclusive === true,\n});\n",
|
|
23
|
-
"import { defineRule } from './rule';\n\nexport const maxItemsRule = defineRule({\n\targument: 'maxItems',\n\ttype: 'Int',\n\ttarget: 'list',\n\ttoZod: (schema, value) => schema.max(value),\n\ttoCode: (schema, value) => `${schema}.max(${value})`,\n\towns: (issue) => issue.code === 'too_big' && issue.origin === 'array',\n});\n",
|
|
24
|
-
"import { defineRule } from './rule';\n\nexport const maxLengthRule = defineRule({\n\targument: 'maxLength',\n\ttype: 'Int',\n\ttarget: 'string',\n\ttoZod: (schema, value) => schema.max(value),\n\ttoCode: (schema, value) => `${schema}.max(${value})`,\n\towns: (issue) => issue.code === 'too_big' && issue.origin === 'string',\n});\n",
|
|
25
|
-
"import { defineRule } from './rule';\n\nexport const minRule = defineRule({\n\targument: 'min',\n\ttype: 'Float',\n\ttarget: 'number',\n\ttoZod: (schema, value) => schema.gte(value),\n\ttoCode: (schema, value) => `${schema}.gte(${value})`,\n\towns: (issue) =>\n\t\tissue.code === 'too_small' &&\n\t\tissue.origin === 'number' &&\n\t\tissue.inclusive === true,\n});\n",
|
|
26
|
-
"import { defineRule } from './rule';\n\nexport const minItemsRule = defineRule({\n\targument: 'minItems',\n\ttype: 'Int',\n\ttarget: 'list',\n\ttoZod: (schema, value) => schema.min(value),\n\ttoCode: (schema, value) => `${schema}.min(${value})`,\n\towns: (issue) => issue.code === 'too_small' && issue.origin === 'array',\n});\n",
|
|
27
|
-
"import { defineRule } from './rule';\n\nexport const minLengthRule = defineRule({\n\targument: 'minLength',\n\ttype: 'Int',\n\ttarget: 'string',\n\ttoZod: (schema, value) => schema.min(value),\n\ttoCode: (schema, value) => `${schema}.min(${value})`,\n\towns: (issue) => issue.code === 'too_small' && issue.origin === 'string',\n});\n",
|
|
28
|
-
"import { defineRule } from './rule';\n\nexport const multipleOfRule = defineRule({\n\targument: 'multipleOf',\n\ttype: 'Float',\n\ttarget: 'number',\n\ttoZod: (schema, value) => schema.multipleOf(value),\n\ttoCode: (schema, value) => `${schema}.multipleOf(${value})`,\n\towns: (issue) => issue.code === 'not_multiple_of',\n});\n",
|
|
29
|
-
"import { defineRule, literal } from './rule';\n\nconst message = (value: string) => `Must not contain ${literal(value)}`;\n\nexport const notContainsRule = defineRule({\n\targument: 'notContains',\n\ttype: 'String',\n\ttarget: 'string',\n\t// `refine` keeps the schema's own type, so later rules still chain.\n\ttoZod: (schema, value) =>\n\t\tschema.refine((input) => !input.includes(value), message(value)),\n\ttoCode: (schema, value) =>\n\t\t`${schema}.refine((input) => !input.includes(${literal(value)}), ${literal(message(value))})`,\n\towns: (issue) => issue.code === 'custom',\n});\n",
|
|
30
|
-
"import { defineRule, literal } from './rule';\n\n/** The pattern as a RegExp, or an error that names the argument. */\nfunction compile(value: string): RegExp {\n\ttry {\n\t\treturn new RegExp(value);\n\t} catch (error) {\n\t\tthrow new Error(\n\t\t\t`Invalid @constraint pattern ${literal(value)}: ${(error as Error).message}`,\n\t\t);\n\t}\n}\n\nexport const patternRule = defineRule({\n\targument: 'pattern',\n\ttype: 'String',\n\ttarget: 'string',\n\ttoZod: (schema, value) => schema.regex(compile(value)),\n\ttoCode: (schema, value) =>\n\t\t`${schema}.regex(new RegExp(${literal(compile(value).source)}))`,\n\towns: (issue) => issue.format === 'regex',\n});\n",
|
|
31
|
-
"import { defineRule, literal } from './rule';\n\nexport const startsWithRule = defineRule({\n\targument: 'startsWith',\n\ttype: 'String',\n\ttarget: 'string',\n\ttoZod: (schema, value) => schema.startsWith(value),\n\ttoCode: (schema, value) => `${schema}.startsWith(${literal(value)})`,\n\towns: (issue) => issue.format === 'starts_with',\n});\n",
|
|
32
|
-
"import type { z } from 'zod';\nimport * as all from './all';\nimport type { IssueFields } from './rule';\n\n/**\n * One of the rules, as its own type: a builder narrows it on `target`, so a\n * number schema never reaches a string rule.\n */\nexport type RegisteredRule = (typeof all)[keyof typeof all];\n\n/** An argument `@constraint` takes. */\nexport type ConstraintArgument = RegisteredRule['argument'];\n\n/**\n * Every rule, keyed by its `@constraint` argument. Derived from what\n * `./all` exports, so a new rule is one file and one line there, and the\n * directive's SDL follows.\n */\nexport const rules = Object.fromEntries(\n\tObject.values(all).map((rule) => [rule.argument, rule]),\n) as {\n\treadonly [A in ConstraintArgument]: Extract<RegisteredRule, { argument: A }>;\n};\n\n/**\n * Applies a rule to a schema its caller has already matched to the rule's\n * target: the one place the rule's typed `toZod` meets a schema built from\n * GraphQL types, which the compiler cannot relate.\n */\nexport function applyRule(\n\trule: RegisteredRule,\n\tschema: z.ZodType,\n\tvalue: string | number,\n): z.ZodType {\n\tconst toZod = rule.toZod as unknown as (\n\t\tschema: z.ZodType,\n\t\tvalue: string | number,\n\t) => z.ZodType;\n\treturn toZod(schema, value);\n}\n\n/** `applyRule` for source: the rule's typed `toCode` on a schema's source. */\nexport function applyRuleCode(\n\trule: RegisteredRule,\n\tsource: string,\n\tvalue: string | number,\n): string {\n\tconst toCode = rule.toCode as (\n\t\tschema: string,\n\t\tvalue: string | number,\n\t) => string;\n\treturn toCode(source, value);\n}\n\n/** The `@constraint` argument whose rule refused with this issue, if any. */\nexport function constraintOf(\n\tissue: z.core.$ZodIssue,\n): ConstraintArgument | undefined {\n\tconst fields = issue as unknown as IssueFields;\n\treturn Object.values(rules).find((rule) => rule.owns(fields))?.argument;\n}\n"
|
|
33
|
-
],
|
|
34
|
-
"mappings": "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",
|
|
35
|
-
"debugId": "0FAF783CE1246B6764756E2164756E21",
|
|
36
|
-
"names": []
|
|
37
|
-
}
|
|
@@ -1,266 +0,0 @@
|
|
|
1
|
-
import {
|
|
2
|
-
rules,
|
|
3
|
-
applyRule,
|
|
4
|
-
assertOwnConstraint
|
|
5
|
-
} from "./index-rbxe5m3y.js";
|
|
6
|
-
|
|
7
|
-
// src/builder/constraints.ts
|
|
8
|
-
import {
|
|
9
|
-
getDirectiveValues
|
|
10
|
-
} from "graphql";
|
|
11
|
-
function constraintsOn2(directive, node) {
|
|
12
|
-
if (!directive || !node)
|
|
13
|
-
return [];
|
|
14
|
-
const values = getDirectiveValues(directive, { directives: node.directives ?? [] }) ?? {};
|
|
15
|
-
return Object.entries(values).filter(([, value]) => value !== undefined && value !== null).map(([argument, value]) => ({
|
|
16
|
-
rule: rules[argument],
|
|
17
|
-
value
|
|
18
|
-
})).sort((a, b) => Number(Boolean(b.rule.base)) - Number(Boolean(a.rule.base)));
|
|
19
|
-
}
|
|
20
|
-
|
|
21
|
-
// src/builder/check-constraints.ts
|
|
22
|
-
import {
|
|
23
|
-
isInterfaceType,
|
|
24
|
-
isObjectType
|
|
25
|
-
} from "graphql";
|
|
26
|
-
|
|
27
|
-
// src/builder/args-schema.ts
|
|
28
|
-
import { z } from "zod";
|
|
29
|
-
function argsSchemaOf(inputs, parent, field) {
|
|
30
|
-
if (!field.args.some((arg) => inputs.needsCheck(arg)))
|
|
31
|
-
return;
|
|
32
|
-
return z.object(Object.fromEntries(field.args.map((arg) => [
|
|
33
|
-
arg.name,
|
|
34
|
-
inputs.of(arg, `${parent}.${field.name}(${arg.name}:)`)
|
|
35
|
-
])));
|
|
36
|
-
}
|
|
37
|
-
function signature(inputs, arg) {
|
|
38
|
-
return constraintsOn2(inputs.directive, arg.astNode).map(({ rule, value }) => `${rule.argument}: ${JSON.stringify(value)}`).sort().join(", ");
|
|
39
|
-
}
|
|
40
|
-
var written = (signature) => signature ? `@constraint(${signature})` : "no @constraint";
|
|
41
|
-
function assertInterfaceConstraintsKept(inputs, type) {
|
|
42
|
-
for (const contract of type.getInterfaces()) {
|
|
43
|
-
for (const [name, declared] of Object.entries(contract.getFields())) {
|
|
44
|
-
const field = type.getFields()[name];
|
|
45
|
-
for (const arg of declared.args) {
|
|
46
|
-
const wanted = signature(inputs, arg);
|
|
47
|
-
if (!wanted)
|
|
48
|
-
continue;
|
|
49
|
-
const own = field?.args.find(({ name: argName }) => argName === arg.name);
|
|
50
|
-
const found = own ? signature(inputs, own) : wanted;
|
|
51
|
-
if (found !== wanted) {
|
|
52
|
-
const verb = found ? "differs on" : "is not repeated on";
|
|
53
|
-
throw new Error(`@constraint on ${contract.name}.${name}(${arg.name}:) ${verb} ${type.name}.${name}(${arg.name}:), which resolves it (${written(wanted)} there, ${written(found)} here). Write the same @constraint on both.`);
|
|
54
|
-
}
|
|
55
|
-
}
|
|
56
|
-
}
|
|
57
|
-
}
|
|
58
|
-
}
|
|
59
|
-
|
|
60
|
-
// src/builder/input-schema.ts
|
|
61
|
-
import {
|
|
62
|
-
getNamedType,
|
|
63
|
-
isInputObjectType,
|
|
64
|
-
isListType,
|
|
65
|
-
isNonNullType,
|
|
66
|
-
valueFromAST
|
|
67
|
-
} from "graphql";
|
|
68
|
-
import { z as z3 } from "zod";
|
|
69
|
-
|
|
70
|
-
// src/builder/leaf.ts
|
|
71
|
-
import {
|
|
72
|
-
GraphQLBoolean,
|
|
73
|
-
GraphQLFloat,
|
|
74
|
-
GraphQLID,
|
|
75
|
-
GraphQLInt,
|
|
76
|
-
GraphQLString
|
|
77
|
-
} from "graphql";
|
|
78
|
-
import { z as z2 } from "zod";
|
|
79
|
-
var kinds = {
|
|
80
|
-
[GraphQLString.name]: "string",
|
|
81
|
-
[GraphQLID.name]: "string",
|
|
82
|
-
[GraphQLInt.name]: "number",
|
|
83
|
-
[GraphQLFloat.name]: "number"
|
|
84
|
-
};
|
|
85
|
-
function baseOf(type) {
|
|
86
|
-
if (type.name === GraphQLInt.name)
|
|
87
|
-
return z2.number().int();
|
|
88
|
-
return kinds[type.name] === "number" ? z2.number() : z2.string();
|
|
89
|
-
}
|
|
90
|
-
function assertLeafTargets(type, constraints, where) {
|
|
91
|
-
const misplaced = constraints.find(({ rule }) => rule.target === "list");
|
|
92
|
-
if (misplaced)
|
|
93
|
-
throw misplacedOn(misplaced, where, type.name);
|
|
94
|
-
const kind = kinds[type.name];
|
|
95
|
-
const wrong = constraints.find(({ rule }) => rule.target !== kind);
|
|
96
|
-
if (wrong)
|
|
97
|
-
throw misplacedOn(wrong, where, type.name);
|
|
98
|
-
}
|
|
99
|
-
function assertObjectTargets(typeName, constraints, where) {
|
|
100
|
-
const first = constraints.find(({ rule }) => rule.target === "list") ?? constraints[0];
|
|
101
|
-
if (first)
|
|
102
|
-
throw misplacedOn(first, where, typeName);
|
|
103
|
-
}
|
|
104
|
-
function misplacedOn({ rule }, where, typeName) {
|
|
105
|
-
return new Error(`@constraint(${rule.argument}) on ${where} needs ${describeTarget(rule.target)}, not ${typeName}.`);
|
|
106
|
-
}
|
|
107
|
-
function leafSchema(type, constraints, where) {
|
|
108
|
-
if (constraints.length === 0)
|
|
109
|
-
return z2.unknown();
|
|
110
|
-
assertLeafTargets(type, constraints, where);
|
|
111
|
-
let schema = baseOf(type);
|
|
112
|
-
for (const { rule, value } of constraints) {
|
|
113
|
-
schema = applyRule(rule, schema, value);
|
|
114
|
-
}
|
|
115
|
-
return schema;
|
|
116
|
-
}
|
|
117
|
-
function baseCode(type) {
|
|
118
|
-
if (type.name === GraphQLInt.name)
|
|
119
|
-
return "z.int32()";
|
|
120
|
-
if (type.name === GraphQLFloat.name)
|
|
121
|
-
return "z.number()";
|
|
122
|
-
if (type.name === GraphQLBoolean.name)
|
|
123
|
-
return "z.boolean()";
|
|
124
|
-
return kinds[type.name] === "string" ? "z.string()" : undefined;
|
|
125
|
-
}
|
|
126
|
-
function describeTarget(target) {
|
|
127
|
-
if (target === "string")
|
|
128
|
-
return "a String or an ID";
|
|
129
|
-
if (target === "number")
|
|
130
|
-
return "an Int or a Float";
|
|
131
|
-
return "a list";
|
|
132
|
-
}
|
|
133
|
-
|
|
134
|
-
// src/builder/input-schema.ts
|
|
135
|
-
class InputSchemas {
|
|
136
|
-
directive;
|
|
137
|
-
#objects = new Map;
|
|
138
|
-
#defaults = [];
|
|
139
|
-
#constrained = new Set;
|
|
140
|
-
constructor(schema) {
|
|
141
|
-
this.directive = schema.getDirective("constraint") ?? undefined;
|
|
142
|
-
const objects = Object.values(schema.getTypeMap()).filter(isInputObjectType);
|
|
143
|
-
for (let changed = true;changed; ) {
|
|
144
|
-
changed = false;
|
|
145
|
-
for (const type of objects) {
|
|
146
|
-
if (this.#constrained.has(type.name))
|
|
147
|
-
continue;
|
|
148
|
-
const constrained = Object.values(type.getFields()).some((field) => constraintsOn2(this.directive, field.astNode).length > 0 || this.isConstrained(field.type));
|
|
149
|
-
if (constrained) {
|
|
150
|
-
this.#constrained.add(type.name);
|
|
151
|
-
changed = true;
|
|
152
|
-
}
|
|
153
|
-
}
|
|
154
|
-
}
|
|
155
|
-
}
|
|
156
|
-
isConstrained(type) {
|
|
157
|
-
const named = getNamedType(type);
|
|
158
|
-
return isInputObjectType(named) && this.#constrained.has(named.name);
|
|
159
|
-
}
|
|
160
|
-
buildAll(schema) {
|
|
161
|
-
for (const type of Object.values(schema.getTypeMap())) {
|
|
162
|
-
if (isInputObjectType(type))
|
|
163
|
-
this.#object(type);
|
|
164
|
-
}
|
|
165
|
-
}
|
|
166
|
-
needsCheck(input) {
|
|
167
|
-
return constraintsOn2(this.directive, input.astNode).length > 0 || this.isConstrained(input.type);
|
|
168
|
-
}
|
|
169
|
-
of(input, where) {
|
|
170
|
-
const schema = this.#typed(input.type, constraintsOn2(this.directive, input.astNode), where);
|
|
171
|
-
const literal = input.astNode?.defaultValue;
|
|
172
|
-
if (literal)
|
|
173
|
-
this.#defaults.push({ schema, literal, type: input.type, where });
|
|
174
|
-
return schema;
|
|
175
|
-
}
|
|
176
|
-
checkDefaults() {
|
|
177
|
-
for (const { schema, literal, type, where } of this.#defaults.splice(0)) {
|
|
178
|
-
const value = valueFromAST(literal, type);
|
|
179
|
-
if (value === undefined)
|
|
180
|
-
continue;
|
|
181
|
-
const result = schema.safeParse(value);
|
|
182
|
-
if (!result.success) {
|
|
183
|
-
throw new Error(`The default value of ${where} breaks its @constraint: ${result.error.issues[0]?.message}`);
|
|
184
|
-
}
|
|
185
|
-
}
|
|
186
|
-
}
|
|
187
|
-
#typed(type, constraints, where) {
|
|
188
|
-
if (isNonNullType(type))
|
|
189
|
-
return this.#required(type.ofType, constraints, where);
|
|
190
|
-
return this.#required(type, constraints, where).nullish();
|
|
191
|
-
}
|
|
192
|
-
#required(type, constraints, where) {
|
|
193
|
-
if (isNonNullType(type))
|
|
194
|
-
return this.#required(type.ofType, constraints, where);
|
|
195
|
-
if (isListType(type)) {
|
|
196
|
-
const own = constraints.filter(({ rule }) => rule.target === "list");
|
|
197
|
-
const items = constraints.filter(({ rule }) => rule.target !== "list");
|
|
198
|
-
let list = z3.array(this.#typed(type.ofType, items, where));
|
|
199
|
-
for (const { rule, value } of own)
|
|
200
|
-
list = applyRule(rule, list, value);
|
|
201
|
-
return list;
|
|
202
|
-
}
|
|
203
|
-
if (isInputObjectType(type)) {
|
|
204
|
-
assertObjectTargets(type.name, constraints, where);
|
|
205
|
-
return this.#object(type);
|
|
206
|
-
}
|
|
207
|
-
return leafSchema(type, constraints, where);
|
|
208
|
-
}
|
|
209
|
-
#object(type) {
|
|
210
|
-
if (!this.isConstrained(type))
|
|
211
|
-
return z3.unknown();
|
|
212
|
-
const built = this.#objects.get(type.name);
|
|
213
|
-
if (built)
|
|
214
|
-
return built;
|
|
215
|
-
let schema;
|
|
216
|
-
this.#objects.set(type.name, z3.lazy(() => schema));
|
|
217
|
-
schema = z3.object(Object.fromEntries(Object.values(type.getFields()).map((field) => [
|
|
218
|
-
field.name,
|
|
219
|
-
this.of(field, `${type.name}.${field.name}`)
|
|
220
|
-
])));
|
|
221
|
-
this.#objects.set(type.name, schema);
|
|
222
|
-
return schema;
|
|
223
|
-
}
|
|
224
|
-
}
|
|
225
|
-
|
|
226
|
-
// src/builder/check-constraints.ts
|
|
227
|
-
function checkConstraints2(schema, onArgs) {
|
|
228
|
-
const inputs = new InputSchemas(schema);
|
|
229
|
-
if (!inputs.directive)
|
|
230
|
-
return;
|
|
231
|
-
assertOwnConstraint(inputs.directive);
|
|
232
|
-
inputs.buildAll(schema);
|
|
233
|
-
assertNoDirectiveArgumentConstrained(inputs, schema);
|
|
234
|
-
for (const type of Object.values(schema.getTypeMap())) {
|
|
235
|
-
if (type.name.startsWith("__"))
|
|
236
|
-
continue;
|
|
237
|
-
if (isInterfaceType(type)) {
|
|
238
|
-
for (const field of Object.values(type.getFields()))
|
|
239
|
-
argsSchemaOf(inputs, type.name, field);
|
|
240
|
-
}
|
|
241
|
-
if (!isObjectType(type))
|
|
242
|
-
continue;
|
|
243
|
-
assertInterfaceConstraintsKept(inputs, type);
|
|
244
|
-
for (const field of Object.values(type.getFields())) {
|
|
245
|
-
const args = argsSchemaOf(inputs, type.name, field);
|
|
246
|
-
if (args)
|
|
247
|
-
onArgs?.(type, field, args);
|
|
248
|
-
}
|
|
249
|
-
}
|
|
250
|
-
inputs.checkDefaults();
|
|
251
|
-
return inputs.directive;
|
|
252
|
-
}
|
|
253
|
-
function assertNoDirectiveArgumentConstrained(inputs, schema) {
|
|
254
|
-
for (const directive of schema.getDirectives()) {
|
|
255
|
-
for (const arg of directive.args) {
|
|
256
|
-
if (constraintsOn2(inputs.directive, arg.astNode).length > 0) {
|
|
257
|
-
throw new Error(`@constraint on @${directive.name}(${arg.name}:) checks nothing: a directive's argument reaches no resolver. Remove it.`);
|
|
258
|
-
}
|
|
259
|
-
}
|
|
260
|
-
}
|
|
261
|
-
}
|
|
262
|
-
|
|
263
|
-
export { constraintsOn2, assertLeafTargets, assertObjectTargets, baseCode, checkConstraints2 };
|
|
264
|
-
|
|
265
|
-
//# debugId=7C317F3D691975BE64756E2164756E21
|
|
266
|
-
//# sourceMappingURL=index-s1kkmg35.js.map
|
|
@@ -1,14 +0,0 @@
|
|
|
1
|
-
{
|
|
2
|
-
"version": 3,
|
|
3
|
-
"sources": ["../src/builder/constraints.ts", "../src/builder/check-constraints.ts", "../src/builder/args-schema.ts", "../src/builder/input-schema.ts", "../src/builder/leaf.ts"],
|
|
4
|
-
"sourcesContent": [
|
|
5
|
-
"import {\n\ttype DirectiveNode,\n\ttype GraphQLDirective,\n\tgetDirectiveValues,\n} from 'graphql';\nimport { type RegisteredRule, rules } from '../rules';\n\n/** One `@constraint` argument written on an argument or an input field. */\nexport interface Constraint {\n\treadonly rule: RegisteredRule;\n\treadonly value: string | number;\n}\n\n/**\n * The constraints written on a node, base rules (`format`) first so the\n * others narrow the schema they produce. Empty when the schema declares no\n * `@constraint` or the node carries none.\n */\nexport function constraintsOn(\n\tdirective: GraphQLDirective | undefined,\n\tnode:\n\t\t| { readonly directives?: ReadonlyArray<DirectiveNode> | undefined }\n\t\t| null\n\t\t| undefined,\n): Constraint[] {\n\tif (!directive || !node) return [];\n\tconst values =\n\t\tgetDirectiveValues(directive, { directives: node.directives ?? [] }) ?? {};\n\treturn Object.entries(values)\n\t\t.filter(([, value]) => value !== undefined && value !== null)\n\t\t.map(([argument, value]) => ({\n\t\t\trule: rules[argument as keyof typeof rules],\n\t\t\tvalue: value as string | number,\n\t\t}))\n\t\t.sort(\n\t\t\t(a, b) => Number(Boolean(b.rule.base)) - Number(Boolean(a.rule.base)),\n\t\t);\n}\n",
|
|
6
|
-
"import {\n\ttype GraphQLDirective,\n\ttype GraphQLField,\n\ttype GraphQLObjectType,\n\ttype GraphQLSchema,\n\tisInterfaceType,\n\tisObjectType,\n} from 'graphql';\nimport type { z } from 'zod';\nimport { assertOwnConstraint } from '../constraint-directive';\nimport { argsSchemaOf, assertInterfaceConstraintsKept } from './args-schema';\nimport { constraintsOn } from './constraints';\nimport { InputSchemas } from './input-schema';\n\n/**\n * Runs every check `withValidation` makes at startup, so a code generator\n * refuses the same schemas: the declaration is `constraintTypeDefs`', every\n * constraint applies where it is written (in every input type), none sits on\n * a directive's argument, objects keep their interfaces' constraints, and no\n * default value breaks its own. `onArgs` receives each object field's\n * arguments schema, for a field with something to check.\n *\n * Returns the `@constraint` directive, or `undefined` when the schema\n * declares none (and so carries no constraint).\n */\nexport function checkConstraints(\n\tschema: GraphQLSchema,\n\tonArgs?: (\n\t\ttype: GraphQLObjectType,\n\t\tfield: GraphQLField<unknown, unknown>,\n\t\targs: z.ZodType,\n\t) => void,\n): GraphQLDirective | undefined {\n\tconst inputs = new InputSchemas(schema);\n\tif (!inputs.directive) return undefined;\n\tassertOwnConstraint(inputs.directive);\n\tinputs.buildAll(schema);\n\tassertNoDirectiveArgumentConstrained(inputs, schema);\n\tfor (const type of Object.values(schema.getTypeMap())) {\n\t\tif (type.name.startsWith('__')) continue;\n\t\t// An interface's fields resolve on its objects: built for their errors only.\n\t\tif (isInterfaceType(type)) {\n\t\t\tfor (const field of Object.values(type.getFields()))\n\t\t\t\targsSchemaOf(inputs, type.name, field);\n\t\t}\n\t\tif (!isObjectType(type)) continue;\n\t\tassertInterfaceConstraintsKept(inputs, type);\n\t\tfor (const field of Object.values(type.getFields()) as GraphQLField<\n\t\t\tunknown,\n\t\t\tunknown\n\t\t>[]) {\n\t\t\tconst args = argsSchemaOf(inputs, type.name, field);\n\t\t\tif (args) onArgs?.(type, field, args);\n\t\t}\n\t}\n\tinputs.checkDefaults();\n\treturn inputs.directive;\n}\n\n/**\n * Fails on a `@constraint` written on a directive's argument: graphql allows\n * it there (ARGUMENT_DEFINITION), but no resolver receives that argument, so\n * it would check nothing.\n */\nfunction assertNoDirectiveArgumentConstrained(\n\tinputs: InputSchemas,\n\tschema: GraphQLSchema,\n): void {\n\tfor (const directive of schema.getDirectives()) {\n\t\tfor (const arg of directive.args) {\n\t\t\tif (constraintsOn(inputs.directive, arg.astNode).length > 0) {\n\t\t\t\tthrow new Error(\n\t\t\t\t\t`@constraint on @${directive.name}(${arg.name}:) checks nothing: a directive's argument reaches no resolver. Remove it.`,\n\t\t\t\t);\n\t\t\t}\n\t\t}\n\t}\n}\n",
|
|
7
|
-
"import type { GraphQLArgument, GraphQLField, GraphQLObjectType } from 'graphql';\nimport { z } from 'zod';\nimport { constraintsOn } from './constraints';\nimport type { InputSchemas } from './input-schema';\n\n/**\n * The schema of a field's arguments, or `undefined` when none of them can\n * break a constraint, so a field with nothing to check is left untouched.\n * `parent` is the type's name, for errors: `Mutation.signUp(input:)`.\n */\nexport function argsSchemaOf(\n\tinputs: InputSchemas,\n\tparent: string,\n\tfield: GraphQLField<unknown, unknown>,\n): z.ZodType | undefined {\n\tif (!field.args.some((arg) => inputs.needsCheck(arg))) return undefined;\n\treturn z.object(\n\t\tObject.fromEntries(\n\t\t\tfield.args.map((arg) => [\n\t\t\t\targ.name,\n\t\t\t\tinputs.of(arg, `${parent}.${field.name}(${arg.name}:)`),\n\t\t\t]),\n\t\t),\n\t);\n}\n\n/** The constraints of an argument as written, sorted: `maxLength: 5, min: 1`. */\nfunction signature(inputs: InputSchemas, arg: GraphQLArgument): string {\n\treturn constraintsOn(inputs.directive, arg.astNode)\n\t\t.map(({ rule, value }) => `${rule.argument}: ${JSON.stringify(value)}`)\n\t\t.sort()\n\t\t.join(', ');\n}\n\n/** A signature as it reads in an error. */\nconst written = (signature: string) =>\n\tsignature ? `@constraint(${signature})` : 'no @constraint';\n\n/**\n * Fails when an object type's field does not repeat the `@constraint` its\n * interface writes on an argument. The object's field is the one that\n * resolves, and graphql lets it redeclare the argument bare: the interface's\n * constraint would then check nothing, in silence.\n */\nexport function assertInterfaceConstraintsKept(\n\tinputs: InputSchemas,\n\ttype: GraphQLObjectType,\n): void {\n\tfor (const contract of type.getInterfaces()) {\n\t\tfor (const [name, declared] of Object.entries(contract.getFields())) {\n\t\t\tconst field = type.getFields()[name];\n\t\t\tfor (const arg of declared.args) {\n\t\t\t\tconst wanted = signature(inputs, arg);\n\t\t\t\tif (!wanted) continue;\n\t\t\t\tconst own = field?.args.find(\n\t\t\t\t\t({ name: argName }) => argName === arg.name,\n\t\t\t\t);\n\t\t\t\tconst found = own ? signature(inputs, own) : wanted;\n\t\t\t\tif (found !== wanted) {\n\t\t\t\t\tconst verb = found ? 'differs on' : 'is not repeated on';\n\t\t\t\t\tthrow new Error(\n\t\t\t\t\t\t`@constraint on ${contract.name}.${name}(${arg.name}:) ${verb} ${type.name}.${name}(${arg.name}:), which resolves it (${written(wanted)} there, ${written(found)} here). Write the same @constraint on both.`,\n\t\t\t\t\t);\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n}\n",
|
|
8
|
-
"import {\n\ttype ConstValueNode,\n\ttype GraphQLArgument,\n\ttype GraphQLDirective,\n\ttype GraphQLInputField,\n\ttype GraphQLInputObjectType,\n\ttype GraphQLInputType,\n\ttype GraphQLSchema,\n\tgetNamedType,\n\tisInputObjectType,\n\tisListType,\n\tisNonNullType,\n\tvalueFromAST,\n} from 'graphql';\nimport { z } from 'zod';\nimport { applyRule } from '../rules';\nimport { type Constraint, constraintsOn } from './constraints';\nimport { assertObjectTargets, leafSchema } from './leaf';\n\n/**\n * Builds the schemas of the arguments and input fields of one GraphQL\n * schema, once each: an input type is walked a single time however many\n * fields use it, and a recursive one (`input Filter { and: [Filter!] }`) is\n * reached through `z.lazy`.\n */\nexport class InputSchemas {\n\treadonly directive: GraphQLDirective | undefined;\n\treadonly #objects = new Map<string, z.ZodType>();\n\treadonly #defaults: {\n\t\tschema: z.ZodType;\n\t\tliteral: ConstValueNode;\n\t\ttype: GraphQLInputType;\n\t\twhere: string;\n\t}[] = [];\n\t/** The input types a value can break a constraint inside. */\n\treadonly #constrained = new Set<string>();\n\n\tconstructor(schema: GraphQLSchema) {\n\t\tthis.directive = schema.getDirective('constraint') ?? undefined;\n\t\tconst objects = Object.values(schema.getTypeMap()).filter(\n\t\t\tisInputObjectType,\n\t\t);\n\t\t// A fixpoint, not a memoised walk: in a cycle, a type visited while it\n\t\t// is still being decided would be cached as unconstrained for good.\n\t\tfor (let changed = true; changed; ) {\n\t\t\tchanged = false;\n\t\t\tfor (const type of objects) {\n\t\t\t\tif (this.#constrained.has(type.name)) continue;\n\t\t\t\tconst constrained = Object.values(type.getFields()).some(\n\t\t\t\t\t(field) =>\n\t\t\t\t\t\tconstraintsOn(this.directive, field.astNode).length > 0 ||\n\t\t\t\t\t\tthis.isConstrained(field.type),\n\t\t\t\t);\n\t\t\t\tif (constrained) {\n\t\t\t\t\tthis.#constrained.add(type.name);\n\t\t\t\t\tchanged = true;\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n\n\t/** Whether a value of this type can break a constraint anywhere inside. */\n\tisConstrained(type: GraphQLInputType): boolean {\n\t\tconst named = getNamedType(type);\n\t\treturn isInputObjectType(named) && this.#constrained.has(named.name);\n\t}\n\n\t/**\n\t * Builds every constrained input type, reached by an argument or not, so\n\t * a constraint that cannot apply fails at startup wherever it is written.\n\t */\n\tbuildAll(schema: GraphQLSchema): void {\n\t\tfor (const type of Object.values(schema.getTypeMap())) {\n\t\t\tif (isInputObjectType(type)) this.#object(type);\n\t\t}\n\t}\n\n\t/** Whether an argument or input field needs checking at all. */\n\tneedsCheck(input: GraphQLArgument | GraphQLInputField): boolean {\n\t\treturn (\n\t\t\tconstraintsOn(this.directive, input.astNode).length > 0 ||\n\t\t\tthis.isConstrained(input.type)\n\t\t);\n\t}\n\n\t/** The schema of one argument or input field, `where` naming it in errors. */\n\tof(input: GraphQLArgument | GraphQLInputField, where: string): z.ZodType {\n\t\tconst schema = this.#typed(\n\t\t\tinput.type,\n\t\t\tconstraintsOn(this.directive, input.astNode),\n\t\t\twhere,\n\t\t);\n\t\tconst literal = input.astNode?.defaultValue;\n\t\tif (literal)\n\t\t\tthis.#defaults.push({ schema, literal, type: input.type, where });\n\t\treturn schema;\n\t}\n\n\t/**\n\t * Fails when a default value breaks its own constraint: every request that\n\t * leaves the value out would be refused for something the client never\n\t * sent. Run once every schema is built, so a recursive type is complete.\n\t */\n\tcheckDefaults(): void {\n\t\tfor (const { schema, literal, type, where } of this.#defaults.splice(0)) {\n\t\t\t// Coerced as graphql coerces it: a single value for a list, an input\n\t\t\t// object's own field defaults. One graphql refuses is its to report.\n\t\t\tconst value = valueFromAST(literal, type);\n\t\t\tif (value === undefined) continue;\n\t\t\tconst result = schema.safeParse(value);\n\t\t\tif (!result.success) {\n\t\t\t\tthrow new Error(\n\t\t\t\t\t`The default value of ${where} breaks its @constraint: ${result.error.issues[0]?.message}`,\n\t\t\t\t);\n\t\t\t}\n\t\t}\n\t}\n\n\t#typed(\n\t\ttype: GraphQLInputType,\n\t\tconstraints: readonly Constraint[],\n\t\twhere: string,\n\t): z.ZodType {\n\t\tif (isNonNullType(type))\n\t\t\treturn this.#required(type.ofType, constraints, where);\n\t\treturn this.#required(type, constraints, where).nullish();\n\t}\n\n\t#required(\n\t\ttype: GraphQLInputType,\n\t\tconstraints: readonly Constraint[],\n\t\twhere: string,\n\t): z.ZodType {\n\t\tif (isNonNullType(type))\n\t\t\treturn this.#required(type.ofType, constraints, where);\n\t\tif (isListType(type)) {\n\t\t\t// minItems and maxItems are the list's; every other rule is its items'.\n\t\t\tconst own = constraints.filter(({ rule }) => rule.target === 'list');\n\t\t\tconst items = constraints.filter(({ rule }) => rule.target !== 'list');\n\t\t\tlet list: z.ZodType = z.array(this.#typed(type.ofType, items, where));\n\t\t\tfor (const { rule, value } of own) list = applyRule(rule, list, value);\n\t\t\treturn list;\n\t\t}\n\t\tif (isInputObjectType(type)) {\n\t\t\tassertObjectTargets(type.name, constraints, where);\n\t\t\treturn this.#object(type);\n\t\t}\n\t\treturn leafSchema(type, constraints, where);\n\t}\n\n\t#object(type: GraphQLInputObjectType): z.ZodType {\n\t\tif (!this.isConstrained(type)) return z.unknown();\n\t\tconst built = this.#objects.get(type.name);\n\t\tif (built) return built;\n\t\t// Registered before the walk, so a field that comes back here ends.\n\t\tlet schema: z.ZodType | undefined;\n\t\tthis.#objects.set(\n\t\t\ttype.name,\n\t\t\tz.lazy(() => schema as z.ZodType),\n\t\t);\n\t\tschema = z.object(\n\t\t\tObject.fromEntries(\n\t\t\t\tObject.values(type.getFields()).map((field) => [\n\t\t\t\t\tfield.name,\n\t\t\t\t\tthis.of(field, `${type.name}.${field.name}`),\n\t\t\t\t]),\n\t\t\t),\n\t\t);\n\t\tthis.#objects.set(type.name, schema);\n\t\treturn schema;\n\t}\n}\n",
|
|
9
|
-
"import {\n\tGraphQLBoolean,\n\tGraphQLFloat,\n\tGraphQLID,\n\tGraphQLInt,\n\ttype GraphQLLeafType,\n\tGraphQLString,\n} from 'graphql';\nimport { z } from 'zod';\nimport { applyRule } from '../rules';\nimport type { Target } from '../rules/rule';\nimport type { Constraint } from './constraints';\n\n/** The kind of value each built-in scalar holds once graphql parsed it. */\nconst kinds: Record<string, Exclude<Target, 'list'>> = {\n\t[GraphQLString.name]: 'string',\n\t[GraphQLID.name]: 'string',\n\t[GraphQLInt.name]: 'number',\n\t[GraphQLFloat.name]: 'number',\n};\n\nfunction baseOf(type: GraphQLLeafType): z.ZodType {\n\tif (type.name === GraphQLInt.name) return z.number().int();\n\treturn kinds[type.name] === 'number' ? z.number() : z.string();\n}\n\n/**\n * Fails unless every constraint applies to a value of `type`: `minLength` on\n * an `Int`, anything on a custom scalar or an enum, fails, naming `where`.\n * The runtime and the code generator refuse the same schemas with the same\n * message.\n */\nexport function assertLeafTargets(\n\ttype: GraphQLLeafType,\n\tconstraints: readonly Constraint[],\n\twhere: string,\n): void {\n\tconst misplaced = constraints.find(({ rule }) => rule.target === 'list');\n\tif (misplaced) throw misplacedOn(misplaced, where, type.name);\n\tconst kind = kinds[type.name];\n\tconst wrong = constraints.find(({ rule }) => rule.target !== kind);\n\tif (wrong) throw misplacedOn(wrong, where, type.name);\n}\n\n/** Fails when an input object carries a constraint: none applies to it. */\nexport function assertObjectTargets(\n\ttypeName: string,\n\tconstraints: readonly Constraint[],\n\twhere: string,\n): void {\n\tconst first =\n\t\tconstraints.find(({ rule }) => rule.target === 'list') ?? constraints[0];\n\tif (first) throw misplacedOn(first, where, typeName);\n}\n\nfunction misplacedOn(\n\t{ rule }: Constraint,\n\twhere: string,\n\ttypeName: string,\n): Error {\n\treturn new Error(\n\t\t`@constraint(${rule.argument}) on ${where} needs ${describeTarget(rule.target)}, not ${typeName}.`,\n\t);\n}\n\n/**\n * The schema of a scalar or enum value with its constraints applied. A leaf\n * without any is left as graphql parsed it. A constraint that cannot apply\n * fails here, at startup.\n */\nexport function leafSchema(\n\ttype: GraphQLLeafType,\n\tconstraints: readonly Constraint[],\n\twhere: string,\n): z.ZodType {\n\tif (constraints.length === 0) return z.unknown();\n\tassertLeafTargets(type, constraints, where);\n\tlet schema = baseOf(type);\n\tfor (const { rule, value } of constraints) {\n\t\tschema = applyRule(rule, schema, value);\n\t}\n\treturn schema;\n}\n\n/** The source of a built-in scalar's schema, before its constraints. */\nexport function baseCode(type: GraphQLLeafType): string | undefined {\n\t// graphql's Int is 32-bit: the client refuses what it refuses.\n\tif (type.name === GraphQLInt.name) return 'z.int32()';\n\tif (type.name === GraphQLFloat.name) return 'z.number()';\n\tif (type.name === GraphQLBoolean.name) return 'z.boolean()';\n\treturn kinds[type.name] === 'string' ? 'z.string()' : undefined;\n}\n\n/** What a rule's target reads as in an error. */\nexport function describeTarget(target: Target): string {\n\tif (target === 'string') return 'a String or an ID';\n\tif (target === 'number') return 'an Int or a Float';\n\treturn 'a list';\n}\n"
|
|
10
|
-
],
|
|
11
|
-
"mappings": "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",
|
|
12
|
-
"debugId": "7C317F3D691975BE64756E2164756E21",
|
|
13
|
-
"names": []
|
|
14
|
-
}
|