typespec-http-zod 0.30.0 → 0.32.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 +22 -0
- package/dist/src/api.d.ts +31 -0
- package/dist/src/api.js +1475 -362
- package/dist/src/constraints.d.ts +31 -2
- package/dist/src/constraints.js +242 -46
- package/dist/src/lib.d.ts +163 -13
- package/dist/src/lib.js +207 -18
- package/dist/src/openapi-versions.d.ts +20 -0
- package/dist/src/openapi-versions.js +31 -0
- package/dist/src/published.d.ts +139 -0
- package/dist/src/published.js +798 -0
- package/dist/src/registry.d.ts +79 -45
- package/dist/src/registry.js +788 -200
- package/dist/src/types.d.ts +12 -2
- package/dist/src/types.js +267 -92
- package/dist/src/uri-template.d.ts +110 -8
- package/dist/src/uri-template.js +251 -46
- package/dist/src/zod.d.ts +764 -39
- package/dist/src/zod.js +4313 -541
- package/package.json +1 -1
package/dist/src/registry.d.ts
CHANGED
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import { type ModelProperty, type Program, type Type } from "@typespec/compiler";
|
|
2
2
|
import { Visibility } from "@typespec/http";
|
|
3
|
+
import { type HeldDeclarations, type PropertyPosition } from "./zod.js";
|
|
3
4
|
/**
|
|
4
5
|
* Assigns each named TypeSpec model/enum a single Zod declaration, emitted in dependency order.
|
|
5
6
|
*
|
|
@@ -47,6 +48,10 @@ interface Declaration {
|
|
|
47
48
|
readonly identifier: string;
|
|
48
49
|
readonly typeName: string;
|
|
49
50
|
readonly source: string;
|
|
51
|
+
/** The type declared, to tell one type in two contexts from two types of one name. */
|
|
52
|
+
readonly type?: Type;
|
|
53
|
+
/** The visibility it is declared at, to tell one type at two visibilities from two contexts. */
|
|
54
|
+
readonly at?: Visibility;
|
|
50
55
|
/**
|
|
51
56
|
* The structural TypeScript body for a declaration on a cycle, emitted INSTEAD of the
|
|
52
57
|
* `z.infer<typeof ...>` alias - which cannot be used here without closing the type-level loop.
|
|
@@ -54,47 +59,22 @@ interface Declaration {
|
|
|
54
59
|
readonly structural?: string;
|
|
55
60
|
/** Whether the declaration is annotated `: z.ZodType<typeName>`, which `z.lazy()` requires. */
|
|
56
61
|
readonly annotated?: boolean;
|
|
62
|
+
/** The registry key it was declared under, and its metadata context, to render it again. */
|
|
63
|
+
readonly key?: string;
|
|
64
|
+
readonly ignore?: boolean;
|
|
65
|
+
/** The 3.0 request it is read for, to render it again - see `withRequestReading`. */
|
|
66
|
+
readonly reading?: Visibility;
|
|
67
|
+
/** A shape no type stands for, and the type it is published for - see `declareNamed`. */
|
|
68
|
+
readonly synthetic?: Synthetic;
|
|
69
|
+
/** The keys a merge in it asked to be refused, to render it again when one is - see `refusedAt`. */
|
|
70
|
+
readonly consulted?: ReadonlySet<string>;
|
|
57
71
|
}
|
|
58
|
-
/**
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
* reason. Keyed on the type alone, whichever position was walked first won and every other position
|
|
65
|
-
* silently got its shape - measured on the corpus, one strict model carrying all six lifecycle
|
|
66
|
-
* properties, so a create request was required to send read-only fields.
|
|
67
|
-
*
|
|
68
|
-
* The suffix rule is openapi3's: canonical (`Read`) keeps the bare name, and another visibility only
|
|
69
|
-
* earns a suffix when the model is actually TRANSFORMED at it. Same rule, so the identifiers line up
|
|
70
|
-
* with the component names the document publishes.
|
|
71
|
-
*/
|
|
72
|
-
/**
|
|
73
|
-
* The visibility a type is actually DECLARED at, which is not always the one requested.
|
|
74
|
-
*
|
|
75
|
-
* **A type not reshaped at this visibility IS the canonical declaration, not a copy of it.** Keying
|
|
76
|
-
* on the requested visibility while only suffixing transformed types produced two cache entries
|
|
77
|
-
* sharing one identifier and an emitted file that stopped parsing:
|
|
78
|
-
* `Identifier 'approvalTierSchema' has already been declared`. An enum is the same enum in a request
|
|
79
|
-
* and a response, which is what the `Model` guard is for.
|
|
80
|
-
*
|
|
81
|
-
* It is the same collapse `@typespec/openapi3` performs before naming a component, and
|
|
82
|
-
* `isTransformedBy` is its own predicate, `metadataInfo.isTransformed`.
|
|
83
|
-
*
|
|
84
|
-
* **Extracted so both registries answer it identically.** They must: the emitted assertion pairs a
|
|
85
|
-
* validator with a contract type BY NAME, so a rule applied in one walk and paraphrased in the other
|
|
86
|
-
* is a pairing that silently compares the wrong two things.
|
|
87
|
-
*/
|
|
88
|
-
export declare function visibilityFor(program: Program, type: Type, requested: Visibility): Visibility;
|
|
89
|
-
/**
|
|
90
|
-
* A declaration's name at a visibility: the bare name at canonical, suffixed anywhere else.
|
|
91
|
-
*
|
|
92
|
-
* The suffix is `@typespec/http`'s `getVisibilitySuffix`, called with `Visibility.Read` as the
|
|
93
|
-
* canonical exactly as `@typespec/openapi3` calls it in `schema-emitter.ts`. Same function, same
|
|
94
|
-
* argument, so these identifiers line up with the component names the document publishes rather than
|
|
95
|
-
* merely resembling them.
|
|
96
|
-
*/
|
|
97
|
-
export declare function nameAt(bare: string, at: Visibility): string;
|
|
72
|
+
/** What a declaration no type stands for is: a multipart body, or a `@discriminated` envelope. */
|
|
73
|
+
interface Synthetic {
|
|
74
|
+
readonly kind: "multipart" | "envelope";
|
|
75
|
+
readonly site: Type;
|
|
76
|
+
}
|
|
77
|
+
export declare function nameAt(bare: string, at: Visibility, type: Type, reading?: Visibility): string;
|
|
98
78
|
export declare class SchemaRegistry {
|
|
99
79
|
#private;
|
|
100
80
|
constructor(program: Program);
|
|
@@ -103,15 +83,27 @@ export declare class SchemaRegistry {
|
|
|
103
83
|
* inline source. Declaring is depth-first so a model's dependencies are emitted above it, which is
|
|
104
84
|
* what lets the generated file be plain `const` declarations with no forward references.
|
|
105
85
|
*/
|
|
106
|
-
expressionFor(
|
|
86
|
+
expressionFor(given: Type, payload?: boolean): string;
|
|
87
|
+
/** What the contract types' walk asks of these declarations, so a merge is `never` on both sides. */
|
|
88
|
+
get held(): HeldDeclarations;
|
|
89
|
+
/**
|
|
90
|
+
* Declare a component the document publishes, at the visibility the walk is at, as a type
|
|
91
|
+
* another refers to - see `publishedComponents`. Nothing refers to it here, so a declaration
|
|
92
|
+
* still in flight is no back edge.
|
|
93
|
+
*/
|
|
94
|
+
declare(type: Type): void;
|
|
107
95
|
/**
|
|
108
96
|
* The Zod for a single property, constraints and optionality included.
|
|
109
97
|
*
|
|
110
98
|
* Used for path/query parameters, which are `ModelProperty`s that belong to no model - so they
|
|
111
99
|
* need the property-level walk rather than the type-level one, or `@minLength` on a path param
|
|
112
100
|
* would be documented and never enforced.
|
|
101
|
+
*
|
|
102
|
+
* **The property is where a refusal inside it points**, as a model's member is - see
|
|
103
|
+
* `withDeclarationSite`. A parameter is walked outside any model, so `@query a?: never[]` was
|
|
104
|
+
* reported at `<unknown location>:1:1`, the intrinsic's own place, which names nothing to edit.
|
|
113
105
|
*/
|
|
114
|
-
expressionForProperty(property: ModelProperty): string;
|
|
106
|
+
expressionForProperty(property: ModelProperty, position?: PropertyPosition): string;
|
|
115
107
|
/**
|
|
116
108
|
* A declaration for a shape the spec never wrote, under a name the document publishes.
|
|
117
109
|
*
|
|
@@ -124,9 +116,11 @@ export declare class SchemaRegistry {
|
|
|
124
116
|
* body: the document publishes `MultiPartRequest` as a component, and there is no walkable type
|
|
125
117
|
* for it - the parts have to be assembled from `@typespec/http`'s own view of the payload.
|
|
126
118
|
*/
|
|
127
|
-
declareNamed(name: string, build: () => string): string;
|
|
119
|
+
declareNamed(name: string, build: () => string, site: Type): string;
|
|
128
120
|
/** Every declaration, dependencies first. */
|
|
129
121
|
declarations(): readonly Declaration[];
|
|
122
|
+
/** The names of the declarations that validate nothing, refused here or in the walk beneath. */
|
|
123
|
+
refusedNames(): ReadonlySet<string>;
|
|
130
124
|
}
|
|
131
125
|
export interface TsDeclaration {
|
|
132
126
|
readonly name: string;
|
|
@@ -135,11 +129,42 @@ export interface TsDeclaration {
|
|
|
135
129
|
/** `true` for an enum-derived alias - declared but not exported, see below. */
|
|
136
130
|
readonly isVocabulary: boolean;
|
|
137
131
|
readonly source: string;
|
|
132
|
+
/** The type declared, to tell one type in two contexts from two types of one name. */
|
|
133
|
+
readonly type?: Type;
|
|
134
|
+
/** The visibility it is declared at - see {@link Declaration.at}. */
|
|
135
|
+
readonly at?: Visibility;
|
|
136
|
+
/** A shape no type stands for - see {@link Declaration.synthetic}. */
|
|
137
|
+
readonly synthetic?: Synthetic;
|
|
138
138
|
}
|
|
139
|
+
/**
|
|
140
|
+
* The same walk as {@link SchemaRegistry}, emitting plain TypeScript instead of Zod.
|
|
141
|
+
*
|
|
142
|
+
* Kept as a separate class rather than a mode on the schema registry because the two produce
|
|
143
|
+
* different *kinds* of declaration - an `interface` versus a `const` - and their reference resolvers
|
|
144
|
+
* hand back different text. Sharing {@link declaredNameOf} is the part that matters: a model named in
|
|
145
|
+
* one artefact is named the same way in the other, so the emitted assertion can pair them by name.
|
|
146
|
+
*/
|
|
147
|
+
/**
|
|
148
|
+
* Whether a rendered body is ONE object literal, and so may be emitted as an `interface`.
|
|
149
|
+
*
|
|
150
|
+
* **This was `source.startsWith("{") && !source.includes("} & ")`, which named the two shapes it had
|
|
151
|
+
* met rather than the property it needed.** A discriminated union with an envelope renders as
|
|
152
|
+
* `{ kind: "cat"; value: Cat; } | { kind: "dog"; value: Dog; }`: it starts with a brace and holds no
|
|
153
|
+
* intersection, so it was emitted as `export interface PetWithEnvelope { ... } | { ... }`. An
|
|
154
|
+
* interface cannot be a union, so the file did not parse at all - and that is the DEFAULT envelope,
|
|
155
|
+
* the shape a spec gets from writing `@discriminated` and nothing else.
|
|
156
|
+
*
|
|
157
|
+
* Balanced braces answer the question actually being asked: an interface is valid exactly when the
|
|
158
|
+
* whole body is a single `{...}`, whatever it contains. A composition operator cannot be missed,
|
|
159
|
+
* because anything following the matching close brace fails the test whatever it happens to be.
|
|
160
|
+
*/
|
|
161
|
+
export declare function isSingleObjectLiteral(source: string): boolean;
|
|
139
162
|
export declare class TypeRegistry {
|
|
140
163
|
#private;
|
|
141
|
-
constructor(program: Program);
|
|
142
|
-
expressionFor(
|
|
164
|
+
constructor(program: Program, held?: HeldDeclarations);
|
|
165
|
+
expressionFor(given: Type, payload?: boolean): string;
|
|
166
|
+
/** Declare a component the document publishes, as {@link SchemaRegistry.declare} does. */
|
|
167
|
+
declare(type: Type): void;
|
|
143
168
|
/**
|
|
144
169
|
* The Zod-free type for a single property - used for path and query parameters, which are
|
|
145
170
|
* `ModelProperty`s belonging to no model. Without routing them through the registry a named model
|
|
@@ -147,7 +172,16 @@ export declare class TypeRegistry {
|
|
|
147
172
|
*/
|
|
148
173
|
/** `wireName` names an HTTP parameter as the wire does - see {@link propertyToTs}. */
|
|
149
174
|
expressionForProperty(property: ModelProperty, wireName?: string): string;
|
|
175
|
+
/** A multipart body's type, under the component's name - see {@link SchemaRegistry.declareNamed}. */
|
|
176
|
+
declareNamed(name: string, build: () => string, site: Type): string;
|
|
150
177
|
/** Every declaration, dependencies first. */
|
|
151
178
|
declarations(): readonly TsDeclaration[];
|
|
179
|
+
/**
|
|
180
|
+
* **A contract type whose validator validates nothing is `never` too**, whatever refused it: two
|
|
181
|
+
* shapes under one name, a union this emitter refuses, a model openapi3 publishes split. The wire
|
|
182
|
+
* assertion pairs the two by name, and a contract type stating a shape beside `z.never()` failed
|
|
183
|
+
* it - `interface HBase { name: string }` beside a refused `hBaseSchema`.
|
|
184
|
+
*/
|
|
185
|
+
refuse(names: ReadonlySet<string>): void;
|
|
152
186
|
}
|
|
153
187
|
export {};
|