From 4d3414bb3861d563c30c1a7e122f6ea12407a43b Mon Sep 17 00:00:00 2001 From: mag123c Date: Wed, 30 Apr 2025 11:18:19 +0900 Subject: [PATCH] feat(swagger-plugin): add skipDefaultValues option to omit unspecified default fields and corresponding test --- lib/plugin/merge-options.ts | 7 ++- lib/plugin/visitors/model-class.visitor.ts | 6 +++ test/plugin/fixtures/create-option.ts | 6 ++- test/plugin/model-class-visitor.spec.ts | 57 +++++++++++++++++++++- 4 files changed, 72 insertions(+), 4 deletions(-) diff --git a/lib/plugin/merge-options.ts b/lib/plugin/merge-options.ts index 7ee569065..abfde6760 100644 --- a/lib/plugin/merge-options.ts +++ b/lib/plugin/merge-options.ts @@ -18,6 +18,10 @@ export interface PluginOptions { * Skip auto-annotating controller methods with HTTP status codes (e.g., @HttpCode(201)) */ skipAutoHttpCode?: boolean; + /** + * Skip add default for properties that do not specify default values. + */ + skipDefaultValues?: boolean; } const defaultOptions: PluginOptions = { @@ -30,7 +34,8 @@ const defaultOptions: PluginOptions = { introspectComments: false, esmCompatible: false, readonly: false, - debug: false + debug: false, + skipDefaultValues: false }; export const mergePluginOptions = ( diff --git a/lib/plugin/visitors/model-class.visitor.ts b/lib/plugin/visitors/model-class.visitor.ts index fe1d65385..6a6c9920f 100644 --- a/lib/plugin/visitors/model-class.visitor.ts +++ b/lib/plugin/visitors/model-class.visitor.ts @@ -656,6 +656,12 @@ export class ModelClassVisitor extends AbstractFileVisitor { options: PluginOptions ) { const key = 'default'; + /** + * Skip add default for properties that do not specify default values. + */ + if (options.skipDefaultValues) { + return undefined; + } if (hasPropertyKey(key, existingProperties)) { return undefined; } diff --git a/test/plugin/fixtures/create-option.ts b/test/plugin/fixtures/create-option.ts index ea68157fb..98e5fa879 100644 --- a/test/plugin/fixtures/create-option.ts +++ b/test/plugin/fixtures/create-option.ts @@ -18,7 +18,8 @@ export const mergedCliPluginMultiOption = { introspectComments: true, esmCompatible: false, readonly: false, - debug: false + debug: false, + skipDefaultValues: false }; export const mergedCliPluginSingleOption = { @@ -31,5 +32,6 @@ export const mergedCliPluginSingleOption = { introspectComments: true, esmCompatible: false, readonly: false, - debug: false + debug: false, + skipDefaultValues: false }; diff --git a/test/plugin/model-class-visitor.spec.ts b/test/plugin/model-class-visitor.spec.ts index 6274333ca..6c03a8fc1 100644 --- a/test/plugin/model-class-visitor.spec.ts +++ b/test/plugin/model-class-visitor.spec.ts @@ -306,7 +306,9 @@ describe('API model properties', () => { ] } }); - expect(esmResult.outputText).toEqual(parameterPropertyDtoTextTranspiled(true)); + expect(esmResult.outputText).toEqual( + parameterPropertyDtoTextTranspiled(true) + ); }); it('should ignore Exclude decorator', () => { @@ -442,4 +444,57 @@ describe('API model properties', () => { }); expect(result.outputText).toEqual(createCatExclusiveDtoTextTranspiled); }); + + it('should skip default property when skipDefaultValues is true', () => { + const options: ts.CompilerOptions = { + module: ts.ModuleKind.ES2020, + target: ts.ScriptTarget.ES2020, + newLine: ts.NewLineKind.LineFeed, + noEmitHelpers: true, + experimentalDecorators: true, + strict: true + }; + const filename = 'default-value.dto.ts'; + const fakeProgram = ts.createProgram([filename], options); + + const defaultValueDtoText = ` + import { ApiProperty } from '../../decorators'; + export class DefaultValueDto { + @ApiProperty() + count: number = 5; + } + `; + + const resultWithoutSkip = ts.transpileModule(defaultValueDtoText, { + compilerOptions: options, + fileName: filename, + transformers: { + before: [ + before( + { introspectComments: true, classValidatorShim: true }, + fakeProgram + ) + ] + } + }); + expect(resultWithoutSkip.outputText).toContain(`default: 5`); + + const resultWithSkip = ts.transpileModule(defaultValueDtoText, { + compilerOptions: options, + fileName: filename, + transformers: { + before: [ + before( + { + introspectComments: true, + classValidatorShim: true, + skipDefaultValues: true + }, + fakeProgram + ) + ] + } + }); + expect(resultWithSkip.outputText).not.toContain(`default: 5`); + }); });