typespec-http-zod 0.29.0 → 0.31.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.
package/dist/src/lib.d.ts CHANGED
@@ -132,17 +132,23 @@ export declare const $lib: import("@typespec/compiler").TypeSpecLibrary<{
132
132
  "unsupported-type": {
133
133
  readonly default: import("@typespec/compiler").CallableMessage<["artefact", "kind", "why", "remedy"]>;
134
134
  };
135
+ "invalid-default": {
136
+ readonly default: import("@typespec/compiler").CallableMessage<["name", "why"]>;
137
+ };
135
138
  "unsupported-default": {
136
139
  readonly default: import("@typespec/compiler").CallableMessage<["why"]>;
137
140
  };
138
141
  "default-on-required-property": {
139
142
  readonly default: import("@typespec/compiler").CallableMessage<["name", "name", "name"]>;
143
+ readonly discriminator: import("@typespec/compiler").CallableMessage<["name"]>;
144
+ readonly ancestor: import("@typespec/compiler").CallableMessage<["name"]>;
140
145
  };
141
146
  "truncated-doc-comment": {
142
147
  readonly default: import("@typespec/compiler").CallableMessage<["name", "tag", "tag"]>;
143
148
  };
144
149
  "undeclared-discriminator": {
145
150
  readonly default: import("@typespec/compiler").CallableMessage<["name", "property", "variant", "property", "variant"]>;
151
+ readonly open: import("@typespec/compiler").CallableMessage<["name", "property", "variant", "property", "variant"]>;
146
152
  };
147
153
  "empty-union": {
148
154
  readonly default: import("@typespec/compiler").CallableMessage<["why"]>;
@@ -150,6 +156,17 @@ export declare const $lib: import("@typespec/compiler").TypeSpecLibrary<{
150
156
  "unmirrorable-seal": {
151
157
  readonly default: import("@typespec/compiler").CallableMessage<["sealed", "open"]>;
152
158
  };
159
+ "invalid-subtype-discriminator": {
160
+ readonly default: import("@typespec/compiler").CallableMessage<["name", "base", "property", "why", "property", "name", "property"]>;
161
+ readonly invisible: import("@typespec/compiler").CallableMessage<["name", "base", "property", "why", "property", "at", "name", "name", "property"]>;
162
+ };
163
+ "sealed-base-extended": {
164
+ readonly default: import("@typespec/compiler").CallableMessage<["name", "base", "name", "base", "keys", "name", "name", "base"]>;
165
+ };
166
+ "unrepresentable-override": {
167
+ readonly default: import("@typespec/compiler").CallableMessage<["model", "name", "base", "declared", "why", "name", "model", "declared"]>;
168
+ readonly recursive: import("@typespec/compiler").CallableMessage<["model", "name", "base", "name", "name", "model", "declared"]>;
169
+ };
153
170
  "unknown-key-vocabulary": {
154
171
  readonly default: import("@typespec/compiler").CallableMessage<["name", "service"]>;
155
172
  };
@@ -159,8 +176,8 @@ export declare const $lib: import("@typespec/compiler").TypeSpecLibrary<{
159
176
  "non-unicode-pattern": {
160
177
  readonly default: import("@typespec/compiler").CallableMessage<["pattern"]>;
161
178
  };
162
- "unenforceable-encoded-bound": {
163
- readonly default: import("@typespec/compiler").CallableMessage<["name"]>;
179
+ "unenforceable-encoded-constraint": {
180
+ readonly default: import("@typespec/compiler").CallableMessage<["keywords", "name", "type", "keywords", "type"]>;
164
181
  };
165
182
  "unenforceable-property-name": {
166
183
  readonly default: import("@typespec/compiler").CallableMessage<["name"]>;
@@ -174,25 +191,61 @@ export declare const $lib: import("@typespec/compiler").TypeSpecLibrary<{
174
191
  "inline-cycle": {
175
192
  readonly default: import("@typespec/compiler").CallableMessage<["type"]>;
176
193
  };
194
+ "never-body": {
195
+ readonly default: import("@typespec/compiler").CallableMessage<["operationId", "position"]>;
196
+ };
197
+ "unsatisfiable-encoding": {
198
+ readonly default: import("@typespec/compiler").CallableMessage<["name", "declared", "encoded", "why"]>;
199
+ };
200
+ "header-case-collision": {
201
+ readonly default: import("@typespec/compiler").CallableMessage<["operation", "first", "second"]>;
202
+ };
203
+ "shared-input-key": {
204
+ readonly default: import("@typespec/compiler").CallableMessage<["operation", "first", "key", "second", "key", "key"]>;
205
+ readonly repeated: import("@typespec/compiler").CallableMessage<["operation", "first", "key"]>;
206
+ };
207
+ "split-visibility": {
208
+ readonly default: import("@typespec/compiler").CallableMessage<["name", "via", "model", "at", "property", "effect", "name", "remedy"]>;
209
+ readonly inherited: import("@typespec/compiler").CallableMessage<["name", "model", "model", "via", "model", "at", "property", "effect", "remedy"]>;
210
+ readonly inline: import("@typespec/compiler").CallableMessage<["model", "at", "property", "effect", "remedy"]>;
211
+ };
212
+ "ambiguous-form-reading": {
213
+ readonly default: import("@typespec/compiler").CallableMessage<["operation", "union", "member", "key", "first", "second", "other", "key", "member", "other"]>;
214
+ };
177
215
  "duplicate-declaration": {
178
216
  readonly default: import("@typespec/compiler").CallableMessage<["name"]>;
217
+ readonly renamed: import("@typespec/compiler").CallableMessage<["first", "second", "name"]>;
218
+ readonly multipart: import("@typespec/compiler").CallableMessage<["name"]>;
219
+ readonly envelope: import("@typespec/compiler").CallableMessage<["name"]>;
220
+ readonly instances: import("@typespec/compiler").CallableMessage<["name", "name"]>;
221
+ readonly binary: import("@typespec/compiler").CallableMessage<["name"]>;
222
+ readonly cased: import("@typespec/compiler").CallableMessage<["first", "second", "name"]>;
223
+ readonly suffixed: import("@typespec/compiler").CallableMessage<["name", "first", "at", "second", "second"]>;
224
+ readonly visibility: import("@typespec/compiler").CallableMessage<["name", "first", "second", "remedy"]>;
225
+ readonly context: import("@typespec/compiler").CallableMessage<["name"]>;
179
226
  };
180
227
  }, EmitterOptions, never>;
181
- export declare const reportDiagnostic: <C extends "default-on-required-property" | "duplicate-declaration" | "duplicate-operation-id" | "empty-union" | "inline-cycle" | "non-unicode-pattern" | "optional-prototype-name" | "truncated-doc-comment" | "undeclared-discriminator" | "unenforceable-encoded-bound" | "unenforceable-property-name" | "unknown-key-vocabulary" | "unmirrorable-seal" | "unsupported-default" | "unsupported-status-code-range" | "unsupported-type", M extends keyof {
228
+ export declare const reportDiagnostic: <C extends "ambiguous-form-reading" | "default-on-required-property" | "duplicate-declaration" | "duplicate-operation-id" | "empty-union" | "header-case-collision" | "inline-cycle" | "invalid-default" | "invalid-subtype-discriminator" | "never-body" | "non-unicode-pattern" | "optional-prototype-name" | "sealed-base-extended" | "shared-input-key" | "split-visibility" | "truncated-doc-comment" | "undeclared-discriminator" | "unenforceable-encoded-constraint" | "unenforceable-property-name" | "unknown-key-vocabulary" | "unmirrorable-seal" | "unrepresentable-override" | "unsatisfiable-encoding" | "unsupported-default" | "unsupported-status-code-range" | "unsupported-type", M extends keyof {
182
229
  "unsupported-type": {
183
230
  readonly default: import("@typespec/compiler").CallableMessage<["artefact", "kind", "why", "remedy"]>;
184
231
  };
232
+ "invalid-default": {
233
+ readonly default: import("@typespec/compiler").CallableMessage<["name", "why"]>;
234
+ };
185
235
  "unsupported-default": {
186
236
  readonly default: import("@typespec/compiler").CallableMessage<["why"]>;
187
237
  };
188
238
  "default-on-required-property": {
189
239
  readonly default: import("@typespec/compiler").CallableMessage<["name", "name", "name"]>;
240
+ readonly discriminator: import("@typespec/compiler").CallableMessage<["name"]>;
241
+ readonly ancestor: import("@typespec/compiler").CallableMessage<["name"]>;
190
242
  };
191
243
  "truncated-doc-comment": {
192
244
  readonly default: import("@typespec/compiler").CallableMessage<["name", "tag", "tag"]>;
193
245
  };
194
246
  "undeclared-discriminator": {
195
247
  readonly default: import("@typespec/compiler").CallableMessage<["name", "property", "variant", "property", "variant"]>;
248
+ readonly open: import("@typespec/compiler").CallableMessage<["name", "property", "variant", "property", "variant"]>;
196
249
  };
197
250
  "empty-union": {
198
251
  readonly default: import("@typespec/compiler").CallableMessage<["why"]>;
@@ -200,6 +253,17 @@ export declare const reportDiagnostic: <C extends "default-on-required-property"
200
253
  "unmirrorable-seal": {
201
254
  readonly default: import("@typespec/compiler").CallableMessage<["sealed", "open"]>;
202
255
  };
256
+ "invalid-subtype-discriminator": {
257
+ readonly default: import("@typespec/compiler").CallableMessage<["name", "base", "property", "why", "property", "name", "property"]>;
258
+ readonly invisible: import("@typespec/compiler").CallableMessage<["name", "base", "property", "why", "property", "at", "name", "name", "property"]>;
259
+ };
260
+ "sealed-base-extended": {
261
+ readonly default: import("@typespec/compiler").CallableMessage<["name", "base", "name", "base", "keys", "name", "name", "base"]>;
262
+ };
263
+ "unrepresentable-override": {
264
+ readonly default: import("@typespec/compiler").CallableMessage<["model", "name", "base", "declared", "why", "name", "model", "declared"]>;
265
+ readonly recursive: import("@typespec/compiler").CallableMessage<["model", "name", "base", "name", "name", "model", "declared"]>;
266
+ };
203
267
  "unknown-key-vocabulary": {
204
268
  readonly default: import("@typespec/compiler").CallableMessage<["name", "service"]>;
205
269
  };
@@ -209,8 +273,8 @@ export declare const reportDiagnostic: <C extends "default-on-required-property"
209
273
  "non-unicode-pattern": {
210
274
  readonly default: import("@typespec/compiler").CallableMessage<["pattern"]>;
211
275
  };
212
- "unenforceable-encoded-bound": {
213
- readonly default: import("@typespec/compiler").CallableMessage<["name"]>;
276
+ "unenforceable-encoded-constraint": {
277
+ readonly default: import("@typespec/compiler").CallableMessage<["keywords", "name", "type", "keywords", "type"]>;
214
278
  };
215
279
  "unenforceable-property-name": {
216
280
  readonly default: import("@typespec/compiler").CallableMessage<["name"]>;
@@ -224,24 +288,60 @@ export declare const reportDiagnostic: <C extends "default-on-required-property"
224
288
  "inline-cycle": {
225
289
  readonly default: import("@typespec/compiler").CallableMessage<["type"]>;
226
290
  };
291
+ "never-body": {
292
+ readonly default: import("@typespec/compiler").CallableMessage<["operationId", "position"]>;
293
+ };
294
+ "unsatisfiable-encoding": {
295
+ readonly default: import("@typespec/compiler").CallableMessage<["name", "declared", "encoded", "why"]>;
296
+ };
297
+ "header-case-collision": {
298
+ readonly default: import("@typespec/compiler").CallableMessage<["operation", "first", "second"]>;
299
+ };
300
+ "shared-input-key": {
301
+ readonly default: import("@typespec/compiler").CallableMessage<["operation", "first", "key", "second", "key", "key"]>;
302
+ readonly repeated: import("@typespec/compiler").CallableMessage<["operation", "first", "key"]>;
303
+ };
304
+ "split-visibility": {
305
+ readonly default: import("@typespec/compiler").CallableMessage<["name", "via", "model", "at", "property", "effect", "name", "remedy"]>;
306
+ readonly inherited: import("@typespec/compiler").CallableMessage<["name", "model", "model", "via", "model", "at", "property", "effect", "remedy"]>;
307
+ readonly inline: import("@typespec/compiler").CallableMessage<["model", "at", "property", "effect", "remedy"]>;
308
+ };
309
+ "ambiguous-form-reading": {
310
+ readonly default: import("@typespec/compiler").CallableMessage<["operation", "union", "member", "key", "first", "second", "other", "key", "member", "other"]>;
311
+ };
227
312
  "duplicate-declaration": {
228
313
  readonly default: import("@typespec/compiler").CallableMessage<["name"]>;
314
+ readonly renamed: import("@typespec/compiler").CallableMessage<["first", "second", "name"]>;
315
+ readonly multipart: import("@typespec/compiler").CallableMessage<["name"]>;
316
+ readonly envelope: import("@typespec/compiler").CallableMessage<["name"]>;
317
+ readonly instances: import("@typespec/compiler").CallableMessage<["name", "name"]>;
318
+ readonly binary: import("@typespec/compiler").CallableMessage<["name"]>;
319
+ readonly cased: import("@typespec/compiler").CallableMessage<["first", "second", "name"]>;
320
+ readonly suffixed: import("@typespec/compiler").CallableMessage<["name", "first", "at", "second", "second"]>;
321
+ readonly visibility: import("@typespec/compiler").CallableMessage<["name", "first", "second", "remedy"]>;
322
+ readonly context: import("@typespec/compiler").CallableMessage<["name"]>;
229
323
  };
230
324
  }[C]>(program: import("@typespec/compiler").Program, diag: import("@typespec/compiler").DiagnosticReport<{
231
325
  "unsupported-type": {
232
326
  readonly default: import("@typespec/compiler").CallableMessage<["artefact", "kind", "why", "remedy"]>;
233
327
  };
328
+ "invalid-default": {
329
+ readonly default: import("@typespec/compiler").CallableMessage<["name", "why"]>;
330
+ };
234
331
  "unsupported-default": {
235
332
  readonly default: import("@typespec/compiler").CallableMessage<["why"]>;
236
333
  };
237
334
  "default-on-required-property": {
238
335
  readonly default: import("@typespec/compiler").CallableMessage<["name", "name", "name"]>;
336
+ readonly discriminator: import("@typespec/compiler").CallableMessage<["name"]>;
337
+ readonly ancestor: import("@typespec/compiler").CallableMessage<["name"]>;
239
338
  };
240
339
  "truncated-doc-comment": {
241
340
  readonly default: import("@typespec/compiler").CallableMessage<["name", "tag", "tag"]>;
242
341
  };
243
342
  "undeclared-discriminator": {
244
343
  readonly default: import("@typespec/compiler").CallableMessage<["name", "property", "variant", "property", "variant"]>;
344
+ readonly open: import("@typespec/compiler").CallableMessage<["name", "property", "variant", "property", "variant"]>;
245
345
  };
246
346
  "empty-union": {
247
347
  readonly default: import("@typespec/compiler").CallableMessage<["why"]>;
@@ -249,6 +349,17 @@ export declare const reportDiagnostic: <C extends "default-on-required-property"
249
349
  "unmirrorable-seal": {
250
350
  readonly default: import("@typespec/compiler").CallableMessage<["sealed", "open"]>;
251
351
  };
352
+ "invalid-subtype-discriminator": {
353
+ readonly default: import("@typespec/compiler").CallableMessage<["name", "base", "property", "why", "property", "name", "property"]>;
354
+ readonly invisible: import("@typespec/compiler").CallableMessage<["name", "base", "property", "why", "property", "at", "name", "name", "property"]>;
355
+ };
356
+ "sealed-base-extended": {
357
+ readonly default: import("@typespec/compiler").CallableMessage<["name", "base", "name", "base", "keys", "name", "name", "base"]>;
358
+ };
359
+ "unrepresentable-override": {
360
+ readonly default: import("@typespec/compiler").CallableMessage<["model", "name", "base", "declared", "why", "name", "model", "declared"]>;
361
+ readonly recursive: import("@typespec/compiler").CallableMessage<["model", "name", "base", "name", "name", "model", "declared"]>;
362
+ };
252
363
  "unknown-key-vocabulary": {
253
364
  readonly default: import("@typespec/compiler").CallableMessage<["name", "service"]>;
254
365
  };
@@ -258,8 +369,8 @@ export declare const reportDiagnostic: <C extends "default-on-required-property"
258
369
  "non-unicode-pattern": {
259
370
  readonly default: import("@typespec/compiler").CallableMessage<["pattern"]>;
260
371
  };
261
- "unenforceable-encoded-bound": {
262
- readonly default: import("@typespec/compiler").CallableMessage<["name"]>;
372
+ "unenforceable-encoded-constraint": {
373
+ readonly default: import("@typespec/compiler").CallableMessage<["keywords", "name", "type", "keywords", "type"]>;
263
374
  };
264
375
  "unenforceable-property-name": {
265
376
  readonly default: import("@typespec/compiler").CallableMessage<["name"]>;
@@ -273,7 +384,37 @@ export declare const reportDiagnostic: <C extends "default-on-required-property"
273
384
  "inline-cycle": {
274
385
  readonly default: import("@typespec/compiler").CallableMessage<["type"]>;
275
386
  };
387
+ "never-body": {
388
+ readonly default: import("@typespec/compiler").CallableMessage<["operationId", "position"]>;
389
+ };
390
+ "unsatisfiable-encoding": {
391
+ readonly default: import("@typespec/compiler").CallableMessage<["name", "declared", "encoded", "why"]>;
392
+ };
393
+ "header-case-collision": {
394
+ readonly default: import("@typespec/compiler").CallableMessage<["operation", "first", "second"]>;
395
+ };
396
+ "shared-input-key": {
397
+ readonly default: import("@typespec/compiler").CallableMessage<["operation", "first", "key", "second", "key", "key"]>;
398
+ readonly repeated: import("@typespec/compiler").CallableMessage<["operation", "first", "key"]>;
399
+ };
400
+ "split-visibility": {
401
+ readonly default: import("@typespec/compiler").CallableMessage<["name", "via", "model", "at", "property", "effect", "name", "remedy"]>;
402
+ readonly inherited: import("@typespec/compiler").CallableMessage<["name", "model", "model", "via", "model", "at", "property", "effect", "remedy"]>;
403
+ readonly inline: import("@typespec/compiler").CallableMessage<["model", "at", "property", "effect", "remedy"]>;
404
+ };
405
+ "ambiguous-form-reading": {
406
+ readonly default: import("@typespec/compiler").CallableMessage<["operation", "union", "member", "key", "first", "second", "other", "key", "member", "other"]>;
407
+ };
276
408
  "duplicate-declaration": {
277
409
  readonly default: import("@typespec/compiler").CallableMessage<["name"]>;
410
+ readonly renamed: import("@typespec/compiler").CallableMessage<["first", "second", "name"]>;
411
+ readonly multipart: import("@typespec/compiler").CallableMessage<["name"]>;
412
+ readonly envelope: import("@typespec/compiler").CallableMessage<["name"]>;
413
+ readonly instances: import("@typespec/compiler").CallableMessage<["name", "name"]>;
414
+ readonly binary: import("@typespec/compiler").CallableMessage<["name"]>;
415
+ readonly cased: import("@typespec/compiler").CallableMessage<["first", "second", "name"]>;
416
+ readonly suffixed: import("@typespec/compiler").CallableMessage<["name", "first", "at", "second", "second"]>;
417
+ readonly visibility: import("@typespec/compiler").CallableMessage<["name", "first", "second", "remedy"]>;
418
+ readonly context: import("@typespec/compiler").CallableMessage<["name"]>;
278
419
  };
279
420
  }, C, M>) => void;
package/dist/src/lib.js CHANGED
@@ -67,7 +67,21 @@ const diagnostics = {
67
67
  "unsupported-type": {
68
68
  severity: "error",
69
69
  messages: {
70
- default: paramMessage `Cannot emit ${"artefact"} for ${"kind"}: ${"why"}. Replace it with a type a value can inhabit. ${"remedy"}`,
70
+ default: paramMessage `Cannot emit ${"artefact"} for ${"kind"}: ${"why"}. Replace or remove the declaration: ${"remedy"}`,
71
+ },
72
+ },
73
+ /**
74
+ * **A default that is no value the position accepts.** openapi3 publishes a default as the JSON it
75
+ * serializes, beside a schema the default need not satisfy - an encoding can change the type
76
+ * under it, a constraint can rule out the literal it names, a key it sets can be one the position
77
+ * does not declare. Filled in, it handed the handler a value its own type refuses, and the module
78
+ * did not compile. A warning, because the property itself is still validated as the document
79
+ * says; only the fallback is dropped.
80
+ */
81
+ "invalid-default": {
82
+ severity: "warning",
83
+ messages: {
84
+ default: paramMessage `The default of '${"name"}' is not emitted: ${"why"}, so filling it in would hand the handler a value the property refuses. Replace it with a value the property accepts, or remove it.`,
71
85
  },
72
86
  },
73
87
  "unsupported-default": {
@@ -110,6 +124,8 @@ const diagnostics = {
110
124
  severity: "warning",
111
125
  messages: {
112
126
  default: paramMessage `'${"name"}' is required, so its default can never apply: a required property is never absent. The OpenAPI document publishes it in 'required' and carries the default only as an annotation, and this validator does the same - a request omitting '${"name"}' is refused. Declare it optional, '${"name"}?: ... = ...', if callers may omit it.`,
127
+ discriminator: paramMessage `'${"name"}' is a discriminator, which '@typespec/openapi3' always publishes in its base's 'required', so it is required here however it is declared and its default can never apply. The validator refuses a value omitting it, as the document does. Remove the '?' and the default.`,
128
+ ancestor: paramMessage `'${"name"}' is required by a declaration of its key above it, which the document holds the value to through 'allOf', so it is required here however it is declared and its default can never apply. The validator refuses a value omitting it, as the document does. Remove the '?' and the default, or make the declaration above optional.`,
113
129
  },
114
130
  },
115
131
  /**
@@ -184,6 +200,7 @@ const diagnostics = {
184
200
  severity: "error",
185
201
  messages: {
186
202
  default: paramMessage `'${"name"}' serialises with '${"property"}' inside each variant, but '${"variant"}' does not declare it - so the OpenAPI document omits it, which OpenAPI 3.1 forbids for a discriminator ("the discriminator field MUST be a required field"). Emitting a validator that required it anyway would enforce a rule the published contract does not state. Declare '${"property"}' on '${"variant"}'.`,
203
+ open: paramMessage `'${"name"}' serialises with '${"property"}' inside each variant, but '${"variant"}' declares it as no one fixed value, so nothing can tell its values from another variant's and no dispatch can hold it. Declare '${"property"}' on '${"variant"}' as the literal its variant name says.`,
187
204
  },
188
205
  },
189
206
  "empty-union": {
@@ -220,6 +237,60 @@ const diagnostics = {
220
237
  default: paramMessage `'seal-object-schemas' resolves to true for ${"sealed"} and false for ${"open"}, and '@typespec/openapi3' has no per-service options - it applies one value to the whole program. So one of these services would publish a document that disagrees with the validator emitted beside it. Give every service the same value, or split the surfaces into separate compiles.`,
221
238
  },
222
239
  },
240
+ /**
241
+ * **A model a discriminated base's `mapping` names, which no dispatch can hold.**
242
+ *
243
+ * The mapping names a subtype for the values its discriminator fixes, and a dispatch reads one
244
+ * fixed value per subtype. A subtype whose discriminator is not fixed - `"lab" | string`, or `kind`
245
+ * renamed with `@encodedName` so its base's open `string` is what it publishes - made Zod throw
246
+ * "Invalid discriminated union option" on import or on the first parse. A subtype whose value a
247
+ * declaration above it refuses - `kind: "cobra"` under `@maxLength(3)` - is published as `allOf`
248
+ * that declaration, so no value is one, and was accepted.
249
+ *
250
+ * **An error, as `undeclared-discriminator` is**: the spec says something the document cannot
251
+ * hold as a dispatch, so it is refused rather than read some other way, and the base dispatches to
252
+ * its other subtypes until it is fixed.
253
+ */
254
+ "invalid-subtype-discriminator": {
255
+ severity: "error",
256
+ messages: {
257
+ default: paramMessage `'${"name"}' is named by the mapping of '${"base"}''s discriminator '${"property"}', and ${"why"}. Declare '${"property"}' on '${"name"}' as one fixed value that every declaration of '${"property"}' above it admits.`,
258
+ invisible: paramMessage `'${"name"}' is named by the mapping of '${"base"}''s discriminator '${"property"}', and ${"why"}. Make '${"property"}' visible at '${"at"}' on '${"name"}' and every model above it that declares it: a value is told as a '${"name"}' by its '${"property"}'.`,
259
+ },
260
+ },
261
+ /**
262
+ * **A template instance that adds properties to a base openapi3 seals.**
263
+ *
264
+ * openapi3 seals a model with no derived models it publishes, and does not count a template
265
+ * instance as one, so under `seal-object-schemas` `Pet<string> extends Animal` leaves `Animal`
266
+ * sealed. `Pet<string>` is published as `allOf` that sealed `Animal`, whose own
267
+ * `unevaluatedProperties` cannot see `Pet<string>`'s properties - so the document refuses every
268
+ * value carrying one. An error, because the published schema refuses what the spec declares, and
269
+ * no validator can agree with both.
270
+ */
271
+ "sealed-base-extended": {
272
+ severity: "error",
273
+ messages: {
274
+ default: paramMessage `'${"name"}' extends '${"base"}', which '@typespec/openapi3' seals under 'seal-object-schemas' because it does not count a template instance as a derived model. The document publishes '${"name"}' as 'allOf' the sealed '${"base"}', so it refuses every value carrying ${"keys"}, which '${"name"}' adds. Declare it as a model of its own with 'model ... is ${"name"}', which openapi3 counts as derived and so leaves '${"base"}' open.`,
275
+ },
276
+ },
277
+ /**
278
+ * **A redeclared property no one validator can hold to both of its declarations.**
279
+ *
280
+ * openapi3 publishes a subtype as `allOf` its base, so a property the subtype redeclares must meet
281
+ * every declaration of it. Where the subtype's narrows the base's - a derived scalar, a model that
282
+ * extends it, a literal the base admits - the base's constraints are applied to the subtype's
283
+ * value. Where it does not - a model that only looks like the base's, a scalar that is not one of
284
+ * the base's - the value is held to two schemas, and intersecting them in Zod merged sealed
285
+ * objects' keys and threw on two defaults. Refused rather than read some other way.
286
+ */
287
+ "unrepresentable-override": {
288
+ severity: "error",
289
+ messages: {
290
+ default: paramMessage `'${"model"}' redeclares '${"name"}', which '${"base"}' declares as '${"declared"}', and ${"why"}: the document holds the value to both, and no one validator here can. Declare '${"name"}' on '${"model"}' as '${"declared"}', or as a type derived from it.`,
291
+ recursive: paramMessage `'${"model"}.${"name"}' is held to '${"base"}.${"name"}' as well, through 'allOf', and merging the two declarations refers back to itself. This emitter declares no recursive merge, so the value is refused rather than validated against one of the two. Declare '${"name"}' on '${"model"}' as '${"declared"}', or as a type derived from it.`,
292
+ },
293
+ },
223
294
  "unknown-key-vocabulary": {
224
295
  severity: "error",
225
296
  messages: {
@@ -287,14 +358,25 @@ const diagnostics = {
287
358
  },
288
359
  },
289
360
  /**
361
+ * **A constraint `@encode` has moved onto a JSON type it does not apply to.**
362
+ *
363
+ * openapi3 applies a property's or a scalar's constraints and then lets the encoding replace
364
+ * `type`, so `@encode(string)` on a numeric property publishes `minimum` beside `type: string`,
365
+ * and `@encode("x", int32)` on a string publishes `pattern` beside `type: integer`. JSON Schema
366
+ * ignores each there, so the document asserts nothing, and the validator drops it too: applied,
367
+ * a numeric bound on text became a LENGTH check, and `.regex()` on an integer or `.min()` on a
368
+ * boolean threw when the module loaded. A default of the declared type under an encoding that
369
+ * changes it is the same case: it is no value of the encoded type.
370
+ *
290
371
  * **A diagnostic, not a linter rule**, because here the emitter cannot do what the spec asks: it
291
- * drops a bound the author wrote. That is the case TypeSpec reserves for `$onValidate`-style
292
- * diagnostics, where a linter is for a program that is correct but could be better.
372
+ * drops a rule the author wrote. That is the case TypeSpec reserves for `$onValidate`-style
373
+ * diagnostics, where a linter is for a program that is correct but could be better. It replaces
374
+ * `unenforceable-encoded-bound`, which reported numeric bounds on text and nothing else.
293
375
  */
294
- "unenforceable-encoded-bound": {
376
+ "unenforceable-encoded-constraint": {
295
377
  severity: "warning",
296
378
  messages: {
297
- default: paramMessage `The bound on '${"name"}' cannot be enforced, and is not emitted. '@encode(string)' makes the wire value text, so '@minValue'/'@maxValue' would become a check on how many CHARACTERS it has - '@minValue(10)' would refuse '"42"' - and the exclusive form has no string equivalent at all. The document is no help either: it publishes 'minimum' on a 'type: string' schema, which JSON Schema ignores, so a validator enforcing the bound would refuse what the published contract accepts. Declare the bound as a '@pattern', which the document publishes and every caller can read, or remove '@encode(string)' and let the value be a number.`,
379
+ default: paramMessage `${"keywords"} on '${"name"}' is not emitted: '@encode' makes the wire value a JSON ${"type"}, and ${"keywords"} is written for the declared type. '@typespec/openapi3' publishes it beside 'type: ${"type"}', where JSON Schema ignores a keyword meant for another type and a default is no value of it, so a validator applying it would disagree with the published contract. Declare the rule in a form the encoded value carries, such as a '@pattern' on a string, or remove '@encode'.`,
298
380
  },
299
381
  },
300
382
  /**
@@ -303,7 +385,7 @@ const diagnostics = {
303
385
  * Zod skips a declared `__proto__` key on purpose, so prototype pollution cannot reach through a
304
386
  * parse (colinhacks/zod#6386): a value of any type, or none, is accepted for it and dropped from
305
387
  * the result. The document publishes it like any other property, and nothing emitted can enforce
306
- * it - which is the case `unenforceable-encoded-bound` reports for a bound, for the same reason:
388
+ * it - which is the case `unenforceable-encoded-constraint` reports for a constraint, for the same reason:
307
389
  * the spec is representable, so refusing it would make it emit under one emitter and not the
308
390
  * other, and serving it silently would leave a validator looser than its contract unsaid.
309
391
  *
@@ -380,10 +462,115 @@ const diagnostics = {
380
462
  default: paramMessage `'${"type"}' closes a reference cycle without passing through anything this emitter can declare, so the cycle has no name to reference itself by. A template instantiation is inlined rather than declared, exactly as '@typespec/openapi3' inlines it, and that emitter refuses the same spec with its own 'inline-cycle' error. Give the type a name with '@friendlyName' so it becomes a declaration, or break the cycle.`,
381
463
  },
382
464
  },
465
+ /**
466
+ * **A body declared `never`.** The type has no values, so the body cannot exist, and
467
+ * `@typespec/openapi3` - whose body paths test only for `void` - publishes it as
468
+ * `content: { "application/json": { schema: {} } }`, any value at all. A validator could agree
469
+ * with the spec or with the document, not both, so the declaration is refused. `void` declares no
470
+ * body, and the document publishes it as none.
471
+ */
472
+ "never-body": {
473
+ severity: "error",
474
+ messages: {
475
+ default: paramMessage `'${"operationId"}' declares a ${"position"} body of type 'never', which has no values, and '@typespec/openapi3' publishes it as any JSON value. Replace it with 'void' to declare no body.`,
476
+ },
477
+ },
478
+ /**
479
+ * **An `@encode` whose published schema no value satisfies, or which states no type.**
480
+ *
481
+ * `@typespec/openapi3` keeps the declared type beside the encoded one, so `@encode("x", string)`
482
+ * on a model publishes `{ $ref: Filter, type: "string" }`: an object and a string at once, which
483
+ * nothing is. The same holds for a list model, an integer enum, or a string scalar encoded as
484
+ * `int32`. An encoding to a scalar outside the standard library publishes no `type` at all, which
485
+ * is also how two scalars whose `@encode` name each other once overflowed the stack. This emitter
486
+ * validated the encoded scalar beside each, so a value the document refuses was accepted, or one
487
+ * it accepts refused.
488
+ *
489
+ * **An error, as `undeclared-discriminator` is**: the published contract is not one a validator
490
+ * can agree with, so the declaration is refused rather than read some other way, and the property
491
+ * validates nothing until the spec says what it means.
492
+ */
493
+ "unsatisfiable-encoding": {
494
+ severity: "error",
495
+ messages: {
496
+ default: paramMessage `'${"name"}' is declared '${"declared"}' and encoded as '${"encoded"}': ${"why"}. Encode it as a standard scalar its declared type admits, or remove '@encode'.`,
497
+ },
498
+ },
499
+ /**
500
+ * **Two inputs of one operation handed to its handler under one key.**
501
+ *
502
+ * A handler's input is the path, query, header and cookie groups spread into one object, with the
503
+ * body merged or named beside them. `@header("x") a: string` beside `@query("x") b: int32` therefore
504
+ * reached the handler as one `x`, the header's string replacing the validated number, while the
505
+ * input was typed `number & string`. `@typespec/http` refuses only a path and a query parameter of
506
+ * one name; the rest compiled with no diagnostic (typespec-http-graphql, 2026-10-16).
507
+ *
508
+ * **A warning, because the spec is valid and openapi3 publishes it**: the parameters are distinct on
509
+ * the wire. It is the input this package states that cannot carry both, so the key is typed and
510
+ * validated as both declarations at once, and the contract types still compile. A server emitter
511
+ * reading `EmittedRoute.sharedInputKeys` declines to mount the operation.
512
+ */
513
+ /**
514
+ * **Two header parameters whose names differ only in case**, which HTTP reads as one header and
515
+ * openapi3 publishes as two parameters of that one value. Refused; see `headerCaseCollisionOf`.
516
+ */
517
+ "header-case-collision": {
518
+ severity: "error",
519
+ messages: {
520
+ default: paramMessage `'${"operation"}' declares the header '${"first"}' and the header '${"second"}', which HTTP reads as one header - a header's name is case-insensitive - and openapi3 publishes as two parameters of the one value it carries. Neither is validated. Give one of them a different name.`,
521
+ },
522
+ },
523
+ "shared-input-key": {
524
+ severity: "warning",
525
+ messages: {
526
+ default: paramMessage `'${"operation"}' takes the ${"first"} '${"key"}' and the ${"second"} '${"key"}', and a handler's input holds one value under each key, so '${"key"}' is stated as both declarations at once and accepts only a value satisfying both. Give one of them a different name.`,
527
+ repeated: paramMessage `'${"operation"}' takes the ${"first"} '${"key"}' twice, and the document publishes only the first: the wire carries one value, which is validated and typed as the first declaration, and the second states nothing. Give one of them a different name.`,
528
+ },
529
+ },
530
+ /**
531
+ * **A schema `@typespec/openapi3` publishes with its properties and its `required` read at two
532
+ * visibilities.** openapi3 writes a component from the first reference that reaches it; where that
533
+ * reference is a request's, and the model has nothing to reshape there, its `required` is read at
534
+ * `Read` and its properties at the request's visibility - a read-only property is then required and
535
+ * not declared, or, optional, left out - and every use of the component shares it. Refused, by the
536
+ * maintainer's decision, rather than validated against a schema the document does not hold. See
537
+ * `publicationOf` in `published.ts` for the measured mechanism.
538
+ */
539
+ "split-visibility": {
540
+ severity: "error",
541
+ messages: {
542
+ default: paramMessage `'@typespec/openapi3' publishes '${"name"}' as ${"via"} first reaches it: there it reads the properties of ${"model"} at '${"at"}' and its 'required' at 'Read', so ${"property"} is ${"effect"}, in every use of '${"name"}'. Refused rather than validated against a schema the document does not hold. Use the request's own view, which openapi3 publishes apart: ${"remedy"}.`,
543
+ inherited: paramMessage `'${"name"}' holds ${"model"} through 'allOf', and '@typespec/openapi3' publishes ${"model"} as ${"via"} first reaches it: there it reads the properties of ${"model"} at '${"at"}' and its 'required' at 'Read', so ${"property"} is ${"effect"}, in every model holding it. Refused rather than validated against a schema the document does not hold. Use the request's own view, which openapi3 publishes apart: ${"remedy"}.`,
544
+ inline: paramMessage `'@typespec/openapi3' publishes ${"model"} with its properties read at '${"at"}' and its 'required' at 'Read', so ${"property"} is ${"effect"}. Refused rather than validated against a schema the document does not hold. Use the request's own view, which openapi3 publishes apart: ${"remedy"}.`,
545
+ },
546
+ },
547
+ /**
548
+ * **A `@oneOf` body sent as a URL-encoded form, where a member may read one text two ways and
549
+ * another member accepts one and not the other.** The document accepts the form where some
550
+ * reading of its text matches exactly one member, and which reading that is depends on every key
551
+ * and member - finding it means trying every combination, exponential in the keys, and a record's
552
+ * keys are the sender's to choose. Refused rather than validated by a reading the document need
553
+ * not take. See `ambiguousFormKeyOf`.
554
+ */
555
+ "ambiguous-form-reading": {
556
+ severity: "error",
557
+ messages: {
558
+ default: paramMessage `'${"operation"}' accepts the '@oneOf' '${"union"}' as a URL-encoded form, where '${"member"}' may read the text of ${"key"} as ${"first"} and as ${"second"}, and '${"other"}' accepts only the first. The document takes the form where some reading of its text matches exactly one member, and which reading that is depends on every key and member, so the body is not validated. Give ${"key"} one reading in '${"member"}', declare it alike in '${"other"}', or publish the union as 'anyOf' by removing '@oneOf'.`,
559
+ },
560
+ },
383
561
  "duplicate-declaration": {
384
562
  severity: "error",
385
563
  messages: {
386
564
  default: paramMessage `Two different types are both named '${"name"}', and a TypeScript module cannot declare one name twice. The document tells them apart by namespace; this file cannot. Give one of them a different name, or set an explicit one with '@friendlyName'.`,
565
+ renamed: paramMessage `Two different types, '${"first"}' and '${"second"}', are both declared as '${"name"}': a character an identifier cannot hold is written '_', and a TypeScript module cannot declare one name twice, so neither is validated. Give one of them a different name, or set an explicit one with '@friendlyName'.`,
566
+ multipart: paramMessage `'${"name"}' is a multipart body and the name of a schema that differs from it - the same model sent as JSON is one: openapi3 publishes one component under the name, and a TypeScript module cannot declare one name twice, so neither is validated. Send the multipart body as a model of its own.`,
567
+ envelope: paramMessage `'${"name"}' is the name openapi3 gives an envelope of a '@discriminated' union, after the union and the variant, and the name of another type: a TypeScript module cannot declare one name twice, so neither is validated. Rename the type, the union or the variant.`,
568
+ instances: paramMessage `Two instances of the template '${"name"}' are both named '${"name"}', as openapi3 names a union instance after its template alone: it refuses its own document for them as 'duplicate-type-name', and a TypeScript module cannot declare one name twice, so neither is validated. Declare a named union for each, or set an explicit name with '@friendlyName'.`,
569
+ binary: paramMessage `'${"name"}' holds 'bytes' and is sent as a multipart part, where openapi3 publishes 'bytes' as any value, and used elsewhere, where it is a base64 string: openapi3 publishes both under the name and refuses its own document as 'duplicate-type-name', and a TypeScript module cannot declare one name twice, so neither is validated. Give the part a union of its own.`,
570
+ cased: paramMessage `Two different types, '${"first"}' and '${"second"}', are both validated by '${"name"}': a validator is named for its type with the first letter lowered, and a TypeScript module cannot declare one name twice, so neither is validated. Give one of them a different name, or set an explicit one with '@friendlyName'.`,
571
+ suffixed: paramMessage `'${"name"}' is the name openapi3 gives '${"first"}' at '${"at"}', a type it suffixes for being used at more than one visibility, and the name of '${"second"}': openapi3 refuses its own document for it as 'duplicate-type-name', and a TypeScript module cannot declare one name twice, so neither is validated. Rename '${"second"}', or set an explicit name with '@friendlyName'.`,
572
+ visibility: paramMessage `'${"name"}' is the document's one name for two different schemas of one model, at '${"first"}' and at '${"second"}': openapi3 publishes both under it and refuses its own document as 'duplicate-type-name', and this module cannot declare one name twice, so neither is validated. ${"remedy"}`,
573
+ context: paramMessage `'${"name"}' is published inside an explicit '@body', where '@typespec/http' ignores its metadata annotations and the document holds them as data, and outside one, where they are metadata: two shapes under one name, which '@typespec/openapi3' refuses too, as 'duplicate-type-name'. Mark the body '@bodyRoot', or give the body a model of its own.`,
387
574
  },
388
575
  },
389
576
  };