@trapi/metadata 1.0.0-alpha.6 → 1.0.0-alpha.8

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 (191) hide show
  1. package/dist/cache/driver.d.ts +13 -13
  2. package/dist/cache/driver.js +83 -83
  3. package/dist/cache/index.d.ts +3 -3
  4. package/dist/cache/index.js +25 -25
  5. package/dist/cache/type.d.ts +32 -32
  6. package/dist/cache/type.js +8 -8
  7. package/dist/cache/utils.d.ts +3 -3
  8. package/dist/cache/utils.js +52 -52
  9. package/dist/config/index.d.ts +1 -1
  10. package/dist/config/index.js +23 -23
  11. package/dist/config/type.d.ts +36 -36
  12. package/dist/config/type.js +8 -8
  13. package/dist/decorator/constants.d.ts +40 -40
  14. package/dist/decorator/constants.js +52 -52
  15. package/dist/decorator/index.d.ts +6 -6
  16. package/dist/decorator/index.js +28 -28
  17. package/dist/decorator/preset/index.d.ts +2 -2
  18. package/dist/decorator/preset/index.js +24 -24
  19. package/dist/decorator/preset/type.d.ts +5 -5
  20. package/dist/decorator/preset/type.js +8 -8
  21. package/dist/decorator/preset/utils/check.d.ts +2 -2
  22. package/dist/decorator/preset/utils/check.js +17 -17
  23. package/dist/decorator/preset/utils/index.d.ts +3 -3
  24. package/dist/decorator/preset/utils/index.js +25 -25
  25. package/dist/decorator/preset/utils/load.d.ts +2 -2
  26. package/dist/decorator/preset/utils/load.js +44 -44
  27. package/dist/decorator/preset/utils/normalize.d.ts +1 -1
  28. package/dist/decorator/preset/utils/normalize.js +26 -26
  29. package/dist/decorator/property-manager/index.d.ts +2 -2
  30. package/dist/decorator/property-manager/index.js +24 -24
  31. package/dist/decorator/property-manager/module.d.ts +16 -16
  32. package/dist/decorator/property-manager/module.js +58 -58
  33. package/dist/decorator/property-manager/utils.d.ts +5 -5
  34. package/dist/decorator/property-manager/utils.js +91 -91
  35. package/dist/decorator/resolver/index.d.ts +2 -2
  36. package/dist/decorator/resolver/index.js +24 -24
  37. package/dist/decorator/resolver/module.d.ts +26 -26
  38. package/dist/decorator/resolver/module.js +71 -71
  39. package/dist/decorator/resolver/type.d.ts +9 -9
  40. package/dist/decorator/resolver/type.js +2 -2
  41. package/dist/decorator/sets/class.d.ts +6 -6
  42. package/dist/decorator/sets/class.js +8 -8
  43. package/dist/decorator/sets/index.d.ts +7 -7
  44. package/dist/decorator/sets/index.js +28 -28
  45. package/dist/decorator/sets/method.d.ts +13 -13
  46. package/dist/decorator/sets/method.js +8 -8
  47. package/dist/decorator/sets/mixed.d.ts +11 -11
  48. package/dist/decorator/sets/mixed.js +8 -8
  49. package/dist/decorator/sets/parameter.d.ts +20 -20
  50. package/dist/decorator/sets/parameter.js +8 -8
  51. package/dist/decorator/sets/request.d.ts +5 -5
  52. package/dist/decorator/sets/request.js +8 -8
  53. package/dist/decorator/sets/response.d.ts +16 -16
  54. package/dist/decorator/sets/response.js +8 -8
  55. package/dist/decorator/sets/type.d.ts +3 -3
  56. package/dist/decorator/sets/type.js +2 -2
  57. package/dist/decorator/type.d.ts +31 -31
  58. package/dist/decorator/type.js +8 -8
  59. package/dist/error/base.d.ts +2 -2
  60. package/dist/error/base.js +12 -12
  61. package/dist/error/index.d.ts +1 -1
  62. package/dist/error/index.js +23 -23
  63. package/dist/generator/abstract.d.ts +18 -18
  64. package/dist/generator/abstract.js +150 -150
  65. package/dist/generator/abstract.js.map +1 -1
  66. package/dist/generator/controller/index.d.ts +2 -2
  67. package/dist/generator/controller/index.js +24 -24
  68. package/dist/generator/controller/module.d.ts +12 -12
  69. package/dist/generator/controller/module.js +67 -67
  70. package/dist/generator/controller/type.d.ts +46 -46
  71. package/dist/generator/controller/type.js +2 -2
  72. package/dist/generator/index.d.ts +6 -6
  73. package/dist/generator/index.js +28 -28
  74. package/dist/generator/metadata/index.d.ts +3 -3
  75. package/dist/generator/metadata/index.js +25 -25
  76. package/dist/generator/metadata/module.d.ts +38 -38
  77. package/dist/generator/metadata/module.js +142 -142
  78. package/dist/generator/metadata/type.d.ts +24 -24
  79. package/dist/generator/metadata/type.js +2 -2
  80. package/dist/generator/metadata/utils.d.ts +2 -2
  81. package/dist/generator/metadata/utils.js +18 -18
  82. package/dist/generator/method/constants.d.ts +10 -10
  83. package/dist/generator/method/constants.js +20 -20
  84. package/dist/generator/method/index.d.ts +3 -3
  85. package/dist/generator/method/index.js +25 -25
  86. package/dist/generator/method/module.d.ts +18 -18
  87. package/dist/generator/method/module.d.ts.map +1 -1
  88. package/dist/generator/method/module.js +187 -188
  89. package/dist/generator/method/module.js.map +1 -1
  90. package/dist/generator/method/type.d.ts +22 -29
  91. package/dist/generator/method/type.d.ts.map +1 -1
  92. package/dist/generator/method/type.js +8 -8
  93. package/dist/generator/parameter/constants.d.ts +18 -18
  94. package/dist/generator/parameter/constants.js +29 -29
  95. package/dist/generator/parameter/error.d.ts +34 -34
  96. package/dist/generator/parameter/error.js +67 -67
  97. package/dist/generator/parameter/index.d.ts +4 -4
  98. package/dist/generator/parameter/index.js +26 -26
  99. package/dist/generator/parameter/module.d.ts +28 -28
  100. package/dist/generator/parameter/module.d.ts.map +1 -1
  101. package/dist/generator/parameter/module.js +555 -554
  102. package/dist/generator/parameter/module.js.map +1 -1
  103. package/dist/generator/parameter/type.d.ts +24 -24
  104. package/dist/generator/parameter/type.d.ts.map +1 -1
  105. package/dist/generator/parameter/type.js +8 -8
  106. package/dist/generator/type.d.ts +19 -18
  107. package/dist/generator/type.d.ts.map +1 -1
  108. package/dist/generator/type.js +8 -8
  109. package/dist/index.d.ts +9 -9
  110. package/dist/index.js +31 -31
  111. package/dist/module.d.ts +4 -4
  112. package/dist/module.js +40 -40
  113. package/dist/resolver/constants.d.ts +27 -0
  114. package/dist/resolver/constants.d.ts.map +1 -0
  115. package/dist/resolver/constants.js +37 -0
  116. package/dist/resolver/constants.js.map +1 -0
  117. package/dist/resolver/error.d.ts +7 -7
  118. package/dist/resolver/error.js +40 -40
  119. package/dist/resolver/extension/index.d.ts +3 -0
  120. package/dist/resolver/extension/index.d.ts.map +1 -0
  121. package/dist/resolver/extension/index.js +25 -0
  122. package/dist/resolver/extension/index.js.map +1 -0
  123. package/dist/resolver/extension/module.d.ts +5 -0
  124. package/dist/resolver/extension/module.d.ts.map +1 -0
  125. package/dist/resolver/extension/module.js +27 -0
  126. package/dist/resolver/extension/module.js.map +1 -0
  127. package/dist/resolver/extension/type.d.ts +8 -0
  128. package/dist/resolver/extension/type.d.ts.map +1 -0
  129. package/dist/resolver/extension/type.js +9 -0
  130. package/dist/resolver/extension/type.js.map +1 -0
  131. package/dist/resolver/index.d.ts +5 -3
  132. package/dist/resolver/index.d.ts.map +1 -1
  133. package/dist/resolver/index.js +27 -25
  134. package/dist/resolver/index.js.map +1 -1
  135. package/dist/resolver/module.d.ts +53 -50
  136. package/dist/resolver/module.d.ts.map +1 -1
  137. package/dist/resolver/module.js +1102 -1088
  138. package/dist/resolver/module.js.map +1 -1
  139. package/dist/resolver/type.d.ts +138 -123
  140. package/dist/resolver/type.d.ts.map +1 -1
  141. package/dist/resolver/type.js +129 -53
  142. package/dist/resolver/type.js.map +1 -1
  143. package/dist/type.d.ts +1 -1
  144. package/dist/type.js +8 -8
  145. package/dist/utils/array.d.ts +2 -0
  146. package/dist/utils/array.d.ts.map +1 -0
  147. package/dist/utils/array.js +22 -0
  148. package/dist/utils/array.js.map +1 -0
  149. package/dist/utils/index.d.ts +9 -8
  150. package/dist/utils/index.d.ts.map +1 -1
  151. package/dist/utils/index.js +31 -30
  152. package/dist/utils/index.js.map +1 -1
  153. package/dist/utils/initializer.d.ts +4 -4
  154. package/dist/utils/initializer.d.ts.map +1 -1
  155. package/dist/utils/initializer.js +130 -130
  156. package/dist/utils/initializer.js.map +1 -1
  157. package/dist/utils/js-doc/constants.d.ts +18 -18
  158. package/dist/utils/js-doc/constants.js +29 -29
  159. package/dist/utils/js-doc/index.d.ts +3 -3
  160. package/dist/utils/js-doc/index.js +25 -25
  161. package/dist/utils/js-doc/module.d.ts +8 -8
  162. package/dist/utils/js-doc/module.js +97 -97
  163. package/dist/utils/js-doc/utils.d.ts +2 -2
  164. package/dist/utils/js-doc/utils.js +28 -28
  165. package/dist/utils/node/index.d.ts +2 -2
  166. package/dist/utils/node/index.js +24 -24
  167. package/dist/utils/node/module.d.ts +9 -9
  168. package/dist/utils/node/module.js +51 -51
  169. package/dist/utils/node/type.d.ts +5 -5
  170. package/dist/utils/node/type.js +8 -8
  171. package/dist/utils/object.d.ts +1 -1
  172. package/dist/utils/object.js +14 -14
  173. package/dist/utils/path-normalize.d.ts +1 -1
  174. package/dist/utils/path-normalize.js +16 -16
  175. package/dist/utils/source-files.d.ts +2 -2
  176. package/dist/utils/source-files.js +31 -31
  177. package/dist/utils/tsconfig/index.d.ts +2 -2
  178. package/dist/utils/tsconfig/index.js +24 -24
  179. package/dist/utils/tsconfig/module.d.ts +3 -3
  180. package/dist/utils/tsconfig/module.js +53 -53
  181. package/dist/utils/tsconfig/type.d.ts +10 -10
  182. package/dist/utils/tsconfig/type.js +8 -8
  183. package/dist/utils/validator/constants.d.ts +12 -12
  184. package/dist/utils/validator/constants.js +22 -22
  185. package/dist/utils/validator/index.d.ts +3 -3
  186. package/dist/utils/validator/index.js +25 -25
  187. package/dist/utils/validator/module.d.ts +3 -3
  188. package/dist/utils/validator/module.js +141 -141
  189. package/dist/utils/validator/type.d.ts +5 -5
  190. package/dist/utils/validator/type.js +8 -8
  191. package/package.json +5 -6
@@ -1,1089 +1,1103 @@
1
- "use strict";
2
- /*
3
- * Copyright (c) 2021.
4
- * Author Peter Placzek (tada5hi)
5
- * For the full copyright and license information,
6
- * view the LICENSE file that was distributed with this source code.
7
- */
8
- var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
9
- if (k2 === undefined) k2 = k;
10
- var desc = Object.getOwnPropertyDescriptor(m, k);
11
- if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
12
- desc = { enumerable: true, get: function() { return m[k]; } };
13
- }
14
- Object.defineProperty(o, k2, desc);
15
- }) : (function(o, m, k, k2) {
16
- if (k2 === undefined) k2 = k;
17
- o[k2] = m[k];
18
- }));
19
- var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
20
- Object.defineProperty(o, "default", { enumerable: true, value: v });
21
- }) : function(o, v) {
22
- o["default"] = v;
23
- });
24
- var __importStar = (this && this.__importStar) || function (mod) {
25
- if (mod && mod.__esModule) return mod;
26
- var result = {};
27
- if (mod != null) for (var k in mod) if (k !== "default" && Object.prototype.hasOwnProperty.call(mod, k)) __createBinding(result, mod, k);
28
- __setModuleDefault(result, mod);
29
- return result;
30
- };
31
- Object.defineProperty(exports, "__esModule", { value: true });
32
- exports.TypeNodeResolver = void 0;
33
- const ts = __importStar(require("typescript"));
34
- const decorator_1 = require("../decorator");
35
- const utils_1 = require("../utils");
36
- const error_1 = require("./error");
37
- const localReferenceTypeCache = {};
38
- const inProgressTypes = {};
39
- class TypeNodeResolver {
40
- constructor(typeNode, current, parentNode, context, referencer) {
41
- this.attemptToResolveKindToPrimitive = (syntaxKind) => {
42
- if (syntaxKind === ts.SyntaxKind.NumberKeyword) {
43
- return 'number';
44
- }
45
- if (syntaxKind === ts.SyntaxKind.StringKeyword) {
46
- return 'string';
47
- }
48
- if (syntaxKind === ts.SyntaxKind.BooleanKeyword) {
49
- return 'boolean';
50
- }
51
- if (syntaxKind === ts.SyntaxKind.VoidKeyword) {
52
- return 'void';
53
- }
54
- return undefined;
55
- };
56
- this.typeNode = typeNode;
57
- this.current = current;
58
- this.parentNode = parentNode;
59
- this.context = context || {};
60
- this.referencer = referencer;
61
- }
62
- static clearCache() {
63
- Object.keys(localReferenceTypeCache).forEach((key) => {
64
- delete localReferenceTypeCache[key];
65
- });
66
- Object.keys(inProgressTypes).forEach((key) => {
67
- delete inProgressTypes[key];
68
- });
69
- }
70
- resolve() {
71
- const primitiveType = this.getPrimitiveType(this.typeNode, this.parentNode);
72
- if (primitiveType) {
73
- return primitiveType;
74
- }
75
- if (this.typeNode.kind === ts.SyntaxKind.NullKeyword) {
76
- return {
77
- typeName: 'enum',
78
- members: [null],
79
- };
80
- }
81
- if (this.typeNode.kind === ts.SyntaxKind.ArrayType) {
82
- return {
83
- typeName: 'array',
84
- elementType: new TypeNodeResolver(this.typeNode.elementType, this.current, this.parentNode, this.context).resolve(),
85
- };
86
- }
87
- if (ts.isUnionTypeNode(this.typeNode)) {
88
- const types = this.typeNode.types.map((type) => new TypeNodeResolver(type, this.current, this.parentNode, this.context).resolve());
89
- return {
90
- typeName: 'union',
91
- members: types,
92
- };
93
- }
94
- if (ts.isIntersectionTypeNode(this.typeNode)) {
95
- const types = this.typeNode.types.map((type) => new TypeNodeResolver(type, this.current, this.parentNode, this.context).resolve());
96
- return {
97
- typeName: 'intersection',
98
- members: types,
99
- };
100
- }
101
- if (this.typeNode.kind === ts.SyntaxKind.AnyKeyword ||
102
- this.typeNode.kind === ts.SyntaxKind.UnknownKeyword ||
103
- this.typeNode.kind === ts.SyntaxKind.UndefinedKeyword) {
104
- return {
105
- typeName: 'any',
106
- };
107
- }
108
- if (ts.isLiteralTypeNode(this.typeNode)) {
109
- return {
110
- typeName: 'enum',
111
- members: [TypeNodeResolver.getLiteralValue(this.typeNode)],
112
- };
113
- }
114
- if (ts.isTypeLiteralNode(this.typeNode)) {
115
- const properties = this.typeNode.members
116
- .filter((member) => ts.isPropertySignature(member))
117
- .reduce((res, propertySignature) => {
118
- const type = new TypeNodeResolver(propertySignature.type, this.current, propertySignature, this.context).resolve();
119
- const property = {
120
- deprecated: (0, utils_1.hasJSDocTag)(propertySignature, utils_1.JSDocTagName.DEPRECATED),
121
- example: this.getNodeExample(propertySignature),
122
- default: (0, utils_1.getJSDocTagComment)(propertySignature, utils_1.JSDocTagName.DEFAULT),
123
- description: this.getNodeDescription(propertySignature),
124
- format: TypeNodeResolver.getNodeFormat(propertySignature),
125
- name: propertySignature.name.text,
126
- required: !propertySignature.questionToken,
127
- type,
128
- validators: (0, utils_1.getDeclarationValidators)(propertySignature) || {},
129
- };
130
- return [property, ...res];
131
- }, []);
132
- const indexMember = this.typeNode.members.find((member) => ts.isIndexSignatureDeclaration(member));
133
- let additionalType;
134
- if (indexMember) {
135
- const indexSignatureDeclaration = indexMember;
136
- const indexType = new TypeNodeResolver(indexSignatureDeclaration.parameters[0].type, this.current, this.parentNode, this.context).resolve();
137
- if (indexType.typeName !== 'string') {
138
- throw new error_1.ResolverError('Only string indexes are supported.', this.typeNode);
139
- }
140
- additionalType = new TypeNodeResolver(indexSignatureDeclaration.type, this.current, this.parentNode, this.context).resolve();
141
- }
142
- return {
143
- additionalProperties: indexMember && additionalType,
144
- typeName: 'nestedObjectLiteral',
145
- properties,
146
- };
147
- }
148
- if (this.typeNode.kind === ts.SyntaxKind.ObjectKeyword || ts.isFunctionTypeNode(this.typeNode)) {
149
- return { typeName: 'object' };
150
- }
151
- if (ts.isMappedTypeNode(this.typeNode) && this.referencer) {
152
- const type = this.current.typeChecker.getTypeFromTypeNode(this.referencer);
153
- const mappedTypeNode = this.typeNode;
154
- const { typeChecker } = this.current;
155
- const getDeclaration = (prop) => prop.declarations && prop.declarations[0];
156
- const isIgnored = (prop) => {
157
- const declaration = getDeclaration(prop);
158
- return (prop.getJsDocTags().find((tag) => tag.name === 'ignore') !== undefined ||
159
- (declaration !== undefined &&
160
- !ts.isPropertyDeclaration(declaration) &&
161
- !ts.isPropertySignature(declaration) &&
162
- !ts.isParameter(declaration)));
163
- };
164
- const properties = type
165
- .getProperties()
166
- // Ignore methods, getter, setter and @ignored props
167
- .filter((property) => isIgnored(property) === false)
168
- // Transform to property
169
- .map((property) => {
170
- const propertyType = typeChecker.getTypeOfSymbolAtLocation(property, this.typeNode);
171
- const declaration = getDeclaration(property);
172
- if (declaration && ts.isPropertySignature(declaration)) {
173
- return { ...this.propertyFromSignature(declaration, mappedTypeNode.questionToken), name: property.getName() };
174
- }
175
- if (declaration && (ts.isPropertyDeclaration(declaration) || ts.isParameter(declaration))) {
176
- return { ...this.propertyFromDeclaration(declaration, mappedTypeNode.questionToken), name: property.getName() };
177
- }
178
- // Resolve default value, required and typeNode
179
- let required = false;
180
- const typeNode = this.current.typeChecker.typeToTypeNode(propertyType, undefined, ts.NodeBuilderFlags.NoTruncation);
181
- if (mappedTypeNode.questionToken && mappedTypeNode.questionToken.kind === ts.SyntaxKind.MinusToken) {
182
- required = true;
183
- }
184
- else if (mappedTypeNode.questionToken && mappedTypeNode.questionToken.kind === ts.SyntaxKind.QuestionToken) {
185
- required = false;
186
- }
187
- // Push property
188
- return {
189
- name: property.getName(),
190
- required,
191
- deprecated: false,
192
- type: new TypeNodeResolver(typeNode, this.current, this.typeNode, this.context, this.referencer).resolve(),
193
- validators: {},
194
- };
195
- });
196
- return {
197
- typeName: 'nestedObjectLiteral',
198
- properties,
199
- };
200
- }
201
- if (ts.isConditionalTypeNode(this.typeNode) && this.referencer && ts.isTypeReferenceNode(this.referencer)) {
202
- const type = this.current.typeChecker.getTypeFromTypeNode(this.referencer);
203
- if (type.aliasSymbol) {
204
- let declaration = type.aliasSymbol.declarations[0];
205
- if (declaration.name) {
206
- declaration = this.getModelTypeDeclaration(declaration.name);
207
- }
208
- const name = TypeNodeResolver.getRefTypeName(this.referencer.getText());
209
- return this.handleCachingAndCircularReferences(name, () => {
210
- if (ts.isTypeAliasDeclaration(declaration)) {
211
- // Note: I don't understand why typescript lose type for `this.referencer` (from above with isTypeReferenceNode())
212
- return this.getTypeAliasReference(declaration, this.current.typeChecker.typeToString(type), this.referencer);
213
- }
214
- if (ts.isEnumDeclaration(declaration)) {
215
- return this.getEnumerateType(declaration.name);
216
- }
217
- throw new error_1.ResolverError(`Couldn't resolve Conditional to TypeNode. If you think this should be resolvable, please file an Issue. We found an aliasSymbol and it's declaration was of kind ${declaration.kind}`, this.typeNode);
218
- });
219
- }
220
- if (type.isClassOrInterface()) {
221
- let declaration = type.symbol.declarations[0];
222
- if (declaration.name) {
223
- declaration = this.getModelTypeDeclaration(declaration.name);
224
- }
225
- const name = TypeNodeResolver.getRefTypeName(this.referencer.getText());
226
- return this.handleCachingAndCircularReferences(name, () => this.getModelReference(declaration, this.current.typeChecker.typeToString(type)));
227
- }
228
- try {
229
- return new TypeNodeResolver(this.current.typeChecker.typeToTypeNode(type, undefined, ts.NodeBuilderFlags.NoTruncation), this.current, this.typeNode, this.context, this.referencer).resolve();
230
- }
231
- catch {
232
- throw new error_1.ResolverError(`Couldn't resolve Conditional to TypeNode. If you think this should be resolvable, please file an Issue. The flags on the result of the ConditionalType was ${type.flags}`, this.typeNode);
233
- }
234
- }
235
- if (ts.isTypeOperatorNode(this.typeNode) && this.typeNode.operator === ts.SyntaxKind.KeyOfKeyword) {
236
- const type = this.current.typeChecker.getTypeFromTypeNode(this.typeNode);
237
- try {
238
- return new TypeNodeResolver(this.current.typeChecker.typeToTypeNode(type, undefined, ts.NodeBuilderFlags.NoTruncation), this.current, this.typeNode, this.context, this.referencer).resolve();
239
- }
240
- catch (err) {
241
- const indexedTypeName = this.current.typeChecker.typeToString(this.current.typeChecker.getTypeFromTypeNode(this.typeNode.type));
242
- throw new error_1.ResolverError(`Could not determine the keys on ${indexedTypeName}`, this.typeNode);
243
- }
244
- }
245
- if (ts.isTypeOperatorNode(this.typeNode) && this.typeNode.operator === ts.SyntaxKind.ReadonlyKeyword) {
246
- return new TypeNodeResolver(this.typeNode.type, this.current, this.typeNode, this.context, this.referencer).resolve();
247
- }
248
- if (ts.isIndexedAccessTypeNode(this.typeNode) &&
249
- (this.typeNode.indexType.kind === ts.SyntaxKind.NumberKeyword ||
250
- this.typeNode.indexType.kind === ts.SyntaxKind.StringKeyword)) {
251
- const numberIndexType = this.typeNode.indexType.kind === ts.SyntaxKind.NumberKeyword;
252
- const objectType = this.current.typeChecker.getTypeFromTypeNode(this.typeNode.objectType);
253
- const type = numberIndexType ? objectType.getNumberIndexType() : objectType.getStringIndexType();
254
- if (type === undefined) {
255
- throw new error_1.ResolverError(`Could not determine ${numberIndexType ? 'number' : 'string'} index on ${this.current.typeChecker.typeToString(objectType)}`, this.typeNode);
256
- }
257
- return new TypeNodeResolver(this.current.typeChecker.typeToTypeNode(type, undefined, undefined), this.current, this.typeNode, this.context, this.referencer).resolve();
258
- }
259
- if (ts.isIndexedAccessTypeNode(this.typeNode) &&
260
- ts.isLiteralTypeNode(this.typeNode.indexType) &&
261
- (ts.isStringLiteral(this.typeNode.indexType.literal) || ts.isNumericLiteral(this.typeNode.indexType.literal))) {
262
- const hasType = (node) => node !== undefined &&
263
- Object.prototype.hasOwnProperty.call(node, 'type');
264
- const symbol = this.current.typeChecker.getPropertyOfType(this.current.typeChecker.getTypeFromTypeNode(this.typeNode.objectType), this.typeNode.indexType.literal.text);
265
- if (symbol === undefined) {
266
- throw new error_1.ResolverError(`Could not determine the keys on ${this.current.typeChecker.typeToString(this.current.typeChecker.getTypeFromTypeNode(this.typeNode.objectType))}`, this.typeNode);
267
- }
268
- if (hasType(symbol.valueDeclaration) && symbol.valueDeclaration.type) {
269
- return new TypeNodeResolver(symbol.valueDeclaration.type, this.current, this.typeNode, this.context, this.referencer).resolve();
270
- }
271
- const declaration = this.current.typeChecker.getTypeOfSymbolAtLocation(symbol, this.typeNode.objectType);
272
- try {
273
- return new TypeNodeResolver(this.current.typeChecker.typeToTypeNode(declaration, undefined, undefined), this.current, this.typeNode, this.context, this.referencer).resolve();
274
- }
275
- catch {
276
- throw new error_1.ResolverError(`Could not determine the keys on ${this.current.typeChecker.typeToString(this.current.typeChecker.getTypeFromTypeNode(this.current.typeChecker.typeToTypeNode(declaration, undefined, undefined)))}`, this.typeNode);
277
- }
278
- }
279
- if (this.typeNode.kind === ts.SyntaxKind.TemplateLiteralType) {
280
- const type = this.current.typeChecker.getTypeFromTypeNode(this.referencer || this.typeNode);
281
- if (type.isUnion() && type.types.every((unionElementType) => unionElementType.isStringLiteral())) {
282
- return {
283
- typeName: 'enum',
284
- members: type.types.map((stringLiteralType) => stringLiteralType.value),
285
- };
286
- }
287
- throw new error_1.ResolverError(`Could not the type of ${this.current.typeChecker.typeToString(this.current.typeChecker.getTypeFromTypeNode(this.typeNode), this.typeNode)}`, this.typeNode);
288
- }
289
- if (ts.isParenthesizedTypeNode(this.typeNode)) {
290
- return new TypeNodeResolver(this.typeNode.type, this.current, this.typeNode, this.context, this.referencer).resolve();
291
- }
292
- if (this.typeNode.kind !== ts.SyntaxKind.TypeReference) {
293
- throw new error_1.ResolverError(`Unknown type: ${ts.SyntaxKind[this.typeNode.kind]}`, this.typeNode);
294
- }
295
- const typeReference = this.typeNode;
296
- if (typeReference.typeName.kind === ts.SyntaxKind.Identifier) {
297
- // Special Utility Type
298
- if (typeReference.typeName.text === 'Record') {
299
- return {
300
- additionalProperties: new TypeNodeResolver(typeReference.typeArguments[1], this.current, this.parentNode, this.context).resolve(),
301
- typeName: 'nestedObjectLiteral',
302
- properties: [],
303
- };
304
- }
305
- const specialReference = TypeNodeResolver.resolveSpecialReference(typeReference.typeName);
306
- if (typeof specialReference !== 'undefined') {
307
- return specialReference;
308
- }
309
- if (typeReference.typeName.text === 'Date') {
310
- return this.getDateType(this.parentNode);
311
- }
312
- if (typeReference.typeName.text === 'Buffer' ||
313
- typeReference.typeName.text === 'Readable') {
314
- return { typeName: 'buffer' };
315
- }
316
- if (typeReference.typeName.text === 'Array' &&
317
- typeReference.typeArguments &&
318
- typeReference.typeArguments.length >= 1) {
319
- return {
320
- typeName: 'array',
321
- elementType: new TypeNodeResolver(typeReference.typeArguments[0], this.current, this.parentNode, this.context).resolve(),
322
- };
323
- }
324
- if (typeReference.typeName.text === 'Promise' &&
325
- typeReference.typeArguments &&
326
- typeReference.typeArguments.length === 1) {
327
- return new TypeNodeResolver(typeReference.typeArguments[0], this.current, this.parentNode, this.context).resolve();
328
- }
329
- if (typeReference.typeName.text === 'String') {
330
- return { typeName: 'string' };
331
- }
332
- if (this.context[typeReference.typeName.text]) {
333
- return new TypeNodeResolver(this.context[typeReference.typeName.text], this.current, this.parentNode, this.context).resolve();
334
- }
335
- }
336
- const referenceType = this.getReferenceType(typeReference);
337
- this.current.addReferenceType(referenceType);
338
- return referenceType;
339
- }
340
- // ------------------------------------------------------------------------
341
- // Utility Type(s)
342
- // ------------------------------------------------------------------------
343
- static isSupportedUtilityType(typeName) {
344
- if (typeof typeName === 'undefined') {
345
- return false;
346
- }
347
- return ['NonNullable', 'Pick', 'Omit', 'Partial', 'Readonly', 'Record', 'Required'].indexOf(typeof typeName !== 'string' ? typeName.text : typeName) !== -1;
348
- }
349
- static getUtilityTypeOptions(typeArguments) {
350
- const utilityOptions = {
351
- keys: [],
352
- };
353
- if (typeArguments.length >= 2) {
354
- if (ts.isUnionTypeNode(typeArguments[1])) {
355
- const args = typeArguments[1].types;
356
- for (let i = 0; i < args.length; i++) {
357
- if (ts.isLiteralTypeNode(args[i])) {
358
- utilityOptions.keys.push(TypeNodeResolver.getLiteralValue(args[i]));
359
- }
360
- }
361
- }
362
- if (ts.isLiteralTypeNode(typeArguments[1])) {
363
- utilityOptions.keys.push(TypeNodeResolver.getLiteralValue(typeArguments[1]));
364
- }
365
- }
366
- return utilityOptions;
367
- }
368
- filterUtilityProperties(properties, utilityType, utilityOptions) {
369
- if (typeof utilityType === 'undefined' || typeof utilityOptions === 'undefined') {
370
- return properties;
371
- }
372
- return properties
373
- .filter((property) => {
374
- const name = typeof property.name !== 'string' ? property.name.text : property.name;
375
- switch (utilityType) {
376
- case 'Pick':
377
- return utilityOptions.keys.indexOf(name) !== -1;
378
- case 'Omit':
379
- return utilityOptions.keys.indexOf(name) === -1;
380
- }
381
- return true;
382
- })
383
- .map((property) => {
384
- if ((0, utils_1.hasOwnProperty)(property, 'required')) {
385
- switch (utilityType) {
386
- case 'Partial':
387
- property.required = false;
388
- break;
389
- case 'Required':
390
- case 'NonNullable':
391
- property.required = true;
392
- break;
393
- }
394
- }
395
- return property;
396
- });
397
- }
398
- static resolveSpecialReference(node) {
399
- switch (node.text) {
400
- case 'Buffer':
401
- case 'DownloadBinaryData':
402
- case 'DownloadResource':
403
- return { typeName: 'buffer' };
404
- default:
405
- return undefined;
406
- }
407
- }
408
- static getLiteralValue(typeNode) {
409
- let value;
410
- switch (typeNode.literal.kind) {
411
- case ts.SyntaxKind.TrueKeyword:
412
- value = true;
413
- break;
414
- case ts.SyntaxKind.FalseKeyword:
415
- value = false;
416
- break;
417
- case ts.SyntaxKind.StringLiteral:
418
- value = typeNode.literal.text;
419
- break;
420
- case ts.SyntaxKind.NumericLiteral:
421
- value = parseFloat(typeNode.literal.text);
422
- break;
423
- case ts.SyntaxKind.NullKeyword:
424
- value = null;
425
- break;
426
- default:
427
- if (Object.prototype.hasOwnProperty.call(typeNode.literal, 'text')) {
428
- value = typeNode.literal.text;
429
- }
430
- else {
431
- throw new error_1.ResolverError(`Couldn't resolve literal node: ${typeNode.literal.getText()}`);
432
- }
433
- }
434
- return value;
435
- }
436
- getPrimitiveType(typeNode, parentNode) {
437
- if (!typeNode) {
438
- return {
439
- typeName: 'void',
440
- };
441
- }
442
- const resolvedType = this.attemptToResolveKindToPrimitive(typeNode.kind);
443
- if (typeof resolvedType === 'undefined') {
444
- return undefined;
445
- }
446
- if (resolvedType === 'number') {
447
- if (!parentNode) {
448
- return { typeName: 'double' };
449
- }
450
- const lookupTags = [
451
- 'isInt',
452
- 'isLong',
453
- 'isFloat',
454
- 'isDouble',
455
- ];
456
- const tags = (0, utils_1.getJSDocTagNames)(parentNode)
457
- .filter((name) => lookupTags.some((m) => m.toLowerCase() === name.toLowerCase()))
458
- .map((name) => name.toLowerCase());
459
- const decoratorIds = [
460
- decorator_1.DecoratorID.IS_INT,
461
- decorator_1.DecoratorID.IS_LONG,
462
- decorator_1.DecoratorID.IS_FLOAT,
463
- decorator_1.DecoratorID.IS_DOUBLE,
464
- ];
465
- let decoratorID;
466
- for (let i = 0; i < decoratorIds.length; i++) {
467
- const decorator = this.current.decoratorResolver.match(decoratorIds[i], parentNode);
468
- if (decorator) {
469
- decoratorID = decoratorIds[i];
470
- break;
471
- }
472
- }
473
- if (!decoratorID && tags.length === 0) {
474
- return { typeName: 'double' };
475
- }
476
- switch (decoratorID || tags[0]) {
477
- case decorator_1.DecoratorID.IS_INT:
478
- case 'isint':
479
- return { typeName: 'integer' };
480
- case decorator_1.DecoratorID.IS_LONG:
481
- case 'islong':
482
- return { typeName: 'long' };
483
- case decorator_1.DecoratorID.IS_FLOAT:
484
- case 'isfloat':
485
- return { typeName: 'float' };
486
- case decorator_1.DecoratorID.IS_DOUBLE:
487
- case 'isdouble':
488
- return { typeName: 'double' };
489
- default:
490
- return { typeName: 'double' };
491
- }
492
- }
493
- else if (resolvedType === 'string') {
494
- return {
495
- typeName: 'string',
496
- };
497
- }
498
- else if (resolvedType === 'boolean') {
499
- return {
500
- typeName: 'boolean',
501
- };
502
- }
503
- else if (resolvedType === 'void') {
504
- return {
505
- typeName: 'void',
506
- };
507
- }
508
- else {
509
- // todo: should not occur
510
- return {
511
- typeName: resolvedType,
512
- };
513
- }
514
- }
515
- getDateType(parentNode) {
516
- if (!parentNode) {
517
- return { typeName: 'datetime' };
518
- }
519
- const tags = (0, utils_1.getJSDocTagNames)(parentNode).filter((name) => ['isDate', 'isDateTime'].some((m) => m === name));
520
- if (tags.length === 0) {
521
- return { typeName: 'datetime' };
522
- }
523
- switch (tags[0]) {
524
- case 'isDate':
525
- return { typeName: 'date' };
526
- case 'isDateTime':
527
- return { typeName: 'datetime' };
528
- default:
529
- return { typeName: 'datetime' };
530
- }
531
- }
532
- static getDesignatedModels(nodes, typeName) {
533
- return nodes;
534
- }
535
- getEnumerateType(typeName) {
536
- const enumName = typeName.text;
537
- let enumNodes = this.current.nodes.filter((node) => node.kind === ts.SyntaxKind.EnumDeclaration && node.name.text === enumName);
538
- if (!enumNodes.length) {
539
- return undefined;
540
- }
541
- enumNodes = TypeNodeResolver.getDesignatedModels(enumNodes, enumName);
542
- if (enumNodes.length > 1) {
543
- throw new error_1.ResolverError(`Multiple matching enum found for enum ${enumName}; please make enum names unique.`);
544
- }
545
- const enumDeclaration = enumNodes[0];
546
- const isNotUndefined = (item) => item !== undefined;
547
- const enums = enumDeclaration.members.map(this.current.typeChecker.getConstantValue.bind(this.current.typeChecker)).filter(isNotUndefined);
548
- const enumNames = enumDeclaration.members.map((e) => e.name.getText()).filter(isNotUndefined);
549
- return {
550
- typeName: 'refEnum',
551
- description: this.getNodeDescription(enumDeclaration),
552
- members: enums,
553
- memberNames: enumNames,
554
- refName: enumName,
555
- deprecated: (0, utils_1.hasJSDocTag)(enumDeclaration, utils_1.JSDocTagName.DEPRECATED),
556
- };
557
- }
558
- getReferenceType(node) {
559
- let type;
560
- if (ts.isTypeReferenceNode(node)) {
561
- type = node.typeName;
562
- }
563
- else if (ts.isExpressionWithTypeArguments(node)) {
564
- type = node.expression;
565
- }
566
- else {
567
- throw new error_1.ResolverError('Can\'t resolve Reference type.');
568
- }
569
- // Can't invoke getText on Synthetic Nodes
570
- let resolvableName = node.pos !== -1 ? node.getText() : type.text;
571
- if (node.pos === -1 && 'typeArguments' in node && Array.isArray(node.typeArguments)) {
572
- // Add typeArguments for Synthetic nodes (e.g. Record<> in TestClassModel.indexedResponse)
573
- const argumentsString = node.typeArguments
574
- .map((arg) => {
575
- if (ts.isLiteralTypeNode(arg)) {
576
- return `'${String(TypeNodeResolver.getLiteralValue(arg))}'`;
577
- }
578
- const resolvedType = this.attemptToResolveKindToPrimitive(arg.kind);
579
- if (typeof resolvedType === 'undefined') {
580
- return 'any';
581
- }
582
- return resolvedType;
583
- });
584
- resolvableName += `<${argumentsString.join(', ')}>`;
585
- }
586
- const name = this.contextualizedName(resolvableName);
587
- // Handle Utility Types
588
- const identifierName = type.text;
589
- const utilityTypeSupported = TypeNodeResolver.isSupportedUtilityType(identifierName);
590
- const utilityType = utilityTypeSupported ? identifierName : undefined;
591
- let utilityOptions = {
592
- keys: [],
593
- };
594
- if (utilityTypeSupported) {
595
- const { typeArguments } = type.parent;
596
- if (ts.isTypeReferenceNode(typeArguments[0])) {
597
- type = typeArguments[0].typeName;
598
- }
599
- else if (ts.isExpressionWithTypeArguments(typeArguments[0])) {
600
- type = typeArguments[0].expression;
601
- }
602
- else {
603
- throw new error_1.ResolverError('Can\'t resolve Reference type.');
604
- }
605
- utilityOptions = TypeNodeResolver.getUtilityTypeOptions(typeArguments);
606
- }
607
- else {
608
- this.typeArgumentsToContext(node, type, this.context);
609
- }
610
- try {
611
- const existingType = localReferenceTypeCache[name];
612
- if (existingType) {
613
- return existingType;
614
- }
615
- const refEnumType = this.getEnumerateType(type);
616
- if (refEnumType) {
617
- localReferenceTypeCache[name] = refEnumType;
618
- return refEnumType;
619
- }
620
- if (inProgressTypes[name]) {
621
- return this.createCircularDependencyResolver(name);
622
- }
623
- inProgressTypes[name] = true;
624
- const declaration = this.getModelTypeDeclaration(type);
625
- let referenceType;
626
- if (ts.isTypeAliasDeclaration(declaration)) {
627
- referenceType = this.getTypeAliasReference(declaration, name, node);
628
- }
629
- else if (ts.isEnumMember(declaration)) {
630
- referenceType = {
631
- typeName: 'refEnum',
632
- refName: TypeNodeResolver.getRefTypeName(name, utilityType),
633
- members: [this.current.typeChecker.getConstantValue(declaration)],
634
- memberNames: [declaration.name.getText()],
635
- deprecated: (0, utils_1.hasJSDocTag)(declaration, utils_1.JSDocTagName.DEPRECATED),
636
- };
637
- }
638
- else {
639
- // todo: dont cast handle property-signature
640
- referenceType = this.getModelReference(declaration, name, utilityType, utilityOptions);
641
- }
642
- localReferenceTypeCache[name] = referenceType;
643
- return referenceType;
644
- }
645
- catch (err) {
646
- // eslint-disable-next-line no-console
647
- console.error(`There was a problem resolving type of '${name}'.`);
648
- throw err;
649
- }
650
- }
651
- getTypeAliasReference(declaration, name, referencer) {
652
- const refName = TypeNodeResolver.getRefTypeName(name);
653
- let type;
654
- if (declaration.type.kind === ts.SyntaxKind.TypeReference) {
655
- const referenceType = this.getReferenceType(declaration.type);
656
- if (referenceType.refName === refName) {
657
- return referenceType;
658
- }
659
- }
660
- if (typeof type === 'undefined') {
661
- type = new TypeNodeResolver(declaration.type, this.current, declaration, this.context, this.referencer || referencer).resolve();
662
- }
663
- const example = this.getNodeExample(declaration);
664
- return {
665
- typeName: 'refAlias',
666
- default: (0, utils_1.getJSDocTagComment)(declaration, utils_1.JSDocTagName.DEFAULT),
667
- description: this.getNodeDescription(declaration),
668
- refName,
669
- format: TypeNodeResolver.getNodeFormat(declaration),
670
- type,
671
- validators: (0, utils_1.getDeclarationValidators)(declaration) || {},
672
- deprecated: (0, utils_1.hasJSDocTag)(declaration, utils_1.JSDocTagName.DEPRECATED),
673
- ...(example && { example }),
674
- };
675
- }
676
- getModelReference(modelType, name, utilityType, utilityOptions) {
677
- const example = this.getNodeExample(modelType);
678
- const description = this.getNodeDescription(modelType);
679
- const deprecated = (0, utils_1.hasJSDocTag)(modelType, utils_1.JSDocTagName.DEPRECATED) ||
680
- !!this.current.decoratorResolver.match(decorator_1.DecoratorID.DEPRECATED, modelType);
681
- // Handle toJSON methods
682
- if (!modelType.name) {
683
- throw new error_1.ResolverError('Can\'t get Symbol from anonymous class', modelType);
684
- }
685
- const type = this.current.typeChecker.getTypeAtLocation(modelType.name);
686
- const toJSON = this.current.typeChecker.getPropertyOfType(type, 'toJSON');
687
- if (toJSON &&
688
- toJSON.valueDeclaration &&
689
- (ts.isMethodDeclaration(toJSON.valueDeclaration) ||
690
- ts.isMethodSignature(toJSON.valueDeclaration))) {
691
- let nodeType = toJSON.valueDeclaration.type;
692
- if (!nodeType) {
693
- const signature = this.current.typeChecker.getSignatureFromDeclaration(toJSON.valueDeclaration);
694
- const implicitType = this.current.typeChecker.getReturnTypeOfSignature(signature);
695
- nodeType = this.current.typeChecker.typeToTypeNode(implicitType, undefined, ts.NodeBuilderFlags.NoTruncation);
696
- }
697
- return {
698
- refName: `${TypeNodeResolver.getRefTypeName(name, utilityType)}Alias`,
699
- typeName: 'refAlias',
700
- description,
701
- type: new TypeNodeResolver(nodeType, this.current).resolve(),
702
- deprecated,
703
- validators: {},
704
- ...(example && { example }),
705
- };
706
- }
707
- const properties = this.getModelProperties(modelType, undefined, utilityType, utilityOptions);
708
- const additionalProperties = this.getModelAdditionalProperties(modelType);
709
- const inheritedProperties = this.getModelInheritedProperties(modelType) || [];
710
- const referenceType = {
711
- additionalProperties,
712
- typeName: 'refObject',
713
- description,
714
- properties: this.filterUtilityProperties(inheritedProperties, utilityType, utilityOptions),
715
- refName: TypeNodeResolver.getRefTypeName(name, utilityType),
716
- deprecated,
717
- ...(example && { example }),
718
- };
719
- referenceType.properties = referenceType.properties.concat(properties);
720
- return referenceType;
721
- }
722
- static getRefTypeName(name, utilityType) {
723
- return encodeURIComponent(name
724
- .replace(/<|>/g, '_')
725
- .replace(/\s+/g, '')
726
- .replace(/,/g, '.')
727
- .replace(/'([^']*)'/g, '$1')
728
- .replace(/"([^"]*)"/g, '$1')
729
- .replace(/&/g, typeof utilityType !== 'undefined' ? '--' : '-and-')
730
- .replace(/\|/g, typeof utilityType !== 'undefined' ? '--' : '-or-')
731
- .replace(/\[\]/g, '-array')
732
- .replace(/{|}/g, '_') // SuccessResponse_{indexesCreated-number}_ -> SuccessResponse__indexesCreated-number__
733
- .replace(/([a-z]+):([a-z]+)/gi, '$1-$2') // SuccessResponse_indexesCreated:number_ -> SuccessResponse_indexesCreated-number_
734
- .replace(/;/g, '--')
735
- .replace(/([a-z]+)\[([a-z]+)\]/gi, '$1-at-$2') // Partial_SerializedDatasourceWithVersion[format]_ -> Partial_SerializedDatasourceWithVersion~format~_,
736
- .replace(/_/g, '')
737
- .replace(/-/g, ''));
738
- }
739
- contextualizedName(name) {
740
- return Object.entries(this.context).reduce((acc, [key, entry]) => acc
741
- .replace(new RegExp(`<\\s*([^>]*\\s)*\\s*(${key})(\\s[^>]*)*\\s*>`, 'g'), `<$1${entry.getText()}$3>`)
742
- .replace(new RegExp(`<\\s*([^,]*\\s)*\\s*(${key})(\\s[^,]*)*\\s*,`, 'g'), `<$1${entry.getText()}$3,`)
743
- .replace(new RegExp(`,\\s*([^>]*\\s)*\\s*(${key})(\\s[^>]*)*\\s*>`, 'g'), `,$1${entry.getText()}$3>`)
744
- .replace(new RegExp(`<\\s*([^<]*\\s)*\\s*(${key})(\\s[^<]*)*\\s*<`, 'g'), `<$1${entry.getText()}$3<`), name);
745
- }
746
- handleCachingAndCircularReferences(name, declarationResolver) {
747
- try {
748
- const existingType = localReferenceTypeCache[name];
749
- if (existingType) {
750
- return existingType;
751
- }
752
- if (inProgressTypes[name]) {
753
- return this.createCircularDependencyResolver(name);
754
- }
755
- inProgressTypes[name] = true;
756
- const reference = declarationResolver();
757
- localReferenceTypeCache[name] = reference;
758
- this.current.addReferenceType(reference);
759
- return reference;
760
- }
761
- catch (err) {
762
- // eslint-disable-next-line no-console
763
- console.error(`There was a problem resolving type of '${name}'.`);
764
- throw err;
765
- }
766
- }
767
- createCircularDependencyResolver(refName) {
768
- const referenceType = {
769
- typeName: 'refObject',
770
- refName,
771
- };
772
- this.current.registerDependencyResolver((referenceTypes) => {
773
- const realReferenceType = referenceTypes[refName];
774
- if (!realReferenceType) {
775
- return;
776
- }
777
- referenceType.description = realReferenceType.description;
778
- if (realReferenceType.typeName === 'refObject' && referenceType.typeName === 'refObject') {
779
- referenceType.properties = realReferenceType.properties;
780
- }
781
- referenceType.typeName = realReferenceType.typeName;
782
- referenceType.refName = realReferenceType.refName;
783
- });
784
- return referenceType;
785
- }
786
- static nodeIsUsable(node) {
787
- switch (node.kind) {
788
- case ts.SyntaxKind.InterfaceDeclaration:
789
- case ts.SyntaxKind.ClassDeclaration:
790
- case ts.SyntaxKind.TypeAliasDeclaration:
791
- case ts.SyntaxKind.EnumDeclaration:
792
- case ts.SyntaxKind.EnumMember:
793
- return true;
794
- default:
795
- return false;
796
- }
797
- }
798
- getModelTypeDeclaration(type) {
799
- let typeName = type.kind === ts.SyntaxKind.Identifier ? type.text : type.right.text;
800
- const symbol = this.getSymbolAtLocation(type);
801
- const declarations = symbol.getDeclarations();
802
- if (declarations.length === 0) {
803
- throw new error_1.ResolverError(`No models found for referenced type ${typeName}.`);
804
- }
805
- if (symbol.escapedName !== typeName && symbol.escapedName !== 'default') {
806
- typeName = symbol.escapedName;
807
- }
808
- let modelTypes = declarations.filter((node) => {
809
- if (!TypeNodeResolver.nodeIsUsable(node) || !this.current.isExportedNode(node)) {
810
- return false;
811
- }
812
- const modelTypeDeclaration = node;
813
- return modelTypeDeclaration.name?.text === typeName;
814
- });
815
- if (!modelTypes.length) {
816
- throw new error_1.ResolverError(`No matching model found for referenced type ${typeName}. If ${typeName} comes from a dependency, please create an interface in your own code that has the same structure. The compiler can not utilize interfaces from external dependencies.`);
817
- }
818
- if (modelTypes.length > 1) {
819
- // remove types that are from typescript e.g. 'Account'
820
- modelTypes = modelTypes.filter((modelType) => modelType.getSourceFile()
821
- .fileName.replace(/\\/g, '/').toLowerCase().indexOf('node_modules/typescript') <= -1);
822
- modelTypes = TypeNodeResolver.getDesignatedModels(modelTypes, typeName);
823
- }
824
- if (modelTypes.length > 1) {
825
- const conflicts = modelTypes.map((modelType) => modelType.getSourceFile().fileName).join('"; "');
826
- throw new error_1.ResolverError(`Multiple matching models found for referenced type ${typeName}; please make model names unique. Conflicts found: "${conflicts}".`);
827
- }
828
- return modelTypes[0];
829
- }
830
- hasFlag(type, flag) {
831
- return (type.flags & flag) === flag;
832
- }
833
- getSymbolAtLocation(type) {
834
- const symbol = this.current.typeChecker.getSymbolAtLocation(type) || type.symbol;
835
- // resolve alias if it is an alias, otherwise take symbol directly
836
- return (symbol &&
837
- this.hasFlag(symbol, ts.SymbolFlags.Alias) &&
838
- this.current.typeChecker.getAliasedSymbol(symbol)) || symbol;
839
- }
840
- getModelProperties(node, overrideToken, utilityType, utilityOptions) {
841
- const isIgnored = (e) => (0, utils_1.hasJSDocTag)(e, utils_1.JSDocTagName.IGNORE);
842
- // Interface model
843
- if (ts.isInterfaceDeclaration(node)) {
844
- return node.members.filter((member) => !isIgnored(member) &&
845
- ts.isPropertySignature(member)).map((member) => this.propertyFromSignature(member, overrideToken));
846
- }
847
- // Class model
848
- let properties = node.members
849
- .filter((member) => !isIgnored(member) &&
850
- member.kind === ts.SyntaxKind.PropertyDeclaration &&
851
- !this.hasStaticModifier(member) &&
852
- this.hasPublicModifier(member));
853
- const classConstructor = node.members.find((member) => ts.isConstructorDeclaration(member));
854
- if (classConstructor && classConstructor.parameters) {
855
- const constructorProperties = classConstructor.parameters.filter((parameter) => this.isAccessibleParameter(parameter));
856
- properties.push(...constructorProperties);
857
- }
858
- properties = this.filterUtilityProperties(properties, utilityType, utilityOptions);
859
- return properties.map((property) => this.propertyFromDeclaration(property, overrideToken, utilityType));
860
- }
861
- propertyFromSignature(propertySignature, overrideToken) {
862
- const identifier = propertySignature.name;
863
- if (!propertySignature.type) {
864
- throw new error_1.ResolverError('No valid type found for property declaration.');
865
- }
866
- let required = !propertySignature.questionToken;
867
- if (overrideToken && overrideToken.kind === ts.SyntaxKind.MinusToken) {
868
- required = true;
869
- }
870
- else if (overrideToken && overrideToken.kind === ts.SyntaxKind.QuestionToken) {
871
- required = false;
872
- }
873
- const property = {
874
- deprecated: (0, utils_1.hasJSDocTag)(propertySignature, utils_1.JSDocTagName.DEPRECATED),
875
- default: (0, utils_1.getJSDocTagComment)(propertySignature, utils_1.JSDocTagName.DEFAULT),
876
- description: this.getNodeDescription(propertySignature),
877
- example: this.getNodeExample(propertySignature),
878
- format: TypeNodeResolver.getNodeFormat(propertySignature),
879
- name: identifier.text,
880
- required,
881
- type: new TypeNodeResolver(propertySignature.type, this.current, propertySignature.type.parent, this.context, propertySignature.type).resolve(),
882
- validators: (0, utils_1.getDeclarationValidators)(propertySignature) || {},
883
- };
884
- return property;
885
- }
886
- propertyFromDeclaration(propertyDeclaration, overrideToken, utilityType) {
887
- const identifier = propertyDeclaration.name;
888
- let typeNode = propertyDeclaration.type;
889
- if (!typeNode) {
890
- const tsType = this.current.typeChecker.getTypeAtLocation(propertyDeclaration);
891
- typeNode = this.current.typeChecker.typeToTypeNode(tsType, undefined, ts.NodeBuilderFlags.NoTruncation);
892
- }
893
- if (!typeNode) {
894
- throw new error_1.ResolverError('No valid type found for property declaration.');
895
- }
896
- const type = new TypeNodeResolver(typeNode, this.current, propertyDeclaration, this.context, typeNode).resolve();
897
- let required = !propertyDeclaration.questionToken && !propertyDeclaration.initializer;
898
- if (overrideToken && overrideToken.kind === ts.SyntaxKind.MinusToken) {
899
- required = true;
900
- }
901
- else if (overrideToken && overrideToken.kind === ts.SyntaxKind.QuestionToken) {
902
- required = false;
903
- }
904
- if (typeof utilityType !== 'undefined') {
905
- if (utilityType === 'Partial') {
906
- required = false;
907
- }
908
- if (utilityType === 'Required') {
909
- required = true;
910
- }
911
- }
912
- const property = {
913
- deprecated: (0, utils_1.hasJSDocTag)(propertyDeclaration, utils_1.JSDocTagName.DEPRECATED),
914
- default: (0, utils_1.getInitializerValue)(propertyDeclaration.initializer, this.current.typeChecker),
915
- description: this.getNodeDescription(propertyDeclaration),
916
- example: this.getNodeExample(propertyDeclaration),
917
- format: TypeNodeResolver.getNodeFormat(propertyDeclaration),
918
- name: identifier.text,
919
- required,
920
- type,
921
- validators: (0, utils_1.getDeclarationValidators)(propertyDeclaration) || {},
922
- };
923
- return property;
924
- }
925
- getModelAdditionalProperties(node) {
926
- if (node.kind === ts.SyntaxKind.InterfaceDeclaration) {
927
- const indexMember = node.members.find((member) => member.kind === ts.SyntaxKind.IndexSignature);
928
- if (!indexMember) {
929
- return undefined;
930
- }
931
- const indexSignatureDeclaration = indexMember;
932
- const indexType = new TypeNodeResolver(indexSignatureDeclaration.parameters[0].type, this.current, this.parentNode, this.context).resolve();
933
- if (indexType.typeName !== 'string') {
934
- throw new error_1.ResolverError('Only string indexers are supported.', this.typeNode);
935
- }
936
- return new TypeNodeResolver(indexSignatureDeclaration.type, this.current, this.parentNode, this.context).resolve();
937
- }
938
- return undefined;
939
- }
940
- typeArgumentsToContext(type, targetEntity, context) {
941
- // this.context = {};
942
- const declaration = this.getModelTypeDeclaration(targetEntity);
943
- if (typeof declaration === 'undefined' || !('typeParameters' in declaration)) {
944
- return context;
945
- }
946
- const { typeParameters } = declaration;
947
- if (typeParameters) {
948
- for (let index = 0; index < typeParameters.length; index++) {
949
- const typeParameter = typeParameters[index];
950
- const typeArg = type.typeArguments && type.typeArguments[index];
951
- let resolvedType;
952
- // Argument may be a forward reference from context
953
- if (typeArg && ts.isTypeReferenceNode(typeArg) && ts.isIdentifier(typeArg.typeName) && context[typeArg.typeName.text]) {
954
- resolvedType = context[typeArg.typeName.text];
955
- }
956
- else if (typeArg) {
957
- resolvedType = typeArg;
958
- }
959
- else if (typeParameter.default) {
960
- resolvedType = typeParameter.default;
961
- }
962
- else {
963
- throw new error_1.ResolverError(`Could not find a value for type parameter ${typeParameter.name.text}`, type);
964
- }
965
- this.context = {
966
- ...this.context,
967
- [typeParameter.name.text]: resolvedType,
968
- };
969
- }
970
- }
971
- return context;
972
- }
973
- getModelInheritedProperties(modelTypeDeclaration) {
974
- let properties = [];
975
- const { heritageClauses } = modelTypeDeclaration;
976
- if (!heritageClauses) {
977
- return properties;
978
- }
979
- heritageClauses.forEach((clause) => {
980
- if (!clause.types) {
981
- return;
982
- }
983
- clause.types.forEach((t) => {
984
- const baseEntityName = t.expression;
985
- // create subContext
986
- const resetCtx = this.typeArgumentsToContext(t, baseEntityName, this.context);
987
- const referenceType = this.getReferenceType(t);
988
- if (referenceType) {
989
- if (referenceType.typeName === 'refEnum') {
990
- // since it doesn't have properties to iterate over, then we don't do anything with it
991
- }
992
- else if (referenceType.typeName === 'refAlias') {
993
- let type = referenceType;
994
- while (type.typeName === 'refAlias') {
995
- type = type.type;
996
- }
997
- if (type.typeName === 'refObject') {
998
- properties = [...properties, ...type.properties];
999
- }
1000
- else if (type.typeName === 'nestedObjectLiteral') {
1001
- properties = [...properties, ...type.properties];
1002
- }
1003
- }
1004
- else if (referenceType.typeName === 'refObject') {
1005
- referenceType.properties.forEach((property) => properties.push(property));
1006
- }
1007
- else {
1008
- // todo: should never assert
1009
- }
1010
- }
1011
- // reset subContext
1012
- this.context = resetCtx;
1013
- });
1014
- });
1015
- return properties;
1016
- }
1017
- hasPublicModifier(node) {
1018
- if (!ts.canHaveModifiers(node)) {
1019
- return true;
1020
- }
1021
- const modifiers = ts.getModifiers(node);
1022
- if (!modifiers) {
1023
- return true;
1024
- }
1025
- return modifiers.every((modifier) => modifier.kind !== ts.SyntaxKind.ProtectedKeyword && modifier.kind !== ts.SyntaxKind.PrivateKeyword);
1026
- }
1027
- hasStaticModifier(node) {
1028
- if (!ts.canHaveModifiers(node)) {
1029
- return false;
1030
- }
1031
- const modifiers = ts.getModifiers(node);
1032
- return modifiers && modifiers.some((modifier) => modifier.kind === ts.SyntaxKind.StaticKeyword);
1033
- }
1034
- isAccessibleParameter(node) {
1035
- // No modifiers
1036
- if (!ts.canHaveModifiers(node)) {
1037
- return false;
1038
- }
1039
- const modifiers = ts.getModifiers(node);
1040
- if (!modifiers) {
1041
- return false;
1042
- }
1043
- // public || public readonly
1044
- if (modifiers.some((modifier) => modifier.kind === ts.SyntaxKind.PublicKeyword)) {
1045
- return true;
1046
- }
1047
- // readonly, not private readonly, not public readonly
1048
- const isReadonly = modifiers.some((modifier) => modifier.kind === ts.SyntaxKind.ReadonlyKeyword);
1049
- const isProtectedOrPrivate = modifiers.some((modifier) => modifier.kind === ts.SyntaxKind.ProtectedKeyword ||
1050
- modifier.kind === ts.SyntaxKind.PrivateKeyword);
1051
- return isReadonly && !isProtectedOrPrivate;
1052
- }
1053
- getNodeDescription(node) {
1054
- const symbol = this.current.typeChecker.getSymbolAtLocation(node.name);
1055
- if (!symbol) {
1056
- return undefined;
1057
- }
1058
- /**
1059
- * TODO: Workaround for what seems like a bug in the compiler
1060
- * Warrants more investigation and possibly a PR against typescript
1061
- */
1062
- if (node.kind === ts.SyntaxKind.Parameter) {
1063
- // TypeScript won't parse jsdoc if the flag is 4, i.e. 'Property'
1064
- symbol.flags = 0;
1065
- }
1066
- const comments = symbol.getDocumentationComment(this.current.typeChecker);
1067
- if (comments.length) {
1068
- return ts.displayPartsToString(comments);
1069
- }
1070
- return undefined;
1071
- }
1072
- static getNodeFormat(node) {
1073
- return (0, utils_1.getJSDocTagComment)(node, utils_1.JSDocTagName.FORMAT);
1074
- }
1075
- getNodeExample(node) {
1076
- const example = (0, utils_1.getJSDocTagComment)(node, utils_1.JSDocTagName.EXAMPLE);
1077
- if (example) {
1078
- try {
1079
- return JSON.parse(example);
1080
- }
1081
- catch {
1082
- // do nothing
1083
- }
1084
- }
1085
- return undefined;
1086
- }
1087
- }
1088
- exports.TypeNodeResolver = TypeNodeResolver;
1
+ "use strict";
2
+ /*
3
+ * Copyright (c) 2021.
4
+ * Author Peter Placzek (tada5hi)
5
+ * For the full copyright and license information,
6
+ * view the LICENSE file that was distributed with this source code.
7
+ */
8
+ var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
9
+ if (k2 === undefined) k2 = k;
10
+ var desc = Object.getOwnPropertyDescriptor(m, k);
11
+ if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
12
+ desc = { enumerable: true, get: function() { return m[k]; } };
13
+ }
14
+ Object.defineProperty(o, k2, desc);
15
+ }) : (function(o, m, k, k2) {
16
+ if (k2 === undefined) k2 = k;
17
+ o[k2] = m[k];
18
+ }));
19
+ var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
20
+ Object.defineProperty(o, "default", { enumerable: true, value: v });
21
+ }) : function(o, v) {
22
+ o["default"] = v;
23
+ });
24
+ var __importStar = (this && this.__importStar) || function (mod) {
25
+ if (mod && mod.__esModule) return mod;
26
+ var result = {};
27
+ if (mod != null) for (var k in mod) if (k !== "default" && Object.prototype.hasOwnProperty.call(mod, k)) __createBinding(result, mod, k);
28
+ __setModuleDefault(result, mod);
29
+ return result;
30
+ };
31
+ Object.defineProperty(exports, "__esModule", { value: true });
32
+ exports.TypeNodeResolver = void 0;
33
+ const ts = __importStar(require("typescript"));
34
+ const decorator_1 = require("../decorator");
35
+ const constants_1 = require("./constants");
36
+ const utils_1 = require("../utils");
37
+ const error_1 = require("./error");
38
+ const extension_1 = require("./extension");
39
+ const type_1 = require("./type");
40
+ const localReferenceTypeCache = {};
41
+ const inProgressTypes = {};
42
+ class TypeNodeResolver {
43
+ constructor(typeNode, current, parentNode, context, referencer) {
44
+ this.attemptToResolveKindToPrimitive = (syntaxKind) => {
45
+ if (syntaxKind === ts.SyntaxKind.NumberKeyword) {
46
+ return 'number';
47
+ }
48
+ if (syntaxKind === ts.SyntaxKind.StringKeyword) {
49
+ return 'string';
50
+ }
51
+ if (syntaxKind === ts.SyntaxKind.BooleanKeyword) {
52
+ return 'boolean';
53
+ }
54
+ if (syntaxKind === ts.SyntaxKind.VoidKeyword) {
55
+ return 'void';
56
+ }
57
+ return undefined;
58
+ };
59
+ this.typeNode = typeNode;
60
+ this.current = current;
61
+ this.parentNode = parentNode;
62
+ this.context = context || {};
63
+ this.referencer = referencer;
64
+ }
65
+ static clearCache() {
66
+ Object.keys(localReferenceTypeCache).forEach((key) => {
67
+ delete localReferenceTypeCache[key];
68
+ });
69
+ Object.keys(inProgressTypes).forEach((key) => {
70
+ delete inProgressTypes[key];
71
+ });
72
+ }
73
+ resolve() {
74
+ const primitiveType = this.getPrimitiveType(this.typeNode, this.parentNode);
75
+ if (primitiveType) {
76
+ return primitiveType;
77
+ }
78
+ if (this.typeNode.kind === ts.SyntaxKind.NullKeyword) {
79
+ return {
80
+ typeName: constants_1.TypeName.ENUM,
81
+ members: [null],
82
+ };
83
+ }
84
+ if (this.typeNode.kind === ts.SyntaxKind.UndefinedKeyword) {
85
+ return {
86
+ typeName: constants_1.TypeName.UNDEFINED,
87
+ };
88
+ }
89
+ if (ts.isArrayTypeNode(this.typeNode)) {
90
+ return {
91
+ typeName: constants_1.TypeName.ARRAY,
92
+ elementType: new TypeNodeResolver(this.typeNode.elementType, this.current, this.parentNode, this.context).resolve(),
93
+ };
94
+ }
95
+ if (ts.isUnionTypeNode(this.typeNode)) {
96
+ const members = this.typeNode.types.map((type) => new TypeNodeResolver(type, this.current, this.parentNode, this.context).resolve());
97
+ return {
98
+ typeName: constants_1.TypeName.UNION,
99
+ members,
100
+ };
101
+ }
102
+ if (ts.isIntersectionTypeNode(this.typeNode)) {
103
+ const members = this.typeNode.types.map((type) => new TypeNodeResolver(type, this.current, this.parentNode, this.context).resolve());
104
+ return {
105
+ typeName: constants_1.TypeName.INTERSECTION,
106
+ members,
107
+ };
108
+ }
109
+ if (this.typeNode.kind === ts.SyntaxKind.AnyKeyword ||
110
+ this.typeNode.kind === ts.SyntaxKind.UnknownKeyword) {
111
+ return {
112
+ typeName: constants_1.TypeName.ANY,
113
+ };
114
+ }
115
+ if (ts.isLiteralTypeNode(this.typeNode)) {
116
+ return {
117
+ typeName: constants_1.TypeName.ENUM,
118
+ members: [TypeNodeResolver.getLiteralValue(this.typeNode)],
119
+ };
120
+ }
121
+ if (ts.isTypeLiteralNode(this.typeNode)) {
122
+ const properties = this.typeNode.members
123
+ .filter((member) => ts.isPropertySignature(member))
124
+ .reduce((res, propertySignature) => {
125
+ const type = new TypeNodeResolver(propertySignature.type, this.current, propertySignature, this.context).resolve();
126
+ const property = {
127
+ deprecated: (0, utils_1.hasJSDocTag)(propertySignature, utils_1.JSDocTagName.DEPRECATED),
128
+ example: this.getNodeExample(propertySignature),
129
+ extensions: this.getNodeExtensions(propertySignature),
130
+ default: (0, utils_1.getJSDocTagComment)(propertySignature, utils_1.JSDocTagName.DEFAULT),
131
+ description: this.getNodeDescription(propertySignature),
132
+ format: TypeNodeResolver.getNodeFormat(propertySignature),
133
+ name: propertySignature.name.text,
134
+ required: !propertySignature.questionToken,
135
+ type,
136
+ validators: (0, utils_1.getDeclarationValidators)(propertySignature) || {},
137
+ };
138
+ return [property, ...res];
139
+ }, []);
140
+ const indexMember = this.typeNode.members.find((member) => ts.isIndexSignatureDeclaration(member));
141
+ let additionalType;
142
+ if (indexMember) {
143
+ const indexSignatureDeclaration = indexMember;
144
+ const indexType = new TypeNodeResolver(indexSignatureDeclaration.parameters[0].type, this.current, this.parentNode, this.context).resolve();
145
+ if (!(0, type_1.isStringType)(indexType)) {
146
+ throw new error_1.ResolverError('Only string indexes are supported.', this.typeNode);
147
+ }
148
+ additionalType = new TypeNodeResolver(indexSignatureDeclaration.type, this.current, this.parentNode, this.context).resolve();
149
+ }
150
+ return {
151
+ additionalProperties: indexMember && additionalType,
152
+ typeName: constants_1.TypeName.NESTED_OBJECT_LITERAL,
153
+ properties,
154
+ };
155
+ }
156
+ if (this.typeNode.kind === ts.SyntaxKind.ObjectKeyword ||
157
+ ts.isFunctionTypeNode(this.typeNode)) {
158
+ return { typeName: constants_1.TypeName.OBJECT };
159
+ }
160
+ if (ts.isMappedTypeNode(this.typeNode) && this.referencer) {
161
+ const type = this.current.typeChecker.getTypeFromTypeNode(this.referencer);
162
+ const mappedTypeNode = this.typeNode;
163
+ const { typeChecker } = this.current;
164
+ const getDeclaration = (prop) => prop.declarations && prop.declarations[0];
165
+ const isIgnored = (prop) => {
166
+ const declaration = getDeclaration(prop);
167
+ const tagNames = prop.getJsDocTags();
168
+ const tagNameIndex = tagNames.findIndex((tag) => tag.name === utils_1.JSDocTagName.IGNORE);
169
+ if (tagNameIndex >= 0) {
170
+ return true;
171
+ }
172
+ return (!!declaration &&
173
+ !ts.isPropertyDeclaration(declaration) &&
174
+ !ts.isPropertySignature(declaration) &&
175
+ !ts.isParameter(declaration));
176
+ };
177
+ const properties = type
178
+ .getProperties()
179
+ // Ignore methods, getter, setter and @ignored props
180
+ .filter((property) => isIgnored(property) === false)
181
+ // Transform to property
182
+ .map((property) => {
183
+ const propertyType = typeChecker.getTypeOfSymbolAtLocation(property, this.typeNode);
184
+ const declaration = getDeclaration(property);
185
+ if (declaration && ts.isPropertySignature(declaration)) {
186
+ return { ...this.propertyFromSignature(declaration, mappedTypeNode.questionToken), name: property.getName() };
187
+ }
188
+ if (declaration && (ts.isPropertyDeclaration(declaration) || ts.isParameter(declaration))) {
189
+ return { ...this.propertyFromDeclaration(declaration, mappedTypeNode.questionToken), name: property.getName() };
190
+ }
191
+ // Resolve default value, required and typeNode
192
+ let required = false;
193
+ const typeNode = this.current.typeChecker.typeToTypeNode(propertyType, undefined, ts.NodeBuilderFlags.NoTruncation);
194
+ if (mappedTypeNode.questionToken && mappedTypeNode.questionToken.kind === ts.SyntaxKind.MinusToken) {
195
+ required = true;
196
+ }
197
+ else if (mappedTypeNode.questionToken && mappedTypeNode.questionToken.kind === ts.SyntaxKind.QuestionToken) {
198
+ required = false;
199
+ }
200
+ // Push property
201
+ return {
202
+ name: property.getName(),
203
+ required,
204
+ deprecated: false,
205
+ type: new TypeNodeResolver(typeNode, this.current, this.typeNode, this.context, this.referencer).resolve(),
206
+ validators: {},
207
+ };
208
+ });
209
+ return {
210
+ typeName: constants_1.TypeName.NESTED_OBJECT_LITERAL,
211
+ properties,
212
+ };
213
+ }
214
+ if (ts.isConditionalTypeNode(this.typeNode) &&
215
+ this.referencer &&
216
+ ts.isTypeReferenceNode(this.referencer)) {
217
+ const type = this.current.typeChecker.getTypeFromTypeNode(this.referencer);
218
+ if (type.aliasSymbol) {
219
+ let declaration = type.aliasSymbol.declarations[0];
220
+ if (declaration.name) {
221
+ declaration = this.getModelTypeDeclaration(declaration.name);
222
+ }
223
+ const name = TypeNodeResolver.getRefTypeName(this.referencer.getText());
224
+ return this.handleCachingAndCircularReferences(name, () => {
225
+ if (ts.isTypeAliasDeclaration(declaration)) {
226
+ // Note: I don't understand why typescript lose type for `this.referencer` (from above with isTypeReferenceNode())
227
+ return this.getTypeAliasReference(declaration, this.current.typeChecker.typeToString(type), this.referencer);
228
+ }
229
+ if (ts.isEnumDeclaration(declaration)) {
230
+ return this.getEnumerateType(declaration.name);
231
+ }
232
+ throw new error_1.ResolverError(`Couldn't resolve Conditional to TypeNode. If you think this should be resolvable, please file an Issue. We found an aliasSymbol and it's declaration was of kind ${declaration.kind}`, this.typeNode);
233
+ });
234
+ }
235
+ if (type.isClassOrInterface()) {
236
+ let declaration = type.symbol.declarations[0];
237
+ if (declaration.name) {
238
+ declaration = this.getModelTypeDeclaration(declaration.name);
239
+ }
240
+ const name = TypeNodeResolver.getRefTypeName(this.referencer.getText());
241
+ return this.handleCachingAndCircularReferences(name, () => this.getModelReference(declaration, this.current.typeChecker.typeToString(type)));
242
+ }
243
+ try {
244
+ return new TypeNodeResolver(this.current.typeChecker.typeToTypeNode(type, undefined, ts.NodeBuilderFlags.NoTruncation), this.current, this.typeNode, this.context, this.referencer).resolve();
245
+ }
246
+ catch {
247
+ throw new error_1.ResolverError(`Couldn't resolve Conditional to TypeNode. If you think this should be resolvable, please file an Issue. The flags on the result of the ConditionalType was ${type.flags}`, this.typeNode);
248
+ }
249
+ }
250
+ if (ts.isTypeOperatorNode(this.typeNode)) {
251
+ if (this.typeNode.operator === ts.SyntaxKind.KeyOfKeyword) {
252
+ const type = this.current.typeChecker.getTypeFromTypeNode(this.typeNode);
253
+ try {
254
+ return new TypeNodeResolver(this.current.typeChecker.typeToTypeNode(type, undefined, ts.NodeBuilderFlags.NoTruncation), this.current, this.typeNode, this.context, this.referencer).resolve();
255
+ }
256
+ catch (err) {
257
+ const indexedTypeName = this.current.typeChecker.typeToString(this.current.typeChecker.getTypeFromTypeNode(this.typeNode.type));
258
+ throw new error_1.ResolverError(`Could not determine the keys on ${indexedTypeName}`, this.typeNode);
259
+ }
260
+ }
261
+ if (this.typeNode.operator === ts.SyntaxKind.ReadonlyKeyword) {
262
+ return new TypeNodeResolver(this.typeNode.type, this.current, this.typeNode, this.context, this.referencer).resolve();
263
+ }
264
+ }
265
+ if (ts.isIndexedAccessTypeNode(this.typeNode) &&
266
+ (this.typeNode.indexType.kind === ts.SyntaxKind.NumberKeyword ||
267
+ this.typeNode.indexType.kind === ts.SyntaxKind.StringKeyword)) {
268
+ const numberIndexType = this.typeNode.indexType.kind === ts.SyntaxKind.NumberKeyword;
269
+ const objectType = this.current.typeChecker.getTypeFromTypeNode(this.typeNode.objectType);
270
+ const type = numberIndexType ? objectType.getNumberIndexType() : objectType.getStringIndexType();
271
+ if (type === undefined) {
272
+ throw new error_1.ResolverError(`Could not determine ${numberIndexType ? 'number' : 'string'} index on ${this.current.typeChecker.typeToString(objectType)}`, this.typeNode);
273
+ }
274
+ return new TypeNodeResolver(this.current.typeChecker.typeToTypeNode(type, undefined, undefined), this.current, this.typeNode, this.context, this.referencer).resolve();
275
+ }
276
+ if (ts.isIndexedAccessTypeNode(this.typeNode) &&
277
+ ts.isLiteralTypeNode(this.typeNode.indexType) &&
278
+ (ts.isStringLiteral(this.typeNode.indexType.literal) || ts.isNumericLiteral(this.typeNode.indexType.literal))) {
279
+ const hasType = (node) => node !== undefined &&
280
+ Object.prototype.hasOwnProperty.call(node, 'type');
281
+ const symbol = this.current.typeChecker.getPropertyOfType(this.current.typeChecker.getTypeFromTypeNode(this.typeNode.objectType), this.typeNode.indexType.literal.text);
282
+ if (symbol === undefined) {
283
+ throw new error_1.ResolverError(`Could not determine the keys on ${this.current.typeChecker.typeToString(this.current.typeChecker.getTypeFromTypeNode(this.typeNode.objectType))}`, this.typeNode);
284
+ }
285
+ if (hasType(symbol.valueDeclaration) && symbol.valueDeclaration.type) {
286
+ return new TypeNodeResolver(symbol.valueDeclaration.type, this.current, this.typeNode, this.context, this.referencer).resolve();
287
+ }
288
+ const declaration = this.current.typeChecker.getTypeOfSymbolAtLocation(symbol, this.typeNode.objectType);
289
+ try {
290
+ return new TypeNodeResolver(this.current.typeChecker.typeToTypeNode(declaration, undefined, undefined), this.current, this.typeNode, this.context, this.referencer).resolve();
291
+ }
292
+ catch {
293
+ throw new error_1.ResolverError(`Could not determine the keys on ${this.current.typeChecker.typeToString(this.current.typeChecker.getTypeFromTypeNode(this.current.typeChecker.typeToTypeNode(declaration, undefined, undefined)))}`, this.typeNode);
294
+ }
295
+ }
296
+ if (this.typeNode.kind === ts.SyntaxKind.TemplateLiteralType) {
297
+ const type = this.current.typeChecker.getTypeFromTypeNode(this.referencer || this.typeNode);
298
+ if (type.isUnion() && type.types.every((unionElementType) => unionElementType.isStringLiteral())) {
299
+ return {
300
+ typeName: constants_1.TypeName.ENUM,
301
+ members: type.types.map((stringLiteralType) => stringLiteralType.value),
302
+ };
303
+ }
304
+ throw new error_1.ResolverError(`Could not the type of ${this.current.typeChecker.typeToString(this.current.typeChecker.getTypeFromTypeNode(this.typeNode), this.typeNode)}`, this.typeNode);
305
+ }
306
+ if (ts.isParenthesizedTypeNode(this.typeNode)) {
307
+ return new TypeNodeResolver(this.typeNode.type, this.current, this.typeNode, this.context, this.referencer).resolve();
308
+ }
309
+ if (this.typeNode.kind !== ts.SyntaxKind.TypeReference) {
310
+ throw new error_1.ResolverError(`Unknown type: ${ts.SyntaxKind[this.typeNode.kind]}`, this.typeNode);
311
+ }
312
+ const typeReference = this.typeNode;
313
+ if (typeReference.typeName.kind === ts.SyntaxKind.Identifier) {
314
+ // Special Utility Type
315
+ if (typeReference.typeName.text === 'Record') {
316
+ return {
317
+ additionalProperties: new TypeNodeResolver(typeReference.typeArguments[1], this.current, this.parentNode, this.context).resolve(),
318
+ typeName: constants_1.TypeName.NESTED_OBJECT_LITERAL,
319
+ properties: [],
320
+ };
321
+ }
322
+ const specialReference = TypeNodeResolver.resolveSpecialReference(typeReference.typeName);
323
+ if (typeof specialReference !== 'undefined') {
324
+ return specialReference;
325
+ }
326
+ if (typeReference.typeName.text === 'Date') {
327
+ return this.getDateType(this.parentNode);
328
+ }
329
+ if (typeReference.typeName.text === 'Buffer' ||
330
+ typeReference.typeName.text === 'Readable') {
331
+ return { typeName: constants_1.TypeName.BUFFER };
332
+ }
333
+ if (typeReference.typeName.text === 'Array' &&
334
+ typeReference.typeArguments &&
335
+ typeReference.typeArguments.length >= 1) {
336
+ return {
337
+ typeName: constants_1.TypeName.ARRAY,
338
+ elementType: new TypeNodeResolver(typeReference.typeArguments[0], this.current, this.parentNode, this.context).resolve(),
339
+ };
340
+ }
341
+ if (typeReference.typeName.text === 'Promise' &&
342
+ typeReference.typeArguments &&
343
+ typeReference.typeArguments.length === 1) {
344
+ return new TypeNodeResolver(typeReference.typeArguments[0], this.current, this.parentNode, this.context).resolve();
345
+ }
346
+ if (typeReference.typeName.text === 'String') {
347
+ return { typeName: constants_1.TypeName.STRING };
348
+ }
349
+ if (this.context[typeReference.typeName.text]) {
350
+ return new TypeNodeResolver(this.context[typeReference.typeName.text], this.current, this.parentNode, this.context).resolve();
351
+ }
352
+ }
353
+ const referenceType = this.getReferenceType(typeReference);
354
+ this.current.addReferenceType(referenceType);
355
+ return referenceType;
356
+ }
357
+ // ------------------------------------------------------------------------
358
+ // Utility Type(s)
359
+ // ------------------------------------------------------------------------
360
+ static isSupportedUtilityType(typeName) {
361
+ if (typeof typeName === 'undefined') {
362
+ return false;
363
+ }
364
+ return ['NonNullable', 'Pick', 'Omit', 'Partial', 'Readonly', 'Record', 'Required'].indexOf(typeof typeName !== 'string' ? typeName.text : typeName) !== -1;
365
+ }
366
+ static getUtilityTypeOptions(typeArguments) {
367
+ const utilityOptions = {
368
+ keys: [],
369
+ };
370
+ if (typeArguments.length >= 2) {
371
+ if (ts.isUnionTypeNode(typeArguments[1])) {
372
+ const args = typeArguments[1].types;
373
+ for (let i = 0; i < args.length; i++) {
374
+ if (ts.isLiteralTypeNode(args[i])) {
375
+ utilityOptions.keys.push(TypeNodeResolver.getLiteralValue(args[i]));
376
+ }
377
+ }
378
+ }
379
+ if (ts.isLiteralTypeNode(typeArguments[1])) {
380
+ utilityOptions.keys.push(TypeNodeResolver.getLiteralValue(typeArguments[1]));
381
+ }
382
+ }
383
+ return utilityOptions;
384
+ }
385
+ filterUtilityProperties(properties, utilityType, utilityOptions) {
386
+ if (typeof utilityType === 'undefined' || typeof utilityOptions === 'undefined') {
387
+ return properties;
388
+ }
389
+ return properties
390
+ .filter((property) => {
391
+ const name = typeof property.name !== 'string' ? property.name.text : property.name;
392
+ switch (utilityType) {
393
+ case 'Pick':
394
+ return utilityOptions.keys.indexOf(name) !== -1;
395
+ case 'Omit':
396
+ return utilityOptions.keys.indexOf(name) === -1;
397
+ }
398
+ return true;
399
+ })
400
+ .map((property) => {
401
+ if ((0, utils_1.hasOwnProperty)(property, 'required')) {
402
+ switch (utilityType) {
403
+ case 'Partial':
404
+ property.required = false;
405
+ break;
406
+ case 'Required':
407
+ case 'NonNullable':
408
+ property.required = true;
409
+ break;
410
+ }
411
+ }
412
+ return property;
413
+ });
414
+ }
415
+ static resolveSpecialReference(node) {
416
+ switch (node.text) {
417
+ case 'Buffer':
418
+ case 'DownloadBinaryData':
419
+ case 'DownloadResource':
420
+ return { typeName: constants_1.TypeName.BUFFER };
421
+ default:
422
+ return undefined;
423
+ }
424
+ }
425
+ static getLiteralValue(typeNode) {
426
+ let value;
427
+ switch (typeNode.literal.kind) {
428
+ case ts.SyntaxKind.TrueKeyword:
429
+ value = true;
430
+ break;
431
+ case ts.SyntaxKind.FalseKeyword:
432
+ value = false;
433
+ break;
434
+ case ts.SyntaxKind.StringLiteral:
435
+ value = typeNode.literal.text;
436
+ break;
437
+ case ts.SyntaxKind.NumericLiteral:
438
+ value = parseFloat(typeNode.literal.text);
439
+ break;
440
+ case ts.SyntaxKind.NullKeyword:
441
+ value = null;
442
+ break;
443
+ default:
444
+ if (Object.prototype.hasOwnProperty.call(typeNode.literal, 'text')) {
445
+ value = typeNode.literal.text;
446
+ }
447
+ else {
448
+ throw new error_1.ResolverError(`Couldn't resolve literal node: ${typeNode.literal.getText()}`);
449
+ }
450
+ }
451
+ return value;
452
+ }
453
+ getPrimitiveType(typeNode, parentNode) {
454
+ if (!typeNode) {
455
+ return {
456
+ typeName: constants_1.TypeName.VOID,
457
+ };
458
+ }
459
+ const resolvedType = this.attemptToResolveKindToPrimitive(typeNode.kind);
460
+ if (typeof resolvedType === 'undefined') {
461
+ return undefined;
462
+ }
463
+ if (resolvedType === 'number') {
464
+ if (!parentNode) {
465
+ return { typeName: constants_1.TypeName.DOUBLE };
466
+ }
467
+ const lookupTags = [
468
+ 'isInt',
469
+ 'isLong',
470
+ 'isFloat',
471
+ 'isDouble',
472
+ ];
473
+ const tags = (0, utils_1.getJSDocTagNames)(parentNode)
474
+ .filter((name) => lookupTags.some((m) => m.toLowerCase() === name.toLowerCase()))
475
+ .map((name) => name.toLowerCase());
476
+ const decoratorIds = [
477
+ decorator_1.DecoratorID.IS_INT,
478
+ decorator_1.DecoratorID.IS_LONG,
479
+ decorator_1.DecoratorID.IS_FLOAT,
480
+ decorator_1.DecoratorID.IS_DOUBLE,
481
+ ];
482
+ let decoratorID;
483
+ for (let i = 0; i < decoratorIds.length; i++) {
484
+ const decorator = this.current.decoratorResolver.match(decoratorIds[i], parentNode);
485
+ if (decorator) {
486
+ decoratorID = decoratorIds[i];
487
+ break;
488
+ }
489
+ }
490
+ if (!decoratorID && tags.length === 0) {
491
+ return { typeName: constants_1.TypeName.DOUBLE };
492
+ }
493
+ switch (decoratorID || tags[0]) {
494
+ case decorator_1.DecoratorID.IS_INT:
495
+ case 'isint':
496
+ return { typeName: constants_1.TypeName.INTEGER };
497
+ case decorator_1.DecoratorID.IS_LONG:
498
+ case 'islong':
499
+ return { typeName: constants_1.TypeName.LONG };
500
+ case decorator_1.DecoratorID.IS_FLOAT:
501
+ case 'isfloat':
502
+ return { typeName: constants_1.TypeName.FLOAT };
503
+ case decorator_1.DecoratorID.IS_DOUBLE:
504
+ case 'isdouble':
505
+ return { typeName: constants_1.TypeName.DOUBLE };
506
+ default:
507
+ return { typeName: constants_1.TypeName.DOUBLE };
508
+ }
509
+ }
510
+ else if (resolvedType === 'string') {
511
+ return {
512
+ typeName: constants_1.TypeName.STRING,
513
+ };
514
+ }
515
+ else if (resolvedType === 'boolean') {
516
+ return {
517
+ typeName: constants_1.TypeName.BOOLEAN,
518
+ };
519
+ }
520
+ else if (resolvedType === 'void') {
521
+ return {
522
+ typeName: constants_1.TypeName.VOID,
523
+ };
524
+ }
525
+ else {
526
+ // todo: should not occur
527
+ return {
528
+ typeName: resolvedType,
529
+ };
530
+ }
531
+ }
532
+ getDateType(parentNode) {
533
+ if (!parentNode) {
534
+ return { typeName: constants_1.TypeName.DATETIME };
535
+ }
536
+ const tags = (0, utils_1.getJSDocTagNames)(parentNode).filter((name) => ['isDate', 'isDateTime'].some((m) => m === name));
537
+ if (tags.length === 0) {
538
+ return { typeName: constants_1.TypeName.DATETIME };
539
+ }
540
+ switch (tags[0]) {
541
+ case 'isDate':
542
+ return { typeName: constants_1.TypeName.DATE };
543
+ default:
544
+ return { typeName: constants_1.TypeName.DATETIME };
545
+ }
546
+ }
547
+ static getDesignatedModels(nodes, typeName) {
548
+ return nodes;
549
+ }
550
+ getEnumerateType(typeName) {
551
+ const enumName = typeName.text;
552
+ let enumNodes = this.current.nodes.filter((node) => node.kind === ts.SyntaxKind.EnumDeclaration && node.name.text === enumName);
553
+ if (!enumNodes.length) {
554
+ return undefined;
555
+ }
556
+ enumNodes = TypeNodeResolver.getDesignatedModels(enumNodes, enumName);
557
+ if (enumNodes.length > 1) {
558
+ throw new error_1.ResolverError(`Multiple matching enum found for enum ${enumName}; please make enum names unique.`);
559
+ }
560
+ const enumDeclaration = enumNodes[0];
561
+ const isNotUndefined = (item) => item !== undefined;
562
+ const enums = enumDeclaration.members.map(this.current.typeChecker.getConstantValue.bind(this.current.typeChecker)).filter(isNotUndefined);
563
+ const enumNames = enumDeclaration.members.map((e) => e.name.getText()).filter(isNotUndefined);
564
+ return {
565
+ typeName: constants_1.TypeName.REF_ENUM,
566
+ description: this.getNodeDescription(enumDeclaration),
567
+ members: enums,
568
+ memberNames: enumNames,
569
+ refName: enumName,
570
+ deprecated: (0, utils_1.hasJSDocTag)(enumDeclaration, utils_1.JSDocTagName.DEPRECATED),
571
+ };
572
+ }
573
+ getReferenceType(node) {
574
+ let type;
575
+ if (ts.isTypeReferenceNode(node)) {
576
+ type = node.typeName;
577
+ }
578
+ else if (ts.isExpressionWithTypeArguments(node)) {
579
+ type = node.expression;
580
+ }
581
+ else {
582
+ throw new error_1.ResolverError('Can\'t resolve reference type.');
583
+ }
584
+ // Can't invoke getText on Synthetic Nodes
585
+ let resolvableName = node.pos !== -1 ? node.getText() : type.text;
586
+ if (node.pos === -1 && 'typeArguments' in node && Array.isArray(node.typeArguments)) {
587
+ // Add typeArguments for Synthetic nodes (e.g. Record<> in TestClassModel.indexedResponse)
588
+ const argumentsString = node.typeArguments
589
+ .map((arg) => {
590
+ if (ts.isLiteralTypeNode(arg)) {
591
+ return `'${String(TypeNodeResolver.getLiteralValue(arg))}'`;
592
+ }
593
+ const resolvedType = this.attemptToResolveKindToPrimitive(arg.kind);
594
+ if (typeof resolvedType === 'undefined') {
595
+ return 'any';
596
+ }
597
+ return resolvedType;
598
+ });
599
+ resolvableName += `<${argumentsString.join(', ')}>`;
600
+ }
601
+ const name = this.contextualizedName(resolvableName);
602
+ // Handle Utility Types
603
+ const identifierName = type.text;
604
+ const utilityTypeSupported = TypeNodeResolver.isSupportedUtilityType(identifierName);
605
+ const utilityType = utilityTypeSupported ? identifierName : undefined;
606
+ let utilityOptions = {
607
+ keys: [],
608
+ };
609
+ if (utilityTypeSupported) {
610
+ const { typeArguments } = type.parent;
611
+ if (ts.isTypeReferenceNode(typeArguments[0])) {
612
+ type = typeArguments[0].typeName;
613
+ }
614
+ else if (ts.isExpressionWithTypeArguments(typeArguments[0])) {
615
+ type = typeArguments[0].expression;
616
+ }
617
+ else {
618
+ throw new error_1.ResolverError('Can\'t resolve Reference type.');
619
+ }
620
+ utilityOptions = TypeNodeResolver.getUtilityTypeOptions(typeArguments);
621
+ }
622
+ else {
623
+ this.typeArgumentsToContext(node, type, this.context);
624
+ }
625
+ try {
626
+ const existingType = localReferenceTypeCache[name];
627
+ if (existingType) {
628
+ return existingType;
629
+ }
630
+ const refEnumType = this.getEnumerateType(type);
631
+ if (refEnumType) {
632
+ localReferenceTypeCache[name] = refEnumType;
633
+ return refEnumType;
634
+ }
635
+ if (inProgressTypes[name]) {
636
+ return this.createCircularDependencyResolver(name);
637
+ }
638
+ inProgressTypes[name] = true;
639
+ const declaration = this.getModelTypeDeclaration(type);
640
+ let referenceType;
641
+ if (ts.isTypeAliasDeclaration(declaration)) {
642
+ referenceType = this.getTypeAliasReference(declaration, name, node);
643
+ }
644
+ else if (ts.isEnumMember(declaration)) {
645
+ referenceType = {
646
+ typeName: constants_1.TypeName.REF_ENUM,
647
+ refName: TypeNodeResolver.getRefTypeName(name, utilityType),
648
+ members: [this.current.typeChecker.getConstantValue(declaration)],
649
+ memberNames: [declaration.name.getText()],
650
+ deprecated: (0, utils_1.hasJSDocTag)(declaration, utils_1.JSDocTagName.DEPRECATED),
651
+ };
652
+ }
653
+ else {
654
+ // todo: dont cast handle property-signature
655
+ referenceType = this.getModelReference(declaration, name, utilityType, utilityOptions);
656
+ }
657
+ localReferenceTypeCache[name] = referenceType;
658
+ return referenceType;
659
+ }
660
+ catch (err) {
661
+ // eslint-disable-next-line no-console
662
+ console.error(`There was a problem resolving type of '${name}'.`);
663
+ throw err;
664
+ }
665
+ }
666
+ getTypeAliasReference(declaration, name, referencer) {
667
+ const refName = TypeNodeResolver.getRefTypeName(name);
668
+ let type;
669
+ if (declaration.type.kind === ts.SyntaxKind.TypeReference) {
670
+ const referenceType = this.getReferenceType(declaration.type);
671
+ if (referenceType.refName === refName) {
672
+ return referenceType;
673
+ }
674
+ }
675
+ if (typeof type === 'undefined') {
676
+ type = new TypeNodeResolver(declaration.type, this.current, declaration, this.context, this.referencer || referencer).resolve();
677
+ }
678
+ const example = this.getNodeExample(declaration);
679
+ return {
680
+ typeName: constants_1.TypeName.REF_ALIAS,
681
+ default: (0, utils_1.getJSDocTagComment)(declaration, utils_1.JSDocTagName.DEFAULT),
682
+ description: this.getNodeDescription(declaration),
683
+ refName,
684
+ format: TypeNodeResolver.getNodeFormat(declaration),
685
+ type,
686
+ validators: (0, utils_1.getDeclarationValidators)(declaration) || {},
687
+ deprecated: (0, utils_1.hasJSDocTag)(declaration, utils_1.JSDocTagName.DEPRECATED),
688
+ ...(example && { example }),
689
+ };
690
+ }
691
+ getModelReference(modelType, name, utilityType, utilityOptions) {
692
+ const example = this.getNodeExample(modelType);
693
+ const description = this.getNodeDescription(modelType);
694
+ const deprecated = (0, utils_1.hasJSDocTag)(modelType, utils_1.JSDocTagName.DEPRECATED) ||
695
+ !!this.current.decoratorResolver.match(decorator_1.DecoratorID.DEPRECATED, modelType);
696
+ // Handle toJSON methods
697
+ if (!modelType.name) {
698
+ throw new error_1.ResolverError('Can\'t get Symbol from anonymous class', modelType);
699
+ }
700
+ const type = this.current.typeChecker.getTypeAtLocation(modelType.name);
701
+ const toJSON = this.current.typeChecker.getPropertyOfType(type, 'toJSON');
702
+ if (toJSON &&
703
+ toJSON.valueDeclaration &&
704
+ (ts.isMethodDeclaration(toJSON.valueDeclaration) ||
705
+ ts.isMethodSignature(toJSON.valueDeclaration))) {
706
+ let nodeType = toJSON.valueDeclaration.type;
707
+ if (!nodeType) {
708
+ const signature = this.current.typeChecker.getSignatureFromDeclaration(toJSON.valueDeclaration);
709
+ const implicitType = this.current.typeChecker.getReturnTypeOfSignature(signature);
710
+ nodeType = this.current.typeChecker.typeToTypeNode(implicitType, undefined, ts.NodeBuilderFlags.NoTruncation);
711
+ }
712
+ return {
713
+ refName: `${TypeNodeResolver.getRefTypeName(name, utilityType)}Alias`,
714
+ typeName: constants_1.TypeName.REF_ALIAS,
715
+ description,
716
+ type: new TypeNodeResolver(nodeType, this.current).resolve(),
717
+ deprecated,
718
+ validators: {},
719
+ ...(example && { example }),
720
+ };
721
+ }
722
+ const properties = this.getModelProperties(modelType, undefined, utilityType, utilityOptions);
723
+ const additionalProperties = this.getModelAdditionalProperties(modelType);
724
+ const inheritedProperties = this.getModelInheritedProperties(modelType) || [];
725
+ const referenceType = {
726
+ additionalProperties,
727
+ typeName: constants_1.TypeName.REF_OBJECT,
728
+ description,
729
+ properties: this.filterUtilityProperties(inheritedProperties, utilityType, utilityOptions),
730
+ refName: TypeNodeResolver.getRefTypeName(name, utilityType),
731
+ deprecated,
732
+ ...(example && { example }),
733
+ };
734
+ referenceType.properties = referenceType.properties.concat(properties);
735
+ return referenceType;
736
+ }
737
+ static getRefTypeName(name, utilityType) {
738
+ return encodeURIComponent(name
739
+ .replace(/<|>/g, '_')
740
+ .replace(/\s+/g, '')
741
+ .replace(/,/g, '.')
742
+ .replace(/'([^']*)'/g, '$1')
743
+ .replace(/"([^"]*)"/g, '$1')
744
+ .replace(/&/g, typeof utilityType !== 'undefined' ? '--' : '-and-')
745
+ .replace(/\|/g, typeof utilityType !== 'undefined' ? '--' : '-or-')
746
+ .replace(/\[\]/g, '-array')
747
+ .replace(/{|}/g, '_') // SuccessResponse_{indexesCreated-number}_ -> SuccessResponse__indexesCreated-number__
748
+ .replace(/([a-z]+):([a-z]+)/gi, '$1-$2') // SuccessResponse_indexesCreated:number_ -> SuccessResponse_indexesCreated-number_
749
+ .replace(/;/g, '--')
750
+ .replace(/([a-z]+)\[([a-z]+)\]/gi, '$1-at-$2') // Partial_SerializedDatasourceWithVersion[format]_ -> Partial_SerializedDatasourceWithVersion~format~_,
751
+ .replace(/_/g, '')
752
+ .replace(/-/g, ''));
753
+ }
754
+ contextualizedName(name) {
755
+ return Object.entries(this.context).reduce((acc, [key, entry]) => acc
756
+ .replace(new RegExp(`<\\s*([^>]*\\s)*\\s*(${key})(\\s[^>]*)*\\s*>`, 'g'), `<$1${entry.getText()}$3>`)
757
+ .replace(new RegExp(`<\\s*([^,]*\\s)*\\s*(${key})(\\s[^,]*)*\\s*,`, 'g'), `<$1${entry.getText()}$3,`)
758
+ .replace(new RegExp(`,\\s*([^>]*\\s)*\\s*(${key})(\\s[^>]*)*\\s*>`, 'g'), `,$1${entry.getText()}$3>`)
759
+ .replace(new RegExp(`<\\s*([^<]*\\s)*\\s*(${key})(\\s[^<]*)*\\s*<`, 'g'), `<$1${entry.getText()}$3<`), name);
760
+ }
761
+ handleCachingAndCircularReferences(name, declarationResolver) {
762
+ try {
763
+ const existingType = localReferenceTypeCache[name];
764
+ if (existingType) {
765
+ return existingType;
766
+ }
767
+ if (inProgressTypes[name]) {
768
+ return this.createCircularDependencyResolver(name);
769
+ }
770
+ inProgressTypes[name] = true;
771
+ const reference = declarationResolver();
772
+ localReferenceTypeCache[name] = reference;
773
+ this.current.addReferenceType(reference);
774
+ return reference;
775
+ }
776
+ catch (err) {
777
+ // eslint-disable-next-line no-console
778
+ console.error(`There was a problem resolving type of '${name}'.`);
779
+ throw err;
780
+ }
781
+ }
782
+ createCircularDependencyResolver(refName) {
783
+ const referenceType = {
784
+ typeName: constants_1.TypeName.REF_OBJECT,
785
+ refName,
786
+ };
787
+ this.current.registerDependencyResolver((referenceTypes) => {
788
+ const realReferenceType = referenceTypes[refName];
789
+ if (!realReferenceType) {
790
+ return;
791
+ }
792
+ referenceType.description = realReferenceType.description;
793
+ if (realReferenceType.typeName === 'refObject' && referenceType.typeName === 'refObject') {
794
+ referenceType.properties = realReferenceType.properties;
795
+ }
796
+ referenceType.typeName = realReferenceType.typeName;
797
+ referenceType.refName = realReferenceType.refName;
798
+ });
799
+ return referenceType;
800
+ }
801
+ static nodeIsUsable(node) {
802
+ switch (node.kind) {
803
+ case ts.SyntaxKind.InterfaceDeclaration:
804
+ case ts.SyntaxKind.ClassDeclaration:
805
+ case ts.SyntaxKind.TypeAliasDeclaration:
806
+ case ts.SyntaxKind.EnumDeclaration:
807
+ case ts.SyntaxKind.EnumMember:
808
+ return true;
809
+ default:
810
+ return false;
811
+ }
812
+ }
813
+ getModelTypeDeclaration(type) {
814
+ let typeName = type.kind === ts.SyntaxKind.Identifier ? type.text : type.right.text;
815
+ const symbol = this.getSymbolAtLocation(type);
816
+ const declarations = symbol.getDeclarations();
817
+ if (declarations.length === 0) {
818
+ throw new error_1.ResolverError(`No models found for referenced type ${typeName}.`);
819
+ }
820
+ if (symbol.escapedName !== typeName && symbol.escapedName !== 'default') {
821
+ typeName = symbol.escapedName;
822
+ }
823
+ let modelTypes = declarations.filter((node) => {
824
+ if (!TypeNodeResolver.nodeIsUsable(node) || !this.current.isExportedNode(node)) {
825
+ return false;
826
+ }
827
+ const modelTypeDeclaration = node;
828
+ return modelTypeDeclaration.name?.text === typeName;
829
+ });
830
+ if (!modelTypes.length) {
831
+ throw new error_1.ResolverError(`No matching model found for referenced type ${typeName}. If ${typeName} comes from a dependency, please create an interface in your own code that has the same structure. The compiler can not utilize interfaces from external dependencies.`);
832
+ }
833
+ if (modelTypes.length > 1) {
834
+ // remove types that are from typescript e.g. 'Account'
835
+ modelTypes = modelTypes.filter((modelType) => modelType.getSourceFile()
836
+ .fileName.replace(/\\/g, '/').toLowerCase().indexOf('node_modules/typescript') <= -1);
837
+ modelTypes = TypeNodeResolver.getDesignatedModels(modelTypes, typeName);
838
+ }
839
+ if (modelTypes.length > 1) {
840
+ const conflicts = modelTypes.map((modelType) => modelType.getSourceFile().fileName).join('"; "');
841
+ throw new error_1.ResolverError(`Multiple matching models found for referenced type ${typeName}; please make model names unique. Conflicts found: "${conflicts}".`);
842
+ }
843
+ return modelTypes[0];
844
+ }
845
+ hasFlag(type, flag) {
846
+ return (type.flags & flag) === flag;
847
+ }
848
+ getSymbolAtLocation(type) {
849
+ const symbol = this.current.typeChecker.getSymbolAtLocation(type) || type.symbol;
850
+ // resolve alias if it is an alias, otherwise take symbol directly
851
+ return (symbol &&
852
+ this.hasFlag(symbol, ts.SymbolFlags.Alias) &&
853
+ this.current.typeChecker.getAliasedSymbol(symbol)) || symbol;
854
+ }
855
+ getModelProperties(node, overrideToken, utilityType, utilityOptions) {
856
+ const isIgnored = (e) => (0, utils_1.hasJSDocTag)(e, utils_1.JSDocTagName.IGNORE);
857
+ // Interface model
858
+ if (ts.isInterfaceDeclaration(node)) {
859
+ return node.members.filter((member) => !isIgnored(member) &&
860
+ ts.isPropertySignature(member)).map((member) => this.propertyFromSignature(member, overrideToken));
861
+ }
862
+ // Class model
863
+ let properties = node.members
864
+ .filter((member) => !isIgnored(member) &&
865
+ member.kind === ts.SyntaxKind.PropertyDeclaration &&
866
+ !this.hasStaticModifier(member) &&
867
+ this.hasPublicModifier(member));
868
+ const classConstructor = node.members.find((member) => ts.isConstructorDeclaration(member));
869
+ if (classConstructor && classConstructor.parameters) {
870
+ const constructorProperties = classConstructor.parameters.filter((parameter) => this.isAccessibleParameter(parameter));
871
+ properties.push(...constructorProperties);
872
+ }
873
+ properties = this.filterUtilityProperties(properties, utilityType, utilityOptions);
874
+ return properties.map((property) => this.propertyFromDeclaration(property, overrideToken, utilityType));
875
+ }
876
+ propertyFromSignature(propertySignature, overrideToken) {
877
+ const identifier = propertySignature.name;
878
+ if (!propertySignature.type) {
879
+ throw new error_1.ResolverError('No valid type found for property declaration.');
880
+ }
881
+ let required = !propertySignature.questionToken;
882
+ if (overrideToken && overrideToken.kind === ts.SyntaxKind.MinusToken) {
883
+ required = true;
884
+ }
885
+ else if (overrideToken && overrideToken.kind === ts.SyntaxKind.QuestionToken) {
886
+ required = false;
887
+ }
888
+ const property = {
889
+ deprecated: (0, utils_1.hasJSDocTag)(propertySignature, utils_1.JSDocTagName.DEPRECATED),
890
+ default: (0, utils_1.getJSDocTagComment)(propertySignature, utils_1.JSDocTagName.DEFAULT),
891
+ description: this.getNodeDescription(propertySignature),
892
+ example: this.getNodeExample(propertySignature),
893
+ extensions: this.getNodeExtensions(propertySignature),
894
+ format: TypeNodeResolver.getNodeFormat(propertySignature),
895
+ name: identifier.text,
896
+ required,
897
+ type: new TypeNodeResolver(propertySignature.type, this.current, propertySignature.type.parent, this.context, propertySignature.type).resolve(),
898
+ validators: (0, utils_1.getDeclarationValidators)(propertySignature) || {},
899
+ };
900
+ return property;
901
+ }
902
+ propertyFromDeclaration(propertyDeclaration, overrideToken, utilityType) {
903
+ const identifier = propertyDeclaration.name;
904
+ let typeNode = propertyDeclaration.type;
905
+ if (!typeNode) {
906
+ const tsType = this.current.typeChecker.getTypeAtLocation(propertyDeclaration);
907
+ typeNode = this.current.typeChecker.typeToTypeNode(tsType, undefined, ts.NodeBuilderFlags.NoTruncation);
908
+ }
909
+ if (!typeNode) {
910
+ throw new error_1.ResolverError('No valid type found for property declaration.');
911
+ }
912
+ const type = new TypeNodeResolver(typeNode, this.current, propertyDeclaration, this.context, typeNode).resolve();
913
+ let required = !propertyDeclaration.questionToken && !propertyDeclaration.initializer;
914
+ if (overrideToken && overrideToken.kind === ts.SyntaxKind.MinusToken) {
915
+ required = true;
916
+ }
917
+ else if (overrideToken && overrideToken.kind === ts.SyntaxKind.QuestionToken) {
918
+ required = false;
919
+ }
920
+ if (typeof utilityType !== 'undefined') {
921
+ if (utilityType === 'Partial') {
922
+ required = false;
923
+ }
924
+ if (utilityType === 'Required') {
925
+ required = true;
926
+ }
927
+ }
928
+ const property = {
929
+ deprecated: (0, utils_1.hasJSDocTag)(propertyDeclaration, utils_1.JSDocTagName.DEPRECATED),
930
+ default: (0, utils_1.getInitializerValue)(propertyDeclaration.initializer, this.current.typeChecker),
931
+ description: this.getNodeDescription(propertyDeclaration),
932
+ example: this.getNodeExample(propertyDeclaration),
933
+ extensions: this.getNodeExtensions(propertyDeclaration),
934
+ format: TypeNodeResolver.getNodeFormat(propertyDeclaration),
935
+ name: identifier.text,
936
+ required,
937
+ type,
938
+ validators: (0, utils_1.getDeclarationValidators)(propertyDeclaration) || {},
939
+ };
940
+ return property;
941
+ }
942
+ getModelAdditionalProperties(node) {
943
+ if (node.kind === ts.SyntaxKind.InterfaceDeclaration) {
944
+ const indexMember = node.members.find((member) => member.kind === ts.SyntaxKind.IndexSignature);
945
+ if (!indexMember) {
946
+ return undefined;
947
+ }
948
+ const indexSignatureDeclaration = indexMember;
949
+ const indexType = new TypeNodeResolver(indexSignatureDeclaration.parameters[0].type, this.current, this.parentNode, this.context).resolve();
950
+ if (indexType.typeName !== 'string') {
951
+ throw new error_1.ResolverError('Only string indexers are supported.', this.typeNode);
952
+ }
953
+ return new TypeNodeResolver(indexSignatureDeclaration.type, this.current, this.parentNode, this.context).resolve();
954
+ }
955
+ return undefined;
956
+ }
957
+ typeArgumentsToContext(type, targetEntity, context) {
958
+ // this.context = {};
959
+ const declaration = this.getModelTypeDeclaration(targetEntity);
960
+ if (typeof declaration === 'undefined' || !('typeParameters' in declaration)) {
961
+ return context;
962
+ }
963
+ const { typeParameters } = declaration;
964
+ if (typeParameters) {
965
+ for (let index = 0; index < typeParameters.length; index++) {
966
+ const typeParameter = typeParameters[index];
967
+ const typeArg = type.typeArguments && type.typeArguments[index];
968
+ let resolvedType;
969
+ // Argument may be a forward reference from context
970
+ if (typeArg && ts.isTypeReferenceNode(typeArg) && ts.isIdentifier(typeArg.typeName) && context[typeArg.typeName.text]) {
971
+ resolvedType = context[typeArg.typeName.text];
972
+ }
973
+ else if (typeArg) {
974
+ resolvedType = typeArg;
975
+ }
976
+ else if (typeParameter.default) {
977
+ resolvedType = typeParameter.default;
978
+ }
979
+ else {
980
+ throw new error_1.ResolverError(`Could not find a value for type parameter ${typeParameter.name.text}`, type);
981
+ }
982
+ this.context = {
983
+ ...this.context,
984
+ [typeParameter.name.text]: resolvedType,
985
+ };
986
+ }
987
+ }
988
+ return context;
989
+ }
990
+ getModelInheritedProperties(modelTypeDeclaration) {
991
+ let properties = [];
992
+ const { heritageClauses } = modelTypeDeclaration;
993
+ if (!heritageClauses) {
994
+ return properties;
995
+ }
996
+ heritageClauses.forEach((clause) => {
997
+ if (!clause.types) {
998
+ return;
999
+ }
1000
+ clause.types.forEach((t) => {
1001
+ const baseEntityName = t.expression;
1002
+ // create subContext
1003
+ const resetCtx = this.typeArgumentsToContext(t, baseEntityName, this.context);
1004
+ const referenceType = this.getReferenceType(t);
1005
+ if (referenceType) {
1006
+ if ((0, type_1.isRefAliasType)(referenceType)) {
1007
+ let type = referenceType;
1008
+ while ((0, type_1.isRefAliasType)(type)) {
1009
+ type = type.type;
1010
+ }
1011
+ if (type.typeName === constants_1.TypeName.REF_OBJECT) {
1012
+ properties = [...properties, ...type.properties];
1013
+ }
1014
+ else if (type.typeName === constants_1.TypeName.NESTED_OBJECT_LITERAL) {
1015
+ properties = [...properties, ...type.properties];
1016
+ }
1017
+ }
1018
+ if ((0, type_1.isRefObjectType)(referenceType)) {
1019
+ referenceType.properties.forEach((property) => properties.push(property));
1020
+ }
1021
+ }
1022
+ // reset subContext
1023
+ this.context = resetCtx;
1024
+ });
1025
+ });
1026
+ return properties;
1027
+ }
1028
+ hasPublicModifier(node) {
1029
+ if (!ts.canHaveModifiers(node)) {
1030
+ return true;
1031
+ }
1032
+ const modifiers = ts.getModifiers(node);
1033
+ if (!modifiers) {
1034
+ return true;
1035
+ }
1036
+ return modifiers.every((modifier) => modifier.kind !== ts.SyntaxKind.ProtectedKeyword && modifier.kind !== ts.SyntaxKind.PrivateKeyword);
1037
+ }
1038
+ hasStaticModifier(node) {
1039
+ if (!ts.canHaveModifiers(node)) {
1040
+ return false;
1041
+ }
1042
+ const modifiers = ts.getModifiers(node);
1043
+ return modifiers && modifiers.some((modifier) => modifier.kind === ts.SyntaxKind.StaticKeyword);
1044
+ }
1045
+ isAccessibleParameter(node) {
1046
+ // No modifiers
1047
+ if (!ts.canHaveModifiers(node)) {
1048
+ return false;
1049
+ }
1050
+ const modifiers = ts.getModifiers(node);
1051
+ if (!modifiers) {
1052
+ return false;
1053
+ }
1054
+ // public || public readonly
1055
+ if (modifiers.some((modifier) => modifier.kind === ts.SyntaxKind.PublicKeyword)) {
1056
+ return true;
1057
+ }
1058
+ // readonly, not private readonly, not public readonly
1059
+ const isReadonly = modifiers.some((modifier) => modifier.kind === ts.SyntaxKind.ReadonlyKeyword);
1060
+ const isProtectedOrPrivate = modifiers.some((modifier) => modifier.kind === ts.SyntaxKind.ProtectedKeyword ||
1061
+ modifier.kind === ts.SyntaxKind.PrivateKeyword);
1062
+ return isReadonly && !isProtectedOrPrivate;
1063
+ }
1064
+ getNodeDescription(node) {
1065
+ const symbol = this.current.typeChecker.getSymbolAtLocation(node.name);
1066
+ if (!symbol) {
1067
+ return undefined;
1068
+ }
1069
+ /**
1070
+ * TODO: Workaround for what seems like a bug in the compiler
1071
+ * Warrants more investigation and possibly a PR against typescript
1072
+ */
1073
+ if (node.kind === ts.SyntaxKind.Parameter) {
1074
+ // TypeScript won't parse jsdoc if the flag is 4, i.e. 'Property'
1075
+ symbol.flags = 0;
1076
+ }
1077
+ const comments = symbol.getDocumentationComment(this.current.typeChecker);
1078
+ if (comments.length) {
1079
+ return ts.displayPartsToString(comments);
1080
+ }
1081
+ return undefined;
1082
+ }
1083
+ static getNodeFormat(node) {
1084
+ return (0, utils_1.getJSDocTagComment)(node, utils_1.JSDocTagName.FORMAT);
1085
+ }
1086
+ getNodeExample(node) {
1087
+ const example = (0, utils_1.getJSDocTagComment)(node, utils_1.JSDocTagName.EXAMPLE);
1088
+ if (example) {
1089
+ try {
1090
+ return JSON.parse(example);
1091
+ }
1092
+ catch {
1093
+ // do nothing
1094
+ }
1095
+ }
1096
+ return undefined;
1097
+ }
1098
+ getNodeExtensions(node) {
1099
+ return (0, extension_1.getNodeExtensions)(node, this.current.decoratorResolver);
1100
+ }
1101
+ }
1102
+ exports.TypeNodeResolver = TypeNodeResolver;
1089
1103
  //# sourceMappingURL=module.js.map