@trapi/metadata 2.0.0-beta.2 → 2.0.0-beta.3
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/index.d.mts +183 -1292
- package/dist/index.d.mts.map +1 -1
- package/dist/index.mjs +364 -1308
- package/dist/index.mjs.map +1 -1
- package/package.json +3 -5
package/dist/index.mjs
CHANGED
|
@@ -1,247 +1,45 @@
|
|
|
1
|
-
import path, { normalize } from "node:path";
|
|
2
1
|
import { BaseError, isBaseError } from "@ebec/core";
|
|
3
|
-
import
|
|
4
|
-
import
|
|
5
|
-
import {
|
|
6
|
-
import {
|
|
7
|
-
import { createValidator } from "@validup/adapter-zod";
|
|
8
|
-
import { z } from "zod";
|
|
2
|
+
import { NodeBuilderFlags, NodeFlags, SymbolFlags, SyntaxKind, canHaveDecorators, canHaveModifiers, convertCompilerOptionsFromJson, createProgram, displayPartsToString, factory, forEachChild, getDecorators, getModifiers, isArrayLiteralExpression, isArrayTypeNode, isCallExpression, isClassDeclaration, isConditionalTypeNode, isConstructorDeclaration, isEnumDeclaration, isEnumMember, isExpressionWithTypeArguments, isFunctionTypeNode, isIdentifier, isImportSpecifier, isIndexSignatureDeclaration, isIndexedAccessTypeNode, isInterfaceDeclaration, isIntersectionTypeNode, isJSDocParameterTag, isJSDocPropertyTag, isJSDocReturnTag, isJSDocThisTag, isJSDocTypeTag, isLiteralTypeNode, isMappedTypeNode, isMethodDeclaration, isMethodSignature, isModuleBlock, isModuleDeclaration, isNamedTupleMember, isNoSubstitutionTemplateLiteral, isNumericLiteral, isObjectLiteralExpression, isParameter, isParenthesizedTypeNode, isPrefixUnaryExpression, isPropertyAccessExpression, isPropertyDeclaration, isPropertySignature, isQualifiedName, isStringLiteral, isTupleTypeNode, isTypeAliasDeclaration, isTypeLiteralNode, isTypeOperatorNode, isTypeReferenceNode, isUnionTypeNode } from "typescript";
|
|
3
|
+
import path, { normalize } from "node:path";
|
|
4
|
+
import { CollectionFormat, NumericKind, ParamKind, ParameterSource, TypeName, UtilityTypeName, ValidatorName, createRegistry, isArrayType, isDeprecatedMarker, isExtensionMarker, isNestedObjectLiteralType, isRefAliasType, isRefEnumType, isRefObjectType, isStringType, isUnionType, isVoidType, loadRegistry, loadRegistryByName, matches, matchesJsDoc, mergeRegistries, namesForMarker, newControllerDraft, newMethodDraft, newParameterDraft, numericMarkerKind, resolvePresetByName, tagsForMarker } from "@trapi/core";
|
|
5
|
+
import { buildFilePath, isObject, load, locateMany } from "locter";
|
|
9
6
|
import process from "node:process";
|
|
10
7
|
import { parse, stringify } from "flatted";
|
|
11
8
|
import crypto from "node:crypto";
|
|
12
9
|
import fs from "node:fs";
|
|
13
10
|
import { tmpdir } from "node:os";
|
|
14
11
|
import { minimatch } from "minimatch";
|
|
15
|
-
//#region src/core/resolver/constants.ts
|
|
16
|
-
let TypeName = /* @__PURE__ */ function(TypeName) {
|
|
17
|
-
TypeName["STRING"] = "string";
|
|
18
|
-
TypeName["BOOLEAN"] = "boolean";
|
|
19
|
-
TypeName["BIGINT"] = "bigint";
|
|
20
|
-
TypeName["DOUBLE"] = "double";
|
|
21
|
-
TypeName["FLOAT"] = "float";
|
|
22
|
-
TypeName["FILE"] = "file";
|
|
23
|
-
TypeName["INTEGER"] = "integer";
|
|
24
|
-
TypeName["LONG"] = "long";
|
|
25
|
-
TypeName["ENUM"] = "enum";
|
|
26
|
-
TypeName["ARRAY"] = "array";
|
|
27
|
-
TypeName["DATETIME"] = "datetime";
|
|
28
|
-
TypeName["DATE"] = "date";
|
|
29
|
-
TypeName["BINARY"] = "binary";
|
|
30
|
-
TypeName["BUFFER"] = "buffer";
|
|
31
|
-
TypeName["BYTE"] = "byte";
|
|
32
|
-
TypeName["VOID"] = "void";
|
|
33
|
-
TypeName["OBJECT"] = "object";
|
|
34
|
-
TypeName["ANY"] = "any";
|
|
35
|
-
TypeName["UNDEFINED"] = "undefined";
|
|
36
|
-
TypeName["NEVER"] = "never";
|
|
37
|
-
TypeName["REF_ENUM"] = "refEnum";
|
|
38
|
-
TypeName["REF_OBJECT"] = "refObject";
|
|
39
|
-
TypeName["REF_ALIAS"] = "refAlias";
|
|
40
|
-
TypeName["NESTED_OBJECT_LITERAL"] = "nestedObjectLiteral";
|
|
41
|
-
TypeName["UNION"] = "union";
|
|
42
|
-
TypeName["INTERSECTION"] = "intersection";
|
|
43
|
-
TypeName["TUPLE"] = "tuple";
|
|
44
|
-
return TypeName;
|
|
45
|
-
}({});
|
|
46
|
-
let UtilityTypeName = /* @__PURE__ */ function(UtilityTypeName) {
|
|
47
|
-
UtilityTypeName["NON_NULLABLE"] = "NonNullable";
|
|
48
|
-
UtilityTypeName["OMIT"] = "Omit";
|
|
49
|
-
UtilityTypeName["PARTIAL"] = "Partial";
|
|
50
|
-
UtilityTypeName["READONLY"] = "Readonly";
|
|
51
|
-
UtilityTypeName["RECORD"] = "Record";
|
|
52
|
-
UtilityTypeName["REQUIRED"] = "Required";
|
|
53
|
-
UtilityTypeName["PICK"] = "Pick";
|
|
54
|
-
UtilityTypeName["EXTRACT"] = "Extract";
|
|
55
|
-
UtilityTypeName["EXCLUDE"] = "Exclude";
|
|
56
|
-
UtilityTypeName["RETURN_TYPE"] = "ReturnType";
|
|
57
|
-
UtilityTypeName["PARAMETERS"] = "Parameters";
|
|
58
|
-
UtilityTypeName["AWAITED"] = "Awaited";
|
|
59
|
-
UtilityTypeName["INSTANCE_TYPE"] = "InstanceType";
|
|
60
|
-
UtilityTypeName["CONSTRUCTOR_PARAMETERS"] = "ConstructorParameters";
|
|
61
|
-
return UtilityTypeName;
|
|
62
|
-
}({});
|
|
63
|
-
//#endregion
|
|
64
|
-
//#region src/core/resolver/type-guards.ts
|
|
65
|
-
function isAnyType(param) {
|
|
66
|
-
return param.typeName === "any";
|
|
67
|
-
}
|
|
68
|
-
function isUndefinedType(param) {
|
|
69
|
-
return param.typeName === "undefined";
|
|
70
|
-
}
|
|
71
|
-
function isStringType(param) {
|
|
72
|
-
return param.typeName === "string";
|
|
73
|
-
}
|
|
74
|
-
function isBooleanType(param) {
|
|
75
|
-
return param.typeName === "boolean";
|
|
76
|
-
}
|
|
77
|
-
function isBigintType(param) {
|
|
78
|
-
return param.typeName === "bigint";
|
|
79
|
-
}
|
|
80
|
-
function isDoubleType(param) {
|
|
81
|
-
return param.typeName === "double";
|
|
82
|
-
}
|
|
83
|
-
function isFloatType(param) {
|
|
84
|
-
return param.typeName === "float";
|
|
85
|
-
}
|
|
86
|
-
function isIntegerType(param) {
|
|
87
|
-
return param.typeName === "integer";
|
|
88
|
-
}
|
|
89
|
-
function isLongType(param) {
|
|
90
|
-
return param.typeName === "long";
|
|
91
|
-
}
|
|
92
|
-
function isVoidType(param) {
|
|
93
|
-
return typeof param === "undefined" || param.typeName === "void";
|
|
94
|
-
}
|
|
95
|
-
function isNeverType(param) {
|
|
96
|
-
return param.typeName === "never";
|
|
97
|
-
}
|
|
98
|
-
function isDateType(param) {
|
|
99
|
-
return param.typeName === "date";
|
|
100
|
-
}
|
|
101
|
-
function isFileType(param) {
|
|
102
|
-
return param.typeName === "file";
|
|
103
|
-
}
|
|
104
|
-
function isDateTimeType(param) {
|
|
105
|
-
return param.typeName === "datetime";
|
|
106
|
-
}
|
|
107
|
-
function isBinaryType(param) {
|
|
108
|
-
return param.typeName === "binary";
|
|
109
|
-
}
|
|
110
|
-
function isBufferType(param) {
|
|
111
|
-
return param.typeName === "buffer";
|
|
112
|
-
}
|
|
113
|
-
function isByteType(param) {
|
|
114
|
-
return param.typeName === "byte";
|
|
115
|
-
}
|
|
116
|
-
function isObjectType(param) {
|
|
117
|
-
return param.typeName === "object";
|
|
118
|
-
}
|
|
119
|
-
function isEnumType(param) {
|
|
120
|
-
return param.typeName === "enum";
|
|
121
|
-
}
|
|
122
|
-
function isArrayType(param) {
|
|
123
|
-
return param.typeName === "array";
|
|
124
|
-
}
|
|
125
|
-
function isNestedObjectLiteralType(param) {
|
|
126
|
-
return param.typeName === "nestedObjectLiteral";
|
|
127
|
-
}
|
|
128
|
-
function isIntersectionType(param) {
|
|
129
|
-
return param.typeName === "intersection";
|
|
130
|
-
}
|
|
131
|
-
function isUnionType(param) {
|
|
132
|
-
return param.typeName === "union";
|
|
133
|
-
}
|
|
134
|
-
function isTupleType(param) {
|
|
135
|
-
return param.typeName === "tuple";
|
|
136
|
-
}
|
|
137
|
-
function isRefEnumType(param) {
|
|
138
|
-
return param.typeName === "refEnum";
|
|
139
|
-
}
|
|
140
|
-
function isRefObjectType(param) {
|
|
141
|
-
return param.typeName === "refObject";
|
|
142
|
-
}
|
|
143
|
-
function isRefAliasType(param) {
|
|
144
|
-
return param.typeName === "refAlias";
|
|
145
|
-
}
|
|
146
|
-
function isReferenceType(param) {
|
|
147
|
-
return param.typeName === "refAlias" || param.typeName === "refEnum" || param.typeName === "refObject";
|
|
148
|
-
}
|
|
149
|
-
function isPrimitiveType(type) {
|
|
150
|
-
return isAnyType(type) || isBinaryType(type) || isBooleanType(type) || isBufferType(type) || isByteType(type) || isDateType(type) || isDateTimeType(type) || isBigintType(type) || isDoubleType(type) || isFloatType(type) || isFileType(type) || isIntegerType(type) || isLongType(type) || isObjectType(type) || isStringType(type) || isUndefinedType(type);
|
|
151
|
-
}
|
|
152
|
-
//#endregion
|
|
153
12
|
//#region src/core/error/base.ts
|
|
154
13
|
var MetadataError = class extends BaseError {};
|
|
155
14
|
//#endregion
|
|
156
|
-
//#region src/core/
|
|
157
|
-
var
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
let file;
|
|
165
|
-
let line;
|
|
166
|
-
if (node) {
|
|
167
|
-
const location = prettyLocationOfNode(node);
|
|
168
|
-
if (location) {
|
|
169
|
-
parts.push(location.text);
|
|
170
|
-
file = location.file;
|
|
171
|
-
line = location.line;
|
|
172
|
-
}
|
|
173
|
-
parts.push(prettyTroubleCause(node, onlyCurrent));
|
|
174
|
-
}
|
|
175
|
-
super({
|
|
176
|
-
message: parts.join("\n"),
|
|
177
|
-
cause: opts?.cause
|
|
178
|
-
});
|
|
179
|
-
this.file = file;
|
|
180
|
-
this.line = line;
|
|
181
|
-
}
|
|
15
|
+
//#region src/core/error/config.ts
|
|
16
|
+
var ConfigError = class extends MetadataError {};
|
|
17
|
+
//#endregion
|
|
18
|
+
//#region src/core/error/config-codes.ts
|
|
19
|
+
const ConfigErrorCode = {
|
|
20
|
+
TSCONFIG_MALFORMED: "CONFIG_TSCONFIG_MALFORMED",
|
|
21
|
+
PRESET_NOT_FOUND: "CONFIG_PRESET_NOT_FOUND",
|
|
22
|
+
PRESET_MISSING: "CONFIG_PRESET_MISSING"
|
|
182
23
|
};
|
|
183
|
-
|
|
24
|
+
//#endregion
|
|
25
|
+
//#region src/core/error/generator.ts
|
|
26
|
+
var GeneratorError = class extends MetadataError {};
|
|
27
|
+
function isGeneratorError(input) {
|
|
184
28
|
if (!isBaseError(input)) return false;
|
|
185
|
-
return
|
|
186
|
-
}
|
|
187
|
-
function prettyLocationOfNode(node) {
|
|
188
|
-
try {
|
|
189
|
-
const sourceFile = node.getSourceFile();
|
|
190
|
-
if (!sourceFile) return void 0;
|
|
191
|
-
const token = node.getFirstToken() || node.parent?.getFirstToken();
|
|
192
|
-
const start = token ? sourceFile.getLineAndCharacterOfPosition(token.getStart()).line + 1 : void 0;
|
|
193
|
-
const end = token ? sourceFile.getLineAndCharacterOfPosition(token.getEnd()).line + 1 : void 0;
|
|
194
|
-
return {
|
|
195
|
-
text: `At: ${normalize(sourceFile.fileName)}${start ? `:${start}` : ""}${end ? `:${end}` : ""}.`,
|
|
196
|
-
file: sourceFile.fileName,
|
|
197
|
-
line: start
|
|
198
|
-
};
|
|
199
|
-
} catch {
|
|
200
|
-
return;
|
|
201
|
-
}
|
|
202
|
-
}
|
|
203
|
-
function prettyTroubleCause(node, onlyCurrent = false) {
|
|
204
|
-
try {
|
|
205
|
-
let name;
|
|
206
|
-
if (onlyCurrent || !node.parent) name = node.pos !== -1 ? node.getText() : node.name.text;
|
|
207
|
-
else name = node.parent.pos !== -1 ? node.parent.getText() : node.parent.name.text;
|
|
208
|
-
return `This was caused by '${name}'`;
|
|
209
|
-
} catch {
|
|
210
|
-
return "This was caused by an unknown node";
|
|
211
|
-
}
|
|
29
|
+
return typeof input.code === "string";
|
|
212
30
|
}
|
|
213
31
|
//#endregion
|
|
214
|
-
//#region src/core/
|
|
215
|
-
const
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
OPTIONS: "OPTIONS",
|
|
223
|
-
HEAD: "HEAD"
|
|
32
|
+
//#region src/core/error/generator-codes.ts
|
|
33
|
+
const GeneratorErrorCode = {
|
|
34
|
+
CONTROLLER_NO_SOURCE_FILE: "GENERATOR_CONTROLLER_NO_SOURCE_FILE",
|
|
35
|
+
CONTROLLER_NO_NAME: "GENERATOR_CONTROLLER_NO_NAME",
|
|
36
|
+
PARAMETER_GENERATION_FAILED: "GENERATOR_PARAMETER_GENERATION_FAILED",
|
|
37
|
+
BODY_PARAMETER_DUPLICATE: "GENERATOR_BODY_PARAMETER_DUPLICATE",
|
|
38
|
+
BODY_FORM_CONFLICT: "GENERATOR_BODY_FORM_CONFLICT",
|
|
39
|
+
STRICT_UNMATCHED_DECORATORS: "GENERATOR_STRICT_UNMATCHED_DECORATORS"
|
|
224
40
|
};
|
|
225
41
|
//#endregion
|
|
226
|
-
//#region src/core/parameter
|
|
227
|
-
const ParameterSource = {
|
|
228
|
-
BODY: "body",
|
|
229
|
-
BODY_PROP: "bodyProp",
|
|
230
|
-
CONTEXT: "context",
|
|
231
|
-
COOKIE: "cookie",
|
|
232
|
-
HEADER: "header",
|
|
233
|
-
FORM_DATA: "formData",
|
|
234
|
-
QUERY: "query",
|
|
235
|
-
QUERY_PROP: "queryProp",
|
|
236
|
-
PATH: "path"
|
|
237
|
-
};
|
|
238
|
-
const CollectionFormat = {
|
|
239
|
-
CSV: "csv",
|
|
240
|
-
SSV: "ssv",
|
|
241
|
-
TSV: "tsv",
|
|
242
|
-
PIPES: "pipes",
|
|
243
|
-
MULTI: "multi"
|
|
244
|
-
};
|
|
42
|
+
//#region src/core/error/parameter-codes.ts
|
|
245
43
|
const ParameterErrorCode = {
|
|
246
44
|
TYPE_UNSUPPORTED: "PARAMETER_TYPE_UNSUPPORTED",
|
|
247
45
|
METHOD_UNSUPPORTED: "PARAMETER_METHOD_UNSUPPORTED",
|
|
@@ -250,7 +48,7 @@ const ParameterErrorCode = {
|
|
|
250
48
|
INVALID_EXAMPLE: "PARAMETER_INVALID_EXAMPLE"
|
|
251
49
|
};
|
|
252
50
|
//#endregion
|
|
253
|
-
//#region src/core/parameter
|
|
51
|
+
//#region src/core/error/parameter.ts
|
|
254
52
|
var ParameterError = class ParameterError extends MetadataError {
|
|
255
53
|
static typeUnsupported(context) {
|
|
256
54
|
const location = context.node ? ParameterError.getCurrentLocation(context.node) : void 0;
|
|
@@ -296,686 +94,74 @@ var ParameterError = class ParameterError extends MetadataError {
|
|
|
296
94
|
}
|
|
297
95
|
};
|
|
298
96
|
//#endregion
|
|
299
|
-
//#region src/core/
|
|
300
|
-
var
|
|
301
|
-
|
|
97
|
+
//#region src/core/error/resolver.ts
|
|
98
|
+
var ResolverError = class extends MetadataError {
|
|
99
|
+
file;
|
|
100
|
+
line;
|
|
101
|
+
constructor(message, node, options) {
|
|
102
|
+
const opts = typeof options === "boolean" ? { onlyCurrent: options } : options;
|
|
103
|
+
const onlyCurrent = opts?.onlyCurrent ?? false;
|
|
104
|
+
const parts = [message];
|
|
105
|
+
let file;
|
|
106
|
+
let line;
|
|
107
|
+
if (node) {
|
|
108
|
+
const location = prettyLocationOfNode(node);
|
|
109
|
+
if (location) {
|
|
110
|
+
parts.push(location.text);
|
|
111
|
+
file = location.file;
|
|
112
|
+
line = location.line;
|
|
113
|
+
}
|
|
114
|
+
parts.push(prettyTroubleCause(node, onlyCurrent));
|
|
115
|
+
}
|
|
116
|
+
super({
|
|
117
|
+
message: parts.join("\n"),
|
|
118
|
+
cause: opts?.cause
|
|
119
|
+
});
|
|
120
|
+
this.file = file;
|
|
121
|
+
this.line = line;
|
|
122
|
+
}
|
|
123
|
+
};
|
|
124
|
+
function isResolverError(input) {
|
|
302
125
|
if (!isBaseError(input)) return false;
|
|
303
|
-
return
|
|
126
|
+
return "file" in input && "line" in input;
|
|
127
|
+
}
|
|
128
|
+
function prettyLocationOfNode(node) {
|
|
129
|
+
try {
|
|
130
|
+
const sourceFile = node.getSourceFile();
|
|
131
|
+
if (!sourceFile) return void 0;
|
|
132
|
+
const token = node.getFirstToken() || node.parent?.getFirstToken();
|
|
133
|
+
const start = token ? sourceFile.getLineAndCharacterOfPosition(token.getStart()).line + 1 : void 0;
|
|
134
|
+
const end = token ? sourceFile.getLineAndCharacterOfPosition(token.getEnd()).line + 1 : void 0;
|
|
135
|
+
return {
|
|
136
|
+
text: `At: ${normalize(sourceFile.fileName)}${start ? `:${start}` : ""}${end ? `:${end}` : ""}.`,
|
|
137
|
+
file: sourceFile.fileName,
|
|
138
|
+
line: start
|
|
139
|
+
};
|
|
140
|
+
} catch {
|
|
141
|
+
return;
|
|
142
|
+
}
|
|
143
|
+
}
|
|
144
|
+
function prettyTroubleCause(node, onlyCurrent = false) {
|
|
145
|
+
try {
|
|
146
|
+
let name;
|
|
147
|
+
if (onlyCurrent || !node.parent) name = node.pos !== -1 ? node.getText() : node.name.text;
|
|
148
|
+
else name = node.parent.pos !== -1 ? node.parent.getText() : node.parent.name.text;
|
|
149
|
+
return `This was caused by '${name}'`;
|
|
150
|
+
} catch {
|
|
151
|
+
return "This was caused by an unknown node";
|
|
152
|
+
}
|
|
304
153
|
}
|
|
305
154
|
//#endregion
|
|
306
|
-
//#region src/core/
|
|
307
|
-
const GeneratorErrorCode = {
|
|
308
|
-
CONTROLLER_NO_SOURCE_FILE: "GENERATOR_CONTROLLER_NO_SOURCE_FILE",
|
|
309
|
-
CONTROLLER_NO_NAME: "GENERATOR_CONTROLLER_NO_NAME",
|
|
310
|
-
PARAMETER_GENERATION_FAILED: "GENERATOR_PARAMETER_GENERATION_FAILED",
|
|
311
|
-
BODY_PARAMETER_DUPLICATE: "GENERATOR_BODY_PARAMETER_DUPLICATE",
|
|
312
|
-
BODY_FORM_CONFLICT: "GENERATOR_BODY_FORM_CONFLICT"
|
|
313
|
-
};
|
|
314
|
-
//#endregion
|
|
315
|
-
//#region src/core/validator/error.ts
|
|
155
|
+
//#region src/core/error/validator.ts
|
|
316
156
|
var ValidatorError = class extends MetadataError {};
|
|
317
157
|
//#endregion
|
|
318
|
-
//#region src/core/validator
|
|
319
|
-
let ValidatorName = /* @__PURE__ */ function(ValidatorName) {
|
|
320
|
-
ValidatorName["UNIQUE_ITEMS"] = "uniqueItems";
|
|
321
|
-
ValidatorName["MINIMUM"] = "minimum";
|
|
322
|
-
ValidatorName["MAXIMUM"] = "maximum";
|
|
323
|
-
ValidatorName["MIN_ITEMS"] = "minItems";
|
|
324
|
-
ValidatorName["MAX_ITEMS"] = "maxItems";
|
|
325
|
-
ValidatorName["MIN_LENGTH"] = "minLength";
|
|
326
|
-
ValidatorName["MAX_LENGTH"] = "maxLength";
|
|
327
|
-
ValidatorName["MIN_DATE"] = "minDate";
|
|
328
|
-
ValidatorName["MAX_DATE"] = "maxDate";
|
|
329
|
-
ValidatorName["PATTERN"] = "pattern";
|
|
330
|
-
return ValidatorName;
|
|
331
|
-
}({});
|
|
158
|
+
//#region src/core/error/validator-codes.ts
|
|
332
159
|
const ValidatorErrorCode = {
|
|
333
160
|
EXPECTED_NUMBER: "VALIDATOR_EXPECTED_NUMBER",
|
|
334
161
|
EXPECTED_DATE: "VALIDATOR_EXPECTED_DATE",
|
|
335
162
|
EXPECTED_STRING: "VALIDATOR_EXPECTED_STRING"
|
|
336
163
|
};
|
|
337
164
|
//#endregion
|
|
338
|
-
//#region src/core/error/config.ts
|
|
339
|
-
var ConfigError = class extends MetadataError {};
|
|
340
|
-
//#endregion
|
|
341
|
-
//#region src/core/error/config-codes.ts
|
|
342
|
-
const ConfigErrorCode = {
|
|
343
|
-
TSCONFIG_MALFORMED: "CONFIG_TSCONFIG_MALFORMED",
|
|
344
|
-
PRESET_NOT_FOUND: "CONFIG_PRESET_NOT_FOUND",
|
|
345
|
-
PRESET_MISSING: "CONFIG_PRESET_MISSING"
|
|
346
|
-
};
|
|
347
|
-
//#endregion
|
|
348
|
-
//#region src/adapters/decorator/constants.ts
|
|
349
|
-
const ParamKind = {
|
|
350
|
-
Body: "body",
|
|
351
|
-
BodyProp: "bodyProp",
|
|
352
|
-
Context: "context",
|
|
353
|
-
Cookie: "cookie",
|
|
354
|
-
Header: "header",
|
|
355
|
-
FormData: "formData",
|
|
356
|
-
Query: "query",
|
|
357
|
-
QueryProp: "queryProp",
|
|
358
|
-
Path: "path"
|
|
359
|
-
};
|
|
360
|
-
const CollectionKind = {
|
|
361
|
-
Csv: "csv",
|
|
362
|
-
Ssv: "ssv",
|
|
363
|
-
Tsv: "tsv",
|
|
364
|
-
Pipes: "pipes",
|
|
365
|
-
Multi: "multi"
|
|
366
|
-
};
|
|
367
|
-
const DecoratorTargetKind = {
|
|
368
|
-
Class: "class",
|
|
369
|
-
Method: "method",
|
|
370
|
-
Parameter: "parameter",
|
|
371
|
-
Property: "property"
|
|
372
|
-
};
|
|
373
|
-
const DecoratorArgumentKindName = {
|
|
374
|
-
Literal: "literal",
|
|
375
|
-
Object: "object",
|
|
376
|
-
Array: "array",
|
|
377
|
-
Identifier: "identifier",
|
|
378
|
-
Unresolvable: "unresolvable"
|
|
379
|
-
};
|
|
380
|
-
const MarkerName = {
|
|
381
|
-
Hidden: "hidden",
|
|
382
|
-
Deprecated: "deprecated",
|
|
383
|
-
Extension: "extension"
|
|
384
|
-
};
|
|
385
|
-
const NumericKind = {
|
|
386
|
-
Int: "int",
|
|
387
|
-
Long: "long",
|
|
388
|
-
Float: "float",
|
|
389
|
-
Double: "double"
|
|
390
|
-
};
|
|
391
|
-
//#endregion
|
|
392
|
-
//#region src/adapters/decorator/helpers.ts
|
|
393
|
-
/**
|
|
394
|
-
* Read a positional argument as a string. Accepts both literal string args
|
|
395
|
-
* (`@Foo('value')`) and identifier references that resolve to a string
|
|
396
|
-
* (`@Foo(SOME_CONSTANT)`). Returns `undefined` for any other argument shape.
|
|
397
|
-
*/
|
|
398
|
-
function readString(arg) {
|
|
399
|
-
if (!arg) return void 0;
|
|
400
|
-
if (arg.kind === "literal" && typeof arg.raw === "string") return arg.raw;
|
|
401
|
-
if (arg.kind === "identifier" && typeof arg.raw === "string") return arg.raw;
|
|
402
|
-
}
|
|
403
|
-
/**
|
|
404
|
-
* Read a positional argument as a number. Only matches numeric literals.
|
|
405
|
-
*/
|
|
406
|
-
function readNumber(arg) {
|
|
407
|
-
if (!arg) return void 0;
|
|
408
|
-
if (arg.kind === "literal" && typeof arg.raw === "number") return arg.raw;
|
|
409
|
-
}
|
|
410
|
-
/**
|
|
411
|
-
* Read a positional argument as a boolean. Only matches boolean literals.
|
|
412
|
-
*/
|
|
413
|
-
function readBoolean(arg) {
|
|
414
|
-
if (!arg) return void 0;
|
|
415
|
-
if (arg.kind === "literal" && typeof arg.raw === "boolean") return arg.raw;
|
|
416
|
-
}
|
|
417
|
-
/**
|
|
418
|
-
* Read a positional argument that may be either a single string or an array
|
|
419
|
-
* of strings. Returns `undefined` when the argument is missing, when any
|
|
420
|
-
* array element is non-string, or otherwise unresolvable. All-or-nothing:
|
|
421
|
-
* never returns a partial array with non-string items silently dropped.
|
|
422
|
-
*/
|
|
423
|
-
function readStringOrStringArray(arg) {
|
|
424
|
-
const single = readString(arg);
|
|
425
|
-
if (single !== void 0) return [single];
|
|
426
|
-
if (arg?.kind === "array" && Array.isArray(arg.raw)) {
|
|
427
|
-
if (arg.raw.every((item) => typeof item === "string")) return arg.raw;
|
|
428
|
-
return;
|
|
429
|
-
}
|
|
430
|
-
}
|
|
431
|
-
/**
|
|
432
|
-
* Convenience for the common controller path assignment. Reads the first
|
|
433
|
-
* argument as a string-or-string-array and writes it to `draft.paths`,
|
|
434
|
-
* defaulting to `['']` when the argument is missing or unresolvable. Use this
|
|
435
|
-
* inside a `controller({ match, apply })` handler to declare a class as a
|
|
436
|
-
* controller.
|
|
437
|
-
*/
|
|
438
|
-
function setControllerPaths(draft, arg) {
|
|
439
|
-
draft.paths = readStringOrStringArray(arg) ?? [""];
|
|
440
|
-
}
|
|
441
|
-
/**
|
|
442
|
-
* Convenience for the common method path assignment. Reads the first argument
|
|
443
|
-
* as a string and writes it to `draft.path` if present; leaves the field
|
|
444
|
-
* untouched otherwise (the orchestrator initialises it to `''`).
|
|
445
|
-
*/
|
|
446
|
-
function setMethodPath(draft, arg) {
|
|
447
|
-
const path = readString(arg);
|
|
448
|
-
if (path !== void 0) draft.path = path;
|
|
449
|
-
}
|
|
450
|
-
//#endregion
|
|
451
|
-
//#region src/adapters/decorator/utils.ts
|
|
452
|
-
function matches(match, source) {
|
|
453
|
-
if (match.name !== source.name) return false;
|
|
454
|
-
if (match.on && match.on !== source.target) return false;
|
|
455
|
-
return true;
|
|
456
|
-
}
|
|
457
|
-
function matchesJsDoc(match, source) {
|
|
458
|
-
if (match.tag !== source.tag) return false;
|
|
459
|
-
if (match.on && match.on !== source.target) return false;
|
|
460
|
-
return true;
|
|
461
|
-
}
|
|
462
|
-
function newControllerDraft(input) {
|
|
463
|
-
return {
|
|
464
|
-
name: input.name,
|
|
465
|
-
location: input.location,
|
|
466
|
-
hidden: false,
|
|
467
|
-
consumes: [],
|
|
468
|
-
produces: [],
|
|
469
|
-
tags: [],
|
|
470
|
-
responses: [],
|
|
471
|
-
security: [],
|
|
472
|
-
extensions: []
|
|
473
|
-
};
|
|
474
|
-
}
|
|
475
|
-
function newMethodDraft(input) {
|
|
476
|
-
return {
|
|
477
|
-
name: input.name,
|
|
478
|
-
path: "",
|
|
479
|
-
description: "",
|
|
480
|
-
hidden: false,
|
|
481
|
-
consumes: [],
|
|
482
|
-
produces: [],
|
|
483
|
-
tags: [],
|
|
484
|
-
responses: [],
|
|
485
|
-
security: [],
|
|
486
|
-
extensions: [],
|
|
487
|
-
parameters: [],
|
|
488
|
-
defaultResponseExamples: []
|
|
489
|
-
};
|
|
490
|
-
}
|
|
491
|
-
function newParameterDraft(input) {
|
|
492
|
-
return {
|
|
493
|
-
parameterName: input.parameterName,
|
|
494
|
-
name: input.parameterName,
|
|
495
|
-
description: "",
|
|
496
|
-
required: true,
|
|
497
|
-
examples: [],
|
|
498
|
-
exampleLabels: [],
|
|
499
|
-
extensions: [],
|
|
500
|
-
validators: {}
|
|
501
|
-
};
|
|
502
|
-
}
|
|
503
|
-
/**
|
|
504
|
-
* Build a {@link Registry}, optionally seeded with handler arrays from `input`.
|
|
505
|
-
* Any kind omitted from `input` falls back to an empty array, so callers can
|
|
506
|
-
* pass just the kinds they care about (e.g. `createRegistry({ methods: [...] })`).
|
|
507
|
-
*
|
|
508
|
-
* The provided arrays are copied — mutating the result does not affect `input`.
|
|
509
|
-
*/
|
|
510
|
-
function createRegistry(input = {}) {
|
|
511
|
-
return {
|
|
512
|
-
controllers: input.controllers ? [...input.controllers] : [],
|
|
513
|
-
methods: input.methods ? [...input.methods] : [],
|
|
514
|
-
parameters: input.parameters ? [...input.parameters] : [],
|
|
515
|
-
controllerJsDoc: input.controllerJsDoc ? [...input.controllerJsDoc] : [],
|
|
516
|
-
methodJsDoc: input.methodJsDoc ? [...input.methodJsDoc] : [],
|
|
517
|
-
parameterJsDoc: input.parameterJsDoc ? [...input.parameterJsDoc] : []
|
|
518
|
-
};
|
|
519
|
-
}
|
|
520
|
-
/**
|
|
521
|
-
* Concatenate two registries kind-by-kind. Earlier handlers run first inside
|
|
522
|
-
* the orchestrator, so callers who want override-by-running-later semantics
|
|
523
|
-
* should pass the dominant registry as `b`.
|
|
524
|
-
*/
|
|
525
|
-
function mergeRegistries(a, b) {
|
|
526
|
-
return {
|
|
527
|
-
controllers: [...a.controllers, ...b.controllers],
|
|
528
|
-
methods: [...a.methods, ...b.methods],
|
|
529
|
-
parameters: [...a.parameters, ...b.parameters],
|
|
530
|
-
controllerJsDoc: [...a.controllerJsDoc, ...b.controllerJsDoc],
|
|
531
|
-
methodJsDoc: [...a.methodJsDoc, ...b.methodJsDoc],
|
|
532
|
-
parameterJsDoc: [...a.parameterJsDoc, ...b.parameterJsDoc]
|
|
533
|
-
};
|
|
534
|
-
}
|
|
535
|
-
function generatePresetLookupPaths(input) {
|
|
536
|
-
if (path.isAbsolute(input) || input.startsWith("./") || input.startsWith("../")) return [input];
|
|
537
|
-
if (input.startsWith("module:")) return [input.substring(7)];
|
|
538
|
-
if (!input.startsWith("@")) return [input, `@trapi/${input}`];
|
|
539
|
-
return [input];
|
|
540
|
-
}
|
|
541
|
-
/**
|
|
542
|
-
* Collect the unique decorator names of every handler whose `marker` matches
|
|
543
|
-
* the given predicate. Lets the type resolver discover preset-renamed
|
|
544
|
-
* decorators without hard-coding canonical names.
|
|
545
|
-
*/
|
|
546
|
-
function namesForMarker(registry, predicate) {
|
|
547
|
-
const names = /* @__PURE__ */ new Set();
|
|
548
|
-
const all = [
|
|
549
|
-
...registry.controllers,
|
|
550
|
-
...registry.methods,
|
|
551
|
-
...registry.parameters
|
|
552
|
-
];
|
|
553
|
-
for (const handler of all) if (handler.marker !== void 0 && predicate(handler.marker)) names.add(handler.match.name);
|
|
554
|
-
return names;
|
|
555
|
-
}
|
|
556
|
-
/**
|
|
557
|
-
* Collect the unique JSDoc tag names of every JSDoc handler whose `marker`
|
|
558
|
-
* matches the given predicate. JSDoc analogue of `namesForMarker`.
|
|
559
|
-
*/
|
|
560
|
-
function tagsForMarker(registry, predicate) {
|
|
561
|
-
const tags = /* @__PURE__ */ new Set();
|
|
562
|
-
const all = [
|
|
563
|
-
...registry.controllerJsDoc,
|
|
564
|
-
...registry.methodJsDoc,
|
|
565
|
-
...registry.parameterJsDoc
|
|
566
|
-
];
|
|
567
|
-
for (const handler of all) if (handler.marker !== void 0 && predicate(handler.marker)) tags.add(handler.match.tag);
|
|
568
|
-
return tags;
|
|
569
|
-
}
|
|
570
|
-
function isHiddenMarker(marker) {
|
|
571
|
-
return marker === "hidden";
|
|
572
|
-
}
|
|
573
|
-
function isDeprecatedMarker(marker) {
|
|
574
|
-
return marker === "deprecated";
|
|
575
|
-
}
|
|
576
|
-
function isExtensionMarker(marker) {
|
|
577
|
-
return marker === "extension";
|
|
578
|
-
}
|
|
579
|
-
function numericMarkerKind(marker) {
|
|
580
|
-
if (typeof marker === "object" && marker !== null && "numeric" in marker) return marker.numeric;
|
|
581
|
-
}
|
|
582
|
-
const controller = (handler) => handler;
|
|
583
|
-
const method = (handler) => handler;
|
|
584
|
-
const parameter = (handler) => handler;
|
|
585
|
-
const controllerJsDoc = (handler) => handler;
|
|
586
|
-
const methodJsDoc = (handler) => handler;
|
|
587
|
-
const parameterJsDoc = (handler) => handler;
|
|
588
|
-
function isLiteralLike(kind) {
|
|
589
|
-
return kind === "literal" || kind === "identifier";
|
|
590
|
-
}
|
|
591
|
-
function readArray(draft, key) {
|
|
592
|
-
const record = draft;
|
|
593
|
-
const existing = record[key];
|
|
594
|
-
if (Array.isArray(existing)) return existing;
|
|
595
|
-
if (typeof existing !== "undefined") throw new TypeError(`append(): cannot append to draft key "${key}": existing value is not an array (got ${typeof existing}).`);
|
|
596
|
-
const created = [];
|
|
597
|
-
record[key] = created;
|
|
598
|
-
return created;
|
|
599
|
-
}
|
|
600
|
-
function into(key) {
|
|
601
|
-
return {
|
|
602
|
-
positional(index) {
|
|
603
|
-
return (ctx, draft) => {
|
|
604
|
-
const arg = ctx.argument(index);
|
|
605
|
-
if (arg && isLiteralLike(arg.kind)) draft[key] = arg.raw;
|
|
606
|
-
};
|
|
607
|
-
},
|
|
608
|
-
typeArgument(index = 0) {
|
|
609
|
-
return (ctx, draft) => {
|
|
610
|
-
const ta = ctx.typeArgument(index);
|
|
611
|
-
if (ta) draft[key] = ta.resolve();
|
|
612
|
-
};
|
|
613
|
-
}
|
|
614
|
-
};
|
|
615
|
-
}
|
|
616
|
-
function append(key) {
|
|
617
|
-
return {
|
|
618
|
-
positional(index) {
|
|
619
|
-
return (ctx, draft) => {
|
|
620
|
-
const arg = ctx.argument(index);
|
|
621
|
-
if (!arg) return;
|
|
622
|
-
const target = readArray(draft, key);
|
|
623
|
-
if (arg.kind === "array" && Array.isArray(arg.raw)) target.push(...arg.raw);
|
|
624
|
-
else if (isLiteralLike(arg.kind)) target.push(arg.raw);
|
|
625
|
-
};
|
|
626
|
-
},
|
|
627
|
-
positionalAll() {
|
|
628
|
-
return (ctx, draft) => {
|
|
629
|
-
const target = readArray(draft, key);
|
|
630
|
-
for (const arg of ctx.arguments()) if (arg.kind === "array" && Array.isArray(arg.raw)) target.push(...arg.raw);
|
|
631
|
-
else if (isLiteralLike(arg.kind)) target.push(arg.raw);
|
|
632
|
-
};
|
|
633
|
-
}
|
|
634
|
-
};
|
|
635
|
-
}
|
|
636
|
-
function flag(key, value = true) {
|
|
637
|
-
return (_ctx, draft) => {
|
|
638
|
-
draft[key] = value;
|
|
639
|
-
};
|
|
640
|
-
}
|
|
641
|
-
//#endregion
|
|
642
|
-
//#region src/adapters/decorator/validation/module.ts
|
|
643
|
-
const decoratorTargetSchema = z.enum([
|
|
644
|
-
"class",
|
|
645
|
-
"method",
|
|
646
|
-
"parameter",
|
|
647
|
-
"property"
|
|
648
|
-
]);
|
|
649
|
-
const replacesPolicySchema = z.union([z.literal(true), z.string().min(1)]);
|
|
650
|
-
function matchSchemaForKind(allowedOn) {
|
|
651
|
-
return z.object({
|
|
652
|
-
name: z.string().min(1),
|
|
653
|
-
on: decoratorTargetSchema.optional()
|
|
654
|
-
}).refine((m) => m.on === void 0 || m.on === allowedOn, {
|
|
655
|
-
message: `match.on is incompatible with the handler array it lives in — expected '${allowedOn}' or omit 'on' entirely.`,
|
|
656
|
-
path: ["on"]
|
|
657
|
-
});
|
|
658
|
-
}
|
|
659
|
-
function jsDocMatchSchemaForKind(allowedOn) {
|
|
660
|
-
return z.object({
|
|
661
|
-
tag: z.string().min(1),
|
|
662
|
-
on: decoratorTargetSchema.optional()
|
|
663
|
-
}).refine((m) => m.on === void 0 || m.on === allowedOn, {
|
|
664
|
-
message: `match.on is incompatible with the JSDoc handler array it lives in — expected '${allowedOn}' or omit 'on' entirely.`,
|
|
665
|
-
path: ["on"]
|
|
666
|
-
});
|
|
667
|
-
}
|
|
668
|
-
const matchSchema = z.object({
|
|
669
|
-
name: z.string().min(1),
|
|
670
|
-
on: decoratorTargetSchema.optional()
|
|
671
|
-
});
|
|
672
|
-
const jsDocMatchSchema = z.object({
|
|
673
|
-
tag: z.string().min(1),
|
|
674
|
-
on: decoratorTargetSchema.optional()
|
|
675
|
-
});
|
|
676
|
-
const numericMarkerSchema = z.object({ numeric: z.enum([
|
|
677
|
-
"int",
|
|
678
|
-
"long",
|
|
679
|
-
"float",
|
|
680
|
-
"double"
|
|
681
|
-
]) });
|
|
682
|
-
const resolverMarkerSchema = z.union([
|
|
683
|
-
z.literal("hidden"),
|
|
684
|
-
z.literal("deprecated"),
|
|
685
|
-
z.literal("extension"),
|
|
686
|
-
numericMarkerSchema
|
|
687
|
-
]);
|
|
688
|
-
const handlerBaseShape = {
|
|
689
|
-
replaces: replacesPolicySchema.optional(),
|
|
690
|
-
marker: resolverMarkerSchema.optional(),
|
|
691
|
-
apply: z.custom((value) => typeof value === "function", { message: "apply must be a function" })
|
|
692
|
-
};
|
|
693
|
-
const controllerHandlerSchema = z.object({
|
|
694
|
-
match: matchSchemaForKind("class"),
|
|
695
|
-
...handlerBaseShape
|
|
696
|
-
});
|
|
697
|
-
const methodHandlerSchema = z.object({
|
|
698
|
-
match: matchSchemaForKind("method"),
|
|
699
|
-
...handlerBaseShape
|
|
700
|
-
});
|
|
701
|
-
const parameterHandlerSchema = z.object({
|
|
702
|
-
match: matchSchemaForKind("parameter"),
|
|
703
|
-
...handlerBaseShape
|
|
704
|
-
});
|
|
705
|
-
const controllerJsDocHandlerSchema = z.object({
|
|
706
|
-
match: jsDocMatchSchemaForKind("class"),
|
|
707
|
-
...handlerBaseShape
|
|
708
|
-
});
|
|
709
|
-
const methodJsDocHandlerSchema = z.object({
|
|
710
|
-
match: jsDocMatchSchemaForKind("method"),
|
|
711
|
-
...handlerBaseShape
|
|
712
|
-
});
|
|
713
|
-
const parameterJsDocHandlerSchema = z.object({
|
|
714
|
-
match: jsDocMatchSchemaForKind("parameter"),
|
|
715
|
-
...handlerBaseShape
|
|
716
|
-
});
|
|
717
|
-
const presetSchema = z.object({
|
|
718
|
-
name: z.string().min(1),
|
|
719
|
-
extends: z.array(z.string().min(1)).optional(),
|
|
720
|
-
controllers: z.array(controllerHandlerSchema).optional(),
|
|
721
|
-
methods: z.array(methodHandlerSchema).optional(),
|
|
722
|
-
parameters: z.array(parameterHandlerSchema).optional(),
|
|
723
|
-
controllerJsDoc: z.array(controllerJsDocHandlerSchema).optional(),
|
|
724
|
-
methodJsDoc: z.array(methodJsDocHandlerSchema).optional(),
|
|
725
|
-
parameterJsDoc: z.array(parameterJsDocHandlerSchema).optional()
|
|
726
|
-
});
|
|
727
|
-
function createPresetContainer() {
|
|
728
|
-
const container = new Container();
|
|
729
|
-
container.mount("name", createValidator(presetSchema.shape.name));
|
|
730
|
-
container.mount("extends", { optional: true }, createValidator(presetSchema.shape.extends));
|
|
731
|
-
container.mount("controllers", { optional: true }, createValidator(presetSchema.shape.controllers));
|
|
732
|
-
container.mount("methods", { optional: true }, createValidator(presetSchema.shape.methods));
|
|
733
|
-
container.mount("parameters", { optional: true }, createValidator(presetSchema.shape.parameters));
|
|
734
|
-
container.mount("controllerJsDoc", { optional: true }, createValidator(presetSchema.shape.controllerJsDoc));
|
|
735
|
-
container.mount("methodJsDoc", { optional: true }, createValidator(presetSchema.shape.methodJsDoc));
|
|
736
|
-
container.mount("parameterJsDoc", { optional: true }, createValidator(presetSchema.shape.parameterJsDoc));
|
|
737
|
-
return container;
|
|
738
|
-
}
|
|
739
|
-
const sharedContainer = createPresetContainer();
|
|
740
|
-
async function validatePreset(input) {
|
|
741
|
-
if (input === null || typeof input !== "object" || Array.isArray(input)) throw new TypeError("preset input must be an object");
|
|
742
|
-
return sharedContainer.run(input);
|
|
743
|
-
}
|
|
744
|
-
//#endregion
|
|
745
|
-
//#region src/adapters/decorator/module.ts
|
|
746
|
-
const decoratorKinds = [
|
|
747
|
-
"controllers",
|
|
748
|
-
"methods",
|
|
749
|
-
"parameters"
|
|
750
|
-
];
|
|
751
|
-
const jsDocKinds = [
|
|
752
|
-
"controllerJsDoc",
|
|
753
|
-
"methodJsDoc",
|
|
754
|
-
"parameterJsDoc"
|
|
755
|
-
];
|
|
756
|
-
function emptyTaggedRegistry() {
|
|
757
|
-
return {
|
|
758
|
-
controllers: [],
|
|
759
|
-
methods: [],
|
|
760
|
-
parameters: [],
|
|
761
|
-
controllerJsDoc: [],
|
|
762
|
-
methodJsDoc: [],
|
|
763
|
-
parameterJsDoc: []
|
|
764
|
-
};
|
|
765
|
-
}
|
|
766
|
-
async function loadRegistry(preset, options) {
|
|
767
|
-
return stripOrigins(await loadTaggedRegistry(preset, options, /* @__PURE__ */ new Set()));
|
|
768
|
-
}
|
|
769
|
-
async function loadTaggedRegistry(preset, options, visited) {
|
|
770
|
-
const validated = await validatePreset(preset);
|
|
771
|
-
if (visited.has(validated.name)) throw new MetadataError({ message: `Preset cycle detected: ${[...visited, validated.name].join(" -> ")}` });
|
|
772
|
-
const nextVisited = new Set(visited);
|
|
773
|
-
nextVisited.add(validated.name);
|
|
774
|
-
const merged = emptyTaggedRegistry();
|
|
775
|
-
for (const extendsName of validated.extends ?? []) appendTagged(merged, await loadTaggedRegistry(await options.resolver(extendsName), options, nextVisited));
|
|
776
|
-
applyOwnHandlers(merged, validated, !!options.strict);
|
|
777
|
-
return merged;
|
|
778
|
-
}
|
|
779
|
-
function applyOwnHandlers(merged, preset, strict) {
|
|
780
|
-
for (const kind of decoratorKinds) {
|
|
781
|
-
const handlers = preset[kind] ?? [];
|
|
782
|
-
for (const handler of handlers) {
|
|
783
|
-
if (handler.replaces) applyReplacesDecorator(merged, kind, handler, preset.name, strict);
|
|
784
|
-
merged[kind].push({
|
|
785
|
-
origin: preset.name,
|
|
786
|
-
handler
|
|
787
|
-
});
|
|
788
|
-
}
|
|
789
|
-
}
|
|
790
|
-
for (const kind of jsDocKinds) {
|
|
791
|
-
const handlers = preset[kind] ?? [];
|
|
792
|
-
for (const handler of handlers) {
|
|
793
|
-
if (handler.replaces) applyReplacesJsDoc(merged, kind, handler, preset.name, strict);
|
|
794
|
-
merged[kind].push({
|
|
795
|
-
origin: preset.name,
|
|
796
|
-
handler
|
|
797
|
-
});
|
|
798
|
-
}
|
|
799
|
-
}
|
|
800
|
-
}
|
|
801
|
-
function applyReplacesDecorator(merged, kind, handler, presetName, strict) {
|
|
802
|
-
const list = merged[kind];
|
|
803
|
-
const remaining = [];
|
|
804
|
-
let removed = 0;
|
|
805
|
-
for (const entry of list) {
|
|
806
|
-
if (entry.origin !== presetName && handlerMatches(handler, entry.handler.match.name, entry.handler.match.on) && originMatches(handler.replaces, entry.origin)) {
|
|
807
|
-
removed += 1;
|
|
808
|
-
continue;
|
|
809
|
-
}
|
|
810
|
-
remaining.push(entry);
|
|
811
|
-
}
|
|
812
|
-
if (removed === 0 && strict) throw new MetadataError({ message: `Preset '${presetName}': handler with replaces=${describeReplaces(handler.replaces)} on '${handler.match.name}' did not match any parent handler` });
|
|
813
|
-
merged[kind] = remaining;
|
|
814
|
-
}
|
|
815
|
-
function applyReplacesJsDoc(merged, kind, handler, presetName, strict) {
|
|
816
|
-
const list = merged[kind];
|
|
817
|
-
const remaining = [];
|
|
818
|
-
let removed = 0;
|
|
819
|
-
for (const entry of list) {
|
|
820
|
-
if (entry.origin !== presetName && handlerMatches(handler, entry.handler.match.tag, entry.handler.match.on) && originMatches(handler.replaces, entry.origin)) {
|
|
821
|
-
removed += 1;
|
|
822
|
-
continue;
|
|
823
|
-
}
|
|
824
|
-
remaining.push(entry);
|
|
825
|
-
}
|
|
826
|
-
if (removed === 0 && strict) throw new MetadataError({ message: `Preset '${presetName}': JSDoc handler with replaces=${describeReplaces(handler.replaces)} on '@${handler.match.tag}' did not match any parent handler` });
|
|
827
|
-
merged[kind] = remaining;
|
|
828
|
-
}
|
|
829
|
-
function handlerMatches(handler, targetName, targetOn) {
|
|
830
|
-
if (("name" in handler.match ? handler.match.name : handler.match.tag) !== targetName) return false;
|
|
831
|
-
if (handler.match.on && handler.match.on !== targetOn) return false;
|
|
832
|
-
return true;
|
|
833
|
-
}
|
|
834
|
-
function originMatches(replaces, origin) {
|
|
835
|
-
if (replaces === true) return true;
|
|
836
|
-
return replaces === origin;
|
|
837
|
-
}
|
|
838
|
-
function describeReplaces(replaces) {
|
|
839
|
-
return replaces === true ? "true" : `'${replaces}'`;
|
|
840
|
-
}
|
|
841
|
-
function appendTagged(target, source) {
|
|
842
|
-
for (const kind of decoratorKinds) target[kind].push(...source[kind]);
|
|
843
|
-
for (const kind of jsDocKinds) target[kind].push(...source[kind]);
|
|
844
|
-
}
|
|
845
|
-
function stripOrigins(tagged) {
|
|
846
|
-
const registry = createRegistry();
|
|
847
|
-
registry.controllers = tagged.controllers.map((e) => e.handler);
|
|
848
|
-
registry.methods = tagged.methods.map((e) => e.handler);
|
|
849
|
-
registry.parameters = tagged.parameters.map((e) => e.handler);
|
|
850
|
-
registry.controllerJsDoc = tagged.controllerJsDoc.map((e) => e.handler);
|
|
851
|
-
registry.methodJsDoc = tagged.methodJsDoc.map((e) => e.handler);
|
|
852
|
-
registry.parameterJsDoc = tagged.parameterJsDoc.map((e) => e.handler);
|
|
853
|
-
return registry;
|
|
854
|
-
}
|
|
855
|
-
/**
|
|
856
|
-
* Resolve a preset by string identifier (npm package, relative path, etc.) and
|
|
857
|
-
* return the v2 Preset object. Looks for a `preset` named export, then the
|
|
858
|
-
* default export, then the module itself.
|
|
859
|
-
*/
|
|
860
|
-
async function resolvePresetByName(input) {
|
|
861
|
-
const lookupPaths = generatePresetLookupPaths(input);
|
|
862
|
-
let lastError;
|
|
863
|
-
for (const lookupPath of lookupPaths) try {
|
|
864
|
-
const moduleExport = await load(lookupPath);
|
|
865
|
-
const candidates = [
|
|
866
|
-
moduleExport.preset,
|
|
867
|
-
moduleExport.default,
|
|
868
|
-
moduleExport
|
|
869
|
-
];
|
|
870
|
-
for (const candidate of candidates) if (isV2Preset(candidate)) return candidate;
|
|
871
|
-
} catch (e) {
|
|
872
|
-
lastError = e;
|
|
873
|
-
}
|
|
874
|
-
throw new ConfigError({
|
|
875
|
-
message: `Preset '${input}' could not be resolved.`,
|
|
876
|
-
code: ConfigErrorCode.PRESET_NOT_FOUND,
|
|
877
|
-
cause: lastError
|
|
878
|
-
});
|
|
879
|
-
}
|
|
880
|
-
/**
|
|
881
|
-
* Resolve a preset by name and immediately materialize its registry, recursively
|
|
882
|
-
* loading `extends` parents through the same resolver.
|
|
883
|
-
*/
|
|
884
|
-
async function loadRegistryByName(input) {
|
|
885
|
-
return loadRegistry(await resolvePresetByName(input), { resolver: resolvePresetByName });
|
|
886
|
-
}
|
|
887
|
-
function isV2Preset(input) {
|
|
888
|
-
return typeof input === "object" && input !== null && typeof input.name === "string" && !("items" in input);
|
|
889
|
-
}
|
|
890
|
-
//#endregion
|
|
891
|
-
//#region src/adapters/decorator/test-helpers.ts
|
|
892
|
-
/**
|
|
893
|
-
* Build a literal-kind {@link DecoratorArgument} from a primitive value.
|
|
894
|
-
* Use this in unit tests to feed handlers a mock argument:
|
|
895
|
-
*
|
|
896
|
-
* ```ts
|
|
897
|
-
* const ctx = createHandlerContext({ args: [literalArg('users')] });
|
|
898
|
-
* controllerHandler.apply(ctx, draft);
|
|
899
|
-
* ```
|
|
900
|
-
*/
|
|
901
|
-
function literalArg(raw) {
|
|
902
|
-
return {
|
|
903
|
-
kind: "literal",
|
|
904
|
-
raw
|
|
905
|
-
};
|
|
906
|
-
}
|
|
907
|
-
/**
|
|
908
|
-
* Build an identifier-kind {@link DecoratorArgument} (e.g. `@Foo(SOME_CONSTANT)`).
|
|
909
|
-
* `raw` is the resolved value the identifier points to — typically a string.
|
|
910
|
-
*/
|
|
911
|
-
function identifierArg(raw) {
|
|
912
|
-
return {
|
|
913
|
-
kind: "identifier",
|
|
914
|
-
raw
|
|
915
|
-
};
|
|
916
|
-
}
|
|
917
|
-
/**
|
|
918
|
-
* Build an array-kind {@link DecoratorArgument} (e.g. `@Foo(['a', 'b'])`).
|
|
919
|
-
*/
|
|
920
|
-
function arrayArg(raw) {
|
|
921
|
-
return {
|
|
922
|
-
kind: "array",
|
|
923
|
-
raw
|
|
924
|
-
};
|
|
925
|
-
}
|
|
926
|
-
/**
|
|
927
|
-
* Build an object-kind {@link DecoratorArgument} (e.g. `@Foo({ key: 'value' })`).
|
|
928
|
-
*/
|
|
929
|
-
function objectArg(raw) {
|
|
930
|
-
return {
|
|
931
|
-
kind: "object",
|
|
932
|
-
raw
|
|
933
|
-
};
|
|
934
|
-
}
|
|
935
|
-
/**
|
|
936
|
-
* Build an unresolvable-kind {@link DecoratorArgument} — represents arguments
|
|
937
|
-
* the source extractor couldn't statically evaluate (e.g. function calls,
|
|
938
|
-
* unknown identifiers).
|
|
939
|
-
*/
|
|
940
|
-
function unresolvableArg() {
|
|
941
|
-
return {
|
|
942
|
-
kind: "unresolvable",
|
|
943
|
-
raw: void 0
|
|
944
|
-
};
|
|
945
|
-
}
|
|
946
|
-
/**
|
|
947
|
-
* Build a {@link DecoratorTypeArgument} stub that returns the supplied type
|
|
948
|
-
* when `resolve()` is called.
|
|
949
|
-
*/
|
|
950
|
-
function typeArg(type) {
|
|
951
|
-
return { resolve: () => type };
|
|
952
|
-
}
|
|
953
|
-
/**
|
|
954
|
-
* Construct a {@link HandlerContext} for unit-testing handlers in isolation
|
|
955
|
-
* without spinning up the full TypeScript compiler / `generateMetadata`
|
|
956
|
-
* pipeline. Combine with the `*Arg(...)` builders to feed a handler a
|
|
957
|
-
* controlled mock decorator source.
|
|
958
|
-
*
|
|
959
|
-
* ```ts
|
|
960
|
-
* const ctx = createHandlerContext({ args: [literalArg('users')] });
|
|
961
|
-
* const draft = newControllerDraft({ name: 'UserController', location: '/x.ts' });
|
|
962
|
-
* myHandler.apply(ctx, draft);
|
|
963
|
-
* expect(draft.paths).toEqual(['users']);
|
|
964
|
-
* ```
|
|
965
|
-
*/
|
|
966
|
-
function createHandlerContext(input = {}) {
|
|
967
|
-
const args = input.args ?? [];
|
|
968
|
-
const typeArgs = input.typeArgs ?? [];
|
|
969
|
-
return {
|
|
970
|
-
host: input.host ?? { name: "TestHost" },
|
|
971
|
-
argument: (index) => args[index],
|
|
972
|
-
arguments: () => [...args],
|
|
973
|
-
typeArgument: (index) => typeArgs[index],
|
|
974
|
-
typeArguments: () => [...typeArgs],
|
|
975
|
-
parameterType: () => input.parameterType
|
|
976
|
-
};
|
|
977
|
-
}
|
|
978
|
-
//#endregion
|
|
979
165
|
//#region src/adapters/typescript/js-doc/constants.ts
|
|
980
166
|
let JSDocTagName = /* @__PURE__ */ function(JSDocTagName) {
|
|
981
167
|
JSDocTagName["ABSTRACT"] = "abstract";
|
|
@@ -1075,22 +261,22 @@ function getJSDocTagNames(node, requireTagName = false) {
|
|
|
1075
261
|
function getInitializerValue(initializer, typeChecker, type) {
|
|
1076
262
|
if (!initializer) return;
|
|
1077
263
|
switch (initializer.kind) {
|
|
1078
|
-
case
|
|
1079
|
-
case
|
|
1080
|
-
case
|
|
1081
|
-
case
|
|
1082
|
-
case
|
|
1083
|
-
case
|
|
264
|
+
case SyntaxKind.ArrayLiteralExpression: return initializer.elements.map((element) => getInitializerValue(element, typeChecker));
|
|
265
|
+
case SyntaxKind.StringLiteral:
|
|
266
|
+
case SyntaxKind.NoSubstitutionTemplateLiteral: return initializer.text;
|
|
267
|
+
case SyntaxKind.TrueKeyword: return true;
|
|
268
|
+
case SyntaxKind.FalseKeyword: return false;
|
|
269
|
+
case SyntaxKind.PrefixUnaryExpression: {
|
|
1084
270
|
const prefixUnary = initializer;
|
|
1085
271
|
switch (prefixUnary.operator) {
|
|
1086
|
-
case
|
|
1087
|
-
case
|
|
272
|
+
case SyntaxKind.PlusToken: return Number(prefixUnary.operand.text);
|
|
273
|
+
case SyntaxKind.MinusToken: return Number(`-${prefixUnary.operand.text}`);
|
|
1088
274
|
default: throw new MetadataError(`Unsupported prefix operator token: ${prefixUnary.operator}`);
|
|
1089
275
|
}
|
|
1090
276
|
}
|
|
1091
|
-
case
|
|
1092
|
-
case
|
|
1093
|
-
case
|
|
277
|
+
case SyntaxKind.NumberKeyword:
|
|
278
|
+
case SyntaxKind.FirstLiteralToken: return Number(initializer.text);
|
|
279
|
+
case SyntaxKind.NewExpression: {
|
|
1094
280
|
const newExpression = initializer;
|
|
1095
281
|
if (newExpression.expression.text === "Date") {
|
|
1096
282
|
let date = /* @__PURE__ */ new Date();
|
|
@@ -1104,8 +290,8 @@ function getInitializerValue(initializer, typeChecker, type) {
|
|
|
1104
290
|
}
|
|
1105
291
|
return;
|
|
1106
292
|
}
|
|
1107
|
-
case
|
|
1108
|
-
case
|
|
293
|
+
case SyntaxKind.NullKeyword: return null;
|
|
294
|
+
case SyntaxKind.ObjectLiteralExpression: {
|
|
1109
295
|
const objectLiteral = initializer;
|
|
1110
296
|
const nestedObject = {};
|
|
1111
297
|
objectLiteral.properties.forEach((p) => {
|
|
@@ -1113,7 +299,7 @@ function getInitializerValue(initializer, typeChecker, type) {
|
|
|
1113
299
|
});
|
|
1114
300
|
return nestedObject;
|
|
1115
301
|
}
|
|
1116
|
-
case
|
|
302
|
+
case SyntaxKind.ImportSpecifier: {
|
|
1117
303
|
if (typeof typeChecker === "undefined") return;
|
|
1118
304
|
const importSpecifier = initializer;
|
|
1119
305
|
const importSymbol = typeChecker.getSymbolAtLocation(importSpecifier.name);
|
|
@@ -1134,7 +320,7 @@ function getInitializerValue(initializer, typeChecker, type) {
|
|
|
1134
320
|
}
|
|
1135
321
|
const hasInitializer = (node) => Object.prototype.hasOwnProperty.call(node, "initializer");
|
|
1136
322
|
const extractInitializer = (valueDeclaration) => valueDeclaration && hasInitializer(valueDeclaration) && valueDeclaration.initializer || void 0;
|
|
1137
|
-
const extractImportSpecifier = (symbol) => symbol?.declarations && symbol.declarations.length > 0 &&
|
|
323
|
+
const extractImportSpecifier = (symbol) => symbol?.declarations && symbol.declarations.length > 0 && isImportSpecifier(symbol.declarations[0]) && symbol.declarations[0] || void 0;
|
|
1138
324
|
//#endregion
|
|
1139
325
|
//#region src/adapters/decorator/typescript/utils.ts
|
|
1140
326
|
/**
|
|
@@ -1143,15 +329,15 @@ const extractImportSpecifier = (symbol) => symbol?.declarations && symbol.declar
|
|
|
1143
329
|
* extension extraction) that only need decorator names + argument values.
|
|
1144
330
|
*/
|
|
1145
331
|
function readNodeDecorators(node, typeChecker) {
|
|
1146
|
-
if (!
|
|
1147
|
-
const decorators =
|
|
332
|
+
if (!canHaveDecorators(node)) return [];
|
|
333
|
+
const decorators = getDecorators(node);
|
|
1148
334
|
if (!decorators || decorators.length === 0) return [];
|
|
1149
335
|
const output = [];
|
|
1150
336
|
for (const decorator of decorators) {
|
|
1151
337
|
const { expression } = decorator;
|
|
1152
338
|
let name;
|
|
1153
339
|
let argumentExpressions = [];
|
|
1154
|
-
if (
|
|
340
|
+
if (isCallExpression(expression)) {
|
|
1155
341
|
argumentExpressions = expression.arguments;
|
|
1156
342
|
name = readDecoratorName$1(expression.expression);
|
|
1157
343
|
} else name = readDecoratorName$1(expression);
|
|
@@ -1173,39 +359,39 @@ function hasDecoratorNamed(node, name, typeChecker) {
|
|
|
1173
359
|
return readNodeDecorators(node, typeChecker).some((d) => d.name === name);
|
|
1174
360
|
}
|
|
1175
361
|
function readDecoratorName$1(expression) {
|
|
1176
|
-
if (
|
|
1177
|
-
if (
|
|
362
|
+
if (isIdentifier(expression)) return expression.text;
|
|
363
|
+
if (isPropertyAccessExpression(expression)) return expression.name.text;
|
|
1178
364
|
}
|
|
1179
365
|
function buildDecoratorArgument(expr, typeChecker) {
|
|
1180
|
-
if (
|
|
366
|
+
if (isStringLiteral(expr) || isNumericLiteral(expr) || isNoSubstitutionTemplateLiteral(expr)) return {
|
|
1181
367
|
raw: getInitializerValue(expr, typeChecker),
|
|
1182
368
|
kind: "literal"
|
|
1183
369
|
};
|
|
1184
|
-
if (expr.kind ===
|
|
370
|
+
if (expr.kind === SyntaxKind.TrueKeyword) return {
|
|
1185
371
|
raw: true,
|
|
1186
372
|
kind: "literal"
|
|
1187
373
|
};
|
|
1188
|
-
if (expr.kind ===
|
|
374
|
+
if (expr.kind === SyntaxKind.FalseKeyword) return {
|
|
1189
375
|
raw: false,
|
|
1190
376
|
kind: "literal"
|
|
1191
377
|
};
|
|
1192
|
-
if (expr.kind ===
|
|
378
|
+
if (expr.kind === SyntaxKind.NullKeyword) return {
|
|
1193
379
|
raw: null,
|
|
1194
380
|
kind: "literal"
|
|
1195
381
|
};
|
|
1196
|
-
if (
|
|
382
|
+
if (isPrefixUnaryExpression(expr) && (expr.operator === SyntaxKind.PlusToken || expr.operator === SyntaxKind.MinusToken) && isNumericLiteral(expr.operand)) return {
|
|
1197
383
|
raw: getInitializerValue(expr, typeChecker),
|
|
1198
384
|
kind: "literal"
|
|
1199
385
|
};
|
|
1200
|
-
if (
|
|
386
|
+
if (isObjectLiteralExpression(expr)) return {
|
|
1201
387
|
raw: getInitializerValue(expr, typeChecker),
|
|
1202
388
|
kind: "object"
|
|
1203
389
|
};
|
|
1204
|
-
if (
|
|
390
|
+
if (isArrayLiteralExpression(expr)) return {
|
|
1205
391
|
raw: getInitializerValue(expr, typeChecker),
|
|
1206
392
|
kind: "array"
|
|
1207
393
|
};
|
|
1208
|
-
if (
|
|
394
|
+
if (isIdentifier(expr) || isPropertyAccessExpression(expr)) {
|
|
1209
395
|
const value = getInitializerValue(expr, typeChecker);
|
|
1210
396
|
if (typeof value !== "undefined") return {
|
|
1211
397
|
raw: value,
|
|
@@ -1224,8 +410,8 @@ function buildDecoratorArgument(expr, typeChecker) {
|
|
|
1224
410
|
//#endregion
|
|
1225
411
|
//#region src/adapters/decorator/typescript/module.ts
|
|
1226
412
|
function buildDecoratorSources(node, options) {
|
|
1227
|
-
if (!
|
|
1228
|
-
const decorators =
|
|
413
|
+
if (!canHaveDecorators(node)) return [];
|
|
414
|
+
const decorators = getDecorators(node);
|
|
1229
415
|
if (!decorators || decorators.length === 0) return [];
|
|
1230
416
|
const output = [];
|
|
1231
417
|
for (const decorator of decorators) {
|
|
@@ -1239,7 +425,7 @@ function buildDecoratorSource(decorator, options) {
|
|
|
1239
425
|
let name;
|
|
1240
426
|
let argumentExpressions = [];
|
|
1241
427
|
let typeArgumentNodes = [];
|
|
1242
|
-
if (
|
|
428
|
+
if (isCallExpression(expression)) {
|
|
1243
429
|
argumentExpressions = expression.arguments;
|
|
1244
430
|
typeArgumentNodes = expression.typeArguments ?? [];
|
|
1245
431
|
name = readDecoratorName(expression.expression);
|
|
@@ -1262,8 +448,8 @@ function buildDecoratorSource(decorator, options) {
|
|
|
1262
448
|
};
|
|
1263
449
|
}
|
|
1264
450
|
function readDecoratorName(expression) {
|
|
1265
|
-
if (
|
|
1266
|
-
if (
|
|
451
|
+
if (isIdentifier(expression)) return expression.text;
|
|
452
|
+
if (isPropertyAccessExpression(expression)) return expression.name.text;
|
|
1267
453
|
}
|
|
1268
454
|
function buildJsDocSources(node, options) {
|
|
1269
455
|
const tags = getJSDocTags(node);
|
|
@@ -1277,10 +463,10 @@ function buildJsDocSource(tag, options) {
|
|
|
1277
463
|
const text = transformJSDocComment(tag.comment);
|
|
1278
464
|
let parameterName;
|
|
1279
465
|
let typeNode;
|
|
1280
|
-
if (
|
|
466
|
+
if (isJSDocParameterTag(tag) || isJSDocPropertyTag(tag)) {
|
|
1281
467
|
if (tag.name) parameterName = readEntityName(tag.name);
|
|
1282
468
|
typeNode = tag.typeExpression?.type;
|
|
1283
|
-
} else if (
|
|
469
|
+
} else if (isJSDocReturnTag(tag) || isJSDocTypeTag(tag) || isJSDocThisTag(tag)) typeNode = tag.typeExpression?.type;
|
|
1284
470
|
const source = {
|
|
1285
471
|
tag: tagName,
|
|
1286
472
|
target: options.target,
|
|
@@ -1295,8 +481,8 @@ function buildJsDocSource(tag, options) {
|
|
|
1295
481
|
return source;
|
|
1296
482
|
}
|
|
1297
483
|
function readEntityName(name) {
|
|
1298
|
-
if (
|
|
1299
|
-
if (
|
|
484
|
+
if (isIdentifier(name)) return name.text;
|
|
485
|
+
if (isQualifiedName(name)) {
|
|
1300
486
|
const left = readEntityName(name.left);
|
|
1301
487
|
return left ? `${left}.${name.right.text}` : name.right.text;
|
|
1302
488
|
}
|
|
@@ -1358,16 +544,6 @@ function applyJsDocHandlers(node, handlers, draft, options) {
|
|
|
1358
544
|
for (const source of sources) for (const handler of handlers) if (matchesJsDoc(handler.match, source)) handler.apply(buildJsDocHandlerContext(source, options), draft);
|
|
1359
545
|
}
|
|
1360
546
|
//#endregion
|
|
1361
|
-
//#region src/core/error/validator.ts
|
|
1362
|
-
var ValidatorError$1 = class extends MetadataError {};
|
|
1363
|
-
//#endregion
|
|
1364
|
-
//#region src/core/error/validator-codes.ts
|
|
1365
|
-
const ValidatorErrorCode$1 = {
|
|
1366
|
-
EXPECTED_NUMBER: "VALIDATOR_EXPECTED_NUMBER",
|
|
1367
|
-
EXPECTED_DATE: "VALIDATOR_EXPECTED_DATE",
|
|
1368
|
-
EXPECTED_STRING: "VALIDATOR_EXPECTED_STRING"
|
|
1369
|
-
};
|
|
1370
|
-
//#endregion
|
|
1371
547
|
//#region src/adapters/typescript/validator/module.ts
|
|
1372
548
|
function getDeclarationValidators(declaration, name) {
|
|
1373
549
|
if (!declaration.parent) return {};
|
|
@@ -1400,23 +576,23 @@ function getDeclarationValidators(declaration, name) {
|
|
|
1400
576
|
comment = comment.substring(comment.indexOf(" ") + 1).trim();
|
|
1401
577
|
const value = getCommentValue(comment);
|
|
1402
578
|
switch (name) {
|
|
1403
|
-
case
|
|
579
|
+
case ValidatorName.UNIQUE_ITEMS:
|
|
1404
580
|
validators[name] = {
|
|
1405
581
|
message: getErrorMsg(comment, false),
|
|
1406
582
|
value: void 0
|
|
1407
583
|
};
|
|
1408
584
|
break;
|
|
1409
|
-
case
|
|
1410
|
-
case
|
|
1411
|
-
case
|
|
1412
|
-
case
|
|
1413
|
-
case
|
|
1414
|
-
case
|
|
585
|
+
case ValidatorName.MINIMUM:
|
|
586
|
+
case ValidatorName.MAXIMUM:
|
|
587
|
+
case ValidatorName.MIN_ITEMS:
|
|
588
|
+
case ValidatorName.MAX_ITEMS:
|
|
589
|
+
case ValidatorName.MIN_LENGTH:
|
|
590
|
+
case ValidatorName.MAX_LENGTH:
|
|
1415
591
|
{
|
|
1416
592
|
const parsed = Number(value);
|
|
1417
|
-
if (!Number.isFinite(parsed)) throw new ValidatorError
|
|
593
|
+
if (!Number.isFinite(parsed)) throw new ValidatorError({
|
|
1418
594
|
message: `@${name} validator expects a numeric value, got '${value}'.`,
|
|
1419
|
-
code: ValidatorErrorCode
|
|
595
|
+
code: ValidatorErrorCode.EXPECTED_NUMBER
|
|
1420
596
|
});
|
|
1421
597
|
validators[name] = {
|
|
1422
598
|
message: getErrorMsg(comment),
|
|
@@ -1424,21 +600,21 @@ function getDeclarationValidators(declaration, name) {
|
|
|
1424
600
|
};
|
|
1425
601
|
}
|
|
1426
602
|
break;
|
|
1427
|
-
case
|
|
1428
|
-
case
|
|
1429
|
-
if (typeof value !== "string") throw new ValidatorError
|
|
603
|
+
case ValidatorName.MIN_DATE:
|
|
604
|
+
case ValidatorName.MAX_DATE:
|
|
605
|
+
if (typeof value !== "string") throw new ValidatorError({
|
|
1430
606
|
message: `@${name} validator expects a date string, got '${typeof value}'.`,
|
|
1431
|
-
code: ValidatorErrorCode
|
|
607
|
+
code: ValidatorErrorCode.EXPECTED_DATE
|
|
1432
608
|
});
|
|
1433
609
|
validators[name] = {
|
|
1434
610
|
message: getErrorMsg(comment),
|
|
1435
611
|
value
|
|
1436
612
|
};
|
|
1437
613
|
break;
|
|
1438
|
-
case
|
|
1439
|
-
if (typeof value !== "string") throw new ValidatorError
|
|
614
|
+
case ValidatorName.PATTERN:
|
|
615
|
+
if (typeof value !== "string") throw new ValidatorError({
|
|
1440
616
|
message: `@${name} validator expects a string pattern, got '${value}'.`,
|
|
1441
|
-
code: ValidatorErrorCode
|
|
617
|
+
code: ValidatorErrorCode.EXPECTED_STRING
|
|
1442
618
|
});
|
|
1443
619
|
validators[name] = {
|
|
1444
620
|
message: getErrorMsg(comment),
|
|
@@ -1486,64 +662,6 @@ function removeSurroundingQuotes(str) {
|
|
|
1486
662
|
return str;
|
|
1487
663
|
}
|
|
1488
664
|
//#endregion
|
|
1489
|
-
//#region src/core/error/resolver.ts
|
|
1490
|
-
var ResolverError$1 = class extends MetadataError {
|
|
1491
|
-
file;
|
|
1492
|
-
line;
|
|
1493
|
-
constructor(message, node, options) {
|
|
1494
|
-
const opts = typeof options === "boolean" ? { onlyCurrent: options } : options;
|
|
1495
|
-
const onlyCurrent = opts?.onlyCurrent ?? false;
|
|
1496
|
-
const parts = [message];
|
|
1497
|
-
let file;
|
|
1498
|
-
let line;
|
|
1499
|
-
if (node) {
|
|
1500
|
-
const location = prettyLocationOfNode$1(node);
|
|
1501
|
-
if (location) {
|
|
1502
|
-
parts.push(location.text);
|
|
1503
|
-
file = location.file;
|
|
1504
|
-
line = location.line;
|
|
1505
|
-
}
|
|
1506
|
-
parts.push(prettyTroubleCause$1(node, onlyCurrent));
|
|
1507
|
-
}
|
|
1508
|
-
super({
|
|
1509
|
-
message: parts.join("\n"),
|
|
1510
|
-
cause: opts?.cause
|
|
1511
|
-
});
|
|
1512
|
-
this.file = file;
|
|
1513
|
-
this.line = line;
|
|
1514
|
-
}
|
|
1515
|
-
};
|
|
1516
|
-
function isResolverError$1(input) {
|
|
1517
|
-
if (!isBaseError(input)) return false;
|
|
1518
|
-
return "file" in input && "line" in input;
|
|
1519
|
-
}
|
|
1520
|
-
function prettyLocationOfNode$1(node) {
|
|
1521
|
-
try {
|
|
1522
|
-
const sourceFile = node.getSourceFile();
|
|
1523
|
-
if (!sourceFile) return void 0;
|
|
1524
|
-
const token = node.getFirstToken() || node.parent?.getFirstToken();
|
|
1525
|
-
const start = token ? sourceFile.getLineAndCharacterOfPosition(token.getStart()).line + 1 : void 0;
|
|
1526
|
-
const end = token ? sourceFile.getLineAndCharacterOfPosition(token.getEnd()).line + 1 : void 0;
|
|
1527
|
-
return {
|
|
1528
|
-
text: `At: ${normalize(sourceFile.fileName)}${start ? `:${start}` : ""}${end ? `:${end}` : ""}.`,
|
|
1529
|
-
file: sourceFile.fileName,
|
|
1530
|
-
line: start
|
|
1531
|
-
};
|
|
1532
|
-
} catch {
|
|
1533
|
-
return;
|
|
1534
|
-
}
|
|
1535
|
-
}
|
|
1536
|
-
function prettyTroubleCause$1(node, onlyCurrent = false) {
|
|
1537
|
-
try {
|
|
1538
|
-
let name;
|
|
1539
|
-
if (onlyCurrent || !node.parent) name = node.pos !== -1 ? node.getText() : node.name.text;
|
|
1540
|
-
else name = node.parent.pos !== -1 ? node.parent.getText() : node.parent.name.text;
|
|
1541
|
-
return `This was caused by '${name}'`;
|
|
1542
|
-
} catch {
|
|
1543
|
-
return "This was caused by an unknown node";
|
|
1544
|
-
}
|
|
1545
|
-
}
|
|
1546
|
-
//#endregion
|
|
1547
665
|
//#region src/adapters/typescript/resolver/extension/module.ts
|
|
1548
666
|
function getNodeExtensions(node, registry) {
|
|
1549
667
|
const names = namesForMarker(registry, isExtensionMarker);
|
|
@@ -1567,9 +685,9 @@ function getNodeExtensions(node, registry) {
|
|
|
1567
685
|
//#endregion
|
|
1568
686
|
//#region src/adapters/typescript/resolver/sub/array.ts
|
|
1569
687
|
function resolveArrayType(typeNode, ctx) {
|
|
1570
|
-
if (!
|
|
688
|
+
if (!isArrayTypeNode(typeNode)) return;
|
|
1571
689
|
return {
|
|
1572
|
-
typeName:
|
|
690
|
+
typeName: TypeName.ARRAY,
|
|
1573
691
|
elementType: ctx.resolveType(typeNode.elementType, ctx.parentNode, ctx.context)
|
|
1574
692
|
};
|
|
1575
693
|
}
|
|
@@ -1613,92 +731,93 @@ function getNodeDescription(node, typeChecker) {
|
|
|
1613
731
|
}
|
|
1614
732
|
function toTypeNodeOrFail(typeChecker, ...args) {
|
|
1615
733
|
const output = typeChecker.typeToTypeNode(...args);
|
|
1616
|
-
if (typeof output === "undefined") throw new ResolverError
|
|
734
|
+
if (typeof output === "undefined") throw new ResolverError("Type could not be transformed to TypeNode.");
|
|
1617
735
|
return output;
|
|
1618
736
|
}
|
|
1619
737
|
//#endregion
|
|
1620
738
|
//#region src/adapters/typescript/resolver/sub/indexed-access.ts
|
|
1621
739
|
function resolveIndexedAccessType(typeNode, ctx) {
|
|
1622
|
-
if (!
|
|
1623
|
-
if (typeNode.indexType.kind ===
|
|
1624
|
-
const numberIndexType = typeNode.indexType.kind ===
|
|
740
|
+
if (!isIndexedAccessTypeNode(typeNode)) return;
|
|
741
|
+
if (typeNode.indexType.kind === SyntaxKind.NumberKeyword || typeNode.indexType.kind === SyntaxKind.StringKeyword) {
|
|
742
|
+
const numberIndexType = typeNode.indexType.kind === SyntaxKind.NumberKeyword;
|
|
1625
743
|
const objectType = ctx.typeChecker.getTypeFromTypeNode(typeNode.objectType);
|
|
1626
744
|
const type = numberIndexType ? objectType.getNumberIndexType() : objectType.getStringIndexType();
|
|
1627
|
-
if (type === void 0) throw new ResolverError
|
|
745
|
+
if (type === void 0) throw new ResolverError(`Could not determine ${numberIndexType ? "number" : "string"} index on ${ctx.typeChecker.typeToString(objectType)}`, typeNode);
|
|
1628
746
|
return ctx.resolveType(toTypeNodeOrFail(ctx.typeChecker, type, void 0, void 0), typeNode, ctx.context, ctx.referencer);
|
|
1629
747
|
}
|
|
1630
|
-
if (
|
|
748
|
+
if (isLiteralTypeNode(typeNode.indexType) && (isStringLiteral(typeNode.indexType.literal) || isNumericLiteral(typeNode.indexType.literal))) {
|
|
1631
749
|
const hasType = (node) => node !== void 0 && Object.prototype.hasOwnProperty.call(node, "type");
|
|
1632
750
|
const symbol = ctx.typeChecker.getPropertyOfType(ctx.typeChecker.getTypeFromTypeNode(typeNode.objectType), typeNode.indexType.literal.text);
|
|
1633
|
-
if (symbol === void 0) throw new ResolverError
|
|
751
|
+
if (symbol === void 0) throw new ResolverError(`Could not determine the keys on ${ctx.typeChecker.typeToString(ctx.typeChecker.getTypeFromTypeNode(typeNode.objectType))}`, typeNode);
|
|
1634
752
|
if (hasType(symbol.valueDeclaration) && symbol.valueDeclaration.type) return ctx.resolveType(symbol.valueDeclaration.type, typeNode, ctx.context, ctx.referencer);
|
|
1635
753
|
const declaration = ctx.typeChecker.getTypeOfSymbolAtLocation(symbol, typeNode.objectType);
|
|
1636
754
|
try {
|
|
1637
755
|
return ctx.resolveType(toTypeNodeOrFail(ctx.typeChecker, declaration, void 0, void 0), typeNode, ctx.context, ctx.referencer);
|
|
1638
756
|
} catch (err) {
|
|
1639
|
-
throw new ResolverError
|
|
757
|
+
throw new ResolverError(`Could not determine the keys on ${ctx.typeChecker.typeToString(declaration)}`, typeNode, { cause: err });
|
|
1640
758
|
}
|
|
1641
759
|
}
|
|
1642
760
|
}
|
|
1643
761
|
//#endregion
|
|
1644
762
|
//#region src/adapters/typescript/resolver/sub/intersection.ts
|
|
1645
763
|
function resolveIntersectionType(typeNode, ctx) {
|
|
1646
|
-
if (!
|
|
764
|
+
if (!isIntersectionTypeNode(typeNode)) return;
|
|
765
|
+
const members = typeNode.types.map((type) => ctx.resolveType(type, ctx.parentNode, ctx.context));
|
|
1647
766
|
return {
|
|
1648
|
-
typeName:
|
|
1649
|
-
members
|
|
767
|
+
typeName: TypeName.INTERSECTION,
|
|
768
|
+
members
|
|
1650
769
|
};
|
|
1651
770
|
}
|
|
1652
771
|
//#endregion
|
|
1653
772
|
//#region src/adapters/typescript/resolver/sub/literal.ts
|
|
1654
773
|
function resolveLiteralType(typeNode, ctx) {
|
|
1655
|
-
if (typeNode.kind ===
|
|
1656
|
-
typeName:
|
|
774
|
+
if (typeNode.kind === SyntaxKind.NullKeyword) return {
|
|
775
|
+
typeName: TypeName.ENUM,
|
|
1657
776
|
members: [null]
|
|
1658
777
|
};
|
|
1659
|
-
if (typeNode.kind ===
|
|
1660
|
-
if (
|
|
1661
|
-
typeName:
|
|
778
|
+
if (typeNode.kind === SyntaxKind.AnyKeyword || typeNode.kind === SyntaxKind.UnknownKeyword) return { typeName: TypeName.ANY };
|
|
779
|
+
if (isLiteralTypeNode(typeNode)) return {
|
|
780
|
+
typeName: TypeName.ENUM,
|
|
1662
781
|
members: [getLiteralValue(typeNode)]
|
|
1663
782
|
};
|
|
1664
|
-
if (typeNode.kind ===
|
|
783
|
+
if (typeNode.kind === SyntaxKind.TemplateLiteralType) {
|
|
1665
784
|
const type = ctx.typeChecker.getTypeFromTypeNode(ctx.referencer || typeNode);
|
|
1666
785
|
if (type.isUnion() && type.types.every((t) => t.isStringLiteral())) return {
|
|
1667
|
-
typeName:
|
|
786
|
+
typeName: TypeName.ENUM,
|
|
1668
787
|
members: type.types.map((t) => t.value)
|
|
1669
788
|
};
|
|
1670
|
-
throw new ResolverError
|
|
789
|
+
throw new ResolverError(`Could not resolve type: ${ctx.typeChecker.typeToString(ctx.typeChecker.getTypeFromTypeNode(typeNode), typeNode)}`, typeNode);
|
|
1671
790
|
}
|
|
1672
|
-
if (
|
|
1673
|
-
if (typeNode.kind ===
|
|
791
|
+
if (isParenthesizedTypeNode(typeNode)) return ctx.resolveType(typeNode.type, typeNode, ctx.context, ctx.referencer);
|
|
792
|
+
if (typeNode.kind === SyntaxKind.ObjectKeyword || isFunctionTypeNode(typeNode)) return { typeName: TypeName.OBJECT };
|
|
1674
793
|
}
|
|
1675
794
|
function getLiteralValue(typeNode) {
|
|
1676
795
|
let value;
|
|
1677
796
|
switch (typeNode.literal.kind) {
|
|
1678
|
-
case
|
|
797
|
+
case SyntaxKind.TrueKeyword:
|
|
1679
798
|
value = true;
|
|
1680
799
|
break;
|
|
1681
|
-
case
|
|
800
|
+
case SyntaxKind.FalseKeyword:
|
|
1682
801
|
value = false;
|
|
1683
802
|
break;
|
|
1684
|
-
case
|
|
803
|
+
case SyntaxKind.StringLiteral:
|
|
1685
804
|
value = typeNode.literal.text;
|
|
1686
805
|
break;
|
|
1687
|
-
case
|
|
806
|
+
case SyntaxKind.NumericLiteral:
|
|
1688
807
|
value = Number.parseFloat(typeNode.literal.text);
|
|
1689
808
|
break;
|
|
1690
|
-
case
|
|
809
|
+
case SyntaxKind.NullKeyword:
|
|
1691
810
|
value = null;
|
|
1692
811
|
break;
|
|
1693
812
|
default: if (Object.prototype.hasOwnProperty.call(typeNode.literal, "text")) value = typeNode.literal.text;
|
|
1694
|
-
else throw new ResolverError
|
|
813
|
+
else throw new ResolverError(`Couldn't resolve literal node: ${typeNode.literal.getText()}`, typeNode.literal);
|
|
1695
814
|
}
|
|
1696
815
|
return value;
|
|
1697
816
|
}
|
|
1698
817
|
//#endregion
|
|
1699
818
|
//#region src/adapters/typescript/resolver/sub/mapped.ts
|
|
1700
819
|
function resolveMappedType(typeNode, ctx) {
|
|
1701
|
-
if (!
|
|
820
|
+
if (!isMappedTypeNode(typeNode) || !ctx.referencer) return;
|
|
1702
821
|
const type = ctx.typeChecker.getTypeFromTypeNode(ctx.referencer);
|
|
1703
822
|
const mappedTypeNode = typeNode;
|
|
1704
823
|
const { typeChecker } = ctx;
|
|
@@ -1706,41 +825,42 @@ function resolveMappedType(typeNode, ctx) {
|
|
|
1706
825
|
const isIgnored = (prop) => {
|
|
1707
826
|
const declaration = getDeclaration(prop);
|
|
1708
827
|
if (prop.getJsDocTags().findIndex((tag) => tag.name === "ignore") >= 0) return true;
|
|
1709
|
-
return !!declaration && !
|
|
828
|
+
return !!declaration && !isPropertyDeclaration(declaration) && !isPropertySignature(declaration) && !isParameter(declaration);
|
|
1710
829
|
};
|
|
830
|
+
const properties = type.getProperties().filter((property) => !isIgnored(property)).map((property) => {
|
|
831
|
+
const declaration = getDeclaration(property);
|
|
832
|
+
const overrideToken = mappedTypeNode.questionToken?.kind === SyntaxKind.PlusToken ? factory.createToken(SyntaxKind.QuestionToken) : mappedTypeNode.questionToken;
|
|
833
|
+
if (declaration && isPropertySignature(declaration)) return {
|
|
834
|
+
...ctx.propertyFromSignature(declaration, overrideToken),
|
|
835
|
+
name: property.getName()
|
|
836
|
+
};
|
|
837
|
+
if (declaration && (isPropertyDeclaration(declaration) || isParameter(declaration))) return {
|
|
838
|
+
...ctx.propertyFromDeclaration(declaration, overrideToken),
|
|
839
|
+
name: property.getName()
|
|
840
|
+
};
|
|
841
|
+
let required = (property.flags & SymbolFlags.Optional) === 0;
|
|
842
|
+
const typeNode2 = toTypeNodeOrFail(typeChecker, typeChecker.getTypeOfSymbolAtLocation(property, typeNode), void 0, NodeBuilderFlags.NoTruncation);
|
|
843
|
+
if (mappedTypeNode.questionToken && mappedTypeNode.questionToken.kind === SyntaxKind.MinusToken) required = true;
|
|
844
|
+
else if (mappedTypeNode.questionToken && (mappedTypeNode.questionToken.kind === SyntaxKind.QuestionToken || mappedTypeNode.questionToken.kind === SyntaxKind.PlusToken)) required = false;
|
|
845
|
+
return {
|
|
846
|
+
name: property.getName(),
|
|
847
|
+
required,
|
|
848
|
+
deprecated: false,
|
|
849
|
+
type: ctx.resolveType(typeNode2, typeNode, ctx.context, ctx.referencer),
|
|
850
|
+
validators: {}
|
|
851
|
+
};
|
|
852
|
+
});
|
|
1711
853
|
return {
|
|
1712
|
-
typeName:
|
|
1713
|
-
properties
|
|
1714
|
-
const declaration = getDeclaration(property);
|
|
1715
|
-
const overrideToken = mappedTypeNode.questionToken?.kind === ts.SyntaxKind.PlusToken ? ts.factory.createToken(ts.SyntaxKind.QuestionToken) : mappedTypeNode.questionToken;
|
|
1716
|
-
if (declaration && ts.isPropertySignature(declaration)) return {
|
|
1717
|
-
...ctx.propertyFromSignature(declaration, overrideToken),
|
|
1718
|
-
name: property.getName()
|
|
1719
|
-
};
|
|
1720
|
-
if (declaration && (ts.isPropertyDeclaration(declaration) || ts.isParameter(declaration))) return {
|
|
1721
|
-
...ctx.propertyFromDeclaration(declaration, overrideToken),
|
|
1722
|
-
name: property.getName()
|
|
1723
|
-
};
|
|
1724
|
-
let required = (property.flags & ts.SymbolFlags.Optional) === 0;
|
|
1725
|
-
const typeNode2 = toTypeNodeOrFail(typeChecker, typeChecker.getTypeOfSymbolAtLocation(property, typeNode), void 0, ts.NodeBuilderFlags.NoTruncation);
|
|
1726
|
-
if (mappedTypeNode.questionToken && mappedTypeNode.questionToken.kind === ts.SyntaxKind.MinusToken) required = true;
|
|
1727
|
-
else if (mappedTypeNode.questionToken && (mappedTypeNode.questionToken.kind === ts.SyntaxKind.QuestionToken || mappedTypeNode.questionToken.kind === ts.SyntaxKind.PlusToken)) required = false;
|
|
1728
|
-
return {
|
|
1729
|
-
name: property.getName(),
|
|
1730
|
-
required,
|
|
1731
|
-
deprecated: false,
|
|
1732
|
-
type: ctx.resolveType(typeNode2, typeNode, ctx.context, ctx.referencer),
|
|
1733
|
-
validators: {}
|
|
1734
|
-
};
|
|
1735
|
-
})
|
|
854
|
+
typeName: TypeName.NESTED_OBJECT_LITERAL,
|
|
855
|
+
properties
|
|
1736
856
|
};
|
|
1737
857
|
}
|
|
1738
858
|
//#endregion
|
|
1739
859
|
//#region src/adapters/typescript/resolver/sub/object-literal.ts
|
|
1740
860
|
function resolveObjectLiteralType(typeNode, ctx) {
|
|
1741
|
-
if (!
|
|
1742
|
-
const properties = typeNode.members.filter((member) =>
|
|
1743
|
-
if (!propertySignature.type) throw new ResolverError
|
|
861
|
+
if (!isTypeLiteralNode(typeNode)) return;
|
|
862
|
+
const properties = typeNode.members.filter((member) => isPropertySignature(member)).reduce((res, propertySignature) => {
|
|
863
|
+
if (!propertySignature.type) throw new ResolverError("No valid type found for property declaration.", propertySignature);
|
|
1744
864
|
const type = ctx.resolveType(propertySignature.type, propertySignature, ctx.context);
|
|
1745
865
|
return [{
|
|
1746
866
|
deprecated: hasJSDocTag(propertySignature, "deprecated"),
|
|
@@ -1755,16 +875,16 @@ function resolveObjectLiteralType(typeNode, ctx) {
|
|
|
1755
875
|
validators: getDeclarationValidators(propertySignature) || {}
|
|
1756
876
|
}, ...res];
|
|
1757
877
|
}, []);
|
|
1758
|
-
const indexMember = typeNode.members.find((member) =>
|
|
878
|
+
const indexMember = typeNode.members.find((member) => isIndexSignatureDeclaration(member));
|
|
1759
879
|
let additionalType;
|
|
1760
880
|
if (indexMember) {
|
|
1761
881
|
const indexSignatureDeclaration = indexMember;
|
|
1762
|
-
if (!isStringType(ctx.resolveType(indexSignatureDeclaration.parameters[0].type, ctx.parentNode, ctx.context))) throw new ResolverError
|
|
882
|
+
if (!isStringType(ctx.resolveType(indexSignatureDeclaration.parameters[0].type, ctx.parentNode, ctx.context))) throw new ResolverError("Only string indexes are supported.", typeNode);
|
|
1763
883
|
additionalType = ctx.resolveType(indexSignatureDeclaration.type, ctx.parentNode, ctx.context);
|
|
1764
884
|
}
|
|
1765
885
|
return {
|
|
1766
886
|
additionalProperties: indexMember && additionalType,
|
|
1767
|
-
typeName:
|
|
887
|
+
typeName: TypeName.NESTED_OBJECT_LITERAL,
|
|
1768
888
|
properties
|
|
1769
889
|
};
|
|
1770
890
|
}
|
|
@@ -1772,17 +892,17 @@ function getNodeFormat(node) {
|
|
|
1772
892
|
return getJSDocTagComment(node, "format");
|
|
1773
893
|
}
|
|
1774
894
|
function getPropertyName(node) {
|
|
1775
|
-
if (
|
|
1776
|
-
if (
|
|
895
|
+
if (isIdentifier(node.name)) return node.name.text;
|
|
896
|
+
if (isStringLiteral(node.name) || isNumericLiteral(node.name)) return node.name.text;
|
|
1777
897
|
return node.name.getText();
|
|
1778
898
|
}
|
|
1779
899
|
//#endregion
|
|
1780
900
|
//#region src/adapters/typescript/resolver/sub/primitive.ts
|
|
1781
901
|
const NUMERIC_KIND_TO_TYPE_NAME = {
|
|
1782
|
-
[NumericKind.Int]:
|
|
1783
|
-
[NumericKind.Long]:
|
|
1784
|
-
[NumericKind.Float]:
|
|
1785
|
-
[NumericKind.Double]:
|
|
902
|
+
[NumericKind.Int]: TypeName.INTEGER,
|
|
903
|
+
[NumericKind.Long]: TypeName.LONG,
|
|
904
|
+
[NumericKind.Float]: TypeName.FLOAT,
|
|
905
|
+
[NumericKind.Double]: TypeName.DOUBLE
|
|
1786
906
|
};
|
|
1787
907
|
var PrimitiveResolver = class {
|
|
1788
908
|
registry;
|
|
@@ -1792,15 +912,15 @@ var PrimitiveResolver = class {
|
|
|
1792
912
|
resolve(node, parentNode) {
|
|
1793
913
|
const resolved = this.resolveSyntaxKind(node.kind);
|
|
1794
914
|
if (resolved) {
|
|
1795
|
-
if (resolved === "string") return { typeName:
|
|
1796
|
-
if (resolved === "void") return { typeName:
|
|
1797
|
-
if (resolved === "boolean") return { typeName:
|
|
1798
|
-
if (resolved === "undefined") return { typeName:
|
|
915
|
+
if (resolved === "string") return { typeName: TypeName.STRING };
|
|
916
|
+
if (resolved === "void") return { typeName: TypeName.VOID };
|
|
917
|
+
if (resolved === "boolean") return { typeName: TypeName.BOOLEAN };
|
|
918
|
+
if (resolved === "undefined") return { typeName: TypeName.UNDEFINED };
|
|
1799
919
|
if (resolved === "null") return;
|
|
1800
|
-
if (resolved === "never") return { typeName:
|
|
1801
|
-
if (resolved === "bigint") return { typeName:
|
|
920
|
+
if (resolved === "never") return { typeName: TypeName.NEVER };
|
|
921
|
+
if (resolved === "bigint") return { typeName: TypeName.BIGINT };
|
|
1802
922
|
if (resolved === "number") {
|
|
1803
|
-
if (!parentNode) return { typeName:
|
|
923
|
+
if (!parentNode) return { typeName: TypeName.DOUBLE };
|
|
1804
924
|
const presentJsDocTags = new Set(getJSDocTagNames(parentNode).map((tag) => tag.toLowerCase()));
|
|
1805
925
|
for (const kind of [
|
|
1806
926
|
NumericKind.Int,
|
|
@@ -1814,7 +934,7 @@ var PrimitiveResolver = class {
|
|
|
1814
934
|
const jsDocTags = tagsForMarker(this.registry, matchKind);
|
|
1815
935
|
for (const tag of jsDocTags) if (presentJsDocTags.has(tag.toLowerCase())) return { typeName: NUMERIC_KIND_TO_TYPE_NAME[kind] };
|
|
1816
936
|
}
|
|
1817
|
-
return { typeName:
|
|
937
|
+
return { typeName: TypeName.DOUBLE };
|
|
1818
938
|
}
|
|
1819
939
|
}
|
|
1820
940
|
}
|
|
@@ -1842,9 +962,9 @@ var ReferenceResolver = class extends ResolverBase {
|
|
|
1842
962
|
}
|
|
1843
963
|
merge(referenceTypes) {
|
|
1844
964
|
if (referenceTypes.length === 1) return referenceTypes[0];
|
|
1845
|
-
if (referenceTypes.every((refType) => refType.refName ===
|
|
1846
|
-
if (referenceTypes.every((refType) => refType.refName ===
|
|
1847
|
-
throw new ResolverError
|
|
965
|
+
if (referenceTypes.every((refType) => refType.refName === TypeName.REF_ENUM)) return this.mergeManyRefEnums(referenceTypes);
|
|
966
|
+
if (referenceTypes.every((refType) => refType.refName === TypeName.REF_OBJECT)) return this.mergeManyRefObjects(referenceTypes);
|
|
967
|
+
throw new ResolverError(`These resolved type merge rules are not defined: ${JSON.stringify(referenceTypes)}`);
|
|
1848
968
|
}
|
|
1849
969
|
mergeManyRefEnums(many) {
|
|
1850
970
|
let merged = this.mergeRefEnums(many[0], many[1]);
|
|
@@ -1857,7 +977,7 @@ var ReferenceResolver = class extends ResolverBase {
|
|
|
1857
977
|
else if (!second.description) description = first.description;
|
|
1858
978
|
else description = `${first.description}\n${second.description}`;
|
|
1859
979
|
return {
|
|
1860
|
-
typeName:
|
|
980
|
+
typeName: TypeName.REF_ENUM,
|
|
1861
981
|
example: first.example || second.example,
|
|
1862
982
|
description,
|
|
1863
983
|
members: [...first.members || [], ...second.members || []],
|
|
@@ -1881,11 +1001,11 @@ var ReferenceResolver = class extends ResolverBase {
|
|
|
1881
1001
|
if (first.additionalProperties || second.additionalProperties) if (!first.additionalProperties) additionalProperties = second.additionalProperties;
|
|
1882
1002
|
else if (!second.additionalProperties) additionalProperties = first.additionalProperties;
|
|
1883
1003
|
else additionalProperties = {
|
|
1884
|
-
typeName:
|
|
1004
|
+
typeName: TypeName.UNION,
|
|
1885
1005
|
members: [first.additionalProperties, second.additionalProperties]
|
|
1886
1006
|
};
|
|
1887
1007
|
return {
|
|
1888
|
-
typeName:
|
|
1008
|
+
typeName: TypeName.REF_OBJECT,
|
|
1889
1009
|
description,
|
|
1890
1010
|
properties,
|
|
1891
1011
|
additionalProperties,
|
|
@@ -1899,7 +1019,7 @@ var ReferenceResolver = class extends ResolverBase {
|
|
|
1899
1019
|
const enums = declaration.members.map(this.typeChecker.getConstantValue.bind(this.typeChecker)).filter(isNotUndefined);
|
|
1900
1020
|
const enumNames = declaration.members.map((e) => e.name.getText()).filter(isNotUndefined);
|
|
1901
1021
|
return {
|
|
1902
|
-
typeName:
|
|
1022
|
+
typeName: TypeName.REF_ENUM,
|
|
1903
1023
|
description: getNodeDescription(declaration, this.typeChecker),
|
|
1904
1024
|
members: enums,
|
|
1905
1025
|
memberNames: enumNames,
|
|
@@ -1909,7 +1029,7 @@ var ReferenceResolver = class extends ResolverBase {
|
|
|
1909
1029
|
}
|
|
1910
1030
|
transformEnumMember(declaration, enumName) {
|
|
1911
1031
|
return {
|
|
1912
|
-
typeName:
|
|
1032
|
+
typeName: TypeName.REF_ENUM,
|
|
1913
1033
|
refName: enumName,
|
|
1914
1034
|
members: [this.typeChecker.getConstantValue(declaration)],
|
|
1915
1035
|
memberNames: [declaration.name.getText()],
|
|
@@ -1920,40 +1040,42 @@ var ReferenceResolver = class extends ResolverBase {
|
|
|
1920
1040
|
//#endregion
|
|
1921
1041
|
//#region src/adapters/typescript/resolver/sub/tuple.ts
|
|
1922
1042
|
function resolveTupleType(typeNode, ctx) {
|
|
1923
|
-
if (!
|
|
1043
|
+
if (!isTupleTypeNode(typeNode)) return;
|
|
1044
|
+
const elements = typeNode.elements.map((element) => {
|
|
1045
|
+
const isNamed = isNamedTupleMember(element);
|
|
1046
|
+
const actualType = isNamed ? element.type : element;
|
|
1047
|
+
return {
|
|
1048
|
+
type: ctx.resolveType(actualType, ctx.parentNode, ctx.context),
|
|
1049
|
+
...isNamed && { name: element.name.text }
|
|
1050
|
+
};
|
|
1051
|
+
});
|
|
1924
1052
|
return {
|
|
1925
|
-
typeName:
|
|
1926
|
-
elements
|
|
1927
|
-
const isNamed = ts.isNamedTupleMember(element);
|
|
1928
|
-
const actualType = isNamed ? element.type : element;
|
|
1929
|
-
return {
|
|
1930
|
-
type: ctx.resolveType(actualType, ctx.parentNode, ctx.context),
|
|
1931
|
-
...isNamed && { name: element.name.text }
|
|
1932
|
-
};
|
|
1933
|
-
})
|
|
1053
|
+
typeName: TypeName.TUPLE,
|
|
1054
|
+
elements
|
|
1934
1055
|
};
|
|
1935
1056
|
}
|
|
1936
1057
|
//#endregion
|
|
1937
1058
|
//#region src/adapters/typescript/resolver/sub/type-operator.ts
|
|
1938
1059
|
function resolveTypeOperatorType(typeNode, ctx) {
|
|
1939
|
-
if (!
|
|
1940
|
-
if (typeNode.operator ===
|
|
1060
|
+
if (!isTypeOperatorNode(typeNode)) return;
|
|
1061
|
+
if (typeNode.operator === SyntaxKind.KeyOfKeyword) {
|
|
1941
1062
|
const type = ctx.typeChecker.getTypeFromTypeNode(typeNode);
|
|
1942
1063
|
try {
|
|
1943
|
-
return ctx.resolveType(toTypeNodeOrFail(ctx.typeChecker, type, void 0,
|
|
1064
|
+
return ctx.resolveType(toTypeNodeOrFail(ctx.typeChecker, type, void 0, NodeBuilderFlags.NoTruncation), typeNode, ctx.context, ctx.referencer);
|
|
1944
1065
|
} catch (err) {
|
|
1945
|
-
throw new ResolverError
|
|
1066
|
+
throw new ResolverError(`Could not determine the keys on ${ctx.typeChecker.typeToString(ctx.typeChecker.getTypeFromTypeNode(typeNode.type))}`, typeNode, { cause: err });
|
|
1946
1067
|
}
|
|
1947
1068
|
}
|
|
1948
|
-
if (typeNode.operator ===
|
|
1069
|
+
if (typeNode.operator === SyntaxKind.ReadonlyKeyword) return ctx.resolveType(typeNode.type, typeNode, ctx.context, ctx.referencer);
|
|
1949
1070
|
}
|
|
1950
1071
|
//#endregion
|
|
1951
1072
|
//#region src/adapters/typescript/resolver/sub/union.ts
|
|
1952
1073
|
function resolveUnionType(typeNode, ctx) {
|
|
1953
|
-
if (!
|
|
1074
|
+
if (!isUnionTypeNode(typeNode)) return;
|
|
1075
|
+
const members = typeNode.types.map((type) => ctx.resolveType(type, ctx.parentNode, ctx.context));
|
|
1954
1076
|
return {
|
|
1955
|
-
typeName:
|
|
1956
|
-
members
|
|
1077
|
+
typeName: TypeName.UNION,
|
|
1078
|
+
members
|
|
1957
1079
|
};
|
|
1958
1080
|
}
|
|
1959
1081
|
//#endregion
|
|
@@ -1985,7 +1107,7 @@ var TypeNodeResolver = class TypeNodeResolver extends ResolverBase {
|
|
|
1985
1107
|
*/
|
|
1986
1108
|
static clearCache() {}
|
|
1987
1109
|
resolve() {
|
|
1988
|
-
if (this.depth > TypeNodeResolver.MAX_DEPTH) throw new ResolverError
|
|
1110
|
+
if (this.depth > TypeNodeResolver.MAX_DEPTH) throw new ResolverError(`Type resolution exceeded maximum depth of ${TypeNodeResolver.MAX_DEPTH}. This usually indicates deeply nested or circular generics.`, this.typeNode);
|
|
1989
1111
|
const ctx = this.createSubResolverContext();
|
|
1990
1112
|
const result = this.primitiveResolver.resolve(this.typeNode, this.parentNode) ?? resolveLiteralType(this.typeNode, ctx) ?? resolveArrayType(this.typeNode, ctx) ?? resolveUnionType(this.typeNode, ctx) ?? resolveIntersectionType(this.typeNode, ctx) ?? resolveObjectLiteralType(this.typeNode, ctx) ?? resolveTupleType(this.typeNode, ctx) ?? resolveMappedType(this.typeNode, ctx) ?? this.resolveConditionalType() ?? resolveTypeOperatorType(this.typeNode, ctx) ?? resolveIndexedAccessType(this.typeNode, ctx) ?? this.resolveTypeReference();
|
|
1991
1113
|
if (!result) this.throwUnknownType();
|
|
@@ -2010,32 +1132,32 @@ var TypeNodeResolver = class TypeNodeResolver extends ResolverBase {
|
|
|
2010
1132
|
return new TypeNodeResolver(typeNode, this.current, parentNode, context, referencer, this.depth + 1).resolve();
|
|
2011
1133
|
}
|
|
2012
1134
|
throwUnknownType() {
|
|
2013
|
-
throw new ResolverError
|
|
1135
|
+
throw new ResolverError(`Unknown type: ${SyntaxKind[this.typeNode.kind]}`, this.typeNode);
|
|
2014
1136
|
}
|
|
2015
1137
|
resolveConditionalType() {
|
|
2016
|
-
if (!
|
|
1138
|
+
if (!isConditionalTypeNode(this.typeNode)) return;
|
|
2017
1139
|
if (Object.keys(this.context).length > 0 && this.referencer) return this.resolveTypeViaChecker(this.referencer);
|
|
2018
1140
|
return this.resolveTypeViaChecker(this.typeNode);
|
|
2019
1141
|
}
|
|
2020
1142
|
resolveTypeReference() {
|
|
2021
|
-
if (this.typeNode.kind !==
|
|
1143
|
+
if (this.typeNode.kind !== SyntaxKind.TypeReference) return;
|
|
2022
1144
|
const typeReference = this.typeNode;
|
|
2023
|
-
if (typeReference.typeName.kind ===
|
|
1145
|
+
if (typeReference.typeName.kind === SyntaxKind.Identifier) {
|
|
2024
1146
|
if (typeReference.typeName.text === "Record" && typeReference.typeArguments) return {
|
|
2025
1147
|
additionalProperties: this.resolveNestedType(typeReference.typeArguments[1], this.parentNode, this.context),
|
|
2026
|
-
typeName:
|
|
1148
|
+
typeName: TypeName.NESTED_OBJECT_LITERAL,
|
|
2027
1149
|
properties: []
|
|
2028
1150
|
};
|
|
2029
1151
|
const specialReference = TypeNodeResolver.resolveSpecialReference(typeReference.typeName);
|
|
2030
1152
|
if (typeof specialReference !== "undefined") return specialReference;
|
|
2031
1153
|
if (typeReference.typeName.text === "Date") return this.getDateType(this.parentNode);
|
|
2032
|
-
if (typeReference.typeName.text === "Buffer" || typeReference.typeName.text === "Readable") return { typeName:
|
|
1154
|
+
if (typeReference.typeName.text === "Buffer" || typeReference.typeName.text === "Readable") return { typeName: TypeName.BUFFER };
|
|
2033
1155
|
if (typeReference.typeName.text === "Array" && typeReference.typeArguments && typeReference.typeArguments.length >= 1) return {
|
|
2034
|
-
typeName:
|
|
1156
|
+
typeName: TypeName.ARRAY,
|
|
2035
1157
|
elementType: this.resolveNestedType(typeReference.typeArguments[0], this.parentNode, this.context)
|
|
2036
1158
|
};
|
|
2037
1159
|
if (typeReference.typeName.text === "Promise" && typeReference.typeArguments && typeReference.typeArguments.length === 1) return this.resolveNestedType(typeReference.typeArguments[0], this.parentNode, this.context);
|
|
2038
|
-
if (typeReference.typeName.text === "String") return { typeName:
|
|
1160
|
+
if (typeReference.typeName.text === "String") return { typeName: TypeName.STRING };
|
|
2039
1161
|
if (this.context[typeReference.typeName.text]) return this.resolveNestedType(this.context[typeReference.typeName.text], this.parentNode, this.context);
|
|
2040
1162
|
if (TypeNodeResolver.isCheckerResolvableUtilityType(typeReference.typeName.text)) return this.resolveUtilityTypeViaChecker(typeReference);
|
|
2041
1163
|
}
|
|
@@ -2052,19 +1174,19 @@ var TypeNodeResolver = class TypeNodeResolver extends ResolverBase {
|
|
|
2052
1174
|
}
|
|
2053
1175
|
}
|
|
2054
1176
|
static CHECKER_RESOLVABLE_UTILITY_TYPES = new Set([
|
|
2055
|
-
|
|
2056
|
-
|
|
2057
|
-
|
|
2058
|
-
|
|
2059
|
-
|
|
2060
|
-
|
|
2061
|
-
|
|
2062
|
-
|
|
2063
|
-
|
|
2064
|
-
|
|
2065
|
-
|
|
2066
|
-
|
|
2067
|
-
|
|
1177
|
+
UtilityTypeName.NON_NULLABLE,
|
|
1178
|
+
UtilityTypeName.OMIT,
|
|
1179
|
+
UtilityTypeName.PARTIAL,
|
|
1180
|
+
UtilityTypeName.READONLY,
|
|
1181
|
+
UtilityTypeName.REQUIRED,
|
|
1182
|
+
UtilityTypeName.PICK,
|
|
1183
|
+
UtilityTypeName.EXTRACT,
|
|
1184
|
+
UtilityTypeName.EXCLUDE,
|
|
1185
|
+
UtilityTypeName.RETURN_TYPE,
|
|
1186
|
+
UtilityTypeName.PARAMETERS,
|
|
1187
|
+
UtilityTypeName.AWAITED,
|
|
1188
|
+
UtilityTypeName.INSTANCE_TYPE,
|
|
1189
|
+
UtilityTypeName.CONSTRUCTOR_PARAMETERS
|
|
2068
1190
|
]);
|
|
2069
1191
|
static isCheckerResolvableUtilityType(name) {
|
|
2070
1192
|
return TypeNodeResolver.CHECKER_RESOLVABLE_UTILITY_TYPES.has(name);
|
|
@@ -2080,9 +1202,9 @@ var TypeNodeResolver = class TypeNodeResolver extends ResolverBase {
|
|
|
2080
1202
|
*/
|
|
2081
1203
|
resolveTypeViaChecker(typeNode) {
|
|
2082
1204
|
const type = this.current.typeChecker.getTypeFromTypeNode(typeNode);
|
|
2083
|
-
const resolvedTypeNode = this.current.typeChecker.typeToTypeNode(type, void 0,
|
|
1205
|
+
const resolvedTypeNode = this.current.typeChecker.typeToTypeNode(type, void 0, NodeBuilderFlags.NoTruncation | NodeBuilderFlags.InTypeAlias);
|
|
2084
1206
|
if (!resolvedTypeNode) return {
|
|
2085
|
-
typeName:
|
|
1207
|
+
typeName: TypeName.TUPLE,
|
|
2086
1208
|
elements: []
|
|
2087
1209
|
};
|
|
2088
1210
|
return this.resolveNestedType(resolvedTypeNode, this.parentNode, this.context);
|
|
@@ -2094,23 +1216,23 @@ var TypeNodeResolver = class TypeNodeResolver extends ResolverBase {
|
|
|
2094
1216
|
*/
|
|
2095
1217
|
hasUnboundContextArgs(typeReference) {
|
|
2096
1218
|
if (!typeReference.typeArguments || Object.keys(this.context).length === 0) return false;
|
|
2097
|
-
return typeReference.typeArguments.some((arg) =>
|
|
1219
|
+
return typeReference.typeArguments.some((arg) => isTypeReferenceNode(arg) && isIdentifier(arg.typeName) && arg.typeName.text in this.context);
|
|
2098
1220
|
}
|
|
2099
1221
|
static resolveSpecialReference(node) {
|
|
2100
1222
|
switch (node.text) {
|
|
2101
1223
|
case "Buffer":
|
|
2102
1224
|
case "DownloadBinaryData":
|
|
2103
|
-
case "DownloadResource": return { typeName:
|
|
1225
|
+
case "DownloadResource": return { typeName: TypeName.BUFFER };
|
|
2104
1226
|
default: return;
|
|
2105
1227
|
}
|
|
2106
1228
|
}
|
|
2107
1229
|
getDateType(parentNode) {
|
|
2108
|
-
if (!parentNode) return { typeName:
|
|
1230
|
+
if (!parentNode) return { typeName: TypeName.DATETIME };
|
|
2109
1231
|
const tags = getJSDocTagNames(parentNode).filter((name) => ["isDate", "isDateTime"].includes(name));
|
|
2110
|
-
if (tags.length === 0) return { typeName:
|
|
1232
|
+
if (tags.length === 0) return { typeName: TypeName.DATETIME };
|
|
2111
1233
|
switch (tags[0]) {
|
|
2112
|
-
case "isDate": return { typeName:
|
|
2113
|
-
default: return { typeName:
|
|
1234
|
+
case "isDate": return { typeName: TypeName.DATE };
|
|
1235
|
+
default: return { typeName: TypeName.DATETIME };
|
|
2114
1236
|
}
|
|
2115
1237
|
}
|
|
2116
1238
|
static getDesignatedModels(nodes, _typeName) {
|
|
@@ -2118,16 +1240,16 @@ var TypeNodeResolver = class TypeNodeResolver extends ResolverBase {
|
|
|
2118
1240
|
}
|
|
2119
1241
|
getEnumerateType(typeName) {
|
|
2120
1242
|
const enumName = typeName.text;
|
|
2121
|
-
let enumNodes = this.current.nodes.filter((node) => node.kind ===
|
|
1243
|
+
let enumNodes = this.current.nodes.filter((node) => node.kind === SyntaxKind.EnumDeclaration && node.name.text === enumName);
|
|
2122
1244
|
if (!enumNodes.length) return;
|
|
2123
1245
|
enumNodes = TypeNodeResolver.getDesignatedModels(enumNodes, enumName);
|
|
2124
|
-
if (enumNodes.length > 1) throw new ResolverError
|
|
1246
|
+
if (enumNodes.length > 1) throw new ResolverError(`Multiple matching enum found for enum ${enumName}; please make enum names unique.`);
|
|
2125
1247
|
const enumDeclaration = enumNodes[0];
|
|
2126
1248
|
const isNotUndefined = (item) => item !== void 0;
|
|
2127
1249
|
const enums = enumDeclaration.members.map(this.current.typeChecker.getConstantValue.bind(this.current.typeChecker)).filter(isNotUndefined);
|
|
2128
1250
|
const enumNames = enumDeclaration.members.map((e) => e.name.getText()).filter(isNotUndefined);
|
|
2129
1251
|
return {
|
|
2130
|
-
typeName:
|
|
1252
|
+
typeName: TypeName.REF_ENUM,
|
|
2131
1253
|
description: this.getNodeDescription(enumDeclaration),
|
|
2132
1254
|
members: enums,
|
|
2133
1255
|
memberNames: enumNames,
|
|
@@ -2137,13 +1259,13 @@ var TypeNodeResolver = class TypeNodeResolver extends ResolverBase {
|
|
|
2137
1259
|
}
|
|
2138
1260
|
getReferenceType(node) {
|
|
2139
1261
|
let type;
|
|
2140
|
-
if (
|
|
2141
|
-
else if (
|
|
2142
|
-
else throw new ResolverError
|
|
1262
|
+
if (isTypeReferenceNode(node)) type = node.typeName;
|
|
1263
|
+
else if (isExpressionWithTypeArguments(node)) type = node.expression;
|
|
1264
|
+
else throw new ResolverError("Can't resolve reference type.");
|
|
2143
1265
|
let resolvableName = node.pos !== -1 ? node.getText() : type.text;
|
|
2144
1266
|
if (node.pos === -1 && "typeArguments" in node && Array.isArray(node.typeArguments)) {
|
|
2145
1267
|
const argumentsString = node.typeArguments.map((arg) => {
|
|
2146
|
-
if (
|
|
1268
|
+
if (isLiteralTypeNode(arg)) return `'${String(getLiteralValue(arg))}'`;
|
|
2147
1269
|
const resolvedType = this.primitiveResolver.resolveSyntaxKind(arg.kind);
|
|
2148
1270
|
if (typeof resolvedType === "undefined") return "any";
|
|
2149
1271
|
return resolvedType;
|
|
@@ -2161,7 +1283,7 @@ var TypeNodeResolver = class TypeNodeResolver extends ResolverBase {
|
|
|
2161
1283
|
const refName = TypeNodeResolver.getRefTypeName(name);
|
|
2162
1284
|
const declarations = this.getModelTypeDeclarations(type);
|
|
2163
1285
|
const referenceTypes = [];
|
|
2164
|
-
for (const declaration of declarations) if (
|
|
1286
|
+
for (const declaration of declarations) if (isTypeAliasDeclaration(declaration)) referenceTypes.push(this.getTypeAliasReference(declaration, name, node));
|
|
2165
1287
|
else if (isEnumDeclaration(declaration)) referenceTypes.push(this.referenceResolver.transformEnum(declaration, refName));
|
|
2166
1288
|
else if (isEnumMember(declaration)) referenceTypes.push(this.referenceResolver.transformEnumMember(declaration, refName));
|
|
2167
1289
|
else referenceTypes.push(this.getModelReference(declaration, name));
|
|
@@ -2172,15 +1294,15 @@ var TypeNodeResolver = class TypeNodeResolver extends ResolverBase {
|
|
|
2172
1294
|
this.current.resolverCache.clearInProgress(name);
|
|
2173
1295
|
}
|
|
2174
1296
|
} catch (err) {
|
|
2175
|
-
throw new ResolverError
|
|
1297
|
+
throw new ResolverError(`There was a problem resolving type of '${name}'.`, node, { cause: err });
|
|
2176
1298
|
}
|
|
2177
1299
|
}
|
|
2178
1300
|
getTypeAliasReference(declaration, name, referencer) {
|
|
2179
1301
|
const refName = TypeNodeResolver.getRefTypeName(name);
|
|
2180
|
-
if (declaration.type.kind ===
|
|
1302
|
+
if (declaration.type.kind === SyntaxKind.TypeReference) {
|
|
2181
1303
|
const innerRef = declaration.type;
|
|
2182
|
-
const innerName =
|
|
2183
|
-
if (!(innerName ===
|
|
1304
|
+
const innerName = isIdentifier(innerRef.typeName) ? innerRef.typeName.text : void 0;
|
|
1305
|
+
if (!(innerName === UtilityTypeName.RECORD || innerName !== void 0 && TypeNodeResolver.isCheckerResolvableUtilityType(innerName))) {
|
|
2184
1306
|
const referenceType = this.getReferenceType(innerRef);
|
|
2185
1307
|
if (referenceType.refName === refName) return referenceType;
|
|
2186
1308
|
}
|
|
@@ -2188,7 +1310,7 @@ var TypeNodeResolver = class TypeNodeResolver extends ResolverBase {
|
|
|
2188
1310
|
const type = this.resolveNestedType(declaration.type, declaration, this.context, this.referencer || referencer);
|
|
2189
1311
|
const example = this.getNodeExample(declaration);
|
|
2190
1312
|
return {
|
|
2191
|
-
typeName:
|
|
1313
|
+
typeName: TypeName.REF_ALIAS,
|
|
2192
1314
|
default: getJSDocTagComment(declaration, "default"),
|
|
2193
1315
|
description: this.getNodeDescription(declaration),
|
|
2194
1316
|
refName,
|
|
@@ -2204,21 +1326,21 @@ var TypeNodeResolver = class TypeNodeResolver extends ResolverBase {
|
|
|
2204
1326
|
const description = this.getNodeDescription(modelType);
|
|
2205
1327
|
const deprecatedDecoratorNames = namesForMarker(this.current.registry, isDeprecatedMarker);
|
|
2206
1328
|
const deprecated = [...tagsForMarker(this.current.registry, isDeprecatedMarker)].some((tag) => hasJSDocTag(modelType, tag)) || [...deprecatedDecoratorNames].some((name) => hasDecoratorNamed(modelType, name));
|
|
2207
|
-
if (!modelType.name) throw new ResolverError
|
|
1329
|
+
if (!modelType.name) throw new ResolverError("Can't get Symbol from anonymous class", modelType);
|
|
2208
1330
|
const type = this.current.typeChecker.getTypeAtLocation(modelType.name);
|
|
2209
1331
|
const toJSON = this.current.typeChecker.getPropertyOfType(type, "toJSON");
|
|
2210
|
-
if (toJSON && toJSON.valueDeclaration && (
|
|
1332
|
+
if (toJSON && toJSON.valueDeclaration && (isMethodDeclaration(toJSON.valueDeclaration) || isMethodSignature(toJSON.valueDeclaration))) {
|
|
2211
1333
|
let nodeType = toJSON.valueDeclaration.type;
|
|
2212
1334
|
if (!nodeType) {
|
|
2213
1335
|
const signature = this.current.typeChecker.getSignatureFromDeclaration(toJSON.valueDeclaration);
|
|
2214
1336
|
if (signature) {
|
|
2215
1337
|
const implicitType = this.current.typeChecker.getReturnTypeOfSignature(signature);
|
|
2216
|
-
nodeType = this.current.typeChecker.typeToTypeNode(implicitType, void 0,
|
|
2217
|
-
} else throw new ResolverError
|
|
1338
|
+
nodeType = this.current.typeChecker.typeToTypeNode(implicitType, void 0, NodeBuilderFlags.NoTruncation);
|
|
1339
|
+
} else throw new ResolverError("Can't get signature from toJson value declaration", modelType);
|
|
2218
1340
|
}
|
|
2219
1341
|
return {
|
|
2220
1342
|
refName: `${TypeNodeResolver.getRefTypeName(name)}Alias`,
|
|
2221
|
-
typeName:
|
|
1343
|
+
typeName: TypeName.REF_ALIAS,
|
|
2222
1344
|
description,
|
|
2223
1345
|
type: this.resolveNestedType(nodeType),
|
|
2224
1346
|
deprecated,
|
|
@@ -2227,11 +1349,13 @@ var TypeNodeResolver = class TypeNodeResolver extends ResolverBase {
|
|
|
2227
1349
|
};
|
|
2228
1350
|
}
|
|
2229
1351
|
const properties = this.getModelProperties(modelType);
|
|
1352
|
+
const additionalProperties = this.getModelAdditionalProperties(modelType);
|
|
1353
|
+
const inheritedProperties = this.getModelInheritedProperties(modelType) || [];
|
|
2230
1354
|
const referenceType = {
|
|
2231
|
-
additionalProperties
|
|
2232
|
-
typeName:
|
|
1355
|
+
additionalProperties,
|
|
1356
|
+
typeName: TypeName.REF_OBJECT,
|
|
2233
1357
|
description,
|
|
2234
|
-
properties:
|
|
1358
|
+
properties: inheritedProperties,
|
|
2235
1359
|
refName: TypeNodeResolver.getRefTypeName(name),
|
|
2236
1360
|
deprecated,
|
|
2237
1361
|
...example && { example }
|
|
@@ -2261,14 +1385,14 @@ var TypeNodeResolver = class TypeNodeResolver extends ResolverBase {
|
|
|
2261
1385
|
this.current.resolverCache.clearInProgress(name);
|
|
2262
1386
|
}
|
|
2263
1387
|
} catch (err) {
|
|
2264
|
-
throw new ResolverError
|
|
1388
|
+
throw new ResolverError(`There was a problem resolving type of '${name}'.`, this.typeNode, { cause: err });
|
|
2265
1389
|
}
|
|
2266
1390
|
}
|
|
2267
1391
|
createCircularDependencyResolver(refName) {
|
|
2268
1392
|
const referenceType = {
|
|
2269
1393
|
deprecated: false,
|
|
2270
1394
|
properties: [],
|
|
2271
|
-
typeName:
|
|
1395
|
+
typeName: TypeName.REF_OBJECT,
|
|
2272
1396
|
refName
|
|
2273
1397
|
};
|
|
2274
1398
|
this.current.registerDependencyResolver((referenceTypes) => {
|
|
@@ -2283,27 +1407,27 @@ var TypeNodeResolver = class TypeNodeResolver extends ResolverBase {
|
|
|
2283
1407
|
}
|
|
2284
1408
|
static nodeIsUsable(node) {
|
|
2285
1409
|
switch (node.kind) {
|
|
2286
|
-
case
|
|
2287
|
-
case
|
|
2288
|
-
case
|
|
2289
|
-
case
|
|
2290
|
-
case
|
|
1410
|
+
case SyntaxKind.InterfaceDeclaration:
|
|
1411
|
+
case SyntaxKind.ClassDeclaration:
|
|
1412
|
+
case SyntaxKind.TypeAliasDeclaration:
|
|
1413
|
+
case SyntaxKind.EnumDeclaration:
|
|
1414
|
+
case SyntaxKind.EnumMember: return true;
|
|
2291
1415
|
default: return false;
|
|
2292
1416
|
}
|
|
2293
1417
|
}
|
|
2294
1418
|
getModelTypeDeclarations(type) {
|
|
2295
|
-
let typeName = type.kind ===
|
|
1419
|
+
let typeName = type.kind === SyntaxKind.Identifier ? type.text : type.right.text;
|
|
2296
1420
|
let symbol = this.getSymbolAtLocation(type);
|
|
2297
|
-
if (!symbol && type.kind ===
|
|
2298
|
-
if (!symbol) throw new ResolverError
|
|
1421
|
+
if (!symbol && type.kind === SyntaxKind.QualifiedName) symbol = this.getSymbolAtLocation(type.left).exports?.get(typeName);
|
|
1422
|
+
if (!symbol) throw new ResolverError(`No symbol found for referenced type ${typeName}.`);
|
|
2299
1423
|
const declarations = symbol.getDeclarations();
|
|
2300
|
-
if (!declarations || declarations.length === 0) throw new ResolverError
|
|
1424
|
+
if (!declarations || declarations.length === 0) throw new ResolverError(`No declarations found for referenced type ${typeName}.`);
|
|
2301
1425
|
if (symbol.escapedName !== typeName && symbol.escapedName !== "default") typeName = symbol.escapedName;
|
|
2302
1426
|
let modelTypes = declarations.filter((node) => {
|
|
2303
1427
|
if (!TypeNodeResolver.nodeIsUsable(node) || !this.current.isExportedNode(node)) return false;
|
|
2304
1428
|
return node.name?.text === typeName;
|
|
2305
1429
|
});
|
|
2306
|
-
if (!modelTypes.length) throw new ResolverError
|
|
1430
|
+
if (!modelTypes.length) throw new 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.`);
|
|
2307
1431
|
if (modelTypes.length > 1) {
|
|
2308
1432
|
modelTypes = modelTypes.filter((modelType) => modelType.getSourceFile().fileName.replace(/\\/g, "/").toLowerCase().indexOf("node_modules/typescript") <= -1);
|
|
2309
1433
|
modelTypes = TypeNodeResolver.getDesignatedModels(modelTypes, typeName);
|
|
@@ -2311,23 +1435,23 @@ var TypeNodeResolver = class TypeNodeResolver extends ResolverBase {
|
|
|
2311
1435
|
return modelTypes;
|
|
2312
1436
|
}
|
|
2313
1437
|
getModelTypeDeclaration(type) {
|
|
2314
|
-
let typeName = type.kind ===
|
|
1438
|
+
let typeName = type.kind === SyntaxKind.Identifier ? type.text : type.right.text;
|
|
2315
1439
|
const symbol = this.getSymbolAtLocation(type);
|
|
2316
1440
|
const declarations = symbol.getDeclarations();
|
|
2317
|
-
if (!declarations || declarations.length === 0) throw new ResolverError
|
|
1441
|
+
if (!declarations || declarations.length === 0) throw new ResolverError(`No models found for referenced type ${typeName}.`);
|
|
2318
1442
|
if (symbol.escapedName !== typeName && symbol.escapedName !== "default") typeName = symbol.escapedName;
|
|
2319
1443
|
let modelTypes = declarations.filter((node) => {
|
|
2320
1444
|
if (!TypeNodeResolver.nodeIsUsable(node) || !this.current.isExportedNode(node)) return false;
|
|
2321
1445
|
return node.name?.text === typeName;
|
|
2322
1446
|
});
|
|
2323
|
-
if (!modelTypes.length) throw new ResolverError
|
|
1447
|
+
if (!modelTypes.length) throw new 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.`);
|
|
2324
1448
|
if (modelTypes.length > 1) {
|
|
2325
1449
|
modelTypes = modelTypes.filter((modelType) => modelType.getSourceFile().fileName.replace(/\\/g, "/").toLowerCase().indexOf("node_modules/typescript") <= -1);
|
|
2326
1450
|
modelTypes = TypeNodeResolver.getDesignatedModels(modelTypes, typeName);
|
|
2327
1451
|
}
|
|
2328
1452
|
if (modelTypes.length > 1) {
|
|
2329
1453
|
const conflicts = modelTypes.map((modelType) => modelType.getSourceFile().fileName).join("\"; \"");
|
|
2330
|
-
throw new ResolverError
|
|
1454
|
+
throw new ResolverError(`Multiple matching models found for referenced type ${typeName}; please make model names unique. Conflicts found: "${conflicts}".`);
|
|
2331
1455
|
}
|
|
2332
1456
|
return modelTypes[0];
|
|
2333
1457
|
}
|
|
@@ -2336,13 +1460,13 @@ var TypeNodeResolver = class TypeNodeResolver extends ResolverBase {
|
|
|
2336
1460
|
}
|
|
2337
1461
|
getSymbolAtLocation(type) {
|
|
2338
1462
|
const symbol = this.current.typeChecker.getSymbolAtLocation(type) || type.symbol;
|
|
2339
|
-
return symbol && this.hasFlag(symbol,
|
|
1463
|
+
return symbol && this.hasFlag(symbol, SymbolFlags.Alias) && this.current.typeChecker.getAliasedSymbol(symbol) || symbol;
|
|
2340
1464
|
}
|
|
2341
1465
|
getModelProperties(node, overrideToken) {
|
|
2342
1466
|
const isIgnored = (e) => hasJSDocTag(e, "ignore");
|
|
2343
|
-
if (
|
|
2344
|
-
const properties = node.members.filter((member) => !isIgnored(member) && member.kind ===
|
|
2345
|
-
const classConstructor = node.members.find((member) =>
|
|
1467
|
+
if (isInterfaceDeclaration(node)) return node.members.filter((member) => !isIgnored(member) && isPropertySignature(member)).map((member) => this.propertyFromSignature(member, overrideToken));
|
|
1468
|
+
const properties = node.members.filter((member) => !isIgnored(member) && member.kind === SyntaxKind.PropertyDeclaration && !this.hasStaticModifier(member) && this.hasPublicModifier(member));
|
|
1469
|
+
const classConstructor = node.members.find((member) => isConstructorDeclaration(member));
|
|
2346
1470
|
if (classConstructor && classConstructor.parameters) {
|
|
2347
1471
|
const constructorProperties = classConstructor.parameters.filter((parameter) => this.isAccessibleParameter(parameter));
|
|
2348
1472
|
properties.push(...constructorProperties);
|
|
@@ -2351,10 +1475,10 @@ var TypeNodeResolver = class TypeNodeResolver extends ResolverBase {
|
|
|
2351
1475
|
}
|
|
2352
1476
|
propertyFromSignature(propertySignature, overrideToken) {
|
|
2353
1477
|
const identifier = propertySignature.name;
|
|
2354
|
-
if (!propertySignature.type) throw new ResolverError
|
|
1478
|
+
if (!propertySignature.type) throw new ResolverError("No valid type found for property declaration.");
|
|
2355
1479
|
let required = !propertySignature.questionToken;
|
|
2356
|
-
if (overrideToken && overrideToken.kind ===
|
|
2357
|
-
else if (overrideToken && overrideToken.kind ===
|
|
1480
|
+
if (overrideToken && overrideToken.kind === SyntaxKind.MinusToken) required = true;
|
|
1481
|
+
else if (overrideToken && overrideToken.kind === SyntaxKind.QuestionToken) required = false;
|
|
2358
1482
|
return {
|
|
2359
1483
|
deprecated: hasJSDocTag(propertySignature, "deprecated"),
|
|
2360
1484
|
default: getJSDocTagComment(propertySignature, "default"),
|
|
@@ -2373,13 +1497,13 @@ var TypeNodeResolver = class TypeNodeResolver extends ResolverBase {
|
|
|
2373
1497
|
let typeNode = propertyDeclaration.type;
|
|
2374
1498
|
if (!typeNode) {
|
|
2375
1499
|
const tsType = this.current.typeChecker.getTypeAtLocation(propertyDeclaration);
|
|
2376
|
-
typeNode = this.current.typeChecker.typeToTypeNode(tsType, void 0,
|
|
1500
|
+
typeNode = this.current.typeChecker.typeToTypeNode(tsType, void 0, NodeBuilderFlags.NoTruncation);
|
|
2377
1501
|
}
|
|
2378
|
-
if (!typeNode) throw new ResolverError
|
|
1502
|
+
if (!typeNode) throw new ResolverError("No valid type found for property declaration.");
|
|
2379
1503
|
const type = this.resolveNestedType(typeNode, propertyDeclaration, this.context, typeNode);
|
|
2380
1504
|
let required = !propertyDeclaration.questionToken && !propertyDeclaration.initializer;
|
|
2381
|
-
if (overrideToken && overrideToken.kind ===
|
|
2382
|
-
else if (overrideToken && overrideToken.kind ===
|
|
1505
|
+
if (overrideToken && overrideToken.kind === SyntaxKind.MinusToken) required = true;
|
|
1506
|
+
else if (overrideToken && overrideToken.kind === SyntaxKind.QuestionToken) required = false;
|
|
2383
1507
|
return {
|
|
2384
1508
|
deprecated: hasJSDocTag(propertyDeclaration, "deprecated"),
|
|
2385
1509
|
default: getInitializerValue(propertyDeclaration.initializer, this.current.typeChecker),
|
|
@@ -2394,11 +1518,11 @@ var TypeNodeResolver = class TypeNodeResolver extends ResolverBase {
|
|
|
2394
1518
|
};
|
|
2395
1519
|
}
|
|
2396
1520
|
getModelAdditionalProperties(node) {
|
|
2397
|
-
if (node.kind ===
|
|
2398
|
-
const indexMember = node.members.find((member) => member.kind ===
|
|
1521
|
+
if (node.kind === SyntaxKind.InterfaceDeclaration) {
|
|
1522
|
+
const indexMember = node.members.find((member) => member.kind === SyntaxKind.IndexSignature);
|
|
2399
1523
|
if (!indexMember) return;
|
|
2400
1524
|
const indexSignatureDeclaration = indexMember;
|
|
2401
|
-
if (this.resolveNestedType(indexSignatureDeclaration.parameters[0].type, this.parentNode, this.context).typeName !== "string") throw new ResolverError
|
|
1525
|
+
if (this.resolveNestedType(indexSignatureDeclaration.parameters[0].type, this.parentNode, this.context).typeName !== "string") throw new ResolverError("Only string indexers are supported.", this.typeNode);
|
|
2402
1526
|
return this.resolveNestedType(indexSignatureDeclaration.type, this.parentNode, this.context);
|
|
2403
1527
|
}
|
|
2404
1528
|
}
|
|
@@ -2409,10 +1533,10 @@ var TypeNodeResolver = class TypeNodeResolver extends ResolverBase {
|
|
|
2409
1533
|
if (typeParameters) for (const [index, typeParameter] of typeParameters.entries()) {
|
|
2410
1534
|
const typeArg = type.typeArguments && type.typeArguments[index];
|
|
2411
1535
|
let resolvedType;
|
|
2412
|
-
if (typeArg &&
|
|
1536
|
+
if (typeArg && isTypeReferenceNode(typeArg) && isIdentifier(typeArg.typeName) && context[typeArg.typeName.text]) resolvedType = context[typeArg.typeName.text];
|
|
2413
1537
|
else if (typeArg) resolvedType = typeArg;
|
|
2414
1538
|
else if (typeParameter.default) resolvedType = typeParameter.default;
|
|
2415
|
-
else throw new ResolverError
|
|
1539
|
+
else throw new ResolverError(`Could not find a value for type parameter ${typeParameter.name.text}`, type);
|
|
2416
1540
|
this.context = {
|
|
2417
1541
|
...this.context,
|
|
2418
1542
|
[typeParameter.name.text]: resolvedType
|
|
@@ -2434,8 +1558,8 @@ var TypeNodeResolver = class TypeNodeResolver extends ResolverBase {
|
|
|
2434
1558
|
if (isRefAliasType(referenceType)) {
|
|
2435
1559
|
let type = referenceType;
|
|
2436
1560
|
while (isRefAliasType(type)) type = type.type;
|
|
2437
|
-
if (type.typeName ===
|
|
2438
|
-
else if (type.typeName ===
|
|
1561
|
+
if (type.typeName === TypeName.REF_OBJECT) properties = [...properties, ...type.properties];
|
|
1562
|
+
else if (type.typeName === TypeName.NESTED_OBJECT_LITERAL) properties = [...properties, ...type.properties];
|
|
2439
1563
|
}
|
|
2440
1564
|
if (isRefObjectType(referenceType)) referenceType.properties.forEach((property) => properties.push(property));
|
|
2441
1565
|
}
|
|
@@ -2748,69 +1872,6 @@ var CacheClient = class {
|
|
|
2748
1872
|
};
|
|
2749
1873
|
const CACHE_KEY_PATTERN = /^[A-Za-z0-9_-]{1,128}$/;
|
|
2750
1874
|
//#endregion
|
|
2751
|
-
//#region src/core/error/generator.ts
|
|
2752
|
-
var GeneratorError$1 = class extends MetadataError {};
|
|
2753
|
-
function isGeneratorError$1(input) {
|
|
2754
|
-
if (!isBaseError(input)) return false;
|
|
2755
|
-
return typeof input.code === "string";
|
|
2756
|
-
}
|
|
2757
|
-
//#endregion
|
|
2758
|
-
//#region src/core/error/generator-codes.ts
|
|
2759
|
-
const GeneratorErrorCode$1 = {
|
|
2760
|
-
CONTROLLER_NO_SOURCE_FILE: "GENERATOR_CONTROLLER_NO_SOURCE_FILE",
|
|
2761
|
-
CONTROLLER_NO_NAME: "GENERATOR_CONTROLLER_NO_NAME",
|
|
2762
|
-
PARAMETER_GENERATION_FAILED: "GENERATOR_PARAMETER_GENERATION_FAILED",
|
|
2763
|
-
BODY_PARAMETER_DUPLICATE: "GENERATOR_BODY_PARAMETER_DUPLICATE",
|
|
2764
|
-
BODY_FORM_CONFLICT: "GENERATOR_BODY_FORM_CONFLICT",
|
|
2765
|
-
STRICT_UNMATCHED_DECORATORS: "GENERATOR_STRICT_UNMATCHED_DECORATORS"
|
|
2766
|
-
};
|
|
2767
|
-
//#endregion
|
|
2768
|
-
//#region src/core/error/parameter.ts
|
|
2769
|
-
var ParameterError$1 = class ParameterError$1 extends MetadataError {
|
|
2770
|
-
static typeUnsupported(context) {
|
|
2771
|
-
const location = context.node ? ParameterError$1.getCurrentLocation(context.node) : void 0;
|
|
2772
|
-
return new ParameterError$1({
|
|
2773
|
-
message: `@${context.decoratorName}('${context.propertyName}') does not support '${context.type.typeName}' type${location ? ` at ${location}` : ""}.`,
|
|
2774
|
-
code: ParameterErrorCode.TYPE_UNSUPPORTED
|
|
2775
|
-
});
|
|
2776
|
-
}
|
|
2777
|
-
static methodUnsupported(context) {
|
|
2778
|
-
const location = context.node ? ParameterError$1.getCurrentLocation(context.node) : void 0;
|
|
2779
|
-
return new ParameterError$1({
|
|
2780
|
-
message: `@${context.decoratorName}('${context.propertyName}') does not support method '${context.method}'${location ? ` at ${location}` : ""}.`,
|
|
2781
|
-
code: ParameterErrorCode.METHOD_UNSUPPORTED
|
|
2782
|
-
});
|
|
2783
|
-
}
|
|
2784
|
-
static invalidPathMatch(context) {
|
|
2785
|
-
const location = context.node ? ParameterError$1.getCurrentLocation(context.node) : void 0;
|
|
2786
|
-
return new ParameterError$1({
|
|
2787
|
-
message: `@${context.decoratorName}('${context.propertyName}') does not exist in path '${context.path}'${location ? ` at ${location}` : ""}.`,
|
|
2788
|
-
code: ParameterErrorCode.PATH_MISMATCH
|
|
2789
|
-
});
|
|
2790
|
-
}
|
|
2791
|
-
static scopeRequired(context) {
|
|
2792
|
-
const location = context.node ? ParameterError$1.getCurrentLocation(context.node) : void 0;
|
|
2793
|
-
return new ParameterError$1({
|
|
2794
|
-
message: `@${context.decoratorName}() requires a scope argument${location ? ` at ${location}` : ""}.`,
|
|
2795
|
-
code: ParameterErrorCode.SCOPE_REQUIRED
|
|
2796
|
-
});
|
|
2797
|
-
}
|
|
2798
|
-
static invalidExampleSchema() {
|
|
2799
|
-
return new ParameterError$1({
|
|
2800
|
-
message: "The @example JSDoc tag contains invalid JSON.",
|
|
2801
|
-
code: ParameterErrorCode.INVALID_EXAMPLE
|
|
2802
|
-
});
|
|
2803
|
-
}
|
|
2804
|
-
static getCurrentLocation(node) {
|
|
2805
|
-
const parts = [];
|
|
2806
|
-
if (isMethodDeclaration(node.parent)) {
|
|
2807
|
-
parts.push(node.parent.name.getText());
|
|
2808
|
-
if (isClassDeclaration(node.parent.parent)) parts.unshift(node.parent.parent.name.text);
|
|
2809
|
-
}
|
|
2810
|
-
return parts.join(".");
|
|
2811
|
-
}
|
|
2812
|
-
};
|
|
2813
|
-
//#endregion
|
|
2814
1875
|
//#region src/app/generator/parameter/module.ts
|
|
2815
1876
|
const BODY_SUPPORTED_METHODS = new Set([
|
|
2816
1877
|
"delete",
|
|
@@ -2820,16 +1881,16 @@ const BODY_SUPPORTED_METHODS = new Set([
|
|
|
2820
1881
|
"get"
|
|
2821
1882
|
]);
|
|
2822
1883
|
const SUPPORTED_LEAF_TYPES = new Set([
|
|
2823
|
-
|
|
2824
|
-
|
|
2825
|
-
|
|
2826
|
-
|
|
2827
|
-
|
|
2828
|
-
|
|
2829
|
-
|
|
2830
|
-
|
|
2831
|
-
|
|
2832
|
-
|
|
1884
|
+
TypeName.STRING,
|
|
1885
|
+
TypeName.INTEGER,
|
|
1886
|
+
TypeName.LONG,
|
|
1887
|
+
TypeName.FLOAT,
|
|
1888
|
+
TypeName.DOUBLE,
|
|
1889
|
+
TypeName.DATE,
|
|
1890
|
+
TypeName.DATETIME,
|
|
1891
|
+
TypeName.BUFFER,
|
|
1892
|
+
TypeName.BOOLEAN,
|
|
1893
|
+
TypeName.ENUM
|
|
2833
1894
|
]);
|
|
2834
1895
|
var ParameterGenerator = class {
|
|
2835
1896
|
parameter;
|
|
@@ -2863,7 +1924,7 @@ var ParameterGenerator = class {
|
|
|
2863
1924
|
}
|
|
2864
1925
|
Object.assign(draft.validators, getDeclarationValidators(this.parameter, parameterName));
|
|
2865
1926
|
if (!draft.in) {
|
|
2866
|
-
if (!BODY_SUPPORTED_METHODS.has(this.method)) throw ParameterError
|
|
1927
|
+
if (!BODY_SUPPORTED_METHODS.has(this.method)) throw ParameterError.methodUnsupported({
|
|
2867
1928
|
decoratorName: "Body",
|
|
2868
1929
|
propertyName: parameterName,
|
|
2869
1930
|
method: this.method,
|
|
@@ -2871,7 +1932,7 @@ var ParameterGenerator = class {
|
|
|
2871
1932
|
});
|
|
2872
1933
|
draft.in = ParamKind.Body;
|
|
2873
1934
|
}
|
|
2874
|
-
if ((draft.in === ParamKind.Body || draft.in === ParamKind.BodyProp) && !BODY_SUPPORTED_METHODS.has(this.method)) throw ParameterError
|
|
1935
|
+
if ((draft.in === ParamKind.Body || draft.in === ParamKind.BodyProp) && !BODY_SUPPORTED_METHODS.has(this.method)) throw ParameterError.methodUnsupported({
|
|
2875
1936
|
decoratorName: "Body",
|
|
2876
1937
|
propertyName: draft.name,
|
|
2877
1938
|
method: this.method,
|
|
@@ -2894,7 +1955,7 @@ var ParameterGenerator = class {
|
|
|
2894
1955
|
return decomposed;
|
|
2895
1956
|
}
|
|
2896
1957
|
if ((kind === ParameterSource.QUERY || kind === ParameterSource.QUERY_PROP) && isArrayType(type)) {
|
|
2897
|
-
if (!this.isLeafTypeSupported(type.elementType)) throw ParameterError
|
|
1958
|
+
if (!this.isLeafTypeSupported(type.elementType)) throw ParameterError.typeUnsupported({
|
|
2898
1959
|
decoratorName: kind === ParameterSource.QUERY ? "Query" : "QueryProp",
|
|
2899
1960
|
propertyName: draft.name,
|
|
2900
1961
|
type: type.elementType,
|
|
@@ -2906,7 +1967,7 @@ var ParameterGenerator = class {
|
|
|
2906
1967
|
type
|
|
2907
1968
|
}];
|
|
2908
1969
|
}
|
|
2909
|
-
if ((kind === ParameterSource.QUERY || kind === ParameterSource.QUERY_PROP) && !this.isLeafOrEnumOrUnion(type)) throw ParameterError
|
|
1970
|
+
if ((kind === ParameterSource.QUERY || kind === ParameterSource.QUERY_PROP) && !this.isLeafOrEnumOrUnion(type)) throw ParameterError.typeUnsupported({
|
|
2910
1971
|
decoratorName: kind === ParameterSource.QUERY ? "Query" : "QueryProp",
|
|
2911
1972
|
propertyName: draft.name,
|
|
2912
1973
|
type,
|
|
@@ -2972,7 +2033,7 @@ var ParameterGenerator = class {
|
|
|
2972
2033
|
return false;
|
|
2973
2034
|
}
|
|
2974
2035
|
validatePathDecomposition(decomposed) {
|
|
2975
|
-
for (const element of decomposed) if (!this.pathContainsParam(element.name)) throw ParameterError
|
|
2036
|
+
for (const element of decomposed) if (!this.pathContainsParam(element.name)) throw ParameterError.invalidPathMatch({
|
|
2976
2037
|
decoratorName: "Path",
|
|
2977
2038
|
propertyName: element.name,
|
|
2978
2039
|
path: this.paths.join(" | "),
|
|
@@ -2981,7 +2042,7 @@ var ParameterGenerator = class {
|
|
|
2981
2042
|
}
|
|
2982
2043
|
validatePathName(name, parameterName) {
|
|
2983
2044
|
const candidate = name || parameterName;
|
|
2984
|
-
if (!this.pathContainsParam(candidate)) throw ParameterError
|
|
2045
|
+
if (!this.pathContainsParam(candidate)) throw ParameterError.invalidPathMatch({
|
|
2985
2046
|
decoratorName: "Path",
|
|
2986
2047
|
propertyName: candidate,
|
|
2987
2048
|
path: this.paths.join(" | "),
|
|
@@ -2998,20 +2059,20 @@ var ParameterGenerator = class {
|
|
|
2998
2059
|
let typeNode = this.parameter.type;
|
|
2999
2060
|
if (!typeNode) {
|
|
3000
2061
|
const t = this.current.typeChecker.getTypeAtLocation(this.parameter);
|
|
3001
|
-
typeNode = this.current.typeChecker.typeToTypeNode(t, void 0,
|
|
2062
|
+
typeNode = this.current.typeChecker.typeToTypeNode(t, void 0, NodeBuilderFlags.NoTruncation);
|
|
3002
2063
|
}
|
|
3003
|
-
if (!typeNode) throw new ParameterError
|
|
2064
|
+
if (!typeNode) throw new ParameterError({ message: `Could not resolve type for parameter '${this.getParameterName()}'.` });
|
|
3004
2065
|
return new TypeNodeResolver(typeNode, this.current, this.parameter).resolve();
|
|
3005
2066
|
}
|
|
3006
2067
|
getParameterName() {
|
|
3007
|
-
if (!
|
|
2068
|
+
if (!isIdentifier(this.parameter.name)) throw new ParameterError({ message: "Destructured parameters are not supported. Use a simple identifier name." });
|
|
3008
2069
|
return this.parameter.name.text;
|
|
3009
2070
|
}
|
|
3010
2071
|
getDescription() {
|
|
3011
2072
|
const symbol = this.current.typeChecker.getSymbolAtLocation(this.parameter.name);
|
|
3012
2073
|
if (symbol) {
|
|
3013
2074
|
const comments = symbol.getDocumentationComment(this.current.typeChecker);
|
|
3014
|
-
if (comments.length > 0) return
|
|
2075
|
+
if (comments.length > 0) return displayPartsToString(comments);
|
|
3015
2076
|
}
|
|
3016
2077
|
return "";
|
|
3017
2078
|
}
|
|
@@ -3036,7 +2097,7 @@ var ParameterGenerator = class {
|
|
|
3036
2097
|
exampleLabels
|
|
3037
2098
|
};
|
|
3038
2099
|
} catch {
|
|
3039
|
-
throw ParameterError
|
|
2100
|
+
throw ParameterError.invalidExampleSchema();
|
|
3040
2101
|
}
|
|
3041
2102
|
}
|
|
3042
2103
|
applyOptions(parameterName) {
|
|
@@ -3136,19 +2197,19 @@ var MethodGenerator = class {
|
|
|
3136
2197
|
}
|
|
3137
2198
|
} catch (e) {
|
|
3138
2199
|
const causeMsg = e instanceof Error ? `: ${e.message}` : "";
|
|
3139
|
-
throw new GeneratorError
|
|
2200
|
+
throw new GeneratorError({
|
|
3140
2201
|
message: `Parameter generation failed for '${controllerId.text}.${methodId.text}' argument index ${i}${causeMsg}`,
|
|
3141
|
-
code: GeneratorErrorCode
|
|
2202
|
+
code: GeneratorErrorCode.PARAMETER_GENERATION_FAILED,
|
|
3142
2203
|
cause: e
|
|
3143
2204
|
});
|
|
3144
2205
|
}
|
|
3145
|
-
if (bodyParameterCount > 1) throw new GeneratorError
|
|
2206
|
+
if (bodyParameterCount > 1) throw new GeneratorError({
|
|
3146
2207
|
message: `Only one body parameter allowed in '${controllerId.text}.${methodId.text}' method.`,
|
|
3147
|
-
code: GeneratorErrorCode
|
|
2208
|
+
code: GeneratorErrorCode.BODY_PARAMETER_DUPLICATE
|
|
3148
2209
|
});
|
|
3149
|
-
if (bodyParameterCount > 0 && formParameterCount > 0) throw new GeneratorError
|
|
2210
|
+
if (bodyParameterCount > 0 && formParameterCount > 0) throw new GeneratorError({
|
|
3150
2211
|
message: `Cannot mix body and form parameters in '${controllerId.text}.${methodId.text}' method.`,
|
|
3151
|
-
code: GeneratorErrorCode
|
|
2212
|
+
code: GeneratorErrorCode.BODY_FORM_CONFLICT
|
|
3152
2213
|
});
|
|
3153
2214
|
return output;
|
|
3154
2215
|
}
|
|
@@ -3186,13 +2247,13 @@ var ControllerGenerator = class {
|
|
|
3186
2247
|
return !!this.node.name;
|
|
3187
2248
|
}
|
|
3188
2249
|
generate() {
|
|
3189
|
-
if (!this.node.parent) throw new GeneratorError
|
|
2250
|
+
if (!this.node.parent) throw new GeneratorError({
|
|
3190
2251
|
message: "Controller node doesn't have a valid parent source file.",
|
|
3191
|
-
code: GeneratorErrorCode
|
|
2252
|
+
code: GeneratorErrorCode.CONTROLLER_NO_SOURCE_FILE
|
|
3192
2253
|
});
|
|
3193
|
-
if (!this.node.name) throw new GeneratorError
|
|
2254
|
+
if (!this.node.name) throw new GeneratorError({
|
|
3194
2255
|
message: "Controller node doesn't have a valid name.",
|
|
3195
|
-
code: GeneratorErrorCode
|
|
2256
|
+
code: GeneratorErrorCode.CONTROLLER_NO_NAME
|
|
3196
2257
|
});
|
|
3197
2258
|
const sourceFile = this.node.parent.getSourceFile();
|
|
3198
2259
|
const draft = newControllerDraft({
|
|
@@ -3254,7 +2315,7 @@ var ControllerGenerator = class {
|
|
|
3254
2315
|
set.add(methodName);
|
|
3255
2316
|
output.push(method);
|
|
3256
2317
|
} catch (error) {
|
|
3257
|
-
if (isResolverError
|
|
2318
|
+
if (isResolverError(error) || isGeneratorError(error) && error.code === GeneratorErrorCode.PARAMETER_GENERATION_FAILED) continue;
|
|
3258
2319
|
throw error;
|
|
3259
2320
|
}
|
|
3260
2321
|
}
|
|
@@ -3374,9 +2435,9 @@ var MetadataGenerator = class {
|
|
|
3374
2435
|
return;
|
|
3375
2436
|
}
|
|
3376
2437
|
const summary = this.formatUnmatchedSummary();
|
|
3377
|
-
if (this.config.strict === "throw") throw new GeneratorError
|
|
2438
|
+
if (this.config.strict === "throw") throw new GeneratorError({
|
|
3378
2439
|
message: summary,
|
|
3379
|
-
code: GeneratorErrorCode
|
|
2440
|
+
code: GeneratorErrorCode.STRICT_UNMATCHED_DECORATORS
|
|
3380
2441
|
});
|
|
3381
2442
|
console.warn(summary);
|
|
3382
2443
|
}
|
|
@@ -3464,11 +2525,6 @@ var MetadataGenerator = class {
|
|
|
3464
2525
|
}
|
|
3465
2526
|
};
|
|
3466
2527
|
//#endregion
|
|
3467
|
-
//#region src/app/generator/metadata/utils.ts
|
|
3468
|
-
function isMetadata(input) {
|
|
3469
|
-
return isObject(input) && hasOwnProperty$1(input, "controllers") && Array.isArray(input.controllers) && hasOwnProperty$1(input, "referenceTypes") && isObject(input.referenceTypes);
|
|
3470
|
-
}
|
|
3471
|
-
//#endregion
|
|
3472
2528
|
//#region src/app/generate.ts
|
|
3473
2529
|
async function generateMetadata(options) {
|
|
3474
2530
|
let compilerOptions;
|
|
@@ -3486,6 +2542,6 @@ async function generateMetadata(options) {
|
|
|
3486
2542
|
}).generate();
|
|
3487
2543
|
}
|
|
3488
2544
|
//#endregion
|
|
3489
|
-
export { CACHE_DEFAULT_MAX_AGE_MS, CACHE_FILE_PREFIX, CACHE_FILE_SUFFIX, CACHE_SCHEMA_VERSION, CacheClient,
|
|
2545
|
+
export { CACHE_DEFAULT_MAX_AGE_MS, CACHE_FILE_PREFIX, CACHE_FILE_SUFFIX, CACHE_SCHEMA_VERSION, CacheClient, ConfigError, ConfigErrorCode, ControllerGenerator, GeneratorError, GeneratorErrorCode, JSDocTagName, MetadataError, MetadataGenerator, MethodGenerator, ParameterError, ParameterErrorCode, ParameterGenerator, PrimitiveResolver, ReferenceResolver, ResolverBase, ResolverCache, ResolverError, TypeNodeResolver, ValidatorError, ValidatorErrorCode, applyDecoratorHandlers, applyJsDocHandlers, buildCacheOptions, buildDecoratorArgument, buildDecoratorSources, buildHandlerContext, buildJsDocHandlerContext, buildJsDocSources, composeCacheKey, findDecoratorByName, findDecoratorsByName, generateMetadata, getDeclarationValidators, getInitializerValue, getJSDoc, getJSDocDescription, getJSDocTagComment, getJSDocTagNames, getJSDocTags, getLiteralValue, getNodeDecorators, getNodeDescription, getNodeExtensions, hasDecoratorNamed, hasInitializer, hasJSDocTag, hasOwnProperty, hashCompilerOptions, hashRegistry, isGeneratorError, isResolverError, isStringArray, loadTSConfig, normalizePath, prettyLocationOfNode, prettyTroubleCause, readNodeDecorators, resolveArrayType, resolveIndexedAccessType, resolveIntersectionType, resolveLiteralType, resolveMappedType, resolveObjectLiteralType, resolveTupleType, resolveTypeOperatorType, resolveUnionType, scanSourceFiles, softLoadTsconfig, toTypeNodeOrFail, transformJSDocComment };
|
|
3490
2546
|
|
|
3491
2547
|
//# sourceMappingURL=index.mjs.map
|