Skip to content

Commit 666fec3

Browse files
authored
Merge pull request #1657 from DominykasValutis/master
Add support for @title keyword annotation
2 parents 82b61ec + 29ec2e9 commit 666fec3

File tree

6 files changed

+272
-119
lines changed

6 files changed

+272
-119
lines changed

packages/cli/src/utils/validatorUtils.ts

Lines changed: 144 additions & 119 deletions
Original file line numberDiff line numberDiff line change
@@ -32,71 +32,74 @@ export function getParameterValidators(parameter: ts.ParameterDeclaration, param
3232
}
3333
}
3434

35-
return tags.reduce((validateObj, tag) => {
36-
if (!tag.comment) {
37-
return validateObj;
38-
}
35+
return tags.reduce(
36+
(validateObj, tag) => {
37+
if (!tag.comment) {
38+
return validateObj;
39+
}
3940

40-
const name = tag.tagName.text;
41-
const comment = commentToString(tag.comment)
42-
?.substr((commentToString(tag.comment)?.indexOf(' ') || -1) + 1)
43-
.trim();
44-
const value = getCommentValue(comment);
41+
const name = tag.tagName.text;
42+
const comment = commentToString(tag.comment)
43+
?.substring((commentToString(tag.comment)?.indexOf(' ') || -1) + 1)
44+
.trim();
45+
const value = getCommentValue(comment);
4546

46-
switch (name) {
47-
case 'uniqueItems':
48-
validateObj[name] = {
49-
errorMsg: getErrorMsg(comment, false),
50-
value: undefined,
51-
};
52-
break;
53-
case 'minimum':
54-
case 'maximum':
55-
case 'minItems':
56-
case 'maxItems':
57-
case 'minLength':
58-
case 'maxLength':
59-
if (isNaN(value as any)) {
60-
throw new GenerateMetadataError(`${name} parameter use number.`);
61-
}
62-
validateObj[name] = {
63-
errorMsg: getErrorMsg(comment),
64-
value: Number(value),
65-
};
66-
break;
67-
case 'minDate':
68-
case 'maxDate':
69-
if (!validator.isISO8601(String(value), { strict: true })) {
70-
throw new GenerateMetadataError(`${name} parameter use date format ISO 8601 ex. 2017-05-14, 2017-05-14T05:18Z`);
71-
}
72-
validateObj[name] = {
73-
errorMsg: getErrorMsg(comment),
74-
value,
75-
};
76-
break;
77-
case 'pattern':
78-
if (typeof value !== 'string') {
79-
throw new GenerateMetadataError(`${name} parameter use string.`);
80-
}
81-
validateObj[name] = {
82-
errorMsg: getErrorMsg(comment),
83-
value: removeSurroundingQuotes(value),
84-
};
85-
break;
86-
default:
87-
if (name.startsWith('is')) {
88-
const errorMsg = getErrorMsg(comment, false);
89-
if (errorMsg) {
90-
validateObj[name] = {
91-
errorMsg,
92-
value: undefined,
93-
};
47+
switch (name) {
48+
case 'uniqueItems':
49+
validateObj[name] = {
50+
errorMsg: getErrorMsg(comment, false),
51+
value: undefined,
52+
};
53+
break;
54+
case 'minimum':
55+
case 'maximum':
56+
case 'minItems':
57+
case 'maxItems':
58+
case 'minLength':
59+
case 'maxLength':
60+
if (isNaN(value as any)) {
61+
throw new GenerateMetadataError(`${name} parameter use number.`);
9462
}
95-
}
96-
break;
97-
}
98-
return validateObj;
99-
}, {} as Tsoa.Validators & { [unknown: string]: { errorMsg: string; value: undefined } });
63+
validateObj[name] = {
64+
errorMsg: getErrorMsg(comment),
65+
value: Number(value),
66+
};
67+
break;
68+
case 'minDate':
69+
case 'maxDate':
70+
if (!validator.isISO8601(String(value), { strict: true })) {
71+
throw new GenerateMetadataError(`${name} parameter use date format ISO 8601 ex. 2017-05-14, 2017-05-14T05:18Z`);
72+
}
73+
validateObj[name] = {
74+
errorMsg: getErrorMsg(comment),
75+
value,
76+
};
77+
break;
78+
case 'pattern':
79+
if (typeof value !== 'string') {
80+
throw new GenerateMetadataError(`${name} parameter use string.`);
81+
}
82+
validateObj[name] = {
83+
errorMsg: getErrorMsg(comment),
84+
value: removeSurroundingQuotes(value),
85+
};
86+
break;
87+
default:
88+
if (name.startsWith('is')) {
89+
const errorMsg = getErrorMsg(comment, false);
90+
if (errorMsg) {
91+
validateObj[name] = {
92+
errorMsg,
93+
value: undefined,
94+
};
95+
}
96+
}
97+
break;
98+
}
99+
return validateObj;
100+
},
101+
{} as Tsoa.Validators & { [unknown: string]: { errorMsg: string; value: undefined } },
102+
);
100103
}
101104

102105
export function getPropertyValidators(property: ts.Node): Tsoa.Validators | undefined {
@@ -109,6 +112,15 @@ export function getPropertyValidators(property: ts.Node): Tsoa.Validators | unde
109112
}
110113
return comment.split(' ')[0];
111114
}
115+
function getFullValue(comment?: string) {
116+
if (!comment) {
117+
return;
118+
}
119+
if (comment.includes('\n')) {
120+
return comment.split('\n')[0];
121+
}
122+
return comment;
123+
}
112124
function getErrorMsg(comment?: string, isValue = true) {
113125
if (!comment) {
114126
return;
@@ -125,65 +137,77 @@ export function getPropertyValidators(property: ts.Node): Tsoa.Validators | unde
125137
}
126138
}
127139

128-
return tags.reduce((validateObj, tag) => {
129-
const name = tag.tagName.text;
130-
const comment = tag.comment;
131-
const value = getValue(commentToString(comment));
140+
return tags.reduce(
141+
(validateObj, tag) => {
142+
const name = tag.tagName.text;
143+
const comment = tag.comment;
144+
const value = getValue(commentToString(comment));
132145

133-
switch (name) {
134-
case 'uniqueItems':
135-
validateObj[name] = {
136-
errorMsg: getErrorMsg(commentToString(comment), false),
137-
value: undefined,
138-
};
139-
break;
140-
case 'minimum':
141-
case 'maximum':
142-
case 'minItems':
143-
case 'maxItems':
144-
case 'minLength':
145-
case 'maxLength':
146-
if (isNaN(value as any)) {
147-
throw new GenerateMetadataError(`${name} parameter use number.`);
148-
}
149-
validateObj[name] = {
150-
errorMsg: getErrorMsg(commentToString(comment)),
151-
value: Number(value),
152-
};
153-
break;
154-
case 'minDate':
155-
case 'maxDate':
156-
if (!validator.isISO8601(String(value), { strict: true })) {
157-
throw new GenerateMetadataError(`${name} parameter use date format ISO 8601 ex. 2017-05-14, 2017-05-14T05:18Z`);
158-
}
159-
validateObj[name] = {
160-
errorMsg: getErrorMsg(commentToString(comment)),
161-
value,
162-
};
163-
break;
164-
case 'pattern':
165-
if (typeof value !== 'string') {
166-
throw new GenerateMetadataError(`${name} parameter use string.`);
167-
}
168-
validateObj[name] = {
169-
errorMsg: getErrorMsg(commentToString(comment)),
170-
value: removeSurroundingQuotes(value),
171-
};
172-
break;
173-
default:
174-
if (name.startsWith('is')) {
175-
const errorMsg = getErrorMsg(commentToString(comment), false);
176-
if (errorMsg) {
177-
validateObj[name] = {
178-
errorMsg,
179-
value: undefined,
180-
};
146+
switch (name) {
147+
case 'uniqueItems':
148+
validateObj[name] = {
149+
errorMsg: getErrorMsg(commentToString(comment), false),
150+
value: undefined,
151+
};
152+
break;
153+
case 'minimum':
154+
case 'maximum':
155+
case 'minItems':
156+
case 'maxItems':
157+
case 'minLength':
158+
case 'maxLength':
159+
if (isNaN(value as any)) {
160+
throw new GenerateMetadataError(`${name} parameter use number.`);
181161
}
182-
}
183-
break;
184-
}
185-
return validateObj;
186-
}, {} as Tsoa.Validators & { [unknown: string]: { errorMsg: string; value: undefined } });
162+
validateObj[name] = {
163+
errorMsg: getErrorMsg(commentToString(comment)),
164+
value: Number(value),
165+
};
166+
break;
167+
case 'minDate':
168+
case 'maxDate':
169+
if (!validator.isISO8601(String(value), { strict: true })) {
170+
throw new GenerateMetadataError(`${name} parameter use date format ISO 8601 ex. 2017-05-14, 2017-05-14T05:18Z`);
171+
}
172+
validateObj[name] = {
173+
errorMsg: getErrorMsg(commentToString(comment)),
174+
value,
175+
};
176+
break;
177+
case 'pattern':
178+
if (typeof value !== 'string') {
179+
throw new GenerateMetadataError(`${name} parameter use string.`);
180+
}
181+
validateObj[name] = {
182+
errorMsg: getErrorMsg(commentToString(comment)),
183+
value: removeSurroundingQuotes(value),
184+
};
185+
break;
186+
case 'title':
187+
if (typeof value !== 'string') {
188+
throw new GenerateMetadataError(`${name} parameter use string.`);
189+
}
190+
validateObj[name] = {
191+
errorMsg: getErrorMsg(commentToString(comment)),
192+
value: getFullValue(commentToString(comment)),
193+
};
194+
break;
195+
default:
196+
if (name.startsWith('is')) {
197+
const errorMsg = getErrorMsg(commentToString(comment), false);
198+
if (errorMsg) {
199+
validateObj[name] = {
200+
errorMsg,
201+
value: undefined,
202+
};
203+
}
204+
}
205+
break;
206+
}
207+
return validateObj;
208+
},
209+
{} as Tsoa.Validators & { [unknown: string]: { errorMsg: string; value: undefined } },
210+
);
187211
}
188212

189213
function getParameterTagSupport() {
@@ -206,6 +230,7 @@ function getParameterTagSupport() {
206230
'maximum',
207231
'minDate',
208232
'maxDate',
233+
'title',
209234
];
210235
}
211236

packages/runtime/src/routeGeneration/templateHelpers.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -826,6 +826,7 @@ export interface StringValidator {
826826
minLength?: { value: number; errorMsg?: string };
827827
maxLength?: { value: number; errorMsg?: string };
828828
pattern?: { value: string; errorMsg?: string };
829+
title?: { value: string; errorMsg?: string };
829830
}
830831

831832
export interface BooleanValidator {

tests/fixtures/testModel.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1143,6 +1143,7 @@ export class TestClassModel extends TestClassBaseModel {
11431143
* @maxLength 20
11441144
* @pattern ^[a-zA-Z]+$
11451145
* @example "classPropExample"
1146+
* @title Example title
11461147
*/
11471148
public publicStringProperty!: string;
11481149
/**

tests/unit/swagger/definitionsGeneration/definitions.spec.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1248,6 +1248,7 @@ describe('Definition generation', () => {
12481248
description: 'This is a description of a public string property',
12491249
format: undefined,
12501250
example: 'classPropExample',
1251+
title: 'Example title',
12511252
},
12521253
defaultValue2: { type: 'string', default: 'Default Value 2', description: undefined, format: undefined, example: undefined },
12531254
account: { $ref: '#/definitions/Account', format: undefined, description: undefined, example: undefined },

0 commit comments

Comments
 (0)