@trapi/metadata 2.0.0-beta.1 → 2.0.0-beta.3
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/index.d.mts +205 -1281
- package/dist/index.d.mts.map +1 -1
- package/dist/index.mjs +379 -1290
- 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,664 +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
|
-
function createRegistry() {
|
|
504
|
-
return {
|
|
505
|
-
controllers: [],
|
|
506
|
-
methods: [],
|
|
507
|
-
parameters: [],
|
|
508
|
-
controllerJsDoc: [],
|
|
509
|
-
methodJsDoc: [],
|
|
510
|
-
parameterJsDoc: []
|
|
511
|
-
};
|
|
512
|
-
}
|
|
513
|
-
function generatePresetLookupPaths(input) {
|
|
514
|
-
if (path.isAbsolute(input) || input.startsWith("./") || input.startsWith("../")) return [input];
|
|
515
|
-
if (input.startsWith("module:")) return [input.substring(7)];
|
|
516
|
-
if (!input.startsWith("@")) return [input, `@trapi/${input}`];
|
|
517
|
-
return [input];
|
|
518
|
-
}
|
|
519
|
-
/**
|
|
520
|
-
* Collect the unique decorator names of every handler whose `marker` matches
|
|
521
|
-
* the given predicate. Lets the type resolver discover preset-renamed
|
|
522
|
-
* decorators without hard-coding canonical names.
|
|
523
|
-
*/
|
|
524
|
-
function namesForMarker(registry, predicate) {
|
|
525
|
-
const names = /* @__PURE__ */ new Set();
|
|
526
|
-
const all = [
|
|
527
|
-
...registry.controllers,
|
|
528
|
-
...registry.methods,
|
|
529
|
-
...registry.parameters
|
|
530
|
-
];
|
|
531
|
-
for (const handler of all) if (handler.marker !== void 0 && predicate(handler.marker)) names.add(handler.match.name);
|
|
532
|
-
return names;
|
|
533
|
-
}
|
|
534
|
-
/**
|
|
535
|
-
* Collect the unique JSDoc tag names of every JSDoc handler whose `marker`
|
|
536
|
-
* matches the given predicate. JSDoc analogue of `namesForMarker`.
|
|
537
|
-
*/
|
|
538
|
-
function tagsForMarker(registry, predicate) {
|
|
539
|
-
const tags = /* @__PURE__ */ new Set();
|
|
540
|
-
const all = [
|
|
541
|
-
...registry.controllerJsDoc,
|
|
542
|
-
...registry.methodJsDoc,
|
|
543
|
-
...registry.parameterJsDoc
|
|
544
|
-
];
|
|
545
|
-
for (const handler of all) if (handler.marker !== void 0 && predicate(handler.marker)) tags.add(handler.match.tag);
|
|
546
|
-
return tags;
|
|
547
|
-
}
|
|
548
|
-
function isHiddenMarker(marker) {
|
|
549
|
-
return marker === "hidden";
|
|
550
|
-
}
|
|
551
|
-
function isDeprecatedMarker(marker) {
|
|
552
|
-
return marker === "deprecated";
|
|
553
|
-
}
|
|
554
|
-
function isExtensionMarker(marker) {
|
|
555
|
-
return marker === "extension";
|
|
556
|
-
}
|
|
557
|
-
function numericMarkerKind(marker) {
|
|
558
|
-
if (typeof marker === "object" && marker !== null && "numeric" in marker) return marker.numeric;
|
|
559
|
-
}
|
|
560
|
-
const controller = (handler) => handler;
|
|
561
|
-
const method = (handler) => handler;
|
|
562
|
-
const parameter = (handler) => handler;
|
|
563
|
-
const controllerJsDoc = (handler) => handler;
|
|
564
|
-
const methodJsDoc = (handler) => handler;
|
|
565
|
-
const parameterJsDoc = (handler) => handler;
|
|
566
|
-
function isLiteralLike(kind) {
|
|
567
|
-
return kind === "literal" || kind === "identifier";
|
|
568
|
-
}
|
|
569
|
-
function readArray(draft, key) {
|
|
570
|
-
const record = draft;
|
|
571
|
-
const existing = record[key];
|
|
572
|
-
if (Array.isArray(existing)) return existing;
|
|
573
|
-
if (typeof existing !== "undefined") throw new TypeError(`append(): cannot append to draft key "${key}": existing value is not an array (got ${typeof existing}).`);
|
|
574
|
-
const created = [];
|
|
575
|
-
record[key] = created;
|
|
576
|
-
return created;
|
|
577
|
-
}
|
|
578
|
-
function into(key) {
|
|
579
|
-
return {
|
|
580
|
-
positional(index) {
|
|
581
|
-
return (ctx, draft) => {
|
|
582
|
-
const arg = ctx.argument(index);
|
|
583
|
-
if (arg && isLiteralLike(arg.kind)) draft[key] = arg.raw;
|
|
584
|
-
};
|
|
585
|
-
},
|
|
586
|
-
typeArgument(index = 0) {
|
|
587
|
-
return (ctx, draft) => {
|
|
588
|
-
const ta = ctx.typeArgument(index);
|
|
589
|
-
if (ta) draft[key] = ta.resolve();
|
|
590
|
-
};
|
|
591
|
-
}
|
|
592
|
-
};
|
|
593
|
-
}
|
|
594
|
-
function append(key) {
|
|
595
|
-
return {
|
|
596
|
-
positional(index) {
|
|
597
|
-
return (ctx, draft) => {
|
|
598
|
-
const arg = ctx.argument(index);
|
|
599
|
-
if (!arg) return;
|
|
600
|
-
const target = readArray(draft, key);
|
|
601
|
-
if (arg.kind === "array" && Array.isArray(arg.raw)) target.push(...arg.raw);
|
|
602
|
-
else if (isLiteralLike(arg.kind)) target.push(arg.raw);
|
|
603
|
-
};
|
|
604
|
-
},
|
|
605
|
-
positionalAll() {
|
|
606
|
-
return (ctx, draft) => {
|
|
607
|
-
const target = readArray(draft, key);
|
|
608
|
-
for (const arg of ctx.arguments()) if (arg.kind === "array" && Array.isArray(arg.raw)) target.push(...arg.raw);
|
|
609
|
-
else if (isLiteralLike(arg.kind)) target.push(arg.raw);
|
|
610
|
-
};
|
|
611
|
-
}
|
|
612
|
-
};
|
|
613
|
-
}
|
|
614
|
-
function flag(key, value = true) {
|
|
615
|
-
return (_ctx, draft) => {
|
|
616
|
-
draft[key] = value;
|
|
617
|
-
};
|
|
618
|
-
}
|
|
619
|
-
//#endregion
|
|
620
|
-
//#region src/adapters/decorator/validation/module.ts
|
|
621
|
-
const decoratorTargetSchema = z.enum([
|
|
622
|
-
"class",
|
|
623
|
-
"method",
|
|
624
|
-
"parameter",
|
|
625
|
-
"property"
|
|
626
|
-
]);
|
|
627
|
-
const replacesPolicySchema = z.union([z.literal(true), z.string().min(1)]);
|
|
628
|
-
function matchSchemaForKind(allowedOn) {
|
|
629
|
-
return z.object({
|
|
630
|
-
name: z.string().min(1),
|
|
631
|
-
on: decoratorTargetSchema.optional()
|
|
632
|
-
}).refine((m) => m.on === void 0 || m.on === allowedOn, {
|
|
633
|
-
message: `match.on is incompatible with the handler array it lives in — expected '${allowedOn}' or omit 'on' entirely.`,
|
|
634
|
-
path: ["on"]
|
|
635
|
-
});
|
|
636
|
-
}
|
|
637
|
-
function jsDocMatchSchemaForKind(allowedOn) {
|
|
638
|
-
return z.object({
|
|
639
|
-
tag: z.string().min(1),
|
|
640
|
-
on: decoratorTargetSchema.optional()
|
|
641
|
-
}).refine((m) => m.on === void 0 || m.on === allowedOn, {
|
|
642
|
-
message: `match.on is incompatible with the JSDoc handler array it lives in — expected '${allowedOn}' or omit 'on' entirely.`,
|
|
643
|
-
path: ["on"]
|
|
644
|
-
});
|
|
645
|
-
}
|
|
646
|
-
const matchSchema = z.object({
|
|
647
|
-
name: z.string().min(1),
|
|
648
|
-
on: decoratorTargetSchema.optional()
|
|
649
|
-
});
|
|
650
|
-
const jsDocMatchSchema = z.object({
|
|
651
|
-
tag: z.string().min(1),
|
|
652
|
-
on: decoratorTargetSchema.optional()
|
|
653
|
-
});
|
|
654
|
-
const numericMarkerSchema = z.object({ numeric: z.enum([
|
|
655
|
-
"int",
|
|
656
|
-
"long",
|
|
657
|
-
"float",
|
|
658
|
-
"double"
|
|
659
|
-
]) });
|
|
660
|
-
const resolverMarkerSchema = z.union([
|
|
661
|
-
z.literal("hidden"),
|
|
662
|
-
z.literal("deprecated"),
|
|
663
|
-
z.literal("extension"),
|
|
664
|
-
numericMarkerSchema
|
|
665
|
-
]);
|
|
666
|
-
const handlerBaseShape = {
|
|
667
|
-
replaces: replacesPolicySchema.optional(),
|
|
668
|
-
marker: resolverMarkerSchema.optional(),
|
|
669
|
-
apply: z.custom((value) => typeof value === "function", { message: "apply must be a function" })
|
|
670
|
-
};
|
|
671
|
-
const controllerHandlerSchema = z.object({
|
|
672
|
-
match: matchSchemaForKind("class"),
|
|
673
|
-
...handlerBaseShape
|
|
674
|
-
});
|
|
675
|
-
const methodHandlerSchema = z.object({
|
|
676
|
-
match: matchSchemaForKind("method"),
|
|
677
|
-
...handlerBaseShape
|
|
678
|
-
});
|
|
679
|
-
const parameterHandlerSchema = z.object({
|
|
680
|
-
match: matchSchemaForKind("parameter"),
|
|
681
|
-
...handlerBaseShape
|
|
682
|
-
});
|
|
683
|
-
const controllerJsDocHandlerSchema = z.object({
|
|
684
|
-
match: jsDocMatchSchemaForKind("class"),
|
|
685
|
-
...handlerBaseShape
|
|
686
|
-
});
|
|
687
|
-
const methodJsDocHandlerSchema = z.object({
|
|
688
|
-
match: jsDocMatchSchemaForKind("method"),
|
|
689
|
-
...handlerBaseShape
|
|
690
|
-
});
|
|
691
|
-
const parameterJsDocHandlerSchema = z.object({
|
|
692
|
-
match: jsDocMatchSchemaForKind("parameter"),
|
|
693
|
-
...handlerBaseShape
|
|
694
|
-
});
|
|
695
|
-
const presetSchema = z.object({
|
|
696
|
-
name: z.string().min(1),
|
|
697
|
-
extends: z.array(z.string().min(1)).optional(),
|
|
698
|
-
controllers: z.array(controllerHandlerSchema).optional(),
|
|
699
|
-
methods: z.array(methodHandlerSchema).optional(),
|
|
700
|
-
parameters: z.array(parameterHandlerSchema).optional(),
|
|
701
|
-
controllerJsDoc: z.array(controllerJsDocHandlerSchema).optional(),
|
|
702
|
-
methodJsDoc: z.array(methodJsDocHandlerSchema).optional(),
|
|
703
|
-
parameterJsDoc: z.array(parameterJsDocHandlerSchema).optional()
|
|
704
|
-
});
|
|
705
|
-
function createPresetContainer() {
|
|
706
|
-
const container = new Container();
|
|
707
|
-
container.mount("name", createValidator(presetSchema.shape.name));
|
|
708
|
-
container.mount("extends", { optional: true }, createValidator(presetSchema.shape.extends));
|
|
709
|
-
container.mount("controllers", { optional: true }, createValidator(presetSchema.shape.controllers));
|
|
710
|
-
container.mount("methods", { optional: true }, createValidator(presetSchema.shape.methods));
|
|
711
|
-
container.mount("parameters", { optional: true }, createValidator(presetSchema.shape.parameters));
|
|
712
|
-
container.mount("controllerJsDoc", { optional: true }, createValidator(presetSchema.shape.controllerJsDoc));
|
|
713
|
-
container.mount("methodJsDoc", { optional: true }, createValidator(presetSchema.shape.methodJsDoc));
|
|
714
|
-
container.mount("parameterJsDoc", { optional: true }, createValidator(presetSchema.shape.parameterJsDoc));
|
|
715
|
-
return container;
|
|
716
|
-
}
|
|
717
|
-
const sharedContainer = createPresetContainer();
|
|
718
|
-
async function validatePreset(input) {
|
|
719
|
-
if (input === null || typeof input !== "object" || Array.isArray(input)) throw new TypeError("preset input must be an object");
|
|
720
|
-
return sharedContainer.run(input);
|
|
721
|
-
}
|
|
722
|
-
//#endregion
|
|
723
|
-
//#region src/adapters/decorator/module.ts
|
|
724
|
-
const decoratorKinds = [
|
|
725
|
-
"controllers",
|
|
726
|
-
"methods",
|
|
727
|
-
"parameters"
|
|
728
|
-
];
|
|
729
|
-
const jsDocKinds = [
|
|
730
|
-
"controllerJsDoc",
|
|
731
|
-
"methodJsDoc",
|
|
732
|
-
"parameterJsDoc"
|
|
733
|
-
];
|
|
734
|
-
function emptyTaggedRegistry() {
|
|
735
|
-
return {
|
|
736
|
-
controllers: [],
|
|
737
|
-
methods: [],
|
|
738
|
-
parameters: [],
|
|
739
|
-
controllerJsDoc: [],
|
|
740
|
-
methodJsDoc: [],
|
|
741
|
-
parameterJsDoc: []
|
|
742
|
-
};
|
|
743
|
-
}
|
|
744
|
-
async function loadRegistry(preset, options) {
|
|
745
|
-
return stripOrigins(await loadTaggedRegistry(preset, options, /* @__PURE__ */ new Set()));
|
|
746
|
-
}
|
|
747
|
-
async function loadTaggedRegistry(preset, options, visited) {
|
|
748
|
-
const validated = await validatePreset(preset);
|
|
749
|
-
if (visited.has(validated.name)) throw new MetadataError({ message: `Preset cycle detected: ${[...visited, validated.name].join(" -> ")}` });
|
|
750
|
-
const nextVisited = new Set(visited);
|
|
751
|
-
nextVisited.add(validated.name);
|
|
752
|
-
const merged = emptyTaggedRegistry();
|
|
753
|
-
for (const extendsName of validated.extends ?? []) appendTagged(merged, await loadTaggedRegistry(await options.resolver(extendsName), options, nextVisited));
|
|
754
|
-
applyOwnHandlers(merged, validated, !!options.strict);
|
|
755
|
-
return merged;
|
|
756
|
-
}
|
|
757
|
-
function applyOwnHandlers(merged, preset, strict) {
|
|
758
|
-
for (const kind of decoratorKinds) {
|
|
759
|
-
const handlers = preset[kind] ?? [];
|
|
760
|
-
for (const handler of handlers) {
|
|
761
|
-
if (handler.replaces) applyReplacesDecorator(merged, kind, handler, preset.name, strict);
|
|
762
|
-
merged[kind].push({
|
|
763
|
-
origin: preset.name,
|
|
764
|
-
handler
|
|
765
|
-
});
|
|
766
|
-
}
|
|
767
|
-
}
|
|
768
|
-
for (const kind of jsDocKinds) {
|
|
769
|
-
const handlers = preset[kind] ?? [];
|
|
770
|
-
for (const handler of handlers) {
|
|
771
|
-
if (handler.replaces) applyReplacesJsDoc(merged, kind, handler, preset.name, strict);
|
|
772
|
-
merged[kind].push({
|
|
773
|
-
origin: preset.name,
|
|
774
|
-
handler
|
|
775
|
-
});
|
|
776
|
-
}
|
|
777
|
-
}
|
|
778
|
-
}
|
|
779
|
-
function applyReplacesDecorator(merged, kind, handler, presetName, strict) {
|
|
780
|
-
const list = merged[kind];
|
|
781
|
-
const remaining = [];
|
|
782
|
-
let removed = 0;
|
|
783
|
-
for (const entry of list) {
|
|
784
|
-
if (entry.origin !== presetName && handlerMatches(handler, entry.handler.match.name, entry.handler.match.on) && originMatches(handler.replaces, entry.origin)) {
|
|
785
|
-
removed += 1;
|
|
786
|
-
continue;
|
|
787
|
-
}
|
|
788
|
-
remaining.push(entry);
|
|
789
|
-
}
|
|
790
|
-
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` });
|
|
791
|
-
merged[kind] = remaining;
|
|
792
|
-
}
|
|
793
|
-
function applyReplacesJsDoc(merged, kind, handler, presetName, strict) {
|
|
794
|
-
const list = merged[kind];
|
|
795
|
-
const remaining = [];
|
|
796
|
-
let removed = 0;
|
|
797
|
-
for (const entry of list) {
|
|
798
|
-
if (entry.origin !== presetName && handlerMatches(handler, entry.handler.match.tag, entry.handler.match.on) && originMatches(handler.replaces, entry.origin)) {
|
|
799
|
-
removed += 1;
|
|
800
|
-
continue;
|
|
801
|
-
}
|
|
802
|
-
remaining.push(entry);
|
|
803
|
-
}
|
|
804
|
-
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` });
|
|
805
|
-
merged[kind] = remaining;
|
|
806
|
-
}
|
|
807
|
-
function handlerMatches(handler, targetName, targetOn) {
|
|
808
|
-
if (("name" in handler.match ? handler.match.name : handler.match.tag) !== targetName) return false;
|
|
809
|
-
if (handler.match.on && handler.match.on !== targetOn) return false;
|
|
810
|
-
return true;
|
|
811
|
-
}
|
|
812
|
-
function originMatches(replaces, origin) {
|
|
813
|
-
if (replaces === true) return true;
|
|
814
|
-
return replaces === origin;
|
|
815
|
-
}
|
|
816
|
-
function describeReplaces(replaces) {
|
|
817
|
-
return replaces === true ? "true" : `'${replaces}'`;
|
|
818
|
-
}
|
|
819
|
-
function appendTagged(target, source) {
|
|
820
|
-
for (const kind of decoratorKinds) target[kind].push(...source[kind]);
|
|
821
|
-
for (const kind of jsDocKinds) target[kind].push(...source[kind]);
|
|
822
|
-
}
|
|
823
|
-
function stripOrigins(tagged) {
|
|
824
|
-
const registry = createRegistry();
|
|
825
|
-
registry.controllers = tagged.controllers.map((e) => e.handler);
|
|
826
|
-
registry.methods = tagged.methods.map((e) => e.handler);
|
|
827
|
-
registry.parameters = tagged.parameters.map((e) => e.handler);
|
|
828
|
-
registry.controllerJsDoc = tagged.controllerJsDoc.map((e) => e.handler);
|
|
829
|
-
registry.methodJsDoc = tagged.methodJsDoc.map((e) => e.handler);
|
|
830
|
-
registry.parameterJsDoc = tagged.parameterJsDoc.map((e) => e.handler);
|
|
831
|
-
return registry;
|
|
832
|
-
}
|
|
833
|
-
/**
|
|
834
|
-
* Resolve a preset by string identifier (npm package, relative path, etc.) and
|
|
835
|
-
* return the v2 Preset object. Looks for a `preset` named export, then the
|
|
836
|
-
* default export, then the module itself.
|
|
837
|
-
*/
|
|
838
|
-
async function resolvePresetByName(input) {
|
|
839
|
-
const lookupPaths = generatePresetLookupPaths(input);
|
|
840
|
-
let lastError;
|
|
841
|
-
for (const lookupPath of lookupPaths) try {
|
|
842
|
-
const moduleExport = await load(lookupPath);
|
|
843
|
-
const candidates = [
|
|
844
|
-
moduleExport.preset,
|
|
845
|
-
moduleExport.default,
|
|
846
|
-
moduleExport
|
|
847
|
-
];
|
|
848
|
-
for (const candidate of candidates) if (isV2Preset(candidate)) return candidate;
|
|
849
|
-
} catch (e) {
|
|
850
|
-
lastError = e;
|
|
851
|
-
}
|
|
852
|
-
throw new ConfigError({
|
|
853
|
-
message: `Preset '${input}' could not be resolved.`,
|
|
854
|
-
code: ConfigErrorCode.PRESET_NOT_FOUND,
|
|
855
|
-
cause: lastError
|
|
856
|
-
});
|
|
857
|
-
}
|
|
858
|
-
/**
|
|
859
|
-
* Resolve a preset by name and immediately materialize its registry, recursively
|
|
860
|
-
* loading `extends` parents through the same resolver.
|
|
861
|
-
*/
|
|
862
|
-
async function loadRegistryByName(input) {
|
|
863
|
-
return loadRegistry(await resolvePresetByName(input), { resolver: resolvePresetByName });
|
|
864
|
-
}
|
|
865
|
-
function isV2Preset(input) {
|
|
866
|
-
return typeof input === "object" && input !== null && typeof input.name === "string" && !("items" in input);
|
|
867
|
-
}
|
|
868
|
-
//#endregion
|
|
869
|
-
//#region src/adapters/decorator/test-helpers.ts
|
|
870
|
-
/**
|
|
871
|
-
* Build a literal-kind {@link DecoratorArgument} from a primitive value.
|
|
872
|
-
* Use this in unit tests to feed handlers a mock argument:
|
|
873
|
-
*
|
|
874
|
-
* ```ts
|
|
875
|
-
* const ctx = createHandlerContext({ args: [literalArg('users')] });
|
|
876
|
-
* controllerHandler.apply(ctx, draft);
|
|
877
|
-
* ```
|
|
878
|
-
*/
|
|
879
|
-
function literalArg(raw) {
|
|
880
|
-
return {
|
|
881
|
-
kind: "literal",
|
|
882
|
-
raw
|
|
883
|
-
};
|
|
884
|
-
}
|
|
885
|
-
/**
|
|
886
|
-
* Build an identifier-kind {@link DecoratorArgument} (e.g. `@Foo(SOME_CONSTANT)`).
|
|
887
|
-
* `raw` is the resolved value the identifier points to — typically a string.
|
|
888
|
-
*/
|
|
889
|
-
function identifierArg(raw) {
|
|
890
|
-
return {
|
|
891
|
-
kind: "identifier",
|
|
892
|
-
raw
|
|
893
|
-
};
|
|
894
|
-
}
|
|
895
|
-
/**
|
|
896
|
-
* Build an array-kind {@link DecoratorArgument} (e.g. `@Foo(['a', 'b'])`).
|
|
897
|
-
*/
|
|
898
|
-
function arrayArg(raw) {
|
|
899
|
-
return {
|
|
900
|
-
kind: "array",
|
|
901
|
-
raw
|
|
902
|
-
};
|
|
903
|
-
}
|
|
904
|
-
/**
|
|
905
|
-
* Build an object-kind {@link DecoratorArgument} (e.g. `@Foo({ key: 'value' })`).
|
|
906
|
-
*/
|
|
907
|
-
function objectArg(raw) {
|
|
908
|
-
return {
|
|
909
|
-
kind: "object",
|
|
910
|
-
raw
|
|
911
|
-
};
|
|
912
|
-
}
|
|
913
|
-
/**
|
|
914
|
-
* Build an unresolvable-kind {@link DecoratorArgument} — represents arguments
|
|
915
|
-
* the source extractor couldn't statically evaluate (e.g. function calls,
|
|
916
|
-
* unknown identifiers).
|
|
917
|
-
*/
|
|
918
|
-
function unresolvableArg() {
|
|
919
|
-
return {
|
|
920
|
-
kind: "unresolvable",
|
|
921
|
-
raw: void 0
|
|
922
|
-
};
|
|
923
|
-
}
|
|
924
|
-
/**
|
|
925
|
-
* Build a {@link DecoratorTypeArgument} stub that returns the supplied type
|
|
926
|
-
* when `resolve()` is called.
|
|
927
|
-
*/
|
|
928
|
-
function typeArg(type) {
|
|
929
|
-
return { resolve: () => type };
|
|
930
|
-
}
|
|
931
|
-
/**
|
|
932
|
-
* Construct a {@link HandlerContext} for unit-testing handlers in isolation
|
|
933
|
-
* without spinning up the full TypeScript compiler / `generateMetadata`
|
|
934
|
-
* pipeline. Combine with the `*Arg(...)` builders to feed a handler a
|
|
935
|
-
* controlled mock decorator source.
|
|
936
|
-
*
|
|
937
|
-
* ```ts
|
|
938
|
-
* const ctx = createHandlerContext({ args: [literalArg('users')] });
|
|
939
|
-
* const draft = newControllerDraft({ name: 'UserController', location: '/x.ts' });
|
|
940
|
-
* myHandler.apply(ctx, draft);
|
|
941
|
-
* expect(draft.paths).toEqual(['users']);
|
|
942
|
-
* ```
|
|
943
|
-
*/
|
|
944
|
-
function createHandlerContext(input = {}) {
|
|
945
|
-
const args = input.args ?? [];
|
|
946
|
-
const typeArgs = input.typeArgs ?? [];
|
|
947
|
-
return {
|
|
948
|
-
host: input.host ?? { name: "TestHost" },
|
|
949
|
-
argument: (index) => args[index],
|
|
950
|
-
arguments: () => [...args],
|
|
951
|
-
typeArgument: (index) => typeArgs[index],
|
|
952
|
-
typeArguments: () => [...typeArgs],
|
|
953
|
-
parameterType: () => input.parameterType
|
|
954
|
-
};
|
|
955
|
-
}
|
|
956
|
-
//#endregion
|
|
957
165
|
//#region src/adapters/typescript/js-doc/constants.ts
|
|
958
166
|
let JSDocTagName = /* @__PURE__ */ function(JSDocTagName) {
|
|
959
167
|
JSDocTagName["ABSTRACT"] = "abstract";
|
|
@@ -1053,22 +261,22 @@ function getJSDocTagNames(node, requireTagName = false) {
|
|
|
1053
261
|
function getInitializerValue(initializer, typeChecker, type) {
|
|
1054
262
|
if (!initializer) return;
|
|
1055
263
|
switch (initializer.kind) {
|
|
1056
|
-
case
|
|
1057
|
-
case
|
|
1058
|
-
case
|
|
1059
|
-
case
|
|
1060
|
-
case
|
|
1061
|
-
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: {
|
|
1062
270
|
const prefixUnary = initializer;
|
|
1063
271
|
switch (prefixUnary.operator) {
|
|
1064
|
-
case
|
|
1065
|
-
case
|
|
272
|
+
case SyntaxKind.PlusToken: return Number(prefixUnary.operand.text);
|
|
273
|
+
case SyntaxKind.MinusToken: return Number(`-${prefixUnary.operand.text}`);
|
|
1066
274
|
default: throw new MetadataError(`Unsupported prefix operator token: ${prefixUnary.operator}`);
|
|
1067
275
|
}
|
|
1068
276
|
}
|
|
1069
|
-
case
|
|
1070
|
-
case
|
|
1071
|
-
case
|
|
277
|
+
case SyntaxKind.NumberKeyword:
|
|
278
|
+
case SyntaxKind.FirstLiteralToken: return Number(initializer.text);
|
|
279
|
+
case SyntaxKind.NewExpression: {
|
|
1072
280
|
const newExpression = initializer;
|
|
1073
281
|
if (newExpression.expression.text === "Date") {
|
|
1074
282
|
let date = /* @__PURE__ */ new Date();
|
|
@@ -1082,8 +290,8 @@ function getInitializerValue(initializer, typeChecker, type) {
|
|
|
1082
290
|
}
|
|
1083
291
|
return;
|
|
1084
292
|
}
|
|
1085
|
-
case
|
|
1086
|
-
case
|
|
293
|
+
case SyntaxKind.NullKeyword: return null;
|
|
294
|
+
case SyntaxKind.ObjectLiteralExpression: {
|
|
1087
295
|
const objectLiteral = initializer;
|
|
1088
296
|
const nestedObject = {};
|
|
1089
297
|
objectLiteral.properties.forEach((p) => {
|
|
@@ -1091,7 +299,7 @@ function getInitializerValue(initializer, typeChecker, type) {
|
|
|
1091
299
|
});
|
|
1092
300
|
return nestedObject;
|
|
1093
301
|
}
|
|
1094
|
-
case
|
|
302
|
+
case SyntaxKind.ImportSpecifier: {
|
|
1095
303
|
if (typeof typeChecker === "undefined") return;
|
|
1096
304
|
const importSpecifier = initializer;
|
|
1097
305
|
const importSymbol = typeChecker.getSymbolAtLocation(importSpecifier.name);
|
|
@@ -1112,7 +320,7 @@ function getInitializerValue(initializer, typeChecker, type) {
|
|
|
1112
320
|
}
|
|
1113
321
|
const hasInitializer = (node) => Object.prototype.hasOwnProperty.call(node, "initializer");
|
|
1114
322
|
const extractInitializer = (valueDeclaration) => valueDeclaration && hasInitializer(valueDeclaration) && valueDeclaration.initializer || void 0;
|
|
1115
|
-
const extractImportSpecifier = (symbol) => symbol?.declarations && symbol.declarations.length > 0 &&
|
|
323
|
+
const extractImportSpecifier = (symbol) => symbol?.declarations && symbol.declarations.length > 0 && isImportSpecifier(symbol.declarations[0]) && symbol.declarations[0] || void 0;
|
|
1116
324
|
//#endregion
|
|
1117
325
|
//#region src/adapters/decorator/typescript/utils.ts
|
|
1118
326
|
/**
|
|
@@ -1121,15 +329,15 @@ const extractImportSpecifier = (symbol) => symbol?.declarations && symbol.declar
|
|
|
1121
329
|
* extension extraction) that only need decorator names + argument values.
|
|
1122
330
|
*/
|
|
1123
331
|
function readNodeDecorators(node, typeChecker) {
|
|
1124
|
-
if (!
|
|
1125
|
-
const decorators =
|
|
332
|
+
if (!canHaveDecorators(node)) return [];
|
|
333
|
+
const decorators = getDecorators(node);
|
|
1126
334
|
if (!decorators || decorators.length === 0) return [];
|
|
1127
335
|
const output = [];
|
|
1128
336
|
for (const decorator of decorators) {
|
|
1129
337
|
const { expression } = decorator;
|
|
1130
338
|
let name;
|
|
1131
339
|
let argumentExpressions = [];
|
|
1132
|
-
if (
|
|
340
|
+
if (isCallExpression(expression)) {
|
|
1133
341
|
argumentExpressions = expression.arguments;
|
|
1134
342
|
name = readDecoratorName$1(expression.expression);
|
|
1135
343
|
} else name = readDecoratorName$1(expression);
|
|
@@ -1151,39 +359,39 @@ function hasDecoratorNamed(node, name, typeChecker) {
|
|
|
1151
359
|
return readNodeDecorators(node, typeChecker).some((d) => d.name === name);
|
|
1152
360
|
}
|
|
1153
361
|
function readDecoratorName$1(expression) {
|
|
1154
|
-
if (
|
|
1155
|
-
if (
|
|
362
|
+
if (isIdentifier(expression)) return expression.text;
|
|
363
|
+
if (isPropertyAccessExpression(expression)) return expression.name.text;
|
|
1156
364
|
}
|
|
1157
365
|
function buildDecoratorArgument(expr, typeChecker) {
|
|
1158
|
-
if (
|
|
366
|
+
if (isStringLiteral(expr) || isNumericLiteral(expr) || isNoSubstitutionTemplateLiteral(expr)) return {
|
|
1159
367
|
raw: getInitializerValue(expr, typeChecker),
|
|
1160
368
|
kind: "literal"
|
|
1161
369
|
};
|
|
1162
|
-
if (expr.kind ===
|
|
370
|
+
if (expr.kind === SyntaxKind.TrueKeyword) return {
|
|
1163
371
|
raw: true,
|
|
1164
372
|
kind: "literal"
|
|
1165
373
|
};
|
|
1166
|
-
if (expr.kind ===
|
|
374
|
+
if (expr.kind === SyntaxKind.FalseKeyword) return {
|
|
1167
375
|
raw: false,
|
|
1168
376
|
kind: "literal"
|
|
1169
377
|
};
|
|
1170
|
-
if (expr.kind ===
|
|
378
|
+
if (expr.kind === SyntaxKind.NullKeyword) return {
|
|
1171
379
|
raw: null,
|
|
1172
380
|
kind: "literal"
|
|
1173
381
|
};
|
|
1174
|
-
if (
|
|
382
|
+
if (isPrefixUnaryExpression(expr) && (expr.operator === SyntaxKind.PlusToken || expr.operator === SyntaxKind.MinusToken) && isNumericLiteral(expr.operand)) return {
|
|
1175
383
|
raw: getInitializerValue(expr, typeChecker),
|
|
1176
384
|
kind: "literal"
|
|
1177
385
|
};
|
|
1178
|
-
if (
|
|
386
|
+
if (isObjectLiteralExpression(expr)) return {
|
|
1179
387
|
raw: getInitializerValue(expr, typeChecker),
|
|
1180
388
|
kind: "object"
|
|
1181
389
|
};
|
|
1182
|
-
if (
|
|
390
|
+
if (isArrayLiteralExpression(expr)) return {
|
|
1183
391
|
raw: getInitializerValue(expr, typeChecker),
|
|
1184
392
|
kind: "array"
|
|
1185
393
|
};
|
|
1186
|
-
if (
|
|
394
|
+
if (isIdentifier(expr) || isPropertyAccessExpression(expr)) {
|
|
1187
395
|
const value = getInitializerValue(expr, typeChecker);
|
|
1188
396
|
if (typeof value !== "undefined") return {
|
|
1189
397
|
raw: value,
|
|
@@ -1202,8 +410,8 @@ function buildDecoratorArgument(expr, typeChecker) {
|
|
|
1202
410
|
//#endregion
|
|
1203
411
|
//#region src/adapters/decorator/typescript/module.ts
|
|
1204
412
|
function buildDecoratorSources(node, options) {
|
|
1205
|
-
if (!
|
|
1206
|
-
const decorators =
|
|
413
|
+
if (!canHaveDecorators(node)) return [];
|
|
414
|
+
const decorators = getDecorators(node);
|
|
1207
415
|
if (!decorators || decorators.length === 0) return [];
|
|
1208
416
|
const output = [];
|
|
1209
417
|
for (const decorator of decorators) {
|
|
@@ -1217,7 +425,7 @@ function buildDecoratorSource(decorator, options) {
|
|
|
1217
425
|
let name;
|
|
1218
426
|
let argumentExpressions = [];
|
|
1219
427
|
let typeArgumentNodes = [];
|
|
1220
|
-
if (
|
|
428
|
+
if (isCallExpression(expression)) {
|
|
1221
429
|
argumentExpressions = expression.arguments;
|
|
1222
430
|
typeArgumentNodes = expression.typeArguments ?? [];
|
|
1223
431
|
name = readDecoratorName(expression.expression);
|
|
@@ -1240,8 +448,8 @@ function buildDecoratorSource(decorator, options) {
|
|
|
1240
448
|
};
|
|
1241
449
|
}
|
|
1242
450
|
function readDecoratorName(expression) {
|
|
1243
|
-
if (
|
|
1244
|
-
if (
|
|
451
|
+
if (isIdentifier(expression)) return expression.text;
|
|
452
|
+
if (isPropertyAccessExpression(expression)) return expression.name.text;
|
|
1245
453
|
}
|
|
1246
454
|
function buildJsDocSources(node, options) {
|
|
1247
455
|
const tags = getJSDocTags(node);
|
|
@@ -1255,10 +463,10 @@ function buildJsDocSource(tag, options) {
|
|
|
1255
463
|
const text = transformJSDocComment(tag.comment);
|
|
1256
464
|
let parameterName;
|
|
1257
465
|
let typeNode;
|
|
1258
|
-
if (
|
|
466
|
+
if (isJSDocParameterTag(tag) || isJSDocPropertyTag(tag)) {
|
|
1259
467
|
if (tag.name) parameterName = readEntityName(tag.name);
|
|
1260
468
|
typeNode = tag.typeExpression?.type;
|
|
1261
|
-
} else if (
|
|
469
|
+
} else if (isJSDocReturnTag(tag) || isJSDocTypeTag(tag) || isJSDocThisTag(tag)) typeNode = tag.typeExpression?.type;
|
|
1262
470
|
const source = {
|
|
1263
471
|
tag: tagName,
|
|
1264
472
|
target: options.target,
|
|
@@ -1273,8 +481,8 @@ function buildJsDocSource(tag, options) {
|
|
|
1273
481
|
return source;
|
|
1274
482
|
}
|
|
1275
483
|
function readEntityName(name) {
|
|
1276
|
-
if (
|
|
1277
|
-
if (
|
|
484
|
+
if (isIdentifier(name)) return name.text;
|
|
485
|
+
if (isQualifiedName(name)) {
|
|
1278
486
|
const left = readEntityName(name.left);
|
|
1279
487
|
return left ? `${left}.${name.right.text}` : name.right.text;
|
|
1280
488
|
}
|
|
@@ -1336,16 +544,6 @@ function applyJsDocHandlers(node, handlers, draft, options) {
|
|
|
1336
544
|
for (const source of sources) for (const handler of handlers) if (matchesJsDoc(handler.match, source)) handler.apply(buildJsDocHandlerContext(source, options), draft);
|
|
1337
545
|
}
|
|
1338
546
|
//#endregion
|
|
1339
|
-
//#region src/core/error/validator.ts
|
|
1340
|
-
var ValidatorError$1 = class extends MetadataError {};
|
|
1341
|
-
//#endregion
|
|
1342
|
-
//#region src/core/error/validator-codes.ts
|
|
1343
|
-
const ValidatorErrorCode$1 = {
|
|
1344
|
-
EXPECTED_NUMBER: "VALIDATOR_EXPECTED_NUMBER",
|
|
1345
|
-
EXPECTED_DATE: "VALIDATOR_EXPECTED_DATE",
|
|
1346
|
-
EXPECTED_STRING: "VALIDATOR_EXPECTED_STRING"
|
|
1347
|
-
};
|
|
1348
|
-
//#endregion
|
|
1349
547
|
//#region src/adapters/typescript/validator/module.ts
|
|
1350
548
|
function getDeclarationValidators(declaration, name) {
|
|
1351
549
|
if (!declaration.parent) return {};
|
|
@@ -1378,23 +576,23 @@ function getDeclarationValidators(declaration, name) {
|
|
|
1378
576
|
comment = comment.substring(comment.indexOf(" ") + 1).trim();
|
|
1379
577
|
const value = getCommentValue(comment);
|
|
1380
578
|
switch (name) {
|
|
1381
|
-
case
|
|
579
|
+
case ValidatorName.UNIQUE_ITEMS:
|
|
1382
580
|
validators[name] = {
|
|
1383
581
|
message: getErrorMsg(comment, false),
|
|
1384
582
|
value: void 0
|
|
1385
583
|
};
|
|
1386
584
|
break;
|
|
1387
|
-
case
|
|
1388
|
-
case
|
|
1389
|
-
case
|
|
1390
|
-
case
|
|
1391
|
-
case
|
|
1392
|
-
case
|
|
585
|
+
case ValidatorName.MINIMUM:
|
|
586
|
+
case ValidatorName.MAXIMUM:
|
|
587
|
+
case ValidatorName.MIN_ITEMS:
|
|
588
|
+
case ValidatorName.MAX_ITEMS:
|
|
589
|
+
case ValidatorName.MIN_LENGTH:
|
|
590
|
+
case ValidatorName.MAX_LENGTH:
|
|
1393
591
|
{
|
|
1394
592
|
const parsed = Number(value);
|
|
1395
|
-
if (!Number.isFinite(parsed)) throw new ValidatorError
|
|
593
|
+
if (!Number.isFinite(parsed)) throw new ValidatorError({
|
|
1396
594
|
message: `@${name} validator expects a numeric value, got '${value}'.`,
|
|
1397
|
-
code: ValidatorErrorCode
|
|
595
|
+
code: ValidatorErrorCode.EXPECTED_NUMBER
|
|
1398
596
|
});
|
|
1399
597
|
validators[name] = {
|
|
1400
598
|
message: getErrorMsg(comment),
|
|
@@ -1402,21 +600,21 @@ function getDeclarationValidators(declaration, name) {
|
|
|
1402
600
|
};
|
|
1403
601
|
}
|
|
1404
602
|
break;
|
|
1405
|
-
case
|
|
1406
|
-
case
|
|
1407
|
-
if (typeof value !== "string") throw new ValidatorError
|
|
603
|
+
case ValidatorName.MIN_DATE:
|
|
604
|
+
case ValidatorName.MAX_DATE:
|
|
605
|
+
if (typeof value !== "string") throw new ValidatorError({
|
|
1408
606
|
message: `@${name} validator expects a date string, got '${typeof value}'.`,
|
|
1409
|
-
code: ValidatorErrorCode
|
|
607
|
+
code: ValidatorErrorCode.EXPECTED_DATE
|
|
1410
608
|
});
|
|
1411
609
|
validators[name] = {
|
|
1412
610
|
message: getErrorMsg(comment),
|
|
1413
611
|
value
|
|
1414
612
|
};
|
|
1415
613
|
break;
|
|
1416
|
-
case
|
|
1417
|
-
if (typeof value !== "string") throw new ValidatorError
|
|
614
|
+
case ValidatorName.PATTERN:
|
|
615
|
+
if (typeof value !== "string") throw new ValidatorError({
|
|
1418
616
|
message: `@${name} validator expects a string pattern, got '${value}'.`,
|
|
1419
|
-
code: ValidatorErrorCode
|
|
617
|
+
code: ValidatorErrorCode.EXPECTED_STRING
|
|
1420
618
|
});
|
|
1421
619
|
validators[name] = {
|
|
1422
620
|
message: getErrorMsg(comment),
|
|
@@ -1464,64 +662,6 @@ function removeSurroundingQuotes(str) {
|
|
|
1464
662
|
return str;
|
|
1465
663
|
}
|
|
1466
664
|
//#endregion
|
|
1467
|
-
//#region src/core/error/resolver.ts
|
|
1468
|
-
var ResolverError$1 = class extends MetadataError {
|
|
1469
|
-
file;
|
|
1470
|
-
line;
|
|
1471
|
-
constructor(message, node, options) {
|
|
1472
|
-
const opts = typeof options === "boolean" ? { onlyCurrent: options } : options;
|
|
1473
|
-
const onlyCurrent = opts?.onlyCurrent ?? false;
|
|
1474
|
-
const parts = [message];
|
|
1475
|
-
let file;
|
|
1476
|
-
let line;
|
|
1477
|
-
if (node) {
|
|
1478
|
-
const location = prettyLocationOfNode$1(node);
|
|
1479
|
-
if (location) {
|
|
1480
|
-
parts.push(location.text);
|
|
1481
|
-
file = location.file;
|
|
1482
|
-
line = location.line;
|
|
1483
|
-
}
|
|
1484
|
-
parts.push(prettyTroubleCause$1(node, onlyCurrent));
|
|
1485
|
-
}
|
|
1486
|
-
super({
|
|
1487
|
-
message: parts.join("\n"),
|
|
1488
|
-
cause: opts?.cause
|
|
1489
|
-
});
|
|
1490
|
-
this.file = file;
|
|
1491
|
-
this.line = line;
|
|
1492
|
-
}
|
|
1493
|
-
};
|
|
1494
|
-
function isResolverError$1(input) {
|
|
1495
|
-
if (!isBaseError(input)) return false;
|
|
1496
|
-
return "file" in input && "line" in input;
|
|
1497
|
-
}
|
|
1498
|
-
function prettyLocationOfNode$1(node) {
|
|
1499
|
-
try {
|
|
1500
|
-
const sourceFile = node.getSourceFile();
|
|
1501
|
-
if (!sourceFile) return void 0;
|
|
1502
|
-
const token = node.getFirstToken() || node.parent?.getFirstToken();
|
|
1503
|
-
const start = token ? sourceFile.getLineAndCharacterOfPosition(token.getStart()).line + 1 : void 0;
|
|
1504
|
-
const end = token ? sourceFile.getLineAndCharacterOfPosition(token.getEnd()).line + 1 : void 0;
|
|
1505
|
-
return {
|
|
1506
|
-
text: `At: ${normalize(sourceFile.fileName)}${start ? `:${start}` : ""}${end ? `:${end}` : ""}.`,
|
|
1507
|
-
file: sourceFile.fileName,
|
|
1508
|
-
line: start
|
|
1509
|
-
};
|
|
1510
|
-
} catch {
|
|
1511
|
-
return;
|
|
1512
|
-
}
|
|
1513
|
-
}
|
|
1514
|
-
function prettyTroubleCause$1(node, onlyCurrent = false) {
|
|
1515
|
-
try {
|
|
1516
|
-
let name;
|
|
1517
|
-
if (onlyCurrent || !node.parent) name = node.pos !== -1 ? node.getText() : node.name.text;
|
|
1518
|
-
else name = node.parent.pos !== -1 ? node.parent.getText() : node.parent.name.text;
|
|
1519
|
-
return `This was caused by '${name}'`;
|
|
1520
|
-
} catch {
|
|
1521
|
-
return "This was caused by an unknown node";
|
|
1522
|
-
}
|
|
1523
|
-
}
|
|
1524
|
-
//#endregion
|
|
1525
665
|
//#region src/adapters/typescript/resolver/extension/module.ts
|
|
1526
666
|
function getNodeExtensions(node, registry) {
|
|
1527
667
|
const names = namesForMarker(registry, isExtensionMarker);
|
|
@@ -1545,9 +685,9 @@ function getNodeExtensions(node, registry) {
|
|
|
1545
685
|
//#endregion
|
|
1546
686
|
//#region src/adapters/typescript/resolver/sub/array.ts
|
|
1547
687
|
function resolveArrayType(typeNode, ctx) {
|
|
1548
|
-
if (!
|
|
688
|
+
if (!isArrayTypeNode(typeNode)) return;
|
|
1549
689
|
return {
|
|
1550
|
-
typeName:
|
|
690
|
+
typeName: TypeName.ARRAY,
|
|
1551
691
|
elementType: ctx.resolveType(typeNode.elementType, ctx.parentNode, ctx.context)
|
|
1552
692
|
};
|
|
1553
693
|
}
|
|
@@ -1591,92 +731,93 @@ function getNodeDescription(node, typeChecker) {
|
|
|
1591
731
|
}
|
|
1592
732
|
function toTypeNodeOrFail(typeChecker, ...args) {
|
|
1593
733
|
const output = typeChecker.typeToTypeNode(...args);
|
|
1594
|
-
if (typeof output === "undefined") throw new ResolverError
|
|
734
|
+
if (typeof output === "undefined") throw new ResolverError("Type could not be transformed to TypeNode.");
|
|
1595
735
|
return output;
|
|
1596
736
|
}
|
|
1597
737
|
//#endregion
|
|
1598
738
|
//#region src/adapters/typescript/resolver/sub/indexed-access.ts
|
|
1599
739
|
function resolveIndexedAccessType(typeNode, ctx) {
|
|
1600
|
-
if (!
|
|
1601
|
-
if (typeNode.indexType.kind ===
|
|
1602
|
-
const numberIndexType = typeNode.indexType.kind ===
|
|
740
|
+
if (!isIndexedAccessTypeNode(typeNode)) return;
|
|
741
|
+
if (typeNode.indexType.kind === SyntaxKind.NumberKeyword || typeNode.indexType.kind === SyntaxKind.StringKeyword) {
|
|
742
|
+
const numberIndexType = typeNode.indexType.kind === SyntaxKind.NumberKeyword;
|
|
1603
743
|
const objectType = ctx.typeChecker.getTypeFromTypeNode(typeNode.objectType);
|
|
1604
744
|
const type = numberIndexType ? objectType.getNumberIndexType() : objectType.getStringIndexType();
|
|
1605
|
-
if (type === void 0) throw new ResolverError
|
|
745
|
+
if (type === void 0) throw new ResolverError(`Could not determine ${numberIndexType ? "number" : "string"} index on ${ctx.typeChecker.typeToString(objectType)}`, typeNode);
|
|
1606
746
|
return ctx.resolveType(toTypeNodeOrFail(ctx.typeChecker, type, void 0, void 0), typeNode, ctx.context, ctx.referencer);
|
|
1607
747
|
}
|
|
1608
|
-
if (
|
|
748
|
+
if (isLiteralTypeNode(typeNode.indexType) && (isStringLiteral(typeNode.indexType.literal) || isNumericLiteral(typeNode.indexType.literal))) {
|
|
1609
749
|
const hasType = (node) => node !== void 0 && Object.prototype.hasOwnProperty.call(node, "type");
|
|
1610
750
|
const symbol = ctx.typeChecker.getPropertyOfType(ctx.typeChecker.getTypeFromTypeNode(typeNode.objectType), typeNode.indexType.literal.text);
|
|
1611
|
-
if (symbol === void 0) throw new ResolverError
|
|
751
|
+
if (symbol === void 0) throw new ResolverError(`Could not determine the keys on ${ctx.typeChecker.typeToString(ctx.typeChecker.getTypeFromTypeNode(typeNode.objectType))}`, typeNode);
|
|
1612
752
|
if (hasType(symbol.valueDeclaration) && symbol.valueDeclaration.type) return ctx.resolveType(symbol.valueDeclaration.type, typeNode, ctx.context, ctx.referencer);
|
|
1613
753
|
const declaration = ctx.typeChecker.getTypeOfSymbolAtLocation(symbol, typeNode.objectType);
|
|
1614
754
|
try {
|
|
1615
755
|
return ctx.resolveType(toTypeNodeOrFail(ctx.typeChecker, declaration, void 0, void 0), typeNode, ctx.context, ctx.referencer);
|
|
1616
756
|
} catch (err) {
|
|
1617
|
-
throw new ResolverError
|
|
757
|
+
throw new ResolverError(`Could not determine the keys on ${ctx.typeChecker.typeToString(declaration)}`, typeNode, { cause: err });
|
|
1618
758
|
}
|
|
1619
759
|
}
|
|
1620
760
|
}
|
|
1621
761
|
//#endregion
|
|
1622
762
|
//#region src/adapters/typescript/resolver/sub/intersection.ts
|
|
1623
763
|
function resolveIntersectionType(typeNode, ctx) {
|
|
1624
|
-
if (!
|
|
764
|
+
if (!isIntersectionTypeNode(typeNode)) return;
|
|
765
|
+
const members = typeNode.types.map((type) => ctx.resolveType(type, ctx.parentNode, ctx.context));
|
|
1625
766
|
return {
|
|
1626
|
-
typeName:
|
|
1627
|
-
members
|
|
767
|
+
typeName: TypeName.INTERSECTION,
|
|
768
|
+
members
|
|
1628
769
|
};
|
|
1629
770
|
}
|
|
1630
771
|
//#endregion
|
|
1631
772
|
//#region src/adapters/typescript/resolver/sub/literal.ts
|
|
1632
773
|
function resolveLiteralType(typeNode, ctx) {
|
|
1633
|
-
if (typeNode.kind ===
|
|
1634
|
-
typeName:
|
|
774
|
+
if (typeNode.kind === SyntaxKind.NullKeyword) return {
|
|
775
|
+
typeName: TypeName.ENUM,
|
|
1635
776
|
members: [null]
|
|
1636
777
|
};
|
|
1637
|
-
if (typeNode.kind ===
|
|
1638
|
-
if (
|
|
1639
|
-
typeName:
|
|
778
|
+
if (typeNode.kind === SyntaxKind.AnyKeyword || typeNode.kind === SyntaxKind.UnknownKeyword) return { typeName: TypeName.ANY };
|
|
779
|
+
if (isLiteralTypeNode(typeNode)) return {
|
|
780
|
+
typeName: TypeName.ENUM,
|
|
1640
781
|
members: [getLiteralValue(typeNode)]
|
|
1641
782
|
};
|
|
1642
|
-
if (typeNode.kind ===
|
|
783
|
+
if (typeNode.kind === SyntaxKind.TemplateLiteralType) {
|
|
1643
784
|
const type = ctx.typeChecker.getTypeFromTypeNode(ctx.referencer || typeNode);
|
|
1644
785
|
if (type.isUnion() && type.types.every((t) => t.isStringLiteral())) return {
|
|
1645
|
-
typeName:
|
|
786
|
+
typeName: TypeName.ENUM,
|
|
1646
787
|
members: type.types.map((t) => t.value)
|
|
1647
788
|
};
|
|
1648
|
-
throw new ResolverError
|
|
789
|
+
throw new ResolverError(`Could not resolve type: ${ctx.typeChecker.typeToString(ctx.typeChecker.getTypeFromTypeNode(typeNode), typeNode)}`, typeNode);
|
|
1649
790
|
}
|
|
1650
|
-
if (
|
|
1651
|
-
if (typeNode.kind ===
|
|
791
|
+
if (isParenthesizedTypeNode(typeNode)) return ctx.resolveType(typeNode.type, typeNode, ctx.context, ctx.referencer);
|
|
792
|
+
if (typeNode.kind === SyntaxKind.ObjectKeyword || isFunctionTypeNode(typeNode)) return { typeName: TypeName.OBJECT };
|
|
1652
793
|
}
|
|
1653
794
|
function getLiteralValue(typeNode) {
|
|
1654
795
|
let value;
|
|
1655
796
|
switch (typeNode.literal.kind) {
|
|
1656
|
-
case
|
|
797
|
+
case SyntaxKind.TrueKeyword:
|
|
1657
798
|
value = true;
|
|
1658
799
|
break;
|
|
1659
|
-
case
|
|
800
|
+
case SyntaxKind.FalseKeyword:
|
|
1660
801
|
value = false;
|
|
1661
802
|
break;
|
|
1662
|
-
case
|
|
803
|
+
case SyntaxKind.StringLiteral:
|
|
1663
804
|
value = typeNode.literal.text;
|
|
1664
805
|
break;
|
|
1665
|
-
case
|
|
806
|
+
case SyntaxKind.NumericLiteral:
|
|
1666
807
|
value = Number.parseFloat(typeNode.literal.text);
|
|
1667
808
|
break;
|
|
1668
|
-
case
|
|
809
|
+
case SyntaxKind.NullKeyword:
|
|
1669
810
|
value = null;
|
|
1670
811
|
break;
|
|
1671
812
|
default: if (Object.prototype.hasOwnProperty.call(typeNode.literal, "text")) value = typeNode.literal.text;
|
|
1672
|
-
else throw new ResolverError
|
|
813
|
+
else throw new ResolverError(`Couldn't resolve literal node: ${typeNode.literal.getText()}`, typeNode.literal);
|
|
1673
814
|
}
|
|
1674
815
|
return value;
|
|
1675
816
|
}
|
|
1676
817
|
//#endregion
|
|
1677
818
|
//#region src/adapters/typescript/resolver/sub/mapped.ts
|
|
1678
819
|
function resolveMappedType(typeNode, ctx) {
|
|
1679
|
-
if (!
|
|
820
|
+
if (!isMappedTypeNode(typeNode) || !ctx.referencer) return;
|
|
1680
821
|
const type = ctx.typeChecker.getTypeFromTypeNode(ctx.referencer);
|
|
1681
822
|
const mappedTypeNode = typeNode;
|
|
1682
823
|
const { typeChecker } = ctx;
|
|
@@ -1684,41 +825,42 @@ function resolveMappedType(typeNode, ctx) {
|
|
|
1684
825
|
const isIgnored = (prop) => {
|
|
1685
826
|
const declaration = getDeclaration(prop);
|
|
1686
827
|
if (prop.getJsDocTags().findIndex((tag) => tag.name === "ignore") >= 0) return true;
|
|
1687
|
-
return !!declaration && !
|
|
828
|
+
return !!declaration && !isPropertyDeclaration(declaration) && !isPropertySignature(declaration) && !isParameter(declaration);
|
|
1688
829
|
};
|
|
830
|
+
const properties = type.getProperties().filter((property) => !isIgnored(property)).map((property) => {
|
|
831
|
+
const declaration = getDeclaration(property);
|
|
832
|
+
const overrideToken = mappedTypeNode.questionToken?.kind === SyntaxKind.PlusToken ? factory.createToken(SyntaxKind.QuestionToken) : mappedTypeNode.questionToken;
|
|
833
|
+
if (declaration && isPropertySignature(declaration)) return {
|
|
834
|
+
...ctx.propertyFromSignature(declaration, overrideToken),
|
|
835
|
+
name: property.getName()
|
|
836
|
+
};
|
|
837
|
+
if (declaration && (isPropertyDeclaration(declaration) || isParameter(declaration))) return {
|
|
838
|
+
...ctx.propertyFromDeclaration(declaration, overrideToken),
|
|
839
|
+
name: property.getName()
|
|
840
|
+
};
|
|
841
|
+
let required = (property.flags & SymbolFlags.Optional) === 0;
|
|
842
|
+
const typeNode2 = toTypeNodeOrFail(typeChecker, typeChecker.getTypeOfSymbolAtLocation(property, typeNode), void 0, NodeBuilderFlags.NoTruncation);
|
|
843
|
+
if (mappedTypeNode.questionToken && mappedTypeNode.questionToken.kind === SyntaxKind.MinusToken) required = true;
|
|
844
|
+
else if (mappedTypeNode.questionToken && (mappedTypeNode.questionToken.kind === SyntaxKind.QuestionToken || mappedTypeNode.questionToken.kind === SyntaxKind.PlusToken)) required = false;
|
|
845
|
+
return {
|
|
846
|
+
name: property.getName(),
|
|
847
|
+
required,
|
|
848
|
+
deprecated: false,
|
|
849
|
+
type: ctx.resolveType(typeNode2, typeNode, ctx.context, ctx.referencer),
|
|
850
|
+
validators: {}
|
|
851
|
+
};
|
|
852
|
+
});
|
|
1689
853
|
return {
|
|
1690
|
-
typeName:
|
|
1691
|
-
properties
|
|
1692
|
-
const declaration = getDeclaration(property);
|
|
1693
|
-
const overrideToken = mappedTypeNode.questionToken?.kind === ts.SyntaxKind.PlusToken ? ts.factory.createToken(ts.SyntaxKind.QuestionToken) : mappedTypeNode.questionToken;
|
|
1694
|
-
if (declaration && ts.isPropertySignature(declaration)) return {
|
|
1695
|
-
...ctx.propertyFromSignature(declaration, overrideToken),
|
|
1696
|
-
name: property.getName()
|
|
1697
|
-
};
|
|
1698
|
-
if (declaration && (ts.isPropertyDeclaration(declaration) || ts.isParameter(declaration))) return {
|
|
1699
|
-
...ctx.propertyFromDeclaration(declaration, overrideToken),
|
|
1700
|
-
name: property.getName()
|
|
1701
|
-
};
|
|
1702
|
-
let required = (property.flags & ts.SymbolFlags.Optional) === 0;
|
|
1703
|
-
const typeNode2 = toTypeNodeOrFail(typeChecker, typeChecker.getTypeOfSymbolAtLocation(property, typeNode), void 0, ts.NodeBuilderFlags.NoTruncation);
|
|
1704
|
-
if (mappedTypeNode.questionToken && mappedTypeNode.questionToken.kind === ts.SyntaxKind.MinusToken) required = true;
|
|
1705
|
-
else if (mappedTypeNode.questionToken && (mappedTypeNode.questionToken.kind === ts.SyntaxKind.QuestionToken || mappedTypeNode.questionToken.kind === ts.SyntaxKind.PlusToken)) required = false;
|
|
1706
|
-
return {
|
|
1707
|
-
name: property.getName(),
|
|
1708
|
-
required,
|
|
1709
|
-
deprecated: false,
|
|
1710
|
-
type: ctx.resolveType(typeNode2, typeNode, ctx.context, ctx.referencer),
|
|
1711
|
-
validators: {}
|
|
1712
|
-
};
|
|
1713
|
-
})
|
|
854
|
+
typeName: TypeName.NESTED_OBJECT_LITERAL,
|
|
855
|
+
properties
|
|
1714
856
|
};
|
|
1715
857
|
}
|
|
1716
858
|
//#endregion
|
|
1717
859
|
//#region src/adapters/typescript/resolver/sub/object-literal.ts
|
|
1718
860
|
function resolveObjectLiteralType(typeNode, ctx) {
|
|
1719
|
-
if (!
|
|
1720
|
-
const properties = typeNode.members.filter((member) =>
|
|
1721
|
-
if (!propertySignature.type) throw new ResolverError
|
|
861
|
+
if (!isTypeLiteralNode(typeNode)) return;
|
|
862
|
+
const properties = typeNode.members.filter((member) => isPropertySignature(member)).reduce((res, propertySignature) => {
|
|
863
|
+
if (!propertySignature.type) throw new ResolverError("No valid type found for property declaration.", propertySignature);
|
|
1722
864
|
const type = ctx.resolveType(propertySignature.type, propertySignature, ctx.context);
|
|
1723
865
|
return [{
|
|
1724
866
|
deprecated: hasJSDocTag(propertySignature, "deprecated"),
|
|
@@ -1733,16 +875,16 @@ function resolveObjectLiteralType(typeNode, ctx) {
|
|
|
1733
875
|
validators: getDeclarationValidators(propertySignature) || {}
|
|
1734
876
|
}, ...res];
|
|
1735
877
|
}, []);
|
|
1736
|
-
const indexMember = typeNode.members.find((member) =>
|
|
878
|
+
const indexMember = typeNode.members.find((member) => isIndexSignatureDeclaration(member));
|
|
1737
879
|
let additionalType;
|
|
1738
880
|
if (indexMember) {
|
|
1739
881
|
const indexSignatureDeclaration = indexMember;
|
|
1740
|
-
if (!isStringType(ctx.resolveType(indexSignatureDeclaration.parameters[0].type, ctx.parentNode, ctx.context))) throw new ResolverError
|
|
882
|
+
if (!isStringType(ctx.resolveType(indexSignatureDeclaration.parameters[0].type, ctx.parentNode, ctx.context))) throw new ResolverError("Only string indexes are supported.", typeNode);
|
|
1741
883
|
additionalType = ctx.resolveType(indexSignatureDeclaration.type, ctx.parentNode, ctx.context);
|
|
1742
884
|
}
|
|
1743
885
|
return {
|
|
1744
886
|
additionalProperties: indexMember && additionalType,
|
|
1745
|
-
typeName:
|
|
887
|
+
typeName: TypeName.NESTED_OBJECT_LITERAL,
|
|
1746
888
|
properties
|
|
1747
889
|
};
|
|
1748
890
|
}
|
|
@@ -1750,17 +892,17 @@ function getNodeFormat(node) {
|
|
|
1750
892
|
return getJSDocTagComment(node, "format");
|
|
1751
893
|
}
|
|
1752
894
|
function getPropertyName(node) {
|
|
1753
|
-
if (
|
|
1754
|
-
if (
|
|
895
|
+
if (isIdentifier(node.name)) return node.name.text;
|
|
896
|
+
if (isStringLiteral(node.name) || isNumericLiteral(node.name)) return node.name.text;
|
|
1755
897
|
return node.name.getText();
|
|
1756
898
|
}
|
|
1757
899
|
//#endregion
|
|
1758
900
|
//#region src/adapters/typescript/resolver/sub/primitive.ts
|
|
1759
901
|
const NUMERIC_KIND_TO_TYPE_NAME = {
|
|
1760
|
-
[NumericKind.Int]:
|
|
1761
|
-
[NumericKind.Long]:
|
|
1762
|
-
[NumericKind.Float]:
|
|
1763
|
-
[NumericKind.Double]:
|
|
902
|
+
[NumericKind.Int]: TypeName.INTEGER,
|
|
903
|
+
[NumericKind.Long]: TypeName.LONG,
|
|
904
|
+
[NumericKind.Float]: TypeName.FLOAT,
|
|
905
|
+
[NumericKind.Double]: TypeName.DOUBLE
|
|
1764
906
|
};
|
|
1765
907
|
var PrimitiveResolver = class {
|
|
1766
908
|
registry;
|
|
@@ -1770,15 +912,15 @@ var PrimitiveResolver = class {
|
|
|
1770
912
|
resolve(node, parentNode) {
|
|
1771
913
|
const resolved = this.resolveSyntaxKind(node.kind);
|
|
1772
914
|
if (resolved) {
|
|
1773
|
-
if (resolved === "string") return { typeName:
|
|
1774
|
-
if (resolved === "void") return { typeName:
|
|
1775
|
-
if (resolved === "boolean") return { typeName:
|
|
1776
|
-
if (resolved === "undefined") return { typeName:
|
|
915
|
+
if (resolved === "string") return { typeName: TypeName.STRING };
|
|
916
|
+
if (resolved === "void") return { typeName: TypeName.VOID };
|
|
917
|
+
if (resolved === "boolean") return { typeName: TypeName.BOOLEAN };
|
|
918
|
+
if (resolved === "undefined") return { typeName: TypeName.UNDEFINED };
|
|
1777
919
|
if (resolved === "null") return;
|
|
1778
|
-
if (resolved === "never") return { typeName:
|
|
1779
|
-
if (resolved === "bigint") return { typeName:
|
|
920
|
+
if (resolved === "never") return { typeName: TypeName.NEVER };
|
|
921
|
+
if (resolved === "bigint") return { typeName: TypeName.BIGINT };
|
|
1780
922
|
if (resolved === "number") {
|
|
1781
|
-
if (!parentNode) return { typeName:
|
|
923
|
+
if (!parentNode) return { typeName: TypeName.DOUBLE };
|
|
1782
924
|
const presentJsDocTags = new Set(getJSDocTagNames(parentNode).map((tag) => tag.toLowerCase()));
|
|
1783
925
|
for (const kind of [
|
|
1784
926
|
NumericKind.Int,
|
|
@@ -1792,7 +934,7 @@ var PrimitiveResolver = class {
|
|
|
1792
934
|
const jsDocTags = tagsForMarker(this.registry, matchKind);
|
|
1793
935
|
for (const tag of jsDocTags) if (presentJsDocTags.has(tag.toLowerCase())) return { typeName: NUMERIC_KIND_TO_TYPE_NAME[kind] };
|
|
1794
936
|
}
|
|
1795
|
-
return { typeName:
|
|
937
|
+
return { typeName: TypeName.DOUBLE };
|
|
1796
938
|
}
|
|
1797
939
|
}
|
|
1798
940
|
}
|
|
@@ -1820,9 +962,9 @@ var ReferenceResolver = class extends ResolverBase {
|
|
|
1820
962
|
}
|
|
1821
963
|
merge(referenceTypes) {
|
|
1822
964
|
if (referenceTypes.length === 1) return referenceTypes[0];
|
|
1823
|
-
if (referenceTypes.every((refType) => refType.refName ===
|
|
1824
|
-
if (referenceTypes.every((refType) => refType.refName ===
|
|
1825
|
-
throw new ResolverError
|
|
965
|
+
if (referenceTypes.every((refType) => refType.refName === TypeName.REF_ENUM)) return this.mergeManyRefEnums(referenceTypes);
|
|
966
|
+
if (referenceTypes.every((refType) => refType.refName === TypeName.REF_OBJECT)) return this.mergeManyRefObjects(referenceTypes);
|
|
967
|
+
throw new ResolverError(`These resolved type merge rules are not defined: ${JSON.stringify(referenceTypes)}`);
|
|
1826
968
|
}
|
|
1827
969
|
mergeManyRefEnums(many) {
|
|
1828
970
|
let merged = this.mergeRefEnums(many[0], many[1]);
|
|
@@ -1835,7 +977,7 @@ var ReferenceResolver = class extends ResolverBase {
|
|
|
1835
977
|
else if (!second.description) description = first.description;
|
|
1836
978
|
else description = `${first.description}\n${second.description}`;
|
|
1837
979
|
return {
|
|
1838
|
-
typeName:
|
|
980
|
+
typeName: TypeName.REF_ENUM,
|
|
1839
981
|
example: first.example || second.example,
|
|
1840
982
|
description,
|
|
1841
983
|
members: [...first.members || [], ...second.members || []],
|
|
@@ -1859,11 +1001,11 @@ var ReferenceResolver = class extends ResolverBase {
|
|
|
1859
1001
|
if (first.additionalProperties || second.additionalProperties) if (!first.additionalProperties) additionalProperties = second.additionalProperties;
|
|
1860
1002
|
else if (!second.additionalProperties) additionalProperties = first.additionalProperties;
|
|
1861
1003
|
else additionalProperties = {
|
|
1862
|
-
typeName:
|
|
1004
|
+
typeName: TypeName.UNION,
|
|
1863
1005
|
members: [first.additionalProperties, second.additionalProperties]
|
|
1864
1006
|
};
|
|
1865
1007
|
return {
|
|
1866
|
-
typeName:
|
|
1008
|
+
typeName: TypeName.REF_OBJECT,
|
|
1867
1009
|
description,
|
|
1868
1010
|
properties,
|
|
1869
1011
|
additionalProperties,
|
|
@@ -1877,7 +1019,7 @@ var ReferenceResolver = class extends ResolverBase {
|
|
|
1877
1019
|
const enums = declaration.members.map(this.typeChecker.getConstantValue.bind(this.typeChecker)).filter(isNotUndefined);
|
|
1878
1020
|
const enumNames = declaration.members.map((e) => e.name.getText()).filter(isNotUndefined);
|
|
1879
1021
|
return {
|
|
1880
|
-
typeName:
|
|
1022
|
+
typeName: TypeName.REF_ENUM,
|
|
1881
1023
|
description: getNodeDescription(declaration, this.typeChecker),
|
|
1882
1024
|
members: enums,
|
|
1883
1025
|
memberNames: enumNames,
|
|
@@ -1887,7 +1029,7 @@ var ReferenceResolver = class extends ResolverBase {
|
|
|
1887
1029
|
}
|
|
1888
1030
|
transformEnumMember(declaration, enumName) {
|
|
1889
1031
|
return {
|
|
1890
|
-
typeName:
|
|
1032
|
+
typeName: TypeName.REF_ENUM,
|
|
1891
1033
|
refName: enumName,
|
|
1892
1034
|
members: [this.typeChecker.getConstantValue(declaration)],
|
|
1893
1035
|
memberNames: [declaration.name.getText()],
|
|
@@ -1898,40 +1040,42 @@ var ReferenceResolver = class extends ResolverBase {
|
|
|
1898
1040
|
//#endregion
|
|
1899
1041
|
//#region src/adapters/typescript/resolver/sub/tuple.ts
|
|
1900
1042
|
function resolveTupleType(typeNode, ctx) {
|
|
1901
|
-
if (!
|
|
1043
|
+
if (!isTupleTypeNode(typeNode)) return;
|
|
1044
|
+
const elements = typeNode.elements.map((element) => {
|
|
1045
|
+
const isNamed = isNamedTupleMember(element);
|
|
1046
|
+
const actualType = isNamed ? element.type : element;
|
|
1047
|
+
return {
|
|
1048
|
+
type: ctx.resolveType(actualType, ctx.parentNode, ctx.context),
|
|
1049
|
+
...isNamed && { name: element.name.text }
|
|
1050
|
+
};
|
|
1051
|
+
});
|
|
1902
1052
|
return {
|
|
1903
|
-
typeName:
|
|
1904
|
-
elements
|
|
1905
|
-
const isNamed = ts.isNamedTupleMember(element);
|
|
1906
|
-
const actualType = isNamed ? element.type : element;
|
|
1907
|
-
return {
|
|
1908
|
-
type: ctx.resolveType(actualType, ctx.parentNode, ctx.context),
|
|
1909
|
-
...isNamed && { name: element.name.text }
|
|
1910
|
-
};
|
|
1911
|
-
})
|
|
1053
|
+
typeName: TypeName.TUPLE,
|
|
1054
|
+
elements
|
|
1912
1055
|
};
|
|
1913
1056
|
}
|
|
1914
1057
|
//#endregion
|
|
1915
1058
|
//#region src/adapters/typescript/resolver/sub/type-operator.ts
|
|
1916
1059
|
function resolveTypeOperatorType(typeNode, ctx) {
|
|
1917
|
-
if (!
|
|
1918
|
-
if (typeNode.operator ===
|
|
1060
|
+
if (!isTypeOperatorNode(typeNode)) return;
|
|
1061
|
+
if (typeNode.operator === SyntaxKind.KeyOfKeyword) {
|
|
1919
1062
|
const type = ctx.typeChecker.getTypeFromTypeNode(typeNode);
|
|
1920
1063
|
try {
|
|
1921
|
-
return ctx.resolveType(toTypeNodeOrFail(ctx.typeChecker, type, void 0,
|
|
1064
|
+
return ctx.resolveType(toTypeNodeOrFail(ctx.typeChecker, type, void 0, NodeBuilderFlags.NoTruncation), typeNode, ctx.context, ctx.referencer);
|
|
1922
1065
|
} catch (err) {
|
|
1923
|
-
throw new ResolverError
|
|
1066
|
+
throw new ResolverError(`Could not determine the keys on ${ctx.typeChecker.typeToString(ctx.typeChecker.getTypeFromTypeNode(typeNode.type))}`, typeNode, { cause: err });
|
|
1924
1067
|
}
|
|
1925
1068
|
}
|
|
1926
|
-
if (typeNode.operator ===
|
|
1069
|
+
if (typeNode.operator === SyntaxKind.ReadonlyKeyword) return ctx.resolveType(typeNode.type, typeNode, ctx.context, ctx.referencer);
|
|
1927
1070
|
}
|
|
1928
1071
|
//#endregion
|
|
1929
1072
|
//#region src/adapters/typescript/resolver/sub/union.ts
|
|
1930
1073
|
function resolveUnionType(typeNode, ctx) {
|
|
1931
|
-
if (!
|
|
1074
|
+
if (!isUnionTypeNode(typeNode)) return;
|
|
1075
|
+
const members = typeNode.types.map((type) => ctx.resolveType(type, ctx.parentNode, ctx.context));
|
|
1932
1076
|
return {
|
|
1933
|
-
typeName:
|
|
1934
|
-
members
|
|
1077
|
+
typeName: TypeName.UNION,
|
|
1078
|
+
members
|
|
1935
1079
|
};
|
|
1936
1080
|
}
|
|
1937
1081
|
//#endregion
|
|
@@ -1963,7 +1107,7 @@ var TypeNodeResolver = class TypeNodeResolver extends ResolverBase {
|
|
|
1963
1107
|
*/
|
|
1964
1108
|
static clearCache() {}
|
|
1965
1109
|
resolve() {
|
|
1966
|
-
if (this.depth > TypeNodeResolver.MAX_DEPTH) throw new ResolverError
|
|
1110
|
+
if (this.depth > TypeNodeResolver.MAX_DEPTH) throw new ResolverError(`Type resolution exceeded maximum depth of ${TypeNodeResolver.MAX_DEPTH}. This usually indicates deeply nested or circular generics.`, this.typeNode);
|
|
1967
1111
|
const ctx = this.createSubResolverContext();
|
|
1968
1112
|
const result = this.primitiveResolver.resolve(this.typeNode, this.parentNode) ?? resolveLiteralType(this.typeNode, ctx) ?? resolveArrayType(this.typeNode, ctx) ?? resolveUnionType(this.typeNode, ctx) ?? resolveIntersectionType(this.typeNode, ctx) ?? resolveObjectLiteralType(this.typeNode, ctx) ?? resolveTupleType(this.typeNode, ctx) ?? resolveMappedType(this.typeNode, ctx) ?? this.resolveConditionalType() ?? resolveTypeOperatorType(this.typeNode, ctx) ?? resolveIndexedAccessType(this.typeNode, ctx) ?? this.resolveTypeReference();
|
|
1969
1113
|
if (!result) this.throwUnknownType();
|
|
@@ -1988,32 +1132,32 @@ var TypeNodeResolver = class TypeNodeResolver extends ResolverBase {
|
|
|
1988
1132
|
return new TypeNodeResolver(typeNode, this.current, parentNode, context, referencer, this.depth + 1).resolve();
|
|
1989
1133
|
}
|
|
1990
1134
|
throwUnknownType() {
|
|
1991
|
-
throw new ResolverError
|
|
1135
|
+
throw new ResolverError(`Unknown type: ${SyntaxKind[this.typeNode.kind]}`, this.typeNode);
|
|
1992
1136
|
}
|
|
1993
1137
|
resolveConditionalType() {
|
|
1994
|
-
if (!
|
|
1138
|
+
if (!isConditionalTypeNode(this.typeNode)) return;
|
|
1995
1139
|
if (Object.keys(this.context).length > 0 && this.referencer) return this.resolveTypeViaChecker(this.referencer);
|
|
1996
1140
|
return this.resolveTypeViaChecker(this.typeNode);
|
|
1997
1141
|
}
|
|
1998
1142
|
resolveTypeReference() {
|
|
1999
|
-
if (this.typeNode.kind !==
|
|
1143
|
+
if (this.typeNode.kind !== SyntaxKind.TypeReference) return;
|
|
2000
1144
|
const typeReference = this.typeNode;
|
|
2001
|
-
if (typeReference.typeName.kind ===
|
|
1145
|
+
if (typeReference.typeName.kind === SyntaxKind.Identifier) {
|
|
2002
1146
|
if (typeReference.typeName.text === "Record" && typeReference.typeArguments) return {
|
|
2003
1147
|
additionalProperties: this.resolveNestedType(typeReference.typeArguments[1], this.parentNode, this.context),
|
|
2004
|
-
typeName:
|
|
1148
|
+
typeName: TypeName.NESTED_OBJECT_LITERAL,
|
|
2005
1149
|
properties: []
|
|
2006
1150
|
};
|
|
2007
1151
|
const specialReference = TypeNodeResolver.resolveSpecialReference(typeReference.typeName);
|
|
2008
1152
|
if (typeof specialReference !== "undefined") return specialReference;
|
|
2009
1153
|
if (typeReference.typeName.text === "Date") return this.getDateType(this.parentNode);
|
|
2010
|
-
if (typeReference.typeName.text === "Buffer" || typeReference.typeName.text === "Readable") return { typeName:
|
|
1154
|
+
if (typeReference.typeName.text === "Buffer" || typeReference.typeName.text === "Readable") return { typeName: TypeName.BUFFER };
|
|
2011
1155
|
if (typeReference.typeName.text === "Array" && typeReference.typeArguments && typeReference.typeArguments.length >= 1) return {
|
|
2012
|
-
typeName:
|
|
1156
|
+
typeName: TypeName.ARRAY,
|
|
2013
1157
|
elementType: this.resolveNestedType(typeReference.typeArguments[0], this.parentNode, this.context)
|
|
2014
1158
|
};
|
|
2015
1159
|
if (typeReference.typeName.text === "Promise" && typeReference.typeArguments && typeReference.typeArguments.length === 1) return this.resolveNestedType(typeReference.typeArguments[0], this.parentNode, this.context);
|
|
2016
|
-
if (typeReference.typeName.text === "String") return { typeName:
|
|
1160
|
+
if (typeReference.typeName.text === "String") return { typeName: TypeName.STRING };
|
|
2017
1161
|
if (this.context[typeReference.typeName.text]) return this.resolveNestedType(this.context[typeReference.typeName.text], this.parentNode, this.context);
|
|
2018
1162
|
if (TypeNodeResolver.isCheckerResolvableUtilityType(typeReference.typeName.text)) return this.resolveUtilityTypeViaChecker(typeReference);
|
|
2019
1163
|
}
|
|
@@ -2030,19 +1174,19 @@ var TypeNodeResolver = class TypeNodeResolver extends ResolverBase {
|
|
|
2030
1174
|
}
|
|
2031
1175
|
}
|
|
2032
1176
|
static CHECKER_RESOLVABLE_UTILITY_TYPES = new Set([
|
|
2033
|
-
|
|
2034
|
-
|
|
2035
|
-
|
|
2036
|
-
|
|
2037
|
-
|
|
2038
|
-
|
|
2039
|
-
|
|
2040
|
-
|
|
2041
|
-
|
|
2042
|
-
|
|
2043
|
-
|
|
2044
|
-
|
|
2045
|
-
|
|
1177
|
+
UtilityTypeName.NON_NULLABLE,
|
|
1178
|
+
UtilityTypeName.OMIT,
|
|
1179
|
+
UtilityTypeName.PARTIAL,
|
|
1180
|
+
UtilityTypeName.READONLY,
|
|
1181
|
+
UtilityTypeName.REQUIRED,
|
|
1182
|
+
UtilityTypeName.PICK,
|
|
1183
|
+
UtilityTypeName.EXTRACT,
|
|
1184
|
+
UtilityTypeName.EXCLUDE,
|
|
1185
|
+
UtilityTypeName.RETURN_TYPE,
|
|
1186
|
+
UtilityTypeName.PARAMETERS,
|
|
1187
|
+
UtilityTypeName.AWAITED,
|
|
1188
|
+
UtilityTypeName.INSTANCE_TYPE,
|
|
1189
|
+
UtilityTypeName.CONSTRUCTOR_PARAMETERS
|
|
2046
1190
|
]);
|
|
2047
1191
|
static isCheckerResolvableUtilityType(name) {
|
|
2048
1192
|
return TypeNodeResolver.CHECKER_RESOLVABLE_UTILITY_TYPES.has(name);
|
|
@@ -2058,9 +1202,9 @@ var TypeNodeResolver = class TypeNodeResolver extends ResolverBase {
|
|
|
2058
1202
|
*/
|
|
2059
1203
|
resolveTypeViaChecker(typeNode) {
|
|
2060
1204
|
const type = this.current.typeChecker.getTypeFromTypeNode(typeNode);
|
|
2061
|
-
const resolvedTypeNode = this.current.typeChecker.typeToTypeNode(type, void 0,
|
|
1205
|
+
const resolvedTypeNode = this.current.typeChecker.typeToTypeNode(type, void 0, NodeBuilderFlags.NoTruncation | NodeBuilderFlags.InTypeAlias);
|
|
2062
1206
|
if (!resolvedTypeNode) return {
|
|
2063
|
-
typeName:
|
|
1207
|
+
typeName: TypeName.TUPLE,
|
|
2064
1208
|
elements: []
|
|
2065
1209
|
};
|
|
2066
1210
|
return this.resolveNestedType(resolvedTypeNode, this.parentNode, this.context);
|
|
@@ -2072,23 +1216,23 @@ var TypeNodeResolver = class TypeNodeResolver extends ResolverBase {
|
|
|
2072
1216
|
*/
|
|
2073
1217
|
hasUnboundContextArgs(typeReference) {
|
|
2074
1218
|
if (!typeReference.typeArguments || Object.keys(this.context).length === 0) return false;
|
|
2075
|
-
return typeReference.typeArguments.some((arg) =>
|
|
1219
|
+
return typeReference.typeArguments.some((arg) => isTypeReferenceNode(arg) && isIdentifier(arg.typeName) && arg.typeName.text in this.context);
|
|
2076
1220
|
}
|
|
2077
1221
|
static resolveSpecialReference(node) {
|
|
2078
1222
|
switch (node.text) {
|
|
2079
1223
|
case "Buffer":
|
|
2080
1224
|
case "DownloadBinaryData":
|
|
2081
|
-
case "DownloadResource": return { typeName:
|
|
1225
|
+
case "DownloadResource": return { typeName: TypeName.BUFFER };
|
|
2082
1226
|
default: return;
|
|
2083
1227
|
}
|
|
2084
1228
|
}
|
|
2085
1229
|
getDateType(parentNode) {
|
|
2086
|
-
if (!parentNode) return { typeName:
|
|
1230
|
+
if (!parentNode) return { typeName: TypeName.DATETIME };
|
|
2087
1231
|
const tags = getJSDocTagNames(parentNode).filter((name) => ["isDate", "isDateTime"].includes(name));
|
|
2088
|
-
if (tags.length === 0) return { typeName:
|
|
1232
|
+
if (tags.length === 0) return { typeName: TypeName.DATETIME };
|
|
2089
1233
|
switch (tags[0]) {
|
|
2090
|
-
case "isDate": return { typeName:
|
|
2091
|
-
default: return { typeName:
|
|
1234
|
+
case "isDate": return { typeName: TypeName.DATE };
|
|
1235
|
+
default: return { typeName: TypeName.DATETIME };
|
|
2092
1236
|
}
|
|
2093
1237
|
}
|
|
2094
1238
|
static getDesignatedModels(nodes, _typeName) {
|
|
@@ -2096,16 +1240,16 @@ var TypeNodeResolver = class TypeNodeResolver extends ResolverBase {
|
|
|
2096
1240
|
}
|
|
2097
1241
|
getEnumerateType(typeName) {
|
|
2098
1242
|
const enumName = typeName.text;
|
|
2099
|
-
let enumNodes = this.current.nodes.filter((node) => node.kind ===
|
|
1243
|
+
let enumNodes = this.current.nodes.filter((node) => node.kind === SyntaxKind.EnumDeclaration && node.name.text === enumName);
|
|
2100
1244
|
if (!enumNodes.length) return;
|
|
2101
1245
|
enumNodes = TypeNodeResolver.getDesignatedModels(enumNodes, enumName);
|
|
2102
|
-
if (enumNodes.length > 1) throw new ResolverError
|
|
1246
|
+
if (enumNodes.length > 1) throw new ResolverError(`Multiple matching enum found for enum ${enumName}; please make enum names unique.`);
|
|
2103
1247
|
const enumDeclaration = enumNodes[0];
|
|
2104
1248
|
const isNotUndefined = (item) => item !== void 0;
|
|
2105
1249
|
const enums = enumDeclaration.members.map(this.current.typeChecker.getConstantValue.bind(this.current.typeChecker)).filter(isNotUndefined);
|
|
2106
1250
|
const enumNames = enumDeclaration.members.map((e) => e.name.getText()).filter(isNotUndefined);
|
|
2107
1251
|
return {
|
|
2108
|
-
typeName:
|
|
1252
|
+
typeName: TypeName.REF_ENUM,
|
|
2109
1253
|
description: this.getNodeDescription(enumDeclaration),
|
|
2110
1254
|
members: enums,
|
|
2111
1255
|
memberNames: enumNames,
|
|
@@ -2115,13 +1259,13 @@ var TypeNodeResolver = class TypeNodeResolver extends ResolverBase {
|
|
|
2115
1259
|
}
|
|
2116
1260
|
getReferenceType(node) {
|
|
2117
1261
|
let type;
|
|
2118
|
-
if (
|
|
2119
|
-
else if (
|
|
2120
|
-
else throw new ResolverError
|
|
1262
|
+
if (isTypeReferenceNode(node)) type = node.typeName;
|
|
1263
|
+
else if (isExpressionWithTypeArguments(node)) type = node.expression;
|
|
1264
|
+
else throw new ResolverError("Can't resolve reference type.");
|
|
2121
1265
|
let resolvableName = node.pos !== -1 ? node.getText() : type.text;
|
|
2122
1266
|
if (node.pos === -1 && "typeArguments" in node && Array.isArray(node.typeArguments)) {
|
|
2123
1267
|
const argumentsString = node.typeArguments.map((arg) => {
|
|
2124
|
-
if (
|
|
1268
|
+
if (isLiteralTypeNode(arg)) return `'${String(getLiteralValue(arg))}'`;
|
|
2125
1269
|
const resolvedType = this.primitiveResolver.resolveSyntaxKind(arg.kind);
|
|
2126
1270
|
if (typeof resolvedType === "undefined") return "any";
|
|
2127
1271
|
return resolvedType;
|
|
@@ -2139,7 +1283,7 @@ var TypeNodeResolver = class TypeNodeResolver extends ResolverBase {
|
|
|
2139
1283
|
const refName = TypeNodeResolver.getRefTypeName(name);
|
|
2140
1284
|
const declarations = this.getModelTypeDeclarations(type);
|
|
2141
1285
|
const referenceTypes = [];
|
|
2142
|
-
for (const declaration of declarations) if (
|
|
1286
|
+
for (const declaration of declarations) if (isTypeAliasDeclaration(declaration)) referenceTypes.push(this.getTypeAliasReference(declaration, name, node));
|
|
2143
1287
|
else if (isEnumDeclaration(declaration)) referenceTypes.push(this.referenceResolver.transformEnum(declaration, refName));
|
|
2144
1288
|
else if (isEnumMember(declaration)) referenceTypes.push(this.referenceResolver.transformEnumMember(declaration, refName));
|
|
2145
1289
|
else referenceTypes.push(this.getModelReference(declaration, name));
|
|
@@ -2150,15 +1294,15 @@ var TypeNodeResolver = class TypeNodeResolver extends ResolverBase {
|
|
|
2150
1294
|
this.current.resolverCache.clearInProgress(name);
|
|
2151
1295
|
}
|
|
2152
1296
|
} catch (err) {
|
|
2153
|
-
throw new ResolverError
|
|
1297
|
+
throw new ResolverError(`There was a problem resolving type of '${name}'.`, node, { cause: err });
|
|
2154
1298
|
}
|
|
2155
1299
|
}
|
|
2156
1300
|
getTypeAliasReference(declaration, name, referencer) {
|
|
2157
1301
|
const refName = TypeNodeResolver.getRefTypeName(name);
|
|
2158
|
-
if (declaration.type.kind ===
|
|
1302
|
+
if (declaration.type.kind === SyntaxKind.TypeReference) {
|
|
2159
1303
|
const innerRef = declaration.type;
|
|
2160
|
-
const innerName =
|
|
2161
|
-
if (!(innerName ===
|
|
1304
|
+
const innerName = isIdentifier(innerRef.typeName) ? innerRef.typeName.text : void 0;
|
|
1305
|
+
if (!(innerName === UtilityTypeName.RECORD || innerName !== void 0 && TypeNodeResolver.isCheckerResolvableUtilityType(innerName))) {
|
|
2162
1306
|
const referenceType = this.getReferenceType(innerRef);
|
|
2163
1307
|
if (referenceType.refName === refName) return referenceType;
|
|
2164
1308
|
}
|
|
@@ -2166,7 +1310,7 @@ var TypeNodeResolver = class TypeNodeResolver extends ResolverBase {
|
|
|
2166
1310
|
const type = this.resolveNestedType(declaration.type, declaration, this.context, this.referencer || referencer);
|
|
2167
1311
|
const example = this.getNodeExample(declaration);
|
|
2168
1312
|
return {
|
|
2169
|
-
typeName:
|
|
1313
|
+
typeName: TypeName.REF_ALIAS,
|
|
2170
1314
|
default: getJSDocTagComment(declaration, "default"),
|
|
2171
1315
|
description: this.getNodeDescription(declaration),
|
|
2172
1316
|
refName,
|
|
@@ -2182,21 +1326,21 @@ var TypeNodeResolver = class TypeNodeResolver extends ResolverBase {
|
|
|
2182
1326
|
const description = this.getNodeDescription(modelType);
|
|
2183
1327
|
const deprecatedDecoratorNames = namesForMarker(this.current.registry, isDeprecatedMarker);
|
|
2184
1328
|
const deprecated = [...tagsForMarker(this.current.registry, isDeprecatedMarker)].some((tag) => hasJSDocTag(modelType, tag)) || [...deprecatedDecoratorNames].some((name) => hasDecoratorNamed(modelType, name));
|
|
2185
|
-
if (!modelType.name) throw new ResolverError
|
|
1329
|
+
if (!modelType.name) throw new ResolverError("Can't get Symbol from anonymous class", modelType);
|
|
2186
1330
|
const type = this.current.typeChecker.getTypeAtLocation(modelType.name);
|
|
2187
1331
|
const toJSON = this.current.typeChecker.getPropertyOfType(type, "toJSON");
|
|
2188
|
-
if (toJSON && toJSON.valueDeclaration && (
|
|
1332
|
+
if (toJSON && toJSON.valueDeclaration && (isMethodDeclaration(toJSON.valueDeclaration) || isMethodSignature(toJSON.valueDeclaration))) {
|
|
2189
1333
|
let nodeType = toJSON.valueDeclaration.type;
|
|
2190
1334
|
if (!nodeType) {
|
|
2191
1335
|
const signature = this.current.typeChecker.getSignatureFromDeclaration(toJSON.valueDeclaration);
|
|
2192
1336
|
if (signature) {
|
|
2193
1337
|
const implicitType = this.current.typeChecker.getReturnTypeOfSignature(signature);
|
|
2194
|
-
nodeType = this.current.typeChecker.typeToTypeNode(implicitType, void 0,
|
|
2195
|
-
} else throw new ResolverError
|
|
1338
|
+
nodeType = this.current.typeChecker.typeToTypeNode(implicitType, void 0, NodeBuilderFlags.NoTruncation);
|
|
1339
|
+
} else throw new ResolverError("Can't get signature from toJson value declaration", modelType);
|
|
2196
1340
|
}
|
|
2197
1341
|
return {
|
|
2198
1342
|
refName: `${TypeNodeResolver.getRefTypeName(name)}Alias`,
|
|
2199
|
-
typeName:
|
|
1343
|
+
typeName: TypeName.REF_ALIAS,
|
|
2200
1344
|
description,
|
|
2201
1345
|
type: this.resolveNestedType(nodeType),
|
|
2202
1346
|
deprecated,
|
|
@@ -2205,11 +1349,13 @@ var TypeNodeResolver = class TypeNodeResolver extends ResolverBase {
|
|
|
2205
1349
|
};
|
|
2206
1350
|
}
|
|
2207
1351
|
const properties = this.getModelProperties(modelType);
|
|
1352
|
+
const additionalProperties = this.getModelAdditionalProperties(modelType);
|
|
1353
|
+
const inheritedProperties = this.getModelInheritedProperties(modelType) || [];
|
|
2208
1354
|
const referenceType = {
|
|
2209
|
-
additionalProperties
|
|
2210
|
-
typeName:
|
|
1355
|
+
additionalProperties,
|
|
1356
|
+
typeName: TypeName.REF_OBJECT,
|
|
2211
1357
|
description,
|
|
2212
|
-
properties:
|
|
1358
|
+
properties: inheritedProperties,
|
|
2213
1359
|
refName: TypeNodeResolver.getRefTypeName(name),
|
|
2214
1360
|
deprecated,
|
|
2215
1361
|
...example && { example }
|
|
@@ -2239,14 +1385,14 @@ var TypeNodeResolver = class TypeNodeResolver extends ResolverBase {
|
|
|
2239
1385
|
this.current.resolverCache.clearInProgress(name);
|
|
2240
1386
|
}
|
|
2241
1387
|
} catch (err) {
|
|
2242
|
-
throw new ResolverError
|
|
1388
|
+
throw new ResolverError(`There was a problem resolving type of '${name}'.`, this.typeNode, { cause: err });
|
|
2243
1389
|
}
|
|
2244
1390
|
}
|
|
2245
1391
|
createCircularDependencyResolver(refName) {
|
|
2246
1392
|
const referenceType = {
|
|
2247
1393
|
deprecated: false,
|
|
2248
1394
|
properties: [],
|
|
2249
|
-
typeName:
|
|
1395
|
+
typeName: TypeName.REF_OBJECT,
|
|
2250
1396
|
refName
|
|
2251
1397
|
};
|
|
2252
1398
|
this.current.registerDependencyResolver((referenceTypes) => {
|
|
@@ -2261,27 +1407,27 @@ var TypeNodeResolver = class TypeNodeResolver extends ResolverBase {
|
|
|
2261
1407
|
}
|
|
2262
1408
|
static nodeIsUsable(node) {
|
|
2263
1409
|
switch (node.kind) {
|
|
2264
|
-
case
|
|
2265
|
-
case
|
|
2266
|
-
case
|
|
2267
|
-
case
|
|
2268
|
-
case
|
|
1410
|
+
case SyntaxKind.InterfaceDeclaration:
|
|
1411
|
+
case SyntaxKind.ClassDeclaration:
|
|
1412
|
+
case SyntaxKind.TypeAliasDeclaration:
|
|
1413
|
+
case SyntaxKind.EnumDeclaration:
|
|
1414
|
+
case SyntaxKind.EnumMember: return true;
|
|
2269
1415
|
default: return false;
|
|
2270
1416
|
}
|
|
2271
1417
|
}
|
|
2272
1418
|
getModelTypeDeclarations(type) {
|
|
2273
|
-
let typeName = type.kind ===
|
|
1419
|
+
let typeName = type.kind === SyntaxKind.Identifier ? type.text : type.right.text;
|
|
2274
1420
|
let symbol = this.getSymbolAtLocation(type);
|
|
2275
|
-
if (!symbol && type.kind ===
|
|
2276
|
-
if (!symbol) throw new ResolverError
|
|
1421
|
+
if (!symbol && type.kind === SyntaxKind.QualifiedName) symbol = this.getSymbolAtLocation(type.left).exports?.get(typeName);
|
|
1422
|
+
if (!symbol) throw new ResolverError(`No symbol found for referenced type ${typeName}.`);
|
|
2277
1423
|
const declarations = symbol.getDeclarations();
|
|
2278
|
-
if (!declarations || declarations.length === 0) throw new ResolverError
|
|
1424
|
+
if (!declarations || declarations.length === 0) throw new ResolverError(`No declarations found for referenced type ${typeName}.`);
|
|
2279
1425
|
if (symbol.escapedName !== typeName && symbol.escapedName !== "default") typeName = symbol.escapedName;
|
|
2280
1426
|
let modelTypes = declarations.filter((node) => {
|
|
2281
1427
|
if (!TypeNodeResolver.nodeIsUsable(node) || !this.current.isExportedNode(node)) return false;
|
|
2282
1428
|
return node.name?.text === typeName;
|
|
2283
1429
|
});
|
|
2284
|
-
if (!modelTypes.length) throw new ResolverError
|
|
1430
|
+
if (!modelTypes.length) throw new ResolverError(`No matching model found for referenced type ${typeName}. If ${typeName} comes from a dependency, please create an interface in your own code that has the same structure. The compiler can not utilize interfaces from external dependencies.`);
|
|
2285
1431
|
if (modelTypes.length > 1) {
|
|
2286
1432
|
modelTypes = modelTypes.filter((modelType) => modelType.getSourceFile().fileName.replace(/\\/g, "/").toLowerCase().indexOf("node_modules/typescript") <= -1);
|
|
2287
1433
|
modelTypes = TypeNodeResolver.getDesignatedModels(modelTypes, typeName);
|
|
@@ -2289,23 +1435,23 @@ var TypeNodeResolver = class TypeNodeResolver extends ResolverBase {
|
|
|
2289
1435
|
return modelTypes;
|
|
2290
1436
|
}
|
|
2291
1437
|
getModelTypeDeclaration(type) {
|
|
2292
|
-
let typeName = type.kind ===
|
|
1438
|
+
let typeName = type.kind === SyntaxKind.Identifier ? type.text : type.right.text;
|
|
2293
1439
|
const symbol = this.getSymbolAtLocation(type);
|
|
2294
1440
|
const declarations = symbol.getDeclarations();
|
|
2295
|
-
if (!declarations || declarations.length === 0) throw new ResolverError
|
|
1441
|
+
if (!declarations || declarations.length === 0) throw new ResolverError(`No models found for referenced type ${typeName}.`);
|
|
2296
1442
|
if (symbol.escapedName !== typeName && symbol.escapedName !== "default") typeName = symbol.escapedName;
|
|
2297
1443
|
let modelTypes = declarations.filter((node) => {
|
|
2298
1444
|
if (!TypeNodeResolver.nodeIsUsable(node) || !this.current.isExportedNode(node)) return false;
|
|
2299
1445
|
return node.name?.text === typeName;
|
|
2300
1446
|
});
|
|
2301
|
-
if (!modelTypes.length) throw new ResolverError
|
|
1447
|
+
if (!modelTypes.length) throw new ResolverError(`No matching model found for referenced type ${typeName}. If ${typeName} comes from a dependency, please create an interface in your own code that has the same structure. The compiler can not utilize interfaces from external dependencies.`);
|
|
2302
1448
|
if (modelTypes.length > 1) {
|
|
2303
1449
|
modelTypes = modelTypes.filter((modelType) => modelType.getSourceFile().fileName.replace(/\\/g, "/").toLowerCase().indexOf("node_modules/typescript") <= -1);
|
|
2304
1450
|
modelTypes = TypeNodeResolver.getDesignatedModels(modelTypes, typeName);
|
|
2305
1451
|
}
|
|
2306
1452
|
if (modelTypes.length > 1) {
|
|
2307
1453
|
const conflicts = modelTypes.map((modelType) => modelType.getSourceFile().fileName).join("\"; \"");
|
|
2308
|
-
throw new ResolverError
|
|
1454
|
+
throw new ResolverError(`Multiple matching models found for referenced type ${typeName}; please make model names unique. Conflicts found: "${conflicts}".`);
|
|
2309
1455
|
}
|
|
2310
1456
|
return modelTypes[0];
|
|
2311
1457
|
}
|
|
@@ -2314,13 +1460,13 @@ var TypeNodeResolver = class TypeNodeResolver extends ResolverBase {
|
|
|
2314
1460
|
}
|
|
2315
1461
|
getSymbolAtLocation(type) {
|
|
2316
1462
|
const symbol = this.current.typeChecker.getSymbolAtLocation(type) || type.symbol;
|
|
2317
|
-
return symbol && this.hasFlag(symbol,
|
|
1463
|
+
return symbol && this.hasFlag(symbol, SymbolFlags.Alias) && this.current.typeChecker.getAliasedSymbol(symbol) || symbol;
|
|
2318
1464
|
}
|
|
2319
1465
|
getModelProperties(node, overrideToken) {
|
|
2320
1466
|
const isIgnored = (e) => hasJSDocTag(e, "ignore");
|
|
2321
|
-
if (
|
|
2322
|
-
const properties = node.members.filter((member) => !isIgnored(member) && member.kind ===
|
|
2323
|
-
const classConstructor = node.members.find((member) =>
|
|
1467
|
+
if (isInterfaceDeclaration(node)) return node.members.filter((member) => !isIgnored(member) && isPropertySignature(member)).map((member) => this.propertyFromSignature(member, overrideToken));
|
|
1468
|
+
const properties = node.members.filter((member) => !isIgnored(member) && member.kind === SyntaxKind.PropertyDeclaration && !this.hasStaticModifier(member) && this.hasPublicModifier(member));
|
|
1469
|
+
const classConstructor = node.members.find((member) => isConstructorDeclaration(member));
|
|
2324
1470
|
if (classConstructor && classConstructor.parameters) {
|
|
2325
1471
|
const constructorProperties = classConstructor.parameters.filter((parameter) => this.isAccessibleParameter(parameter));
|
|
2326
1472
|
properties.push(...constructorProperties);
|
|
@@ -2329,10 +1475,10 @@ var TypeNodeResolver = class TypeNodeResolver extends ResolverBase {
|
|
|
2329
1475
|
}
|
|
2330
1476
|
propertyFromSignature(propertySignature, overrideToken) {
|
|
2331
1477
|
const identifier = propertySignature.name;
|
|
2332
|
-
if (!propertySignature.type) throw new ResolverError
|
|
1478
|
+
if (!propertySignature.type) throw new ResolverError("No valid type found for property declaration.");
|
|
2333
1479
|
let required = !propertySignature.questionToken;
|
|
2334
|
-
if (overrideToken && overrideToken.kind ===
|
|
2335
|
-
else if (overrideToken && overrideToken.kind ===
|
|
1480
|
+
if (overrideToken && overrideToken.kind === SyntaxKind.MinusToken) required = true;
|
|
1481
|
+
else if (overrideToken && overrideToken.kind === SyntaxKind.QuestionToken) required = false;
|
|
2336
1482
|
return {
|
|
2337
1483
|
deprecated: hasJSDocTag(propertySignature, "deprecated"),
|
|
2338
1484
|
default: getJSDocTagComment(propertySignature, "default"),
|
|
@@ -2351,13 +1497,13 @@ var TypeNodeResolver = class TypeNodeResolver extends ResolverBase {
|
|
|
2351
1497
|
let typeNode = propertyDeclaration.type;
|
|
2352
1498
|
if (!typeNode) {
|
|
2353
1499
|
const tsType = this.current.typeChecker.getTypeAtLocation(propertyDeclaration);
|
|
2354
|
-
typeNode = this.current.typeChecker.typeToTypeNode(tsType, void 0,
|
|
1500
|
+
typeNode = this.current.typeChecker.typeToTypeNode(tsType, void 0, NodeBuilderFlags.NoTruncation);
|
|
2355
1501
|
}
|
|
2356
|
-
if (!typeNode) throw new ResolverError
|
|
1502
|
+
if (!typeNode) throw new ResolverError("No valid type found for property declaration.");
|
|
2357
1503
|
const type = this.resolveNestedType(typeNode, propertyDeclaration, this.context, typeNode);
|
|
2358
1504
|
let required = !propertyDeclaration.questionToken && !propertyDeclaration.initializer;
|
|
2359
|
-
if (overrideToken && overrideToken.kind ===
|
|
2360
|
-
else if (overrideToken && overrideToken.kind ===
|
|
1505
|
+
if (overrideToken && overrideToken.kind === SyntaxKind.MinusToken) required = true;
|
|
1506
|
+
else if (overrideToken && overrideToken.kind === SyntaxKind.QuestionToken) required = false;
|
|
2361
1507
|
return {
|
|
2362
1508
|
deprecated: hasJSDocTag(propertyDeclaration, "deprecated"),
|
|
2363
1509
|
default: getInitializerValue(propertyDeclaration.initializer, this.current.typeChecker),
|
|
@@ -2372,11 +1518,11 @@ var TypeNodeResolver = class TypeNodeResolver extends ResolverBase {
|
|
|
2372
1518
|
};
|
|
2373
1519
|
}
|
|
2374
1520
|
getModelAdditionalProperties(node) {
|
|
2375
|
-
if (node.kind ===
|
|
2376
|
-
const indexMember = node.members.find((member) => member.kind ===
|
|
1521
|
+
if (node.kind === SyntaxKind.InterfaceDeclaration) {
|
|
1522
|
+
const indexMember = node.members.find((member) => member.kind === SyntaxKind.IndexSignature);
|
|
2377
1523
|
if (!indexMember) return;
|
|
2378
1524
|
const indexSignatureDeclaration = indexMember;
|
|
2379
|
-
if (this.resolveNestedType(indexSignatureDeclaration.parameters[0].type, this.parentNode, this.context).typeName !== "string") throw new ResolverError
|
|
1525
|
+
if (this.resolveNestedType(indexSignatureDeclaration.parameters[0].type, this.parentNode, this.context).typeName !== "string") throw new ResolverError("Only string indexers are supported.", this.typeNode);
|
|
2380
1526
|
return this.resolveNestedType(indexSignatureDeclaration.type, this.parentNode, this.context);
|
|
2381
1527
|
}
|
|
2382
1528
|
}
|
|
@@ -2387,10 +1533,10 @@ var TypeNodeResolver = class TypeNodeResolver extends ResolverBase {
|
|
|
2387
1533
|
if (typeParameters) for (const [index, typeParameter] of typeParameters.entries()) {
|
|
2388
1534
|
const typeArg = type.typeArguments && type.typeArguments[index];
|
|
2389
1535
|
let resolvedType;
|
|
2390
|
-
if (typeArg &&
|
|
1536
|
+
if (typeArg && isTypeReferenceNode(typeArg) && isIdentifier(typeArg.typeName) && context[typeArg.typeName.text]) resolvedType = context[typeArg.typeName.text];
|
|
2391
1537
|
else if (typeArg) resolvedType = typeArg;
|
|
2392
1538
|
else if (typeParameter.default) resolvedType = typeParameter.default;
|
|
2393
|
-
else throw new ResolverError
|
|
1539
|
+
else throw new ResolverError(`Could not find a value for type parameter ${typeParameter.name.text}`, type);
|
|
2394
1540
|
this.context = {
|
|
2395
1541
|
...this.context,
|
|
2396
1542
|
[typeParameter.name.text]: resolvedType
|
|
@@ -2412,8 +1558,8 @@ var TypeNodeResolver = class TypeNodeResolver extends ResolverBase {
|
|
|
2412
1558
|
if (isRefAliasType(referenceType)) {
|
|
2413
1559
|
let type = referenceType;
|
|
2414
1560
|
while (isRefAliasType(type)) type = type.type;
|
|
2415
|
-
if (type.typeName ===
|
|
2416
|
-
else if (type.typeName ===
|
|
1561
|
+
if (type.typeName === TypeName.REF_OBJECT) properties = [...properties, ...type.properties];
|
|
1562
|
+
else if (type.typeName === TypeName.NESTED_OBJECT_LITERAL) properties = [...properties, ...type.properties];
|
|
2417
1563
|
}
|
|
2418
1564
|
if (isRefObjectType(referenceType)) referenceType.properties.forEach((property) => properties.push(property));
|
|
2419
1565
|
}
|
|
@@ -2726,69 +1872,6 @@ var CacheClient = class {
|
|
|
2726
1872
|
};
|
|
2727
1873
|
const CACHE_KEY_PATTERN = /^[A-Za-z0-9_-]{1,128}$/;
|
|
2728
1874
|
//#endregion
|
|
2729
|
-
//#region src/core/error/generator.ts
|
|
2730
|
-
var GeneratorError$1 = class extends MetadataError {};
|
|
2731
|
-
function isGeneratorError$1(input) {
|
|
2732
|
-
if (!isBaseError(input)) return false;
|
|
2733
|
-
return typeof input.code === "string";
|
|
2734
|
-
}
|
|
2735
|
-
//#endregion
|
|
2736
|
-
//#region src/core/error/generator-codes.ts
|
|
2737
|
-
const GeneratorErrorCode$1 = {
|
|
2738
|
-
CONTROLLER_NO_SOURCE_FILE: "GENERATOR_CONTROLLER_NO_SOURCE_FILE",
|
|
2739
|
-
CONTROLLER_NO_NAME: "GENERATOR_CONTROLLER_NO_NAME",
|
|
2740
|
-
PARAMETER_GENERATION_FAILED: "GENERATOR_PARAMETER_GENERATION_FAILED",
|
|
2741
|
-
BODY_PARAMETER_DUPLICATE: "GENERATOR_BODY_PARAMETER_DUPLICATE",
|
|
2742
|
-
BODY_FORM_CONFLICT: "GENERATOR_BODY_FORM_CONFLICT",
|
|
2743
|
-
STRICT_UNMATCHED_DECORATORS: "GENERATOR_STRICT_UNMATCHED_DECORATORS"
|
|
2744
|
-
};
|
|
2745
|
-
//#endregion
|
|
2746
|
-
//#region src/core/error/parameter.ts
|
|
2747
|
-
var ParameterError$1 = class ParameterError$1 extends MetadataError {
|
|
2748
|
-
static typeUnsupported(context) {
|
|
2749
|
-
const location = context.node ? ParameterError$1.getCurrentLocation(context.node) : void 0;
|
|
2750
|
-
return new ParameterError$1({
|
|
2751
|
-
message: `@${context.decoratorName}('${context.propertyName}') does not support '${context.type.typeName}' type${location ? ` at ${location}` : ""}.`,
|
|
2752
|
-
code: ParameterErrorCode.TYPE_UNSUPPORTED
|
|
2753
|
-
});
|
|
2754
|
-
}
|
|
2755
|
-
static methodUnsupported(context) {
|
|
2756
|
-
const location = context.node ? ParameterError$1.getCurrentLocation(context.node) : void 0;
|
|
2757
|
-
return new ParameterError$1({
|
|
2758
|
-
message: `@${context.decoratorName}('${context.propertyName}') does not support method '${context.method}'${location ? ` at ${location}` : ""}.`,
|
|
2759
|
-
code: ParameterErrorCode.METHOD_UNSUPPORTED
|
|
2760
|
-
});
|
|
2761
|
-
}
|
|
2762
|
-
static invalidPathMatch(context) {
|
|
2763
|
-
const location = context.node ? ParameterError$1.getCurrentLocation(context.node) : void 0;
|
|
2764
|
-
return new ParameterError$1({
|
|
2765
|
-
message: `@${context.decoratorName}('${context.propertyName}') does not exist in path '${context.path}'${location ? ` at ${location}` : ""}.`,
|
|
2766
|
-
code: ParameterErrorCode.PATH_MISMATCH
|
|
2767
|
-
});
|
|
2768
|
-
}
|
|
2769
|
-
static scopeRequired(context) {
|
|
2770
|
-
const location = context.node ? ParameterError$1.getCurrentLocation(context.node) : void 0;
|
|
2771
|
-
return new ParameterError$1({
|
|
2772
|
-
message: `@${context.decoratorName}() requires a scope argument${location ? ` at ${location}` : ""}.`,
|
|
2773
|
-
code: ParameterErrorCode.SCOPE_REQUIRED
|
|
2774
|
-
});
|
|
2775
|
-
}
|
|
2776
|
-
static invalidExampleSchema() {
|
|
2777
|
-
return new ParameterError$1({
|
|
2778
|
-
message: "The @example JSDoc tag contains invalid JSON.",
|
|
2779
|
-
code: ParameterErrorCode.INVALID_EXAMPLE
|
|
2780
|
-
});
|
|
2781
|
-
}
|
|
2782
|
-
static getCurrentLocation(node) {
|
|
2783
|
-
const parts = [];
|
|
2784
|
-
if (isMethodDeclaration(node.parent)) {
|
|
2785
|
-
parts.push(node.parent.name.getText());
|
|
2786
|
-
if (isClassDeclaration(node.parent.parent)) parts.unshift(node.parent.parent.name.text);
|
|
2787
|
-
}
|
|
2788
|
-
return parts.join(".");
|
|
2789
|
-
}
|
|
2790
|
-
};
|
|
2791
|
-
//#endregion
|
|
2792
1875
|
//#region src/app/generator/parameter/module.ts
|
|
2793
1876
|
const BODY_SUPPORTED_METHODS = new Set([
|
|
2794
1877
|
"delete",
|
|
@@ -2798,16 +1881,16 @@ const BODY_SUPPORTED_METHODS = new Set([
|
|
|
2798
1881
|
"get"
|
|
2799
1882
|
]);
|
|
2800
1883
|
const SUPPORTED_LEAF_TYPES = new Set([
|
|
2801
|
-
|
|
2802
|
-
|
|
2803
|
-
|
|
2804
|
-
|
|
2805
|
-
|
|
2806
|
-
|
|
2807
|
-
|
|
2808
|
-
|
|
2809
|
-
|
|
2810
|
-
|
|
1884
|
+
TypeName.STRING,
|
|
1885
|
+
TypeName.INTEGER,
|
|
1886
|
+
TypeName.LONG,
|
|
1887
|
+
TypeName.FLOAT,
|
|
1888
|
+
TypeName.DOUBLE,
|
|
1889
|
+
TypeName.DATE,
|
|
1890
|
+
TypeName.DATETIME,
|
|
1891
|
+
TypeName.BUFFER,
|
|
1892
|
+
TypeName.BOOLEAN,
|
|
1893
|
+
TypeName.ENUM
|
|
2811
1894
|
]);
|
|
2812
1895
|
var ParameterGenerator = class {
|
|
2813
1896
|
parameter;
|
|
@@ -2841,7 +1924,7 @@ var ParameterGenerator = class {
|
|
|
2841
1924
|
}
|
|
2842
1925
|
Object.assign(draft.validators, getDeclarationValidators(this.parameter, parameterName));
|
|
2843
1926
|
if (!draft.in) {
|
|
2844
|
-
if (!BODY_SUPPORTED_METHODS.has(this.method)) throw ParameterError
|
|
1927
|
+
if (!BODY_SUPPORTED_METHODS.has(this.method)) throw ParameterError.methodUnsupported({
|
|
2845
1928
|
decoratorName: "Body",
|
|
2846
1929
|
propertyName: parameterName,
|
|
2847
1930
|
method: this.method,
|
|
@@ -2849,7 +1932,7 @@ var ParameterGenerator = class {
|
|
|
2849
1932
|
});
|
|
2850
1933
|
draft.in = ParamKind.Body;
|
|
2851
1934
|
}
|
|
2852
|
-
if ((draft.in === ParamKind.Body || draft.in === ParamKind.BodyProp) && !BODY_SUPPORTED_METHODS.has(this.method)) throw ParameterError
|
|
1935
|
+
if ((draft.in === ParamKind.Body || draft.in === ParamKind.BodyProp) && !BODY_SUPPORTED_METHODS.has(this.method)) throw ParameterError.methodUnsupported({
|
|
2853
1936
|
decoratorName: "Body",
|
|
2854
1937
|
propertyName: draft.name,
|
|
2855
1938
|
method: this.method,
|
|
@@ -2872,7 +1955,7 @@ var ParameterGenerator = class {
|
|
|
2872
1955
|
return decomposed;
|
|
2873
1956
|
}
|
|
2874
1957
|
if ((kind === ParameterSource.QUERY || kind === ParameterSource.QUERY_PROP) && isArrayType(type)) {
|
|
2875
|
-
if (!this.isLeafTypeSupported(type.elementType)) throw ParameterError
|
|
1958
|
+
if (!this.isLeafTypeSupported(type.elementType)) throw ParameterError.typeUnsupported({
|
|
2876
1959
|
decoratorName: kind === ParameterSource.QUERY ? "Query" : "QueryProp",
|
|
2877
1960
|
propertyName: draft.name,
|
|
2878
1961
|
type: type.elementType,
|
|
@@ -2884,7 +1967,7 @@ var ParameterGenerator = class {
|
|
|
2884
1967
|
type
|
|
2885
1968
|
}];
|
|
2886
1969
|
}
|
|
2887
|
-
if ((kind === ParameterSource.QUERY || kind === ParameterSource.QUERY_PROP) && !this.isLeafOrEnumOrUnion(type)) throw ParameterError
|
|
1970
|
+
if ((kind === ParameterSource.QUERY || kind === ParameterSource.QUERY_PROP) && !this.isLeafOrEnumOrUnion(type)) throw ParameterError.typeUnsupported({
|
|
2888
1971
|
decoratorName: kind === ParameterSource.QUERY ? "Query" : "QueryProp",
|
|
2889
1972
|
propertyName: draft.name,
|
|
2890
1973
|
type,
|
|
@@ -2950,7 +2033,7 @@ var ParameterGenerator = class {
|
|
|
2950
2033
|
return false;
|
|
2951
2034
|
}
|
|
2952
2035
|
validatePathDecomposition(decomposed) {
|
|
2953
|
-
for (const element of decomposed) if (!this.pathContainsParam(element.name)) throw ParameterError
|
|
2036
|
+
for (const element of decomposed) if (!this.pathContainsParam(element.name)) throw ParameterError.invalidPathMatch({
|
|
2954
2037
|
decoratorName: "Path",
|
|
2955
2038
|
propertyName: element.name,
|
|
2956
2039
|
path: this.paths.join(" | "),
|
|
@@ -2959,7 +2042,7 @@ var ParameterGenerator = class {
|
|
|
2959
2042
|
}
|
|
2960
2043
|
validatePathName(name, parameterName) {
|
|
2961
2044
|
const candidate = name || parameterName;
|
|
2962
|
-
if (!this.pathContainsParam(candidate)) throw ParameterError
|
|
2045
|
+
if (!this.pathContainsParam(candidate)) throw ParameterError.invalidPathMatch({
|
|
2963
2046
|
decoratorName: "Path",
|
|
2964
2047
|
propertyName: candidate,
|
|
2965
2048
|
path: this.paths.join(" | "),
|
|
@@ -2976,20 +2059,20 @@ var ParameterGenerator = class {
|
|
|
2976
2059
|
let typeNode = this.parameter.type;
|
|
2977
2060
|
if (!typeNode) {
|
|
2978
2061
|
const t = this.current.typeChecker.getTypeAtLocation(this.parameter);
|
|
2979
|
-
typeNode = this.current.typeChecker.typeToTypeNode(t, void 0,
|
|
2062
|
+
typeNode = this.current.typeChecker.typeToTypeNode(t, void 0, NodeBuilderFlags.NoTruncation);
|
|
2980
2063
|
}
|
|
2981
|
-
if (!typeNode) throw new ParameterError
|
|
2064
|
+
if (!typeNode) throw new ParameterError({ message: `Could not resolve type for parameter '${this.getParameterName()}'.` });
|
|
2982
2065
|
return new TypeNodeResolver(typeNode, this.current, this.parameter).resolve();
|
|
2983
2066
|
}
|
|
2984
2067
|
getParameterName() {
|
|
2985
|
-
if (!
|
|
2068
|
+
if (!isIdentifier(this.parameter.name)) throw new ParameterError({ message: "Destructured parameters are not supported. Use a simple identifier name." });
|
|
2986
2069
|
return this.parameter.name.text;
|
|
2987
2070
|
}
|
|
2988
2071
|
getDescription() {
|
|
2989
2072
|
const symbol = this.current.typeChecker.getSymbolAtLocation(this.parameter.name);
|
|
2990
2073
|
if (symbol) {
|
|
2991
2074
|
const comments = symbol.getDocumentationComment(this.current.typeChecker);
|
|
2992
|
-
if (comments.length > 0) return
|
|
2075
|
+
if (comments.length > 0) return displayPartsToString(comments);
|
|
2993
2076
|
}
|
|
2994
2077
|
return "";
|
|
2995
2078
|
}
|
|
@@ -3014,7 +2097,7 @@ var ParameterGenerator = class {
|
|
|
3014
2097
|
exampleLabels
|
|
3015
2098
|
};
|
|
3016
2099
|
} catch {
|
|
3017
|
-
throw ParameterError
|
|
2100
|
+
throw ParameterError.invalidExampleSchema();
|
|
3018
2101
|
}
|
|
3019
2102
|
}
|
|
3020
2103
|
applyOptions(parameterName) {
|
|
@@ -3114,19 +2197,19 @@ var MethodGenerator = class {
|
|
|
3114
2197
|
}
|
|
3115
2198
|
} catch (e) {
|
|
3116
2199
|
const causeMsg = e instanceof Error ? `: ${e.message}` : "";
|
|
3117
|
-
throw new GeneratorError
|
|
2200
|
+
throw new GeneratorError({
|
|
3118
2201
|
message: `Parameter generation failed for '${controllerId.text}.${methodId.text}' argument index ${i}${causeMsg}`,
|
|
3119
|
-
code: GeneratorErrorCode
|
|
2202
|
+
code: GeneratorErrorCode.PARAMETER_GENERATION_FAILED,
|
|
3120
2203
|
cause: e
|
|
3121
2204
|
});
|
|
3122
2205
|
}
|
|
3123
|
-
if (bodyParameterCount > 1) throw new GeneratorError
|
|
2206
|
+
if (bodyParameterCount > 1) throw new GeneratorError({
|
|
3124
2207
|
message: `Only one body parameter allowed in '${controllerId.text}.${methodId.text}' method.`,
|
|
3125
|
-
code: GeneratorErrorCode
|
|
2208
|
+
code: GeneratorErrorCode.BODY_PARAMETER_DUPLICATE
|
|
3126
2209
|
});
|
|
3127
|
-
if (bodyParameterCount > 0 && formParameterCount > 0) throw new GeneratorError
|
|
2210
|
+
if (bodyParameterCount > 0 && formParameterCount > 0) throw new GeneratorError({
|
|
3128
2211
|
message: `Cannot mix body and form parameters in '${controllerId.text}.${methodId.text}' method.`,
|
|
3129
|
-
code: GeneratorErrorCode
|
|
2212
|
+
code: GeneratorErrorCode.BODY_FORM_CONFLICT
|
|
3130
2213
|
});
|
|
3131
2214
|
return output;
|
|
3132
2215
|
}
|
|
@@ -3164,13 +2247,13 @@ var ControllerGenerator = class {
|
|
|
3164
2247
|
return !!this.node.name;
|
|
3165
2248
|
}
|
|
3166
2249
|
generate() {
|
|
3167
|
-
if (!this.node.parent) throw new GeneratorError
|
|
2250
|
+
if (!this.node.parent) throw new GeneratorError({
|
|
3168
2251
|
message: "Controller node doesn't have a valid parent source file.",
|
|
3169
|
-
code: GeneratorErrorCode
|
|
2252
|
+
code: GeneratorErrorCode.CONTROLLER_NO_SOURCE_FILE
|
|
3170
2253
|
});
|
|
3171
|
-
if (!this.node.name) throw new GeneratorError
|
|
2254
|
+
if (!this.node.name) throw new GeneratorError({
|
|
3172
2255
|
message: "Controller node doesn't have a valid name.",
|
|
3173
|
-
code: GeneratorErrorCode
|
|
2256
|
+
code: GeneratorErrorCode.CONTROLLER_NO_NAME
|
|
3174
2257
|
});
|
|
3175
2258
|
const sourceFile = this.node.parent.getSourceFile();
|
|
3176
2259
|
const draft = newControllerDraft({
|
|
@@ -3232,7 +2315,7 @@ var ControllerGenerator = class {
|
|
|
3232
2315
|
set.add(methodName);
|
|
3233
2316
|
output.push(method);
|
|
3234
2317
|
} catch (error) {
|
|
3235
|
-
if (isResolverError
|
|
2318
|
+
if (isResolverError(error) || isGeneratorError(error) && error.code === GeneratorErrorCode.PARAMETER_GENERATION_FAILED) continue;
|
|
3236
2319
|
throw error;
|
|
3237
2320
|
}
|
|
3238
2321
|
}
|
|
@@ -3287,13 +2370,24 @@ var MetadataGenerator = class {
|
|
|
3287
2370
|
}
|
|
3288
2371
|
async generate() {
|
|
3289
2372
|
const sourceFilesHash = this.buildNodesFromSourceFiles();
|
|
3290
|
-
|
|
2373
|
+
let presetRegistry;
|
|
2374
|
+
let presetName;
|
|
2375
|
+
if (typeof this.config.preset === "string") {
|
|
2376
|
+
presetName = this.config.preset;
|
|
2377
|
+
presetRegistry = await loadRegistryByName(this.config.preset);
|
|
2378
|
+
} else if (this.config.preset) {
|
|
2379
|
+
presetName = this.config.preset.name;
|
|
2380
|
+
presetRegistry = await loadRegistry(this.config.preset, { resolver: resolvePresetByName });
|
|
2381
|
+
}
|
|
2382
|
+
if (presetRegistry && this.config.registry) this.registry = mergeRegistries(presetRegistry, this.config.registry);
|
|
2383
|
+
else if (presetRegistry) this.registry = presetRegistry;
|
|
2384
|
+
else if (this.config.registry) this.registry = this.config.registry;
|
|
3291
2385
|
const cacheKey = composeCacheKey({
|
|
3292
2386
|
schemaVersion: "3",
|
|
3293
2387
|
sourceFilesHash,
|
|
3294
2388
|
compilerOptionsHash: hashCompilerOptions(this.program.getCompilerOptions()),
|
|
3295
2389
|
registryHash: hashRegistry(this.registry),
|
|
3296
|
-
presetName
|
|
2390
|
+
presetName
|
|
3297
2391
|
});
|
|
3298
2392
|
const bypassCache = !!(this.config.strict || this.config.onUnmatchedDecorator);
|
|
3299
2393
|
let cache = bypassCache ? void 0 : await this.cache.get(cacheKey);
|
|
@@ -3316,10 +2410,10 @@ var MetadataGenerator = class {
|
|
|
3316
2410
|
};
|
|
3317
2411
|
}
|
|
3318
2412
|
assertPresetProducedControllers() {
|
|
3319
|
-
if (this.config.preset || this.controllers.length > 0) return;
|
|
2413
|
+
if (this.config.preset || this.config.registry || this.controllers.length > 0) return;
|
|
3320
2414
|
if (this.nodes.length === 0) return;
|
|
3321
2415
|
throw new ConfigError({
|
|
3322
|
-
message: "No preset configured and no controllers detected. Provide `preset: '@trapi/preset-decorators-express'` (or another preset) so handlers can match your decorators.",
|
|
2416
|
+
message: "No preset or registry configured and no controllers detected. Provide `preset: '@trapi/preset-decorators-express'` (or another preset), or pass an inline `registry`, so handlers can match your decorators.",
|
|
3323
2417
|
code: ConfigErrorCode.PRESET_MISSING
|
|
3324
2418
|
});
|
|
3325
2419
|
}
|
|
@@ -3341,9 +2435,9 @@ var MetadataGenerator = class {
|
|
|
3341
2435
|
return;
|
|
3342
2436
|
}
|
|
3343
2437
|
const summary = this.formatUnmatchedSummary();
|
|
3344
|
-
if (this.config.strict === "throw") throw new GeneratorError
|
|
2438
|
+
if (this.config.strict === "throw") throw new GeneratorError({
|
|
3345
2439
|
message: summary,
|
|
3346
|
-
code: GeneratorErrorCode
|
|
2440
|
+
code: GeneratorErrorCode.STRICT_UNMATCHED_DECORATORS
|
|
3347
2441
|
});
|
|
3348
2442
|
console.warn(summary);
|
|
3349
2443
|
}
|
|
@@ -3431,11 +2525,6 @@ var MetadataGenerator = class {
|
|
|
3431
2525
|
}
|
|
3432
2526
|
};
|
|
3433
2527
|
//#endregion
|
|
3434
|
-
//#region src/app/generator/metadata/utils.ts
|
|
3435
|
-
function isMetadata(input) {
|
|
3436
|
-
return isObject(input) && hasOwnProperty$1(input, "controllers") && Array.isArray(input.controllers) && hasOwnProperty$1(input, "referenceTypes") && isObject(input.referenceTypes);
|
|
3437
|
-
}
|
|
3438
|
-
//#endregion
|
|
3439
2528
|
//#region src/app/generate.ts
|
|
3440
2529
|
async function generateMetadata(options) {
|
|
3441
2530
|
let compilerOptions;
|
|
@@ -3453,6 +2542,6 @@ async function generateMetadata(options) {
|
|
|
3453
2542
|
}).generate();
|
|
3454
2543
|
}
|
|
3455
2544
|
//#endregion
|
|
3456
|
-
export { CACHE_DEFAULT_MAX_AGE_MS, CACHE_FILE_PREFIX, CACHE_FILE_SUFFIX, CACHE_SCHEMA_VERSION, CacheClient,
|
|
2545
|
+
export { CACHE_DEFAULT_MAX_AGE_MS, CACHE_FILE_PREFIX, CACHE_FILE_SUFFIX, CACHE_SCHEMA_VERSION, CacheClient, ConfigError, ConfigErrorCode, ControllerGenerator, GeneratorError, GeneratorErrorCode, JSDocTagName, MetadataError, MetadataGenerator, MethodGenerator, ParameterError, ParameterErrorCode, ParameterGenerator, PrimitiveResolver, ReferenceResolver, ResolverBase, ResolverCache, ResolverError, TypeNodeResolver, ValidatorError, ValidatorErrorCode, applyDecoratorHandlers, applyJsDocHandlers, buildCacheOptions, buildDecoratorArgument, buildDecoratorSources, buildHandlerContext, buildJsDocHandlerContext, buildJsDocSources, composeCacheKey, findDecoratorByName, findDecoratorsByName, generateMetadata, getDeclarationValidators, getInitializerValue, getJSDoc, getJSDocDescription, getJSDocTagComment, getJSDocTagNames, getJSDocTags, getLiteralValue, getNodeDecorators, getNodeDescription, getNodeExtensions, hasDecoratorNamed, hasInitializer, hasJSDocTag, hasOwnProperty, hashCompilerOptions, hashRegistry, isGeneratorError, isResolverError, isStringArray, loadTSConfig, normalizePath, prettyLocationOfNode, prettyTroubleCause, readNodeDecorators, resolveArrayType, resolveIndexedAccessType, resolveIntersectionType, resolveLiteralType, resolveMappedType, resolveObjectLiteralType, resolveTupleType, resolveTypeOperatorType, resolveUnionType, scanSourceFiles, softLoadTsconfig, toTypeNodeOrFail, transformJSDocComment };
|
|
3457
2546
|
|
|
3458
2547
|
//# sourceMappingURL=index.mjs.map
|