Skip to content

Commit

Permalink
fix metadata generation for computed properties names with enum values
Browse files Browse the repository at this point in the history
remove unused import from propertyTransformer.ts

adding test for  computed properties names with number enum values
  • Loading branch information
wilker7ribeiro committed Apr 15, 2024
1 parent 4219d33 commit 83b7768
Show file tree
Hide file tree
Showing 5 changed files with 75 additions and 13 deletions.
Original file line number Diff line number Diff line change
@@ -1,6 +1,5 @@
import type {
Token,
Identifier,
InterfaceDeclaration,
ClassDeclaration,
PropertyDeclaration,
Expand Down Expand Up @@ -66,12 +65,7 @@ export class PropertyTransformer extends Transformer {
}

private propertyFromSignature(propertySignature: PropertySignature, overrideToken?: OverrideToken): Tsoa.Property {
const identifier = propertySignature.name as Identifier;

throwUnless(
propertySignature.type,
new GenerateMetadataError(`No valid type found for property declaration.`),
);
throwUnless(propertySignature.type, new GenerateMetadataError(`No valid type found for property declaration.`));

let required = !propertySignature.questionToken;
if (overrideToken && overrideToken.kind === SyntaxKind.MinusToken) {
Expand All @@ -87,7 +81,7 @@ export class PropertyTransformer extends Transformer {
description: this.resolver.getNodeDescription(propertySignature),
example: this.resolver.getNodeExample(propertySignature),
format: this.resolver.getNodeFormat(propertySignature),
name: identifier.text,
name: this.resolver.getPropertyName(propertySignature),
required,
type: new TypeResolver(propertySignature.type, this.resolver.current, propertySignature.type.parent, this.resolver.context).resolve(),
validators: getPropertyValidators(propertySignature) || {},
Expand All @@ -98,7 +92,6 @@ export class PropertyTransformer extends Transformer {
}

private propertyFromDeclaration(propertyDeclaration: PropertyDeclaration | ParameterDeclaration, overrideToken?: OverrideToken): Tsoa.Property {
const identifier = propertyDeclaration.name as Identifier;
let typeNode = propertyDeclaration.type;

const tsType = this.resolver.current.typeChecker.getTypeAtLocation(propertyDeclaration);
Expand Down Expand Up @@ -126,7 +119,7 @@ export class PropertyTransformer extends Transformer {
description: this.resolver.getNodeDescription(propertyDeclaration),
example: this.resolver.getNodeExample(propertyDeclaration),
format: this.resolver.getNodeFormat(propertyDeclaration),
name: identifier.text,
name: this.resolver.getPropertyName(propertyDeclaration),
required,
type,
validators: getPropertyValidators(propertyDeclaration) || {},
Expand Down
12 changes: 11 additions & 1 deletion packages/cli/src/metadataGeneration/typeResolver.ts
Original file line number Diff line number Diff line change
Expand Up @@ -126,7 +126,7 @@ export class TypeResolver {
default: def,
description: this.getNodeDescription(propertySignature),
format: this.getNodeFormat(propertySignature),
name: (propertySignature.name as ts.Identifier).text,
name: this.getPropertyName(propertySignature),
required: !propertySignature.questionToken,
type,
validators: getPropertyValidators(propertySignature) || {},
Expand Down Expand Up @@ -1165,6 +1165,16 @@ export class TypeResolver {
return getJSDocComment(node, 'format');
}

public getPropertyName(prop: ts.PropertySignature | ts.PropertyDeclaration | ts.ParameterDeclaration): string {
if (ts.isComputedPropertyName(prop.name) && ts.isPropertyAccessExpression(prop.name.expression)) {
const initializerValue = getInitializerValue(prop.name.expression, this.current.typeChecker);
if (initializerValue) {
return initializerValue?.toString();
}
}
return (prop.name as ts.Identifier).text;
}

public getNodeExample(node: ts.Node) {
const exampleJSDoc = getJSDocComment(node, 'example');
if (exampleJSDoc) {
Expand Down
13 changes: 13 additions & 0 deletions tests/fixtures/testModel.ts
Original file line number Diff line number Diff line change
Expand Up @@ -410,6 +410,11 @@ export interface TestModel extends Model {
separateField2: Partial<SeparateField<Partial<{ a: string; b: string }>, 'a' | 'b'>>;
separateField3: Partial<SeparateField<Partial<{ a: string; b: number }>, 'a' | 'b'>>;
};

computedKeys?: {
[EnumDynamicPropertyKey.STRING_KEY]: string;
[EnumDynamicPropertyKey.NUMBER_KEY]: string;
};
}

type SeparateField<T, Field extends keyof T> = {
Expand Down Expand Up @@ -699,6 +704,14 @@ export enum EnumStringValue {
VALUE_2 = 'VALUE_2',
}

/**
* EnumDynamicPropertyKey.
*/
export enum EnumDynamicPropertyKey {
STRING_KEY = 'enumDynamicKey',
NUMBER_KEY = 1,
}

// shortened from StringLiteral to make the tslint enforced
// alphabetical sorting cleaner
export type StrLiteral = '' | 'Foo' | 'Bar';
Expand Down
25 changes: 24 additions & 1 deletion tests/unit/swagger/definitionsGeneration/definitions.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ import 'mocha';
import * as os from 'os';
import { versionMajorMinor } from 'typescript';
import { getDefaultOptions } from '../../../fixtures/defaultOptions';
import { TestModel } from '../../../fixtures/testModel';
import { EnumDynamicPropertyKey, TestModel } from '../../../fixtures/testModel';

describe('Definition generation', () => {
const metadata = new MetadataGenerator('./fixtures/controllers/getController.ts').Generate();
Expand Down Expand Up @@ -3237,6 +3237,29 @@ describe('Definition generation', () => {
`for property ${propertyName}.separateField3.omitted`,
);
},
computedKeys: (propertyName, propertySchema) => {
expect(propertyName).to.eq('computedKeys');
expect(propertySchema?.properties![EnumDynamicPropertyKey.STRING_KEY]).to.deep.eq(
{
type: 'string',
description: undefined,
default: undefined,
example: undefined,
format: undefined,
},
`for property ${propertyName}`,
);
expect(propertySchema?.properties![EnumDynamicPropertyKey.NUMBER_KEY]).to.deep.eq(
{
type: 'string',
description: undefined,
default: undefined,
example: undefined,
format: undefined,
},
`for property ${propertyName}`,
);
},
};

Object.keys(assertionsPerProperty).forEach(aPropertyName => {
Expand Down
25 changes: 24 additions & 1 deletion tests/unit/swagger/schemaDetails3.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ import 'mocha';
import * as os from 'os';
import { versionMajorMinor } from 'typescript';
import { getDefaultExtendedOptions } from '../../fixtures/defaultOptions';
import { TestModel } from '../../fixtures/testModel';
import { EnumDynamicPropertyKey, TestModel } from '../../fixtures/testModel';

describe('Definition generation for OpenAPI 3.0.0', () => {
const metadataGet = new MetadataGenerator('./fixtures/controllers/getController.ts').Generate();
Expand Down Expand Up @@ -4439,6 +4439,29 @@ describe('Definition generation for OpenAPI 3.0.0', () => {
default: undefined,
});
},
computedKeys: (propertyName, propertySchema) => {
expect(propertyName).to.eq('computedKeys');
expect(propertySchema?.properties![EnumDynamicPropertyKey.STRING_KEY]).to.deep.eq(
{
type: 'string',
description: undefined,
default: undefined,
example: undefined,
format: undefined,
},
`for property ${propertyName}`,
);
expect(propertySchema?.properties![EnumDynamicPropertyKey.NUMBER_KEY]).to.deep.eq(
{
type: 'string',
description: undefined,
default: undefined,
example: undefined,
format: undefined,
},
`for property ${propertyName}`,
);
},
};

const testModel = currentSpec.spec.components.schemas[interfaceModelName];
Expand Down

0 comments on commit 83b7768

Please sign in to comment.