@nestjs/swagger
Version:
Nest - modern, fast, powerful node.js web framework (@swagger)
61 lines (60 loc) • 3.02 kB
JavaScript
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;
}