UNPKG

@nestjs/swagger

Version:

Nest - modern, fast, powerful node.js web framework (@swagger)

61 lines (60 loc) 3.02 kB
import { applyIsOptionalDecorator, applyValidateIfDefinedDecorator, inheritPropertyInitializers, inheritTransformationMetadata, inheritValidationMetadata } from '@nestjs/mapped-types'; import { mapValues } from 'es-toolkit/compat'; import { DECORATORS } from '../constants.js'; import { ApiProperty } from '../decorators/index.js'; import { MetadataLoader } from '../plugin/metadata-loader.js'; import { METADATA_FACTORY_NAME } from '../plugin/plugin-constants.js'; import { ModelPropertiesAccessor } from '../services/model-properties-accessor.js'; import { clonePluginMetadataFactory, setMappedTypeClassName } from './mapped-types.utils.js'; const modelPropertiesAccessor = new ModelPropertiesAccessor(); export function PartialType(classRef, options = {}) { const applyPartialDecoratorFn = options.skipNullProperties === false ? applyValidateIfDefinedDecorator : applyIsOptionalDecorator; const fields = modelPropertiesAccessor.getModelProperties(classRef.prototype); class PartialTypeClass { constructor() { inheritPropertyInitializers(this, classRef); } } setMappedTypeClassName(PartialTypeClass, 'Partial', classRef); const keysWithValidationConstraints = inheritValidationMetadata(classRef, PartialTypeClass); if (keysWithValidationConstraints) { keysWithValidationConstraints .filter((key) => !fields.includes(key)) .forEach((key) => applyPartialDecoratorFn(PartialTypeClass, key)); } inheritTransformationMetadata(classRef, PartialTypeClass); function applyFields(fields) { clonePluginMetadataFactory(PartialTypeClass, classRef.prototype, (metadata) => mapValues(metadata, (item) => ({ ...item, required: false }))); fields.forEach((key) => { const metadata = Reflect.getMetadata(DECORATORS.API_MODEL_PROPERTIES, classRef.prototype, key) || {}; const decoratorFactory = ApiProperty({ ...metadata, required: false }); decoratorFactory(PartialTypeClass.prototype, key); applyPartialDecoratorFn(PartialTypeClass, key); }); if (PartialTypeClass[METADATA_FACTORY_NAME]) { const pluginMetadata = PartialTypeClass[METADATA_FACTORY_NAME](); const pluginFields = Object.keys(pluginMetadata); pluginFields.forEach((key) => { if (!fields.includes(key)) { const decoratorFactory = ApiProperty({ ...pluginMetadata[key], required: false }); decoratorFactory(PartialTypeClass.prototype, key); } applyPartialDecoratorFn(PartialTypeClass, key); }); } } applyFields(fields); MetadataLoader.addRefreshHook(() => { const fields = modelPropertiesAccessor.getModelProperties(classRef.prototype); applyFields(fields); }); return PartialTypeClass; }