import { Type } from "@nestjs/common";
import {
EnumAllowedTypes,
SchemaObjectMetadata,
} from "@nestjs/swagger/dist/interfaces/schema-object-metadata.interface";
import { EnumSchemaAttributes } from "@nestjs/swagger/dist/interfaces/enum-schema-attributes.interface";
import { getTypeIsArrayTuple } from "@nestjs/swagger/dist/decorators/helpers";
import {
getEnumType,
getEnumValues,
} from "@nestjs/swagger/dist/utils/enum.utils";
import { DECORATORS } from "@nestjs/swagger/dist/constants";
import { createPropertyDecorator } from "./helpers";
export type ApiPropertyCommonOptions = SchemaObjectMetadata & {
"x-enumNames"?: string[];
/**
* Lazy function returning the type for which the decorated property
* can be used as an id
*
* Use together with @ApiDefaultGetter on the getter route of the type
* to generate OpenAPI link objects
*
* @see [Swagger link objects](https://swagger.io/docs/specification/links/)
*/
// eslint-disable-next-line @typescript-eslint/no-unsafe-function-type
link?: () => Type<unknown> | Function;
};
export type ApiPropertyOptions =
| ApiPropertyCommonOptions
| (ApiPropertyCommonOptions & {
enumName: string;
enumSchema?: EnumSchemaAttributes;
});
const isEnumArray = (
opts: ApiPropertyOptions
): opts is {
isArray: true;
enum: EnumAllowedTypes;
type: any;
items: any;
} => (opts.isArray && "enum" in opts && opts.enum !== undefined) as boolean;
/**
* @publicApi
*/
export function ApiProperty(
options: ApiPropertyOptions = {}
): PropertyDecorator {
return createApiPropertyDecorator(options);
}
export function createApiPropertyDecorator(
options: ApiPropertyOptions = {},
overrideExisting = true
): PropertyDecorator {
const [type, isArray] = getTypeIsArrayTuple(
options.type,
options.isArray as boolean
);
options = {
...options,
type,
isArray,
} as ApiPropertyOptions;
if (isEnumArray(options)) {
options.type = "array";
const enumValues = getEnumValues(options.enum);
options.items = {
type: getEnumType(enumValues),
enum: enumValues,
};
// @ts-expect-error nest swagger override
delete options.enum;
} else if ("enum" in options && options.enum !== undefined) {
const enumValues = getEnumValues(options.enum);
options.enum = enumValues;
options.type = getEnumType(enumValues);
}
if (Array.isArray(options.type)) {
options.type = "array";
options.items = {
type: "array",
items: {
type: options.type[0],
},
};
}
return createPropertyDecorator(
DECORATORS.API_MODEL_PROPERTIES,
options,
overrideExisting
);
}
export function ApiPropertyOptional(
options: ApiPropertyOptions = {}
): PropertyDecorator {
return ApiProperty({
...options,
required: false,
} as ApiPropertyOptions);
}
export function ApiResponseProperty(
options: Pick<
ApiPropertyOptions,
"type" | "example" | "format" | "deprecated" | "enum"
> = {}
): PropertyDecorator {
return ApiProperty({
readOnly: true,
...options,
} as ApiPropertyOptions);
}
Source