fix(plugin): support boolean literal types and boolean enum values#3761
Open
lucreiss wants to merge 1 commit intonestjs:masterfrom
Open
fix(plugin): support boolean literal types and boolean enum values#3761lucreiss wants to merge 1 commit intonestjs:masterfrom
lucreiss wants to merge 1 commit intonestjs:masterfrom
Conversation
The CLI plugin does not recognize TypeScript `BooleanLiteral` types (true/false), causing properties typed as literal `true` or `false` to emit no `type` in metadata. Additionally, `getEnumType()` only returns 'string' or 'number', so `enum: [true]` or `enum: [true, false]` incorrectly produces `type: "number"` in the OpenAPI schema, violating the spec. Finally, both `createFromObjectLiteral()` and the `@ApiProperty` decorator unconditionally overwrite an explicit `type` with the inferred enum type, preventing users from setting `type: 'boolean'` alongside `enum`. - Update `isBoolean()` in ast-utils to also match `TypeFlags.BooleanLiteral` - Add `isBooleanLiteral()` helper consistent with existing `isStringLiteral()` - Add boolean detection to `getEnumType()` so it returns 'boolean' for boolean enums - Include `boolean[]` in `SwaggerEnumType` and `getEnumValues()` return type - Guard `type` assignment in `createFromObjectLiteral()` and `@ApiProperty` decorator to only infer from `getEnumType()` when no explicit `type` is already set
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
PR Checklist
Please check if your PR fulfills the following requirements:
PR Type
What kind of change does this PR introduce?
What is the current behavior?
Boolean literal types are not recognized by the CLI plugin. When a DTO property is typed as literal
trueorfalse(e.g.hasPaymentMethod: true), the plugin'sisBoolean()only checksTypeFlags.Booleanand missesTypeFlags.BooleanLiteral. This causesgetTypeReferenceAsStringto return{ typeName: undefined }, so notypeis emitted in the plugin metadata for the property.getEnumType()returns'number'for boolean enum values. The function only distinguishes between'string'and'number', defaulting to'number'for anything that isn't a string. So@ApiProperty({ enum: [true, false] })producestype: "number"in the OpenAPI schema, which violates the OpenAPI 3.0 specification (Section 5.1 — Schema Object listsbooleanas a valid primitive type).Explicit
typeis overwritten by enum type inference. BothcreateFromObjectLiteral()inSchemaObjectFactoryand the@ApiPropertydecorator unconditionally overwrite thetypeproperty with the result ofgetEnumType()whenenumis present. This means@ApiProperty({ type: 'boolean', enum: [true] })has itstype: 'boolean'replaced withtype: 'number', with no escape hatch for the user.Issue Number: N/A
What is the new behavior?
isBoolean()now also matchesTypeFlags.BooleanLiteral, so the plugin correctly emitstype: () => Booleanfor literaltrue/falseproperties. A newisBooleanLiteral()helper is added, consistent with the existingisStringLiteral()andisEnumLiteral()functions.getEnumType()detects boolean values and returns'boolean', producing spec-compliant OpenAPI schemas.SwaggerEnumTypeandgetEnumValues()return types are updated to includeboolean[].The enum type inference in both
createFromObjectLiteral()and the@ApiPropertydecorator now only applies when no explicittypeis already set on the metadata. This is consistent with every other code path in the library where user-provided decorator metadata takes precedence over inference.OpenAPI / JSON Schema specification compliance
These changes bring the generated schemas in line with the OpenAPI 3.0.3 specification and the JSON Schema Validation draft it builds on:
type: "boolean"is a first-class primitive. OAS 3.0.3 §4.7.24.1 (Schema Object) defines data types via JSON Schema §4.2, which listsbooleanalongsidestring,number,integer,array, andobjectas valid primitive types. Before this fix,enum: [true, false]producedtype: "number"— an invalid schema that would cause spec validators (e.g.swagger-cli validate, Redocly, Spectral) to flag a type mismatch since the enum values are not numbers.enumconstrains values, not types. JSON Schema §5.20 definesenumas a value-space constraint that is valid for any type. The OpenAPI toolchain (Swagger UI, Swagger Codegen, openapi-generator) resolvestypeindependently fromenum— they are orthogonal. By returning'boolean'fromgetEnumType()when the values are booleans, the generated schema now correctly pairstype: "boolean"withenum: [true]orenum: [true, false], which is valid per §5.20 and renders correctly in Swagger UI as a constrained boolean field.Explicit
typemust not be silently discarded. OAS 3.0.3 §4.7.24.1 states that thetypefield determines the data type of the schema. When a user explicitly declares@ApiProperty({ type: 'boolean', enum: [true] }), the intent is unambiguous — the property is a boolean constrained to a single value. Overwriting this totype: "number"produced a schema where the declared type contradicts the enum values, which is a validation error under JSON Schema §5.20 (enum values must be valid against the schema). The guard now preserves user intent and produces schemas wheretypeandenumare always consistent.Boolean literal discriminators are now representable. A common OpenAPI pattern for discriminated unions uses a fixed boolean property (e.g.
hasSomething: truevshasSomething: false) as a discriminator withoneOf. This requires{ type: "boolean", enum: [true] }and{ type: "boolean", enum: [false] }in the respective sub-schemas. Before this fix, both would incorrectly producetype: "number", breaking code generators (openapi-generator, swagger-codegen) that rely ontypeto determine the target language type for the property.Does this PR introduce a breaking change?
Other information
Files changed (source):
lib/plugin/utils/ast-utils.ts— updateisBoolean(), addisBooleanLiteral()lib/utils/enum.utils.ts— add boolean support togetEnumType()andgetEnumValues()lib/types/swagger-enum.type.ts— addboolean[]toSwaggerEnumTypelib/services/schema-object-factory.ts— guardtypeassignment increateFromObjectLiteral()lib/decorators/api-property.decorator.ts— guardtypeassignment increateApiPropertyDecorator()Files changed (tests):
test/plugin/fixtures/boolean-literal.dto.ts— new fixture with boolean literal propertiestest/plugin/model-class-visitor.spec.ts— test that plugin transpiles boolean literals totype: () => Booleantest/utils/enum-utils.spec.ts— unit tests forgetEnumType()andgetEnumValues()with boolean valuestest/services/schema-object-factory.spec.ts— tests for boolean enum schemas and explicit type preservation