@trapi/metadata 2.0.0-beta.2 → 2.0.0-beta.4
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 +365 -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);
|
|
@@ -1128,13 +314,14 @@ function getInitializerValue(initializer, typeChecker, type) {
|
|
|
1128
314
|
return;
|
|
1129
315
|
}
|
|
1130
316
|
const symbol = typeChecker.getSymbolAtLocation(initializer);
|
|
317
|
+
if (!symbol) return;
|
|
1131
318
|
return getInitializerValue(extractInitializer(symbol.valueDeclaration) || extractInitializer(extractImportSpecifier(symbol)), typeChecker);
|
|
1132
319
|
}
|
|
1133
320
|
}
|
|
1134
321
|
}
|
|
1135
322
|
const hasInitializer = (node) => Object.prototype.hasOwnProperty.call(node, "initializer");
|
|
1136
323
|
const extractInitializer = (valueDeclaration) => valueDeclaration && hasInitializer(valueDeclaration) && valueDeclaration.initializer || void 0;
|
|
1137
|
-
const extractImportSpecifier = (symbol) => symbol?.declarations && symbol.declarations.length > 0 &&
|
|
324
|
+
const extractImportSpecifier = (symbol) => symbol?.declarations && symbol.declarations.length > 0 && isImportSpecifier(symbol.declarations[0]) && symbol.declarations[0] || void 0;
|
|
1138
325
|
//#endregion
|
|
1139
326
|
//#region src/adapters/decorator/typescript/utils.ts
|
|
1140
327
|
/**
|
|
@@ -1143,15 +330,15 @@ const extractImportSpecifier = (symbol) => symbol?.declarations && symbol.declar
|
|
|
1143
330
|
* extension extraction) that only need decorator names + argument values.
|
|
1144
331
|
*/
|
|
1145
332
|
function readNodeDecorators(node, typeChecker) {
|
|
1146
|
-
if (!
|
|
1147
|
-
const decorators =
|
|
333
|
+
if (!canHaveDecorators(node)) return [];
|
|
334
|
+
const decorators = getDecorators(node);
|
|
1148
335
|
if (!decorators || decorators.length === 0) return [];
|
|
1149
336
|
const output = [];
|
|
1150
337
|
for (const decorator of decorators) {
|
|
1151
338
|
const { expression } = decorator;
|
|
1152
339
|
let name;
|
|
1153
340
|
let argumentExpressions = [];
|
|
1154
|
-
if (
|
|
341
|
+
if (isCallExpression(expression)) {
|
|
1155
342
|
argumentExpressions = expression.arguments;
|
|
1156
343
|
name = readDecoratorName$1(expression.expression);
|
|
1157
344
|
} else name = readDecoratorName$1(expression);
|
|
@@ -1173,39 +360,39 @@ function hasDecoratorNamed(node, name, typeChecker) {
|
|
|
1173
360
|
return readNodeDecorators(node, typeChecker).some((d) => d.name === name);
|
|
1174
361
|
}
|
|
1175
362
|
function readDecoratorName$1(expression) {
|
|
1176
|
-
if (
|
|
1177
|
-
if (
|
|
363
|
+
if (isIdentifier(expression)) return expression.text;
|
|
364
|
+
if (isPropertyAccessExpression(expression)) return expression.name.text;
|
|
1178
365
|
}
|
|
1179
366
|
function buildDecoratorArgument(expr, typeChecker) {
|
|
1180
|
-
if (
|
|
367
|
+
if (isStringLiteral(expr) || isNumericLiteral(expr) || isNoSubstitutionTemplateLiteral(expr)) return {
|
|
1181
368
|
raw: getInitializerValue(expr, typeChecker),
|
|
1182
369
|
kind: "literal"
|
|
1183
370
|
};
|
|
1184
|
-
if (expr.kind ===
|
|
371
|
+
if (expr.kind === SyntaxKind.TrueKeyword) return {
|
|
1185
372
|
raw: true,
|
|
1186
373
|
kind: "literal"
|
|
1187
374
|
};
|
|
1188
|
-
if (expr.kind ===
|
|
375
|
+
if (expr.kind === SyntaxKind.FalseKeyword) return {
|
|
1189
376
|
raw: false,
|
|
1190
377
|
kind: "literal"
|
|
1191
378
|
};
|
|
1192
|
-
if (expr.kind ===
|
|
379
|
+
if (expr.kind === SyntaxKind.NullKeyword) return {
|
|
1193
380
|
raw: null,
|
|
1194
381
|
kind: "literal"
|
|
1195
382
|
};
|
|
1196
|
-
if (
|
|
383
|
+
if (isPrefixUnaryExpression(expr) && (expr.operator === SyntaxKind.PlusToken || expr.operator === SyntaxKind.MinusToken) && isNumericLiteral(expr.operand)) return {
|
|
1197
384
|
raw: getInitializerValue(expr, typeChecker),
|
|
1198
385
|
kind: "literal"
|
|
1199
386
|
};
|
|
1200
|
-
if (
|
|
387
|
+
if (isObjectLiteralExpression(expr)) return {
|
|
1201
388
|
raw: getInitializerValue(expr, typeChecker),
|
|
1202
389
|
kind: "object"
|
|
1203
390
|
};
|
|
1204
|
-
if (
|
|
391
|
+
if (isArrayLiteralExpression(expr)) return {
|
|
1205
392
|
raw: getInitializerValue(expr, typeChecker),
|
|
1206
393
|
kind: "array"
|
|
1207
394
|
};
|
|
1208
|
-
if (
|
|
395
|
+
if (isIdentifier(expr) || isPropertyAccessExpression(expr)) {
|
|
1209
396
|
const value = getInitializerValue(expr, typeChecker);
|
|
1210
397
|
if (typeof value !== "undefined") return {
|
|
1211
398
|
raw: value,
|
|
@@ -1224,8 +411,8 @@ function buildDecoratorArgument(expr, typeChecker) {
|
|
|
1224
411
|
//#endregion
|
|
1225
412
|
//#region src/adapters/decorator/typescript/module.ts
|
|
1226
413
|
function buildDecoratorSources(node, options) {
|
|
1227
|
-
if (!
|
|
1228
|
-
const decorators =
|
|
414
|
+
if (!canHaveDecorators(node)) return [];
|
|
415
|
+
const decorators = getDecorators(node);
|
|
1229
416
|
if (!decorators || decorators.length === 0) return [];
|
|
1230
417
|
const output = [];
|
|
1231
418
|
for (const decorator of decorators) {
|
|
@@ -1239,7 +426,7 @@ function buildDecoratorSource(decorator, options) {
|
|
|
1239
426
|
let name;
|
|
1240
427
|
let argumentExpressions = [];
|
|
1241
428
|
let typeArgumentNodes = [];
|
|
1242
|
-
if (
|
|
429
|
+
if (isCallExpression(expression)) {
|
|
1243
430
|
argumentExpressions = expression.arguments;
|
|
1244
431
|
typeArgumentNodes = expression.typeArguments ?? [];
|
|
1245
432
|
name = readDecoratorName(expression.expression);
|
|
@@ -1262,8 +449,8 @@ function buildDecoratorSource(decorator, options) {
|
|
|
1262
449
|
};
|
|
1263
450
|
}
|
|
1264
451
|
function readDecoratorName(expression) {
|
|
1265
|
-
if (
|
|
1266
|
-
if (
|
|
452
|
+
if (isIdentifier(expression)) return expression.text;
|
|
453
|
+
if (isPropertyAccessExpression(expression)) return expression.name.text;
|
|
1267
454
|
}
|
|
1268
455
|
function buildJsDocSources(node, options) {
|
|
1269
456
|
const tags = getJSDocTags(node);
|
|
@@ -1277,10 +464,10 @@ function buildJsDocSource(tag, options) {
|
|
|
1277
464
|
const text = transformJSDocComment(tag.comment);
|
|
1278
465
|
let parameterName;
|
|
1279
466
|
let typeNode;
|
|
1280
|
-
if (
|
|
467
|
+
if (isJSDocParameterTag(tag) || isJSDocPropertyTag(tag)) {
|
|
1281
468
|
if (tag.name) parameterName = readEntityName(tag.name);
|
|
1282
469
|
typeNode = tag.typeExpression?.type;
|
|
1283
|
-
} else if (
|
|
470
|
+
} else if (isJSDocReturnTag(tag) || isJSDocTypeTag(tag) || isJSDocThisTag(tag)) typeNode = tag.typeExpression?.type;
|
|
1284
471
|
const source = {
|
|
1285
472
|
tag: tagName,
|
|
1286
473
|
target: options.target,
|
|
@@ -1295,8 +482,8 @@ function buildJsDocSource(tag, options) {
|
|
|
1295
482
|
return source;
|
|
1296
483
|
}
|
|
1297
484
|
function readEntityName(name) {
|
|
1298
|
-
if (
|
|
1299
|
-
if (
|
|
485
|
+
if (isIdentifier(name)) return name.text;
|
|
486
|
+
if (isQualifiedName(name)) {
|
|
1300
487
|
const left = readEntityName(name.left);
|
|
1301
488
|
return left ? `${left}.${name.right.text}` : name.right.text;
|
|
1302
489
|
}
|
|
@@ -1358,16 +545,6 @@ function applyJsDocHandlers(node, handlers, draft, options) {
|
|
|
1358
545
|
for (const source of sources) for (const handler of handlers) if (matchesJsDoc(handler.match, source)) handler.apply(buildJsDocHandlerContext(source, options), draft);
|
|
1359
546
|
}
|
|
1360
547
|
//#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
548
|
//#region src/adapters/typescript/validator/module.ts
|
|
1372
549
|
function getDeclarationValidators(declaration, name) {
|
|
1373
550
|
if (!declaration.parent) return {};
|
|
@@ -1400,23 +577,23 @@ function getDeclarationValidators(declaration, name) {
|
|
|
1400
577
|
comment = comment.substring(comment.indexOf(" ") + 1).trim();
|
|
1401
578
|
const value = getCommentValue(comment);
|
|
1402
579
|
switch (name) {
|
|
1403
|
-
case
|
|
580
|
+
case ValidatorName.UNIQUE_ITEMS:
|
|
1404
581
|
validators[name] = {
|
|
1405
582
|
message: getErrorMsg(comment, false),
|
|
1406
583
|
value: void 0
|
|
1407
584
|
};
|
|
1408
585
|
break;
|
|
1409
|
-
case
|
|
1410
|
-
case
|
|
1411
|
-
case
|
|
1412
|
-
case
|
|
1413
|
-
case
|
|
1414
|
-
case
|
|
586
|
+
case ValidatorName.MINIMUM:
|
|
587
|
+
case ValidatorName.MAXIMUM:
|
|
588
|
+
case ValidatorName.MIN_ITEMS:
|
|
589
|
+
case ValidatorName.MAX_ITEMS:
|
|
590
|
+
case ValidatorName.MIN_LENGTH:
|
|
591
|
+
case ValidatorName.MAX_LENGTH:
|
|
1415
592
|
{
|
|
1416
593
|
const parsed = Number(value);
|
|
1417
|
-
if (!Number.isFinite(parsed)) throw new ValidatorError
|
|
594
|
+
if (!Number.isFinite(parsed)) throw new ValidatorError({
|
|
1418
595
|
message: `@${name} validator expects a numeric value, got '${value}'.`,
|
|
1419
|
-
code: ValidatorErrorCode
|
|
596
|
+
code: ValidatorErrorCode.EXPECTED_NUMBER
|
|
1420
597
|
});
|
|
1421
598
|
validators[name] = {
|
|
1422
599
|
message: getErrorMsg(comment),
|
|
@@ -1424,21 +601,21 @@ function getDeclarationValidators(declaration, name) {
|
|
|
1424
601
|
};
|
|
1425
602
|
}
|
|
1426
603
|
break;
|
|
1427
|
-
case
|
|
1428
|
-
case
|
|
1429
|
-
if (typeof value !== "string") throw new ValidatorError
|
|
604
|
+
case ValidatorName.MIN_DATE:
|
|
605
|
+
case ValidatorName.MAX_DATE:
|
|
606
|
+
if (typeof value !== "string") throw new ValidatorError({
|
|
1430
607
|
message: `@${name} validator expects a date string, got '${typeof value}'.`,
|
|
1431
|
-
code: ValidatorErrorCode
|
|
608
|
+
code: ValidatorErrorCode.EXPECTED_DATE
|
|
1432
609
|
});
|
|
1433
610
|
validators[name] = {
|
|
1434
611
|
message: getErrorMsg(comment),
|
|
1435
612
|
value
|
|
1436
613
|
};
|
|
1437
614
|
break;
|
|
1438
|
-
case
|
|
1439
|
-
if (typeof value !== "string") throw new ValidatorError
|
|
615
|
+
case ValidatorName.PATTERN:
|
|
616
|
+
if (typeof value !== "string") throw new ValidatorError({
|
|
1440
617
|
message: `@${name} validator expects a string pattern, got '${value}'.`,
|
|
1441
|
-
code: ValidatorErrorCode
|
|
618
|
+
code: ValidatorErrorCode.EXPECTED_STRING
|
|
1442
619
|
});
|
|
1443
620
|
validators[name] = {
|
|
1444
621
|
message: getErrorMsg(comment),
|
|
@@ -1486,64 +663,6 @@ function removeSurroundingQuotes(str) {
|
|
|
1486
663
|
return str;
|
|
1487
664
|
}
|
|
1488
665
|
//#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
666
|
//#region src/adapters/typescript/resolver/extension/module.ts
|
|
1548
667
|
function getNodeExtensions(node, registry) {
|
|
1549
668
|
const names = namesForMarker(registry, isExtensionMarker);
|
|
@@ -1567,9 +686,9 @@ function getNodeExtensions(node, registry) {
|
|
|
1567
686
|
//#endregion
|
|
1568
687
|
//#region src/adapters/typescript/resolver/sub/array.ts
|
|
1569
688
|
function resolveArrayType(typeNode, ctx) {
|
|
1570
|
-
if (!
|
|
689
|
+
if (!isArrayTypeNode(typeNode)) return;
|
|
1571
690
|
return {
|
|
1572
|
-
typeName:
|
|
691
|
+
typeName: TypeName.ARRAY,
|
|
1573
692
|
elementType: ctx.resolveType(typeNode.elementType, ctx.parentNode, ctx.context)
|
|
1574
693
|
};
|
|
1575
694
|
}
|
|
@@ -1613,92 +732,93 @@ function getNodeDescription(node, typeChecker) {
|
|
|
1613
732
|
}
|
|
1614
733
|
function toTypeNodeOrFail(typeChecker, ...args) {
|
|
1615
734
|
const output = typeChecker.typeToTypeNode(...args);
|
|
1616
|
-
if (typeof output === "undefined") throw new ResolverError
|
|
735
|
+
if (typeof output === "undefined") throw new ResolverError("Type could not be transformed to TypeNode.");
|
|
1617
736
|
return output;
|
|
1618
737
|
}
|
|
1619
738
|
//#endregion
|
|
1620
739
|
//#region src/adapters/typescript/resolver/sub/indexed-access.ts
|
|
1621
740
|
function resolveIndexedAccessType(typeNode, ctx) {
|
|
1622
|
-
if (!
|
|
1623
|
-
if (typeNode.indexType.kind ===
|
|
1624
|
-
const numberIndexType = typeNode.indexType.kind ===
|
|
741
|
+
if (!isIndexedAccessTypeNode(typeNode)) return;
|
|
742
|
+
if (typeNode.indexType.kind === SyntaxKind.NumberKeyword || typeNode.indexType.kind === SyntaxKind.StringKeyword) {
|
|
743
|
+
const numberIndexType = typeNode.indexType.kind === SyntaxKind.NumberKeyword;
|
|
1625
744
|
const objectType = ctx.typeChecker.getTypeFromTypeNode(typeNode.objectType);
|
|
1626
745
|
const type = numberIndexType ? objectType.getNumberIndexType() : objectType.getStringIndexType();
|
|
1627
|
-
if (type === void 0) throw new ResolverError
|
|
746
|
+
if (type === void 0) throw new ResolverError(`Could not determine ${numberIndexType ? "number" : "string"} index on ${ctx.typeChecker.typeToString(objectType)}`, typeNode);
|
|
1628
747
|
return ctx.resolveType(toTypeNodeOrFail(ctx.typeChecker, type, void 0, void 0), typeNode, ctx.context, ctx.referencer);
|
|
1629
748
|
}
|
|
1630
|
-
if (
|
|
749
|
+
if (isLiteralTypeNode(typeNode.indexType) && (isStringLiteral(typeNode.indexType.literal) || isNumericLiteral(typeNode.indexType.literal))) {
|
|
1631
750
|
const hasType = (node) => node !== void 0 && Object.prototype.hasOwnProperty.call(node, "type");
|
|
1632
751
|
const symbol = ctx.typeChecker.getPropertyOfType(ctx.typeChecker.getTypeFromTypeNode(typeNode.objectType), typeNode.indexType.literal.text);
|
|
1633
|
-
if (symbol === void 0) throw new ResolverError
|
|
752
|
+
if (symbol === void 0) throw new ResolverError(`Could not determine the keys on ${ctx.typeChecker.typeToString(ctx.typeChecker.getTypeFromTypeNode(typeNode.objectType))}`, typeNode);
|
|
1634
753
|
if (hasType(symbol.valueDeclaration) && symbol.valueDeclaration.type) return ctx.resolveType(symbol.valueDeclaration.type, typeNode, ctx.context, ctx.referencer);
|
|
1635
754
|
const declaration = ctx.typeChecker.getTypeOfSymbolAtLocation(symbol, typeNode.objectType);
|
|
1636
755
|
try {
|
|
1637
756
|
return ctx.resolveType(toTypeNodeOrFail(ctx.typeChecker, declaration, void 0, void 0), typeNode, ctx.context, ctx.referencer);
|
|
1638
757
|
} catch (err) {
|
|
1639
|
-
throw new ResolverError
|
|
758
|
+
throw new ResolverError(`Could not determine the keys on ${ctx.typeChecker.typeToString(declaration)}`, typeNode, { cause: err });
|
|
1640
759
|
}
|
|
1641
760
|
}
|
|
1642
761
|
}
|
|
1643
762
|
//#endregion
|
|
1644
763
|
//#region src/adapters/typescript/resolver/sub/intersection.ts
|
|
1645
764
|
function resolveIntersectionType(typeNode, ctx) {
|
|
1646
|
-
if (!
|
|
765
|
+
if (!isIntersectionTypeNode(typeNode)) return;
|
|
766
|
+
const members = typeNode.types.map((type) => ctx.resolveType(type, ctx.parentNode, ctx.context));
|
|
1647
767
|
return {
|
|
1648
|
-
typeName:
|
|
1649
|
-
members
|
|
768
|
+
typeName: TypeName.INTERSECTION,
|
|
769
|
+
members
|
|
1650
770
|
};
|
|
1651
771
|
}
|
|
1652
772
|
//#endregion
|
|
1653
773
|
//#region src/adapters/typescript/resolver/sub/literal.ts
|
|
1654
774
|
function resolveLiteralType(typeNode, ctx) {
|
|
1655
|
-
if (typeNode.kind ===
|
|
1656
|
-
typeName:
|
|
775
|
+
if (typeNode.kind === SyntaxKind.NullKeyword) return {
|
|
776
|
+
typeName: TypeName.ENUM,
|
|
1657
777
|
members: [null]
|
|
1658
778
|
};
|
|
1659
|
-
if (typeNode.kind ===
|
|
1660
|
-
if (
|
|
1661
|
-
typeName:
|
|
779
|
+
if (typeNode.kind === SyntaxKind.AnyKeyword || typeNode.kind === SyntaxKind.UnknownKeyword) return { typeName: TypeName.ANY };
|
|
780
|
+
if (isLiteralTypeNode(typeNode)) return {
|
|
781
|
+
typeName: TypeName.ENUM,
|
|
1662
782
|
members: [getLiteralValue(typeNode)]
|
|
1663
783
|
};
|
|
1664
|
-
if (typeNode.kind ===
|
|
784
|
+
if (typeNode.kind === SyntaxKind.TemplateLiteralType) {
|
|
1665
785
|
const type = ctx.typeChecker.getTypeFromTypeNode(ctx.referencer || typeNode);
|
|
1666
786
|
if (type.isUnion() && type.types.every((t) => t.isStringLiteral())) return {
|
|
1667
|
-
typeName:
|
|
787
|
+
typeName: TypeName.ENUM,
|
|
1668
788
|
members: type.types.map((t) => t.value)
|
|
1669
789
|
};
|
|
1670
|
-
throw new ResolverError
|
|
790
|
+
throw new ResolverError(`Could not resolve type: ${ctx.typeChecker.typeToString(ctx.typeChecker.getTypeFromTypeNode(typeNode), typeNode)}`, typeNode);
|
|
1671
791
|
}
|
|
1672
|
-
if (
|
|
1673
|
-
if (typeNode.kind ===
|
|
792
|
+
if (isParenthesizedTypeNode(typeNode)) return ctx.resolveType(typeNode.type, typeNode, ctx.context, ctx.referencer);
|
|
793
|
+
if (typeNode.kind === SyntaxKind.ObjectKeyword || isFunctionTypeNode(typeNode)) return { typeName: TypeName.OBJECT };
|
|
1674
794
|
}
|
|
1675
795
|
function getLiteralValue(typeNode) {
|
|
1676
796
|
let value;
|
|
1677
797
|
switch (typeNode.literal.kind) {
|
|
1678
|
-
case
|
|
798
|
+
case SyntaxKind.TrueKeyword:
|
|
1679
799
|
value = true;
|
|
1680
800
|
break;
|
|
1681
|
-
case
|
|
801
|
+
case SyntaxKind.FalseKeyword:
|
|
1682
802
|
value = false;
|
|
1683
803
|
break;
|
|
1684
|
-
case
|
|
804
|
+
case SyntaxKind.StringLiteral:
|
|
1685
805
|
value = typeNode.literal.text;
|
|
1686
806
|
break;
|
|
1687
|
-
case
|
|
807
|
+
case SyntaxKind.NumericLiteral:
|
|
1688
808
|
value = Number.parseFloat(typeNode.literal.text);
|
|
1689
809
|
break;
|
|
1690
|
-
case
|
|
810
|
+
case SyntaxKind.NullKeyword:
|
|
1691
811
|
value = null;
|
|
1692
812
|
break;
|
|
1693
813
|
default: if (Object.prototype.hasOwnProperty.call(typeNode.literal, "text")) value = typeNode.literal.text;
|
|
1694
|
-
else throw new ResolverError
|
|
814
|
+
else throw new ResolverError(`Couldn't resolve literal node: ${typeNode.literal.getText()}`, typeNode.literal);
|
|
1695
815
|
}
|
|
1696
816
|
return value;
|
|
1697
817
|
}
|
|
1698
818
|
//#endregion
|
|
1699
819
|
//#region src/adapters/typescript/resolver/sub/mapped.ts
|
|
1700
820
|
function resolveMappedType(typeNode, ctx) {
|
|
1701
|
-
if (!
|
|
821
|
+
if (!isMappedTypeNode(typeNode) || !ctx.referencer) return;
|
|
1702
822
|
const type = ctx.typeChecker.getTypeFromTypeNode(ctx.referencer);
|
|
1703
823
|
const mappedTypeNode = typeNode;
|
|
1704
824
|
const { typeChecker } = ctx;
|
|
@@ -1706,41 +826,42 @@ function resolveMappedType(typeNode, ctx) {
|
|
|
1706
826
|
const isIgnored = (prop) => {
|
|
1707
827
|
const declaration = getDeclaration(prop);
|
|
1708
828
|
if (prop.getJsDocTags().findIndex((tag) => tag.name === "ignore") >= 0) return true;
|
|
1709
|
-
return !!declaration && !
|
|
829
|
+
return !!declaration && !isPropertyDeclaration(declaration) && !isPropertySignature(declaration) && !isParameter(declaration);
|
|
1710
830
|
};
|
|
831
|
+
const properties = type.getProperties().filter((property) => !isIgnored(property)).map((property) => {
|
|
832
|
+
const declaration = getDeclaration(property);
|
|
833
|
+
const overrideToken = mappedTypeNode.questionToken?.kind === SyntaxKind.PlusToken ? factory.createToken(SyntaxKind.QuestionToken) : mappedTypeNode.questionToken;
|
|
834
|
+
if (declaration && isPropertySignature(declaration)) return {
|
|
835
|
+
...ctx.propertyFromSignature(declaration, overrideToken),
|
|
836
|
+
name: property.getName()
|
|
837
|
+
};
|
|
838
|
+
if (declaration && (isPropertyDeclaration(declaration) || isParameter(declaration))) return {
|
|
839
|
+
...ctx.propertyFromDeclaration(declaration, overrideToken),
|
|
840
|
+
name: property.getName()
|
|
841
|
+
};
|
|
842
|
+
let required = (property.flags & SymbolFlags.Optional) === 0;
|
|
843
|
+
const typeNode2 = toTypeNodeOrFail(typeChecker, typeChecker.getTypeOfSymbolAtLocation(property, typeNode), void 0, NodeBuilderFlags.NoTruncation);
|
|
844
|
+
if (mappedTypeNode.questionToken && mappedTypeNode.questionToken.kind === SyntaxKind.MinusToken) required = true;
|
|
845
|
+
else if (mappedTypeNode.questionToken && (mappedTypeNode.questionToken.kind === SyntaxKind.QuestionToken || mappedTypeNode.questionToken.kind === SyntaxKind.PlusToken)) required = false;
|
|
846
|
+
return {
|
|
847
|
+
name: property.getName(),
|
|
848
|
+
required,
|
|
849
|
+
deprecated: false,
|
|
850
|
+
type: ctx.resolveType(typeNode2, typeNode, ctx.context, ctx.referencer),
|
|
851
|
+
validators: {}
|
|
852
|
+
};
|
|
853
|
+
});
|
|
1711
854
|
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
|
-
})
|
|
855
|
+
typeName: TypeName.NESTED_OBJECT_LITERAL,
|
|
856
|
+
properties
|
|
1736
857
|
};
|
|
1737
858
|
}
|
|
1738
859
|
//#endregion
|
|
1739
860
|
//#region src/adapters/typescript/resolver/sub/object-literal.ts
|
|
1740
861
|
function resolveObjectLiteralType(typeNode, ctx) {
|
|
1741
|
-
if (!
|
|
1742
|
-
const properties = typeNode.members.filter((member) =>
|
|
1743
|
-
if (!propertySignature.type) throw new ResolverError
|
|
862
|
+
if (!isTypeLiteralNode(typeNode)) return;
|
|
863
|
+
const properties = typeNode.members.filter((member) => isPropertySignature(member)).reduce((res, propertySignature) => {
|
|
864
|
+
if (!propertySignature.type) throw new ResolverError("No valid type found for property declaration.", propertySignature);
|
|
1744
865
|
const type = ctx.resolveType(propertySignature.type, propertySignature, ctx.context);
|
|
1745
866
|
return [{
|
|
1746
867
|
deprecated: hasJSDocTag(propertySignature, "deprecated"),
|
|
@@ -1755,16 +876,16 @@ function resolveObjectLiteralType(typeNode, ctx) {
|
|
|
1755
876
|
validators: getDeclarationValidators(propertySignature) || {}
|
|
1756
877
|
}, ...res];
|
|
1757
878
|
}, []);
|
|
1758
|
-
const indexMember = typeNode.members.find((member) =>
|
|
879
|
+
const indexMember = typeNode.members.find((member) => isIndexSignatureDeclaration(member));
|
|
1759
880
|
let additionalType;
|
|
1760
881
|
if (indexMember) {
|
|
1761
882
|
const indexSignatureDeclaration = indexMember;
|
|
1762
|
-
if (!isStringType(ctx.resolveType(indexSignatureDeclaration.parameters[0].type, ctx.parentNode, ctx.context))) throw new ResolverError
|
|
883
|
+
if (!isStringType(ctx.resolveType(indexSignatureDeclaration.parameters[0].type, ctx.parentNode, ctx.context))) throw new ResolverError("Only string indexes are supported.", typeNode);
|
|
1763
884
|
additionalType = ctx.resolveType(indexSignatureDeclaration.type, ctx.parentNode, ctx.context);
|
|
1764
885
|
}
|
|
1765
886
|
return {
|
|
1766
887
|
additionalProperties: indexMember && additionalType,
|
|
1767
|
-
typeName:
|
|
888
|
+
typeName: TypeName.NESTED_OBJECT_LITERAL,
|
|
1768
889
|
properties
|
|
1769
890
|
};
|
|
1770
891
|
}
|
|
@@ -1772,17 +893,17 @@ function getNodeFormat(node) {
|
|
|
1772
893
|
return getJSDocTagComment(node, "format");
|
|
1773
894
|
}
|
|
1774
895
|
function getPropertyName(node) {
|
|
1775
|
-
if (
|
|
1776
|
-
if (
|
|
896
|
+
if (isIdentifier(node.name)) return node.name.text;
|
|
897
|
+
if (isStringLiteral(node.name) || isNumericLiteral(node.name)) return node.name.text;
|
|
1777
898
|
return node.name.getText();
|
|
1778
899
|
}
|
|
1779
900
|
//#endregion
|
|
1780
901
|
//#region src/adapters/typescript/resolver/sub/primitive.ts
|
|
1781
902
|
const NUMERIC_KIND_TO_TYPE_NAME = {
|
|
1782
|
-
[NumericKind.Int]:
|
|
1783
|
-
[NumericKind.Long]:
|
|
1784
|
-
[NumericKind.Float]:
|
|
1785
|
-
[NumericKind.Double]:
|
|
903
|
+
[NumericKind.Int]: TypeName.INTEGER,
|
|
904
|
+
[NumericKind.Long]: TypeName.LONG,
|
|
905
|
+
[NumericKind.Float]: TypeName.FLOAT,
|
|
906
|
+
[NumericKind.Double]: TypeName.DOUBLE
|
|
1786
907
|
};
|
|
1787
908
|
var PrimitiveResolver = class {
|
|
1788
909
|
registry;
|
|
@@ -1792,15 +913,15 @@ var PrimitiveResolver = class {
|
|
|
1792
913
|
resolve(node, parentNode) {
|
|
1793
914
|
const resolved = this.resolveSyntaxKind(node.kind);
|
|
1794
915
|
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:
|
|
916
|
+
if (resolved === "string") return { typeName: TypeName.STRING };
|
|
917
|
+
if (resolved === "void") return { typeName: TypeName.VOID };
|
|
918
|
+
if (resolved === "boolean") return { typeName: TypeName.BOOLEAN };
|
|
919
|
+
if (resolved === "undefined") return { typeName: TypeName.UNDEFINED };
|
|
1799
920
|
if (resolved === "null") return;
|
|
1800
|
-
if (resolved === "never") return { typeName:
|
|
1801
|
-
if (resolved === "bigint") return { typeName:
|
|
921
|
+
if (resolved === "never") return { typeName: TypeName.NEVER };
|
|
922
|
+
if (resolved === "bigint") return { typeName: TypeName.BIGINT };
|
|
1802
923
|
if (resolved === "number") {
|
|
1803
|
-
if (!parentNode) return { typeName:
|
|
924
|
+
if (!parentNode) return { typeName: TypeName.DOUBLE };
|
|
1804
925
|
const presentJsDocTags = new Set(getJSDocTagNames(parentNode).map((tag) => tag.toLowerCase()));
|
|
1805
926
|
for (const kind of [
|
|
1806
927
|
NumericKind.Int,
|
|
@@ -1814,7 +935,7 @@ var PrimitiveResolver = class {
|
|
|
1814
935
|
const jsDocTags = tagsForMarker(this.registry, matchKind);
|
|
1815
936
|
for (const tag of jsDocTags) if (presentJsDocTags.has(tag.toLowerCase())) return { typeName: NUMERIC_KIND_TO_TYPE_NAME[kind] };
|
|
1816
937
|
}
|
|
1817
|
-
return { typeName:
|
|
938
|
+
return { typeName: TypeName.DOUBLE };
|
|
1818
939
|
}
|
|
1819
940
|
}
|
|
1820
941
|
}
|
|
@@ -1842,9 +963,9 @@ var ReferenceResolver = class extends ResolverBase {
|
|
|
1842
963
|
}
|
|
1843
964
|
merge(referenceTypes) {
|
|
1844
965
|
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
|
|
966
|
+
if (referenceTypes.every((refType) => refType.refName === TypeName.REF_ENUM)) return this.mergeManyRefEnums(referenceTypes);
|
|
967
|
+
if (referenceTypes.every((refType) => refType.refName === TypeName.REF_OBJECT)) return this.mergeManyRefObjects(referenceTypes);
|
|
968
|
+
throw new ResolverError(`These resolved type merge rules are not defined: ${JSON.stringify(referenceTypes)}`);
|
|
1848
969
|
}
|
|
1849
970
|
mergeManyRefEnums(many) {
|
|
1850
971
|
let merged = this.mergeRefEnums(many[0], many[1]);
|
|
@@ -1857,7 +978,7 @@ var ReferenceResolver = class extends ResolverBase {
|
|
|
1857
978
|
else if (!second.description) description = first.description;
|
|
1858
979
|
else description = `${first.description}\n${second.description}`;
|
|
1859
980
|
return {
|
|
1860
|
-
typeName:
|
|
981
|
+
typeName: TypeName.REF_ENUM,
|
|
1861
982
|
example: first.example || second.example,
|
|
1862
983
|
description,
|
|
1863
984
|
members: [...first.members || [], ...second.members || []],
|
|
@@ -1881,11 +1002,11 @@ var ReferenceResolver = class extends ResolverBase {
|
|
|
1881
1002
|
if (first.additionalProperties || second.additionalProperties) if (!first.additionalProperties) additionalProperties = second.additionalProperties;
|
|
1882
1003
|
else if (!second.additionalProperties) additionalProperties = first.additionalProperties;
|
|
1883
1004
|
else additionalProperties = {
|
|
1884
|
-
typeName:
|
|
1005
|
+
typeName: TypeName.UNION,
|
|
1885
1006
|
members: [first.additionalProperties, second.additionalProperties]
|
|
1886
1007
|
};
|
|
1887
1008
|
return {
|
|
1888
|
-
typeName:
|
|
1009
|
+
typeName: TypeName.REF_OBJECT,
|
|
1889
1010
|
description,
|
|
1890
1011
|
properties,
|
|
1891
1012
|
additionalProperties,
|
|
@@ -1899,7 +1020,7 @@ var ReferenceResolver = class extends ResolverBase {
|
|
|
1899
1020
|
const enums = declaration.members.map(this.typeChecker.getConstantValue.bind(this.typeChecker)).filter(isNotUndefined);
|
|
1900
1021
|
const enumNames = declaration.members.map((e) => e.name.getText()).filter(isNotUndefined);
|
|
1901
1022
|
return {
|
|
1902
|
-
typeName:
|
|
1023
|
+
typeName: TypeName.REF_ENUM,
|
|
1903
1024
|
description: getNodeDescription(declaration, this.typeChecker),
|
|
1904
1025
|
members: enums,
|
|
1905
1026
|
memberNames: enumNames,
|
|
@@ -1909,7 +1030,7 @@ var ReferenceResolver = class extends ResolverBase {
|
|
|
1909
1030
|
}
|
|
1910
1031
|
transformEnumMember(declaration, enumName) {
|
|
1911
1032
|
return {
|
|
1912
|
-
typeName:
|
|
1033
|
+
typeName: TypeName.REF_ENUM,
|
|
1913
1034
|
refName: enumName,
|
|
1914
1035
|
members: [this.typeChecker.getConstantValue(declaration)],
|
|
1915
1036
|
memberNames: [declaration.name.getText()],
|
|
@@ -1920,40 +1041,42 @@ var ReferenceResolver = class extends ResolverBase {
|
|
|
1920
1041
|
//#endregion
|
|
1921
1042
|
//#region src/adapters/typescript/resolver/sub/tuple.ts
|
|
1922
1043
|
function resolveTupleType(typeNode, ctx) {
|
|
1923
|
-
if (!
|
|
1044
|
+
if (!isTupleTypeNode(typeNode)) return;
|
|
1045
|
+
const elements = typeNode.elements.map((element) => {
|
|
1046
|
+
const isNamed = isNamedTupleMember(element);
|
|
1047
|
+
const actualType = isNamed ? element.type : element;
|
|
1048
|
+
return {
|
|
1049
|
+
type: ctx.resolveType(actualType, ctx.parentNode, ctx.context),
|
|
1050
|
+
...isNamed && { name: element.name.text }
|
|
1051
|
+
};
|
|
1052
|
+
});
|
|
1924
1053
|
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
|
-
})
|
|
1054
|
+
typeName: TypeName.TUPLE,
|
|
1055
|
+
elements
|
|
1934
1056
|
};
|
|
1935
1057
|
}
|
|
1936
1058
|
//#endregion
|
|
1937
1059
|
//#region src/adapters/typescript/resolver/sub/type-operator.ts
|
|
1938
1060
|
function resolveTypeOperatorType(typeNode, ctx) {
|
|
1939
|
-
if (!
|
|
1940
|
-
if (typeNode.operator ===
|
|
1061
|
+
if (!isTypeOperatorNode(typeNode)) return;
|
|
1062
|
+
if (typeNode.operator === SyntaxKind.KeyOfKeyword) {
|
|
1941
1063
|
const type = ctx.typeChecker.getTypeFromTypeNode(typeNode);
|
|
1942
1064
|
try {
|
|
1943
|
-
return ctx.resolveType(toTypeNodeOrFail(ctx.typeChecker, type, void 0,
|
|
1065
|
+
return ctx.resolveType(toTypeNodeOrFail(ctx.typeChecker, type, void 0, NodeBuilderFlags.NoTruncation), typeNode, ctx.context, ctx.referencer);
|
|
1944
1066
|
} catch (err) {
|
|
1945
|
-
throw new ResolverError
|
|
1067
|
+
throw new ResolverError(`Could not determine the keys on ${ctx.typeChecker.typeToString(ctx.typeChecker.getTypeFromTypeNode(typeNode.type))}`, typeNode, { cause: err });
|
|
1946
1068
|
}
|
|
1947
1069
|
}
|
|
1948
|
-
if (typeNode.operator ===
|
|
1070
|
+
if (typeNode.operator === SyntaxKind.ReadonlyKeyword) return ctx.resolveType(typeNode.type, typeNode, ctx.context, ctx.referencer);
|
|
1949
1071
|
}
|
|
1950
1072
|
//#endregion
|
|
1951
1073
|
//#region src/adapters/typescript/resolver/sub/union.ts
|
|
1952
1074
|
function resolveUnionType(typeNode, ctx) {
|
|
1953
|
-
if (!
|
|
1075
|
+
if (!isUnionTypeNode(typeNode)) return;
|
|
1076
|
+
const members = typeNode.types.map((type) => ctx.resolveType(type, ctx.parentNode, ctx.context));
|
|
1954
1077
|
return {
|
|
1955
|
-
typeName:
|
|
1956
|
-
members
|
|
1078
|
+
typeName: TypeName.UNION,
|
|
1079
|
+
members
|
|
1957
1080
|
};
|
|
1958
1081
|
}
|
|
1959
1082
|
//#endregion
|
|
@@ -1985,7 +1108,7 @@ var TypeNodeResolver = class TypeNodeResolver extends ResolverBase {
|
|
|
1985
1108
|
*/
|
|
1986
1109
|
static clearCache() {}
|
|
1987
1110
|
resolve() {
|
|
1988
|
-
if (this.depth > TypeNodeResolver.MAX_DEPTH) throw new ResolverError
|
|
1111
|
+
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
1112
|
const ctx = this.createSubResolverContext();
|
|
1990
1113
|
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
1114
|
if (!result) this.throwUnknownType();
|
|
@@ -2010,32 +1133,32 @@ var TypeNodeResolver = class TypeNodeResolver extends ResolverBase {
|
|
|
2010
1133
|
return new TypeNodeResolver(typeNode, this.current, parentNode, context, referencer, this.depth + 1).resolve();
|
|
2011
1134
|
}
|
|
2012
1135
|
throwUnknownType() {
|
|
2013
|
-
throw new ResolverError
|
|
1136
|
+
throw new ResolverError(`Unknown type: ${SyntaxKind[this.typeNode.kind]}`, this.typeNode);
|
|
2014
1137
|
}
|
|
2015
1138
|
resolveConditionalType() {
|
|
2016
|
-
if (!
|
|
1139
|
+
if (!isConditionalTypeNode(this.typeNode)) return;
|
|
2017
1140
|
if (Object.keys(this.context).length > 0 && this.referencer) return this.resolveTypeViaChecker(this.referencer);
|
|
2018
1141
|
return this.resolveTypeViaChecker(this.typeNode);
|
|
2019
1142
|
}
|
|
2020
1143
|
resolveTypeReference() {
|
|
2021
|
-
if (this.typeNode.kind !==
|
|
1144
|
+
if (this.typeNode.kind !== SyntaxKind.TypeReference) return;
|
|
2022
1145
|
const typeReference = this.typeNode;
|
|
2023
|
-
if (typeReference.typeName.kind ===
|
|
1146
|
+
if (typeReference.typeName.kind === SyntaxKind.Identifier) {
|
|
2024
1147
|
if (typeReference.typeName.text === "Record" && typeReference.typeArguments) return {
|
|
2025
1148
|
additionalProperties: this.resolveNestedType(typeReference.typeArguments[1], this.parentNode, this.context),
|
|
2026
|
-
typeName:
|
|
1149
|
+
typeName: TypeName.NESTED_OBJECT_LITERAL,
|
|
2027
1150
|
properties: []
|
|
2028
1151
|
};
|
|
2029
1152
|
const specialReference = TypeNodeResolver.resolveSpecialReference(typeReference.typeName);
|
|
2030
1153
|
if (typeof specialReference !== "undefined") return specialReference;
|
|
2031
1154
|
if (typeReference.typeName.text === "Date") return this.getDateType(this.parentNode);
|
|
2032
|
-
if (typeReference.typeName.text === "Buffer" || typeReference.typeName.text === "Readable") return { typeName:
|
|
1155
|
+
if (typeReference.typeName.text === "Buffer" || typeReference.typeName.text === "Readable") return { typeName: TypeName.BUFFER };
|
|
2033
1156
|
if (typeReference.typeName.text === "Array" && typeReference.typeArguments && typeReference.typeArguments.length >= 1) return {
|
|
2034
|
-
typeName:
|
|
1157
|
+
typeName: TypeName.ARRAY,
|
|
2035
1158
|
elementType: this.resolveNestedType(typeReference.typeArguments[0], this.parentNode, this.context)
|
|
2036
1159
|
};
|
|
2037
1160
|
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:
|
|
1161
|
+
if (typeReference.typeName.text === "String") return { typeName: TypeName.STRING };
|
|
2039
1162
|
if (this.context[typeReference.typeName.text]) return this.resolveNestedType(this.context[typeReference.typeName.text], this.parentNode, this.context);
|
|
2040
1163
|
if (TypeNodeResolver.isCheckerResolvableUtilityType(typeReference.typeName.text)) return this.resolveUtilityTypeViaChecker(typeReference);
|
|
2041
1164
|
}
|
|
@@ -2052,19 +1175,19 @@ var TypeNodeResolver = class TypeNodeResolver extends ResolverBase {
|
|
|
2052
1175
|
}
|
|
2053
1176
|
}
|
|
2054
1177
|
static CHECKER_RESOLVABLE_UTILITY_TYPES = new Set([
|
|
2055
|
-
|
|
2056
|
-
|
|
2057
|
-
|
|
2058
|
-
|
|
2059
|
-
|
|
2060
|
-
|
|
2061
|
-
|
|
2062
|
-
|
|
2063
|
-
|
|
2064
|
-
|
|
2065
|
-
|
|
2066
|
-
|
|
2067
|
-
|
|
1178
|
+
UtilityTypeName.NON_NULLABLE,
|
|
1179
|
+
UtilityTypeName.OMIT,
|
|
1180
|
+
UtilityTypeName.PARTIAL,
|
|
1181
|
+
UtilityTypeName.READONLY,
|
|
1182
|
+
UtilityTypeName.REQUIRED,
|
|
1183
|
+
UtilityTypeName.PICK,
|
|
1184
|
+
UtilityTypeName.EXTRACT,
|
|
1185
|
+
UtilityTypeName.EXCLUDE,
|
|
1186
|
+
UtilityTypeName.RETURN_TYPE,
|
|
1187
|
+
UtilityTypeName.PARAMETERS,
|
|
1188
|
+
UtilityTypeName.AWAITED,
|
|
1189
|
+
UtilityTypeName.INSTANCE_TYPE,
|
|
1190
|
+
UtilityTypeName.CONSTRUCTOR_PARAMETERS
|
|
2068
1191
|
]);
|
|
2069
1192
|
static isCheckerResolvableUtilityType(name) {
|
|
2070
1193
|
return TypeNodeResolver.CHECKER_RESOLVABLE_UTILITY_TYPES.has(name);
|
|
@@ -2080,9 +1203,9 @@ var TypeNodeResolver = class TypeNodeResolver extends ResolverBase {
|
|
|
2080
1203
|
*/
|
|
2081
1204
|
resolveTypeViaChecker(typeNode) {
|
|
2082
1205
|
const type = this.current.typeChecker.getTypeFromTypeNode(typeNode);
|
|
2083
|
-
const resolvedTypeNode = this.current.typeChecker.typeToTypeNode(type, void 0,
|
|
1206
|
+
const resolvedTypeNode = this.current.typeChecker.typeToTypeNode(type, void 0, NodeBuilderFlags.NoTruncation | NodeBuilderFlags.InTypeAlias);
|
|
2084
1207
|
if (!resolvedTypeNode) return {
|
|
2085
|
-
typeName:
|
|
1208
|
+
typeName: TypeName.TUPLE,
|
|
2086
1209
|
elements: []
|
|
2087
1210
|
};
|
|
2088
1211
|
return this.resolveNestedType(resolvedTypeNode, this.parentNode, this.context);
|
|
@@ -2094,23 +1217,23 @@ var TypeNodeResolver = class TypeNodeResolver extends ResolverBase {
|
|
|
2094
1217
|
*/
|
|
2095
1218
|
hasUnboundContextArgs(typeReference) {
|
|
2096
1219
|
if (!typeReference.typeArguments || Object.keys(this.context).length === 0) return false;
|
|
2097
|
-
return typeReference.typeArguments.some((arg) =>
|
|
1220
|
+
return typeReference.typeArguments.some((arg) => isTypeReferenceNode(arg) && isIdentifier(arg.typeName) && arg.typeName.text in this.context);
|
|
2098
1221
|
}
|
|
2099
1222
|
static resolveSpecialReference(node) {
|
|
2100
1223
|
switch (node.text) {
|
|
2101
1224
|
case "Buffer":
|
|
2102
1225
|
case "DownloadBinaryData":
|
|
2103
|
-
case "DownloadResource": return { typeName:
|
|
1226
|
+
case "DownloadResource": return { typeName: TypeName.BUFFER };
|
|
2104
1227
|
default: return;
|
|
2105
1228
|
}
|
|
2106
1229
|
}
|
|
2107
1230
|
getDateType(parentNode) {
|
|
2108
|
-
if (!parentNode) return { typeName:
|
|
1231
|
+
if (!parentNode) return { typeName: TypeName.DATETIME };
|
|
2109
1232
|
const tags = getJSDocTagNames(parentNode).filter((name) => ["isDate", "isDateTime"].includes(name));
|
|
2110
|
-
if (tags.length === 0) return { typeName:
|
|
1233
|
+
if (tags.length === 0) return { typeName: TypeName.DATETIME };
|
|
2111
1234
|
switch (tags[0]) {
|
|
2112
|
-
case "isDate": return { typeName:
|
|
2113
|
-
default: return { typeName:
|
|
1235
|
+
case "isDate": return { typeName: TypeName.DATE };
|
|
1236
|
+
default: return { typeName: TypeName.DATETIME };
|
|
2114
1237
|
}
|
|
2115
1238
|
}
|
|
2116
1239
|
static getDesignatedModels(nodes, _typeName) {
|
|
@@ -2118,16 +1241,16 @@ var TypeNodeResolver = class TypeNodeResolver extends ResolverBase {
|
|
|
2118
1241
|
}
|
|
2119
1242
|
getEnumerateType(typeName) {
|
|
2120
1243
|
const enumName = typeName.text;
|
|
2121
|
-
let enumNodes = this.current.nodes.filter((node) => node.kind ===
|
|
1244
|
+
let enumNodes = this.current.nodes.filter((node) => node.kind === SyntaxKind.EnumDeclaration && node.name.text === enumName);
|
|
2122
1245
|
if (!enumNodes.length) return;
|
|
2123
1246
|
enumNodes = TypeNodeResolver.getDesignatedModels(enumNodes, enumName);
|
|
2124
|
-
if (enumNodes.length > 1) throw new ResolverError
|
|
1247
|
+
if (enumNodes.length > 1) throw new ResolverError(`Multiple matching enum found for enum ${enumName}; please make enum names unique.`);
|
|
2125
1248
|
const enumDeclaration = enumNodes[0];
|
|
2126
1249
|
const isNotUndefined = (item) => item !== void 0;
|
|
2127
1250
|
const enums = enumDeclaration.members.map(this.current.typeChecker.getConstantValue.bind(this.current.typeChecker)).filter(isNotUndefined);
|
|
2128
1251
|
const enumNames = enumDeclaration.members.map((e) => e.name.getText()).filter(isNotUndefined);
|
|
2129
1252
|
return {
|
|
2130
|
-
typeName:
|
|
1253
|
+
typeName: TypeName.REF_ENUM,
|
|
2131
1254
|
description: this.getNodeDescription(enumDeclaration),
|
|
2132
1255
|
members: enums,
|
|
2133
1256
|
memberNames: enumNames,
|
|
@@ -2137,13 +1260,13 @@ var TypeNodeResolver = class TypeNodeResolver extends ResolverBase {
|
|
|
2137
1260
|
}
|
|
2138
1261
|
getReferenceType(node) {
|
|
2139
1262
|
let type;
|
|
2140
|
-
if (
|
|
2141
|
-
else if (
|
|
2142
|
-
else throw new ResolverError
|
|
1263
|
+
if (isTypeReferenceNode(node)) type = node.typeName;
|
|
1264
|
+
else if (isExpressionWithTypeArguments(node)) type = node.expression;
|
|
1265
|
+
else throw new ResolverError("Can't resolve reference type.");
|
|
2143
1266
|
let resolvableName = node.pos !== -1 ? node.getText() : type.text;
|
|
2144
1267
|
if (node.pos === -1 && "typeArguments" in node && Array.isArray(node.typeArguments)) {
|
|
2145
1268
|
const argumentsString = node.typeArguments.map((arg) => {
|
|
2146
|
-
if (
|
|
1269
|
+
if (isLiteralTypeNode(arg)) return `'${String(getLiteralValue(arg))}'`;
|
|
2147
1270
|
const resolvedType = this.primitiveResolver.resolveSyntaxKind(arg.kind);
|
|
2148
1271
|
if (typeof resolvedType === "undefined") return "any";
|
|
2149
1272
|
return resolvedType;
|
|
@@ -2161,7 +1284,7 @@ var TypeNodeResolver = class TypeNodeResolver extends ResolverBase {
|
|
|
2161
1284
|
const refName = TypeNodeResolver.getRefTypeName(name);
|
|
2162
1285
|
const declarations = this.getModelTypeDeclarations(type);
|
|
2163
1286
|
const referenceTypes = [];
|
|
2164
|
-
for (const declaration of declarations) if (
|
|
1287
|
+
for (const declaration of declarations) if (isTypeAliasDeclaration(declaration)) referenceTypes.push(this.getTypeAliasReference(declaration, name, node));
|
|
2165
1288
|
else if (isEnumDeclaration(declaration)) referenceTypes.push(this.referenceResolver.transformEnum(declaration, refName));
|
|
2166
1289
|
else if (isEnumMember(declaration)) referenceTypes.push(this.referenceResolver.transformEnumMember(declaration, refName));
|
|
2167
1290
|
else referenceTypes.push(this.getModelReference(declaration, name));
|
|
@@ -2172,15 +1295,15 @@ var TypeNodeResolver = class TypeNodeResolver extends ResolverBase {
|
|
|
2172
1295
|
this.current.resolverCache.clearInProgress(name);
|
|
2173
1296
|
}
|
|
2174
1297
|
} catch (err) {
|
|
2175
|
-
throw new ResolverError
|
|
1298
|
+
throw new ResolverError(`There was a problem resolving type of '${name}'.`, node, { cause: err });
|
|
2176
1299
|
}
|
|
2177
1300
|
}
|
|
2178
1301
|
getTypeAliasReference(declaration, name, referencer) {
|
|
2179
1302
|
const refName = TypeNodeResolver.getRefTypeName(name);
|
|
2180
|
-
if (declaration.type.kind ===
|
|
1303
|
+
if (declaration.type.kind === SyntaxKind.TypeReference) {
|
|
2181
1304
|
const innerRef = declaration.type;
|
|
2182
|
-
const innerName =
|
|
2183
|
-
if (!(innerName ===
|
|
1305
|
+
const innerName = isIdentifier(innerRef.typeName) ? innerRef.typeName.text : void 0;
|
|
1306
|
+
if (!(innerName === UtilityTypeName.RECORD || innerName !== void 0 && TypeNodeResolver.isCheckerResolvableUtilityType(innerName))) {
|
|
2184
1307
|
const referenceType = this.getReferenceType(innerRef);
|
|
2185
1308
|
if (referenceType.refName === refName) return referenceType;
|
|
2186
1309
|
}
|
|
@@ -2188,7 +1311,7 @@ var TypeNodeResolver = class TypeNodeResolver extends ResolverBase {
|
|
|
2188
1311
|
const type = this.resolveNestedType(declaration.type, declaration, this.context, this.referencer || referencer);
|
|
2189
1312
|
const example = this.getNodeExample(declaration);
|
|
2190
1313
|
return {
|
|
2191
|
-
typeName:
|
|
1314
|
+
typeName: TypeName.REF_ALIAS,
|
|
2192
1315
|
default: getJSDocTagComment(declaration, "default"),
|
|
2193
1316
|
description: this.getNodeDescription(declaration),
|
|
2194
1317
|
refName,
|
|
@@ -2204,21 +1327,21 @@ var TypeNodeResolver = class TypeNodeResolver extends ResolverBase {
|
|
|
2204
1327
|
const description = this.getNodeDescription(modelType);
|
|
2205
1328
|
const deprecatedDecoratorNames = namesForMarker(this.current.registry, isDeprecatedMarker);
|
|
2206
1329
|
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
|
|
1330
|
+
if (!modelType.name) throw new ResolverError("Can't get Symbol from anonymous class", modelType);
|
|
2208
1331
|
const type = this.current.typeChecker.getTypeAtLocation(modelType.name);
|
|
2209
1332
|
const toJSON = this.current.typeChecker.getPropertyOfType(type, "toJSON");
|
|
2210
|
-
if (toJSON && toJSON.valueDeclaration && (
|
|
1333
|
+
if (toJSON && toJSON.valueDeclaration && (isMethodDeclaration(toJSON.valueDeclaration) || isMethodSignature(toJSON.valueDeclaration))) {
|
|
2211
1334
|
let nodeType = toJSON.valueDeclaration.type;
|
|
2212
1335
|
if (!nodeType) {
|
|
2213
1336
|
const signature = this.current.typeChecker.getSignatureFromDeclaration(toJSON.valueDeclaration);
|
|
2214
1337
|
if (signature) {
|
|
2215
1338
|
const implicitType = this.current.typeChecker.getReturnTypeOfSignature(signature);
|
|
2216
|
-
nodeType = this.current.typeChecker.typeToTypeNode(implicitType, void 0,
|
|
2217
|
-
} else throw new ResolverError
|
|
1339
|
+
nodeType = this.current.typeChecker.typeToTypeNode(implicitType, void 0, NodeBuilderFlags.NoTruncation);
|
|
1340
|
+
} else throw new ResolverError("Can't get signature from toJson value declaration", modelType);
|
|
2218
1341
|
}
|
|
2219
1342
|
return {
|
|
2220
1343
|
refName: `${TypeNodeResolver.getRefTypeName(name)}Alias`,
|
|
2221
|
-
typeName:
|
|
1344
|
+
typeName: TypeName.REF_ALIAS,
|
|
2222
1345
|
description,
|
|
2223
1346
|
type: this.resolveNestedType(nodeType),
|
|
2224
1347
|
deprecated,
|
|
@@ -2227,11 +1350,13 @@ var TypeNodeResolver = class TypeNodeResolver extends ResolverBase {
|
|
|
2227
1350
|
};
|
|
2228
1351
|
}
|
|
2229
1352
|
const properties = this.getModelProperties(modelType);
|
|
1353
|
+
const additionalProperties = this.getModelAdditionalProperties(modelType);
|
|
1354
|
+
const inheritedProperties = this.getModelInheritedProperties(modelType) || [];
|
|
2230
1355
|
const referenceType = {
|
|
2231
|
-
additionalProperties
|
|
2232
|
-
typeName:
|
|
1356
|
+
additionalProperties,
|
|
1357
|
+
typeName: TypeName.REF_OBJECT,
|
|
2233
1358
|
description,
|
|
2234
|
-
properties:
|
|
1359
|
+
properties: inheritedProperties,
|
|
2235
1360
|
refName: TypeNodeResolver.getRefTypeName(name),
|
|
2236
1361
|
deprecated,
|
|
2237
1362
|
...example && { example }
|
|
@@ -2261,14 +1386,14 @@ var TypeNodeResolver = class TypeNodeResolver extends ResolverBase {
|
|
|
2261
1386
|
this.current.resolverCache.clearInProgress(name);
|
|
2262
1387
|
}
|
|
2263
1388
|
} catch (err) {
|
|
2264
|
-
throw new ResolverError
|
|
1389
|
+
throw new ResolverError(`There was a problem resolving type of '${name}'.`, this.typeNode, { cause: err });
|
|
2265
1390
|
}
|
|
2266
1391
|
}
|
|
2267
1392
|
createCircularDependencyResolver(refName) {
|
|
2268
1393
|
const referenceType = {
|
|
2269
1394
|
deprecated: false,
|
|
2270
1395
|
properties: [],
|
|
2271
|
-
typeName:
|
|
1396
|
+
typeName: TypeName.REF_OBJECT,
|
|
2272
1397
|
refName
|
|
2273
1398
|
};
|
|
2274
1399
|
this.current.registerDependencyResolver((referenceTypes) => {
|
|
@@ -2283,27 +1408,27 @@ var TypeNodeResolver = class TypeNodeResolver extends ResolverBase {
|
|
|
2283
1408
|
}
|
|
2284
1409
|
static nodeIsUsable(node) {
|
|
2285
1410
|
switch (node.kind) {
|
|
2286
|
-
case
|
|
2287
|
-
case
|
|
2288
|
-
case
|
|
2289
|
-
case
|
|
2290
|
-
case
|
|
1411
|
+
case SyntaxKind.InterfaceDeclaration:
|
|
1412
|
+
case SyntaxKind.ClassDeclaration:
|
|
1413
|
+
case SyntaxKind.TypeAliasDeclaration:
|
|
1414
|
+
case SyntaxKind.EnumDeclaration:
|
|
1415
|
+
case SyntaxKind.EnumMember: return true;
|
|
2291
1416
|
default: return false;
|
|
2292
1417
|
}
|
|
2293
1418
|
}
|
|
2294
1419
|
getModelTypeDeclarations(type) {
|
|
2295
|
-
let typeName = type.kind ===
|
|
1420
|
+
let typeName = type.kind === SyntaxKind.Identifier ? type.text : type.right.text;
|
|
2296
1421
|
let symbol = this.getSymbolAtLocation(type);
|
|
2297
|
-
if (!symbol && type.kind ===
|
|
2298
|
-
if (!symbol) throw new ResolverError
|
|
1422
|
+
if (!symbol && type.kind === SyntaxKind.QualifiedName) symbol = this.getSymbolAtLocation(type.left).exports?.get(typeName);
|
|
1423
|
+
if (!symbol) throw new ResolverError(`No symbol found for referenced type ${typeName}.`);
|
|
2299
1424
|
const declarations = symbol.getDeclarations();
|
|
2300
|
-
if (!declarations || declarations.length === 0) throw new ResolverError
|
|
1425
|
+
if (!declarations || declarations.length === 0) throw new ResolverError(`No declarations found for referenced type ${typeName}.`);
|
|
2301
1426
|
if (symbol.escapedName !== typeName && symbol.escapedName !== "default") typeName = symbol.escapedName;
|
|
2302
1427
|
let modelTypes = declarations.filter((node) => {
|
|
2303
1428
|
if (!TypeNodeResolver.nodeIsUsable(node) || !this.current.isExportedNode(node)) return false;
|
|
2304
1429
|
return node.name?.text === typeName;
|
|
2305
1430
|
});
|
|
2306
|
-
if (!modelTypes.length) throw new ResolverError
|
|
1431
|
+
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
1432
|
if (modelTypes.length > 1) {
|
|
2308
1433
|
modelTypes = modelTypes.filter((modelType) => modelType.getSourceFile().fileName.replace(/\\/g, "/").toLowerCase().indexOf("node_modules/typescript") <= -1);
|
|
2309
1434
|
modelTypes = TypeNodeResolver.getDesignatedModels(modelTypes, typeName);
|
|
@@ -2311,23 +1436,23 @@ var TypeNodeResolver = class TypeNodeResolver extends ResolverBase {
|
|
|
2311
1436
|
return modelTypes;
|
|
2312
1437
|
}
|
|
2313
1438
|
getModelTypeDeclaration(type) {
|
|
2314
|
-
let typeName = type.kind ===
|
|
1439
|
+
let typeName = type.kind === SyntaxKind.Identifier ? type.text : type.right.text;
|
|
2315
1440
|
const symbol = this.getSymbolAtLocation(type);
|
|
2316
1441
|
const declarations = symbol.getDeclarations();
|
|
2317
|
-
if (!declarations || declarations.length === 0) throw new ResolverError
|
|
1442
|
+
if (!declarations || declarations.length === 0) throw new ResolverError(`No models found for referenced type ${typeName}.`);
|
|
2318
1443
|
if (symbol.escapedName !== typeName && symbol.escapedName !== "default") typeName = symbol.escapedName;
|
|
2319
1444
|
let modelTypes = declarations.filter((node) => {
|
|
2320
1445
|
if (!TypeNodeResolver.nodeIsUsable(node) || !this.current.isExportedNode(node)) return false;
|
|
2321
1446
|
return node.name?.text === typeName;
|
|
2322
1447
|
});
|
|
2323
|
-
if (!modelTypes.length) throw new ResolverError
|
|
1448
|
+
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
1449
|
if (modelTypes.length > 1) {
|
|
2325
1450
|
modelTypes = modelTypes.filter((modelType) => modelType.getSourceFile().fileName.replace(/\\/g, "/").toLowerCase().indexOf("node_modules/typescript") <= -1);
|
|
2326
1451
|
modelTypes = TypeNodeResolver.getDesignatedModels(modelTypes, typeName);
|
|
2327
1452
|
}
|
|
2328
1453
|
if (modelTypes.length > 1) {
|
|
2329
1454
|
const conflicts = modelTypes.map((modelType) => modelType.getSourceFile().fileName).join("\"; \"");
|
|
2330
|
-
throw new ResolverError
|
|
1455
|
+
throw new ResolverError(`Multiple matching models found for referenced type ${typeName}; please make model names unique. Conflicts found: "${conflicts}".`);
|
|
2331
1456
|
}
|
|
2332
1457
|
return modelTypes[0];
|
|
2333
1458
|
}
|
|
@@ -2336,13 +1461,13 @@ var TypeNodeResolver = class TypeNodeResolver extends ResolverBase {
|
|
|
2336
1461
|
}
|
|
2337
1462
|
getSymbolAtLocation(type) {
|
|
2338
1463
|
const symbol = this.current.typeChecker.getSymbolAtLocation(type) || type.symbol;
|
|
2339
|
-
return symbol && this.hasFlag(symbol,
|
|
1464
|
+
return symbol && this.hasFlag(symbol, SymbolFlags.Alias) && this.current.typeChecker.getAliasedSymbol(symbol) || symbol;
|
|
2340
1465
|
}
|
|
2341
1466
|
getModelProperties(node, overrideToken) {
|
|
2342
1467
|
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) =>
|
|
1468
|
+
if (isInterfaceDeclaration(node)) return node.members.filter((member) => !isIgnored(member) && isPropertySignature(member)).map((member) => this.propertyFromSignature(member, overrideToken));
|
|
1469
|
+
const properties = node.members.filter((member) => !isIgnored(member) && member.kind === SyntaxKind.PropertyDeclaration && !this.hasStaticModifier(member) && this.hasPublicModifier(member));
|
|
1470
|
+
const classConstructor = node.members.find((member) => isConstructorDeclaration(member));
|
|
2346
1471
|
if (classConstructor && classConstructor.parameters) {
|
|
2347
1472
|
const constructorProperties = classConstructor.parameters.filter((parameter) => this.isAccessibleParameter(parameter));
|
|
2348
1473
|
properties.push(...constructorProperties);
|
|
@@ -2351,10 +1476,10 @@ var TypeNodeResolver = class TypeNodeResolver extends ResolverBase {
|
|
|
2351
1476
|
}
|
|
2352
1477
|
propertyFromSignature(propertySignature, overrideToken) {
|
|
2353
1478
|
const identifier = propertySignature.name;
|
|
2354
|
-
if (!propertySignature.type) throw new ResolverError
|
|
1479
|
+
if (!propertySignature.type) throw new ResolverError("No valid type found for property declaration.");
|
|
2355
1480
|
let required = !propertySignature.questionToken;
|
|
2356
|
-
if (overrideToken && overrideToken.kind ===
|
|
2357
|
-
else if (overrideToken && overrideToken.kind ===
|
|
1481
|
+
if (overrideToken && overrideToken.kind === SyntaxKind.MinusToken) required = true;
|
|
1482
|
+
else if (overrideToken && overrideToken.kind === SyntaxKind.QuestionToken) required = false;
|
|
2358
1483
|
return {
|
|
2359
1484
|
deprecated: hasJSDocTag(propertySignature, "deprecated"),
|
|
2360
1485
|
default: getJSDocTagComment(propertySignature, "default"),
|
|
@@ -2373,13 +1498,13 @@ var TypeNodeResolver = class TypeNodeResolver extends ResolverBase {
|
|
|
2373
1498
|
let typeNode = propertyDeclaration.type;
|
|
2374
1499
|
if (!typeNode) {
|
|
2375
1500
|
const tsType = this.current.typeChecker.getTypeAtLocation(propertyDeclaration);
|
|
2376
|
-
typeNode = this.current.typeChecker.typeToTypeNode(tsType, void 0,
|
|
1501
|
+
typeNode = this.current.typeChecker.typeToTypeNode(tsType, void 0, NodeBuilderFlags.NoTruncation);
|
|
2377
1502
|
}
|
|
2378
|
-
if (!typeNode) throw new ResolverError
|
|
1503
|
+
if (!typeNode) throw new ResolverError("No valid type found for property declaration.");
|
|
2379
1504
|
const type = this.resolveNestedType(typeNode, propertyDeclaration, this.context, typeNode);
|
|
2380
1505
|
let required = !propertyDeclaration.questionToken && !propertyDeclaration.initializer;
|
|
2381
|
-
if (overrideToken && overrideToken.kind ===
|
|
2382
|
-
else if (overrideToken && overrideToken.kind ===
|
|
1506
|
+
if (overrideToken && overrideToken.kind === SyntaxKind.MinusToken) required = true;
|
|
1507
|
+
else if (overrideToken && overrideToken.kind === SyntaxKind.QuestionToken) required = false;
|
|
2383
1508
|
return {
|
|
2384
1509
|
deprecated: hasJSDocTag(propertyDeclaration, "deprecated"),
|
|
2385
1510
|
default: getInitializerValue(propertyDeclaration.initializer, this.current.typeChecker),
|
|
@@ -2394,11 +1519,11 @@ var TypeNodeResolver = class TypeNodeResolver extends ResolverBase {
|
|
|
2394
1519
|
};
|
|
2395
1520
|
}
|
|
2396
1521
|
getModelAdditionalProperties(node) {
|
|
2397
|
-
if (node.kind ===
|
|
2398
|
-
const indexMember = node.members.find((member) => member.kind ===
|
|
1522
|
+
if (node.kind === SyntaxKind.InterfaceDeclaration) {
|
|
1523
|
+
const indexMember = node.members.find((member) => member.kind === SyntaxKind.IndexSignature);
|
|
2399
1524
|
if (!indexMember) return;
|
|
2400
1525
|
const indexSignatureDeclaration = indexMember;
|
|
2401
|
-
if (this.resolveNestedType(indexSignatureDeclaration.parameters[0].type, this.parentNode, this.context).typeName !== "string") throw new ResolverError
|
|
1526
|
+
if (this.resolveNestedType(indexSignatureDeclaration.parameters[0].type, this.parentNode, this.context).typeName !== "string") throw new ResolverError("Only string indexers are supported.", this.typeNode);
|
|
2402
1527
|
return this.resolveNestedType(indexSignatureDeclaration.type, this.parentNode, this.context);
|
|
2403
1528
|
}
|
|
2404
1529
|
}
|
|
@@ -2409,10 +1534,10 @@ var TypeNodeResolver = class TypeNodeResolver extends ResolverBase {
|
|
|
2409
1534
|
if (typeParameters) for (const [index, typeParameter] of typeParameters.entries()) {
|
|
2410
1535
|
const typeArg = type.typeArguments && type.typeArguments[index];
|
|
2411
1536
|
let resolvedType;
|
|
2412
|
-
if (typeArg &&
|
|
1537
|
+
if (typeArg && isTypeReferenceNode(typeArg) && isIdentifier(typeArg.typeName) && context[typeArg.typeName.text]) resolvedType = context[typeArg.typeName.text];
|
|
2413
1538
|
else if (typeArg) resolvedType = typeArg;
|
|
2414
1539
|
else if (typeParameter.default) resolvedType = typeParameter.default;
|
|
2415
|
-
else throw new ResolverError
|
|
1540
|
+
else throw new ResolverError(`Could not find a value for type parameter ${typeParameter.name.text}`, type);
|
|
2416
1541
|
this.context = {
|
|
2417
1542
|
...this.context,
|
|
2418
1543
|
[typeParameter.name.text]: resolvedType
|
|
@@ -2434,8 +1559,8 @@ var TypeNodeResolver = class TypeNodeResolver extends ResolverBase {
|
|
|
2434
1559
|
if (isRefAliasType(referenceType)) {
|
|
2435
1560
|
let type = referenceType;
|
|
2436
1561
|
while (isRefAliasType(type)) type = type.type;
|
|
2437
|
-
if (type.typeName ===
|
|
2438
|
-
else if (type.typeName ===
|
|
1562
|
+
if (type.typeName === TypeName.REF_OBJECT) properties = [...properties, ...type.properties];
|
|
1563
|
+
else if (type.typeName === TypeName.NESTED_OBJECT_LITERAL) properties = [...properties, ...type.properties];
|
|
2439
1564
|
}
|
|
2440
1565
|
if (isRefObjectType(referenceType)) referenceType.properties.forEach((property) => properties.push(property));
|
|
2441
1566
|
}
|
|
@@ -2748,69 +1873,6 @@ var CacheClient = class {
|
|
|
2748
1873
|
};
|
|
2749
1874
|
const CACHE_KEY_PATTERN = /^[A-Za-z0-9_-]{1,128}$/;
|
|
2750
1875
|
//#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
1876
|
//#region src/app/generator/parameter/module.ts
|
|
2815
1877
|
const BODY_SUPPORTED_METHODS = new Set([
|
|
2816
1878
|
"delete",
|
|
@@ -2820,16 +1882,16 @@ const BODY_SUPPORTED_METHODS = new Set([
|
|
|
2820
1882
|
"get"
|
|
2821
1883
|
]);
|
|
2822
1884
|
const SUPPORTED_LEAF_TYPES = new Set([
|
|
2823
|
-
|
|
2824
|
-
|
|
2825
|
-
|
|
2826
|
-
|
|
2827
|
-
|
|
2828
|
-
|
|
2829
|
-
|
|
2830
|
-
|
|
2831
|
-
|
|
2832
|
-
|
|
1885
|
+
TypeName.STRING,
|
|
1886
|
+
TypeName.INTEGER,
|
|
1887
|
+
TypeName.LONG,
|
|
1888
|
+
TypeName.FLOAT,
|
|
1889
|
+
TypeName.DOUBLE,
|
|
1890
|
+
TypeName.DATE,
|
|
1891
|
+
TypeName.DATETIME,
|
|
1892
|
+
TypeName.BUFFER,
|
|
1893
|
+
TypeName.BOOLEAN,
|
|
1894
|
+
TypeName.ENUM
|
|
2833
1895
|
]);
|
|
2834
1896
|
var ParameterGenerator = class {
|
|
2835
1897
|
parameter;
|
|
@@ -2863,7 +1925,7 @@ var ParameterGenerator = class {
|
|
|
2863
1925
|
}
|
|
2864
1926
|
Object.assign(draft.validators, getDeclarationValidators(this.parameter, parameterName));
|
|
2865
1927
|
if (!draft.in) {
|
|
2866
|
-
if (!BODY_SUPPORTED_METHODS.has(this.method)) throw ParameterError
|
|
1928
|
+
if (!BODY_SUPPORTED_METHODS.has(this.method)) throw ParameterError.methodUnsupported({
|
|
2867
1929
|
decoratorName: "Body",
|
|
2868
1930
|
propertyName: parameterName,
|
|
2869
1931
|
method: this.method,
|
|
@@ -2871,7 +1933,7 @@ var ParameterGenerator = class {
|
|
|
2871
1933
|
});
|
|
2872
1934
|
draft.in = ParamKind.Body;
|
|
2873
1935
|
}
|
|
2874
|
-
if ((draft.in === ParamKind.Body || draft.in === ParamKind.BodyProp) && !BODY_SUPPORTED_METHODS.has(this.method)) throw ParameterError
|
|
1936
|
+
if ((draft.in === ParamKind.Body || draft.in === ParamKind.BodyProp) && !BODY_SUPPORTED_METHODS.has(this.method)) throw ParameterError.methodUnsupported({
|
|
2875
1937
|
decoratorName: "Body",
|
|
2876
1938
|
propertyName: draft.name,
|
|
2877
1939
|
method: this.method,
|
|
@@ -2894,7 +1956,7 @@ var ParameterGenerator = class {
|
|
|
2894
1956
|
return decomposed;
|
|
2895
1957
|
}
|
|
2896
1958
|
if ((kind === ParameterSource.QUERY || kind === ParameterSource.QUERY_PROP) && isArrayType(type)) {
|
|
2897
|
-
if (!this.isLeafTypeSupported(type.elementType)) throw ParameterError
|
|
1959
|
+
if (!this.isLeafTypeSupported(type.elementType)) throw ParameterError.typeUnsupported({
|
|
2898
1960
|
decoratorName: kind === ParameterSource.QUERY ? "Query" : "QueryProp",
|
|
2899
1961
|
propertyName: draft.name,
|
|
2900
1962
|
type: type.elementType,
|
|
@@ -2906,7 +1968,7 @@ var ParameterGenerator = class {
|
|
|
2906
1968
|
type
|
|
2907
1969
|
}];
|
|
2908
1970
|
}
|
|
2909
|
-
if ((kind === ParameterSource.QUERY || kind === ParameterSource.QUERY_PROP) && !this.isLeafOrEnumOrUnion(type)) throw ParameterError
|
|
1971
|
+
if ((kind === ParameterSource.QUERY || kind === ParameterSource.QUERY_PROP) && !this.isLeafOrEnumOrUnion(type)) throw ParameterError.typeUnsupported({
|
|
2910
1972
|
decoratorName: kind === ParameterSource.QUERY ? "Query" : "QueryProp",
|
|
2911
1973
|
propertyName: draft.name,
|
|
2912
1974
|
type,
|
|
@@ -2972,7 +2034,7 @@ var ParameterGenerator = class {
|
|
|
2972
2034
|
return false;
|
|
2973
2035
|
}
|
|
2974
2036
|
validatePathDecomposition(decomposed) {
|
|
2975
|
-
for (const element of decomposed) if (!this.pathContainsParam(element.name)) throw ParameterError
|
|
2037
|
+
for (const element of decomposed) if (!this.pathContainsParam(element.name)) throw ParameterError.invalidPathMatch({
|
|
2976
2038
|
decoratorName: "Path",
|
|
2977
2039
|
propertyName: element.name,
|
|
2978
2040
|
path: this.paths.join(" | "),
|
|
@@ -2981,7 +2043,7 @@ var ParameterGenerator = class {
|
|
|
2981
2043
|
}
|
|
2982
2044
|
validatePathName(name, parameterName) {
|
|
2983
2045
|
const candidate = name || parameterName;
|
|
2984
|
-
if (!this.pathContainsParam(candidate)) throw ParameterError
|
|
2046
|
+
if (!this.pathContainsParam(candidate)) throw ParameterError.invalidPathMatch({
|
|
2985
2047
|
decoratorName: "Path",
|
|
2986
2048
|
propertyName: candidate,
|
|
2987
2049
|
path: this.paths.join(" | "),
|
|
@@ -2998,20 +2060,20 @@ var ParameterGenerator = class {
|
|
|
2998
2060
|
let typeNode = this.parameter.type;
|
|
2999
2061
|
if (!typeNode) {
|
|
3000
2062
|
const t = this.current.typeChecker.getTypeAtLocation(this.parameter);
|
|
3001
|
-
typeNode = this.current.typeChecker.typeToTypeNode(t, void 0,
|
|
2063
|
+
typeNode = this.current.typeChecker.typeToTypeNode(t, void 0, NodeBuilderFlags.NoTruncation);
|
|
3002
2064
|
}
|
|
3003
|
-
if (!typeNode) throw new ParameterError
|
|
2065
|
+
if (!typeNode) throw new ParameterError({ message: `Could not resolve type for parameter '${this.getParameterName()}'.` });
|
|
3004
2066
|
return new TypeNodeResolver(typeNode, this.current, this.parameter).resolve();
|
|
3005
2067
|
}
|
|
3006
2068
|
getParameterName() {
|
|
3007
|
-
if (!
|
|
2069
|
+
if (!isIdentifier(this.parameter.name)) throw new ParameterError({ message: "Destructured parameters are not supported. Use a simple identifier name." });
|
|
3008
2070
|
return this.parameter.name.text;
|
|
3009
2071
|
}
|
|
3010
2072
|
getDescription() {
|
|
3011
2073
|
const symbol = this.current.typeChecker.getSymbolAtLocation(this.parameter.name);
|
|
3012
2074
|
if (symbol) {
|
|
3013
2075
|
const comments = symbol.getDocumentationComment(this.current.typeChecker);
|
|
3014
|
-
if (comments.length > 0) return
|
|
2076
|
+
if (comments.length > 0) return displayPartsToString(comments);
|
|
3015
2077
|
}
|
|
3016
2078
|
return "";
|
|
3017
2079
|
}
|
|
@@ -3036,7 +2098,7 @@ var ParameterGenerator = class {
|
|
|
3036
2098
|
exampleLabels
|
|
3037
2099
|
};
|
|
3038
2100
|
} catch {
|
|
3039
|
-
throw ParameterError
|
|
2101
|
+
throw ParameterError.invalidExampleSchema();
|
|
3040
2102
|
}
|
|
3041
2103
|
}
|
|
3042
2104
|
applyOptions(parameterName) {
|
|
@@ -3136,19 +2198,19 @@ var MethodGenerator = class {
|
|
|
3136
2198
|
}
|
|
3137
2199
|
} catch (e) {
|
|
3138
2200
|
const causeMsg = e instanceof Error ? `: ${e.message}` : "";
|
|
3139
|
-
throw new GeneratorError
|
|
2201
|
+
throw new GeneratorError({
|
|
3140
2202
|
message: `Parameter generation failed for '${controllerId.text}.${methodId.text}' argument index ${i}${causeMsg}`,
|
|
3141
|
-
code: GeneratorErrorCode
|
|
2203
|
+
code: GeneratorErrorCode.PARAMETER_GENERATION_FAILED,
|
|
3142
2204
|
cause: e
|
|
3143
2205
|
});
|
|
3144
2206
|
}
|
|
3145
|
-
if (bodyParameterCount > 1) throw new GeneratorError
|
|
2207
|
+
if (bodyParameterCount > 1) throw new GeneratorError({
|
|
3146
2208
|
message: `Only one body parameter allowed in '${controllerId.text}.${methodId.text}' method.`,
|
|
3147
|
-
code: GeneratorErrorCode
|
|
2209
|
+
code: GeneratorErrorCode.BODY_PARAMETER_DUPLICATE
|
|
3148
2210
|
});
|
|
3149
|
-
if (bodyParameterCount > 0 && formParameterCount > 0) throw new GeneratorError
|
|
2211
|
+
if (bodyParameterCount > 0 && formParameterCount > 0) throw new GeneratorError({
|
|
3150
2212
|
message: `Cannot mix body and form parameters in '${controllerId.text}.${methodId.text}' method.`,
|
|
3151
|
-
code: GeneratorErrorCode
|
|
2213
|
+
code: GeneratorErrorCode.BODY_FORM_CONFLICT
|
|
3152
2214
|
});
|
|
3153
2215
|
return output;
|
|
3154
2216
|
}
|
|
@@ -3186,13 +2248,13 @@ var ControllerGenerator = class {
|
|
|
3186
2248
|
return !!this.node.name;
|
|
3187
2249
|
}
|
|
3188
2250
|
generate() {
|
|
3189
|
-
if (!this.node.parent) throw new GeneratorError
|
|
2251
|
+
if (!this.node.parent) throw new GeneratorError({
|
|
3190
2252
|
message: "Controller node doesn't have a valid parent source file.",
|
|
3191
|
-
code: GeneratorErrorCode
|
|
2253
|
+
code: GeneratorErrorCode.CONTROLLER_NO_SOURCE_FILE
|
|
3192
2254
|
});
|
|
3193
|
-
if (!this.node.name) throw new GeneratorError
|
|
2255
|
+
if (!this.node.name) throw new GeneratorError({
|
|
3194
2256
|
message: "Controller node doesn't have a valid name.",
|
|
3195
|
-
code: GeneratorErrorCode
|
|
2257
|
+
code: GeneratorErrorCode.CONTROLLER_NO_NAME
|
|
3196
2258
|
});
|
|
3197
2259
|
const sourceFile = this.node.parent.getSourceFile();
|
|
3198
2260
|
const draft = newControllerDraft({
|
|
@@ -3254,7 +2316,7 @@ var ControllerGenerator = class {
|
|
|
3254
2316
|
set.add(methodName);
|
|
3255
2317
|
output.push(method);
|
|
3256
2318
|
} catch (error) {
|
|
3257
|
-
if (isResolverError
|
|
2319
|
+
if (isResolverError(error) || isGeneratorError(error) && error.code === GeneratorErrorCode.PARAMETER_GENERATION_FAILED) continue;
|
|
3258
2320
|
throw error;
|
|
3259
2321
|
}
|
|
3260
2322
|
}
|
|
@@ -3374,9 +2436,9 @@ var MetadataGenerator = class {
|
|
|
3374
2436
|
return;
|
|
3375
2437
|
}
|
|
3376
2438
|
const summary = this.formatUnmatchedSummary();
|
|
3377
|
-
if (this.config.strict === "throw") throw new GeneratorError
|
|
2439
|
+
if (this.config.strict === "throw") throw new GeneratorError({
|
|
3378
2440
|
message: summary,
|
|
3379
|
-
code: GeneratorErrorCode
|
|
2441
|
+
code: GeneratorErrorCode.STRICT_UNMATCHED_DECORATORS
|
|
3380
2442
|
});
|
|
3381
2443
|
console.warn(summary);
|
|
3382
2444
|
}
|
|
@@ -3464,11 +2526,6 @@ var MetadataGenerator = class {
|
|
|
3464
2526
|
}
|
|
3465
2527
|
};
|
|
3466
2528
|
//#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
2529
|
//#region src/app/generate.ts
|
|
3473
2530
|
async function generateMetadata(options) {
|
|
3474
2531
|
let compilerOptions;
|
|
@@ -3486,6 +2543,6 @@ async function generateMetadata(options) {
|
|
|
3486
2543
|
}).generate();
|
|
3487
2544
|
}
|
|
3488
2545
|
//#endregion
|
|
3489
|
-
export { CACHE_DEFAULT_MAX_AGE_MS, CACHE_FILE_PREFIX, CACHE_FILE_SUFFIX, CACHE_SCHEMA_VERSION, CacheClient,
|
|
2546
|
+
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
2547
|
|
|
3491
2548
|
//# sourceMappingURL=index.mjs.map
|