diff --git a/.chronus/changes/almend-ScalarDefaultValue-2024-8-12-15-34-32.md b/.chronus/changes/almend-ScalarDefaultValue-2024-8-12-15-34-32.md new file mode 100644 index 0000000000..234ab1f96b --- /dev/null +++ b/.chronus/changes/almend-ScalarDefaultValue-2024-8-12-15-34-32.md @@ -0,0 +1,7 @@ +--- +changeKind: feature +packages: + - "@typespec/openapi3" +--- + +Added support to use Scalar and Object as default types \ No newline at end of file diff --git a/packages/openapi3/src/lib.ts b/packages/openapi3/src/lib.ts index 5a0995f68f..ffcb14991c 100644 --- a/packages/openapi3/src/lib.ts +++ b/packages/openapi3/src/lib.ts @@ -239,12 +239,6 @@ export const libDef = { default: "Enums are not supported unless all options are literals of the same type.", }, }, - "invalid-default": { - severity: "error", - messages: { - default: paramMessage`Invalid type '${"type"}' for a default value`, - }, - }, "inline-cycle": { severity: "error", messages: { diff --git a/packages/openapi3/src/openapi.ts b/packages/openapi3/src/openapi.ts index 24a3f74296..9f714a0e3a 100644 --- a/packages/openapi3/src/openapi.ts +++ b/packages/openapi3/src/openapi.ts @@ -395,7 +395,7 @@ function createOAPIEmitter( } const variable: OpenAPI3ServerVariable = { - default: prop.defaultValue ? getDefaultValue(program, prop.defaultValue) : "", + default: prop.defaultValue ? getDefaultValue(program, prop.defaultValue, prop) : "", description: getDoc(program, prop), }; @@ -1371,7 +1371,7 @@ function createOAPIEmitter( options, ); if (param.defaultValue) { - schema.default = getDefaultValue(program, param.defaultValue); + schema.default = getDefaultValue(program, param.defaultValue, param); } // Description is already provided in the parameter itself. delete schema.description; diff --git a/packages/openapi3/src/schema-emitter.ts b/packages/openapi3/src/schema-emitter.ts index 110547f9e8..1bbac8029e 100644 --- a/packages/openapi3/src/schema-emitter.ts +++ b/packages/openapi3/src/schema-emitter.ts @@ -377,7 +377,7 @@ export class OpenAPI3SchemaEmitter extends TypeEmitter< // Apply decorators on the property to the type's schema const additionalProps: Partial = this.#applyConstraints(prop, {}); if (prop.defaultValue) { - additionalProps.default = getDefaultValue(program, prop.defaultValue); + additionalProps.default = getDefaultValue(program, prop.defaultValue, prop); } if (isReadonlyProperty(program, prop)) { @@ -922,27 +922,12 @@ const B = { }, } as const; -export function getDefaultValue(program: Program, defaultType: Value): any { - switch (defaultType.valueKind) { - case "StringValue": - return defaultType.value; - case "NumericValue": - return defaultType.value.asNumber() ?? undefined; - case "BooleanValue": - return defaultType.value; - case "ArrayValue": - return defaultType.values.map((x) => getDefaultValue(program, x)); - case "NullValue": - return null; - case "EnumValue": - return defaultType.value.value ?? defaultType.value.name; - default: - reportDiagnostic(program, { - code: "invalid-default", - format: { type: defaultType.valueKind }, - target: defaultType, - }); - } +export function getDefaultValue( + program: Program, + defaultType: Value, + modelProperty: ModelProperty, +): any { + return serializeValueAsJson(program, defaultType, modelProperty); } export function isBytesKeptRaw(program: Program, type: Type) { diff --git a/packages/openapi3/test/models.test.ts b/packages/openapi3/test/models.test.ts index d71a02e720..70c198105f 100644 --- a/packages/openapi3/test/models.test.ts +++ b/packages/openapi3/test/models.test.ts @@ -259,6 +259,41 @@ describe("openapi3: models", () => { }); }); + it("scalar used as a default value", async () => { + const res = await oapiForModel( + "Pet", + ` + scalar shortName { init name(value: string);} + + model Pet { name: shortName = shortName.name("Shorty"); } + `, + ); + + expect(res.schemas.Pet.properties.name.default).toEqual("Shorty"); + }); + + it("encode know scalar as a default value", async () => { + const res = await oapiForModel( + "Test", + ` + model Test { @encode("rfc7231") minDate: utcDateTime = utcDateTime.fromISO("2024-01-01T11:32:00Z"); } + `, + ); + + expect(res.schemas.Test.properties.minDate.default).toEqual("Mon, 01 Jan 2024 11:32:00 GMT"); + }); + + it("object value used as a default value", async () => { + const res = await oapiForModel( + "Test", + ` + model Test { Pet: {name: string;} = #{ name: "Dog"}; } + `, + ); + + expect(res.schemas.Test.properties.Pet.default.name).toEqual("Dog"); + }); + describe("numeric defaults", () => { it.each([ ["0.01", 0.01],