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/README.md CHANGED
@@ -193,6 +193,25 @@ break the build until the validator and the contract type diverge.
193
193
  Identifiers are named from the operation id the document publishes. An operation inside a namespace
194
194
  carries the whole id, so `op readWidget` in `namespace Widgets` becomes `Widgets_readWidgetPath`.
195
195
 
196
+ Every component the document publishes is declared under its name - `widgetSchema` and `Widget` -
197
+ including the types no operation reaches, which openapi3 publishes at `All`, and those no route
198
+ names, such as a model a merge holds. A type used only by an operation the document leaves out -
199
+ one whose path holds a query string, or an `@overload` on its base operation's endpoint - is
200
+ declared too, as its validators are emitted. A component carries a visibility suffix,
201
+ `WidgetCreate`, only where its type is used at more than one visibility, as openapi3 names it. Four
202
+ names cannot be TypeScript's, and are not: a namespace is dropped, as one module has one, so two
203
+ types of one name in two namespaces are `duplicate-declaration`; a character an identifier cannot
204
+ hold is written `_`, `Hy-phen` as `Hy_phen`, and a name TypeScript refuses for a declaration - a
205
+ reserved word, a predefined type such as `string`, a strict-mode word such as `public`, a type
206
+ operator such as `keyof` - or a name the generated files declare or name for themselves takes a
207
+ trailing `_` - `delete_`, `string_`, `WireReader_`, `ArrayBuffer_`; and
208
+ a scalar is validated inline wherever it is used, since TypeScript cannot carry its constraints. A
209
+ model named `Record`, `Promise`, `Readonly` or `Exclude` keeps its name - the copy a visibility
210
+ template makes of a `Record<T>` instance, which openapi3 publishes as `Record`, included - and every
211
+ generated file names the library's type as `globalThis.Record<...>`. A type published only as a
212
+ reference to another document, by `@useRef`, is refused as `unsupported-type`: the document states
213
+ no schema for it.
214
+
196
215
  ## Docs
197
216
 
198
217
  - [Guides](docs/guides.md): installing, validating a request, answering with the right body, content
package/dist/src/api.d.ts CHANGED
@@ -242,6 +242,11 @@ export interface EmittedRoute {
242
242
  * hands `pathSchema` the TEXT of that segment (for an exploding `/` expression, of every segment
243
243
  * after it), and `pathSchema` undoes the expansion. A segment holding more than one expression is
244
244
  * `unsupported`: no segment router can split it.
245
+ *
246
+ * **For a `/` expression this is the only statement of the route there is.** openapi3 cannot
247
+ * publish the operator: `/lx{/v*}` is `/lx{v}` in the document, under `simple` style and its own
248
+ * `invalid-style` warning, which joins an exploded list `1,2` where the route joins it `1/2`. The
249
+ * validator undoes the route's, as `@typespec/http-specs` expects - see `docs/reference.md`.
245
250
  */
246
251
  readonly pathSegments: readonly EmittedPathSegment[];
247
252
  /**
@@ -257,6 +262,19 @@ export interface EmittedRoute {
257
262
  * a scalar. Empty when there is none, never `undefined`.
258
263
  */
259
264
  readonly decodedPathParameters: readonly string[];
265
+ /**
266
+ * Every pair of inputs a handler would be handed under ONE key - `@header("x")` beside
267
+ * `@query("x")`, two `@query("x")`, a `@path id` beside a `@header("id")`, a parameter named as
268
+ * the body is. Empty for almost every operation.
269
+ *
270
+ * **A server emitter spreads the parameter groups into one input, so the later group's value
271
+ * silently replaced the earlier one**, after each had been validated against its own schema.
272
+ * `@typespec/http` refuses only a path and a query parameter of one name. The handler input has
273
+ * one value per key and cannot carry both, so a server should not mount such an operation; this
274
+ * package reports it as `shared-input-key`, and states the key as both declarations at once. See
275
+ * {@link SharedInputKey}.
276
+ */
277
+ readonly sharedInputKeys: readonly SharedInputKey[];
260
278
  /**
261
279
  * A query string written into the route itself, as the pairs it spells:
262
280
  * `/items?fixed=true{&param}` carries `[["fixed", "true"]]`. It identifies the route as much as
@@ -310,6 +328,26 @@ export interface EmittedRoute {
310
328
  readonly requestTextual: boolean;
311
329
  readonly summary: string | undefined;
312
330
  readonly requestSchema: string | undefined;
331
+ /**
332
+ * **The body as a URL-encoded form carries it**, where the route also takes it under another media
333
+ * type: each field read from the text a form holds - `n=5` is `5` where `n` is an `int32` - and a
334
+ * key sent more than once read as the list it stands for. A server validates a form body with this
335
+ * and any other with {@link requestSchema}. `undefined` where no form is declared, or where only a
336
+ * form is, when `requestSchema` reads it itself: validated as JSON, every numeric or boolean field
337
+ * of a form refused every conformant request.
338
+ */
339
+ readonly formRequestSchema?: string;
340
+ /**
341
+ * **The multipart parts whose value is read from text**, each with whether it is JSON alone: every
342
+ * part but a file and raw bytes. A client may send one with a filename all the same - `curl -F
343
+ * 'r=@data.json;type=application/json'` - and a form reader then hands it over as a file, which
344
+ * the part's schema, reading text, refuses. A server reads such a part's text first. Its media type
345
+ * says what the part is, not the filename. `undefined` where the body is not multipart.
346
+ */
347
+ readonly textParts?: readonly {
348
+ readonly name: string;
349
+ readonly json: boolean;
350
+ }[];
313
351
  /**
314
352
  * The parameters, split by WHERE they arrive - see `parameterSchemasOf`.
315
353
  *
@@ -439,6 +477,17 @@ export interface EmittedRoute {
439
477
  */
440
478
  readonly security: readonly SecurityRequirement[];
441
479
  }
480
+ /** Where a value reaches a handler's input from. */
481
+ export type InputLocation = "path" | "query" | "header" | "cookie" | "body";
482
+ /** Two inputs a handler would be handed under one key. See {@link EmittedRoute.sharedInputKeys}. */
483
+ export interface SharedInputKey {
484
+ /** The key both arrive under, as the input spells it. */
485
+ readonly key: string;
486
+ /** Where the input declared first comes from. */
487
+ readonly first: InputLocation;
488
+ /** Where the input declared second comes from. */
489
+ readonly second: InputLocation;
490
+ }
442
491
  export declare function collectRoutes(program: Program, registry: SchemaRegistry, service: HttpService): EmittedRoute[];
443
492
  /** Whether emitted source references `name` as an identifier rather than as part of a longer one. */
444
493
  export declare function referencedIn(source: string, name: string): boolean;
@@ -478,6 +527,12 @@ export interface RouteSchemaNames {
478
527
  */
479
528
  readonly cookie?: string | undefined;
480
529
  readonly body: string | undefined;
530
+ /**
531
+ * The validator of the body as a URL-encoded form carries it, where it differs from `body`'s - see
532
+ * {@link EmittedRoute.formRequestSchema}. Absent where a form, if one is declared, is validated by
533
+ * `body`.
534
+ */
535
+ readonly formBody?: string;
481
536
  /**
482
537
  * The identifier each response's body is declared under, parallel to `EmittedRoute.responses` and
483
538
  * in the same order. `schema` is `undefined` exactly where that response carries no body.