@trapi/metadata 1.0.0-alpha.2 → 1.0.0-alpha.3

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (109) hide show
  1. package/dist/cache/driver.js.map +1 -1
  2. package/dist/decorator/constants.d.ts +13 -12
  3. package/dist/decorator/constants.d.ts.map +1 -1
  4. package/dist/decorator/constants.js +13 -12
  5. package/dist/decorator/constants.js.map +1 -1
  6. package/dist/decorator/preset/utils/load.d.ts.map +1 -1
  7. package/dist/decorator/preset/utils/load.js +1 -4
  8. package/dist/decorator/preset/utils/load.js.map +1 -1
  9. package/dist/decorator/property-manager/module.d.ts +6 -8
  10. package/dist/decorator/property-manager/module.d.ts.map +1 -1
  11. package/dist/decorator/property-manager/module.js +14 -20
  12. package/dist/decorator/property-manager/module.js.map +1 -1
  13. package/dist/decorator/property-manager/utils.d.ts +4 -5
  14. package/dist/decorator/property-manager/utils.d.ts.map +1 -1
  15. package/dist/decorator/property-manager/utils.js +55 -84
  16. package/dist/decorator/property-manager/utils.js.map +1 -1
  17. package/dist/decorator/sets/class.d.ts +2 -2
  18. package/dist/decorator/sets/class.d.ts.map +1 -1
  19. package/dist/decorator/sets/method.d.ts +2 -2
  20. package/dist/decorator/sets/method.d.ts.map +1 -1
  21. package/dist/decorator/sets/mixed.d.ts +6 -2
  22. package/dist/decorator/sets/mixed.d.ts.map +1 -1
  23. package/dist/decorator/sets/parameter.d.ts +2 -2
  24. package/dist/decorator/sets/parameter.d.ts.map +1 -1
  25. package/dist/decorator/sets/request.d.ts +2 -2
  26. package/dist/decorator/sets/request.d.ts.map +1 -1
  27. package/dist/decorator/sets/response.d.ts +3 -2
  28. package/dist/decorator/sets/response.d.ts.map +1 -1
  29. package/dist/decorator/type.d.ts +8 -15
  30. package/dist/decorator/type.d.ts.map +1 -1
  31. package/dist/error/index.d.ts +0 -1
  32. package/dist/error/index.d.ts.map +1 -1
  33. package/dist/error/index.js +0 -1
  34. package/dist/error/index.js.map +1 -1
  35. package/dist/generator/abstract.d.ts +6 -13
  36. package/dist/generator/abstract.d.ts.map +1 -1
  37. package/dist/generator/abstract.js +48 -56
  38. package/dist/generator/abstract.js.map +1 -1
  39. package/dist/generator/controller/module.d.ts +2 -2
  40. package/dist/generator/controller/module.d.ts.map +1 -1
  41. package/dist/generator/controller/module.js +24 -19
  42. package/dist/generator/controller/module.js.map +1 -1
  43. package/dist/generator/controller/type.d.ts +12 -7
  44. package/dist/generator/controller/type.d.ts.map +1 -1
  45. package/dist/generator/metadata/index.d.ts +1 -0
  46. package/dist/generator/metadata/index.d.ts.map +1 -1
  47. package/dist/generator/metadata/index.js +1 -0
  48. package/dist/generator/metadata/index.js.map +1 -1
  49. package/dist/generator/metadata/module.d.ts +0 -2
  50. package/dist/generator/metadata/module.d.ts.map +1 -1
  51. package/dist/generator/metadata/module.js +13 -33
  52. package/dist/generator/metadata/module.js.map +1 -1
  53. package/dist/generator/metadata/utils.d.ts +3 -0
  54. package/dist/generator/metadata/utils.d.ts.map +1 -0
  55. package/dist/generator/metadata/utils.js +19 -0
  56. package/dist/generator/metadata/utils.js.map +1 -0
  57. package/dist/generator/method/module.d.ts +8 -9
  58. package/dist/generator/method/module.d.ts.map +1 -1
  59. package/dist/generator/method/module.js +53 -72
  60. package/dist/generator/method/module.js.map +1 -1
  61. package/dist/generator/parameter/constants.d.ts +19 -0
  62. package/dist/generator/parameter/constants.d.ts.map +1 -0
  63. package/dist/generator/parameter/constants.js +30 -0
  64. package/dist/generator/parameter/constants.js.map +1 -0
  65. package/dist/generator/parameter/error.d.ts +35 -0
  66. package/dist/generator/parameter/error.d.ts.map +1 -0
  67. package/dist/generator/parameter/error.js +68 -0
  68. package/dist/generator/parameter/error.js.map +1 -0
  69. package/dist/generator/parameter/index.d.ts +2 -0
  70. package/dist/generator/parameter/index.d.ts.map +1 -1
  71. package/dist/generator/parameter/index.js +2 -0
  72. package/dist/generator/parameter/index.js.map +1 -1
  73. package/dist/generator/parameter/module.d.ts +7 -6
  74. package/dist/generator/parameter/module.d.ts.map +1 -1
  75. package/dist/generator/parameter/module.js +362 -196
  76. package/dist/generator/parameter/module.js.map +1 -1
  77. package/dist/generator/parameter/type.d.ts +8 -5
  78. package/dist/generator/parameter/type.d.ts.map +1 -1
  79. package/dist/generator/parameter/validator.d.ts.map +1 -1
  80. package/dist/generator/parameter/validator.js +15 -9
  81. package/dist/generator/parameter/validator.js.map +1 -1
  82. package/dist/generator/type.d.ts +8 -5
  83. package/dist/generator/type.d.ts.map +1 -1
  84. package/dist/module.d.ts.map +1 -1
  85. package/dist/module.js +10 -3
  86. package/dist/module.js.map +1 -1
  87. package/dist/resolver/module.d.ts +1 -1
  88. package/dist/resolver/module.d.ts.map +1 -1
  89. package/dist/resolver/module.js +7 -7
  90. package/dist/resolver/module.js.map +1 -1
  91. package/dist/utils/js-doc/index.d.ts +1 -0
  92. package/dist/utils/js-doc/index.d.ts.map +1 -1
  93. package/dist/utils/js-doc/index.js +1 -0
  94. package/dist/utils/js-doc/index.js.map +1 -1
  95. package/dist/utils/js-doc/module.d.ts.map +1 -1
  96. package/dist/utils/js-doc/module.js +2 -7
  97. package/dist/utils/js-doc/module.js.map +1 -1
  98. package/dist/utils/js-doc/utils.d.ts +3 -0
  99. package/dist/utils/js-doc/utils.d.ts.map +1 -0
  100. package/dist/utils/js-doc/utils.js +29 -0
  101. package/dist/utils/js-doc/utils.js.map +1 -0
  102. package/dist/utils/object.d.ts.map +1 -1
  103. package/dist/utils/object.js +1 -0
  104. package/dist/utils/object.js.map +1 -1
  105. package/package.json +5 -4
  106. package/dist/error/parameter-invalid.d.ts +0 -4
  107. package/dist/error/parameter-invalid.d.ts.map +0 -1
  108. package/dist/error/parameter-invalid.js +0 -14
  109. package/dist/error/parameter-invalid.js.map +0 -1
@@ -30,11 +30,14 @@ var __importStar = (this && this.__importStar) || function (mod) {
30
30
  };
31
31
  Object.defineProperty(exports, "__esModule", { value: true });
32
32
  exports.ParameterGenerator = void 0;
33
+ const locter_1 = require("locter");
33
34
  const ts = __importStar(require("typescript"));
34
35
  const decorator_1 = require("../../decorator");
35
- const error_1 = require("../../error");
36
36
  const resolver_1 = require("../../resolver");
37
37
  const utils_1 = require("../../utils");
38
+ const constants_1 = require("./constants");
39
+ const error_1 = require("./error");
40
+ const validator_1 = require("./validator");
38
41
  const parameterKeys = [
39
42
  decorator_1.DecoratorID.CONTEXT,
40
43
  decorator_1.DecoratorID.PARAM,
@@ -46,10 +49,10 @@ const parameterKeys = [
46
49
  decorator_1.DecoratorID.HEADERS,
47
50
  decorator_1.DecoratorID.COOKIE,
48
51
  decorator_1.DecoratorID.COOKIES,
49
- decorator_1.DecoratorID.PATH_PARAM,
50
- decorator_1.DecoratorID.PATH_PARAMS,
51
- decorator_1.DecoratorID.FILE_PARAM,
52
- decorator_1.DecoratorID.FILES_PARAM,
52
+ decorator_1.DecoratorID.PATH,
53
+ decorator_1.DecoratorID.PATHS,
54
+ decorator_1.DecoratorID.FILE,
55
+ decorator_1.DecoratorID.FILES,
53
56
  ];
54
57
  class ParameterGenerator {
55
58
  constructor(parameter, method, path, current) {
@@ -61,248 +64,314 @@ class ParameterGenerator {
61
64
  generate() {
62
65
  const decorators = (0, utils_1.getNodeDecorators)(this.parameter);
63
66
  for (let i = 0; i < parameterKeys.length; i++) {
64
- const representation = this.current.decoratorResolver.match(parameterKeys[i], decorators);
65
- if (typeof representation === 'undefined') {
67
+ const manager = this.current.decoratorResolver.match(parameterKeys[i], decorators);
68
+ if (typeof manager === 'undefined') {
66
69
  continue;
67
70
  }
68
- switch (representation.key) {
71
+ switch (manager.representation.id) {
69
72
  case decorator_1.DecoratorID.CONTEXT:
70
73
  return this.getContextParameter();
71
74
  case decorator_1.DecoratorID.PARAM:
72
75
  case decorator_1.DecoratorID.PARAMS:
73
- return this.getRequestParameter(representation);
76
+ return this.getParamParameter(manager);
74
77
  case decorator_1.DecoratorID.FORM:
75
- return this.getFormParameter(representation);
78
+ return this.getFormParameter(manager);
76
79
  case decorator_1.DecoratorID.QUERY:
77
- return this.getQueryParameter(representation);
80
+ return this.getQueryParameter(manager);
78
81
  case decorator_1.DecoratorID.BODY:
79
- return this.getBodyParameter(representation);
82
+ return this.getBodyParameter(manager);
80
83
  case decorator_1.DecoratorID.HEADER:
81
84
  case decorator_1.DecoratorID.HEADERS:
82
- return this.getHeaderParameter(representation);
85
+ return this.getHeaderParameter(manager);
83
86
  case decorator_1.DecoratorID.COOKIE:
84
87
  case decorator_1.DecoratorID.COOKIES:
85
- return this.getCookieParameter(representation);
86
- case decorator_1.DecoratorID.PATH_PARAM:
87
- case decorator_1.DecoratorID.PATH_PARAMS:
88
- return this.getPathParameter(representation);
89
- case decorator_1.DecoratorID.FILE_PARAM:
90
- return this.getFileParameter(representation);
91
- case decorator_1.DecoratorID.FILES_PARAM:
92
- return this.getFileParameter(representation, true);
88
+ return this.getCookieParameter(manager);
89
+ case decorator_1.DecoratorID.PATH:
90
+ case decorator_1.DecoratorID.PATHS:
91
+ return this.getPathParameter(manager);
92
+ case decorator_1.DecoratorID.FILE:
93
+ case decorator_1.DecoratorID.FILES:
94
+ return this.getFileParameter(manager);
93
95
  }
94
96
  }
97
+ // todo: add BodyProp decorator, due the fact that single body parameter can contain object.
95
98
  return this.getBodyParameter();
96
99
  }
97
- getCurrentLocation() {
98
- const methodId = this.parameter.parent.name;
99
- const controllerId = this.parameter.parent.parent.name;
100
- return `${controllerId.text}.${methodId.text}`;
101
- }
102
- getRequestParameter(manager) {
103
- const parameterName = this.parameter.name.text;
104
- let name = parameterName;
105
- const type = this.getValidatedType(this.parameter);
106
- if (!this.supportsBodyParameters(this.method)) {
107
- throw new Error(`Param can't support '${this.getCurrentLocation()}' method.`);
100
+ buildParametersForObject(type, details) {
101
+ if (type.properties.length === 0) {
102
+ return [];
108
103
  }
109
- const value = manager.getPropertyValue('value');
110
- if (typeof value === 'string') {
111
- name = value;
104
+ const parameterName = this.parameter.name.text;
105
+ const initializerValue = (0, utils_1.getInitializerValue)(this.parameter.initializer, this.current.typeChecker, type);
106
+ const output = [];
107
+ for (let i = 0; i < type.properties.length; i++) {
108
+ const property = type.properties[i];
109
+ const propertyDefaultValue = initializerValue[property.name];
110
+ let propertyRequired = !this.parameter.questionToken;
111
+ if (propertyRequired) {
112
+ propertyRequired = property.required;
113
+ }
114
+ output.push({
115
+ ...details,
116
+ default: property.default || propertyDefaultValue,
117
+ description: property.description || details.description || this.getParameterDescription(),
118
+ name: property.name,
119
+ parameterName,
120
+ required: propertyRequired,
121
+ type: property.type,
122
+ deprecated: property.deprecated || this.getParameterDeprecation(),
123
+ });
124
+ // todo: example, format
112
125
  }
113
- return {
114
- default: (0, utils_1.getInitializerValue)(this.parameter.initializer, this.current.typeChecker, type),
115
- description: this.getParameterDescription(),
116
- in: 'param',
117
- name: name || parameterName,
118
- parameterName,
119
- required: !this.parameter.questionToken,
120
- type,
121
- deprecated: this.getParameterDeprecation(),
122
- };
126
+ return output;
127
+ }
128
+ getParamParameter(manager) {
129
+ return [
130
+ ...this.getBodyParameter(manager),
131
+ ...this.getCookieParameter(manager),
132
+ ];
123
133
  }
124
134
  getContextParameter() {
125
135
  const parameterName = this.parameter.name.text;
126
- return {
127
- description: this.getParameterDescription(),
128
- in: 'context',
129
- name: parameterName,
130
- parameterName,
131
- required: !this.parameter.questionToken,
132
- type: null,
133
- };
134
- }
135
- /*
136
- private getFileParameter(parameter: ts.ParameterDeclaration): Metadata.Parameter{
137
- const parameterName = (parameter.name as ts.Identifier).text;
138
-
139
- if (!this.supportsBodyParameters(this.method)) {
140
- throw new Error(`FileParam can't support '${this.getCurrentLocation()}' method.`);
141
- }
142
-
143
- return {
144
- description: this.getParameterDescription(parameter),
145
- in: 'formData',
146
- name: getDecoratorTextValue(this.parameter, ident => ident.text === 'FileParam') || parameterName,
147
- parameterName: parameterName,
148
- required: !parameter.questionToken,
149
- type: { typeName: 'file' }
150
- };
136
+ // todo: req, res, next should maybe be separate parameter sources.
137
+ return [
138
+ {
139
+ description: this.getParameterDescription(),
140
+ in: constants_1.ParameterSource.CONTEXT,
141
+ name: parameterName,
142
+ parameterName,
143
+ required: !this.parameter.questionToken,
144
+ type: null,
145
+ },
146
+ ];
151
147
  }
152
- */
153
- getFileParameter(representationManager, isArray) {
148
+ getFileParameter(manager) {
154
149
  const parameterName = this.parameter.name.text;
155
150
  let name = parameterName;
156
- if (!this.supportsBodyParameters(this.method)) {
157
- throw new Error(`File(s)Param can't support '${this.getCurrentLocation()}' method.`);
158
- }
159
- const value = representationManager.getPropertyValue('value');
151
+ const value = manager.get('value');
160
152
  if (typeof value === 'string') {
161
153
  name = value;
162
154
  }
155
+ if (!this.isBodySupportedForMethod(this.method)) {
156
+ throw error_1.ParameterError.methodUnsupported({
157
+ decoratorName: manager.representation.name,
158
+ propertyName: name,
159
+ method: this.method,
160
+ node: this.parameter,
161
+ });
162
+ }
163
163
  const elementType = { typeName: 'file' };
164
164
  let type;
165
- if (isArray) {
165
+ if (manager.representation.id === decorator_1.DecoratorID.FILES) {
166
166
  type = { typeName: 'array', elementType };
167
167
  }
168
168
  else {
169
169
  type = elementType;
170
170
  }
171
- return {
172
- default: (0, utils_1.getInitializerValue)(this.parameter.initializer, this.current.typeChecker, type),
173
- description: this.getParameterDescription(),
174
- in: 'formData',
175
- name: name || parameterName,
176
- parameterName,
177
- required: !this.parameter.questionToken && !this.parameter.initializer,
178
- type,
179
- deprecated: this.getParameterDeprecation(),
180
- };
171
+ const { examples, exampleLabels } = this.getParameterExample(parameterName);
172
+ return [
173
+ {
174
+ default: (0, utils_1.getInitializerValue)(this.parameter.initializer, this.current.typeChecker, type),
175
+ description: this.getParameterDescription(),
176
+ examples,
177
+ exampleLabels,
178
+ in: constants_1.ParameterSource.FORM_DATA,
179
+ name: name || parameterName,
180
+ parameterName,
181
+ required: !this.parameter.questionToken && !this.parameter.initializer,
182
+ type,
183
+ deprecated: this.getParameterDeprecation(),
184
+ validators: (0, validator_1.getParameterValidators)(this.parameter, parameterName),
185
+ },
186
+ ];
181
187
  }
182
- getFormParameter(representationManager) {
188
+ getFormParameter(manager) {
183
189
  const parameterName = this.parameter.name.text;
184
190
  let name = parameterName;
185
191
  const type = this.getValidatedType(this.parameter);
186
- if (!this.supportsBodyParameters(this.method)) {
187
- throw new Error(`Form can't support '${this.getCurrentLocation()}' method.`);
192
+ if (!this.isBodySupportedForMethod(this.method)) {
193
+ throw error_1.ParameterError.methodUnsupported({
194
+ decoratorName: manager.representation.name,
195
+ propertyName: name,
196
+ method: this.method,
197
+ node: this.parameter,
198
+ });
188
199
  }
189
- const value = representationManager.getPropertyValue('value');
200
+ const value = manager.get('value');
190
201
  if (typeof value === 'string') {
191
202
  name = value;
192
203
  }
193
- return {
194
- default: (0, utils_1.getInitializerValue)(this.parameter.initializer, this.current.typeChecker, type),
195
- description: this.getParameterDescription(),
196
- in: 'formData',
197
- name: name || parameterName,
198
- parameterName,
199
- required: !this.parameter.questionToken && !this.parameter.initializer,
200
- type,
201
- deprecated: this.getParameterDeprecation(),
202
- };
204
+ const { examples, exampleLabels } = this.getParameterExample(parameterName);
205
+ return [
206
+ {
207
+ default: (0, utils_1.getInitializerValue)(this.parameter.initializer, this.current.typeChecker, type),
208
+ description: this.getParameterDescription(),
209
+ examples,
210
+ exampleLabels,
211
+ in: constants_1.ParameterSource.FORM_DATA,
212
+ name: name || parameterName,
213
+ parameterName,
214
+ required: !this.parameter.questionToken && !this.parameter.initializer,
215
+ type,
216
+ deprecated: this.getParameterDeprecation(),
217
+ validators: (0, validator_1.getParameterValidators)(this.parameter, parameterName),
218
+ },
219
+ ];
203
220
  }
204
221
  getCookieParameter(manager) {
205
222
  const parameterName = this.parameter.name.text;
206
223
  let name = parameterName;
207
224
  const type = this.getValidatedType(this.parameter);
208
- if (!this.supportPathDataType(type)) {
209
- throw new Error(`Cookie can't support '${this.getCurrentLocation()}' method.`);
225
+ const { examples, exampleLabels } = this.getParameterExample(parameterName);
226
+ if (type.typeName === 'nestedObjectLiteral' ||
227
+ type.typeName === 'refObject') {
228
+ return this.buildParametersForObject(type, {
229
+ in: constants_1.ParameterSource.COOKIE,
230
+ examples,
231
+ exampleLabels,
232
+ });
233
+ }
234
+ if (!this.isTypeSupported(type)) {
235
+ throw error_1.ParameterError.typeUnsupported({
236
+ decoratorName: manager.representation.name,
237
+ propertyName: name,
238
+ type,
239
+ node: this.parameter,
240
+ });
210
241
  }
211
- const value = manager.getPropertyValue('value');
242
+ const value = manager.get('value');
212
243
  if (typeof value === 'string') {
213
244
  name = value;
214
245
  }
215
- return {
216
- default: (0, utils_1.getInitializerValue)(this.parameter.initializer, this.current.typeChecker, type),
217
- description: this.getParameterDescription(),
218
- in: 'cookie',
219
- name: name || parameterName,
220
- parameterName,
221
- required: !this.parameter.questionToken && !this.parameter.initializer,
222
- type,
223
- deprecated: this.getParameterDeprecation(),
224
- };
246
+ return [
247
+ {
248
+ default: (0, utils_1.getInitializerValue)(this.parameter.initializer, this.current.typeChecker, type),
249
+ description: this.getParameterDescription(),
250
+ examples,
251
+ exampleLabels,
252
+ in: constants_1.ParameterSource.COOKIE,
253
+ name: name || parameterName,
254
+ parameterName,
255
+ required: !this.parameter.questionToken && !this.parameter.initializer,
256
+ type,
257
+ deprecated: this.getParameterDeprecation(),
258
+ validators: (0, validator_1.getParameterValidators)(this.parameter, parameterName),
259
+ },
260
+ ];
225
261
  }
226
262
  getBodyParameter(manager) {
227
263
  const parameterName = this.parameter.name.text;
228
264
  let name = parameterName;
229
- const type = this.getValidatedType(this.parameter);
230
- if (!this.supportsBodyParameters(this.method)) {
231
- throw new Error(`Body can't support ${this.method} method`);
232
- }
233
- if (typeof manager !== 'undefined') {
234
- const value = manager.getPropertyValue('value');
265
+ let source = constants_1.ParameterSource.BODY;
266
+ if (manager) {
267
+ const value = manager.get('value');
235
268
  if (typeof value === 'string') {
236
269
  name = value;
270
+ source = constants_1.ParameterSource.BODY_PROP;
237
271
  }
238
272
  }
239
- return {
240
- default: (0, utils_1.getInitializerValue)(this.parameter.initializer, this.current.typeChecker, type),
241
- description: this.getParameterDescription(),
242
- in: 'body',
243
- name: name || parameterName,
244
- parameterName,
245
- required: !this.parameter.questionToken && !this.parameter.initializer,
246
- type,
247
- deprecated: this.getParameterDeprecation(),
248
- };
273
+ const type = this.getValidatedType(this.parameter);
274
+ if (!this.isBodySupportedForMethod(this.method)) {
275
+ throw error_1.ParameterError.methodUnsupported({
276
+ decoratorName: manager ? manager.representation.name : 'Body',
277
+ propertyName: name,
278
+ method: this.method,
279
+ node: this.parameter,
280
+ });
281
+ }
282
+ const { examples, exampleLabels } = this.getParameterExample(parameterName);
283
+ return [
284
+ {
285
+ default: (0, utils_1.getInitializerValue)(this.parameter.initializer, this.current.typeChecker, type),
286
+ description: this.getParameterDescription(),
287
+ examples,
288
+ exampleLabels,
289
+ in: source,
290
+ name: name || parameterName,
291
+ parameterName,
292
+ required: !this.parameter.questionToken && !this.parameter.initializer,
293
+ type,
294
+ deprecated: this.getParameterDeprecation(),
295
+ validators: (0, validator_1.getParameterValidators)(this.parameter, parameterName),
296
+ },
297
+ ];
249
298
  }
250
299
  getHeaderParameter(manager) {
251
300
  const parameterName = this.parameter.name.text;
252
301
  let name = parameterName;
253
302
  const type = this.getValidatedType(this.parameter);
254
- if (!this.supportPathDataType(type)) {
255
- throw new error_1.InvalidParameterException(`Parameter '${parameterName}' can't be passed as a header parameter in '${this.getCurrentLocation()}'.`);
256
- }
257
- const value = manager.getPropertyValue('value');
303
+ const value = manager.get('value');
258
304
  if (typeof value === 'string') {
259
305
  name = value;
260
306
  }
261
- return {
262
- default: (0, utils_1.getInitializerValue)(this.parameter.initializer, this.current.typeChecker, type),
263
- description: this.getParameterDescription(),
264
- in: 'header',
265
- name: name || parameterName,
266
- parameterName,
267
- required: !this.parameter.questionToken && !this.parameter.initializer,
268
- type,
269
- deprecated: this.getParameterDeprecation(),
270
- };
307
+ const { examples, exampleLabels } = this.getParameterExample(parameterName);
308
+ if (type.typeName === 'nestedObjectLiteral' || type.typeName === 'refObject') {
309
+ return this.buildParametersForObject(type, {
310
+ in: constants_1.ParameterSource.HEADER,
311
+ examples,
312
+ exampleLabels,
313
+ });
314
+ }
315
+ if (!this.isTypeSupported(type)) {
316
+ throw error_1.ParameterError.typeUnsupported({
317
+ decoratorName: manager.representation.name,
318
+ propertyName: name,
319
+ type,
320
+ node: this.parameter,
321
+ });
322
+ }
323
+ return [
324
+ {
325
+ default: (0, utils_1.getInitializerValue)(this.parameter.initializer, this.current.typeChecker, type),
326
+ description: this.getParameterDescription(),
327
+ examples,
328
+ exampleLabels,
329
+ in: constants_1.ParameterSource.HEADER,
330
+ name: name || parameterName,
331
+ parameterName,
332
+ required: !this.parameter.questionToken && !this.parameter.initializer,
333
+ type,
334
+ deprecated: this.getParameterDeprecation(),
335
+ validators: (0, validator_1.getParameterValidators)(this.parameter, parameterName),
336
+ },
337
+ ];
271
338
  }
272
- getQueryParameter(representationManager) {
339
+ getQueryParameter(manager) {
273
340
  const parameterName = this.parameter.name.text;
274
341
  const type = this.getValidatedType(this.parameter);
275
- if (!this.supportQueryDataType(type)) {
276
- /*
277
- const arrayType = getCommonPrimitiveAndArrayUnionType(parameter.type);
278
- if (arrayType && this.supportQueryDataType(arrayType)) {
279
- type = arrayType;
280
- } else {
281
- throw new InvalidParameterException(
282
- `Parameter '${parameterName}' can't be passed as a query parameter in '${this.getCurrentLocation()}'.`
283
- );
284
- }
285
- */
286
- // throw new InvalidParameterException(
287
- // `Parameter '${parameterName}' can't be passed as a query parameter in '${this.getCurrentLocation()}'.`
288
- // );
289
- }
290
342
  let name = parameterName;
291
343
  let options = {};
292
- const nameValue = representationManager.getPropertyValue('value');
344
+ let source = constants_1.ParameterSource.QUERY;
345
+ const nameValue = manager.get('value');
293
346
  if (typeof nameValue === 'string') {
294
347
  name = nameValue;
348
+ source = constants_1.ParameterSource.QUERY_PROP;
295
349
  }
296
- const optionsValue = representationManager.getPropertyValue('options');
297
- if (typeof optionsValue !== 'undefined') {
350
+ const optionsValue = manager.get('options');
351
+ if ((0, locter_1.isObject)(optionsValue)) {
298
352
  options = optionsValue;
299
353
  }
354
+ const { examples, exampleLabels } = this.getParameterExample(parameterName);
355
+ if (source === constants_1.ParameterSource.QUERY) {
356
+ // yeah! we can transform the object to individual properties.
357
+ if (type.typeName === 'nestedObjectLiteral' ||
358
+ type.typeName === 'refObject') {
359
+ return this.buildParametersForObject(type, {
360
+ in: constants_1.ParameterSource.QUERY_PROP,
361
+ examples,
362
+ exampleLabels,
363
+ });
364
+ // todo: transform ( type.typeName === 'array')
365
+ }
366
+ }
300
367
  const properties = {
301
368
  allowEmptyValue: options.allowEmptyValue,
302
369
  collectionFormat: options.collectionFormat,
303
370
  default: (0, utils_1.getInitializerValue)(this.parameter.initializer, this.current.typeChecker, type),
304
371
  description: this.getParameterDescription(),
305
- in: 'query',
372
+ examples,
373
+ exampleLabels,
374
+ in: source,
306
375
  maxItems: options.maxItems,
307
376
  minItems: options.minItems,
308
377
  name,
@@ -310,41 +379,101 @@ class ParameterGenerator {
310
379
  required: !this.parameter.questionToken && !this.parameter.initializer,
311
380
  type,
312
381
  deprecated: this.getParameterDeprecation(),
382
+ validators: (0, validator_1.getParameterValidators)(this.parameter, parameterName),
313
383
  };
314
384
  if (type.typeName === 'array') {
315
- return {
316
- ...properties,
317
- collectionFormat: 'multi',
385
+ if (!this.isTypeSupported(type.elementType)) {
386
+ throw error_1.ParameterError.typeUnsupported({
387
+ decoratorName: manager.representation.name,
388
+ propertyName: name,
389
+ type: type.elementType,
390
+ node: this.parameter,
391
+ });
392
+ }
393
+ return [{
394
+ ...properties,
395
+ collectionFormat: constants_1.CollectionFormat.MULTI,
396
+ type,
397
+ }];
398
+ }
399
+ // todo: investigate if this refEnum and union are valid types
400
+ if (!this.isTypeSupportedForQueryParameter(type)) {
401
+ throw error_1.ParameterError.typeUnsupported({
402
+ decoratorName: manager.representation.name,
403
+ propertyName: name,
318
404
  type,
319
- };
405
+ node: this.parameter,
406
+ });
320
407
  }
321
- return properties;
408
+ return [properties];
409
+ }
410
+ isTypeSupportedForQueryParameter(type) {
411
+ return this.isTypeSupported(type) ||
412
+ type.typeName === 'refEnum' ||
413
+ type.typeName === 'union';
322
414
  }
323
415
  getPathParameter(manager) {
324
416
  const parameterName = this.parameter.name.text;
325
- let pathName = parameterName;
417
+ let name = parameterName;
326
418
  const type = this.getValidatedType(this.parameter);
327
- const value = manager.getPropertyValue('value');
419
+ const value = manager.get('value');
328
420
  if (typeof value === 'string') {
329
- pathName = value;
421
+ name = value;
330
422
  }
331
- if (!this.supportPathDataType(type)) {
332
- throw new error_1.InvalidParameterException(`Parameter '${parameterName}:${type.typeName}' can't be passed as a path parameter in '${this.getCurrentLocation()}'.`);
423
+ const { examples, exampleLabels } = this.getParameterExample(parameterName);
424
+ if (type.typeName === 'nestedObjectLiteral' || type.typeName === 'refObject') {
425
+ const output = this.buildParametersForObject(type, {
426
+ in: constants_1.ParameterSource.PATH,
427
+ examples,
428
+ exampleLabels,
429
+ });
430
+ for (let i = 0; i < output.length; i++) {
431
+ if ((!this.path.includes(`{${output[i].name}}`)) &&
432
+ (!this.path.includes(`:${output[i].name}`))) {
433
+ throw error_1.ParameterError.invalidPathMatch({
434
+ decoratorName: manager.representation.name,
435
+ propertyName: name,
436
+ path: this.path,
437
+ node: this.parameter,
438
+ });
439
+ }
440
+ }
441
+ return output;
333
442
  }
334
- if ((!this.path.includes(`{${pathName}}`)) && (!this.path.includes(`:${pathName}`))) {
335
- throw new Error(`Parameter '${parameterName}' can't match in path: '${this.path}'`);
443
+ if (!this.isTypeSupported(type)) {
444
+ throw error_1.ParameterError.typeUnsupported({
445
+ decoratorName: manager.representation.name,
446
+ propertyName: name,
447
+ type,
448
+ node: this.parameter,
449
+ });
336
450
  }
337
- return {
338
- default: (0, utils_1.getInitializerValue)(this.parameter.initializer, this.current.typeChecker, type),
339
- description: this.getParameterDescription(),
340
- in: 'path',
341
- name: pathName,
342
- parameterName,
343
- required: true,
344
- type,
345
- deprecated: this.getParameterDeprecation(),
346
- };
451
+ if ((!this.path.includes(`{${name}}`)) &&
452
+ (!this.path.includes(`:${name}`))) {
453
+ throw error_1.ParameterError.invalidPathMatch({
454
+ decoratorName: manager.representation.name,
455
+ propertyName: name,
456
+ path: this.path,
457
+ node: this.parameter,
458
+ });
459
+ }
460
+ return [
461
+ {
462
+ default: (0, utils_1.getInitializerValue)(this.parameter.initializer, this.current.typeChecker, type),
463
+ description: this.getParameterDescription(),
464
+ examples,
465
+ exampleLabels,
466
+ in: constants_1.ParameterSource.PATH,
467
+ name: name || parameterName,
468
+ parameterName,
469
+ required: true,
470
+ type,
471
+ deprecated: this.getParameterDeprecation(),
472
+ validators: (0, validator_1.getParameterValidators)(this.parameter, parameterName),
473
+ },
474
+ ];
347
475
  }
476
+ // -------------------------------------------------------------------------------------
348
477
  getParameterDescription() {
349
478
  const symbol = this.current.typeChecker.getSymbolAtLocation(this.parameter.name);
350
479
  if (symbol) {
@@ -359,19 +488,56 @@ class ParameterGenerator {
359
488
  if ((0, utils_1.hasJSDocTag)(this.parameter, utils_1.JSDocTagName.DEPRECATED)) {
360
489
  return true;
361
490
  }
362
- const decorators = (0, utils_1.getNodeDecorators)(this.parameter, (identifier) => identifier.text === 'Deprecated');
363
- return decorators.length > 0;
491
+ const match = this.current.decoratorResolver.match(decorator_1.DecoratorID.DEPRECATED, this.parameter);
492
+ return !!match;
364
493
  }
365
- supportsBodyParameters(method) {
366
- return ['delete', 'post', 'put', 'patch', 'get'].some((m) => m === method);
494
+ getParameterExample(parameterName) {
495
+ const exampleLabels = [];
496
+ const examples = (0, utils_1.getJSDocTags)(this.parameter.parent, (tag) => {
497
+ const comment = (0, utils_1.transformJSDocComment)(tag.comment);
498
+ const isExample = (tag.tagName.text === utils_1.JSDocTagName.EXAMPLE || tag.tagName.escapedText === utils_1.JSDocTagName.EXAMPLE) &&
499
+ !!comment && comment.startsWith(parameterName);
500
+ if (isExample && comment) {
501
+ const hasExampleLabel = (comment.split(' ')[0].indexOf('.') || -1) > 0;
502
+ // custom example label is delimited by first '.' and the rest will all be included as example label
503
+ exampleLabels.push(hasExampleLabel ? comment.split(' ')[0].split('.').slice(1).join('.') : undefined);
504
+ }
505
+ return isExample ?? false;
506
+ }).map((tag) => ((0, utils_1.transformJSDocComment)(tag.comment) || '')
507
+ .replace(`${(0, utils_1.transformJSDocComment)(tag.comment)?.split(' ')[0] || ''}`, '')
508
+ .replace(/\r/g, ''));
509
+ if (examples.length === 0) {
510
+ return {
511
+ examples: undefined,
512
+ exampleLabels: undefined,
513
+ };
514
+ }
515
+ try {
516
+ return {
517
+ examples: examples.map((example) => JSON.parse(example)),
518
+ exampleLabels,
519
+ };
520
+ }
521
+ catch (e) {
522
+ throw error_1.ParameterError.invalidExampleSchema();
523
+ }
367
524
  }
368
- supportPathDataType(parameterType) {
369
- return ['string', 'integer', 'long', 'float', 'double', 'date', 'datetime', 'buffer', 'boolean', 'enum'].find((t) => t === parameterType.typeName);
525
+ isBodySupportedForMethod(method) {
526
+ return ['delete', 'post', 'put', 'patch', 'get'].some((m) => m === method);
370
527
  }
371
- supportQueryDataType(parameterType) {
372
- // Copied from supportPathDataType and added 'array'. Not sure if all options apply to queries, but kept to avoid breaking change.
373
- return ['string', 'integer', 'long', 'float', 'double', 'date',
374
- 'datetime', 'buffer', 'boolean', 'enum', 'array', 'object'].find((t) => t === parameterType.typeName);
528
+ isTypeSupported(parameterType) {
529
+ return [
530
+ 'string',
531
+ 'integer',
532
+ 'long',
533
+ 'float',
534
+ 'double',
535
+ 'date',
536
+ 'datetime',
537
+ 'buffer',
538
+ 'boolean',
539
+ 'enum',
540
+ ].find((t) => t === parameterType.typeName);
375
541
  }
376
542
  getValidatedType(parameter) {
377
543
  let typeNode = parameter.type;