@typespec/openapi3 0.64.0-dev.1 → 0.64.0-dev.4
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 +4 -0
- package/dist/src/attach-extensions.d.ts +3 -0
- package/dist/src/attach-extensions.d.ts.map +1 -0
- package/dist/src/attach-extensions.js +11 -0
- package/dist/src/attach-extensions.js.map +1 -0
- package/dist/src/encoding.d.ts +2 -2
- package/dist/src/encoding.d.ts.map +1 -1
- package/dist/src/encoding.js +3 -2
- package/dist/src/encoding.js.map +1 -1
- package/dist/src/json-schema.d.ts +3 -0
- package/dist/src/json-schema.d.ts.map +1 -0
- package/dist/src/json-schema.js +9 -0
- package/dist/src/json-schema.js.map +1 -0
- package/dist/src/lib.d.ts +1 -0
- package/dist/src/lib.d.ts.map +1 -1
- package/dist/src/lib.js +12 -0
- package/dist/src/lib.js.map +1 -1
- package/dist/src/openapi-helpers-3-0.d.ts +6 -0
- package/dist/src/openapi-helpers-3-0.d.ts.map +1 -0
- package/dist/src/openapi-helpers-3-0.js +15 -0
- package/dist/src/openapi-helpers-3-0.js.map +1 -0
- package/dist/src/openapi-helpers-3-1.d.ts +6 -0
- package/dist/src/openapi-helpers-3-1.d.ts.map +1 -0
- package/dist/src/openapi-helpers-3-1.js +23 -0
- package/dist/src/openapi-helpers-3-1.js.map +1 -0
- package/dist/src/openapi-spec-mappings.d.ts +33 -0
- package/dist/src/openapi-spec-mappings.d.ts.map +1 -0
- package/dist/src/openapi-spec-mappings.js +53 -0
- package/dist/src/openapi-spec-mappings.js.map +1 -0
- package/dist/src/openapi.d.ts +2 -1
- package/dist/src/openapi.d.ts.map +1 -1
- package/dist/src/openapi.js +42 -44
- package/dist/src/openapi.js.map +1 -1
- package/dist/src/schema-emitter-3-0.d.ts +19 -0
- package/dist/src/schema-emitter-3-0.d.ts.map +1 -0
- package/dist/src/schema-emitter-3-0.js +199 -0
- package/dist/src/schema-emitter-3-0.js.map +1 -0
- package/dist/src/schema-emitter-3-1.d.ts +24 -0
- package/dist/src/schema-emitter-3-1.d.ts.map +1 -0
- package/dist/src/schema-emitter-3-1.js +226 -0
- package/dist/src/schema-emitter-3-1.js.map +1 -0
- package/dist/src/schema-emitter.d.ts +33 -10
- package/dist/src/schema-emitter.d.ts.map +1 -1
- package/dist/src/schema-emitter.js +104 -280
- package/dist/src/schema-emitter.js.map +1 -1
- package/dist/src/std-scalar-schemas.d.ts +2 -2
- package/dist/src/std-scalar-schemas.d.ts.map +1 -1
- package/dist/src/types.d.ts +352 -2
- package/dist/src/types.d.ts.map +1 -1
- package/dist/src/util.d.ts +10 -0
- package/dist/src/util.d.ts.map +1 -1
- package/dist/src/util.js +42 -0
- package/dist/src/util.js.map +1 -1
- package/dist/src/xml-module.d.ts +3 -3
- package/dist/src/xml-module.d.ts.map +1 -1
- package/dist/src/xml-module.js.map +1 -1
- package/package.json +6 -1
|
@@ -1,25 +1,28 @@
|
|
|
1
|
-
import { compilerAssert, explainStringTemplateNotSerializable, getDeprecated, getDiscriminatedUnion, getDiscriminator, getDoc, getEncode,
|
|
1
|
+
import { compilerAssert, explainStringTemplateNotSerializable, getDeprecated, getDiscriminatedUnion, getDiscriminator, getDoc, getEncode, getFormat, getKnownValues, getMaxItems, getMaxLength, getMaxValue, getMinItems, getMinLength, getMinValue, getNamespaceFullName, getPattern, getSummary, getTypeName, ignoreDiagnostics, isArrayModelType, isNeverType, isSecret, resolveEncodedName, } from "@typespec/compiler";
|
|
2
2
|
import { ArrayBuilder, ObjectBuilder, Placeholder, TypeEmitter, } from "@typespec/compiler/emitter-framework";
|
|
3
3
|
import { Visibility, getVisibilitySuffix } from "@typespec/http";
|
|
4
|
-
import { checkDuplicateTypeName,
|
|
4
|
+
import { checkDuplicateTypeName, getExternalDocs, getOpenAPITypeName, isReadonlyProperty, shouldInline, } from "@typespec/openapi";
|
|
5
|
+
import { attachExtensions } from "./attach-extensions.js";
|
|
5
6
|
import { getOneOf, getRef } from "./decorators.js";
|
|
6
|
-
import { applyEncoding } from "./encoding.js";
|
|
7
7
|
import { reportDiagnostic } from "./lib.js";
|
|
8
8
|
import { getSchemaForStdScalars } from "./std-scalar-schemas.js";
|
|
9
|
+
import { getDefaultValue, includeDerivedModel, isBytesKeptRaw, isStdType } from "./util.js";
|
|
9
10
|
/**
|
|
10
|
-
* OpenAPI3 schema emitter. Deals with emitting content of `components/schemas` section.
|
|
11
|
+
* Base OpenAPI3 schema emitter. Deals with emitting content of `components/schemas` section.
|
|
11
12
|
*/
|
|
12
|
-
export class
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
13
|
+
export class OpenAPI3SchemaEmitterBase extends TypeEmitter {
|
|
14
|
+
_metadataInfo;
|
|
15
|
+
_visibilityUsage;
|
|
16
|
+
_options;
|
|
17
|
+
_jsonSchemaModule;
|
|
18
|
+
_xmlModule;
|
|
19
|
+
constructor(emitter, metadataInfo, visibilityUsage, options, optionalDependencies) {
|
|
18
20
|
super(emitter);
|
|
19
|
-
this
|
|
20
|
-
this
|
|
21
|
-
this
|
|
22
|
-
this
|
|
21
|
+
this._metadataInfo = metadataInfo;
|
|
22
|
+
this._visibilityUsage = visibilityUsage;
|
|
23
|
+
this._options = options;
|
|
24
|
+
this._jsonSchemaModule = optionalDependencies.jsonSchemaModule;
|
|
25
|
+
this._xmlModule = optionalDependencies.xmlModule;
|
|
23
26
|
}
|
|
24
27
|
modelDeclarationReferenceContext(model, name) {
|
|
25
28
|
return this.reduceContext(model);
|
|
@@ -39,15 +42,28 @@ export class OpenAPI3SchemaEmitter extends TypeEmitter {
|
|
|
39
42
|
reduceContext(type) {
|
|
40
43
|
const visibility = this.#getVisibilityContext();
|
|
41
44
|
const patch = {};
|
|
42
|
-
if (visibility !== Visibility.Read && !this
|
|
45
|
+
if (visibility !== Visibility.Read && !this._metadataInfo.isTransformed(type, visibility)) {
|
|
43
46
|
patch.visibility = Visibility.Read;
|
|
44
47
|
}
|
|
45
|
-
const contentType = this
|
|
48
|
+
const contentType = this.getContentType();
|
|
46
49
|
if (contentType === "application/json") {
|
|
47
50
|
patch.contentType = undefined;
|
|
48
51
|
}
|
|
49
52
|
return patch;
|
|
50
53
|
}
|
|
54
|
+
applyDiscriminator(type, schema) {
|
|
55
|
+
const program = this.emitter.getProgram();
|
|
56
|
+
const discriminator = getDiscriminator(program, type);
|
|
57
|
+
if (discriminator) {
|
|
58
|
+
// the decorator validates that all the variants will be a model type
|
|
59
|
+
// with the discriminator field present.
|
|
60
|
+
schema.discriminator = { ...discriminator };
|
|
61
|
+
const discriminatedUnion = ignoreDiagnostics(getDiscriminatedUnion(type, discriminator));
|
|
62
|
+
if (discriminatedUnion.variants.size > 0) {
|
|
63
|
+
schema.discriminator.mapping = this.getDiscriminatorMapping(discriminatedUnion);
|
|
64
|
+
}
|
|
65
|
+
}
|
|
66
|
+
}
|
|
51
67
|
modelDeclaration(model, _) {
|
|
52
68
|
const program = this.emitter.getProgram();
|
|
53
69
|
const visibility = this.#getVisibilityContext();
|
|
@@ -64,23 +80,15 @@ export class OpenAPI3SchemaEmitter extends TypeEmitter {
|
|
|
64
80
|
for (const child of derivedModels) {
|
|
65
81
|
this.emitter.emitTypeReference(child);
|
|
66
82
|
}
|
|
67
|
-
|
|
68
|
-
if (discriminator) {
|
|
69
|
-
const [union] = getDiscriminatedUnion(model, discriminator);
|
|
70
|
-
const openApiDiscriminator = { ...discriminator };
|
|
71
|
-
if (union.variants.size > 0) {
|
|
72
|
-
openApiDiscriminator.mapping = this.#getDiscriminatorMapping(union);
|
|
73
|
-
}
|
|
74
|
-
schema.discriminator = openApiDiscriminator;
|
|
75
|
-
}
|
|
83
|
+
this.applyDiscriminator(model, schema);
|
|
76
84
|
this.#applyExternalDocs(model, schema);
|
|
77
85
|
if (model.baseModel) {
|
|
78
|
-
schema.set("allOf",
|
|
86
|
+
schema.set("allOf", Builders.array([this.emitter.emitTypeReference(model.baseModel)]));
|
|
79
87
|
}
|
|
80
88
|
const baseName = getOpenAPITypeName(program, model, this.#typeNameOptions());
|
|
81
|
-
const isMultipart = this
|
|
89
|
+
const isMultipart = this.getContentType().startsWith("multipart/");
|
|
82
90
|
const name = isMultipart ? baseName + "MultiPart" : baseName;
|
|
83
|
-
return this.#createDeclaration(model, name, this
|
|
91
|
+
return this.#createDeclaration(model, name, this.applyConstraints(model, schema));
|
|
84
92
|
}
|
|
85
93
|
#applyExternalDocs(typespecType, target) {
|
|
86
94
|
const externalDocs = getExternalDocs(this.emitter.getProgram(), typespecType);
|
|
@@ -104,7 +112,7 @@ export class OpenAPI3SchemaEmitter extends TypeEmitter {
|
|
|
104
112
|
#ignoreMetadataAnnotations() {
|
|
105
113
|
return this.emitter.getContext().ignoreMetadataAnnotations;
|
|
106
114
|
}
|
|
107
|
-
|
|
115
|
+
getContentType() {
|
|
108
116
|
return this.emitter.getContext().contentType ?? "application/json";
|
|
109
117
|
}
|
|
110
118
|
modelLiteral(model) {
|
|
@@ -130,7 +138,7 @@ export class OpenAPI3SchemaEmitter extends TypeEmitter {
|
|
|
130
138
|
type: "array",
|
|
131
139
|
items: this.emitter.emitTypeReference(elementType),
|
|
132
140
|
});
|
|
133
|
-
return this.#createDeclaration(array, name, this
|
|
141
|
+
return this.#createDeclaration(array, name, this.applyConstraints(array, schema));
|
|
134
142
|
}
|
|
135
143
|
arrayDeclarationReferenceContext(array, name, elementType) {
|
|
136
144
|
return {
|
|
@@ -155,11 +163,11 @@ export class OpenAPI3SchemaEmitter extends TypeEmitter {
|
|
|
155
163
|
// If the property has a type of 'never', don't include it in the schema
|
|
156
164
|
continue;
|
|
157
165
|
}
|
|
158
|
-
if (!this
|
|
166
|
+
if (!this._metadataInfo.isPayloadProperty(prop, visibility, this.#ignoreMetadataAnnotations())) {
|
|
159
167
|
continue;
|
|
160
168
|
}
|
|
161
|
-
if (!this
|
|
162
|
-
const encodedName = resolveEncodedName(this.emitter.getProgram(), prop, this
|
|
169
|
+
if (!this._metadataInfo.isOptional(prop, visibility)) {
|
|
170
|
+
const encodedName = resolveEncodedName(this.emitter.getProgram(), prop, this.getContentType());
|
|
163
171
|
requiredProps.push(encodedName);
|
|
164
172
|
}
|
|
165
173
|
}
|
|
@@ -175,13 +183,13 @@ export class OpenAPI3SchemaEmitter extends TypeEmitter {
|
|
|
175
183
|
const program = this.emitter.getProgram();
|
|
176
184
|
const props = new ObjectBuilder();
|
|
177
185
|
const visibility = this.emitter.getContext().visibility;
|
|
178
|
-
const contentType = this
|
|
186
|
+
const contentType = this.getContentType();
|
|
179
187
|
for (const prop of model.properties.values()) {
|
|
180
188
|
if (isNeverType(prop.type)) {
|
|
181
189
|
// If the property has a type of 'never', don't include it in the schema
|
|
182
190
|
continue;
|
|
183
191
|
}
|
|
184
|
-
if (!this
|
|
192
|
+
if (!this._metadataInfo.isPayloadProperty(prop, visibility, this.#ignoreMetadataAnnotations())) {
|
|
185
193
|
continue;
|
|
186
194
|
}
|
|
187
195
|
const result = this.emitter.emitModelProperty(prop);
|
|
@@ -200,17 +208,20 @@ export class OpenAPI3SchemaEmitter extends TypeEmitter {
|
|
|
200
208
|
}
|
|
201
209
|
return props;
|
|
202
210
|
}
|
|
211
|
+
getRawBinarySchema() {
|
|
212
|
+
throw new Error("Method not implemented.");
|
|
213
|
+
}
|
|
203
214
|
modelPropertyLiteral(prop) {
|
|
204
215
|
const program = this.emitter.getProgram();
|
|
205
|
-
const isMultipart = this
|
|
216
|
+
const isMultipart = this.getContentType().startsWith("multipart/");
|
|
206
217
|
if (isMultipart) {
|
|
207
218
|
if (isBytesKeptRaw(program, prop.type) && getEncode(program, prop) === undefined) {
|
|
208
|
-
return
|
|
219
|
+
return this.getRawBinarySchema();
|
|
209
220
|
}
|
|
210
221
|
if (prop.type.kind === "Model" &&
|
|
211
222
|
isArrayModelType(program, prop.type) &&
|
|
212
223
|
isBytesKeptRaw(program, prop.type.indexer.value)) {
|
|
213
|
-
return { type: "array", items:
|
|
224
|
+
return { type: "array", items: this.getRawBinarySchema() };
|
|
214
225
|
}
|
|
215
226
|
}
|
|
216
227
|
const refSchema = this.emitter.emitTypeReference(prop.type, {
|
|
@@ -231,9 +242,9 @@ export class OpenAPI3SchemaEmitter extends TypeEmitter {
|
|
|
231
242
|
return {};
|
|
232
243
|
}
|
|
233
244
|
const isRef = refSchema.value instanceof Placeholder || "$ref" in refSchema.value;
|
|
234
|
-
const schema = this
|
|
245
|
+
const schema = this.applyEncoding(prop, refSchema.value);
|
|
235
246
|
// Apply decorators on the property to the type's schema
|
|
236
|
-
const additionalProps = this
|
|
247
|
+
const additionalProps = this.applyConstraints(prop, {}, schema);
|
|
237
248
|
if (prop.defaultValue) {
|
|
238
249
|
additionalProps.default = getDefaultValue(program, prop.defaultValue, prop);
|
|
239
250
|
}
|
|
@@ -241,7 +252,7 @@ export class OpenAPI3SchemaEmitter extends TypeEmitter {
|
|
|
241
252
|
additionalProps.readOnly = true;
|
|
242
253
|
}
|
|
243
254
|
// Attach any additional OpenAPI extensions
|
|
244
|
-
|
|
255
|
+
attachExtensions(program, prop, additionalProps);
|
|
245
256
|
if (schema && isRef && !(prop.type.kind === "Model" && isArrayModelType(program, prop.type))) {
|
|
246
257
|
if (Object.keys(additionalProps).length === 0) {
|
|
247
258
|
return schema;
|
|
@@ -291,28 +302,11 @@ export class OpenAPI3SchemaEmitter extends TypeEmitter {
|
|
|
291
302
|
}
|
|
292
303
|
enumDeclaration(en, name) {
|
|
293
304
|
const baseName = getOpenAPITypeName(this.emitter.getProgram(), en, this.#typeNameOptions());
|
|
294
|
-
return this.#createDeclaration(en, baseName, new ObjectBuilder(this
|
|
305
|
+
return this.#createDeclaration(en, baseName, new ObjectBuilder(this.enumSchema(en)));
|
|
295
306
|
}
|
|
296
|
-
|
|
297
|
-
|
|
298
|
-
|
|
299
|
-
reportDiagnostic(program, { code: "empty-enum", target: en });
|
|
300
|
-
return {};
|
|
301
|
-
}
|
|
302
|
-
const enumTypes = new Set();
|
|
303
|
-
const enumValues = new Set();
|
|
304
|
-
for (const member of en.members.values()) {
|
|
305
|
-
enumTypes.add(typeof member.value === "number" ? "number" : "string");
|
|
306
|
-
enumValues.add(member.value ?? member.name);
|
|
307
|
-
}
|
|
308
|
-
if (enumTypes.size > 1) {
|
|
309
|
-
reportDiagnostic(program, { code: "enum-unique-type", target: en });
|
|
310
|
-
}
|
|
311
|
-
const schema = {
|
|
312
|
-
type: enumTypes.values().next().value,
|
|
313
|
-
enum: [...enumValues],
|
|
314
|
-
};
|
|
315
|
-
return this.#applyConstraints(en, schema);
|
|
307
|
+
enumSchema(en) {
|
|
308
|
+
// Enums are handled differently between 3.x versions due to the differences in `type`
|
|
309
|
+
throw new Error("Method not implemented.");
|
|
316
310
|
}
|
|
317
311
|
enumMember(member) {
|
|
318
312
|
return this.enumMemberReference(member);
|
|
@@ -329,134 +323,16 @@ export class OpenAPI3SchemaEmitter extends TypeEmitter {
|
|
|
329
323
|
}
|
|
330
324
|
}
|
|
331
325
|
unionDeclaration(union, name) {
|
|
332
|
-
const schema = this
|
|
326
|
+
const schema = this.unionSchema(union);
|
|
333
327
|
const baseName = getOpenAPITypeName(this.emitter.getProgram(), union, this.#typeNameOptions());
|
|
334
328
|
return this.#createDeclaration(union, baseName, schema);
|
|
335
329
|
}
|
|
336
|
-
|
|
337
|
-
|
|
338
|
-
|
|
339
|
-
|
|
340
|
-
return new ObjectBuilder({});
|
|
341
|
-
}
|
|
342
|
-
const variants = Array.from(union.variants.values());
|
|
343
|
-
const literalVariantEnumByType = {};
|
|
344
|
-
const ofType = getOneOf(program, union) ? "oneOf" : "anyOf";
|
|
345
|
-
const schemaMembers = [];
|
|
346
|
-
let nullable = false;
|
|
347
|
-
const discriminator = getDiscriminator(program, union);
|
|
348
|
-
const isMultipart = this.#getContentType().startsWith("multipart/");
|
|
349
|
-
for (const variant of variants) {
|
|
350
|
-
if (isNullType(variant.type)) {
|
|
351
|
-
nullable = true;
|
|
352
|
-
continue;
|
|
353
|
-
}
|
|
354
|
-
if (isMultipart && isBytesKeptRaw(program, variant.type)) {
|
|
355
|
-
schemaMembers.push({ schema: { type: "string", format: "binary" }, type: variant.type });
|
|
356
|
-
continue;
|
|
357
|
-
}
|
|
358
|
-
if (isLiteralType(variant.type)) {
|
|
359
|
-
if (!literalVariantEnumByType[variant.type.kind]) {
|
|
360
|
-
const enumValue = [variant.type.value];
|
|
361
|
-
literalVariantEnumByType[variant.type.kind] = enumValue;
|
|
362
|
-
schemaMembers.push({
|
|
363
|
-
schema: { type: literalType(variant.type), enum: enumValue },
|
|
364
|
-
type: null,
|
|
365
|
-
});
|
|
366
|
-
}
|
|
367
|
-
else {
|
|
368
|
-
literalVariantEnumByType[variant.type.kind].push(variant.type.value);
|
|
369
|
-
}
|
|
370
|
-
}
|
|
371
|
-
else {
|
|
372
|
-
const enumSchema = this.emitter.emitTypeReference(variant.type, {
|
|
373
|
-
referenceContext: isMultipart ? { contentType: "application/json" } : {},
|
|
374
|
-
});
|
|
375
|
-
compilerAssert(enumSchema.kind === "code", "Unexpected enum schema. Should be kind: code");
|
|
376
|
-
schemaMembers.push({ schema: enumSchema.value, type: variant.type });
|
|
377
|
-
}
|
|
378
|
-
}
|
|
379
|
-
const wrapWithObjectBuilder = (schemaMember, { mergeUnionWideConstraints }) => {
|
|
380
|
-
// we can just return the single schema member after applying nullable
|
|
381
|
-
const schema = schemaMember.schema;
|
|
382
|
-
const type = schemaMember.type;
|
|
383
|
-
const additionalProps = mergeUnionWideConstraints
|
|
384
|
-
? this.#applyConstraints(union, {})
|
|
385
|
-
: {};
|
|
386
|
-
if (mergeUnionWideConstraints && nullable) {
|
|
387
|
-
additionalProps.nullable = true;
|
|
388
|
-
}
|
|
389
|
-
if (Object.keys(additionalProps).length === 0) {
|
|
390
|
-
return new ObjectBuilder(schema);
|
|
391
|
-
}
|
|
392
|
-
else {
|
|
393
|
-
if ((schema instanceof Placeholder || "$ref" in schema) &&
|
|
394
|
-
!(type && shouldInline(program, type))) {
|
|
395
|
-
if (type && (type.kind === "Model" || type.kind === "Scalar")) {
|
|
396
|
-
return new ObjectBuilder({
|
|
397
|
-
type: "object",
|
|
398
|
-
allOf: B.array([schema]),
|
|
399
|
-
...additionalProps,
|
|
400
|
-
});
|
|
401
|
-
}
|
|
402
|
-
else {
|
|
403
|
-
return new ObjectBuilder({ allOf: B.array([schema]), ...additionalProps });
|
|
404
|
-
}
|
|
405
|
-
}
|
|
406
|
-
else {
|
|
407
|
-
const merged = new ObjectBuilder(schema);
|
|
408
|
-
for (const [key, value] of Object.entries(additionalProps)) {
|
|
409
|
-
merged.set(key, value);
|
|
410
|
-
}
|
|
411
|
-
return merged;
|
|
412
|
-
}
|
|
413
|
-
}
|
|
414
|
-
};
|
|
415
|
-
const checkMerge = (schemaMembers) => {
|
|
416
|
-
if (nullable) {
|
|
417
|
-
for (const m of schemaMembers) {
|
|
418
|
-
if (m.schema instanceof Placeholder || "$ref" in m.schema) {
|
|
419
|
-
return true;
|
|
420
|
-
}
|
|
421
|
-
}
|
|
422
|
-
}
|
|
423
|
-
return false;
|
|
424
|
-
};
|
|
425
|
-
if (schemaMembers.length === 0) {
|
|
426
|
-
if (nullable) {
|
|
427
|
-
// This union is equivalent to just `null` but OA3 has no way to specify
|
|
428
|
-
// null as a value, so we throw an error.
|
|
429
|
-
reportDiagnostic(program, { code: "union-null", target: union });
|
|
430
|
-
return new ObjectBuilder({});
|
|
431
|
-
}
|
|
432
|
-
else {
|
|
433
|
-
// completely empty union can maybe only happen with bugs?
|
|
434
|
-
compilerAssert(false, "Attempting to emit an empty union");
|
|
435
|
-
}
|
|
436
|
-
}
|
|
437
|
-
if (schemaMembers.length === 1) {
|
|
438
|
-
return wrapWithObjectBuilder(schemaMembers[0], { mergeUnionWideConstraints: true });
|
|
439
|
-
}
|
|
440
|
-
const isMerge = checkMerge(schemaMembers);
|
|
441
|
-
const schema = {
|
|
442
|
-
[ofType]: schemaMembers.map((m) => wrapWithObjectBuilder(m, { mergeUnionWideConstraints: isMerge })),
|
|
443
|
-
};
|
|
444
|
-
if (!isMerge && nullable) {
|
|
445
|
-
schema.nullable = true;
|
|
446
|
-
}
|
|
447
|
-
if (discriminator) {
|
|
448
|
-
// the decorator validates that all the variants will be a model type
|
|
449
|
-
// with the discriminator field present.
|
|
450
|
-
schema.discriminator = { ...discriminator };
|
|
451
|
-
// Diagnostic already reported in compiler for unions
|
|
452
|
-
const discriminatedUnion = ignoreDiagnostics(getDiscriminatedUnion(union, discriminator));
|
|
453
|
-
if (discriminatedUnion.variants.size > 0) {
|
|
454
|
-
schema.discriminator.mapping = this.#getDiscriminatorMapping(discriminatedUnion);
|
|
455
|
-
}
|
|
456
|
-
}
|
|
457
|
-
return this.#applyConstraints(union, schema);
|
|
330
|
+
unionSchema(union) {
|
|
331
|
+
// Unions are handled differently between 3.x versions
|
|
332
|
+
// mostly due to how nullable properties are handled.
|
|
333
|
+
throw new Error("Method not implemented.");
|
|
458
334
|
}
|
|
459
|
-
|
|
335
|
+
getDiscriminatorMapping(union) {
|
|
460
336
|
const mapping = {};
|
|
461
337
|
for (const [key, model] of union.variants.entries()) {
|
|
462
338
|
const ref = this.emitter.emitTypeReference(model);
|
|
@@ -466,7 +342,7 @@ export class OpenAPI3SchemaEmitter extends TypeEmitter {
|
|
|
466
342
|
return mapping;
|
|
467
343
|
}
|
|
468
344
|
unionLiteral(union) {
|
|
469
|
-
return this
|
|
345
|
+
return this.unionSchema(union);
|
|
470
346
|
}
|
|
471
347
|
unionVariants(union) {
|
|
472
348
|
const variants = new ArrayBuilder();
|
|
@@ -481,15 +357,6 @@ export class OpenAPI3SchemaEmitter extends TypeEmitter {
|
|
|
481
357
|
modelPropertyReference(prop) {
|
|
482
358
|
return this.modelPropertyLiteral(prop);
|
|
483
359
|
}
|
|
484
|
-
#attachExtensions(program, type, emitObject) {
|
|
485
|
-
// Attach any OpenAPI extensions
|
|
486
|
-
const extensions = getExtensions(program, type);
|
|
487
|
-
if (extensions) {
|
|
488
|
-
for (const key of extensions.keys()) {
|
|
489
|
-
emitObject[key] = extensions.get(key);
|
|
490
|
-
}
|
|
491
|
-
}
|
|
492
|
-
}
|
|
493
360
|
reference(targetDeclaration, pathUp, pathDown, commonScope) {
|
|
494
361
|
if (targetDeclaration.value instanceof Placeholder) {
|
|
495
362
|
// I don't think this is possible, confirm.
|
|
@@ -517,11 +384,13 @@ export class OpenAPI3SchemaEmitter extends TypeEmitter {
|
|
|
517
384
|
return super.circularReference(target, scope, cycle);
|
|
518
385
|
}
|
|
519
386
|
scalarDeclaration(scalar, name) {
|
|
520
|
-
const isStd =
|
|
387
|
+
const isStd = isStdType(this.emitter.getProgram(), scalar);
|
|
521
388
|
const schema = this.#getSchemaForScalar(scalar);
|
|
522
389
|
const baseName = getOpenAPITypeName(this.emitter.getProgram(), scalar, this.#typeNameOptions());
|
|
523
390
|
// Don't create a declaration for std types
|
|
524
|
-
return isStd
|
|
391
|
+
return isStd
|
|
392
|
+
? schema
|
|
393
|
+
: this.#createDeclaration(scalar, baseName, new ObjectBuilder(schema));
|
|
525
394
|
}
|
|
526
395
|
scalarInstantiation(scalar, name) {
|
|
527
396
|
return this.#getSchemaForScalar(scalar);
|
|
@@ -531,31 +400,26 @@ export class OpenAPI3SchemaEmitter extends TypeEmitter {
|
|
|
531
400
|
}
|
|
532
401
|
#getSchemaForScalar(scalar) {
|
|
533
402
|
let result = {};
|
|
534
|
-
const isStd =
|
|
403
|
+
const isStd = isStdType(this.emitter.getProgram(), scalar);
|
|
535
404
|
if (isStd) {
|
|
536
|
-
result = this
|
|
405
|
+
result = this.getSchemaForStdScalars(scalar);
|
|
537
406
|
}
|
|
538
407
|
else if (scalar.baseScalar) {
|
|
539
408
|
result = this.#getSchemaForScalar(scalar.baseScalar);
|
|
540
409
|
}
|
|
541
|
-
const withDecorators = this
|
|
410
|
+
const withDecorators = this.applyEncoding(scalar, this.applyConstraints(scalar, result));
|
|
542
411
|
if (isStd) {
|
|
543
412
|
// Standard types are going to be inlined in the spec and we don't want the description of the scalar to show up
|
|
544
413
|
delete withDecorators.description;
|
|
545
414
|
}
|
|
546
415
|
return withDecorators;
|
|
547
416
|
}
|
|
548
|
-
|
|
549
|
-
return getSchemaForStdScalars(scalar, this
|
|
417
|
+
getSchemaForStdScalars(scalar) {
|
|
418
|
+
return getSchemaForStdScalars(scalar, this._options);
|
|
550
419
|
}
|
|
551
|
-
|
|
552
|
-
|
|
553
|
-
|
|
554
|
-
if (examples.length > 0) {
|
|
555
|
-
target.set("example", serializeValueAsJson(program, examples[0].value, type));
|
|
556
|
-
}
|
|
557
|
-
}
|
|
558
|
-
#applyConstraints(type, original, refSchema) {
|
|
420
|
+
applyCustomConstraints(type, target, refSchema) { }
|
|
421
|
+
applyConstraints(type, original, refSchema) {
|
|
422
|
+
// Apply common constraints
|
|
559
423
|
const schema = new ObjectBuilder(original);
|
|
560
424
|
const program = this.emitter.getProgram();
|
|
561
425
|
const applyConstraint = (fn, key) => {
|
|
@@ -564,7 +428,6 @@ export class OpenAPI3SchemaEmitter extends TypeEmitter {
|
|
|
564
428
|
schema[key] = value;
|
|
565
429
|
}
|
|
566
430
|
};
|
|
567
|
-
this.#applySchemaExamples(type, schema);
|
|
568
431
|
applyConstraint(getMinLength, "minLength");
|
|
569
432
|
applyConstraint(getMaxLength, "maxLength");
|
|
570
433
|
applyConstraint(getMinValue, "minimum");
|
|
@@ -572,49 +435,52 @@ export class OpenAPI3SchemaEmitter extends TypeEmitter {
|
|
|
572
435
|
applyConstraint(getPattern, "pattern");
|
|
573
436
|
applyConstraint(getMinItems, "minItems");
|
|
574
437
|
applyConstraint(getMaxItems, "maxItems");
|
|
575
|
-
|
|
576
|
-
|
|
577
|
-
|
|
578
|
-
|
|
579
|
-
|
|
580
|
-
|
|
581
|
-
|
|
582
|
-
schema.maximum = maxValueExclusive;
|
|
583
|
-
schema.exclusiveMaximum = true;
|
|
438
|
+
// apply json schema decorators
|
|
439
|
+
const jsonSchemaModule = this._jsonSchemaModule;
|
|
440
|
+
if (jsonSchemaModule) {
|
|
441
|
+
applyConstraint(jsonSchemaModule.getMultipleOf, "multipleOf");
|
|
442
|
+
applyConstraint(jsonSchemaModule.getUniqueItems, "uniqueItems");
|
|
443
|
+
applyConstraint(jsonSchemaModule.getMinProperties, "minProperties");
|
|
444
|
+
applyConstraint(jsonSchemaModule.getMaxProperties, "maxProperties");
|
|
584
445
|
}
|
|
585
446
|
if (isSecret(program, type)) {
|
|
586
447
|
schema.format = "password";
|
|
587
448
|
}
|
|
588
449
|
// the stdlib applies a format of "url" but json schema wants "uri",
|
|
589
450
|
// so ignore this format if it's the built-in type.
|
|
590
|
-
if (!
|
|
451
|
+
if (!isStdType(program, type) || type.name !== "url") {
|
|
591
452
|
applyConstraint(getFormat, "format");
|
|
592
453
|
}
|
|
593
454
|
applyConstraint(getDoc, "description");
|
|
594
455
|
applyConstraint(getSummary, "title");
|
|
595
456
|
applyConstraint((p, t) => (getDeprecated(p, t) !== undefined ? true : undefined), "deprecated");
|
|
596
|
-
|
|
457
|
+
this.applyCustomConstraints(type, schema, refSchema);
|
|
458
|
+
this.applyXml(type, schema, refSchema);
|
|
459
|
+
attachExtensions(program, type, schema);
|
|
460
|
+
const values = getKnownValues(program, type);
|
|
461
|
+
if (values) {
|
|
462
|
+
return new ObjectBuilder({
|
|
463
|
+
oneOf: [schema, this.enumSchema(values)],
|
|
464
|
+
});
|
|
465
|
+
}
|
|
466
|
+
return new ObjectBuilder(schema);
|
|
467
|
+
}
|
|
468
|
+
applyXml(type, schema, refSchema) {
|
|
469
|
+
const program = this.emitter.getProgram();
|
|
470
|
+
if (this._xmlModule) {
|
|
597
471
|
switch (type.kind) {
|
|
598
472
|
case "Scalar":
|
|
599
473
|
case "Model":
|
|
600
|
-
this
|
|
474
|
+
this._xmlModule.attachXmlObjectForScalarOrModel(program, type, schema);
|
|
601
475
|
break;
|
|
602
476
|
case "ModelProperty":
|
|
603
|
-
this
|
|
477
|
+
this._xmlModule.attachXmlObjectForModelProperty(program, this._options, type, schema, refSchema);
|
|
604
478
|
break;
|
|
605
479
|
}
|
|
606
480
|
}
|
|
607
|
-
this.#attachExtensions(program, type, schema);
|
|
608
|
-
const values = getKnownValues(program, type);
|
|
609
|
-
if (values) {
|
|
610
|
-
return new ObjectBuilder({
|
|
611
|
-
oneOf: [schema, this.#enumSchema(values)],
|
|
612
|
-
});
|
|
613
|
-
}
|
|
614
|
-
return new ObjectBuilder(schema);
|
|
615
481
|
}
|
|
616
482
|
#inlineType(type, schema) {
|
|
617
|
-
if (this
|
|
483
|
+
if (this._options.includeXTypeSpecName !== "never") {
|
|
618
484
|
schema.set("x-typespec-name", getTypeName(type, this.#typeNameOptions()));
|
|
619
485
|
}
|
|
620
486
|
return schema;
|
|
@@ -633,7 +499,7 @@ export class OpenAPI3SchemaEmitter extends TypeEmitter {
|
|
|
633
499
|
if (title) {
|
|
634
500
|
schema.set("title", title);
|
|
635
501
|
}
|
|
636
|
-
const usage = this
|
|
502
|
+
const usage = this._visibilityUsage.getUsage(type);
|
|
637
503
|
const shouldAddSuffix = usage !== undefined && usage.size > 1;
|
|
638
504
|
const visibility = this.#getVisibilityContext();
|
|
639
505
|
const fullName = name + (shouldAddSuffix ? getVisibilitySuffix(visibility, Visibility.Read) : "");
|
|
@@ -641,51 +507,15 @@ export class OpenAPI3SchemaEmitter extends TypeEmitter {
|
|
|
641
507
|
checkDuplicateTypeName(this.emitter.getProgram(), type, fullName, Object.fromEntries(decl.scope.declarations.map((x) => [x.name, true])));
|
|
642
508
|
return decl;
|
|
643
509
|
}
|
|
644
|
-
|
|
645
|
-
|
|
646
|
-
}
|
|
647
|
-
#applyEncoding(typespecType, target) {
|
|
648
|
-
return applyEncoding(this.emitter.getProgram(), typespecType, target, this.#options);
|
|
649
|
-
}
|
|
650
|
-
intrinsic(intrinsic, name) {
|
|
651
|
-
switch (name) {
|
|
652
|
-
case "unknown":
|
|
653
|
-
return {};
|
|
654
|
-
case "null":
|
|
655
|
-
return { nullable: true };
|
|
656
|
-
}
|
|
657
|
-
reportDiagnostic(this.emitter.getProgram(), {
|
|
658
|
-
code: "invalid-schema",
|
|
659
|
-
format: { type: name },
|
|
660
|
-
target: intrinsic,
|
|
661
|
-
});
|
|
662
|
-
return {};
|
|
510
|
+
applyEncoding(typespecType, target) {
|
|
511
|
+
throw new Error("Method not implemented.");
|
|
663
512
|
}
|
|
664
513
|
programContext(program) {
|
|
665
514
|
const sourceFile = this.emitter.createSourceFile("openapi");
|
|
666
515
|
return { scope: sourceFile.globalScope };
|
|
667
516
|
}
|
|
668
517
|
}
|
|
669
|
-
|
|
670
|
-
return type.kind === "Boolean" || type.kind === "String" || type.kind === "Number";
|
|
671
|
-
}
|
|
672
|
-
function literalType(type) {
|
|
673
|
-
switch (type.kind) {
|
|
674
|
-
case "String":
|
|
675
|
-
return "string";
|
|
676
|
-
case "Number":
|
|
677
|
-
return "number";
|
|
678
|
-
case "Boolean":
|
|
679
|
-
return "boolean";
|
|
680
|
-
}
|
|
681
|
-
}
|
|
682
|
-
function includeDerivedModel(model) {
|
|
683
|
-
return (!isTemplateDeclaration(model) &&
|
|
684
|
-
(model.templateMapper?.args === undefined ||
|
|
685
|
-
model.templateMapper.args?.length === 0 ||
|
|
686
|
-
model.derivedModels.length > 0));
|
|
687
|
-
}
|
|
688
|
-
const B = {
|
|
518
|
+
export const Builders = {
|
|
689
519
|
array: (items) => {
|
|
690
520
|
const builder = new ArrayBuilder();
|
|
691
521
|
for (const item of items) {
|
|
@@ -701,10 +531,4 @@ const B = {
|
|
|
701
531
|
return builder;
|
|
702
532
|
},
|
|
703
533
|
};
|
|
704
|
-
export function getDefaultValue(program, defaultType, modelProperty) {
|
|
705
|
-
return serializeValueAsJson(program, defaultType, modelProperty);
|
|
706
|
-
}
|
|
707
|
-
export function isBytesKeptRaw(program, type) {
|
|
708
|
-
return type.kind === "Scalar" && type.name === "bytes" && getEncode(program, type) === undefined;
|
|
709
|
-
}
|
|
710
534
|
//# sourceMappingURL=schema-emitter.js.map
|